Project import generated by Copybara. GitOrigin-RevId: 05dc909ff03281f027f18caebd767cfbe166299b
diff --git a/Makefile b/Makefile old mode 100644 new mode 100755 index 6640ff9..7481eee --- a/Makefile +++ b/Makefile
@@ -1,3 +1,6 @@ +mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST))) +MEDIA_MODULE_PATH := $(dir $(mkfile_path)) +VERSION_CONTROL_CFLAGS := $(shell ${MEDIA_MODULE_PATH}/version_control.sh) CONFIGS := CONFIG_AMLOGIC_MEDIA_VDEC_MPEG12=m \ CONFIG_AMLOGIC_MEDIA_VDEC_MPEG2_MULTI=m \ @@ -15,21 +18,25 @@ CONFIG_AMLOGIC_MEDIA_VDEC_AVS=m \ CONFIG_AMLOGIC_MEDIA_VDEC_AVS_MULTI=m \ CONFIG_AMLOGIC_MEDIA_VDEC_AVS2=m \ - CONFIG_AMLOGIC_MEDIA_VDEC_AV1=m \ CONFIG_AMLOGIC_MEDIA_VENC_H264=m \ - CONFIG_AMLOGIC_MEDIA_VENC_JPEG=m \ - CONFIG_AMLOGIC_MEDIA_VENC_H265=m - + CONFIG_AMLOGIC_MEDIA_VENC_H265=m \ + CONFIG_AMLOGIC_MEDIA_VDEC_AV1=m \ + CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION=y \ + CONFIG_AMLOGIC_MEDIA_GE2D=y \ + CONFIG_AMLOGIC_MEDIA_VENC_MULTI=m \ + CONFIG_AMLOGIC_MEDIA_VENC_JPEG=m EXTRA_INCLUDE := -I$(KERNEL_SRC)/$(M)/drivers/include CONFIGS_BUILD := -Wno-parentheses-equality -Wno-pointer-bool-conversion \ -Wno-unused-const-variable -Wno-typedef-redefinition \ - -Wno-logical-not-parentheses -Wno-sometimes-uninitialized + -Wno-logical-not-parentheses -Wno-sometimes-uninitialized \ + -Wno-frame-larger-than= +KBUILD_CFLAGS_MODULE += $(GKI_EXT_MODULE_PREDEFINE) modules: - $(MAKE) -C $(KERNEL_SRC) M=$(M)/drivers modules "EXTRA_CFLAGS+=-I$(INCLUDE) -Wno-error $(CONFIGS_BUILD) $(EXTRA_INCLUDE)" $(CONFIGS) + $(MAKE) -C $(KERNEL_SRC) M=$(M)/drivers modules "EXTRA_CFLAGS+=-I$(INCLUDE) -Wno-error $(CONFIGS_BUILD) $(EXTRA_INCLUDE) $(KBUILD_CFLAGS_MODULE) ${VERSION_CONTROL_CFLAGS}" $(CONFIGS) all: modules
diff --git a/Media.mk b/Media.mk index 68b0778..58db63b 100644 --- a/Media.mk +++ b/Media.mk
@@ -18,13 +18,13 @@ CONFIG_AMLOGIC_MEDIA_VDEC_MJPEG_MULTI=m \ CONFIG_AMLOGIC_MEDIA_VDEC_REAL=m \ CONFIG_AMLOGIC_MEDIA_VDEC_AVS=m \ - CONFIG_AMLOGIC_MEDIA_VDEC_AVS_MULTI=m \ CONFIG_AMLOGIC_MEDIA_VDEC_AVS2=m \ - CONFIG_AMLOGIC_MEDIA_VDEC_AV1=m \ CONFIG_AMLOGIC_MEDIA_VENC_H264=m \ - CONFIG_AMLOGIC_MEDIA_VENC_JPEG=m \ CONFIG_AMLOGIC_MEDIA_VENC_H265=m \ - CONFIG_FRAME_WARN=4096 + CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION=y \ + CONFIG_AMLOGIC_MEDIA_GE2D=y \ + CONFIG_AMLOGIC_MEDIA_VENC_MULTI=m \ + CONFIG_AMLOGIC_MEDIA_VENC_JPEG=m define copy-media-modules $(foreach m, $(shell find $(strip $(1)) -name "*.ko"),\ @@ -63,11 +63,10 @@ $(shell cp $(MEDIA_DRIVERS)/* $(MEDIA_MODULES) -rfa) define media-modules - PATH=$$(cd ./$(TARGET_HOST_TOOL_PATH); pwd):$$PATH \ - $(MAKE) -C $(KDIR) M=$(MEDIA_MODULES) ARCH=$(KERNEL_ARCH) \ - CROSS_COMPILE=$(PREFIX_CROSS_COMPILE) $(CONFIGS) \ - EXTRA_CFLAGS+=-I$(INCLUDE) modules; - sh $(TOP)/device/amlogic/common/copy_modules.sh $(MEDIA_MODULES) $(MODS_OUT) + PATH=$(KERNEL_TOOLPATHS):$$PATH \ + $(MAKE) -C $(KDIR) M=$(MEDIA_MODULES) $(KERNEL_ARGS) $(CONFIGS) \ + "EXTRA_CFLAGS+=-I$(INCLUDE) -Wno-error" modules; \ + find $(MEDIA_MODULES) -name "*.ko" | PATH=$$(cd ./$(TARGET_HOST_TOOL_PATH); pwd):$$PATH xargs -i cp {} $(MODS_OUT) endef else @@ -91,18 +90,10 @@ $(shell mkdir $(MODS_OUT) -p) endif -ifeq ($(KERNEL_A32_SUPPORT), true) -TOOLS := /opt/gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- -else -TOOLS := /opt/gcc-linaro-5.3-2016.02-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- -endif - - modules: - CCACHE_NODIRECT="true" PATH=$$(cd ./$(TARGET_HOST_TOOL_PATH); pwd):$$PATH \ - $(MAKE) -C $(KDIR) M=$(MEDIA_DRIVERS) ARCH=$(KERNEL_ARCH) \ - CROSS_COMPILE=$(TOOLS) $(CONFIGS) \ - EXTRA_CFLAGS+=-I$(INCLUDE) -j64 + CCACHE_NODIRECT="true" PATH=$(KERNEL_TOOLPATHS):$$PATH \ + $(MAKE) -C $(KDIR) M=$(MEDIA_DRIVERS) ARCH=$(KERNEL_ARCH) $(KERNEL_ARGS) $(CONFIGS) \ + EXTRA_CFLAGS+=-I$(INCLUDE) -j64 copy-modules: @echo "start copying media modules." @@ -111,8 +102,9 @@ all: modules copy-modules + clean: - PATH=$$(cd ./$(TARGET_HOST_TOOL_PATH); pwd):$$PATH \ - $(MAKE) -C $(KDIR) M=$(MEDIA_DRIVERS) ARCH=$(KERNEL_ARCH) clean + PATH=$(KERNEL_TOOLPATHS):$$PATH \ + $(MAKE) -C $(KDIR) M=$(MEDIA_DRIVERS) $(KERNEL_ARGS) clean endif
diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..4b1504d --- /dev/null +++ b/VERSION
@@ -0,0 +1,76 @@ +Major_V=5 +Minor_V=3 +BaseChangeId=Ifc17e92ef9c9e211b8f01ebae1e97c5855fea084 + + +#history version +#V5.2.104-g795aee00.003025 Release Notes +#Release_ChangeId_V5_2=I34801cba60d54bfd9f459f7445d0362989c23496 +#V5.1.77-g0cdebf27.003009 Release Notes +#Release_ChangeId_V5_1=Id7e315bbf379d166ca4b335cef13c983a8ca5078 +#Feature develop total count: 6 +# critical feature develop count: 0 +# important feature develop count: 4 +# normal feature develop count: 2 +#Feature develop detail information: +# improve pip channel play +# support decoder fence +# fixed can't get hdr information correctly. +# add multi-vdec info for new format av1 after revert +# change ptsadjust and threshold from s64 to s32. +# support dw 0x100 +#Fixed BUG total count: 30 +# fixed critical BUG count: 3 +# fixed important feature develop count: 15 +# fixed normal feature develop count: 12 +#Fixed BUG detail information: +# add VIDTYPE_COMPRESS in vf for dw mode with afbc buffer +# fix some the crash caused by null pointer +# fixed vpp wrapper memory leak. +# metadata lose the last byte every frame in frame mode +# fix avs color abnormal. +# fix gst secure v4l2 decoder not work +# fix the playback stuck when resolution changed +# h265 ucode send 2 interrupts cause playback stuck +# fix av1 freeze when burn-in test. +# fixed playback stuck after seek. +# fix 8k display abnormal. +# fixed irq-vdec-0 takes more cpu slice. +# fixed AV1 seek freezing. +# fixed failed to allocate tvp memory +# fixed issue of reports resolution change. +#V5.0 Release Notes +#Release_ChangeId_V5_0=I6053e02900215d9006469c38ca375ace498b849f +#upgrade Kernel version to 5.4 +#Android R + v4l2dec (no vpp) xts clean +#v4ldec driver seperate from amports drivers +# +#V4.0.0 Release Notes +#upgrade Kernel version to 4.19 +#v4l2 support for h264/h265/vp9 +#add fra support in decoder driver +# +#V3.0.0 Release Notes +#upgrade Kernel version to 4.9 +#media_module remove from kernel +#new firmware management +#mjpeg/mpeg12/mpeg2 multi-instance decoder support +#h264 4k afbc support +#AVS2 decoder support +#vdec double write support +#add av1 decoder support +#add decoder QOS info report +#upgrade TA ucode to 0.2 version +# +#V2.0.0 Release Notes +#upgrade Kernel version to 3.14 +#Introduce codec_mm memory managment +#add afbc scatter memory support +#add vp9 decoder support +#add 264/265/vp9 multi-instance decoder support +# +#V1.0.0 Release Notes +#based kernel to 3.10 +#add H264 4K decoder support +#add H265 video decoder support +#H265 decoder support afbc output
diff --git a/build_media.sh b/build_media.sh deleted file mode 100755 index 63eaf1a..0000000 --- a/build_media.sh +++ /dev/null
@@ -1,105 +0,0 @@ -#!/bin/bash -# Builds the media driver and updates the workspace path with output files - -exec_name=$0 - -cpu_num=$(grep -c processor /proc/cpuinfo) - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -CROSS_COMPILE=$DIR/../prebuilt/toolchain/aarch64/bin/aarch64-cros-linux-gnu- -KERNEL_ARCH=arm64 -KDIR=$DIR/../kernel -INCLUDE=$DIR/drivers/include -MEDIA_MODULES=$DIR/drivers -CONFIGS="CONFIG_AMLOGIC_MEDIA_VDEC_MPEG12=m \ - CONFIG_AMLOGIC_MEDIA_VDEC_MPEG2_MULTI=m \ - CONFIG_AMLOGIC_MEDIA_VDEC_MPEG4=m \ - CONFIG_AMLOGIC_MEDIA_VDEC_MPEG4_MULTI=m \ - CONFIG_AMLOGIC_MEDIA_VDEC_VC1=m \ - CONFIG_AMLOGIC_MEDIA_VDEC_H264=m \ - CONFIG_AMLOGIC_MEDIA_VDEC_H264_MULTI=m \ - CONFIG_AMLOGIC_MEDIA_VDEC_H264_MVC=m \ - CONFIG_AMLOGIC_MEDIA_VDEC_H265=m \ - CONFIG_AMLOGIC_MEDIA_VDEC_VP9=m \ - CONFIG_AMLOGIC_MEDIA_VDEC_MJPEG=m \ - CONFIG_AMLOGIC_MEDIA_VDEC_MJPEG_MULTI=m \ - CONFIG_AMLOGIC_MEDIA_VDEC_REAL=m \ - CONFIG_AMLOGIC_MEDIA_VDEC_AVS=m \ - CONFIG_AMLOGIC_MEDIA_VDEC_AVS_MULTI=m \ - CONFIG_AMLOGIC_MEDIA_VDEC_AVS2=m \ - CONFIG_AMLOGIC_MEDIA_VENC_H264=m \ - CONFIG_AMLOGIC_MEDIA_VENC_H265=m \ - CONFIG_FRAME_WARN=4096" - -set -o errtrace -trap 'echo Fatal error: script ${exec_name} aborting at line $LINENO, command \"$BASH_COMMAND\" returned $?; exit 1' ERR - -function usage(){ - echo "Usage: ${exec_name} <product> [workspace path]" - echo "supported products: sabrina" - echo "Note: if [workspace path] is not set, it still builds" -} - -if (( $# < 1 )) -then - usage - exit 2 -fi - -readonly product=$1 -readonly workspace_path=$2 - -pushd $DIR - - -make -C $KDIR M=$MEDIA_MODULES ARCH=$KERNEL_ARCH \ -CROSS_COMPILE=$CROSS_COMPILE $CONFIGS \ -EXTRA_CFLAGS+=-I$INCLUDE modules -j64 - -case $product in - sabrina*) - ;; - *) - echo "unknown product: $product" - exit 1 -esac - -popd - -if [ ! -z $workspace_path ]; then - media_out_dir=${workspace_path}/device/google/${product}-kernel/lib/modules - mkdir -p ${media_out_dir} - - for ko in aml_hardware_dmx.ko \ - amvdec_avs2.ko \ - amvdec_avs.ko \ - amvdec_h264.ko \ - amvdec_h264mvc.ko \ - amvdec_h265.ko \ - amvdec_mh264.ko \ - amvdec_mjpeg.ko \ - amvdec_mmjpeg.ko \ - amvdec_mmpeg12.ko \ - amvdec_mmpeg4.ko \ - amvdec_mpeg12.ko \ - amvdec_mpeg4.ko \ - amvdec_real.ko \ - amvdec_vc1.ko \ - amvdec_vp9.ko \ - decoder_common.ko \ - encoder.ko \ - firmware.ko \ - media_clock.ko \ - stream_input.ko \ - vpu.ko \ - amvdec_ports.ko \ - video_framerate_adapter.ko \ - media_sync.ko - do - find $MEDIA_MODULES -name $ko | xargs -i cp {} $media_out_dir - done - media_fw_out_dir=${workspace_path}/device/google/${product}-kernel/lib/firmware/video/ - mkdir -p $media_fw_out_dir - cp -r firmware/* $media_fw_out_dir -fi
diff --git a/drivers/Makefile b/drivers/Makefile index 3e487db..e96ba44 100644 --- a/drivers/Makefile +++ b/drivers/Makefile
@@ -3,6 +3,6 @@ obj-y += frame_sink/ obj-y += stream_input/ obj-y += amvdec_ports/ -obj-y += fake_video_out/ obj-y += framerate_adapter/ obj-y += media_sync/ +obj-$(CONFIG_AMLOGIC_MEDIA_V4L_DEC) += amvdec_ports/
diff --git a/drivers/amvdec_ports/Makefile b/drivers/amvdec_ports/Makefile index 6395adf..2e7cff4 100644 --- a/drivers/amvdec_ports/Makefile +++ b/drivers/amvdec_ports/Makefile
@@ -3,8 +3,10 @@ amvdec_ports-objs += aml_vcodec_dec.o amvdec_ports-objs += aml_vcodec_util.o amvdec_ports-objs += aml_vcodec_adapt.o -amvdec_ports-objs += aml_vcodec_vfm.o +amvdec_ports-objs += aml_vcodec_vpp.o +amvdec_ports-objs += aml_vcodec_ge2d.o amvdec_ports-objs += vdec_drv_if.o +amvdec_ports-objs += aml_task_chain.o amvdec_ports-objs += decoder/vdec_h264_if.o amvdec_ports-objs += decoder/vdec_hevc_if.o amvdec_ports-objs += decoder/vdec_vp9_if.o
diff --git a/drivers/amvdec_ports/aml_task_chain.c b/drivers/amvdec_ports/aml_task_chain.c new file mode 100644 index 0000000..8dfe014 --- /dev/null +++ b/drivers/amvdec_ports/aml_task_chain.c
@@ -0,0 +1,365 @@ +/* +* Copyright (C) 2017 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. +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, write to the Free Software Foundation, Inc., +* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +* Description: +*/ + +#include <linux/list.h> +#include <linux/spinlock.h> + +#include "aml_vcodec_drv.h" +#include "aml_task_chain.h" + +#define KERNEL_ATRACE_TAG KERNEL_ATRACE_TAG_V4L2 +#include <trace/events/meson_atrace.h> + +struct task_item_name_s { + enum task_type_e type; + const u8 *name; +}; + +static const struct task_item_name_s iname[] = { + {TASK_TYPE_DEC, "dec"}, + {TASK_TYPE_VPP, "vpp"}, + {TASK_TYPE_V4L_SINK, "v4l-sink"}, + {TASK_TYPE_GE2D, "ge2d"}, + {TASK_TYPE_MAX, "unknown"}, +}; + +static const u8 *type_to_name(enum task_type_e type) +{ + const u8 *name = "unknown"; + int i, size = ARRAY_SIZE(iname); + + for (i = 0; i < size; i++) { + if (type == iname[i].type) + name = iname[i].name; + } + + return name; +} + +static struct task_item_s *find_task_item(struct task_chain_s *task, + enum task_type_e type) +{ + struct task_item_s *item = NULL; + ulong flags; + + spin_lock_irqsave(&task->slock, flags); + + if (!list_empty(&task->list_item)) { + struct task_item_s *p; + + list_for_each_entry(p, &task->list_item, node) { + if (p->ops->type == type) { + item = p; + break; + } + } + } + + if (item) + kref_get(&item->ref); + + spin_unlock_irqrestore(&task->slock, flags); + + return item; +} + +static void task_item_release(struct kref *kref); + +static void task_item_vframe_push(struct task_item_s *item, struct vframe_s *vframe) +{ + int i = 0; + + for (i = 0 ; i < 3; i++) { + if (item->vframe[i] == NULL) { + item->vframe[i] = vframe; + break; + } + } +} + +static struct vframe_s *task_item_vframe_pop(struct task_item_s *item) +{ + struct vframe_s *vframe = NULL; + int i = 0; + + for (i = 0 ; i < 3; i++) { + if (item->vframe[i] != NULL) { + vframe = item->vframe[i]; + item->vframe[i] = NULL; + break; + } + } + + return vframe; +} + +static struct task_item_s *task_item_get(struct task_chain_s *task, + enum task_type_e type) +{ + struct task_item_s *item = NULL; + + item = find_task_item(task, type); + if (!item) { + v4l_dbg(task->ctx, V4L_DEBUG_CODEC_ERROR, + "TSK(%px):%d get item:%d fail.\n", task, task->id, type); + } + + return item; +} + +static int task_item_put(struct task_item_s *item) +{ + return kref_put(&item->ref, task_item_release); +} + +static void task_buffer_submit(struct task_chain_s *task, + enum task_type_e type) +{ + struct vdec_v4l2_buffer *fb = + (struct vdec_v4l2_buffer *)task->obj; + struct task_item_s *item = NULL; + struct task_item_s *item2 = NULL; + struct vframe_s *vf = NULL; + + item = task_item_get(task, type); + if (item) { + item->ops->get_vframe(item->caller, &vf); + fb->vframe = (void *)vf; + task_item_vframe_push(item, vf); + item->is_active = false; + + item2 = task_item_get(task, task->map[0][type]); + if (item2) { + item2->is_active = true; + item2->ops->fill_buffer(task->ctx, fb); + + v4l_dbg(task->ctx, V4L_DEBUG_TASK_CHAIN, + "TSK(%px):%d, vf:%px, phy:%lx, submit %d => %d.\n", + task, task->id, vf, fb->m.mem[0].addr, + type, task->map[0][type]); + + task->direction = TASK_DIR_SUBMIT; + task_item_put(item2); + } + task_item_put(item); + } +} + +static void task_buffer_recycle(struct task_chain_s *task, + enum task_type_e type) +{ + struct vdec_v4l2_buffer *fb = + (struct vdec_v4l2_buffer *)task->obj; + struct task_item_s *item = NULL; + struct task_item_s *item2 = NULL; + + item = task_item_get(task, type); + if (item) { + item->is_active = false; + + item2 = task_item_get(task, task->map[1][type]); + if (item2) { + struct vframe_s *vf = NULL; + + item2->is_active = true; + + vf = task_item_vframe_pop(item2); + item2->ops->put_vframe(item2->caller, vf); + + v4l_dbg(task->ctx, V4L_DEBUG_TASK_CHAIN, + "TSK(%px):%d, vf:%px, phy:%lx, recycle %d => %d.\n", + task, task->id, vf, fb->m.mem[0].addr, + type, task->map[1][type]); + + task->direction = TASK_DIR_RECYCLE; + task_item_put(item2); + } + task_item_put(item); + } +} + +void task_chain_show(struct task_chain_s *task) +{ + struct task_item_s *item = NULL; + char buf[128] = {0}; + char *pbuf = buf; + ulong flags; + + if (!task || !task->ctx) + return; + + spin_lock_irqsave(&task->slock, flags); + + if (!list_empty(&task->list_item)) { + struct vdec_v4l2_buffer *fb = + (struct vdec_v4l2_buffer *)task->obj; + + list_for_each_entry(item, &task->list_item, node) { + pbuf += sprintf(pbuf, "%s(%d)", + item->name, item->is_active); + if (item->node.next != &task->list_item) { + if (task->direction == TASK_DIR_SUBMIT) + pbuf += sprintf(pbuf, " ==> "); + else + pbuf += sprintf(pbuf, " <== "); + } + } + v4l_dbg(task->ctx, V4L_DEBUG_CODEC_PRINFO, + "vb:%2d, phy:%lx %s\n", + task->id, fb->m.mem[0].addr, buf); + } + + spin_unlock_irqrestore(&task->slock, flags); +} +EXPORT_SYMBOL(task_chain_show); + +static void task_chain_destroy(struct kref *kref) +{ + struct task_chain_s *task; + + task = container_of(kref, struct task_chain_s, ref); + + task->cur_type = TASK_TYPE_MAX; + memset(task->map, 0, sizeof(task->map)); + + v4l_dbg(task->ctx, V4L_DEBUG_TASK_CHAIN, + "TSK(%px):%d task chain destroyed.\n", task, task->id); + + kfree(task); +} + +static void task_item_release(struct kref *kref) +{ + struct task_item_s *item; + + item = container_of(kref, struct task_item_s, ref); + list_del(&item->node); + + v4l_dbg(item->task->ctx, V4L_DEBUG_TASK_CHAIN, + "TSK(%px):%d task item:(%px,%d) released.\n", + item->task, item->task->id, item, item->ops->type); + + kref_put(&item->task->ref, task_chain_destroy); + + kfree(item); +} + +void task_chain_clean(struct task_chain_s *task) +{ + struct task_item_s *item, *tmp; + + v4l_dbg(task->ctx, V4L_DEBUG_TASK_CHAIN, + "TSK(%px):%d task chain clean.\n", task, task->id); + + if (!list_empty(&task->list_item)) { + list_for_each_entry_safe(item, tmp, &task->list_item, node) + kref_put(&item->ref, task_item_release); + } +} +EXPORT_SYMBOL(task_chain_clean); + +void task_chain_release(struct task_chain_s *task) +{ + v4l_dbg(task->ctx, V4L_DEBUG_TASK_CHAIN, + "TSK(%px):%d task chain release.\n", task, task->id); + + kref_put(&task->ref, task_chain_destroy); +} +EXPORT_SYMBOL(task_chain_release); + +void task_order_attach(struct task_chain_s *task, + struct task_ops_s *ops, + void *caller) +{ + struct task_item_s *item; + + item = kzalloc(sizeof(struct task_item_s), GFP_ATOMIC); + if (!item) { + v4l_dbg(task->ctx, V4L_DEBUG_CODEC_ERROR, + "TSK(%px):%d alloc item fail.\n", task, task->id); + return; + } + + item->task = task; + item->ops = ops; + item->caller = caller; + item->name = type_to_name(ops->type); + kref_init(&item->ref); + + task->map[0][ops->type] = task->cur_type; + task->map[1][task->cur_type] = ops->type; + task->cur_type = ops->type; + kref_get(&task->ref); + + list_add(&item->node, &task->list_item); + + v4l_dbg(task->ctx, V4L_DEBUG_TASK_CHAIN, + "TSK(%px):%d attach item:(%px,%d).\n", + task, task->id, item, ops->type); +} +EXPORT_SYMBOL(task_order_attach); + +void task_chain_update_object(struct task_chain_s *task, void *obj) +{ + /* + * Note: have to invoke this funtion + * if the task object has been changed. + */ + task->obj = obj; + + v4l_dbg(task->ctx, V4L_DEBUG_TASK_CHAIN, + "TSK(%px):%d update task obj:%px.\n", + task, task->id, obj); +} +EXPORT_SYMBOL(task_chain_update_object); + +int task_chain_init(struct task_chain_s **task_out, + void *v4l_ctx, + void *obj, + int vb_idx) +{ + struct task_chain_s *task; + + task = kzalloc(sizeof(struct task_chain_s), GFP_ATOMIC); + if (!task) { + v4l_dbg(task->ctx, V4L_DEBUG_CODEC_ERROR, + "TSK(%px):%d alloc task fail.\n", task, task->id); + return -ENOMEM; + } + + task->id = vb_idx; + task->obj = obj; + task->ctx = v4l_ctx; + kref_init(&task->ref); + spin_lock_init(&task->slock); + INIT_LIST_HEAD(&task->list_item); + + task->attach = task_order_attach; + task->submit = task_buffer_submit; + task->recycle = task_buffer_recycle; + + *task_out = task; + + v4l_dbg(task->ctx, V4L_DEBUG_TASK_CHAIN, + "TSK(%px):%d task chain creat success.\n", task, task->id); + return 0; +} +EXPORT_SYMBOL(task_chain_init); +
diff --git a/drivers/amvdec_ports/aml_task_chain.h b/drivers/amvdec_ports/aml_task_chain.h new file mode 100644 index 0000000..fdbe2fb --- /dev/null +++ b/drivers/amvdec_ports/aml_task_chain.h
@@ -0,0 +1,125 @@ +/* +* Copyright (C) 2017 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. +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, write to the Free Software Foundation, Inc., +* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +* Description: +*/ + +#ifndef AML_TASK_CHAIN_H +#define AML_TASK_CHAIN_H + +#include <linux/amlogic/media/vfm/vframe.h> + +enum task_type_e { + TASK_TYPE_DEC, + TASK_TYPE_VPP, + TASK_TYPE_V4L_SINK, + TASK_TYPE_GE2D, + TASK_TYPE_MAX +}; + +enum task_dir_e { + TASK_DIR_SUBMIT, + TASK_DIR_RECYCLE, + TASK_DIR_MAX +}; + +struct task_chain_s; + +/* + * struct task_ops_s - interface of the task item. + * @type : type of task ops involves dec, vpp, v4l sink etc. + * @get_vframe : get the video frame from caller's fifo. + * @put_vframe : put the video frame to caller's fifo. + * @fill_buffer : submit the buffer into next process module. + */ +struct task_ops_s { + enum task_type_e type; + void (*get_vframe) (void *caller, struct vframe_s **vf); + void (*put_vframe) (void *caller, struct vframe_s *vf); + void (*fill_buffer) (void *v4l_ctx, void *fb_ctx); +}; + +/* + * struct task_item_s - items of the task chain. + * @node : list node of the specific task item. + * @ref : reference count of item be used by others. + * @name : name of task item, map with task type. + * @is_active : indicate this item whether is active. + * @vframe[3] : store the vframes that get from caller. + * @task : the context of the task chain. + * @caller : it's the handle, meght it's dec, vpp or v4l-sink etc. + * @ops : sets of interface which attach from task item. + */ +struct task_item_s { + struct list_head node; + struct kref ref; + const u8 *name; + bool is_active; + void *vframe[3]; + struct task_chain_s *task; + void *caller; + struct task_ops_s *ops; +}; + +/* + * struct task_chain_s - the manager struct of the task chain. + * @list_item : all task items be attached are store in the list. + * @node : will register to the task chain pool. + * @ref : reference count of task chain be used by others. + * @slock : used for list item write and read safely. + * @id : it's vb index to be a mark used for task chain. + * @ctx : the context of the v4l driver. + * @obj : the object managed by task chain. + * @direction : direction incluse 2 flows submit & recycle. + * @cur_type : the latest item type before a new item be attached. + * @map : the map store the pipeline information. + * @attach : attach a new item to task chain. + * @submit : submit the finish item to next item module. + * @recycle : if item's date was consumed will be recycled to item. + */ +struct task_chain_s { + struct list_head list_item; + struct list_head node; + struct kref ref; + spinlock_t slock; + int id; + void *ctx; + void *obj; + enum task_dir_e direction; + enum task_type_e cur_type; + u8 map[2][8]; + + void (*attach) (struct task_chain_s *, struct task_ops_s *, void *); + void (*submit) (struct task_chain_s *, enum task_type_e); + void (*recycle) (struct task_chain_s *, enum task_type_e); +}; + + +int task_chain_init(struct task_chain_s **task_out, + void *v4l_ctx, + void *obj, + int vb_idx); +void task_order_attach(struct task_chain_s *task, + struct task_ops_s *ops, + void *caller); +void task_chain_clean(struct task_chain_s *task); +void task_chain_release(struct task_chain_s *task); +void task_chain_show(struct task_chain_s *task); +void task_chain_update_object(struct task_chain_s *task, void *obj); + +#endif //AML_TASK_CHAIN_H +
diff --git a/drivers/amvdec_ports/aml_vcodec_adapt.c b/drivers/amvdec_ports/aml_vcodec_adapt.c index 95ee48a..7e08371 100644 --- a/drivers/amvdec_ports/aml_vcodec_adapt.c +++ b/drivers/amvdec_ports/aml_vcodec_adapt.c
@@ -56,17 +56,11 @@ //#define DATA_DEBUG extern int dump_output_frame; +extern u32 dump_output_start_position; extern void aml_recycle_dma_buffers(struct aml_vcodec_ctx *ctx, u32 handle); -static int def_4k_vstreambuf_sizeM = - (DEFAULT_VIDEO_BUFFER_SIZE_4K >> 20); -static int def_vstreambuf_sizeM = - (DEFAULT_VIDEO_BUFFER_SIZE >> 20); static int slow_input = 0; -static int use_bufferlevelx10000 = 10000; -static unsigned int amstream_buf_num = BUF_MAX_NUM; - static struct stream_buf_s bufs[BUF_MAX_NUM] = { { .reg_base = VLD_MEM_VIFIFO_REG_BASE, @@ -173,60 +167,6 @@ return 0; } -static int reset_canuse_buferlevel(int levelx10000) -{ - int i; - struct stream_buf_s *p = NULL; - - if (levelx10000 >= 0 && levelx10000 <= 10000) - use_bufferlevelx10000 = levelx10000; - else - use_bufferlevelx10000 = 10000; - for (i = 0; i < amstream_buf_num; i++) { - p = &bufs[i]; - p->canusebuf_size = ((p->buf_size / 1024) * - use_bufferlevelx10000 / 10000) * 1024; - p->canusebuf_size += 1023; - p->canusebuf_size &= ~1023; - - if (p->canusebuf_size > p->buf_size) - p->canusebuf_size = p->buf_size; - } - - return 0; -} - -static void change_vbufsize(struct vdec_s *vdec, - struct stream_buf_s *pvbuf) -{ - if (pvbuf->buf_start != 0) { - v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "streambuf is alloced before\n"); - return; - } - - if (vdec->port->is_4k) { - pvbuf->buf_size = def_4k_vstreambuf_sizeM * SZ_1M; - - if (vdec->port_flag & PORT_FLAG_DRM) - pvbuf->buf_size = DEFAULT_VIDEO_BUFFER_SIZE_4K_TVP; - - if ((pvbuf->buf_size > 30 * SZ_1M) - && (codec_mm_get_total_size() < 220 * SZ_1M)) { - /*if less than 250M, used 20M for 4K & 265*/ - pvbuf->buf_size = pvbuf->buf_size >> 1; - } - } else if (pvbuf->buf_size > def_vstreambuf_sizeM * SZ_1M) { - if (vdec->port_flag & PORT_FLAG_DRM) - pvbuf->buf_size = DEFAULT_VIDEO_BUFFER_SIZE_TVP; - } else { - pvbuf->buf_size = def_vstreambuf_sizeM * SZ_1M; - if (vdec->port_flag & PORT_FLAG_DRM) - pvbuf->buf_size = DEFAULT_VIDEO_BUFFER_SIZE_TVP; - } - - reset_canuse_buferlevel(10000); -} - static void user_buffer_init(void) { struct stream_buf_s *pubuf = &bufs[BUF_TYPE_USERDATA]; @@ -237,41 +177,14 @@ pubuf->buf_rp = 0; } -static void video_component_release(struct stream_port_s *port, -struct stream_buf_s *pbuf, int release_num) +static void video_component_release(struct stream_port_s *port) { struct aml_vdec_adapt *ada_ctx = container_of(port, struct aml_vdec_adapt, port); struct vdec_s *vdec = ada_ctx->vdec; - struct vdec_s *slave = NULL; + vdec_release(vdec); - switch (release_num) { - default: - case 0: - case 4: { - if ((port->type & PORT_TYPE_FRAME) == 0) - esparser_release(pbuf); - } - - case 3: { - if (vdec->slave) - slave = vdec->slave; - vdec_release(vdec); - - if (slave) - vdec_release(slave); - vdec = NULL; - } - - case 2: { - if ((port->type & PORT_TYPE_FRAME) == 0) - stbuf_release(pbuf); - } - - case 1: - ; - } } static int video_component_init(struct stream_port_s *port, @@ -291,69 +204,21 @@ || port->vformat == VFORMAT_H264_4K2K) { port->is_4k = true; if (get_cpu_type() >= MESON_CPU_MAJOR_ID_TXLX - && port->vformat == VFORMAT_H264) + && (port->vformat == VFORMAT_H264)) vdec_poweron(VDEC_HEVC); } else port->is_4k = false; - if (port->type & PORT_TYPE_FRAME) { - ret = vdec_init(vdec, port->is_4k); + if (port->type & PORT_TYPE_FRAME || + (port->type & PORT_TYPE_ES)) { + ret = vdec_init(vdec, port->is_4k, true); if (ret < 0) { v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_ERROR, "failed\n"); - video_component_release(port, pbuf, 2); - return ret; - } - - return 0; - } - - change_vbufsize(vdec, pbuf); - - if (has_hevc_vdec()) { - if (port->type & PORT_TYPE_MPTS) { - if (pbuf->type == BUF_TYPE_HEVC) - vdec_poweroff(VDEC_1); - else - vdec_poweroff(VDEC_HEVC); - } - } - - ret = stbuf_init(pbuf, vdec); - if (ret < 0) { - v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_ERROR, "stbuf_init failed\n"); - return ret; - } - - /* todo: set path based on port flag */ - ret = vdec_init(vdec, port->is_4k); - if (ret < 0) { - v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_ERROR, "vdec_init failed\n"); - video_component_release(port, pbuf, 2); - return ret; - } - - if (vdec_dual(vdec)) { - ret = vdec_init(vdec->slave, port->is_4k); - if (ret < 0) { - v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_ERROR, "vdec_init failed\n"); - video_component_release(port, pbuf, 2); + video_component_release(port); return ret; } } - if (port->type & PORT_TYPE_ES) { - ret = esparser_init(pbuf, vdec); - if (ret < 0) { - video_component_release(port, pbuf, 3); - v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_ERROR, "esparser_init() failed\n"); - return ret; - } - } - - pbuf->flag |= BUF_FLAG_IN_USE; - - vdec_connect(vdec); - return 0; } @@ -362,8 +227,8 @@ struct stream_buf_s *pvbuf = &bufs[BUF_TYPE_VIDEO]; if (has_hevc_vdec()) { - if (port->vformat == VFORMAT_HEVC - || port->vformat == VFORMAT_VP9) + if (port->vformat == VFORMAT_HEVC || + port->vformat == VFORMAT_VP9) pvbuf = &bufs[BUF_TYPE_HEVC]; } @@ -376,7 +241,7 @@ psparser_release(); if (port->type & PORT_TYPE_VIDEO) - video_component_release(port, pvbuf, 0); + video_component_release(port); port->pcr_inited = 0; port->flag = 0; @@ -391,7 +256,6 @@ vdec->port = &ada_ctx->port; vdec->format = ada_ctx->video_type; vdec->sys_info_store = ada_ctx->dec_prop; - vdec->vf_receiver_name = ada_ctx->recv_name; /* binding v4l2 ctx to vdec. */ vdec->private = ada_ctx->ctx; @@ -425,7 +289,6 @@ vdec->frame_base_video_path = aml_set_vfm_path; vdec->port->flag = vdec->port_flag; - ada_ctx->vfm_path = vdec->frame_base_video_path; vdec->config_len = ada_ctx->config.length > PAGE_SIZE ? PAGE_SIZE : ada_ctx->config.length; @@ -445,6 +308,7 @@ if (IS_ERR_OR_NULL(vdec)) return -1; + vdec->disable_vfm = true; set_vdec_properity(vdec, ada_ctx); /* init hw and gate*/ @@ -461,8 +325,8 @@ && (vdec->port_flag & PORT_FLAG_VFORMAT)) { vdec->port->is_4k = false; if (has_hevc_vdec()) { - if (vdec->port->vformat == VFORMAT_HEVC - || vdec->port->vformat == VFORMAT_VP9) + if (vdec->port->vformat == VFORMAT_HEVC || + vdec->port->vformat == VFORMAT_VP9) pvbuf = &bufs[BUF_TYPE_HEVC]; } @@ -526,9 +390,11 @@ if (!IS_ERR(fp)) { kernel_write(fp, data, size, 0); filp_close(fp, NULL); + } else { + pr_info("Dump ES fail, should check RW permission, size:%x\n", size); } - } + int vdec_vbuf_write(struct aml_vdec_adapt *ada_ctx, const char *buf, unsigned int count) { @@ -579,11 +445,11 @@ { struct vdec_s *vdec = ada_ctx->vdec; - return (vdec->input.have_frame_num > 600) ? true : false; + return (vdec->input.have_frame_num > 60) ? true : false; } int vdec_vframe_write(struct aml_vdec_adapt *ada_ctx, - const char *buf, unsigned int count, u64 timestamp) + const char *buf, unsigned int count, u64 timestamp, ulong meta_ptr) { int ret = -1; struct vdec_s *vdec = ada_ctx->vdec; @@ -591,6 +457,9 @@ /* set timestamp */ vdec_set_timestamp(vdec, timestamp); + /* set metadata */ + vdec_set_metadata(vdec, meta_ptr); + ret = vdec_write_vframe(vdec, buf, count); if (slow_input) { @@ -599,9 +468,12 @@ msleep(30); } - if (dump_output_frame > 0) { + if (dump_output_frame > 0 && + (!dump_output_start_position || + (dump_output_start_position == crc32_le(0, buf, count)))) { dump("/data/es.data", buf, count); dump_output_frame--; + dump_output_start_position = 0; } v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_INPUT, @@ -658,23 +530,14 @@ int ret = 0; if (vdec) { - if (!ada_ctx->ctx->q_data[AML_Q_DATA_SRC].resolution_changed) + if (ada_ctx->ctx->v4l_resolution_change) + *mode = V4L_RESET_MODE_LIGHT; + else vdec_set_eos(vdec, false); - if (*mode == V4L_RESET_MODE_NORMAL && - vdec->input.have_frame_num == 0) { - v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_PRINFO, - "no input reset mode: %d\n", *mode); - *mode = V4L_RESET_MODE_LIGHT; - } - if (ada_ctx->ctx->param_sets_from_ucode && - *mode == V4L_RESET_MODE_NORMAL && - ada_ctx->ctx->q_data[AML_Q_DATA_SRC].resolution_changed == true) { - v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_PRINFO, - "resolution_changed reset mode: %d\n", *mode); - *mode = V4L_RESET_MODE_LIGHT; - } + v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_PRINFO, - "reset mode: %d\n", *mode); + "reset mode: %d, es frames buffering: %d\n", + *mode, vdec_frame_number(ada_ctx)); ret = vdec_v4l2_reset(vdec, *mode); *mode = V4L_RESET_MODE_NORMAL; @@ -709,6 +572,11 @@ return -1; } +int vdec_get_instance_num(void) +{ + return vdec_get_core_nr(); +} + void v4l2_config_vdec_parm(struct aml_vdec_adapt *ada_ctx, u8 *data, u32 len) { struct vdec_s *vdec = ada_ctx->vdec; @@ -716,3 +584,8 @@ vdec->config_len = len > PAGE_SIZE ? PAGE_SIZE : len; memcpy(vdec->config, data, vdec->config_len); } + +void vdec_set_duration(s32 duration) +{ + vdec_frame_rate_uevent(duration); +}
diff --git a/drivers/amvdec_ports/aml_vcodec_adapt.h b/drivers/amvdec_ports/aml_vcodec_adapt.h index b86cbff..c8641ce 100644 --- a/drivers/amvdec_ports/aml_vcodec_adapt.h +++ b/drivers/amvdec_ports/aml_vcodec_adapt.h
@@ -27,13 +27,12 @@ #include "aml_vcodec_drv.h" struct aml_vdec_adapt { - enum vformat_e format; + int format; void *vsi; int32_t failure; uint32_t inst_addr; unsigned int signaled; struct aml_vcodec_ctx *ctx; - struct platform_device *dev; wait_queue_head_t wq; struct file *filp; struct vdec_s *vdec; @@ -41,8 +40,7 @@ struct dec_sysinfo dec_prop; struct v4l2_config_parm config; int video_type; - char *recv_name; - int vfm_path; + char *frm_name; }; int video_decoder_init(struct aml_vdec_adapt *ada_ctx); @@ -53,7 +51,7 @@ const char *buf, unsigned int count); int vdec_vframe_write(struct aml_vdec_adapt *ada_ctx, - const char *buf, unsigned int count, u64 timestamp); + const char *buf, unsigned int count, u64 timestamp, ulong meta_ptr); void vdec_vframe_input_free(void *priv, u32 handle); @@ -73,5 +71,9 @@ int vdec_frame_number(struct aml_vdec_adapt *ada_ctx); +int vdec_get_instance_num(void); + +void vdec_set_duration(s32 duration); + #endif /* VDEC_ADAPT_H */
diff --git a/drivers/amvdec_ports/aml_vcodec_dec.c b/drivers/amvdec_ports/aml_vcodec_dec.c index afebb7a..2bbfb6e 100644 --- a/drivers/amvdec_ports/aml_vcodec_dec.c +++ b/drivers/amvdec_ports/aml_vcodec_dec.c
@@ -20,27 +20,41 @@ #include <media/v4l2-event.h> #include <media/v4l2-mem2mem.h> #include <media/videobuf2-dma-contig.h> +#include <media/videobuf2-dma-sg.h> -#include "aml_vcodec_drv.h" -#include "aml_vcodec_dec.h" -//#include "aml_vcodec_intr.h" -#include "aml_vcodec_util.h" -#include "vdec_drv_if.h" #include <linux/delay.h> #include <linux/atomic.h> #include <linux/crc32.h> -#include "aml_vcodec_adapt.h" +#include <linux/sched.h> #include <linux/spinlock.h> +#include <linux/amlogic/meson_uvm_core.h> +#include <linux/scatterlist.h> +#include <linux/sched/clock.h> +#include <linux/highmem.h> +#include <uapi/linux/sched/types.h> -#include "aml_vcodec_vfm.h" +#include "aml_vcodec_drv.h" +#include "aml_vcodec_dec.h" +#include "aml_vcodec_util.h" +#include "vdec_drv_if.h" +#include "aml_vcodec_adapt.h" +#include "aml_vcodec_vpp.h" +#include "aml_vcodec_ge2d.h" + #include "../frame_provider/decoder/utils/decoder_bmmu_box.h" #include "../frame_provider/decoder/utils/decoder_mmu_box.h" +#include "../common/chips/decoder_cpu_ver_info.h" +#include "utils/common.h" +#include "../frame_provider/decoder/utils/vdec_sync.h" + #define KERNEL_ATRACE_TAG KERNEL_ATRACE_TAG_V4L2 #include <trace/events/meson_atrace.h> -#define OUT_FMT_IDX 0 //default h264 -#define CAP_FMT_IDX 8 //capture nv21 + +#define OUT_FMT_IDX (0) //default h264 +#define CAP_FMT_IDX (9) //capture nv21 +#define CAP_FMT_I420_IDX (12) //use for mjpeg #define AML_VDEC_MIN_W 64U #define AML_VDEC_MIN_H 64U @@ -49,8 +63,12 @@ #define V4L2_CID_USER_AMLOGIC_BASE (V4L2_CID_USER_BASE + 0x1100) #define AML_V4L2_SET_DRMMODE (V4L2_CID_USER_AMLOGIC_BASE + 0) +#define AML_V4L2_GET_INPUT_BUFFER_NUM (V4L2_CID_USER_AMLOGIC_BASE + 1) +#define AML_V4L2_SET_DURATION (V4L2_CID_USER_AMLOGIC_BASE + 2) +#define AML_V4L2_GET_FILMGRAIN_INFO (V4L2_CID_USER_AMLOGIC_BASE + 3) #define WORK_ITEMS_MAX (32) +#define MAX_DI_INSTANCE (2) //#define USEC_PER_SEC 1000000 @@ -62,70 +80,89 @@ static struct aml_video_fmt aml_video_formats[] = { { + .name = "H.264", .fourcc = V4L2_PIX_FMT_H264, .type = AML_FMT_DEC, .num_planes = 1, }, { + .name = "H.265", .fourcc = V4L2_PIX_FMT_HEVC, .type = AML_FMT_DEC, .num_planes = 1, }, { + .name = "VP9", .fourcc = V4L2_PIX_FMT_VP9, .type = AML_FMT_DEC, .num_planes = 1, }, { + .name = "MPEG1", .fourcc = V4L2_PIX_FMT_MPEG1, .type = AML_FMT_DEC, .num_planes = 1, }, { + .name = "MPEG2", .fourcc = V4L2_PIX_FMT_MPEG2, .type = AML_FMT_DEC, .num_planes = 1, }, { + .name = "MPEG4", .fourcc = V4L2_PIX_FMT_MPEG4, .type = AML_FMT_DEC, .num_planes = 1, }, { + .name = "MJPEG", .fourcc = V4L2_PIX_FMT_MJPEG, .type = AML_FMT_DEC, .num_planes = 1, }, { + .name = "AV1", .fourcc = V4L2_PIX_FMT_AV1, .type = AML_FMT_DEC, .num_planes = 1, }, { + .name = "NV21", .fourcc = V4L2_PIX_FMT_NV21, .type = AML_FMT_FRAME, .num_planes = 1, }, { + .name = "NV21M", .fourcc = V4L2_PIX_FMT_NV21M, .type = AML_FMT_FRAME, .num_planes = 2, }, { + .name = "NV12", .fourcc = V4L2_PIX_FMT_NV12, .type = AML_FMT_FRAME, .num_planes = 1, }, { + .name = "NV12M", .fourcc = V4L2_PIX_FMT_NV12M, .type = AML_FMT_FRAME, .num_planes = 2, }, { + .name = "YUV420", .fourcc = V4L2_PIX_FMT_YUV420, .type = AML_FMT_FRAME, .num_planes = 1, }, + { + .name = "YUV420M", + .fourcc = V4L2_PIX_FMT_YUV420M, + .type = AML_FMT_FRAME, + .num_planes = 2, + }, }; static const struct aml_codec_framesizes aml_vdec_framesizes[] = { @@ -165,6 +202,11 @@ AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, }, { + .fourcc = V4L2_PIX_FMT_AV1, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, + }, + { .fourcc = V4L2_PIX_FMT_NV21, .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, @@ -184,16 +226,44 @@ .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, }, + { + .fourcc = V4L2_PIX_FMT_YUV420, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, + }, + { + .fourcc = V4L2_PIX_FMT_YUV420M, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, + }, }; #define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(aml_vdec_framesizes) #define NUM_FORMATS ARRAY_SIZE(aml_video_formats) extern bool multiplanar; -extern bool dump_capture_frame; +extern int dump_capture_frame; +extern int bypass_vpp; +extern int bypass_ge2d; +extern bool support_format_I420; +extern bool support_mjpeg; +extern int bypass_progressive; +extern int force_enable_nr; +extern int force_enable_di_local_buffer; +extern int max_di_instance; +extern int bypass_nr_flag; extern int dmabuf_fd_install_data(int fd, void* data, u32 size); extern bool is_v4l2_buf_file(struct file *file); +extern int get_double_write_ratio(int dw_mode); +static void box_release(struct kref *kref); +static struct internal_comp_buf* vb_to_comp(struct aml_vcodec_ctx *ctx, + struct vb2_buffer *vb); +static void update_ctx_dimension(struct aml_vcodec_ctx *ctx, u32 type); +static void copy_v4l2_format_dimention(struct v4l2_pix_format_mplane *pix_mp, + struct v4l2_pix_format *pix, + struct aml_q_data *q_data, + u32 type); static ulong aml_vcodec_ctx_lock(struct aml_vcodec_ctx *ctx) { @@ -209,6 +279,23 @@ spin_unlock_irqrestore(&ctx->slock, flags); } +static ulong dmabuf_contiguous_size(struct sg_table *sgt) +{ + struct scatterlist *s; + dma_addr_t expected = sg_dma_address(sgt->sgl); + ulong size = 0; + u32 i; + + for_each_sg(sgt->sgl, s, sgt->nents, i) { + if (sg_dma_address(s) != expected) + break; + expected = sg_dma_address(s) + sg_dma_len(s); + size += sg_dma_len(s); + } + + return size; +} + static struct aml_video_fmt *aml_vdec_find_format(struct v4l2_format *f) { struct aml_video_fmt *fmt; @@ -236,16 +323,6 @@ { struct v4l2_event event = {0}; - if (ctx->receive_cmd_stop && - changes != V4L2_EVENT_SRC_CH_RESOLUTION && - changes != V4L2_EVENT_SEND_EOS) { - ctx->state = AML_STATE_ABORT; - ATRACE_COUNTER("v4l2_state", ctx->state); - changes = V4L2_EVENT_REQUEST_EXIT; - v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, - "vcodec state (AML_STATE_ABORT)\n"); - } - switch (changes) { case V4L2_EVENT_SRC_CH_RESOLUTION: case V4L2_EVENT_SRC_CH_HDRINFO: @@ -277,11 +354,176 @@ aml_decoder_flush(ctx->ada_ctx); } -static void aml_vdec_pic_info_update(struct aml_vcodec_ctx *ctx) +/* Conditions: + * Always connect VPP for mpeg2 and h264 when the stream size is under 2K. + * Always connect VPP for hevc/av1/vp9 when color space is not SDR and + * stream size is under 2K. + * For DV, need application to notify V4L2 driver to enforce the color space + * conversion. Plan to do it through a system node. + * Do not connect VPP in other cases. + */ +static bool vpp_needed(struct aml_vcodec_ctx *ctx, u32* mode) { - unsigned int dpbsize = 0; - int ret; + int width = ctx->picinfo.coded_width; + int height = ctx->picinfo.coded_height; + int size = 1920 * 1088; + if (bypass_vpp) + return false; + + if (!ctx->vpp_cfg.enable_nr && + (ctx->picinfo.field == V4L2_FIELD_NONE)) { + return false; + } + + if (!ctx->vpp_cfg.enable_nr && + (ctx->output_pix_fmt == V4L2_PIX_FMT_HEVC)) { + if (is_over_size(width, height, size)) { + return false; + } + } + + if ((ctx->output_pix_fmt == V4L2_PIX_FMT_H264) && + (ctx->picinfo.field != V4L2_FIELD_NONE)) { + if (is_over_size(width, height, size)) { + return false; + } + } + + if (ctx->vpp_cfg.enable_nr) { + if (ctx->vpp_cfg.enable_local_buf) + *mode = VPP_MODE_NOISE_REDUC_LOCAL; + else + *mode = VPP_MODE_NOISE_REDUC; + } else { + if (ctx->vpp_cfg.enable_local_buf) + *mode = VPP_MODE_DI_LOCAL; + else + *mode = VPP_MODE_DI; + } + +#if 0//enable later + if (ctx->colorspace != V4L2_COLORSPACE_DEFAULT && + !is_over_size(width, height, size)) { + if (ctx->vpp_cfg.enable_local_buf) + *mode = VPP_MODE_COLOR_CONV_LOCAL; + else + *mode = VPP_MODE_COLOR_CONV; + } +#endif + + return true; +} + +static bool ge2d_needed(struct aml_vcodec_ctx *ctx, u32* mode) +{ + bool enable_fence = (ctx->config.parm.dec.cfg.low_latency_mode & 2) ? 1 : 0; + + if ((get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T7) && enable_fence) { + return false; + } + + if (bypass_ge2d) + return false; + + if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T7) { + if ((ctx->output_pix_fmt != V4L2_PIX_FMT_H264) && + (ctx->output_pix_fmt != V4L2_PIX_FMT_MPEG1) && + (ctx->output_pix_fmt != V4L2_PIX_FMT_MPEG2) && + (ctx->output_pix_fmt != V4L2_PIX_FMT_MPEG4) && + (ctx->output_pix_fmt != V4L2_PIX_FMT_MJPEG)) { + return false; + } + } else if (ctx->output_pix_fmt != V4L2_PIX_FMT_MJPEG) { + return false; + } + + if (ctx->picinfo.field != V4L2_FIELD_NONE) { + return false; + } + + if ((ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12) || + (ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12M)) + *mode = GE2D_MODE_CONVERT_NV12; + else if ((ctx->cap_pix_fmt == V4L2_PIX_FMT_NV21) || + (ctx->cap_pix_fmt == V4L2_PIX_FMT_NV21M)) + *mode = GE2D_MODE_CONVERT_NV21; + else + *mode = GE2D_MODE_CONVERT_NV21; + + *mode |= GE2D_MODE_CONVERT_LE; + + return true; +} + +static u32 v4l_buf_size_decision(struct aml_vcodec_ctx *ctx) +{ + u32 mode, total_size; + struct vdec_pic_info *picinfo = &ctx->picinfo; + struct aml_vpp_cfg_infos *vpp = &ctx->vpp_cfg; + struct aml_ge2d_cfg_infos *ge2d = &ctx->ge2d_cfg; + + if (vpp_needed(ctx, &mode)) { + vpp->mode = mode; + vpp->fmt = ctx->cap_pix_fmt; + vpp->is_drm = ctx->is_drm_mode; + vpp->buf_size = aml_v4l2_vpp_get_buf_num(vpp->mode) + + picinfo->vpp_margin; + + if (picinfo->field == V4L2_FIELD_NONE) { + vpp->is_prog = true; + vpp->buf_size = 0; + } else { + vpp->is_prog = false; + /* for between with dec & vpp. */ + picinfo->dpb_margin = 2; + } + + if (vpp->is_prog && + !vpp->enable_local_buf && + bypass_progressive) { + vpp->is_bypass_p = true; + } + ctx->vpp_is_need = true; + } else { + vpp->buf_size = 0; + ctx->vpp_is_need = false; + } + + if (ge2d_needed(ctx, &mode)) { + ge2d->mode = mode; + ge2d->buf_size = 4 + picinfo->dpb_margin; + ctx->ge2d_is_need = true; + picinfo->dpb_margin = 2; + } else { + ge2d->buf_size = 0; + ctx->ge2d_is_need = false; + } + + ctx->dpb_size = picinfo->dpb_frames + picinfo->dpb_margin; + ctx->vpp_size = vpp->buf_size; + ctx->ge2d_size = ge2d->buf_size; + + total_size = ctx->dpb_size + ctx->vpp_size + ctx->ge2d_size; + + if (total_size > V4L_CAP_BUFF_MAX) { + if (ctx->ge2d_size) { + ctx->dpb_size = V4L_CAP_BUFF_MAX - ctx->ge2d_size - ctx->vpp_size; + } else if (ctx->vpp_size) { + ctx->dpb_size = V4L_CAP_BUFF_MAX - ctx->vpp_size; + } else { + ctx->dpb_size = V4L_CAP_BUFF_MAX; + } + picinfo->dpb_margin = ctx->dpb_size - picinfo->dpb_frames; + total_size = V4L_CAP_BUFF_MAX; + } + vdec_if_set_param(ctx, SET_PARAM_PIC_INFO, picinfo); + + return total_size; +} + +void aml_vdec_pic_info_update(struct aml_vcodec_ctx *ctx) +{ if (vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, &ctx->last_decoded_picinfo)) { v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "Cannot get param : GET_PARAM_PICTURE_INFO ERR\n"); @@ -309,287 +551,277 @@ ctx->last_decoded_picinfo.coded_width, ctx->last_decoded_picinfo.coded_width); - ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize); - if (dpbsize == 0) - v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, - "Incorrect dpb size, ret=%d\n", ret); - - /* update picture information */ - ctx->dpb_size = dpbsize; ctx->picinfo = ctx->last_decoded_picinfo; -} -static bool aml_check_inst_quit(struct aml_vcodec_dev *dev, - struct aml_vcodec_ctx * inst, u32 id) -{ - struct aml_vcodec_ctx *ctx = NULL; - bool ret = true; + if (ctx->vpp_is_need) + ctx->vpp_cfg.is_vpp_reset = true; - if (dev == NULL) - return false; + v4l_buf_size_decision(ctx); - mutex_lock(&dev->dev_mutex); - - if (list_empty(&dev->ctx_list)) { - v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, - "v4l inst list is empty.\n"); - ret = true; - goto out; - } - - list_for_each_entry(ctx, &dev->ctx_list, list) { - if ((ctx == inst) && (ctx->id == id)) { - ret = ctx->receive_cmd_stop ? true : false; - goto out; - } - } -out: - mutex_unlock(&dev->dev_mutex); - - return ret; + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, + "Update picture buffer count: dec:%u, vpp:%u, ge2d:%u, margin:%u, total:%u\n", + ctx->picinfo.dpb_frames, ctx->vpp_size, ctx->ge2d_size, + ctx->picinfo.dpb_margin, + CTX_BUF_TOTAL(ctx)); } void vdec_frame_buffer_release(void *data) { struct file_private_data *priv_data = (struct file_private_data *) data; - struct aml_vcodec_dev *dev = (struct aml_vcodec_dev *) - priv_data->vb_handle; - struct aml_vcodec_ctx *inst = (struct aml_vcodec_ctx *) + struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *) priv_data->v4l_dec_ctx; - u32 id = priv_data->v4l_inst_id; + struct aml_video_dec_buf *vb = (struct aml_video_dec_buf *) + priv_data->vb_handle; + struct uvm_hook_mod_info *uvm = NULL; - if (aml_check_inst_quit(dev, inst, id)) { - struct vframe_s *vf = &priv_data->vf; - - v4l_dbg(0, V4L_DEBUG_CODEC_BUFMGR, - "[%d]: vf idx: %d, bmmu idx: %d, bmmu_box: %lx\n", - id, vf->index, vf->mm_box.bmmu_idx, - (ulong) vf->mm_box.bmmu_box); - - v4l_dbg(0, V4L_DEBUG_CODEC_BUFMGR, - "[%d]: vf idx: %d, mmu_idx: %d, mmu_box: %lx\n", - id, vf->index, vf->mm_box.mmu_idx, - (ulong) vf->mm_box.mmu_box); - - if (decoder_bmmu_box_valide_check(vf->mm_box.bmmu_box)) { - decoder_bmmu_box_free_idx(vf->mm_box.bmmu_box, - vf->mm_box.bmmu_idx); - decoder_bmmu_try_to_release_box(vf->mm_box.bmmu_box); - } - - if (decoder_mmu_box_valide_check(vf->mm_box.mmu_box)) { - decoder_mmu_box_free_idx(vf->mm_box.mmu_box, - vf->mm_box.mmu_idx); - decoder_mmu_try_to_release_box(vf->mm_box.mmu_box); - } - + if (ctx && ctx->uvm_proxy) { + uvm = &ctx->uvm_proxy[vb->internal_index]; + uvm->free(uvm->arg); } memset(data, 0, sizeof(struct file_private_data)); kfree(data); } -int get_fb_from_queue(struct aml_vcodec_ctx *ctx, struct vdec_v4l2_buffer **out_fb) +static void v4l2_buff_done(struct vb2_v4l2_buffer *buf, enum vb2_buffer_state state) { + struct aml_vcodec_ctx *ctx = vb2_get_drv_priv(buf->vb2_buf.vb2_queue); + + mutex_lock(&ctx->buff_done_lock); + if (buf->vb2_buf.state != VB2_BUF_STATE_ACTIVE) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "vb is not active state = %d!\n", + buf->vb2_buf.state); + mutex_unlock(&ctx->buff_done_lock); + return; + } + v4l2_m2m_buf_done(buf, state); + mutex_unlock(&ctx->buff_done_lock); +} + +static void comp_buf_set_vframe(struct aml_vcodec_ctx *ctx, + struct vb2_buffer *vb, + struct vframe_s *vf) +{ + dmabuf_set_vframe(vb->planes[0].dbuf, vf, VF_SRC_DECODER); +} + +static void fb_map_table_clean(struct aml_vcodec_ctx *ctx) +{ + int i; ulong flags; - struct vb2_buffer *dst_buf = NULL; - struct vdec_v4l2_buffer *pfb; - struct aml_video_dec_buf *dst_buf_info, *info; - struct vb2_v4l2_buffer *dst_vb2_v4l2; flags = aml_vcodec_ctx_lock(ctx); - if (ctx->state == AML_STATE_ABORT) { - aml_vcodec_ctx_unlock(ctx, flags); - return -1; + for (i = 0; i < ARRAY_SIZE(ctx->fb_map); i++) { + ctx->fb_map[i].addr = 0; + ctx->fb_map[i].vframe = NULL; + ctx->fb_map[i].task = NULL; + ctx->fb_map[i].icomp = 0; } - dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); - if (!dst_buf) { - aml_vcodec_ctx_unlock(ctx, flags); - return -1; - } - - v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, - "vbuf idx: %d, state: %d, ready: %d\n", - dst_buf->index, dst_buf->state, - v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx)); - - dst_vb2_v4l2 = container_of(dst_buf, struct vb2_v4l2_buffer, vb2_buf); - dst_buf_info = container_of(dst_vb2_v4l2, struct aml_video_dec_buf, vb); - - pfb = &dst_buf_info->frame_buffer; - pfb->buf_idx = dst_buf->index; - pfb->num_planes = dst_buf->num_planes; - pfb->status = FB_ST_NORMAL; - if (dst_buf->num_planes == 1) { - pfb->m.mem[0].dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); - pfb->m.mem[0].addr = dma_to_phys(v4l_get_dev_from_codec_mm(), pfb->m.mem[0].dma_addr); - pfb->m.mem[0].size = ctx->picinfo.y_len_sz + ctx->picinfo.c_len_sz; - pfb->m.mem[0].offset = ctx->picinfo.y_len_sz; - v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, - "idx: %u, 1 plane, y:(0x%lx, %d)\n", dst_buf->index, - pfb->m.mem[0].addr, pfb->m.mem[0].size); - } else if (dst_buf->num_planes == 2) { - pfb->m.mem[0].dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); - pfb->m.mem[0].addr = dma_to_phys(v4l_get_dev_from_codec_mm(), pfb->m.mem[0].dma_addr); - pfb->m.mem[0].size = ctx->picinfo.y_len_sz; - pfb->m.mem[0].offset = 0; - - pfb->m.mem[1].dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 1); - pfb->m.mem[1].addr = dma_to_phys(v4l_get_dev_from_codec_mm(), pfb->m.mem[1].dma_addr); - pfb->m.mem[1].size = ctx->picinfo.c_len_sz; - pfb->m.mem[1].offset = ctx->picinfo.c_len_sz >> 1; - v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, - "idx: %u, 2 planes, y:(0x%lx, %d), c:(0x%lx, %d)\n", dst_buf->index, - pfb->m.mem[0].addr, pfb->m.mem[0].size, - pfb->m.mem[1].addr, pfb->m.mem[1].size); - } else { - pfb->m.mem[0].dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); - pfb->m.mem[0].addr = dma_to_phys(v4l_get_dev_from_codec_mm(), pfb->m.mem[0].dma_addr); - pfb->m.mem[0].size = ctx->picinfo.y_len_sz; - pfb->m.mem[0].offset = 0; - - pfb->m.mem[1].dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 1); - pfb->m.mem[1].addr = dma_to_phys(v4l_get_dev_from_codec_mm(), pfb->m.mem[2].dma_addr); - pfb->m.mem[1].size = ctx->picinfo.c_len_sz >> 1; - pfb->m.mem[1].offset = 0; - - pfb->m.mem[2].dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 2); - pfb->m.mem[2].addr = dma_to_phys(v4l_get_dev_from_codec_mm(), pfb->m.mem[3].dma_addr); - pfb->m.mem[2].size = ctx->picinfo.c_len_sz >> 1; - pfb->m.mem[2].offset = 0; - - v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, - "idx: %u, 3 planes, y:(0x%lx, %d), u:(0x%lx, %d), v:(0x%lx, %d)\n", - dst_buf->index, - pfb->m.mem[0].addr, pfb->m.mem[0].size, - pfb->m.mem[1].addr, pfb->m.mem[1].size, - pfb->m.mem[2].addr, pfb->m.mem[2].size); - } - - dst_buf_info->used = true; - ctx->buf_used_count++; - - *out_fb = pfb; - - info = container_of(pfb, struct aml_video_dec_buf, frame_buffer); - - ctx->cap_pool.dec++; - ctx->cap_pool.seq[ctx->cap_pool.out++] = - (V4L_CAP_BUFF_IN_DEC << 16 | dst_buf->index); - v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); - aml_vcodec_ctx_unlock(ctx, flags); - return 0; + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "%s done\n", __func__); } -EXPORT_SYMBOL(get_fb_from_queue); -int put_fb_to_queue(struct aml_vcodec_ctx *ctx, struct vdec_v4l2_buffer *in_fb) +static void fb_map_table_hold(struct aml_vcodec_ctx *ctx, + struct vb2_buffer *vb, + struct vframe_s *vf, + struct task_chain_s *task, + u32 icomp) { - struct aml_video_dec_buf *dstbuf; + int i; + ulong addr, flags; - v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, "%s\n", __func__); + flags = aml_vcodec_ctx_lock(ctx); - if (in_fb == NULL) { - v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "No free frame buffer\n"); - return -1; + addr = vb2_dma_contig_plane_dma_addr(vb, 0); + + for (i = 0; i < ARRAY_SIZE(ctx->fb_map); i++) { + if (!ctx->fb_map[i].addr || + (addr == ctx->fb_map[i].addr)) { + ctx->fb_map[i].task = task; + ctx->fb_map[i].addr = addr; + ctx->fb_map[i].vframe = vf; + ctx->fb_map[i].icomp = icomp; + + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + "%s, task:%px, vf:%px, addr:%lx, icomp:%u\n", + __func__, task, vf, addr, icomp); + break; + } } - dstbuf = container_of(in_fb, struct aml_video_dec_buf, frame_buffer); + aml_vcodec_ctx_unlock(ctx, flags); - mutex_lock(&ctx->lock); - - if (!dstbuf->used) - goto out; - - v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, - "status=%x queue id=%d to rdy_queue\n", - in_fb->status, dstbuf->vb.vb2_buf.index); - - v4l2_m2m_buf_queue(ctx->m2m_ctx, &dstbuf->vb); - - dstbuf->used = false; -out: - mutex_unlock(&ctx->lock); - - return 0; - + if (i >= ARRAY_SIZE(ctx->fb_map)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "%s, table is full. addr:%lx, vf:%px\n", + __func__, addr, vf); + } } -EXPORT_SYMBOL(put_fb_to_queue); -void trans_vframe_to_user(struct aml_vcodec_ctx *ctx, struct vdec_v4l2_buffer *fb) +static void fb_map_table_fetch(struct aml_vcodec_ctx *ctx, + struct vb2_buffer *vb, + struct vframe_s **vf, + struct task_chain_s **task, + u32 *icomp) { - struct aml_video_dec_buf *dstbuf = NULL; - struct vb2_buffer *vb2_buf = NULL; - struct vframe_s *vf = (struct vframe_s *)fb->vf_handle; + int i; + ulong addr, flags; + + flags = aml_vcodec_ctx_lock(ctx); + + addr = vb2_dma_contig_plane_dma_addr(vb, 0); + + for (i = 0; i < ARRAY_SIZE(ctx->fb_map); i++) { + if (addr == ctx->fb_map[i].addr) { + *task = ctx->fb_map[i].task; + *vf = ctx->fb_map[i].vframe; + *icomp = ctx->fb_map[i].icomp; + + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + "%s, task:%px, vf:%px, addr:%lx, icomp:%u\n", + __func__, task, vf, addr, *icomp); + + ctx->fb_map[i].task = NULL; + ctx->fb_map[i].vframe = NULL; + ctx->fb_map[i].addr = 0; + ctx->fb_map[i].icomp = 0; + break; + } + } + + aml_vcodec_ctx_unlock(ctx, flags); + + if (i >= ARRAY_SIZE(ctx->fb_map)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, + "%s, there is new addr:%lx.\n", + __func__, addr); + } +} + +static bool is_fb_mapped(struct aml_vcodec_ctx *ctx, ulong addr) +{ + int i; + ulong flags; + + flags = aml_vcodec_ctx_lock(ctx); + + for (i = 0; i < ARRAY_SIZE(ctx->fb_map); i++) { + if (addr == ctx->fb_map[i].addr) + break; + } + + aml_vcodec_ctx_unlock(ctx, flags); + + if (i >= ARRAY_SIZE(ctx->fb_map)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + "%s, addr:%lx isn't output.\n", + __func__, addr); + return false; + } + + return true; +} + + static void post_frame_to_upper(struct aml_vcodec_ctx *ctx, + struct vdec_v4l2_buffer *fb) +{ + struct aml_video_dec_buf *dstbuf = + container_of(fb, struct aml_video_dec_buf, frame_buffer); + struct vb2_buffer *vb2_buf = &dstbuf->vb.vb2_buf; + struct vframe_s *vf = fb->vframe; + struct vb2_v4l2_buffer *vb2_v4l2 = NULL; + + vf->index_disp = ctx->index_disp; + ctx->index_disp++; + ctx->post_to_upper_done = false; v4l_dbg(ctx, V4L_DEBUG_CODEC_OUTPUT, - "FROM (%s %s) vf: %lx, ts: %llu, idx: %d, " + "OUT_BUFF (%s, st:%d, seq:%d) vb:(%d, %px), vf:(%d, %px), ts:%lld, " "Y:(%lx, %u) C/U:(%lx, %u) V:(%lx, %u)\n", - vf_get_provider(ctx->ada_ctx->recv_name)->name, - ctx->ada_ctx->vfm_path != FRAME_BASE_PATH_V4L_VIDEO ? "OSD" : "VIDEO", - (ulong) vf, vf->timestamp, vf->index, + ctx->ada_ctx->frm_name, fb->status, vf->index_disp, + vb2_buf->index, vb2_buf, + vf->index & 0xff, vf, + vf->timestamp, fb->m.mem[0].addr, fb->m.mem[0].size, fb->m.mem[1].addr, fb->m.mem[1].size, fb->m.mem[2].addr, fb->m.mem[2].size); - dstbuf = container_of(fb, struct aml_video_dec_buf, frame_buffer); - vb2_buf = &dstbuf->vb.vb2_buf; + vb2_v4l2 = container_of(vb2_buf, struct vb2_v4l2_buffer, vb2_buf); if (dstbuf->frame_buffer.num_planes == 1) { - vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 0, fb->m.mem[0].bytes_used); + vb2_set_plane_payload(vb2_buf, 0, fb->m.mem[0].bytes_used); } else if (dstbuf->frame_buffer.num_planes == 2) { - vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 0, fb->m.mem[0].bytes_used); - vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 1, fb->m.mem[1].bytes_used); + vb2_set_plane_payload(vb2_buf, 0, fb->m.mem[0].bytes_used); + vb2_set_plane_payload(vb2_buf, 1, fb->m.mem[1].bytes_used); } - dstbuf->vb.vb2_buf.timestamp = vf->timestamp; - dstbuf->ready_to_display = true; + vb2_buf->timestamp = vf->timestamp; + dstbuf->vb.flags |= vf->frame_type; - if (dump_capture_frame) { + if ((ctx->picinfo.field == V4L2_FIELD_INTERLACED) && (!ctx->vpp_is_need)) { + vb2_v4l2->field = V4L2_FIELD_INTERLACED; + } + + do { + unsigned int dw_mode = VDEC_DW_NO_AFBC; struct file *fp; - fp = filp_open("/data/dec_dump.raw", + char file_name[32] = {0}; + + if (!dump_capture_frame || ctx->is_drm_mode) + break; + if (vdec_if_get_param(ctx, GET_PARAM_DW_MODE, &dw_mode)) + break; + if (dw_mode == VDEC_DW_AFBC_ONLY) + break; + + snprintf(file_name, 32, "/data/dec_dump_%ux%u.raw", vf->width, vf->height); + + fp = filp_open(file_name, O_CREAT | O_RDWR | O_LARGEFILE | O_APPEND, 0600); + if (!IS_ERR(fp)) { - struct vb2_buffer *vb = &dstbuf->vb.vb2_buf; - kernel_write(fp,vb2_plane_vaddr(vb, 0),vb->planes[0].bytesused, 0); + struct vb2_buffer *vb = vb2_buf; + + kernel_write(fp,vb2_plane_vaddr(vb, 0),vb->planes[0].length, 0); if (dstbuf->frame_buffer.num_planes == 2) kernel_write(fp,vb2_plane_vaddr(vb, 1), - vb->planes[1].bytesused, 0); + vb->planes[1].length, 0); pr_info("dump idx: %d %dx%d\n", dump_capture_frame, vf->width, vf->height); - dump_capture_frame = false; + dump_capture_frame--; filp_close(fp, NULL); } - } + } while(0); + + ATRACE_COUNTER("VC_OUT_VSINK-1.submit", vb2_buf->index); + ATRACE_COUNTER("V_ST_VSINK-input_buffering", vdec_frame_number(ctx->ada_ctx)); if (vf->flag & VFRAME_FLAG_EMPTY_FRAME_V4L) { dstbuf->vb.flags = V4L2_BUF_FLAG_LAST; if (dstbuf->frame_buffer.num_planes == 1) { - vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 0, 0); + vb2_set_plane_payload(vb2_buf, 0, 0); } else if (dstbuf->frame_buffer.num_planes == 2) { - vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 0, 0); - vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 1, 0); + vb2_set_plane_payload(vb2_buf, 0, 0); + vb2_set_plane_payload(vb2_buf, 1, 0); } ctx->has_receive_eos = true; v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, "recevie a empty frame. idx: %d, state: %d\n", - dstbuf->vb.vb2_buf.index, - dstbuf->vb.vb2_buf.state); - ATRACE_COUNTER("v4l2_eos", 0); + vb2_buf->index, vb2_buf->state); } v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, "receive vbuf idx: %d, state: %d\n", - dstbuf->vb.vb2_buf.index, - dstbuf->vb.vb2_buf.state); + vb2_buf->index, vb2_buf->state); if (vf->flag & VFRAME_FLAG_EMPTY_FRAME_V4L) { - if (ctx->q_data[AML_Q_DATA_SRC].resolution_changed) { + if (ctx->v4l_resolution_change) { /* make the run to stanby until new buffs to enque. */ ctx->v4l_codec_dpb_ready = false; ctx->reset_flag = V4L_RESET_MODE_LIGHT; + ctx->vpp_cfg.res_chg = true; /* * After all buffers containing decoded frames from @@ -606,50 +838,449 @@ if (dstbuf->vb.vb2_buf.state == VB2_BUF_STATE_ACTIVE) { /* binding vframe handle. */ - vf->flag |= VFRAME_FLAG_VIDEO_LINEAR; - ATRACE_COUNTER("v4l2_from", vf->index_disp); - dstbuf->privdata.vf = *vf; - dstbuf->privdata.vf.omx_index = - dstbuf->vb.vb2_buf.index; + if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T7) { + if (vf->canvas0_config[0].block_mode == CANVAS_BLKMODE_LINEAR) { + if ((ctx->output_pix_fmt != V4L2_PIX_FMT_H264) && + (ctx->output_pix_fmt != V4L2_PIX_FMT_MPEG1) && + (ctx->output_pix_fmt != V4L2_PIX_FMT_MPEG2) && + (ctx->output_pix_fmt != V4L2_PIX_FMT_MPEG4) && + (ctx->output_pix_fmt != V4L2_PIX_FMT_MJPEG)) { + vf->flag |= VFRAME_FLAG_VIDEO_LINEAR; + } + else { + if (fb->status == FB_ST_GE2D) + vf->flag |= VFRAME_FLAG_VIDEO_LINEAR; + } + } + } else { + if (vf->canvas0_config[0].block_mode == CANVAS_BLKMODE_LINEAR) + vf->flag |= VFRAME_FLAG_VIDEO_LINEAR; + } - v4l2_m2m_buf_done(&dstbuf->vb, VB2_BUF_STATE_DONE); + vf->omx_index = vf->index_disp; + dstbuf->privdata.vf = *vf; + + if (vb2_buf->memory == VB2_MEMORY_DMABUF) { + struct dma_buf * dma; + + dma = dstbuf->vb.vb2_buf.planes[0].dbuf; + if (dmabuf_is_uvm(dma)) { + /* only Y will contain vframe */ + comp_buf_set_vframe(ctx, vb2_buf, vf); + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + "set vf(%px) into %dth buf\n", + vf, vb2_buf->index); + } + } + + fb_map_table_hold(ctx, vb2_buf, vf, fb->task, dstbuf->internal_index); + + v4l2_buff_done(&dstbuf->vb, VB2_BUF_STATE_DONE); + + fb->status = FB_ST_DISPLAY; } mutex_lock(&ctx->state_lock); if (ctx->state == AML_STATE_FLUSHING && ctx->has_receive_eos) { ctx->state = AML_STATE_FLUSHED; - ATRACE_COUNTER("v4l2_state", ctx->state); + ATRACE_COUNTER("V_ST_VSINK-state", ctx->state); v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, "vcodec state (AML_STATE_FLUSHED)\n"); } mutex_unlock(&ctx->state_lock); + if (ctx->post_to_upper_done == false) { + ctx->post_to_upper_done = true; + wake_up_interruptible(&ctx->post_done_wq); + } + ctx->decoded_frame_cnt++; } -static int get_display_buffer(struct aml_vcodec_ctx *ctx, struct vdec_v4l2_buffer **out) +static void fill_capture_done_cb(void *v4l_ctx, void *fb_ctx) { - int ret = -1; + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)v4l_ctx; + struct vdec_v4l2_buffer *fb = + (struct vdec_v4l2_buffer *)fb_ctx; + struct aml_video_dec_buf *aml_buff = + container_of(fb, struct aml_video_dec_buf, frame_buffer); + struct vb2_v4l2_buffer *vb = &aml_buff->vb; - v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, "%s\n", __func__); - - ret = vdec_if_get_param(ctx, GET_PARAM_DISP_FRAME_BUFFER, out); - if (ret) { - v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, - "Cannot get param : GET_PARAM_DISP_FRAME_BUFFER\n"); - return -1; + if (ctx->is_stream_off) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_INPUT, + "ignore buff idx: %d streamoff\n", fb->buf_idx); + return; } - if (!*out) { - v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, - "No display frame buffer\n"); - return -1; + ATRACE_COUNTER("VC_OUT_VSINK-0.receive", vb->vb2_buf.index); + + mutex_lock(&ctx->capture_buffer_lock); + kfifo_put(&ctx->capture_buffer, vb); + mutex_unlock(&ctx->capture_buffer_lock); + + aml_thread_post_task(ctx, AML_THREAD_CAPTURE); +} + +static void update_vdec_buf_plane(struct aml_vcodec_ctx *ctx, + struct vdec_v4l2_buffer *fb, + struct vb2_buffer *vb) +{ + int i; + char plane_n[3] = {'Y','U','V'}; + + fb->num_planes = vb->num_planes; + fb->buf_idx = vb->index; + + for (i = 0 ; i < vb->num_planes ; i++) { + fb->m.mem[i].addr = vb2_dma_contig_plane_dma_addr(vb, i); + fb->m.mem[i].dbuf = vb->planes[i].dbuf; + if (i == 0) { + //Y + if (vb->num_planes == 1) { + fb->m.mem[0].size = ctx->picinfo.y_len_sz + + ctx->picinfo.c_len_sz; + fb->m.mem[0].offset = ctx->picinfo.y_len_sz; + } else { + fb->m.mem[0].size = ctx->picinfo.y_len_sz; + fb->m.mem[0].offset = 0; + } + } else { + if (vb->num_planes == 2) { + //UV + fb->m.mem[1].size = ctx->picinfo.c_len_sz; + fb->m.mem[1].offset = ctx->picinfo.c_len_sz >> 1; + } else { + fb->m.mem[i].size = ctx->picinfo.c_len_sz >> 1; + fb->m.mem[i].offset = 0; + } + } + + v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, + "idx: %u, %c:(0x%lx, %d)\n", vb->index, + plane_n[i], fb->m.mem[i].addr, fb->m.mem[i].size); } +} + +static bool fb_token_insert(struct aml_vcodec_ctx *ctx, + ulong *token) +{ + ulong vb_handle; + int i; + + for (i = 0; i < ARRAY_SIZE(ctx->token_table); i++) { + if (ctx->token_table[i] && + (ctx->token_table[i] == *token)) { + return true; + } + } + + if (!v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx)) + return false; + + vb_handle = (ulong)v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); + + for (i = 0; i < ARRAY_SIZE(ctx->token_table); i++) { + if (!ctx->token_table[i]) { + ctx->token_table[i] = vb_handle; + break; + } + } + + if (i >= ARRAY_SIZE(ctx->token_table)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "%s, table is full. token:%lx\n", + __func__, vb_handle); + return false; + } + + *token = vb_handle; + + return true; +} + +static void fb_token_remove(struct aml_vcodec_ctx *ctx, + ulong token) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ctx->token_table); i++) { + if (token == ctx->token_table[i]) { + ctx->token_table[i] = 0; + break; + } + } + + if (i >= ARRAY_SIZE(ctx->token_table)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "%s, remove token err, token:%lx.\n", + __func__, token); + } +} + +static void fb_token_clean(struct aml_vcodec_ctx *ctx) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ctx->token_table); i++) { + ctx->token_table[i] = 0; + } + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "%s done\n", __func__); +} + +static bool fb_buff_query(struct aml_fb_ops *fb, ulong *token) +{ + struct aml_vcodec_ctx *ctx = + container_of(fb, struct aml_vcodec_ctx, fb_ops); + struct vb2_queue * que = v4l2_m2m_get_dst_vq(ctx->m2m_ctx); + bool ret = false; + ulong flags; + + if (!que->streaming) + return false; + + flags = aml_vcodec_ctx_lock(ctx); + + ret = fb_token_insert(ctx, token); + + aml_vcodec_ctx_unlock(ctx, flags); return ret; } +static void aml_task_chain_remove(struct aml_vcodec_ctx *ctx) +{ + struct task_chain_s *task, *tmp; + + list_for_each_entry_safe(task, tmp, &ctx->task_chain_pool, node) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, + "remove task chain:%d, %px\n", task->id, task); + list_del(&task->node); + task_chain_clean(task); + task_chain_release(task); + } +} + +static struct task_ops_s *get_v4l_sink_ops(void); + +static void aml_creat_pipeline(struct aml_vcodec_ctx *ctx, + struct vdec_v4l2_buffer *fb, + u32 requester) +{ + struct task_chain_s *task = fb->task; + /* + * line 1: dec <==> vpp <==> v4l-sink, for P / P + DI.NR. + * line 2: dec <==> vpp, vpp <==> v4l-sink, for I / I + DI.NR. + * line 3: dec <==> v4l-sink, only for P. + * line 4: dec <==> ge2d, ge2d <==> v4l-sink, used for fmt convert. + * line 5: dec <==> ge2d, ge2d <==>vpp, vpp <==> v4l-sink. + * line 6: dec <==> ge2d, ge2d <==> vpp <==> v4l-sink. + */ + + switch (requester) { + case AML_FB_REQ_DEC: + if (ctx->ge2d) { + /* dec <==> ge2d. */ + task->attach(task, get_ge2d_ops(), ctx->ge2d); + } else if (ctx->vpp) { + if (ctx->vpp->is_prog) { + /* dec <==> vpp <==> v4l-sink. */ + task->attach(task, get_v4l_sink_ops(), ctx); + task->attach(task, get_vpp_ops(), ctx->vpp); + } else { + /* dec <==> vpp. */ + task->attach(task, get_vpp_ops(), ctx->vpp); + } + } else { + /* dec <==> v4l-sink. */ + task->attach(task, get_v4l_sink_ops(), ctx); + } + break; + + case AML_FB_REQ_GE2D: + if (ctx->vpp) { + if (ctx->vpp->is_prog) { + /* ge2d <==> vpp <==> v4l-sink. */ + task->attach(task, get_v4l_sink_ops(), ctx); + task->attach(task, get_vpp_ops(), ctx->vpp); + task->attach(task, get_ge2d_ops(), ctx->ge2d); + } else { + /* ge2d <==> vpp. */ + task->attach(task, get_vpp_ops(), ctx->vpp); + task->attach(task, get_ge2d_ops(), ctx->ge2d); + } + } else { + /* ge2d <==> v4l-sink. */ + task->attach(task, get_v4l_sink_ops(), ctx); + task->attach(task, get_ge2d_ops(), ctx->ge2d); + } + break; + + case AML_FB_REQ_VPP: + /* vpp <==> v4l-sink. */ + task->attach(task, get_v4l_sink_ops(), ctx); + task->attach(task, get_vpp_ops(), ctx->vpp); + break; + + default: + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "unsupport requester %x\n", requester); + } +} + +static int fb_buff_from_queue(struct aml_fb_ops *fb_ops, + ulong token, struct vdec_v4l2_buffer **out_fb, + u32 requester) +{ + struct aml_vcodec_ctx *ctx = + container_of(fb_ops, struct aml_vcodec_ctx, fb_ops); + struct aml_video_dec_buf *aml_buf = NULL; + struct vb2_v4l2_buffer *v4l_buf = NULL; + struct vdec_v4l2_buffer *fb = NULL; + u32 buf_status = 0; + ulong flags; + + flags = aml_vcodec_ctx_lock(ctx); + + if (ctx->is_stream_off) { + aml_vcodec_ctx_unlock(ctx, flags); + return -1; + } + + v4l_buf = (struct vb2_v4l2_buffer *) token; + if (!v4l_buf) { + aml_vcodec_ctx_unlock(ctx, flags); + return -1; + } + + aml_buf = container_of(v4l_buf, struct aml_video_dec_buf, vb); + + fb = &aml_buf->frame_buffer; + fb->buf_idx = v4l_buf->vb2_buf.index; + aml_buf->used = true; + ctx->buf_used_count++; + + if (requester == AML_FB_REQ_VPP) { + buf_status = V4L_CAP_BUFF_IN_VPP; + ctx->cap_pool.vpp++; + } else if (requester == AML_FB_REQ_DEC) { + buf_status = V4L_CAP_BUFF_IN_DEC; + ctx->cap_pool.dec++; + } else if (requester == AML_FB_REQ_GE2D) { + buf_status = V4L_CAP_BUFF_IN_GE2D; + ctx->cap_pool.ge2d++; + } + + ctx->cap_pool.seq[ctx->cap_pool.out++] = + (buf_status << 16 | fb->buf_idx); + + update_vdec_buf_plane(ctx, fb, &v4l_buf->vb2_buf); + + aml_creat_pipeline(ctx, fb, requester); + + fb_token_remove(ctx, token); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, + "vid:%d, task:%px, phy:%lx, state:%d, ready:%d, requester:%d\n", + fb->buf_idx, fb->task, fb->m.mem[0].addr, v4l_buf->vb2_buf.state, + v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx), requester); + + ATRACE_COUNTER("VC_IN_VSINK-3.require", v4l_buf->vb2_buf.index); + + *out_fb = fb; + + aml_vcodec_ctx_unlock(ctx, flags); + + return 0; +} + +static struct task_ops_s v4l_sink_ops = { + .type = TASK_TYPE_V4L_SINK, + .fill_buffer = fill_capture_done_cb, +}; + +static struct task_ops_s *get_v4l_sink_ops(void) +{ + return &v4l_sink_ops; +} + +void aml_vdec_basic_information(struct aml_vcodec_ctx *ctx) +{ + struct aml_q_data *outq = NULL; + struct aml_q_data *capq = NULL; + struct vdec_pic_info pic; + + if (vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, &pic)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "get pic info err\n"); + return; + } + + outq = aml_vdec_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + capq = aml_vdec_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + + pr_info("\n==== Show Basic Information ==== \n"); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, + "Format : %s\n", + outq->fmt->name); + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, + "Color space: %s\n", + capq->fmt->name); + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, + "Scan type : %s\n", + (pic.field == V4L2_FIELD_NONE) ? + "Progressive" : "Interlaced"); + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, + "Resolution : visible(%dx%d), coded(%dx%d)\n", + pic.visible_width, pic.visible_height, + pic.coded_width, pic.coded_height); + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, + "Buffer num : dec:%d, vpp:%d, ge2d:%d, margin:%d, total:%d\n", + ctx->picinfo.dpb_frames, ctx->vpp_size, ctx->ge2d_size, + ctx->picinfo.dpb_margin, CTX_BUF_TOTAL(ctx)); + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, + "Config : dw:%d, drm:%d, byp:%d, lc:%d, nr:%d, ge2d:%x\n", + ctx->config.parm.dec.cfg.double_write_mode, + ctx->is_drm_mode, + ctx->vpp_cfg.is_bypass_p, + ctx->vpp_cfg.enable_local_buf, + ctx->vpp_cfg.enable_nr, + ctx->ge2d_cfg.mode); +} + +void aml_buffer_status(struct aml_vcodec_ctx *ctx) +{ + struct vb2_v4l2_buffer *vb = NULL; + struct aml_video_dec_buf *aml_buff = NULL; + struct vdec_v4l2_buffer *fb = NULL; + struct vb2_queue *q = NULL; + ulong flags; + int i; + + flags = aml_vcodec_ctx_lock(ctx); + + q = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (!q->streaming) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "can't achieve buffers status before start streaming.\n"); + } + + pr_info("\n==== Show Buffer Status ======== \n"); + for (i = 0; i < q->num_buffers; ++i) { + vb = to_vb2_v4l2_buffer(q->bufs[i]); + aml_buff = container_of(vb, struct aml_video_dec_buf, vb); + fb = &aml_buff->frame_buffer; + + /* print out task chain status. */ + task_chain_show(fb->task); + } + + aml_vcodec_ctx_unlock(ctx, flags); +} + static void aml_check_dpb_ready(struct aml_vcodec_ctx *ctx) { if (!ctx->v4l_codec_dpb_ready) { @@ -660,12 +1291,26 @@ ctx->v4l_codec_dpb_ready = true; v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, - "dpb: %d, ready: %d, used: %d, dpb is ready: %s\n", - ctx->dpb_size, v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx), + "dpb: %d, vpp: %d, ready: %d, used: %d, dpb is ready: %s\n", + ctx->dpb_size, ctx->vpp_size, + v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx), ctx->cap_pool.out, ctx->v4l_codec_dpb_ready ? "yes" : "no"); } } +static void reconfig_vpp_status(struct aml_vcodec_ctx *ctx) +{ + if (bypass_nr_flag && + !ctx->vpp_cfg.is_prog && + ((ctx->vpp_cfg.mode == VPP_MODE_NOISE_REDUC_LOCAL) || + (ctx->vpp_cfg.mode == VPP_MODE_NOISE_REDUC))) { + ctx->vpp_cfg.enable_nr = 0; + ctx->vpp_cfg.enable_local_buf = 0; + + ctx->vpp_cfg.mode = VPP_MODE_DI; + } +} + static int is_vdec_ready(struct aml_vcodec_ctx *ctx) { struct aml_vcodec_dev *dev = ctx->dev; @@ -681,7 +1326,7 @@ mutex_lock(&ctx->state_lock); if (ctx->state == AML_STATE_PROBE) { ctx->state = AML_STATE_READY; - ATRACE_COUNTER("v4l2_state", ctx->state); + ATRACE_COUNTER("V_ST_VSINK-state", ctx->state); v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, "vcodec state (AML_STATE_READY)\n"); } @@ -693,7 +1338,7 @@ if (ctx->m2m_ctx->out_q_ctx.q.streaming && ctx->m2m_ctx->cap_q_ctx.q.streaming) { ctx->state = AML_STATE_ACTIVE; - ATRACE_COUNTER("v4l2_state", ctx->state); + ATRACE_COUNTER("V_ST_VSINK-state", ctx->state); v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, "vcodec state (AML_STATE_ACTIVE)\n"); } @@ -718,7 +1363,7 @@ return true; } -static void aml_wait_dpb_ready(struct aml_vcodec_ctx *ctx) +static void aml_wait_buf_ready(struct aml_vcodec_ctx *ctx) { ulong expires; @@ -733,34 +1378,75 @@ } ready_num = v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx); - if ((ready_num + ctx->buf_used_count) >= ctx->dpb_size) + if ((ready_num + ctx->buf_used_count) >= CTX_BUF_TOTAL(ctx)) ctx->v4l_codec_dpb_ready = true; } } +void dmabuff_recycle_worker(struct work_struct *work) +{ + struct aml_vcodec_ctx *ctx = + container_of(work, struct aml_vcodec_ctx, dmabuff_recycle_work); + struct vb2_v4l2_buffer *vb = NULL; + struct aml_video_dec_buf *buf = NULL; + unsigned long flags; + + for (;;) { + spin_lock_irqsave(&ctx->dmabuff_recycle_lock, flags); + if (!kfifo_get(&ctx->dmabuff_recycle, &vb)) { + spin_unlock_irqrestore(&ctx->dmabuff_recycle_lock, flags); + break; + } + spin_unlock_irqrestore(&ctx->dmabuff_recycle_lock, flags); + + buf = container_of(vb, struct aml_video_dec_buf, vb); + + if (ctx->is_out_stream_off) + continue; + + if (wait_event_interruptible_timeout + (ctx->wq, buf->used == false, + msecs_to_jiffies(200)) == 0) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "wait recycle dma buff timeout.\n"); + } + + v4l_dbg(ctx, V4L_DEBUG_CODEC_INPUT, + "recycle buff idx: %d, vbuf: %lx\n", vb->vb2_buf.index, + (ulong)sg_dma_address(buf->out_sgt->sgl)); + + ATRACE_COUNTER("VO_OUT_VSINK-2.write_secure_end", vb->vb2_buf.index); + + if (vb->vb2_buf.state != VB2_BUF_STATE_ERROR) + v4l2_buff_done(vb, buf->error ? VB2_BUF_STATE_ERROR : + VB2_BUF_STATE_DONE); + } +} + void aml_recycle_dma_buffers(struct aml_vcodec_ctx *ctx, u32 handle) { - struct vb2_v4l2_buffer *vb; - struct aml_video_dec_buf *buf; - struct vb2_queue *q; + struct aml_vcodec_dev *dev = ctx->dev; + struct vb2_v4l2_buffer *vb = NULL; + struct vb2_queue *q = NULL; int index = handle & 0xf; + unsigned long flags; if (ctx->is_out_stream_off) { v4l_dbg(ctx, V4L_DEBUG_CODEC_INPUT, "ignore buff idx: %d streamoff\n", index); return; } + q = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); vb = to_vb2_v4l2_buffer(q->bufs[index]); - buf = container_of(vb, struct aml_video_dec_buf, vb); - v4l2_m2m_buf_done(vb, buf->error ? VB2_BUF_STATE_ERROR : - VB2_BUF_STATE_DONE); - v4l_dbg(ctx, V4L_DEBUG_CODEC_INPUT, - "recycle buff idx: %d, vbuf: %lx\n", index, - (ulong)vb2_dma_contig_plane_dma_addr(q->bufs[index], 0)); + spin_lock_irqsave(&ctx->dmabuff_recycle_lock, flags); + kfifo_put(&ctx->dmabuff_recycle, vb); + spin_unlock_irqrestore(&ctx->dmabuff_recycle_lock, flags); + + queue_work(dev->decode_workqueue, &ctx->dmabuff_recycle_work); } static void aml_vdec_worker(struct work_struct *work) @@ -768,12 +1454,12 @@ struct aml_vcodec_ctx *ctx = container_of(work, struct aml_vcodec_ctx, decode_work); struct aml_vcodec_dev *dev = ctx->dev; - struct vb2_buffer *src_buf; + struct aml_video_dec_buf *aml_buf; + struct vb2_v4l2_buffer *vb2_v4l2; + struct vb2_buffer *vb; struct aml_vcodec_mem buf; bool res_chg = false; int ret; - struct aml_video_dec_buf *src_buf_info; - struct vb2_v4l2_buffer *src_vb2_v4l2; if (ctx->state < AML_STATE_INIT || ctx->state > AML_STATE_FLUSHED) { @@ -787,21 +1473,23 @@ goto out; } - src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); - if (src_buf == NULL) { + vb2_v4l2 = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + if (vb2_v4l2 == NULL) { v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "src_buf empty.\n"); goto out; } + vb = (struct vb2_buffer *)vb2_v4l2; + /*this case for google, but some frames are droped on ffmpeg, so disabled temp.*/ if (0 && !is_enough_work_items(ctx)) goto out; - src_vb2_v4l2 = container_of(src_buf, struct vb2_v4l2_buffer, vb2_buf); - src_buf_info = container_of(src_vb2_v4l2, struct aml_video_dec_buf, vb); + aml_buf = container_of(vb2_v4l2, struct aml_video_dec_buf, vb); + if (aml_buf->lastframe) { + ulong expires; - if (src_buf_info->lastframe) { /*the empty data use to flushed the decoder.*/ v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, "Got empty flush input buffer.\n"); @@ -809,22 +1497,34 @@ /* * when inputs a small amount of src buff, then soon to * switch state FLUSHING, must to wait the DBP to be ready. + * (!ctx->v4l_codec_dpb_ready) change to only need one buf + * for run ready in new version. */ - if (!ctx->v4l_codec_dpb_ready) { - v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); - goto out; + expires = jiffies + msecs_to_jiffies(5000); + while ((vdec_frame_number(ctx->ada_ctx) > 0) && + (ctx->cap_pool.in < 1)) { + if (time_after(jiffies, expires)) { + aml_vdec_flush_decoder(ctx); + v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + aml_vdec_dispatch_event(ctx, V4L2_EVENT_REQUEST_EXIT); + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "capture buffer waiting timeout.\n"); + goto out; + } + usleep_range(5000, 5500); } mutex_lock(&ctx->state_lock); if (ctx->state == AML_STATE_ACTIVE) { ctx->state = AML_STATE_FLUSHING;// prepare flushing - ATRACE_COUNTER("v4l2_state", ctx->state); + ATRACE_COUNTER("V_ST_VSINK-state", ctx->state); v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, "vcodec state (AML_STATE_FLUSHING-LASTFRM)\n"); } mutex_unlock(&ctx->state_lock); - src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + v4l2_m2m_src_buf_remove(ctx->m2m_ctx); v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); /* sets eos data for vdec input. */ @@ -833,21 +1533,22 @@ goto out; } - buf.index = src_buf->index; - buf.vaddr = vb2_plane_vaddr(src_buf, 0); - buf.addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); - buf.size = src_buf->planes[0].bytesused; - buf.model = src_buf->memory; - buf.timestamp = src_buf->timestamp; + buf.index = vb->index; + buf.vaddr = vb2_plane_vaddr(vb, 0); + buf.addr = sg_dma_address(aml_buf->out_sgt->sgl); + buf.size = vb->planes[0].bytesused; + buf.model = vb->memory; + buf.timestamp = vb->timestamp; + buf.meta_ptr = (ulong)aml_buf->meta_data; if (!buf.vaddr && !buf.addr) { v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, - "id=%d src_addr is NULL.\n", src_buf->index); + "id=%d src_addr is NULL.\n", vb->index); goto out; } - src_buf_info->used = true; + aml_buf->used = true; /* v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, "size: 0x%zx, crc: 0x%x\n", @@ -857,29 +1558,52 @@ /*v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, "timestamp: 0x%llx\n", src_buf->timestamp);*/ + if (ctx->is_drm_mode && + (buf.model == VB2_MEMORY_DMABUF)) { + ATRACE_COUNTER("VO_IN_VSINK-2.write_secure", buf.size); + } else { + ATRACE_COUNTER("VO_IN_VSINK-2.write", buf.size); + } + + ATRACE_COUNTER("V_ST_VSINK-input_buffering", vdec_frame_number(ctx->ada_ctx)); + ret = vdec_if_decode(ctx, &buf, &res_chg); if (ret > 0) { /* * we only return src buffer with VB2_BUF_STATE_DONE * when decode success without resolution change. */ - v4l2_m2m_src_buf_remove(ctx->m2m_ctx); - if (!(ctx->is_drm_mode && buf.model == VB2_MEMORY_DMABUF)) - v4l2_m2m_buf_done(&src_buf_info->vb, VB2_BUF_STATE_DONE); - } else if (ret && ret != -EAGAIN) { - src_buf_info->error = (ret == -EIO ? true : false); + aml_buf->used = false; v4l2_m2m_src_buf_remove(ctx->m2m_ctx); - if (!(ctx->is_drm_mode && buf.model == VB2_MEMORY_DMABUF)) - v4l2_m2m_buf_done(&src_buf_info->vb, VB2_BUF_STATE_ERROR); + if (ctx->is_drm_mode && + (buf.model == VB2_MEMORY_DMABUF)) { + wake_up_interruptible(&ctx->wq); + } else { + ATRACE_COUNTER("VO_OUT_VSINK-0.wrtie_end", buf.size); + v4l2_buff_done(&aml_buf->vb, + VB2_BUF_STATE_DONE); + } + } else if (ret && ret != -EAGAIN) { + aml_buf->used = false; + v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + + if (ctx->is_drm_mode && + (buf.model == VB2_MEMORY_DMABUF)) { + wake_up_interruptible(&ctx->wq); + } else { + ATRACE_COUNTER("VO_OUT_VSINK-3.write_error", buf.size); + v4l2_buff_done(&aml_buf->vb, + VB2_BUF_STATE_ERROR); + } v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "error processing src data. %d.\n", ret); } else if (res_chg) { /* wait the DPB state to be ready. */ - aml_wait_dpb_ready(ctx); + aml_wait_buf_ready(ctx); - src_buf_info->used = false; + aml_buf->used = false; aml_vdec_pic_info_update(ctx); /* * On encountering a resolution change in the stream. @@ -890,13 +1614,13 @@ mutex_lock(&ctx->state_lock); if (ctx->state == AML_STATE_ACTIVE) { ctx->state = AML_STATE_FLUSHING;// prepare flushing - ATRACE_COUNTER("v4l2_state", ctx->state); + ATRACE_COUNTER("V_ST_VSINK-state", ctx->state); v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, "vcodec state (AML_STATE_FLUSHING-RESCHG)\n"); } mutex_unlock(&ctx->state_lock); - ctx->q_data[AML_Q_DATA_SRC].resolution_changed = true; + ctx->v4l_resolution_change = true; while (ctx->m2m_ctx->job_flags & TRANS_RUNNING) { v4l2_m2m_job_pause(dev->m2m_dev_dec, ctx->m2m_ctx); } @@ -905,8 +1629,10 @@ goto out; } else { + ATRACE_COUNTER("VO_OUT_VSINK-1.write_again", buf.size); /* decoder is lack of resource, retry after short delay */ - usleep_range(50000, 55000); + if (vdec_get_instance_num() < 2) + usleep_range(2000, 4000); } v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); @@ -924,28 +1650,10 @@ if (aml_codec_reset(ctx->ada_ctx, &ctx->reset_flag)) { ctx->state = AML_STATE_ABORT; - ATRACE_COUNTER("v4l2_state", ctx->state); + ATRACE_COUNTER("V_ST_VSINK-state", ctx->state); v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, "vcodec state (AML_STATE_ABORT).\n"); - goto out; } - - if (ctx->state == AML_STATE_RESET) { - ctx->state = AML_STATE_PROBE; - ATRACE_COUNTER("v4l2_state", ctx->state); - v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, - "vcodec state (AML_STATE_PROBE)\n"); - - v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, - "dpb: %d, ready: %d, used: %d\n", ctx->dpb_size, - v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx), - ctx->buf_used_count); - - /* vdec has ready to decode subsequence data of new resolution. */ - ctx->q_data[AML_Q_DATA_SRC].resolution_changed = false; - v4l2_m2m_job_resume(ctx->dev->m2m_dev_dec, ctx->m2m_ctx); - } - out: complete(&ctx->comp); return; @@ -953,13 +1661,13 @@ void wait_vcodec_ending(struct aml_vcodec_ctx *ctx) { - struct aml_vcodec_dev *dev = ctx->dev; - /* disable queue output item to worker. */ ctx->output_thread_ready = false; + ctx->is_stream_off = true; /* flush output buffer worker. */ - flush_workqueue(dev->decode_workqueue); + cancel_work_sync(&ctx->decode_work); + cancel_work_sync(&ctx->dmabuff_recycle_work); /* clean output cache and decoder status . */ if (ctx->state > AML_STATE_INIT) @@ -973,33 +1681,38 @@ ctx->v4l_codec_dpb_ready = false; } -void try_to_capture(struct aml_vcodec_ctx *ctx) +void aml_thread_capture_worker(struct aml_vcodec_ctx *ctx) { - int ret = 0; + struct vb2_v4l2_buffer *vb = NULL; + struct aml_video_dec_buf *aml_buff = NULL; struct vdec_v4l2_buffer *fb = NULL; - ret = get_display_buffer(ctx, &fb); - if (ret) { - v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, - "the que have no disp buf,ret: %d\n", ret); - return; + for (;;) { + mutex_lock(&ctx->capture_buffer_lock); + if (!kfifo_get(&ctx->capture_buffer, &vb)) { + mutex_unlock(&ctx->capture_buffer_lock); + break; + } + mutex_unlock(&ctx->capture_buffer_lock); + + aml_buff = container_of(vb, struct aml_video_dec_buf, vb); + fb = &aml_buff->frame_buffer; + + if (ctx->is_stream_off) + continue; + + post_frame_to_upper(ctx, fb); } - - trans_vframe_to_user(ctx, fb); } -EXPORT_SYMBOL_GPL(try_to_capture); +EXPORT_SYMBOL_GPL(aml_thread_capture_worker); -static int vdec_thread(void *data) +static int vdec_capture_thread(void *data) { - struct sched_param param = - {.sched_priority = MAX_RT_PRIO / 2}; struct aml_vdec_thread *thread = (struct aml_vdec_thread *) data; struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *) thread->priv; - sched_setscheduler(current, SCHED_FIFO, ¶m); - for (;;) { v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, "%s, state: %d\n", __func__, ctx->state); @@ -1015,19 +1728,19 @@ } while (!kthread_should_stop()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule(); + usleep_range(1000, 2000); } return 0; } -void aml_thread_notify(struct aml_vcodec_ctx *ctx, +void aml_thread_post_task(struct aml_vcodec_ctx *ctx, enum aml_thread_type type) { struct aml_vdec_thread *thread = NULL; + ulong flags; - mutex_lock(&ctx->lock); + spin_lock_irqsave(&ctx->tsplock, flags); list_for_each_entry(thread, &ctx->vdec_thread_list, node) { if (thread->task == NULL) continue; @@ -1035,9 +1748,9 @@ if (thread->type == type) up(&thread->sem); } - mutex_unlock(&ctx->lock); + spin_unlock_irqrestore(&ctx->tsplock, flags); } -EXPORT_SYMBOL_GPL(aml_thread_notify); +EXPORT_SYMBOL_GPL(aml_thread_post_task); int aml_thread_start(struct aml_vcodec_ctx *ctx, aml_thread_func func, enum aml_thread_type type, const char *thread_name) @@ -1055,7 +1768,7 @@ thread->priv = ctx; sema_init(&thread->sem, 0); - thread->task = kthread_run(vdec_thread, thread, "aml-%s", thread_name); + thread->task = kthread_run(vdec_capture_thread, thread, "aml-%s-%d", thread_name, ctx->id); if (IS_ERR(thread->task)) { ret = PTR_ERR(thread->task); thread->task = NULL; @@ -1063,6 +1776,10 @@ } sched_setscheduler_nocheck(thread->task, SCHED_FIFO, ¶m); + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + "%s, policy is:%d priority is:%d\n", + __func__, thread->task->policy, thread->task->rt_priority); + list_add(&thread->node, &ctx->vdec_thread_list); return 0; @@ -1077,13 +1794,14 @@ void aml_thread_stop(struct aml_vcodec_ctx *ctx) { struct aml_vdec_thread *thread = NULL; + ulong flags; while (!list_empty(&ctx->vdec_thread_list)) { thread = list_entry(ctx->vdec_thread_list.next, struct aml_vdec_thread, node); - mutex_lock(&ctx->lock); + spin_lock_irqsave(&ctx->tsplock, flags); list_del(&thread->node); - mutex_unlock(&ctx->lock); + spin_unlock_irqrestore(&ctx->tsplock, flags); thread->stop = true; up(&thread->sem); @@ -1105,7 +1823,17 @@ switch (cmd->cmd) { case V4L2_DEC_CMD_STOP: case V4L2_DEC_CMD_START: - if (cmd->flags != 0) { + if (cmd->cmd == V4L2_DEC_CMD_START) { + if (cmd->start.speed == ~0) + cmd->start.speed = 0; + if (cmd->start.format == ~0) + cmd->start.format = 0; + } + + if (cmd->flags == ~0) + cmd->flags = 0; + + if ((cmd->flags != 0) && (cmd->flags != ~0)) { v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "cmd->flags=%u\n", cmd->flags); return -EINVAL; @@ -1134,19 +1862,6 @@ switch (cmd->cmd) { case V4L2_DEC_CMD_STOP: - ATRACE_COUNTER("v4l2_stop", 0); - if (ctx->state != AML_STATE_ACTIVE) { - if (ctx->state >= AML_STATE_IDLE && - ctx->state < AML_STATE_PROBE) { - ctx->state = AML_STATE_ABORT; - ATRACE_COUNTER("v4l2_state", ctx->state); - aml_vdec_dispatch_event(ctx, V4L2_EVENT_REQUEST_EXIT); - v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, - "vcodec state (AML_STATE_ABORT)\n"); - return 0; - } - } - src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); if (!vb2_is_streaming(src_vq)) { @@ -1155,18 +1870,32 @@ return 0; } + dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, + multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : + V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (!vb2_is_streaming(dst_vq)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "Capture stream is off. No need to flush.\n"); + return 0; + } + /* flush pipeline */ v4l2_m2m_buf_queue(ctx->m2m_ctx, &ctx->empty_flush_buf->vb); v4l2_m2m_try_schedule(ctx->m2m_ctx);//pay attention ctx->receive_cmd_stop = true; + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, + "%s, receive cmd stop and prepare flush pipeline.\n", __func__); break; case V4L2_DEC_CMD_START: - v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, "CMD V4L2_DEC_CMD_START\n"); dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE); vb2_clear_last_buffer_dequeued(dst_vq);//pay attention + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, + "%s, receive cmd start.\n", __func__); break; default: @@ -1176,6 +1905,20 @@ return 0; } +static void aml_wait_resource(struct aml_vcodec_ctx *ctx) +{ + ulong expires = jiffies + msecs_to_jiffies(1000); + + while (atomic_read(&ctx->dev->vpp_count) >= max_di_instance) { + if (time_after(jiffies, expires)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, + "wait resource timeout.\n"); + break; + } + usleep_range(2000, 4000); + } +} + static int vidioc_decoder_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { @@ -1184,26 +1927,80 @@ struct vb2_queue *q; q = v4l2_m2m_get_vq(fh->m2m_ctx, i); - if (!V4L2_TYPE_IS_OUTPUT(q->type)) { - if (ctx->is_stream_off) { - mutex_lock(&ctx->state_lock); - if ((ctx->state == AML_STATE_ACTIVE || - ctx->state == AML_STATE_FLUSHING || - ctx->state == AML_STATE_FLUSHED) || - (ctx->reset_flag == V4L_RESET_MODE_LIGHT)) { - ctx->state = AML_STATE_RESET; - ATRACE_COUNTER("v4l2_state", ctx->state); - ctx->v4l_codec_dpb_ready = false; + if (!V4L2_TYPE_IS_OUTPUT(q->type) && + ctx->is_stream_off) { + if (ctx->vpp_is_need) { + int ret; - v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, - "vcodec state (AML_STATE_RESET)\n"); - aml_vdec_reset(ctx); + if (ctx->vpp_cfg.fmt == 0) + ctx->vpp_cfg.fmt = ctx->cap_pix_fmt; + + if (ctx->vpp == NULL) + aml_wait_resource(ctx); + + if ((atomic_read(&ctx->dev->vpp_count) < max_di_instance) || + (ctx->vpp != NULL)) { + if (ctx->vpp && ctx->vpp_cfg.is_vpp_reset && + (ctx->vpp->is_prog == ctx->vpp_cfg.is_prog) && + (ctx->vpp->is_bypass_p == ctx->vpp_cfg.is_bypass_p) && + (ctx->vpp->work_mode == ctx->vpp_cfg.mode)) { + aml_v4l2_vpp_reset(ctx->vpp); + } else { + if (ctx->vpp) { + atomic_dec(&ctx->dev->vpp_count); + aml_v4l2_vpp_destroy(ctx->vpp); + ctx->vpp = NULL; + } + + ret = aml_v4l2_vpp_init(ctx, &ctx->vpp_cfg, &ctx->vpp); + if (ret) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "vpp_wrapper init err:%d vpp_cfg.fmt: %d\n", + ret, ctx->vpp_cfg.fmt); + return ret; + } + + atomic_inc(&ctx->dev->vpp_count); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, + "vpp_wrapper instance count: %d\n", + atomic_read(&ctx->dev->vpp_count)); + } + } else { + ctx->vpp_cfg.enable_local_buf = 0; + ctx->vpp_cfg.enable_nr = 0; + ctx->picinfo.dpb_margin += ctx->vpp_size; + ctx->dpb_size = ctx->picinfo.dpb_margin + ctx->picinfo.dpb_frames; + ctx->vpp_size = 0; + vdec_if_set_param(ctx, SET_PARAM_PIC_INFO, &ctx->picinfo); + ctx->vpp_is_need = false; } - mutex_unlock(&ctx->state_lock); - - ctx->is_stream_off = false; - ctx->v4l_resolution_change = false; + ctx->vpp_cfg.is_vpp_reset = false; + } else { + if (ctx->vpp) { + atomic_dec(&ctx->dev->vpp_count); + aml_v4l2_vpp_destroy(ctx->vpp); + ctx->vpp = NULL; + } } + + if (ctx->ge2d_is_need) { + int ret; + + if (ctx->ge2d) { + aml_v4l2_ge2d_destroy(ctx->ge2d); + ctx->ge2d = NULL; + } + + ret = aml_v4l2_ge2d_init(ctx, &ctx->ge2d_cfg, &ctx->ge2d); + if (ret) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "ge2d_wrapper init err:%d\n", ret); + return ret; + } + } + + ctx->is_stream_off = false; } else ctx->is_out_stream_off = false; @@ -1219,12 +2016,26 @@ struct v4l2_fh *fh = file->private_data; struct aml_vcodec_ctx *ctx = fh_to_ctx(fh); struct vb2_queue *q; + ulong flags; q = v4l2_m2m_get_vq(fh->m2m_ctx, i); - if (!V4L2_TYPE_IS_OUTPUT(q->type)) - ctx->is_stream_off = true; - else + + flags = aml_vcodec_ctx_lock(ctx); + + if (V4L2_TYPE_IS_OUTPUT(q->type)) ctx->is_out_stream_off = true; + else + ctx->is_stream_off = true; + + aml_vcodec_ctx_unlock(ctx, flags); + + if (!V4L2_TYPE_IS_OUTPUT(q->type)) { + if (ctx->vpp) { + reconfig_vpp_status(ctx); + } + } else { + ctx->index_disp = 0; + } v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s, type: %d\n", __func__, q->type); @@ -1241,19 +2052,38 @@ q = v4l2_m2m_get_vq(fh->m2m_ctx, rb->type); - if (!rb->count) + if (!rb->count) { + if (!V4L2_TYPE_IS_OUTPUT(rb->type)) { + if (wait_event_interruptible_timeout + (ctx->post_done_wq, ctx->post_to_upper_done == true, + msecs_to_jiffies(200)) == 0) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "wait post frame to upper finish timeout.\n"); + } + } vb2_queue_release(q); + } v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s, type: %d, count: %d\n", __func__, q->type, rb->count); if (!V4L2_TYPE_IS_OUTPUT(rb->type)) { - /* driver needs match v4l buffer number with dpb_size */ - if (rb->count > ctx->dpb_size) { + /* driver needs match v4l buffer number with total size*/ + if (rb->count > CTX_BUF_TOTAL(ctx)) { v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "reqbufs (st:%d) %d -> %d\n", - ctx->state, rb->count, ctx->dpb_size); + ctx->state, rb->count, CTX_BUF_TOTAL(ctx)); + ctx->picinfo.dpb_margin += (rb->count - CTX_BUF_TOTAL(ctx)); + ctx->dpb_size = ctx->picinfo.dpb_frames + ctx->picinfo.dpb_margin; + vdec_if_set_param(ctx, SET_PARAM_PIC_INFO, &ctx->picinfo); + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, + "%s buf updated, dec: %d (%d + %d), vpp %d\n", + __func__, + ctx->dpb_size, + ctx->picinfo.dpb_frames, + ctx->picinfo.dpb_margin, + ctx->vpp_size); //rb->count = ctx->dpb_size; } } else { @@ -1293,9 +2123,12 @@ { ulong flags; + if (kref_read(&ctx->box_ref)) + kref_put(&ctx->box_ref, box_release); + flags = aml_vcodec_ctx_lock(ctx); ctx->state = AML_STATE_ABORT; - ATRACE_COUNTER("v4l2_state", ctx->state); + ATRACE_COUNTER("V_ST_VSINK-state", ctx->state); v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, "vcodec state (AML_STATE_ABORT)\n"); aml_vcodec_ctx_unlock(ctx, flags); @@ -1321,6 +2154,8 @@ memset(q_data, 0, sizeof(struct aml_q_data)); q_data->visible_width = DFT_CFG_WIDTH; q_data->visible_height = DFT_CFG_HEIGHT; + q_data->coded_width = DFT_CFG_WIDTH; + q_data->coded_height = DFT_CFG_HEIGHT; q_data->fmt = &aml_video_formats[OUT_FMT_IDX]; q_data->field = V4L2_FIELD_NONE; @@ -1334,6 +2169,9 @@ q_data->coded_width = DFT_CFG_WIDTH; q_data->coded_height = DFT_CFG_HEIGHT; q_data->fmt = &aml_video_formats[CAP_FMT_IDX]; + if (support_format_I420) + q_data->fmt = &aml_video_formats[CAP_FMT_I420_IDX]; + q_data->field = V4L2_FIELD_NONE; v4l_bound_align_image(&q_data->coded_width, @@ -1349,8 +2187,11 @@ q_data->bytesperline[1] = q_data->coded_width; ctx->reset_flag = V4L_RESET_MODE_NORMAL; + ctx->fb_ops.query = fb_buff_query; + ctx->fb_ops.alloc = fb_buff_from_queue; + ctx->state = AML_STATE_IDLE; - ATRACE_COUNTER("v4l2_state", ctx->state); + ATRACE_COUNTER("V_ST_VSINK-state", ctx->state); v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, "vcodec state (AML_STATE_IDLE)\n"); } @@ -1374,11 +2215,24 @@ ret = v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); if (V4L2_TYPE_IS_OUTPUT(buf->type)) { + if (V4L2_TYPE_IS_MULTIPLANAR(buf->type)) { + if (ret == -EAGAIN) + ATRACE_COUNTER("VO_IN_VSINK-1.que_again", buf->m.planes[0].bytesused); + else + ATRACE_COUNTER("VO_IN_VSINK-0.que", buf->m.planes[0].bytesused); + } else { + if (ret == -EAGAIN) + ATRACE_COUNTER("VO_IN_VSINK-1.que_again", buf->length); + else + ATRACE_COUNTER("VO_IN_VSINK-0.que", buf->length); + } + } else { if (ret == -EAGAIN) - ATRACE_COUNTER("v4l2_qbuf_eagain", 0); + ATRACE_COUNTER("VC_IN_VSINK-1.que_again", buf->index); else - ATRACE_COUNTER("v4l2_qbuf_ok", 0); + ATRACE_COUNTER("VC_IN_VSINK-0.que", buf->index); } + return ret; } @@ -1400,39 +2254,47 @@ } ret = v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); - if (V4L2_TYPE_IS_OUTPUT(buf->type)) { - if (ret == -EAGAIN) - ATRACE_COUNTER("v4l2_dqin_eagain", 0); - else - ATRACE_COUNTER("v4l2_dqin_ok", 0); - } else { - if (ret == -EAGAIN) - ATRACE_COUNTER("v4l2_dqout_eagain", 0); - } - if (!ret && !V4L2_TYPE_IS_OUTPUT(buf->type)) { struct vb2_queue *vq; struct vb2_v4l2_buffer *vb2_v4l2 = NULL; struct aml_video_dec_buf *aml_buf = NULL; + struct file *file = NULL; vq = v4l2_m2m_get_vq(ctx->m2m_ctx, buf->type); vb2_v4l2 = to_vb2_v4l2_buffer(vq->bufs[buf->index]); aml_buf = container_of(vb2_v4l2, struct aml_video_dec_buf, vb); - aml_buf->privdata.vb_handle = (ulong) ctx->dev; + aml_buf->privdata.vb_handle = (ulong) aml_buf; aml_buf->privdata.v4l_dec_ctx = (ulong) ctx; - aml_buf->privdata.v4l_inst_id = ctx->id; file = fget(vb2_v4l2->private); - if (is_v4l2_buf_file(file)) { + if (file && is_v4l2_buf_file(file)) { dmabuf_fd_install_data(vb2_v4l2->private, (void*)&aml_buf->privdata, sizeof(struct file_private_data)); - ATRACE_COUNTER("v4l2_dqout_ok", aml_buf->privdata.vf.index_disp); v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, "disp: %d, vf: %lx\n", aml_buf->privdata.vf.index_disp, (ulong) v4l_get_vf_handle(vb2_v4l2->private)); + fput(file); } - fput(file); + } + + if (V4L2_TYPE_IS_OUTPUT(buf->type)) { + if (V4L2_TYPE_IS_MULTIPLANAR(buf->type)) { + if (ret == -EAGAIN) + ATRACE_COUNTER("VO_OUT_VSINK-5.deque_again", buf->m.planes[0].bytesused); + else + ATRACE_COUNTER("VO_OUT_VSINK-4.deque", buf->m.planes[0].bytesused); + } else { + if (ret == -EAGAIN) + ATRACE_COUNTER("VO_OUT_VSINK-5.deque_again", buf->length); + else + ATRACE_COUNTER("VO_OUT_VSINK-4.deque", buf->length); + } + } else { + if (ret == -EAGAIN) + ATRACE_COUNTER("VC_OUT_VSINK-3.deque_again", buf->index); + else + ATRACE_COUNTER("VC_OUT_VSINK-2.deque", buf->index); } return ret; @@ -1442,10 +2304,12 @@ struct v4l2_capability *cap) { struct aml_vcodec_ctx *ctx = fh_to_ctx(priv); + struct video_device *vfd_dec = video_devdata(file); strlcpy(cap->driver, AML_VCODEC_DEC_NAME, sizeof(cap->driver)); strlcpy(cap->bus_info, AML_PLATFORM_STR, sizeof(cap->bus_info)); strlcpy(cap->card, AML_PLATFORM_STR, sizeof(cap->card)); + cap->device_caps = vfd_dec->device_caps; v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s, %s\n", __func__, cap->card); @@ -1483,115 +2347,154 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct aml_video_fmt *fmt) { - struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; int i; + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct v4l2_pix_format *pix = &f->fmt.pix; - if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - pix_fmt_mp->num_planes = 1; - pix_fmt_mp->plane_fmt[0].bytesperline = 0; - if (pix_fmt_mp->pixelformat != V4L2_PIX_FMT_MPEG2 && - pix_fmt_mp->pixelformat != V4L2_PIX_FMT_H264) - pix_fmt_mp->field = V4L2_FIELD_NONE; - else if (pix_fmt_mp->field != V4L2_FIELD_NONE) - pr_info("%s, field: %u, fmt: %u\n", - __func__, pix_fmt_mp->field, - pix_fmt_mp->pixelformat); - } else if (!V4L2_TYPE_IS_OUTPUT(f->type)) { - int tmp_w, tmp_h; + if (V4L2_TYPE_IS_MULTIPLANAR(f->type)) { + if (V4L2_TYPE_IS_OUTPUT(f->type)) { + pix_mp->num_planes = 1; + pix_mp->plane_fmt[0].bytesperline = 0; - pix_fmt_mp->field = V4L2_FIELD_NONE; - pix_fmt_mp->height = clamp(pix_fmt_mp->height, - AML_VDEC_MIN_H, - AML_VDEC_MAX_H); - pix_fmt_mp->width = clamp(pix_fmt_mp->width, - AML_VDEC_MIN_W, - AML_VDEC_MAX_W); + if ((pix_mp->pixelformat != V4L2_PIX_FMT_MPEG2) && + (pix_mp->pixelformat != V4L2_PIX_FMT_H264) && + (pix_mp->pixelformat != V4L2_PIX_FMT_MPEG1)) { + pix_mp->field = V4L2_FIELD_NONE; + } else if (pix_mp->field != V4L2_FIELD_NONE) { + if (pix_mp->field == V4L2_FIELD_ANY) + pix_mp->field = V4L2_FIELD_NONE; - /* - * Find next closer width align 64, heign align 64, size align - * 64 rectangle - * Note: This only get default value, the real HW needed value - * only available when ctx in AML_STATE_PROBE state - */ - tmp_w = pix_fmt_mp->width; - tmp_h = pix_fmt_mp->height; - v4l_bound_align_image(&pix_fmt_mp->width, - AML_VDEC_MIN_W, - AML_VDEC_MAX_W, 6, - &pix_fmt_mp->height, - AML_VDEC_MIN_H, - AML_VDEC_MAX_H, 6, 9); + pr_info("%s, field: %u, fmt: %x\n", + __func__, pix_mp->field, + pix_mp->pixelformat); + } + } else { + if (pix_mp->field != V4L2_FIELD_INTERLACED) + pix_mp->field = V4L2_FIELD_NONE; + pix_mp->height = clamp(pix_mp->height, + AML_VDEC_MIN_H, + AML_VDEC_MAX_H); + pix_mp->width = clamp(pix_mp->width, + AML_VDEC_MIN_W, + AML_VDEC_MAX_W); - if (pix_fmt_mp->width < tmp_w && - (pix_fmt_mp->width + 64) <= AML_VDEC_MAX_W) - pix_fmt_mp->width += 64; - if (pix_fmt_mp->height < tmp_h && - (pix_fmt_mp->height + 64) <= AML_VDEC_MAX_H) - pix_fmt_mp->height += 64; + pix_mp->num_planes = fmt->num_planes; - pix_fmt_mp->num_planes = fmt->num_planes; - pix_fmt_mp->plane_fmt[0].sizeimage = - pix_fmt_mp->width * pix_fmt_mp->height; - pix_fmt_mp->plane_fmt[0].bytesperline = pix_fmt_mp->width; + pix_mp->plane_fmt[0].bytesperline = pix_mp->width; + pix_mp->plane_fmt[0].sizeimage = + pix_mp->width * pix_mp->height; - if (pix_fmt_mp->num_planes == 2) { - pix_fmt_mp->plane_fmt[1].sizeimage = - (pix_fmt_mp->width * pix_fmt_mp->height) / 2; - pix_fmt_mp->plane_fmt[1].bytesperline = - pix_fmt_mp->width; + pix_mp->plane_fmt[1].bytesperline = pix_mp->width; + pix_mp->plane_fmt[1].sizeimage = + pix_mp->width * pix_mp->height / 2; } + + for (i = 0; i < pix_mp->num_planes; i++) { + memset(&(pix_mp->plane_fmt[i].reserved[0]), 0x0, + sizeof(pix_mp->plane_fmt[0].reserved)); + } + memset(&pix_mp->reserved, 0x0, sizeof(pix_mp->reserved)); + + pix_mp->flags = 0; + } else { + if (V4L2_TYPE_IS_OUTPUT(f->type)) { + pix->bytesperline = 0; + if ((pix->pixelformat != V4L2_PIX_FMT_MPEG2) && + (pix->pixelformat != V4L2_PIX_FMT_H264) && + (pix->pixelformat != V4L2_PIX_FMT_MPEG1)) { + pix->field = V4L2_FIELD_NONE; + } else if (pix->field != V4L2_FIELD_NONE) { + if (pix->field == V4L2_FIELD_ANY) + pix->field = V4L2_FIELD_NONE; + + pr_info("%s, field: %u, fmt: %x\n", + __func__, pix->field, + pix->pixelformat); + } + } else { + if (pix->field != V4L2_FIELD_INTERLACED) + pix->field = V4L2_FIELD_NONE; + + pix->height = clamp(pix->height, + AML_VDEC_MIN_H, + AML_VDEC_MAX_H); + pix->width = clamp(pix->width, + AML_VDEC_MIN_W, + AML_VDEC_MAX_W); + + pix->bytesperline = pix->width; + pix->sizeimage = pix->width * pix->height; + } + pix->flags = 0; } - for (i = 0; i < pix_fmt_mp->num_planes; i++) - memset(&(pix_fmt_mp->plane_fmt[i].reserved[0]), 0x0, - sizeof(pix_fmt_mp->plane_fmt[0].reserved)); - - pix_fmt_mp->flags = 0; - memset(&pix_fmt_mp->reserved, 0x0, sizeof(pix_fmt_mp->reserved)); return 0; } -static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, +static int vidioc_try_fmt_vid_cap_out(struct file *file, void *priv, struct v4l2_format *f) { + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct v4l2_pix_format *pix = &f->fmt.pix; + struct aml_q_data *q_data = NULL; struct aml_video_fmt *fmt = NULL; struct aml_vcodec_ctx *ctx = fh_to_ctx(priv); + struct vb2_queue *dst_vq; v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, - "%s, type: %u, planes: %u, fmt: %u\n", - __func__, f->type, f->fmt.pix_mp.num_planes, + "%s, type: %u, planes: %u, fmt: %x\n", + __func__, f->type, + V4L2_TYPE_IS_MULTIPLANAR(f->type) ? + f->fmt.pix_mp.num_planes : 1, f->fmt.pix_mp.pixelformat); - fmt = aml_vdec_find_format(f); - if (!fmt) - return -EINVAL; - - return vidioc_try_fmt(f, fmt); -} - -static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; - struct aml_video_fmt *fmt = NULL; - struct aml_vcodec_ctx *ctx = fh_to_ctx(priv); - - v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, - "%s, type: %u, planes: %u, fmt: %u\n", - __func__, f->type, f->fmt.pix_mp.num_planes, - f->fmt.pix_mp.pixelformat); - - fmt = aml_vdec_find_format(f); - if (!fmt) - return -EINVAL; - - if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) { - v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, - "sizeimage of output format must be given\n"); + dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (!dst_vq) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "no vb2 queue for type=%d\n", V4L2_BUF_TYPE_VIDEO_CAPTURE); return -EINVAL; } - return vidioc_try_fmt(f, fmt); + if (!V4L2_TYPE_IS_MULTIPLANAR(f->type) && dst_vq->is_multiplanar) + return -EINVAL; + + fmt = aml_vdec_find_format(f); + if (!fmt) { + if (V4L2_TYPE_IS_OUTPUT(f->type)) + f->fmt.pix.pixelformat = aml_video_formats[OUT_FMT_IDX].fourcc; + else + f->fmt.pix.pixelformat = aml_video_formats[CAP_FMT_IDX].fourcc; + fmt = aml_vdec_find_format(f); + } + + vidioc_try_fmt(f, fmt); + + q_data = aml_vdec_get_q_data(ctx, f->type); + if (!q_data) + return -EINVAL; + + if (ctx->state >= AML_STATE_PROBE) + update_ctx_dimension(ctx, f->type); + copy_v4l2_format_dimention(pix_mp, pix, q_data, f->type); + + if (!V4L2_TYPE_IS_OUTPUT(f->type)) + return 0; + + if (V4L2_TYPE_IS_MULTIPLANAR(f->type)) { + if (pix_mp->plane_fmt[0].sizeimage == 0) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "sizeimage of output format must be given\n"); + return -EINVAL; + } + } else { + if (pix->sizeimage == 0) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "sizeimage of output format must be given\n"); + return -EINVAL; + } + } + + return 0; } static int vidioc_vdec_g_selection(struct file *file, void *priv, @@ -1599,29 +2502,36 @@ { struct aml_vcodec_ctx *ctx = fh_to_ctx(priv); struct aml_q_data *q_data; + int ratio = 1; if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) return -EINVAL; + if (ctx->internal_dw_scale) { + if (ctx->state >= AML_STATE_PROBE) { + unsigned int dw_mode = VDEC_DW_NO_AFBC; + if (vdec_if_get_param(ctx, GET_PARAM_DW_MODE, &dw_mode)) + return -EBUSY; + ratio = get_double_write_ratio(dw_mode); + } + } + q_data = &ctx->q_data[AML_Q_DATA_DST]; switch (s->target) { case V4L2_SEL_TGT_COMPOSE_DEFAULT: case V4L2_SEL_TGT_COMPOSE: - if (vdec_if_get_param(ctx, GET_PARAM_CROP_INFO, &(s->r))) { - /* set to default value if header info not ready yet*/ - s->r.left = 0; - s->r.top = 0; - s->r.width = q_data->visible_width; - s->r.height = q_data->visible_height; - } + s->r.left = 0; + s->r.top = 0; + s->r.width = ctx->picinfo.visible_width / ratio; + s->r.height = ctx->picinfo.visible_height / ratio; break; case V4L2_SEL_TGT_COMPOSE_BOUNDS: s->r.left = 0; s->r.top = 0; - s->r.width = ctx->picinfo.coded_width; - s->r.height = ctx->picinfo.coded_height; + s->r.width = ctx->picinfo.coded_width / ratio; + s->r.height = ctx->picinfo.coded_height / ratio; break; default: return -EINVAL; @@ -1645,6 +2555,7 @@ struct v4l2_selection *s) { struct aml_vcodec_ctx *ctx = fh_to_ctx(priv); + int ratio = 1; v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s, type: %d\n", __func__, s->type); @@ -1652,12 +2563,21 @@ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; + if (ctx->internal_dw_scale) { + if (ctx->state >= AML_STATE_PROBE) { + unsigned int dw_mode = VDEC_DW_NO_AFBC; + if (vdec_if_get_param(ctx, GET_PARAM_DW_MODE, &dw_mode)) + return -EBUSY; + ratio = get_double_write_ratio(dw_mode); + } + } + switch (s->target) { case V4L2_SEL_TGT_COMPOSE: s->r.left = 0; s->r.top = 0; - s->r.width = ctx->picinfo.visible_width; - s->r.height = ctx->picinfo.visible_height; + s->r.width = ctx->picinfo.visible_width / ratio; + s->r.height = ctx->picinfo.visible_height / ratio; break; default: return -EINVAL; @@ -1666,89 +2586,127 @@ return 0; } -static void copy_v4l2_format_dimention(struct v4l2_pix_format_mplane *pix_mp, - struct aml_q_data *q_data, u32 type) +/* called when it is beyong AML_STATE_PROBE */ +static void update_ctx_dimension(struct aml_vcodec_ctx *ctx, u32 type) { - if (!pix_mp || !q_data) - return; + struct aml_q_data *q_data; + unsigned int dw_mode = VDEC_DW_NO_AFBC; + int ratio = 1; - if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - pix_mp->width = q_data->visible_width; - pix_mp->height = q_data->visible_height; - } else { - /* - * Width and height are set to the dimensions - * of the movie, the buffer is bigger and - * further processing stages should crop to this - * rectangle. - */ - pix_mp->width = q_data->coded_width; - pix_mp->height = q_data->coded_height; + q_data = aml_vdec_get_q_data(ctx, type); + + if (ctx->internal_dw_scale) { + if (vdec_if_get_param(ctx, GET_PARAM_DW_MODE, &dw_mode)) + return; + ratio = get_double_write_ratio(dw_mode); } - /* - * Set pixelformat to the format in which mt vcodec - * outputs the decoded frame - */ - pix_mp->num_planes = q_data->fmt->num_planes; - pix_mp->pixelformat = q_data->fmt->fourcc; - pix_mp->plane_fmt[0].bytesperline = q_data->bytesperline[0]; - pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage[0]; - if (type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - pix_mp->plane_fmt[1].bytesperline = q_data->bytesperline[1]; - pix_mp->plane_fmt[1].sizeimage = q_data->sizeimage[1]; + if (V4L2_TYPE_IS_MULTIPLANAR(type)) { + q_data->sizeimage[0] = ctx->picinfo.y_len_sz; + q_data->sizeimage[1] = ctx->picinfo.c_len_sz; + + q_data->coded_width = ALIGN(ctx->picinfo.coded_width / ratio, 64); + q_data->coded_height = ALIGN(ctx->picinfo.coded_height / ratio, 64); + + q_data->bytesperline[0] = ALIGN(ctx->picinfo.coded_width / ratio, 64); + q_data->bytesperline[1] = ALIGN(ctx->picinfo.coded_width / ratio, 64); + } else { + q_data->coded_width = ALIGN(ctx->picinfo.coded_width / ratio, 64); + q_data->coded_height = ALIGN(ctx->picinfo.coded_height / ratio, 64); + q_data->sizeimage[0] = ctx->picinfo.y_len_sz; + q_data->sizeimage[0] += ctx->picinfo.c_len_sz; + q_data->bytesperline[0] = ALIGN(ctx->picinfo.coded_width / ratio, 64); + } +} + +static void copy_v4l2_format_dimention(struct v4l2_pix_format_mplane *pix_mp, + struct v4l2_pix_format *pix, + struct aml_q_data *q_data, + u32 type) +{ + int i; + + if (!pix || !pix_mp || !q_data) + return; + + if (V4L2_TYPE_IS_MULTIPLANAR(type)) { + pix_mp->width = q_data->coded_width; + pix_mp->height = q_data->coded_height; + pix_mp->num_planes = q_data->fmt->num_planes; + pix_mp->pixelformat = q_data->fmt->fourcc; + + for (i = 0; i < q_data->fmt->num_planes; i++) { + pix_mp->plane_fmt[i].bytesperline = q_data->bytesperline[i]; + pix_mp->plane_fmt[i].sizeimage = q_data->sizeimage[i]; + } + } else { + pix->width = q_data->coded_width; + pix->height = q_data->coded_height; + pix->pixelformat = q_data->fmt->fourcc; + pix->bytesperline = q_data->bytesperline[0]; + pix->sizeimage = q_data->sizeimage[0]; } } static int vidioc_vdec_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct aml_vcodec_ctx *ctx = fh_to_ctx(priv); - struct v4l2_pix_format_mplane *pix_mp; - struct aml_q_data *q_data; int ret = 0; + struct aml_vcodec_ctx *ctx = fh_to_ctx(priv); + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct v4l2_pix_format *pix = &f->fmt.pix; + struct aml_q_data *q_data = NULL; struct aml_video_fmt *fmt; + struct vb2_queue *dst_vq; v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, - "%s, type: %u, planes: %u, fmt: %u\n", - __func__, f->type, f->fmt.pix_mp.num_planes, + "%s, type: %u, planes: %u, fmt: %x\n", + __func__, f->type, + V4L2_TYPE_IS_MULTIPLANAR(f->type) ? + f->fmt.pix_mp.num_planes : 1, f->fmt.pix_mp.pixelformat); + dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (!dst_vq) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "no vb2 queue for type=%d\n", V4L2_BUF_TYPE_VIDEO_CAPTURE); + return -EINVAL; + } + + if (!V4L2_TYPE_IS_MULTIPLANAR(f->type) && dst_vq->is_multiplanar) + return -EINVAL; + q_data = aml_vdec_get_q_data(ctx, f->type); if (!q_data) return -EINVAL; - pix_mp = &f->fmt.pix_mp; if ((f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) && vb2_is_busy(&ctx->m2m_ctx->out_q_ctx.q)) { v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "out_q_ctx buffers already requested\n"); + ret = -EBUSY; } if ((!V4L2_TYPE_IS_OUTPUT(f->type)) && vb2_is_busy(&ctx->m2m_ctx->cap_q_ctx.q)) { v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "cap_q_ctx buffers already requested\n"); + ret = -EBUSY; } fmt = aml_vdec_find_format(f); if (fmt == NULL) { - if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - f->fmt.pix.pixelformat = - aml_video_formats[OUT_FMT_IDX].fourcc; - fmt = aml_vdec_find_format(f); - } else if (!V4L2_TYPE_IS_OUTPUT(f->type)) { - f->fmt.pix.pixelformat = - aml_video_formats[CAP_FMT_IDX].fourcc; - fmt = aml_vdec_find_format(f); - } + if (V4L2_TYPE_IS_OUTPUT(f->type)) + fmt = &aml_video_formats[OUT_FMT_IDX]; + else + fmt = &aml_video_formats[CAP_FMT_IDX]; + f->fmt.pix.pixelformat = fmt->fourcc; } q_data->fmt = fmt; vidioc_try_fmt(f, q_data->fmt); + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - if (ctx->is_drm_mode) - pix_mp->plane_fmt[0].sizeimage = 1; q_data->sizeimage[0] = pix_mp->plane_fmt[0].sizeimage; q_data->coded_width = pix_mp->width; q_data->coded_height = pix_mp->height; @@ -1758,6 +2716,7 @@ pix_mp->width, pix_mp->height, pix_mp->plane_fmt[0].sizeimage); + ctx->output_pix_fmt = pix_mp->pixelformat; ctx->colorspace = f->fmt.pix_mp.colorspace; ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; ctx->quantization = f->fmt.pix_mp.quantization; @@ -1773,7 +2732,38 @@ return -EINVAL; } ctx->state = AML_STATE_INIT; - ATRACE_COUNTER("v4l2_state", ctx->state); + ATRACE_COUNTER("V_ST_VSINK-state", ctx->state); + v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, + "vcodec state (AML_STATE_INIT)\n"); + } + mutex_unlock(&ctx->state_lock); + } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + q_data->sizeimage[0] = pix->sizeimage; + q_data->coded_width = pix->width; + q_data->coded_height = pix->height; + + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + "w: %d, h: %d, size: %d\n", + pix->width, pix->height, + pix->sizeimage); + + ctx->output_pix_fmt = pix->pixelformat; + ctx->colorspace = f->fmt.pix.colorspace; + ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc; + ctx->quantization = f->fmt.pix.quantization; + ctx->xfer_func = f->fmt.pix.xfer_func; + + mutex_lock(&ctx->state_lock); + if (ctx->state == AML_STATE_IDLE) { + ret = vdec_if_init(ctx, q_data->fmt->fourcc); + if (ret) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "vdec_if_init() fail ret=%d\n", ret); + mutex_unlock(&ctx->state_lock); + return -EINVAL; + } + ctx->state = AML_STATE_INIT; + ATRACE_COUNTER("V_ST_VSINK-state", ctx->state); v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, "vcodec state (AML_STATE_INIT)\n"); } @@ -1781,9 +2771,13 @@ } if (!V4L2_TYPE_IS_OUTPUT(f->type)) { - ctx->cap_pix_fmt = pix_mp->pixelformat; - if (ctx->state >= AML_STATE_PROBE) - copy_v4l2_format_dimention(pix_mp, q_data, f->type); + ctx->cap_pix_fmt = V4L2_TYPE_IS_MULTIPLANAR(f->type) ? + pix_mp->pixelformat : pix->pixelformat; + if (ctx->state >= AML_STATE_PROBE) { + update_ctx_dimension(ctx, f->type); + copy_v4l2_format_dimention(pix_mp, pix, q_data, f->type); + v4l_buf_size_decision(ctx); + } } return 0; @@ -1833,16 +2827,31 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) { struct aml_video_fmt *fmt; - int i, j = 0; + int i = 0, j = 0; - for (i = 0; i < NUM_FORMATS; i++) { - if (output_queue && (aml_video_formats[i].type != AML_FMT_DEC)) + /* I420 only used for mjpeg. */ + if (!output_queue && support_mjpeg && support_format_I420) { + for (i = 0; i < NUM_FORMATS; i++) { + fmt = &aml_video_formats[i]; + if ((fmt->fourcc == V4L2_PIX_FMT_YUV420) || + (fmt->fourcc == V4L2_PIX_FMT_YUV420M)) { + break; + } + } + } + + for (; i < NUM_FORMATS; i++) { + fmt = &aml_video_formats[i]; + if (output_queue && (fmt->type != AML_FMT_DEC)) continue; - if (!output_queue && (aml_video_formats[i].type != AML_FMT_FRAME)) + if (!output_queue && (fmt->type != AML_FMT_FRAME)) + continue; + if (support_mjpeg && !support_format_I420 && + ((fmt->fourcc == V4L2_PIX_FMT_YUV420) || + (fmt->fourcc == V4L2_PIX_FMT_YUV420M))) continue; if (j == f->index) { - fmt = &aml_video_formats[i]; f->pixelformat = fmt->fourcc; return 0; } @@ -1879,6 +2888,7 @@ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; struct v4l2_pix_format *pix = &f->fmt.pix; struct vb2_queue *vq; + struct vb2_queue *dst_vq; struct aml_q_data *q_data; int ret = 0; @@ -1889,12 +2899,29 @@ return -EINVAL; } + dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (!dst_vq) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "no vb2 queue for type=%d\n", V4L2_BUF_TYPE_VIDEO_CAPTURE); + return -EINVAL; + } + + if (!V4L2_TYPE_IS_MULTIPLANAR(f->type) && dst_vq->is_multiplanar) + return -EINVAL; + q_data = aml_vdec_get_q_data(ctx, f->type); ret = vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, &ctx->picinfo); if (ret) { v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "GET_PARAM_PICTURE_INFO err\n"); + } else { + if ((ctx->picinfo.visible_height < 16 && ctx->picinfo.visible_height > 0) || + (ctx->picinfo.visible_width < 16 && ctx->picinfo.visible_width > 0)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "The width or height of the stream is less than 16\n"); + return -EPERM; + } } if (V4L2_TYPE_IS_MULTIPLANAR(f->type)) { @@ -1913,24 +2940,8 @@ if ((!V4L2_TYPE_IS_OUTPUT(f->type)) && (ctx->state >= AML_STATE_PROBE)) { - /* Until STREAMOFF is called on the CAPTURE queue - * (acknowledging the event), the driver operates as if - * the resolution hasn't changed yet. - * So we just return picinfo yet, and update picinfo in - * stop_streaming hook function - */ - /* it is used for alloc the decode buffer size. */ - q_data->sizeimage[0] = ctx->picinfo.y_len_sz; - q_data->sizeimage[1] = ctx->picinfo.c_len_sz; - - /* it is used for alloc the EGL image buffer size. */ - q_data->coded_width = ctx->picinfo.coded_width; - q_data->coded_height = ctx->picinfo.coded_height; - - q_data->bytesperline[0] = ctx->picinfo.coded_width; - q_data->bytesperline[1] = ctx->picinfo.coded_width; - - copy_v4l2_format_dimention(pix_mp, q_data, f->type); + update_ctx_dimension(ctx, f->type); + copy_v4l2_format_dimention(pix_mp, pix, q_data, f->type); } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { /* * This is run on OUTPUT @@ -1938,20 +2949,21 @@ * so width and height have no meaning. * Assign value here to pass v4l2-compliance test */ - copy_v4l2_format_dimention(pix_mp, q_data, f->type); + copy_v4l2_format_dimention(pix_mp, pix, q_data, f->type); } else { - copy_v4l2_format_dimention(pix_mp, q_data, f->type); + copy_v4l2_format_dimention(pix_mp, pix, q_data, f->type); v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, "type=%d state=%d Format information could not be read, not ready yet!\n", f->type, ctx->state); - return -EINVAL; } v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, - "%s, type: %u, planes: %u, fmt: %u\n", - __func__, f->type, f->fmt.pix_mp.num_planes, - f->fmt.pix_mp.pixelformat); + "%s, type: %u, planes: %u, fmt: %x\n", + __func__, f->type, + V4L2_TYPE_IS_MULTIPLANAR(f->type) ? + q_data->fmt->num_planes : 1, + q_data->fmt->fourcc); return 0; } @@ -2007,21 +3019,32 @@ for (i = 0; i < *nplanes; i++) { if (sizes[i] < q_data->sizeimage[i]) return -EINVAL; - //alloc_devs[i] = &ctx->dev->plat_dev->dev; - alloc_devs[i] = v4l_get_dev_from_codec_mm();//alloc mm from the codec mm + alloc_devs[i] = &ctx->dev->plat_dev->dev; + + if (!V4L2_TYPE_IS_OUTPUT(vq->type)) + alloc_devs[i] = v4l_get_dev_from_codec_mm(); } } else { + int dw_mode = VDEC_DW_NO_AFBC; + if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) *nplanes = 2; else *nplanes = 1; + if (!vdec_if_get_param(ctx, GET_PARAM_DW_MODE, &dw_mode)) { + if (dw_mode == VDEC_DW_AFBC_ONLY) + *nplanes = 1; + } + for (i = 0; i < *nplanes; i++) { sizes[i] = q_data->sizeimage[i]; if (V4L2_TYPE_IS_OUTPUT(vq->type) && ctx->output_dma_mode) - sizes[i] = 0; - //alloc_devs[i] = &ctx->dev->plat_dev->dev; - alloc_devs[i] = v4l_get_dev_from_codec_mm();//alloc mm from the codec mm + sizes[i] = 1; + alloc_devs[i] = &ctx->dev->plat_dev->dev; + + if (!V4L2_TYPE_IS_OUTPUT(vq->type)) + alloc_devs[i] = v4l_get_dev_from_codec_mm(); } } @@ -2036,6 +3059,8 @@ { struct aml_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct aml_q_data *q_data; + struct vb2_v4l2_buffer *vb2_v4l2 = NULL; + struct aml_video_dec_buf *buf = NULL; int i; v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, @@ -2057,65 +3082,710 @@ } } + vb2_v4l2 = to_vb2_v4l2_buffer(vb); + buf = container_of(vb2_v4l2, struct aml_video_dec_buf, vb); + + if (vb2_v4l2->meta_ptr && (copy_from_user(buf->meta_data, + (void *)vb2_v4l2->meta_ptr, META_DATA_SIZE + 4))) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "%s:copy meta data error. ptr: %lx\n", __func__, vb2_v4l2->meta_ptr); + } + return 0; } +static int init_mmu_bmmu_box(struct aml_vcodec_ctx *ctx) +{ + int i; + int mmu_flag = ctx->is_drm_mode? CODEC_MM_FLAGS_TVP:0; + int bmmu_flag = mmu_flag; + u32 dw_mode = VDEC_DW_NO_AFBC; + + ctx->comp_bufs = vzalloc(sizeof(*ctx->comp_bufs) * V4L_CAP_BUFF_MAX); + if (!ctx->comp_bufs) + return -ENOMEM; + + if (vdec_if_get_param(ctx, GET_PARAM_DW_MODE, &dw_mode)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "invalid dw_mode\n"); + goto free_comp_bufs; + } + + /* init mmu box */ + ctx->mmu_box = decoder_mmu_box_alloc_box("v4l2_dec", + ctx->id, V4L_CAP_BUFF_MAX, + ctx->comp_info.max_size * SZ_1M, mmu_flag); + if (!ctx->mmu_box) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "fail to create mmu box\n"); + goto free_comp_bufs; + } + + /* init bmmu box */ + bmmu_flag |= CODEC_MM_FLAGS_CMA_CLEAR | CODEC_MM_FLAGS_FOR_VDECODER; + ctx->bmmu_box = decoder_bmmu_box_alloc_box("v4l2_dec", + ctx->id, V4L_CAP_BUFF_MAX, + 4 + PAGE_SHIFT, bmmu_flag); + if (!ctx->bmmu_box) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "fail to create bmmu box\n"); + goto free_mmubox; + } + + if (dw_mode & 0x20) { + /* init mmu box dw*/ + ctx->mmu_box_dw = decoder_mmu_box_alloc_box("v4l2_dec", + ctx->id, V4L_CAP_BUFF_MAX, + ctx->comp_info.max_size * SZ_1M, mmu_flag); + if (!ctx->mmu_box_dw) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "fail to create mmu box dw\n"); + goto free_bmmubox; + } + + /* init bmmu box dw*/ + bmmu_flag |= CODEC_MM_FLAGS_CMA_CLEAR | CODEC_MM_FLAGS_FOR_VDECODER; + ctx->bmmu_box_dw = decoder_bmmu_box_alloc_box("v4l2_dec", + ctx->id, V4L_CAP_BUFF_MAX, + 4 + PAGE_SHIFT, bmmu_flag); + if (!ctx->bmmu_box_dw) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "fail to create bmmu box dw\n"); + goto free_mmubox_dw; + } + } + + kref_init(&ctx->box_ref); + for (i = 0; i < V4L_CAP_BUFF_MAX; i++) { + struct internal_comp_buf *buf; + buf = &ctx->comp_bufs[i]; + buf->index = i; + buf->ref = 0; + buf->box_ref = &ctx->box_ref; + buf->mmu_box = ctx->mmu_box; + buf->bmmu_box = ctx->bmmu_box; + buf->mmu_box_dw = ctx->mmu_box_dw; + buf->bmmu_box_dw = ctx->bmmu_box_dw; + } + kref_get(&ctx->ctx_ref); + + ctx->uvm_proxy = vzalloc(sizeof(*ctx->uvm_proxy) * V4L_CAP_BUFF_MAX); + if (!ctx->uvm_proxy) + goto free_mmubox; + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, + "box init, bmmu: %px, mmu: %px, mmu_dw: %px bmmu_dw: %px\n", + ctx->bmmu_box, ctx->mmu_box, ctx->mmu_box_dw, ctx->bmmu_box_dw); + + return 0; +free_mmubox_dw: + decoder_mmu_box_free(ctx->mmu_box_dw); + ctx->mmu_box_dw = NULL; + +free_bmmubox: + decoder_bmmu_box_free(ctx->bmmu_box); + ctx->bmmu_box = NULL; + +free_mmubox: + decoder_mmu_box_free(ctx->mmu_box); + ctx->mmu_box = NULL; + +free_comp_bufs: + vfree(ctx->comp_bufs); + ctx->comp_bufs = NULL; + + return -1; +} + +void aml_alloc_buffer(struct aml_vcodec_ctx *ctx, int flag) +{ + int i = 0; + + if (flag & DV_TYPE) { + for (i = 0; i < V4L_CAP_BUFF_MAX; i++) { + ctx->aux_infos.bufs[i].md_buf = vzalloc(MD_BUF_SIZE); + if (ctx->aux_infos.bufs[i].md_buf == NULL) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "v4l2 alloc %dth dv md buffer fail\n", i); + } + + ctx->aux_infos.bufs[i].comp_buf = vzalloc(COMP_BUF_SIZE); + if (ctx->aux_infos.bufs[i].comp_buf == NULL) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "v4l2 alloc %dth dv comp buffer fail\n", i); + } + } + } + + if (flag & SEI_TYPE) { + for (i = 0; i < V4L_CAP_BUFF_MAX; i++) { + ctx->aux_infos.bufs[i].sei_buf = vzalloc(SEI_BUF_SIZE); + if (ctx->aux_infos.bufs[i].sei_buf) { + ctx->aux_infos.bufs[i].sei_size = 0; + ctx->aux_infos.bufs[i].sei_state = 1; + ctx->aux_infos.sei_need_free = false; + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + "v4l2 alloc %dth aux buffer:%px\n", + i, ctx->aux_infos.bufs[i].sei_buf); + } else { + ctx->aux_infos.bufs[i].sei_buf = NULL; + ctx->aux_infos.bufs[i].sei_state = 0; + ctx->aux_infos.bufs[i].sei_size = 0; + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "v4l2 alloc %dth aux buffer fail\n", i); + } + } + } +} + +void aml_free_buffer(struct aml_vcodec_ctx *ctx, int flag) +{ + int i = 0; + + if (flag & DV_TYPE) { + for (i = 0; i < V4L_CAP_BUFF_MAX; i++) { + if (ctx->aux_infos.bufs[i].md_buf != NULL) { + vfree(ctx->aux_infos.bufs[i].md_buf); + ctx->aux_infos.bufs[i].md_buf = NULL; + } + + if (ctx->aux_infos.bufs[i].comp_buf != NULL) { + vfree(ctx->aux_infos.bufs[i].comp_buf); + ctx->aux_infos.bufs[i].comp_buf = NULL; + } + } + } + + if (flag & SEI_TYPE) { + for (i = 0; i < V4L_CAP_BUFF_MAX; i++) { + if (ctx->aux_infos.bufs[i].sei_buf != NULL) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + "v4l2 free %dth aux buffer:%px\n", + i, ctx->aux_infos.bufs[i].sei_buf); + vfree(ctx->aux_infos.bufs[i].sei_buf); + ctx->aux_infos.bufs[i].sei_state = 0; + ctx->aux_infos.bufs[i].sei_size = 0; + ctx->aux_infos.bufs[i].sei_buf = NULL; + } + } + } +} + +void aml_free_one_sei_buffer(struct aml_vcodec_ctx *ctx, char **addr, int *size, int idx) +{ + if (ctx->aux_infos.bufs[idx].sei_buf != NULL) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + "v4l2 free %dth aux buffer:%px\n", + idx, ctx->aux_infos.bufs[idx].sei_buf); + + vfree(ctx->aux_infos.bufs[idx].sei_buf); + ctx->aux_infos.bufs[idx].sei_state = 0; + ctx->aux_infos.bufs[idx].sei_size = 0; + ctx->aux_infos.bufs[idx].sei_buf = NULL; + *addr = NULL; + *size = 0; + ctx->aux_infos.sei_need_free = true; + } +} + +void aml_bind_sei_buffer(struct aml_vcodec_ctx *ctx, char **addr, int *size, int *idx) +{ + int index = ctx->aux_infos.sei_index; + int count = 0; + + if (ctx->aux_infos.sei_need_free) { + for (count = 0; count < V4L_CAP_BUFF_MAX; count++) { + if ((ctx->aux_infos.bufs[index].sei_buf != NULL) && + (ctx->aux_infos.bufs[index].sei_state == 1)) { + break; + } + index = (index + 1) % V4L_CAP_BUFF_MAX; + } + } else { + for (count = 0; count < V4L_CAP_BUFF_MAX; count++) { + if ((ctx->aux_infos.bufs[index].sei_buf != NULL) && + ((ctx->aux_infos.bufs[index].sei_state == 1) || + (ctx->aux_infos.bufs[index].sei_state == 2))) { + memset(ctx->aux_infos.bufs[index].sei_buf, 0, SEI_BUF_SIZE); + ctx->aux_infos.bufs[index].sei_size = 0; + break; + } + index = (index + 1) % V4L_CAP_BUFF_MAX; + } + } + + if (count == V4L_CAP_BUFF_MAX) { + *addr = NULL; + *size = 0; + } else { + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + "v4l2 bind %dth aux buffer:%px, count = %d\n", + index, ctx->aux_infos.bufs[index].sei_buf, count); + *addr = ctx->aux_infos.bufs[index].sei_buf; + *size = ctx->aux_infos.bufs[index].sei_size; + *idx = index; + ctx->aux_infos.bufs[index].sei_state = 2; + ctx->aux_infos.sei_index = (index + 1) % V4L_CAP_BUFF_MAX; + } +} + +void aml_bind_dv_buffer(struct aml_vcodec_ctx *ctx, char **comp_buf, char **md_buf) +{ + int index = ctx->aux_infos.dv_index; + + if ((ctx->aux_infos.bufs[index].comp_buf != NULL) && + (ctx->aux_infos.bufs[index].md_buf != NULL)) { + *comp_buf = ctx->aux_infos.bufs[index].comp_buf; + *md_buf = ctx->aux_infos.bufs[index].md_buf; + ctx->aux_infos.dv_index = (index + 1) % V4L_CAP_BUFF_MAX; + } +} + +void aml_v4l_ctx_release(struct kref *kref) +{ + struct aml_vcodec_ctx * ctx; + + ctx = container_of(kref, struct aml_vcodec_ctx, ctx_ref); + + if (ctx->vpp) { + atomic_dec(&ctx->dev->vpp_count); + aml_v4l2_vpp_destroy(ctx->vpp); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, + "vpp destory inst count:%d.\n", + atomic_read(&ctx->dev->vpp_count)); + } + + if (ctx->ge2d) { + aml_v4l2_ge2d_destroy(ctx->ge2d); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, + "ge2d destory.\n"); + } + + v4l2_m2m_ctx_release(ctx->m2m_ctx); + aml_task_chain_remove(ctx); + + vfree(ctx->meta_infos.meta_bufs); + ctx->aux_infos.free_buffer(ctx, SEI_TYPE | DV_TYPE); + ctx->aux_infos.free_buffer(ctx, 1); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, + "v4ldec has been destroyed.\n"); + + if (ctx->sync) { + vdec_clean_all_fence(ctx->sync); + } + + kfree(ctx); +} + +static void box_release(struct kref *kref) +{ + struct aml_vcodec_ctx * ctx + = container_of(kref, struct aml_vcodec_ctx, box_ref); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, + "%s, bmmu: %px, mmu: %px mmu_dw: %pu\n", + __func__, ctx->bmmu_box, ctx->mmu_box,ctx->mmu_box_dw); + + decoder_bmmu_box_free(ctx->bmmu_box); + decoder_mmu_box_free(ctx->mmu_box); + + if (ctx->config.parm.dec.cfg.double_write_mode & 0x20) { + decoder_mmu_box_free(ctx->mmu_box_dw); + decoder_bmmu_box_free(ctx->bmmu_box_dw); + } + vfree(ctx->comp_bufs); + vfree(ctx->uvm_proxy); + kref_put(&ctx->ctx_ref, aml_v4l_ctx_release); +} + +static void internal_buf_free(void *arg) +{ + struct internal_comp_buf* ibuf = + (struct internal_comp_buf*)arg; + struct aml_vcodec_ctx * ctx + = container_of(ibuf->box_ref,struct aml_vcodec_ctx, box_ref); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, + "%s, idx:%d\n", __func__, ibuf->index); + + mutex_lock(&ctx->comp_lock); + + if (!(ibuf->ref & 0xff00)) { + decoder_mmu_box_free_idx(ibuf->mmu_box, ibuf->index); + decoder_bmmu_box_free_idx(ibuf->bmmu_box, ibuf->index); + + if (ctx->config.parm.dec.cfg.double_write_mode & 0x20) { + decoder_mmu_box_free_idx(ibuf->mmu_box_dw, ibuf->index); + decoder_bmmu_box_free_idx(ibuf->bmmu_box_dw, ibuf->index); + } + } + ibuf->ref = 0; + + mutex_unlock(&ctx->comp_lock); + + kref_put(ibuf->box_ref, box_release); +} + +static void internal_buf_free2(void *arg) +{ + struct internal_comp_buf *ibuf = + container_of(arg, struct internal_comp_buf, priv_data); + struct aml_vcodec_ctx * ctx + = container_of(ibuf->box_ref, struct aml_vcodec_ctx, box_ref); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, + "%s, idx: %d\n", __func__, ibuf->index); + + mutex_lock(&ctx->comp_lock); + + if (!(ibuf->ref & 0xff00)) { + decoder_mmu_box_free_idx(ibuf->mmu_box, ibuf->index); + decoder_bmmu_box_free_idx(ibuf->bmmu_box, ibuf->index); + + if (ctx->config.parm.dec.cfg.double_write_mode & 0x20) { + decoder_mmu_box_free_idx(ibuf->mmu_box_dw, ibuf->index); + decoder_bmmu_box_free_idx(ibuf->bmmu_box_dw, ibuf->index); + } + } + ibuf->ref = 0; + + mutex_unlock(&ctx->comp_lock); + + kref_put(ibuf->box_ref, box_release); +} + +static void aml_uvm_buf_free(void *arg) +{ + struct aml_uvm_buff_ref * ubuf = + (struct aml_uvm_buff_ref*)arg; + struct aml_vcodec_ctx * ctx + = container_of(ubuf->ref, struct aml_vcodec_ctx, ctx_ref); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, + "%s, vb:%d, dbuf:%px, ino:%lu\n", + __func__, ubuf->index, ubuf->dbuf, + file_inode(ubuf->dbuf->file)->i_ino); + + kref_put(ubuf->ref, aml_v4l_ctx_release); + vfree(ubuf); +} + +static int uvm_attach_hook_mod_local(struct aml_vcodec_ctx *ctx, + struct uvm_hook_mod_info *uvm) +{ + struct internal_comp_buf* ibuf = uvm->arg; + + ctx->uvm_proxy[ibuf->index] = *uvm; + + return 0; +} + +static int update_comp_buffer_to_reuse(struct aml_vcodec_ctx *ctx, + struct aml_video_dec_buf *buf) +{ + struct internal_comp_buf* ibuf = NULL; + + mutex_lock(&ctx->comp_lock); + + ibuf = vb_to_comp(ctx, &buf->vb.vb2_buf); + if (!ibuf) { + mutex_unlock(&ctx->comp_lock); + return 0; + } + + if (ibuf->ref & 0xff) { + buf->internal_index = ibuf->index; + ibuf->frame_buffer_size = ctx->comp_info.frame_buffer_size; + + if (ctx->comp_info.header_size != ibuf->header_size) { + decoder_bmmu_box_free_idx(ctx->bmmu_box, ibuf->index); + if (decoder_bmmu_box_alloc_buf_phy(ctx->bmmu_box, + ibuf->index, ctx->comp_info.header_size, + "v4l2_dec", &ibuf->header_addr) < 0) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "fail to alloc %dth bmmu\n", + ibuf->index); + mutex_unlock(&ctx->comp_lock); + return -ENOMEM; + } + ibuf->header_size = ctx->comp_info.header_size; + } + + ibuf->ref |= (1 << 8); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, + "%s, reuse comp buffer vb2:%d <--> internal: %d, header_addr 0x%lx, size: %u\n", + __func__, buf->vb.vb2_buf.index, + buf->internal_index, + ibuf->header_addr, + ibuf->header_size); + } + + mutex_unlock(&ctx->comp_lock); + + return (ibuf->ref & 0xff00) ? 1 : 0; +} + +static int bind_comp_buffer_to_uvm(struct aml_vcodec_ctx *ctx, + struct aml_video_dec_buf *buf) +{ + int ret, i; + struct dma_buf * dma = buf->vb.vb2_buf.planes[0].dbuf; + struct aml_dec_params *parms = &ctx->config.parm.dec; + struct uvm_hook_mod_info u_info; + struct internal_comp_buf* ibuf; + u32 dw_mode = VDEC_DW_NO_AFBC; + + /* get header and page size */ + if (vdec_if_get_param(ctx, GET_PARAM_COMP_BUF_INFO, &ctx->comp_info)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "fail to get comp info\n"); + return -EINVAL; + } + + if (!ctx->bmmu_box || !ctx->mmu_box) + if (init_mmu_bmmu_box(ctx)) + return -EINVAL; + + ret = update_comp_buffer_to_reuse(ctx, buf); + if (ret < 0) + return ret; + + if (ret == 1 /*reused*/) + return 0; + + for (i = 0; i < V4L_CAP_BUFF_MAX; i++) { + if (!ctx->comp_bufs[i].ref) + break; + } + + if (i == V4L_CAP_BUFF_MAX) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "out of internal buf\n"); + return -EINVAL; + } + + if (vdec_if_get_param(ctx, GET_PARAM_DW_MODE, &dw_mode)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "invalid dw_mode\n"); + return -EINVAL; + } + + buf->internal_index = i; + ibuf = &ctx->comp_bufs[i]; + ibuf->frame_buffer_size = ctx->comp_info.frame_buffer_size; + ibuf->header_size = ctx->comp_info.header_size; + + /* allocate header */ + ret = decoder_bmmu_box_alloc_buf_phy(ctx->bmmu_box, + ibuf->index, ctx->comp_info.header_size, + "v4l2_dec", &ibuf->header_addr); + if (ret < 0) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "fail to alloc %dth bmmu\n", i); + return -ENOMEM; + } + + if (dw_mode & 0x20) { + ret = decoder_bmmu_box_alloc_buf_phy(ctx->bmmu_box_dw, + ibuf->index, ctx->comp_info.header_size, + "v4l2_dec", &ibuf->header_dw_addr); + if (ret < 0) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "fail to alloc %dth bmmu dw\n", i); + return -ENOMEM; + } + } + + kref_get(&ctx->box_ref); + ibuf->ref = 1; + + /* frame SG buffer need to be realloc inside decoder, + * just before slice decoding to save memory + */ + u_info.type = VF_SRC_DECODER; + u_info.arg = ibuf; + u_info.free = internal_buf_free; + + if (parms->cfg.uvm_hook_type == VF_PROCESS_V4LVIDEO) { + /* adapted video composer to use for hwc. */ + ibuf->priv_data.v4l_inst_id = ctx->id; + u_info.type = VF_PROCESS_V4LVIDEO; + u_info.arg = &ibuf->priv_data; + u_info.free = internal_buf_free2; + } + + ret = dmabuf_is_uvm(dma) ? + uvm_attach_hook_mod(dma, &u_info) : + uvm_attach_hook_mod_local(ctx, &u_info); + if (ret < 0) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "fail to set dmabuf priv buf\n"); + goto bmmu_box_free; + } + + v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, + "%s, bind vb2:(%d, %px) <--> internal: (%d, %px) header_addr 0x%lx, size: %u\n", + __func__, buf->vb.vb2_buf.index, + dma, i, ibuf, ibuf->header_addr, + ctx->comp_info.header_size); + + return 0; + +bmmu_box_free: + if (dw_mode & 0x20) { + decoder_bmmu_box_free_idx(ibuf->bmmu_box_dw, ibuf->index); + } + decoder_bmmu_box_free_idx(ibuf->bmmu_box, ibuf->index); + kref_put(&ctx->box_ref, box_release); + ibuf->ref = 0; + return -EINVAL; +} + +static int aml_uvm_buff_attach(struct vb2_buffer * vb) +{ + int ret = 0; + struct dma_buf *dbuf = vb->planes[0].dbuf; + struct uvm_hook_mod_info u_info; + struct aml_vcodec_ctx *ctx = + vb2_get_drv_priv(vb->vb2_queue); + struct aml_uvm_buff_ref *ubuf = NULL; + + if (vb->memory != VB2_MEMORY_DMABUF || !dmabuf_is_uvm(dbuf)) + return 0; + + ubuf = vzalloc(sizeof(struct aml_uvm_buff_ref)); + if (ubuf == NULL) + return -ENOMEM; + + ubuf->index = vb->index; + ubuf->addr = vb2_dma_contig_plane_dma_addr(vb, 0); + ubuf->dbuf = dbuf; + ubuf->ref = &ctx->ctx_ref; + + u_info.type = VF_PROCESS_DECODER; + u_info.arg = (void *)ubuf; + u_info.free = aml_uvm_buf_free; + ret = uvm_attach_hook_mod(dbuf, &u_info); + if (ret < 0) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "aml uvm buffer %d attach fail.\n", + ubuf->index); + return ret; + } + + kref_get(ubuf->ref); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, + "%s, vb:%d, dbuf:%px, ino:%lu\n", + __func__, ubuf->index, ubuf->dbuf, + file_inode(ubuf->dbuf->file)->i_ino); + + return ret; +} + +static struct internal_comp_buf* vb_to_comp(struct aml_vcodec_ctx *ctx, + struct vb2_buffer *vb) +{ + struct aml_dec_params *parms = &ctx->config.parm.dec; + bool is_v4lvideo = (parms->cfg.uvm_hook_type == VF_PROCESS_V4LVIDEO); + enum uvm_hook_mod_type u_type = + is_v4lvideo ? VF_PROCESS_V4LVIDEO : VF_SRC_DECODER; + struct dma_buf *dbuf = vb->planes[0].dbuf; + struct internal_comp_buf *ibuf = NULL; + struct uvm_hook_mod *uhmod = NULL; + + uhmod = uvm_get_hook_mod(dbuf, u_type); + if (IS_ERR_OR_NULL(uhmod)) + return NULL; + + ibuf = !is_v4lvideo ? (struct internal_comp_buf *) uhmod->arg : + container_of(uhmod->arg, struct internal_comp_buf, priv_data); + + uvm_put_hook_mod(dbuf, u_type); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + "%s, vb2: (%d, %px) --> comp: (%d, %px)\n", + __func__, vb->index, dbuf, ibuf->index, ibuf); + + return ibuf; +} + static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) { struct aml_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct vb2_v4l2_buffer *vb2_v4l2 = NULL; - struct aml_video_dec_buf *buf = NULL; + struct vb2_v4l2_buffer *vb2_v4l2 = to_vb2_v4l2_buffer(vb); + struct aml_video_dec_buf *buf = + container_of(vb2_v4l2, struct aml_video_dec_buf, vb); + struct vdec_v4l2_buffer *fb = &buf->frame_buffer; struct aml_vcodec_mem src_mem; - unsigned int dpb = 0; - - vb2_v4l2 = to_vb2_v4l2_buffer(vb); - buf = container_of(vb2_v4l2, struct aml_video_dec_buf, vb); v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s, vb: %lx, type: %d, idx: %d, state: %d, used: %d, ts: %llu\n", __func__, (ulong) vb, vb->vb2_queue->type, vb->index, vb->state, buf->used, vb->timestamp); + /* * check if this buffer is ready to be used after decode */ if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { - if (vb->index >= ctx->dpb_size) { - v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, - "enque capture buf idx %d/%d is invalid.\n", - vb->index, ctx->dpb_size); - return; - } + u32 dw_mode = VDEC_DW_NO_AFBC; - v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, - "y_addr: %lx, vf_h: %lx, state: %d", - buf->frame_buffer.m.mem[0].addr, - buf->frame_buffer.vf_handle, - buf->frame_buffer.status); + if (vdec_if_get_param(ctx, GET_PARAM_DW_MODE, &dw_mode)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "invalid dw_mode\n"); + return; + + } if (!buf->que_in_m2m) { v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, "enque capture buf idx %d, vf: %lx\n", vb->index, (ulong) v4l_get_vf_handle(vb2_v4l2->private)); - v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2); - buf->que_in_m2m = true; - buf->queued_in_vb2 = true; - buf->queued_in_v4l2 = true; - buf->ready_to_display = false; + /* bind compressed buffer to uvm */ + if ((dw_mode != VDEC_DW_NO_AFBC) && + vb->memory == VB2_MEMORY_DMABUF && + bind_comp_buffer_to_uvm(ctx, buf)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "fail to bind comp buffer\n"); + return; + } + + /* DI hook must be detached if the dmabuff be reused. */ + if (ctx->vpp_cfg.enable_local_buf) { + struct dma_buf *dma = vb->planes[0].dbuf; + + if (dmabuf_is_uvm(dma) && + uvm_detach_hook_mod(dma, VF_PROCESS_DI) < 0) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + "dmabuf without attach DI hook.\n"); + } + } + + task_chain_clean(fb->task); + ctx->cap_pool.seq[ctx->cap_pool.in++] = (V4L_CAP_BUFF_IN_M2M << 16 | vb->index); + v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2); + buf->que_in_m2m = true; + + fb->status = FB_ST_INIT; + ATRACE_COUNTER("VC_IN_VSINK-2.storage", vb->index); /* check dpb ready */ aml_check_dpb_ready(ctx); - } else if (buf->frame_buffer.status == FB_ST_DISPLAY) { - buf->queued_in_vb2 = false; - buf->queued_in_v4l2 = true; - buf->ready_to_display = false; + } else { + struct vframe_s *vf = fb->vframe; + struct task_chain_s *task = fb->task; - /* recycle vf */ - video_vf_put(ctx->ada_ctx->recv_name, - &buf->frame_buffer, ctx->id); + v4l_dbg(ctx, V4L_DEBUG_CODEC_OUTPUT, + "IN__BUFF (%s, st:%d, seq:%d) vb:(%d, %px), vf:(%d, %px), ts:%lld, " + "Y:(%lx, %u) C/U:(%lx, %u) V:(%lx, %u)\n", + ctx->ada_ctx->frm_name, fb->status, vf ? vf->index_disp : -1, + vb->index, vb, + vf ? vf->index & 0xff : -1, vf, + vf ? vf->timestamp : 0, + fb->m.mem[0].addr, fb->m.mem[0].size, + fb->m.mem[1].addr, fb->m.mem[1].size, + fb->m.mem[2].addr, fb->m.mem[2].size); + + ATRACE_COUNTER("VC_IN_VSINK-4.recycle", vb->index); + + task->recycle(task, TASK_TYPE_V4L_SINK); } + + wake_up_interruptible(&ctx->cap_wq); return; } @@ -2125,28 +3795,41 @@ return; } + buf->used = true; vb2_v4l2 = to_vb2_v4l2_buffer(vb); buf = container_of(vb2_v4l2, struct aml_video_dec_buf, vb); if (buf->lastframe) { /* This shouldn't happen. Just in case. */ v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "Invalid flush buffer.\n"); + buf->used = false; v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + if (ctx->is_drm_mode && (vb->memory == VB2_MEMORY_DMABUF)) + wake_up_interruptible(&ctx->wq); + return; } src_mem.index = vb->index; src_mem.vaddr = vb2_plane_vaddr(vb, 0); - src_mem.addr = vb2_dma_contig_plane_dma_addr(vb, 0); + src_mem.addr = sg_dma_address(buf->out_sgt->sgl); src_mem.size = vb->planes[0].bytesused; src_mem.model = vb->memory; src_mem.timestamp = vb->timestamp; + src_mem.meta_ptr = (ulong)buf->meta_data; if (vdec_if_probe(ctx, &src_mem, NULL)) { + buf->used = false; v4l2_m2m_src_buf_remove(ctx->m2m_ctx); - if (!(ctx->is_drm_mode && src_mem.model == VB2_MEMORY_DMABUF)) - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_DONE); + if (ctx->is_drm_mode && + (src_mem.model == VB2_MEMORY_DMABUF)) { + wake_up_interruptible(&ctx->wq); + } else { + v4l2_buff_done(to_vb2_v4l2_buffer(vb), + VB2_BUF_STATE_DONE); + } + return; } @@ -2154,11 +3837,14 @@ * If on model dmabuf must remove the buffer * because this data has been consumed by hw. */ - if (ctx->is_drm_mode && src_mem.model == VB2_MEMORY_DMABUF) { - v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + buf->used = false; + v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + + if (ctx->is_drm_mode && + (src_mem.model == VB2_MEMORY_DMABUF)) { + wake_up_interruptible(&ctx->wq); } else if (ctx->param_sets_from_ucode) { - v4l2_m2m_src_buf_remove(ctx->m2m_ctx); - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), + v4l2_buff_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_DONE); } @@ -2168,23 +3854,24 @@ return; } - if (vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpb)) { - v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, - "GET_PARAM_DPB_SIZE err\n"); - return; - } - - if (!dpb) + if (!ctx->picinfo.dpb_frames) return; - ctx->dpb_size = dpb; + v4l_buf_size_decision(ctx); ctx->last_decoded_picinfo = ctx->picinfo; + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, + "Picture buffer count: dec:%u, vpp:%u, ge2d:%u, margin:%u, total:%u\n", + ctx->picinfo.dpb_frames, ctx->vpp_size, ctx->ge2d_size, + ctx->picinfo.dpb_margin, + CTX_BUF_TOTAL(ctx)); + aml_vdec_dispatch_event(ctx, V4L2_EVENT_SRC_CH_RESOLUTION); mutex_lock(&ctx->state_lock); if (ctx->state == AML_STATE_INIT) { ctx->state = AML_STATE_PROBE; - ATRACE_COUNTER("v4l2_state", ctx->state); + ATRACE_COUNTER("V_ST_VSINK-state", ctx->state); v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, "vcodec state (AML_STATE_PROBE)\n"); } @@ -2196,26 +3883,19 @@ struct aml_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct vb2_v4l2_buffer *vb2_v4l2 = NULL; struct aml_video_dec_buf *buf = NULL; - bool buf_error; v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s, type: %d, idx: %d\n", __func__, vb->vb2_queue->type, vb->index); - vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf); + vb2_v4l2 = to_vb2_v4l2_buffer(vb); buf = container_of(vb2_v4l2, struct aml_video_dec_buf, vb); - if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { - buf->queued_in_v4l2 = false; - buf->queued_in_vb2 = false; - } - buf_error = buf->error; - - if (buf_error) { + if (buf->error) { v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "Unrecoverable error on buffer.\n"); ctx->state = AML_STATE_ABORT; - ATRACE_COUNTER("v4l2_state", ctx->state); + ATRACE_COUNTER("V_ST_VSINK-state", ctx->state); v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, "vcodec state (AML_STATE_ABORT)\n"); } @@ -2228,108 +3908,145 @@ struct vb2_v4l2_buffer, vb2_buf); struct aml_video_dec_buf *buf = container_of(vb2_v4l2, struct aml_video_dec_buf, vb); - unsigned int size, phy_addr = 0; - char *owner = __getname(); + struct vdec_v4l2_buffer *fb = &buf->frame_buffer; + u32 size, phy_addr = 0; + int i; v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s, type: %d, idx: %d\n", __func__, vb->vb2_queue->type, vb->index); - if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { - buf->used = false; - buf->ready_to_display = false; - buf->queued_in_v4l2 = false; - buf->frame_buffer.status = FB_ST_NORMAL; - } else { + if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { buf->lastframe = false; } /* codec_mm buffers count */ - if (V4L2_TYPE_IS_OUTPUT(vb->type)) { + if (!V4L2_TYPE_IS_OUTPUT(vb->type)) { if (vb->memory == VB2_MEMORY_MMAP) { - size = vb->planes[0].length; - phy_addr = vb2_dma_contig_plane_dma_addr(vb, 0); - snprintf(owner, PATH_MAX, "%s-%d", "v4l-input", ctx->id); + char *owner = __getname(); + + snprintf(owner, PATH_MAX, "%s-%d", "v4l-output", ctx->id); strncpy(buf->mem_onwer, owner, sizeof(buf->mem_onwer)); buf->mem_onwer[sizeof(buf->mem_onwer) - 1] = '\0'; + __putname(owner); - buf->mem[0] = v4l_reqbufs_from_codec_mm(buf->mem_onwer, - phy_addr, size, vb->index); - v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, - "IN alloc, addr: %x, size: %u, idx: %u\n", - phy_addr, size, vb->index); - } - } else { - snprintf(owner, PATH_MAX, "%s-%d", "v4l-output", ctx->id); - strncpy(buf->mem_onwer, owner, sizeof(buf->mem_onwer)); - buf->mem_onwer[sizeof(buf->mem_onwer) - 1] = '\0'; + for (i = 0; i < vb->num_planes; i++) { + size = vb->planes[i].length; + phy_addr = vb2_dma_contig_plane_dma_addr(vb, i); + buf->mem[i] = v4l_reqbufs_from_codec_mm(buf->mem_onwer, + phy_addr, size, vb->index); + v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, + "OUT %c alloc, addr: %x, size: %u, idx: %u\n", + (i == 0? 'Y':'C'), phy_addr, size, vb->index); + } + } else if (vb->memory == VB2_MEMORY_DMABUF) { + unsigned int dw_mode = VDEC_DW_NO_AFBC; - if ((vb->memory == VB2_MEMORY_MMAP) && (vb->num_planes == 1)) { - size = vb->planes[0].length; - phy_addr = vb2_dma_contig_plane_dma_addr(vb, 0); - buf->mem[0] = v4l_reqbufs_from_codec_mm(buf->mem_onwer, - phy_addr, size, vb->index); - v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, - "OUT Y alloc, addr: %x, size: %u, idx: %u\n", - phy_addr, size, vb->index); - } else if ((vb->memory == VB2_MEMORY_MMAP) && (vb->num_planes == 2)) { - size = vb->planes[0].length; - phy_addr = vb2_dma_contig_plane_dma_addr(vb, 0); - buf->mem[0] = v4l_reqbufs_from_codec_mm(buf->mem_onwer, - phy_addr, size, vb->index); - v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, - "OUT Y alloc, addr: %x, size: %u, idx: %u\n", - phy_addr, size, vb->index); + for (i = 0; i < vb->num_planes; i++) { + struct dma_buf * dma; - size = vb->planes[1].length; - phy_addr = vb2_dma_contig_plane_dma_addr(vb, 1); - buf->mem[1] = v4l_reqbufs_from_codec_mm(buf->mem_onwer, - phy_addr, size, vb->index); - v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, - "OUT C alloc, addr: %x, size: %u, idx: %u\n", - phy_addr, size, vb->index); + if (vdec_if_get_param(ctx, GET_PARAM_DW_MODE, &dw_mode)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "invalid dw_mode\n"); + return -EINVAL; + } + /* None-DW mode means single layer */ + if (dw_mode == VDEC_DW_AFBC_ONLY && i > 0) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "only support single plane in dw mode 0\n"); + return -EINVAL; + } + size = vb->planes[i].length; + dma = vb->planes[i].dbuf; + + if (!dmabuf_is_uvm(dma)) + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "non-uvm dmabuf\n"); + } } } - __putname(owner); + if (!V4L2_TYPE_IS_OUTPUT(vb->type)) { + struct vframe_s *vf = NULL; + struct task_chain_s *task = NULL; + struct task_chain_s *task_pre = fb->task; + u32 icomp = -1; + + fb_map_table_fetch(ctx, vb, &vf, &task, &icomp); + if (vf) { + fb->task = task; + fb->vframe = vf; + vf->v4l_mem_handle = (ulong)fb; + buf->internal_index = icomp; + task_chain_update_object(task, fb); + } else { + buf->que_in_m2m = false; + + if (aml_uvm_buff_attach(vb)) + return -EFAULT; + + if (task_chain_init(&fb->task, ctx, fb, vb->index)) + return -EFAULT; + + list_add(&fb->task->node, &ctx->task_chain_pool); + } + + v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, + "init buffer(%s), vb idx:%d, task:(%px -> %px), addr:(%lx -> %lx), icomp:%d\n", + vf ? "update" : "idel", + vb->index, task_pre, fb->task, + fb->m.mem[0].addr, + (ulong) vb2_dma_contig_plane_dma_addr(vb, 0), + (int)icomp); + + update_vdec_buf_plane(ctx, fb, vb); + } + + if (V4L2_TYPE_IS_OUTPUT(vb->type)) { + ulong contig_size; + + buf->out_sgt = vb2_dma_sg_plane_desc(vb, 0); + + contig_size = dmabuf_contiguous_size(buf->out_sgt); + if (contig_size < vb->planes[0].bytesused) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "contiguous mapping is too small %lu/%u\n", + contig_size, size); + return -EFAULT; + } + } return 0; } -static void codec_mm_bufs_cnt_clean(struct vb2_queue *q) +static void vb2ops_vdec_buf_cleanup(struct vb2_buffer *vb) { - struct aml_vcodec_ctx *ctx = vb2_get_drv_priv(q); - struct vb2_v4l2_buffer *vb2_v4l2 = NULL; - struct aml_video_dec_buf *buf = NULL; - int i; + struct aml_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vb2_v4l2 = container_of(vb, + struct vb2_v4l2_buffer, vb2_buf); + struct aml_video_dec_buf *buf = container_of(vb2_v4l2, + struct aml_video_dec_buf, vb); + struct vdec_v4l2_buffer *fb = &buf->frame_buffer;; - for (i = 0; i < q->num_buffers; ++i) { - vb2_v4l2 = to_vb2_v4l2_buffer(q->bufs[i]); - buf = container_of(vb2_v4l2, struct aml_video_dec_buf, vb); - if (IS_ERR_OR_NULL(buf->mem[0])) - return; + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s, type: %d, idx: %d\n", + __func__, vb->vb2_queue->type, vb->index); - if (V4L2_TYPE_IS_OUTPUT(q->bufs[i]->type)) { - v4l_freebufs_back_to_codec_mm(buf->mem_onwer, buf->mem[0]); + if (!V4L2_TYPE_IS_OUTPUT(vb->type)) { + if (vb->memory == VB2_MEMORY_MMAP) { + int i; - v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, - "IN clean, addr: %lx, size: %u, idx: %u\n", - buf->mem[0]->phy_addr, buf->mem[0]->buffer_size, i); - buf->mem[0] = NULL; - continue; + for (i = 0; i < vb->num_planes ; i++) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, + "OUT %c clean, addr: %lx, size: %u, idx: %u\n", + (i == 0)? 'Y':'C', + buf->mem[i]->phy_addr, buf->mem[i]->buffer_size, vb->index); + v4l_freebufs_back_to_codec_mm(buf->mem_onwer, buf->mem[i]); + buf->mem[i] = NULL; + } } - - if (q->memory == VB2_MEMORY_MMAP) { - v4l_freebufs_back_to_codec_mm(buf->mem_onwer, buf->mem[0]); - v4l_freebufs_back_to_codec_mm(buf->mem_onwer, buf->mem[1]); - - v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, - "OUT Y clean, addr: %lx, size: %u, idx: %u\n", - buf->mem[0]->phy_addr, buf->mem[0]->buffer_size, i); - v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, - "OUT C clean, addr: %lx, size: %u, idx: %u\n", - buf->mem[1]->phy_addr, buf->mem[1]->buffer_size, i); - buf->mem[0] = NULL; - buf->mem[1] = NULL; + if (ctx->output_thread_ready) { + if (!is_fb_mapped(ctx, fb->m.mem[0].addr)) { + list_del(&fb->task->node); + task_chain_clean(fb->task); + task_chain_release(fb->task); + } } } } @@ -2339,6 +4056,10 @@ struct aml_vcodec_ctx *ctx = vb2_get_drv_priv(q); ctx->has_receive_eos = false; + ctx->v4l_resolution_change = false; + + /* vdec has ready to decode subsequence data of new resolution. */ + v4l2_m2m_job_resume(ctx->dev->m2m_dev_dec, ctx->m2m_ctx); v4l2_m2m_set_dst_buffered(ctx->fh.m2m_ctx, true); @@ -2359,40 +4080,81 @@ "%s, type: %d, state: %x, frame_cnt: %d\n", __func__, q->type, ctx->state, ctx->decoded_frame_cnt); - codec_mm_bufs_cnt_clean(q); + if (V4L2_TYPE_IS_OUTPUT(q->type)) + ctx->is_out_stream_off = true; + else + ctx->is_stream_off = true; if (V4L2_TYPE_IS_OUTPUT(q->type)) { + struct vb2_queue * que = v4l2_m2m_get_dst_vq(ctx->m2m_ctx); + unsigned long flags; + + cancel_work_sync(&ctx->dmabuff_recycle_work); + spin_lock_irqsave(&ctx->dmabuff_recycle_lock, flags); + INIT_KFIFO(ctx->dmabuff_recycle); + spin_unlock_irqrestore(&ctx->dmabuff_recycle_lock, flags); + while ((vb2_v4l2 = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) - v4l2_m2m_buf_done(vb2_v4l2, VB2_BUF_STATE_ERROR); + v4l2_buff_done(vb2_v4l2, VB2_BUF_STATE_ERROR); for (i = 0; i < q->num_buffers; ++i) { vb2_v4l2 = to_vb2_v4l2_buffer(q->bufs[i]); if (vb2_v4l2->vb2_buf.state == VB2_BUF_STATE_ACTIVE) - v4l2_m2m_buf_done(vb2_v4l2, VB2_BUF_STATE_ERROR); + v4l2_buff_done(vb2_v4l2, VB2_BUF_STATE_ERROR); + } + + /* + * drop es frame was stored in the vdec_input + * if the capture queue have not start streaming. + */ + if (!que->streaming && + (vdec_frame_number(ctx->ada_ctx) > 0) && + (ctx->state < AML_STATE_ACTIVE)) { + ctx->state = AML_STATE_INIT; + ATRACE_COUNTER("V_ST_VSINK-state", ctx->state); + ctx->v4l_resolution_change = false; + ctx->reset_flag = V4L_RESET_MODE_NORMAL; + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, + "force reset to drop es frames.\n"); + wake_up_interruptible(&ctx->cap_wq); + aml_vdec_reset(ctx); } } else { /* clean output cache and decoder status . */ - if (ctx->state > AML_STATE_INIT) + if (ctx->state > AML_STATE_INIT) { + wake_up_interruptible(&ctx->cap_wq); aml_vdec_reset(ctx); + } + + cancel_work_sync(&ctx->decode_work); + mutex_lock(&ctx->capture_buffer_lock); + INIT_KFIFO(ctx->capture_buffer); + mutex_unlock(&ctx->capture_buffer_lock); while ((vb2_v4l2 = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) - v4l2_m2m_buf_done(vb2_v4l2, VB2_BUF_STATE_ERROR); + v4l2_buff_done(vb2_v4l2, VB2_BUF_STATE_ERROR); for (i = 0; i < q->num_buffers; ++i) { vb2_v4l2 = to_vb2_v4l2_buffer(q->bufs[i]); buf = container_of(vb2_v4l2, struct aml_video_dec_buf, vb); - buf->frame_buffer.status = FB_ST_NORMAL; - buf->que_in_m2m = false; - buf->vb.flags = 0; - ctx->cap_pool.seq[i] = 0; + buf->frame_buffer.status = FB_ST_FREE; + buf->frame_buffer.vframe = NULL; + buf->que_in_m2m = false; + buf->used = false; + buf->vb.flags = 0; + ctx->cap_pool.seq[i] = 0; if (vb2_v4l2->vb2_buf.state == VB2_BUF_STATE_ACTIVE) - v4l2_m2m_buf_done(vb2_v4l2, VB2_BUF_STATE_ERROR); + v4l2_buff_done(vb2_v4l2, VB2_BUF_STATE_ERROR); /*v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, "idx: %d, state: %d\n", q->bufs[i]->index, q->bufs[i]->state);*/ } + fb_map_table_clean(ctx); + + fb_token_clean(ctx); + ctx->buf_used_count = 0; ctx->cap_pool.in = 0; ctx->cap_pool.out = 0; @@ -2410,15 +4172,6 @@ queue_work(dev->decode_workqueue, &ctx->decode_work); } -void vdec_device_vf_run(struct aml_vcodec_ctx *ctx) -{ - if (ctx->state < AML_STATE_INIT || - ctx->state > AML_STATE_FLUSHED) - return; - - aml_thread_notify(ctx, AML_THREAD_CAPTURE); -} - static int m2mops_vdec_job_ready(void *m2m_priv) { struct aml_vcodec_ctx *ctx = m2m_priv; @@ -2448,17 +4201,23 @@ switch (ctrl->id) { case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: if (ctx->state >= AML_STATE_PROBE) { - ctrl->val = ctx->dpb_size; + ctrl->val = CTX_BUF_TOTAL(ctx); } else { v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "Seqinfo not ready.\n"); ctrl->val = 0; - ret = -EINVAL; } break; case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: ctrl->val = 4; break; + case AML_V4L2_GET_INPUT_BUFFER_NUM: + if (ctx->ada_ctx != NULL) + ctrl->val = vdec_frame_number(ctx->ada_ctx); + break; + case AML_V4L2_GET_FILMGRAIN_INFO: + ctrl->val = ctx->film_grain_present; + break; default: ret = -EINVAL; } @@ -2476,6 +4235,10 @@ ctx->param_sets_from_ucode = true; v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "set stream mode: %x\n", ctrl->val); + } else if (ctrl->id == AML_V4L2_SET_DURATION) { + vdec_set_duration(ctrl->val); + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, + "set duration: %x\n", ctrl->val); } return 0; @@ -2498,6 +4261,42 @@ .def = 0, }; +static const struct v4l2_ctrl_config ctrl_gt_input_buffer_number = { + .name = "input buffer number", + .id = AML_V4L2_GET_INPUT_BUFFER_NUM, + .ops = &aml_vcodec_dec_ctrl_ops, + .type = V4L2_CTRL_TYPE_INTEGER, + .flags = V4L2_CTRL_FLAG_VOLATILE, + .min = 0, + .max = 128, + .step = 1, + .def = 0, +}; + +static const struct v4l2_ctrl_config ctrl_st_duration = { + .name = "duration", + .id = AML_V4L2_SET_DURATION, + .ops = &aml_vcodec_dec_ctrl_ops, + .type = V4L2_CTRL_TYPE_INTEGER, + .flags = V4L2_CTRL_FLAG_WRITE_ONLY, + .min = 0, + .max = 96000, + .step = 1, + .def = 0, +}; + +static const struct v4l2_ctrl_config ctrl_gt_filmgrain_info = { + .name = "filmgrain info", + .id = AML_V4L2_GET_FILMGRAIN_INFO, + .ops = &aml_vcodec_dec_ctrl_ops, + .type = V4L2_CTRL_TYPE_INTEGER, + .flags = V4L2_CTRL_FLAG_VOLATILE, + .min = 0, + .max = 1, + .step = 1, + .def = 0, +}; + int aml_vcodec_dec_ctrls_setup(struct aml_vcodec_ctx *ctx) { int ret; @@ -2508,24 +4307,42 @@ &aml_vcodec_dec_ctrl_ops, V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 0, 32, 1, 2); - ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; - if (ctx->ctrl_hdl.error) { + if ((ctrl == NULL) || (ctx->ctrl_hdl.error)) { ret = ctx->ctrl_hdl.error; goto err; } + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; ctrl = v4l2_ctrl_new_std(&ctx->ctrl_hdl, &aml_vcodec_dec_ctrl_ops, V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 0, 32, 1, 8); + if ((ctrl == NULL) || (ctx->ctrl_hdl.error)) { + ret = ctx->ctrl_hdl.error; + goto err; + } ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; - if (ctx->ctrl_hdl.error) { + + ctrl = v4l2_ctrl_new_custom(&ctx->ctrl_hdl, &ctrl_st_mode, NULL); + if ((ctrl == NULL) || (ctx->ctrl_hdl.error)) { ret = ctx->ctrl_hdl.error; goto err; } - ctrl = v4l2_ctrl_new_custom(&ctx->ctrl_hdl, &ctrl_st_mode, NULL); - if (ctx->ctrl_hdl.error) { + ctrl = v4l2_ctrl_new_custom(&ctx->ctrl_hdl, &ctrl_gt_input_buffer_number, NULL); + if ((ctrl == NULL) || (ctx->ctrl_hdl.error)) { + ret = ctx->ctrl_hdl.error; + goto err; + } + + ctrl = v4l2_ctrl_new_custom(&ctx->ctrl_hdl, &ctrl_st_duration, NULL); + if ((ctrl == NULL) || (ctx->ctrl_hdl.error)) { + ret = ctx->ctrl_hdl.error; + goto err; + } + + ctrl = v4l2_ctrl_new_custom(&ctx->ctrl_hdl, &ctrl_gt_filmgrain_info, NULL); + if ((ctrl == NULL) || (ctx->ctrl_hdl.error)) { ret = ctx->ctrl_hdl.error; goto err; } @@ -2545,16 +4362,25 @@ struct v4l2_streamparm *a) { struct aml_vcodec_ctx *ctx = fh_to_ctx(fh); + struct vb2_queue *dst_vq; - if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - if (vdec_if_get_param(ctx, GET_PARAM_CONFIG_INFO, - &ctx->config.parm.dec)) { + dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (!dst_vq) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "no vb2 queue for type=%d\n", V4L2_BUF_TYPE_VIDEO_CAPTURE); + return -EINVAL; + } + + if (!V4L2_TYPE_IS_MULTIPLANAR(a->type) && dst_vq->is_multiplanar) + return -EINVAL; + + if ((a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) || (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) { + if (vdec_if_get_param(ctx, GET_PARAM_CONFIG_INFO, &ctx->config.parm.dec)) v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "GET_PARAM_CONFIG_INFO err\n"); - return -1; - } - memcpy(a->parm.raw_data, ctx->config.parm.data, - sizeof(a->parm.raw_data)); + else + memcpy(a->parm.raw_data, ctx->config.parm.data, + sizeof(a->parm.raw_data)); } v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s\n", __func__); @@ -2562,22 +4388,65 @@ return 0; } +static int check_dec_cfginfo(struct aml_vdec_cfg_infos *cfg) +{ + if (cfg->double_write_mode != 0 && + cfg->double_write_mode != 1 && + cfg->double_write_mode != 2 && + cfg->double_write_mode != 3 && + cfg->double_write_mode != 4 && + cfg->double_write_mode != 16 && + cfg->double_write_mode != 0x21 && + cfg->double_write_mode != 0x100 && + cfg->double_write_mode != 0x200) { + pr_err("invalid double write mode %d\n", cfg->double_write_mode); + return -1; + } + if (cfg->ref_buf_margin > 20) { + pr_err("invalid margin %d\n", cfg->ref_buf_margin); + return -1; + } + + if (mandatory_dw_mmu) { + cfg->double_write_mode = 0x21; + } + + pr_info("double write mode %d margin %d\n", + cfg->double_write_mode, cfg->ref_buf_margin); + return 0; +} + static int vidioc_vdec_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct aml_vcodec_ctx *ctx = fh_to_ctx(fh); + struct vb2_queue *dst_vq; v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s\n", __func__); - if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (!dst_vq) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "no vb2 queue for type=%d\n", V4L2_BUF_TYPE_VIDEO_CAPTURE); + return -EINVAL; + } + + if (!V4L2_TYPE_IS_MULTIPLANAR(a->type) && dst_vq->is_multiplanar) + return -EINVAL; + + if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT || + a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { struct aml_dec_params *in = (struct aml_dec_params *) a->parm.raw_data; struct aml_dec_params *dec = &ctx->config.parm.dec; ctx->config.type = V4L2_CONFIG_PARM_DECODE; - if (in->parms_status & V4L2_CONFIG_PARM_DECODE_CFGINFO) + if (in->parms_status & V4L2_CONFIG_PARM_DECODE_CFGINFO) { + if (check_dec_cfginfo(&in->cfg)) + return -EINVAL; dec->cfg = in->cfg; + } if (in->parms_status & V4L2_CONFIG_PARM_DECODE_PSINFO) dec->ps = in->ps; if (in->parms_status & V4L2_CONFIG_PARM_DECODE_HDRINFO) @@ -2586,31 +4455,37 @@ dec->cnt = in->cnt; dec->parms_status |= in->parms_status; + + /* aml v4l driver parms config. */ + ctx->vpp_cfg.enable_nr = + (dec->cfg.metadata_config_flag & (1 << 15)); + if (force_enable_nr) + ctx->vpp_cfg.enable_nr = true; + + ctx->vpp_cfg.enable_local_buf = + (dec->cfg.metadata_config_flag & (1 << 14)); + if (force_enable_di_local_buffer) + ctx->vpp_cfg.enable_local_buf = true; + + ctx->internal_dw_scale = dec->cfg.metadata_config_flag & (1 << 13); + ctx->second_field_pts_mode = dec->cfg.metadata_config_flag & (1 << 12); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s parms:%x metadata_config_flag: 0x%x\n", + __func__, in->parms_status, dec->cfg.metadata_config_flag); + + memset(a->parm.output.reserved, 0, sizeof(a->parm.output.reserved)); + } else { + memset(a->parm.capture.reserved, 0, sizeof(a->parm.capture.reserved)); } return 0; } -static void m2mops_vdec_lock(void *m2m_priv) -{ - struct aml_vcodec_ctx *ctx = m2m_priv; - - mutex_lock(&ctx->dev->dev_mutex); -} - -static void m2mops_vdec_unlock(void *m2m_priv) -{ - struct aml_vcodec_ctx *ctx = m2m_priv; - - mutex_unlock(&ctx->dev->dev_mutex); -} const struct v4l2_m2m_ops aml_vdec_m2m_ops = { .device_run = m2mops_vdec_device_run, .job_ready = m2mops_vdec_job_ready, .job_abort = m2mops_vdec_job_abort, - .lock = m2mops_vdec_lock, - .unlock = m2mops_vdec_unlock, }; static const struct vb2_ops aml_vdec_vb2_ops = { @@ -2620,6 +4495,7 @@ .wait_prepare = vb2_ops_wait_prepare, .wait_finish = vb2_ops_wait_finish, .buf_init = vb2ops_vdec_buf_init, + .buf_cleanup = vb2ops_vdec_buf_cleanup, .buf_finish = vb2ops_vdec_buf_finish, .start_streaming = vb2ops_vdec_start_streaming, .stop_streaming = vb2ops_vdec_stop_streaming, @@ -2636,10 +4512,10 @@ .vidioc_qbuf = vidioc_vdec_qbuf, .vidioc_dqbuf = vidioc_vdec_dqbuf, - .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap_mplane, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap_mplane, - .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out_mplane, - .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out_mplane, + .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap_out, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap_out, + .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_cap_out, + .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_cap_out, .vidioc_s_fmt_vid_cap_mplane = vidioc_vdec_s_fmt, .vidioc_s_fmt_vid_cap = vidioc_vdec_s_fmt, @@ -2652,17 +4528,18 @@ .vidioc_create_bufs = vidioc_vdec_create_bufs, - .vidioc_enum_fmt_vid_cap_mplane = vidioc_vdec_enum_fmt_vid_cap_mplane, + //fixme + //.vidioc_enum_fmt_vid_cap_mplane = vidioc_vdec_enum_fmt_vid_cap_mplane, + //.vidioc_enum_fmt_vid_out_mplane = vidioc_vdec_enum_fmt_vid_out_mplane, .vidioc_enum_fmt_vid_cap = vidioc_vdec_enum_fmt_vid_cap_mplane, - .vidioc_enum_fmt_vid_out_mplane = vidioc_vdec_enum_fmt_vid_out_mplane, .vidioc_enum_fmt_vid_out = vidioc_vdec_enum_fmt_vid_out_mplane, .vidioc_enum_framesizes = vidioc_enum_framesizes, .vidioc_querycap = vidioc_vdec_querycap, .vidioc_subscribe_event = vidioc_vdec_subscribe_evt, .vidioc_unsubscribe_event = vidioc_vdec_event_unsubscribe, - .vidioc_g_selection = vidioc_vdec_g_selection, - .vidioc_s_selection = vidioc_vdec_s_selection, + .vidioc_g_selection = vidioc_vdec_g_selection, + .vidioc_s_selection = vidioc_vdec_s_selection, .vidioc_decoder_cmd = vidioc_decoder_cmd, .vidioc_try_decoder_cmd = vidioc_try_decoder_cmd, @@ -2680,11 +4557,11 @@ v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, "%s\n", __func__); src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - src_vq->io_modes = VB2_DMABUF | VB2_MMAP; + src_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR; src_vq->drv_priv = ctx; src_vq->buf_struct_size = sizeof(struct aml_video_dec_buf); src_vq->ops = &aml_vdec_vb2_ops; - src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->mem_ops = &vb2_dma_sg_memops; src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; src_vq->lock = &ctx->dev->dev_mutex; ret = vb2_queue_init(src_vq); @@ -2703,6 +4580,7 @@ dst_vq->mem_ops = &vb2_dma_contig_memops; dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; dst_vq->lock = &ctx->dev->dev_mutex; + dst_vq->min_buffers_needed = 1; ret = vb2_queue_init(dst_vq); if (ret) { vb2_queue_release(src_vq);
diff --git a/drivers/amvdec_ports/aml_vcodec_dec.h b/drivers/amvdec_ports/aml_vcodec_dec.h index 3653ff0..a23522c 100644 --- a/drivers/amvdec_ports/aml_vcodec_dec.h +++ b/drivers/amvdec_ports/aml_vcodec_dec.h
@@ -20,11 +20,14 @@ #ifndef _AML_VCODEC_DEC_H_ #define _AML_VCODEC_DEC_H_ +#include <linux/kref.h> +#include <linux/scatterlist.h> #include <media/videobuf2-core.h> #include <media/videobuf2-v4l2.h> #include <linux/amlogic/media/codec_mm/codec_mm.h> #include <linux/amlogic/media/video_sink/v4lvideo_ext.h> #include "aml_vcodec_util.h" +#include "aml_task_chain.h" #define VCODEC_CAPABILITY_4K_DISABLED 0x10 #define VCODEC_DEC_4K_CODED_WIDTH 4096U @@ -38,15 +41,25 @@ #define VDEC_GATHER_MEMORY_TYPE 0 #define VDEC_SCATTER_MEMORY_TYPE 1 -/** - * struct vdec_fb - decoder frame buffer +#define META_DATA_SIZE (256) +#define MD_BUF_SIZE (1024) +#define COMP_BUF_SIZE (8196) +#define SEI_BUF_SIZE (2 * 12 * 1024) +#define SEI_TYPE (1) +#define DV_TYPE (2) + + +/* + * struct vdec_v4l2_buffer - decoder frame buffer * @mem_type : gather or scatter memory. * @num_planes : used number of the plane * @mem[4] : array mem for used planes, * mem[0]: Y, mem[1]: C/U, mem[2]: V * @vf_fd : the file handle of video frame - * @vf_handle : video frame handle * @status : frame buffer status (vdec_fb_status) + * @buf_idx : the index from vb2 index. + * @vframe : store the vframe that get from caller. + * @task : the context of task chain manager. */ struct vdec_v4l2_buffer { @@ -56,11 +69,12 @@ struct aml_vcodec_mem mem[4]; u32 vf_fd; } m; - ulong vf_handle; u32 status; u32 buf_idx; -}; + void *vframe; + struct task_chain_s *task; +}; /** * struct aml_video_dec_buf - Private data related to each VB2 buffer. @@ -68,10 +82,6 @@ * @list: link list * @used: Capture buffer contain decoded frame data and keep in * codec data structure - * @ready_to_display: Capture buffer not display yet - * @queued_in_vb2: Capture buffer is queue in vb2 - * @queued_in_v4l2: Capture buffer is in v4l2 driver, but not in vb2 - * queue yet * @lastframe: Intput buffer is last buffer - EOS * @error: An unrecoverable error occurs on this buffer. * @frame_buffer: Decode status, and buffer information of Capture buffer @@ -87,12 +97,21 @@ struct codec_mm_s *mem[2]; char mem_onwer[32]; bool used; - bool ready_to_display; bool que_in_m2m; - bool queued_in_vb2; - bool queued_in_v4l2; bool lastframe; bool error; + + /* internal compressed buffer */ + unsigned int internal_index; + + ulong vpp_buf_handle; + ulong ge2d_buf_handle; + + /*4 bytes data for data len*/ + char meta_data[META_DATA_SIZE + 4]; + + struct sg_table *out_sgt; + struct sg_table *cap_sgt; }; extern const struct v4l2_ioctl_ops aml_vdec_ioctl_ops; @@ -111,16 +130,19 @@ void aml_vcodec_dec_set_default_params(struct aml_vcodec_ctx *ctx); void aml_vcodec_dec_release(struct aml_vcodec_ctx *ctx); int aml_vcodec_dec_ctrls_setup(struct aml_vcodec_ctx *ctx); -void vdec_device_vf_run(struct aml_vcodec_ctx *ctx); -void try_to_capture(struct aml_vcodec_ctx *ctx); -void aml_thread_notify(struct aml_vcodec_ctx *ctx, - enum aml_thread_type type); -int aml_thread_start(struct aml_vcodec_ctx *ctx, aml_thread_func func, - enum aml_thread_type type, const char *thread_name); -void aml_thread_stop(struct aml_vcodec_ctx *ctx); void wait_vcodec_ending(struct aml_vcodec_ctx *ctx); void vdec_frame_buffer_release(void *data); void aml_vdec_dispatch_event(struct aml_vcodec_ctx *ctx, u32 changes); void* v4l_get_vf_handle(int fd); +void aml_v4l_ctx_release(struct kref *kref); +void dmabuff_recycle_worker(struct work_struct *work); +void aml_buffer_status(struct aml_vcodec_ctx *ctx); +void aml_vdec_basic_information(struct aml_vcodec_ctx *ctx); + +void aml_alloc_buffer(struct aml_vcodec_ctx *ctx, int flag); +void aml_free_buffer(struct aml_vcodec_ctx *ctx, int flag); +void aml_free_one_sei_buffer(struct aml_vcodec_ctx *ctx, char **addr, int *size, int idx); +void aml_bind_sei_buffer(struct aml_vcodec_ctx *v4l, char **addr, int *size, int *idx); +void aml_bind_dv_buffer(struct aml_vcodec_ctx *v4l, char **comp_buf, char **md_buf); #endif /* _AML_VCODEC_DEC_H_ */
diff --git a/drivers/amvdec_ports/aml_vcodec_dec_drv.c b/drivers/amvdec_ports/aml_vcodec_dec_drv.c index 1ed0b97..18f0254 100644 --- a/drivers/amvdec_ports/aml_vcodec_dec_drv.c +++ b/drivers/amvdec_ports/aml_vcodec_dec_drv.c
@@ -29,11 +29,11 @@ #include <media/v4l2-mem2mem.h> #include <media/videobuf2-dma-contig.h> #include <linux/kthread.h> - +#include <linux/compat.h> #include "aml_vcodec_drv.h" #include "aml_vcodec_dec.h" #include "aml_vcodec_util.h" -#include "aml_vcodec_vfm.h" +#include "aml_vcodec_vpp.h" #include <linux/file.h> #include <linux/anon_inodes.h> @@ -50,6 +50,7 @@ bool param_sets_from_ucode = 1; bool enable_drm_mode; +extern void aml_vdec_pic_info_update(struct aml_vcodec_ctx *ctx); static int fops_vcodec_open(struct file *file) { @@ -62,12 +63,21 @@ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; + kref_init(&ctx->ctx_ref); + aml_buf = kzalloc(sizeof(*aml_buf), GFP_KERNEL); if (!aml_buf) { kfree(ctx); return -ENOMEM; } + ctx->meta_infos.meta_bufs = vzalloc(sizeof(struct meta_data) * V4L_CAP_BUFF_MAX); + if (ctx->meta_infos.meta_bufs == NULL) { + kfree(aml_buf); + kfree(ctx); + return -ENOMEM; + } + mutex_lock(&dev->dev_mutex); ctx->empty_flush_buf = aml_buf; ctx->id = dev->id_counter++; @@ -76,14 +86,26 @@ v4l2_fh_add(&ctx->fh); INIT_LIST_HEAD(&ctx->list); INIT_LIST_HEAD(&ctx->vdec_thread_list); + INIT_LIST_HEAD(&ctx->task_chain_pool); dev->filp = file; ctx->dev = dev; init_waitqueue_head(&ctx->queue); + mutex_init(&ctx->capture_buffer_lock); + mutex_init(&ctx->buff_done_lock); mutex_init(&ctx->state_lock); - mutex_init(&ctx->lock); + mutex_init(&ctx->comp_lock); spin_lock_init(&ctx->slock); + spin_lock_init(&ctx->tsplock); + spin_lock_init(&ctx->dmabuff_recycle_lock); init_completion(&ctx->comp); + init_waitqueue_head(&ctx->wq); + init_waitqueue_head(&ctx->cap_wq); + init_waitqueue_head(&ctx->post_done_wq); + INIT_WORK(&ctx->dmabuff_recycle_work, dmabuff_recycle_worker); + INIT_KFIFO(ctx->dmabuff_recycle); + INIT_KFIFO(ctx->capture_buffer); + ctx->post_to_upper_done = true; ctx->param_sets_from_ucode = param_sets_from_ucode ? 1 : 0; if (enable_drm_mode) { @@ -111,9 +133,19 @@ ctx->output_thread_ready = true; ctx->empty_flush_buf->vb.vb2_buf.vb2_queue = src_vq; ctx->empty_flush_buf->lastframe = true; + ctx->vdec_pic_info_update = aml_vdec_pic_info_update; aml_vcodec_dec_set_default_params(ctx); + ctx->is_stream_off = true; - ret = aml_thread_start(ctx, try_to_capture, AML_THREAD_CAPTURE, "cap"); + ctx->aux_infos.dv_index = 0; + ctx->aux_infos.sei_index = 0; + ctx->aux_infos.alloc_buffer = aml_alloc_buffer; + ctx->aux_infos.free_buffer = aml_free_buffer; + ctx->aux_infos.bind_sei_buffer = aml_bind_sei_buffer; + ctx->aux_infos.bind_dv_buffer = aml_bind_dv_buffer; + ctx->aux_infos.free_one_sei_buffer = aml_free_one_sei_buffer; + + ret = aml_thread_start(ctx, aml_thread_capture_worker, AML_THREAD_CAPTURE, "cap"); if (ret) { v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "Failed to creat capture thread.\n"); @@ -126,7 +158,7 @@ v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "%s decoder %lx\n", dev_name(&dev->plat_dev->dev), (ulong)ctx); - return ret; + return 0; /* Deinit when failure occurred */ err_creat_thread: @@ -136,6 +168,7 @@ err_ctrls_setup: v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); + vfree(ctx->meta_infos.meta_bufs); kfree(ctx->empty_flush_buf); kfree(ctx); mutex_unlock(&dev->dev_mutex); @@ -151,24 +184,20 @@ v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "release decoder %lx\n", (ulong) ctx); mutex_lock(&dev->dev_mutex); - /* - * Call v4l2_m2m_ctx_release before aml_vcodec_dec_release. First, it - * makes sure the worker thread is not running after vdec_if_deinit. - * Second, the decoder will be flushed and all the buffers will be - * returned in stop_streaming. - */ aml_thread_stop(ctx); wait_vcodec_ending(ctx); - v4l2_m2m_ctx_release(ctx->m2m_ctx); - aml_vcodec_dec_release(ctx); + vb2_queue_release(&ctx->m2m_ctx->cap_q_ctx.q); + vb2_queue_release(&ctx->m2m_ctx->out_q_ctx.q); + aml_vcodec_dec_release(ctx); v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->ctrl_hdl); list_del_init(&ctx->list); + kfree(ctx->empty_flush_buf); - kfree(ctx); + kref_put(&ctx->ctx_ref, aml_v4l_ctx_release); mutex_unlock(&dev->dev_mutex); return 0; } @@ -302,8 +331,10 @@ if (!is_v4l2_buf_file(file)) { fput(file); +#if 0 v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "the buf file checked fail!\n"); +#endif return NULL; } @@ -415,6 +446,43 @@ .mmap = v4l2_m2m_fop_mmap, }; +static ssize_t status_show(struct class *cls, + struct class_attribute *attr, char *buf) +{ + struct aml_vcodec_dev *dev = container_of(cls, + struct aml_vcodec_dev, v4ldec_class); + struct aml_vcodec_ctx *ctx = NULL; + char *pbuf = buf; + + mutex_lock(&dev->dev_mutex); + + if (list_empty(&dev->ctx_list)) { + pbuf += sprintf(pbuf, "No v4ldec context.\n"); + goto out; + } + + list_for_each_entry(ctx, &dev->ctx_list, list) { + /* basic information. */ + aml_vdec_basic_information(ctx); + + /* buffers status. */ + aml_buffer_status(ctx); + } +out: + mutex_unlock(&dev->dev_mutex); + + return pbuf - buf; +} + +static CLASS_ATTR_RO(status); + +static struct attribute *v4ldec_class_attrs[] = { + &class_attr_status.attr, + NULL +}; + +ATTRIBUTE_GROUPS(v4ldec_class); + static int aml_vcodec_probe(struct platform_device *pdev) { struct aml_vcodec_dev *dev; @@ -427,6 +495,7 @@ INIT_LIST_HEAD(&dev->ctx_list); dev->plat_dev = pdev; + atomic_set(&dev->vpp_count, 0); mutex_init(&dev->dec_mutex); mutex_init(&dev->dev_mutex); @@ -437,8 +506,7 @@ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); if (ret) { - v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, - "v4l2_device_register err=%d\n", ret); + dev_err(&pdev->dev, "v4l2_device_register err=%d\n", ret); goto err_res; } @@ -446,8 +514,7 @@ vfd_dec = video_device_alloc(); if (!vfd_dec) { - v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, - "Failed to allocate video device\n"); + dev_err(&pdev->dev, "Failed to allocate video device\n"); ret = -ENOMEM; goto err_dec_alloc; } @@ -459,7 +526,7 @@ vfd_dec->v4l2_dev = &dev->v4l2_dev; vfd_dec->vfl_dir = VFL_DIR_M2M; vfd_dec->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | - V4L2_CAP_STREAMING; + V4L2_CAP_STREAMING; snprintf(vfd_dec->name, sizeof(vfd_dec->name), "%s", AML_VCODEC_DEC_NAME); @@ -469,18 +536,16 @@ dev->m2m_dev_dec = v4l2_m2m_init(&aml_vdec_m2m_ops); if (IS_ERR((__force void *)dev->m2m_dev_dec)) { - v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, - "Failed to init mem2mem dec device\n"); + dev_err(&pdev->dev, "Failed to init mem2mem dec device\n"); ret = PTR_ERR((__force void *)dev->m2m_dev_dec); goto err_dec_mem_init; } dev->decode_workqueue = - alloc_ordered_workqueue(AML_VCODEC_DEC_NAME, - WQ_MEM_RECLAIM | WQ_FREEZABLE); + alloc_ordered_workqueue("output-worker", + __WQ_LEGACY | WQ_MEM_RECLAIM | WQ_HIGHPRI); if (!dev->decode_workqueue) { - v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, - "Failed to create decode workqueue\n"); + dev_err(&pdev->dev, "Failed to create decode workqueue\n"); ret = -EINVAL; goto err_event_workq; } @@ -489,16 +554,26 @@ ret = video_register_device(vfd_dec, VFL_TYPE_GRABBER, 26); if (ret) { - v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, - "Failed to register video device\n"); + dev_err(&pdev->dev, "Failed to register video device\n"); goto err_dec_reg; } - v4l_dbg(0, V4L_DEBUG_CODEC_PRINFO, - "decoder registered as /dev/video%d\n", vfd_dec->num); + /*init class*/ + dev->v4ldec_class.name = "v4ldec"; + dev->v4ldec_class.owner = THIS_MODULE; + dev->v4ldec_class.class_groups = v4ldec_class_groups; + ret = class_register(&dev->v4ldec_class); + if (ret) { + dev_err(&pdev->dev, "v4l dec class create fail.\n"); + goto err_reg_class; + } + + dev_info(&pdev->dev, "v4ldec registered as /dev/video%d\n", vfd_dec->num); return 0; +err_reg_class: + class_unregister(&dev->v4ldec_class); err_dec_reg: destroy_workqueue(dev->decode_workqueue); err_event_workq: @@ -512,13 +587,6 @@ return ret; } -static const struct of_device_id aml_vcodec_match[] = { - {.compatible = "amlogic, vcodec-dec",}, - {}, -}; - -MODULE_DEVICE_TABLE(of, aml_vcodec_match); - static int aml_vcodec_dec_remove(struct platform_device *pdev) { struct aml_vcodec_dev *dev = platform_get_drvdata(pdev); @@ -526,6 +594,8 @@ flush_workqueue(dev->decode_workqueue); destroy_workqueue(dev->decode_workqueue); + class_unregister(&dev->v4ldec_class); + if (dev->m2m_dev_dec) v4l2_m2m_release(dev->m2m_dev_dec); @@ -534,12 +604,17 @@ v4l2_device_unregister(&dev->v4l2_dev); + dev_info(&pdev->dev, "v4ldec removed.\n"); + return 0; } -/*static void aml_vcodec_dev_release(struct device *dev) -{ -}*/ +static const struct of_device_id aml_vcodec_match[] = { + {.compatible = "amlogic, vcodec-dec",}, + {}, +}; + +MODULE_DEVICE_TABLE(of, aml_vcodec_match); static struct platform_driver aml_vcodec_dec_driver = { .probe = aml_vcodec_probe, @@ -550,44 +625,36 @@ }, }; -/* -static struct platform_device aml_vcodec_dec_device = { - .name = AML_VCODEC_DEC_NAME, - .dev.release = aml_vcodec_dev_release, -};*/ - -module_platform_driver(aml_vcodec_dec_driver); - -/* static int __init amvdec_ports_init(void) { - int ret; + pr_info("v4l dec module init\n"); - ret = platform_device_register(&aml_vcodec_dec_device); - if (ret) - return ret; + if (platform_driver_register(&aml_vcodec_dec_driver)) { + pr_err("failed to register v4l dec driver\n"); + return -ENODEV; + } - ret = platform_driver_register(&aml_vcodec_dec_driver); - if (ret) - platform_device_unregister(&aml_vcodec_dec_device); - - return ret; + return 0; } static void __exit amvdec_ports_exit(void) { + pr_info("v4l dec module exit\n"); + platform_driver_unregister(&aml_vcodec_dec_driver); - platform_device_unregister(&aml_vcodec_dec_device); } module_init(amvdec_ports_init); module_exit(amvdec_ports_exit); -*/ u32 debug_mode; EXPORT_SYMBOL(debug_mode); module_param(debug_mode, uint, 0644); +u32 mandatory_dw_mmu; +EXPORT_SYMBOL(mandatory_dw_mmu); +module_param(mandatory_dw_mmu, uint, 0644); + bool aml_set_vfm_enable; EXPORT_SYMBOL(aml_set_vfm_enable); module_param(aml_set_vfm_enable, bool, 0644); @@ -616,20 +683,72 @@ EXPORT_SYMBOL(multiplanar); module_param(multiplanar, bool, 0644); -bool dump_capture_frame; +int dump_capture_frame; EXPORT_SYMBOL(dump_capture_frame); -module_param(dump_capture_frame, bool, 0644); +module_param(dump_capture_frame, int, 0644); + +int dump_vpp_input; +EXPORT_SYMBOL(dump_vpp_input); +module_param(dump_vpp_input, int, 0644); + +int dump_ge2d_input; +EXPORT_SYMBOL(dump_ge2d_input); +module_param(dump_ge2d_input, int, 0644); int dump_output_frame; EXPORT_SYMBOL(dump_output_frame); module_param(dump_output_frame, int, 0644); +u32 dump_output_start_position; +EXPORT_SYMBOL(dump_output_start_position); +module_param(dump_output_start_position, uint, 0644); + EXPORT_SYMBOL(param_sets_from_ucode); module_param(param_sets_from_ucode, bool, 0644); EXPORT_SYMBOL(enable_drm_mode); module_param(enable_drm_mode, bool, 0644); +int bypass_vpp; +EXPORT_SYMBOL(bypass_vpp); +module_param(bypass_vpp, int, 0644); + +int bypass_ge2d; +EXPORT_SYMBOL(bypass_ge2d); +module_param(bypass_ge2d, int, 0644); + +int max_di_instance = 2; +EXPORT_SYMBOL(max_di_instance); +module_param(max_di_instance, int, 0644); + +int bypass_progressive = 1; +EXPORT_SYMBOL(bypass_progressive); +module_param(bypass_progressive, int, 0644); + +bool support_mjpeg; +EXPORT_SYMBOL(support_mjpeg); +module_param(support_mjpeg, bool, 0644); + +bool support_format_I420; +EXPORT_SYMBOL(support_format_I420); +module_param(support_format_I420, bool, 0644); + +int force_enable_nr; +EXPORT_SYMBOL(force_enable_nr); +module_param(force_enable_nr, int, 0644); + +int force_enable_di_local_buffer; +EXPORT_SYMBOL(force_enable_di_local_buffer); +module_param(force_enable_di_local_buffer, int, 0644); + +int vpp_bypass_frames; +EXPORT_SYMBOL(vpp_bypass_frames); +module_param(vpp_bypass_frames, int, 0644); + +int bypass_nr_flag; +EXPORT_SYMBOL(bypass_nr_flag); +module_param(bypass_nr_flag, int, 0644); + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("AML video codec V4L2 decoder driver");
diff --git a/drivers/amvdec_ports/aml_vcodec_drv.h b/drivers/amvdec_ports/aml_vcodec_drv.h index 2e9e576..522fe67 100644 --- a/drivers/amvdec_ports/aml_vcodec_drv.h +++ b/drivers/amvdec_ports/aml_vcodec_drv.h
@@ -20,14 +20,19 @@ #ifndef _AML_VCODEC_DRV_H_ #define _AML_VCODEC_DRV_H_ +#include <linux/kref.h> #include <linux/platform_device.h> #include <linux/videodev2.h> +#include <linux/kfifo.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <media/videobuf2-core.h> +#include <media/videobuf2-v4l2.h> #include <linux/amlogic/media/vfm/vframe.h> +#include <linux/amlogic/media/video_sink/v4lvideo_ext.h> #include "aml_vcodec_util.h" +#include "aml_vcodec_dec.h" #define AML_VCODEC_DRV_NAME "aml_vcodec_drv" #define AML_VCODEC_DEC_NAME "aml-vcodec-dec" @@ -66,6 +71,8 @@ #define V4L_CAP_BUFF_INVALID (0) #define V4L_CAP_BUFF_IN_M2M (1) #define V4L_CAP_BUFF_IN_DEC (2) +#define V4L_CAP_BUFF_IN_VPP (3) +#define V4L_CAP_BUFF_IN_GE2D (4) /* v4l reset mode */ #define V4L_RESET_MODE_NORMAL (1 << 0) /* reset vdec_input and decoder. */ @@ -79,6 +86,7 @@ /* Instance is currently aborting */ #define TRANS_ABORT (1 << 2) +#define CTX_BUF_TOTAL(ctx) (ctx->dpb_size + ctx->vpp_size + ctx->ge2d_size) /** * enum aml_hw_reg_idx - AML hw register base index */ @@ -119,7 +127,6 @@ * @AML_STATE_ACTIVE - vdec is ready for work. * @AML_STATE_FLUSHING - vdec is flushing. Only used by decoder * @AML_STATE_FLUSHED - decoder has transacted the last frame. - * @AML_STATE_RESET - decoder has be reset after flush. * @AML_STATE_ABORT - vcodec should be aborted */ enum aml_instance_state { @@ -130,7 +137,6 @@ AML_STATE_ACTIVE, AML_STATE_FLUSHING, AML_STATE_FLUSHED, - AML_STATE_RESET, AML_STATE_ABORT, }; @@ -156,9 +162,10 @@ * struct aml_video_fmt - Structure used to store information about pixelformats */ struct aml_video_fmt { - u32 fourcc; + u32 fourcc; enum aml_fmt_type type; - u32 num_planes; + u32 num_planes; + const u8 *name; }; /** @@ -183,13 +190,13 @@ * struct aml_q_data - Structure used to store information about queue */ struct aml_q_data { - unsigned int visible_width; - unsigned int visible_height; - unsigned int coded_width; - unsigned int coded_height; + u32 visible_width; + u32 visible_height; + u32 coded_width; + u32 coded_height; enum v4l2_field field; - unsigned int bytesperline[AML_VCODEC_MAX_PLANES]; - unsigned int sizeimage[AML_VCODEC_MAX_PLANES]; + u32 bytesperline[AML_VCODEC_MAX_PLANES]; + u32 sizeimage[AML_VCODEC_MAX_PLANES]; struct aml_video_fmt *fmt; bool resolution_changed; }; @@ -214,42 +221,19 @@ * @force_intra: force/insert intra frame */ struct aml_enc_params { - unsigned int bitrate; - unsigned int num_b_frame; - unsigned int rc_frame; - unsigned int rc_mb; - unsigned int seq_hdr_mode; - unsigned int intra_period; - unsigned int gop_size; - unsigned int framerate_num; - unsigned int framerate_denom; - unsigned int h264_max_qp; - unsigned int h264_profile; - unsigned int h264_level; - unsigned int force_intra; -}; - -/** - * struct aml_vcodec_pm - Power management data structure - */ -struct aml_vcodec_pm { - struct clk *vdec_bus_clk_src; - struct clk *vencpll; - - struct clk *vcodecpll; - struct clk *univpll_d2; - struct clk *clk_cci400_sel; - struct clk *vdecpll; - struct clk *vdec_sel; - struct clk *vencpll_d2; - struct clk *venc_sel; - struct clk *univpll1_d2; - struct clk *venc_lt_sel; - struct device *larbvdec; - struct device *larbvenc; - struct device *larbvenclt; - struct device *dev; - struct aml_vcodec_dev *amldev; + u32 bitrate; + u32 num_b_frame; + u32 rc_frame; + u32 rc_mb; + u32 seq_hdr_mode; + u32 intra_period; + u32 gop_size; + u32 framerate_num; + u32 framerate_denom; + u32 h264_max_qp; + u32 h264_profile; + u32 h264_level; + u32 force_intra; }; /** @@ -266,20 +250,38 @@ * plane * E.g. suppose picture size is 176x144, * buffer size will be aligned to 176x160. + * @profile_idc: source profile level * @field: frame/field information. + * @dpb_frames: used for DPB size of calculation. + * @dpb_margin: extra buffers for decoder. + * @vpp_margin: extra buffers for vpp. */ struct vdec_pic_info { - unsigned int visible_width; - unsigned int visible_height; - unsigned int coded_width; - unsigned int coded_height; - unsigned int y_bs_sz; - unsigned int c_bs_sz; - unsigned int y_len_sz; - unsigned int c_len_sz; + u32 visible_width; + u32 visible_height; + u32 coded_width; + u32 coded_height; + u32 y_bs_sz; + u32 c_bs_sz; + u32 y_len_sz; + u32 c_len_sz; int profile_idc; - int ref_frame_count; enum v4l2_field field; + u32 dpb_frames; + u32 dpb_margin; + u32 vpp_margin; +}; + +/** + * struct vdec_comp_buf_info - compressed buffer info + * @max_size: max size needed for MMU Box in MB + * @header_size: contineous size for the compressed header + * @frame_buffer_size: SG page number to store the frame + */ +struct vdec_comp_buf_info { + u32 max_size; + u32 header_size; + u32 frame_buffer_size; }; struct aml_vdec_cfg_infos { @@ -290,6 +292,20 @@ u32 canvas_mem_mode; u32 canvas_mem_endian; u32 low_latency_mode; + u32 uvm_hook_type; + /* + * bit 16 : force progressive output flag. + * bit 15 : enable nr. + * bit 14 : enable di local buff. + * bit 13 : report downscale yuv buffer size flag. + * bit 12 : for second field pts mode. + * bit 11 : disable error policy + * bit 1 : Non-standard dv flag. + * bit 0 : dv two layer flag. + */ + u32 metadata_config_flag; // for metadata config flag + u32 duration; + u32 data[4]; }; struct aml_vdec_hdr_infos { @@ -323,8 +339,10 @@ u32 mb_height; u32 dpb_size; u32 ref_frames; - u32 reorder_frames; + u32 dpb_frames; + u32 dpb_margin; u32 field; + u32 data[3]; }; struct aml_vdec_cnt_infos { @@ -361,7 +379,7 @@ */ u32 seq[V4L_CAP_BUFF_MAX]; u32 in, out; - u32 dec, vpp; + u32 dec, vpp, ge2d; }; enum aml_thread_type { @@ -372,35 +390,203 @@ typedef void (*aml_thread_func)(struct aml_vcodec_ctx *ctx); struct aml_vdec_thread { - struct list_head node; - spinlock_t lock; - struct semaphore sem; - struct task_struct *task; - enum aml_thread_type type; - void *priv; - int stop; + struct list_head node; + spinlock_t lock; + struct semaphore sem; + struct task_struct *task; + enum aml_thread_type type; + void *priv; + int stop; - aml_thread_func func; + aml_thread_func func; }; -/** +/* struct internal_comp_buf - compressed buffer + * @index: index of this buf within (B)MMU BOX + * @ref: [0-7]:reference number of this buf + * [8-15]: use for reuse. + * @mmu_box: mmu_box of context + * @bmmu_box: bmmu_box of context + * @box_ref: box_ref of context + * @header_addr: header for compressed buffer + * @frame_buffer_size: SG buffer page number from + * @priv_data use for video composer + * struct vdec_comp_buf_info + */ +struct internal_comp_buf { + u32 index; + u32 ref; + void *mmu_box; + void *bmmu_box; + struct kref *box_ref; + + ulong header_addr; + u32 header_size; + u32 frame_buffer_size; + struct file_private_data priv_data; + ulong header_dw_addr; + void *mmu_box_dw; + void *bmmu_box_dw; +}; + +/* + * struct aml_uvm_buff_ref - uvm buff is used reseve ctx ref count. + * @index : index of video buffer. + * @addr : physic address of video buffer. + * @ref : reference of v4ldec context. + * @dma : dma buf of associated with vb. + */ +struct aml_uvm_buff_ref { + int index; + ulong addr; + struct kref *ref; + struct dma_buf *dbuf; +}; + +/* + * enum aml_fb_requester - indicate which module request fb buffers. + */ +enum aml_fb_requester { + AML_FB_REQ_DEC, + AML_FB_REQ_VPP, + AML_FB_REQ_GE2D, + AML_FB_REQ_MAX +}; + +/* + * @query: try to achieved fb token. + * @alloc: used for allocte fb buffer. + */ +struct aml_fb_ops { + bool (*query)(struct aml_fb_ops *, ulong *); + int (*alloc)(struct aml_fb_ops *, ulong, struct vdec_v4l2_buffer **, u32); +}; + +/* + * struct aml_fb_map_table - record some buffer map infos + * @addr : yuv linear buffer address. + * @header_addr : used for compress buffer. + * @vframe : which is from decoder or vpp vf pool. + * @task : context of task chain. + * @icomp : compress buffer index. + */ +struct aml_fb_map_table { + ulong addr; + ulong header_addr; + struct vframe_s *vframe; + struct task_chain_s *task; + u32 icomp; +}; + +/* + * struct aux_data - record sei data and dv data + * @sei_size: sei data size. + * @sei_buf: sei data addr. + * @sei_state: sei buffer state. (0 free, 1 not used, 2 used) + * @comp_buf: stores comp data parsed from sei data. + * @md_buf: stores md data parsed from sei data. + */ +struct aux_data { + int sei_size; + char* sei_buf; + int sei_state; + char* comp_buf; + char* md_buf; +}; + +/* + * struct aux_info - record aux data infos + * @sei_index: sei data index. + * @dv_index: dv data index. + * @sei_need_free: sei buffer need to free. + * @bufs: stores aux data. + * @alloc_buffer: alloc aux buffer functions. + * @free_buffer: free aux buffer functions. + * @free_one_sei_buffer:free sei buffer with index functions. + * @bind_sei_buffer: bind sei buffer functions. + * @bind_dv_buffer: bind dv buffer functions. + */ +struct aux_info { + int sei_index; + int dv_index; + bool sei_need_free; + struct aux_data bufs[V4L_CAP_BUFF_MAX]; + void (*alloc_buffer)(struct aml_vcodec_ctx *ctx, int flag); + void (*free_buffer)(struct aml_vcodec_ctx *ctx, int flag); + void (*free_one_sei_buffer)(struct aml_vcodec_ctx *ctx, char **addr, int *size, int idx); + void (*bind_sei_buffer)(struct aml_vcodec_ctx *ctx, char **addr, int *size, int *idx); + void (*bind_dv_buffer)(struct aml_vcodec_ctx *ctx, char **comp_buf, char **md_buf); +}; + +/* + * struct meta_data - record meta data. + * @buf[META_DATA_SIZE]: meta data information. + */ +struct meta_data { + char buf[META_DATA_SIZE]; +}; + +/* + * struct meta_info - record some meta data infos + * @index: meta data index. + * @meta_bufs: record meta data. + */ +struct meta_info { + int index; + struct meta_data *meta_bufs; +}; + +/* + * struct aml_vpp_cfg_infos - config vpp init param + * @mode : vpp work mode + * @fmt : picture format used to switch nv21 or nv12. + * @buf_size: config buffer size for vpp + * @is_drm : is drm mode + * @is_prog : is a progressive source. + * @is_bypass_p : to set progressive bypass in vpp + * @enable_nr : enable nosie reduce. + * @enable_local_buf: DI used buff alloc by itself. + * @res_chg : indicate resolution changed. + * @is_vpp_reset: vpp reset just used to res chg. + */ +struct aml_vpp_cfg_infos { + u32 mode; + u32 fmt; + u32 buf_size; + bool is_drm; + bool is_prog; + bool is_bypass_p; + bool enable_nr; + bool enable_local_buf; + bool res_chg; + bool is_vpp_reset; +}; + +struct aml_ge2d_cfg_infos { + u32 mode; + u32 buf_size; + bool is_drm; +}; + +/* * struct aml_vcodec_ctx - Context (instance) private data. - * * @id: index of the context that this structure describes. + * @ctx_ref: for deferred free of this context. * @type: type of the instance - decoder or encoder. * @dev: pointer to the aml_vcodec_dev of the device. * @m2m_ctx: pointer to the v4l2_m2m_ctx of the context. * @ada_ctx: pointer to the aml_vdec_adapt of the context. + * @vpp: pointer to video post processor * @dec_if: hooked decoder driver interface. * @drv_handle: driver handle for specific decode instance * @fh: struct v4l2_fh. * @ctrl_hdl: handler for v4l2 framework. * @slock: protect v4l2 codec context. + * @tsplock: protect the vdec thread context. * @empty_flush_buf: a fake size-0 capture buffer that indicates flush. * @list: link to ctx_list of aml_vcodec_dev. * @q_data: store information of input and output queue of the context. * @queue: waitqueue that can be used to wait for this context to finish. - * @lock: protect the vdec thread. * @state_lock: protect the codec status. * @state: state of the context. * @decode_work: decoder work be used to output buffer. @@ -408,6 +594,7 @@ * @cap_pool: capture buffers are remark in the pool. * @vdec_thread_list: vdec thread be used to capture. * @dpb_size: store dpb count after header parsing + * @vpp_size: store vpp buffer count after header parsing * @param_change: indicate encode parameter type * @param_sets_from_ucode: if true indicate ps from ucode. * @v4l_codec_dpb_ready: queue buffer number greater than dpb. @@ -430,24 +617,46 @@ * @reset_flag: reset mode includes lightly and normal mode. * @decoded_frame_cnt: the capture buffer deque number to be count. * @buf_used_count: means that decode allocate how many buffs from v4l. + * @wq: wait recycle dma buffer finish. + * @cap_wq: the wq used for wait capture buffer. + * @dmabuff_recycle_lock: protect the lock dmabuff free. + * @dmabuff_recycle_work: used for recycle dmabuff. + * @dmabuff_recycle: kfifo used for store vb buff. + * @capture_buffer: kfifo used for store capture vb buff. + * @mmu_box: mmu_box of context. + * @bmmu_box: bmmu_box of context. + * @box_ref: box_ref of context. + * @comp_info: compress buffer information. + * @comp_bufs: compress buffer describe. + * @comp_lock: used for lock ibuf free cb. + * @fb_ops: frame buffer ops interface. + * @dv_infos: dv data information. + * @vpp_cfg: vpp init parms of configuration. + * @vdec_pic_info_update: update pic info cb. + * @vpp_is_need: the instance is need vpp. + * @task_chain_pool: used to store task chain inst. + * @index_disp: the number of frames output. */ struct aml_vcodec_ctx { int id; + struct kref ctx_ref; enum aml_instance_type type; struct aml_vcodec_dev *dev; struct v4l2_m2m_ctx *m2m_ctx; struct aml_vdec_adapt *ada_ctx; + struct aml_v4l2_vpp *vpp; const struct vdec_common_if *dec_if; ulong drv_handle; struct v4l2_fh fh; struct v4l2_ctrl_handler ctrl_hdl; spinlock_t slock; + spinlock_t tsplock; struct aml_video_dec_buf *empty_flush_buf; struct list_head list; struct aml_q_data q_data[2]; wait_queue_head_t queue; - struct mutex lock, state_lock; + struct mutex state_lock; enum aml_instance_state state; struct work_struct decode_work; bool output_thread_ready; @@ -455,6 +664,8 @@ struct list_head vdec_thread_list; int dpb_size; + int vpp_size; + int ge2d_size; bool param_sets_from_ucode; bool v4l_codec_dpb_ready; bool v4l_resolution_change; @@ -467,6 +678,7 @@ enum v4l2_quantization quantization; enum v4l2_xfer_func xfer_func; u32 cap_pix_fmt; + u32 output_pix_fmt; bool has_receive_eos; bool is_drm_mode; @@ -477,81 +689,84 @@ int reset_flag; int decoded_frame_cnt; int buf_used_count; + wait_queue_head_t wq, cap_wq, post_done_wq; + struct mutex capture_buffer_lock; + spinlock_t dmabuff_recycle_lock; + struct mutex buff_done_lock; + struct work_struct dmabuff_recycle_work; + DECLARE_KFIFO(dmabuff_recycle, struct vb2_v4l2_buffer *, 32); + DECLARE_KFIFO(capture_buffer, struct vb2_v4l2_buffer *, 32); + + /* compressed buffer support */ + void *bmmu_box; + void *mmu_box; + struct kref box_ref; + struct vdec_comp_buf_info comp_info; + struct internal_comp_buf *comp_bufs; + struct uvm_hook_mod_info *uvm_proxy; + struct mutex comp_lock; + + struct aml_fb_ops fb_ops; + ulong token_table[32]; + + struct aml_fb_map_table fb_map[32]; + struct aml_vpp_cfg_infos vpp_cfg; + void (*vdec_pic_info_update)(struct aml_vcodec_ctx *ctx); + bool vpp_is_need; + struct list_head task_chain_pool; + struct meta_info meta_infos; + struct vdec_sync *sync; + u32 internal_dw_scale; + + /* ge2d field. */ + struct aml_v4l2_ge2d *ge2d; + struct aml_ge2d_cfg_infos ge2d_cfg; + bool ge2d_is_need; + + bool second_field_pts_mode; + struct aux_info aux_infos; + u32 index_disp; + bool post_to_upper_done; + bool film_grain_present; + void *bmmu_box_dw; + void *mmu_box_dw; }; /** - * struct aml_vcodec_dev - driver data - * @v4l2_dev: V4L2 device to register video devices for. - * @vfd_dec: Video device for decoder - * @vfd_enc: Video device for encoder. - * - * @m2m_dev_dec: m2m device for decoder - * @m2m_dev_enc: m2m device for encoder. - * @plat_dev: platform device - * @vpu_plat_dev: aml vpu platform device - * @alloc_ctx: VB2 allocator context - * (for allocations without kernel mapping). - * @ctx_list: list of struct aml_vcodec_ctx - * @irqlock: protect data access by irq handler and work thread - * @curr_ctx: The context that is waiting for codec hardware - * - * @reg_base: Mapped address of AML Vcodec registers. - * - * @id_counter: used to identify current opened instance - * - * @encode_workqueue: encode work queue - * - * @int_cond: used to identify interrupt condition happen - * @int_type: used to identify what kind of interrupt condition happen - * @dev_mutex: video_device lock - * @queue: waitqueue for waiting for completion of device commands - * - * @dec_irq: decoder irq resource - * @enc_irq: h264 encoder irq resource - * @enc_lt_irq: vp8 encoder irq resource - * - * @dec_mutex: decoder hardware lock - * @enc_mutex: encoder hardware lock. - * - * @pm: power management control - * @dec_capability: used to identify decode capability, ex: 4k - * @enc_capability: used to identify encode capability + * struct aml_vcodec_dev - driver data. + * @v4l2_dev : V4L2 device to register video devices for. + * @vfd_dec : Video device for decoder. + * @plat_dev : platform device. + * @m2m_dev_dec : m2m device for decoder. + * @curr_ctx : The context that is waiting for codec hardware. + * @id_counter : used to identify current opened instance. + * @dec_capability : used to identify decode capability, ex: 4k + * @decode_workqueue : the worker used to output buffer schedule. + * @ctx_list : list of struct aml_vcodec_ctx. + * @irqlock : protect data access by irq handler and work thread. + * @dev_mutex : video_device lock. + * @dec_mutex : decoder hardware lock. + * @queue : waitqueue for waiting for completion of device commands. + * @vpp_count : count the number of open vpp. + * @v4ldec_class : creat class sysfs uesd to show some information. */ struct aml_vcodec_dev { - struct v4l2_device v4l2_dev; - struct video_device *vfd_dec; - struct video_device *vfd_enc; - struct file *filp; - - struct v4l2_m2m_dev *m2m_dev_dec; - struct v4l2_m2m_dev *m2m_dev_enc; - struct platform_device *plat_dev; - struct platform_device *vpu_plat_dev;//?? - struct vb2_alloc_ctx *alloc_ctx;//?? - struct list_head ctx_list; - spinlock_t irqlock; - struct aml_vcodec_ctx *curr_ctx; - void __iomem *reg_base[NUM_MAX_VCODEC_REG_BASE]; - - unsigned long id_counter; - - struct workqueue_struct *decode_workqueue; - struct workqueue_struct *encode_workqueue; - int int_cond; - int int_type; - struct mutex dev_mutex; - wait_queue_head_t queue; - - int dec_irq; - int enc_irq; - int enc_lt_irq; - - struct mutex dec_mutex; - struct mutex enc_mutex; - - struct aml_vcodec_pm pm; - unsigned int dec_capability; - unsigned int enc_capability; + struct v4l2_device v4l2_dev; + struct video_device *vfd_dec; + struct platform_device *plat_dev; + struct v4l2_m2m_dev *m2m_dev_dec; + struct aml_vcodec_ctx *curr_ctx; + ulong id_counter; + u32 dec_capability; + struct workqueue_struct *decode_workqueue; + struct list_head ctx_list; + struct file *filp; + spinlock_t irqlock; + struct mutex dev_mutex; + struct mutex dec_mutex; + wait_queue_head_t queue; + atomic_t vpp_count; + struct class v4ldec_class; }; static inline struct aml_vcodec_ctx *fh_to_ctx(struct v4l2_fh *fh) @@ -564,4 +779,10 @@ return container_of(ctrl->handler, struct aml_vcodec_ctx, ctrl_hdl); } +void aml_thread_capture_worker(struct aml_vcodec_ctx *ctx); +void aml_thread_post_task(struct aml_vcodec_ctx *ctx, enum aml_thread_type type); +int aml_thread_start(struct aml_vcodec_ctx *ctx, aml_thread_func func, + enum aml_thread_type type, const char *thread_name); +void aml_thread_stop(struct aml_vcodec_ctx *ctx); + #endif /* _AML_VCODEC_DRV_H_ */
diff --git a/drivers/amvdec_ports/aml_vcodec_ge2d.c b/drivers/amvdec_ports/aml_vcodec_ge2d.c new file mode 100644 index 0000000..2d331ed --- /dev/null +++ b/drivers/amvdec_ports/aml_vcodec_ge2d.c
@@ -0,0 +1,968 @@ +/* +* Copyright (C) 2020 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. +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, write to the Free Software Foundation, Inc., +* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +* Description: +*/ + +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/videodev2.h> +#include <linux/sched/clock.h> +#include <uapi/linux/sched/types.h> +#include <linux/amlogic/meson_uvm_core.h> +#include <linux/amlogic/media/ge2d/ge2d.h> +#include <linux/amlogic/media/canvas/canvas_mgr.h> + +#include "../common/chips/decoder_cpu_ver_info.h" +#include "aml_vcodec_ge2d.h" +#include "aml_vcodec_adapt.h" +#include "vdec_drv_if.h" + +#define KERNEL_ATRACE_TAG KERNEL_ATRACE_TAG_V4L2 +#include <trace/events/meson_atrace.h> + +#define GE2D_BUF_GET_IDX(ge2d_buf) (ge2d_buf->aml_buf->vb.vb2_buf.index) +#define INPUT_PORT 0 +#define OUTPUT_PORT 1 + +extern int dump_ge2d_input; +extern int ge2d_bypass_frames; + +enum GE2D_FLAG { + GE2D_FLAG_P = 0x1, + GE2D_FLAG_I = 0x2, + GE2D_FLAG_EOS = 0x4, + GE2D_FLAG_BUF_BY_PASS = 0x8, + GE2D_FLAG_MAX = 0x7FFFFFFF, +}; + +enum videocom_source_type { + DECODER_8BIT_NORMAL = 0, + DECODER_8BIT_BOTTOM, + DECODER_8BIT_TOP, + DECODER_10BIT_NORMAL, + DECODER_10BIT_BOTTOM, + DECODER_10BIT_TOP +}; + +#ifndef CONFIG_AMLOGIC_MEDIA_GE2D +inline void stretchblt_noalpha(struct ge2d_context_s *wq, + int src_x, int src_y, int src_w, int src_h, + int dst_x, int dst_y, int dst_w, int dst_h) { return; } +inline int ge2d_context_config_ex(struct ge2d_context_s *context, + struct config_para_ex_s *ge2d_config) { return -1; } +inline struct ge2d_context_s *create_ge2d_work_queue(void) { return NULL; } +inline int destroy_ge2d_work_queue(struct ge2d_context_s *ge2d_work_queue) { return -1; } +#endif + +static int get_source_type(struct vframe_s *vf) +{ + enum videocom_source_type ret; + int interlace_mode; + + interlace_mode = vf->type & VIDTYPE_TYPEMASK; + + if ((vf->bitdepth & BITDEPTH_Y10) && + (!(vf->type & VIDTYPE_COMPRESS)) && + (get_cpu_type() >= MESON_CPU_MAJOR_ID_TXL)) { + if (interlace_mode == VIDTYPE_INTERLACE_TOP) + ret = DECODER_10BIT_TOP; + else if (interlace_mode == VIDTYPE_INTERLACE_BOTTOM) + ret = DECODER_10BIT_BOTTOM; + else + ret = DECODER_10BIT_NORMAL; + } else { + if (interlace_mode == VIDTYPE_INTERLACE_TOP) + ret = DECODER_8BIT_TOP; + else if (interlace_mode == VIDTYPE_INTERLACE_BOTTOM) + ret = DECODER_8BIT_BOTTOM; + else + ret = DECODER_8BIT_NORMAL; + } + + return ret; +} + +static int get_input_format(struct vframe_s *vf) +{ + int format = GE2D_FORMAT_M24_YUV420; + enum videocom_source_type soure_type; + + soure_type = get_source_type(vf); + + switch (soure_type) { + case DECODER_8BIT_NORMAL: + if (vf->type & VIDTYPE_VIU_422) + format = GE2D_FORMAT_S16_YUV422; + else if (vf->type & VIDTYPE_VIU_NV21) + format = GE2D_FORMAT_M24_NV21; + else if (vf->type & VIDTYPE_VIU_NV12) + format = GE2D_FORMAT_M24_NV12; + else if (vf->type & VIDTYPE_VIU_444) + format = GE2D_FORMAT_S24_YUV444; + else + format = GE2D_FORMAT_M24_YUV420; + break; + case DECODER_8BIT_BOTTOM: + if (vf->type & VIDTYPE_VIU_422) + format = GE2D_FORMAT_S16_YUV422 + | (GE2D_FORMAT_S16_YUV422B & (3 << 3)); + else if (vf->type & VIDTYPE_VIU_NV21) + format = GE2D_FORMAT_M24_NV21 + | (GE2D_FORMAT_M24_NV21B & (3 << 3)); + else if (vf->type & VIDTYPE_VIU_NV12) + format = GE2D_FORMAT_M24_NV12 + | (GE2D_FORMAT_M24_NV12B & (3 << 3)); + else if (vf->type & VIDTYPE_VIU_444) + format = GE2D_FORMAT_S24_YUV444 + | (GE2D_FORMAT_S24_YUV444B & (3 << 3)); + else + format = GE2D_FORMAT_M24_YUV420 + | (GE2D_FMT_M24_YUV420B & (3 << 3)); + break; + case DECODER_8BIT_TOP: + if (vf->type & VIDTYPE_VIU_422) + format = GE2D_FORMAT_S16_YUV422 + | (GE2D_FORMAT_S16_YUV422T & (3 << 3)); + else if (vf->type & VIDTYPE_VIU_NV21) + format = GE2D_FORMAT_M24_NV21 + | (GE2D_FORMAT_M24_NV21T & (3 << 3)); + else if (vf->type & VIDTYPE_VIU_NV12) + format = GE2D_FORMAT_M24_NV12 + | (GE2D_FORMAT_M24_NV12T & (3 << 3)); + else if (vf->type & VIDTYPE_VIU_444) + format = GE2D_FORMAT_S24_YUV444 + | (GE2D_FORMAT_S24_YUV444T & (3 << 3)); + else + format = GE2D_FORMAT_M24_YUV420 + | (GE2D_FMT_M24_YUV420T & (3 << 3)); + break; + case DECODER_10BIT_NORMAL: + if (vf->type & VIDTYPE_VIU_422) { + if (vf->bitdepth & FULL_PACK_422_MODE) + format = GE2D_FORMAT_S16_10BIT_YUV422; + else + format = GE2D_FORMAT_S16_12BIT_YUV422; + } + break; + case DECODER_10BIT_BOTTOM: + if (vf->type & VIDTYPE_VIU_422) { + if (vf->bitdepth & FULL_PACK_422_MODE) + format = GE2D_FORMAT_S16_10BIT_YUV422 + | (GE2D_FORMAT_S16_10BIT_YUV422B + & (3 << 3)); + else + format = GE2D_FORMAT_S16_12BIT_YUV422 + | (GE2D_FORMAT_S16_12BIT_YUV422B + & (3 << 3)); + } + break; + case DECODER_10BIT_TOP: + if (vf->type & VIDTYPE_VIU_422) { + if (vf->bitdepth & FULL_PACK_422_MODE) + format = GE2D_FORMAT_S16_10BIT_YUV422 + | (GE2D_FORMAT_S16_10BIT_YUV422T + & (3 << 3)); + else + format = GE2D_FORMAT_S16_12BIT_YUV422 + | (GE2D_FORMAT_S16_12BIT_YUV422T + & (3 << 3)); + } + break; + default: + format = GE2D_FORMAT_M24_YUV420; + } + return format; +} + +static int v4l_ge2d_empty_input_done(struct aml_v4l2_ge2d_buf *buf) +{ + struct aml_v4l2_ge2d *ge2d = buf->caller_data; + struct vdec_v4l2_buffer *fb = NULL; + bool eos = false; + + if (!ge2d || !ge2d->ctx) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "fatal %s %d ge2d:%px\n", + __func__, __LINE__, ge2d); + return -1; + } + + fb = &buf->aml_buf->frame_buffer; + eos = (buf->flag & GE2D_FLAG_EOS); + + v4l_dbg(ge2d->ctx, V4L_DEBUG_GE2D_BUFMGR, + "ge2d_input done: vf:%px, idx: %d, flag(vf:%x ge2d:%x) %s, ts:%lld, " + "in:%d, out:%d, vf:%d, in done:%d, out done:%d\n", + buf->vf, + buf->vf->index, + buf->vf->flag, + buf->flag, + eos ? "eos" : "", + buf->vf->timestamp, + kfifo_len(&ge2d->input), + kfifo_len(&ge2d->output), + kfifo_len(&ge2d->frame), + kfifo_len(&ge2d->in_done_q), + kfifo_len(&ge2d->out_done_q)); + + fb->task->recycle(fb->task, TASK_TYPE_GE2D); + + kfifo_put(&ge2d->input, buf); + + ATRACE_COUNTER("VC_IN_GE2D-1.recycle", fb->buf_idx); + + return 0; +} + +static int v4l_ge2d_fill_output_done(struct aml_v4l2_ge2d_buf *buf) +{ + struct aml_v4l2_ge2d *ge2d = buf->caller_data; + struct vdec_v4l2_buffer *fb = NULL; + bool bypass = false; + bool eos = false; + + if (!ge2d || !ge2d->ctx) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "fatal %s %d ge2d:%px\n", + __func__, __LINE__, ge2d); + return -1; + } + + fb = &buf->aml_buf->frame_buffer; + eos = (buf->flag & GE2D_FLAG_EOS); + bypass = (buf->flag & GE2D_FLAG_BUF_BY_PASS); + + /* recovery fb handle. */ + buf->vf->v4l_mem_handle = (ulong)fb; + + kfifo_put(&ge2d->out_done_q, buf); + + v4l_dbg(ge2d->ctx, V4L_DEBUG_GE2D_BUFMGR, + "ge2d_output done: vf:%px, idx:%d, flag(vf:%x ge2d:%x) %s, ts:%lld, " + "in:%d, out:%d, vf:%d, in done:%d, out done:%d, wxh:%ux%u\n", + buf->vf, + buf->vf->index, + buf->vf->flag, + buf->flag, + eos ? "eos" : "", + buf->vf->timestamp, + kfifo_len(&ge2d->input), + kfifo_len(&ge2d->output), + kfifo_len(&ge2d->frame), + kfifo_len(&ge2d->in_done_q), + kfifo_len(&ge2d->out_done_q), + buf->vf->width, buf->vf->height); + + ATRACE_COUNTER("VC_OUT_GE2D-2.submit", fb->buf_idx); + + fb->task->submit(fb->task, TASK_TYPE_GE2D); + + ge2d->out_num[OUTPUT_PORT]++; + + return 0; +} + +static void ge2d_vf_get(void *caller, struct vframe_s **vf_out) +{ + struct aml_v4l2_ge2d *ge2d = (struct aml_v4l2_ge2d *)caller; + struct aml_v4l2_ge2d_buf *buf = NULL; + struct vdec_v4l2_buffer *fb = NULL; + struct vframe_s *vf = NULL; + bool bypass = false; + bool eos = false; + + if (!ge2d || !ge2d->ctx) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "fatal %s %d ge2d:%px\n", + __func__, __LINE__, ge2d); + return; + } + + if (kfifo_get(&ge2d->out_done_q, &buf)) { + fb = &buf->aml_buf->frame_buffer; + eos = (buf->flag & GE2D_FLAG_EOS); + bypass = (buf->flag & GE2D_FLAG_BUF_BY_PASS); + vf = buf->vf; + + if (eos) { + v4l_dbg(ge2d->ctx, V4L_DEBUG_GE2D_DETAIL, + "%s %d got eos\n", + __func__, __LINE__); + vf->type |= VIDTYPE_V4L_EOS; + vf->flag = VFRAME_FLAG_EMPTY_FRAME_V4L; + } + + *vf_out = vf; + + ATRACE_COUNTER("VC_OUT_GE2D-3.vf_get", fb->buf_idx); + + v4l_dbg(ge2d->ctx, V4L_DEBUG_GE2D_BUFMGR, + "%s: vf:%px, index:%d, flag(vf:%x ge2d:%x), ts:%lld, type:%x, wxh:%ux%u\n", + __func__, vf, + vf->index, + vf->flag, + buf->flag, + vf->timestamp, vf->type, vf->width, vf->height); + } +} + +static void ge2d_vf_put(void *caller, struct vframe_s *vf) +{ + struct aml_v4l2_ge2d *ge2d = (struct aml_v4l2_ge2d *)caller; + struct vdec_v4l2_buffer *fb = NULL; + struct aml_video_dec_buf *aml_buf = NULL; + struct aml_v4l2_ge2d_buf *buf = NULL; + bool bypass = false; + bool eos = false; + + fb = (struct vdec_v4l2_buffer *) vf->v4l_mem_handle; + aml_buf = container_of(fb, struct aml_video_dec_buf, frame_buffer); + buf = (struct aml_v4l2_ge2d_buf *) aml_buf->ge2d_buf_handle; + eos = (buf->flag & GE2D_FLAG_EOS); + bypass = (buf->flag & GE2D_FLAG_BUF_BY_PASS); + + v4l_dbg(ge2d->ctx, V4L_DEBUG_GE2D_BUFMGR, + "%s: vf:%px, index:%d, flag(vf:%x ge2d:%x), ts:%lld\n", + __func__, vf, + vf->index, + vf->flag, + buf->flag, + vf->timestamp); + + ATRACE_COUNTER("VC_IN_GE2D-0.vf_put", fb->buf_idx); + + mutex_lock(&ge2d->output_lock); + kfifo_put(&ge2d->frame, vf); + kfifo_put(&ge2d->output, buf); + mutex_unlock(&ge2d->output_lock); + up(&ge2d->sem_out); +} + +static int aml_v4l2_ge2d_thread(void* param) +{ + struct aml_v4l2_ge2d* ge2d = param; + struct aml_vcodec_ctx *ctx = ge2d->ctx; + struct config_para_ex_s ge2d_config; + u32 src_fmt = 0, dst_fmt = 0; + struct canvas_s cd; + ulong start_time; + + v4l_dbg(ctx, V4L_DEBUG_GE2D_DETAIL, "enter ge2d thread\n"); + while (ge2d->running) { + struct aml_v4l2_ge2d_buf *in_buf; + struct aml_v4l2_ge2d_buf *out_buf = NULL; + struct vframe_s *vf_out = NULL; + struct vdec_v4l2_buffer *fb; + + if (down_interruptible(&ge2d->sem_in)) + goto exit; +retry: + if (!ge2d->running) + break; + + if (kfifo_is_empty(&ge2d->output)) { + if (down_interruptible(&ge2d->sem_out)) + goto exit; + goto retry; + } + + mutex_lock(&ge2d->output_lock); + if (!kfifo_get(&ge2d->output, &out_buf)) { + mutex_unlock(&ge2d->output_lock); + v4l_dbg(ctx, 0, "ge2d can not get output\n"); + goto exit; + } + mutex_unlock(&ge2d->output_lock); + + /* bind v4l2 buffers */ + if (!out_buf->aml_buf) { + struct vdec_v4l2_buffer *out; + + if (!ctx->fb_ops.query(&ctx->fb_ops, &ge2d->fb_token)) { + usleep_range(500, 550); + mutex_lock(&ge2d->output_lock); + kfifo_put(&ge2d->output, out_buf); + mutex_unlock(&ge2d->output_lock); + goto retry; + } + + if (ctx->fb_ops.alloc(&ctx->fb_ops, ge2d->fb_token, &out, AML_FB_REQ_GE2D)) { + usleep_range(5000, 5500); + mutex_lock(&ge2d->output_lock); + kfifo_put(&ge2d->output, out_buf); + mutex_unlock(&ge2d->output_lock); + goto retry; + } + + out_buf->aml_buf = container_of(out, + struct aml_video_dec_buf, frame_buffer); + out_buf->aml_buf->ge2d_buf_handle = (ulong) out_buf; + v4l_dbg(ctx, V4L_DEBUG_GE2D_BUFMGR, + "ge2d bind buf:%d to ge2d_buf:%px\n", + GE2D_BUF_GET_IDX(out_buf), out_buf); + + out->m.mem[0].bytes_used = out->m.mem[0].size; + out->m.mem[1].bytes_used = out->m.mem[1].size; + } + + /* safe to pop in_buf */ + if (!kfifo_get(&ge2d->in_done_q, &in_buf)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "ge2d can not get input\n"); + goto exit; + } + + mutex_lock(&ge2d->output_lock); + if (!kfifo_get(&ge2d->frame, &vf_out)) { + mutex_unlock(&ge2d->output_lock); + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "ge2d can not get frame\n"); + goto exit; + } + mutex_unlock(&ge2d->output_lock); + + fb = &out_buf->aml_buf->frame_buffer; + fb->status = FB_ST_GE2D; + + /* fill output vframe information. */ + memcpy(vf_out, in_buf->vf, sizeof(*vf_out)); + memcpy(vf_out->canvas0_config, + in_buf->vf->canvas0_config, + 2 * sizeof(struct canvas_config_s)); + + vf_out->canvas0_config[0].phy_addr = fb->m.mem[0].addr; + if (fb->num_planes == 1) { + vf_out->canvas0_config[1].phy_addr = + fb->m.mem[0].addr + fb->m.mem[0].offset; + vf_out->canvas0_config[2].phy_addr = + fb->m.mem[0].addr + fb->m.mem[0].offset + + (fb->m.mem[0].offset >> 2); + } else { + vf_out->canvas0_config[1].phy_addr = + fb->m.mem[1].addr; + vf_out->canvas0_config[2].phy_addr = + fb->m.mem[2].addr; + } + + /* fill outbuf parms. */ + out_buf->vf = vf_out; + out_buf->flag = 0; + out_buf->caller_data = ge2d; + + /* fill inbuf parms. */ + in_buf->caller_data = ge2d; + + memset(&ge2d_config, 0, sizeof(ge2d_config)); + + src_fmt = get_input_format(in_buf->vf); + if (in_buf->vf->canvas0_config[0].endian == 7) + src_fmt |= GE2D_BIG_ENDIAN; + else + src_fmt |= GE2D_LITTLE_ENDIAN; + + /* negotiate format of destination */ + dst_fmt = get_input_format(in_buf->vf); + if (ge2d->work_mode & GE2D_MODE_CONVERT_NV12) + dst_fmt |= GE2D_FORMAT_M24_NV12; + else if (ge2d->work_mode & GE2D_MODE_CONVERT_NV21) + dst_fmt |= GE2D_FORMAT_M24_NV21; + + if (ge2d->work_mode & GE2D_MODE_CONVERT_LE) + dst_fmt |= GE2D_LITTLE_ENDIAN; + else + dst_fmt |= GE2D_BIG_ENDIAN; + + if ((dst_fmt & GE2D_COLOR_MAP_MASK) == GE2D_COLOR_MAP_NV12) { + vf_out->type |= VIDTYPE_VIU_NV12; + vf_out->type &= ~VIDTYPE_VIU_NV21; + } else if ((dst_fmt & GE2D_COLOR_MAP_MASK) == GE2D_COLOR_MAP_NV21) { + vf_out->type |= VIDTYPE_VIU_NV21; + vf_out->type &= ~VIDTYPE_VIU_NV12; + } + if ((dst_fmt & GE2D_ENDIAN_MASK) == GE2D_LITTLE_ENDIAN) { + vf_out->canvas0_config[0].endian = 0; + vf_out->canvas0_config[1].endian = 0; + vf_out->canvas0_config[2].endian = 0; + } else if ((dst_fmt & GE2D_ENDIAN_MASK) == GE2D_BIG_ENDIAN){ + vf_out->canvas0_config[0].endian = 7; + vf_out->canvas0_config[1].endian = 7; + vf_out->canvas0_config[2].endian = 7; + } + + start_time = local_clock(); + /* src canvas configure. */ + if ((in_buf->vf->canvas0Addr == 0) || + (in_buf->vf->canvas0Addr == (u32)-1)) { + canvas_config_config(ge2d->src_canvas_id[0], &in_buf->vf->canvas0_config[0]); + canvas_config_config(ge2d->src_canvas_id[1], &in_buf->vf->canvas0_config[1]); + canvas_config_config(ge2d->src_canvas_id[2], &in_buf->vf->canvas0_config[2]); + ge2d_config.src_para.canvas_index = + ge2d->src_canvas_id[0] | + ge2d->src_canvas_id[1] << 8 | + ge2d->src_canvas_id[2] << 16; + + ge2d_config.src_planes[0].addr = + in_buf->vf->canvas0_config[0].phy_addr; + ge2d_config.src_planes[0].w = + in_buf->vf->canvas0_config[0].width; + ge2d_config.src_planes[0].h = + in_buf->vf->canvas0_config[0].height; + ge2d_config.src_planes[1].addr = + in_buf->vf->canvas0_config[1].phy_addr; + ge2d_config.src_planes[1].w = + in_buf->vf->canvas0_config[1].width; + ge2d_config.src_planes[1].h = + in_buf->vf->canvas0_config[1].height; + ge2d_config.src_planes[2].addr = + in_buf->vf->canvas0_config[2].phy_addr; + ge2d_config.src_planes[2].w = + in_buf->vf->canvas0_config[2].width; + ge2d_config.src_planes[2].h = + in_buf->vf->canvas0_config[2].height; + } else { + ge2d_config.src_para.canvas_index = in_buf->vf->canvas0Addr; + } + ge2d_config.src_para.mem_type = CANVAS_TYPE_INVALID; + ge2d_config.src_para.format = src_fmt; + ge2d_config.src_para.fill_color_en = 0; + ge2d_config.src_para.fill_mode = 0; + ge2d_config.src_para.x_rev = 0; + ge2d_config.src_para.y_rev = 0; + ge2d_config.src_para.color = 0xffffffff; + ge2d_config.src_para.top = 0; + ge2d_config.src_para.left = 0; + ge2d_config.src_para.width = in_buf->vf->width; + if (in_buf->vf->type & VIDTYPE_INTERLACE) + ge2d_config.src_para.height = in_buf->vf->height >> 1; + else + ge2d_config.src_para.height = in_buf->vf->height; + + /* dst canvas configure. */ + canvas_config_config(ge2d->dst_canvas_id[0], &vf_out->canvas0_config[0]); + if ((ge2d_config.src_para.format & 0xfffff) == GE2D_FORMAT_M24_YUV420) { + vf_out->canvas0_config[1].width <<= 1; + } + canvas_config_config(ge2d->dst_canvas_id[1], &vf_out->canvas0_config[1]); + canvas_config_config(ge2d->dst_canvas_id[2], &vf_out->canvas0_config[2]); + ge2d_config.dst_para.canvas_index = + ge2d->dst_canvas_id[0] | + ge2d->dst_canvas_id[1] << 8; + canvas_read(ge2d->dst_canvas_id[0], &cd); + ge2d_config.dst_planes[0].addr = cd.addr; + ge2d_config.dst_planes[0].w = cd.width; + ge2d_config.dst_planes[0].h = cd.height; + canvas_read(ge2d->dst_canvas_id[1], &cd); + ge2d_config.dst_planes[1].addr = cd.addr; + ge2d_config.dst_planes[1].w = cd.width; + ge2d_config.dst_planes[1].h = cd.height; + + ge2d_config.dst_para.format = dst_fmt; + ge2d_config.dst_para.width = in_buf->vf->width; + ge2d_config.dst_para.height = in_buf->vf->height; + ge2d_config.dst_para.mem_type = CANVAS_TYPE_INVALID; + ge2d_config.dst_para.fill_color_en = 0; + ge2d_config.dst_para.fill_mode = 0; + ge2d_config.dst_para.x_rev = 0; + ge2d_config.dst_para.y_rev = 0; + ge2d_config.dst_para.color = 0; + ge2d_config.dst_para.top = 0; + ge2d_config.dst_para.left = 0; + + /* other ge2d parameters configure. */ + ge2d_config.src_key.key_enable = 0; + ge2d_config.src_key.key_mask = 0; + ge2d_config.src_key.key_mode = 0; + ge2d_config.alu_const_color = 0; + ge2d_config.bitmask_en = 0; + ge2d_config.src1_gb_alpha = 0; + ge2d_config.dst_xy_swap = 0; + ge2d_config.src2_para.mem_type = CANVAS_TYPE_INVALID; + + ATRACE_COUNTER("VC_OUT_GE2D-1.handle_start", + in_buf->aml_buf->frame_buffer.buf_idx); + + v4l_dbg(ctx, V4L_DEBUG_GE2D_BUFMGR, + "ge2d_handle start: dec vf:%px/%d, ge2d vf:%px/%d, iphy:%lx/%lx %dx%d ophy:%lx/%lx %dx%d, vf:%ux%u, fmt(src:%x, dst:%x), " + "in:%d, out:%d, vf:%d, in done:%d, out done:%d\n", + in_buf->vf, in_buf->vf->index, + out_buf->vf, GE2D_BUF_GET_IDX(out_buf), + in_buf->vf->canvas0_config[0].phy_addr, + in_buf->vf->canvas0_config[1].phy_addr, + in_buf->vf->canvas0_config[0].width, + in_buf->vf->canvas0_config[0].height, + vf_out->canvas0_config[0].phy_addr, + vf_out->canvas0_config[1].phy_addr, + vf_out->canvas0_config[0].width, + vf_out->canvas0_config[0].height, + vf_out->width, vf_out->height, + src_fmt, dst_fmt, + kfifo_len(&ge2d->input), + kfifo_len(&ge2d->output), + kfifo_len(&ge2d->frame), + kfifo_len(&ge2d->in_done_q), + kfifo_len(&ge2d->out_done_q)); + + if (ge2d_context_config_ex(ge2d->ge2d_context, &ge2d_config) < 0) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "ge2d_context_config_ex error.\n"); + goto exit; + } + + if (!(in_buf->flag & GE2D_FLAG_EOS)) { + if (in_buf->vf->type & VIDTYPE_INTERLACE) { + stretchblt_noalpha(ge2d->ge2d_context, + 0, 0, in_buf->vf->width, in_buf->vf->height / 2, + 0, 0, in_buf->vf->width, in_buf->vf->height); + } else { + stretchblt_noalpha(ge2d->ge2d_context, + 0, 0, in_buf->vf->width, in_buf->vf->height, + 0, 0, in_buf->vf->width, in_buf->vf->height); + } + } + + //pr_info("consume time %d us\n", div64_u64(local_clock() - start_time, 1000)); + + v4l_ge2d_fill_output_done(out_buf); + v4l_ge2d_empty_input_done(in_buf); + + ge2d->in_num[INPUT_PORT]++; + ge2d->out_num[INPUT_PORT]++; + } +exit: + while (!kthread_should_stop()) { + usleep_range(1000, 2000); + } + + v4l_dbg(ctx, V4L_DEBUG_GE2D_DETAIL, "exit ge2d thread\n"); + + return 0; +} + +int aml_v4l2_ge2d_get_buf_num(u32 mode) +{ + return 4; +} + +int aml_v4l2_ge2d_init( + struct aml_vcodec_ctx *ctx, + struct aml_ge2d_cfg_infos *cfg, + struct aml_v4l2_ge2d** ge2d_handle) +{ + struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; + struct aml_v4l2_ge2d *ge2d; + u32 work_mode = cfg->mode; + u32 buf_size; + int i, ret; + + if (!cfg || !ge2d_handle) + return -EINVAL; + + ge2d = kzalloc(sizeof(*ge2d), GFP_KERNEL); + if (!ge2d) + return -ENOMEM; + + ge2d->work_mode = work_mode; + + /* default convert little endian. */ + if (!ge2d->work_mode) { + ge2d->work_mode = GE2D_MODE_CONVERT_LE; + } + + ge2d->ge2d_context = create_ge2d_work_queue(); + if (!ge2d->ge2d_context) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "ge2d_create_instance fail\n"); + ret = -EINVAL; + goto error; + } + + INIT_KFIFO(ge2d->input); + INIT_KFIFO(ge2d->output); + INIT_KFIFO(ge2d->frame); + INIT_KFIFO(ge2d->out_done_q); + INIT_KFIFO(ge2d->in_done_q); + + ge2d->ctx = ctx; + buf_size = cfg->buf_size; + ge2d->buf_size = buf_size; + + /* setup output fifo */ + ret = kfifo_alloc(&ge2d->output, buf_size, GFP_KERNEL); + if (ret) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "alloc output fifo fail.\n"); + ret = -ENOMEM; + goto error2; + } + + ge2d->ovbpool = vzalloc(buf_size * sizeof(*ge2d->ovbpool)); + if (!ge2d->ovbpool) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "alloc output vb pool fail.\n"); + ret = -ENOMEM; + goto error3; + } + + /* setup vframe fifo */ + ret = kfifo_alloc(&ge2d->frame, buf_size, GFP_KERNEL); + if (ret) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "alloc ge2d vframe fifo fail.\n"); + ret = -ENOMEM; + goto error4; + } + + ge2d->vfpool = vzalloc(buf_size * sizeof(*ge2d->vfpool)); + if (!ge2d->vfpool) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "alloc vf pool fail.\n"); + ret = -ENOMEM; + goto error5; + } + + ret = kfifo_alloc(&ge2d->input, GE2D_FRAME_SIZE, GFP_KERNEL); + if (ret) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "alloc input fifo fail.\n"); + ret = -ENOMEM; + goto error6; + } + + ge2d->ivbpool = vzalloc(GE2D_FRAME_SIZE * sizeof(*ge2d->ivbpool)); + if (!ge2d->ivbpool) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "alloc input vb pool fail.\n"); + ret = -ENOMEM; + goto error7; + } + + for (i = 0 ; i < GE2D_FRAME_SIZE ; i++) { + kfifo_put(&ge2d->input, &ge2d->ivbpool[i]); + } + + for (i = 0 ; i < buf_size ; i++) { + kfifo_put(&ge2d->output, &ge2d->ovbpool[i]); + kfifo_put(&ge2d->frame, &ge2d->vfpool[i]); + } + + ge2d->src_canvas_id[0] = canvas_pool_map_alloc_canvas("v4ldec-ge2d"); + ge2d->src_canvas_id[1] = canvas_pool_map_alloc_canvas("v4ldec-ge2d"); + ge2d->src_canvas_id[2] = canvas_pool_map_alloc_canvas("v4ldec-ge2d"); + ge2d->dst_canvas_id[0] = canvas_pool_map_alloc_canvas("v4ldec-ge2d"); + ge2d->dst_canvas_id[1] = canvas_pool_map_alloc_canvas("v4ldec-ge2d"); + ge2d->dst_canvas_id[2] = canvas_pool_map_alloc_canvas("v4ldec-ge2d"); + if ((ge2d->src_canvas_id[0] <= 0) || + (ge2d->src_canvas_id[1] <= 0) || + (ge2d->src_canvas_id[2] <= 0) || + (ge2d->dst_canvas_id[0] <= 0) || + (ge2d->dst_canvas_id[1] <= 0) || + (ge2d->dst_canvas_id[2] <= 0)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "canvas pool alloc fail. src(%d, %d, %d) dst(%d, %d, %d).\n", + ge2d->src_canvas_id[0], + ge2d->src_canvas_id[1], + ge2d->src_canvas_id[2], + ge2d->dst_canvas_id[0], + ge2d->dst_canvas_id[1], + ge2d->dst_canvas_id[2]); + goto error8; + } + + mutex_init(&ge2d->output_lock); + sema_init(&ge2d->sem_in, 0); + sema_init(&ge2d->sem_out, 0); + + ge2d->running = true; + ge2d->task = kthread_run(aml_v4l2_ge2d_thread, ge2d, + "%s", "aml-v4l2-ge2d"); + if (IS_ERR(ge2d->task)) { + ret = PTR_ERR(ge2d->task); + goto error9; + } + sched_setscheduler_nocheck(ge2d->task, SCHED_FIFO, ¶m); + + *ge2d_handle = ge2d; + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, + "GE2D_CFG bsize:%d, wkm:%x, bm:%x, drm:%d\n", + ge2d->buf_size, + ge2d->work_mode, + ge2d->buffer_mode, + cfg->is_drm); + + return 0; + +error9: + if (ge2d->src_canvas_id[0] > 0) + canvas_pool_map_free_canvas(ge2d->src_canvas_id[0]); + if (ge2d->src_canvas_id[1] > 0) + canvas_pool_map_free_canvas(ge2d->src_canvas_id[1]); + if (ge2d->src_canvas_id[2] > 0) + canvas_pool_map_free_canvas(ge2d->src_canvas_id[2]); + if (ge2d->dst_canvas_id[0] > 0) + canvas_pool_map_free_canvas(ge2d->dst_canvas_id[0]); + if (ge2d->dst_canvas_id[1] > 0) + canvas_pool_map_free_canvas(ge2d->dst_canvas_id[1]); + if (ge2d->dst_canvas_id[2] > 0) + canvas_pool_map_free_canvas(ge2d->dst_canvas_id[2]); +error8: + vfree(ge2d->ivbpool); +error7: + kfifo_free(&ge2d->input); +error6: + vfree(ge2d->vfpool); +error5: + kfifo_free(&ge2d->frame); +error4: + vfree(ge2d->ovbpool); +error3: + kfifo_free(&ge2d->output); +error2: + destroy_ge2d_work_queue(ge2d->ge2d_context); +error: + kfree(ge2d); + + return ret; +} +EXPORT_SYMBOL(aml_v4l2_ge2d_init); + +int aml_v4l2_ge2d_destroy(struct aml_v4l2_ge2d* ge2d) +{ + v4l_dbg(ge2d->ctx, V4L_DEBUG_GE2D_DETAIL, + "ge2d destroy begin\n"); + + ge2d->running = false; + up(&ge2d->sem_in); + up(&ge2d->sem_out); + kthread_stop(ge2d->task); + + destroy_ge2d_work_queue(ge2d->ge2d_context); + /* no more ge2d callback below this line */ + + kfifo_free(&ge2d->frame); + vfree(ge2d->vfpool); + kfifo_free(&ge2d->output); + vfree(ge2d->ovbpool); + kfifo_free(&ge2d->input); + vfree(ge2d->ivbpool); + mutex_destroy(&ge2d->output_lock); + + canvas_pool_map_free_canvas(ge2d->src_canvas_id[0]); + canvas_pool_map_free_canvas(ge2d->src_canvas_id[1]); + canvas_pool_map_free_canvas(ge2d->src_canvas_id[2]); + canvas_pool_map_free_canvas(ge2d->dst_canvas_id[0]); + canvas_pool_map_free_canvas(ge2d->dst_canvas_id[1]); + canvas_pool_map_free_canvas(ge2d->dst_canvas_id[2]); + + v4l_dbg(ge2d->ctx, V4L_DEBUG_GE2D_DETAIL, + "ge2d destroy done\n"); + + kfree(ge2d); + + return 0; +} +EXPORT_SYMBOL(aml_v4l2_ge2d_destroy); + +static int aml_v4l2_ge2d_push_vframe(struct aml_v4l2_ge2d* ge2d, struct vframe_s *vf) +{ + struct aml_v4l2_ge2d_buf* in_buf; + struct vdec_v4l2_buffer *fb = NULL; + + if (!ge2d) + return -EINVAL; + + if (!kfifo_get(&ge2d->input, &in_buf)) { + v4l_dbg(ge2d->ctx, V4L_DEBUG_CODEC_ERROR, + "cat not get free input buffer.\n"); + return -1; + } + + if (vf->type & VIDTYPE_V4L_EOS) + in_buf->flag |= GE2D_FLAG_EOS; + + v4l_dbg(ge2d->ctx, V4L_DEBUG_GE2D_BUFMGR, + "ge2d_push_vframe: vf:%px, idx:%d, type:%x, ts:%lld\n", + vf, vf->index, vf->type, vf->timestamp); + + fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; + in_buf->aml_buf = container_of(fb, struct aml_video_dec_buf, frame_buffer); + in_buf->vf = vf; + + do { + unsigned int dw_mode = VDEC_DW_NO_AFBC; + struct file *fp; + + if (!dump_ge2d_input || ge2d->ctx->is_drm_mode) + break; + + if (vdec_if_get_param(ge2d->ctx, GET_PARAM_DW_MODE, &dw_mode)) + break; + + if (dw_mode == VDEC_DW_AFBC_ONLY) + break; + + fp = filp_open("/data/dec_dump_before.raw", + O_CREAT | O_RDWR | O_LARGEFILE | O_APPEND, 0600); + if (!IS_ERR(fp)) { + struct vb2_buffer *vb = &in_buf->aml_buf->vb.vb2_buf; + + kernel_write(fp,vb2_plane_vaddr(vb, 0),vb->planes[0].length, 0); + if (in_buf->aml_buf->frame_buffer.num_planes == 2) + kernel_write(fp,vb2_plane_vaddr(vb, 1), + vb->planes[1].length, 0); + dump_ge2d_input--; + filp_close(fp, NULL); + } + } while(0); + + ATRACE_COUNTER("VC_OUT_GE2D-0.receive", fb->buf_idx); + + kfifo_put(&ge2d->in_done_q, in_buf); + up(&ge2d->sem_in); + + return 0; +} + +static void fill_ge2d_buf_cb(void *v4l_ctx, void *fb_ctx) +{ + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)v4l_ctx; + struct vdec_v4l2_buffer *fb = + (struct vdec_v4l2_buffer *)fb_ctx; + int ret = -1; + + ret = aml_v4l2_ge2d_push_vframe(ctx->ge2d, fb->vframe); + if (ret < 0) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "ge2d push vframe err, ret: %d\n", ret); + } +} + +static struct task_ops_s ge2d_ops = { + .type = TASK_TYPE_GE2D, + .get_vframe = ge2d_vf_get, + .put_vframe = ge2d_vf_put, + .fill_buffer = fill_ge2d_buf_cb, +}; + +struct task_ops_s *get_ge2d_ops(void) +{ + return &ge2d_ops; +} +EXPORT_SYMBOL(get_ge2d_ops); +
diff --git a/drivers/amvdec_ports/aml_vcodec_ge2d.h b/drivers/amvdec_ports/aml_vcodec_ge2d.h new file mode 100644 index 0000000..a12931d --- /dev/null +++ b/drivers/amvdec_ports/aml_vcodec_ge2d.h
@@ -0,0 +1,89 @@ +/* +* Copyright (C) 2020 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. +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, write to the Free Software Foundation, Inc., +* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +* Description: +*/ +#ifndef _AML_VCODEC_GE2D_H_ +#define _AML_VCODEC_GE2D_H_ + +#include <linux/kfifo.h> +#include "aml_vcodec_drv.h" +#include "aml_vcodec_dec.h" + +/* define ge2d work mode. */ +#define GE2D_MODE_CONVERT_NV12 (1 << 0) +#define GE2D_MODE_CONVERT_NV21 (1 << 1) +#define GE2D_MODE_CONVERT_LE (1 << 2) +#define GE2D_MODE_CONVERT_BE (1 << 3) +#define GE2D_MODE_SEPARATE_FIELD (1 << 4) +#define GE2D_MODE_422_TO_420 (1 << 5) + +#define GE2D_FRAME_SIZE 64 + +struct aml_v4l2_ge2d_buf { + u32 flag; + struct vframe_s *vf; + void *caller_data; + struct aml_video_dec_buf *aml_buf; +}; + +struct aml_v4l2_ge2d { + struct ge2d_context_s *ge2d_context; /* handle of GE2D */ + u32 buf_size; /* buffer size for ge2d */ + u32 work_mode; /* enum ge2d_work_mode */ + u32 buffer_mode; + struct aml_vcodec_ctx *ctx; + + DECLARE_KFIFO_PTR(input, typeof(struct aml_v4l2_ge2d_buf*)); + DECLARE_KFIFO_PTR(output, typeof(struct aml_v4l2_ge2d_buf*)); + DECLARE_KFIFO_PTR(frame, typeof(struct vframe_s *)); + DECLARE_KFIFO(out_done_q, struct aml_v4l2_ge2d_buf *, GE2D_FRAME_SIZE); + DECLARE_KFIFO(in_done_q, struct aml_v4l2_ge2d_buf *, GE2D_FRAME_SIZE); + + struct vframe_s *vfpool; + struct aml_v4l2_ge2d_buf *ovbpool; + struct aml_v4l2_ge2d_buf *ivbpool; + struct task_struct *task; + bool running; + struct semaphore sem_in, sem_out; + + /* In p to i transition, output/frame can be multi writer */ + struct mutex output_lock; + + /* for debugging */ + /* + * in[0] --> ge2d <-- in[1] + * out[0]<-- ge2d --> out[1] + */ + int in_num[2]; + int out_num[2]; + ulong fb_token; + + int src_canvas_id[3]; + int dst_canvas_id[3]; +}; + +struct task_ops_s *get_ge2d_ops(void); + +int aml_v4l2_ge2d_init( + struct aml_vcodec_ctx *ctx, + struct aml_ge2d_cfg_infos *cfg, + struct aml_v4l2_ge2d** ge2d_handle); + +int aml_v4l2_ge2d_destroy(struct aml_v4l2_ge2d* ge2d); + +#endif
diff --git a/drivers/amvdec_ports/aml_vcodec_util.c b/drivers/amvdec_ports/aml_vcodec_util.c index 509a42a..54b0d06 100644 --- a/drivers/amvdec_ports/aml_vcodec_util.c +++ b/drivers/amvdec_ports/aml_vcodec_util.c
@@ -22,72 +22,6 @@ #include "aml_vcodec_drv.h" #include "aml_vcodec_util.h" -void __iomem *aml_vcodec_get_reg_addr(struct aml_vcodec_ctx *data, - unsigned int reg_idx) -{ - struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)data; - - if (!data || reg_idx >= NUM_MAX_VCODEC_REG_BASE) { - v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, - "Invalid arguments, reg_idx=%d\n", reg_idx); - return NULL; - } - return ctx->dev->reg_base[reg_idx]; -} -EXPORT_SYMBOL(aml_vcodec_get_reg_addr); - -int aml_vcodec_mem_alloc(struct aml_vcodec_ctx *data, - struct aml_vcodec_mem *mem) -{ - unsigned long size = mem->size; - struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)data; - struct device *dev = &ctx->dev->plat_dev->dev; - - mem->vaddr = dma_alloc_coherent(dev, size, &mem->dma_addr, GFP_KERNEL); - //mem->vaddr = codec_mm_dma_alloc_coherent(dev_name(dev), size, - // &mem->dma_addr, GFP_KERNEL, 0); - if (!mem->vaddr) { - v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, - "%s dma_alloc size=%ld failed!\n", dev_name(dev), - size); - return -ENOMEM; - } - - memset(mem->vaddr, 0, size); - - v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "va: %p\n", mem->vaddr); - v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "dma: 0x%lx\n", (ulong) mem->dma_addr); - v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "size: 0x%lx\n", size); - - return 0; -} -EXPORT_SYMBOL(aml_vcodec_mem_alloc); - -void aml_vcodec_mem_free(struct aml_vcodec_ctx *data, - struct aml_vcodec_mem *mem) -{ - unsigned long size = mem->size; - struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)data; - struct device *dev = &ctx->dev->plat_dev->dev; - - if (!mem->vaddr) { - v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, - "%s dma_free size=%ld failed!\n", dev_name(dev), - size); - return; - } - - v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "va: %p\n", mem->vaddr); - v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "dma: 0x%lx\n", (ulong) mem->dma_addr); - v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "size: 0x%lx\n", size); - - dma_free_coherent(dev, size, mem->vaddr, mem->dma_addr); - mem->vaddr = NULL; - mem->dma_addr = 0; - mem->size = 0; -} -EXPORT_SYMBOL(aml_vcodec_mem_free); - void aml_vcodec_set_curr_ctx(struct aml_vcodec_dev *dev, struct aml_vcodec_ctx *ctx) {
diff --git a/drivers/amvdec_ports/aml_vcodec_util.h b/drivers/amvdec_ports/aml_vcodec_util.h index 312ee40..96c5453 100644 --- a/drivers/amvdec_ports/aml_vcodec_util.h +++ b/drivers/amvdec_ports/aml_vcodec_util.h
@@ -23,14 +23,14 @@ #include <linux/types.h> #include <linux/dma-direction.h> #include <linux/amlogic/media/codec_mm/codec_mm.h> - +/* typedef unsigned long long u64; typedef signed long long s64; typedef unsigned int u32; typedef unsigned short int u16; typedef short int s16; typedef unsigned char u8; - +*/ #define CODEC_MODE(a, b, c, d)\ (((u8)(a) << 24) | ((u8)(b) << 16) | ((u8)(c) << 8) | (u8)(d)) @@ -45,14 +45,16 @@ u32 bytes_used; u32 offset; u64 timestamp; - dma_addr_t dma_addr; u32 model; + ulong meta_ptr; + struct dma_buf *dbuf; }; struct aml_vcodec_ctx; struct aml_vcodec_dev; extern u32 debug_mode; +extern u32 mandatory_dw_mmu; #ifdef v4l_dbg #undef v4l_dbg @@ -69,6 +71,11 @@ #define V4L_DEBUG_CODEC_PARSER (1 << 6) #define V4L_DEBUG_CODEC_PROT (1 << 7) #define V4L_DEBUG_CODEC_EXINFO (1 << 8) +#define V4L_DEBUG_VPP_BUFMGR (1 << 9) +#define V4L_DEBUG_VPP_DETAIL (1 << 10) +#define V4L_DEBUG_TASK_CHAIN (1 << 11) +#define V4L_DEBUG_GE2D_BUFMGR (1 << 12) +#define V4L_DEBUG_GE2D_DETAIL (1 << 13) #define __v4l_dbg(h, id, fmt, args...) \ do { \ @@ -92,12 +99,6 @@ } \ } while (0) -void __iomem *aml_vcodec_get_reg_addr(struct aml_vcodec_ctx *data, - unsigned int reg_idx); -int aml_vcodec_mem_alloc(struct aml_vcodec_ctx *data, - struct aml_vcodec_mem *mem); -void aml_vcodec_mem_free(struct aml_vcodec_ctx *data, - struct aml_vcodec_mem *mem); void aml_vcodec_set_curr_ctx(struct aml_vcodec_dev *dev, struct aml_vcodec_ctx *ctx); struct aml_vcodec_ctx *aml_vcodec_get_curr_ctx(struct aml_vcodec_dev *dev);
diff --git a/drivers/amvdec_ports/aml_vcodec_vfm.c b/drivers/amvdec_ports/aml_vcodec_vfm.c deleted file mode 100644 index 62896ea..0000000 --- a/drivers/amvdec_ports/aml_vcodec_vfm.c +++ /dev/null
@@ -1,245 +0,0 @@ -/* -* Copyright (C) 2017 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. -* -* You should have received a copy of the GNU General Public License along -* with this program; if not, write to the Free Software Foundation, Inc., -* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -* -* Description: -*/ -#include "aml_vcodec_vfm.h" -#include "aml_vcodec_vfq.h" -#include "aml_vcodec_util.h" -#include "aml_vcodec_adapt.h" -#include <media/v4l2-mem2mem.h> - -#define KERNEL_ATRACE_TAG KERNEL_ATRACE_TAG_VIDEO_COMPOSER -#include <trace/events/meson_atrace.h> - -#define RECEIVER_NAME "v4l2-video" -#define PROVIDER_NAME "v4l2-video" - -static struct vframe_s *vdec_vf_peek(void *op_arg) -{ - struct vcodec_vfm_s *vfm = (struct vcodec_vfm_s *)op_arg; - - return vfq_peek(&vfm->vf_que); -} - -static struct vframe_s *vdec_vf_get(void *op_arg) -{ - struct vcodec_vfm_s *vfm = (struct vcodec_vfm_s *)op_arg; - - return vfq_pop(&vfm->vf_que); -} - -static void vdec_vf_put(struct vframe_s *vf, void *op_arg) -{ - struct vcodec_vfm_s *vfm = (struct vcodec_vfm_s *)op_arg; - - /* If the video frame from amvide that means */ - /* the data has been processed and finished, */ - /* then push back to VDA. thus we don't put the */ - /* buffer to the decoder directly.*/ - - //vf_put(vf, vfm->recv_name); - //vf_notify_provider(vfm->recv_name, VFRAME_EVENT_RECEIVER_PUT, NULL); - - if (vfq_level(&vfm->vf_que_recycle) > POOL_SIZE - 1) { - v4l_dbg(vfm->ctx, V4L_DEBUG_CODEC_ERROR, "vfq full.\n"); - return; - } - - atomic_set(&vf->use_cnt, 1); - - vfq_push(&vfm->vf_que_recycle, vf); - - /* schedule capture work. */ - vdec_device_vf_run(vfm->ctx); -} - -static int vdec_event_cb(int type, void *data, void *private_data) -{ - - if (type & VFRAME_EVENT_RECEIVER_PUT) { - } else if (type & VFRAME_EVENT_RECEIVER_GET) { - } else if (type & VFRAME_EVENT_RECEIVER_FRAME_WAIT) { - } - return 0; -} - -static int vdec_vf_states(struct vframe_states *states, void *op_arg) -{ - struct vcodec_vfm_s *vfm = (struct vcodec_vfm_s *)op_arg; - - states->vf_pool_size = POOL_SIZE; - states->buf_recycle_num = 0; - states->buf_free_num = POOL_SIZE - vfq_level(&vfm->vf_que); - states->buf_avail_num = vfq_level(&vfm->vf_que); - - return 0; -} - -void video_vf_put(char *receiver, struct vdec_v4l2_buffer *fb, int id) -{ - struct vframe_provider_s *vfp = vf_get_provider(receiver); - struct vframe_s *vf = (struct vframe_s *)fb->vf_handle; - - ATRACE_COUNTER("v4l2_to", vf->index_disp); - - v4l_dbg(0, V4L_DEBUG_CODEC_OUTPUT, - "[%d]: TO (%s) vf: %p, idx: %d, " - "Y:(%lx, %u) C/U:(%lx, %u) V:(%lx, %u)\n", - id, vfp->name, vf, vf->index, - fb->m.mem[0].addr, fb->m.mem[0].size, - fb->m.mem[1].addr, fb->m.mem[1].size, - fb->m.mem[2].addr, fb->m.mem[2].size); - - if (vfp && vf && atomic_dec_and_test(&vf->use_cnt)) - vf_put(vf, receiver); -} - -static const struct vframe_operations_s vf_provider = { - .peek = vdec_vf_peek, - .get = vdec_vf_get, - .put = vdec_vf_put, - .event_cb = vdec_event_cb, - .vf_states = vdec_vf_states, -}; - -static int video_receiver_event_fun(int type, void *data, void *private_data) -{ - int ret = 0; - struct vframe_states states; - struct vcodec_vfm_s *vfm = (struct vcodec_vfm_s *)private_data; - - switch (type) { - case VFRAME_EVENT_PROVIDER_UNREG: { - if (vf_get_receiver(vfm->prov_name)) { - v4l_dbg(vfm->ctx, V4L_DEBUG_CODEC_EXINFO, - "unreg %s provider.\n", - vfm->prov_name); - vf_unreg_provider(&vfm->vf_prov); - } - - break; - } - - case VFRAME_EVENT_PROVIDER_START: { - if (vf_get_receiver(vfm->prov_name)) { - v4l_dbg(vfm->ctx, V4L_DEBUG_CODEC_EXINFO, - "reg %s provider.\n", - vfm->prov_name); - vf_provider_init(&vfm->vf_prov, vfm->prov_name, - &vf_provider, vfm); - vf_reg_provider(&vfm->vf_prov); - vf_notify_receiver(vfm->prov_name, - VFRAME_EVENT_PROVIDER_START, NULL); - } - - vfq_init(&vfm->vf_que, POOL_SIZE + 1, &vfm->pool[0]); - vfq_init(&vfm->vf_que_recycle, POOL_SIZE + 1, &vfm->pool_recycle[0]); - - break; - } - - case VFRAME_EVENT_PROVIDER_QUREY_STATE: { - vdec_vf_states(&states, vfm); - if (states.buf_avail_num > 0) - ret = RECEIVER_ACTIVE; - break; - } - - case VFRAME_EVENT_PROVIDER_VFRAME_READY: { - if (vfq_level(&vfm->vf_que) > POOL_SIZE - 1) - ret = -1; - - if (!vf_peek(vfm->recv_name)) - ret = -1; - - vfm->vf = vf_get(vfm->recv_name); - if (!vfm->vf) - ret = -1; - - if (ret < 0) { - v4l_dbg(vfm->ctx, V4L_DEBUG_CODEC_ERROR, "receiver vf err.\n"); - break; - } - - vfq_push(&vfm->vf_que, vfm->vf); - - if (vfm->ada_ctx->vfm_path == FRAME_BASE_PATH_V4L_VIDEO) { - vf_notify_receiver(vfm->prov_name, - VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); - break; - } - - /* schedule capture work. */ - vdec_device_vf_run(vfm->ctx); - - break; - } - - default: - v4l_dbg(vfm->ctx, V4L_DEBUG_CODEC_EXINFO, - "the vf event is %d", type); - } - - return ret; -} - -static const struct vframe_receiver_op_s vf_receiver = { - .event_cb = video_receiver_event_fun -}; - -struct vframe_s *peek_video_frame(struct vcodec_vfm_s *vfm) -{ - if (vfm->ada_ctx->vfm_path == FRAME_BASE_PATH_V4L_VIDEO) - return vfq_peek(&vfm->vf_que_recycle); - else - return vfq_peek(&vfm->vf_que); -} - -struct vframe_s *get_video_frame(struct vcodec_vfm_s *vfm) -{ - if (vfm->ada_ctx->vfm_path == FRAME_BASE_PATH_V4L_VIDEO) - return vfq_pop(&vfm->vf_que_recycle); - else - return vfq_pop(&vfm->vf_que); -} - -int vcodec_vfm_init(struct vcodec_vfm_s *vfm) -{ - int ret; - - snprintf(vfm->recv_name, VF_NAME_SIZE, "%s-%d", - RECEIVER_NAME, vfm->ctx->id); - snprintf(vfm->prov_name, VF_NAME_SIZE, "%s-%d", - PROVIDER_NAME, vfm->ctx->id); - - vfm->ada_ctx->recv_name = vfm->recv_name; - - vf_receiver_init(&vfm->vf_recv, vfm->recv_name, &vf_receiver, vfm); - ret = vf_reg_receiver(&vfm->vf_recv); - - vfm->vfm_initialized = ret ? false : true; - - return ret; -} - -void vcodec_vfm_release(struct vcodec_vfm_s *vfm) -{ - if (vfm->vfm_initialized) - vf_unreg_receiver(&vfm->vf_recv); -} -
diff --git a/drivers/amvdec_ports/aml_vcodec_vfm.h b/drivers/amvdec_ports/aml_vcodec_vfm.h deleted file mode 100644 index 141e9a7..0000000 --- a/drivers/amvdec_ports/aml_vcodec_vfm.h +++ /dev/null
@@ -1,60 +0,0 @@ -/* -* Copyright (C) 2017 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. -* -* You should have received a copy of the GNU General Public License along -* with this program; if not, write to the Free Software Foundation, Inc., -* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -* -* Description: -*/ -#ifndef __AML_VCODEC_VFM_H_ -#define __AML_VCODEC_VFM_H_ - -#include "aml_vcodec_vfq.h" -#include "aml_vcodec_drv.h" -#include "aml_vcodec_dec.h" -#include <linux/amlogic/media/vfm/vframe_provider.h> -#include <linux/amlogic/media/vfm/vframe_receiver.h> - -#define VF_NAME_SIZE (32) -#define POOL_SIZE (32) - -struct vcodec_vfm_s { - struct aml_vcodec_ctx *ctx; - struct aml_vdec_adapt *ada_ctx; - struct vfq_s vf_que; - struct vfq_s vf_que_recycle; - struct vframe_s *vf; - struct vframe_s *pool[POOL_SIZE + 1]; - struct vframe_s *pool_recycle[POOL_SIZE + 1]; - char recv_name[VF_NAME_SIZE]; - char prov_name[VF_NAME_SIZE]; - struct vframe_provider_s vf_prov; - struct vframe_receiver_s vf_recv; - bool vfm_initialized; -}; - -int vcodec_vfm_init(struct vcodec_vfm_s *vfm); - -void vcodec_vfm_release(struct vcodec_vfm_s *vfm); - -struct vframe_s *peek_video_frame(struct vcodec_vfm_s *vfm); - -struct vframe_s *get_video_frame(struct vcodec_vfm_s *vfm); - -int get_fb_from_queue(struct aml_vcodec_ctx *ctx, struct vdec_v4l2_buffer **out_fb); -int put_fb_to_queue(struct aml_vcodec_ctx *ctx, struct vdec_v4l2_buffer *in_fb); - -void video_vf_put(char *receiver, struct vdec_v4l2_buffer *fb, int id); - -#endif /* __AML_VCODEC_VFM_H_ */
diff --git a/drivers/amvdec_ports/aml_vcodec_vfq.h b/drivers/amvdec_ports/aml_vcodec_vfq.h deleted file mode 100644 index e19c53c..0000000 --- a/drivers/amvdec_ports/aml_vcodec_vfq.h +++ /dev/null
@@ -1,112 +0,0 @@ -/* -* Copyright (C) 2017 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. -* -* You should have received a copy of the GNU General Public License along -* with this program; if not, write to the Free Software Foundation, Inc., -* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -* -* Description: -*/ -#ifndef __AML_VCODEC_VFQ_H_ -#define __AML_VCODEC_VFQ_H_ - -#include <linux/types.h> -#include <asm/barrier.h> - -struct vfq_s { - int rp; - int wp; - int size; - int pre_rp; - int pre_wp; - struct vframe_s **pool; -}; - -static inline void vfq_lookup_start(struct vfq_s *q) -{ - q->pre_rp = q->rp; - q->pre_wp = q->wp; -} -static inline void vfq_lookup_end(struct vfq_s *q) -{ - q->rp = q->pre_rp; - q->wp = q->pre_wp; -} - -static inline void vfq_init(struct vfq_s *q, u32 size, struct vframe_s **pool) -{ - q->rp = q->wp = 0; - q->size = size; - q->pool = pool; -} - -static inline bool vfq_empty(struct vfq_s *q) -{ - return q->rp == q->wp; -} - -static inline void vfq_push(struct vfq_s *q, struct vframe_s *vf) -{ - int wp = q->wp; - - /*ToDo*/ - smp_mb(); - - q->pool[wp] = vf; - - /*ToDo*/ - smp_wmb(); - - q->wp = (wp == (q->size - 1)) ? 0 : (wp + 1); -} - -static inline struct vframe_s *vfq_pop(struct vfq_s *q) -{ - struct vframe_s *vf; - int rp; - - if (vfq_empty(q)) - return NULL; - - rp = q->rp; - - /*ToDo*/ - smp_rmb(); - - vf = q->pool[rp]; - - /*ToDo*/ - smp_mb(); - - q->rp = (rp == (q->size - 1)) ? 0 : (rp + 1); - - return vf; -} - -static inline struct vframe_s *vfq_peek(struct vfq_s *q) -{ - return (vfq_empty(q)) ? NULL : q->pool[q->rp]; -} - -static inline int vfq_level(struct vfq_s *q) -{ - int level = q->wp - q->rp; - - if (level < 0) - level += q->size; - - return level; -} - -#endif /* __AML_VCODEC_VFQ_H_ */ -
diff --git a/drivers/amvdec_ports/aml_vcodec_vpp.c b/drivers/amvdec_ports/aml_vcodec_vpp.c new file mode 100644 index 0000000..9f4e960 --- /dev/null +++ b/drivers/amvdec_ports/aml_vcodec_vpp.c
@@ -0,0 +1,1102 @@ +/* +* Copyright (C) 2020 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. +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, write to the Free Software Foundation, Inc., +* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +* Description: +*/ + +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/videodev2.h> +#include <uapi/linux/sched/types.h> +#include <linux/amlogic/meson_uvm_core.h> + +#include "aml_vcodec_vpp.h" +#include "aml_vcodec_adapt.h" +#include "vdec_drv_if.h" +#include "../common/chips/decoder_cpu_ver_info.h" + +#define KERNEL_ATRACE_TAG KERNEL_ATRACE_TAG_V4L2 +#include <trace/events/meson_atrace.h> + +#define VPP_BUF_GET_IDX(vpp_buf) (vpp_buf->aml_buf->vb.vb2_buf.index) +#define INPUT_PORT 0 +#define OUTPUT_PORT 1 + +extern int dump_vpp_input; +extern int vpp_bypass_frames; + +static void di_release_keep_buf_wrap(void *arg) +{ + struct di_buffer *buf = (struct di_buffer *)arg; + + v4l_dbg(0, V4L_DEBUG_VPP_BUFMGR, + "%s release di local buffer %px, vf:%px, comm:%s, pid:%d\n", + __func__ , buf, buf->vf, + current->comm, current->pid); + + di_release_keep_buf(buf); + + ATRACE_COUNTER("VC_OUT_VPP_LC-2.lc_release", buf->mng.index); +} + +static int attach_DI_buffer(struct aml_v4l2_vpp_buf *vpp_buf) +{ + struct aml_v4l2_vpp *vpp = vpp_buf->di_buf.caller_data; + struct dma_buf *dma = NULL; + struct aml_video_dec_buf *aml_buf = NULL; + struct uvm_hook_mod_info u_info; + int ret; + + aml_buf = vpp_buf->aml_buf; + if (!aml_buf) + return -EINVAL; + + dma = aml_buf->vb.vb2_buf.planes[0].dbuf; + if (!dma || !dmabuf_is_uvm(dma)) { + v4l_dbg(vpp->ctx, V4L_DEBUG_CODEC_ERROR, + "attach_DI_buffer err\n"); + return -EINVAL; + } + + if (!vpp_buf->di_local_buf) { + v4l_dbg(vpp->ctx, V4L_DEBUG_VPP_BUFMGR, + "attach_DI_buffer nothing\n"); + return 0; + } + + if (uvm_get_hook_mod(dma, VF_PROCESS_DI)) { + uvm_put_hook_mod(dma, VF_PROCESS_DI); + v4l_dbg(vpp->ctx, V4L_DEBUG_CODEC_ERROR, + "attach_DI_buffer exist hook\n"); + return -EINVAL; + } + u_info.type = VF_PROCESS_DI; + u_info.arg = (void *)vpp_buf->di_local_buf; + u_info.free = di_release_keep_buf_wrap; + + ret = uvm_attach_hook_mod(dma, &u_info); + if (ret < 0) { + v4l_dbg(vpp->ctx, V4L_DEBUG_CODEC_ERROR, + "fail to set dmabuf DI hook\n"); + } + + ATRACE_COUNTER("VC_OUT_VPP_LC-0.lc_attach", vpp_buf->di_local_buf->mng.index); + + v4l_dbg(vpp->ctx, V4L_DEBUG_VPP_BUFMGR, + "%s attach di local buffer %px, dbuf:%px\n", + __func__ , vpp_buf->di_local_buf, dma); + + return ret; +} + +static int detach_DI_buffer(struct aml_v4l2_vpp_buf *vpp_buf) +{ + struct aml_v4l2_vpp *vpp = vpp_buf->di_buf.caller_data; + struct dma_buf *dma = NULL; + struct aml_video_dec_buf *aml_buf = NULL; + int ret; + + aml_buf = vpp_buf->aml_buf; + if (!aml_buf) + return -EINVAL; + + dma = aml_buf->vb.vb2_buf.planes[0].dbuf; + if (!dma || !dmabuf_is_uvm(dma)) { + v4l_dbg(vpp->ctx, V4L_DEBUG_CODEC_ERROR, + "detach_DI_buffer err\n"); + return -EINVAL; + } + + if (!vpp_buf->di_local_buf) { + v4l_dbg(vpp->ctx, V4L_DEBUG_VPP_BUFMGR, + "detach_DI_buffer nothing\n"); + return 0; + } + + ATRACE_COUNTER("VC_OUT_VPP_LC-1.lc_detach", vpp_buf->di_local_buf->mng.index); + + ret = uvm_detach_hook_mod(dma, VF_PROCESS_DI); + if (ret < 0) { + v4l_dbg(vpp->ctx, V4L_DEBUG_VPP_BUFMGR, + "fail to remove dmabuf DI hook\n"); + } + + v4l_dbg(vpp->ctx, V4L_DEBUG_VPP_BUFMGR, + "%s detach di local buffer %px, dbuf:%px\n", + __func__ , vpp_buf->di_local_buf, dma); + + return ret; +} + +static void release_DI_buff(struct aml_v4l2_vpp* vpp) +{ + struct aml_v4l2_vpp_buf *vpp_buf = NULL; + + while (kfifo_get(&vpp->out_done_q, &vpp_buf)) { + if (vpp_buf->di_buf.private_data) { + di_release_keep_buf(vpp_buf->di_local_buf); + v4l_dbg(vpp->ctx, V4L_DEBUG_VPP_BUFMGR, + "%s release di local buffer %px\n", + __func__ , vpp_buf->di_local_buf); + } + } +} + +static int is_di_input_buff_full(struct aml_v4l2_vpp *vpp) +{ + return ((vpp->in_num[INPUT_PORT] - vpp->in_num[OUTPUT_PORT]) + > vpp->di_ibuf_num) ? true : false; +} + +static int is_di_output_buff_full(struct aml_v4l2_vpp *vpp) +{ + return ((vpp->out_num[INPUT_PORT] - vpp->out_num[OUTPUT_PORT]) + > vpp->di_obuf_num) ? true : false; +} + +static enum DI_ERRORTYPE + v4l_vpp_fill_output_done_alloc_buffer(struct di_buffer *buf) +{ + struct aml_v4l2_vpp *vpp = buf->caller_data; + struct aml_v4l2_vpp_buf *vpp_buf = NULL; + struct vdec_v4l2_buffer *fb = NULL; + bool bypass = false; + bool eos = false; + + if (!vpp || !vpp->ctx) { + pr_err("fatal %s %d vpp:%p\n", + __func__, __LINE__, vpp); + di_release_keep_buf_wrap(buf); + return DI_ERR_UNDEFINED; + } + + if (vpp->ctx->is_stream_off) { + v4l_dbg(vpp->ctx, V4L_DEBUG_CODEC_EXINFO, + "vpp discard submit frame %s %d vpp:%p\n", + __func__, __LINE__, vpp); + di_release_keep_buf_wrap(buf); + return DI_ERR_UNDEFINED; + } + + if (!kfifo_get(&vpp->processing, &vpp_buf)) { + v4l_dbg(vpp->ctx, V4L_DEBUG_CODEC_EXINFO, + "vpp doesn't get output %s %d vpp:%p\n", + __func__, __LINE__, vpp); + di_release_keep_buf_wrap(buf); + return DI_ERR_UNDEFINED; + } + + fb = &vpp_buf->aml_buf->frame_buffer; + eos = (buf->flag & DI_FLAG_EOS); + bypass = (buf->flag & DI_FLAG_BUF_BY_PASS); + + vpp_buf->di_buf.vf->timestamp = buf->vf->timestamp; + vpp_buf->di_buf.private_data = buf->private_data; + vpp_buf->di_buf.vf->vf_ext = buf->vf; + vpp_buf->di_buf.flag = buf->flag; + vpp_buf->di_buf.vf->v4l_mem_handle = (ulong)fb; + + if (!eos && !bypass) { + vpp_buf->di_local_buf = buf; + vpp_buf->di_buf.vf->vf_ext = buf->vf; + vpp_buf->di_buf.vf->flag |= VFRAME_FLAG_CONTAIN_POST_FRAME; + } + + kfifo_put(&vpp->out_done_q, vpp_buf); + + if (vpp->is_prog) + kfifo_put(&vpp->input, vpp_buf->inbuf); + + v4l_dbg(vpp->ctx, V4L_DEBUG_VPP_BUFMGR, + "vpp_output local done: idx:%d, vf:%px, ext vf:%px, idx:%d, flag(vf:%x di:%x) %s %s, ts:%lld, " + "in:%d, out:%d, vf:%d, in done:%d, out done:%d\n", + fb->buf_idx, + vpp_buf->di_buf.vf, + vpp_buf->di_buf.vf->vf_ext, + vpp_buf->di_buf.vf->index, + vpp_buf->di_buf.vf->flag, + buf->flag, + vpp->is_prog ? "P" : "I", + eos ? "eos" : "", + vpp_buf->di_buf.vf->timestamp, + kfifo_len(&vpp->input), + kfifo_len(&vpp->output), + kfifo_len(&vpp->frame), + kfifo_len(&vpp->in_done_q), + kfifo_len(&vpp->out_done_q)); + + ATRACE_COUNTER("VC_OUT_VPP-2.lc_submit", fb->buf_idx); + + fb->task->submit(fb->task, TASK_TYPE_VPP); + + vpp->out_num[OUTPUT_PORT]++; + vpp->in_num[OUTPUT_PORT]++; + + return DI_ERR_NONE; +} + +static enum DI_ERRORTYPE + v4l_vpp_empty_input_done(struct di_buffer *buf) +{ + struct aml_v4l2_vpp *vpp = buf->caller_data; + struct aml_v4l2_vpp_buf *vpp_buf; + struct vdec_v4l2_buffer *fb = NULL; + bool eos = false; + + if (!vpp || !vpp->ctx) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "fatal %s %d vpp:%px\n", + __func__, __LINE__, vpp); + return DI_ERR_UNDEFINED; + } + + if (vpp->ctx->is_stream_off) { + v4l_dbg(vpp->ctx, V4L_DEBUG_CODEC_EXINFO, + "vpp discard recycle frame %s %d vpp:%p\n", + __func__, __LINE__, vpp); + return DI_ERR_UNDEFINED; + } + + vpp_buf = container_of(buf, struct aml_v4l2_vpp_buf, di_buf); + fb = &vpp_buf->aml_buf->frame_buffer; + eos = (buf->flag & DI_FLAG_EOS); + + v4l_dbg(vpp->ctx, V4L_DEBUG_VPP_BUFMGR, + "vpp_input done: idx:%d, vf:%px, idx: %d, flag(vf:%x di:%x) %s %s, ts:%lld, " + "in:%d, out:%d, vf:%d, in done:%d, out done:%d\n", + fb->buf_idx, + buf->vf, + buf->vf->index, + buf->vf->flag, + buf->flag, + vpp->is_prog ? "P" : "I", + eos ? "eos" : "", + buf->vf->timestamp, + kfifo_len(&vpp->input), + kfifo_len(&vpp->output), + kfifo_len(&vpp->frame), + kfifo_len(&vpp->in_done_q), + kfifo_len(&vpp->out_done_q)); + + if (!vpp->is_prog) { + /* recycle vf only in non-bypass mode */ + fb->task->recycle(fb->task, TASK_TYPE_VPP); + + kfifo_put(&vpp->input, vpp_buf); + } + + if (vpp->buffer_mode != BUFFER_MODE_ALLOC_BUF) + vpp->in_num[OUTPUT_PORT]++; + + ATRACE_COUNTER("VC_IN_VPP-1.recycle", fb->buf_idx); + + return DI_ERR_NONE; +} + +static enum DI_ERRORTYPE + v4l_vpp_fill_output_done(struct di_buffer *buf) +{ + struct aml_v4l2_vpp *vpp = buf->caller_data; + struct aml_v4l2_vpp_buf *vpp_buf = NULL; + struct vdec_v4l2_buffer *fb = NULL; + bool bypass = false; + bool eos = false; + + if (!vpp || !vpp->ctx) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "fatal %s %d vpp:%px\n", + __func__, __LINE__, vpp); + return DI_ERR_UNDEFINED; + } + + if (vpp->ctx->is_stream_off) { + v4l_dbg(vpp->ctx, V4L_DEBUG_CODEC_EXINFO, + "vpp discard submit frame %s %d vpp:%p\n", + __func__, __LINE__, vpp); + return DI_ERR_UNDEFINED; + } + + vpp_buf = container_of(buf, struct aml_v4l2_vpp_buf, di_buf); + fb = &vpp_buf->aml_buf->frame_buffer; + eos = (buf->flag & DI_FLAG_EOS); + bypass = (buf->flag & DI_FLAG_BUF_BY_PASS); + + /* recovery fb handle. */ + buf->vf->v4l_mem_handle = (ulong)fb; + + kfifo_put(&vpp->out_done_q, vpp_buf); + + v4l_dbg(vpp->ctx, V4L_DEBUG_VPP_BUFMGR, + "vpp_output done: idx:%d, vf:%px, idx:%d, flag(vf:%x di:%x) %s %s, ts:%lld, " + "in:%d, out:%d, vf:%d, in done:%d, out done:%d\n", + fb->buf_idx, + buf->vf, + buf->vf->index, + buf->vf->flag, + buf->flag, + vpp->is_prog ? "P" : "I", + eos ? "eos" : "", + buf->vf->timestamp, + kfifo_len(&vpp->input), + kfifo_len(&vpp->output), + kfifo_len(&vpp->frame), + kfifo_len(&vpp->in_done_q), + kfifo_len(&vpp->out_done_q)); + + ATRACE_COUNTER("VC_OUT_VPP-2.submit", fb->buf_idx); + + fb->task->submit(fb->task, TASK_TYPE_VPP); + + vpp->out_num[OUTPUT_PORT]++; + + /* count for bypass nr */ + if (vpp->buffer_mode == BUFFER_MODE_ALLOC_BUF) + vpp->in_num[OUTPUT_PORT]++; + + return DI_ERR_NONE; +} + +static void vpp_vf_get(void *caller, struct vframe_s **vf_out) +{ + struct aml_v4l2_vpp *vpp = (struct aml_v4l2_vpp *)caller; + struct aml_v4l2_vpp_buf *vpp_buf = NULL; + struct vdec_v4l2_buffer *fb = NULL; + struct di_buffer *buf = NULL; + struct vframe_s *vf = NULL; + bool bypass = false; + bool eos = false; + + if (!vpp || !vpp->ctx) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "fatal %s %d vpp:%px\n", + __func__, __LINE__, vpp); + return; + } + + if (kfifo_get(&vpp->out_done_q, &vpp_buf)) { + fb = &vpp_buf->aml_buf->frame_buffer; + buf = &vpp_buf->di_buf; + eos = (buf->flag & DI_FLAG_EOS); + bypass = (buf->flag & DI_FLAG_BUF_BY_PASS); + vf = buf->vf; + + if (eos) { + v4l_dbg(vpp->ctx, V4L_DEBUG_VPP_DETAIL, + "%s %d got eos\n", + __func__, __LINE__); + vf->type |= VIDTYPE_V4L_EOS; + vf->flag = VFRAME_FLAG_EMPTY_FRAME_V4L; + } + + if (!eos && !bypass) { + if (vpp->buffer_mode == BUFFER_MODE_ALLOC_BUF) { + attach_DI_buffer(vpp_buf); + } + } + + *vf_out = vf; + + ATRACE_COUNTER("VC_OUT_VPP-3.vf_get", fb->buf_idx); + + v4l_dbg(vpp->ctx, V4L_DEBUG_VPP_BUFMGR, + "%s: vf:%px, index:%d, flag(vf:%x di:%x), ts:%lld\n", + __func__, vf, + vf->index, + vf->flag, + buf->flag, + vf->timestamp); + } +} + +static void vpp_vf_put(void *caller, struct vframe_s *vf) +{ + struct aml_v4l2_vpp *vpp = (struct aml_v4l2_vpp *)caller; + struct vdec_v4l2_buffer *fb = NULL; + struct aml_video_dec_buf *aml_buf = NULL; + struct aml_v4l2_vpp_buf *vpp_buf = NULL; + struct di_buffer *buf = NULL; + bool bypass = false; + bool eos = false; + + fb = (struct vdec_v4l2_buffer *) vf->v4l_mem_handle; + aml_buf = container_of(fb, struct aml_video_dec_buf, frame_buffer); + + + vpp_buf = (struct aml_v4l2_vpp_buf *) aml_buf->vpp_buf_handle; + buf = &vpp_buf->di_buf; + eos = (buf->flag & DI_FLAG_EOS); + bypass = (buf->flag & DI_FLAG_BUF_BY_PASS); + + v4l_dbg(vpp->ctx, V4L_DEBUG_VPP_BUFMGR, + "%s: vf:%px, index:%d, flag(vf:%x di:%x), ts:%lld\n", + __func__, vf, + vf->index, + vf->flag, + buf->flag, + vf->timestamp); + + ATRACE_COUNTER("VC_IN_VPP-0.vf_put", fb->buf_idx); + + if (vpp->is_prog) { + ATRACE_COUNTER("VC_IN_VPP-1.recycle", fb->buf_idx); + fb->task->recycle(fb->task, TASK_TYPE_VPP); + } + + if (!eos && !bypass) { + if (vpp->buffer_mode == BUFFER_MODE_ALLOC_BUF) { + detach_DI_buffer(vpp_buf); + } + } + + mutex_lock(&vpp->output_lock); + kfifo_put(&vpp->frame, vf); + kfifo_put(&vpp->output, vpp_buf); + mutex_unlock(&vpp->output_lock); + up(&vpp->sem_out); +} + +static int aml_v4l2_vpp_thread(void* param) +{ + struct aml_v4l2_vpp* vpp = param; + struct aml_vcodec_ctx *ctx = vpp->ctx; + + v4l_dbg(ctx, V4L_DEBUG_VPP_DETAIL, "enter vpp thread\n"); + while (vpp->running) { + struct aml_v4l2_vpp_buf *in_buf; + struct aml_v4l2_vpp_buf *out_buf = NULL; + struct vframe_s *vf_out = NULL; + struct vdec_v4l2_buffer *fb; + + if (down_interruptible(&vpp->sem_in)) + goto exit; +retry: + if (!vpp->running) + break; + + if (kfifo_is_empty(&vpp->output)) { + if (down_interruptible(&vpp->sem_out)) + goto exit; + goto retry; + } + + if ((vpp->buffer_mode == BUFFER_MODE_ALLOC_BUF) && + (is_di_input_buff_full(vpp) || is_di_output_buff_full(vpp))) { + usleep_range(500, 550); + goto retry; + } + + mutex_lock(&vpp->output_lock); + if (!kfifo_get(&vpp->output, &out_buf)) { + mutex_unlock(&vpp->output_lock); + v4l_dbg(ctx, 0, "vpp can not get output\n"); + goto exit; + } + mutex_unlock(&vpp->output_lock); + + /* bind v4l2 buffers */ + if (!vpp->is_prog && !out_buf->aml_buf) { + struct vdec_v4l2_buffer *out; + + if (!ctx->fb_ops.query(&ctx->fb_ops, &vpp->fb_token)) { + usleep_range(500, 550); + mutex_lock(&vpp->output_lock); + kfifo_put(&vpp->output, out_buf); + mutex_unlock(&vpp->output_lock); + goto retry; + } + + if (ctx->fb_ops.alloc(&ctx->fb_ops, vpp->fb_token, &out, AML_FB_REQ_VPP)) { + usleep_range(5000, 5500); + mutex_lock(&vpp->output_lock); + kfifo_put(&vpp->output, out_buf); + mutex_unlock(&vpp->output_lock); + goto retry; + } + + out_buf->aml_buf = container_of(out, + struct aml_video_dec_buf, frame_buffer); + out_buf->aml_buf->vpp_buf_handle = (ulong) out_buf; + v4l_dbg(ctx, V4L_DEBUG_VPP_BUFMGR, + "vpp bind buf:%d to vpp_buf:%px\n", + VPP_BUF_GET_IDX(out_buf), out_buf); + + out->m.mem[0].bytes_used = out->m.mem[0].size; + out->m.mem[1].bytes_used = out->m.mem[1].size; + } + + /* safe to pop in_buf */ + if (!kfifo_get(&vpp->in_done_q, &in_buf)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "vpp can not get input\n"); + goto exit; + } + + mutex_lock(&vpp->output_lock); + if (!kfifo_get(&vpp->frame, &vf_out)) { + mutex_unlock(&vpp->output_lock); + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "vpp can not get frame\n"); + goto exit; + } + mutex_unlock(&vpp->output_lock); + + if (!vpp->is_prog) { + /* submit I to DI. */ + fb = &out_buf->aml_buf->frame_buffer; + fb->status = FB_ST_VPP; + + memcpy(vf_out, in_buf->di_buf.vf, sizeof(*vf_out)); + memcpy(vf_out->canvas0_config, + in_buf->di_buf.vf->canvas0_config, + 2 * sizeof(struct canvas_config_s)); + + vf_out->canvas0_config[0].phy_addr = fb->m.mem[0].addr; + if (fb->num_planes == 1) + vf_out->canvas0_config[1].phy_addr = + fb->m.mem[0].addr + fb->m.mem[0].offset; + else + vf_out->canvas0_config[1].phy_addr = + fb->m.mem[1].addr; + + if (in_buf->di_buf.flag & DI_FLAG_EOS) + memset(vf_out, 0, sizeof(*vf_out)); + + vf_out->meta_data_size = in_buf->di_buf.vf->meta_data_size; + vf_out->meta_data_buf = in_buf->di_buf.vf->meta_data_buf; + } else { + /* submit P to DI. */ + out_buf->aml_buf = in_buf->aml_buf; + out_buf->aml_buf->vpp_buf_handle = (ulong) out_buf; + + memcpy(vf_out, in_buf->di_buf.vf, sizeof(*vf_out)); + } + + /* fill outbuf parms. */ + out_buf->di_buf.vf = vf_out; + out_buf->di_buf.flag = 0; + out_buf->di_local_buf = NULL; + out_buf->di_buf.caller_data = vpp; + + /* fill inbuf parms. */ + in_buf->di_buf.caller_data = vpp; + + /* + * HWC or SF should hold di buffres refcnt after resolution changed + * that might cause stuck, thus sumbit 10 frames from dec to display directly. + * then frames will be pushed out from these buffer queuen and + * recycle local buffers to DI module. + */ + if (/*(ctx->vpp_cfg.res_chg) && */(vpp->is_prog) && + (vpp->buffer_mode == BUFFER_MODE_ALLOC_BUF)) { + if (vpp->in_num[INPUT_PORT] < vpp_bypass_frames) { + vpp->is_bypass_p = true; + } else { + vpp->is_bypass_p = false; + ctx->vpp_cfg.res_chg = false; + } + } + + v4l_dbg(ctx, V4L_DEBUG_VPP_BUFMGR, + "vpp_handle start: idx:(%d, %d), dec vf:%px/%d, vpp vf:%px/%d, iphy:%lx/%lx %dx%d ophy:%lx/%lx %dx%d, %s %s " + "in:%d, out:%d, vf:%d, in done:%d, out done:%d", + in_buf->aml_buf->frame_buffer.buf_idx, + out_buf->aml_buf->frame_buffer.buf_idx, + in_buf->di_buf.vf, in_buf->di_buf.vf->index, + out_buf->di_buf.vf, VPP_BUF_GET_IDX(out_buf), + in_buf->di_buf.vf->canvas0_config[0].phy_addr, + in_buf->di_buf.vf->canvas0_config[1].phy_addr, + in_buf->di_buf.vf->canvas0_config[0].width, + in_buf->di_buf.vf->canvas0_config[0].height, + vf_out->canvas0_config[0].phy_addr, + vf_out->canvas0_config[1].phy_addr, + vf_out->canvas0_config[0].width, + vf_out->canvas0_config[0].height, + vpp->is_prog ? "P" : "", + vpp->is_bypass_p ? "bypass-prog" : "", + kfifo_len(&vpp->input), + kfifo_len(&vpp->output), + kfifo_len(&vpp->frame), + kfifo_len(&vpp->in_done_q), + kfifo_len(&vpp->out_done_q)); + + if (vpp->is_bypass_p) { + ATRACE_COUNTER("V4L_OUT_VPP-1.direct_handle_start", + in_buf->aml_buf->frame_buffer.buf_idx); + out_buf->di_buf.flag = in_buf->di_buf.flag; + out_buf->di_buf.vf->vf_ext = in_buf->di_buf.vf; + + v4l_vpp_fill_output_done(&out_buf->di_buf); + v4l_vpp_empty_input_done(&in_buf->di_buf); + } else { + if (vpp->buffer_mode == BUFFER_MODE_ALLOC_BUF) { + /* + * the flow of DI local buffer: + * empty input -> output done cb -> fetch processing fifo. + */ + ATRACE_COUNTER("VC_OUT_VPP-1.lc_handle_start", + in_buf->aml_buf->frame_buffer.buf_idx); + out_buf->inbuf = in_buf; + kfifo_put(&vpp->processing, out_buf); + + di_empty_input_buffer(vpp->di_handle, &in_buf->di_buf); + } else { + ATRACE_COUNTER("VC_OUT_VPP-1.fill_output_start", + out_buf->aml_buf->frame_buffer.buf_idx); + di_fill_output_buffer(vpp->di_handle, &out_buf->di_buf); + + ATRACE_COUNTER("VC_OUT_VPP-1.empty_input_start", + in_buf->aml_buf->frame_buffer.buf_idx); + di_empty_input_buffer(vpp->di_handle, &in_buf->di_buf); + } + } + vpp->in_num[INPUT_PORT]++; + vpp->out_num[INPUT_PORT]++; + } +exit: + while (!kthread_should_stop()) { + usleep_range(1000, 2000); + } + + v4l_dbg(ctx, V4L_DEBUG_VPP_DETAIL, "exit vpp thread\n"); + + return 0; +} + +int aml_v4l2_vpp_get_buf_num(u32 mode) +{ + if ((mode == VPP_MODE_DI) || + (mode == VPP_MODE_COLOR_CONV) || + (mode == VPP_MODE_NOISE_REDUC)) { + return 4; + } + //TODO: support more modes + return 2; +} + +int aml_v4l2_vpp_reset(struct aml_v4l2_vpp *vpp) +{ + int i; + struct sched_param param = + { .sched_priority = MAX_RT_PRIO - 1 }; + + vpp->running = false; + up(&vpp->sem_in); + up(&vpp->sem_out); + kthread_stop(vpp->task); + + kfifo_reset(&vpp->input); + kfifo_reset(&vpp->output); + kfifo_reset(&vpp->frame); + kfifo_reset(&vpp->out_done_q); + kfifo_reset(&vpp->in_done_q); + kfifo_reset(&vpp->processing); + + for (i = 0 ; i < VPP_FRAME_SIZE ; i++) { + memset(&vpp->ivbpool[i], 0, sizeof(struct aml_v4l2_vpp_buf)); + + kfifo_put(&vpp->input, &vpp->ivbpool[i]); + } + + for (i = 0 ; i < vpp->buf_size ; i++) { + memset(&vpp->ovbpool[i], 0, sizeof(struct aml_v4l2_vpp_buf)); + memset(&vpp->vfpool[i], 0, sizeof(struct vframe_s)); + + kfifo_put(&vpp->output, &vpp->ovbpool[i]); + kfifo_put(&vpp->frame, &vpp->vfpool[i]); + } + + vpp->in_num[0] = 0; + vpp->in_num[1] = 0; + vpp->out_num[0] = 0; + vpp->out_num[1] = 0; + vpp->fb_token = 0; + sema_init(&vpp->sem_in, 0); + sema_init(&vpp->sem_out, 0); + + vpp->running = true; + vpp->task = kthread_run(aml_v4l2_vpp_thread, vpp, + "%s", "aml-v4l2-vpp"); + if (IS_ERR(vpp->task)) { + return PTR_ERR(vpp->task); + } + + sched_setscheduler_nocheck(vpp->task, SCHED_FIFO, ¶m); + + v4l_dbg(vpp->ctx, V4L_DEBUG_CODEC_PRINFO, "vpp wrapper reset.\n"); + + return 0; + +} +EXPORT_SYMBOL(aml_v4l2_vpp_reset); + +int aml_v4l2_vpp_init( + struct aml_vcodec_ctx *ctx, + struct aml_vpp_cfg_infos *cfg, + struct aml_v4l2_vpp** vpp_handle) +{ + struct di_init_parm init; + u32 buf_size; + int i, ret; + struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; + struct aml_v4l2_vpp *vpp; + u32 work_mode = cfg->mode; + + if (!cfg || work_mode > VPP_MODE_MAX || !ctx || !vpp_handle) + return -EINVAL; + if (cfg->fmt != V4L2_PIX_FMT_NV12 && cfg->fmt != V4L2_PIX_FMT_NV12M && + cfg->fmt != V4L2_PIX_FMT_NV21 && cfg->fmt != V4L2_PIX_FMT_NV21M) + return -EINVAL; + + vpp = kzalloc(sizeof(*vpp), GFP_KERNEL); + if (!vpp) + return -ENOMEM; + + vpp->work_mode = work_mode; + if (vpp->work_mode >= VPP_MODE_DI_LOCAL && + vpp->work_mode <= VPP_MODE_NOISE_REDUC_LOCAL) + vpp->buffer_mode = BUFFER_MODE_ALLOC_BUF; + else + vpp->buffer_mode = BUFFER_MODE_USE_BUF; + + init.work_mode = WORK_MODE_PRE_POST; + init.buffer_mode = vpp->buffer_mode; + init.ops.fill_output_done = v4l_vpp_fill_output_done; + init.ops.empty_input_done = v4l_vpp_empty_input_done; + init.caller_data = (void *)vpp; + + if (vpp->buffer_mode == BUFFER_MODE_ALLOC_BUF) { + init.ops.fill_output_done = + v4l_vpp_fill_output_done_alloc_buffer; + } + + if (vpp->buffer_mode == BUFFER_MODE_ALLOC_BUF) + init.output_format = DI_OUTPUT_BY_DI_DEFINE; + else if ((vpp->buffer_mode == BUFFER_MODE_USE_BUF) && + ((cfg->fmt == V4L2_PIX_FMT_NV21M) || (cfg->fmt == V4L2_PIX_FMT_NV21))) + init.output_format = DI_OUTPUT_NV21 | DI_OUTPUT_LINEAR; + else if ((vpp->buffer_mode == BUFFER_MODE_USE_BUF) && + ((cfg->fmt == V4L2_PIX_FMT_NV12M) || (cfg->fmt == V4L2_PIX_FMT_NV12))) + init.output_format = DI_OUTPUT_NV12 | DI_OUTPUT_LINEAR; + else /* AFBC deocde case, NV12 as default */ + init.output_format = DI_OUTPUT_NV12 | DI_OUTPUT_LINEAR; + + if (cfg->is_drm) + init.output_format |= DI_OUTPUT_TVP; + + vpp->di_handle = di_create_instance(init); + if (vpp->di_handle < 0) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "di_create_instance fail\n"); + ret = -EINVAL; + goto error; + } + + INIT_KFIFO(vpp->input); + INIT_KFIFO(vpp->output); + INIT_KFIFO(vpp->frame); + INIT_KFIFO(vpp->out_done_q); + INIT_KFIFO(vpp->in_done_q); + INIT_KFIFO(vpp->processing); + + vpp->ctx = ctx; + vpp->is_prog = cfg->is_prog; + vpp->is_bypass_p = cfg->is_bypass_p; + + buf_size = vpp->is_prog ? 16 : cfg->buf_size; + vpp->buf_size = buf_size; + + /* setup output fifo */ + ret = kfifo_alloc(&vpp->output, buf_size, GFP_KERNEL); + if (ret) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "alloc output fifo fail.\n"); + ret = -ENOMEM; + goto error2; + } + + vpp->ovbpool = vzalloc(buf_size * sizeof(*vpp->ovbpool)); + if (!vpp->ovbpool) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "alloc output vb pool fail.\n"); + ret = -ENOMEM; + goto error3; + } + + /* setup vframe fifo */ + ret = kfifo_alloc(&vpp->frame, buf_size, GFP_KERNEL); + if (ret) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "alloc vpp vframe fifo fail.\n"); + ret = -ENOMEM; + goto error4; + } + + vpp->vfpool = vzalloc(buf_size * sizeof(*vpp->vfpool)); + if (!vpp->vfpool) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "alloc vf pool fail.\n"); + ret = -ENOMEM; + goto error5; + } + + /* setup processing fifo */ + ret = kfifo_alloc(&vpp->processing, buf_size, GFP_KERNEL); + if (ret) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "alloc processing fifo fail.\n"); + ret = -ENOMEM; + goto error6; + } + + ret = kfifo_alloc(&vpp->input, VPP_FRAME_SIZE, GFP_KERNEL); + if (ret) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "alloc input fifo fail.\n"); + ret = -ENOMEM; + goto error7; + } + + vpp->ivbpool = vzalloc(VPP_FRAME_SIZE * sizeof(*vpp->ivbpool)); + if (!vpp->ivbpool) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "alloc input vb pool fail.\n"); + ret = -ENOMEM; + goto error8; + } + + for (i = 0 ; i < VPP_FRAME_SIZE ; i++) { + kfifo_put(&vpp->input, &vpp->ivbpool[i]); + } + + for (i = 0 ; i < buf_size ; i++) { + kfifo_put(&vpp->output, &vpp->ovbpool[i]); + kfifo_put(&vpp->frame, &vpp->vfpool[i]); + } + + mutex_init(&vpp->output_lock); + sema_init(&vpp->sem_in, 0); + sema_init(&vpp->sem_out, 0); + + vpp->running = true; + vpp->task = kthread_run(aml_v4l2_vpp_thread, vpp, + "aml-%s", "aml-v4l2-vpp"); + if (IS_ERR(vpp->task)) { + ret = PTR_ERR(vpp->task); + goto error9; + } + sched_setscheduler_nocheck(vpp->task, SCHED_FIFO, ¶m); + + vpp->di_ibuf_num = di_get_input_buffer_num(vpp->di_handle); + vpp->di_obuf_num = di_get_output_buffer_num(vpp->di_handle); + + *vpp_handle = vpp; + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, + "vpp_wrapper init bsize:%d, di(i:%d, o:%d), wkm:%x, bm:%x, fmt:%x, drm:%d, prog:%d, byp:%d, local:%d, NR:%d\n", + vpp->buf_size, + vpp->di_ibuf_num, + vpp->di_obuf_num, + vpp->work_mode, + vpp->buffer_mode, + init.output_format, + cfg->is_drm, + cfg->is_prog, + cfg->is_bypass_p, + cfg->enable_local_buf, + cfg->enable_nr); + + return 0; + +error9: + vfree(vpp->ivbpool); +error8: + kfifo_free(&vpp->input); +error7: + kfifo_free(&vpp->processing); +error6: + vfree(vpp->vfpool); +error5: + kfifo_free(&vpp->frame); +error4: + vfree(vpp->ovbpool); +error3: + kfifo_free(&vpp->output); +error2: + di_destroy_instance(vpp->di_handle); +error: + kfree(vpp); + return ret; +} +EXPORT_SYMBOL(aml_v4l2_vpp_init); + +int aml_v4l2_vpp_destroy(struct aml_v4l2_vpp* vpp) +{ + v4l_dbg(vpp->ctx, V4L_DEBUG_VPP_DETAIL, + "vpp destroy begin\n"); + vpp->running = false; + up(&vpp->sem_in); + up(&vpp->sem_out); + kthread_stop(vpp->task); + + di_destroy_instance(vpp->di_handle); + /* no more vpp callback below this line */ + + if (vpp->buffer_mode == BUFFER_MODE_ALLOC_BUF) + release_DI_buff(vpp); + + kfifo_free(&vpp->processing); + kfifo_free(&vpp->frame); + vfree(vpp->vfpool); + kfifo_free(&vpp->output); + vfree(vpp->ovbpool); + kfifo_free(&vpp->input); + vfree(vpp->ivbpool); + mutex_destroy(&vpp->output_lock); + v4l_dbg(vpp->ctx, V4L_DEBUG_VPP_DETAIL, + "vpp_wrapper destroy done\n"); + kfree(vpp); + + return 0; +} +EXPORT_SYMBOL(aml_v4l2_vpp_destroy); + +static int aml_v4l2_vpp_push_vframe(struct aml_v4l2_vpp* vpp, struct vframe_s *vf) +{ + struct aml_v4l2_vpp_buf *in_buf; + struct vdec_v4l2_buffer *fb = NULL; + + if (!vpp) + return -EINVAL; + + if (!kfifo_get(&vpp->input, &in_buf)) { + v4l_dbg(vpp->ctx, V4L_DEBUG_CODEC_ERROR, + "cat not get free input buffer.\n"); + return -1; + } + +#if 0 //to debug di by frame + if (vpp->in_num[INPUT_PORT] > 2) + return 0; + if (vpp->in_num[INPUT_PORT] == 2) + vf->type |= VIDTYPE_V4L_EOS; +#endif + + in_buf->di_buf.vf = vf; + in_buf->di_buf.flag = 0; + if (vf->type & VIDTYPE_V4L_EOS) { + u32 dw_mode = VDEC_DW_NO_AFBC; + + in_buf->di_buf.flag |= DI_FLAG_EOS; + + if (vdec_if_get_param(vpp->ctx, GET_PARAM_DW_MODE, &dw_mode)) + return -1; + + vf->type |= vpp->ctx->vpp_cfg.is_prog ? + VIDTYPE_PROGRESSIVE : + VIDTYPE_INTERLACE; + + if (dw_mode != VDEC_DW_NO_AFBC) + vf->type |= VIDTYPE_COMPRESS; + } + + fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; + in_buf->aml_buf = container_of(fb, struct aml_video_dec_buf, frame_buffer); + + if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T7) { + if (vf->canvas0_config[0].block_mode == CANVAS_BLKMODE_LINEAR) { + if ((vpp->ctx->output_pix_fmt != V4L2_PIX_FMT_H264) && + (vpp->ctx->output_pix_fmt != V4L2_PIX_FMT_MPEG1) && + (vpp->ctx->output_pix_fmt != V4L2_PIX_FMT_MPEG2) && + (vpp->ctx->output_pix_fmt != V4L2_PIX_FMT_MPEG4) && + (vpp->ctx->output_pix_fmt != V4L2_PIX_FMT_MJPEG)) { + vf->flag |= VFRAME_FLAG_VIDEO_LINEAR; + } + else { + if (fb->status == FB_ST_GE2D) + vf->flag |= VFRAME_FLAG_VIDEO_LINEAR; + } + } + } else { + if (vf->canvas0_config[0].block_mode == CANVAS_BLKMODE_LINEAR) + vf->flag |= VFRAME_FLAG_VIDEO_LINEAR; + } + + v4l_dbg(vpp->ctx, V4L_DEBUG_VPP_BUFMGR, + "vpp_push_vframe: idx:%d, vf:%px, idx:%d, type:%x, ts:%lld\n", + fb->buf_idx, vf, vf->index, vf->type, vf->timestamp); + + do { + unsigned int dw_mode = VDEC_DW_NO_AFBC; + struct file *fp; + + if (!dump_vpp_input || vpp->ctx->is_drm_mode) + break; + if (vdec_if_get_param(vpp->ctx, GET_PARAM_DW_MODE, &dw_mode)) + break; + if (dw_mode == VDEC_DW_AFBC_ONLY) + break; + + fp = filp_open("/data/dec_dump_before.raw", + O_CREAT | O_RDWR | O_LARGEFILE | O_APPEND, 0600); + if (!IS_ERR(fp)) { + struct vb2_buffer *vb = &in_buf->aml_buf->vb.vb2_buf; + + kernel_write(fp,vb2_plane_vaddr(vb, 0),vb->planes[0].length, 0); + if (in_buf->aml_buf->frame_buffer.num_planes == 2) + kernel_write(fp,vb2_plane_vaddr(vb, 1), + vb->planes[1].length, 0); + dump_vpp_input--; + filp_close(fp, NULL); + } + } while(0); + + ATRACE_COUNTER("VC_OUT_VPP-0.receive", fb->buf_idx); + + kfifo_put(&vpp->in_done_q, in_buf); + up(&vpp->sem_in); + + return 0; +} + +static void fill_vpp_buf_cb(void *v4l_ctx, void *fb_ctx) +{ + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)v4l_ctx; + struct vdec_v4l2_buffer *fb = + (struct vdec_v4l2_buffer *)fb_ctx; + int ret = -1; + + ret = aml_v4l2_vpp_push_vframe(ctx->vpp, fb->vframe); + if (ret < 0) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "vpp push vframe err, ret: %d\n", ret); + } +} + +static struct task_ops_s vpp_ops = { + .type = TASK_TYPE_VPP, + .get_vframe = vpp_vf_get, + .put_vframe = vpp_vf_put, + .fill_buffer = fill_vpp_buf_cb, +}; + +struct task_ops_s *get_vpp_ops(void) +{ + return &vpp_ops; +} +EXPORT_SYMBOL(get_vpp_ops); +
diff --git a/drivers/amvdec_ports/aml_vcodec_vpp.h b/drivers/amvdec_ports/aml_vcodec_vpp.h new file mode 100644 index 0000000..7a5771d --- /dev/null +++ b/drivers/amvdec_ports/aml_vcodec_vpp.h
@@ -0,0 +1,112 @@ +/* +* Copyright (C) 2020 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. +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, write to the Free Software Foundation, Inc., +* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +* Description: +*/ +#ifndef _AML_VCODEC_VPP_H_ +#define _AML_VCODEC_VPP_H_ + +#define SUPPORT_V4L_VPP + +#include <linux/kfifo.h> +#ifdef SUPPORT_V4L_VPP +#include <linux/amlogic/media/di/di_interface.h> +#endif +#include "aml_vcodec_drv.h" +#include "aml_vcodec_dec.h" + +enum vpp_work_mode { + VPP_MODE_DI, + VPP_MODE_COLOR_CONV, + VPP_MODE_NOISE_REDUC, + VPP_MODE_DI_LOCAL = 0x81, + VPP_MODE_COLOR_CONV_LOCAL = 0x82, + VPP_MODE_NOISE_REDUC_LOCAL = 0x83, + VPP_MODE_MAX = 0xff +}; + +#define VPP_FRAME_SIZE 64 + +struct aml_v4l2_vpp_buf { +#ifdef SUPPORT_V4L_VPP + struct di_buffer di_buf; + struct di_buffer *di_local_buf; +#endif + struct aml_video_dec_buf *aml_buf; + struct aml_v4l2_vpp_buf *inbuf; +}; + +struct aml_v4l2_vpp { + int di_handle; /* handle of DI */ + struct aml_vcodec_ctx *ctx; + u32 buf_size; /* buffer size for vpp */ + u32 work_mode; /* enum vpp_work_mode */ + u32 buffer_mode; + + DECLARE_KFIFO_PTR(input, typeof(struct aml_v4l2_vpp_buf*)); + DECLARE_KFIFO_PTR(output, typeof(struct aml_v4l2_vpp_buf*)); + DECLARE_KFIFO_PTR(processing, typeof(struct aml_v4l2_vpp_buf*)); + DECLARE_KFIFO_PTR(frame, typeof(struct vframe_s *)); + DECLARE_KFIFO(out_done_q, struct aml_v4l2_vpp_buf *, VPP_FRAME_SIZE); + DECLARE_KFIFO(in_done_q, struct aml_v4l2_vpp_buf *, VPP_FRAME_SIZE); + + struct vframe_s *vfpool; + struct aml_v4l2_vpp_buf *ovbpool; + struct aml_v4l2_vpp_buf *ivbpool; + struct task_struct *task; + bool running; + struct semaphore sem_in, sem_out; + + /* In p to i transition, output/frame can be multi writer */ + struct mutex output_lock; + + /* for debugging */ + /* + * in[0] --> vpp <-- in[1] + * out[0]<-- vpp --> out[1] + */ + int in_num[2]; + int out_num[2]; + ulong fb_token; + + bool is_prog; + bool is_bypass_p; + int di_ibuf_num; + int di_obuf_num; +}; + +struct task_ops_s *get_vpp_ops(void); + +#ifdef SUPPORT_V4L_VPP +/* get number of buffer needed for a working mode */ +int aml_v4l2_vpp_get_buf_num(u32 mode); +int aml_v4l2_vpp_init( + struct aml_vcodec_ctx *ctx, + struct aml_vpp_cfg_infos *cfg, + struct aml_v4l2_vpp** vpp_handle); +int aml_v4l2_vpp_destroy(struct aml_v4l2_vpp* vpp); +int aml_v4l2_vpp_reset(struct aml_v4l2_vpp *vpp); +#else +static inline int aml_v4l2_vpp_get_buf_num(u32 mode) { return -1; } +static inline int aml_v4l2_vpp_init( + struct aml_vcodec_ctx *ctx, + struct aml_vpp_cfg_infos *cfg, + struct aml_v4l2_vpp** vpp_handle) { return -1; } +static inline int aml_v4l2_vpp_destroy(struct aml_v4l2_vpp* vpp) { return -1; } +#endif + +#endif
diff --git a/drivers/amvdec_ports/decoder/aml_h264_parser.c b/drivers/amvdec_ports/decoder/aml_h264_parser.c index c9da299..d0d0198 100644 --- a/drivers/amvdec_ports/decoder/aml_h264_parser.c +++ b/drivers/amvdec_ports/decoder/aml_h264_parser.c
@@ -1,22 +1,3 @@ -/* -* Copyright (C) 2017 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. -* -* You should have received a copy of the GNU General Public License along -* with this program; if not, write to the Free Software Foundation, Inc., -* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -* -* Description: -*/ #include <linux/kernel.h> #include <linux/types.h> #include <linux/vmalloc.h>
diff --git a/drivers/amvdec_ports/decoder/aml_hevc_parser.c b/drivers/amvdec_ports/decoder/aml_hevc_parser.c index 4ea76b9..24977a8 100644 --- a/drivers/amvdec_ports/decoder/aml_hevc_parser.c +++ b/drivers/amvdec_ports/decoder/aml_hevc_parser.c
@@ -1,22 +1,3 @@ -/* -* Copyright (C) 2017 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. -* -* You should have received a copy of the GNU General Public License along -* with this program; if not, write to the Free Software Foundation, Inc., -* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -* -* Description: -*/ #include <linux/kernel.h> #include <linux/types.h> #include <linux/vmalloc.h>
diff --git a/drivers/amvdec_ports/decoder/aml_hevc_parser.h b/drivers/amvdec_ports/decoder/aml_hevc_parser.h index 0c81cb5..9223639 100644 --- a/drivers/amvdec_ports/decoder/aml_hevc_parser.h +++ b/drivers/amvdec_ports/decoder/aml_hevc_parser.h
@@ -22,7 +22,6 @@ #include "../aml_vcodec_drv.h" #include "../utils/common.h" - #define MAX_DPB_SIZE 16 // A.4.1 #define MAX_REFS 16
diff --git a/drivers/amvdec_ports/decoder/aml_mjpeg_parser.c b/drivers/amvdec_ports/decoder/aml_mjpeg_parser.c index fd56755..c582ab0 100644 --- a/drivers/amvdec_ports/decoder/aml_mjpeg_parser.c +++ b/drivers/amvdec_ports/decoder/aml_mjpeg_parser.c
@@ -1,22 +1,3 @@ -/* -* Copyright (C) 2017 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. -* -* You should have received a copy of the GNU General Public License along -* with this program; if not, write to the Free Software Foundation, Inc., -* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -* -* Description: -*/ #include <linux/kernel.h> #include <linux/types.h> #include <linux/vmalloc.h>
diff --git a/drivers/amvdec_ports/decoder/aml_mjpeg_parser.h b/drivers/amvdec_ports/decoder/aml_mjpeg_parser.h index bbc9282..4704ba0 100644 --- a/drivers/amvdec_ports/decoder/aml_mjpeg_parser.h +++ b/drivers/amvdec_ports/decoder/aml_mjpeg_parser.h
@@ -1,19 +1,3 @@ -/* - * drivers/amvdec_ports/decoder/aml_mjpeg_parser.h - * - * Copyright (C) 2015 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 AML_MJPEG_PARSER_H #define AML_MJPEG_PARSER_H
diff --git a/drivers/amvdec_ports/decoder/aml_mpeg12_parser.c b/drivers/amvdec_ports/decoder/aml_mpeg12_parser.c index 2720446..748a83f 100644 --- a/drivers/amvdec_ports/decoder/aml_mpeg12_parser.c +++ b/drivers/amvdec_ports/decoder/aml_mpeg12_parser.c
@@ -1,22 +1,3 @@ -/* -* Copyright (C) 2017 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. -* -* You should have received a copy of the GNU General Public License along -* with this program; if not, write to the Free Software Foundation, Inc., -* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -* -* Description: -*/ #include <linux/kernel.h> #include <linux/types.h> #include <linux/vmalloc.h>
diff --git a/drivers/amvdec_ports/decoder/aml_mpeg12_parser.h b/drivers/amvdec_ports/decoder/aml_mpeg12_parser.h index 8abbc78..c06d632 100644 --- a/drivers/amvdec_ports/decoder/aml_mpeg12_parser.h +++ b/drivers/amvdec_ports/decoder/aml_mpeg12_parser.h
@@ -1,19 +1,3 @@ -/* - * drivers/amvdec_ports/decoder/aml_mpeg12_parser.h - * - * Copyright (C) 2015 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 AML_MPEG12_PARSER_H #define AML_MPEG12_PARSER_H @@ -23,7 +7,6 @@ #include "../utils/pixfmt.h" #endif - /* Start codes. */ #define SEQ_END_CODE 0x000001b7 #define SEQ_START_CODE 0x000001b3
diff --git a/drivers/amvdec_ports/decoder/aml_mpeg4_parser.c b/drivers/amvdec_ports/decoder/aml_mpeg4_parser.c index f680b12..9c47c08 100644 --- a/drivers/amvdec_ports/decoder/aml_mpeg4_parser.c +++ b/drivers/amvdec_ports/decoder/aml_mpeg4_parser.c
@@ -1,22 +1,3 @@ -/* -* Copyright (C) 2017 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. -* -* You should have received a copy of the GNU General Public License along -* with this program; if not, write to the Free Software Foundation, Inc., -* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -* -* Description: -*/ #include <linux/kernel.h> #include <linux/types.h> #include <linux/vmalloc.h>
diff --git a/drivers/amvdec_ports/decoder/aml_mpeg4_parser.h b/drivers/amvdec_ports/decoder/aml_mpeg4_parser.h index 3e5bf62..f9b71cf 100644 --- a/drivers/amvdec_ports/decoder/aml_mpeg4_parser.h +++ b/drivers/amvdec_ports/decoder/aml_mpeg4_parser.h
@@ -1,19 +1,3 @@ -/* - * drivers/amvdec_ports/decoder/aml_mpeg4_parser.h - * - * Copyright (C) 2015 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 AVCODEC_MPEG4VIDEO_H #define AVCODEC_MPEG4VIDEO_H
diff --git a/drivers/amvdec_ports/decoder/aml_vp9_parser.c b/drivers/amvdec_ports/decoder/aml_vp9_parser.c index b027b8a..21d5283 100644 --- a/drivers/amvdec_ports/decoder/aml_vp9_parser.c +++ b/drivers/amvdec_ports/decoder/aml_vp9_parser.c
@@ -1,22 +1,3 @@ -/* -* Copyright (C) 2017 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. -* -* You should have received a copy of the GNU General Public License along -* with this program; if not, write to the Free Software Foundation, Inc., -* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -* -* Description: -*/ #include <linux/kernel.h> #include <linux/types.h> #include <linux/vmalloc.h>
diff --git a/drivers/amvdec_ports/decoder/vdec_av1_if.c b/drivers/amvdec_ports/decoder/vdec_av1_if.c index e8693d4..c28ca10 100644 --- a/drivers/amvdec_ports/decoder/vdec_av1_if.c +++ b/drivers/amvdec_ports/decoder/vdec_av1_if.c
@@ -29,7 +29,6 @@ #include "../aml_vcodec_drv.h" #include "../aml_vcodec_adapt.h" #include "../vdec_drv_base.h" -#include "../aml_vcodec_vfm.h" #include "../utils/common.h" #define KERNEL_ATRACE_TAG KERNEL_ATRACE_TAG_V4L2 @@ -118,9 +117,9 @@ struct aml_vcodec_ctx *ctx; struct aml_vdec_adapt vdec; struct vdec_av1_vsi *vsi; - struct vcodec_vfm_s vfm; struct aml_dec_params parms; struct completion comp; + struct vdec_comp_buf_info comp_info; }; /*!\brief OBU types. */ @@ -207,6 +206,7 @@ static int vdec_write_nalu(struct vdec_av1_inst *inst, u8 *buf, u32 size, u64 ts); +static int vdec_get_dw_mode(struct vdec_av1_inst *inst, int dw_mode); static void get_pic_info(struct vdec_av1_inst *inst, struct vdec_pic_info *pic) @@ -246,12 +246,12 @@ u8 *pbuf = parm; pbuf += sprintf(pbuf, "parm_v4l_codec_enable:1;"); - pbuf += sprintf(pbuf, "parm_v4l_buffer_margin:11;"); - pbuf += sprintf(pbuf, "av1_double_write_mode:3;"); + pbuf += sprintf(pbuf, "parm_v4l_buffer_margin:7;"); + pbuf += sprintf(pbuf, "av1_double_write_mode:1;"); pbuf += sprintf(pbuf, "av1_buf_width:1920;"); pbuf += sprintf(pbuf, "av1_buf_height:1088;"); - pbuf += sprintf(pbuf, "av1_max_pic_w:8192;"); - pbuf += sprintf(pbuf, "av1_max_pic_h:4608;"); + pbuf += sprintf(pbuf, "av1_max_pic_w:4096;"); + pbuf += sprintf(pbuf, "av1_max_pic_h:2304;"); pbuf += sprintf(pbuf, "save_buffer_mode:0;"); pbuf += sprintf(pbuf, "no_head:0;"); pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_mode:0;"); @@ -264,6 +264,10 @@ { struct aml_vcodec_ctx *ctx = inst->ctx; + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + "%s:parms_status = 0x%x, present_flag = %d\n", + __func__, ctx->config.parm.dec.parms_status, + ctx->config.parm.dec.hdr.color_parms.present_flag); if (ctx->config.parm.dec.parms_status & V4L2_CONFIG_PARM_DECODE_CFGINFO) { u8 *pbuf = ctx->config.buf; @@ -273,10 +277,8 @@ ctx->config.parm.dec.cfg.ref_buf_margin); pbuf += sprintf(pbuf, "av1_double_write_mode:%d;", ctx->config.parm.dec.cfg.double_write_mode); - pbuf += sprintf(pbuf, "av1_buf_width:%d;", - ctx->config.parm.dec.cfg.init_width); - pbuf += sprintf(pbuf, "av1_buf_height:%d;", - ctx->config.parm.dec.cfg.init_height); + pbuf += sprintf(pbuf, "av1_buf_width:1920;"); + pbuf += sprintf(pbuf, "av1_buf_height:1088;"); pbuf += sprintf(pbuf, "save_buffer_mode:0;"); pbuf += sprintf(pbuf, "no_head:0;"); pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_mode:%d;", @@ -285,19 +287,23 @@ ctx->config.parm.dec.cfg.canvas_mem_endian); pbuf += sprintf(pbuf, "parm_v4l_low_latency_mode:%d;", ctx->config.parm.dec.cfg.low_latency_mode); + pbuf += sprintf(pbuf, "parm_v4l_duration:%d;", + ctx->config.parm.dec.cfg.duration); ctx->config.length = pbuf - ctx->config.buf; } else { - ctx->config.parm.dec.cfg.double_write_mode = 16; + ctx->config.parm.dec.cfg.double_write_mode = 1; ctx->config.parm.dec.cfg.ref_buf_margin = 7; ctx->config.length = vdec_config_default_parms(ctx->config.buf); } if ((ctx->config.parm.dec.parms_status & V4L2_CONFIG_PARM_DECODE_HDRINFO) && - inst->parms.hdr.color_parms.present_flag) { + ctx->config.parm.dec.hdr.color_parms.present_flag) { u8 *pbuf = ctx->config.buf + ctx->config.length; pbuf += sprintf(pbuf, "HDRStaticInfo:%d;", 1); + pbuf += sprintf(pbuf, "signal_type:%d;", + ctx->config.parm.dec.hdr.signal_type); pbuf += sprintf(pbuf, "mG.x:%d;", ctx->config.parm.dec.hdr.color_parms.primaries[0][0]); pbuf += sprintf(pbuf, "mG.y:%d;", @@ -326,6 +332,8 @@ inst->parms.hdr = ctx->config.parm.dec.hdr; inst->parms.parms_status |= V4L2_CONFIG_PARM_DECODE_HDRINFO; } + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + "config.buf = %s\n", ctx->config.buf); inst->vdec.config = ctx->config; inst->parms.cfg = ctx->config.parm.dec.cfg; @@ -341,6 +349,7 @@ if (!inst) return -ENOMEM; + inst->vdec.frm_name = "AV1"; inst->vdec.video_type = VFORMAT_AV1; inst->vdec.filp = ctx->dev->filp; inst->vdec.ctx = ctx; @@ -355,16 +364,6 @@ /* to eable av1 hw.*/ inst->vdec.port.type = PORT_TYPE_HEVC; - /* init vfm */ - inst->vfm.ctx = ctx; - inst->vfm.ada_ctx = &inst->vdec; - ret = vcodec_vfm_init(&inst->vfm); - if (ret) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "init vfm failed.\n"); - goto err; - } - /* probe info from the stream */ inst->vsi = kzalloc(sizeof(struct vdec_av1_vsi), GFP_KERNEL); if (!inst->vsi) { @@ -373,7 +372,7 @@ } /* alloc the header buffer to be used cache sps or spp etc.*/ - inst->vsi->header_buf = kzalloc(HEADER_BUFFER_SIZE, GFP_KERNEL); + inst->vsi->header_buf = vzalloc(HEADER_BUFFER_SIZE); if (!inst->vsi->header_buf) { ret = -ENOMEM; goto err; @@ -381,9 +380,6 @@ init_completion(&inst->comp); - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, - "av1 Instance >> %lx\n", (ulong) inst); - ctx->ada_ctx = &inst->vdec; *h_vdec = (unsigned long)inst; @@ -395,14 +391,13 @@ goto err; } - //dump_init(); + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + "av1 Instance >> %lx\n", (ulong) inst); return 0; err: - if (inst) - vcodec_vfm_release(&inst->vfm); if (inst && inst->vsi && inst->vsi->header_buf) - kfree(inst->vsi->header_buf); + vfree(inst->vsi->header_buf); if (inst && inst->vsi) kfree(inst->vsi); if (inst) @@ -428,7 +423,7 @@ wait_for_completion_timeout(&inst->comp, msecs_to_jiffies(1000)); - return inst->vsi->dec.dpb_sz ? 0 : -1; + return inst->vsi->pic.dpb_frames ? 0 : -1; } static int parse_stream_ucode_dma(struct vdec_av1_inst *inst, @@ -449,7 +444,7 @@ wait_for_completion_timeout(&inst->comp, msecs_to_jiffies(1000)); - return inst->vsi->dec.dpb_sz ? 0 : -1; + return inst->vsi->pic.dpb_frames ? 0 : -1; } static int parse_stream_cpu(struct vdec_av1_inst *inst, u8 *buf, u32 size) @@ -504,19 +499,13 @@ static void vdec_av1_deinit(unsigned long h_vdec) { - ulong flags; struct vdec_av1_inst *inst = (struct vdec_av1_inst *)h_vdec; struct aml_vcodec_ctx *ctx = inst->ctx; video_decoder_release(&inst->vdec); - vcodec_vfm_release(&inst->vfm); - - //dump_deinit(); - - spin_lock_irqsave(&ctx->slock, flags); if (inst->vsi && inst->vsi->header_buf) - kfree(inst->vsi->header_buf); + vfree(inst->vsi->header_buf); if (inst->vsi) kfree(inst->vsi); @@ -524,42 +513,6 @@ kfree(inst); ctx->drv_handle = 0; - spin_unlock_irqrestore(&ctx->slock, flags); -} - -static int vdec_av1_get_fb(struct vdec_av1_inst *inst, struct vdec_v4l2_buffer **out) -{ - return get_fb_from_queue(inst->ctx, out); -} - -static void vdec_av1_get_vf(struct vdec_av1_inst *inst, struct vdec_v4l2_buffer **out) -{ - struct vframe_s *vf = NULL; - struct vdec_v4l2_buffer *fb = NULL; - - vf = peek_video_frame(&inst->vfm); - if (!vf) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "there is no vframe.\n"); - *out = NULL; - return; - } - - vf = get_video_frame(&inst->vfm); - if (!vf) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "the vframe is avalid.\n"); - *out = NULL; - return; - } - - atomic_set(&vf->use_cnt, 1); - - fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; - fb->vf_handle = (unsigned long)vf; - fb->status = FB_ST_DISPLAY; - - *out = fb; } // Returns 1 when OBU type is valid, and 0 otherwise. @@ -636,7 +589,7 @@ int i; const size_t leb_size = uleb_size_in_bytes(value); - if (leb_size > kMaximumLeb128Size || + if (value > kMaximumLeb128Value || leb_size > kMaximumLeb128Size || leb_size > available || !coded_value || !coded_size) { return -1; } @@ -704,13 +657,12 @@ static int read_obu_header(struct read_bit_buffer *rb, int is_annexb, struct ObuHeader *header) { - int bit_buffer_byte_length; + const int bit_buffer_byte_length = + rb->bit_buffer_end - rb->bit_buffer; if (!rb || !header) return -1; - bit_buffer_byte_length = rb->bit_buffer_end - rb->bit_buffer; - if (bit_buffer_byte_length < 1) return -1; @@ -1048,13 +1000,13 @@ parser_frame(0, src, src + size, data, &length, meta_buffer, &meta_size); if (length) - ret = vdec_vframe_write(vdec, data, length, ts); + ret = vdec_vframe_write(vdec, data, length, ts, 0); else ret = -1; vfree(data); } else { - ret = vdec_vframe_write(vdec, buf, size, ts); + ret = vdec_vframe_write(vdec, buf, size, ts, 0); } return ret; @@ -1088,18 +1040,14 @@ { struct vdec_av1_inst *inst = (struct vdec_av1_inst *)h_vdec; struct aml_vdec_adapt *vdec = &inst->vdec; - u8 *buf; - u32 size; + u8 *buf = (u8 *) bs->vaddr; + u32 size = bs->size; int ret = -1; if (bs == NULL) return -1; - buf = (u8 *) bs->vaddr; - size = bs->size; - if (vdec_input_full(vdec)) { - ATRACE_COUNTER("vdec_input_full", 0); return -EAGAIN; } @@ -1121,7 +1069,8 @@ ret = vdec_vframe_write(vdec, s->data, s->len, - bs->timestamp); + bs->timestamp, + 0); } else if (bs->model == VB2_MEMORY_DMABUF || bs->model == VB2_MEMORY_USERPTR) { ret = vdec_vframe_write_with_dma(vdec, @@ -1137,7 +1086,6 @@ ret = vdec_write_nalu(inst, buf, size, bs->timestamp); } - ATRACE_COUNTER("v4l2_decode_write", ret); return ret; } @@ -1145,8 +1093,12 @@ static void get_param_config_info(struct vdec_av1_inst *inst, struct aml_dec_params *parms) { - if (inst->parms.parms_status & V4L2_CONFIG_PARM_DECODE_CFGINFO) - parms->cfg = inst->parms.cfg; + if (inst->parms.parms_status & V4L2_CONFIG_PARM_DECODE_CFGINFO) { + /* dw use v4l cfg */ + inst->parms.cfg.double_write_mode = + inst->ctx->config.parm.dec.cfg.double_write_mode; + parms->cfg = inst->parms.cfg; + } if (inst->parms.parms_status & V4L2_CONFIG_PARM_DECODE_PSINFO) parms->ps = inst->parms.ps; if (inst->parms.parms_status & V4L2_CONFIG_PARM_DECODE_HDRINFO) @@ -1156,10 +1108,16 @@ parms->parms_status |= inst->parms.parms_status; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "parms status: %u\n", parms->parms_status); } +static void get_param_comp_buf_info(struct vdec_av1_inst *inst, + struct vdec_comp_buf_info *params) +{ + memcpy(params, &inst->comp_info, sizeof(*params)); +} + static int vdec_av1_get_param(unsigned long h_vdec, enum vdec_get_param_type type, void *out) { @@ -1167,20 +1125,12 @@ struct vdec_av1_inst *inst = (struct vdec_av1_inst *)h_vdec; if (!inst) { - v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "the av1 inst of dec is invalid.\n"); return -1; } switch (type) { - case GET_PARAM_DISP_FRAME_BUFFER: - vdec_av1_get_vf(inst, out); - break; - - case GET_PARAM_FREE_FRAME_BUFFER: - ret = vdec_av1_get_fb(inst, out); - break; - case GET_PARAM_PIC_INFO: get_pic_info(inst, out); break; @@ -1197,6 +1147,20 @@ get_param_config_info(inst, out); break; + case GET_PARAM_DW_MODE: + { + u32 *mode = out; + u32 m = inst->ctx->config.parm.dec.cfg.double_write_mode; + if (m <= 16) + *mode = inst->ctx->config.parm.dec.cfg.double_write_mode; + else + *mode = vdec_get_dw_mode(inst, 0); + break; + } + case GET_PARAM_COMP_BUF_INFO: + get_param_comp_buf_info(inst, out); + break; + default: v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "invalid get parameter type=%d\n", type); @@ -1211,12 +1175,69 @@ complete(&inst->comp); } +static int vdec_get_dw_mode(struct vdec_av1_inst *inst, int dw_mode) +{ + u32 valid_dw_mode = inst->ctx->config.parm.dec.cfg.double_write_mode; + int w = inst->vsi->pic.coded_width; + int h = inst->vsi->pic.coded_height; + u32 dw = 0x1; /*1:1*/ + + switch (valid_dw_mode) { + case 0x100: + if (w > 1920 && h > 1088) + dw = 0x4; /*1:2*/ + break; + case 0x200: + if (w > 1920 && h > 1088) + dw = 0x2; /*1:4*/ + break; + case 0x300: + if (w > 1280 && h > 720) + dw = 0x4; /*1:2*/ + break; + default: + dw = valid_dw_mode; + break; + } + + return dw; +} + +static int vdec_pic_scale(struct vdec_av1_inst *inst, int length, int dw_mode) +{ + int ret = 64; + + switch (vdec_get_dw_mode(inst, dw_mode)) { + case 0x0: /* only afbc, output afbc */ + case 0x21: /* only afbc, output afbc */ + ret = 64; + break; + case 0x1: /* afbc and (w x h), output YUV420 */ + ret = length; + break; + case 0x2: /* afbc and (w/4 x h/4), output YUV420 */ + case 0x3: /* afbc and (w/4 x h/4), output afbc and YUV420 */ + ret = length >> 2; + break; + case 0x4: /* afbc and (w/2 x h/2), output YUV420 */ + ret = length >> 1; + break; + case 0x10: /* (w x h), output YUV420-8bit) */ + default: + ret = length; + break; + } + + return ret; +} + static void set_param_ps_info(struct vdec_av1_inst *inst, struct aml_vdec_ps_infos *ps) { struct vdec_pic_info *pic = &inst->vsi->pic; struct vdec_av1_dec_info *dec = &inst->vsi->dec; struct v4l2_rect *rect = &inst->vsi->crop; + int dw = inst->parms.cfg.double_write_mode; /* fill visible area size that be used for EGL. */ pic->visible_width = ps->visible_width; @@ -1232,11 +1253,16 @@ pic->coded_width = ps->coded_width; pic->coded_height = ps->coded_height; - pic->y_len_sz = pic->coded_width * pic->coded_height; + pic->y_len_sz = ALIGN(vdec_pic_scale(inst, pic->coded_width, dw), 64) * + ALIGN(vdec_pic_scale(inst, pic->coded_height, dw), 64); pic->c_len_sz = pic->y_len_sz >> 1; /* calc DPB size */ + pic->dpb_frames = ps->dpb_frames; + pic->dpb_margin = ps->dpb_margin; + pic->vpp_margin = ps->dpb_margin; dec->dpb_sz = ps->dpb_size; + pic->field = ps->field; inst->parms.ps = *ps; inst->parms.parms_status |= @@ -1246,23 +1272,27 @@ complete(&inst->comp); v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, - "Parse from ucode, crop(%d x %d), coded(%d x %d) dpb: %d\n", + "Parse from ucode, visible(%d x %d), coded(%d x %d)\n", ps->visible_width, ps->visible_height, - ps->coded_width, ps->coded_height, - ps->dpb_size); + ps->coded_width, ps->coded_height); +} + +static void set_param_comp_buf_info(struct vdec_av1_inst *inst, + struct vdec_comp_buf_info *info) +{ + memcpy(&inst->comp_info, info, sizeof(*info)); } static void set_param_hdr_info(struct vdec_av1_inst *inst, struct aml_vdec_hdr_infos *hdr) { - if ((inst->parms.parms_status & - V4L2_CONFIG_PARM_DECODE_HDRINFO)) { + if (hdr->signal_type != 0) { inst->parms.hdr = *hdr; inst->parms.parms_status |= V4L2_CONFIG_PARM_DECODE_HDRINFO; aml_vdec_dispatch_event(inst->ctx, V4L2_EVENT_SRC_CH_HDRINFO); - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "av1 set HDR infos\n"); } } @@ -1274,6 +1304,12 @@ "av1 post event: %d\n", *event); } +static void set_pic_info(struct vdec_av1_inst *inst, + struct vdec_pic_info *pic) +{ + inst->vsi->pic = *pic; +} + static int vdec_av1_set_param(unsigned long h_vdec, enum vdec_set_param_type type, void *in) { @@ -1281,7 +1317,7 @@ struct vdec_av1_inst *inst = (struct vdec_av1_inst *)h_vdec; if (!inst) { - v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "the av1 inst of dec is invalid.\n"); return -1; } @@ -1295,6 +1331,10 @@ set_param_ps_info(inst, in); break; + case SET_PARAM_COMP_BUF_INFO: + set_param_comp_buf_info(inst, in); + break; + case SET_PARAM_HDR_INFO: set_param_hdr_info(inst, in); break; @@ -1302,6 +1342,11 @@ case SET_PARAM_POST_EVENT: set_param_post_event(inst, in); break; + + case SET_PARAM_PIC_INFO: + set_pic_info(inst, in); + break; + default: v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "invalid set parameter type=%d\n", type);
diff --git a/drivers/amvdec_ports/decoder/vdec_h264_if.c b/drivers/amvdec_ports/decoder/vdec_h264_if.c index d13fc34..911c91d 100644 --- a/drivers/amvdec_ports/decoder/vdec_h264_if.c +++ b/drivers/amvdec_ports/decoder/vdec_h264_if.c
@@ -30,7 +30,6 @@ #include "../aml_vcodec_drv.h" #include "../aml_vcodec_adapt.h" #include "../vdec_drv_base.h" -#include "../aml_vcodec_vfm.h" #include "aml_h264_parser.h" #include "../utils/common.h" @@ -150,7 +149,6 @@ struct aml_vcodec_mem mv_buf[H264_MAX_FB_NUM]; struct aml_vdec_adapt vdec; struct vdec_h264_vsi *vsi; - struct vcodec_vfm_s vfm; struct aml_dec_params parms; struct completion comp; }; @@ -281,6 +279,10 @@ ctx->config.parm.dec.cfg.canvas_mem_endian); pbuf += sprintf(pbuf, "parm_v4l_low_latency_mode:%d;", ctx->config.parm.dec.cfg.low_latency_mode); + pbuf += sprintf(pbuf, "parm_v4l_metadata_config_flag:%d;", + ctx->config.parm.dec.cfg.metadata_config_flag); + pbuf += sprintf(pbuf, "parm_v4l_duration:%d;", + ctx->config.parm.dec.cfg.duration); ctx->config.length = pbuf - ctx->config.buf; } else { ctx->config.parm.dec.cfg.double_write_mode = 16; @@ -297,14 +299,13 @@ { struct vdec_h264_inst *inst = NULL; int ret = -1; - bool dec_init = false; - inst = kzalloc(sizeof(*inst), GFP_KERNEL); + inst = vzalloc(sizeof(*inst)); if (!inst) return -ENOMEM; + inst->vdec.frm_name = "H.264"; inst->vdec.video_type = VFORMAT_H264; - inst->vdec.dev = ctx->dev->vpu_plat_dev; inst->vdec.filp = ctx->dev->filp; inst->vdec.ctx = ctx; inst->ctx = ctx; @@ -315,33 +316,15 @@ if (ctx->is_drm_mode) inst->vdec.port.flag |= PORT_FLAG_DRM; - /* init vfm */ - inst->vfm.ctx = ctx; - inst->vfm.ada_ctx = &inst->vdec; - ret = vcodec_vfm_init(&inst->vfm); - if (ret) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "init vfm failed.\n"); - goto err; - } - - ret = video_decoder_init(&inst->vdec); - if (ret) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "vdec_h264 init err=%d\n", ret); - goto err; - } - dec_init = true; - /* probe info from the stream */ - inst->vsi = kzalloc(sizeof(struct vdec_h264_vsi), GFP_KERNEL); + inst->vsi = vzalloc(sizeof(struct vdec_h264_vsi)); if (!inst->vsi) { ret = -ENOMEM; goto err; } /* alloc the header buffer to be used cache sps or spp etc.*/ - inst->vsi->header_buf = kzalloc(HEADER_BUFFER_SIZE, GFP_KERNEL); + inst->vsi->header_buf = vzalloc(HEADER_BUFFER_SIZE); if (!inst->vsi->header_buf) { ret = -ENOMEM; goto err; @@ -349,26 +332,27 @@ init_completion(&inst->comp); - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, - "H264 Instance >> %lx", (ulong) inst); - ctx->ada_ctx = &inst->vdec; *h_vdec = (unsigned long)inst; - //dump_init(); + ret = video_decoder_init(&inst->vdec); + if (ret) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "vdec_h264 init err=%d\n", ret); + goto err; + } + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + "H264 Instance >> %lx", (ulong) inst); return 0; err: - if (dec_init) - video_decoder_release(&inst->vdec); - if (inst) - vcodec_vfm_release(&inst->vfm); if (inst && inst->vsi && inst->vsi->header_buf) - kfree(inst->vsi->header_buf); + vfree(inst->vsi->header_buf); if (inst && inst->vsi) - kfree(inst->vsi); + vfree(inst->vsi); if (inst) - kfree(inst); + vfree(inst); *h_vdec = 0; return ret; @@ -497,7 +481,6 @@ pic->y_len_sz = pic->coded_width * pic->coded_height; pic->c_len_sz = pic->y_len_sz >> 1; pic->profile_idc = sps->profile_idc; - pic->ref_frame_count= sps->ref_frame_count; /* calc DPB size */ dec->dpb_sz = sps->num_reorder_frames + margin; @@ -509,7 +492,7 @@ inst->parms.ps.mb_width = sps->mb_width; inst->parms.ps.mb_height = sps->mb_height; inst->parms.ps.ref_frames = sps->ref_frame_count; - inst->parms.ps.reorder_frames = sps->num_reorder_frames; + inst->parms.ps.dpb_frames = sps->num_reorder_frames; inst->parms.ps.dpb_size = dec->dpb_sz; inst->parms.parms_status |= V4L2_CONFIG_PARM_DECODE_PSINFO; @@ -571,7 +554,7 @@ int ret = 0; struct aml_vdec_adapt *vdec = &inst->vdec; - ret = vdec_vframe_write(vdec, buf, size, timestamp); + ret = vdec_vframe_write(vdec, buf, size, timestamp, 0); if (ret < 0) { v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "write frame data failed. err: %d\n", ret); @@ -582,7 +565,7 @@ wait_for_completion_timeout(&inst->comp, msecs_to_jiffies(1000)); - return inst->vsi->dec.dpb_sz ? 0 : -1; + return inst->vsi->pic.dpb_frames ? 0 : -1; } static int parse_stream_ucode_dma(struct vdec_h264_inst *inst, @@ -603,7 +586,7 @@ wait_for_completion_timeout(&inst->comp, msecs_to_jiffies(1000)); - return inst->vsi->dec.dpb_sz ? 0 : -1; + return inst->vsi->pic.dpb_frames ? 0 : -1; } static int parse_stream_cpu(struct vdec_h264_inst *inst, u8 *buf, u32 size) @@ -688,71 +671,20 @@ static void vdec_h264_deinit(unsigned long h_vdec) { - ulong flags; struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec; struct aml_vcodec_ctx *ctx = inst->ctx; video_decoder_release(&inst->vdec); - vcodec_vfm_release(&inst->vfm); - - //dump_deinit(); - - spin_lock_irqsave(&ctx->slock, flags); if (inst->vsi && inst->vsi->header_buf) - kfree(inst->vsi->header_buf); + vfree(inst->vsi->header_buf); if (inst->vsi) - kfree(inst->vsi); + vfree(inst->vsi); - kfree(inst); + vfree(inst); ctx->drv_handle = 0; - spin_unlock_irqrestore(&ctx->slock, flags); -} - -static int vdec_h264_get_fb(struct vdec_h264_inst *inst, struct vdec_v4l2_buffer **out) -{ - return get_fb_from_queue(inst->ctx, out); -} - -static void vdec_h264_get_vf(struct vdec_h264_inst *inst, struct vdec_v4l2_buffer **out) -{ - struct vframe_s *vf = NULL; - struct vdec_v4l2_buffer *fb = NULL; - - vf = peek_video_frame(&inst->vfm); - if (!vf) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "there is no vframe.\n"); - *out = NULL; - return; - } - - vf = get_video_frame(&inst->vfm); - if (!vf) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "the vframe is avalid.\n"); - *out = NULL; - return; - } - - atomic_set(&vf->use_cnt, 1); - - fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; - if (fb) { - fb->vf_handle = (unsigned long)vf; - fb->status = FB_ST_DISPLAY; - } - - *out = fb; - - //pr_info("%s, %d\n", __func__, fb->base_y.bytes_used); - //dump_write(fb->base_y.vaddr, fb->base_y.bytes_used); - //dump_write(fb->base_c.vaddr, fb->base_c.bytes_used); - - /* convert yuv format. */ - //swap_uv(fb->base_c.vaddr, fb->base_c.size); } static int vdec_write_nalu(struct vdec_h264_inst *inst, @@ -802,7 +734,7 @@ inst->vsi->head_offset += inst->vsi->sei_size; ret = size; } else if (inst->vsi->head_offset == 0) { - ret = vdec_vframe_write(vdec, buf, size, ts); + ret = vdec_vframe_write(vdec, buf, size, ts, 0); } else { char *write_buf = vmalloc(inst->vsi->head_offset + size); if (!write_buf) { @@ -814,7 +746,7 @@ memcpy(write_buf + inst->vsi->head_offset, buf, size); ret = vdec_vframe_write(vdec, write_buf, - inst->vsi->head_offset + size, ts); + inst->vsi->head_offset + size, ts, 0); memset(inst->vsi->header_buf, 0, HEADER_BUFFER_SIZE); inst->vsi->head_offset = 0; @@ -862,9 +794,7 @@ inst->vsi->cur_pic.coded_height != inst->vsi->pic.coded_height) || (inst->vsi->pic.profile_idc != - inst->vsi->cur_pic.profile_idc) || - (inst->vsi->pic.ref_frame_count != - inst->vsi->cur_pic.ref_frame_count))) { + inst->vsi->cur_pic.profile_idc))) { v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, "res change\n"); inst->vsi->cur_pic = inst->vsi->pic; return true; @@ -878,16 +808,13 @@ { struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec; struct aml_vdec_adapt *vdec = &inst->vdec; - u8 *buf; - u32 size; + u8 *buf = (u8 *) bs->vaddr; + u32 size = bs->size; int ret = -1; if (bs == NULL) return -1; - buf = (u8 *) bs->vaddr; - size = bs->size; - if (vdec_input_full(vdec)) return -EAGAIN; @@ -909,7 +836,8 @@ ret = vdec_vframe_write(vdec, s->data, s->len, - bs->timestamp); + bs->timestamp, + 0); } else if (bs->model == VB2_MEMORY_DMABUF || bs->model == VB2_MEMORY_USERPTR) { ret = vdec_vframe_write_with_dma(vdec, @@ -961,20 +889,12 @@ struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec; if (!inst) { - v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "the h264 inst of dec is invalid.\n"); return -1; } switch (type) { - case GET_PARAM_DISP_FRAME_BUFFER: - vdec_h264_get_vf(inst, out); - break; - - case GET_PARAM_FREE_FRAME_BUFFER: - ret = vdec_h264_get_fb(inst, out); - break; - case GET_PARAM_PIC_INFO: get_pic_info(inst, out); break; @@ -990,6 +910,14 @@ case GET_PARAM_CONFIG_INFO: get_param_config_info(inst, out); break; + + case GET_PARAM_DW_MODE: + { + unsigned int* mode = out; + *mode = inst->ctx->config.parm.dec.cfg.double_write_mode; + break; + } + default: v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "invalid get parameter type=%d\n", type); @@ -1028,8 +956,10 @@ pic->y_len_sz = pic->coded_width * pic->coded_height; pic->c_len_sz = pic->y_len_sz >> 1; pic->profile_idc = ps->profile; - pic->ref_frame_count = ps->ref_frames; pic->field = ps->field; + pic->dpb_frames = ps->dpb_frames; + pic->dpb_margin = ps->dpb_margin; + pic->vpp_margin = ps->dpb_margin; dec->dpb_sz = ps->dpb_size; inst->parms.ps = *ps; @@ -1042,10 +972,9 @@ complete(&inst->comp); v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, - "Parse from ucode, visible(%d x %d), coded(%d x %d) dpb: %d, scan: %s\n", + "Parse from ucode, visible(%d x %d), coded(%d x %d), scan:%s\n", ps->visible_width, ps->visible_height, ps->coded_width, ps->coded_height, - dec->dpb_sz, ps->field == V4L2_FIELD_NONE ? "P" : "I"); } @@ -1065,6 +994,12 @@ } } +static void set_pic_info(struct vdec_h264_inst *inst, + struct vdec_pic_info *pic) +{ + inst->vsi->pic = *pic; +} + static void set_param_post_event(struct vdec_h264_inst *inst, u32 *event) { aml_vdec_dispatch_event(inst->ctx, *event); @@ -1079,7 +1014,7 @@ struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec; if (!inst) { - v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "the h264 inst of dec is invalid.\n"); return -1; } @@ -1100,6 +1035,11 @@ case SET_PARAM_POST_EVENT: set_param_post_event(inst, in); break; + + case SET_PARAM_PIC_INFO: + set_pic_info(inst, in); + break; + default: v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "invalid set parameter type=%d\n", type);
diff --git a/drivers/amvdec_ports/decoder/vdec_hevc_if.c b/drivers/amvdec_ports/decoder/vdec_hevc_if.c index 2a41276..56d492a 100644 --- a/drivers/amvdec_ports/decoder/vdec_hevc_if.c +++ b/drivers/amvdec_ports/decoder/vdec_hevc_if.c
@@ -29,7 +29,6 @@ #include "../aml_vcodec_drv.h" #include "../aml_vcodec_adapt.h" #include "../vdec_drv_base.h" -#include "../aml_vcodec_vfm.h" #include "aml_hevc_parser.h" #define HEVC_NAL_TYPE(value) ((value >> 1) & 0x3F) @@ -112,9 +111,9 @@ struct aml_vcodec_ctx *ctx; struct aml_vdec_adapt vdec; struct vdec_hevc_vsi *vsi; - struct vcodec_vfm_s vfm; struct aml_dec_params parms; struct completion comp; + struct vdec_comp_buf_info comp_info; }; static void get_pic_info(struct vdec_hevc_inst *inst, @@ -155,7 +154,7 @@ pbuf += sprintf(pbuf, "parm_v4l_codec_enable:1;"); pbuf += sprintf(pbuf, "parm_v4l_buffer_margin:7;"); - pbuf += sprintf(pbuf, "hevc_double_write_mode:16;"); + pbuf += sprintf(pbuf, "hevc_double_write_mode:1;"); pbuf += sprintf(pbuf, "hevc_buf_width:4096;"); pbuf += sprintf(pbuf, "hevc_buf_height:2304;"); pbuf += sprintf(pbuf, "save_buffer_mode:0;"); @@ -187,9 +186,13 @@ ctx->config.parm.dec.cfg.canvas_mem_endian); pbuf += sprintf(pbuf, "parm_v4l_low_latency_mode:%d;", ctx->config.parm.dec.cfg.low_latency_mode); + pbuf += sprintf(pbuf, "parm_v4l_metadata_config_flag:%d;", + ctx->config.parm.dec.cfg.metadata_config_flag); + pbuf += sprintf(pbuf, "parm_v4l_duration:%d;", + ctx->config.parm.dec.cfg.duration); ctx->config.length = pbuf - ctx->config.buf; } else { - ctx->config.parm.dec.cfg.double_write_mode = 16; + ctx->config.parm.dec.cfg.double_write_mode = 1; ctx->config.parm.dec.cfg.ref_buf_margin = 7; ctx->config.length = vdec_config_default_parms(ctx->config.buf); } @@ -203,14 +206,13 @@ { struct vdec_hevc_inst *inst = NULL; int ret = -1; - bool dec_init = false; inst = kzalloc(sizeof(*inst), GFP_KERNEL); if (!inst) return -ENOMEM; + inst->vdec.frm_name = "H.265"; inst->vdec.video_type = VFORMAT_HEVC; - inst->vdec.dev = ctx->dev->vpu_plat_dev; inst->vdec.filp = ctx->dev->filp; inst->vdec.ctx = ctx; inst->ctx = ctx; @@ -224,24 +226,6 @@ /* to eable hevc hw.*/ inst->vdec.port.type = PORT_TYPE_HEVC; - /* init vfm */ - inst->vfm.ctx = ctx; - inst->vfm.ada_ctx = &inst->vdec; - ret = vcodec_vfm_init(&inst->vfm); - if (ret) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "init vfm failed.\n"); - goto err; - } - - ret = video_decoder_init(&inst->vdec); - if (ret) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "vdec_hevc init err=%d\n", ret); - goto err; - } - dec_init = true; - /* probe info from the stream */ inst->vsi = kzalloc(sizeof(struct vdec_hevc_vsi), GFP_KERNEL); if (!inst->vsi) { @@ -250,7 +234,7 @@ } /* alloc the header buffer to be used cache sps or spp etc.*/ - inst->vsi->header_buf = kzalloc(HEADER_BUFFER_SIZE, GFP_KERNEL); + inst->vsi->header_buf = vzalloc(HEADER_BUFFER_SIZE); if (!inst->vsi->header_buf) { ret = -ENOMEM; goto err; @@ -258,22 +242,23 @@ init_completion(&inst->comp); - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, - "hevc Instance >> %lx\n", (ulong) inst); - ctx->ada_ctx = &inst->vdec; *h_vdec = (unsigned long)inst; - //dump_init(); + ret = video_decoder_init(&inst->vdec); + if (ret) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "vdec_hevc init err=%d\n", ret); + goto err; + } + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + "hevc Instance >> %lx\n", (ulong) inst); return 0; err: - if (dec_init) - video_decoder_release(&inst->vdec); - if (inst) - vcodec_vfm_release(&inst->vfm); if (inst && inst->vsi && inst->vsi->header_buf) - kfree(inst->vsi->header_buf); + vfree(inst->vsi->header_buf); if (inst && inst->vsi) kfree(inst->vsi); if (inst) @@ -317,8 +302,8 @@ static int vdec_get_dw_mode(struct vdec_hevc_inst *inst, int dw_mode) { u32 valid_dw_mode = inst->parms.cfg.double_write_mode; - int w = inst->parms.cfg.init_width; - int h = inst->parms.cfg.init_height; + int w = inst->vsi->pic.coded_width; + int h = inst->vsi->pic.coded_height; u32 dw = 0x1; /*1:1*/ switch (valid_dw_mode) { @@ -421,7 +406,7 @@ int ret = 0; struct aml_vdec_adapt *vdec = &inst->vdec; - ret = vdec_vframe_write(vdec, buf, size, timestamp); + ret = vdec_vframe_write(vdec, buf, size, timestamp, 0); if (ret < 0) { v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "write frame data failed. err: %d\n", ret); @@ -432,7 +417,7 @@ wait_for_completion_timeout(&inst->comp, msecs_to_jiffies(1000)); - return inst->vsi->dec.dpb_sz ? 0 : -1; + return inst->vsi->pic.dpb_frames ? 0 : -1; } static int parse_stream_ucode_dma(struct vdec_hevc_inst *inst, @@ -453,7 +438,7 @@ wait_for_completion_timeout(&inst->comp, msecs_to_jiffies(1000)); - return inst->vsi->dec.dpb_sz ? 0 : -1; + return inst->vsi->pic.dpb_frames ? 0 : -1; } static int parse_stream_cpu(struct vdec_hevc_inst *inst, u8 *buf, u32 size) @@ -526,19 +511,13 @@ static void vdec_hevc_deinit(unsigned long h_vdec) { - ulong flags; struct vdec_hevc_inst *inst = (struct vdec_hevc_inst *)h_vdec; struct aml_vcodec_ctx *ctx = inst->ctx; video_decoder_release(&inst->vdec); - vcodec_vfm_release(&inst->vfm); - - //dump_deinit(); - - spin_lock_irqsave(&ctx->slock, flags); if (inst->vsi && inst->vsi->header_buf) - kfree(inst->vsi->header_buf); + vfree(inst->vsi->header_buf); if (inst->vsi) kfree(inst->vsi); @@ -546,49 +525,6 @@ kfree(inst); ctx->drv_handle = 0; - spin_unlock_irqrestore(&ctx->slock, flags); -} - -static int vdec_hevc_get_fb(struct vdec_hevc_inst *inst, struct vdec_v4l2_buffer **out) -{ - return get_fb_from_queue(inst->ctx, out); -} - -static void vdec_hevc_get_vf(struct vdec_hevc_inst *inst, struct vdec_v4l2_buffer **out) -{ - struct vframe_s *vf = NULL; - struct vdec_v4l2_buffer *fb = NULL; - - vf = peek_video_frame(&inst->vfm); - if (!vf) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "there is no vframe.\n"); - *out = NULL; - return; - } - - vf = get_video_frame(&inst->vfm); - if (!vf) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "the vframe is avalid.\n"); - *out = NULL; - return; - } - - atomic_set(&vf->use_cnt, 1); - - fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; - fb->vf_handle = (unsigned long)vf; - fb->status = FB_ST_DISPLAY; - - *out = fb; - - //pr_info("%s, %d\n", __func__, fb->base_y.bytes_used); - //dump_write(fb->base_y.vaddr, fb->base_y.bytes_used); - //dump_write(fb->base_c.vaddr, fb->base_c.bytes_used); - - /* convert yuv format. */ - //swap_uv(fb->base_c.vaddr, fb->base_c.size); } static int vdec_write_nalu(struct vdec_hevc_inst *inst, @@ -597,7 +533,7 @@ int ret = 0; struct aml_vdec_adapt *vdec = &inst->vdec; - ret = vdec_vframe_write(vdec, buf, size, ts); + ret = vdec_vframe_write(vdec, buf, size, ts, 0); return ret; } @@ -644,16 +580,13 @@ { struct vdec_hevc_inst *inst = (struct vdec_hevc_inst *)h_vdec; struct aml_vdec_adapt *vdec = &inst->vdec; - u8 *buf; - u32 size; + u8 *buf = (u8 *) bs->vaddr; + u32 size = bs->size; int ret = -1; if (bs == NULL) return -1; - buf = (u8 *) bs->vaddr; - size = bs->size; - if (vdec_input_full(vdec)) return -EAGAIN; @@ -675,7 +608,8 @@ ret = vdec_vframe_write(vdec, s->data, s->len, - bs->timestamp); + bs->timestamp, + 0); } else if (bs->model == VB2_MEMORY_DMABUF || bs->model == VB2_MEMORY_USERPTR) { ret = vdec_vframe_write_with_dma(vdec, @@ -713,6 +647,12 @@ "parms status: %u\n", parms->parms_status); } +static void get_param_comp_buf_info(struct vdec_hevc_inst *inst, + struct vdec_comp_buf_info *params) +{ + memcpy(params, &inst->comp_info, sizeof(*params)); +} + static int vdec_hevc_get_param(unsigned long h_vdec, enum vdec_get_param_type type, void *out) { @@ -720,20 +660,12 @@ struct vdec_hevc_inst *inst = (struct vdec_hevc_inst *)h_vdec; if (!inst) { - v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "the hevc inst of dec is invalid.\n"); return -1; } switch (type) { - case GET_PARAM_DISP_FRAME_BUFFER: - vdec_hevc_get_vf(inst, out); - break; - - case GET_PARAM_FREE_FRAME_BUFFER: - ret = vdec_hevc_get_fb(inst, out); - break; - case GET_PARAM_PIC_INFO: get_pic_info(inst, out); break; @@ -749,6 +681,21 @@ case GET_PARAM_CONFIG_INFO: get_param_config_info(inst, out); break; + + case GET_PARAM_DW_MODE: + { + u32 *mode = out; + u32 m = inst->ctx->config.parm.dec.cfg.double_write_mode; + if (m <= 16) + *mode = inst->ctx->config.parm.dec.cfg.double_write_mode; + else + *mode = vdec_get_dw_mode(inst, 0); + break; + } + case GET_PARAM_COMP_BUF_INFO: + get_param_comp_buf_info(inst, out); + break; + default: v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "invalid get parameter type=%d\n", type); @@ -769,6 +716,7 @@ struct vdec_pic_info *pic = &inst->vsi->pic; struct vdec_hevc_dec_info *dec = &inst->vsi->dec; struct v4l2_rect *rect = &inst->vsi->crop; + int dw = inst->parms.cfg.double_write_mode; /* fill visible area size that be used for EGL. */ pic->visible_width = ps->visible_width; @@ -784,9 +732,14 @@ pic->coded_width = ps->coded_width; pic->coded_height = ps->coded_height; - pic->y_len_sz = pic->coded_width * pic->coded_height; + + pic->y_len_sz = ALIGN(vdec_pic_scale(inst, pic->coded_width, dw), 64) * + ALIGN(vdec_pic_scale(inst, pic->coded_height, dw), 64); pic->c_len_sz = pic->y_len_sz >> 1; + pic->dpb_frames = ps->dpb_frames; + pic->dpb_margin = ps->dpb_margin; + pic->vpp_margin = ps->dpb_margin; dec->dpb_sz = ps->dpb_size; pic->field = ps->field; @@ -798,13 +751,27 @@ complete(&inst->comp); v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, - "Parse from ucode, crop(%d x %d), coded(%d x %d) dpb: %d, scan: %s\n", + "Parse from ucode, visible(%d x %d), coded(%d x %d), scan:%s\n", pic->visible_width, pic->visible_height, pic->coded_width, pic->coded_height, - dec->dpb_sz, pic->field == V4L2_FIELD_NONE ? "P" : "I"); } +static void set_cfg_info(struct vdec_hevc_inst *inst, + struct aml_vdec_cfg_infos *cfg) +{ + memcpy(&inst->ctx->config.parm.dec.cfg, + cfg, sizeof(struct aml_vdec_cfg_infos)); + memcpy(&inst->parms.cfg, + cfg, sizeof(struct aml_vdec_cfg_infos)); +} + +static void set_param_comp_buf_info(struct vdec_hevc_inst *inst, + struct vdec_comp_buf_info *info) +{ + memcpy(&inst->comp_info, info, sizeof(*info)); +} + static void set_param_hdr_info(struct vdec_hevc_inst *inst, struct aml_vdec_hdr_infos *hdr) { @@ -827,6 +794,12 @@ "H265 post event: %d\n", *event); } +static void set_pic_info(struct vdec_hevc_inst *inst, + struct vdec_pic_info *pic) +{ + inst->vsi->pic = *pic; +} + static int vdec_hevc_set_param(unsigned long h_vdec, enum vdec_set_param_type type, void *in) { @@ -834,7 +807,7 @@ struct vdec_hevc_inst *inst = (struct vdec_hevc_inst *)h_vdec; if (!inst) { - v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "the hevc inst of dec is invalid.\n"); return -1; } @@ -844,10 +817,18 @@ set_param_write_sync(inst); break; + case SET_PARAM_CFG_INFO: + set_cfg_info(inst, in); + break; + case SET_PARAM_PS_INFO: set_param_ps_info(inst, in); break; + case SET_PARAM_COMP_BUF_INFO: + set_param_comp_buf_info(inst, in); + break; + case SET_PARAM_HDR_INFO: set_param_hdr_info(inst, in); break; @@ -855,6 +836,10 @@ case SET_PARAM_POST_EVENT: set_param_post_event(inst, in); break; + + case SET_PARAM_PIC_INFO: + set_pic_info(inst, in); + break; default: v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "invalid set parameter type=%d\n", type);
diff --git a/drivers/amvdec_ports/decoder/vdec_mjpeg_if.c b/drivers/amvdec_ports/decoder/vdec_mjpeg_if.c index f9816cc..8332956 100644 --- a/drivers/amvdec_ports/decoder/vdec_mjpeg_if.c +++ b/drivers/amvdec_ports/decoder/vdec_mjpeg_if.c
@@ -28,7 +28,6 @@ #include "../aml_vcodec_dec.h" #include "../aml_vcodec_adapt.h" #include "../vdec_drv_base.h" -#include "../aml_vcodec_vfm.h" #include "aml_mjpeg_parser.h" #include <media/v4l2-mem2mem.h> @@ -112,7 +111,6 @@ struct aml_vcodec_ctx *ctx; struct aml_vdec_adapt vdec; struct vdec_mjpeg_vsi *vsi; - struct vcodec_vfm_s vfm; struct aml_dec_params parms; struct completion comp; }; @@ -158,6 +156,7 @@ pbuf += sprintf(pbuf, "parm_v4l_codec_enable:1;"); pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_mode:0;"); pbuf += sprintf(pbuf, "parm_v4l_buffer_margin:0;"); + pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_endian:0;"); return pbuf - parm; } @@ -177,6 +176,8 @@ ctx->config.parm.dec.cfg.ref_buf_margin); pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_endian:%d;", ctx->config.parm.dec.cfg.canvas_mem_endian); + pbuf += sprintf(pbuf, "parm_v4l_duration:%d;", + ctx->config.parm.dec.cfg.duration); ctx->config.length = pbuf - ctx->config.buf; } else { ctx->config.length = vdec_config_default_parms(ctx->config.buf); @@ -192,14 +193,13 @@ { struct vdec_mjpeg_inst *inst = NULL; int ret = -1; - bool dec_init = false; inst = kzalloc(sizeof(*inst), GFP_KERNEL); if (!inst) return -ENOMEM; + inst->vdec.frm_name = "MJPEG"; inst->vdec.video_type = VFORMAT_MJPEG; - inst->vdec.dev = ctx->dev->vpu_plat_dev; inst->vdec.filp = ctx->dev->filp; inst->vdec.config = ctx->config; inst->vdec.ctx = ctx; @@ -213,24 +213,6 @@ /* to eable mjpeg hw.*/ inst->vdec.port.type = PORT_TYPE_VIDEO; - /* init vfm */ - inst->vfm.ctx = ctx; - inst->vfm.ada_ctx = &inst->vdec; - ret = vcodec_vfm_init(&inst->vfm); - if (ret) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "init vfm failed.\n"); - goto err; - } - - ret = video_decoder_init(&inst->vdec); - if (ret) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "vdec_mjpeg init err=%d\n", ret); - goto err; - } - dec_init = true; - /* probe info from the stream */ inst->vsi = kzalloc(sizeof(struct vdec_mjpeg_vsi), GFP_KERNEL); if (!inst->vsi) { @@ -239,30 +221,31 @@ } /* alloc the header buffer to be used cache sps or spp etc.*/ - inst->vsi->header_buf = kzalloc(HEADER_BUFFER_SIZE, GFP_KERNEL); + inst->vsi->header_buf = vzalloc(HEADER_BUFFER_SIZE); if (!inst->vsi->header_buf) { ret = -ENOMEM; goto err; } + init_completion(&inst->comp); + ctx->ada_ctx = &inst->vdec; + *h_vdec = (unsigned long)inst; + + ret = video_decoder_init(&inst->vdec); + if (ret) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "vdec_mjpeg init err=%d\n", ret); + goto err; + } + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, "mjpeg Instance >> %lx\n", (ulong) inst); - init_completion(&inst->comp); - ctx->ada_ctx = &inst->vdec; - *h_vdec = (unsigned long)inst; - - //dump_init(); - return 0; err: - if (dec_init) - video_decoder_release(&inst->vdec); - if (inst) - vcodec_vfm_release(&inst->vfm); if (inst && inst->vsi && inst->vsi->header_buf) - kfree(inst->vsi->header_buf); + vfree(inst->vsi->header_buf); if (inst && inst->vsi) kfree(inst->vsi); if (inst) @@ -308,9 +291,9 @@ dec->dpb_sz = 8; v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_BUFMGR, - "The stream infos, coded:(%d x %d), visible:(%d x %d), DPB: %d\n", + "The stream infos, coded:(%d x %d), visible:(%d x %d)\n", pic->coded_width, pic->coded_height, - pic->visible_width, pic->visible_height, dec->dpb_sz); + pic->visible_width, pic->visible_height); } static int parse_stream_ucode(struct vdec_mjpeg_inst *inst, @@ -319,7 +302,7 @@ int ret = 0; struct aml_vdec_adapt *vdec = &inst->vdec; - ret = vdec_vframe_write(vdec, buf, size, timestamp); + ret = vdec_vframe_write(vdec, buf, size, timestamp, 0); if (ret < 0) { v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "write frame data failed. err: %d\n", ret); @@ -330,7 +313,7 @@ wait_for_completion_timeout(&inst->comp, msecs_to_jiffies(1000)); - return inst->vsi->dec.dpb_sz ? 0 : -1; + return inst->vsi->pic.dpb_frames ? 0 : -1; } static int parse_stream_ucode_dma(struct vdec_mjpeg_inst *inst, @@ -351,7 +334,7 @@ wait_for_completion_timeout(&inst->comp, msecs_to_jiffies(1000)); - return inst->vsi->dec.dpb_sz ? 0 : -1; + return inst->vsi->pic.dpb_frames ? 0 : -1; } static int parse_stream_cpu(struct vdec_mjpeg_inst *inst, u8 *buf, u32 size) @@ -431,12 +414,8 @@ video_decoder_release(&inst->vdec); - vcodec_vfm_release(&inst->vfm); - - //dump_deinit(); - if (inst->vsi && inst->vsi->header_buf) - kfree(inst->vsi->header_buf); + vfree(inst->vsi->header_buf); if (inst->vsi) kfree(inst->vsi); @@ -444,55 +423,13 @@ kfree(inst); } -static int vdec_mjpeg_get_fb(struct vdec_mjpeg_inst *inst, struct vdec_v4l2_buffer **out) -{ - return get_fb_from_queue(inst->ctx, out); -} - -static void vdec_mjpeg_get_vf(struct vdec_mjpeg_inst *inst, struct vdec_v4l2_buffer **out) -{ - struct vframe_s *vf = NULL; - struct vdec_v4l2_buffer *fb = NULL; - - vf = peek_video_frame(&inst->vfm); - if (!vf) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "there is no vframe.\n"); - *out = NULL; - return; - } - - vf = get_video_frame(&inst->vfm); - if (!vf) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "the vframe is avalid.\n"); - *out = NULL; - return; - } - - atomic_set(&vf->use_cnt, 1); - - fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; - fb->vf_handle = (unsigned long)vf; - fb->status = FB_ST_DISPLAY; - - *out = fb; - - //pr_info("%s, %d\n", __func__, fb->base_y.bytes_used); - //dump_write(fb->base_y.va, fb->base_y.bytes_used); - //dump_write(fb->base_c.va, fb->base_c.bytes_used); - - /* convert yuv format. */ - //swap_uv(fb->base_c.va, fb->base_c.size); -} - static int vdec_write_nalu(struct vdec_mjpeg_inst *inst, u8 *buf, u32 size, u64 ts) { int ret = 0; struct aml_vdec_adapt *vdec = &inst->vdec; - ret = vdec_vframe_write(vdec, buf, size, ts); + ret = vdec_vframe_write(vdec, buf, size, ts, 0); return ret; } @@ -520,7 +457,8 @@ ret = vdec_vframe_write(vdec, s->data, s->len, - bs->timestamp); + bs->timestamp, + 0); } else if (bs->model == VB2_MEMORY_DMABUF || bs->model == VB2_MEMORY_USERPTR) { ret = vdec_vframe_write_with_dma(vdec, @@ -542,20 +480,12 @@ struct vdec_mjpeg_inst *inst = (struct vdec_mjpeg_inst *)h_vdec; if (!inst) { - v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "the mjpeg inst of dec is invalid.\n"); return -1; } switch (type) { - case GET_PARAM_DISP_FRAME_BUFFER: - vdec_mjpeg_get_vf(inst, out); - break; - - case GET_PARAM_FREE_FRAME_BUFFER: - ret = vdec_mjpeg_get_fb(inst, out); - break; - case GET_PARAM_PIC_INFO: get_pic_info(inst, out); break; @@ -568,6 +498,13 @@ get_crop_info(inst, out); break; + case GET_PARAM_DW_MODE: + { + unsigned int* mode = out; + *mode = VDEC_DW_NO_AFBC; + break; + } + default: v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "invalid get parameter type=%d\n", type); @@ -599,9 +536,13 @@ pic->coded_width = ps->coded_width; pic->coded_height = ps->coded_height; pic->y_len_sz = pic->coded_width * pic->coded_height; - pic->c_len_sz = pic->y_len_sz; + pic->c_len_sz = pic->y_len_sz >> 1; + pic->dpb_frames = ps->dpb_frames; + pic->dpb_margin = ps->dpb_margin; + pic->vpp_margin = ps->dpb_margin; dec->dpb_sz = ps->dpb_size; + pic->field = ps->field; inst->parms.ps = *ps; inst->parms.parms_status |= @@ -611,10 +552,10 @@ complete(&inst->comp); v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, - "Parse from ucode, crop(%d x %d), coded(%d x %d) dpb: %d\n", + "Parse from ucode, visible(%d x %d), coded(%d x %d), scan:%s\n", ps->visible_width, ps->visible_height, ps->coded_width, ps->coded_height, - dec->dpb_sz); + pic->field == V4L2_FIELD_NONE ? "P" : "I"); } static void set_param_write_sync(struct vdec_mjpeg_inst *inst) @@ -622,6 +563,12 @@ complete(&inst->comp); } +static void set_pic_info(struct vdec_mjpeg_inst *inst, + struct vdec_pic_info *pic) +{ + inst->vsi->pic = *pic; +} + static int vdec_mjpeg_set_param(unsigned long h_vdec, enum vdec_set_param_type type, void *in) { @@ -629,7 +576,7 @@ struct vdec_mjpeg_inst *inst = (struct vdec_mjpeg_inst *)h_vdec; if (!inst) { - v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "the mjpeg inst of dec is invalid.\n"); return -1; } @@ -638,10 +585,15 @@ case SET_PARAM_WRITE_FRAME_SYNC: set_param_write_sync(inst); break; + case SET_PARAM_PS_INFO: set_param_ps_info(inst, in); break; + case SET_PARAM_PIC_INFO: + set_pic_info(inst, in); + break; + default: v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "invalid set parameter type=%d\n", type);
diff --git a/drivers/amvdec_ports/decoder/vdec_mpeg12_if.c b/drivers/amvdec_ports/decoder/vdec_mpeg12_if.c index 9a38e71..2472ac1 100644 --- a/drivers/amvdec_ports/decoder/vdec_mpeg12_if.c +++ b/drivers/amvdec_ports/decoder/vdec_mpeg12_if.c
@@ -28,7 +28,6 @@ #include "../aml_vcodec_dec.h" #include "../aml_vcodec_adapt.h" #include "../vdec_drv_base.h" -#include "../aml_vcodec_vfm.h" #include "aml_mpeg12_parser.h" #define NAL_TYPE(value) ((value) & 0x1F) @@ -111,7 +110,6 @@ struct aml_vcodec_ctx *ctx; struct aml_vdec_adapt vdec; struct vdec_mpeg12_vsi *vsi; - struct vcodec_vfm_s vfm; struct aml_dec_params parms; struct completion comp; }; @@ -173,6 +171,10 @@ ctx->config.parm.dec.cfg.canvas_mem_mode); pbuf += sprintf(pbuf, "parm_v4l_buffer_margin:%d;", ctx->config.parm.dec.cfg.ref_buf_margin); + pbuf += sprintf(pbuf, "parm_v4l_metadata_config_flag:%d;", + ctx->config.parm.dec.cfg.metadata_config_flag); + pbuf += sprintf(pbuf, "parm_v4l_duration:%d;", + ctx->config.parm.dec.cfg.duration); ctx->config.length = pbuf - ctx->config.buf; } else { ctx->config.length = vdec_config_default_parms(ctx->config.buf); @@ -187,14 +189,13 @@ { struct vdec_mpeg12_inst *inst = NULL; int ret = -1; - bool dec_init = false; inst = kzalloc(sizeof(*inst), GFP_KERNEL); if (!inst) return -ENOMEM; + inst->vdec.frm_name = "MPEG2"; inst->vdec.video_type = VFORMAT_MPEG12; - inst->vdec.dev = ctx->dev->vpu_plat_dev; inst->vdec.filp = ctx->dev->filp; inst->vdec.config = ctx->config; inst->vdec.ctx = ctx; @@ -209,24 +210,6 @@ /* to eable mpeg12 hw.*/ inst->vdec.port.type = PORT_TYPE_VIDEO; - /* init vfm */ - inst->vfm.ctx = ctx; - inst->vfm.ada_ctx = &inst->vdec; - ret = vcodec_vfm_init(&inst->vfm); - if (ret) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "init vfm failed.\n"); - goto err; - } - - ret = video_decoder_init(&inst->vdec); - if (ret) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "vdec_mpeg12 init err=%d\n", ret); - goto err; - } - dec_init = true; - /* probe info from the stream */ inst->vsi = kzalloc(sizeof(struct vdec_mpeg12_vsi), GFP_KERNEL); if (!inst->vsi) { @@ -235,29 +218,31 @@ } /* alloc the header buffer to be used cache sps or spp etc.*/ - inst->vsi->header_buf = kzalloc(HEADER_BUFFER_SIZE, GFP_KERNEL); + inst->vsi->header_buf = vzalloc(HEADER_BUFFER_SIZE); if (!inst->vsi->header_buf) { ret = -ENOMEM; goto err; } - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, - "mpeg12 Instance >> %lx\n", (ulong) inst); init_completion(&inst->comp); ctx->ada_ctx = &inst->vdec; *h_vdec = (unsigned long)inst; - //dump_init(); + ret = video_decoder_init(&inst->vdec); + if (ret) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "vdec_mpeg12 init err=%d\n", ret); + goto err; + } + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + "mpeg12 Instance >> %lx\n", (ulong) inst); return 0; err: - if (dec_init) - video_decoder_release(&inst->vdec); - if (inst) - vcodec_vfm_release(&inst->vfm); if (inst && inst->vsi && inst->vsi->header_buf) - kfree(inst->vsi->header_buf); + vfree(inst->vsi->header_buf); if (inst && inst->vsi) kfree(inst->vsi); if (inst) @@ -306,7 +291,7 @@ int ret = 0; struct aml_vdec_adapt *vdec = &inst->vdec; - ret = vdec_vframe_write(vdec, buf, size, timestamp); + ret = vdec_vframe_write(vdec, buf, size, timestamp, 0); if (ret < 0) { v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "write frame data failed. err: %d\n", ret); @@ -317,7 +302,7 @@ wait_for_completion_timeout(&inst->comp, msecs_to_jiffies(1000)); - return inst->vsi->dec.dpb_sz ? 0 : -1; + return inst->vsi->pic.dpb_frames ? 0 : -1; } static int parse_stream_ucode_dma(struct vdec_mpeg12_inst *inst, @@ -338,7 +323,7 @@ wait_for_completion_timeout(&inst->comp, msecs_to_jiffies(1000)); - return inst->vsi->dec.dpb_sz ? 0 : -1; + return inst->vsi->pic.dpb_frames ? 0 : -1; } static int parse_stream_cpu(struct vdec_mpeg12_inst *inst, u8 *buf, u32 size) @@ -418,12 +403,8 @@ video_decoder_release(&inst->vdec); - vcodec_vfm_release(&inst->vfm); - - //dump_deinit(); - if (inst->vsi && inst->vsi->header_buf) - kfree(inst->vsi->header_buf); + vfree(inst->vsi->header_buf); if (inst->vsi) kfree(inst->vsi); @@ -431,55 +412,13 @@ kfree(inst); } -static int vdec_mpeg12_get_fb(struct vdec_mpeg12_inst *inst, struct vdec_v4l2_buffer **out) -{ - return get_fb_from_queue(inst->ctx, out); -} - -static void vdec_mpeg12_get_vf(struct vdec_mpeg12_inst *inst, struct vdec_v4l2_buffer **out) -{ - struct vframe_s *vf = NULL; - struct vdec_v4l2_buffer *fb = NULL; - - vf = peek_video_frame(&inst->vfm); - if (!vf) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "there is no vframe.\n"); - *out = NULL; - return; - } - - vf = get_video_frame(&inst->vfm); - if (!vf) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "the vframe is avalid.\n"); - *out = NULL; - return; - } - - atomic_set(&vf->use_cnt, 1); - - fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; - fb->vf_handle = (unsigned long)vf; - fb->status = FB_ST_DISPLAY; - - *out = fb; - - //pr_info("%s, %d\n", __func__, fb->base_y.bytes_used); - //dump_write(fb->base_y.va, fb->base_y.bytes_used); - //dump_write(fb->base_c.va, fb->base_c.bytes_used); - - /* convert yuv format. */ - //swap_uv(fb->base_c.va, fb->base_c.size); -} - static int vdec_write_nalu(struct vdec_mpeg12_inst *inst, u8 *buf, u32 size, u64 ts) { int ret = 0; struct aml_vdec_adapt *vdec = &inst->vdec; - ret = vdec_vframe_write(vdec, buf, size, ts); + ret = vdec_vframe_write(vdec, buf, size, ts, 0); return ret; } @@ -507,7 +446,8 @@ ret = vdec_vframe_write(vdec, s->data, s->len, - bs->timestamp); + bs->timestamp, + 0); } else if (bs->model == VB2_MEMORY_DMABUF || bs->model == VB2_MEMORY_USERPTR) { ret = vdec_vframe_write_with_dma(vdec, @@ -522,6 +462,19 @@ return ret; } +static void get_param_config_info(struct vdec_mpeg12_inst *inst, + struct aml_dec_params *parms) +{ + + if (inst->parms.parms_status & V4L2_CONFIG_PARM_DECODE_HDRINFO) + parms->hdr = inst->parms.hdr; + + parms->parms_status |= inst->parms.parms_status; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + "parms status: %u\n", parms->parms_status); +} + static int vdec_mpeg12_get_param(unsigned long h_vdec, enum vdec_get_param_type type, void *out) { @@ -529,20 +482,12 @@ struct vdec_mpeg12_inst *inst = (struct vdec_mpeg12_inst *)h_vdec; if (!inst) { - v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "the mpeg12 inst of dec is invalid.\n"); return -1; } switch (type) { - case GET_PARAM_DISP_FRAME_BUFFER: - vdec_mpeg12_get_vf(inst, out); - break; - - case GET_PARAM_FREE_FRAME_BUFFER: - ret = vdec_mpeg12_get_fb(inst, out); - break; - case GET_PARAM_PIC_INFO: get_pic_info(inst, out); break; @@ -555,6 +500,17 @@ get_crop_info(inst, out); break; + case GET_PARAM_CONFIG_INFO: + get_param_config_info(inst, out); + break; + + case GET_PARAM_DW_MODE: + { + unsigned int* mode = out; + *mode = VDEC_DW_NO_AFBC; + break; + } + default: v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "invalid get parameter type=%d\n", type); @@ -569,6 +525,12 @@ complete(&inst->comp); } +static void set_pic_info(struct vdec_mpeg12_inst *inst, + struct vdec_pic_info *pic) +{ + inst->vsi->pic = *pic; +} + static void set_param_ps_info(struct vdec_mpeg12_inst *inst, struct aml_vdec_ps_infos *ps) { @@ -592,6 +554,9 @@ pic->y_len_sz = pic->coded_width * pic->coded_height; pic->c_len_sz = pic->y_len_sz >> 1; + pic->dpb_frames = ps->dpb_frames; + pic->dpb_margin = ps->dpb_margin; + pic->vpp_margin = ps->dpb_margin; dec->dpb_sz = ps->dpb_size; pic->field = ps->field; @@ -603,13 +568,28 @@ complete(&inst->comp); v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, - "Parse from ucode, crop(%d x %d), coded(%d x %d) dpb: %d scan: %s\n", + "Parse from ucode, visible(%d x %d), coded(%d x %d), scan:%s\n", ps->visible_width, ps->visible_height, ps->coded_width, ps->coded_height, - dec->dpb_sz, pic->field == V4L2_FIELD_NONE ? "P" : "I"); } +static void set_param_hdr_info(struct vdec_mpeg12_inst *inst, + struct aml_vdec_hdr_infos *hdr) +{ + inst->parms.hdr = *hdr; + if (!(inst->parms.parms_status & + V4L2_CONFIG_PARM_DECODE_HDRINFO)) { + inst->parms.hdr = *hdr; + inst->parms.parms_status |= + V4L2_CONFIG_PARM_DECODE_HDRINFO; + aml_vdec_dispatch_event(inst->ctx, + V4L2_EVENT_SRC_CH_HDRINFO); + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + "mpeg12 set HDR infos\n"); + } +} + static int vdec_mpeg12_set_param(unsigned long h_vdec, enum vdec_set_param_type type, void *in) { @@ -617,7 +597,7 @@ struct vdec_mpeg12_inst *inst = (struct vdec_mpeg12_inst *)h_vdec; if (!inst) { - v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "the mpeg12 inst of dec is invalid.\n"); return -1; } @@ -626,10 +606,19 @@ case SET_PARAM_WRITE_FRAME_SYNC: set_param_write_sync(inst); break; + + case SET_PARAM_HDR_INFO: + set_param_hdr_info(inst, in); + break; + case SET_PARAM_PS_INFO: set_param_ps_info(inst, in); break; + case SET_PARAM_PIC_INFO: + set_pic_info(inst, in); + break; + default: v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "invalid set parameter type=%d\n", type);
diff --git a/drivers/amvdec_ports/decoder/vdec_mpeg4_if.c b/drivers/amvdec_ports/decoder/vdec_mpeg4_if.c index c47bafc..bc0af24 100644 --- a/drivers/amvdec_ports/decoder/vdec_mpeg4_if.c +++ b/drivers/amvdec_ports/decoder/vdec_mpeg4_if.c
@@ -28,7 +28,6 @@ #include "../aml_vcodec_dec.h" #include "../aml_vcodec_adapt.h" #include "../vdec_drv_base.h" -#include "../aml_vcodec_vfm.h" #include "aml_mpeg4_parser.h" #define NAL_TYPE(value) ((value) & 0x1F) @@ -111,7 +110,6 @@ struct aml_vcodec_ctx *ctx; struct aml_vdec_adapt vdec; struct vdec_mpeg4_vsi *vsi; - struct vcodec_vfm_s vfm; struct aml_dec_params parms; struct completion comp; }; @@ -173,6 +171,8 @@ ctx->config.parm.dec.cfg.canvas_mem_mode); pbuf += sprintf(pbuf, "parm_v4l_buffer_margin:%d;", ctx->config.parm.dec.cfg.ref_buf_margin); + pbuf += sprintf(pbuf, "parm_v4l_duration:%d;", + ctx->config.parm.dec.cfg.duration); ctx->config.length = pbuf - ctx->config.buf; } else { ctx->config.length = vdec_config_default_parms(ctx->config.buf); @@ -188,15 +188,14 @@ { struct vdec_mpeg4_inst *inst = NULL; int ret = -1; - bool dec_init = false; inst = kzalloc(sizeof(*inst), GFP_KERNEL); if (!inst) return -ENOMEM; + inst->vdec.frm_name = "MPEG4"; inst->vdec.video_type = VFORMAT_MPEG4; inst->vdec.format = VIDEO_DEC_FORMAT_MPEG4_5; - inst->vdec.dev = ctx->dev->vpu_plat_dev; inst->vdec.filp = ctx->dev->filp; inst->vdec.config = ctx->config; inst->vdec.ctx = ctx; @@ -210,24 +209,6 @@ /* to eable mpeg4 hw.*/ inst->vdec.port.type = PORT_TYPE_VIDEO; - /* init vfm */ - inst->vfm.ctx = ctx; - inst->vfm.ada_ctx = &inst->vdec; - ret = vcodec_vfm_init(&inst->vfm); - if (ret) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "init vfm failed.\n"); - goto err; - } - dec_init = true; - - ret = video_decoder_init(&inst->vdec); - if (ret) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "vdec_mpeg4 init err=%d\n", ret); - goto err; - } - /* probe info from the stream */ inst->vsi = kzalloc(sizeof(struct vdec_mpeg4_vsi), GFP_KERNEL); if (!inst->vsi) { @@ -236,30 +217,31 @@ } /* alloc the header buffer to be used cache sps or spp etc.*/ - inst->vsi->header_buf = kzalloc(HEADER_BUFFER_SIZE, GFP_KERNEL); + inst->vsi->header_buf = vzalloc(HEADER_BUFFER_SIZE); if (!inst->vsi->header_buf) { ret = -ENOMEM; goto err; } + init_completion(&inst->comp); + ctx->ada_ctx = &inst->vdec; + *h_vdec = (unsigned long)inst; + + ret = video_decoder_init(&inst->vdec); + if (ret) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "vdec_mpeg4 init err=%d\n", ret); + goto err; + } + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, "mpeg4 Instance >> %lx\n", (ulong) inst); - init_completion(&inst->comp); - ctx->ada_ctx = &inst->vdec; - *h_vdec = (unsigned long)inst; - - //dump_init(); - return 0; err: - if (dec_init) - video_decoder_release(&inst->vdec); - if (inst) - vcodec_vfm_release(&inst->vfm); if (inst && inst->vsi && inst->vsi->header_buf) - kfree(inst->vsi->header_buf); + vfree(inst->vsi->header_buf); if (inst && inst->vsi) kfree(inst->vsi); if (inst) @@ -316,7 +298,7 @@ int ret = 0; struct aml_vdec_adapt *vdec = &inst->vdec; - ret = vdec_vframe_write(vdec, buf, size, timestamp); + ret = vdec_vframe_write(vdec, buf, size, timestamp, 0); if (ret < 0) { v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "write frame data failed. err: %d\n", ret); @@ -327,7 +309,7 @@ wait_for_completion_timeout(&inst->comp, msecs_to_jiffies(1000)); - return inst->vsi->dec.dpb_sz ? 0 : -1; + return inst->vsi->pic.dpb_frames ? 0 : -1; } static int parse_stream_ucode_dma(struct vdec_mpeg4_inst *inst, @@ -348,7 +330,7 @@ wait_for_completion_timeout(&inst->comp, msecs_to_jiffies(1000)); - return inst->vsi->dec.dpb_sz ? 0 : -1; + return inst->vsi->pic.dpb_frames ? 0 : -1; } static int parse_stream_cpu(struct vdec_mpeg4_inst *inst, u8 *buf, u32 size) @@ -428,12 +410,8 @@ video_decoder_release(&inst->vdec); - vcodec_vfm_release(&inst->vfm); - - //dump_deinit(); - if (inst->vsi && inst->vsi->header_buf) - kfree(inst->vsi->header_buf); + vfree(inst->vsi->header_buf); if (inst->vsi) kfree(inst->vsi); @@ -441,55 +419,13 @@ kfree(inst); } -static int vdec_mpeg4_get_fb(struct vdec_mpeg4_inst *inst, struct vdec_v4l2_buffer **out) -{ - return get_fb_from_queue(inst->ctx, out); -} - -static void vdec_mpeg4_get_vf(struct vdec_mpeg4_inst *inst, struct vdec_v4l2_buffer **out) -{ - struct vframe_s *vf = NULL; - struct vdec_v4l2_buffer *fb = NULL; - - vf = peek_video_frame(&inst->vfm); - if (!vf) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "there is no vframe.\n"); - *out = NULL; - return; - } - - vf = get_video_frame(&inst->vfm); - if (!vf) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "the vframe is avalid.\n"); - *out = NULL; - return; - } - - atomic_set(&vf->use_cnt, 1); - - fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; - fb->vf_handle = (unsigned long)vf; - fb->status = FB_ST_DISPLAY; - - *out = fb; - - //pr_info("%s, %d\n", __func__, fb->base_y.bytes_used); - //dump_write(fb->base_y.va, fb->base_y.bytes_used); - //dump_write(fb->base_c.va, fb->base_c.bytes_used); - - /* convert yuv format. */ - //swap_uv(fb->base_c.va, fb->base_c.size); -} - static int vdec_write_nalu(struct vdec_mpeg4_inst *inst, u8 *buf, u32 size, u64 ts) { int ret = 0; struct aml_vdec_adapt *vdec = &inst->vdec; - ret = vdec_vframe_write(vdec, buf, size, ts); + ret = vdec_vframe_write(vdec, buf, size, ts, 0); return ret; } @@ -517,7 +453,8 @@ ret = vdec_vframe_write(vdec, s->data, s->len, - bs->timestamp); + bs->timestamp, + 0); } else if (bs->model == VB2_MEMORY_DMABUF || bs->model == VB2_MEMORY_USERPTR) { ret = vdec_vframe_write_with_dma(vdec, @@ -539,20 +476,12 @@ struct vdec_mpeg4_inst *inst = (struct vdec_mpeg4_inst *)h_vdec; if (!inst) { - v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "the mpeg4 inst of dec is invalid.\n"); return -1; } switch (type) { - case GET_PARAM_DISP_FRAME_BUFFER: - vdec_mpeg4_get_vf(inst, out); - break; - - case GET_PARAM_FREE_FRAME_BUFFER: - ret = vdec_mpeg4_get_fb(inst, out); - break; - case GET_PARAM_PIC_INFO: get_pic_info(inst, out); break; @@ -564,6 +493,12 @@ case GET_PARAM_CROP_INFO: get_crop_info(inst, out); break; + case GET_PARAM_DW_MODE: + { + unsigned int* mode = out; + *mode = VDEC_DW_NO_AFBC; + break; + } default: v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, @@ -598,6 +533,9 @@ pic->y_len_sz = pic->coded_width * pic->coded_height; pic->c_len_sz = pic->y_len_sz >> 1; + pic->dpb_frames = ps->dpb_frames; + pic->dpb_margin = ps->dpb_margin; + pic->vpp_margin = ps->dpb_margin; dec->dpb_sz = ps->dpb_size; pic->field = ps->field; @@ -609,10 +547,9 @@ complete(&inst->comp); v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, - "Parse from ucode, crop(%d x %d), coded(%d x %d) dpb: %d, scan:%s\n", + "Parse from ucode, visible(%d x %d), coded(%d x %d), scan:%s\n", ps->visible_width, ps->visible_height, ps->coded_width, ps->coded_height, - dec->dpb_sz, pic->field == V4L2_FIELD_NONE ? "P" : "I"); } @@ -621,6 +558,12 @@ complete(&inst->comp); } +static void set_pic_info(struct vdec_mpeg4_inst *inst, + struct vdec_pic_info *pic) +{ + inst->vsi->pic = *pic; +} + static int vdec_mpeg4_set_param(unsigned long h_vdec, enum vdec_set_param_type type, void *in) { @@ -628,7 +571,7 @@ struct vdec_mpeg4_inst *inst = (struct vdec_mpeg4_inst *)h_vdec; if (!inst) { - v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "the mpeg4 inst of dec is invalid.\n"); return -1; } @@ -637,10 +580,15 @@ case SET_PARAM_WRITE_FRAME_SYNC: set_param_write_sync(inst); break; + case SET_PARAM_PS_INFO: set_param_ps_info(inst, in); break; + case SET_PARAM_PIC_INFO: + set_pic_info(inst, in); + break; + default: v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "invalid set parameter type=%d\n", type);
diff --git a/drivers/amvdec_ports/decoder/vdec_vp9_if.c b/drivers/amvdec_ports/decoder/vdec_vp9_if.c index 6704350..fe81ddd 100644 --- a/drivers/amvdec_ports/decoder/vdec_vp9_if.c +++ b/drivers/amvdec_ports/decoder/vdec_vp9_if.c
@@ -29,7 +29,6 @@ #include "../aml_vcodec_drv.h" #include "../aml_vcodec_adapt.h" #include "../vdec_drv_base.h" -#include "../aml_vcodec_vfm.h" #include "aml_vp9_parser.h" #include "vdec_vp9_trigger.h" @@ -123,13 +122,13 @@ struct aml_vcodec_ctx *ctx; struct aml_vdec_adapt vdec; struct vdec_vp9_vsi *vsi; - struct vcodec_vfm_s vfm; struct aml_dec_params parms; struct completion comp; + struct vdec_comp_buf_info comp_info; }; static int vdec_write_nalu(struct vdec_vp9_inst *inst, - u8 *buf, u32 size, u64 ts); + u8 *buf, u32 size, u64 ts, ulong meta_ptr); static void get_pic_info(struct vdec_vp9_inst *inst, struct vdec_pic_info *pic) @@ -170,7 +169,7 @@ pbuf += sprintf(pbuf, "parm_v4l_codec_enable:1;"); pbuf += sprintf(pbuf, "parm_v4l_buffer_margin:7;"); - pbuf += sprintf(pbuf, "vp9_double_write_mode:16;"); + pbuf += sprintf(pbuf, "vp9_double_write_mode:1;"); pbuf += sprintf(pbuf, "vp9_buf_width:1920;"); pbuf += sprintf(pbuf, "vp9_buf_height:1088;"); pbuf += sprintf(pbuf, "vp9_max_pic_w:4096;"); @@ -187,6 +186,10 @@ { struct aml_vcodec_ctx *ctx = inst->ctx; + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + "%s:parms_status = 0x%x, present_flag = %d\n", + __func__, ctx->config.parm.dec.parms_status, + ctx->config.parm.dec.hdr.color_parms.present_flag); if (ctx->config.parm.dec.parms_status & V4L2_CONFIG_PARM_DECODE_CFGINFO) { u8 *pbuf = ctx->config.buf; @@ -208,9 +211,11 @@ ctx->config.parm.dec.cfg.canvas_mem_endian); pbuf += sprintf(pbuf, "parm_v4l_low_latency_mode:%d;", ctx->config.parm.dec.cfg.low_latency_mode); + pbuf += sprintf(pbuf, "parm_v4l_duration:%d;", + ctx->config.parm.dec.cfg.duration); ctx->config.length = pbuf - ctx->config.buf; } else { - ctx->config.parm.dec.cfg.double_write_mode = 16; + ctx->config.parm.dec.cfg.double_write_mode = 1; ctx->config.parm.dec.cfg.ref_buf_margin = 7; ctx->config.length = vdec_config_default_parms(ctx->config.buf); } @@ -221,6 +226,8 @@ u8 *pbuf = ctx->config.buf + ctx->config.length; pbuf += sprintf(pbuf, "HDRStaticInfo:%d;", 1); + pbuf += sprintf(pbuf, "signal_type:%d;", + ctx->config.parm.dec.hdr.signal_type); pbuf += sprintf(pbuf, "mG.x:%d;", ctx->config.parm.dec.hdr.color_parms.primaries[0][0]); pbuf += sprintf(pbuf, "mG.y:%d;", @@ -249,6 +256,8 @@ inst->parms.hdr = ctx->config.parm.dec.hdr; inst->parms.parms_status |= V4L2_CONFIG_PARM_DECODE_HDRINFO; } + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + "config.buf = %s\n", ctx->config.buf); inst->vdec.config = ctx->config; inst->parms.cfg = ctx->config.parm.dec.cfg; @@ -264,8 +273,8 @@ if (!inst) return -ENOMEM; + inst->vdec.frm_name = "VP9"; inst->vdec.video_type = VFORMAT_VP9; - inst->vdec.dev = ctx->dev->vpu_plat_dev; inst->vdec.filp = ctx->dev->filp; inst->vdec.ctx = ctx; inst->ctx = ctx; @@ -279,16 +288,6 @@ /* to eable vp9 hw.*/ inst->vdec.port.type = PORT_TYPE_HEVC; - /* init vfm */ - inst->vfm.ctx = ctx; - inst->vfm.ada_ctx = &inst->vdec; - ret = vcodec_vfm_init(&inst->vfm); - if (ret) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "init vfm failed.\n"); - goto err; - } - /* probe info from the stream */ inst->vsi = kzalloc(sizeof(struct vdec_vp9_vsi), GFP_KERNEL); if (!inst->vsi) { @@ -297,7 +296,7 @@ } /* alloc the header buffer to be used cache sps or spp etc.*/ - inst->vsi->header_buf = kzalloc(HEADER_BUFFER_SIZE, GFP_KERNEL); + inst->vsi->header_buf = vzalloc(HEADER_BUFFER_SIZE); if (!inst->vsi->header_buf) { ret = -ENOMEM; goto err; @@ -319,14 +318,10 @@ goto err; } - //dump_init(); - return 0; err: - if (inst) - vcodec_vfm_release(&inst->vfm); if (inst && inst->vsi && inst->vsi->header_buf) - kfree(inst->vsi->header_buf); + vfree(inst->vsi->header_buf); if (inst && inst->vsi) kfree(inst->vsi); if (inst) @@ -347,8 +342,8 @@ static int vdec_get_dw_mode(struct vdec_vp9_inst *inst, int dw_mode) { u32 valid_dw_mode = inst->parms.cfg.double_write_mode; - int w = inst->parms.cfg.init_width; - int h = inst->parms.cfg.init_height; + int w = inst->vsi->pic.coded_width; + int h = inst->vsi->pic.coded_height; u32 dw = 0x1; /*1:1*/ switch (valid_dw_mode) { @@ -443,11 +438,11 @@ } static int parse_stream_ucode(struct vdec_vp9_inst *inst, - u8 *buf, u32 size, u64 timestamp) + u8 *buf, u32 size, u64 timestamp, ulong meta_ptr) { int ret = 0; - ret = vdec_write_nalu(inst, buf, size, timestamp); + ret = vdec_write_nalu(inst, buf, size, timestamp, meta_ptr); if (ret < 0) { v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "write frame data failed. err: %d\n", ret); @@ -458,7 +453,7 @@ wait_for_completion_timeout(&inst->comp, msecs_to_jiffies(1000)); - return inst->vsi->dec.dpb_sz ? 0 : -1; + return inst->vsi->pic.dpb_frames ? 0 : -1; } static int parse_stream_ucode_dma(struct vdec_vp9_inst *inst, @@ -479,7 +474,7 @@ wait_for_completion_timeout(&inst->comp, msecs_to_jiffies(1000)); - return inst->vsi->dec.dpb_sz ? 0 : -1; + return inst->vsi->pic.dpb_frames ? 0 : -1; } static int parse_stream_cpu(struct vdec_vp9_inst *inst, u8 *buf, u32 size) @@ -528,7 +523,7 @@ if (inst->ctx->param_sets_from_ucode) { ret = parse_stream_ucode(inst, s->data, - s->len, bs->timestamp); + s->len, bs->timestamp, 0); } else { ret = parse_stream_cpu(inst, s->data, s->len); } @@ -539,7 +534,7 @@ } } else { if (inst->ctx->param_sets_from_ucode) { - ret = parse_stream_ucode(inst, buf, size, bs->timestamp); + ret = parse_stream_ucode(inst, buf, size, bs->timestamp, bs->meta_ptr); } else { ret = parse_stream_cpu(inst, buf, size); } @@ -552,19 +547,13 @@ static void vdec_vp9_deinit(unsigned long h_vdec) { - ulong flags; struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec; struct aml_vcodec_ctx *ctx = inst->ctx; video_decoder_release(&inst->vdec); - vcodec_vfm_release(&inst->vfm); - - //dump_deinit(); - - spin_lock_irqsave(&ctx->slock, flags); if (inst->vsi && inst->vsi->header_buf) - kfree(inst->vsi->header_buf); + vfree(inst->vsi->header_buf); if (inst->vsi) kfree(inst->vsi); @@ -572,54 +561,11 @@ kfree(inst); ctx->drv_handle = 0; - spin_unlock_irqrestore(&ctx->slock, flags); need_trigger = false; dump_cnt = 0; } -static int vdec_vp9_get_fb(struct vdec_vp9_inst *inst, struct vdec_v4l2_buffer **out) -{ - return get_fb_from_queue(inst->ctx, out); -} - -static void vdec_vp9_get_vf(struct vdec_vp9_inst *inst, struct vdec_v4l2_buffer **out) -{ - struct vframe_s *vf = NULL; - struct vdec_v4l2_buffer *fb = NULL; - - vf = peek_video_frame(&inst->vfm); - if (!vf) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "there is no vframe.\n"); - *out = NULL; - return; - } - - vf = get_video_frame(&inst->vfm); - if (!vf) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, - "the vframe is avalid.\n"); - *out = NULL; - return; - } - - atomic_set(&vf->use_cnt, 1); - - fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; - fb->vf_handle = (unsigned long)vf; - fb->status = FB_ST_DISPLAY; - - *out = fb; - - //pr_info("%s, %d\n", __func__, fb->base_y.bytes_used); - //dump_write(fb->base_y.vaddr, fb->base_y.bytes_used); - //dump_write(fb->base_c.vaddr, fb->base_c.bytes_used); - - /* convert yuv format. */ - //swap_uv(fb->base_c.vaddr, fb->base_c.size); -} - static void add_prefix_data(struct vp9_superframe_split *s, u8 **out, u32 *out_size) { @@ -770,7 +716,7 @@ for (i = 0; i < ARRAY_SIZE(vp9_trigger_framesize); i++) { frame_size = vp9_trigger_framesize[i]; ret = vdec_vframe_write(vdec, p, - frame_size, 0); + frame_size, 0, 0); v4l_dbg(vdec->ctx, V4L_DEBUG_CODEC_ERROR, "write trigger frame %d\n", ret); p += frame_size; @@ -778,7 +724,7 @@ } static int vdec_write_nalu(struct vdec_vp9_inst *inst, - u8 *buf, u32 size, u64 ts) + u8 *buf, u32 size, u64 ts, ulong meta_ptr) { int ret = 0; struct aml_vdec_adapt *vdec = &inst->vdec; @@ -808,10 +754,10 @@ /*add headers.*/ add_prefix_data(&s, &data, &length); - ret = vdec_vframe_write(vdec, data, length, ts); + ret = vdec_vframe_write(vdec, data, length, ts, 0); vfree(data); } else { - ret = vdec_vframe_write(vdec, buf, size, ts); + ret = vdec_vframe_write(vdec, buf, size, ts, meta_ptr); } return ret; @@ -845,18 +791,14 @@ { struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec; struct aml_vdec_adapt *vdec = &inst->vdec; - u8 *buf; - u32 size; + u8 *buf = (u8 *) bs->vaddr; + u32 size = bs->size; int ret = -1; if (bs == NULL) return -1; - buf = (u8 *) bs->vaddr; - size = bs->size; - if (vdec_input_full(vdec)) { - ATRACE_COUNTER("vdec_input_full", 0); return -EAGAIN; } @@ -878,7 +820,8 @@ ret = vdec_vframe_write(vdec, s->data, s->len, - bs->timestamp); + bs->timestamp, + 0); } else if (bs->model == VB2_MEMORY_DMABUF || bs->model == VB2_MEMORY_USERPTR) { ret = vdec_vframe_write_with_dma(vdec, @@ -891,10 +834,8 @@ if ((!inst->ctx->param_sets_from_ucode) && (*res_chg = monitor_res_change(inst, buf, size))) return 0; - - ret = vdec_write_nalu(inst, buf, size, bs->timestamp); + ret = vdec_write_nalu(inst, buf, size, bs->timestamp, bs->meta_ptr); } - ATRACE_COUNTER("v4l2_decode_write", ret); return ret; } @@ -917,6 +858,12 @@ "parms status: %u\n", parms->parms_status); } +static void get_param_comp_buf_info(struct vdec_vp9_inst *inst, + struct vdec_comp_buf_info *params) +{ + memcpy(params, &inst->comp_info, sizeof(*params)); +} + static int vdec_vp9_get_param(unsigned long h_vdec, enum vdec_get_param_type type, void *out) { @@ -924,20 +871,12 @@ struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec; if (!inst) { - v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "the vp9 inst of dec is invalid.\n"); return -1; } switch (type) { - case GET_PARAM_DISP_FRAME_BUFFER: - vdec_vp9_get_vf(inst, out); - break; - - case GET_PARAM_FREE_FRAME_BUFFER: - ret = vdec_vp9_get_fb(inst, out); - break; - case GET_PARAM_PIC_INFO: get_pic_info(inst, out); break; @@ -953,6 +892,21 @@ case GET_PARAM_CONFIG_INFO: get_param_config_info(inst, out); break; + + case GET_PARAM_DW_MODE: + { + u32 *mode = out; + u32 m = inst->ctx->config.parm.dec.cfg.double_write_mode; + if (m <= 16) + *mode = inst->ctx->config.parm.dec.cfg.double_write_mode; + else + *mode = vdec_get_dw_mode(inst, 0); + break; + } + case GET_PARAM_COMP_BUF_INFO: + get_param_comp_buf_info(inst, out); + break; + default: v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "invalid get parameter type=%d\n", type); @@ -973,6 +927,7 @@ struct vdec_pic_info *pic = &inst->vsi->pic; struct vdec_vp9_dec_info *dec = &inst->vsi->dec; struct v4l2_rect *rect = &inst->vsi->crop; + int dw = inst->parms.cfg.double_write_mode; /* fill visible area size that be used for EGL. */ pic->visible_width = ps->visible_width; @@ -988,11 +943,16 @@ pic->coded_width = ps->coded_width; pic->coded_height = ps->coded_height; - pic->y_len_sz = pic->coded_width * pic->coded_height; + pic->y_len_sz = ALIGN(vdec_pic_scale(inst, pic->coded_width, dw), 64) * + ALIGN(vdec_pic_scale(inst, pic->coded_height, dw), 64); pic->c_len_sz = pic->y_len_sz >> 1; /* calc DPB size */ + pic->dpb_frames = ps->dpb_frames; + pic->dpb_margin = ps->dpb_margin; + pic->vpp_margin = ps->dpb_margin; dec->dpb_sz = ps->dpb_size; + pic->field = ps->field; inst->parms.ps = *ps; inst->parms.parms_status |= @@ -1002,10 +962,15 @@ complete(&inst->comp); v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, - "Parse from ucode, crop(%d x %d), coded(%d x %d) dpb: %d\n", - ps->visible_width, ps->visible_height, - ps->coded_width, ps->coded_height, - ps->dpb_size); + "Parse from ucode, visible(%d x %d), coded(%d x %d)\n", + pic->visible_width, pic->visible_height, + pic->coded_width, pic->coded_height); +} + +static void set_param_comp_buf_info(struct vdec_vp9_inst *inst, + struct vdec_comp_buf_info *info) +{ + memcpy(&inst->comp_info, info, sizeof(*info)); } static void set_param_hdr_info(struct vdec_vp9_inst *inst, @@ -1030,6 +995,12 @@ "VP9 post event: %d\n", *event); } +static void set_pic_info(struct vdec_vp9_inst *inst, + struct vdec_pic_info *pic) +{ + inst->vsi->pic = *pic; +} + static int vdec_vp9_set_param(unsigned long h_vdec, enum vdec_set_param_type type, void *in) { @@ -1037,7 +1008,7 @@ struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec; if (!inst) { - v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "the vp9 inst of dec is invalid.\n"); return -1; } @@ -1051,6 +1022,10 @@ set_param_ps_info(inst, in); break; + case SET_PARAM_COMP_BUF_INFO: + set_param_comp_buf_info(inst, in); + break; + case SET_PARAM_HDR_INFO: set_param_hdr_info(inst, in); break; @@ -1058,6 +1033,11 @@ case SET_PARAM_POST_EVENT: set_param_post_event(inst, in); break; + + case SET_PARAM_PIC_INFO: + set_pic_info(inst, in); + break; + default: v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "invalid set parameter type=%d\n", type);
diff --git a/drivers/amvdec_ports/utils/common.c b/drivers/amvdec_ports/utils/common.c index 1d621da..67cf93b 100644 --- a/drivers/amvdec_ports/utils/common.c +++ b/drivers/amvdec_ports/utils/common.c
@@ -1,22 +1,3 @@ -/* -* Copyright (C) 2017 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. -* -* You should have received a copy of the GNU General Public License along -* with this program; if not, write to the Free Software Foundation, Inc., -* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -* -* Description: -*/ #include <linux/kernel.h> #include <linux/types.h> #include <linux/vmalloc.h> @@ -240,3 +221,12 @@ _pr_hex("print hex ending. len %d\n\n", l); } +bool is_over_size(int w, int h, int size) +{ + if (h != 0 && (w > size / h)) + return true; + + return false; +} + +
diff --git a/drivers/amvdec_ports/utils/common.h b/drivers/amvdec_ports/utils/common.h index dd4c51f..89ae50b 100644 --- a/drivers/amvdec_ports/utils/common.h +++ b/drivers/amvdec_ports/utils/common.h
@@ -1,22 +1,3 @@ -/* -* Copyright (C) 2017 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. -* -* You should have received a copy of the GNU General Public License along -* with this program; if not, write to the Free Software Foundation, Inc., -* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -* -* Description: -*/ #ifndef UTILS_COMMON_H #define UTILS_COMMON_H @@ -77,7 +58,7 @@ #ifndef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER /** * YUV colorspace type. - * These values match the ones defined by ISO/IEC 23001-8_2013 § 7.3. + * These values match the ones defined by ISO/IEC 23001-8_2013 ¡ì 7.3. */ enum AVColorSpace { AVCOL_SPC_RGB = 0, ///< order of coefficients is actually GBR, also IEC 61966-2-1 (sRGB) @@ -101,7 +82,7 @@ /** * Chromaticity coordinates of the source primaries. - * These values match the ones defined by ISO/IEC 23001-8_2013 § 7.1. + * These values match the ones defined by ISO/IEC 23001-8_2013 ¡ì 7.1. */ enum AVColorPrimaries { AVCOL_PRI_RESERVED0 = 0, @@ -125,7 +106,7 @@ /** * Color Transfer Characteristic. - * These values match the ones defined by ISO/IEC 23001-8_2013 § 7.2. + * These values match the ones defined by ISO/IEC 23001-8_2013 ¡ì 7.2. */ enum AVColorTransferCharacteristic { AVCOL_TRC_RESERVED0 = 0, @@ -151,8 +132,8 @@ AVCOL_TRC_ARIB_STD_B67 = 18, ///< ARIB STD-B67, known as "Hybrid log-gamma" AVCOL_TRC_NB ///< Not part of ABI }; - #endif + //fmt const char *av_color_space_name(enum AVColorSpace space); const char *av_color_primaries_name(enum AVColorPrimaries primaries); @@ -169,4 +150,6 @@ //debug void print_hex_debug(u8 *data, u32 len, int max); -#endif +bool is_over_size(int w, int h, int size); + +#endif \ No newline at end of file
diff --git a/drivers/amvdec_ports/vdec_drv_if.c b/drivers/amvdec_ports/vdec_drv_if.c index ed9f053..01510c5 100644 --- a/drivers/amvdec_ports/vdec_drv_if.c +++ b/drivers/amvdec_ports/vdec_drv_if.c
@@ -116,6 +116,19 @@ return ret; } +int vdec_if_set_param(struct aml_vcodec_ctx *ctx, + enum vdec_set_param_type type, void *in) +{ + int ret = 0; + + if (ctx->drv_handle == 0) + return -EIO; + + ret = ctx->dec_if->set_param(ctx->drv_handle, type, in); + + return ret; +} + void vdec_if_deinit(struct aml_vcodec_ctx *ctx) { if (ctx->drv_handle == 0)
diff --git a/drivers/amvdec_ports/vdec_drv_if.h b/drivers/amvdec_ports/vdec_drv_if.h index a04d832..29911f8 100644 --- a/drivers/amvdec_ports/vdec_drv_if.h +++ b/drivers/amvdec_ports/vdec_drv_if.h
@@ -50,33 +50,48 @@ /** * struct vdec_fb_status - decoder frame buffer status - * @FB_ST_NORMAL : initial state - * @FB_ST_DISPLAY : frmae buffer is ready to be displayed + * @FB_ST_INIT : initial state + * @FB_ST_DECODER : frame buffer be allocted by decoder. + * @FB_ST_VPP : frame buffer be allocate by vpp. + * @FB_ST_DISPLAY : frame buffer is ready to be displayed. * @FB_ST_FREE : frame buffer is not used by decoder any more */ enum vdec_fb_status { - FB_ST_NORMAL, + FB_ST_INIT, + FB_ST_DECODER, + FB_ST_VPP, + FB_ST_GE2D, FB_ST_DISPLAY, FB_ST_FREE }; -/* For GET_PARAM_DISP_FRAME_BUFFER and GET_PARAM_FREE_FRAME_BUFFER, +enum vdec_dw_mode { + VDEC_DW_AFBC_ONLY = 0, + VDEC_DW_AFBC_1_1_DW = 1, + VDEC_DW_AFBC_1_4_DW = 2, + VDEC_DW_AFBC_x2_1_4_DW = 3, + VDEC_DW_AFBC_1_2_DW = 4, + VDEC_DW_NO_AFBC = 16, + VDEC_DW_AFBC_AUTO_1_2 = 0x100, + VDEC_DW_AFBC_AUTO_1_4 = 0x200, +}; + +/* * the caller does not own the returned buffer. The buffer will not be * released before vdec_if_deinit. - * GET_PARAM_DISP_FRAME_BUFFER : get next displayable frame buffer, - * struct vdec_fb** - * GET_PARAM_FREE_FRAME_BUFFER : get non-referenced framebuffer, vdec_fb** * GET_PARAM_PIC_INFO : get picture info, struct vdec_pic_info* * GET_PARAM_CROP_INFO : get crop info, struct v4l2_crop* * GET_PARAM_DPB_SIZE : get dpb size, unsigned int* + * GET_PARAM_DW_MODE: : get double write mode, unsigned int* + * GET_PARAM_COMP_BUF_INFO : get compressed buf info, struct vdec_comp_buf_info* */ enum vdec_get_param_type { - GET_PARAM_DISP_FRAME_BUFFER, - GET_PARAM_FREE_FRAME_BUFFER, GET_PARAM_PIC_INFO, GET_PARAM_CROP_INFO, GET_PARAM_DPB_SIZE, - GET_PARAM_CONFIG_INFO + GET_PARAM_CONFIG_INFO, + GET_PARAM_DW_MODE, + GET_PARAM_COMP_BUF_INFO }; /* @@ -85,8 +100,11 @@ enum vdec_set_param_type { SET_PARAM_WRITE_FRAME_SYNC, SET_PARAM_PS_INFO, + SET_PARAM_COMP_BUF_INFO, SET_PARAM_HDR_INFO, - SET_PARAM_POST_EVENT + SET_PARAM_POST_EVENT, + SET_PARAM_PIC_INFO, + SET_PARAM_CFG_INFO }; /** @@ -138,7 +156,10 @@ * @type : [in] input parameter type * @out : [out] buffer to store query result */ -int vdec_if_get_param(struct aml_vcodec_ctx *ctx, enum vdec_get_param_type type, - void *out); +int vdec_if_get_param(struct aml_vcodec_ctx *ctx, + enum vdec_get_param_type type, void *out); + +int vdec_if_set_param(struct aml_vcodec_ctx *ctx, + enum vdec_set_param_type type, void *in); #endif
diff --git a/drivers/common/chips/chips.c b/drivers/common/chips/chips.c index d692ca8..158e32c 100644 --- a/drivers/common/chips/chips.c +++ b/drivers/common/chips/chips.c
@@ -25,7 +25,7 @@ #include <linux/mm.h> #include <linux/amlogic/media/utils/vformat.h> -#include <linux/amlogic/cpu_version.h> +#include <linux/amlogic/media/registers/cpu_version.h> #include "../../stream_input/amports/amports_priv.h" #include "../../frame_provider/decoder/utils/vdec.h" #include "chips.h" @@ -78,6 +78,14 @@ {AM_MESON_CPU_MAJOR_ID_TL1, "tl1"}, {AM_MESON_CPU_MAJOR_ID_TM2, "tm2"}, {AM_MESON_CPU_MAJOR_ID_SC2, "sc2"}, + {AM_MESON_CPU_MAJOR_ID_T5, "t5"}, + {AM_MESON_CPU_MAJOR_ID_T5D, "t5d"}, + {AM_MESON_CPU_MAJOR_ID_T7, "t7"}, + {AM_MESON_CPU_MAJOR_ID_S4, "s4"}, + {AM_MESON_CPU_MAJOR_ID_T3, "t3"}, + {AM_MESON_CPU_MAJOR_ID_P1, "p1"}, + {AM_MESON_CPU_MAJOR_ID_S4D, "s4d"}, + {AM_MESON_CPU_MAJOR_ID_T5W, "t5w"}, {0, NULL}, };
diff --git a/drivers/common/chips/decoder_cpu_ver_info.c b/drivers/common/chips/decoder_cpu_ver_info.c index d74728c..af162b8 100644 --- a/drivers/common/chips/decoder_cpu_ver_info.c +++ b/drivers/common/chips/decoder_cpu_ver_info.c
@@ -24,7 +24,7 @@ #include <linux/errno.h> #include <linux/platform_device.h> #include <linux/of_device.h> -#include <linux/amlogic/cpu_version.h> +#include <linux/amlogic/media/registers/cpu_version.h> #include "decoder_cpu_ver_info.h" #define DECODE_CPU_VER_ID_NODE_NAME "cpu_ver_name" @@ -32,6 +32,7 @@ #define MAJOR_ID_START AM_MESON_CPU_MAJOR_ID_M6 static enum AM_MESON_CPU_MAJOR_ID cpu_ver_id = AM_MESON_CPU_MAJOR_ID_MAX; +static int cpu_sub_id = 0; static enum AM_MESON_CPU_MAJOR_ID cpu_ver_info[AM_MESON_CPU_MAJOR_ID_MAX - MAJOR_ID_START]= { @@ -57,13 +58,22 @@ AM_MESON_CPU_MAJOR_ID_G12B, AM_MESON_CPU_MAJOR_ID_GXLX2, AM_MESON_CPU_MAJOR_ID_SM1, - AM_MESON_CPU_MAJOR_ID_RES_0x2c, + AM_MESON_CPU_MAJOR_ID_A1, AM_MESON_CPU_MAJOR_ID_RES_0x2d, AM_MESON_CPU_MAJOR_ID_TL1, AM_MESON_CPU_MAJOR_ID_TM2, - AM_MESON_CPU_MAJOR_ID_RES_0x30, + AM_MESON_CPU_MAJOR_ID_C1, AM_MESON_CPU_MAJOR_ID_RES_0x31, AM_MESON_CPU_MAJOR_ID_SC2, + AM_MESON_CPU_MAJOR_ID_C2, + AM_MESON_CPU_MAJOR_ID_T5, + AM_MESON_CPU_MAJOR_ID_T5D, + AM_MESON_CPU_MAJOR_ID_T7, + AM_MESON_CPU_MAJOR_ID_S4, + AM_MESON_CPU_MAJOR_ID_T3, + AM_MESON_CPU_MAJOR_ID_P1, + AM_MESON_CPU_MAJOR_ID_S4D, + AM_MESON_CPU_MAJOR_ID_T5W, }; static const struct of_device_id cpu_ver_of_match[] = { @@ -114,32 +124,90 @@ .compatible = "amlogic, cpu-major-id-sc2", .data = &cpu_ver_info[AM_MESON_CPU_MAJOR_ID_SC2 - MAJOR_ID_START], }, + { + .compatible = "amlogic, cpu-major-id-t5", + .data = &cpu_ver_info[AM_MESON_CPU_MAJOR_ID_T5 - MAJOR_ID_START], + }, + { + .compatible = "amlogic, cpu-major-id-t5d", + .data = &cpu_ver_info[AM_MESON_CPU_MAJOR_ID_T5D - MAJOR_ID_START], + }, + { + .compatible = "amlogic, cpu-major-id-t7", + .data = &cpu_ver_info[AM_MESON_CPU_MAJOR_ID_T7 - MAJOR_ID_START], + }, + { + .compatible = "amlogic, cpu-major-id-s4", + .data = &cpu_ver_info[AM_MESON_CPU_MAJOR_ID_S4 - MAJOR_ID_START], + }, + { + .compatible = "amlogic, cpu-major-id-t3", + .data = &cpu_ver_info[AM_MESON_CPU_MAJOR_ID_T3 - MAJOR_ID_START], + }, + { + .compatible = "amlogic, cpu-major-id-p1", + .data = &cpu_ver_info[AM_MESON_CPU_MAJOR_ID_P1 - MAJOR_ID_START], + }, + { + .compatible = "amlogic, cpu-major-id-s4d", + .data = &cpu_ver_info[AM_MESON_CPU_MAJOR_ID_S4D - MAJOR_ID_START], + }, + { + .compatible = "amlogic, cpu-major-id-t5w", + .data = &cpu_ver_info[AM_MESON_CPU_MAJOR_ID_T5W - MAJOR_ID_START], + }, {}, }; -static bool get_cpu_id_from_dtb(enum AM_MESON_CPU_MAJOR_ID *pidType) -{ - struct device_node *pNode = NULL; - struct platform_device* pDev = NULL; - const struct of_device_id *pMatch = NULL; +static const int cpu_sub_info[] = { + AM_MESON_CPU_MINOR_ID_REVB_G12B, + AM_MESON_CPU_MINOR_ID_REVB_TM2, + AM_MESON_CPU_MINOR_ID_S4_S805X2, +}; - pNode = of_find_node_by_name(NULL, DECODE_CPU_VER_ID_NODE_NAME); - if (NULL == pNode) { +static const struct of_device_id cpu_sub_id_of_match[] = { + { + .compatible = "amlogic, cpu-major-id-g12b-b", + .data = &cpu_sub_info[0], + }, + { + .compatible = "amlogic, cpu-major-id-tm2-b", + .data = &cpu_sub_info[1], + }, + { + .compatible = "amlogic, cpu-major-id-s4-805x2", + .data = &cpu_sub_info[2], + }, +}; + +static bool get_cpu_id_from_dtb(enum AM_MESON_CPU_MAJOR_ID *pid_type, int *sub_id) +{ + struct device_node *pnode = NULL; + struct platform_device *pdev = NULL; + const struct of_device_id *pmatch = NULL; + + pnode = of_find_node_by_name(NULL, DECODE_CPU_VER_ID_NODE_NAME); + if (NULL == pnode) { pr_err("No find node.\n"); return -EINVAL; } - pDev = of_find_device_by_node(pNode); - if (NULL == pDev) + pdev = of_find_device_by_node(pnode); + if (NULL == pdev) return -EINVAL; - pMatch = of_match_device(cpu_ver_of_match, &pDev->dev); - if (NULL == pMatch) { - pr_err("No find of_match_device\n"); - return -EINVAL; + pmatch = of_match_device(cpu_ver_of_match, &pdev->dev); + if (NULL == pmatch) { + pmatch = of_match_device(cpu_sub_id_of_match, &pdev->dev); + if (NULL == pmatch) { + pr_err("No find of_match_device\n"); + return -EINVAL; + } } - *pidType = *(enum AM_MESON_CPU_MAJOR_ID *)pMatch->data; + *pid_type = (enum AM_MESON_CPU_MAJOR_ID)(*(int *)pmatch->data) & (MAJOY_ID_MASK); + + *sub_id = ((*(int *)pmatch->data) & (SUB_ID_MASK)) >> 8; return AM_SUCESS; } @@ -147,15 +215,20 @@ static void initial_cpu_id(void) { enum AM_MESON_CPU_MAJOR_ID id_type = AM_MESON_CPU_MAJOR_ID_MAX; + int sub_id = 0; - if (AM_SUCESS == get_cpu_id_from_dtb(&id_type)) + if (AM_SUCESS == get_cpu_id_from_dtb(&id_type, &sub_id)) { cpu_ver_id = id_type; - else + cpu_sub_id = sub_id; + } else { cpu_ver_id = (enum AM_MESON_CPU_MAJOR_ID)get_cpu_type(); + cpu_sub_id = (is_meson_rev_b()) ? CHIP_REVB : CHIP_REVA; + } - if (AM_MESON_CPU_MAJOR_ID_G12B == cpu_ver_id) - if (is_meson_rev_b()) - cpu_ver_id = AM_MESON_CPU_MAJOR_ID_TL1; + if ((AM_MESON_CPU_MAJOR_ID_G12B == cpu_ver_id) && (CHIP_REVB == cpu_sub_id)) + cpu_ver_id = AM_MESON_CPU_MAJOR_ID_TL1; + + pr_info("vdec init cpu id: 0x%x(%d)", cpu_ver_id, cpu_sub_id); } enum AM_MESON_CPU_MAJOR_ID get_cpu_major_id(void) @@ -167,10 +240,32 @@ } EXPORT_SYMBOL(get_cpu_major_id); +int get_cpu_sub_id(void) +{ + return cpu_sub_id; +} +EXPORT_SYMBOL(get_cpu_sub_id); + +bool is_cpu_meson_revb(void) +{ + if (AM_MESON_CPU_MAJOR_ID_MAX == cpu_ver_id) + initial_cpu_id(); + + return (cpu_sub_id == CHIP_REVB); +} +EXPORT_SYMBOL(is_cpu_meson_revb); + bool is_cpu_tm2_revb(void) { - return ((get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_TM2) && - (is_meson_rev_b())); + return ((get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_TM2) + && (is_cpu_meson_revb())); } EXPORT_SYMBOL(is_cpu_tm2_revb); +bool is_cpu_s4_s805x2(void) +{ + return ((get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_S4) + && (get_cpu_sub_id() == CHIP_REVX)); +} +EXPORT_SYMBOL(is_cpu_s4_s805x2); +
diff --git a/drivers/common/chips/decoder_cpu_ver_info.h b/drivers/common/chips/decoder_cpu_ver_info.h index 673b001..6129244 100644 --- a/drivers/common/chips/decoder_cpu_ver_info.h +++ b/drivers/common/chips/decoder_cpu_ver_info.h
@@ -19,9 +19,11 @@ */ #ifndef DECODER_CPU_VER_INFO_H #define DECODER_CPU_VER_INFO_H +#include <linux/amlogic/media/registers/cpu_version.h> +/* majoy chip id define */ +#define MAJOY_ID_MASK (0x000000ff) -enum AM_MESON_CPU_MAJOR_ID -{ +enum AM_MESON_CPU_MAJOR_ID { AM_MESON_CPU_MAJOR_ID_M6 = 0x16, AM_MESON_CPU_MAJOR_ID_M6TV = 0x17, AM_MESON_CPU_MAJOR_ID_M6TVL = 0x18, @@ -44,18 +46,50 @@ AM_MESON_CPU_MAJOR_ID_G12B = 0x29, AM_MESON_CPU_MAJOR_ID_GXLX2 = 0x2a, AM_MESON_CPU_MAJOR_ID_SM1 = 0x2b, - AM_MESON_CPU_MAJOR_ID_RES_0x2c, + AM_MESON_CPU_MAJOR_ID_A1 = 0x2c, AM_MESON_CPU_MAJOR_ID_RES_0x2d, AM_MESON_CPU_MAJOR_ID_TL1 = 0x2e, AM_MESON_CPU_MAJOR_ID_TM2 = 0x2f, - AM_MESON_CPU_MAJOR_ID_RES_0x30, + AM_MESON_CPU_MAJOR_ID_C1 = 0x30, AM_MESON_CPU_MAJOR_ID_RES_0x31, AM_MESON_CPU_MAJOR_ID_SC2 = 0x32, - AM_MESON_CPU_MAJOR_ID_RES_0x33, - AM_MESON_CPU_MAJOR_ID_T5, + AM_MESON_CPU_MAJOR_ID_C2 = 0x33, + AM_MESON_CPU_MAJOR_ID_T5 = 0x34, + AM_MESON_CPU_MAJOR_ID_T5D = 0x35, + AM_MESON_CPU_MAJOR_ID_T7 = 0x36, + AM_MESON_CPU_MAJOR_ID_S4 = 0x37, + AM_MESON_CPU_MAJOR_ID_T3 = 0x38, + AM_MESON_CPU_MAJOR_ID_P1 = 0x39, + AM_MESON_CPU_MAJOR_ID_S4D = 0x3a, + AM_MESON_CPU_MAJOR_ID_T5W = 0x3b, AM_MESON_CPU_MAJOR_ID_MAX, }; +/* chips sub id define */ +#define CHIP_REVA 0x0 +#define CHIP_REVB 0x1 +#define CHIP_REVC 0x2 +#define CHIP_REVX 0x10 + +#define REVB_MASK (CHIP_REVB << 8) +#define REVC_MASK (CHIP_REVC << 8) +#define REVX_MASK (CHIP_REVX << 8) + +#define SUB_ID_MASK (REVB_MASK | REVC_MASK | REVX_MASK) + +#define AM_MESON_CPU_MINOR_ID_REVB_G12B (REVB_MASK | AM_MESON_CPU_MAJOR_ID_G12B) +#define AM_MESON_CPU_MINOR_ID_REVB_TM2 (REVB_MASK | AM_MESON_CPU_MAJOR_ID_TM2) +#define AM_MESON_CPU_MINOR_ID_S4_S805X2 (REVX_MASK | AM_MESON_CPU_MAJOR_ID_S4) + +/* export functions */ enum AM_MESON_CPU_MAJOR_ID get_cpu_major_id(void); + +bool is_cpu_meson_revb(void); + bool is_cpu_tm2_revb(void); + +int get_cpu_sub_id(void); + +bool is_cpu_s4_s805x2(void); + #endif
diff --git a/drivers/common/firmware/firmware_drv.c b/drivers/common/firmware/firmware_drv.c index 85a81e6..9422198 100644 --- a/drivers/common/firmware/firmware_drv.c +++ b/drivers/common/firmware/firmware_drv.c
@@ -25,7 +25,7 @@ #include <linux/slab.h> #include <linux/amlogic/media/utils/vformat.h> -#include <linux/amlogic/cpu_version.h> +#include <linux/amlogic/media/registers/cpu_version.h> #include "../../stream_input/amports/amports_priv.h" #include "../../frame_provider/decoder/utils/vdec.h" #include "firmware_priv.h" @@ -34,13 +34,14 @@ #include <linux/amlogic/media/utils/log.h> #include <linux/firmware.h> #include <linux/amlogic/tee.h> -#include <linux/amlogic/major.h> +//#include <linux/amlogic/major.h> //if kernel is 4.9 then use this one +#include <uapi/linux/major.h> #include <linux/cdev.h> #include <linux/crc32.h> #include "../chips/decoder_cpu_ver_info.h" /* major.minor */ -#define PACK_VERS "v0.2" +#define PACK_VERS "v0.3" #define CLASS_NAME "firmware_codec" #define DEV_NAME "firmware_vdec" @@ -75,6 +76,7 @@ struct fw_mgr_s *g_mgr; struct fw_dev_s *g_dev; +struct package_head_s package_head; static u32 debug; static u32 detail; @@ -85,7 +87,7 @@ struct fw_mgr_s *mgr = g_mgr; struct fw_info_s *info; - pr_info("[%s], the fw (%s) will be loaded.\n", + pr_info("[%s], the fw (%s) will be loaded...\n", tee_enabled() ? "TEE" : "LOCAL", get_fw_format_name(format)); @@ -109,6 +111,7 @@ break; } + out: mutex_unlock(&mutex); @@ -341,6 +344,8 @@ struct fw_info_s *info; unsigned int secs = 0; struct tm tm; + char history_change_id[7] = {0}; + int i; mutex_lock(&mutex); @@ -350,7 +355,21 @@ } /* shows version of driver. */ - pr_info("The driver version is %s\n", PACK_VERS); + pr_info("The ucode driver version is %s\n", PACK_VERS); + + pr_info("The firmware version is %d.%d.%d-g%s\n", + (package_head.version >> 16) & 0xff, + package_head.version & 0xff, + package_head.submit_count, + package_head.commit); + + pr_info("change id history:\n"); + for (i = 0; i < 5; i++) { + memset(history_change_id, 0, sizeof(history_change_id)); + strncpy(history_change_id, &(package_head.history_change_id[i * 6]), 6); + pr_info("\t%s\n", history_change_id); + + } list_for_each_entry(info, &mgr->fw_head, node) { if (IS_ERR_OR_NULL(info->data)) @@ -375,7 +394,8 @@ secs = info->data->head.time - sys_tz.tz_minuteswest * 60; - time_to_tm(secs, 0, &tm); + //time_to_tm(secs, 0, &tm);//kernel4.9 + time64_to_tm(secs, 0, &tm); pr_info("%s %-16s, %02d:%02d:%02d %d/%d/%ld, %s %-8s, %s %-8s, %s %s\n", "fmt:", info->data->head.format, @@ -577,6 +597,7 @@ if (ret != 2) return -1; + package_head = pack->head; major_fw = (pack->head.version >> 16) & 0xff; minor_fw = pack->head.version & 0xff; @@ -595,7 +616,7 @@ if (debug) { pr_info("The package has %d fws totally.\n", pack->head.total); pr_info("The driver ver is v%d.%d\n", major, minor); - pr_info("The firmware ver is v%d.%d\n", major_fw, minor_fw); + pr_info("The firmware ver is v%d.%d.%d\n", major_fw, minor_fw, pack->head.submit_count); } return 0; @@ -910,6 +931,7 @@ return count; } +#if 0 //kernel4.9 static struct class_attribute fw_class_attrs[] = { __ATTR(info, 0664, info_show, info_store), __ATTR(reload, 0664, reload_show, reload_store), @@ -921,7 +943,26 @@ .name = CLASS_NAME, .class_attrs = fw_class_attrs, }; +#else //below is for kernel 4.19 and 5.4 +static CLASS_ATTR_RW(info); +static CLASS_ATTR_RW(reload); +static CLASS_ATTR_RW(debug); +static struct attribute *fw_class_attrs[] = { + &class_attr_info.attr, + &class_attr_reload.attr, + &class_attr_debug.attr, + NULL +}; + +ATTRIBUTE_GROUPS(fw_class); + +static struct class fw_class = { + .name = CLASS_NAME, + .class_groups = fw_class_groups, +}; + +#endif static int fw_driver_init(void) { int ret = -1;
diff --git a/drivers/common/firmware/firmware_priv.h b/drivers/common/firmware/firmware_priv.h index 410745b..d901f9d 100644 --- a/drivers/common/firmware/firmware_priv.h +++ b/drivers/common/firmware/firmware_priv.h
@@ -85,7 +85,11 @@ int checksum; int total; int version; - char reserved[128]; + int submit_count; + char change_id[16]; + char commit[16]; + char history_change_id[30]; + char reserved[62]; }; struct package_s {
diff --git a/drivers/common/firmware/firmware_type.c b/drivers/common/firmware/firmware_type.c index c232020..8d95c12 100644 --- a/drivers/common/firmware/firmware_type.c +++ b/drivers/common/firmware/firmware_type.c
@@ -76,6 +76,13 @@ {AM_MESON_CPU_MAJOR_ID_TL1, "tl1"}, {AM_MESON_CPU_MAJOR_ID_TM2, "tm2"}, {AM_MESON_CPU_MAJOR_ID_SC2, "sc2"}, + {AM_MESON_CPU_MAJOR_ID_T5, "t5"}, + {AM_MESON_CPU_MAJOR_ID_T5D, "t5d"}, + {AM_MESON_CPU_MAJOR_ID_T7, "t7"}, + {AM_MESON_CPU_MAJOR_ID_S4, "s4"}, + {AM_MESON_CPU_MAJOR_ID_T3, "t3"}, + {AM_MESON_CPU_MAJOR_ID_P1, "p1"}, + {AM_MESON_CPU_MAJOR_ID_S4D, "s4d"}, }; const char *get_fw_format_name(unsigned int format)
diff --git a/drivers/common/firmware/firmware_type.h b/drivers/common/firmware/firmware_type.h index e997057..4615baf 100644 --- a/drivers/common/firmware/firmware_type.h +++ b/drivers/common/firmware/firmware_type.h
@@ -80,6 +80,7 @@ #define OPTEE_VDEC_LEGENCY (0) #define OPTEE_VDEC (1) #define OPTEE_VDEC_HEVC (2) +#define OPTEE_VDEC_HCDEC (3) struct format_name_s { unsigned int format;
diff --git a/drivers/common/media_clock/clk/clk.c b/drivers/common/media_clock/clk/clk.c index 972bcc1..6340c1a 100644 --- a/drivers/common/media_clock/clk/clk.c +++ b/drivers/common/media_clock/clk/clk.c
@@ -27,7 +27,7 @@ #include <linux/slab.h> #include <linux/amlogic/media/utils/vformat.h> -#include <linux/amlogic/cpu_version.h> +#include <linux/amlogic/media/registers/cpu_version.h> #include "../../../stream_input/amports/amports_priv.h" #include "../../../frame_provider/decoder/utils/vdec.h" #include "../../chips/chips.h" @@ -165,7 +165,7 @@ void hcodec_clock_enable(void) { - hcodec_clock_set(1); + hcodec_clock_set(667); } EXPORT_SYMBOL(hcodec_clock_enable); @@ -311,6 +311,21 @@ } EXPORT_SYMBOL(get_clk_with_source); +bool is_hevc_front_back_clk_combined(void) +{ + int cpu_id = get_cpu_major_id(); + + if (cpu_id == AM_MESON_CPU_MAJOR_ID_T5 || + (cpu_id == AM_MESON_CPU_MAJOR_ID_T5D) || + (cpu_id == AM_MESON_CPU_MAJOR_ID_S4) || + (cpu_id == AM_MESON_CPU_MAJOR_ID_S4D) || + (cpu_id == AM_MESON_CPU_MAJOR_ID_T5W)) + return true; + + return false; +} +EXPORT_SYMBOL(is_hevc_front_back_clk_combined); + int vdec_source_changed_for_clk_set(int format, int width, int height, int fps) { int clk = get_clk_with_source(format, width * height * fps); @@ -338,7 +353,8 @@ || format == VFORMAT_AV1) { ret_clk = hevc_clock_set(clk); clock_source_wxhxfps_saved[VDEC_HEVC] = width * height * fps; - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A && + !is_hevc_front_back_clk_combined()) { ret_clk = hevc_back_clock_set(clk); clock_source_wxhxfps_saved[VDEC_HEVCB] = width * height * fps; } @@ -372,7 +388,7 @@ */ return 0; /* ignore don't needed firmare. */ } - mgr = vzalloc(sizeof(struct chip_vdec_clk_s)); + mgr = kmalloc(sizeof(struct chip_vdec_clk_s), GFP_KERNEL); if (!mgr) return -ENOMEM; *mgr = *t_mgr; @@ -381,7 +397,7 @@ */ if (mgr->clock_init) { if (mgr->clock_init()) { - vfree(mgr); + kfree(mgr); return -ENOMEM; } } @@ -404,7 +420,7 @@ int unregister_vdec_clk_mgr(enum vdec_type_e vdec_type) { - vfree(get_current_vdec_chip()->clk_mgr[vdec_type]); + kfree(get_current_vdec_chip()->clk_mgr[vdec_type]); return 0; } @@ -423,7 +439,7 @@ */ return 0; /* ignore don't needed this setting . */ } - p_setting = vzalloc(size); + p_setting = kmalloc(size, GFP_KERNEL); if (!p_setting) return -ENOMEM; memcpy(p_setting, setting, size); @@ -449,7 +465,7 @@ int unregister_vdec_clk_setting(void) { - vfree(get_current_vdec_chip()->clk_setting_array); + kfree(get_current_vdec_chip()->clk_setting_array); return 0; }
diff --git a/drivers/common/media_clock/clk/clk.h b/drivers/common/media_clock/clk/clk.h index 82eec1d..bbc3bee 100644 --- a/drivers/common/media_clock/clk/clk.h +++ b/drivers/common/media_clock/clk/clk.h
@@ -52,6 +52,8 @@ int vdec_source_get(enum vdec_type_e core); int vdec_clk_get(enum vdec_type_e core); +bool is_hevc_front_back_clk_combined(void); + int vdec_source_changed_for_clk_set(int format, int width, int height, int fps); int get_clk_with_source(int format, int w_x_h_fps); @@ -130,7 +132,7 @@ #endif #ifdef VDEC_HAS_HEVC register_vdec_clk_mgr(cpus, VDEC_HEVC, &vdec_hevc_clk_mgr); - if (get_cpu_major_id() >= MESON_CPU_MAJOR_ID_G12A) + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) register_vdec_clk_mgr(cpus, VDEC_HEVCB, &vdec_hevc_back_clk_mgr); #endif #ifdef VDEC_HAS_VDEC_HCODEC
diff --git a/drivers/common/media_clock/clk/clkg12.c b/drivers/common/media_clock/clk/clkg12.c index be2401c..c49d150 100644 --- a/drivers/common/media_clock/clk/clkg12.c +++ b/drivers/common/media_clock/clk/clkg12.c
@@ -114,11 +114,6 @@ WRITE_HHI_REG_BITS(HHI_VDEC2_CLK_CNTL, 0, 8, 1);\ }while(0) -#define CHECK_RET(_ret) if (ret) {debug_print(\ - "%s:%d:function call failed with result: %d\n",\ - __FUNCTION__, __LINE__, _ret);} - - static int clock_real_clk[VDEC_MAX + 1]; static unsigned int set_frq_enable, vdec_frq, hevc_frq, hevcb_frq; @@ -130,19 +125,14 @@ static int gp_pll_user_cb_vdec(struct gp_pll_user_handle_s *user, int event) { - int ret; - debug_print("gp_pll_user_cb_vdec call\n"); if (event == GP_PLL_USER_EVENT_GRANT) { struct clk *clk = clk_get(NULL, "gp0_pll"); if (!IS_ERR(clk)) { - if (is_gp0_div2) { - ret = clk_set_rate(clk, 1296000000UL); - CHECK_RET(ret); - } else { - ret = clk_set_rate(clk, 648000000UL); - CHECK_RET(ret); - } + if (is_gp0_div2) + clk_set_rate(clk, 1296000000UL); + else + clk_set_rate(clk, 648000000UL); VDEC1_SAFE_CLOCK(); VDEC1_CLOCK_OFF(); if (is_gp0_div2) @@ -426,7 +416,9 @@ struct gate_switch_node *node = NULL; char *hevc_mux_str = NULL; - if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SC2) + if ((get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SC2) || + (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5) || + (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5D)) hevc_mux_str = "clk_hevc_mux"; else hevc_mux_str = "clk_hevcf_mux"; @@ -466,7 +458,6 @@ static int vdec_set_clk(int dec, int rate) { struct clk *clk = NULL; - int ret; switch (dec) { case VDEC_1: @@ -506,8 +497,7 @@ return -1; } - ret = clk_set_rate(clk, rate); - CHECK_RET(ret); + clk_set_rate(clk, rate); return 0; } @@ -523,12 +513,12 @@ { gp_pll_user_vdec = gp_pll_user_register("vdec", 0, gp_pll_user_cb_vdec); - if (get_cpu_major_id() >= MESON_CPU_MAJOR_ID_GXL) + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) is_gp0_div2 = false; else is_gp0_div2 = true; - if (get_cpu_major_id() >= MESON_CPU_MAJOR_ID_GXL) { + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) { pr_info("used fix clk for vdec clk source!\n"); //update_vdec_clk_config_settings(1); } @@ -743,9 +733,14 @@ } if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1 && - get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1) + get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1 && + get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5 && + get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5D) clk = 800; + if (is_cpu_s4_s805x2()) + clk = 500; + if (set_frq_enable && vdec_frq) { pr_info("Set the vdec frq is %u MHz\n", vdec_frq); clk = vdec_frq; @@ -841,10 +836,15 @@ if ((clk > 500 && clk != 667)) { if (clock_real_clk[VDEC_HEVC] == 648) return 648; - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5) && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5D)) clk = TL1_HEVC_MAX_CLK; else clk = 667; + + if (is_cpu_s4_s805x2()) + clk = 500; } if (set_frq_enable && hevc_frq) { @@ -1042,6 +1042,14 @@ AM_MESON_CPU_MAJOR_ID_TL1,\ AM_MESON_CPU_MAJOR_ID_TM2,\ AM_MESON_CPU_MAJOR_ID_SC2,\ + AM_MESON_CPU_MAJOR_ID_T5,\ + AM_MESON_CPU_MAJOR_ID_T5D,\ + AM_MESON_CPU_MAJOR_ID_T7,\ + AM_MESON_CPU_MAJOR_ID_S4,\ + AM_MESON_CPU_MAJOR_ID_T3,\ + AM_MESON_CPU_MAJOR_ID_P1,\ + AM_MESON_CPU_MAJOR_ID_S4D,\ + AM_MESON_CPU_MAJOR_ID_T5W,\ 0} #include "clk.h"
diff --git a/drivers/common/media_clock/switch/amports_gate.c b/drivers/common/media_clock/switch/amports_gate.c index 9d5f7b4..58a0289 100644 --- a/drivers/common/media_clock/switch/amports_gate.c +++ b/drivers/common/media_clock/switch/amports_gate.c
@@ -99,11 +99,11 @@ gates[i].clk = devm_clk_get(dev, gates[i].name); if (IS_ERR_OR_NULL(gates[i].clk)) { gates[i].clk = NULL; - pr_info("get gate %s control failed %p\n", + pr_info("get gate %s control failed %px\n", gates[i].name, gates[i].clk); } else { - pr_info("get gate %s control ok %p\n", + pr_info("get gate %s control ok %px\n", gates[i].name, gates[i].clk); }
diff --git a/drivers/fake_video_out/Makefile b/drivers/fake_video_out/Makefile deleted file mode 100644 index 1dd937c..0000000 --- a/drivers/fake_video_out/Makefile +++ /dev/null
@@ -1 +0,0 @@ -obj-m += fake_video.o
diff --git a/drivers/fake_video_out/fake_video.c b/drivers/fake_video_out/fake_video.c deleted file mode 100644 index e0e9b16..0000000 --- a/drivers/fake_video_out/fake_video.c +++ /dev/null
@@ -1,309 +0,0 @@ -/* -* Copyright (C) 2017 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. -* -* You should have received a copy of the GNU General Public License along -* with this program; if not, write to the Free Software Foundation, Inc., -* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -* -* Description: -*/ -#include <linux/version.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/mutex.h> -#include <linux/ctype.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/poll.h> -#include <linux/clk.h> -#include <linux/debugfs.h> -#include <linux/dma-mapping.h> -#include <linux/dma-contiguous.h> -#include <linux/sched.h> -#include <linux/amlogic/media/vfm/vframe.h> -#include <linux/amlogic/media/vfm/vframe_provider.h> -#include <linux/amlogic/media/vfm/vframe_receiver.h> -#include <linux/amlogic/major.h> -#include "../frame_provider/decoder/utils/vdec.h" -#include <linux/delay.h> -#include <linux/kthread.h> - -#define RECEIVER_NAME "fake-amvideo" -#define DEVICE_NAME "fake-amvideo" - -#define TUNNEL_MODE (0) -#define NON_TUNNEL_MODE (1) - -static u32 display_mode = TUNNEL_MODE; -module_param(display_mode, uint, 0664); -MODULE_PARM_DESC(display_mode, "\n display_mode\n"); - -static struct device *amvideo_dev = NULL; -struct timer_list timer; -struct task_struct *task; -bool thread_stop = false; -atomic_t frame_count; - -static struct vframe_receiver_s fake_video_vf_recv; -static int video_receiver_event_fun(int type, void *data, void *); -static const struct vframe_receiver_op_s fake_video_vf_receiver = { - .event_cb = video_receiver_event_fun -}; - -static struct vframe_s *video_vf_peek(void) -{ - return vf_peek(RECEIVER_NAME); -} - -static struct vframe_s *video_vf_get(void) -{ - struct vframe_s *vf = NULL; - - vf = vf_get(RECEIVER_NAME); - - if (vf) { - atomic_set(&vf->use_cnt, 1); - /*pr_err("Get vframe w: %d, h: %d, fence: %lx, idx: %d\n", - vf->width, vf->height, (ulong)vf->fence, vf->index & 0xff);*/ - } - - return vf; -} - -static void video_vf_put(struct vframe_s *vf) -{ - struct vframe_provider_s *vfp = vf_get_provider(RECEIVER_NAME); - - if (vfp && vf && atomic_dec_and_test(&vf->use_cnt)) { - vf_put(vf, RECEIVER_NAME); - } -} - -static int video_receiver_event_fun(int type, void *data, void *private_data) -{ - switch (type) { - case VFRAME_EVENT_PROVIDER_UNREG: { - atomic_set(&frame_count, 0); - pr_info("VFRAME_EVENT_PROVIDER_UNREG\n"); - break; - } - case VFRAME_EVENT_PROVIDER_START: { - pr_info("VFRAME_EVENT_PROVIDER_START\n"); - break; - } - case VFRAME_EVENT_PROVIDER_QUREY_STATE: { - break; - } - case VFRAME_EVENT_PROVIDER_VFRAME_READY: { - pr_info("VFRAME_EVENT_PROVIDER_VFRAME_READY\n"); - atomic_inc(&frame_count); - break; - } - default: - break; - } - - return 0; -} - -static void display_timer_func(unsigned long arg) -{ - struct vframe_s *vf = NULL; - - if (display_mode != TUNNEL_MODE) - goto out; - - vf = video_vf_peek(); - if (!vf) { - goto out; - } - - if (vf->fence) { - if (vdec_fence_status_get(vf->fence) == 1) { - pr_info("[VDEC-FENCE]: Display, idx: %d\n", - vf->index & 0xff); - vf = video_vf_get(); - video_vf_put(vf); - } else { - pr_err("[VDEC-FENCE]: Display invalid, fence status err.\n"); - } - } - -out: - mod_timer(&timer, jiffies + msecs_to_jiffies(16)); -} - -static int display_thread(void *data) -{ - struct vframe_s *vf = NULL; - - for (;;) { - if (thread_stop) - break; - - if ((atomic_read(&frame_count) == 0) || - display_mode != NON_TUNNEL_MODE) - continue; - - if (video_vf_peek()) { - vf = video_vf_get(); - if (!vf) { - pr_err("receiver vf err.\n"); - break; - } - - atomic_dec(&frame_count); - - if (vf->fence) { - u64 timestamp = local_clock(); - /* fence waiting until frame ready. */ - vdec_fence_wait(vf->fence, msecs_to_jiffies(2000)); - - if (vdec_fence_status_get(vf->fence) == 1) { - pr_info("[VDEC-FENCE]: Display, idx: %d, dec cost: %lld\n", - vf->index & 0xff, local_clock() - timestamp); - } else { - pr_err("[VDEC-FENCE]: Display invalid, fence status err.\n"); - } - } - - video_vf_put(vf); - } - msleep(16); - } - return 0; -} - -static int amvideo_open(struct inode *inode, struct file *file) -{ - file->private_data = NULL; - return 0; -} - -static int amvideo_release(struct inode *inode, struct file *file) -{ - file->private_data = NULL; - return 0; -} - -static long amvideo_ioctl(struct file *file, unsigned int cmd, ulong arg) -{ - file->private_data = NULL; - return 0; -} - -#ifdef CONFIG_COMPAT -static long amvideo_compat_ioctl(struct file *file, unsigned int cmd, ulong arg) -{ - file->private_data = NULL; - return 0; -} -#endif - -static const struct file_operations amvideo_fops = { - .owner = THIS_MODULE, - .open = amvideo_open, - .release = amvideo_release, - .unlocked_ioctl = amvideo_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = amvideo_compat_ioctl, -#endif - //.poll = amvideo_poll, -}; - -static struct class amvideo_class = { - .name = "fake_video", -}; - -#define FAKEVIDEO_MAJOR (23 + (AML_BASE)) - -static int __init fake_video_init(void) -{ - int ret = 0; - - ret = class_register(&amvideo_class); - if (ret) { - pr_err("create video class fail.\n"); - return 0; - } - - - /* create video device */ - ret = register_chrdev(FAKEVIDEO_MAJOR, DEVICE_NAME, &amvideo_fops); - if (ret < 0) { - pr_err("Can't register major for amvideo device\n"); - goto err1; - } - - amvideo_dev = device_create(&amvideo_class, NULL, - MKDEV(FAKEVIDEO_MAJOR, 0), NULL, DEVICE_NAME); - if (IS_ERR(amvideo_dev)) { - pr_err("Can't create amvideo device\n"); - goto err; - } - - vf_receiver_init(&fake_video_vf_recv, RECEIVER_NAME, - &fake_video_vf_receiver, NULL); - vf_reg_receiver(&fake_video_vf_recv); - - atomic_set(&frame_count, 0); - - init_timer(&timer); - //timer.data = 0; - timer.function = display_timer_func; - timer.expires = jiffies + HZ; - add_timer(&timer); - - thread_stop = false; - task = kthread_run(display_thread, NULL, "aml-%s", "fake-video-thread"); - if (IS_ERR(task)) { - ret = PTR_ERR(task); - pr_err("Failed to creat display thread, ret: %d.\n", ret); - goto err; - } - - return 0; - -err: - unregister_chrdev(FAKEVIDEO_MAJOR, DEVICE_NAME); -err1: - class_unregister(&amvideo_class); - - return ret; -} - -static void __exit fake_video_exit(void) -{ - thread_stop = true; - kthread_stop(task); - - del_timer_sync(&timer); - - vf_unreg_receiver(&fake_video_vf_recv); - - device_destroy(&amvideo_class, MKDEV(FAKEVIDEO_MAJOR, 0)); - unregister_chrdev(FAKEVIDEO_MAJOR, DEVICE_NAME); - class_unregister(&amvideo_class); - -} - - -module_init(fake_video_init); -module_exit(fake_video_exit); - - -MODULE_DESCRIPTION("AMLOGIC fake video output driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Nanxin Qin <nanxin.qin@amlogic.com>"); -
diff --git a/drivers/frame_provider/Makefile b/drivers/frame_provider/Makefile index 371e088..f30c4f1 100644 --- a/drivers/frame_provider/Makefile +++ b/drivers/frame_provider/Makefile
@@ -1 +1,2 @@ obj-y += decoder/ +obj-y += decoder_v4l/
diff --git a/drivers/frame_provider/decoder/Makefile b/drivers/frame_provider/decoder/Makefile index 349d381..bb0079e 100644 --- a/drivers/frame_provider/decoder/Makefile +++ b/drivers/frame_provider/decoder/Makefile
@@ -7,7 +7,6 @@ obj-y += h265/ obj-y += vp9/ obj-y += mjpeg/ -obj-y += real/ obj-y += avs/ obj-y += avs2/ obj-y += avs_multi/
diff --git a/drivers/frame_provider/decoder/avs/avs.c b/drivers/frame_provider/decoder/avs/avs.c index 6314f9d..5869eac 100644 --- a/drivers/frame_provider/decoder/avs/avs.c +++ b/drivers/frame_provider/decoder/avs/avs.c
@@ -43,8 +43,8 @@ #include "../utils/decoder_bmmu_box.h" #include "../utils/firmware.h" #include "../../../common/chips/decoder_cpu_ver_info.h" -#include <linux/amlogic/tee.h> - +//#include <linux/amlogic/tee.h> +#include <uapi/linux/tee.h> #define DRIVER_NAME "amvdec_avs" #define MODULE_NAME "amvdec_avs" @@ -162,7 +162,6 @@ int canvas_num = 3; #endif - static struct vframe_s vfpool[VF_POOL_SIZE]; /*static struct vframe_s vfpool2[VF_POOL_SIZE];*/ static struct vframe_s *cur_vfpool; @@ -413,6 +412,7 @@ } } + #ifdef HANDLE_AVS_IRQ static irqreturn_t vavs_isr(int irq, void *dev_id) #else @@ -654,6 +654,7 @@ decoder_bmmu_box_get_mem_handle( mm_blk_handle, buffer_index); + kfifo_put(&display_q, (const struct vframe_s *)vf); ATRACE_COUNTER(MODULE_NAME, vf->pts); @@ -740,7 +741,6 @@ decoder_bmmu_box_get_mem_handle( mm_blk_handle, buffer_index); - decoder_do_frame_check(NULL, vf); kfifo_put(&display_q, (const struct vframe_s *)vf); @@ -945,35 +945,35 @@ else endian = 0; #ifdef NV21 - canvas_config_ex(canvas_base + canvas_num * i + 0, + config_cav_lut_ex(canvas_base + canvas_num * i + 0, buf_start, canvas_width, canvas_height, CANVAS_ADDR_NOWRAP, - vdec->canvas_mode, endian); - canvas_config_ex(canvas_base + canvas_num * i + 1, + vdec->canvas_mode, endian, VDEC_1); + config_cav_lut_ex(canvas_base + canvas_num * i + 1, buf_start + decbuf_y_size, canvas_width, canvas_height / 2, CANVAS_ADDR_NOWRAP, - vdec->canvas_mode, endian); + vdec->canvas_mode, endian, VDEC_1); #else - canvas_config_ex(canvas_num * i + 0, + config_cav_lut_ex(canvas_num * i + 0, buf_start, canvas_width, canvas_height, CANVAS_ADDR_NOWRAP, - vdec->canvas_mode, endian); - canvas_config_ex(canvas_num * i + 1, + vdec->canvas_mode, endian, VDEC_1); + config_cav_lut_ex(canvas_num * i + 1, buf_start + decbuf_y_size, canvas_width / 2, canvas_height / 2, CANVAS_ADDR_NOWRAP, - vdec->canvas_mode, endian); - canvas_config_ex(canvas_num * i + 2, + vdec->canvas_mode, endian, VDEC_1); + config_cav_lut_ex(canvas_num * i + 2, buf_start + decbuf_y_size + decbuf_uv_size, canvas_width / 2, canvas_height / 2, CANVAS_ADDR_NOWRAP, - vdec->canvas_mode, endian); + vdec->canvas_mode, endian, VDEC_1); #endif if (debug_flag & AVS_DEBUG_PRINT) { pr_info("canvas config %d, addr %p\n", i, @@ -1353,10 +1353,8 @@ } } -static void vavs_put_timer_func(unsigned long arg) +static void vavs_put_timer_func(struct timer_list *timer) { - struct timer_list *timer = (struct timer_list *)arg; - #ifndef HANDLE_AVS_IRQ vavs_isr(); #endif @@ -1573,7 +1571,6 @@ return -ENOMEM; pr_info("vavs_init\n"); - init_timer(&recycle_timer); stat |= STAT_TIMER_INIT; @@ -1657,10 +1654,8 @@ stat |= STAT_VF_HOOK; - recycle_timer.data = (ulong)(&recycle_timer); - recycle_timer.function = vavs_put_timer_func; + timer_setup(&recycle_timer, vavs_put_timer_func, 0); recycle_timer.expires = jiffies + PUT_INTERVAL; - add_timer(&recycle_timer); stat |= STAT_TIMER_ARM;
diff --git a/drivers/frame_provider/decoder/avs2/avs2_bufmgr.c b/drivers/frame_provider/decoder/avs2/avs2_bufmgr.c index 3da87e4..de9a3d2 100644 --- a/drivers/frame_provider/decoder/avs2/avs2_bufmgr.c +++ b/drivers/frame_provider/decoder/avs2/avs2_bufmgr.c
@@ -39,7 +39,9 @@ #include <linux/dma-mapping.h> #include <linux/dma-contiguous.h> #include <linux/slab.h> -#include <linux/amlogic/tee.h> +//#include <linux/amlogic/tee.h> +#include <uapi/linux/tee.h> +#include <linux/sched/clock.h> #include "../../../stream_input/amports/amports_priv.h" #include <linux/amlogic/media/codec_mm/codec_mm.h> #include "../utils/decoder_mmu_box.h"
diff --git a/drivers/frame_provider/decoder/avs2/avs2_global.h b/drivers/frame_provider/decoder/avs2/avs2_global.h index 3e7fcb8..be35a5e 100644 --- a/drivers/frame_provider/decoder/avs2/avs2_global.h +++ b/drivers/frame_provider/decoder/avs2/avs2_global.h
@@ -772,6 +772,9 @@ uint8_t bg_flag; /**/ unsigned long header_adr; + /*AVS2_10B_MMU_DW*/ + unsigned long dw_header_adr; + int buf_size; int lcu_total; int comp_body_size; @@ -814,6 +817,9 @@ u32 hw_decode_time; u32 frame_size; // For frame base mode + + char *cuva_data_buf; + int cuva_data_size; };
diff --git a/drivers/frame_provider/decoder/avs2/vavs2.c b/drivers/frame_provider/decoder/avs2/vavs2.c index a5d550f..e21dc55 100644 --- a/drivers/frame_provider/decoder/avs2/vavs2.c +++ b/drivers/frame_provider/decoder/avs2/vavs2.c
@@ -37,7 +37,9 @@ #include <linux/dma-mapping.h> #include <linux/dma-contiguous.h> #include <linux/slab.h> -#include <linux/amlogic/tee.h> +//#include <linux/amlogic/tee.h> +#include <uapi/linux/tee.h> +#include <linux/sched/clock.h> #include "../../../stream_input/amports/amports_priv.h" #include <linux/amlogic/media/codec_mm/codec_mm.h> #include "../utils/decoder_mmu_box.h" @@ -55,26 +57,46 @@ #include "../utils/config_parser.h" #include "../utils/firmware.h" #include "../../../common/chips/decoder_cpu_ver_info.h" -#include <linux/amlogic/tee.h> - +#include "../utils/vdec_feature.h" #define I_ONLY_SUPPORT #define MIX_STREAM_SUPPORT -#define G12A_BRINGUP_DEBUG #define CONSTRAIN_MAX_BUF_NUM +#define CO_MV_COMPRESS + #include "vavs2.h" #define HEVC_SHIFT_LENGTH_PROTECT 0x313a +#define HEVC_MPRED_CTRL4 0x324c #define HEVC_MPRED_CTRL9 0x325b #define HEVC_DBLK_CFGD 0x350d - - #define HEVC_CM_HEADER_START_ADDR 0x3628 #define HEVC_DBLK_CFGB 0x350b #define HEVCD_MPP_ANC2AXI_TBL_DATA 0x3464 #define HEVC_SAO_MMU_VH1_ADDR 0x363b #define HEVC_SAO_MMU_VH0_ADDR 0x363a +#define HEVC_CM_BODY_LENGTH2 0x3663 +#define HEVC_CM_HEADER_OFFSET2 0x3664 +#define HEVC_CM_HEADER_LENGTH2 0x3665 + +#define HEVC_ASSIST_MMU_MAP_ADDR 0x3009 + +#define HEVC_CM_HEADER_START_ADDR 0x3628 +#define HEVC_CM_HEADER_START_ADDR2 0x364a +#define HEVC_SAO_MMU_VH1_ADDR 0x363b +#define HEVC_SAO_MMU_VH0_ADDR 0x363a +#define HEVC_SAO_MMU_VH0_ADDR2 0x364d +#define HEVC_SAO_MMU_VH1_ADDR2 0x364e + +#define HEVC_SAO_MMU_DMA_CTRL2 0x364c +#define HEVC_SAO_MMU_STATUS2 0x3650 +#define HEVC_DW_VH0_ADDDR 0x365e +#define HEVC_DW_VH1_ADDDR 0x365f + +#define HEVC_SAO_CTRL9 0x362d + + /* * AVS2_DEC_STATUS define @@ -227,6 +249,9 @@ #define unlock_buffer(dec, flags) \ spin_unlock_irqrestore(&dec->buffer_lock, flags) +static u32 debug_mask = 0xffffffff; +#define get_dbg_flag(dec) ((debug_mask & (1 << dec->index)) ? debug : 0) + static unsigned int max_decode_instance_num = MAX_DECODE_INSTANCE_NUM; static unsigned int decode_frame_count[MAX_DECODE_INSTANCE_NUM]; @@ -236,17 +261,11 @@ static unsigned int input_empty[MAX_DECODE_INSTANCE_NUM]; static unsigned int not_run_ready[MAX_DECODE_INSTANCE_NUM]; -#ifdef G12A_BRINGUP_DEBUG static u32 decode_timeout_val = 200; -#else -static u32 decode_timeout_val = 200; -#endif + static int start_decode_buf_level = 0x8000; -#ifdef AVS2_10B_MMU -static u32 work_buf_size; /* = 24 * 1024 * 1024*/; -#else -static u32 work_buf_size = 32 * 1024 * 1024; -#endif + +static u32 work_buf_size; static u32 mv_buf_margin; static int pre_decode_buf_level = 0x1000; @@ -260,6 +279,7 @@ * 2, (1/4):(1/4) ratio; * 3, (1/4):(1/4) ratio, with both compressed frame included * 4, (1/2):(1/2) ratio; + * 8, (1/8):(1/8) ratio; * 0x10, double write only * 0x100, if > 1080p,use mode 4,else use mode 1; * 0x200, if > 1080p,use mode 2,else use mode 1; @@ -298,7 +318,7 @@ static s32 vavs2_init(struct vdec_s *vdec); static void vavs2_prot_init(struct AVS2Decoder_s *dec); static int vavs2_local_init(struct AVS2Decoder_s *dec); -static void vavs2_put_timer_func(unsigned long arg); +static void vavs2_put_timer_func(struct timer_list *timer); static void dump_data(struct AVS2Decoder_s *dec, int size); static unsigned char get_data_check_sum (struct AVS2Decoder_s *dec, int size); @@ -330,6 +350,8 @@ static u32 force_video_signal_type; static u32 enable_force_video_signal_type; #define VIDEO_SIGNAL_TYPE_AVAILABLE_MASK 0x20000000 +#define HDR_CUVA_MASK 0x40000000 + static const char * const video_format_names[] = { "component", "PAL", "NTSC", "SECAM", @@ -405,11 +427,6 @@ #define DOUBLE_WRITE_YSTART_TEMP 0x02000000 #define DOUBLE_WRITE_CSTART_TEMP 0x02900000 - - -typedef unsigned int u32; -typedef unsigned short u16; - #define AVS2_DBG_BUFMGR 0x01 #define AVS2_DBG_BUFMGR_MORE 0x02 #define AVS2_DBG_BUFMGR_DETAIL 0x04 @@ -425,6 +442,7 @@ #define AVS2_DBG_PIC_LEAK 0x1000 #define AVS2_DBG_PIC_LEAK_WAIT 0x2000 #define AVS2_DBG_HDR_INFO 0x4000 +#define AVS2_DBG_HDR_DATA 0x8000 #define AVS2_DBG_DIS_LOC_ERROR_PROC 0x10000 #define AVS2_DBG_DIS_SYS_ERROR_PROC 0x20000 #define AVS2_DBG_DUMP_PIC_LIST 0x40000 @@ -497,6 +515,9 @@ static u32 force_disp_pic_index; +#define AUX_BUF_ALIGN(adr) ((adr + 0xf) & (~0xf)) +static u32 cuva_buf_size = 512; + #define DEBUG_REG #ifdef DEBUG_REG static void WRITE_VREG_DBG2(unsigned adr, unsigned val) @@ -511,11 +532,6 @@ #define WRITE_VREG WRITE_VREG_DBG2 #endif - -//#ifdef AVS2_10B_MMU -//#define MMU_COMPRESS_HEADER_SIZE 0x48000 -//#define MMU_COMPRESS_8K_HEADER_SIZE 0x48000*4 -//#endif #define MMU_COMPRESS_HEADER_SIZE_1080P 0x10000 #define MMU_COMPRESS_HEADER_SIZE_4K 0x48000 #define MMU_COMPRESS_HEADER_SIZE_8K 0x120000 @@ -530,7 +546,7 @@ #define FRAME_CONTEXTS_LOG2 2 #define FRAME_CONTEXTS (1 << FRAME_CONTEXTS_LOG2) /*buffer + header buffer + workspace*/ -#undef MV_USE_FIXED_BUF + #ifdef MV_USE_FIXED_BUF #define MAX_BMMU_BUFFER_NUM ((FRAME_BUFFERS + HEADER_FRAME_BUFFERS + 1)+1) #define VF_BUFFER_IDX(n) (n) @@ -542,6 +558,7 @@ #define HEADER_BUFFER_IDX(n) (FRAME_BUFFERS + n+1) #define MV_BUFFER_IDX(n) ((FRAME_BUFFERS * 2) + n+1) #define WORK_SPACE_BUF_ID ((FRAME_BUFFERS * 2) + HEADER_FRAME_BUFFERS+1) +//#define DW_HEADER_BUFFER_IDX(n) ((FRAME_BUFFERS * 3) + n+1) #endif #define CO_MV_BUF_SIZE_1080P 0x3fc00 @@ -584,6 +601,10 @@ struct buff_s mmu_vbh; struct buff_s cm_header; #endif +#ifdef AVS2_10B_MMU_DW + struct buff_s mmu_vbh_dw; + struct buff_s cm_header_dw; +#endif struct buff_s mpred_above; #ifdef MV_USE_FIXED_BUF struct buff_s mpred_mv; @@ -668,11 +689,22 @@ unsigned short *lmem_ptr; unsigned short *debug_ptr; -#if 1 - /*AVS2_10B_MMU*/ +#ifdef AVS2_10B_MMU + bool mmu_enable; + + u32 cuva_size; + void *cuva_addr; + dma_addr_t cuva_phy_addr; + void *frame_mmu_map_addr; dma_addr_t frame_mmu_map_phy_addr; #endif +#ifdef AVS2_10B_MMU_DW + bool dw_mmu_enable; + void *dw_mmu_box; + void *dw_frame_mmu_map_addr; + dma_addr_t dw_frame_mmu_map_phy_addr; +#endif unsigned int use_cma_flag; struct BUF_s m_BUF[MAX_BUF_NUM]; @@ -775,10 +807,14 @@ u32 dynamic_buf_margin; int sidebind_type; int sidebind_channel_id; + u32 endian; char vdec_name[32]; char pts_name[32]; char new_q_name[32]; char disp_q_name[32]; + dma_addr_t rdma_phy_adr; + unsigned *rdma_adr; + int hdr_flag; }; static int compute_losless_comp_body_size( @@ -888,10 +924,19 @@ static u32 get_valid_double_write_mode(struct AVS2Decoder_s *dec) { - return (dec->m_ins_flag && + u32 dw_mode; + + dw_mode = (dec->m_ins_flag && ((double_write_mode & 0x80000000) == 0)) ? dec->double_write_mode : (double_write_mode & 0x7fffffff); + if (dw_mode & 0x20) { + if ((get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_T3) + && ((dw_mode & 0xf) == 2 || (dw_mode & 0xf) == 3)) + dw_mode = 0; + } + + return dw_mode; } static int get_double_write_mode(struct AVS2Decoder_s *dec) @@ -949,18 +994,6 @@ return dw; } -static int get_double_write_ratio(struct AVS2Decoder_s *dec, - int dw_mode) -{ - int ratio = 1; - if ((dw_mode == 2) || - (dw_mode == 3)) - ratio = 4; - else if (dw_mode == 4) - ratio = 2; - return ratio; -} - //#define MAX_4K_NUM 0x1200 #ifdef AVS2_10B_MMU int avs2_alloc_mmu( @@ -974,25 +1007,6 @@ int bit_depth_10 = (bit_depth == AVS2_BITS_10); int picture_size; int cur_mmu_4k_number, max_frame_num; -#ifdef DYNAMIC_ALLOC_HEAD - unsigned long buf_addr; - struct avs2_frame_s *pic = dec->avs2_dec.hc.cur_pic; - if (pic->header_adr == 0) { - if (decoder_bmmu_box_alloc_buf_phy - (dec->bmmu_box, - HEADER_BUFFER_IDX(cur_buf_idx), - get_compress_header_size(dec), - DRIVER_HEADER_NAME, - &buf_addr) < 0){ - avs2_print(dec, 0, - "%s malloc compress header failed %d\n", - DRIVER_HEADER_NAME, cur_buf_idx); - dec->fatal_error |= DECODER_FATAL_ERROR_NO_MEM; - return -1; - } else - pic->header_adr = buf_addr; - } -#endif picture_size = compute_losless_comp_body_size( dec, pic_width, pic_height, @@ -1015,157 +1029,38 @@ } #endif -#if 0 -/*ndef MV_USE_FIXED_BUF*/ -static void dealloc_mv_bufs(struct AVS2Decoder_s *dec) +#ifdef AVS2_10B_MMU_DW +int avs2_alloc_dw_mmu( + struct AVS2Decoder_s *dec, + int cur_buf_idx, + int pic_width, + int pic_height, + unsigned short bit_depth, + unsigned int *mmu_index_adr) { - int i; - for (i = 0; i < FRAME_BUFFERS; i++) { - if (dec->m_mv_BUF[i].start_adr) { - if (debug) - pr_info( - "dealloc mv buf(%d) adr %ld size 0x%x used_flag %d\n", - i, dec->m_mv_BUF[i].start_adr, - dec->m_mv_BUF[i].size, - dec->m_mv_BUF[i].used_flag); - decoder_bmmu_box_free_idx( - dec->bmmu_box, - MV_BUFFER_IDX(i)); - dec->m_mv_BUF[i].start_adr = 0; - dec->m_mv_BUF[i].size = 0; - dec->m_mv_BUF[i].used_flag = 0; - } + int bit_depth_10 = (bit_depth == AVS2_BITS_10); + int picture_size; + int cur_mmu_4k_number, max_frame_num; + + picture_size = compute_losless_comp_body_size( + dec, pic_width, pic_height, + bit_depth_10); + cur_mmu_4k_number = ((picture_size + (1 << 12) - 1) >> 12); + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) + max_frame_num = MAX_FRAME_8K_NUM; + else + max_frame_num = MAX_FRAME_4K_NUM; + if (cur_mmu_4k_number > max_frame_num) { + pr_err("over max !! cur_mmu_4k_number 0x%x width %d height %d\n", + cur_mmu_4k_number, pic_width, pic_height); + return -1; } + return decoder_mmu_box_alloc_idx( + dec->dw_mmu_box, + cur_buf_idx, + cur_mmu_4k_number, + mmu_index_adr); } - -static int alloc_mv_buf(struct AVS2Decoder_s *dec, - int i, int size) -{ - int ret = 0; - if (decoder_bmmu_box_alloc_buf_phy - (dec->bmmu_box, - MV_BUFFER_IDX(i), size, - DRIVER_NAME, - &dec->m_mv_BUF[i].start_adr) < 0) { - dec->m_mv_BUF[i].start_adr = 0; - ret = -1; - } else { - dec->m_mv_BUF[i].size = size; - dec->m_mv_BUF[i].used_flag = 0; - ret = 0; - if (debug) { - pr_info( - "MV Buffer %d: start_adr %p size %x\n", - i, - (void *)dec->m_mv_BUF[i].start_adr, - dec->m_mv_BUF[i].size); - } - } - return ret; -} - -static int init_mv_buf_list(struct AVS2Decoder_s *dec) -{ - int i; - int ret = 0; - int count = FRAME_BUFFERS; - int pic_width = dec->init_pic_w; - int pic_height = dec->init_pic_h; - int lcu_size = 64; /*fixed 64*/ - int pic_width_64 = (pic_width + 63) & (~0x3f); - int pic_height_32 = (pic_height + 31) & (~0x1f); - int pic_width_lcu = (pic_width_64 % lcu_size) ? - pic_width_64 / lcu_size + 1 - : pic_width_64 / lcu_size; - int pic_height_lcu = (pic_height_32 % lcu_size) ? - pic_height_32 / lcu_size + 1 - : pic_height_32 / lcu_size; - int lcu_total = pic_width_lcu * pic_height_lcu; - int size = ((lcu_total * MV_MEM_UNIT) + 0xffff) & - (~0xffff); - if (mv_buf_margin > 0) - count = dec->avs2_dec.ref_maxbuffer + mv_buf_margin; - for (i = 0; i < count; i++) { - if (alloc_mv_buf(dec, i, size) < 0) { - ret = -1; - break; - } - } - return ret; -} -#if 0 - -static int get_mv_buf(struct AVS2Decoder_s *dec, - struct avs2_frame_s *pic) -{ - int i; - int ret = -1; - for (i = 0; i < FRAME_BUFFERS; i++) { - if (dec->m_mv_BUF[i].start_adr && - dec->m_mv_BUF[i].used_flag == 0) { - dec->m_mv_BUF[i].used_flag = 1; - ret = i; - break; - } - } - - if (ret >= 0) { - pic->mv_buf_index = ret; - pic->mpred_mv_wr_start_addr = - (dec->m_mv_BUF[ret].start_adr + 0xffff) & - (~0xffff); - if (debug & AVS2_DBG_BUFMGR_MORE) - pr_info( - "%s => %d (%d) size 0x%x\n", - __func__, ret, - pic->mpred_mv_wr_start_addr, - dec->m_mv_BUF[ret].size); - } else { - pr_info( - "%s: Error, mv buf is not enough\n", - __func__); - } - return ret; -} - -static void put_mv_buf(struct AVS2Decoder_s *dec, - struct avs2_frame_s *pic) -{ - int i = pic->mv_buf_index; - if (i >= FRAME_BUFFERS) { - if (debug & AVS2_DBG_BUFMGR_MORE) - pr_info( - "%s: index %d beyond range\n", - __func__, i); - return; - } - if (debug & AVS2_DBG_BUFMGR_MORE) - pr_info( - "%s(%d): used_flag(%d)\n", - __func__, i, - dec->m_mv_BUF[i].used_flag); - - pic->mv_buf_index = -1; - if (dec->m_mv_BUF[i].start_adr && - dec->m_mv_BUF[i].used_flag) - dec->m_mv_BUF[i].used_flag = 0; -} - -static void put_un_used_mv_bufs(struct AVS2Decoder_s *dec) -{ - struct VP9_Common_s *const cm = &dec->common; - struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs; - int i; - for (i = 0; i < dec->used_buf_num; ++i) { - if ((frame_bufs[i].ref_count == 0) && - (frame_bufs[i].buf.index != -1) && - (frame_bufs[i].buf.mv_buf_index >= 0) - ) - put_mv_buf(dec, &frame_bufs[i].buf); - } -} -#endif - #endif static int get_free_buf_count(struct AVS2Decoder_s *dec) @@ -1308,13 +1203,19 @@ const u32 avs2_version = 201602101; -static u32 debug; static u32 radr; static u32 rval; static u32 pop_shorts; static u32 dbg_cmd; static u32 dbg_skip_decode_index; -static u32 endian = 0xff0; +/* + * bit 0~3, for HEVCD_IPP_AXIIF_CONFIG endian config + * bit 8~23, for HEVC_SAO_CTRL1 endian config + */ +static u32 endian; +#define HEVC_CONFIG_BIG_ENDIAN ((0x880 << 8) | 0x8) +#define HEVC_CONFIG_LITTLE_ENDIAN ((0xff0 << 8) | 0xf) + #ifdef ERROR_HANDLE_DEBUG static u32 dbg_nal_skip_flag; /* bit[0], skip vps; bit[1], skip sps; bit[2], skip pps */ @@ -1418,6 +1319,9 @@ #define VP9_COUNT_SWAP_BUFFER HEVC_ASSIST_SCRATCH_A #define VP9_SEG_MAP_BUFFER HEVC_ASSIST_SCRATCH_B */ +#define AVS2_CUVA_ADR HEVC_ASSIST_SCRATCH_A +#define AVS2_CUVA_DATA_SIZE HEVC_ASSIST_SCRATCH_B + //#define HEVC_SCALELUT HEVC_ASSIST_SCRATCH_D #define HEVC_WAIT_FLAG HEVC_ASSIST_SCRATCH_E #define RPM_CMD_REG HEVC_ASSIST_SCRATCH_F @@ -1476,7 +1380,10 @@ #define DW_VBH_BUF_SIZE_8K (VBH_BUF_SIZE_8K * 2) #define DW_VBH_BUF_SIZE(bufspec) (bufspec->mmu_vbh_dw.buf_size / 4) -#define WORK_BUF_SPEC_NUM 3 +/* necessary 4K page size align for t7/t3 decoder and after */ +#define WORKBUF_ALIGN(addr) (ALIGN(addr, PAGE_SIZE)) + +#define WORK_BUF_SPEC_NUM 6 static struct BuffInfo_s amvavs2_workbuff_spec[WORK_BUF_SPEC_NUM] = { { /* 8M bytes */ @@ -1485,6 +1392,283 @@ .ipp = { /* IPP work space calculation : 4096 * (Y+CbCr+Flags) = 12k, round to 16k */ + .buf_size = 0x4000, + }, + .sao_abv = { + .buf_size = 0x30000, + }, + .sao_vb = { + .buf_size = 0x30000, + }, + .short_term_rps = { + /* SHORT_TERM_RPS - Max 64 set, 16 entry every set, + total 64x16x2 = 2048 bytes (0x800) */ + .buf_size = 0x800, + }, + .rcs = { + /* RCS STORE AREA - Max 32 RCS, each has 32 bytes, + total 0x0400 bytes */ + .buf_size = 0x400, + }, + .sps = { + /* SPS STORE AREA - Max 16 SPS, each has 0x80 bytes, + total 0x0800 bytes*/ + .buf_size = 0x800, + }, + .pps = { + /*PPS STORE AREA - Max 64 PPS, each has 0x80 bytes, + total 0x2000 bytes*/ + .buf_size = 0x2000, + }, + .sao_up = { + /* SAO UP STORE AREA - Max 640(10240/16) LCU, + each has 16 bytes total 0x2800 bytes */ + .buf_size = 0x2800, + }, + .swap_buf = { + /* 256cyclex64bit = 2K bytes 0x800 + (only 144 cycles valid) */ + .buf_size = 0x800, + }, + .swap_buf2 = { + .buf_size = 0x800, + }, + .scalelut = { + /* support up to 32 SCALELUT 1024x32 = + 32Kbytes (0x8000) */ + .buf_size = 0x8000, + }, + .dblk_para = { + /* DBLK -> Max 256(4096/16) LCU, + each para 1024bytes(total:0x40000), + data 1024bytes(total:0x40000)*/ + .buf_size = 0x40000, + }, + .dblk_data = { + .buf_size = 0x40000, + }, + .dblk_data2 = { + .buf_size = 0x40000, + }, +#ifdef AVS2_10B_MMU + .mmu_vbh = { + .buf_size = 0x5000, /*2*16*(more than 2304)/4, 4K*/ + }, +#if 0 + .cm_header = { + /*add one for keeper.*/ + .buf_size = MMU_COMPRESS_HEADER_SIZE * + (FRAME_BUFFERS + 1), + /* 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) */ + }, +#endif +#endif + .mpred_above = { + .buf_size = 0x8000, /* 2 * size of hevc*/ + }, +#ifdef MV_USE_FIXED_BUF + .mpred_mv = {/* 1080p, 0x40000 per buffer */ + .buf_size = 0x40000 * FRAME_BUFFERS, + }, +#endif + .rpm = { + .buf_size = RPM_BUF_SIZE, + }, + .lmem = { + .buf_size = 0x400 * 2, + } + }, + { + .max_width = 4096, + .max_height = 2304, + .ipp = { + /* IPP work space calculation : + 4096 * (Y+CbCr+Flags) = 12k, round to 16k */ + .buf_size = 0x4000, + }, + .sao_abv = { + .buf_size = 0x30000, + }, + .sao_vb = { + .buf_size = 0x30000, + }, + .short_term_rps = { + /* SHORT_TERM_RPS - Max 64 set, 16 entry every set, + total 64x16x2 = 2048 bytes (0x800) */ + .buf_size = 0x800, + }, + .rcs = { + /* RCS STORE AREA - Max 16 RCS, each has 32 bytes, + total 0x0400 bytes */ + .buf_size = 0x400, + }, + .sps = { + /* SPS STORE AREA - Max 16 SPS, each has 0x80 bytes, + total 0x0800 bytes */ + .buf_size = 0x800, + }, + .pps = { + /* PPS STORE AREA - Max 64 PPS, each has 0x80 bytes, + total 0x2000 bytes */ + .buf_size = 0x2000, + }, + .sao_up = { + /* SAO UP STORE AREA - Max 640(10240/16) LCU, + each has 16 bytes total 0x2800 bytes */ + .buf_size = 0x2800, + }, + .swap_buf = { + /* 256cyclex64bit = 2K bytes 0x800 + (only 144 cycles valid) */ + .buf_size = 0x800, + }, + .swap_buf2 = { + .buf_size = 0x800, + }, + .scalelut = { + /* support up to 32 SCALELUT 1024x32 = 32Kbytes + (0x8000) */ + .buf_size = 0x8000, + }, + .dblk_para = { + /* DBLK -> Max 256(4096/16) LCU, + each para 1024bytes(total:0x40000), + data 1024bytes(total:0x40000)*/ + .buf_size = 0x80000, + }, + .dblk_data = { + /*DBLK -> Max 256(4096/16) LCU, + each para 1024bytes(total:0x40000), + data 1024bytes(total:0x40000)*/ + .buf_size = 0x80000, + }, + .dblk_data2 = { + .buf_size = 0x80000, + }, +#ifdef AVS2_10B_MMU + .mmu_vbh = { + .buf_size = 0x5000,/*2*16*(more than 2304)/4, 4K*/ + }, +#if 0 + .cm_header = { + /*add one for keeper.*/ + .buf_size = MMU_COMPRESS_HEADER_SIZE * + (FRAME_BUFFERS + 1), + /* 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) */ + }, +#endif +#endif + .mpred_above = { + .buf_size = 0x10000, /* 2 * size of hevc*/ + }, +#ifdef MV_USE_FIXED_BUF + .mpred_mv = { + /* .buf_size = 0x100000*16, + //4k2k , 0x100000 per buffer */ + /* 4096x2304 , 0x120000 per buffer */ + .buf_size = 0x120000 * FRAME_BUFFERS, + }, +#endif + .rpm = { + .buf_size = RPM_BUF_SIZE, + }, + .lmem = { + .buf_size = 0x400 * 2, + } + }, + { + .max_width = 4096 * 2, + .max_height = 2304 * 2, + .ipp = { + /*IPP work space calculation : 4096 * (Y+CbCr+Flags) = 12k, + round to 16k*/ + .buf_size = 0x4000 * 2, + }, + .sao_abv = { + .buf_size = 0x30000 * 2, + }, + .sao_vb = { + .buf_size = 0x30000 * 2, + }, + .short_term_rps = { + /*SHORT_TERM_RPS - Max 64 set, 16 entry every set, + total 64x16x2 = 2048 bytes (0x800)*/ + .buf_size = 0x800, + }, + .rcs = { + /*RCS STORE AREA - Max 16 RCS, each has 32 bytes, + total 0x0400 bytes*/ + .buf_size = 0x400, + }, + .sps = { + /*SPS STORE AREA - Max 16 SPS, each has 0x80 bytes, + total 0x0800 bytes*/ + .buf_size = 0x800, + }, + .pps = { + /*PPS STORE AREA - Max 64 PPS, each has 0x80 bytes, total + 0x2000 bytes*/ + .buf_size = 0x2000, + }, + .sao_up = { + /*SAO UP STORE AREA - Max 640(10240/16) LCU, each has 16 bytes i + total 0x2800 bytes*/ + .buf_size = 0x2800 * 2, + }, + .swap_buf = { + /*256cyclex64bit = 2K bytes 0x800 (only 144 cycles valid)*/ + .buf_size = 0x800, + }, + .swap_buf2 = { + .buf_size = 0x800, + }, + .scalelut = { + /*support up to 32 SCALELUT 1024x32 = 32Kbytes (0x8000)*/ + .buf_size = 0x8000 * 2, + }, + .dblk_para = { + .buf_size = 0x40000 * 2, + }, + .dblk_data = { + .buf_size = 0x80000 * 2, + }, + .dblk_data2 = { + .buf_size = 0x80000 * 2, + }, +#ifdef AVS2_10B_MMU + .mmu_vbh = { + .buf_size = 0x5000 * 2, /*2*16*2304/4, 4K*/ + }, +#if 0 + .cm_header = { + /*0x44000 = ((1088*2*1024*4)/32/4)*(32/8)*/ + .buf_size = MMU_COMPRESS_8K_HEADER_SIZE * 17, + }, +#endif +#endif + .mpred_above = { + .buf_size = 0x8000 * 2, + }, +#ifdef MV_USE_FIXED_BUF + .mpred_mv = { + /*4k2k , 0x100000 per buffer*/ + .buf_size = 0x120000 * FRAME_BUFFERS * 4, + }, +#endif + .rpm = { + .buf_size = RPM_BUF_SIZE, + }, + .lmem = { + .buf_size = 0x400 * 2, + } + }, + { + /* 8M bytes */ + .max_width = 1920, + .max_height = 1088, + .ipp = { + /* IPP work space calculation : + 4096 * (Y+CbCr+Flags) = 12k, round to 16k */ .buf_size = 0x1e00, }, .sao_abv = { @@ -1556,6 +1740,16 @@ }, #endif #endif +#ifdef AVS2_10B_MMU_DW + .mmu_vbh_dw = { + .buf_size = DW_VBH_BUF_SIZE_1080P, //2*16*2304/4, 4K + }, +#if 0 + .cm_header_dw = { + .buf_size = MMU_COMPRESS_HEADER_SIZE_DW*17, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) + }, +#endif +#endif .mpred_above = { .buf_size = 0x1e00, /* 2 * size of hevc*/ }, @@ -1651,6 +1845,16 @@ }, #endif #endif +#ifdef AVS2_10B_MMU_DW + .mmu_vbh_dw = { + .buf_size = DW_VBH_BUF_SIZE_4K, //2*16*2304/4, 4K + }, +#if 0 + .cm_header_dw = { + .buf_size = MMU_COMPRESS_HEADER_SIZE_DW*17, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) + }, +#endif +#endif .mpred_above = { .buf_size = 0x4000, /* 2 * size of hevc*/ }, @@ -1739,6 +1943,16 @@ }, #endif #endif +#ifdef AVS2_10B_MMU_DW + .mmu_vbh_dw = { + .buf_size = DW_VBH_BUF_SIZE_8K, //2*16*2304/4, 4K + }, +#if 0 + .cm_header_dw = { + .buf_size = MMU_COMPRESS_HEADER_SIZE_DW*17, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) + }, +#endif +#endif .mpred_above = { .buf_size = 0x8000, }, @@ -1840,64 +2054,70 @@ struct BuffInfo_s *buf_spec) { void *mem_start_virt; - buf_spec->ipp.buf_start = buf_spec->start_adr; + buf_spec->ipp.buf_start = + WORKBUF_ALIGN(buf_spec->start_adr); buf_spec->sao_abv.buf_start = - buf_spec->ipp.buf_start + buf_spec->ipp.buf_size; - + WORKBUF_ALIGN(buf_spec->ipp.buf_start + buf_spec->ipp.buf_size); buf_spec->sao_vb.buf_start = - buf_spec->sao_abv.buf_start + buf_spec->sao_abv.buf_size; + WORKBUF_ALIGN(buf_spec->sao_abv.buf_start + buf_spec->sao_abv.buf_size); buf_spec->short_term_rps.buf_start = - buf_spec->sao_vb.buf_start + buf_spec->sao_vb.buf_size; + WORKBUF_ALIGN(buf_spec->sao_vb.buf_start + buf_spec->sao_vb.buf_size); buf_spec->rcs.buf_start = - buf_spec->short_term_rps.buf_start + - buf_spec->short_term_rps.buf_size; + WORKBUF_ALIGN(buf_spec->short_term_rps.buf_start + buf_spec->short_term_rps.buf_size); buf_spec->sps.buf_start = - buf_spec->rcs.buf_start + buf_spec->rcs.buf_size; + WORKBUF_ALIGN(buf_spec->rcs.buf_start + buf_spec->rcs.buf_size); buf_spec->pps.buf_start = - buf_spec->sps.buf_start + buf_spec->sps.buf_size; + WORKBUF_ALIGN(buf_spec->sps.buf_start + buf_spec->sps.buf_size); buf_spec->sao_up.buf_start = - buf_spec->pps.buf_start + buf_spec->pps.buf_size; + WORKBUF_ALIGN(buf_spec->pps.buf_start + buf_spec->pps.buf_size); buf_spec->swap_buf.buf_start = - buf_spec->sao_up.buf_start + buf_spec->sao_up.buf_size; + WORKBUF_ALIGN(buf_spec->sao_up.buf_start + buf_spec->sao_up.buf_size); buf_spec->swap_buf2.buf_start = - buf_spec->swap_buf.buf_start + buf_spec->swap_buf.buf_size; + WORKBUF_ALIGN(buf_spec->swap_buf.buf_start + buf_spec->swap_buf.buf_size); buf_spec->scalelut.buf_start = - buf_spec->swap_buf2.buf_start + buf_spec->swap_buf2.buf_size; + WORKBUF_ALIGN(buf_spec->swap_buf2.buf_start + buf_spec->swap_buf2.buf_size); buf_spec->dblk_para.buf_start = - buf_spec->scalelut.buf_start + buf_spec->scalelut.buf_size; + WORKBUF_ALIGN(buf_spec->scalelut.buf_start + buf_spec->scalelut.buf_size); buf_spec->dblk_data.buf_start = - buf_spec->dblk_para.buf_start + buf_spec->dblk_para.buf_size; + WORKBUF_ALIGN(buf_spec->dblk_para.buf_start + buf_spec->dblk_para.buf_size); buf_spec->dblk_data2.buf_start = - buf_spec->dblk_data.buf_start + buf_spec->dblk_data.buf_size; + WORKBUF_ALIGN(buf_spec->dblk_data.buf_start + buf_spec->dblk_data.buf_size); #ifdef AVS2_10B_MMU buf_spec->mmu_vbh.buf_start = - buf_spec->dblk_data2.buf_start + buf_spec->dblk_data2.buf_size; + WORKBUF_ALIGN(buf_spec->dblk_data2.buf_start + buf_spec->dblk_data2.buf_size); + #ifdef AVS2_10B_MMU_DW + buf_spec->mmu_vbh_dw.buf_start = + WORKBUF_ALIGN(buf_spec->mmu_vbh.buf_start + buf_spec->mmu_vbh.buf_size); buf_spec->mpred_above.buf_start = - buf_spec->mmu_vbh.buf_start + buf_spec->mmu_vbh.buf_size; -#else + WORKBUF_ALIGN(buf_spec->mmu_vbh_dw.buf_start + buf_spec->mmu_vbh_dw.buf_size); + #else buf_spec->mpred_above.buf_start = - buf_spec->dblk_data2.buf_start + buf_spec->dblk_data2.buf_size; -#endif + WORKBUF_ALIGN(buf_spec->mmu_vbh.buf_start + buf_spec->mmu_vbh.buf_size); + #endif +#else /* AVS2_10B_MMU */ + #ifdef AVS2_10B_MMU_DW + buf_spec->mmu_vbh_dw.buf_start = + WORKBUF_ALIGN(buf_spec->dblk_data2.buf_start + buf_spec->dblk_data2.buf_size); + buf_spec->mpred_above.buf_start = + WORKBUF_ALIGN(buf_spec->mmu_vbh_dw.buf_start + buf_spec->mmu_vbh_dw.buf_size); + #else + buf_spec->mpred_above.buf_start = + WORKBUF_ALIGN(buf_spec->dblk_data2.buf_start + buf_spec->dblk_data2.buf_size); + #endif +#endif /* AVS2_10B_MMU */ #ifdef MV_USE_FIXED_BUF buf_spec->mpred_mv.buf_start = - buf_spec->mpred_above.buf_start + - buf_spec->mpred_above.buf_size; - + WORKBUF_ALIGN(buf_spec->mpred_above.buf_start + buf_spec->mpred_above.buf_size); buf_spec->rpm.buf_start = - buf_spec->mpred_mv.buf_start + - buf_spec->mpred_mv.buf_size; + WORKBUF_ALIGN(buf_spec->mpred_mv.buf_start + buf_spec->mpred_mv.buf_size); #else buf_spec->rpm.buf_start = - buf_spec->mpred_above.buf_start + - buf_spec->mpred_above.buf_size; - + WORKBUF_ALIGN(buf_spec->mpred_above.buf_start + buf_spec->mpred_above.buf_size); #endif buf_spec->lmem.buf_start = - buf_spec->rpm.buf_start + - buf_spec->rpm.buf_size; + WORKBUF_ALIGN(buf_spec->rpm.buf_start + buf_spec->rpm.buf_size); buf_spec->end_adr = - buf_spec->lmem.buf_start + - buf_spec->lmem.buf_size; + WORKBUF_ALIGN(buf_spec->lmem.buf_start + buf_spec->lmem.buf_size); if (dec) { mem_start_virt = @@ -1950,6 +2170,10 @@ pr_info("mmu_vbh.buf_start :%x\n", buf_spec->mmu_vbh.buf_start); #endif + #ifdef AVS2_10B_MMU_DW + pr_info("mmu_vbh_dw.buf_start :%x\n", + buf_spec->mmu_vbh_dw.buf_start); + #endif pr_info("mpred_above.buf_start :%x\n", buf_spec->mpred_above.buf_start); #ifdef MV_USE_FIXED_BUF @@ -1967,9 +2191,11 @@ static void uninit_mmu_buffers(struct AVS2Decoder_s *dec) { -#if 0 -/*ndef MV_USE_FIXED_BUF*/ - dealloc_mv_bufs(dec); +#ifdef AVS2_10B_MMU_DW + if (dec->dw_mmu_enable && dec->dw_mmu_box) { + decoder_mmu_box_free(dec->dw_mmu_box); + dec->dw_mmu_box = NULL; + } #endif decoder_mmu_box_free(dec->mmu_box); dec->mmu_box = NULL; @@ -2010,9 +2236,9 @@ if (dw_mode) { int pic_width_dw = pic_width / - get_double_write_ratio(dec, dw_mode); + get_double_write_ratio(dw_mode); int pic_height_dw = pic_height / - get_double_write_ratio(dec, dw_mode); + get_double_write_ratio(dw_mode); int lcu_size = 64; /*fixed 64*/ int pic_width_64 = (pic_width_dw + 63) & (~0x3f); int pic_height_32 = (pic_height_dw + 31) & (~0x1f); @@ -2043,7 +2269,7 @@ for (i = 0; i < dec->used_buf_num; i++) { if (((i + 1) * buf_size) > dec->mc_buf->buf_size) dec->use_cma_flag = 1; -#ifndef AVS2_10B_MMU + dec->m_BUF[i].alloc_flag = 0; dec->m_BUF[i].index = i; @@ -2084,7 +2310,6 @@ "Buffer %d: start_adr %p size %x\n", i, (void *)dec->m_BUF[i].start_adr, dec->m_BUF[i].size); -#endif } dec->buf_num = i; } @@ -2109,15 +2334,7 @@ pic_height_32 / lcu_size + 1 : pic_height_32 / lcu_size; int lcu_total = pic_width_lcu * pic_height_lcu; -#if 0 - int32_t MV_MEM_UNIT = - (lcu_size_log2 == 6) ? 0x200 : - ((lcu_size_log2 == 5) ? 0x80 : 0x20); -#endif -#ifdef MV_USE_FIXED_BUF - u32 mpred_mv_end = dec->work_space_buf->mpred_mv.buf_start + - dec->work_space_buf->mpred_mv.buf_size; -#endif + u32 y_adr = 0; int buf_size = 0; @@ -2133,11 +2350,11 @@ int mc_buffer_size_u_v_h = 0; int dw_mode = get_double_write_mode_init(dec); - if (dw_mode) { + if (dw_mode && ((dw_mode & 0x20) == 0)) { int pic_width_dw = pic_width / - get_double_write_ratio(dec, dw_mode); + get_double_write_ratio(dw_mode); int pic_height_dw = pic_height / - get_double_write_ratio(dec, dw_mode); + get_double_write_ratio(dw_mode); int pic_width_64_dw = (pic_width_dw + 63) & (~0x3f); int pic_height_32_dw = (pic_height_dw + 31) & (~0x1f); int pic_width_lcu_dw = (pic_width_64_dw % lcu_size) ? @@ -2156,171 +2373,150 @@ } if (mc_buffer_size & 0xffff) /*64k alignment*/ mc_buffer_size_h += 1; -#ifndef AVS2_10B_MMU + + +#ifdef AVS2_10B_MMU + if (dec->mmu_enable) { + pic->header_adr = decoder_bmmu_box_get_phy_addr( + dec->bmmu_box, HEADER_BUFFER_IDX(pic->index)); + +#ifdef AVS2_10B_MMU_DW + if (dec->dw_mmu_enable) { + pic->dw_header_adr = pic->header_adr + + get_compress_header_size(dec); + } +#endif + avs2_print(dec, AVS2_DBG_BUFMGR_MORE, + "buf_size %d, MMU header_adr %d: %ld\n", + buf_size, pic->index, pic->header_adr); + } +#else if ((dw_mode & 0x10) == 0) buf_size += (mc_buffer_size_h << 16); #endif -#ifdef AVS2_10B_MMU -#ifndef DYNAMIC_ALLOC_HEAD - pic->header_adr = decoder_bmmu_box_get_phy_addr( - dec->bmmu_box, HEADER_BUFFER_IDX(pic->index)); - - avs2_print(dec, AVS2_DBG_BUFMGR_MORE, - "buf_size %d, MMU header_adr %d: %ld\n", - buf_size, pic->index, pic->header_adr); -#endif -#endif - i = pic->index; -#ifdef MV_USE_FIXED_BUF -#ifdef G12A_BRINGUP_DEBUG - if (1) { + +#ifndef AVS2_10B_MMU + if (debug) { + pr_err("start %x .size=%d\n", + dec->mc_buf_spec.buf_start + i * buf_size, buf_size); + } + for (i = 0; i < dec->buf_num; i++) { + y_adr = ((dec->m_BUF[i].free_start_adr + + 0xffff) >> 16) << 16; + /*64k alignment*/ + if ((y_adr+buf_size) <= (dec->m_BUF[i].start_adr+ + dec->m_BUF[i].size)) { + dec->m_BUF[i].free_start_adr = + y_adr + buf_size; + break; + } + } + if (i < dec->buf_num) #else - if ((dec->work_space_buf->mpred_mv.buf_start + - (((i + 1) * lcu_total) * MV_MEM_UNIT)) - <= mpred_mv_end - ) { -#endif -#endif -#ifndef AVS2_10B_MMU - if (debug) { - pr_err("start %x .size=%d\n", - dec->mc_buf_spec.buf_start + i * buf_size, - buf_size); + /*if ((dec->mc_buf->buf_start + (i + 1) * buf_size) < + dec->mc_buf->buf_end) + y_adr = dec->mc_buf->buf_start + i * buf_size; + else {*/ + if (buf_size > 0 && pic->cma_alloc_addr == 0) { + ret = decoder_bmmu_box_alloc_buf_phy(dec->bmmu_box, + VF_BUFFER_IDX(i), + buf_size, DRIVER_NAME, + &pic->cma_alloc_addr); + if (ret < 0) { + avs2_print(dec, 0, + "decoder_bmmu_box_alloc_buf_phy idx %d size %d fail\n", + VF_BUFFER_IDX(i), + buf_size + ); + return ret; } -#endif -#ifndef AVS2_10B_MMU - for (i = 0; i < dec->buf_num; i++) { - y_adr = ((dec->m_BUF[i].free_start_adr - + 0xffff) >> 16) << 16; - /*64k alignment*/ - if ((y_adr+buf_size) <= (dec->m_BUF[i].start_adr+ - dec->m_BUF[i].size)) { - dec->m_BUF[i].free_start_adr = - y_adr + buf_size; - break; - } + + if (pic->cma_alloc_addr) + y_adr = pic->cma_alloc_addr; + else { + avs2_print(dec, 0, + "decoder_bmmu_box_alloc_buf_phy idx %d size %d return null\n", + VF_BUFFER_IDX(i), + buf_size + ); + return -1; } - if (i < dec->buf_num) -#else - /*if ((dec->mc_buf->buf_start + (i + 1) * buf_size) < - dec->mc_buf->buf_end) - y_adr = dec->mc_buf->buf_start + i * buf_size; - else {*/ - if (buf_size > 0 && pic->cma_alloc_addr == 0) { - ret = decoder_bmmu_box_alloc_buf_phy(dec->bmmu_box, - VF_BUFFER_IDX(i), - buf_size, DRIVER_NAME, - &pic->cma_alloc_addr); - if (ret < 0) { - avs2_print(dec, 0, - "decoder_bmmu_box_alloc_buf_phy idx %d size %d fail\n", - VF_BUFFER_IDX(i), - buf_size - ); - return ret; - } - - if (pic->cma_alloc_addr) - y_adr = pic->cma_alloc_addr; - else { - avs2_print(dec, 0, - "decoder_bmmu_box_alloc_buf_phy idx %d size %d return null\n", - VF_BUFFER_IDX(i), - buf_size - ); - return -1; - } - } -#endif - { - /*ensure get_pic_by_POC() - not get the buffer not decoded*/ - pic->BUF_index = i; - pic->lcu_total = lcu_total; - - pic->comp_body_size = losless_comp_body_size; - pic->buf_size = buf_size; -#ifndef AVS2_10B_MMU - pic->mc_y_adr = y_adr; -#endif - pic->mc_canvas_y = pic->index; - pic->mc_canvas_u_v = pic->index; -#ifndef AVS2_10B_MMU - if (dw_mode & 0x10) { - pic->mc_u_v_adr = y_adr + - ((mc_buffer_size_u_v_h << 16) << 1); - - pic->mc_canvas_y = - (pic->index << 1); - pic->mc_canvas_u_v = - (pic->index << 1) + 1; - - pic->dw_y_adr = y_adr; - pic->dw_u_v_adr = pic->mc_u_v_adr; - } else -#endif - if (dw_mode) { - pic->dw_y_adr = y_adr -#ifndef AVS2_10B_MMU - + (mc_buffer_size_h << 16) -#endif - ; - pic->dw_u_v_adr = pic->dw_y_adr + - ((mc_buffer_size_u_v_h << 16) << 1); -#ifdef AVS2_10B_MMU - pic->mc_y_adr = pic->dw_y_adr; - pic->mc_u_v_adr = pic->dw_u_v_adr; -#endif - } -#ifdef MV_USE_FIXED_BUF -#ifdef G12A_BRINGUP_DEBUG - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) { - pic->mpred_mv_wr_start_addr = - dec->work_space_buf->mpred_mv.buf_start + - (pic->index * 0x120000 * 4); - } else { - pic->mpred_mv_wr_start_addr = - dec->work_space_buf->mpred_mv.buf_start + - (pic->index * 0x120000); - } -#else - pic->mpred_mv_wr_start_addr = - dec->work_space_buf->mpred_mv.buf_start + - ((pic->index * lcu_total) - * MV_MEM_UNIT); -#endif -#endif - if (debug) { - avs2_print(dec, AVS2_DBG_BUFMGR, - "%s index %d BUF_index %d mc_y_adr %x ", - __func__, pic->index, - pic->BUF_index, - pic->mc_y_adr); - avs2_print_cont(dec, AVS2_DBG_BUFMGR, - "comp_body_size %x comp_buf_size %x ", - pic->comp_body_size, - pic->buf_size); - avs2_print_cont(dec, AVS2_DBG_BUFMGR, - "mpred_mv_wr_start_adr %d\n", - pic->mpred_mv_wr_start_addr); - avs2_print_cont(dec, AVS2_DBG_BUFMGR, - "dw_y_adr %d, pic->dw_u_v_adr =%d\n", - pic->dw_y_adr, - pic->dw_u_v_adr); - } - ret = 0; - } -#ifdef MV_USE_FIXED_BUF - } else { - avs2_print(dec, 0, - "mv buffer alloc fail %x > %x\n", - dec->work_space_buf->mpred_mv.buf_start + - (((i + 1) * lcu_total) * MV_MEM_UNIT), - mpred_mv_end); } #endif + { + /*ensure get_pic_by_POC() + not get the buffer not decoded*/ + pic->BUF_index = i; + pic->lcu_total = lcu_total; + + pic->comp_body_size = losless_comp_body_size; + pic->buf_size = buf_size; + pic->mc_canvas_y = pic->index; + pic->mc_canvas_u_v = pic->index; +#ifndef AVS2_10B_MMU + pic->mc_y_adr = y_adr; + if (dw_mode & 0x10) { + pic->mc_u_v_adr = y_adr + + ((mc_buffer_size_u_v_h << 16) << 1); + + pic->mc_canvas_y = + (pic->index << 1); + pic->mc_canvas_u_v = + (pic->index << 1) + 1; + + pic->dw_y_adr = y_adr; + pic->dw_u_v_adr = pic->mc_u_v_adr; + } else +#endif + if (dw_mode) { +#ifdef AVS2_10B_MMU + pic->dw_y_adr = y_adr; + pic->dw_u_v_adr = pic->dw_y_adr + + ((mc_buffer_size_u_v_h << 16) << 1); + pic->mc_y_adr = pic->dw_y_adr; + pic->mc_u_v_adr = pic->dw_u_v_adr; +#else + pic->dw_y_adr = y_adr + (mc_buffer_size_h << 16); + pic->dw_u_v_adr = pic->dw_y_adr + + ((mc_buffer_size_u_v_h << 16) << 1); +#endif + } +#ifdef MV_USE_FIXED_BUF + pic->mpred_mv_wr_start_addr = + dec->work_space_buf->mpred_mv.buf_start + + pic->index * (dec->work_space_buf->mpred_mv.buf_size / FRAME_BUFFERS); + if (pic->mpred_mv_wr_start_addr > + (dec->work_space_buf->mpred_mv.buf_start + + dec->work_space_buf->mpred_mv.buf_size)) { + avs2_print(dec, 0, "err: fixed mv buf out of size, 0x0%x\n", + pic->mpred_mv_wr_start_addr); + pic->mpred_mv_wr_start_addr = + dec->work_space_buf->mpred_mv.buf_start; + } +#endif + if (debug) { + avs2_print(dec, AVS2_DBG_BUFMGR, + "%s index %d BUF_index %d mc_y_adr %x ", + __func__, pic->index, + pic->BUF_index, + pic->mc_y_adr); + avs2_print_cont(dec, AVS2_DBG_BUFMGR, + "comp_body_size %x comp_buf_size %x ", + pic->comp_body_size, + pic->buf_size); + avs2_print_cont(dec, AVS2_DBG_BUFMGR, + "mpred_mv_wr_start_adr %d\n", + pic->mpred_mv_wr_start_addr); + avs2_print_cont(dec, AVS2_DBG_BUFMGR, + "dw_y_adr %d, pic->dw_u_v_adr =%d\n", + pic->dw_y_adr, + pic->dw_u_v_adr); + } + ret = 0; + } + return ret; } @@ -2331,36 +2527,28 @@ struct avs2_decoder *avs2_dec = &dec->avs2_dec; struct avs2_frame_s *pic; #ifdef AVS2_10B_MMU - unsigned long buf_addr1; - /*alloc AVS2 compress header first*/ - if (decoder_bmmu_box_alloc_buf_phy - (dec->bmmu_box, - HEADER_BUFFER_IDX(-1), get_compress_header_size(dec), - DRIVER_HEADER_NAME, - &buf_addr1) < 0){ - avs2_print(dec, 0, - "%s malloc compress header failed %d\n", - DRIVER_HEADER_NAME, -1); - dec->fatal_error |= DECODER_FATAL_ERROR_NO_MEM; - return; - } -#ifndef DYNAMIC_ALLOC_HEAD - for (i = 0; i < dec->used_buf_num; i++) { - unsigned long buf_addr; - if (decoder_bmmu_box_alloc_buf_phy - (dec->bmmu_box, - HEADER_BUFFER_IDX(i), get_compress_header_size(dec), - DRIVER_HEADER_NAME, - &buf_addr) < 0){ - avs2_print(dec, 0, - "%s malloc compress header failed %d\n", - DRIVER_HEADER_NAME, i); - dec->fatal_error |= DECODER_FATAL_ERROR_NO_MEM; - return; + if (dec->mmu_enable) { + for (i = 0; i < dec->used_buf_num; i++) { + unsigned long buf_addr; + u32 header_size = get_compress_header_size(dec); +#ifdef AVS2_10B_MMU_DW + if (dec->dw_mmu_enable) + header_size <<= 1; +#endif + if (decoder_bmmu_box_alloc_buf_phy + (dec->bmmu_box, + HEADER_BUFFER_IDX(i), header_size, + DRIVER_HEADER_NAME, + &buf_addr) < 0){ + avs2_print(dec, 0, + "%s malloc compress header failed %d\n", + DRIVER_HEADER_NAME, i); + dec->fatal_error |= DECODER_FATAL_ERROR_NO_MEM; + return; + } } } #endif -#endif dec->frame_height = avs2_dec->img.height; dec->frame_width = avs2_dec->img.width; @@ -3073,7 +3261,7 @@ if ((get_double_write_mode(dec) & 0x10) == 0) WRITE_VREG(HEVC_CM_BODY_START_ADDR, cur_pic->mc_y_adr); #endif - if (get_double_write_mode(dec)) { + if ((get_double_write_mode(dec) & 0x20) == 0) { WRITE_VREG(HEVC_SAO_Y_START_ADDR, cur_pic->dw_y_adr); WRITE_VREG(HEVC_SAO_C_START_ADDR, cur_pic->dw_u_v_adr); WRITE_VREG(HEVC_SAO_Y_WPTR, cur_pic->dw_y_adr); @@ -3085,6 +3273,14 @@ #ifdef AVS2_10B_MMU WRITE_VREG(HEVC_CM_HEADER_START_ADDR, cur_pic->header_adr); #endif +#ifdef AVS2_10B_MMU_DW + if (dec->dw_mmu_enable) { + WRITE_VREG(HEVC_CM_HEADER_START_ADDR2, cur_pic->dw_header_adr); + WRITE_VREG(HEVC_SAO_Y_START_ADDR, 0); + WRITE_VREG(HEVC_SAO_C_START_ADDR, 0); + } +#endif + data32 = (mc_buffer_size_u_v_h << 16) << 1; /*pr_info("data32=%x,mc_buffer_size_u_v_h=%x,lcu_total=%x\n", data32, mc_buffer_size_u_v_h, cur_pic->lcu_total);*/ @@ -3101,6 +3297,22 @@ data32 |= (MEM_MAP_MODE << 12); data32 &= (~0x3); data32 |= 0x1; /* [1]:dw_disable [0]:cm_disable*/ + + /* + * [31:24] ar_fifo1_axi_thred + * [23:16] ar_fifo0_axi_thred + * [15:14] axi_linealign, 0-16bytes, 1-32bytes, 2-64bytes + * [13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32 + * [11:08] axi_lendian_C + * [07:04] axi_lendian_Y + * [3] reserved + * [2] clk_forceon + * [1] dw_disable:disable double write output + * [0] cm_disable:disable compress output + */ + data32 &= (~(3 << 14)); + data32 |= (2 << 14); + WRITE_VREG(HEVC_SAO_CTRL1, data32); /*[23:22] dw_v1_ctrl [21:20] dw_v0_ctrl [19:18] dw_h1_ctrl [17:16] dw_h0_ctrl*/ @@ -3132,23 +3344,41 @@ data32 &= ~(0xff << 16); WRITE_VREG(HEVC_SAO_CTRL5, data32); + /* + * [3:0] little_endian + * [5:4] address_format 00:linear 01:32x32 10:64x32 + * [7:6] reserved + * [9:8] Linear_LineAlignment 00:16byte 01:32byte 10:64byte + * [11:10] reserved + * [12] CbCr_byte_swap + * [31:13] reserved + */ + data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG); data32 &= (~0x30); /*[5:4] address_format 00:linear 01:32x32 10:64x32*/ data32 |= (MEM_MAP_MODE << 4); data32 &= (~0xF); data32 |= 0x8; /*Big-Endian per 64-bit*/ + + data32 &= (~(3 << 8)); + data32 |= (2 << 8); WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32); #endif #else data32 = READ_VREG(HEVC_SAO_CTRL1); + data32 &= (~(3 << 14)); + data32 |= (2 << 14); /* line align with 64*/ data32 &= (~0x3000); - data32 |= (MEM_MAP_MODE << - 12); /* [13:12] axi_aformat, 0-Linear, + data32 |= (MEM_MAP_MODE << 12); /* [13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32 */ data32 &= (~0xff0); - /* data32 |= 0x670; // Big-Endian per 64-bit */ - data32 |= endian; /* Big-Endian per 64-bit */ +#ifdef AVS2_10B_MMU_DW + if (dec->dw_mmu_enable == 0) + data32 |= ((dec->endian >> 8) & 0xfff); +#else + data32 |= ((dec->endian >> 8) & 0xfff); /* data32 |= 0x670; Big-Endian per 64-bit */ +#endif data32 &= (~0x3); /*[1]:dw_disable [0]:cm_disable*/ #if 0 if (get_cpu_major_id() < MESON_CPU_MAJOR_ID_G12A) { @@ -3166,6 +3396,18 @@ else if (get_double_write_mode(dec) & 0x10) data32 |= 0x1; /*disable cm*/ + /* + * [31:24] ar_fifo1_axi_thred + * [23:16] ar_fifo0_axi_thred + * [15:14] axi_linealign, 0-16bytes, 1-32bytes, 2-64bytes + * [13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32 + * [11:08] axi_lendian_C + * [07:04] axi_lendian_Y + * [3] reserved + * [2] clk_forceon + * [1] dw_disable:disable double write output + * [0] cm_disable:disable compress output + */ WRITE_VREG(HEVC_SAO_CTRL1, data32); if (get_double_write_mode(dec) & 0x10) { @@ -3179,26 +3421,55 @@ data32 &= ~(0xff << 16); WRITE_VREG(HEVC_SAO_CTRL5, data32); } else { + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T7) + WRITE_VREG(HEVC_SAO_CTRL26, 0); + data32 = READ_VREG(HEVC_SAO_CTRL5); data32 &= (~(0xff << 16)); - if (get_double_write_mode(dec) == 2 || - get_double_write_mode(dec) == 3) + if ((get_double_write_mode(dec) & 0xf) == 8 || + (get_double_write_mode(dec) & 0xf) == 9) { data32 |= (0xff<<16); - else if (get_double_write_mode(dec) == 4) + WRITE_VREG(HEVC_SAO_CTRL26, 0xf); + } else if ((get_double_write_mode(dec) & 0xf) == 2 || + (get_double_write_mode(dec) & 0xf) == 3) + data32 |= (0xff<<16); + else if ((get_double_write_mode(dec) & 0xf) == 4) data32 |= (0x33<<16); WRITE_VREG(HEVC_SAO_CTRL5, data32); } + /* + * [3:0] little_endian + * [5:4] address_format 00:linear 01:32x32 10:64x32 + * [7:6] reserved + * [9:8] Linear_LineAlignment 00:16byte 01:32byte 10:64byte + * [11:10] reserved + * [12] CbCr_byte_swap + * [31:13] reserved + */ + data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG); data32 &= (~0x30); /* [5:4] -- address_format 00:linear 01:32x32 10:64x32 */ - data32 |= (mem_map_mode << - 4); + data32 |= (mem_map_mode << 4); data32 &= (~0xF); - data32 |= 0xf; /* valid only when double write only */ - /*data32 |= 0x8;*/ /* Big-Endian per 64-bit */ + data32 |= (dec->endian & 0xf); /* valid only when double write only */ + /*data32 |= 0x8;*/ /* Big-Endian per 64-bit */ + data32 &= (~(3 << 8)); + data32 |= (2 << 8); /* line align with 64 for dw only */ WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32); #endif +#ifndef AVS2_10B_NV21 +#ifdef AVS2_10B_MMU_DW + if (dec->dw_mmu_enable) { + struct BuffInfo_s *buf_spec = NULL; + buf_spec = &dec->work_space_buf_store; + WRITE_VREG(HEVC_DW_VH0_ADDDR, buf_spec->mmu_vbh_dw.buf_start + (2 * DW_VBH_BUF_SIZE(buf_spec))); + WRITE_VREG(HEVC_DW_VH1_ADDDR, buf_spec->mmu_vbh_dw.buf_start + (3 * DW_VBH_BUF_SIZE(buf_spec))); + } +#endif +#endif + } static void reconstructCoefficients(struct AVS2Decoder_s *dec, @@ -3465,6 +3736,110 @@ #endif } +static u32 init_cuva_size; +static int cuva_data_is_avaible(struct AVS2Decoder_s *dec) +{ + u32 reg_val; + + reg_val = READ_VREG(AVS2_CUVA_DATA_SIZE); + avs2_print(dec, AVS2_DBG_BUFMGR_MORE, + "%s:reg_val: %u \n", + __func__, reg_val); + if (reg_val != 0 && reg_val != init_cuva_size) + return 1; + else + return 0; +} + +static void config_cuva_buf(struct AVS2Decoder_s *dec) +{ + WRITE_VREG(AVS2_CUVA_ADR, dec->cuva_phy_addr); + init_cuva_size = (dec->cuva_size >> 4) << 16; + WRITE_VREG(AVS2_CUVA_DATA_SIZE, init_cuva_size); +} + +static void set_cuva_data(struct AVS2Decoder_s *dec) +{ + int i; + unsigned short *cuva_adr; + unsigned int size_reg_val = + READ_VREG(AVS2_CUVA_DATA_SIZE); + unsigned int cuva_count = 0; + int cuva_size = 0; + struct avs2_frame_s *pic = dec->avs2_dec.hc.cur_pic; + if (pic == NULL || 0 == cuva_data_is_avaible(dec)) { + avs2_print(dec, AVS2_DBG_HDR_INFO, + "%s:pic 0x%p or data not avaible\n", + __func__, pic); + return; + } + + cuva_adr = (unsigned short *)dec->cuva_addr; + cuva_count = ((size_reg_val >> 16) << 4) >> 1; + cuva_size = dec->cuva_size; + dec->hdr_flag |= HDR_CUVA_MASK; + + avs2_print(dec, AVS2_DBG_BUFMGR_MORE, + "%s:pic 0x%p cuva_count(%d) cuva_size(%d) hdr_flag 0x%x\n", + __func__, pic, cuva_count, cuva_size, dec->hdr_flag); + if (cuva_size > 0 && cuva_count > 0) { + int new_size; + char *new_buf; + + new_size = cuva_size; + new_buf = vzalloc(new_size); + if (new_buf) { + unsigned char *p = new_buf; + int len = 0; + pic->cuva_data_buf = new_buf; + + for (i = 0; i < cuva_count; i += 4) { + int j; + + for (j = 0; j < 4; j++) { + unsigned short aa = cuva_adr[i + 3 - j]; + *p = aa & 0xff; + p++; + len++; + } + } + if (len > 0) { + pic->cuva_data_size = len; + } + + avs2_print(dec, AVS2_DBG_BUFMGR_MORE, + "cuva: (size %d)\n", + pic->cuva_data_size); + if (get_dbg_flag(dec) & AVS2_DBG_HDR_DATA) { + for (i = 0; i < pic->cuva_data_size; i++) { + pr_info("%02x ", pic->cuva_data_buf[i]); + if (((i + 1) & 0xf) == 0) + pr_info("\n"); + } + pr_info("\n"); + } + + } else { + avs2_print(dec, 0, "new buf alloc failed\n"); + if (pic->cuva_data_buf) + vfree(pic->cuva_data_buf); + pic->cuva_data_buf = NULL; + pic->cuva_data_size = 0; + } + } +} + +static void release_cuva_data(struct avs2_frame_s *pic) +{ + if (pic == NULL) + return; + if (pic->cuva_data_buf) { + vfree(pic->cuva_data_buf); + } + pic->cuva_data_buf = NULL; + pic->cuva_data_size = 0; +} + static void avs2_config_work_space_hw(struct AVS2Decoder_s *dec) { struct BuffInfo_s *buf_spec = dec->work_space_buf; @@ -3511,6 +3886,12 @@ #else WRITE_VREG(HEVC_STREAM_SWAP_BUFFER, buf_spec->swap_buf.buf_start); #endif +#ifdef AVS2_10B_MMU_DW + if (dec->dw_mmu_enable) { + //WRITE_VREG(HEVC_ASSIST_MMU_MAP_ADDR2, FRAME_MMU_MAP_ADDR_DW); + WRITE_VREG(HEVC_SAO_MMU_DMA_CTRL2, dec->dw_frame_mmu_map_phy_addr); + } +#endif WRITE_VREG(HEVC_STREAM_SWAP_BUFFER2, buf_spec->swap_buf2.buf_start); //WRITE_VREG(HEVC_SCALELUT, buf_spec->scalelut.buf_start); @@ -3580,11 +3961,38 @@ #endif +#ifdef AVS2_10B_MMU_DW + if (dec->dw_mmu_enable) { + u32 data_tmp; + data_tmp = READ_VREG(HEVC_SAO_CTRL9); + data_tmp |= (1<<10); + WRITE_VREG(HEVC_SAO_CTRL9, data_tmp); + + WRITE_VREG(HEVC_CM_BODY_LENGTH2,losless_comp_body_size); + WRITE_VREG(HEVC_CM_HEADER_OFFSET2,losless_comp_body_size); + WRITE_VREG(HEVC_CM_HEADER_LENGTH2,losless_comp_header_size); + + WRITE_VREG(HEVC_SAO_MMU_VH0_ADDR2, buf_spec->mmu_vbh_dw.buf_start); + WRITE_VREG(HEVC_SAO_MMU_VH1_ADDR2, buf_spec->mmu_vbh_dw.buf_start + DW_VBH_BUF_SIZE(buf_spec)); + + /* use HEVC_CM_HEADER_START_ADDR */ + data32 = READ_VREG(HEVC_SAO_CTRL5); + data32 |= (1<<15); + WRITE_VREG(HEVC_SAO_CTRL5, data32); + } +#endif + + WRITE_VREG(LMEM_DUMP_ADR, (u32)dec->lmem_phy_addr); -#if 1 -/*MULTI_INSTANCE_SUPPORT*/ - /*new added in simulation???*/ + WRITE_VREG(HEVC_MPRED_ABV_START_ADDR, buf_spec->mpred_above.buf_start); + +#ifdef CO_MV_COMPRESS + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T7) { + data32 = READ_VREG(HEVC_MPRED_CTRL4); + data32 |= (1 << 1); + WRITE_VREG(HEVC_MPRED_CTRL4, data32); + } #endif } @@ -3611,7 +4019,6 @@ unsigned int data32; unsigned int decode_mode; int i; - /*if (debug & AVS2_DBG_BUFMGR_MORE) pr_info("%s\n", __func__);*/ data32 = READ_VREG(HEVC_PARSER_INT_CONTROL); @@ -3666,11 +4073,13 @@ WRITE_VREG(HEVC_DEC_STATUS_REG, 0); /*Initial IQIT_SCALELUT memory -- just to avoid X in simulation*/ - - WRITE_VREG(HEVC_IQIT_SCALELUT_WR_ADDR, 0);/*cfg_p_addr*/ - for (i = 0; i < 1024; i++) - WRITE_VREG(HEVC_IQIT_SCALELUT_DATA, 0); - + if (is_rdma_enable()) + rdma_back_end_work(dec->rdma_phy_adr, RDMA_SIZE); + else { + WRITE_VREG(HEVC_IQIT_SCALELUT_WR_ADDR, 0);/*cfg_p_addr*/ + for (i = 0; i < 1024; i++) + WRITE_VREG(HEVC_IQIT_SCALELUT_DATA, 0); + } #ifdef ENABLE_SWAP_TEST WRITE_VREG(HEVC_STREAM_SWAP_TEST, 100); @@ -3852,10 +4261,6 @@ } #endif - - - - static struct AVS2Decoder_s gAVS2Decoder; static void avs2_local_uninit(struct AVS2Decoder_s *dec) @@ -3868,6 +4273,14 @@ dec->rpm_phy_addr); dec->rpm_addr = NULL; } + + if (dec->cuva_addr) { + dma_free_coherent(amports_get_dma_device(), + dec->cuva_size, dec->cuva_addr, + dec->cuva_phy_addr); + dec->cuva_addr = NULL; + } + if (dec->lmem_addr) { if (dec->lmem_phy_addr) dma_free_coherent(amports_get_dma_device(), @@ -3885,6 +4298,17 @@ dec->frame_mmu_map_addr = NULL; } #endif + +#ifdef AVS2_10B_MMU_DW + if (dec->dw_frame_mmu_map_addr) { + if (dec->dw_frame_mmu_map_phy_addr) + dma_free_coherent(amports_get_dma_device(), + get_frame_mmu_map_size(dec), dec->dw_frame_mmu_map_addr, + dec->dw_frame_mmu_map_phy_addr); + dec->dw_frame_mmu_map_addr = NULL; + } +#endif + if (dec->gvs) vfree(dec->gvs); dec->gvs = NULL; @@ -3902,16 +4326,27 @@ memcpy(cur_buf_info, &amvavs2_workbuff_spec[force_bufspec & 0xf], sizeof(struct BuffInfo_s)); pr_info("force buffer spec %d\n", force_bufspec & 0xf); - } else if (vdec_is_support_4k()) { - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) - memcpy(cur_buf_info, &amvavs2_workbuff_spec[2], /* 8k */ - sizeof(struct BuffInfo_s)); - else - memcpy(cur_buf_info, &amvavs2_workbuff_spec[1], /* 4k */ - sizeof(struct BuffInfo_s)); - } else - memcpy(cur_buf_info, &amvavs2_workbuff_spec[0],/* 1080p */ - sizeof(struct BuffInfo_s)); + } else { + if (get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_TM2 && !is_cpu_tm2_revb()) { + if (vdec_is_support_4k()) { + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) + memcpy(cur_buf_info, &amvavs2_workbuff_spec[2], /* 8k */ + sizeof(struct BuffInfo_s)); + else + memcpy(cur_buf_info, &amvavs2_workbuff_spec[1], /* 4k */ + sizeof(struct BuffInfo_s)); + } else + memcpy(cur_buf_info, &amvavs2_workbuff_spec[0],/* 1080p */ + sizeof(struct BuffInfo_s)); + } else { //get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_TM2 || is_cpu_tm2_revb() + if (vdec_is_support_4k()) { + memcpy(cur_buf_info, &amvavs2_workbuff_spec[5], /* 8k */ + sizeof(struct BuffInfo_s)); + } else + memcpy(cur_buf_info, &amvavs2_workbuff_spec[3],/* 1080p */ + sizeof(struct BuffInfo_s)); + } + } cur_buf_info->start_adr = dec->buf_start; #ifndef AVS2_10B_MMU @@ -3937,14 +4372,15 @@ } avs2_bufmgr_init(dec, cur_buf_info, &dec->mc_buf_spec); #endif - - if (!vdec_is_support_4k() - && (buf_alloc_width > 1920 && buf_alloc_height > 1088)) { - buf_alloc_width = 1920; - buf_alloc_height = 1088; - } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) { - buf_alloc_width = 8192; - buf_alloc_height = 4608; + if ((buf_alloc_width & buf_alloc_height) == 0) { + if (!vdec_is_support_4k() + && (buf_alloc_width > 1920 && buf_alloc_height > 1088)) { + buf_alloc_width = 1920; + buf_alloc_height = 1088; + } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) { + buf_alloc_width = 3840; + buf_alloc_height = 2160; + } } dec->init_pic_w = buf_alloc_width ? buf_alloc_width : (dec->vavs2_amstream_dec_info.width ? @@ -3954,13 +4390,6 @@ (dec->vavs2_amstream_dec_info.height ? dec->vavs2_amstream_dec_info.height : dec->work_space_buf->max_height); -#if 0 -/*ndef MV_USE_FIXED_BUF*/ - if (init_mv_buf_list(dec) < 0) { - pr_err("%s: init_mv_buf_list fail\n", __func__); - return -1; - } -#endif #ifndef AVS2_10B_MMU init_buf_list(dec); @@ -3990,6 +4419,20 @@ dec->rpm_ptr = dec->rpm_addr; } + if (cuva_buf_size > 0) { + dec->cuva_size = AUX_BUF_ALIGN(cuva_buf_size); + + dec->cuva_addr = dma_alloc_coherent(amports_get_dma_device(), + dec->cuva_size, &dec->cuva_phy_addr, GFP_KERNEL); + avs2_print(dec, AVS2_DBG_BUFMGR, + "%s, cuva_size = %d cuva_phy_addr %x dec->cuva_addr = %px\n", + __func__, dec->cuva_size, (u32)dec->cuva_phy_addr, dec->cuva_addr); + if (dec->cuva_addr == NULL) { + pr_err("%s: failed to alloc cuva buffer\n", __func__); + return -1; + } + } + dec->lmem_addr = dma_alloc_coherent(amports_get_dma_device(), LMEM_BUF_SIZE, &dec->lmem_phy_addr, GFP_KERNEL); @@ -4000,21 +4443,33 @@ avs2_print(dec, AVS2_DBG_BUFMGR, "%s, lmem_phy_addr %x\n", __func__, (u32)dec->lmem_phy_addr); - dec->lmem_ptr = dec->lmem_addr; - #ifdef AVS2_10B_MMU - dec->frame_mmu_map_addr = dma_alloc_coherent(amports_get_dma_device(), - get_frame_mmu_map_size(dec), - &dec->frame_mmu_map_phy_addr, GFP_KERNEL); - if (dec->frame_mmu_map_addr == NULL) { - pr_err("%s: failed to alloc count_buffer\n", __func__); - return -1; + if (dec->mmu_enable) { + dec->frame_mmu_map_addr = dma_alloc_coherent(amports_get_dma_device(), + get_frame_mmu_map_size(dec), + &dec->frame_mmu_map_phy_addr, GFP_KERNEL); + if (dec->frame_mmu_map_addr == NULL) { + pr_err("%s: failed to alloc count_buffer\n", __func__); + return -1; + } + memset(dec->frame_mmu_map_addr, 0, get_frame_mmu_map_size(dec)); } - memset(dec->frame_mmu_map_addr, 0, get_frame_mmu_map_size(dec)); #endif +#ifdef AVS2_10B_MMU_DW + if (dec->dw_mmu_enable) { + dec->dw_frame_mmu_map_addr = dma_alloc_coherent(amports_get_dma_device(), + get_frame_mmu_map_size(dec), + &dec->dw_frame_mmu_map_phy_addr, GFP_KERNEL); + if (dec->dw_frame_mmu_map_addr == NULL) { + pr_err("%s: failed to alloc count_buffer\n", __func__); + return -1; + } + memset(dec->dw_frame_mmu_map_addr, 0, get_frame_mmu_map_size(dec)); + } +#endif ret = 0; return ret; } @@ -4050,16 +4505,11 @@ /*CANVAS_BLKMODE_64X32*/ if (pic->double_write_mode) { canvas_w = pic->pic_w / - get_double_write_ratio(dec, - pic->double_write_mode); + get_double_write_ratio(pic->double_write_mode); canvas_h = pic->pic_h / - get_double_write_ratio(dec, - pic->double_write_mode); - - if (mem_map_mode == 0) - canvas_w = ALIGN(canvas_w, 32); - else - canvas_w = ALIGN(canvas_w, 64); + get_double_write_ratio(pic->double_write_mode); + /*sao_crtl1 aligned with 64*/ + canvas_w = ALIGN(canvas_w, 64); canvas_h = ALIGN(canvas_h, 32); if (vdec->parallel_dec == 1) { @@ -4072,31 +4522,23 @@ pic->uv_canvas_index = 128 + pic->index * 2 + 1; } - canvas_config_ex(pic->y_canvas_index, + config_cav_lut_ex(pic->y_canvas_index, pic->dw_y_adr, canvas_w, canvas_h, - CANVAS_ADDR_NOWRAP, blkmode, 0x7); - canvas_config_ex(pic->uv_canvas_index, + CANVAS_ADDR_NOWRAP, blkmode, 0x7, VDEC_HEVC); + config_cav_lut_ex(pic->uv_canvas_index, pic->dw_u_v_adr, canvas_w, canvas_h, - CANVAS_ADDR_NOWRAP, blkmode, 0x7); + CANVAS_ADDR_NOWRAP, blkmode, 0x7, VDEC_HEVC); #ifdef MULTI_INSTANCE_SUPPORT - pic->canvas_config[0].phy_addr = - pic->dw_y_adr; - pic->canvas_config[0].width = - canvas_w; - pic->canvas_config[0].height = - canvas_h; - pic->canvas_config[0].block_mode = - blkmode; + pic->canvas_config[0].phy_addr = pic->dw_y_adr; + pic->canvas_config[0].width = canvas_w; + pic->canvas_config[0].height = canvas_h; + pic->canvas_config[0].block_mode = blkmode; pic->canvas_config[0].endian = 7; - pic->canvas_config[1].phy_addr = - pic->dw_u_v_adr; - pic->canvas_config[1].width = - canvas_w; - pic->canvas_config[1].height = - canvas_h; - pic->canvas_config[1].block_mode = - blkmode; + pic->canvas_config[1].phy_addr = pic->dw_u_v_adr; + pic->canvas_config[1].width = canvas_w; + pic->canvas_config[1].height = canvas_h; + pic->canvas_config[1].block_mode = blkmode; pic->canvas_config[1].endian = 7; #endif } else { @@ -4111,12 +4553,12 @@ pic->uv_canvas_index = 128 + pic->index; } - canvas_config_ex(pic->y_canvas_index, + config_cav_lut_ex(pic->y_canvas_index, pic->mc_y_adr, canvas_w, canvas_h, - CANVAS_ADDR_NOWRAP, blkmode, 0x7); - canvas_config_ex(pic->uv_canvas_index, - pic->mc_u_v_adr, canvas_w, canvas_h, - CANVAS_ADDR_NOWRAP, blkmode, 0x7); + CANVAS_ADDR_NOWRAP, blkmode, 0x7, VDEC_HEVC); + config_cav_lut_ex(pic->uv_canvas_index, + pic->mc_u_v_adr,canvas_w, canvas_h, + CANVAS_ADDR_NOWRAP, blkmode, 0x7, VDEC_HEVC); #endif } } @@ -4130,8 +4572,14 @@ vf->duration_pulldown = 0; vf->flag = 0; vf->prop.master_display_colour = dec->vf_dp; + if (dec->hdr_flag & HDR_CUVA_MASK) + dec->video_signal_type |= 1 << 31; vf->signal_type = dec->video_signal_type; + avs2_print(dec, AVS2_DBG_HDR_INFO, + "signal_typesignal_type 0x%x \n", + vf->signal_type); + pixel_ratio = dec->vavs2_amstream_dec_info.ratio; if (dec->vavs2_ratio == 0) { @@ -4361,6 +4809,32 @@ req->req_result[0] = vdec_secure(hw_to_vdec(dec)); else req->req_result[0] = 0xffffffff; + } else if (type & VFRAME_EVENT_RECEIVER_GET_AUX_DATA) { + struct provider_aux_req_s *req = + (struct provider_aux_req_s *)data; + unsigned char index; + unsigned long flags; + struct avs2_frame_s *pic; + + if (!req->vf) { + req->aux_size = dec->vf_put_count; + return 0; + } + lock_buffer(dec, flags); + index = req->vf->index & 0xff; + req->aux_buf = NULL; + req->aux_size = 0; + req->format = VFORMAT_AVS2; + if (index < dec->used_buf_num) { + pic = get_pic_by_index(dec, index); + req->aux_buf = pic->cuva_data_buf; + req->aux_size = pic->cuva_data_size; + } + unlock_buffer(dec, flags); + + avs2_print(dec, PRINT_FLAG_VDEC_STATUS, + "%s pic 0x%p index %d =>size %d\n", + __func__, pic, index, req->aux_size); } return 0; @@ -4462,7 +4936,7 @@ __func__, pic->index, pic->imgtr_fwRefDistance); - if (pic->double_write_mode) + if (pic->double_write_mode && (pic->double_write_mode & 0x20) == 0) set_canvas(dec, pic); display_frame_count[dec->index]++; @@ -4475,7 +4949,7 @@ } else { #endif if ((vdec->vbuf.no_parser == 0) || (vdec->vbuf.use_ptsserv)) { - /* if (pts_lookup_offset(PTS_TYPE_VIDEO, + /* if (pts_lookup_offset(PTS_TYPE_VIDEO, stream_offset, &vf->pts, 0) != 0) { */ if (pts_lookup_offset_us64 (PTS_TYPE_VIDEO, stream_offset, @@ -4530,18 +5004,16 @@ if (vf->pts != 0) dec->last_lookup_pts = vf->pts; -#if 1 + if ((dec->pts_mode == PTS_NONE_REF_USE_DURATION) && ((pic->slice_type != I_IMG) || (!pts_discontinue && !first_pts_checkin_complete(PTS_TYPE_AUDIO)))) vf->pts = dec->last_pts + DUR2PTS(dec->frame_dur); -#endif dec->last_pts = vf->pts; if (vf->pts_us64 != 0) dec->last_lookup_pts_us64 = vf->pts_us64; -#if 1 if ((dec->pts_mode == PTS_NONE_REF_USE_DURATION) && ((pic->slice_type != I_IMG) || (!pts_discontinue && !first_pts_checkin_complete(PTS_TYPE_AUDIO)))) { @@ -4549,7 +5021,7 @@ dec->last_pts_us64 + (DUR2PTS(dec->frame_dur) * 100 / 9); } -#endif + dec->last_pts_us64 = vf->pts_us64; avs2_print(dec, AVS2_DBG_OUT_PTS, "avs2 dec out pts: vf->pts=%d, vf->pts_us64 = %lld\n", @@ -4564,16 +5036,30 @@ vf->compHeadAddr = 0; } else { #ifdef AVS2_10B_MMU - vf->compBodyAddr = 0; - vf->compHeadAddr = pic->header_adr; + vf->compBodyAddr = 0; + vf->compHeadAddr = pic->header_adr; +#ifdef AVS2_10B_MMU_DW + vf->dwBodyAddr = 0; + vf->dwHeadAddr = 0; + if (pic->double_write_mode & 0x20) { + u32 mode = pic->double_write_mode & 0xf; + if (mode == 5 || mode == 3) + vf->dwHeadAddr = pic->dw_header_adr; + else if ((mode == 1 || mode == 2 || mode == 4) + && ((debug & AVS2_DBG_OUT_PTS) == 0)) { + vf->compHeadAddr = pic->dw_header_adr; + pr_info("Use dw mmu for display\n"); + } + } +#endif + #else - vf->compBodyAddr = pic->mc_y_adr; /*body adr*/ - vf->compHeadAddr = pic->mc_y_adr + - pic->comp_body_size; - /*head adr*/ + vf->compBodyAddr = pic->mc_y_adr; /*body adr*/ + vf->compHeadAddr = pic->mc_y_adr + pic->comp_body_size; #endif } - if (pic->double_write_mode) { + if (pic->double_write_mode && + ((pic->double_write_mode & 0x20) == 0)) { vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD; vf->type |= VIDTYPE_VIU_NV21; @@ -4637,17 +5123,26 @@ vf->width,vf->height, pic->width, pic->height); */ vf->width = pic->pic_w / - get_double_write_ratio(dec, - pic->double_write_mode); + get_double_write_ratio(pic->double_write_mode); vf->height = pic->pic_h / - get_double_write_ratio(dec, - pic->double_write_mode); + get_double_write_ratio(pic->double_write_mode); if (force_w_h != 0) { vf->width = (force_w_h >> 16) & 0xffff; vf->height = force_w_h & 0xffff; } - vf->compWidth = pic->pic_w; - vf->compHeight = pic->pic_h; + if ((pic->double_write_mode & 0x20) && + ((pic->double_write_mode & 0xf) == 2 || + (pic->double_write_mode & 0xf) == 4)) { + vf->compWidth = pic->pic_w / + get_double_write_ratio( + pic->double_write_mode & 0xf); + vf->compHeight = pic->pic_h / + get_double_write_ratio( + pic->double_write_mode & 0xf); + } else { + vf->compWidth = pic->pic_w; + vf->compHeight = pic->pic_h; + } if (force_fps & 0x100) { u32 rate = force_fps & 0xff; if (rate) @@ -4657,12 +5152,26 @@ } #ifdef AVS2_10B_MMU if (vf->type & VIDTYPE_SCATTER) { +#ifdef AVS2_10B_MMU_DW + if (pic->double_write_mode & 0x20) { + vf->mem_handle = + decoder_mmu_box_get_mem_handle( + dec->dw_mmu_box, pic->index); + vf->mem_head_handle = + decoder_bmmu_box_get_mem_handle( + dec->bmmu_box, + HEADER_BUFFER_IDX(pic->BUF_index)); + vf->mem_dw_handle = NULL; + } else +#endif + { vf->mem_handle = decoder_mmu_box_get_mem_handle( dec->mmu_box, pic->index); vf->mem_head_handle = decoder_bmmu_box_get_mem_handle( dec->bmmu_box, HEADER_BUFFER_IDX(pic->index)); + } } else { vf->mem_handle = decoder_bmmu_box_get_mem_handle( dec->bmmu_box, @@ -4705,7 +5214,6 @@ dec->gvs->status = dec->stat | dec->fatal_error; } - static int avs2_prepare_display_buf(struct AVS2Decoder_s *dec) { #ifndef NO_DISPLAY @@ -4725,7 +5233,8 @@ if (pic->error_mark) { avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, - "!!!error pic, skip\n"); + "!!!error pic, skip\n", + 0); continue; } @@ -4734,7 +5243,7 @@ pic->slice_type != I_IMG) { avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, "!!!slice type %d (not I) skip\n", - pic->slice_type); + 0, pic->slice_type); continue; } dec->skip_PB_before_I = 0; @@ -4771,7 +5280,7 @@ memcpy(&tmp4x, dec->gvs, sizeof(struct vdec_info)); tmp4x.bit_depth_luma = bit_depth_luma; tmp4x.bit_depth_chroma = bit_depth_chroma; - tmp4x.double_write_mode = get_double_write_mode(dec); + tmp4x.double_write_mode = pic->double_write_mode; vdec_fill_vdec_frame(pvdec, &dec->vframe_qos, &tmp4x, vf, pic->hw_decode_time); pvdec->vdec_fps_detec(pvdec->id); if (without_display_mode == 0) { @@ -4965,7 +5474,7 @@ struct vdec_s *vdec = hw_to_vdec(dec); if (!picture) { avs2_print(dec, AVS2_DBG_BUFMGR_MORE, - "decode picture is none exist\n"); + "%s decode picture is none exist\n"); return; } @@ -5432,6 +5941,7 @@ PRINT_LINE(); dec->start_decoding_flag |= 0x3; if (dec->m_ins_flag) { + set_cuva_data(dec); update_decoded_pic(dec); get_picture_qos_info(dec); reset_process_time(dec); @@ -5561,31 +6071,19 @@ dec->avs2_dec.hc.cur_pic = NULL; for (ii = 0; ii < dec->avs2_dec.ref_maxbuffer; ii++) { - if (dec->avs2_dec.fref[ii]-> - bg_flag == 0 && - dec->avs2_dec.fref[ii]-> - is_output == -1 && - dec->avs2_dec.fref[ii]-> - mmu_alloc_flag && - dec->avs2_dec.fref[ii]-> - vf_ref == 0) { - struct avs2_frame_s *pic = - dec->avs2_dec.fref[ii]; - if (dec->avs2_dec.fref[ii]-> - refered_by_others == 0) { + struct avs2_frame_s *pic = + dec->avs2_dec.fref[ii]; + if (pic->bg_flag == 0 && + pic->is_output == -1 && + pic->mmu_alloc_flag && + pic->vf_ref == 0) { + if (pic->refered_by_others == 0) { #ifdef AVS2_10B_MMU - dec->avs2_dec.fref[ii]-> - mmu_alloc_flag = 0; + pic->mmu_alloc_flag = 0; /*release_buffer_4k( dec->avs2_dec.fref[ii]->index);*/ decoder_mmu_box_free_idx(dec->mmu_box, - dec->avs2_dec.fref[ii]->index); -#ifdef DYNAMIC_ALLOC_HEAD - decoder_bmmu_box_free_idx( - dec->bmmu_box, - HEADER_BUFFER_IDX(pic->index)); - pic->header_adr = 0; -#endif + pic->index); #endif #ifndef MV_USE_FIXED_BUF decoder_bmmu_box_free_idx( @@ -5594,10 +6092,6 @@ pic->mpred_mv_wr_start_addr = 0; #endif } - decoder_bmmu_box_free_idx( - dec->bmmu_box, - VF_BUFFER_IDX(pic->index)); - dec->cma_alloc_addr = 0; } } } @@ -5634,7 +6128,7 @@ debug_buffer_mgr_more(dec); get_frame_rate(&dec->avs2_dec.param, dec); -#if 0 // The video_signal_type is type of uint16_t and result false, so comment it out. +#if 1 // The video_signal_type is type of uint16_t and result false, so comment it out. if (dec->avs2_dec.param.p.video_signal_type & (1<<30)) { union param_u *pPara; @@ -5718,9 +6212,9 @@ u32 convert_c = c; if (v & 0x2000) { - avs2_print(dec, 0, + avs2_print(dec, AVS2_DBG_HDR_INFO, "video_signal_type present:\n"); - avs2_print(dec, 0, + avs2_print(dec, AVS2_DBG_HDR_INFO, " %s %s\n", video_format_names[(v >> 10) & 7], ((v >> 9) & 1) ? @@ -5729,21 +6223,21 @@ u32 transfer; u32 maxtrix; - avs2_print(dec, 0, + avs2_print(dec, AVS2_DBG_HDR_INFO, "color_description present:\n"); - avs2_print(dec, 0, + avs2_print(dec, AVS2_DBG_HDR_INFO, "color_primarie = %d\n", v & 0xff); - avs2_print(dec, 0, + avs2_print(dec, AVS2_DBG_HDR_INFO, "transfer_characteristic = %d\n", (c >> 8) & 0xff); - avs2_print(dec, 0, + avs2_print(dec, AVS2_DBG_HDR_INFO, " matrix_coefficient = %d\n", c & 0xff); transfer = (c >> 8) & 0xFF; if (transfer >= 15) - avs2_print(dec, 0, + avs2_print(dec, AVS2_DBG_HDR_INFO, "unsupport transfer_characteristic\n"); else if (transfer == 14) transfer = 18; /* HLG */ @@ -5756,7 +6250,7 @@ maxtrix = c & 0xFF; if (maxtrix >= 10) - avs2_print(dec, 0, + avs2_print(dec, AVS2_DBG_HDR_INFO, "unsupport matrix_coefficient\n"); else if (maxtrix == 9) maxtrix = 10; @@ -5765,7 +6259,7 @@ convert_c = (transfer << 8) | (maxtrix); - avs2_print(dec, 0, + avs2_print(dec, AVS2_DBG_HDR_INFO, " convered c:0x%x\n", convert_c); } @@ -5824,34 +6318,58 @@ if (!dec->m_ins_flag) dec->slice_idx++; + if (dec->m_ins_flag && ret + && dec->avs2_dec.hc.cur_pic->cuva_data_buf != NULL) + release_cuva_data(dec->avs2_dec.hc.cur_pic); + PRINT_LINE(); #ifdef I_ONLY_SUPPORT if ((start_code == PB_PICTURE_START_CODE) && (dec->i_only & 0x2)) ret = -2; #endif -#ifdef AVS2_10B_MMU + if (ret >= 0) { - ret = avs2_alloc_mmu(dec, - dec->avs2_dec.hc.cur_pic->index, - dec->avs2_dec.img.width, - dec->avs2_dec.img.height, - dec->avs2_dec.input.sample_bit_depth, - dec->frame_mmu_map_addr); - if (ret >= 0) { - dec->cur_fb_idx_mmu = - dec->avs2_dec.hc.cur_pic->index; - dec->avs2_dec.hc.cur_pic->mmu_alloc_flag = 1; - } else - pr_err("can't alloc need mmu1,idx %d ret =%d\n", +#ifdef AVS2_10B_MMU + if (dec->mmu_enable) { + ret = avs2_alloc_mmu(dec, dec->avs2_dec.hc.cur_pic->index, - ret); - } + dec->avs2_dec.img.width, + dec->avs2_dec.img.height, + dec->avs2_dec.input.sample_bit_depth, + dec->frame_mmu_map_addr); + if (ret >= 0) { + dec->cur_fb_idx_mmu = + dec->avs2_dec.hc.cur_pic->index; + dec->avs2_dec.hc.cur_pic->mmu_alloc_flag = 1; + } else + pr_err("can't alloc need mmu1,idx %d ret =%d\n", + dec->avs2_dec.hc.cur_pic->index, + ret); + } #endif +#ifdef AVS2_10B_MMU_DW + if (dec->dw_mmu_enable) { + ret = avs2_alloc_dw_mmu(dec, + dec->avs2_dec.hc.cur_pic->index, + dec->avs2_dec.img.width, + dec->avs2_dec.img.height, + dec->avs2_dec.input.sample_bit_depth, + dec->dw_frame_mmu_map_addr); + if (ret >= 0) { + dec->cur_fb_idx_mmu = + dec->avs2_dec.hc.cur_pic->index; + dec->avs2_dec.hc.cur_pic->mmu_alloc_flag = 1; + } else + pr_err("can't alloc need dw mmu1,idx %d ret =%d\n", + dec->avs2_dec.hc.cur_pic->index, + ret); + } +#endif + } #ifndef MV_USE_FIXED_BUF - if (ret >= 0 && - dec->avs2_dec.hc.cur_pic-> + if (ret >= 0 && dec->avs2_dec.hc.cur_pic-> mpred_mv_wr_start_addr == 0) { unsigned long buf_addr; unsigned mv_buf_size = get_mv_buf_size( @@ -5880,7 +6398,8 @@ ret); WRITE_VREG(HEVC_DEC_STATUS_REG, AVS2_10B_DISCARD_NAL); #ifdef AVS2_10B_MMU - avs2_recycle_mmu_buf(dec); + if (dec->mmu_enable) + avs2_recycle_mmu_buf(dec); #endif if (dec->m_ins_flag) { dec->dec_result = DEC_RESULT_DONE; @@ -6075,10 +6594,10 @@ return IRQ_WAKE_THREAD; } -static void vavs2_put_timer_func(unsigned long arg) +static void vavs2_put_timer_func(struct timer_list *timer) { - struct AVS2Decoder_s *dec = (struct AVS2Decoder_s *)arg; - struct timer_list *timer = &dec->timer; + struct AVS2Decoder_s *dec = container_of(timer, + struct AVS2Decoder_s, timer); uint8_t empty_flag; unsigned int buf_level; @@ -6196,6 +6715,7 @@ } if (debug & AVS2_DBG_DUMP_RPM_BUF) { int i; + pr_info("RPM:\n"); for (i = 0; i < RPM_BUF_SIZE; i += 4) { int ii; @@ -6212,6 +6732,7 @@ } if (debug & AVS2_DBG_DUMP_LMEM_BUF) { int i; + pr_info("LMEM:\n"); for (i = 0; i < LMEM_BUF_SIZE; i += 4) { int ii; @@ -6407,6 +6928,7 @@ WRITE_VREG(DECODE_STOP_POS, udebug_flag); + config_cuva_buf(dec); } #ifdef I_ONLY_SUPPORT @@ -6495,7 +7017,8 @@ int fw_size = 0x1000 * 16; struct firmware_s *fw = NULL; struct AVS2Decoder_s *dec = (struct AVS2Decoder_s *)vdec->private; - init_timer(&dec->timer); + + timer_setup(&dec->timer, vavs2_put_timer_func, 0); dec->stat |= STAT_TIMER_INIT; if (vavs2_local_init(dec) < 0) @@ -6517,8 +7040,6 @@ fw->len = fw_size; if (dec->m_ins_flag) { - dec->timer.data = (ulong) dec; - dec->timer.function = vavs2_put_timer_func; dec->timer.expires = jiffies + PUT_INTERVAL; /*add_timer(&dec->timer); @@ -6531,7 +7052,9 @@ return 0; } + amhevc_enable(); + ret = amhevc_loadmc_ex(VFORMAT_AVS2, NULL, fw->data); if (ret < 0) { amhevc_disable(); @@ -6574,11 +7097,7 @@ } dec->stat |= STAT_VF_HOOK; - dec->timer.data = (ulong)dec; - dec->timer.function = vavs2_put_timer_func; dec->timer.expires = jiffies + PUT_INTERVAL; - - add_timer(&dec->timer); dec->stat |= STAT_TIMER_ARM; @@ -6670,17 +7189,32 @@ CODEC_MM_FLAGS_TVP : 0; int buf_size = 48; -#ifdef AVS2_10B_MMU dec->need_cache_size = buf_size * SZ_1M; dec->sc_start_time = get_jiffies_64(); - dec->mmu_box = decoder_mmu_box_alloc_box(DRIVER_NAME, - dec->index, FRAME_BUFFERS, - dec->need_cache_size, - tvp_flag - ); - if (!dec->mmu_box) { - pr_err("avs2 alloc mmu box failed!!\n"); - return -1; +#ifdef AVS2_10B_MMU + if (dec->mmu_enable) { + dec->mmu_box = decoder_mmu_box_alloc_box(DRIVER_NAME, + dec->index, FRAME_BUFFERS, + dec->need_cache_size, + tvp_flag + ); + if (!dec->mmu_box) { + pr_err("avs2 alloc mmu box failed!!\n"); + return -1; + } + } +#endif +#ifdef AVS2_10B_MMU_DW + if (dec->dw_mmu_enable) { + dec->dw_mmu_box = decoder_mmu_box_alloc_box(DRIVER_NAME, + dec->index, FRAME_BUFFERS, + dec->need_cache_size, + tvp_flag + ); + if (!dec->dw_mmu_box) { + pr_err("avs2 alloc dw mmu box failed!!\n"); + dec->dw_mmu_enable = 0; + } } #endif dec->bmmu_box = decoder_bmmu_box_alloc_box( @@ -6701,15 +7235,19 @@ static int amvdec_avs2_probe(struct platform_device *pdev) { struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data; - struct BUF_s BUF[MAX_BUF_NUM]; + /*struct BUF_s BUF[MAX_BUF_NUM];*/ struct AVS2Decoder_s *dec = &gAVS2Decoder; int ret; pr_info("%s\n", __func__); - mutex_lock(&vavs2_mutex); - memcpy(&BUF[0], &dec->m_BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM); - memset(dec, 0, sizeof(struct AVS2Decoder_s)); - memcpy(&dec->m_BUF[0], &BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM); + dec = vzalloc(sizeof(struct AVS2Decoder_s)); + if (!dec) + return -ENOMEM; + + pdata->private = dec; + platform_set_drvdata(pdev, pdata); + + mutex_lock(&vavs2_mutex); dec->init_flag = 0; dec->first_sc_checked = 0; @@ -6728,6 +7266,14 @@ dec->platform_dev = pdev; platform_set_drvdata(pdev, pdata); +#ifdef AVS2_10B_MMU_DW + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T5D) { + dec->dw_mmu_enable = + (get_double_write_mode(dec) & 0x20) ? 1 : 0; + } else { + dec->dw_mmu_enable = 0; + } +#endif if (amvdec_avs2_mmu_init(dec) < 0) { mutex_unlock(&vavs2_mutex); pr_err("avs2 alloc bmmu box failed!!\n"); @@ -6763,6 +7309,12 @@ } dec->cma_dev = pdata->cma_dev; + dec->endian = HEVC_CONFIG_LITTLE_ENDIAN; + if (is_support_vdec_canvas()) + dec->endian = HEVC_CONFIG_BIG_ENDIAN; + if (endian) + dec->endian = endian; + pdata->private = dec; pdata->dec_status = vavs2_dec_status; /*pdata->set_isreset = vavs2_set_isreset;*/ @@ -6808,32 +7360,16 @@ } /****************************************/ -#ifdef CONFIG_PM -static int avs2_suspend(struct device *dev) -{ - amhevc_suspend(to_platform_device(dev), dev->power.power_state); - return 0; -} - -static int avs2_resume(struct device *dev) -{ - amhevc_resume(to_platform_device(dev)); - return 0; -} - -static const struct dev_pm_ops avs2_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(avs2_suspend, avs2_resume) -}; -#endif static struct platform_driver amvdec_avs2_driver = { .probe = amvdec_avs2_probe, .remove = amvdec_avs2_remove, +#ifdef CONFIG_PM + .suspend = amhevc_suspend, + .resume = amhevc_resume, +#endif .driver = { .name = DRIVER_NAME, -#ifdef CONFIG_PM - .pm = &avs2_pm_ops, -#endif } }; @@ -7001,8 +7537,8 @@ decode_frame_count[dec->index] = dec->frame_count; #ifdef AVS2_10B_MMU - dec->used_4k_num = - (READ_VREG(HEVC_SAO_MMU_STATUS) >> 16); + if (dec->mmu_enable) + dec->used_4k_num = (READ_VREG(HEVC_SAO_MMU_STATUS) >> 16); #endif avs2_print(dec, PRINT_FLAG_VDEC_STATUS, "%s (===> %d) dec_result %d %x %x %x shiftbytes 0x%x decbytes 0x%x\n", @@ -7376,7 +7912,7 @@ for (i = 0; i < MAX_BUF_NUM; i++) { avs2_print(dec, 0, - "mv_Buf(%d) start_adr 0x%lx size 0x%x used %d\n", + "mv_Buf(%d) start_adr 0x%x size 0x%x used %d\n", i, dec->m_mv_BUF[i].start_adr, dec->m_mv_BUF[i].size, @@ -7465,12 +8001,18 @@ struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data; int ret; int config_val; + int i; struct vframe_content_light_level_s content_light_level; struct vframe_master_display_colour_s vf_dp; - - struct BUF_s BUF[MAX_BUF_NUM]; + /*struct BUF_s BUF[MAX_BUF_NUM];*/ struct AVS2Decoder_s *dec = NULL; + pr_info("%s\n", __func__); + if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5D) { + pr_info("%s, chip id %d is not support avs2\n", + __func__, get_cpu_major_id()); + return -1; + } if (pdata == NULL) { pr_info("\nammvdec_avs2 memory resource undefined.\n"); return -EFAULT; @@ -7478,8 +8020,7 @@ /*dec = (struct AVS2Decoder_s *)devm_kzalloc(&pdev->dev, sizeof(struct AVS2Decoder_s), GFP_KERNEL);*/ memset(&vf_dp, 0, sizeof(struct vframe_master_display_colour_s)); - dec = vmalloc(sizeof(struct AVS2Decoder_s)); - memset(dec, 0, sizeof(struct AVS2Decoder_s)); + dec = vzalloc(sizeof(struct AVS2Decoder_s)); if (dec == NULL) { pr_info("\nammvdec_avs2 device data allocation failed\n"); return -ENOMEM; @@ -7503,12 +8044,26 @@ pdata->threaded_irq_handler = avs2_threaded_irq_cb; pdata->dump_state = avs2_dump_state; - memcpy(&BUF[0], &dec->m_BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM); - memset(dec, 0, sizeof(struct AVS2Decoder_s)); - memcpy(&dec->m_BUF[0], &BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM); + /* + * memcpy(&BUF[0], &dec->m_BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM); + * memset(dec, 0, sizeof(struct AVS2Decoder_s)); + * memcpy(&dec->m_BUF[0], &BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM); + */ dec->index = pdev->id; dec->m_ins_flag = 1; + if (is_rdma_enable()) { + dec->rdma_adr = dma_alloc_coherent(amports_get_dma_device(), RDMA_SIZE, &dec->rdma_phy_adr, GFP_KERNEL); + for (i = 0; i < SCALELUT_DATA_WRITE_NUM; i++) { + dec->rdma_adr[i * 4] = HEVC_IQIT_SCALELUT_WR_ADDR & 0xfff; + dec->rdma_adr[i * 4 + 1] = i; + dec->rdma_adr[i * 4 + 2] = HEVC_IQIT_SCALELUT_DATA & 0xfff; + dec->rdma_adr[i * 4 + 3] = 0; + if (i == SCALELUT_DATA_WRITE_NUM - 1) { + dec->rdma_adr[i * 4 + 2] = (HEVC_IQIT_SCALELUT_DATA & 0xfff) | 0x20000; + } + } + } snprintf(dec->vdec_name, sizeof(dec->vdec_name), "avs2-%d", dec->index); @@ -7538,9 +8093,8 @@ dec->video_ori_signal_type = 0; if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_TXLX) dec->stat |= VP9_TRIGGER_FRAME_ENABLE; -#if 1 - if ((debug & IGNORE_PARAM_FROM_CONFIG) == 0 && - pdata->config_len) { + + if ((debug & IGNORE_PARAM_FROM_CONFIG) == 0 && pdata->config_len) { /*use ptr config for doubel_write_mode, etc*/ avs2_print(dec, 0, "pdata->config=%s\n", pdata->config); if (get_config_int(pdata->config, "avs2_double_write_mode", @@ -7601,9 +8155,7 @@ | (9 << 0); /* 2020 */ } dec->vf_dp = vf_dp; - } else -#endif - { + } else { /*dec->vavs2_amstream_dec_info.width = 0; dec->vavs2_amstream_dec_info.height = 0; dec->vavs2_amstream_dec_info.rate = 30;*/ @@ -7612,10 +8164,21 @@ } video_signal_type = dec->video_signal_type; -#if 0 - dec->buf_start = pdata->mem_start; - dec->buf_size = pdata->mem_end - pdata->mem_start + 1; -#else + if (double_write_mode) { + dec->double_write_mode = get_double_write_mode(dec); + } + + if ((dec->double_write_mode & 0x10) == 0) + dec->mmu_enable = 1; + +#ifdef AVS2_10B_MMU_DW + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T5D) { + dec->dw_mmu_enable = + (get_double_write_mode(dec) & 0x20) ? 1 : 0; + } else { + dec->dw_mmu_enable = 0; + } +#endif if (amvdec_avs2_mmu_init(dec) < 0) { pr_err("avs2 alloc bmmu box failed!!\n"); /* devm_kfree(&pdev->dev, (void *)dec); */ @@ -7634,7 +8197,7 @@ } dec->buf_start = dec->cma_alloc_addr; dec->buf_size = work_buf_size; -#endif + dec->init_flag = 0; dec->first_sc_checked = 0; dec->fatal_error = 0; @@ -7656,6 +8219,12 @@ dec->vavs2_amstream_dec_info.rate = 30; } + dec->endian = HEVC_CONFIG_LITTLE_ENDIAN; + if (is_support_vdec_canvas()) + dec->endian = HEVC_CONFIG_BIG_ENDIAN; + if (endian) + dec->endian = endian; + dec->cma_dev = pdata->cma_dev; if (vavs2_init(pdata) < 0) { pr_info("\namvdec_avs2 init failed.\n"); @@ -7684,6 +8253,8 @@ struct AVS2Decoder_s *dec = (struct AVS2Decoder_s *) (((struct vdec_s *)(platform_get_drvdata(pdev)))->private); struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data; + struct avs2_decoder *avs2_dec = &dec->avs2_dec; + struct avs2_frame_s *pic; int i; if (debug) @@ -7704,11 +8275,21 @@ } } + for (i = 0; i < dec->used_buf_num; i++) { + if (i == (dec->used_buf_num - 1)) + pic = avs2_dec->m_bg; + else + pic = avs2_dec->fref[i]; + release_cuva_data(pic); + } + #ifdef DEBUG_PTS pr_info("pts missed %ld, pts hit %ld, duration %d\n", dec->pts_missed, dec->pts_hit, dec->frame_dur); #endif + if (is_rdma_enable()) + dma_free_coherent(amports_get_dma_device(), RDMA_SIZE, dec->rdma_adr, dec->rdma_phy_adr); /* devm_kfree(&pdev->dev, (void *)dec); */ vfree((void *)dec); return 0; @@ -7717,11 +8298,12 @@ static struct platform_driver ammvdec_avs2_driver = { .probe = ammvdec_avs2_probe, .remove = ammvdec_avs2_remove, +#ifdef CONFIG_PM + .suspend = amvdec_suspend, + .resume = amvdec_resume, +#endif .driver = { .name = MULTI_DRIVER_NAME, -#ifdef CONFIG_PM - .pm = &avs2_pm_ops, -#endif } }; #endif @@ -7767,16 +8349,22 @@ { #ifdef AVS2_10B_MMU - struct BuffInfo_s *p_buf_info; - if (vdec_is_support_4k()) { - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) - p_buf_info = &amvavs2_workbuff_spec[2]; - else - p_buf_info = &amvavs2_workbuff_spec[1]; - } else - p_buf_info = &amvavs2_workbuff_spec[0]; + if (get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_TM2 && !is_cpu_tm2_revb()) { + if (vdec_is_support_4k()) { + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) + p_buf_info = &amvavs2_workbuff_spec[2]; + else + p_buf_info = &amvavs2_workbuff_spec[1]; + } else + p_buf_info = &amvavs2_workbuff_spec[0]; + } else { //get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_TM2 || is_cpu_tm2_revb() + if (vdec_is_support_4k()) { + p_buf_info = &amvavs2_workbuff_spec[5]; + } else + p_buf_info = &amvavs2_workbuff_spec[3]; + } init_buff_spec(NULL, p_buf_info); work_buf_size = @@ -7803,10 +8391,10 @@ return -ENODEV; } - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) { - amvdec_avs2_profile.profile = - "8k, 10bit, dwrite, compressed"; - } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { + if ((get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_G12A) || + (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5D)) { + amvdec_avs2_profile.name = "avs2_unsupport"; + } else if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SM1) { if (vdec_is_support_4k()) amvdec_avs2_profile.profile = "4k, 10bit, dwrite, compressed"; @@ -7814,7 +8402,9 @@ amvdec_avs2_profile.profile = "10bit, dwrite, compressed"; } else { - amvdec_avs2_profile.name = "avs2_unsupport"; + /* cpu id larger than sm1 support 8k */ + amvdec_avs2_profile.profile = + "8k, 10bit, dwrite, compressed"; } vcodec_profile_register(&amvdec_avs2_profile); @@ -7824,6 +8414,7 @@ INIT_REG_NODE_CONFIGS("media.decoder", &avs2_node, "avs2", avs2_configs, CONFIG_FOR_RW); + vcodec_feature_register(VFORMAT_AVS2, 0); return 0; }
diff --git a/drivers/frame_provider/decoder/avs2/vavs2.h b/drivers/frame_provider/decoder/avs2/vavs2.h index 6b51f61..071bfb3 100644 --- a/drivers/frame_provider/decoder/avs2/vavs2.h +++ b/drivers/frame_provider/decoder/avs2/vavs2.h
@@ -19,7 +19,7 @@ #define VAVS2_H #define AVS2_10B_MMU -#define MV_USE_FIXED_BUF +#define AVS2_10B_MMU_DW void adapt_coef_probs(int pic_count, int prev_kf, int cur_kf, int pre_fc, unsigned int *prev_prob, unsigned int *cur_prob, unsigned int *count);
diff --git a/drivers/frame_provider/decoder/avs_multi/avs_multi.c b/drivers/frame_provider/decoder/avs_multi/avs_multi.c index 38e39d0..7dd20bb 100644 --- a/drivers/frame_provider/decoder/avs_multi/avs_multi.c +++ b/drivers/frame_provider/decoder/avs_multi/avs_multi.c
@@ -44,6 +44,7 @@ #include "../utils/firmware.h" #include "../../../common/chips/decoder_cpu_ver_info.h" #include <linux/amlogic/tee.h> +#include "../utils/vdec_feature.h" #define DEBUG_MULTI_FLAG 0 /* @@ -123,9 +124,6 @@ #define DECODE_CFG AV_SCRATCH_K - - - #define VF_POOL_SIZE 64 #define PUT_INTERVAL (HZ/100) @@ -153,7 +151,7 @@ #define DEBUG_REG2 AV_SCRATCH_D -static void check_timer_func(unsigned long arg); +static void check_timer_func(struct timer_list *timer); static void vavs_work(struct work_struct *work); #define DEC_CONTROL_FLAG_FORCE_2500_1080P_INTERLACE 0x0001 @@ -1272,35 +1270,35 @@ } else { #ifdef NV21 - canvas_config(canvas_base + canvas_num * i + 0, + config_cav_lut_ex(canvas_base + canvas_num * i + 0, buf_start, canvas_width, canvas_height, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_32X32); - canvas_config(canvas_base + canvas_num * i + 1, + CANVAS_BLKMODE_32X32, 0, VDEC_1); + config_cav_lut_ex(canvas_base + canvas_num * i + 1, buf_start + decbuf_y_size, canvas_width, canvas_height / 2, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_32X32); + CANVAS_BLKMODE_32X32, 0, VDEC_1); #else - canvas_config(canvas_num * i + 0, + config_cav_lut_ex(canvas_num * i + 0, buf_start, canvas_width, canvas_height, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_32X32); - canvas_config(canvas_num * i + 1, + CANVAS_BLKMODE_32X32, 0, VDEC_1); + config_cav_lut_ex(canvas_num * i + 1, buf_start + decbuf_y_size, canvas_width / 2, canvas_height / 2, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_32X32); - canvas_config(canvas_num * i + 2, + CANVAS_BLKMODE_32X32, 0, VDEC_1); + config_cav_lut_ex(canvas_num * i + 2, buf_start + decbuf_y_size + decbuf_uv_size, canvas_width / 2, canvas_height / 2, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_32X32); + CANVAS_BLKMODE_32X32, 0, VDEC_1); #endif debug_print(hw, PRINT_FLAG_VFRAME_DETAIL, "canvas config %d, addr %p\n", i, @@ -1392,6 +1390,7 @@ #ifdef NV21 SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17); #endif + CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 16); #ifdef PIC_DC_NEED_CLEAR CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 31); @@ -1601,21 +1600,21 @@ vavs_restore_regs(hw); for (i = 0; i < hw->vf_buf_num_used; i++) { - canvas_config_ex(canvas_y(hw->canvas_spec[i]), + config_cav_lut_ex(canvas_y(hw->canvas_spec[i]), hw->canvas_config[i][0].phy_addr, hw->canvas_config[i][0].width, hw->canvas_config[i][0].height, CANVAS_ADDR_NOWRAP, hw->canvas_config[i][0].block_mode, - 0); + 0, VDEC_1); - canvas_config_ex(canvas_u(hw->canvas_spec[i]), + config_cav_lut_ex(canvas_u(hw->canvas_spec[i]), hw->canvas_config[i][1].phy_addr, hw->canvas_config[i][1].width, hw->canvas_config[i][1].height, CANVAS_ADDR_NOWRAP, hw->canvas_config[i][1].block_mode, - 0); + 0, VDEC_1); } } else { r = vavs_canvas_init(hw); @@ -1695,6 +1694,7 @@ #ifdef NV21 SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17); #endif + CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 16); #ifdef PIC_DC_NEED_CLEAR CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 31); @@ -1938,9 +1938,10 @@ #ifdef DEBUG_MULTI_WITH_AUTOMODE int delay_count = 0; #endif -static void vavs_put_timer_func(unsigned long arg) +static void vavs_put_timer_func(struct timer_list *arg) { - struct vdec_avs_hw_s *hw = (struct vdec_avs_hw_s *)arg; + struct vdec_avs_hw_s *hw = container_of(arg, + struct vdec_avs_hw_s, recycle_timer); struct timer_list *timer = &hw->recycle_timer; #ifndef HANDLE_AVS_IRQ @@ -2215,9 +2216,10 @@ hw->fw = fw; if (hw->m_ins_flag) { - init_timer(&hw->check_timer); - hw->check_timer.data = (ulong) hw; - hw->check_timer.function = check_timer_func; + timer_setup(&hw->check_timer, check_timer_func, 0); + //init_timer(&hw->check_timer); + //hw->check_timer.data = (ulong) hw; + //hw->check_timer.function = check_timer_func; hw->check_timer.expires = jiffies + CHECK_INTERVAL; @@ -2287,8 +2289,9 @@ hw->stat |= STAT_VF_HOOK; - hw->recycle_timer.data = (ulong)(hw); - hw->recycle_timer.function = vavs_put_timer_func; + timer_setup(&hw->recycle_timer, vavs_put_timer_func, 0); + //hw->recycle_timer.data = (ulong)(hw); + //hw->recycle_timer.function = vavs_put_timer_func; hw->recycle_timer.expires = jiffies + PUT_INTERVAL; add_timer(&hw->recycle_timer); @@ -2510,7 +2513,7 @@ } /****************************************/ -#ifdef DEBUG_WITH_SINGLE_MODE +#if 0 static struct platform_driver amvdec_avs_driver = { .probe = amvdec_avs_probe, .remove = amvdec_avs_remove, @@ -2519,6 +2522,7 @@ } }; #endif + static void recycle_frames(struct vdec_avs_hw_s *hw); static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) @@ -2527,7 +2531,6 @@ (struct vdec_avs_hw_s *)vdec->private; int ret = 1; unsigned buf_busy_mask = (1 << hw->vf_buf_num_used) - 1; - #ifdef DEBUG_MULTI_FRAME_INS if ((DECODE_ID(hw) == 0) && run_count[0] > run_count[1] && run_count[1] < max_run_count[1]) @@ -2849,9 +2852,10 @@ } -static void check_timer_func(unsigned long arg) +static void check_timer_func(struct timer_list *timer) { - struct vdec_avs_hw_s *hw = (struct vdec_avs_hw_s *)arg; + struct vdec_avs_hw_s *hw = container_of(timer, + struct vdec_avs_hw_s, check_timer); struct vdec_s *vdec = hw_to_vdec(hw); unsigned int timeout_val = decode_timeout_val; unsigned long flags; @@ -3191,8 +3195,8 @@ "%s READ_VREG(AVS_BUFFERIN)=0x%x, recycle_q num %d\n", __func__, READ_VREG(AVS_BUFFERIN), kfifo_len(&hw->recycle_q)); - WRITE_VREG(VIFF_BIT_CNT, size * 8); + WRITE_VREG(VIFF_BIT_CNT, size * 8); if (hw->reset_decode_flag) WRITE_VREG(DECODE_STATUS, 0); else { @@ -3835,7 +3839,6 @@ #endif } - static irqreturn_t vmavs_isr(struct vdec_s *vdec, int irq) { @@ -4375,21 +4378,21 @@ vavs_restore_regs(hw); for (i = 0; i < hw->vf_buf_num_used; i++) { - canvas_config_ex(canvas_y(hw->canvas_spec[i]), + config_cav_lut_ex(canvas_y(hw->canvas_spec[i]), hw->canvas_config[i][0].phy_addr, hw->canvas_config[i][0].width, hw->canvas_config[i][0].height, CANVAS_ADDR_NOWRAP, hw->canvas_config[i][0].block_mode, - 0); + 0, VDEC_1); - canvas_config_ex(canvas_u(hw->canvas_spec[i]), + config_cav_lut_ex(canvas_u(hw->canvas_spec[i]), hw->canvas_config[i][1].phy_addr, hw->canvas_config[i][1].width, hw->canvas_config[i][1].height, CANVAS_ADDR_NOWRAP, hw->canvas_config[i][1].block_mode, - 0); + 0, VDEC_1); } } } @@ -4449,6 +4452,8 @@ #ifdef NV21 SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17); #endif + CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 16); + if (start_decoding_delay & 0x20000) msleep(start_decoding_delay&0xffff); @@ -4862,6 +4867,8 @@ pr_info("failed to register amvdec_avs driver\n"); return -ENODEV; } +#else + //amvdec_avs_driver = amvdec_avs_driver; #endif if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXBB) ammvdec_avs_profile.profile = "mavs+"; @@ -4869,6 +4876,7 @@ vcodec_profile_register(&ammvdec_avs_profile); INIT_REG_NODE_CONFIGS("media.decoder", &mavs_node, "mavs", mavs_configs, CONFIG_FOR_RW); + vcodec_feature_register(VFORMAT_AVS, 0); return 0; } @@ -4981,7 +4989,6 @@ module_param(udebug_pause_ins_id, uint, 0664); MODULE_PARM_DESC(udebug_pause_ins_id, "\n udebug_pause_ins_id\n"); - module_param(start_decoding_delay, uint, 0664); MODULE_PARM_DESC(start_decoding_delay, "\n start_decoding_delay\n");
diff --git a/drivers/frame_provider/decoder/h264/vh264.c b/drivers/frame_provider/decoder/h264/vh264.c index 03a1dba..55f0581 100644 --- a/drivers/frame_provider/decoder/h264/vh264.c +++ b/drivers/frame_provider/decoder/h264/vh264.c
@@ -23,7 +23,6 @@ #include <linux/timer.h> #include <linux/kfifo.h> #include <linux/platform_device.h> - #include <linux/amlogic/media/utils/amstream.h> #include <linux/amlogic/media/frame_sync/ptsserv.h> #include <linux/amlogic/media/vfm/vframe.h> @@ -38,7 +37,6 @@ #include <linux/slab.h> #include "../../../stream_input/amports/amports_priv.h" #include <linux/amlogic/media/canvas/canvas.h> - #include "../utils/vdec.h" #include <linux/amlogic/media/utils/vdec_reg.h> #include "../utils/amvdec.h" @@ -46,19 +44,17 @@ #include "../../../stream_input/amports/streambuf.h" #include <linux/delay.h> #include <linux/amlogic/media/video_sink/video.h> -#include <linux/amlogic/tee.h> +//#include <linux/amlogic/tee.h> +#include <uapi/linux/tee.h> #include <linux/amlogic/media/ge2d/ge2d.h> #include "../utils/decoder_mmu_box.h" #include "../utils/decoder_bmmu_box.h" #include <linux/amlogic/media/codec_mm/codec_mm.h> #include <linux/amlogic/media/codec_mm/configs.h> #include "../utils/firmware.h" -#include <linux/amlogic/tee.h> #include "../../../common/chips/decoder_cpu_ver_info.h" #include <linux/uaccess.h> - - #define DRIVER_NAME "amvdec_h264" #define MODULE_NAME "amvdec_h264" #define MEM_NAME "codec_264" @@ -160,7 +156,7 @@ static void vh264_prot_init(void); static int vh264_local_init(void); -static void vh264_put_timer_func(unsigned long arg); +static void vh264_put_timer_func(struct timer_list *timer); static void stream_switching_done(void); static const char vh264_dec_id[] = "vh264-dev"; @@ -253,14 +249,6 @@ #endif static u32 enable_userdata_debug; -/* if not define, must clear AV_SCRATCH_J in isr when - * ITU_T35 code enabled in ucode, otherwise may fatal - * error repeatly. - */ -//#define ENABLE_SEI_ITU_T35 - - - static unsigned int enable_switch_fense = 1; #define EN_SWITCH_FENCE() (enable_switch_fense && !is_4k) static struct vframe_qos_s s_vframe_qos; @@ -472,15 +460,15 @@ int endian; endian = (canvas_mode == CANVAS_BLKMODE_LINEAR)?7:0; - canvas_config_ex(spec->y_canvas_index, + config_cav_lut_ex(spec->y_canvas_index, spec->y_addr, width, height, - CANVAS_ADDR_NOWRAP, canvas_mode, endian); + CANVAS_ADDR_NOWRAP, canvas_mode, endian, VDEC_1); - canvas_config_ex(spec->u_canvas_index, + config_cav_lut_ex(spec->u_canvas_index, spec->u_addr, width, height / 2, - CANVAS_ADDR_NOWRAP, canvas_mode, endian); + CANVAS_ADDR_NOWRAP, canvas_mode, endian, VDEC_1); } @@ -2208,16 +2196,16 @@ buffer_spec[i].v_canvas_height = mb_height << 4; endian = (canvas_mode == CANVAS_BLKMODE_LINEAR)?7:0; - canvas_config_ex(128 + i * 2, + config_cav_lut_ex(128 + i * 2, buffer_spec[i].y_addr, mb_width << 4, mb_height << 4, CANVAS_ADDR_NOWRAP, - canvas_mode, endian); - canvas_config_ex(128 + i * 2 + 1, + canvas_mode, endian, VDEC_1); + config_cav_lut_ex(128 + i * 2 + 1, buffer_spec[i].u_addr, mb_width << 4, mb_height << 3, CANVAS_ADDR_NOWRAP, - canvas_mode, endian); + canvas_mode, endian, VDEC_1); WRITE_VREG(ANC0_CANVAS_ADDR + i, spec2canvas(&buffer_spec[i])); } else { @@ -2599,7 +2587,6 @@ gvs->ratio_control = ratio_control; } - #ifdef HANDLE_H264_IRQ static irqreturn_t vh264_isr(int irq, void *dev_id) #else @@ -3348,9 +3335,8 @@ frame_width, frame_height, fps); } -static void vh264_put_timer_func(unsigned long arg) +static void vh264_put_timer_func(struct timer_list *timer) { - struct timer_list *timer = (struct timer_list *)arg; unsigned int wait_buffer_status; unsigned int wait_i_pass_frames; unsigned int reg_val; @@ -3800,7 +3786,7 @@ int firmwareloaded = 0; /* pr_info("\nvh264_init\n"); */ - init_timer(&recycle_timer); + timer_setup(&recycle_timer, vh264_put_timer_func, 0); stat |= STAT_TIMER_INIT; @@ -3992,10 +3978,7 @@ stat |= STAT_VF_HOOK; - recycle_timer.data = (ulong) &recycle_timer; - recycle_timer.function = vh264_put_timer_func; recycle_timer.expires = jiffies + PUT_INTERVAL; - add_timer(&recycle_timer); stat |= STAT_TIMER_ARM; @@ -4224,17 +4207,17 @@ canvas_read(y_index, &csy); canvas_read(u_index, &csu); - canvas_config(fense_buffer_spec[i].y_canvas_index, + config_cav_lut_ex(fense_buffer_spec[i].y_canvas_index, fense_buffer_spec[i].phy_addr, mb_width_num << 4, mb_height_num << 4, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_LINEAR); - canvas_config(fense_buffer_spec[i].u_canvas_index, + CANVAS_BLKMODE_LINEAR, 0, VDEC_1); + config_cav_lut_ex(fense_buffer_spec[i].u_canvas_index, fense_buffer_spec[i].phy_addr + (mb_total_num << 8), mb_width_num << 4, mb_height_num << 3, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_LINEAR); + CANVAS_BLKMODE_LINEAR, 0, VDEC_1); y_desindex = fense_buffer_spec[i].y_canvas_index; u_desindex = fense_buffer_spec[i].u_canvas_index; @@ -4351,8 +4334,6 @@ INIT_WORK(&userdata_push_work, userdata_push_do_work); INIT_WORK(&qos_work, qos_do_work); - - atomic_set(&vh264_active, 1); mutex_unlock(&vh264_mutex); @@ -4395,32 +4376,16 @@ } /****************************************/ -#ifdef CONFIG_PM -static int h264_suspend(struct device *dev) -{ - amvdec_suspend(to_platform_device(dev), dev->power.power_state); - return 0; -} - -static int h264_resume(struct device *dev) -{ - amvdec_resume(to_platform_device(dev)); - return 0; -} - -static const struct dev_pm_ops h264_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(h264_suspend, h264_resume) -}; -#endif static struct platform_driver amvdec_h264_driver = { .probe = amvdec_h264_probe, .remove = amvdec_h264_remove, +#ifdef CONFIG_PM + .suspend = amvdec_suspend, + .resume = amvdec_resume, +#endif .driver = { .name = DRIVER_NAME, -#ifdef CONFIG_PM - .pm = &h264_pm_ops, -#endif } }; @@ -4460,7 +4425,8 @@ return -ENODEV; } if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXTVBB - && (codec_mm_get_total_size() > 80 * SZ_1M)) { + && (codec_mm_get_total_size() > 80 * SZ_1M) && + get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5D) { amvdec_h264_profile.profile = "4k"; } vcodec_profile_register(&amvdec_h264_profile); @@ -4490,7 +4456,7 @@ MODULE_PARM_DESC(dec_control, "\n amvdec_h264 decoder control\n"); module_param(frame_count, uint, 0664); MODULE_PARM_DESC(frame_count, - "\n amvdec_h264 decoded total count\n"); + "\n amvdec_h264 decoded total count\n"); module_param(fatal_error_reset, uint, 0664); MODULE_PARM_DESC(fatal_error_reset, "\n amvdec_h264 decoder reset when fatal error happens\n");
diff --git a/drivers/frame_provider/decoder/h264/vh264_4k2k.c b/drivers/frame_provider/decoder/h264/vh264_4k2k.c deleted file mode 100644 index 44465ad..0000000 --- a/drivers/frame_provider/decoder/h264/vh264_4k2k.c +++ /dev/null
@@ -1,1808 +0,0 @@ -/* - * drivers/amlogic/amports/vh264_4k2k.c - * - * Copyright (C) 2015 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/interrupt.h> -#include <linux/timer.h> -#include <linux/kfifo.h> -#include <linux/platform_device.h> -#include <linux/amlogic/media/utils/amstream.h> -#include <linux/amlogic/media/utils/vformat.h> -#include <linux/amlogic/media/frame_sync/ptsserv.h> -#include <linux/amlogic/media/canvas/canvas.h> -#include <linux/amlogic/media/vfm/vframe.h> -#include <linux/amlogic/media/vfm/vframe_provider.h> -#include <linux/amlogic/media/vfm/vframe_receiver.h> -#include <linux/dma-mapping.h> -#include <linux/dma-contiguous.h> -#include <linux/delay.h> - -#include <linux/amlogic/media/codec_mm/codec_mm.h> -#include <linux/amlogic/media/video_sink/video_keeper.h> -#include "../utils/firmware.h" -#include <linux/amlogic/tee.h> -#include "../../../common/chips/decoder_cpu_ver_info.h" - - - -#define MEM_NAME "codec_264_4k" - -/* #include <mach/am_regs.h> */ -#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ - -#include <linux/amlogic/media/vpu/vpu.h> -#endif - -#include <linux/amlogic/media/utils/vdec_reg.h> -#include "../../../stream_input/amports/amports_priv.h" -#include "../utils/vdec.h" -#include "../utils/amvdec.h" -#include "../utils/decoder_mmu_box.h" -#include "../utils/decoder_bmmu_box.h" -#include <linux/amlogic/media/codec_mm/codec_mm.h> -#include <linux/amlogic/media/codec_mm/configs.h> - - - -#if 0 /* MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6TVD */ -#define DOUBLE_WRITE -#endif - -#define DRIVER_NAME "amvdec_h264_4k2k" -#define MODULE_NAME "amvdec_h264_4k2k" - -#define PUT_INTERVAL (HZ/100) -#define ERROR_RESET_COUNT 500 -#define DECODE_BUFFER_NUM_MAX 32 -#define DISPLAY_BUFFER_NUM 6 -#define MAX_BMMU_BUFFER_NUM (DECODE_BUFFER_NUM_MAX + DISPLAY_BUFFER_NUM) -#define VF_BUFFER_IDX(n) (2 + n) -#define DECODER_WORK_SPACE_SIZE 0x800000 - -#if 1 /* MESON_CPU_TYPE == MESON_CPU_TYPE_MESONG9TV */ -#define H264_4K2K_SINGLE_CORE 1 -#else -#define H264_4K2K_SINGLE_CORE IS_MESON_M8M2_CPU -#endif - -#define SLICE_TYPE_I 2 - -static int vh264_4k2k_vf_states(struct vframe_states *states, void *); -static struct vframe_s *vh264_4k2k_vf_peek(void *); -static struct vframe_s *vh264_4k2k_vf_get(void *); -static void vh264_4k2k_vf_put(struct vframe_s *, void *); -static int vh264_4k2k_event_cb(int type, void *data, void *private_data); - -static void vh264_4k2k_prot_init(void); -static int vh264_4k2k_local_init(void); -static void vh264_4k2k_put_timer_func(unsigned long arg); - -static const char vh264_4k2k_dec_id[] = "vh264_4k2k-dev"; -static const char vh264_4k2k_dec_id2[] = "vh264_4k2k-vdec2-dev"; - -#define PROVIDER_NAME "decoder.h264_4k2k" - -static const struct vframe_operations_s vh264_4k2k_vf_provider = { - .peek = vh264_4k2k_vf_peek, - .get = vh264_4k2k_vf_get, - .put = vh264_4k2k_vf_put, - .event_cb = vh264_4k2k_event_cb, - .vf_states = vh264_4k2k_vf_states, -}; -static void *mm_blk_handle; -static struct vframe_provider_s vh264_4k2k_vf_prov; - -static u32 mb_width_old, mb_height_old; -static u32 frame_width, frame_height, frame_dur, frame_ar; -static u32 saved_resolution; -static struct timer_list recycle_timer; -static u32 stat; -static u32 error_watchdog_count; -static uint error_recovery_mode; -static u32 sync_outside; -static u32 vh264_4k2k_rotation; -static u32 first_i_received; -static struct vframe_s *p_last_vf; -static struct work_struct set_clk_work; - -#ifdef DEBUG_PTS -static unsigned long pts_missed, pts_hit; -#endif - -static struct dec_sysinfo vh264_4k2k_amstream_dec_info; -static dma_addr_t mc_dma_handle; -static void *mc_cpu_addr; - -#define AMVDEC_H264_4K2K_CANVAS_INDEX 0x80 -#define AMVDEC_H264_4K2K_CANVAS_MAX 0xc6 -static DEFINE_SPINLOCK(lock); -static int fatal_error; - -static atomic_t vh264_4k2k_active = ATOMIC_INIT(0); - -static DEFINE_MUTEX(vh264_4k2k_mutex); - -static void (*probe_callback)(void); -static void (*remove_callback)(void); -static struct device *cma_dev; - -/* bit[3:0] command : */ -/* 0 - command finished */ -/* (DATA0 - {level_idc_mmco, max_reference_frame_num, width, height} */ -/* 1 - alloc view_0 display_buffer and reference_data_area */ -/* 2 - alloc view_1 display_buffer and reference_data_area */ -#define MAILBOX_COMMAND AV_SCRATCH_0 -#define MAILBOX_DATA_0 AV_SCRATCH_1 -#define MAILBOX_DATA_1 AV_SCRATCH_2 -#define MAILBOX_DATA_2 AV_SCRATCH_3 -#define MAILBOX_DATA_3 AV_SCRATCH_4 -#define MAILBOX_DATA_4 AV_SCRATCH_5 -#define CANVAS_START AV_SCRATCH_6 -#define BUFFER_RECYCLE AV_SCRATCH_7 -#define PICTURE_COUNT AV_SCRATCH_9 -#define DECODE_STATUS AV_SCRATCH_A -#define SPS_STATUS AV_SCRATCH_B -#define PPS_STATUS AV_SCRATCH_C -#define MS_ID AV_SCRATCH_D -#define WORKSPACE_START AV_SCRATCH_E -#define DECODED_PIC_NUM AV_SCRATCH_F -#define DECODE_ERROR_CNT AV_SCRATCH_G -#define CURRENT_UCODE AV_SCRATCH_H -/* bit[15:9]-SPS, bit[8:0]-PPS */ -#define CURRENT_SPS_PPS AV_SCRATCH_I -#define DECODE_SKIP_PICTURE AV_SCRATCH_J -#define DECODE_MODE AV_SCRATCH_K -#define RESERVED_REG_L AV_SCRATCH_L -#define REF_START_VIEW_0 AV_SCRATCH_M -#define REF_START_VIEW_1 AV_SCRATCH_N - -#define VDEC2_MAILBOX_COMMAND VDEC2_AV_SCRATCH_0 -#define VDEC2_MAILBOX_DATA_0 VDEC2_AV_SCRATCH_1 -#define VDEC2_MAILBOX_DATA_1 VDEC2_AV_SCRATCH_2 -#define VDEC2_MAILBOX_DATA_2 VDEC2_AV_SCRATCH_3 -#define VDEC2_MAILBOX_DATA_3 VDEC2_AV_SCRATCH_4 -#define VDEC2_MAILBOX_DATA_4 VDEC2_AV_SCRATCH_5 -#define VDEC2_CANVAS_START VDEC2_AV_SCRATCH_6 -#define VDEC2_BUFFER_RECYCLE VDEC2_AV_SCRATCH_7 -#define VDEC2_PICTURE_COUNT VDEC2_AV_SCRATCH_9 -#define VDEC2_DECODE_STATUS VDEC2_AV_SCRATCH_A -#define VDEC2_SPS_STATUS VDEC2_AV_SCRATCH_B -#define VDEC2_PPS_STATUS VDEC2_AV_SCRATCH_C -#define VDEC2_MS_ID VDEC2_AV_SCRATCH_D -#define VDEC2_WORKSPACE_START VDEC2_AV_SCRATCH_E -#define VDEC2_DECODED_PIC_NUM VDEC2_AV_SCRATCH_F -#define VDEC2_DECODE_ERROR_CNT VDEC2_AV_SCRATCH_G -#define VDEC2_CURRENT_UCODE VDEC2_AV_SCRATCH_H -/* bit[15:9]-SPS, bit[8:0]-PPS */ -#define VDEC2_CURRENT_SPS_PPS VDEC2_AV_SCRATCH_I -#define VDEC2_DECODE_SKIP_PICTURE VDEC2_AV_SCRATCH_J -#define VDEC2_RESERVED_REG_K VDEC2_AV_SCRATCH_K -#define VDEC2_RESERVED_REG_L VDEC2_AV_SCRATCH_L -#define VDEC2_REF_START_VIEW_0 VDEC2_AV_SCRATCH_M -#define VDEC2_REF_START_VIEW_1 VDEC2_AV_SCRATCH_N - -/******************************************** - * DECODE_STATUS Define - ******************************************* - */ -#define DECODE_IDLE 0 -#define DECODE_START_HEADER 1 -#define DECODE_HEADER 2 -#define DECODE_START_MMCO 3 -#define DECODE_MMCO 4 -#define DECODE_START_SLICE 5 -#define DECODE_SLICE 6 -#define DECODE_WAIT_BUFFER 7 - -/******************************************** - * Dual Core Communication - ******************************************** - */ -#define FATAL_ERROR DOS_SCRATCH16 -#define PRE_MASTER_UPDATE_TIMES DOS_SCRATCH20 -/* bit[31] - REQUEST */ -/* bit[30:0] - MASTER_UPDATE_TIMES */ -#define SLAVE_WAIT_DPB_UPDATE DOS_SCRATCH21 -/* [15:8] - current_ref, [7:0] current_dpb (0x80 means no buffer found) */ -#define SLAVE_REF_DPB DOS_SCRATCH22 -#define SAVE_MVC_ENTENSION_0 DOS_SCRATCH23 -#define SAVE_I_POC DOS_SCRATCH24 -/* bit[31:30] - core_status 0-idle, 1-mmco, 2-decoding, 3-finished */ -/* bit[29:0] - core_pic_count */ -#define CORE_STATUS_M DOS_SCRATCH25 -#define CORE_STATUS_S DOS_SCRATCH26 -#define SAVE_ref_status_view_0 DOS_SCRATCH27 -#define SAVE_ref_status_view_1 DOS_SCRATCH28 -#define ALLOC_INFO_0 DOS_SCRATCH29 -#define ALLOC_INFO_1 DOS_SCRATCH30 - -/******************************************** - * Mailbox command - ********************************************/ -#define CMD_FINISHED 0 -#define CMD_ALLOC_VIEW 1 -#define CMD_FRAME_DISPLAY 3 -#define CMD_DEBUG 10 - -#define MC_TOTAL_SIZE (28*SZ_1K) -#define MC_SWAP_SIZE (4*SZ_1K) - -static unsigned long work_space_adr, ref_start_addr; -static unsigned long reserved_buffer; - - -#define video_domain_addr(adr) (adr&0x7fffffff) - - -struct buffer_spec_s { - unsigned int y_addr; - unsigned int uv_addr; -#ifdef DOUBLE_WRITE - unsigned int y_dw_addr; - unsigned int uv_dw_addr; -#endif - - int y_canvas_index; - int uv_canvas_index; -#ifdef DOUBLE_WRITE - int y_dw_canvas_index; - int uv_dw_canvas_index; -#endif - - struct page *alloc_pages; - unsigned long phy_addr; - int alloc_count; -}; - -static struct buffer_spec_s buffer_spec[MAX_BMMU_BUFFER_NUM]; - -#ifdef DOUBLE_WRITE -#define spec2canvas(x) \ - (((x)->uv_dw_canvas_index << 16) | \ - ((x)->uv_dw_canvas_index << 8) | \ - ((x)->y_dw_canvas_index << 0)) -#else -#define spec2canvas(x) \ - (((x)->uv_canvas_index << 16) | \ - ((x)->uv_canvas_index << 8) | \ - ((x)->y_canvas_index << 0)) -#endif - -#define VF_POOL_SIZE 32 - -static DECLARE_KFIFO(newframe_q, struct vframe_s *, VF_POOL_SIZE); -static DECLARE_KFIFO(display_q, struct vframe_s *, VF_POOL_SIZE); -static DECLARE_KFIFO(recycle_q, struct vframe_s *, VF_POOL_SIZE); - -static s32 vfbuf_use[DECODE_BUFFER_NUM_MAX]; -static struct vframe_s vfpool[VF_POOL_SIZE]; - -static struct work_struct alloc_work; -static struct vdec_info *gvs; - -static void set_frame_info(struct vframe_s *vf) -{ - unsigned int ar; - -#ifdef DOUBLE_WRITE - vf->width = frame_width / 2; - vf->height = frame_height / 2; -#else - vf->width = frame_width; - vf->height = frame_height; -#endif - vf->duration = frame_dur; - vf->duration_pulldown = 0; - vf->flag = 0; - - ar = min_t(u32, frame_ar, DISP_RATIO_ASPECT_RATIO_MAX); - vf->ratio_control = (ar << DISP_RATIO_ASPECT_RATIO_BIT); - vf->orientation = vh264_4k2k_rotation; - -} - -static int vh264_4k2k_vf_states(struct vframe_states *states, void *op_arg) -{ - unsigned long flags; - - spin_lock_irqsave(&lock, flags); - - states->vf_pool_size = VF_POOL_SIZE; - states->buf_free_num = kfifo_len(&newframe_q); - states->buf_avail_num = kfifo_len(&display_q); - states->buf_recycle_num = kfifo_len(&recycle_q); - - spin_unlock_irqrestore(&lock, flags); - return 0; -} - -static struct vframe_s *vh264_4k2k_vf_peek(void *op_arg) -{ - struct vframe_s *vf; - - if (kfifo_peek(&display_q, &vf)) - return vf; - - return NULL; -} - -static struct vframe_s *vh264_4k2k_vf_get(void *op_arg) -{ - struct vframe_s *vf; - - if (kfifo_get(&display_q, &vf)) - return vf; - - return NULL; -} - -static void vh264_4k2k_vf_put(struct vframe_s *vf, void *op_arg) -{ - kfifo_put(&recycle_q, (const struct vframe_s *)vf); -} - -static int vh264_4k2k_event_cb(int type, void *data, void *private_data) -{ - if (type & VFRAME_EVENT_RECEIVER_RESET) { - unsigned long flags; - - amvdec_stop(); - - if (!H264_4K2K_SINGLE_CORE) - amvdec2_stop(); -#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER - vf_light_unreg_provider(&vh264_4k2k_vf_prov); -#endif - spin_lock_irqsave(&lock, flags); - vh264_4k2k_local_init(); - vh264_4k2k_prot_init(); - spin_unlock_irqrestore(&lock, flags); -#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER - vf_reg_provider(&vh264_4k2k_vf_prov); -#endif - amvdec_start(); - - if (!H264_4K2K_SINGLE_CORE) - amvdec2_start(); - } - - return 0; -} - -static int init_canvas(int refbuf_size, long dpb_size, int dpb_number, - int mb_width, int mb_height, - struct buffer_spec_s *buffer_spec) -{ - unsigned long addr; - int i, j, ret = -1; - int mb_total; - int canvas_addr = ANC0_CANVAS_ADDR; - int vdec2_canvas_addr = VDEC2_ANC0_CANVAS_ADDR; - int index = AMVDEC_H264_4K2K_CANVAS_INDEX; - - mb_total = mb_width * mb_height; - mutex_lock(&vh264_4k2k_mutex); - - for (j = 0; j < (dpb_number + 1); j++) { - int page_count; - if (j == 0) { - ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle, 1, - refbuf_size, DRIVER_NAME, &ref_start_addr); - if (ret < 0) { - mutex_unlock(&vh264_4k2k_mutex); - return ret; - } - continue; - } - - WRITE_VREG(canvas_addr++, index | ((index + 1) << 8) | - ((index + 1) << 16)); - if (!H264_4K2K_SINGLE_CORE) { - WRITE_VREG(vdec2_canvas_addr++, - index | ((index + 1) << 8) | - ((index + 1) << 16)); - } - - i = j - 1; -#ifdef DOUBLE_WRITE - page_count = - PAGE_ALIGN((mb_total << 8) + (mb_total << 7) + - (mb_total << 6) + (mb_total << 5)) / PAGE_SIZE; -#else - page_count = - PAGE_ALIGN((mb_total << 8) + (mb_total << 7)) / PAGE_SIZE; -#endif - - ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle, - VF_BUFFER_IDX(i), page_count << PAGE_SHIFT, - DRIVER_NAME, &buffer_spec[i].phy_addr); - - if (ret < 0) { - buffer_spec[i].alloc_count = 0; - mutex_unlock(&vh264_4k2k_mutex); - return ret; - } - addr = buffer_spec[i].phy_addr; - buffer_spec[i].alloc_count = page_count; - buffer_spec[i].y_addr = addr; - buffer_spec[i].y_canvas_index = index; - canvas_config(index, - addr, - mb_width << 4, - mb_height << 4, - CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); - - addr += mb_total << 8; - index++; - - buffer_spec[i].uv_addr = addr; - buffer_spec[i].uv_canvas_index = index; - canvas_config(index, - addr, - mb_width << 4, - mb_height << 3, - CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); - - addr += mb_total << 7; - index++; - -#ifdef DOUBLE_WRITE - buffer_spec[i].y_dw_addr = addr; - buffer_spec[i].y_dw_canvas_index = index; - canvas_config(index, - addr, - mb_width << 3, - mb_height << 3, - CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); - - addr += mb_total << 6; - index++; - - buffer_spec[i].uv_dw_addr = addr; - buffer_spec[i].uv_dw_canvas_index = index; - canvas_config(index, - addr, - mb_width << 3, - mb_height << 2, - CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); - - index++; -#endif - } - - mutex_unlock(&vh264_4k2k_mutex); - - pr_info - ("H264 4k2k decoder canvas allocation successful, "); - - return 0; -} - -static int get_max_dec_frame_buf_size(int level_idc, - int max_reference_frame_num, int mb_width, - int mb_height) -{ - int pic_size = mb_width * mb_height * 384; - - int size = 0; - - switch (level_idc) { - case 9: - size = 152064; - break; - case 10: - size = 152064; - break; - case 11: - size = 345600; - break; - case 12: - size = 912384; - break; - case 13: - size = 912384; - break; - case 20: - size = 912384; - break; - case 21: - size = 1824768; - break; - case 22: - size = 3110400; - break; - case 30: - size = 3110400; - break; - case 31: - size = 6912000; - break; - case 32: - size = 7864320; - break; - case 40: - size = 12582912; - break; - case 41: - size = 12582912; - break; - case 42: - size = 13369344; - break; - case 50: - size = 42393600; - break; - case 51: - case 52: - default: - size = 70778880; - break; - } - - size /= pic_size; - size = size + 1; /* need one more buffer */ - - if (max_reference_frame_num > size) - size = max_reference_frame_num; - - if (size > DECODE_BUFFER_NUM_MAX) - size = DECODE_BUFFER_NUM_MAX; - - return size; -} - -static void do_alloc_work(struct work_struct *work) -{ - int level_idc, max_reference_frame_num, mb_width, mb_height, - frame_mbs_only_flag; - int dpb_size, ref_size, refbuf_size; - int max_dec_frame_buffering, - total_dec_frame_buffering; - unsigned int chroma444; - unsigned int crop_infor, crop_bottom, crop_right; - int ret = READ_VREG(MAILBOX_COMMAND); - - - ret = READ_VREG(MAILBOX_DATA_0); - /* MAILBOX_DATA_1 : - * bit15 : frame_mbs_only_flag - * bit 0-7 : chroma_format_idc - * MAILBOX_DATA_2: - * bit31-16: (left << 8 | right ) << 1 - * bit15-0 : (top << 8 | bottom ) << (2 - frame_mbs_only_flag) - */ - frame_mbs_only_flag = READ_VREG(MAILBOX_DATA_1); - crop_infor = READ_VREG(MAILBOX_DATA_2); - level_idc = (ret >> 24) & 0xff; - max_reference_frame_num = (ret >> 16) & 0xff; - mb_width = (ret >> 8) & 0xff; - if (mb_width == 0) - mb_width = 256; - mb_height = (ret >> 0) & 0xff; - max_dec_frame_buffering = - get_max_dec_frame_buf_size(level_idc, max_reference_frame_num, - mb_width, mb_height); - total_dec_frame_buffering = - max_dec_frame_buffering + DISPLAY_BUFFER_NUM; - - chroma444 = ((frame_mbs_only_flag&0xffff) == 3) ? 1 : 0; - frame_mbs_only_flag = (frame_mbs_only_flag >> 16) & 0x01; - crop_bottom = (crop_infor & 0xff) >> (2 - frame_mbs_only_flag); - crop_right = ((crop_infor >> 16) & 0xff) >> 1; - pr_info("crop_right = 0x%x crop_bottom = 0x%x chroma_format_idc = 0x%x\n", - crop_right, crop_bottom, chroma444); - - if ((frame_width == 0) || (frame_height == 0) || crop_infor || - mb_width != mb_width_old || - mb_height != mb_height_old) { - frame_width = mb_width << 4; - frame_height = mb_height << 4; - mb_width_old = mb_width; - mb_height_old = mb_height; - if (frame_mbs_only_flag) { - frame_height -= (2 >> chroma444) * - min(crop_bottom, - (unsigned int)((8 << chroma444) - 1)); - frame_width -= (2 >> chroma444) * - min(crop_right, - (unsigned int)((8 << chroma444) - 1)); - } else { - frame_height -= (4 >> chroma444) * - min(crop_bottom, - (unsigned int)((8 << chroma444) - 1)); - frame_width -= (4 >> chroma444) * - min(crop_right, - (unsigned int)((8 << chroma444) - 1)); - } - pr_info("frame_mbs_only_flag %d, crop_bottom %d frame_height %d, mb_height %d crop_right %d, frame_width %d, mb_width %d\n", - frame_mbs_only_flag, crop_bottom, frame_height, - mb_height, crop_right, frame_width, mb_height); - } - - mb_width = (mb_width + 3) & 0xfffffffc; - mb_height = (mb_height + 3) & 0xfffffffc; - - dpb_size = mb_width * mb_height * 384; - ref_size = mb_width * mb_height * 96; - refbuf_size = ref_size * (max_reference_frame_num + 1) * 2; - - - pr_info("mb_width=%d, mb_height=%d\n", - mb_width, mb_height); - - ret = init_canvas(refbuf_size, dpb_size, - total_dec_frame_buffering, mb_width, mb_height, - buffer_spec); - - if (ret == -1) { - pr_info(" Un-expected memory alloc problem\n"); - return; - } - - if (frame_width == 0) - frame_width = mb_width << 4; - if (frame_height == 0) - frame_height = mb_height << 4; - - WRITE_VREG(REF_START_VIEW_0, video_domain_addr(ref_start_addr)); - if (!H264_4K2K_SINGLE_CORE) { - WRITE_VREG(VDEC2_REF_START_VIEW_0, - video_domain_addr(ref_start_addr)); - } - - WRITE_VREG(MAILBOX_DATA_0, - (max_dec_frame_buffering << 8) | - (total_dec_frame_buffering << 0)); - WRITE_VREG(MAILBOX_DATA_1, ref_size); - WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED); - - /* ///////////// FAKE FIRST PIC */ - -} - -static irqreturn_t vh264_4k2k_isr(int irq, void *dev_id) -{ - int drop_status, display_buff_id, display_POC, slice_type, error; - unsigned int stream_offset; - struct vframe_s *vf = NULL; - int ret = READ_VREG(MAILBOX_COMMAND); - u32 frame_size; - - switch (ret & 0xff) { - case CMD_ALLOC_VIEW: - schedule_work(&alloc_work); - break; - - case CMD_FRAME_DISPLAY: - ret >>= 8; - display_buff_id = (ret >> 0) & 0x3f; - drop_status = (ret >> 8) & 0x1; - slice_type = (ret >> 9) & 0x7; - error = (ret >> 12) & 0x1; - display_POC = READ_VREG(MAILBOX_DATA_0); - stream_offset = READ_VREG(MAILBOX_DATA_1); - - smp_rmb();/* rmb smp */ - - WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED); - - if (kfifo_get(&newframe_q, &vf) == 0) { - pr_info("fatal error, no available buffer slot."); - return IRQ_HANDLED; - } - - if (vf) { - vfbuf_use[display_buff_id]++; - - vf->pts = 0; - vf->pts_us64 = 0; - - if ((!sync_outside) - || (sync_outside && - (slice_type == SLICE_TYPE_I))) { - ret = pts_lookup_offset_us64(PTS_TYPE_VIDEO, - stream_offset, - &vf->pts, - &frame_size, - 0, - &vf->pts_us64); - if (ret != 0) - pr_debug(" vpts lookup failed\n"); - } -#ifdef H264_4K2K_SINGLE_CORE - if (READ_VREG(DECODE_MODE) & 1) { - /* for I only mode, ignore the PTS information - * and only uses 10fps for each - * I frame decoded - */ - if (p_last_vf) { - vf->pts = 0; - vf->pts_us64 = 0; - } - frame_dur = 96000 / 10; - } -#endif - vf->signal_type = 0; - vf->index = display_buff_id; - vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD; - vf->type |= VIDTYPE_VIU_NV21; - vf->canvas0Addr = vf->canvas1Addr = - spec2canvas(&buffer_spec[display_buff_id]); - set_frame_info(vf); - - if (error) - gvs->drop_frame_count++; - - gvs->frame_dur = frame_dur; - vdec_count_info(gvs, error, stream_offset); - - if (((error_recovery_mode & 2) && error) - || (!first_i_received - && (slice_type != SLICE_TYPE_I))) { - kfifo_put(&recycle_q, - (const struct vframe_s *)vf); - } else { - p_last_vf = vf; - first_i_received = 1; - vf->mem_handle = - decoder_bmmu_box_get_mem_handle( - mm_blk_handle, - VF_BUFFER_IDX(display_buff_id)); - kfifo_put(&display_q, - (const struct vframe_s *)vf); - ATRACE_COUNTER(MODULE_NAME, vf->pts); - - vf_notify_receiver(PROVIDER_NAME, - VFRAME_EVENT_PROVIDER_VFRAME_READY, - NULL); - } - } - break; - - case CMD_DEBUG: - pr_info("M: core_status 0x%08x 0x%08x; ", - READ_VREG(CORE_STATUS_M), READ_VREG(CORE_STATUS_S)); - switch (READ_VREG(MAILBOX_DATA_0)) { - case 1: - pr_info("H264_BUFFER_INFO_INDEX = 0x%x\n", - READ_VREG(MAILBOX_DATA_1)); - WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED); - break; - case 2: - pr_info("H264_BUFFER_INFO_DATA = 0x%x\n", - READ_VREG(MAILBOX_DATA_1)); - WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED); - break; - case 3: - pr_info("REC_CANVAS_ADDR = 0x%x\n", - READ_VREG(MAILBOX_DATA_1)); - WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED); - break; - case 4: - pr_info("after DPB_MMCO\n"); - WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED); - break; - case 5: - pr_info("MBY = 0x%x, S_MBXY = 0x%x\n", - READ_VREG(MAILBOX_DATA_1), - READ_VREG(0x2c07)); - WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED); - break; - case 6: - pr_info("after FIFO_OUT_FRAME\n"); - WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED); - break; - case 7: - pr_info("after RELEASE_EXCEED_REF_BUFF\n"); - WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED); - break; - case 0x5a: - pr_info("\n"); - break; - default: - pr_info("\n"); - break; - } - break; - - default: - break; - } - - return IRQ_HANDLED; -} - -#if 1 /*MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8*/ -static irqreturn_t vh264_4k2k_vdec2_isr(int irq, void *dev_id) -{ - int ret = READ_VREG(VDEC2_MAILBOX_COMMAND); - - switch (ret & 0xff) { - case CMD_DEBUG: - pr_info("S: core_status 0x%08x 0x%08x; ", - READ_VREG(CORE_STATUS_M), READ_VREG(CORE_STATUS_S)); - switch (READ_VREG(VDEC2_MAILBOX_DATA_0)) { - case 1: - pr_info("H264_BUFFER_INFO_INDEX = 0x%x\n", - READ_VREG(VDEC2_MAILBOX_DATA_1)); - WRITE_VREG(VDEC2_MAILBOX_COMMAND, CMD_FINISHED); - break; - case 2: - pr_info("H264_BUFFER_INFO_DATA = 0x%x\n", - READ_VREG(VDEC2_MAILBOX_DATA_1)); - WRITE_VREG(VDEC2_MAILBOX_COMMAND, CMD_FINISHED); - break; - case 3: - pr_info("REC_CANVAS_ADDR = 0x%x\n", - READ_VREG(VDEC2_MAILBOX_DATA_1)); - WRITE_VREG(VDEC2_MAILBOX_COMMAND, CMD_FINISHED); - break; - case 4: - pr_info("after DPB_MMCO\n"); - WRITE_VREG(VDEC2_MAILBOX_COMMAND, CMD_FINISHED); - break; - case 5: - pr_info("MBY = 0x%x, M/S_MBXY = 0x%x-0x%x\n", - READ_VREG(VDEC2_MAILBOX_DATA_1), - READ_VREG(0xc07), READ_VREG(0x2c07)); - WRITE_VREG(VDEC2_MAILBOX_COMMAND, CMD_FINISHED); - break; - case 6: - pr_info("after FIFO_OUT_FRAME\n"); - WRITE_VREG(VDEC2_MAILBOX_COMMAND, CMD_FINISHED); - break; - case 7: - pr_info("after RELEASE_EXCEED_REF_BUFF\n"); - WRITE_VREG(VDEC2_MAILBOX_COMMAND, CMD_FINISHED); - break; - case 0x5a: - pr_info("\n"); - break; - default: - pr_info("\n"); - break; - } - break; - - default: - break; - } - - return IRQ_HANDLED; -} -#endif - -static void vh264_4k2k_set_clk(struct work_struct *work) -{ - if (first_i_received &&/*do switch after first i frame ready.*/ - frame_dur > 0 && saved_resolution != - frame_width * frame_height * (96000 / frame_dur)) { - int fps = 96000 / frame_dur; - - pr_info("H264 4k2k resolution changed!!\n"); - if (vdec_source_changed(VFORMAT_H264_4K2K, - frame_width, frame_height, fps) > 0)/*changed clk ok*/ - saved_resolution = frame_width * frame_height * fps; - } -} - -static void vh264_4k2k_put_timer_func(unsigned long arg) -{ - struct timer_list *timer = (struct timer_list *)arg; - enum receviver_start_e state = RECEIVER_INACTIVE; - - if (vf_get_receiver(PROVIDER_NAME)) { - state = vf_notify_receiver(PROVIDER_NAME, - VFRAME_EVENT_PROVIDER_QUREY_STATE, NULL); - if ((state == RECEIVER_STATE_NULL) - || (state == RECEIVER_STATE_NONE)) - state = RECEIVER_INACTIVE; - } else - state = RECEIVER_INACTIVE; - - /* error watchdog */ - if (((READ_VREG(VLD_MEM_VIFIFO_CONTROL) & 0x100) == 0) &&/* dec has in*/ - (state == RECEIVER_INACTIVE) && /* rec has no buf to recycle */ - (kfifo_is_empty(&display_q)) && /* no buf in display queue */ - (kfifo_is_empty(&recycle_q)) && /* no buf to recycle */ - (READ_VREG(MS_ID) & 0x100) -#ifdef CONFIG_H264_2K4K_SINGLE_CORE - && (READ_VREG(VDEC2_MS_ID) & 0x100) - -/* with both decoder - * have started decoding - */ -#endif - && first_i_received) { - if (++error_watchdog_count == ERROR_RESET_COUNT) { - /* and it lasts for a while */ - pr_info("H264 4k2k decoder fatal error watchdog.\n"); - fatal_error = DECODER_FATAL_ERROR_UNKNOWN; - } - } else - error_watchdog_count = 0; - - if (READ_VREG(FATAL_ERROR) != 0) { - pr_info("H264 4k2k decoder ucode fatal error.\n"); - fatal_error = DECODER_FATAL_ERROR_UNKNOWN; - WRITE_VREG(FATAL_ERROR, 0); - } - - while (!kfifo_is_empty(&recycle_q) && - (READ_VREG(BUFFER_RECYCLE) == 0)) { - struct vframe_s *vf; - - if (kfifo_get(&recycle_q, &vf)) { - if ((vf->index < DECODE_BUFFER_NUM_MAX) - && (--vfbuf_use[vf->index] == 0)) { - WRITE_VREG(BUFFER_RECYCLE, vf->index + 1); - vf->index = DECODE_BUFFER_NUM_MAX; - } - - kfifo_put(&newframe_q, (const struct vframe_s *)vf); - } - } - - schedule_work(&set_clk_work); - - timer->expires = jiffies + PUT_INTERVAL; - - add_timer(timer); -} - -int vh264_4k2k_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus) -{ - vstatus->frame_width = frame_width; - vstatus->frame_height = frame_height; - if (frame_dur != 0) - vstatus->frame_rate = 96000 / frame_dur; - else - vstatus->frame_rate = -1; - vstatus->error_count = 0; - vstatus->status = stat | fatal_error; - vstatus->frame_dur = frame_dur; - vstatus->frame_data = gvs->frame_data; - vstatus->total_data = gvs->total_data; - vstatus->frame_count = gvs->frame_count; - vstatus->error_frame_count = gvs->error_frame_count; - vstatus->drop_frame_count = gvs->drop_frame_count; - vstatus->total_data = gvs->total_data; - vstatus->samp_cnt = gvs->samp_cnt; - vstatus->offset = gvs->offset; - snprintf(vstatus->vdec_name, sizeof(vstatus->vdec_name), - "%s", DRIVER_NAME); - - return 0; -} - -static int vh264_4k2k_vdec_info_init(void) -{ - gvs = kzalloc(sizeof(struct vdec_info), GFP_KERNEL); - if (NULL == gvs) { - pr_info("the struct of vdec status malloc failed.\n"); - return -ENOMEM; - } - return 0; -} - -int vh264_4k2k_set_trickmode(struct vdec_s *vdec, unsigned long trickmode) -{ - if (trickmode == TRICKMODE_I) { - WRITE_VREG(DECODE_MODE, 1); - trickmode_i = 1; - } else if (trickmode == TRICKMODE_NONE) { - WRITE_VREG(DECODE_MODE, 0); - trickmode_i = 0; - } - - return 0; -} - -static void H264_DECODE_INIT(void) -{ - int i; - - WRITE_VREG(GCLK_EN, 0x3ff); - - WRITE_VREG(DOS_SW_RESET0, (1 << 7) | (1 << 6) | (1 << 4)); - WRITE_VREG(DOS_SW_RESET0, 0); - - READ_VREG(DOS_SW_RESET0); - READ_VREG(DOS_SW_RESET0); - READ_VREG(DOS_SW_RESET0); - - WRITE_VREG(DOS_SW_RESET0, (1 << 7) | (1 << 6) | (1 << 4)); - WRITE_VREG(DOS_SW_RESET0, 0); - - WRITE_VREG(DOS_SW_RESET0, (1 << 9) | (1 << 8)); - WRITE_VREG(DOS_SW_RESET0, 0); - - READ_VREG(DOS_SW_RESET0); - READ_VREG(DOS_SW_RESET0); - READ_VREG(DOS_SW_RESET0); - - /* fill_weight_pred */ - WRITE_VREG(MC_MPORT_CTRL, 0x0300); - for (i = 0; i < 192; i++) - WRITE_VREG(MC_MPORT_DAT, 0x100); - WRITE_VREG(MC_MPORT_CTRL, 0); - - WRITE_VREG(MB_WIDTH, 0xff); /* invalid mb_width */ - - /* set slice start to 0x000000 or 0x000001 for check more_rbsp_data */ - WRITE_VREG(SLICE_START_BYTE_01, 0x00000000); - WRITE_VREG(SLICE_START_BYTE_23, 0x01010000); - /* set to mpeg2 to enable mismatch logic */ - WRITE_VREG(MPEG1_2_REG, 1); - WRITE_VREG(VLD_ERROR_MASK, - 0x1011); - - /* Config MCPU Amrisc interrupt */ - WRITE_VREG(ASSIST_AMR1_INT0, 0x1); /* viu_vsync_int */ - WRITE_VREG(ASSIST_AMR1_INT1, 0x5); /* mbox_isr */ - WRITE_VREG(ASSIST_AMR1_INT2, 0x8); /* vld_isr */ - /* WRITE_VREG(ASSIST_AMR1_INT3, 0x15); // vififo_empty */ - WRITE_VREG(ASSIST_AMR1_INT4, 0xd); /* rv_ai_mb_finished_int */ - WRITE_VREG(ASSIST_AMR1_INT7, 0x14); /* dcac_dma_done */ - WRITE_VREG(ASSIST_AMR1_INT8, 0x15); /* vififo_empty */ - - /* Config MCPU Amrisc interrupt */ - WRITE_VREG(ASSIST_AMR1_INT5, 0x9); /* MCPU interrupt */ - WRITE_VREG(ASSIST_AMR1_INT6, 0x17); /* CCPU interrupt */ - - WRITE_VREG(CPC_P, 0xc00); /* CCPU Code will start from 0xc00 */ - WRITE_VREG(CINT_VEC_BASE, (0xc20 >> 5)); - WRITE_VREG(POWER_CTL_VLD, (1 << 10) | /* disable cabac_step_2 */ - (1 << 9) | /* viff_drop_flag_en */ - (1 << 6)); /* h264_000003_en */ - WRITE_VREG(M4_CONTROL_REG, (1 << 13)); /* H264_DECODE_INFO - h264_en */ - - WRITE_VREG(CANVAS_START, AMVDEC_H264_4K2K_CANVAS_INDEX); - /* Start Address of Workspace (UCODE, temp_data...) */ - WRITE_VREG(WORKSPACE_START, - video_domain_addr(work_space_adr)); - /* Clear all sequence parameter set available */ - WRITE_VREG(SPS_STATUS, 0); - /* Clear all picture parameter set available */ - WRITE_VREG(PPS_STATUS, 0); - /* Set current microcode to NULL */ - WRITE_VREG(CURRENT_UCODE, 0xff); - /* Set current SPS/PPS to NULL */ - WRITE_VREG(CURRENT_SPS_PPS, 0xffff); - /* Set decode status to DECODE_START_HEADER */ - WRITE_VREG(DECODE_STATUS, 1); -} - -static void H264_DECODE2_INIT(void) -{ - int i; - - WRITE_VREG(VDEC2_GCLK_EN, 0x3ff); - - WRITE_VREG(DOS_SW_RESET2, (1 << 7) | (1 << 6) | (1 << 4)); - WRITE_VREG(DOS_SW_RESET2, 0); - - READ_VREG(DOS_SW_RESET2); - READ_VREG(DOS_SW_RESET2); - READ_VREG(DOS_SW_RESET2); - - WRITE_VREG(DOS_SW_RESET2, (1 << 7) | (1 << 6) | (1 << 4)); - WRITE_VREG(DOS_SW_RESET2, 0); - - WRITE_VREG(DOS_SW_RESET2, (1 << 9) | (1 << 8)); - WRITE_VREG(DOS_SW_RESET2, 0); - - READ_VREG(DOS_SW_RESET2); - READ_VREG(DOS_SW_RESET2); - READ_VREG(DOS_SW_RESET2); - - /* fill_weight_pred */ - WRITE_VREG(VDEC2_MC_MPORT_CTRL, 0x0300); - for (i = 0; i < 192; i++) - WRITE_VREG(VDEC2_MC_MPORT_DAT, 0x100); - WRITE_VREG(VDEC2_MC_MPORT_CTRL, 0); - - WRITE_VREG(VDEC2_MB_WIDTH, 0xff); /* invalid mb_width */ - - /* set slice start to 0x000000 or 0x000001 for check more_rbsp_data */ - WRITE_VREG(VDEC2_SLICE_START_BYTE_01, 0x00000000); - WRITE_VREG(VDEC2_SLICE_START_BYTE_23, 0x01010000); - /* set to mpeg2 to enable mismatch logic */ - WRITE_VREG(VDEC2_MPEG1_2_REG, 1); - /* disable COEF_GT_64 , error_m4_table and voff_rw_err */ - WRITE_VREG(VDEC2_VLD_ERROR_MASK, - 0x1011); - - /* Config MCPU Amrisc interrupt */ - WRITE_VREG(VDEC2_ASSIST_AMR1_INT0, 0x1);/* viu_vsync_int */ - WRITE_VREG(VDEC2_ASSIST_AMR1_INT1, 0x5);/* mbox_isr */ - WRITE_VREG(VDEC2_ASSIST_AMR1_INT2, 0x8);/* vld_isr */ - /* WRITE_VREG(VDEC2_ASSIST_AMR1_INT3, 0x15); // vififo_empty */ - WRITE_VREG(VDEC2_ASSIST_AMR1_INT4, 0xd);/* rv_ai_mb_finished_int */ - WRITE_VREG(VDEC2_ASSIST_AMR1_INT7, 0x14);/* dcac_dma_done */ - WRITE_VREG(VDEC2_ASSIST_AMR1_INT8, 0x15);/* vififo_empty */ - - /* Config MCPU Amrisc interrupt */ - WRITE_VREG(VDEC2_ASSIST_AMR1_INT5, 0x9);/* MCPU interrupt */ - WRITE_VREG(VDEC2_ASSIST_AMR1_INT6, 0x17);/* CCPU interrupt */ - - WRITE_VREG(VDEC2_CPC_P, 0xc00); /* CCPU Code will start from 0xc00 */ - WRITE_VREG(VDEC2_CINT_VEC_BASE, (0xc20 >> 5)); - WRITE_VREG(VDEC2_POWER_CTL_VLD, (1 << 10) |/* disable cabac_step_2 */ - (1 << 9) | /* viff_drop_flag_en */ - (1 << 6)); /* h264_000003_en */ - /* H264_DECODE_INFO - h264_en */ - WRITE_VREG(VDEC2_M4_CONTROL_REG, (1 << 13)); - - WRITE_VREG(VDEC2_CANVAS_START, AMVDEC_H264_4K2K_CANVAS_INDEX); - /* Start Address of Workspace (UCODE, temp_data...) */ - WRITE_VREG(VDEC2_WORKSPACE_START, - video_domain_addr(work_space_adr)); - /* Clear all sequence parameter set available */ - WRITE_VREG(VDEC2_SPS_STATUS, 0); - /* Clear all picture parameter set available */ - WRITE_VREG(VDEC2_PPS_STATUS, 0); - /* Set current microcode to NULL */ - WRITE_VREG(VDEC2_CURRENT_UCODE, 0xff); - /* Set current SPS/PPS to NULL */ - WRITE_VREG(VDEC2_CURRENT_SPS_PPS, 0xffff); - /* Set decode status to DECODE_START_HEADER */ - WRITE_VREG(VDEC2_DECODE_STATUS, 1); -} - -static void vh264_4k2k_prot_init(void) -{ - /* clear mailbox interrupt */ -#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ - if (!H264_4K2K_SINGLE_CORE) - WRITE_VREG(VDEC2_ASSIST_MBOX0_CLR_REG, 1); -#endif - WRITE_VREG(VDEC_ASSIST_MBOX1_CLR_REG, 1); - - /* enable mailbox interrupt */ -#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ - if (!H264_4K2K_SINGLE_CORE) - WRITE_VREG(VDEC2_ASSIST_MBOX0_MASK, 1); -#endif - WRITE_VREG(VDEC_ASSIST_MBOX1_MASK, 1); - - /* disable PSCALE for hardware sharing */ - WRITE_VREG(PSCALE_CTRL, 0); - - H264_DECODE_INIT(); - if (!H264_4K2K_SINGLE_CORE) - H264_DECODE2_INIT(); - - WRITE_VREG(DOS_SW_RESET0, (1 << 11)); - WRITE_VREG(DOS_SW_RESET0, 0); - - READ_VREG(DOS_SW_RESET0); - READ_VREG(DOS_SW_RESET0); - READ_VREG(DOS_SW_RESET0); - - if (!H264_4K2K_SINGLE_CORE) { - WRITE_VREG(DOS_SW_RESET2, (1 << 11)); - WRITE_VREG(DOS_SW_RESET2, 0); - - READ_VREG(DOS_SW_RESET2); - READ_VREG(DOS_SW_RESET2); - READ_VREG(DOS_SW_RESET2); - } - - WRITE_VREG(MAILBOX_COMMAND, 0); - WRITE_VREG(BUFFER_RECYCLE, 0); - - if (!H264_4K2K_SINGLE_CORE) { - WRITE_VREG(VDEC2_MAILBOX_COMMAND, 0); - WRITE_VREG(VDEC2_BUFFER_RECYCLE, 0); - } - - CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17); - if (!H264_4K2K_SINGLE_CORE) - CLEAR_VREG_MASK(VDEC2_MDEC_PIC_DC_CTRL, 1 << 17); - - /* set VDEC Master/ID 0 */ - WRITE_VREG(MS_ID, (1 << 7) | (0 << 0)); - if (!H264_4K2K_SINGLE_CORE) { - /* set VDEC2 Slave/ID 0 */ - WRITE_VREG(VDEC2_MS_ID, (0 << 7) | (1 << 0)); - } - WRITE_VREG(DECODE_SKIP_PICTURE, 0); - if (!H264_4K2K_SINGLE_CORE) - WRITE_VREG(VDEC2_DECODE_SKIP_PICTURE, 0); - - WRITE_VREG(PRE_MASTER_UPDATE_TIMES, 0); - WRITE_VREG(SLAVE_WAIT_DPB_UPDATE, 0); - WRITE_VREG(SLAVE_REF_DPB, 0); - WRITE_VREG(SAVE_MVC_ENTENSION_0, 0); - WRITE_VREG(SAVE_I_POC, 0); - WRITE_VREG(CORE_STATUS_M, 0); - WRITE_VREG(CORE_STATUS_S, 0); - WRITE_VREG(SAVE_ref_status_view_0, 0); - WRITE_VREG(SAVE_ref_status_view_1, 0); - WRITE_VREG(ALLOC_INFO_0, 0); - WRITE_VREG(ALLOC_INFO_1, 0); - WRITE_VREG(FATAL_ERROR, 0); - - SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17); - if (!H264_4K2K_SINGLE_CORE) - SET_VREG_MASK(VDEC2_MDEC_PIC_DC_CTRL, 1 << 17); - - WRITE_VREG(MDEC_PIC_DC_THRESH, 0x404038aa); - if (!H264_4K2K_SINGLE_CORE) { - WRITE_VREG(VDEC2_MDEC_PIC_DC_THRESH, 0x404038aa); - } -#ifdef DOUBLE_WRITE - WRITE_VREG(MDEC_DOUBLEW_CFG0, (0 << 31) | /* half y address */ - (1 << 30) | /* 0:No Merge 1:Automatic Merge */ - (0 << 28) | - -/* Field Picture, 0x:no skip - * 10:top only - * 11:bottom only - */ - (0 << 27) | /* Source from, 1:MCW 0:DBLK */ - (0 << 24) | /* Endian Control for Chroma */ - (0 << 18) | /* DMA ID */ - (0 << 12) | /* DMA Burst Number */ - (0 << 11) | /* DMA Urgent */ - (0 << 10) | /* 1:Round 0:Truncation */ - (1 << 9) | - -/* Size by vertical, 0:original size - * 1: 1/2 shrunken size - */ - (1 << 8) | - -/* Size by horizontal, 0:original size - * 1: 1/2 shrunken size - */ - (0 << 6) | - -/* Pixel sel by vertical, 0x:1/2 - * 10:up - * 11:down - */ - (0 << 4) | - -/* Pixel sel by horizontal, 0x:1/2 - * 10:left - * 11:right - */ - (0 << 1) | /* Endian Control for Luma */ - (1 << 0)); /* Double Write Enable */ - if (!H264_4K2K_SINGLE_CORE) { - WRITE_VREG(VDEC2_MDEC_DOUBLEW_CFG0, - (0 << 31) | /* half y address */ - (1 << 30) | - -/* 0:No Merge - * 1:Automatic Merge - */ - (0 << 28) | - -/* Field Picture, 0x:no skip - * 10:top only - * 11:bottom only - */ - (0 << 27) | /* Source from, 1:MCW 0:DBLK */ - (0 << 24) | /* Endian Control for Chroma */ - (0 << 18) | /* DMA ID */ - (0 << 12) | /* DMA Burst Number */ - (0 << 11) | /* DMA Urgent */ - (0 << 10) | /* 1:Round 0:Truncation */ - (1 << 9) | - -/* Size by vertical, - * 0:original size - * 1: 1/2 shrunken size - */ - (1 << 8) | - -/* Size by horizontal, - * 0:original size - * 1: 1/2 shrunken size - */ - (0 << 6) | - -/* Pixel sel by vertical, - * 0x:1/2 - * 10:up - * 11:down - */ - (0 << 4) | - -/* Pixel sel by horizontal, - * 0x:1/2 - * 10:left - * 11:right - */ - (0 << 1) | /* Endian Control for Luma */ - (1 << 0)); /* Double Write Enable */ - } -#endif -} - -static int vh264_4k2k_local_init(void) -{ - int i, size, ret; - -#ifdef DEBUG_PTS - pts_missed = 0; - pts_hit = 0; -#endif - mb_width_old = 0; - mb_height_old = 0; - saved_resolution = 0; - vh264_4k2k_rotation = - (((unsigned long) vh264_4k2k_amstream_dec_info.param) >> 16) - & 0xffff; - frame_width = vh264_4k2k_amstream_dec_info.width; - frame_height = vh264_4k2k_amstream_dec_info.height; - frame_dur = - (vh264_4k2k_amstream_dec_info.rate == - 0) ? 3600 : vh264_4k2k_amstream_dec_info.rate; - if (frame_width && frame_height) - frame_ar = frame_height * 0x100 / frame_width; - sync_outside = ((unsigned long) vh264_4k2k_amstream_dec_info.param - & 0x02) >> 1; - error_watchdog_count = 0; - - pr_info("H264_4K2K: decinfo: %dx%d rate=%d\n", - frame_width, frame_height, - frame_dur); - - if (frame_dur == 0) - frame_dur = 96000 / 24; - - INIT_KFIFO(display_q); - INIT_KFIFO(recycle_q); - INIT_KFIFO(newframe_q); - - for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) - vfbuf_use[i] = 0; - - for (i = 0; i < VF_POOL_SIZE; i++) { - const struct vframe_s *vf = &vfpool[i]; - - vfpool[i].index = DECODE_BUFFER_NUM_MAX; - kfifo_put(&newframe_q, vf); - } - - reserved_buffer = 0; - p_last_vf = NULL; - first_i_received = 0; - INIT_WORK(&alloc_work, do_alloc_work); - - if (mm_blk_handle) { - decoder_bmmu_box_free(mm_blk_handle); - mm_blk_handle = NULL; - } - - mm_blk_handle = decoder_bmmu_box_alloc_box( - DRIVER_NAME, - 0, - MAX_BMMU_BUFFER_NUM, - 4 + PAGE_SHIFT, - CODEC_MM_FLAGS_CMA_CLEAR | - CODEC_MM_FLAGS_FOR_VDECODER); - - size = DECODER_WORK_SPACE_SIZE; - ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle, 0, - size, DRIVER_NAME, &work_space_adr); - return ret; -} - -static s32 vh264_4k2k_init(void) -{ - int ret = -1, size = -1; - char *buf = vmalloc(0x1000 * 16); - - if (buf == NULL) - return -ENOMEM; - - pr_info("\nvh264_4k2k_init\n"); - - init_timer(&recycle_timer); - - stat |= STAT_TIMER_INIT; - - ret = vh264_4k2k_local_init(); - if (ret < 0) { - vfree(buf); - return ret; - } - amvdec_enable(); - - /* -- ucode loading (amrisc and swap code) */ - mc_cpu_addr = dma_alloc_coherent(amports_get_dma_device(), - MC_TOTAL_SIZE, &mc_dma_handle, GFP_KERNEL); - if (!mc_cpu_addr) { - amvdec_disable(); - vfree(buf); - pr_err("vh264_4k2k init: Can not allocate mc memory.\n"); - return -ENOMEM; - } - - WRITE_VREG(AV_SCRATCH_L, mc_dma_handle); - if (!H264_4K2K_SINGLE_CORE) - WRITE_VREG(VDEC2_AV_SCRATCH_L, mc_dma_handle); - - if (H264_4K2K_SINGLE_CORE) - size = get_firmware_data(VIDEO_DEC_H264_4k2K_SINGLE, buf); - else - size = get_firmware_data(VIDEO_DEC_H264_4k2K, buf); - - if (size < 0) { - pr_err("get firmware fail."); - vfree(buf); - return -1; - } - - if (H264_4K2K_SINGLE_CORE) - ret = amvdec_loadmc_ex(VFORMAT_H264_4K2K, "single_core", buf); - else - ret = amvdec_loadmc_ex(VFORMAT_H264_4K2K, NULL, buf); - - if (ret < 0) { - amvdec_disable(); - dma_free_coherent(amports_get_dma_device(), - MC_TOTAL_SIZE, mc_cpu_addr, mc_dma_handle); - mc_cpu_addr = NULL; - pr_err("H264_4K2K: the %s fw loading failed, err: %x\n", - tee_enabled() ? "TEE" : "local", ret); - return -EBUSY; - } - - if (!H264_4K2K_SINGLE_CORE) { - amvdec2_enable(); - - if (amvdec2_loadmc_ex(VFORMAT_H264_4K2K, NULL, buf) < 0) { - amvdec_disable(); - amvdec2_disable(); - dma_free_coherent(amports_get_dma_device(), - MC_TOTAL_SIZE, mc_cpu_addr, mc_dma_handle); - mc_cpu_addr = NULL; - return -EBUSY; - } - } - - /*header*/ - memcpy((u8 *) mc_cpu_addr, buf + 0x1000, 0x1000); - - /*mmco*/ - memcpy((u8 *) mc_cpu_addr + 0x1000, buf + 0x2000, 0x2000); - - /*slice*/ - memcpy((u8 *) mc_cpu_addr + 0x3000, buf + 0x4000, 0x3000); - - stat |= STAT_MC_LOAD; - - /* enable AMRISC side protocol */ - vh264_4k2k_prot_init(); - - if (vdec_request_irq(VDEC_IRQ_1, vh264_4k2k_isr, - "vh264_4k2k-irq", (void *)vh264_4k2k_dec_id)) { - pr_info("vh264_4k2k irq register error.\n"); - amvdec_disable(); - if (!H264_4K2K_SINGLE_CORE) - amvdec2_disable(); - - return -ENOENT; - } -#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ - if (!H264_4K2K_SINGLE_CORE) { - if (vdec_request_irq(VDEC_IRQ_0, vh264_4k2k_vdec2_isr, - "vh264_4k2k-vdec2-irq", - (void *)vh264_4k2k_dec_id2)) { - pr_info("vh264_4k2k irq register error.\n"); - vdec_free_irq(VDEC_IRQ_1, (void *)vh264_4k2k_dec_id); - amvdec_disable(); - amvdec2_disable(); - return -ENOENT; - } - } -#endif - - stat |= STAT_ISR_REG; - - vf_provider_init(&vh264_4k2k_vf_prov, PROVIDER_NAME, - &vh264_4k2k_vf_provider, NULL); - vf_reg_provider(&vh264_4k2k_vf_prov); - vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_START, NULL); - - vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_FR_HINT, - (void *)((unsigned long) - vh264_4k2k_amstream_dec_info.rate)); - - stat |= STAT_VF_HOOK; - - recycle_timer.data = (ulong) (&recycle_timer); - recycle_timer.function = vh264_4k2k_put_timer_func; - recycle_timer.expires = jiffies + PUT_INTERVAL; - - add_timer(&recycle_timer); - - stat |= STAT_TIMER_ARM; - - amvdec_start(); - if (!H264_4K2K_SINGLE_CORE) - amvdec2_start(); - - stat |= STAT_VDEC_RUN; - - ret = vh264_4k2k_vdec_info_init(); - if (0 != ret) - return -ret; - - return 0; -} - -static int vh264_4k2k_stop(void) -{ - - if (stat & STAT_VDEC_RUN) { - amvdec_stop(); - if (!H264_4K2K_SINGLE_CORE) - amvdec2_stop(); - stat &= ~STAT_VDEC_RUN; - } - - if (stat & STAT_ISR_REG) { - WRITE_VREG(VDEC_ASSIST_MBOX1_MASK, 0); - if (!H264_4K2K_SINGLE_CORE) - WRITE_VREG(VDEC2_ASSIST_MBOX0_MASK, 0); - - vdec_free_irq(VDEC_IRQ_1, (void *)vh264_4k2k_dec_id); -#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ - if (!H264_4K2K_SINGLE_CORE) - vdec_free_irq(VDEC_IRQ_0, (void *)vh264_4k2k_dec_id2); -#endif - stat &= ~STAT_ISR_REG; - } - - if (stat & STAT_TIMER_ARM) { - del_timer_sync(&recycle_timer); - stat &= ~STAT_TIMER_ARM; - } - - if (stat & STAT_VF_HOOK) { - vf_notify_receiver(PROVIDER_NAME, - VFRAME_EVENT_PROVIDER_FR_END_HINT, NULL); - - vf_unreg_provider(&vh264_4k2k_vf_prov); - stat &= ~STAT_VF_HOOK; - } -#ifdef DOUBLE_WRITE - WRITE_VREG(MDEC_DOUBLEW_CFG0, 0); - if (!H264_4K2K_SINGLE_CORE) - WRITE_VREG(VDEC2_MDEC_DOUBLEW_CFG0, 0); -#endif - - if (stat & STAT_MC_LOAD) { - if (mc_cpu_addr != NULL) { - dma_free_coherent(amports_get_dma_device(), - MC_TOTAL_SIZE, mc_cpu_addr, mc_dma_handle); - mc_cpu_addr = NULL; - } - - stat &= ~STAT_MC_LOAD; - } - - amvdec_disable(); - if (!H264_4K2K_SINGLE_CORE) - amvdec2_disable(); -#ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA - msleep(100); -#endif - if (mm_blk_handle) { - decoder_bmmu_box_free(mm_blk_handle); - mm_blk_handle = NULL; - } - - return 0; -} - -void vh264_4k_free_cmabuf(void) -{ - int i; - - if (atomic_read(&vh264_4k2k_active)) - return; - mutex_lock(&vh264_4k2k_mutex); - for (i = 0; i < ARRAY_SIZE(buffer_spec); i++) { - if (buffer_spec[i].phy_addr) { - codec_mm_free_for_dma(MEM_NAME, - buffer_spec[i].phy_addr); - buffer_spec[i].phy_addr = 0; - buffer_spec[i].alloc_pages = NULL; - buffer_spec[i].alloc_count = 0; - pr_info("force free CMA buffer %d\n", i); - } - } - mutex_unlock(&vh264_4k2k_mutex); -} - -static int amvdec_h264_4k2k_probe(struct platform_device *pdev) -{ - struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data; - - pr_info("amvdec_h264_4k2k probe start.\n"); - - mutex_lock(&vh264_4k2k_mutex); - - fatal_error = 0; - - if (pdata == NULL) { - pr_info("\namvdec_h264_4k2k memory resource undefined.\n"); - mutex_unlock(&vh264_4k2k_mutex); - return -EFAULT; - } - - if (pdata->sys_info) - vh264_4k2k_amstream_dec_info = *pdata->sys_info; - cma_dev = pdata->cma_dev; - - pr_info(" sysinfo: %dx%d, rate = %d, param = 0x%lx\n", - vh264_4k2k_amstream_dec_info.width, - vh264_4k2k_amstream_dec_info.height, - vh264_4k2k_amstream_dec_info.rate, - (unsigned long) vh264_4k2k_amstream_dec_info.param); - - if (!H264_4K2K_SINGLE_CORE) { - if (vdec_on(VDEC_2)) { /* ++++ */ - vdec_poweroff(VDEC_2); /* ++++ */ - mdelay(10); - } - vdec_poweron(VDEC_2); - } - - - if (!H264_4K2K_SINGLE_CORE) - vdec2_power_mode(1); - - pdata->dec_status = vh264_4k2k_dec_status; - if (H264_4K2K_SINGLE_CORE) - pdata->set_trickmode = vh264_4k2k_set_trickmode; - - if (vh264_4k2k_init() < 0) { - pr_info("\namvdec_h264_4k2k init failed.\n"); - mutex_unlock(&vh264_4k2k_mutex); - kfree(gvs); - gvs = NULL; - - return -ENODEV; - } -#if 1/*MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8*/ - request_vpu_clk_vmod(360000000, VPU_VIU_VD1); -#endif - - if (probe_callback) - probe_callback(); - /*set the max clk for smooth playing...*/ - vdec_source_changed(VFORMAT_H264_4K2K, - 4096, 2048, 30); - INIT_WORK(&set_clk_work, vh264_4k2k_set_clk); - - atomic_set(&vh264_4k2k_active, 1); - mutex_unlock(&vh264_4k2k_mutex); - - return 0; -} - -static int amvdec_h264_4k2k_remove(struct platform_device *pdev) -{ - cancel_work_sync(&alloc_work); - cancel_work_sync(&set_clk_work); - mutex_lock(&vh264_4k2k_mutex); - atomic_set(&vh264_4k2k_active, 0); - - vh264_4k2k_stop(); - - vdec_source_changed(VFORMAT_H264_4K2K, 0, 0, 0); - - if (!H264_4K2K_SINGLE_CORE) { - vdec_poweroff(VDEC_2); - } -#ifdef DEBUG_PTS - pr_info("pts missed %ld, pts hit %ld, duration %d\n", - pts_missed, pts_hit, frame_dur); -#endif - - if (remove_callback) - remove_callback(); - - mutex_unlock(&vh264_4k2k_mutex); - - kfree(gvs); - gvs = NULL; - - pr_info("amvdec_h264_4k2k_remove\n"); - return 0; -} - -void vh264_4k2k_register_module_callback(void (*enter_func)(void), - void (*remove_func)(void)) -{ - probe_callback = enter_func; - remove_callback = remove_func; -} -EXPORT_SYMBOL(vh264_4k2k_register_module_callback); - -/****************************************/ - -static struct platform_driver amvdec_h264_4k2k_driver = { - .probe = amvdec_h264_4k2k_probe, - .remove = amvdec_h264_4k2k_remove, -#ifdef CONFIG_PM - .suspend = amvdec_suspend, - .resume = amvdec_resume, -#endif - .driver = { - .name = DRIVER_NAME, - } -}; - -static struct codec_profile_t amvdec_h264_4k2k_profile = { - .name = "h264_4k2k", - .profile = "" -}; -static struct mconfig h264_4k2k_configs[] = { - MC_PU32("stat", &stat), - MC_PU32("error_recovery_mode", &error_recovery_mode), -}; -static struct mconfig_node h264_4k2k_node; - -static int __init amvdec_h264_4k2k_driver_init_module(void) -{ - pr_debug("amvdec_h264_4k2k module init\n"); - - if (platform_driver_register(&amvdec_h264_4k2k_driver)) { - pr_err("failed to register amvdec_h264_4k2k driver\n"); - return -ENODEV; - } - if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_GXTVBB) - vcodec_profile_register(&amvdec_h264_4k2k_profile); - INIT_REG_NODE_CONFIGS("media.decoder", &h264_4k2k_node, - "h264_4k2k", h264_4k2k_configs, CONFIG_FOR_RW); - return 0; -} - -static void __exit amvdec_h264_4k2k_driver_remove_module(void) -{ - pr_debug("amvdec_h264_4k2k module remove.\n"); - - platform_driver_unregister(&amvdec_h264_4k2k_driver); -} - -/****************************************/ - -module_param(stat, uint, 0664); -MODULE_PARM_DESC(stat, "\n amvdec_h264_4k2k stat\n"); - -module_param(error_recovery_mode, uint, 0664); -MODULE_PARM_DESC(error_recovery_mode, "\n amvdec_h264 error_recovery_mode\n"); - -module_init(amvdec_h264_4k2k_driver_init_module); -module_exit(amvdec_h264_4k2k_driver_remove_module); - -MODULE_DESCRIPTION("AMLOGIC h264_4k2k Video Decoder Driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Tim Yao <tim.yao@amlogic.com>");
diff --git a/drivers/frame_provider/decoder/h264/vh264_mvc.c b/drivers/frame_provider/decoder/h264/vh264_mvc.c index 0efd1a0..4827e38 100644 --- a/drivers/frame_provider/decoder/h264/vh264_mvc.c +++ b/drivers/frame_provider/decoder/h264/vh264_mvc.c
@@ -31,11 +31,8 @@ #include <linux/workqueue.h> #include <linux/dma-mapping.h> #include <linux/atomic.h> -#include <linux/amlogic/tee.h> - #include <linux/module.h> #include <linux/slab.h> - #include <linux/amlogic/media/utils/vdec_reg.h> #include "../../../stream_input/amports/amports_priv.h" #include "../utils/vdec.h" @@ -45,8 +42,8 @@ #include <linux/amlogic/media/codec_mm/codec_mm.h> #include <linux/amlogic/media/codec_mm/configs.h> #include "../utils/firmware.h" -#include <linux/amlogic/tee.h> #include "../utils/config_parser.h" +#include "../../../common/chips/decoder_cpu_ver_info.h" #define TIME_TASK_PRINT_ENABLE 0x100 #define PUT_PRINT_ENABLE 0x200 @@ -82,7 +79,7 @@ static void vh264mvc_prot_init(void); static int vh264mvc_local_init(void); -static void vh264mvc_put_timer_func(unsigned long arg); +static void vh264mvc_put_timer_func(struct timer_list *timer); static const char vh264mvc_dec_id[] = "vh264mvc-dev"; @@ -515,10 +512,10 @@ static struct vframe_s *vh264mvc_vf_get(void *op_arg) { - struct vframe_s *vf; int view0_buf_id; int view1_buf_id; + struct buffer_spec_s *buf_spec_0, *buf_spec_1; if (get_ptr == fill_ptr) return NULL; @@ -530,10 +527,27 @@ if ((view0_buf_id >= 0) && (view1_buf_id >= 0)) { if (view_mode == 0 || view_mode == 1) { vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD; - vf->canvas0Addr = vf->canvas1Addr = - (view_mode == - 0) ? spec2canvas(&buffer_spec0[view0_buf_id]) : - spec2canvas(&buffer_spec1[view1_buf_id]); + + buf_spec_0 = (view_mode == 0) ? (&buffer_spec0[view0_buf_id]) : + (&buffer_spec1[view1_buf_id]); + vf->canvas0Addr = vf->canvas1Addr = spec2canvas(buf_spec_0); + + if (is_support_vdec_canvas()) { + vf->canvas0Addr = vf->canvas1Addr = -1; + vf->canvas0_config[0].block_mode = CANVAS_BLKMODE_32X32; + vf->canvas0_config[0].phy_addr = buf_spec_0->y_addr; + vf->canvas0_config[0].width = vdec_cav_get_width(buf_spec_0->y_canvas_index); + vf->canvas0_config[0].height = vdec_cav_get_height(buf_spec_0->y_canvas_index); + vf->canvas0_config[1].block_mode = CANVAS_BLKMODE_32X32; + vf->canvas0_config[1].phy_addr = buf_spec_0->u_addr; + vf->canvas0_config[1].width = vdec_cav_get_width(buf_spec_0->u_canvas_index); + vf->canvas0_config[1].height = vdec_cav_get_height(buf_spec_0->u_canvas_index); + vf->canvas0_config[2].block_mode = CANVAS_BLKMODE_32X32; + vf->canvas0_config[2].phy_addr = buf_spec_0->v_addr; + vf->canvas0_config[2].width = vdec_cav_get_width(buf_spec_0->v_canvas_index); + vf->canvas0_config[2].height = vdec_cav_get_height(buf_spec_0->v_canvas_index); + vf->plane_num = 3; + } } else { vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_MVC; @@ -545,25 +559,50 @@ vf->right_eye.start_y = 0; vf->right_eye.width = vf->width; vf->right_eye.height = vf->height; - vf->trans_fmt = TVIN_TFMT_3D_TB; + //vf->trans_fmt = TVIN_TFMT_3D_TB; if (view_mode == 2) { - vf->canvas0Addr = - spec2canvas(&buffer_spec1[ - view1_buf_id]); - vf->canvas1Addr = - spec2canvas(&buffer_spec0[ - view0_buf_id]); + buf_spec_0 = &buffer_spec1[view1_buf_id]; + buf_spec_1 = &buffer_spec0[view0_buf_id]; } else { - vf->canvas0Addr = - spec2canvas(&buffer_spec0[ - view0_buf_id]); - vf->canvas1Addr = - spec2canvas(&buffer_spec1[ - view1_buf_id]); + buf_spec_0 = &buffer_spec0[view0_buf_id]; + buf_spec_1 = &buffer_spec1[view1_buf_id]; + } + if (is_support_vdec_canvas()) { + vf->canvas0Addr = vf->canvas1Addr = -1; + vf->canvas0_config[0].block_mode = CANVAS_BLKMODE_32X32; + vf->canvas0_config[0].phy_addr = buf_spec_0->y_addr; + vf->canvas0_config[0].width = vdec_cav_get_width(buf_spec_0->y_canvas_index); + vf->canvas0_config[0].height = vdec_cav_get_height(buf_spec_0->y_canvas_index); + vf->canvas0_config[1].block_mode = CANVAS_BLKMODE_32X32; + vf->canvas0_config[1].phy_addr = buf_spec_0->u_addr; + vf->canvas0_config[1].width = vdec_cav_get_width(buf_spec_0->u_canvas_index); + vf->canvas0_config[1].height = vdec_cav_get_height(buf_spec_0->u_canvas_index); + vf->canvas0_config[2].block_mode = CANVAS_BLKMODE_32X32; + vf->canvas0_config[2].phy_addr = buf_spec_0->v_addr; + vf->canvas0_config[2].width = vdec_cav_get_width(buf_spec_0->v_canvas_index); + vf->canvas0_config[2].height = vdec_cav_get_height(buf_spec_0->v_canvas_index); + + vf->canvas1_config[0].block_mode = CANVAS_BLKMODE_32X32; + vf->canvas1_config[0].phy_addr = buf_spec_1->y_addr; + vf->canvas1_config[0].width = vdec_cav_get_width(buf_spec_1->y_canvas_index); + vf->canvas1_config[0].height = vdec_cav_get_height(buf_spec_1->y_canvas_index); + vf->canvas1_config[1].block_mode = CANVAS_BLKMODE_32X32; + vf->canvas1_config[1].phy_addr = buf_spec_1->u_addr; + vf->canvas1_config[1].width = vdec_cav_get_width(buf_spec_1->u_canvas_index); + vf->canvas1_config[1].height = vdec_cav_get_height(buf_spec_1->u_canvas_index); + vf->canvas1_config[2].block_mode = CANVAS_BLKMODE_32X32; + vf->canvas1_config[2].phy_addr = buf_spec_1->v_addr; + vf->canvas1_config[2].width = vdec_cav_get_width(buf_spec_1->v_canvas_index); + vf->canvas1_config[2].height = vdec_cav_get_height(buf_spec_1->v_canvas_index); + vf->plane_num = 3; + } else { + vf->canvas0Addr = spec2canvas(buf_spec_0); + vf->canvas1Addr = spec2canvas(buf_spec_1); } } } + vf->type_original = vf->type; if (((vfpool_idx[get_ptr].view0_drop != 0) || (vfpool_idx[get_ptr].view1_drop != 0)) @@ -704,23 +743,23 @@ buffer_spec[i].alloc_count = page_count; buffer_spec[i].y_addr = addr; buffer_spec[i].y_canvas_index = index; - canvas_config(index, addr, + config_cav_lut_ex(index, addr, mb_width << 4, mb_height << 4, - CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); + CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32, 0, VDEC_1); addr += mb_total << 8; index++; buffer_spec[i].u_addr = addr; buffer_spec[i].u_canvas_index = index; - canvas_config(index, addr, mb_width << 3, mb_height << 3, - CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); + config_cav_lut_ex(index, addr, mb_width << 3, mb_height << 3, + CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32, 0, VDEC_1); addr += mb_total << 6; index++; buffer_spec[i].v_addr = addr; buffer_spec[i].v_canvas_index = index; - canvas_config(index, addr, mb_width << 3, mb_height << 3, - CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); + config_cav_lut_ex(index, addr, mb_width << 3, mb_height << 3, + CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32, 0, VDEC_1); index++; } @@ -858,7 +897,10 @@ refbuf_size = ref_size * (max_reference_frame_num + 1) * 2; - index = CANVAS_INDEX_START; + if (is_support_vdec_canvas()) + index = 0; + else + index = CANVAS_INDEX_START; ANC_CANVAS_ADDR = ANC0_CANVAS_ADDR; ret = @@ -937,7 +979,10 @@ max_reference_frame_num); } - index = CANVAS_INDEX_START + total_dec_frame_buffering[0] * 3; + if (is_support_vdec_canvas()) + index = total_dec_frame_buffering[0] * 3; + else + index = CANVAS_INDEX_START + total_dec_frame_buffering[0] * 3; ANC_CANVAS_ADDR = ANC0_CANVAS_ADDR + total_dec_frame_buffering[0]; @@ -1188,10 +1233,8 @@ } } -static void vh264mvc_put_timer_func(unsigned long arg) +static void vh264mvc_put_timer_func(struct timer_list *timer) { - struct timer_list *timer = (struct timer_list *)arg; - int valid_frame = 0; mvc_set_rp(); @@ -1380,7 +1423,10 @@ #endif WRITE_VREG(M4_CONTROL_REG, (1 << 13)); /* H264_DECODE_INFO - h264_en */ - WRITE_VREG(CANVAS_START, CANVAS_INDEX_START); + if (is_support_vdec_canvas()) + WRITE_VREG(CANVAS_START, 0); + else + WRITE_VREG(CANVAS_START, CANVAS_INDEX_START); #if 1 /* Start Address of Workspace (UCODE, temp_data...) */ WRITE_VREG(WORKSPACE_START, @@ -1435,6 +1481,9 @@ WRITE_VREG(BUFFER_RECYCLE, 0); WRITE_VREG(DROP_CONTROL, 0); CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17); + + CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 16); + #if 1 /* /MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ WRITE_VREG(MDEC_PIC_DC_THRESH, 0x404038aa); #endif @@ -1480,7 +1529,6 @@ max_dec_frame_buffering[1] = -1; fill_ptr = get_ptr = put_ptr = putting_ptr = 0; dirty_frame_num = 0; - for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) { view0_vfbuf_use[i] = 0; view1_vfbuf_use[i] = 0; @@ -1524,11 +1572,12 @@ { int ret = -1; char *buf = vmalloc(0x1000 * 16); + if (buf == NULL) return -ENOMEM; pr_info("\nvh264mvc_init\n"); - init_timer(&recycle_timer); + timer_setup(&recycle_timer, vh264mvc_put_timer_func, 0); stat |= STAT_TIMER_INIT; @@ -1618,10 +1667,7 @@ stat |= STAT_VF_HOOK; - recycle_timer.data = (ulong) (&recycle_timer); - recycle_timer.function = vh264mvc_put_timer_func; recycle_timer.expires = jiffies + PUT_INTERVAL; - add_timer(&recycle_timer); stat |= STAT_TIMER_ARM; @@ -1788,32 +1834,16 @@ } /****************************************/ -#ifdef CONFIG_PM -static int h264mvc_suspend(struct device *dev) -{ - amvdec_suspend(to_platform_device(dev), dev->power.power_state); - return 0; -} - -static int h264mvc_resume(struct device *dev) -{ - amvdec_resume(to_platform_device(dev)); - return 0; -} - -static const struct dev_pm_ops h264mvc_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(h264mvc_suspend, h264mvc_resume) -}; -#endif static struct platform_driver amvdec_h264mvc_driver = { .probe = amvdec_h264mvc_probe, .remove = amvdec_h264mvc_remove, +#ifdef CONFIG_PM + .suspend = amvdec_suspend, + .resume = amvdec_resume, +#endif .driver = { .name = DRIVER_NAME, -#ifdef CONFIG_PM - .pm = &h264mvc_pm_ops, -#endif } };
diff --git a/drivers/frame_provider/decoder/h264_multi/h264_dpb.c b/drivers/frame_provider/decoder/h264_multi/h264_dpb.c old mode 100755 new mode 100644 index 7b0980a..52d9611 --- a/drivers/frame_provider/decoder/h264_multi/h264_dpb.c +++ b/drivers/frame_provider/decoder/h264_multi/h264_dpb.c
@@ -37,15 +37,19 @@ if (((h264_debug_flag & debug_flag) && ((1 << index) & h264_debug_mask)) || (debug_flag == PRINT_FLAG_ERROR)) { - unsigned char buf[512]; + unsigned char *buf = kzalloc(512, GFP_ATOMIC); int len = 0; va_list args; + if (!buf) + return 0; + va_start(args, fmt); len = sprintf(buf, "%d: ", index); vsnprintf(buf + len, 512-len, fmt, args); pr_debug("%s", buf); va_end(args); + kfree(buf); } return 0; } @@ -55,13 +59,18 @@ if (((h264_debug_flag & debug_flag) && ((1 << index) & h264_debug_mask)) || (debug_flag == PRINT_FLAG_ERROR)) { - unsigned char buf[512]; + unsigned char *buf = kzalloc(512, GFP_ATOMIC); int len = 0; va_list args; + + if (!buf) + return 0; + va_start(args, fmt); vsnprintf(buf + len, 512-len, fmt, args); pr_info("%s", buf); va_end(args); + kfree(buf); } return 0; } @@ -412,6 +421,8 @@ pSlice->long_term_reference_flag, pSlice->no_output_of_prior_pics_flag); + p_H264_Dpb->long_term_reference_flag = pSlice->long_term_reference_flag; + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, "idr set pre_frame_num(%d) to frame_num (%d)\n", @@ -652,7 +663,7 @@ (pSlice->toppoc < pSlice->bottompoc) ? pSlice->toppoc : pSlice->bottompoc; /* POC200301 */ - } else if (pSlice->bottom_field_flag == FALSE) { + } else if (pSlice->bottom_field_flag == 0) { /* top field */ pSlice->ThisPOC = pSlice->toppoc = pSlice->PicOrderCntMsb + @@ -770,7 +781,7 @@ (pSlice->toppoc < pSlice->bottompoc) ? pSlice->toppoc : pSlice->bottompoc; /* POC200301 */ - } else if (pSlice->bottom_field_flag == FALSE) { + } else if (pSlice->bottom_field_flag == 0) { /* top field */ pSlice->ThisPOC = pSlice->toppoc = p_Vid->ExpectedPicOrderCnt + @@ -824,7 +835,7 @@ if (pSlice->field_pic_flag == 0) pSlice->toppoc = pSlice->bottompoc = pSlice->framepoc = pSlice->ThisPOC; - else if (pSlice->bottom_field_flag == FALSE) + else if (pSlice->bottom_field_flag == 0) pSlice->toppoc = pSlice->framepoc = pSlice->ThisPOC; else @@ -1839,6 +1850,35 @@ } +static void unmark_for_long_term_reference(struct FrameStore *fs) +{ + if (fs->is_used & 1) { + if (fs->top_field) { + fs->top_field->used_for_reference = 0; + fs->top_field->is_long_term = 0; + } + } + if (fs->is_used & 2) { + if (fs->bottom_field) { + fs->bottom_field->used_for_reference = 0; + fs->bottom_field->is_long_term = 0; + } + } + if (fs->is_used == 3) { + if (fs->top_field && fs->bottom_field) { + fs->top_field->used_for_reference = 0; + fs->top_field->is_long_term = 0; + fs->bottom_field->used_for_reference = 0; + fs->bottom_field->is_long_term = 0; + } + fs->frame->used_for_reference = 0; + fs->frame->is_long_term = 0; + } + + fs->is_reference = 0; + fs->is_long_term = 0; +} + int get_long_term_flag_by_buf_spec_num(struct h264_dpb_stru *p_H264_Dpb, int buf_spec_num) { @@ -2164,7 +2204,6 @@ struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; int ret = 0; unsigned char removed_flag = 0; - do { ret = remove_unused_frame_from_dpb(p_H264_Dpb); if (ret != 0) @@ -2331,7 +2370,8 @@ "%s first_insert_frame %d \n", __func__, p_H264_Dpb->first_insert_frame); } if (prepare_display_buf(p_H264_Dpb->vdec, p_Dpb->fs[pos]) >= 0) { - if (!p_H264_Dpb->without_display_mode) + if (!p_H264_Dpb->without_display_mode && + p_Dpb->fs[pos]->show_frame != false) p_Dpb->fs[pos]->pre_output = 1; } else { if (h264_debug_flag & PRINT_FLAG_DPB_DETAIL) { @@ -2555,6 +2595,14 @@ if (p->no_output_of_prior_pics_flag) { + int i; + for (i = 0; i < p_Dpb->used_size; i++) { + unmark_for_reference(p_Dpb, p_Dpb->fs[i]); + if (p_Dpb->fs[i]->is_long_term) + unmark_for_long_term_reference(p_Dpb->fs[i]); + if (!p_Dpb->fs[i]->is_output && !p_Dpb->fs[i]->pre_output) + set_frame_output_flag(p_H264_Dpb, i); + } #if 0 /*???*/ /* free all stored pictures */ @@ -2653,108 +2701,90 @@ void dump_dpb(struct DecodedPictureBuffer *p_Dpb, u8 force) { - unsigned i; + unsigned int i; + unsigned char *buf = NULL; + unsigned int buf_size = 512, len = 0; struct h264_dpb_stru *p_H264_Dpb = container_of(p_Dpb, struct h264_dpb_stru, mDPB); + +#define DPB_STRCAT(args...) do { \ + len += snprintf(buf + len, \ + buf_size - len, ##args);\ + } while (0) + if ((h264_debug_flag & PRINT_FLAG_DUMP_DPB) == 0 && force == 0) return; + + buf = kzalloc(buf_size, GFP_ATOMIC); + if (buf == NULL) + return; + for (i = 0; i < p_Dpb->used_size; i++) { - dpb_print(p_H264_Dpb->decoder_index, - 0, - "("); - dpb_print_cont(p_H264_Dpb->decoder_index, - 0, - "fn=%d is_used %d ", + len = 0; + memset(buf, 0, buf_size); + DPB_STRCAT("fn=%d is_used %d ", p_Dpb->fs[i]->frame_num, p_Dpb->fs[i]->is_used); + if (p_Dpb->fs[i]->is_used & 1) { if (p_Dpb->fs[i]->top_field) - dpb_print_cont(p_H264_Dpb->decoder_index, - 0, - "T: poc=%d pic_num=%d ", + DPB_STRCAT("T: poc=%d pic_num=%d ", p_Dpb->fs[i]->top_field->poc, p_Dpb->fs[i]->top_field->pic_num); else - dpb_print_cont(p_H264_Dpb->decoder_index, - 0, - "T: poc=%d ", + DPB_STRCAT("T: poc=%d ", p_Dpb->fs[i]->frame->top_poc); } if (p_Dpb->fs[i]->is_used & 2) { if (p_Dpb->fs[i]->bottom_field) - dpb_print_cont(p_H264_Dpb->decoder_index, - 0, - "B: poc=%d pic_num=%d ", + DPB_STRCAT("B: poc=%d pic_num=%d ", p_Dpb->fs[i]->bottom_field->poc, p_Dpb->fs[i]->bottom_field->pic_num); else - dpb_print_cont(p_H264_Dpb->decoder_index, - 0, - "B: poc=%d ", + DPB_STRCAT("B: poc=%d ", p_Dpb->fs[i]->frame->bottom_poc); } if (p_Dpb->fs[i]->is_used == 3) { if (p_Dpb->fs[i]->frame != NULL) - dpb_print_cont(p_H264_Dpb->decoder_index, - 0, - "F: poc=%d pic_num=%d ", + DPB_STRCAT("F: poc=%d pic_num=%d ", p_Dpb->fs[i]->frame->poc, p_Dpb->fs[i]->frame->pic_num); else - dpb_print_cont(p_H264_Dpb->decoder_index, - 0, "fs[%d] frame is null ", i); + DPB_STRCAT("fs[%d] frame is null ", i); } - dpb_print_cont(p_H264_Dpb->decoder_index, - 0, - "G: poc=%d) ", p_Dpb->fs[i]->poc); + DPB_STRCAT("G: poc=%d) ", p_Dpb->fs[i]->poc); if (p_Dpb->fs[i]->is_reference) - dpb_print_cont(p_H264_Dpb->decoder_index, - 0, - "ref (%d) ", p_Dpb->fs[i]->is_reference); + DPB_STRCAT("ref (%d) ", p_Dpb->fs[i]->is_reference); if (p_Dpb->fs[i]->is_long_term) - dpb_print_cont(p_H264_Dpb->decoder_index, - 0, - "lt_ref (%d) ", p_Dpb->fs[i]->is_reference); + DPB_STRCAT("lt_ref (%d) ", p_Dpb->fs[i]->is_reference); if (p_Dpb->fs[i]->is_output) - dpb_print_cont(p_H264_Dpb->decoder_index, - 0, - "out(displayed) "); + DPB_STRCAT("out(displayed) "); if (p_Dpb->fs[i]->pre_output) - dpb_print_cont(p_H264_Dpb->decoder_index, - 0, - "pre_output(in dispq or displaying) "); + DPB_STRCAT("pre_output(in dispq or displaying) "); if (p_Dpb->fs[i]->is_used == 3) { if (p_Dpb->fs[i]->frame != NULL && p_Dpb->fs[i]->frame->non_existing) - dpb_print_cont(p_H264_Dpb->decoder_index, - 0, - "non_existing "); + DPB_STRCAT("non_existing "); else - dpb_print_cont(p_H264_Dpb->decoder_index, - 0, "fs[%d] frame is null ", i); + DPB_STRCAT("fs[%d] frame is null ", i); } - dpb_print_cont(p_H264_Dpb->decoder_index, - 0, - "dpb_frame_count %d ", + DPB_STRCAT("dpb_frame_count %d ", p_Dpb->fs[i]->dpb_frame_count); #if (MVC_EXTENSION_ENABLE) if (p_Dpb->fs[i]->is_reference) - dpb_print_cont(p_H264_Dpb->decoder_index, - 0, - "view_id (%d) ", p_Dpb->fs[i]->view_id); + DPB_STRCAT("view_id (%d) ", p_Dpb->fs[i]->view_id); #endif if (p_Dpb->fs[i]->data_flag) { - dpb_print_cont(p_H264_Dpb->decoder_index, - 0, - "data_flag(0x%x)", + DPB_STRCAT("data_flag(0x%x)", p_Dpb->fs[i]->data_flag); } - dpb_print_cont(p_H264_Dpb->decoder_index, - 0, - " bufspec %d\n", + DPB_STRCAT(" bufspec %d\n", p_Dpb->fs[i]->buf_spec_num); + dpb_print(p_H264_Dpb->decoder_index, 0, "%s", buf); } + + kfree(buf); } /*! @@ -2872,35 +2902,6 @@ } } -static void unmark_for_long_term_reference(struct FrameStore *fs) -{ - if (fs->is_used & 1) { - if (fs->top_field) { - fs->top_field->used_for_reference = 0; - fs->top_field->is_long_term = 0; - } - } - if (fs->is_used & 2) { - if (fs->bottom_field) { - fs->bottom_field->used_for_reference = 0; - fs->bottom_field->is_long_term = 0; - } - } - if (fs->is_used == 3) { - if (fs->top_field && fs->bottom_field) { - fs->top_field->used_for_reference = 0; - fs->top_field->is_long_term = 0; - fs->bottom_field->used_for_reference = 0; - fs->bottom_field->is_long_term = 0; - } - fs->frame->used_for_reference = 0; - fs->frame->is_long_term = 0; - } - - fs->is_reference = 0; - fs->is_long_term = 0; -} - /*! ************************************************************************ * \brief @@ -3687,8 +3688,7 @@ else i = 0; - if (i || (p_H264_Dpb->first_insert_frame < FirstInsertFrm_SKIPDONE) || - ((p_Dpb->size - frame_outside_count) == p_H264_Dpb->dec_dpb_size)) { + if (i || (p_H264_Dpb->first_insert_frame < FirstInsertFrm_SKIPDONE)) { while (output_frames(p_H264_Dpb, i)) ; } @@ -5066,7 +5066,7 @@ } dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, - "%s: RefPicListX[ %d ] = pic %px (%d)\n", __func__, + "%s: RefPicListX[ %d ] = pic %x (%d)\n", __func__, *refIdxLX, picLX, picNumLX); RefPicListX[(*refIdxLX)++] = picLX; @@ -5501,7 +5501,7 @@ p_old_slice->pps_id = INT_MAX; p_old_slice->frame_num = INT_MAX; p_old_slice->nal_ref_idc = INT_MAX; - p_old_slice->idr_flag = FALSE; + p_old_slice->idr_flag = 0; p_old_slice->pic_oder_cnt_lsb = UINT_MAX; p_old_slice->delta_pic_oder_cnt_bottom = INT_MAX; @@ -5836,11 +5836,7 @@ * p_Vid->height_cr, */ 1); - if (!p_H264_Dpb->mVideo.dec_picture) { - dpb_print(p_H264_Dpb->decoder_index, - PRINT_FLAG_DPB_DETAIL, "p_H264_Dpb->decoder_index is null\n"); - return -1; - } else { + if (p_H264_Dpb->mVideo.dec_picture) { u32 offset_lo, offset_hi; struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; @@ -5892,12 +5888,13 @@ } } #endif + if (post_picture_early(p_H264_Dpb->vdec, + p_H264_Dpb->mVideo.dec_picture->buf_spec_num)) + return -1; } } - if (post_picture_early(p_H264_Dpb->vdec, - p_H264_Dpb->mVideo.dec_picture->buf_spec_num)) - return -1; + if (p_H264_Dpb->mSlice.slice_type == P_SLICE) init_lists_p_slice(&p_H264_Dpb->mSlice); @@ -5949,8 +5946,15 @@ /*int j;*/ struct Slice *currSlice = &p_H264_Dpb->mSlice; /* in first output, ignore ref check */ - if (p_H264_Dpb->first_insert_frame < FirstInsertFrm_SKIPDONE) + if ((p_H264_Dpb->first_insert_frame == FirstInsertFrm_OUT) && + (p_H264_Dpb->mVideo.dec_picture) && + p_H264_Dpb->first_output_poc > p_H264_Dpb->mVideo.dec_picture->poc) { + + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "p_H264_Dpb->first_output_poc %d, p_H264_Dpb->mVideo.dec_picture->poc %d\n", + p_H264_Dpb->first_output_poc, p_H264_Dpb->mVideo.dec_picture->poc); return 0; + } if ((currSlice->slice_type != I_SLICE) && (currSlice->slice_type != SI_SLICE)) { for (i = 0; i < currSlice->listXsize[0]; i++) {
diff --git a/drivers/frame_provider/decoder/h264_multi/h264_dpb.h b/drivers/frame_provider/decoder/h264_multi/h264_dpb.h old mode 100755 new mode 100644 index 10b2dba..8b3e8bb --- a/drivers/frame_provider/decoder/h264_multi/h264_dpb.h +++ b/drivers/frame_provider/decoder/h264_multi/h264_dpb.h
@@ -39,6 +39,7 @@ #define DEBUG_DISABLE_RUNREADY_RMBUF 0x0800 #define PRINT_FLAG_DUMP_BUFSPEC 0x1000 #define PRINT_FLAG_FCC_STATUS 0x2000 +#define PRINT_FLAG_SEI_DETAIL 0x4000 #define PRINT_FLAG_V4L_DETAIL 0x8000 #define DISABLE_ERROR_HANDLE 0x10000 #define DEBUG_DUMP_STAT 0x80000 @@ -64,7 +65,7 @@ #define H264_OUTPUT_MODE_NORMAL 0x4 #define H264_OUTPUT_MODE_FAST 0x8 -#define FALSE 0 +//#define FALSE 0 #define H264_SLICE_HEAD_DONE 0x01 #define H264_PIC_DATA_DONE 0x02 @@ -823,7 +824,7 @@ u32 hw_decode_time; u32 frame_size2; // For recording the chunk->size in frame mode bool show_frame; - struct fence *fence; + struct dma_fence *fence; u32 decoded_frame_size; }; @@ -925,6 +926,7 @@ int first_output_poc; int dpb_frame_count; u32 without_display_mode; + int long_term_reference_flag; };
diff --git a/drivers/frame_provider/decoder/h264_multi/vmh264.c b/drivers/frame_provider/decoder/h264_multi/vmh264.c old mode 100755 new mode 100644 index 3274134..7a1762a --- a/drivers/frame_provider/decoder/h264_multi/vmh264.c +++ b/drivers/frame_provider/decoder/h264_multi/vmh264.c
@@ -23,7 +23,6 @@ #include <linux/kfifo.h> #include <linux/platform_device.h> #include <linux/random.h> - #include <linux/amlogic/media/utils/amstream.h> #include <linux/amlogic/media/frame_sync/ptsserv.h> #include <linux/amlogic/media/canvas/canvas.h> @@ -41,10 +40,10 @@ #include <linux/dma-contiguous.h> #include "../../../stream_input/amports/amports_priv.h" #include <linux/amlogic/media/codec_mm/codec_mm.h> - #include "../utils/vdec_input.h" -#include <linux/amlogic/tee.h> - +//#include <linux/amlogic/tee.h> +#include <uapi/linux/tee.h> +#include <linux/sched/clock.h> #include <linux/amlogic/media/utils/vdec_reg.h> #include "../utils/vdec.h" #include "../utils/amvdec.h" @@ -55,13 +54,14 @@ #include "../utils/decoder_mmu_box.h" #include "../utils/decoder_bmmu_box.h" #include "../utils/firmware.h" -#include <linux/amlogic/tee.h> #include <linux/uaccess.h> #include "../utils/config_parser.h" #include "../../../common/chips/decoder_cpu_ver_info.h" #include "../utils/vdec_v4l2_buffer_ops.h" #include <linux/crc32.h> #include <media/v4l2-mem2mem.h> +#include "../utils/vdec_feature.h" + #define DETECT_WRONG_MULTI_SLICE @@ -119,6 +119,9 @@ #define DUR2PTS_REM(x) (x*90 - DUR2PTS(x)*96) #define FIX_FRAME_RATE_CHECK_IDRFRAME_NUM 2 +#define ALIGN_WIDTH(x) (ALIGN((x), 64)) +#define ALIGN_HEIGHT(x) (ALIGN((x), 32)) + #define H264_DEV_NUM 9 #define CONSTRAIN_MAX_BUF_NUM @@ -127,7 +130,6 @@ #define VIDEO_SIGNAL_TYPE_AVAILABLE_MASK 0x20000000 #define INVALID_IDX -1 /* Invalid buffer index.*/ - static int mmu_enable; /*mmu do not support mbaff*/ static int force_enable_mmu = 0; @@ -152,6 +154,8 @@ static int pre_decode_buf_level = 0x1000; static int stream_mode_start_num = 4; static int dirty_again_threshold = 100; +static unsigned int colocate_old_cal; + static int check_dirty_data(struct vdec_s *vdec); #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION @@ -285,6 +289,7 @@ bit[20] 1: fixed some error stream will lead to the diffusion of the error, resulting playback stuck. bit[21] 1: fixed DVB loop playback cause jetter issue. bit[22] 1: In streaming mode, support for discarding data. + bit[23] 0: set error flag on frame number gap error and drop it, 1: ignore error. */ static unsigned int error_proc_policy = 0x7fCfb6; /*0x1f14*/ @@ -556,7 +561,6 @@ #define DEC_RESULT_EOS 7 #define DEC_RESULT_FORCE_EXIT 8 #define DEC_RESULT_TIMEOUT 9 -#define DEC_RESULT_DISCARD_DATA 10 /* @@ -609,6 +613,7 @@ NAL_SEARCH_CTL: bit 0, enable itu_t35 NAL_SEARCH_CTL: bit 1, enable mmu NAL_SEARCH_CTL: bit 2, detect frame_mbs_only_flag whether switch resolution + NAL_SEARCH_CTL: bit 15,bitstream_restriction_flag */ #define NAL_SEARCH_CTL AV_SCRATCH_9 #define MBY_MBX MB_MOTION_MODE /*0xc07*/ @@ -620,8 +625,6 @@ #define DECODE_MODE_MULTI_DVENL 0x4 static DEFINE_MUTEX(vmh264_mutex); - - #ifdef MH264_USERDATA_ENABLE struct mh264_userdata_record_t { @@ -650,6 +653,11 @@ #endif +struct mh264_fence_vf_t { + u32 used_size; + struct vframe_s *fence_vf[VF_POOL_SIZE]; +}; + struct vdec_h264_hw_s { spinlock_t lock; spinlock_t bufspec_lock; @@ -820,8 +828,8 @@ /**/ unsigned int last_frame_time; u32 vf_pre_count; - u32 vf_get_count; - u32 vf_put_count; + atomic_t vf_get_count; + atomic_t vf_put_count; /* timeout handle */ unsigned long int start_process_time; @@ -929,6 +937,7 @@ bool enable_fence; int fence_usage; bool discard_dv_data; + u32 metadata_config_flag; int vdec_pg_enable_flag; u32 save_reg_f; u32 start_bit_cnt; @@ -936,11 +945,14 @@ u32 wrong_frame_count; u32 error_frame_width; u32 error_frame_height; - char vdec_name[32]; - char pts_name[32]; - char new_q_name[32]; - char disp_q_name[32]; + ulong fb_token; int dec_again_cnt; + struct mh264_fence_vf_t fence_vf_s; + struct mutex fence_mutex; + u32 no_decoder_buffer_flag; + u32 video_signal_type; + struct trace_decoder_name trace; + int csd_change_flag; }; static u32 again_threshold; @@ -994,11 +1006,15 @@ static u32 mem_map_mode = H265_MEM_MAP_MODE; #define MAX_SIZE_4K (4096 * 2304) +#define MAX_SIZE_2K (1920 * 1088) static int is_oversize(int w, int h) { int max = MAX_SIZE_4K; + if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5D) + max = MAX_SIZE_2K; + if (w < 0 || h < 0) return true; @@ -1092,19 +1108,6 @@ return hsize; } -static int get_double_write_ratio(struct vdec_h264_hw_s *hw) -{ - int ratio = 1; - int dw_mode = hw->double_write_mode; - if ((dw_mode == 2) || - (dw_mode == 3)) - ratio = 4; - else if (dw_mode == 4) - ratio = 2; - return ratio; -} - - static int get_dw_size(struct vdec_h264_hw_s *hw, u32 *pdw_buffer_size_u_v_h) { int pic_width, pic_height; @@ -1119,9 +1122,9 @@ if (dw_mode) { int pic_width_dw = pic_width / - get_double_write_ratio(hw); + get_double_write_ratio(hw->double_write_mode); int pic_height_dw = pic_height / - get_double_write_ratio(hw); + get_double_write_ratio(hw->double_write_mode); int pic_width_lcu_dw = (pic_width_dw % lcu_size) ? pic_width_dw / lcu_size + 1 : @@ -1156,6 +1159,7 @@ u32 dw_buffer_size_u_v_h; u32 blkmode = hw->canvas_mode; int dw_mode = hw->double_write_mode; + struct vdec_s *vdec = hw_to_vdec(hw); canvas_addr = ANC0_CANVAS_ADDR; for (i = 0; i < num_buff; i++) @@ -1190,6 +1194,11 @@ DRIVER_HEADER_NAME, i); return; } + if (hw->enable_fence) { + vdec_fence_buffer_count_increase((ulong)vdec->sync); + INIT_LIST_HEAD(&vdec->sync->release_callback[HEADER_BUFFER_IDX(i)].node); + decoder_bmmu_box_add_callback_func(hw->bmmu_box, HEADER_BUFFER_IDX(i), (void *)&vdec->sync->release_callback[i]); + } } else maddr = hw->buffer_spec[i].alloc_header_addr; WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA, maddr >> 5); @@ -1204,9 +1213,9 @@ int canvas_h; canvas_w = hw->frame_width / - get_double_write_ratio(hw); + get_double_write_ratio(hw->double_write_mode); canvas_h = hw->frame_height / - get_double_write_ratio(hw); + get_double_write_ratio(hw->double_write_mode); if (hw->canvas_mode == 0) canvas_w = ALIGN(canvas_w, 32); @@ -1373,7 +1382,9 @@ u32 mc_buffer_size_u_v_h; int dw_mode = hw->double_write_mode; - lcu_x_num = (width + 15) >> 4; + /*lcu_x_num = (width + 15) >> 4;*/ + // width need to be round to 64 pixel -- case0260 1/10/2020 + lcu_x_num = (((width + 63) >> 6) << 2); lcu_y_num = (height + 15) >> 4; lcu_total = lcu_x_num * lcu_y_num; @@ -1422,7 +1433,7 @@ /* ipp_enable*/ WRITE_VREG(HEVCD_IPP_TOP_CNTL, 0x1 << 1); - if (get_cpu_major_id() >= MESON_CPU_MAJOR_ID_G12A) { + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { WRITE_VREG(HEVC_DBLK_CFG1, 0x2); // set ctusize==16 WRITE_VREG(HEVC_DBLK_CFG2, ((height & 0xffff)<<16) | (width & 0xffff)); if (dw_mode & 0x10) @@ -1590,7 +1601,7 @@ } /*Reset SAO + Enable SAO slice_start*/ - if (hw->mmu_enable && get_cpu_major_id() >= MESON_CPU_MAJOR_ID_G12A) + if (hw->mmu_enable && get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) WRITE_VREG(HEVC_DBLK_CFG0, 0x1); // reset buffer32x4 in lpf for every picture WRITE_VREG(HEVC_SAO_INT_STATUS, READ_VREG(HEVC_SAO_INT_STATUS) | 0x1 << 28); @@ -1599,7 +1610,7 @@ /*pr_info("hevc_sao_set_pic_buffer:mc_y_adr: %x\n", mc_y_adr);*/ /*Send coommand to hevc-code to supply 4k buffers to sao*/ - if (get_cpu_major_id() < MESON_CPU_MAJOR_ID_G12A) { + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_G12A) { WRITE_VREG(H265_SAO_4K_SET_BASE, (u32)hw->frame_mmu_map_phy_addr); WRITE_VREG(H265_SAO_4K_SET_COUNT, MAX_FRAME_4K_NUM); } else @@ -1674,7 +1685,7 @@ } timeout = jiffies + HZ; if ((hw->frame_busy == 1) && (hw->frame_done == 1) ) { - if (get_cpu_major_id() < MESON_CPU_MAJOR_ID_G12A) { + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_G12A) { WRITE_VREG(SYS_COMMAND, H265_ABORT_SAO_4K_SET); while ((READ_VREG(SYS_COMMAND) & 0xff) != H265_ABORT_SAO_4K_SET_DONE) { @@ -1724,7 +1735,8 @@ vf->index = -1; } } - if (buffer_reset_flag) { + /* buffers are alloced when error reset, v4l must find buffer by buffer_wrap[] */ + if (hw->reset_bufmgr_flag && buffer_reset_flag) { for (i = 0; i < BUFSPEC_POOL_SIZE; i++) { if (hw->buffer_spec[i].used == 1 || hw->buffer_spec[i].used == 2) hw->buffer_spec[i].used = 0; @@ -1743,6 +1755,7 @@ spin_unlock_irqrestore(&hw->bufspec_lock, flags); } + /*is active in buf management */ static unsigned char is_buf_spec_in_use(struct vdec_h264_hw_s *hw, int buf_spec_num) @@ -1786,137 +1799,142 @@ buf_size += (hw->mb_total << 7) + (hw->mb_total << 6); else if (IS_VDEC_DW(hw) == 2) buf_size += (hw->mb_total << 6) + (hw->mb_total << 5); + else if (IS_VDEC_DW(hw) == 4) + buf_size += (hw->mb_total << 4) + (hw->mb_total << 3); + else if (IS_VDEC_DW(hw) == 8) + buf_size += (hw->mb_total << 2) + (hw->mb_total << 1); + if (IS_VDEC_DW(hw)) { + u32 align_size; + /* add align padding size for blk64x32: (mb_w<<4)*32, (mb_h<<4)*64 */ + align_size = ((hw->mb_width << 9) + (hw->mb_height << 10)) / IS_VDEC_DW(hw); + /* double align padding size for uv*/ + align_size <<= 1; + buf_size += align_size + PAGE_SIZE; + } #endif if (hw->buffer_spec[i].cma_alloc_addr) return 0; - if (decoder_bmmu_box_alloc_buf_phy(hw->bmmu_box, i, - PAGE_ALIGN(buf_size), DRIVER_NAME, - &hw->buffer_spec[i].cma_alloc_addr) < 0) { - hw->buffer_spec[i].cma_alloc_addr = 0; - if (hw->no_mem_count++ > 3) { - hw->stat |= DECODER_FATAL_ERROR_NO_MEM; - hw->reset_bufmgr_flag = 1; - } - dpb_print(DECODE_ID(hw), 0, - "%s, fail to alloc buf for bufspec%d, try later\n", - __func__, i - ); - return -1; - } else { - hw->no_mem_count = 0; - hw->stat &= ~DECODER_FATAL_ERROR_NO_MEM; - } - if (!vdec_secure(vdec)) { - /*init internal buf*/ - char *tmpbuf = (char *)codec_mm_phys_to_virt(hw->buffer_spec[i].cma_alloc_addr); - if (tmpbuf) { - memset(tmpbuf, 0, PAGE_ALIGN(buf_size)); - codec_mm_dma_flush(tmpbuf, - PAGE_ALIGN(buf_size), - DMA_TO_DEVICE); + if (decoder_bmmu_box_alloc_buf_phy(hw->bmmu_box, i, + PAGE_ALIGN(buf_size), DRIVER_NAME, + &hw->buffer_spec[i].cma_alloc_addr) < 0) { + hw->buffer_spec[i].cma_alloc_addr = 0; + if (hw->no_mem_count++ > 3) { + hw->stat |= DECODER_FATAL_ERROR_NO_MEM; + hw->reset_bufmgr_flag = 1; + } + dpb_print(DECODE_ID(hw), 0, + "%s, fail to alloc buf for bufspec%d, try later\n", + __func__, i + ); + return -1; } else { - tmpbuf = codec_mm_vmap(hw->buffer_spec[i].cma_alloc_addr, PAGE_ALIGN(buf_size)); + if (hw->enable_fence) { + vdec_fence_buffer_count_increase((ulong)vdec->sync); + INIT_LIST_HEAD(&vdec->sync->release_callback[i].node); + decoder_bmmu_box_add_callback_func(hw->bmmu_box, i, (void *)&vdec->sync->release_callback[i]); + } + hw->no_mem_count = 0; + hw->stat &= ~DECODER_FATAL_ERROR_NO_MEM; + } + if (!vdec_secure(vdec)) { + /*init internal buf*/ + char *tmpbuf = (char *)codec_mm_phys_to_virt(hw->buffer_spec[i].cma_alloc_addr); if (tmpbuf) { memset(tmpbuf, 0, PAGE_ALIGN(buf_size)); codec_mm_dma_flush(tmpbuf, PAGE_ALIGN(buf_size), DMA_TO_DEVICE); - codec_mm_unmap_phyaddr(tmpbuf); + } else { + tmpbuf = codec_mm_vmap(hw->buffer_spec[i].cma_alloc_addr, PAGE_ALIGN(buf_size)); + if (tmpbuf) { + memset(tmpbuf, 0, PAGE_ALIGN(buf_size)); + codec_mm_dma_flush(tmpbuf, + PAGE_ALIGN(buf_size), + DMA_TO_DEVICE); + codec_mm_unmap_phyaddr(tmpbuf); + } } } - } - hw->buffer_spec[i].buf_adr = - hw->buffer_spec[i].cma_alloc_addr; - addr = hw->buffer_spec[i].buf_adr; + hw->buffer_spec[i].buf_adr = + hw->buffer_spec[i].cma_alloc_addr; + addr = hw->buffer_spec[i].buf_adr; - hw->buffer_spec[i].y_addr = addr; - addr += hw->mb_total << 8; - hw->buffer_spec[i].u_addr = addr; - hw->buffer_spec[i].v_addr = addr; - addr += hw->mb_total << 7; - - hw->buffer_spec[i].canvas_config[0].phy_addr = - hw->buffer_spec[i].y_addr; - hw->buffer_spec[i].canvas_config[0].width = - hw->mb_width << 4; - hw->buffer_spec[i].canvas_config[0].height = - hw->mb_height << 4; - hw->buffer_spec[i].canvas_config[0].block_mode = - hw->canvas_mode; - - hw->buffer_spec[i].canvas_config[1].phy_addr = - hw->buffer_spec[i].u_addr; - hw->buffer_spec[i].canvas_config[1].width = - hw->mb_width << 4; - hw->buffer_spec[i].canvas_config[1].height = - hw->mb_height << 3; - hw->buffer_spec[i].canvas_config[1].block_mode = - hw->canvas_mode; - dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, - "%s, alloc buf for bufspec%d\n", - __func__, i - ); -#ifdef VDEC_DW - - if (!IS_VDEC_DW(hw)) - return 0; - else if (IS_VDEC_DW(hw) == 1) { - addr = hw->buffer_spec[i].cma_alloc_addr + orig_buf_size; - hw->buffer_spec[i].vdec_dw_y_addr = addr; + hw->buffer_spec[i].y_addr = addr; + addr += hw->mb_total << 8; + hw->buffer_spec[i].u_addr = addr; + hw->buffer_spec[i].v_addr = addr; addr += hw->mb_total << 7; - hw->buffer_spec[i].vdec_dw_u_addr = addr; - hw->buffer_spec[i].vdec_dw_v_addr = addr; - addr += hw->mb_total << 6; - hw->buffer_spec[i].vdec_dw_canvas_config[0].phy_addr = - hw->buffer_spec[i].vdec_dw_y_addr; - hw->buffer_spec[i].vdec_dw_canvas_config[0].width = - hw->mb_width << 3; - hw->buffer_spec[i].vdec_dw_canvas_config[0].height = + hw->buffer_spec[i].canvas_config[0].phy_addr = + hw->buffer_spec[i].y_addr; + hw->buffer_spec[i].canvas_config[0].width = + hw->mb_width << 4; + hw->buffer_spec[i].canvas_config[0].height = hw->mb_height << 4; - hw->buffer_spec[i].vdec_dw_canvas_config[0].block_mode = - CANVAS_BLKMODE_32X32; + hw->buffer_spec[i].canvas_config[0].block_mode = + hw->canvas_mode; - hw->buffer_spec[i].vdec_dw_canvas_config[1].phy_addr = - hw->buffer_spec[i].vdec_dw_u_addr; - hw->buffer_spec[i].vdec_dw_canvas_config[1].width = - hw->mb_width << 3; - hw->buffer_spec[i].vdec_dw_canvas_config[1].height = + hw->buffer_spec[i].canvas_config[1].phy_addr = + hw->buffer_spec[i].u_addr; + hw->buffer_spec[i].canvas_config[1].width = + hw->mb_width << 4; + hw->buffer_spec[i].canvas_config[1].height = hw->mb_height << 3; - hw->buffer_spec[i].vdec_dw_canvas_config[1].block_mode = - CANVAS_BLKMODE_32X32; - }else { - addr = hw->buffer_spec[i].cma_alloc_addr + orig_buf_size; - hw->buffer_spec[i].vdec_dw_y_addr = addr; - addr += hw->mb_total << 6; - hw->buffer_spec[i].vdec_dw_u_addr = addr; - hw->buffer_spec[i].vdec_dw_v_addr = addr; - addr += hw->mb_total << 5; + hw->buffer_spec[i].canvas_config[1].block_mode = + hw->canvas_mode; + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s, alloc buf for bufspec%d\n", + __func__, i); +#ifdef VDEC_DW + if (!IS_VDEC_DW(hw)) + return 0; + else { + int w_shift = 3, h_shift = 3; - hw->buffer_spec[i].vdec_dw_canvas_config[0].phy_addr = - hw->buffer_spec[i].vdec_dw_y_addr; - hw->buffer_spec[i].vdec_dw_canvas_config[0].width = - hw->mb_width << 3; - hw->buffer_spec[i].vdec_dw_canvas_config[0].height = - hw->mb_height << 3; - hw->buffer_spec[i].vdec_dw_canvas_config[0].block_mode = - CANVAS_BLKMODE_32X32; + if (IS_VDEC_DW(hw) == 1) { + w_shift = 3; + h_shift = 4; + } else if (IS_VDEC_DW(hw) == 2) { + w_shift = 3; + h_shift = 3; + } else if (IS_VDEC_DW(hw) == 4) { + w_shift = 2; + h_shift = 2; + } else if (IS_VDEC_DW(hw) == 8) { + w_shift = 1; + h_shift = 1; + } - hw->buffer_spec[i].vdec_dw_canvas_config[1].phy_addr = + addr = hw->buffer_spec[i].cma_alloc_addr + PAGE_ALIGN(orig_buf_size); + hw->buffer_spec[i].vdec_dw_y_addr = addr; + addr += ALIGN_WIDTH(hw->mb_width << w_shift) * ALIGN_HEIGHT(hw->mb_height << h_shift); + hw->buffer_spec[i].vdec_dw_u_addr = addr; + hw->buffer_spec[i].vdec_dw_v_addr = addr; + addr += hw->mb_total << (w_shift + h_shift - 1); + + hw->buffer_spec[i].vdec_dw_canvas_config[0].phy_addr = + hw->buffer_spec[i].vdec_dw_y_addr; + hw->buffer_spec[i].vdec_dw_canvas_config[0].width = + ALIGN_WIDTH(hw->mb_width << w_shift); + hw->buffer_spec[i].vdec_dw_canvas_config[0].height = + ALIGN_HEIGHT(hw->mb_height << h_shift); + hw->buffer_spec[i].vdec_dw_canvas_config[0].block_mode = + hw->canvas_mode; + + hw->buffer_spec[i].vdec_dw_canvas_config[1].phy_addr = hw->buffer_spec[i].vdec_dw_u_addr; - hw->buffer_spec[i].vdec_dw_canvas_config[1].width = - hw->mb_width << 3; - hw->buffer_spec[i].vdec_dw_canvas_config[1].height = - hw->mb_height << 2; - hw->buffer_spec[i].vdec_dw_canvas_config[1].block_mode = - CANVAS_BLKMODE_32X32; - } - dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, - "%s, vdec_dw: alloc buf for bufspec%d\n", - __func__, i - ); + hw->buffer_spec[i].vdec_dw_canvas_config[1].width = + ALIGN_WIDTH(hw->mb_width << w_shift); + hw->buffer_spec[i].vdec_dw_canvas_config[1].height = + ALIGN_HEIGHT(hw->mb_height << (h_shift - 1)); + hw->buffer_spec[i].vdec_dw_canvas_config[1].block_mode = + hw->canvas_mode; + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s, vdec_dw: alloc buf for bufspec%d blkmod %d\n", + __func__, i, hw->canvas_mode); + } #endif } return 0; @@ -1946,7 +1964,7 @@ ctx->id, __func__, (hw->mb_total << 8) + (hw->mb_total << 7)); - ret = vdec_v4l_get_buffer(hw->v4l2_ctx, &fb); + ret = ctx->fb_ops.alloc(&ctx->fb_ops, hw->fb_token, &fb, AML_FB_REQ_DEC); if (ret < 0) { dpb_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL, "[%d] get fb fail.\n", ctx->id); @@ -1955,7 +1973,7 @@ bs->cma_alloc_addr = (unsigned long)fb; dpb_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL, - "[%d] %s(), cma alloc addr: 0x%lx, out %d dec %d\n", + "[%d] %s(), cma alloc addr: 0x%x, out %d dec %d\n", ctx->id, __func__, bs->cma_alloc_addr, ctx->cap_pool.out, ctx->cap_pool.dec); @@ -1970,6 +1988,8 @@ fb->m.mem[1].bytes_used = fb->m.mem[1].size; } + fb->status = FB_ST_DECODER; + dpb_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL, "[%d] %s(), y_addr: %x, size: %u\n", ctx->id, __func__, y_addr, fb->m.mem[0].size); @@ -2023,14 +2043,15 @@ if (hw->is_used_v4l) endian = 7; - canvas_config_ex(hw->buffer_spec[i]. + config_cav_lut_ex(hw->buffer_spec[i]. y_canvas_index, hw->buffer_spec[i].y_addr, hw->mb_width << 4, hw->mb_height << 4, CANVAS_ADDR_NOWRAP, blkmode, - endian); + endian, + VDEC_1); if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { WRITE_VREG(VDEC_ASSIST_CANVAS_BLK32, @@ -2041,14 +2062,15 @@ ); } - canvas_config_ex(hw->buffer_spec[i]. + config_cav_lut_ex(hw->buffer_spec[i]. u_canvas_index, hw->buffer_spec[i].u_addr, hw->mb_width << 4, hw->mb_height << 3, CANVAS_ADDR_NOWRAP, blkmode, - endian); + endian, + VDEC_1); if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { WRITE_VREG(VDEC_ASSIST_CANVAS_BLK32, @@ -2065,46 +2087,16 @@ #ifdef VDEC_DW if (!IS_VDEC_DW(hw)) return; - else if (IS_VDEC_DW(hw) == 1) { - canvas_config_ex(hw->buffer_spec[i]. + else { + config_cav_lut_ex(hw->buffer_spec[i]. vdec_dw_y_canvas_index, - hw->buffer_spec[i].vdec_dw_y_addr, - hw->mb_width << 3, - hw->mb_height << 4, + hw->buffer_spec[i].vdec_dw_canvas_config[0].phy_addr, + hw->buffer_spec[i].vdec_dw_canvas_config[0].width, + hw->buffer_spec[i].vdec_dw_canvas_config[0].height, CANVAS_ADDR_NOWRAP, blkmode, - endian); - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { - WRITE_VREG(VDEC_ASSIST_CANVAS_BLK32, - (1 << 11) | - (blkmode << 10) | - (1 << 8) | - (hw->buffer_spec[i].vdec_dw_y_canvas_index << 0)); - } - canvas_config_ex(hw->buffer_spec[i]. - vdec_dw_u_canvas_index, - hw->buffer_spec[i].vdec_dw_u_addr, - hw->mb_width << 3, - hw->mb_height << 3, - CANVAS_ADDR_NOWRAP, - blkmode, - endian); - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { - WRITE_VREG(VDEC_ASSIST_CANVAS_BLK32, - (1 << 11) | - (blkmode << 10) | - (1 << 8) | - (hw->buffer_spec[i].vdec_dw_u_canvas_index << 0)); - } - } else { - canvas_config_ex(hw->buffer_spec[i]. - vdec_dw_y_canvas_index, - hw->buffer_spec[i].vdec_dw_y_addr, - hw->mb_width << 3, - hw->mb_height << 3, - CANVAS_ADDR_NOWRAP, - blkmode, - endian); + endian, + VDEC_1); if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { WRITE_VREG(VDEC_ASSIST_CANVAS_BLK32, (1 << 11) | @@ -2113,14 +2105,15 @@ (hw->buffer_spec[i].vdec_dw_y_canvas_index << 0)); } - canvas_config_ex(hw->buffer_spec[i]. + config_cav_lut_ex(hw->buffer_spec[i]. vdec_dw_u_canvas_index, - hw->buffer_spec[i].vdec_dw_u_addr, - hw->mb_width << 3, - hw->mb_height << 2, + hw->buffer_spec[i].vdec_dw_canvas_config[1].phy_addr, + hw->buffer_spec[i].vdec_dw_canvas_config[1].width, + hw->buffer_spec[i].vdec_dw_canvas_config[1].height, CANVAS_ADDR_NOWRAP, blkmode, - endian); + endian, + VDEC_1); if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { WRITE_VREG(VDEC_ASSIST_CANVAS_BLK32, (1 << 11) | @@ -2139,9 +2132,9 @@ int canvas_h; canvas_w = hw->frame_width / - get_double_write_ratio(hw); + get_double_write_ratio(hw->double_write_mode); canvas_h = hw->frame_height / - get_double_write_ratio(hw); + get_double_write_ratio(hw->double_write_mode); if (hw->canvas_mode == 0) canvas_w = ALIGN(canvas_w, 32); @@ -2149,26 +2142,27 @@ canvas_w = ALIGN(canvas_w, 64); canvas_h = ALIGN(canvas_h, 32); - canvas_config_ex(hw->buffer_spec[i]. + config_cav_lut_ex(hw->buffer_spec[i]. y_canvas_index, hw->buffer_spec[i].dw_y_adr, canvas_w, canvas_h, CANVAS_ADDR_NOWRAP, blkmode, - 7); + 7, + VDEC_HEVC); - canvas_config_ex(hw->buffer_spec[i]. + config_cav_lut_ex(hw->buffer_spec[i]. u_canvas_index, hw->buffer_spec[i].dw_u_v_adr, canvas_w, canvas_h, CANVAS_ADDR_NOWRAP, blkmode, - 7); + 7, + VDEC_HEVC); } - static int v4l_get_free_buffer_spec(struct vdec_h264_hw_s *hw) { int i; @@ -2200,7 +2194,7 @@ struct buffer_spec_s *pic = NULL; int i, rt, idx = INVALID_IDX; ulong flags; - u32 state, index; + u32 state = 0, index; spin_lock_irqsave(&hw->bufspec_lock, flags); for (i = 0; i < pool->in; ++i) { @@ -2233,7 +2227,6 @@ } break; default: - pr_err("v4l buffer state err %d.\n", state); break; } @@ -2245,12 +2238,17 @@ spin_unlock_irqrestore(&hw->bufspec_lock, flags); if (idx < 0) { - dpb_print(DECODE_ID(hw), 0, "%s fail\n", __func__); + dpb_print(DECODE_ID(hw), 0, "%s fail, state %d\n", __func__, state); for (i = 0; i < BUFSPEC_POOL_SIZE; i++) { dpb_print(DECODE_ID(hw), 0, "%s, %d\n", __func__, hw->buffer_wrap[i]); } vmh264_dump_state(vdec); + } else { + struct vdec_v4l2_buffer *fb = + (struct vdec_v4l2_buffer *)pic->cma_alloc_addr; + + fb->status = FB_ST_DECODER; } return idx; @@ -2301,6 +2299,7 @@ } } } + spin_unlock_irqrestore(&hw->bufspec_lock, flags); if (hw->start_search_pos >= buf_total) hw->start_search_pos = 0; @@ -2548,7 +2547,7 @@ int i; unsigned long addr; struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; - struct aml_vcodec_ctx * v4l = hw->v4l2_ctx; + struct aml_vcodec_ctx * ctx = hw->v4l2_ctx; int canvas_pos_min = BUFSPEC_POOL_SIZE; int index = -1; int ret = 0; @@ -2557,6 +2556,10 @@ if (hw->is_used_v4l) { struct h264_dpb_stru *dpb = &hw->dpb; + /* trigger to parse head data. */ + if (!hw->v4l_params_parsed) + return 1; + if (dpb->mDPB.used_size >= dpb->mDPB.size - 1) return 0; @@ -2568,10 +2571,13 @@ } } - if (v4l->cap_pool.dec < hw->dpb.mDPB.size && - v4l2_m2m_num_dst_bufs_ready(v4l->m2m_ctx) - >= run_ready_min_buf_num) - return 1; + if (ctx->cap_pool.dec < hw->dpb.mDPB.size) { + if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) >= + run_ready_min_buf_num) { + if (ctx->fb_ops.query(&ctx->fb_ops, &hw->fb_token)) + return 1; + } + } return 0; } @@ -2654,6 +2660,9 @@ if (vdec_secure(hw_to_vdec(hw))) return 0; + if (hw->i_only) + return 0; + if ((dec_control & DEC_CONTROL_FLAG_FORCE_2997_1080P_INTERLACE) && hw->bitstream_restriction_flag && (hw->frame_width == 1920) @@ -2667,9 +2676,7 @@ && (hw->frame_dur == 3840)) { bForceInterlace = 1; } - if ((frame->frame) && (hw->is_used_v4l) && (bForceInterlace == 0)) { - bForceInterlace = (frame->frame->mb_aff_frame_flag)?1:0; - } + return bForceInterlace; } @@ -2771,23 +2778,22 @@ if (frame->frame == NULL && ((frame->is_used == 1 && frame->top_field) || (frame->is_used == 2 && frame->bottom_field))) { - if (hw->i_only) { - if (frame->is_used == 1) - dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, - "%s No bottom_field !! frame_num %d used %d\n", + if (hw->i_only) { + if (frame->is_used == 1) + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s No bottom_field !! frame_num %d used %d\n", + __func__, frame->frame_num, frame->is_used); + if (frame->is_used == 2) + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s No top_field !! frame_num %d used %d\n", + __func__, frame->frame_num, frame->is_used); + } + else { + frame->data_flag |= ERROR_FLAG; + dpb_print(DECODE_ID(hw), PRINT_FLAG_ERRORFLAG_DBG, + "%s Error frame_num %d used %d\n", __func__, frame->frame_num, frame->is_used); - if (frame->is_used == 2) - dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, - "%s No top_field !! frame_num %d used %d\n", - __func__, frame->frame_num, frame->is_used); - } - else { - frame->data_flag |= ERROR_FLAG; - dpb_print(DECODE_ID(hw), PRINT_FLAG_ERRORFLAG_DBG, - "%s Error frame_num %d used %d\n", - __func__, frame->frame_num, frame->is_used); - } - + } } if (vdec_stream_based(vdec) && !(frame->data_flag & NODISP_FLAG)) { if ((vdec->vbuf.no_parser == 0) || (vdec->vbuf.use_ptsserv)) { @@ -2808,6 +2814,7 @@ hw->wrong_frame_count++; } } + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, "%s error= 0x%x poc = %d offset= 0x%x pts= 0x%x last_pts =0x%x pts64 = %lld last_pts64= %lld duration = %d\n", __func__, (frame->data_flag & ERROR_FLAG), frame->poc, @@ -2866,13 +2873,13 @@ } - if ((frame->data_flag & NODISP_FLAG) || + if ((!hw->enable_fence) && + ((frame->data_flag & NODISP_FLAG) || (frame->data_flag & NULL_FLAG) || ((!hw->send_error_frame_flag) && (frame->data_flag & ERROR_FLAG)) || ((hw->i_only & 0x1) && - (!(frame->data_flag & I_FLAG)))) { - set_frame_output_flag(&hw->dpb, frame->index); + (!(frame->data_flag & I_FLAG))))) { frame->show_frame = false; return 0; } @@ -2901,6 +2908,7 @@ struct vframe_s *vf = NULL; int buffer_index = frame->buf_spec_num; struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx; + struct vdec_v4l2_buffer *fb = NULL; ulong nv_order = VIDTYPE_VIU_NV21; int bForceInterlace = 0; int vf_count = 1; @@ -2921,12 +2929,15 @@ bForceInterlace = check_force_interlace(hw, frame); if (bForceInterlace) vf_count = 2; - if (hw->is_used_v4l) - vf_count = 1; + if (!hw->enable_fence) hw->buffer_spec[buffer_index].vf_ref = 0; fill_frame_info(hw, frame); + if ((hw->is_used_v4l) && + (vdec->prog_only)) + vf_count = 1; + for (i = 0; i < vf_count; i++) { if (kfifo_get(&hw->newframe_q, &vf) == 0 || vf == NULL) { @@ -2951,6 +2962,7 @@ if (hw->is_used_v4l) { vf->v4l_mem_handle = hw->buffer_spec[buffer_index].cma_alloc_addr; + fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; } if (hw->enable_fence) { @@ -3016,9 +3028,14 @@ vf->canvas0Addr = vf->canvas1Addr = spec2canvas(&hw->buffer_spec[buffer_index]); #ifdef VDEC_DW - if (IS_VDEC_DW(hw)) - vf->canvas0Addr = vf->canvas1Addr = - vdec_dw_spec2canvas(&hw->buffer_spec[buffer_index]); + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_T7) { + if (IS_VDEC_DW(hw)) + vf->canvas0Addr = vf->canvas1Addr = + vdec_dw_spec2canvas(&hw->buffer_spec[buffer_index]); + } else { + if (IS_VDEC_DW(hw)) + vf->canvas0Addr = vf->canvas1Addr = -1; + } #endif } @@ -3029,9 +3046,17 @@ if (hw->mmu_enable && hw->double_write_mode) { vf->width = hw->frame_width / - get_double_write_ratio(hw); + get_double_write_ratio(hw->double_write_mode); vf->height = hw->frame_height / - get_double_write_ratio(hw); + get_double_write_ratio(hw->double_write_mode); + } + + if (frame->slice_type == I_SLICE) { + vf->frame_type |= V4L2_BUF_FLAG_KEYFRAME; + } else if (frame->slice_type == P_SLICE) { + vf->frame_type |= V4L2_BUF_FLAG_PFRAME; + } else if (frame->slice_type == B_SLICE) { + vf->frame_type |= V4L2_BUF_FLAG_BFRAME; } vf->flag = 0; @@ -3122,21 +3147,6 @@ } } - if (i == 0) { - struct vdec_s *pvdec; - struct vdec_info vs; - - pvdec = hw_to_vdec(hw); - memset(&vs, 0, sizeof(struct vdec_info)); - pvdec->dec_status(pvdec, &vs); - decoder_do_frame_check(pvdec, vf); - vdec_fill_vdec_frame(pvdec, &hw->vframe_qos, &vs, vf, frame->hw_decode_time); - - dpb_print(DECODE_ID(hw), PRINT_FLAG_DPB_DETAIL, - "[%s:%d] i_decoded_frame = %d p_decoded_frame = %d b_decoded_frame = %d\n", - __func__, __LINE__,vs.i_decoded_frames,vs.p_decoded_frames,vs.b_decoded_frames); - } - /*vf->ratio_control |= (0x3FF << DISP_RATIO_ASPECT_RATIO_BIT);*/ vf->sar_width = hw->width_aspect_ratio; vf->sar_height = hw->height_aspect_ratio; @@ -3152,26 +3162,73 @@ vf->pts = 0; } } + + hw->vf_pre_count++; vdec_vframe_ready(hw_to_vdec(hw), vf); + if (!frame->show_frame) { + vh264_vf_put(vf, vdec); + atomic_add(1, &hw->vf_get_count); + continue; + } + + if (i == 0) { + struct vdec_s *pvdec; + struct vdec_info vs; + + pvdec = hw_to_vdec(hw); + memset(&vs, 0, sizeof(struct vdec_info)); + pvdec->dec_status(pvdec, &vs); + decoder_do_frame_check(pvdec, vf); + vdec_fill_vdec_frame(pvdec, &hw->vframe_qos, &vs, vf, frame->hw_decode_time); + + dpb_print(DECODE_ID(hw), PRINT_FLAG_DPB_DETAIL, + "[%s:%d] i_decoded_frame = %d p_decoded_frame = %d b_decoded_frame = %d\n", + __func__, __LINE__,vs.i_decoded_frames,vs.p_decoded_frames,vs.b_decoded_frames); + } + kfifo_put(&hw->display_q, (const struct vframe_s *)vf); - ATRACE_COUNTER(hw->pts_name, vf->pts); - ATRACE_COUNTER(hw->disp_q_name, kfifo_len(&hw->display_q)); - ATRACE_COUNTER(hw->new_q_name, kfifo_len(&hw->newframe_q)); + ATRACE_COUNTER(hw->trace.pts_name, vf->pts); + ATRACE_COUNTER(hw->trace.disp_q_name, kfifo_len(&hw->display_q)); + ATRACE_COUNTER(hw->trace.new_q_name, kfifo_len(&hw->newframe_q)); hw->vf_pre_count++; vdec->vdec_fps_detec(vdec->id); #ifdef AUX_DATA_CRC decoder_do_aux_data_check(vdec, hw->buffer_spec[buffer_index].aux_data_buf, hw->buffer_spec[buffer_index].aux_data_size); #endif - if (hw->is_used_v4l) + + dpb_print(DECODE_ID(hw), PRINT_FLAG_SEI_DETAIL, "aux_data_size: %d, signal_type: 0x%x\n", + hw->buffer_spec[buffer_index].aux_data_size, hw->video_signal_type); + + if (dpb_is_debug(DECODE_ID(hw), PRINT_FLAG_SEI_DETAIL)) { + int i = 0; + PR_INIT(128); + + for (i = 0; i < hw->buffer_spec[buffer_index].aux_data_size; i++) { + PR_FILL("%02x ", hw->buffer_spec[buffer_index].aux_data_buf[i]); + if (((i + 1) & 0xf) == 0) + PR_INFO(hw->id); + } + PR_INFO(hw->id); + } + + if (hw->is_used_v4l) { update_vframe_src_fmt(vf, hw->buffer_spec[buffer_index].aux_data_buf, hw->buffer_spec[buffer_index].aux_data_size, false, vdec->vf_provider_name, NULL); + } if (without_display_mode == 0) { - vf_notify_receiver(vdec->vf_provider_name, - VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + if (hw->is_used_v4l) { + if (v4l2_ctx->is_stream_off) { + vh264_vf_put(vh264_vf_get(vdec), vdec); + } else { + fb->task->submit(fb->task, TASK_TYPE_DEC); + } + } else + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); } else vh264_vf_put(vh264_vf_get(vdec), vdec); } @@ -3193,13 +3250,13 @@ return 0; /* create fence for each buffers. */ - if (vdec_timeline_create_fence(&vdec->sync)) + if (vdec_timeline_create_fence(vdec->sync)) return -1; memset(&fs, 0, sizeof(fs)); fs.buf_spec_num = index; - fs.fence = vdec->sync.fence; + fs.fence = vdec->sync->fence; fs.slice_type = dpb_stru->mSlice.slice_type; fs.dpb_frame_count = dpb_stru->dpb_frame_count; @@ -3212,7 +3269,7 @@ fs.pts64 = hw->chunk->pts64; fs.timestamp = hw->chunk->timestamp; } - + fs.show_frame = true; post_video_frame(vdec, &fs); display_frame_count[DECODE_ID(hw)]++; @@ -3225,6 +3282,10 @@ (struct vdec_h264_hw_s *)vdec->private; if (hw->enable_fence) { + int i, j, used_size, ret; + int signed_count = 0; + struct vframe_s *signed_fence[VF_POOL_SIZE]; + post_prepare_process(vdec, frame); if (!frame->show_frame) @@ -3235,16 +3296,36 @@ hw->buffer_spec[frame->buf_spec_num].fs_idx = frame->index; /* notify signal to wake up wq of fence. */ - vdec_timeline_increase(&vdec->sync, 1); + vdec_timeline_increase(vdec->sync, 1); + + mutex_lock(&hw->fence_mutex); + used_size = hw->fence_vf_s.used_size; + if (used_size) { + for (i = 0, j = 0; i < VF_POOL_SIZE && j < used_size; i++) { + if (hw->fence_vf_s.fence_vf[i] != NULL) { + ret = dma_fence_get_status(hw->fence_vf_s.fence_vf[i]->fence); + if (ret == 1) { + signed_fence[signed_count] = hw->fence_vf_s.fence_vf[i]; + hw->fence_vf_s.fence_vf[i] = NULL; + hw->fence_vf_s.used_size--; + signed_count++; + } + j++; + } + } + } + mutex_unlock(&hw->fence_mutex); + if (signed_count != 0) { + for (i = 0; i < signed_count; i++) + vh264_vf_put(signed_fence[i], vdec); + } + return 0; } if (post_prepare_process(vdec, frame)) return -1; - if (!frame->show_frame) - return 0; - if (post_video_frame(vdec, frame)) return -1; @@ -3271,7 +3352,8 @@ } if (index == INVALID_IDX) { - if (vdec_v4l_get_buffer(hw->v4l2_ctx, &fb) < 0) { + ctx->fb_ops.query(&ctx->fb_ops, &hw->fb_token); + if (ctx->fb_ops.alloc(&ctx->fb_ops, hw->fb_token, &fb, AML_FB_REQ_DEC) < 0) { pr_err("[%d] EOS get free buff fail.\n", ctx->id); return -1; } @@ -3283,12 +3365,18 @@ vf->flag = VFRAME_FLAG_EMPTY_FRAME_V4L; vf->v4l_mem_handle = (index == INVALID_IDX) ? (ulong)fb : hw->buffer_spec[index].cma_alloc_addr; + fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; vdec_vframe_ready(vdec, vf); kfifo_put(&hw->display_q, (const struct vframe_s *)vf); - ATRACE_COUNTER(hw->pts_name, vf->pts); - vf_notify_receiver(vdec->vf_provider_name, - VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + + ATRACE_COUNTER(hw->trace.pts_name, vf->pts); + + if (hw->is_used_v4l) + fb->task->submit(fb->task, TASK_TYPE_DEC); + else + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); pr_info("[%d] H264 EOS notify.\n", (hw->is_used_v4l)?ctx->id:vdec->id); } @@ -3395,7 +3483,7 @@ hw_buf->prefix_aux_size; } if (dpb_is_debug(DECODE_ID(hw), - PRINT_FLAG_DEC_DETAIL)) { + PRINT_FLAG_SEI_DETAIL)) { dpb_print(DECODE_ID(hw), 0, "%s:poc %d old size %d count %d,suf %d dv_flag %d\r\n", __func__, pic->poc, AUX_DATA_SIZE(pic), @@ -3494,7 +3582,7 @@ h[7] = (padding_len) & 0xff; } if (dpb_is_debug(DECODE_ID(hw), - PRINT_FLAG_DEC_DETAIL)) { + PRINT_FLAG_SEI_DETAIL)) { dpb_print(DECODE_ID(hw), 0, "aux: (size %d) suffix_flag %d\n", AUX_DATA_SIZE(pic), suffix_flag); @@ -3574,6 +3662,98 @@ } } +#ifdef VDEC_DW + +struct vdec_dw_param_set{ + char dw_x_shrink_1st; + char dw_x_shrink_2nd; + char dw_x_shrink_3rd; + char dw_y_shrink_1st; + char dw_y_shrink_2nd; + char dw_y_shrink_3rd; + char dw_merge_8to16; + char dw_merge_16to32; + char dw_dma_blk_mode; + char dw_bwsave_mode; +}; +//#define FOR_LPDDR4_EFFICIENCY + +static void h264_vdec_dw_cfg(struct vdec_h264_hw_s *hw, int canvas_pos) +{ + u32 data32 = 0, stride = 0; + struct vdec_dw_param_set *p = NULL; + struct vdec_dw_param_set dw_param_set_pool[] = { + /*x1, x2, x3, y1, y2, y3, m8t6, m16to32 */ + //{0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, /* 1/1, 1/1 */ + {1, 0, 0, 0, 0, 0, 0, 0, 0, 1}, /* 1/2, 1/1 */ + {1, 0, 0, 1, 0, 0, 0, 0, 0, 1}, /* 1/2, 1/2 */ + //{1, 0, 0, 1, 1, 0, 0, 0, 0, 1}, /* 1/4, 1/2 */ + {2, 0, 1, 1, 3, 0, 0, 1, 0, 1}, /* 1/4, 1/4 */ + //{1, 1, 1, 0, 1, 1, 1, 1, 0, 1}, /*> 1080p 1/8, 1/4 */ + {1, 1, 1, 1, 1, 1, 1, 1, 0, 1}, /*> 1080p 1/8, 1/8 */ + }; + + if (IS_VDEC_DW(hw)) + p = &dw_param_set_pool[__ffs(IS_VDEC_DW(hw))]; + else + return; + + WRITE_VREG(MDEC_DOUBLEW_CFG3, + hw->buffer_spec[canvas_pos].vdec_dw_y_addr); // luma start address + WRITE_VREG(MDEC_DOUBLEW_CFG4, + hw->buffer_spec[canvas_pos].vdec_dw_u_addr); // chroma start address + + stride = ALIGN_WIDTH((hw->mb_width << 4) / (IS_VDEC_DW(hw))); + if ((IS_VDEC_DW(hw)) == 1) //width 1/2 + stride >>= 1; + data32 = (stride << 16) | stride; + WRITE_VREG(MDEC_DOUBLEW_CFG5, data32); // chroma stride | luma stride + + data32 = 0; + p->dw_dma_blk_mode = hw->canvas_mode; + data32 |= ((p->dw_x_shrink_1st << 0 ) | // 1st down-scale horizontal, 00:no-scale 01:1/2avg 10:left 11:right + (p->dw_y_shrink_1st << 2 ) | // 1st down-scale vertical, 00:no-scale 01:1/2avg 10:up 11:down + (p->dw_x_shrink_2nd << 4 ) | // 2nd down-scale horizontal, 00:no-scale 01:1/2avg 10:left 11:right + (p->dw_y_shrink_2nd << 6 ) | // 2nd down-scale vertical, 00:no-scale 01:1/2avg 10:up 11:down + (p->dw_x_shrink_3rd << 8 ) | // 3rd down-scale horizontal, 00:no-scale 01:1/2avg 10:left 11:right + (p->dw_y_shrink_3rd << 10) | // 3rd down-scale vertical, 00:no-scale 01:1/2avg 10:up 11:down + (p->dw_merge_8to16 << 12 ) | // 8->16 horizontal block merge for better ddr efficiency + (p->dw_merge_16to32 << 13) | // 16->32 horizontal block merge for better ddr efficiency + (p->dw_dma_blk_mode << 14) | // DMA block mode, 0:linear 1:32x32 2:64x32 +#ifdef FOR_LPDDR4_EFFICIENCY + (1 << 19) | +#endif + (p->dw_bwsave_mode << 22)); // Save line buffers to save band width + WRITE_VREG(MDEC_DOUBLEW_CFG1, data32); // add some special tests here + + data32 = 0; + data32 |= (1 << 0) | (0 << 27); + WRITE_VREG(MDEC_DOUBLEW_CFG0, data32); // Double Write Enable | source from dblk + + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "vdec_double_write mode %d\n", + IS_VDEC_DW(hw)); + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "param {%d, %d, %d, %d, %d, %d, %d, %d, %d}\n", + p->dw_x_shrink_1st, + p->dw_y_shrink_1st, + p->dw_x_shrink_2nd, + p->dw_y_shrink_2nd, + p->dw_x_shrink_3rd, + p->dw_y_shrink_3rd, + p->dw_merge_8to16, + p->dw_merge_16to32, + p->dw_dma_blk_mode); + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "cfg0,1,3,4,5 = {%x, %x, %x, %x, %x}\n", + READ_VREG(MDEC_DOUBLEW_CFG0), + READ_VREG(MDEC_DOUBLEW_CFG1), + READ_VREG(MDEC_DOUBLEW_CFG3), + READ_VREG(MDEC_DOUBLEW_CFG4), + READ_VREG(MDEC_DOUBLEW_CFG5)); +} +#endif + static void config_decode_mode(struct vdec_h264_hw_s *hw) { #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION @@ -3604,6 +3784,7 @@ else WRITE_VREG(INIT_FLAG_REG, 1); } + int config_decode_buf(struct vdec_h264_hw_s *hw, struct StorablePicture *pic) { /* static int count = 0; */ @@ -3665,9 +3846,11 @@ print_pic_info(DECODE_ID(hw), "cur", pic, pSlice->slice_type); #ifdef VDEC_DW - if (IS_VDEC_DW(hw) && pic->mb_aff_frame_flag) - WRITE_VREG(MDEC_DOUBLEW_CFG0, - ( READ_VREG(MDEC_DOUBLEW_CFG0) & (~(1 << 30)))); + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_T7) { + if (IS_VDEC_DW(hw) && pic->mb_aff_frame_flag) + WRITE_VREG(MDEC_DOUBLEW_CFG0, + (READ_VREG(MDEC_DOUBLEW_CFG0) & (~(1 << 30)))); + } #endif WRITE_VREG(CURR_CANVAS_CTRL, canvas_pos << 24); canvas_adr = READ_VREG(CURR_CANVAS_CTRL) & 0xffffff; @@ -3677,9 +3860,13 @@ WRITE_VREG(DBKR_CANVAS_ADDR, canvas_adr); WRITE_VREG(DBKW_CANVAS_ADDR, canvas_adr); #ifdef VDEC_DW - WRITE_VREG(MDEC_DOUBLEW_CFG1, - (hw->buffer_spec[canvas_pos].vdec_dw_y_canvas_index - | (hw->buffer_spec[canvas_pos].vdec_dw_u_canvas_index << 8))); + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_T7) { + WRITE_VREG(MDEC_DOUBLEW_CFG1, + (hw->buffer_spec[canvas_pos].vdec_dw_y_canvas_index | + (hw->buffer_spec[canvas_pos].vdec_dw_u_canvas_index << 8))); + } else { + h264_vdec_dw_cfg(hw, canvas_pos); + } #endif } else hevc_sao_set_pic_buffer(hw, pic); @@ -3999,12 +4186,16 @@ * 00 - top field, 01 - bottom field, * 10 - frame, 11 - mbaff frame */ - int l10_structure; + int l10_structure, cur_structure; int cur_colocate_ref_type; /* H264_CO_MB_RD_ADDR[bit 29], top/bot for B field pciture, * 0 - top, 1 - bot */ unsigned int val; + unsigned int colocate_rd_adr_offset; + unsigned int mby_mbx; + unsigned int mby, mbx; + #ifdef ERROR_CHECK if (colocate_pic == NULL) { hw->data_flag |= ERROR_FLAG; @@ -4030,6 +4221,60 @@ l10_structure = (colocate_pic->structure == BOTTOM_FIELD) ? 1 : 0; } + + //ALLEGRO_FIX, ported from single mode ucode + mby_mbx = READ_VREG(MBY_MBX); + mby = pSlice->first_mb_in_slice / hw->mb_width; + mbx = pSlice->first_mb_in_slice % hw->mb_width; + if (pic->mb_aff_frame_flag) + cur_structure = 3; + else { + if (pic->coded_frame) + cur_structure = 2; + else + cur_structure = (pic->structure == + BOTTOM_FIELD) ? 1 : 0; + } + if (cur_structure < 2) { + //current_field_structure + if (l10_structure != 2) { + colocate_rd_adr_offset = pSlice->first_mb_in_slice * 2; + } else { + // field_ref_from_frame co_mv_rd_addr : + // mby*2*mb_width + mbx + colocate_rd_adr_offset = mby * 2 * hw->mb_width + mbx; + } + + } else { + //current_frame_structure + if (l10_structure < 2) { + //calculate_co_mv_offset_frame_ref_field: + // frame_ref_from_field co_mv_rd_addr : + // (mby/2*mb_width+mbx)*2 + colocate_rd_adr_offset = ((mby / 2) * hw->mb_width + mbx) * 2; + } else if (cur_structure == 2) { + colocate_rd_adr_offset = pSlice->first_mb_in_slice; + } else { + //mbaff frame case1196 + colocate_rd_adr_offset = pSlice->first_mb_in_slice * 2; + } + + } + + colocate_rd_adr_offset *= 96; + if (use_direct_8x8) + colocate_rd_adr_offset >>= 2; + + if (colocate_old_cal) + colocate_rd_adr_offset = colocate_adr_offset; + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "first_mb_in_slice 0x%x 0x%x 0x%x (MBY_MBX reg 0x%x) use_direct_8x8 %d cur %d (mb_aff_frame_flag %d, coded_frame %d structure %d) col %d (mb_aff_frame_flag %d, coded_frame %d structure %d) offset 0x%x rdoffset 0x%x\n", + pSlice->first_mb_in_slice, mby, mbx, mby_mbx, use_direct_8x8, + cur_structure, pic->mb_aff_frame_flag, pic->coded_frame, pic->structure, + l10_structure, colocate_pic->mb_aff_frame_flag, colocate_pic->coded_frame, colocate_pic->structure, + colocate_adr_offset, + colocate_rd_adr_offset); + #if 0 /*case0016, p16, *cur_colocate_ref_type should be configured base on current pic @@ -4089,14 +4334,14 @@ * [2:0] will set to 3'b000 */ /* #define H264_CO_MB_RD_ADDR VLD_C39 0xc39 */ - val = ((colocate_rd_adr+colocate_adr_offset) >> 3) | + val = ((colocate_rd_adr+colocate_rd_adr_offset) >> 3) | (l10_structure << 30) | (cur_colocate_ref_type << 29); WRITE_VREG(H264_CO_MB_RD_ADDR, val); dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, "co idx %d, WRITE_VREG(H264_CO_MB_RD_ADDR) = %x, addr %x L1(0) pic_structure %d mbaff %d\n", colocate_pic->colocated_buf_index, - val, colocate_rd_adr + colocate_adr_offset, + val, colocate_rd_adr + colocate_rd_adr_offset, colocate_pic->structure, colocate_pic->mb_aff_frame_flag); } else { @@ -4128,7 +4373,7 @@ * [2:0] will set to 3'b000 */ /* #define H264_CO_MB_RD_ADDR VLD_C39 0xc39 */ - val = ((colocate_rd_adr+colocate_adr_offset)>>3) | + val = ((colocate_rd_adr+colocate_rd_adr_offset)>>3) | (l10_structure << 30) | (cur_colocate_ref_type << 29); WRITE_VREG(H264_CO_MB_RD_ADDR, val); dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, @@ -4196,14 +4441,12 @@ struct vframe_s *vf; struct vdec_s *vdec = op_arg; struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; - struct aml_vcodec_ctx * v4l2_ctx; + struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx; ulong nv_order = VIDTYPE_VIU_NV21; if (!hw) return NULL; - v4l2_ctx = hw->v4l2_ctx; - /* swap uv */ if (hw->is_used_v4l) { if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12) || @@ -4273,9 +4516,9 @@ if (hw->double_write_mode) { vf->width = hw->frame_width / - get_double_write_ratio(hw); + get_double_write_ratio(hw->double_write_mode); vf->height = hw->frame_height / - get_double_write_ratio(hw); + get_double_write_ratio(hw->double_write_mode); } } else { vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD | @@ -4296,7 +4539,7 @@ unsigned int frame_interval = 1000*(time - hw->last_frame_time)/HZ; struct vframe_s *next_vf = NULL; - ATRACE_COUNTER(hw->disp_q_name, kfifo_len(&hw->display_q)); + ATRACE_COUNTER(hw->trace.disp_q_name, kfifo_len(&hw->display_q)); if (dpb_is_debug(DECODE_ID(hw), PRINT_FLAG_VDEC_DETAIL)) { struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; @@ -4308,10 +4551,10 @@ __func__, vf->index); } else { dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_DETAIL, - "%s buf_spec_num %d vf %p poc %d dur %d pts %d interval %dms\n", + "%s buf_spec_num %d vf %p poc %d dur %d pts %d interval %dms, ts: %lld\n", __func__, BUFSPEC_INDEX(vf->index), vf, p_H264_Dpb->mFrameStore[frame_index].poc, - vf->duration, vf->pts, frame_interval); + vf->duration, vf->pts, frame_interval, vf->timestamp); } } if (hw->last_frame_time > 0) { @@ -4321,13 +4564,14 @@ = frame_interval; } hw->last_frame_time = time; - vf->index_disp = hw->vf_get_count; - hw->vf_get_count++; + vf->index_disp = atomic_read(&hw->vf_get_count); + atomic_add(1, &hw->vf_get_count); if (kfifo_peek(&hw->display_q, &next_vf) && next_vf) { vf->next_vf_pts_valid = true; vf->next_vf_pts = next_vf->pts; } else vf->next_vf_pts_valid = false; + return vf; } @@ -4373,6 +4617,24 @@ return; } + if (hw->enable_fence && vf->fence) { + int ret, i; + + mutex_lock(&hw->fence_mutex); + ret = dma_fence_get_status(vf->fence); + if (ret == 0) { + for (i = 0; i < VF_POOL_SIZE; i++) { + if (hw->fence_vf_s.fence_vf[i] == NULL) { + hw->fence_vf_s.fence_vf[i] = vf; + hw->fence_vf_s.used_size++; + mutex_unlock(&hw->fence_mutex); + return; + } + } + } + mutex_unlock(&hw->fence_mutex); + } + buf_spec_num = BUFSPEC_INDEX(vf->index); if (hw->enable_fence) frame_index = hw->buffer_spec[buf_spec_num].fs_idx; @@ -4428,10 +4690,17 @@ } - hw->vf_put_count++; - if (vf_valid_check(vf, hw) == true) { + if (hw->is_used_v4l) { + struct buffer_spec_s *pic = &hw->buffer_spec[buf_spec_num]; + + if (vf->v4l_mem_handle != pic->cma_alloc_addr) + pic->cma_alloc_addr = vf->v4l_mem_handle; + } + + atomic_add(1, &hw->vf_put_count); + if (vf && (vf_valid_check(vf, hw) == true)) { kfifo_put(&hw->newframe_q, (const struct vframe_s *)vf); - ATRACE_COUNTER(hw->new_q_name, kfifo_len(&hw->newframe_q)); + ATRACE_COUNTER(hw->trace.new_q_name, kfifo_len(&hw->newframe_q)); } #define ASSIST_MBOX1_IRQ_REG VDEC_ASSIST_MBOX1_IRQ_REG @@ -4439,6 +4708,7 @@ WRITE_VREG(ASSIST_MBOX1_IRQ_REG, 0x1); spin_unlock_irqrestore(&hw->bufspec_lock, flags); } + void * vh264_get_bufspec_lock(struct vdec_s *vdec) { struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; @@ -4459,7 +4729,7 @@ int buf_spec_num; if (!req->vf) { - req->aux_size = hw->vf_put_count; + req->aux_size = atomic_read(&hw->vf_put_count); return 0; } buf_spec_num = BUFSPEC_INDEX(req->vf->index); @@ -4522,6 +4792,7 @@ } } else vf->signal_type = 0; + hw->video_signal_type = vf->signal_type; vf->width = hw->frame_width; vf->height = hw->frame_height; @@ -4551,9 +4822,11 @@ #endif if (IS_VDEC_DW(hw)) { - vf->width = (hw->frame_width /2); - if (IS_VDEC_DW(hw) == 2) - vf->height = (hw->frame_height /2); + if (IS_VDEC_DW(hw) == 1) + vf->width = hw->frame_width / 2; + else + vf->width = (hw->frame_width / IS_VDEC_DW(hw)); + vf->height = (hw->frame_height / IS_VDEC_DW(hw)); p_canvas_config = &hw->buffer_spec[index].vdec_dw_canvas_config[0]; } else p_canvas_config = &hw->buffer_spec[index].canvas_config[0]; @@ -5046,11 +5319,68 @@ size = size_vui; } - size += 1; /* need one more buffer */ + size += 2; /* need two more buffer */ return size; } +static int get_dec_dpb_size_active(struct vdec_h264_hw_s *hw, u32 param1) +{ +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + struct vdec_s *vdec = hw_to_vdec(hw); +#endif + int mb_width, mb_total; + int mb_height = 0; + int active_buffer_spec_num, dec_dpb_size; + u32 used_reorder_dpb_size_margin + = hw->reorder_dpb_size_margin; + + mb_width = param1 & 0xff; + mb_total = (param1 >> 8) & 0xffff; + if (!mb_width && mb_total) /*for 4k2k*/ + mb_width = 256; + if (mb_width) + mb_height = mb_total/mb_width; + if (mb_width <= 0 || mb_height <= 0 || + is_oversize(mb_width << 4, mb_height << 4)) { + dpb_print(DECODE_ID(hw), 0, + "!!!wrong param1 0x%x mb_width/mb_height (0x%x/0x%x) %x\r\n", + param1, + mb_width, + mb_height); + hw->error_frame_width = mb_width << 4; + hw->error_frame_height = mb_height << 4; + return -1; + } + hw->error_frame_width = 0; + hw->error_frame_height = 0; + +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + if (vdec->master || vdec->slave) + used_reorder_dpb_size_margin = + reorder_dpb_size_margin_dv; +#endif + + dec_dpb_size = get_dec_dpb_size(hw , mb_width, mb_height); + + active_buffer_spec_num = + dec_dpb_size + + used_reorder_dpb_size_margin; + + if (active_buffer_spec_num > MAX_VF_BUF_NUM) { + active_buffer_spec_num = MAX_VF_BUF_NUM; + dec_dpb_size = active_buffer_spec_num + - used_reorder_dpb_size_margin; + } + + hw->dpb.mDPB.size = active_buffer_spec_num; + + if (hw->no_poc_reorder_flag) + dec_dpb_size = 1; + + return dec_dpb_size; +} + static void vh264_config_canvs_for_mmu(struct vdec_h264_hw_s *hw) { int i, j; @@ -5088,6 +5418,7 @@ unsigned int used_reorder_dpb_size_margin = hw->reorder_dpb_size_margin; u8 *colocate_vaddr = NULL; + int dec_dpb_size_change = 0; #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION if (vdec->master || vdec->slave) @@ -5106,7 +5437,7 @@ if (mb_width <= 0 || mb_height <= 0 || is_oversize(mb_width << 4, mb_height << 4)) { dpb_print(DECODE_ID(hw), 0, - "!!!wrong seq_info2 0x%x mb_width/mb_height (0x%x/0x%x)\r\n", + "!!!wrong seq_info2 0x%x mb_width/mb_height (0x%x/0x%x) %x\r\n", seq_info2, mb_width, mb_height); @@ -5117,11 +5448,28 @@ hw->error_frame_width = 0; hw->error_frame_height = 0; - if (seq_info2 != 0 && - hw->seq_info2 != seq_info2 && + dec_dpb_size_change = hw->csd_change_flag && (hw->dpb.dec_dpb_size != get_dec_dpb_size_active(hw, param1)); + + if (((seq_info2 != 0 && + hw->seq_info2 != seq_info2) || hw->csd_change_flag) && hw->seq_info2 != 0 - ) /*picture size changed*/ - h264_reconfig(hw); + ) { + if (hw->seq_info2 != seq_info2 || dec_dpb_size_change) { /*picture size changed*/ + h264_reconfig(hw); + } else { + /*someting changes and not including dpb_size, width, height, ...*/ + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + u32 reg_val = param4; + max_reference_size = (reg_val >> 8) & 0xff; + hw->dpb.reorder_output = max_reference_size; + + if (p_H264_Dpb->bitstream_restriction_flag && + p_H264_Dpb->num_reorder_frames <= p_H264_Dpb->max_dec_frame_buffering && + p_H264_Dpb->num_reorder_frames >= 0) { + hw->dpb.reorder_output = hw->num_reorder_frames + 1; + } + } + } if (hw->config_bufmgr_done == 0) { struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; @@ -5143,7 +5491,8 @@ p_H264_Dpb->fast_output_enable = fast_output_enable; /*mb_mv_byte = (seq_info2 & 0x80000000) ? 24 : 96;*/ - + if (hw->enable_fence) + p_H264_Dpb->fast_output_enable = H264_OUTPUT_MODE_FAST; #if 1 /*crop*/ /* AV_SCRATCH_2 @@ -5229,10 +5578,6 @@ hevc_mcr_sao_global_hw_init(hw, (hw->mb_width << 4), (hw->mb_height << 4)); - reg_val = param4; - level_idc = reg_val & 0xff; - max_reference_size = (reg_val >> 8) & 0xff; - hw->dpb.reorder_output = max_reference_size; dpb_print(DECODE_ID(hw), 0, "mb height/widht/total: %x/%x/%x level_idc %x max_ref_num %x\n", mb_height, mb_width, mb_total, @@ -5249,11 +5594,6 @@ used_reorder_dpb_size_margin); if (p_H264_Dpb->bitstream_restriction_flag && - p_H264_Dpb->num_reorder_frames <= p_H264_Dpb->max_dec_frame_buffering) { - hw->dpb.reorder_output = hw->num_reorder_frames + 1; - } - - if (p_H264_Dpb->bitstream_restriction_flag && p_H264_Dpb->num_reorder_frames <= p_H264_Dpb->max_dec_frame_buffering && p_H264_Dpb->num_reorder_frames >= 0) { hw->dpb.reorder_output = hw->num_reorder_frames + 1; @@ -5650,6 +5990,10 @@ struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; bufmgr_h264_remove_unused_frame(p_H264_Dpb, 2); + if (error_proc_policy & 0x20) { + if (!hw->is_used_v4l) + hw->reset_bufmgr_flag = 1; + } } void bufmgr_force_recover(struct h264_dpb_stru *p_H264_Dpb) @@ -5747,10 +6091,18 @@ } } spin_unlock_irqrestore(&hw->bufspec_lock, flags); - inner_size = p_Dpb->used_size - frame_outside_count; + inner_size = p_Dpb->size - frame_outside_count; if (inner_size >= p_H264_Dpb->dec_dpb_size) { - bufmgr_recover(hw); + if (p_H264_Dpb->mDPB.used_size >= + p_H264_Dpb->mDPB.size) { + bufmgr_recover(hw); + } else if (p_H264_Dpb->mDPB.used_size >= + (p_H264_Dpb->mDPB.size - 1)) { + if (inner_size > p_H264_Dpb->dec_dpb_size) { + bufmgr_recover(hw); + } + } } bufmgr_h264_remove_unused_frame(p_H264_Dpb, 0); } else if ((error_proc_policy & 0x8) && @@ -5766,6 +6118,7 @@ if (hw->reset_bufmgr_flag == 1) buffer_available = 1; } + if (hw->is_used_v4l) buffer_available = have_free_buf_spec(vdec); @@ -5994,8 +6347,11 @@ mb_width = 256; decode_mb_count = ((mby_mbx & 0xff) * mb_width + (((mby_mbx >> 8) & 0xff) + 1)); - if (mby_mbx == 0) + if ((mby_mbx == 0) && (p_H264_Dpb->dec_dpb_status != H264_SLICE_HEAD_DONE)) { + dpb_print(DECODE_ID(hw), 0, + "mby_mbx is zero\n"); return; + } if (get_cur_slice_picture_struct(p_H264_Dpb) != FRAME) mb_total /= 2; @@ -6004,11 +6360,11 @@ p->data_flag |= ERROR_FLAG; } - if (error_proc_policy & 0x100) { + if (error_proc_policy & 0x100 && !(p->data_flag & ERROR_FLAG)) { if (decode_mb_count < mb_total) { p->data_flag |= ERROR_FLAG; - if ((error_proc_policy & 0x20000) && - decode_mb_count >= mb_total * (100 - mb_count_threshold) / 100) { + if (((error_proc_policy & 0x20000) && + decode_mb_count >= mb_total * (100 - mb_count_threshold) / 100)) { p->data_flag &= ~ERROR_FLAG; } } @@ -6199,6 +6555,7 @@ p_H264_Dpb->mVideo.dec_picture->data_flag); + if (ret == -1) { release_cur_decoding_buf(hw); bufmgr_force_recover(p_H264_Dpb); @@ -6243,61 +6600,6 @@ return 0; } -#ifdef VDEC_FCC_SUPPORT -static void fcc_discard_mode_process(struct vdec_s *vdec) -{ - struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)(vdec->private); - struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; - - if (vdec->fcc_status == AGAIN_STATUS) { - vdec->stream_offset = (p_H264_Dpb->dpb_param.l.data[OFFSET_DELIMITER_LO] | - p_H264_Dpb->dpb_param.l.data[OFFSET_DELIMITER_HI] << 16); - dpb_print(DECODE_ID(hw), PRINT_FLAG_FCC_STATUS, - "[%d][FCC]: Notify stream_offset: %d\n", - vdec->id, vdec->stream_offset); - vdec_wakeup_fcc_poll(vdec); - amvdec_stop(); - vdec->mc_loaded = 0; - hw->init_flag = 0; - vdec->fcc_status = WAIT_MSG_STATUS; - hw->dec_result = DEC_RESULT_AGAIN; - vdec_schedule_work(&hw->work); - } else if (vdec->fcc_status == DISCARD_STATUS) { - dpb_print(DECODE_ID(hw), PRINT_FLAG_FCC_STATUS, - "[%d][FCC]: Discard current gop and to find next gop!\n", - vdec->id); - amvdec_stop(); - vdec->mc_loaded = 0; - hw->init_flag = 0; - vdec->fcc_status = AGAIN_STATUS; - hw->dec_result = DEC_RESULT_DISCARD_DATA; - vdec_schedule_work(&hw->work); - } -} - -static int vh264_fcc_process(struct vdec_s *vdec) -{ - struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)(vdec->private); - - if (input_stream_based(vdec)) { - switch (vdec->fcc_mode) { - case FCC_DISCARD_MODE: - fcc_discard_mode_process(vdec); - return 1; - case FCC_DEC_MODE: - dpb_print(DECODE_ID(hw), PRINT_FLAG_FCC_STATUS, - "[%d][FCC]: Current is Dec mode.\n", vdec->id); - break; - case FCC_BUTT: - default: - break; - } - } - - return 0; -} -#endif - static irqreturn_t vh264_isr_thread_fn(struct vdec_s *vdec, int irq) { int i; @@ -6306,6 +6608,18 @@ unsigned int dec_dpb_status = p_H264_Dpb->dec_dpb_status; u32 debug_tag; + if (dec_dpb_status == H264_SLICE_HEAD_DONE || + p_H264_Dpb->dec_dpb_status == H264_CONFIG_REQUEST) { + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_START); + } + else if (dec_dpb_status == H264_PIC_DATA_DONE) { + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_PIC_DONE_START); + } + else if (dec_dpb_status == H264_SEI_DATA_READY) + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_SEI_START); + else if (dec_dpb_status == H264_AUX_DATA_READY) + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_AUX_START); + if (dec_dpb_status == H264_CONFIG_REQUEST) { #if 1 unsigned short *p = (unsigned short *)hw->lmem_addr; @@ -6330,7 +6644,13 @@ } } } - + if (p_H264_Dpb->bitstream_restriction_flag != + ((p_H264_Dpb->dpb_param.l.data[SPS_FLAGS2] >> 3) & 0x1)) { + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "p_H264_Dpb->bitstream_restriction_flag 0x%x, new 0x%x\n", + p_H264_Dpb->bitstream_restriction_flag, ((p_H264_Dpb->dpb_param.l.data[SPS_FLAGS2] >> 3) & 0x1)); + hw->csd_change_flag = 1; + } p_H264_Dpb->bitstream_restriction_flag = (p_H264_Dpb->dpb_param.l.data[SPS_FLAGS2] >> 3) & 0x1; p_H264_Dpb->num_reorder_frames = @@ -6357,7 +6677,7 @@ p_H264_Dpb->frame_crop_top_offset = p_H264_Dpb->dpb_param.dpb.frame_crop_top_offset; p_H264_Dpb->frame_crop_bottom_offset = p_H264_Dpb->dpb_param.dpb.frame_crop_bottom_offset; - dpb_print(DECODE_ID(hw), PRINT_FLAG_DPB_DETAIL, + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, "%s chroma_format_idc %d crop offset: left %d right %d top %d bottom %d\n", __func__, p_H264_Dpb->chroma_format_idc, p_H264_Dpb->frame_crop_left_offset, @@ -6366,11 +6686,6 @@ p_H264_Dpb->frame_crop_bottom_offset); #endif -#ifdef VDEC_FCC_SUPPORT - if (vh264_fcc_process(vdec) > 0) - return IRQ_HANDLED; -#endif - WRITE_VREG(DPB_STATUS_REG, H264_ACTION_CONFIG_DONE); reset_process_time(hw); hw->reg_iqidct_control = READ_VREG(IQIDCT_CONTROL); @@ -6390,6 +6705,7 @@ hw->multi_slice_pic_flag = 0; hw->picture_slice_count = 0; #endif + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_END); vdec_schedule_work(&hw->work); } else if (dec_dpb_status == H264_SLICE_HEAD_DONE) { u16 data_hight; @@ -6405,18 +6721,27 @@ unsigned mb_width = hw->seq_info2 & 0xff; unsigned short first_mb_in_slice; unsigned int decode_mb_count, mby_mbx; + struct StorablePicture *pic = p_H264_Dpb->mVideo.dec_picture; reset_process_time(hw); + hw->frmbase_cont_flag = 0; + + if ((pic != NULL) && (pic->mb_aff_frame_flag == 1)) + first_mb_in_slice = p[FIRST_MB_IN_SLICE + 3] * 2; + else + first_mb_in_slice = p[FIRST_MB_IN_SLICE + 3]; #ifdef DETECT_WRONG_MULTI_SLICE hw->cur_picture_slice_count++; - if (hw->multi_slice_pic_flag == 1 && - hw->cur_picture_slice_count == 1 && - (error_proc_policy & 0x10000)) { - hw->first_pre_frame_num = p_H264_Dpb->mVideo.pre_frame_num; - } - if (hw->multi_slice_pic_flag == 1 && - hw->cur_picture_slice_count > 1 && - (error_proc_policy & 0x10000)) { + + if ((error_proc_policy & 0x10000) && + (hw->cur_picture_slice_count > 1) && + (first_mb_in_slice == 0) && + (hw->multi_slice_pic_flag == 0)) + hw->multi_slice_pic_check_count = 0; + + if ((error_proc_policy & 0x10000) && + (hw->cur_picture_slice_count > 1) && + (hw->multi_slice_pic_flag == 1)) { dpb_print(DECODE_ID(hw), 0, "%s MULTI_SLICE_DETECT (check_count %d slice_count %d cur_slice_count %d flag %d), WRONG_MULTI_SLICE detected, insert picture\n", __func__, @@ -6425,7 +6750,6 @@ hw->cur_picture_slice_count, hw->multi_slice_pic_flag); - first_mb_in_slice = p[FIRST_MB_IN_SLICE + 3]; mby_mbx = READ_VREG(MBY_MBX); decode_mb_count = ((mby_mbx & 0xff) * mb_width + (((mby_mbx >> 8) & 0xff) + 1)); @@ -6438,8 +6762,19 @@ hw->multi_slice_pic_flag = 0; hw->multi_slice_pic_check_count = 0; - } else if (hw->cur_picture_slice_count > hw->last_picture_slice_count) + } else if (hw->cur_picture_slice_count > hw->last_picture_slice_count) { vh264_pic_done_proc(vdec); + //if (p_H264_Dpb->mDPB.used_size == p_H264_Dpb->mDPB.size) { + if (!have_free_buf_spec(vdec)) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, "dpb full, wait buffer\n"); + p_H264_Dpb->mVideo.pre_frame_num = hw->first_pre_frame_num; + hw->last_picture_slice_count = hw->cur_picture_slice_count; + hw->no_decoder_buffer_flag = 1; + hw->dec_result = DEC_RESULT_AGAIN; + vdec_schedule_work(&hw->work); + return IRQ_HANDLED; + } + } else { if (p_H264_Dpb->mVideo.dec_picture) { if (p_H264_Dpb->mVideo.dec_picture->colocated_buf_index >= 0) { @@ -6506,6 +6841,9 @@ } #else dpb_param_bak = p_H264_Dpb->dpb_param; + + ATRACE_COUNTER(hw->trace.decode_header_time_name, TRACE_HEADER_RPM_START); + for (i = 0; i < (RPM_END-RPM_BEGIN); i += 4) { int ii; @@ -6528,6 +6866,7 @@ } } } + ATRACE_COUNTER(hw->trace.decode_header_time_name, TRACE_HEADER_RPM_END); #endif #ifdef DETECT_WRONG_MULTI_SLICE @@ -6666,6 +7005,9 @@ else p_H264_Dpb->fast_output_enable = fast_output_enable; + if (hw->enable_fence) + p_H264_Dpb->fast_output_enable = H264_OUTPUT_MODE_FAST; + hw->data_flag = I_flag; if ((p_H264_Dpb-> dpb_param.dpb.NAL_info_mmco & 0x1f) @@ -6707,13 +7049,15 @@ }*/ } - if (!I_flag && frame_num_gap) { - hw->data_flag |= ERROR_FLAG; - p_H264_Dpb->mVideo.dec_picture->data_flag |= ERROR_FLAG; - dpb_print(DECODE_ID(hw), 0, "frame number gap error\n"); + if (!I_flag && frame_num_gap && !p_H264_Dpb->long_term_reference_flag) { + if (!(error_proc_policy & 0x800000)) { + hw->data_flag |= ERROR_FLAG; + p_H264_Dpb->mVideo.dec_picture->data_flag |= ERROR_FLAG; + dpb_print(DECODE_ID(hw), 0, "frame number gap error\n"); + } } - if (error_proc_policy & 0x400) { + if ((error_proc_policy & 0x400) && !hw->enable_fence) { int ret = dpb_check_ref_list_error(p_H264_Dpb); if (ret != 0) { hw->reflist_error_count ++; @@ -6756,9 +7100,10 @@ return IRQ_HANDLED; } } - + ATRACE_COUNTER(hw->trace.decode_header_time_name, TRACE_HEADER_REGISTER_START); cfg_ret = config_decode_buf(hw, p_H264_Dpb->mVideo.dec_picture); + ATRACE_COUNTER(hw->trace.decode_header_time_name, TRACE_HEADER_REGISTER_END); if (cfg_ret < 0) { dpb_print(DECODE_ID(hw), PRINT_FLAG_ERROR, "config_decode_buf fail (%d)\n", @@ -6776,11 +7121,12 @@ } } - if (slice_header_process_status == 1) { + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_END); + + if (slice_header_process_status == 1) WRITE_VREG(DPB_STATUS_REG, H264_ACTION_DECODE_NEWPIC); - } else { + else WRITE_VREG(DPB_STATUS_REG, H264_ACTION_DECODE_SLICE); - } hw->last_mby_mbx = 0; hw->last_vld_level = 0; start_process_time(hw); @@ -6815,6 +7161,16 @@ pic_done_proc: reset_process_time(hw); + if ((dec_dpb_status == H264_SEARCH_BUFEMPTY) || + (dec_dpb_status == H264_DECODE_BUFEMPTY) || + (dec_dpb_status == H264_DECODE_TIMEOUT) || + ((dec_dpb_status == H264_DATA_REQUEST) && input_frame_based(vdec))) { + hw->data_flag |= ERROR_FLAG; + if (hw->dpb.mVideo.dec_picture) + hw->dpb.mVideo.dec_picture->data_flag |= ERROR_FLAG; + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_DETAIL, + "%s, mark err_frame\n", __func__); + } vh264_pic_done_proc(vdec); if (hw->frmbase_cont_flag) { @@ -6866,6 +7222,7 @@ hw->got_valid_nal = 1; } #endif + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_EDN); hw->dec_result = DEC_RESULT_DONE; vdec_schedule_work(&hw->work); @@ -6880,7 +7237,7 @@ reset_process_time(hw); if (READ_VREG(H264_AUX_DATA_SIZE) != 0) { if (dpb_is_debug(DECODE_ID(hw), - PRINT_FLAG_DPB_DETAIL)) + PRINT_FLAG_SEI_DETAIL)) dump_aux_buf(hw); #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION if (vdec_frame_based(vdec)) { @@ -6918,6 +7275,7 @@ #endif dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, "%s H264_AUX_DATA_READY\n", __func__); + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_EDN); hw->dec_result = DEC_RESULT_DONE; vdec_schedule_work(&hw->work); } else if (/*(dec_dpb_status == H264_DATA_REQUEST) ||*/ @@ -6927,7 +7285,8 @@ empty_proc: reset_process_time(hw); if ((error_proc_policy & 0x40000) && - dec_dpb_status == H264_DECODE_TIMEOUT) + ((dec_dpb_status == H264_DECODE_TIMEOUT) || + (!hw->frmbase_cont_flag && (dec_dpb_status == H264_SEARCH_BUFEMPTY || dec_dpb_status == H264_DECODE_BUFEMPTY) && input_frame_based(vdec)))) goto pic_done_proc; if (!hw->frmbase_cont_flag) release_cur_decoding_buf(hw); @@ -6968,7 +7327,7 @@ (p_H264_Dpb->mSlice.slice_type != B_SLICE))) { dpb_print(DECODE_ID(hw), PRINT_FLAG_ERROR, "%s last dpb status 0x%x need bugmgr reset \n", - __func__, p_H264_Dpb->last_dpb_status); + p_H264_Dpb->last_dpb_status, __func__); hw->reset_bufmgr_flag = 1; } } @@ -6981,9 +7340,7 @@ } else { /* WRITE_VREG(DPB_STATUS_REG, H264_ACTION_INIT); */ #ifdef DETECT_WRONG_MULTI_SLICE - if (hw->multi_slice_pic_flag == 1 && - hw->cur_picture_slice_count > 1 && - (error_proc_policy & 0x10000)) { + if (error_proc_policy & 0x10000) { p_H264_Dpb->mVideo.pre_frame_num = hw->first_pre_frame_num; } hw->last_picture_slice_count = hw->cur_picture_slice_count; @@ -7080,6 +7437,7 @@ left_len); } } + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_EDN); WRITE_VREG(DPB_STATUS_REG, H264_SEI_DATA_DONE); return IRQ_HANDLED; @@ -7160,6 +7518,17 @@ p_H264_Dpb->vdec = vdec; p_H264_Dpb->dec_dpb_status = READ_VREG(DPB_STATUS_REG); + if (p_H264_Dpb->dec_dpb_status == H264_SLICE_HEAD_DONE || + p_H264_Dpb->dec_dpb_status == H264_CONFIG_REQUEST) { + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_HEAD_DONE); + } + else if (p_H264_Dpb->dec_dpb_status == H264_PIC_DATA_DONE) { + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_PIC_DONE); + } + else if (p_H264_Dpb->dec_dpb_status == H264_SEI_DATA_READY) + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_SEI_DONE); + else if (p_H264_Dpb->dec_dpb_status == H264_AUX_DATA_READY) + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_AUX_DONE); dpb_print(DECODE_ID(hw), PRINT_FLAG_UCODE_EVT, "%s DPB_STATUS_REG: 0x%x, run(%d) last_state (%x) ERROR_STATUS_REG 0x%x, sb (0x%x 0x%x 0x%x) bitcnt 0x%x mby_mbx 0x%x\n", @@ -7180,6 +7549,7 @@ WRITE_VREG(DPB_STATUS_REG, H264_WRRSP_DONE); return IRQ_HANDLED; } + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_END); return IRQ_WAKE_THREAD; } @@ -7200,7 +7570,6 @@ pr_err("%s h264[%d] work pending, do nothing.\n",__func__, vdec->id); return; } - hw->timeout_num++; amvdec_stop(); vdec->mc_loaded = 0; @@ -7209,7 +7578,7 @@ hevc_sao_wait_done(hw); } dpb_print(DECODE_ID(hw), - PRINT_FLAG_ERROR, "%s decoder timeout\n", __func__); + PRINT_FLAG_ERROR, "%s decoder timeout, DPB_STATUS_REG 0x%x\n", __func__, READ_VREG(DPB_STATUS_REG)); release_cur_decoding_buf(hw); hw->dec_result = DEC_RESULT_TIMEOUT; hw->data_flag |= ERROR_FLAG; @@ -7255,7 +7624,7 @@ dpb_print(DECODE_ID(hw), 0, "====== %s\n", __func__); dpb_print(DECODE_ID(hw), 0, - "width/height (%d/%d), num_reorder_frames %d dec_dpb_size %d dpb size(bufspec count) %d max_reference_size(collocate count) %d i_only %d send_err %d\n", + "width/height (%d/%d), num_reorder_frames %d dec_dpb_size %d dpb size(bufspec count) %d max_reference_size(collocate count) %d i_only %d video_signal_type 0x%x send_err %d \n", hw->frame_width, hw->frame_height, hw->num_reorder_frames, @@ -7263,6 +7632,7 @@ hw->dpb.mDPB.size, hw->max_reference_size, hw->i_only, + hw->video_signal_type, hw->send_error_frame_flag ); @@ -7290,9 +7660,7 @@ hw->cur_picture_slice_count, hw->multi_slice_pic_flag); #endif - - - if (vf_get_receiver(vdec->vf_provider_name)) { + if (!hw->is_used_v4l && vf_get_receiver(vdec->vf_provider_name)) { enum receviver_start_e state = vf_notify_receiver(vdec->vf_provider_name, VFRAME_EVENT_PROVIDER_QUREY_STATE, @@ -7398,9 +7766,10 @@ } -static void check_timer_func(unsigned long arg) +static void check_timer_func(struct timer_list *timer) { - struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)arg; + struct vdec_h264_hw_s *hw = container_of(timer, + struct vdec_h264_hw_s, check_timer); struct vdec_s *vdec = hw_to_vdec(hw); int error_skip_frame_count = error_skip_count & 0xfff; unsigned int timeout_val = decode_timeout_val; @@ -7454,7 +7823,9 @@ if ((dpb_status == H264_ACTION_DECODE_NEWPIC) || (dpb_status == H264_ACTION_DECODE_SLICE) || (dpb_status == H264_SEI_DATA_DONE) || - (dpb_status == H264_STATE_SEARCH_HEAD)) { + (dpb_status == H264_STATE_SEARCH_HEAD) || + (dpb_status == H264_SLICE_HEAD_DONE) || + (dpb_status == H264_SEI_DATA_READY)) { if (h264_debug_flag & DEBUG_TIMEOUT_DEC_STAT) pr_debug("%s dpb_status = 0x%x last_mby_mbx = %u mby_mbx = %u\n", __func__, dpb_status, hw->last_mby_mbx, mby_mbx); @@ -7555,6 +7926,7 @@ int i, j; struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx; + hw->frmbase_cont_flag = 0; /* if (hw->init_flag == 0) { */ if (h264_debug_flag & 0x40000000) { /* if (1) */ @@ -7646,12 +8018,14 @@ #endif #ifdef VDEC_DW - if (IS_VDEC_DW(hw)) { - u32 data = ((1 << 30) |(1 << 0) |(1 << 8)); + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_T7) { + if (IS_VDEC_DW(hw)) { + u32 data = ((1 << 30) |(1 << 0) |(1 << 8)); - if (IS_VDEC_DW(hw) == 2) - data |= (1 << 9); - WRITE_VREG(MDEC_DOUBLEW_CFG0, data); /* Double Write Enable*/ + if (IS_VDEC_DW(hw) == 2) + data |= (1 << 9); + WRITE_VREG(MDEC_DOUBLEW_CFG0, data); /* Double Write Enable*/ + } } #endif if (hw->dpb.mDPB.size > 0) { @@ -7677,9 +8051,8 @@ if (hw->init_flag == 0) WRITE_VREG(DPB_STATUS_REG, 0); - else { + else WRITE_VREG(DPB_STATUS_REG, H264_ACTION_DECODE_START); - } WRITE_VREG(FRAME_COUNTER_REG, hw->decode_pic_count); WRITE_VREG(AV_SCRATCH_8, hw->buf_offset); @@ -7848,10 +8221,7 @@ /* init_timer(&hw->recycle_timer); */ /* timer init */ - init_timer(&hw->check_timer); - - hw->check_timer.data = (unsigned long)hw; - hw->check_timer.function = check_timer_func; + timer_setup(&hw->check_timer, check_timer_func, 0); hw->check_timer.expires = jiffies + CHECK_INTERVAL; /* add_timer(&hw->check_timer); */ @@ -7987,13 +8357,13 @@ return -1; } - hw->sei_data_buf = vzalloc(SEI_DATA_SIZE); + hw->sei_data_buf = kmalloc(SEI_DATA_SIZE, GFP_KERNEL); if (hw->sei_data_buf == NULL) { pr_err("%s: failed to alloc sei itu data buffer\n", __func__); return -1; } - hw->sei_itu_data_buf = vzalloc(SEI_ITU_DATA_SIZE); + hw->sei_itu_data_buf = kmalloc(SEI_ITU_DATA_SIZE, GFP_KERNEL); if (hw->sei_itu_data_buf == NULL) { pr_err("%s: failed to alloc sei itu data buffer\n", __func__); @@ -8001,14 +8371,15 @@ hw->prefix_aux_size + hw->suffix_aux_size, hw->aux_addr, hw->aux_phy_addr); hw->aux_addr = NULL; - vfree(hw->sei_data_buf); + kfree(hw->sei_data_buf); hw->sei_data_buf = NULL; return -1; } if (NULL == hw->sei_user_data_buffer) { - hw->sei_user_data_buffer = vzalloc(USER_DATA_SIZE); + hw->sei_user_data_buffer = kmalloc(USER_DATA_SIZE, + GFP_KERNEL); if (!hw->sei_user_data_buffer) { pr_info("%s: Can not allocate sei_data_buffer\n", __func__); @@ -8016,9 +8387,9 @@ hw->prefix_aux_size + hw->suffix_aux_size, hw->aux_addr, hw->aux_phy_addr); hw->aux_addr = NULL; - vfree(hw->sei_data_buf); + kfree(hw->sei_data_buf); hw->sei_data_buf = NULL; - vfree(hw->sei_itu_data_buf); + kfree(hw->sei_itu_data_buf); hw->sei_itu_data_buf = NULL; return -1; @@ -8044,6 +8415,7 @@ } #ifdef VDEC_DW WRITE_VREG(MDEC_DOUBLEW_CFG0, 0); + WRITE_VREG(MDEC_DOUBLEW_CFG1, 0); #endif #ifdef MH264_USERDATA_ENABLE cancel_work_sync(&hw->user_data_ready_work); @@ -8052,7 +8424,6 @@ cancel_work_sync(&hw->timeout_work); cancel_work_sync(&hw->work); - if (hw->stat & STAT_MC_LOAD) { if (hw->mc_cpu_addr != NULL) { dma_free_coherent(amports_get_dma_device(), @@ -8086,15 +8457,15 @@ hw->aux_addr = NULL; } if (hw->sei_data_buf != NULL) { - vfree(hw->sei_data_buf); + kfree(hw->sei_data_buf); hw->sei_data_buf = NULL; } if (hw->sei_itu_data_buf != NULL) { - vfree(hw->sei_itu_data_buf); + kfree(hw->sei_itu_data_buf); hw->sei_itu_data_buf = NULL; } if (hw->sei_user_data_buffer != NULL) { - vfree(hw->sei_user_data_buffer); + kfree(hw->sei_user_data_buffer); hw->sei_user_data_buffer = NULL; } /* amvdec_disable(); */ @@ -8137,6 +8508,10 @@ struct vdec_h264_hw_s *hw = container_of(work, struct vdec_h264_hw_s, notify_work); struct vdec_s *vdec = hw_to_vdec(hw); + + if (hw->is_used_v4l) + return; + if (vdec->fr_hint_state == VDEC_NEED_HINT) { vf_notify_receiver(vdec->vf_provider_name, VFRAME_EVENT_PROVIDER_FR_HINT, @@ -8431,7 +8806,7 @@ static int vmh264_init_userdata_dump(void) { - user_data_buf = vzalloc(MAX_USER_DATA_SIZE); + user_data_buf = kmalloc(MAX_USER_DATA_SIZE, GFP_KERNEL); if (user_data_buf) return 1; else @@ -8442,7 +8817,7 @@ { if (user_data_buf) { show_user_data_buf(); - vfree(user_data_buf); + kfree(user_data_buf); user_data_buf = NULL; } } @@ -8804,7 +9179,7 @@ if (mb_width <= 0 || mb_height <= 0 || is_oversize(mb_width << 4, mb_height << 4)) { dpb_print(DECODE_ID(hw), 0, - "!!!wrong param1 0x%x mb_width/mb_height (0x%x/0x%x)\r\n", + "!!!wrong param1 0x%x mb_width/mb_height (0x%x/0x%x) %x\r\n", param1, mb_width, mb_height); @@ -8835,6 +9210,8 @@ - used_reorder_dpb_size_margin; } + hw->dpb.mDPB.size = active_buffer_spec_num; + if (hw->no_poc_reorder_flag) dec_dpb_size = 1; @@ -8844,6 +9221,7 @@ * bit 15: frame_mbs_only_flag * bit 13-14: chroma_format_idc */ + hw->seq_info = param2; frame_mbs_only_flag = (hw->seq_info >> 15) & 0x01; if (hw->dpb.mSPS.profile_idc != 100 && hw->dpb.mSPS.profile_idc != 110 && @@ -8902,9 +9280,8 @@ ps->visible_height = frame_height; ps->coded_width = ALIGN(mb_width << 4, 64); ps->coded_height = ALIGN(mb_height << 4, 64); - ps->reorder_frames = dec_dpb_size + 1; /* +1 for two frames in one packet */ + ps->dpb_frames = dec_dpb_size + 1; /* +1 for two frames in one packet */ ps->dpb_size = active_buffer_spec_num; - ps->field = frame_mbs_only_flag ? V4L2_FIELD_NONE : V4L2_FIELD_INTERLACED; return 0; } @@ -8917,34 +9294,36 @@ (struct aml_vcodec_ctx *)(hw->v4l2_ctx); struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; int ret = 0; + int dec_dpb_size_change = hw->csd_change_flag && (hw->dpb.dec_dpb_size != get_dec_dpb_size_active(hw, param1)); if (ctx->param_sets_from_ucode && hw->res_ch_flag == 0) { - if (param1 != 0 && - hw->seq_info2 != param1 && - hw->seq_info2 != 0) /*picture size changed*/ { - struct aml_vdec_ps_infos ps; - dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, - "h264 res_change\n"); - if (vmh264_get_ps_info(hw, param1, - param2, param3, param4, &ps) < 0) { - dpb_print(DECODE_ID(hw), 0, - "set parameters error\n"); - } - hw->v4l_params_parsed = false; - vdec_v4l_set_ps_infos(ctx, &ps); - vdec_v4l_res_ch_event(ctx); - hw->res_ch_flag = 1; - ctx->v4l_resolution_change = 1; - amvdec_stop(); - if (hw->mmu_enable) - amhevc_stop(); - hw->eos = 1; - flush_dpb(p_H264_Dpb); - //del_timer_sync(&hw->check_timer); - if (hw->is_used_v4l) + if (((param1 != 0 && + hw->seq_info2 != param1) || hw->csd_change_flag) && + hw->seq_info2 != 0) { + if (hw->seq_info2 != param1 || dec_dpb_size_change) { /*picture size changed*/ + struct aml_vdec_ps_infos ps; + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "h264 res_change\n"); + if (vmh264_get_ps_info(hw, param1, + param2, param3, param4, &ps) < 0) { + dpb_print(DECODE_ID(hw), 0, + "set parameters error\n"); + } + hw->v4l_params_parsed = false; + vdec_v4l_set_ps_infos(ctx, &ps); + vdec_v4l_res_ch_event(ctx); + hw->res_ch_flag = 1; + ctx->v4l_resolution_change = 1; + amvdec_stop(); + if (hw->mmu_enable) + amhevc_stop(); + hw->eos = 1; + flush_dpb(p_H264_Dpb); + //del_timer_sync(&hw->check_timer); notify_v4l_eos(hw_to_vdec(hw)); - ret = 1; + ret = 1; + } } } @@ -8983,6 +9362,13 @@ /* finished decoding one frame or error, * notify vdec core to switch context */ + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + + if (hw->dec_result == DEC_RESULT_DONE) { + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_WORKER_START); + } else if (hw->dec_result == DEC_RESULT_AGAIN) + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_WORKER_AGAIN); + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_DETAIL, "%s dec_result %d %x %x %x\n", __func__, @@ -9010,7 +9396,6 @@ if (!v4l_res_change(hw, param1, param2, param3, param4)) { if (!hw->v4l_params_parsed) { struct aml_vdec_ps_infos ps; - dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, "h264 parsered csd data\n"); @@ -9160,7 +9545,6 @@ return; } else if (hw->dec_result == DEC_RESULT_DONE || hw->dec_result == DEC_RESULT_TIMEOUT) { - /* if (!hw->ctx_valid) hw->ctx_valid = 1; */ hw->dec_again_cnt = 0; @@ -9181,7 +9565,7 @@ for (i = 0; i < p_Dpb->used_size; i++) { int i_flag = p_Dpb->fs[i]->bottom_field || p_Dpb->fs[i]->top_field; - int threshold = i_flag ? ((50 + p_Dpb->used_size) * 2) : 50 + p_Dpb->used_size; + int threshold = (i_flag || (hw->max_reference_size >= 12)) ? ((50 + p_Dpb->used_size) * 2) : 50 + p_Dpb->used_size; if ((p_Dpb->fs[i]->dpb_frame_count + threshold < p_H264_Dpb->dpb_frame_count) && p_Dpb->fs[i]->is_reference && @@ -9225,17 +9609,7 @@ hw->gvs.b_decoded_frames++; } amvdec_stop(); - if (!vdec_is_support_4k()) { - if (clk_adj_frame_count < VDEC_CLOCK_ADJUST_FRAME) { - clk_adj_frame_count++; - if (clk_adj_frame_count == VDEC_CLOCK_ADJUST_FRAME) { - if (hw->frame_height <= 144) - vdec_source_changed(VFORMAT_H264, 1920, 1080, 29); - else - vdec_source_changed(VFORMAT_H264, 3840, 2160, 60); - } - } - } + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, "%s dec_result %d %x %x %x\n", __func__, @@ -9253,11 +9627,12 @@ frame base: vdec_prepare_input fail */ if (!vdec_has_more_input(vdec) && (hw_to_vdec(hw)->next_status != - VDEC_STATUS_DISCONNECTED)) { + VDEC_STATUS_DISCONNECTED) && (hw->no_decoder_buffer_flag == 0)) { hw->dec_result = DEC_RESULT_EOS; vdec_schedule_work(&hw->work); return; } + if ((vdec_stream_based(vdec)) && (error_proc_policy & 0x400000) && check_dirty_data(vdec)) { @@ -9265,6 +9640,7 @@ vdec_schedule_work(&hw->work); return; } + hw->no_decoder_buffer_flag = 0; hw->next_again_flag = 1; } else if (hw->dec_result == DEC_RESULT_EOS) { struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; @@ -9293,12 +9669,14 @@ vdec_free_irq(VDEC_IRQ_1, (void *)hw); hw->stat &= ~STAT_ISR_REG; } - } else if (hw->dec_result == DEC_RESULT_DISCARD_DATA) { - mutex_lock(&hw->chunks_mutex); - vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk); - hw->chunk = NULL; - mutex_unlock(&hw->chunks_mutex); } + + if (p_H264_Dpb->mVideo.dec_picture) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s, release decoded picture\n", __func__); + release_cur_decoding_buf(hw); + } + WRITE_VREG(ASSIST_MBOX1_MASK, 0); del_timer_sync(&hw->check_timer); hw->stat &= ~STAT_TIMER_ARM; @@ -9306,7 +9684,9 @@ if (hw->dec_result != DEC_RESULT_AGAIN) hw->last_picture_slice_count = 0; #endif + ATRACE_COUNTER(hw->trace.decode_work_time_name, TRACE_WORK_WAIT_SEARCH_DONE_START); wait_vmh264_search_done(hw); + ATRACE_COUNTER(hw->trace.decode_work_time_name, TRACE_WORK_WAIT_SEARCH_DONE_END); /* mark itself has all HW resource released and input released */ #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION @@ -9329,6 +9709,9 @@ return; } } + if (hw->dec_result == DEC_RESULT_DONE) { + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_WORKER_END); + } /* mark itself has all HW resource released and input released */ if (vdec->parallel_dec == 1) { @@ -9376,16 +9759,8 @@ hw->timeout_processing = 1; vh264_work_implement(hw, vdec, 1); - } -#ifdef VDEC_FCC_SUPPORT -static void vmh264_wakeup_fcc_poll(struct vdec_s *vdec) -{ - amstream_wakeup_fcc_poll(vdec); -} -#endif - static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) { bool ret = 0; @@ -9393,9 +9768,6 @@ (struct vdec_h264_hw_s *)vdec->private; int tvp = vdec_secure(hw_to_vdec(hw)) ? CODEC_MM_FLAGS_TVP : 0; -#ifdef VDEC_FCC_SUPPORT - int get_msg = 1; -#endif if (hw->timeout_processing && (work_pending(&hw->work) || work_busy(&hw->work) || @@ -9468,7 +9840,7 @@ ret = is_buffer_available(vdec); #ifdef CONSTRAIN_MAX_BUF_NUM - if (hw->dpb.mDPB.size > 0) { /*make sure initilized*/ + if (ret && (hw->dpb.mDPB.size > 0)) { /*make sure initilized*/ if (run_ready_max_vf_only_num > 0 && get_vf_ref_only_buf_count(hw) >= run_ready_max_vf_only_num @@ -9481,12 +9853,15 @@ /*avoid more buffers consumed when switching resolution*/ if (run_ready_max_buf_num == 0xff && - !have_free_buf_spec(vdec)) + get_used_buf_count(hw) > + hw->dpb.mDPB.size) ret = 0; else if (run_ready_max_buf_num && get_used_buf_count(hw) >= run_ready_max_buf_num) ret = 0; + if (ret == 0) + bufmgr_h264_remove_unused_frame(&hw->dpb, 0); } #endif if (hw->is_used_v4l) { @@ -9495,13 +9870,12 @@ if (ctx->param_sets_from_ucode) { if (hw->v4l_params_parsed) { - if (!ctx->v4l_codec_dpb_ready && - v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < - run_ready_min_buf_num) - ret = 0; - else if (ctx->v4l_codec_dpb_ready && - !is_buffer_available(vdec)) - ret = 0; + if (ctx->cap_pool.dec < hw->dpb.mDPB.size) { + if (is_buffer_available(vdec)) + ret = 1; + else + ret = 0; + } } else { if (ctx->v4l_resolution_change) ret = 0; @@ -9511,19 +9885,12 @@ run_ready_min_buf_num) ret = 0; } - } -#ifdef VDEC_FCC_SUPPORT - get_msg = vdec_has_get_fcc_new_msg(vdec); - ret &= get_msg; -#endif - if (ret) not_run_ready[DECODE_ID(hw)] = 0; else not_run_ready[DECODE_ID(hw)]++; - if (vdec->parallel_dec == 1) { if (hw->mmu_enable == 0) return ret ? (CORE_MASK_VDEC_1) : 0; @@ -9568,6 +9935,8 @@ if (hw->mmu_enable) amhevc_enable(); } + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_RUN_START); + run_count[DECODE_ID(hw)]++; vdec_reset_core(vdec); if (hw->mmu_enable) @@ -9595,10 +9964,8 @@ if (hw->reset_bufmgr_flag || ((error_proc_policy & 0x40) && p_H264_Dpb->buf_alloc_fail)) { - if (p_H264_Dpb->buf_alloc_fail){ - hw->reset_bufmgr_flag = 1; - } h264_reset_bufmgr(vdec); + //flag must clear after reset for v4l buf_spec_init use hw->reset_bufmgr_flag = 0; } @@ -9630,6 +9997,7 @@ hw->dec_result = DEC_RESULT_NONE; hw->get_data_count = 0; + hw->csd_change_flag = 0; #if 0 pr_info("VLD_MEM_VIFIFO_LEVEL = 0x%x, rp = 0x%x, wp = 0x%x\n", READ_VREG(VLD_MEM_VIFIFO_LEVEL), @@ -9699,7 +10067,7 @@ */ WRITE_VREG(AV_SCRATCH_G, hw->reg_g_status); } else { - + ATRACE_COUNTER(hw->trace.decode_run_time_name, TRACE_RUN_LOADING_FW_START); ret = amvdec_vdec_loadmc_ex(VFORMAT_H264, "mh264", vdec, hw->fw->data); if (ret < 0) { amvdec_enable_flag = false; @@ -9730,13 +10098,18 @@ vdec->mc_type = ((1 << 16) | VFORMAT_H264); } vdec->mc_loaded = 0; + ATRACE_COUNTER(hw->trace.decode_run_time_name, TRACE_RUN_LOADING_FW_END); } vmh264_reset_udr_mgr(hw); - + ATRACE_COUNTER(hw->trace.decode_run_time_name, TRACE_RUN_LOADING_RESTORE_START); if (vh264_hw_ctx_restore(hw) < 0) { vdec_schedule_work(&hw->work); return; } + if (error_proc_policy & 0x10000) { + hw->first_pre_frame_num = p_H264_Dpb->mVideo.pre_frame_num; + } + ATRACE_COUNTER(hw->trace.decode_run_time_name, TRACE_RUN_LOADING_RESTORE_END); if (input_frame_based(vdec)) { int decode_size = 0; @@ -9770,12 +10143,14 @@ WRITE_VREG(NAL_SEARCH_CTL, READ_VREG(NAL_SEARCH_CTL) & (~0x2)); } - WRITE_VREG(NAL_SEARCH_CTL, READ_VREG(NAL_SEARCH_CTL) | (1 << 2)); + WRITE_VREG(NAL_SEARCH_CTL, READ_VREG(NAL_SEARCH_CTL) | (1 << 2) | (hw->bitstream_restriction_flag << 15)); + if (udebug_flag) WRITE_VREG(AV_SCRATCH_K, udebug_flag); + hw->stat |= STAT_TIMER_ARM; mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL); - if (get_cpu_major_id() >= MESON_CPU_MAJOR_ID_G12A) { + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { if (hw->mmu_enable) SET_VREG_MASK(VDEC_ASSIST_MMC_CTRL1, 1 << 3); @@ -9800,6 +10175,7 @@ /* } */ hw->init_flag = 1; + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_RUN_END); } static void clear_refer_bufs(struct vdec_h264_hw_s *hw) @@ -9916,6 +10292,12 @@ hw->buffer_spec[i].used = 4; hw->buffer_spec[i].canvas_pos = -1; + + if (hw->buffer_spec[i].used == 4 && + hw->buffer_spec[i].vf_ref != 0 && + hw->buffer_spec[i].cma_alloc_addr) { + hw->buffer_spec[i].used = 3; + } } spin_unlock_irqrestore(&hw->bufspec_lock, flags); hw->has_i_frame = 0; @@ -10011,16 +10393,15 @@ __func__, hw->decode_pic_count+1, hw->skip_frame_count); - /* Only the caller from inside decoder we call flush_dbp */ - if (!hw->reset_bufmgr_flag){ - flush_dpb(&hw->dpb); - } + flush_dpb(&hw->dpb); - timeout = jiffies + HZ; - while (kfifo_len(&hw->display_q) > 0) { - if (time_after(jiffies, timeout)) - break; - schedule(); + if (!hw->is_used_v4l) { + timeout = jiffies + HZ; + while (kfifo_len(&hw->display_q) > 0) { + if (time_after(jiffies, timeout)) + break; + schedule(); + } } buf_spec_init(hw, true); @@ -10109,12 +10490,10 @@ struct vdec_h264_hw_s *hw = NULL; char *tmpbuf; int config_val; - if (pdata == NULL) { pr_info("\nammvdec_h264 memory resource undefined.\n"); return -EFAULT; } - pr_info("%s:cts test\n",__func__); hw = (struct vdec_h264_hw_s *)h264_alloc_hw_stru(&pdev->dev, sizeof(struct vdec_h264_hw_s), GFP_KERNEL); @@ -10125,14 +10504,22 @@ hw->id = pdev->id; hw->platform_dev = pdev; - snprintf(hw->vdec_name, sizeof(hw->vdec_name), + snprintf(hw->trace.vdec_name, sizeof(hw->trace.vdec_name), "h264-%d", hw->id); - snprintf(hw->pts_name, sizeof(hw->pts_name), - "%s-pts", hw->vdec_name); - snprintf(hw->new_q_name, sizeof(hw->new_q_name), - "%s-newframe_q", hw->vdec_name); - snprintf(hw->disp_q_name, sizeof(hw->disp_q_name), - "%s-dispframe_q", hw->vdec_name); + snprintf(hw->trace.pts_name, sizeof(hw->trace.pts_name), + "%s-pts", hw->trace.vdec_name); + snprintf(hw->trace.new_q_name, sizeof(hw->trace.new_q_name), + "%s-newframe_q", hw->trace.vdec_name); + snprintf(hw->trace.disp_q_name, sizeof(hw->trace.disp_q_name), + "%s-dispframe_q", hw->trace.vdec_name); + snprintf(hw->trace.decode_time_name, sizeof(hw->trace.decode_time_name), + "decoder_time%d", pdev->id); + snprintf(hw->trace.decode_run_time_name, sizeof(hw->trace.decode_run_time_name), + "decoder_run_time%d", pdev->id); + snprintf(hw->trace.decode_header_time_name, sizeof(hw->trace.decode_header_time_name), + "decoder_header_time%d", pdev->id); + snprintf(hw->trace.decode_work_time_name, sizeof(hw->trace.decode_work_time_name), + "decoder_work_time%d", pdev->id); /* the ctx from v4l2 driver. */ hw->v4l2_ctx = pdata->private; @@ -10169,6 +10556,7 @@ } if (pdata->config_len) { + dpb_print(DECODE_ID(hw), 0, "pdata->config=%s\n", pdata->config); /*use ptr config for doubel_write_mode, etc*/ if (get_config_int(pdata->config, "mh264_double_write_mode", &config_val) == 0) @@ -10218,6 +10606,16 @@ hw->discard_dv_data = config_val; dpb_print(DECODE_ID(hw), 0, "discard dv data\n"); } + + if (get_config_int(pdata->config, + "parm_v4l_metadata_config_flag", + &config_val) == 0) { + hw->metadata_config_flag = config_val; + hw->discard_dv_data = hw->metadata_config_flag & VDEC_CFG_FLAG_DV_NEGATIVE; + if (hw->discard_dv_data) + dpb_print(DECODE_ID(hw), 0, "discard dv data\n"); + } + } else hw->double_write_mode = double_write_mode; @@ -10234,9 +10632,6 @@ hw->enable_fence, hw->fence_usage); } - if (hw->enable_fence) - pdata->sync.usage = hw->fence_usage; - if (!hw->is_used_v4l) { hw->reorder_dpb_size_margin = reorder_dpb_size_margin; hw->canvas_mode = mem_map_mode; @@ -10289,11 +10684,6 @@ pdata->user_data_read = NULL; pdata->reset_userdata_fifo = NULL; #endif - -#ifdef VDEC_FCC_SUPPORT - pdata->wakeup_fcc_poll = vmh264_wakeup_fcc_poll; -#endif - if (pdata->use_vfm_path) { snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE, VFM_DEC_PROVIDER_NAME); @@ -10301,24 +10691,38 @@ } #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION else if (vdec_dual(pdata)) { - if (dv_toggle_prov_name) /*debug purpose*/ - snprintf(pdata->vf_provider_name, - VDEC_PROVIDER_NAME_SIZE, - (pdata->master) ? VFM_DEC_DVBL_PROVIDER_NAME : - VFM_DEC_DVEL_PROVIDER_NAME); - else - snprintf(pdata->vf_provider_name, - VDEC_PROVIDER_NAME_SIZE, - (pdata->master) ? VFM_DEC_DVEL_PROVIDER_NAME : - VFM_DEC_DVBL_PROVIDER_NAME); + if (!pdata->is_stream_mode_dv_multi) { + if (dv_toggle_prov_name) /*debug purpose*/ + snprintf(pdata->vf_provider_name, + VDEC_PROVIDER_NAME_SIZE, + (pdata->master) ? VFM_DEC_DVBL_PROVIDER_NAME : + VFM_DEC_DVEL_PROVIDER_NAME); + else + snprintf(pdata->vf_provider_name, + VDEC_PROVIDER_NAME_SIZE, + (pdata->master) ? VFM_DEC_DVEL_PROVIDER_NAME : + VFM_DEC_DVBL_PROVIDER_NAME); + } else { + if (dv_toggle_prov_name) /*debug purpose*/ + snprintf(pdata->vf_provider_name, + VDEC_PROVIDER_NAME_SIZE, + (pdata->master) ? VFM_DEC_DVBL_PROVIDER_NAME2 : + VFM_DEC_DVEL_PROVIDER_NAME2); + else + snprintf(pdata->vf_provider_name, + VDEC_PROVIDER_NAME_SIZE, + (pdata->master) ? VFM_DEC_DVEL_PROVIDER_NAME2 : + VFM_DEC_DVBL_PROVIDER_NAME2); + } } #endif else snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE, PROVIDER_NAME ".%02x", pdev->id & 0xff); - vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name, - &vf_provider_ops, pdata); + if (!hw->is_used_v4l) + vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name, + &vf_provider_ops, pdata); platform_set_drvdata(pdev, pdata); @@ -10341,7 +10745,7 @@ DCAC_READ_MARGIN; if (hw->mmu_enable) { u32 extif_size = EXTIF_BUF_SIZE; - if (get_cpu_major_id() >= MESON_CPU_MAJOR_ID_G12A) + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) extif_size <<= 1; if (decoder_bmmu_box_alloc_buf_phy(hw->bmmu_box, BMMU_EXTIF_IDX, extif_size, DRIVER_NAME, &hw->extif_addr) < 0) { @@ -10404,19 +10808,8 @@ dpb_print(DECODE_ID(hw), 0, "ammvdec_h264 mem-addr=%lx,buff_offset=%x,buf_start=%lx\n", pdata->mem_start, hw->buf_offset, hw->cma_alloc_addr); - if (vdec_is_support_4k() || - (clk_adj_frame_count > (VDEC_CLOCK_ADJUST_FRAME - 1))) - vdec_source_changed(VFORMAT_H264, 3840, 2160, 60); - else if (pdata->sys_info->height * pdata->sys_info->width < 1280 * 720) - { - vdec_source_changed(VFORMAT_H264, 1280, 720, 29); - } else if (pdata->sys_info->height * pdata->sys_info->width < 1920 * 1080) - { - vdec_source_changed(VFORMAT_H264, 1920, 1080, 29); - } else - { - vdec_source_changed(VFORMAT_H264, 3840, 2160, 60); - } + vdec_source_changed(VFORMAT_H264, 3840, 2160, 60); + if (hw->mmu_enable) hevc_source_changed(VFORMAT_HEVC, 3840, 2160, 60); @@ -10454,10 +10847,19 @@ display_frame_count[DECODE_ID(hw)] = 0; decode_frame_count[DECODE_ID(hw)] = 0; hw->dpb.without_display_mode = without_display_mode; - + mutex_init(&hw->fence_mutex); if (hw->enable_fence) { + pdata->sync = vdec_sync_get(); + if (!pdata->sync) { + dpb_print(DECODE_ID(hw), 0, "alloc fence timeline error\n"); + ammvdec_h264_mmu_release(hw); + h264_free_hw_stru(&pdev->dev, (void *)hw); + pdata->dec_status = NULL; + return -ENODEV; + } + pdata->sync->usage = hw->fence_usage; /* creat timeline. */ - vdec_timeline_create(&pdata->sync, DRIVER_NAME); + vdec_timeline_create(pdata->sync, DRIVER_NAME); } return 0; @@ -10467,7 +10869,6 @@ struct vdec_sync *sync) { ulong expires; - int i; /* clear display pool. */ clear_refer_bufs(hw); @@ -10483,14 +10884,7 @@ } } - for (i = 0; i < VF_POOL_SIZE; i++) { - struct vframe_s *vf = &hw->vfpool[hw->cur_pool][i]; - - if (vf->fence) { - vdec_fence_put(vf->fence); - vf->fence = NULL; - } - } + pr_info("fence start release\n"); /* decreases refcnt of timeline. */ vdec_timeline_put(sync); @@ -10564,7 +10958,7 @@ } if (hw->enable_fence) - vdec_fence_release(hw, &vdec->sync); + vdec_fence_release(hw, vdec->sync); ammvdec_h264_mmu_release(hw); h264_free_hw_stru(&pdev->dev, (void *)hw); @@ -10574,32 +10968,16 @@ } /****************************************/ -#ifdef CONFIG_PM -static int mh264_suspend(struct device *dev) -{ - amvdec_suspend(to_platform_device(dev), dev->power.power_state); - return 0; -} - -static int mh264_resume(struct device *dev) -{ - amvdec_resume(to_platform_device(dev)); - return 0; -} - -static const struct dev_pm_ops mh264_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(mh264_suspend, mh264_resume) -}; -#endif static struct platform_driver ammvdec_h264_driver = { .probe = ammvdec_h264_probe, .remove = ammvdec_h264_remove, +#ifdef CONFIG_PM + .suspend = amvdec_suspend, + .resume = amvdec_resume, +#endif .driver = { .name = DRIVER_NAME, -#ifdef CONFIG_PM - .pm = &mh264_pm_ops, -#endif } }; @@ -10638,6 +11016,7 @@ static int __init ammvdec_h264_driver_init_module(void) { + pr_info("ammvdec_h264 module init\n"); if (platform_driver_register(&ammvdec_h264_driver)) { pr_info("failed to register ammvdec_h264 driver\n"); @@ -10647,15 +11026,25 @@ if (vdec_is_support_4k()) { if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_TXLX) { ammvdec_h264_profile.profile = - "4k, dwrite, compressed, frame_dv, fence"; + "4k, dwrite, compressed, frame_dv, fence, v4l"; } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXTVBB) { - ammvdec_h264_profile.profile = "4k, frame_dv, fence"; + ammvdec_h264_profile.profile = "4k, frame_dv, fence, v4l"; + } + } else { + if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5D || is_cpu_s4_s805x2()) { + ammvdec_h264_profile.profile = + "dwrite, compressed, frame_dv, v4l"; + } else { + ammvdec_h264_profile.profile = + "dwrite, compressed, v4l"; } } vcodec_profile_register(&ammvdec_h264_profile); INIT_REG_NODE_CONFIGS("media.decoder", &hm264_node, "mh264", hm264_configs, CONFIG_FOR_RW); + + vcodec_feature_register(VFORMAT_H264, 0); return 0; } @@ -10816,6 +11205,9 @@ module_param(stream_mode_start_num, uint, 0664); MODULE_PARM_DESC(stream_mode_start_num, "\n stream_mode_start_num\n"); +module_param(colocate_old_cal, uint, 0664); +MODULE_PARM_DESC(colocate_old_cal, "\n amvdec_mh264 colocate_old_cal\n"); + /* module_param(trigger_task, uint, 0664); MODULE_PARM_DESC(trigger_task, "\n amvdec_h264 trigger_task\n");
diff --git a/drivers/frame_provider/decoder/h265/vh265.c b/drivers/frame_provider/decoder/h265/vh265.c old mode 100755 new mode 100644 index 2e9bafc..d5945ce --- a/drivers/frame_provider/decoder/h265/vh265.c +++ b/drivers/frame_provider/decoder/h265/vh265.c
@@ -38,7 +38,10 @@ #include <linux/dma-contiguous.h> #include <linux/slab.h> #include <linux/mm.h> -#include <linux/amlogic/tee.h> +#include <linux/timer.h> +//#include <linux/amlogic/tee.h> +#include <uapi/linux/tee.h> +#include <linux/sched/clock.h> #include "../../../stream_input/amports/amports_priv.h" #include <linux/amlogic/media/codec_mm/codec_mm.h> #include "../utils/decoder_mmu_box.h" @@ -57,6 +60,8 @@ #define HEVC_8K_LFTOFFSET_FIX #define SUPPORT_LONG_TERM_RPS +//#define CO_MV_COMPRESS + #define CONSTRAIN_MAX_BUF_NUM #define SWAP_HEVC_UCODE @@ -81,7 +86,7 @@ #define DB_NUM 20 #define MAX_FRAME_4K_NUM 0x1200 -#define MAX_FRAME_8K_NUM (0x1200*4) +#define MAX_FRAME_8K_NUM ((MAX_FRAME_4K_NUM) * 4) //#define FRAME_MMU_MAP_SIZE (MAX_FRAME_4K_NUM * 4) #define H265_MMU_MAP_BUFFER HEVC_ASSIST_SCRATCH_7 @@ -89,8 +94,16 @@ #define HEVC_ASSIST_MMU_MAP_ADDR 0x3009 #define HEVC_CM_HEADER_START_ADDR 0x3628 +#define HEVC_CM_HEADER_START_ADDR2 0x364a #define HEVC_SAO_MMU_VH1_ADDR 0x363b #define HEVC_SAO_MMU_VH0_ADDR 0x363a +#define HEVC_SAO_MMU_VH0_ADDR2 0x364d +#define HEVC_SAO_MMU_VH1_ADDR2 0x364e + +#define HEVC_SAO_MMU_DMA_CTRL2 0x364c +#define HEVC_SAO_MMU_STATUS2 0x3650 +#define HEVC_DW_VH0_ADDDR 0x365e +#define HEVC_DW_VH1_ADDDR 0x365f #define HEVC_DBLK_CFGB 0x350b #define HEVCD_MPP_DECOMP_AXIURG_CTL 0x34c7 @@ -104,9 +117,11 @@ #include "../utils/amvdec.h" #include <linux/amlogic/media/video_sink/video.h> #include <linux/amlogic/media/codec_mm/configs.h> +#include "../utils/vdec_feature.h" #define SEND_LMEM_WITH_RPM #define SUPPORT_10BIT +#define H265_10B_MMU_DW /* #define ERROR_HANDLE_DEBUG */ #ifndef STAT_KTHREAD @@ -133,6 +148,7 @@ #define MAX_SIZE_8K (8192 * 4608) #define MAX_SIZE_4K (4096 * 2304) +#define MAX_SIZE_2K (1920 * 1088) #define IS_8K_SIZE(w, h) (((w) * (h)) > MAX_SIZE_4K) #define IS_4K_SIZE(w, h) (((w) * (h)) > (1920*1088)) @@ -167,10 +183,11 @@ #endif static void vh265_prot_init(struct hevc_state_s *hevc); static int vh265_local_init(struct hevc_state_s *hevc); -static void vh265_check_timer_func(unsigned long arg); +static void vh265_check_timer_func(struct timer_list *timer); static void config_decode_mode(struct hevc_state_s *hevc); static int check_data_size(struct vdec_s *vdec); + static const char vh265_dec_id[] = "vh265-dev"; #define PROVIDER_NAME "decoder.h265" @@ -239,6 +256,11 @@ #define HEVC_CM_HEADER_LENGTH 0x3629 #define HEVC_CM_HEADER_OFFSET 0x362b #define HEVC_SAO_CTRL9 0x362d + +#define HEVC_CM_BODY_LENGTH2 0x3663 +#define HEVC_CM_HEADER_OFFSET2 0x3664 +#define HEVC_CM_HEADER_LENGTH2 0x3665 + #define LOSLESS_COMPRESS_MODE /* DOUBLE_WRITE_MODE is enabled only when NV21 8 bit output is needed */ /* double_write_mode: @@ -248,6 +270,7 @@ * 3, (1/4):(1/4) ratio, with both compressed frame included * 4, (1/2):(1/2) ratio; * 5, (1/2):(1/2) ratio, with both compressed frame included + * 8, (1/8):(1/8) ratio, from t7 * 0x10, double write only * 0x100, if > 1080p,use mode 4,else use mode 1; * 0x200, if > 1080p,use mode 2,else use mode 1; @@ -330,7 +353,14 @@ static u32 dbg_cmd; static u32 dump_nal; static u32 dbg_skip_decode_index; -static u32 endian = 0xff0; +/* + * bit 0~3, for HEVCD_IPP_AXIIF_CONFIG endian config + * bit 8~23, for HEVC_SAO_CTRL1 endian config + */ +static u32 endian; +#define HEVC_CONFIG_BIG_ENDIAN ((0x880 << 8) | 0x8) +#define HEVC_CONFIG_LITTLE_ENDIAN ((0xff0 << 8) | 0xf) + #ifdef ERROR_HANDLE_DEBUG static u32 dbg_nal_skip_flag; /* bit[0], skip vps; bit[1], skip sps; bit[2], skip pps */ @@ -474,8 +504,7 @@ *bit 9: 0, discard dirty data on playback start * 1, do not discard dirty data on playback start *bit 10:0, when ucode always returns again, it supports discarding data - * 1, When ucode always returns again, it does not support discarding data - * + * 1, When ucode always returns again, it does not support discarding data */ static u32 error_handle_policy; @@ -960,6 +989,10 @@ struct buff_s dblk_data2; struct buff_s mmu_vbh; struct buff_s cm_header; +#ifdef H265_10B_MMU_DW + struct buff_s mmu_vbh_dw; + struct buff_s cm_header_dw; +#endif struct buff_s mpred_above; #ifdef MV_USE_FIXED_BUF struct buff_s mpred_mv; @@ -971,7 +1004,7 @@ //#define VBH_BUF_SIZE (2 * 16 * 2304) //#define VBH_BUF_COUNT 4 - /*mmu_vbh buf is used by HEVC_SAO_MMU_VH0_ADDR, HEVC_SAO_MMU_VH1_ADDR*/ +/*mmu_vbh buf is used by HEVC_SAO_MMU_VH0_ADDR, HEVC_SAO_MMU_VH1_ADDR*/ #define VBH_BUF_SIZE_1080P 0x3000 #define VBH_BUF_SIZE_4K 0x5000 #define VBH_BUF_SIZE_8K 0xa000 @@ -983,12 +1016,288 @@ #define DW_VBH_BUF_SIZE_8K (VBH_BUF_SIZE_8K * 2) #define DW_VBH_BUF_SIZE(bufspec) (bufspec->mmu_vbh_dw.buf_size / 4) -#define WORK_BUF_SPEC_NUM 3 +/* necessary 4K page size align for t7/t3 decoder and after */ +#define WORKBUF_ALIGN(addr) (ALIGN(addr, PAGE_SIZE)) + +#define WORK_BUF_SPEC_NUM 6 static struct BuffInfo_s amvh265_workbuff_spec[WORK_BUF_SPEC_NUM] = { { /* 8M bytes */ .max_width = 1920, .max_height = 1088, + .ipp = { + /* IPP work space calculation : + * 4096 * (Y+CbCr+Flags) = 12k, round to 16k + */ + .buf_size = 0x4000, + }, + .sao_abv = { + .buf_size = 0x30000, + }, + .sao_vb = { + .buf_size = 0x30000, + }, + .short_term_rps = { + /* SHORT_TERM_RPS - Max 64 set, 16 entry every set, + * total 64x16x2 = 2048 bytes (0x800) + */ + .buf_size = 0x800, + }, + .vps = { + /* VPS STORE AREA - Max 16 VPS, each has 0x80 bytes, + * total 0x0800 bytes + */ + .buf_size = 0x800, + }, + .sps = { + /* SPS STORE AREA - Max 16 SPS, each has 0x80 bytes, + * total 0x0800 bytes + */ + .buf_size = 0x800, + }, + .pps = { + /* PPS STORE AREA - Max 64 PPS, each has 0x80 bytes, + * total 0x2000 bytes + */ + .buf_size = 0x2000, + }, + .sao_up = { + /* SAO UP STORE AREA - Max 640(10240/16) LCU, + * each has 16 bytes total 0x2800 bytes + */ + .buf_size = 0x2800, + }, + .swap_buf = { + /* 256cyclex64bit = 2K bytes 0x800 + * (only 144 cycles valid) + */ + .buf_size = 0x800, + }, + .swap_buf2 = { + .buf_size = 0x800, + }, + .scalelut = { + /* support up to 32 SCALELUT 1024x32 = + * 32Kbytes (0x8000) + */ + .buf_size = 0x8000, + }, + .dblk_para = { +#ifdef SUPPORT_10BIT + .buf_size = 0x40000, +#else + /* DBLK -> Max 256(4096/16) LCU, each para + *512bytes(total:0x20000), data 1024bytes(total:0x40000) + */ + .buf_size = 0x20000, +#endif + }, + .dblk_data = { + .buf_size = 0x40000, + }, + .dblk_data2 = { + .buf_size = 0x80000 * 2, + }, /*dblk data for adapter*/ + .mmu_vbh = { + .buf_size = 0x5000, /*2*16*2304/4, 4K*/ + }, +#if 0 + .cm_header = {/* 0x44000 = ((1088*2*1024*4)/32/4)*(32/8)*/ + .buf_size = MMU_COMPRESS_HEADER_SIZE * + (MAX_REF_PIC_NUM + 1), + }, +#endif + .mpred_above = { + .buf_size = 0x8000, + }, +#ifdef MV_USE_FIXED_BUF + .mpred_mv = {/* 1080p, 0x40000 per buffer */ + .buf_size = 0x40000 * MAX_REF_PIC_NUM, + }, +#endif + .rpm = { + .buf_size = RPM_BUF_SIZE, + }, + .lmem = { + .buf_size = 0x500 * 2, + } + }, + { + .max_width = 4096, + .max_height = 2048, + .ipp = { + /* IPP work space calculation : + * 4096 * (Y+CbCr+Flags) = 12k, round to 16k + */ + .buf_size = 0x1e00, + }, + .sao_abv = { + .buf_size = 0, //0x30000, + }, + .sao_vb = { + .buf_size = 0, //0x30000, + }, + .short_term_rps = { + /* SHORT_TERM_RPS - Max 64 set, 16 entry every set, + * total 64x16x2 = 2048 bytes (0x800) + */ + .buf_size = 0x800, + }, + .vps = { + /* VPS STORE AREA - Max 16 VPS, each has 0x80 bytes, + * total 0x0800 bytes + */ + .buf_size = 0x800, + }, + .sps = { + /* SPS STORE AREA - Max 16 SPS, each has 0x80 bytes, + * total 0x0800 bytes + */ + .buf_size = 0x800, + }, + .pps = { + /* PPS STORE AREA - Max 64 PPS, each has 0x80 bytes, + * total 0x2000 bytes + */ + .buf_size = 0x2000, + }, + .sao_up = { + /* SAO UP STORE AREA - Max 640(10240/16) LCU, + * each has 16 bytes total 0x2800 bytes + */ + .buf_size = 0x2800, + }, + .swap_buf = { + /* 256cyclex64bit = 2K bytes 0x800 + * (only 144 cycles valid) + */ + .buf_size = 0x800, + }, + .swap_buf2 = { + .buf_size = 0x800, + }, + .scalelut = { + /* support up to 32 SCALELUT 1024x32 = 32Kbytes + * (0x8000) + */ + .buf_size = 0x8000, + }, + .dblk_para = { + /* DBLK -> Max 256(4096/16) LCU, each para + * 512bytes(total:0x20000), + * data 1024bytes(total:0x40000) + */ + .buf_size = 0x20000, + }, + .dblk_data = { + .buf_size = 0x80000, + }, + .dblk_data2 = { + .buf_size = 0x80000, + }, /*dblk data for adapter*/ + .mmu_vbh = { + .buf_size = 0x5000, /*2*16*2304/4, 4K*/ + }, +#if 0 + .cm_header = {/*0x44000 = ((1088*2*1024*4)/32/4)*(32/8)*/ + .buf_size = MMU_COMPRESS_HEADER_SIZE * + (MAX_REF_PIC_NUM + 1), + }, +#endif + .mpred_above = { + .buf_size = 0x8000, + }, +#ifdef MV_USE_FIXED_BUF + .mpred_mv = { + /* .buf_size = 0x100000*16, + //4k2k , 0x100000 per buffer */ + /* 4096x2304 , 0x120000 per buffer */ + .buf_size = MPRED_4K_MV_BUF_SIZE * MAX_REF_PIC_NUM, + }, +#endif + .rpm = { + .buf_size = RPM_BUF_SIZE, + }, + .lmem = { + .buf_size = 0x500 * 2, + } + }, + + { + .max_width = 4096*2, + .max_height = 2048*2, + .ipp = { + // IPP work space calculation : 4096 * (Y+CbCr+Flags) = 12k, round to 16k + .buf_size = 0x4000*2, + }, + .sao_abv = { + .buf_size = 0x30000*2, + }, + .sao_vb = { + .buf_size = 0x30000*2, + }, + .short_term_rps = { + // SHORT_TERM_RPS - Max 64 set, 16 entry every set, total 64x16x2 = 2048 bytes (0x800) + .buf_size = 0x800, + }, + .vps = { + // VPS STORE AREA - Max 16 VPS, each has 0x80 bytes, total 0x0800 bytes + .buf_size = 0x800, + }, + .sps = { + // SPS STORE AREA - Max 16 SPS, each has 0x80 bytes, total 0x0800 bytes + .buf_size = 0x800, + }, + .pps = { + // PPS STORE AREA - Max 64 PPS, each has 0x80 bytes, total 0x2000 bytes + .buf_size = 0x2000, + }, + .sao_up = { + // SAO UP STORE AREA - Max 640(10240/16) LCU, each has 16 bytes total 0x2800 bytes + .buf_size = 0x2800*2, + }, + .swap_buf = { + // 256cyclex64bit = 2K bytes 0x800 (only 144 cycles valid) + .buf_size = 0x800, + }, + .swap_buf2 = { + .buf_size = 0x800, + }, + .scalelut = { + // support up to 32 SCALELUT 1024x32 = 32Kbytes (0x8000) + .buf_size = 0x8000*2, + }, + .dblk_para = {.buf_size = 0x40000*2, }, // dblk parameter + .dblk_data = {.buf_size = 0x80000*2, }, // dblk data for left/top + .dblk_data2 = {.buf_size = 0x80000*2, }, // dblk data for adapter + .mmu_vbh = { + .buf_size = 0x5000*2, //2*16*2304/4, 4K + }, +#if 0 + .cm_header = { + .buf_size = MMU_COMPRESS_8K_HEADER_SIZE * + MAX_REF_PIC_NUM, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) + }, +#endif + .mpred_above = { + .buf_size = 0x8000*2, + }, +#ifdef MV_USE_FIXED_BUF + .mpred_mv = { + .buf_size = MPRED_8K_MV_BUF_SIZE * MAX_REF_PIC_NUM, //4k2k , 0x120000 per buffer + }, +#endif + .rpm = { + .buf_size = RPM_BUF_SIZE, + }, + .lmem = { + .buf_size = 0x500 * 2, + }, + }, + { + /* 8M bytes */ + .max_width = 1920, + .max_height = 1088, .ipp = {/*checked*/ /* IPP work space calculation : * 4096 * (Y+CbCr+Flags) = 12k, round to 16k @@ -1058,6 +1367,16 @@ (MAX_REF_PIC_NUM + 1), }, #endif +#ifdef H265_10B_MMU_DW + .mmu_vbh_dw = {/*checked*/ + .buf_size = DW_VBH_BUF_SIZE_1080P, //VBH_BUF_SIZE * VBH_BUF_COUNT, //2*16*2304/4, 4K + }, +#ifdef USE_FIXED_MMU_DW_HEADER + .cm_header_dw = {/*checked*/ + .buf_size = MMU_COMPRESS_HEADER_SIZE_1080P * DB_NUM, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) + }, +#endif +#endif .mpred_above = {/*checked*/ .buf_size = 0x1e00, }, @@ -1135,7 +1454,7 @@ }, .dblk_para = {.buf_size = 0x19100, }, // dblk parameter .dblk_data = {.buf_size = 0x88800, }, // dblk data for left/top - .dblk_data2 = {.buf_size = 0x80000, }, // dblk data for adapter + .dblk_data2 = {.buf_size = 0x48800, }, // dblk data for adapter .mmu_vbh = { .buf_size = VBH_BUF_SIZE_4K, /*2*16*2304/4, 4K*/ }, @@ -1145,6 +1464,16 @@ (MAX_REF_PIC_NUM + 1), }, #endif +#ifdef H265_10B_MMU_DW + .mmu_vbh_dw = { + .buf_size = DW_VBH_BUF_SIZE_4K, //VBH_BUF_SIZE * VBH_BUF_COUNT, //2*16*(more than 2304)/4, 4K + }, +#ifdef USE_FIXED_MMU_DW_HEADER + .cm_header_dw = { + .buf_size = MMU_COMPRESS_HEADER_SIZE_4K * DB_NUM, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) + }, +#endif +#endif .mpred_above = { .buf_size = 0x4000, }, @@ -1220,6 +1549,16 @@ MAX_REF_PIC_NUM, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) }, #endif +#ifdef H265_10B_MMU_DW + .mmu_vbh_dw = { + .buf_size = DW_VBH_BUF_SIZE_8K, //VBH_BUF_SIZE * VBH_BUF_COUNT, //2*16*2304/4, 4K + }, +#ifdef USE_FIXED_MMU_DW_HEADER + .cm_header_dw = { + .buf_size = MMU_COMPRESS_HEADER_SIZE_8K * DB_NUM, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) + }, +#endif +#endif .mpred_above = { .buf_size = 0x8000, }, @@ -1240,64 +1579,66 @@ static void init_buff_spec(struct hevc_state_s *hevc, struct BuffInfo_s *buf_spec) { - buf_spec->ipp.buf_start = buf_spec->start_adr; + buf_spec->ipp.buf_start = + WORKBUF_ALIGN(buf_spec->start_adr); buf_spec->sao_abv.buf_start = - buf_spec->ipp.buf_start + buf_spec->ipp.buf_size; - + WORKBUF_ALIGN(buf_spec->ipp.buf_start + buf_spec->ipp.buf_size); buf_spec->sao_vb.buf_start = - buf_spec->sao_abv.buf_start + buf_spec->sao_abv.buf_size; + WORKBUF_ALIGN(buf_spec->sao_abv.buf_start + buf_spec->sao_abv.buf_size); buf_spec->short_term_rps.buf_start = - buf_spec->sao_vb.buf_start + buf_spec->sao_vb.buf_size; + WORKBUF_ALIGN(buf_spec->sao_vb.buf_start + buf_spec->sao_vb.buf_size); buf_spec->vps.buf_start = - buf_spec->short_term_rps.buf_start + - buf_spec->short_term_rps.buf_size; + WORKBUF_ALIGN(buf_spec->short_term_rps.buf_start + buf_spec->short_term_rps.buf_size); buf_spec->sps.buf_start = - buf_spec->vps.buf_start + buf_spec->vps.buf_size; + WORKBUF_ALIGN(buf_spec->vps.buf_start + buf_spec->vps.buf_size); buf_spec->pps.buf_start = - buf_spec->sps.buf_start + buf_spec->sps.buf_size; + WORKBUF_ALIGN(buf_spec->sps.buf_start + buf_spec->sps.buf_size); buf_spec->sao_up.buf_start = - buf_spec->pps.buf_start + buf_spec->pps.buf_size; + WORKBUF_ALIGN(buf_spec->pps.buf_start + buf_spec->pps.buf_size); buf_spec->swap_buf.buf_start = - buf_spec->sao_up.buf_start + buf_spec->sao_up.buf_size; + WORKBUF_ALIGN(buf_spec->sao_up.buf_start + buf_spec->sao_up.buf_size); buf_spec->swap_buf2.buf_start = - buf_spec->swap_buf.buf_start + buf_spec->swap_buf.buf_size; + WORKBUF_ALIGN(buf_spec->swap_buf.buf_start + buf_spec->swap_buf.buf_size); buf_spec->scalelut.buf_start = - buf_spec->swap_buf2.buf_start + buf_spec->swap_buf2.buf_size; + WORKBUF_ALIGN(buf_spec->swap_buf2.buf_start + buf_spec->swap_buf2.buf_size); buf_spec->dblk_para.buf_start = - buf_spec->scalelut.buf_start + buf_spec->scalelut.buf_size; + WORKBUF_ALIGN(buf_spec->scalelut.buf_start + buf_spec->scalelut.buf_size); buf_spec->dblk_data.buf_start = - buf_spec->dblk_para.buf_start + buf_spec->dblk_para.buf_size; + WORKBUF_ALIGN(buf_spec->dblk_para.buf_start + buf_spec->dblk_para.buf_size); buf_spec->dblk_data2.buf_start = - buf_spec->dblk_data.buf_start + buf_spec->dblk_data.buf_size; + WORKBUF_ALIGN(buf_spec->dblk_data.buf_start + buf_spec->dblk_data.buf_size); buf_spec->mmu_vbh.buf_start = - buf_spec->dblk_data2.buf_start + buf_spec->dblk_data2.buf_size; + WORKBUF_ALIGN(buf_spec->dblk_data2.buf_start + buf_spec->dblk_data2.buf_size); +#ifdef H265_10B_MMU_DW + buf_spec->mmu_vbh_dw.buf_start = + WORKBUF_ALIGN(buf_spec->mmu_vbh.buf_start + buf_spec->mmu_vbh.buf_size); + buf_spec->cm_header_dw.buf_start = + WORKBUF_ALIGN(buf_spec->mmu_vbh_dw.buf_start + buf_spec->mmu_vbh_dw.buf_size); buf_spec->mpred_above.buf_start = - buf_spec->mmu_vbh.buf_start + buf_spec->mmu_vbh.buf_size; + WORKBUF_ALIGN(buf_spec->cm_header_dw.buf_start + buf_spec->cm_header_dw.buf_size); +#else + buf_spec->mpred_above.buf_start = + WORKBUF_ALIGN(buf_spec->mmu_vbh.buf_start + buf_spec->mmu_vbh.buf_size); +#endif #ifdef MV_USE_FIXED_BUF buf_spec->mpred_mv.buf_start = - buf_spec->mpred_above.buf_start + - buf_spec->mpred_above.buf_size; - + WORKBUF_ALIGN(buf_spec->mpred_above.buf_start + buf_spec->mpred_above.buf_size); buf_spec->rpm.buf_start = - buf_spec->mpred_mv.buf_start + - buf_spec->mpred_mv.buf_size; + WORKBUF_ALIGN(buf_spec->mpred_mv.buf_start + buf_spec->mpred_mv.buf_size); #else buf_spec->rpm.buf_start = - buf_spec->mpred_above.buf_start + - buf_spec->mpred_above.buf_size; + WORKBUF_ALIGN(buf_spec->mpred_above.buf_start + buf_spec->mpred_above.buf_size); #endif buf_spec->lmem.buf_start = - buf_spec->rpm.buf_start + - buf_spec->rpm.buf_size; + WORKBUF_ALIGN(buf_spec->rpm.buf_start + buf_spec->rpm.buf_size); buf_spec->end_adr = - buf_spec->lmem.buf_start + - buf_spec->lmem.buf_size; + WORKBUF_ALIGN(buf_spec->lmem.buf_start + buf_spec->lmem.buf_size); if (hevc && get_dbg_flag2(hevc)) { hevc_print(hevc, 0, - "%s workspace (%x %x) size = %x\n", __func__, - buf_spec->start_adr, buf_spec->end_adr, - buf_spec->end_adr - buf_spec->start_adr); + "%s workspace (%x %x) size = %x\n", __func__, + buf_spec->start_adr, buf_spec->end_adr, + buf_spec->end_adr - buf_spec->start_adr); hevc_print(hevc, 0, "ipp.buf_start :%x\n", @@ -1341,6 +1682,14 @@ hevc_print(hevc, 0, "dblk_data2.buf_start :%x\n", buf_spec->dblk_data2.buf_start); +#ifdef H265_10B_MMU_DW + hevc_print(hevc, 0, + "mmu_vbh_dw.buf_start :%x\n", + buf_spec->mmu_vbh_dw.buf_start); + hevc_print(hevc, 0, + "cm_header_dw.buf_start :%x\n", + buf_spec->cm_header_dw.buf_start); +#endif hevc_print(hevc, 0, "mpred_above.buf_start :%x\n", buf_spec->mpred_above.buf_start); @@ -1427,6 +1776,9 @@ unsigned int dw_y_adr; unsigned int dw_u_v_adr; #endif + u32 luma_size; + u32 chroma_size; + int mc_canvas_y; int mc_canvas_u_v; int width; @@ -1445,6 +1797,9 @@ #ifdef LOSLESS_COMPRESS_MODE unsigned int losless_comp_body_size; #endif +#ifdef H265_10B_MMU_DW + u32 header_dw_adr; +#endif unsigned char pic_struct; int vf_ref; @@ -1477,11 +1832,10 @@ u32 hw_decode_time; u32 frame_size; // For frame base mode - bool vframe_bound; bool ip_mode; u32 hdr10p_data_size; char *hdr10p_data_buf; - struct fence *fence; + struct dma_fence *fence; bool show_frame; } /*PIC_t */; @@ -1500,6 +1854,8 @@ #define SEI_MASTER_DISPLAY_COLOR_MASK 0x00000001 #define SEI_CONTENT_LIGHT_LEVEL_MASK 0x00000002 #define SEI_HDR10PLUS_MASK 0x00000004 +#define SEI_HDR_CUVA_MASK 0x00000008 + #define VF_POOL_SIZE 32 @@ -1516,7 +1872,6 @@ #define DEC_RESULT_EOS 9 #define DEC_RESULT_FORCE_EXIT 10 #define DEC_RESULT_FREE_CANVAS 11 -#define DEC_RESULT_DISCARD_DATA 12 static void vh265_work(struct work_struct *work); @@ -1530,6 +1885,11 @@ uint8_t data; /*will alloc more size*/ }; +struct mh265_fence_vf_t { + u32 used_size; + struct vframe_s *fence_vf[VF_POOL_SIZE]; +}; + struct hevc_state_s { #ifdef MULTI_INSTANCE_SUPPORT struct platform_device *platform_dev; @@ -1756,6 +2116,12 @@ void *mmu_box; void *bmmu_box; int mmu_enable; +#ifdef H265_10B_MMU_DW + void *frame_dw_mmu_map_addr; + dma_addr_t frame_dw_mmu_map_phy_addr; + void *mmu_box_dw; + int dw_mmu_enable; +#endif unsigned int dec_status; @@ -1781,8 +2147,8 @@ u32 start_shift_bytes; u32 vf_pre_count; - u32 vf_get_count; - u32 vf_put_count; + atomic_t vf_get_count; + atomic_t vf_put_count; #ifdef SWAP_HEVC_UCODE dma_addr_t mc_dma_handle; void *mc_cpu_addr; @@ -1812,6 +2178,7 @@ u32 skip_nal_count; bool is_swap; bool is_4k; + int frameinfo_enable; struct vframe_qos_s vframe_qos; bool is_used_v4l; @@ -1820,7 +2187,6 @@ u32 mem_map_mode; u32 performance_profile; struct vdec_info *gvs; - u32 res_ch_flag; bool ip_mode; u32 kpi_first_i_comming; u32 kpi_first_i_decoded; @@ -1835,18 +2201,21 @@ bool discard_dv_data; bool enable_fence; int fence_usage; + int buffer_wrap[MAX_REF_PIC_NUM]; int low_latency_flag; + u32 metadata_config_flag; + int last_width; + int last_height; + int used_buf_num; u32 dirty_shift_flag; - char vdec_name[32]; - char set_canvas0_addr[32]; - char get_canvas0_addr[32]; - char put_canvas0_addr[32]; - char vf_put_name[32]; - char vf_get_name[32]; - char new_q_name[32]; - char disp_q_name[32]; - char pts_name[32]; + u32 endian; + ulong fb_token; int dec_again_cnt; + struct mh265_fence_vf_t fence_vf_s; + struct mutex fence_mutex; + dma_addr_t rdma_phy_adr; + unsigned *rdma_adr; + struct trace_decoder_name trace; } /*hevc_stru_t */; #ifdef AGAIN_HAS_THRESHOLD @@ -1870,6 +2239,9 @@ int max = (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1)? MAX_SIZE_8K : MAX_SIZE_4K; + if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5D) + max = MAX_SIZE_2K; + if (w < 0 || h < 0) return true; @@ -1935,7 +2307,7 @@ #ifdef SUPPORT_10BIT /* Losless compression body buffer size 4K per 64x32 (jt) */ -static int compute_losless_comp_body_size(struct hevc_state_s *hevc, +static int compute_losless_comp_body_size(struct hevc_state_s *hevc, int width, int height, int mem_saving_mode) { int width_x64; @@ -1958,7 +2330,7 @@ } /* Losless compression header buffer size 32bytes per 128x64 (jt) */ -static int compute_losless_comp_header_size(int width, int height) +static int compute_losless_comp_header_size(int width, int height) { int width_x128; int height_x64; @@ -2042,10 +2414,18 @@ #ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC static int get_valid_double_write_mode(struct hevc_state_s *hevc) { - return (hevc->m_ins_flag && + u32 dw = (hevc->m_ins_flag && ((double_write_mode & 0x80000000) == 0)) ? hevc->double_write_mode : (double_write_mode & 0x7fffffff); + if (dw & 0x20) { + if ((get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_T3) + && ((dw & 0xf) == 2 || (dw & 0xf) == 3)) { + pr_info("MMU doueble write 1:4 not supported !!!\n"); + dw = 0; + } + } + return dw; } static int get_dynamic_buf_num_margin(struct hevc_state_s *hevc) @@ -2063,30 +2443,15 @@ int w = hevc->pic_w; int h = hevc->pic_h; u32 dw = 0x1; /*1:1*/ - switch (valid_dw_mode) { - case 0x100: - if (w > 1920 && h > 1088) - dw = 0x4; /*1:2*/ - break; - case 0x200: - if (w > 1920 && h > 1088) - dw = 0x2; /*1:4*/ - break; - case 0x300: - if (w > 1280 && h > 720) - dw = 0x4; /*1:2*/ - break; - default: - dw = valid_dw_mode; - break; - } - return dw; -} -static int v4l_parser_get_double_write_mode(struct hevc_state_s *hevc, int w, int h) -{ - u32 valid_dw_mode = get_valid_double_write_mode(hevc); - u32 dw = 0x1; /*1:1*/ + if (hevc->is_used_v4l) { + unsigned int out; + + vdec_v4l_get_dw_mode(hevc->v4l2_ctx, &out); + dw = out; + return dw; + } + switch (valid_dw_mode) { case 0x100: if (w > 1920 && h > 1088) @@ -2115,19 +2480,6 @@ return dw; } - -static int get_double_write_ratio(struct hevc_state_s *hevc, - int dw_mode) -{ - int ratio = 1; - if ((dw_mode == 2) || - (dw_mode == 3)) - ratio = 4; - else if ((dw_mode == 4) || - (dw_mode == 5)) - ratio = 2; - return ratio; -} #ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC static unsigned char get_idx(struct hevc_state_s *hevc) { @@ -2140,7 +2492,7 @@ static int hevc_print(struct hevc_state_s *hevc, int flag, const char *fmt, ...) { -#define HEVC_PRINT_BUF 256 +#define HEVC_PRINT_BUF 512 unsigned char buf[HEVC_PRINT_BUF]; int len = 0; #ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC @@ -2239,7 +2591,7 @@ release_aux_data(hevc, hevc->decoding_pic); hevc->decoding_pic = NULL; } - if (vdec_stream_based(vdec) && + /*if (vdec_stream_based(vdec) && (hevc->decode_idx - hevc->decode_idx_bak > 1)) { int i; hevc_print(hevc, 0, "decode_idx %d, decode_idx_bak %d\n", @@ -2265,7 +2617,7 @@ release_aux_data(hevc, pic); } } - } + }*/ hevc->decode_idx = hevc->decode_idx_bak; hevc->m_pocRandomAccess = hevc->m_pocRandomAccess_bak; hevc->curr_POC = hevc->curr_POC_bak; @@ -2391,6 +2743,10 @@ static int H265_alloc_mmu(struct hevc_state_s *hevc, struct PIC_s *new_pic, unsigned short bit_depth, unsigned int *mmu_index_adr); +#ifdef H265_10B_MMU_DW +static int H265_alloc_mmu_dw(struct hevc_state_s *hevc, struct PIC_s *new_pic, + unsigned short bit_depth, unsigned int *mmu_index_adr); +#endif #ifdef DETREFILL_ENABLE #define DETREFILL_BUF_SIZE (4 * 0x4000) @@ -2587,7 +2943,7 @@ uint16_t ctuy = (ctuPosition>> 0) & 0xffff; int32_t aboveCtuAvailable = (ctuy) ? 1 : 0; - uint16_t cmBodyBuf[32 * 18]; + uint16_t *cmBodyBuf = NULL; uint32_t pic_width_x64_pre = picWidth + 0x3f; uint32_t pic_width_x64 = pic_width_x64_pre >> 6; @@ -2609,6 +2965,10 @@ int32_t blkIdx; + cmBodyBuf = vzalloc(sizeof(uint16_t) * 32 * 18); + if (!cmBodyBuf) + return; + WRITE_VREG(HEVC_SAO_CTRL10, cmHeaderAddrAbv); WRITE_VREG(HEVC_SAO_CTRL11, cmHeaderAddrCur); WRITE_VREG(HEVC_SAO_DBG_MODE0, hevc->detbuf_adr); @@ -2727,6 +3087,7 @@ } while (tmpData32); hevc_print(hevc, H265_DEBUG_BUFMGR_MORE, "%s, %d\n", __func__, __LINE__); + vfree(cmBodyBuf); } static void delrefill(struct hevc_state_s *hevc) @@ -2792,17 +3153,18 @@ struct PIC_s *pic; int i; - for (i = 0; i < MAX_REF_PIC_NUM; i++) { + for (i = 0; i < hevc->used_buf_num; i++) { pic = hevc->m_PIC[i]; - if (pic == NULL || - pic->index == -1 || - pic->BUF_index == -1) + if ((pic == NULL) || + (pic->index == -1) || + (pic->BUF_index == -1)) continue; - if (pic->output_mark == 0 && - pic->referenced == 0 && - pic->output_ready == 0 && - pic->cma_alloc_addr) { + if ((pic->output_mark == 0) && + (pic->referenced == 0) && + (pic->output_ready == 0) && + (pic->vf_ref == 0) && + (pic->cma_alloc_addr)) { pic->output_ready = 1; index = i; break; @@ -2877,80 +3239,46 @@ static int init_buf_spec(struct hevc_state_s *hevc); -static bool v4l_is_there_vframe_bound(struct hevc_state_s *hevc) -{ - int i; - - for (i = 0; i < MAX_REF_PIC_NUM; i++) { - struct PIC_s *pic = hevc->m_PIC[i]; - - if (pic && pic->vframe_bound) - return true; - } - - return false; -} - -static void v4l_mmu_buffer_release(struct hevc_state_s *hevc) -{ - int i; - - /* release workspace */ - if (hevc->bmmu_box) - decoder_bmmu_box_free_idx(hevc->bmmu_box, - BMMU_WORKSPACE_ID); - /* - * it's only when vframe get back to driver, right now we can be sure - * that vframe and fd are related. if the playback exits, the capture - * requires the upper app to release when the fd is closed, and others - * buffers drivers are released by driver. - */ - for (i = 0; i < MAX_REF_PIC_NUM; i++) { - struct PIC_s *pic = hevc->m_PIC[i]; - - if (pic && !pic->vframe_bound) { - if (hevc->bmmu_box) - decoder_bmmu_box_free_idx(hevc->bmmu_box, - VF_BUFFER_IDX(i)); - if (hevc->mmu_box) - decoder_mmu_box_free_idx(hevc->mmu_box, i); - - hevc_print(hevc, PRINT_FLAG_V4L_DETAIL, - "%s free buffer[%d], bmmu_box: %p, mmu_box: %p\n", - __func__, i, hevc->bmmu_box, hevc->mmu_box); - } - } -} static void uninit_mmu_buffers(struct hevc_state_s *hevc) { - if (hevc->is_used_v4l && - v4l_is_there_vframe_bound(hevc)) { - if (get_double_write_mode(hevc) != 0x10) { - v4l_mmu_buffer_release(hevc); - return; - } - } - - if (hevc->mmu_box) + if (hevc->mmu_box) { decoder_mmu_box_free(hevc->mmu_box); - hevc->mmu_box = NULL; - - if (hevc->bmmu_box) + hevc->mmu_box = NULL; + } +#ifdef H265_10B_MMU_DW + if (hevc->mmu_box_dw) { + decoder_mmu_box_free(hevc->mmu_box_dw); + hevc->mmu_box_dw = NULL; + } +#endif + if (hevc->bmmu_box) { + /* release workspace */ + decoder_bmmu_box_free_idx(hevc->bmmu_box, + BMMU_WORKSPACE_ID); decoder_bmmu_box_free(hevc->bmmu_box); - hevc->bmmu_box = NULL; + hevc->bmmu_box = NULL; + } } -static int init_mmu_box(struct hevc_state_s *hevc) +/* return in MB */ +static int hevc_max_mmu_buf_size(int max_w, int max_h) +{ + int buf_size = 64; + + if ((max_w * max_h) > 0 && + (max_w * max_h) <= 1920*1088) { + buf_size = 24; + } + return buf_size; +} + +static int init_mmu_buffers(struct hevc_state_s *hevc, int bmmu_flag) { int tvp_flag = vdec_secure(hw_to_vdec(hevc)) ? CODEC_MM_FLAGS_TVP : 0; - int buf_size = 64; - - if ((hevc->max_pic_w * hevc->max_pic_h) > 0 && - (hevc->max_pic_w * hevc->max_pic_h) <= 1920*1088) { - buf_size = 24; - } + int buf_size = hevc_max_mmu_buf_size(hevc->max_pic_w, + hevc->max_pic_h); if (get_dbg_flag(hevc)) { hevc_print(hevc, 0, "%s max_w %d max_h %d\n", @@ -2959,43 +3287,7 @@ hevc->need_cache_size = buf_size * SZ_1M; hevc->sc_start_time = get_jiffies_64(); - if (hevc->mmu_enable - && ((get_double_write_mode(hevc) & 0x10) == 0)) { - hevc->mmu_box = decoder_mmu_box_alloc_box(DRIVER_NAME, - hevc->index, - MAX_REF_PIC_NUM, - buf_size * SZ_1M, - tvp_flag - ); - if (!hevc->mmu_box) { - hevc_print(hevc, 0, "h265 alloc mmu box failed!!\n"); - return -1; - } - } - - return 0; -} - -static int init_mmu_buffers(struct hevc_state_s *hevc) -{ - int tvp_flag = vdec_secure(hw_to_vdec(hevc)) ? - CODEC_MM_FLAGS_TVP : 0; - int buf_size = 64; - - if ((hevc->max_pic_w * hevc->max_pic_h) > 0 && - (hevc->max_pic_w * hevc->max_pic_h) <= 1920*1088) { - buf_size = 24; - } - - if (get_dbg_flag(hevc)) { - hevc_print(hevc, 0, "%s max_w %d max_h %d\n", - __func__, hevc->max_pic_w, hevc->max_pic_h); - } - - hevc->need_cache_size = buf_size * SZ_1M; - hevc->sc_start_time = get_jiffies_64(); - if (hevc->mmu_enable - && ((get_double_write_mode(hevc) & 0x10) == 0)) { + if (hevc->mmu_enable && !hevc->is_used_v4l) { hevc->mmu_box = decoder_mmu_box_alloc_box(DRIVER_NAME, hevc->index, MAX_REF_PIC_NUM, @@ -3006,7 +3298,21 @@ pr_err("h265 alloc mmu box failed!!\n"); return -1; } +#ifdef H265_10B_MMU_DW + if (hevc->dw_mmu_enable) { + hevc->mmu_box_dw = decoder_mmu_box_alloc_box(DRIVER_NAME, + hevc->index, + MAX_REF_PIC_NUM, + buf_size * SZ_1M, + tvp_flag + ); + if (!hevc->mmu_box_dw) + goto dw_mmu_box_failed; + } +#endif } + if (bmmu_flag) + return 0; hevc->bmmu_box = decoder_bmmu_box_alloc_box(DRIVER_NAME, hevc->index, @@ -3015,14 +3321,23 @@ CODEC_MM_FLAGS_CMA_CLEAR | CODEC_MM_FLAGS_FOR_VDECODER | tvp_flag); - if (!hevc->bmmu_box) { - if (hevc->mmu_box) - decoder_mmu_box_free(hevc->mmu_box); - hevc->mmu_box = NULL; - pr_err("h265 alloc mmu box failed!!\n"); - return -1; - } + if (!hevc->bmmu_box) + goto bmmu_box_failed; + return 0; +bmmu_box_failed: +#ifdef H265_10B_MMU_DW + if (hevc->mmu_box_dw) + decoder_mmu_box_free(hevc->mmu_box_dw); + hevc->mmu_box_dw = NULL; +dw_mmu_box_failed: +#endif + if (hevc->mmu_box) { + decoder_mmu_box_free(hevc->mmu_box); + } + hevc->mmu_box = NULL; + pr_err("h265 %s failed!!\n", __func__); + return -1; } struct buf_stru_s @@ -3040,7 +3355,7 @@ if (hevc->m_mv_BUF[i].start_adr) { if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) hevc_print(hevc, 0, - "dealloc mv buf(%d) adr 0x%lx size 0x%x used_flag %d\n", + "dealloc mv buf(%d) adr 0x%p size 0x%x used_flag %d\n", i, hevc->m_mv_BUF[i].start_adr, hevc->m_mv_BUF[i].size, hevc->m_mv_BUF[i].used_flag); @@ -3238,10 +3553,20 @@ #endif } +static int hevc_get_header_size(int w, int h) +{ + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && + (IS_8K_SIZE(w, h))) + return MMU_COMPRESS_HEADER_SIZE_8K; + else if (IS_4K_SIZE(w, h)) + return MMU_COMPRESS_HEADER_SIZE_4K; + else + return MMU_COMPRESS_HEADER_SIZE_1080P; +} + static int cal_current_buf_size(struct hevc_state_s *hevc, struct buf_stru_s *buf_stru) { - int buf_size; int pic_width = hevc->pic_w; int pic_height = hevc->pic_h; @@ -3263,22 +3588,21 @@ int dw_mode = get_double_write_mode(hevc); - if (hevc->mmu_enable) { - if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && - (IS_8K_SIZE(hevc->pic_w, hevc->pic_h))) - buf_size = ((MMU_COMPRESS_HEADER_SIZE_8K + 0xffff) >> 16) - << 16; - else - buf_size = ((MMU_COMPRESS_HEADER_SIZE_4K + 0xffff) >> 16) - << 16; - } else + if (hevc->mmu_enable) + buf_size = hevc_get_header_size(hevc->pic_w, hevc->pic_h); + else buf_size = 0; - - if (dw_mode) { +#ifdef H265_10B_MMU_DW + if (hevc->dw_mmu_enable) { + buf_size = ((buf_size + 0xffff) >> 16) << 16; + buf_size <<= 1; + } +#endif + if (dw_mode && ((dw_mode & 0x20) == 0)) { int pic_width_dw = pic_width / - get_double_write_ratio(hevc, dw_mode); + get_double_write_ratio(dw_mode); int pic_height_dw = pic_height / - get_double_write_ratio(hevc, dw_mode); + get_double_write_ratio(dw_mode); int pic_width_lcu_dw = (pic_width_dw % lcu_size) ? pic_width_dw / lcu_size + 1 : @@ -3319,40 +3643,48 @@ return buf_size; } +static struct internal_comp_buf* v4lfb_to_icomp_buf( + struct hevc_state_s *hevc, + struct vdec_v4l2_buffer *fb) +{ + struct aml_video_dec_buf *aml_fb = NULL; + struct aml_vcodec_ctx * v4l2_ctx = hevc->v4l2_ctx; + + aml_fb = container_of(fb, struct aml_video_dec_buf, frame_buffer); + return &v4l2_ctx->comp_bufs[aml_fb->internal_index]; +} + +static struct internal_comp_buf* index_to_icomp_buf( + struct hevc_state_s *hevc, int index) +{ + struct aml_video_dec_buf *aml_fb = NULL; + struct aml_vcodec_ctx * v4l2_ctx = hevc->v4l2_ctx; + struct vdec_v4l2_buffer *fb = NULL; + + fb = (struct vdec_v4l2_buffer *) + hevc->m_BUF[index].v4l_ref_buf_addr; + aml_fb = container_of(fb, struct aml_video_dec_buf, frame_buffer); + return &v4l2_ctx->comp_bufs[aml_fb->internal_index]; +} + static int v4l_alloc_buf(struct hevc_state_s *hevc, struct PIC_s *pic) { int ret = -1; int i = pic->index; + struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)hevc->v4l2_ctx; struct vdec_v4l2_buffer *fb = NULL; - if (hevc->fatal_error & DECODER_FATAL_ERROR_NO_MEM) - return ret; - - ret = vdec_v4l_get_buffer(hevc->v4l2_ctx, &fb); + ret = ctx->fb_ops.alloc(&ctx->fb_ops, hevc->fb_token, &fb, AML_FB_REQ_DEC); if (ret < 0) { - hevc_print(hevc, 0, "[%d] H265 get buffer fail.\n", - ((struct aml_vcodec_ctx *)(hevc->v4l2_ctx))->id); + hevc_print(hevc, 0, "[%d] H265 get buffer fail.\n", ctx->id); return ret; } - if (hevc->mmu_enable) { - if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && - (IS_8K_SIZE(hevc->pic_w, hevc->pic_h))) - hevc->m_BUF[i].header_size = - ALIGN(MMU_COMPRESS_HEADER_SIZE_8K, 0x10000); - else - hevc->m_BUF[i].header_size = - ALIGN(MMU_COMPRESS_HEADER_SIZE_4K, 0x10000); + fb->status = FB_ST_DECODER; - ret = decoder_bmmu_box_alloc_buf_phy(hevc->bmmu_box, - VF_BUFFER_IDX(i), hevc->m_BUF[i].header_size, - DRIVER_NAME, &hevc->m_BUF[i].header_addr); - if (ret < 0) { - hevc_print(hevc, PRINT_FLAG_ERROR, - "%s[%d], header size: %d, no mem fatal err\n", - __func__, i, hevc->m_BUF[i].header_size); - return ret; - } + if (hevc->mmu_enable) { + struct internal_comp_buf *ibuf = v4lfb_to_icomp_buf(hevc, fb); + hevc->m_BUF[i].header_addr = ibuf->header_addr; } hevc->m_BUF[i].used_flag = 0; @@ -3365,6 +3697,8 @@ fb->m.mem[0].bytes_used = fb->m.mem[0].size; pic->dw_y_adr = hevc->m_BUF[i].start_adr; pic->dw_u_v_adr = pic->dw_y_adr + hevc->m_BUF[i].luma_size; + pic->luma_size = fb->m.mem[0].offset; + pic->chroma_size = fb->m.mem[0].size - fb->m.mem[0].offset; } else if (fb->num_planes == 2) { hevc->m_BUF[i].start_adr = fb->m.mem[0].addr; hevc->m_BUF[i].luma_size = fb->m.mem[0].size; @@ -3375,6 +3709,8 @@ fb->m.mem[1].bytes_used = fb->m.mem[1].size; pic->dw_y_adr = hevc->m_BUF[i].start_adr; pic->dw_u_v_adr = hevc->m_BUF[i].chroma_addr; + pic->luma_size = fb->m.mem[0].size; + pic->chroma_size = fb->m.mem[1].size; } return ret; @@ -3385,6 +3721,7 @@ int i; int ret = -1; int buf_size = cal_current_buf_size(hevc, NULL); + struct vdec_s *vdec = hw_to_vdec(hevc); if (hevc->fatal_error & DECODER_FATAL_ERROR_NO_MEM) return ret; @@ -3412,6 +3749,11 @@ } if (ret >= 0) { + if (hevc->enable_fence) { + vdec_fence_buffer_count_increase((ulong)vdec->sync); + INIT_LIST_HEAD(&vdec->sync->release_callback[VF_BUFFER_IDX(i)].node); + decoder_bmmu_box_add_callback_func(hevc->bmmu_box, VF_BUFFER_IDX(i), (void *)&vdec->sync->release_callback[VF_BUFFER_IDX(i)]); + } hevc->m_BUF[i].size = buf_size; hevc->m_BUF[i].used_flag = 0; ret = 0; @@ -3446,7 +3788,7 @@ if (ret >= 0) { if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) { hevc_print(hevc, 0, - "alloc buf(%d) for %d/%d size 0x%x) => %lx\n", + "alloc buf(%d) for %d/%d size 0x%x) => %p\n", i, hevc->pic_w, hevc->pic_h, buf_size, hevc->m_BUF[i].start_adr); @@ -3476,7 +3818,7 @@ hevc->m_BUF[i].used_flag == 0) { if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) { hevc_print(hevc, 0, - "dealloc buf(%d) adr 0x%lx size 0x%x\n", + "dealloc buf(%d) adr 0x%p size 0x%x\n", i, hevc->m_BUF[i].start_adr, hevc->m_BUF[i].size); } @@ -3485,6 +3827,7 @@ hevc->bmmu_box, VF_BUFFER_IDX(i)); hevc->m_BUF[i].start_adr = 0; + hevc->m_BUF[i].header_addr = 0; hevc->m_BUF[i].size = 0; } } @@ -3500,7 +3843,7 @@ hevc->m_BUF[i].start_adr) { if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) { hevc_print(hevc, 0, - "dealloc buf(%d) adr 0x%lx size 0x%x\n", + "dealloc buf(%d) adr 0x%p size 0x%x\n", i, hevc->m_BUF[i].start_adr, hevc->m_BUF[i].size); } @@ -3511,6 +3854,7 @@ VF_BUFFER_IDX(i)); hevc->m_BUF[i].used_flag = 0; hevc->m_BUF[i].start_adr = 0; + hevc->m_BUF[i].header_addr = 0; hevc->m_BUF[i].size = 0; } } @@ -3601,10 +3945,8 @@ "save buf _mode : dynamic_buf_num_margin %d ----> %d \n", dynamic_buf_num_margin, hevc->dynamic_buf_num_margin); - if (sps_pic_buf_diff >= 4) - { - used_buf_num += sps_pic_buf_diff;; - } + if (sps_pic_buf_diff >= 3) + used_buf_num += sps_pic_buf_diff; /* for eos add more buffer to flush.*/ used_buf_num++; @@ -3681,26 +4023,35 @@ if (hevc->mmu_enable) { pic->header_adr = hevc->m_BUF[i].start_adr; - if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && - (IS_8K_SIZE(hevc->pic_w, hevc->pic_h))) - y_adr = hevc->m_BUF[i].start_adr + - MMU_COMPRESS_HEADER_SIZE_8K; - else - y_adr = hevc->m_BUF[i].start_adr + - MMU_COMPRESS_HEADER_SIZE_4K; + y_adr = hevc->m_BUF[i].start_adr + + hevc_get_header_size(hevc->pic_w, hevc->pic_h); } else y_adr = hevc->m_BUF[i].start_adr; y_adr = ((y_adr + 0xffff) >> 16) << 16; /*64k alignment*/ +#ifdef H265_10B_MMU_DW + if (hevc->dw_mmu_enable) { +#ifdef USE_FIXED_MMU_DW_HEADER + pic->header_dw_adr = hevc->work_space_buf->cm_header_dw.buf_start + + (i * hevc_get_header_size(hevc->pic_w, hevc->pic_h)); +#else + pic->header_dw_adr = y_adr; + y_adr = pic->header_dw_adr + + hevc_get_header_size(hevc->pic_w, hevc->pic_h); +#endif + hevc_print(hevc, H265_DEBUG_BUFMGR, + "MMU header_dw_adr %d: %x\n", pic->header_dw_adr); + } +#endif + pic->POC = INVALID_POC; /*ensure get_pic_by_POC() not get the buffer not decoded*/ pic->BUF_index = i; if ((!hevc->mmu_enable) && - ((dw_mode & 0x10) == 0) - ) { + ((dw_mode & 0x10) == 0)) { pic->mc_y_adr = y_adr; y_adr += (buf_stru.mc_buffer_size_h << 16); } @@ -3715,7 +4066,7 @@ pic->dw_y_adr = pic->mc_y_adr; pic->dw_u_v_adr = pic->mc_u_v_adr; - } else if (dw_mode) { + } else if (dw_mode && (dw_mode & 0x20) == 0) { pic->dw_y_adr = y_adr; pic->dw_u_v_adr = pic->dw_y_adr + ((buf_stru.mc_buffer_size_u_v_h << 16) << 1); @@ -3726,8 +4077,7 @@ "%s index %d BUF_index %d mc_y_adr %x\n", __func__, pic->index, pic->BUF_index, pic->mc_y_adr); - if (hevc->mmu_enable && - dw_mode) + if (hevc->mmu_enable && dw_mode) hevc_print(hevc, 0, "mmu double write adr %ld\n", pic->cma_alloc_addr); @@ -3784,6 +4134,7 @@ pic->width = hevc->pic_w; pic->height = hevc->pic_h; pic->double_write_mode = dw_mode; + pic->POC = INVALID_POC; /*config canvas will be delay if work on v4l. */ if (!hevc->is_used_v4l) { @@ -3874,7 +4225,34 @@ data32 |= (1<<10); WRITE_VREG(HEVC_SAO_CTRL5, data32); } +#ifdef H265_10B_MMU_DW + if (hevc->dw_mmu_enable) { + u32 data_tmp; + data_tmp = READ_VREG(HEVC_SAO_CTRL9); + data_tmp |= (1 << 10); + WRITE_VREG(HEVC_SAO_CTRL9, data_tmp); + WRITE_VREG(HEVC_CM_BODY_LENGTH2, + losless_comp_body_size); + WRITE_VREG(HEVC_CM_HEADER_OFFSET2, + losless_comp_body_size); + WRITE_VREG(HEVC_CM_HEADER_LENGTH2, + losless_comp_header_size); + + WRITE_VREG(HEVC_SAO_MMU_VH0_ADDR2, + buf_spec->mmu_vbh_dw.buf_start); + WRITE_VREG(HEVC_SAO_MMU_VH1_ADDR2, + buf_spec->mmu_vbh_dw.buf_start + DW_VBH_BUF_SIZE(buf_spec)); + WRITE_VREG(HEVC_DW_VH0_ADDDR, + buf_spec->mmu_vbh_dw.buf_start + (2 * DW_VBH_BUF_SIZE(buf_spec))); + WRITE_VREG(HEVC_DW_VH1_ADDDR, + buf_spec->mmu_vbh_dw.buf_start + (3 * DW_VBH_BUF_SIZE(buf_spec))); + /* use HEVC_CM_HEADER_START_ADDR */ + data32 |= (1 << 15); + } else + data32 &= ~(1 << 15); + WRITE_VREG(HEVC_SAO_CTRL5, data32); +#endif if (!hevc->m_ins_flag) hevc_print(hevc, 0, "%s: (%d, %d) body_size 0x%x header_size 0x%x\n", @@ -4082,10 +4460,8 @@ decode_idx)) pic_display = pic; - } else pic_display = pic; - } } #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION @@ -4098,7 +4474,6 @@ && (!fisrt_pic_flag)) pic_display = NULL; #endif - if (pic_display) { if ((num_pic_not_yet_display > pic_display->num_reorder_pic) @@ -4853,6 +5228,12 @@ "write HEVC_DBLK_CFG3 to %x\n", READ_VREG(HEVC_DBLK_CFG3)); } #endif +#ifdef H265_10B_MMU_DW + if (hevc->dw_mmu_enable) { + //WRITE_VREG(HEVC_ASSIST_MMU_MAP_ADDR2, FRAME_MMU_MAP_ADDR_DW); + WRITE_VREG(HEVC_SAO_MMU_DMA_CTRL2, hevc->frame_dw_mmu_map_phy_addr); + } +#endif /* cfg_p_addr */ WRITE_VREG(HEVC_DBLK_CFG4, buf_spec->dblk_para.buf_start); /* cfg_d_addr */ @@ -4992,9 +5373,13 @@ WRITE_VREG(HEVC_DEC_STATUS_REG, 0); /* Initial IQIT_SCALELUT memory -- just to avoid X in simulation */ - WRITE_VREG(HEVC_IQIT_SCALELUT_WR_ADDR, 0); /* cfg_p_addr */ - for (i = 0; i < 1024; i++) - WRITE_VREG(HEVC_IQIT_SCALELUT_DATA, 0); + if (is_rdma_enable()) + rdma_back_end_work(hevc->rdma_phy_adr, RDMA_SIZE); + else { + WRITE_VREG(HEVC_IQIT_SCALELUT_WR_ADDR, 0);/*cfg_p_addr*/ + for (i = 0; i < 1024; i++) + WRITE_VREG(HEVC_IQIT_SCALELUT_DATA, 0); + } #ifdef ENABLE_SWAP_TEST WRITE_VREG(HEVC_STREAM_SWAP_TEST, 100); @@ -5140,7 +5525,6 @@ WRITE_VREG(HEVCD_IPP_TOP_CNTL, (1 << 1) | /* enable ipp */ (0 << 0) /* software reset ipp and mpp */ ); - } #ifdef CONFIG_HEVC_CLK_FORCED_ON @@ -5527,6 +5911,7 @@ int mc_buffer_size_u_v_h = (mc_buffer_size_u_v + 0xffff) >> 16; struct PIC_s *cur_pic = hevc->cur_pic; struct aml_vcodec_ctx * v4l2_ctx = hevc->v4l2_ctx; + int dw_mode = get_double_write_mode(hevc); data32 = READ_VREG(HEVC_SAO_CTRL0); data32 &= (~0xf); @@ -5543,34 +5928,50 @@ WRITE_VREG(HEVC_SAO_Y_START_ADDR, 0xffffffff); #ifdef LOSLESS_COMPRESS_MODE /*SUPPORT_10BIT*/ - if ((get_double_write_mode(hevc) & 0x10) == 0) { + if ((dw_mode & 0x10) == 0) { + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T7) + WRITE_VREG(HEVC_SAO_CTRL26, 0); + data32 = READ_VREG(HEVC_SAO_CTRL5); data32 &= (~(0xff << 16)); + if (((dw_mode & 0xf) == 8) || + ((dw_mode & 0xf) == 9)) { + data32 |= (0xff << 16); + WRITE_VREG(HEVC_SAO_CTRL5, data32); + WRITE_VREG(HEVC_SAO_CTRL26, 0xf); + } else { + if ((dw_mode & 0xf) == 2 || + (dw_mode & 0xf) == 3) + data32 |= (0xff<<16); + else if ((dw_mode & 0xf) == 4 || + (dw_mode & 0xf) == 5) + data32 |= (0x33<<16); - if (get_double_write_mode(hevc) == 2 || - get_double_write_mode(hevc) == 3) - data32 |= (0xff<<16); - else if (get_double_write_mode(hevc) == 4 || - get_double_write_mode(hevc) == 5) - data32 |= (0x33<<16); - - if (hevc->mem_saving_mode == 1) - data32 |= (1 << 9); - else - data32 &= ~(1 << 9); - if (workaround_enable & 1) - data32 |= (1 << 7); - WRITE_VREG(HEVC_SAO_CTRL5, data32); + if (hevc->mem_saving_mode == 1) + data32 |= (1 << 9); + else + data32 &= ~(1 << 9); + if (workaround_enable & 1) + data32 |= (1 << 7); + WRITE_VREG(HEVC_SAO_CTRL5, data32); + } } data32 = cur_pic->mc_y_adr; - if (get_double_write_mode(hevc)) + if (dw_mode && ((dw_mode & 0x20) == 0)) WRITE_VREG(HEVC_SAO_Y_START_ADDR, cur_pic->dw_y_adr); - if ((get_double_write_mode(hevc) & 0x10) == 0) + if ((dw_mode & 0x10) == 0) WRITE_VREG(HEVC_CM_BODY_START_ADDR, data32); if (hevc->mmu_enable) WRITE_VREG(HEVC_CM_HEADER_START_ADDR, cur_pic->header_adr); +#ifdef H265_10B_MMU_DW + if (hevc->dw_mmu_enable) { + WRITE_VREG(HEVC_SAO_Y_START_ADDR, 0); + WRITE_VREG(HEVC_SAO_C_START_ADDR, 0); + WRITE_VREG(HEVC_CM_HEADER_START_ADDR2, cur_pic->header_dw_adr); + } +#endif #else data32 = cur_pic->mc_y_adr; WRITE_VREG(HEVC_SAO_Y_START_ADDR, data32); @@ -5580,7 +5981,7 @@ #ifdef LOSLESS_COMPRESS_MODE /*SUPPORT_10BIT*/ - if (get_double_write_mode(hevc)) + if (dw_mode && ((dw_mode & 0x20) == 0)) WRITE_VREG(HEVC_SAO_C_START_ADDR, cur_pic->dw_u_v_adr); #else data32 = cur_pic->mc_u_v_adr; @@ -5589,9 +5990,20 @@ data32 = (mc_buffer_size_u_v_h << 16); WRITE_VREG(HEVC_SAO_C_LENGTH, data32); + if (hevc->is_used_v4l) { + WRITE_VREG(HEVC_SAO_Y_LENGTH, cur_pic->luma_size); + WRITE_VREG(HEVC_SAO_C_LENGTH, cur_pic->chroma_size); + if (debug & PRINT_FLAG_V4L_DETAIL) { + pr_info("[%d] config pic, id: %d, Y:(%x, %d) C:(%x, %d).\n", + v4l2_ctx->id, cur_pic->index, + cur_pic->dw_y_adr, cur_pic->luma_size, + cur_pic->dw_u_v_adr, cur_pic->chroma_size); + } + } + #ifdef LOSLESS_COMPRESS_MODE /*SUPPORT_10BIT*/ - if (get_double_write_mode(hevc)) { + if (dw_mode && ((dw_mode & 0x20) == 0)) { WRITE_VREG(HEVC_SAO_Y_WPTR, cur_pic->dw_y_adr); WRITE_VREG(HEVC_SAO_C_WPTR, cur_pic->dw_u_v_adr); } @@ -5615,9 +6027,9 @@ if (hevc->pic_w >= 1280) data32 |= (0x1 << 4); /*dblk pipeline mode=1 for performance*/ data32 &= (~0x300); /*[8]:first write enable (compress) [9]:double write enable (uncompress)*/ - if (get_double_write_mode(hevc) == 0) + if (dw_mode == 0) data32 |= (0x1 << 8); /*enable first write*/ - else if (get_double_write_mode(hevc) == 0x10) + else if (dw_mode == 0x10) data32 |= (0x1 << 9); /*double write only*/ else data32 |= ((0x1 << 8) |(0x1 << 9)); @@ -5644,7 +6056,7 @@ data32 |= (hevc->lcu_size == 64) ? 0 : ((hevc->lcu_size == 32) ? 1 : 2); - + data32 |= (hevc->pic_w <= 64) ? (1 << 20) : 0; WRITE_VREG(HEVC_DBLK_CFG1, data32); if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { @@ -5681,19 +6093,19 @@ /* m8baby test1902 */ data32 = READ_VREG(HEVC_SAO_CTRL1); data32 &= (~0x3000); - data32 |= (hevc->mem_map_mode << - 12); - -/* [13:12] axi_aformat, 0-Linear, - * 1-32x32, 2-64x32 - */ + /* [13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32 */ + data32 |= (hevc->mem_map_mode << 12); data32 &= (~0xff0); - /* data32 |= 0x670; // Big-Endian per 64-bit */ - data32 |= endian; /* Big-Endian per 64-bit */ +#ifdef H265_10B_MMU_DW + if (hevc->dw_mmu_enable == 0) + data32 |= ((hevc->endian >> 8) & 0xfff); +#else + data32 |= ((hevc->endian >> 8) & 0xfff); /* data32 |= 0x670; Big-Endian per 64-bit */ +#endif data32 &= (~0x3); /*[1]:dw_disable [0]:cm_disable*/ - if (get_double_write_mode(hevc) == 0) + if (dw_mode == 0) data32 |= 0x2; /*disable double write*/ - else if (get_double_write_mode(hevc) & 0x10) + else if (dw_mode & 0x10) data32 |= 0x1; /*disable cm*/ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { unsigned int data; @@ -5702,9 +6114,9 @@ if (hevc->pic_w >= 1280) data |= (0x1 << 4); /*dblk pipeline mode=1 for performance*/ data &= (~0x300); /*[8]:first write enable (compress) [9]:double write enable (uncompress)*/ - if (get_double_write_mode(hevc) == 0) + if (dw_mode == 0) data |= (0x1 << 8); /*enable first write*/ - else if (get_double_write_mode(hevc) & 0x10) + else if (dw_mode & 0x10) data |= (0x1 << 9); /*double write only*/ else data |= ((0x1 << 8) |(0x1 << 9)); @@ -5721,7 +6133,8 @@ else data32 |= (1 << 8); /* NV12 */ } - + data32 &= (~(3 << 14)); + data32 |= (2 << 14); /* * [31:24] ar_fifo1_axi_thred * [23:16] ar_fifo0_axi_thred @@ -5734,9 +6147,8 @@ * [1] dw_disable:disable double write output * [0] cm_disable:disable compress output */ - WRITE_VREG(HEVC_SAO_CTRL1, data32); - if (get_double_write_mode(hevc) & 0x10) { + if (dw_mode & 0x10) { /* [23:22] dw_v1_ctrl *[21:20] dw_v0_ctrl *[19:18] dw_h1_ctrl @@ -5751,11 +6163,9 @@ data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG); data32 &= (~0x30); /* [5:4] -- address_format 00:linear 01:32x32 10:64x32 */ - data32 |= (hevc->mem_map_mode << - 4); + data32 |= (hevc->mem_map_mode << 4); data32 &= (~0xF); - data32 |= 0xf; /* valid only when double write only */ - /*data32 |= 0x8;*/ /* Big-Endian per 64-bit */ + data32 |= (hevc->endian & 0xf); /* valid only when double write only */ /* swap uv */ if (hevc->is_used_v4l) { @@ -5765,7 +6175,8 @@ else data32 &= ~(1 << 12); /* NV12 */ } - + data32 &= (~(3 << 8)); + data32 |= (2 << 8); /* * [3:0] little_endian * [5:4] address_format 00:linear 01:32x32 10:64x32 @@ -5887,7 +6298,9 @@ if (alloc_pic_count > work_pic_num) { pic->width = 0; pic->height = 0; + ATRACE_COUNTER(hevc->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_START); release_pic_mmu_buf(hevc, pic); + ATRACE_COUNTER(hevc->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_END); pic->index = -1; } else { pic->width = hevc->pic_w; @@ -6003,6 +6416,21 @@ return NULL; } } +#ifdef H265_10B_MMU_DW + if (hevc->dw_mmu_enable) { + ret = H265_alloc_mmu_dw(hevc, new_pic, + rpm_param->p.bit_depth, + hevc->frame_dw_mmu_map_addr); + if (ret != 0) { + put_mv_buf(hevc, new_pic); + hevc_print(hevc, 0, + "can't alloc need mmu_dw_1,idx %d ret =%d\n", + new_pic->decode_idx, + ret); + return NULL; + } + } +#endif new_pic->referenced = 1; new_pic->decode_idx = hevc->decode_idx; new_pic->slice_idx = 0; @@ -6058,6 +6486,24 @@ return new_pic; } +static int get_free_fb_idx(struct hevc_state_s *hevc) +{ + int i; + + for (i = 0; i < MAX_REF_PIC_NUM; ++i) { + if (hevc->m_PIC[i] == NULL) + continue; + + if ((hevc->m_PIC[i]->referenced == 0) && + (hevc->m_PIC[i]->vf_ref == 0) && + (!hevc->m_PIC[i]->cma_alloc_addr)) + break; + } + + return (hevc->m_PIC[i] && + (i != MAX_REF_PIC_NUM)) ? i : -1; +} + static struct PIC_s *v4l_get_new_pic(struct hevc_state_s *hevc, union param_u *rpm_param) { @@ -6067,7 +6513,7 @@ struct v4l_buff_pool *pool = &v4l->cap_pool; struct PIC_s *new_pic = NULL; struct PIC_s *pic = NULL; - int i; + int i, j, idx; for (i = 0; i < pool->in; ++i) { u32 state = (pool->seq[i] >> 16); @@ -6075,22 +6521,37 @@ switch (state) { case V4L_CAP_BUFF_IN_DEC: - pic = hevc->m_PIC[i]; - if (pic && (pic->index != -1) && - (pic->output_mark == 0) && - (pic->referenced == 0) && - (pic->output_ready == 0) && - (pic->width == hevc->pic_w) && - (pic->height == hevc->pic_h) && - (pic->vf_ref == 0) && - pic->cma_alloc_addr) { - new_pic = pic; + for (j = 0; j < MAX_REF_PIC_NUM; j++) { + pic = hevc->m_PIC[j]; + if (pic == NULL || pic->index == -1) + continue; + + if (pic->output_mark == 0 && + pic->referenced == 0 && + pic->output_ready == 0 && + pic->width == hevc->pic_w && + pic->height == hevc->pic_h && + pic->vf_ref == 0 && + pic->cma_alloc_addr) { + if (new_pic) { + if (new_pic->POC != INVALID_POC) { + if (pic->POC == INVALID_POC || + pic->POC < new_pic->POC) + new_pic = pic; + } + } else + new_pic = pic; + } } break; case V4L_CAP_BUFF_IN_M2M: - pic = hevc->m_PIC[index]; + idx = get_free_fb_idx(hevc); + if (idx < 0) + break; + pic = hevc->m_PIC[idx]; pic->width = hevc->pic_w; pic->height = hevc->pic_h; + hevc->buffer_wrap[idx] = index; if ((pic->index != -1) && !v4l_alloc_buf(hevc, pic)) { v4l_config_pic(hevc, pic); @@ -6140,10 +6601,10 @@ new_pic->dis_mark = 0; /* new_pic->output_ready = 0; */ new_pic->num_reorder_pic = rpm_param->p.sps_num_reorder_pics_0; - new_pic->ip_mode = (!new_pic->num_reorder_pic && - !(vdec->slave || vdec->master) && - !disable_ip_mode && - hevc->low_latency_flag) ? true : false; + new_pic->ip_mode = hevc->low_latency_flag ? true : + (!new_pic->num_reorder_pic && + !(vdec->slave || vdec->master) && + !disable_ip_mode) ? true : false; new_pic->losless_comp_body_size = hevc->losless_comp_body_size; new_pic->POC = hevc->curr_POC; new_pic->pic_struct = hevc->curr_pic_struct; @@ -6172,7 +6633,14 @@ new_pic->chroma_format_idc = hevc->param.p.chroma_format_idc; - hevc_print(hevc, H265_DEBUG_BUFMGR_MORE, + if (new_pic) { + struct vdec_v4l2_buffer *fb = + (struct vdec_v4l2_buffer *)new_pic->cma_alloc_addr; + + fb->status = FB_ST_DECODER; + } + + hevc_print(hevc, H265_DEBUG_BUFMGR, "%s: index %d, buf_idx %d, decode_idx %d, POC %d\n", __func__, new_pic->index, new_pic->BUF_index, new_pic->decode_idx, @@ -6328,7 +6796,7 @@ aux_size = hevc->prefix_aux_size; } - if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR_MORE) { + if (get_dbg_flag(hevc) & H265_DEBUG_PRINT_SEI) { hevc_print(hevc, 0, "%s:pic 0x%p old size %d count %d,suf %d dv_flag %d\r\n", __func__, pic, pic->aux_data_size, @@ -6437,7 +6905,7 @@ h[6] = (padding_len >> 8) & 0xff; h[7] = (padding_len) & 0xff; } - if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR_MORE) { + if (get_dbg_flag(hevc) & H265_DEBUG_PRINT_SEI) { hevc_print(hevc, 0, "aux: (size %d) suffix_flag %d\n", pic->aux_data_size, suffix_flag); @@ -6473,6 +6941,39 @@ pic->aux_data_size = 0; } +static int recycle_mmu_buf_tail(struct hevc_state_s *hevc, + bool check_dma) +{ + hevc_print(hevc, + H265_DEBUG_BUFMGR_MORE, + "%s pic index %d scatter_alloc %d page_start %d\n", + "decoder_mmu_box_free_idx_tail", + hevc->cur_pic->index, + hevc->cur_pic->scatter_alloc, + hevc->used_4k_num); + if (check_dma) + hevc_mmu_dma_check(hw_to_vdec(hevc)); + + if (hevc->is_used_v4l) { + int index = hevc->cur_pic->BUF_index; + struct internal_comp_buf *ibuf = + index_to_icomp_buf(hevc, index); + + decoder_mmu_box_free_idx_tail( + ibuf->mmu_box, + ibuf->index, + hevc->used_4k_num); + } else { + decoder_mmu_box_free_idx_tail( + hevc->mmu_box, + hevc->cur_pic->index, + hevc->used_4k_num); + } + hevc->cur_pic->scatter_alloc = 2; + hevc->used_4k_num = -1; + return 0; +} + static inline void hevc_pre_pic(struct hevc_state_s *hevc, struct PIC_s *pic) { @@ -6521,22 +7022,10 @@ (hevc->used_4k_num >= 0) && (hevc->cur_pic->scatter_alloc == 1)) { - hevc_print(hevc, - H265_DEBUG_BUFMGR_MORE, - "%s pic index %d scatter_alloc %d page_start %ld\n", - "decoder_mmu_box_free_idx_tail", - hevc->cur_pic->index, - hevc->cur_pic->scatter_alloc, - hevc->used_4k_num); - hevc_mmu_dma_check(hw_to_vdec(hevc)); - decoder_mmu_box_free_idx_tail( - hevc->mmu_box, - hevc->cur_pic->index, - hevc->used_4k_num); - hevc->cur_pic->scatter_alloc - = 2; - } - hevc->used_4k_num = -1; + ATRACE_COUNTER(hevc->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_START); + recycle_mmu_buf_tail(hevc, true); + ATRACE_COUNTER(hevc->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_END); + } } } if (!pic->ip_mode) @@ -6624,7 +7113,7 @@ hevc_print(hevc, 0, "clear referenced flag of all buffers\n"); } - if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) + if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR_MORE) dump_pic_list(hevc); if (hevc->vf_pre_count == 1 && hevc->first_pic_flag == 1) { @@ -7185,17 +7674,14 @@ union param_u *rpm_param, int decode_pic_begin) { +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION struct vdec_s *vdec = hw_to_vdec(hevc); +#endif int i; int lcu_x_num_div; int lcu_y_num_div; int Col_ref; int dbg_skip_flag = 0; - struct aml_vcodec_ctx *ctx = - (struct aml_vcodec_ctx *)(hevc->v4l2_ctx); - - if (hevc->is_used_v4l && ctx->param_sets_from_ucode) - hevc->res_ch_flag = 0; if (hevc->wait_buf == 0) { hevc->sps_num_reorder_pics_0 = @@ -7209,11 +7695,22 @@ (rpm_param->p.profile_etc >> 2) & 0x1; hevc->curr_pic_struct = (rpm_param->p.sei_frame_field_info >> 3) & 0xf; - if (parser_sei_enable & 0x4) { - hevc->frame_field_info_present_flag = - (rpm_param->p.sei_frame_field_info >> 8) & 0x1; + hevc->frame_field_info_present_flag = + (rpm_param->p.sei_frame_field_info >> 8) & 0x1; + + if (hevc->frame_field_info_present_flag) { + if (hevc->curr_pic_struct == 0 + || hevc->curr_pic_struct == 7 + || hevc->curr_pic_struct == 8) + hevc->interlace_flag = 0; } + hevc_print(hevc, H265_DEBUG_PIC_STRUCT, + "frame_field_info_present_flag = %d curr_pic_struct = %d interlace_flag = %d\n", + hevc->frame_field_info_present_flag, + hevc->curr_pic_struct, + hevc->interlace_flag); + /* if (interlace_enable == 0 || hevc->m_ins_flag) */ if (interlace_enable == 0) hevc->interlace_flag = 0; @@ -7268,6 +7765,7 @@ rpm_param->p.pic_width_in_luma_samples, rpm_param->p.pic_height_in_luma_samples, hevc->interlace_flag); + hevc->pic_w = rpm_param->p.pic_width_in_luma_samples; hevc->pic_h = rpm_param->p.pic_height_in_luma_samples; hevc->frame_width = hevc->pic_w; @@ -7434,7 +7932,7 @@ /**/ /* if((iPrevPOC != curr_POC)){ */ if (rpm_param->p.slice_segment_address == 0) { - struct PIC_s *pic; + struct PIC_s *pic = NULL; hevc->new_pic = 1; #ifdef MULTI_INSTANCE_SUPPORT @@ -7443,6 +7941,10 @@ check_pic_decoded_error_pre(hevc, READ_VREG(HEVC_PARSER_LCU_START) & 0xffffff); + if (vdec_stream_based(vdec) && ((READ_VREG(HEVC_PARSER_LCU_START) & 0xffffff) != 0)) { + if (hevc->cur_pic) + hevc->cur_pic->error_mark = 1; + } /**/ if (use_cma == 0) { if (hevc->pic_list_init_flag == 0) { init_pic_list(hevc); @@ -7499,7 +8001,7 @@ v4l_get_new_pic(hevc, rpm_param) : get_new_pic(hevc, rpm_param); if (hevc->cur_pic == NULL) { - if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) + if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR_MORE) dump_pic_list(hevc); hevc->wait_buf = 1; return -1; @@ -7821,7 +8323,7 @@ || (dbg_skip_flag)) return 0xf; #endif - + ATRACE_COUNTER(hevc->trace.decode_header_memory_time_name, TRACE_HEADER_REGISTER_START); config_mc_buffer(hevc, hevc->cur_pic); if (is_skip_decoding(hevc, @@ -7869,7 +8371,7 @@ config_mpred_hw(hevc); config_sao_hw(hevc, rpm_param); - + ATRACE_COUNTER(hevc->trace.decode_header_memory_time_name, TRACE_HEADER_REGISTER_END); if ((hevc->slice_type != 2) && (hevc->i_only & 0x2)) return 0xf; @@ -7879,50 +8381,106 @@ return 0; } - - -static int H265_alloc_mmu(struct hevc_state_s *hevc, struct PIC_s *new_pic, - unsigned short bit_depth, unsigned int *mmu_index_adr) { - int cur_buf_idx = new_pic->index; - int bit_depth_10 = (bit_depth != 0x00); +/* return page number */ +static int hevc_mmu_page_num(struct hevc_state_s *hevc, + int w, int h, int save_mode) +{ int picture_size; - int cur_mmu_4k_number; - int ret, max_frame_num; - picture_size = compute_losless_comp_body_size(hevc, new_pic->width, - new_pic->height, !bit_depth_10); - cur_mmu_4k_number = ((picture_size+(1<<12)-1) >> 12); - if (get_double_write_mode(hevc) == 0x10) - return 0; - /*hevc_print(hevc, 0, - "alloc_mmu cur_idx : %d picture_size : %d mmu_4k_number : %d\r\n", - cur_buf_idx, picture_size, cur_mmu_4k_number);*/ + int page_num; + int max_frame_num; + + picture_size = compute_losless_comp_body_size(hevc, w, + h, save_mode); + page_num = ((picture_size + PAGE_SIZE - 1) >> PAGE_SHIFT); if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) max_frame_num = MAX_FRAME_8K_NUM; else max_frame_num = MAX_FRAME_4K_NUM; - if (cur_mmu_4k_number > max_frame_num) { + + if (page_num > max_frame_num) { hevc_print(hevc, 0, "over max !! 0x%x width %d height %d\n", - cur_mmu_4k_number, - new_pic->width, - new_pic->height); + page_num, w, h); return -1; } - ret = decoder_mmu_box_alloc_idx( - hevc->mmu_box, - cur_buf_idx, - cur_mmu_4k_number, - mmu_index_adr); + return page_num; +} + +static int H265_alloc_mmu(struct hevc_state_s *hevc, struct PIC_s *new_pic, + unsigned short bit_depth, unsigned int *mmu_index_adr) { + int bit_depth_10 = (bit_depth != 0x00); + int cur_mmu_4k_number; + int ret; + + if (get_double_write_mode(hevc) == 0x10) + return 0; + + cur_mmu_4k_number = hevc_mmu_page_num(hevc, new_pic->width, + new_pic->height, !bit_depth_10); + if (cur_mmu_4k_number < 0) + return -1; + + if (hevc->is_used_v4l) { + struct internal_comp_buf *ibuf = + index_to_icomp_buf(hevc, new_pic->BUF_index); + + ret = decoder_mmu_box_alloc_idx( + ibuf->mmu_box, + ibuf->index, + ibuf->frame_buffer_size, + mmu_index_adr); + } else { + ATRACE_COUNTER(hevc->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_START); + ret = decoder_mmu_box_alloc_idx( + hevc->mmu_box, + new_pic->index, + cur_mmu_4k_number, + mmu_index_adr); + ATRACE_COUNTER(hevc->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_END); + } new_pic->scatter_alloc = 1; hevc_print(hevc, H265_DEBUG_BUFMGR_MORE, "%s pic index %d page count(%d) ret =%d\n", - __func__, cur_buf_idx, + __func__, new_pic->index, cur_mmu_4k_number, ret); return ret; } +#ifdef H265_10B_MMU_DW +static int H265_alloc_mmu_dw(struct hevc_state_s *hevc, struct PIC_s *new_pic, + unsigned short bit_depth, unsigned int *mmu_index_adr) { + int bit_depth_10 = (bit_depth != 0x00); + int cur_mmu_4k_number; + int ret; + if (!hevc->mmu_box_dw) { + hevc_print(hevc, 0, + "%s, error no mmu box dw!\n", __func__); + return -1; + } + + if (get_double_write_mode(hevc) == 0x10) + return 0; + + cur_mmu_4k_number = hevc_mmu_page_num(hevc, new_pic->width, + new_pic->height, !bit_depth_10); + if (cur_mmu_4k_number < 0) + return -1; + + ret = decoder_mmu_box_alloc_idx( + hevc->mmu_box_dw, + new_pic->index, + cur_mmu_4k_number, + mmu_index_adr); + + hevc_print(hevc, H265_DEBUG_BUFMGR_MORE, + "%s pic index %d page count(%d) ret =%d\n", + __func__, new_pic->index, + cur_mmu_4k_number, ret); + return ret; +} +#endif static void release_pic_mmu_buf(struct hevc_state_s *hevc, struct PIC_s *pic) @@ -7933,9 +8491,20 @@ pic->scatter_alloc); if (hevc->mmu_enable - && ((hevc->double_write_mode & 0x10) == 0) - && pic->scatter_alloc) - decoder_mmu_box_free_idx(hevc->mmu_box, pic->index); + && !(hevc->double_write_mode & 0x10) + && pic->scatter_alloc) { + if (!hevc->is_used_v4l) + decoder_mmu_box_free_idx(hevc->mmu_box, pic->index); + else { + struct internal_comp_buf *ibuf = + ibuf = index_to_icomp_buf(hevc, pic->BUF_index); + decoder_mmu_box_free_idx(ibuf->mmu_box, ibuf->index); + } + } +#ifdef H265_10B_MMU_DW + if (hevc->dw_mmu_enable) + decoder_mmu_box_free_idx(hevc->mmu_box_dw, pic->index); +#endif pic->scatter_alloc = 0; } @@ -7995,7 +8564,16 @@ hevc->frame_mmu_map_addr = NULL; } +#ifdef H265_10B_MMU_DW + if (hevc->dw_mmu_enable && hevc->frame_dw_mmu_map_addr) { + if (hevc->frame_dw_mmu_map_phy_addr) + dma_free_coherent(amports_get_dma_device(), + get_frame_mmu_map_size(), hevc->frame_dw_mmu_map_addr, + hevc->frame_dw_mmu_map_phy_addr); + hevc->frame_dw_mmu_map_addr = NULL; + } +#endif //pr_err("[%s line %d] hevc->gvs=0x%p operation\n",__func__, __LINE__, hevc->gvs); } @@ -8007,20 +8585,34 @@ memset(&hevc->param, 0, sizeof(union param_u)); cur_buf_info = &hevc->work_space_buf_store; + if (force_bufspec) { memcpy(cur_buf_info, &amvh265_workbuff_spec[force_bufspec & 0xf], sizeof(struct BuffInfo_s)); pr_info("force buffer spec %d\n", force_bufspec & 0xf); - } else if (vdec_is_support_4k()) { - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) - memcpy(cur_buf_info, &amvh265_workbuff_spec[2], /* 4k */ - sizeof(struct BuffInfo_s)); - else - memcpy(cur_buf_info, &amvh265_workbuff_spec[1], /* 4k */ - sizeof(struct BuffInfo_s)); - } else - memcpy(cur_buf_info, &amvh265_workbuff_spec[0], /* 1080p */ - sizeof(struct BuffInfo_s)); + } else { + if (get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_TM2 && !is_cpu_tm2_revb()) { + if (vdec_is_support_4k()) { + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) + memcpy(cur_buf_info, &amvh265_workbuff_spec[2], /* 4k */ + sizeof(struct BuffInfo_s)); + else + memcpy(cur_buf_info, &amvh265_workbuff_spec[1], /* 4k */ + sizeof(struct BuffInfo_s)); + } else { + memcpy(cur_buf_info, &amvh265_workbuff_spec[0], /* 1080p */ + sizeof(struct BuffInfo_s)); + } + } else { //get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_TM2 || is_cpu_tm2_revb() + if (vdec_is_support_4k()) { + memcpy(cur_buf_info, &amvh265_workbuff_spec[5], /* 4k */ + sizeof(struct BuffInfo_s)); + } else { + memcpy(cur_buf_info, &amvh265_workbuff_spec[3], /* 1080p */ + sizeof(struct BuffInfo_s)); + } + } + } cur_buf_info->start_adr = hevc->buf_start; init_buff_spec(hevc, cur_buf_info); @@ -8079,6 +8671,19 @@ } memset(hevc->frame_mmu_map_addr, 0, get_frame_mmu_map_size()); } +#ifdef H265_10B_MMU_DW + if (hevc->dw_mmu_enable) { + hevc->frame_dw_mmu_map_addr = + dma_alloc_coherent(amports_get_dma_device(), + get_frame_mmu_map_size(), + &hevc->frame_dw_mmu_map_phy_addr, GFP_KERNEL); + if (hevc->frame_dw_mmu_map_addr == NULL) { + pr_err("%s: failed to alloc count_buffer\n", __func__); + return -1; + } + memset(hevc->frame_dw_mmu_map_addr, 0, get_frame_mmu_map_size()); + } +#endif ret = 0; return ret; } @@ -8115,16 +8720,14 @@ /*CANVAS_BLKMODE_64X32*/ #ifdef SUPPORT_10BIT - if (pic->double_write_mode) { + if (pic->double_write_mode && + ((pic->double_write_mode & 0x20) == 0)) { canvas_w = pic->width / - get_double_write_ratio(hevc, pic->double_write_mode); + get_double_write_ratio(pic->double_write_mode & 0xf); canvas_h = pic->height / - get_double_write_ratio(hevc, pic->double_write_mode); + get_double_write_ratio(pic->double_write_mode & 0xf); - if (hevc->mem_map_mode == 0) - canvas_w = ALIGN(canvas_w, 32); - else - canvas_w = ALIGN(canvas_w, 64); + canvas_w = ALIGN(canvas_w, 64); canvas_h = ALIGN(canvas_h, 32); if (vdec->parallel_dec == 1) { @@ -8137,12 +8740,12 @@ pic->uv_canvas_index = 128 + pic->index * 2 + 1; } - canvas_config_ex(pic->y_canvas_index, + config_cav_lut_ex(pic->y_canvas_index, pic->dw_y_adr, canvas_w, canvas_h, - CANVAS_ADDR_NOWRAP, blkmode, hevc->is_used_v4l ? 0 : 7); - canvas_config_ex(pic->uv_canvas_index, pic->dw_u_v_adr, + CANVAS_ADDR_NOWRAP, blkmode, hevc->is_used_v4l ? 0 : 7, VDEC_HEVC); + config_cav_lut_ex(pic->uv_canvas_index, pic->dw_u_v_adr, canvas_w, canvas_h, - CANVAS_ADDR_NOWRAP, blkmode, hevc->is_used_v4l ? 0 : 7); + CANVAS_ADDR_NOWRAP, blkmode, hevc->is_used_v4l ? 0 : 7, VDEC_HEVC); #ifdef MULTI_INSTANCE_SUPPORT pic->canvas_config[0].phy_addr = pic->dw_y_adr; @@ -8164,11 +8767,11 @@ blkmode; pic->canvas_config[1].endian = hevc->is_used_v4l ? 0 : 7; - ATRACE_COUNTER(hevc->set_canvas0_addr, pic->canvas_config[0].phy_addr); + ATRACE_COUNTER(hevc->trace.set_canvas0_addr, pic->canvas_config[0].phy_addr); hevc_print(hevc, H265_DEBUG_PIC_STRUCT,"%s(canvas0 addr:0x%x)\n", __func__, pic->canvas_config[0].phy_addr); #else - ATRACE_COUNTER(hevc->set_canvas0_addr, spec2canvas(pic)); + ATRACE_COUNTER(hevc->trace.set_canvas0_addr, spec2canvas(pic)); hevc_print(hevc, H265_DEBUG_PIC_STRUCT,"%s(canvas0 addr:0x%x)\n", __func__, spec2canvas(pic)); #endif @@ -8184,14 +8787,14 @@ pic->uv_canvas_index = 128 + pic->index; } - canvas_config_ex(pic->y_canvas_index, + config_cav_lut_ex(pic->y_canvas_index, pic->mc_y_adr, canvas_w, canvas_h, - CANVAS_ADDR_NOWRAP, blkmode, hevc->is_used_v4l ? 0 : 7); - canvas_config_ex(pic->uv_canvas_index, pic->mc_u_v_adr, + CANVAS_ADDR_NOWRAP, blkmode, hevc->is_used_v4l ? 0 : 7, VDEC_HEVC); + config_cav_lut_ex(pic->uv_canvas_index, pic->mc_u_v_adr, canvas_w, canvas_h, - CANVAS_ADDR_NOWRAP, blkmode, hevc->is_used_v4l ? 0 : 7); + CANVAS_ADDR_NOWRAP, blkmode, hevc->is_used_v4l ? 0 : 7, VDEC_HEVC); } - ATRACE_COUNTER(hevc->set_canvas0_addr, spec2canvas(pic)); + ATRACE_COUNTER(hevc->trace.set_canvas0_addr, spec2canvas(pic)); hevc_print(hevc, H265_DEBUG_PIC_STRUCT,"%s(canvas0 addr:0x%x)\n", __func__, spec2canvas(pic)); } @@ -8207,13 +8810,13 @@ } - canvas_config_ex(pic->y_canvas_index, pic->mc_y_adr, canvas_w, canvas_h, - CANVAS_ADDR_NOWRAP, blkmode, hevc->is_used_v4l ? 0 : 7); - canvas_config_ex(pic->uv_canvas_index, pic->mc_u_v_adr, + config_cav_lut_ex(pic->y_canvas_index, pic->mc_y_adr, canvas_w, canvas_h, + CANVAS_ADDR_NOWRAP, blkmode, hevc->is_used_v4l ? 0 : 7, VDEC_HEVC); + config_cav_lut_ex(pic->uv_canvas_index, pic->mc_u_v_adr, canvas_w, canvas_h, - CANVAS_ADDR_NOWRAP, blkmode, hevc->is_used_v4l ? 0 : 7); + CANVAS_ADDR_NOWRAP, blkmode, hevc->is_used_v4l ? 0 : 7, VDEC_HEVC); - ATRACE_COUNTER(hevc->set_canvas0_addr, spec2canvas(pic)); + ATRACE_COUNTER(hevc->trace.set_canvas0_addr, spec2canvas(pic)); hevc_print(hevc, H265_DEBUG_PIC_STRUCT,"%s(canvas0 addr:0x%x)\n", __func__, spec2canvas(pic)); #endif @@ -8247,8 +8850,8 @@ char *p = sei_buf; char *p_sei; uint16_t header; - uint8_t nal_unit_type; - uint8_t payload_type, payload_size; + uint16_t nal_unit_type; + uint16_t payload_type, payload_size; int i, j; if (size < 2) @@ -8260,9 +8863,16 @@ if ((nal_unit_type != NAL_UNIT_SEI) && (nal_unit_type != NAL_UNIT_SEI_SUFFIX)) return 0; - while (p+2 <= sei_buf+size) { + while (p+4 <= sei_buf+size) { payload_type = *p++; + if (payload_type == 0xff) { + payload_type += *p++; + } payload_size = *p++; + if (payload_size == 0xff) { + payload_size += *p++; + } + if (p+payload_size <= sei_buf+size) { switch (payload_type) { case SEI_PicTiming: @@ -8301,6 +8911,25 @@ pic->hdr10p_data_buf = NULL; pic->hdr10p_data_size = 0; } + } else if (p_sei[0] == 0x26 + && p_sei[1] == 0x00 + && p_sei[2] == 0x04 + && p_sei[3] == 0x00 + && p_sei[4] == 0x05) { + hevc->sei_present_flag |= SEI_HDR_CUVA_MASK; + + if (get_dbg_flag(hevc) & H265_DEBUG_PRINT_SEI) { + hevc_print(hevc, 0, + "hdr cuva data: (size %d)\n", + payload_size); + for (i = 0; i < payload_size; i++) { + hevc_print_cont(hevc, 0, + "%02x ", p_sei[i]); + if (((i + 1) & 0xf) == 0) + hevc_print_cont(hevc, 0, "\n"); + } + hevc_print_cont(hevc, 0, "\n"); + } } break; @@ -8460,9 +9089,9 @@ = &vf->prop.master_display_colour; vf->width = pic->width / - get_double_write_ratio(hevc, pic->double_write_mode); + get_double_write_ratio(pic->double_write_mode); vf->height = pic->height / - get_double_write_ratio(hevc, pic->double_write_mode); + get_double_write_ratio(pic->double_write_mode); vf->duration = hevc->frame_dur; vf->duration_pulldown = 0; @@ -8520,6 +9149,14 @@ data = data | (0x30<<8); vf->signal_type = data; } + + if (hevc->sei_present_flag & SEI_HDR_CUVA_MASK) { + u32 data; + data = vf->signal_type; + data = data & 0x7FFFFFFF; + data = data | (1<<31); + vf->signal_type = data; + } } else vf->signal_type = 0; @@ -8550,7 +9187,8 @@ vf_dp->content_light_level.present_flag = 0; if (hevc->is_used_v4l && - ((hevc->sei_present_flag & SEI_HDR10PLUS_MASK) || + ((hevc->video_signal_type & VIDEO_SIGNAL_TYPE_AVAILABLE_MASK) || + (hevc->sei_present_flag & SEI_HDR10PLUS_MASK) || (vf_dp->present_flag) || (vf_dp->content_light_level.present_flag))) { struct aml_vdec_hdr_infos hdr; @@ -8565,32 +9203,34 @@ if ((hevc->sei_present_flag & SEI_HDR10PLUS_MASK) && (pic->hdr10p_data_buf != NULL) && (pic->hdr10p_data_size != 0)) { - char *new_buf; - new_buf = vzalloc(pic->hdr10p_data_size); + if (pic->hdr10p_data_size <= 128) { + char *new_buf; + new_buf = kzalloc(pic->hdr10p_data_size, GFP_ATOMIC); - if (new_buf) { - memcpy(new_buf, pic->hdr10p_data_buf, pic->hdr10p_data_size); - if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR_MORE) { - hevc_print(hevc, 0, - "hdr10p data: (size %d)\n", - pic->hdr10p_data_size); - for (i = 0; i < pic->hdr10p_data_size; i++) { - hevc_print_cont(hevc, 0, - "%02x ", pic->hdr10p_data_buf[i]); - if (((i + 1) & 0xf) == 0) - hevc_print_cont(hevc, 0, "\n"); + if (new_buf) { + memcpy(new_buf, pic->hdr10p_data_buf, pic->hdr10p_data_size); + if (get_dbg_flag(hevc) & H265_DEBUG_PRINT_SEI) { + hevc_print(hevc, 0, + "hdr10p data: (size %d)\n", + pic->hdr10p_data_size); + for (i = 0; i < pic->hdr10p_data_size; i++) { + hevc_print_cont(hevc, 0, + "%02x ", pic->hdr10p_data_buf[i]); + if (((i + 1) & 0xf) == 0) + hevc_print_cont(hevc, 0, "\n"); + } + hevc_print_cont(hevc, 0, "\n"); } - hevc_print_cont(hevc, 0, "\n"); - } - vf->hdr10p_data_size = pic->hdr10p_data_size; - vf->hdr10p_data_buf = new_buf; - } else { - hevc_print(hevc, 0, - "%s:hdr10p data vzalloc size(%d) fail\n", - __func__, pic->hdr10p_data_size); - vf->hdr10p_data_buf = NULL; - vf->hdr10p_data_size = 0; + vf->hdr10p_data_size = pic->hdr10p_data_size; + vf->hdr10p_data_buf = new_buf; + } else { + hevc_print(hevc, 0, + "%s:hdr10p data vzalloc size(%d) fail\n", + __func__, pic->hdr10p_data_size); + vf->hdr10p_data_buf = NULL; + vf->hdr10p_data_size = 0; + } } vfree(pic->hdr10p_data_buf); @@ -8676,6 +9316,7 @@ return NULL; else if (step == 1) step = 2; + #if 0 if (force_disp_pic_index & 0x100) { int buffer_index = force_disp_pic_index & 0xff; @@ -8740,9 +9381,9 @@ set_frame_info(hevc, vf); vf->width = pic->width / - get_double_write_ratio(hevc, pic->double_write_mode); + get_double_write_ratio(pic->double_write_mode); vf->height = pic->height / - get_double_write_ratio(hevc, pic->double_write_mode); + get_double_write_ratio(pic->double_write_mode); force_disp_pic_index |= 0x200; return vf; @@ -8752,17 +9393,17 @@ if (kfifo_get(&hevc->display_q, &vf)) { struct vframe_s *next_vf = NULL; - ATRACE_COUNTER(hevc->vf_get_name, (long)vf); - ATRACE_COUNTER(hevc->disp_q_name, kfifo_len(&hevc->display_q)); + ATRACE_COUNTER(hevc->trace.vf_get_name, (long)vf); + ATRACE_COUNTER(hevc->trace.disp_q_name, kfifo_len(&hevc->display_q)); #ifdef MULTI_INSTANCE_SUPPORT - ATRACE_COUNTER(hevc->set_canvas0_addr, vf->canvas0_config[0].phy_addr); + ATRACE_COUNTER(hevc->trace.set_canvas0_addr, vf->canvas0_config[0].phy_addr); #else - ATRACE_COUNTER(hevc->get_canvas0_addr, vf->canvas0Addr); + ATRACE_COUNTER(hevc->trace.get_canvas0_addr, vf->canvas0Addr); #endif if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT) { hevc_print(hevc, 0, - "%s(vf 0x%p type %d index 0x%x poc %d/%d) pts(%d,%ld) dur %d\n", + "%s(vf 0x%p type %d index 0x%x poc %d/%d) pts(%d,%d) dur %d\n", __func__, vf, vf->type, vf->index, get_pic_poc(hevc, vf->index & 0xff), get_pic_poc(hevc, (vf->index >> 8) & 0xff), @@ -8792,8 +9433,8 @@ } #endif hevc->show_frame_num++; - vf->index_disp = hevc->vf_get_count; - hevc->vf_get_count++; + vf->index_disp = atomic_read(&hevc->vf_get_count); + atomic_add(1, &hevc->vf_get_count); if (kfifo_peek(&hevc->display_q, &next_vf) && next_vf) { vf->next_vf_pts_valid = true; @@ -8831,23 +9472,39 @@ unsigned char index_top; unsigned char index_bot; - if (vf && (vf_valid_check(vf, hevc) == false)) + if (!vf) return; if (vf == (&hevc->vframe_dummy)) return; - if (!vf) + if (vf && (vf_valid_check(vf, hevc) == false)) return; - ATRACE_COUNTER(hevc->vf_put_name, (long)vf); -#ifdef MULTI_INSTANCE_SUPPORT - ATRACE_COUNTER(hevc->put_canvas0_addr, vf->canvas0_config[0].phy_addr); -#else - ATRACE_COUNTER(hevc->put_canvas0_addr, vf->canvas0Addr); -#endif + if (hevc->enable_fence && vf->fence) { + int ret, i; + mutex_lock(&hevc->fence_mutex); + ret = dma_fence_get_status(vf->fence); + if (ret == 0) { + for (i = 0; i < VF_POOL_SIZE; i++) { + if (hevc->fence_vf_s.fence_vf[i] == NULL) { + hevc->fence_vf_s.fence_vf[i] = vf; + hevc->fence_vf_s.used_size++; + mutex_unlock(&hevc->fence_mutex); + return; + } + } + } + mutex_unlock(&hevc->fence_mutex); + } + + ATRACE_COUNTER(hevc->trace.vf_put_name, (long)vf); +#ifdef MULTI_INSTANCE_SUPPORT + ATRACE_COUNTER(hevc->trace.put_canvas0_addr, vf->canvas0_config[0].phy_addr); +#else + ATRACE_COUNTER(hevc->trace.put_canvas0_addr, vf->canvas0Addr); +#endif index_top = vf->index & 0xff; index_bot = (vf->index >> 8) & 0xff; - if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT) hevc_print(hevc, 0, "%s(vf 0x%p type %d index 0x%x put canvas0 addr:0x%x)\n", @@ -8858,27 +9515,25 @@ , vf->canvas0Addr #endif ); - - hevc->vf_put_count++; + atomic_add(1, &hevc->vf_put_count); spin_lock_irqsave(&lock, flags); kfifo_put(&hevc->newframe_q, (const struct vframe_s *)vf); - ATRACE_COUNTER(hevc->new_q_name, kfifo_len(&hevc->newframe_q)); + ATRACE_COUNTER(hevc->trace.new_q_name, kfifo_len(&hevc->newframe_q)); if (hevc->enable_fence && vf->fence) { vdec_fence_put(vf->fence); vf->fence = NULL; } if (vf->hdr10p_data_buf) { - vfree(vf->hdr10p_data_buf); + kfree(vf->hdr10p_data_buf); vf->hdr10p_data_buf = NULL; vf->hdr10p_data_size = 0; } + if (index_top != 0xff && index_top < MAX_REF_PIC_NUM && hevc->m_PIC[index_top]) { - if (hevc->is_used_v4l) - hevc->m_PIC[index_top]->vframe_bound = true; if (hevc->m_PIC[index_top]->vf_ref > 0) { hevc->m_PIC[index_top]->vf_ref--; @@ -8896,8 +9551,6 @@ if (index_bot != 0xff && index_bot < MAX_REF_PIC_NUM && hevc->m_PIC[index_bot]) { - if (hevc->is_used_v4l) - hevc->m_PIC[index_bot]->vframe_bound = true; if (hevc->m_PIC[index_bot]->vf_ref > 0) { hevc->m_PIC[index_bot]->vf_ref--; @@ -8944,13 +9597,14 @@ unsigned char index; if (!req->vf) { - req->aux_size = hevc->vf_put_count; + req->aux_size = atomic_read(&hevc->vf_put_count); return 0; } spin_lock_irqsave(&lock, flags); index = req->vf->index & 0xff; req->aux_buf = NULL; req->aux_size = 0; + req->format = VFORMAT_HEVC; if (req->bot_flag) index = (req->vf->index >> 8) & 0xff; if (index != 0xff @@ -9023,6 +9677,8 @@ if (kfifo_len(&hevc->pending_q) > 1) { unsigned long flags; + int index1; + int index2; /* do not pending more than 1 frame */ if (kfifo_get(&hevc->pending_q, &vf) == 0) { hevc_print(hevc, 0, @@ -9031,34 +9687,45 @@ } if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT) hevc_print(hevc, 0, - "%s warning(1), vf=>display_q: (index 0x%x)\n", - __func__, vf->index); + "%s warning(1), vf=>display_q: (index 0x%x), vf 0x%px\n", + __func__, vf->index, vf); if ((pair_pic->double_write_mode == 3) && (!(IS_8K_SIZE(vf->width, vf->height)))) { vf->type |= VIDTYPE_COMPRESS; if (hevc->mmu_enable) vf->type |= VIDTYPE_SCATTER; } + hevc->vf_pre_count++; spin_lock_irqsave(&lock, flags); kfifo_put(&hevc->newframe_q, (const struct vframe_s *)vf); - vf->index &= 0xff; - if (vf->index >= MAX_REF_PIC_NUM) { + index1 = vf->index & 0xff; + index2 = (vf->index >> 8) & 0xff; + if (index1 >= MAX_REF_PIC_NUM && + index2 >= MAX_REF_PIC_NUM) { spin_unlock_irqrestore(&lock, flags); return -1; } - hevc->m_PIC[vf->index]->vf_ref = 0; - hevc->m_PIC[vf->index]->output_ready = 0; + + if (index1 < MAX_REF_PIC_NUM) { + hevc->m_PIC[index1]->vf_ref = 0; + hevc->m_PIC[index1]->output_ready = 0; + } + if (index2 < MAX_REF_PIC_NUM) { + hevc->m_PIC[index2]->vf_ref = 0; + hevc->m_PIC[index2]->output_ready = 0; + } + if (hevc->wait_buf != 0) WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG, 0x1); spin_unlock_irqrestore(&lock, flags); - ATRACE_COUNTER(hevc->pts_name, vf->pts); + ATRACE_COUNTER(hevc->trace.pts_name, vf->pts); } if (kfifo_peek(&hevc->pending_q, &vf)) { - if (pair_pic->vf_ref <= 0) { + if (pair_pic == NULL || pair_pic->vf_ref <= 0) { /* *if pair_pic is recycled (pair_pic->vf_ref <= 0), *do not use it @@ -9083,7 +9750,7 @@ vdec_vframe_ready(hw_to_vdec(hevc), vf); kfifo_put(&hevc->display_q, (const struct vframe_s *)vf); - ATRACE_COUNTER(hevc->pts_name, vf->pts); + ATRACE_COUNTER(hevc->trace.pts_name, vf->pts); } } else if ((!pair_frame_top_flag) && (((vf->index >> 8) & 0xff) == 0xff)) { @@ -9105,7 +9772,7 @@ vdec_vframe_ready(hw_to_vdec(hevc), vf); kfifo_put(&hevc->display_q, (const struct vframe_s *)vf); - ATRACE_COUNTER(hevc->pts_name, vf->pts); + ATRACE_COUNTER(hevc->trace.pts_name, vf->pts); hevc->vf_pre_count++; if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT) hevc_print(hevc, 0, @@ -9132,7 +9799,7 @@ vdec_vframe_ready(hw_to_vdec(hevc), vf); kfifo_put(&hevc->display_q, (const struct vframe_s *)vf); - ATRACE_COUNTER(hevc->pts_name, vf->pts); + ATRACE_COUNTER(hevc->trace.pts_name, vf->pts); hevc->vf_pre_count++; if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT) hevc_print(hevc, 0, @@ -9147,16 +9814,33 @@ static void update_vf_memhandle(struct hevc_state_s *hevc, struct vframe_s *vf, struct PIC_s *pic) { - if (pic->index < 0) { - vf->mem_handle = NULL; - vf->mem_head_handle = NULL; - } else if (vf->type & VIDTYPE_SCATTER) { - vf->mem_handle = - decoder_mmu_box_get_mem_handle( - hevc->mmu_box, pic->index); - vf->mem_head_handle = - decoder_bmmu_box_get_mem_handle( - hevc->bmmu_box, VF_BUFFER_IDX(pic->BUF_index)); + vf->mem_handle = NULL; + vf->mem_head_handle = NULL; + + /* keeper not needed for v4l solution */ + if (hevc->is_used_v4l) + return; + + if (vf->type & VIDTYPE_SCATTER) { +#ifdef H265_10B_MMU_DW + if (hevc->dw_mmu_enable) { + vf->mem_handle = + decoder_mmu_box_get_mem_handle( + hevc->mmu_box_dw, pic->index); + vf->mem_head_handle = + decoder_bmmu_box_get_mem_handle( + hevc->bmmu_box, VF_BUFFER_IDX(pic->BUF_index)); + } else + +#endif + { + vf->mem_handle = + decoder_mmu_box_get_mem_handle( + hevc->mmu_box, pic->index); + vf->mem_head_handle = + decoder_bmmu_box_get_mem_handle( + hevc->bmmu_box, VF_BUFFER_IDX(pic->BUF_index)); + } } else { vf->mem_handle = decoder_bmmu_box_get_mem_handle( @@ -9228,11 +9912,11 @@ } -static inline void hevc_update_gvs(struct hevc_state_s *hevc) +static inline void hevc_update_gvs(struct hevc_state_s *hevc, struct PIC_s *pic) { - if (hevc->gvs->frame_height != hevc->frame_height) { - hevc->gvs->frame_width = hevc->frame_width; - hevc->gvs->frame_height = hevc->frame_height; + if (hevc->gvs->frame_height != pic->height) { + hevc->gvs->frame_width = pic->width; + hevc->gvs->frame_height = pic->height; } if (hevc->gvs->frame_dur != hevc->frame_dur) { hevc->gvs->frame_dur = hevc->frame_dur; @@ -9254,7 +9938,7 @@ decoder_do_frame_check(hw_to_vdec(hevc), vf); vdec_vframe_ready(hw_to_vdec(hevc), vf); kfifo_put(&hevc->display_q, (const struct vframe_s *)vf); - ATRACE_COUNTER(hevc->pts_name, vf->pts); + ATRACE_COUNTER(hevc->trace.pts_name, vf->pts); } static int post_prepare_process(struct vdec_s *vdec, struct PIC_s *frame) @@ -9266,7 +9950,7 @@ frame->output_ready = 0; frame->show_frame = false; hevc_print(hevc, 0, "discard show frame.\n"); - return -1; + return 0; } frame->show_frame = true; @@ -9284,6 +9968,8 @@ u32 frame_size = 0; struct vdec_info tmp4x; struct aml_vcodec_ctx * v4l2_ctx = hevc->v4l2_ctx; + struct vdec_v4l2_buffer *fb = NULL; + int index; /* swap uv */ if (hevc->is_used_v4l) { @@ -9306,11 +9992,12 @@ if (hevc->is_used_v4l) { vf->v4l_mem_handle = hevc->m_BUF[pic->BUF_index].v4l_ref_buf_addr; + fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; if (hevc->mmu_enable) { vf->mm_box.bmmu_box = hevc->bmmu_box; - vf->mm_box.bmmu_idx = VF_BUFFER_IDX(pic->BUF_index); + vf->mm_box.bmmu_idx = VF_BUFFER_IDX(hevc->buffer_wrap[pic->BUF_index]); vf->mm_box.mmu_box = hevc->mmu_box; - vf->mm_box.mmu_idx = pic->index; + vf->mm_box.mmu_idx = hevc->buffer_wrap[pic->BUF_index]; } } @@ -9340,7 +10027,8 @@ if ((vdec->vbuf.no_parser == 0) || (vdec->vbuf.use_ptsserv)) { if (pts_lookup_offset_us64 (PTS_TYPE_VIDEO, stream_offset, &vf->pts, - &frame_size, 0, &vf->pts_us64) != 0) { + &frame_size, 0, + &vf->pts_us64) != 0) { #ifdef DEBUG_PTS hevc->pts_missed++; #endif @@ -9388,8 +10076,8 @@ hevc->last_pts_us64 = vf->pts_us64; if ((get_dbg_flag(hevc) & H265_DEBUG_OUT_PTS) != 0) { hevc_print(hevc, 0, - "H265 dec out pts: vf->pts=%d, vf->pts_us64 = %lld\n", - vf->pts, vf->pts_us64); + "H265 dec out pts: vf->pts=%d, vf->pts_us64 = %lld, ts: %llu\n", + vf->pts, vf->pts_us64, vf->timestamp); } /* @@ -9409,26 +10097,44 @@ /* double write only */ vf->compBodyAddr = 0; vf->compHeadAddr = 0; +#ifdef H265_10B_MMU_DW + vf->dwBodyAddr = 0; + vf->dwHeadAddr = 0; +#endif } else { - - if (hevc->mmu_enable) { - vf->compBodyAddr = 0; - vf->compHeadAddr = pic->header_adr; - } else { - vf->compBodyAddr = pic->mc_y_adr; /*body adr*/ - vf->compHeadAddr = pic->mc_y_adr + - pic->losless_comp_body_size; - vf->mem_head_handle = NULL; - } - - /*head adr*/ + if (hevc->mmu_enable) { + vf->compBodyAddr = 0; + vf->compHeadAddr = pic->header_adr; +#ifdef H265_10B_MMU_DW + vf->dwBodyAddr = 0; + vf->dwHeadAddr = 0; + if (pic->double_write_mode & 0x20) { + u32 mode = pic->double_write_mode & 0xf; + if (mode == 5 || mode == 3) + vf->dwHeadAddr = pic->header_dw_adr; + else if ((mode == 1 || mode == 2 || mode == 4) + && (debug & H265_DEBUG_OUT_PTS) == 0) { + vf->compHeadAddr = pic->header_dw_adr; + pr_debug("Use dw mmu for display\n"); + } + } +#endif + } else { + vf->compBodyAddr = pic->mc_y_adr; /*body adr*/ + vf->compHeadAddr = pic->mc_y_adr + + pic->losless_comp_body_size; + vf->mem_head_handle = NULL; + } + /*head adr*/ vf->canvas0Addr = vf->canvas1Addr = 0; } - if (pic->double_write_mode) { + if (pic->double_write_mode && + ((pic->double_write_mode & 0x20) == 0)) { vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD; vf->type |= nv_order; - if (((pic->double_write_mode == 3) || (pic->double_write_mode == 5)) && + if (((pic->double_write_mode == 3) || (pic->double_write_mode == 5) || + (pic->double_write_mode == 9)) && (!(IS_8K_SIZE(pic->width, pic->height)))) { vf->type |= VIDTYPE_COMPRESS; if (hevc->mmu_enable) @@ -9580,9 +10286,21 @@ vf->sar_height = hevc->cur_pic->sar_height; } vf->width = vf->width / - get_double_write_ratio(hevc, pic->double_write_mode); + get_double_write_ratio(pic->double_write_mode & 0xf); vf->height = vf->height / - get_double_write_ratio(hevc, pic->double_write_mode); + get_double_write_ratio(pic->double_write_mode & 0xf); + +#ifdef H265_10B_MMU_DW + if ((pic->double_write_mode & 0x20) && + ((pic->double_write_mode & 0xf) == 2 || + (pic->double_write_mode & 0xf) == 4)) { + vf->compWidth = vf->width; + vf->compHeight = vf->height; + } +#endif + if (hevc->is_used_v4l && vdec->prog_only) + pic->pic_struct = 0; + #ifdef HEVC_PIC_STRUCT_SUPPORT if (pic->pic_struct == 3 || pic->pic_struct == 4) { struct vframe_s *vf2; @@ -9613,12 +10331,20 @@ vf2->type = VIDTYPE_INTERLACE_TOP | nv_order; } - put_vf_to_display_q(hevc, vf); - hevc->vf_pre_count++; - vdec_vframe_ready(hw_to_vdec(hevc), vf2); - kfifo_put(&hevc->display_q, - (const struct vframe_s *)vf2); - ATRACE_COUNTER(hevc->pts_name, vf2->pts); + if (pic->show_frame) { + put_vf_to_display_q(hevc, vf); + hevc->vf_pre_count++; + vdec_vframe_ready(hw_to_vdec(hevc), vf2); + kfifo_put(&hevc->display_q, + (const struct vframe_s *)vf2); + ATRACE_COUNTER(hevc->trace.pts_name, vf2->pts); + } else { + vh265_vf_put(vf, vdec); + vh265_vf_put(vf2, vdec); + atomic_add(2, &hevc->vf_get_count); + hevc->vf_pre_count += 2; + return 0; + } } else if (pic->pic_struct == 5 || pic->pic_struct == 6) { struct vframe_s *vf2, *vf3; @@ -9659,18 +10385,26 @@ vf3->type = VIDTYPE_INTERLACE_BOTTOM | nv_order; } - put_vf_to_display_q(hevc, vf); - hevc->vf_pre_count++; - vdec_vframe_ready(hw_to_vdec(hevc), vf2); - kfifo_put(&hevc->display_q, - (const struct vframe_s *)vf2); - ATRACE_COUNTER(hevc->pts_name, vf2->pts); - hevc->vf_pre_count++; - vdec_vframe_ready(hw_to_vdec(hevc), vf3); - kfifo_put(&hevc->display_q, - (const struct vframe_s *)vf3); - ATRACE_COUNTER(hevc->pts_name, vf3->pts); - + if (pic->show_frame) { + put_vf_to_display_q(hevc, vf); + hevc->vf_pre_count++; + vdec_vframe_ready(hw_to_vdec(hevc), vf2); + kfifo_put(&hevc->display_q, + (const struct vframe_s *)vf2); + ATRACE_COUNTER(hevc->trace.pts_name, vf2->pts); + hevc->vf_pre_count++; + vdec_vframe_ready(hw_to_vdec(hevc), vf3); + kfifo_put(&hevc->display_q, + (const struct vframe_s *)vf3); + ATRACE_COUNTER(hevc->trace.pts_name, vf3->pts); + } else { + vh265_vf_put(vf, vdec); + vh265_vf_put(vf2, vdec); + vh265_vf_put(vf3, vdec); + atomic_add(3, &hevc->vf_get_count); + hevc->vf_pre_count += 3;; + return 0; + } } else if (pic->pic_struct == 9 || pic->pic_struct == 10) { if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT) @@ -9683,35 +10417,40 @@ /* process previous pending vf*/ process_pending_vframe(hevc, pic, (pic->pic_struct == 9)); - - decoder_do_frame_check(vdec, vf); - vdec_vframe_ready(vdec, vf); - /* process current vf */ - kfifo_put(&hevc->pending_q, - (const struct vframe_s *)vf); vf->height <<= 1; - if (pic->pic_struct == 9) { - vf->type = VIDTYPE_INTERLACE_TOP - | nv_order | VIDTYPE_VIU_FIELD; - process_pending_vframe(hevc, - hevc->pre_bot_pic, 0); + if (pic->show_frame) { + decoder_do_frame_check(vdec, vf); + vdec_vframe_ready(vdec, vf); + /* process current vf */ + kfifo_put(&hevc->pending_q, + (const struct vframe_s *)vf); + if (pic->pic_struct == 9) { + vf->type = VIDTYPE_INTERLACE_TOP + | nv_order | VIDTYPE_VIU_FIELD; + process_pending_vframe(hevc, + hevc->pre_bot_pic, 0); + } else { + vf->type = VIDTYPE_INTERLACE_BOTTOM | + nv_order | VIDTYPE_VIU_FIELD; + vf->index = (pic->index << 8) | 0xff; + process_pending_vframe(hevc, + hevc->pre_top_pic, 1); + } + + if (hevc->vf_pre_count == 0) + hevc->vf_pre_count++; + + /**/ + if (pic->pic_struct == 9) + hevc->pre_top_pic = pic; + else + hevc->pre_bot_pic = pic; } else { - vf->type = VIDTYPE_INTERLACE_BOTTOM | - nv_order | VIDTYPE_VIU_FIELD; - vf->index = (pic->index << 8) | 0xff; - process_pending_vframe(hevc, - hevc->pre_top_pic, 1); - } - - if (hevc->vf_pre_count == 0) + vh265_vf_put(vf, vdec); + atomic_add(1, &hevc->vf_get_count); hevc->vf_pre_count++; - - /**/ - if (pic->pic_struct == 9) - hevc->pre_top_pic = pic; - else - hevc->pre_bot_pic = pic; - + return 0; + } } else if (pic->pic_struct == 11 || pic->pic_struct == 12) { if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT) @@ -9734,19 +10473,25 @@ nv_order | VIDTYPE_VIU_FIELD; vf->index = (pic->index << 8) | 0xff; } - decoder_do_frame_check(vdec, vf); - vdec_vframe_ready(vdec, vf); - kfifo_put(&hevc->pending_q, - (const struct vframe_s *)vf); - if (hevc->vf_pre_count == 0) + if (pic->show_frame) { + decoder_do_frame_check(vdec, vf); + vdec_vframe_ready(vdec, vf); + kfifo_put(&hevc->pending_q, + (const struct vframe_s *)vf); + if (hevc->vf_pre_count == 0) + hevc->vf_pre_count++; + + /**/ + if (pic->pic_struct == 11) + hevc->pre_top_pic = pic; + else + hevc->pre_bot_pic = pic; + } else { + vh265_vf_put(vf, vdec); + atomic_add(1, &hevc->vf_get_count); hevc->vf_pre_count++; - - /**/ - if (pic->pic_struct == 11) - hevc->pre_top_pic = pic; - else - hevc->pre_bot_pic = pic; - + return 0; + } } else { pic->vf_ref = 1; @@ -9779,50 +10524,81 @@ hevc->pre_bot_pic = pic; break; } - put_vf_to_display_q(hevc, vf); + if (pic->show_frame) { + put_vf_to_display_q(hevc, vf); + } else { + vh265_vf_put(vf, vdec); + atomic_add(1, &hevc->vf_get_count); + hevc->vf_pre_count++; + return 0; + } } #else vf->type_original = vf->type; pic->vf_ref = 1; put_vf_to_display_q(hevc, vf); #endif - ATRACE_COUNTER(hevc->new_q_name, kfifo_len(&hevc->newframe_q)); - ATRACE_COUNTER(hevc->disp_q_name, kfifo_len(&hevc->display_q)); + ATRACE_COUNTER(hevc->trace.new_q_name, kfifo_len(&hevc->newframe_q)); + ATRACE_COUNTER(hevc->trace.disp_q_name, kfifo_len(&hevc->display_q)); /*count info*/ vdec_count_info(hevc->gvs, 0, stream_offset); - if (hevc->cur_pic != NULL) { - if (hevc->cur_pic->slice_type == I_SLICE) { - hevc->gvs->i_decoded_frames++; - } else if (hevc->cur_pic->slice_type == P_SLICE) { - hevc->gvs->p_decoded_frames++; - } else if (hevc->cur_pic->slice_type == B_SLICE) { - hevc->gvs->b_decoded_frames++; - } + if (pic->slice_type == I_SLICE) { + hevc->gvs->i_decoded_frames++; + vf->frame_type |= V4L2_BUF_FLAG_KEYFRAME; + } else if (pic->slice_type == P_SLICE) { + hevc->gvs->p_decoded_frames++; + vf->frame_type |= V4L2_BUF_FLAG_PFRAME; + } else if (pic->slice_type == B_SLICE) { + hevc->gvs->b_decoded_frames++; + vf->frame_type |= V4L2_BUF_FLAG_BFRAME; } - hevc_update_gvs(hevc); + hevc_update_gvs(hevc, pic); memcpy(&tmp4x, hevc->gvs, sizeof(struct vdec_info)); - tmp4x.bit_depth_luma = hevc->bit_depth_luma; - tmp4x.bit_depth_chroma = hevc->bit_depth_chroma; - tmp4x.double_write_mode = get_double_write_mode(hevc); + tmp4x.bit_depth_luma = pic->bit_depth_luma; + tmp4x.bit_depth_chroma = pic->bit_depth_chroma; + tmp4x.double_write_mode = pic->double_write_mode; vdec_fill_vdec_frame(vdec, &hevc->vframe_qos, &tmp4x, vf, pic->hw_decode_time); vdec->vdec_fps_detec(vdec->id); hevc_print(hevc, H265_DEBUG_BUFMGR, - "%s(type %d index 0x%x poc %d/%d) pts(%d,%lld) dur %d\n", + "%s(type %d index 0x%x poc %d/%d) pts(%d,%d) dur %d\n", __func__, vf->type, vf->index, get_pic_poc(hevc, vf->index & 0xff), get_pic_poc(hevc, (vf->index >> 8) & 0xff), vf->pts, vf->pts_us64, vf->duration); + + if (pic->pic_struct == 10 || pic->pic_struct == 12) { + index = (vf->index >> 8) & 0xff; + } else { + index = vf->index & 0xff; + } + #ifdef AUX_DATA_CRC - if ((vf->index & 0xff) <= MAX_REF_PIC_NUM) - decoder_do_aux_data_check(vdec, hevc->m_PIC[vf->index & 0xff]->aux_data_buf, - hevc->m_PIC[vf->index & 0xff]->aux_data_size); + if (index <= MAX_REF_PIC_NUM) + decoder_do_aux_data_check(vdec, hevc->m_PIC[index]->aux_data_buf, + hevc->m_PIC[index]->aux_data_size); #endif + + hevc_print(hevc, H265_DEBUG_PRINT_SEI, + "aux_data_size:%d, signal_type: %d, sei_present_flag: %d\n", + hevc->m_PIC[index]->aux_data_size, hevc->video_signal_type, hevc->sei_present_flag); + + if (get_dbg_flag(hevc) & H265_DEBUG_PRINT_SEI) { + int i = 0; + PR_INIT(128); + for (i = 0; i < hevc->m_PIC[index]->aux_data_size; i++) { + PR_FILL("%02x ", hevc->m_PIC[index]->aux_data_buf[i]); + if (((i + 1) & 0xf) == 0) + PR_INFO(hevc->index); + } + PR_INFO(hevc->index); + } + if (hevc->is_used_v4l) update_vframe_src_fmt(vf, - hevc->m_PIC[vf->index & 0xff]->aux_data_buf, - hevc->m_PIC[vf->index & 0xff]->aux_data_size, - false, hevc->provider_name, NULL); + hevc->m_PIC[index]->aux_data_buf, + hevc->m_PIC[index]->aux_data_size, + hevc->dv_duallayer, hevc->provider_name, NULL); /*if (pic->vf_ref == hevc->vf_pre_count) {*/ if (hevc->kpi_first_i_decoded == 0) { @@ -9832,8 +10608,16 @@ } if (without_display_mode == 0) { - vf_notify_receiver(hevc->provider_name, - VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + if (hevc->is_used_v4l) { + if (v4l2_ctx->is_stream_off) { + vh265_vf_put(vh265_vf_get(vdec), vdec); + } else { + fb->task->submit(fb->task, TASK_TYPE_DEC); + } + } else { + vf_notify_receiver(hevc->provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + } } else vh265_vf_put(vh265_vf_get(vdec), vdec); @@ -9851,10 +10635,10 @@ return 0; /* create fence for each buffers. */ - if (vdec_timeline_create_fence(&vdec->sync)) + if (vdec_timeline_create_fence(vdec->sync)) return -1; - pic->fence = vdec->sync.fence; + pic->fence = vdec->sync->fence; pic->stream_offset = READ_VREG(HEVC_SHIFT_BYTE_COUNT); if (hevc->chunk) { @@ -9862,7 +10646,7 @@ pic->pts64 = hevc->chunk->pts64; pic->timestamp = hevc->chunk->timestamp; } - + pic->show_frame = true; post_video_frame(vdec, pic); display_frame_count[hevc->index]++; @@ -9876,6 +10660,10 @@ (struct hevc_state_s *)vdec->private; if (hevc->enable_fence) { + int i, j, used_size, ret; + int signed_count = 0; + struct vframe_s *signed_fence[VF_POOL_SIZE]; + post_prepare_process(vdec, frame); if (!frame->show_frame) @@ -9884,16 +10672,35 @@ hevc->m_PIC[frame->index]->vf_ref = 1; /* notify signal to wake up wq of fence. */ - vdec_timeline_increase(&vdec->sync, 1); + vdec_timeline_increase(vdec->sync, 1); + mutex_lock(&hevc->fence_mutex); + used_size = hevc->fence_vf_s.used_size; + if (used_size) { + for (i = 0, j = 0; i < VF_POOL_SIZE && j < used_size; i++) { + if (hevc->fence_vf_s.fence_vf[i] != NULL) { + ret = dma_fence_get_status(hevc->fence_vf_s.fence_vf[i]->fence); + if (ret == 1) { + signed_fence[signed_count] = hevc->fence_vf_s.fence_vf[i]; + hevc->fence_vf_s.fence_vf[i] = NULL; + hevc->fence_vf_s.used_size--; + signed_count++; + } + j++; + } + } + } + mutex_unlock(&hevc->fence_mutex); + if (signed_count != 0) { + for (i = 0; i < signed_count; i++) + vh265_vf_put(signed_fence[i], vdec); + } + return 0; } if (post_prepare_process(vdec, frame)) return -1; - if (!frame->show_frame) - return 0; - if (post_video_frame(vdec, frame)) return -1; @@ -9920,7 +10727,8 @@ } if (index == INVALID_IDX) { - if (vdec_v4l_get_buffer(hw->v4l2_ctx, &fb) < 0) { + ctx->fb_ops.query(&ctx->fb_ops, &hw->fb_token); + if (ctx->fb_ops.alloc(&ctx->fb_ops, hw->fb_token, &fb, AML_FB_REQ_DEC) < 0) { pr_err("[%d] EOS get free buff fail.\n", ctx->id); return -1; } @@ -9932,10 +10740,16 @@ vf->flag = VFRAME_FLAG_EMPTY_FRAME_V4L; vf->v4l_mem_handle = (index == INVALID_IDX) ? (ulong)fb : hw->m_BUF[index].v4l_ref_buf_addr; + fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; + vdec_vframe_ready(vdec, vf); kfifo_put(&hw->display_q, (const struct vframe_s *)vf); - vf_notify_receiver(vdec->vf_provider_name, - VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + + if (hw->is_used_v4l) + fb->task->submit(fb->task, TASK_TYPE_DEC); + else + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); pr_info("[%d] H265 EOS notify.\n", (hw->is_used_v4l)?ctx->id:vdec->id); } @@ -10266,7 +11080,7 @@ struct vdec_s *vdec = hw_to_vdec(hevc); if (get_dbg_flag(hevc) & - H265_DEBUG_BUFMGR_MORE) + H265_DEBUG_PRINT_SEI) dump_aux_buf(hevc); if (vdec->dolby_meta_with_el || vdec->slave) { set_aux_data(hevc, @@ -10297,49 +11111,123 @@ hevc->rps_set_id = (decode_info >> 8) & 0xff; } -static int vh265_get_ps_info(struct hevc_state_s *hevc, int width, int height, struct aml_vdec_ps_infos *ps) +static int vh265_get_ps_info(struct hevc_state_s *hevc, + union param_u *rpm_param, + struct aml_vdec_ps_infos *ps) { - int dw_mode = v4l_parser_get_double_write_mode(hevc, width, height); + u32 width = rpm_param->p.pic_width_in_luma_samples; + u32 height = rpm_param->p.pic_height_in_luma_samples; + u32 SubWidthC, SubHeightC; - ps->visible_width = width / get_double_write_ratio(hevc, dw_mode); - ps->visible_height = height / get_double_write_ratio(hevc, dw_mode); - ps->coded_width = ALIGN(width, 32) / get_double_write_ratio(hevc, dw_mode); - ps->coded_height = ALIGN(height, 32) / get_double_write_ratio(hevc, dw_mode); + switch (rpm_param->p.chroma_format_idc) { + case 1: + SubWidthC = 2; + SubHeightC = 2; + break; + case 2: + SubWidthC = 2; + SubHeightC = 1; + break; + default: + SubWidthC = 1; + SubHeightC = 1; + break; + } + + width -= SubWidthC * + (rpm_param->p.conf_win_left_offset + + rpm_param->p.conf_win_right_offset); + height -= SubHeightC * + (rpm_param->p.conf_win_top_offset + + rpm_param->p.conf_win_bottom_offset); + + hevc->last_width = rpm_param->p.pic_width_in_luma_samples; + hevc->last_height = rpm_param->p.pic_height_in_luma_samples; + hevc->sps_num_reorder_pics_0 = + rpm_param->p.sps_num_reorder_pics_0; + hevc->used_buf_num = v4l_parser_work_pic_num(hevc); + + ps->visible_width = width; + ps->visible_height = height; + ps->coded_width = ALIGN(width, 64); + ps->coded_height = ALIGN(height, 64); ps->dpb_size = v4l_parser_work_pic_num(hevc); - ps->field = hevc->interlace_flag ? V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE; return 0; } +static void get_comp_buf_info(struct hevc_state_s *hevc, + struct vdec_comp_buf_info *info) +{ + u16 bit_depth = hevc->param.p.bit_depth; + int w = hevc->param.p.pic_width_in_luma_samples; + int h = hevc->param.p.pic_height_in_luma_samples; + + info->max_size = hevc_max_mmu_buf_size( + hevc->max_pic_w, + hevc->max_pic_h); + info->header_size = hevc_get_header_size(w,h); + info->frame_buffer_size = hevc_mmu_page_num( + hevc, w, h, bit_depth == 0); + + pr_info("hevc get comp info: %d %d %d\n", + info->max_size, info->header_size, + info->frame_buffer_size); +} + static int v4l_res_change(struct hevc_state_s *hevc, union param_u *rpm_param) { struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hevc->v4l2_ctx); - int ret = 0; + int i, ret = 0; - if (ctx->param_sets_from_ucode && - hevc->res_ch_flag == 0) { + if (ctx->param_sets_from_ucode) { struct aml_vdec_ps_infos ps; int width = rpm_param->p.pic_width_in_luma_samples; int height = rpm_param->p.pic_height_in_luma_samples; - if ((hevc->pic_w != 0 && - hevc->pic_h != 0) && - (hevc->pic_w != width || - hevc->pic_h != height)) { + if ((hevc->last_width != 0 && + hevc->last_height != 0) && + (hevc->last_width != width || + hevc->last_height != height)) { hevc_print(hevc, 0, "v4l_res_change Pic Width/Height Change (%d,%d)=>(%d,%d), interlace %d\n", - hevc->pic_w, hevc->pic_h, + hevc->last_width, hevc->last_height, width, height, hevc->interlace_flag); - vh265_get_ps_info(hevc, width, height, &ps); + if (get_valid_double_write_mode(hevc) != 16) { + struct vdec_comp_buf_info info; + + get_comp_buf_info(hevc, &info); + vdec_v4l_set_comp_buf_info(ctx, &info); + } + + vh265_get_ps_info(hevc, &hevc->param, &ps); vdec_v4l_set_ps_infos(ctx, &ps); vdec_v4l_res_ch_event(ctx); hevc->v4l_params_parsed = false; - hevc->res_ch_flag = 1; ctx->v4l_resolution_change = 1; hevc->eos = 1; + + /* + * marks frame valid on the dpb is the ouput state, + * then via flush_output all frames can be flushed out. + */ + for (i = 0; i < MAX_REF_PIC_NUM; ++i) { + if ((hevc->m_PIC[i] == NULL) || + (hevc->m_PIC[i]->index == -1) || + (hevc->m_PIC[i]->BUF_index == -1)) + continue; + + if ((hevc->m_PIC[i]->POC != INVALID_POC) && + (hevc->m_PIC[i]->output_ready == 0) && + hevc->m_PIC[i]->referenced && + (hevc->m_PIC[i]->POC >= hevc->decoded_poc)) { + hevc->m_PIC[i]->output_mark = 1; + } + } + flush_output(hevc, NULL); //del_timer_sync(&hevc->timer); notify_v4l_eos(hw_to_vdec(hevc)); @@ -10366,55 +11254,6 @@ return 0; } -#ifdef VDEC_FCC_SUPPORT -static void fcc_discard_mode_process(struct vdec_s *vdec, struct hevc_state_s *hevc) -{ - if (vdec->fcc_status == AGAIN_STATUS && - hevc->param.p.slice_type == I_SLICE) { - vdec->stream_offset = READ_VREG(HEVC_SHIFT_BYTE_COUNT); - hevc_print(hevc, PRINT_FLAG_VDEC_DETAIL, - "[%d][FCC]: Notify stream_offset: %u\n", - vdec->id, vdec->stream_offset); - - vdec_wakeup_fcc_poll(vdec); - amhevc_stop(); - vdec->fcc_status = WAIT_MSG_STATUS; - hevc->dec_result = DEC_RESULT_AGAIN; - vdec_schedule_work(&hevc->work); - } else if (vdec->fcc_status == DISCARD_STATUS || - hevc->param.p.slice_type != I_SLICE) { - hevc_print(hevc, PRINT_FLAG_VDEC_DETAIL, - "[%d][FCC]: Discard current gop and to find next gop!\n", - vdec->id); - - amhevc_stop(); - vdec->fcc_status = AGAIN_STATUS; - hevc->dec_result = DEC_RESULT_DISCARD_DATA; - vdec_schedule_work(&hevc->work); - } -} - -static int vh265_fcc_process(struct vdec_s *vdec, struct hevc_state_s *hevc) -{ - if (input_stream_based(vdec)) { - switch (vdec->fcc_mode) { - case FCC_DISCARD_MODE: - fcc_discard_mode_process(vdec, hevc); - return 1; - case FCC_DEC_MODE: - hevc_print(hevc, PRINT_FLAG_VDEC_DETAIL, - "[%d][FCC]: Current is Dec mode.\n", vdec->id); - break; - case FCC_BUTT: - default: - break; - } - } - - return 0; -} -#endif - static void aspect_ratio_set(struct hevc_state_s *hevc) { int aspect_ratio_idc = hevc->param.p.aspect_ratio_idc; @@ -10517,6 +11356,13 @@ struct vdec_s *vdec = hw_to_vdec(hevc); + if (dec_status == HEVC_SLICE_SEGMENT_DONE) { + ATRACE_COUNTER(hevc->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_START); + } + else if (dec_status == HEVC_DECPIC_DATA_DONE) { + ATRACE_COUNTER(hevc->trace.decode_time_name, DECODER_ISR_THREAD_PIC_DONE_START); + } + if (hevc->eos) return IRQ_HANDLED; if ( @@ -10702,11 +11548,20 @@ #endif hevc->empty_flag = 0; pic_done: + if (vdec->master == NULL && vdec->slave == NULL && + hevc->empty_flag == 0) { + hevc->over_decode = + (READ_VREG(HEVC_SHIFT_STATUS) >> 15) & 0x1; + if (hevc->over_decode) + hevc_print(hevc, 0, + "!!!Over decode %d\n", __LINE__); + } if (input_frame_based(hw_to_vdec(hevc)) && frmbase_cont_bitlevel != 0 && (hevc->decode_size > READ_VREG(HEVC_SHIFT_BYTE_COUNT)) && (hevc->decode_size - (READ_VREG(HEVC_SHIFT_BYTE_COUNT)) > frmbase_cont_bitlevel)) { + check_pic_decoded_error(hevc, READ_VREG(HEVC_PARSER_LCU_START) & 0xffffff); /*handle the case: multi pictures in one packet*/ hevc_print(hevc, PRINT_FLAG_VDEC_STATUS, "%s has more data index= %d, size=0x%x shiftcnt=0x%x)\n", @@ -10762,27 +11617,12 @@ && ((hevc->double_write_mode & 0x10) == 0)) { if (!hevc->m_ins_flag) { hevc->used_4k_num = - READ_VREG(HEVC_SAO_MMU_STATUS) >> 16; - + READ_VREG(HEVC_SAO_MMU_STATUS) >> 16; if ((!is_skip_decoding(hevc, pic)) && (hevc->used_4k_num >= 0) && (hevc->cur_pic->scatter_alloc - == 1)) { - hevc_print(hevc, - H265_DEBUG_BUFMGR_MORE, - "%s pic index %d scatter_alloc %d page_start %ld\n", - "decoder_mmu_box_free_idx_tail", - hevc->cur_pic->index, - hevc->cur_pic->scatter_alloc, - hevc->used_4k_num); - decoder_mmu_box_free_idx_tail( - hevc->mmu_box, - hevc->cur_pic->index, - hevc->used_4k_num); - hevc->cur_pic->scatter_alloc - = 2; - } - hevc->used_4k_num = -1; + == 1)) + recycle_mmu_buf_tail(hevc, false); } } @@ -10796,7 +11636,7 @@ } } /*Detects the first frame whether has an over decode error*/ - if ((!vdec_dual(vdec)) && + if (vdec->master == NULL && vdec->slave == NULL && hevc->empty_flag == 0) { hevc->over_decode = (READ_VREG(HEVC_SHIFT_STATUS) >> 15) & 0x1; @@ -10848,7 +11688,7 @@ } } } - + ATRACE_COUNTER(hevc->trace.decode_time_name, DECODER_ISR_THREAD_EDN); vdec_schedule_work(&hevc->work); } @@ -10988,7 +11828,7 @@ } #endif /*Detects frame whether has an over decode error*/ - if ((!vdec_dual(vdec)) && + if (vdec->master == NULL && vdec->slave == NULL && hevc->empty_flag == 0 && input_stream_based(vdec)) { hevc->over_decode = (READ_VREG(HEVC_SHIFT_STATUS) >> 15) & 0x1; @@ -11196,7 +12036,7 @@ if (get_dbg_flag(hevc) & H265_DEBUG_SEND_PARAM_WITH_REG) get_rpm_param(&hevc->param); else { - + ATRACE_COUNTER(hevc->trace.decode_header_memory_time_name, TRACE_HEADER_RPM_START); for (i = 0; i < (RPM_END - RPM_BEGIN); i += 4) { int ii; @@ -11206,14 +12046,11 @@ - ii]; } } + ATRACE_COUNTER(hevc->trace.decode_header_memory_time_name, TRACE_HEADER_RPM_END); #ifdef SEND_LMEM_WITH_RPM check_head_error(hevc); #endif } -#ifdef VDEC_FCC_SUPPORT - if (vh265_fcc_process(vdec, hevc) > 0) - return IRQ_HANDLED; -#endif if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR_MORE) { hevc_print(hevc, 0, "rpm_param: (%d)\n", hevc->slice_idx); @@ -11241,9 +12078,22 @@ struct aml_vdec_ps_infos ps; int width = hevc->param.p.pic_width_in_luma_samples; int height = hevc->param.p.pic_height_in_luma_samples; + int log = hevc->param.p.log2_min_coding_block_size_minus3; + int log_s = hevc->param.p.log2_diff_max_min_coding_block_size; + + hevc->pic_w = width; + hevc->pic_h = height; + hevc->lcu_size = 1 << (log + 3 + log_s); pr_debug("set ucode parse\n"); - vh265_get_ps_info(hevc, width, height, &ps); + if (get_valid_double_write_mode(hevc) != 16) { + struct vdec_comp_buf_info info; + + get_comp_buf_info(hevc, &info); + vdec_v4l_set_comp_buf_info(ctx, &info); + } + + vh265_get_ps_info(hevc, &hevc->param, &ps); /*notice the v4l2 codec.*/ vdec_v4l_set_ps_infos(ctx, &ps); hevc->v4l_params_parsed = true; @@ -11262,7 +12112,6 @@ reset_process_time(hevc); vdec_schedule_work(&hevc->work); return IRQ_HANDLED; - } } @@ -11275,7 +12124,7 @@ ) { if (get_dbg_flag(hevc) & - H265_DEBUG_BUFMGR_MORE) + H265_DEBUG_PRINT_SEI) dump_aux_buf(hevc); } @@ -11401,15 +12250,16 @@ } else { hevc->sps_num_reorder_pics_0 = hevc->param.p.sps_num_reorder_pics_0; - hevc->ip_mode = (!hevc->sps_num_reorder_pics_0 && - !(vdec->slave || vdec->master) && - !disable_ip_mode && - hevc->low_latency_flag) ? true : false; + hevc->ip_mode = hevc->low_latency_flag ? true : + (!hevc->sps_num_reorder_pics_0 && + !(vdec->slave || vdec->master) && + !disable_ip_mode) ? true : false; hevc->pic_list_init_flag = 1; if ((!IS_4K_SIZE(hevc->pic_w, hevc->pic_h)) && ((hevc->param.p.profile_etc & 0xc) == 0x4) && (interlace_enable != 0)) { hevc->double_write_mode = 1; + hevc->mmu_enable = 1; hevc->interlace_flag = 1; hevc->frame_ar = (hevc->pic_h * 0x100 / hevc->pic_w) * 2; hevc_print(hevc, 0, @@ -11417,7 +12267,7 @@ hevc->pic_w, hevc->pic_h, hevc->param.p.profile_etc, hevc->frame_ar, get_double_write_mode(hevc)); /* When dw changed from 0x10 to 1, the mmu_box is NULL */ - if (!hevc->mmu_box && init_mmu_box(hevc) != 0) { + if (!hevc->mmu_box && init_mmu_buffers(hevc, 1) != 0) { hevc->dec_result = DEC_RESULT_FORCE_EXIT; hevc->fatal_error |= DECODER_FATAL_ERROR_NO_MEM; @@ -11426,6 +12276,17 @@ 0, "can not alloc mmu box, force exit\n"); return IRQ_HANDLED; } + if (hevc->frame_mmu_map_addr == NULL) { + hevc->frame_mmu_map_addr = + dma_alloc_coherent(amports_get_dma_device(), + get_frame_mmu_map_size(), + &hevc->frame_mmu_map_phy_addr, GFP_KERNEL); + if (hevc->frame_mmu_map_addr == NULL) { + pr_err("%s: failed to alloc count_buffer\n", __func__); + return IRQ_HANDLED; + } + memset(hevc->frame_mmu_map_addr, 0, get_frame_mmu_map_size()); + } } #ifdef MULTI_INSTANCE_SUPPORT if (hevc->m_ins_flag) { @@ -11435,6 +12296,7 @@ up(&h265_sema); hevc_print(hevc, 0, "set pic_list_init_flag 1\n"); } + ATRACE_COUNTER(hevc->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_END); return IRQ_HANDLED; } @@ -11463,7 +12325,6 @@ hevc_print(hevc, H265_DEBUG_OUT_PTS, "read stream_offset = 0x%x\n", hevc->cur_pic->stream_offset); - hevc->cur_pic->aspect_ratio_idc = hevc->param.p.aspect_ratio_idc; hevc->cur_pic->sar_width = @@ -11515,6 +12376,8 @@ WRITE_VREG(HEVC_MCPU_INTR_REQ, AMRISC_MAIN_REQ); } + ATRACE_COUNTER(hevc->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_END); + } else if (dec_status == HEVC_DECODE_OVER_SIZE) { hevc_print(hevc, 0 , "hevc decode oversize !!\n"); #ifdef MULTI_INSTANCE_SUPPORT @@ -11548,6 +12411,14 @@ u32 debug_tag; dec_status = READ_VREG(HEVC_DEC_STATUS_REG); + + if (dec_status == HEVC_SLICE_SEGMENT_DONE) { + ATRACE_COUNTER(hevc->trace.decode_time_name, DECODER_ISR_HEAD_DONE); + } + else if (dec_status == HEVC_DECPIC_DATA_DONE) { + ATRACE_COUNTER(hevc->trace.decode_time_name, DECODER_ISR_PIC_DONE); + } + if (hevc->init_flag == 0) return IRQ_HANDLED; hevc->dec_status = dec_status; @@ -11638,7 +12509,7 @@ return IRQ_HANDLED; } } - + ATRACE_COUNTER(hevc->trace.decode_time_name, DECODER_ISR_END); return IRQ_WAKE_THREAD; } @@ -11656,10 +12527,10 @@ hevc->frame_height * fps; } -static void vh265_check_timer_func(unsigned long arg) +static void vh265_check_timer_func(struct timer_list *timer) { - struct hevc_state_s *hevc = (struct hevc_state_s *)arg; - struct timer_list *timer = &hevc->timer; + struct hevc_state_s *hevc = container_of(timer, + struct hevc_state_s, timer); unsigned char empty_flag; unsigned int buf_level; @@ -11965,11 +12836,17 @@ 96000 / hevc->frame_dur : (96000 / hevc->frame_dur +1); else vstatus->frame_rate = -1; - + vstatus->error_count = hevc->gvs->error_frame_count; vstatus->status = hevc->stat | hevc->fatal_error; + if (!vdec_is_support_4k() && + (IS_4K_SIZE(vstatus->frame_width, vstatus->frame_height)) && + (vstatus->frame_width <= 4096 && vstatus->frame_height <= 2304)) { + vstatus->status |= DECODER_FATAL_ERROR_SIZE_OVERFLOW; + } + + vstatus->bit_rate = hevc->gvs->bit_rate; vstatus->frame_dur = hevc->frame_dur; if (hevc->gvs) { - vstatus->error_count = hevc->gvs->error_frame_count; vstatus->bit_rate = hevc->gvs->bit_rate; vstatus->frame_data = hevc->gvs->frame_data; vstatus->total_data = hevc->gvs->total_data; @@ -12036,28 +12913,28 @@ int vh265_set_trickmode(struct vdec_s *vdec, unsigned long trickmode) { - struct hevc_state_s *hevc = (struct hevc_state_s *)vdec->private; - hevc_print(hevc, 0, "[%s %d] trickmode:%lu\n", __func__, __LINE__, trickmode); + struct hevc_state_s *hevc = (struct hevc_state_s *)vdec->private; + hevc_print(hevc, 0, "[%s %d] trickmode:%lu\n", __func__, __LINE__, trickmode); - if (trickmode == TRICKMODE_I) { + if (trickmode == TRICKMODE_I) { trickmode_i = 1; i_only_flag = 0x1; - } else if (trickmode == TRICKMODE_NONE) { + } else if (trickmode == TRICKMODE_NONE) { trickmode_i = 0; i_only_flag = 0x0; - } else if (trickmode == 0x02) { + } else if (trickmode == 0x02) { trickmode_i = 0; i_only_flag = 0x02; - } else if (trickmode == 0x03) { + } else if (trickmode == 0x03) { trickmode_i = 1; i_only_flag = 0x03; - } else if (trickmode == 0x07) { + } else if (trickmode == 0x07) { trickmode_i = 1; i_only_flag = 0x07; - } - //hevc_print(hevc, 0, "i_only_flag: %d trickmode_i:%d\n", i_only_flag, trickmode_i); + } + //hevc_print(hevc, 0, "i_only_flag: %d trickmode_i:%d\n", i_only_flag, trickmode_i); - return 0; + return 0; } static void config_decode_mode(struct hevc_state_s *hevc) @@ -12149,7 +13026,6 @@ } else { /* check vps/sps/pps/i-slice in ucode */ unsigned ctl_val = 0x8; - if (hevc->PB_skip_mode == 0) ctl_val = 0x4; /* check vps/sps/pps only in ucode */ else if (hevc->PB_skip_mode == 3) @@ -12288,7 +13164,7 @@ int fw_size = 0x1000 * 16; struct firmware_s *fw = NULL; - init_timer(&hevc->timer); + timer_setup(&hevc->timer, vh265_check_timer_func, 0); hevc->stat |= STAT_TIMER_INIT; @@ -12307,11 +13183,11 @@ INIT_WORK(&hevc->notify_work, vh265_notify_work); INIT_WORK(&hevc->set_clk_work, vh265_set_clk); - fw = vmalloc(sizeof(struct firmware_s) + fw_size); + fw = vzalloc(sizeof(struct firmware_s) + fw_size); if (IS_ERR_OR_NULL(fw)) return -ENOMEM; - if (hevc->mmu_enable) + if (hevc->mmu_enable) { if (get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_GXM) size = get_firmware_data(VIDEO_DEC_HEVC_MMU, fw->data); else { @@ -12330,7 +13206,7 @@ size = get_firmware_data(VIDEO_DEC_HEVC_MMU, fw->data); } - else + } else size = get_firmware_data(VIDEO_DEC_HEVC, fw->data); if (size < 0) { @@ -12360,7 +13236,7 @@ hevc->swap_size); hevc_print(hevc, 0, - "vh265 mmu ucode swap loaded %llx\n", + "vh265 mmu ucode swap loaded %x\n", hevc->mc_dma_handle); } } @@ -12368,8 +13244,8 @@ #ifdef MULTI_INSTANCE_SUPPORT if (hevc->m_ins_flag) { - hevc->timer.data = (ulong) hevc; - hevc->timer.function = vh265_check_timer_func; + //hevc->timer.data = (ulong) hevc; + //hevc->timer.function = vh265_check_timer_func; hevc->timer.expires = jiffies + PUT_INTERVAL; hevc->fw = fw; @@ -12435,21 +13311,23 @@ hevc->provider_name = PROVIDER_NAME; #ifdef MULTI_INSTANCE_SUPPORT - vf_provider_init(&vh265_vf_prov, hevc->provider_name, - &vh265_vf_provider, vdec); - vf_reg_provider(&vh265_vf_prov); - vf_notify_receiver(hevc->provider_name, VFRAME_EVENT_PROVIDER_START, - NULL); - if (hevc->frame_dur != 0) { - if (!is_reset) { - vf_notify_receiver(hevc->provider_name, - VFRAME_EVENT_PROVIDER_FR_HINT, - (void *) - ((unsigned long)hevc->frame_dur)); - fr_hint_status = VDEC_HINTED; - } - } else - fr_hint_status = VDEC_NEED_HINT; + if (!hevc->is_used_v4l) { + vf_provider_init(&vh265_vf_prov, hevc->provider_name, + &vh265_vf_provider, vdec); + vf_reg_provider(&vh265_vf_prov); + vf_notify_receiver(hevc->provider_name, VFRAME_EVENT_PROVIDER_START, + NULL); + if (hevc->frame_dur != 0) { + if (!is_reset) { + vf_notify_receiver(hevc->provider_name, + VFRAME_EVENT_PROVIDER_FR_HINT, + (void *) + ((unsigned long)hevc->frame_dur)); + fr_hint_status = VDEC_HINTED; + } + } else + fr_hint_status = VDEC_NEED_HINT; + } #else vf_provider_init(&vh265_vf_prov, PROVIDER_NAME, &vh265_vf_provider, hevc); @@ -12466,8 +13344,8 @@ #endif hevc->stat |= STAT_VF_HOOK; - hevc->timer.data = (ulong) hevc; - hevc->timer.function = vh265_check_timer_func; + //hevc->timer.data = (ulong) hevc; + //hevc->timer.function = vh265_check_timer_func; hevc->timer.expires = jiffies + PUT_INTERVAL; add_timer(&hevc->timer); @@ -12781,6 +13659,38 @@ } #endif +static bool is_avaliable_buffer(struct hevc_state_s *hevc) +{ + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hevc->v4l2_ctx); + struct PIC_s *pic = NULL; + int i, free_count = 0; + + if (ctx->cap_pool.dec < hevc->used_buf_num) { + free_count = v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx); + if (free_count && + !ctx->fb_ops.query(&ctx->fb_ops, &hevc->fb_token)) { + return false; + } + } + + for (i = 0; i < hevc->used_buf_num; i++) { + pic = hevc->m_PIC[i]; + if (pic == NULL || + pic->index == -1 || + pic->BUF_index == -1) + continue; + + if (pic->output_mark == 0 && + pic->referenced == 0 && + pic->output_ready == 0 && + pic->cma_alloc_addr) { + free_count++; + } + } + + return free_count < run_ready_min_buf_num ? 0 : 1; +} static unsigned char is_new_pic_available(struct hevc_state_s *hevc) { @@ -12812,7 +13722,7 @@ new_pic = pic; } } - if (new_pic == NULL) { + if (!hevc->is_used_v4l && new_pic == NULL) { enum receviver_start_e state = RECEIVER_INACTIVE; if (vf_get_receiver(vdec->vf_provider_name)) { state = @@ -12832,7 +13742,7 @@ if ((pic->referenced == 0) && (pic->error_mark == 1) && (pic->output_mark == 1)) { - if (pic->POC < poc) { + if (poc == INVALID_POC || (pic->POC < poc)) { new_pic = pic; poc = pic->POC; } @@ -12875,7 +13785,7 @@ if (!(error_handle_policy & 0x400)) { spin_unlock_irqrestore(&lock, flags); flush_output(hevc, NULL); - hevc_print(hevc, H265_DEBUG_BUFMGR_MORE, "flush dpb, ref_error_count %d, sps_max_dec_pic_buffering_minus1_0 %d\n", + hevc_print(hevc, H265_DEBUG_BUFMGR, "flush dpb, ref_error_count %d, sps_max_dec_pic_buffering_minus1_0 %d\n", decode_count, hevc->param.p.sps_max_dec_pic_buffering_minus1_0); return 0; } @@ -12893,6 +13803,10 @@ struct vdec_s *vdec = hw_to_vdec(hevc); enum receviver_start_e state = RECEIVER_INACTIVE; + + if (hevc->is_used_v4l) + return; + if (vf_get_receiver(vdec->vf_provider_name)) { state = vf_notify_receiver(vdec->vf_provider_name, @@ -12920,7 +13834,7 @@ if ((pic->referenced == 0) && (pic->error_mark == 1) && (pic->output_mark == 1)) { - if (pic->POC < poc) { + if (poc == INVALID_POC || (pic->POC < poc)) { new_pic = pic; poc = pic->POC; } @@ -12962,7 +13876,7 @@ hevc->stat &= ~STAT_ISR_REG; } - if (hevc->stat & STAT_VF_HOOK) { + if (!hevc->is_used_v4l && hevc->stat & STAT_VF_HOOK) { if (fr_hint_status == VDEC_HINTED) vf_notify_receiver(hevc->provider_name, VFRAME_EVENT_PROVIDER_FR_END_HINT, @@ -13025,6 +13939,14 @@ for (jj = 0; jj < size; jj++) sum += data[jj]; + hevc_print(hevc, PRINT_FLAG_VDEC_STATUS, + "%s: size 0x%x sum 0x%x %02x %02x %02x %02x %02x %02x .. %02x %02x %02x %02x\n", + __func__, size, sum, + data[0], data[1], data[2], data[3], + data[4], data[5], data[size - 4], + data[size - 3], data[size - 2], + data[size - 1]); + if (!hevc->chunk->block->is_mapped) codec_mm_unmap_phyaddr(data); return sum; @@ -13037,6 +13959,10 @@ struct hevc_state_s, notify_work); struct vdec_s *vdec = hw_to_vdec(hevc); + + if (hevc->is_used_v4l) + return; + #ifdef MULTI_INSTANCE_SUPPORT if (vdec->fr_hint_state == VDEC_NEED_HINT) { vf_notify_receiver(hevc->provider_name, @@ -13067,6 +13993,11 @@ static void vh265_work_implement(struct hevc_state_s *hevc, struct vdec_s *vdec,int from) { + if (hevc->dec_result == DEC_RESULT_DONE) { + ATRACE_COUNTER(hevc->trace.decode_time_name, DECODER_WORKER_START); + } else if (hevc->dec_result == DEC_RESULT_AGAIN) + ATRACE_COUNTER(hevc->trace.decode_time_name, DECODER_WORKER_AGAIN); + if (hevc->dec_result == DEC_RESULT_FREE_CANVAS) { /*USE_BUF_BLOCK*/ uninit_pic_list(hevc); @@ -13248,34 +14179,20 @@ } } #endif - if (hevc->mmu_enable && ((hevc->double_write_mode & 0x10) == 0)) { hevc->used_4k_num = READ_VREG(HEVC_SAO_MMU_STATUS) >> 16; if (hevc->used_4k_num >= 0 && hevc->cur_pic && hevc->cur_pic->scatter_alloc - == 1) { - hevc_print(hevc, H265_DEBUG_BUFMGR_MORE, - "%s pic index %d scatter_alloc %d page_start %ld\n", - "decoder_mmu_box_free_idx_tail", - hevc->cur_pic->index, - hevc->cur_pic->scatter_alloc, - hevc->used_4k_num); - if (hevc->m_ins_flag) - hevc_mmu_dma_check(hw_to_vdec(hevc)); - decoder_mmu_box_free_idx_tail( - hevc->mmu_box, - hevc->cur_pic->index, - hevc->used_4k_num); - hevc->cur_pic->scatter_alloc = 2; - } + == 1) + recycle_mmu_buf_tail(hevc, hevc->m_ins_flag); } hevc->pic_decoded_lcu_idx = READ_VREG(HEVC_PARSER_LCU_START) & 0xffffff; - if ((!vdec_dual(vdec)) && + if (vdec->master == NULL && vdec->slave == NULL && hevc->empty_flag == 0) { hevc->over_decode = (READ_VREG(HEVC_SHIFT_STATUS) >> 15) & 0x1; @@ -13286,7 +14203,7 @@ if (is_log_enable(hevc)) add_log(hevc, - "%s dec_result %d lcu %d used_mmu %ld shiftbyte 0x%x decbytes 0x%x", + "%s dec_result %d lcu %d used_mmu %d shiftbyte 0x%x decbytes 0x%x", __func__, hevc->dec_result, hevc->pic_decoded_lcu_idx, @@ -13297,7 +14214,7 @@ ); hevc_print(hevc, PRINT_FLAG_VDEC_STATUS, - "%s dec_result %d (%x %x %x) lcu %d used_mmu %ld shiftbyte 0x%x decbytes 0x%x\n", + "%s dec_result %d (%x %x %x) lcu %d used_mmu %d shiftbyte 0x%x decbytes 0x%x\n", __func__, hevc->dec_result, READ_VREG(HEVC_STREAM_LEVEL), @@ -13399,7 +14316,6 @@ stream base: stream buf empty or timeout frame base: vdec_prepare_input fail */ - if (!vdec_has_more_input(vdec)) { hevc->dec_result = DEC_RESULT_EOS; vdec_schedule_work(&hevc->work); @@ -13475,11 +14391,6 @@ } hevc_print(hevc, 0, "%s: force exit end\n", __func__); - } else if (hevc->dec_result == DEC_RESULT_DISCARD_DATA) { - mutex_lock(&hevc->chunks_mutex); - vdec_vframe_dirty(hw_to_vdec(hevc), hevc->chunk); - hevc->chunk = NULL; - mutex_unlock(&hevc->chunks_mutex); } if (hevc->stat & STAT_VDEC_RUN) { @@ -13491,8 +14402,10 @@ del_timer_sync(&hevc->timer); hevc->stat &= ~STAT_TIMER_ARM; } - + ATRACE_COUNTER(hevc->trace.decode_work_time_name, TRACE_WORK_WAIT_SEARCH_DONE_START); wait_hevc_search_done(hevc); + ATRACE_COUNTER(hevc->trace.decode_work_time_name, TRACE_WORK_WAIT_SEARCH_DONE_END); + #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION if (hevc->switch_dvlayer_flag) { if (vdec->slave) @@ -13514,6 +14427,9 @@ //cancel_work_sync(&hevc->work);//reserved for future considraion } } + if (hevc->dec_result == DEC_RESULT_DONE) { + ATRACE_COUNTER(hevc->trace.decode_time_name, DECODER_WORKER_END); + } /* mark itself has all HW resource released and input released */ if (vdec->parallel_dec == 1) @@ -13555,12 +14471,6 @@ vh265_work_implement(hevc, vdec, 1); } -#ifdef VDEC_FCC_SUPPORT -static void vh265_wakeup_fcc_poll(struct vdec_s *vdec) -{ - amstream_wakeup_fcc_poll(vdec); -} -#endif static int vh265_hw_ctx_restore(struct hevc_state_s *hevc) { @@ -13575,9 +14485,6 @@ int tvp = vdec_secure(hw_to_vdec(hevc)) ? CODEC_MM_FLAGS_TVP : 0; bool ret = 0; -#ifdef VDEC_FCC_SUPPORT - int get_msg = 1; -#endif if (step == 0x12) return 0; else if (step == 0x11) @@ -13599,7 +14506,17 @@ } hevc->timeout_processing = 0; if (!hevc->first_sc_checked && hevc->mmu_enable) { - int size = decoder_mmu_box_sc_check(hevc->mmu_box, tvp); + int size; + void * mmu_box; + + if (hevc->is_used_v4l) { + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hevc->v4l2_ctx); + mmu_box = ctx->mmu_box; + } else + mmu_box = hevc->mmu_box; + + size = decoder_mmu_box_sc_check(mmu_box, tvp); hevc->first_sc_checked =1; hevc_print(hevc, 0, "vh265 cached=%d need_size=%d speed= %d ms\n", @@ -13655,7 +14572,7 @@ } #ifdef CONSTRAIN_MAX_BUF_NUM - if (hevc->pic_list_init_flag == 3) { + if (hevc->pic_list_init_flag == 3 && !hevc->is_used_v4l) { if (run_ready_max_vf_only_num > 0 && get_vf_ref_only_buf_count(hevc) >= run_ready_max_vf_only_num @@ -13687,10 +14604,12 @@ if (ctx->param_sets_from_ucode) { if (hevc->v4l_params_parsed) { - if (!ctx->v4l_codec_dpb_ready && - v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < - run_ready_min_buf_num) - ret = 0; + if (ctx->cap_pool.dec < hevc->used_buf_num) { + if (is_avaliable_buffer(hevc)) + ret = 1; + else + ret = 0; + } } else { if (ctx->v4l_resolution_change) ret = 0; @@ -13702,10 +14621,6 @@ } } -#ifdef VDEC_FCC_SUPPORT - get_msg = vdec_has_get_fcc_new_msg(vdec); - ret &= get_msg; -#endif if (ret) not_run_ready[hevc->index] = 0; else @@ -13728,6 +14643,8 @@ hevc->vdec_cb_arg = arg; hevc->vdec_cb = callback; hevc->aux_data_dirty = 1; + + ATRACE_COUNTER(hevc->trace.decode_time_name, DECODER_RUN_START); hevc_reset_core(vdec); #ifdef AGAIN_HAS_THRESHOLD @@ -13805,6 +14722,7 @@ if (!hevc->chunk->block->is_mapped) codec_mm_unmap_phyaddr(data); } + ATRACE_COUNTER(hevc->trace.decode_run_time_name, TRACE_RUN_LOADING_FW_START); if (vdec->mc_loaded) { /*firmware have load before, and not changes to another. @@ -13814,7 +14732,7 @@ get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_GXM) WRITE_VREG(HEVC_STREAM_SWAP_BUFFER2, hevc->swap_addr); } else { - if (hevc->mmu_enable) + if (hevc->mmu_enable) { if (get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_GXM) loadr = amhevc_vdec_loadmc_ex(VFORMAT_HEVC, vdec, "h265_mmu", hevc->fw->data); @@ -13839,9 +14757,10 @@ VFORMAT_HEVC, vdec, "h265_mmu", hevc->fw->data); } - else + } else loadr = amhevc_vdec_loadmc_ex(VFORMAT_HEVC, vdec, NULL, hevc->fw->data); + if (loadr < 0) { amhevc_disable(); hevc_print(hevc, 0, "H265: the %s fw loading failed, err: %x\n", @@ -13862,10 +14781,14 @@ vdec->mc_loaded = 1; vdec->mc_type = VFORMAT_HEVC; } + ATRACE_COUNTER(hevc->trace.decode_run_time_name, TRACE_RUN_LOADING_FW_END); + + ATRACE_COUNTER(hevc->trace.decode_run_time_name, TRACE_RUN_LOADING_RESTORE_START); if (vh265_hw_ctx_restore(hevc) < 0) { vdec_schedule_work(&hevc->work); return; } + ATRACE_COUNTER(hevc->trace.decode_run_time_name, TRACE_RUN_LOADING_RESTORE_END); vdec_enable_input(vdec); WRITE_VREG(HEVC_DEC_STATUS_REG, HEVC_ACTION_DONE); @@ -13894,6 +14817,7 @@ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR_MORE) dump_pic_list(hevc); backup_decode_state(hevc); + start_process_time(hevc); mod_timer(&hevc->timer, jiffies); hevc->stat |= STAT_TIMER_ARM; @@ -13902,6 +14826,8 @@ vdec->mvfrm->hw_decode_start = local_clock(); amhevc_start(); hevc->stat |= STAT_VDEC_RUN; + + ATRACE_COUNTER(hevc->trace.decode_time_name, DECODER_RUN_END); } static void aml_free_canvas(struct vdec_s *vdec) @@ -13919,6 +14845,7 @@ vdec->free_canvas_ex(pic->uv_canvas_index, vdec->id); } } + hevc->buffer_wrap[i] = i; } } @@ -14026,7 +14953,15 @@ else hevc->mmu_enable = 1; } - if (init_mmu_buffers(hevc)) { +#ifdef H265_10B_MMU_DW + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T5D) { + hevc->dw_mmu_enable = + get_double_write_mode(hevc) & 0x20 ? 1 : 0; + } else { + hevc->dw_mmu_enable = 0; + } +#endif + if (init_mmu_buffers(hevc, 0)) { hevc_print(hevc, 0, "\n 265 mmu init failed!\n"); vfree(hevc); @@ -14080,6 +15015,13 @@ hevc->vh265_amstream_dec_info.height = 0; hevc->vh265_amstream_dec_info.rate = 30; } + + hevc->endian = HEVC_CONFIG_LITTLE_ENDIAN; + if (is_support_vdec_canvas()) + hevc->endian = HEVC_CONFIG_BIG_ENDIAN; + if (endian) + hevc->endian = endian; + #ifndef MULTI_INSTANCE_SUPPORT if (pdata->flag & DEC_FLAG_HEVC_WORKAROUND) { workaround_enable |= 3; @@ -14212,7 +15154,7 @@ input_empty[hevc->index] ); - if (vf_get_receiver(vdec->vf_provider_name)) { + if (hevc->is_used_v4l && vf_get_receiver(vdec->vf_provider_name)) { enum receviver_start_e state = vf_notify_receiver(vdec->vf_provider_name, VFRAME_EVENT_PROVIDER_QUREY_STATE, @@ -14241,16 +15183,17 @@ for (i = 0; i < BUF_POOL_SIZE; i++) { hevc_print(hevc, 0, - "Buf(%d) start_adr 0x%lx size 0x%x used %d\n", + "Buf(%d) start_adr 0x%x header_addr 0x%x size 0x%x used %d\n", i, hevc->m_BUF[i].start_adr, + hevc->m_BUF[i].header_addr, hevc->m_BUF[i].size, hevc->m_BUF[i].used_flag); } for (i = 0; i < MAX_REF_PIC_NUM; i++) { hevc_print(hevc, 0, - "mv_Buf(%d) start_adr 0x%lx size 0x%x used %d\n", + "mv_Buf(%d) start_adr 0x%x size 0x%x used %d\n", i, hevc->m_mv_BUF[i].start_adr, hevc->m_mv_BUF[i].size, @@ -14347,17 +15290,17 @@ struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data; struct hevc_state_s *hevc = NULL; int ret; + int i; #ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC int config_val; #endif - //pr_err("[%s pid=%d tgid=%d] \n",__func__, current->pid, current->tgid); + if (pdata == NULL) { pr_info("\nammvdec_h265 memory resource undefined.\n"); return -EFAULT; } - /* hevc = (struct hevc_state_s *)devm_kzalloc(&pdev->dev, - sizeof(struct hevc_state_s), GFP_KERNEL); */ + hevc = vmalloc(sizeof(struct hevc_state_s)); if (hevc == NULL) { pr_info("\nammvdec_h265 device data allocation failed\n"); @@ -14377,30 +15320,48 @@ pdata->irq_handler = vh265_irq_cb; pdata->threaded_irq_handler = vh265_threaded_irq_cb; pdata->dump_state = vh265_dump_state; -#ifdef VDEC_FCC_SUPPORT - pdata->wakeup_fcc_poll = vh265_wakeup_fcc_poll; -#endif + hevc->index = pdev->id; hevc->m_ins_flag = 1; - snprintf(hevc->vdec_name, sizeof(hevc->vdec_name), + if (is_rdma_enable()) { + hevc->rdma_adr = dma_alloc_coherent(amports_get_dma_device(), RDMA_SIZE, &hevc->rdma_phy_adr, GFP_KERNEL); + for (i = 0; i < SCALELUT_DATA_WRITE_NUM; i++) { + hevc->rdma_adr[i * 4] = HEVC_IQIT_SCALELUT_WR_ADDR & 0xfff; + hevc->rdma_adr[i * 4 + 1] = i; + hevc->rdma_adr[i * 4 + 2] = HEVC_IQIT_SCALELUT_DATA & 0xfff; + hevc->rdma_adr[i * 4 + 3] = 0; + if (i == SCALELUT_DATA_WRITE_NUM - 1) { + hevc->rdma_adr[i * 4 + 2] = (HEVC_IQIT_SCALELUT_DATA & 0xfff) | 0x20000; + } + } + } + snprintf(hevc->trace.vdec_name, sizeof(hevc->trace.vdec_name), "h265-%d", hevc->index); - snprintf(hevc->pts_name, sizeof(hevc->pts_name), - "%s-pts", hevc->vdec_name); - snprintf(hevc->vf_get_name, sizeof(hevc->vf_get_name), - "%s-vf_get", hevc->vdec_name); - snprintf(hevc->vf_put_name, sizeof(hevc->vf_put_name), - "%s-vf_put", hevc->vdec_name); - snprintf(hevc->set_canvas0_addr, sizeof(hevc->set_canvas0_addr), - "%s-set_canvas0_addr", hevc->vdec_name); - snprintf(hevc->get_canvas0_addr, sizeof(hevc->get_canvas0_addr), - "%s-get_canvas0_addr", hevc->vdec_name); - snprintf(hevc->put_canvas0_addr, sizeof(hevc->put_canvas0_addr), - "%s-put_canvas0_addr", hevc->vdec_name); - snprintf(hevc->new_q_name, sizeof(hevc->new_q_name), - "%s-newframe_q", hevc->vdec_name); - snprintf(hevc->disp_q_name, sizeof(hevc->disp_q_name), - "%s-dispframe_q", hevc->vdec_name); + snprintf(hevc->trace.pts_name, sizeof(hevc->trace.pts_name), + "%s-pts", hevc->trace.vdec_name); + snprintf(hevc->trace.vf_get_name, sizeof(hevc->trace.vf_get_name), + "%s-vf_get", hevc->trace.vdec_name); + snprintf(hevc->trace.vf_put_name, sizeof(hevc->trace.vf_put_name), + "%s-vf_put", hevc->trace.vdec_name); + snprintf(hevc->trace.set_canvas0_addr, sizeof(hevc->trace.set_canvas0_addr), + "%s-set_canvas0_addr", hevc->trace.vdec_name); + snprintf(hevc->trace.get_canvas0_addr, sizeof(hevc->trace.get_canvas0_addr), + "%s-get_canvas0_addr", hevc->trace.vdec_name); + snprintf(hevc->trace.put_canvas0_addr, sizeof(hevc->trace.put_canvas0_addr), + "%s-put_canvas0_addr", hevc->trace.vdec_name); + snprintf(hevc->trace.new_q_name, sizeof(hevc->trace.new_q_name), + "%s-newframe_q", hevc->trace.vdec_name); + snprintf(hevc->trace.disp_q_name, sizeof(hevc->trace.disp_q_name), + "%s-dispframe_q", hevc->trace.vdec_name); + snprintf(hevc->trace.decode_time_name, sizeof(hevc->trace.decode_time_name), + "decoder_time%d", pdev->id); + snprintf(hevc->trace.decode_run_time_name, sizeof(hevc->trace.decode_run_time_name), + "decoder_run_time%d", pdev->id); + snprintf(hevc->trace.decode_header_memory_time_name, sizeof(hevc->trace.decode_header_memory_time_name), + "decoder_header_time%d", pdev->id); + snprintf(hevc->trace.decode_work_time_name, sizeof(hevc->trace.decode_work_time_name), + "decoder_work_time%d", pdev->id); if (pdata->use_vfm_path) { snprintf(pdata->vf_provider_name, @@ -14412,16 +15373,30 @@ else if (vdec_dual(pdata)) { struct hevc_state_s *hevc_pair = NULL; - if (dv_toggle_prov_name) /*debug purpose*/ - snprintf(pdata->vf_provider_name, - VDEC_PROVIDER_NAME_SIZE, - (pdata->master) ? VFM_DEC_DVBL_PROVIDER_NAME : - VFM_DEC_DVEL_PROVIDER_NAME); - else - snprintf(pdata->vf_provider_name, - VDEC_PROVIDER_NAME_SIZE, - (pdata->master) ? VFM_DEC_DVEL_PROVIDER_NAME : - VFM_DEC_DVBL_PROVIDER_NAME); + if (!pdata->is_stream_mode_dv_multi) { + if (dv_toggle_prov_name) /*debug purpose*/ + snprintf(pdata->vf_provider_name, + VDEC_PROVIDER_NAME_SIZE, + (pdata->master) ? VFM_DEC_DVBL_PROVIDER_NAME : + VFM_DEC_DVEL_PROVIDER_NAME); + else + snprintf(pdata->vf_provider_name, + VDEC_PROVIDER_NAME_SIZE, + (pdata->master) ? VFM_DEC_DVEL_PROVIDER_NAME : + VFM_DEC_DVBL_PROVIDER_NAME); + } else { + if (dv_toggle_prov_name) /*debug purpose*/ + snprintf(pdata->vf_provider_name, + VDEC_PROVIDER_NAME_SIZE, + (pdata->master) ? VFM_DEC_DVBL_PROVIDER_NAME2 : + VFM_DEC_DVEL_PROVIDER_NAME2); + else + snprintf(pdata->vf_provider_name, + VDEC_PROVIDER_NAME_SIZE, + (pdata->master) ? VFM_DEC_DVEL_PROVIDER_NAME2 : + VFM_DEC_DVBL_PROVIDER_NAME2); + } + hevc->dolby_enhance_flag = pdata->master ? 1 : 0; if (pdata->master) hevc_pair = (struct hevc_state_s *) @@ -14438,16 +15413,13 @@ snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE, MULTI_INSTANCE_PROVIDER_NAME ".%02x", pdev->id & 0xff); - vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name, - &vh265_vf_provider, pdata); - hevc->provider_name = pdata->vf_provider_name; platform_set_drvdata(pdev, pdata); hevc->platform_dev = pdev; if (((get_dbg_flag(hevc) & IGNORE_PARAM_FROM_CONFIG) == 0) && - pdata->config && pdata->config_len) { + pdata->config_len) { #ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC /*use ptr config for doubel_write_mode, etc*/ hevc_print(hevc, 0, "pdata->config=%s\n", pdata->config); @@ -14496,18 +15468,18 @@ &config_val) == 0) hevc->mem_map_mode = config_val; - if (get_config_int(pdata->config, "dv_duallayer", - &config_val) == 0) - hevc->dv_duallayer = config_val; - else - hevc->dv_duallayer = false; - if (get_config_int(pdata->config, "negative_dv", &config_val) == 0) { hevc->discard_dv_data = config_val; hevc_print(hevc, 0, "discard dv data\n"); } + if (get_config_int(pdata->config, "dv_duallayer", + &config_val) == 0) { + hevc->dv_duallayer = config_val; + hevc_print(hevc, 0, "dv dual layer\n"); + } + if (get_config_int(pdata->config, "parm_enable_fence", &config_val) == 0) @@ -14523,6 +15495,17 @@ &config_val) == 0) hevc->low_latency_flag = config_val; + if (get_config_int(pdata->config, + "parm_v4l_metadata_config_flag", + &config_val) == 0) { + hevc->metadata_config_flag = config_val; + hevc->discard_dv_data = hevc->metadata_config_flag & VDEC_CFG_FLAG_DV_NEGATIVE; + hevc->dv_duallayer = hevc->metadata_config_flag & VDEC_CFG_FLAG_DV_TWOLARYER; + if (hevc->discard_dv_data) + hevc_print(hevc, 0, "discard dv data\n"); + if (hevc->dv_duallayer) + hevc_print(hevc, 0, "dv_duallayer\n"); + } #endif } else { if (pdata->sys_info) @@ -14534,8 +15517,10 @@ } hevc->double_write_mode = double_write_mode; } - /* get valid double write from configure or node */ - //hevc->double_write_mode = get_double_write_mode(hevc); + + + vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name, + &vh265_vf_provider, pdata); if (force_config_fence) { hevc->enable_fence = true; @@ -14547,31 +15532,45 @@ hevc->enable_fence, hevc->fence_usage); } - if (hevc->enable_fence) - pdata->sync.usage = hevc->fence_usage; + if (hevc->save_buffer_mode && dynamic_buf_num_margin > 2) + hevc->dynamic_buf_num_margin = dynamic_buf_num_margin -2; + else + hevc->dynamic_buf_num_margin = dynamic_buf_num_margin; + + hevc->mem_map_mode = mem_map_mode; + + hevc->endian = HEVC_CONFIG_LITTLE_ENDIAN; + if (is_support_vdec_canvas()) + hevc->endian = HEVC_CONFIG_BIG_ENDIAN; + if (endian) + hevc->endian = endian; if ((get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5) && (hevc->double_write_mode == 3)) hevc->double_write_mode = 0x1000; - if (!hevc->is_used_v4l) { - /* get valid double write from configure or node */ - //hevc->double_write_mode = get_double_write_mode(hevc); - if (hevc->save_buffer_mode && dynamic_buf_num_margin > 2) - hevc->dynamic_buf_num_margin = dynamic_buf_num_margin -2; - else - hevc->dynamic_buf_num_margin = dynamic_buf_num_margin; - hevc->mem_map_mode = mem_map_mode; - } + /* get valid double write from node */ + if (double_write_mode) + hevc->double_write_mode = get_double_write_mode(hevc); - if (mmu_enable_force == 0) { - if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_GXL) + if (mmu_enable_force) { + hevc->mmu_enable = 1; + } else { + if ((get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_GXL) || + (hevc->double_write_mode & 0x10)) hevc->mmu_enable = 0; else hevc->mmu_enable = 1; } - - if (init_mmu_buffers(hevc) < 0) { +#ifdef H265_10B_MMU_DW + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T5D) { + hevc->dw_mmu_enable = + get_double_write_mode(hevc) & 0x20 ? 1 : 0; + } else { + hevc->dw_mmu_enable = 0; + } +#endif + if (init_mmu_buffers(hevc, 0) < 0) { hevc_print(hevc, 0, "\n 265 mmu init failed!\n"); mutex_unlock(&vh265_mutex); @@ -14660,9 +15659,25 @@ vdec_core_request(pdata, CORE_MASK_VDEC_1 | CORE_MASK_HEVC | CORE_MASK_COMBINE); + mutex_init(&hevc->fence_mutex); if (hevc->enable_fence) { + pdata->sync = vdec_sync_get(); + if (!pdata->sync) { + hevc_print(hevc, 0, "alloc fence timeline error\n"); + hevc_local_uninit(hevc); + if (hevc->gvs) + kfree(hevc->gvs); + hevc->gvs = NULL; + uninit_mmu_buffers(hevc); + /* devm_kfree(&pdev->dev, (void *)hevc); */ + if (hevc) + vfree((void *)hevc); + pdata->dec_status = NULL; + return -ENODEV; + } + pdata->sync->usage = hevc->fence_usage; /* creat timeline. */ - vdec_timeline_create(&pdata->sync, DRIVER_NAME); + vdec_timeline_create(pdata->sync, DRIVER_NAME); } return 0; @@ -14672,7 +15687,6 @@ struct vdec_sync *sync) { ulong expires; - int i; /* notify signal to wake up all fences. */ vdec_timeline_increase(sync, VF_POOL_SIZE); @@ -14685,15 +15699,6 @@ } } - for (i = 0; i < VF_POOL_SIZE; i++) { - struct vframe_s *vf = &hw->vfpool[i]; - - if (vf->fence) { - vdec_fence_put(vf->fence); - vf->fence = NULL; - } - } - /* decreases refcnt of timeline. */ vdec_timeline_put(sync); } @@ -14728,8 +15733,9 @@ vdec_set_status(hw_to_vdec(hevc), VDEC_STATUS_DISCONNECTED); if (hevc->enable_fence) - vdec_fence_release(hevc, &vdec->sync); - + vdec_fence_release(hevc, vdec->sync); + if (is_rdma_enable()) + dma_free_coherent(amports_get_dma_device(), RDMA_SIZE, hevc->rdma_adr, hevc->rdma_phy_adr); vfree((void *)hevc); return 0; @@ -14816,13 +15822,20 @@ { struct BuffInfo_s *p_buf_info; - if (vdec_is_support_4k()) { - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) - p_buf_info = &amvh265_workbuff_spec[2]; + if (get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_TM2 && !is_cpu_tm2_revb()) { + if (vdec_is_support_4k()) { + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) + p_buf_info = &amvh265_workbuff_spec[2]; + else + p_buf_info = &amvh265_workbuff_spec[1]; + } else + p_buf_info = &amvh265_workbuff_spec[0]; + } else { //get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_TM2 || is_cpu_tm2_revb() + if (vdec_is_support_4k()) + p_buf_info = &amvh265_workbuff_spec[5]; else - p_buf_info = &amvh265_workbuff_spec[1]; - } else - p_buf_info = &amvh265_workbuff_spec[0]; + p_buf_info = &amvh265_workbuff_spec[3]; + } init_buff_spec(NULL, p_buf_info); work_buf_size = @@ -14862,19 +15875,26 @@ amvdec_h265_profile.profile = "4k"; } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) { amvdec_h265_profile.profile = - "8k, 8bit, 10bit, dwrite, compressed, frame_dv, fence"; + "8k, 8bit, 10bit, dwrite, compressed, frame_dv, fence, v4l-uvm"; }else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXBB) { amvdec_h265_profile.profile = - "4k, 8bit, 10bit, dwrite, compressed, frame_dv, fence"; + "4k, 8bit, 10bit, dwrite, compressed, frame_dv, fence, v4l-uvm"; } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_MG9TV) amvdec_h265_profile.profile = "4k"; + } else { + if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5D || is_cpu_s4_s805x2()) { + amvdec_h265_profile.profile = + "8bit, 10bit, dwrite, compressed, frame_dv, v4l"; + } else { + amvdec_h265_profile.profile = + "8bit, 10bit, dwrite, compressed, v4l"; + } } #endif if (codec_mm_get_total_size() < 80 * SZ_1M) { pr_info("amvdec_h265 default mmu enabled.\n"); mmu_enable = 1; } - vcodec_profile_register(&amvdec_h265_profile); amvdec_h265_profile_single = amvdec_h265_profile; amvdec_h265_profile_single.name = "h265"; @@ -14884,6 +15904,7 @@ vcodec_profile_register(&amvdec_h265_profile_mult); INIT_REG_NODE_CONFIGS("media.decoder", &decoder_265_node, "h265", h265_configs, CONFIG_FOR_RW); + vcodec_feature_register(VFORMAT_HEVC, 0); return 0; }
diff --git a/drivers/frame_provider/decoder/mjpeg/vmjpeg.c b/drivers/frame_provider/decoder/mjpeg/vmjpeg.c index 6b87d4a..917a2a1 100644 --- a/drivers/frame_provider/decoder/mjpeg/vmjpeg.c +++ b/drivers/frame_provider/decoder/mjpeg/vmjpeg.c
@@ -28,7 +28,6 @@ #include <linux/amlogic/media/vfm/vframe.h> #include <linux/amlogic/media/vfm/vframe_provider.h> #include <linux/amlogic/media/vfm/vframe_receiver.h> - #include <linux/amlogic/media/utils/vdec_reg.h> #include "../../../stream_input/amports/amports_priv.h" #include <linux/amlogic/media/registers/register.h> @@ -36,9 +35,6 @@ #include "../utils/decoder_bmmu_box.h" #include <linux/amlogic/media/codec_mm/codec_mm.h> #include <linux/amlogic/media/codec_mm/configs.h> -#include <linux/amlogic/tee.h> - - #ifdef CONFIG_AM_VDEC_MJPEG_LOG #define AMLOG @@ -397,10 +393,8 @@ } } -static void vmjpeg_put_timer_func(unsigned long arg) +static void vmjpeg_put_timer_func(struct timer_list *timer) { - struct timer_list *timer = (struct timer_list *)arg; - while (!kfifo_is_empty(&recycle_q) && (READ_VREG(MREG_TO_AMRISC) == 0)) { struct vframe_s *vf; @@ -489,61 +483,61 @@ if (ret < 0) return ret; #ifdef NV21 - canvas_config(index2canvas0(i) & 0xff, + config_cav_lut_ex(index2canvas0(i) & 0xff, buf_start, canvas_width, canvas_height, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_LINEAR); - canvas_config((index2canvas0(i) >> 8) & 0xff, + CANVAS_BLKMODE_LINEAR, 0, VDEC_1); + config_cav_lut_ex((index2canvas0(i) >> 8) & 0xff, buf_start + decbuf_y_size, canvas_width, canvas_height / 2, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_LINEAR); - canvas_config(index2canvas1(i) & 0xff, + CANVAS_BLKMODE_LINEAR, 0, VDEC_1); + config_cav_lut_ex(index2canvas1(i) & 0xff, buf_start + decbuf_size / 2, canvas_width, canvas_height, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_LINEAR); - canvas_config((index2canvas1(i) >> 8) & 0xff, + CANVAS_BLKMODE_LINEAR, 0, VDEC_1); + config_cav_lut_ex((index2canvas1(i) >> 8) & 0xff, buf_start + decbuf_y_size + decbuf_uv_size / 2, canvas_width, canvas_height / 2, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_LINEAR); + CANVAS_BLKMODE_LINEAR, 0, VDEC_1); #else - canvas_config(index2canvas0(i) & 0xff, + config_cav_lut_ex(index2canvas0(i) & 0xff, buf_start, canvas_width, canvas_height, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_LINEAR); - canvas_config((index2canvas0(i) >> 8) & 0xff, + CANVAS_BLKMODE_LINEAR, 0, VDEC_1); + config_cav_lut_ex((index2canvas0(i) >> 8) & 0xff, buf_start + decbuf_y_size, canvas_width / 2, canvas_height / 2, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_LINEAR); - canvas_config((index2canvas0(i) >> 16) & 0xff, + CANVAS_BLKMODE_LINEAR, 0, VDEC_1); + config_cav_lut_ex((index2canvas0(i) >> 16) & 0xff, buf_start + decbuf_y_size + decbuf_uv_size, canvas_width / 2, canvas_height / 2, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_LINEAR); - canvas_config(index2canvas1(i) & 0xff, + CANVAS_BLKMODE_LINEAR, 0, VDEC_1); + config_cav_lut_ex(index2canvas1(i) & 0xff, buf_start + decbuf_size / 2, canvas_width, canvas_height, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_LINEAR); - canvas_config((index2canvas1(i) >> 8) & 0xff, + CANVAS_BLKMODE_LINEAR, 0, VDEC_1); + config_cav_lut_ex((index2canvas1(i) >> 8) & 0xff, buf_start + decbuf_y_size + decbuf_uv_size / 2, canvas_width / 2, canvas_height / 2, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_LINEAR); - canvas_config((index2canvas1(i) >> 16) & 0xff, + CANVAS_BLKMODE_LINEAR, 0, VDEC_1); + config_cav_lut_ex((index2canvas1(i) >> 16) & 0xff, buf_start + decbuf_y_size + decbuf_uv_size + decbuf_uv_size / 2, canvas_width / 2, canvas_height / 2, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_LINEAR); + CANVAS_BLKMODE_LINEAR, 0, VDEC_1); #endif } @@ -740,7 +734,7 @@ if (IS_ERR_OR_NULL(buf)) return -ENOMEM; - init_timer(&recycle_timer); + timer_setup(&recycle_timer, vmjpeg_put_timer_func, 0); stat |= STAT_TIMER_INIT; @@ -805,10 +799,7 @@ stat |= STAT_VF_HOOK; - recycle_timer.data = (ulong)&recycle_timer; - recycle_timer.function = vmjpeg_put_timer_func; recycle_timer.expires = jiffies + PUT_INTERVAL; - add_timer(&recycle_timer); stat |= STAT_TIMER_ARM; @@ -911,32 +902,16 @@ } /****************************************/ -#ifdef CONFIG_PM -static int mjpeg_suspend(struct device *dev) -{ - amvdec_suspend(to_platform_device(dev), dev->power.power_state); - return 0; -} - -static int mjpeg_resume(struct device *dev) -{ - amvdec_resume(to_platform_device(dev)); - return 0; -} - -static const struct dev_pm_ops mjpeg_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(mjpeg_suspend, mjpeg_resume) -}; -#endif static struct platform_driver amvdec_mjpeg_driver = { .probe = amvdec_mjpeg_probe, .remove = amvdec_mjpeg_remove, +#ifdef CONFIG_PM + .suspend = amvdec_suspend, + .resume = amvdec_resume, +#endif .driver = { .name = DRIVER_NAME, -#ifdef CONFIG_PM - .pm = &mjpeg_pm_ops, -#endif } };
diff --git a/drivers/frame_provider/decoder/mjpeg/vmjpeg_multi.c b/drivers/frame_provider/decoder/mjpeg/vmjpeg_multi.c index 108f5da..22d7dbd 100644 --- a/drivers/frame_provider/decoder/mjpeg/vmjpeg_multi.c +++ b/drivers/frame_provider/decoder/mjpeg/vmjpeg_multi.c
@@ -29,7 +29,8 @@ #include <linux/amlogic/media/vfm/vframe.h> #include <linux/amlogic/media/vfm/vframe_provider.h> #include <linux/amlogic/media/vfm/vframe_receiver.h> -#include <linux/amlogic/tee.h> +//#include <linux/amlogic/tee.h> +#include <uapi/linux/tee.h> #include <linux/amlogic/media/utils/vdec_reg.h> #include <linux/amlogic/media/registers/register.h> @@ -47,6 +48,7 @@ #include "../utils/vdec_v4l2_buffer_ops.h" #include "../utils/config_parser.h" #include <media/v4l2-mem2mem.h> +#include "../utils/vdec_feature.h" #define MEM_NAME "codec_mmjpeg" @@ -96,6 +98,7 @@ static int vmjpeg_vf_states(struct vframe_states *states, void *); static int vmjpeg_event_cb(int type, void *data, void *private_data); static void vmjpeg_work(struct work_struct *work); +static int notify_v4l_eos(struct vdec_s *vdec); static int pre_decode_buf_level = 0x800; static int start_decode_buf_level = 0x2000; static u32 without_display_mode; @@ -124,14 +127,19 @@ if (((debug_enable & debug_flag) && ((1 << index) & mmjpeg_debug_mask)) || (debug_flag == PRINT_FLAG_ERROR)) { - unsigned char buf[512]; + unsigned char *buf = kzalloc(512, GFP_ATOMIC); int len = 0; va_list args; + + if (!buf) + return 0; + va_start(args, fmt); len = sprintf(buf, "%d: ", index); vsnprintf(buf + len, 512-len, fmt, args); pr_info("%s", buf); va_end(args); + kfree(buf); } return 0; } @@ -208,7 +216,7 @@ struct firmware_s *fw; struct timer_list check_timer; u32 decode_timeout_count; - unsigned long int start_process_time; + u32 start_process_time; u32 last_vld_level; u8 eos; u32 frame_num; @@ -229,6 +237,7 @@ u32 res_ch_flag; u32 canvas_mode; u32 canvas_endian; + ulong fb_token; char vdec_name[32]; char pts_name[32]; char new_q_name[32]; @@ -326,7 +335,8 @@ hw->res_ch_flag = 1; ctx->v4l_resolution_change = 1; hw->eos = 1; - notify_v4l_eos(hw_to_vdec(hw)); + if (hw->is_used_v4l) + notify_v4l_eos(hw_to_vdec(hw)); ret = 1; } @@ -338,6 +348,8 @@ static irqreturn_t vmjpeg_isr_thread_fn(struct vdec_s *vdec, int irq) { struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)(vdec->private); + struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx; + struct vdec_v4l2_buffer *fb = NULL; u32 reg; struct vframe_s *vf = NULL; u32 index, offset = 0, pts; @@ -400,6 +412,7 @@ if (hw->is_used_v4l) { vf->v4l_mem_handle = hw->buffer_spec[index].v4l_ref_buf_addr; + fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; mmjpeg_debug_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL, "[%d] %s(), v4l mem handle: 0x%lx\n", ((struct aml_vcodec_ctx *)(hw->v4l2_ctx))->id, @@ -455,9 +468,17 @@ vf->pts, vf->pts_us64, vf->duration); vdec->vdec_fps_detec(vdec->id); if (without_display_mode == 0) { - vf_notify_receiver(vdec->vf_provider_name, - VFRAME_EVENT_PROVIDER_VFRAME_READY, - NULL); + if (hw->is_used_v4l) { + if (v4l2_ctx->is_stream_off) { + vmjpeg_vf_put(vmjpeg_vf_get(vdec), vdec); + } else { + fb->task->submit(fb->task, TASK_TYPE_DEC); + } + } else { + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, + NULL); + } } else vmjpeg_vf_put(vmjpeg_vf_get(vdec), vdec); @@ -650,12 +671,12 @@ hw->buffer_spec[i].v_canvas_index = canvas_v(canvas); } - canvas_config_ex(hw->buffer_spec[i].y_canvas_index, + config_cav_lut_ex(hw->buffer_spec[i].y_canvas_index, hw->buffer_spec[i].y_addr, canvas_width, canvas_height, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_LINEAR, endian); + CANVAS_BLKMODE_LINEAR, endian, VDEC_1); hw->buffer_spec[i].canvas_config[0].phy_addr = hw->buffer_spec[i].y_addr; hw->buffer_spec[i].canvas_config[0].width = @@ -667,12 +688,12 @@ hw->buffer_spec[i].canvas_config[0].endian = endian; - canvas_config_ex(hw->buffer_spec[i].u_canvas_index, + config_cav_lut_ex(hw->buffer_spec[i].u_canvas_index, hw->buffer_spec[i].u_addr, canvas_width / 2, canvas_height / 2, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_LINEAR, endian); + CANVAS_BLKMODE_LINEAR, endian, VDEC_1); hw->buffer_spec[i].canvas_config[1].phy_addr = hw->buffer_spec[i].u_addr; hw->buffer_spec[i].canvas_config[1].width = @@ -684,12 +705,12 @@ hw->buffer_spec[i].canvas_config[1].endian = endian; - canvas_config_ex(hw->buffer_spec[i].v_canvas_index, + config_cav_lut_ex(hw->buffer_spec[i].v_canvas_index, hw->buffer_spec[i].v_addr, canvas_width / 2, canvas_height / 2, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_LINEAR, endian); + CANVAS_BLKMODE_LINEAR, endian, VDEC_1); hw->buffer_spec[i].canvas_config[2].phy_addr = hw->buffer_spec[i].v_addr; hw->buffer_spec[i].canvas_config[2].width = @@ -812,7 +833,7 @@ hw->not_run_ready, hw->input_empty ); - if (vf_get_receiver(vdec->vf_provider_name)) { + if (!hw->is_used_v4l && vf_get_receiver(vdec->vf_provider_name)) { enum receviver_start_e state = vf_notify_receiver(vdec->vf_provider_name, VFRAME_EVENT_PROVIDER_QUREY_STATE, @@ -915,9 +936,10 @@ vdec_schedule_work(&hw->work); } -static void check_timer_func(unsigned long arg) +static void check_timer_func(struct timer_list *timer) { - struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)arg; + struct vdec_mjpeg_hw_s *hw = container_of(timer, + struct vdec_mjpeg_hw_s, check_timer); struct vdec_s *vdec = hw_to_vdec(hw); int timeout_val = decode_timeout_val; @@ -986,10 +1008,16 @@ struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx); - if (hw->buffer_spec[i].v4l_ref_buf_addr) - return 0; + if (hw->buffer_spec[i].v4l_ref_buf_addr) { + struct vdec_v4l2_buffer *fb = + (struct vdec_v4l2_buffer *) + hw->buffer_spec[i].v4l_ref_buf_addr; - ret = vdec_v4l_get_buffer(hw->v4l2_ctx, &fb); + fb->status = FB_ST_DECODER; + return 0; + } + + ret = ctx->fb_ops.alloc(&ctx->fb_ops, hw->fb_token, &fb, AML_FB_REQ_DEC); if (ret < 0) { mmjpeg_debug_print(DECODE_ID(hw), 0, "[%d] get fb fail.\n", @@ -998,6 +1026,8 @@ return ret; } + fb->status = FB_ST_DECODER; + if (!hw->frame_width || !hw->frame_height) { struct vdec_pic_info pic; vdec_v4l_get_pic_info(ctx, &pic); @@ -1023,7 +1053,7 @@ decbuf_start = fb->m.mem[0].addr; decbuf_y_size = fb->m.mem[0].size; decbuf_u_start = fb->m.mem[1].addr; - decbuf_u_size = fb->m.mem[1].size; + decbuf_u_size = fb->m.mem[1].size >> 1; decbuf_v_start = decbuf_u_start + decbuf_u_size; decbuf_v_size = decbuf_u_size; canvas_width = ALIGN(hw->frame_width, 64); @@ -1045,7 +1075,7 @@ } mmjpeg_debug_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL, - "[%d] v4l ref buf addr: 0x%px\n", ctx->id, fb); + "[%d] v4l ref buf addr: 0x%x\n", ctx->id, fb); if (vdec->parallel_dec == 1) { if (hw->buffer_spec[i].y_canvas_index == -1) @@ -1075,8 +1105,8 @@ hw->buffer_spec[i].canvas_config[0].endian = hw->canvas_endian; - canvas_config_config(hw->buffer_spec[i].y_canvas_index, - &hw->buffer_spec[i].canvas_config[0]); + config_cav_lut(hw->buffer_spec[i].y_canvas_index, + &hw->buffer_spec[i].canvas_config[0], VDEC_1); hw->buffer_spec[i].canvas_config[1].phy_addr = decbuf_u_start; @@ -1089,8 +1119,8 @@ hw->buffer_spec[i].canvas_config[1].endian = hw->canvas_endian; - canvas_config_config(hw->buffer_spec[i].u_canvas_index, - &hw->buffer_spec[i].canvas_config[1]); + config_cav_lut(hw->buffer_spec[i].u_canvas_index, + &hw->buffer_spec[i].canvas_config[1], VDEC_1); hw->buffer_spec[i].canvas_config[2].phy_addr = decbuf_v_start; @@ -1103,8 +1133,8 @@ hw->buffer_spec[i].canvas_config[2].endian = hw->canvas_endian; - canvas_config_config(hw->buffer_spec[i].v_canvas_index, - &hw->buffer_spec[i].canvas_config[2]); + config_cav_lut(hw->buffer_spec[i].v_canvas_index, + &hw->buffer_spec[i].canvas_config[2], VDEC_1); /* mjpeg decoder canvas need to be revert to match display. */ hw->buffer_spec[i].canvas_config[0].endian = hw->canvas_endian ? 0 : 7; @@ -1157,6 +1187,9 @@ /*run to parser csd data*/ i = 0; } else { + if (!ctx->fb_ops.query(&ctx->fb_ops, &hw->fb_token)) + return -1; + if (vmjpeg_v4l_alloc_buff_config_canvas(hw, i)) return -1; } @@ -1183,12 +1216,12 @@ if (!hw->is_used_v4l) { for (i = 0; i < hw->buf_num; i++) { buff_spec = &hw->buffer_spec[i]; - canvas_config_config(buff_spec->y_canvas_index, - &buff_spec->canvas_config[0]); - canvas_config_config(buff_spec->u_canvas_index, - &buff_spec->canvas_config[1]); - canvas_config_config(buff_spec->v_canvas_index, - &buff_spec->canvas_config[2]); + config_cav_lut(buff_spec->y_canvas_index, + &buff_spec->canvas_config[0], VDEC_1); + config_cav_lut(buff_spec->u_canvas_index, + &buff_spec->canvas_config[1], VDEC_1); + config_cav_lut(buff_spec->v_canvas_index, + &buff_spec->canvas_config[2], VDEC_1); } } } @@ -1284,10 +1317,7 @@ CODEC_MM_FLAGS_CMA_CLEAR | CODEC_MM_FLAGS_FOR_VDECODER); - init_timer(&hw->check_timer); - - hw->check_timer.data = (unsigned long)hw; - hw->check_timer.function = check_timer_func; + timer_setup(&hw->check_timer, check_timer_func, 0); hw->check_timer.expires = jiffies + CHECK_INTERVAL; /*add_timer(&hw->check_timer);*/ hw->stat |= STAT_TIMER_ARM; @@ -1490,9 +1520,12 @@ if (hw->is_used_v4l) { index = find_free_buffer(hw); - if ((index == -1) && vdec_v4l_get_buffer(hw->v4l2_ctx, &fb)) { - pr_err("[%d] get fb fail.\n", ctx->id); - return -1; + if (index == -1) { + ctx->fb_ops.query(&ctx->fb_ops, &hw->fb_token); + if (ctx->fb_ops.alloc(&ctx->fb_ops, hw->fb_token, &fb, AML_FB_REQ_DEC) < 0) { + pr_err("[%d] get fb fail.\n", ctx->id); + return -1; + } } } @@ -1501,13 +1534,18 @@ vf->v4l_mem_handle = (index == -1) ? (ulong)fb : hw->buffer_spec[index].v4l_ref_buf_addr; vf->flag = VFRAME_FLAG_EMPTY_FRAME_V4L; + fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; vdec_vframe_ready(vdec, vf); kfifo_put(&hw->display_q, (const struct vframe_s *)vf); - vf_notify_receiver(vdec->vf_provider_name, - VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); - pr_info("[%d] mpeg12 EOS notify.\n", (hw->is_used_v4l)?ctx->id:vdec->id); + if (hw->is_used_v4l) + fb->task->submit(fb->task, TASK_TYPE_DEC); + else + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + + pr_info("[%d] mjpeg EOS notify.\n", (hw->is_used_v4l)?ctx->id:vdec->id); } return 0; @@ -1718,8 +1756,9 @@ hw->buf_num = vmjpeg_get_buf_num(hw); - vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name, - &vf_provider_ops, pdata); + if (!hw->is_used_v4l) + vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name, + &vf_provider_ops, pdata); platform_set_drvdata(pdev, pdata); @@ -1774,6 +1813,7 @@ vdec->free_canvas_ex(hw->buffer_spec[i].v_canvas_index, vdec->id); } } + vfree(hw); pr_info("%s\n", __func__); @@ -1781,38 +1821,22 @@ } /****************************************/ -#ifdef CONFIG_PM -static int mmjpeg_suspend(struct device *dev) -{ - amvdec_suspend(to_platform_device(dev), dev->power.power_state); - return 0; -} - -static int mmjpeg_resume(struct device *dev) -{ - amvdec_resume(to_platform_device(dev)); - return 0; -} - -static const struct dev_pm_ops mmjpeg_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(mmjpeg_suspend, mmjpeg_resume) -}; -#endif static struct platform_driver ammvdec_mjpeg_driver = { .probe = ammvdec_mjpeg_probe, .remove = ammvdec_mjpeg_remove, +#ifdef CONFIG_PM + .suspend = amvdec_suspend, + .resume = amvdec_resume, +#endif .driver = { .name = DRIVER_NAME, -#ifdef CONFIG_PM - .pm = &mmjpeg_pm_ops, -#endif } }; static struct codec_profile_t ammvdec_mjpeg_profile = { .name = "mmjpeg", - .profile = "" + .profile = "v4l" }; static int __init ammvdec_mjpeg_driver_init_module(void) @@ -1822,6 +1846,7 @@ return -ENODEV; } vcodec_profile_register(&ammvdec_mjpeg_profile); + vcodec_feature_register(VFORMAT_MJPEG, 0); return 0; }
diff --git a/drivers/frame_provider/decoder/mpeg12/vmpeg12.c b/drivers/frame_provider/decoder/mpeg12/vmpeg12.c index 29757a0..a813ac7 100644 --- a/drivers/frame_provider/decoder/mpeg12/vmpeg12.c +++ b/drivers/frame_provider/decoder/mpeg12/vmpeg12.c
@@ -29,7 +29,7 @@ #include <linux/amlogic/media/vfm/vframe.h> #include <linux/amlogic/media/vfm/vframe_provider.h> #include <linux/amlogic/media/vfm/vframe_receiver.h> -#include <linux/amlogic/cpu_version.h> +#include <linux/amlogic/media/registers/cpu_version.h> #include <linux/amlogic/media/codec_mm/codec_mm.h> #include <linux/dma-mapping.h> #include <linux/slab.h> @@ -41,7 +41,8 @@ #include "../utils/decoder_bmmu_box.h" #include <linux/uaccess.h> #include <linux/amlogic/media/codec_mm/configs.h> -#include <linux/amlogic/tee.h> +//#include <linux/amlogic/tee.h> +#include <uapi/linux/tee.h> @@ -1310,11 +1311,9 @@ } -static void vmpeg_put_timer_func(unsigned long arg) +static void vmpeg_put_timer_func(struct timer_list *timer) { - struct timer_list *timer = (struct timer_list *)arg; int fatal_reset = 0; - enum receviver_start_e state = RECEIVER_INACTIVE; if (vf_get_receiver(PROVIDER_NAME)) { @@ -1765,30 +1764,30 @@ } else { #ifdef NV21 - canvas_config(2 * i + 0, + config_cav_lut_ex(2 * i + 0, buf_start, canvas_width, canvas_height, - CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); - canvas_config(2 * i + 1, + CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32, 0, VDEC_1); + config_cav_lut_ex(2 * i + 1, buf_start + decbuf_y_size, canvas_width, canvas_height / 2, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_32X32); + CANVAS_BLKMODE_32X32, 0, VDEC_1); #else - canvas_config(3 * i + 0, + config_cav_lut_ex(3 * i + 0, buf_start, canvas_width, canvas_height, - CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); - canvas_config(3 * i + 1, + CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32, 0, VDEC_1); + config_cav_lut_ex(3 * i + 1, buf_start + decbuf_y_size, canvas_width / 2, canvas_height / 2, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_32X32); - canvas_config(3 * i + 2, + CANVAS_BLKMODE_32X32, 0, VDEC_1); + config_cav_lut_ex(3 * i + 2, buf_start + decbuf_y_size + decbuf_uv_size, canvas_width / 2, canvas_height / 2, - CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); + CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32, 0, VDEC_1); #endif } } @@ -1949,7 +1948,7 @@ if (IS_ERR_OR_NULL(buf)) return -ENOMEM; - init_timer(&recycle_timer); + timer_setup(&recycle_timer, vmpeg_put_timer_func, 0); stat |= STAT_TIMER_INIT; @@ -2014,10 +2013,7 @@ stat |= STAT_VF_HOOK; - recycle_timer.data = (ulong)&recycle_timer; - recycle_timer.function = vmpeg_put_timer_func; recycle_timer.expires = jiffies + PUT_INTERVAL; - add_timer(&recycle_timer); stat |= STAT_TIMER_ARM; @@ -2159,32 +2155,16 @@ } /****************************************/ -#ifdef CONFIG_PM -static int mpeg12_suspend(struct device *dev) -{ - amvdec_suspend(to_platform_device(dev), dev->power.power_state); - return 0; -} - -static int mpeg12_resume(struct device *dev) -{ - amvdec_resume(to_platform_device(dev)); - return 0; -} - -static const struct dev_pm_ops mpeg12_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(mpeg12_suspend, mpeg12_resume) -}; -#endif static struct platform_driver amvdec_mpeg12_driver = { .probe = amvdec_mpeg12_probe, .remove = amvdec_mpeg12_remove, +#ifdef CONFIG_PM + .suspend = amvdec_suspend, + .resume = amvdec_resume, +#endif .driver = { .name = DRIVER_NAME, -#ifdef CONFIG_PM - .pm = &mpeg12_pm_ops, -#endif } };
diff --git a/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c b/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c index 76a021e..f77bb7f 100644 --- a/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c +++ b/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c
@@ -15,6 +15,7 @@ * */ +#define DEBUG #include <linux/kernel.h> #include <linux/types.h> #include <linux/errno.h> @@ -26,19 +27,19 @@ #include <linux/dma-mapping.h> #include <linux/slab.h> #include <linux/delay.h> - +#include <linux/sched/clock.h> #include <linux/amlogic/media/frame_sync/ptsserv.h> #include <linux/amlogic/media/utils/amstream.h> #include <linux/amlogic/media/canvas/canvas.h> #include <linux/amlogic/media/vfm/vframe.h> #include <linux/amlogic/media/vfm/vframe_provider.h> #include <linux/amlogic/media/vfm/vframe_receiver.h> -#include <linux/amlogic/tee.h> +//#include <linux/amlogic/tee.h> +#include <uapi/linux/tee.h> #include <linux/amlogic/media/utils/vdec_reg.h> #include <linux/amlogic/media/registers/register.h> #include "../../../stream_input/amports/amports_priv.h" - #include "../utils/vdec_input.h" #include "../utils/vdec.h" #include "../utils/amvdec.h" @@ -51,8 +52,7 @@ #include "../utils/vdec_v4l2_buffer_ops.h" #include "../utils/config_parser.h" #include <media/v4l2-mem2mem.h> - - +#include "../utils/vdec_feature.h" #define MEM_NAME "codec_mmpeg12" #define CHECK_INTERVAL (HZ/100) @@ -88,7 +88,6 @@ #define PICINFO_RPT_FIRST 0x4000 #define PICINFO_TOP_FIRST 0x2000 #define PICINFO_FRAME 0x1000 - #define TOP_FIELD 0x1000 #define BOTTOM_FIELD 0x2000 #define FRAME_PICTURE 0x3000 @@ -112,6 +111,8 @@ #define CTX_DECBUF_OFFSET (CTX_CO_MV_OFFSET + 0x11000) #define DEFAULT_MEM_SIZE (32*SZ_1M) +#define INVALID_IDX (-1) /* Invalid buffer index.*/ + static u32 buf_size = 32 * 1024 * 1024; static int pre_decode_buf_level = 0x800; static int start_decode_buf_level = 0x4000; @@ -179,7 +180,6 @@ #define DEC_RESULT_EOS 5 #define DEC_RESULT_GET_DATA 6 #define DEC_RESULT_GET_DATA_RETRY 7 -#define DEC_RESULT_DISCARD_DATA 8 #define DEC_DECODE_TIMEOUT 0x21 #define DECODE_ID(hw) (hw_to_vdec(hw)->id) @@ -217,6 +217,7 @@ ulong v4l_ref_buf_addr; u32 hw_decode_time; u32 frame_size; // For frame base mode + u64 timestamp; }; struct vdec_mpeg12_hw_s { @@ -270,6 +271,7 @@ s32 refs[2]; int dec_result; u32 timeout_processing; + wait_queue_head_t wait_q; struct work_struct work; struct work_struct timeout_work; struct work_struct notify_work; @@ -301,6 +303,7 @@ u32 pre_parser_wr_ptr; u8 next_again_flag; #endif + struct work_struct userdata_push_work; struct mutex userdata_mutex; struct mmpeg2_userdata_info_t userdata_info; @@ -339,17 +342,18 @@ u32 level_idc; int dec_again_cnt; int vdec_pg_enable_flag; + ulong fb_token; char vdec_name[32]; char pts_name[32]; char new_q_name[32]; char disp_q_name[32]; - u32 last_frame_offset; + bool run_flag; }; static void vmpeg12_local_init(struct vdec_mpeg12_hw_s *hw); static int vmpeg12_hw_ctx_restore(struct vdec_mpeg12_hw_s *hw); static void reset_process_time(struct vdec_mpeg12_hw_s *hw); -static void vmpeg12_canvas_init(struct vdec_mpeg12_hw_s *hw); +static int vmpeg12_canvas_init(struct vdec_mpeg12_hw_s *hw); static void flush_output(struct vdec_mpeg12_hw_s *hw); static struct vframe_s *vmpeg_vf_peek(void *); static struct vframe_s *vmpeg_vf_get(void *); @@ -359,14 +363,12 @@ static int notify_v4l_eos(struct vdec_s *vdec); static void start_process_time_set(struct vdec_mpeg12_hw_s *hw); static int check_dirty_data(struct vdec_s *vdec); - static int debug_enable; /*static struct work_struct userdata_push_work;*/ #undef pr_info #define pr_info printk unsigned int mpeg12_debug_mask = 0xff; /*static int counter_max = 5;*/ - static u32 run_ready_min_buf_num = 2; static int dirty_again_threshold = 100; static int error_proc_policy = 0x1; @@ -374,7 +376,7 @@ #define PRINT_FLAG_ERROR 0x0 #define PRINT_FLAG_RUN_FLOW 0X0001 #define PRINT_FLAG_TIMEINFO 0x0002 -#define PRINT_FLAG_UCODE_DETAIL 0x0004 +#define PRINT_FLAG_UCODE_DETAIL 0x0004 #define PRINT_FLAG_VLD_DETAIL 0x0008 #define PRINT_FLAG_DEC_DETAIL 0x0010 #define PRINT_FLAG_BUFFER_DETAIL 0x0020 @@ -388,25 +390,28 @@ #define PRINT_FLAG_USERDATA_DETAIL 0x2000 #define PRINT_FLAG_TIMEOUT_STATUS 0x4000 #define PRINT_FLAG_V4L_DETAIL 0x8000 -#define PRINT_FLAG_FCC_STATUS 0x10000 #define IGNORE_PARAM_FROM_CONFIG 0x8000000 - int debug_print(int index, int debug_flag, const char *fmt, ...) { if (((debug_enable & debug_flag) && ((1 << index) & mpeg12_debug_mask)) || (debug_flag == PRINT_FLAG_ERROR)) { - unsigned char buf[512]; + unsigned char *buf = kzalloc(512, GFP_ATOMIC); int len = 0; va_list args; + + if (!buf) + return 0; + va_start(args, fmt); len = sprintf(buf, "%d: ", index); vsnprintf(buf + len, 512-len, fmt, args); pr_info("%s", buf); va_end(args); + kfree(buf); } return 0; } @@ -444,10 +449,16 @@ struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx); - if (hw->pics[i].v4l_ref_buf_addr) - return 0; + if (hw->pics[i].v4l_ref_buf_addr) { + struct vdec_v4l2_buffer *fb = + (struct vdec_v4l2_buffer *) + hw->pics[i].v4l_ref_buf_addr; - ret = vdec_v4l_get_buffer(hw->v4l2_ctx, &fb); + fb->status = FB_ST_DECODER; + return 0; + } + + ret = ctx->fb_ops.alloc(&ctx->fb_ops, hw->fb_token, &fb, AML_FB_REQ_DEC); if (ret < 0) { debug_print(DECODE_ID(hw), 0, "[%d] get fb fail %d/%d.\n", @@ -455,6 +466,8 @@ return ret; } + fb->status = FB_ST_DECODER; + if (!hw->frame_width || !hw->frame_height) { struct vdec_pic_info pic; vdec_v4l_get_pic_info(ctx, &pic); @@ -485,7 +498,7 @@ fb->m.mem[1].bytes_used = decbuf_uv_size; } - debug_print(DECODE_ID(hw), 0, "[%d] %s(), v4l ref buf addr: 0x%px\n", + debug_print(DECODE_ID(hw), 0, "[%d] %s(), v4l ref buf addr: 0x%x\n", ctx->id, __func__, fb); if (vdec->parallel_dec == 1) { @@ -513,7 +526,11 @@ hw->canvas_config[i][0].block_mode = hw->canvas_mode; hw->canvas_config[i][0].endian = (hw->canvas_mode == CANVAS_BLKMODE_LINEAR) ? 7 : 0; - canvas_config_config(canvas_y(canvas), &hw->canvas_config[i][0]); + config_cav_lut(canvas_y(canvas), &hw->canvas_config[i][0], VDEC_1); + + /* mpeg2 decoder canvas need to be revert to match display canvas */ + hw->canvas_config[i][0].endian = + (hw->canvas_mode != CANVAS_BLKMODE_LINEAR) ? 7 : 0; hw->canvas_config[i][1].phy_addr = decbuf_uv_start; hw->canvas_config[i][1].width = canvas_width; @@ -521,10 +538,14 @@ hw->canvas_config[i][1].block_mode = hw->canvas_mode; hw->canvas_config[i][1].endian = (hw->canvas_mode == CANVAS_BLKMODE_LINEAR) ? 7 : 0; - canvas_config_config(canvas_u(canvas), &hw->canvas_config[i][1]); + config_cav_lut(canvas_u(canvas), &hw->canvas_config[i][1], VDEC_1); + + /* mpeg2 decoder canvas need to be revert to match display canvas */ + hw->canvas_config[i][1].endian = + (hw->canvas_mode != CANVAS_BLKMODE_LINEAR) ? 7 : 0; debug_print(DECODE_ID(hw), PRINT_FLAG_BUFFER_DETAIL, - "[%d] %s(), canvas: 0x%x mode: %d y: %lx uv: %lx w: %d h: %d\n", + "[%d] %s(), canvas: 0x%x mode: %d y: %x uv: %x w: %d h: %d\n", ctx->id, __func__, canvas, hw->canvas_mode, decbuf_start, decbuf_uv_start, canvas_width, canvas_height); @@ -532,6 +553,7 @@ return 0; } + static unsigned int vmpeg12_get_buf_num(struct vdec_mpeg12_hw_s *hw) { unsigned int buf_num = DECODE_BUFFER_NUM_DEF; @@ -576,6 +598,9 @@ /*run to parser csd data*/ i = 0; } else { + if (!ctx->fb_ops.query(&ctx->fb_ops, &hw->fb_token)) + return -1; + if (vmpeg12_v4l_alloc_buff_config_canvas(hw, i)) return -1; } @@ -1456,6 +1481,11 @@ offset = READ_VREG(AV_SCRATCH_I); + codec_mm_dma_flush( + hw->ccbuf_phyAddress_virt, + CCBUF_SIZE, + DMA_FROM_DEVICE); + mutex_lock(&hw->userdata_mutex); if (hw->ccbuf_phyAddress_virt) { pdata = (u8 *)hw->ccbuf_phyAddress_virt + hw->ucode_cc_last_wp; @@ -1538,6 +1568,7 @@ if (pdata >= hw->userdata_info.data_buf_end) pdata = hw->userdata_info.data_buf; } + pcur_ud_rec = hw->ud_record + hw->cur_ud_idx; pcur_ud_rec->meta_info = meta_info; @@ -1564,7 +1595,6 @@ hw->cur_ud_idx++; WRITE_VREG(AV_SCRATCH_J, 0); - } @@ -1611,12 +1641,10 @@ u32 info = pic->buffer_info; struct vdec_s *vdec = hw_to_vdec(hw); struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx; + struct vdec_v4l2_buffer *fb = NULL; ulong nv_order = VIDTYPE_VIU_NV21; bool pb_skip = false; -#ifdef NV21 - type = nv_order; -#endif /* swap uv */ if (hw->is_used_v4l) { if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12) || @@ -1624,6 +1652,9 @@ nv_order = VIDTYPE_VIU_NV12; } +#ifdef NV21 + type = nv_order; +#endif if (hw->i_only) { pb_skip = 1; } @@ -1645,6 +1676,10 @@ field_num = (info & PICINFO_RPT_FIRST) ? 3 : 2; } + if ((hw->is_used_v4l) && + (vdec->prog_only)) + field_num = 1; + for (i = 0; i < field_num; i++) { if (kfifo_get(&hw->newframe_q, &vf) == 0) { debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR, @@ -1657,6 +1692,7 @@ if (hw->is_used_v4l) { vf->v4l_mem_handle = hw->pics[index].v4l_ref_buf_addr; + fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; debug_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL, "[%d] %s(), v4l mem handle: 0x%lx\n", ((struct aml_vcodec_ctx *)(hw->v4l2_ctx))->id, @@ -1701,9 +1737,11 @@ if (i > 0) { vf->pts = 0; vf->pts_us64 = 0; + vf->timestamp = 0; } else { vf->pts = (pic->pts_valid) ? pic->pts : 0; vf->pts_us64 = (pic->pts_valid) ? pic->pts64 : 0; + vf->timestamp = pic->timestamp; } vf->type_original = vf->type; @@ -1780,9 +1818,17 @@ __func__); } if (without_display_mode == 0) { - vf_notify_receiver(vdec->vf_provider_name, - VFRAME_EVENT_PROVIDER_VFRAME_READY, - NULL); + if (hw->is_used_v4l) { + if (v4l2_ctx->is_stream_off) { + vmpeg_vf_put(vmpeg_vf_get(vdec), vdec); + } else { + fb->task->submit(fb->task, TASK_TYPE_DEC); + } + } else { + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, + NULL); + } } else vmpeg_vf_put(vmpeg_vf_get(vdec), vdec); @@ -1863,20 +1909,18 @@ return 0; } -static int vmpeg2_get_ps_info(struct vdec_mpeg12_hw_s *hw, int width, int height, - bool frame_prog, struct aml_vdec_ps_infos *ps) +static int vmpeg2_get_ps_info(struct vdec_mpeg12_hw_s *hw, int width, int height, struct aml_vdec_ps_infos *ps) { ps->visible_width = width; ps->visible_height = height; ps->coded_width = ALIGN(width, 64); ps->coded_height = ALIGN(height, 32); ps->dpb_size = hw->buf_num; - ps->field = frame_prog ? V4L2_FIELD_NONE : V4L2_FIELD_INTERLACED; return 0; } -static int v4l_res_change(struct vdec_mpeg12_hw_s *hw, int width, int height, bool frame_prog) +static int v4l_res_change(struct vdec_mpeg12_hw_s *hw, int width, int height) { struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx); @@ -1895,7 +1939,7 @@ hw->frame_width, hw->frame_height, width, height); - vmpeg2_get_ps_info(hw, width, height, frame_prog, &ps); + vmpeg2_get_ps_info(hw, width, height, &ps); vdec_v4l_set_ps_infos(ctx, &ps); vdec_v4l_res_ch_event(ctx); hw->v4l_params_parsed = false; @@ -1903,7 +1947,8 @@ ctx->v4l_resolution_change = 1; hw->eos = 1; flush_output(hw); - notify_v4l_eos(hw_to_vdec(hw)); + if (hw->is_used_v4l) + notify_v4l_eos(hw_to_vdec(hw)); ret = 1; } @@ -1912,65 +1957,6 @@ return ret; } -#ifdef VDEC_FCC_SUPPORT -static void fcc_discard_mode_process(struct vdec_s *vdec) -{ - struct vdec_mpeg12_hw_s *hw = - (struct vdec_mpeg12_hw_s *)(vdec->private); - int wrap_count; - u32 rp; - u32 first_ptr; - - if (vdec->fcc_status == AGAIN_STATUS) { - wrap_count = READ_VREG(VLD_MEM_VIFIFO_WRAP_COUNT); - rp = READ_VREG(VLD_MEM_VIFIFO_RP); - first_ptr = vdec->vbuf.ext_buf_addr; - - vdec->stream_offset = rp + vdec->input.size * wrap_count - first_ptr; - debug_print(DECODE_ID(hw), PRINT_FLAG_FCC_STATUS, - "[%d][FCC]: Notify stream_offset: %d\n", - vdec->id, vdec->stream_offset); - - debug_print(DECODE_ID(hw), PRINT_FLAG_FCC_STATUS, - "[%d][FCC]: rp : 0x%x size: 0x%x wrap_count:%d first_ptr: 0x%x\n", - vdec->id, rp, vdec->input.size, wrap_count, first_ptr); - vdec_wakeup_fcc_poll(vdec); - vdec->fcc_status = WAIT_MSG_STATUS; - hw->dec_result = DEC_RESULT_AGAIN; - vdec_schedule_work(&hw->work); - } else if (vdec->fcc_status == DISCARD_STATUS) { - debug_print(DECODE_ID(hw), PRINT_FLAG_FCC_STATUS, - "[%d][FCC]: Discard current gop and to find next gop!\n", - vdec->id); - vdec->fcc_status = AGAIN_STATUS; - hw->dec_result = DEC_RESULT_DISCARD_DATA; - vdec_schedule_work(&hw->work); - } -} - -static int vmpeg2_fcc_process(struct vdec_s *vdec) -{ - struct vdec_mpeg12_hw_s *hw = - (struct vdec_mpeg12_hw_s *)(vdec->private); - - if (input_stream_based(vdec)) { - switch (vdec->fcc_mode) { - case FCC_DISCARD_MODE: - fcc_discard_mode_process(vdec); - return 1; - case FCC_DEC_MODE: - debug_print(DECODE_ID(hw), PRINT_FLAG_FCC_STATUS, - "[%d][FCC]: Current is Dec mode.\n", vdec->id); - break; - case FCC_BUTT: - default: - break; - } - } - - return 0; -} -#endif static irqreturn_t vmpeg12_isr_thread_fn(struct vdec_s *vdec, int irq) { @@ -2002,26 +1988,16 @@ "[vdec_kpi][%s] First I frame coming.\n", __func__); } - -#ifdef VDEC_FCC_SUPPORT - if (vmpeg2_fcc_process(vdec) > 0) { - WRITE_VREG(AV_SCRATCH_G, 0); - return IRQ_HANDLED; - } -#endif if (hw->is_used_v4l) { int frame_width = READ_VREG(MREG_PIC_WIDTH); int frame_height = READ_VREG(MREG_PIC_HEIGHT); - int info = READ_VREG(MREG_SEQ_INFO); - bool frame_prog = info & 0x10000; - - if (!v4l_res_change(hw, frame_width, frame_height, frame_prog)) { + if (!v4l_res_change(hw, frame_width, frame_height)) { struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx); if (ctx->param_sets_from_ucode && !hw->v4l_params_parsed) { struct aml_vdec_ps_infos ps; - vmpeg2_get_ps_info(hw, frame_width, frame_height, frame_prog, &ps); + vmpeg2_get_ps_info(hw, frame_width, frame_height, &ps); hw->v4l_params_parsed = true; vdec_v4l_set_ps_infos(ctx, &ps); userdata_pushed_drop(hw); @@ -2043,7 +2019,7 @@ } reg = READ_VREG(AV_SCRATCH_J); - if (reg & (1 << 16)) { + if (reg & (1<<16)) { vdec_schedule_work(&hw->userdata_push_work); return IRQ_HANDLED; } @@ -2066,6 +2042,7 @@ READ_VREG(VLD_MEM_VIFIFO_LEVEL), READ_VREG(VLD_MEM_VIFIFO_CONTROL), READ_VREG(VIFF_BIT_CNT)); + if (vdec_frame_based(vdec)) { userdata_pushed_drop(hw); hw->dec_result = DEC_RESULT_DONE; @@ -2142,6 +2119,7 @@ new_pic->pts_valid = hw->chunk->pts_valid; new_pic->pts = hw->chunk->pts; new_pic->pts64 = hw->chunk->pts64; + new_pic->timestamp = hw->chunk->timestamp; if (hw->last_chunk_pts == hw->chunk->pts) { new_pic->pts_valid = 0; debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEINFO, @@ -2161,12 +2139,9 @@ } else { if (hw->chunk) { hw->last_chunk_pts = hw->chunk->pts; - new_pic->pts_valid = hw->chunk->pts_valid; - new_pic->pts = hw->chunk->pts; - new_pic->pts64 = hw->chunk->pts64; - } else { - new_pic->pts_valid = false; + new_pic->timestamp = hw->chunk->timestamp; } + new_pic->pts_valid = false; } debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW, @@ -2224,9 +2199,10 @@ } debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW, - "mmpeg12: disp_pic=%d(%c), ind=%d, offst=%x, pts=(%d,%lld)(%d)\n", + "mmpeg12: disp_pic=%d(%c), ind=%d, offst=%x, pts=(%d,%lld,%llx)(%d)\n", hw->disp_num, GET_SLICE_TYPE(info), index, disp_pic->offset, - disp_pic->pts, disp_pic->pts64, disp_pic->pts_valid); + disp_pic->pts, disp_pic->pts64, + disp_pic->timestamp, disp_pic->pts_valid); prepare_display_buf(hw, disp_pic); vdec_schedule_work(&hw->work); @@ -2238,32 +2214,30 @@ { u32 info, offset; struct vdec_mpeg12_hw_s *hw = - (struct vdec_mpeg12_hw_s *)(vdec->private); + (struct vdec_mpeg12_hw_s *)(vdec->private); if (hw->eos) return IRQ_HANDLED; info = READ_VREG(MREG_PIC_INFO); offset = READ_VREG(MREG_FRAME_OFFSET); - if (offset != hw->last_frame_offset) { - vdec_count_info(&hw->gvs, info & PICINFO_ERROR, offset); - if (info & PICINFO_ERROR) { - if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_I) { - hw->gvs.i_concealed_frames++; - } else if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_P) { - hw->gvs.p_concealed_frames++; - } else if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_B) { - hw->gvs.b_concealed_frames++; - } + + vdec_count_info(&hw->gvs, info & PICINFO_ERROR, offset); + if (info &PICINFO_ERROR) { + if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_I) { + hw->gvs.i_concealed_frames++; + } else if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_P) { + hw->gvs.p_concealed_frames++; + } else if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_B) { + hw->gvs.b_concealed_frames++; } - if (offset) { - if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_I) { - hw->gvs.i_decoded_frames++; - } else if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_P) { - hw->gvs.p_decoded_frames++; - } else if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_B) { - hw->gvs.b_decoded_frames++; - } + } + if (offset) { + if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_I) { + hw->gvs.i_decoded_frames++; + } else if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_P) { + hw->gvs.p_decoded_frames++; + } else if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_B) { + hw->gvs.b_decoded_frames++; } - hw->last_frame_offset = offset; } WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); @@ -2277,7 +2251,7 @@ struct vdec_mpeg12_hw_s, notify_work); struct vdec_s *vdec = hw_to_vdec(hw); - if (vdec->fr_hint_state == VDEC_NEED_HINT) { + if (!hw->is_used_v4l && vdec->fr_hint_state == VDEC_NEED_HINT) { vf_notify_receiver(vdec->vf_provider_name, VFRAME_EVENT_PROVIDER_FR_HINT, (void *)((unsigned long)hw->frame_dur)); @@ -2329,7 +2303,7 @@ struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx); struct vframe_s *vf = NULL; struct vdec_v4l2_buffer *fb = NULL; - int index = -1; + int index = INVALID_IDX; if (hw->eos) { if (kfifo_get(&hw->newframe_q, &vf) == 0 || vf == NULL) { @@ -2340,24 +2314,31 @@ } if (hw->is_used_v4l) { index = find_free_buffer(hw); - if ((index == -1) && - vdec_v4l_get_buffer(hw->v4l2_ctx, &fb)) { - pr_err("[%d] get fb fail.\n", ctx->id); - return -1; + if (index == INVALID_IDX) { + ctx->fb_ops.query(&ctx->fb_ops, &hw->fb_token); + if (ctx->fb_ops.alloc(&ctx->fb_ops, hw->fb_token, &fb, AML_FB_REQ_DEC) < 0) { + pr_err("[%d] get fb fail.\n", ctx->id); + return -1; + } } } vf->type |= VIDTYPE_V4L_EOS; vf->timestamp = ULONG_MAX; - vf->v4l_mem_handle = (index == -1) ? (ulong)fb : + vf->v4l_mem_handle = (index == INVALID_IDX) ? (ulong)fb : hw->pics[index].v4l_ref_buf_addr; vf->flag = VFRAME_FLAG_EMPTY_FRAME_V4L; + fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; vdec_vframe_ready(vdec, vf); kfifo_put(&hw->display_q, (const struct vframe_s *)vf); ATRACE_COUNTER(hw->pts_name, vf->pts); - vf_notify_receiver(vdec->vf_provider_name, - VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + + if (hw->is_used_v4l) + fb->task->submit(fb->task, TASK_TYPE_DEC); + else + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); pr_info("[%d] mpeg12 EOS notify.\n", (hw->is_used_v4l)?ctx->id:vdec->id); } @@ -2474,10 +2455,6 @@ debug_print(DECODE_ID(hw), 0, "%s: end of stream, num %d(%d)\n", __func__, hw->disp_num, hw->dec_num); - } else if (hw->dec_result == DEC_RESULT_DISCARD_DATA) { - hw->dec_again_cnt = 0; - vdec_vframe_dirty(vdec, hw->chunk); - hw->chunk = NULL; } if (hw->stat & STAT_VDEC_RUN) { amvdec_stop(); @@ -2506,6 +2483,7 @@ else vdec_core_finish_run(vdec, CORE_MASK_VDEC_1 | CORE_MASK_HEVC); + wake_up_interruptible(&hw->wait_q); if (hw->is_used_v4l) { struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx); @@ -2725,7 +2703,7 @@ /****************************************/ -static void vmpeg12_canvas_init(struct vdec_mpeg12_hw_s *hw) +static int vmpeg12_canvas_init(struct vdec_mpeg12_hw_s *hw) { int i, ret; u32 canvas_width, canvas_height; @@ -2762,9 +2740,9 @@ ret = decoder_bmmu_box_alloc_buf_phy(hw->mm_blk_handle, i, decbuf_size, DRIVER_NAME, &decbuf_start); if (ret < 0) { - pr_err("mmu alloc failed! size 0x%d idx %d\n", + pr_err("bmmu alloc failed! size 0x%d idx %d\n", decbuf_size, i); - return; + return ret; } } @@ -2775,7 +2753,7 @@ GFP_KERNEL); if (hw->ccbuf_phyAddress_virt == NULL) { pr_err("%s: failed to alloc cc buffer\n", __func__); - return; + return -ENOMEM; } hw->buf_start = decbuf_start; WRITE_VREG(MREG_CO_MV_START, hw->buf_start); @@ -2813,8 +2791,8 @@ hw->canvas_config[i][0].endian = (hw->canvas_mode == CANVAS_BLKMODE_LINEAR)?7:0; - canvas_config_config(canvas_y(canvas), - &hw->canvas_config[i][0]); + config_cav_lut(canvas_y(canvas), + &hw->canvas_config[i][0], VDEC_1); hw->canvas_config[i][1].phy_addr = decbuf_start + decbuf_y_size; @@ -2824,11 +2802,11 @@ hw->canvas_config[i][1].endian = (hw->canvas_mode == CANVAS_BLKMODE_LINEAR)?7:0; - canvas_config_config(canvas_u(canvas), - &hw->canvas_config[i][1]); + config_cav_lut(canvas_u(canvas), + &hw->canvas_config[i][1], VDEC_1); } } - return; + return 0; } static void vmpeg2_dump_state(struct vdec_s *vdec) @@ -2839,11 +2817,12 @@ debug_print(DECODE_ID(hw), 0, "====== %s\n", __func__); debug_print(DECODE_ID(hw), 0, - "width/height (%d/%d),i_first %d, buf_num %d\n", + "width/height (%d/%d),i_first %d, buf_num %d, run_flag %d\n", hw->frame_width, hw->frame_height, hw->first_i_frame_ready, - hw->buf_num + hw->buf_num, + hw->run_flag ); debug_print(DECODE_ID(hw), 0, "is_framebase(%d), eos %d, state 0x%x, dec_result 0x%x dec_frm %d put_frm %d run %d not_run_ready %d,input_empty %d\n", @@ -2864,7 +2843,7 @@ hw->vfbuf_use[i], hw->ref_use[i]); } - if (vf_get_receiver(vdec->vf_provider_name)) { + if (!hw->is_used_v4l && vf_get_receiver(vdec->vf_provider_name)) { enum receviver_start_e state = vf_notify_receiver(vdec->vf_provider_name, VFRAME_EVENT_PROVIDER_QUREY_STATE, @@ -2962,7 +2941,6 @@ hw->decode_timeout_count = 10; hw->start_process_time = jiffies; } - static void timeout_process(struct vdec_mpeg12_hw_s *hw) { struct vdec_s *vdec = hw_to_vdec(hw); @@ -2994,9 +2972,10 @@ vdec_schedule_work(&hw->timeout_work); } -static void check_timer_func(unsigned long arg) +static void check_timer_func(struct timer_list *timer) { - struct vdec_mpeg12_hw_s *hw = (struct vdec_mpeg12_hw_s *)arg; + struct vdec_mpeg12_hw_s *hw = container_of(timer, + struct vdec_mpeg12_hw_s, check_timer); struct vdec_s *vdec = hw_to_vdec(hw); unsigned int timeout_val = decode_timeout_val; @@ -3036,24 +3015,26 @@ static int vmpeg12_hw_ctx_restore(struct vdec_mpeg12_hw_s *hw) { - int index = -1; - u32 i; + u32 index = -1, i; struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx; index = find_free_buffer(hw); if (index < 0 || index >= hw->buf_num) return -1; - if (!hw->init_flag) - vmpeg12_canvas_init(hw); - else { + if (!hw->init_flag) { + if (vmpeg12_canvas_init(hw) < 0) { + debug_print(DECODE_ID(hw), 0, "vmpeg12_canvas_init failed\n"); + return -1; + } + } else { WRITE_VREG(MREG_CO_MV_START, hw->buf_start); WRITE_VREG(MREG_CC_ADDR, hw->ccbuf_phyAddress); if (!hw->is_used_v4l) { for (i = 0; i < hw->buf_num; i++) { - canvas_config_config(canvas_y(hw->canvas_spec[i]), - &hw->canvas_config[i][0]); - canvas_config_config(canvas_u(hw->canvas_spec[i]), - &hw->canvas_config[i][1]); + config_cav_lut(canvas_y(hw->canvas_spec[i]), + &hw->canvas_config[i][0], VDEC_1); + config_cav_lut(canvas_u(hw->canvas_spec[i]), + &hw->canvas_config[i][1], VDEC_1); } } } @@ -3078,6 +3059,7 @@ READ_VREG(MREG_REF1), READ_VREG(REC_CANVAS_ADDR), hw->ctx_valid, index); + /* set to mpeg1 default */ WRITE_VREG(MPEG1_2_REG, (hw->ctx_valid) ? hw->reg_mpeg1_2_reg : 0); @@ -3225,6 +3207,7 @@ hw->dec_again_cnt = 0; hw->error_frame_skip_level = error_frame_skip_level; + init_waitqueue_head(&hw->wait_q); if (dec_control) hw->dec_control = dec_control; } @@ -3272,9 +3255,10 @@ USER_DATA_SIZE); //amvdec_enable(); - init_timer(&hw->check_timer); - hw->check_timer.data = (unsigned long)hw; - hw->check_timer.function = check_timer_func; + timer_setup(&hw->check_timer, check_timer_func, 0); + //init_timer(&hw->check_timer); + //hw->check_timer.data = (unsigned long)hw; + //hw->check_timer.function = check_timer_func; hw->check_timer.expires = jiffies + CHECK_INTERVAL; hw->stat |= STAT_TIMER_ARM; @@ -3286,13 +3270,6 @@ return 0; } -#ifdef VDEC_FCC_SUPPORT -static void vmmpeg2_wakeup_fcc_poll(struct vdec_s *vdec) -{ - amstream_wakeup_fcc_poll(vdec); -} -#endif - static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) { struct vdec_mpeg12_hw_s *hw = @@ -3306,6 +3283,7 @@ "mpeg12 work pending,not ready for run.\n"); return 0; } + hw->timeout_processing = 0; if (vdec_stream_based(vdec) && (hw->init_flag == 0) && pre_decode_buf_level != 0) { u32 rp, wp, level; @@ -3363,17 +3341,10 @@ } if (!is_enough_free_buffer(hw)) { + hw->not_run_ready++; hw->buffer_not_ready++; return 0; } - -#ifdef VDEC_FCC_SUPPORT - if (!vdec_has_get_fcc_new_msg(vdec)) { - hw->buffer_not_ready++; - return 0; - } -#endif - hw->not_run_ready = 0; hw->buffer_not_ready = 0; if (vdec->parallel_dec == 1) @@ -3420,6 +3391,7 @@ if (level > (vdec->input.size / 2)) hw->dec_again_cnt++; + if (hw->dec_again_cnt > dirty_again_threshold) { debug_print(DECODE_ID(hw), 0, "mpeg12 data skipped %x\n", level); hw->dec_again_cnt = 0; @@ -3437,6 +3409,8 @@ (struct vdec_mpeg12_hw_s *)vdec->private; int save_reg; int size, ret; + + hw->run_flag = 1; if (!hw->vdec_pg_enable_flag) { hw->vdec_pg_enable_flag = 1; amvdec_enable(); @@ -3467,6 +3441,7 @@ debug_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, "vdec_prepare_input: Insufficient data\n"); vdec_schedule_work(&hw->work); + hw->run_flag = 0; return; } @@ -3495,8 +3470,8 @@ u8 *data = NULL; if (hw->chunk) debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW, - "run: chunk offset 0x%x, size %d, pts %d, pts64 %lld\n", - hw->chunk->offset, hw->chunk->size, hw->chunk->pts, hw->chunk->pts64); + "run: chunk offset 0x%x, size %d\n", + hw->chunk->offset, hw->chunk->size); if (!hw->chunk->block->is_mapped) data = codec_mm_vmap(hw->chunk->block->start + @@ -3557,6 +3532,7 @@ hw->fw->name, tee_enabled() ? "TEE" : "local", ret); hw->dec_result = DEC_RESULT_FORCE_EXIT; vdec_schedule_work(&hw->work); + hw->run_flag = 0; return; } vdec->mc_loaded = 1; @@ -3567,7 +3543,7 @@ hw->dec_result = DEC_RESULT_ERROR; debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR, "ammvdec_mpeg12: error HW context restore\n"); - vdec_schedule_work(&hw->work); + hw->run_flag = 0; return; } /*wmb();*/ @@ -3580,14 +3556,29 @@ vdec->mvfrm->hw_decode_start = local_clock(); amvdec_start(); hw->stat |= STAT_VDEC_RUN; + hw->stat |= STAT_TIMER_ARM; hw->init_flag = 1; - - mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL); + if (hw->mm_blk_handle) + mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL); + hw->run_flag = 0; } static void reset(struct vdec_s *vdec) { + struct vdec_mpeg12_hw_s *hw = (struct vdec_mpeg12_hw_s *)vdec->private; + pr_info("ammvdec_mpeg12: reset.\n"); + + vmpeg12_local_init(hw); + + if (hw->is_used_v4l) { + u32 i, buf_num = vmpeg12_get_buf_num(hw); + for (i = 0; i < buf_num; i++) { + hw->pics[i].v4l_ref_buf_addr = 0; + } + } + + hw->ctx_valid = 0; } static int vmpeg12_set_trickmode(struct vdec_s *vdec, unsigned long trickmode) @@ -3643,9 +3634,6 @@ pdata->reset_userdata_fifo = vmmpeg2_reset_userdata_fifo; pdata->wakeup_userdata_poll = vmmpeg2_wakeup_userdata_poll; -#ifdef VDEC_FCC_SUPPORT - pdata->wakeup_fcc_poll = vmmpeg2_wakeup_fcc_poll; -#endif snprintf(hw->vdec_name, sizeof(hw->vdec_name), "mpeg12-%d", pdev->id); snprintf(hw->pts_name, sizeof(hw->pts_name), @@ -3738,7 +3726,6 @@ vdec_core_request(pdata, CORE_MASK_VDEC_1 | CORE_MASK_HEVC | CORE_MASK_COMBINE); } - hw->last_frame_offset = 0xFFFFFFFF; #ifdef DUMP_USER_DATA amvdec_mmpeg12_init_userdata_dump(hw); reset_user_data_buf(hw); @@ -3757,6 +3744,17 @@ struct vdec_s *vdec = hw_to_vdec(hw); int i; + if (vdec->next_status == VDEC_STATUS_DISCONNECTED + && (vdec->status == VDEC_STATUS_ACTIVE)) { + debug_print(DECODE_ID(hw), 0, + "%s, force exit %d\n", __func__, __LINE__); + hw->dec_result = DEC_RESULT_FORCE_EXIT; + vdec_schedule_work(&hw->work); + wait_event_interruptible_timeout(hw->wait_q, + (vdec->status == VDEC_STATUS_CONNECTED), + msecs_to_jiffies(1000)); /* wait for work done */ + } + if (hw->stat & STAT_VDEC_RUN) { amvdec_stop(); hw->stat &= ~STAT_VDEC_RUN; @@ -3777,8 +3775,12 @@ cancel_work_sync(&hw->timeout_work); if (hw->mm_blk_handle) { - decoder_bmmu_box_free(hw->mm_blk_handle); + void *bmmu_box_tmp = hw->mm_blk_handle; hw->mm_blk_handle = NULL; + while (hw->run_flag) + usleep_range(1000, 2000); + decoder_bmmu_box_free(bmmu_box_tmp); + bmmu_box_tmp = NULL; } if (vdec->parallel_dec == 1) vdec_core_release(hw_to_vdec(hw), CORE_MASK_VDEC_1); @@ -3823,38 +3825,22 @@ } /****************************************/ -#ifdef CONFIG_PM -static int mmpeg12_suspend(struct device *dev) -{ - amvdec_suspend(to_platform_device(dev), dev->power.power_state); - return 0; -} - -static int mmpeg12_resume(struct device *dev) -{ - amvdec_resume(to_platform_device(dev)); - return 0; -} - -static const struct dev_pm_ops mmpeg12_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(mmpeg12_suspend, mmpeg12_resume) -}; -#endif static struct platform_driver ammvdec_mpeg12_driver = { .probe = ammvdec_mpeg12_probe, .remove = ammvdec_mpeg12_remove, +#ifdef CONFIG_PM + .suspend = amvdec_suspend, + .resume = amvdec_resume, +#endif .driver = { .name = DRIVER_NAME, -#ifdef CONFIG_PM - .pm = &mmpeg12_pm_ops, -#endif } }; static struct codec_profile_t ammvdec_mpeg12_profile = { .name = "mmpeg12", - .profile = "" + .profile = "v4l" }; static struct mconfig mmpeg12_configs[] = { @@ -3886,6 +3872,7 @@ vcodec_profile_register(&ammvdec_mpeg12_profile); INIT_REG_NODE_CONFIGS("media.decoder", &mmpeg12_node, "mmpeg12", mmpeg12_configs, CONFIG_FOR_RW); + vcodec_feature_register(VFORMAT_MPEG12, 0); return 0; }
diff --git a/drivers/frame_provider/decoder/mpeg4/vmpeg4.c b/drivers/frame_provider/decoder/mpeg4/vmpeg4.c index b13ca9c..7d33a75 100644 --- a/drivers/frame_provider/decoder/mpeg4/vmpeg4.c +++ b/drivers/frame_provider/decoder/mpeg4/vmpeg4.c
@@ -26,12 +26,10 @@ #include <linux/dma-mapping.h> #include <linux/amlogic/media/utils/amstream.h> #include <linux/amlogic/media/frame_sync/ptsserv.h> - #include <linux/amlogic/media/vfm/vframe.h> #include <linux/amlogic/media/vfm/vframe_provider.h> #include <linux/amlogic/media/vfm/vframe_receiver.h> #include <linux/amlogic/media/canvas/canvas.h> - #include <linux/amlogic/media/utils/vdec_reg.h> #include "vmpeg4.h" #include <linux/amlogic/media/registers/register.h> @@ -40,10 +38,12 @@ #include "../utils/decoder_bmmu_box.h" #include <linux/amlogic/media/codec_mm/codec_mm.h> #include <linux/amlogic/media/codec_mm/configs.h> -#include <linux/amlogic/tee.h> +//#include <linux/amlogic/tee.h> +#include <uapi/linux/tee.h> #include "../../../common/chips/decoder_cpu_ver_info.h" + /* #define CONFIG_AM_VDEC_MPEG4_LOG */ #ifdef CONFIG_AM_VDEC_MPEG4_LOG #define AMLOG @@ -182,7 +182,6 @@ static struct work_struct notify_work; static struct work_struct set_clk_work; static bool is_reset; -static bool first_i_frame_ready; static DEFINE_SPINLOCK(lock); @@ -436,8 +435,8 @@ pts += vop_time_inc_since_last_anch * PTS_UNIT / rate; - pts_us64 += (u64)(vop_time_inc_since_last_anch * - PTS_UNIT / rate) * 100 / 9; + pts_us64 += div_u64((u64)(vop_time_inc_since_last_anch * + PTS_UNIT / rate) * 100, 9); if (vop_time_inc_since_last_anch > (1 << 14)) { /* avoid overflow */ @@ -463,11 +462,6 @@ } } - if ( (first_i_frame_ready == 0) && - (picture_type == I_PICTURE)) { - first_i_frame_ready = 1; - } - if (reg & INTERLACE_FLAG) { /* interlace */ if (kfifo_get(&newframe_q, &vf) == 0) { printk @@ -498,23 +492,17 @@ set_aspect_ratio(vf, READ_VREG(MP4_PIC_RATIO)); vfbuf_use[buffer_index]++; - - if (first_i_frame_ready == 0) { - kfifo_put(&recycle_q, (const struct vframe_s *)vf); - } else { - vf->mem_handle = - decoder_bmmu_box_get_mem_handle( + vf->mem_handle = + decoder_bmmu_box_get_mem_handle( mm_blk_handle, buffer_index); - kfifo_put(&display_q, (const struct vframe_s *)vf); - ATRACE_COUNTER(MODULE_NAME, vf->pts); + kfifo_put(&display_q, (const struct vframe_s *)vf); + ATRACE_COUNTER(MODULE_NAME, vf->pts); - vf_notify_receiver(PROVIDER_NAME, - VFRAME_EVENT_PROVIDER_VFRAME_READY, - NULL); - - } + vf_notify_receiver(PROVIDER_NAME, + VFRAME_EVENT_PROVIDER_VFRAME_READY, + NULL); if (kfifo_get(&newframe_q, &vf) == 0) { printk( @@ -545,29 +533,23 @@ set_aspect_ratio(vf, READ_VREG(MP4_PIC_RATIO)); + vfbuf_use[buffer_index]++; + vf->mem_handle = + decoder_bmmu_box_get_mem_handle( + mm_blk_handle, + buffer_index); + amlog_mask(LOG_MASK_PTS, "[%s:%d] [inte] dur=0x%x rate=%d picture_type=%d\n", __func__, __LINE__, vf->duration, vmpeg4_amstream_dec_info.rate, picture_type); - vfbuf_use[buffer_index]++; + kfifo_put(&display_q, (const struct vframe_s *)vf); + ATRACE_COUNTER(MODULE_NAME, vf->pts); - if (first_i_frame_ready == 0) { - kfifo_put(&recycle_q, (const struct vframe_s *)vf); - } else { - vf->mem_handle = - decoder_bmmu_box_get_mem_handle( - mm_blk_handle, - buffer_index); - - kfifo_put(&display_q, (const struct vframe_s *)vf); - ATRACE_COUNTER(MODULE_NAME, vf->pts); - - vf_notify_receiver(PROVIDER_NAME, - VFRAME_EVENT_PROVIDER_VFRAME_READY, + vf_notify_receiver(PROVIDER_NAME, + VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); - } - } else { /* progressive */ if (kfifo_get(&newframe_q, &vf) == 0) { @@ -604,25 +586,18 @@ __func__, __LINE__, vf->duration, vmpeg4_amstream_dec_info.rate, picture_type); - vfbuf_use[buffer_index]++; - - if (first_i_frame_ready == 0) { - kfifo_put(&recycle_q, (const struct vframe_s *)vf); - } else { - vf->mem_handle = + vf->mem_handle = decoder_bmmu_box_get_mem_handle( - mm_blk_handle, - buffer_index); + mm_blk_handle, + buffer_index); - kfifo_put(&display_q, (const struct vframe_s *)vf); - ATRACE_COUNTER(MODULE_NAME, vf->pts); + kfifo_put(&display_q, (const struct vframe_s *)vf); + ATRACE_COUNTER(MODULE_NAME, vf->pts); - vf_notify_receiver(PROVIDER_NAME, - VFRAME_EVENT_PROVIDER_VFRAME_READY, - NULL); - } - + vf_notify_receiver(PROVIDER_NAME, + VFRAME_EVENT_PROVIDER_VFRAME_READY, + NULL); } total_frame += repeat_cnt + 1; @@ -750,10 +725,8 @@ frame_width, frame_height, fps); } -static void vmpeg_put_timer_func(unsigned long arg) +static void vmpeg_put_timer_func(struct timer_list *timer) { - struct timer_list *timer = (struct timer_list *)arg; - while (!kfifo_is_empty(&recycle_q) && (READ_VREG(MREG_BUFFERIN) == 0)) { struct vframe_s *vf; @@ -769,7 +742,7 @@ if (frame_dur > 0 && saved_resolution != frame_width * frame_height * (96000 / frame_dur)) - schedule_work(&set_clk_work); + schedule_work(&set_clk_work); if (READ_VREG(AV_SCRATCH_L)) { pr_info("mpeg4 fatal error happened,need reset !!\n"); @@ -899,30 +872,30 @@ #ifdef NV21 - canvas_config(2 * i + 0, + config_cav_lut_ex(2 * i + 0, buf_start, canvas_width, canvas_height, - CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); - canvas_config(2 * i + 1, + CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32, 0, VDEC_1); + config_cav_lut_ex(2 * i + 1, buf_start + decbuf_y_size, canvas_width, canvas_height / 2, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_32X32); + CANVAS_BLKMODE_32X32, 0, VDEC_1); #else - canvas_config(3 * i + 0, + config_cav_lut_ex(3 * i + 0, buf_start, canvas_width, canvas_height, - CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); - canvas_config(3 * i + 1, + CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32, 0, VDEC_1); + config_cav_lut_ex(3 * i + 1, buf_start + decbuf_y_size, canvas_width / 2, canvas_height / 2, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_32X32); - canvas_config(3 * i + 2, + CANVAS_BLKMODE_32X32, 0, VDEC_1); + config_cav_lut_ex(3 * i + 2, buf_start + decbuf_y_size + decbuf_uv_size, canvas_width / 2, canvas_height / 2, - CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); + CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32, 0, VDEC_1); #endif } @@ -1024,7 +997,6 @@ frame_num_since_last_anch = 0; - first_i_frame_ready = 0; #ifdef CONFIG_AM_VDEC_MPEG4_LOG pts_hit = pts_missed = pts_i_hit = pts_i_missed = 0; #endif @@ -1101,7 +1073,7 @@ stat |= STAT_MC_LOAD; query_video_status(0, &trickmode_fffb); - init_timer(&recycle_timer); + timer_setup(&recycle_timer, vmpeg_put_timer_func, 0); stat |= STAT_TIMER_INIT; if (vdec_request_irq(VDEC_IRQ_1, vmpeg4_isr, @@ -1146,10 +1118,7 @@ stat |= STAT_VF_HOOK; - recycle_timer.data = (ulong)&recycle_timer; - recycle_timer.function = vmpeg_put_timer_func; recycle_timer.expires = jiffies + PUT_INTERVAL; - add_timer(&recycle_timer); stat |= STAT_TIMER_ARM; @@ -1256,32 +1225,16 @@ } /****************************************/ -#ifdef CONFIG_PM -static int mpeg4_suspend(struct device *dev) -{ - amvdec_suspend(to_platform_device(dev), dev->power.power_state); - return 0; -} - -static int mpeg4_resume(struct device *dev) -{ - amvdec_resume(to_platform_device(dev)); - return 0; -} - -static const struct dev_pm_ops mpeg4_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(mpeg4_suspend, mpeg4_resume) -}; -#endif static struct platform_driver amvdec_mpeg4_driver = { .probe = amvdec_mpeg4_probe, .remove = amvdec_mpeg4_remove, +#ifdef CONFIG_PM + .suspend = amvdec_suspend, + .resume = amvdec_resume, +#endif .driver = { .name = DRIVER_NAME, -#ifdef CONFIG_PM - .pm = &mpeg4_pm_ops, -#endif } };
diff --git a/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c b/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c index 167204c..00ceb71 100644 --- a/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c +++ b/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c
@@ -24,15 +24,17 @@ #include <linux/kfifo.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> +#include <linux/delay.h> #include <linux/amlogic/media/utils/amstream.h> #include <linux/amlogic/media/frame_sync/ptsserv.h> - #include <linux/amlogic/media/vfm/vframe.h> #include <linux/amlogic/media/vfm/vframe_provider.h> #include <linux/amlogic/media/vfm/vframe_receiver.h> #include <linux/amlogic/media/canvas/canvas.h> #include <linux/amlogic/media/codec_mm/codec_mm.h> -#include <linux/amlogic/tee.h> +//#include <linux/amlogic/tee.h> +#include <uapi/linux/tee.h> +#include <linux/sched/clock.h> #include <linux/amlogic/media/utils/vdec_reg.h> #include <linux/amlogic/media/registers/register.h> #include "../../../stream_input/amports/amports_priv.h" @@ -47,8 +49,8 @@ #include "../utils/firmware.h" #include "../utils/vdec_v4l2_buffer_ops.h" #include "../utils/config_parser.h" -#include "../../../common/chips/decoder_cpu_ver_info.h" #include <media/v4l2-mem2mem.h> +#include "../utils/vdec_feature.h" #define DRIVER_NAME "ammvdec_mpeg4" @@ -185,14 +187,19 @@ if (((debug_enable & debug_flag) && ((1 << index) & mpeg4_debug_mask)) || (debug_flag == PRINT_FLAG_ERROR)) { - unsigned char buf[512]; + unsigned char *buf = kzalloc(512, GFP_ATOMIC); int len = 0; va_list args; + + if (!buf) + return 0; + va_start(args, fmt); len = sprintf(buf, "%d: ", index); vsnprintf(buf + len, 512-len, fmt, args); pr_info("%s", buf); va_end(args); + kfree(buf); } return 0; } @@ -209,6 +216,7 @@ ulong v4l_ref_buf_addr; u32 hw_decode_time; u32 frame_size; // For frame base mode; + u64 timestamp; u32 offset; u32 height; u32 width; @@ -321,6 +329,8 @@ int sidebind_type; int sidebind_channel_id; u32 res_ch_flag; + u32 profile_idc; + u32 level_idc; unsigned int i_decoded_frames; unsigned int i_lost_frames; unsigned int i_concealed_frames; @@ -330,13 +340,13 @@ unsigned int b_decoded_frames; unsigned int b_lost_frames; unsigned int b_concealed_frames; - u32 profile_idc; - u32 level_idc; int vdec_pg_enable_flag; + ulong fb_token; char vdec_name[32]; char pts_name[32]; char new_q_name[32]; char disp_q_name[32]; + bool run_flag; }; static void vmpeg4_local_init(struct vdec_mpeg4_hw_s *hw); static int vmpeg4_hw_ctx_restore(struct vdec_mpeg4_hw_s *hw); @@ -371,7 +381,6 @@ static void reset_process_time(struct vdec_mpeg4_hw_s *hw); - static int vmpeg4_get_buf_num(struct vdec_mpeg4_hw_s *hw) { int buf_num = DECODE_BUFFER_NUM_DEF; @@ -395,10 +404,16 @@ struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx); - if (hw->pic[i].v4l_ref_buf_addr) - return 0; + if (hw->pic[i].v4l_ref_buf_addr) { + struct vdec_v4l2_buffer *fb = + (struct vdec_v4l2_buffer *) + hw->pic[i].v4l_ref_buf_addr; - ret = vdec_v4l_get_buffer(hw->v4l2_ctx, &fb); + fb->status = FB_ST_DECODER; + return 0; + } + + ret = ctx->fb_ops.alloc(&ctx->fb_ops, hw->fb_token, &fb, AML_FB_REQ_DEC); if (ret < 0) { mmpeg4_debug_print(DECODE_ID(hw), 0, "[%d] get fb fail.\n", @@ -407,6 +422,8 @@ return ret; } + fb->status = FB_ST_DECODER; + if (!hw->frame_width || !hw->frame_height) { struct vdec_pic_info pic; vdec_v4l_get_pic_info(ctx, &pic); @@ -437,8 +454,8 @@ fb->m.mem[1].bytes_used = decbuf_uv_size; } - mmpeg4_debug_print(DECODE_ID(hw), 0, "[%d] %s(), v4l ref buf addr: 0x%px\n", - ctx->id, __func__, fb); + mmpeg4_debug_print(DECODE_ID(hw), 0, "[%d] %s(), v4l ref buf addr: 0x%x\n", + ((struct aml_vcodec_ctx *)(hw->v4l2_ctx))->id, __func__, fb); if (vdec->parallel_dec == 1) { u32 tmp; @@ -467,8 +484,11 @@ hw->canvas_config[i][0].endian = 7; else hw->canvas_config[i][0].endian = 0; - canvas_config_config(canvas_y(canvas), - &hw->canvas_config[i][0]); + config_cav_lut(canvas_y(canvas), + &hw->canvas_config[i][0], VDEC_1); + /* mpeg4 decoder canvas need to be revert to match display canvas */ + hw->canvas_config[i][0].endian = + (hw->blkmode != CANVAS_BLKMODE_LINEAR) ? 7 : 0; hw->canvas_config[i][1].phy_addr = decbuf_uv_start; @@ -479,8 +499,11 @@ hw->canvas_config[i][1].endian = 7; else hw->canvas_config[i][1].endian = 0; - canvas_config_config(canvas_u(canvas), - &hw->canvas_config[i][1]); + config_cav_lut(canvas_u(canvas), + &hw->canvas_config[i][1], VDEC_1); + /* mpeg4 decoder canvas need to be revert to match display canvas */ + hw->canvas_config[i][1].endian = + (hw->blkmode != CANVAS_BLKMODE_LINEAR) ? 7 : 0; return 0; } @@ -514,14 +537,16 @@ (struct aml_vcodec_ctx *)(hw->v4l2_ctx); if (ctx->param_sets_from_ucode && !hw->v4l_params_parsed) { /*run to parser csd data*/ - i = 0; + i = 0xffffff; } else { + if (!ctx->fb_ops.query(&ctx->fb_ops, &hw->fb_token)) + return -1; + if (vmpeg4_v4l_alloc_buff_config_canvas(hw, i)) return -1; } } - return i; } @@ -689,6 +714,7 @@ struct vframe_s *vf = NULL; struct vdec_s *vdec = hw_to_vdec(hw); struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx; + struct vdec_v4l2_buffer *fb = NULL; ulong nv_order = VIDTYPE_VIU_NV21; int index = pic->index; bool pb_skip = false; @@ -699,6 +725,8 @@ if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12) || (v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12M)) nv_order = VIDTYPE_VIU_NV12; + if (vdec->prog_only) + pic->pic_info &= ~INTERLACE_FLAG; } if (hw->i_only) @@ -714,6 +742,7 @@ if (hw->is_used_v4l) { vf->v4l_mem_handle = hw->pic[index].v4l_ref_buf_addr; + fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL, "[%d] %s(), v4l mem handle: 0x%lx\n", ((struct aml_vcodec_ctx *)(hw->v4l2_ctx))->id, @@ -728,6 +757,7 @@ vf->orientation = hw->vmpeg4_rotation; vf->pts = pic->pts; vf->pts_us64 = pic->pts64; + vf->timestamp = pic->timestamp; vf->duration = pic->duration >> 1; vf->duration_pulldown = 0; vf->type = (pic->pic_info & TOP_FIELD_FIRST_FLAG) ? @@ -741,7 +771,6 @@ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEINFO, "field0: pts %d, pts64 %lld, w %d, h %d, dur %d\n", vf->pts, vf->pts_us64, vf->width, vf->height, vf->duration); - if (vdec_stream_based(vdec) && (!vdec->vbuf.use_ptsserv)) { vf->pts_us64 = (((u64)vf->duration << 32) & @@ -779,11 +808,20 @@ hw->b_decoded_frames++; } if (without_display_mode == 0) { - vf_notify_receiver(vdec->vf_provider_name, - VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + if (hw->is_used_v4l) { + if (v4l2_ctx->is_stream_off) { + vmpeg_vf_put(vmpeg_vf_get(vdec), vdec); + } else { + fb->task->submit(fb->task, TASK_TYPE_DEC); + } + } else { + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + } } else vmpeg_vf_put(vmpeg_vf_get(vdec), vdec); } + if (kfifo_get(&hw->newframe_q, &vf) == 0) { mmpeg4_debug_print(DECODE_ID(hw), 0, "error, no available buf.\n"); @@ -791,16 +829,6 @@ return -1; } - if (hw->is_used_v4l) { - vf->v4l_mem_handle - = hw->pic[index].v4l_ref_buf_addr; - mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL, - "[%d] %s(), v4l mem handle: 0x%lx\n", - ((struct aml_vcodec_ctx *)(hw->v4l2_ctx))->id, - __func__, vf->v4l_mem_handle); - } - - vf->index = pic->index; vf->width = pic->width; vf->height = pic->height; @@ -809,6 +837,7 @@ vf->orientation = hw->vmpeg4_rotation; vf->pts = 0; vf->pts_us64 = 0; + vf->timestamp = 0; vf->duration = pic->duration >> 1; vf->duration_pulldown = 0; vf->type = (pic->pic_info & TOP_FIELD_FIRST_FLAG) ? @@ -827,7 +856,6 @@ vf->pts_us64 = (u64)-1; vf->pts = 0; } - if (((hw->first_i_frame_ready == 0) || pb_skip) && (pic->pic_type != I_PICTURE)) { hw->drop_frame_count++; @@ -862,8 +890,16 @@ hw->b_decoded_frames++; } if (without_display_mode == 0) { - vf_notify_receiver(vdec->vf_provider_name, - VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + if (hw->is_used_v4l) { + if (v4l2_ctx->is_stream_off) { + vmpeg_vf_put(vmpeg_vf_get(vdec), vdec); + } else { + fb->task->submit(fb->task, TASK_TYPE_DEC); + } + } else { + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + } } else vmpeg_vf_put(vmpeg_vf_get(vdec), vdec); } @@ -875,6 +911,7 @@ hw->dec_result = DEC_RESULT_ERROR; return -1; } + if (hw->is_used_v4l) { vf->v4l_mem_handle = hw->pic[index].v4l_ref_buf_addr; @@ -892,6 +929,7 @@ vf->orientation = hw->vmpeg4_rotation; vf->pts = pic->pts; vf->pts_us64 = pic->pts64; + vf->timestamp = pic->timestamp; vf->duration = pic->duration; vf->duration_pulldown = pic->repeat_cnt * pic->duration; @@ -908,14 +946,12 @@ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEINFO, "prog: pts %d, pts64 %lld, w %d, h %d, dur %d\n", vf->pts, vf->pts_us64, vf->width, vf->height, vf->duration); - if (vdec_stream_based(vdec) && (!vdec->vbuf.use_ptsserv)) { vf->pts_us64 = (((u64)vf->duration << 32) & 0xffffffff00000000) | pic->offset; vf->pts = 0; } - if (((hw->first_i_frame_ready == 0) || pb_skip) && (pic->pic_type != I_PICTURE)) { hw->drop_frame_count++; @@ -956,8 +992,16 @@ vdec_fill_vdec_frame(vdec, NULL, &vinfo, vf, pic->hw_decode_time); if (without_display_mode == 0) { - vf_notify_receiver(vdec->vf_provider_name, - VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + if (hw->is_used_v4l) { + if (v4l2_ctx->is_stream_off) { + vmpeg_vf_put(vmpeg_vf_get(vdec), vdec); + } else { + fb->task->submit(fb->task, TASK_TYPE_DEC); + } + } else { + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + } } else vmpeg_vf_put(vmpeg_vf_get(vdec), vdec); } @@ -983,8 +1027,7 @@ /* reset VLD fifo for all vdec */ WRITE_VREG(DOS_SW_RESET0, (1<<5) | (1<<4) | (1<<3)); WRITE_VREG(DOS_SW_RESET0, 0); - if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SC2) - dummy = READ_RESET_REG(RESET0_REGISTER); + WRITE_VREG(POWER_CTL_VLD, 1 << 4); /* @@ -1026,19 +1069,18 @@ } } -static int vmpeg4_get_ps_info(struct vdec_mpeg4_hw_s *hw, int width, int height, int interlace, struct aml_vdec_ps_infos *ps) +static int vmpeg4_get_ps_info(struct vdec_mpeg4_hw_s *hw, int width, int height, struct aml_vdec_ps_infos *ps) { ps->visible_width = width; ps->visible_height = height; ps->coded_width = ALIGN(width, 64); ps->coded_height = ALIGN(height, 64); ps->dpb_size = hw->buf_num; - ps->field = interlace ? V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE; return 0; } -static int v4l_res_change(struct vdec_mpeg4_hw_s *hw, int width, int height, int interlace) +static int v4l_res_change(struct vdec_mpeg4_hw_s *hw, int width, int height) { struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx); @@ -1057,7 +1099,7 @@ hw->frame_width, hw->frame_height, width, height); - vmpeg4_get_ps_info(hw, width, height, interlace, &ps); + vmpeg4_get_ps_info(hw, width, height, &ps); vdec_v4l_set_ps_infos(ctx, &ps); vdec_v4l_res_ch_event(ctx); hw->v4l_params_parsed = false; @@ -1065,7 +1107,8 @@ ctx->v4l_resolution_change = 1; hw->eos = 1; flush_output(hw); - notify_v4l_eos(hw_to_vdec(hw)); + if (hw->is_used_v4l) + notify_v4l_eos(hw_to_vdec(hw)); ret = 1; } @@ -1087,7 +1130,6 @@ u32 repeat_cnt, duration = 3200; struct pic_info_t *dec_pic, *disp_pic; struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)(vdec->private); - if (hw->eos) return IRQ_HANDLED; @@ -1095,16 +1137,13 @@ if (hw->is_used_v4l) { int frame_width = READ_VREG(MP4_PIC_WH)>> 16; int frame_height = READ_VREG(MP4_PIC_WH) & 0xffff; - int interlace = (READ_VREG(MP4_PIC_RATIO) & 0x80000000) >> 31; - mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_BUFFER_DETAIL, - "interlace = %d\n", interlace); - if (!v4l_res_change(hw, frame_width, frame_height, interlace)) { + if (!v4l_res_change(hw, frame_width, frame_height)) { struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx); if (ctx->param_sets_from_ucode && !hw->v4l_params_parsed) { struct aml_vdec_ps_infos ps; - vmpeg4_get_ps_info(hw, frame_width, frame_height, interlace, &ps); + vmpeg4_get_ps_info(hw, frame_width, frame_height, &ps); hw->v4l_params_parsed = true; vdec_v4l_set_ps_infos(ctx, &ps); reset_process_time(hw); @@ -1123,6 +1162,14 @@ return IRQ_HANDLED; } + if ((hw->is_used_v4l) && !hw->v4l_params_parsed) { + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL, + "The head was not found, can not to decode\n"); + hw->dec_result = DEC_RESULT_DONE; + vdec_schedule_work(&hw->work); + return IRQ_HANDLED; + } + WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); if (READ_VREG(AV_SCRATCH_M) != 0 && (debug_enable & PRINT_FLAG_UCODE_DETAIL)) { @@ -1220,6 +1267,7 @@ dec_pic->pts_valid = false; dec_pic->pts = 0; dec_pic->pts64 = 0; + dec_pic->timestamp = 0; mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_BUFFER_DETAIL, "new pic: index=%d, used=%d, repeat=%d, time_inc=%d\n", index, hw->vfbuf_use[index], repeat_cnt, vop_time_inc); @@ -1234,6 +1282,7 @@ hw->frame_height = dec_h; dec_pic->height = dec_h; } + hw->res_ch_flag = 0; if (hw->vmpeg4_amstream_dec_info.rate == 0) { if (vop_time_inc < hw->last_vop_time_inc) { @@ -1278,6 +1327,7 @@ dec_pic->pts_valid = hw->chunk->pts_valid; dec_pic->pts = hw->chunk->pts; dec_pic->pts64 = hw->chunk->pts64; + dec_pic->timestamp = hw->chunk->timestamp; if ((B_PICTURE == picture_type) || (hw->last_dec_pts == dec_pic->pts)) dec_pic->pts_valid = 0; @@ -1290,6 +1340,7 @@ dec_pic->pts_valid = hw->chunk->pts_valid; dec_pic->pts = hw->chunk->pts; dec_pic->pts64 = hw->chunk->pts64; + dec_pic->timestamp = hw->chunk->timestamp; } else { dec_pic->offset = offset; if ((vdec->vbuf.no_parser == 0) || (vdec->vbuf.use_ptsserv)) { @@ -1317,10 +1368,11 @@ dec_pic->duration = duration; hw->vfbuf_use[index] = 0; mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW, - "mmpeg4: pic_num: %d, index %d, type %c, pts %x, pts64 %lld, height %d, width %d\n", + "mmpeg4: pic_num: %d, index %d, type %c, pts %x\n", hw->frame_num, index, GET_PIC_TYPE(picture_type), - dec_pic->pts, dec_pic->pts64, dec_pic->height, dec_pic->width); + dec_pic->pts); + /* buffer management */ if ((picture_type == I_PICTURE) || (picture_type == P_PICTURE)) { @@ -1440,15 +1492,17 @@ if (!disp_pic->pts_valid) { disp_pic->pts = 0; disp_pic->pts64 = 0; + disp_pic->timestamp = 0; } } mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEINFO, - "disp: pic_type %c, pts %d(%lld), diff %d, cnt %d\n", + "disp: pic_type %c, pts %d(%lld), diff %d, cnt %d, disp_pic->timestamp %llu\n", GET_PIC_TYPE(disp_pic->pic_type), disp_pic->pts, disp_pic->pts64, disp_pic->pts - hw->last_pts, - hw->chunk_frame_count); + hw->chunk_frame_count, + disp_pic->timestamp); hw->last_pts = disp_pic->pts; hw->last_pts64 = disp_pic->pts64; hw->frame_dur = duration; @@ -1543,10 +1597,12 @@ if (hw->is_used_v4l) { index = find_free_buffer(hw); - if ((index == -1) && - vdec_v4l_get_buffer(hw->v4l2_ctx, &fb)) { - pr_err("[%d] get fb fail.\n", ctx->id); - return -1; + if ((index == -1) || (index == 0xffffff)) { + ctx->fb_ops.query(&ctx->fb_ops, &hw->fb_token); + if (ctx->fb_ops.alloc(&ctx->fb_ops, hw->fb_token, &fb, AML_FB_REQ_DEC) < 0) { + pr_err("[%d] get fb fail.\n", ctx->id); + return -1; + } } } @@ -1555,12 +1611,17 @@ vf->v4l_mem_handle = (index == -1) ? (ulong)fb : hw->pic[index].v4l_ref_buf_addr;; vf->flag = VFRAME_FLAG_EMPTY_FRAME_V4L; + fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; vdec_vframe_ready(vdec, vf); kfifo_put(&hw->display_q, (const struct vframe_s *)vf); + + if (hw->is_used_v4l) + fb->task->submit(fb->task, TASK_TYPE_DEC); + else + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); ATRACE_COUNTER(hw->pts_name, vf->pts); - vf_notify_receiver(vdec->vf_provider_name, - VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); pr_info("[%d] mpeg4 EOS notify.\n", (hw->is_used_v4l)?ctx->id:vdec->id); } @@ -1587,7 +1648,7 @@ hw->ctx_valid = 1; } else if ((hw->dec_result == DEC_RESULT_DONE) || - ((input_frame_based(&vdec->input)) && hw->chunk)) { + ((!hw->is_used_v4l) && (input_frame_based(&vdec->input)) && hw->chunk)) { if (!hw->ctx_valid) hw->ctx_valid = 1; @@ -1622,6 +1683,7 @@ hw->chunk = NULL; vdec_clean_input(vdec); flush_output(hw); + notify_v4l_eos(vdec); mmpeg4_debug_print(DECODE_ID(hw), 0, @@ -1851,25 +1913,26 @@ ret = decoder_bmmu_box_alloc_buf_phy(hw->mm_blk_handle, i, decbuf_size, DRIVER_NAME, &decbuf_start); if (ret < 0) { - pr_err("mmu alloc failed! size %d idx %d\n", + pr_err("bmmu alloc failed! size %d idx %d\n", decbuf_size, i); return ret; } - if (!vdec_secure(vdec)) { - /*init internal buf*/ - char *tmpbuf = (char *)codec_mm_phys_to_virt(decbuf_start); + } + + if (!vdec_secure(vdec)) { + /*init internal buf*/ + char *tmpbuf = (char *)codec_mm_phys_to_virt(decbuf_start); + if (tmpbuf) { + memset(tmpbuf, 0, decbuf_size); + codec_mm_dma_flush(tmpbuf, + decbuf_size, DMA_TO_DEVICE); + } else { + tmpbuf = codec_mm_vmap(decbuf_start, decbuf_size); if (tmpbuf) { memset(tmpbuf, 0, decbuf_size); codec_mm_dma_flush(tmpbuf, decbuf_size, DMA_TO_DEVICE); - } else { - tmpbuf = codec_mm_vmap(decbuf_start, decbuf_size); - if (tmpbuf) { - memset(tmpbuf, 0, decbuf_size); - codec_mm_dma_flush(tmpbuf, - decbuf_size, DMA_TO_DEVICE); - codec_mm_unmap_phyaddr(tmpbuf); - } + codec_mm_unmap_phyaddr(tmpbuf); } } } @@ -1906,8 +1969,8 @@ hw->canvas_config[i][0].endian = 7; else hw->canvas_config[i][0].endian = 0; - canvas_config_config(canvas_y(canvas), - &hw->canvas_config[i][0]); + config_cav_lut(canvas_y(canvas), + &hw->canvas_config[i][0], VDEC_1); hw->canvas_config[i][1].phy_addr = decbuf_start + decbuf_y_size; @@ -1918,8 +1981,8 @@ hw->canvas_config[i][1].endian = 7; else hw->canvas_config[i][1].endian = 0; - canvas_config_config(canvas_u(canvas), - &hw->canvas_config[i][1]); + config_cav_lut(canvas_u(canvas), + &hw->canvas_config[i][1], VDEC_1); } } @@ -1934,12 +1997,13 @@ mmpeg4_debug_print(DECODE_ID(hw), 0, "====== %s\n", __func__); mmpeg4_debug_print(DECODE_ID(hw), 0, - "width/height (%d/%d), i_fram:%d, buffer_not_ready %d, buf_num %d\n", + "width/height (%d/%d), i_fram:%d, buffer_not_ready %d, buf_num %d, run_flag %d\n", hw->frame_width, hw->frame_height, hw->first_i_frame_ready, hw->buffer_not_ready, - hw->buf_num + hw->buf_num, + hw->run_flag ); for (i = 0; i < hw->buf_num; i++) { mmpeg4_debug_print(DECODE_ID(hw), 0, @@ -1964,7 +2028,7 @@ hw->drop_frame_count ); - if (vf_get_receiver(vdec->vf_provider_name)) { + if (!hw->is_used_v4l && vf_get_receiver(vdec->vf_provider_name)) { enum receviver_start_e state = vf_notify_receiver(vdec->vf_provider_name, VFRAME_EVENT_PROVIDER_QUREY_STATE, @@ -2079,9 +2143,10 @@ } -static void check_timer_func(unsigned long arg) +static void check_timer_func(struct timer_list *timer) { - struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)arg; + struct vdec_mpeg4_hw_s *hw = container_of(timer, + struct vdec_mpeg4_hw_s, check_timer); struct vdec_s *vdec = hw_to_vdec(hw); unsigned int timeout_val = decode_timeout_val; @@ -2135,10 +2200,10 @@ } else { if (!hw->is_used_v4l) { for (i = 0; i < hw->buf_num; i++) { - canvas_config_config(canvas_y(hw->canvas_spec[i]), - &hw->canvas_config[i][0]); - canvas_config_config(canvas_u(hw->canvas_spec[i]), - &hw->canvas_config[i][1]); + config_cav_lut(canvas_y(hw->canvas_spec[i]), + &hw->canvas_config[i][0], VDEC_1); + config_cav_lut(canvas_u(hw->canvas_spec[i]), + &hw->canvas_config[i][1], VDEC_1); } } } @@ -2151,14 +2216,17 @@ WRITE_VREG(MREG_REF0, (hw->refs[1] == -1) ? 0xffffffff : hw->canvas_spec[hw->refs[1]]); } else { - WRITE_VREG(MREG_REF0, (hw->refs[0] == -1) ? 0xffffffff : - hw->canvas_spec[hw->refs[0]]); + WRITE_VREG(MREG_REF0, hw->canvas_spec[hw->refs[0]]); } WRITE_VREG(MREG_REF1, (hw->refs[1] == -1) ? 0xffffffff : hw->canvas_spec[hw->refs[1]]); - - WRITE_VREG(REC_CANVAS_ADDR, hw->canvas_spec[index]); - WRITE_VREG(ANC2_CANVAS_ADDR, hw->canvas_spec[index]); + if ((hw->is_used_v4l) && (index == 0xffffff)) { + WRITE_VREG(REC_CANVAS_ADDR, 0xffffff); + WRITE_VREG(ANC2_CANVAS_ADDR, 0xffffff); + } else { + WRITE_VREG(REC_CANVAS_ADDR, hw->canvas_spec[index]); + WRITE_VREG(ANC2_CANVAS_ADDR, hw->canvas_spec[index]); + } mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_RESTORE, "restore ref0=0x%x, ref1=0x%x, rec=0x%x, ctx_valid=%d,index=%d\n", @@ -2254,7 +2322,7 @@ hw->unstable_pts = (((unsigned long) hw->vmpeg4_amstream_dec_info.param & 0x40) >> 6); mmpeg4_debug_print(DECODE_ID(hw), 0, - "param = 0x%px unstable_pts = %d\n", + "param = 0x%x unstable_pts = %d\n", hw->vmpeg4_amstream_dec_info.param, hw->unstable_pts); hw->last_dec_pts = -1; @@ -2354,9 +2422,10 @@ //amvdec_enable(); - init_timer(&hw->check_timer); - hw->check_timer.data = (unsigned long)hw; - hw->check_timer.function = check_timer_func; + timer_setup(&hw->check_timer, check_timer_func, 0); + //init_timer(&hw->check_timer); + //hw->check_timer.data = (unsigned long)hw; + //hw->check_timer.function = check_timer_func; hw->check_timer.expires = jiffies + CHECK_INTERVAL; hw->stat |= STAT_TIMER_ARM; hw->eos = 0; @@ -2371,7 +2440,6 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) { struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)vdec->private; - if (hw->eos) return 0; if (vdec_stream_based(vdec) && (hw->init_flag == 0) @@ -2451,6 +2519,8 @@ { struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)vdec->private; int size = 0, ret = 0; + + hw->run_flag = 1; if (!hw->vdec_pg_enable_flag) { hw->vdec_pg_enable_flag = 1; amvdec_enable(); @@ -2470,6 +2540,7 @@ hw->input_empty++; hw->dec_result = DEC_RESULT_AGAIN; vdec_schedule_work(&hw->work); + hw->run_flag = 0; return; } if ((vdec_frame_based(vdec)) && @@ -2496,10 +2567,10 @@ if (!hw->chunk->block->is_mapped) data = codec_mm_vmap(hw->chunk->block->start + - hw->chunk->offset, size); + hw->chunk_offset, size); else data = ((u8 *)hw->chunk->block->start_virt) + - hw->chunk->offset; + hw->chunk_offset; mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, "%s: size 0x%x sum 0x%x %02x %02x %02x %02x %02x %02x .. %02x %02x %02x %02x\n", @@ -2554,6 +2625,7 @@ hw->fw->name, tee_enabled() ? "TEE" : "local", ret); hw->dec_result = DEC_RESULT_FORCE_EXIT; vdec_schedule_work(&hw->work); + hw->run_flag = 0; return; } vdec->mc_loaded = 1; @@ -2563,7 +2635,7 @@ hw->dec_result = DEC_RESULT_ERROR; mmpeg4_debug_print(DECODE_ID(hw), 0, "amvdec_mpeg4: error HW context restore\n"); - vdec_schedule_work(&hw->work); + hw->run_flag = 0; return; } if (vdec_frame_based(vdec)) { @@ -2584,8 +2656,10 @@ vdec->mvfrm->hw_decode_start = local_clock(); amvdec_start(); hw->stat |= STAT_VDEC_RUN; + hw->stat |= STAT_TIMER_ARM; hw->init_flag = 1; mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL); + hw->run_flag = 0; } static int vmpeg4_stop(struct vdec_mpeg4_hw_s *hw) @@ -2593,8 +2667,12 @@ cancel_work_sync(&hw->work); if (hw->mm_blk_handle) { - decoder_bmmu_box_free(hw->mm_blk_handle); - hw->mm_blk_handle = NULL; + void *bmmu_box_tmp = hw->mm_blk_handle; + hw->mm_blk_handle = NULL; + while (hw->run_flag) + usleep_range(1000, 2000); + decoder_bmmu_box_free(bmmu_box_tmp); + bmmu_box_tmp = NULL; } if (hw->stat & STAT_TIMER_ARM) { @@ -2616,6 +2694,12 @@ vmpeg4_local_init(hw); + if (hw->is_used_v4l) { + u32 i, buf_num = vmpeg4_get_buf_num(hw); + for (i = 0; i < buf_num; i++) { + hw->pic[i].v4l_ref_buf_addr = 0; + } + } hw->ctx_valid = 0; } @@ -2687,15 +2771,24 @@ platform_set_drvdata(pdev, pdata); hw->platform_dev = pdev; + if (((debug_enable & IGNORE_PARAM_FROM_CONFIG) == 0) && pdata->config_len) { + mmpeg4_debug_print(DECODE_ID(hw), 0, "pdata->config: %s\n", pdata->config); + if (get_config_int(pdata->config, "parm_v4l_buffer_margin", + &config_val) == 0) + hw->dynamic_buf_num_margin = config_val; + else + hw->dynamic_buf_num_margin = dynamic_buf_num_margin; + } else { + hw->dynamic_buf_num_margin = dynamic_buf_num_margin; + } + hw->buf_num = vmpeg4_get_buf_num(hw); + if (pdata->parallel_dec == 1) { int i; for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) hw->canvas_spec[i] = 0xffffff; } - vf_provider_init(&pdata->vframe_provider, - pdata->vf_provider_name, &vf_provider_ops, pdata); - hw->blkmode = pdata->canvas_mode; if (pdata->sys_info) { @@ -2717,7 +2810,6 @@ hw->vmpeg4_amstream_dec_info.height, hw->vmpeg4_amstream_dec_info.rate); } - if (((debug_enable & IGNORE_PARAM_FROM_CONFIG) == 0) && pdata->config_len) { mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW, "pdata->config: %s\n", pdata->config); @@ -2747,6 +2839,10 @@ } else hw->dynamic_buf_num_margin = dynamic_buf_num_margin; + if (!hw->is_used_v4l) + vf_provider_init(&pdata->vframe_provider, + pdata->vf_provider_name, &vf_provider_ops, pdata); + hw->buf_num = vmpeg4_get_buf_num(hw); if (vmmpeg4_init(hw) < 0) { @@ -2817,38 +2913,22 @@ } /****************************************/ -#ifdef CONFIG_PM -static int mmpeg4_suspend(struct device *dev) -{ - amvdec_suspend(to_platform_device(dev), dev->power.power_state); - return 0; -} - -static int mmpeg4_resume(struct device *dev) -{ - amvdec_resume(to_platform_device(dev)); - return 0; -} - -static const struct dev_pm_ops mmpeg4_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(mmpeg4_suspend, mmpeg4_resume) -}; -#endif static struct platform_driver ammvdec_mpeg4_driver = { .probe = ammvdec_mpeg4_probe, .remove = ammvdec_mpeg4_remove, +#ifdef CONFIG_PM + .suspend = amvdec_suspend, + .resume = amvdec_resume, +#endif .driver = { .name = DRIVER_NAME, -#ifdef CONFIG_PM - .pm = &mmpeg4_pm_ops, -#endif } }; static struct codec_profile_t amvdec_mpeg4_profile = { .name = "mmpeg4", - .profile = "" + .profile = "v4l, no_single" }; static int __init ammvdec_mpeg4_driver_init_module(void) @@ -2860,6 +2940,7 @@ return -ENODEV; } vcodec_profile_register(&amvdec_mpeg4_profile); + vcodec_feature_register(VFORMAT_MPEG4, 0); return 0; }
diff --git a/drivers/frame_provider/decoder/real/Makefile b/drivers/frame_provider/decoder/real/Makefile deleted file mode 100644 index ab03ef2..0000000 --- a/drivers/frame_provider/decoder/real/Makefile +++ /dev/null
@@ -1,2 +0,0 @@ -obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_REAL) += amvdec_real.o -amvdec_real-objs += vreal.o
diff --git a/drivers/frame_provider/decoder/real/vreal.c b/drivers/frame_provider/decoder/real/vreal.c deleted file mode 100644 index f6474b6..0000000 --- a/drivers/frame_provider/decoder/real/vreal.c +++ /dev/null
@@ -1,1069 +0,0 @@ -/* - * drivers/amlogic/amports/vreal.c - * - * Copyright (C) 2015 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/types.h> -#include <linux/errno.h> -#include <linux/interrupt.h> -#include <linux/timer.h> -#include <linux/fs.h> -#include <linux/kfifo.h> -#include <linux/platform_device.h> - -#include <linux/amlogic/media/canvas/canvas.h> - -#include <linux/dma-mapping.h> -#include <linux/amlogic/media/utils/amstream.h> -#include <linux/amlogic/media/utils/vformat.h> -#include <linux/amlogic/media/frame_sync/ptsserv.h> -#include <linux/amlogic/media/vfm/vframe.h> -#include <linux/amlogic/media/vfm/vframe_provider.h> -#include <linux/amlogic/media/vfm/vframe_receiver.h> -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/uaccess.h> -#include "../../../stream_input/amports/amports_priv.h" -#include "../utils/vdec.h" -#include <linux/amlogic/media/utils/vdec_reg.h> -#include "../utils/amvdec.h" - -#include "../../../stream_input/amports/streambuf.h" -#include "../../../stream_input/amports/streambuf_reg.h" -#include "../../../stream_input/parser/rmparser.h" - -#include "vreal.h" -#include <linux/amlogic/media/registers/register.h> -#include "../utils/decoder_mmu_box.h" -#include "../utils/decoder_bmmu_box.h" -#include <linux/amlogic/media/codec_mm/codec_mm.h> -#include <linux/amlogic/media/codec_mm/configs.h> -#include "../utils/firmware.h" -#include <linux/amlogic/tee.h> - - - -#define DRIVER_NAME "amvdec_real" -#define MODULE_NAME "amvdec_real" - -#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */ -#define NV21 -#endif - -#define RM_DEF_BUFFER_ADDR 0x01000000 -/* protocol registers */ -#define STATUS_AMRISC AV_SCRATCH_4 - -#define RV_PIC_INFO AV_SCRATCH_5 -#define VPTS_TR AV_SCRATCH_6 -#define VDTS AV_SCRATCH_7 -#define FROM_AMRISC AV_SCRATCH_8 -#define TO_AMRISC AV_SCRATCH_9 -#define SKIP_B_AMRISC AV_SCRATCH_A -#define INT_REASON AV_SCRATCH_B -#define WAIT_BUFFER AV_SCRATCH_E - -#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */ -#define MDEC_WIDTH AV_SCRATCH_I -#define MDEC_HEIGHT AV_SCRATCH_J -#else -#define MDEC_WIDTH HARM_ASB_MB2 -#define MDEC_HEIGHT HASB_ARM_MB0 -#endif - -#define PARC_FORBIDDEN 0 -#define PARC_SQUARE 1 -#define PARC_CIF 2 -#define PARC_10_11 3 -#define PARC_16_11 4 -#define PARC_40_33 5 -#define PARC_RESERVED 6 -/* values between 6 and 14 are reserved */ -#define PARC_EXTENDED 15 - -#define VF_POOL_SIZE 16 -#define VF_BUF_NUM 4 -#define PUT_INTERVAL (HZ/100) -#define WORKSPACE_SIZE (1 * SZ_1M) -#define MAX_BMMU_BUFFER_NUM (VF_BUF_NUM + 1) -#define RV_AI_BUFF_START_IP 0x01f00000 - -static struct vframe_s *vreal_vf_peek(void *); -static struct vframe_s *vreal_vf_get(void *); -static void vreal_vf_put(struct vframe_s *, void *); -static int vreal_vf_states(struct vframe_states *states, void *); -static int vreal_event_cb(int type, void *data, void *private_data); - -static int vreal_prot_init(void); -static void vreal_local_init(void); - -static const char vreal_dec_id[] = "vreal-dev"; - -#define PROVIDER_NAME "decoder.real" - -/* - *int query_video_status(int type, int *value); - */ -static const struct vframe_operations_s vreal_vf_provider = { - .peek = vreal_vf_peek, - .get = vreal_vf_get, - .put = vreal_vf_put, - .event_cb = vreal_event_cb, - .vf_states = vreal_vf_states, -}; - -static struct vframe_provider_s vreal_vf_prov; -static void *mm_blk_handle; - -static DECLARE_KFIFO(newframe_q, struct vframe_s *, VF_POOL_SIZE); -static DECLARE_KFIFO(display_q, struct vframe_s *, VF_POOL_SIZE); -static DECLARE_KFIFO(recycle_q, struct vframe_s *, VF_POOL_SIZE); - -static struct vframe_s vfpool[VF_POOL_SIZE]; -static s32 vfbuf_use[VF_BUF_NUM]; - -static u32 frame_width, frame_height, frame_dur, frame_prog; -static u32 saved_resolution; -static struct timer_list recycle_timer; -static u32 stat; -static u32 buf_size = 32 * 1024 * 1024; -static u32 buf_offset; -static u32 vreal_ratio; -u32 vreal_format; -static u32 wait_key_frame; -static u32 last_tr; -static u32 frame_count; -static u32 current_vdts; -static u32 hold; -static u32 decoder_state; -static u32 real_err_count; - -static u32 fatal_flag; -static s32 wait_buffer_counter; -static struct work_struct set_clk_work; -static bool is_reset; - -static DEFINE_SPINLOCK(lock); - -static unsigned short pic_sz_tbl[12] ____cacheline_aligned; -static dma_addr_t pic_sz_tbl_map; -static const unsigned char RPR_size[9] = { 0, 1, 1, 2, 2, 3, 3, 3, 3 }; - -static struct dec_sysinfo vreal_amstream_dec_info; - -static unsigned char aspect_ratio_table[16] = { - PARC_FORBIDDEN, - PARC_SQUARE, - PARC_CIF, - PARC_10_11, - PARC_16_11, - PARC_40_33, - PARC_RESERVED, PARC_RESERVED, PARC_RESERVED, PARC_RESERVED, - PARC_RESERVED, PARC_RESERVED, PARC_RESERVED, PARC_RESERVED, - PARC_RESERVED, PARC_EXTENDED -}; - -static inline u32 index2canvas(u32 index) -{ - const u32 canvas_tab[4] = { -#ifdef NV21 - 0x010100, 0x030302, 0x050504, 0x070706 -#else - 0x020100, 0x050403, 0x080706, 0x0b0a09 -#endif - }; - - return canvas_tab[index]; -} - -static void set_aspect_ratio(struct vframe_s *vf, unsigned int pixel_ratio) -{ - int ar = 0; - - if (vreal_ratio == 0) { - vf->ratio_control |= (0x90 << - DISP_RATIO_ASPECT_RATIO_BIT); - /* always stretch to 16:9 */ - } else { - switch (aspect_ratio_table[pixel_ratio]) { - case 0: - ar = vreal_amstream_dec_info.height * vreal_ratio / - vreal_amstream_dec_info.width; - break; - case 1: - case 0xff: - ar = vreal_ratio * vf->height / vf->width; - break; - case 2: - ar = (vreal_ratio * vf->height * 12) / (vf->width * 11); - break; - case 3: - ar = (vreal_ratio * vf->height * 11) / (vf->width * 10); - break; - case 4: - ar = (vreal_ratio * vf->height * 11) / (vf->width * 16); - break; - case 5: - ar = (vreal_ratio * vf->height * 33) / (vf->width * 40); - break; - default: - ar = vreal_ratio * vf->height / vf->width; - break; - } - } - - ar = min(ar, DISP_RATIO_ASPECT_RATIO_MAX); - - vf->ratio_control |= (ar << DISP_RATIO_ASPECT_RATIO_BIT); -} - -static irqreturn_t vreal_isr(int irq, void *dev_id) -{ - u32 from; - struct vframe_s *vf = NULL; - u32 buffer_index; - unsigned int status; - unsigned int vdts; - unsigned int info; - unsigned int tr; - unsigned int pictype; - u32 r = READ_VREG(INT_REASON); - - if (decoder_state == 0) - return IRQ_HANDLED; - - status = READ_VREG(STATUS_AMRISC); - if (status & (PARSER_ERROR_WRONG_PACKAGE_SIZE | - PARSER_ERROR_WRONG_HEAD_VER | - DECODER_ERROR_VLC_DECODE_TBL)) { - /* decoder or parser error */ - real_err_count++; - /* pr_info("real decoder or parser - *error, status 0x%x\n", status); - */ - } - - if (r == 2) { - pr_info("first vpts = 0x%x\n", READ_VREG(VDTS)); - pts_checkin_offset(PTS_TYPE_AUDIO, 0, READ_VREG(VDTS) * 90); - WRITE_VREG(AV_SCRATCH_B, 0); - WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); - return IRQ_HANDLED; - } else if (r == 3) { - pr_info("first apts = 0x%x\n", READ_VREG(VDTS)); - pts_checkin_offset(PTS_TYPE_VIDEO, 0, READ_VREG(VDTS) * 90); - WRITE_VREG(AV_SCRATCH_B, 0); - WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); - return IRQ_HANDLED; - } - - from = READ_VREG(FROM_AMRISC); - if ((hold == 0) && from) { - tr = READ_VREG(VPTS_TR); - pictype = (tr >> 13) & 3; - tr = (tr & 0x1fff) * 96; - - if (kfifo_get(&newframe_q, &vf) == 0) { - pr_info("fatal error, no available buffer slot."); - return IRQ_HANDLED; - } - - vdts = READ_VREG(VDTS); - if (last_tr == -1) /* ignore tr for first time */ - vf->duration = frame_dur; - else { - if (tr > last_tr) - vf->duration = tr - last_tr; - else - vf->duration = (96 << 13) + tr - last_tr; - - if (vf->duration > 10 * frame_dur) { - /* not a reasonable duration, - *should not happen - */ - vf->duration = frame_dur; - } -#if 0 - else { - if (check_frame_duration == 0) { - frame_dur = vf->duration; - check_frame_duration = 1; - } - } -#endif - } - - last_tr = tr; - buffer_index = from & 0x03; - - if (pictype == 0) { /* I */ - current_vdts = vdts * 90 + 1; - vf->pts = current_vdts; - if (wait_key_frame) - wait_key_frame = 0; - } else { - if (wait_key_frame) { - while (READ_VREG(TO_AMRISC)) - ; - WRITE_VREG(TO_AMRISC, ~(1 << buffer_index)); - WRITE_VREG(FROM_AMRISC, 0); - return IRQ_HANDLED; - } else { - current_vdts += - vf->duration - (vf->duration >> 4); - vf->pts = current_vdts; - } - } - - /* pr_info("pts %d, picture type %d\n", vf->pts, pictype); */ - - info = READ_VREG(RV_PIC_INFO); - vf->signal_type = 0; - vf->index = buffer_index; - vf->width = info >> 16; - vf->height = (info >> 4) & 0xfff; - vf->bufWidth = 1920; - vf->flag = 0; - vf->ratio_control = 0; - set_aspect_ratio(vf, info & 0x0f); - vf->duration_pulldown = 0; -#ifdef NV21 - vf->type = VIDTYPE_PROGRESSIVE | - VIDTYPE_VIU_FIELD | VIDTYPE_VIU_NV21; -#else - vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD; -#endif - vf->canvas0Addr = vf->canvas1Addr = index2canvas(buffer_index); - vf->orientation = 0; - vf->type_original = vf->type; - - vfbuf_use[buffer_index] = 1; - vf->mem_handle = - decoder_bmmu_box_get_mem_handle( - mm_blk_handle, - buffer_index); - - kfifo_put(&display_q, (const struct vframe_s *)vf); - ATRACE_COUNTER(MODULE_NAME, vf->pts); - - frame_count++; - vf_notify_receiver(PROVIDER_NAME, - VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); - WRITE_VREG(FROM_AMRISC, 0); - } - - WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); - - return IRQ_HANDLED; -} - -static struct vframe_s *vreal_vf_peek(void *op_arg) -{ - struct vframe_s *vf; - - if (kfifo_peek(&display_q, &vf)) - return vf; - - return NULL; -} - -static struct vframe_s *vreal_vf_get(void *op_arg) -{ - struct vframe_s *vf; - - if (kfifo_get(&display_q, &vf)) - return vf; - - return NULL; -} - -static void vreal_vf_put(struct vframe_s *vf, void *op_arg) -{ - kfifo_put(&recycle_q, (const struct vframe_s *)vf); -} - -static int vreal_event_cb(int type, void *data, void *private_data) -{ - if (type & VFRAME_EVENT_RECEIVER_RESET) { - unsigned long flags; - - amvdec_stop(); -#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER - vf_light_unreg_provider(&vreal_vf_prov); -#endif - spin_lock_irqsave(&lock, flags); - vreal_local_init(); - vreal_prot_init(); - spin_unlock_irqrestore(&lock, flags); -#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER - vf_reg_provider(&vreal_vf_prov); -#endif - amvdec_start(); - } - return 0; -} - -static int vreal_vf_states(struct vframe_states *states, void *op_arg) -{ - unsigned long flags; - - spin_lock_irqsave(&lock, flags); - - states->vf_pool_size = VF_POOL_SIZE; - states->buf_free_num = kfifo_len(&newframe_q); - states->buf_avail_num = kfifo_len(&display_q); - states->buf_recycle_num = kfifo_len(&recycle_q); - - spin_unlock_irqrestore(&lock, flags); - - return 0; -} -#if 0 -#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER -static void vreal_ppmgr_reset(void) -{ - vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_RESET, NULL); - - vreal_local_init(); - - pr_info("vrealdec: vf_ppmgr_reset\n"); -} -#endif -#endif - -static void vreal_set_clk(struct work_struct *work) -{ - if (frame_dur > 0 && - saved_resolution != - frame_width * frame_height * (96000 / frame_dur)) { - int fps = 96000 / frame_dur; - - saved_resolution = frame_width * frame_height * fps; - vdec_source_changed(VFORMAT_REAL, - frame_width, frame_height, fps); - } -} - -static void vreal_put_timer_func(unsigned long arg) -{ - struct timer_list *timer = (struct timer_list *)arg; - /* unsigned int status; */ - -#if 0 - enum receviver_start_e state = RECEIVER_INACTIVE; - - if (vf_get_receiver(PROVIDER_NAME)) { - state = - vf_notify_receiver(PROVIDER_NAME, - VFRAME_EVENT_PROVIDER_QUREY_STATE, NULL); - if ((state == RECEIVER_STATE_NULL) - || (state == RECEIVER_STATE_NONE)) { - /* receiver has no event_cb - *or receiver's event_cb does not process this event - */ - state = RECEIVER_INACTIVE; - } - } else - state = RECEIVER_INACTIVE; - - if ((READ_VREG(WAIT_BUFFER) != 0) && - kfifo_is_empty(&display_q) && - kfifo_is_empty(&recycle_q) && (state == RECEIVER_INACTIVE)) { - pr_info("$$$$$$decoder is waiting for buffer\n"); - if (++wait_buffer_counter > 2) { - amvdec_stop(); - -#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER - vreal_ppmgr_reset(); -#else - vf_light_unreg_provider(&vreal_vf_prov); - vreal_local_init(); - vf_reg_provider(&vreal_vf_prov); -#endif - vreal_prot_init(); - amvdec_start(); - } - } -#endif - - while (!kfifo_is_empty(&recycle_q) && (READ_VREG(TO_AMRISC) == 0)) { - struct vframe_s *vf; - - if (kfifo_get(&recycle_q, &vf)) { - if ((vf->index < VF_BUF_NUM) - && (--vfbuf_use[vf->index] == 0)) { - WRITE_VREG(TO_AMRISC, ~(1 << vf->index)); - vf->index = VF_BUF_NUM; - } - - kfifo_put(&newframe_q, (const struct vframe_s *)vf); - } - } - - schedule_work(&set_clk_work); - - timer->expires = jiffies + PUT_INTERVAL; - - add_timer(timer); -} - -int vreal_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus) -{ - if (!(stat & STAT_VDEC_RUN)) - return -1; - - vstatus->frame_width = vreal_amstream_dec_info.width; - vstatus->frame_height = vreal_amstream_dec_info.height; - if (0 != vreal_amstream_dec_info.rate) - vstatus->frame_rate = 96000 / vreal_amstream_dec_info.rate; - else - vstatus->frame_rate = 96000; - vstatus->error_count = real_err_count; - vstatus->status = - ((READ_VREG(STATUS_AMRISC) << 16) | fatal_flag) | stat; - /* pr_info("vreal_dec_status 0x%x\n", vstatus->status); */ - return 0; -} - -int vreal_set_isreset(struct vdec_s *vdec, int isreset) -{ - is_reset = isreset; - return 0; -} - -/****************************************/ -static int vreal_canvas_init(void) -{ - int i, ret; - unsigned long buf_start; - u32 canvas_width, canvas_height; - u32 alloc_size, decbuf_size, decbuf_y_size, decbuf_uv_size; - - if (buf_size <= 0x00400000) { - /* SD only */ - canvas_width = 768; - canvas_height = 576; - decbuf_y_size = 0x80000; - decbuf_uv_size = 0x20000; - decbuf_size = 0x100000; - } else { - /* HD & SD */ - #if 1 - int w = vreal_amstream_dec_info.width; - int h = vreal_amstream_dec_info.height; - int align_w, align_h; - int max, min; - - align_w = ALIGN(w, 64); - align_h = ALIGN(h, 64); - if (align_w > align_h) { - max = align_w; - min = align_h; - } else { - canvas_width = 1920; - canvas_height = 1088; - max = align_h; - min = align_w; - } - /* HD & SD */ - if ((max > 1920 || min > 1088) && - ALIGN(align_w * align_h * 3/2, SZ_64K) * 9 <= - buf_size) { - canvas_width = align_w; - canvas_height = align_h; - decbuf_y_size = ALIGN(align_w * align_h, SZ_64K); - decbuf_uv_size = ALIGN(align_w * align_h/4, SZ_64K); - decbuf_size = ALIGN(align_w * align_h * 3/2, SZ_64K); - } else { /*1080p*/ - if (h > w) { - canvas_width = 1088; - canvas_height = 1920; - } else { - canvas_width = 1920; - canvas_height = 1088; - } - decbuf_y_size = 0x200000; - decbuf_uv_size = 0x80000; - decbuf_size = 0x300000; - } - #endif - } - - for (i = 0; i < MAX_BMMU_BUFFER_NUM; i++) { - /* workspace mem */ - if (i == (MAX_BMMU_BUFFER_NUM - 1)) - alloc_size = WORKSPACE_SIZE; - else - alloc_size = decbuf_size; - - ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle, i, - alloc_size, DRIVER_NAME, &buf_start); - if (ret < 0) - return ret; - - if (i == (MAX_BMMU_BUFFER_NUM - 1)) { - buf_offset = buf_start - RV_AI_BUFF_START_IP; - continue; - } - -#ifdef NV21 - canvas_config(2 * i + 0, - buf_start, - canvas_width, canvas_height, - CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); - canvas_config(2 * i + 1, - buf_start + - decbuf_y_size, canvas_width, - canvas_height / 2, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_32X32); -#else - canvas_config(3 * i + 0, - buf_start, - canvas_width, canvas_height, - CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); - canvas_config(3 * i + 1, - buf_start + - decbuf_y_size, canvas_width / 2, - canvas_height / 2, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_32X32); - canvas_config(3 * i + 2, - buf_start + - decbuf_y_size + decbuf_uv_size, - canvas_width / 2, canvas_height / 2, - CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); -#endif - } - - return 0; -} - -static int vreal_prot_init(void) -{ - int r; -#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */ - WRITE_VREG(DOS_SW_RESET0, (1 << 7) | (1 << 6)); - WRITE_VREG(DOS_SW_RESET0, 0); -#else - WRITE_RESET_REG(RESET0_REGISTER, RESET_IQIDCT | RESET_MC); -#endif - - - - r = vreal_canvas_init(); - - /* index v << 16 | u << 8 | y */ -#ifdef NV21 - WRITE_VREG(AV_SCRATCH_0, 0x010100); - WRITE_VREG(AV_SCRATCH_1, 0x030302); - WRITE_VREG(AV_SCRATCH_2, 0x050504); - WRITE_VREG(AV_SCRATCH_3, 0x070706); -#else - WRITE_VREG(AV_SCRATCH_0, 0x020100); - WRITE_VREG(AV_SCRATCH_1, 0x050403); - WRITE_VREG(AV_SCRATCH_2, 0x080706); - WRITE_VREG(AV_SCRATCH_3, 0x0b0a09); -#endif - - /* notify ucode the buffer offset */ - WRITE_VREG(AV_SCRATCH_F, buf_offset); - -#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */ - WRITE_VREG(DOS_SW_RESET0, (1 << 9) | (1 << 8)); - WRITE_VREG(DOS_SW_RESET0, 0); -#else - WRITE_RESET_REG(RESET2_REGISTER, RESET_PIC_DC | RESET_DBLK); -#endif - - /* disable PSCALE for hardware sharing */ - WRITE_VREG(PSCALE_CTRL, 0); - - WRITE_VREG(FROM_AMRISC, 0); - WRITE_VREG(TO_AMRISC, 0); - WRITE_VREG(STATUS_AMRISC, 0); - - WRITE_VREG(RV_PIC_INFO, 0); - WRITE_VREG(VPTS_TR, 0); - WRITE_VREG(VDTS, 0); - WRITE_VREG(SKIP_B_AMRISC, 0); - - WRITE_VREG(MDEC_WIDTH, (frame_width + 15) & 0xfff0); - WRITE_VREG(MDEC_HEIGHT, (frame_height + 15) & 0xfff0); - - /* clear mailbox interrupt */ - WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); - - /* enable mailbox interrupt */ - WRITE_VREG(ASSIST_MBOX1_MASK, 1); - - /* clear wait buffer status */ - WRITE_VREG(WAIT_BUFFER, 0); - -#ifdef NV21 - SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17); -#endif - return r; -} - -static void vreal_local_init(void) -{ - int i; - - /* vreal_ratio = vreal_amstream_dec_info.ratio; */ - vreal_ratio = 0x100; - - frame_prog = 0; - - frame_width = vreal_amstream_dec_info.width; - frame_height = vreal_amstream_dec_info.height; - frame_dur = vreal_amstream_dec_info.rate; - - for (i = 0; i < VF_BUF_NUM; i++) - vfbuf_use[i] = 0; - - INIT_KFIFO(display_q); - INIT_KFIFO(recycle_q); - INIT_KFIFO(newframe_q); - - for (i = 0; i < VF_POOL_SIZE; i++) { - const struct vframe_s *vf = &vfpool[i]; - vfpool[i].index = VF_BUF_NUM; - kfifo_put(&newframe_q, vf); - } - - if (mm_blk_handle) { - decoder_bmmu_box_free(mm_blk_handle); - mm_blk_handle = NULL; - } - - mm_blk_handle = decoder_bmmu_box_alloc_box( - DRIVER_NAME, - 0, - MAX_BMMU_BUFFER_NUM, - 4 + PAGE_SHIFT, - CODEC_MM_FLAGS_CMA_CLEAR | - CODEC_MM_FLAGS_FOR_VDECODER); - - decoder_state = 1; - hold = 0; - last_tr = -1; - wait_key_frame = 1; - frame_count = 0; - current_vdts = 0; - real_err_count = 0; - - pic_sz_tbl_map = 0; - saved_resolution = 0; - fatal_flag = 0; - wait_buffer_counter = 0; -} - -static void load_block_data(void *dest, unsigned int count) -{ - unsigned short *pdest = (unsigned short *)dest; - unsigned short src_tbl[12]; - unsigned int i; - - src_tbl[0] = RPR_size[vreal_amstream_dec_info.extra + 1]; - memcpy((void *)&src_tbl[1], vreal_amstream_dec_info.param, - 2 << src_tbl[0]); - -#if 0 - for (i = 0; i < 12; i++) - pr_info("src_tbl[%d]: 0x%x\n", i, src_tbl[i]); -#endif - - for (i = 0; i < count / 4; i++) { - pdest[i * 4] = src_tbl[i * 4 + 3]; - pdest[i * 4 + 1] = src_tbl[i * 4 + 2]; - pdest[i * 4 + 2] = src_tbl[i * 4 + 1]; - pdest[i * 4 + 3] = src_tbl[i * 4]; - } - - pic_sz_tbl_map = dma_map_single(amports_get_dma_device(), &pic_sz_tbl, - sizeof(pic_sz_tbl), DMA_TO_DEVICE); - -} - -s32 vreal_init(struct vdec_s *vdec) -{ - int ret = -1, size = -1; - char fw_name[32] = {0}; - char *buf = vmalloc(0x1000 * 16); - - if (IS_ERR_OR_NULL(buf)) - return -ENOMEM; - - pr_info("vreal_init\n"); - - init_timer(&recycle_timer); - - stat |= STAT_TIMER_INIT; - - amvdec_enable(); - - vreal_local_init(); - - ret = rmparser_init(vdec); - if (ret) { - amvdec_disable(); - vfree(buf); - pr_info("rm parser init failed\n"); - return ret; - } - - if (vreal_amstream_dec_info.format == VIDEO_DEC_FORMAT_REAL_8) { - if (vreal_amstream_dec_info.param == NULL) { - rmparser_release(); - amvdec_disable(); - vfree(buf); - return -1; - } - load_block_data((void *)pic_sz_tbl, 12); - - /* TODO: need to load the table into lmem */ - WRITE_VREG(LMEM_DMA_ADR, (unsigned int)pic_sz_tbl_map); - WRITE_VREG(LMEM_DMA_COUNT, 10); - WRITE_VREG(LMEM_DMA_CTRL, 0xc178 | (3 << 11)); - while (READ_VREG(LMEM_DMA_CTRL) & 0x8000) - ; - size = get_firmware_data(VIDEO_DEC_REAL_V8, buf); - strncpy(fw_name, "vreal_mc_8", sizeof(fw_name)); - - pr_info("load VIDEO_DEC_FORMAT_REAL_8\n"); - } else if (vreal_amstream_dec_info.format == VIDEO_DEC_FORMAT_REAL_9) { - size = get_firmware_data(VIDEO_DEC_REAL_V9, buf); - strncpy(fw_name, "vreal_mc_9", sizeof(fw_name)); - - pr_info("load VIDEO_DEC_FORMAT_REAL_9\n"); - } else - pr_info("unsurpported real format\n"); - - if (size < 0) { - rmparser_release(); - amvdec_disable(); - pr_err("get firmware fail."); - vfree(buf); - return -1; - } - - ret = amvdec_loadmc_ex(VFORMAT_REAL, fw_name, buf); - if (ret < 0) { - rmparser_release(); - amvdec_disable(); - vfree(buf); - pr_err("%s: the %s fw loading failed, err: %x\n", - fw_name, tee_enabled() ? "TEE" : "local", ret); - return -EBUSY; - } - - vfree(buf); - - stat |= STAT_MC_LOAD; - - /* enable AMRISC side protocol */ - ret = vreal_prot_init(); - if (ret < 0) { - rmparser_release(); - amvdec_disable(); - return ret; - } - if (vdec_request_irq(VDEC_IRQ_1, vreal_isr, - "vreal-irq", (void *)vreal_dec_id)) { - rmparser_release(); - amvdec_disable(); - - pr_info("vreal irq register error.\n"); - return -ENOENT; - } - - stat |= STAT_ISR_REG; -#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER - vf_provider_init(&vreal_vf_prov, PROVIDER_NAME, &vreal_vf_provider, - NULL); - vf_reg_provider(&vreal_vf_prov); - vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_START, NULL); -#else - vf_provider_init(&vreal_vf_prov, PROVIDER_NAME, &vreal_vf_provider, - NULL); - vf_reg_provider(&vreal_vf_prov); -#endif - - if (!is_reset) - vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_FR_HINT, - (void *)((unsigned long)vreal_amstream_dec_info.rate)); - - stat |= STAT_VF_HOOK; - - recycle_timer.data = (ulong)&recycle_timer; - recycle_timer.function = vreal_put_timer_func; - recycle_timer.expires = jiffies + PUT_INTERVAL; - - add_timer(&recycle_timer); - - stat |= STAT_TIMER_ARM; - - amvdec_start(); - - stat |= STAT_VDEC_RUN; - - pr_info("vreal init finished\n"); - - return 0; -} - -void vreal_set_fatal_flag(int flag) -{ - if (flag) - fatal_flag = PARSER_FATAL_ERROR; -} - -static int amvdec_real_probe(struct platform_device *pdev) -{ - struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data; - - if (pdata == NULL) { - pr_info("amvdec_real memory resource undefined.\n"); - return -EFAULT; - } - if (pdata->sys_info) - vreal_amstream_dec_info = *pdata->sys_info; - - pdata->dec_status = vreal_dec_status; - pdata->set_isreset = vreal_set_isreset; - is_reset = 0; - - INIT_WORK(&set_clk_work, vreal_set_clk); - if (vreal_init(pdata) < 0) { - pr_info("amvdec_real init failed.\n"); - pdata->dec_status = NULL; - return -ENODEV; - } - return 0; -} - -static int amvdec_real_remove(struct platform_device *pdev) -{ - cancel_work_sync(&set_clk_work); - if (stat & STAT_VDEC_RUN) { - amvdec_stop(); - stat &= ~STAT_VDEC_RUN; - } - - if (stat & STAT_ISR_REG) { - vdec_free_irq(VDEC_IRQ_1, (void *)vreal_dec_id); - stat &= ~STAT_ISR_REG; - } - - if (stat & STAT_TIMER_ARM) { - del_timer_sync(&recycle_timer); - stat &= ~STAT_TIMER_ARM; - } - - if (stat & STAT_VF_HOOK) { - if (!is_reset) - vf_notify_receiver(PROVIDER_NAME, - VFRAME_EVENT_PROVIDER_FR_END_HINT, NULL); - - vf_unreg_provider(&vreal_vf_prov); - stat &= ~STAT_VF_HOOK; - } - - if (pic_sz_tbl_map != 0) { - dma_unmap_single(NULL, pic_sz_tbl_map, sizeof(pic_sz_tbl), - DMA_TO_DEVICE); - } - - rmparser_release(); - - vdec_source_changed(VFORMAT_REAL, 0, 0, 0); - - amvdec_disable(); - - if (mm_blk_handle) { - decoder_bmmu_box_free(mm_blk_handle); - mm_blk_handle = NULL; - } - pr_info("frame duration %d, frames %d\n", frame_dur, frame_count); - return 0; -} - -/****************************************/ -#ifdef CONFIG_PM -static int real_suspend(struct device *dev) -{ - amvdec_suspend(to_platform_device(dev), dev->power.power_state); - return 0; -} - -static int real_resume(struct device *dev) -{ - amvdec_resume(to_platform_device(dev)); - return 0; -} - -static const struct dev_pm_ops real_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(real_suspend, real_resume) -}; -#endif - -static struct platform_driver amvdec_real_driver = { - .probe = amvdec_real_probe, - .remove = amvdec_real_remove, - .driver = { - .name = DRIVER_NAME, -#ifdef CONFIG_PM - .pm = &real_pm_ops, -#endif - } -}; - -static struct codec_profile_t amvdec_real_profile = { - .name = "real", - .profile = "rmvb,1080p+" -}; -static struct mconfig real_configs[] = { - MC_PU32("stat", &stat), -}; -static struct mconfig_node real_node; - -static int __init amvdec_real_driver_init_module(void) -{ - pr_debug("amvdec_real module init\n"); - - if (platform_driver_register(&amvdec_real_driver)) { - pr_err("failed to register amvdec_real driver\n"); - return -ENODEV; - } - vcodec_profile_register(&amvdec_real_profile); - INIT_REG_NODE_CONFIGS("media.decoder", &real_node, - "real", real_configs, CONFIG_FOR_R); - return 0; -} - -static void __exit amvdec_real_driver_remove_module(void) -{ - pr_debug("amvdec_real module remove.\n"); - - platform_driver_unregister(&amvdec_real_driver); -} - -/****************************************/ - -module_init(amvdec_real_driver_init_module); -module_exit(amvdec_real_driver_remove_module); - -MODULE_DESCRIPTION("AMLOGIC REAL Video Decoder Driver"); -MODULE_LICENSE("GPL");
diff --git a/drivers/frame_provider/decoder/utils/Makefile b/drivers/frame_provider/decoder/utils/Makefile index 1e7552b..6f8540b 100644 --- a/drivers/frame_provider/decoder/utils/Makefile +++ b/drivers/frame_provider/decoder/utils/Makefile
@@ -1,10 +1,13 @@ obj-m += decoder_common.o 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 += config_parser.o vdec_profile.o decoder_common-objs += amstream_profile.o decoder_common-objs += frame_check.o amlogic_fbc_hook.o decoder_common-objs += vdec_v4l2_buffer_ops.o decoder_common-objs += vdec_sync.o decoder_common-objs += vdec_power_ctrl.o +decoder_common-objs += vdec_canvas_utils.o +decoder_common-objs += vdec_feature.o +decoder_common-objs += vdec_ge2d_utils.o
diff --git a/drivers/frame_provider/decoder/utils/amstream_profile.c b/drivers/frame_provider/decoder/utils/amstream_profile.c index c8033ce..0e2b9c8 100644 --- a/drivers/frame_provider/decoder/utils/amstream_profile.c +++ b/drivers/frame_provider/decoder/utils/amstream_profile.c
@@ -66,5 +66,3 @@ return ret; } EXPORT_SYMBOL(is_support_profile); - -
diff --git a/drivers/frame_provider/decoder/utils/amvdec.c b/drivers/frame_provider/decoder/utils/amvdec.c index af36ef1..d525fe8 100644 --- a/drivers/frame_provider/decoder/utils/amvdec.c +++ b/drivers/frame_provider/decoder/utils/amvdec.c
@@ -43,7 +43,8 @@ #include "amvdec.h" #include <linux/amlogic/media/utils/amports_config.h> #include "firmware.h" -#include <linux/amlogic/tee.h> +//#include <linux/amlogic/tee.h> +#include <uapi/linux/tee.h> #include "../../../common/chips/decoder_cpu_ver_info.h" #define MC_SIZE (4096 * 16) @@ -484,9 +485,16 @@ } else format = VIDEO_DEC_H264; break; - + case VFORMAT_JPEG_ENC: + format = VIDEO_ENC_JPEG; + vdec = OPTEE_VDEC_HCDEC; + break; + case VFORMAT_H264_ENC: + format = VIDEO_ENC_H264; + vdec = OPTEE_VDEC_HCDEC; + break; default: - pr_info("Unknow vdec format!\n"); + pr_info("Unknow vdec format: %u\n", (u32)type); break; } @@ -675,13 +683,17 @@ WRITE_VREG(HEVC_IMEM_DMA_ADR, mc_addr_map); WRITE_VREG(HEVC_IMEM_DMA_COUNT, 0x1000); - WRITE_VREG(HEVC_IMEM_DMA_CTRL, (0x8000 | (7 << 16))); + if ((get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T7) || + (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T3)) + WRITE_VREG(HEVC_IMEM_DMA_CTRL, (0x8000 | (0xf << 16))); + else + WRITE_VREG(HEVC_IMEM_DMA_CTRL, (0x8000 | (0x7 << 16))); while (READ_VREG(HEVC_IMEM_DMA_CTRL) & 0x8000) { if (time_before(jiffies, timeout)) schedule(); else { - pr_err("vdec2 load mc error\n"); + pr_err("hevc load mc error\n"); ret = -EBUSY; break; } @@ -966,6 +978,14 @@ #ifdef CONFIG_PM int amvdec_suspend(struct platform_device *dev, pm_message_t event) { + struct vdec_s *vdec = *(struct vdec_s **)dev->dev.platform_data;; + + if (vdec) { + wait_event_interruptible_timeout(vdec->idle_wait, + (vdec->status != VDEC_STATUS_ACTIVE), + msecs_to_jiffies(100)); + } + amvdec_pg_enable(false); /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6TVD */ @@ -1000,6 +1020,14 @@ int amhevc_suspend(struct platform_device *dev, pm_message_t event) { + struct vdec_s *vdec = *(struct vdec_s **)dev->dev.platform_data;; + + if (vdec) { + wait_event_interruptible_timeout(vdec->idle_wait, + (vdec->status != VDEC_STATUS_ACTIVE), + msecs_to_jiffies(100)); + } + if (has_hevc_vdec()) { amhevc_pg_enable(false); /*vdec_set_suspend_clk(1, 1);*//*DEBUG_TMP*/ @@ -1161,9 +1189,8 @@ module_init(amvdec_init); module_exit(amvdec_exit); - +#endif MODULE_DESCRIPTION("Amlogic Video Decoder Utility Driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Tim Yao <timyao@amlogic.com>"); -#endif
diff --git a/drivers/frame_provider/decoder/utils/decoder_bmmu_box.c b/drivers/frame_provider/decoder/utils/decoder_bmmu_box.c index 461621b..33a9e4b 100644 --- a/drivers/frame_provider/decoder/utils/decoder_bmmu_box.c +++ b/drivers/frame_provider/decoder/utils/decoder_bmmu_box.c
@@ -141,7 +141,7 @@ int memflags = mem_flags; if (!box || idx < 0 || idx >= box->max_mm_num) { - pr_err("can't alloc mmu box(%p),idx:%d\n", + pr_err("can't alloc bmmu box(%p),idx:%d\n", box, idx); return -1; } @@ -324,7 +324,7 @@ } /*flags: &0x1 for wait,*/ -int decoder_bmmu_box_check_and_wait_size(int size, int flags) +int decoder_bmmu_box_check_and_wait_size(int size, int flags, int mem_flags) { if ((flags & BMMU_ALLOC_FLAGS_CAN_CLEAR_KEEPER) && codec_mm_get_free_size() < size) { @@ -335,7 +335,7 @@ } return codec_mm_enough_for_size(size, - flags & BMMU_ALLOC_FLAGS_WAIT); + flags & BMMU_ALLOC_FLAGS_WAIT, mem_flags); } int decoder_bmmu_box_alloc_idx_wait( @@ -361,7 +361,8 @@ } have_space = decoder_bmmu_box_check_and_wait_size( size, - wait_flags); + wait_flags, + mem_flags); if (have_space) { ret = decoder_bmmu_box_alloc_idx(handle, idx, size, aligned_2n, mem_flags); @@ -382,9 +383,14 @@ int size, unsigned char *driver_name, unsigned long *buf_phy_addr) { + struct decoder_bmmu_box *bmmu_box = (struct decoder_bmmu_box *)handle; + + if (bmmu_box == NULL) + return -EINVAL; + if (!decoder_bmmu_box_check_and_wait_size( size, - 1)) { + 1, bmmu_box->mem_flags)) { pr_info("%s not enough buf for buf_idx = %d\n", driver_name, idx); return -ENOMEM; @@ -394,9 +400,8 @@ idx, size, -1, - -1, - BMMU_ALLOC_FLAGS_WAITCLEAR - )) { + bmmu_box->mem_flags, + BMMU_ALLOC_FLAGS_WAITCLEAR)) { *buf_phy_addr = decoder_bmmu_box_get_phy_addr( handle, @@ -414,6 +419,25 @@ } EXPORT_SYMBOL(decoder_bmmu_box_alloc_buf_phy); +int decoder_bmmu_box_add_callback_func( + void *handle, int idx, + void *cb) +{ + struct decoder_bmmu_box *box = handle; + struct codec_mm_s *mm; + + if (!box || idx < 0 || idx >= box->max_mm_num) + return 0; + + mutex_lock(&box->mutex); + mm = box->mm_list[idx]; + codec_mm_add_release_callback(mm, (struct codec_mm_cb_s *)cb); + mutex_unlock(&box->mutex); + + return 0; +} +EXPORT_SYMBOL(decoder_bmmu_box_add_callback_func); + static int decoder_bmmu_box_dump(struct decoder_bmmu_box *box, void *buf, int size) { @@ -422,6 +446,7 @@ int tsize = 0; int s; int i; + if (!buf) { pbuf = sbuf; size = 512; @@ -466,6 +491,7 @@ int s; int i; struct list_head *head, *list; + if (!buf) { pbuf = sbuf; size = 512; @@ -523,7 +549,7 @@ return ret; } -static ssize_t box_debug_show(struct class *class, +static ssize_t debug_show(struct class *class, struct class_attribute *attr, char *buf) { @@ -537,8 +563,7 @@ return size; } - -static ssize_t box_debug_store(struct class *class, +static ssize_t debug_store(struct class *class, struct class_attribute *attr, const char *buf, size_t size) { @@ -559,19 +584,21 @@ } +static CLASS_ATTR_RO(box_dump); +static CLASS_ATTR_RW(debug); - -static struct class_attribute decoder_bmmu_box_class_attrs[] = { - __ATTR_RO(box_dump), - __ATTR(debug, S_IRUGO | S_IWUSR | S_IWGRP, - box_debug_show, box_debug_store), - __ATTR_NULL +static struct attribute *decoder_bmmu_box_class_attrs[] = { + &class_attr_box_dump.attr, + &class_attr_debug.attr, + NULL }; +ATTRIBUTE_GROUPS(decoder_bmmu_box_class); + static struct class decoder_bmmu_box_class = { - .name = "decoder_bmmu_box", - .class_attrs = decoder_bmmu_box_class_attrs, - }; + .name = "decoder_bmmu_box", + .class_groups = decoder_bmmu_box_class_groups, +}; int decoder_bmmu_box_init(void) {
diff --git a/drivers/frame_provider/decoder/utils/decoder_bmmu_box.h b/drivers/frame_provider/decoder/utils/decoder_bmmu_box.h index 778cb8e..93974ec 100644 --- a/drivers/frame_provider/decoder/utils/decoder_bmmu_box.h +++ b/drivers/frame_provider/decoder/utils/decoder_bmmu_box.h
@@ -41,13 +41,17 @@ /*flags: &0x1 for wait,*/ int decoder_bmmu_box_check_and_wait_size( - int size, int flags); + int size, int flags, int mem_flags); int decoder_bmmu_box_alloc_buf_phy( void *handle, int idx, int size, unsigned char *driver_name, unsigned long *buf_phy_addr); +int decoder_bmmu_box_add_callback_func( + void *handle, int idx, + void *cb); + #define BMMU_ALLOC_FLAGS_WAIT (1 << 0) #define BMMU_ALLOC_FLAGS_CAN_CLEAR_KEEPER (1 << 1) #define BMMU_ALLOC_FLAGS_WAITCLEAR \
diff --git a/drivers/frame_provider/decoder/utils/decoder_mmu_box.c b/drivers/frame_provider/decoder/utils/decoder_mmu_box.c index 75862ec..57180dd 100644 --- a/drivers/frame_provider/decoder/utils/decoder_mmu_box.c +++ b/drivers/frame_provider/decoder/utils/decoder_mmu_box.c
@@ -28,13 +28,11 @@ #include <linux/slab.h> #include <linux/amlogic/media/codec_mm/codec_mm_scatter.h> #include <linux/platform_device.h> - struct decoder_mmu_box { int max_sc_num; const char *name; int channel_id; int tvp_mode; - int box_ref_cnt; struct mutex mutex; struct list_head list; struct codec_mm_scatter *sc_list[1]; @@ -76,51 +74,6 @@ return 0; } -bool decoder_mmu_box_valide_check(void *box) -{ - struct decoder_mmu_box_mgr *mgr = get_decoder_mmu_box_mgr(); - struct decoder_mmu_box *mmu_box = NULL; - bool is_valide = false; - - mutex_lock(&mgr->mutex); - list_for_each_entry(mmu_box, &mgr->box_list, list) { - if (mmu_box && mmu_box == box) { - is_valide = true; - break; - } - } - mutex_unlock(&mgr->mutex); - - return is_valide; -} -EXPORT_SYMBOL(decoder_mmu_box_valide_check); - -void decoder_mmu_try_to_release_box(void *handle) -{ - struct decoder_mmu_box *box = handle; - bool is_keep = false; - int i; - - if (!box || box->box_ref_cnt) - return; - - mutex_lock(&box->mutex); - for (i = 0; i < box->max_sc_num; i++) { - if (box->sc_list[i]) { - is_keep = true; - break; - } - } - mutex_unlock(&box->mutex); - - if (!is_keep) { - decoder_mmu_box_mgr_del_box(box); - codec_mm_scatter_mgt_delay_free_swith(0, 0, 0, box->tvp_mode); - kfree(box); - } -} -EXPORT_SYMBOL(decoder_mmu_try_to_release_box); - int decoder_mmu_box_sc_check(void *handle, int is_tvp) { struct decoder_mmu_box *box = handle; @@ -162,7 +115,7 @@ mutex_init(&box->mutex); INIT_LIST_HEAD(&box->list); decoder_mmu_box_mgr_add_box(box); - codec_mm_scatter_mgt_delay_free_swith(1, 2000, + codec_mm_scatter_mgt_delay_free_switch(1, 2000, min_size_M, box->tvp_mode); return (void *)box; } @@ -189,7 +142,6 @@ ret = codec_mm_scatter_alloc_want_pages(sc, num_pages); else { - box->box_ref_cnt--; codec_mm_scatter_dec_owner_user(sc, 0); box->sc_list[idx] = NULL; sc = NULL; @@ -206,7 +158,6 @@ return -1; } box->sc_list[idx] = sc; - box->box_ref_cnt++; } for (i = 0; i < num_pages; i++) @@ -252,17 +203,15 @@ box ? (box->max_sc_num - 1) : 0); return -1; } + mutex_lock(&box->mutex); sc = box->sc_list[idx]; if (sc && sc->page_cnt > 0) { codec_mm_scatter_dec_owner_user(sc, 0); box->sc_list[idx] = NULL; - box->box_ref_cnt--; } - mutex_unlock(&box->mutex); - if (sc && box->box_ref_cnt == 0) - codec_mm_scatter_mgt_delay_free_swith(0, 0, 0, box->tvp_mode); + mutex_unlock(&box->mutex); return 0; } @@ -278,18 +227,24 @@ pr_err("can't free box of NULL box!\n"); return -1; } + mutex_lock(&box->mutex); for (i = 0; i < box->max_sc_num; i++) { sc = box->sc_list[i]; if (sc) { codec_mm_scatter_dec_owner_user(sc, 0); box->sc_list[i] = NULL; + } } + + codec_mm_scatter_mgt_delay_free_switch(0, 0, 0, box->tvp_mode); + mutex_unlock(&box->mutex); + decoder_mmu_box_mgr_del_box(box); - codec_mm_scatter_mgt_delay_free_swith(0, 0, 0, box->tvp_mode); kfree(box); + return 0; } EXPORT_SYMBOL(decoder_mmu_box_free); @@ -411,16 +366,18 @@ return ret; } +static CLASS_ATTR_RO(box_dump); - -static struct class_attribute decoder_mmu_box_class_attrs[] = { - __ATTR_RO(box_dump), - __ATTR_NULL +static struct attribute *decoder_mmu_box_class_attrs[] = { + &class_attr_box_dump.attr, + NULL }; +ATTRIBUTE_GROUPS(decoder_mmu_box_class); + static struct class decoder_mmu_box_class = { .name = "decoder_mmu_box", - .class_attrs = decoder_mmu_box_class_attrs, + .class_groups = decoder_mmu_box_class_groups, }; int decoder_mmu_box_init(void)
diff --git a/drivers/frame_provider/decoder/utils/decoder_mmu_box.h b/drivers/frame_provider/decoder/utils/decoder_mmu_box.h index 029f91a..13b3dd9 100644 --- a/drivers/frame_provider/decoder/utils/decoder_mmu_box.h +++ b/drivers/frame_provider/decoder/utils/decoder_mmu_box.h
@@ -40,11 +40,13 @@ int decoder_mmu_box_move_keep_idx(void *box_handle, int keep_idx); int decoder_mmu_box_free_keep(int keep_id); + int decoder_mmu_box_free_all_keep(void); + void *decoder_mmu_box_get_mem_handle(void *box_handle, int idx); -bool decoder_mmu_box_valide_check(void *box); -void decoder_mmu_try_to_release_box(void *handle); + int decoder_mmu_box_init(void); + void decoder_mmu_box_exit(void); #endif
diff --git a/drivers/frame_provider/decoder/utils/firmware.h b/drivers/frame_provider/decoder/utils/firmware.h index c799fd0..cd48036 100644 --- a/drivers/frame_provider/decoder/utils/firmware.h +++ b/drivers/frame_provider/decoder/utils/firmware.h
@@ -22,6 +22,9 @@ #include "../../../common/firmware/firmware_type.h" #include <linux/amlogic/media/utils/vformat.h> +#if defined(CONFIG_AMLOGIC_TEE) || defined(CONFIG_AMLOGIC_TEE_MODULE) +#include <linux/amlogic/tee.h> +#endif #define FW_LOAD_FORCE (0x1) #define FW_LOAD_TRY (0X2) @@ -38,4 +41,16 @@ extern int get_firmware_data(unsigned int foramt, char *buf); extern int video_fw_reload(int mode); +#if !defined(CONFIG_AMLOGIC_TEE) && !defined(CONFIG_AMLOGIC_TEE_MODULE) +static inline bool tee_enabled(void) { return false; } +static inline int tee_load_video_fw_swap(u32 index, u32 vdec, bool is_swap) +{ + return -1; +} +static inline int tee_load_video_fw(u32 index, u32 vdec) +{ + return -1; +} +#endif + #endif
diff --git a/drivers/frame_provider/decoder/utils/frame_check.c b/drivers/frame_provider/decoder/utils/frame_check.c index 4cd80c0..0600f8e 100644 --- a/drivers/frame_provider/decoder/utils/frame_check.c +++ b/drivers/frame_provider/decoder/utils/frame_check.c
@@ -25,9 +25,8 @@ #include <linux/timer.h> #include <linux/kfifo.h> #include <linux/kthread.h> +#include <linux/vmalloc.h> #include <linux/platform_device.h> -#include <linux/amlogic/media/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> @@ -72,7 +71,7 @@ #define dbg_print(mask, ...) do { \ if ((fc_debug & mask) || \ (mask == FC_ERROR)) \ - printk("[FRMAE_CHECK] "__VA_ARGS__);\ + printk("[FRAME_CHECK] "__VA_ARGS__);\ } while(0) @@ -167,6 +166,18 @@ return false; } +unsigned long vdec_cav_get_addr(int index); +unsigned int vdec_cav_get_width(int index); +unsigned int vdec_cav_get_height(int index); +#define canvas_0(v) ((v) & 0xff) +#define canvas_1(v) (((v) >> 8) & 0xff) +#define canvas_2(v) (((v) >> 16) & 0xff) +#define canvas_3(v) (((v) >> 24) & 0xff) + +#define canvasY(v) canvas_0(v) +#define canvasU(v) canvas_1(v) +#define canvasV(v) canvas_2(v) +#define canvasUV(v) canvas_1(v) static int get_frame_size(struct pic_check_mgr_t *pic, struct vframe_s *vf) @@ -188,10 +199,10 @@ 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)); + pic->canvas_w = vdec_cav_get_width(canvasY(vf->canvas0Addr)); + //canvas_get_width(canvasY(vf->canvas0Addr)); + pic->canvas_h = vdec_cav_get_height(canvasY(vf->canvas0Addr)); + //canvas_get_height(canvasY(vf->canvas0Addr)); } else { pic->canvas_w = vf->canvas0_config[0].width; pic->canvas_h = vf->canvas0_config[0].height; @@ -221,8 +232,8 @@ 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(canvasU(vf->canvas0Addr)); + phy_y_addr = vdec_cav_get_addr(canvasY(vf->canvas0Addr)); //canvas_get_addr(canvasY(vf->canvas0Addr)); + phy_uv_addr = vdec_cav_get_addr(canvasUV(vf->canvas0Addr)); //canvas_get_addr(canvasUV(vf->canvas0Addr)); } else { phy_y_addr = vf->canvas0_config[0].phy_addr; phy_uv_addr = vf->canvas0_config[1].phy_addr; @@ -426,10 +437,14 @@ static int write_crc_work(struct pic_check_mgr_t *mgr) { unsigned int wr_size; - char *crc_buf, crc_tmp[64*30]; + char *crc_buf, *crc_tmp = NULL; mm_segment_t old_fs; struct pic_check_t *check = &mgr->pic_check; + crc_tmp = (char *)vzalloc(64 * 30); + if (!crc_tmp) + return -1; + if (mgr->enable & CRC_MASK) { wr_size = 0; while (kfifo_get(&check->wr_chk_q, &crc_buf) != 0) { @@ -453,10 +468,11 @@ set_fs(old_fs); } } + + vfree(crc_tmp); return 0; } - static int write_aux_data_crc_work(struct aux_data_check_mgr_t *mgr) { unsigned int wr_size; @@ -490,8 +506,6 @@ return 0; } - - static void do_check_work(struct work_struct *work) { struct pic_check_mgr_t *mgr = container_of(work, @@ -1109,6 +1123,10 @@ single_mode_vdec = NULL; } + if (!single_mode_vdec && + unlikely(in_interrupt())) + return 0; + if ((mgr == NULL) || (vf == NULL) || (mgr->enable == 0)) return 0; @@ -1131,7 +1149,8 @@ resize = 0; mgr->last_size_pic = mgr->size_pic; - if ((vf->type & VIDTYPE_VIU_NV21) || (mgr->mjpeg_flag)) { + if ((vf->type & VIDTYPE_VIU_NV21) || (mgr->mjpeg_flag) || + (vf->type & VIDTYPE_VIU_NV12)) { int flush_size; if (canvas_get_virt_addr(mgr, vf) < 0)
diff --git a/drivers/frame_provider/decoder/utils/secprot.c b/drivers/frame_provider/decoder/utils/secprot.c deleted file mode 100644 index a1e7fa7..0000000 --- a/drivers/frame_provider/decoder/utils/secprot.c +++ /dev/null
@@ -1,75 +0,0 @@ -/* - * drivers/amlogic/amports/arch/secprot.c - * - * Copyright (C) 2017 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 <asm/compiler.h> -#include "secprot.h" -#ifndef CONFIG_ARM64 -#include <asm/opcodes-sec.h> -#endif - -#ifdef CONFIG_ARM64 - -int tee_config_device_secure(int dev_id, int secure) -{ - int ret = 0; - register unsigned x0 asm("x0"); - register unsigned x1 asm("x1"); - register unsigned x2 asm("x2"); - - x0 = OPTEE_SMC_CONFIG_DEVICE_SECURE; - x1 = dev_id; - x2 = secure; - - asm volatile( - __asmeq("%0", "x0") - __asmeq("%1", "x0") - __asmeq("%2", "x1") - __asmeq("%3", "x2") - "smc #0\n" - : "=r"(x0) - : "r"(x0), "r"(x1), "r"(x2)); - ret = x0; - - return ret; -} -#else -int tee_config_device_secure(int dev_id, int secure) -{ - int ret = 0; - register unsigned int r0 asm("r0"); - register unsigned int r1 asm("r1"); - register unsigned int r2 asm("r2"); - - r0 = OPTEE_SMC_CONFIG_DEVICE_SECURE; - r1 = dev_id; - r2 = secure; - - asm volatile( - __asmeq("%0", "r0") - __asmeq("%1", "r0") - __asmeq("%2", "r1") - __asmeq("%3", "r2") - __SMC(0) - : "=r"(r0) - : "r"(r0), "r"(r1), "r"(r2)); - ret = r0; - - return ret; -} -#endif -
diff --git a/drivers/frame_provider/decoder/utils/secprot.h b/drivers/frame_provider/decoder/utils/secprot.h deleted file mode 100644 index 28ee477..0000000 --- a/drivers/frame_provider/decoder/utils/secprot.h +++ /dev/null
@@ -1,39 +0,0 @@ -/* - * drivers/amlogic/amports/arch/secprot.h - * - * Copyright (C) 2017 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 __SECPROT_H_ -#define __SECPROT_H_ - -#define DMC_DEV_TYPE_NON_SECURE 0 -#define DMC_DEV_TYPE_SECURE 1 - -#define DMC_DEV_ID_GPU 1 -#define DMC_DEV_ID_HEVC 4 -#define DMC_DEV_ID_PARSER 7 -#define DMC_DEV_ID_VPU 8 -#define DMC_DEV_ID_VDEC 13 -#define DMC_DEV_ID_HCODEC 14 -#define DMC_DEV_ID_GE2D 15 - -#define OPTEE_SMC_CONFIG_DEVICE_SECURE 0xb200000e - -/*#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t"*/ - -extern int tee_config_device_secure(int dev_id, int secure); - -#endif /* __SECPROT_H_ */ -
diff --git a/drivers/frame_provider/decoder/utils/utils.c b/drivers/frame_provider/decoder/utils/utils.c index 44b1626..0372a18 100644 --- a/drivers/frame_provider/decoder/utils/utils.c +++ b/drivers/frame_provider/decoder/utils/utils.c
@@ -69,5 +69,6 @@ module_init(decoder_common_init); module_exit(decoder_common_exit); + MODULE_DESCRIPTION("AMLOGIC decoder_common driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL"); \ No newline at end of file
diff --git a/drivers/frame_provider/decoder/utils/vdec.c b/drivers/frame_provider/decoder/utils/vdec.c index 69ec60c..98f0e3c 100644 --- a/drivers/frame_provider/decoder/utils/vdec.c +++ b/drivers/frame_provider/decoder/utils/vdec.c
@@ -37,9 +37,11 @@ #include <linux/amlogic/media/video_sink/v4lvideo_ext.h> #endif #include <linux/amlogic/media/vfm/vfm_ext.h> +#include <linux/sched/clock.h> +#include <uapi/linux/sched/types.h> +#include <linux/signal.h> /*for VDEC_DEBUG_SUPPORT*/ #include <linux/time.h> - #include <linux/amlogic/media/utils/vdec_reg.h> #include "../../../stream_input/amports/streambuf.h" #include "vdec.h" @@ -47,6 +49,7 @@ #ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC #include "vdec_profile.h" #endif +#include <linux/sched/clock.h> #include <linux/of.h> #include <linux/of_fdt.h> #include <linux/libfdt_env.h> @@ -65,21 +68,27 @@ #include "../../../common/media_clock/clk/clk.h" #include <linux/reset.h> -#include <linux/amlogic/cpu_version.h> +#include <linux/amlogic/media/registers/cpu_version.h> #include <linux/amlogic/media/codec_mm/codec_mm.h> #include <linux/amlogic/media/video_sink/video_keeper.h> #include <linux/amlogic/media/codec_mm/configs.h> #include <linux/amlogic/media/frame_sync/ptsserv.h> -#include "secprot.h" #include "../../../common/chips/decoder_cpu_ver_info.h" #include "frame_check.h" +#include <linux/amlogic/tee.h> +#include "vdec_canvas_utils.h" +#include "../../../amvdec_ports/aml_vcodec_drv.h" + #ifdef CONFIG_AMLOGIC_POWER #include <linux/amlogic/power_ctrl.h> #endif -#include <dt-bindings/power/sc2-pd.h> -#include <linux/amlogic/pwr_ctrl.h> +#ifdef CONFIG_AMLOGIC_IONVIDEO +#include <linux/amlogic/media/video_sink/ionvideo_ext.h> +#endif +//#include <dt-bindings/power/sc2-pd.h> +//#include <linux/amlogic/pwr_ctrl.h> #include <linux/of_device.h> #include "vdec_power_ctrl.h" @@ -96,10 +105,12 @@ static unsigned int debug_trace_num = 16 * 20; static int step_mode; static unsigned int clk_config; -#ifdef VDEC_FCC_SUPPORT -static int fcc_debug; -static void vdec_fcc_jump_back(struct vdec_s *vdec); -#endif +/* +0x1 : enable rdma +0x2 : check rdma result +*/ +static int rdma_mode = 0x1; + /* * 0x1 : sched_priority to MAX_RT_PRIO -1. * 0x2 : always reload firmware. @@ -111,23 +122,36 @@ #define VDEC_DBG_CANVAS_STATUS (0x4) #define VDEC_DBG_ENABLE_FENCE (0x100) -#define FRAME_BASE_PATH_DI_V4LVIDEO_0 (29) -#define FRAME_BASE_PATH_DI_V4LVIDEO_1 (30) -#define FRAME_BASE_PATH_DI_V4LVIDEO_2 (31) -u32 debug = VDEC_DBG_ALWAYS_LOAD_FW; -EXPORT_SYMBOL(debug); +#define HEVC_RDMA_F_CTRL 0x30f0 +#define HEVC_RDMA_F_START_ADDR 0x30f1 +#define HEVC_RDMA_F_END_ADDR 0x30f2 +#define HEVC_RDMA_F_STATUS0 0x30f3 + +#define HEVC_RDMA_B_CTRL 0x30f8 +#define HEVC_RDMA_B_START_ADDR 0x30f9 +#define HEVC_RDMA_B_END_ADDR 0x30fa +#define HEVC_RDMA_B_STATUS0 0x30fb + + +static u32 debug = VDEC_DBG_ALWAYS_LOAD_FW; + +u32 vdec_get_debug(void) +{ + return debug; +} +EXPORT_SYMBOL(vdec_get_debug); + int hevc_max_reset_count; EXPORT_SYMBOL(hevc_max_reset_count); int no_powerdown; EXPORT_SYMBOL(no_powerdown); - static int parallel_decode = 1; static int fps_detection; static int fps_clear; - +static bool prog_only; static int force_nosecure_even_drm; static int disable_switch_single_to_mult; @@ -143,8 +167,12 @@ #define RESET7_REGISTER_LEVEL 0x1127 #define P_RESETCTRL_RESET5_LEVEL 0x15 +#define str(a) #a +#define xstr(a) str(a) + static int frameinfo_flag = 0; static int v4lvideo_add_di = 1; +static int v4lvideo_add_ppmgr = 0; static int max_di_instance = 2; static int max_supported_di_instance = 4; @@ -153,12 +181,39 @@ static int enable_mvdec_info = 1; int decode_underflow = 0; +u32 debug_meta; static int enable_stream_mode_multi_dec; -#define CANVAS_MAX_SIZE (AMVDEC_CANVAS_MAX1 - AMVDEC_CANVAS_START_INDEX + 1 + AMVDEC_CANVAS_MAX2 + 1) +st_userdata userdata; +typedef void (*vdec_frame_rate_event_func)(int); + +#if 1 extern void vframe_rate_uevent(int duration); +vdec_frame_rate_event_func frame_rate_notify = vframe_rate_uevent; +#else +vdec_frame_rate_event_func frame_rate_notify = NULL; +#endif + +void vdec_frame_rate_uevent(int dur) +{ + if (frame_rate_notify == NULL) + return; + + if (unlikely(in_interrupt())) + return; + pr_info("vdec_frame_rate_uevent %d\n", dur); + frame_rate_notify(dur); +} +EXPORT_SYMBOL(vdec_frame_rate_uevent); + + +void register_frame_rate_uevent_func(vdec_frame_rate_event_func func) +{ + frame_rate_notify = func; +} +EXPORT_SYMBOL(register_frame_rate_uevent_func); struct am_reg { char *name; @@ -211,15 +266,9 @@ unsigned long stream_buff_flag; struct power_manager_s *pm; u32 vdec_resouce_status; + struct post_task_mgr_s post; }; -struct canvas_status_s { - int type; - int canvas_used_flag; - int id; -}; - - static struct vdec_core_s *vdec_core; static const char * const vdec_status_string[] = { @@ -229,6 +278,7 @@ "VDEC_STATUS_ACTIVE" }; /* +bit [29] enable steam mode dv multi; bit [28] enable print bit [23:16] etc bit [15:12] @@ -286,9 +336,6 @@ "reserved", }; -static struct canvas_status_s canvas_stat[AMVDEC_CANVAS_MAX1 - AMVDEC_CANVAS_START_INDEX + 1 + AMVDEC_CANVAS_MAX2 + 1]; - - int vdec_get_debug_flags(void) { return debugflags; @@ -302,15 +349,6 @@ } EXPORT_SYMBOL(VDEC_PRINT_FUN_LINENO); -bool is_support_no_parser(void) -{ - if ((enable_stream_mode_multi_dec) || - (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2)) - return true; - return false; -} -EXPORT_SYMBOL(is_support_no_parser); - unsigned char is_mult_inc(unsigned int type) { unsigned char ret = 0; @@ -323,6 +361,16 @@ } EXPORT_SYMBOL(is_mult_inc); +bool is_support_no_parser(void) +{ + if ((enable_stream_mode_multi_dec) || + (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_SC2) || + (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T7)) + return true; + return false; +} +EXPORT_SYMBOL(is_support_no_parser); + static const bool cores_with_input[VDEC_MAX] = { true, /* VDEC_1 */ false, /* VDEC_HCODEC */ @@ -339,17 +387,17 @@ VDEC_IRQ_HEVC_BACK }; -unsigned long vdec_canvas_lock(struct vdec_core_s *core) +unsigned long vdec_canvas_lock(void) { unsigned long flags; - spin_lock_irqsave(&core->canvas_lock, flags); + spin_lock_irqsave(&vdec_core->canvas_lock, flags); return flags; } -void vdec_canvas_unlock(struct vdec_core_s *core, unsigned long flags) +void vdec_canvas_unlock(unsigned long flags) { - spin_unlock_irqrestore(&core->canvas_lock, flags); + spin_unlock_irqrestore(&vdec_core->canvas_lock, flags); } unsigned long vdec_fps_lock(struct vdec_core_s *core) @@ -415,14 +463,9 @@ up(&core->sem); } - static u64 vdec_get_us_time_system(void) { - struct timeval tv; - - do_gettimeofday(&tv); - - return div64_u64(timeval_to_ns(&tv), 1000); + return div64_u64(local_clock(), 1000); } static void vdec_fps_clear(int id) @@ -483,130 +526,6 @@ vdec_fps_unlock(vdec_core, flags); } - - -static int get_canvas(unsigned int index, unsigned int base) -{ - int start; - int canvas_index = index * base; - int ret; - - if ((base > 4) || (base == 0)) - return -1; - - if ((AMVDEC_CANVAS_START_INDEX + canvas_index + base - 1) - <= AMVDEC_CANVAS_MAX1) { - start = AMVDEC_CANVAS_START_INDEX + base * index; - } else { - canvas_index -= (AMVDEC_CANVAS_MAX1 - - AMVDEC_CANVAS_START_INDEX + 1) / base * base; - if (canvas_index <= AMVDEC_CANVAS_MAX2) - start = canvas_index / base; - else - return -1; - } - - if (base == 1) { - ret = start; - } else if (base == 2) { - ret = ((start + 1) << 16) | ((start + 1) << 8) | start; - } else if (base == 3) { - ret = ((start + 2) << 16) | ((start + 1) << 8) | start; - } else if (base == 4) { - ret = (((start + 3) << 24) | (start + 2) << 16) | - ((start + 1) << 8) | start; - } - - return ret; -} - -static int get_canvas_ex(int type, int id) -{ - int i; - unsigned long flags; - - flags = vdec_canvas_lock(vdec_core); - - for (i = 0; i < CANVAS_MAX_SIZE; i++) { - if ((canvas_stat[i].type == type) && - (canvas_stat[i].id & (1 << id)) == 0) { - canvas_stat[i].canvas_used_flag++; - canvas_stat[i].id |= (1 << id); - if (debug & 4) - pr_debug("get used canvas %d\n", i); - vdec_canvas_unlock(vdec_core, flags); - if (i < AMVDEC_CANVAS_MAX2 + 1) - return i; - else - return (i + AMVDEC_CANVAS_START_INDEX - AMVDEC_CANVAS_MAX2 - 1); - } - } - - for (i = 0; i < CANVAS_MAX_SIZE; i++) { - if (canvas_stat[i].type == 0) { - canvas_stat[i].type = type; - canvas_stat[i].canvas_used_flag = 1; - canvas_stat[i].id = (1 << id); - if (debug & 4) { - pr_debug("get canvas %d\n", i); - pr_debug("canvas_used_flag %d\n", - canvas_stat[i].canvas_used_flag); - pr_debug("canvas_stat[i].id %d\n", - canvas_stat[i].id); - } - vdec_canvas_unlock(vdec_core, flags); - if (i < AMVDEC_CANVAS_MAX2 + 1) - return i; - else - return (i + AMVDEC_CANVAS_START_INDEX - AMVDEC_CANVAS_MAX2 - 1); - } - } - vdec_canvas_unlock(vdec_core, flags); - - pr_info("cannot get canvas\n"); - - return -1; -} - -static void free_canvas_ex(int index, int id) -{ - unsigned long flags; - int offset; - - flags = vdec_canvas_lock(vdec_core); - if (index >= 0 && - index < AMVDEC_CANVAS_MAX2 + 1) - offset = index; - else if ((index >= AMVDEC_CANVAS_START_INDEX) && - (index <= AMVDEC_CANVAS_MAX1)) - offset = index + AMVDEC_CANVAS_MAX2 + 1 - AMVDEC_CANVAS_START_INDEX; - else { - vdec_canvas_unlock(vdec_core, flags); - return; - } - - if ((canvas_stat[offset].canvas_used_flag > 0) && - (canvas_stat[offset].id & (1 << id))) { - canvas_stat[offset].canvas_used_flag--; - canvas_stat[offset].id &= ~(1 << id); - if (canvas_stat[offset].canvas_used_flag == 0) { - canvas_stat[offset].type = 0; - canvas_stat[offset].id = 0; - } - if (debug & 4) { - pr_debug("free index %d used_flag %d, type = %d, id = %d\n", - offset, - canvas_stat[offset].canvas_used_flag, - canvas_stat[offset].type, - canvas_stat[offset].id); - } - } - vdec_canvas_unlock(vdec_core, flags); - - return; - -} - static void vdec_dmc_pipeline_reset(void) { /* @@ -657,42 +576,143 @@ } } +#define VDEC_ASSIST_DBUS_DISABLE 0x0046 +#define HEVC_ASSIST_AXI_STATUS2_LO 0x307f + +static void vdec_dbus_ctrl(bool enable) +{ + if (enable) { + WRITE_VREG(VDEC_ASSIST_DBUS_DISABLE, 0); + } else { + u32 nop_cnt = 200; + WRITE_VREG(VDEC_ASSIST_DBUS_DISABLE, 0xffff); + while (READ_VREG(VDEC_ASSIST_DBUS_DISABLE) != 0xffff); + while (nop_cnt--); + } +} + +static void hevc_arb_ctrl(bool enable) +{ + u32 axi_ctrl, axi_status, nop_cnt = 200; + + if (enable) { + axi_ctrl = READ_VREG(HEVC_ASSIST_AXI_CTRL); + axi_ctrl &= (~((1 << 6) | (1 << 14))); + WRITE_VREG(HEVC_ASSIST_AXI_CTRL, axi_ctrl); //enable front/back arbitor + } else { + axi_ctrl = READ_VREG(HEVC_ASSIST_AXI_CTRL); + axi_ctrl |= (1 << 6); + WRITE_VREG(HEVC_ASSIST_AXI_CTRL, axi_ctrl); // disable front arbitor + + do { + axi_status = READ_VREG(HEVC_ASSIST_AXI_STATUS); + if (axi_status & ((1 << 15) | (1 << 11))) //read/write disable + break; + } while (1); + + axi_ctrl |= (1 << 14); + WRITE_VREG(HEVC_ASSIST_AXI_CTRL, axi_ctrl); // disable back arbitor + + do { + axi_status = READ_VREG(HEVC_ASSIST_AXI_STATUS2_LO); + if (axi_status & ((1 << 15) | (1 << 11))) //read/write disable + break; + } while (1); + + while (nop_cnt--); + } +} + +static void dec_dmc_port_ctrl(bool dmc_on, u32 target) +{ + unsigned long flags; + unsigned int sts_reg_addr = DMC_CHAN_STS; + unsigned int mask = 0; + unsigned int cpu_type = get_cpu_major_id(); + + if (target == VDEC_INPUT_TARGET_VLD) { + mask = (1 << 13); /*bit13: DOS VDEC interface*/ + if (cpu_type >= AM_MESON_CPU_MAJOR_ID_G12A) + mask = (1 << 21); + } else if (target == VDEC_INPUT_TARGET_HEVC) { + mask = (1 << 4); /*hevc*/ + if (cpu_type >= AM_MESON_CPU_MAJOR_ID_G12A) + mask |= (1 << 8); /*hevcb */ + } + + if (!mask) { + pr_info("debug dmc ctrl return\n"); + return; + } + + if (dmc_on) { + /* dmc async on requset */ + spin_lock_irqsave(&vdec_spin_lock, flags); + + codec_dmcbus_write(DMC_REQ_CTRL, + codec_dmcbus_read(DMC_REQ_CTRL) | mask); + + spin_unlock_irqrestore(&vdec_spin_lock, flags); + } else { + /* dmc async off requset */ + spin_lock_irqsave(&vdec_spin_lock, flags); + + codec_dmcbus_write(DMC_REQ_CTRL, + codec_dmcbus_read(DMC_REQ_CTRL) & ~mask); + + spin_unlock_irqrestore(&vdec_spin_lock, flags); + + switch (cpu_type) { + case AM_MESON_CPU_MAJOR_ID_S4: + case AM_MESON_CPU_MAJOR_ID_S4D: + case AM_MESON_CPU_MAJOR_ID_T5W: + sts_reg_addr = S4_DMC_CHAN_STS; + break; + case AM_MESON_CPU_MAJOR_ID_T5: + case AM_MESON_CPU_MAJOR_ID_T5D: + sts_reg_addr = T5_DMC_CHAN_STS; + break; + case AM_MESON_CPU_MAJOR_ID_SC2: + sts_reg_addr = TM2_REVB_DMC_CHAN_STS; + break; + case AM_MESON_CPU_MAJOR_ID_TM2: + if (is_cpu_meson_revb()) + sts_reg_addr = TM2_REVB_DMC_CHAN_STS; + else + sts_reg_addr = DMC_CHAN_STS; + break; + default: + sts_reg_addr = DMC_CHAN_STS; + break; + } + while (!(codec_dmcbus_read(sts_reg_addr) + & mask)) + ; + } +} + static void vdec_disable_DMC(struct vdec_s *vdec) { /*close first,then wait pedding end,timing suggestion from vlsi*/ struct vdec_input_s *input = &vdec->input; - unsigned long flags; - unsigned int mask = 0; - - if (input->target == VDEC_INPUT_TARGET_VLD) { - mask = (1 << 13); - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) - mask = (1 << 21); - } else if (input->target == VDEC_INPUT_TARGET_HEVC) { - mask = (1 << 4); /*hevc*/ - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) - mask |= (1 << 8); /*hevcb */ - } /* need to stop armrisc. */ if (!IS_ERR_OR_NULL(vdec->dev)) vdec_stop_armrisc(input->target); - spin_lock_irqsave(&vdec_spin_lock, flags); - codec_dmcbus_write(DMC_REQ_CTRL, - codec_dmcbus_read(DMC_REQ_CTRL) & ~mask); - spin_unlock_irqrestore(&vdec_spin_lock, flags); - - if (is_cpu_tm2_revb() || - (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2)) { - while (!(codec_dmcbus_read(TM2_REVB_DMC_CHAN_STS) - & mask)) - ; - } else { - while (!(codec_dmcbus_read(DMC_CHAN_STS) - & mask)) - ; - } + if ((get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T7) || + (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T3)) { + if (input->target == VDEC_INPUT_TARGET_VLD) { + if (!vdec_on(VDEC_1)) + return; + vdec_dbus_ctrl(0); + } else if (input->target == VDEC_INPUT_TARGET_HEVC) { + if (!vdec_on(VDEC_HEVC)) + return; + hevc_arb_ctrl(0); + } + } else + dec_dmc_port_ctrl(0, input->target); pr_debug("%s input->target= 0x%x\n", __func__, input->target); } @@ -700,27 +720,22 @@ static void vdec_enable_DMC(struct vdec_s *vdec) { struct vdec_input_s *input = &vdec->input; - unsigned long flags; - unsigned int mask = 0; - if (input->target == VDEC_INPUT_TARGET_VLD) { - mask = (1 << 13); - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) - mask = (1 << 21); - } else if (input->target == VDEC_INPUT_TARGET_HEVC) { - mask = (1 << 4); /*hevc*/ - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) - mask |= (1 << 8); /*hevcb */ + if ((get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T7) || + (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T3)) { + if (input->target == VDEC_INPUT_TARGET_VLD) + vdec_dbus_ctrl(1); + else if (input->target == VDEC_INPUT_TARGET_HEVC) + hevc_arb_ctrl(1); + return; } /*must to be reset the dmc pipeline if it's g12b.*/ if (get_cpu_type() == AM_MESON_CPU_MAJOR_ID_G12B) vdec_dmc_pipeline_reset(); - spin_lock_irqsave(&vdec_spin_lock, flags); - codec_dmcbus_write(DMC_REQ_CTRL, - codec_dmcbus_read(DMC_REQ_CTRL) | mask); - spin_unlock_irqrestore(&vdec_spin_lock, flags); + dec_dmc_port_ctrl(1, input->target); + pr_debug("%s input->target= 0x%x\n", __func__, input->target); } @@ -852,6 +867,7 @@ int vdec_set_trickmode(struct vdec_s *vdec, unsigned long trickmode) { int r; + if (vdec->set_trickmode) { r = vdec->set_trickmode(vdec, trickmode); @@ -860,6 +876,7 @@ trickmode); return r; } + return -1; } EXPORT_SYMBOL(vdec_set_trickmode); @@ -921,7 +938,9 @@ EXPORT_SYMBOL(vdec_count_info); int vdec_is_support_4k(void) { - return !is_meson_gxl_package_805X(); + return ((!is_meson_gxl_package_805X()) && + (!is_cpu_s4_s805x2()) && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5D)); } EXPORT_SYMBOL(vdec_is_support_4k); @@ -948,6 +967,12 @@ return vdec_core->cma_dev; } +int vdec_get_core_nr(void) +{ + return (int)atomic_read(&vdec_core->vdec_nr); +} +EXPORT_SYMBOL(vdec_get_core_nr); + #ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC static const char * const vdec_device_name[] = { "amvdec_mpeg12", "ammvdec_mpeg12", @@ -1107,7 +1132,6 @@ struct vdec_s *vdec; int type = VDEC_TYPE_SINGLE; int id; - if (is_mult_inc(port->type)) type = (port->type & PORT_TYPE_FRAME) ? VDEC_TYPE_FRAME_BLOCK : @@ -1131,11 +1155,14 @@ INIT_LIST_HEAD(&vdec->list); + init_waitqueue_head(&vdec->idle_wait); + atomic_inc(&vdec_core->vdec_nr); #ifdef CONFIG_AMLOGIC_V4L_VIDEO3 v4lvideo_dec_count_increase(); #endif vdec->id = id; + vdec->video_id = 0xffffffff; vdec_input_init(&vdec->input, vdec); vdec->input.vdec_is_input_frame_empty = vdec_is_input_frame_empty; vdec->input.vdec_up = vdec_up; @@ -1171,6 +1198,7 @@ vdec->slave->format = format; vdec->slave->port_flag |= PORT_FLAG_VFORMAT; } + //trace_vdec_set_format(vdec, format);/*DEBUG_TMP*/ return 0; @@ -1194,6 +1222,34 @@ } EXPORT_SYMBOL(vdec_set_timestamp); +void vdec_set_metadata(struct vdec_s *vdec, ulong meta_ptr) +{ + char *tmp_buf = NULL; + u32 size = 0; + + if (!meta_ptr) + return; + + tmp_buf = vmalloc(META_DATA_SIZE + 4); + if (!tmp_buf) { + pr_err("%s:vmalloc 256+4 fail\n", __func__); + return; + } + memcpy(tmp_buf, (void *)meta_ptr, META_DATA_SIZE + 4); + + size = tmp_buf[0] + (tmp_buf[1] << 8) + + (tmp_buf[2] << 16) + (tmp_buf[3] << 24); + + if ((size > 0) && (size <= META_DATA_SIZE)) { + memcpy(vdec->hdr10p_data_buf, tmp_buf + 4, size); + vdec->hdr10p_data_size = size; + vdec->hdr10p_data_valid = true; + } + + vfree(tmp_buf); +} +EXPORT_SYMBOL(vdec_set_metadata); + int vdec_set_pts64(struct vdec_s *vdec, u64 pts64) { vdec->pts64 = pts64; @@ -1422,6 +1478,8 @@ } EXPORT_SYMBOL(vdec_stream_skip_data); + + /* *get next frame from input chain */ @@ -1579,9 +1637,6 @@ while (READ_VREG(VLD_MEM_SWAP_CTL) & (1<<7)) ; WRITE_VREG(VLD_MEM_SWAP_CTL, 0); -#ifdef VDEC_FCC_SUPPORT - vdec_fcc_jump_back(vdec); -#endif /* restore wrap count */ WRITE_VREG(VLD_MEM_VIFIFO_WRAP_COUNT, @@ -1615,9 +1670,7 @@ & (1<<7)) ; WRITE_VREG(HEVC_STREAM_SWAP_CTRL, 0); -#ifdef VDEC_FCC_SUPPORT - vdec_fcc_jump_back(vdec); -#endif + /* restore stream offset */ WRITE_VREG(HEVC_SHIFT_BYTE_COUNT, input->stream_cookie); @@ -1650,7 +1703,6 @@ else first_set_rp = input->start; } - if (input->target == VDEC_INPUT_TARGET_VLD) { WRITE_VREG(VLD_MEM_VIFIFO_START_PTR, input->start); @@ -1712,6 +1764,57 @@ } EXPORT_SYMBOL(vdec_prepare_input); +u32 vdec_offset_prepare_input(struct vdec_s *vdec, u32 consume_byte, u32 data_offset, u32 data_size) +{ + struct vdec_input_s *input = &vdec->input; + u32 res_byte, header_offset, header_data_size, data_invalid; + + res_byte = data_size - consume_byte; + header_offset = data_offset; + header_data_size = data_size; + data_offset += consume_byte; + data_size = res_byte; + + if (input->target == VDEC_INPUT_TARGET_VLD) { + //to do + } else if (input->target == VDEC_INPUT_TARGET_HEVC) { + data_invalid = data_offset - round_down(data_offset, 0x40); + data_offset -= data_invalid; + data_size += data_invalid; + + if (data_offset < header_offset) { + data_invalid = consume_byte; + data_offset = header_offset; + data_size = header_data_size; + } + + if (input_frame_based(input)) { + struct vframe_chunk_s *chunk = vdec_input_next_chunk(&vdec->input); + struct vframe_block_list_s *block = NULL; + int dummy; + + block = chunk->block; + WRITE_VREG(HEVC_STREAM_START_ADDR, block->start); + WRITE_VREG(HEVC_STREAM_END_ADDR, block->start + + block->size); + WRITE_VREG(HEVC_STREAM_RD_PTR, block->start + + data_offset); + dummy = data_offset + data_size + + HEVC_PADDING_SIZE; + if (dummy >= block->size) + dummy -= block->size; + WRITE_VREG(HEVC_STREAM_WR_PTR, + round_down(block->start + dummy, + VDEC_FIFO_ALIGN)); + + /* set endian */ + SET_VREG_MASK(HEVC_STREAM_CONTROL, 7 << 4); + } + } + return data_invalid; +} +EXPORT_SYMBOL(vdec_offset_prepare_input); + void vdec_enable_input(struct vdec_s *vdec) { struct vdec_input_s *input = &vdec->input; @@ -1909,29 +2012,13 @@ EXPORT_SYMBOL(vdec_need_more_data); -void hevc_wait_ddr(void) +static void hevc_wait_ddr(void) { - unsigned long flags; - unsigned int mask = 0; - - mask = 1 << 4; /* hevc */ - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) - mask |= (1 << 8); /* hevcb */ - - spin_lock_irqsave(&vdec_spin_lock, flags); - codec_dmcbus_write(DMC_REQ_CTRL, - codec_dmcbus_read(DMC_REQ_CTRL) & ~mask); - spin_unlock_irqrestore(&vdec_spin_lock, flags); - - if (is_cpu_tm2_revb() || - (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2)) { - while (!(codec_dmcbus_read(TM2_REVB_DMC_CHAN_STS) - & mask)) - ; + if ((get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T7) || + (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T3)) { + hevc_arb_ctrl(0); } else { - while (!(codec_dmcbus_read(DMC_CHAN_STS) - & mask)) - ; + dec_dmc_port_ctrl(0, VDEC_INPUT_TARGET_HEVC); } } @@ -2248,7 +2335,18 @@ return 0; discon_timeout: pr_err("%s timeout!!! status: 0x%x force it to 2\n", __func__, vdec->status); - vdec_set_status(vdec, VDEC_STATUS_CONNECTED); + if (vdec->status == VDEC_STATUS_ACTIVE) { + if (vdec->input.target == VDEC_INPUT_TARGET_VLD) { + amvdec_stop(); + WRITE_VREG(ASSIST_MBOX1_MASK, 0); + vdec_free_irq(VDEC_IRQ_1, NULL); + } else if (vdec->input.target == VDEC_INPUT_TARGET_HEVC) { + amhevc_stop(); + WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG, 0); + vdec_free_irq(VDEC_IRQ_0, NULL); + } + } + return 0; } EXPORT_SYMBOL(vdec_disconnect); @@ -2284,41 +2382,10 @@ true : false; } -static bool is_nontunnel_pipeline(u32 pl) +static bool is_res_locked(u32 pre, u32 cur) { - return (pl & BIT(FRAME_BASE_PATH_DI_V4LVIDEO)) ? true : false; -} - -static bool is_v4lvideo_already_used(u32 pre, int vf_receiver_inst) -{ - if (vf_receiver_inst == 0) { - if (pre & BIT(FRAME_BASE_PATH_DI_V4LVIDEO_0)) { - return true; - } - } else if (vf_receiver_inst == 1) { - if (pre & BIT(FRAME_BASE_PATH_DI_V4LVIDEO_1)) { - return true; - } - } else if (vf_receiver_inst == 2) { - if (pre & BIT(FRAME_BASE_PATH_DI_V4LVIDEO_2)) { - return true; - } - } - return false; -} - -static bool is_res_locked(u32 pre, u32 cur, int vf_receiver_inst) -{ - if (is_tunnel_pipeline(pre)) { - if (is_tunnel_pipeline(cur)) { - return true; - } - } else if (is_nontunnel_pipeline(cur)) { - if (is_v4lvideo_already_used(pre,vf_receiver_inst)) { - return true; - } - } - return false; + return is_tunnel_pipeline(pre) ? + (is_tunnel_pipeline(cur) ? true : false) : false; } int vdec_resource_checking(struct vdec_s *vdec) @@ -2329,9 +2396,9 @@ * pipeline these are being released. */ ulong expires = jiffies + msecs_to_jiffies(2000); + while (is_res_locked(vdec_core->vdec_resouce_status, - BIT(vdec->frame_base_video_path), - vdec->vf_receiver_inst)) { + BIT(vdec->frame_base_video_path))) { if (time_after(jiffies, expires)) { pr_err("wait vdec resource timeout.\n"); return -EBUSY; @@ -2347,29 +2414,32 @@ *register vdec_device * create output, vfm or create ionvideo output */ -s32 vdec_init(struct vdec_s *vdec, int is_4k) +s32 vdec_init(struct vdec_s *vdec, int is_4k, bool is_v4l) { int r = 0; struct vdec_s *p = vdec; - const char *dev_name; + const char *pdev_name; + char dev_name[32] = {0}; int id = PLATFORM_DEVID_AUTO;/*if have used my self*/ int max_di_count = max_di_instance; - + char postprocess_name[64] = {0}; if (vdec_stream_based(vdec)) max_di_count = max_supported_di_instance; - + vdec->is_v4l = is_v4l ? 1 : 0; if (is_res_locked(vdec_core->vdec_resouce_status, - BIT(vdec->frame_base_video_path), - vdec->vf_receiver_inst)) + BIT(vdec->frame_base_video_path))) return -EBUSY; - //pr_err("%s [pid=%d,tgid=%d]\n", __func__, current->pid, current->tgid); - dev_name = get_dev_name(vdec_single(vdec), vdec->format); - if (dev_name == NULL) + //pr_err("%s [pid=%d,tgid=%d]\n", __func__, current->pid, current->tgid); + pdev_name = get_dev_name(vdec_single(vdec), vdec->format); + if (pdev_name == NULL) return -ENODEV; - pr_info("vdec_init, dev_name:%s, vdec_type=%s id = %d\n", - dev_name, vdec_type_str(vdec), vdec->id); + snprintf(dev_name, sizeof(dev_name), + "%s%s", pdev_name, is_v4l ? "_v4l": ""); + + pr_info("vdec_init, dev_name:%s, vdec_type=%s, format: %d\n", + dev_name, vdec_type_str(vdec), vdec->format); snprintf(vdec->name, sizeof(vdec->name), "vdec-%d", vdec->id); @@ -2409,24 +2479,31 @@ if (vdec_single(vdec) || (vdec_get_debug_flags() & 0x2)) vdec_enable_DMC(vdec); p->cma_dev = vdec_core->cma_dev; - p->get_canvas = get_canvas; - p->get_canvas_ex = get_canvas_ex; - p->free_canvas_ex = free_canvas_ex; + + vdec_canvas_port_register(vdec); + p->vdec_fps_detec = vdec_fps_detec; /* todo */ if (!vdec_dual(vdec)) { p->use_vfm_path = - (is_support_no_parser()) ? + is_support_no_parser() ? vdec_single(vdec) : vdec_stream_based(vdec); } + if (debugflags & (1 << 29)) + p->is_stream_mode_dv_multi = true; + else + p->is_stream_mode_dv_multi = false; + if (debugflags & 0x4) p->use_vfm_path = 1; /* vdec_dev_reg.flag = 0; */ if (vdec->id >= 0) id = vdec->id; p->parallel_dec = parallel_decode; + p->prog_only = prog_only; + vdec_core->parallel_dec = parallel_decode; vdec->canvas_mode = CANVAS_BLKMODE_32X32; #ifdef FRAME_CHECK @@ -2489,7 +2566,7 @@ if (p->use_vfm_path) { vdec->vf_receiver_inst = -1; vdec->vfm_map_id[0] = 0; - } else if (!vdec_dual(vdec)) { + } else if (!vdec_dual(vdec) && !vdec->disable_vfm) { /* create IONVIDEO instance and connect decoder's * vf_provider interface to it */ @@ -2609,21 +2686,32 @@ mutex_unlock(&vdec_mutex); goto error; } - if (!v4lvideo_add_di) + if (v4lvideo_add_ppmgr) + snprintf(postprocess_name, sizeof(postprocess_name), + "%s ", "ppmgr"); + if (debug_vdetect && (vdec->vf_receiver_inst == 0)) + snprintf(postprocess_name + strlen(postprocess_name), sizeof(postprocess_name), + "%s ", "vdetect.0"); + /* 8K remove di */ + if ((vdec->sys_info->width * vdec->sys_info->height > (4096 * 2304)) + || (!v4lvideo_add_di)) snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE, - "%s %s", vdec->vf_provider_name, + "%s %s%s", vdec->vf_provider_name, + postprocess_name, vdec->vf_receiver_name); else { if ((vdec->vf_receiver_inst == 0) && (max_di_count > 0)) if (max_di_count == 1) snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE, - "%s %s %s", vdec->vf_provider_name, + "%s %s%s %s", vdec->vf_provider_name, + postprocess_name, "deinterlace", vdec->vf_receiver_name); else snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE, - "%s %s %s", vdec->vf_provider_name, + "%s %s%s %s", vdec->vf_provider_name, + postprocess_name, "dimulti.1", vdec->vf_receiver_name); else if ((vdec->vf_receiver_inst < @@ -2685,6 +2773,27 @@ "amlvideo amvideo"); snprintf(vdec->vfm_map_id, VDEC_MAP_NAME_SIZE, "vdec-map-%d", vdec->id); + } else if (p->frame_base_video_path == + FRAME_BASE_PATH_V4LVIDEO_FENCE) { +#ifdef CONFIG_AMLOGIC_V4L_VIDEO3 + r = v4lvideo_assign_map(&vdec->vf_receiver_name, + &vdec->vf_receiver_inst); +#else + r = -1; +#endif + if (r < 0) { + pr_err("V4lVideo frame receiver allocation failed.\n"); + mutex_lock(&vdec_mutex); + inited_vcodec_num--; + mutex_unlock(&vdec_mutex); + goto error; + } + + snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE, + "%s %s", vdec->vf_provider_name, + vdec->vf_receiver_name); + snprintf(vdec->vfm_map_id, VDEC_MAP_NAME_SIZE, + "vdec-map-%d", vdec->id); } if (vfm_map_add(vdec->vfm_map_id, @@ -2720,7 +2829,7 @@ } - if (!vdec_single(vdec)) { + if (!vdec_single(vdec) && !vdec->disable_vfm) { vf_reg_provider(&p->vframe_provider); vf_notify_receiver(p->vf_provider_name, @@ -2752,15 +2861,6 @@ mutex_lock(&vdec_mutex); vdec_core->vdec_resouce_status |= BIT(p->frame_base_video_path); - if (p->frame_base_video_path == FRAME_BASE_PATH_DI_V4LVIDEO) { - if (p->vf_receiver_inst == 0) { - vdec_core->vdec_resouce_status |= BIT(FRAME_BASE_PATH_DI_V4LVIDEO_0); - } else if (p->vf_receiver_inst == 1) { - vdec_core->vdec_resouce_status |= BIT(FRAME_BASE_PATH_DI_V4LVIDEO_1); - } else if (p->vf_receiver_inst == 2) { - vdec_core->vdec_resouce_status |= BIT(FRAME_BASE_PATH_DI_V4LVIDEO_2); - } - } mutex_unlock(&vdec_mutex); vdec_input_prepare_bufs(/*prepared buffer for fast playing.*/ @@ -2769,13 +2869,6 @@ vdec->sys_info->height); /* vdec is now ready to be active */ vdec_set_status(vdec, VDEC_STATUS_DISCONNECTED); - -#ifdef VDEC_FCC_SUPPORT - init_waitqueue_head(&vdec->jump_back_wq); - mutex_init(&vdec->jump_back_mutex); - vdec->fcc_mode = FCC_BUTT; - vdec->fcc_status = STATUS_BUTT; -#endif return 0; error: @@ -2815,6 +2908,36 @@ vdec_core_unlock(core, flags); } +st_userdata *get_vdec_userdata_ctx() +{ + return &userdata; +} +EXPORT_SYMBOL(get_vdec_userdata_ctx); + +static void vdec_userdata_ctx_release(struct vdec_s *vdec) +{ + int i; + st_userdata *userdata = get_vdec_userdata_ctx(); + + mutex_lock(&userdata->mutex); + + for (i = 0; i < MAX_USERDATA_CHANNEL_NUM; i++) { + if (userdata->used[i] == 1 && vdec->video_id != 0xffffffff) { + if (vdec_get_debug_flags() & 0x10000000) + pr_info("ctx_release i: %d userdata.id %d\n", + i, userdata->id[i]); + userdata->ready_flag[i] = 0; + userdata->id[i] = -1; + userdata->used[i] = 0; + userdata->set_id_flag = 0; + } + } + + mutex_unlock(&userdata->mutex); + + return; +} + /* vdec_create/init/release/destroy are applied to both dual running decoders */ void vdec_release(struct vdec_s *vdec) @@ -2831,10 +2954,10 @@ } #endif /* When release, userspace systemctl need this duration 0 event */ - vframe_rate_uevent(0); + vdec_frame_rate_uevent(0); vdec_disconnect(vdec); - if (vdec->vframe_provider.name) { + if (!vdec->disable_vfm && vdec->vframe_provider.name) { if (!vdec_single(vdec)) { if (vdec_core->hint_fr_vdec == vdec && vdec->fr_hint_state == VDEC_HINTED) @@ -2887,27 +3010,20 @@ if (vdec->vbuf.ops && !vdec->master) vdec->vbuf.ops->release(&vdec->vbuf); - pr_debug("vdec_release instance %p, total %d id = %d\n", vdec, - atomic_read(&vdec_core->vdec_nr), vdec->id); + vdec_userdata_ctx_release(vdec); + + pr_debug("vdec_release instance %p, total %d\n", vdec, + atomic_read(&vdec_core->vdec_nr)); mutex_lock(&vdec_mutex); - if (vdec->frame_base_video_path == FRAME_BASE_PATH_DI_V4LVIDEO) { - if (vdec->vf_receiver_inst == 0) { - vdec_core->vdec_resouce_status &= ~BIT(FRAME_BASE_PATH_DI_V4LVIDEO_0); - } else if (vdec->vf_receiver_inst == 1) { - vdec_core->vdec_resouce_status &= ~BIT(FRAME_BASE_PATH_DI_V4LVIDEO_1); - } else if (vdec->vf_receiver_inst == 2) { - vdec_core->vdec_resouce_status &= ~BIT(FRAME_BASE_PATH_DI_V4LVIDEO_2); - } - } vdec_core->vdec_resouce_status &= ~BIT(vdec->frame_base_video_path); mutex_unlock(&vdec_mutex); - vdec_destroy(vdec); mutex_lock(&vdec_mutex); inited_vcodec_num--; mutex_unlock(&vdec_mutex); + } EXPORT_SYMBOL(vdec_release); @@ -2919,11 +3035,13 @@ vdec_disconnect(vdec); - if (vdec->vframe_provider.name) - vf_unreg_provider(&vdec->vframe_provider); + if (!vdec->disable_vfm) { + if (vdec->vframe_provider.name) + vf_unreg_provider(&vdec->vframe_provider); - if ((vdec->slave) && (vdec->slave->vframe_provider.name)) - vf_unreg_provider(&vdec->slave->vframe_provider); + if ((vdec->slave) && (vdec->slave->vframe_provider.name)) + vf_unreg_provider(&vdec->slave->vframe_provider); + } if (vdec->reset) { vdec->reset(vdec); @@ -2938,15 +3056,17 @@ vdec_input_prepare_bufs(&vdec->input, vdec->sys_info->width, vdec->sys_info->height); - vf_reg_provider(&vdec->vframe_provider); - vf_notify_receiver(vdec->vf_provider_name, - VFRAME_EVENT_PROVIDER_START, vdec); + if (!vdec->disable_vfm) { + vf_reg_provider(&vdec->vframe_provider); + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_START, vdec); - if (vdec->slave) { - vf_reg_provider(&vdec->slave->vframe_provider); - vf_notify_receiver(vdec->slave->vf_provider_name, - VFRAME_EVENT_PROVIDER_START, vdec->slave); - vdec->slave->mc_loaded = 0;/*clear for reload firmware*/ + if (vdec->slave) { + vf_reg_provider(&vdec->slave->vframe_provider); + vf_notify_receiver(vdec->slave->vf_provider_name, + VFRAME_EVENT_PROVIDER_START, vdec->slave); + vdec->slave->mc_loaded = 0;/*clear for reload firmware*/ + } } vdec_connect(vdec); @@ -2961,11 +3081,13 @@ pr_debug("vdec_v4l2_reset %d\n", flag); vdec_disconnect(vdec); if (flag != 2) { - if (vdec->vframe_provider.name) - vf_unreg_provider(&vdec->vframe_provider); + if (!vdec->disable_vfm) { + if (vdec->vframe_provider.name) + vf_unreg_provider(&vdec->vframe_provider); - if ((vdec->slave) && (vdec->slave->vframe_provider.name)) - vf_unreg_provider(&vdec->slave->vframe_provider); + if ((vdec->slave) && (vdec->slave->vframe_provider.name)) + vf_unreg_provider(&vdec->slave->vframe_provider); + } if (vdec->reset) { vdec->reset(vdec); @@ -2981,15 +3103,17 @@ vdec_input_prepare_bufs(&vdec->input, vdec->sys_info->width, vdec->sys_info->height); - vf_reg_provider(&vdec->vframe_provider); - vf_notify_receiver(vdec->vf_provider_name, - VFRAME_EVENT_PROVIDER_START, vdec); + if (!vdec->disable_vfm) { + vf_reg_provider(&vdec->vframe_provider); + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_START, vdec); - if (vdec->slave) { - vf_reg_provider(&vdec->slave->vframe_provider); - vf_notify_receiver(vdec->slave->vf_provider_name, - VFRAME_EVENT_PROVIDER_START, vdec->slave); - vdec->slave->mc_loaded = 0;/*clear for reload firmware*/ + if (vdec->slave) { + vf_reg_provider(&vdec->slave->vframe_provider); + vf_notify_receiver(vdec->slave->vf_provider_name, + VFRAME_EVENT_PROVIDER_START, vdec->slave); + vdec->slave->mc_loaded = 0;/*clear for reload firmware*/ + } } } else { if (vdec->reset) { @@ -3001,13 +3125,10 @@ vdec_connect(vdec); - vdec_frame_check_init(vdec); - return 0; } EXPORT_SYMBOL(vdec_v4l2_reset); - void vdec_free_cmabuf(void) { mutex_lock(&vdec_mutex); @@ -3070,8 +3191,10 @@ t &= ~(1 << i); } - if (vdec->active_mask == 0) + if (vdec->active_mask == 0) { vdec_set_status(vdec, VDEC_STATUS_CONNECTED); + wake_up_interruptible(&vdec->idle_wait); + } mutex_unlock(&vdec_mutex); } @@ -3202,6 +3325,30 @@ return ret; } +int vdec_check_rec_num_enough(struct vdec_s *vdec) { + + if (vdec->vbuf.use_ptsserv) { + return (pts_get_rec_num(PTS_TYPE_VIDEO, + vdec->input.total_rd_count) >= 2); + } else { + u64 total_rd_count = vdec->input.total_rd_count; + + if (vdec->input.target == VDEC_INPUT_TARGET_VLD) { + //total_rd_count -= vdec->input.start; + /*just like use ptsserv, alway return true*/ + return 1; + } + if ((total_rd_count >= vdec->vbuf.last_offset[0]) && + (total_rd_count - vdec->vbuf.last_offset[0] < 0x80000000)) + return 0; + else if ((total_rd_count >= vdec->vbuf.last_offset[1]) && + (total_rd_count - vdec->vbuf.last_offset[1] < 0x80000000)) + return 0; + + return 1; + } +} + unsigned long vdec_ready_to_run(struct vdec_s *vdec, unsigned long mask) { unsigned long ready_mask; @@ -3229,7 +3376,6 @@ inc_profi_count(mask, vdec->check_count); #endif if (vdec_core_with_input(mask)) { - /* check frame based input underrun */ if (input && !input->eos && input_frame_based(input) && (!vdec_input_next_chunk(input))) { @@ -3250,8 +3396,7 @@ level = wp - rp; if ((level < input->prepare_level) && - (pts_get_rec_num(PTS_TYPE_VIDEO, - vdec->input.total_rd_count) < 2)) { + !vdec_check_rec_num_enough(vdec)) { vdec->need_more_data |= VDEC_NEED_MORE_DATA; #ifdef VDEC_DEBUG_SUPPORT inc_profi_count(mask, vdec->input_underrun_count); @@ -3320,6 +3465,9 @@ * Perform need_more_data checking and set flag is decoder * is not consuming data. */ +#define DMC_DEV_TYPE_NON_SECURE 0 +#define DMC_DEV_TYPE_SECURE 1 + void vdec_prepare_run(struct vdec_s *vdec, unsigned long mask) { struct vdec_input_s *input = &vdec->input; @@ -3333,12 +3481,12 @@ if (vdec_stream_based(vdec) && !vdec_secure(vdec)) { - tee_config_device_secure(DMC_DEV_ID_PARSER, 0); + tee_config_device_state(DMC_DEV_ID_PARSER, 0); } if (input->target == VDEC_INPUT_TARGET_VLD) - tee_config_device_secure(DMC_DEV_ID_VDEC, secure); + tee_config_device_state(DMC_DEV_ID_VDEC, secure); else if (input->target == VDEC_INPUT_TARGET_HEVC) - tee_config_device_secure(DMC_DEV_ID_HEVC, secure); + tee_config_device_state(DMC_DEV_ID_HEVC, secure); if (vdec_stream_based(vdec) && ((vdec->need_more_data & VDEC_NEED_MORE_DATA_RUN) && @@ -3350,7 +3498,6 @@ vdec->need_more_data &= ~VDEC_NEED_MORE_DATA_DIRTY; } - /* struct vdec_core_shread manages all decoder instance in active list. When * a vdec is added into the active list, it can onlt be in two status: * VDEC_STATUS_CONNECTED(the decoder does not own HW resource and ready to run) @@ -3550,7 +3697,6 @@ inc_profi_count(mask, vdec->run_count); update_profi_clk_run(vdec, mask, get_current_clk()); #endif - vdec->run(vdec, mask, vdec_callback, core); @@ -3650,6 +3796,7 @@ } EXPORT_SYMBOL(vdec_power_reset); + void vdec_poweron(enum vdec_type_e core) { if (core >= VDEC_MAX) @@ -3797,27 +3944,12 @@ void vdec_reset_core(struct vdec_s *vdec) { - unsigned long flags; - unsigned int mask = 0; - - mask = 1 << 13; /*bit13: DOS VDEC interface*/ - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) - mask = 1 << 21; /*bit21: DOS VDEC interface*/ - - spin_lock_irqsave(&vdec_spin_lock, flags); - codec_dmcbus_write(DMC_REQ_CTRL, - codec_dmcbus_read(DMC_REQ_CTRL) & ~mask); - spin_unlock_irqrestore(&vdec_spin_lock, flags); - - if (is_cpu_tm2_revb() || - (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2)) { - while (!(codec_dmcbus_read(TM2_REVB_DMC_CHAN_STS) - & mask)) - ; + if ((get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T7) || + (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T3)) { + /* t7 no dmc req for vdec only */ + vdec_dbus_ctrl(0); } else { - while (!(codec_dmcbus_read(DMC_CHAN_STS) - & mask)) - ; + dec_dmc_port_ctrl(0, VDEC_INPUT_TARGET_VLD); } /* * 2: assist @@ -3837,10 +3969,11 @@ WRITE_VREG(DOS_SW_RESET0, (1<<3)|(1<<4)|(1<<5)|(1<<7)|(1<<8)|(1<<9)); WRITE_VREG(DOS_SW_RESET0, 0); - spin_lock_irqsave(&vdec_spin_lock, flags); - codec_dmcbus_write(DMC_REQ_CTRL, - codec_dmcbus_read(DMC_REQ_CTRL) | mask); - spin_unlock_irqrestore(&vdec_spin_lock, flags); + if ((get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T7) || + (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T3)) + vdec_dbus_ctrl(1); + else + dec_dmc_port_ctrl(1, VDEC_INPUT_TARGET_VLD); } EXPORT_SYMBOL(vdec_reset_core); @@ -3880,39 +4013,25 @@ void hevc_reset_core(struct vdec_s *vdec) { - unsigned long flags; - unsigned int mask = 0; - int cpu_type; + int cpu_type = get_cpu_major_id(); - mask = 1 << 4; /*bit4: hevc*/ - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) - mask |= 1 << 8; /*bit8: hevcb*/ - - WRITE_VREG(HEVC_STREAM_CONTROL, 0); - spin_lock_irqsave(&vdec_spin_lock, flags); - codec_dmcbus_write(DMC_REQ_CTRL, - codec_dmcbus_read(DMC_REQ_CTRL) & ~mask); - spin_unlock_irqrestore(&vdec_spin_lock, flags); - - if (is_cpu_tm2_revb() || - (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2)) { - while (!(codec_dmcbus_read(TM2_REVB_DMC_CHAN_STS) - & mask)) - ; + if ((cpu_type == AM_MESON_CPU_MAJOR_ID_T7) || + (cpu_type == AM_MESON_CPU_MAJOR_ID_T3)) { + /* t7 no dmc req for hevc only */ + hevc_arb_ctrl(0); } else { - while (!(codec_dmcbus_read(DMC_CHAN_STS) - & mask)) - ; + WRITE_VREG(HEVC_STREAM_CONTROL, 0); + + dec_dmc_port_ctrl(0, VDEC_INPUT_TARGET_HEVC); } if (vdec == NULL || input_frame_based(vdec)) WRITE_VREG(HEVC_STREAM_CONTROL, 0); - WRITE_VREG(HEVC_SAO_MMU_RESET_CTRL, READ_VREG(HEVC_SAO_MMU_RESET_CTRL) | 1); - /* + /* * 2: assist * 3: parser * 4: parser_state @@ -3929,25 +4048,17 @@ * 24:hevc_afifo * 26:rst_mmu_n */ - if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2) && - (vdec->format == VFORMAT_AVS2)) { - WRITE_VREG(DOS_SW_RESET3, - (1<<3)|(1<<4)|(1<<8)|(1<<11)| - (1<<12)|(1<<14)|(1<<15)| - (1<<17)|(1<<18)|(1<<19)); - } else { - WRITE_VREG(DOS_SW_RESET3, - (1<<3)|(1<<4)|(1<<8)|(1<<10)|(1<<11)| - (1<<12)|(1<<13)|(1<<14)|(1<<15)| - (1<<17)|(1<<18)|(1<<19)|(1<<24)|(1<<26)); - } + WRITE_VREG(DOS_SW_RESET3, + (1<<3)|(1<<4)|(1<<8)|(1<<10)|(1<<11)| + (1<<12)|(1<<13)|(1<<14)|(1<<15)| + (1<<17)|(1<<18)|(1<<19)|(1<<24)|(1<<26)); WRITE_VREG(DOS_SW_RESET3, 0); while (READ_VREG(HEVC_WRRSP_LMEM) & 0xfff) ; WRITE_VREG(HEVC_SAO_MMU_RESET_CTRL, READ_VREG(HEVC_SAO_MMU_RESET_CTRL) & (~1)); - cpu_type = get_cpu_major_id(); + if (cpu_type == AM_MESON_CPU_MAJOR_ID_TL1 && is_meson_rev_b()) cpu_type = AM_MESON_CPU_MAJOR_ID_G12B; @@ -3962,12 +4073,17 @@ case AM_MESON_CPU_MAJOR_ID_SM1: case AM_MESON_CPU_MAJOR_ID_TL1: case AM_MESON_CPU_MAJOR_ID_TM2: + case AM_MESON_CPU_MAJOR_ID_T5: + case AM_MESON_CPU_MAJOR_ID_T5D: + case AM_MESON_CPU_MAJOR_ID_T5W: WRITE_RESET_REG((RESET7_REGISTER_LEVEL), READ_RESET_REG(RESET7_REGISTER_LEVEL) & (~((1<<13)))); WRITE_RESET_REG((RESET7_REGISTER_LEVEL), READ_RESET_REG((RESET7_REGISTER_LEVEL)) | ((1<<13))); break; case AM_MESON_CPU_MAJOR_ID_SC2: + case AM_MESON_CPU_MAJOR_ID_S4: + case AM_MESON_CPU_MAJOR_ID_S4D: WRITE_RESET_REG(P_RESETCTRL_RESET5_LEVEL, READ_RESET_REG(P_RESETCTRL_RESET5_LEVEL) & (~((1<<1)|(1<<12)|(1<<13)))); WRITE_RESET_REG(P_RESETCTRL_RESET5_LEVEL, @@ -3977,12 +4093,11 @@ break; } - - spin_lock_irqsave(&vdec_spin_lock, flags); - codec_dmcbus_write(DMC_REQ_CTRL, - codec_dmcbus_read(DMC_REQ_CTRL) | mask); - spin_unlock_irqrestore(&vdec_spin_lock, flags); - + if ((cpu_type == AM_MESON_CPU_MAJOR_ID_T7) || + (cpu_type == AM_MESON_CPU_MAJOR_ID_T3)) + hevc_arb_ctrl(1); + else + dec_dmc_port_ctrl(1, VDEC_INPUT_TARGET_HEVC); } EXPORT_SYMBOL(hevc_reset_core); @@ -4130,7 +4245,7 @@ int i; char *pbuf = buf; ssize_t ret; - u16 *trace_buf = vzalloc(debug_trace_num * 2); + u16 *trace_buf = kmalloc(debug_trace_num * 2, GFP_KERNEL); if (!trace_buf) { pbuf += sprintf(pbuf, "No Memory bug\n"); @@ -4141,7 +4256,7 @@ mutex_lock(&vdec_mutex); if (!vdec_on(VDEC_1)) { mutex_unlock(&vdec_mutex); - vfree(trace_buf); + kfree(trace_buf); pbuf += sprintf(pbuf, "amrisc is power off\n"); ret = pbuf - buf; return ret; @@ -4197,7 +4312,7 @@ } while (i < debug_trace_num) ; - vfree(trace_buf); + kfree(trace_buf); pbuf += sprintf(pbuf, "\n"); ret = pbuf - buf; return ret; @@ -4241,8 +4356,7 @@ return count; } - -static ssize_t store_poweron_clock_level(struct class *class, +static ssize_t poweron_clock_level_store(struct class *class, struct class_attribute *attr, const char *buf, size_t size) { @@ -4258,7 +4372,7 @@ return size; } -static ssize_t show_poweron_clock_level(struct class *class, +static ssize_t poweron_clock_level_show(struct class *class, struct class_attribute *attr, char *buf) { return sprintf(buf, "%d\n", poweron_clock_level); @@ -4269,7 +4383,7 @@ *always don't release *vdec 64 memory for fast play. */ -static ssize_t store_keep_vdec_mem(struct class *class, +static ssize_t keep_vdec_mem_store(struct class *class, struct class_attribute *attr, const char *buf, size_t size) { @@ -4284,15 +4398,14 @@ return size; } -static ssize_t show_keep_vdec_mem(struct class *class, +static ssize_t keep_vdec_mem_show(struct class *class, struct class_attribute *attr, char *buf) { return sprintf(buf, "%d\n", keep_vdec_mem); } - #ifdef VDEC_DEBUG_SUPPORT -static ssize_t store_debug(struct class *class, +static ssize_t debug_store(struct class *class, struct class_attribute *attr, const char *buf, size_t size) { @@ -4331,6 +4444,10 @@ "VDEC_DEBUG: HHI_VDEC4_CLK_CNTL = 0x%x, HHI_VDEC2_CLK_CNTL = 0x%x\n", READ_HHI_REG(HHI_VDEC4_CLK_CNTL), READ_HHI_REG(HHI_VDEC2_CLK_CNTL)); + } else if (strcmp(cbuf, "no_interlace") == 0) { + prog_only ^= 1; + pr_info("set prog only %d, %s output\n", + prog_only, prog_only?"force one filed only":"interlace"); } flags = vdec_core_lock(vdec_core); @@ -4349,7 +4466,7 @@ return size; } -static ssize_t show_debug(struct class *class, +static ssize_t debug_show(struct class *class, struct class_attribute *attr, char *buf) { char *pbuf = buf; @@ -4375,6 +4492,8 @@ pbuf += sprintf(pbuf, "read_hevc_clk_reg - read HHI register for hevc clk\n"); pbuf += sprintf(pbuf, + "no_interlace - force v4l no_interlace output. %d\n", prog_only); + pbuf += sprintf(pbuf, "===================\n"); pbuf += sprintf(pbuf, @@ -4412,7 +4531,6 @@ } #endif - int show_stream_buffer_status(char *buf, int (*callback) (struct stream_buf_s *, char *)) { @@ -4436,7 +4554,7 @@ } EXPORT_SYMBOL(show_stream_buffer_status); -static ssize_t store_vdec_vfm_path(struct class *class, +static ssize_t vdec_vfm_path_store(struct class *class, struct class_attribute *attr, const char *buf, size_t count) { @@ -4495,7 +4613,7 @@ return count; } -static ssize_t show_vdec_vfm_path(struct class *class, +static ssize_t vdec_vfm_path_show(struct class *class, struct class_attribute *attr, char *buf) { int len = 0; @@ -4550,7 +4668,6 @@ vdec_core->isr_context[num].dev_isr = handler; vdec_core->isr_context[num].dev_threaded_isr = thread_fn; vdec_core->isr_context[num].dev_id = dev; - ret = request_threaded_irq(res_irq, vdec_isr, vdec_thread_isr, @@ -4608,6 +4725,20 @@ } EXPORT_SYMBOL(vdec_free_irq); +void vdec_sync_irq(enum vdec_irq_num num) +{ +#if 0 + if (!vdec) + return; + if (vdec->input.target == VDEC_INPUT_TARGET_HEVC) + synchronize_irq(vdec_core->isr_context[VDEC_IRQ_0].irq); + else (vdec->input.target == VDEC_INPUT_TARGET_VLD) + synchronize_irq(vdec_core->isr_context[VDEC_IRQ_1].irq); +#endif + synchronize_irq(vdec_core->isr_context[num].irq); +} +EXPORT_SYMBOL(vdec_sync_irq); + struct vdec_s *vdec_get_default_vdec_for_userdata(void) { struct vdec_s *vdec; @@ -4734,192 +4865,6 @@ } EXPORT_SYMBOL(vdec_set_profile_level); -#ifdef VDEC_FCC_SUPPORT -int vdec_wakeup_fcc_poll(struct vdec_s *vdec) -{ - if (vdec) { - if (vdec->wakeup_fcc_poll) - vdec->wakeup_fcc_poll(vdec); - } - - return 0; -} -EXPORT_SYMBOL(vdec_wakeup_fcc_poll); - -int vdec_has_get_fcc_new_msg(struct vdec_s *vdec) -{ - int ret = 1; - - if (vdec == NULL) { - pr_info("Error, invalid vdec instance!\n"); - return 0; - } - - if (input_stream_based(vdec)) { - if (vdec->fcc_mode == FCC_DISCARD_MODE && - vdec->fcc_status == STATUS_BUTT) { - ret = 1; - vdec->fcc_status = AGAIN_STATUS; - } else if (vdec->fcc_mode == FCC_DEC_MODE && - vdec->fcc_status != SWITCH_DONE_STATUS) { - ret = 1; - - if (wait_event_interruptible_timeout(vdec->jump_back_wq, vdec->jump_back_done | vdec->jump_back_error, - HZ / 2) <= 0) { - pr_info("[%d][FCC]: Error! Wait jump back wp timeout 500ms!\n", - vdec->id); - vdec->fcc_status = SWITCH_DONE_STATUS; - } else { - if (fcc_debug_enable()) - pr_info("[%d][FCC]: jump_back_done = %d\n", - vdec->id, vdec->jump_back_done); - if (vdec->jump_back_done) { - vdec->fcc_status = JUMP_BACK_STATUS; - vdec->jump_back_done = 0; - } else { - vdec->fcc_status = SWITCH_DONE_STATUS; - vdec->jump_back_error = 0; - } - } - - if (fcc_debug_enable()) - pr_info("[%d][FCC]: It is DEC mode now! fcc_status: %d\n", - vdec->id, vdec->fcc_status); - } else if (vdec->fcc_mode == FCC_DISCARD_MODE && - !vdec->fcc_new_msg) { - if (vdec->fcc_status == WAIT_MSG_STATUS) { - if (fcc_debug_enable()) - pr_info("[%d][FCC]: Wait msg!\n", vdec->id); - ret = 0; - } else { - if (fcc_debug_enable()) - pr_info("[%d][FCC]: Continue to find header!\n", vdec->id); - ret = 1; - } - } else if (vdec->fcc_new_msg) { - if (fcc_debug_enable()) - pr_info("[%d][FCC]: Got discard msg!\n", vdec->id); - ret = 1; - vdec->fcc_new_msg = 0; - if (vdec->fcc_mode == FCC_DISCARD_MODE) { - vdec->fcc_status = DISCARD_STATUS; - } - } - } - - return ret; -} -EXPORT_SYMBOL(vdec_has_get_fcc_new_msg); -void vdec_set_dmc_urgent(struct vdec_s *vdec, int urgentType) -{ -#ifndef DMC_AXI4_G12_CHAN_CTRL -#define DMC_AXI4_G12_CHAN_CTRL (0x90 << 2) -#endif -#define DMC_URGENT_TYPE_NORMAL 1 -#define DMC_URGENT_TYPE_URGENT 2 -#define DMC_URGENT_TYPE_SUPERURGENT 4 - - if (vdec) { - if (urgentType == DMC_URGENT_TYPE_NORMAL || - urgentType == DMC_URGENT_TYPE_URGENT || - urgentType == DMC_URGENT_TYPE_SUPERURGENT) { - int type; - unsigned int val; - - type = vdec_get_hw_type(vdec->port->vformat); - if (type == CORE_MASK_HEVC) { - if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_G12A) { - val = READ_DMCREG(DMC_AXI4_CHAN_CTRL); - val &= (~(0x7 << 16)); - val |= ((urgentType & 0x7) << 16); - WRITE_DMCREG(DMC_AXI4_CHAN_CTRL, val); - } else { - val = READ_DMCREG(DMC_AXI4_G12_CHAN_CTRL); - val &= (~(0x7 << 16)); - val |= ((urgentType & 0x7) << 16); - WRITE_DMCREG(DMC_AXI4_G12_CHAN_CTRL, val); - } - } - } - } - -} -EXPORT_SYMBOL(vdec_set_dmc_urgent); - -int fcc_debug_enable(void) -{ - return fcc_debug; -} -EXPORT_SYMBOL(fcc_debug_enable); - -static void vdec_fcc_jump_back(struct vdec_s *vdec) -{ - u32 cur_rp, set_rp; - struct vdec_input_s *input = &vdec->input; - - if (fcc_debug_enable()) - pr_info("[%d][FCC]: fcc_mode = %d fcc_status = %d\n", - vdec->id, vdec->fcc_mode, vdec->fcc_status); - - if (input->target == VDEC_INPUT_TARGET_VLD) { - if (vdec->fcc_mode == FCC_DEC_MODE && - vdec->fcc_status == JUMP_BACK_STATUS) { - set_rp = vdec->jump_back_rp; - cur_rp =READ_VREG(VLD_MEM_VIFIFO_RP); - input->stream_cookie = READ_VREG(VLD_MEM_VIFIFO_WRAP_COUNT); - if (cur_rp < set_rp) { - if (fcc_debug_enable()) - pr_info("[%d][FCC]: Packet is wrapped! VLD_MEM_VIFIFO_WRAP_COUNT = %d\n", - vdec->id, input->stream_cookie); - input->stream_cookie = (input->stream_cookie - 1) < 0 ? - 0 : input->stream_cookie - 1; - } - - WRITE_VREG(VLD_MEM_VIFIFO_CURR_PTR, set_rp); - WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 1); - WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 0); - - WRITE_VREG(VLD_MEM_SWAP_ADDR, - input->swap_page_phys); - WRITE_VREG(VLD_MEM_SWAP_CTL, 3); - while (READ_VREG(VLD_MEM_SWAP_CTL) & (1<<7)) - ; - WRITE_VREG(VLD_MEM_SWAP_CTL, 0); - vdec->fcc_status = SWITCH_DONE_STATUS; - if (fcc_debug_enable()) { - pr_info("[%d][FCC]:Current VLD_MEM_VIFIFO_WRAP_COUNT = %d cur_rp = %x set_rp = %x\n", - vdec->id, input->stream_cookie, cur_rp, set_rp); - } - } - } else if (input->target == VDEC_INPUT_TARGET_HEVC) { - if (vdec->fcc_mode == FCC_DEC_MODE && - vdec->fcc_status == JUMP_BACK_STATUS) { - set_rp = vdec->jump_back_rp; - cur_rp = READ_VREG(HEVC_STREAM_RD_PTR); - if (cur_rp < set_rp) { - input->stream_cookie = input->stream_cookie + set_rp - cur_rp - vdec->input.size; - } else { - input->stream_cookie = input->stream_cookie - cur_rp + set_rp; - } - - WRITE_VREG(HEVC_STREAM_RD_PTR, set_rp); - vdec->fcc_status = SWITCH_DONE_STATUS; - - WRITE_VREG(HEVC_STREAM_SWAP_ADDR, - input->swap_page_phys); - WRITE_VREG(HEVC_STREAM_SWAP_CTRL, 3); - - while (READ_VREG(HEVC_STREAM_SWAP_CTRL) - & (1<<7)) - ; - WRITE_VREG(HEVC_STREAM_SWAP_CTRL, 0); - } - } - - return; -} -#endif - static int dump_mode; static ssize_t dump_risc_mem_store(struct class *class, struct class_attribute *attr, @@ -5036,10 +4981,11 @@ list_for_each_entry(vdec, &core->connected_vdec_list, list) { pbuf += sprintf(pbuf, - "\tvdec.%d (%p (%s)), status = %s,\ttype = %s, \tactive_mask = %lx\n", + "\tvdec.%d (%p (%s%s)), status = %s,\ttype = %s, \tactive_mask = %lx\n", vdec->id, vdec, vdec_device_name[vdec->format * 2], + (vdec->is_v4l == 1) ? "_v4l" : "", vdec_status_str(vdec), vdec_type_str(vdec), vdec->active_mask); @@ -5209,6 +5155,28 @@ return pbuf - buf; } +static ssize_t version_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + char *pbuf = buf; +#ifdef DECODER_VERSION + pbuf += sprintf(pbuf, "DECODER VERSION: V" xstr(DECODER_VERSION) "\n"); +#else +#ifdef RELEASED_VERSION + pbuf += sprintf(pbuf, "Due to project compilation environment problems,\ +the current decoder version could not be detected,\ +Please Use The DECODER BASE Version for traceability\n"); + pbuf += sprintf(pbuf, "DECODER BASE Version: " xstr(RELEASED_VERSION) "\n"); +#endif +#endif + +#ifdef UCODE_VERSION + pbuf += sprintf(pbuf, "UCODE VERSION: V" xstr(UCODE_VERSION) "\n"); +#endif + + return pbuf - buf; +} + static char * parser_h264_profile(char *pbuf, struct vdec_s *vdec) { switch (vdec->profile_idc) { @@ -5476,71 +5444,65 @@ return pbuf - buf; } -#ifdef VDEC_FCC_SUPPORT -static ssize_t store_fcc_debug(struct class *class, - struct class_attribute *attr, - const char *buf, size_t size) -{ - unsigned int val; - ssize_t ret; - - ret = kstrtoint(buf, 0, &val); - if (ret != 0) - return -EINVAL; - fcc_debug = val; - return size; -} - -static ssize_t show_fcc_debug(struct class *class, - struct class_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", fcc_debug); -} -#endif - -static struct class_attribute vdec_class_attrs[] = { - __ATTR_RO(amrisc_regs), - __ATTR_RO(dump_trace), - __ATTR_RO(clock_level), - __ATTR(enable_mvdec_info, S_IRUGO | S_IWUSR | S_IWGRP, - enable_mvdec_info_show, enable_mvdec_info_store), - __ATTR(poweron_clock_level, S_IRUGO | S_IWUSR | S_IWGRP, - show_poweron_clock_level, store_poweron_clock_level), - __ATTR(dump_risc_mem, S_IRUGO | S_IWUSR | S_IWGRP, - dump_risc_mem_show, dump_risc_mem_store), - __ATTR(keep_vdec_mem, S_IRUGO | S_IWUSR | S_IWGRP, - show_keep_vdec_mem, store_keep_vdec_mem), - __ATTR_RO(core), - __ATTR_RO(vdec_status), - __ATTR_RO(dump_vdec_blocks), - __ATTR_RO(dump_vdec_chunks), - __ATTR_RO(dump_decoder_state), +static CLASS_ATTR_RO(amrisc_regs); +static CLASS_ATTR_RO(dump_trace); +static CLASS_ATTR_RO(clock_level); +static CLASS_ATTR_RW(poweron_clock_level); +static CLASS_ATTR_RW(dump_risc_mem); +static CLASS_ATTR_RW(keep_vdec_mem); +static CLASS_ATTR_RW(enable_mvdec_info); +static CLASS_ATTR_RO(core); +static CLASS_ATTR_RO(vdec_status); +static CLASS_ATTR_RO(dump_vdec_blocks); +static CLASS_ATTR_RO(dump_vdec_chunks); +static CLASS_ATTR_RO(dump_decoder_state); #ifdef VDEC_DEBUG_SUPPORT - __ATTR(debug, S_IRUGO | S_IWUSR | S_IWGRP, - show_debug, store_debug), +static CLASS_ATTR_RW(debug); #endif +static CLASS_ATTR_RW(vdec_vfm_path); #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), +static CLASS_ATTR_RW(dump_yuv); +static CLASS_ATTR_RW(frame_check); #endif - __ATTR_RO(dump_fps), - __ATTR_RO(profile_idc), - __ATTR_RO(level_idc), - __ATTR(vfm_path, S_IRUGO | S_IWUSR | S_IWGRP, - show_vdec_vfm_path, store_vdec_vfm_path), -#ifdef VDEC_FCC_SUPPORT - __ATTR(fcc_debug, S_IRUGO | S_IWUSR | S_IWGRP, - show_fcc_debug, store_fcc_debug), +static CLASS_ATTR_RO(dump_fps); +static CLASS_ATTR_RO(profile_idc); +static CLASS_ATTR_RO(level_idc); +static CLASS_ATTR_RO(version); + +static struct attribute *vdec_class_attrs[] = { + &class_attr_amrisc_regs.attr, + &class_attr_dump_trace.attr, + &class_attr_clock_level.attr, + &class_attr_poweron_clock_level.attr, + &class_attr_dump_risc_mem.attr, + &class_attr_keep_vdec_mem.attr, + &class_attr_enable_mvdec_info.attr, + &class_attr_core.attr, + &class_attr_vdec_status.attr, + &class_attr_dump_vdec_blocks.attr, + &class_attr_dump_vdec_chunks.attr, + &class_attr_dump_decoder_state.attr, +#ifdef VDEC_DEBUG_SUPPORT + &class_attr_debug.attr, #endif - __ATTR_NULL + &class_attr_vdec_vfm_path.attr, +#ifdef FRAME_CHECK + &class_attr_dump_yuv.attr, + &class_attr_frame_check.attr, +#endif + &class_attr_dump_fps.attr, + &class_attr_profile_idc.attr, + &class_attr_level_idc.attr, + &class_attr_version.attr, + NULL }; +ATTRIBUTE_GROUPS(vdec_class); + static struct class vdec_class = { - .name = "vdec", - .class_attrs = vdec_class_attrs, - }; + .name = "vdec", + .class_groups = vdec_class_groups, +}; struct device *get_vdec_device(void) { @@ -5548,6 +5510,119 @@ } EXPORT_SYMBOL(get_vdec_device); +static int vdec_post_task_recycle(void *args) +{ + struct post_task_mgr_s *post = + (struct post_task_mgr_s *)args; + + while (post->running && + down_interruptible(&post->sem) == 0) { + if (kthread_should_stop()) + break; + mutex_lock(&post->mutex); + if (!list_empty(&post->task_recycle)) { + struct vdec_post_task_parms_s *parms, *tmp; + list_for_each_entry_safe(parms, tmp, &post->task_recycle, recycle) { + if (parms->scheduled) { + list_del(&parms->recycle); + kthread_stop(parms->task); + kfree(parms); + parms = NULL; + } + } + } + mutex_unlock(&post->mutex); + } + + return 0; +} + +static void vdec_post_task_exit(void) +{ + struct post_task_mgr_s *post = &vdec_core->post; + + post->running = false; + up(&post->sem); + + kthread_stop(post->task); +} + +static int vdec_post_task_init(void) +{ + struct post_task_mgr_s *post = &vdec_core->post; + + sema_init(&post->sem, 0); + INIT_LIST_HEAD(&post->task_recycle); + mutex_init(&post->mutex); + post->running = true; + + post->task = kthread_run(vdec_post_task_recycle, + post, "task-post-daemon-thread"); + if (IS_ERR(post->task)) { + pr_err("%s, creat task post daemon thread faild %ld\n", + __func__, PTR_ERR(post->task)); + return PTR_ERR(post->task); + } + + return 0; +} + +static int vdec_post_handler(void *args) +{ + struct vdec_post_task_parms_s *parms = + (struct vdec_post_task_parms_s *) args; + struct post_task_mgr_s *post = &vdec_core->post; + + complete(&parms->park); + + /* process client task. */ + parms->func(parms->private); + parms->scheduled = 1; + up(&post->sem); + + while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); + usleep_range(1000, 2000); + } + + return 0; +} + +int vdec_post_task(post_task_handler func, void *args) +{ + struct vdec_post_task_parms_s *parms; + struct post_task_mgr_s *post = &vdec_core->post; + + parms = kzalloc(sizeof(*parms), GFP_KERNEL); + if (parms == NULL) + return -ENOMEM; + + parms->func = func; + parms->private = args; + init_completion(&parms->park); + parms->scheduled = 0; + parms->task = kthread_run(vdec_post_handler, + parms, "task-post-thread"); + if (IS_ERR(parms->task)) { + pr_err("%s, creat task post thread faild %ld\n", + __func__, PTR_ERR(parms->task)); + kfree(parms); + return PTR_ERR(parms->task); + } + if (!__kthread_should_park(parms->task)) + wait_for_completion(&parms->park); + + mutex_lock(&post->mutex); + /* add to list for resource recycle in post daemon kthread */ + list_add_tail(&parms->recycle, &post->task_recycle); + mutex_unlock(&post->mutex); + + return 0; +} +EXPORT_SYMBOL(vdec_post_task); + + + static int vdec_probe(struct platform_device *pdev) { s32 i, r; @@ -5628,6 +5703,8 @@ WQ_MEM_RECLAIM |WQ_HIGHPRI/*high priority*/, "vdec-work"); /*work queue priority lower than vdec-core.*/ + vdec_post_task_init(); + /* power manager init. */ vdec_core->pm = (struct power_manager_s *) of_device_get_match_data(&pdev->dev); @@ -5637,6 +5714,7 @@ pr_err("vdec power manager init failed\n"); return r; } + pr_err("vdec power init success!\n"); } return 0; @@ -5657,6 +5735,8 @@ } } + vdec_post_task_exit(); + kthread_stop(vdec_core->thread); destroy_workqueue(vdec_core->vdec_core_wq); @@ -5812,9 +5892,9 @@ ready = (ready + fifo[slot].frame_dur) / 2; else ready = fifo[slot].frame_dur; - pr_debug("%s inner driver dur%u \n",__func__, ready); - } - goto end_handle; + pr_debug("%s inner driver dur%u \n",__func__, ready); + } + goto end_handle; } if (slot == 1) { @@ -5853,7 +5933,7 @@ end_handle: if (must_send) { ++must_send; - vframe_rate_uevent(ready); + vdec_frame_rate_uevent(ready); } } @@ -5891,7 +5971,7 @@ fifo_buf[i].pts_us64 = vf->pts_us64; /* Calculate the duration from pts */ - if (mvfrm->wr < MINIMUM_FRAMES && mvfrm->wr > 0) + if (!vdec->is_v4l && (mvfrm->wr < MINIMUM_FRAMES && mvfrm->wr > 0)) cal_dur_from_pts(vdec, i); } mvfrm->wr++; @@ -5907,6 +5987,76 @@ } EXPORT_SYMBOL(vdec_vframe_ready); +void set_meta_data_to_vf(struct vframe_s *vf, u32 type, void *v4l2_ctx) +{ + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(v4l2_ctx); + struct aml_meta_head_s head; + struct aml_vf_base_info_s vfb_infos; + + if ((ctx == NULL) || (vf == NULL)) + return ; + + if (vf->meta_data_buf == NULL) { + vf->meta_data_buf = ctx->meta_infos.meta_bufs[ctx->meta_infos.index].buf; + ctx->meta_infos.index = (ctx->meta_infos.index + 1) % V4L_CAP_BUFF_MAX; + } + + switch (type) { + case UVM_META_DATA_VF_BASE_INFOS: + if ((vf->meta_data_size + sizeof(struct aml_vf_base_info_s) + AML_META_HEAD_SIZE) <= META_DATA_SIZE) { + head.magic = META_DATA_MAGIC; + head.type = UVM_META_DATA_VF_BASE_INFOS; + head.data_size = sizeof(struct aml_vf_base_info_s); + + memcpy(vf->meta_data_buf + vf->meta_data_size, + &head, AML_META_HEAD_SIZE); + vf->meta_data_size += AML_META_HEAD_SIZE; + + vfb_infos.width = vf->width; + vfb_infos.height = vf->height; + vfb_infos.duration = vf->duration; + vfb_infos.frame_type = vf->frame_type; + vfb_infos.type = vf->type; + + memcpy(vf->meta_data_buf + vf->meta_data_size, + &vfb_infos, sizeof(struct aml_vf_base_info_s)); + vf->meta_data_size += sizeof(struct aml_vf_base_info_s); + + if (debug_meta) { + pr_debug("vf->meta_data_size = %d\n", vf->meta_data_size); + pr_debug("vf:width:%d height:%d duration:%d frame_type:%d type:%d\n", + vfb_infos.width, vfb_infos.height, vfb_infos.duration, + vfb_infos.frame_type, vfb_infos.type); + } + } + break; + case UVM_META_DATA_HDR10P_DATA: + if ((vf->meta_data_size + vf->hdr10p_data_size + AML_META_HEAD_SIZE) <= META_DATA_SIZE) { + head.magic = META_DATA_MAGIC; + head.type = UVM_META_DATA_HDR10P_DATA; + head.data_size = vf->hdr10p_data_size; + + memcpy(vf->meta_data_buf + vf->meta_data_size, + &head, AML_META_HEAD_SIZE); + vf->meta_data_size += AML_META_HEAD_SIZE; + + memcpy(vf->meta_data_buf + vf->meta_data_size, + vf->hdr10p_data_buf, vf->hdr10p_data_size); + vf->meta_data_size += vf->hdr10p_data_size; + + if (debug_meta) { + pr_debug("vf->meta_data_size = %d\n", vf->meta_data_size); + pr_debug("vf->hdr10p_data_size = %d\n", vf->hdr10p_data_size); + } + } + break; + default: + break; + } +} +EXPORT_SYMBOL(set_meta_data_to_vf); + /* In this function,if we use copy_to_user, we may encounter sleep, which may block the vdec_fill_vdec_frame,this is not acceptable. So, we should use a tmp buffer(passed by caller) to get the content */ @@ -5963,6 +6113,23 @@ } EXPORT_SYMBOL(vdec_get_frame_vdec); +int get_double_write_ratio(int dw_mode) +{ + int ratio = 1; + + if ((dw_mode == 2) || + (dw_mode == 3)) + ratio = 4; + else if ((dw_mode == 4) || + (dw_mode == 5)) + ratio = 2; + else if ((dw_mode == 8) || + (dw_mode == 9)) + ratio = 8; + return ratio; +} +EXPORT_SYMBOL(get_double_write_ratio); + void vdec_set_vld_wp(struct vdec_s *vdec, u32 wp) { if (vdec_single(vdec)) { @@ -6010,6 +6177,111 @@ } EXPORT_SYMBOL(vdec_config_vld_reg); +static void check_rdma_result(int num) +{ + int i, wr,rd,data; + int flag = 1; + for (i = 0; i < num; i++) { + wr = READ_VREG(HEVC_IQIT_SCALELUT_WR_ADDR); + rd = READ_VREG(HEVC_IQIT_SCALELUT_RD_ADDR); + data = READ_VREG(HEVC_IQIT_SCALELUT_DATA); + if (wr != (num & 0x3ff)) { + pr_info("--->HEVC_IQIT_SCALELUT_WR_ADDR = 0x%x\n", wr); + flag = 0; + break; + } + if (rd != i) { + pr_info("--->HEVC_IQIT_SCALELUT_RD_ADDR = 0x%x\n", rd); + flag = 0; + break; + } + + if (data != 0) { + pr_info("--->HEVC_IQIT_SCALELUT_DATA = 0x%x\n", data); + flag = 0; + break; + } + } + if (flag == 0) + pr_info("-->%d--rdma flail\n", i); + else + pr_info("rdma ok\n"); + return; + +} + +int is_rdma_enable(void) +{ + if (rdma_mode && (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T3)) + return 1; + else + return 0; +} +EXPORT_SYMBOL(is_rdma_enable); + +void rdma_front_end_wrok(dma_addr_t ddr_phy_addr, u32 size) +{ + ulong expires; + + WRITE_VREG(HEVC_RDMA_F_CTRL, + (0X0 << 7) | //axi id + (0X7 << 3) | //axi length + (0X0 << 2) | //rdma force cg en + (0X1 << 1)); //rdma path en + WRITE_VREG(HEVC_RDMA_F_START_ADDR, ddr_phy_addr); //rdma start address + WRITE_VREG(HEVC_RDMA_F_END_ADDR, ddr_phy_addr + 0xff); //rdma end address + WRITE_VREG(HEVC_RDMA_F_STATUS0, 0X1); //trigger rdma start to work + + expires = jiffies + msecs_to_jiffies(2000); + while (1) { + if ((READ_VREG(HEVC_RDMA_F_STATUS0) & 0x1) == 0) { + //pr_info("rdma front_end done\n"); + break; + } + if (time_after(jiffies, expires)) { + pr_info("wait rdma done timeout\n"); + break; + } + } + + if (rdma_mode & 0x2) + check_rdma_result(SCALELUT_DATA_WRITE_NUM); + + return; +} +EXPORT_SYMBOL(rdma_front_end_wrok); + +void rdma_back_end_work(dma_addr_t back_ddr_phy_addr, u32 size) +{ + ulong expires; + + WRITE_VREG(HEVC_RDMA_B_CTRL, + (0X0 << 7) | //axi id + (0X7 << 3) | //axi length + (0X0 << 2) | //rdma force cg en + (0X1 << 1)); //rdma path en + WRITE_VREG(HEVC_RDMA_B_START_ADDR, back_ddr_phy_addr); //rdma start address + WRITE_VREG(HEVC_RDMA_B_END_ADDR, back_ddr_phy_addr + size -1); //rdma end address + WRITE_VREG(HEVC_RDMA_B_STATUS0, 0X1); //trigger rdma start to work + + expires = jiffies + msecs_to_jiffies(2000); + while (1) { + if ((READ_VREG(HEVC_RDMA_B_STATUS0) & 0x1) == 0) { + //pr_info("rdma back_end done\n"); + break; + } + if (time_after(jiffies, expires)) { + pr_info("wait rdma done timeout\n"); + break; + } + } + if (rdma_mode & 0x2) + check_rdma_result(SCALELUT_DATA_WRITE_NUM); + + return; +} +EXPORT_SYMBOL(rdma_back_end_work); + RESERVEDMEM_OF_DECLARE(vdec, "amlogic, vdec-memory", vdec_mem_setup); /* uint force_hevc_clock_cntl; @@ -6029,6 +6301,8 @@ module_param(force_nosecure_even_drm, int, 0664); module_param(disable_switch_single_to_mult, int, 0664); +module_param(debug_meta, uint, 0664); + module_param(frameinfo_flag, int, 0664); MODULE_PARM_DESC(frameinfo_flag, "\n frameinfo_flag\n"); @@ -6036,6 +6310,10 @@ MODULE_PARM_DESC(v4lvideo_add_di, "\n v4lvideo_add_di\n"); +module_param(v4lvideo_add_ppmgr, int, 0664); +MODULE_PARM_DESC(v4lvideo_add_ppmgr, + "\n v4lvideo_add_ppmgr\n"); + module_param(max_di_instance, int, 0664); MODULE_PARM_DESC(max_di_instance, "\n max_di_instance\n"); @@ -6043,19 +6321,16 @@ module_param(max_supported_di_instance, int, 0664); MODULE_PARM_DESC(max_supported_di_instance, "\n max_supported_di_instance\n"); - module_param(debug_vdetect, int, 0664); MODULE_PARM_DESC(debug_vdetect, "\n debug_vdetect\n"); -#ifdef VDEC_FCC_SUPPORT -module_param(fcc_debug, int, 0664); -MODULE_PARM_DESC(fcc_debug, "\n fcc_debug\n"); -#endif - module_param(enable_stream_mode_multi_dec, int, 0664); -EXPORT_SYMBOL(enable_stream_mode_multi_dec); MODULE_PARM_DESC(enable_stream_mode_multi_dec, "\n enable multi-decoding on stream mode. \n"); + +module_param(rdma_mode, int, 0664); +MODULE_PARM_DESC(rdma_mode, "\n rdma_enable\n"); + /* *module_init(vdec_module_init); *module_exit(vdec_module_exit);
diff --git a/drivers/frame_provider/decoder/utils/vdec.h b/drivers/frame_provider/decoder/utils/vdec.h index 302bfad..a50bdb5 100644 --- a/drivers/frame_provider/decoder/utils/vdec.h +++ b/drivers/frame_provider/decoder/utils/vdec.h
@@ -23,7 +23,7 @@ #include <linux/list.h> #include <linux/completion.h> #include <linux/irqreturn.h> - +#include <linux/videodev2.h> #include <linux/amlogic/media/utils/amstream.h> #include <linux/amlogic/media/vfm/vframe.h> #include <linux/amlogic/media/vfm/vframe_provider.h> @@ -37,6 +37,7 @@ #include "vdec_input.h" #include "frame_check.h" #include "vdec_sync.h" +#include "vdec_canvas_utils.h" s32 vdec_dev_register(void); s32 vdec_dev_unregister(void); @@ -56,17 +57,84 @@ #define VDEC_FIFO_ALIGN 8 -#define VDEC_FCC_SUPPORT - enum vdec_type_e { VDEC_1 = 0, VDEC_HCODEC, VDEC_2, VDEC_HEVC, VDEC_HEVCB, + VDEC_WAVE, VDEC_MAX }; +struct trace_decoder_name { + char set_canvas0_addr[32]; + char get_canvas0_addr[32]; + char put_canvas0_addr[32]; + char vf_put_name[32]; + char vf_get_name[32]; + char vdec_name[32]; + char pts_name[32]; + char new_q_name[32]; + char disp_q_name[32]; + char decode_time_name[32]; + char decode_run_time_name[32]; + char decode_header_time_name[32]; + char decode_work_time_name[32]; + char decode_header_memory_time_name[32]; +}; + + +enum e_trace_decoder_status { + DECODER_RUN_START = 1, + DECODER_RUN_END = 2, + DECODER_ISR_HEAD_DONE = 3, + DECODER_ISR_PIC_DONE = 4, + DECODER_ISR_END = 5, + DECODER_ISR_THREAD_HEAD_START = 6, + DECODER_ISR_THREAD_PIC_DONE_START = 7, + DECODER_ISR_THREAD_EDN = 8, + DECODER_WORKER_START = 9, + DECODER_WORKER_END = 10, + DECODER_WORKER_AGAIN = 11, + DECODER_ISR_SEI_DONE = 12, + DECODER_ISR_THREAD_SEI_START = 13, + DECODER_ISR_AUX_DONE = 14, + DECODER_ISR_THREAD_AUX_START = 15, + DECODER_ISR_THREAD_HEAD_END = 16, +}; + +enum e_trace_run_status { + TRACE_RUN_LOADING_FW_START = 1, + TRACE_RUN_LOADING_FW_END = 2, + TRACE_RUN_LOADING_RESTORE_START = 3, + TRACE_RUN_LOADING_RESTORE_END = 4, +}; + +enum e_trace_header_status { + TRACE_HEADER_MEMORY_START = 1, + TRACE_HEADER_MEMORY_END = 2, + TRACE_HEADER_REGISTER_START = 3, + TRACE_HEADER_REGISTER_END = 4, + TRACE_HEADER_RPM_START = 5, + TRACE_HEADER_RPM_END = 6, +}; + +enum e_trace_work_status { + TRACE_WORK_WAIT_SEARCH_DONE_START = 1, + TRACE_WORK_WAIT_SEARCH_DONE_END = 2, +}; + + +#define VDEC_CFG_FLAG_DV_TWOLARYER (1 << 0) +#define VDEC_CFG_FLAG_DV_NEGATIVE (1 << 1) +#define VDEC_CFG_FLAG_DIS_ERR_POLICY (1 << 11) + +#define VDEC_CFG_FLAG_PROG_ONLY (1 << 16) + +#define UVM_META_DATA_VF_BASE_INFOS (1 << 0) +#define UVM_META_DATA_HDR10P_DATA (1 << 1) + #define CORE_MASK_VDEC_1 (1 << VDEC_1) #define CORE_MASK_HCODEC (1 << VDEC_HCODEC) #define CORE_MASK_VDEC_2 (1 << VDEC_2) @@ -75,14 +143,16 @@ #define CORE_MASK_HEVC_BACK (1 << VDEC_HEVCB) #define CORE_MASK_COMBINE (1UL << 31) +#define META_DATA_SIZE (256) + +#define SEI_TYPE (1) +#define DV_TYPE (2) + extern void vdec2_power_mode(int level); extern void vdec_poweron(enum vdec_type_e core); extern void vdec_poweroff(enum vdec_type_e core); extern bool vdec_on(enum vdec_type_e core); extern void vdec_power_reset(void); -extern void vdec_set_dmc_urgent(struct vdec_s *vdec, int urgentType); - - /*irq num as same as .dts*/ @@ -116,19 +186,6 @@ VDEC_NEED_HINT, VDEC_HINTED, }; - -#ifdef VDEC_FCC_SUPPORT -typedef enum { - DISCARD_STATUS = 1, - AGAIN_STATUS, - WAIT_MSG_STATUS, - SWITCHING_STATUS, - JUMP_BACK_STATUS, - SWITCH_DONE_STATUS, - STATUS_BUTT -} FCC_STATUS; -#endif - extern s32 vdec_request_threaded_irq(enum vdec_irq_num num, irq_handler_t handler, irq_handler_t thread_fn, @@ -151,7 +208,6 @@ extern void vdec_vframe_ready(struct vdec_s *vdec, struct vframe_s *vf); extern void vdec_set_vframe_comm(struct vdec_s *vdec, char *n); - struct vdec_s; enum vformat_t; @@ -190,6 +246,9 @@ #define VDEC_NEED_MORE_DATA_DIRTY 0x02 #define VDEC_NEED_MORE_DATA 0x04 +#define SCALELUT_DATA_WRITE_NUM 1024 +#define RDMA_SIZE (1024 * 4 * 4) + struct vdec_s { u32 magic; struct list_head list; @@ -215,7 +274,7 @@ int flag; int sched; int need_more_data; - u32 canvas_mode; + u32 canvas_mode; //canvas block mode struct completion inactive_done; @@ -277,9 +336,6 @@ struct userdata_param_t *puserdata_para); void (*reset_userdata_fifo)(struct vdec_s *vdec, int bInit); void (*wakeup_userdata_poll)(struct vdec_s *vdec); -#ifdef VDEC_FCC_SUPPORT - void (*wakeup_fcc_poll)(struct vdec_s *vdec); -#endif /* private */ void *private; /* decoder per instance specific data */ #ifdef VDEC_DEBUG_SUPPORT @@ -296,7 +352,7 @@ u64 irq_cnt; int parallel_dec; struct vdec_frames_s *mvfrm; - struct vdec_sync sync; + struct vdec_sync *sync; /*aux data check*/ struct aux_data_check_mgr_t adc; @@ -306,29 +362,90 @@ bool hdr10p_data_valid; u32 profile_idc; u32 level_idc; -#ifdef VDEC_FCC_SUPPORT - enum fcc_mode_e fcc_mode; - u32 stream_offset; - int fcc_new_msg; - FCC_STATUS fcc_status; - wait_queue_head_t jump_back_wq; - struct mutex jump_back_mutex; - u32 jump_back_done; - u32 jump_back_error; - u32 jump_back_rp; -#endif - u32 video_id; + bool prog_only; + bool disable_vfm; char name[32]; char dec_spend_time[32]; char dec_spend_time_ave[32]; u32 discard_start_data_flag; + u32 video_id; + int is_v4l; + bool is_stream_mode_dv_multi; + wait_queue_head_t idle_wait; }; +#define CODEC_MODE(a, b, c, d)\ + (((u8)(a) << 24) | ((u8)(b) << 16) | ((u8)(c) << 8) | (u8)(d)) + +#define META_DATA_MAGIC CODEC_MODE('M', 'E', 'T', 'A') +#define AML_META_HEAD_NUM 8 +#define AML_META_HEAD_SIZE (AML_META_HEAD_NUM * sizeof(u32)) + + +struct aml_meta_head_s { + u32 magic; + u32 type; + u32 data_size; + u32 data[5]; +}; + +struct aml_vf_base_info_s { + u32 width; + u32 height; + u32 duration; + u32 frame_type; + u32 type; + u32 data[12]; +}; + +struct aml_meta_info_s { + union { + struct aml_meta_head_s head; + u32 buf[AML_META_HEAD_NUM]; + }; + u8 data[0]; +}; + +typedef int (*post_task_handler)(void *args); + +struct post_task_mgr_s { + struct list_head task_recycle; + struct task_struct *task; + struct semaphore sem; + struct mutex mutex; + bool running; + void *private; +}; + +struct vdec_post_task_parms_s { + struct list_head recycle; + struct task_struct *task; + struct completion park; + post_task_handler func; + void *private; + int scheduled; +}; + +#define MAX_USERDATA_CHANNEL_NUM 9 + +typedef struct { + struct mutex mutex; + wait_queue_head_t userdata_wait; + u32 video_id; + u32 set_id_flag; + u32 ready_flag[MAX_USERDATA_CHANNEL_NUM]; + int used[MAX_USERDATA_CHANNEL_NUM]; + u32 id[MAX_USERDATA_CHANNEL_NUM]; +} st_userdata; + /* common decoder vframe provider name to use default vfm path */ #define VFM_DEC_PROVIDER_NAME "decoder" #define VFM_DEC_DVBL_PROVIDER_NAME "dvbldec" #define VFM_DEC_DVEL_PROVIDER_NAME "dveldec" +#define VFM_DEC_DVBL_PROVIDER_NAME2 "dvbldec2" +#define VFM_DEC_DVEL_PROVIDER_NAME2 "dveldec2" + #define hw_to_vdec(hw) ((struct vdec_s *) \ (platform_get_drvdata(hw->platform_dev))) @@ -352,6 +469,24 @@ #define vdec_secure(vdec) \ (((vdec)->port_flag & PORT_FLAG_DRM)) +#define PR_INIT(s) \ + int __len = 0, __size = s; \ + u8 __buf[s] = {0} + +#define PR_FILL(args...) \ + do { \ + if ((__size - __len) <= 0) break; \ + __len += snprintf(__buf + __len, \ + __size - __len, ##args); \ + } while (0) + +#define PR_INFO(id) \ + do { \ + if (__len == 0) break; \ + pr_info("[%d] %s\n", id, __buf); \ + __len = 0; \ + } while (0) + /* construct vdec strcture */ extern struct vdec_s *vdec_create(struct stream_port_s *port, struct vdec_s *master); @@ -384,6 +519,9 @@ /* prepare decoder input */ extern int vdec_prepare_input(struct vdec_s *vdec, struct vframe_chunk_s **p); +extern u32 vdec_offset_prepare_input(struct vdec_s *vdec, u32 consume_byte, + u32 data_offset, u32 data_size); + /* clean decoder input */ extern void vdec_clean_input(struct vdec_s *vdec); @@ -422,14 +560,13 @@ extern int vdec_reset(struct vdec_s *vdec); extern int vdec_v4l2_reset(struct vdec_s *vdec, int flag); - extern void vdec_set_status(struct vdec_s *vdec, int status); extern void vdec_set_next_status(struct vdec_s *vdec, int status); extern int vdec_set_decinfo(struct vdec_s *vdec, struct dec_sysinfo *p); -extern int vdec_init(struct vdec_s *vdec, int is_4k); +extern int vdec_init(struct vdec_s *vdec, int is_4k, bool is_v4l); extern void vdec_release(struct vdec_s *vdec); @@ -484,7 +621,9 @@ #ifdef VDEC_DEBUG_SUPPORT extern void vdec_set_step_mode(void); #endif + extern void hevc_mmu_dma_check(struct vdec_s *vdec); + int vdec_read_user_data(struct vdec_s *vdec, struct userdata_param_t *p_userdata_param); @@ -496,12 +635,6 @@ struct vdec_s *vdec_get_vdec_by_id(int vdec_id); -#ifdef VDEC_FCC_SUPPORT -int vdec_wakeup_fcc_poll(struct vdec_s *vdec); -int vdec_has_get_fcc_new_msg(struct vdec_s *vdec); -int fcc_debug_enable(void); -#endif - #ifdef VDEC_DEBUG_SUPPORT extern void vdec_set_step_mode(void); #endif @@ -509,12 +642,12 @@ void VDEC_PRINT_FUN_LINENO(const char *fun, int line); - unsigned char is_mult_inc(unsigned int); int vdec_get_status(struct vdec_s *vdec); void vdec_set_timestamp(struct vdec_s *vdec, u64 timestamp); +void vdec_set_metadata(struct vdec_s *vdec, ulong meta_ptr); extern u32 vdec_get_frame_vdec(struct vdec_s *vdec, struct vframe_counter_s *tmpbuf); @@ -523,12 +656,13 @@ int show_stream_buffer_status(char *buf, int (*callback) (struct stream_buf_s *, char *)); -bool is_support_no_parser(void); +extern int get_double_write_ratio(int dw_mode); -extern u32 timestamp_avsync_counter_get(void); +bool is_support_no_parser(void); int vdec_resource_checking(struct vdec_s *vdec); +void set_meta_data_to_vf(struct vframe_s *vf, u32 type, void *v4l2_ctx); void vdec_set_profile_level(struct vdec_s *vdec, u32 profile_idc, u32 level_idc); @@ -536,4 +670,28 @@ void vdec_set_vld_wp(struct vdec_s *vdec, u32 wp); void vdec_config_vld_reg(struct vdec_s *vdec, u32 addr, u32 size); +extern u32 timestamp_avsync_counter_get(void); + +void vdec_canvas_unlock(unsigned long flags); + +unsigned long vdec_canvas_lock(void); + +int vdec_get_core_nr(void); + + +int vdec_post_task(post_task_handler func, void *args); + +void rdma_front_end_wrok(dma_addr_t ddr_phy_addr, u32 size); + +void rdma_back_end_work(dma_addr_t back_ddr_phy_addr, u32 size); + +int is_rdma_enable(void); + +st_userdata *get_vdec_userdata_ctx(void); + +void vdec_frame_rate_uevent(int dur); + +void vdec_sync_irq(enum vdec_irq_num num); + + #endif /* VDEC_H */
diff --git a/drivers/frame_provider/decoder/utils/vdec_canvas_utils.c b/drivers/frame_provider/decoder/utils/vdec_canvas_utils.c new file mode 100644 index 0000000..46fc003 --- /dev/null +++ b/drivers/frame_provider/decoder/utils/vdec_canvas_utils.c
@@ -0,0 +1,415 @@ +/* + * drivers/amlogic/media/frame_provider/decoder/utils/vdec_canvas_utils.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/types.h> +#include "vdec_canvas_utils.h" +#include "../../../common/chips/decoder_cpu_ver_info.h" +#include <linux/amlogic/media/canvas/canvas.h> +#include <linux/amlogic/media/utils/vdec_reg.h> +#include "vdec.h" + +static struct canvas_status_s canvas_stat[CANVAS_MAX_SIZE]; +static struct canvas_status_s mdec_cav_stat[MDEC_CAV_LUT_MAX]; +static struct canvas_config_s *mdec_cav_pool = NULL; + +extern u32 vdec_get_debug(void); + + +bool is_support_vdec_canvas(void) +{ + /* vdec canvas note: + * 1. canvas params config to display, do not use + * vf->canvasxAddr, should use vf->canvasxconfig[]. + * 2. the endian can not config with canvas. and hevc + * core should not config canvas. config endian in + * probe function like h265/vp9/av1/avs2. + */ + if ((get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T7) || + (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T3) || + (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5W)) + return true; + return false; +} +EXPORT_SYMBOL(is_support_vdec_canvas); + +static int get_canvas(unsigned int index, unsigned int base) +{ + int start; + int canvas_index = index * base; + int ret = 0; + + if ((base > 4) || (base == 0)) + return -1; + + if ((AMVDEC_CANVAS_START_INDEX + canvas_index + base - 1) + <= AMVDEC_CANVAS_MAX1) { + start = AMVDEC_CANVAS_START_INDEX + base * index; + } else { + canvas_index -= (AMVDEC_CANVAS_MAX1 - + AMVDEC_CANVAS_START_INDEX + 1) / base * base; + if (canvas_index <= AMVDEC_CANVAS_MAX2) + start = canvas_index / base; + else + return -1; + } + + if (base == 1) { + ret = start; + } else if (base == 2) { + ret = ((start + 1) << 16) | ((start + 1) << 8) | start; + } else if (base == 3) { + ret = ((start + 2) << 16) | ((start + 1) << 8) | start; + } else if (base == 4) { + ret = (((start + 3) << 24) | (start + 2) << 16) | + ((start + 1) << 8) | start; + } + + return ret; +} + +static int get_canvas_ex(int type, int id) +{ + int i; + unsigned long flags; + + flags = vdec_canvas_lock(); + + for (i = 0; i < CANVAS_MAX_SIZE; i++) { + /*0x10-0x15 has been used by rdma*/ + if ((i >= 0x10) && (i <= 0x15)) + continue; + if ((canvas_stat[i].type == type) && + (canvas_stat[i].id & (1 << id)) == 0) { + canvas_stat[i].canvas_used_flag++; + canvas_stat[i].id |= (1 << id); + if (vdec_get_debug() & 4) + pr_debug("get used canvas %d\n", i); + vdec_canvas_unlock(flags); + if (i < AMVDEC_CANVAS_MAX2 + 1) + return i; + else + return (i + AMVDEC_CANVAS_START_INDEX - AMVDEC_CANVAS_MAX2 - 1); + } + } + + for (i = 0; i < CANVAS_MAX_SIZE; i++) { + /*0x10-0x15 has been used by rdma*/ + if ((i >= 0x10) && (i <= 0x15)) + continue; + if (canvas_stat[i].type == 0) { + canvas_stat[i].type = type; + canvas_stat[i].canvas_used_flag = 1; + canvas_stat[i].id = (1 << id); + if (vdec_get_debug() & 4) { + pr_debug("get canvas %d\n", i); + pr_debug("canvas_used_flag %d\n", + canvas_stat[i].canvas_used_flag); + pr_debug("canvas_stat[i].id %d\n", + canvas_stat[i].id); + } + vdec_canvas_unlock(flags); + if (i < AMVDEC_CANVAS_MAX2 + 1) + return i; + else + return (i + AMVDEC_CANVAS_START_INDEX - AMVDEC_CANVAS_MAX2 - 1); + } + } + vdec_canvas_unlock(flags); + + pr_info("cannot get canvas\n"); + + return -1; +} + +static void free_canvas_ex(int index, int id) +{ + unsigned long flags; + int offset; + + flags = vdec_canvas_lock(); + if (index >= 0 && + index < AMVDEC_CANVAS_MAX2 + 1) + offset = index; + else if ((index >= AMVDEC_CANVAS_START_INDEX) && + (index <= AMVDEC_CANVAS_MAX1)) + offset = index + AMVDEC_CANVAS_MAX2 + 1 - AMVDEC_CANVAS_START_INDEX; + else { + vdec_canvas_unlock(flags); + return; + } + + if ((canvas_stat[offset].canvas_used_flag > 0) && + (canvas_stat[offset].id & (1 << id))) { + canvas_stat[offset].canvas_used_flag--; + canvas_stat[offset].id &= ~(1 << id); + if (canvas_stat[offset].canvas_used_flag == 0) { + canvas_stat[offset].type = 0; + canvas_stat[offset].id = 0; + } + if (vdec_get_debug() & 4) { + pr_debug("free index %d used_flag %d, type = %d, id = %d\n", + offset, + canvas_stat[offset].canvas_used_flag, + canvas_stat[offset].type, + canvas_stat[offset].id); + } + } + vdec_canvas_unlock(flags); + + return; +} + + +static int get_internal_cav_lut(unsigned int index, unsigned int base) +{ + int start; + int canvas_index = index * base; + int ret = 0; + + if ((base > 4) || (base == 0)) + return -1; + + if (canvas_index + base - 1 < MDEC_CAV_LUT_MAX) + start = canvas_index; + else + return -1; + + if (base == 1) { + ret = start; + } else if (base == 2) { + ret = ((start + 1) << 16) | ((start + 1) << 8) | start; + } else if (base == 3) { + ret = ((start + 2) << 16) | ((start + 1) << 8) | start; + } else if (base == 4) { + ret = (((start + 3) << 24) | (start + 2) << 16) | + ((start + 1) << 8) | start; + } + + return ret; +} + +static int get_internal_cav_lut_ex(int type, int id) +{ + int i; + unsigned long flags; + + flags = vdec_canvas_lock(); + + for (i = 0; i < MDEC_CAV_LUT_MAX; i++) { + if ((mdec_cav_stat[i].type == type) && + (mdec_cav_stat[i].id & (1 << id)) == 0) { + mdec_cav_stat[i].canvas_used_flag++; + mdec_cav_stat[i].id |= (1 << id); + if (vdec_get_debug() & 4) + pr_debug("get used cav lut %d\n", i); + vdec_canvas_unlock(flags); + return i; + } + } + + for (i = 0; i < MDEC_CAV_LUT_MAX; i++) { + if (mdec_cav_stat[i].type == 0) { + mdec_cav_stat[i].type = type; + mdec_cav_stat[i].canvas_used_flag = 1; + mdec_cav_stat[i].id = (1 << id); + if (vdec_get_debug() & 4) + pr_debug("get cav lut %d\n", i); + vdec_canvas_unlock(flags); + return i; + } + } + vdec_canvas_unlock(flags); + + pr_info("cannot get cav lut\n"); + + return -1; +} + +static void free_internal_cav_lut(int index, int id) +{ + unsigned long flags; + int offset; + + flags = vdec_canvas_lock(); + if (index > 0 && index < MDEC_CAV_LUT_MAX) + offset = index; + else { + vdec_canvas_unlock(flags); + return; + } + if ((mdec_cav_stat[offset].canvas_used_flag > 0) && + (mdec_cav_stat[offset].id & (1 << id))) { + mdec_cav_stat[offset].canvas_used_flag--; + mdec_cav_stat[offset].id &= ~(1 << id); + if (mdec_cav_stat[offset].canvas_used_flag == 0) { + mdec_cav_stat[offset].type = 0; + mdec_cav_stat[offset].id = 0; + } + if (vdec_get_debug() & 4) { + pr_debug("free index %d used_flag %d, type = %d, id = %d\n", + offset, + mdec_cav_stat[offset].canvas_used_flag, + mdec_cav_stat[offset].type, + mdec_cav_stat[offset].id); + } + } + vdec_canvas_unlock(flags); + + return; +} + +unsigned long vdec_cav_get_addr(int index) +{ + if (index < 0 || index >= MDEC_CAV_LUT_MAX) { + pr_err("%s, error index %d\n", __func__, index); + return -1; + } + + return mdec_cav_pool[index & MDEC_CAV_INDEX_MASK].phy_addr; +} +EXPORT_SYMBOL(vdec_cav_get_addr); + +unsigned int vdec_cav_get_width(int index) +{ + if (index < 0 || index >= MDEC_CAV_LUT_MAX) { + pr_err("%s, error index %d\n", __func__, index); + return -1; + } + + return mdec_cav_pool[index & MDEC_CAV_INDEX_MASK].width; +} +EXPORT_SYMBOL(vdec_cav_get_width); + +unsigned int vdec_cav_get_height(int index) +{ + if (index < 0 || index >= MDEC_CAV_LUT_MAX) { + pr_err("%s, error index %d\n", __func__, index); + return -1; + } + return mdec_cav_pool[index & MDEC_CAV_INDEX_MASK].height; +} +EXPORT_SYMBOL(vdec_cav_get_height); + +void cav_lut_info_store(u32 index, ulong addr, u32 width, + u32 height, u32 wrap, u32 blkmode, u32 endian) +{ + struct canvas_config_s *pool = NULL; + + if (index < 0 || index >= MDEC_CAV_LUT_MAX) { + pr_err("%s, error index %d\n", __func__, index); + return; + } + if (mdec_cav_pool == NULL) + mdec_cav_pool = vzalloc(sizeof(struct canvas_config_s) + * (MDEC_CAV_LUT_MAX + 1)); + + if (mdec_cav_pool == NULL) { + pr_err("%s failed, mdec_cav_pool null\n", __func__); + return; + } + pool = &mdec_cav_pool[index]; + pool->width = width; + pool->height = height; + pool->block_mode = blkmode; + pool->endian = endian; + pool->phy_addr = addr; +} + +void config_cav_lut_ex(u32 index, ulong addr, u32 width, + u32 height, u32 wrap, u32 blkmode, + u32 endian, enum vdec_type_e core) +{ + unsigned long datah_temp, datal_temp; + + if (!is_support_vdec_canvas()) { + canvas_config_ex(index, addr, width, height, wrap, blkmode, endian); + if (vdec_get_debug() & 0x40000000) { + pr_info("%s %2d) addr: %lx, width: %d, height: %d, blkm: %d, endian: %d\n", + __func__, index, addr, width, height, blkmode, endian); + } + } else { + /* + datal_temp = (cav_lut.start_addr & 0x1fffffff) | + ((cav_lut.cav_width & 0x7 ) << 29 ); + datah_temp = ((cav_lut.cav_width >> 3) & 0x1ff) | + (( cav_lut.cav_hight & 0x1fff) <<9 ) | + ((cav_lut.x_wrap_en & 1) << 22 ) | + (( cav_lut.y_wrap_en & 1) << 23) | + (( cav_lut.blk_mode & 0x3) << 24); + */ + u32 addr_bits_l = ((((addr + 7) >> 3) & CANVAS_ADDR_LMASK) << CAV_WADDR_LBIT); + u32 width_l = ((((width + 7) >> 3) & CANVAS_WIDTH_LMASK) << CAV_WIDTH_LBIT); + u32 width_h = ((((width + 7) >> 3) >> CANVAS_WIDTH_LWID) << CAV_WIDTH_HBIT); + u32 height_h = (height & CANVAS_HEIGHT_MASK) << CAV_HEIGHT_HBIT; + u32 blkmod_h = (blkmode & CANVAS_BLKMODE_MASK) << CAV_BLKMODE_HBIT; + u32 switch_bits_ctl = (endian & 0xf) << CAV_ENDIAN_HBIT; + u32 wrap_h = (0 << 23); + datal_temp = addr_bits_l | width_l; + datah_temp = width_h | height_h | wrap_h | blkmod_h | switch_bits_ctl; + + if (core == VDEC_1) { + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T3) && (endian == 7)) + WRITE_VREG(MDEC_CAV_CFG0, 0x1ff << 17); + else + WRITE_VREG(MDEC_CAV_CFG0, 0); //[0]canv_mode, by default is non-canv-mode + WRITE_VREG(MDEC_CAV_LUT_DATAL, datal_temp); + WRITE_VREG(MDEC_CAV_LUT_DATAH, datah_temp); + WRITE_VREG(MDEC_CAV_LUT_ADDR, index); + } + + cav_lut_info_store(index, addr, width, height, wrap, blkmode, endian); + + if (vdec_get_debug() & 0x40000000) { + pr_info("%s %2d) addr: %lx, width: %d, height: %d, blkm: %d, endian: %d\n", + __func__, index, addr, width, height, blkmode, endian); + pr_info("data(h,l): 0x%8lx, 0x%8lx\n", datah_temp, datal_temp); + } + } +} +EXPORT_SYMBOL(config_cav_lut_ex); + +void config_cav_lut(int index, struct canvas_config_s *cfg, + enum vdec_type_e core) +{ + config_cav_lut_ex(index, + cfg->phy_addr, + cfg->width, + cfg->height, + CANVAS_ADDR_NOWRAP, + cfg->block_mode, + cfg->endian, + core); +} +EXPORT_SYMBOL(config_cav_lut); + + +void vdec_canvas_port_register(struct vdec_s *vdec) +{ + if (is_support_vdec_canvas()) { + vdec->get_canvas = get_internal_cav_lut; + vdec->get_canvas_ex = get_internal_cav_lut_ex; + vdec->free_canvas_ex = free_internal_cav_lut; + if (mdec_cav_pool == NULL) { + mdec_cav_pool = vzalloc(sizeof(struct canvas_config_s) + * (MDEC_CAV_LUT_MAX + 1)); + } + } else { + vdec->get_canvas = get_canvas; + vdec->get_canvas_ex = get_canvas_ex; + vdec->free_canvas_ex = free_canvas_ex; + } +} +EXPORT_SYMBOL(vdec_canvas_port_register);
diff --git a/drivers/frame_provider/decoder/utils/vdec_canvas_utils.h b/drivers/frame_provider/decoder/utils/vdec_canvas_utils.h new file mode 100644 index 0000000..add83cf --- /dev/null +++ b/drivers/frame_provider/decoder/utils/vdec_canvas_utils.h
@@ -0,0 +1,70 @@ +/* + * drivers/amlogic/media/frame_provider/decoder/utils/vdec_canvas_utils.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 __CANVAS_UTILS_H__ +#define __CANVAS_UTILS_H__ + +#include "vdec.h" + +/* external canvas */ +struct canvas_status_s { + int type; + int canvas_used_flag; + int id; +}; + +#define CANVAS_MAX_SIZE (AMVDEC_CANVAS_MAX1 - AMVDEC_CANVAS_START_INDEX + 1 + AMVDEC_CANVAS_MAX2 + 1) + + +/* internal canvas */ +#define CANVAS_ADDR_LMASK 0x1fffffff +#define CANVAS_WIDTH_LMASK 0x7 +#define CANVAS_WIDTH_LWID 3 +#define CANVAS_HEIGHT_MASK 0x1fff +#define CANVAS_BLKMODE_MASK 3 + +#define CAV_WADDR_LBIT 0 +#define CAV_WIDTH_LBIT 29 +#define CAV_WIDTH_HBIT 0 +#define CAV_HEIGHT_HBIT (41 - 32) +#define CAV_WRAPX_HBIT (54 - 32) +#define CAV_WRAPY_HBIT (55 - 32) +#define CAV_BLKMODE_HBIT (56 - 32) +#define CAV_ENDIAN_HBIT (58 - 32) + +#define MDEC_CAV_LUT_MAX 128 +#define MDEC_CAV_INDEX_MASK 0x7f + +enum vdec_type_e; + +void config_cav_lut(int index, struct canvas_config_s *cfg, enum vdec_type_e core); + +void config_cav_lut_ex(u32 index, ulong addr, u32 width, + u32 height, u32 wrap, u32 blkmode, + u32 endian, enum vdec_type_e core); + +unsigned int vdec_cav_get_width(int index); + +unsigned int vdec_cav_get_height(int index); + +unsigned long vdec_cav_get_addr(int index); + +bool is_support_vdec_canvas(void); + +void vdec_canvas_port_register(struct vdec_s *vdec); + +#endif +
diff --git a/drivers/frame_provider/decoder/utils/vdec_feature.c b/drivers/frame_provider/decoder/utils/vdec_feature.c new file mode 100644 index 0000000..ea3a75d --- /dev/null +++ b/drivers/frame_provider/decoder/utils/vdec_feature.c
@@ -0,0 +1,522 @@ +/* + * drivers/amlogic/media/stream_input/amports/amstream_profile.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/fs.h> +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/amlogic/media/utils/amstream.h> +#include <linux/amlogic/media/utils/vformat.h> +#include "../../../common/chips/decoder_cpu_ver_info.h" +#include "vdec.h" + + + +//static const struct codec_profile_t *vcodec_feature[SUPPORT_VDEC_NUM] = { 0 }; + +struct vcodec_feature { + int format; + int is_v4l; +}; + +static struct vcodec_feature feature[SUPPORT_VDEC_NUM]; + +static int vcodec_feature_idx; +static ulong last_time; +u8 buf[4096]; + + +static const char * const format_name[] = { + "ammvdec_mpeg12", + "ammvdec_mpeg4", + "ammvdec_h264", + "ammvdec_mjpeg", + "ammvdec_real", + "ammjpegdec", + "ammvdec_vc1", + "ammvdec_avs", + "ammvdec_yuv", + "ammvdec_h264mvc", + "ammvdec_h264_4k2k", + "ammvdec_h265", + "amvenc_avc", + "jpegenc", + "ammvdec_vp9", + "ammvdec_avs2", + "ammvdec_av1", +}; + +static int vcodec_feature_CC(u8 *buf, int size, int vformat, int is_v4l) +{ + u8 *pbuf = buf; + + if (!is_v4l) { + switch (vformat) { + case VFORMAT_MPEG12: + case VFORMAT_H264: + case VFORMAT_AVS: + pbuf += snprintf(pbuf, size, " \"CC subtitle\" : \"true\"\n"); + break; + default: + break; + } + } + + return pbuf - buf; +} + +static int vcodec_feature_report_information(u8 *buf, int size, int vformat, int is_v4l) +{ + u8 *pbuf = buf; + + if (!is_v4l) { + pbuf += snprintf(pbuf, size, " \"Decoder information report\" : \"true\"\n"); + } + + return pbuf - buf; +} + +static int vcodec_feature_i_only_mode(u8 *buf, int size, int vformat) +{ + u8 *pbuf = buf; + + switch (vformat) { + case VFORMAT_MPEG12: + case VFORMAT_H264: + case VFORMAT_MPEG4: + case VFORMAT_HEVC: + case VFORMAT_AVS2: + pbuf += snprintf(pbuf, size, " \"I only mode\" : \"true\"\n"); + break; + default: + break; + } + + return pbuf - buf; +} + +static int vcodec_feature_dolbyVison(u8 *buf, int size, int vformat) +{ + u8 *pbuf = buf; + + switch (vformat) { + case VFORMAT_H264: + case VFORMAT_HEVC: + case VFORMAT_AV1: + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXM) && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5) && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5D) && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_S4)) + pbuf += snprintf(pbuf, size, " \"DolbyVision\" : \"true\"\n"); + break; + default: + break; + } + + return pbuf - buf; +} + +static int vcodec_feature_HDR(u8 *buf, int size, int vformat) +{ + u8 *pbuf = buf; + + switch (vformat) { + case VFORMAT_H264: + case VFORMAT_HEVC: + case VFORMAT_AV1: + case VFORMAT_AVS2: + case VFORMAT_VP9: + pbuf += snprintf(pbuf, size, " \"HDR\" : \"true\"\n"); + break; + default: + break; + } + + return pbuf - buf; +} + + +static int vcodec_feature_doublewrite(u8 *buf, int size, int vformat) +{ + u8 *pbuf = buf; + int tsize = 0; + int s; + + switch (vformat) { + case VFORMAT_HEVC: + case VFORMAT_VP9: + case VFORMAT_AVS2: + case VFORMAT_AV1: + s = snprintf(pbuf, size - tsize, " \"DoubleWrite\" "); + tsize += s; + pbuf += s; + if ((get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T7) && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T3)) { + s = snprintf(pbuf, size - tsize, "[ \"0\", \"1\", \"2\", \"3\", \"4\", \"0x10\", \"0x10000\", \"0x20000\"]\n"); + tsize += s; + pbuf += s; + } + else { + s = snprintf(pbuf, size - tsize, "[ \"0\", \"1\", \"2\", \"3\", \"4\", \"8\", \"0x10\", \"0x10000\", \"0x20000\"]\n"); + tsize += s; + pbuf += s; + } + break; + default: + break; + } + + return pbuf - buf; +} + +static int vcodec_feature_vdec_fence(u8 *buf, int size, int vformat) +{ + u8 *pbuf = buf; + + switch (vformat) { + case VFORMAT_H264: + case VFORMAT_HEVC: + case VFORMAT_VP9: + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXM) + pbuf += snprintf(pbuf, size, " \"GameMode\" : \"true\"\n"); + break; + default: + break; + } + + return pbuf - buf; +} + +static int vcodec_feature_bitdepth(u8 *buf, int size, int vformat) +{ + u8 *pbuf = buf; + + switch (vformat) { + case VFORMAT_HEVC: + case VFORMAT_VP9: + case VFORMAT_AVS2: + case VFORMAT_AV1: + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXBB) + pbuf += snprintf(pbuf, size, " \"BitDepth\" : \"10\"\n"); + else + pbuf += snprintf(pbuf, size, " \"BitDepth\" : \"8\"\n"); + break; + default: + break; + } + + return pbuf - buf; +} + + +static int vcodec_feature_MaxResolution(u8 *buf, int size, int vformat) +{ + u8 *pbuf = buf; + + switch (vformat) { + case VFORMAT_HEVC: + case VFORMAT_VP9: + case VFORMAT_AVS2: + case VFORMAT_AV1: + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5D)) + pbuf += snprintf(pbuf, size, " \"MaximumResolution\" : \"8k\"\n"); + else if (vdec_is_support_4k() && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5D)) + pbuf += snprintf(pbuf, size, " \"MaximumResolution\" : \"4k60\"\n"); + else + pbuf += snprintf(pbuf, size, " \"MaximumResolution\" : \"1080p60\"\n"); + break; + case VFORMAT_H264: + if (vdec_is_support_4k()) + pbuf += snprintf(pbuf, size, " \"MaximumResolution\" : \"4k30\"\n"); + else + pbuf += snprintf(pbuf, size, " \"MaximumResolution\" : \"1080p60\"\n"); + break; + case VFORMAT_MPEG12: + case VFORMAT_MPEG4: + case VFORMAT_MJPEG: + case VFORMAT_VC1: + case VFORMAT_AVS: + pbuf += snprintf(pbuf, size, " \"MaximumResolution\" : \"1080p60\"\n"); + break; + default: + break; + } + + return pbuf - buf; +} + +static int vcodec_feature_clock(u8 *buf, int size, int vformat) +{ + u8 *pbuf = buf; + + switch (vformat) { + case VFORMAT_HEVC: + case VFORMAT_VP9: + case VFORMAT_AVS2: + case VFORMAT_AV1: + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12B) && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_GXLX2) && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5) && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5D)) + pbuf += snprintf(pbuf, size, " \"ClockFrequency\" : \"800MHZ\"\n"); + else + pbuf += snprintf(pbuf, size, " \"ClockFrequency\" : \"667MHZ\"\n"); + break; + case VFORMAT_H264: + case VFORMAT_MPEG12: + case VFORMAT_MPEG4: + case VFORMAT_MJPEG: + case VFORMAT_VC1: + case VFORMAT_AVS: + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1) && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_GXLX2) && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5) && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5D)) + pbuf += snprintf(pbuf, size, " \"ClockFrequency\" : \"800MHZ\"\n"); + else + pbuf += snprintf(pbuf, size, " \"ClockFrequency\" : \"667MHZ\"\n"); + break; + default: + break; + } + + return pbuf - buf; +} + +static int vcodec_feature_support_format(int vformat) +{ + + switch (vformat) { + case VFORMAT_VP9: + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5)) + return 1; + else + return 0; + case VFORMAT_AVS2: + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5D)) + return 1; + else + return 0; + case VFORMAT_AV1: + if (((get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_TM2) && + is_cpu_tm2_revb()) || + ((get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_TM2) && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5))) + return 1; + else + return 0; + case VFORMAT_AVS: + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXM)) + return 1; + else + return 0; + case VFORMAT_MJPEG: + case VFORMAT_VC1: + case VFORMAT_MPEG4: + case VFORMAT_MPEG12: + case VFORMAT_H264: + case VFORMAT_HEVC: + return 1; + default: + break; + } + + return 0; +} + +static int vcodec_feature_FCC(u8 *buf, int size, int vformat, int is_v4l) +{ + u8 *pbuf = buf; + + if (!is_v4l) { + switch (vformat) { + case VFORMAT_HEVC: + case VFORMAT_H264: + case VFORMAT_MPEG12: + pbuf += snprintf(pbuf, size, " \"Decoder FCC support\" : \"true\"\n"); + break; + default: + break; + } + } + + return pbuf - buf; +} + +static int vcodec_feature_RDMA(u8 *buf, int size, int vformat) +{ + u8 *pbuf = buf; + + if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T3) + pbuf += snprintf(pbuf, size, " \"Decoder RDMA support\" : \"true\"\n"); + + return pbuf - buf; +} + +static int vcodec_feature_v4ldec_nr(u8 *buf, int size, int vformat, int is_v4l) +{ + u8 *pbuf = buf; + + if (is_v4l) { + pbuf += snprintf(pbuf, size, " \"V4ldec nr\" : \"true\"\n"); + } + + return pbuf - buf; +} + +static int vcodec_feature_ge2d_wrapper(u8 *buf, int size, int vformat, int is_v4l) +{ + u8 *pbuf = buf; + + if (is_v4l && (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T7)) { + pbuf += snprintf(pbuf, size, " \"Ge2d wrapper\" : \"true\"\n"); + } + + return pbuf - buf; +} + + + +int vcodec_feature_get_feature(u8 *buf, int vformat, int is_v4l) +{ + u8 *pbuf = buf; + int size = PAGE_SIZE; + int tsize = 0; + int s; + + s = snprintf(pbuf, size - tsize, " \"%s%s\": ", format_name[vformat], is_v4l ? "_v4l" : ""); + tsize += s; + pbuf += s; + + s = snprintf(pbuf, size - tsize, "{\n"); + tsize += s; + pbuf += s; + + s = vcodec_feature_CC(pbuf, size - tsize, vformat, is_v4l); + tsize += s; + pbuf += s; + + s = vcodec_feature_report_information(pbuf, size - tsize, vformat, is_v4l); + tsize += s; + pbuf += s; + + s = vcodec_feature_vdec_fence(pbuf, size - tsize, vformat); + tsize += s; + pbuf += s; + + s = vcodec_feature_i_only_mode(pbuf, size - tsize, vformat); + tsize += s; + pbuf += s; + + s = vcodec_feature_dolbyVison(pbuf, size - tsize, vformat); + tsize += s; + pbuf += s; + + s = vcodec_feature_HDR(pbuf, size - tsize, vformat); + tsize += s; + pbuf += s; + + s = vcodec_feature_doublewrite(pbuf, size - tsize, vformat); + tsize += s; + pbuf += s; + + s = vcodec_feature_bitdepth(pbuf, size - tsize, vformat); + tsize += s; + pbuf += s; + + s = vcodec_feature_MaxResolution(pbuf, size - tsize, vformat); + tsize += s; + pbuf += s; + + s = vcodec_feature_clock(pbuf, size - tsize, vformat); + tsize += s; + pbuf += s; + + s = vcodec_feature_FCC(pbuf, size - tsize, vformat, is_v4l); + tsize += s; + pbuf += s; + + s = vcodec_feature_RDMA(pbuf, size - tsize, vformat); + tsize += s; + pbuf += s; + + s = vcodec_feature_v4ldec_nr(pbuf, size - tsize, vformat, is_v4l); + tsize += s; + pbuf += s; + + s = vcodec_feature_ge2d_wrapper(pbuf, size - tsize, vformat, is_v4l); + tsize += s; + pbuf += s; + + s = snprintf(pbuf, size - tsize, " \"UcodeVersionRequest\" : \"0.3.10\"\n"); + tsize += s; + pbuf += s; + + s = snprintf(pbuf, size - tsize, " }\n"); + tsize += s; + pbuf += s; + + return pbuf - buf; +} + + +ssize_t vcodec_feature_read(char *buf) +{ + static int read_count; + char *pbuf = buf; + + if (jiffies - last_time > 5 * HZ) { + read_count = 0; + /*timeout :not continue dump,dump from first. */ + } + + if (vcodec_feature_idx > 0) { + if (read_count == 0) + pbuf += snprintf(pbuf, PAGE_SIZE - (pbuf - buf), "{\n"); + pbuf += vcodec_feature_get_feature(pbuf, feature[read_count].format, feature[read_count].is_v4l); + read_count++; + if (read_count >= vcodec_feature_idx) { + read_count = 0; + pbuf += snprintf(pbuf, PAGE_SIZE - (pbuf - buf), "}"); + } + } + last_time = jiffies; + return pbuf - buf; +} +EXPORT_SYMBOL(vcodec_feature_read); + + +int vcodec_feature_register(int vformat, int is_v4l) +{ + if ((vcodec_feature_idx < SUPPORT_VDEC_NUM) && vcodec_feature_support_format(vformat)) { + feature[vcodec_feature_idx].format = vformat; + feature[vcodec_feature_idx].is_v4l = is_v4l; + vcodec_feature_idx++; + //pr_debug("regist %s codec profile\n", vdec_profile->name); + } + + return 0; +} +EXPORT_SYMBOL(vcodec_feature_register); + + +
diff --git a/drivers/frame_provider/decoder/real/vreal.h b/drivers/frame_provider/decoder/utils/vdec_feature.h similarity index 63% copy from drivers/frame_provider/decoder/real/vreal.h copy to drivers/frame_provider/decoder/utils/vdec_feature.h index 734cc6f..a2918fd 100644 --- a/drivers/frame_provider/decoder/real/vreal.h +++ b/drivers/frame_provider/decoder/utils/vdec_feature.h
@@ -1,7 +1,7 @@ /* - * drivers/amlogic/amports/vreal.h + * drivers/amlogic/amports/vdec_profile.h * - * Copyright (C) 2015 Amlogic, Inc. All rights reserved. + * 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 @@ -13,14 +13,15 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - */ +*/ -#ifndef VREAL_H -#define VREAL_H +#ifndef VDEC_FEATURE_H +#define VDEC_FEATURE_H -#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */ -/* TODO: move to register headers */ -#define VPP_VD1_POSTBLEND (1 << 10) -#endif +int vcodec_feature_register(int vformat, int is_v4l); -#endif /* VREAL_H */ +ssize_t vcodec_feature_read(char *buf); + + + +#endif /* VDEC_FEATURE_H */
diff --git a/drivers/frame_provider/decoder/utils/vdec_ge2d_utils.c b/drivers/frame_provider/decoder/utils/vdec_ge2d_utils.c new file mode 100644 index 0000000..08cd0d7 --- /dev/null +++ b/drivers/frame_provider/decoder/utils/vdec_ge2d_utils.c
@@ -0,0 +1,487 @@ +/* + * Copyright (C) 2017 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Description: + */ +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/amlogic/media/ge2d/ge2d.h> +#include <linux/amlogic/media/canvas/canvas_mgr.h> +#include "vdec.h" +#include "vdec_ge2d_utils.h" +#include "../../../common/chips/decoder_cpu_ver_info.h" + +static u32 vdec_ge2d_debug = 0; + +#ifndef CONFIG_AMLOGIC_MEDIA_GE2D +inline struct ge2d_context_s *create_ge2d_work_queue(void) { return NULL; } +inline int destroy_ge2d_work_queue(struct ge2d_context_s *ge2d_work_queue) { return -1; } +#endif + +enum videocom_source_type { + DECODER_8BIT_NORMAL = 0, + DECODER_8BIT_BOTTOM, + DECODER_8BIT_TOP, + DECODER_10BIT_NORMAL, + DECODER_10BIT_BOTTOM, + DECODER_10BIT_TOP +}; + +static void vdec_canvas_cache_free(struct vdec_canvas_cache *canche) +{ + int i = -1; + + for (i = 0; i < ARRAY_SIZE(canche->res); i++) { + if (canche->res[i].cid > 0) { + if (vdec_ge2d_debug) + pr_info("canvas-free, name:%s, canvas id:%d\n", + canche->res[i].name, + canche->res[i].cid); + + canvas_pool_map_free_canvas(canche->res[i].cid); + + canche->res[i].cid = 0; + } + } +} + +static void vdec_canvas_cache_put(struct vdec_ge2d *ge2d) +{ + struct vdec_canvas_cache *canche = &ge2d->canche; + + mutex_lock(&canche->lock); + + pr_info("canvas-put, ref:%d\n", canche->ref); + + canche->ref--; + + if (canche->ref == 0) { + vdec_canvas_cache_free(canche); + } + + mutex_unlock(&canche->lock); +} + +static int vdec_canvas_cache_get(struct vdec_ge2d *ge2d, char *usr) +{ + struct vdec_canvas_cache *canche = &ge2d->canche; + int i; + + mutex_lock(&canche->lock); + + canche->ref++; + + for (i = 0; i < ARRAY_SIZE(canche->res); i++) { + if (canche->res[i].cid <= 0) { + snprintf(canche->res[i].name, 32, "%s-%d", usr, i); + canche->res[i].cid = + canvas_pool_map_alloc_canvas(canche->res[i].name); + } + + if (vdec_ge2d_debug) + pr_info("canvas-alloc, name:%s, canvas id:%d\n", + canche->res[i].name, + canche->res[i].cid); + + if (canche->res[i].cid <= 0) { + pr_err("canvas-fail, name:%s, canvas id:%d.\n", + canche->res[i].name, + canche->res[i].cid); + + mutex_unlock(&canche->lock); + goto err; + } + } + + if (vdec_ge2d_debug) + pr_info("canvas-get, ref:%d\n", canche->ref); + + mutex_unlock(&canche->lock); + return 0; +err: + vdec_canvas_cache_put(ge2d); + return -1; +} + +static int vdec_canvas_cache_init(struct vdec_ge2d *ge2d) +{ + ge2d->canche.ref = 0; + mutex_init(&ge2d->canche.lock); + + pr_info("canvas-init, ref:%d\n", ge2d->canche.ref); + + return 0; +} + +static int get_source_type(struct vframe_s *vf) +{ + enum videocom_source_type ret; + int interlace_mode; + + interlace_mode = vf->type & VIDTYPE_TYPEMASK; + + if ((vf->bitdepth & BITDEPTH_Y10) && + (!(vf->type & VIDTYPE_COMPRESS)) && + (get_cpu_type() >= MESON_CPU_MAJOR_ID_TXL)) { + if (interlace_mode == VIDTYPE_INTERLACE_TOP) + ret = DECODER_10BIT_TOP; + else if (interlace_mode == VIDTYPE_INTERLACE_BOTTOM) + ret = DECODER_10BIT_BOTTOM; + else + ret = DECODER_10BIT_NORMAL; + } else { + if (interlace_mode == VIDTYPE_INTERLACE_TOP) + ret = DECODER_8BIT_TOP; + else if (interlace_mode == VIDTYPE_INTERLACE_BOTTOM) + ret = DECODER_8BIT_BOTTOM; + else + ret = DECODER_8BIT_NORMAL; + } + + return ret; +} + +static int get_input_format(struct vframe_s *vf) +{ + int format = GE2D_FORMAT_M24_YUV420; + enum videocom_source_type soure_type; + + soure_type = get_source_type(vf); + + switch (soure_type) { + case DECODER_8BIT_NORMAL: + if (vf->type & VIDTYPE_VIU_422) + format = GE2D_FORMAT_S16_YUV422; + else if (vf->type & VIDTYPE_VIU_NV21) + format = GE2D_FORMAT_M24_NV21; + else if (vf->type & VIDTYPE_VIU_NV12) + format = GE2D_FORMAT_M24_NV12; + else if (vf->type & VIDTYPE_VIU_444) + format = GE2D_FORMAT_S24_YUV444; + else + format = GE2D_FORMAT_M24_YUV420; + break; + case DECODER_8BIT_BOTTOM: + if (vf->type & VIDTYPE_VIU_422) + format = GE2D_FORMAT_S16_YUV422 + | (GE2D_FORMAT_S16_YUV422B & (3 << 3)); + else if (vf->type & VIDTYPE_VIU_NV21) + format = GE2D_FORMAT_M24_NV21 + | (GE2D_FORMAT_M24_NV21B & (3 << 3)); + else if (vf->type & VIDTYPE_VIU_NV12) + format = GE2D_FORMAT_M24_NV12 + | (GE2D_FORMAT_M24_NV12B & (3 << 3)); + else if (vf->type & VIDTYPE_VIU_444) + format = GE2D_FORMAT_S24_YUV444 + | (GE2D_FORMAT_S24_YUV444B & (3 << 3)); + else + format = GE2D_FORMAT_M24_YUV420 + | (GE2D_FMT_M24_YUV420B & (3 << 3)); + break; + case DECODER_8BIT_TOP: + if (vf->type & VIDTYPE_VIU_422) + format = GE2D_FORMAT_S16_YUV422 + | (GE2D_FORMAT_S16_YUV422T & (3 << 3)); + else if (vf->type & VIDTYPE_VIU_NV21) + format = GE2D_FORMAT_M24_NV21 + | (GE2D_FORMAT_M24_NV21T & (3 << 3)); + else if (vf->type & VIDTYPE_VIU_NV12) + format = GE2D_FORMAT_M24_NV12 + | (GE2D_FORMAT_M24_NV12T & (3 << 3)); + else if (vf->type & VIDTYPE_VIU_444) + format = GE2D_FORMAT_S24_YUV444 + | (GE2D_FORMAT_S24_YUV444T & (3 << 3)); + else + format = GE2D_FORMAT_M24_YUV420 + | (GE2D_FMT_M24_YUV420T & (3 << 3)); + break; + case DECODER_10BIT_NORMAL: + if (vf->type & VIDTYPE_VIU_422) { + if (vf->bitdepth & FULL_PACK_422_MODE) + format = GE2D_FORMAT_S16_10BIT_YUV422; + else + format = GE2D_FORMAT_S16_12BIT_YUV422; + } + break; + case DECODER_10BIT_BOTTOM: + if (vf->type & VIDTYPE_VIU_422) { + if (vf->bitdepth & FULL_PACK_422_MODE) + format = GE2D_FORMAT_S16_10BIT_YUV422 + | (GE2D_FORMAT_S16_10BIT_YUV422B + & (3 << 3)); + else + format = GE2D_FORMAT_S16_12BIT_YUV422 + | (GE2D_FORMAT_S16_12BIT_YUV422B + & (3 << 3)); + } + break; + case DECODER_10BIT_TOP: + if (vf->type & VIDTYPE_VIU_422) { + if (vf->bitdepth & FULL_PACK_422_MODE) + format = GE2D_FORMAT_S16_10BIT_YUV422 + | (GE2D_FORMAT_S16_10BIT_YUV422T + & (3 << 3)); + else + format = GE2D_FORMAT_S16_12BIT_YUV422 + | (GE2D_FORMAT_S16_12BIT_YUV422T + & (3 << 3)); + } + break; + default: + format = GE2D_FORMAT_M24_YUV420; + } + return format; +} + +int vdec_ge2d_init(struct vdec_ge2d** ge2d_handle, int mode) +{ + int ret; + struct vdec_ge2d *ge2d; + + if (!ge2d_handle) + return -EINVAL; + + ge2d = kzalloc(sizeof(*ge2d), GFP_KERNEL); + if (!ge2d) + return -ENOMEM; + + vdec_canvas_cache_init(ge2d); + + ge2d->work_mode = mode; + if (!ge2d->work_mode) { + ge2d->work_mode = GE2D_MODE_CONVERT_LE; + } + pr_info("vdec_ge2d_init work_mode:%d\n", ge2d->work_mode); + + ge2d->ge2d_context = create_ge2d_work_queue(); + if (!ge2d->ge2d_context) { + pr_err("ge2d_create_instance fail\n"); + ret = -EINVAL; + goto error; + } + + if (vdec_canvas_cache_get(ge2d, "vdec-ge2d-dec") < 0) { + pr_err("canvas pool alloc fail. src(%d, %d, %d) dst(%d, %d, %d).\n", + ge2d->canche.res[0].cid, + ge2d->canche.res[1].cid, + ge2d->canche.res[2].cid, + ge2d->canche.res[3].cid, + ge2d->canche.res[4].cid, + ge2d->canche.res[5].cid); + ret = -ENOMEM; + goto error1; + } + + *ge2d_handle = ge2d; + + return 0; +error1: + destroy_ge2d_work_queue(ge2d->ge2d_context); +error: + kfree(ge2d); + + return ret; +} +EXPORT_SYMBOL(vdec_ge2d_init); + +int vdec_ge2d_copy_data(struct vdec_ge2d *ge2d, struct vdec_ge2d_info *ge2d_info) +{ + struct config_para_ex_s ge2d_config; + u32 src_fmt = 0, dst_fmt = 0; + struct canvas_s cd; + + if (!ge2d) + return -1; + + if (vdec_ge2d_debug) + pr_info("vdec_ge2d_copy_data start\n"); + + memset(&ge2d_config, 0, sizeof(ge2d_config)); + + src_fmt = get_input_format(ge2d_info->dst_vf); + if (ge2d_info->src_canvas0_config[0].endian == 7) + src_fmt |= GE2D_BIG_ENDIAN; + else + src_fmt |= GE2D_LITTLE_ENDIAN; + + /* negotiate format of destination */ + dst_fmt = get_input_format(ge2d_info->dst_vf); + if (ge2d->work_mode & GE2D_MODE_CONVERT_NV12) + dst_fmt |= GE2D_FORMAT_M24_NV12; + else if (ge2d->work_mode & GE2D_MODE_CONVERT_NV21) + dst_fmt |= GE2D_FORMAT_M24_NV21; + + if (ge2d->work_mode & GE2D_MODE_CONVERT_LE) + dst_fmt |= GE2D_LITTLE_ENDIAN; + else + dst_fmt |= GE2D_BIG_ENDIAN; + + if ((dst_fmt & GE2D_COLOR_MAP_MASK) == GE2D_COLOR_MAP_NV12) { + ge2d_info->dst_vf->type |= VIDTYPE_VIU_NV12; + ge2d_info->dst_vf->type &= ~VIDTYPE_VIU_NV21; + } else if ((dst_fmt & GE2D_COLOR_MAP_MASK) == GE2D_COLOR_MAP_NV21) { + ge2d_info->dst_vf->type |= VIDTYPE_VIU_NV21; + ge2d_info->dst_vf->type &= ~VIDTYPE_VIU_NV12; + } + if ((dst_fmt & GE2D_ENDIAN_MASK) == GE2D_LITTLE_ENDIAN) { + ge2d_info->dst_vf->canvas0_config[0].endian = 0; + ge2d_info->dst_vf->canvas0_config[1].endian = 0; + ge2d_info->dst_vf->canvas0_config[2].endian = 0; + } else if ((dst_fmt & GE2D_ENDIAN_MASK) == GE2D_BIG_ENDIAN){ + ge2d_info->dst_vf->canvas0_config[0].endian = 7; + ge2d_info->dst_vf->canvas0_config[1].endian = 7; + ge2d_info->dst_vf->canvas0_config[2].endian = 7; + } + + ge2d_info->dst_vf->mem_sec = ge2d_info->dst_vf->flag & VFRAME_FLAG_VIDEO_SECURE ? 1 : 0; + + mutex_lock(&ge2d->canche.lock); + + /* src canvas configure. */ + if ((ge2d_info->dst_vf->canvas0Addr == 0) || + (ge2d_info->dst_vf->canvas0Addr == (u32)-1)) { + canvas_config_config(ge2d->canche.res[0].cid, &ge2d_info->src_canvas0_config[0]); + canvas_config_config(ge2d->canche.res[1].cid, &ge2d_info->src_canvas0_config[1]); + canvas_config_config(ge2d->canche.res[2].cid, &ge2d_info->src_canvas0_config[2]); + ge2d_config.src_para.canvas_index = + ge2d->canche.res[0].cid | + ge2d->canche.res[1].cid << 8 | + ge2d->canche.res[2].cid << 16; + + ge2d_config.src_planes[0].addr = + ge2d_info->src_canvas0_config[0].phy_addr; + ge2d_config.src_planes[0].w = + ge2d_info->src_canvas0_config[0].width; + ge2d_config.src_planes[0].h = + ge2d_info->src_canvas0_config[0].height; + ge2d_config.src_planes[1].addr = + ge2d_info->src_canvas0_config[1].phy_addr; + ge2d_config.src_planes[1].w = + ge2d_info->src_canvas0_config[1].width; + ge2d_config.src_planes[1].h = + ge2d_info->src_canvas0_config[1].height; + ge2d_config.src_planes[2].addr = + ge2d_info->src_canvas0_config[2].phy_addr; + ge2d_config.src_planes[2].w = + ge2d_info->src_canvas0_config[2].width; + ge2d_config.src_planes[2].h = + ge2d_info->src_canvas0_config[2].height; + } else { + ge2d_config.src_para.canvas_index = ge2d_info->src_canvas0Addr; + } + ge2d_config.src_para.mem_type = CANVAS_TYPE_INVALID; + ge2d_config.src_para.format = src_fmt; + ge2d_config.src_para.fill_color_en = 0; + ge2d_config.src_para.fill_mode = 0; + ge2d_config.src_para.x_rev = 0; + ge2d_config.src_para.y_rev = 0; + ge2d_config.src_para.color = 0xffffffff; + ge2d_config.src_para.top = 0; + ge2d_config.src_para.left = 0; + ge2d_config.src_para.width = ge2d_info->dst_vf->width; + if (ge2d_info->dst_vf->type & VIDTYPE_INTERLACE) + ge2d_config.src_para.height = ge2d_info->dst_vf->height >> 1; + else + ge2d_config.src_para.height = ge2d_info->dst_vf->height; + + /* dst canvas configure. */ + canvas_config_config(ge2d->canche.res[3].cid, &ge2d_info->dst_vf->canvas0_config[0]); + if ((ge2d_config.src_para.format & 0xfffff) == GE2D_FORMAT_M24_YUV420) { + ge2d_info->dst_vf->canvas0_config[1].width <<= 1; + } + canvas_config_config(ge2d->canche.res[4].cid, &ge2d_info->dst_vf->canvas0_config[1]); + canvas_config_config(ge2d->canche.res[5].cid, &ge2d_info->dst_vf->canvas0_config[2]); + ge2d_config.dst_para.canvas_index = + ge2d->canche.res[3].cid | + ge2d->canche.res[4].cid << 8; + canvas_read(ge2d->canche.res[3].cid, &cd); + ge2d_config.dst_planes[0].addr = cd.addr; + ge2d_config.dst_planes[0].w = cd.width; + ge2d_config.dst_planes[0].h = cd.height; + canvas_read(ge2d->canche.res[4].cid, &cd); + ge2d_config.dst_planes[1].addr = cd.addr; + ge2d_config.dst_planes[1].w = cd.width; + ge2d_config.dst_planes[1].h = cd.height; + + ge2d_config.dst_para.format = dst_fmt; + ge2d_config.dst_para.width = ge2d_info->dst_vf->width; + ge2d_config.dst_para.height = ge2d_info->dst_vf->height; + ge2d_config.dst_para.mem_type = CANVAS_TYPE_INVALID; + ge2d_config.dst_para.fill_color_en = 0; + ge2d_config.dst_para.fill_mode = 0; + ge2d_config.dst_para.x_rev = 0; + ge2d_config.dst_para.y_rev = 0; + ge2d_config.dst_para.color = 0; + ge2d_config.dst_para.top = 0; + ge2d_config.dst_para.left = 0; + + /* other ge2d parameters configure. */ + ge2d_config.src_key.key_enable = 0; + ge2d_config.src_key.key_mask = 0; + ge2d_config.src_key.key_mode = 0; + ge2d_config.alu_const_color = 0; + ge2d_config.bitmask_en = 0; + ge2d_config.src1_gb_alpha = 0; + ge2d_config.dst_xy_swap = 0; + ge2d_config.src2_para.mem_type = CANVAS_TYPE_INVALID; + ge2d_config.mem_sec = ge2d_info->dst_vf->flag & VFRAME_FLAG_VIDEO_SECURE ? 1 : 0; + + if (ge2d_context_config_ex(ge2d->ge2d_context, &ge2d_config) < 0) { + pr_err("vdec_ge2d_context_config_ex error.\n"); + mutex_unlock(&ge2d->canche.lock); + return -1; + } + + if (!(ge2d_info->dst_vf->type & VIDTYPE_V4L_EOS)) { + if (ge2d_info->dst_vf->type & VIDTYPE_INTERLACE) { + stretchblt_noalpha(ge2d->ge2d_context, + 0, 0, ge2d_info->dst_vf->width, ge2d_info->dst_vf->height / 2, + 0, 0, ge2d_info->dst_vf->width, ge2d_info->dst_vf->height); + } else { + stretchblt_noalpha(ge2d->ge2d_context, + 0, 0, ge2d_info->dst_vf->width, ge2d_info->dst_vf->height, + 0, 0, ge2d_info->dst_vf->width, ge2d_info->dst_vf->height); + } + } + mutex_unlock(&ge2d->canche.lock); + if (vdec_ge2d_debug) + pr_info("vdec_ge2d_copy_data done\n"); + + return 0; +} +EXPORT_SYMBOL(vdec_ge2d_copy_data); + +int vdec_ge2d_destroy(struct vdec_ge2d *ge2d) +{ + if (!ge2d) + return -1; + + pr_info("vdec ge2d destroy begin\n"); + + destroy_ge2d_work_queue(ge2d->ge2d_context); + vdec_canvas_cache_put(ge2d); + kfree(ge2d); + + pr_info("vdec ge2d destroy done\n"); + + return 0; +} +EXPORT_SYMBOL(vdec_ge2d_destroy); + +module_param(vdec_ge2d_debug, int, 0664); +MODULE_PARM_DESC(vdec_ge2d_debug, "\n vdec_ge2d_debug\n");
diff --git a/drivers/frame_provider/decoder/utils/vdec_ge2d_utils.h b/drivers/frame_provider/decoder/utils/vdec_ge2d_utils.h new file mode 100644 index 0000000..31018f7 --- /dev/null +++ b/drivers/frame_provider/decoder/utils/vdec_ge2d_utils.h
@@ -0,0 +1,69 @@ +/* + * Copyright (C) 2017 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Description: + */ +#ifndef __GE2D_UTILS_H__ +#define __GE2D_UTILS_H__ + +//#include "../../../amvdec_ports/aml_vcodec_drv.h" +#include <linux/amlogic/media/vfm/vframe.h> + + +/* define ge2d work mode. */ +#define GE2D_MODE_CONVERT_NV12 (1 << 0) +#define GE2D_MODE_CONVERT_NV21 (1 << 1) +#define GE2D_MODE_CONVERT_LE (1 << 2) +#define GE2D_MODE_CONVERT_BE (1 << 3) +#define GE2D_MODE_SEPARATE_FIELD (1 << 4) +#define GE2D_MODE_422_TO_420 (1 << 5) + +struct vdec_canvas_res { + int cid; + u8 name[32]; +}; + +struct vdec_canvas_cache { + int ref; + struct vdec_canvas_res res[6]; + struct mutex lock; +}; + +struct vdec_ge2d { + u32 work_mode; /* enum ge2d_work_mode */ + struct ge2d_context_s *ge2d_context; /* handle of GE2D */ + struct aml_vcodec_ctx *ctx; + struct vdec_canvas_cache canche; + void *hw; +}; + +struct vdec_ge2d_info { + struct vframe_s *dst_vf; + u32 src_canvas0Addr; + u32 src_canvas1Addr;; + struct canvas_config_s src_canvas0_config[3]; + struct canvas_config_s src_canvas1_config[3]; +}; + +int vdec_ge2d_init(struct vdec_ge2d** ge2d_handle, int mode); + +int vdec_ge2d_copy_data(struct vdec_ge2d *ge2d, struct vdec_ge2d_info *ge2d_info); + +int vdec_ge2d_destroy(struct vdec_ge2d *ge2d); + +#endif +
diff --git a/drivers/frame_provider/decoder/utils/vdec_input.c b/drivers/frame_provider/decoder/utils/vdec_input.c index 5deb374..6fec0ad 100644 --- a/drivers/frame_provider/decoder/utils/vdec_input.c +++ b/drivers/frame_provider/decoder/utils/vdec_input.c
@@ -20,15 +20,12 @@ #include <linux/slab.h> #include <linux/dma-mapping.h> #include <linux/amlogic/media/codec_mm/codec_mm.h> - #include "../../../stream_input/amports/amports_priv.h" #include "vdec.h" #include "vdec_input.h" - #include <asm/cacheflush.h> #include <linux/crc32.h> - #define VFRAME_BLOCK_SIZE (512 * SZ_1K)/*512 for 1080p default init.*/ #define VFRAME_BLOCK_SIZE_4K (2 * SZ_1M) /*2M for 4K default.*/ #define VFRAME_BLOCK_SIZE_MAX (4 * SZ_1M) @@ -64,7 +61,7 @@ { int ret =0; - if (likely(access_ok(VERIFY_READ, from, n))) + if (likely(access_ok(from, n))) ret = copy_from_user(to, from, n); else memcpy(to, from, n); @@ -348,6 +345,7 @@ char sbuf[512]; int tsize = 0; int s; + if (!pbuf) { pbuf = sbuf; size = 512; @@ -434,6 +432,7 @@ s += vdec_input_dump_block_locked(block, lbuf, size - s); } vdec_input_unlock(input, flags); + return s; } @@ -446,6 +445,7 @@ char sbuf[512]; int tsize = 0; int s; + if (!pbuf) { pbuf = sbuf; size = 512; @@ -492,6 +492,7 @@ if (size <= 0) return 0; + if (!bufs) lbuf = sbuf; s = snprintf(lbuf + s, size - s, @@ -522,6 +523,7 @@ break; } vdec_input_unlock(input, flags); + return s; } @@ -549,6 +551,7 @@ if (input->swap_page_phys == 0) return -ENOMEM; + return 0; } EXPORT_SYMBOL(vdec_input_set_buffer); @@ -788,6 +791,7 @@ struct vframe_chunk_s *chunk; struct vdec_s *vdec = input->vdec; struct vframe_block_list_s *block; + int need_pading_size = MIN_FRAME_PADDING_SIZE; if (vdec_secure(vdec)) { @@ -1212,5 +1216,3 @@ return handle; } EXPORT_SYMBOL(vdec_input_get_freed_handle); - -
diff --git a/drivers/frame_provider/decoder/utils/vdec_power_ctrl.c b/drivers/frame_provider/decoder/utils/vdec_power_ctrl.c index 9057a80..e43c45a 100644 --- a/drivers/frame_provider/decoder/utils/vdec_power_ctrl.c +++ b/drivers/frame_provider/decoder/utils/vdec_power_ctrl.c
@@ -19,8 +19,10 @@ #include "vdec_power_ctrl.h" #include <linux/amlogic/media/utils/vdec_reg.h> #include <linux/amlogic/power_ctrl.h> +//#include <dt-bindings/power/sc2-pd.h> +//#include <linux/amlogic/pwr_ctrl.h> +#include <linux/amlogic/power_domain.h> #include <dt-bindings/power/sc2-pd.h> -#include <linux/amlogic/pwr_ctrl.h> #include <linux/amlogic/media/codec_mm/codec_mm.h> #include "../../../common/media_clock/switch/amports_gate.h" #include "../../../common/chips/decoder_cpu_ver_info.h" @@ -29,6 +31,12 @@ #define HEVC_TEST_LIMIT (100) #define GXBB_REV_A_MINOR (0xa) +#define PDID_DSP 0 +#define PDID_DOS_HCODEC 1 +#define PDID_DOS_HEVC 2 +#define PDID_DOS_VDEC 3 +#define PDID_DOS_WAVE 4 + extern int no_powerdown; extern int hevc_max_reset_count; @@ -136,14 +144,20 @@ hcodec_clock_enable(); } else if (id == VDEC_HEVC) { /* enable hevc clock */ - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2) + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2 && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5) && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5D)) amports_switch_gate("clk_hevcf_mux", 1); else amports_switch_gate("clk_hevc_mux", 1); - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) && + !is_hevc_front_back_clk_combined()) amports_switch_gate("clk_hevcb_mux", 1); + hevc_clock_hi_enable(); - hevc_back_clock_hi_enable(); + + if (!is_hevc_front_back_clk_combined()) + hevc_back_clock_hi_enable(); } } @@ -156,7 +170,8 @@ } else if (id == VDEC_HEVC) { /* disable hevc clock */ hevc_clock_off(); - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) && + !is_hevc_front_back_clk_combined()) hevc_back_clock_off(); } } @@ -693,7 +708,6 @@ pm_vdec_clock_on(id); pwr_ctrl_psci_smc(pd_id, PWR_ON); - } static void pm_vdec_pd_sec_api_power_off(struct device *dev, int id) @@ -720,7 +734,7 @@ #if 0 int pd_id = (id == VDEC_1) ? PM_DOS_VDEC : (id == VDEC_HEVC) ? PM_DOS_HEVC : - PM_DOS_HCODEC; + PM_DOS_HCODEC; pm_vdec_clock_on(id); power_domain_switch(pd_id, PWR_ON);
diff --git a/drivers/frame_provider/decoder/utils/vdec_power_ctrl.h b/drivers/frame_provider/decoder/utils/vdec_power_ctrl.h index 53545f8..e7ab77e 100644 --- a/drivers/frame_provider/decoder/utils/vdec_power_ctrl.h +++ b/drivers/frame_provider/decoder/utils/vdec_power_ctrl.h
@@ -90,10 +90,10 @@ #define DL_FLAG_RPM_ACTIVE BIT(3) #define DL_FLAG_AUTOREMOVE_SUPPLIER BIT(4) -//struct device_link { -// u32 flags; -// /* ... */ -//}; +struct device_link { + u32 flags; + /* ... */ +}; static inline struct device *dev_pm_domain_attach_by_name(struct device *dev, const char *name)
diff --git a/drivers/frame_provider/decoder/utils/vdec_profile.c b/drivers/frame_provider/decoder/utils/vdec_profile.c index 94f8b8f..dfffeb1 100644 --- a/drivers/frame_provider/decoder/utils/vdec_profile.c +++ b/drivers/frame_provider/decoder/utils/vdec_profile.c
@@ -20,14 +20,12 @@ #include <linux/types.h> #include <linux/debugfs.h> #include <linux/moduleparam.h> - - +#include <linux/sched/clock.h> #include <linux/amlogic/media/utils/vdec_reg.h> #include <trace/events/meson_atrace.h> #include "vdec_profile.h" #include "vdec.h" - #define ISA_TIMERE 0x2662 #define ISA_TIMERE_HI 0x2663 @@ -112,11 +110,7 @@ static u64 get_us_time_system(void) { - struct timeval tv; - - do_gettimeofday(&tv); - - return div64_u64(timeval_to_ns(&tv), 1000); + return div64_u64(local_clock(), 1000); } static void vdec_profile_update_alloc_time(
diff --git a/drivers/frame_provider/decoder/utils/vdec_sync.c b/drivers/frame_provider/decoder/utils/vdec_sync.c index 314a4f0..b4192f6 100644 --- a/drivers/frame_provider/decoder/utils/vdec_sync.c +++ b/drivers/frame_provider/decoder/utils/vdec_sync.c
@@ -21,15 +21,24 @@ #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/slab.h> +#include <linux/sched/clock.h> #include <linux/sync_file.h> #include "vdec_sync.h" #define VDEC_DBG_ENABLE_FENCE (0x100) +#define VDEC_SYNC_COUNT 32 -extern u32 debug; +struct vdec_sync_core_s { + struct vdec_sync s_vdec_sync[VDEC_SYNC_COUNT]; + spinlock_t vdec_sync_lock; +}; -static const struct fence_ops timeline_fence_ops; -static inline struct sync_pt *fence_to_sync_pt(struct fence *fence) +static struct vdec_sync_core_s vdec_sync_core; + +extern u32 vdec_get_debug(void); + +static const struct dma_fence_ops timeline_fence_ops; +static inline struct sync_pt *fence_to_sync_pt(struct dma_fence *fence) { if (fence->ops != &timeline_fence_ops) return NULL; @@ -52,7 +61,7 @@ return NULL; kref_init(&obj->kref); - obj->context = fence_context_alloc(1); + obj->context = dma_fence_context_alloc(1); obj->timestamp = local_clock(); strlcpy(obj->name, name, sizeof(obj->name)); INIT_LIST_HEAD(&obj->active_list_head); @@ -66,9 +75,12 @@ { struct sync_timeline *obj = container_of(kref, struct sync_timeline, kref); + struct vdec_sync *sync = obj->parent_sync; pr_info("[VDEC-FENCE] free timeline: %lx\n", (ulong) obj); kfree(obj); + atomic_set(&sync->use_flag, 0); + sync->timeline = NULL; } static void sync_timeline_get(struct sync_timeline *obj) @@ -81,21 +93,21 @@ kref_put(&obj->kref, sync_timeline_free); } -static const char *timeline_fence_get_driver_name(struct fence *fence) +static const char *timeline_fence_get_driver_name(struct dma_fence *fence) { struct sync_timeline *parent = fence_parent(fence); return parent->name; } -static const char *timeline_fence_get_timeline_name(struct fence *fence) +static const char *timeline_fence_get_timeline_name(struct dma_fence *fence) { struct sync_timeline *parent = fence_parent(fence); return parent->name; } -static void timeline_fence_release(struct fence *fence) +static void timeline_fence_release(struct dma_fence *fence) { struct sync_pt *pt = fence_to_sync_pt(fence); struct sync_timeline *parent = fence_parent(fence); @@ -109,15 +121,15 @@ list_del(&pt->active_list); spin_unlock_irqrestore(fence->lock, flags); sync_timeline_put(parent); - fence_free(fence); + dma_fence_free(fence); } -static bool timeline_fence_signaled(struct fence *fence) +static bool timeline_fence_signaled(struct dma_fence *fence) { struct sync_timeline *parent = fence_parent(fence); struct sync_pt *pt = get_sync_pt(fence); - if (__fence_is_later(fence->seqno, parent->value)) + if (__dma_fence_is_later(fence->seqno, parent->value, fence->ops)) return false; if (pt->timestamp > parent->timestamp) @@ -126,7 +138,7 @@ return true; } -static bool timeline_fence_enable_signaling(struct fence *fence) +static bool timeline_fence_enable_signaling(struct dma_fence *fence) { struct sync_pt *pt = container_of(fence, struct sync_pt, fence); struct sync_timeline *parent = fence_parent(fence); @@ -138,20 +150,22 @@ return true; } -static void timeline_fence_disable_signaling(struct fence *fence) +#if 0 +static void timeline_fence_disable_signaling(struct dma_fence *fence) { struct sync_pt *pt = container_of(fence, struct sync_pt, fence); list_del_init(&pt->active_list); } +#endif -static void timeline_fence_value_str(struct fence *fence, +static void timeline_fence_value_str(struct dma_fence *fence, char *str, int size) { - snprintf(str, size, "%d", fence->seqno); + snprintf(str, size, "%llu", fence->seqno); } -static void timeline_fence_timeline_value_str(struct fence *fence, +static void timeline_fence_timeline_value_str(struct dma_fence *fence, char *str, int size) { struct sync_timeline *parent = fence_parent(fence); @@ -159,13 +173,13 @@ snprintf(str, size, "%d", parent->value); } -static const struct fence_ops timeline_fence_ops = { +static const struct dma_fence_ops timeline_fence_ops = { .get_driver_name = timeline_fence_get_driver_name, .get_timeline_name = timeline_fence_get_timeline_name, .enable_signaling = timeline_fence_enable_signaling, - .disable_signaling = timeline_fence_disable_signaling, + //.disable_signaling = timeline_fence_disable_signaling, .signaled = timeline_fence_signaled, - .wait = fence_default_wait, + .wait = dma_fence_default_wait, .release = timeline_fence_release, .fence_value_str = timeline_fence_value_str, .timeline_value_str = timeline_fence_timeline_value_str, @@ -188,7 +202,7 @@ obj->value += inc; list_for_each_entry_safe(pt, next, &obj->active_list_head, active_list) { - if (fence_is_signaled(&pt->fence)) + if (dma_fence_is_signaled_locked(&pt->fence)) list_del_init(&pt->active_list); } spin_unlock_irqrestore(&obj->lock, flags); @@ -215,7 +229,7 @@ return NULL; spin_lock_irqsave(&obj->lock, flags); sync_timeline_get(obj); - fence_init(&pt->fence, &timeline_fence_ops, &obj->lock, + dma_fence_init(&pt->fence, &timeline_fence_ops, &obj->lock, obj->context, value); list_add_tail(&pt->link, &obj->pt_list); INIT_LIST_HEAD(&pt->active_list); @@ -238,7 +252,7 @@ } static int timeline_create_fence(struct vdec_sync *sync, int usage, - struct fence **fence, int *fd, u32 value) + struct dma_fence **fence, int *fd, u32 value) { int ret; struct sync_pt *pt; @@ -256,7 +270,7 @@ if (usage == FENCE_USE_FOR_APP) { *fd = get_unused_fd_flags(O_CLOEXEC); if (*fd < 0) { - ret = -EBADF; + return -EBADF; goto err; } @@ -269,16 +283,16 @@ fd_install(*fd, sync_file->file); /* decreases refcnt. */ - fence_put(&pt->fence); + dma_fence_put(&pt->fence); } *fence = &pt->fence; pt->timestamp = local_clock(); - if (debug & VDEC_DBG_ENABLE_FENCE) + if (vdec_get_debug() & VDEC_DBG_ENABLE_FENCE) pr_info("[VDEC-FENCE]: create fence: %lx, fd: %d, ref: %d, usage: %d\n", - (ulong) &pt->fence, *fd, atomic_read(&pt->fence.refcount.refcount), usage); + (ulong) &pt->fence, *fd, atomic_read(&pt->fence.refcount.refcount.refs), usage); return 0; err: put_unused_fd(*fd); @@ -288,35 +302,64 @@ return ret; } -struct fence *vdec_fence_get(int fd) +struct dma_fence *vdec_fence_get(int fd) { return sync_file_get_fence(fd); } EXPORT_SYMBOL(vdec_fence_get); -void vdec_fence_put(struct fence *fence) +void vdec_fence_put(struct dma_fence *fence) { - if (debug & VDEC_DBG_ENABLE_FENCE) + if (vdec_get_debug() & VDEC_DBG_ENABLE_FENCE) pr_info("[VDEC-FENCE]: the fence (%px) cost time: %lld ns\n", fence, local_clock() - get_sync_pt(fence)->timestamp); - fence_put(fence); + dma_fence_put(fence); } EXPORT_SYMBOL(vdec_fence_put); -int vdec_fence_wait(struct fence *fence, long timeout) +int vdec_fence_wait(struct dma_fence *fence, long timeout) { - if (debug & VDEC_DBG_ENABLE_FENCE) + if (vdec_get_debug() & VDEC_DBG_ENABLE_FENCE) pr_info("[VDEC-FENCE]: wait fence %lx.\n", (ulong) fence); - return fence_wait_timeout(fence, false, timeout); + return dma_fence_wait_timeout(fence, false, timeout); } EXPORT_SYMBOL(vdec_fence_wait); +struct vdec_sync *vdec_sync_get(void) +{ + int i; + struct vdec_sync_core_s *core = &vdec_sync_core; + ulong flags; + + spin_lock_irqsave(&core->vdec_sync_lock, flags); + + for (i = 0; i < VDEC_SYNC_COUNT; i++) { + if (atomic_read(&core->s_vdec_sync[i].use_flag) == 0) { + int j; + atomic_set(&core->s_vdec_sync[i].use_flag, 1); + for (j = 0; j < 64; j++) { + core->s_vdec_sync[i].release_callback[j].func = vdec_fence_buffer_count_decrease; + core->s_vdec_sync[i].release_callback[j].private_data = (void *)&core->s_vdec_sync[i]; + } + spin_unlock_irqrestore(&core->vdec_sync_lock, flags); + return &core->s_vdec_sync[i]; + } + } + spin_unlock_irqrestore(&core->vdec_sync_lock, flags); + return 0; +} +EXPORT_SYMBOL(vdec_sync_get); + void vdec_timeline_create(struct vdec_sync *sync, u8 *name) { + struct sync_timeline *obj; snprintf(sync->name, sizeof(sync->name), "%s", name); - sync->timeline = (void *)sync_timeline_create(sync->name); + obj = sync_timeline_create(sync->name); + obj->parent_sync = sync; + sync->timeline = (void *)obj; + if (sync->timeline) pr_info("[VDEC-FENCE]: create timeline %lx, name: %s\n", (ulong) sync->timeline, sync->name); @@ -337,13 +380,12 @@ spin_lock_irqsave(&obj->lock, flags); - pt = list_last_entry(&obj->pt_list, struct sync_pt, link); value = obj->value + 1; if (!list_empty(&obj->pt_list)) { pt = list_last_entry(&obj->pt_list, struct sync_pt, link); - if (value == pt->fence.seqno) { - value++; + if (value <= pt->fence.seqno) { + value = pt->fence.seqno + 1; } } spin_unlock_irqrestore(&obj->lock, flags); @@ -365,7 +407,7 @@ obj->timestamp = local_clock(); - if (debug & VDEC_DBG_ENABLE_FENCE) + if (vdec_get_debug() & VDEC_DBG_ENABLE_FENCE) pr_info("[VDEC-FENCE]: update timeline %d.\n", obj->value + value); @@ -373,6 +415,15 @@ } EXPORT_SYMBOL(vdec_timeline_increase); +void vdec_timeline_get(struct vdec_sync *sync) +{ + struct sync_timeline *obj = sync->timeline; + + sync_timeline_get(obj); +} +EXPORT_SYMBOL(vdec_timeline_get); + + void vdec_timeline_put(struct vdec_sync *sync) { struct sync_timeline *obj = sync->timeline; @@ -381,15 +432,15 @@ } EXPORT_SYMBOL(vdec_timeline_put); -void vdec_fence_status_set(struct fence *fence, int status) +void vdec_fence_status_set(struct dma_fence *fence, int status) { fence->error = status; } EXPORT_SYMBOL(vdec_fence_status_set); -int vdec_fence_status_get(struct fence *fence) +int vdec_fence_status_get(struct dma_fence *fence) { - return fence_get_status(fence); + return dma_fence_get_status(fence); } EXPORT_SYMBOL(vdec_fence_status_get); @@ -409,19 +460,72 @@ int vdec_clean_all_fence(struct vdec_sync *sync) { - struct sync_timeline *obj = sync->timeline; + /*struct sync_timeline *obj = sync->timeline; struct sync_pt *pt, *next; spin_lock_irq(&obj->lock); list_for_each_entry_safe(pt, next, &obj->pt_list, link) { - fence_set_error(&pt->fence, -ENOENT); - fence_signal_locked(&pt->fence); + dma_fence_set_error(&pt->fence, -ENOENT); + dma_fence_signal_locked(&pt->fence); } - spin_unlock_irq(&obj->lock); + spin_unlock_irq(&obj->lock);*/ + + struct sync_pt *pt, *next; + struct sync_timeline *obj = sync->timeline; + + list_for_each_entry_safe(pt, next, &obj->pt_list, link) { + pr_err("vdec_clean_all_fence %px\n" , obj->parent_sync); + vdec_fence_put(&pt->fence); + } + + sync_timeline_put(obj); return 0; } EXPORT_SYMBOL(vdec_clean_all_fence); +void vdec_fence_buffer_count_increase(ulong fence) +{ + struct vdec_sync *sync = (struct vdec_sync *)fence; + struct sync_timeline *obj = sync->timeline; + + spin_lock_irq(&obj->lock); + + if (atomic_read(&sync->buffer_count) == 0) { + sync_timeline_get(obj); + } + + atomic_inc(&sync->buffer_count); + + spin_unlock_irq(&obj->lock); +} +EXPORT_SYMBOL(vdec_fence_buffer_count_increase); + +void vdec_fence_buffer_count_decrease(struct codec_mm_s *mm, struct codec_mm_cb_s *cb) +{ + struct vdec_sync *sync = (struct vdec_sync *)cb->private_data; + struct sync_pt *pt, *next; + struct sync_timeline *obj = sync->timeline; + + atomic_dec(&sync->buffer_count); + + if (atomic_read(&sync->buffer_count) == 0) { + sync_timeline_put(obj); + list_for_each_entry_safe(pt, next, &obj->pt_list, link) { + vdec_fence_put(&pt->fence); + } + return; + } + return ; +} +EXPORT_SYMBOL(vdec_fence_buffer_count_decrease); + +void vdec_sync_core_init(void) +{ + spin_lock_init(&vdec_sync_core.vdec_sync_lock); +} +EXPORT_SYMBOL(vdec_sync_core_init); + +
diff --git a/drivers/frame_provider/decoder/utils/vdec_sync.h b/drivers/frame_provider/decoder/utils/vdec_sync.h index 0622341..6637b42 100644 --- a/drivers/frame_provider/decoder/utils/vdec_sync.h +++ b/drivers/frame_provider/decoder/utils/vdec_sync.h
@@ -20,9 +20,11 @@ #include <linux/list.h> #include <linux/rbtree.h> #include <linux/spinlock.h> -#include <linux/fence.h> +#include <linux/dma-fence.h> #include <linux/sync_file.h> #include <uapi/linux/sync_file.h> +#include <linux/device.h> +#include <linux/amlogic/media/codec_mm/codec_mm.h> #define FENCE_USE_FOR_DRIVER (0) #define FENCE_USE_FOR_APP (1) @@ -40,10 +42,11 @@ spinlock_t lock; u64 timestamp; + struct vdec_sync *parent_sync; }; struct sync_pt { - struct fence fence; + struct dma_fence fence; struct list_head link; struct list_head active_list; u64 timestamp; @@ -54,24 +57,27 @@ void *timeline; int usage; int fd; - struct fence *fence; + struct dma_fence *fence; + atomic_t buffer_count; + atomic_t use_flag; + struct codec_mm_cb_s release_callback[64]; }; -static inline struct sync_timeline *fence_parent(struct fence *fence) +static inline struct sync_timeline *fence_parent(struct dma_fence *fence) { return container_of(fence->lock, struct sync_timeline, lock); } -static inline struct sync_pt *get_sync_pt(struct fence *fence) +static inline struct sync_pt *get_sync_pt(struct dma_fence *fence) { return container_of(fence, struct sync_pt, fence); } -struct fence *vdec_fence_get(int fd); +struct dma_fence *vdec_fence_get(int fd); -void vdec_fence_put(struct fence *fence); +void vdec_fence_put(struct dma_fence *fence); -int vdec_fence_wait(struct fence *fence, long timeout); +int vdec_fence_wait(struct dma_fence *fence, long timeout); void vdec_timeline_create(struct vdec_sync *sync, u8 *name); @@ -79,13 +85,23 @@ void vdec_timeline_increase(struct vdec_sync *sync, u32 value); +void vdec_timeline_get(struct vdec_sync *sync); + void vdec_timeline_put(struct vdec_sync *sync); -int vdec_fence_status_get(struct fence *fence); +int vdec_fence_status_get(struct dma_fence *fence); -void vdec_fence_status_set(struct fence *fence, int status); +void vdec_fence_status_set(struct dma_fence *fence, int status); bool check_objs_all_signaled(struct vdec_sync *sync); int vdec_clean_all_fence(struct vdec_sync *sync); +void vdec_fence_buffer_count_increase(ulong fence); + +void vdec_fence_buffer_count_decrease(struct codec_mm_s *mm, struct codec_mm_cb_s *cb); + +struct vdec_sync *vdec_sync_get(void); + +void vdec_sync_core_init(void); +
diff --git a/drivers/frame_provider/decoder/utils/vdec_v4l2_buffer_ops.c b/drivers/frame_provider/decoder/utils/vdec_v4l2_buffer_ops.c index e892127..34bc21a 100644 --- a/drivers/frame_provider/decoder/utils/vdec_v4l2_buffer_ops.c +++ b/drivers/frame_provider/decoder/utils/vdec_v4l2_buffer_ops.c
@@ -21,21 +21,6 @@ #include <media/v4l2-mem2mem.h> #include <linux/printk.h> -int vdec_v4l_get_buffer(struct aml_vcodec_ctx *ctx, - struct vdec_v4l2_buffer **out) -{ - int ret = -1; - - if (ctx->drv_handle == 0) - return -EIO; - - ret = ctx->dec_if->get_param(ctx->drv_handle, - GET_PARAM_FREE_FRAME_BUFFER, out); - - return ret; -} -EXPORT_SYMBOL(vdec_v4l_get_buffer); - int vdec_v4l_get_pic_info(struct aml_vcodec_ctx *ctx, struct vdec_pic_info *pic) { @@ -51,6 +36,21 @@ } EXPORT_SYMBOL(vdec_v4l_get_pic_info); +int vdec_v4l_set_cfg_infos(struct aml_vcodec_ctx *ctx, + struct aml_vdec_cfg_infos *cfg) +{ + int ret = 0; + + if (ctx->drv_handle == 0) + return -EIO; + + ret = ctx->dec_if->set_param(ctx->drv_handle, + SET_PARAM_CFG_INFO, cfg); + + return ret; +} +EXPORT_SYMBOL(vdec_v4l_set_cfg_infos); + int vdec_v4l_set_ps_infos(struct aml_vcodec_ctx *ctx, struct aml_vdec_ps_infos *ps) { @@ -66,6 +66,22 @@ } EXPORT_SYMBOL(vdec_v4l_set_ps_infos); +int vdec_v4l_set_comp_buf_info(struct aml_vcodec_ctx *ctx, + struct vdec_comp_buf_info *info) +{ + int ret = 0; + + if (ctx->drv_handle == 0) + return -EIO; + + ret = ctx->dec_if->set_param(ctx->drv_handle, + SET_PARAM_COMP_BUF_INFO, info); + + return ret; + +} +EXPORT_SYMBOL(vdec_v4l_set_comp_buf_info); + int vdec_v4l_set_hdr_infos(struct aml_vcodec_ctx *ctx, struct aml_vdec_hdr_infos *hdr) { @@ -81,50 +97,10 @@ } EXPORT_SYMBOL(vdec_v4l_set_hdr_infos); -static void aml_wait_dpb_ready(struct aml_vcodec_ctx *ctx) -{ - ulong expires; - - expires = jiffies + msecs_to_jiffies(1000); - while (!ctx->v4l_codec_dpb_ready) { - u32 ready_num = 0; - - if (time_after(jiffies, expires)) { - pr_err("the DPB state has not ready.\n"); - break; - } - - ready_num = v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx); - if ((ready_num + ctx->buf_used_count) >= ctx->dpb_size) - ctx->v4l_codec_dpb_ready = true; - } -} - void aml_vdec_pic_info_update(struct aml_vcodec_ctx *ctx) { - unsigned int dpbsize = 0; - int ret; - - if (ctx->dec_if->get_param(ctx->drv_handle, GET_PARAM_PIC_INFO, &ctx->last_decoded_picinfo)) { - pr_err("Cannot get param : GET_PARAM_PICTURE_INFO ERR\n"); - return; - } - - if (ctx->last_decoded_picinfo.visible_width == 0 || - ctx->last_decoded_picinfo.visible_height == 0 || - ctx->last_decoded_picinfo.coded_width == 0 || - ctx->last_decoded_picinfo.coded_height == 0) { - pr_err("Cannot get correct pic info\n"); - return; - } - - ret = ctx->dec_if->get_param(ctx->drv_handle, GET_PARAM_DPB_SIZE, &dpbsize); - if (dpbsize == 0) - pr_err("Incorrect dpb size, ret=%d\n", ret); - - /* update picture information */ - ctx->dpb_size = dpbsize; - ctx->picinfo = ctx->last_decoded_picinfo; + if (ctx != NULL) + ctx->vdec_pic_info_update(ctx); } int vdec_v4l_post_evet(struct aml_vcodec_ctx *ctx, u32 event) @@ -150,9 +126,6 @@ if (ctx->drv_handle == 0) return -EIO; - /* wait the DPB state to be ready. */ - aml_wait_dpb_ready(ctx); - aml_vdec_pic_info_update(ctx); mutex_lock(&ctx->state_lock); @@ -163,8 +136,9 @@ mutex_unlock(&ctx->state_lock); - ctx->q_data[AML_Q_DATA_SRC].resolution_changed = true; - v4l2_m2m_job_pause(dev->m2m_dev_dec, ctx->m2m_ctx); + while (ctx->m2m_ctx->job_flags & TRANS_RUNNING) { + v4l2_m2m_job_pause(dev->m2m_dev_dec, ctx->m2m_ctx); + } return ret; } @@ -185,3 +159,17 @@ } EXPORT_SYMBOL(vdec_v4l_write_frame_sync); +int vdec_v4l_get_dw_mode(struct aml_vcodec_ctx *ctx, + unsigned int *dw_mode) +{ + int ret = -1; + + if (ctx->drv_handle == 0) + return -EIO; + + ret = ctx->dec_if->get_param(ctx->drv_handle, + GET_PARAM_DW_MODE, dw_mode); + + return ret; +} +EXPORT_SYMBOL(vdec_v4l_get_dw_mode);
diff --git a/drivers/frame_provider/decoder/utils/vdec_v4l2_buffer_ops.h b/drivers/frame_provider/decoder/utils/vdec_v4l2_buffer_ops.h index 1494f10..98513d9 100644 --- a/drivers/frame_provider/decoder/utils/vdec_v4l2_buffer_ops.h +++ b/drivers/frame_provider/decoder/utils/vdec_v4l2_buffer_ops.h
@@ -23,18 +23,22 @@ #include "../../../amvdec_ports/vdec_drv_base.h" #include "../../../amvdec_ports/aml_vcodec_adapt.h" -int vdec_v4l_get_buffer( - struct aml_vcodec_ctx *ctx, - struct vdec_v4l2_buffer **out); - int vdec_v4l_get_pic_info( struct aml_vcodec_ctx *ctx, struct vdec_pic_info *pic); +int vdec_v4l_set_cfg_infos( + struct aml_vcodec_ctx *ctx, + struct aml_vdec_cfg_infos *cfg); + int vdec_v4l_set_ps_infos( struct aml_vcodec_ctx *ctx, struct aml_vdec_ps_infos *ps); +int vdec_v4l_set_comp_buf_info( + struct aml_vcodec_ctx *ctx, + struct vdec_comp_buf_info *info); + int vdec_v4l_set_hdr_infos( struct aml_vcodec_ctx *ctx, struct aml_vdec_hdr_infos *hdr); @@ -49,4 +53,8 @@ int vdec_v4l_res_ch_event( struct aml_vcodec_ctx *ctx); +int vdec_v4l_get_dw_mode( + struct aml_vcodec_ctx *ctx, + unsigned int *dw_mode); + #endif
diff --git a/drivers/frame_provider/decoder/vav1/av1_bufmgr.c b/drivers/frame_provider/decoder/vav1/av1_bufmgr.c index 41a522f..1e45320 100644 --- a/drivers/frame_provider/decoder/vav1/av1_bufmgr.c +++ b/drivers/frame_provider/decoder/vav1/av1_bufmgr.c
@@ -530,16 +530,23 @@ void av1_bufmgr_ctx_reset(AV1Decoder *pbi, BufferPool *const pool, AV1_COMMON *cm) { + u32 save_w, save_h; + if (!pbi || !pool || !cm) return; reset_frame_buffers(pbi); memset(pbi, 0, sizeof(*pbi)); + /*save w,h for resolution change after seek */ + save_w = cm->width; + save_h = cm->height; memset(cm, 0, sizeof(*cm)); cm->current_frame.frame_number = 0; cm->seq_params.bit_depth = AOM_BITS_8; cm->error.setjmp = 0; + cm->width = save_w; + cm->height = save_h; pbi->bufmgr_proc_count = 0; pbi->need_resync = 1; @@ -585,6 +592,17 @@ } } +void clear_frame_buf_ref_count(AV1Decoder *pbi) +{ + int i; + + for (i = 0; i < pbi->num_output_frames; i++) { + decrease_ref_count(pbi, pbi->output_frames[i], + pbi->common->buffer_pool); + } + pbi->num_output_frames = 0; +} + static void swap_frame_buffers(AV1Decoder *pbi, int frame_decoded) { int ref_index = 0, mask; AV1_COMMON *const cm = pbi->common; @@ -958,9 +976,10 @@ #ifdef ORI_CODE fail: +#endif // clear the mi_* values to force a realloc on resync av1_set_mb_mi(cm, 0, 0); - +#ifdef ORI_CODE av1_free_context_buffers(cm); #endif return 1; @@ -2016,6 +2035,7 @@ // See if this frame can be used as show_existing_frame in future cm->showable_frame = params->p.showable_frame;//aom_rb_read_bit(rb); } + cm->cur_frame->show_frame = cm->show_frame; cm->cur_frame->showable_frame = cm->showable_frame; cm->error_resilient_mode = frame_is_sframe(cm) || @@ -2926,6 +2946,14 @@ // TODO(wtc): Verify that the frame_header_obu is identical to the // original frame_header_obu. For now just skip frame_header_size // bytes in the bit buffer. + if (frame_header_size > payload_size) { + cm->error.error_code = AOM_CODEC_CORRUPT_FRAME; + return -1; + } + assert(rb.bit_offset == 0); +#ifdef ORI_CODE + rb.bit_offset = 8 * frame_header_size; +#endif } decoded_payload_size = frame_header_size; @@ -2984,7 +3012,6 @@ } } } - return i; }
diff --git a/drivers/frame_provider/decoder/vav1/av1_global.h b/drivers/frame_provider/decoder/vav1/av1_global.h index 75af688..e12b224 100644 --- a/drivers/frame_provider/decoder/vav1/av1_global.h +++ b/drivers/frame_provider/decoder/vav1/av1_global.h
@@ -52,13 +52,6 @@ #define AOMMIN(x, y) (((x) < (y)) ? (x) : (y)) #define AOMMAX(x, y) (((x) > (y)) ? (x) : (y)) -//typedef char int8_t; -//#ifndef BUFMGR_FOR_SIM -typedef unsigned char uint8_t; -//#endif -typedef unsigned int uint32_t; -//typedef int int32_t; -//typedef long long int64_t; #ifdef AML #define AOM_AV1_MMU @@ -108,9 +101,12 @@ } BuffInfo_t; #endif +#if 0 #define va_start(v,l) __builtin_va_start(v,l) #define va_end(v) __builtin_va_end(v) #define va_arg(v,l) __builtin_va_arg(v,l) +#endif + /* mem.h */ @@ -1322,8 +1318,9 @@ int min_mv; int avg_mv; #endif - bool vframe_bound; - u64 timestamp; + u64 timestamp; + u32 hw_decode_time; + u32 frame_size2; // For frame base mode } PIC_BUFFER_CONFIG; /* @@ -1564,6 +1561,7 @@ FRAME_CONTEXT frame_context; #endif + int show_frame; } RefCntBuffer; typedef struct BufferPool_s { @@ -2227,7 +2225,9 @@ unsigned short seg_lf_info_c[8]; unsigned short video_signal_type; unsigned short color_description; - + unsigned short mmu_used_num; + unsigned short dw_mmu_used_num; + unsigned short seq_flags_2; /*ucode end*/ /*other*/ unsigned short enable_superres; @@ -2317,6 +2317,7 @@ #define AV1_DEBUG_DUMP_DATA 0x800000 #define AV1_DEBUG_CACHE 0x1000000 #define AV1_DEBUG_CACHE_HIT_RATE 0x2000000 +#define AV1_DEBUG_SEI_DETAIL 0x4000000 #define IGNORE_PARAM_FROM_CONFIG 0x8000000 #if 1 /*def MULTI_INSTANCE_SUPPORT*/
diff --git a/drivers/frame_provider/decoder/vav1/vav1.c b/drivers/frame_provider/decoder/vav1/vav1.c index 8379316..c67757a 100644 --- a/drivers/frame_provider/decoder/vav1/vav1.c +++ b/drivers/frame_provider/decoder/vav1/vav1.c
@@ -25,6 +25,7 @@ #include <linux/timer.h> #include <linux/kfifo.h> #include <linux/kthread.h> +#include <linux/sched/clock.h> #include <linux/spinlock.h> #include <linux/platform_device.h> #include <linux/amlogic/media/vfm/vframe.h> @@ -73,6 +74,7 @@ #include <media/v4l2-mem2mem.h> #endif #include "../../../amvdec_ports/utils/common.h" +#include "../utils/vdec_feature.h" #define AML #include "aom_av1_define.h" @@ -88,6 +90,8 @@ #define USE_DEC_PIC_END +#define SANITY_CHECK +#define CO_MV_COMPRESS #include "vav1.h" @@ -168,6 +172,7 @@ #define AOM_AV1_DUMP_LMEM 7 #define AOM_AV1_FGS_PARAM_CONT 8 #define AOM_AV1_DISCARD_NAL 0x10 +#define AOM_AV1_RESULT_NEED_MORE_BUFFER 0x11 /*status*/ #define AOM_AV1_DEC_PIC_END 0xe0 @@ -192,7 +197,6 @@ #define AOM_EOS 0x24 #define AOM_NAL_DECODE_DONE 0x25 - #define VF_POOL_SIZE 32 #undef pr_info @@ -265,8 +269,8 @@ #ifdef AOM_AV1_MMU_DW static unsigned int dw_mmu_enable[MAX_DECODE_INSTANCE_NUM]; #endif -/* disable timeout for av1 mosaic JIRA SWPL-23326 */ -static u32 decode_timeout_val = 0; + +static u32 decode_timeout_val = 600; static int start_decode_buf_level = 0x8000; //static u32 work_buf_size; static u32 force_pts_unstable; @@ -281,9 +285,10 @@ * 2, (1/4):(1/4) ratio; * 3, (1/4):(1/4) ratio, with both compressed frame included * 4, (1/2):(1/2) ratio; - * 5, (1/2):(1/2) ratio, with both compressed frame included + * 5, (1/2):(1/2) ratio, with both compressed frame included + * 8, (1/8):(1/8) ratio; * 0x10, double write only - * 0x20, mmu double write + * 0x20, mmu double write * 0x100, if > 1080p,use mode 4,else use mode 1; * 0x200, if > 1080p,use mode 2,else use mode 1; * 0x300, if > 720p, use mode 4, else use mode 1; @@ -309,7 +314,7 @@ #define DUR2PTS(x) ((x)*90/96) #define PTS2DUR(x) ((x)*96/90) - +#define PTS2DUR_u64(x) (div_u64((x)*96, 90)) struct AV1HW_s; static int vav1_vf_states(struct vframe_states *states, void *); @@ -326,7 +331,7 @@ #endif static void vav1_prot_init(struct AV1HW_s *hw, u32 mask); static int vav1_local_init(struct AV1HW_s *hw); -static void vav1_put_timer_func(unsigned long arg); +static void vav1_put_timer_func(struct timer_list *timer); static void dump_data(struct AV1HW_s *hw, int size); static unsigned int get_data_check_sum (struct AV1HW_s *hw, int size); @@ -371,6 +376,8 @@ static u32 video_signal_type; static u32 on_no_keyframe_skiped; static u32 without_display_mode; +static u32 v4l_bitstream_id_enable = 1; + #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION static u32 force_dv_enable; #endif @@ -432,10 +439,6 @@ #define LOSLESS_COMPRESS_MODE #endif -typedef unsigned int u32; -typedef unsigned short u16; - - static u32 get_picture_qos; static u32 debug; @@ -534,6 +537,7 @@ //#define MMU_COMPRESS_8K_HEADER_SIZE (0x48000*4) #define MAX_SIZE_8K (8192 * 4608) #define MAX_SIZE_4K (4096 * 2304) +#define MAX_SIZE_2K (1920 * 1088) #define IS_8K_SIZE(w, h) (((w) * (h)) > MAX_SIZE_4K) #define IS_4K_SIZE(w, h) (((w) * (h)) > (1920*1088)) @@ -595,7 +599,7 @@ static int compute_losless_comp_body_size(int width, int height, uint8_t is_bit_depth_10); - +void clear_frame_buf_ref_count(AV1Decoder *pbi); #ifdef MULTI_INSTANCE_SUPPORT #define DEC_RESULT_NONE 0 @@ -752,23 +756,10 @@ u32 video_signal_type; u32 pts_unstable; - bool av1_first_pts_ready; - bool dur_recalc_flag; - u8 first_pts_index; - u32 frame_mode_pts_save[FRAME_BUFFERS]; - u64 frame_mode_pts64_save[FRAME_BUFFERS]; - u64 frame_mode_timestamp_save[FRAME_BUFFERS]; - u64 timestamp_duration; + u32 last_chunk_pts; + u32 pts_diff_count; + u64 pts_diff_sum; - int last_pts; - u64 last_pts_us64; - u64 last_timestamp; - u64 shift_byte_count; - - u32 shift_byte_count_lo; - u32 shift_byte_count_hi; - int pts_mode_switching_count; - int pts_mode_recovery_count; bool get_frame_dur; u32 saved_resolution; @@ -861,17 +852,23 @@ int buffer_wrap[FRAME_BUFFERS]; int sidebind_type; int sidebind_channel_id; - char vdec_name[32]; - char pts_name[32]; - char new_q_name[32]; - char disp_q_name[32]; + u32 cur_obu_type; + u32 multi_frame_cnt; + u32 endian; + u32 run_ready_min_buf_num; + int one_package_frame_cnt; + ulong fb_token; + dma_addr_t rdma_phy_adr; + unsigned *rdma_adr; + struct trace_decoder_name trace; }; + static void av1_dump_state(struct vdec_s *vdec); int av1_print(struct AV1HW_s *hw, int flag, const char *fmt, ...) { -#define HEVC_PRINT_BUF 256 +#define HEVC_PRINT_BUF 512 unsigned char buf[HEVC_PRINT_BUF]; int len = 0; @@ -921,6 +918,9 @@ int max = (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1)? MAX_SIZE_8K : MAX_SIZE_4K; + if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5D) + max = MAX_SIZE_2K; + if (w <= 0 || h <= 0) return true; @@ -1015,48 +1015,16 @@ u32 dw = ((double_write_mode & 0x80000000) == 0) ? hw->double_write_mode : (double_write_mode & 0x7fffffff); - if ((dw & 0x20) && - ((dw & 0xf) == 2 || (dw & 0xf) == 3)) { - pr_info("MMU doueble write 1:4 not supported !!!\n"); - dw = 0; + if (dw & 0x20) { + if ((get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_T3) + && ((dw & 0xf) == 2 || (dw & 0xf) == 3)) { + pr_info("MMU doueble write 1:4 not supported !!!\n"); + dw = 0; + } } return dw; } -static int v4l_parser_get_double_write_mode(struct AV1HW_s *hw) -{ - u32 valid_dw_mode = get_valid_double_write_mode(hw); - u32 dw; - int w, h; - - /* mask for supporting double write value bigger than 0x100 */ - if (valid_dw_mode & 0xffffff00) { - w = hw->frame_width; - h = hw->frame_height; - - dw = 0x1; /*1:1*/ - switch (valid_dw_mode) { - case 0x100: - if (w > 1920 && h > 1088) - dw = 0x4; /*1:2*/ - break; - case 0x200: - if (w > 1920 && h > 1088) - dw = 0x2; /*1:4*/ - break; - case 0x300: - if (w > 1280 && h > 720) - dw = 0x4; /*1:2*/ - break; - default: - break; - } - return dw; - } - - return valid_dw_mode; -} - static int get_double_write_mode(struct AV1HW_s *hw) { u32 valid_dw_mode = get_valid_double_write_mode(hw); @@ -1067,6 +1035,15 @@ if (!cm->cur_frame) return 1;/*no valid frame,*/ + + if (hw->is_used_v4l) { + unsigned int out; + + vdec_v4l_get_dw_mode(hw->v4l2_ctx, &out); + dw = out; + return dw; + } + cur_pic_config = &cm->cur_frame->buf; w = cur_pic_config->y_crop_width; h = cur_pic_config->y_crop_height; @@ -1122,19 +1099,6 @@ } #endif -static int get_double_write_ratio(struct AV1HW_s *hw, - int dw_mode) -{ - int ratio = 1; - int dw_mode_ratio = dw_mode & 0xf; - if ((dw_mode_ratio == 2) || - (dw_mode_ratio == 3)) - ratio = 4; - else if (dw_mode_ratio == 4) - ratio = 2; - return ratio; -} - /* return page number */ static int av1_mmu_page_num(struct AV1HW_s *hw, int w, int h, int save_mode) @@ -1159,6 +1123,32 @@ return cur_mmu_4k_number; } +static struct internal_comp_buf* v4lfb_to_icomp_buf( + struct AV1HW_s *hw, + struct vdec_v4l2_buffer *fb) +{ + struct aml_video_dec_buf *aml_fb = NULL; + struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx; + + aml_fb = container_of(fb, struct aml_video_dec_buf, frame_buffer); + + return &v4l2_ctx->comp_bufs[aml_fb->internal_index]; +} + +static struct internal_comp_buf* index_to_icomp_buf( + struct AV1HW_s *hw, int index) +{ + struct aml_video_dec_buf *aml_fb = NULL; + struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx; + struct vdec_v4l2_buffer *fb = NULL; + + fb = (struct vdec_v4l2_buffer *) + hw->m_BUF[index].v4l_ref_buf_addr; + aml_fb = container_of(fb, struct aml_video_dec_buf, frame_buffer); + + return &v4l2_ctx->comp_bufs[aml_fb->internal_index]; +} + //#define MAX_4K_NUM 0x1200 int av1_alloc_mmu( struct AV1HW_s *hw, @@ -1172,11 +1162,6 @@ int bit_depth_10 = (bit_depth == AOM_BITS_10); int cur_mmu_4k_number; - if (!hw->mmu_box) { - pr_err("error no mmu box!\n"); - return -1; - } - if (hw->double_write_mode & 0x10) return 0; @@ -1193,11 +1178,22 @@ if (cur_mmu_4k_number < 0) return -1; - ret = decoder_mmu_box_alloc_idx( - hw->mmu_box, - hw->buffer_wrap[cur_buf_idx], - cur_mmu_4k_number, - mmu_index_adr); + if (hw->is_used_v4l) { + struct internal_comp_buf *ibuf = + index_to_icomp_buf(hw, cur_buf_idx); + + ret = decoder_mmu_box_alloc_idx( + ibuf->mmu_box, + ibuf->index, + ibuf->frame_buffer_size, + mmu_index_adr); + } else { + ret = decoder_mmu_box_alloc_idx( + hw->mmu_box, + cur_buf_idx, + cur_mmu_4k_number, + mmu_index_adr); + } return ret; } @@ -1245,7 +1241,7 @@ } ret = decoder_mmu_box_alloc_idx( hw->mmu_box_dw, - hw->buffer_wrap[cur_buf_idx], + cur_buf_idx, cur_mmu_4k_number, mmu_index_adr); return ret; @@ -1278,6 +1274,13 @@ int i, int size) { int ret = 0; + + if (hw->m_mv_BUF[i].start_adr && + size > hw->m_mv_BUF[i].size) { + dealloc_mv_bufs(hw); + } else if (hw->m_mv_BUF[i].start_adr) + return 0; + if (decoder_bmmu_box_alloc_buf_phy (hw->bmmu_box, MV_BUFFER_IDX(i), size, @@ -1353,10 +1356,7 @@ __func__, size); if ((hw->is_used_v4l) && !IS_8K_SIZE(pic_width, pic_height)) { - if (vdec_is_support_4k()) - size = 0xb0000; - else - size = 0x30000; + size = 0x100000; } if (hw->init_pic_w > 4096 && hw->init_pic_h > 2048) @@ -1502,6 +1502,26 @@ static void init_pic_list_hw(struct AV1HW_s *pbi); +static void update_hide_frame_timestamp(struct AV1HW_s *hw) +{ + RefCntBuffer *const frame_bufs = hw->common.buffer_pool->frame_bufs; + int i; + + for (i = 0; i < hw->used_buf_num; ++i) { + if ((!frame_bufs[i].show_frame) && + (frame_bufs[i].showable_frame) && + (!frame_bufs[i].buf.vf_ref) && + (frame_bufs[i].buf.BUF_index != -1)) { + frame_bufs[i].buf.timestamp = hw->chunk->timestamp; + frame_bufs[i].buf.pts = hw->chunk->pts; + frame_bufs[i].buf.pts64 = hw->chunk->pts64; + av1_print(hw, AV1_DEBUG_OUT_PTS, + "%s, update %d hide frame ts: %lld, pts %d, pts64 %lld\n", + __func__, i, frame_bufs[i].buf.timestamp, hw->chunk->pts, hw->chunk->pts64); + } + } +} + static int get_free_fb_idx(AV1_COMMON *cm) { int i; @@ -1513,7 +1533,7 @@ break; } - return i; + return (i != FRAME_BUFFERS) ? i : -1; } static int v4l_get_free_fb(struct AV1HW_s *hw) @@ -1545,6 +1565,9 @@ break; case V4L_CAP_BUFF_IN_M2M: idx = get_free_fb_idx(cm); + if (idx < 0) + break; + pic = &frame_bufs[idx].buf; pic->y_crop_width = hw->frame_width; pic->y_crop_height = hw->frame_height; @@ -1578,8 +1601,30 @@ } } + if (free_pic && hw->chunk) { + free_pic->timestamp = hw->chunk->timestamp; + update_hide_frame_timestamp(hw); + } + unlock_buffer_pool(cm->buffer_pool, flags); + if (free_pic) { + struct vdec_v4l2_buffer *fb = + (struct vdec_v4l2_buffer *) + hw->m_BUF[free_pic->index].v4l_ref_buf_addr; + + fb->status = FB_ST_DECODER; + } + + if (debug & AV1_DEBUG_OUT_PTS) { + if (free_pic) { + pr_debug("%s, idx: %d, ts: %lld\n", + __func__, free_pic->index, free_pic->timestamp); + } else { + pr_debug("%s, av1 get free pic null\n", __func__); + } + } + return free_pic ? free_pic->index : INVALID_IDX; } @@ -1619,7 +1664,25 @@ i = INVALID_IDX; } + if (i != INVALID_IDX) { + struct PIC_BUFFER_CONFIG_s *pic = &frame_bufs[i].buf; + struct AV1HW_s *hw = container_of(cm, struct AV1HW_s, common); + + if (pic && hw->chunk) { + pic->timestamp = hw->chunk->timestamp; + pic->pts = hw->chunk->pts; + pic->pts64 = hw->chunk->pts64; + update_hide_frame_timestamp(hw); + } + + if (pic) + av1_print(hw, AV1_DEBUG_OUT_PTS, + "%s, idx: %d, ts: %lld, pts %d, pts64 %lld\n", + __func__, i, pic->timestamp, pic->pts, pic->pts64); + } + unlock_buffer_pool(cm->buffer_pool, flags); + return i; } @@ -1634,14 +1697,42 @@ { struct AV1_Common_s *const cm = &hw->common; struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs; - int i; - int free_buf_count = 0; - for (i = 0; i < hw->used_buf_num; ++i) - if ((frame_bufs[i].ref_count == 0) && - (frame_bufs[i].buf.vf_ref == 0) && - (frame_bufs[i].buf.index != -1) - ) - free_buf_count++; + struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + int i, free_buf_count = 0; + + if (hw->is_used_v4l) { + for (i = 0; i < hw->used_buf_num; ++i) { + if ((frame_bufs[i].ref_count == 0) && + (frame_bufs[i].buf.vf_ref == 0) && + frame_bufs[i].buf.cma_alloc_addr) { + free_buf_count++; + } + } + + if (ctx->cap_pool.dec < hw->used_buf_num) { + free_buf_count += + v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx); + } + /* trigger to parse head data. */ + if (!hw->v4l_params_parsed) { + free_buf_count = hw->run_ready_min_buf_num; + } + if ((debug & AV1_DEBUG_BUFMGR_MORE) && + (free_buf_count <= 0)) { + pr_info("%s, free count %d, m2m_ready %d\n", + __func__, + free_buf_count, + v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx)); + } + } else { + for (i = 0; i < hw->used_buf_num; ++i) + if ((frame_bufs[i].ref_count == 0) && + (frame_bufs[i].buf.vf_ref == 0) && + (frame_bufs[i].buf.index != -1)) { + free_buf_count++; + } + } + return free_buf_count; } @@ -1687,18 +1778,13 @@ hw->wait_buf = 0; hw->error_flag = 0; - hw->last_pts = 0; - hw->last_pts_us64 = 0; - hw->last_timestamp = 0; - hw->shift_byte_count = 0; - hw->shift_byte_count_lo = 0; - hw->shift_byte_count_hi = 0; - hw->pts_mode_switching_count = 0; - hw->pts_mode_recovery_count = 0; - hw->buf_num = 0; hw->pic_num = 0; + hw->last_chunk_pts = 0; + hw->pts_diff_count = 0; + hw->pts_diff_sum = 0; + return 0; } @@ -1740,7 +1826,14 @@ static u32 pop_shorts; static u32 dbg_cmd; static u32 dbg_skip_decode_index; -static u32 endian = 0xff0; +/* + * bit 0~3, for HEVCD_IPP_AXIIF_CONFIG endian config + * bit 8~23, for HEVC_SAO_CTRL1 endian config + */ +static u32 endian; +#define HEVC_CONFIG_BIG_ENDIAN ((0x880 << 8) | 0x8) +#define HEVC_CONFIG_LITTLE_ENDIAN ((0xff0 << 8) | 0xf) + static u32 multi_frames_in_one_pack = 1; #ifdef ERROR_HANDLE_DEBUG static u32 dbg_nal_skip_flag; @@ -1932,9 +2025,12 @@ #define DW_VBH_BUF_SIZE_8K (VBH_BUF_SIZE_8K * 2) #define DW_VBH_BUF_SIZE(bufspec) (bufspec->mmu_vbh_dw.buf_size / 4) +/* necessary 4K page size align for t7/t3 decoder and after. fix case1440 dec timeout */ +#define WORKBUF_ALIGN(addr) (ALIGN(addr, PAGE_SIZE)) + #define WORK_BUF_SPEC_NUM 3 -static struct BuffInfo_s aom_workbuff_spec[WORK_BUF_SPEC_NUM] = { +static struct BuffInfo_s aom_workbuff_spec[WORK_BUF_SPEC_NUM] = { { //8M bytes .max_width = 1920, .max_height = 1088, @@ -2617,82 +2713,73 @@ { void *mem_start_virt; - buf_spec->ipp.buf_start = - buf_spec->start_adr; - buf_spec->sao_abv.buf_start = - buf_spec->ipp.buf_start + buf_spec->ipp.buf_size; - - buf_spec->sao_vb.buf_start = - buf_spec->sao_abv.buf_start + buf_spec->sao_abv.buf_size; - buf_spec->short_term_rps.buf_start = - buf_spec->sao_vb.buf_start + buf_spec->sao_vb.buf_size; - buf_spec->vps.buf_start = - buf_spec->short_term_rps.buf_start + buf_spec->short_term_rps.buf_size; - buf_spec->seg_map.buf_start = - buf_spec->vps.buf_start + buf_spec->vps.buf_size; - buf_spec->daala_top.buf_start = - buf_spec->seg_map.buf_start + buf_spec->seg_map.buf_size; - buf_spec->sao_up.buf_start = - buf_spec->daala_top.buf_start + buf_spec->daala_top.buf_size; - buf_spec->swap_buf.buf_start = - buf_spec->sao_up.buf_start + buf_spec->sao_up.buf_size; - buf_spec->cdf_buf.buf_start = - buf_spec->swap_buf.buf_start + buf_spec->swap_buf.buf_size; - buf_spec->gmc_buf.buf_start = - buf_spec->cdf_buf.buf_start + buf_spec->cdf_buf.buf_size; - buf_spec->scalelut.buf_start = - buf_spec->gmc_buf.buf_start + buf_spec->gmc_buf.buf_size; - buf_spec->dblk_para.buf_start = - buf_spec->scalelut.buf_start + buf_spec->scalelut.buf_size; - buf_spec->dblk_data.buf_start = - buf_spec->dblk_para.buf_start + buf_spec->dblk_para.buf_size; - buf_spec->cdef_data.buf_start = - buf_spec->dblk_data.buf_start + buf_spec->dblk_data.buf_size; - buf_spec->ups_data.buf_start = - buf_spec->cdef_data.buf_start + buf_spec->cdef_data.buf_size; - buf_spec->fgs_table.buf_start = - buf_spec->ups_data.buf_start + buf_spec->ups_data.buf_size; + buf_spec->ipp.buf_start = + WORKBUF_ALIGN(buf_spec->start_adr); + buf_spec->sao_abv.buf_start = + WORKBUF_ALIGN(buf_spec->ipp.buf_start + buf_spec->ipp.buf_size); + buf_spec->sao_vb.buf_start = + WORKBUF_ALIGN(buf_spec->sao_abv.buf_start + buf_spec->sao_abv.buf_size); + buf_spec->short_term_rps.buf_start = + WORKBUF_ALIGN(buf_spec->sao_vb.buf_start + buf_spec->sao_vb.buf_size); + buf_spec->vps.buf_start = + WORKBUF_ALIGN(buf_spec->short_term_rps.buf_start + buf_spec->short_term_rps.buf_size); + buf_spec->seg_map.buf_start = + WORKBUF_ALIGN(buf_spec->vps.buf_start + buf_spec->vps.buf_size); + buf_spec->daala_top.buf_start = + WORKBUF_ALIGN(buf_spec->seg_map.buf_start + buf_spec->seg_map.buf_size); + buf_spec->sao_up.buf_start = + WORKBUF_ALIGN(buf_spec->daala_top.buf_start + buf_spec->daala_top.buf_size); + buf_spec->swap_buf.buf_start = + WORKBUF_ALIGN(buf_spec->sao_up.buf_start + buf_spec->sao_up.buf_size); + buf_spec->cdf_buf.buf_start = + WORKBUF_ALIGN(buf_spec->swap_buf.buf_start + buf_spec->swap_buf.buf_size); + buf_spec->gmc_buf.buf_start = + WORKBUF_ALIGN(buf_spec->cdf_buf.buf_start + buf_spec->cdf_buf.buf_size); + buf_spec->scalelut.buf_start = + WORKBUF_ALIGN(buf_spec->gmc_buf.buf_start + buf_spec->gmc_buf.buf_size); + buf_spec->dblk_para.buf_start = + WORKBUF_ALIGN(buf_spec->scalelut.buf_start + buf_spec->scalelut.buf_size); + buf_spec->dblk_data.buf_start = + WORKBUF_ALIGN(buf_spec->dblk_para.buf_start + buf_spec->dblk_para.buf_size); + buf_spec->cdef_data.buf_start = + WORKBUF_ALIGN(buf_spec->dblk_data.buf_start + buf_spec->dblk_data.buf_size); + buf_spec->ups_data.buf_start = + WORKBUF_ALIGN(buf_spec->cdef_data.buf_start + buf_spec->cdef_data.buf_size); + buf_spec->fgs_table.buf_start = + WORKBUF_ALIGN(buf_spec->ups_data.buf_start + buf_spec->ups_data.buf_size); #ifdef AOM_AV1_MMU - buf_spec->mmu_vbh.buf_start = - buf_spec->fgs_table.buf_start + buf_spec->fgs_table.buf_size; - buf_spec->cm_header.buf_start = - buf_spec->mmu_vbh.buf_start + buf_spec->mmu_vbh.buf_size; + buf_spec->mmu_vbh.buf_start = + WORKBUF_ALIGN(buf_spec->fgs_table.buf_start + buf_spec->fgs_table.buf_size); + buf_spec->cm_header.buf_start = + WORKBUF_ALIGN(buf_spec->mmu_vbh.buf_start + buf_spec->mmu_vbh.buf_size); #ifdef AOM_AV1_MMU_DW - buf_spec->mmu_vbh_dw.buf_start = - buf_spec->cm_header.buf_start + buf_spec->cm_header.buf_size; - buf_spec->cm_header_dw.buf_start = - buf_spec->mmu_vbh_dw.buf_start + buf_spec->mmu_vbh_dw.buf_size; - buf_spec->mpred_above.buf_start = - buf_spec->cm_header_dw.buf_start + buf_spec->cm_header_dw.buf_size; + buf_spec->mmu_vbh_dw.buf_start = + WORKBUF_ALIGN(buf_spec->cm_header.buf_start + buf_spec->cm_header.buf_size); + buf_spec->cm_header_dw.buf_start = + WORKBUF_ALIGN(buf_spec->mmu_vbh_dw.buf_start + buf_spec->mmu_vbh_dw.buf_size); + buf_spec->mpred_above.buf_start = + WORKBUF_ALIGN(buf_spec->cm_header_dw.buf_start + buf_spec->cm_header_dw.buf_size); #else - buf_spec->mpred_above.buf_start = - buf_spec->cm_header.buf_start + buf_spec->cm_header.buf_size; + buf_spec->mpred_above.buf_start = + WORKBUF_ALIGN(buf_spec->cm_header.buf_start + buf_spec->cm_header.buf_size); #endif #else - buf_spec->mpred_above.buf_start = - buf_spec->fgs_table.buf_start + buf_spec->fgs_table.buf_size; + buf_spec->mpred_above.buf_start = + WORKBUF_ALIGN(buf_spec->fgs_table.buf_start + buf_spec->fgs_table.buf_size); #endif - #ifdef MV_USE_FIXED_BUF buf_spec->mpred_mv.buf_start = - buf_spec->mpred_above.buf_start + - buf_spec->mpred_above.buf_size; - + WORKBUF_ALIGN(buf_spec->mpred_above.buf_start + buf_spec->mpred_above.buf_size); buf_spec->rpm.buf_start = - buf_spec->mpred_mv.buf_start + - buf_spec->mpred_mv.buf_size; + WORKBUF_ALIGN(buf_spec->mpred_mv.buf_start + buf_spec->mpred_mv.buf_size); #else buf_spec->rpm.buf_start = - buf_spec->mpred_above.buf_start + - buf_spec->mpred_above.buf_size; - + WORKBUF_ALIGN(buf_spec->mpred_above.buf_start + buf_spec->mpred_above.buf_size); #endif buf_spec->lmem.buf_start = - buf_spec->rpm.buf_start + - buf_spec->rpm.buf_size; + WORKBUF_ALIGN(buf_spec->rpm.buf_start + buf_spec->rpm.buf_size); buf_spec->end_adr = - buf_spec->lmem.buf_start + - buf_spec->lmem.buf_size; + WORKBUF_ALIGN(buf_spec->lmem.buf_start + buf_spec->lmem.buf_size); if (!hw) return; @@ -2780,64 +2867,13 @@ } } -static bool v4l_is_there_vframe_bound(struct AV1HW_s *hw) -{ - int i; - struct AV1_Common_s *const cm = &hw->common; - struct RefCntBuffer_s *frame_bufs = cm->buffer_pool->frame_bufs; - for (i = 0; i < hw->used_buf_num; ++i) { - if (frame_bufs[i].buf.vframe_bound) - return true; - } - - return false; -} - -static void v4l_mmu_buffer_release(struct AV1HW_s *hw) -{ - struct AV1_Common_s *const cm = &hw->common; - struct RefCntBuffer_s *frame_bufs = cm->buffer_pool->frame_bufs; - int i; - - /* release workspace */ - if (hw->bmmu_box) - decoder_bmmu_box_free_idx(hw->bmmu_box, - WORK_SPACE_BUF_ID); - /* - * it's only when vframe get back to driver, right now we can be sure - * that vframe and fd are related. if the playback exits, the capture - * requires the upper app to release when the fd is closed, and others - * buffers drivers are released by driver. - */ - for (i = 0; i < hw->used_buf_num; ++i) { - if (!frame_bufs[i].buf.vframe_bound) { - if (hw->bmmu_box) - decoder_bmmu_box_free_idx(hw->bmmu_box, - HEADER_BUFFER_IDX(hw->buffer_wrap[i])); - if (hw->mmu_box) - decoder_mmu_box_free_idx(hw->mmu_box, hw->buffer_wrap[i]); - - av1_print(hw, PRINT_FLAG_V4L_DETAIL, - "%s free buffer[%d], bmmu_box: %p, mmu_box: %p\n", - __func__, i, hw->bmmu_box, hw->mmu_box); - } - } -} static void uninit_mmu_buffers(struct AV1HW_s *hw) { #ifndef MV_USE_FIXED_BUF dealloc_mv_bufs(hw); #endif - if (hw->is_used_v4l && - v4l_is_there_vframe_bound(hw)) { - if (get_double_write_mode(hw) != 0x10) { - v4l_mmu_buffer_release(hw); - return; - } - } - if (hw->mmu_box) decoder_mmu_box_free(hw->mmu_box); hw->mmu_box = NULL; @@ -2864,6 +2900,33 @@ return pic_width_lcu * pic_height_lcu; } +/* return in MB */ +static int av1_max_mmu_buf_size(int max_w, int max_h) +{ + int buf_size = 48; + + if ((max_w * max_h > 1280*736) && + (max_w * max_h <= 1920*1088)) { + buf_size = 12; + } else if ((max_w * max_h > 0) && + (max_w * max_h <= 1280*736)) { + buf_size = 4; + } + + return buf_size; +} + +static int av1_get_header_size(int w, int h) +{ + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && + IS_8K_SIZE(w, h)) + return MMU_COMPRESS_HEADER_SIZE_8K; + if (IS_4K_SIZE(w, h)) + return MMU_COMPRESS_HEADER_SIZE_4K; + + return MMU_COMPRESS_HEADER_SIZE_1080P; +} + static int v4l_alloc_and_config_pic(struct AV1HW_s *hw, struct PIC_BUFFER_CONFIG_s *pic) { @@ -2882,21 +2945,24 @@ int32_t mv_buffer_size = hw->max_one_mv_buffer_size; //#endif #endif + struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)hw->v4l2_ctx; struct vdec_v4l2_buffer *fb = NULL; if (i < 0) return ret; - ret = vdec_v4l_get_buffer(hw->v4l2_ctx, &fb); + ret = ctx->fb_ops.alloc(&ctx->fb_ops, hw->fb_token, &fb, AML_FB_REQ_DEC); if (ret < 0) { - av1_print(hw, 0, "[%d] AV1 get buffer fail.\n", - ((struct aml_vcodec_ctx *) (hw->v4l2_ctx))->id); + av1_print(hw, 0, "[%d] AV1 get buffer fail.\n", ctx->id); return ret; } + fb->status = FB_ST_DECODER; + if (hw->mmu_enable) { - hw->m_BUF[i].header_addr = decoder_bmmu_box_get_phy_addr( - hw->bmmu_box, HEADER_BUFFER_IDX(hw->buffer_wrap[i])); + struct internal_comp_buf *ibuf = v4lfb_to_icomp_buf(hw, fb); + + hw->m_BUF[i].header_addr = ibuf->header_addr; if (debug & AV1_DEBUG_BUFMGR_MORE) { pr_info("MMU header_adr %d: %ld\n", i, hw->m_BUF[i].header_addr); @@ -3028,9 +3094,9 @@ if (dw_mode && (dw_mode & 0x20) == 0) { int pic_width_dw = pic_width / - get_double_write_ratio(hw, dw_mode); + get_double_write_ratio(dw_mode & 0xf); int pic_height_dw = pic_height / - get_double_write_ratio(hw, dw_mode); + get_double_write_ratio(dw_mode & 0xf); int pic_width_64_dw = (pic_width_dw + 63) & (~0x3f); int pic_height_32_dw = (pic_height_dw + 31) & (~0x1f); @@ -3073,26 +3139,26 @@ /*!USE_SPEC_BUF_FOR_MMU_HEAD*/ if (hw->mmu_enable) { pic_config->header_adr = decoder_bmmu_box_get_phy_addr( - hw->bmmu_box, HEADER_BUFFER_IDX(hw->buffer_wrap[pic_config->index])); + hw->bmmu_box, HEADER_BUFFER_IDX(pic_config->index)); #ifdef AOM_AV1_MMU_DW if (hw->dw_mmu_enable) { pic_config->header_dw_adr = decoder_bmmu_box_get_phy_addr( - hw->bmmu_box, DW_HEADER_BUFFER_IDX(hw->buffer_wrap[pic_config->index])); + hw->bmmu_box, DW_HEADER_BUFFER_IDX(pic_config->index)); } if (debug & AV1_DEBUG_BUFMGR_MORE) { pr_info("MMU dw header_adr (%d, %d) %d: %d\n", hw->dw_mmu_enable, - DW_HEADER_BUFFER_IDX(hw->buffer_wrap[pic_config->index]), - hw->buffer_wrap[pic_config->index], + DW_HEADER_BUFFER_IDX(pic_config->index), + pic_config->index, pic_config->header_dw_adr); } #endif if (debug & AV1_DEBUG_BUFMGR_MORE) { pr_info("MMU header_adr %d: %d\n", - hw->buffer_wrap[pic_config->index], pic_config->header_adr); + pic_config->index, pic_config->header_adr); } } #endif @@ -3106,13 +3172,13 @@ #endif if (buf_size > 0) { ret = decoder_bmmu_box_alloc_buf_phy(hw->bmmu_box, - VF_BUFFER_IDX(hw->buffer_wrap[i]), + VF_BUFFER_IDX(i), buf_size, DRIVER_NAME, &pic_config->cma_alloc_addr); if (ret < 0) { pr_info( "decoder_bmmu_box_alloc_buf_phy idx %d size %d fail\n", - VF_BUFFER_IDX(hw->buffer_wrap[i]), + VF_BUFFER_IDX(i), buf_size ); return ret; @@ -3123,7 +3189,7 @@ else { pr_info( "decoder_bmmu_box_alloc_buf_phy idx %d size %d return null\n", - VF_BUFFER_IDX(hw->buffer_wrap[i]), + VF_BUFFER_IDX(i), buf_size ); return -1; @@ -3556,8 +3622,10 @@ seg_map_size = ((frame_width + 127) >> 7) * ((frame_height + 127) >> 7) * 384 ; */ - WRITE_VREG(HEVC_PARSER_PICTURE_SIZE, - (frame_height << 16) | frame_width); + if (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T3) { + WRITE_VREG(HEVC_PARSER_PICTURE_SIZE, + (frame_height << 16) | frame_width); + } #ifdef DUAL_DECODE #else WRITE_VREG(HEVC_ASSIST_PIC_SIZE_FB_READ, @@ -3830,7 +3898,15 @@ cur_pic_config->index, last_frame_pic_config->index);*/ //WRITE_VREG(HEVC_MPRED_CTRL3,0x24122412); - WRITE_VREG(HEVC_MPRED_CTRL3, 0x13151315); // 'd19, 'd21 for AV1 +#ifdef CO_MV_COMPRESS + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T5D) { + WRITE_VREG(HEVC_MPRED_CTRL3,0x10151015); // 'd10, 'd21 for AV1 + } else { + WRITE_VREG(HEVC_MPRED_CTRL3,0x13151315); // 'd19, 'd21 for AV1 + } +#else + WRITE_VREG(HEVC_MPRED_CTRL3,0x13151315); // 'd19, 'd21 for AV1 +#endif WRITE_VREG(HEVC_MPRED_ABV_START_ADDR, hw->pbi->work_space_buf->mpred_above.buf_start); @@ -3856,11 +3932,19 @@ "WRITE_VREG(HEVC_MPRED_CTRL4, 0x%x)\n", data32); } #if 1 - data32 = ( - (cm->seq_params.order_hint_info.enable_order_hint << 27) | + data32 = ((cm->seq_params.order_hint_info.enable_order_hint << 27) | (cm->seq_params.order_hint_info.order_hint_bits_minus_1 << 24) | - (cm->cur_frame->order_hint <<16 ) | - (0x13 << 8) | (0x13 << 0)); + (cm->cur_frame->order_hint << 16 )); +#ifdef CO_MV_COMPRESS + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T5D) { + data32 |= (0x10 << 8) | (0x10 << 0); + } else { + data32 |= (0x13 << 8) | (0x13 << 0); + } +#else + data32 |= (0x13 << 8) | (0x13 << 0); +#endif + #else data32 = READ_VREG(HEVC_MPRED_L0_REF00_POC); data32 &= (~(0xff << 16)); @@ -3989,7 +4073,7 @@ WRITE_VREG(HEVC_MPRED_MV_WPTR, cur_pic_config->mpred_mv_wr_start_addr); - if ((inter_flag) && (mv_cal_tpl_count <= 3)) { + if (inter_flag) { for (i = 0; i < mv_cal_tpl_count; i++) { PIC_BUFFER_CONFIG *pic_config = av1_get_ref_frame_spec_buf(cm, mv_ref_id[i]); @@ -4010,6 +4094,9 @@ pic_config->mpred_mv_wr_start_addr); WRITE_VREG(HEVC_MPRED_MV_RPTR_2, pic_config->mpred_mv_wr_start_addr); + } else { + av1_print(hw, AOM_DEBUG_HW_MORE, + "%s: mv_ref_id error\n", __func__); } } } @@ -4049,7 +4136,7 @@ !!!!!!!!!!!!!!!!!!!!!!!!!TODO .... !!!!!!!!!!! mem_map_mode, endian, get_double_write_mode */ - AV1_COMMON *cm = &hw->common; + AV1_COMMON *cm = &hw->common; PIC_BUFFER_CONFIG* pic_config = &cm->cur_frame->buf; uint32_t data32; int32_t lcu_size = @@ -4156,7 +4243,7 @@ #ifdef DOS_PROJECT data32 = READ_VREG(HEVC_SAO_CTRL1); data32 &= (~0x3000); - data32 |= (MEM_MAP_MODE << 12); // [13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32 + data32 |= (hw->mem_map_mode << 12); // [13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32 data32 &= (~0x3); data32 |= 0x1; // [1]:dw_disable [0]:cm_disable WRITE_VREG(HEVC_SAO_CTRL1, data32); @@ -4167,13 +4254,13 @@ data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG); data32 &= (~0x30); - data32 |= (MEM_MAP_MODE << 4); // [5:4] -- address_format 00:linear 01:32x32 10:64x32 + data32 |= (hw->mem_map_mode << 4); // [5:4] -- address_format 00:linear 01:32x32 10:64x32 WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32); #else // m8baby test1902 data32 = READ_VREG(HEVC_SAO_CTRL1); data32 &= (~0x3000); - data32 |= (MEM_MAP_MODE << 12); // [13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32 + data32 |= (hw->mem_map_mode << 12); // [13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32 data32 &= (~0xff0); //data32 |= 0x670; // Big-Endian per 64-bit data32 |= 0x880; // Big-Endian per 64-bit @@ -4187,7 +4274,7 @@ data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG); data32 &= (~0x30); - data32 |= (MEM_MAP_MODE << 4); // [5:4] -- address_format 00:linear 01:32x32 10:64x32 + data32 |= (hw->mem_map_mode << 4); // [5:4] -- address_format 00:linear 01:32x32 10:64x32 data32 &= (~0xF); data32 |= 0x8; // Big-Endian per 64-bit WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32); @@ -4196,19 +4283,14 @@ /*CHANGE_DONE nnn*/ data32 = READ_VREG(HEVC_SAO_CTRL1); data32 &= (~0x3000); - data32 |= (mem_map_mode << - 12); - -/* [13:12] axi_aformat, 0-Linear, - * 1-32x32, 2-64x32 - */ + data32 |= (hw->mem_map_mode << 12); /* [13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32 */ data32 &= (~0xff0); /* data32 |= 0x670; // Big-Endian per 64-bit */ #ifdef AOM_AV1_MMU_DW if (hw->dw_mmu_enable == 0) - data32 |= endian; /* Big-Endian per 64-bit */ + data32 |= ((hw->endian >> 8) & 0xfff); /* Big-Endian per 64-bit */ #else - data32 |= endian; /* Big-Endian per 64-bit */ + data32 |= ((hw->endian >> 8) & 0xfff); /* Big-Endian per 64-bit */ #endif data32 &= (~0x3); /*[1]:dw_disable [0]:cm_disable*/ if (get_double_write_mode(hw) == 0) @@ -4236,7 +4318,8 @@ else data32 |= (1 << 8); /* NV12 */ } - + data32 &= (~(3 << 14)); + data32 |= (2 << 14); /* * [31:24] ar_fifo1_axi_thred * [23:16] ar_fifo0_axi_thred @@ -4262,9 +4345,14 @@ data32 &= ~(0xff << 16); WRITE_VREG(HEVC_SAO_CTRL5, data32); } else { + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T7) + WRITE_VREG(HEVC_SAO_CTRL26, 0); data32 = READ_VREG(HEVC_SAO_CTRL5); data32 &= (~(0xff << 16)); - if ((get_double_write_mode(hw) & 0xf) == 2 || + if ((get_double_write_mode(hw) & 0xf) == 8) { + WRITE_VREG(HEVC_SAO_CTRL26, 0xf); + data32 |= (0xff << 16); + } else if ((get_double_write_mode(hw) & 0xf) == 2 || (get_double_write_mode(hw) & 0xf) == 3) data32 |= (0xff<<16); else if ((get_double_write_mode(hw) & 0xf) == 4 || @@ -4276,11 +4364,9 @@ data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG); data32 &= (~0x30); /* [5:4] -- address_format 00:linear 01:32x32 10:64x32 */ - data32 |= (mem_map_mode << - 4); - data32 &= (~0xF); - data32 |= 0xf; /* valid only when double write only */ - /*data32 |= 0x8;*/ /* Big-Endian per 64-bit */ + data32 |= (hw->mem_map_mode << 4); + data32 &= (~0xf); + data32 |= (hw->endian & 0xf); /* valid only when double write only */ /* swap uv */ if (hw->is_used_v4l) { @@ -4290,7 +4376,8 @@ else data32 &= ~(1 << 12); /* NV12 */ } - + data32 &= (~(3 << 8)); + data32 |= (2 << 8); /* * [3:0] little_endian * [5:4] address_format 00:linear 01:32x32 10:64x32 @@ -4855,7 +4942,7 @@ lf->sharpness_level = hw->aom_param.p.loop_filter_sharpness_level; if (((hw->aom_param.p.loop_filter_mode_ref_delta_enabled)&3) == 3) { // enabled but and update - if (cm->prev_frame == NULL) { + if (cm->prev_frame <= 0) { // already initialized in Microcode lf->ref_deltas[0] = conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_0),7); lf->ref_deltas[1] = conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_0>>8),7); @@ -4901,7 +4988,7 @@ } } //else if (hw->aom_param.p.loop_filter_mode_ref_delta_enabled == 1) { // enabled but no update else { // match c code -- not enabled, still need to copy prev to used for next - if ((cm->prev_frame == NULL) | (hw->aom_param.p.loop_filter_mode_ref_delta_enabled & 4)) { + if ((cm->prev_frame <= 0) | (hw->aom_param.p.loop_filter_mode_ref_delta_enabled & 4)) { av1_print(hw, AOM_DEBUG_HW_MORE, "[test.c] mode_ref_delta set to default\n"); lf->ref_deltas[0] = conv2int8((uint8_t)1,7); @@ -4917,18 +5004,16 @@ } else { av1_print(hw, AOM_DEBUG_HW_MORE, "[test.c] mode_ref_delta copy from prev_frame\n"); - if (cm->prev_frame) { - lf->ref_deltas[0] = cm->prev_frame->ref_deltas[0]; - lf->ref_deltas[1] = cm->prev_frame->ref_deltas[1]; - lf->ref_deltas[2] = cm->prev_frame->ref_deltas[2]; - lf->ref_deltas[3] = cm->prev_frame->ref_deltas[3]; - lf->ref_deltas[4] = cm->prev_frame->ref_deltas[4]; - lf->ref_deltas[5] = cm->prev_frame->ref_deltas[5]; - lf->ref_deltas[6] = cm->prev_frame->ref_deltas[6]; - lf->ref_deltas[7] = cm->prev_frame->ref_deltas[7]; - lf->mode_deltas[0] = cm->prev_frame->mode_deltas[0]; - lf->mode_deltas[1] = cm->prev_frame->mode_deltas[1]; - } + lf->ref_deltas[0] = cm->prev_frame->ref_deltas[0]; + lf->ref_deltas[1] = cm->prev_frame->ref_deltas[1]; + lf->ref_deltas[2] = cm->prev_frame->ref_deltas[2]; + lf->ref_deltas[3] = cm->prev_frame->ref_deltas[3]; + lf->ref_deltas[4] = cm->prev_frame->ref_deltas[4]; + lf->ref_deltas[5] = cm->prev_frame->ref_deltas[5]; + lf->ref_deltas[6] = cm->prev_frame->ref_deltas[6]; + lf->ref_deltas[7] = cm->prev_frame->ref_deltas[7]; + lf->mode_deltas[0] = cm->prev_frame->mode_deltas[0]; + lf->mode_deltas[1] = cm->prev_frame->mode_deltas[1]; } } lf->filter_level[0] = hw->aom_param.p.loop_filter_level_0; @@ -4936,24 +5021,23 @@ lf->filter_level_u = hw->aom_param.p.loop_filter_level_u; lf->filter_level_v = hw->aom_param.p.loop_filter_level_v; - if (cm->cur_frame) { - cm->cur_frame->ref_deltas[0] = lf->ref_deltas[0]; - cm->cur_frame->ref_deltas[1] = lf->ref_deltas[1]; - cm->cur_frame->ref_deltas[2] = lf->ref_deltas[2]; - cm->cur_frame->ref_deltas[3] = lf->ref_deltas[3]; - cm->cur_frame->ref_deltas[4] = lf->ref_deltas[4]; - cm->cur_frame->ref_deltas[5] = lf->ref_deltas[5]; - cm->cur_frame->ref_deltas[6] = lf->ref_deltas[6]; - cm->cur_frame->ref_deltas[7] = lf->ref_deltas[7]; - cm->cur_frame->mode_deltas[0] = lf->mode_deltas[0]; - cm->cur_frame->mode_deltas[1] = lf->mode_deltas[1]; + cm->cur_frame->ref_deltas[0] = lf->ref_deltas[0]; + cm->cur_frame->ref_deltas[1] = lf->ref_deltas[1]; + cm->cur_frame->ref_deltas[2] = lf->ref_deltas[2]; + cm->cur_frame->ref_deltas[3] = lf->ref_deltas[3]; + cm->cur_frame->ref_deltas[4] = lf->ref_deltas[4]; + cm->cur_frame->ref_deltas[5] = lf->ref_deltas[5]; + cm->cur_frame->ref_deltas[6] = lf->ref_deltas[6]; + cm->cur_frame->ref_deltas[7] = lf->ref_deltas[7]; + cm->cur_frame->mode_deltas[0] = lf->mode_deltas[0]; + cm->cur_frame->mode_deltas[1] = lf->mode_deltas[1]; - // get seg_4lf parameters from parser - seg_4lf->enabled = hw->aom_param.p.segmentation_enabled & 1; - cm->cur_frame->segmentation_enabled = hw->aom_param.p.segmentation_enabled & 1; - cm->cur_frame->intra_only = (hw->aom_param.p.segmentation_enabled >> 2) & 1; - cm->cur_frame->segmentation_update_map = (hw->aom_param.p.segmentation_enabled >> 3) & 1; - } + // get seg_4lf parameters from parser + seg_4lf->enabled = hw->aom_param.p.segmentation_enabled & 1; + cm->cur_frame->segmentation_enabled = hw->aom_param.p.segmentation_enabled & 1; + cm->cur_frame->intra_only = (hw->aom_param.p.segmentation_enabled >> 2) & 1; + cm->cur_frame->segmentation_update_map = (hw->aom_param.p.segmentation_enabled >> 3) & 1; + if (hw->aom_param.p.segmentation_enabled & 1) { // segmentation_enabled if (hw->aom_param.p.segmentation_enabled & 2) { // segmentation_update_data for (i = 0; i < MAX_SEGMENTS; i++) { @@ -4966,7 +5050,7 @@ } } // segmentation_update_data else { // no segmentation_update_data - if (cm->prev_frame == NULL) { + if (cm->prev_frame <= 0) { for (i=0;i<MAX_SEGMENTS;i++) { seg_4lf->seg_lf_info_y[i] = 0; seg_4lf->seg_lf_info_c[i] = 0; @@ -5022,7 +5106,7 @@ av1_print(hw, AOM_DEBUG_HW_MORE, "[test.c] cur_frame : %p prev_frame : %p - %p \n", cm->cur_frame, cm->prev_frame, av1_get_primary_ref_frame_buf(cm)); - if (cm->cur_frame == NULL) { + if (cm->cur_frame <= 0) { WRITE_VREG(AOM_AV1_CDF_BUFFER_W, buf_spec->cdf_buf.buf_start); WRITE_VREG(AOM_AV1_SEG_MAP_BUFFER_W, buf_spec->seg_map.buf_start); } @@ -5037,7 +5121,7 @@ } cm->cur_frame->seg_mi_rows = cm->cur_frame->mi_rows; cm->cur_frame->seg_mi_cols = cm->cur_frame->mi_cols; - if (cm->prev_frame == NULL) { + if (cm->prev_frame <= 0) { WRITE_VREG(AOM_AV1_CDF_BUFFER_R, buf_spec->cdf_buf.buf_start); WRITE_VREG(AOM_AV1_SEG_MAP_BUFFER_R, buf_spec->seg_map.buf_start); } else { @@ -5322,6 +5406,13 @@ } #endif #endif +#ifdef CO_MV_COMPRESS + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T5D) { + data32 = READ_VREG(HEVC_MPRED_CTRL4); + data32 |= (1 << 1); + WRITE_VREG(HEVC_MPRED_CTRL4, data32); + } +#endif } config_aux_buf(hw); @@ -5427,10 +5518,13 @@ if (mask & HW_MASK_BACK) { /*Initial IQIT_SCALELUT memory -- just to avoid X in simulation*/ - - WRITE_VREG(HEVC_IQIT_SCALELUT_WR_ADDR, 0);/*cfg_p_addr*/ - for (i = 0; i < 1024; i++) - WRITE_VREG(HEVC_IQIT_SCALELUT_DATA, 0); + if (is_rdma_enable()) + rdma_back_end_work(hw->rdma_phy_adr, RDMA_SIZE); + else { + WRITE_VREG(HEVC_IQIT_SCALELUT_WR_ADDR, 0);/*cfg_p_addr*/ + for (i = 0; i < 1024; i++) + WRITE_VREG(HEVC_IQIT_SCALELUT_DATA, 0); + } } if (mask & HW_MASK_FRONT) { @@ -5758,25 +5852,14 @@ buf_alloc_width = 8192; buf_alloc_height = 4608; } -#if 0 - hw->init_pic_w = hw->max_pic_w ? hw->max_pic_w : - (buf_alloc_width ? buf_alloc_width : - (hw->vav1_amstream_dec_info.width ? - hw->vav1_amstream_dec_info.width : - hw->work_space_buf->max_width)); - hw->init_pic_h = hw->max_pic_h ? hw->max_pic_h : - (buf_alloc_height ? buf_alloc_height : - (hw->vav1_amstream_dec_info.height ? - hw->vav1_amstream_dec_info.height : - hw->work_space_buf->max_height)); -#else + hw->init_pic_w = hw->max_pic_w ? hw->max_pic_w : (hw->vav1_amstream_dec_info.width ? hw->vav1_amstream_dec_info.width : (buf_alloc_width ? buf_alloc_width : hw->work_space_buf->max_width)); hw->init_pic_h = hw->max_pic_h ? hw->max_pic_h : (hw->vav1_amstream_dec_info.height ? hw->vav1_amstream_dec_info.height : (buf_alloc_height ? buf_alloc_height : hw->work_space_buf->max_height)); -#endif + hw->pbi->frame_width = hw->init_pic_w; hw->pbi->frame_height = hw->init_pic_h; @@ -5789,9 +5872,9 @@ (hw->vav1_amstream_dec_info.width % 64) != 0)) { if (hw_to_vdec(hw)->canvas_mode != CANVAS_BLKMODE_LINEAR) - mem_map_mode = 2; + hw->mem_map_mode = 2; else { - mem_map_mode = 0; + hw->mem_map_mode = 0; av1_print(hw, AOM_DEBUG_HW_MORE, "vdec blkmod linear, force mem_map_mode 0\n"); } } @@ -5895,6 +5978,7 @@ } memset(hw->count_buffer_addr, 0, COUNT_BUF_SIZE); + vdec_set_vframe_comm(hw_to_vdec(hw), DRIVER_NAME); ret = vav1_mmu_map_alloc(hw); if (ret < 0) goto dma_alloc_fail; @@ -5919,20 +6003,18 @@ struct vdec_s *vdec = hw_to_vdec(hw); int canvas_w = ALIGN(pic_config->y_crop_width, 64)/4; int canvas_h = ALIGN(pic_config->y_crop_height, 32)/4; - int blkmode = mem_map_mode; + int blkmode = hw->mem_map_mode; /*CANVAS_BLKMODE_64X32*/ if (pic_config->double_write_mode) { canvas_w = pic_config->y_crop_width / - get_double_write_ratio(hw, - pic_config->double_write_mode); + get_double_write_ratio( + pic_config->double_write_mode & 0xf); canvas_h = pic_config->y_crop_height / - get_double_write_ratio(hw, - pic_config->double_write_mode); + get_double_write_ratio( + pic_config->double_write_mode & 0xf); - if (mem_map_mode == 0) - canvas_w = ALIGN(canvas_w, 32); - else - canvas_w = ALIGN(canvas_w, 64); + /* sao ctrl1 config aligned with 64, so aligned with 64 same */ + canvas_w = ALIGN(canvas_w, 64); canvas_h = ALIGN(canvas_h, 32); if (vdec->parallel_dec == 1) { @@ -5947,12 +6029,12 @@ pic_config->uv_canvas_index = 128 + pic_config->index * 2 + 1; } - canvas_config_ex(pic_config->y_canvas_index, + config_cav_lut_ex(pic_config->y_canvas_index, pic_config->dw_y_adr, canvas_w, canvas_h, - CANVAS_ADDR_NOWRAP, blkmode, hw->is_used_v4l ? 0 : 7); - canvas_config_ex(pic_config->uv_canvas_index, + CANVAS_ADDR_NOWRAP, blkmode, hw->is_used_v4l ? 0 : 7, VDEC_HEVC); + config_cav_lut_ex(pic_config->uv_canvas_index, pic_config->dw_u_v_adr, canvas_w, canvas_h, - CANVAS_ADDR_NOWRAP, blkmode, hw->is_used_v4l ? 0 : 7); + CANVAS_ADDR_NOWRAP, blkmode, hw->is_used_v4l ? 0 : 7, VDEC_HEVC); #ifdef MULTI_INSTANCE_SUPPORT pic_config->canvas_config[0].phy_addr = @@ -6061,10 +6143,11 @@ if (kfifo_get(&hw->display_q, &vf)) { struct vframe_s *next_vf = NULL; uint8_t index = vf->index & 0xff; - ATRACE_COUNTER(hw->disp_q_name, kfifo_len(&hw->display_q)); + ATRACE_COUNTER(hw->trace.disp_q_name, kfifo_len(&hw->display_q)); if (index < hw->used_buf_num || (vf->type & VIDTYPE_V4L_EOS)) { hw->vf_get_count++; + vf->index_disp = hw->vf_get_count; if (debug & AOM_DEBUG_VFRAME) { struct BufferPool_s *pool = hw->common.buffer_pool; struct PIC_BUFFER_CONFIG_s *pic = @@ -6110,16 +6193,14 @@ static void vav1_vf_put(struct vframe_s *vf, void *op_arg) { struct AV1HW_s *hw = (struct AV1HW_s *)op_arg; - uint8_t index; + uint8_t index = vf->index & 0xff; unsigned long flags; if ((vf == NULL) || (hw == NULL)) return; - index = vf->index & 0xff; - kfifo_put(&hw->newframe_q, (const struct vframe_s *)vf); - ATRACE_COUNTER(hw->new_q_name, kfifo_len(&hw->newframe_q)); + ATRACE_COUNTER(hw->trace.new_q_name, kfifo_len(&hw->newframe_q)); hw->vf_put_count++; if (debug & AOM_DEBUG_VFRAME) { lock_buffer_pool(hw->common.buffer_pool, flags); @@ -6141,10 +6222,6 @@ if (pool->frame_bufs[index].buf.vf_ref > 0) pool->frame_bufs[index].buf.vf_ref--; } - - if (hw->is_used_v4l) - pool->frame_bufs[index].buf.vframe_bound = true; - if (hw->wait_buf) WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG, 0x1); @@ -6325,27 +6402,27 @@ (debug & AOM_DEBUG_DW_DISP_MAIN) == 0) { vf->mem_handle = decoder_mmu_box_get_mem_handle( - hw->mmu_box_dw, hw->buffer_wrap[pic->index]); + hw->mmu_box_dw, pic->index); vf->mem_head_handle = decoder_bmmu_box_get_mem_handle( hw->bmmu_box, - DW_HEADER_BUFFER_IDX(hw->buffer_wrap[pic->BUF_index])); + DW_HEADER_BUFFER_IDX(pic->BUF_index)); vf->mem_dw_handle = NULL; } else #endif { vf->mem_handle = decoder_mmu_box_get_mem_handle( - hw->mmu_box, hw->buffer_wrap[pic->index]); + hw->mmu_box, pic->index); vf->mem_head_handle = decoder_bmmu_box_get_mem_handle( hw->bmmu_box, - HEADER_BUFFER_IDX(hw->buffer_wrap[pic->BUF_index])); + HEADER_BUFFER_IDX(pic->BUF_index)); if (hw->double_write_mode == 3) vf->mem_dw_handle = decoder_bmmu_box_get_mem_handle( hw->bmmu_box, - VF_BUFFER_IDX(hw->buffer_wrap[pic->BUF_index])); + VF_BUFFER_IDX(pic->BUF_index)); else vf->mem_dw_handle = NULL; } @@ -6355,7 +6432,7 @@ } else { vf->mem_handle = decoder_bmmu_box_get_mem_handle( - hw->bmmu_box, VF_BUFFER_IDX(hw->buffer_wrap[pic->BUF_index])); + hw->bmmu_box, VF_BUFFER_IDX(pic->BUF_index)); vf->mem_head_handle = NULL; vf->mem_dw_handle = NULL; /*vf->mem_head_handle = @@ -6365,22 +6442,47 @@ } } +static inline void av1_update_gvs(struct AV1HW_s *hw, struct vframe_s *vf, + struct PIC_BUFFER_CONFIG_s *pic_config) +{ + if (hw->gvs->frame_height != pic_config->y_crop_height) { + hw->gvs->frame_width = pic_config->y_crop_width; + hw->gvs->frame_height = pic_config->y_crop_height; + } + if (hw->gvs->frame_dur != hw->frame_dur) { + hw->gvs->frame_dur = hw->frame_dur; + if (hw->frame_dur != 0) + hw->gvs->frame_rate = ((96000 * 10 / hw->frame_dur) % 10) < 5 ? + 96000 / hw->frame_dur : (96000 / hw->frame_dur +1); + else + hw->gvs->frame_rate = -1; + } + if (vf && hw->gvs->ratio_control != vf->ratio_control) + hw->gvs->ratio_control = vf->ratio_control; + + hw->gvs->status = hw->stat | hw->fatal_error; + hw->gvs->error_count = hw->gvs->error_frame_count; + +} + static int prepare_display_buf(struct AV1HW_s *hw, struct PIC_BUFFER_CONFIG_s *pic_config) { struct vframe_s *vf = NULL; + struct vdec_info tmp4x; int stream_offset = pic_config->stream_offset; struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx; + struct vdec_v4l2_buffer *fb = NULL; ulong nv_order = VIDTYPE_VIU_NV21; u32 pts_valid = 0, pts_us64_valid = 0; - u32 frame_size = 0; - int i, reclac_flag = 0; + u32 frame_size; av1_print(hw, AOM_DEBUG_VFRAME, "%s index = %d\r\n", __func__, pic_config->index); if (kfifo_get(&hw->newframe_q, &vf) == 0) { av1_print(hw, 0, "fatal error, no available buffer slot."); return -1; } + /* swap uv */ if (hw->is_used_v4l) { if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12) || @@ -6394,49 +6496,10 @@ display_frame_count[hw->index]++; if (vf) { - if (!force_pts_unstable && (hw->av1_first_pts_ready)) { - if (hw->is_used_v4l) { - if ((pic_config->timestamp == 0) || (pic_config->timestamp <= hw->last_timestamp)) { - for (i = (FRAME_BUFFERS - 1); i > 0; i--) { - if (hw->last_timestamp == hw->frame_mode_timestamp_save[i]) { - pic_config->timestamp = hw->frame_mode_timestamp_save[i - 1]; - break; - } - } - - if ((i == 0) || (pic_config->timestamp <= hw->last_timestamp)) { - av1_print(hw, AV1_DEBUG_OUT_PTS, - "no found timestamp %d, set 0. %lld, %lld\n", - i, pic_config->timestamp, hw->last_timestamp); - pic_config->timestamp = 0; - } - } - } else { - if ((pic_config->pts == 0) || ((pic_config->pts <= hw->last_pts) && - (pic_config->pts64 <= hw->last_pts_us64))) { - for (i = (FRAME_BUFFERS - 1); i > 0; i--) { - if ((hw->last_pts == hw->frame_mode_pts_save[i]) || - (hw->last_pts_us64 == hw->frame_mode_pts64_save[i])) { - pic_config->pts = hw->frame_mode_pts_save[i - 1]; - pic_config->pts64 = hw->frame_mode_pts64_save[i - 1]; - break; - } - } - - if ((i == 0) || (pic_config->pts <= hw->last_pts)) { - av1_print(hw, AV1_DEBUG_OUT_PTS, - "no found pts %d, set 0. %d, %d\n", - i, pic_config->pts, hw->last_pts); - pic_config->pts = 0; - pic_config->pts64 = 0; - } - } - } - } - if (hw->is_used_v4l) { vf->v4l_mem_handle = hw->m_BUF[pic_config->BUF_index].v4l_ref_buf_addr; + fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; if (hw->mmu_enable) { vf->mm_box.bmmu_box = hw->bmmu_box; vf->mm_box.bmmu_idx = HEADER_BUFFER_IDX(hw->buffer_wrap[pic_config->BUF_index]); @@ -6449,7 +6512,12 @@ if (vdec_frame_based(hw_to_vdec(hw))) { vf->pts = pic_config->pts; vf->pts_us64 = pic_config->pts64; - vf->timestamp = pic_config->timestamp; + + if (hw->is_used_v4l && v4l_bitstream_id_enable) + vf->timestamp = pic_config->timestamp; + else + vf->timestamp = pic_config->pts64; + if (vf->pts != 0 || vf->pts_us64 != 0) { pts_valid = 1; pts_us64_valid = 1; @@ -6477,68 +6545,6 @@ pts_valid = 1; pts_us64_valid = 1; } - - if (hw->av1_first_pts_ready) { - if (hw->is_used_v4l) { - if (hw->frame_dur && (vf->timestamp == 0)) { - vf->timestamp = hw->last_timestamp + - hw->timestamp_duration; - } - - if (!close_to(vf->timestamp, (hw->last_timestamp + - hw->timestamp_duration), 100)) { - vf->timestamp = hw->last_timestamp + - hw->timestamp_duration; - } - } else { - if (hw->frame_dur && ((vf->pts == 0) || (vf->pts_us64 == 0))) { - vf->pts = hw->last_pts + DUR2PTS(hw->frame_dur); - vf->pts_us64 = hw->last_pts_us64 + - (DUR2PTS(hw->frame_dur) * 100 / 9); - reclac_flag = 1; - } - - if (!close_to(vf->pts, (hw->last_pts + DUR2PTS(hw->frame_dur)), 100)) { - vf->pts = hw->last_pts + DUR2PTS(hw->frame_dur); - vf->pts_us64 = hw->last_pts_us64 + - (DUR2PTS(hw->frame_dur) * 100 / 9); - reclac_flag = 2; - } - } - - /* try find the closed pts in saved pts pool */ - if (reclac_flag) { - for (i = 0; i < FRAME_BUFFERS - 1; i++) { - if ((hw->frame_mode_pts_save[i] > vf->pts) && - (hw->frame_mode_pts_save[i + 1] < vf->pts)) { - if ((hw->frame_mode_pts_save[i] - vf->pts) > - (vf->pts - hw->frame_mode_pts_save[i + 1])) { - vf->pts = hw->frame_mode_pts_save[i + 1]; - vf->pts_us64 = hw->frame_mode_pts64_save[i + 1]; - } else { - vf->pts = hw->frame_mode_pts_save[i]; - vf->pts_us64 = hw->frame_mode_pts64_save[i]; - } - break; - } - } - if (i == (FRAME_BUFFERS - 1)) - hw->dur_recalc_flag = 1; - } - } else { - av1_print(hw, AV1_DEBUG_OUT_PTS, - "first pts %d change to save[%d] %d, ts: %llu\n", - vf->pts, hw->first_pts_index - 1, - hw->frame_mode_pts_save[hw->first_pts_index - 1], - hw->frame_mode_timestamp_save[hw->first_pts_index - 1]); - vf->pts = hw->frame_mode_pts_save[hw->first_pts_index - 1]; - vf->pts_us64 = hw->frame_mode_pts64_save[hw->first_pts_index - 1]; - vf->timestamp = hw->frame_mode_timestamp_save[hw->first_pts_index - 1]; - } - hw->last_pts = vf->pts; - hw->last_pts_us64 = vf->pts_us64; - hw->last_timestamp = vf->timestamp; - hw->av1_first_pts_ready = true; av1_print(hw, AV1_DEBUG_OUT_PTS, "av1 output slice type %d, dur %d, pts %d, pts64 %lld, ts: %llu\n", pic_config->slice_type, hw->frame_dur, vf->pts, vf->pts_us64, vf->timestamp); @@ -6569,10 +6575,10 @@ vf->dwHeadAddr = pic_config->header_dw_adr; else if ((mode == 1 || mode == 2 || mode == 4) && (debug & AOM_DEBUG_DW_DISP_MAIN) == 0) { - vf->compHeadAddr = pic_config->header_dw_adr; - vf->fgs_valid = 0; - av1_print(hw, AOM_DEBUG_VFRAME, - "Use dw mmu for display\n"); + vf->compHeadAddr = pic_config->header_dw_adr; + vf->fgs_valid = 0; + av1_print(hw, 0, + "Use dw mmu for display\n"); } } #endif @@ -6588,7 +6594,7 @@ (pic_config->double_write_mode & 0x20) == 0) { vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD; - vf->type |= VIDTYPE_VIU_NV21; + vf->type |= nv_order; if ((pic_config->double_write_mode == 3 || pic_config->double_write_mode == 5) && (!IS_8K_SIZE(pic_config->y_crop_width, @@ -6649,11 +6655,11 @@ vf->width,vf->height, pic_config->width, pic_config->height); */ vf->width = pic_config->y_crop_width / - get_double_write_ratio(hw, - pic_config->double_write_mode); + get_double_write_ratio( + pic_config->double_write_mode & 0xf); vf->height = pic_config->y_crop_height / - get_double_write_ratio(hw, - pic_config->double_write_mode); + get_double_write_ratio( + pic_config->double_write_mode & 0xf); if (force_w_h != 0) { vf->width = (force_w_h >> 16) & 0xffff; vf->height = force_w_h & 0xffff; @@ -6662,11 +6668,11 @@ ((pic_config->double_write_mode & 0xf) == 2 || (pic_config->double_write_mode & 0xf) == 4)) { vf->compWidth = pic_config->y_crop_width / - get_double_write_ratio(hw, - pic_config->double_write_mode); + get_double_write_ratio( + pic_config->double_write_mode & 0xf); vf->compHeight = pic_config->y_crop_height / - get_double_write_ratio(hw, - pic_config->double_write_mode); + get_double_write_ratio( + pic_config->double_write_mode & 0xf); } else { vf->compWidth = pic_config->y_crop_width; vf->compHeight = pic_config->y_crop_height; @@ -6686,20 +6692,60 @@ decoder_do_frame_check(hw_to_vdec(hw), vf); vdec_vframe_ready(hw_to_vdec(hw), vf); kfifo_put(&hw->display_q, (const struct vframe_s *)vf); - ATRACE_COUNTER(hw->pts_name, vf->pts); - ATRACE_COUNTER(hw->new_q_name, kfifo_len(&hw->newframe_q)); - ATRACE_COUNTER(hw->disp_q_name, kfifo_len(&hw->display_q)); + ATRACE_COUNTER(hw->trace.pts_name, vf->pts); + ATRACE_COUNTER(hw->trace.new_q_name, kfifo_len(&hw->newframe_q)); + ATRACE_COUNTER(hw->trace.disp_q_name, kfifo_len(&hw->display_q)); hw->vf_pre_count++; -#ifndef CONFIG_AMLOGIC_MEDIA_MULTI_DEC /*count info*/ - gvs->frame_dur = hw->frame_dur; - vdec_count_info(gvs, 0, stream_offset); -#endif + hw->gvs->frame_dur = hw->frame_dur; + vdec_count_info(hw->gvs, 0, stream_offset); + hw_to_vdec(hw)->vdec_fps_detec(hw_to_vdec(hw)->id); + +#ifdef AUX_DATA_CRC + decoder_do_aux_data_check(hw_to_vdec(hw), pic_config->aux_data_buf, + pic_config->aux_data_size); +#endif + + av1_print(hw, AV1_DEBUG_SEI_DETAIL, "%s aux_data_size = %d\n", + __func__, pic_config->aux_data_size); + + if (debug & AV1_DEBUG_SEI_DETAIL) { + int i = 0; + PR_INIT(128); + for (i = 0; i < pic_config->aux_data_size; i++) { + PR_FILL("%02x ", pic_config->aux_data_buf[i]); + if (((i + 1) & 0xf) == 0) + PR_INFO(hw->index); + } + PR_INFO(hw->index); + } + + if (hw->is_used_v4l) { + update_vframe_src_fmt(vf, + pic_config->aux_data_buf, + pic_config->aux_data_size, + false, hw->provider_name, NULL); + } + + av1_update_gvs(hw, vf, pic_config); + memcpy(&tmp4x, hw->gvs, sizeof(struct vdec_info)); + tmp4x.bit_depth_luma = bit_depth_luma; + tmp4x.bit_depth_chroma = bit_depth_chroma; + tmp4x.double_write_mode = pic_config->double_write_mode; + vdec_fill_vdec_frame(hw_to_vdec(hw), &hw->vframe_qos, &tmp4x, vf, pic_config->hw_decode_time); if (without_display_mode == 0) { - vf_notify_receiver(hw->provider_name, - VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + if (hw->is_used_v4l) { + if (v4l2_ctx->is_stream_off) { + vav1_vf_put(vav1_vf_get(hw), hw); + } else { + fb->task->submit(fb->task, TASK_TYPE_DEC); + } + } else { + vf_notify_receiver(hw->provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + } } else vav1_vf_put(vav1_vf_get(hw), hw); } @@ -6733,7 +6779,8 @@ } if (index == INVALID_IDX) { - if (vdec_v4l_get_buffer(hw->v4l2_ctx, &fb) < 0) { + ctx->fb_ops.query(&ctx->fb_ops, &hw->fb_token); + if (ctx->fb_ops.alloc(&ctx->fb_ops, hw->fb_token, &fb, AML_FB_REQ_DEC) < 0) { pr_err("[%d] EOS get free buff fail.\n", ctx->id); return -1; } @@ -6745,14 +6792,18 @@ vf->flag = VFRAME_FLAG_EMPTY_FRAME_V4L; vf->v4l_mem_handle = (index == INVALID_IDX) ? (ulong)fb : hw->m_BUF[index].v4l_ref_buf_addr; + fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; vdec_vframe_ready(vdec, vf); kfifo_put(&hw->display_q, (const struct vframe_s *)vf); - vf_notify_receiver(vdec->vf_provider_name, - VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); - av1_print(hw, PRINT_FLAG_V4L_DETAIL, - "[%d] AV1 EOS notify.\n", (hw->is_used_v4l)?ctx->id:vdec->id); + if (hw->is_used_v4l) + fb->task->submit(fb->task, TASK_TYPE_DEC); + else + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + + av1_print(hw, 0, "[%d] AV1 EOS notify.\n", (hw->is_used_v4l)?ctx->id:vdec->id); } return 0; @@ -6793,10 +6844,21 @@ if (check_dma) hevc_mmu_dma_check(hw_to_vdec(hw)); - decoder_mmu_box_free_idx_tail( - hw->mmu_box, - hw->buffer_wrap[cm->cur_fb_idx_mmu], - hw->used_4k_num); + if (hw->is_used_v4l) { + int index = cm->cur_fb_idx_mmu; + struct internal_comp_buf *ibuf = + index_to_icomp_buf(hw, index); + + decoder_mmu_box_free_idx_tail( + ibuf->mmu_box, + ibuf->index, + hw->used_4k_num); + } else { + decoder_mmu_box_free_idx_tail( + hw->mmu_box, + cm->cur_fb_idx_mmu, + hw->used_4k_num); + } cm->cur_fb_idx_mmu = INVALID_IDX; hw->used_4k_num = -1; @@ -6831,7 +6893,7 @@ return; if (cm->cur_fb_idx_mmu != INVALID_IDX) { decoder_mmu_box_free_idx(hw->mmu_box, - hw->buffer_wrap[cm->cur_fb_idx_mmu]); + cm->cur_fb_idx_mmu); cm->cur_fb_idx_mmu = INVALID_IDX; hw->used_4k_num = -1; @@ -7102,12 +7164,12 @@ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "MCRCC_HIT_RATE : %d\n", hitrate); hitrate = 100*(byp_mcr_cnt_nchoutwin + byp_mcr_cnt_nchcanv)/raw_mcr_cnt; av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "MCRCC_BYP_RATE : %d\n", hitrate); - mcrcc_hit_rate = 100*hit_mcr_cnt/raw_mcr_cnt; - mcrcc_bypass_rate = 100*(byp_mcr_cnt_nchoutwin + byp_mcr_cnt_nchcanv)/raw_mcr_cnt; } else { av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "MCRCC_HIT_RATE : na\n"); av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "MCRCC_BYP_RATE : na\n"); } + mcrcc_hit_rate = 100*hit_mcr_cnt/raw_mcr_cnt; + mcrcc_bypass_rate = 100*(byp_mcr_cnt_nchoutwin + byp_mcr_cnt_nchcanv)/raw_mcr_cnt; return; } @@ -7137,7 +7199,7 @@ if ( raw_mcr_cnt != 0 ) { hitrate = 100*hit_mcr_cnt/raw_mcr_cnt; - av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "DECOMP_HCACHE_HIT_RATE : %d\n", hitrate); + av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "DECOMP_HCACHE_HIT_RATE : %.2f\%\n", hitrate); } else { av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "DECOMP_HCACHE_HIT_RATE : na\n"); } @@ -7337,9 +7399,36 @@ #endif +#if 0 +void release_unused_4k_ext(MMU_BUFF_MGR *mmumgr, int32_t cur_buf_idx, long used_4k_num) +{ + int32_t release_4k_position; + int32_t i; + + if(mmumgr->mmu_pic_count < 0) return; + + mmumgr->mmu_offset_seed = used_4k_num & 0xff; + if(used_4k_num > mmumgr->mmu_buf[cur_buf_idx].mmu_4k_number) { + printk("[MMU MEM ERROR] : Use more 4K Page than allocated %d > ([%d] = %d)!!\r\n", used_4k_num, cur_buf_idx, mmumgr->mmu_buf[cur_buf_idx].mmu_4k_number); + } + else printk("[MMU MEM RELEASE] : P%d(buffer %d) used %d of %d 4k buffer (%d%c)\r\n", mmumgr->mmu_pic_count, cur_buf_idx, used_4k_num, mmumgr->mmu_buf[cur_buf_idx].mmu_4k_number, used_4k_num*100/mmumgr->mmu_buf[cur_buf_idx].mmu_4k_number, '%'); + + for(i = used_4k_num; i<mmumgr->mmu_buf[cur_buf_idx].mmu_4k_number; i++){ + release_4k_position = mmumgr->mmu_buf[cur_buf_idx].mmu_4k_index[i] - mmumgr->MC_BUFFER_START_4K_ADR; + printk("[MMU MEM RELEASE DEBUG] release_4k_position[%d] : 0x%x\n", i, release_4k_position+mmumgr->MC_BUFFER_START_4K_ADR); + mmumgr->mmu_4k_status[release_4k_position] = 0; + } + mmumgr->cur_mem_usage -= (mmumgr->mmu_buf[cur_buf_idx].mmu_4k_number - used_4k_num)*4096; + mmumgr->mmu_buf[cur_buf_idx].mmu_4k_number = used_4k_num; +} +#endif + int av1_continue_decoding(struct AV1HW_s *hw, int obu_type) { - int ret; + int ret = 0; +#ifdef SANITY_CHECK + param_t* params = &hw->aom_param; +#endif #if 1 //def CHANGE_DONE AV1Decoder *pbi = hw->pbi; @@ -7383,18 +7472,70 @@ } else { hw->new_compressed_data = 0; } - ret = av1_bufmgr_process(pbi, &hw->aom_param, - hw->new_compressed_data, obu_type); - av1_print(hw, AOM_DEBUG_HW_MORE, - "%s: pbi %p cm %p cur_frame %p\n", - __func__, pbi, cm, cm->cur_frame); +#ifdef SEND_MMU_USED_NUM + if (cm->prev_fb_idx != INVALID_IDX) { + long used_4k_num = aom_param.p.mmu_used_num; + if (used_4k_num != 0) { + printk("mmu free tail, index %d used_num 0x%x\n", + cm->prev_fb_idx, used_4k_num); + release_unused_4k_ext(&av1_mmumgr_m, cm->prev_fb_idx, used_4k_num); + } - av1_print(hw, AOM_DEBUG_HW_MORE, - "1+++++++++++++++++++++++++++++++++++%d %p\n", - ret, cm->cur_frame); - if (hw->new_compressed_data) - WRITE_VREG(PIC_END_LCU_COUNT, 0); +#ifdef AOM_AV1_MMU_DW + used_4k_num = aom_param.p.dw_mmu_used_num; + if (used_4k_num != 0) { + release_unused_4k_ext(&av1_mmumgr_dw, cm->prev_fb_idx, used_4k_num); + printk("dw mmu free tail, index %d used_num 0x%x\n", + cm->prev_fb_idx, used_4k_num); + } +#endif + } + cm->prev_fb_idx = INVALID_IDX; +#endif +#ifdef SANITY_CHECK + ret = 0; + av1_print(hw, AOM_DEBUG_HW_MORE, + "Check Picture size, max (%d, %d), width/height (%d, %d), dec_width %d\n", + params->p.max_frame_width, + params->p.max_frame_height, + params->p.frame_width_scaled, + params->p.frame_height, + params->p.dec_frame_width + ); + + if (/*params->p.max_frame_width > MAX_PIC_WIDTH || + params->p.max_frame_height > MAX_PIC_HEIGHT ||*/ + (params->p.frame_width_scaled * params->p.frame_height) > MAX_SIZE_8K || + (params->p.dec_frame_width * params->p.frame_height) > MAX_SIZE_8K || + params->p.frame_width_scaled <= 0 || + params->p.dec_frame_width <= 0 || + params->p.frame_height <= 0) { + av1_print(hw, 0, "!!Picture size error, max (%d, %d), width/height (%d, %d), dec_width %d\n", + params->p.max_frame_width, + params->p.max_frame_height, + params->p.frame_width_scaled, + params->p.frame_height, + params->p.dec_frame_width + ); + ret = -1; + } +#endif + if (ret >= 0) { + ret = av1_bufmgr_process(pbi, &hw->aom_param, + hw->new_compressed_data, obu_type); + if (ret < 0) + return -1; + av1_print(hw, AOM_DEBUG_HW_MORE, + "%s: pbi %p cm %p cur_frame %p\n", + __func__, pbi, cm, cm->cur_frame); + + av1_print(hw, AOM_DEBUG_HW_MORE, + "1+++++++++++++++++++++++++++++++++++%d %p\n", + ret, cm->cur_frame); + if (hw->new_compressed_data) + WRITE_VREG(PIC_END_LCU_COUNT, 0); + } if (ret > 0) { /* the case when cm->show_existing_frame is 1 */ /*case 3016*/ @@ -7416,16 +7557,16 @@ av1_print(hw, AOM_DEBUG_HW_MORE, "aom_bufmgr_process=> %d,decode done, AOM_AV1_SEARCH_HEAD\r\n", ret); - WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_SEARCH_HEAD); + WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_SEARCH_HEAD); pbi->decode_idx++; pbi->bufmgr_proc_count++; hw->frame_decoded = 1; return 0; - } - else if (ret < 0) { + } else if (ret < 0) { hw->frame_decoded = 1; av1_print(hw, AOM_DEBUG_HW_MORE, - "aom_bufmgr_process=> %d, bufmgr e.r.r.o.r., AOM_AV1_SEARCH_HEAD\r\n", ret); + "aom_bufmgr_process=> %d, bufmgr e.r.r.o.r. %d, AOM_AV1_SEARCH_HEAD\r\n", + ret, cm->error.error_code); WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_SEARCH_HEAD); return 0; } @@ -7487,18 +7628,25 @@ pbi->bufmgr_proc_count); pbi->decode_idx++; hw->frame_count++; +#ifdef SEND_MMU_USED_NUM + cm->prev_fb_idx = cm->cur_fb_idx_mmu; + cm->cur_fb_idx_mmu = cm->cur_frame->buf.index; +#endif cur_pic_config->slice_type = cm->cur_frame->frame_type; if (hw->chunk) { av1_print(hw, AV1_DEBUG_OUT_PTS, - "%s, config pic pts %d, pts64 %lld\n", - __func__, hw->chunk->pts, hw->chunk->pts64); + "%s, config pic pts %d, pts64 %lld, ts: %lld\n", + __func__, hw->chunk->pts, hw->chunk->pts64, hw->chunk->timestamp); cur_pic_config->pts = hw->chunk->pts; cur_pic_config->pts64 = hw->chunk->pts64; cur_pic_config->timestamp = hw->chunk->timestamp; - hw->chunk->pts = 0; - hw->chunk->pts64 = 0; - hw->chunk->timestamp = 0; + + if (hw->is_used_v4l && !v4l_bitstream_id_enable) { + cur_pic_config->pts64 = hw->chunk->timestamp; + hw->chunk->timestamp = 0; + } } + ATRACE_COUNTER(hw->trace.decode_header_memory_time_name, TRACE_HEADER_REGISTER_START); #ifdef DUAL_DECODE #else config_pic_size(hw, hw->aom_param.p.bit_depth); @@ -7511,12 +7659,14 @@ } if (ret >= 0 && hw->mmu_enable && ((hw->double_write_mode & 0x10) == 0)) { + ATRACE_COUNTER(hw->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_START); ret = av1_alloc_mmu(hw, cm->cur_frame->buf.index, cur_pic_config->y_crop_width, cur_pic_config->y_crop_height, hw->aom_param.p.bit_depth, hw->frame_mmu_map_addr); + ATRACE_COUNTER(hw->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_END); if (ret >= 0) cm->cur_fb_idx_mmu = cm->cur_frame->buf.index; else @@ -7567,6 +7717,16 @@ config_dblk_hw(hw); + /* store segment_feature before shared sub-module run to fix mosaic on t5d */ + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2) + WRITE_VREG(HEVC_PARSER_MEM_WR_ADDR, 0x11b0 + (cur_pic_config->index)); + else + WRITE_VREG(HEVC_PARSER_MEM_WR_ADDR, 0x1010 + (cur_pic_config->index)); + if (hw->aom_param.p.segmentation_enabled & 1) // segmentation_enabled + WRITE_VREG(HEVC_PARSER_MEM_RW_DATA, READ_VREG(AV1_REF_SEG_INFO)); + else + WRITE_VREG(HEVC_PARSER_MEM_RW_DATA, 0); + av1_print(hw, AOM_DEBUG_HW_MORE, "HEVC_DEC_STATUS_REG <= AOM_AV1_DECODE_SLICE\n"); WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_DECODE_SLICE); @@ -7580,15 +7740,13 @@ cm->cur_frame->segment_feature[i] = (0x80000000 | (i << 22)); } } - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2) - WRITE_VREG(HEVC_PARSER_MEM_WR_ADDR, 0x11b0 + (cur_pic_config->index)); - else - WRITE_VREG(HEVC_PARSER_MEM_WR_ADDR, 0x1010 + (cur_pic_config->index)); - if (hw->aom_param.p.segmentation_enabled & 1) // segmentation_enabled - WRITE_VREG(HEVC_PARSER_MEM_RW_DATA, READ_VREG(AV1_REF_SEG_INFO)); - else - WRITE_VREG(HEVC_PARSER_MEM_RW_DATA, 0); + } else { + av1_print(hw, AOM_DEBUG_HW_MORE, "Sequence head, Search next start code\n"); + cm->prev_fb_idx = INVALID_IDX; + //skip, search next start code + WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_DECODE_SLICE); } + ATRACE_COUNTER(hw->trace.decode_header_memory_time_name, TRACE_HEADER_REGISTER_END); return ret; #else @@ -7793,7 +7951,7 @@ frame->min_mv = a[0]; av1_print(hw, AV1_DEBUG_QOS_INFO, - "mv data %lx a[0]= %x a[1]= %x a[2]= %x\n", + "mv data %x a[0]= %x a[1]= %x a[2]= %x\n", data, a[0], a[1], a[2]); data = READ_VREG(HEVC_QP_INFO); @@ -7820,7 +7978,7 @@ frame->min_qp = a[0]; av1_print(hw, AV1_DEBUG_QOS_INFO, - "qp data %lx a[0]= %x a[1]= %x a[2]= %x\n", + "qp data %x a[0]= %x a[1]= %x a[2]= %x\n", data, a[0], a[1], a[2]); data = READ_VREG(HEVC_SKIP_INFO); @@ -7847,7 +8005,7 @@ frame->min_skip = a[0]; av1_print(hw, AV1_DEBUG_QOS_INFO, - "skip data %lx a[0]= %x a[1]= %x a[2]= %x\n", + "skip data %x a[0]= %x a[1]= %x a[2]= %x\n", data, a[0], a[1], a[2]); } else { uint32_t blk88_y_count; @@ -8183,19 +8341,20 @@ //printf("Error, dec_status of 0x%x, not supported!!!\n", dec_status); return -1; } - av1_print2(AOM_DEBUG_HW_MORE, "load_param: ret 0x%x\n", head_type); - - if (debug&AOM_AV1_DEBUG_SEND_PARAM_WITH_REG) { - get_rpm_param(params); - } - else { - for (i = 0; i < (RPM_END-RPM_BEGIN); i += 4) { - int32_t ii; - for (ii = 0; ii < 4; ii++) { - params->l.data[i+ii]=hw->rpm_ptr[i+3-ii]; - } + av1_print2(AOM_DEBUG_HW_MORE, "load_param: ret 0x%x\n", head_type); + ATRACE_COUNTER(hw->trace.decode_header_memory_time_name, TRACE_HEADER_RPM_START); + if (debug&AOM_AV1_DEBUG_SEND_PARAM_WITH_REG) { + get_rpm_param(params); + } + else { + for (i = 0; i < (RPM_END-RPM_BEGIN); i += 4) { + int32_t ii; + for (ii = 0; ii < 4; ii++) { + params->l.data[i+ii]=hw->rpm_ptr[i+3-ii]; } } + } + ATRACE_COUNTER(hw->trace.decode_header_memory_time_name, TRACE_HEADER_RPM_END); params->p.enable_ref_frame_mvs = (params->p.seq_flags >> 7) & 0x1; params->p.enable_superres = (params->p.seq_flags >> 15) & 0x1; @@ -8222,14 +8381,29 @@ return av1_bufmgr_postproc(hw->pbi, hw->frame_decoded); } +static void vav1_get_comp_buf_info(struct AV1HW_s *hw, + struct vdec_comp_buf_info *info) +{ + u16 bit_depth = hw->param.p.bit_depth; + + info->max_size = av1_max_mmu_buf_size( + hw->max_pic_w, + hw->max_pic_h); + info->header_size = av1_get_header_size( + hw->frame_width, + hw->frame_height); + info->frame_buffer_size = av1_mmu_page_num( + hw, hw->frame_width, + hw->frame_height, + bit_depth == 0); +} + static int vav1_get_ps_info(struct AV1HW_s *hw, struct aml_vdec_ps_infos *ps) { - int dw_mode = v4l_parser_get_double_write_mode(hw); - - ps->visible_width = hw->frame_width / get_double_write_ratio(hw, dw_mode); - ps->visible_height = hw->frame_height / get_double_write_ratio(hw, dw_mode); - ps->coded_width = ALIGN(hw->frame_width, 32) / get_double_write_ratio(hw, dw_mode); - ps->coded_height = ALIGN(hw->frame_height, 32) / get_double_write_ratio(hw, dw_mode); + ps->visible_width = hw->frame_width; + ps->visible_height = hw->frame_height; + ps->coded_width = ALIGN(hw->frame_width, 64); + ps->coded_height = ALIGN(hw->frame_height, 64); ps->dpb_size = hw->used_buf_num; return 0; @@ -8246,6 +8420,7 @@ if (ctx->param_sets_from_ucode && hw->res_ch_flag == 0) { struct aml_vdec_ps_infos ps; + struct vdec_comp_buf_info comp; if ((cm->width != 0 && cm->height != 0) && @@ -8256,6 +8431,11 @@ "%s (%d,%d)=>(%d,%d)\r\n", __func__, cm->width, cm->height, hw->frame_width, hw->frame_height); + if (get_valid_double_write_mode(hw) != 16) { + vav1_get_comp_buf_info(hw, &comp); + vdec_v4l_set_comp_buf_info(ctx, &comp); + } + vav1_get_ps_info(hw, &ps); vdec_v4l_set_ps_infos(ctx, &ps); vdec_v4l_res_ch_event(ctx); @@ -8279,9 +8459,16 @@ int obu_type; int ret = 0; - /*if (hw->wait_buf) - * pr_info("set wait_buf to 0\r\n"); - */ + if (dec_status == AOM_AV1_FRAME_HEAD_PARSER_DONE || + dec_status == AOM_AV1_SEQ_HEAD_PARSER_DONE || + dec_status == AOM_AV1_FRAME_PARSER_DONE) { + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_START); + } + else if (dec_status == AOM_AV1_DEC_PIC_END || + dec_status == AOM_NAL_DECODE_DONE) { + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_PIC_DONE_START); + } + if (hw->eos) return IRQ_HANDLED; hw->wait_buf = 0; @@ -8295,6 +8482,7 @@ dec_again_process(hw); else { hw->dec_result = DEC_RESULT_DONE; + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_EDN); vdec_schedule_work(&hw->work); } } @@ -8302,6 +8490,8 @@ return IRQ_HANDLED; } else if (dec_status == AOM_AV1_DEC_PIC_END) { struct AV1_Common_s *const cm = &hw->common; + struct PIC_BUFFER_CONFIG_s *frame = &cm->cur_frame->buf; + struct vdec_s *vdec = hw_to_vdec(hw); #if 1 u32 fg_reg0, fg_reg1, num_y_points, num_cb_points, num_cr_points; WRITE_VREG(HEVC_FGS_IDX, 0); @@ -8331,6 +8521,12 @@ #ifdef USE_DEC_PIC_END if (READ_VREG(PIC_END_LCU_COUNT) != 0) { hw->frame_decoded = 1; + if (cm->cur_frame && vdec->mvfrm && frame) { + frame->hw_decode_time = + local_clock() - vdec->mvfrm->hw_decode_start; + frame->frame_size2 = vdec->mvfrm->frame_size; + } + hw->gvs->frame_count = hw->frame_count; /* In c module, multi obus are put in one packet, which is decoded with av1_receive_compressed_data(). @@ -8361,17 +8557,27 @@ if (cm->cur_frame != NULL) { hevc_mmu_dma_check(hw_to_vdec(hw)); - av1_print(hw, AOM_DEBUG_HW_MORE, "mmu free tail, index %d used_num 0x%lx\n", + av1_print(hw, AOM_DEBUG_HW_MORE, "mmu free tail, index %d used_num 0x%x\n", cm->cur_frame->buf.index, used_4k_num); - decoder_mmu_box_free_idx_tail(hw->mmu_box, - hw->buffer_wrap[cm->cur_frame->buf.index], used_4k_num); + if (hw->is_used_v4l) { + struct internal_comp_buf *ibuf = + index_to_icomp_buf(hw, cm->cur_fb_idx_mmu); + + decoder_mmu_box_free_idx_tail( + ibuf->mmu_box, + ibuf->index, + used_4k_num); + } else { + decoder_mmu_box_free_idx_tail(hw->mmu_box, + cm->cur_frame->buf.index, used_4k_num); + } #ifdef AOM_AV1_MMU_DW if (hw->dw_mmu_enable) { used_4k_num = (READ_VREG(HEVC_SAO_MMU_STATUS2) >> 16); decoder_mmu_box_free_idx_tail(hw->mmu_box_dw, - hw->buffer_wrap[cm->cur_frame->buf.index], used_4k_num); - av1_print(hw, AOM_DEBUG_HW_MORE, "dw mmu free tail, index %d used_num 0x%lx\n", + cm->cur_frame->buf.index, used_4k_num); + av1_print(hw, AOM_DEBUG_HW_MORE, "dw mmu free tail, index %d used_num 0x%x\n", cm->cur_frame->buf.index, used_4k_num); } #endif @@ -8393,7 +8599,7 @@ hw->frame_decoded && READ_VREG(HEVC_SHIFT_BYTE_COUNT) < hw->data_size) { #ifdef DEBUG_CRC_ERROR - if (crc_debug_flag & 0x40) + if ((crc_debug_flag & 0x40) && cm->cur_frame) dump_mv_buffer(hw, &cm->cur_frame->buf); #endif WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_SEARCH_HEAD); @@ -8402,9 +8608,10 @@ hw->fgs_valid); if (hw->config_next_ref_info_flag) config_next_ref_info_hw(hw); + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_EDN); } else { #ifdef DEBUG_CRC_ERROR - if (crc_debug_flag & 0x40) + if ((crc_debug_flag & 0x40) && cm->cur_frame) dump_mv_buffer(hw, &cm->cur_frame->buf); #endif hw->dec_result = DEC_RESULT_DONE; @@ -8413,13 +8620,13 @@ if (mcrcc_cache_alg_flag) dump_hit_rate(hw); #endif + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_EDN); vdec_schedule_work(&hw->work); } } else { av1_print(hw, AOM_DEBUG_HW_MORE, "PIC_END, fgs_valid %d search head ...\n", hw->fgs_valid); - WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_SEARCH_HEAD); #ifdef USE_DEC_PIC_END if (READ_VREG(PIC_END_LCU_COUNT) != 0) { hw->frame_decoded = 1; @@ -8430,11 +8637,13 @@ we assume each packet must and only include one picture of data (LCUs) or cm->show_existing_frame is 1 */ - av1_print(hw, AOM_DEBUG_HW_MORE, "Decoding done (index %d)\n", - cm->cur_frame? cm->cur_frame->buf.index:-1); + if (cm->cur_frame) + av1_print(hw, AOM_DEBUG_HW_MORE, "Decoding done (index %d)\n", + cm->cur_frame? cm->cur_frame->buf.index:-1); config_next_ref_info_hw(hw); } #endif + WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_SEARCH_HEAD); /* if (debug & AV1_DEBUG_BUFMGR_MORE) @@ -8512,8 +8721,9 @@ hw->mv_buf_margin = hw->used_buf_num - REF_FRAMES_4K + 1; if (((hw->max_pic_w % 64) != 0) && (hw_to_vdec(hw)->canvas_mode != CANVAS_BLKMODE_LINEAR)) - mem_map_mode = 2; - av1_print(hw, 0, "force 8k double write 4, mem_map_mode %d\n", mem_map_mode); + hw->mem_map_mode = 2; + av1_print(hw, 0, + "force 8k double write 4, mem_map_mode %d\n", hw->mem_map_mode); } vav1_mmu_map_alloc(hw); if (hw->mmu_enable) @@ -8526,6 +8736,15 @@ WRITE_VREG(HEVC_SAO_C_START_ADDR, 0); } #endif + + /*v4l2 alloc new mv when max size changed */ + if (hw->is_used_v4l) { + /* now less than 8k use fix mv buf size */ + if (IS_8K_SIZE(hw->max_pic_w, hw->max_pic_h) && hw->pic_list_init_done) { + if (init_mv_buf_list(hw) < 0) + pr_err("%s: !!!!Error, reinit_mv_buf_list fail\n", __func__); + } + } } bit_depth_luma = hw->aom_param.p.bit_depth; bit_depth_chroma = hw->aom_param.p.bit_depth; @@ -8563,6 +8782,7 @@ "AOM_AV1_SEQ_HEAD_PARSER_DONE, search head ...\n"); WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_SEARCH_HEAD); hw->process_busy = 0; + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_END); return IRQ_HANDLED; } #ifndef USE_DEC_PIC_END @@ -8577,8 +8797,9 @@ we assume each packet must and only include one picture of data (LCUs) or cm->show_existing_frame is 1 */ - av1_print(hw, AOM_DEBUG_HW_MORE, "Decoding done (index %d)\n", - cm->cur_frame? cm->cur_frame->buf.index:-1); + if (cm->cur_frame) + av1_print(hw, AOM_DEBUG_HW_MORE, "Decoding done (index %d)\n", + cm->cur_frame? cm->cur_frame->buf.index:-1); } } #endif @@ -8628,8 +8849,14 @@ if (!v4l_res_change(hw)) { if (ctx->param_sets_from_ucode && !hw->v4l_params_parsed) { struct aml_vdec_ps_infos ps; + struct vdec_comp_buf_info comp; pr_info("set ucode parse\n"); + if (get_valid_double_write_mode(hw) != 16) { + vav1_get_comp_buf_info(hw, &comp); + vdec_v4l_set_comp_buf_info(ctx, &comp); + } + vav1_get_ps_info(hw, &ps); /*notice the v4l2 codec.*/ vdec_v4l_set_ps_infos(ctx, &ps); @@ -8647,6 +8874,18 @@ } } + if (hw->one_package_frame_cnt) { + if (get_free_buf_count(hw) <= 0) { + hw->dec_result = AOM_AV1_RESULT_NEED_MORE_BUFFER; + hw->cur_obu_type = obu_type; + hw->process_busy = 0; + vdec_schedule_work(&hw->work); + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_END); + return IRQ_HANDLED; + } + } + hw->one_package_frame_cnt++; + ret = av1_continue_decoding(hw, obu_type); hw->postproc_done = 0; hw->process_busy = 0; @@ -8660,7 +8899,7 @@ vdec_schedule_work(&hw->work); } } - + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_END); return IRQ_HANDLED; } @@ -8675,6 +8914,16 @@ WRITE_VREG(HEVC_ASSIST_MBOX0_CLR_REG, 1); dec_status = READ_VREG(HEVC_DEC_STATUS_REG) & 0xff; + + if (dec_status == AOM_AV1_FRAME_HEAD_PARSER_DONE || + dec_status == AOM_AV1_SEQ_HEAD_PARSER_DONE || + dec_status == AOM_AV1_FRAME_PARSER_DONE) { + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_HEAD_DONE); + } + else if (dec_status == AOM_AV1_DEC_PIC_END || + dec_status == AOM_NAL_DECODE_DONE) { + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_PIC_DONE); + } if (!hw) return IRQ_HANDLED; if (hw->init_flag == 0) @@ -8799,19 +9048,20 @@ hw->process_busy = 0; return IRQ_HANDLED; } - } - if (get_free_buf_count(hw) <= 0) { - /* - if (hw->wait_buf == 0) + if (get_free_buf_count(hw) <= 0) { + /* + if (hw->wait_buf == 0) pr_info("set wait_buf to 1\r\n"); - */ - hw->wait_buf = 1; - hw->process_busy = 0; - av1_print(hw, AV1_DEBUG_BUFMGR, - "free buf not enough = %d\n", - get_free_buf_count(hw)); - return IRQ_HANDLED; + */ + hw->wait_buf = 1; + hw->process_busy = 0; + av1_print(hw, AV1_DEBUG_BUFMGR, + "free buf not enough = %d\n", + get_free_buf_count(hw)); + return IRQ_HANDLED; + } } + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_END); return IRQ_WAKE_THREAD; } @@ -8827,10 +9077,10 @@ frame_height * fps; } -static void vav1_put_timer_func(unsigned long arg) +static void vav1_put_timer_func(struct timer_list *timer) { - struct AV1HW_s *hw = (struct AV1HW_s *)arg; - struct timer_list *timer = &hw->timer; + struct AV1HW_s *hw = container_of(timer, + struct AV1HW_s, timer); uint8_t empty_flag; unsigned int buf_level; @@ -9036,19 +9286,18 @@ vstatus->error_count = 0; vstatus->status = av1->stat | av1->fatal_error; vstatus->frame_dur = av1->frame_dur; -#ifndef CONFIG_AMLOGIC_MEDIA_MULTI_DEC - vstatus->bit_rate = gvs->bit_rate; - vstatus->frame_data = gvs->frame_data; - vstatus->total_data = gvs->total_data; - vstatus->frame_count = gvs->frame_count; - vstatus->error_frame_count = gvs->error_frame_count; - vstatus->drop_frame_count = gvs->drop_frame_count; - vstatus->total_data = gvs->total_data; - vstatus->samp_cnt = gvs->samp_cnt; - vstatus->offset = gvs->offset; +//#ifndef CONFIG_AMLOGIC_MEDIA_MULTI_DEC + vstatus->bit_rate = av1->gvs->bit_rate; + vstatus->frame_data = av1->gvs->frame_data; + vstatus->total_data = av1->gvs->total_data; + vstatus->frame_count = av1->gvs->frame_count; + vstatus->error_frame_count = av1->gvs->error_frame_count; + vstatus->drop_frame_count = av1->gvs->drop_frame_count; + vstatus->samp_cnt = av1->gvs->samp_cnt; + vstatus->offset = av1->gvs->offset; snprintf(vstatus->vdec_name, sizeof(vstatus->vdec_name), "%s", DRIVER_NAME); -#endif +//#endif return 0; } @@ -9192,9 +9441,6 @@ hw->saved_resolution = 0; hw->get_frame_dur = false; on_no_keyframe_skiped = 0; - hw->first_pts_index = 0; - hw->dur_recalc_flag = 0; - hw->av1_first_pts_ready = false; width = hw->vav1_amstream_dec_info.width; height = hw->vav1_amstream_dec_info.height; hw->frame_dur = @@ -9275,12 +9521,10 @@ fw->len = fw_size; INIT_WORK(&hw->set_clk_work, av1_set_clk); - init_timer(&hw->timer); + timer_setup(&hw->timer, vav1_put_timer_func, 0); #ifdef MULTI_INSTANCE_SUPPORT if (hw->m_ins_flag) { - hw->timer.data = (ulong) hw; - hw->timer.function = vav1_put_timer_func; hw->timer.expires = jiffies + PUT_INTERVAL; /*add_timer(&hw->timer); @@ -9330,16 +9574,18 @@ #endif hw->provider_name = PROVIDER_NAME; #ifdef MULTI_INSTANCE_SUPPORT - vf_provider_init(&vav1_vf_prov, hw->provider_name, - &vav1_vf_provider, hw); - vf_reg_provider(&vav1_vf_prov); - vf_notify_receiver(hw->provider_name, VFRAME_EVENT_PROVIDER_START, NULL); - if (hw->frame_dur != 0) { - if (!is_reset) - vf_notify_receiver(hw->provider_name, - VFRAME_EVENT_PROVIDER_FR_HINT, - (void *) - ((unsigned long)hw->frame_dur)); + if (!hw->is_used_v4l) { + vf_provider_init(&vav1_vf_prov, hw->provider_name, + &vav1_vf_provider, hw); + vf_reg_provider(&vav1_vf_prov); + vf_notify_receiver(hw->provider_name, VFRAME_EVENT_PROVIDER_START, NULL); + if (hw->frame_dur != 0) { + if (!is_reset) + vf_notify_receiver(hw->provider_name, + VFRAME_EVENT_PROVIDER_FR_HINT, + (void *) + ((unsigned long)hw->frame_dur)); + } } #else vf_provider_init(&vav1_vf_prov, hw->provider_name, &vav1_vf_provider, @@ -9352,13 +9598,10 @@ #endif hw->stat |= STAT_VF_HOOK; - hw->timer.data = (ulong)hw; - hw->timer.function = vav1_put_timer_func; hw->timer.expires = jiffies + PUT_INTERVAL; + add_timer(&hw->timer); hw->stat |= STAT_VDEC_RUN; - - add_timer(&hw->timer); hw->stat |= STAT_TIMER_ARM; amhevc_start(); @@ -9387,7 +9630,7 @@ hw->stat &= ~STAT_TIMER_ARM; } - if (hw->stat & STAT_VF_HOOK) { + if (!hw->is_used_v4l && (hw->stat & STAT_VF_HOOK)) { if (!is_reset) vf_notify_receiver(hw->provider_name, VFRAME_EVENT_PROVIDER_FR_END_HINT, @@ -9431,7 +9674,7 @@ hw->stat &= ~STAT_TIMER_ARM; } - if (hw->stat & STAT_VF_HOOK) { + if (!hw->is_used_v4l && (hw->stat & STAT_VF_HOOK)) { if (!is_reset) vf_notify_receiver(hw->provider_name, VFRAME_EVENT_PROVIDER_FR_END_HINT, @@ -9472,7 +9715,7 @@ } hw->need_cache_size = buf_size * SZ_1M; hw->sc_start_time = get_jiffies_64(); - if (hw->mmu_enable) { + if (hw->mmu_enable && !hw->is_used_v4l) { int count = FRAME_BUFFERS; hw->mmu_box = decoder_mmu_box_alloc_box(DRIVER_NAME, hw->index /* * 2*/, count, @@ -9532,13 +9775,12 @@ #ifndef MULTI_INSTANCE_SUPPORT int i; #endif - pr_debug("%s\n", __func__); - - if (!(is_cpu_tm2_revb() || - (get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_TM2))) { - pr_err("unsupport av1, cpu %d, is_tm2_revb %d\n", + if ((get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_TM2) || + (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5) || + ((get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_TM2) && !is_meson_rev_b())) { + pr_err("av1 unsupported on cpu %d, is_tm2_revb %d\n", get_cpu_major_id(), is_cpu_tm2_revb()); - return -EFAULT; + return -EINVAL; } mutex_lock(&vav1_mutex); @@ -9690,6 +9932,12 @@ cma_dev = pdata->cma_dev; #endif + hw->endian = HEVC_CONFIG_LITTLE_ENDIAN; + if (is_support_vdec_canvas()) + hw->endian = HEVC_CONFIG_BIG_ENDIAN; + if (endian) + hw->endian = endian; + #ifdef MULTI_INSTANCE_SUPPORT pdata->private = hw; pdata->dec_status = vav1_dec_status; @@ -9862,6 +10110,12 @@ /* finished decoding one frame or error, * notify vdec core to switch context */ + if (hw->dec_result != AOM_AV1_RESULT_NEED_MORE_BUFFER) + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_WORKER_START); + + if (hw->dec_result == DEC_RESULT_AGAIN) + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_WORKER_AGAIN); + av1_print(hw, PRINT_FLAG_VDEC_DETAIL, "%s dec_result %d %x %x %x\n", __func__, @@ -9869,6 +10123,21 @@ READ_VREG(HEVC_STREAM_LEVEL), READ_VREG(HEVC_STREAM_WR_PTR), READ_VREG(HEVC_STREAM_RD_PTR)); + + if (hw->dec_result == AOM_AV1_RESULT_NEED_MORE_BUFFER) { + reset_process_time(hw); + if (get_free_buf_count(hw) <= 0) { + hw->dec_result = AOM_AV1_RESULT_NEED_MORE_BUFFER; + vdec_schedule_work(&hw->work); + } else { + av1_release_bufs(hw); + av1_continue_decoding(hw, hw->cur_obu_type); + hw->postproc_done = 0; + start_process_time(hw); + } + return; + } + if (((hw->dec_result == DEC_RESULT_GET_DATA) || (hw->dec_result == DEC_RESULT_GET_DATA_RETRY)) && (hw_to_vdec(hw)->next_status != @@ -9891,7 +10160,7 @@ } if (get_free_buf_count(hw) >= - run_ready_min_buf_num) { + hw->run_ready_min_buf_num) { int r; int decode_size; r = vdec_prepare_input(vdec, &hw->chunk); @@ -10004,6 +10273,7 @@ del_timer_sync(&hw->timer); hw->stat &= ~STAT_TIMER_ARM; } + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_WORKER_END); /* mark itself has all HW resource released and input released */ if (vdec->parallel_dec == 1) vdec_core_finish_run(vdec, CORE_MASK_HEVC); @@ -10018,6 +10288,35 @@ vav1_prot_init(hw, HW_MASK_FRONT | HW_MASK_BACK); return 0; } + +static bool is_avaliable_buffer(struct AV1HW_s *hw) +{ + AV1_COMMON *cm = &hw->common; + RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs; + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + int i, free_count = 0; + + if (ctx->cap_pool.dec < hw->used_buf_num) { + free_count = v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx); + if (free_count && + !ctx->fb_ops.query(&ctx->fb_ops, &hw->fb_token)) { + return false; + } + } + + for (i = 0; i < hw->used_buf_num; ++i) { + if ((frame_bufs[i].ref_count == 0) && + (frame_bufs[i].buf.vf_ref == 0) && + (frame_bufs[i].buf.index >= 0) && + frame_bufs[i].buf.cma_alloc_addr) { + free_count++; + } + } + + return free_count < hw->run_ready_min_buf_num ? 0 : 1; +} + static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) { struct AV1HW_s *hw = @@ -10030,8 +10329,17 @@ return ret; if (!hw->first_sc_checked && hw->mmu_enable) { - int size = decoder_mmu_box_sc_check(hw->mmu_box, tvp); + int size; + void * mmu_box; + if (hw->is_used_v4l) { + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + mmu_box = ctx->mmu_box; + } else + mmu_box = hw->mmu_box; + + size = decoder_mmu_box_sc_check(mmu_box, tvp); hw->first_sc_checked = 1; av1_print(hw, 0, "av1 cached=%d need_size=%d speed= %d ms\n", size, (hw->need_cache_size >> PAGE_SHIFT), @@ -10045,7 +10353,7 @@ } if (get_free_buf_count(hw) >= - run_ready_min_buf_num) { + hw->run_ready_min_buf_num) { if (vdec->parallel_dec == 1) ret = CORE_MASK_HEVC; else @@ -10058,17 +10366,19 @@ if (ctx->param_sets_from_ucode) { if (hw->v4l_params_parsed) { - if ((ctx->cap_pool.in < hw->used_buf_num) && - v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < - run_ready_min_buf_num) - ret = 0; + if (ctx->cap_pool.dec < hw->used_buf_num) { + if (is_avaliable_buffer(hw)) + ret = CORE_MASK_HEVC; + else + ret = 0; + } } else { if (ctx->v4l_resolution_change) ret = 0; } } else if (ctx->cap_pool.in < ctx->dpb_size) { if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < - run_ready_min_buf_num) + hw->run_ready_min_buf_num) ret = 0; } } @@ -10084,105 +10394,30 @@ return ret; } -static void av1_frame_mode_pts_save(struct AV1HW_s *hw) +static void av1_frame_mode_cal_dur(struct AV1HW_s *hw) { - u64 i, valid_pts_diff_cnt, pts_diff_sum; - u64 in_pts_diff, last_valid_pts_diff, calc_dur; - if (hw->chunk == NULL) - return; - /* no return when first pts is 0 */ - if (hw->first_pts_index) { - /* filtration pts 0 and continuous same pts */ - if ((hw->chunk->pts == 0) || - (hw->frame_mode_pts_save[0] == hw->chunk->pts)) - return; + return; + av1_print(hw, AV1_DEBUG_OUT_PTS, + "run_front: pts %d, pts64 %lld, ts: %llu\n", + hw->chunk->pts, hw->chunk->pts64, hw->chunk->timestamp); - /* fps change, frame dur change to lower or higher, - * can't find closed pts in saved pool */ - if ((hw->dur_recalc_flag) || - (hw->last_pts > hw->chunk->pts)) { - hw->av1_first_pts_ready = 0; - hw->first_pts_index = 0; - hw->get_frame_dur = 0; - hw->dur_recalc_flag = 0; - memset(hw->frame_mode_pts_save, 0, - sizeof(hw->frame_mode_pts_save)); - memset(hw->frame_mode_pts64_save, 0, - sizeof(hw->frame_mode_pts64_save)); - /*v4l use*/ - memset(hw->frame_mode_timestamp_save, 0, - sizeof(hw->frame_mode_timestamp_save)); - } - } - av1_print(hw, AV1_DEBUG_OUT_PTS, - "run_front: pts %d, pts64 %lld, ts: %llu\n", - hw->chunk->pts, hw->chunk->pts64, hw->chunk->timestamp); + if (hw->pts_diff_count > FRAME_BUFFERS) + return ; - for (i = (FRAME_BUFFERS - 1); i > 0; i--) { - hw->frame_mode_pts_save[i] = hw->frame_mode_pts_save[i - 1]; - hw->frame_mode_pts64_save[i] = hw->frame_mode_pts64_save[i - 1]; - hw->frame_mode_timestamp_save[i] = hw->frame_mode_timestamp_save[i - 1]; - } - hw->frame_mode_pts_save[0] = hw->chunk->pts; - hw->frame_mode_pts64_save[0] = hw->chunk->pts64; - hw->frame_mode_timestamp_save[0] = hw->chunk->timestamp; - if (hw->first_pts_index < ARRAY_SIZE(hw->frame_mode_pts_save)) - hw->first_pts_index++; - /* frame duration check, vdec_secure return for nts problem */ - if ((!hw->first_pts_index) || hw->get_frame_dur || vdec_secure(hw_to_vdec(hw))) - return; - valid_pts_diff_cnt = 0; - pts_diff_sum = 0; - - for (i = 0; i < FRAME_BUFFERS - 1; i++) { - if (hw->is_used_v4l) { - if ((hw->frame_mode_timestamp_save[i] > hw->frame_mode_timestamp_save[i + 1]) && - (hw->frame_mode_timestamp_save[i + 1] != 0)) - in_pts_diff = hw->frame_mode_timestamp_save[i] - - hw->frame_mode_timestamp_save[i + 1]; - else - in_pts_diff = 0; - } else { - if ((hw->frame_mode_pts_save[i] > hw->frame_mode_pts_save[i + 1]) && - (hw->frame_mode_pts_save[i + 1] != 0)) - in_pts_diff = hw->frame_mode_pts_save[i] - - hw->frame_mode_pts_save[i + 1]; - else - in_pts_diff = 0; + if ((hw->chunk->pts > hw->last_chunk_pts) && (hw->last_chunk_pts > 0)) { + hw->pts_diff_count++; + hw->pts_diff_sum = hw->pts_diff_sum + (hw->chunk->pts - hw->last_chunk_pts); + if (hw->pts_diff_count > FRAME_BUFFERS) { + u32 calc_dur = (u32)div_u64(div_u64(hw->pts_diff_sum, hw->pts_diff_count)*96, 90); + if ((calc_dur <= 16000) && (calc_dur >= 800)) { + av1_print(hw, 0, "change to calc dur %d, old dur %d\n", calc_dur, hw->frame_dur); + hw->frame_dur = calc_dur; + } + } } - if (in_pts_diff < 100 || - (valid_pts_diff_cnt && (!close_to(in_pts_diff, last_valid_pts_diff, 100)))) - in_pts_diff = 0; - else { - last_valid_pts_diff = in_pts_diff; - valid_pts_diff_cnt++; - } - - pts_diff_sum += in_pts_diff; - } - - if (!valid_pts_diff_cnt) { - av1_print(hw, 0, "checked no avaliable pts\n"); - return; - } - - calc_dur = PTS2DUR(pts_diff_sum / valid_pts_diff_cnt); - if ((!close_to(calc_dur, hw->frame_dur, 10)) && - (calc_dur < 9601) && (calc_dur > 800)) { - av1_print(hw, 0, "change to calc dur %lld, old dur %d\n", calc_dur, hw->frame_dur); - hw->frame_dur = calc_dur; - hw->get_frame_dur = true; - } else { - if (hw->frame_count > FRAME_BUFFERS) - hw->get_frame_dur = true; - } - - if (hw->is_used_v4l) { - hw->timestamp_duration = - pts_diff_sum / valid_pts_diff_cnt; - } + hw->last_chunk_pts = hw->chunk->pts; } static void run_front(struct vdec_s *vdec) @@ -10211,7 +10446,8 @@ hw->dec_result = DEC_RESULT_NONE; hw->start_shift_bytes = READ_VREG(HEVC_SHIFT_BYTE_COUNT); - av1_frame_mode_pts_save(hw); + av1_frame_mode_cal_dur(hw); + if (debug & PRINT_FLAG_VDEC_STATUS) { if (vdec_frame_based(vdec) && hw->chunk && !vdec_secure(vdec)) { u8 *data = NULL; @@ -10258,6 +10494,7 @@ hw->start_shift_bytes); } } + ATRACE_COUNTER(hw->trace.decode_run_time_name, TRACE_RUN_LOADING_FW_START); if (vdec->mc_loaded) { /*firmware have load before, and not changes to another. @@ -10285,12 +10522,14 @@ vdec->mc_type = VFORMAT_AV1; #endif } + ATRACE_COUNTER(hw->trace.decode_run_time_name, TRACE_RUN_LOADING_FW_END); + ATRACE_COUNTER(hw->trace.decode_run_time_name, TRACE_RUN_LOADING_RESTORE_START); if (av1_hw_ctx_restore(hw) < 0) { vdec_schedule_work(&hw->work); return; } - + ATRACE_COUNTER(hw->trace.decode_run_time_name, TRACE_RUN_LOADING_RESTORE_END); vdec_enable_input(vdec); WRITE_VREG(HEVC_DEC_STATUS_REG, HEVC_ACTION_DONE); @@ -10302,6 +10541,8 @@ WRITE_VREG(HEVC_SHIFT_BYTE_COUNT, 0); size = hw->chunk->size + (hw->chunk->offset & (VDEC_FIFO_ALIGN - 1)); + if (vdec->mvfrm) + vdec->mvfrm->frame_size = hw->chunk->size; } hw->data_size = size; WRITE_VREG(HEVC_DECODE_SIZE, size); @@ -10334,14 +10575,19 @@ struct AV1HW_s *hw = (struct AV1HW_s *)vdec->private; + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_RUN_START); av1_print(hw, PRINT_FLAG_VDEC_DETAIL, "%s mask %lx\r\n", __func__, mask); run_count[hw->index]++; + if (vdec->mvfrm) + vdec->mvfrm->hw_decode_start = local_clock(); hw->vdec_cb_arg = arg; hw->vdec_cb = callback; + hw->one_package_frame_cnt = 0; run_front(vdec); + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_RUN_END); } static void av1_decode_ctx_reset(struct AV1HW_s *hw) @@ -10362,11 +10608,6 @@ for (i = 0; i < MV_BUFFER_NUM; i++) { if (hw->m_mv_BUF[i].start_adr) { - if (mv_buf_dynamic_alloc) { - decoder_bmmu_box_free_idx(hw->bmmu_box, MV_BUFFER_IDX(i)); - hw->m_mv_BUF[i].start_adr = 0; - hw->m_mv_BUF[i].size = 0; - } hw->m_mv_BUF[i].used_flag = 0; } } @@ -10459,7 +10700,7 @@ hw->no_head ); - if (vf_get_receiver(vdec->vf_provider_name)) { + if (!hw->is_used_v4l && vf_get_receiver(vdec->vf_provider_name)) { enum receviver_start_e state = vf_notify_receiver(vdec->vf_provider_name, VFRAME_EVENT_PROVIDER_QUREY_STATE, @@ -10481,14 +10722,14 @@ hw->vf_get_count, hw->vf_put_count, get_free_buf_count(hw), - run_ready_min_buf_num + hw->run_ready_min_buf_num ); dump_pic_list(hw); for (i = 0; i < MAX_BUF_NUM; i++) { av1_print(hw, 0, - "mv_Buf(%d) start_adr 0x%lx size 0x%x used %d\n", + "mv_Buf(%d) start_adr 0x%x size 0x%x used %d\n", i, hw->m_mv_BUF[i].start_adr, hw->m_mv_BUF[i].size, @@ -10580,20 +10821,19 @@ struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data; int ret; int config_val; + int i; struct vframe_content_light_level_s content_light_level; struct vframe_master_display_colour_s vf_dp; u32 work_buf_size; struct BuffInfo_s *p_buf_info; - - struct BUF_s BUF[MAX_BUF_NUM]; struct AV1HW_s *hw = NULL; - pr_debug("%s\n", __func__); - if (!(is_cpu_tm2_revb() || - (get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_TM2))) { - pr_err("unsupport av1, cpu %d, is_tm2_revb %d\n", + if ((get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_TM2) || + (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5) || + ((get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_TM2) && !is_meson_rev_b())) { + pr_err("av1 unsupported on cpu %d, is_tm2_revb %d\n", get_cpu_major_id(), is_cpu_tm2_revb()); - return -EFAULT; + return -EINVAL; } if (pdata == NULL) { @@ -10636,19 +10876,35 @@ pdata->threaded_irq_handler = av1_threaded_irq_cb; pdata->dump_state = av1_dump_state; - memcpy(&BUF[0], &hw->m_BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM); - memcpy(&hw->m_BUF[0], &BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM); - hw->index = pdev->id; - - snprintf(hw->vdec_name, sizeof(hw->vdec_name), + if (is_rdma_enable()) { + hw->rdma_adr = dma_alloc_coherent(amports_get_dma_device(), RDMA_SIZE, &hw->rdma_phy_adr, GFP_KERNEL); + for (i = 0; i < SCALELUT_DATA_WRITE_NUM; i++) { + hw->rdma_adr[i * 4] = HEVC_IQIT_SCALELUT_WR_ADDR & 0xfff; + hw->rdma_adr[i * 4 + 1] = i; + hw->rdma_adr[i * 4 + 2] = HEVC_IQIT_SCALELUT_DATA & 0xfff; + hw->rdma_adr[i * 4 + 3] = 0; + if (i == SCALELUT_DATA_WRITE_NUM - 1) { + hw->rdma_adr[i * 4 + 2] = (HEVC_IQIT_SCALELUT_DATA & 0xfff) | 0x20000; + } + } + } + snprintf(hw->trace.vdec_name, sizeof(hw->trace.vdec_name), "av1-%d", hw->index); - snprintf(hw->pts_name, sizeof(hw->pts_name), - "%s-pts", hw->vdec_name); - snprintf(hw->new_q_name, sizeof(hw->new_q_name), - "%s-newframe_q", hw->vdec_name); - snprintf(hw->disp_q_name, sizeof(hw->disp_q_name), - "%s-dispframe_q", hw->vdec_name); + snprintf(hw->trace.pts_name, sizeof(hw->trace.pts_name), + "%s-pts", hw->trace.vdec_name); + snprintf(hw->trace.new_q_name, sizeof(hw->trace.new_q_name), + "%s-newframe_q", hw->trace.vdec_name); + snprintf(hw->trace.disp_q_name, sizeof(hw->trace.disp_q_name), + "%s-dispframe_q", hw->trace.vdec_name); + snprintf(hw->trace.decode_time_name, sizeof(hw->trace.decode_time_name), + "decoder_time%d", pdev->id); + snprintf(hw->trace.decode_run_time_name, sizeof(hw->trace.decode_run_time_name), + "decoder_run_time%d", pdev->id); + snprintf(hw->trace.decode_header_memory_time_name, sizeof(hw->trace.decode_header_memory_time_name), + "decoder_header_time%d", pdev->id); + snprintf(hw->trace.decode_work_time_name, sizeof(hw->trace.decode_work_time_name), + "decoder_work_time%d", pdev->id); if (pdata->use_vfm_path) snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE, VFM_DEC_PROVIDER_NAME); @@ -10670,18 +10926,12 @@ hevc_pair = (struct AV1HW_s *)pdata->master->private; else if (pdata->slave) hevc_pair = (struct AV1HW_s *)pdata->slave->private; - - if (hevc_pair) - hw->shift_byte_count_lo = hevc_pair->shift_byte_count_lo; } #endif else snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE, MULTI_INSTANCE_PROVIDER_NAME ".%02x", pdev->id & 0xff); - vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name, - &vav1_vf_provider, hw); - hw->provider_name = pdata->vf_provider_name; platform_set_drvdata(pdev, pdata); @@ -10819,25 +11069,38 @@ } hw->vf_dp = vf_dp; } else { - /*hw->vav1_amstream_dec_info.width = 0; - hw->vav1_amstream_dec_info.height = 0; - hw->vav1_amstream_dec_info.rate = 30;*/ + u32 force_w, force_h; + if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5D) { + force_w = 1920; + force_h = 1088; + } else { + force_w = 8192; + force_h = 4608; + } if (hw->vav1_amstream_dec_info.width) hw->max_pic_w = hw->vav1_amstream_dec_info.width; else - hw->max_pic_w = 8192; + hw->max_pic_w = force_w; if (hw->vav1_amstream_dec_info.height) hw->max_pic_h = hw->vav1_amstream_dec_info.height; else - hw->max_pic_h = 4608; + hw->max_pic_h = force_h; hw->double_write_mode = double_write_mode; } + hw->endian = HEVC_CONFIG_LITTLE_ENDIAN; if (!hw->is_used_v4l) { - hw->mem_map_mode = mem_map_mode; + vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name, + &vav1_vf_provider, hw); } + hw->mem_map_mode = mem_map_mode; + if (is_support_vdec_canvas()) + hw->endian = HEVC_CONFIG_BIG_ENDIAN; + if (endian) + hw->endian = endian; + if (is_oversize(hw->max_pic_w, hw->max_pic_h)) { pr_err("over size: %dx%d, probe failed\n", hw->max_pic_w, hw->max_pic_h); @@ -10905,8 +11168,8 @@ #endif av1_print(hw, 0, - "no_head %d low_latency %d\n", - hw->no_head, hw->low_latency_flag); + "no_head %d low_latency %d, signal_type 0x%x\n", + hw->no_head, hw->low_latency_flag, hw->video_signal_type); #if 0 hw->buf_start = pdata->mem_start; hw->buf_size = pdata->mem_end - pdata->mem_start + 1; @@ -10938,6 +11201,7 @@ hw->first_sc_checked = 0; hw->fatal_error = 0; hw->show_frame_num = 0; + hw->run_ready_min_buf_num = run_ready_min_buf_num; if (debug) { av1_print(hw, AOM_DEBUG_HW_MORE, "===AV1 decoder mem resource 0x%lx size 0x%x\n", @@ -10955,6 +11219,11 @@ pdata->dec_status = NULL; return -ENODEV; } + +#ifdef AUX_DATA_CRC + vdec_aux_data_check_init(pdata); +#endif + vdec_set_prepare_level(pdata, start_decode_buf_level); hevc_source_changed(VFORMAT_AV1, 4096, 2048, 60); @@ -10977,6 +11246,10 @@ if (debug) av1_print(hw, AOM_DEBUG_HW_MORE, "amvdec_av1_remove\n"); +#ifdef AUX_DATA_CRC + vdec_aux_data_check_exit(vdec); +#endif + vmav1_stop(hw); if (vdec->parallel_dec == 1) @@ -11002,6 +11275,8 @@ hw->pts_missed, hw->pts_hit, hw->frame_dur); #endif /* devm_kfree(&pdev->dev, (void *)hw); */ + if (is_rdma_enable()) + dma_free_coherent(amports_get_dma_device(), RDMA_SIZE, hw->rdma_adr, hw->rdma_phy_adr); vfree(hw->pbi); release_dblk_struct(hw); vfree((void *)hw); @@ -11068,7 +11343,10 @@ #endif /* if (vdec_is_support_4k()) { - p_buf_info = &aom_workbuff_spec[1]; + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) + p_buf_info = &aom_workbuff_spec[1]; + else + p_buf_info = &aom_workbuff_spec[1]; } else p_buf_info = &aom_workbuff_spec[0]; @@ -11102,10 +11380,13 @@ pr_err("failed to register amvdec_av1 driver\n"); return -ENODEV; } - - if ((get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_TM2) || is_cpu_tm2_revb()) { + if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5D) { amvdec_av1_profile.profile = - "8k, 10bit, dwrite, compressed, no_head, frame_dv"; + "10bit, dwrite, compressed, no_head, v4l-uvm"; + } else if (((get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_TM2) || is_cpu_tm2_revb()) + && (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5)) { + amvdec_av1_profile.profile = + "8k, 10bit, dwrite, compressed, no_head, frame_dv, v4l-uvm"; } else { amvdec_av1_profile.name = "av1_unsupport"; } @@ -11125,6 +11406,7 @@ INIT_REG_NODE_CONFIGS("media.decoder", &av1_node, "av1", av1_configs, CONFIG_FOR_RW); #endif + vcodec_feature_register(VFORMAT_AV1, 0); return 0; } @@ -11363,6 +11645,9 @@ module_param(without_display_mode, uint, 0664); MODULE_PARM_DESC(without_display_mode, "\n without_display_mode\n"); +module_param(v4l_bitstream_id_enable, uint, 0664); +MODULE_PARM_DESC(v4l_bitstream_id_enable, "\n v4l_bitstream_id_enable\n"); + module_init(amvdec_av1_driver_init_module); module_exit(amvdec_av1_driver_remove_module);
diff --git a/drivers/frame_provider/decoder/vc1/vvc1.c b/drivers/frame_provider/decoder/vc1/vvc1.c index aa215a9..1f0dfa9 100644 --- a/drivers/frame_provider/decoder/vc1/vvc1.c +++ b/drivers/frame_provider/decoder/vc1/vvc1.c
@@ -30,7 +30,6 @@ #include <linux/amlogic/media/vfm/vframe.h> #include <linux/amlogic/media/vfm/vframe_provider.h> #include <linux/amlogic/media/vfm/vframe_receiver.h> - #include <linux/amlogic/media/utils/vdec_reg.h> #include "../utils/amvdec.h" #include "../utils/vdec.h" @@ -41,10 +40,11 @@ #include <linux/amlogic/media/codec_mm/codec_mm.h> #include <linux/amlogic/media/codec_mm/configs.h> #include "../utils/firmware.h" -#include <linux/amlogic/tee.h> +//#include <linux/amlogic/tee.h> +#include <uapi/linux/tee.h> #include <linux/delay.h> #include "../../../common/chips/decoder_cpu_ver_info.h" - +#include "../utils/vdec_feature.h" #define DRIVER_NAME "amvdec_vc1" #define MODULE_NAME "amvdec_vc1" @@ -146,6 +146,7 @@ static bool is_reset; static struct work_struct set_clk_work; static struct work_struct error_wd_work; +static struct canvas_config_s vc1_canvas_config[DECODE_BUFFER_NUM_MAX][3]; spinlock_t vc1_rp_lock; @@ -516,9 +517,9 @@ } if (next_pts_us64 != 0) { next_pts_us64 += - (u64)((vf->duration) - + div_u64((u64)((vf->duration) - ((vf->duration) >> 4)) * - 100 / 9; + 100, 9); } } else { vf->duration = @@ -550,6 +551,17 @@ decoder_bmmu_box_get_mem_handle( mm_blk_handle, buffer_index); + if (is_support_vdec_canvas()) { + vf->canvas0Addr = vf->canvas1Addr = -1; + vf->canvas0_config[0] = vc1_canvas_config[buffer_index][0]; + vf->canvas0_config[1] = vc1_canvas_config[buffer_index][1]; +#ifdef NV21 + vf->plane_num = 2; +#else + vf->canvas0_config[2] = vc1_canvas_config[buffer_index][2]; + vf->plane_num = 3; +#endif + } kfifo_put(&display_q, (const struct vframe_s *)vf); ATRACE_COUNTER(MODULE_NAME, vf->pts); @@ -582,8 +594,8 @@ ((vf->duration) >> 4)); } if (next_pts_us64 != 0) { - next_pts_us64 += (u64)((vf->duration) - - ((vf->duration) >> 4)) * 100 / 9; + next_pts_us64 += div_u64((u64)((vf->duration) - + ((vf->duration) >> 4)) * 100, 9); } } else { vf->duration = @@ -614,6 +626,18 @@ decoder_bmmu_box_get_mem_handle( mm_blk_handle, buffer_index); + + if (is_support_vdec_canvas()) { + vf->canvas0Addr = vf->canvas1Addr = -1; + vf->canvas0_config[0] = vc1_canvas_config[buffer_index][0]; + vf->canvas0_config[1] = vc1_canvas_config[buffer_index][1]; +#ifdef NV21 + vf->plane_num = 2; +#else + vf->canvas0_config[2] = vc1_canvas_config[buffer_index][2]; + vf->plane_num = 3; +#endif + } kfifo_put(&display_q, (const struct vframe_s *)vf); ATRACE_COUNTER(MODULE_NAME, vf->pts); @@ -673,9 +697,9 @@ } if (next_pts_us64 != 0) { next_pts_us64 += - (u64)((vf->duration) - + div_u64((u64)((vf->duration) - ((vf->duration) >> 4)) * - 100 / 9; + 100, 9); } } else { vf->duration = @@ -709,7 +733,17 @@ decoder_bmmu_box_get_mem_handle( mm_blk_handle, buffer_index); - + if (is_support_vdec_canvas()) { + vf->canvas0Addr = vf->canvas1Addr = -1; + vf->canvas0_config[0] = vc1_canvas_config[buffer_index][0]; + vf->canvas0_config[1] = vc1_canvas_config[buffer_index][1]; +#ifdef NV21 + vf->plane_num = 2; +#else + vf->canvas0_config[2] = vc1_canvas_config[buffer_index][2]; + vf->plane_num = 3; +#endif + } kfifo_put(&display_q, (const struct vframe_s *)vf); ATRACE_COUNTER(MODULE_NAME, vf->pts); @@ -893,30 +927,57 @@ } #ifdef NV21 - canvas_config(2 * i + 0, + config_cav_lut_ex(2 * i + 0, buf_start, canvas_width, canvas_height, - CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); - canvas_config(2 * i + 1, + CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32, 0, VDEC_1); + vc1_canvas_config[i][0].endian = 0; + vc1_canvas_config[i][0].width = canvas_width; + vc1_canvas_config[i][0].height = canvas_height; + vc1_canvas_config[i][0].block_mode = CANVAS_BLKMODE_32X32; + vc1_canvas_config[i][0].phy_addr = buf_start; + + config_cav_lut_ex(2 * i + 1, buf_start + decbuf_y_size, canvas_width, canvas_height / 2, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_32X32); + CANVAS_BLKMODE_32X32, 0, VDEC_1); + vc1_canvas_config[i][1].endian = 0; + vc1_canvas_config[i][1].width = canvas_width; + vc1_canvas_config[i][1].height = canvas_height >> 1; + vc1_canvas_config[i][1].block_mode = CANVAS_BLKMODE_32X32; + vc1_canvas_config[i][1].phy_addr = buf_start + decbuf_y_size; #else - canvas_config(3 * i + 0, + config_cav_lut_ex(3 * i + 0, buf_start, canvas_width, canvas_height, - CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); - canvas_config(3 * i + 1, + CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32, 0, VDEC_1); + vc1_canvas_config[i][0].endian = 0; + vc1_canvas_config[i][0].width = canvas_width; + vc1_canvas_config[i][0].height = canvas_height; + vc1_canvas_config[i][0].block_mode = CANVAS_BLKMODE_32X32; + vc1_canvas_config[i][0].phy_addr = buf_start; + config_cav_lut_ex(3 * i + 1, buf_start + decbuf_y_size, canvas_width / 2, canvas_height / 2, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_32X32); - canvas_config(3 * i + 2, + CANVAS_BLKMODE_32X32, 0, VDEC_1); + vc1_canvas_config[i][1].endian = 0; + vc1_canvas_config[i][1].width = canvas_width >> 1; + vc1_canvas_config[i][1].height = canvas_height >> 1; + vc1_canvas_config[i][1].block_mode = CANVAS_BLKMODE_32X32; + vc1_canvas_config[i][1].phy_addr = buf_start + decbuf_y_size; + config_cav_lut_ex(3 * i + 2, buf_start + decbuf_y_size + decbuf_uv_size, canvas_width / 2, canvas_height / 2, - CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); + CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32, 0, VDEC_1); + vc1_canvas_config[i][2].endian = 0; + vc1_canvas_config[i][2].width = canvas_width >> 1; + vc1_canvas_config[i][2].height = canvas_height >> 1; + vc1_canvas_config[i][2].block_mode = CANVAS_BLKMODE_32X32; + vc1_canvas_config[i][2].phy_addr = buf_start + + decbuf_y_size + decbuf_uv_size; #endif } @@ -994,6 +1055,8 @@ #ifdef NV21 SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17); #endif + CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 16); + return r; } @@ -1100,11 +1163,8 @@ amvdec_start(); } - -static void vvc1_put_timer_func(unsigned long arg) +static void vvc1_put_timer_func(struct timer_list *timer) { - struct timer_list *timer = (struct timer_list *)arg; - if (READ_VREG(VC1_SOS_COUNT) > 10) schedule_work(&error_wd_work); @@ -1142,7 +1202,7 @@ return -ENOMEM; pr_info("vvc1_init, format %d\n", vvc1_amstream_dec_info.format); - init_timer(&recycle_timer); + timer_setup(&recycle_timer, vvc1_put_timer_func, 0); stat |= STAT_TIMER_INIT; @@ -1216,10 +1276,7 @@ stat |= STAT_VF_HOOK; - recycle_timer.data = (ulong)&recycle_timer; - recycle_timer.function = vvc1_put_timer_func; recycle_timer.expires = jiffies + PUT_INTERVAL; - add_timer(&recycle_timer); stat |= STAT_TIMER_ARM; @@ -1327,32 +1384,16 @@ } /****************************************/ -#ifdef CONFIG_PM -static int vc1_suspend(struct device *dev) -{ - amvdec_suspend(to_platform_device(dev), dev->power.power_state); - return 0; -} - -static int vc1_resume(struct device *dev) -{ - amvdec_resume(to_platform_device(dev)); - return 0; -} - -static const struct dev_pm_ops vc1_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(vc1_suspend, vc1_resume) -}; -#endif static struct platform_driver amvdec_vc1_driver = { .probe = amvdec_vc1_probe, .remove = amvdec_vc1_remove, +#ifdef CONFIG_PM + .suspend = amvdec_suspend, + .resume = amvdec_resume, +#endif .driver = { .name = DRIVER_NAME, -#ifdef CONFIG_PM - .pm = &vc1_pm_ops, -#endif } }; @@ -1377,6 +1418,7 @@ return -ENODEV; } vcodec_profile_register(&amvdec_vc1_profile); + vcodec_feature_register(VFORMAT_VC1, 0); return 0; }
diff --git a/drivers/frame_provider/decoder/vp9/vvp9.c b/drivers/frame_provider/decoder/vp9/vvp9.c index fa75afb..e6a47fd 100644 --- a/drivers/frame_provider/decoder/vp9/vvp9.c +++ b/drivers/frame_provider/decoder/vp9/vvp9.c
@@ -37,14 +37,15 @@ #include <linux/dma-mapping.h> #include <linux/dma-contiguous.h> #include <linux/slab.h> -#include <linux/amlogic/tee.h> +//#include <linux/amlogic/tee.h> +#include <uapi/linux/tee.h> +#include <linux/sched/clock.h> #include "../../../stream_input/amports/amports_priv.h" #include <linux/amlogic/media/codec_mm/codec_mm.h> #include "../utils/decoder_mmu_box.h" #include "../utils/decoder_bmmu_box.h" #define MEM_NAME "codec_vp9" -/* #include <mach/am_regs.h> */ #include <linux/amlogic/media/utils/vdec_reg.h> #include "../utils/vdec.h" #include "../utils/amvdec.h" @@ -59,16 +60,17 @@ #include "../../../common/chips/decoder_cpu_ver_info.h" #include "../utils/vdec_v4l2_buffer_ops.h" #include <media/v4l2-mem2mem.h> +#include "../utils/vdec_feature.h" #define MIX_STREAM_SUPPORT #include "vvp9.h" - +#define VP9_10B_MMU_DW /*#define SUPPORT_FB_DECODING*/ /*#define FB_DECODING_TEST_SCHEDULE*/ - +#define CO_MV_COMPRESS #define HW_MASK_FRONT 0x1 #define HW_MASK_BACK 0x2 @@ -81,11 +83,21 @@ #define HEVCD_MPP_ANC2AXI_TBL_DATA 0x3464 #define HEVC_SAO_MMU_VH1_ADDR 0x363b #define HEVC_SAO_MMU_VH0_ADDR 0x363a - +#define HEVC_SAO_MMU_VH0_ADDR2 0x364d +#define HEVC_SAO_MMU_VH1_ADDR2 0x364e #define HEVC_MV_INFO 0x310d #define HEVC_QP_INFO 0x3137 #define HEVC_SKIP_INFO 0x3136 +#define HEVC_SAO_CTRL9 0x362d +#define HEVC_CM_HEADER_START_ADDR2 0x364a +#define HEVC_SAO_MMU_DMA_CTRL2 0x364c +#define HEVC_SAO_MMU_VH0_ADDR2 0x364d +#define HEVC_SAO_MMU_VH1_ADDR2 0x364e +#define HEVC_SAO_MMU_STATUS2 0x3650 +#define HEVC_DW_VH0_ADDDR 0x365e +#define HEVC_DW_VH1_ADDDR 0x365f + #define VP9_10B_DEC_IDLE 0 #define VP9_10B_DEC_FRAME_HEADER 1 #define VP9_10B_DEC_SLICE_SEGMENT 2 @@ -148,6 +160,7 @@ #ifdef MULTI_INSTANCE_SUPPORT #define MAX_DECODE_INSTANCE_NUM 9 #define MULTI_DRIVER_NAME "ammvdec_vp9" + static unsigned int max_decode_instance_num = MAX_DECODE_INSTANCE_NUM; static unsigned int decode_frame_count[MAX_DECODE_INSTANCE_NUM]; @@ -174,6 +187,7 @@ * 2, (1/4):(1/4) ratio; * 3, (1/4):(1/4) ratio, with both compressed frame included * 4, (1/2):(1/2) ratio; + * 8, (1/8):(1/8) ratio; * 0x10, double write only * 0x100, if > 1080p,use mode 4,else use mode 1; * 0x200, if > 1080p,use mode 2,else use mode 1; @@ -211,7 +225,7 @@ #endif static void vvp9_prot_init(struct VP9Decoder_s *pbi, u32 mask); static int vvp9_local_init(struct VP9Decoder_s *pbi); -static void vvp9_put_timer_func(unsigned long arg); +static void vvp9_put_timer_func(struct timer_list *timer); static void dump_data(struct VP9Decoder_s *pbi, int size); static unsigned char get_data_check_sum (struct VP9Decoder_s *pbi, int size); @@ -223,7 +237,15 @@ int pic_height, unsigned short bit_depth, unsigned int *mmu_index_adr); - +#ifdef VP9_10B_MMU_DW +int vp9_alloc_mmu_dw( + struct VP9Decoder_s *pbi, + int cur_buf_idx, + int pic_width, + int pic_height, + unsigned short bit_depth, + unsigned int *mmu_index_adr); +#endif static const char vvp9_dec_id[] = "vvp9-dev"; @@ -256,6 +278,20 @@ #define MAX_FRAME_8K_NUM 0x4800 #define HEVC_ASSIST_MMU_MAP_ADDR 0x3009 +// bit[31:20] -- fb_read_lcu_y +// READ only// bit[19:8] -- fb_read_lcu_x +// READ only// bit[7] -- fb_read_lcu_latch +// bit[6:5] -- reserved +// bit[4] -- fb_disable_wr_iqit_buf +// bit[3] -- fb_read_avs2_enable +// bit[2] -- fb_read_vp9_enable +// bit[1] -- fb_avs2_enable +// bit[0] -- fb_vp9_enable +#define HEVC_ASSIST_HED_FB_CTL 0x300c +// [31:16] height// [15:0] width +#define HEVC_ASSIST_PIC_SIZE_FB_READ 0x300d +#define HEVC_ASSIST_MMU_MAP_ADDR2 0x300e + #ifdef SUPPORT_FB_DECODING /* register define */ @@ -269,6 +305,7 @@ #define MAX_STAGE_PAGE_NUM 0x1200 #define STAGE_MMU_MAP_SIZE (MAX_STAGE_PAGE_NUM * 4) #endif + static inline int div_r32(int64_t m, int n) { /* @@ -337,11 +374,6 @@ #define DOUBLE_WRITE_YSTART_TEMP 0x02000000 #define DOUBLE_WRITE_CSTART_TEMP 0x02900000 - - -typedef unsigned int u32; -typedef unsigned short u16; - #define VP9_DEBUG_BUFMGR 0x01 #define VP9_DEBUG_BUFMGR_MORE 0x02 #define VP9_DEBUG_BUFMGR_DETAIL 0x04 @@ -401,6 +433,8 @@ static u32 without_display_mode; +static u32 v4l_bitstream_id_enable = 1; + /* *[3:0] 0: default use config from omx. * 1: force enable fence. @@ -441,9 +475,12 @@ //#define MMU_COMPRESS_8K_HEADER_SIZE (MMU_COMPRESS_HEADER_SIZE * 4) #define MMU_COMPRESS_HEADER_SIZE 0x48000 -#define MMU_COMPRESS_8K_HEADER_SIZE (0x48000*4) +#define MMU_COMPRESS_HEADER_SIZE_DW 0x48000 +#define MMU_COMPRESS_8K_HEADER_SIZE (MMU_COMPRESS_HEADER_SIZE * 4) + #define MAX_SIZE_8K (8192 * 4608) #define MAX_SIZE_4K (4096 * 2304) +#define MAX_SIZE_2K (1920 * 1088) #define IS_8K_SIZE(w, h) (((w) * (h)) > MAX_SIZE_4K) #define IS_4K_SIZE(w, h) (((w) * (h)) > (1920*1088)) @@ -547,6 +584,9 @@ int slice_idx; /*buffer*/ unsigned long header_adr; +#ifdef VP9_10B_MMU_DW + unsigned long header_dw_adr; +#endif unsigned long mpred_mv_wr_start_addr; int mv_size; /*unsigned long mc_y_adr; @@ -554,6 +594,8 @@ */ unsigned int dw_y_adr; unsigned int dw_u_v_adr; + u32 luma_size; + u32 chroma_size; int mc_canvas_y; int mc_canvas_u_v; @@ -608,10 +650,9 @@ u32 hw_decode_time; u32 frame_size2; // For frame base mode - bool vframe_bound; /* vdec sync. */ - struct fence *fence; + struct dma_fence *fence; /* hdr10 plus data */ u32 hdr10p_data_size; @@ -707,6 +748,8 @@ */ int row; int col; + + int show_frame; } RefCntBuffer; struct RefBuffer_s { @@ -860,7 +903,6 @@ struct BufferPool_s *buffer_pool; int above_context_alloc_cols; - }; static void set_canvas(struct VP9Decoder_s *pbi, @@ -958,6 +1000,10 @@ struct buff_s seg_map; struct buff_s mmu_vbh; struct buff_s cm_header; +#ifdef VP9_10B_MMU_DW + struct buff_s mmu_vbh_dw; + struct buff_s cm_header_dw; +#endif struct buff_s mpred_above; #ifdef MV_USE_FIXED_BUF struct buff_s mpred_mv; @@ -1017,6 +1063,11 @@ #endif #endif +struct vp9_fence_vf_t { + u32 used_size; + struct vframe_s *fence_vf[VF_POOL_SIZE]; +}; + struct VP9Decoder_s { #ifdef MULTI_INSTANCE_SUPPORT unsigned char index; @@ -1084,7 +1135,10 @@ void *frame_mmu_map_addr; dma_addr_t frame_mmu_map_phy_addr; - +#ifdef VP9_10B_MMU_DW + void *frame_mmu_dw_map_addr; + dma_addr_t frame_mmu_dw_map_phy_addr; +#endif unsigned int use_cma_flag; struct BUF_s m_BUF[MAX_BUF_NUM]; @@ -1101,7 +1155,6 @@ int pic_num; int lcu_size_log2; unsigned int losless_comp_body_size; - u32 video_signal_type; int pts_mode; @@ -1179,6 +1232,10 @@ void *mmu_box; void *bmmu_box; int mmu_enable; +#ifdef VP9_10B_MMU_DW + void *mmu_box_dw; + int dw_mmu_enable; +#endif struct vframe_master_display_colour_s vf_dp; struct firmware_s *fw; int max_pic_w; @@ -1237,18 +1294,24 @@ u64 frame_mode_pts64_save[FRAME_BUFFERS]; int run_ready_min_buf_num; int one_package_frame_cnt; + int buffer_wrap[FRAME_BUFFERS]; + int last_width; + int last_height; u32 error_frame_width; u32 error_frame_height; - char vdec_name[32]; - char pts_name[32]; - char new_q_name[32]; - char disp_q_name[32]; + u32 endian; + ulong fb_token; + struct vp9_fence_vf_t fence_vf_s; + struct mutex fence_mutex; + dma_addr_t rdma_phy_adr; + unsigned *rdma_adr; + struct trace_decoder_name trace; }; static int vp9_print(struct VP9Decoder_s *pbi, int flag, const char *fmt, ...) { -#define HEVC_PRINT_BUF 256 +#define HEVC_PRINT_BUF 512 unsigned char buf[HEVC_PRINT_BUF]; int len = 0; @@ -1272,6 +1335,9 @@ int max = (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1)? MAX_SIZE_8K : MAX_SIZE_4K; + if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5D) + max = MAX_SIZE_2K; + if (w <= 0 || h <= 0) return true; @@ -1281,6 +1347,26 @@ return false; } +static int vvp9_mmu_compress_header_size(int w, int h) +{ + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && + IS_8K_SIZE(w, h)) + return (MMU_COMPRESS_HEADER_SIZE_8K); + if (IS_4K_SIZE(w, h)) + return (MMU_COMPRESS_HEADER_SIZE_4K); + return (MMU_COMPRESS_HEADER_SIZE_1080P); +} + +/*#define FRAME_MMU_MAP_SIZE (MAX_FRAME_4K_NUM * 4)*/ +static int vvp9_frame_mmu_map_size(struct VP9Decoder_s *pbi) +{ + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && + IS_8K_SIZE(pbi->max_pic_w, pbi->max_pic_h)) + return (MAX_FRAME_8K_NUM << 2); + + return (MAX_FRAME_4K_NUM << 2); +} + static int v4l_alloc_and_config_pic(struct VP9Decoder_s *pbi, struct PIC_BUFFER_CONFIG_s *pic); @@ -1293,8 +1379,9 @@ pbi->vp9_first_pts_ready = 0; pbi->duration_from_pts_done = 0; } - pr_info("%s (%d,%d)=>(%d,%d)\r\n", __func__, cm->width, - cm->height, width, height); + pr_info("%s (%d,%d)=>(%d,%d)\r\n", __func__, + cm->width, cm->height, + width, height); cm->width = width; cm->height = height; } @@ -1330,6 +1417,7 @@ struct VP9Decoder_s *pbi, struct VP9_Common_s *cm, union param_u *params, unsigned int *mmu_index_adr, + unsigned int *mmu_dw_index_adr, int print_header_info) { int width, height; struct BufferPool_s * const pool = cm->buffer_pool; @@ -1373,7 +1461,19 @@ } cm->cur_fb_idx_mmu = cm->new_fb_idx; } - +#ifdef VP9_10B_MMU_DW + if (pbi->dw_mmu_enable && (mmu_dw_index_adr != NULL)) { + ret = vp9_alloc_mmu_dw(pbi, cm->new_fb_idx, + params->p.width, params->p.height, + params->p.bit_depth, mmu_dw_index_adr); + if (ret != 0) { + pr_err("can't alloc need mmu1 dw,idx %d ret =%d\n", + cm->new_fb_idx, + ret); + return ret; + } + } +#endif resize_context_buffers(pbi, cm, width, height); setup_display_size(cm, params, print_header_info); #if 0 @@ -1416,6 +1516,7 @@ struct VP9_Common_s *cm, union param_u *params, unsigned int *mmu_index_adr, + unsigned int *mmu_dw_index_adr, int print_header_info) { int width, height; @@ -1501,7 +1602,18 @@ } cm->cur_fb_idx_mmu = cm->new_fb_idx; } - +#ifdef VP9_10B_MMU_DW + if (pbi->dw_mmu_enable && (mmu_dw_index_adr != NULL)) { + ret = vp9_alloc_mmu_dw(pbi, cm->new_fb_idx, + params->p.width, params->p.height, + params->p.bit_depth, mmu_dw_index_adr); + if (ret != 0) { + pr_err("can't alloc need mmu dw,idx %d\r\n", + cm->new_fb_idx); + return ret; + } + } +#endif /*Check to make sure at least one of frames that this frame references *has valid dimensions. */ @@ -1644,46 +1756,19 @@ static u32 get_valid_double_write_mode(struct VP9Decoder_s *pbi) { - return ((double_write_mode & 0x80000000) == 0) ? + u32 dw = ((double_write_mode & 0x80000000) == 0) ? pbi->double_write_mode : (double_write_mode & 0x7fffffff); -} - -static int v4l_parser_get_double_write_mode(struct VP9Decoder_s *pbi) -{ - u32 valid_dw_mode = get_valid_double_write_mode(pbi); - u32 dw; - int w, h; - - /* mask for supporting double write value bigger than 0x100 */ - if (valid_dw_mode & 0xffffff00) { - w = pbi->frame_width; - h = pbi->frame_height; - - dw = 0x1; /*1:1*/ - switch (valid_dw_mode) { - case 0x100: - if (w > 1920 && h > 1088) - dw = 0x4; /*1:2*/ - break; - case 0x200: - if (w > 1920 && h > 1088) - dw = 0x2; /*1:4*/ - break; - case 0x300: - if (w > 1280 && h > 720) - dw = 0x4; /*1:2*/ - break; - default: - break; + if (dw & 0x20) { + if ((get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_T3) + && ((dw & 0xf) == 2 || (dw & 0xf) == 3)) { + pr_info("MMU doueble write 1:4 not supported !!!\n"); + dw = 0; } - return dw; } - - return valid_dw_mode; + return dw; } - static int get_double_write_mode(struct VP9Decoder_s *pbi) { u32 valid_dw_mode = get_valid_double_write_mode(pbi); @@ -1692,6 +1777,14 @@ struct VP9_Common_s *cm = &pbi->common; struct PIC_BUFFER_CONFIG_s *cur_pic_config; + if (pbi->is_used_v4l) { + unsigned int out; + + vdec_v4l_get_dw_mode(pbi->v4l2_ctx, &out); + dw = out; + return dw; + } + /* mask for supporting double write value bigger than 0x100 */ if (valid_dw_mode & 0xffffff00) { if (!cm->cur_frame) @@ -1753,19 +1846,52 @@ } #endif -static int get_double_write_ratio(struct VP9Decoder_s *pbi, - int dw_mode) +//#define MAX_4K_NUM 0x1200 + +/* return page number */ +static int vp9_mmu_page_num(struct VP9Decoder_s *pbi, + int w, int h, int save_mode) { - int ratio = 1; - if ((dw_mode == 2) || - (dw_mode == 3)) - ratio = 4; - else if (dw_mode == 4) - ratio = 2; - return ratio; + int picture_size; + int cur_mmu_4k_number, max_frame_num; + + picture_size = compute_losless_comp_body_size(w, h, save_mode); + cur_mmu_4k_number = ((picture_size + (PAGE_SIZE - 1)) >> PAGE_SHIFT); + + max_frame_num = (vvp9_frame_mmu_map_size(pbi) >> 2); + + if (cur_mmu_4k_number > max_frame_num) { + pr_err("over max !! cur_mmu_4k_number 0x%x width %d height %d\n", + cur_mmu_4k_number, w, h); + return -1; + } + + return cur_mmu_4k_number; } -//#define MAX_4K_NUM 0x1200 +static struct internal_comp_buf* v4lfb_to_icomp_buf( + struct VP9Decoder_s *pbi, + struct vdec_v4l2_buffer *fb) +{ + struct aml_video_dec_buf *aml_fb = NULL; + struct aml_vcodec_ctx * v4l2_ctx = pbi->v4l2_ctx; + + aml_fb = container_of(fb, struct aml_video_dec_buf, frame_buffer); + return &v4l2_ctx->comp_bufs[aml_fb->internal_index]; +} + +static struct internal_comp_buf* index_to_icomp_buf( + struct VP9Decoder_s *pbi, int index) +{ + struct aml_video_dec_buf *aml_fb = NULL; + struct aml_vcodec_ctx * v4l2_ctx = pbi->v4l2_ctx; + struct vdec_v4l2_buffer *fb = NULL; + + fb = (struct vdec_v4l2_buffer *) + pbi->m_BUF[index].v4l_ref_buf_addr; + aml_fb = container_of(fb, struct aml_video_dec_buf, frame_buffer); + return &v4l2_ctx->comp_bufs[aml_fb->internal_index]; +} int vp9_alloc_mmu( struct VP9Decoder_s *pbi, @@ -1775,42 +1901,90 @@ unsigned short bit_depth, unsigned int *mmu_index_adr) { + int ret; int bit_depth_10 = (bit_depth == VPX_BITS_10); - int picture_size; - int cur_mmu_4k_number, max_frame_num; - if (!pbi->mmu_box) { - pr_err("error no mmu box!\n"); - return -1; - } + int cur_mmu_4k_number; + if (get_double_write_mode(pbi) == 0x10) return 0; + if (bit_depth >= VPX_BITS_12) { pbi->fatal_error = DECODER_FATAL_ERROR_SIZE_OVERFLOW; pr_err("fatal_error, un support bit depth 12!\n\n"); return -1; } - picture_size = compute_losless_comp_body_size(pic_width, pic_height, - bit_depth_10); - cur_mmu_4k_number = ((picture_size + (1 << 12) - 1) >> 12); - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) - max_frame_num = MAX_FRAME_8K_NUM; - else - max_frame_num = MAX_FRAME_4K_NUM; + cur_mmu_4k_number = vp9_mmu_page_num(pbi, + pic_width, + pic_height, + bit_depth_10); + if (cur_mmu_4k_number < 0) + return -1; - if (cur_mmu_4k_number > max_frame_num) { - pr_err("over max !! cur_mmu_4k_number 0x%x width %d height %d\n", - cur_mmu_4k_number, pic_width, pic_height); + if (pbi->is_used_v4l) { + struct internal_comp_buf *ibuf = + index_to_icomp_buf(pbi, cur_buf_idx); + + ret = decoder_mmu_box_alloc_idx( + ibuf->mmu_box, + ibuf->index, + ibuf->frame_buffer_size, + mmu_index_adr); + } else { + ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_START); + ret = decoder_mmu_box_alloc_idx( + pbi->mmu_box, + cur_buf_idx, + cur_mmu_4k_number, + mmu_index_adr); + ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_END); + } + + return ret; +} + +#ifdef VP9_10B_MMU_DW +int vp9_alloc_mmu_dw( + struct VP9Decoder_s *pbi, + int cur_buf_idx, + int pic_width, + int pic_height, + unsigned short bit_depth, + unsigned int *mmu_index_adr) +{ + int ret; + int bit_depth_10 = (bit_depth == VPX_BITS_10); + int cur_mmu_4k_number; + + if (pbi->is_used_v4l) + return -1; + + if (get_double_write_mode(pbi) == 0x10) + return 0; + + if (bit_depth >= VPX_BITS_12) { + pbi->fatal_error = DECODER_FATAL_ERROR_SIZE_OVERFLOW; + pr_err("fatal_error, un support bit depth 12!\n\n"); return -1; } - return decoder_mmu_box_alloc_idx( - pbi->mmu_box, - cur_buf_idx, - cur_mmu_4k_number, - mmu_index_adr); + cur_mmu_4k_number = vp9_mmu_page_num(pbi, + pic_width, + pic_height, + bit_depth_10); + if (cur_mmu_4k_number < 0) + return -1; + + ret = decoder_mmu_box_alloc_idx( + pbi->mmu_box_dw, + cur_buf_idx, + cur_mmu_4k_number, + mmu_index_adr); + + return ret; } +#endif #ifndef MV_USE_FIXED_BUF static void dealloc_mv_bufs(struct VP9Decoder_s *pbi) @@ -1858,7 +2032,7 @@ ret = 0; if (debug) { pr_info( - "MV Buffer %d: start_adr %p size %x\n", + "MV Buffer %d: start_adr %px size %x\n", i, (void *)pbi->m_mv_BUF[i].start_adr, pbi->m_mv_BUF[i].size); @@ -1982,7 +2156,7 @@ pic_config->mv_size = pbi->m_mv_BUF[ret].size; if (debug & VP9_DEBUG_BUFMGR_MORE) pr_info( - "%s => %d (%ld) size 0x%x\n", + "%s => %d (%lx) size 0x%x\n", __func__, ret, pic_config->mpred_mv_wr_start_addr, pic_config->mv_size); @@ -2042,10 +2216,18 @@ struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs; int i; for (i = 0; i < pbi->used_buf_num; ++i) { +#if 0 if ((frame_bufs[i].ref_count == 0) && (frame_bufs[i].buf.index != -1) && (frame_bufs[i].buf.mv_buf_index >= 0) ) +#else + if ((&frame_bufs[i] != cm->prev_frame) && + (frame_bufs[i].buf.index != -1) && + (frame_bufs[i].buf.mv_buf_index >= 0) + ) +#endif + put_mv_buf(pbi, &frame_bufs[i].buf.mv_buf_index); } } @@ -2326,7 +2508,8 @@ for (i = 0; i < pbi->used_buf_num; ++i) { if ((frame_bufs[i].ref_count == 0) && (frame_bufs[i].buf.vf_ref == 0) && - (frame_bufs[i].buf.index != -1) + (frame_bufs[i].buf.index != -1) && + (cm->cur_frame != &frame_bufs[i]) ) break; } @@ -2344,6 +2527,39 @@ return i; } +static void update_hide_frame_timestamp(struct VP9Decoder_s *pbi) +{ + struct RefCntBuffer_s *const frame_bufs = + pbi->common.buffer_pool->frame_bufs; + int i; + + for (i = 0; i < pbi->used_buf_num; ++i) { + if ((!frame_bufs[i].show_frame) && + (!frame_bufs[i].buf.vf_ref) && + (frame_bufs[i].buf.BUF_index != -1)) { + frame_bufs[i].buf.timestamp = pbi->chunk->timestamp; + vp9_print(pbi, VP9_DEBUG_OUT_PTS, + "%s, update %d hide frame ts: %lld\n", + __func__, i, frame_bufs[i].buf.timestamp); + } + } +} + +static int get_free_fb_idx(struct VP9Decoder_s *pbi) +{ + int i; + struct VP9_Common_s *const cm = &pbi->common; + struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs; + + for (i = 0; i < pbi->used_buf_num; ++i) { + if ((frame_bufs[i].ref_count == 0) && + (frame_bufs[i].buf.vf_ref == 0)) + break; + } + + return i; +} + static int v4l_get_free_fb(struct VP9Decoder_s *pbi) { struct VP9_Common_s *const cm = &pbi->common; @@ -2351,8 +2567,9 @@ struct aml_vcodec_ctx * v4l = pbi->v4l2_ctx; struct v4l_buff_pool *pool = &v4l->cap_pool; struct PIC_BUFFER_CONFIG_s *pic = NULL; - int i, idx = INVALID_IDX; + struct PIC_BUFFER_CONFIG_s *free_pic = NULL; ulong flags; + int idx, i; lock_buffer_pool(cm->buffer_pool, flags); @@ -2367,47 +2584,92 @@ (pic->vf_ref == 0) && (pic->index != -1) && pic->cma_alloc_addr) { - idx = i; + free_pic = pic; } break; case V4L_CAP_BUFF_IN_M2M: - pic = &frame_bufs[index].buf; + idx = get_free_fb_idx(pbi); + pic = &frame_bufs[idx].buf; pic->y_crop_width = pbi->frame_width; pic->y_crop_height = pbi->frame_height; + pbi->buffer_wrap[idx] = index; if (!v4l_alloc_and_config_pic(pbi, pic)) { set_canvas(pbi, pic); init_pic_list_hw(pbi); - idx = index; + free_pic = pic; } break; default: - pr_err("v4l buffer state err %d.\n", state); break; } - if (idx != INVALID_IDX) { - frame_bufs[idx].ref_count = 1; + if (free_pic) { + frame_bufs[i].ref_count = 1; break; } } + if (free_pic && pbi->chunk) { + free_pic->timestamp = pbi->chunk->timestamp; + update_hide_frame_timestamp(pbi); + } + unlock_buffer_pool(cm->buffer_pool, flags); - return idx; + if (free_pic) { + struct vdec_v4l2_buffer *fb = + (struct vdec_v4l2_buffer *) + pbi->m_BUF[i].v4l_ref_buf_addr; + + fb->status = FB_ST_DECODER; + } + + if (debug & VP9_DEBUG_OUT_PTS) { + if (free_pic) { + pr_debug("%s, idx: %d, ts: %lld\n", + __func__, free_pic->index, free_pic->timestamp); + } else { + pr_debug("%s, vp9 get free pic null\n", __func__); + } + } + + return free_pic ? free_pic->index : INVALID_IDX; } static int get_free_buf_count(struct VP9Decoder_s *pbi) { struct VP9_Common_s *const cm = &pbi->common; struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs; - int i; - int free_buf_count = 0; - for (i = 0; i < pbi->used_buf_num; ++i) - if ((frame_bufs[i].ref_count == 0) && - (frame_bufs[i].buf.vf_ref == 0) && - (frame_bufs[i].buf.index != -1) - ) - free_buf_count++; + struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(pbi->v4l2_ctx); + int i, free_buf_count = 0; + + if (pbi->is_used_v4l) { + for (i = 0; i < pbi->used_buf_num; ++i) { + if ((frame_bufs[i].ref_count == 0) && + (frame_bufs[i].buf.vf_ref == 0) && + frame_bufs[i].buf.cma_alloc_addr) { + free_buf_count++; + } + } + + if (ctx->cap_pool.dec < pbi->used_buf_num) { + free_buf_count += + v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx); + } + + /* trigger to parse head data. */ + if (!pbi->v4l_params_parsed) { + free_buf_count = pbi->run_ready_min_buf_num; + } + } else { + for (i = 0; i < pbi->used_buf_num; ++i) { + if ((frame_bufs[i].ref_count == 0) && + (frame_bufs[i].buf.vf_ref == 0) && + (frame_bufs[i].buf.index != -1)) + free_buf_count++; + } + } + return free_buf_count; } @@ -2528,9 +2790,11 @@ pbi->ready_for_new_data = 0; - if (pbi->has_keyframe == 0 && - params->p.frame_type != KEY_FRAME){ + if ((pbi->has_keyframe == 0) && + (params->p.frame_type != KEY_FRAME) && + (!params->p.intra_only)){ on_no_keyframe_skiped++; + pr_info("vp9_bufmgr_process no key frame return\n"); return -2; } pbi->has_keyframe = 1; @@ -2631,6 +2895,7 @@ pbi->refresh_frame_flags = 0; /*cm->lf.filter_level = 0;*/ cm->show_frame = 1; + cm->cur_frame->show_frame = 1; /* *if (pbi->frame_parallel_decode) { @@ -2646,7 +2911,7 @@ cm->show_frame = params->p.show_frame; cm->bit_depth = params->p.bit_depth; cm->error_resilient_mode = params->p.error_resilient_mode; - + cm->cur_frame->show_frame = cm->show_frame; if (cm->frame_type == KEY_FRAME) { pbi->refresh_frame_flags = (1 << REF_FRAMES) - 1; @@ -2655,10 +2920,19 @@ cm->frame_refs[i].idx = INVALID_IDX; cm->frame_refs[i].buf = NULL; } - +#ifdef VP9_10B_MMU_DW ret = setup_frame_size(pbi, - cm, params, pbi->frame_mmu_map_addr, - print_header_info); + cm, params, + pbi->frame_mmu_map_addr, + pbi->frame_mmu_dw_map_addr, + print_header_info); +#else + ret = setup_frame_size(pbi, + cm, params, + pbi->frame_mmu_map_addr, + NULL, + print_header_info); +#endif if (ret) return -1; if (pbi->need_resync) { @@ -2717,11 +2991,21 @@ * pr_info("*%d-bits refresh_frame read:0x%x\n", * REF_FRAMES, pbi->refresh_frame_flags); */ +#ifdef VP9_10B_MMU_DW ret = setup_frame_size(pbi, cm, params, pbi->frame_mmu_map_addr, + pbi->frame_mmu_dw_map_addr, print_header_info); +#else + ret = setup_frame_size(pbi, + cm, + params, + pbi->frame_mmu_map_addr, + NULL, + print_header_info); +#endif if (ret) return -1; if (pbi->need_resync) { @@ -2767,13 +3051,23 @@ */ } - +#ifdef VP9_10B_MMU_DW ret = setup_frame_size_with_refs( pbi, cm, params, pbi->frame_mmu_map_addr, + pbi->frame_mmu_dw_map_addr, print_header_info); +#else + ret = setup_frame_size_with_refs( + pbi, + cm, + params, + pbi->frame_mmu_map_addr, + NULL, + print_header_info); +#endif if (ret) return -1; for (i = 0; i < REFS_PER_FRAME; ++i) { @@ -2841,11 +3135,11 @@ struct vdec_s *vdec = hw_to_vdec(pbi); /* create fence for each buffers. */ - ret = vdec_timeline_create_fence(&vdec->sync); + ret = vdec_timeline_create_fence(vdec->sync); if (ret < 0) return ret; - pic->fence = vdec->sync.fence; + pic->fence = vdec->sync->fence; pic->bit_depth = cm->bit_depth; pic->slice_type = cm->frame_type; pic->stream_offset = pbi->pre_stream_offset; @@ -3007,6 +3301,9 @@ } cm->last_width = cm->width; cm->last_height = cm->height; + pbi->last_width = cm->width; + pbi->last_height = cm->height; + if (cm->show_frame) cm->current_video_frame++; @@ -3015,8 +3312,32 @@ sd.stream_offset = pbi->pre_stream_offset; if (pbi->enable_fence) { + int i, j, used_size, ret; + int signed_count = 0; + struct vframe_s *signed_fence[VF_POOL_SIZE]; /* notify signal to wake up wq of fence. */ - vdec_timeline_increase(&vdec->sync, 1); + vdec_timeline_increase(vdec->sync, 1); + mutex_lock(&pbi->fence_mutex); + used_size = pbi->fence_vf_s.used_size; + if (used_size) { + for (i = 0, j = 0; i < VF_POOL_SIZE && j < used_size; i++) { + if (pbi->fence_vf_s.fence_vf[i] != NULL) { + ret = dma_fence_get_status(pbi->fence_vf_s.fence_vf[i]->fence); + if (ret == 1) { + signed_fence[signed_count] = pbi->fence_vf_s.fence_vf[i]; + pbi->fence_vf_s.fence_vf[i] = NULL; + pbi->fence_vf_s.used_size--; + signed_count++; + } + j++; + } + } + } + mutex_unlock(&pbi->fence_mutex); + if (signed_count != 0) { + for (i = 0; i < signed_count; i++) + vvp9_vf_put(signed_fence[i], vdec); + } } else { prepare_display_buf(pbi, &sd); } @@ -3045,6 +3366,9 @@ #define HEVC_CM_HEADER_LENGTH 0x3629 #define HEVC_CM_HEADER_OFFSET 0x362b +#define HEVC_CM_BODY_LENGTH2 0x3663 +#define HEVC_CM_HEADER_OFFSET2 0x3664 +#define HEVC_CM_HEADER_LENGTH2 0x3665 #define LOSLESS_COMPRESS_MODE /*#define DECOMP_HEADR_SURGENT*/ @@ -3066,7 +3390,15 @@ static u32 pop_shorts; static u32 dbg_cmd; static u32 dbg_skip_decode_index; -static u32 endian = 0xff0; + +/* + * bit 0~3, for HEVCD_IPP_AXIIF_CONFIG endian config + * bit 8~23, for HEVC_SAO_CTRL1 endian config + */ +static u32 endian; +#define HEVC_CONFIG_BIG_ENDIAN ((0x880 << 8) | 0x8) +#define HEVC_CONFIG_LITTLE_ENDIAN ((0xff0 << 8) | 0xf) + #ifdef ERROR_HANDLE_DEBUG static u32 dbg_nal_skip_flag; /* bit[0], skip vps; bit[1], skip sps; bit[2], skip pps */ @@ -3076,18 +3408,10 @@ static u32 decode_pic_begin; static uint slice_parse_begin; static u32 step; -#ifdef MIX_STREAM_SUPPORT -static u32 buf_alloc_width = 4096; -static u32 buf_alloc_height = 2304; -static u32 vp9_max_pic_w = 4096; -static u32 vp9_max_pic_h = 2304; - +static u32 vp9_max_pic_w; +static u32 vp9_max_pic_h; static u32 dynamic_buf_num_margin; -#else -static u32 buf_alloc_width; -static u32 buf_alloc_height; -static u32 dynamic_buf_num_margin = 7; -#endif + static u32 buf_alloc_depth = 10; static u32 buf_alloc_size; /* @@ -3233,7 +3557,10 @@ #define DW_VBH_BUF_SIZE_8K (VBH_BUF_SIZE_8K * 2) #define DW_VBH_BUF_SIZE(bufspec) (bufspec->mmu_vbh_dw.buf_size / 4) -#define WORK_BUF_SPEC_NUM 3 +/* necessary 4K page size align for t7/t3 decoder and after */ +#define WORKBUF_ALIGN(addr) (ALIGN(addr, PAGE_SIZE)) + +#define WORK_BUF_SPEC_NUM 6 static struct BuffInfo_s amvvp9_workbuff_spec[WORK_BUF_SPEC_NUM] = { { /* 8M bytes */ @@ -3243,6 +3570,292 @@ /* IPP work space calculation : * 4096 * (Y+CbCr+Flags) = 12k, round to 16k */ + .buf_size = 0x4000, + }, + .sao_abv = { + .buf_size = 0x30000, + }, + .sao_vb = { + .buf_size = 0x30000, + }, + .short_term_rps = { + /* SHORT_TERM_RPS - Max 64 set, 16 entry every set, + * total 64x16x2 = 2048 bytes (0x800) + */ + .buf_size = 0x800, + }, + .vps = { + /* VPS STORE AREA - Max 16 VPS, each has 0x80 bytes, + * total 0x0800 bytes + */ + .buf_size = 0x800, + }, + .sps = { + /* SPS STORE AREA - Max 16 SPS, each has 0x80 bytes, + * total 0x0800 bytes + */ + .buf_size = 0x800, + }, + .pps = { + /* PPS STORE AREA - Max 64 PPS, each has 0x80 bytes, + * total 0x2000 bytes + */ + .buf_size = 0x2000, + }, + .sao_up = { + /* SAO UP STORE AREA - Max 640(10240/16) LCU, + * each has 16 bytes total 0x2800 bytes + */ + .buf_size = 0x2800, + }, + .swap_buf = { + /* 256cyclex64bit = 2K bytes 0x800 + * (only 144 cycles valid) + */ + .buf_size = 0x800, + }, + .swap_buf2 = { + .buf_size = 0x800, + }, + .scalelut = { + /* support up to 32 SCALELUT 1024x32 = + * 32Kbytes (0x8000) + */ + .buf_size = 0x8000, + }, + .dblk_para = { + /* DBLK -> Max 256(4096/16) LCU, + *each para 1024bytes(total:0x40000), + *data 1024bytes(total:0x40000) + */ + .buf_size = 0x80000, + }, + .dblk_data = { + .buf_size = 0x80000, + }, + .seg_map = { + /*4096x2304/64/64 *24 = 0xd800 Bytes*/ + .buf_size = 0xd800, + }, + .mmu_vbh = { + .buf_size = 0x5000, /*2*16*(more than 2304)/4, 4K*/ + }, +#if 0 + .cm_header = { + /*add one for keeper.*/ + .buf_size = MMU_COMPRESS_HEADER_SIZE * + (FRAME_BUFFERS + 1), + /* 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) */ + }, +#endif + .mpred_above = { + .buf_size = 0x10000, /* 2 * size of hevc*/ + }, +#ifdef MV_USE_FIXED_BUF + .mpred_mv = {/* 1080p, 0x40000 per buffer */ + .buf_size = 0x40000 * FRAME_BUFFERS, + }, +#endif + .rpm = { + .buf_size = RPM_BUF_SIZE, + }, + .lmem = { + .buf_size = 0x400 * 2, + } + }, + { + .max_width = 4096, + .max_height = 2304, + .ipp = { + /* IPP work space calculation : + * 4096 * (Y+CbCr+Flags) = 12k, round to 16k + */ + .buf_size = 0x4000, + }, + .sao_abv = { + .buf_size = 0x30000, + }, + .sao_vb = { + .buf_size = 0x30000, + }, + .short_term_rps = { + /* SHORT_TERM_RPS - Max 64 set, 16 entry every set, + * total 64x16x2 = 2048 bytes (0x800) + */ + .buf_size = 0x800, + }, + .vps = { + /* VPS STORE AREA - Max 16 VPS, each has 0x80 bytes, + * total 0x0800 bytes + */ + .buf_size = 0x800, + }, + .sps = { + /* SPS STORE AREA - Max 16 SPS, each has 0x80 bytes, + * total 0x0800 bytes + */ + .buf_size = 0x800, + }, + .pps = { + /* PPS STORE AREA - Max 64 PPS, each has 0x80 bytes, + * total 0x2000 bytes + */ + .buf_size = 0x2000, + }, + .sao_up = { + /* SAO UP STORE AREA - Max 640(10240/16) LCU, + * each has 16 bytes total 0x2800 bytes + */ + .buf_size = 0x2800, + }, + .swap_buf = { + /* 256cyclex64bit = 2K bytes 0x800 + * (only 144 cycles valid) + */ + .buf_size = 0x800, + }, + .swap_buf2 = { + .buf_size = 0x800, + }, + .scalelut = { + /* support up to 32 SCALELUT 1024x32 = 32Kbytes + * (0x8000) + */ + .buf_size = 0x8000, + }, + .dblk_para = { + /* DBLK -> Max 256(4096/16) LCU, + *each para 1024bytes(total:0x40000), + *data 1024bytes(total:0x40000) + */ + .buf_size = 0x80000, + }, + .dblk_data = { + .buf_size = 0x80000, + }, + .seg_map = { + /*4096x2304/64/64 *24 = 0xd800 Bytes*/ + .buf_size = 0xd800, + }, + .mmu_vbh = { + .buf_size = 0x5000,/*2*16*(more than 2304)/4, 4K*/ + }, +#if 0 + .cm_header = { + /*add one for keeper.*/ + .buf_size = MMU_COMPRESS_HEADER_SIZE * + (FRAME_BUFFERS + 1), + /* 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) */ + }, +#endif + .mpred_above = { + .buf_size = 0x10000, /* 2 * size of hevc*/ + }, +#ifdef MV_USE_FIXED_BUF + .mpred_mv = { + /* .buf_size = 0x100000*16, + * //4k2k , 0x100000 per buffer + */ + /* 4096x2304 , 0x120000 per buffer */ + .buf_size = 0x120000 * FRAME_BUFFERS, + }, +#endif + .rpm = { + .buf_size = RPM_BUF_SIZE, + }, + .lmem = { + .buf_size = 0x400 * 2, + } + }, + { + .max_width = 4096*2, + .max_height = 2304*2, + .ipp = { + // IPP work space calculation : 4096 * (Y+CbCr+Flags) = 12k, round to 16k + .buf_size = 0x4000*2, + }, + .sao_abv = { + .buf_size = 0x30000*2, + }, + .sao_vb = { + .buf_size = 0x30000*2, + }, + .short_term_rps = { + // SHORT_TERM_RPS - Max 64 set, 16 entry every set, total 64x16x2 = 2048 bytes (0x800) + .buf_size = 0x800, + }, + .vps = { + // VPS STORE AREA - Max 16 VPS, each has 0x80 bytes, total 0x0800 bytes + .buf_size = 0x800, + }, + .sps = { + // SPS STORE AREA - Max 16 SPS, each has 0x80 bytes, total 0x0800 bytes + .buf_size = 0x800, + }, + .pps = { + // PPS STORE AREA - Max 64 PPS, each has 0x80 bytes, total 0x2000 bytes + .buf_size = 0x2000, + }, + .sao_up = { + // SAO UP STORE AREA - Max 640(10240/16) LCU, each has 16 bytes total 0x2800 bytes + .buf_size = 0x2800*2, + }, + .swap_buf = { + // 256cyclex64bit = 2K bytes 0x800 (only 144 cycles valid) + .buf_size = 0x800, + }, + .swap_buf2 = { + .buf_size = 0x800, + }, + .scalelut = { + // support up to 32 SCALELUT 1024x32 = 32Kbytes (0x8000) + .buf_size = 0x8000*2, + }, + .dblk_para = { + // DBLK -> Max 256(4096/16) LCU, each para 1024bytes(total:0x40000), data 1024bytes(total:0x40000) + .buf_size = 0x80000*2, + }, + .dblk_data = { + .buf_size = 0x80000*2, + }, + .seg_map = { + /*4096x2304/64/64 *24 = 0xd800 Bytes*/ + .buf_size = 0xd800*4, + }, + .mmu_vbh = { + .buf_size = 0x5000*2, //2*16*(more than 2304)/4, 4K + }, +#if 0 + .cm_header = { + //.buf_size = MMU_COMPRESS_HEADER_SIZE*8, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) + .buf_size = MMU_COMPRESS_HEADER_SIZE*16, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) + }, +#endif + .mpred_above = { + .buf_size = 0x10000*2, /* 2 * size of hevc*/ + }, +#ifdef MV_USE_FIXED_BUF + .mpred_mv = { + //4k2k , 0x100000 per buffer */ + /* 4096x2304 , 0x120000 per buffer */ + .buf_size = 0x120000 * FRAME_BUFFERS * 4, + }, +#endif + .rpm = { + .buf_size = RPM_BUF_SIZE, + }, + .lmem = { + .buf_size = 0x400 * 2, + } + }, + { + /* 8M bytes */ + .max_width = 1920, + .max_height = 1088, + .ipp = { + /* IPP work space calculation : + * 4096 * (Y+CbCr+Flags) = 12k, round to 16k + */ .buf_size = 0x1e00, }, .sao_abv = { @@ -3321,6 +3934,16 @@ /* 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) */ }, #endif +#ifdef VP9_10B_MMU_DW + .mmu_vbh_dw = { + .buf_size = DW_VBH_BUF_SIZE_1080P, //VBH_BUF_SIZE * VBH_BUF_COUNT, //2*16*(more than 2304)/4, 4K + }, +#if 0 + .cm_header_dw = { + .buf_size = MMU_COMPRESS_HEADER_SIZE_DW * 16, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) + }, +#endif +#endif .mpred_above = { .buf_size = 0x2200, //0x21c0, /* 2 * size of hevc*/ }, @@ -3421,6 +4044,16 @@ /* 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) */ }, #endif +#ifdef VP9_10B_MMU_DW + .mmu_vbh_dw = { + .buf_size = DW_VBH_BUF_SIZE_4K, //VBH_BUF_SIZE * VBH_BUF_COUNT, //2*16*(more than 2304)/4, 4K + }, +#if 0 + .cm_header_dw = { + .buf_size = MMU_COMPRESS_HEADER_SIZE_DW * 16, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) + }, +#endif +#endif .mpred_above = { .buf_size = 0x4800, /* 2 * size of hevc*/ }, @@ -3504,6 +4137,16 @@ .buf_size = MMU_COMPRESS_HEADER_SIZE*16, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) }, #endif +#ifdef VP9_10B_MMU_DW + .mmu_vbh_dw = { + .buf_size = DW_VBH_BUF_SIZE_8K, //VBH_BUF_SIZE * VBH_BUF_COUNT, //2*16*(more than 2304)/4, 4K + }, +#if 0 + .cm_header_dw = { + .buf_size = MMU_COMPRESS_HEADER_SIZE_DW * 16, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) + }, +#endif +#endif .mpred_above = { .buf_size = 0x9000, }, @@ -3525,7 +4168,7 @@ /*Losless compression body buffer size 4K per 64x32 (jt)*/ -int compute_losless_comp_body_size(int width, int height, +static int compute_losless_comp_body_size(int width, int height, uint8_t is_bit_depth_10) { int width_x64; @@ -3546,7 +4189,7 @@ } /* Losless compression header buffer size 32bytes per 128x64 (jt)*/ -static int compute_losless_comp_header_size(int width, int height) +static int compute_losless_comp_header_size(int width, int height) { int width_x128; int height_x64; @@ -3571,66 +4214,69 @@ { void *mem_start_virt; - buf_spec->ipp.buf_start = buf_spec->start_adr; + buf_spec->ipp.buf_start = + WORKBUF_ALIGN(buf_spec->start_adr); buf_spec->sao_abv.buf_start = - buf_spec->ipp.buf_start + buf_spec->ipp.buf_size; - + WORKBUF_ALIGN(buf_spec->ipp.buf_start + buf_spec->ipp.buf_size); buf_spec->sao_vb.buf_start = - buf_spec->sao_abv.buf_start + buf_spec->sao_abv.buf_size; + WORKBUF_ALIGN(buf_spec->sao_abv.buf_start + buf_spec->sao_abv.buf_size); buf_spec->short_term_rps.buf_start = - buf_spec->sao_vb.buf_start + buf_spec->sao_vb.buf_size; + WORKBUF_ALIGN(buf_spec->sao_vb.buf_start + buf_spec->sao_vb.buf_size); buf_spec->vps.buf_start = - buf_spec->short_term_rps.buf_start + - buf_spec->short_term_rps.buf_size; + WORKBUF_ALIGN(buf_spec->short_term_rps.buf_start + buf_spec->short_term_rps.buf_size); buf_spec->sps.buf_start = - buf_spec->vps.buf_start + buf_spec->vps.buf_size; + WORKBUF_ALIGN(buf_spec->vps.buf_start + buf_spec->vps.buf_size); buf_spec->pps.buf_start = - buf_spec->sps.buf_start + buf_spec->sps.buf_size; + WORKBUF_ALIGN(buf_spec->sps.buf_start + buf_spec->sps.buf_size); buf_spec->sao_up.buf_start = - buf_spec->pps.buf_start + buf_spec->pps.buf_size; + WORKBUF_ALIGN(buf_spec->pps.buf_start + buf_spec->pps.buf_size); buf_spec->swap_buf.buf_start = - buf_spec->sao_up.buf_start + buf_spec->sao_up.buf_size; + WORKBUF_ALIGN(buf_spec->sao_up.buf_start + buf_spec->sao_up.buf_size); buf_spec->swap_buf2.buf_start = - buf_spec->swap_buf.buf_start + buf_spec->swap_buf.buf_size; + WORKBUF_ALIGN(buf_spec->swap_buf.buf_start + buf_spec->swap_buf.buf_size); buf_spec->scalelut.buf_start = - buf_spec->swap_buf2.buf_start + buf_spec->swap_buf2.buf_size; + WORKBUF_ALIGN(buf_spec->swap_buf2.buf_start + buf_spec->swap_buf2.buf_size); buf_spec->dblk_para.buf_start = - buf_spec->scalelut.buf_start + buf_spec->scalelut.buf_size; + WORKBUF_ALIGN(buf_spec->scalelut.buf_start + buf_spec->scalelut.buf_size); buf_spec->dblk_data.buf_start = - buf_spec->dblk_para.buf_start + buf_spec->dblk_para.buf_size; + WORKBUF_ALIGN(buf_spec->dblk_para.buf_start + buf_spec->dblk_para.buf_size); buf_spec->seg_map.buf_start = - buf_spec->dblk_data.buf_start + buf_spec->dblk_data.buf_size; + WORKBUF_ALIGN(buf_spec->dblk_data.buf_start + buf_spec->dblk_data.buf_size); if (pbi == NULL || pbi->mmu_enable) { buf_spec->mmu_vbh.buf_start = - buf_spec->seg_map.buf_start + - buf_spec->seg_map.buf_size; + WORKBUF_ALIGN(buf_spec->seg_map.buf_start + buf_spec->seg_map.buf_size); +#ifdef VP9_10B_MMU_DW + if (pbi == NULL || pbi->dw_mmu_enable) { + buf_spec->mmu_vbh_dw.buf_start = + WORKBUF_ALIGN(buf_spec->mmu_vbh.buf_start + buf_spec->mmu_vbh.buf_size); + buf_spec->mpred_above.buf_start = + WORKBUF_ALIGN(buf_spec->mmu_vbh_dw.buf_start + buf_spec->mmu_vbh_dw.buf_size); + } else { + buf_spec->mpred_above.buf_start = + WORKBUF_ALIGN(buf_spec->mmu_vbh.buf_start + buf_spec->mmu_vbh.buf_size); + } +#else buf_spec->mpred_above.buf_start = - buf_spec->mmu_vbh.buf_start + - buf_spec->mmu_vbh.buf_size; + WORKBUF_ALIGN(buf_spec->mmu_vbh.buf_start + buf_spec->mmu_vbh.buf_size); +#endif } else { buf_spec->mpred_above.buf_start = - buf_spec->seg_map.buf_start + buf_spec->seg_map.buf_size; + WORKBUF_ALIGN(buf_spec->seg_map.buf_start + buf_spec->seg_map.buf_size); } #ifdef MV_USE_FIXED_BUF buf_spec->mpred_mv.buf_start = - buf_spec->mpred_above.buf_start + - buf_spec->mpred_above.buf_size; + WORKBUF_ALIGN(buf_spec->mpred_above.buf_start + buf_spec->mpred_above.buf_size); buf_spec->rpm.buf_start = - buf_spec->mpred_mv.buf_start + - buf_spec->mpred_mv.buf_size; + WORKBUF_ALIGN(buf_spec->mpred_mv.buf_start + buf_spec->mpred_mv.buf_size); #else buf_spec->rpm.buf_start = - buf_spec->mpred_above.buf_start + - buf_spec->mpred_above.buf_size; - + WORKBUF_ALIGN(buf_spec->mpred_above.buf_start + buf_spec->mpred_above.buf_size); #endif buf_spec->lmem.buf_start = - buf_spec->rpm.buf_start + - buf_spec->rpm.buf_size; + WORKBUF_ALIGN(buf_spec->rpm.buf_start + buf_spec->rpm.buf_size); buf_spec->end_adr = - buf_spec->lmem.buf_start + - buf_spec->lmem.buf_size; + WORKBUF_ALIGN(buf_spec->lmem.buf_start + buf_spec->lmem.buf_size); if (!pbi) return; @@ -3701,6 +4347,16 @@ if (pbi->mmu_enable) { pr_info("mmu_vbh.buf_start :%x\n", buf_spec->mmu_vbh.buf_start); +#ifdef VP9_10B_MMU_DW + if (pbi->dw_mmu_enable) { + pr_info("mmu_vbh_dw.buf_start :%x", + buf_spec->mmu_vbh_dw.buf_start); +#if 0 + pr_info("cm_header_dw.buf_start :%x", + buf_spec->mmu_vbh_dw.buf_start); +#endif + } +#endif } pr_info("mpred_above.buf_start :%x\n", buf_spec->mpred_above.buf_start); @@ -4898,71 +5554,25 @@ } -static bool v4l_is_there_vframe_bound(struct VP9Decoder_s *pbi) -{ - int i; - struct VP9_Common_s *const cm = &pbi->common; - struct RefCntBuffer_s *frame_bufs = cm->buffer_pool->frame_bufs; - - for (i = 0; i < pbi->used_buf_num; ++i) { - if (frame_bufs[i].buf.vframe_bound) - return true; - } - - return false; -} - -static void v4l_mmu_buffer_release(struct VP9Decoder_s *pbi) -{ - struct VP9_Common_s *const cm = &pbi->common; - struct RefCntBuffer_s *frame_bufs = cm->buffer_pool->frame_bufs; - int i; - - /* release workspace */ - if (pbi->bmmu_box) - decoder_bmmu_box_free_idx(pbi->bmmu_box, - WORK_SPACE_BUF_ID); - /* - * it's only when vframe get back to driver, right now we can be sure - * that vframe and fd are related. if the playback exits, the capture - * requires the upper app to release when the fd is closed, and others - * buffers drivers are released by driver. - */ - for (i = 0; i < pbi->used_buf_num; ++i) { - if (!frame_bufs[i].buf.vframe_bound) { - if (pbi->bmmu_box) - decoder_bmmu_box_free_idx(pbi->bmmu_box, - HEADER_BUFFER_IDX(i)); - if (pbi->mmu_box) - decoder_mmu_box_free_idx(pbi->mmu_box, i); - - vp9_print(pbi, PRINT_FLAG_V4L_DETAIL, - "%s free buffer[%d], bmmu_box: %p, mmu_box: %p\n", - __func__, i, pbi->bmmu_box, pbi->mmu_box); - } - } -} - static void uninit_mmu_buffers(struct VP9Decoder_s *pbi) { #ifndef MV_USE_FIXED_BUF dealloc_mv_bufs(pbi); #endif - if (pbi->is_used_v4l && - v4l_is_there_vframe_bound(pbi)) { - if (get_double_write_mode(pbi) != 0x10) { - v4l_mmu_buffer_release(pbi); - return; - } - } - - if (pbi->mmu_box) + if (pbi->mmu_box) { decoder_mmu_box_free(pbi->mmu_box); - pbi->mmu_box = NULL; - - if (pbi->bmmu_box) + pbi->mmu_box = NULL; + } +#ifdef VP9_10B_MMU_DW + if (pbi->mmu_box_dw) { + decoder_mmu_box_free(pbi->mmu_box_dw); + pbi->mmu_box_dw = NULL; + } +#endif + if (pbi->bmmu_box) { decoder_bmmu_box_free(pbi->bmmu_box); - pbi->bmmu_box = NULL; + pbi->bmmu_box = NULL; + } } static int calc_luc_quantity(u32 w, u32 h) @@ -4978,6 +5588,22 @@ return pic_width_lcu * pic_height_lcu; } +/* return in MB */ +static int vp9_max_mmu_buf_size(int max_w, int max_h) +{ + int buf_size = 48; + + if ((max_w * max_h > 1280*736) && + (max_w * max_h <= 1920*1088)) { + buf_size = 12; + } else if ((max_w * max_h > 0) && + (max_w * max_h <= 1280*736)) { + buf_size = 4; + } + + return buf_size; +} + static int v4l_alloc_and_config_pic(struct VP9Decoder_s *pbi, struct PIC_BUFFER_CONFIG_s *pic) { @@ -4990,21 +5616,25 @@ pbi->work_space_buf->mpred_mv.buf_size; int mv_size = cal_mv_buf_size(pbi, pbi->frame_width, pbi->frame_height); #endif + struct aml_vcodec_ctx * ctx = (struct aml_vcodec_ctx *)pbi->v4l2_ctx; struct vdec_v4l2_buffer *fb = NULL; if (i < 0) return ret; - ret = vdec_v4l_get_buffer(pbi->v4l2_ctx, &fb); + ret = ctx->fb_ops.alloc(&ctx->fb_ops, pbi->fb_token, &fb, AML_FB_REQ_DEC); if (ret < 0) { vp9_print(pbi, 0, "[%d] VP9 get buffer fail.\n", ((struct aml_vcodec_ctx *) (pbi->v4l2_ctx))->id); return ret; } + fb->status = FB_ST_DECODER; + if (pbi->mmu_enable) { - pbi->m_BUF[i].header_addr = decoder_bmmu_box_get_phy_addr( - pbi->bmmu_box, HEADER_BUFFER_IDX(i)); + struct internal_comp_buf *ibuf = v4lfb_to_icomp_buf(pbi, fb); + + pbi->m_BUF[i].header_addr = ibuf->header_addr; if (debug & VP9_DEBUG_BUFMGR_MORE) { pr_info("MMU header_adr %d: %ld\n", i, pbi->m_BUF[i].header_addr); @@ -5025,6 +5655,8 @@ fb->m.mem[0].bytes_used = fb->m.mem[0].size; pic->dw_y_adr = pbi->m_BUF[i].start_adr; pic->dw_u_v_adr = pic->dw_y_adr + pbi->m_BUF[i].luma_size; + pic->luma_size = fb->m.mem[0].offset; + pic->chroma_size = fb->m.mem[0].size - fb->m.mem[0].offset; } else if (fb->num_planes == 2) { pbi->m_BUF[i].start_adr = fb->m.mem[0].addr; pbi->m_BUF[i].size = fb->m.mem[0].size; @@ -5034,6 +5666,8 @@ fb->m.mem[1].bytes_used = fb->m.mem[1].size; pic->dw_y_adr = pbi->m_BUF[i].start_adr; pic->dw_u_v_adr = pbi->m_BUF[i].chroma_addr; + pic->luma_size = fb->m.mem[0].size; + pic->chroma_size = fb->m.mem[1].size; } /* config frame buffer */ @@ -5110,14 +5744,15 @@ int mc_buffer_size_u_v = 0; int mc_buffer_size_u_v_h = 0; int dw_mode = get_double_write_mode_init(pbi); + struct vdec_s *vdec = hw_to_vdec(pbi); pbi->lcu_total = lcu_total; - if (dw_mode) { + if (dw_mode && (dw_mode & 0x20) == 0) { int pic_width_dw = pic_width / - get_double_write_ratio(pbi, dw_mode); + get_double_write_ratio(dw_mode & 0xf); int pic_height_dw = pic_height / - get_double_write_ratio(pbi, dw_mode); + get_double_write_ratio(dw_mode & 0xf); int pic_width_64_dw = (pic_width_dw + 63) & (~0x3f); int pic_height_32_dw = (pic_height_dw + 31) & (~0x1f); @@ -5148,8 +5783,19 @@ pr_info("MMU header_adr %d: %ld\n", pic_config->index, pic_config->header_adr); } - } +#ifdef VP9_10B_MMU_DW + if (pbi->dw_mmu_enable) { + pic_config->header_dw_adr = pic_config->header_adr + + vvp9_mmu_compress_header_size(pbi->init_pic_w, pbi->init_pic_h); + if (debug & VP9_DEBUG_BUFMGR_MORE) { + pr_info("MMU header_dw_adr %d: %ld size 0x%x\n", + pic_config->index, pic_config->header_dw_adr, + vvp9_mmu_compress_header_size(pbi->init_pic_w, pbi->init_pic_h)); + } + } +#endif + } i = pic_config->index; #ifdef MV_USE_FIXED_BUF if ((pbi->work_space_buf->mpred_mv.buf_start + @@ -5171,6 +5817,13 @@ return ret; } + if (pbi->enable_fence) { + //mm->fence_ref_release = vdec_fence_buffer_count_decrease; + vdec_fence_buffer_count_increase((ulong)vdec->sync); + INIT_LIST_HEAD(&vdec->sync->release_callback[VF_BUFFER_IDX(i)].node); + decoder_bmmu_box_add_callback_func(pbi->bmmu_box, VF_BUFFER_IDX(i), (void *)&vdec->sync->release_callback[VF_BUFFER_IDX(i)]); + } + if (pic_config->cma_alloc_addr) y_adr = pic_config->cma_alloc_addr; else { @@ -5202,7 +5855,7 @@ (pic_config->index << 1); pic_config->mc_canvas_u_v = (pic_config->index << 1) + 1; - } else if (dw_mode) { + } else if (dw_mode && ((dw_mode & 0x20) == 0)) { pic_config->dw_y_adr = y_adr; pic_config->dw_u_v_adr = pic_config->dw_y_adr + ((mc_buffer_size_u_v_h << 16) << 1); @@ -5237,24 +5890,6 @@ return ret; } -static int vvp9_mmu_compress_header_size(struct VP9Decoder_s *pbi) -{ - if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && - IS_8K_SIZE(pbi->max_pic_w, pbi->max_pic_h)) - return (MMU_COMPRESS_8K_HEADER_SIZE); - - return (MMU_COMPRESS_HEADER_SIZE); -} - -/*#define FRAME_MMU_MAP_SIZE (MAX_FRAME_4K_NUM * 4)*/ -static int vvp9_frame_mmu_map_size(struct VP9Decoder_s *pbi) -{ - if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && - IS_8K_SIZE(pbi->max_pic_w, pbi->max_pic_h)) - return (MAX_FRAME_8K_NUM * 4); - - return (MAX_FRAME_4K_NUM * 4); -} static void init_pic_list(struct VP9Decoder_s *pbi) { @@ -5264,8 +5899,13 @@ u32 header_size; struct vdec_s *vdec = hw_to_vdec(pbi); - if (pbi->mmu_enable && ((pbi->double_write_mode & 0x10) == 0)) { - header_size = vvp9_mmu_compress_header_size(pbi); + if (!pbi->is_used_v4l && pbi->mmu_enable && ((pbi->double_write_mode & 0x10) == 0)) { + header_size = vvp9_mmu_compress_header_size( + pbi->max_pic_w, pbi->max_pic_h); +#ifdef VP9_10B_MMU_DW + if (pbi->dw_mmu_enable) + header_size <<= 1; +#endif /*alloc VP9 compress header first*/ for (i = 0; i < pbi->used_buf_num; i++) { unsigned long buf_addr; @@ -5279,6 +5919,12 @@ pbi->fatal_error |= DECODER_FATAL_ERROR_NO_MEM; return; } + if (pbi->enable_fence) { + vdec_fence_buffer_count_increase((ulong)vdec->sync); + INIT_LIST_HEAD(&vdec->sync->release_callback[HEADER_BUFFER_IDX(i)].node); + decoder_bmmu_box_add_callback_func(pbi->bmmu_box, HEADER_BUFFER_IDX(i), (void *)&vdec->sync->release_callback[HEADER_BUFFER_IDX(i)]); + //mm->fence_ref_release = vdec_fence_buffer_count_decrease; + } } } for (i = 0; i < pbi->used_buf_num; i++) { @@ -5303,7 +5949,8 @@ break; } - if (pic_config->double_write_mode) { + if (pic_config->double_write_mode && + (pic_config->double_write_mode & 0x20) == 0) { set_canvas(pbi, pic_config); } } @@ -5331,14 +5978,12 @@ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, (0x1 << 1) | (0x1 << 2)); - for (i = 0; i < pbi->used_buf_num; i++) { pic_config = &cm->buffer_pool->frame_bufs[i].buf; if (pic_config->index < 0) break; if (pbi->mmu_enable && ((pic_config->double_write_mode & 0x10) == 0)) { - WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA, pic_config->header_adr >> 5); } else { @@ -5372,7 +6017,6 @@ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); } - static void dump_pic_list(struct VP9Decoder_s *pbi) { struct VP9_Common_s *const cm = &pbi->common; @@ -5381,7 +6025,7 @@ for (i = 0; i < FRAME_BUFFERS; i++) { pic_config = &cm->buffer_pool->frame_bufs[i].buf; vp9_print(pbi, 0, - "Buf(%d) index %d mv_buf_index %d ref_count %d vf_ref %d dec_idx %d slice_type %d w/h %d/%d adr%ld\n", + "Buf(%d) index %d mv_buf_index %d ref_count %d vf_ref %d dec_idx %d slice_type %d w/h %d/%d adr: %x\n", i, pic_config->index, #ifndef MV_USE_FIXED_BUF @@ -5452,6 +6096,14 @@ #else WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31); #endif +#ifdef VP9_10B_MMU_DW + if (pbi->dw_mmu_enable) { + /*losless_comp_header_size_dw same as losless_comp_header_size*/ + WRITE_VREG(HEVC_CM_BODY_LENGTH2, losless_comp_body_size); + WRITE_VREG(HEVC_CM_HEADER_OFFSET2, losless_comp_body_size); + WRITE_VREG(HEVC_CM_HEADER_LENGTH2, losless_comp_header_size); + } +#endif return 0; } @@ -5596,26 +6248,45 @@ (mc_buffer_size_u_v + 0xffff) >> 16;/*64k alignment*/ struct aml_vcodec_ctx * v4l2_ctx = pbi->v4l2_ctx; - if (get_double_write_mode(pbi)) { + if (get_double_write_mode(pbi) && + (get_double_write_mode(pbi) & 0x20) == 0) { WRITE_VREG(HEVC_SAO_Y_START_ADDR, pic_config->dw_y_adr); WRITE_VREG(HEVC_SAO_C_START_ADDR, pic_config->dw_u_v_adr); WRITE_VREG(HEVC_SAO_Y_WPTR, pic_config->dw_y_adr); WRITE_VREG(HEVC_SAO_C_WPTR, pic_config->dw_u_v_adr); } else { - WRITE_VREG(HEVC_SAO_Y_START_ADDR, 0xffffffff); - WRITE_VREG(HEVC_SAO_C_START_ADDR, 0xffffffff); + if (!pbi->dw_mmu_enable) { + WRITE_VREG(HEVC_SAO_Y_START_ADDR, 0xffffffff); + WRITE_VREG(HEVC_SAO_C_START_ADDR, 0xffffffff); + } } if (pbi->mmu_enable) WRITE_VREG(HEVC_CM_HEADER_START_ADDR, pic_config->header_adr); - data32 = (mc_buffer_size_u_v_h << 16) << 1; - /*pr_info("data32=%x,mc_buffer_size_u_v_h=%x,lcu_total=%x\n", - * data32, mc_buffer_size_u_v_h, pic_config->lcu_total); - */ - WRITE_VREG(HEVC_SAO_Y_LENGTH, data32); + if (pbi->is_used_v4l) { + WRITE_VREG(HEVC_SAO_Y_LENGTH, pic_config->luma_size); + WRITE_VREG(HEVC_SAO_C_LENGTH, pic_config->chroma_size); + if (debug & PRINT_FLAG_V4L_DETAIL) { + pr_info("[%d] config pic, id: %d, Y:(%x, %d) C:(%x, %d).\n", + v4l2_ctx->id, pic_config->index, + pic_config->dw_y_adr, pic_config->luma_size, + pic_config->dw_u_v_adr, pic_config->chroma_size); + } + } else { +#ifdef VP9_10B_MMU_DW + if (pbi->dw_mmu_enable) { + WRITE_VREG(HEVC_CM_HEADER_START_ADDR2, pic_config->header_dw_adr); + } +#endif + data32 = (mc_buffer_size_u_v_h << 16) << 1; + /*pr_info("data32=%x,mc_buffer_size_u_v_h=%x,lcu_total=%x\n", + data32, mc_buffer_size_u_v_h, pic_config->lcu_total);*/ - data32 = (mc_buffer_size_u_v_h << 16); - WRITE_VREG(HEVC_SAO_C_LENGTH, data32); + WRITE_VREG(HEVC_SAO_Y_LENGTH, data32); + + data32 = (mc_buffer_size_u_v_h << 16); + WRITE_VREG(HEVC_SAO_C_LENGTH, data32); + } #ifdef VP9_10B_NV21 #ifdef DOS_PROJECT @@ -5668,17 +6339,21 @@ #endif #else data32 = READ_VREG(HEVC_SAO_CTRL1); - data32 &= (~0x3000); - data32 |= (pbi->mem_map_mode << - 12); + data32 &= (~(3 << 14)); + data32 |= (2 << 14); /* line align with 64*/ -/* [13:12] axi_aformat, 0-Linear, - * 1-32x32, 2-64x32 - */ + data32 &= (~0x3000); + /* [13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32 */ + data32 |= (pbi->mem_map_mode << 12); + data32 &= (~0xff0); - /* data32 |= 0x670; // Big-Endian per 64-bit */ - data32 |= endian; /* Big-Endian per 64-bit */ - data32 &= (~0x3); /*[1]:dw_disable [0]:cm_disable*/ +#ifdef VP9_10B_MMU_DW + if (pbi->dw_mmu_enable == 0) + data32 |= ((pbi->endian >> 8) & 0xfff); /* Big-Endian per 64-bit */ +#else + data32 |= ((pbi->endian >> 8) & 0xfff); +#endif + data32 &= (~0x3); /*[1]:dw_disable [0]:cm_disable*/ if (get_double_write_mode(pbi) == 0) data32 |= 0x2; /*disable double write*/ else if (get_double_write_mode(pbi) & 0x10) @@ -5730,24 +6405,29 @@ data32 &= ~(0xff << 16); WRITE_VREG(HEVC_SAO_CTRL5, data32); } else { + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T7) + WRITE_VREG(HEVC_SAO_CTRL26, 0); + data32 = READ_VREG(HEVC_SAO_CTRL5); data32 &= (~(0xff << 16)); - if (get_double_write_mode(pbi) == 2 || - get_double_write_mode(pbi) == 3) - data32 |= (0xff<<16); - else if (get_double_write_mode(pbi) == 4) - data32 |= (0x33<<16); + if ((get_double_write_mode(pbi) & 0xf) == 8 || + (get_double_write_mode(pbi) & 0xf) == 9) { + data32 |= (0xff << 16); + WRITE_VREG(HEVC_SAO_CTRL26, 0xf); + } else if ((get_double_write_mode(pbi) & 0xf) == 2 || + (get_double_write_mode(pbi) & 0xf) == 3) + data32 |= (0xff << 16); + else if ((get_double_write_mode(pbi) & 0xf) == 4) + data32 |= (0x33 << 16); WRITE_VREG(HEVC_SAO_CTRL5, data32); } data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG); data32 &= (~0x30); /* [5:4] -- address_format 00:linear 01:32x32 10:64x32 */ - data32 |= (pbi->mem_map_mode << - 4); - data32 &= (~0xF); - data32 |= 0xf; /* valid only when double write only */ - /*data32 |= 0x8;*/ /* Big-Endian per 64-bit */ + data32 |= (pbi->mem_map_mode << 4); + data32 &= (~0xf); + data32 |= (pbi->endian & 0xf); /* valid only when double write only */ /* swap uv */ if (pbi->is_used_v4l) { @@ -5757,7 +6437,8 @@ else data32 &= ~(1 << 12); /* NV12 */ } - + data32 &= (~(3 << 8)); + data32 |= (2 << 8); /* line align with 64 for dw only */ /* * [3:0] little_endian * [5:4] address_format 00:linear 01:32x32 10:64x32 @@ -5774,7 +6455,7 @@ static void vp9_config_work_space_hw(struct VP9Decoder_s *pbi, u32 mask) { struct BuffInfo_s *buf_spec = pbi->work_space_buf; - unsigned int data32; + unsigned int data32, data_tmp; int losless_comp_header_size, losless_comp_body_size; if (debug && pbi->init_flag == 0) @@ -5812,29 +6493,32 @@ } - if (mask & HW_MASK_BACK) { + if ((mask & HW_MASK_BACK) == 0) + return; + #ifdef LOSLESS_COMPRESS_MODE - losless_comp_header_size = - compute_losless_comp_header_size(pbi->init_pic_w, - pbi->init_pic_h); - losless_comp_body_size = - compute_losless_comp_body_size(pbi->init_pic_w, - pbi->init_pic_h, buf_alloc_depth == 10); + losless_comp_header_size = + compute_losless_comp_header_size(pbi->init_pic_w, + pbi->init_pic_h); + losless_comp_body_size = + compute_losless_comp_body_size(pbi->init_pic_w, + pbi->init_pic_h, buf_alloc_depth == 10); #endif - WRITE_VREG(HEVCD_IPP_LINEBUFF_BASE, - buf_spec->ipp.buf_start); - //WRITE_VREG(HEVC_SAO_UP, buf_spec->sao_up.buf_start); - //WRITE_VREG(HEVC_SCALELUT, buf_spec->scalelut.buf_start); - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { - /* cfg_addr_adp*/ - WRITE_VREG(HEVC_DBLK_CFGE, buf_spec->dblk_para.buf_start); - if (debug & VP9_DEBUG_BUFMGR_MORE) - pr_info("Write HEVC_DBLK_CFGE\n"); - } - /* cfg_p_addr */ - WRITE_VREG(HEVC_DBLK_CFG4, buf_spec->dblk_para.buf_start); - /* cfg_d_addr */ - WRITE_VREG(HEVC_DBLK_CFG5, buf_spec->dblk_data.buf_start); + WRITE_VREG(HEVCD_IPP_LINEBUFF_BASE, + buf_spec->ipp.buf_start); + //WRITE_VREG(HEVC_SAO_UP, buf_spec->sao_up.buf_start); + //WRITE_VREG(HEVC_SCALELUT, buf_spec->scalelut.buf_start); + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { + /* cfg_addr_adp*/ + WRITE_VREG(HEVC_DBLK_CFGE, buf_spec->dblk_para.buf_start); + if (debug & VP9_DEBUG_BUFMGR_MORE) + pr_info("Write HEVC_DBLK_CFGE\n"); + } + /* cfg_p_addr */ + WRITE_VREG(HEVC_DBLK_CFG4, buf_spec->dblk_para.buf_start); + + /* cfg_d_addr */ + WRITE_VREG(HEVC_DBLK_CFG5, buf_spec->dblk_data.buf_start); if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) { /* @@ -5874,6 +6558,7 @@ WRITE_VREG(HEVC_CM_BODY_LENGTH, losless_comp_body_size); WRITE_VREG(HEVC_CM_HEADER_OFFSET, losless_comp_body_size); WRITE_VREG(HEVC_CM_HEADER_LENGTH, losless_comp_header_size); + if (get_double_write_mode(pbi) & 0x10) WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31); #else @@ -5893,20 +6578,76 @@ data32 |= (1<<10); WRITE_VREG(HEVC_SAO_CTRL5, data32); } +#ifdef VP9_10B_MMU_DW + if (pbi->dw_mmu_enable) { + data_tmp = READ_VREG(HEVC_SAO_CTRL9); + data_tmp |= (1<<10); + WRITE_VREG(HEVC_SAO_CTRL9, data_tmp); - WRITE_VREG(VP9_SEG_MAP_BUFFER, buf_spec->seg_map.buf_start); + WRITE_VREG(HEVC_CM_BODY_LENGTH2, losless_comp_body_size); + WRITE_VREG(HEVC_CM_HEADER_OFFSET2, losless_comp_body_size); + WRITE_VREG(HEVC_CM_HEADER_LENGTH2, losless_comp_header_size); + + WRITE_VREG(HEVC_SAO_MMU_VH0_ADDR2, buf_spec->mmu_vbh_dw.buf_start); + WRITE_VREG(HEVC_SAO_MMU_VH1_ADDR2, buf_spec->mmu_vbh_dw.buf_start + + DW_VBH_BUF_SIZE(buf_spec)); + + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T5D) { + if (get_double_write_mode(pbi) & 0x20) { + WRITE_VREG(HEVC_DW_VH0_ADDDR, + buf_spec->mmu_vbh_dw.buf_start + DW_VBH_BUF_SIZE(buf_spec) * 2); + WRITE_VREG(HEVC_DW_VH1_ADDDR, + buf_spec->mmu_vbh_dw.buf_start + DW_VBH_BUF_SIZE(buf_spec) * 3); + } + } + data32 = READ_VREG(HEVC_SAO_CTRL5); + /* use HEVC_CM_HEADER_START_ADDR */ + data32 |= (1<<15); + WRITE_VREG(HEVC_SAO_CTRL5, data32); + } +#endif + + /* config mpred axi burst threshold */ + WRITE_VREG(HEVC_MPRED_CTRL3, 0x24122412); + +#ifdef CO_MV_COMPRESS + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T7) { + data32 = READ_VREG(HEVC_MPRED_CTRL4); + data32 |= (1 << 1); + WRITE_VREG(HEVC_MPRED_CTRL4, data32); + } +#endif + + WRITE_VREG(VP9_SEG_MAP_BUFFER, buf_spec->seg_map.buf_start); WRITE_VREG(LMEM_DUMP_ADR, (u32)pbi->lmem_phy_addr); - /**/ - WRITE_VREG(VP9_PROB_SWAP_BUFFER, pbi->prob_buffer_phy_addr); - WRITE_VREG(VP9_COUNT_SWAP_BUFFER, pbi->count_buffer_phy_addr); - if (pbi->mmu_enable) { - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) - WRITE_VREG(HEVC_ASSIST_MMU_MAP_ADDR, pbi->frame_mmu_map_phy_addr); - else - WRITE_VREG(VP9_MMU_MAP_BUFFER, pbi->frame_mmu_map_phy_addr); - } + + WRITE_VREG(VP9_PROB_SWAP_BUFFER, pbi->prob_buffer_phy_addr); + WRITE_VREG(VP9_COUNT_SWAP_BUFFER, pbi->count_buffer_phy_addr); + if (pbi->mmu_enable) { + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) + WRITE_VREG(HEVC_ASSIST_MMU_MAP_ADDR, pbi->frame_mmu_map_phy_addr); + else + WRITE_VREG(VP9_MMU_MAP_BUFFER, pbi->frame_mmu_map_phy_addr); } +#ifdef VP9_10B_MMU_DW + if (pbi->dw_mmu_enable) { + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T5D) { + WRITE_VREG(HEVC_SAO_MMU_DMA_CTRL2, pbi->frame_mmu_dw_map_phy_addr); + //WRITE_VREG(HEVC_ASSIST_MMU_MAP_ADDR2, pbi->frame_mmu_dw_map_phy_addr); + } else { + WRITE_VREG(HEVC_ASSIST_MMU_MAP_ADDR2, pbi->frame_mmu_dw_map_phy_addr); + } + WRITE_VREG(HEVC_SAO_Y_START_ADDR, 0); + WRITE_VREG(HEVC_SAO_C_START_ADDR, 0); +#ifdef VP9_10B_HED_FB + WRITE_VREG(HEVC_ASSIST_FB_MMU_MAP_ADDR2, FB_FRAME_MMU_MAP_ADDR); + #ifdef VP9_10B_HED_SAME_FB + WRITE_VREG(HEVC_ASSIST_FBD_MMU_MAP_ADDR2, FB_FRAME_MMU_MAP_ADDR); + #endif +#endif + } +#endif } @@ -6277,10 +7018,13 @@ if (mask & HW_MASK_BACK) { /*Initial IQIT_SCALELUT memory -- just to avoid X in simulation*/ - - WRITE_VREG(HEVC_IQIT_SCALELUT_WR_ADDR, 0);/*cfg_p_addr*/ - for (i = 0; i < 1024; i++) - WRITE_VREG(HEVC_IQIT_SCALELUT_DATA, 0); + if (is_rdma_enable()) + rdma_back_end_work(pbi->rdma_phy_adr, RDMA_SIZE); + else { + WRITE_VREG(HEVC_IQIT_SCALELUT_WR_ADDR, 0);/*cfg_p_addr*/ + for (i = 0; i < 1024; i++) + WRITE_VREG(HEVC_IQIT_SCALELUT_DATA, 0); + } } if (mask & HW_MASK_FRONT) { @@ -6668,21 +7412,30 @@ pbi->lmem_phy_addr); pbi->lmem_addr = NULL; } - if (pbi->prob_buffer_addr) { - if (pbi->prob_buffer_phy_addr) - dma_free_coherent(amports_get_dma_device(), - PROB_BUF_SIZE, pbi->prob_buffer_addr, - pbi->prob_buffer_phy_addr); - + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) && + (vdec_secure(hw_to_vdec(pbi)))) { + tee_vp9_prob_free((u32)pbi->prob_buffer_phy_addr); + pbi->prob_buffer_phy_addr = 0; + pbi->count_buffer_phy_addr = 0; pbi->prob_buffer_addr = NULL; - } - if (pbi->count_buffer_addr) { - if (pbi->count_buffer_phy_addr) - dma_free_coherent(amports_get_dma_device(), - COUNT_BUF_SIZE, pbi->count_buffer_addr, - pbi->count_buffer_phy_addr); - pbi->count_buffer_addr = NULL; + } else { + if (pbi->prob_buffer_addr) { + if (pbi->prob_buffer_phy_addr) + dma_free_coherent(amports_get_dma_device(), + PROB_BUF_SIZE, pbi->prob_buffer_addr, + pbi->prob_buffer_phy_addr); + + pbi->prob_buffer_addr = NULL; + } + if (pbi->count_buffer_addr) { + if (pbi->count_buffer_phy_addr) + dma_free_coherent(amports_get_dma_device(), + COUNT_BUF_SIZE, pbi->count_buffer_addr, + pbi->count_buffer_phy_addr); + + pbi->count_buffer_addr = NULL; + } } if (pbi->mmu_enable) { u32 mmu_map_size = vvp9_frame_mmu_map_size(pbi); @@ -6695,6 +7448,21 @@ pbi->frame_mmu_map_addr = NULL; } } + +#ifdef VP9_10B_MMU_DW + if (pbi->dw_mmu_enable) { + u32 dw_mmu_map_size = vvp9_frame_mmu_map_size(pbi); + if (pbi->frame_mmu_dw_map_addr) { + if (pbi->frame_mmu_dw_map_phy_addr) + dma_free_coherent(amports_get_dma_device(), + dw_mmu_map_size, + pbi->frame_mmu_dw_map_addr, + pbi->frame_mmu_dw_map_phy_addr); + pbi->frame_mmu_dw_map_addr = NULL; + } + } +#endif + #ifdef SUPPORT_FB_DECODING if (pbi->stage_mmu_map_addr) { if (pbi->stage_mmu_map_phy_addr) @@ -6731,58 +7499,41 @@ memcpy(cur_buf_info, &amvvp9_workbuff_spec[force_bufspec & 0xf], sizeof(struct BuffInfo_s)); pr_info("force buffer spec %d\n", force_bufspec & 0xf); - } else if (vdec_is_support_4k()) { - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) { - memcpy(cur_buf_info, &amvvp9_workbuff_spec[2], /* 8k */ - sizeof(struct BuffInfo_s)); - } else - memcpy(cur_buf_info, &amvvp9_workbuff_spec[1], /* 4k */ - sizeof(struct BuffInfo_s)); - } else - memcpy(cur_buf_info, &amvvp9_workbuff_spec[0],/* 1080p */ - sizeof(struct BuffInfo_s)); + } else { + if (get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_TM2 && !is_cpu_tm2_revb()) { + if (vdec_is_support_4k()) { + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) { + memcpy(cur_buf_info, &amvvp9_workbuff_spec[2], /* 8k */ + sizeof(struct BuffInfo_s)); + } else + memcpy(cur_buf_info, &amvvp9_workbuff_spec[1], /* 4k */ + sizeof(struct BuffInfo_s)); + } else + memcpy(cur_buf_info, &amvvp9_workbuff_spec[0],/* 1080p */ + sizeof(struct BuffInfo_s)); + } else { //get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_TM2 || is_cpu_tm2_revb() + if (vdec_is_support_4k()) { + memcpy(cur_buf_info, &amvvp9_workbuff_spec[5], /* 8k */ + sizeof(struct BuffInfo_s)); + } else + memcpy(cur_buf_info, &amvvp9_workbuff_spec[3],/* 1080p */ + sizeof(struct BuffInfo_s)); + } + } cur_buf_info->start_adr = pbi->buf_start; if (!pbi->mmu_enable) pbi->mc_buf_spec.buf_end = pbi->buf_start + pbi->buf_size; - -#else -/*! MULTI_INSTANCE_SUPPORT*/ - if (vdec_is_support_4k()) { - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) - cur_buf_info = &amvvp9_workbuff_spec[2];/* 8k work space */ - else - cur_buf_info = &amvvp9_workbuff_spec[1];/* 4k2k work space */ - } else - cur_buf_info = &amvvp9_workbuff_spec[0];/* 1080p work space */ - #endif init_buff_spec(pbi, cur_buf_info); vp9_bufmgr_init(pbi, cur_buf_info, NULL); - if (!vdec_is_support_4k() - && (buf_alloc_width > 1920 && buf_alloc_height > 1088)) { - buf_alloc_width = 1920; - buf_alloc_height = 1088; - if (pbi->max_pic_w > 1920 && pbi->max_pic_h > 1088) { - pbi->max_pic_w = 1920; - pbi->max_pic_h = 1088; - } - } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) { - buf_alloc_width = 8192; - buf_alloc_height = 4608; - } - pbi->init_pic_w = pbi->max_pic_w ? pbi->max_pic_w : - (buf_alloc_width ? buf_alloc_width : - (pbi->vvp9_amstream_dec_info.width ? - pbi->vvp9_amstream_dec_info.width : - pbi->work_space_buf->max_width)); - pbi->init_pic_h = pbi->max_pic_h ? pbi->max_pic_h : - (buf_alloc_height ? buf_alloc_height : - (pbi->vvp9_amstream_dec_info.height ? - pbi->vvp9_amstream_dec_info.height : - pbi->work_space_buf->max_height)); + /* vp9_max_pic_w/h for debug */ + pbi->init_pic_w = (vp9_max_pic_w) ? vp9_max_pic_w: + ((pbi->max_pic_w) ? pbi->max_pic_w : pbi->work_space_buf->max_width); + pbi->init_pic_h = (vp9_max_pic_h) ? vp9_max_pic_h: + ((pbi->max_pic_h) ? pbi->max_pic_h : pbi->work_space_buf->max_height); /* video is not support unaligned with 64 in tl1 ** vdec canvas mode will be linear when dump yuv is set @@ -6801,9 +7552,11 @@ } #ifndef MV_USE_FIXED_BUF - if (init_mv_buf_list(pbi) < 0) { - pr_err("%s: init_mv_buf_list fail\n", __func__); - return -1; + if (!pbi->is_used_v4l) { + if (init_mv_buf_list(pbi) < 0) { + pr_err("%s: init_mv_buf_list fail\n", __func__); + return -1; + } } #endif if (pbi->save_buffer_mode) @@ -6842,24 +7595,38 @@ pr_err("%s: failed to alloc lmem buffer\n", __func__); return -1; } - pbi->lmem_ptr = pbi->lmem_addr; + pbi->lmem_ptr = pbi->lmem_addr; - pbi->prob_buffer_addr = dma_alloc_coherent(amports_get_dma_device(), - PROB_BUF_SIZE, - &pbi->prob_buffer_phy_addr, GFP_KERNEL); - if (pbi->prob_buffer_addr == NULL) { - pr_err("%s: failed to alloc prob_buffer\n", __func__); - return -1; + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) && + (vdec_secure(hw_to_vdec(pbi)))) { + u32 prob_addr, id; + id = tee_vp9_prob_malloc(&prob_addr); + if (prob_addr <= 0) + pr_err("%s, tee[%d] malloc prob buf failed\n", __func__, id); + else { + pbi->prob_buffer_phy_addr = prob_addr; + pbi->count_buffer_phy_addr = pbi->prob_buffer_phy_addr + PROB_BUF_SIZE; + } + pbi->prob_buffer_addr = NULL; + pbi->count_buffer_addr = NULL; + } else { + pbi->prob_buffer_addr = dma_alloc_coherent(amports_get_dma_device(), + PROB_BUF_SIZE, + &pbi->prob_buffer_phy_addr, GFP_KERNEL); + if (pbi->prob_buffer_addr == NULL) { + pr_err("%s: failed to alloc prob_buffer\n", __func__); + return -1; + } + memset(pbi->prob_buffer_addr, 0, PROB_BUF_SIZE); + pbi->count_buffer_addr = dma_alloc_coherent(amports_get_dma_device(), + COUNT_BUF_SIZE, + &pbi->count_buffer_phy_addr, GFP_KERNEL); + if (pbi->count_buffer_addr == NULL) { + pr_err("%s: failed to alloc count_buffer\n", __func__); + return -1; + } + memset(pbi->count_buffer_addr, 0, COUNT_BUF_SIZE); } - memset(pbi->prob_buffer_addr, 0, PROB_BUF_SIZE); - pbi->count_buffer_addr = dma_alloc_coherent(amports_get_dma_device(), - COUNT_BUF_SIZE, - &pbi->count_buffer_phy_addr, GFP_KERNEL); - if (pbi->count_buffer_addr == NULL) { - pr_err("%s: failed to alloc count_buffer\n", __func__); - return -1; - } - memset(pbi->count_buffer_addr, 0, COUNT_BUF_SIZE); if (pbi->mmu_enable) { u32 mmu_map_size = vvp9_frame_mmu_map_size(pbi); @@ -6873,6 +7640,20 @@ } memset(pbi->frame_mmu_map_addr, 0, COUNT_BUF_SIZE); } +#ifdef VP9_10B_MMU_DW + if (pbi->dw_mmu_enable) { + u32 dw_mmu_map_size = vvp9_frame_mmu_map_size(pbi); + pbi->frame_mmu_dw_map_addr = + dma_alloc_coherent(amports_get_dma_device(), + dw_mmu_map_size, + &pbi->frame_mmu_dw_map_phy_addr, GFP_KERNEL); + if (pbi->frame_mmu_dw_map_addr == NULL) { + pr_err("%s: failed to alloc count_buffer mmu dw\n", __func__); + return -1; + } + memset(pbi->frame_mmu_dw_map_addr, 0, COUNT_BUF_SIZE); + } +#endif #ifdef SUPPORT_FB_DECODING if (pbi->m_ins_flag && stage_buf_num > 0) { pbi->stage_mmu_map_addr = @@ -6925,16 +7706,14 @@ /*CANVAS_BLKMODE_64X32*/ if (pic_config->double_write_mode) { canvas_w = pic_config->y_crop_width / - get_double_write_ratio(pbi, - pic_config->double_write_mode); + get_double_write_ratio( + pic_config->double_write_mode & 0xf); canvas_h = pic_config->y_crop_height / - get_double_write_ratio(pbi, - pic_config->double_write_mode); + get_double_write_ratio( + pic_config->double_write_mode & 0xf); - if (pbi->mem_map_mode == 0) - canvas_w = ALIGN(canvas_w, 32); - else - canvas_w = ALIGN(canvas_w, 64); + /* sao ctrl1 reg alignline with 64, align with 64 */ + canvas_w = ALIGN(canvas_w, 64); canvas_h = ALIGN(canvas_h, 32); if (vdec->parallel_dec == 1) { @@ -6949,12 +7728,12 @@ pic_config->uv_canvas_index = 128 + pic_config->index * 2 + 1; } - canvas_config_ex(pic_config->y_canvas_index, + config_cav_lut_ex(pic_config->y_canvas_index, pic_config->dw_y_adr, canvas_w, canvas_h, - CANVAS_ADDR_NOWRAP, blkmode, pbi->is_used_v4l ? 0 : 7); - canvas_config_ex(pic_config->uv_canvas_index, + CANVAS_ADDR_NOWRAP, blkmode, pbi->is_used_v4l ? 0 : 7, VDEC_HEVC); + config_cav_lut_ex(pic_config->uv_canvas_index, pic_config->dw_u_v_adr, canvas_w, canvas_h, - CANVAS_ADDR_NOWRAP, blkmode, pbi->is_used_v4l ? 0 : 7); + CANVAS_ADDR_NOWRAP, blkmode, pbi->is_used_v4l ? 0 : 7, VDEC_HEVC); #ifdef MULTI_INSTANCE_SUPPORT pic_config->canvas_config[0].phy_addr = @@ -7004,37 +7783,42 @@ memset(&hdr, 0, sizeof(hdr)); hdr.signal_type = vf->signal_type; hdr.color_parms = pbi->vf_dp; + + hdr.color_parms.luminance[0] = hdr.color_parms.luminance[0] / 10000; + vdec_v4l_set_hdr_infos(ctx, &hdr); } if ((pbi->chunk != NULL) && (pbi->chunk->hdr10p_data_buf != NULL) && (pbi->chunk->hdr10p_data_size != 0)) { - char *new_buf; - int i = 0; - new_buf = vzalloc(pbi->chunk->hdr10p_data_size); + if (pbi->chunk->hdr10p_data_size <= 128) { + char *new_buf; + int i = 0; + new_buf = kzalloc(pbi->chunk->hdr10p_data_size, GFP_ATOMIC); - if (new_buf) { - memcpy(new_buf, pbi->chunk->hdr10p_data_buf, pbi->chunk->hdr10p_data_size); - if (debug & VP9_DEBUG_BUFMGR_MORE) { - vp9_print(pbi, VP9_DEBUG_BUFMGR_MORE, - "hdr10p data: (size %d)\n", - pbi->chunk->hdr10p_data_size); - for (i = 0; i < pbi->chunk->hdr10p_data_size; i++) { + if (new_buf) { + memcpy(new_buf, pbi->chunk->hdr10p_data_buf, pbi->chunk->hdr10p_data_size); + if (debug & VP9_DEBUG_BUFMGR_MORE) { vp9_print(pbi, VP9_DEBUG_BUFMGR_MORE, - "%02x ", pbi->chunk->hdr10p_data_buf[i]); - if (((i + 1) & 0xf) == 0) - vp9_print(pbi, VP9_DEBUG_BUFMGR_MORE, "\n"); + "hdr10p data: (size %d)\n", + pbi->chunk->hdr10p_data_size); + for (i = 0; i < pbi->chunk->hdr10p_data_size; i++) { + vp9_print(pbi, VP9_DEBUG_BUFMGR_MORE, + "%02x ", pbi->chunk->hdr10p_data_buf[i]); + if (((i + 1) & 0xf) == 0) + vp9_print(pbi, VP9_DEBUG_BUFMGR_MORE, "\n"); + } + vp9_print(pbi, VP9_DEBUG_BUFMGR_MORE, "\n"); } - vp9_print(pbi, VP9_DEBUG_BUFMGR_MORE, "\n"); - } - vf->hdr10p_data_size = pbi->chunk->hdr10p_data_size; - vf->hdr10p_data_buf = new_buf; - } else { - vp9_print(pbi, 0, "%s:hdr10p data vzalloc size(%d) fail\n", - __func__, pbi->chunk->hdr10p_data_size); - vf->hdr10p_data_size = pbi->chunk->hdr10p_data_size; - vf->hdr10p_data_buf = new_buf; + vf->hdr10p_data_size = pbi->chunk->hdr10p_data_size; + vf->hdr10p_data_buf = new_buf; + } else { + vp9_print(pbi, 0, "%s:hdr10p data vzalloc size(%d) fail\n", + __func__, pbi->chunk->hdr10p_data_size); + vf->hdr10p_data_size = pbi->chunk->hdr10p_data_size; + vf->hdr10p_data_buf = new_buf; + } } vfree(pbi->chunk->hdr10p_data_buf); @@ -7099,17 +7883,18 @@ if (kfifo_get(&pbi->display_q, &vf)) { struct vframe_s *next_vf = NULL; uint8_t index = vf->index & 0xff; - ATRACE_COUNTER(pbi->disp_q_name, kfifo_len(&pbi->display_q)); + ATRACE_COUNTER(pbi->trace.disp_q_name, kfifo_len(&pbi->display_q)); if (index < pbi->used_buf_num || (vf->type & VIDTYPE_V4L_EOS)) { vf->index_disp = pbi->vf_get_count; pbi->vf_get_count++; if (debug & VP9_DEBUG_BUFMGR) - pr_info("%s type 0x%x w/h %d/%d, pts %d, %lld\n", - __func__, vf->type, + pr_info("%s idx: %d, type 0x%x w/h %d/%d, pts %d, %lld, ts: %lld\n", + __func__, index, vf->type, vf->width, vf->height, vf->pts, - vf->pts_us64); + vf->pts_us64, + vf->timestamp); if (kfifo_peek(&pbi->display_q, &next_vf) && next_vf) { vf->next_vf_pts_valid = true; @@ -7120,6 +7905,7 @@ return vf; } } + return NULL; } @@ -7134,6 +7920,24 @@ if (!vf) return; + if (pbi->enable_fence && vf->fence) { + int ret, i; + + mutex_lock(&pbi->fence_mutex); + ret = dma_fence_get_status(vf->fence); + if (ret == 0) { + for (i = 0; i < VF_POOL_SIZE; i++) { + if (pbi->fence_vf_s.fence_vf[i] == NULL) { + pbi->fence_vf_s.fence_vf[i] = vf; + pbi->fence_vf_s.used_size++; + mutex_unlock(&pbi->fence_mutex); + return; + } + } + } + mutex_unlock(&pbi->fence_mutex); + } + index = vf->index & 0xff; if (pbi->enable_fence && vf->fence) { @@ -7142,14 +7946,23 @@ } if (vf->hdr10p_data_buf) { - vfree(vf->hdr10p_data_buf); + kfree(vf->hdr10p_data_buf); vf->hdr10p_data_buf = NULL; vf->hdr10p_data_size = 0; } kfifo_put(&pbi->newframe_q, (const struct vframe_s *)vf); - ATRACE_COUNTER(pbi->new_q_name, kfifo_len(&pbi->newframe_q)); + ATRACE_COUNTER(pbi->trace.new_q_name, kfifo_len(&pbi->newframe_q)); pbi->vf_put_count++; + + if (debug & VP9_DEBUG_BUFMGR) + pr_info("%s idx: %d, type 0x%x w/h %d/%d, pts %d, %lld, ts: %lld\n", + __func__, index, vf->type, + vf->width, vf->height, + vf->pts, + vf->pts_us64, + vf->timestamp); + if (index < pbi->used_buf_num) { struct VP9_Common_s *cm = &pbi->common; struct BufferPool_s *pool = cm->buffer_pool; @@ -7159,9 +7972,6 @@ if (pool->frame_bufs[index].buf.vf_ref > 0) pool->frame_bufs[index].buf.vf_ref--; - if (pbi->is_used_v4l) - pool->frame_bufs[index].buf.vframe_bound = true; - if (pbi->wait_buf) WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG, 0x1); @@ -7290,11 +8100,29 @@ static void update_vf_memhandle(struct VP9Decoder_s *pbi, struct vframe_s *vf, struct PIC_BUFFER_CONFIG_s *pic) { - if (pic->index < 0) { - vf->mem_handle = NULL; - vf->mem_head_handle = NULL; - vf->mem_dw_handle = NULL; - } else if (vf->type & VIDTYPE_SCATTER) { + vf->mem_handle = NULL; + vf->mem_head_handle = NULL; + vf->mem_dw_handle = NULL; + + /* keeper not needed for v4l solution */ + if (pbi->is_used_v4l) + return; + + if (vf->type & VIDTYPE_SCATTER) { + +#ifdef VP9_10B_MMU_DW + if (pic->double_write_mode & 0x20) { + vf->mem_handle = + decoder_mmu_box_get_mem_handle( + pbi->mmu_box_dw, pic->index); + vf->mem_head_handle = + decoder_bmmu_box_get_mem_handle( + pbi->bmmu_box, + HEADER_BUFFER_IDX(pic->BUF_index)); + vf->mem_dw_handle = NULL; + } else +#endif + { vf->mem_handle = decoder_mmu_box_get_mem_handle( pbi->mmu_box, pic->index); @@ -7309,6 +8137,7 @@ VF_BUFFER_IDX(pic->BUF_index)); else vf->mem_dw_handle = NULL; + } } else { vf->mem_handle = decoder_bmmu_box_get_mem_handle( @@ -7322,11 +8151,12 @@ } } -static inline void pbi_update_gvs(struct VP9Decoder_s *pbi) +static inline void pbi_update_gvs(struct VP9Decoder_s *pbi, + struct PIC_BUFFER_CONFIG_s *pic_config) { - if (pbi->gvs->frame_height != frame_height) { - pbi->gvs->frame_width = frame_width; - pbi->gvs->frame_height = frame_height; + if (pbi->gvs->frame_height != pic_config->y_crop_height) { + pbi->gvs->frame_width = pic_config->y_crop_width; + pbi->gvs->frame_height = pic_config->y_crop_height; } if (pbi->gvs->frame_dur != pbi->frame_dur) { pbi->gvs->frame_dur = pbi->frame_dur; @@ -7347,6 +8177,7 @@ int stream_offset = pic_config->stream_offset; unsigned short slice_type = pic_config->slice_type; struct aml_vcodec_ctx * v4l2_ctx = pbi->v4l2_ctx; + struct vdec_v4l2_buffer *fb = NULL; ulong nv_order = VIDTYPE_VIU_NV21; u32 pts_valid = 0, pts_us64_valid = 0; u32 pts_save; @@ -7361,6 +8192,7 @@ pr_info("fatal error, no available buffer slot."); return -1; } + /* swap uv */ if (pbi->is_used_v4l) { if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12) || @@ -7368,7 +8200,8 @@ nv_order = VIDTYPE_VIU_NV12; } - if (pic_config->double_write_mode) + if (pic_config->double_write_mode && + (pic_config->double_write_mode & 0x20) == 0) set_canvas(pbi, pic_config); display_frame_count[pbi->index]++; @@ -7376,20 +8209,20 @@ if (!force_pts_unstable) { if ((pic_config->pts == 0) || ((pic_config->pts <= pbi->last_pts) && (pic_config->pts64 <= pbi->last_pts_us64))) { - for (i = (FRAME_BUFFERS - 1); i > 0; i--) { - if ((pbi->last_pts == pbi->frame_mode_pts_save[i]) || - (pbi->last_pts_us64 == pbi->frame_mode_pts64_save[i])) { - pic_config->pts = pbi->frame_mode_pts_save[i - 1]; - pic_config->pts64 = pbi->frame_mode_pts64_save[i - 1]; - break; - } + for (i = (FRAME_BUFFERS - 1); i > 0; i--) { + if ((pbi->last_pts == pbi->frame_mode_pts_save[i]) || + (pbi->last_pts_us64 == pbi->frame_mode_pts64_save[i])) { + pic_config->pts = pbi->frame_mode_pts_save[i - 1]; + pic_config->pts64 = pbi->frame_mode_pts64_save[i - 1]; + break; + } } if ((i == 0) || (pic_config->pts <= pbi->last_pts)) { - vp9_print(pbi, VP9_DEBUG_OUT_PTS, - "no found pts %d, set 0. %d, %d\n", - i, pic_config->pts, pbi->last_pts); - pic_config->pts = 0; - pic_config->pts64 = 0; + vp9_print(pbi, VP9_DEBUG_OUT_PTS, + "no found pts %d, set 0. %d, %d\n", + i, pic_config->pts, pbi->last_pts); + pic_config->pts = 0; + pic_config->pts64 = 0; } } } @@ -7397,11 +8230,12 @@ if (pbi->is_used_v4l) { vf->v4l_mem_handle = pbi->m_BUF[pic_config->BUF_index].v4l_ref_buf_addr; + fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; if (pbi->mmu_enable) { vf->mm_box.bmmu_box = pbi->bmmu_box; - vf->mm_box.bmmu_idx = HEADER_BUFFER_IDX(pic_config->BUF_index); + vf->mm_box.bmmu_idx = HEADER_BUFFER_IDX(pbi->buffer_wrap[pic_config->BUF_index]); vf->mm_box.mmu_box = pbi->mmu_box; - vf->mm_box.mmu_idx = pic_config->index; + vf->mm_box.mmu_idx = pbi->buffer_wrap[pic_config->index]; } } @@ -7415,7 +8249,12 @@ if (vdec_frame_based(pvdec)) { vf->pts = pic_config->pts; vf->pts_us64 = pic_config->pts64; - vf->timestamp = pic_config->timestamp; + + if (pbi->is_used_v4l && v4l_bitstream_id_enable) + vf->timestamp = pic_config->timestamp; + else + vf->timestamp = pic_config->pts64; + if (vf->pts != 0 || vf->pts_us64 != 0) { pts_valid = 1; pts_us64_valid = 1; @@ -7453,7 +8292,7 @@ pts_save = vf->pts; pts_us64_save = vf->pts_us64; - if (pbi->pts_unstable) { + if (pbi->is_used_v4l || pbi->pts_unstable) { frame_duration_adapt(pbi, vf, pts_valid); if (pbi->duration_from_pts_done) { pbi->pts_mode = PTS_NONE_REF_USE_DURATION; @@ -7525,10 +8364,28 @@ /* double write only */ vf->compBodyAddr = 0; vf->compHeadAddr = 0; +#ifdef VP9_10B_MMU_DW + vf->dwBodyAddr = 0; + vf->dwHeadAddr = 0; +#endif } else { if (pbi->mmu_enable) { vf->compBodyAddr = 0; vf->compHeadAddr = pic_config->header_adr; +#ifdef VP9_10B_MMU_DW + vf->dwBodyAddr = 0; + vf->dwHeadAddr = 0; + if (pic_config->double_write_mode & 0x20) { + u32 mode = pic_config->double_write_mode & 0xf; + if (mode == 5 || mode == 3) + vf->dwHeadAddr = pic_config->header_dw_adr; + else if ((mode == 1 || mode == 2 || mode == 4) + && (debug & VP9_DEBUG_OUT_PTS) == 0) { + vf->compHeadAddr = pic_config->header_dw_adr; + pr_debug("Use dw mmu for display\n"); + } + } +#endif } else { /*vf->compBodyAddr = pic_config->mc_y_adr; *vf->compHeadAddr = pic_config->mc_y_adr + @@ -7537,11 +8394,13 @@ } vf->canvas0Addr = vf->canvas1Addr = 0; } - if (pic_config->double_write_mode) { + if (pic_config->double_write_mode && + (pic_config->double_write_mode & 0x20) == 0) { vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD; vf->type |= nv_order; - if ((pic_config->double_write_mode == 3) && + if ((pic_config->double_write_mode == 3 || + pic_config->double_write_mode == 5) && (!IS_8K_SIZE(pic_config->y_crop_width, pic_config->y_crop_height))) { vf->type |= VIDTYPE_COMPRESS; @@ -7593,24 +8452,29 @@ if (pic_config->bit_depth == VPX_BITS_8) vf->bitdepth |= BITDEPTH_SAVING_MODE; - /* if((vf->width!=pic_config->width)| - * (vf->height!=pic_config->height)) - */ - /* pr_info("aaa: %d/%d, %d/%d\n", - vf->width,vf->height, pic_config->width, - pic_config->height); */ vf->width = pic_config->y_crop_width / - get_double_write_ratio(pbi, - pic_config->double_write_mode); + get_double_write_ratio( + pic_config->double_write_mode & 0xf); vf->height = pic_config->y_crop_height / - get_double_write_ratio(pbi, - pic_config->double_write_mode); + get_double_write_ratio( + pic_config->double_write_mode & 0xf); if (force_w_h != 0) { vf->width = (force_w_h >> 16) & 0xffff; vf->height = force_w_h & 0xffff; } - vf->compWidth = pic_config->y_crop_width; - vf->compHeight = pic_config->y_crop_height; + if ((pic_config->double_write_mode & 0x20) && + ((pic_config->double_write_mode & 0xf) == 2 || + (pic_config->double_write_mode & 0xf) == 4)) { + vf->compWidth = pic_config->y_crop_width / + get_double_write_ratio( + pic_config->double_write_mode & 0xf); + vf->compHeight = pic_config->y_crop_height / + get_double_write_ratio( + pic_config->double_write_mode & 0xf); + } else { + vf->compWidth = pic_config->y_crop_width; + vf->compHeight = pic_config->y_crop_height; + } set_frame_info(pbi, vf); if (force_fps & 0x100) { u32 rate = force_fps & 0xff; @@ -7627,9 +8491,10 @@ } if ((debug & VP9_DEBUG_OUT_PTS) != 0) { pr_info - ("VP9 dec out pts: pts_mode=%d,dur=%d,pts(%d,%lld)(%d,%lld)\n", + ("VP9 dec out pts: pts_mode=%d,dur=%d,pts(%d,%lld,%lld)(%d,%lld)\n", pbi->pts_mode, pbi->frame_dur, vf->pts, - vf->pts_us64, pts_save, pts_us64_save); + vf->pts_us64, vf->timestamp, pts_save, + pts_us64_save); } if (!(pic_config->y_crop_width == 196 && pic_config->y_crop_height == 196 @@ -7641,11 +8506,11 @@ decoder_do_frame_check(pvdec, vf); vdec_vframe_ready(pvdec, vf); kfifo_put(&pbi->display_q, (const struct vframe_s *)vf); - ATRACE_COUNTER(pbi->pts_name, vf->pts); - ATRACE_COUNTER(pbi->new_q_name, kfifo_len(&pbi->newframe_q)); - ATRACE_COUNTER(pbi->disp_q_name, kfifo_len(&pbi->display_q)); + ATRACE_COUNTER(pbi->trace.pts_name, vf->pts); + ATRACE_COUNTER(pbi->trace.new_q_name, kfifo_len(&pbi->newframe_q)); + ATRACE_COUNTER(pbi->trace.disp_q_name, kfifo_len(&pbi->display_q)); pbi->vf_pre_count++; - pbi_update_gvs(pbi); + pbi_update_gvs(pbi, pic_config); /*count info*/ vdec_count_info(pbi->gvs, 0, stream_offset); if (stream_offset) { @@ -7660,13 +8525,21 @@ memcpy(&tmp4x, pbi->gvs, sizeof(struct vdec_info)); tmp4x.bit_depth_luma = pbi->vp9_param.p.bit_depth; tmp4x.bit_depth_chroma = pbi->vp9_param.p.bit_depth; - tmp4x.double_write_mode = get_double_write_mode(pbi); + tmp4x.double_write_mode = pic_config->double_write_mode; vdec_fill_vdec_frame(pvdec, &pbi->vframe_qos, &tmp4x, vf, pic_config->hw_decode_time); pvdec->vdec_fps_detec(pvdec->id); if (without_display_mode == 0) { - vf_notify_receiver(pbi->provider_name, + if (pbi->is_used_v4l) { + if (v4l2_ctx->is_stream_off) { + vvp9_vf_put(vvp9_vf_get(pbi), pbi); + } else { + fb->task->submit(fb->task, TASK_TYPE_DEC); + } + } else { + vf_notify_receiver(pbi->provider_name, VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + } } else vvp9_vf_put(vvp9_vf_get(pbi), pbi); } else { @@ -7700,7 +8573,8 @@ } if (index == INVALID_IDX) { - if (vdec_v4l_get_buffer(hw->v4l2_ctx, &fb) < 0) { + ctx->fb_ops.query(&ctx->fb_ops, &hw->fb_token); + if (ctx->fb_ops.alloc(&ctx->fb_ops, hw->fb_token, &fb, AML_FB_REQ_DEC) < 0) { pr_err("[%d] EOS get free buff fail.\n", ctx->id); return -1; } @@ -7712,11 +8586,16 @@ vf->flag = VFRAME_FLAG_EMPTY_FRAME_V4L; vf->v4l_mem_handle = (index == INVALID_IDX) ? (ulong)fb : hw->m_BUF[index].v4l_ref_buf_addr; + fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; vdec_vframe_ready(vdec, vf); kfifo_put(&hw->display_q, (const struct vframe_s *)vf); - vf_notify_receiver(vdec->vf_provider_name, - VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + + if (hw->is_used_v4l) + fb->task->submit(fb->task, TASK_TYPE_DEC); + else + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); pr_info("[%d] VP9 EOS notify.\n", (hw->is_used_v4l)?ctx->id:vdec->id); } @@ -7814,6 +8693,43 @@ } +static int recycle_mmu_buf_tail(struct VP9Decoder_s *pbi, + bool check_dma) +{ + struct VP9_Common_s *const cm = &pbi->common; + + if (pbi->used_4k_num == -1) { + pbi->used_4k_num = + READ_VREG(HEVC_SAO_MMU_STATUS) >> 16; + } + vp9_print(pbi, VP9_DEBUG_BUFMGR_MORE, + "pic index %d page_start %d\n", + cm->cur_fb_idx_mmu, pbi->used_4k_num); + + if (check_dma) + hevc_mmu_dma_check(hw_to_vdec(pbi)); + + if (pbi->is_used_v4l) { + int index = cm->cur_fb_idx_mmu; + struct internal_comp_buf *ibuf = + index_to_icomp_buf(pbi, index); + + decoder_mmu_box_free_idx_tail( + ibuf->mmu_box, + ibuf->index, + pbi->used_4k_num); + } else { + decoder_mmu_box_free_idx_tail( + pbi->mmu_box, + cm->cur_fb_idx_mmu, + pbi->used_4k_num); + } + + cm->cur_fb_idx_mmu = INVALID_IDX; + pbi->used_4k_num = -1; + + return 0; +} static void vp9_recycle_mmu_buf_tail(struct VP9Decoder_s *pbi) { @@ -7821,16 +8737,9 @@ if (pbi->double_write_mode & 0x10) return; if (cm->cur_fb_idx_mmu != INVALID_IDX) { - if (pbi->used_4k_num == -1) { - pbi->used_4k_num = - (READ_VREG(HEVC_SAO_MMU_STATUS) >> 16); - if (pbi->m_ins_flag) - hevc_mmu_dma_check(hw_to_vdec(pbi)); - } - decoder_mmu_box_free_idx_tail(pbi->mmu_box, - cm->cur_fb_idx_mmu, pbi->used_4k_num); - cm->cur_fb_idx_mmu = INVALID_IDX; - pbi->used_4k_num = -1; + recycle_mmu_buf_tail(pbi, + ((pbi->used_4k_num == -1) && + pbi->m_ins_flag) ? 1 : 0); } } @@ -7838,6 +8747,10 @@ static void vp9_recycle_mmu_buf(struct VP9Decoder_s *pbi) { struct VP9_Common_s *const cm = &pbi->common; + + if (pbi->is_used_v4l) + return; + if (pbi->double_write_mode & 0x10) return; if (cm->cur_fb_idx_mmu != INVALID_IDX) { @@ -7890,7 +8803,6 @@ if (pbi->is_used_v4l && ctx->param_sets_from_ucode) pbi->res_ch_flag = 0; - bit_depth_luma = pbi->vp9_param.p.bit_depth; bit_depth_chroma = pbi->vp9_param.p.bit_depth; @@ -7921,6 +8833,22 @@ pr_err("can't alloc need mmu1,idx %d ret =%d\n", cm->new_fb_idx, ret); + +#ifdef VP9_10B_MMU_DW + if (pbi->dw_mmu_enable && ((pbi->double_write_mode & 0x10) == 0)) { + ret = vp9_alloc_mmu_dw(pbi, + cm->new_fb_idx, + params->p.width, + params->p.height, + params->p.bit_depth, + pbi->frame_mmu_dw_map_addr); + if (ret < 0) + pr_err("can't alloc need dw mmu1,idx %d ret =%d\n", + cm->new_fb_idx, + ret); + } +#endif + } else { ret = 0; } @@ -7932,8 +8860,11 @@ ret); WRITE_VREG(HEVC_DEC_STATUS_REG, VP9_10B_DISCARD_NAL); cm->show_frame = 0; - if (pbi->mmu_enable) + if (pbi->mmu_enable) { + ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_START); vp9_recycle_mmu_buf(pbi); + ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_END); + } #ifdef MULTI_INSTANCE_SUPPORT if (pbi->m_ins_flag) { pbi->dec_result = DEC_RESULT_DONE; @@ -7960,11 +8891,14 @@ if (pbi->chunk) { cur_pic_config->pts = pbi->chunk->pts; cur_pic_config->pts64 = pbi->chunk->pts64; - cur_pic_config->timestamp = pbi->chunk->timestamp; + + if (pbi->is_used_v4l && !v4l_bitstream_id_enable) + cur_pic_config->pts64 = pbi->chunk->timestamp; } #endif } /*pr_info("Decode Frame Data %d\n", pbi->frame_count);*/ + ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_REGISTER_START); config_pic_size(pbi, pbi->vp9_param.p.bit_depth); if ((pbi->common.frame_type != KEY_FRAME) @@ -7980,6 +8914,7 @@ #endif clear_mpred_hw(pbi); } + #ifdef MCRCC_ENABLE if (mcrcc_cache_alg_flag) config_mcrcc_axi_hw_new(pbi); @@ -8045,11 +8980,28 @@ if ((frame_bufs[i].ref_count == 0) && (frame_bufs[i].buf.vf_ref == 0) && (frame_bufs[i].buf.index != -1)) { - decoder_mmu_box_free_idx(pbi->mmu_box, i); + if (pbi->is_used_v4l) { + struct internal_comp_buf *ibuf = + index_to_icomp_buf(pbi, i); + ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_START); + decoder_mmu_box_free_idx(ibuf->mmu_box, ibuf->index); + ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_END); + } else { + ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_START); + decoder_mmu_box_free_idx(pbi->mmu_box, i); + ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_END); + +#ifdef VP9_10B_MMU_DW + if (pbi->dw_mmu_enable) + decoder_mmu_box_free_idx(pbi->mmu_box_dw, i); +#endif + + } } pbi->last_put_idx = -1; } } + ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_REGISTER_END); return ret; } @@ -8151,7 +9103,7 @@ frame->min_mv = a[0]; vp9_print(pbi, VP9_DEBUG_QOS_INFO, - "mv data %lx a[0]= %x a[1]= %x a[2]= %x\n", + "mv data %x a[0]= %x a[1]= %x a[2]= %x\n", data, a[0], a[1], a[2]); data = READ_VREG(HEVC_QP_INFO); @@ -8178,7 +9130,7 @@ frame->min_qp = a[0]; vp9_print(pbi, VP9_DEBUG_QOS_INFO, - "qp data %lx a[0]= %x a[1]= %x a[2]= %x\n", + "qp data %x a[0]= %x a[1]= %x a[2]= %x\n", data, a[0], a[1], a[2]); data = READ_VREG(HEVC_SKIP_INFO); @@ -8205,7 +9157,7 @@ frame->min_skip = a[0]; vp9_print(pbi, VP9_DEBUG_QOS_INFO, - "skip data %lx a[0]= %x a[1]= %x a[2]= %x\n", + "skip data %x a[0]= %x a[1]= %x a[2]= %x\n", data, a[0], a[1], a[2]); } else { uint32_t blk88_y_count; @@ -8524,14 +9476,29 @@ } } +static void vvp9_get_comp_buf_info(struct VP9Decoder_s *pbi, + struct vdec_comp_buf_info *info) +{ + u16 bit_depth = pbi->param.p.bit_depth; + + info->max_size = vp9_max_mmu_buf_size( + pbi->max_pic_w, + pbi->max_pic_h); + info->header_size = vvp9_mmu_compress_header_size( + pbi->frame_width, + pbi->frame_height); + info->frame_buffer_size = vp9_mmu_page_num( + pbi, pbi->frame_width, + pbi->frame_height, + bit_depth == 0); +} + static int vvp9_get_ps_info(struct VP9Decoder_s *pbi, struct aml_vdec_ps_infos *ps) { - int dw_mode = v4l_parser_get_double_write_mode(pbi); - - ps->visible_width = pbi->frame_width / get_double_write_ratio(pbi, dw_mode); - ps->visible_height = pbi->frame_height / get_double_write_ratio(pbi, dw_mode); - ps->coded_width = ALIGN(pbi->frame_width, 32) / get_double_write_ratio(pbi, dw_mode); - ps->coded_height = ALIGN(pbi->frame_height, 32) / get_double_write_ratio(pbi, dw_mode); + ps->visible_width = pbi->frame_width; + ps->visible_height = pbi->frame_height; + ps->coded_width = ALIGN(pbi->frame_width, 64); + ps->coded_height = ALIGN(pbi->frame_height, 64); ps->dpb_size = pbi->used_buf_num; return 0; @@ -8542,22 +9509,34 @@ { struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(pbi->v4l2_ctx); - struct VP9_Common_s *const cm = &pbi->common; int ret = 0; if (ctx->param_sets_from_ucode && pbi->res_ch_flag == 0) { struct aml_vdec_ps_infos ps; - if ((cm->width != 0 && - cm->height != 0) && - (pbi->frame_width != cm->width || - pbi->frame_height != cm->height)) { + struct vdec_comp_buf_info comp; - vp9_print(pbi, 0, "%s (%d,%d)=>(%d,%d)\r\n", __func__, cm->width, - cm->height, pbi->frame_width, pbi->frame_height); + if ((pbi->last_width != 0 && + pbi->last_height != 0) && + (pbi->frame_width != pbi->last_width || + pbi->frame_height != pbi->last_height)) { + + vp9_print(pbi, 0, "%s (%d,%d)=>(%d,%d)\r\n", __func__, pbi->last_width, + pbi->last_height, pbi->frame_width, pbi->frame_height); + + if (get_valid_double_write_mode(pbi) != 16) { + vvp9_get_comp_buf_info(pbi, &comp); + vdec_v4l_set_comp_buf_info(ctx, &comp); + } + vvp9_get_ps_info(pbi, &ps); vdec_v4l_set_ps_infos(ctx, &ps); vdec_v4l_res_ch_event(ctx); + + pbi->init_pic_w = pbi->frame_width; + pbi->init_pic_h = pbi->frame_height; + init_mv_buf_list(pbi); + pbi->v4l_params_parsed = false; pbi->res_ch_flag = 1; ctx->v4l_resolution_change = 1; @@ -8582,6 +9561,14 @@ /*if (pbi->wait_buf) * pr_info("set wait_buf to 0\r\n"); */ + + if (dec_status == VP9_HEAD_PARSER_DONE) { + ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_START); + } + else if (dec_status == HEVC_DECPIC_DATA_DONE) { + ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_ISR_THREAD_PIC_DONE_START); + } + if (pbi->eos) return IRQ_HANDLED; pbi->wait_buf = 0; @@ -8617,8 +9604,15 @@ if (!vdec_frame_based(hw_to_vdec(pbi))) dec_again_process(pbi); else { - pbi->dec_result = DEC_RESULT_GET_DATA; - vdec_schedule_work(&pbi->work); + if (pbi->common.show_existing_frame) { + pbi->dec_result = DEC_RESULT_DONE; + amhevc_stop(); + vdec_schedule_work(&pbi->work); + } + else { + pbi->dec_result = DEC_RESULT_GET_DATA; + vdec_schedule_work(&pbi->work); + } } } pbi->process_busy = 0; @@ -8649,6 +9643,7 @@ amhevc_stop(); if (mcrcc_cache_alg_flag) dump_hit_rate(pbi); + ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_ISR_THREAD_EDN); vdec_schedule_work(&pbi->work); } } else { @@ -8733,9 +9728,11 @@ && pbi->used_stage_buf_num == 0 #endif ) { - if (pbi->mmu_enable) + if (pbi->mmu_enable) { + ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_START); vp9_recycle_mmu_buf_tail(pbi); - + ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_MEMORY_END); + } if (pbi->frame_count > 0) vp9_bufmgr_postproc(pbi); @@ -8794,12 +9791,14 @@ } else #endif { + ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_RPM_START); for (i = 0; i < (RPM_END - RPM_BEGIN); i += 4) { int ii; for (ii = 0; ii < 4; ii++) pbi->vp9_param.l.data[i + ii] = pbi->rpm_ptr[i + 3 - ii]; } + ATRACE_COUNTER(pbi->trace.decode_header_memory_time_name, TRACE_HEADER_RPM_END); } } @@ -8822,11 +9821,22 @@ if (!v4l_res_change(pbi)) { if (ctx->param_sets_from_ucode && !pbi->v4l_params_parsed) { struct aml_vdec_ps_infos ps; + struct vdec_comp_buf_info comp; pr_debug("set ucode parse\n"); + if (get_valid_double_write_mode(pbi) != 16) { + vvp9_get_comp_buf_info(pbi, &comp); + vdec_v4l_set_comp_buf_info(ctx, &comp); + } + vvp9_get_ps_info(pbi, &ps); /*notice the v4l2 codec.*/ vdec_v4l_set_ps_infos(ctx, &ps); + + pbi->init_pic_w = pbi->frame_width; + pbi->init_pic_h = pbi->frame_height; + init_mv_buf_list(pbi); + pbi->v4l_params_parsed = true; pbi->postproc_done = 0; pbi->process_busy = 0; @@ -8849,7 +9859,7 @@ if (pbi->m_ins_flag) start_process_time(pbi); #endif - + ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_END); return IRQ_HANDLED; } @@ -8859,22 +9869,25 @@ unsigned int dec_status; struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)data; unsigned int adapt_prob_status; - struct VP9_Common_s *const cm = &pbi->common; uint debug_tag; WRITE_VREG(HEVC_ASSIST_MBOX0_CLR_REG, 1); dec_status = READ_VREG(HEVC_DEC_STATUS_REG); + if (dec_status == VP9_HEAD_PARSER_DONE) { + ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_ISR_HEAD_DONE); + } + else if (dec_status == HEVC_DECPIC_DATA_DONE) { + ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_ISR_PIC_DONE); + } + adapt_prob_status = READ_VREG(VP9_ADAPT_PROB_REG); if (!pbi) return IRQ_HANDLED; if (pbi->init_flag == 0) return IRQ_HANDLED; - if (pbi->process_busy) {/*on process.*/ - vp9_print(pbi, PRINT_FLAG_VDEC_STATUS, - "%s: process_busy isr return\n", __func__); + if (pbi->process_busy)/*on process.*/ return IRQ_HANDLED; - } pbi->dec_status = dec_status; pbi->process_busy = 1; if (debug & VP9_DEBUG_BUFMGR) @@ -8964,34 +9977,44 @@ } #endif if ((adapt_prob_status & 0xff) == 0xfd) { - /*VP9_REQ_ADAPT_PROB*/ - int pre_fc = (cm->frame_type == KEY_FRAME) ? 1 : 0; - uint8_t *prev_prob_b = - ((uint8_t *)pbi->prob_buffer_addr) + - ((adapt_prob_status >> 8) * 0x1000); - uint8_t *cur_prob_b = - ((uint8_t *)pbi->prob_buffer_addr) + 0x4000; - uint8_t *count_b = (uint8_t *)pbi->count_buffer_addr; -#ifdef MULTI_INSTANCE_SUPPORT - if (pbi->m_ins_flag) - reset_process_time(pbi); -#endif - adapt_coef_probs(pbi->pic_count, - (cm->last_frame_type == KEY_FRAME), - pre_fc, (adapt_prob_status >> 8), - (unsigned int *)prev_prob_b, - (unsigned int *)cur_prob_b, (unsigned int *)count_b); + struct VP9_Common_s *const cm = &pbi->common; + int pre_fc = 0; - memcpy(prev_prob_b, cur_prob_b, PROB_SIZE); + if (pbi->m_ins_flag) + reset_process_time(pbi); + + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) && + (vdec_secure(hw_to_vdec(pbi)))) { + pre_fc = ((cm->frame_type == KEY_FRAME) || (cm->intra_only)) ? 0 : 1; + tee_vp9_prob_process(pre_fc, cm->last_frame_type, + adapt_prob_status, (unsigned int)pbi->prob_buffer_phy_addr); + } else { + uint8_t *prev_prob_b, *cur_prob_b, *count_b; + + /*VP9_REQ_ADAPT_PROB*/ + pre_fc = ((cm->frame_type == KEY_FRAME) || (cm->intra_only)); + prev_prob_b = ((uint8_t *)pbi->prob_buffer_addr) + + ((adapt_prob_status >> 8) * 0x1000); + cur_prob_b = ((uint8_t *)pbi->prob_buffer_addr) + 0x4000; + count_b = (uint8_t *)pbi->count_buffer_addr; + + adapt_coef_probs(pbi->pic_count, + (cm->last_frame_type == KEY_FRAME), + pre_fc, (adapt_prob_status >> 8), + (unsigned int *)prev_prob_b, + (unsigned int *)cur_prob_b, (unsigned int *)count_b); + + memcpy(prev_prob_b, cur_prob_b, PROB_SIZE); + } + WRITE_VREG(VP9_ADAPT_PROB_REG, 0); pbi->pic_count += 1; #ifdef MULTI_INSTANCE_SUPPORT if (pbi->m_ins_flag) start_process_time(pbi); #endif - - /*return IRQ_HANDLED;*/ } + ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_ISR_END); return IRQ_WAKE_THREAD; } @@ -9007,15 +10030,14 @@ frame_height * fps; } -static void vvp9_put_timer_func(unsigned long arg) +static void vvp9_put_timer_func(struct timer_list *timer) { - struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)arg; - struct timer_list *timer = &pbi->timer; + struct VP9Decoder_s *pbi = container_of(timer, + struct VP9Decoder_s, timer); + enum receviver_start_e state = RECEIVER_INACTIVE; uint8_t empty_flag; unsigned int buf_level; - enum receviver_start_e state = RECEIVER_INACTIVE; - if (pbi->m_ins_flag) { if (hw_to_vdec(pbi)->next_status == VDEC_STATUS_DISCONNECTED && @@ -9517,12 +10539,10 @@ fw->len = fw_size; INIT_WORK(&pbi->set_clk_work, vp9_set_clk); - init_timer(&pbi->timer); + timer_setup(&pbi->timer, vvp9_put_timer_func, 0); #ifdef MULTI_INSTANCE_SUPPORT if (pbi->m_ins_flag) { - pbi->timer.data = (ulong) pbi; - pbi->timer.function = vvp9_put_timer_func; pbi->timer.expires = jiffies + PUT_INTERVAL; /*add_timer(&pbi->timer); @@ -9579,16 +10599,18 @@ pbi->provider_name = PROVIDER_NAME; #ifdef MULTI_INSTANCE_SUPPORT - vf_provider_init(&vvp9_vf_prov, PROVIDER_NAME, - &vvp9_vf_provider, pbi); - vf_reg_provider(&vvp9_vf_prov); - vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_START, NULL); - if (pbi->frame_dur != 0) { - if (!is_reset) - vf_notify_receiver(pbi->provider_name, - VFRAME_EVENT_PROVIDER_FR_HINT, - (void *) - ((unsigned long)pbi->frame_dur)); + if (!pbi->is_used_v4l) { + vf_provider_init(&vvp9_vf_prov, PROVIDER_NAME, + &vvp9_vf_provider, pbi); + vf_reg_provider(&vvp9_vf_prov); + vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_START, NULL); + if (pbi->frame_dur != 0) { + if (!is_reset) + vf_notify_receiver(pbi->provider_name, + VFRAME_EVENT_PROVIDER_FR_HINT, + (void *) + ((unsigned long)pbi->frame_dur)); + } } #else vf_provider_init(&vvp9_vf_prov, PROVIDER_NAME, &vvp9_vf_provider, @@ -9601,14 +10623,11 @@ #endif pbi->stat |= STAT_VF_HOOK; - pbi->timer.data = (ulong)pbi; - pbi->timer.function = vvp9_put_timer_func; pbi->timer.expires = jiffies + PUT_INTERVAL; + add_timer(&pbi->timer); pbi->stat |= STAT_VDEC_RUN; - add_timer(&pbi->timer); - pbi->stat |= STAT_TIMER_ARM; amhevc_start(); @@ -9637,7 +10656,7 @@ pbi->stat &= ~STAT_TIMER_ARM; } - if (pbi->stat & STAT_VF_HOOK) { + if (!pbi->is_used_v4l && (pbi->stat & STAT_VF_HOOK)) { if (!is_reset) vf_notify_receiver(pbi->provider_name, VFRAME_EVENT_PROVIDER_FR_END_HINT, @@ -9686,7 +10705,7 @@ pbi->stat &= ~STAT_TIMER_ARM; } - if (pbi->stat & STAT_VF_HOOK) { + if (!pbi->is_used_v4l && (pbi->stat & STAT_VF_HOOK)) { if (!is_reset) vf_notify_receiver(pbi->provider_name, VFRAME_EVENT_PROVIDER_FR_END_HINT, @@ -9717,22 +10736,16 @@ pbi->fw = NULL; return 0; } + static int amvdec_vp9_mmu_init(struct VP9Decoder_s *pbi) { int tvp_flag = vdec_secure(hw_to_vdec(pbi)) ? CODEC_MM_FLAGS_TVP : 0; - int buf_size = 48; + int buf_size = vp9_max_mmu_buf_size(pbi->max_pic_w, pbi->max_pic_h); - if ((pbi->max_pic_w * pbi->max_pic_h > 1280*736) && - (pbi->max_pic_w * pbi->max_pic_h <= 1920*1088)) { - buf_size = 12; - } else if ((pbi->max_pic_w * pbi->max_pic_h > 0) && - (pbi->max_pic_w * pbi->max_pic_h <= 1280*736)) { - buf_size = 4; - } pbi->need_cache_size = buf_size * SZ_1M; pbi->sc_start_time = get_jiffies_64(); - if (pbi->mmu_enable && ((pbi->double_write_mode & 0x10) == 0)) { + if (pbi->mmu_enable && !pbi->is_used_v4l) { pbi->mmu_box = decoder_mmu_box_alloc_box(DRIVER_NAME, pbi->index, FRAME_BUFFERS, pbi->need_cache_size, @@ -9743,6 +10756,18 @@ return -1; } } +#ifdef VP9_10B_MMU_DW + if (pbi->dw_mmu_enable && !pbi->is_used_v4l) { + pbi->mmu_box_dw = decoder_mmu_box_alloc_box(DRIVER_NAME, + pbi->index, FRAME_BUFFERS, + pbi->need_cache_size, + tvp_flag + ); + if (!pbi->mmu_box_dw) { + pr_err("vp9 alloc mmu dw box failed!!\n"); + } + } +#endif pbi->bmmu_box = decoder_bmmu_box_alloc_box( DRIVER_NAME, pbi->index, @@ -9769,10 +10794,16 @@ #ifndef MULTI_INSTANCE_SUPPORT int i; #endif + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_GXL || + get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_TXL || + get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5) { + pr_info("vp9 unsupported on cpu 0x%x\n", get_cpu_major_id()); + return -EINVAL; + } pr_debug("%s\n", __func__); mutex_lock(&vvp9_mutex); - pbi = vmalloc(sizeof(struct VP9Decoder_s)); + pbi = vzalloc(sizeof(struct VP9Decoder_s)); if (pbi == NULL) { pr_info("\namvdec_vp9 device data allocation failed\n"); mutex_unlock(&vvp9_mutex); @@ -9786,12 +10817,29 @@ pbi->init_flag = 0; pbi->first_sc_checked= 0; - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) { - vp9_max_pic_w = 8192; - vp9_max_pic_h = 4608; + + if (!vdec_is_support_4k()) { + pbi->max_pic_w = 1920; + pbi->max_pic_h = 1088; + } else if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SM1) { + pbi->max_pic_w = 4096; + pbi->max_pic_h = 2304; + } else { + pbi->max_pic_w = 8192; + pbi->max_pic_h = 4608; } - pbi->max_pic_w = vp9_max_pic_w; - pbi->max_pic_h = vp9_max_pic_h; + if (pdata->sys_info) { + pbi->vvp9_amstream_dec_info = *pdata->sys_info; + if ((pbi->vvp9_amstream_dec_info.width != 0) && + (pbi->vvp9_amstream_dec_info.height != 0)) { + pbi->max_pic_w = pbi->vvp9_amstream_dec_info.width; + pbi->max_pic_h = pbi->vvp9_amstream_dec_info.height; + } + } else { + pbi->vvp9_amstream_dec_info.width = 0; + pbi->vvp9_amstream_dec_info.height = 0; + pbi->vvp9_amstream_dec_info.rate = 30; + } #ifdef MULTI_INSTANCE_SUPPORT pbi->eos = 0; @@ -9813,6 +10861,14 @@ #endif pbi->double_write_mode = double_write_mode; pbi->mmu_enable = 1; +#ifdef VP9_10B_MMU_DW + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T5D) { + pbi->dw_mmu_enable = + (get_double_write_mode(pbi) & 0x20) ? 1 : 0; + } else { + pbi->dw_mmu_enable = 0; + } +#endif if (amvdec_vp9_mmu_init(pbi) < 0) { vfree(pbi); mutex_unlock(&vvp9_mutex); @@ -9845,20 +10901,18 @@ pr_info("===VP9 decoder mem resource 0x%lx size 0x%x\n", pdata->mem_start, pbi->buf_size); } - - if (pdata->sys_info) - pbi->vvp9_amstream_dec_info = *pdata->sys_info; - else { - pbi->vvp9_amstream_dec_info.width = 0; - pbi->vvp9_amstream_dec_info.height = 0; - pbi->vvp9_amstream_dec_info.rate = 30; - } pbi->no_head = no_head; #ifdef MULTI_INSTANCE_SUPPORT pbi->cma_dev = pdata->cma_dev; #else cma_dev = pdata->cma_dev; #endif + /* config endian */ + pbi->endian = HEVC_CONFIG_LITTLE_ENDIAN; + if (is_support_vdec_canvas()) + pbi->endian = HEVC_CONFIG_BIG_ENDIAN; + if (endian) + pbi->endian = endian; #ifdef MULTI_INSTANCE_SUPPORT pdata->private = pbi; @@ -9889,7 +10943,6 @@ struct vdec_sync *sync) { ulong expires; - int i; /* notify signal to wake up all fences. */ vdec_timeline_increase(sync, VF_POOL_SIZE); @@ -9902,15 +10955,6 @@ } } - for (i = 0; i < VF_POOL_SIZE; i++) { - struct vframe_s *vf = &pbi->vfpool[i]; - - if (vf->fence) { - vdec_fence_put(vf->fence); - vf->fence = NULL; - } - } - /* decreases refcnt of timeline. */ vdec_timeline_put(sync); } @@ -9946,7 +10990,7 @@ mem_map_mode = 0; if (pbi->enable_fence) - vdec_fence_release(pbi, &vdec->sync); + vdec_fence_release(pbi, vdec->sync); vfree(pbi); mutex_unlock(&vvp9_mutex); @@ -9955,32 +10999,16 @@ } /****************************************/ -#ifdef CONFIG_PM -static int vp9_suspend(struct device *dev) -{ - amhevc_suspend(to_platform_device(dev), dev->power.power_state); - return 0; -} - -static int vp9_resume(struct device *dev) -{ - amhevc_resume(to_platform_device(dev)); - return 0; -} - -static const struct dev_pm_ops vp9_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(vp9_suspend, vp9_resume) -}; -#endif static struct platform_driver amvdec_vp9_driver = { .probe = amvdec_vp9_probe, .remove = amvdec_vp9_remove, +#ifdef CONFIG_PM + .suspend = amhevc_suspend, + .resume = amhevc_resume, +#endif .driver = { .name = DRIVER_NAME, -#ifdef CONFIG_PM - .pm = &vp9_pm_ops, -#endif } }; @@ -9998,6 +11026,9 @@ int sum = 0; u8 *data = NULL; + if (vdec_secure(hw_to_vdec(pbi))) + return 0; + if (!pbi->chunk->block->is_mapped) data = codec_mm_vmap(pbi->chunk->block->start + pbi->chunk->offset, size); @@ -10008,6 +11039,20 @@ for (jj = 0; jj < size; jj++) sum += data[jj]; + vp9_print(pbi, PRINT_FLAG_VDEC_STATUS, + "%s: size 0x%x sum 0x%x %02x %02x %02x %02x %02x %02x .. %02x %02x %02x %02x\n", + __func__, size, sum, + (size < 1) ? 0 : data[0], + (size < 2) ? 0 : data[1], + (size < 3) ? 0 : data[2], + (size < 4) ? 0 : data[3], + (size < 5) ? 0 : data[4], + (size < 6) ? 0 : data[5], + (size < 4) ? 0 : data[size - 4], + (size < 3) ? 0 : data[size - 3], + (size < 2) ? 0 : data[size - 2], + (size < 1) ? 0 : data[size - 1]); + if (!pbi->chunk->block->is_mapped) codec_mm_unmap_phyaddr(data); return sum; @@ -10064,6 +11109,9 @@ /* finished decoding one frame or error, * notify vdec core to switch context */ + ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_WORKER_START); + if (pbi->dec_result == DEC_RESULT_AGAIN) + ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_WORKER_AGAIN); vp9_print(pbi, PRINT_FLAG_VDEC_DETAIL, "%s dec_result %d %x %x %x\n", __func__, @@ -10081,7 +11129,6 @@ if (pbi->dec_result == DEC_RESULT_NEED_MORE_BUFFER) { reset_process_time(pbi); if (!get_free_buf_count(pbi)) { - pbi->process_busy = 0; pbi->dec_result = DEC_RESULT_NEED_MORE_BUFFER; vdec_schedule_work(&pbi->work); } else { @@ -10262,6 +11309,7 @@ pbi->stat &= ~STAT_TIMER_ARM; } /* mark itself has all HW resource released and input released */ + ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_WORKER_END); #ifdef SUPPORT_FB_DECODING if (pbi->used_stage_buf_num > 0) vdec_core_finish_run(hw_to_vdec(pbi), CORE_MASK_HEVC_BACK); @@ -10296,6 +11344,34 @@ #endif return 0; } + +static bool is_avaliable_buffer(struct VP9Decoder_s *pbi) +{ + struct VP9_Common_s *const cm = &pbi->common; + struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs; + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(pbi->v4l2_ctx); + int i, free_count = 0; + + if (ctx->cap_pool.dec < pbi->used_buf_num) { + free_count = v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx); + if (free_count && + !ctx->fb_ops.query(&ctx->fb_ops, &pbi->fb_token)) { + return false; + } + } + + for (i = 0; i < pbi->used_buf_num; ++i) { + if ((frame_bufs[i].ref_count == 0) && + (frame_bufs[i].buf.vf_ref == 0) && + frame_bufs[i].buf.cma_alloc_addr) { + free_count++; + } + } + + return free_count < pbi->run_ready_min_buf_num ? 0 : 1; +} + static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) { struct VP9Decoder_s *pbi = @@ -10307,7 +11383,17 @@ if (!(pbi->pic_list_init_done && pbi->pic_list_init_done2) || pbi->eos) return ret; if (!pbi->first_sc_checked && pbi->mmu_enable) { - int size = decoder_mmu_box_sc_check(pbi->mmu_box, tvp); + int size; + void * mmu_box; + + if (pbi->is_used_v4l) { + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(pbi->v4l2_ctx); + mmu_box = ctx->mmu_box; + } else + mmu_box = pbi->mmu_box; + + size = decoder_mmu_box_sc_check(mmu_box, tvp); pbi->first_sc_checked = 1; vp9_print(pbi, 0, "vp9 cached=%d need_size=%d speed= %d ms\n", size, (pbi->need_cache_size >> PAGE_SHIFT), @@ -10377,10 +11463,12 @@ if (ctx->param_sets_from_ucode) { if (pbi->v4l_params_parsed) { - if ((ctx->cap_pool.in < pbi->used_buf_num) && - v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < - pbi->run_ready_min_buf_num) - ret = 0; + if (ctx->cap_pool.dec < pbi->used_buf_num) { + if (is_avaliable_buffer(pbi)) + ret = CORE_MASK_HEVC; + else + ret = 0; + } } else { if (ctx->v4l_resolution_change) ret = 0; @@ -10411,13 +11499,17 @@ if (pbi->chunk == NULL) return; vp9_print(pbi, VP9_DEBUG_OUT_PTS, - "run front: pts %d, pts64 %lld\n", pbi->chunk->pts, pbi->chunk->pts64); + "run front: pts %d, pts64 %lld, ts: %lld\n", + pbi->chunk->pts, pbi->chunk->pts64, pbi->chunk->timestamp); for (i = (FRAME_BUFFERS - 1); i > 0; i--) { - pbi->frame_mode_pts_save[i] = pbi->frame_mode_pts_save[i - 1]; - pbi->frame_mode_pts64_save[i] = pbi->frame_mode_pts64_save[i - 1]; + pbi->frame_mode_pts_save[i] = pbi->frame_mode_pts_save[i - 1]; + pbi->frame_mode_pts64_save[i] = pbi->frame_mode_pts64_save[i - 1]; } pbi->frame_mode_pts_save[0] = pbi->chunk->pts; pbi->frame_mode_pts64_save[0] = pbi->chunk->pts64; + + if (pbi->is_used_v4l && !v4l_bitstream_id_enable) + pbi->frame_mode_pts64_save[0] = pbi->chunk->timestamp; } static void run_front(struct vdec_s *vdec) @@ -10475,7 +11567,9 @@ READ_VREG(HEVC_STREAM_WR_PTR), READ_VREG(HEVC_STREAM_RD_PTR), pbi->start_shift_bytes); - if (vdec_frame_based(vdec) && pbi->chunk) { + + if (!vdec_secure(hw_to_vdec(pbi)) && + vdec_frame_based(vdec) && pbi->chunk) { u8 *data = NULL; if (!pbi->chunk->block->is_mapped) @@ -10496,6 +11590,7 @@ } vp9_print_cont(pbi, 0, "\r\n"); } + ATRACE_COUNTER(pbi->trace.decode_run_time_name, TRACE_RUN_LOADING_FW_START); if (vdec->mc_loaded) { /*firmware have load before, and not changes to another. @@ -10515,12 +11610,14 @@ vdec->mc_loaded = 1; vdec->mc_type = VFORMAT_VP9; } + ATRACE_COUNTER(pbi->trace.decode_run_time_name, TRACE_RUN_LOADING_FW_END); + ATRACE_COUNTER(pbi->trace.decode_run_time_name, TRACE_RUN_LOADING_RESTORE_START); if (vp9_hw_ctx_restore(pbi) < 0) { vdec_schedule_work(&pbi->work); return; } - + ATRACE_COUNTER(pbi->trace.decode_run_time_name, TRACE_RUN_LOADING_RESTORE_END); vdec_enable_input(vdec); WRITE_VREG(HEVC_DEC_STATUS_REG, HEVC_ACTION_DONE); @@ -10694,7 +11791,7 @@ { struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)vdec->private; - + ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_RUN_START); vp9_print(pbi, PRINT_FLAG_VDEC_DETAIL, "%s mask %lx\r\n", __func__, mask); @@ -10716,23 +11813,36 @@ #else run_front(vdec); #endif + ATRACE_COUNTER(pbi->trace.decode_time_name, DECODER_RUN_END); } -static void init_frame_bufs(struct VP9Decoder_s *pbi) +static void vp9_decoder_ctx_reset(struct VP9Decoder_s *pbi) { struct vdec_s *vdec = hw_to_vdec(pbi); struct VP9_Common_s *const cm = &pbi->common; struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs; + struct BufferPool_s *buffer_pool = cm->buffer_pool; int i; - for (i = 0; i < pbi->used_buf_num; ++i) { - frame_bufs[i].ref_count = 0; - frame_bufs[i].buf.vf_ref = 0; - frame_bufs[i].buf.decode_idx = 0; + cm->buffer_pool = buffer_pool; + + for (i = 0; i < FRAME_BUFFERS; ++i) { + frame_bufs[i].buf.index = i; + frame_bufs[i].ref_count = 0; + frame_bufs[i].buf.vf_ref = 0; + frame_bufs[i].buf.decode_idx = 0; frame_bufs[i].buf.cma_alloc_addr = 0; - frame_bufs[i].buf.index = i; - frame_bufs[i].buf.vframe_bound = 0; + frame_bufs[i].buf.BUF_index = -1; + frame_bufs[i].buf.slice_type = 0; + } + + for (i = 0; i < MV_BUFFER_NUM; ++i) { + pbi->m_mv_BUF[i].used_flag = 0; + } + + for (i = 0; i < FRAME_BUFFERS; i++) { + pbi->buffer_wrap[i] = i; } if (vdec->parallel_dec == 1) { @@ -10745,6 +11855,12 @@ vdec->id); } } + + pbi->init_flag = 0; + pbi->first_sc_checked = 0; + pbi->fatal_error = 0; + pbi->show_frame_num = 0; + pbi->eos = 0; } static void reset(struct vdec_s *vdec) @@ -10752,6 +11868,7 @@ struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)vdec->private; + cancel_work_sync(&pbi->set_clk_work); cancel_work_sync(&pbi->work); if (pbi->stat & STAT_VDEC_RUN) { amhevc_stop(); @@ -10762,16 +11879,16 @@ del_timer_sync(&pbi->timer); pbi->stat &= ~STAT_TIMER_ARM; } - pbi->dec_result = DEC_RESULT_NONE; + reset_process_time(pbi); + vp9_local_uninit(pbi); if (vvp9_local_init(pbi) < 0) - vp9_print(pbi, 0, "%s local_init failed \r\n", __func__); - init_frame_bufs(pbi); + vp9_print(pbi, 0, "%s local_init failed \r\n", __func__); - pbi->eos = 0; + vp9_decoder_ctx_reset(pbi); - vp9_print(pbi, PRINT_FLAG_VDEC_DETAIL, "%s\r\n", __func__); + vp9_print(pbi, 0, "%s\r\n", __func__); } static irqreturn_t vp9_irq_cb(struct vdec_s *vdec, int irq) @@ -10818,7 +11935,7 @@ pbi->no_head ); - if (vf_get_receiver(vdec->vf_provider_name)) { + if (!pbi->is_used_v4l && vf_get_receiver(vdec->vf_provider_name)) { enum receviver_start_e state = vf_notify_receiver(vdec->vf_provider_name, VFRAME_EVENT_PROVIDER_QUREY_STATE, @@ -10847,7 +11964,7 @@ for (i = 0; i < MAX_BUF_NUM; i++) { vp9_print(pbi, 0, - "mv_Buf(%d) start_adr 0x%lx size 0x%x used %d\n", + "mv_Buf(%d) start_adr 0x%x size 0x%x used %d\n", i, pbi->m_mv_BUF[i].start_adr, pbi->m_mv_BUF[i].size, @@ -10942,9 +12059,15 @@ int transfer_val; struct vframe_content_light_level_s content_light_level; struct vframe_master_display_colour_s vf_dp; - - struct BUF_s BUF[MAX_BUF_NUM]; struct VP9Decoder_s *pbi = NULL; + int i; + + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_GXL || + get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_TXL || + get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5) { + pr_info("vp9 unsupported on cpu 0x%x\n", get_cpu_major_id()); + return -EINVAL; + } pr_debug("%s\n", __func__); if (pdata == NULL) { @@ -10974,19 +12097,35 @@ pdata->threaded_irq_handler = vp9_threaded_irq_cb; pdata->dump_state = vp9_dump_state; - memcpy(&BUF[0], &pbi->m_BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM); - memcpy(&pbi->m_BUF[0], &BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM); - pbi->index = pdev->id; - snprintf(pbi->vdec_name, sizeof(pbi->vdec_name), + if (is_rdma_enable()) { + pbi->rdma_adr = dma_alloc_coherent(amports_get_dma_device(), RDMA_SIZE, &pbi->rdma_phy_adr, GFP_KERNEL); + for (i = 0; i < SCALELUT_DATA_WRITE_NUM; i++) { + pbi->rdma_adr[i * 4] = HEVC_IQIT_SCALELUT_WR_ADDR & 0xfff; + pbi->rdma_adr[i * 4 + 1] = i; + pbi->rdma_adr[i * 4 + 2] = HEVC_IQIT_SCALELUT_DATA & 0xfff; + pbi->rdma_adr[i * 4 + 3] = 0; + if (i == SCALELUT_DATA_WRITE_NUM - 1) { + pbi->rdma_adr[i * 4 + 2] = (HEVC_IQIT_SCALELUT_DATA & 0xfff) | 0x20000; + } + } + } + + snprintf(pbi->trace.vdec_name, sizeof(pbi->trace.vdec_name), "vp9-%d", pbi->index); - snprintf(pbi->pts_name, sizeof(pbi->pts_name), - "%s-pts", pbi->vdec_name); - snprintf(pbi->new_q_name, sizeof(pbi->new_q_name), - "%s-newframe_q", pbi->vdec_name); - snprintf(pbi->disp_q_name, sizeof(pbi->disp_q_name), - "%s-dispframe_q", pbi->vdec_name); + snprintf(pbi->trace.pts_name, sizeof(pbi->trace.pts_name), + "%s-pts", pbi->trace.vdec_name); + snprintf(pbi->trace.new_q_name, sizeof(pbi->trace.new_q_name), + "%s-newframe_q", pbi->trace.vdec_name); + snprintf(pbi->trace.disp_q_name, sizeof(pbi->trace.disp_q_name), + "%s-dispframe_q", pbi->trace.vdec_name); + snprintf(pbi->trace.decode_time_name, sizeof(pbi->trace.decode_time_name), + "decoder_time%d", pdev->id); + snprintf(pbi->trace.decode_run_time_name, sizeof(pbi->trace.decode_run_time_name), + "decoder_run_time%d", pdev->id); + snprintf(pbi->trace.decode_header_memory_time_name, sizeof(pbi->trace.decode_header_memory_time_name), + "decoder_header_time%d", pdev->id); if (pdata->use_vfm_path) snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE, @@ -10995,26 +12134,23 @@ snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE, MULTI_INSTANCE_PROVIDER_NAME ".%02x", pdev->id & 0xff); - vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name, - &vvp9_vf_provider, pbi); - pbi->provider_name = pdata->vf_provider_name; platform_set_drvdata(pdev, pdata); pbi->platform_dev = pdev; pbi->video_signal_type = 0; pbi->m_ins_flag = 1; - if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_TXLX) - pbi->stat |= VP9_TRIGGER_FRAME_ENABLE; - - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) { - pbi->max_pic_w = 8192; - pbi->max_pic_h = 4608; - } else { + if (!vdec_is_support_4k()) { + pbi->max_pic_w = 1920; + pbi->max_pic_h = 1088; + } else if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SM1) { pbi->max_pic_w = 4096; pbi->max_pic_h = 2304; + } else { + pbi->max_pic_w = 8192; + pbi->max_pic_h = 4608; } -#if 1 + if ((debug & IGNORE_PARAM_FROM_CONFIG) == 0 && pdata->config_len) { #ifdef MULTI_INSTANCE_SUPPORT @@ -11057,6 +12193,7 @@ &config_val) == 0) { pbi->max_pic_h = config_val; } + if ((pbi->max_pic_w * pbi->max_pic_h) < (vp9_buf_width * vp9_buf_height)) { pbi->max_pic_w = vp9_buf_width; @@ -11105,6 +12242,8 @@ if (get_config_int(pdata->config, "HDRStaticInfo", &vf_dp.present_flag) == 0 && vf_dp.present_flag == 1) { + get_config_int(pdata->config, "signal_type", + &pbi->video_signal_type); get_config_int(pdata->config, "mG.x", &vf_dp.primaries[0][0]); get_config_int(pdata->config, "mG.y", @@ -11140,18 +12279,18 @@ vp9_print(pbi, 0, "transfer_val=%d\n",transfer_val); vf_dp.content_light_level = content_light_level; - pbi->video_signal_type = (1 << 29) + if (!pbi->video_signal_type) { + pbi->video_signal_type = (1 << 29) | (5 << 26) /* unspecified */ | (0 << 25) /* limit */ | (1 << 24) /* color available */ | (9 << 16) /* 2020 */ | (transfer_val << 8) /* 2084 */ | (9 << 0); /* 2020 */ + } } pbi->vf_dp = vf_dp; - } else -#endif - { + } else { if (pdata->sys_info) { pbi->vvp9_amstream_dec_info = *pdata->sys_info; if ((pbi->vvp9_amstream_dec_info.width != 0) && @@ -11166,14 +12305,29 @@ pbi->double_write_mode = double_write_mode; } + if (!pbi->is_used_v4l) { + vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name, + &vvp9_vf_provider, pbi); + } + if (no_head & 0x10) { pbi->no_head = (no_head & 0xf); } + pbi->endian = HEVC_CONFIG_LITTLE_ENDIAN; if (!pbi->is_used_v4l) { pbi->mem_map_mode = mem_map_mode; + if (is_support_vdec_canvas()) + pbi->endian = HEVC_CONFIG_BIG_ENDIAN; } - pbi->run_ready_min_buf_num = run_ready_min_buf_num; + if (endian) + pbi->endian = endian; + + if (pbi->is_used_v4l) + pbi->run_ready_min_buf_num = run_ready_min_buf_num - 1 ; + else + pbi->run_ready_min_buf_num = run_ready_min_buf_num; + if (is_oversize(pbi->max_pic_w, pbi->max_pic_h)) { pr_err("over size: %dx%d, probe failed\n", pbi->max_pic_w, pbi->max_pic_h); @@ -11190,10 +12344,20 @@ pbi->enable_fence, pbi->fence_usage); } - if (pbi->enable_fence) - pdata->sync.usage = pbi->fence_usage; + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_GXL || + pbi->double_write_mode == 0x10) + pbi->mmu_enable = 0; + else + pbi->mmu_enable = 1; - pbi->mmu_enable = 1; +#ifdef VP9_10B_MMU_DW + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T5D) { + pbi->dw_mmu_enable = + (get_double_write_mode(pbi) & 0x20) ? 1 : 0; + } else { + pbi->dw_mmu_enable = 0; + } +#endif video_signal_type = pbi->video_signal_type; if (pdata->sys_info) { @@ -11206,8 +12370,8 @@ pbi->low_latency_flag = 1; vp9_print(pbi, 0, - "no_head %d low_latency %d\n", - pbi->no_head, pbi->low_latency_flag); + "no_head %d low_latency %d, signal_type 0x%x\n", + pbi->no_head, pbi->low_latency_flag, pbi->video_signal_type); #if 0 pbi->buf_start = pdata->mem_start; pbi->buf_size = pdata->mem_end - pdata->mem_start + 1; @@ -11247,8 +12411,27 @@ } pbi->cma_dev = pdata->cma_dev; + + mutex_init(&pbi->fence_mutex); + + if (pbi->enable_fence) { + pdata->sync = vdec_sync_get(); + if (!pdata->sync) { + vp9_print(pbi, 0, "alloc fence timeline error\n"); + vp9_local_uninit(pbi); + uninit_mmu_buffers(pbi); + /* devm_kfree(&pdev->dev, (void *)pbi); */ + vfree((void *)pbi); + pdata->dec_status = NULL; + return -1; + } + pdata->sync->usage = pbi->fence_usage; + vdec_timeline_create(pdata->sync, DRIVER_NAME); + } + if (vvp9_init(pdata) < 0) { pr_info("\namvdec_vp9 init failed.\n"); + vdec_timeline_put(pdata->sync); vp9_local_uninit(pbi); uninit_mmu_buffers(pbi); /* devm_kfree(&pdev->dev, (void *)pbi); */ @@ -11276,11 +12459,6 @@ #endif pbi->pic_list_init_done2 = true; - if (pbi->enable_fence) { - /* creat timeline. */ - vdec_timeline_create(&pdata->sync, DRIVER_NAME); - } - return 0; } @@ -11319,7 +12497,7 @@ } if (pbi->enable_fence) - vdec_fence_release(pbi, &vdec->sync); + vdec_fence_release(pbi, vdec->sync); #ifdef DEBUG_PTS pr_info("pts missed %ld, pts hit %ld, duration %d\n", @@ -11328,6 +12506,8 @@ mem_map_mode = 0; /* devm_kfree(&pdev->dev, (void *)pbi); */ + if (is_rdma_enable()) + dma_free_coherent(amports_get_dma_device(), RDMA_SIZE, pbi->rdma_adr, pbi->rdma_phy_adr); vfree((void *)pbi); return 0; } @@ -11335,11 +12515,12 @@ static struct platform_driver ammvdec_vp9_driver = { .probe = ammvdec_vp9_probe, .remove = ammvdec_vp9_remove, +#ifdef CONFIG_PM + .suspend = amhevc_suspend, + .resume = amhevc_resume, +#endif .driver = { .name = MULTI_DRIVER_NAME, -#ifdef CONFIG_PM - .pm = &vp9_pm_ops, -#endif } }; #endif @@ -11361,8 +12542,6 @@ MC_PU32("slice_parse_begin", &slice_parse_begin), MC_PU32("i_only_flag", &i_only_flag), MC_PU32("error_handle_policy", &error_handle_policy), - MC_PU32("buf_alloc_width", &buf_alloc_width), - MC_PU32("buf_alloc_height", &buf_alloc_height), MC_PU32("buf_alloc_depth", &buf_alloc_depth), MC_PU32("buf_alloc_size", &buf_alloc_size), MC_PU32("buffer_mode", &buffer_mode), @@ -11388,13 +12567,20 @@ struct BuffInfo_s *p_buf_info; - if (vdec_is_support_4k()) { - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) - p_buf_info = &amvvp9_workbuff_spec[2]; + if (get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_TM2 && !is_cpu_tm2_revb()) { + if (vdec_is_support_4k()) { + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) + p_buf_info = &amvvp9_workbuff_spec[2]; + else + p_buf_info = &amvvp9_workbuff_spec[1]; + } else + p_buf_info = &amvvp9_workbuff_spec[0]; + } else { //get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_TM2 || is_cpu_tm2_revb() + if (vdec_is_support_4k()) + p_buf_info = &amvvp9_workbuff_spec[5]; else - p_buf_info = &amvvp9_workbuff_spec[1]; - } else - p_buf_info = &amvvp9_workbuff_spec[0]; + p_buf_info = &amvvp9_workbuff_spec[4]; + } init_buff_spec(NULL, p_buf_info); work_buf_size = @@ -11424,20 +12610,21 @@ return -ENODEV; } - if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) { - amvdec_vp9_profile.profile = - "8k, 10bit, dwrite, compressed, fence"; - } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL - /*&& get_cpu_major_id() != MESON_CPU_MAJOR_ID_GXLX*/ - && get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TXL) { - if (vdec_is_support_4k()) - amvdec_vp9_profile.profile = - "4k, 10bit, dwrite, compressed, fence"; - else - amvdec_vp9_profile.profile = - "10bit, dwrite, compressed, fence"; - } else { + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_GXL || + get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_TXL || + get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5) { amvdec_vp9_profile.name = "vp9_unsupport"; + } else if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5D)) { + amvdec_vp9_profile.profile = + "8k, 10bit, dwrite, compressed, fence, v4l-uvm"; + } else { + if (vdec_is_support_4k()) + amvdec_vp9_profile.profile = + "4k, 10bit, dwrite, compressed, fence, v4l-uvm"; + else + amvdec_vp9_profile.profile = + "10bit, dwrite, compressed, fence, v4l-uvm"; } if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) @@ -11449,6 +12636,7 @@ vcodec_profile_register(&amvdec_vp9_profile_mult); INIT_REG_NODE_CONFIGS("media.decoder", &vp9_node, "vp9", vp9_configs, CONFIG_FOR_RW); + vcodec_feature_register(VFORMAT_VP9, 0); return 0; } @@ -11518,12 +12706,6 @@ module_param(error_handle_policy, uint, 0664); MODULE_PARM_DESC(error_handle_policy, "\n amvdec_vp9 error_handle_policy\n"); -module_param(buf_alloc_width, uint, 0664); -MODULE_PARM_DESC(buf_alloc_width, "\n buf_alloc_width\n"); - -module_param(buf_alloc_height, uint, 0664); -MODULE_PARM_DESC(buf_alloc_height, "\n buf_alloc_height\n"); - module_param(buf_alloc_depth, uint, 0664); MODULE_PARM_DESC(buf_alloc_depth, "\n buf_alloc_depth\n"); @@ -11647,6 +12829,9 @@ module_param(force_pts_unstable, uint, 0664); MODULE_PARM_DESC(force_pts_unstable, "\n force_pts_unstable\n"); +module_param(v4l_bitstream_id_enable, uint, 0664); +MODULE_PARM_DESC(v4l_bitstream_id_enable, "\n v4l_bitstream_id_enable\n"); + module_init(amvdec_vp9_driver_init_module); module_exit(amvdec_vp9_driver_remove_module);
diff --git a/drivers/frame_provider/decoder_v4l/Makefile b/drivers/frame_provider/decoder_v4l/Makefile new file mode 100644 index 0000000..43e94df --- /dev/null +++ b/drivers/frame_provider/decoder_v4l/Makefile
@@ -0,0 +1,9 @@ +obj-y += mpeg12/ +obj-y += mpeg4/ +obj-y += h264_multi/ +obj-y += h265/ +obj-y += vp9/ +obj-y += mjpeg/ +obj-y += avs2/ +obj-y += avs_multi/ +obj-y += vav1/
diff --git a/drivers/frame_provider/decoder_v4l/avs2/Makefile b/drivers/frame_provider/decoder_v4l/avs2/Makefile new file mode 100644 index 0000000..9995065 --- /dev/null +++ b/drivers/frame_provider/decoder_v4l/avs2/Makefile
@@ -0,0 +1,2 @@ +obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_AVS2) += amvdec_avs2_v4l.o +amvdec_avs2_v4l-objs += vavs2.o avs2_bufmgr.o
diff --git a/drivers/frame_provider/decoder_v4l/avs2/avs2_bufmgr.c b/drivers/frame_provider/decoder_v4l/avs2/avs2_bufmgr.c new file mode 100644 index 0000000..91c3132 --- /dev/null +++ b/drivers/frame_provider/decoder_v4l/avs2/avs2_bufmgr.c
@@ -0,0 +1,2205 @@ +/* +* Copyright (C) 2017 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. +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, write to the Free Software Foundation, Inc., +* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +* Description: +*/ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/errno.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/spinlock.h> +#include <linux/platform_device.h> +#include <linux/amlogic/media/vfm/vframe.h> +#include <linux/amlogic/media/utils/amstream.h> +#include <linux/amlogic/media/utils/vformat.h> +#include <linux/amlogic/media/frame_sync/ptsserv.h> +#include <linux/amlogic/media/canvas/canvas.h> +#include <linux/amlogic/media/vfm/vframe_provider.h> +#include <linux/amlogic/media/vfm/vframe_receiver.h> +#include <linux/dma-mapping.h> +#include <linux/dma-contiguous.h> +#include <linux/slab.h> +//#include <linux/amlogic/tee.h> +#include <uapi/linux/tee.h> +#include <linux/sched/clock.h> +#include "../../../stream_input/amports/amports_priv.h" +#include <linux/amlogic/media/codec_mm/codec_mm.h> +#include "../../decoder/utils/decoder_mmu_box.h" +#include "../../decoder/utils/decoder_bmmu_box.h" +#include "avs2_global.h" + +#include <linux/amlogic/media/utils/vdec_reg.h> +#include "../../decoder/utils/vdec.h" +#include "../../decoder/utils/amvdec.h" + +#undef pr_info +#define pr_info printk + +#define assert(chk_cond) {\ + if (!(chk_cond))\ + pr_info("error line %d\n", __LINE__);\ + while (!(chk_cond))\ + ;\ +} + +int16_t get_param(uint16_t value, int8_t *print_info) +{ + if (is_avs2_print_param()) + pr_info("%s = %x\n", print_info, value); + return (int16_t)value; +} + +void readAlfCoeff(struct avs2_decoder *avs2_dec, struct ALFParam_s *Alfp) +{ + int32_t pos; + union param_u *rpm_param = &avs2_dec->param; + + int32_t f = 0, symbol, pre_symbole; + const int32_t numCoeff = (int32_t)ALF_MAX_NUM_COEF; + + switch (Alfp->componentID) { + case ALF_Cb: + case ALF_Cr: { + for (pos = 0; pos < numCoeff; pos++) { + if (Alfp->componentID == ALF_Cb) + Alfp->coeffmulti[0][pos] = + get_param( + rpm_param->alf.alf_cb_coeffmulti[pos], + "Chroma ALF coefficients"); + else + Alfp->coeffmulti[0][pos] = + get_param( + rpm_param->alf.alf_cr_coeffmulti[pos], + "Chroma ALF coefficients"); +#if Check_Bitstream + if (pos <= 7) + assert(Alfp->coeffmulti[0][pos] >= -64 + && Alfp->coeffmulti[0][pos] <= 63); + if (pos == 8) + assert(Alfp->coeffmulti[0][pos] >= -1088 + && Alfp->coeffmulti[0][pos] <= 1071); +#endif + } + } + break; + case ALF_Y: { + int32_t region_distance_idx = 0; + Alfp->filters_per_group = + get_param(rpm_param->alf.alf_filters_num_m_1, + "ALF_filter_number_minus_1"); +#if Check_Bitstream + assert(Alfp->filters_per_group >= 0 + && Alfp->filters_per_group <= 15); +#endif + Alfp->filters_per_group = Alfp->filters_per_group + 1; + + memset(Alfp->filterPattern, 0, NO_VAR_BINS * sizeof(int32_t)); + pre_symbole = 0; + symbol = 0; + for (f = 0; f < Alfp->filters_per_group; f++) { + if (f > 0) { + if (Alfp->filters_per_group != 16) { + symbol = + get_param(rpm_param->alf.region_distance + [region_distance_idx++], + "Region distance"); + } else { + symbol = 1; + } + Alfp->filterPattern[symbol + pre_symbole] = 1; + pre_symbole = symbol + pre_symbole; + } + + for (pos = 0; pos < numCoeff; pos++) { + Alfp->coeffmulti[f][pos] = + get_param( + rpm_param->alf.alf_y_coeffmulti[f][pos], + "Luma ALF coefficients"); +#if Check_Bitstream + if (pos <= 7) + assert( + Alfp->coeffmulti[f][pos] + >= -64 && + Alfp->coeffmulti[f][pos] + <= 63); + if (pos == 8) + assert( + Alfp->coeffmulti[f][pos] + >= -1088 && + Alfp->coeffmulti[f][pos] + <= 1071); +#endif + + } + } + +#if Check_Bitstream + assert(pre_symbole >= 0 && pre_symbole <= 15); + +#endif + } + break; + default: { + pr_info("Not a legal component ID\n"); + assert(0); + return; /* exit(-1);*/ + } + } +} + +void Read_ALF_param(struct avs2_decoder *avs2_dec) +{ + struct inp_par *input = &avs2_dec->input; + struct ImageParameters_s *img = &avs2_dec->img; + union param_u *rpm_param = &avs2_dec->param; + int32_t compIdx; + if (input->alf_enable) { + img->pic_alf_on[0] = + get_param( + rpm_param->alf.picture_alf_enable_Y, + "alf_pic_flag_Y"); + img->pic_alf_on[1] = + get_param( + rpm_param->alf.picture_alf_enable_Cb, + "alf_pic_flag_Cb"); + img->pic_alf_on[2] = + get_param( + rpm_param->alf.picture_alf_enable_Cr, + "alf_pic_flag_Cr"); + + avs2_dec->m_alfPictureParam[ALF_Y].alf_flag + = img->pic_alf_on[ALF_Y]; + avs2_dec->m_alfPictureParam[ALF_Cb].alf_flag + = img->pic_alf_on[ALF_Cb]; + avs2_dec->m_alfPictureParam[ALF_Cr].alf_flag + = img->pic_alf_on[ALF_Cr]; + if (img->pic_alf_on[0] + || img->pic_alf_on[1] + || img->pic_alf_on[2]) { + for (compIdx = 0; + compIdx < NUM_ALF_COMPONENT; + compIdx++) { + if (img->pic_alf_on[compIdx]) { + readAlfCoeff( + avs2_dec, + &avs2_dec->m_alfPictureParam[compIdx]); + } + } + } + } + +} + +void Get_SequenceHeader(struct avs2_decoder *avs2_dec) +{ + struct inp_par *input = &avs2_dec->input; + struct ImageParameters_s *img = &avs2_dec->img; + struct Video_Com_data_s *hc = &avs2_dec->hc; + struct Video_Dec_data_s *hd = &avs2_dec->hd; + union param_u *rpm_param = &avs2_dec->param; + /*int32_t i, j;*/ + + /*fpr_info(stdout, "Sequence Header\n");*/ + /*memcpy(currStream->streamBuffer, buf, length);*/ + /*currStream->code_len = currStream->bitstream_length = length;*/ + /*currStream->read_len = currStream->frame_bitoffset = (startcodepos + + 1) * 8;*/ + + input->profile_id = + get_param(rpm_param->p.profile_id, "profile_id"); + input->level_id = + get_param(rpm_param->p.level_id, "level_id"); + hd->progressive_sequence = + get_param( + rpm_param->p.progressive_sequence, + "progressive_sequence"); +#if INTERLACE_CODING + hd->is_field_sequence = + get_param( + rpm_param->p.is_field_sequence, + "field_coded_sequence"); +#endif +#if HALF_PIXEL_COMPENSATION || HALF_PIXEL_CHROMA + img->is_field_sequence = hd->is_field_sequence; +#endif + hd->horizontal_size = + get_param(rpm_param->p.horizontal_size, "horizontal_size"); + hd->vertical_size = + get_param(rpm_param->p.vertical_size, "vertical_size"); + input->chroma_format = + get_param(rpm_param->p.chroma_format, "chroma_format"); + input->output_bit_depth = 8; + input->sample_bit_depth = 8; + hd->sample_precision = 1; + if (input->profile_id == BASELINE10_PROFILE) { /* 10bit profile (0x52)*/ + input->output_bit_depth = + get_param(rpm_param->p.sample_precision, + "sample_precision"); + input->output_bit_depth = + 6 + (input->output_bit_depth) * 2; + input->sample_bit_depth = + get_param(rpm_param->p.encoding_precision, + "encoding_precision"); + input->sample_bit_depth = + 6 + (input->sample_bit_depth) * 2; + } else { /* other profile*/ + hd->sample_precision = + get_param(rpm_param->p.sample_precision, + "sample_precision"); + } + hd->aspect_ratio_information = + get_param(rpm_param->p.aspect_ratio_information, + "aspect_ratio_information"); + hd->frame_rate_code = + get_param(rpm_param->p.frame_rate_code, "frame_rate_code"); + + hd->bit_rate_lower = + get_param(rpm_param->p.bit_rate_lower, "bit_rate_lower"); + /*hd->marker_bit = get_param(rpm_param->p.marker_bit, + * "marker bit");*/ + /*CHECKMARKERBIT*/ + hd->bit_rate_upper = + get_param(rpm_param->p.bit_rate_upper, "bit_rate_upper"); + hd->low_delay = + get_param(rpm_param->p.low_delay, "low_delay"); + /*hd->marker_bit = + get_param(rpm_param->p.marker_bit2, + "marker bit");*/ + /*CHECKMARKERBIT*/ +#if M3480_TEMPORAL_SCALABLE + hd->temporal_id_exist_flag = + get_param(rpm_param->p.temporal_id_exist_flag, + "temporal_id exist flag"); /*get + Extention Flag*/ +#endif + /*u_v(18, "bbv buffer size");*/ + input->g_uiMaxSizeInBit = + get_param(rpm_param->p.g_uiMaxSizeInBit, + "Largest Coding Block Size"); + + + /*hd->background_picture_enable = 0x01 ^ + (get_param(rpm_param->p.avs2_seq_flags, + "background_picture_disable") + >> BACKGROUND_PICTURE_DISABLE_BIT) & 0x1;*/ + /*rain???*/ + hd->background_picture_enable = 0x01 ^ + ((get_param(rpm_param->p.avs2_seq_flags, + "background_picture_disable") + >> BACKGROUND_PICTURE_DISABLE_BIT) & 0x1); + + + hd->b_dmh_enabled = 1; + + hd->b_mhpskip_enabled = + get_param(rpm_param->p.avs2_seq_flags >> B_MHPSKIP_ENABLED_BIT, + "mhpskip enabled") & 0x1; + hd->dhp_enabled = + get_param(rpm_param->p.avs2_seq_flags >> DHP_ENABLED_BIT, + "dhp enabled") & 0x1; + hd->wsm_enabled = + get_param(rpm_param->p.avs2_seq_flags >> WSM_ENABLED_BIT, + "wsm enabled") & 0x1; + + img->inter_amp_enable = + get_param(rpm_param->p.avs2_seq_flags >> INTER_AMP_ENABLE_BIT, + "Asymmetric Motion Partitions") & 0x1; + input->useNSQT = + get_param(rpm_param->p.avs2_seq_flags >> USENSQT_BIT, + "useNSQT") & 0x1; + input->useSDIP = + get_param(rpm_param->p.avs2_seq_flags >> USESDIP_BIT, + "useNSIP") & 0x1; + + hd->b_secT_enabled = + get_param(rpm_param->p.avs2_seq_flags >> B_SECT_ENABLED_BIT, + "secT enabled") & 0x1; + + input->sao_enable = + get_param(rpm_param->p.avs2_seq_flags >> SAO_ENABLE_BIT, + "SAO Enable Flag") & 0x1; + input->alf_enable = + get_param(rpm_param->p.avs2_seq_flags >> ALF_ENABLE_BIT, + "ALF Enable Flag") & 0x1; + hd->b_pmvr_enabled = + get_param(rpm_param->p.avs2_seq_flags >> B_PMVR_ENABLED_BIT, + "pmvr enabled") & 0x1; + + + hd->gop_size = get_param(rpm_param->p.num_of_RPS, + "num_of_RPS"); +#if Check_Bitstream + /*assert(hd->gop_size<=32);*/ +#endif + + if (hd->low_delay == 0) { + hd->picture_reorder_delay = + get_param(rpm_param->p.picture_reorder_delay, + "picture_reorder_delay"); + } + + input->crossSliceLoopFilter = + get_param(rpm_param->p.avs2_seq_flags + >> CROSSSLICELOOPFILTER_BIT, + "Cross Loop Filter Flag") & 0x1; + +#if BCBR + if ((input->profile_id == SCENE_PROFILE || + input->profile_id == SCENE10_PROFILE) && + hd->background_picture_enable) { + hd->bcbr_enable = u_v(1, + "block_composed_background_picture_enable"); + u_v(1, "reserved bits"); + } else { + hd->bcbr_enable = 0; + u_v(2, "reserved bits"); + } +#else + /*u_v(2, "reserved bits");*/ +#endif + + img->width = hd->horizontal_size; + img->height = hd->vertical_size; + img->width_cr = (img->width >> 1); + + if (input->chroma_format == 1) { + img->height_cr + = (img->height >> 1); + } + + img->PicWidthInMbs = img->width / MIN_CU_SIZE; + img->PicHeightInMbs = img->height / MIN_CU_SIZE; + img->PicSizeInMbs = img->PicWidthInMbs * img->PicHeightInMbs; + img->buf_cycle = input->buf_cycle + 1; + img->max_mb_nr = (img->width * img->height) + / (MIN_CU_SIZE * MIN_CU_SIZE); + +#ifdef AML +avs2_dec->lcu_size = + get_param(rpm_param->p.lcu_size, "lcu_size"); +avs2_dec->lcu_size = 1<<(avs2_dec->lcu_size); +#endif +hc->seq_header++; +} + + +void Get_I_Picture_Header(struct avs2_decoder *avs2_dec) +{ + struct ImageParameters_s *img = &avs2_dec->img; + struct Video_Dec_data_s *hd = &avs2_dec->hd; + union param_u *rpm_param = &avs2_dec->param; + +#if RD1501_FIX_BG /*//Longfei.Wang@mediatek.com*/ + hd->background_picture_flag = 0; + hd->background_picture_output_flag = 0; + img->typeb = 0; +#endif + + hd->time_code_flag = + get_param(rpm_param->p.time_code_flag, + "time_code_flag"); + + if (hd->time_code_flag) { + hd->time_code = + get_param(rpm_param->p.time_code, + "time_code"); + } + if (hd->background_picture_enable) { + hd->background_picture_flag = + get_param(rpm_param->p.background_picture_flag, + "background_picture_flag"); + + if (hd->background_picture_flag) { + img->typeb = + BACKGROUND_IMG; + } else { + img->typeb = 0; + } + + if (img->typeb == BACKGROUND_IMG) { + hd->background_picture_output_flag = + get_param( + rpm_param->p.background_picture_output_flag, + "background_picture_output_flag"); + } + } + + + { + img->coding_order = + get_param(rpm_param->p.coding_order, + "coding_order"); + + + +#if M3480_TEMPORAL_SCALABLE + if (hd->temporal_id_exist_flag == 1) { + hd->cur_layer = + get_param(rpm_param->p.cur_layer, + "temporal_id"); + } +#endif +#if RD1501_FIX_BG /*Longfei.Wang@mediatek.com*/ + if (hd->low_delay == 0 + && !(hd->background_picture_flag && + !hd->background_picture_output_flag)) { /*cdp*/ +#else + if (hd->low_delay == 0 && + !(hd->background_picture_enable && + !hd->background_picture_output_flag)) { /*cdp*/ +#endif + hd->displaydelay = + get_param(rpm_param->p.displaydelay, + "picture_output_delay"); + } + + } + { + int32_t RPS_idx;/* = (img->coding_order-1) % gop_size;*/ + int32_t predict; + int32_t j; + predict = + get_param(rpm_param->p.predict, + "use RCS in SPS"); + /*if (predict) {*/ + RPS_idx = + get_param(rpm_param->p.RPS_idx, + "predict for RCS"); + /* hd->curr_RPS = hd->decod_RPS[RPS_idx];*/ + /*} else {*/ + /*gop size16*/ + hd->curr_RPS.referd_by_others = + get_param(rpm_param->p.referd_by_others_cur, + "refered by others"); + hd->curr_RPS.num_of_ref = + get_param(rpm_param->p.num_of_ref_cur, + "num of reference picture"); + for (j = 0; j < hd->curr_RPS.num_of_ref; j++) { + hd->curr_RPS.ref_pic[j] = + get_param(rpm_param->p.ref_pic_cur[j], + "delta COI of ref pic"); + } + hd->curr_RPS.num_to_remove = + get_param(rpm_param->p.num_to_remove_cur, + "num of removed picture"); +#ifdef SANITY_CHECK + if (hd->curr_RPS.num_to_remove > MAXREF) { + hd->curr_RPS.num_to_remove = MAXREF; + pr_info("Warning, %s: num_to_remove %d beyond range, force to MAXREF\n", + __func__, hd->curr_RPS.num_to_remove); + } +#endif + + for (j = 0; j < hd->curr_RPS.num_to_remove; j++) { + hd->curr_RPS.remove_pic[j] = + get_param( + rpm_param->p.remove_pic_cur[j], + "delta COI of removed pic"); + } + /*u_v(1, "marker bit");*/ + + /*}*/ + } + /*xyji 12.23*/ + if (hd->low_delay) { + /*ue_v( + "bbv check times");*/ + } + + hd->progressive_frame = + get_param(rpm_param->p.progressive_frame, + "progressive_frame"); + + if (!hd->progressive_frame) { + img->picture_structure = + get_param(rpm_param->p.picture_structure, + "picture_structure"); + } else { + img->picture_structure + = 1; + } + + hd->top_field_first = + get_param(rpm_param->p.top_field_first, + "top_field_first"); + hd->repeat_first_field = + get_param(rpm_param->p.repeat_first_field, + "repeat_first_field"); +#if INTERLACE_CODING + if (hd->is_field_sequence) { + hd->is_top_field = + get_param(rpm_param->p.is_top_field, + "is_top_field"); +#if HALF_PIXEL_COMPENSATION || HALF_PIXEL_CHROMA + img->is_top_field = hd->is_top_field; +#endif + } +#endif + + + img->qp = hd->picture_qp; + + img->type = I_IMG; + +} + +/* + * Function:pb picture header + * Input: + * Output: + * Return: + * Attention: + */ + +void Get_PB_Picture_Header(struct avs2_decoder *avs2_dec) +{ + struct ImageParameters_s *img = &avs2_dec->img; + struct Video_Dec_data_s *hd = &avs2_dec->hd; + union param_u *rpm_param = &avs2_dec->param; + + + /*u_v(32, "bbv delay");*/ + + hd->picture_coding_type = + get_param(rpm_param->p.picture_coding_type, + "picture_coding_type"); + + if (hd->background_picture_enable && + (hd->picture_coding_type == 1 || + hd->picture_coding_type == 3)) { + if (hd->picture_coding_type == 1) { + hd->background_pred_flag = + get_param( + rpm_param->p.background_pred_flag, + "background_pred_flag"); + } else { + hd->background_pred_flag = 0; + } + if (hd->background_pred_flag == 0) { + + hd->background_reference_enable = + get_param( + rpm_param-> + p.background_reference_enable, + "background_reference_enable"); + + } else { +#if RD170_FIX_BG + hd->background_reference_enable = 1; +#else + hd->background_reference_enable = 0; +#endif + } + + } else { + hd->background_pred_flag = 0; + hd->background_reference_enable = 0; + } + + + + if (hd->picture_coding_type == 1) { + img->type = + P_IMG; + } else if (hd->picture_coding_type == 3) { + img->type = + F_IMG; + } else { + img->type = + B_IMG; + } + + + if (hd->picture_coding_type == 1 && + hd->background_pred_flag) { + img->typeb = BP_IMG; + } else { + img->typeb = 0; + } + + + { + img->coding_order = + get_param( + rpm_param->p.coding_order, + "coding_order"); + + +#if M3480_TEMPORAL_SCALABLE + if (hd->temporal_id_exist_flag == 1) { + hd->cur_layer = + get_param(rpm_param->p.cur_layer, + "temporal_id"); + } +#endif + + if (hd->low_delay == 0) { + hd->displaydelay = + get_param(rpm_param->p.displaydelay, + "displaydelay"); + } + } + { + int32_t RPS_idx;/* = (img->coding_order-1) % gop_size;*/ + int32_t predict; + predict = + get_param(rpm_param->p.predict, + "use RPS in SPS"); + if (predict) { + RPS_idx = + get_param(rpm_param->p.RPS_idx, + "predict for RPS"); + hd->curr_RPS = hd->decod_RPS[RPS_idx]; + } /*else*/ + { + /*gop size16*/ + int32_t j; + hd->curr_RPS.referd_by_others = + get_param( + rpm_param->p.referd_by_others_cur, + "refered by others"); + hd->curr_RPS.num_of_ref = + get_param( + rpm_param->p.num_of_ref_cur, + "num of reference picture"); + for (j = 0; j < hd->curr_RPS.num_of_ref; j++) { + hd->curr_RPS.ref_pic[j] = + get_param( + rpm_param->p.ref_pic_cur[j], + "delta COI of ref pic"); + } + hd->curr_RPS.num_to_remove = + get_param( + rpm_param->p.num_to_remove_cur, + "num of removed picture"); +#ifdef SANITY_CHECK + if (hd->curr_RPS.num_to_remove > MAXREF) { + hd->curr_RPS.num_to_remove = MAXREF; + pr_info("Warning, %s: num_to_remove %d beyond range, force to MAXREF\n", + __func__, hd->curr_RPS.num_to_remove); + } +#endif + for (j = 0; + j < hd->curr_RPS.num_to_remove; j++) { + hd->curr_RPS.remove_pic[j] = + get_param( + rpm_param->p.remove_pic_cur[j], + "delta COI of removed pic"); + } + /*u_v(1, "marker bit");*/ + + } + } + /*xyji 12.23*/ + if (hd->low_delay) { + /*ue_v( + "bbv check times");*/ + } + + hd->progressive_frame = + get_param(rpm_param->p.progressive_frame, + "progressive_frame"); + + if (!hd->progressive_frame) { + img->picture_structure = + get_param(rpm_param->p.picture_structure, + "picture_structure"); + } else { + img->picture_structure = 1; + } + + hd->top_field_first = + get_param(rpm_param->p.top_field_first, + "top_field_first"); + hd->repeat_first_field = + get_param(rpm_param->p.repeat_first_field, + "repeat_first_field"); +#if INTERLACE_CODING + if (hd->is_field_sequence) { + hd->is_top_field = + get_param(rpm_param->p.is_top_field, + "is_top_field"); +#if HALF_PIXEL_COMPENSATION || HALF_PIXEL_CHROMA + img->is_top_field = hd->is_top_field; +#endif + /*u_v(1, "reserved bit for interlace coding");*/ + } +#endif + +#if Check_Bitstream + /*assert(hd->picture_qp>=0&&hd->picture_qp<=(63 + 8 * + (input->sample_bit_depth - 8)));*/ +#endif + + img->random_access_decodable_flag = + get_param(rpm_param->p.random_access_decodable_flag, + "random_access_decodable_flag"); + + img->qp = hd->picture_qp; +} + + + + +void calc_picture_distance(struct avs2_decoder *avs2_dec) +{ + struct ImageParameters_s *img = &avs2_dec->img; + struct Video_Com_data_s *hc = &avs2_dec->hc; + struct Video_Dec_data_s *hd = &avs2_dec->hd; + /* + union param_u *rpm_param = &avs2_dec->param; + + for POC mode 0: + uint32_t MaxPicDistanceLsb = (1 << 8); + */ + if (img->coding_order < img->PrevPicDistanceLsb) + + { + int32_t i, j; + + hc->total_frames++; + for (i = 0; i < avs2_dec->ref_maxbuffer; i++) { + if ( + avs2_dec->fref[i]->imgtr_fwRefDistance + >= 0) { + avs2_dec->fref[i]-> + imgtr_fwRefDistance -= 256; + avs2_dec->fref[i]-> + imgcoi_ref -= 256; + } +#if RD170_FIX_BG + for (j = 0; j < MAXREF; j++) { +#else + for (j = 0; j < 4; j++) { +#endif + avs2_dec->fref[i]->ref_poc[j] -= 256; + } + } + for (i = 0; i < avs2_dec->outprint.buffer_num; i++) { + avs2_dec->outprint.stdoutdata[i].framenum -= 256; + avs2_dec->outprint.stdoutdata[i].tr -= 256; + } + + hd->last_output -= 256; + hd->curr_IDRtr -= 256; + hd->curr_IDRcoi -= 256; + hd->next_IDRtr -= 256; + hd->next_IDRcoi -= 256; + } + if (hd->low_delay == 0) { + img->tr = img->coding_order + + hd->displaydelay - hd->picture_reorder_delay; + } else { + img->tr = + img->coding_order; + } + +#if REMOVE_UNUSED + img->pic_distance = img->tr; +#else + img->pic_distance = img->tr % 256; +#endif + hc->picture_distance = img->pic_distance; + +} + +int32_t avs2_init_global_buffers(struct avs2_decoder *avs2_dec) +{ + struct inp_par *input = &avs2_dec->input; + struct ImageParameters_s *img = &avs2_dec->img; + struct Video_Com_data_s *hc = &avs2_dec->hc; + + int32_t refnum; + + int32_t memory_size = 0; + /* +int32_t img_height = (hd->vertical_size + img->auto_crop_bottom); + */ + img->buf_cycle = input->buf_cycle + 1; + + img->buf_cycle *= 2; + + hc->background_ref = hc->backgroundReferenceFrame; + + for (refnum = 0; refnum < REF_MAXBUFFER; refnum++) { + avs2_dec->fref[refnum] = &avs2_dec->frm_pool[refnum]; + + /*//avs2_dec->fref[i] memory allocation*/ + if (is_avs2_print_bufmgr_detail()) + pr_info("[t] avs2_dec->fref[%d]@0x%p\n", + refnum, avs2_dec->fref[refnum]); + avs2_dec->fref[refnum]->imgcoi_ref = -257; + avs2_dec->fref[refnum]->is_output = -1; + avs2_dec->fref[refnum]->refered_by_others = -1; + avs2_dec->fref[refnum]-> + imgtr_fwRefDistance = -256; + init_frame_t(avs2_dec->fref[refnum]); +#ifdef AML + avs2_dec->fref[refnum]->index = refnum; +#endif + } +#ifdef AML + avs2_dec->f_bg = NULL; + + avs2_dec->m_bg = &avs2_dec->frm_pool[REF_MAXBUFFER]; + /*///avs2_dec->fref[i] memory allocation*/ + if (is_avs2_print_bufmgr_detail()) + pr_info("[t] avs2_dec->m_bg@0x%p\n", + avs2_dec->m_bg); + avs2_dec->m_bg->imgcoi_ref = -257; + avs2_dec->m_bg->is_output = -1; + avs2_dec->m_bg->refered_by_others = -1; + avs2_dec->m_bg->imgtr_fwRefDistance = -256; + init_frame_t(avs2_dec->m_bg); + avs2_dec->m_bg->index = refnum; +#endif + +#if BCBR + /*init BCBR related*/ + img->iNumCUsInFrame = + ((img->width + MAX_CU_SIZE - 1) / MAX_CU_SIZE) + * ((img->height + MAX_CU_SIZE - 1) + / MAX_CU_SIZE); + /*img->BLCUidx = (int32_t*) calloc( + img->iNumCUsInFrame, sizeof(int32_t));*/ + /*memset( img->BLCUidx, 0, img->iNumCUsInFrame);*/ +#endif + return memory_size; +} + +#ifdef AML +static void free_unused_buffers(struct avs2_decoder *avs2_dec) +{ + struct inp_par *input = &avs2_dec->input; + struct ImageParameters_s *img = &avs2_dec->img; + struct Video_Com_data_s *hc = &avs2_dec->hc; + + int32_t refnum; + + img->buf_cycle = input->buf_cycle + 1; + + img->buf_cycle *= 2; + + hc->background_ref = hc->backgroundReferenceFrame; + + for (refnum = 0; refnum < REF_MAXBUFFER; refnum++) { +#ifndef NO_DISPLAY + if (avs2_dec->fref[refnum]->vf_ref > 0 || + avs2_dec->fref[refnum]->to_prepare_disp) + continue; +#endif + if (is_avs2_print_bufmgr_detail()) + pr_info("%s[t] avs2_dec->fref[%d]@0x%p\n", + __func__, refnum, avs2_dec->fref[refnum]); + avs2_dec->fref[refnum]->imgcoi_ref = -257; + avs2_dec->fref[refnum]->is_output = -1; + avs2_dec->fref[refnum]->refered_by_others = -1; + avs2_dec->fref[refnum]-> + imgtr_fwRefDistance = -256; + memset(avs2_dec->fref[refnum]->ref_poc, 0, + sizeof(avs2_dec->fref[refnum]->ref_poc)); + } + avs2_dec->f_bg = NULL; + + if (is_avs2_print_bufmgr_detail()) + pr_info("%s[t] avs2_dec->m_bg@0x%p\n", + __func__, avs2_dec->m_bg); + avs2_dec->m_bg->imgcoi_ref = -257; + avs2_dec->m_bg->is_output = -1; + avs2_dec->m_bg->refered_by_others = -1; + avs2_dec->m_bg->imgtr_fwRefDistance = -256; + memset(avs2_dec->m_bg->ref_poc, 0, + sizeof(avs2_dec->m_bg->ref_poc)); + +#if BCBR + /*init BCBR related*/ + img->iNumCUsInFrame = + ((img->width + MAX_CU_SIZE - 1) / MAX_CU_SIZE) + * ((img->height + MAX_CU_SIZE - 1) + / MAX_CU_SIZE); + /*img->BLCUidx = (int32_t*) calloc( + img->iNumCUsInFrame, sizeof(int32_t));*/ + /*memset( img->BLCUidx, 0, img->iNumCUsInFrame);*/ +#endif +} +#endif + +void init_frame_t(struct avs2_frame_s *currfref) +{ + memset(currfref, 0, sizeof(struct avs2_frame_s)); + currfref->imgcoi_ref = -257; + currfref->is_output = -1; + currfref->refered_by_others = -1; + currfref->imgtr_fwRefDistance = -256; + memset(currfref->ref_poc, 0, sizeof(currfref->ref_poc)); +} + +void get_reference_list_info(struct avs2_decoder *avs2_dec, int8_t *str) +{ + struct ImageParameters_s *img = &avs2_dec->img; + struct Video_Com_data_s *hc = &avs2_dec->hc; + + int8_t str_tmp[16]; + int32_t i; + /* int32_t poc = hc->f_rec->imgtr_fwRefDistance; + fred.chiu@mediatek.com*/ + + if (img->num_of_references > 0) { + strcpy(str, "["); + for (i = 0; i < img->num_of_references; i++) { +#if RD1510_FIX_BG + if (img->type == B_IMG) { + sprintf(str_tmp, "%4d ", + hc->f_rec-> + ref_poc[ + img->num_of_references - 1 - i]); + } else { + sprintf(str_tmp, "%4d ", + hc->f_rec->ref_poc[i]); + } +#else + sprintf(str_tmp, "%4d ", + avs2_dec->fref[i]->imgtr_fwRefDistance); +#endif + + str_tmp[5] = '\0'; + strcat(str, str_tmp); + } + strcat(str, "]"); + } else { + str[0] = '\0'; + } +} + +void prepare_RefInfo(struct avs2_decoder *avs2_dec) +{ + struct ImageParameters_s *img = &avs2_dec->img; + struct Video_Com_data_s *hc = &avs2_dec->hc; + struct Video_Dec_data_s *hd = &avs2_dec->hd; + + int32_t i, j; + int32_t ii; + struct avs2_frame_s *tmp_fref; + + /*update IDR frame*/ + if (img->tr > hd->next_IDRtr && hd->curr_IDRtr != hd->next_IDRtr) { + hd->curr_IDRtr = hd->next_IDRtr; + hd->curr_IDRcoi = hd->next_IDRcoi; + } + /* re-order the ref buffer according to RPS*/ + img->num_of_references = hd->curr_RPS.num_of_ref; + +#if 1 + /*rain*/ + if (is_avs2_print_bufmgr_detail()) { + pr_info("%s: coding_order is %d, curr_IDRcoi is %d\n", + __func__, img->coding_order, hd->curr_IDRcoi); + for (ii = 0; ii < MAXREF; ii++) { + pr_info("ref_pic(%d)=%d\n", + ii, hd->curr_RPS.ref_pic[ii]); + } + for (ii = 0; ii < avs2_dec->ref_maxbuffer; ii++) { + pr_info( + "fref[%d]: index %d imgcoi_ref %d imgtr_fwRefDistance %d\n", + ii, avs2_dec->fref[ii]->index, + avs2_dec->fref[ii]->imgcoi_ref, + avs2_dec->fref[ii]->imgtr_fwRefDistance); + } + } +#endif + + for (i = 0; i < hd->curr_RPS.num_of_ref; i++) { + /*int32_t accumulate = 0;*/ + /* copy tmp_fref from avs2_dec->fref[i] */ + tmp_fref = avs2_dec->fref[i]; + +#if REMOVE_UNUSED + for (j = i; j < avs2_dec->ref_maxbuffer; j++) { + /*/////////////to be modified IDR*/ + if (avs2_dec->fref[j]->imgcoi_ref == + img->coding_order - + hd->curr_RPS.ref_pic[i]) { + break; + } + } +#else + + for (j = i; j < avs2_dec->ref_maxbuffer; j++) { + /*/////////////to be modified IDR*/ + int32_t k , tmp_tr; + for (k = 0; k < avs2_dec->ref_maxbuffer; k++) { + if (((int32_t)img->coding_order - + (int32_t)hd->curr_RPS.ref_pic[i]) == + avs2_dec->fref[k]->imgcoi_ref && + avs2_dec->fref[k]->imgcoi_ref >= -256) { + break; + } + } + if (k == avs2_dec->ref_maxbuffer) { + tmp_tr = + -1-1; + } else { + tmp_tr = + avs2_dec->fref[k]->imgtr_fwRefDistance; + } + if (tmp_tr < hd->curr_IDRtr) { + hd->curr_RPS.ref_pic[i] = + img->coding_order - hd->curr_IDRcoi; + + for (k = 0; k < i; k++) { + if (hd->curr_RPS.ref_pic[k] == + hd->curr_RPS.ref_pic[i]) { + accumulate++; + break; + } + } + } + if (avs2_dec->fref[j]->imgcoi_ref == + img->coding_order - hd->curr_RPS.ref_pic[i]) { + break; + } + } + if (j == avs2_dec->ref_maxbuffer || accumulate) + img->num_of_references--; +#endif + if (j != avs2_dec->ref_maxbuffer) { + /* copy avs2_dec->fref[i] from avs2_dec->fref[j] */ + avs2_dec->fref[i] = avs2_dec->fref[j]; + /* copy avs2_dec->fref[j] from ferf[tmp] */ + avs2_dec->fref[j] = tmp_fref; + if (is_avs2_print_bufmgr_detail()) { + pr_info("%s, switch %d %d: ", __func__, i, j); + for (ii = 0; ii < hd->curr_RPS.num_of_ref + || ii <= j; ii++) + pr_info("%d ", + avs2_dec->fref[ii]->index); + pr_info("\n"); + } + } + } + if (img->type == B_IMG && + (avs2_dec->fref[0]->imgtr_fwRefDistance <= img->tr + || avs2_dec->fref[1]->imgtr_fwRefDistance >= img->tr)) { + + pr_info("wrong reference configuration for B frame\n"); + pr_info( + "fref0 imgtr_fwRefDistance %d, fref1 imgtr_fwRefDistance %d, img->tr %d\n", + avs2_dec->fref[0]->imgtr_fwRefDistance, + avs2_dec->fref[1]->imgtr_fwRefDistance, + img->tr); + hc->f_rec->error_mark = 1; + avs2_dec->bufmgr_error_flag = 1; + return; /* exit(-1);*/ + /*******************************************/ + } + +#if !FIX_PROFILE_LEVEL_DPB_RPS_1 + /* delete the frame that will never be used*/ + for (i = 0; i < hd->curr_RPS.num_to_remove; i++) { + for (j = 0; j < avs2_dec->ref_maxbuffer; j++) { + if (avs2_dec->fref[j]->imgcoi_ref >= -256 + && avs2_dec->fref[j]->imgcoi_ref + == img->coding_order - + hd->curr_RPS.remove_pic[i]) { + break; + } + } + if (j < avs2_dec->ref_maxbuffer && + j >= img->num_of_references) { + avs2_dec->fref[j]->imgcoi_ref = -257; +#if M3480_TEMPORAL_SCALABLE + avs2_dec->fref[j]->temporal_id = -1; +#endif + if (avs2_dec->fref[j]->is_output == -1) { + avs2_dec->fref[j]-> + imgtr_fwRefDistance = -256; + } + } + } +#endif + + /* add inter-view reference picture*/ + + /* add current frame to ref buffer*/ + for (i = 0; i < avs2_dec->ref_maxbuffer; i++) { + if ((avs2_dec->fref[i]->imgcoi_ref < -256 + || abs(avs2_dec->fref[i]-> + imgtr_fwRefDistance - img->tr) >= 128) + && avs2_dec->fref[i]->is_output == -1 + && avs2_dec->fref[i]->bg_flag == 0 +#ifndef NO_DISPLAY + && avs2_dec->fref[i]->vf_ref == 0 + && avs2_dec->fref[i]->to_prepare_disp == 0 +#endif + ) { + break; + } + } + if (i == avs2_dec->ref_maxbuffer) { + pr_info( + "%s, warning, no enough buf\n", + __func__); + i--; + } + + hc->f_rec = avs2_dec->fref[i]; + hc->currentFrame = hc->f_rec->ref; + hc->f_rec->imgtr_fwRefDistance = img->tr; + hc->f_rec->imgcoi_ref = img->coding_order; +#if M3480_TEMPORAL_SCALABLE + hc->f_rec->temporal_id = hd->cur_layer; +#endif + hc->f_rec->is_output = 1; +#ifdef AML + hc->f_rec->error_mark = 0; + hc->f_rec->decoded_lcu = 0; + hc->f_rec->slice_type = img->type; +#endif + hc->f_rec->refered_by_others = hd->curr_RPS.referd_by_others; + if (is_avs2_print_bufmgr_detail()) + pr_info( + "%s, set f_rec (cur_pic) <= fref[%d] img->tr %d coding_order %d img_type %d\n", + __func__, i, img->tr, img->coding_order, + img->type); + + if (img->type != B_IMG) { + for (j = 0; + j < img->num_of_references; j++) { + hc->f_rec->ref_poc[j] = + avs2_dec->fref[j]->imgtr_fwRefDistance; + } + } else { + hc->f_rec->ref_poc[0] = + avs2_dec->fref[1]->imgtr_fwRefDistance; + hc->f_rec->ref_poc[1] = + avs2_dec->fref[0]->imgtr_fwRefDistance; + } + +#if M3480_TEMPORAL_SCALABLE + + for (j = img->num_of_references; + j < 4; j++) { + /**/ + hc->f_rec->ref_poc[j] = 0; + } + + if (img->type == INTRA_IMG) { + int32_t l; + for (l = 0; l < 4; l++) { + hc->f_rec->ref_poc[l] + = img->tr; + } + } + +#endif + +/*////////////////////////////////////////////////////////////////////////*/ + /* updata ref pointer*/ + + if (img->type != I_IMG) { + + img->imgtr_next_P = img->type == B_IMG ? + avs2_dec->fref[0]->imgtr_fwRefDistance : img->tr; + if (img->type == B_IMG) { + hd->trtmp = avs2_dec->fref[0]->imgtr_fwRefDistance; + avs2_dec->fref[0]->imgtr_fwRefDistance = + avs2_dec->fref[1]->imgtr_fwRefDistance; + } + } +#if 1 + /*rain*/ + if (is_avs2_print_bufmgr_detail()) { + for (ii = 0; ii < avs2_dec->ref_maxbuffer; ii++) { + pr_info( + "fref[%d]: index %d imgcoi_ref %d imgtr_fwRefDistance %d refered %d, is_out %d, bg %d, vf_ref %d ref_pos(%d,%d,%d,%d,%d,%d,%d)\n", + ii, avs2_dec->fref[ii]->index, + avs2_dec->fref[ii]->imgcoi_ref, + avs2_dec->fref[ii]->imgtr_fwRefDistance, + avs2_dec->fref[ii]->refered_by_others, + avs2_dec->fref[ii]->is_output, + avs2_dec->fref[ii]->bg_flag, + avs2_dec->fref[ii]->vf_ref, + avs2_dec->fref[ii]->ref_poc[0], + avs2_dec->fref[ii]->ref_poc[1], + avs2_dec->fref[ii]->ref_poc[2], + avs2_dec->fref[ii]->ref_poc[3], + avs2_dec->fref[ii]->ref_poc[4], + avs2_dec->fref[ii]->ref_poc[5], + avs2_dec->fref[ii]->ref_poc[6] + ); + } + } +#endif +} + +int32_t init_frame(struct avs2_decoder *avs2_dec) +{ + struct ImageParameters_s *img = &avs2_dec->img; + struct Video_Com_data_s *hc = &avs2_dec->hc; + struct Video_Dec_data_s *hd = &avs2_dec->hd; + + +#if RD1510_FIX_BG + if (img->type == I_IMG && + img->typeb == BACKGROUND_IMG) { /*G/GB frame*/ + img->num_of_references = 0; + } else if (img->type == P_IMG && img->typeb == BP_IMG) { + /* only one reference frame(G\GB) for S frame*/ + img->num_of_references = 1; + } +#endif + + if (img->typeb == BACKGROUND_IMG && + hd->background_picture_output_flag == 0) { + hc->currentFrame = hc->background_ref; +#ifdef AML + hc->cur_pic = avs2_dec->m_bg; +#endif + } else { + prepare_RefInfo(avs2_dec); +#ifdef AML + hc->cur_pic = hc->f_rec; +#endif + } + + +#ifdef FIX_CHROMA_FIELD_MV_BK_DIST + if (img->typeb == BACKGROUND_IMG + && img->is_field_sequence) { + avs2_dec->bk_img_is_top_field + = img->is_top_field; + } +#endif + return 0; +} + +void delete_trbuffer(struct outdata_s *data, int32_t pos) +{ + int32_t i; + for (i = pos; + i < data->buffer_num - 1; i++) { + data->stdoutdata[i] = + data->stdoutdata[i + 1]; + } + data->buffer_num--; +} + +#if RD170_FIX_BG +void flushDPB(struct avs2_decoder *avs2_dec) +{ + struct Video_Dec_data_s *hd = &avs2_dec->hd; + int j, tmp_min, i, pos = -1; + int search_times = avs2_dec->outprint.buffer_num; + + tmp_min = 1 << 20; + i = 0, j = 0; + pos = -1; + + for (j = 0; j < search_times; j++) { + pos = -1; + tmp_min = (1 << 20); + /*search for min poi picture to display*/ + for (i = 0; i < avs2_dec->outprint.buffer_num; i++) { + if (avs2_dec->outprint.stdoutdata[i].tr < tmp_min) { + pos = i; + tmp_min = avs2_dec->outprint.stdoutdata[i].tr; + } + } + + if (pos != -1) { + hd->last_output = avs2_dec->outprint.stdoutdata[pos].tr; + report_frame(avs2_dec, &avs2_dec->outprint, pos); + if (avs2_dec->outprint.stdoutdata[pos].typeb + == BACKGROUND_IMG && + avs2_dec->outprint.stdoutdata[pos]. + background_picture_output_flag + == 0) { + /*write_GB_frame(hd->p_out_background);*/ + } else { + write_frame(avs2_dec, + avs2_dec->outprint.stdoutdata[pos].tr); + } + + delete_trbuffer(&avs2_dec->outprint, pos); + } + } + + /*clear dpb info*/ + for (j = 0; j < REF_MAXBUFFER; j++) { + avs2_dec->fref[j]->imgtr_fwRefDistance = -256; + avs2_dec->fref[j]->imgcoi_ref = -257; + avs2_dec->fref[j]->temporal_id = -1; + avs2_dec->fref[j]->refered_by_others = 0; + } +} +#endif + + + +#if M3480_TEMPORAL_SCALABLE +void cleanRefMVBufRef(int pos) +{ +#if 0 + int k, x, y; + /*re-init mvbuf*/ + for (k = 0; k < 2; k++) { + for (y = 0; y < img->height / MIN_BLOCK_SIZE; y++) { + for (x = 0; x < img->width / MIN_BLOCK_SIZE; x++) + fref[pos]->mvbuf[y][x][k] = 0; + + } + } + /*re-init refbuf*/ + for (y = 0; y < img->height / MIN_BLOCK_SIZE; y++) { + for (x = 0; x < img->width / MIN_BLOCK_SIZE ; x++) + fref[pos]->refbuf[y][x] = -1; + + } +#endif +} +#endif + +static int frame_postprocessing(struct avs2_decoder *avs2_dec) +{ + struct ImageParameters_s *img = &avs2_dec->img; + struct Video_Com_data_s *hc = &avs2_dec->hc; + struct Video_Dec_data_s *hd = &avs2_dec->hd; + + int32_t pointer_tmp = avs2_dec->outprint.buffer_num; + int32_t i; + struct STDOUT_DATA_s *p_outdata; +#if RD160_FIX_BG + int32_t j, tmp_min, output_cur_dec_pic, pos = -1; + int32_t search_times = avs2_dec->outprint.buffer_num; +#endif + /*pic dist by Grandview Semi. @ [06-07-20 15:25]*/ + img->PrevPicDistanceLsb = (img->coding_order % 256); + + pointer_tmp = avs2_dec->outprint.buffer_num; + p_outdata = &avs2_dec->outprint.stdoutdata[pointer_tmp]; + + p_outdata->type = img->type; + p_outdata->typeb = img->typeb; + p_outdata->framenum = img->tr; + p_outdata->tr = img->tr; +#if 0 /*def ORI*/ + p_outdata->qp = img->qp; +#else + p_outdata->qp = 0; +#endif + /*p_outdata->snr_y = snr->snr_y;*/ + /*p_outdata->snr_u = snr->snr_u;*/ + /*p_outdata->snr_v = snr->snr_v;*/ + p_outdata->tmp_time = hd->tmp_time; + p_outdata->picture_structure = img->picture_structure; + /*p_outdata->curr_frame_bits = + StatBitsPtr->curr_frame_bits;*/ + /*p_outdata->emulate_bits = StatBitsPtr->emulate_bits;*/ +#if RD1501_FIX_BG + p_outdata->background_picture_output_flag + = hd->background_picture_output_flag; + /*Longfei.Wang@mediatek.com*/ +#endif + +#if RD160_FIX_BG + p_outdata->picture_reorder_delay = hd->picture_reorder_delay; +#endif + avs2_dec->outprint.buffer_num++; + +#if RD170_FIX_BG + search_times = avs2_dec->outprint.buffer_num; +#endif + /* record the reference list*/ + strcpy(p_outdata->str_reference_list, hc->str_list_reference); + +#if !REF_OUTPUT + #error "!!!REF_OUTPUT should be 1" + for (i = 0; i < avs2_dec->outprint.buffer_num; i++) { + min_tr(avs2_dec->outprint, &pos); + if (avs2_dec->outprint.stdoutdata[pos].tr < img->tr + || avs2_dec->outprint.stdoutdata[pos].tr + == (hd->last_output + 1)) { + hd->last_output = avs2_dec->outprint.stdoutdata[pos].tr; + report_frame(avs2_dec, &avs2_dec->outprint, pos); +#if 0 /*def ORI*/ + write_frame(hd->p_out, + avs2_dec->outprint.stdoutdata[pos].tr); +#endif + delete_trbuffer(&avs2_dec->outprint, pos); + i--; + } else { + break; + } + } +#else +#if RD160_FIX_BG /*Longfei.Wang@mediatek.com*/ + tmp_min = 1 << 20; + i = 0, j = 0; + output_cur_dec_pic = 0; + pos = -1; + for (j = 0; j < search_times; j++) { + pos = -1; + tmp_min = (1 << 20); + /*search for min poi picture to display*/ + for (i = 0; i < avs2_dec->outprint.buffer_num; i++) { + if ((avs2_dec->outprint.stdoutdata[i].tr < tmp_min) && + ((avs2_dec->outprint.stdoutdata[i].tr + + avs2_dec->outprint.stdoutdata[i]. + picture_reorder_delay) + <= (int32_t)img->coding_order)) { + pos = i; + tmp_min = avs2_dec->outprint.stdoutdata[i].tr; + } + } + + if ((0 == hd->displaydelay) && (0 == output_cur_dec_pic)) { + if (img->tr <= tmp_min) {/*fred.chiu@mediatek.com*/ + /*output current decode picture + right now*/ + pos = avs2_dec->outprint.buffer_num - 1; + output_cur_dec_pic = 1; + } + } + if (pos != -1) { + hd->last_output = avs2_dec->outprint.stdoutdata[pos].tr; + report_frame(avs2_dec, &avs2_dec->outprint, pos); +#if 1 /*def ORI*/ + if (avs2_dec->outprint.stdoutdata[pos].typeb + == BACKGROUND_IMG && + avs2_dec->outprint.stdoutdata[pos]. + background_picture_output_flag == 0) { + /**/ + /**/ + } else { + write_frame(avs2_dec, + avs2_dec->outprint.stdoutdata[pos].tr); + } +#endif + delete_trbuffer(&avs2_dec->outprint, pos); + } + + } + +#else + #error "!!!RD160_FIX_BG should be defined" + if (img->coding_order + + (uint32_t)hc->total_frames * 256 >= + (uint32_t)hd->picture_reorder_delay) { + int32_t tmp_min, pos = -1; + tmp_min = 1 << 20; + + for (i = 0; i < + avs2_dec->outprint.buffer_num; i++) { + if (avs2_dec->outprint.stdoutdata[i].tr + < tmp_min && + avs2_dec->outprint.stdoutdata[i].tr + >= hd->last_output) { + /*GB has the same "tr" with "last_output"*/ + pos = i; + tmp_min = + avs2_dec->outprint.stdoutdata[i].tr; + } + } + + if (pos != -1) { + hd->last_output = avs2_dec->outprint.stdoutdata[pos].tr; + report_frame(avs2_dec, &avs2_dec->outprint, pos); +#if RD1501_FIX_BG + if (avs2_dec->outprint.stdoutdata[pos].typeb + == BACKGROUND_IMG && avs2_dec-> + outprint.stdoutdata[pos]. + background_picture_output_flag == 0) { +#else + if (avs2_dec->outprint.stdoutdata[pos].typeb + == BACKGROUND_IMG && + hd->background_picture_output_flag + == 0) { +#endif + write_GB_frame( + hd->p_out_background); + } else { + write_frame(avs2_dec, + avs2_dec->outprint.stdoutdata[pos].tr); + } + delete_trbuffer(&avs2_dec->outprint, pos); + + } + + } +#endif +#endif + return pos; + + } + +void write_frame(struct avs2_decoder *avs2_dec, int32_t pos) +{ + int32_t j; + + if (is_avs2_print_bufmgr_detail()) + pr_info("%s(pos = %d)\n", __func__, pos); + + for (j = 0; j < avs2_dec->ref_maxbuffer; j++) { + if (avs2_dec->fref[j]->imgtr_fwRefDistance == pos) { + avs2_dec->fref[j]->imgtr_fwRefDistance_bak = pos; + avs2_dec->fref[j]->is_output = -1; + avs2_dec->fref[j]->to_prepare_disp = + avs2_dec->to_prepare_disp_count++; + if (avs2_dec->fref[j]->refered_by_others == 0 + || avs2_dec->fref[j]->imgcoi_ref + == -257) { + avs2_dec->fref[j]->imgtr_fwRefDistance + = -256; + avs2_dec->fref[j]->imgcoi_ref = -257; +#if M3480_TEMPORAL_SCALABLE + avs2_dec->fref[j]->temporal_id = -1; +#endif + if (is_avs2_print_bufmgr_detail()) + pr_info("%s, fref index %d\n", + __func__, j); + } + break; + } + } +} + +/*rain???, outdata *data*/ +void report_frame(struct avs2_decoder *avs2_dec, + struct outdata_s *data, int32_t pos) +{ + struct ImageParameters_s *img = &avs2_dec->img; + struct Video_Com_data_s *hc = &avs2_dec->hc; + struct Video_Dec_data_s *hd = &avs2_dec->hd; + + int8_t *Frmfld; + int8_t Frm[] = "FRM"; + int8_t Fld[] = "FLD"; + struct STDOUT_DATA_s *p_stdoutdata + = &data->stdoutdata[pos]; + const int8_t *typ; + +#if 0 + if (input->MD5Enable & 0x02) { + sprintf(MD5str, "%08X%08X%08X%08X\0", + p_stdoutdata->DecMD5Value[0], + p_stdoutdata->DecMD5Value[1], + p_stdoutdata->DecMD5Value[2], + p_stdoutdata->DecMD5Value[3]); + } else { + memset(MD5val, 0, 16); + memset(MD5str, 0, 33); + } +#endif + + if (p_stdoutdata-> + picture_structure) { + Frmfld = Frm; + } else { + Frmfld = Fld; + } +#if INTERLACE_CODING + if (img->is_field_sequence) { /*rcs??*/ + Frmfld = Fld; + } +#endif + if ((p_stdoutdata->tr + hc->total_frames * 256) + == hd->end_SeqTr) { /* I picture*/ + /*if ( img->new_sequence_flag == 1 )*/ + { + img->sequence_end_flag = 0; + /*fprintf(stdout, "Sequence + End\n\n");*/ + } + } + if ((p_stdoutdata->tr + hc->total_frames * 256) + == hd->next_IDRtr) { +#if !RD170_FIX_BG + if (hd->vec_flag) /**/ +#endif + { + hd->vec_flag = 0; + /*fprintf(stdout, "Video Edit + Code\n");*/ + } + } + + if (p_stdoutdata->typeb == BACKGROUND_IMG) { + typ = (hd->background_picture_output_flag != 0) ? "G" : "GB"; + } else { +#if REMOVE_UNUSED + typ = (p_stdoutdata->type == INTRA_IMG) + ? "I" : (p_stdoutdata->type == INTER_IMG) ? + ((p_stdoutdata->typeb == BP_IMG) ? "S" : "P") + : (p_stdoutdata->type == F_IMG ? "F" : "B"); +#else + typ = (p_stdoutdata->type == INTRA_IMG) ? "I" : + (p_stdoutdata->type == INTER_IMG) ? + ((p_stdoutdata->type == BP_IMG) ? "S" : "P") + : (p_stdoutdata->type == F_IMG ? "F" : "B"); +#endif + } + +#if 0 + /*rain???*/ + pr_info("%3d(%s) %3d %5d %7.4f %7.4f %7.4f %5d\t\t%s %8d %6d\t%s", + p_stdoutdata->framenum + hc->total_frames * 256, + typ, p_stdoutdata->tr + hc->total_frames * 256, + p_stdoutdata->qp, p_stdoutdata->snr_y, + p_stdoutdata->snr_u, p_stdoutdata->snr_v, + p_stdoutdata->tmp_time, Frmfld, + p_stdoutdata->curr_frame_bits, + p_stdoutdata->emulate_bits, + ""); +#endif + if (is_avs2_print_bufmgr_detail()) + pr_info(" %s\n", p_stdoutdata->str_reference_list); + + /*fflush(stdout);*/ + hd->FrameNum++; +} + +void avs2_prepare_header(struct avs2_decoder *avs2_dec, int32_t start_code) +{ + struct ImageParameters_s *img = &avs2_dec->img; + struct Video_Dec_data_s *hd = &avs2_dec->hd; + + switch (start_code) { + case SEQUENCE_HEADER_CODE: + img->new_sequence_flag = 1; + if (is_avs2_print_bufmgr_detail()) + pr_info("SEQUENCE\n"); +#ifdef TO_CHECK +#if SEQ_CHANGE_CHECKER + if (seq_checker_buf == NULL) { + seq_checker_buf = malloc(length); + seq_checker_length = length; + memcpy(seq_checker_buf, Buf, length); + } else { + if ((seq_checker_length != length) || + (memcmp(seq_checker_buf, Buf, length) != 0)) { + free(seq_checker_buf); + /*fprintf(stdout, + "Non-conformance + stream: sequence + header cannot change + !!\n");*/ +#if RD170_FIX_BG + seq_checker_buf = NULL; + seq_checker_length = 0; + seq_checker_buf = malloc(length); + seq_checker_length = length; + memcpy(seq_checker_buf, Buf, length); +#endif + } + + + } +#endif +#if RD170_FIX_BG + if (input->alf_enable + && alfParAllcoated == 1) { + ReleaseAlfGlobalBuffer(); + alfParAllcoated = 0; + } +#endif +/*TO_CHECK*/ +#endif +#if FIX_FLUSH_DPB_BY_LF + if (hd->vec_flag) { + int32_t k; + if (is_avs2_print_bufmgr_detail()) + pr_info("vec_flag is 1, flushDPB and reinit bugmgr\n"); + + flushDPB(avs2_dec); + for (k = 0; k < avs2_dec->ref_maxbuffer; k++) + cleanRefMVBufRef(k); + + hd->vec_flag = 0; +#ifdef AML + free_unused_buffers(avs2_dec); +#else + free_global_buffers(avs2_dec); +#endif + img->number = 0; + img->PrevPicDistanceLsb = 0; + avs2_dec->init_hw_flag = 0; + } +#endif + +#if FIX_SEQ_END_FLUSH_DPB_BY_LF + if (img->new_sequence_flag + && img->sequence_end_flag) { + int32_t k; + if (is_avs2_print_bufmgr_detail()) + pr_info( + "new_sequence_flag after sequence_end_flag, flushDPB and reinit bugmgr\n"); + flushDPB(avs2_dec); + for (k = 0; k < avs2_dec->ref_maxbuffer; k++) + cleanRefMVBufRef(k); + +#ifdef AML + free_unused_buffers(avs2_dec); +#else + free_global_buffers(avs2_dec); +#endif + img->number = 0; + img->PrevPicDistanceLsb = 0; + avs2_dec->init_hw_flag = 0; + } +#endif + img->seq_header_indicate = 1; + break; + case I_PICTURE_START_CODE: + if (is_avs2_print_bufmgr_detail()) + pr_info("PIC-I\n"); + Get_SequenceHeader(avs2_dec); + Get_I_Picture_Header(avs2_dec); + calc_picture_distance(avs2_dec); + Read_ALF_param(avs2_dec); + if (!img->seq_header_indicate) { + img->B_discard_flag = 1; + /*fprintf(stdout, " I + %3d\t\tDIDSCARD!!\n", + img->tr);*/ + break; + } + break; + case PB_PICTURE_START_CODE: + if (is_avs2_print_bufmgr_detail()) + pr_info("PIC-PB\n"); + Get_SequenceHeader(avs2_dec); + Get_PB_Picture_Header(avs2_dec); + calc_picture_distance(avs2_dec); + Read_ALF_param(avs2_dec); + /* xiaozhen zheng, 20071009*/ + if (!img->seq_header_indicate) { + img->B_discard_flag = 1; + + if (img->type == P_IMG) { + /*fprintf(stdout, " P + %3d\t\tDIDSCARD!!\n", + img->tr);*/ + } + if (img->type == F_IMG) { + /*fprintf(stdout, " F + %3d\t\tDIDSCARD!!\n", + img->tr);*/ + } else { + /*fprintf(stdout, " B + %3d\t\tDIDSCARD!!\n", + img->tr);*/ + } + + break; + } + + if (img->seq_header_indicate == 1 + && img->type != B_IMG) { + img->B_discard_flag = 0; + } + if (img->type == B_IMG && img->B_discard_flag == 1 + && !img->random_access_decodable_flag) { + /*fprintf(stdout, " B + %3d\t\tDIDSCARD!!\n", + img->tr);*/ + break; + } + + break; + case SEQUENCE_END_CODE: + if (is_avs2_print_bufmgr_detail()) + pr_info("SEQUENCE_END_CODE\n"); +#ifdef TO_CHECK +#if SEQ_CHANGE_CHECKER + if (seq_checker_buf != NULL) { + free(seq_checker_buf); + seq_checker_buf = NULL; + seq_checker_length = 0; + } +#endif +#endif +img->new_sequence_flag = 1; +img->sequence_end_flag = 1; +break; + case VIDEO_EDIT_CODE: + if (is_avs2_print_bufmgr_detail()) + pr_info("VIDEO_EDIT_CODE\n"); + /*video_edit_code_data(Buf, startcodepos, length);*/ + hd->vec_flag = 1; +#ifdef TO_CHECK +#if SEQ_CHANGE_CHECKER + if (seq_checker_buf != NULL) { + free(seq_checker_buf); + seq_checker_buf = NULL; + seq_checker_length = 0; + } +#endif +#endif + +break; + } +} + +#ifdef AML +static uint32_t log2i(uint32_t val) +{ + uint32_t ret = -1; + while (val != 0) { + val >>= 1; + ret++; + } + return ret; +} +#endif + +int32_t avs2_process_header(struct avs2_decoder *avs2_dec) +{ + struct inp_par *input = &avs2_dec->input; + struct ImageParameters_s *img = &avs2_dec->img; + struct Video_Dec_data_s *hd = &avs2_dec->hd; + int32_t lcu_x_num_div; + int32_t lcu_y_num_div; + + int32_t N8_SizeScale; + /*pr_info("%s\n", __func__);*/ + { + N8_SizeScale = 1; + + if (hd->horizontal_size % + (MIN_CU_SIZE * N8_SizeScale) != 0) { + img->auto_crop_right = + (MIN_CU_SIZE * N8_SizeScale) - + (hd->horizontal_size % + (MIN_CU_SIZE * N8_SizeScale)); + } else + img->auto_crop_right = 0; + +#if !INTERLACE_CODING + if (hd->progressive_sequence) /**/ +#endif + { + if (hd->vertical_size % + (MIN_CU_SIZE * N8_SizeScale) != 0) { + img->auto_crop_bottom = + (MIN_CU_SIZE * N8_SizeScale) - + (hd->vertical_size % + (MIN_CU_SIZE * N8_SizeScale)); + } else + img->auto_crop_bottom = 0; + } + + /* Reinit parameters (NOTE: need to do + before init_frame //*/ + img->width = + (hd->horizontal_size + img->auto_crop_right); + img->height = + (hd->vertical_size + img->auto_crop_bottom); + img->width_cr = (img->width >> 1); + + if (input->chroma_format == 1) + img->height_cr = (img->height >> 1); + + img->PicWidthInMbs = img->width / MIN_CU_SIZE; + img->PicHeightInMbs = img->height / MIN_CU_SIZE; + img->PicSizeInMbs = img->PicWidthInMbs * img->PicHeightInMbs; + img->max_mb_nr = (img->width * img->height) / + (MIN_CU_SIZE * MIN_CU_SIZE); + } + + if (img->new_sequence_flag && img->sequence_end_flag) { +#if 0/*RD170_FIX_BG //*/ + int32_t k; + flushDPB(); + for (k = 0; k < avs2_dec->ref_maxbuffer; k++) + cleanRefMVBufRef(k); + + free_global_buffers(); + img->number = 0; +#endif + hd->end_SeqTr = img->tr; + img->sequence_end_flag = 0; + } + if (img->new_sequence_flag) { + hd->next_IDRtr = img->tr; + hd->next_IDRcoi = img->coding_order; + img->new_sequence_flag = 0; + } +#if 0/*RD170_FIX_BG*/ + if (hd->vec_flag) { + int32_t k; + flushDPB(); + for (k = 0; k < avs2_dec->ref_maxbuffer; k++) + cleanRefMVBufRef(k); + + hd->vec_flag = 0; + free_global_buffers(); + img->number = 0; + } +#endif +/* allocate memory for frame buffers*/ +#if 0 +/* called in vavs2.c*/ + if (img->number == 0) + avs2_init_global_buffers(avs2_dec); +#endif + img->current_mb_nr = 0; + + init_frame(avs2_dec); + + img->types = img->type; /* jlzheng 7.15*/ + + if (img->type != B_IMG) { + hd->pre_img_type = img->type; + hd->pre_img_types = img->types; + } + +#ifdef AML + avs2_dec->lcu_size_log2 = log2i(avs2_dec->lcu_size); + lcu_x_num_div = (img->width/avs2_dec->lcu_size); + lcu_y_num_div = (img->height/avs2_dec->lcu_size); + avs2_dec->lcu_x_num = ((img->width % avs2_dec->lcu_size) == 0) ? + lcu_x_num_div : lcu_x_num_div+1; + avs2_dec->lcu_y_num = ((img->height % avs2_dec->lcu_size) == 0) ? + lcu_y_num_div : lcu_y_num_div+1; + avs2_dec->lcu_total = avs2_dec->lcu_x_num*avs2_dec->lcu_y_num; +#endif + return SOP; +} + +int avs2_post_process(struct avs2_decoder *avs2_dec) +{ + struct ImageParameters_s *img = &avs2_dec->img; + struct Video_Com_data_s *hc = &avs2_dec->hc; + struct Video_Dec_data_s *hd = &avs2_dec->hd; + int32_t i; + int ret; + if (img->typeb == BACKGROUND_IMG && hd->background_picture_enable) { +#ifdef AML + for (i = 0; i < avs2_dec->ref_maxbuffer; i++) { + if (avs2_dec->fref[i]->bg_flag != 0) { + avs2_dec->fref[i]->bg_flag = 0; + if (is_avs2_print_bufmgr_detail()) + pr_info( + "clear old BACKGROUND_IMG for index %d\r\n", + avs2_dec->fref[i]->index); + } + } + if (is_avs2_print_bufmgr_detail()) + pr_info( + "post_process: set BACKGROUND_IMG flag for %d\r\n", + hc->cur_pic->index); + avs2_dec->f_bg = hc->cur_pic; + hc->cur_pic->bg_flag = 1; +#endif + } + +#if BCBR + if (hd->background_picture_enable + && hd->bcbr_enable && img->number > 0) + updateBgReference(); +#endif + + if (img->typeb == BACKGROUND_IMG && + hd->background_picture_output_flag == 0) + hd->background_number++; + + if (img->type == B_IMG) { + avs2_dec->fref[0]->imgtr_fwRefDistance + = hd->trtmp; + } + + /* record the reference list information*/ + get_reference_list_info(avs2_dec, avs2_dec->hc.str_list_reference); + + /*pr_info("%s\n", __func__);*/ + ret = frame_postprocessing(avs2_dec); + +#if FIX_PROFILE_LEVEL_DPB_RPS_1 + /* delete the frame that will never be used*/ + { + int32_t i, j; + if (is_avs2_print_bufmgr_detail()) { + pr_info( + "%s, coding_order %d to remove %d buf: ", + __func__, + img->coding_order, + hd->curr_RPS.num_to_remove); + for (i = 0; i < hd->curr_RPS.num_to_remove; i++) + pr_info("%d ", hd->curr_RPS.remove_pic[i]); + pr_info("\n"); + } + for (i = 0; i < hd->curr_RPS.num_to_remove; i++) { + for (j = 0; j < avs2_dec->ref_maxbuffer; j++) { + + if (avs2_dec->fref[j]->imgcoi_ref >= -256 + && avs2_dec->fref[j]->imgcoi_ref == + img->coding_order - + hd->curr_RPS.remove_pic[i]) + break; + } + if (j < avs2_dec->ref_maxbuffer) { /**/ +#if FIX_RPS_PICTURE_REMOVE +/* Label new frames as "un-referenced" */ + avs2_dec->fref[j]->refered_by_others = 0; + + /* remove frames which have been outputted */ + if (avs2_dec->fref[j]->is_output == -1) { + avs2_dec->fref[j]-> + imgtr_fwRefDistance = -256; + avs2_dec->fref[j]->imgcoi_ref = -257; + avs2_dec->fref[j]->temporal_id = -1; + + } +#else + avs2_dec->fref[j]->imgcoi_ref = -257; +#if M3480_TEMPORAL_SCALABLE + avs2_dec->fref[j]->temporal_id = -1; +#endif + if (avs2_dec->fref[j]->is_output == -1) { + avs2_dec->fref[j]->imgtr_fwRefDistance + = -256; + } +#endif + } + } + } +#endif + + + /*! TO 19.11.2001 Known Problem: for init_frame + * we have to know the picture type of the + * actual frame*/ + /*! in case the first slice of the P-Frame + * following the I-Frame was lost we decode this + * P-Frame but! do not write it because it + * was + * assumed to be an I-Frame in init_frame.So we + * force the decoder to*/ + /*! guess the right picture type. This is a hack + * a should be removed by the time there is a + * clean*/ + /*! solution where we do not have to know the + * picture type for the function init_frame.*/ + /*! End TO 19.11.2001//Lou*/ + + { + if (img->type == I_IMG || + img->type == P_IMG || + img->type == F_IMG) + img->number++; + else { + hc->Bframe_ctr++; /* B + pictures*/ + } + } + return ret; +} + +void init_avs2_decoder(struct avs2_decoder *avs2_dec) +{ + int32_t i, j, k; + + struct inp_par *input = &avs2_dec->input; + struct ImageParameters_s *img = &avs2_dec->img; + struct Video_Com_data_s *hc = &avs2_dec->hc; + struct Video_Dec_data_s *hd = &avs2_dec->hd; + if (is_avs2_print_bufmgr_detail()) + pr_info("[t] struct avs2_dec @0x%p\n", avs2_dec); + memset(avs2_dec, 0, sizeof(struct avs2_decoder)); +#ifdef AML + avs2_dec->to_prepare_disp_count = 1; +#endif + /* + * ALFParam init + */ + for (i = 0; i < 3; i++) { + avs2_dec->m_alfPictureParam[i].alf_flag = 0; /*1*/ + avs2_dec->m_alfPictureParam[i].num_coeff = 9; /*1*/ + avs2_dec->m_alfPictureParam[i].filters_per_group = 3; /*1*/ + avs2_dec->m_alfPictureParam[i].componentID = i; /*1*/ + for (j = 0; j < 16; j++) { + avs2_dec->m_alfPictureParam[i].filterPattern[j] = 0; + /*16*/ + } + for (j = 0; j < 16; j++) { + for (k = 0; k < 9; k++) { + avs2_dec-> + m_alfPictureParam[i].coeffmulti[j][k] = 0; + /*16*9*/ + } + } + } + + img->seq_header_indicate = 0; + img->B_discard_flag = 0; + + hd->eos = 0; + + if (input->ref_pic_order) { /*ref order*/ + hd->dec_ref_num = 0; + } + + /* + memset(g_log2size, -1, MAX_CU_SIZE + 1); + c = 2; + for (k = 4; k <= MAX_CU_SIZE; k *= 2) { + g_log2size[k] = c; + c++; + } + */ + + avs2_dec->outprint.buffer_num = 0; + + hd->last_output = -1; + hd->end_SeqTr = -1; + hd->curr_IDRtr = 0; + hd->curr_IDRcoi = 0; + hd->next_IDRtr = 0; + hd->next_IDRcoi = 0; + /* Allocate Slice data struct*/ + img->number = 0; + img->type = I_IMG; + + img->imgtr_next_P = 0; + + img->imgcoi_next_ref = 0; + + + img->num_of_references = 0; + hc->seq_header = 0; + + img->new_sequence_flag = 1; + + hd->vec_flag = 0; + + hd->FrameNum = 0; + + /* B pictures*/ + hc->Bframe_ctr = 0; + hc->total_frames = 0; + + /* time for total decoding session*/ + hc->tot_time = 0; + +} +
diff --git a/drivers/frame_provider/decoder_v4l/avs2/avs2_global.h b/drivers/frame_provider/decoder_v4l/avs2/avs2_global.h new file mode 100644 index 0000000..d9f85bd --- /dev/null +++ b/drivers/frame_provider/decoder_v4l/avs2/avs2_global.h
@@ -0,0 +1,1687 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2002-2016, Audio Video coding Standard Workgroup of China + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Audio Video coding Standard Workgroup of China + * nor the names of its contributors maybe + * used to endorse or promote products + * derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + + + +/* + * File name: global.h + * Function: global definitions for for AVS decoder. + * + */ + +#ifndef _GLOBAL_H_ +#define _GLOBAL_H_ + +/* #include <stdio.h> //!< for FILE */ +/* #include <stdlib.h> */ + +#define AML +#define SANITY_CHECK +#undef NO_DISPLAY + +/* #include "define.h" */ +#define RD "19.2" +#define VERSION "19.2" + +#define RESERVED_PROFILE_ID 0x24 +#define BASELINE_PICTURE_PROFILE 18 +#define BASELINE_PROFILE 32 /* 0x20 */ +#define BASELINE10_PROFILE 34 /* 0x22 */ + + +#define SCENE_PROFILE 48 /* 0x21 */ +#define SCENE10_PROFILE 50 /* 0x23 */ + +#define TRACE 0 /* !< 0:Trace off 1:Trace on */ + + +/* Type definitions and file operation for Windows/Linux + * All file operations for windows are replaced with native (FILE *) operations + * Falei LUO (falei.luo@vipl.ict.ac.cn) + * */ + +#define _FILE_OFFSET_BITS 64 /* for 64 bit fseeko */ +#define fseek fseeko + +#define int16 int16_t +#define int64 int64_t + +/* ////////////////// bug fix ///////////////////////////// */ +#define ALFSliceFix 1 +#define WRITENBIT_FIX 1 +#define FIX_PROFILE_LEVEL_DPB_RPS_1 1 +#define FIX_PROFILE_LEVEL_DPB_RPS_2 1 +#define FIX_RPS_PICTURE_REMOVE 1 /* flluo@pku.edu.cn */ +#define Mv_Clip 1 /* yuquanhe@hisilicon.com */ +#define REMOVE_UNUSED 1 /* yuquanhe@hisilicon.com */ +#define SAO_Height_Fix 1 /* yuquanhe@hisilicon.com */ +#define B_BACKGROUND_Fix 1 /* yuquanhe@hisilicon.com */ +#define Check_Bitstream 1 /* yuquanhe@hisilicon.com */ +#define Wq_param_Clip 1 /* yuquanhe@hisilicon.com */ + /* luofalei flluo@pku.edu.cn , wlq15@mails.tsinghua.edu.cn , + Longfei.Wang@mediatek.com */ +#define RD1501_FIX_BG 1 + /* yuquanhe@hisilicon.com ; he-yuan.lin@mstarsemi.com */ +#define Mv_Rang 1 + /* Longfei.Wang@mediatek.com ;fred.chiu@mediatek.com + jie1222.chen@samsung.com */ +#define RD160_FIX_BG 1 + /* Y_K_Tu@novatek.com.tw, he-yuan.lin@mstarsemi.com, + victor.huang@montage-tech.com M4041 */ +#define RD1601_FIX_BG 1 +#define SEQ_CHANGE_CHECKER 1 /* he-yuan.lin@mstarsemi.com */ +#define M4140_END_OF_SLICE_CHECKER 1 /* he-yuan.lin@mstarsemi.com */ + /* wlq15@mails.tsinghua.edu.cn */ +#define Mv_check_bug 1 +#define SAO_ASSERTION_FIX 1 /* fred.chiu@mediatek.com */ +#define FIELD_HORI_MV_NO_SCALE_FIX 1 /* fred.chiu@mediatek.com */ +#define RD170_FIX_BG 1 +#define FIX_CHROMA_FIELD_MV_BK_DIST 1 +#define FIX_LUMA_FIELD_MV_BK_DIST 1 +#define FIX_CHROMA_FIELD_MV_CLIP 1 +#if 1 +#define FIX_FLUSH_DPB_BY_LF 1 /* fred.chiu@mediatek.com */ +#define FIX_SEQ_END_FLUSH_DPB_BY_LF 1 /* fred.chiu@mediatek.com */ +#else +#define FIX_FLUSH_DPB_BY_LF 0 /* fred.chiu@mediatek.com */ +#define FIX_SEQ_END_FLUSH_DPB_BY_LF 0 /* fred.chiu@mediatek.com */ +#endif +#define RD191_FIX_BUG 1 /* yuquanhe@hsilicon.com */ +#define SYM_MV_SCALE_FIX 1/* peisong.chen@broadcom.com */ +#define BUG_10BIT_REFINEQP 0 /* wangzhenyu */ + + + +#if RD191_FIX_BUG +#endif + +/************************ + * AVS2 macros start + **************************/ + +#define INTERLACE_CODING 1 +#if INTERLACE_CODING /* M3531: MV scaling compensation */ +/* Luma component */ +#define HALF_PIXEL_COMPENSATION 1 /* common functions definition */ +#define HALF_PIXEL_COMPENSATION_PMV 1 /* spacial MV prediction */ +#define HALF_PIXEL_COMPENSATION_DIRECT 1 /* B direct mode */ + /* MV derivation method 1, weighted P_skip mode */ +#define HALF_PIXEL_COMPENSATION_M1 1 + /* M1 related with mv-scaling function */ +#define HALF_PIXEL_COMPENSATION_M1_FUCTION 1 +#define HALF_PIXEL_COMPENSATION_MVD 1 /* MV scaling from FW->BW */ +/* Chroma components */ + /* chroma MV is scaled with luma MV for 4:2:0 format */ +#define HALF_PIXEL_CHROMA 1 + /* half pixel compensation for p skip/direct */ +#define HALF_PIXEL_PSKIP 1 +#define INTERLACE_CODING_FIX 1 /* HLS fix */ +#define OUTPUT_INTERLACE_MERGED_PIC 1 + +#endif +/* + ******************************* +AVS2 10bit/12bit profile + ******************************** + */ + +#define DBFIX_10bit 1 + +#define BUG_10bit 1 + +/* + *************************************** +AVS2 HIGH LEVEL SYNTAX + *************************************** + */ +#define AVS2_HDR_HLS 1 + /* AVS2 HDR technology //yuquanhe@hisilicon.com */ +#define AVS2_HDR_Tec 1 +#if AVS2_HDR_Tec +#define HDR_CHROMA_DELTA_QP 1 /* M3905 */ +#define HDR_ADPTIVE_UV_DELTA 1 +#endif +/* + ************************************* +AVS2 S2 + ************************************* + */ +#define AVS2_S2_FASTMODEDECISION 1 +#define RD1510_FIX_BG 1 /* 20160714, flluo@pku.edu.cn */ + + +/* ////////////////// prediction techniques ///////////////////////////// */ +#define LAM_2Level_TU 0.8 + + +#define DIRECTION 4 +#define DS_FORWARD 4 +#define DS_BACKWARD 2 +#define DS_SYM 3 +#define DS_BID 1 + +#define MH_PSKIP_NUM 4 +#define NUM_OFFSET 0 +#define BID_P_FST 1 +#define BID_P_SND 2 +#define FW_P_FST 3 +#define FW_P_SND 4 +#define WPM_NUM 3 + /* M3330 changes it to 2, the original value is 3 */ +#define MAX_MVP_CAND_NUM 2 + +#define DMH_MODE_NUM 5 /* Number of DMH mode */ +#define TH_ME 0 /* Threshold of ME */ + +#define MV_SCALE 1 + +/* ///// reference picture management // */ +#define FIX_MAX_REF 1 /* Falei LUO, flluo@pku.edu.cn */ +#if FIX_MAX_REF + /* maximum number of reference frame for each frame */ +#define MAXREF 7 +#define MAXGOP 32 +#endif + +/* #define REF_MAXBUFFER 7 */ +/* more bufferes for displaying and background */ +/* #define REF_MAXBUFFER 15 */ +#if 1 +#define REF_MAXBUFFER 23 +#define REF_BUFFER 16 +#else +#if RD170_FIX_BG +#define REF_MAXBUFFER 16 +#else +#define REF_MAXBUFFER 7 +#endif +#endif + +#ifdef TO_PORTING + /* block-composed background reference, fangdong@mail.ustc.edu.cn */ +#define BCBR 1 +#else +#define BCBR 0 +#endif +/* one more buffer for background when background_picture_output_flag is 0*/ +#define AVS2_MAX_BUFFER_NUM (REF_MAXBUFFER + 1) + +/* /////////////////Adaptive Loop Filter////////////////////////// */ +#define NUM_ALF_COEFF_CTX 1 +#define NUM_ALF_LCU_CTX 4 + +#define LAMBDA_SCALE_LUMA (1.0) +#define LAMBDA_SCALE_CHROMA (1.0) + + + +/* ////////////////// entropy coding ///////////////////////////// */ + /* M3090: Make sure rs1 will not overflow for 8-bit unsign char */ +#define NUN_VALUE_BOUND 254 +#define Encoder_BYPASS_Final 1 /* M3484 */ +#define Decoder_Bypass_Annex 0 /* M3484 */ +#define Decoder_Final_Annex 0 /* M3540 */ + + +/* ////////////////// coefficient coding ///// */ + /* M3035 size of an coefficient group, 4x4 */ +#define CG_SIZE 16 + +#define SWAP(x, y) {\ + (y) = (y) ^ (x);\ + (x) = (y) ^ (x);\ + (y) = (x) ^ (y);\ +} + +/* ////////////////// encoder optimization /////// */ +#define TH 2 + +#define M3624MDLOG /* reserved */ + +#define TDRDO 1 /* M3528 */ +/* #define FIX_TDRDO_BG 1 // flluo@pku.edu.cn, 20160318// */ +#define RATECONTROL 1 /* M3580 M3627 M3689 */ +#define AQPO 1 /* M3623 */ +#define AQPOM3694 0 +#define AQPOM4063 1 +#define AQPOM3762 1 +#define BGQPO 1 /* M4061 */ +#if BGQPO +#define LONGREFERENCE 32 +#endif + +/* #define REPORT */ +/* ////////////////// Quantization /////////////////////////////////////// */ + /* Adaptive frequency weighting quantization */ +#define FREQUENCY_WEIGHTING_QUANTIZATION 1 +#if FREQUENCY_WEIGHTING_QUANTIZATION +#define CHROMA_DELTA_QP 1 +#define AWQ_WEIGHTING 1 +#define AWQ_LARGE_BLOCK_ENABLE 1 +#define COUNT_BIT_OVERHEAD 0 +#define AWQ_LARGE_BLOCK_EXT_MAPPING 1 +#endif + +#define QuantClip 1 +#define QuantMatrixClipFix 1 /* 20160418, fllu@pku.edu.cn */ + +#define WQ_MATRIX_FCD 1 +#if !WQ_MATRIX_FCD +#define WQ_FLATBASE_INBIT 7 +#else +#define WQ_FLATBASE_INBIT 6 +#endif + + +#define REFINED_QP 1 + + +/* ////////////////// delta QP ///// */ + /* M3122: the minimum dQP unit is Macro block */ +#define MB_DQP 1 + /* M3122: 1 represents left prediction + and 0 represents previous prediction */ +#define LEFT_PREDICTION 1 + + +/* //////////////////////SAO///////// */ +#define NUM_BO_OFFSET 32 +#define MAX_NUM_SAO_CLASSES 32 +#define NUM_SAO_BO_CLASSES_LOG2 5 +#define NUM_SAO_BO_CLASSES_IN_BIT 5 +#define MAX_DOUBLE (1.7e + 308) +#define NUM_SAO_EO_TYPES_LOG2 2 +#define NUM_SAO_BO_CLASSES (1<<NUM_SAO_BO_CLASSES_LOG2) +#define SAO_RATE_THR 0.75 +#define SAO_RATE_CHROMA_THR 1 +#define SAO_SHIFT_PIX_NUM 4 + +#define SAO_PARA_CROSS_SLICE 1 +#define SAO_MULSLICE_FTR_FIX 1 + +/* /////////////////// Transform ///////////////////// */ +#define SEC_TR_SIZE 4 + /* apply secT to greater than or equal to 8x8 block, */ +#define SEC_TR_MIN_BITSIZE 3 + +#define BUGFIXED_COMBINED_ST_BD 1 + +/* /////////////////// Scalable ///////////////////// */ +#define M3480_TEMPORAL_SCALABLE 1 +#define TEMPORAL_MAXLEVEL 8 +#define TEMPORAL_MAXLEVEL_BIT 3 + + + + +/* + ************************************* + * AVS2 macros end + * + ************************************* + */ + +#define CHROMA 1 +#define LUMA_8x8 2 +#define NUM_BLOCK_TYPES 8 + +#if (!defined clamp) + /* !< clamp a to the range of [b;c] */ +#define clamp(a, b, c) ((a) < (b) ? (b) : ((a) > (c) ? (c) : (a))) +#endif + + /* POC200301 moved from defines.h */ +#define LOG2_MAX_FRAME_NUM_MINUS4 4 + /* !< bytes for one frame */ +#define MAX_CODED_FRAME_SIZE 15000000 + +/* ----------------------- */ +/* FLAGS and DEFINES for new chroma intra prediction, Dzung Hoang */ +/* Threshold values to zero out quantized transform coefficients. */ +/* Recommend that _CHROMA_COEFF_COST_ be low to improve chroma quality */ +#define _LUMA_COEFF_COST_ 4 /* !< threshold for luma coeffs */ + /* !< Number of pixels padded around the reference frame (>=4) */ +#define IMG_PAD_SIZE 64 + +#define OUTSTRING_SIZE 255 + + /* !< abs macro, faster than procedure */ +#define absm(A) ((A) < (0) ? (-(A)) : (A)) + /* !< used for start value for some variables */ +#define MAX_VALUE 999999 + +#define Clip1(a) ((a) > 255 ? 255:((a) < 0 ? 0 : (a))) +#define Clip3(min, max, val) (((val) < (min)) ?\ + (min) : (((val) > (max)) ? (max) : (val))) + +/* --------------------------------------------- */ + +/* block size of block transformed by AVS */ +#define PSKIPDIRECT 0 +#define P2NX2N 1 +#define P2NXN 2 +#define PNX2N 3 +#define PHOR_UP 4 +#define PHOR_DOWN 5 +#define PVER_LEFT 6 +#define PVER_RIGHT 7 +#define PNXN 8 +#define I8MB 9 +#define I16MB 10 +#define IBLOCK 11 +#define InNxNMB 12 +#define INxnNMB 13 +#define MAXMODE 14 /* add yuqh 20130824 */ +#define LAMBDA_ACCURACY_BITS 16 +#define LAMBDA_FACTOR(lambda) ((int)((double)(1 << LAMBDA_ACCURACY_BITS)\ + * lambda + 0.5)) +#define WEIGHTED_COST(factor, bits) (((factor) * (bits))\ + >> LAMBDA_ACCURACY_BITS) +#define MV_COST(f, s, cx, cy, px, py) (WEIGHTED_COST(f, mvbits[((cx) << (s))\ + - px] + mvbits[((cy) << (s)) - py])) +#define REF_COST(f, ref) (WEIGHTED_COST(f, refbits[(ref)])) + +#define BWD_IDX(ref) (((ref) < 2) ? 1 - (ref) : (ref)) +#define REF_COST_FWD(f, ref) (WEIGHTED_COST(f,\ + ((img->num_ref_pic_active_fwd_minus1 == 0) ?\ + 0 : refbits[(ref)]))) +#define REF_COST_BWD(f, ef) (WEIGHTED_COST(f,\ + ((img->num_ref_pic_active_bwd_minus1 == 0) ?\ + 0 : BWD_IDX(refbits[ref])))) + +#define IS_INTRA(MB) ((MB)->cuType == I8MB ||\ + (MB)->cuType == I16MB ||\ + (MB)->cuType == InNxNMB || (MB)->cuType == INxnNMB) +#define IS_INTER(MB) ((MB)->cuType != I8MB &&\ + (MB)->cuType != I16MB && (MB)->cuType != InNxNMB\ + && (MB)->cuType != INxnNMB) +#define IS_INTERMV(MB) ((MB)->cuType != I8MB &&\ + (MB)->cuType != I16MB && (MB)->cuType != InNxNMB &&\ + (MB)->cuType != INxnNMB && (MB)->cuType != 0) + + +#define IS_DIRECT(MB) ((MB)->cuType == PSKIPDIRECT && (img->type == B_IMG)) +#define IS_P_SKIP(MB) ((MB)->cuType == PSKIPDIRECT &&\ + (((img->type == F_IMG)) || ((img->type == P_IMG)))) +#define IS_P8x8(MB) ((MB)->cuType == PNXN) + +/* Quantization parameter range */ +#define MIN_QP 0 +#define MAX_QP 63 +#define SHIFT_QP 11 + +/* Picture types */ +#define INTRA_IMG 0 /* !< I frame */ +#define INTER_IMG 1 /* !< P frame */ +#define B_IMG 2 /* !< B frame */ +#define I_IMG 0 /* !< I frame */ +#define P_IMG 1 /* !< P frame */ +#define F_IMG 4 /* !< F frame */ + +#define BACKGROUND_IMG 3 + +#define BP_IMG 5 + + +/* Direct Mode types */ +#define MIN_CU_SIZE 8 +#define MIN_BLOCK_SIZE 4 +#define MIN_CU_SIZE_IN_BIT 3 +#define MIN_BLOCK_SIZE_IN_BIT 2 +#define BLOCK_MULTIPLE (MIN_CU_SIZE/(MIN_BLOCK_SIZE)) +#define MAX_CU_SIZE 64 +#define MAX_CU_SIZE_IN_BIT 6 +#define B4X4_IN_BIT 2 +#define B8X8_IN_BIT 3 +#define B16X16_IN_BIT 4 +#define B32X32_IN_BIT 5 +#define B64X64_IN_BIT 6 + /* !< # luma intra prediction modes */ +#define NUM_INTRA_PMODE 33 + /* number of luma modes for full RD search */ +#define NUM_MODE_FULL_RD 9 + /* !< #chroma intra prediction modes */ +#define NUM_INTRA_PMODE_CHROMA 5 + +/* luma intra prediction modes */ + +#define DC_PRED 0 +#define PLANE_PRED 1 +#define BI_PRED 2 +#define VERT_PRED 12 +#define HOR_PRED 24 + + +/* chroma intra prediction modes */ +#define DM_PRED_C 0 +#define DC_PRED_C 1 +#define HOR_PRED_C 2 +#define VERT_PRED_C 3 +#define BI_PRED_C 4 + +#define EOS 1 /* !< End Of Sequence */ + /* !< Start Of Picture */ +#define SOP 2 + +#define DECODING_OK 0 +#define SEARCH_SYNC 1 +#define DECODE_MB 1 + +#ifndef max + /* !< Macro returning max value */ +#define max(a, b) ((a) > (b) ? (a) : (b)) + /* !< Macro returning min value */ +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + + +#define XY_MIN_PMV 1 +#if XY_MIN_PMV +#define MVPRED_xy_MIN 0 +#else +#define MVPRED_MEDIAN 0 +#endif +#define MVPRED_L 1 +#define MVPRED_U 2 +#define MVPRED_UR 3 + +#define DUAL 4 +#define FORWARD 0 +#define BACKWARD 1 +#define SYM 2 +#define BID 3 +#define INTRA -1 + +#define BUF_CYCLE 5 + +#define ROI_M3264 1 /* ROI Information Encoding */ + +#define PicExtensionData 1 + + +#define REF_OUTPUT 1 /* M3337 */ + + +/* MV scaling 14 bit */ +#define MULTI 16384 +#define HALF_MULTI 8192 +#define OFFSET 14 +/* end of MV scaling */ + /* store the middle pixel's mv in a motion information unit */ +#define MV_DECIMATION_FACTOR 4 + +/* BUGFIX_AVAILABILITY_INTRA */ +#define NEIGHBOR_INTRA_LEFT 0 +#define NEIGHBOR_INTRA_UP 1 +#define NEIGHBOR_INTRA_UP_RIGHT 2 +#define NEIGHBOR_INTRA_UP_LEFT 3 +#define NEIGHBOR_INTRA_LEFT_DOWN 4 +/* end of BUGFIX_AVAILABILITY_INTRA */ + +/* end #include "define.h" */ + +/*#include "commonStructures.h"*/ + +/*typedef uint16_t byte;*/ /* !< byte type definition */ +#define byte uint16_t +#define pel_t byte + +enum BitCountType_e { + BITS_HEADER, + BITS_TOTAL_MB, + BITS_MB_MODE, + BITS_INTER_MB, + BITS_CBP_MB, + BITS_CBP01_MB, + BITS_COEFF_Y_MB, + BITS_COEFF_UV_MB, + BITS_DELTA_QUANT_MB, + BITS_SAO_MB, + MAX_BITCOUNTER_MB +}; + + +enum SAOEOClasses { +/* EO Groups, the assignments depended on +how you implement the edgeType calculation */ + SAO_CLASS_EO_FULL_VALLEY = 0, + SAO_CLASS_EO_HALF_VALLEY = 1, + SAO_CLASS_EO_PLAIN = 2, + SAO_CLASS_EO_HALF_PEAK = 3, + SAO_CLASS_EO_FULL_PEAK = 4, + SAO_CLASS_BO = 5, + NUM_SAO_EO_CLASSES = SAO_CLASS_BO, + NUM_SAO_OFFSET +}; + +struct SAOstatdata { + int32_t diff[MAX_NUM_SAO_CLASSES]; + int32_t count[MAX_NUM_SAO_CLASSES]; +}; + +struct CopyRight_s { + int32_t extension_id; + int32_t copyright_flag; + int32_t copyright_id; + int32_t original_or_copy; + int32_t reserved; + int32_t copyright_number; +}; + +struct CameraParamters_s { + int32_t reserved; + int32_t camera_id; + int32_t height_of_image_device; + int32_t focal_length; + int32_t f_number; + int32_t vertical_angle_of_view; + int32_t camera_position_x; + int32_t camera_position_y; + int32_t camera_position_z; + int32_t camera_direction_x; + int32_t camera_direction_y; + int32_t camera_direction_z; + int32_t image_plane_vertical_x; + int32_t image_plane_vertical_y; + int32_t image_plane_vertical_z; +}; + +/* ! SNRParameters */ +struct SNRParameters_s { + double snr_y; /* !< current Y SNR */ + double snr_u; /* !< current U SNR */ + double snr_v; /* !< current V SNR */ + double snr_y1; /* !< SNR Y(dB) first frame */ + double snr_u1; /* !< SNR U(dB) first frame */ + double snr_v1; /* !< SNR V(dB) first frame */ + double snr_ya; /* !< Average SNR Y(dB) remaining frames */ + double snr_ua; /* !< Average SNR U(dB) remaining frames */ + double snr_va; /* !< Average SNR V(dB) remaining frames */ +#if INTERLACE_CODING + double i_snr_ya; /* !< current Y SNR */ + double i_snr_ua; /* !< current U SNR */ + double i_snr_va; /* !< current V SNR */ +#endif +}; + +/* signal to noise ratio parameters */ + +/* ! codingUnit */ +struct codingUnit { + uint32_t ui_MbBitSize; + int32_t uiBitSize; /* size of MB */ + /* !< number of current syntax element */ + int32_t currSEnr; + int32_t slice_nr; + int32_t delta_quant; /* !< for rate control */ + int32_t delta_qp; + int32_t qp; + int32_t bitcounter[MAX_BITCOUNTER_MB]; + struct codingUnit + *mb_available[3][3]; /*!< pointer to neighboring MBs + in a 3x3 window of current MB, which is located at [1][1] \n + NULL pointer identifies neighboring MBs which are unavailable */ + /* some storage of codingUnit syntax elements for global access */ + int32_t cuType; + int32_t weighted_skipmode; + + int32_t md_directskip_mode; + + int32_t trans_size; + int + /* !< indices correspond to [forw,backw][block_y][block_x][x,y, dmh] */ + mvd[2][BLOCK_MULTIPLE][BLOCK_MULTIPLE][3]; + + int32_t intra_pred_modes[BLOCK_MULTIPLE * BLOCK_MULTIPLE]; + int32_t real_intra_pred_modes[BLOCK_MULTIPLE * BLOCK_MULTIPLE]; + int32_t l_ipred_mode; + int32_t cbp, cbp_blk; + uint32_t cbp_bits; + + int32_t b8mode[4]; + int32_t b8pdir[4]; + /* !< chroma intra prediction mode */ + int32_t c_ipred_mode; + + /* !< pointer to neighboring MB (AEC) */ + struct codingUnit *mb_available_up; + /* !< pointer to neighboring MB (AEC) */ + struct codingUnit *mb_available_left; + int32_t mbAddrA, mbAddrB, mbAddrC, mbAddrD; + /* !<added by mz, 2008.04 */ + int32_t slice_set_index; + /* added by mz, 2008.04 */ + int32_t slice_header_flag; + int32_t sliceqp; /* added by mz, 2008.04 */ +#if MB_DQP + int32_t previouse_qp; + int32_t left_cu_qp; +#endif + int32_t block_available_up; + int32_t block_available_left; + +}; + + +/* image parameters */ +struct syntaxelement; +struct slice; +struct alfdatapart; +struct SAOBlkParam_s { + int32_t modeIdc; /* NEW, MERGE, OFF */ + /* NEW: EO_0, EO_90, EO_135, EO_45, BO. MERGE: left, above */ + int32_t typeIdc; + int32_t startBand; /* BO: starting band index */ + int32_t startBand2; + int32_t deltaband; + int32_t offset[MAX_NUM_SAO_CLASSES]; +}; +struct ALFParam_s { + int32_t alf_flag; + int32_t num_coeff; + int32_t filters_per_group; + int32_t componentID; + int32_t filterPattern[16]; /* *filterPattern; */ + int32_t coeffmulti[16][9]; /* **coeffmulti; */ +}; + +enum ALFComponentID { + ALF_Y = 0, + ALF_Cb, + ALF_Cr, + NUM_ALF_COMPONENT +}; +struct ALF_APS_s { + int32_t usedflag; + int32_t cur_number; + int32_t max_number; + struct ALFParam_s alf_par[NUM_ALF_COMPONENT]; +}; + + +/* ------------------------------------------------------ + * frame data + */ +struct avs2_frame_s { + int32_t imgcoi_ref; + byte * *referenceFrame[3]; + int32_t **refbuf; + int32_t ***mvbuf; +#if 0 + double saorate[NUM_SAO_COMPONENTS]; +#endif + byte ***ref; + + int32_t imgtr_fwRefDistance; + int32_t refered_by_others; + int32_t is_output; + int32_t to_prepare_disp; +#if M3480_TEMPORAL_SCALABLE + /* temporal level setted in configure file */ + int32_t temporal_id; +#endif + byte **oneForthRefY; +#if FIX_MAX_REF + int32_t ref_poc[MAXREF]; +#else + int32_t ref_poc[4]; +#endif +#ifdef AML + int32_t index; + int32_t mmu_alloc_flag; + int32_t lcu_size_log2; + /*uint32_t header_adr;*/ + uint32_t mc_y_adr; + uint32_t mc_u_v_adr; + uint32_t mc_canvas_y; + uint32_t mc_canvas_u_v; + uint32_t mpred_mv_wr_start_addr; + uint8_t bg_flag; + /**/ + unsigned long header_adr; + int buf_size; + int lcu_total; + int comp_body_size; + uint32_t dw_y_adr; + uint32_t dw_u_v_adr; + int y_canvas_index; + int uv_canvas_index; + struct canvas_config_s canvas_config[2]; + int double_write_mode; + int bit_depth; + unsigned long cma_alloc_addr; + int BUF_index; + int pic_w; + int pic_h; + int stream_offset; + u32 pts; + u64 pts64; + /**/ + int vf_ref; + int decode_idx; + int slice_type; + int32_t imgtr_fwRefDistance_bak; + int32_t error_mark; + int32_t decoded_lcu; +#endif +#ifndef MV_USE_FIXED_BUF + int mv_buf_index; +#endif + + /* picture qos infomation*/ + int max_qp; + int avg_qp; + int min_qp; + int max_skip; + int avg_skip; + int min_skip; + int max_mv; + int min_mv; + int avg_mv; + + u32 hw_decode_time; + u32 frame_size; // For frame base mode + + char *cuva_data_buf; + int cuva_data_size; +}; + + +struct ImageParameters_s { + struct codingUnit *mb_data; + int32_t number; /* <! frame number */ + int32_t numIPFrames; + + int32_t type; + int32_t typeb; + int32_t typeb_before; + + int32_t qp; /* <! quant for the current frame */ + int32_t current_mb_nr; /* bitstream order */ + int32_t current_slice_nr; + int32_t tr; /* <! temporal reference, 8 bit, */ + + int32_t width; /* !< Number of pels */ + int32_t width_cr; /* !< Number of pels chroma */ + int32_t height; /* !< Number of lines */ + int32_t height_cr; /* !< Number of lines chroma */ + int32_t PicWidthInMbs; + int32_t PicSizeInMbs; + int32_t block8_x, block8_y; + int32_t subblock_x; + int32_t subblock_y; + + int32_t num_of_references; + /* <! Bug Fix: correct picture size for outputted reconstructed pictures */ + int32_t auto_crop_right; + int32_t auto_crop_bottom; + int32_t buf_cycle; + int32_t picture_structure; + /* <! pointer to current Slice data struct */ + struct slice *currentSlice; + + int32_t **predBlock; /* !< current best prediction mode */ + int32_t **predBlockTmp; + /* !< the diff pixel values between orginal image and prediction */ + int32_t **resiY; + /* !< Array containing square values,used for snr computation */ + int32_t *quad; + + /* //location of current MB////// */ + int32_t mb_y; /* !< current MB vertical */ + int32_t mb_x; /* !< current MB horizontal */ + int32_t pix_y; /* !< current pixel vertical */ + int32_t pix_x; /* !< current pixel horizontal */ + int32_t pix_c_y; /* !< current pixel chroma vertical */ + int32_t pix_c_x; /* !< current pixel chroma horizontal */ + + int32_t imgtr_next_P; + + int32_t imgcoi_next_ref; + + /* !< GH ipredmode[90][74];prediction mode for inter frames */ + /* fix from ver 4.1 */ + int32_t **ipredmode; + int32_t **rec_ipredmode; + + + /* //////////////decoder////////////////////////// */ + int32_t max_mb_nr; + int32_t **intra_block; + + int32_t block_y; + int32_t block_x; + /* <! final 4x4 block. Extended to 16x16 for AVS */ + int32_t resiUV[2][MAX_CU_SIZE][MAX_CU_SIZE]; + + int32_t **fw_refFrArr; /* <! [72][88]; */ + int32_t **bw_refFrArr; /* <! [72][88]; */ + + int32_t random_access_decodable_flag; + + int32_t seq_header_indicate; + int32_t B_discard_flag; + + /* B pictures */ + uint32_t pic_distance; + + uint32_t coding_order; + + uint32_t PrevPicDistanceLsb; + int32_t CurrPicDistanceMsb; + + int32_t PicHeightInMbs; + + int32_t types; + + int32_t new_sequence_flag; + int32_t sequence_end_flag; /* <! rm52k_r2 */ + + int32_t current_slice_set_index; /* <! added by mz, 2008.04 */ + int32_t current_slice_header_flag; /* <! added by mz, 2008.04 */ + int32_t slice_set_qp[64]; /* <! added by mz, 2008.04 */ + + + int32_t inter_amp_enable; + + /* ////////////////////////encoder////////////////////////// */ + + /* int32_t nb_references; //!< replaced by "num_of_references" */ + + int32_t framerate; + + int32_t ***predBlockY; /* !< all 9 prediction modes */ + /* !< new chroma 8x8 intra prediction modes */ + int32_t ****predBlockUV; + + int32_t **Coeff_all;/* qyu 0821 */ + + struct syntaxelement *MB_SyntaxElements; /* !< by oliver 0612 */ + + /* B pictures */ + + int32_t b_frame_to_code; + int32_t num_ref_pic_active_fwd_minus1; + int32_t num_ref_pic_active_bwd_minus1; + int32_t mv_range_flag; + + uint32_t frame_num; /* frame_num for this frame */ + int32_t slice_offset; + /* the following are sent in the slice header */ + int32_t NoResidueDirect; + int32_t coded_mb_nr; + int32_t progressive_frame; + int32_t tc_reserve_bit; + /* the last MB no in current slice. Yulj 2004.07.15 */ + int32_t mb_no_currSliceLastMB; + int32_t Seqheader_flag; /* Added by cjw, 20070327 */ + int32_t EncodeEnd_flag; /* Carmen, 2007/12/19 */ + + uint16_t bbv_delay; + + int32_t tmp_fwBSkipMv[DIRECTION + 1][2]; + int32_t tmp_bwBSkipMv[DIRECTION + 1][2]; + + int32_t tmp_pref_fst[MH_PSKIP_NUM + NUM_OFFSET + 1]; + int32_t tmp_pref_snd[MH_PSKIP_NUM + NUM_OFFSET + 1]; + int32_t tmp_fstPSkipMv[MH_PSKIP_NUM + NUM_OFFSET + 1][3]; + int32_t tmp_sndPSkipMv[MH_PSKIP_NUM + NUM_OFFSET + 1][3]; +#if BCBR +byte *org_ref_y; +byte *org_ref_u; +byte *org_ref_v; +int32_t *BLCUidx; +int32_t *DQPList; +int32_t iNumCUsInFrame; + +byte *org_ref2_y; +byte *org_ref2_u; +byte *org_ref2_v; +int32_t ref2Num; +#endif +/* //////////////SAO parameter////////////////// */ +double *cur_saorate; +#if 0 +int32_t slice_sao_on[NUM_SAO_COMPONENTS]; +#endif +int32_t pic_alf_on[NUM_ALF_COMPONENT]; +struct alfdatapart *dp_ALF; + +#if INTERLACE_CODING +int32_t is_field_sequence; +int32_t is_top_field; +#endif + + +}; + + + +/* ! struct for context management */ +struct BiContextType_s { + uint8_t MPS; /* 1 bit */ + uint32_t LG_PMPS; /* 10 bits */ + uint8_t cycno; /* 2 bits */ +}; + +/*********************************************************************** + * D a t a t y p e s f o r A E C + ************************************************************************/ + + + +struct pix_pos { + int32_t available; /* ABCD */ + int32_t mb_addr; /* MB position */ + int32_t x; + int32_t y; + int32_t pos_x; /* 4x4 x-pos */ + int32_t pos_y; +}; + + + +struct STDOUT_DATA_s { + int32_t type; + int32_t typeb; + + int32_t framenum; + int32_t tr; + int32_t qp; + double snr_y; + double snr_u; + double snr_v; + int32_t tmp_time; + int32_t picture_structure; + int32_t curr_frame_bits; + int32_t emulate_bits; + + uint32_t DecMD5Value[4]; +#if RD1501_FIX_BG +int32_t background_picture_output_flag;/* Longfei.Wang@mediatek.com */ +#endif +#if RD160_FIX_BG +int32_t picture_reorder_delay; +#endif +int8_t str_reference_list[128]; /* reference list information */ +}; + +/********************************************************************** + * C O N T E X T S F O R T M L S Y N T A X E L E M E N T S + ********************************************************************** + */ +#define NUM_CuType_CTX (11 + 10) +#define NUM_B8_TYPE_CTX 9 +#define NUM_MVD_CTX 15 +#define NUM_PMV_IDX_CTX 10 +#define NUM_REF_NO_CTX 6 +#define NUM_DELTA_QP_CTX 4 +#define NUM_INTER_DIR_CTX 18 +#define NUM_INTER_DIR_DHP_CTX 3 +#define NUM_B8_TYPE_DHP_CTX 1 +#define NUM_AMP_CTX 2 +#define NUM_C_INTRA_MODE_CTX 4 +#define NUM_CBP_CTX 4 +#define NUM_BCBP_CTX 4 +#define NUM_MAP_CTX 17 +#define NUM_LAST_CTX 17 + +#define NUM_INTRA_MODE_CTX 7 + +#define NUM_ABS_CTX 5 +#define NUM_TU_CTX 3 +#define NUM_SPLIT_CTX 8 /* CU depth */ +#if BCBR +#define NUM_BGBLCOK_CTX 1 +#endif + +#define NUM_BRP_CTX 8 + + +#define NUM_LAST_CG_CTX_LUMA 12 +#define NUM_LAST_CG_CTX_CHROMA 6 +#define NUM_SIGCG_CTX_LUMA 2 +#define NUM_SIGCG_CTX_CHROMA 1 +#define NUM_LAST_POS_CTX_LUMA 56 +#define NUM_LAST_POS_CTX_CHROMA 16 +#define NUM_LAST_CG_CTX (NUM_LAST_CG_CTX_LUMA + NUM_LAST_CG_CTX_CHROMA) +#define NUM_SIGCG_CTX (NUM_SIGCG_CTX_LUMA + NUM_SIGCG_CTX_CHROMA) +#define NUM_LAST_POS_CTX (NUM_LAST_POS_CTX_LUMA + NUM_LAST_POS_CTX_CHROMA) +#define NUM_SAO_MERGE_FLAG_CTX 3 +#define NUM_SAO_MODE_CTX 1 +#define NUM_SAO_OFFSET_CTX 2 +#define NUM_INTER_DIR_MIN_CTX 2 + +/*end #include "commonStructures.h"*/ + +/*#include "commonVariables.h"*/ + +/* +extern struct CameraParamters_s *camera; +extern struct SNRParameters_s *snr; +extern struct ImageParameters_s *img; + */ + +/* avs2_frame_t *fref[REF_MAXBUFFER]; */ + + +#define ET_SIZE 300 /* !< size of error text buffer */ + + +/* ------------------------------------------------------ + * common data + */ +struct Video_Com_data_s { + int32_t Bframe_ctr; + + /* FILE *p_log; //!< SNR file */ + /* FILE *p_trace; //!< Trace file */ + + int32_t tot_time; + + /* Tsinghua for picture_distance 200701 */ + int32_t picture_distance; + + /* M3178 PKU Reference Manage */ + int32_t coding_order; + /* !< current encoding/decoding frame pointer */ + struct avs2_frame_s *f_rec; + int32_t seq_header; + /* !< Array for reference frames of each block */ + int32_t **refFrArr; + int32_t **p_snd_refFrArr; + + byte ***currentFrame; /* [yuv][height][width] */ +#ifdef AML + struct avs2_frame_s *cur_pic; /*either f_rec or m_bg*/ +#endif + byte **backgroundReferenceFrame[3]; + byte ***background_ref; + + + int32_t total_frames; + + /* mv_range, 20071009 */ + int32_t Min_V_MV; + int32_t Max_V_MV; + int32_t Min_H_MV; + int32_t Max_H_MV; + /* !< buffer for error message for exit with error(void) */ + int8_t errortext[ET_SIZE]; + int8_t str_list_reference[128]; + + +}; +/* extern Video_Com_data *hc; */ + + +/*end #include "commonVariables.h"*/ +/* #define USE_PARAM_TXT */ +/* +#if FIX_CHROMA_FIELD_MV_BK_DIST +int8_t bk_img_is_top_field; +#endif +*/ +/* void write_GB_frame(FILE *p_dec); */ + +#if !FIX_MAX_REF +#define MAXREF 4 +#define MAXGOP 32 +#endif + +struct StatBits { + int32_t curr_frame_bits; + int32_t prev_frame_bits; + int32_t emulate_bits; + int32_t prev_emulate_bits; + int32_t last_unit_bits; + int32_t bitrate; + int32_t total_bitrate[1000]; + int32_t coded_pic_num; + int32_t time_s; +}; + +struct reference_management { + int32_t poc; + int32_t qp_offset; + int32_t num_of_ref; + int32_t referd_by_others; + int32_t ref_pic[MAXREF]; + int32_t predict; + int32_t deltaRPS; + int32_t num_to_remove; + int32_t remove_pic[MAXREF]; +}; + + +/* ------------------------------------------------------ + * dec data + */ +struct Video_Dec_data_s { + byte **background_frame[3]; + int32_t background_reference_enable; + + int32_t background_picture_flag; + int32_t background_picture_output_flag; + int32_t background_picture_enable; + + int32_t background_number; + +#if BCBR + int32_t bcbr_enable; +#endif + + int32_t demulate_enable; + int32_t currentbitoffset; + + int32_t aspect_ratio_information; + int32_t frame_rate_code; + int32_t bit_rate_lower; + int32_t bit_rate_upper; + int32_t marker_bit; + + int32_t video_format; + int32_t color_description; + int32_t color_primaries; + int32_t transfer_characteristics; + int32_t matrix_coefficients; + + int32_t progressive_sequence; +#if INTERLACE_CODING +int32_t is_field_sequence; +#endif +int32_t low_delay; +int32_t horizontal_size; +int32_t vertical_size; +int32_t sample_precision; +int32_t video_range; + +int32_t display_horizontal_size; +int32_t display_vertical_size; +int32_t TD_mode; +int32_t view_packing_mode; +int32_t view_reverse; + +int32_t b_pmvr_enabled; +int32_t dhp_enabled; +int32_t b_dmh_enabled; +int32_t b_mhpskip_enabled; +int32_t wsm_enabled; +int32_t b_secT_enabled; + +int32_t tmp_time; +int32_t FrameNum; +int32_t eos; +int32_t pre_img_type; +int32_t pre_img_types; +/* int32_t pre_str_vec; */ +int32_t pre_img_tr; +int32_t pre_img_qp; +int32_t pre_tmp_time; +int32_t RefPicExist; /* 20071224 */ +int32_t BgRefPicExist; +int32_t dec_ref_num; /* ref order */ + +/* video edit code */ /* M1956 by Grandview 2006.12.12 */ +int32_t vec_flag; + +/* Copyright_extension(void) header */ +int32_t copyright_flag; +int32_t copyright_identifier; +int32_t original_or_copy; +int64_t copyright_number_1; +int64_t copyright_number_2; +int64_t copyright_number_3; +/* Camera_parameters_extension */ +int32_t camera_id; +int32_t height_of_image_device; +int32_t focal_length; +int32_t f_number; +int32_t vertical_angle_of_view; +int32_t camera_position_x_upper; +int32_t camera_position_x_lower; +int32_t camera_position_y_upper; +int32_t camera_position_y_lower; +int32_t camera_position_z_upper; +int32_t camera_position_z_lower; +int32_t camera_direction_x; +int32_t camera_direction_y; +int32_t camera_direction_z; +int32_t image_plane_vertical_x; +int32_t image_plane_vertical_y; +int32_t image_plane_vertical_z; + +#if AVS2_HDR_HLS +/* mastering_display_and_content_metadata_extension(void) header */ +int32_t display_primaries_x0; +int32_t display_primaries_y0; +int32_t display_primaries_x1; +int32_t display_primaries_y1; +int32_t display_primaries_x2; +int32_t display_primaries_y2; +int32_t white_point_x; +int32_t white_point_y; +int32_t max_display_mastering_luminance; +int32_t min_display_mastering_luminance; +int32_t maximum_content_light_level; +int32_t maximum_frame_average_light_level; +#endif + +/* I_pictures_header(void) */ +int32_t top_field_first; +int32_t repeat_first_field; +int32_t progressive_frame; +#if INTERLACE_CODING +int32_t is_top_field; +#endif +/* int32_t fixed_picture_qp; //qyu 0927 */ +int32_t picture_qp; +int32_t fixed_picture_qp; +int32_t time_code_flag; +int32_t time_code; +int32_t loop_filter_disable; +int32_t loop_filter_parameter_flag; +/* int32_t alpha_offset; */ +/* int32_t beta_offset; */ + +/* Pb_picture_header(void) */ +int32_t picture_coding_type; + +/*picture_display_extension(void)*/ +int32_t frame_centre_horizontal_offset[4]; +int32_t frame_centre_vertical_offset[4]; + +/* slice_header(void) */ +int32_t img_width; +int32_t slice_vertical_position; +int32_t slice_vertical_position_extension; +int32_t fixed_slice_qp; +int32_t slice_qp; +int32_t slice_horizontal_positon; /* added by mz, 2008.04 */ +int32_t slice_horizontal_positon_extension; + +int32_t StartCodePosition; +int32_t background_pred_flag; + + +/* Reference Manage */ +int32_t displaydelay; +int32_t picture_reorder_delay; +#if M3480_TEMPORAL_SCALABLE +int32_t temporal_id_exist_flag; +#endif + +int32_t gop_size; +struct reference_management decod_RPS[MAXGOP]; +struct reference_management curr_RPS; +int32_t last_output; +int32_t trtmp; +#if M3480_TEMPORAL_SCALABLE +int32_t cur_layer; +#endif + +/* Adaptive frequency weighting quantization */ +#if FREQUENCY_WEIGHTING_QUANTIZATION +int32_t weight_quant_enable_flag; +int32_t load_seq_weight_quant_data_flag; + +int32_t pic_weight_quant_enable_flag; +int32_t pic_weight_quant_data_index; +int32_t weighting_quant_param; +int32_t weighting_quant_model; +int16_t quant_param_undetail[6]; /* M2148 2007-09 */ +int16_t quant_param_detail[6]; /* M2148 2007-09 */ +int32_t WeightQuantEnable; /* M2148 2007-09 */ +int32_t mb_adapt_wq_disable; /* M2331 2008-04 */ +int32_t mb_wq_mode; /* M2331 2008-04 */ +#if CHROMA_DELTA_QP +int32_t chroma_quant_param_disable; +int32_t chroma_quant_param_delta_u; +int32_t chroma_quant_param_delta_v; +#endif + +int32_t b_pre_dec_intra_img; +int32_t pre_dec_img_type; +int32_t CurrentSceneModel; +#endif + +int32_t curr_IDRcoi; +int32_t curr_IDRtr; +int32_t next_IDRtr; +int32_t next_IDRcoi; +int32_t end_SeqTr; + +#if MB_DQP +int32_t lastQP; +/* FILE * testQP; */ +#endif + +}; +/* extern Video_Dec_data *hd; */ + +struct DecodingEnvironment_s { + uint32_t Dbuffer; + int32_t Dbits_to_go; + uint8_t *Dcodestrm; + int32_t *Dcodestrm_len; +}; + +/* added at rm52k version */ + +struct inp_par; + + + +/* ! Slice */ +struct slice { + int32_t picture_id; + int32_t qp; + int32_t picture_type; /* !< picture type */ + int32_t start_mb_nr; + /* !< number of different partitions */ + int32_t max_part_nr; + + /* added by lzhang */ + /* !< pointer to struct of context models for use in AEC */ + struct SyntaxInfoContexts_s *syn_ctx; +}; + +struct alfdatapart { + struct Bitstream_s *bitstream; + struct DecodingEnvironment_s de_AEC; + struct SyntaxInfoContexts_s *syn_ctx; +}; +/* static int32_t alfParAllcoated = 0; */ + +/* input parameters from configuration file */ +struct inp_par { + int32_t buf_cycle; /* <! Frame buffer size */ + int32_t ref_pic_order; /* <! ref order */ + int32_t output_dec_pic; /* <! output_dec_pic */ + int32_t profile_id; + int32_t level_id; + int32_t chroma_format; + int32_t g_uiMaxSizeInBit; + int32_t alpha_c_offset; + int32_t beta_offset; + int32_t useNSQT; +#if MB_DQP + int32_t useDQP; +#endif + int32_t useSDIP; + int32_t sao_enable; +#if M3480_TEMPORAL_SCALABLE + int32_t temporal_id_exist_flag; +#endif + int32_t alf_enable; + + int32_t crossSliceLoopFilter; + + int32_t sample_bit_depth; /* sample bit depth */ + /* decoded file bit depth (assuming output_bit_depth is + less or equal to sample_bit_depth) */ + int32_t output_bit_depth; + + + int32_t MD5Enable; + +#if OUTPUT_INTERLACE_MERGED_PIC + int32_t output_interlace_merged_picture; +#endif + +}; + +/* extern struct inp_par *input; */ + +struct outdata_s { +#if RD170_FIX_BG + struct STDOUT_DATA_s stdoutdata[REF_MAXBUFFER]; +#else + struct STDOUT_DATA_s stdoutdata[8]; +#endif + int32_t buffer_num; +}; +/* outdata outprint; */ + +#define PAYLOAD_TYPE_IDERP 8 + +struct Bitstream_s *AllocBitstream(void); +void FreeBitstream(void); +#if TRACE +void tracebits2(const int8_t *trace_str, int32_t len, int32_t info); +#endif + +/* int32_t direct_mv[45][80][4][4][3]; // only to verify result */ + +#define I_PICTURE_START_CODE 0xB3 +#define PB_PICTURE_START_CODE 0xB6 +#define SLICE_START_CODE_MIN 0x00 +#define SLICE_START_CODE_MAX 0x8F +#define USER_DATA_START_CODE 0xB2 +#define SEQUENCE_HEADER_CODE 0xB0 +#define EXTENSION_START_CODE 0xB5 +#define SEQUENCE_END_CODE 0xB1 +#define VIDEO_EDIT_CODE 0xB7 + + +#define SEQUENCE_DISPLAY_EXTENSION_ID 2 +#define COPYRIGHT_EXTENSION_ID 4 +#define CAMERAPARAMETERS_EXTENSION_ID 11 +#define PICTURE_DISPLAY_EXTENSION_ID 7 +#if M3480_TEMPORAL_SCALABLE +#define TEMPORAL_SCALABLE_EXTENSION_ID 3 +#endif + +#if ROI_M3264 +#if RD1501_FIX_BG +#define LOCATION_DATA_EXTENSION_ID 12 +#else +#define LOCATION_DATA_EXTENSION_ID 15 +#endif +#endif + +#if AVS2_HDR_HLS +#define MASTERING_DISPLAY_AND_CONTENT_METADATA_EXTENSION 10 +#endif + +void malloc_slice(void); +void free_slice(void); + + +void read_ipred_modes(void); + +int32_t AEC_startcode_follows(int32_t eos_bit); + +/* extern uint32_t max_value_s; */ + +/*ComAdaptiveLoopFilter.h*/ +#define ALF_MAX_NUM_COEF 9 +#define NO_VAR_BINS 16 + + +#define RPM_BEGIN 0x100 +#define ALF_BEGIN 0x180 +#define RPM_END 0x280 + +union param_u { + struct { + uint16_t data[RPM_END - RPM_BEGIN]; + } l; + struct { + /*sequence*/ + uint16_t profile_id; + uint16_t level_id; + uint16_t progressive_sequence; + uint16_t is_field_sequence; + uint16_t horizontal_size; + uint16_t vertical_size; + uint16_t chroma_format; + uint16_t sample_precision; + uint16_t encoding_precision; + uint16_t aspect_ratio_information; + uint16_t frame_rate_code; + uint16_t bit_rate_lower; + uint16_t bit_rate_upper; + uint16_t low_delay; + uint16_t temporal_id_exist_flag; + uint16_t g_uiMaxSizeInBit; + +#define BACKGROUND_PICTURE_DISABLE_BIT 11 +#define B_MHPSKIP_ENABLED_BIT 10 +#define DHP_ENABLED_BIT 9 +#define WSM_ENABLED_BIT 8 +#define INTER_AMP_ENABLE_BIT 7 +#define USENSQT_BIT 6 +#define USESDIP_BIT 5 +#define B_SECT_ENABLED_BIT 4 +#define SAO_ENABLE_BIT 3 +#define ALF_ENABLE_BIT 2 +#define B_PMVR_ENABLED_BIT 1 +#define CROSSSLICELOOPFILTER_BIT 0 + uint16_t avs2_seq_flags; + + uint16_t num_of_RPS; + uint16_t picture_reorder_delay; + /*PIC*/ + uint16_t time_code_flag; + uint16_t time_code; + uint16_t background_picture_flag; + uint16_t background_picture_output_flag; + uint16_t coding_order; + uint16_t cur_layer; + uint16_t displaydelay; /*???*/ + uint16_t predict; /*???*/ + uint16_t RPS_idx; /*???*/ + uint16_t referd_by_others_cur; + uint16_t num_of_ref_cur; + uint16_t ref_pic_cur[8]; + uint16_t num_to_remove_cur; + uint16_t remove_pic_cur[8]; + uint16_t progressive_frame; + uint16_t picture_structure; + uint16_t top_field_first; + uint16_t repeat_first_field; + uint16_t is_top_field; + + uint16_t picture_coding_type; + uint16_t background_pred_flag; + uint16_t background_reference_enable; + uint16_t random_access_decodable_flag; + uint16_t lcu_size; + uint16_t alpha_c_offset; + uint16_t beta_offset; + uint16_t chroma_quant_param_delta_cb; + uint16_t chroma_quant_param_delta_cr; + uint16_t loop_filter_disable; + + uint16_t video_signal_type; + uint16_t color_description; + uint16_t display_primaries_x[3]; + uint16_t display_primaries_y[3]; + uint16_t white_point_x; + uint16_t white_point_y; + uint16_t max_display_mastering_luminance; + uint16_t min_display_mastering_luminance; + uint16_t max_content_light_level; + uint16_t max_picture_average_light_level; + } p; + struct { + uint16_t padding[ALF_BEGIN - RPM_BEGIN]; + uint16_t picture_alf_enable_Y; + uint16_t picture_alf_enable_Cb; + uint16_t picture_alf_enable_Cr; + uint16_t alf_filters_num_m_1; + uint16_t region_distance[16]; + uint16_t alf_cb_coeffmulti[9]; + uint16_t alf_cr_coeffmulti[9]; + uint16_t alf_y_coeffmulti[16][9]; + } alf; +}; + + +struct avs2_decoder { + uint8_t init_hw_flag; + struct inp_par input; + struct ImageParameters_s img; + struct Video_Com_data_s hc; + struct Video_Dec_data_s hd; + union param_u param; + struct avs2_frame_s frm_pool[AVS2_MAX_BUFFER_NUM]; + struct avs2_frame_s *fref[REF_MAXBUFFER]; +#ifdef AML + /*used for background + when background_picture_output_flag is 0*/ + struct avs2_frame_s *m_bg; + /*current background picture, ether m_bg or fref[..]*/ + struct avs2_frame_s *f_bg; +#endif + struct outdata_s outprint; + uint32_t cm_header_start; + struct ALFParam_s m_alfPictureParam[NUM_ALF_COMPONENT]; +#ifdef FIX_CHROMA_FIELD_MV_BK_DIST + int8_t bk_img_is_top_field; +#endif +#ifdef AML + int32_t lcu_size; + int32_t lcu_size_log2; + int32_t lcu_x_num; + int32_t lcu_y_num; + int32_t lcu_total; + int32_t ref_maxbuffer; + int32_t to_prepare_disp_count; + int8_t bufmgr_error_flag; +#endif +}; + + +extern void write_frame(struct avs2_decoder *avs2_dec, int32_t pos); +extern void init_frame_t(struct avs2_frame_s *currfref); +extern void report_frame(struct avs2_decoder *avs2_dec, + struct outdata_s *data, int32_t pos); + +extern int avs2_post_process(struct avs2_decoder *avs2_dec); +extern void avs2_prepare_header(struct avs2_decoder *avs2_dec, + int32_t start_code); +extern int32_t avs2_process_header(struct avs2_decoder *avs2_dec); + +extern void init_avs2_decoder(struct avs2_decoder *avs2_dec); + +extern int32_t avs2_init_global_buffers(struct avs2_decoder *avs2_dec); + +extern bool is_avs2_print_param(void); +extern bool is_avs2_print_bufmgr_detail(void); +#endif +
diff --git a/drivers/frame_provider/decoder_v4l/avs2/vavs2.c b/drivers/frame_provider/decoder_v4l/avs2/vavs2.c new file mode 100644 index 0000000..ce5ffde --- /dev/null +++ b/drivers/frame_provider/decoder_v4l/avs2/vavs2.c
@@ -0,0 +1,8375 @@ + /* + * drivers/amlogic/amports/avs2.c + * + * Copyright (C) 2015 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/interrupt.h> +#include <linux/semaphore.h> +#include <linux/delay.h> +#include <linux/timer.h> +#include <linux/kfifo.h> +#include <linux/kthread.h> +#include <linux/spinlock.h> +#include <linux/platform_device.h> +#include <linux/amlogic/media/vfm/vframe.h> +#include <linux/amlogic/media/utils/amstream.h> +#include <linux/amlogic/media/utils/vformat.h> +#include <linux/amlogic/media/frame_sync/ptsserv.h> +#include <linux/amlogic/media/frame_sync/tsync.h> +#include <linux/amlogic/media/canvas/canvas.h> +#include <linux/amlogic/media/vfm/vframe_provider.h> +#include <linux/amlogic/media/vfm/vframe_receiver.h> +#include <linux/dma-mapping.h> +#include <linux/dma-contiguous.h> +#include <linux/slab.h> +//#include <linux/amlogic/tee.h> +#include <uapi/linux/tee.h> +#include <linux/sched/clock.h> +#include "../../../stream_input/amports/amports_priv.h" +#include <linux/amlogic/media/codec_mm/codec_mm.h> +#include "../../decoder/utils/decoder_mmu_box.h" +#include "../../decoder/utils/decoder_bmmu_box.h" +#include "avs2_global.h" + +#define MEM_NAME "codec_avs2" +/* #include <mach/am_regs.h> */ +#include <linux/amlogic/media/utils/vdec_reg.h> +#include "../../decoder/utils/vdec.h" +#include "../../decoder/utils/amvdec.h" + +#include <linux/amlogic/media/video_sink/video.h> +#include <linux/amlogic/media/codec_mm/configs.h> +#include "../../decoder/utils/config_parser.h" +#include "../../decoder/utils/firmware.h" +#include "../../../common/chips/decoder_cpu_ver_info.h" +#include "../../decoder/utils/vdec_feature.h" + + +#define I_ONLY_SUPPORT +#define MIX_STREAM_SUPPORT +#define G12A_BRINGUP_DEBUG +#define CONSTRAIN_MAX_BUF_NUM + +#define CO_MV_COMPRESS + +#include "vavs2.h" +#define HEVC_SHIFT_LENGTH_PROTECT 0x313a +#define HEVC_MPRED_CTRL4 0x324c +#define HEVC_MPRED_CTRL9 0x325b +#define HEVC_DBLK_CFGD 0x350d +#define HEVC_CM_HEADER_START_ADDR 0x3628 +#define HEVC_DBLK_CFGB 0x350b +#define HEVCD_MPP_ANC2AXI_TBL_DATA 0x3464 +#define HEVC_SAO_MMU_VH1_ADDR 0x363b +#define HEVC_SAO_MMU_VH0_ADDR 0x363a + + +/* + * AVS2_DEC_STATUS define +*/ +/*internal*/ +#define AVS2_DEC_IDLE 0 +#define AVS2_SEQUENCE 1 +#define AVS2_I_PICTURE 2 +#define AVS2_PB_PICTURE 3 +#define AVS2_DISCARD_STARTCODE 4 +#define AVS2_DISCARD_NAL 4 + +#define AVS2_SLICE_DECODING 6 + +#define SWAP_IN_CMD 0x10 +#define SWAP_OUT_CMD 0x11 +#define SWAP_OUTIN_CMD 0x12 +#define SWAP_DONE 0x13 +#define SWAP_POST_INIT 0x14 + +/*head*/ +#define AVS2_HEAD_SEQ_READY 0x21 +#define AVS2_HEAD_PIC_I_READY 0x22 +#define AVS2_HEAD_PIC_PB_READY 0x23 +#define AVS2_HEAD_SEQ_END_READY 0x24 +#define AVS2_STARTCODE_SEARCH_DONE 0x25 + +/*pic done*/ +#define HEVC_DECPIC_DATA_DONE 0x30 +#define HEVC_DECPIC_DATA_ERROR 0x31 +#define HEVC_NAL_DECODE_DONE 0x32 +#define AVS2_DECODE_BUFEMPTY 0x33 +#define AVS2_DECODE_TIMEOUT 0x34 +#define AVS2_DECODE_OVER_SIZE 0x35 +#define AVS2_EOS 0x36 + +/*cmd*/ +#define AVS2_10B_DISCARD_NAL 0xf0 +#define AVS2_SEARCH_NEW_PIC 0xf1 +#define AVS2_ACTION_ERROR 0xfe +#define HEVC_ACTION_ERROR 0xfe +#define AVS2_ACTION_DONE 0xff +/*AVS2_DEC_STATUS end*/ + + +#define VF_POOL_SIZE 32 + +#undef pr_info +#define pr_info printk + +#define DECODE_MODE_SINGLE (0 | (0x80 << 24)) +#define DECODE_MODE_MULTI_STREAMBASE (1 | (0x80 << 24)) +#define DECODE_MODE_MULTI_FRAMEBASE (2 | (0x80 << 24)) + + +#define VP9_TRIGGER_FRAME_DONE 0x100 +#define VP9_TRIGGER_FRAME_ENABLE 0x200 + +/*#define MV_MEM_UNIT 0x240*/ +#define MV_MEM_UNIT 0x200 +/*--------------------------------------------------- + Include "parser_cmd.h" +---------------------------------------------------*/ +#define PARSER_CMD_SKIP_CFG_0 0x0000090b + +#define PARSER_CMD_SKIP_CFG_1 0x1b14140f + +#define PARSER_CMD_SKIP_CFG_2 0x001b1910 + + +#define PARSER_CMD_NUMBER 37 + +static unsigned short parser_cmd[PARSER_CMD_NUMBER] = { +0x0401, +0x8401, +0x0800, +0x0402, +0x9002, +0x1423, +0x8CC3, +0x1423, +0x8804, +0x9825, +0x0800, +0x04FE, +0x8406, +0x8411, +0x1800, +0x8408, +0x8409, +0x8C2A, +0x9C2B, +0x1C00, +0x840F, +0x8407, +0x8000, +0x8408, +0x2000, +0xA800, +0x8410, +0x04DE, +0x840C, +0x840D, +0xAC00, +0xA000, +0x08C0, +0x08E0, +0xA40E, +0xFC00, +0x7C00 +}; + +static int32_t g_WqMDefault4x4[16] = { + 64, 64, 64, 68, + 64, 64, 68, 72, + 64, 68, 76, 80, + 72, 76, 84, 96 +}; + + +static int32_t g_WqMDefault8x8[64] = { + 64, 64, 64, 64, 68, 68, 72, 76, + 64, 64, 64, 68, 72, 76, 84, 92, + 64, 64, 68, 72, 76, 80, 88, 100, + 64, 68, 72, 80, 84, 92, 100, 112, + 68, 72, 80, 84, 92, 104, 112, 128, + 76, 80, 84, 92, 104, 116, 132, 152, + 96, 100, 104, 116, 124, 140, 164, 188, + 104, 108, 116, 128, 152, 172, 192, 216 +}; +/*#define HEVC_PIC_STRUCT_SUPPORT*/ +/* to remove, fix build error */ + +/*#define CODEC_MM_FLAGS_FOR_VDECODER 0*/ + +#define MULTI_INSTANCE_SUPPORT +/* #define ERROR_HANDLE_DEBUG */ + +#ifndef STAT_KTHREAD +#define STAT_KTHREAD 0x40 +#endif + +#ifdef MULTI_INSTANCE_SUPPORT +#define MAX_DECODE_INSTANCE_NUM 12 +#define MULTI_DRIVER_NAME "ammvdec_avs2_v4l" + +#define lock_buffer(dec, flags) \ + spin_lock_irqsave(&dec->buffer_lock, flags) + +#define unlock_buffer(dec, flags) \ + spin_unlock_irqrestore(&dec->buffer_lock, flags) + +static u32 debug_mask = 0xffffffff; +#define get_dbg_flag(dec) ((debug_mask & (1 << dec->index)) ? debug : 0) + +static unsigned int max_decode_instance_num + = MAX_DECODE_INSTANCE_NUM; +static unsigned int decode_frame_count[MAX_DECODE_INSTANCE_NUM]; +static unsigned int display_frame_count[MAX_DECODE_INSTANCE_NUM]; +static unsigned int max_process_time[MAX_DECODE_INSTANCE_NUM]; +static unsigned int run_count[MAX_DECODE_INSTANCE_NUM]; +static unsigned int input_empty[MAX_DECODE_INSTANCE_NUM]; +static unsigned int not_run_ready[MAX_DECODE_INSTANCE_NUM]; + +#ifdef G12A_BRINGUP_DEBUG +static u32 decode_timeout_val = 200; +#else +static u32 decode_timeout_val = 200; +#endif +static int start_decode_buf_level = 0x8000; +#ifdef AVS2_10B_MMU +static u32 work_buf_size; /* = 24 * 1024 * 1024*/; +#else +static u32 work_buf_size = 32 * 1024 * 1024; +#endif + +static u32 mv_buf_margin; +static int pre_decode_buf_level = 0x1000; +static u32 again_threshold; + + +/* DOUBLE_WRITE_MODE is enabled only when NV21 8 bit output is needed */ +/* double_write_mode: + * 0, no double write; + * 1, 1:1 ratio; + * 2, (1/4):(1/4) ratio; + * 3, (1/4):(1/4) ratio, with both compressed frame included + * 4, (1/2):(1/2) ratio; + * 8, (1/8):(1/8) ratio; + * 0x10, double write only + * 0x100, if > 1080p,use mode 4,else use mode 1; + * 0x200, if > 1080p,use mode 2,else use mode 1; + * 0x300, if > 720p, use mode 4, else use mode 1; + */ +static u32 double_write_mode; +static u32 without_display_mode; + +static u32 mv_buf_dynamic_alloc; +#define DRIVER_NAME "amvdec_avs2_v4l" +#define DRIVER_HEADER_NAME "amvdec_avs2_header" + + +#define PUT_INTERVAL (HZ/100) +#define ERROR_SYSTEM_RESET_COUNT 200 + +#define PTS_NORMAL 0 +#define PTS_NONE_REF_USE_DURATION 1 + +#define PTS_MODE_SWITCHING_THRESHOLD 3 +#define PTS_MODE_SWITCHING_RECOVERY_THREASHOLD 3 + +#define DUR2PTS(x) ((x)*90/96) + +struct AVS2Decoder_s; +static int vavs2_vf_states(struct vframe_states *states, void *); +static struct vframe_s *vavs2_vf_peek(void *); +static struct vframe_s *vavs2_vf_get(void *); +static void vavs2_vf_put(struct vframe_s *, void *); +static int vavs2_event_cb(int type, void *data, void *private_data); +static void set_vframe(struct AVS2Decoder_s *dec, + struct vframe_s *vf, struct avs2_frame_s *pic, u8 dummy); +static s32 vavs2_init(struct vdec_s *vdec); +static void vavs2_prot_init(struct AVS2Decoder_s *dec); +static int vavs2_local_init(struct AVS2Decoder_s *dec); +static void vavs2_put_timer_func(struct timer_list *timer); +static void dump_data(struct AVS2Decoder_s *dec, int size); +static unsigned char get_data_check_sum + (struct AVS2Decoder_s *dec, int size); +static void dump_pic_list(struct AVS2Decoder_s *dec); + +static const char vavs2_dec_id[] = "vavs2-dev"; + +#define PROVIDER_NAME "decoder.avs2" +#define MULTI_INSTANCE_PROVIDER_NAME "vdec.avs2" + +static const struct vframe_operations_s vavs2_vf_provider = { + .peek = vavs2_vf_peek, + .get = vavs2_vf_get, + .put = vavs2_vf_put, + .event_cb = vavs2_event_cb, + .vf_states = vavs2_vf_states, +}; + +static struct vframe_provider_s vavs2_vf_prov; + +static u32 bit_depth_luma; +static u32 bit_depth_chroma; +static u32 frame_width; +static u32 frame_height; +static u32 video_signal_type; +static u32 pts_unstable; +static u32 on_no_keyframe_skiped; + +static u32 force_video_signal_type; +static u32 enable_force_video_signal_type; +#define VIDEO_SIGNAL_TYPE_AVAILABLE_MASK 0x20000000 +#define HDR_CUVA_MASK 0x40000000 + + +static const char * const video_format_names[] = { + "component", "PAL", "NTSC", "SECAM", + "MAC", "unspecified", "Reserved", "Reserved" +}; + +static inline int div_r32(int64_t m, int n) +{ +/* +return (int)(m/n) +*/ +#ifndef CONFIG_ARM64 + int64_t qu = 0; + qu = div_s64(m, n); + return (int)qu; +#else + return (int)(m/n); +#endif +} + +enum vpx_bit_depth_t { + AVS2_BITS_8 = 8, /**< 8 bits */ + AVS2_BITS_10 = 10, /**< 10 bits */ + AVS2_BITS_12 = 12, /**< 12 bits */ +}; + +/*USE_BUF_BLOCK*/ +struct BUF_s { + int index; + unsigned int alloc_flag; + /*buffer */ + unsigned int cma_page_count; + unsigned long alloc_addr; + unsigned long start_adr; + unsigned int size; + + unsigned int free_start_adr; +} /*BUF_t */; + +struct MVBUF_s { + unsigned long start_adr; + unsigned int size; + int used_flag; +} /*MVBUF_t */; + + /* #undef BUFMGR_ONLY to enable hardware configuration */ + +/*#define TEST_WR_PTR_INC*/ +#define WR_PTR_INC_NUM 128 + +#define SIMULATION +#define DOS_PROJECT +#undef MEMORY_MAP_IN_REAL_CHIP + +/*#undef DOS_PROJECT*/ +/*#define MEMORY_MAP_IN_REAL_CHIP*/ + +/*#define BUFFER_MGR_ONLY*/ +/*#define CONFIG_HEVC_CLK_FORCED_ON*/ +/*#define ENABLE_SWAP_TEST*/ + +#ifdef AVS2_10B_NV21 +#define MEM_MAP_MODE 2 /* 0:linear 1:32x32 2:64x32*/ +#else +#define MEM_MAP_MODE 0 /* 0:linear 1:32x32 2:64x32*/ +#endif + +#ifdef AVS2_10B_NV21 +#else +#define LOSLESS_COMPRESS_MODE +#endif + +#define DOUBLE_WRITE_YSTART_TEMP 0x02000000 +#define DOUBLE_WRITE_CSTART_TEMP 0x02900000 + +#define AVS2_DBG_BUFMGR 0x01 +#define AVS2_DBG_BUFMGR_MORE 0x02 +#define AVS2_DBG_BUFMGR_DETAIL 0x04 +#define AVS2_DBG_IRQ_EVENT 0x08 +#define AVS2_DBG_OUT_PTS 0x10 +#define AVS2_DBG_PRINT_SOURCE_LINE 0x20 +#define AVS2_DBG_PRINT_PARAM 0x40 +#define AVS2_DBG_PRINT_PIC_LIST 0x80 +#define AVS2_DBG_SEND_PARAM_WITH_REG 0x100 +#define AVS2_DBG_MERGE 0x200 +#define AVS2_DBG_DBG_LF_PRINT 0x400 +#define AVS2_DBG_REG 0x800 +#define AVS2_DBG_PIC_LEAK 0x1000 +#define AVS2_DBG_PIC_LEAK_WAIT 0x2000 +#define AVS2_DBG_HDR_INFO 0x4000 +#define AVS2_DBG_HDR_DATA 0x8000 +#define AVS2_DBG_DIS_LOC_ERROR_PROC 0x10000 +#define AVS2_DBG_DIS_SYS_ERROR_PROC 0x20000 +#define AVS2_DBG_DUMP_PIC_LIST 0x40000 +#define AVS2_DBG_TRIG_SLICE_SEGMENT_PROC 0x80000 +#define AVS2_DBG_FORCE_UNCOMPRESS 0x100000 +#define AVS2_DBG_LOAD_UCODE_FROM_FILE 0x200000 +#define AVS2_DBG_FORCE_SEND_AGAIN 0x400000 +#define AVS2_DBG_DUMP_DATA 0x800000 +#define AVS2_DBG_DUMP_LMEM_BUF 0x1000000 +#define AVS2_DBG_DUMP_RPM_BUF 0x2000000 +#define AVS2_DBG_CACHE 0x4000000 +#define IGNORE_PARAM_FROM_CONFIG 0x8000000 +/*MULTI_INSTANCE_SUPPORT*/ +#define PRINT_FLAG_ERROR 0 +#define PRINT_FLAG_VDEC_STATUS 0x20000000 +#define PRINT_FLAG_VDEC_DETAIL 0x40000000 +#define PRINT_FLAG_VDEC_DATA 0x80000000 + +#define PRINT_LINE() \ + do { \ + if (debug & AVS2_DBG_PRINT_SOURCE_LINE)\ + pr_info("%s line %d\n", __func__, __LINE__);\ + } while (0) + +static u32 debug; + +static u32 debug_again; + +bool is_avs2_print_param(void) +{ + bool ret = false; + if (debug & AVS2_DBG_PRINT_PARAM) + ret = true; + return ret; +} + +bool is_avs2_print_bufmgr_detail(void) +{ + bool ret = false; + if (debug & AVS2_DBG_BUFMGR_DETAIL) + ret = true; + return ret; +} +static bool is_reset; +/*for debug*/ +static u32 force_bufspec; +/* + udebug_flag: + bit 0, enable ucode print + bit 1, enable ucode detail print + bit [31:16] not 0, pos to dump lmem + bit 2, pop bits to lmem + bit [11:8], pre-pop bits for alignment (when bit 2 is 1) +*/ +static u32 udebug_flag; +/* + when udebug_flag[1:0] is not 0 + udebug_pause_pos not 0, + pause position +*/ +static u32 udebug_pause_pos; +/* + when udebug_flag[1:0] is not 0 + and udebug_pause_pos is not 0, + pause only when DEBUG_REG2 is equal to this val +*/ +static u32 udebug_pause_val; + +static u32 udebug_pause_decode_idx; + +static u32 force_disp_pic_index; + +#define AUX_BUF_ALIGN(adr) ((adr + 0xf) & (~0xf)) +static u32 cuva_buf_size = 512; + +#define DEBUG_REG +#ifdef DEBUG_REG +static void WRITE_VREG_DBG2(unsigned adr, unsigned val) +{ + if (debug & AVS2_DBG_REG) + pr_info("%s(%x, %x)\n", __func__, adr, val); + if (adr != 0) + WRITE_VREG(adr, val); +} + +#undef WRITE_VREG +#define WRITE_VREG WRITE_VREG_DBG2 +#endif + + +//#ifdef AVS2_10B_MMU +//#define MMU_COMPRESS_HEADER_SIZE 0x48000 +//#define MMU_COMPRESS_8K_HEADER_SIZE 0x48000*4 +//#endif +#define MMU_COMPRESS_HEADER_SIZE_1080P 0x10000 +#define MMU_COMPRESS_HEADER_SIZE_4K 0x48000 +#define MMU_COMPRESS_HEADER_SIZE_8K 0x120000 + +#define INVALID_IDX -1 /* Invalid buffer index.*/ + + +#define FRAME_BUFFERS (AVS2_MAX_BUFFER_NUM) +#define HEADER_FRAME_BUFFERS (FRAME_BUFFERS) +#define MAX_BUF_NUM (FRAME_BUFFERS) + +#define FRAME_CONTEXTS_LOG2 2 +#define FRAME_CONTEXTS (1 << FRAME_CONTEXTS_LOG2) +/*buffer + header buffer + workspace*/ +#undef MV_USE_FIXED_BUF +#ifdef MV_USE_FIXED_BUF +#define MAX_BMMU_BUFFER_NUM ((FRAME_BUFFERS + HEADER_FRAME_BUFFERS + 1)+1) +#define VF_BUFFER_IDX(n) (n) +#define HEADER_BUFFER_IDX(n) (FRAME_BUFFERS + n+1) +#define WORK_SPACE_BUF_ID (FRAME_BUFFERS + HEADER_FRAME_BUFFERS+1) +#else +#define MAX_BMMU_BUFFER_NUM (((FRAME_BUFFERS*2)+HEADER_FRAME_BUFFERS+1)+1) +#define VF_BUFFER_IDX(n) (n) +#define HEADER_BUFFER_IDX(n) (FRAME_BUFFERS + n+1) +#define MV_BUFFER_IDX(n) ((FRAME_BUFFERS * 2) + n+1) +#define WORK_SPACE_BUF_ID ((FRAME_BUFFERS * 2) + HEADER_FRAME_BUFFERS+1) +#endif + +#define CO_MV_BUF_SIZE_1080P 0x3fc00 +#define CO_MV_BUF_SIZE_4K 0x120000 +#define CO_MV_BUF_SIZE_8K 0x480000 +/* +static void set_canvas(struct AVS2Decoder_s *dec, + struct avs2_frame_s *pic); +int avs2_prepare_display_buf(struct AVS2Decoder_s *dec, + int pos); +*/ + + +struct buff_s { + u32 buf_start; + u32 buf_size; + u32 buf_end; +}; + +struct BuffInfo_s { + u32 max_width; + u32 max_height; + u32 start_adr; + u32 end_adr; + struct buff_s ipp; + struct buff_s sao_abv; + struct buff_s sao_vb; + struct buff_s short_term_rps; + struct buff_s rcs; + struct buff_s sps; + struct buff_s pps; + struct buff_s sao_up; + struct buff_s swap_buf; + struct buff_s swap_buf2; + struct buff_s scalelut; + struct buff_s dblk_para; + struct buff_s dblk_data; + struct buff_s dblk_data2; +#ifdef AVS2_10B_MMU + struct buff_s mmu_vbh; + struct buff_s cm_header; +#endif + struct buff_s mpred_above; +#ifdef MV_USE_FIXED_BUF + struct buff_s mpred_mv; +#endif + struct buff_s rpm; + struct buff_s lmem; +}; + +#define DEC_RESULT_NONE 0 +#define DEC_RESULT_DONE 1 +#define DEC_RESULT_AGAIN 2 +#define DEC_RESULT_CONFIG_PARAM 3 +#define DEC_RESULT_ERROR 4 +#define DEC_INIT_PICLIST 5 +#define DEC_UNINIT_PICLIST 6 +#define DEC_RESULT_GET_DATA 7 +#define DEC_RESULT_GET_DATA_RETRY 8 +#define DEC_RESULT_EOS 9 +#define DEC_RESULT_FORCE_EXIT 10 + +static void avs2_work(struct work_struct *work); +struct loop_filter_info_n; +struct loopfilter; +struct segmentation; + +struct AVS2Decoder_s { + int pic_list_init_flag; + unsigned char index; + spinlock_t buffer_lock; + struct device *cma_dev; + struct platform_device *platform_dev; + void (*vdec_cb)(struct vdec_s *, void *); + void *vdec_cb_arg; + struct vframe_chunk_s *chunk; + int dec_result; + struct work_struct work; + u32 start_shift_bytes; + + struct BuffInfo_s work_space_buf_store; + unsigned long buf_start; + u32 buf_size; + u32 cma_alloc_count; + unsigned long cma_alloc_addr; + uint8_t eos; + unsigned long int start_process_time; + unsigned last_lcu_idx; + int decode_timeout_count; + unsigned timeout_num; + + int double_write_mode; + + unsigned char m_ins_flag; + char *provider_name; + int frame_count; + u32 stat; + struct timer_list timer; + u32 frame_dur; + u32 frame_ar; + int fatal_error; + uint8_t init_flag; + uint8_t first_sc_checked; + uint8_t process_busy; +#define PROC_STATE_INIT 0 +#define PROC_STATE_HEAD_DONE 1 +#define PROC_STATE_DECODING 2 +#define PROC_STATE_HEAD_AGAIN 3 +#define PROC_STATE_DECODE_AGAIN 4 +#define PROC_STATE_TEST1 5 + uint8_t process_state; + u32 ucode_pause_pos; + + int show_frame_num; +#ifndef AVS2_10B_MMU + struct buff_s mc_buf_spec; +#endif + struct dec_sysinfo vavs2_amstream_dec_info; + void *rpm_addr; + void *lmem_addr; + dma_addr_t rpm_phy_addr; + dma_addr_t lmem_phy_addr; + unsigned short *lmem_ptr; + unsigned short *debug_ptr; + + u32 cuva_size; + void *cuva_addr; + dma_addr_t cuva_phy_addr; + +#if 1 + /*AVS2_10B_MMU*/ + void *frame_mmu_map_addr; + dma_addr_t frame_mmu_map_phy_addr; +#endif + unsigned int use_cma_flag; + + struct BUF_s m_BUF[MAX_BUF_NUM]; + struct MVBUF_s m_mv_BUF[MAX_BUF_NUM]; + u32 used_buf_num; + DECLARE_KFIFO(newframe_q, struct vframe_s *, VF_POOL_SIZE); + DECLARE_KFIFO(display_q, struct vframe_s *, VF_POOL_SIZE); + DECLARE_KFIFO(pending_q, struct vframe_s *, VF_POOL_SIZE); + struct vframe_s vfpool[VF_POOL_SIZE]; + atomic_t vf_pre_count; + atomic_t vf_get_count; + atomic_t vf_put_count; + int buf_num; + unsigned int losless_comp_body_size; + + u32 video_signal_type; + u32 video_ori_signal_type; + + int pts_mode; + int last_lookup_pts; + int last_pts; + u64 last_lookup_pts_us64; + u64 last_pts_us64; + u64 shift_byte_count; + u32 shift_byte_count_lo; + u32 shift_byte_count_hi; + int pts_mode_switching_count; + int pts_mode_recovery_count; + + bool get_frame_dur; + u32 saved_resolution; + + /**/ + int refresh_frame_flags; + uint8_t hold_ref_buf; + struct BuffInfo_s *work_space_buf; +#ifndef AVS2_10B_MMU + struct buff_s *mc_buf; +#endif + unsigned int frame_width; + unsigned int frame_height; + + unsigned short *rpm_ptr; + int init_pic_w; + int init_pic_h; + + int slice_type; + + int decode_idx; + int slice_idx; + uint8_t wait_buf; + uint8_t error_flag; + unsigned int bufmgr_error_count; + + /* bit 0, for decoding; bit 1, for displaying */ + uint8_t ignore_bufmgr_error; + uint8_t skip_PB_before_I; + int PB_skip_mode; + int PB_skip_count_after_decoding; + /*hw*/ + + /**/ + struct vdec_info *gvs; + + + unsigned int dec_status; + u32 last_put_idx; + int new_frame_displayed; + void *mmu_box; + void *bmmu_box; + struct vframe_master_display_colour_s vf_dp; + struct firmware_s *fw; +#ifdef AVS2_10B_MMU + int cur_fb_idx_mmu; + long used_4k_num; +#endif + struct avs2_decoder avs2_dec; +#define ALF_NUM_BIT_SHIFT 6 +#define NO_VAR_BINS 16 + int32_t m_filterCoeffSym[16][9]; + int32_t m_varIndTab[NO_VAR_BINS]; + + struct vframe_s vframe_dummy; + /* start_decoding_flag, + bit 0, SEQ ready + bit 1, I ready + */ + unsigned char start_decoding_flag; + uint32_t mpred_abv_start_addr; + uint32_t mpred_abv_start_addr_bak; + u8 next_again_flag; + u32 pre_parser_wr_ptr; + int need_cache_size; + u64 sc_start_time; +#ifdef I_ONLY_SUPPORT + u32 i_only; +#endif + int frameinfo_enable; + struct vframe_qos_s vframe_qos; + u32 dynamic_buf_margin; + int sidebind_type; + int sidebind_channel_id; + u32 endian; + char vdec_name[32]; + char pts_name[32]; + char new_q_name[32]; + char disp_q_name[32]; + dma_addr_t rdma_phy_adr; + unsigned *rdma_adr; + int hdr_flag; +}; + +static int compute_losless_comp_body_size( + struct AVS2Decoder_s *dec, int width, int height, + uint8_t is_bit_depth_10); + +static int avs2_print(struct AVS2Decoder_s *dec, + int flag, const char *fmt, ...) +{ +#define HEVC_PRINT_BUF 256 + unsigned char buf[HEVC_PRINT_BUF]; + int len = 0; + if (dec == NULL || + (flag == 0) || + (debug & flag)) { + va_list args; + va_start(args, fmt); + if (dec) + len = sprintf(buf, "[%d]", dec->index); + vsnprintf(buf + len, HEVC_PRINT_BUF - len, fmt, args); + pr_info("%s", buf); + va_end(args); + } + return 0; +} + +static int avs2_print_cont(struct AVS2Decoder_s *dec, + int flag, const char *fmt, ...) +{ + unsigned char buf[HEVC_PRINT_BUF]; + int len = 0; + if (dec == NULL || + (flag == 0) || + (debug & flag)) { + va_list args; + va_start(args, fmt); + vsnprintf(buf + len, HEVC_PRINT_BUF - len, fmt, args); + pr_info("%s", buf); + va_end(args); + } + return 0; +} + +#define PROB_SIZE (496 * 2 * 4) +#define PROB_BUF_SIZE (0x5000) +#define COUNT_BUF_SIZE (0x300 * 4 * 4) +/*compute_losless_comp_body_size(4096, 2304, 1) = 18874368(0x1200000)*/ +#define MAX_FRAME_4K_NUM 0x1200 +#define MAX_FRAME_8K_NUM 0x4800 +#define MAX_SIZE_4K (4096 * 2304) +#define IS_8K_SIZE(w, h) (((w) * (h)) > MAX_SIZE_4K) +#define IS_4K_SIZE(w, h) (((w) * (h)) > (1920*1088)) + +static int get_frame_mmu_map_size(struct AVS2Decoder_s *dec) +{ + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && + (IS_8K_SIZE(dec->init_pic_w, dec->init_pic_h))) + return (MAX_FRAME_8K_NUM * 4); + return (MAX_FRAME_4K_NUM * 4); +} + +static int get_compress_header_size(struct AVS2Decoder_s *dec) +{ + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && + (IS_8K_SIZE(dec->init_pic_w, dec->init_pic_h))) + return MMU_COMPRESS_HEADER_SIZE_8K; + else if (IS_4K_SIZE(dec->init_pic_w, dec->init_pic_h)) + return MMU_COMPRESS_HEADER_SIZE_4K; + return MMU_COMPRESS_HEADER_SIZE_1080P; +} + +static void reset_process_time(struct AVS2Decoder_s *dec) +{ + if (dec->start_process_time) { + unsigned process_time = + 1000 * (jiffies - dec->start_process_time) / HZ; + dec->start_process_time = 0; + if (process_time > max_process_time[dec->index]) + max_process_time[dec->index] = process_time; + } +} + +static void start_process_time(struct AVS2Decoder_s *dec) +{ + dec->start_process_time = jiffies; + dec->decode_timeout_count = 0; + dec->last_lcu_idx = 0; +} + +static void update_decoded_pic(struct AVS2Decoder_s *dec); + +static void timeout_process(struct AVS2Decoder_s *dec) +{ + struct avs2_decoder *avs2_dec = &dec->avs2_dec; + struct avs2_frame_s *cur_pic = avs2_dec->hc.cur_pic; + dec->timeout_num++; + amhevc_stop(); + avs2_print(dec, + 0, "%s decoder timeout\n", __func__); + if (cur_pic) + cur_pic->error_mark = 1; + dec->dec_result = DEC_RESULT_DONE; + update_decoded_pic(dec); + reset_process_time(dec); + vdec_schedule_work(&dec->work); +} + +static u32 get_valid_double_write_mode(struct AVS2Decoder_s *dec) +{ + return (dec->m_ins_flag && + ((double_write_mode & 0x80000000) == 0)) ? + dec->double_write_mode : + (double_write_mode & 0x7fffffff); +} + +static int get_double_write_mode(struct AVS2Decoder_s *dec) +{ + u32 valid_dw_mode = get_valid_double_write_mode(dec); + int w = dec->avs2_dec.img.width; + int h = dec->avs2_dec.img.height; + u32 dw = 0x1; /*1:1*/ + switch (valid_dw_mode) { + case 0x100: + if (w > 1920 && h > 1088) + dw = 0x4; /*1:2*/ + break; + case 0x200: + if (w > 1920 && h > 1088) + dw = 0x2; /*1:4*/ + break; + case 0x300: + if (w > 1280 && h > 720) + dw = 0x4; /*1:2*/ + break; + default: + dw = valid_dw_mode; + break; + } + return dw; +} + +/* for double write buf alloc */ +static int get_double_write_mode_init(struct AVS2Decoder_s *dec) +{ + u32 valid_dw_mode = get_valid_double_write_mode(dec); + u32 dw; + int w = dec->init_pic_w; + int h = dec->init_pic_h; + + dw = 0x1; /*1:1*/ + switch (valid_dw_mode) { + case 0x100: + if (w > 1920 && h > 1088) + dw = 0x4; /*1:2*/ + break; + case 0x200: + if (w > 1920 && h > 1088) + dw = 0x2; /*1:4*/ + break; + case 0x300: + if (w > 1280 && h > 720) + dw = 0x4; /*1:2*/ + break; + default: + dw = valid_dw_mode; + break; + } + return dw; +} + +//#define MAX_4K_NUM 0x1200 +#ifdef AVS2_10B_MMU +int avs2_alloc_mmu( + struct AVS2Decoder_s *dec, + int cur_buf_idx, + int pic_width, + int pic_height, + unsigned short bit_depth, + unsigned int *mmu_index_adr) +{ + int bit_depth_10 = (bit_depth == AVS2_BITS_10); + int picture_size; + int cur_mmu_4k_number, max_frame_num; +#ifdef DYNAMIC_ALLOC_HEAD + unsigned long buf_addr; + struct avs2_frame_s *pic = dec->avs2_dec.hc.cur_pic; + if (pic->header_adr == 0) { + if (decoder_bmmu_box_alloc_buf_phy + (dec->bmmu_box, + HEADER_BUFFER_IDX(cur_buf_idx), + get_compress_header_size(dec), + DRIVER_HEADER_NAME, + &buf_addr) < 0){ + avs2_print(dec, 0, + "%s malloc compress header failed %d\n", + DRIVER_HEADER_NAME, cur_buf_idx); + dec->fatal_error |= DECODER_FATAL_ERROR_NO_MEM; + return -1; + } else + pic->header_adr = buf_addr; + } +#endif + + picture_size = compute_losless_comp_body_size( + dec, pic_width, pic_height, + bit_depth_10); + cur_mmu_4k_number = ((picture_size + (1 << 12) - 1) >> 12); + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) + max_frame_num = MAX_FRAME_8K_NUM; + else + max_frame_num = MAX_FRAME_4K_NUM; + if (cur_mmu_4k_number > max_frame_num) { + pr_err("over max !! cur_mmu_4k_number 0x%x width %d height %d\n", + cur_mmu_4k_number, pic_width, pic_height); + return -1; + } + return decoder_mmu_box_alloc_idx( + dec->mmu_box, + cur_buf_idx, + cur_mmu_4k_number, + mmu_index_adr); +} +#endif + +#if 0 +/*ndef MV_USE_FIXED_BUF*/ +static void dealloc_mv_bufs(struct AVS2Decoder_s *dec) +{ + int i; + for (i = 0; i < FRAME_BUFFERS; i++) { + if (dec->m_mv_BUF[i].start_adr) { + if (debug) + pr_info( + "dealloc mv buf(%d) adr %ld size 0x%x used_flag %d\n", + i, dec->m_mv_BUF[i].start_adr, + dec->m_mv_BUF[i].size, + dec->m_mv_BUF[i].used_flag); + decoder_bmmu_box_free_idx( + dec->bmmu_box, + MV_BUFFER_IDX(i)); + dec->m_mv_BUF[i].start_adr = 0; + dec->m_mv_BUF[i].size = 0; + dec->m_mv_BUF[i].used_flag = 0; + } + } +} + +static int alloc_mv_buf(struct AVS2Decoder_s *dec, + int i, int size) +{ + int ret = 0; + if (decoder_bmmu_box_alloc_buf_phy + (dec->bmmu_box, + MV_BUFFER_IDX(i), size, + DRIVER_NAME, + &dec->m_mv_BUF[i].start_adr) < 0) { + dec->m_mv_BUF[i].start_adr = 0; + ret = -1; + } else { + dec->m_mv_BUF[i].size = size; + dec->m_mv_BUF[i].used_flag = 0; + ret = 0; + if (debug) { + pr_info( + "MV Buffer %d: start_adr %p size %x\n", + i, + (void *)dec->m_mv_BUF[i].start_adr, + dec->m_mv_BUF[i].size); + } + } + return ret; +} + +static int init_mv_buf_list(struct AVS2Decoder_s *dec) +{ + int i; + int ret = 0; + int count = FRAME_BUFFERS; + int pic_width = dec->init_pic_w; + int pic_height = dec->init_pic_h; + int lcu_size = 64; /*fixed 64*/ + int pic_width_64 = (pic_width + 63) & (~0x3f); + int pic_height_32 = (pic_height + 31) & (~0x1f); + int pic_width_lcu = (pic_width_64 % lcu_size) ? + pic_width_64 / lcu_size + 1 + : pic_width_64 / lcu_size; + int pic_height_lcu = (pic_height_32 % lcu_size) ? + pic_height_32 / lcu_size + 1 + : pic_height_32 / lcu_size; + int lcu_total = pic_width_lcu * pic_height_lcu; + int size = ((lcu_total * MV_MEM_UNIT) + 0xffff) & + (~0xffff); + if (mv_buf_margin > 0) + count = dec->avs2_dec.ref_maxbuffer + mv_buf_margin; + for (i = 0; i < count; i++) { + if (alloc_mv_buf(dec, i, size) < 0) { + ret = -1; + break; + } + } + return ret; +} +#if 0 + +static int get_mv_buf(struct AVS2Decoder_s *dec, + struct avs2_frame_s *pic) +{ + int i; + int ret = -1; + for (i = 0; i < FRAME_BUFFERS; i++) { + if (dec->m_mv_BUF[i].start_adr && + dec->m_mv_BUF[i].used_flag == 0) { + dec->m_mv_BUF[i].used_flag = 1; + ret = i; + break; + } + } + + if (ret >= 0) { + pic->mv_buf_index = ret; + pic->mpred_mv_wr_start_addr = + (dec->m_mv_BUF[ret].start_adr + 0xffff) & + (~0xffff); + if (debug & AVS2_DBG_BUFMGR_MORE) + pr_info( + "%s => %d (%d) size 0x%x\n", + __func__, ret, + pic->mpred_mv_wr_start_addr, + dec->m_mv_BUF[ret].size); + } else { + pr_info( + "%s: Error, mv buf is not enough\n", + __func__); + } + return ret; +} + +static void put_mv_buf(struct AVS2Decoder_s *dec, + struct avs2_frame_s *pic) +{ + int i = pic->mv_buf_index; + if (i >= FRAME_BUFFERS) { + if (debug & AVS2_DBG_BUFMGR_MORE) + pr_info( + "%s: index %d beyond range\n", + __func__, i); + return; + } + if (debug & AVS2_DBG_BUFMGR_MORE) + pr_info( + "%s(%d): used_flag(%d)\n", + __func__, i, + dec->m_mv_BUF[i].used_flag); + + pic->mv_buf_index = -1; + if (dec->m_mv_BUF[i].start_adr && + dec->m_mv_BUF[i].used_flag) + dec->m_mv_BUF[i].used_flag = 0; +} + +static void put_un_used_mv_bufs(struct AVS2Decoder_s *dec) +{ + struct VP9_Common_s *const cm = &dec->common; + struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs; + int i; + for (i = 0; i < dec->used_buf_num; ++i) { + if ((frame_bufs[i].ref_count == 0) && + (frame_bufs[i].buf.index != -1) && + (frame_bufs[i].buf.mv_buf_index >= 0) + ) + put_mv_buf(dec, &frame_bufs[i].buf); + } +} +#endif + +#endif + +static int get_free_buf_count(struct AVS2Decoder_s *dec) +{ + struct avs2_decoder *avs2_dec = &dec->avs2_dec; + int i; + int count = 0; + for (i = 0; i < avs2_dec->ref_maxbuffer; i++) { + if ((avs2_dec->fref[i]->imgcoi_ref < -256 +#if 0 + || abs(avs2_dec->fref[i]-> + imgtr_fwRefDistance - img->tr) >= 128 +#endif + ) && avs2_dec->fref[i]->is_output == -1 + && avs2_dec->fref[i]->bg_flag == 0 +#ifndef NO_DISPLAY + && avs2_dec->fref[i]->vf_ref == 0 + && avs2_dec->fref[i]->to_prepare_disp == 0 +#endif + ) { + count++; + } + } + + return count; +} + +#ifdef CONSTRAIN_MAX_BUF_NUM +static int get_vf_ref_only_buf_count(struct AVS2Decoder_s *dec) +{ + struct avs2_decoder *avs2_dec = &dec->avs2_dec; + int i; + int count = 0; + for (i = 0; i < avs2_dec->ref_maxbuffer; i++) { + if ((avs2_dec->fref[i]->imgcoi_ref < -256 +#if 0 + || abs(avs2_dec->fref[i]-> + imgtr_fwRefDistance - img->tr) >= 128 +#endif + ) && avs2_dec->fref[i]->is_output == -1 + && avs2_dec->fref[i]->bg_flag == 0 +#ifndef NO_DISPLAY + && avs2_dec->fref[i]->vf_ref > 0 + && avs2_dec->fref[i]->to_prepare_disp == 0 +#endif + ) { + count++; + } + } + + return count; +} + +static int get_used_buf_count(struct AVS2Decoder_s *dec) +{ + struct avs2_decoder *avs2_dec = &dec->avs2_dec; + int i; + int count = 0; + for (i = 0; i < avs2_dec->ref_maxbuffer; i++) { + if ((avs2_dec->fref[i]->imgcoi_ref >= -256 +#if 0 + || abs(avs2_dec->fref[i]-> + imgtr_fwRefDistance - img->tr) >= 128 +#endif + ) || avs2_dec->fref[i]->is_output != -1 + || avs2_dec->fref[i]->bg_flag != 0 +#ifndef NO_DISPLAY + || avs2_dec->fref[i]->vf_ref != 0 + || avs2_dec->fref[i]->to_prepare_disp != 0 +#endif + ) { + count++; + } + } + + return count; +} +#endif + +int avs2_bufmgr_init(struct AVS2Decoder_s *dec, struct BuffInfo_s *buf_spec_i, + struct buff_s *mc_buf_i) { + + dec->frame_count = 0; +#ifdef AVS2_10B_MMU + dec->used_4k_num = -1; + dec->cur_fb_idx_mmu = INVALID_IDX; +#endif + + + /* private init */ + dec->work_space_buf = buf_spec_i; +#ifndef AVS2_10B_MMU + dec->mc_buf = mc_buf_i; +#endif + dec->rpm_addr = NULL; + dec->lmem_addr = NULL; + + dec->use_cma_flag = 0; + dec->decode_idx = 0; + dec->slice_idx = 0; + /*int m_uiMaxCUWidth = 1<<7;*/ + /*int m_uiMaxCUHeight = 1<<7;*/ + dec->wait_buf = 0; + dec->error_flag = 0; + dec->skip_PB_before_I = 0; + + dec->pts_mode = PTS_NORMAL; + dec->last_pts = 0; + dec->last_lookup_pts = 0; + dec->last_pts_us64 = 0; + dec->last_lookup_pts_us64 = 0; + dec->shift_byte_count = 0; + dec->shift_byte_count_lo = 0; + dec->shift_byte_count_hi = 0; + dec->pts_mode_switching_count = 0; + dec->pts_mode_recovery_count = 0; + + dec->buf_num = 0; + + dec->bufmgr_error_count = 0; + return 0; +} + + + +#define HEVC_CM_BODY_START_ADDR 0x3626 +#define HEVC_CM_BODY_LENGTH 0x3627 +#define HEVC_CM_HEADER_LENGTH 0x3629 +#define HEVC_CM_HEADER_OFFSET 0x362b + +#define LOSLESS_COMPRESS_MODE + +/*#define DECOMP_HEADR_SURGENT*/ + +static u32 mem_map_mode; /* 0:linear 1:32x32 2:64x32 ; m8baby test1902 */ +static u32 enable_mem_saving = 1; +static u32 force_w_h; + +static u32 force_fps; + + +const u32 avs2_version = 201602101; +static u32 debug; +static u32 radr; +static u32 rval; +static u32 pop_shorts; +static u32 dbg_cmd; +static u32 dbg_skip_decode_index; +/* + * bit 0~3, for HEVCD_IPP_AXIIF_CONFIG endian config + * bit 8~23, for HEVC_SAO_CTRL1 endian config + */ +static u32 endian; +#define HEVC_CONFIG_BIG_ENDIAN ((0x880 << 8) | 0x8) +#define HEVC_CONFIG_LITTLE_ENDIAN ((0xff0 << 8) | 0xf) + +#ifdef ERROR_HANDLE_DEBUG +static u32 dbg_nal_skip_flag; + /* bit[0], skip vps; bit[1], skip sps; bit[2], skip pps */ +static u32 dbg_nal_skip_count; +#endif +/*for debug*/ +static u32 decode_pic_begin; +static uint slice_parse_begin; +static u32 step; +#ifdef MIX_STREAM_SUPPORT +static u32 buf_alloc_width = 4096; +static u32 buf_alloc_height = 2304; + +static u32 dynamic_buf_num_margin; +#else +static u32 buf_alloc_width; +static u32 buf_alloc_height; +static u32 dynamic_buf_num_margin = 7; +#endif +#ifdef CONSTRAIN_MAX_BUF_NUM +static u32 run_ready_max_vf_only_num; +static u32 run_ready_display_q_num; + /*0: not check + 0xff: avs2_dec.ref_maxbuffer + */ +static u32 run_ready_max_buf_num = 0xff; +#endif +static u32 buf_alloc_depth = 10; +static u32 buf_alloc_size; +/* +bit[0]: 0, + bit[1]: 0, always release cma buffer when stop + bit[1]: 1, never release cma buffer when stop +bit[0]: 1, when stop, release cma buffer if blackout is 1; +do not release cma buffer is blackout is not 1 + +bit[2]: 0, when start decoding, check current displayed buffer + (only for buffer decoded by vp9) if blackout is 0 + 1, do not check current displayed buffer + +bit[3]: 1, if blackout is not 1, do not release current + displayed cma buffer always. +*/ +/* set to 1 for fast play; + set to 8 for other case of "keep last frame" +*/ +static u32 buffer_mode = 1; +/* buffer_mode_dbg: debug only*/ +static u32 buffer_mode_dbg = 0xffff0000; +/**/ + +/* +bit 0, 1: only display I picture; +bit 1, 1: only decode I picture; +*/ +static u32 i_only_flag; + + +static u32 max_decoding_time; +/* +error handling +*/ +/*error_handle_policy: +bit 0: search seq again if buffer mgr error occur + (buffer mgr error count need big than + re_search_seq_threshold) +bit 1: 1, display from I picture; + 0, display from any correct pic +*/ + +static u32 error_handle_policy = 1; +/* +re_search_seq_threshold: + bit 7~0: buffer mgr error research seq count + bit 15~8: frame count threshold +*/ +static u32 re_search_seq_threshold = 0x800; /*0x8;*/ +/*static u32 parser_sei_enable = 1;*/ + +static u32 max_buf_num = (REF_BUFFER + 1); + +static u32 run_ready_min_buf_num = 2; + +static DEFINE_MUTEX(vavs2_mutex); + +#define HEVC_DEC_STATUS_REG HEVC_ASSIST_SCRATCH_0 +#define HEVC_RPM_BUFFER HEVC_ASSIST_SCRATCH_1 +#define AVS2_ALF_SWAP_BUFFER HEVC_ASSIST_SCRATCH_2 +#define HEVC_RCS_BUFFER HEVC_ASSIST_SCRATCH_3 +#define HEVC_SPS_BUFFER HEVC_ASSIST_SCRATCH_4 +#define HEVC_PPS_BUFFER HEVC_ASSIST_SCRATCH_5 +//#define HEVC_SAO_UP HEVC_ASSIST_SCRATCH_6 +#ifdef AVS2_10B_MMU +#define AVS2_MMU_MAP_BUFFER HEVC_ASSIST_SCRATCH_7 +#else +#define HEVC_STREAM_SWAP_BUFFER HEVC_ASSIST_SCRATCH_7 +#endif +#define HEVC_STREAM_SWAP_BUFFER2 HEVC_ASSIST_SCRATCH_8 +/* +#define VP9_PROB_SWAP_BUFFER HEVC_ASSIST_SCRATCH_9 +#define VP9_COUNT_SWAP_BUFFER HEVC_ASSIST_SCRATCH_A +#define VP9_SEG_MAP_BUFFER HEVC_ASSIST_SCRATCH_B +*/ +//#define HEVC_SCALELUT HEVC_ASSIST_SCRATCH_D +#define AVS2_CUVA_ADR HEVC_ASSIST_SCRATCH_A +#define AVS2_CUVA_DATA_SIZE HEVC_ASSIST_SCRATCH_B + +#define HEVC_WAIT_FLAG HEVC_ASSIST_SCRATCH_E +#define RPM_CMD_REG HEVC_ASSIST_SCRATCH_F +#define LMEM_DUMP_ADR HEVC_ASSIST_SCRATCH_9 +#define HEVC_STREAM_SWAP_TEST HEVC_ASSIST_SCRATCH_L +/*!!!*/ +#define HEVC_DECODE_COUNT HEVC_ASSIST_SCRATCH_M +#define HEVC_DECODE_SIZE HEVC_ASSIST_SCRATCH_N +#define DEBUG_REG1 HEVC_ASSIST_SCRATCH_G +#define DEBUG_REG2 HEVC_ASSIST_SCRATCH_H + + +/* +ucode parser/search control +bit 0: 0, header auto parse; 1, header manual parse +bit 1: 0, auto skip for noneseamless stream; 1, no skip +bit [3:2]: valid when bit1==0; +0, auto skip nal before first vps/sps/pps/idr; +1, auto skip nal before first vps/sps/pps +2, auto skip nal before first vps/sps/pps, + and not decode until the first I slice (with slice address of 0) + +3, auto skip before first I slice (nal_type >=16 && nal_type<=21) +bit [15:4] nal skip count (valid when bit0 == 1 (manual mode) ) +bit [16]: for NAL_UNIT_EOS when bit0 is 0: + 0, send SEARCH_DONE to arm ; 1, do not send SEARCH_DONE to arm +bit [17]: for NAL_SEI when bit0 is 0: + 0, do not parse SEI in ucode; 1, parse SEI in ucode +bit [31:20]: used by ucode for debug purpose +*/ +#define NAL_SEARCH_CTL HEVC_ASSIST_SCRATCH_I + /*DECODE_MODE: set before start decoder + bit 7~0: decode mode + bit 23~16: start_decoding_flag + bit [0] - SEQ_ready + bit [2:1] - I Picture Count + bit 31~24: chip feature + */ +#define DECODE_MODE HEVC_ASSIST_SCRATCH_J +#define DECODE_STOP_POS HEVC_ASSIST_SCRATCH_K + /*read only*/ +#define CUR_NAL_UNIT_TYPE HEVC_ASSIST_SCRATCH_J + +#define RPM_BUF_SIZE (0x600 * 2) +#define LMEM_BUF_SIZE (0x600 * 2) + + /*mmu_vbh buf is used by HEVC_SAO_MMU_VH0_ADDR, HEVC_SAO_MMU_VH1_ADDR*/ +#define VBH_BUF_SIZE_1080P 0x3000 +#define VBH_BUF_SIZE_4K 0x5000 +#define VBH_BUF_SIZE_8K 0xa000 +#define VBH_BUF_SIZE(bufspec) (bufspec->mmu_vbh.buf_size / 2) + /*mmu_vbh_dw buf is used by HEVC_SAO_MMU_VH0_ADDR2,HEVC_SAO_MMU_VH1_ADDR2, + HEVC_DW_VH0_ADDDR, HEVC_DW_VH1_ADDDR*/ +#define DW_VBH_BUF_SIZE_1080P (VBH_BUF_SIZE_1080P * 2) +#define DW_VBH_BUF_SIZE_4K (VBH_BUF_SIZE_4K * 2) +#define DW_VBH_BUF_SIZE_8K (VBH_BUF_SIZE_8K * 2) +#define DW_VBH_BUF_SIZE(bufspec) (bufspec->mmu_vbh_dw.buf_size / 4) + +/* necessary 4K page size align for t7/t3 decoder and after */ +#define WORKBUF_ALIGN(addr) (ALIGN(addr, PAGE_SIZE)) + +#define WORK_BUF_SPEC_NUM 6 +static struct BuffInfo_s amvavs2_workbuff_spec[WORK_BUF_SPEC_NUM] = { + { + /* 8M bytes */ + .max_width = 1920, + .max_height = 1088, + .ipp = { + /* IPP work space calculation : + 4096 * (Y+CbCr+Flags) = 12k, round to 16k */ + .buf_size = 0x4000, + }, + .sao_abv = { + .buf_size = 0x30000, + }, + .sao_vb = { + .buf_size = 0x30000, + }, + .short_term_rps = { + /* SHORT_TERM_RPS - Max 64 set, 16 entry every set, + total 64x16x2 = 2048 bytes (0x800) */ + .buf_size = 0x800, + }, + .rcs = { + /* RCS STORE AREA - Max 32 RCS, each has 32 bytes, + total 0x0400 bytes */ + .buf_size = 0x400, + }, + .sps = { + /* SPS STORE AREA - Max 16 SPS, each has 0x80 bytes, + total 0x0800 bytes*/ + .buf_size = 0x800, + }, + .pps = { + /*PPS STORE AREA - Max 64 PPS, each has 0x80 bytes, + total 0x2000 bytes*/ + .buf_size = 0x2000, + }, + .sao_up = { + /* SAO UP STORE AREA - Max 640(10240/16) LCU, + each has 16 bytes total 0x2800 bytes */ + .buf_size = 0x2800, + }, + .swap_buf = { + /* 256cyclex64bit = 2K bytes 0x800 + (only 144 cycles valid) */ + .buf_size = 0x800, + }, + .swap_buf2 = { + .buf_size = 0x800, + }, + .scalelut = { + /* support up to 32 SCALELUT 1024x32 = + 32Kbytes (0x8000) */ + .buf_size = 0x8000, + }, + .dblk_para = { + /* DBLK -> Max 256(4096/16) LCU, + each para 1024bytes(total:0x40000), + data 1024bytes(total:0x40000)*/ + .buf_size = 0x40000, + }, + .dblk_data = { + .buf_size = 0x40000, + }, + .dblk_data2 = { + .buf_size = 0x40000, + }, +#ifdef AVS2_10B_MMU + .mmu_vbh = { + .buf_size = 0x5000, /*2*16*(more than 2304)/4, 4K*/ + }, +#if 0 + .cm_header = { + /*add one for keeper.*/ + .buf_size = MMU_COMPRESS_HEADER_SIZE * + (FRAME_BUFFERS + 1), + /* 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) */ + }, +#endif +#endif + .mpred_above = { + .buf_size = 0x8000, /* 2 * size of hevc*/ + }, +#ifdef MV_USE_FIXED_BUF + .mpred_mv = {/* 1080p, 0x40000 per buffer */ + .buf_size = 0x40000 * FRAME_BUFFERS, + }, +#endif + .rpm = { + .buf_size = RPM_BUF_SIZE, + }, + .lmem = { + .buf_size = 0x400 * 2, + } + }, + { + .max_width = 4096, + .max_height = 2304, + .ipp = { + /* IPP work space calculation : + 4096 * (Y+CbCr+Flags) = 12k, round to 16k */ + .buf_size = 0x4000, + }, + .sao_abv = { + .buf_size = 0x30000, + }, + .sao_vb = { + .buf_size = 0x30000, + }, + .short_term_rps = { + /* SHORT_TERM_RPS - Max 64 set, 16 entry every set, + total 64x16x2 = 2048 bytes (0x800) */ + .buf_size = 0x800, + }, + .rcs = { + /* RCS STORE AREA - Max 16 RCS, each has 32 bytes, + total 0x0400 bytes */ + .buf_size = 0x400, + }, + .sps = { + /* SPS STORE AREA - Max 16 SPS, each has 0x80 bytes, + total 0x0800 bytes */ + .buf_size = 0x800, + }, + .pps = { + /* PPS STORE AREA - Max 64 PPS, each has 0x80 bytes, + total 0x2000 bytes */ + .buf_size = 0x2000, + }, + .sao_up = { + /* SAO UP STORE AREA - Max 640(10240/16) LCU, + each has 16 bytes total 0x2800 bytes */ + .buf_size = 0x2800, + }, + .swap_buf = { + /* 256cyclex64bit = 2K bytes 0x800 + (only 144 cycles valid) */ + .buf_size = 0x800, + }, + .swap_buf2 = { + .buf_size = 0x800, + }, + .scalelut = { + /* support up to 32 SCALELUT 1024x32 = 32Kbytes + (0x8000) */ + .buf_size = 0x8000, + }, + .dblk_para = { + /* DBLK -> Max 256(4096/16) LCU, + each para 1024bytes(total:0x40000), + data 1024bytes(total:0x40000)*/ + .buf_size = 0x80000, + }, + .dblk_data = { + /*DBLK -> Max 256(4096/16) LCU, + each para 1024bytes(total:0x40000), + data 1024bytes(total:0x40000)*/ + .buf_size = 0x80000, + }, + .dblk_data2 = { + .buf_size = 0x80000, + }, +#ifdef AVS2_10B_MMU + .mmu_vbh = { + .buf_size = 0x5000,/*2*16*(more than 2304)/4, 4K*/ + }, +#if 0 + .cm_header = { + /*add one for keeper.*/ + .buf_size = MMU_COMPRESS_HEADER_SIZE * + (FRAME_BUFFERS + 1), + /* 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) */ + }, +#endif +#endif + .mpred_above = { + .buf_size = 0x10000, /* 2 * size of hevc*/ + }, +#ifdef MV_USE_FIXED_BUF + .mpred_mv = { + /* .buf_size = 0x100000*16, + //4k2k , 0x100000 per buffer */ + /* 4096x2304 , 0x120000 per buffer */ + .buf_size = 0x120000 * FRAME_BUFFERS, + }, +#endif + .rpm = { + .buf_size = RPM_BUF_SIZE, + }, + .lmem = { + .buf_size = 0x400 * 2, + } + }, + { + .max_width = 4096 * 2, + .max_height = 2304 * 2, + .ipp = { + /*IPP work space calculation : 4096 * (Y+CbCr+Flags) = 12k, + round to 16k*/ + .buf_size = 0x4000 * 2, + }, + .sao_abv = { + .buf_size = 0x30000 * 2, + }, + .sao_vb = { + .buf_size = 0x30000 * 2, + }, + .short_term_rps = { + /*SHORT_TERM_RPS - Max 64 set, 16 entry every set, + total 64x16x2 = 2048 bytes (0x800)*/ + .buf_size = 0x800, + }, + .rcs = { + /*RCS STORE AREA - Max 16 RCS, each has 32 bytes, + total 0x0400 bytes*/ + .buf_size = 0x400, + }, + .sps = { + /*SPS STORE AREA - Max 16 SPS, each has 0x80 bytes, + total 0x0800 bytes*/ + .buf_size = 0x800, + }, + .pps = { + /*PPS STORE AREA - Max 64 PPS, each has 0x80 bytes, total + 0x2000 bytes*/ + .buf_size = 0x2000, + }, + .sao_up = { + /*SAO UP STORE AREA - Max 640(10240/16) LCU, each has 16 bytes i + total 0x2800 bytes*/ + .buf_size = 0x2800 * 2, + }, + .swap_buf = { + /*256cyclex64bit = 2K bytes 0x800 (only 144 cycles valid)*/ + .buf_size = 0x800, + }, + .swap_buf2 = { + .buf_size = 0x800, + }, + .scalelut = { + /*support up to 32 SCALELUT 1024x32 = 32Kbytes (0x8000)*/ + .buf_size = 0x8000 * 2, + }, + .dblk_para = { + .buf_size = 0x40000 * 2, + }, + .dblk_data = { + .buf_size = 0x80000 * 2, + }, + .dblk_data2 = { + .buf_size = 0x80000 * 2, + }, +#ifdef AVS2_10B_MMU + .mmu_vbh = { + .buf_size = 0x5000 * 2, /*2*16*2304/4, 4K*/ + }, +#if 0 + .cm_header = { + /*0x44000 = ((1088*2*1024*4)/32/4)*(32/8)*/ + .buf_size = MMU_COMPRESS_8K_HEADER_SIZE * 17, + }, +#endif +#endif + .mpred_above = { + .buf_size = 0x8000 * 2, + }, +#ifdef MV_USE_FIXED_BUF + .mpred_mv = { + /*4k2k , 0x100000 per buffer*/ + .buf_size = 0x120000 * FRAME_BUFFERS * 4, + }, +#endif + .rpm = { + .buf_size = RPM_BUF_SIZE, + }, + .lmem = { + .buf_size = 0x400 * 2, + } + }, + { + /* 8M bytes */ + .max_width = 1920, + .max_height = 1088, + .ipp = { + /* IPP work space calculation : + 4096 * (Y+CbCr+Flags) = 12k, round to 16k */ + .buf_size = 0x1e00, + }, + .sao_abv = { + .buf_size = 0, + }, + .sao_vb = { + .buf_size = 0, + }, + .short_term_rps = { + /* SHORT_TERM_RPS - Max 64 set, 16 entry every set, + total 64x16x2 = 2048 bytes (0x800) */ + .buf_size = 0x800, + }, + .rcs = { + /* RCS STORE AREA - Max 32 RCS, each has 32 bytes, + total 0x0400 bytes */ + .buf_size = 0x400, + }, + .sps = { + /* SPS STORE AREA - Max 16 SPS, each has 0x80 bytes, + total 0x0800 bytes*/ + .buf_size = 0x800, + }, + .pps = { + /*PPS STORE AREA - Max 64 PPS, each has 0x80 bytes, + total 0x2000 bytes*/ + .buf_size = 0x2000, + }, + .sao_up = { + /* SAO UP STORE AREA - Max 640(10240/16) LCU, + each has 16 bytes total 0x2800 bytes */ + .buf_size = 0x2800, + }, + .swap_buf = { + /* 256cyclex64bit = 2K bytes 0x800 + (only 144 cycles valid) */ + .buf_size = 0x800, + }, + .swap_buf2 = { + .buf_size = 0x800, + }, + .scalelut = { + /* support up to 32 SCALELUT 1024x32 = + 32Kbytes (0x8000) */ + .buf_size = 0, + }, + .dblk_para = { + /* DBLK -> Max 256(4096/16) LCU, + each para 1024bytes(total:0x40000), + data 1024bytes(total:0x40000)*/ + .buf_size = 0x3d00, //0x3c80, + }, + .dblk_data = { + .buf_size = 0x62800, + }, + .dblk_data2 = { + .buf_size = 0x62800, + }, +#ifdef AVS2_10B_MMU + .mmu_vbh = { + .buf_size = VBH_BUF_SIZE_1080P, /*2*16*(more than 2304)/4, 4K*/ + }, +#if 0 + .cm_header = { + /*add one for keeper.*/ + .buf_size = MMU_COMPRESS_HEADER_SIZE * + (FRAME_BUFFERS + 1), + /* 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) */ + }, +#endif +#endif + .mpred_above = { + .buf_size = 0x1e00, /* 2 * size of hevc*/ + }, +#ifdef MV_USE_FIXED_BUF + .mpred_mv = {/* 1080p, 0x40000 per buffer */ + .buf_size = CO_MV_BUF_SIZE_1080P * FRAME_BUFFERS, + }, +#endif + .rpm = { + .buf_size = RPM_BUF_SIZE, + }, + .lmem = { + .buf_size = 0x400 * 2, + } + }, + { + .max_width = 4096, + .max_height = 2304, + .ipp = { + /* IPP work space calculation : + 4096 * (Y+CbCr+Flags) = 12k, round to 16k */ + .buf_size = 0x4000, + }, + .sao_abv = { + .buf_size = 0, + }, + .sao_vb = { + .buf_size = 0, + }, + .short_term_rps = { + /* SHORT_TERM_RPS - Max 64 set, 16 entry every set, + total 64x16x2 = 2048 bytes (0x800) */ + .buf_size = 0x800, + }, + .rcs = { + /* RCS STORE AREA - Max 16 RCS, each has 32 bytes, + total 0x0400 bytes */ + .buf_size = 0x400, + }, + .sps = { + /* SPS STORE AREA - Max 16 SPS, each has 0x80 bytes, + total 0x0800 bytes */ + .buf_size = 0x800, + }, + .pps = { + /* PPS STORE AREA - Max 64 PPS, each has 0x80 bytes, + total 0x2000 bytes */ + .buf_size = 0x2000, + }, + .sao_up = { + /* SAO UP STORE AREA - Max 640(10240/16) LCU, + each has 16 bytes total 0x2800 bytes */ + .buf_size = 0, + }, + .swap_buf = { + /* 256cyclex64bit = 2K bytes 0x800 + (only 144 cycles valid) */ + .buf_size = 0x800, + }, + .swap_buf2 = { + .buf_size = 0x800, + }, + .scalelut = { + /* support up to 32 SCALELUT 1024x32 = 32Kbytes + (0x8000) */ + .buf_size = 0, + }, + .dblk_para = { + /* DBLK -> Max 256(4096/16) LCU, + each para 1024bytes(total:0x40000), + data 1024bytes(total:0x40000)*/ + .buf_size = 0x8100, //0x8080, + }, + .dblk_data = { + /*DBLK -> Max 256(4096/16) LCU, + each para 1024bytes(total:0x40000), + data 1024bytes(total:0x40000)*/ + .buf_size = 0x88800, + }, + .dblk_data2 = { + .buf_size = 0x88800, + }, +#ifdef AVS2_10B_MMU + .mmu_vbh = { + .buf_size = VBH_BUF_SIZE_4K,/*2*16*(more than 2304)/4, 4K*/ + }, +#if 0 + .cm_header = { + /*add one for keeper.*/ + .buf_size = MMU_COMPRESS_HEADER_SIZE * + (FRAME_BUFFERS + 1), + /* 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) */ + }, +#endif +#endif + .mpred_above = { + .buf_size = 0x4000, /* 2 * size of hevc*/ + }, +#ifdef MV_USE_FIXED_BUF + .mpred_mv = { + /* .buf_size = 0x100000*16, + //4k2k , 0x100000 per buffer */ + /* 4096x2304 , 0x120000 per buffer */ + .buf_size = CO_MV_BUF_SIZE_4K * FRAME_BUFFERS, + }, +#endif + .rpm = { + .buf_size = RPM_BUF_SIZE, + }, + .lmem = { + .buf_size = 0x400 * 2, + } + }, + { + .max_width = 4096 * 2, + .max_height = 2304 * 2, + .ipp = { + /*IPP work space calculation : 4096 * (Y+CbCr+Flags) = 12k, + round to 16k*/ + .buf_size = 0x4000 * 2, + }, + .sao_abv = { + .buf_size = 0, + }, + .sao_vb = { + .buf_size = 0, + }, + .short_term_rps = { + /*SHORT_TERM_RPS - Max 64 set, 16 entry every set, + total 64x16x2 = 2048 bytes (0x800)*/ + .buf_size = 0x800, + }, + .rcs = { + /*RCS STORE AREA - Max 16 RCS, each has 32 bytes, + total 0x0400 bytes*/ + .buf_size = 0x400, + }, + .sps = { + /*SPS STORE AREA - Max 16 SPS, each has 0x80 bytes, + total 0x0800 bytes*/ + .buf_size = 0x800, + }, + .pps = { + /*PPS STORE AREA - Max 64 PPS, each has 0x80 bytes, total + 0x2000 bytes*/ + .buf_size = 0x2000, + }, + .sao_up = { + /*SAO UP STORE AREA - Max 640(10240/16) LCU, each has 16 bytes i + total 0x2800 bytes*/ + .buf_size = 0, + }, + .swap_buf = { + /*256cyclex64bit = 2K bytes 0x800 (only 144 cycles valid)*/ + .buf_size = 0x800, + }, + .swap_buf2 = { + .buf_size = 0x800, + }, + .scalelut = { + /*support up to 32 SCALELUT 1024x32 = 32Kbytes (0x8000)*/ + .buf_size = 0, + }, + .dblk_para = { + .buf_size = 0x10100, //0x10080, + }, + .dblk_data = { + .buf_size = 0x110800, + }, + .dblk_data2 = { + .buf_size = 0x110800, + }, +#ifdef AVS2_10B_MMU + .mmu_vbh = { + .buf_size = VBH_BUF_SIZE_8K, /*2*16*2304/4, 4K*/ + }, +#if 0 + .cm_header = { + /*0x44000 = ((1088*2*1024*4)/32/4)*(32/8)*/ + .buf_size = MMU_COMPRESS_8K_HEADER_SIZE * 17, + }, +#endif +#endif + .mpred_above = { + .buf_size = 0x8000, + }, +#ifdef MV_USE_FIXED_BUF + .mpred_mv = { + /*4k2k , 0x100000 per buffer*/ + .buf_size = CO_MV_BUF_SIZE_8K * FRAME_BUFFERS, + }, +#endif + .rpm = { + .buf_size = RPM_BUF_SIZE, + }, + .lmem = { + .buf_size = 0x400 * 2, + } + } +}; + +#define IS_8K_SIZE(w, h) (((w) * (h)) > MAX_SIZE_4K) +#define IS_4K_SIZE(w, h) (((w) * (h)) > (1920*1088)) +#ifndef MV_USE_FIXED_BUF +static uint32_t get_mv_buf_size(struct AVS2Decoder_s *dec, int width, int height) { + struct avs2_decoder *avs2_dec = &dec->avs2_dec; + uint32_t size; + if (mv_buf_dynamic_alloc == 1) { + int mv_mem_unit = + avs2_dec->lcu_size_log2 == 6 ? 0x200 : avs2_dec->lcu_size_log2 == + 5 ? 0x80 : 0x20; + int extended_pic_width = (width + avs2_dec->lcu_size -1) + & (~(avs2_dec->lcu_size - 1)); + int extended_pic_height = (height + avs2_dec->lcu_size -1) + & (~(avs2_dec->lcu_size - 1)); + int lcu_x_num = extended_pic_width / avs2_dec->lcu_size; + int lcu_y_num = extended_pic_height / avs2_dec->lcu_size; + int new_size = lcu_x_num * lcu_y_num * mv_mem_unit; + size = (new_size + 0xffff) & (~0xffff); + + } else { + if (IS_8K_SIZE(width, height)) + size = CO_MV_BUF_SIZE_8K; + else if (IS_4K_SIZE(width, height)) + size = CO_MV_BUF_SIZE_4K; + else + size = CO_MV_BUF_SIZE_1080P; + } + return size; +} +#endif + +/*Losless compression body buffer size 4K per 64x32 (jt)*/ +static int compute_losless_comp_body_size(struct AVS2Decoder_s *dec, + int width, int height, + uint8_t is_bit_depth_10) +{ + int width_x64; + int height_x32; + int bsize; + width_x64 = width + 63; + width_x64 >>= 6; + height_x32 = height + 31; + height_x32 >>= 5; +#ifdef AVS2_10B_MMU + bsize = (is_bit_depth_10 ? 4096 : 3200) + * width_x64 * height_x32; +#else + bsize = (is_bit_depth_10 ? 4096 : 3072) + * width_x64 * height_x32; +#endif + avs2_print(dec, AVS2_DBG_BUFMGR_MORE, + "%s(%d,%d,%d)=>%d\n", + __func__, width, height, + is_bit_depth_10, bsize); + + return bsize; +} + +/* Losless compression header buffer size 32bytes per 128x64 (jt)*/ +static int compute_losless_comp_header_size(struct AVS2Decoder_s *dec, + int width, int height) +{ + int width_x128; + int height_x64; + int hsize; + width_x128 = width + 127; + width_x128 >>= 7; + height_x64 = height + 63; + height_x64 >>= 6; + + hsize = 32 * width_x128 * height_x64; + avs2_print(dec, AVS2_DBG_BUFMGR_MORE, + "%s(%d,%d)=>%d\n", + __func__, width, height, + hsize); + + return hsize; +} + +static void init_buff_spec(struct AVS2Decoder_s *dec, + struct BuffInfo_s *buf_spec) +{ + void *mem_start_virt; + + buf_spec->ipp.buf_start = + WORKBUF_ALIGN(buf_spec->start_adr); + buf_spec->sao_abv.buf_start = + WORKBUF_ALIGN(buf_spec->ipp.buf_start + buf_spec->ipp.buf_size); + buf_spec->sao_vb.buf_start = + WORKBUF_ALIGN(buf_spec->sao_abv.buf_start + buf_spec->sao_abv.buf_size); + buf_spec->short_term_rps.buf_start = + WORKBUF_ALIGN(buf_spec->sao_vb.buf_start + buf_spec->sao_vb.buf_size); + buf_spec->rcs.buf_start = + WORKBUF_ALIGN(buf_spec->short_term_rps.buf_start + buf_spec->short_term_rps.buf_size); + buf_spec->sps.buf_start = + WORKBUF_ALIGN(buf_spec->rcs.buf_start + buf_spec->rcs.buf_size); + buf_spec->pps.buf_start = + WORKBUF_ALIGN(buf_spec->sps.buf_start + buf_spec->sps.buf_size); + buf_spec->sao_up.buf_start = + WORKBUF_ALIGN(buf_spec->pps.buf_start + buf_spec->pps.buf_size); + buf_spec->swap_buf.buf_start = + WORKBUF_ALIGN(buf_spec->sao_up.buf_start + buf_spec->sao_up.buf_size); + buf_spec->swap_buf2.buf_start = + WORKBUF_ALIGN(buf_spec->swap_buf.buf_start + buf_spec->swap_buf.buf_size); + buf_spec->scalelut.buf_start = + WORKBUF_ALIGN(buf_spec->swap_buf2.buf_start + buf_spec->swap_buf2.buf_size); + buf_spec->dblk_para.buf_start = + WORKBUF_ALIGN(buf_spec->scalelut.buf_start + buf_spec->scalelut.buf_size); + buf_spec->dblk_data.buf_start = + WORKBUF_ALIGN(buf_spec->dblk_para.buf_start + buf_spec->dblk_para.buf_size); + buf_spec->dblk_data2.buf_start = + WORKBUF_ALIGN(buf_spec->dblk_data.buf_start + buf_spec->dblk_data.buf_size); +#ifdef AVS2_10B_MMU + buf_spec->mmu_vbh.buf_start = + WORKBUF_ALIGN(buf_spec->dblk_data2.buf_start + buf_spec->dblk_data2.buf_size); + buf_spec->mpred_above.buf_start = + WORKBUF_ALIGN(buf_spec->mmu_vbh.buf_start + buf_spec->mmu_vbh.buf_size); +#else + buf_spec->mpred_above.buf_start = + WORKBUF_ALIGN(buf_spec->dblk_data2.buf_start + buf_spec->dblk_data2.buf_size); +#endif +#ifdef MV_USE_FIXED_BUF + buf_spec->mpred_mv.buf_start = + WORKBUF_ALIGN(buf_spec->mpred_above.buf_start + buf_spec->mpred_above.buf_size); + buf_spec->rpm.buf_start = + WORKBUF_ALIGN(buf_spec->mpred_mv.buf_start + buf_spec->mpred_mv.buf_size); +#else + buf_spec->rpm.buf_start = + WORKBUF_ALIGN(buf_spec->mpred_above.buf_start + buf_spec->mpred_above.buf_size); +#endif + buf_spec->lmem.buf_start = + WORKBUF_ALIGN(buf_spec->rpm.buf_start + buf_spec->rpm.buf_size); + buf_spec->end_adr = + WORKBUF_ALIGN(buf_spec->lmem.buf_start + buf_spec->lmem.buf_size); + + if (dec) { + mem_start_virt = + codec_mm_phys_to_virt(buf_spec->dblk_para.buf_start); + if (mem_start_virt) { + memset(mem_start_virt, 0, buf_spec->dblk_para.buf_size); + codec_mm_dma_flush(mem_start_virt, + buf_spec->dblk_para.buf_size, + DMA_TO_DEVICE); + } else { + /*not virt for tvp playing, + may need clear on ucode.*/ + pr_err("mem_start_virt failed\n"); + } + if (debug) { + pr_info("%s workspace (%x %x) size = %x\n", __func__, + buf_spec->start_adr, buf_spec->end_adr, + buf_spec->end_adr - buf_spec->start_adr); + } + if (debug) { + pr_info("ipp.buf_start :%x\n", + buf_spec->ipp.buf_start); + pr_info("sao_abv.buf_start :%x\n", + buf_spec->sao_abv.buf_start); + pr_info("sao_vb.buf_start :%x\n", + buf_spec->sao_vb.buf_start); + pr_info("short_term_rps.buf_start :%x\n", + buf_spec->short_term_rps.buf_start); + pr_info("rcs.buf_start :%x\n", + buf_spec->rcs.buf_start); + pr_info("sps.buf_start :%x\n", + buf_spec->sps.buf_start); + pr_info("pps.buf_start :%x\n", + buf_spec->pps.buf_start); + pr_info("sao_up.buf_start :%x\n", + buf_spec->sao_up.buf_start); + pr_info("swap_buf.buf_start :%x\n", + buf_spec->swap_buf.buf_start); + pr_info("swap_buf2.buf_start :%x\n", + buf_spec->swap_buf2.buf_start); + pr_info("scalelut.buf_start :%x\n", + buf_spec->scalelut.buf_start); + pr_info("dblk_para.buf_start :%x\n", + buf_spec->dblk_para.buf_start); + pr_info("dblk_data.buf_start :%x\n", + buf_spec->dblk_data.buf_start); + pr_info("dblk_data2.buf_start :%x\n", + buf_spec->dblk_data2.buf_start); + #ifdef AVS2_10B_MMU + pr_info("mmu_vbh.buf_start :%x\n", + buf_spec->mmu_vbh.buf_start); + #endif + pr_info("mpred_above.buf_start :%x\n", + buf_spec->mpred_above.buf_start); +#ifdef MV_USE_FIXED_BUF + pr_info("mpred_mv.buf_start :%x\n", + buf_spec->mpred_mv.buf_start); +#endif + if ((debug & AVS2_DBG_SEND_PARAM_WITH_REG) == 0) { + pr_info("rpm.buf_start :%x\n", + buf_spec->rpm.buf_start); + } + } + } + +} + +static void uninit_mmu_buffers(struct AVS2Decoder_s *dec) +{ +#if 0 +/*ndef MV_USE_FIXED_BUF*/ + dealloc_mv_bufs(dec); +#endif + decoder_mmu_box_free(dec->mmu_box); + dec->mmu_box = NULL; + + if (dec->bmmu_box) + decoder_bmmu_box_free(dec->bmmu_box); + dec->bmmu_box = NULL; +} + +#ifndef AVS2_10B_MMU +static void init_buf_list(struct AVS2Decoder_s *dec) +{ + int i; + int buf_size; + int mc_buffer_end = dec->mc_buf->buf_start + dec->mc_buf->buf_size; + dec->used_buf_num = max_buf_num; + + if (dec->used_buf_num > MAX_BUF_NUM) + dec->used_buf_num = MAX_BUF_NUM; + if (buf_alloc_size > 0) { + buf_size = buf_alloc_size; + avs2_print(dec, AVS2_DBG_BUFMGR, + "[Buffer Management] init_buf_list:\n"); + } else { + int pic_width = dec->init_pic_w; + int pic_height = dec->init_pic_h; + + /*SUPPORT_10BIT*/ + int losless_comp_header_size = compute_losless_comp_header_size + (dec, pic_width, pic_height); + int losless_comp_body_size = compute_losless_comp_body_size + (dec, pic_width, pic_height, buf_alloc_depth == 10); + int mc_buffer_size = losless_comp_header_size + + losless_comp_body_size; + int mc_buffer_size_h = (mc_buffer_size + 0xffff)>>16; + + int dw_mode = get_double_write_mode_init(dec); + + if (dw_mode) { + int pic_width_dw = pic_width / + get_double_write_ratio(dw_mode); + int pic_height_dw = pic_height / + get_double_write_ratio(dw_mode); + int lcu_size = 64; /*fixed 64*/ + int pic_width_64 = (pic_width_dw + 63) & (~0x3f); + int pic_height_32 = (pic_height_dw + 31) & (~0x1f); + int pic_width_lcu = + (pic_width_64 % lcu_size) ? pic_width_64 / lcu_size + + 1 : pic_width_64 / lcu_size; + int pic_height_lcu = + (pic_height_32 % lcu_size) ? pic_height_32 / lcu_size + + 1 : pic_height_32 / lcu_size; + int lcu_total = pic_width_lcu * pic_height_lcu; + int mc_buffer_size_u_v = lcu_total * lcu_size * lcu_size / 2; + int mc_buffer_size_u_v_h = (mc_buffer_size_u_v + 0xffff) >> 16; + /*64k alignment*/ + buf_size = ((mc_buffer_size_u_v_h << 16) * 3); + } else + buf_size = 0; + + if (mc_buffer_size & 0xffff) { /*64k alignment*/ + mc_buffer_size_h += 1; + } + if ((dw_mode & 0x10) == 0) + buf_size += (mc_buffer_size_h << 16); + avs2_print(dec, AVS2_DBG_BUFMGR, + "init_buf_list num %d (width %d height %d):\n", + dec->used_buf_num, pic_width, pic_height); + } + + for (i = 0; i < dec->used_buf_num; i++) { + if (((i + 1) * buf_size) > dec->mc_buf->buf_size) + dec->use_cma_flag = 1; +#ifndef AVS2_10B_MMU + dec->m_BUF[i].alloc_flag = 0; + dec->m_BUF[i].index = i; + + dec->use_cma_flag = 1; + if (dec->use_cma_flag) { + dec->m_BUF[i].cma_page_count = + PAGE_ALIGN(buf_size) / PAGE_SIZE; + if (decoder_bmmu_box_alloc_buf_phy(dec->bmmu_box, + VF_BUFFER_IDX(i), buf_size, DRIVER_NAME, + &dec->m_BUF[i].alloc_addr) < 0) { + dec->m_BUF[i].cma_page_count = 0; + if (i <= 5) { + dec->fatal_error |= + DECODER_FATAL_ERROR_NO_MEM; + } + break; + } + dec->m_BUF[i].start_adr = dec->m_BUF[i].alloc_addr; + } else { + dec->m_BUF[i].cma_page_count = 0; + dec->m_BUF[i].alloc_addr = 0; + dec->m_BUF[i].start_adr = + dec->mc_buf->buf_start + i * buf_size; + } + dec->m_BUF[i].size = buf_size; + dec->m_BUF[i].free_start_adr = dec->m_BUF[i].start_adr; + + if (((dec->m_BUF[i].start_adr + buf_size) > mc_buffer_end) + && (dec->m_BUF[i].alloc_addr == 0)) { + if (debug) { + avs2_print(dec, 0, + "Max mc buffer or mpred_mv buffer is used\n"); + } + break; + } + + avs2_print(dec, AVS2_DBG_BUFMGR, + "Buffer %d: start_adr %p size %x\n", i, + (void *)dec->m_BUF[i].start_adr, + dec->m_BUF[i].size); +#endif + } + dec->buf_num = i; +} +#endif + +static int config_pic(struct AVS2Decoder_s *dec, + struct avs2_frame_s *pic, int32_t lcu_size_log2) +{ + int ret = -1; + int i; + int pic_width = dec->init_pic_w; + int pic_height = dec->init_pic_h; + /*struct avs2_decoder *avs2_dec = &dec->avs2_dec; + int32_t lcu_size_log2 = avs2_dec->lcu_size_log2;*/ + int32_t lcu_size = 1 << lcu_size_log2; + int pic_width_64 = (pic_width + 63) & (~0x3f); + int pic_height_32 = (pic_height + 31) & (~0x1f); + int pic_width_lcu = (pic_width_64 % lcu_size) ? + pic_width_64 / lcu_size + 1 + : pic_width_64 / lcu_size; + int pic_height_lcu = (pic_height_32 % lcu_size) ? + pic_height_32 / lcu_size + 1 + : pic_height_32 / lcu_size; + int lcu_total = pic_width_lcu * pic_height_lcu; +#if 0 + int32_t MV_MEM_UNIT = + (lcu_size_log2 == 6) ? 0x200 : + ((lcu_size_log2 == 5) ? 0x80 : 0x20); +#endif +#ifdef MV_USE_FIXED_BUF + u32 mpred_mv_end = dec->work_space_buf->mpred_mv.buf_start + + dec->work_space_buf->mpred_mv.buf_size; +#endif + u32 y_adr = 0; + int buf_size = 0; + + int losless_comp_header_size = + compute_losless_comp_header_size( + dec, pic_width, pic_height); + int losless_comp_body_size = compute_losless_comp_body_size( + dec, pic_width, + pic_height, buf_alloc_depth == 10); + int mc_buffer_size = losless_comp_header_size + losless_comp_body_size; + int mc_buffer_size_h = (mc_buffer_size + 0xffff) >> 16; + int mc_buffer_size_u_v = 0; + int mc_buffer_size_u_v_h = 0; + int dw_mode = get_double_write_mode_init(dec); + + if (dw_mode) { + int pic_width_dw = pic_width / + get_double_write_ratio(dw_mode); + int pic_height_dw = pic_height / + get_double_write_ratio(dw_mode); + int pic_width_64_dw = (pic_width_dw + 63) & (~0x3f); + int pic_height_32_dw = (pic_height_dw + 31) & (~0x1f); + int pic_width_lcu_dw = (pic_width_64_dw % lcu_size) ? + pic_width_64_dw / lcu_size + 1 + : pic_width_64_dw / lcu_size; + int pic_height_lcu_dw = (pic_height_32_dw % lcu_size) ? + pic_height_32_dw / lcu_size + 1 + : pic_height_32_dw / lcu_size; + int lcu_total_dw = pic_width_lcu_dw * pic_height_lcu_dw; + + mc_buffer_size_u_v = lcu_total_dw * lcu_size * lcu_size / 2; + mc_buffer_size_u_v_h = (mc_buffer_size_u_v + 0xffff) >> 16; + /*64k alignment*/ + buf_size = ((mc_buffer_size_u_v_h << 16) * 3); + buf_size = ((buf_size + 0xffff) >> 16) << 16; + } + if (mc_buffer_size & 0xffff) /*64k alignment*/ + mc_buffer_size_h += 1; +#ifndef AVS2_10B_MMU + if ((dw_mode & 0x10) == 0) + buf_size += (mc_buffer_size_h << 16); +#endif + +#ifdef AVS2_10B_MMU +#ifndef DYNAMIC_ALLOC_HEAD + pic->header_adr = decoder_bmmu_box_get_phy_addr( + dec->bmmu_box, HEADER_BUFFER_IDX(pic->index)); + + avs2_print(dec, AVS2_DBG_BUFMGR_MORE, + "buf_size %d, MMU header_adr %d: %ld\n", + buf_size, pic->index, pic->header_adr); +#endif +#endif + + i = pic->index; +#ifdef MV_USE_FIXED_BUF +#ifdef G12A_BRINGUP_DEBUG + if (1) { +#else + if ((dec->work_space_buf->mpred_mv.buf_start + + (((i + 1) * lcu_total) * MV_MEM_UNIT)) + <= mpred_mv_end + ) { +#endif +#endif +#ifndef AVS2_10B_MMU + if (debug) { + pr_err("start %x .size=%d\n", + dec->mc_buf_spec.buf_start + i * buf_size, + buf_size); + } +#endif +#ifndef AVS2_10B_MMU + for (i = 0; i < dec->buf_num; i++) { + y_adr = ((dec->m_BUF[i].free_start_adr + + 0xffff) >> 16) << 16; + /*64k alignment*/ + if ((y_adr+buf_size) <= (dec->m_BUF[i].start_adr+ + dec->m_BUF[i].size)) { + dec->m_BUF[i].free_start_adr = + y_adr + buf_size; + break; + } + } + if (i < dec->buf_num) +#else + /*if ((dec->mc_buf->buf_start + (i + 1) * buf_size) < + dec->mc_buf->buf_end) + y_adr = dec->mc_buf->buf_start + i * buf_size; + else {*/ + if (buf_size > 0 && pic->cma_alloc_addr == 0) { + ret = decoder_bmmu_box_alloc_buf_phy(dec->bmmu_box, + VF_BUFFER_IDX(i), + buf_size, DRIVER_NAME, + &pic->cma_alloc_addr); + if (ret < 0) { + avs2_print(dec, 0, + "decoder_bmmu_box_alloc_buf_phy idx %d size %d fail\n", + VF_BUFFER_IDX(i), + buf_size + ); + return ret; + } + + if (pic->cma_alloc_addr) + y_adr = pic->cma_alloc_addr; + else { + avs2_print(dec, 0, + "decoder_bmmu_box_alloc_buf_phy idx %d size %d return null\n", + VF_BUFFER_IDX(i), + buf_size + ); + return -1; + } + } +#endif + { + /*ensure get_pic_by_POC() + not get the buffer not decoded*/ + pic->BUF_index = i; + pic->lcu_total = lcu_total; + + pic->comp_body_size = losless_comp_body_size; + pic->buf_size = buf_size; +#ifndef AVS2_10B_MMU + pic->mc_y_adr = y_adr; +#endif + pic->mc_canvas_y = pic->index; + pic->mc_canvas_u_v = pic->index; +#ifndef AVS2_10B_MMU + if (dw_mode & 0x10) { + pic->mc_u_v_adr = y_adr + + ((mc_buffer_size_u_v_h << 16) << 1); + + pic->mc_canvas_y = + (pic->index << 1); + pic->mc_canvas_u_v = + (pic->index << 1) + 1; + + pic->dw_y_adr = y_adr; + pic->dw_u_v_adr = pic->mc_u_v_adr; + } else +#endif + if (dw_mode) { + pic->dw_y_adr = y_adr +#ifndef AVS2_10B_MMU + + (mc_buffer_size_h << 16) +#endif + ; + pic->dw_u_v_adr = pic->dw_y_adr + + ((mc_buffer_size_u_v_h << 16) << 1); +#ifdef AVS2_10B_MMU + pic->mc_y_adr = pic->dw_y_adr; + pic->mc_u_v_adr = pic->dw_u_v_adr; +#endif + } +#ifdef MV_USE_FIXED_BUF +#ifdef G12A_BRINGUP_DEBUG + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) { + pic->mpred_mv_wr_start_addr = + dec->work_space_buf->mpred_mv.buf_start + + (pic->index * 0x120000 * 4); + } else { + pic->mpred_mv_wr_start_addr = + dec->work_space_buf->mpred_mv.buf_start + + (pic->index * 0x120000); + } +#else + pic->mpred_mv_wr_start_addr = + dec->work_space_buf->mpred_mv.buf_start + + ((pic->index * lcu_total) + * MV_MEM_UNIT); +#endif +#endif + if (debug) { + avs2_print(dec, AVS2_DBG_BUFMGR, + "%s index %d BUF_index %d mc_y_adr %x ", + __func__, pic->index, + pic->BUF_index, + pic->mc_y_adr); + avs2_print_cont(dec, AVS2_DBG_BUFMGR, + "comp_body_size %x comp_buf_size %x ", + pic->comp_body_size, + pic->buf_size); + avs2_print_cont(dec, AVS2_DBG_BUFMGR, + "mpred_mv_wr_start_adr %d\n", + pic->mpred_mv_wr_start_addr); + avs2_print_cont(dec, AVS2_DBG_BUFMGR, + "dw_y_adr %d, pic->dw_u_v_adr =%d\n", + pic->dw_y_adr, + pic->dw_u_v_adr); + } + ret = 0; + } +#ifdef MV_USE_FIXED_BUF + } else { + avs2_print(dec, 0, + "mv buffer alloc fail %x > %x\n", + dec->work_space_buf->mpred_mv.buf_start + + (((i + 1) * lcu_total) * MV_MEM_UNIT), + mpred_mv_end); + } +#endif + return ret; +} + +static void init_pic_list(struct AVS2Decoder_s *dec, + int32_t lcu_size_log2) +{ + int i; + struct avs2_decoder *avs2_dec = &dec->avs2_dec; + struct avs2_frame_s *pic; +#ifdef AVS2_10B_MMU + unsigned long buf_addr1; + /*alloc AVS2 compress header first*/ + if (decoder_bmmu_box_alloc_buf_phy + (dec->bmmu_box, + HEADER_BUFFER_IDX(-1), get_compress_header_size(dec), + DRIVER_HEADER_NAME, + &buf_addr1) < 0){ + avs2_print(dec, 0, + "%s malloc compress header failed %d\n", + DRIVER_HEADER_NAME, -1); + dec->fatal_error |= DECODER_FATAL_ERROR_NO_MEM; + return; + } +#ifndef DYNAMIC_ALLOC_HEAD + for (i = 0; i < dec->used_buf_num; i++) { + unsigned long buf_addr; + if (decoder_bmmu_box_alloc_buf_phy + (dec->bmmu_box, + HEADER_BUFFER_IDX(i), get_compress_header_size(dec), + DRIVER_HEADER_NAME, + &buf_addr) < 0){ + avs2_print(dec, 0, + "%s malloc compress header failed %d\n", + DRIVER_HEADER_NAME, i); + dec->fatal_error |= DECODER_FATAL_ERROR_NO_MEM; + return; + } + } +#endif +#endif + dec->frame_height = avs2_dec->img.height; + dec->frame_width = avs2_dec->img.width; + + for (i = 0; i < dec->used_buf_num; i++) { + if (i == (dec->used_buf_num - 1)) + pic = avs2_dec->m_bg; + else + pic = avs2_dec->fref[i]; + pic->index = i; + pic->BUF_index = -1; + pic->mv_buf_index = -1; + if (config_pic(dec, pic, lcu_size_log2) < 0) { + if (debug) + avs2_print(dec, 0, + "Config_pic %d fail\n", + pic->index); + pic->index = -1; + break; + } + pic->pic_w = avs2_dec->img.width; + pic->pic_h = avs2_dec->img.height; + } + for (; i < dec->used_buf_num; i++) { + if (i == (dec->used_buf_num - 1)) + pic = avs2_dec->m_bg; + else + pic = avs2_dec->fref[i]; + pic->index = -1; + pic->BUF_index = -1; + pic->mv_buf_index = -1; + } + avs2_print(dec, AVS2_DBG_BUFMGR, + "%s ok, used_buf_num = %d\n", + __func__, dec->used_buf_num); + dec->pic_list_init_flag = 1; +} + + +static void init_pic_list_hw(struct AVS2Decoder_s *dec) +{ + int i; + struct avs2_decoder *avs2_dec = &dec->avs2_dec; + struct avs2_frame_s *pic; + /*WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0x0);*/ +#if 0 + WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, + (0x1 << 1) | (0x1 << 2)); + +#ifdef DUAL_CORE_64 + WRITE_VREG(HEVC2_HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, + (0x1 << 1) | (0x1 << 2)); +#endif +#endif + for (i = 0; i < dec->used_buf_num; i++) { + if (i == (dec->used_buf_num - 1)) + pic = avs2_dec->m_bg; + else + pic = avs2_dec->fref[i]; + if (pic->index < 0) + break; +#ifdef AVS2_10B_MMU + /*WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, + pic->header_adr + | (pic->mc_canvas_y << 8)|0x1);*/ + WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, + (0x1 << 1) | (pic->index << 8)); + +#ifdef DUAL_CORE_64 + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXLX2) + WRITE_VREG(HEVC2_MPP_ANC2AXI_TBL_CONF_ADDR, + (0x1 << 1) | (pic->index << 8)); + else + WRITE_VREG(HEVC2_HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, + (0x1 << 1) | (pic->index << 8)); +#endif + WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA, pic->header_adr >> 5); +#else + /*WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, + pic->mc_y_adr + | (pic->mc_canvas_y << 8) | 0x1);*/ + WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA, pic->mc_y_adr >> 5); +#endif +#ifndef LOSLESS_COMPRESS_MODE + /*WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, + pic->mc_u_v_adr + | (pic->mc_canvas_u_v << 8)| 0x1);*/ + WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA, pic->mc_u_v_adr >> 5); +#endif +#ifdef DUAL_CORE_64 +#ifdef AVS2_10B_MMU + WRITE_VREG(HEVC2_HEVCD_MPP_ANC2AXI_TBL_DATA, + pic->header_adr >> 5); +#else + WRITE_VREG(HEVC2_HEVCD_MPP_ANC2AXI_TBL_DATA, + pic->mc_y_adr >> 5); +#endif +#ifndef LOSLESS_COMPRESS_MODE + WRITE_VREG(HEVC2_HEVCD_MPP_ANC2AXI_TBL_DATA, + pic->mc_u_v_adr >> 5); +#endif +/*DUAL_CORE_64*/ +#endif + } + WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0x1); +#ifdef DUAL_CORE_64 + WRITE_VREG(HEVC2_HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, + 0x1); +#endif + /*Zero out canvas registers in IPP -- avoid simulation X*/ + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, + (0 << 8) | (0 << 1) | 1); + for (i = 0; i < 32; i++) { + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); +#ifdef DUAL_CORE_64 + WRITE_VREG(HEVC2_HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); +#endif + } +} + + +static void dump_pic_list(struct AVS2Decoder_s *dec) +{ + int ii; + struct avs2_decoder *avs2_dec = &dec->avs2_dec; + for (ii = 0; ii < avs2_dec->ref_maxbuffer; ii++) { + avs2_print(dec, 0, + "fref[%d]: index %d decode_id %d mvbuf %d imgcoi_ref %d imgtr_fwRefDistance %d refered %d, pre %d is_out %d, bg %d, vf_ref %d error %d lcu %d ref_pos(%d,%d,%d,%d,%d,%d,%d)\n", + ii, avs2_dec->fref[ii]->index, + avs2_dec->fref[ii]->decode_idx, + avs2_dec->fref[ii]->mv_buf_index, + avs2_dec->fref[ii]->imgcoi_ref, + avs2_dec->fref[ii]->imgtr_fwRefDistance, + avs2_dec->fref[ii]->refered_by_others, + avs2_dec->fref[ii]->to_prepare_disp, + avs2_dec->fref[ii]->is_output, + avs2_dec->fref[ii]->bg_flag, + avs2_dec->fref[ii]->vf_ref, + avs2_dec->fref[ii]->error_mark, + avs2_dec->fref[ii]->decoded_lcu, + avs2_dec->fref[ii]->ref_poc[0], + avs2_dec->fref[ii]->ref_poc[1], + avs2_dec->fref[ii]->ref_poc[2], + avs2_dec->fref[ii]->ref_poc[3], + avs2_dec->fref[ii]->ref_poc[4], + avs2_dec->fref[ii]->ref_poc[5], + avs2_dec->fref[ii]->ref_poc[6] + ); + } + return; +} + +static int config_mc_buffer(struct AVS2Decoder_s *dec) +{ + int32_t i; + struct avs2_decoder *avs2_dec = &dec->avs2_dec; + struct avs2_frame_s *pic; + struct avs2_frame_s *cur_pic = avs2_dec->hc.cur_pic; + + /*if (avs2_dec->img.type == I_IMG) + return 0; + */ + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "Entered config_mc_buffer....\n"); + if (avs2_dec->f_bg != NULL) { + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "config_mc_buffer for background (canvas_y %d, canvas_u_v %d)\n", + avs2_dec->f_bg->mc_canvas_y, avs2_dec->f_bg->mc_canvas_u_v); + /*WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, + (7 << 8) | (0<<1) | 1); L0:BG */ + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, + (15 << 8) | (0<<1) | 1); /* L0:BG*/ + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, + (avs2_dec->f_bg->mc_canvas_u_v << 16) | + (avs2_dec->f_bg->mc_canvas_u_v << 8) | + avs2_dec->f_bg->mc_canvas_y); + /*WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, + (23 << 8) | (0<<1) | 1); L1:BG*/ + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, + (31 << 8) | (0<<1) | 1); /* L1:BG*/ + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, + (avs2_dec->f_bg->mc_canvas_u_v << 16) | + (avs2_dec->f_bg->mc_canvas_u_v << 8) | + avs2_dec->f_bg->mc_canvas_y); + } + + if (avs2_dec->img.type == I_IMG) + return 0; + + if (avs2_dec->img.type == P_IMG) { + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "config_mc_buffer for P_IMG, img type %d\n", + avs2_dec->img.type); + /*refer to prepare_RefInfo()*/ + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, + (0 << 8) | (0<<1) | 1); + for (i = 0; i < avs2_dec->img.num_of_references; i++) { + pic = avs2_dec->fref[i]; + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, + (pic->mc_canvas_u_v << 16) | + (pic->mc_canvas_u_v << 8) | + pic->mc_canvas_y); + + if (pic->error_mark) + cur_pic->error_mark = 1; + + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "refid %x mc_canvas_u_v %x mc_canvas_y %x error_mark %x\n", + i, pic->mc_canvas_u_v, pic->mc_canvas_y, + pic->error_mark); + } + } else if (avs2_dec->img.type == F_IMG) { + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "config_mc_buffer for F_IMG, img type %d\n", + avs2_dec->img.type); + /*refer to prepare_RefInfo()*/ + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, + (0 << 8) | (0<<1) | 1); + for (i = 0; i < avs2_dec->img.num_of_references; i++) { + pic = avs2_dec->fref[i]; + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, + (pic->mc_canvas_u_v << 16) | + (pic->mc_canvas_u_v << 8) | + pic->mc_canvas_y); + + if (pic->error_mark) + cur_pic->error_mark = 1; + + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "refid %x mc_canvas_u_v %x mc_canvas_y %x error_mark %x\n", + i, pic->mc_canvas_u_v, pic->mc_canvas_y, + pic->error_mark); + } + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, + (16 << 8) | (0<<1) | 1); + for (i = 0; i < avs2_dec->img.num_of_references; i++) { + pic = avs2_dec->fref[i]; + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, + (pic->mc_canvas_u_v << 16) | + (pic->mc_canvas_u_v << 8) | + pic->mc_canvas_y); + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "refid %x mc_canvas_u_v %x mc_canvas_y %x\n", + i, pic->mc_canvas_u_v, pic->mc_canvas_y); + } + } else { + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "config_mc_buffer for B_IMG\n"); + /*refer to prepare_RefInfo()*/ + pic = avs2_dec->fref[1]; + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, + (0 << 8) | (0<<1) | 1); + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, + (pic->mc_canvas_u_v << 16) | + (pic->mc_canvas_u_v << 8) | + pic->mc_canvas_y); + + if (pic->error_mark) + cur_pic->error_mark = 1; + + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "refid %x mc_canvas_u_v %x mc_canvas_y %x error_mark %x\n", + 1, pic->mc_canvas_u_v, pic->mc_canvas_y, + pic->error_mark); + + pic = avs2_dec->fref[0]; + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, + (16 << 8) | (0<<1) | 1); + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, + (pic->mc_canvas_u_v<<16) | + (pic->mc_canvas_u_v<<8) | + pic->mc_canvas_y); + + if (pic->error_mark) + cur_pic->error_mark = 1; + + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "refid %x mc_canvas_u_v %x mc_canvas_y %x error_mark %x\n", + 0, pic->mc_canvas_u_v, pic->mc_canvas_y, + pic->error_mark); + } + return 0; +} +#if 0 +static void mcrcc_get_hitrate(void) +{ + u32 tmp; + u32 raw_mcr_cnt; + u32 hit_mcr_cnt; + u32 byp_mcr_cnt_nchoutwin; + u32 byp_mcr_cnt_nchcanv; + int hitrate; + + if (debug & AVS2_DBG_CACHE) + pr_info("[cache_util.c] Entered mcrcc_get_hitrate...\n"); + WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x0<<1)); + raw_mcr_cnt = READ_VREG(HEVCD_MCRCC_PERFMON_DATA); + WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x1<<1)); + hit_mcr_cnt = READ_VREG(HEVCD_MCRCC_PERFMON_DATA); + WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x2<<1)); + byp_mcr_cnt_nchoutwin = READ_VREG(HEVCD_MCRCC_PERFMON_DATA); + WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x3<<1)); + byp_mcr_cnt_nchcanv = READ_VREG(HEVCD_MCRCC_PERFMON_DATA); + + if (debug & AVS2_DBG_CACHE) { + pr_info("raw_mcr_cnt_total: %d\n",raw_mcr_cnt); + pr_info("hit_mcr_cnt_total: %d\n",hit_mcr_cnt); + pr_info("byp_mcr_cnt_nchoutwin_total: %d\n",byp_mcr_cnt_nchoutwin); + pr_info("byp_mcr_cnt_nchcanv_total: %d\n",byp_mcr_cnt_nchcanv); + } + WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x4<<1)); + tmp = READ_VREG(HEVCD_MCRCC_PERFMON_DATA); + if (debug & AVS2_DBG_CACHE) + pr_info("miss_mcr_0_cnt_total: %d\n", tmp); + + WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x5<<1)); + tmp = READ_VREG(HEVCD_MCRCC_PERFMON_DATA); + if (debug & AVS2_DBG_CACHE) + pr_info("miss_mcr_1_cnt_total: %d\n", tmp); + + WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x6<<1)); + tmp = READ_VREG(HEVCD_MCRCC_PERFMON_DATA); + if (debug & AVS2_DBG_CACHE) + pr_info("hit_mcr_0_cnt_total: %d\n",tmp); + + WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x7<<1)); + tmp= READ_VREG(HEVCD_MCRCC_PERFMON_DATA); + if (debug & AVS2_DBG_CACHE) + pr_info("hit_mcr_1_cnt_total: %d\n",tmp); + + if (raw_mcr_cnt != 0) { + hitrate = (hit_mcr_cnt / raw_mcr_cnt) * 100; + if (debug & AVS2_DBG_CACHE) + pr_info("MCRCC_HIT_RATE : %d\n", hitrate); + hitrate = ((byp_mcr_cnt_nchoutwin + byp_mcr_cnt_nchcanv) + /raw_mcr_cnt) * 100; + if (debug & AVS2_DBG_CACHE) + pr_info("MCRCC_BYP_RATE : %d\n", hitrate); + } else if (debug & AVS2_DBG_CACHE) { + pr_info("MCRCC_HIT_RATE : na\n"); + pr_info("MCRCC_BYP_RATE : na\n"); + } + return; +} + + +static void decomp_get_hitrate(void) +{ + u32 raw_mcr_cnt; + u32 hit_mcr_cnt; + int hitrate; + + if (debug & AVS2_DBG_CACHE) + pr_info("[cache_util.c] Entered decomp_get_hitrate...\n"); + WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x0<<1)); + raw_mcr_cnt = READ_VREG(HEVCD_MPP_DECOMP_PERFMON_DATA); + WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x1<<1)); + hit_mcr_cnt = READ_VREG(HEVCD_MPP_DECOMP_PERFMON_DATA); + + if (debug & AVS2_DBG_CACHE) { + pr_info("hcache_raw_cnt_total: %d\n",raw_mcr_cnt); + pr_info("hcache_hit_cnt_total: %d\n",hit_mcr_cnt); + } + if (raw_mcr_cnt != 0) { + hitrate = (hit_mcr_cnt / raw_mcr_cnt) * 100; + if (debug & AVS2_DBG_CACHE) + pr_info("DECOMP_HCACHE_HIT_RATE : %d\n", hitrate); + } else { + if (debug & AVS2_DBG_CACHE) + pr_info("DECOMP_HCACHE_HIT_RATE : na\n"); + } + WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x2<<1)); + raw_mcr_cnt = READ_VREG(HEVCD_MPP_DECOMP_PERFMON_DATA); + WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x3<<1)); + hit_mcr_cnt = READ_VREG(HEVCD_MPP_DECOMP_PERFMON_DATA); + + if (debug & AVS2_DBG_CACHE) { + pr_info("dcache_raw_cnt_total: %d\n", raw_mcr_cnt); + pr_info("dcache_hit_cnt_total: %d\n", hit_mcr_cnt); + } + if (raw_mcr_cnt != 0) { + hitrate = (hit_mcr_cnt / raw_mcr_cnt) * 100; + if (debug & AVS2_DBG_CACHE) + pr_info("DECOMP_DCACHE_HIT_RATE : %d\n", hitrate); + } else if (debug & AVS2_DBG_CACHE) { + pr_info("DECOMP_DCACHE_HIT_RATE : na\n"); + } +return; +} + +static void decomp_get_comprate(void) +{ + u32 raw_ucomp_cnt; + u32 fast_comp_cnt; + u32 slow_comp_cnt; + int comprate; + + if (debug & AVS2_DBG_CACHE) + pr_info("[cache_util.c] Entered decomp_get_comprate...\n"); + WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x4<<1)); + fast_comp_cnt = READ_VREG(HEVCD_MPP_DECOMP_PERFMON_DATA); + WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x5<<1)); + slow_comp_cnt = READ_VREG(HEVCD_MPP_DECOMP_PERFMON_DATA); + WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x6<<1)); + raw_ucomp_cnt = READ_VREG(HEVCD_MPP_DECOMP_PERFMON_DATA); + if (debug & AVS2_DBG_CACHE) { + pr_info("decomp_fast_comp_total: %d\n", fast_comp_cnt); + pr_info("decomp_slow_comp_total: %d\n", slow_comp_cnt); + pr_info("decomp_raw_uncomp_total: %d\n", raw_ucomp_cnt); + } + + if (raw_ucomp_cnt != 0) { + comprate = ((fast_comp_cnt + slow_comp_cnt) + / raw_ucomp_cnt) * 100; + if (debug & AVS2_DBG_CACHE) + pr_info("DECOMP_COMP_RATIO : %d\n", comprate); + } else if (debug & AVS2_DBG_CACHE) { + pr_info("DECOMP_COMP_RATIO : na\n"); + } + return; +} +#endif + +static void config_mcrcc_axi_hw(struct AVS2Decoder_s *dec) +{ + uint32_t rdata32; + uint32_t rdata32_2; + struct avs2_decoder *avs2_dec = &dec->avs2_dec; + + WRITE_VREG(HEVCD_MCRCC_CTL1, 0x2); /* reset mcrcc*/ + + if (avs2_dec->img.type == I_IMG) { /* I-PIC*/ + /* remove reset -- disables clock */ + WRITE_VREG(HEVCD_MCRCC_CTL1, 0x0); + return; + } +/* + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) { + mcrcc_get_hitrate(); + decomp_get_hitrate(); + decomp_get_comprate(); + } +*/ + if ((avs2_dec->img.type == B_IMG) || + (avs2_dec->img.type == F_IMG)) { /*B-PIC or F_PIC*/ + /*Programme canvas0 */ + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, + (0 << 8) | (0 << 1) | 0); + rdata32 = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR); + rdata32 = rdata32 & 0xffff; + rdata32 = rdata32 | (rdata32 << 16); + WRITE_VREG(HEVCD_MCRCC_CTL2, rdata32); + + /*Programme canvas1 */ + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, + (16 << 8) | (1 << 1) | 0); + rdata32_2 = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR); + rdata32_2 = rdata32_2 & 0xffff; + rdata32_2 = rdata32_2 | (rdata32_2 << 16); + if (rdata32 == rdata32_2) { + rdata32_2 = + READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR); + rdata32_2 = rdata32_2 & 0xffff; + rdata32_2 = rdata32_2 | (rdata32_2 << 16); + } + WRITE_VREG(HEVCD_MCRCC_CTL3, rdata32_2); + } else { /* P-PIC */ + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, + (0 << 8) | (1 << 1) | 0); + rdata32 = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR); + rdata32 = rdata32 & 0xffff; + rdata32 = rdata32 | (rdata32 << 16); + WRITE_VREG(HEVCD_MCRCC_CTL2, rdata32); + + /*Programme canvas1*/ + rdata32 = + READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR); + rdata32 = rdata32 & 0xffff; + rdata32 = rdata32 | (rdata32 << 16); + WRITE_VREG(HEVCD_MCRCC_CTL3, rdata32); + } + /*enable mcrcc progressive-mode */ + WRITE_VREG(HEVCD_MCRCC_CTL1, 0xff0); + return; +} + +static void config_mpred_hw(struct AVS2Decoder_s *dec) +{ + uint32_t data32; + struct avs2_decoder *avs2_dec = &dec->avs2_dec; + struct avs2_frame_s *cur_pic = avs2_dec->hc.cur_pic; + struct avs2_frame_s *col_pic = avs2_dec->fref[0]; + int32_t mpred_mv_rd_start_addr; + int32_t mpred_curr_lcu_x; + int32_t mpred_curr_lcu_y; + int32_t mpred_mv_rd_end_addr; + int32_t above_en; + int32_t mv_wr_en; + int32_t mv_rd_en; + int32_t col_isIntra; + int mv_mem_unit; + if (avs2_dec->img.type != I_IMG) { + above_en = 1; + mv_wr_en = 1; + mv_rd_en = 1; + col_isIntra = 0; + } else { + above_en = 1; + mv_wr_en = 1; + mv_rd_en = 0; + col_isIntra = 0; + } + + mpred_mv_rd_start_addr = + col_pic->mpred_mv_wr_start_addr; + data32 = READ_VREG(HEVC_MPRED_CURR_LCU); + mpred_curr_lcu_x = data32 & 0xffff; + mpred_curr_lcu_y = (data32 >> 16) & 0xffff; + + mv_mem_unit = avs2_dec->lcu_size_log2 == 6 ? + 0x200 : (avs2_dec->lcu_size_log2 == 5 ? + 0x80 : 0x20); + + mpred_mv_rd_end_addr = + mpred_mv_rd_start_addr + + ((avs2_dec->lcu_x_num * + avs2_dec->lcu_y_num) * mv_mem_unit); + + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "cur pic index %d col pic index %d\n", + cur_pic->index, col_pic->index); + + + WRITE_VREG(HEVC_MPRED_MV_WR_START_ADDR, + cur_pic->mpred_mv_wr_start_addr); + WRITE_VREG(HEVC_MPRED_MV_RD_START_ADDR, + col_pic->mpred_mv_wr_start_addr); + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "[MPRED CO_MV] write 0x%x read 0x%x\n", + cur_pic->mpred_mv_wr_start_addr, + col_pic->mpred_mv_wr_start_addr); + + data32 = + ((avs2_dec->bk_img_is_top_field) << 13) | + ((avs2_dec->hd.background_picture_enable & 1) << 12) | + ((avs2_dec->hd.curr_RPS.num_of_ref & 7) << 8) | + ((avs2_dec->hd.b_pmvr_enabled & 1) << 6) | + ((avs2_dec->img.is_top_field & 1) << 5) | + ((avs2_dec->img.is_field_sequence & 1) << 4) | + ((avs2_dec->img.typeb & 7) << 1) | + (avs2_dec->hd.background_reference_enable & 0x1); + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "HEVC_MPRED_CTRL9 <= 0x%x(num of ref %d)\n", + data32, avs2_dec->hd.curr_RPS.num_of_ref); + WRITE_VREG(HEVC_MPRED_CTRL9, data32); + + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "%s: dis %d %d %d %d %d %d %d fref0_ref_poc %d %d %d %d %d %d %d\n", + __func__, + avs2_dec->fref[0]->imgtr_fwRefDistance, + avs2_dec->fref[1]->imgtr_fwRefDistance, + avs2_dec->fref[2]->imgtr_fwRefDistance, + avs2_dec->fref[3]->imgtr_fwRefDistance, + avs2_dec->fref[4]->imgtr_fwRefDistance, + avs2_dec->fref[5]->imgtr_fwRefDistance, + avs2_dec->fref[6]->imgtr_fwRefDistance, + avs2_dec->fref[0]->ref_poc[0], + avs2_dec->fref[0]->ref_poc[1], + avs2_dec->fref[0]->ref_poc[2], + avs2_dec->fref[0]->ref_poc[3], + avs2_dec->fref[0]->ref_poc[4], + avs2_dec->fref[0]->ref_poc[5], + avs2_dec->fref[0]->ref_poc[6] + ); + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "pic_distance %d, imgtr_next_P %d\n", + avs2_dec->img.pic_distance, avs2_dec->img.imgtr_next_P); + + + WRITE_VREG(HEVC_MPRED_CUR_POC, avs2_dec->img.pic_distance); + WRITE_VREG(HEVC_MPRED_COL_POC, avs2_dec->img.imgtr_next_P); + + /*below MPRED Ref_POC_xx_Lx registers + must follow Ref_POC_xx_L0 -> + Ref_POC_xx_L1 in pair write order!!!*/ + WRITE_VREG(HEVC_MPRED_L0_REF00_POC, + avs2_dec->fref[0]->imgtr_fwRefDistance); + WRITE_VREG(HEVC_MPRED_L1_REF00_POC, + avs2_dec->fref[0]->ref_poc[0]); + + WRITE_VREG(HEVC_MPRED_L0_REF01_POC, + avs2_dec->fref[1]->imgtr_fwRefDistance); + WRITE_VREG(HEVC_MPRED_L1_REF01_POC, + avs2_dec->fref[0]->ref_poc[1]); + + WRITE_VREG(HEVC_MPRED_L0_REF02_POC, + avs2_dec->fref[2]->imgtr_fwRefDistance); + WRITE_VREG(HEVC_MPRED_L1_REF02_POC, + avs2_dec->fref[0]->ref_poc[2]); + + WRITE_VREG(HEVC_MPRED_L0_REF03_POC, + avs2_dec->fref[3]->imgtr_fwRefDistance); + WRITE_VREG(HEVC_MPRED_L1_REF03_POC, + avs2_dec->fref[0]->ref_poc[3]); + + WRITE_VREG(HEVC_MPRED_L0_REF04_POC, + avs2_dec->fref[4]->imgtr_fwRefDistance); + WRITE_VREG(HEVC_MPRED_L1_REF04_POC, + avs2_dec->fref[0]->ref_poc[4]); + + WRITE_VREG(HEVC_MPRED_L0_REF05_POC, + avs2_dec->fref[5]->imgtr_fwRefDistance); + WRITE_VREG(HEVC_MPRED_L1_REF05_POC, + avs2_dec->fref[0]->ref_poc[5]); + + WRITE_VREG(HEVC_MPRED_L0_REF06_POC, + avs2_dec->fref[6]->imgtr_fwRefDistance); + WRITE_VREG(HEVC_MPRED_L1_REF06_POC, + avs2_dec->fref[0]->ref_poc[6]); + + + WRITE_VREG(HEVC_MPRED_MV_RD_END_ADDR, + mpred_mv_rd_end_addr); +} + +static void config_dblk_hw(struct AVS2Decoder_s *dec) +{ + /* + * Picture level de-block parameter configuration here + */ + struct avs2_decoder *avs2_dec = &dec->avs2_dec; + union param_u *rpm_param = &avs2_dec->param; + uint32_t data32; + + data32 = READ_VREG(HEVC_DBLK_CFG1); + data32 = (((data32 >> 20) & 0xfff) << 20) | + (((avs2_dec->input.sample_bit_depth == 10) + ? 0xa : 0x0) << 16) | /*[16 +: 4]: {luma_bd[1:0], + chroma_bd[1:0]}*/ + (((data32 >> 2) & 0x3fff) << 2) | + (((rpm_param->p.lcu_size == 6) + ? 0 : (rpm_param->p.lcu_size == 5) + ? 1 : 2) << 0);/*[ 0 +: 2]: lcu_size*/ + WRITE_VREG(HEVC_DBLK_CFG1, data32); + + data32 = (avs2_dec->img.height << 16) | + avs2_dec->img.width; + WRITE_VREG(HEVC_DBLK_CFG2, data32); + /* + [27 +: 1]: cross_slice_loopfilter_enable_flag + [26 +: 1]: loop_filter_disable + [25 +: 1]: useNSQT + [22 +: 3]: imgtype + [17 +: 5]: alpha_c_offset (-8~8) + [12 +: 5]: beta_offset (-8~8) + [ 6 +: 6]: chroma_quant_param_delta_u (-16~16) + [ 0 +: 6]: chroma_quant_param_delta_v (-16~16) + */ + data32 = ((avs2_dec->input.crossSliceLoopFilter + & 0x1) << 27) | + ((rpm_param->p.loop_filter_disable & 0x1) << 26) | + ((avs2_dec->input.useNSQT & 0x1) << 25) | + ((avs2_dec->img.type & 0x7) << 22) | + ((rpm_param->p.alpha_c_offset & 0x1f) << 17) | + ((rpm_param->p.beta_offset & 0x1f) << 12) | + ((rpm_param->p.chroma_quant_param_delta_cb & 0x3f) << 6) | + ((rpm_param->p.chroma_quant_param_delta_cr & 0x3f) << 0); + + WRITE_VREG(HEVC_DBLK_CFG9, data32); + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "[c] cfgDBLK: crossslice(%d),lfdisable(%d),bitDepth(%d),lcuSize(%d),NSQT(%d)\n", + avs2_dec->input.crossSliceLoopFilter, + rpm_param->p.loop_filter_disable, + avs2_dec->input.sample_bit_depth, + avs2_dec->lcu_size, + avs2_dec->input.useNSQT); + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "[c] cfgDBLK: alphaCOffset(%d),betaOffset(%d),quantDeltaCb(%d),quantDeltaCr(%d)\n", + rpm_param->p.alpha_c_offset, + rpm_param->p.beta_offset, + rpm_param->p.chroma_quant_param_delta_cb, + rpm_param->p.chroma_quant_param_delta_cr); + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "[c] cfgDBLK: .done.\n"); +} + +static void config_sao_hw(struct AVS2Decoder_s *dec) +{ + uint32_t data32; + struct avs2_decoder *avs2_dec = &dec->avs2_dec; + struct avs2_frame_s *cur_pic = avs2_dec->hc.cur_pic; + + int lcu_size = 64; + int mc_buffer_size_u_v = + cur_pic->lcu_total * lcu_size*lcu_size/2; + int mc_buffer_size_u_v_h = + (mc_buffer_size_u_v + 0xffff) >> 16;/*64k alignment*/ + + data32 = READ_VREG(HEVC_SAO_CTRL0); + data32 &= (~0xf); + data32 |= avs2_dec->lcu_size_log2; + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "%s, lcu_size_log2 = %d, config HEVC_SAO_CTRL0 0x%x\n", + __func__, + avs2_dec->lcu_size_log2, + data32); + + WRITE_VREG(HEVC_SAO_CTRL0, data32); + +#ifndef AVS2_10B_MMU + if ((get_double_write_mode(dec) & 0x10) == 0) + WRITE_VREG(HEVC_CM_BODY_START_ADDR, cur_pic->mc_y_adr); +#endif + if (get_double_write_mode(dec)) { + WRITE_VREG(HEVC_SAO_Y_START_ADDR, cur_pic->dw_y_adr); + WRITE_VREG(HEVC_SAO_C_START_ADDR, cur_pic->dw_u_v_adr); + WRITE_VREG(HEVC_SAO_Y_WPTR, cur_pic->dw_y_adr); + WRITE_VREG(HEVC_SAO_C_WPTR, cur_pic->dw_u_v_adr); + } else { + WRITE_VREG(HEVC_SAO_Y_START_ADDR, 0xffffffff); + WRITE_VREG(HEVC_SAO_C_START_ADDR, 0xffffffff); + } +#ifdef AVS2_10B_MMU + WRITE_VREG(HEVC_CM_HEADER_START_ADDR, cur_pic->header_adr); +#endif + data32 = (mc_buffer_size_u_v_h << 16) << 1; + /*pr_info("data32=%x,mc_buffer_size_u_v_h=%x,lcu_total=%x\n", + data32, mc_buffer_size_u_v_h, cur_pic->lcu_total);*/ + WRITE_VREG(HEVC_SAO_Y_LENGTH, data32); + + data32 = (mc_buffer_size_u_v_h << 16); + WRITE_VREG(HEVC_SAO_C_LENGTH, data32); + +#ifdef AVS2_10B_NV21 +#ifdef DOS_PROJECT + data32 = READ_VREG(HEVC_SAO_CTRL1); + data32 &= (~0x3000); + /*[13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32*/ + data32 |= (MEM_MAP_MODE << 12); + data32 &= (~0x3); + data32 |= 0x1; /* [1]:dw_disable [0]:cm_disable*/ + + /* + * [31:24] ar_fifo1_axi_thred + * [23:16] ar_fifo0_axi_thred + * [15:14] axi_linealign, 0-16bytes, 1-32bytes, 2-64bytes + * [13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32 + * [11:08] axi_lendian_C + * [07:04] axi_lendian_Y + * [3] reserved + * [2] clk_forceon + * [1] dw_disable:disable double write output + * [0] cm_disable:disable compress output + */ + data32 &= (~(3 << 14)); + data32 |= (2 << 14); + + WRITE_VREG(HEVC_SAO_CTRL1, data32); + /*[23:22] dw_v1_ctrl [21:20] dw_v0_ctrl [19:18] dw_h1_ctrl + [17:16] dw_h0_ctrl*/ + data32 = READ_VREG(HEVC_SAO_CTRL5); + /*set them all 0 for H265_NV21 (no down-scale)*/ + data32 &= ~(0xff << 16); + WRITE_VREG(HEVC_SAO_CTRL5, data32); + ata32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG); + data32 &= (~0x30); + /*[5:4] address_format 00:linear 01:32x32 10:64x32*/ + data32 |= (MEM_MAP_MODE << 4); + WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32); +#else + /*m8baby test1902*/ + data32 = READ_VREG(HEVC_SAO_CTRL1); + data32 &= (~0x3000); + /*[13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32*/ + data32 |= (MEM_MAP_MODE << 12); + data32 &= (~0xff0); + /*data32 |= 0x670;*/ /*Big-Endian per 64-bit*/ + data32 |= 0x880; /*.Big-Endian per 64-bit */ + data32 &= (~0x3); + data32 |= 0x1; /*[1]:dw_disable [0]:cm_disable*/ + WRITE_VREG(HEVC_SAO_CTRL1, data32); + /* [23:22] dw_v1_ctrl [21:20] dw_v0_ctrl + [19:18] dw_h1_ctrl [17:16] dw_h0_ctrl*/ + data32 = READ_VREG(HEVC_SAO_CTRL5); + /* set them all 0 for H265_NV21 (no down-scale)*/ + data32 &= ~(0xff << 16); + WRITE_VREG(HEVC_SAO_CTRL5, data32); + + /* + * [3:0] little_endian + * [5:4] address_format 00:linear 01:32x32 10:64x32 + * [7:6] reserved + * [9:8] Linear_LineAlignment 00:16byte 01:32byte 10:64byte + * [11:10] reserved + * [12] CbCr_byte_swap + * [31:13] reserved + */ + + data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG); + data32 &= (~0x30); + /*[5:4] address_format 00:linear 01:32x32 10:64x32*/ + data32 |= (MEM_MAP_MODE << 4); + data32 &= (~0xF); + data32 |= 0x8; /*Big-Endian per 64-bit*/ + + data32 &= (~(3 << 8)); + data32 |= (2 << 8); + WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32); +#endif +#else + data32 = READ_VREG(HEVC_SAO_CTRL1); + data32 &= (~(3 << 14)); + data32 |= (2 << 14); /* line align with 64*/ + data32 &= (~0x3000); + data32 |= (MEM_MAP_MODE << 12); /* [13:12] axi_aformat, 0-Linear, + 1-32x32, 2-64x32 */ + data32 &= (~0xff0); + data32 |= ((dec->endian >> 8) & 0xfff); /* data32 |= 0x670; Big-Endian per 64-bit */ + data32 &= (~0x3); /*[1]:dw_disable [0]:cm_disable*/ +#if 0 + if (get_cpu_major_id() < MESON_CPU_MAJOR_ID_G12A) { + if (get_double_write_mode(dec) == 0) + data32 |= 0x2; /*disable double write*/ +#ifndef AVS2_10B_MMU + else + if (get_double_write_mode(dec) & 0x10) + data32 |= 0x1; /*disable cm*/ +#endif + } +#endif + if (get_double_write_mode(dec) == 0) + data32 |= 0x2; /*disable double write*/ + else if (get_double_write_mode(dec) & 0x10) + data32 |= 0x1; /*disable cm*/ + + /* + * [31:24] ar_fifo1_axi_thred + * [23:16] ar_fifo0_axi_thred + * [15:14] axi_linealign, 0-16bytes, 1-32bytes, 2-64bytes + * [13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32 + * [11:08] axi_lendian_C + * [07:04] axi_lendian_Y + * [3] reserved + * [2] clk_forceon + * [1] dw_disable:disable double write output + * [0] cm_disable:disable compress output + */ + WRITE_VREG(HEVC_SAO_CTRL1, data32); + + if (get_double_write_mode(dec) & 0x10) { + /* [23:22] dw_v1_ctrl + [21:20] dw_v0_ctrl + [19:18] dw_h1_ctrl + [17:16] dw_h0_ctrl + */ + data32 = READ_VREG(HEVC_SAO_CTRL5); + /*set them all 0 for H265_NV21 (no down-scale)*/ + data32 &= ~(0xff << 16); + WRITE_VREG(HEVC_SAO_CTRL5, data32); + } else { + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T7) + WRITE_VREG(HEVC_SAO_CTRL26, 0); + + data32 = READ_VREG(HEVC_SAO_CTRL5); + data32 &= (~(0xff << 16)); + if (get_double_write_mode(dec) == 8 || + get_double_write_mode(dec) == 9) { + data32 |= (0xff<<16); + WRITE_VREG(HEVC_SAO_CTRL26, 0xf); + } else if (get_double_write_mode(dec) == 2 || + get_double_write_mode(dec) == 3) + data32 |= (0xff<<16); + else if (get_double_write_mode(dec) == 4) + data32 |= (0x33<<16); + WRITE_VREG(HEVC_SAO_CTRL5, data32); + } + + /* + * [3:0] little_endian + * [5:4] address_format 00:linear 01:32x32 10:64x32 + * [7:6] reserved + * [9:8] Linear_LineAlignment 00:16byte 01:32byte 10:64byte + * [11:10] reserved + * [12] CbCr_byte_swap + * [31:13] reserved + */ + + data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG); + data32 &= (~0x30); + /* [5:4] -- address_format 00:linear 01:32x32 10:64x32 */ + data32 |= (mem_map_mode << 4); + data32 &= (~0xF); + data32 |= (dec->endian & 0xf); /* valid only when double write only */ + /*data32 |= 0x8;*/ /* Big-Endian per 64-bit */ + data32 &= (~(3 << 8)); + data32 |= (2 << 8); /* line align with 64 for dw only */ + WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32); +#endif +} + +static void reconstructCoefficients(struct AVS2Decoder_s *dec, + struct ALFParam_s *alfParam) +{ + int32_t g, sum, i, coeffPred; + for (g = 0; g < alfParam->filters_per_group; g++) { + sum = 0; + for (i = 0; i < alfParam->num_coeff - 1; i++) { + sum += (2 * alfParam->coeffmulti[g][i]); + dec->m_filterCoeffSym[g][i] = + alfParam->coeffmulti[g][i]; + /*pr_info("[t] dec->m_filterCoeffSym[%d][%d]=0x%x\n", + g, i, dec->m_filterCoeffSym[g][i]);*/ + } + coeffPred = (1 << ALF_NUM_BIT_SHIFT) - sum; + dec->m_filterCoeffSym[g][alfParam->num_coeff - 1] + = coeffPred + + alfParam->coeffmulti[g][alfParam->num_coeff - 1]; + /*pr_info("[t] dec->m_filterCoeffSym[%d][%d]=0x%x\n", + g, (alfParam->num_coeff - 1), + dec->m_filterCoeffSym[g][alfParam->num_coeff - 1]);*/ + } +} + +static void reconstructCoefInfo(struct AVS2Decoder_s *dec, + int32_t compIdx, struct ALFParam_s *alfParam) +{ + int32_t i; + if (compIdx == ALF_Y) { + if (alfParam->filters_per_group > 1) { + for (i = 1; i < NO_VAR_BINS; ++i) { + if (alfParam->filterPattern[i]) + dec->m_varIndTab[i] = + dec->m_varIndTab[i - 1] + 1; + else + dec->m_varIndTab[i] = + dec->m_varIndTab[i - 1]; + } + } + } + reconstructCoefficients(dec, alfParam); +} + +static void config_alf_hw(struct AVS2Decoder_s *dec) +{ + /* + * Picture level ALF parameter configuration here + */ + uint32_t data32; + int32_t i, j; + int32_t m_filters_per_group; + struct avs2_decoder *avs2_dec = &dec->avs2_dec; + struct ALFParam_s *m_alfPictureParam_y = + &avs2_dec->m_alfPictureParam[0]; + struct ALFParam_s *m_alfPictureParam_cb = + &avs2_dec->m_alfPictureParam[1]; + struct ALFParam_s *m_alfPictureParam_cr = + &avs2_dec->m_alfPictureParam[2]; + + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "[t]alfy,cidx(%d),flag(%d),filters_per_group(%d),filterPattern[0]=0x%x,[15]=0x%x\n", + m_alfPictureParam_y->componentID, + m_alfPictureParam_y->alf_flag, + m_alfPictureParam_y->filters_per_group, + m_alfPictureParam_y->filterPattern[0], + m_alfPictureParam_y->filterPattern[15]); + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "[t]alfy,num_coeff(%d),coeffmulti[0][0]=0x%x,[0][1]=0x%x,[1][0]=0x%x,[1][1]=0x%x\n", + m_alfPictureParam_y->num_coeff, + m_alfPictureParam_y->coeffmulti[0][0], + m_alfPictureParam_y->coeffmulti[0][1], + m_alfPictureParam_y->coeffmulti[1][0], + m_alfPictureParam_y->coeffmulti[1][1]); + + /*Cr*/ + for (i = 0; i < 16; i++) + dec->m_varIndTab[i] = 0; + for (j = 0; j < 16; j++) + for (i = 0; i < 9; i++) + dec->m_filterCoeffSym[j][i] = 0; + reconstructCoefInfo(dec, 2, m_alfPictureParam_cr); + data32 = + ((dec->m_filterCoeffSym[0][4] & 0xf) << 28) | + ((dec->m_filterCoeffSym[0][3] & 0x7f) << 21) | + ((dec->m_filterCoeffSym[0][2] & 0x7f) << 14) | + ((dec->m_filterCoeffSym[0][1] & 0x7f) << 7) | + ((dec->m_filterCoeffSym[0][0] & 0x7f) << 0); + WRITE_VREG(HEVC_DBLK_CFGD, data32); + data32 = + ((dec->m_filterCoeffSym[0][8] & 0x7f) << 24) | + ((dec->m_filterCoeffSym[0][7] & 0x7f) << 17) | + ((dec->m_filterCoeffSym[0][6] & 0x7f) << 10) | + ((dec->m_filterCoeffSym[0][5] & 0x7f) << 3) | + (((dec->m_filterCoeffSym[0][4] >> 4) & 0x7) << 0); + WRITE_VREG(HEVC_DBLK_CFGD, data32); + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "[c] pic_alf_on_cr(%d), alf_cr_coef(%d %d %d %d %d %d %d %d %d)\n", + m_alfPictureParam_cr->alf_flag, + dec->m_filterCoeffSym[0][0], + dec->m_filterCoeffSym[0][1], + dec->m_filterCoeffSym[0][2], + dec->m_filterCoeffSym[0][3], + dec->m_filterCoeffSym[0][4], + dec->m_filterCoeffSym[0][5], + dec->m_filterCoeffSym[0][6], + dec->m_filterCoeffSym[0][7], + dec->m_filterCoeffSym[0][8]); + + /* Cb*/ + for (j = 0; j < 16; j++) + for (i = 0; i < 9; i++) + dec->m_filterCoeffSym[j][i] = 0; + reconstructCoefInfo(dec, 1, m_alfPictureParam_cb); + data32 = + ((dec->m_filterCoeffSym[0][4] & 0xf) << 28) | + ((dec->m_filterCoeffSym[0][3] & 0x7f) << 21) | + ((dec->m_filterCoeffSym[0][2] & 0x7f) << 14) | + ((dec->m_filterCoeffSym[0][1] & 0x7f) << 7) | + ((dec->m_filterCoeffSym[0][0] & 0x7f) << 0); + WRITE_VREG(HEVC_DBLK_CFGD, data32); + data32 = + ((dec->m_filterCoeffSym[0][8] & 0x7f) << 24) | + ((dec->m_filterCoeffSym[0][7] & 0x7f) << 17) | + ((dec->m_filterCoeffSym[0][6] & 0x7f) << 10) | + ((dec->m_filterCoeffSym[0][5] & 0x7f) << 3) | + (((dec->m_filterCoeffSym[0][4] >> 4) & 0x7) << 0); + WRITE_VREG(HEVC_DBLK_CFGD, data32); + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "[c] pic_alf_on_cb(%d), alf_cb_coef(%d %d %d %d %d %d %d %d %d)\n", + m_alfPictureParam_cb->alf_flag, + dec->m_filterCoeffSym[0][0], + dec->m_filterCoeffSym[0][1], + dec->m_filterCoeffSym[0][2], + dec->m_filterCoeffSym[0][3], + dec->m_filterCoeffSym[0][4], + dec->m_filterCoeffSym[0][5], + dec->m_filterCoeffSym[0][6], + dec->m_filterCoeffSym[0][7], + dec->m_filterCoeffSym[0][8]); + + /* Y*/ + for (j = 0; j < 16; j++) + for (i = 0; i < 9; i++) + dec->m_filterCoeffSym[j][i] = 0; + reconstructCoefInfo(dec, 0, m_alfPictureParam_y); + data32 = + ((dec->m_varIndTab[7] & 0xf) << 28) | + ((dec->m_varIndTab[6] & 0xf) << 24) | + ((dec->m_varIndTab[5] & 0xf) << 20) | + ((dec->m_varIndTab[4] & 0xf) << 16) | + ((dec->m_varIndTab[3] & 0xf) << 12) | + ((dec->m_varIndTab[2] & 0xf) << 8) | + ((dec->m_varIndTab[1] & 0xf) << 4) | + ((dec->m_varIndTab[0] & 0xf) << 0); + WRITE_VREG(HEVC_DBLK_CFGD, data32); + data32 = ((dec->m_varIndTab[15] & 0xf) << 28) | + ((dec->m_varIndTab[14] & 0xf) << 24) | + ((dec->m_varIndTab[13] & 0xf) << 20) | + ((dec->m_varIndTab[12] & 0xf) << 16) | + ((dec->m_varIndTab[11] & 0xf) << 12) | + ((dec->m_varIndTab[10] & 0xf) << 8) | + ((dec->m_varIndTab[9] & 0xf) << 4) | + ((dec->m_varIndTab[8] & 0xf) << 0); + WRITE_VREG(HEVC_DBLK_CFGD, data32); + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "[c] pic_alf_on_y(%d), alf_y_tab(%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d)\n", + m_alfPictureParam_y->alf_flag, + dec->m_varIndTab[0], + dec->m_varIndTab[1], + dec->m_varIndTab[2], + dec->m_varIndTab[3], + dec->m_varIndTab[4], + dec->m_varIndTab[5], + dec->m_varIndTab[6], + dec->m_varIndTab[7], + dec->m_varIndTab[8], + dec->m_varIndTab[9], + dec->m_varIndTab[10], + dec->m_varIndTab[11], + dec->m_varIndTab[12], + dec->m_varIndTab[13], + dec->m_varIndTab[14], + dec->m_varIndTab[15]); + + m_filters_per_group = + (m_alfPictureParam_y->alf_flag == 0) ? + 1 : m_alfPictureParam_y->filters_per_group; + for (i = 0; i < m_filters_per_group; i++) { + data32 = + ((dec->m_filterCoeffSym[i][4] & 0xf) << 28) | + ((dec->m_filterCoeffSym[i][3] & 0x7f) << 21) | + ((dec->m_filterCoeffSym[i][2] & 0x7f) << 14) | + ((dec->m_filterCoeffSym[i][1] & 0x7f) << 7) | + ((dec->m_filterCoeffSym[i][0] & 0x7f) << 0); + WRITE_VREG(HEVC_DBLK_CFGD, data32); + data32 = + /*[31] last indication*/ + ((i == m_filters_per_group-1) << 31) | + ((dec->m_filterCoeffSym[i][8] & 0x7f) << 24) | + ((dec->m_filterCoeffSym[i][7] & 0x7f) << 17) | + ((dec->m_filterCoeffSym[i][6] & 0x7f) << 10) | + ((dec->m_filterCoeffSym[i][5] & 0x7f) << 3) | + (((dec->m_filterCoeffSym[i][4] >> 4) & 0x7) << 0); + WRITE_VREG(HEVC_DBLK_CFGD, data32); + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "[c] alf_y_coef[%d](%d %d %d %d %d %d %d %d %d)\n", + i, dec->m_filterCoeffSym[i][0], + dec->m_filterCoeffSym[i][1], + dec->m_filterCoeffSym[i][2], + dec->m_filterCoeffSym[i][3], + dec->m_filterCoeffSym[i][4], + dec->m_filterCoeffSym[i][5], + dec->m_filterCoeffSym[i][6], + dec->m_filterCoeffSym[i][7], + dec->m_filterCoeffSym[i][8]); + } + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "[c] cfgALF .done.\n"); +} + +static void config_other_hw(struct AVS2Decoder_s *dec) +{ + uint32_t data32; + struct avs2_decoder *avs2_dec = &dec->avs2_dec; + struct avs2_frame_s *cur_pic = avs2_dec->hc.cur_pic; + int bit_depth = cur_pic->bit_depth; + int losless_comp_header_size = + compute_losless_comp_header_size( + dec, cur_pic->pic_w, + cur_pic->pic_h); + int losless_comp_body_size = + compute_losless_comp_body_size( + dec, cur_pic->pic_w, + cur_pic->pic_h, (bit_depth == AVS2_BITS_10)); + cur_pic->comp_body_size = losless_comp_body_size; + +#ifdef LOSLESS_COMPRESS_MODE + data32 = READ_VREG(HEVC_SAO_CTRL5); + if (bit_depth == AVS2_BITS_10) + data32 &= ~(1 << 9); + else + data32 |= (1 << 9); + + WRITE_VREG(HEVC_SAO_CTRL5, data32); + +#ifdef AVS2_10B_MMU + /*bit[4] : paged_mem_mode*/ + WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0x1 << 4)); +#else + /*bit[3] smem mdoe*/ + if (bit_depth == AVS2_BITS_10) + WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0 << 3)); + else + WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (1 << 3)); +#endif + WRITE_VREG(HEVCD_MPP_DECOMP_CTL2, (losless_comp_body_size >> 5)); + /*WRITE_VREG(HEVCD_MPP_DECOMP_CTL3,(0xff<<20) | (0xff<<10) | 0xff);*/ + WRITE_VREG(HEVC_CM_BODY_LENGTH, losless_comp_body_size); + WRITE_VREG(HEVC_CM_HEADER_OFFSET, losless_comp_body_size); + WRITE_VREG(HEVC_CM_HEADER_LENGTH, losless_comp_header_size); +#else + WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31); +#endif +} + +static u32 init_cuva_size; +static int cuva_data_is_avaible(struct AVS2Decoder_s *dec) +{ + u32 reg_val; + + reg_val = READ_VREG(AVS2_CUVA_DATA_SIZE); + avs2_print(dec, AVS2_DBG_BUFMGR_MORE, + "%s:reg_val: %u \n", + __func__, reg_val); + if (reg_val != 0 && reg_val != init_cuva_size) + return 1; + else + return 0; +} + +static void config_cuva_buf(struct AVS2Decoder_s *dec) +{ + WRITE_VREG(AVS2_CUVA_ADR, dec->cuva_phy_addr); + init_cuva_size = (dec->cuva_size >> 4) << 16; + WRITE_VREG(AVS2_CUVA_DATA_SIZE, init_cuva_size); +} + +static void set_cuva_data(struct AVS2Decoder_s *dec) +{ + int i; + unsigned short *cuva_adr; + unsigned int size_reg_val = + READ_VREG(AVS2_CUVA_DATA_SIZE); + unsigned int cuva_count = 0; + int cuva_size = 0; + struct avs2_frame_s *pic = dec->avs2_dec.hc.cur_pic; + if (pic == NULL || 0 == cuva_data_is_avaible(dec)) { + avs2_print(dec, AVS2_DBG_HDR_INFO, + "%s:pic 0x%p or data not avaible\n", + __func__, pic); + return; + } + + cuva_adr = (unsigned short *)dec->cuva_addr; + cuva_count = ((size_reg_val >> 16) << 4) >> 1; + cuva_size = dec->cuva_size; + dec->hdr_flag |= HDR_CUVA_MASK; + + avs2_print(dec, AVS2_DBG_BUFMGR_MORE, + "%s:pic 0x%p cuva_count(%d) cuva_size(%d) hdr_flag 0x%x\n", + __func__, pic, cuva_count, cuva_size, dec->hdr_flag); + if (cuva_size > 0 && cuva_count > 0) { + int new_size; + char *new_buf; + + new_size = cuva_size; + new_buf = vzalloc(new_size); + if (new_buf) { + unsigned char *p = new_buf; + int len = 0; + pic->cuva_data_buf = new_buf; + + for (i = 0; i < cuva_count; i += 4) { + int j; + + for (j = 0; j < 4; j++) { + unsigned short aa = cuva_adr[i + 3 - j]; + *p = aa & 0xff; + p++; + len++; + } + } + if (len > 0) { + pic->cuva_data_size = len; + } + + avs2_print(dec, AVS2_DBG_BUFMGR_MORE, + "cuva: (size %d)\n", + pic->cuva_data_size); + if (get_dbg_flag(dec) & AVS2_DBG_HDR_DATA) { + for (i = 0; i < pic->cuva_data_size; i++) { + pr_info("%02x ", pic->cuva_data_buf[i]); + if (((i + 1) & 0xf) == 0) + pr_info("\n"); + } + pr_info("\n"); + } + + } else { + avs2_print(dec, 0, "new buf alloc failed\n"); + if (pic->cuva_data_buf) + vfree(pic->cuva_data_buf); + pic->cuva_data_buf = NULL; + pic->cuva_data_size = 0; + } + } +} + +static void release_cuva_data(struct avs2_frame_s *pic) +{ + if (pic == NULL) + return; + if (pic->cuva_data_buf) { + vfree(pic->cuva_data_buf); + } + pic->cuva_data_buf = NULL; + pic->cuva_data_size = 0; +} + +static void avs2_config_work_space_hw(struct AVS2Decoder_s *dec) +{ + struct BuffInfo_s *buf_spec = dec->work_space_buf; +#ifdef LOSLESS_COMPRESS_MODE + int losless_comp_header_size = + compute_losless_comp_header_size( + dec, dec->init_pic_w, + dec->init_pic_h); + int losless_comp_body_size = + compute_losless_comp_body_size(dec, + dec->init_pic_w, + dec->init_pic_h, buf_alloc_depth == 10); +#endif +#ifdef AVS2_10B_MMU + unsigned int data32; +#endif + if (debug && dec->init_flag == 0) + avs2_print(dec, 0, + "%s %x %x %x %x %x %x %x %x %x %x %x %x %x\n", + __func__, + buf_spec->ipp.buf_start, + buf_spec->start_adr, + buf_spec->short_term_rps.buf_start, + buf_spec->rcs.buf_start, + buf_spec->sps.buf_start, + buf_spec->pps.buf_start, + buf_spec->sao_up.buf_start, + buf_spec->swap_buf.buf_start, + buf_spec->swap_buf2.buf_start, + buf_spec->scalelut.buf_start, + buf_spec->dblk_para.buf_start, + buf_spec->dblk_data.buf_start, + buf_spec->dblk_data2.buf_start); + WRITE_VREG(HEVCD_IPP_LINEBUFF_BASE, buf_spec->ipp.buf_start); + if ((debug & AVS2_DBG_SEND_PARAM_WITH_REG) == 0) + WRITE_VREG(HEVC_RPM_BUFFER, (u32)dec->rpm_phy_addr); + WRITE_VREG(AVS2_ALF_SWAP_BUFFER, buf_spec->short_term_rps.buf_start); + WRITE_VREG(HEVC_RCS_BUFFER, buf_spec->rcs.buf_start); + WRITE_VREG(HEVC_SPS_BUFFER, buf_spec->sps.buf_start); + WRITE_VREG(HEVC_PPS_BUFFER, buf_spec->pps.buf_start); + //WRITE_VREG(HEVC_SAO_UP, buf_spec->sao_up.buf_start); +#ifdef AVS2_10B_MMU + WRITE_VREG(AVS2_MMU_MAP_BUFFER, dec->frame_mmu_map_phy_addr); +#else + WRITE_VREG(HEVC_STREAM_SWAP_BUFFER, buf_spec->swap_buf.buf_start); +#endif + WRITE_VREG(HEVC_STREAM_SWAP_BUFFER2, buf_spec->swap_buf2.buf_start); + //WRITE_VREG(HEVC_SCALELUT, buf_spec->scalelut.buf_start); + + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) { + if (buf_spec->max_width <= 4096 && buf_spec->max_height <= 2304) + WRITE_VREG(HEVC_DBLK_CFG3, 0x404010); //default value + else + WRITE_VREG(HEVC_DBLK_CFG3, 0x808020); // make left storage 2 x 4k] + avs2_print(dec, AVS2_DBG_BUFMGR, + "HEVC_DBLK_CFG3 = %x\n", READ_VREG(HEVC_DBLK_CFG3)); + } + + /* cfg_p_addr */ + WRITE_VREG(HEVC_DBLK_CFG4, buf_spec->dblk_para.buf_start); + /* cfg_d_addr */ + WRITE_VREG(HEVC_DBLK_CFG5, buf_spec->dblk_data.buf_start); + + WRITE_VREG(HEVC_DBLK_CFGE, buf_spec->dblk_data2.buf_start); + +#ifdef LOSLESS_COMPRESS_MODE + data32 = READ_VREG(HEVC_SAO_CTRL5); +#if 1 + data32 &= ~(1<<9); +#else + if (params->p.bit_depth != 0x00) + data32 &= ~(1<<9); + else + data32 |= (1<<9); +#endif + WRITE_VREG(HEVC_SAO_CTRL5, data32); +#ifdef AVS2_10B_MMU + /*bit[4] : paged_mem_mode*/ + WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0x1 << 4)); + WRITE_VREG(HEVCD_MPP_DECOMP_CTL2, 0); +#else + /* bit[3] smem mode*/ + WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0<<3)); + + WRITE_VREG(HEVCD_MPP_DECOMP_CTL2, (losless_comp_body_size >> 5)); +#endif + /*WRITE_VREG(HEVCD_MPP_DECOMP_CTL2,(losless_comp_body_size >> 5));*/ + /*WRITE_VREG(HEVCD_MPP_DECOMP_CTL3,(0xff<<20) | (0xff<<10) | 0xff);*/ +/*8-bit mode */ + WRITE_VREG(HEVC_CM_BODY_LENGTH, losless_comp_body_size); + WRITE_VREG(HEVC_CM_HEADER_OFFSET, losless_comp_body_size); + WRITE_VREG(HEVC_CM_HEADER_LENGTH, losless_comp_header_size); +#else + WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31); +#endif + +#ifdef AVS2_10B_MMU + WRITE_VREG(HEVC_SAO_MMU_VH0_ADDR, buf_spec->mmu_vbh.buf_start); + WRITE_VREG(HEVC_SAO_MMU_VH1_ADDR, buf_spec->mmu_vbh.buf_start + + VBH_BUF_SIZE(buf_spec)); + /*data32 = READ_VREG(HEVC_SAO_CTRL9);*/ + /*data32 |= 0x1;*/ + /*WRITE_VREG(HEVC_SAO_CTRL9, data32);*/ + + /* use HEVC_CM_HEADER_START_ADDR */ + data32 = READ_VREG(HEVC_SAO_CTRL5); + data32 |= (1<<10); +#if 1 + if (debug & AVS2_DBG_FORCE_UNCOMPRESS) + data32 |= 0x80; +#endif + WRITE_VREG(HEVC_SAO_CTRL5, data32); + +#endif + + WRITE_VREG(LMEM_DUMP_ADR, (u32)dec->lmem_phy_addr); +#if 1 +/*MULTI_INSTANCE_SUPPORT*/ + /*new added in simulation???*/ + WRITE_VREG(HEVC_MPRED_ABV_START_ADDR, buf_spec->mpred_above.buf_start); +#endif +#ifdef CO_MV_COMPRESS + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_T7) { + data32 = READ_VREG(HEVC_MPRED_CTRL4); + data32 |= (1 << 1); + WRITE_VREG(HEVC_MPRED_CTRL4, data32); + } +#endif +} + +static void decomp_perfcount_reset(void) +{ + if (debug & AVS2_DBG_CACHE) + pr_info("[cache_util.c] Entered decomp_perfcount_reset...\n"); + WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)0x1); + WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)0x0); + return; +} + +static void mcrcc_perfcount_reset(void) +{ + if (debug & AVS2_DBG_CACHE) + pr_info("[cache_util.c] Entered mcrcc_perfcount_reset...\n"); + WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)0x1); + WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)0x0); + return; +} + +static void avs2_init_decoder_hw(struct AVS2Decoder_s *dec) +{ + unsigned int data32; + unsigned int decode_mode; + int i; + + /*if (debug & AVS2_DBG_BUFMGR_MORE) + pr_info("%s\n", __func__);*/ + data32 = READ_VREG(HEVC_PARSER_INT_CONTROL); +#if 1 + /* set bit 31~29 to 3 if HEVC_STREAM_FIFO_CTL[29] is 1 */ + data32 &= ~(7 << 29); + data32 |= (3 << 29); +#endif + data32 = data32 | + (1 << 24) |/*stream_buffer_empty_int_amrisc_enable*/ + (1 << 22) |/*stream_fifo_empty_int_amrisc_enable*/ + (1 << 7) |/*dec_done_int_cpu_enable*/ + (1 << 4) |/*startcode_found_int_cpu_enable*/ + (0 << 3) |/*startcode_found_int_amrisc_enable*/ + (1 << 0) /*parser_int_enable*/ + ; + WRITE_VREG(HEVC_PARSER_INT_CONTROL, data32); + + data32 = READ_VREG(HEVC_SHIFT_STATUS); + data32 = data32 | + (0 << 1) |/*emulation_check_off VP9 + do not have emulation*/ + (1 << 0)/*startcode_check_on*/ + ; + WRITE_VREG(HEVC_SHIFT_STATUS, data32); + WRITE_VREG(HEVC_SHIFT_CONTROL, + (6 << 20) | /* emu_push_bits (6-bits for AVS2)*/ + (0 << 19) | /* emu_3_enable, maybe turned on in microcode*/ + (0 << 18) | /* emu_2_enable, maybe turned on in microcode*/ + (0 << 17) | /* emu_1_enable, maybe turned on in microcode*/ + (0 << 16) | /* emu_0_enable, maybe turned on in microcode*/ + (0 << 14) | /*disable_start_code_protect*/ + (3 << 6) | /* sft_valid_wr_position*/ + (2 << 4) | /* emulate_code_length_sub_1*/ + (2 << 1) | /* start_code_length_sub_1*/ + (1 << 0) /* stream_shift_enable*/ + ); + + WRITE_VREG(HEVC_SHIFT_LENGTH_PROTECT, + (0 << 30) | /*data_protect_fill_00_enable*/ + (1 << 29) /*data_protect_fill_ff_enable*/ + ); + WRITE_VREG(HEVC_CABAC_CONTROL, + (1 << 0)/*cabac_enable*/ + ); + + WRITE_VREG(HEVC_PARSER_CORE_CONTROL, + (1 << 0)/* hevc_parser_core_clk_en*/ + ); + + + WRITE_VREG(HEVC_DEC_STATUS_REG, 0); + + /*Initial IQIT_SCALELUT memory -- just to avoid X in simulation*/ + if (is_rdma_enable()) + rdma_back_end_work(dec->rdma_phy_adr, RDMA_SIZE); + else { + WRITE_VREG(HEVC_IQIT_SCALELUT_WR_ADDR, 0);/*cfg_p_addr*/ + for (i = 0; i < 1024; i++) + WRITE_VREG(HEVC_IQIT_SCALELUT_DATA, 0); + } + +#ifdef ENABLE_SWAP_TEST + WRITE_VREG(HEVC_STREAM_SWAP_TEST, 100); +#else + WRITE_VREG(HEVC_STREAM_SWAP_TEST, 0); +#endif + if (!dec->m_ins_flag) + decode_mode = DECODE_MODE_SINGLE; + else if (vdec_frame_based(hw_to_vdec(dec))) + decode_mode = DECODE_MODE_MULTI_FRAMEBASE; + else + decode_mode = DECODE_MODE_MULTI_STREAMBASE; + if (dec->avs2_dec.bufmgr_error_flag && + (error_handle_policy & 0x1)) { + dec->bufmgr_error_count++; + dec->avs2_dec.bufmgr_error_flag = 0; + if (dec->bufmgr_error_count > + (re_search_seq_threshold & 0xff) + && dec->frame_count > + ((re_search_seq_threshold >> 8) & 0xff)) { + struct avs2_decoder *avs2_dec = &dec->avs2_dec; + dec->start_decoding_flag = 0; + avs2_dec->hd.vec_flag = 1; + dec->skip_PB_before_I = 1; + avs2_print(dec, 0, + "!!Bufmgr error, search seq again (0x%x %d %d)\n", + error_handle_policy, + dec->frame_count, + dec->bufmgr_error_count); + dec->bufmgr_error_count = 0; + } + } + decode_mode |= (dec->start_decoding_flag << 16); + + WRITE_VREG(DECODE_MODE, decode_mode); + WRITE_VREG(HEVC_DECODE_SIZE, 0); + WRITE_VREG(HEVC_DECODE_COUNT, 0); + + /*Send parser_cmd*/ + WRITE_VREG(HEVC_PARSER_CMD_WRITE, (1 << 16) | (0 << 0)); + for (i = 0; i < PARSER_CMD_NUMBER; i++) + WRITE_VREG(HEVC_PARSER_CMD_WRITE, parser_cmd[i]); + WRITE_VREG(HEVC_PARSER_CMD_SKIP_0, PARSER_CMD_SKIP_CFG_0); + WRITE_VREG(HEVC_PARSER_CMD_SKIP_1, PARSER_CMD_SKIP_CFG_1); + WRITE_VREG(HEVC_PARSER_CMD_SKIP_2, PARSER_CMD_SKIP_CFG_2); + + + WRITE_VREG(HEVC_PARSER_IF_CONTROL, + (1 << 9) | /* parser_alf_if_en*/ + /* (1 << 8) |*/ /*sao_sw_pred_enable*/ + (1 << 5) | /*parser_sao_if_en*/ + (1 << 2) | /*parser_mpred_if_en*/ + (1 << 0) /*parser_scaler_if_en*/ + ); + +#ifdef MULTI_INSTANCE_SUPPORT + WRITE_VREG(HEVC_MPRED_INT_STATUS, (1<<31)); + + WRITE_VREG(HEVC_PARSER_RESULT_3, 0xffffffff); + + for (i = 0; i < 8; i++) + data32 = READ_VREG(HEVC_MPRED_ABV_START_ADDR); + + WRITE_VREG(DOS_SW_RESET3, (1<<18)); /* reset mpred */ + WRITE_VREG(DOS_SW_RESET3, 0); + WRITE_VREG(HEVC_MPRED_ABV_START_ADDR, data32); + WRITE_VREG(HEVC_MPRED_ABV_START_ADDR, data32); + WRITE_VREG(HEVC_MPRED_ABV_START_ADDR, data32); +#endif + /*End of Multi-instance*/ + /*Changed to Start MPRED in microcode*/ + /* + pr_info("[test.c] Start MPRED\n"); + WRITE_VREG(HEVC_MPRED_INT_STATUS, + (1<<31) + ); + */ + + /*AVS2 default seq_wq_matrix config*/ + + avs2_print(dec, AVS2_DBG_BUFMGR_MORE, + "Config AVS2 default seq_wq_matrix ...\n"); + /*4x4*/ + /* default seq_wq_matrix_4x4 begin address*/ + WRITE_VREG(HEVC_IQIT_SCALELUT_WR_ADDR, 64); + for (i = 0; i < 16; i++) + WRITE_VREG(HEVC_IQIT_SCALELUT_DATA, g_WqMDefault4x4[i]); + + /*8x8*/ + /*default seq_wq_matrix_8x8 begin address*/ + WRITE_VREG(HEVC_IQIT_SCALELUT_WR_ADDR, 0); + for (i = 0; i < 64; i++) + WRITE_VREG(HEVC_IQIT_SCALELUT_DATA, g_WqMDefault8x8[i]); + + + WRITE_VREG(HEVCD_IPP_TOP_CNTL, + (0 << 1) | /*enable ipp*/ + (1 << 0) /*software reset ipp and mpp*/ + ); + WRITE_VREG(HEVCD_IPP_TOP_CNTL, + (1 << 1) | /*enable ipp*/ + (0 << 0) /*software reset ipp and mpp*/ + ); +#if 0 +/*AVS2_10B_NV21*/ + /*Enable NV21 reference read mode for MC*/ + WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31); +#endif + /* Init dblk*/ + data32 = READ_VREG(HEVC_DBLK_CFGB); + data32 |= (2 << 0); + /* [3:0] cfg_video_type -> AVS2*/ + + data32 &= (~0x300); /*[8]:first write enable (compress) + [9]:double write enable (uncompress)*/ + if (get_double_write_mode(dec) == 0) + data32 |= (0x1 << 8); /*enable first write*/ + else if (get_double_write_mode(dec) == 0x10) + data32 |= (0x1 << 9); /*double write only*/ + else + data32 |= ((0x1 << 8) | (0x1 << 9)); + WRITE_VREG(HEVC_DBLK_CFGB, data32); + + WRITE_VREG(HEVC_DBLK_CFG0, (1 << 0)); /* [0] rst_sync*/ + avs2_print(dec, AVS2_DBG_BUFMGR_MORE, + "Bitstream level Init for DBLK .Done.\n"); + + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) { + mcrcc_perfcount_reset(); + decomp_perfcount_reset(); + } + + return; +} + + +#ifdef CONFIG_HEVC_CLK_FORCED_ON +static void config_avs2_clk_forced_on(void) +{ + unsigned int rdata32; + /*IQIT*/ + rdata32 = READ_VREG(HEVC_IQIT_CLK_RST_CTRL); + WRITE_VREG(HEVC_IQIT_CLK_RST_CTRL, rdata32 | (0x1 << 2)); + + /* DBLK*/ + rdata32 = READ_VREG(HEVC_DBLK_CFG0); + WRITE_VREG(HEVC_DBLK_CFG0, rdata32 | (0x1 << 2)); + + /* SAO*/ + rdata32 = READ_VREG(HEVC_SAO_CTRL1); + WRITE_VREG(HEVC_SAO_CTRL1, rdata32 | (0x1 << 2)); + + /*MPRED*/ + rdata32 = READ_VREG(HEVC_MPRED_CTRL1); + WRITE_VREG(HEVC_MPRED_CTRL1, rdata32 | (0x1 << 24)); + + /* PARSER*/ + rdata32 = READ_VREG(HEVC_STREAM_CONTROL); + WRITE_VREG(HEVC_STREAM_CONTROL, rdata32 | (0x1 << 15)); + rdata32 = READ_VREG(HEVC_SHIFT_CONTROL); + WRITE_VREG(HEVC_SHIFT_CONTROL, rdata32 | (0x1 << 15)); + rdata32 = READ_VREG(HEVC_CABAC_CONTROL); + WRITE_VREG(HEVC_CABAC_CONTROL, rdata32 | (0x1 << 13)); + rdata32 = READ_VREG(HEVC_PARSER_CORE_CONTROL); + WRITE_VREG(HEVC_PARSER_CORE_CONTROL, rdata32 | (0x1 << 15)); + rdata32 = READ_VREG(HEVC_PARSER_INT_CONTROL); + WRITE_VREG(HEVC_PARSER_INT_CONTROL, rdata32 | (0x1 << 15)); + rdata32 = READ_VREG(HEVC_PARSER_IF_CONTROL); + WRITE_VREG(HEVC_PARSER_IF_CONTROL, + rdata32 | (0x1 << 6) | (0x1 << 3) | (0x1 << 1)); + + /*IPP*/ + rdata32 = READ_VREG(HEVCD_IPP_DYNCLKGATE_CONFIG); + WRITE_VREG(HEVCD_IPP_DYNCLKGATE_CONFIG, rdata32 | 0xffffffff); + + /* MCRCC*/ + rdata32 = READ_VREG(HEVCD_MCRCC_CTL1); + WRITE_VREG(HEVCD_MCRCC_CTL1, rdata32 | (0x1 << 3)); +} +#endif + +static void avs2_local_uninit(struct AVS2Decoder_s *dec) +{ + dec->rpm_ptr = NULL; + dec->lmem_ptr = NULL; + if (dec->rpm_addr) { + dma_free_coherent(amports_get_dma_device(), + RPM_BUF_SIZE, dec->rpm_addr, + dec->rpm_phy_addr); + dec->rpm_addr = NULL; + } + + if (dec->cuva_addr) { + dma_free_coherent(amports_get_dma_device(), + dec->cuva_size, dec->cuva_addr, + dec->cuva_phy_addr); + dec->cuva_addr = NULL; + } + + if (dec->lmem_addr) { + if (dec->lmem_phy_addr) + dma_free_coherent(amports_get_dma_device(), + LMEM_BUF_SIZE, dec->lmem_addr, + dec->lmem_phy_addr); + dec->lmem_addr = NULL; + } + +#ifdef AVS2_10B_MMU + if (dec->frame_mmu_map_addr) { + if (dec->frame_mmu_map_phy_addr) + dma_free_coherent(amports_get_dma_device(), + get_frame_mmu_map_size(dec), dec->frame_mmu_map_addr, + dec->frame_mmu_map_phy_addr); + dec->frame_mmu_map_addr = NULL; + } +#endif + if (dec->gvs) + vfree(dec->gvs); + dec->gvs = NULL; +} + +static int avs2_local_init(struct AVS2Decoder_s *dec) +{ + int ret = -1; + /*int losless_comp_header_size, losless_comp_body_size;*/ + + struct BuffInfo_s *cur_buf_info = NULL; + + cur_buf_info = &dec->work_space_buf_store; + if (force_bufspec) { + memcpy(cur_buf_info, &amvavs2_workbuff_spec[force_bufspec & 0xf], + sizeof(struct BuffInfo_s)); + pr_info("force buffer spec %d\n", force_bufspec & 0xf); + } else { + if (get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_TM2 && !is_cpu_tm2_revb()) { + if (vdec_is_support_4k()) { + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) + memcpy(cur_buf_info, &amvavs2_workbuff_spec[2], /* 8k */ + sizeof(struct BuffInfo_s)); + else + memcpy(cur_buf_info, &amvavs2_workbuff_spec[1], /* 4k */ + sizeof(struct BuffInfo_s)); + } else + memcpy(cur_buf_info, &amvavs2_workbuff_spec[0],/* 1080p */ + sizeof(struct BuffInfo_s)); + } else { //get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_TM2 || is_cpu_tm2_revb() + if (vdec_is_support_4k()) { + memcpy(cur_buf_info, &amvavs2_workbuff_spec[5], /* 8k */ + sizeof(struct BuffInfo_s)); + } else + memcpy(cur_buf_info, &amvavs2_workbuff_spec[3],/* 1080p */ + sizeof(struct BuffInfo_s)); + } + } + + cur_buf_info->start_adr = dec->buf_start; +#ifndef AVS2_10B_MMU + dec->mc_buf_spec.buf_end = dec->buf_start + dec->buf_size; +#endif + + init_buff_spec(dec, cur_buf_info); + + init_avs2_decoder(&dec->avs2_dec); + +#ifdef AVS2_10B_MMU + avs2_bufmgr_init(dec, cur_buf_info, NULL); +#else + dec->mc_buf_spec.buf_start = (cur_buf_info->end_adr + 0xffff) + & (~0xffff); + dec->mc_buf_spec.buf_size = (dec->mc_buf_spec.buf_end + - dec->mc_buf_spec.buf_start); + if (debug) { + pr_err("dec->mc_buf_spec.buf_start %x-%x\n", + dec->mc_buf_spec.buf_start, + dec->mc_buf_spec.buf_start + + dec->mc_buf_spec.buf_size); + } + avs2_bufmgr_init(dec, cur_buf_info, &dec->mc_buf_spec); +#endif + + if (!vdec_is_support_4k() + && (buf_alloc_width > 1920 && buf_alloc_height > 1088)) { + buf_alloc_width = 1920; + buf_alloc_height = 1088; + } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) { + buf_alloc_width = 8192; + buf_alloc_height = 4608; + } + dec->init_pic_w = buf_alloc_width ? buf_alloc_width : + (dec->vavs2_amstream_dec_info.width ? + dec->vavs2_amstream_dec_info.width : + dec->work_space_buf->max_width); + dec->init_pic_h = buf_alloc_height ? buf_alloc_height : + (dec->vavs2_amstream_dec_info.height ? + dec->vavs2_amstream_dec_info.height : + dec->work_space_buf->max_height); +#if 0 +/*ndef MV_USE_FIXED_BUF*/ + if (init_mv_buf_list(dec) < 0) { + pr_err("%s: init_mv_buf_list fail\n", __func__); + return -1; + } +#endif + +#ifndef AVS2_10B_MMU + init_buf_list(dec); +#else + dec->used_buf_num = max_buf_num + dec->dynamic_buf_margin; + if (dec->used_buf_num > MAX_BUF_NUM) + dec->used_buf_num = MAX_BUF_NUM; + if (dec->used_buf_num > FRAME_BUFFERS) + dec->used_buf_num = FRAME_BUFFERS; +#endif + dec->avs2_dec.ref_maxbuffer = dec->used_buf_num - 1; + /*init_pic_list(dec);*/ + + pts_unstable = ((unsigned long)(dec->vavs2_amstream_dec_info.param) + & 0x40) >> 6; + + if ((debug & AVS2_DBG_SEND_PARAM_WITH_REG) == 0) { + dec->rpm_addr = dma_alloc_coherent(amports_get_dma_device(), + RPM_BUF_SIZE, + &dec->rpm_phy_addr, GFP_KERNEL); + if (dec->rpm_addr == NULL) { + pr_err("%s: failed to alloc rpm buffer\n", __func__); + return -1; + } + avs2_print(dec, AVS2_DBG_BUFMGR, + "rpm_phy_addr %x\n", (u32) dec->rpm_phy_addr); + dec->rpm_ptr = dec->rpm_addr; + } + + if (cuva_buf_size > 0) { + dec->cuva_size = AUX_BUF_ALIGN(cuva_buf_size); + + dec->cuva_addr = dma_alloc_coherent(amports_get_dma_device(), + dec->cuva_size, &dec->cuva_phy_addr, GFP_KERNEL); + avs2_print(dec, AVS2_DBG_BUFMGR, + "%s, cuva_size = %d cuva_phy_addr %x dec->cuva_addr = %px\n", + __func__, dec->cuva_size, (u32)dec->cuva_phy_addr, dec->cuva_addr); + if (dec->cuva_addr == NULL) { + pr_err("%s: failed to alloc cuva buffer\n", __func__); + return -1; + } + } + + dec->lmem_addr = dma_alloc_coherent(amports_get_dma_device(), + LMEM_BUF_SIZE, + &dec->lmem_phy_addr, GFP_KERNEL); + if (dec->lmem_addr == NULL) { + pr_err("%s: failed to alloc lmem buffer\n", __func__); + return -1; + } else + avs2_print(dec, AVS2_DBG_BUFMGR, + "%s, lmem_phy_addr %x\n", + __func__, (u32)dec->lmem_phy_addr); +/* + dec->lmem_phy_addr = dma_map_single(amports_get_dma_device(), + dec->lmem_addr, LMEM_BUF_SIZE, DMA_BIDIRECTIONAL); + if (dma_mapping_error(amports_get_dma_device(), + dec->lmem_phy_addr)) { + pr_err("%s: failed to map lmem buffer\n", __func__); + kfree(dec->lmem_addr); + dec->lmem_addr = NULL; + return -1; + } +*/ + dec->lmem_ptr = dec->lmem_addr; + + +#ifdef AVS2_10B_MMU + dec->frame_mmu_map_addr = dma_alloc_coherent(amports_get_dma_device(), + get_frame_mmu_map_size(dec), + &dec->frame_mmu_map_phy_addr, GFP_KERNEL); + if (dec->frame_mmu_map_addr == NULL) { + pr_err("%s: failed to alloc count_buffer\n", __func__); + return -1; + } + memset(dec->frame_mmu_map_addr, 0, get_frame_mmu_map_size(dec)); +/* dec->frame_mmu_map_phy_addr = dma_map_single(amports_get_dma_device(), + dec->frame_mmu_map_addr, FRAME_MMU_MAP_SIZE, DMA_BIDIRECTIONAL); + if (dma_mapping_error(amports_get_dma_device(), + dec->frame_mmu_map_phy_addr)) { + pr_err("%s: failed to map count_buffer\n", __func__); + kfree(dec->frame_mmu_map_addr); + dec->frame_mmu_map_addr = NULL; + return -1; + }*/ +#endif + + ret = 0; + return ret; +} + +/******************************************** + * Mailbox command + ********************************************/ +#define CMD_FINISHED 0 +#define CMD_ALLOC_VIEW 1 +#define CMD_FRAME_DISPLAY 3 +#define CMD_DEBUG 10 + + +#define DECODE_BUFFER_NUM_MAX 32 +#define DISPLAY_BUFFER_NUM 6 + +#define video_domain_addr(adr) (adr&0x7fffffff) +#define DECODER_WORK_SPACE_SIZE 0x800000 + +#define spec2canvas(x) \ + (((x)->uv_canvas_index << 16) | \ + ((x)->uv_canvas_index << 8) | \ + ((x)->y_canvas_index << 0)) + + +static void set_canvas(struct AVS2Decoder_s *dec, + struct avs2_frame_s *pic) +{ + int canvas_w = ALIGN(pic->pic_w, 64)/4; + int canvas_h = ALIGN(pic->pic_h, 32)/4; + int blkmode = mem_map_mode; + struct vdec_s *vdec = hw_to_vdec(dec); + /*CANVAS_BLKMODE_64X32*/ + if (pic->double_write_mode) { + canvas_w = pic->pic_w / + get_double_write_ratio(pic->double_write_mode); + canvas_h = pic->pic_h / + get_double_write_ratio(pic->double_write_mode); + /*sao_crtl1 aligned with 64*/ + canvas_w = ALIGN(canvas_w, 64); + canvas_h = ALIGN(canvas_h, 32); + + if (vdec->parallel_dec == 1) { + if (pic->y_canvas_index == -1) + pic->y_canvas_index = vdec->get_canvas_ex(CORE_MASK_HEVC, vdec->id); + if (pic->uv_canvas_index == -1) + pic->uv_canvas_index = vdec->get_canvas_ex(CORE_MASK_HEVC, vdec->id); + } else { + pic->y_canvas_index = 128 + pic->index * 2; + pic->uv_canvas_index = 128 + pic->index * 2 + 1; + } + + config_cav_lut_ex(pic->y_canvas_index, + pic->dw_y_adr, canvas_w, canvas_h, + CANVAS_ADDR_NOWRAP, blkmode, 0x7, VDEC_HEVC); + config_cav_lut_ex(pic->uv_canvas_index, + pic->dw_u_v_adr, canvas_w, canvas_h, + CANVAS_ADDR_NOWRAP, blkmode, 0x7, VDEC_HEVC); +#ifdef MULTI_INSTANCE_SUPPORT + pic->canvas_config[0].phy_addr = + pic->dw_y_adr; + pic->canvas_config[0].width = + canvas_w; + pic->canvas_config[0].height = + canvas_h; + pic->canvas_config[0].block_mode = + blkmode; + pic->canvas_config[0].endian = 7; + + pic->canvas_config[1].phy_addr = + pic->dw_u_v_adr; + pic->canvas_config[1].width = + canvas_w; + pic->canvas_config[1].height = + canvas_h; + pic->canvas_config[1].block_mode = + blkmode; + pic->canvas_config[1].endian = 7; +#endif + } else { + #ifndef AVS2_10B_MMU + if (vdec->parallel_dec == 1) { + if (pic->y_canvas_index == -1) + pic->y_canvas_index = vdec->get_canvas_ex(CORE_MASK_HEVC, vdec->id); + if (pic->uv_canvas_index == -1) + pic->uv_canvas_index = vdec->get_canvas_ex(CORE_MASK_HEVC, vdec->id); + } else { + pic->y_canvas_index = 128 + pic->index; + pic->uv_canvas_index = 128 + pic->index; + } + + config_cav_lut_ex(pic->y_canvas_index, + pic->mc_y_adr, canvas_w, canvas_h, + CANVAS_ADDR_NOWRAP, blkmode, 0x7, VDEC_HEVC); + config_cav_lut_ex(pic->uv_canvas_index, + pic->mc_u_v_adr, canvas_w, canvas_h, + CANVAS_ADDR_NOWRAP, blkmode, 0x7, VDEC_HEVC); + #endif + } +} + +static void set_frame_info(struct AVS2Decoder_s *dec, struct vframe_s *vf) +{ + unsigned int ar; + + vf->duration = dec->frame_dur; + vf->duration_pulldown = 0; + vf->flag = 0; + vf->prop.master_display_colour = dec->vf_dp; + if (dec->hdr_flag & HDR_CUVA_MASK) + dec->video_signal_type |= 1 << 31; + vf->signal_type = dec->video_signal_type; + + avs2_print(dec, AVS2_DBG_HDR_INFO, + "signal_typesignal_type 0x%x \n", + vf->signal_type); + + ar = min_t(u32, dec->frame_ar, DISP_RATIO_ASPECT_RATIO_MAX); + vf->ratio_control = (ar << DISP_RATIO_ASPECT_RATIO_BIT); + + vf->sidebind_type = dec->sidebind_type; + vf->sidebind_channel_id = dec->sidebind_channel_id; + + return; +} + +static int vavs2_vf_states(struct vframe_states *states, void *op_arg) +{ + struct AVS2Decoder_s *dec = (struct AVS2Decoder_s *)op_arg; + + states->vf_pool_size = VF_POOL_SIZE; + states->buf_free_num = kfifo_len(&dec->newframe_q); + states->buf_avail_num = kfifo_len(&dec->display_q); + + if (step == 2) + states->buf_avail_num = 0; + return 0; +} + +static struct vframe_s *vavs2_vf_peek(void *op_arg) +{ + struct vframe_s *vf; + struct AVS2Decoder_s *dec = (struct AVS2Decoder_s *)op_arg; + if (step == 2) + return NULL; + + if (force_disp_pic_index & 0x100) { + if (force_disp_pic_index & 0x200) + return NULL; + return &dec->vframe_dummy; + } + + if (kfifo_peek(&dec->display_q, &vf)) + return vf; + + return NULL; +} + +static struct avs2_frame_s *get_pic_by_index( + struct AVS2Decoder_s *dec, int index) +{ + int i; + struct avs2_frame_s *pic = NULL; + if (index == (dec->used_buf_num - 1)) + pic = dec->avs2_dec.m_bg; + else if (index >= 0 && index < dec->used_buf_num) { + for (i = 0; i < dec->used_buf_num; i++) { + if (dec->avs2_dec.fref[i]->index == index) + pic = dec->avs2_dec.fref[i]; + } + } + return pic; +} + +static struct vframe_s *vavs2_vf_get(void *op_arg) +{ + struct vframe_s *vf; + struct AVS2Decoder_s *dec = (struct AVS2Decoder_s *)op_arg; + if (step == 2) + return NULL; + else if (step == 1) + step = 2; + + if (force_disp_pic_index & 0x100) { + int idx = force_disp_pic_index & 0xff; + struct avs2_frame_s *pic = NULL; + if (idx >= 0 + && idx < dec->avs2_dec.ref_maxbuffer) + pic = get_pic_by_index(dec, idx); + if (pic == NULL) + return NULL; + if (force_disp_pic_index & 0x200) + return NULL; + + vf = &dec->vframe_dummy; + + set_vframe(dec, vf, pic, 1); + + force_disp_pic_index |= 0x200; + return vf; + } + + if (kfifo_get(&dec->display_q, &vf)) { + uint8_t index = vf->index & 0xff; + ATRACE_COUNTER(dec->disp_q_name, kfifo_len(&dec->display_q)); + if (index < dec->used_buf_num) { + struct avs2_frame_s *pic = get_pic_by_index(dec, index); + if (pic == NULL && + (debug & AVS2_DBG_PIC_LEAK)) { + int i; + avs2_print(dec, 0, + "%s error index 0x%x pic not exist\n", + __func__, index); + dump_pic_list(dec); + for (i = 0; i < 10; i++) { + pic = get_pic_by_index(dec, index); + pr_info("pic = %p\n", pic); + } + + if (debug & AVS2_DBG_PIC_LEAK) + debug |= AVS2_DBG_PIC_LEAK_WAIT; + return NULL; + } + vf->index_disp = atomic_read(&dec->vf_get_count); + atomic_add(1, &dec->vf_get_count); + if (pic) + avs2_print(dec, AVS2_DBG_BUFMGR, + "%s index 0x%x pos %d getcount %d type 0x%x w/h %d/%d, pts %d, %lld\n", + __func__, index, + pic->imgtr_fwRefDistance_bak, + dec->vf_get_count, + vf->type, + vf->width, vf->height, + vf->pts, + vf->pts_us64); + return vf; + } + } + return NULL; +} + +static void vavs2_vf_put(struct vframe_s *vf, void *op_arg) +{ + struct AVS2Decoder_s *dec = (struct AVS2Decoder_s *)op_arg; + uint8_t index; + + if (vf == (&dec->vframe_dummy)) + return; + + if (!vf) + return; + + index = vf->index & 0xff; + + kfifo_put(&dec->newframe_q, (const struct vframe_s *)vf); + ATRACE_COUNTER(dec->new_q_name, kfifo_len(&dec->newframe_q)); + atomic_add(1, &dec->vf_put_count); + avs2_print(dec, AVS2_DBG_BUFMGR, + "%s index putcount 0x%x %d\n", + __func__, vf->index, + dec->vf_put_count); + + if (index < dec->used_buf_num) { + unsigned long flags; + struct avs2_frame_s *pic; + + lock_buffer(dec, flags); + pic = get_pic_by_index(dec, index); + if (pic && pic->vf_ref > 0) + pic->vf_ref--; + else { + if (pic) + avs2_print(dec, 0, + "%s, error pic (index %d) vf_ref is %d\n", + __func__, index, pic->vf_ref); + else + avs2_print(dec, 0, + "%s, error pic (index %d) is NULL\n", + __func__, index); + } + if (dec->wait_buf) + WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG, + 0x1); + dec->last_put_idx = index; + dec->new_frame_displayed++; + unlock_buffer(dec, flags); + } + +} + +static int vavs2_event_cb(int type, void *data, void *private_data) +{ + struct AVS2Decoder_s *dec = (struct AVS2Decoder_s *)private_data; + + if (type & VFRAME_EVENT_RECEIVER_REQ_STATE) { + struct provider_state_req_s *req = + (struct provider_state_req_s *)data; + if (req->req_type == REQ_STATE_SECURE) + req->req_result[0] = vdec_secure(hw_to_vdec(dec)); + else + req->req_result[0] = 0xffffffff; + } else if (type & VFRAME_EVENT_RECEIVER_GET_AUX_DATA) { + struct provider_aux_req_s *req = + (struct provider_aux_req_s *)data; + unsigned char index; + unsigned long flags; + struct avs2_frame_s *pic; + + if (!req->vf) { + req->aux_size = atomic_read(&dec->vf_put_count); + return 0; + } + lock_buffer(dec, flags); + index = req->vf->index & 0xff; + req->aux_buf = NULL; + req->aux_size = 0; + req->format = VFORMAT_AVS2; + if (index < dec->used_buf_num) { + pic = get_pic_by_index(dec, index); + req->aux_buf = pic->cuva_data_buf; + req->aux_size = pic->cuva_data_size; + } + unlock_buffer(dec, flags); + + avs2_print(dec, PRINT_FLAG_VDEC_STATUS, + "%s pic 0x%p index %d =>size %d\n", + __func__, pic, index, req->aux_size); + } + + return 0; +} + +static struct avs2_frame_s *get_disp_pic(struct AVS2Decoder_s *dec) +{ + struct avs2_decoder *avs2_dec = &dec->avs2_dec; + struct avs2_frame_s *pic = NULL; + int32_t j; + int32_t pre_disp_count_min = 0x7fffffff; + for (j = 0; j < avs2_dec->ref_maxbuffer; j++) { + if (avs2_dec->fref[j]->to_prepare_disp && + avs2_dec->fref[j]->to_prepare_disp < + pre_disp_count_min) { + pre_disp_count_min = + avs2_dec->fref[j]->to_prepare_disp; + pic = avs2_dec->fref[j]; + } + } + if (pic) + pic->to_prepare_disp = 0; + + return pic; + +} + + + +static void fill_frame_info(struct AVS2Decoder_s *dec, + struct avs2_frame_s *pic, unsigned int framesize, unsigned int pts) +{ + struct vframe_qos_s *vframe_qos = &dec->vframe_qos; + + if (pic->slice_type == I_IMG) + vframe_qos->type = 1; + else if (pic->slice_type == P_IMG) + vframe_qos->type = 2; + else if (pic->slice_type == B_IMG) + vframe_qos->type = 3; +/* +#define SHOW_QOS_INFO +*/ + if (input_frame_based(hw_to_vdec(dec))) + vframe_qos->size = pic->frame_size; + else + vframe_qos->size = framesize; + vframe_qos->pts = pts; +#ifdef SHOW_QOS_INFO + avs2_print(dec, 0, "slice:%d\n", pic->slice_type); +#endif + + + vframe_qos->max_mv = pic->max_mv; + vframe_qos->avg_mv = pic->avg_mv; + vframe_qos->min_mv = pic->min_mv; +#ifdef SHOW_QOS_INFO + avs2_print(dec, 0, "mv: max:%d, avg:%d, min:%d\n", + vframe_qos->max_mv, + vframe_qos->avg_mv, + vframe_qos->min_mv); +#endif + + vframe_qos->max_qp = pic->max_qp; + vframe_qos->avg_qp = pic->avg_qp; + vframe_qos->min_qp = pic->min_qp; +#ifdef SHOW_QOS_INFO + avs2_print(dec, 0, "qp: max:%d, avg:%d, min:%d\n", + vframe_qos->max_qp, + vframe_qos->avg_qp, + vframe_qos->min_qp); +#endif + + vframe_qos->max_skip = pic->max_skip; + vframe_qos->avg_skip = pic->avg_skip; + vframe_qos->min_skip = pic->min_skip; +#ifdef SHOW_QOS_INFO + avs2_print(dec, 0, "skip: max:%d, avg:%d, min:%d\n", + vframe_qos->max_skip, + vframe_qos->avg_skip, + vframe_qos->min_skip); +#endif + + vframe_qos->num++; + +} + +static void set_vframe(struct AVS2Decoder_s *dec, + struct vframe_s *vf, struct avs2_frame_s *pic, u8 dummy) +{ + unsigned long flags; + int stream_offset; + unsigned int frame_size = 0; + int pts_discontinue; + struct vdec_s *vdec = hw_to_vdec(dec); + stream_offset = pic->stream_offset; + avs2_print(dec, AVS2_DBG_BUFMGR, + "%s index = %d pos = %d\r\n", + __func__, pic->index, + pic->imgtr_fwRefDistance); + + if (pic->double_write_mode) + set_canvas(dec, pic); + + display_frame_count[dec->index]++; + + if (!dummy) { +#ifdef MULTI_INSTANCE_SUPPORT + if (vdec_frame_based(vdec)) { + vf->pts = pic->pts; + vf->pts_us64 = pic->pts64; + } else { +#endif + if ((vdec->vbuf.no_parser == 0) || (vdec->vbuf.use_ptsserv)) { + /* if (pts_lookup_offset(PTS_TYPE_VIDEO, + stream_offset, &vf->pts, 0) != 0) { */ + if (pts_lookup_offset_us64 + (PTS_TYPE_VIDEO, stream_offset, + &vf->pts, &frame_size, 0, + &vf->pts_us64) != 0) { +#ifdef DEBUG_PTS + dec->pts_missed++; +#endif + vf->pts = 0; + vf->pts_us64 = 0; + } + } + } +#ifdef DEBUG_PTS + else + dec->pts_hit++; +#endif + if (pts_unstable) + dec->pts_mode = PTS_NONE_REF_USE_DURATION; + + fill_frame_info(dec, pic, frame_size, vf->pts); + + if ((dec->pts_mode == PTS_NORMAL) && (vf->pts != 0) + && dec->get_frame_dur) { + int pts_diff = (int)vf->pts - dec->last_lookup_pts; + + if (pts_diff < 0) { + dec->pts_mode_switching_count++; + dec->pts_mode_recovery_count = 0; + + if (dec->pts_mode_switching_count >= + PTS_MODE_SWITCHING_THRESHOLD) { + dec->pts_mode = + PTS_NONE_REF_USE_DURATION; + pr_info + ("HEVC: switch to n_d mode.\n"); + } + + } else { + int p = PTS_MODE_SWITCHING_RECOVERY_THREASHOLD; + dec->pts_mode_recovery_count++; + if (dec->pts_mode_recovery_count > p) { + dec->pts_mode_switching_count = 0; + dec->pts_mode_recovery_count = 0; + } + } + } + + pts_discontinue = + (abs(dec->last_pts - vf->pts) >= + tsync_vpts_discontinuity_margin()); + + if (vf->pts != 0) + dec->last_lookup_pts = vf->pts; +#if 1 + if ((dec->pts_mode == PTS_NONE_REF_USE_DURATION) + && ((pic->slice_type != I_IMG) || (!pts_discontinue && + !first_pts_checkin_complete(PTS_TYPE_AUDIO)))) + vf->pts = dec->last_pts + DUR2PTS(dec->frame_dur); +#endif + dec->last_pts = vf->pts; + + if (vf->pts_us64 != 0) + dec->last_lookup_pts_us64 = vf->pts_us64; + +#if 1 + if ((dec->pts_mode == PTS_NONE_REF_USE_DURATION) + && ((pic->slice_type != I_IMG) || (!pts_discontinue && + !first_pts_checkin_complete(PTS_TYPE_AUDIO)))) { + vf->pts_us64 = + dec->last_pts_us64 + + (DUR2PTS(dec->frame_dur) * 100 / 9); + } +#endif + dec->last_pts_us64 = vf->pts_us64; + avs2_print(dec, AVS2_DBG_OUT_PTS, + "avs2 dec out pts: vf->pts=%d, vf->pts_us64 = %lld\n", + vf->pts, vf->pts_us64); + } + + vf->index = 0xff00 | pic->index; + + if (pic->double_write_mode & 0x10) { + /* double write only */ + vf->compBodyAddr = 0; + vf->compHeadAddr = 0; + } else { +#ifdef AVS2_10B_MMU + vf->compBodyAddr = 0; + vf->compHeadAddr = pic->header_adr; +#else + vf->compBodyAddr = pic->mc_y_adr; /*body adr*/ + vf->compHeadAddr = pic->mc_y_adr + + pic->comp_body_size; + /*head adr*/ +#endif + } + if (pic->double_write_mode) { + vf->type = VIDTYPE_PROGRESSIVE | + VIDTYPE_VIU_FIELD; + vf->type |= VIDTYPE_VIU_NV21; + if (pic->double_write_mode == 3) { + vf->type |= VIDTYPE_COMPRESS; +#ifdef AVS2_10B_MMU + vf->type |= VIDTYPE_SCATTER; +#endif + } +#ifdef MULTI_INSTANCE_SUPPORT + if (dec->m_ins_flag) { + vf->canvas0Addr = vf->canvas1Addr = -1; + vf->plane_num = 2; + vf->canvas0_config[0] = + pic->canvas_config[0]; + vf->canvas0_config[1] = + pic->canvas_config[1]; + + vf->canvas1_config[0] = + pic->canvas_config[0]; + vf->canvas1_config[1] = + pic->canvas_config[1]; + + } else +#endif + vf->canvas0Addr = vf->canvas1Addr = + spec2canvas(pic); + } else { + vf->canvas0Addr = vf->canvas1Addr = 0; + vf->type = VIDTYPE_COMPRESS | VIDTYPE_VIU_FIELD; +#ifdef AVS2_10B_MMU + vf->type |= VIDTYPE_SCATTER; +#endif + } + + switch (pic->bit_depth) { + case AVS2_BITS_8: + vf->bitdepth = BITDEPTH_Y8 | + BITDEPTH_U8 | BITDEPTH_V8; + break; + case AVS2_BITS_10: + case AVS2_BITS_12: + vf->bitdepth = BITDEPTH_Y10 | + BITDEPTH_U10 | BITDEPTH_V10; + break; + default: + vf->bitdepth = BITDEPTH_Y10 | + BITDEPTH_U10 | BITDEPTH_V10; + break; + } + if ((vf->type & VIDTYPE_COMPRESS) == 0) + vf->bitdepth = + BITDEPTH_Y8 | BITDEPTH_U8 | BITDEPTH_V8; + if (pic->bit_depth == AVS2_BITS_8) + vf->bitdepth |= BITDEPTH_SAVING_MODE; + + set_frame_info(dec, vf); + /* if((vf->width!=pic->width)| + (vf->height!=pic->height)) */ + /* pr_info("aaa: %d/%d, %d/%d\n", + vf->width,vf->height, pic->width, + pic->height); */ + vf->width = pic->pic_w / + get_double_write_ratio(pic->double_write_mode); + vf->height = pic->pic_h / + get_double_write_ratio(pic->double_write_mode); + if (force_w_h != 0) { + vf->width = (force_w_h >> 16) & 0xffff; + vf->height = force_w_h & 0xffff; + } + vf->compWidth = pic->pic_w; + vf->compHeight = pic->pic_h; + if (force_fps & 0x100) { + u32 rate = force_fps & 0xff; + if (rate) + vf->duration = 96000/rate; + else + vf->duration = 0; + } +#ifdef AVS2_10B_MMU + if (vf->type & VIDTYPE_SCATTER) { + vf->mem_handle = decoder_mmu_box_get_mem_handle( + dec->mmu_box, + pic->index); + vf->mem_head_handle = decoder_bmmu_box_get_mem_handle( + dec->bmmu_box, + HEADER_BUFFER_IDX(pic->index)); + } else { + vf->mem_handle = decoder_bmmu_box_get_mem_handle( + dec->bmmu_box, + VF_BUFFER_IDX(pic->index)); + vf->mem_head_handle = decoder_bmmu_box_get_mem_handle( + dec->bmmu_box, + HEADER_BUFFER_IDX(pic->index)); + } +#else + vf->mem_handle = decoder_bmmu_box_get_mem_handle( + dec->bmmu_box, + VF_BUFFER_IDX(pic->index)); +#endif + if (!vdec->vbuf.use_ptsserv && vdec_stream_based(vdec)) { + vf->pts_us64 = stream_offset; + vf->pts = 0; + } + if (!dummy) { + lock_buffer(dec, flags); + pic->vf_ref = 1; + unlock_buffer(dec, flags); + } + atomic_add(1, &dec->vf_pre_count); +} + +static inline void dec_update_gvs(struct AVS2Decoder_s *dec) +{ + if (dec->gvs->frame_height != dec->frame_height) { + dec->gvs->frame_width = dec->frame_width; + dec->gvs->frame_height = dec->frame_height; + } + if (dec->gvs->frame_dur != dec->frame_dur) { + dec->gvs->frame_dur = dec->frame_dur; + if (dec->frame_dur != 0) + dec->gvs->frame_rate = ((96000 * 10 / dec->frame_dur) % 10) < 5 ? + 96000 / dec->frame_dur : (96000 / dec->frame_dur +1); + else + dec->gvs->frame_rate = -1; + } + dec->gvs->status = dec->stat | dec->fatal_error; +} + +static int avs2_prepare_display_buf(struct AVS2Decoder_s *dec) +{ +#ifndef NO_DISPLAY + struct vframe_s *vf = NULL; + /*unsigned short slice_type;*/ + struct avs2_frame_s *pic; + struct vdec_s *pvdec = hw_to_vdec(dec); + while (1) { + pic = get_disp_pic(dec); + if (pic == NULL) + break; + + if (force_disp_pic_index & 0x100) { + /*recycle directly*/ + continue; + } + + if (pic->error_mark) { + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "!!!error pic, skip\n", + 0); + continue; + } + + if (dec->start_decoding_flag != 0) { + if (dec->skip_PB_before_I && + pic->slice_type != I_IMG) { + avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL, + "!!!slice type %d (not I) skip\n", + 0, pic->slice_type); + continue; + } + dec->skip_PB_before_I = 0; + } + + if (kfifo_get(&dec->newframe_q, &vf) == 0) { + pr_info("fatal error, no available buffer slot."); + return -1; + } + + if (vf) { + struct vdec_info tmp4x; + int stream_offset = pic->stream_offset; + set_vframe(dec, vf, pic, 0); + decoder_do_frame_check(pvdec, vf); + vdec_vframe_ready(pvdec, vf); + kfifo_put(&dec->display_q, (const struct vframe_s *)vf); + ATRACE_COUNTER(dec->pts_name, vf->timestamp); + ATRACE_COUNTER(dec->new_q_name, kfifo_len(&dec->newframe_q)); + ATRACE_COUNTER(dec->disp_q_name, kfifo_len(&dec->display_q)); + + dec_update_gvs(dec); + /*count info*/ + vdec_count_info(dec->gvs, 0, stream_offset); + if (stream_offset) { + if (pic->slice_type == I_IMG) { + dec->gvs->i_decoded_frames++; + } else if (pic->slice_type == P_IMG) { + dec->gvs->p_decoded_frames++; + } else if (pic->slice_type == B_IMG) { + dec->gvs->b_decoded_frames++; + } + } + memcpy(&tmp4x, dec->gvs, sizeof(struct vdec_info)); + tmp4x.bit_depth_luma = bit_depth_luma; + tmp4x.bit_depth_chroma = bit_depth_chroma; + tmp4x.double_write_mode = pic->double_write_mode; + vdec_fill_vdec_frame(pvdec, &dec->vframe_qos, &tmp4x, vf, pic->hw_decode_time); + pvdec->vdec_fps_detec(pvdec->id); + if (without_display_mode == 0) { + vf_notify_receiver(dec->provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + } else + vavs2_vf_put(vavs2_vf_get(dec), dec); + } + } +/*!NO_DISPLAY*/ +#endif + return 0; +} + +static void get_rpm_param(union param_u *params) +{ + int i; + unsigned int data32; + if (debug & AVS2_DBG_BUFMGR) + pr_info("enter %s\r\n", __func__); + for (i = 0; i < (RPM_END - RPM_BEGIN); i++) { + do { + data32 = READ_VREG(RPM_CMD_REG); + /*pr_info("%x\n", data32);*/ + } while ((data32 & 0x10000) == 0); + params->l.data[i] = data32&0xffff; + /*pr_info("%x\n", data32);*/ + WRITE_VREG(RPM_CMD_REG, 0); + } + if (debug & AVS2_DBG_BUFMGR) + pr_info("leave %s\r\n", __func__); +} +static void debug_buffer_mgr_more(struct AVS2Decoder_s *dec) +{ + int i; + if (!(debug & AVS2_DBG_BUFMGR_MORE)) + return; + pr_info("avs2_param: (%d)\n", dec->avs2_dec.img.number); + for (i = 0; i < (RPM_END-RPM_BEGIN); i++) { + pr_info("%04x ", dec->avs2_dec.param.l.data[i]); + if (((i + 1) & 0xf) == 0) + pr_info("\n"); + } +} + +#ifdef AVS2_10B_MMU +static void avs2_recycle_mmu_buf_tail(struct AVS2Decoder_s *dec) +{ + if (dec->cur_fb_idx_mmu != INVALID_IDX) { + if (dec->used_4k_num == -1) { + dec->used_4k_num = + (READ_VREG(HEVC_SAO_MMU_STATUS) >> 16); + if (dec->m_ins_flag) + hevc_mmu_dma_check(hw_to_vdec(dec)); + decoder_mmu_box_free_idx_tail(dec->mmu_box, + dec->cur_fb_idx_mmu, dec->used_4k_num); + } + dec->cur_fb_idx_mmu = INVALID_IDX; + dec->used_4k_num = -1; + } +} + +static void avs2_recycle_mmu_buf(struct AVS2Decoder_s *dec) +{ + if (dec->cur_fb_idx_mmu != INVALID_IDX) { + decoder_mmu_box_free_idx(dec->mmu_box, + dec->cur_fb_idx_mmu); + + dec->cur_fb_idx_mmu = INVALID_IDX; + dec->used_4k_num = -1; + } +} +#endif + +static void dec_again_process(struct AVS2Decoder_s *dec) +{ + amhevc_stop(); + dec->dec_result = DEC_RESULT_AGAIN; + if (dec->process_state == + PROC_STATE_DECODING) { + dec->process_state = + PROC_STATE_DECODE_AGAIN; + } else if (dec->process_state == + PROC_STATE_HEAD_DONE) { + dec->process_state = + PROC_STATE_HEAD_AGAIN; + } + dec->next_again_flag = 1; + reset_process_time(dec); + vdec_schedule_work(&dec->work); +} + +static uint32_t log2i(uint32_t val) +{ + uint32_t ret = -1; + while (val != 0) { + val >>= 1; + ret++; + } + return ret; +} + +static void check_pic_error(struct AVS2Decoder_s *dec, + struct avs2_frame_s *pic) +{ + if (pic->decoded_lcu == 0) { + pic->decoded_lcu = + (READ_VREG(HEVC_PARSER_LCU_START) + & 0xffffff) + 1; + } + if (pic->decoded_lcu != dec->avs2_dec.lcu_total) { + avs2_print(dec, AVS2_DBG_BUFMGR, + "%s error pic(index %d imgtr_fwRefDistance %d) decoded lcu %d (total %d)\n", + __func__, pic->index, pic->imgtr_fwRefDistance, + pic->decoded_lcu, dec->avs2_dec.lcu_total); + pic->error_mark = 1; + } else { + avs2_print(dec, AVS2_DBG_BUFMGR_MORE, + "%s pic(index %d imgtr_fwRefDistance %d) decoded lcu %d (total %d)\n", + __func__, pic->index, pic->imgtr_fwRefDistance, + pic->decoded_lcu, dec->avs2_dec.lcu_total); + + } +} +static void update_decoded_pic(struct AVS2Decoder_s *dec) +{ + struct avs2_frame_s *pic = dec->avs2_dec.hc.cur_pic; + if (pic) { + dec->avs2_dec.hc.cur_pic->decoded_lcu = + (READ_VREG(HEVC_PARSER_LCU_START) + & 0xffffff) + 1; + avs2_print(dec, AVS2_DBG_BUFMGR_MORE, + "%s pic(index %d imgtr_fwRefDistance %d) decoded lcu %d (total %d)\n", + __func__, pic->index, pic->imgtr_fwRefDistance, + pic->decoded_lcu, dec->avs2_dec.lcu_total); + } +} +/* +[SE] [BUG][BUG-171463][chuanqi.wang]: get frame rate by video sequeue*/ +static int get_frame_rate(union param_u *params, struct AVS2Decoder_s *dec) +{ + int tmp = 0; + + switch (params->p.frame_rate_code) { + case 1: + case 2: + tmp = 24; + break; + case 3: + tmp = 25; + break; + case 4: + case 5: + tmp = 30; + break; + case 6: + tmp = 50; + break; + case 7: + case 8: + tmp = 60; + break; + case 9: + tmp = 100; + break; + case 10: + tmp = 120; + break; + default: + tmp = 25; + break; + } + + if (!params->p.progressive_sequence) + tmp = tmp / 2; + dec->frame_dur = div_u64(96000ULL, tmp); + dec->get_frame_dur = true; + /*avs2_print(dec, 0, "avs2 frame_dur:%d,progressive:%d\n", dec->frame_dur, params->p.progressive_sequence);*/ + return 0; +} + + +#define HEVC_MV_INFO 0x310d +#define HEVC_QP_INFO 0x3137 +#define HEVC_SKIP_INFO 0x3136 + +/* only when we decoded one field or one frame, +we can call this function to get qos info*/ +static void get_picture_qos_info(struct AVS2Decoder_s *dec) +{ + struct avs2_frame_s *picture = dec->avs2_dec.hc.cur_pic; + struct vdec_s *vdec = hw_to_vdec(dec); + if (!picture) { + avs2_print(dec, AVS2_DBG_BUFMGR_MORE, + "%s decode picture is none exist\n"); + + return; + } + if (vdec->mvfrm) { + picture->frame_size = vdec->mvfrm->frame_size; + picture->hw_decode_time = + local_clock() - vdec->mvfrm->hw_decode_start; + } + +/* +#define DEBUG_QOS +*/ + + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_G12A) { + unsigned char a[3]; + unsigned char i, j, t; + unsigned long data; + + data = READ_VREG(HEVC_MV_INFO); + if (picture->slice_type == I_IMG) + data = 0; + a[0] = data & 0xff; + a[1] = (data >> 8) & 0xff; + a[2] = (data >> 16) & 0xff; + + for (i = 0; i < 3; i++) + for (j = i+1; j < 3; j++) { + if (a[j] < a[i]) { + t = a[j]; + a[j] = a[i]; + a[i] = t; + } else if (a[j] == a[i]) { + a[i]++; + t = a[j]; + a[j] = a[i]; + a[i] = t; + } + } + picture->max_mv = a[2]; + picture->avg_mv = a[1]; + picture->min_mv = a[0]; +#ifdef DEBUG_QOS + avs2_print(dec, 0, "mv data %x a[0]= %x a[1]= %x a[2]= %x\n", + data, a[0], a[1], a[2]); +#endif + + data = READ_VREG(HEVC_QP_INFO); + a[0] = data & 0x1f; + a[1] = (data >> 8) & 0x3f; + a[2] = (data >> 16) & 0x7f; + + for (i = 0; i < 3; i++) + for (j = i+1; j < 3; j++) { + if (a[j] < a[i]) { + t = a[j]; + a[j] = a[i]; + a[i] = t; + } else if (a[j] == a[i]) { + a[i]++; + t = a[j]; + a[j] = a[i]; + a[i] = t; + } + } + picture->max_qp = a[2]; + picture->avg_qp = a[1]; + picture->min_qp = a[0]; +#ifdef DEBUG_QOS + avs2_print(dec, 0, "qp data %x a[0]= %x a[1]= %x a[2]= %x\n", + data, a[0], a[1], a[2]); +#endif + + data = READ_VREG(HEVC_SKIP_INFO); + a[0] = data & 0x1f; + a[1] = (data >> 8) & 0x3f; + a[2] = (data >> 16) & 0x7f; + + for (i = 0; i < 3; i++) + for (j = i+1; j < 3; j++) { + if (a[j] < a[i]) { + t = a[j]; + a[j] = a[i]; + a[i] = t; + } else if (a[j] == a[i]) { + a[i]++; + t = a[j]; + a[j] = a[i]; + a[i] = t; + } + } + picture->max_skip = a[2]; + picture->avg_skip = a[1]; + picture->min_skip = a[0]; + +#ifdef DEBUG_QOS + avs2_print(dec, 0, + "skip data %x a[0]= %x a[1]= %x a[2]= %x\n", + data, a[0], a[1], a[2]); +#endif + } else { + uint32_t blk88_y_count; + uint32_t blk88_c_count; + uint32_t blk22_mv_count; + uint32_t rdata32; + int32_t mv_hi; + int32_t mv_lo; + uint32_t rdata32_l; + uint32_t mvx_L0_hi; + uint32_t mvy_L0_hi; + uint32_t mvx_L1_hi; + uint32_t mvy_L1_hi; + int64_t value; + uint64_t temp_value; +#ifdef DEBUG_QOS + int pic_number = 0; +#endif + + picture->max_mv = 0; + picture->avg_mv = 0; + picture->min_mv = 0; + + picture->max_skip = 0; + picture->avg_skip = 0; + picture->min_skip = 0; + + picture->max_qp = 0; + picture->avg_qp = 0; + picture->min_qp = 0; + + + +#ifdef DEBUG_QOS + avs2_print(dec, 0, "slice_type:%d, poc:%d\n", + picture->slice_type, + pic_number); +#endif + /* set rd_idx to 0 */ + WRITE_VREG(HEVC_PIC_QUALITY_CTRL, 0); + + blk88_y_count = READ_VREG(HEVC_PIC_QUALITY_DATA); + if (blk88_y_count == 0) { +#ifdef DEBUG_QOS + avs2_print(dec, 0, + "[Picture %d Quality] NO Data yet.\n", + pic_number); +#endif + /* reset all counts */ + WRITE_VREG(HEVC_PIC_QUALITY_CTRL, (1<<8)); + return; + } + /* qp_y_sum */ + rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA); +#ifdef DEBUG_QOS + avs2_print(dec, 0, + "[Picture %d Quality] Y QP AVG : %d (%d/%d)\n", + pic_number, rdata32/blk88_y_count, + rdata32, blk88_y_count); +#endif + picture->avg_qp = rdata32/blk88_y_count; + /* intra_y_count */ + rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA); +#ifdef DEBUG_QOS + avs2_print(dec, 0, + "[Picture %d Quality] Y intra rate : %d%c (%d)\n", + pic_number, rdata32*100/blk88_y_count, + '%', rdata32); +#endif + /* skipped_y_count */ + rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA); +#ifdef DEBUG_QOS + avs2_print(dec, 0, + "[Picture %d Quality] Y skipped rate : %d%c (%d)\n", + pic_number, rdata32*100/blk88_y_count, + '%', rdata32); +#endif + picture->avg_skip = rdata32*100/blk88_y_count; + /* coeff_non_zero_y_count */ + rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA); +#ifdef DEBUG_QOS + avs2_print(dec, 0, + "[Picture %d Quality] Y ZERO_Coeff rate : %d%c (%d)\n", + pic_number, (100 - rdata32*100/(blk88_y_count*1)), + '%', rdata32); +#endif + /* blk66_c_count */ + blk88_c_count = READ_VREG(HEVC_PIC_QUALITY_DATA); + if (blk88_c_count == 0) { +#ifdef DEBUG_QOS + avs2_print(dec, 0, + "[Picture %d Quality] NO Data yet.\n", + pic_number); +#endif + /* reset all counts */ + WRITE_VREG(HEVC_PIC_QUALITY_CTRL, (1<<8)); + return; + } + /* qp_c_sum */ + rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA); +#ifdef DEBUG_QOS + avs2_print(dec, 0, + "[Picture %d Quality] C QP AVG : %d (%d/%d)\n", + pic_number, rdata32/blk88_c_count, + rdata32, blk88_c_count); +#endif + /* intra_c_count */ + rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA); +#ifdef DEBUG_QOS + avs2_print(dec, 0, + "[Picture %d Quality] C intra rate : %d%c (%d)\n", + pic_number, rdata32*100/blk88_c_count, + '%', rdata32); +#endif + /* skipped_cu_c_count */ + rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA); +#ifdef DEBUG_QOS + avs2_print(dec, 0, + "[Picture %d Quality] C skipped rate : %d%c (%d)\n", + pic_number, rdata32*100/blk88_c_count, + '%', rdata32); +#endif + /* coeff_non_zero_c_count */ + rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA); +#ifdef DEBUG_QOS + avs2_print(dec, 0, + "[Picture %d Quality] C ZERO_Coeff rate : %d%c (%d)\n", + pic_number, (100 - rdata32*100/(blk88_c_count*1)), + '%', rdata32); +#endif + + /* 1'h0, qp_c_max[6:0], 1'h0, qp_c_min[6:0], + 1'h0, qp_y_max[6:0], 1'h0, qp_y_min[6:0] */ + rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA); +#ifdef DEBUG_QOS + avs2_print(dec, 0, "[Picture %d Quality] Y QP min : %d\n", + pic_number, (rdata32>>0)&0xff); +#endif + picture->min_qp = (rdata32>>0)&0xff; + +#ifdef DEBUG_QOS + avs2_print(dec, 0, "[Picture %d Quality] Y QP max : %d\n", + pic_number, (rdata32>>8)&0xff); +#endif + picture->max_qp = (rdata32>>8)&0xff; + +#ifdef DEBUG_QOS + avs2_print(dec, 0, "[Picture %d Quality] C QP min : %d\n", + pic_number, (rdata32>>16)&0xff); + avs2_print(dec, 0, "[Picture %d Quality] C QP max : %d\n", + pic_number, (rdata32>>24)&0xff); +#endif + + /* blk22_mv_count */ + blk22_mv_count = READ_VREG(HEVC_PIC_QUALITY_DATA); + if (blk22_mv_count == 0) { +#ifdef DEBUG_QOS + avs2_print(dec, 0, + "[Picture %d Quality] NO MV Data yet.\n", + pic_number); +#endif + /* reset all counts */ + WRITE_VREG(HEVC_PIC_QUALITY_CTRL, (1<<8)); + return; + } + /* mvy_L1_count[39:32], mvx_L1_count[39:32], + mvy_L0_count[39:32], mvx_L0_count[39:32] */ + rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA); + /* should all be 0x00 or 0xff */ +#ifdef DEBUG_QOS + avs2_print(dec, 0, + "[Picture %d Quality] MV AVG High Bits: 0x%X\n", + pic_number, rdata32); +#endif + mvx_L0_hi = ((rdata32>>0)&0xff); + mvy_L0_hi = ((rdata32>>8)&0xff); + mvx_L1_hi = ((rdata32>>16)&0xff); + mvy_L1_hi = ((rdata32>>24)&0xff); + + /* mvx_L0_count[31:0] */ + rdata32_l = READ_VREG(HEVC_PIC_QUALITY_DATA); + temp_value = mvx_L0_hi; + temp_value = (temp_value << 32) | rdata32_l; + + if (mvx_L0_hi & 0x80) + value = 0xFFFFFFF000000000 | temp_value; + else + value = temp_value; + value = div_s64(value, blk22_mv_count); +#ifdef DEBUG_QOS + avs2_print(dec, 0, + "[Picture %d Quality] MVX_L0 AVG : %d (%lld/%d)\n", + pic_number, (int)value, + value, blk22_mv_count); +#endif + picture->avg_mv = value; + + /* mvy_L0_count[31:0] */ + rdata32_l = READ_VREG(HEVC_PIC_QUALITY_DATA); + temp_value = mvy_L0_hi; + temp_value = (temp_value << 32) | rdata32_l; + + if (mvy_L0_hi & 0x80) + value = 0xFFFFFFF000000000 | temp_value; + else + value = temp_value; +#ifdef DEBUG_QOS + avs2_print(dec, 0, + "[Picture %d Quality] MVY_L0 AVG : %d (%lld/%d)\n", + pic_number, rdata32_l/blk22_mv_count, + value, blk22_mv_count); +#endif + + /* mvx_L1_count[31:0] */ + rdata32_l = READ_VREG(HEVC_PIC_QUALITY_DATA); + temp_value = mvx_L1_hi; + temp_value = (temp_value << 32) | rdata32_l; + if (mvx_L1_hi & 0x80) + value = 0xFFFFFFF000000000 | temp_value; + else + value = temp_value; +#ifdef DEBUG_QOS + avs2_print(dec, 0, + "[Picture %d Quality] MVX_L1 AVG : %d (%lld/%d)\n", + pic_number, rdata32_l/blk22_mv_count, + value, blk22_mv_count); +#endif + + /* mvy_L1_count[31:0] */ + rdata32_l = READ_VREG(HEVC_PIC_QUALITY_DATA); + temp_value = mvy_L1_hi; + temp_value = (temp_value << 32) | rdata32_l; + if (mvy_L1_hi & 0x80) + value = 0xFFFFFFF000000000 | temp_value; + else + value = temp_value; +#ifdef DEBUG_QOS + avs2_print(dec, 0, + "[Picture %d Quality] MVY_L1 AVG : %d (%lld/%d)\n", + pic_number, rdata32_l/blk22_mv_count, + value, blk22_mv_count); +#endif + + /* {mvx_L0_max, mvx_L0_min} // format : {sign, abs[14:0]} */ + rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA); + mv_hi = (rdata32>>16)&0xffff; + if (mv_hi & 0x8000) + mv_hi = 0x8000 - mv_hi; +#ifdef DEBUG_QOS + avs2_print(dec, 0, "[Picture %d Quality] MVX_L0 MAX : %d\n", + pic_number, mv_hi); +#endif + picture->max_mv = mv_hi; + + mv_lo = (rdata32>>0)&0xffff; + if (mv_lo & 0x8000) + mv_lo = 0x8000 - mv_lo; +#ifdef DEBUG_QOS + avs2_print(dec, 0, "[Picture %d Quality] MVX_L0 MIN : %d\n", + pic_number, mv_lo); +#endif + picture->min_mv = mv_lo; + +#ifdef DEBUG_QOS + /* {mvy_L0_max, mvy_L0_min} */ + rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA); + mv_hi = (rdata32>>16)&0xffff; + if (mv_hi & 0x8000) + mv_hi = 0x8000 - mv_hi; + avs2_print(dec, 0, "[Picture %d Quality] MVY_L0 MAX : %d\n", + pic_number, mv_hi); + + + mv_lo = (rdata32>>0)&0xffff; + if (mv_lo & 0x8000) + mv_lo = 0x8000 - mv_lo; + + avs2_print(dec, 0, "[Picture %d Quality] MVY_L0 MIN : %d\n", + pic_number, mv_lo); + + + /* {mvx_L1_max, mvx_L1_min} */ + rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA); + mv_hi = (rdata32>>16)&0xffff; + if (mv_hi & 0x8000) + mv_hi = 0x8000 - mv_hi; + + avs2_print(dec, 0, "[Picture %d Quality] MVX_L1 MAX : %d\n", + pic_number, mv_hi); + + + mv_lo = (rdata32>>0)&0xffff; + if (mv_lo & 0x8000) + mv_lo = 0x8000 - mv_lo; + + avs2_print(dec, 0, "[Picture %d Quality] MVX_L1 MIN : %d\n", + pic_number, mv_lo); + + + /* {mvy_L1_max, mvy_L1_min} */ + rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA); + mv_hi = (rdata32>>16)&0xffff; + if (mv_hi & 0x8000) + mv_hi = 0x8000 - mv_hi; + + avs2_print(dec, 0, "[Picture %d Quality] MVY_L1 MAX : %d\n", + pic_number, mv_hi); + + mv_lo = (rdata32>>0)&0xffff; + if (mv_lo & 0x8000) + mv_lo = 0x8000 - mv_lo; + + avs2_print(dec, 0, "[Picture %d Quality] MVY_L1 MIN : %d\n", + pic_number, mv_lo); +#endif + + rdata32 = READ_VREG(HEVC_PIC_QUALITY_CTRL); +#ifdef DEBUG_QOS + avs2_print(dec, 0, + "[Picture %d Quality] After Read : VDEC_PIC_QUALITY_CTRL : 0x%x\n", + pic_number, rdata32); +#endif + /* reset all counts */ + WRITE_VREG(HEVC_PIC_QUALITY_CTRL, (1<<8)); + } +} + +static irqreturn_t vavs2_isr_thread_fn(int irq, void *data) +{ + struct AVS2Decoder_s *dec = (struct AVS2Decoder_s *)data; + unsigned int dec_status = dec->dec_status; + int i, ret; + int32_t start_code = 0; + + /*if (dec->wait_buf) + pr_info("set wait_buf to 0\r\n"); + */ + + avs2_print(dec, AVS2_DBG_BUFMGR_MORE, + "%s decode_status 0x%x process_state %d lcu 0x%x\n", + __func__, dec_status, dec->process_state, + READ_VREG(HEVC_PARSER_LCU_START)); + +#ifndef G12A_BRINGUP_DEBUG + if (dec->eos) { + PRINT_LINE(); + goto irq_handled_exit; + } +#endif + dec->wait_buf = 0; + if (dec_status == AVS2_DECODE_BUFEMPTY) { + PRINT_LINE(); + if (dec->m_ins_flag) { + reset_process_time(dec); + if (!vdec_frame_based(hw_to_vdec(dec))) + dec_again_process(dec); + else { + dec->dec_result = DEC_RESULT_DONE; + reset_process_time(dec); + amhevc_stop(); + vdec_schedule_work(&dec->work); + } + } + goto irq_handled_exit; + } else if (dec_status == HEVC_DECPIC_DATA_DONE) { + PRINT_LINE(); + dec->start_decoding_flag |= 0x3; + if (dec->m_ins_flag) { + set_cuva_data(dec); + update_decoded_pic(dec); + get_picture_qos_info(dec); + reset_process_time(dec); + dec->dec_result = DEC_RESULT_DONE; + amhevc_stop(); +#if 0 /*def AVS2_10B_MMU*/ + if (dec->m_ins_flag) { + /*avs2_recycle_mmu_buf_tail(dec);*/ + dec->used_4k_num = + (READ_VREG(HEVC_SAO_MMU_STATUS) >> 16); + } +#endif + +#if 0 + /*keep hardware state*/ + WRITE_VREG(HEVC_MPRED_INT_STATUS, (1<<31)); + WRITE_VREG(HEVC_PARSER_RESULT_3, 0xffffffff); + dec->mpred_abv_start_addr = + READ_VREG(HEVC_MPRED_ABV_START_ADDR); + /**/ +#endif + vdec_schedule_work(&dec->work); + } + goto irq_handled_exit; + } + PRINT_LINE(); +#if 0 + if (dec_status == AVS2_EOS) { + if (dec->m_ins_flag) + reset_process_time(dec); + + avs2_print(dec, AVS2_DBG_BUFMGR, + "AVS2_EOS, flush buffer\r\n"); + + avs2_post_process(&dec->avs2_dec); + avs2_prepare_display_buf(dec); + + avs2_print(dec, AVS2_DBG_BUFMGR, + "send AVS2_10B_DISCARD_NAL\r\n"); + WRITE_VREG(HEVC_DEC_STATUS_REG, AVS2_10B_DISCARD_NAL); + if (dec->m_ins_flag) { + update_decoded_pic(dec); + dec->dec_result = DEC_RESULT_DONE; + amhevc_stop(); + vdec_schedule_work(&dec->work); + } + goto irq_handled_exit; + } else +#endif + if (dec_status == AVS2_DECODE_OVER_SIZE) { + avs2_print(dec, 0, + "avs2 decode oversize !!\n"); + debug |= (AVS2_DBG_DIS_LOC_ERROR_PROC | + AVS2_DBG_DIS_SYS_ERROR_PROC); + dec->fatal_error |= DECODER_FATAL_ERROR_SIZE_OVERFLOW; + if (dec->m_ins_flag) + reset_process_time(dec); + goto irq_handled_exit; + } + PRINT_LINE(); + + if (dec->m_ins_flag) + reset_process_time(dec); + + if (dec_status == AVS2_HEAD_SEQ_READY) + start_code = SEQUENCE_HEADER_CODE; + else if (dec_status == AVS2_HEAD_PIC_I_READY) + start_code = I_PICTURE_START_CODE; + else if (dec_status == AVS2_HEAD_PIC_PB_READY) + start_code = PB_PICTURE_START_CODE; + else if (dec_status == AVS2_STARTCODE_SEARCH_DONE) + /*SEQUENCE_END_CODE, VIDEO_EDIT_CODE*/ + start_code = READ_VREG(CUR_NAL_UNIT_TYPE); + + if (dec->process_state == + PROC_STATE_HEAD_AGAIN + ) { + if ((start_code == I_PICTURE_START_CODE) + || (start_code == PB_PICTURE_START_CODE)) { + avs2_print(dec, 0, + "PROC_STATE_HEAD_AGAIN error, start_code 0x%x!!!\r\n", + start_code); + goto irq_handled_exit; + } else { + avs2_print(dec, AVS2_DBG_BUFMGR, + "PROC_STATE_HEAD_AGAIN, start_code 0x%x\r\n", + start_code); + dec->process_state = PROC_STATE_HEAD_DONE; + WRITE_VREG(HEVC_DEC_STATUS_REG, AVS2_ACTION_DONE); + goto irq_handled_exit; + } + } else if (dec->process_state == + PROC_STATE_DECODE_AGAIN) { + if ((start_code == I_PICTURE_START_CODE) + || (start_code == PB_PICTURE_START_CODE)) { + avs2_print(dec, AVS2_DBG_BUFMGR, + "PROC_STATE_DECODE_AGAIN=> decode_slice, start_code 0x%x\r\n", + start_code); + goto decode_slice; + } else { + avs2_print(dec, 0, + "PROC_STATE_DECODE_AGAIN, start_code 0x%x!!!\r\n", + start_code); + WRITE_VREG(HEVC_DEC_STATUS_REG, AVS2_ACTION_DONE); + goto irq_handled_exit; + } + } + + if ((start_code == I_PICTURE_START_CODE) + || (start_code == PB_PICTURE_START_CODE) + || (start_code == SEQUENCE_END_CODE) + || (start_code == VIDEO_EDIT_CODE)) { + PRINT_LINE(); + + if (dec->avs2_dec.hc.cur_pic != NULL) { + int32_t ii; +#ifdef AVS2_10B_MMU + avs2_recycle_mmu_buf_tail(dec); +#endif + check_pic_error(dec, dec->avs2_dec.hc.cur_pic); + avs2_post_process(&dec->avs2_dec); + + if (debug & AVS2_DBG_PRINT_PIC_LIST) + dump_pic_list(dec); + + avs2_prepare_display_buf(dec); + dec->avs2_dec.hc.cur_pic = NULL; + for (ii = 0; ii < dec->avs2_dec.ref_maxbuffer; + ii++) { + struct avs2_frame_s *pic = + dec->avs2_dec.fref[ii]; + if (pic->bg_flag == 0 && + pic->is_output == -1 && + pic->mmu_alloc_flag && + pic->vf_ref == 0) { + if (pic->refered_by_others == 0) { +#ifdef AVS2_10B_MMU + pic->mmu_alloc_flag = 0; + /*release_buffer_4k( + dec->avs2_dec.fref[ii]->index);*/ + decoder_mmu_box_free_idx(dec->mmu_box, + pic->index); +#ifdef DYNAMIC_ALLOC_HEAD + decoder_bmmu_box_free_idx( + dec->bmmu_box, + HEADER_BUFFER_IDX(pic->index)); + pic->header_adr = 0; +#endif +#endif +#ifndef MV_USE_FIXED_BUF + decoder_bmmu_box_free_idx( + dec->bmmu_box, + MV_BUFFER_IDX(pic->index)); + pic->mpred_mv_wr_start_addr = 0; +#endif + } + /* + decoder_bmmu_box_free_idx( + dec->bmmu_box, + VF_BUFFER_IDX(pic->index)); + dec->cma_alloc_addr = 0;*/ + } + } + } + } + + if ((dec_status == AVS2_HEAD_PIC_I_READY) + || (dec_status == AVS2_HEAD_PIC_PB_READY)) { + PRINT_LINE(); + + if (debug & AVS2_DBG_SEND_PARAM_WITH_REG) { + get_rpm_param( + &dec->avs2_dec.param); + } else { + + for (i = 0; i < (RPM_END - RPM_BEGIN); i += 4) { + int ii; + for (ii = 0; ii < 4; ii++) + dec->avs2_dec.param.l.data[i + ii] = + dec->rpm_ptr[i + 3 - ii]; + } + } +#ifdef SANITY_CHECK + if (dec->avs2_dec.param.p.num_of_ref_cur > + dec->avs2_dec.ref_maxbuffer) { + pr_info("Warning: Wrong num_of_ref_cur %d, force to %d\n", + dec->avs2_dec.param.p.num_of_ref_cur, + dec->avs2_dec.ref_maxbuffer); + dec->avs2_dec.param.p.num_of_ref_cur = + dec->avs2_dec.ref_maxbuffer; + } +#endif + PRINT_LINE(); + + debug_buffer_mgr_more(dec); + get_frame_rate(&dec->avs2_dec.param, dec); + +#if 1 // The video_signal_type is type of uint16_t and result false, so comment it out. + if (dec->avs2_dec.param.p.video_signal_type + & (1<<30)) { + union param_u *pPara; + + avs2_print(dec, 0, + "avs2 HDR meta data present\n"); + pPara = &dec->avs2_dec.param; + + /*clean this flag*/ + pPara->p.video_signal_type + &= ~(1<<30); + + dec->vf_dp.present_flag = 1; + + dec->vf_dp.white_point[0] + = pPara->p.white_point_x; + avs2_print(dec, AVS2_DBG_HDR_INFO, + "white_point[0]:0x%x\n", + dec->vf_dp.white_point[0]); + + dec->vf_dp.white_point[1] + = pPara->p.white_point_y; + avs2_print(dec, AVS2_DBG_HDR_INFO, + "white_point[1]:0x%x\n", + dec->vf_dp.white_point[1]); + + for (i = 0; i < 3; i++) { + dec->vf_dp.primaries[i][0] + = pPara->p.display_primaries_x[i]; + avs2_print(dec, AVS2_DBG_HDR_INFO, + "primaries[%d][0]:0x%x\n", + i, + dec->vf_dp.primaries[i][0]); + } + + for (i = 0; i < 3; i++) { + dec->vf_dp.primaries[i][1] + = pPara->p.display_primaries_y[i]; + avs2_print(dec, AVS2_DBG_HDR_INFO, + "primaries[%d][1]:0x%x\n", + i, + dec->vf_dp.primaries[i][1]); + } + + dec->vf_dp.luminance[0] + = pPara->p.max_display_mastering_luminance; + avs2_print(dec, AVS2_DBG_HDR_INFO, + "luminance[0]:0x%x\n", + dec->vf_dp.luminance[0]); + + dec->vf_dp.luminance[1] + = pPara->p.min_display_mastering_luminance; + avs2_print(dec, AVS2_DBG_HDR_INFO, + "luminance[1]:0x%x\n", + dec->vf_dp.luminance[1]); + + + dec->vf_dp.content_light_level.present_flag + = 1; + dec->vf_dp.content_light_level.max_content + = pPara->p.max_content_light_level; + avs2_print(dec, AVS2_DBG_HDR_INFO, + "max_content:0x%x\n", + dec->vf_dp.content_light_level.max_content); + + dec->vf_dp.content_light_level.max_pic_average + = pPara->p.max_picture_average_light_level; + + avs2_print(dec, AVS2_DBG_HDR_INFO, + "max_pic_average:0x%x\n", + dec->vf_dp.content_light_level.max_pic_average); + } +#endif + + + if (dec->video_ori_signal_type != + ((dec->avs2_dec.param.p.video_signal_type << 16) + | dec->avs2_dec.param.p.color_description)) { + u32 v = dec->avs2_dec.param.p.video_signal_type; + u32 c = dec->avs2_dec.param.p.color_description; + u32 convert_c = c; + + if (v & 0x2000) { + avs2_print(dec, AVS2_DBG_HDR_INFO, + "video_signal_type present:\n"); + avs2_print(dec, AVS2_DBG_HDR_INFO, + " %s %s\n", + video_format_names[(v >> 10) & 7], + ((v >> 9) & 1) ? + "full_range" : "limited"); + if (v & 0x100) { + u32 transfer; + u32 maxtrix; + + avs2_print(dec, AVS2_DBG_HDR_INFO, + "color_description present:\n"); + avs2_print(dec, AVS2_DBG_HDR_INFO, + "color_primarie = %d\n", + v & 0xff); + avs2_print(dec, AVS2_DBG_HDR_INFO, + "transfer_characteristic = %d\n", + (c >> 8) & 0xff); + avs2_print(dec, AVS2_DBG_HDR_INFO, + " matrix_coefficient = %d\n", + c & 0xff); + + transfer = (c >> 8) & 0xFF; + if (transfer >= 15) + avs2_print(dec, AVS2_DBG_HDR_INFO, + "unsupport transfer_characteristic\n"); + else if (transfer == 14) + transfer = 18; /* HLG */ + else if (transfer == 13) + transfer = 32; + else if (transfer == 12) + transfer = 16; + else if (transfer == 11) + transfer = 15; + + maxtrix = c & 0xFF; + if (maxtrix >= 10) + avs2_print(dec, AVS2_DBG_HDR_INFO, + "unsupport matrix_coefficient\n"); + else if (maxtrix == 9) + maxtrix = 10; + else if (maxtrix == 8) + maxtrix = 9; + + convert_c = (transfer << 8) | (maxtrix); + + avs2_print(dec, AVS2_DBG_HDR_INFO, + " convered c:0x%x\n", + convert_c); + } + } + + if (enable_force_video_signal_type) + dec->video_signal_type + = force_video_signal_type; + else { + dec->video_signal_type + = (v << 16) | convert_c; + + dec->video_ori_signal_type + = (v << 16) | c; + } + + video_signal_type = dec->video_signal_type; + } + } +#if 0 + if ((debug_again & 0x4) && + dec->process_state == + PROC_STATE_INIT) { + if (start_code == PB_PICTURE_START_CODE) { + dec->process_state = PROC_STATE_TEST1; + dec_again_process(dec); + goto irq_handled_exit; + } + } +#endif + PRINT_LINE(); + avs2_prepare_header(&dec->avs2_dec, start_code); + + if (start_code == SEQUENCE_HEADER_CODE || + start_code == VIDEO_EDIT_CODE || + start_code == SEQUENCE_END_CODE) { + if (dec->m_ins_flag && + vdec_frame_based(hw_to_vdec(dec))) + dec->start_decoding_flag |= 0x1; + dec->process_state = PROC_STATE_HEAD_DONE; + WRITE_VREG(HEVC_DEC_STATUS_REG, AVS2_ACTION_DONE); + } else if (start_code == I_PICTURE_START_CODE || + start_code == PB_PICTURE_START_CODE) { + ret = 0; + if (dec->pic_list_init_flag == 0) { + int32_t lcu_size_log2 = + log2i(dec->avs2_dec.param.p.lcu_size); + + avs2_init_global_buffers(&dec->avs2_dec); + /*avs2_dec->m_bg->index is + set to dec->used_buf_num - 1*/ + init_pic_list(dec, lcu_size_log2); + init_pic_list_hw(dec); + } + ret = avs2_process_header(&dec->avs2_dec); + if (!dec->m_ins_flag) + dec->slice_idx++; + + if (dec->m_ins_flag && ret + && dec->avs2_dec.hc.cur_pic->cuva_data_buf != NULL) + release_cuva_data(dec->avs2_dec.hc.cur_pic); + + PRINT_LINE(); +#ifdef I_ONLY_SUPPORT + if ((start_code == PB_PICTURE_START_CODE) && + (dec->i_only & 0x2)) + ret = -2; +#endif +#ifdef AVS2_10B_MMU + if (ret >= 0) { + ret = avs2_alloc_mmu(dec, + dec->avs2_dec.hc.cur_pic->index, + dec->avs2_dec.img.width, + dec->avs2_dec.img.height, + dec->avs2_dec.input.sample_bit_depth, + dec->frame_mmu_map_addr); + if (ret >= 0) { + dec->cur_fb_idx_mmu = + dec->avs2_dec.hc.cur_pic->index; + dec->avs2_dec.hc.cur_pic->mmu_alloc_flag = 1; + } else + pr_err("can't alloc need mmu1,idx %d ret =%d\n", + dec->avs2_dec.hc.cur_pic->index, + ret); + } +#endif + +#ifndef MV_USE_FIXED_BUF + if (ret >= 0 && + dec->avs2_dec.hc.cur_pic-> + mpred_mv_wr_start_addr == 0) { + unsigned long buf_addr; + unsigned mv_buf_size = get_mv_buf_size( + dec, + dec->avs2_dec.hc.cur_pic->pic_w, + dec->avs2_dec.hc.cur_pic->pic_h); + int i = dec->avs2_dec.hc.cur_pic->index; + /*if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) + mv_buf_size = 0x120000 * 4;*/ + if (decoder_bmmu_box_alloc_buf_phy + (dec->bmmu_box, + MV_BUFFER_IDX(i), + mv_buf_size, + DRIVER_NAME, + &buf_addr) < 0) + ret = -1; + else + dec->avs2_dec.hc.cur_pic-> + mpred_mv_wr_start_addr + = buf_addr; + } +#endif + if (ret < 0) { + avs2_print(dec, AVS2_DBG_BUFMGR, + "avs2_bufmgr_process=> %d, AVS2_10B_DISCARD_NAL\r\n", + ret); + WRITE_VREG(HEVC_DEC_STATUS_REG, AVS2_10B_DISCARD_NAL); + #ifdef AVS2_10B_MMU + avs2_recycle_mmu_buf(dec); + #endif + if (dec->m_ins_flag) { + dec->dec_result = DEC_RESULT_DONE; + amhevc_stop(); + vdec_schedule_work(&dec->work); + } + + goto irq_handled_exit; + } else { + PRINT_LINE(); + dec->avs2_dec.hc.cur_pic->stream_offset = + READ_VREG(HEVC_SHIFT_BYTE_COUNT); + /* + struct PIC_BUFFER_CONFIG_s *cur_pic + = &cm->cur_frame->buf; + cur_pic->decode_idx = dec->frame_count; + */ + if (!dec->m_ins_flag) { + dec->frame_count++; + decode_frame_count[dec->index] + = dec->frame_count; + } + /*MULTI_INSTANCE_SUPPORT*/ + if (dec->chunk) { + dec->avs2_dec.hc.cur_pic->pts = + dec->chunk->pts; + dec->avs2_dec.hc.cur_pic->pts64 = + dec->chunk->pts64; + } + /**/ + dec->avs2_dec.hc.cur_pic->bit_depth + = dec->avs2_dec.input.sample_bit_depth; + dec->avs2_dec.hc.cur_pic->double_write_mode + = get_double_write_mode(dec); +decode_slice: + PRINT_LINE(); + + config_mc_buffer(dec); + config_mcrcc_axi_hw(dec); + config_mpred_hw(dec); + config_dblk_hw(dec); + config_sao_hw(dec); + config_alf_hw(dec); + config_other_hw(dec); + + avs2_print(dec, AVS2_DBG_BUFMGR_MORE, + "=>fref0 imgtr_fwRefDistance %d, fref1 imgtr_fwRefDistance %d, dis2/dis3/dis4 %d %d %d img->tr %d\n", + dec->avs2_dec.fref[0]->imgtr_fwRefDistance, + dec->avs2_dec.fref[1]->imgtr_fwRefDistance, + dec->avs2_dec.fref[2]->imgtr_fwRefDistance, + dec->avs2_dec.fref[3]->imgtr_fwRefDistance, + dec->avs2_dec.fref[4]->imgtr_fwRefDistance, + dec->avs2_dec.img.tr); + + if ((debug_again & 0x2) && + dec->process_state == + PROC_STATE_INIT) { + dec->process_state = PROC_STATE_DECODING; + dec_again_process(dec); + goto irq_handled_exit; + } + + dec->process_state = PROC_STATE_DECODING; + + WRITE_VREG(HEVC_DEC_STATUS_REG, AVS2_ACTION_DONE); + + } + + if (dec->m_ins_flag) + start_process_time(dec); + } +irq_handled_exit: + PRINT_LINE(); + dec->process_busy = 0; + return IRQ_HANDLED; +} + +static irqreturn_t vavs2_isr(int irq, void *data) +{ + int i; + unsigned int dec_status; + struct AVS2Decoder_s *dec = (struct AVS2Decoder_s *)data; + uint debug_tag; + + WRITE_VREG(HEVC_ASSIST_MBOX0_CLR_REG, 1); + + dec_status = READ_VREG(HEVC_DEC_STATUS_REG); + + if (!dec) + return IRQ_HANDLED; + if (dec->init_flag == 0) + return IRQ_HANDLED; + if (dec->process_busy)/*on process.*/ + return IRQ_HANDLED; + dec->dec_status = dec_status; + dec->process_busy = 1; + if (debug & AVS2_DBG_IRQ_EVENT) + avs2_print(dec, 0, + "avs2 isr dec status = 0x%x, lcu 0x%x shiftbyte 0x%x (%x %x lev %x, wr %x, rd %x)\n", + dec_status, READ_VREG(HEVC_PARSER_LCU_START), + READ_VREG(HEVC_SHIFT_BYTE_COUNT), + READ_VREG(HEVC_STREAM_START_ADDR), + READ_VREG(HEVC_STREAM_END_ADDR), + READ_VREG(HEVC_STREAM_LEVEL), + READ_VREG(HEVC_STREAM_WR_PTR), + READ_VREG(HEVC_STREAM_RD_PTR) + ); + + debug_tag = READ_HREG(DEBUG_REG1); + if (debug_tag & 0x10000) { + dma_sync_single_for_cpu( + amports_get_dma_device(), + dec->lmem_phy_addr, + LMEM_BUF_SIZE, + DMA_FROM_DEVICE); + + pr_info("LMEM<tag %x>:\n", READ_HREG(DEBUG_REG1)); + for (i = 0; i < 0x400; i += 4) { + int ii; + if ((i & 0xf) == 0) + pr_info("%03x: ", i); + for (ii = 0; ii < 4; ii++) { + pr_info("%04x ", + dec->lmem_ptr[i + 3 - ii]); + } + if (((i + ii) & 0xf) == 0) + pr_info("\n"); + } + + if (((udebug_pause_pos & 0xffff) + == (debug_tag & 0xffff)) && + (udebug_pause_decode_idx == 0 || + udebug_pause_decode_idx == dec->decode_idx) && + (udebug_pause_val == 0 || + udebug_pause_val == READ_HREG(DEBUG_REG2))) { + udebug_pause_pos &= 0xffff; + dec->ucode_pause_pos = udebug_pause_pos; + } else if (debug_tag & 0x20000) + dec->ucode_pause_pos = 0xffffffff; + if (dec->ucode_pause_pos) + reset_process_time(dec); + else + WRITE_HREG(DEBUG_REG1, 0); + } else if (debug_tag != 0) { + pr_info( + "dbg%x: %x lcu %x\n", READ_HREG(DEBUG_REG1), + READ_HREG(DEBUG_REG2), + READ_VREG(HEVC_PARSER_LCU_START)); + if (((udebug_pause_pos & 0xffff) + == (debug_tag & 0xffff)) && + (udebug_pause_decode_idx == 0 || + udebug_pause_decode_idx == dec->decode_idx) && + (udebug_pause_val == 0 || + udebug_pause_val == READ_HREG(DEBUG_REG2))) { + udebug_pause_pos &= 0xffff; + dec->ucode_pause_pos = udebug_pause_pos; + } + if (dec->ucode_pause_pos) + reset_process_time(dec); + else + WRITE_HREG(DEBUG_REG1, 0); + dec->process_busy = 0; + return IRQ_HANDLED; + } + + if (!dec->m_ins_flag) { + if (dec->error_flag == 1) { + dec->error_flag = 2; + dec->process_busy = 0; + return IRQ_HANDLED; + } else if (dec->error_flag == 3) { + dec->process_busy = 0; + return IRQ_HANDLED; + } + + if ((dec->pic_list_init_flag) && + get_free_buf_count(dec) <= 0) { + /* + if (dec->wait_buf == 0) + pr_info("set wait_buf to 1\r\n"); + */ + dec->wait_buf = 1; + dec->process_busy = 0; + if (debug & AVS2_DBG_IRQ_EVENT) + avs2_print(dec, 0, "wait_buf\n"); + return IRQ_HANDLED; + } else if (force_disp_pic_index) { + dec->process_busy = 0; + return IRQ_HANDLED; + } + } + return IRQ_WAKE_THREAD; +} + +static void vavs2_put_timer_func(struct timer_list *timer) +{ + struct AVS2Decoder_s *dec = container_of(timer, + struct AVS2Decoder_s, timer); + uint8_t empty_flag; + unsigned int buf_level; + + enum receviver_start_e state = RECEIVER_INACTIVE; + if (dec->m_ins_flag) { + if (hw_to_vdec(dec)->next_status + == VDEC_STATUS_DISCONNECTED) { + dec->dec_result = DEC_RESULT_FORCE_EXIT; + vdec_schedule_work(&dec->work); + avs2_print(dec, AVS2_DBG_BUFMGR, + "vdec requested to be disconnected\n"); + return; + } + } + if (dec->init_flag == 0) { + if (dec->stat & STAT_TIMER_ARM) { + timer->expires = jiffies + PUT_INTERVAL; + add_timer(&dec->timer); + } + return; + } + if (dec->m_ins_flag == 0) { + if (vf_get_receiver(dec->provider_name)) { + state = + vf_notify_receiver(dec->provider_name, + VFRAME_EVENT_PROVIDER_QUREY_STATE, + NULL); + if ((state == RECEIVER_STATE_NULL) + || (state == RECEIVER_STATE_NONE)) + state = RECEIVER_INACTIVE; + } else + state = RECEIVER_INACTIVE; + + empty_flag = (READ_VREG(HEVC_PARSER_INT_STATUS) >> 6) & 0x1; + /* error watchdog */ + if (empty_flag == 0) { + /* decoder has input */ + if ((debug & AVS2_DBG_DIS_LOC_ERROR_PROC) == 0) { + + buf_level = READ_VREG(HEVC_STREAM_LEVEL); + /* receiver has no buffer to recycle */ + if ((state == RECEIVER_INACTIVE) && + (kfifo_is_empty(&dec->display_q) && + buf_level > 0x200) + ) { + WRITE_VREG + (HEVC_ASSIST_MBOX0_IRQ_REG, + 0x1); + } + } + + if ((debug & AVS2_DBG_DIS_SYS_ERROR_PROC) == 0) { + /* receiver has no buffer to recycle */ + /*if ((state == RECEIVER_INACTIVE) && + (kfifo_is_empty(&dec->display_q))) { + pr_info("avs2 something error,need reset\n"); + }*/ + } + } + } else { + if ( + (decode_timeout_val > 0) && + (dec->start_process_time > 0) && + ((1000 * (jiffies - dec->start_process_time) / HZ) + > decode_timeout_val) + ) { + int current_lcu_idx = + READ_VREG(HEVC_PARSER_LCU_START) + & 0xffffff; + if (dec->last_lcu_idx == current_lcu_idx) { + if (dec->decode_timeout_count > 0) + dec->decode_timeout_count--; + if (dec->decode_timeout_count == 0) { + if (input_frame_based( + hw_to_vdec(dec)) || + (READ_VREG(HEVC_STREAM_LEVEL) > 0x200)) + timeout_process(dec); + else { + avs2_print(dec, 0, + "timeout & empty, again\n"); + dec_again_process(dec); + } + } + } else { + start_process_time(dec); + dec->last_lcu_idx = current_lcu_idx; + } + } + } + + if ((dec->ucode_pause_pos != 0) && + (dec->ucode_pause_pos != 0xffffffff) && + udebug_pause_pos != dec->ucode_pause_pos) { + dec->ucode_pause_pos = 0; + WRITE_HREG(DEBUG_REG1, 0); + } + if (debug & AVS2_DBG_DUMP_DATA) { + debug &= ~AVS2_DBG_DUMP_DATA; + avs2_print(dec, 0, + "%s: chunk size 0x%x off 0x%x sum 0x%x\n", + __func__, + dec->chunk->size, + dec->chunk->offset, + get_data_check_sum(dec, dec->chunk->size) + ); + dump_data(dec, dec->chunk->size); + } + if (debug & AVS2_DBG_DUMP_PIC_LIST) { + dump_pic_list(dec); + debug &= ~AVS2_DBG_DUMP_PIC_LIST; + } + if (debug & AVS2_DBG_TRIG_SLICE_SEGMENT_PROC) { + WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG, 0x1); + debug &= ~AVS2_DBG_TRIG_SLICE_SEGMENT_PROC; + } + if (debug & AVS2_DBG_DUMP_RPM_BUF) { + int i; + + pr_info("RPM:\n"); + for (i = 0; i < RPM_BUF_SIZE; i += 4) { + int ii; + if ((i & 0xf) == 0) + pr_info("%03x: ", i); + for (ii = 0; ii < 4; ii++) { + pr_info("%04x ", + dec->lmem_ptr[i + 3 - ii]); + } + if (((i + ii) & 0xf) == 0) + pr_info("\n"); + } + debug &= ~AVS2_DBG_DUMP_RPM_BUF; + } + if (debug & AVS2_DBG_DUMP_LMEM_BUF) { + int i; + + pr_info("LMEM:\n"); + for (i = 0; i < LMEM_BUF_SIZE; i += 4) { + int ii; + if ((i & 0xf) == 0) + pr_info("%03x: ", i); + for (ii = 0; ii < 4; ii++) { + pr_info("%04x ", + dec->lmem_ptr[i + 3 - ii]); + } + if (((i + ii) & 0xf) == 0) + pr_info("\n"); + } + debug &= ~AVS2_DBG_DUMP_LMEM_BUF; + } + /*if (debug & AVS2_DBG_HW_RESET) { + }*/ + + if (radr != 0) { + if (rval != 0) { + WRITE_VREG(radr, rval); + pr_info("WRITE_VREG(%x,%x)\n", radr, rval); + } else + pr_info("READ_VREG(%x)=%x\n", radr, READ_VREG(radr)); + rval = 0; + radr = 0; + } + if (pop_shorts != 0) { + int i; + u32 sum = 0; + pr_info("pop stream 0x%x shorts\r\n", pop_shorts); + for (i = 0; i < pop_shorts; i++) { + u32 data = + (READ_HREG(HEVC_SHIFTED_DATA) >> 16); + WRITE_HREG(HEVC_SHIFT_COMMAND, + (1<<7)|16); + if ((i & 0xf) == 0) + pr_info("%04x:", i); + pr_info("%04x ", data); + if (((i + 1) & 0xf) == 0) + pr_info("\r\n"); + sum += data; + } + pr_info("\r\nsum = %x\r\n", sum); + pop_shorts = 0; + } + if (dbg_cmd != 0) { + if (dbg_cmd == 1) { + u32 disp_laddr; + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXBB && + get_double_write_mode(dec) == 0) { + disp_laddr = + READ_VCBUS_REG(AFBC_BODY_BADDR) << 4; + } else { + struct canvas_s cur_canvas; + canvas_read((READ_VCBUS_REG(VD1_IF0_CANVAS0) + & 0xff), &cur_canvas); + disp_laddr = cur_canvas.addr; + } + pr_info("current displayed buffer address %x\r\n", + disp_laddr); + } + dbg_cmd = 0; + } + /*don't changed at start.*/ + if (dec->get_frame_dur && dec->show_frame_num > 60 && + dec->frame_dur > 0 && dec->saved_resolution != + frame_width * frame_height * + (96000 / dec->frame_dur)) { + int fps = 96000 / dec->frame_dur; + if (hevc_source_changed(VFORMAT_AVS2, + frame_width, frame_height, fps) > 0) + dec->saved_resolution = frame_width * + frame_height * fps; + } + + timer->expires = jiffies + PUT_INTERVAL; + add_timer(timer); +} + + +int vavs2_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus) +{ + struct AVS2Decoder_s *dec = + (struct AVS2Decoder_s *)vdec->private; + + if (!dec) + return -1; + + vstatus->frame_width = dec->frame_width; + vstatus->frame_height = dec->frame_height; + + if (dec->frame_dur != 0) + vstatus->frame_rate = ((96000 * 10 / dec->frame_dur) % 10) < 5 ? + 96000 / dec->frame_dur : (96000 / dec->frame_dur +1); + else + vstatus->frame_rate = -1; + vstatus->error_count = 0; + vstatus->status = dec->stat | dec->fatal_error; + vstatus->frame_dur = dec->frame_dur; + vstatus->bit_rate = dec->gvs->bit_rate; + vstatus->frame_data = dec->gvs->frame_data; + vstatus->total_data = dec->gvs->total_data; + vstatus->frame_count = dec->gvs->frame_count; + vstatus->error_frame_count = dec->gvs->error_frame_count; + vstatus->drop_frame_count = dec->gvs->drop_frame_count; + vstatus->i_decoded_frames = dec->gvs->i_decoded_frames; + vstatus->i_lost_frames = dec->gvs->i_lost_frames; + vstatus->i_concealed_frames = dec->gvs->i_concealed_frames; + vstatus->p_decoded_frames = dec->gvs->p_decoded_frames; + vstatus->p_lost_frames = dec->gvs->p_lost_frames; + vstatus->p_concealed_frames = dec->gvs->p_concealed_frames; + vstatus->b_decoded_frames = dec->gvs->b_decoded_frames; + vstatus->b_lost_frames = dec->gvs->b_lost_frames; + vstatus->b_concealed_frames = dec->gvs->b_concealed_frames; + vstatus->total_data = dec->gvs->total_data; + vstatus->samp_cnt = dec->gvs->samp_cnt; + vstatus->offset = dec->gvs->offset; + snprintf(vstatus->vdec_name, sizeof(vstatus->vdec_name), + "%s", DRIVER_NAME); + return 0; +} + +int vavs2_set_isreset(struct vdec_s *vdec, int isreset) +{ + is_reset = isreset; + return 0; +} + +static void vavs2_prot_init(struct AVS2Decoder_s *dec) +{ + unsigned int data32; + + avs2_config_work_space_hw(dec); + if (dec->pic_list_init_flag) + init_pic_list_hw(dec); + + avs2_init_decoder_hw(dec); + +#if 1 + avs2_print(dec, AVS2_DBG_BUFMGR_MORE, + "%s\n", __func__); + data32 = READ_VREG(HEVC_STREAM_CONTROL); + data32 = data32 | + (1 << 0)/*stream_fetch_enable*/ + ; + WRITE_VREG(HEVC_STREAM_CONTROL, data32); +#if 0 + data32 = READ_VREG(HEVC_SHIFT_STARTCODE); + if (data32 != 0x00000100) { + pr_info("avs2 prot init error %d\n", __LINE__); + return; + } + data32 = READ_VREG(HEVC_SHIFT_EMULATECODE); + if (data32 != 0x00000300) { + pr_info("avs2 prot init error %d\n", __LINE__); + return; + } + WRITE_VREG(HEVC_SHIFT_STARTCODE, 0x12345678); + WRITE_VREG(HEVC_SHIFT_EMULATECODE, 0x9abcdef0); + data32 = READ_VREG(HEVC_SHIFT_STARTCODE); + if (data32 != 0x12345678) { + pr_info("avs2 prot init error %d\n", __LINE__); + return; + } + data32 = READ_VREG(HEVC_SHIFT_EMULATECODE); + if (data32 != 0x9abcdef0) { + pr_info("avs2 prot init error %d\n", __LINE__); + return; + } +#endif + WRITE_VREG(HEVC_SHIFT_STARTCODE, 0x00000100); + WRITE_VREG(HEVC_SHIFT_EMULATECODE, 0x00000000); +#endif + + + + WRITE_VREG(HEVC_WAIT_FLAG, 1); + + /* WRITE_VREG(HEVC_MPSR, 1); */ + + /* clear mailbox interrupt */ + WRITE_VREG(HEVC_ASSIST_MBOX0_CLR_REG, 1); + + /* enable mailbox interrupt */ + WRITE_VREG(HEVC_ASSIST_MBOX0_MASK, 1); + + /* disable PSCALE for hardware sharing */ + WRITE_VREG(HEVC_PSCALE_CTRL, 0); + + WRITE_VREG(DEBUG_REG1, 0x0); + /*check vps/sps/pps/i-slice in ucode*/ + WRITE_VREG(NAL_SEARCH_CTL, 0x8); + + WRITE_VREG(DECODE_STOP_POS, udebug_flag); + + config_cuva_buf(dec); +} + +#ifdef I_ONLY_SUPPORT +static int vavs2_set_trickmode(struct vdec_s *vdec, unsigned long trickmode) +{ + struct AVS2Decoder_s *dec = + (struct AVS2Decoder_s *)vdec->private; + if (i_only_flag & 0x100) + return 0; + if (trickmode == TRICKMODE_I || trickmode == TRICKMODE_I_HEVC) + dec->i_only = 0x3; + else if (trickmode == TRICKMODE_NONE) + dec->i_only = 0x0; + return 0; +} +#endif + +static int vavs2_local_init(struct AVS2Decoder_s *dec) +{ + int i; + int ret; + int width, height; + + dec->gvs = vzalloc(sizeof(struct vdec_info)); + if (NULL == dec->gvs) { + avs2_print(dec, 0, + "the struct of vdec status malloc failed.\n"); + return -1; + } +#ifdef DEBUG_PTS + dec->pts_missed = 0; + dec->pts_hit = 0; +#endif + dec->new_frame_displayed = 0; + dec->last_put_idx = -1; + dec->saved_resolution = 0; + dec->get_frame_dur = false; + on_no_keyframe_skiped = 0; + width = dec->vavs2_amstream_dec_info.width; + height = dec->vavs2_amstream_dec_info.height; + dec->frame_dur = + (dec->vavs2_amstream_dec_info.rate == + 0) ? 3600 : dec->vavs2_amstream_dec_info.rate; + if (width && height) + dec->frame_ar = height * 0x100 / width; +/* +TODO:FOR VERSION +*/ + avs2_print(dec, AVS2_DBG_BUFMGR, + "avs2: ver (%d,%d) decinfo: %dx%d rate=%d\n", avs2_version, + 0, width, height, dec->frame_dur); + + if (dec->frame_dur == 0) + dec->frame_dur = 96000 / 24; +#ifdef I_ONLY_SUPPORT + if (i_only_flag & 0x100) + dec->i_only = i_only_flag & 0xff; + else if ((unsigned long) dec->vavs2_amstream_dec_info.param + & 0x08) + dec->i_only = 0x7; + else + dec->i_only = 0x0; +#endif + INIT_KFIFO(dec->display_q); + INIT_KFIFO(dec->newframe_q); + + + for (i = 0; i < VF_POOL_SIZE; i++) { + const struct vframe_s *vf = &dec->vfpool[i]; + dec->vfpool[i].index = -1; + kfifo_put(&dec->newframe_q, vf); + } + + + ret = avs2_local_init(dec); + + return ret; +} + + +static s32 vavs2_init(struct vdec_s *vdec) +{ + int ret = -1, size = -1; + int fw_size = 0x1000 * 16; + struct firmware_s *fw = NULL; + struct AVS2Decoder_s *dec = (struct AVS2Decoder_s *)vdec->private; + + timer_setup(&dec->timer, vavs2_put_timer_func, 0); + + dec->stat |= STAT_TIMER_INIT; + if (vavs2_local_init(dec) < 0) + return -EBUSY; + + vdec_set_vframe_comm(vdec, DRIVER_NAME); + + fw = vmalloc(sizeof(struct firmware_s) + fw_size); + if (IS_ERR_OR_NULL(fw)) + return -ENOMEM; + + size = get_firmware_data(VIDEO_DEC_AVS2_MMU, fw->data); + if (size < 0) { + pr_err("get firmware fail.\n"); + vfree(fw); + return -1; + } + + fw->len = fw_size; + + if (dec->m_ins_flag) { + dec->timer.expires = jiffies + PUT_INTERVAL; + + /*add_timer(&dec->timer); + + dec->stat |= STAT_TIMER_ARM; + dec->stat |= STAT_ISR_REG;*/ + + INIT_WORK(&dec->work, avs2_work); + dec->fw = fw; + + return 0; + } + + amhevc_enable(); + + ret = amhevc_loadmc_ex(VFORMAT_AVS2, NULL, fw->data); + if (ret < 0) { + amhevc_disable(); + vfree(fw); + pr_err("AVS2: the %s fw loading failed, err: %x\n", + tee_enabled() ? "TEE" : "local", ret); + return -EBUSY; + } + + vfree(fw); + + dec->stat |= STAT_MC_LOAD; + + /* enable AMRISC side protocol */ + vavs2_prot_init(dec); + + if (vdec_request_threaded_irq(VDEC_IRQ_0, + vavs2_isr, + vavs2_isr_thread_fn, + IRQF_ONESHOT,/*run thread on this irq disabled*/ + "vavs2-irq", (void *)dec)) { + pr_info("vavs2 irq register error.\n"); + amhevc_disable(); + return -ENOENT; + } + + dec->stat |= STAT_ISR_REG; + + dec->provider_name = PROVIDER_NAME; + vf_provider_init(&vavs2_vf_prov, PROVIDER_NAME, + &vavs2_vf_provider, dec); + vf_reg_provider(&vavs2_vf_prov); + vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_START, NULL); + if (dec->frame_dur != 0) { + if (!is_reset) + vf_notify_receiver(dec->provider_name, + VFRAME_EVENT_PROVIDER_FR_HINT, + (void *) + ((unsigned long)dec->frame_dur)); + } + dec->stat |= STAT_VF_HOOK; + + dec->timer.expires = jiffies + PUT_INTERVAL; + add_timer(&dec->timer); + + dec->stat |= STAT_TIMER_ARM; + + /* dec->stat |= STAT_KTHREAD; */ + dec->process_busy = 0; + avs2_print(dec, AVS2_DBG_BUFMGR_MORE, + "%d, vavs2_init, RP=0x%x\n", + __LINE__, READ_VREG(HEVC_STREAM_RD_PTR)); + return 0; +} + +static int vmavs2_stop(struct AVS2Decoder_s *dec) +{ + dec->init_flag = 0; + dec->first_sc_checked = 0; + if (dec->stat & STAT_TIMER_ARM) { + del_timer_sync(&dec->timer); + dec->stat &= ~STAT_TIMER_ARM; + } + + if (dec->stat & STAT_VF_HOOK) { + if (!is_reset) + vf_notify_receiver(dec->provider_name, + VFRAME_EVENT_PROVIDER_FR_END_HINT, + NULL); + + vf_unreg_provider(&vavs2_vf_prov); + dec->stat &= ~STAT_VF_HOOK; + } + avs2_local_uninit(dec); + reset_process_time(dec); + cancel_work_sync(&dec->work); + uninit_mmu_buffers(dec); + if (dec->fw) { + vfree(dec->fw); + dec->fw = NULL; + } + + return 0; +} + +static int amvdec_avs2_mmu_init(struct AVS2Decoder_s *dec) +{ + int tvp_flag = vdec_secure(hw_to_vdec(dec)) ? + CODEC_MM_FLAGS_TVP : 0; + int buf_size = 48; + +#ifdef AVS2_10B_MMU + dec->need_cache_size = buf_size * SZ_1M; + dec->sc_start_time = get_jiffies_64(); + dec->mmu_box = decoder_mmu_box_alloc_box(DRIVER_NAME, + dec->index, FRAME_BUFFERS, + dec->need_cache_size, + tvp_flag + ); + if (!dec->mmu_box) { + pr_err("avs2 alloc mmu box failed!!\n"); + return -1; + } +#endif + dec->bmmu_box = decoder_bmmu_box_alloc_box( + DRIVER_NAME, + dec->index, + MAX_BMMU_BUFFER_NUM, + 4 + PAGE_SHIFT, + CODEC_MM_FLAGS_CMA_CLEAR | + CODEC_MM_FLAGS_FOR_VDECODER | + tvp_flag); + if (!dec->bmmu_box) { + pr_err("avs2 alloc bmmu box failed!!\n"); + return -1; + } + return 0; +} + +/****************************************/ +static struct codec_profile_t amvdec_avs2_profile = { + .name = "AVS2-V4L", + .profile = "" +}; + +static unsigned char get_data_check_sum + (struct AVS2Decoder_s *dec, int size) +{ + int jj; + int sum = 0; + u8 *data = NULL; + + if (!dec->chunk->block->is_mapped) + data = codec_mm_vmap(dec->chunk->block->start + + dec->chunk->offset, size); + else + data = ((u8 *)dec->chunk->block->start_virt) + + dec->chunk->offset; + + for (jj = 0; jj < size; jj++) + sum += data[jj]; + + if (!dec->chunk->block->is_mapped) + codec_mm_unmap_phyaddr(data); + return sum; +} + +static void dump_data(struct AVS2Decoder_s *dec, int size) +{ + int jj; + u8 *data = NULL; + int padding_size = dec->chunk->offset & + (VDEC_FIFO_ALIGN - 1); + + if (!dec->chunk->block->is_mapped) + data = codec_mm_vmap(dec->chunk->block->start + + dec->chunk->offset, size); + else + data = ((u8 *)dec->chunk->block->start_virt) + + dec->chunk->offset; + + avs2_print(dec, 0, "padding: "); + for (jj = padding_size; jj > 0; jj--) + avs2_print_cont(dec, + 0, + "%02x ", *(data - jj)); + avs2_print_cont(dec, 0, "data adr %p\n", + data); + + for (jj = 0; jj < size; jj++) { + if ((jj & 0xf) == 0) + avs2_print(dec, + 0, + "%06x:", jj); + avs2_print_cont(dec, + 0, + "%02x ", data[jj]); + if (((jj + 1) & 0xf) == 0) + avs2_print(dec, + 0, + "\n"); + } + avs2_print(dec, + 0, + "\n"); + + if (!dec->chunk->block->is_mapped) + codec_mm_unmap_phyaddr(data); +} + +static void avs2_work(struct work_struct *work) +{ + struct AVS2Decoder_s *dec = container_of(work, + struct AVS2Decoder_s, work); + struct vdec_s *vdec = hw_to_vdec(dec); + /* finished decoding one frame or error, + * notify vdec core to switch context + */ + avs2_print(dec, PRINT_FLAG_VDEC_DETAIL, + "%s dec_result %d %x %x %x\n", + __func__, + dec->dec_result, + READ_VREG(HEVC_STREAM_LEVEL), + READ_VREG(HEVC_STREAM_WR_PTR), + READ_VREG(HEVC_STREAM_RD_PTR)); + + if (((dec->dec_result == DEC_RESULT_GET_DATA) || + (dec->dec_result == DEC_RESULT_GET_DATA_RETRY)) + && (hw_to_vdec(dec)->next_status != + VDEC_STATUS_DISCONNECTED)) { + if (!vdec_has_more_input(vdec)) { + dec->dec_result = DEC_RESULT_EOS; + vdec_schedule_work(&dec->work); + return; + } + + if (dec->dec_result == DEC_RESULT_GET_DATA) { + avs2_print(dec, PRINT_FLAG_VDEC_STATUS, + "%s DEC_RESULT_GET_DATA %x %x %x\n", + __func__, + READ_VREG(HEVC_STREAM_LEVEL), + READ_VREG(HEVC_STREAM_WR_PTR), + READ_VREG(HEVC_STREAM_RD_PTR)); + vdec_vframe_dirty(vdec, dec->chunk); + vdec_clean_input(vdec); + } + + if (get_free_buf_count(dec) >= + run_ready_min_buf_num) { + int r; + int decode_size; + r = vdec_prepare_input(vdec, &dec->chunk); + if (r < 0) { + dec->dec_result = DEC_RESULT_GET_DATA_RETRY; + + avs2_print(dec, + PRINT_FLAG_VDEC_DETAIL, + "amvdec_vh265: Insufficient data\n"); + + vdec_schedule_work(&dec->work); + return; + } + dec->dec_result = DEC_RESULT_NONE; + avs2_print(dec, PRINT_FLAG_VDEC_STATUS, + "%s: chunk size 0x%x sum 0x%x\n", + __func__, r, + (debug & PRINT_FLAG_VDEC_STATUS) ? + get_data_check_sum(dec, r) : 0 + ); + if (debug & PRINT_FLAG_VDEC_DATA) + dump_data(dec, dec->chunk->size); + + decode_size = dec->chunk->size + + (dec->chunk->offset & (VDEC_FIFO_ALIGN - 1)); + + WRITE_VREG(HEVC_DECODE_SIZE, + READ_VREG(HEVC_DECODE_SIZE) + decode_size); + + vdec_enable_input(vdec); + + WRITE_VREG(HEVC_DEC_STATUS_REG, AVS2_ACTION_DONE); + + start_process_time(dec); + + } else{ + dec->dec_result = DEC_RESULT_GET_DATA_RETRY; + + avs2_print(dec, PRINT_FLAG_VDEC_DETAIL, + "amvdec_vh265: Insufficient data\n"); + + vdec_schedule_work(&dec->work); + } + return; + } else if (dec->dec_result == DEC_RESULT_DONE) { + /* if (!dec->ctx_valid) + dec->ctx_valid = 1; */ + dec->slice_idx++; + dec->frame_count++; + dec->process_state = PROC_STATE_INIT; + decode_frame_count[dec->index] = dec->frame_count; + +#ifdef AVS2_10B_MMU + dec->used_4k_num = + (READ_VREG(HEVC_SAO_MMU_STATUS) >> 16); +#endif + avs2_print(dec, PRINT_FLAG_VDEC_STATUS, + "%s (===> %d) dec_result %d %x %x %x shiftbytes 0x%x decbytes 0x%x\n", + __func__, + dec->frame_count, + dec->dec_result, + READ_VREG(HEVC_STREAM_LEVEL), + READ_VREG(HEVC_STREAM_WR_PTR), + READ_VREG(HEVC_STREAM_RD_PTR), + READ_VREG(HEVC_SHIFT_BYTE_COUNT), + READ_VREG(HEVC_SHIFT_BYTE_COUNT) - + dec->start_shift_bytes + ); + vdec_vframe_dirty(hw_to_vdec(dec), dec->chunk); + } else if (dec->dec_result == DEC_RESULT_AGAIN) { + /* + stream base: stream buf empty or timeout + frame base: vdec_prepare_input fail + */ + if (!vdec_has_more_input(vdec)) { + dec->dec_result = DEC_RESULT_EOS; + vdec_schedule_work(&dec->work); + return; + } + } else if (dec->dec_result == DEC_RESULT_EOS) { + avs2_print(dec, 0, + "%s: end of stream\n", + __func__); + dec->eos = 1; + if ( dec->avs2_dec.hc.cur_pic != NULL) { + check_pic_error(dec, dec->avs2_dec.hc.cur_pic); + avs2_post_process(&dec->avs2_dec); + avs2_prepare_display_buf(dec); + } + vdec_vframe_dirty(hw_to_vdec(dec), dec->chunk); + } else if (dec->dec_result == DEC_RESULT_FORCE_EXIT) { + avs2_print(dec, PRINT_FLAG_VDEC_STATUS, + "%s: force exit\n", + __func__); + if (dec->stat & STAT_VDEC_RUN) { + amhevc_stop(); + dec->stat &= ~STAT_VDEC_RUN; + } + + if (dec->stat & STAT_ISR_REG) { + if (!dec->m_ins_flag) + WRITE_VREG(HEVC_ASSIST_MBOX0_MASK, 0); + vdec_free_irq(VDEC_IRQ_0, (void *)dec); + dec->stat &= ~STAT_ISR_REG; + } + } + + if (dec->stat & STAT_TIMER_ARM) { + del_timer_sync(&dec->timer); + dec->stat &= ~STAT_TIMER_ARM; + } + /* mark itself has all HW resource released and input released */ + if (vdec->parallel_dec ==1) + vdec_core_finish_run(vdec, CORE_MASK_HEVC); + else + vdec_core_finish_run(vdec, CORE_MASK_VDEC_1 | CORE_MASK_HEVC); + + if (dec->vdec_cb) + dec->vdec_cb(hw_to_vdec(dec), dec->vdec_cb_arg); +} + +static int avs2_hw_ctx_restore(struct AVS2Decoder_s *dec) +{ + /* new to do ... */ + vavs2_prot_init(dec); + return 0; +} + +static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) +{ + struct AVS2Decoder_s *dec = + (struct AVS2Decoder_s *)vdec->private; + int tvp = vdec_secure(hw_to_vdec(dec)) ? + CODEC_MM_FLAGS_TVP : 0; + unsigned long ret = 0; + avs2_print(dec, + PRINT_FLAG_VDEC_DETAIL, "%s\r\n", __func__); + if (debug & AVS2_DBG_PIC_LEAK_WAIT) + return ret; + + if (dec->eos) + return ret; + if (!dec->first_sc_checked) { + int size = decoder_mmu_box_sc_check(dec->mmu_box, tvp); + dec->first_sc_checked = 1; + avs2_print(dec, 0, "vavs2 cached=%d need_size=%d speed= %d ms\n", + size, (dec->need_cache_size >> PAGE_SHIFT), + (int)(get_jiffies_64() - dec->sc_start_time) * 1000/HZ); + } + + if (dec->next_again_flag && + (!vdec_frame_based(vdec))) { + u32 parser_wr_ptr = + STBUF_READ(&vdec->vbuf, get_wp); + if (parser_wr_ptr >= dec->pre_parser_wr_ptr && + (parser_wr_ptr - dec->pre_parser_wr_ptr) < + again_threshold) { + int r = vdec_sync_input(vdec); + avs2_print(dec, + PRINT_FLAG_VDEC_DETAIL, "%s buf lelvel:%x\n", __func__, r); + return 0; + } + } +/* + if (vdec_stream_based(vdec) && (dec->pic_list_init_flag == 0) + && pre_decode_buf_level != 0) { + u32 rp, wp, level; + + rp = STBUF_READ(&vdec->vbuf, get_rp); + wp = STBUF_READ(&vdec->vbuf, get_wp); + if (wp < rp) + level = vdec->input.size + wp - rp; + else + level = wp - rp; + + if (level < pre_decode_buf_level) + return 0; + } +*/ + + if ((dec->pic_list_init_flag == 0) || + get_free_buf_count(dec) >= + run_ready_min_buf_num) + ret = 1; +#ifdef CONSTRAIN_MAX_BUF_NUM + if (dec->pic_list_init_flag) { + if (run_ready_max_vf_only_num > 0 && + get_vf_ref_only_buf_count(dec) >= + run_ready_max_vf_only_num + ) + ret = 0; + if (run_ready_display_q_num > 0 && + kfifo_len(&dec->display_q) >= + run_ready_display_q_num) + ret = 0; + + if (run_ready_max_buf_num == 0xff && + get_used_buf_count(dec) >= + dec->avs2_dec.ref_maxbuffer) + ret = 0; + else if (run_ready_max_buf_num && + get_used_buf_count(dec) >= + run_ready_max_buf_num) + ret = 0; + } +#endif + if (ret) + not_run_ready[dec->index] = 0; + else + not_run_ready[dec->index]++; + + if (vdec->parallel_dec == 1) + return ret ? CORE_MASK_HEVC : 0; + else + return ret ? (CORE_MASK_VDEC_1 | CORE_MASK_HEVC) : 0; +} + +static void run(struct vdec_s *vdec, unsigned long mask, + void (*callback)(struct vdec_s *, void *), void *arg) +{ + struct AVS2Decoder_s *dec = + (struct AVS2Decoder_s *)vdec->private; + int r; + + run_count[dec->index]++; + dec->vdec_cb_arg = arg; + dec->vdec_cb = callback; + /* dec->chunk = vdec_prepare_input(vdec); */ + hevc_reset_core(vdec); + + if (vdec_stream_based(vdec)) { + dec->pre_parser_wr_ptr = + STBUF_READ(&vdec->vbuf, get_wp); + dec->next_again_flag = 0; + } + + r = vdec_prepare_input(vdec, &dec->chunk); + if (r < 0) { + input_empty[dec->index]++; + + dec->dec_result = DEC_RESULT_AGAIN; + + avs2_print(dec, PRINT_FLAG_VDEC_DETAIL, + "ammvdec_vh265: Insufficient data\n"); + + vdec_schedule_work(&dec->work); + return; + } + input_empty[dec->index] = 0; + dec->dec_result = DEC_RESULT_NONE; + dec->start_shift_bytes = READ_VREG(HEVC_SHIFT_BYTE_COUNT); + + if (debug & PRINT_FLAG_VDEC_STATUS) { + int ii; + avs2_print(dec, 0, + "%s (%d): size 0x%x (0x%x 0x%x) sum 0x%x (%x %x %x %x %x) bytes 0x%x", + __func__, + dec->frame_count, r, + dec->chunk ? dec->chunk->size : 0, + dec->chunk ? dec->chunk->offset : 0, + dec->chunk ? ((vdec_frame_based(vdec) && + (debug & PRINT_FLAG_VDEC_STATUS)) ? + get_data_check_sum(dec, r) : 0) : 0, + READ_VREG(HEVC_STREAM_START_ADDR), + READ_VREG(HEVC_STREAM_END_ADDR), + READ_VREG(HEVC_STREAM_LEVEL), + READ_VREG(HEVC_STREAM_WR_PTR), + READ_VREG(HEVC_STREAM_RD_PTR), + dec->start_shift_bytes); + if (vdec_frame_based(vdec) && dec->chunk) { + u8 *data = NULL; + if (!dec->chunk->block->is_mapped) + data = codec_mm_vmap(dec->chunk->block->start + + dec->chunk->offset, 8); + else + data = ((u8 *)dec->chunk->block->start_virt) + + dec->chunk->offset; + + avs2_print_cont(dec, 0, "data adr %p:", + data); + for (ii = 0; ii < 8; ii++) + avs2_print_cont(dec, 0, "%02x ", + data[ii]); + if (!dec->chunk->block->is_mapped) + codec_mm_unmap_phyaddr(data); + } + avs2_print_cont(dec, 0, "\r\n"); + } + if (vdec->mc_loaded) { + /*firmware have load before, + and not changes to another. + ignore reload. + */ + } else if (amhevc_loadmc_ex(VFORMAT_AVS2, NULL, dec->fw->data) < 0) { + vdec->mc_loaded = 0; + amhevc_disable(); + avs2_print(dec, 0, + "%s: Error amvdec_loadmc fail\n", __func__); + dec->dec_result = DEC_RESULT_FORCE_EXIT; + vdec_schedule_work(&dec->work); + return; + } else { + vdec->mc_loaded = 1; + vdec->mc_type = VFORMAT_AVS2; + } + + + if (avs2_hw_ctx_restore(dec) < 0) { + vdec_schedule_work(&dec->work); + return; + } + + vdec_enable_input(vdec); + + WRITE_VREG(HEVC_DEC_STATUS_REG, AVS2_SEARCH_NEW_PIC); + + if (vdec_frame_based(vdec) && dec->chunk) { + if (debug & PRINT_FLAG_VDEC_DATA) + dump_data(dec, dec->chunk->size); + + WRITE_VREG(HEVC_SHIFT_BYTE_COUNT, 0); + r = dec->chunk->size + + (dec->chunk->offset & (VDEC_FIFO_ALIGN - 1)); + if (vdec->mvfrm) + vdec->mvfrm->frame_size = dec->chunk->size; + } + + WRITE_VREG(HEVC_DECODE_SIZE, r); + WRITE_VREG(HEVC_DECODE_COUNT, dec->slice_idx); + dec->init_flag = 1; + + avs2_print(dec, PRINT_FLAG_VDEC_DETAIL, + "%s: start hevc (%x %x %x)\n", + __func__, + READ_VREG(HEVC_DEC_STATUS_REG), + READ_VREG(HEVC_MPC_E), + READ_VREG(HEVC_MPSR)); + + start_process_time(dec); + mod_timer(&dec->timer, jiffies); + dec->stat |= STAT_TIMER_ARM; + dec->stat |= STAT_ISR_REG; + if (vdec->mvfrm) + vdec->mvfrm->hw_decode_start = local_clock(); + amhevc_start(); + dec->stat |= STAT_VDEC_RUN; +} + +static void reset(struct vdec_s *vdec) +{ + + struct AVS2Decoder_s *dec = + (struct AVS2Decoder_s *)vdec->private; + + atomic_set(&dec->vf_pre_count, 0); + atomic_set(&dec->vf_get_count, 0); + atomic_set(&dec->vf_put_count, 0); + + avs2_print(dec, + PRINT_FLAG_VDEC_DETAIL, "%s\r\n", __func__); + +} + +static irqreturn_t avs2_irq_cb(struct vdec_s *vdec, int irq) +{ + struct AVS2Decoder_s *dec = + (struct AVS2Decoder_s *)vdec->private; + return vavs2_isr(0, dec); +} + +static irqreturn_t avs2_threaded_irq_cb(struct vdec_s *vdec, int irq) +{ + struct AVS2Decoder_s *dec = + (struct AVS2Decoder_s *)vdec->private; + return vavs2_isr_thread_fn(0, dec); +} + +static void avs2_dump_state(struct vdec_s *vdec) +{ + struct AVS2Decoder_s *dec = + (struct AVS2Decoder_s *)vdec->private; + int i; + avs2_print(dec, 0, "====== %s\n", __func__); + + avs2_print(dec, 0, + "width/height (%d/%d), used_buf_num %d\n", + dec->avs2_dec.img.width, + dec->avs2_dec.img.height, + dec->used_buf_num + ); + + avs2_print(dec, 0, + "is_framebase(%d), eos %d, dec_result 0x%x dec_frm %d disp_frm %d run %d not_run_ready %d input_empty %d\n", + input_frame_based(vdec), + dec->eos, + dec->dec_result, + decode_frame_count[dec->index], + display_frame_count[dec->index], + run_count[dec->index], + not_run_ready[dec->index], + input_empty[dec->index] + ); + + if (vf_get_receiver(vdec->vf_provider_name)) { + enum receviver_start_e state = + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_QUREY_STATE, + NULL); + avs2_print(dec, 0, + "\nreceiver(%s) state %d\n", + vdec->vf_provider_name, + state); + } + + avs2_print(dec, 0, + "%s, newq(%d/%d), dispq(%d/%d), vf prepare/get/put (%d/%d/%d), free_buf_count %d (min %d for run_ready)\n", + __func__, + kfifo_len(&dec->newframe_q), + VF_POOL_SIZE, + kfifo_len(&dec->display_q), + VF_POOL_SIZE, + dec->vf_pre_count, + dec->vf_get_count, + dec->vf_put_count, + get_free_buf_count(dec), + run_ready_min_buf_num + ); + + dump_pic_list(dec); + + for (i = 0; i < MAX_BUF_NUM; i++) { + avs2_print(dec, 0, + "mv_Buf(%d) start_adr 0x%x size 0x%x used %d\n", + i, + dec->m_mv_BUF[i].start_adr, + dec->m_mv_BUF[i].size, + dec->m_mv_BUF[i].used_flag); + } + + avs2_print(dec, 0, + "HEVC_DEC_STATUS_REG=0x%x\n", + READ_VREG(HEVC_DEC_STATUS_REG)); + avs2_print(dec, 0, + "HEVC_MPC_E=0x%x\n", + READ_VREG(HEVC_MPC_E)); + avs2_print(dec, 0, + "DECODE_MODE=0x%x\n", + READ_VREG(DECODE_MODE)); + avs2_print(dec, 0, + "NAL_SEARCH_CTL=0x%x\n", + READ_VREG(NAL_SEARCH_CTL)); + avs2_print(dec, 0, + "HEVC_PARSER_LCU_START=0x%x\n", + READ_VREG(HEVC_PARSER_LCU_START)); + avs2_print(dec, 0, + "HEVC_DECODE_SIZE=0x%x\n", + READ_VREG(HEVC_DECODE_SIZE)); + avs2_print(dec, 0, + "HEVC_SHIFT_BYTE_COUNT=0x%x\n", + READ_VREG(HEVC_SHIFT_BYTE_COUNT)); + avs2_print(dec, 0, + "HEVC_STREAM_START_ADDR=0x%x\n", + READ_VREG(HEVC_STREAM_START_ADDR)); + avs2_print(dec, 0, + "HEVC_STREAM_END_ADDR=0x%x\n", + READ_VREG(HEVC_STREAM_END_ADDR)); + avs2_print(dec, 0, + "HEVC_STREAM_LEVEL=0x%x\n", + READ_VREG(HEVC_STREAM_LEVEL)); + avs2_print(dec, 0, + "HEVC_STREAM_WR_PTR=0x%x\n", + READ_VREG(HEVC_STREAM_WR_PTR)); + avs2_print(dec, 0, + "HEVC_STREAM_RD_PTR=0x%x\n", + READ_VREG(HEVC_STREAM_RD_PTR)); + avs2_print(dec, 0, + "PARSER_VIDEO_RP=0x%x\n", + STBUF_READ(&vdec->vbuf, get_rp)); + avs2_print(dec, 0, + "PARSER_VIDEO_WP=0x%x\n", + STBUF_READ(&vdec->vbuf, get_wp)); + + if (input_frame_based(vdec) && + (debug & PRINT_FLAG_VDEC_DATA) + ) { + int jj; + if (dec->chunk && dec->chunk->block && + dec->chunk->size > 0) { + u8 *data = NULL; + if (!dec->chunk->block->is_mapped) + data = codec_mm_vmap(dec->chunk->block->start + + dec->chunk->offset, dec->chunk->size); + else + data = ((u8 *)dec->chunk->block->start_virt) + + dec->chunk->offset; + avs2_print(dec, 0, + "frame data size 0x%x\n", + dec->chunk->size); + for (jj = 0; jj < dec->chunk->size; jj++) { + if ((jj & 0xf) == 0) + avs2_print(dec, 0, + "%06x:", jj); + avs2_print_cont(dec, 0, + "%02x ", data[jj]); + if (((jj + 1) & 0xf) == 0) + avs2_print_cont(dec, 0, + "\n"); + } + + if (!dec->chunk->block->is_mapped) + codec_mm_unmap_phyaddr(data); + } + } + +} + +static int ammvdec_avs2_probe(struct platform_device *pdev) +{ + struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data; + int ret; + int config_val; + int i; + struct vframe_content_light_level_s content_light_level; + struct vframe_master_display_colour_s vf_dp; + /*struct BUF_s BUF[MAX_BUF_NUM];*/ + struct AVS2Decoder_s *dec = NULL; + + pr_info("%s\n", __func__); + if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5D) { + pr_info("%s, chip id %d is not support avs2\n", + __func__, get_cpu_major_id()); + return -1; + } + if (pdata == NULL) { + pr_info("\nammvdec_avs2 memory resource undefined.\n"); + return -EFAULT; + } + /*dec = (struct AVS2Decoder_s *)devm_kzalloc(&pdev->dev, + sizeof(struct AVS2Decoder_s), GFP_KERNEL);*/ + memset(&vf_dp, 0, sizeof(struct vframe_master_display_colour_s)); + dec = vmalloc(sizeof(struct AVS2Decoder_s)); + memset(dec, 0, sizeof(struct AVS2Decoder_s)); + if (dec == NULL) { + pr_info("\nammvdec_avs2 device data allocation failed\n"); + return -ENOMEM; + } + if (pdata->parallel_dec == 1) { + int i; + for (i = 0; i < AVS2_MAX_BUFFER_NUM; i++) { + dec->avs2_dec.frm_pool[i].y_canvas_index = -1; + dec->avs2_dec.frm_pool[i].uv_canvas_index = -1; + } + } + pdata->private = dec; + pdata->dec_status = vavs2_dec_status; +#ifdef I_ONLY_SUPPORT + pdata->set_trickmode = vavs2_set_trickmode; +#endif + pdata->run_ready = run_ready; + pdata->run = run; + pdata->reset = reset; + pdata->irq_handler = avs2_irq_cb; + pdata->threaded_irq_handler = avs2_threaded_irq_cb; + pdata->dump_state = avs2_dump_state; + + /* + * memcpy(&BUF[0], &dec->m_BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM); + * memset(dec, 0, sizeof(struct AVS2Decoder_s)); + * memcpy(&dec->m_BUF[0], &BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM); + */ + + dec->index = pdev->id; + dec->m_ins_flag = 1; + + if (is_rdma_enable()) { + dec->rdma_adr = dma_alloc_coherent(amports_get_dma_device(), RDMA_SIZE , &dec->rdma_phy_adr, GFP_KERNEL); + for (i = 0; i < SCALELUT_DATA_WRITE_NUM; i++) { + dec->rdma_adr[i * 4] = HEVC_IQIT_SCALELUT_WR_ADDR & 0xfff; + dec->rdma_adr[i * 4 + 1] = i; + dec->rdma_adr[i * 4 + 2] = HEVC_IQIT_SCALELUT_DATA & 0xfff; + dec->rdma_adr[i * 4 + 3] = 0; + if (i == SCALELUT_DATA_WRITE_NUM - 1) { + dec->rdma_adr[i * 4 + 2] = (HEVC_IQIT_SCALELUT_DATA & 0xfff) | 0x20000; + } + } + } + + snprintf(dec->vdec_name, sizeof(dec->vdec_name), + "avs2-%d", dec->index); + snprintf(dec->pts_name, sizeof(dec->pts_name), + "%s-timestamp", dec->vdec_name); + snprintf(dec->new_q_name, sizeof(dec->new_q_name), + "%s-newframe_q", dec->vdec_name); + snprintf(dec->disp_q_name, sizeof(dec->disp_q_name), + "%s-dispframe_q", dec->vdec_name); + + if (pdata->use_vfm_path) { + snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE, + VFM_DEC_PROVIDER_NAME); + dec->frameinfo_enable = 1; + } else + snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE, + MULTI_INSTANCE_PROVIDER_NAME ".%02x", pdev->id & 0xff); + + vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name, + &vavs2_vf_provider, dec); + + dec->provider_name = pdata->vf_provider_name; + platform_set_drvdata(pdev, pdata); + + dec->platform_dev = pdev; + dec->video_signal_type = 0; + dec->video_ori_signal_type = 0; + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_TXLX) + dec->stat |= VP9_TRIGGER_FRAME_ENABLE; +#if 1 + if ((debug & IGNORE_PARAM_FROM_CONFIG) == 0 && + pdata->config_len) { + /*use ptr config for doubel_write_mode, etc*/ + avs2_print(dec, 0, "pdata->config=%s\n", pdata->config); + if (get_config_int(pdata->config, "avs2_double_write_mode", + &config_val) == 0) + dec->double_write_mode = config_val; + else + dec->double_write_mode = double_write_mode; + + if (get_config_int(pdata->config, "parm_v4l_buffer_margin", + &config_val) == 0) + dec->dynamic_buf_margin = config_val; + else + dec->dynamic_buf_margin = 0; + + if (get_config_int(pdata->config, "sidebind_type", + &config_val) == 0) + dec->sidebind_type = config_val; + + if (get_config_int(pdata->config, "sidebind_channel_id", + &config_val) == 0) + dec->sidebind_channel_id = config_val; + + if (get_config_int(pdata->config, "HDRStaticInfo", + &vf_dp.present_flag) == 0 + && vf_dp.present_flag == 1) { + get_config_int(pdata->config, "mG.x", + &vf_dp.primaries[0][0]); + get_config_int(pdata->config, "mG.y", + &vf_dp.primaries[0][1]); + get_config_int(pdata->config, "mB.x", + &vf_dp.primaries[1][0]); + get_config_int(pdata->config, "mB.y", + &vf_dp.primaries[1][1]); + get_config_int(pdata->config, "mR.x", + &vf_dp.primaries[2][0]); + get_config_int(pdata->config, "mR.y", + &vf_dp.primaries[2][1]); + get_config_int(pdata->config, "mW.x", + &vf_dp.white_point[0]); + get_config_int(pdata->config, "mW.y", + &vf_dp.white_point[1]); + get_config_int(pdata->config, "mMaxDL", + &vf_dp.luminance[0]); + get_config_int(pdata->config, "mMinDL", + &vf_dp.luminance[1]); + vf_dp.content_light_level.present_flag = 1; + get_config_int(pdata->config, "mMaxCLL", + &content_light_level.max_content); + get_config_int(pdata->config, "mMaxFALL", + &content_light_level.max_pic_average); + vf_dp.content_light_level = content_light_level; + dec->video_signal_type = (1 << 29) + | (5 << 26) /* unspecified */ + | (0 << 25) /* limit */ + | (1 << 24) /* color available */ + | (9 << 16) /* 2020 */ + | (16 << 8) /* 2084 */ + | (9 << 0); /* 2020 */ + } + dec->vf_dp = vf_dp; + } else +#endif + { + /*dec->vavs2_amstream_dec_info.width = 0; + dec->vavs2_amstream_dec_info.height = 0; + dec->vavs2_amstream_dec_info.rate = 30;*/ + dec->double_write_mode = double_write_mode; + dec->dynamic_buf_margin = dynamic_buf_num_margin; + } + video_signal_type = dec->video_signal_type; + +#if 0 + dec->buf_start = pdata->mem_start; + dec->buf_size = pdata->mem_end - pdata->mem_start + 1; +#else + if (amvdec_avs2_mmu_init(dec) < 0) { + pr_err("avs2 alloc bmmu box failed!!\n"); + /* devm_kfree(&pdev->dev, (void *)dec); */ + vfree((void *)dec); + return -1; + } + dec->cma_alloc_count = PAGE_ALIGN(work_buf_size) / PAGE_SIZE; + ret = decoder_bmmu_box_alloc_buf_phy(dec->bmmu_box, WORK_SPACE_BUF_ID, + dec->cma_alloc_count * PAGE_SIZE, DRIVER_NAME, + &dec->cma_alloc_addr); + if (ret < 0) { + uninit_mmu_buffers(dec); + /* devm_kfree(&pdev->dev, (void *)dec); */ + vfree((void *)dec); + return ret; + } + dec->buf_start = dec->cma_alloc_addr; + dec->buf_size = work_buf_size; +#endif + dec->init_flag = 0; + dec->first_sc_checked = 0; + dec->fatal_error = 0; + dec->show_frame_num = 0; + + if (debug) { + pr_info("===AVS2 decoder mem resource 0x%lx size 0x%x\n", + dec->buf_start, + dec->buf_size); + } + + if (pdata->sys_info) { + dec->vavs2_amstream_dec_info = *pdata->sys_info; + dec->frame_width = dec->vavs2_amstream_dec_info.width; + dec->frame_height = dec->vavs2_amstream_dec_info.height; + } else { + dec->vavs2_amstream_dec_info.width = 0; + dec->vavs2_amstream_dec_info.height = 0; + dec->vavs2_amstream_dec_info.rate = 30; + } + + dec->endian = HEVC_CONFIG_LITTLE_ENDIAN; + if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T7) + dec->endian = HEVC_CONFIG_BIG_ENDIAN; + if (endian) + dec->endian = endian; + + dec->cma_dev = pdata->cma_dev; + if (vavs2_init(pdata) < 0) { + pr_info("\namvdec_avs2 init failed.\n"); + avs2_local_uninit(dec); + uninit_mmu_buffers(dec); + /* devm_kfree(&pdev->dev, (void *)dec); */ + vfree((void *)dec); + pdata->dec_status = NULL; + return -ENODEV; + } + vdec_set_prepare_level(pdata, start_decode_buf_level); + hevc_source_changed(VFORMAT_AVS2, + 4096, 2048, 60); + if (pdata->parallel_dec == 1) + vdec_core_request(pdata, CORE_MASK_HEVC); + else { + vdec_core_request(pdata, CORE_MASK_VDEC_1 | CORE_MASK_HEVC + | CORE_MASK_COMBINE); + } + + return 0; +} + +static int ammvdec_avs2_remove(struct platform_device *pdev) +{ + struct AVS2Decoder_s *dec = (struct AVS2Decoder_s *) + (((struct vdec_s *)(platform_get_drvdata(pdev)))->private); + struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data; + struct avs2_decoder *avs2_dec = &dec->avs2_dec; + struct avs2_frame_s *pic; + int i; + + if (debug) + pr_info("amvdec_avs2_remove\n"); + + vmavs2_stop(dec); + + if (pdata->parallel_dec == 1) + vdec_core_release(hw_to_vdec(dec), CORE_MASK_HEVC); + else + vdec_core_release(hw_to_vdec(dec), CORE_MASK_HEVC); + + vdec_set_status(hw_to_vdec(dec), VDEC_STATUS_DISCONNECTED); + if (pdata->parallel_dec == 1) { + for (i = 0; i < AVS2_MAX_BUFFER_NUM; i++) { + pdata->free_canvas_ex(dec->avs2_dec.frm_pool[i].y_canvas_index, pdata->id); + pdata->free_canvas_ex(dec->avs2_dec.frm_pool[i].uv_canvas_index, pdata->id); + } + } + + for (i = 0; i < dec->used_buf_num; i++) { + if (i == (dec->used_buf_num - 1)) + pic = avs2_dec->m_bg; + else + pic = avs2_dec->fref[i]; + release_cuva_data(pic); + } + + +#ifdef DEBUG_PTS + pr_info("pts missed %ld, pts hit %ld, duration %d\n", + dec->pts_missed, dec->pts_hit, dec->frame_dur); +#endif + if (is_rdma_enable()) + dma_free_coherent(amports_get_dma_device(), RDMA_SIZE, dec->rdma_adr, dec->rdma_phy_adr); + /* devm_kfree(&pdev->dev, (void *)dec); */ + vfree((void *)dec); + return 0; +} + +static struct platform_driver ammvdec_avs2_driver = { + .probe = ammvdec_avs2_probe, + .remove = ammvdec_avs2_remove, +#ifdef CONFIG_PM + .suspend = amvdec_suspend, + .resume = amvdec_resume, +#endif + .driver = { + .name = MULTI_DRIVER_NAME, + } +}; +#endif +static struct mconfig avs2_configs[] = { + MC_PU32("bit_depth_luma", &bit_depth_luma), + MC_PU32("bit_depth_chroma", &bit_depth_chroma), + MC_PU32("frame_width", &frame_width), + MC_PU32("frame_height", &frame_height), + MC_PU32("debug", &debug), + MC_PU32("radr", &radr), + MC_PU32("rval", &rval), + MC_PU32("pop_shorts", &pop_shorts), + MC_PU32("dbg_cmd", &dbg_cmd), + MC_PU32("dbg_skip_decode_index", &dbg_skip_decode_index), + MC_PU32("endian", &endian), + MC_PU32("step", &step), + MC_PU32("udebug_flag", &udebug_flag), + MC_PU32("decode_pic_begin", &decode_pic_begin), + MC_PU32("slice_parse_begin", &slice_parse_begin), + MC_PU32("i_only_flag", &i_only_flag), + MC_PU32("error_handle_policy", &error_handle_policy), + MC_PU32("buf_alloc_width", &buf_alloc_width), + MC_PU32("buf_alloc_height", &buf_alloc_height), + MC_PU32("buf_alloc_depth", &buf_alloc_depth), + MC_PU32("buf_alloc_size", &buf_alloc_size), + MC_PU32("buffer_mode", &buffer_mode), + MC_PU32("buffer_mode_dbg", &buffer_mode_dbg), + MC_PU32("max_buf_num", &max_buf_num), + MC_PU32("dynamic_buf_num_margin", &dynamic_buf_num_margin), + MC_PU32("mem_map_mode", &mem_map_mode), + MC_PU32("double_write_mode", &double_write_mode), + MC_PU32("enable_mem_saving", &enable_mem_saving), + MC_PU32("force_w_h", &force_w_h), + MC_PU32("force_fps", &force_fps), + MC_PU32("max_decoding_time", &max_decoding_time), + MC_PU32("on_no_keyframe_skiped", &on_no_keyframe_skiped), + MC_PU32("start_decode_buf_level", &start_decode_buf_level), + MC_PU32("decode_timeout_val", &decode_timeout_val), +}; +static struct mconfig_node avs2_node; + +static int __init amvdec_avs2_driver_init_module(void) +{ + +#ifdef AVS2_10B_MMU + + struct BuffInfo_s *p_buf_info; + + if (get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_TM2 && !is_cpu_tm2_revb()) { + if (vdec_is_support_4k()) { + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) + p_buf_info = &amvavs2_workbuff_spec[2]; + else + p_buf_info = &amvavs2_workbuff_spec[1]; + } else + p_buf_info = &amvavs2_workbuff_spec[0]; + } else { //get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_TM2 || is_cpu_tm2_revb() + if (vdec_is_support_4k()) { + p_buf_info = &amvavs2_workbuff_spec[5]; + } else + p_buf_info = &amvavs2_workbuff_spec[3]; + } + + init_buff_spec(NULL, p_buf_info); + work_buf_size = + (p_buf_info->end_adr - p_buf_info->start_adr + + 0xffff) & (~0xffff); + +#endif + pr_debug("amvdec_avs2 module init\n"); + +#ifdef ERROR_HANDLE_DEBUG + dbg_nal_skip_flag = 0; + dbg_nal_skip_count = 0; +#endif + udebug_flag = 0; + decode_pic_begin = 0; + slice_parse_begin = 0; + step = 0; + buf_alloc_size = 0; + + if (platform_driver_register(&ammvdec_avs2_driver)) { + pr_err("failed to register ammvdec_avs2 driver\n"); + return -ENODEV; + } + + if ((get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_G12A) || + (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5D)) { + amvdec_avs2_profile.name = "avs2_unsupport"; + } else if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SM1) { + if (vdec_is_support_4k()) + amvdec_avs2_profile.profile = + "4k, 10bit, dwrite, compressed"; + else + amvdec_avs2_profile.profile = + "10bit, dwrite, compressed"; + } else { + /* cpu id larger than sm1 support 8k */ + amvdec_avs2_profile.profile = + "8k, 10bit, dwrite, compressed"; + } + + vcodec_profile_register(&amvdec_avs2_profile); + + INIT_REG_NODE_CONFIGS("media.decoder", &avs2_node, + "avs2-v4l", avs2_configs, CONFIG_FOR_RW); + vcodec_feature_register(VFORMAT_AVS2, 1); + + return 0; +} + +static void __exit amvdec_avs2_driver_remove_module(void) +{ + pr_debug("amvdec_avs2 module remove.\n"); + platform_driver_unregister(&ammvdec_avs2_driver); +} + +/****************************************/ + +module_param(bit_depth_luma, uint, 0664); +MODULE_PARM_DESC(bit_depth_luma, "\n amvdec_avs2 bit_depth_luma\n"); + +module_param(bit_depth_chroma, uint, 0664); +MODULE_PARM_DESC(bit_depth_chroma, "\n amvdec_avs2 bit_depth_chroma\n"); + +module_param(frame_width, uint, 0664); +MODULE_PARM_DESC(frame_width, "\n amvdec_avs2 frame_width\n"); + +module_param(frame_height, uint, 0664); +MODULE_PARM_DESC(frame_height, "\n amvdec_avs2 frame_height\n"); + +module_param(debug, uint, 0664); +MODULE_PARM_DESC(debug, "\n amvdec_avs2 debug\n"); + +module_param(debug_again, uint, 0664); +MODULE_PARM_DESC(debug_again, "\n amvdec_avs2 debug_again\n"); + +module_param(radr, uint, 0664); +MODULE_PARM_DESC(radr, "\nradr\n"); + +module_param(rval, uint, 0664); +MODULE_PARM_DESC(rval, "\nrval\n"); + +module_param(pop_shorts, uint, 0664); +MODULE_PARM_DESC(pop_shorts, "\nrval\n"); + +module_param(dbg_cmd, uint, 0664); +MODULE_PARM_DESC(dbg_cmd, "\ndbg_cmd\n"); + +module_param(dbg_skip_decode_index, uint, 0664); +MODULE_PARM_DESC(dbg_skip_decode_index, "\ndbg_skip_decode_index\n"); + +module_param(endian, uint, 0664); +MODULE_PARM_DESC(endian, "\nrval\n"); + +module_param(step, uint, 0664); +MODULE_PARM_DESC(step, "\n amvdec_avs2 step\n"); + +module_param(decode_pic_begin, uint, 0664); +MODULE_PARM_DESC(decode_pic_begin, "\n amvdec_avs2 decode_pic_begin\n"); + +module_param(slice_parse_begin, uint, 0664); +MODULE_PARM_DESC(slice_parse_begin, "\n amvdec_avs2 slice_parse_begin\n"); + +module_param(i_only_flag, uint, 0664); +MODULE_PARM_DESC(i_only_flag, "\n amvdec_avs2 i_only_flag\n"); + +module_param(error_handle_policy, uint, 0664); +MODULE_PARM_DESC(error_handle_policy, "\n amvdec_avs2 error_handle_policy\n"); + +module_param(re_search_seq_threshold, uint, 0664); +MODULE_PARM_DESC(re_search_seq_threshold, "\n amvdec_avs2 re_search_seq_threshold\n"); + +module_param(buf_alloc_width, uint, 0664); +MODULE_PARM_DESC(buf_alloc_width, "\n buf_alloc_width\n"); + +module_param(buf_alloc_height, uint, 0664); +MODULE_PARM_DESC(buf_alloc_height, "\n buf_alloc_height\n"); + +module_param(buf_alloc_depth, uint, 0664); +MODULE_PARM_DESC(buf_alloc_depth, "\n buf_alloc_depth\n"); + +module_param(buf_alloc_size, uint, 0664); +MODULE_PARM_DESC(buf_alloc_size, "\n buf_alloc_size\n"); + +module_param(buffer_mode, uint, 0664); +MODULE_PARM_DESC(buffer_mode, "\n buffer_mode\n"); + +module_param(buffer_mode_dbg, uint, 0664); +MODULE_PARM_DESC(buffer_mode_dbg, "\n buffer_mode_dbg\n"); +/*USE_BUF_BLOCK*/ +module_param(max_buf_num, uint, 0664); +MODULE_PARM_DESC(max_buf_num, "\n max_buf_num\n"); + +module_param(dynamic_buf_num_margin, uint, 0664); +MODULE_PARM_DESC(dynamic_buf_num_margin, "\n dynamic_buf_num_margin\n"); + +#ifdef CONSTRAIN_MAX_BUF_NUM +module_param(run_ready_max_vf_only_num, uint, 0664); +MODULE_PARM_DESC(run_ready_max_vf_only_num, "\n run_ready_max_vf_only_num\n"); + +module_param(run_ready_display_q_num, uint, 0664); +MODULE_PARM_DESC(run_ready_display_q_num, "\n run_ready_display_q_num\n"); + +module_param(run_ready_max_buf_num, uint, 0664); +MODULE_PARM_DESC(run_ready_max_buf_num, "\n run_ready_max_buf_num\n"); +#endif + +module_param(mv_buf_margin, uint, 0664); +MODULE_PARM_DESC(mv_buf_margin, "\n mv_buf_margin\n"); + +module_param(run_ready_min_buf_num, uint, 0664); +MODULE_PARM_DESC(run_ready_min_buf_num, "\n run_ready_min_buf_num\n"); + +/**/ + +module_param(mem_map_mode, uint, 0664); +MODULE_PARM_DESC(mem_map_mode, "\n mem_map_mode\n"); + +module_param(double_write_mode, uint, 0664); +MODULE_PARM_DESC(double_write_mode, "\n double_write_mode\n"); + +module_param(enable_mem_saving, uint, 0664); +MODULE_PARM_DESC(enable_mem_saving, "\n enable_mem_saving\n"); + +module_param(force_w_h, uint, 0664); +MODULE_PARM_DESC(force_w_h, "\n force_w_h\n"); + +module_param(force_fps, uint, 0664); +MODULE_PARM_DESC(force_fps, "\n force_fps\n"); + +module_param(max_decoding_time, uint, 0664); +MODULE_PARM_DESC(max_decoding_time, "\n max_decoding_time\n"); + +module_param(on_no_keyframe_skiped, uint, 0664); +MODULE_PARM_DESC(on_no_keyframe_skiped, "\n on_no_keyframe_skiped\n"); + + +module_param(start_decode_buf_level, int, 0664); +MODULE_PARM_DESC(start_decode_buf_level, + "\n avs2 start_decode_buf_level\n"); + +module_param(decode_timeout_val, uint, 0664); +MODULE_PARM_DESC(decode_timeout_val, + "\n avs2 decode_timeout_val\n"); + +module_param_array(decode_frame_count, uint, + &max_decode_instance_num, 0664); + +module_param_array(display_frame_count, uint, + &max_decode_instance_num, 0664); + +module_param_array(max_process_time, uint, + &max_decode_instance_num, 0664); + +module_param_array(run_count, uint, + &max_decode_instance_num, 0664); + +module_param_array(input_empty, uint, + &max_decode_instance_num, 0664); + +module_param_array(not_run_ready, uint, + &max_decode_instance_num, 0664); + +module_param(video_signal_type, uint, 0664); +MODULE_PARM_DESC(video_signal_type, "\n amvdec_avs2 video_signal_type\n"); + +module_param(force_video_signal_type, uint, 0664); +MODULE_PARM_DESC(force_video_signal_type, "\n amvdec_avs2 force_video_signal_type\n"); + +module_param(enable_force_video_signal_type, uint, 0664); +MODULE_PARM_DESC(enable_force_video_signal_type, "\n amvdec_avs2 enable_force_video_signal_type\n"); + +module_param(force_bufspec, uint, 0664); +MODULE_PARM_DESC(force_bufspec, "\n amvdec_h265 force_bufspec\n"); + +module_param(udebug_flag, uint, 0664); +MODULE_PARM_DESC(udebug_flag, "\n amvdec_h265 udebug_flag\n"); + +module_param(udebug_pause_pos, uint, 0664); +MODULE_PARM_DESC(udebug_pause_pos, "\n udebug_pause_pos\n"); + +module_param(udebug_pause_val, uint, 0664); +MODULE_PARM_DESC(udebug_pause_val, "\n udebug_pause_val\n"); + +module_param(udebug_pause_decode_idx, uint, 0664); +MODULE_PARM_DESC(udebug_pause_decode_idx, "\n udebug_pause_decode_idx\n"); + +module_param(pre_decode_buf_level, int, 0664); +MODULE_PARM_DESC(pre_decode_buf_level, + "\n amvdec_avs2 pre_decode_buf_level\n"); + +module_param(again_threshold, uint, 0664); +MODULE_PARM_DESC(again_threshold, "\n again_threshold\n"); + + +module_param(force_disp_pic_index, int, 0664); +MODULE_PARM_DESC(force_disp_pic_index, + "\n amvdec_h265 force_disp_pic_index\n"); + +module_param(without_display_mode, uint, 0664); +MODULE_PARM_DESC(without_display_mode, "\n without_display_mode\n"); + +module_param(mv_buf_dynamic_alloc, uint, 0664); +MODULE_PARM_DESC(mv_buf_dynamic_alloc, "\n mv_buf_dynamic_alloc\n"); + +module_init(amvdec_avs2_driver_init_module); +module_exit(amvdec_avs2_driver_remove_module); + +MODULE_DESCRIPTION("AMLOGIC avs2 Video Decoder Driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Tim Yao <tim.yao@amlogic.com>");
diff --git a/drivers/frame_provider/decoder/real/vreal.h b/drivers/frame_provider/decoder_v4l/avs2/vavs2.h similarity index 68% copy from drivers/frame_provider/decoder/real/vreal.h copy to drivers/frame_provider/decoder_v4l/avs2/vavs2.h index 734cc6f..6b51f61 100644 --- a/drivers/frame_provider/decoder/real/vreal.h +++ b/drivers/frame_provider/decoder_v4l/avs2/vavs2.h
@@ -1,5 +1,5 @@ /* - * drivers/amlogic/amports/vreal.h + * drivers/amlogic/amports/vavs2.h * * Copyright (C) 2015 Amlogic, Inc. All rights reserved. * @@ -13,14 +13,14 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - */ +*/ -#ifndef VREAL_H -#define VREAL_H +#ifndef VAVS2_H +#define VAVS2_H -#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */ -/* TODO: move to register headers */ -#define VPP_VD1_POSTBLEND (1 << 10) +#define AVS2_10B_MMU +#define MV_USE_FIXED_BUF + +void adapt_coef_probs(int pic_count, int prev_kf, int cur_kf, int pre_fc, +unsigned int *prev_prob, unsigned int *cur_prob, unsigned int *count); #endif - -#endif /* VREAL_H */
diff --git a/drivers/frame_provider/decoder_v4l/avs_multi/Makefile b/drivers/frame_provider/decoder_v4l/avs_multi/Makefile new file mode 100644 index 0000000..10da3ab --- /dev/null +++ b/drivers/frame_provider/decoder_v4l/avs_multi/Makefile
@@ -0,0 +1,2 @@ +obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_AVS_MULTI) += amvdec_mavs_v4l.o +amvdec_mavs_v4l-objs += avs_multi.o
diff --git a/drivers/frame_provider/decoder_v4l/avs_multi/avs_multi.c b/drivers/frame_provider/decoder_v4l/avs_multi/avs_multi.c new file mode 100644 index 0000000..3ad9385 --- /dev/null +++ b/drivers/frame_provider/decoder_v4l/avs_multi/avs_multi.c
@@ -0,0 +1,5016 @@ +/* + * drivers/amlogic/amports/vavs.c + * + * Copyright (C) 2015 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/types.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/semaphore.h> +#include <linux/timer.h> +#include <linux/kfifo.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/amlogic/media/utils/amstream.h> +#include <linux/amlogic/media/frame_sync/ptsserv.h> +#include <linux/amlogic/media/canvas/canvas.h> +#include <linux/amlogic/media/vfm/vframe_provider.h> +#include <linux/amlogic/media/vfm/vframe_receiver.h> +#include <linux/amlogic/media/vfm/vframe.h> +#include <linux/amlogic/media/utils/vdec_reg.h> +#include "../../../stream_input/amports/streambuf_reg.h" +#include "../../decoder/utils/amvdec.h" +#include <linux/amlogic/media/registers/register.h> +#include "../../../stream_input/amports/amports_priv.h" +#include <linux/dma-mapping.h> +#include <linux/amlogic/media/codec_mm/codec_mm.h> +#include <linux/slab.h> +#include "avs_multi.h" +#include <linux/amlogic/media/codec_mm/configs.h> +#include "../../decoder/utils/decoder_mmu_box.h" +#include "../../decoder/utils/decoder_bmmu_box.h" +#include "../../decoder/utils/firmware.h" +#include "../../../common/chips/decoder_cpu_ver_info.h" +#include <linux/amlogic/tee.h> +#include "../../decoder/utils/vdec_feature.h" + +#define DEBUG_MULTI_FLAG 0 +/* +#define DEBUG_WITH_SINGLE_MODE +#define DEBUG_MULTI_WITH_AUTOMODE +#define DEBUG_MULTI_FRAME_INS +*/ + + +#define USE_DYNAMIC_BUF_NUM + +#define DRIVER_NAME "ammvdec_avs_v4l" + + +#define MULTI_DRIVER_NAME "ammvdec_avs_v4l" + +#define ENABLE_USER_DATA + +#if 1/* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */ +#define NV21 +#endif + +#define USE_AVS_SEQ_INFO +#define HANDLE_AVS_IRQ +#define DEBUG_PTS + +#define CHECK_INTERVAL (HZ/100) + +#define I_PICTURE 0 +#define P_PICTURE 1 +#define B_PICTURE 2 + +#define LMEM_BUF_SIZE (0x500 * 2) + +/* #define ORI_BUFFER_START_ADDR 0x81000000 */ +#define ORI_BUFFER_START_ADDR 0x80000000 + +#define INTERLACE_FLAG 0x80 +#define TOP_FIELD_FIRST_FLAG 0x40 + +/* protocol registers */ +#define AVS_PIC_RATIO AV_SCRATCH_0 +#define AVS_PIC_WIDTH AV_SCRATCH_1 +#define AVS_PIC_HEIGHT AV_SCRATCH_2 +#define AVS_FRAME_RATE AV_SCRATCH_3 + +/*#define AVS_ERROR_COUNT AV_SCRATCH_6*/ +#define AVS_SOS_COUNT AV_SCRATCH_7 +#define AVS_BUFFERIN AV_SCRATCH_8 +#define AVS_BUFFEROUT AV_SCRATCH_9 +#define AVS_REPEAT_COUNT AV_SCRATCH_A +#define AVS_TIME_STAMP AV_SCRATCH_B +#define AVS_OFFSET_REG AV_SCRATCH_C +#define MEM_OFFSET_REG AV_SCRATCH_F +#define AVS_ERROR_RECOVERY_MODE AV_SCRATCH_G +#define DECODE_PIC_COUNT AV_SCRATCH_G + +#define DECODE_MODE AV_SCRATCH_6 +#define DECODE_MODE_SINGLE 0x0 +#define DECODE_MODE_MULTI_FRAMEBASE 0x1 +#define DECODE_MODE_MULTI_STREAMBASE 0x2 +#define DECODE_MODE_MULTI_STREAMBASE_CONT 0x3 + +#define DECODE_STATUS AV_SCRATCH_H +#define DECODE_STATUS_PIC_DONE 0x1 +#define DECODE_STATUS_DECODE_BUF_EMPTY 0x2 +#define DECODE_STATUS_SEARCH_BUF_EMPTY 0x3 +#define DECODE_STATUS_SKIP_PIC_DONE 0x4 +#define DECODE_SEARCH_HEAD 0xff + +#define DECODE_STOP_POS AV_SCRATCH_J + +#define DECODE_LMEM_BUF_ADR AV_SCRATCH_I + +#define DECODE_CFG AV_SCRATCH_K + +#define VF_POOL_SIZE 64 +#define PUT_INTERVAL (HZ/100) + +#if 1 /*MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8*/ +#define INT_AMVENCODER INT_DOS_MAILBOX_1 +#else +/* #define AMVENC_DEV_VERSION "AML-MT" */ +#define INT_AMVENCODER INT_MAILBOX_1A +#endif + +#ifdef USE_DYNAMIC_BUF_NUM +static unsigned int buf_spec_reg[] = { + AV_SCRATCH_0, + AV_SCRATCH_1, + AV_SCRATCH_2, + AV_SCRATCH_3, + AV_SCRATCH_7, /*AVS_SOS_COUNT*/ + AV_SCRATCH_D, /*DEBUG_REG2*/ + AV_SCRATCH_E, /*DEBUG_REG1*/ + AV_SCRATCH_M /*user_data_poc_number*/ +}; +#endif + +#define DEBUG_REG1 AV_SCRATCH_E +#define DEBUG_REG2 AV_SCRATCH_D + + +static void check_timer_func(struct timer_list *timer); +static void vavs_work(struct work_struct *work); + +#define DEC_CONTROL_FLAG_FORCE_2500_1080P_INTERLACE 0x0001 +static u32 dec_control = DEC_CONTROL_FLAG_FORCE_2500_1080P_INTERLACE; + + +#define VPP_VD1_POSTBLEND (1 << 10) + +static int debug; +static unsigned int debug_mask = 0xff; + +/*for debug*/ +/* + udebug_flag: + bit 0, enable ucode print + bit 1, enable ucode more print + bit 3, enable ucdode detail print + bit [31:16] not 0, pos to dump lmem + bit 2, pop bits to lmem + bit [11:8], pre-pop bits for alignment (when bit 2 is 1) + + avs only: + bit [8], disable empty muitl-instance handling + bit [9], enable writting of VC1_CONTROL_REG in ucode +*/ +static u32 udebug_flag; +/* + when udebug_flag[1:0] is not 0 + udebug_pause_pos not 0, + pause position +*/ +static u32 udebug_pause_pos; +/* + when udebug_flag[1:0] is not 0 + and udebug_pause_pos is not 0, + pause only when DEBUG_REG2 is equal to this val +*/ +static u32 udebug_pause_val; + +static u32 udebug_pause_decode_idx; + +static u32 udebug_pause_ins_id; + +static u32 force_fps; + +#ifdef DEBUG_MULTI_FRAME_INS +static u32 delay; +#endif + +static u32 step; + +static u32 start_decoding_delay; + +#define AVS_DEV_NUM 9 +static unsigned int max_decode_instance_num = AVS_DEV_NUM; +static unsigned int max_process_time[AVS_DEV_NUM]; +static unsigned int max_get_frame_interval[AVS_DEV_NUM]; +static unsigned int run_count[AVS_DEV_NUM]; +static unsigned int ins_udebug_flag[AVS_DEV_NUM]; +#ifdef DEBUG_MULTI_FRAME_INS +static unsigned int max_run_count[AVS_DEV_NUM]; +#endif +/* +error_handle_policy: +*/ +static unsigned int error_handle_policy = 3; + +static u32 again_threshold = 0; /*0x40;*/ + +static unsigned int decode_timeout_val = 200; +static unsigned int start_decode_buf_level = 0x8000; + +/******************************** +firmware_sel + 0: use avsp_trans long cabac ucode; + 1: not use avsp_trans long cabac ucode + in ucode: + #define USE_EXT_BUFFER_ASSIGNMENT + #undef USE_DYNAMIC_BUF_NUM +********************************/ +static int firmware_sel; +static int disable_longcabac_trans = 1; +static int pre_decode_buf_level = 0x800; + + +static struct vframe_s *vavs_vf_peek(void *); +static struct vframe_s *vavs_vf_get(void *); +static void vavs_vf_put(struct vframe_s *, void *); +static int vavs_vf_states(struct vframe_states *states, void *); +static int vavs_event_cb(int type, void *data, void *private_data); + +static const char vavs_dec_id[] = "vavs-dev"; + +#define PROVIDER_NAME "decoder.avs" +static DEFINE_SPINLOCK(lock); +static DEFINE_MUTEX(vavs_mutex); + +static const struct vframe_operations_s vavs_vf_provider = { + .peek = vavs_vf_peek, + .get = vavs_vf_get, + .put = vavs_vf_put, + .event_cb = vavs_event_cb, + .vf_states = vavs_vf_states, +}; +/* +static void *mm_blk_handle; +*/ +static struct vframe_provider_s vavs_vf_prov; + +#define VF_BUF_NUM_MAX 16 +#ifdef DEBUG_MULTI_FRAME_INS +#define WORKSPACE_SIZE (16 * SZ_1M) +#else +#define WORKSPACE_SIZE (4 * SZ_1M) +#endif +#ifdef AVSP_LONG_CABAC +#define MAX_BMMU_BUFFER_NUM (VF_BUF_NUM_MAX + 2) +#define WORKSPACE_SIZE_A (MAX_CODED_FRAME_SIZE + LOCAL_HEAP_SIZE) +#else +#define MAX_BMMU_BUFFER_NUM (VF_BUF_NUM_MAX + 1) +#endif + +#define RV_AI_BUFF_START_ADDR 0x01a00000 +#define LONG_CABAC_RV_AI_BUFF_START_ADDR 0x00000000 + +/* 4 buffers not enough for multi inc*/ +static u32 vf_buf_num = 8; +/*static u32 vf_buf_num_used;*/ +static u32 canvas_base = 128; +#ifdef NV21 +static int canvas_num = 2; /*NV21*/ +#else +static int canvas_num = 3; +#endif + +#if 0 +static struct vframe_s vfpool[VF_POOL_SIZE]; +/*static struct vframe_s vfpool2[VF_POOL_SIZE];*/ +static struct vframe_s *cur_vfpool; +static unsigned char recover_flag; +static s32 vfbuf_use[VF_BUF_NUM_MAX]; +static u32 saved_resolution; +static u32 frame_width, frame_height, frame_dur, frame_prog; +static struct timer_list recycle_timer; +static u32 stat; +#endif +static u32 buf_size = 32 * 1024 * 1024; +#if 0 +static u32 buf_offset; +static u32 avi_flag; +static u32 vavs_ratio; +static u32 pic_type; +#endif +static u32 pts_by_offset = 1; +#if 0 +static u32 total_frame; +static u32 next_pts; +static unsigned char throw_pb_flag; +#ifdef DEBUG_PTS +static u32 pts_hit, pts_missed, pts_i_hit, pts_i_missed; +#endif +#endif +static u32 radr, rval; +static u32 dbg_cmd; +#if 0 +static struct dec_sysinfo vavs_amstream_dec_info; +static struct vdec_info *gvs; +static u32 fr_hint_status; +static struct work_struct notify_work; +static struct work_struct set_clk_work; +static bool is_reset; +#endif +/*static struct vdec_s *vdec;*/ + +#ifdef AVSP_LONG_CABAC +static struct work_struct long_cabac_wd_work; +void *es_write_addr_virt; +dma_addr_t es_write_addr_phy; + +void *bitstream_read_tmp; +dma_addr_t bitstream_read_tmp_phy; +void *avsp_heap_adr; +static uint long_cabac_busy; +#endif + +#if 0 +#ifdef ENABLE_USER_DATA +static void *user_data_buffer; +static dma_addr_t user_data_buffer_phys; +#endif +static DECLARE_KFIFO(newframe_q, struct vframe_s *, VF_POOL_SIZE); +static DECLARE_KFIFO(display_q, struct vframe_s *, VF_POOL_SIZE); +static DECLARE_KFIFO(recycle_q, struct vframe_s *, VF_POOL_SIZE); +#endif +static inline u32 index2canvas(u32 index) +{ + const u32 canvas_tab[VF_BUF_NUM_MAX] = { + 0x010100, 0x030302, 0x050504, 0x070706, + 0x090908, 0x0b0b0a, 0x0d0d0c, 0x0f0f0e, + 0x111110, 0x131312, 0x151514, 0x171716, + 0x191918, 0x1b1b1a, 0x1d1d1c, 0x1f1f1e, + }; + const u32 canvas_tab_3[4] = { + 0x010100, 0x040403, 0x070706, 0x0a0a09 + }; + + if (canvas_num == 2) + return canvas_tab[index] + (canvas_base << 16) + + (canvas_base << 8) + canvas_base; + + return canvas_tab_3[index] + (canvas_base << 16) + + (canvas_base << 8) + canvas_base; +} + +static const u32 frame_rate_tab[16] = { + 96000 / 30, /* forbidden */ + 96000000 / 23976, /* 24000/1001 (23.967) */ + 96000 / 24, + 96000 / 25, + 9600000 / 2997, /* 30000/1001 (29.97) */ + 96000 / 30, + 96000 / 50, + 9600000 / 5994, /* 60000/1001 (59.94) */ + 96000 / 60, + /* > 8 reserved, use 24 */ + 96000 / 24, 96000 / 24, 96000 / 24, 96000 / 24, + 96000 / 24, 96000 / 24, 96000 / 24 +}; + +#define DECODE_BUFFER_NUM_MAX VF_BUF_NUM_MAX +#define PIC_PTS_NUM 64 +struct buf_pool_s { + unsigned detached; + struct vframe_s vf; +}; + +#define buf_of_vf(vf) container_of(vf, struct buf_pool_s, vf) + +struct pic_pts_s { + u32 pts; + u64 pts64; + u64 timestamp; + unsigned short decode_pic_count; +}; + +struct vdec_avs_hw_s { + spinlock_t lock; + unsigned char m_ins_flag; + struct platform_device *platform_dev; + DECLARE_KFIFO(newframe_q, struct vframe_s *, VF_POOL_SIZE); + DECLARE_KFIFO(display_q, struct vframe_s *, VF_POOL_SIZE); + DECLARE_KFIFO(recycle_q, struct vframe_s *, VF_POOL_SIZE); + struct buf_pool_s vfpool[VF_POOL_SIZE]; + s32 vfbuf_use[VF_BUF_NUM_MAX]; + unsigned char again_flag; + unsigned char recover_flag; + u32 frame_width; + u32 frame_height; + u32 frame_dur; + u32 frame_prog; + u32 saved_resolution; + u32 avi_flag; + u32 vavs_ratio; + u32 pic_type; + + u32 vf_buf_num_used; + u32 total_frame; + u32 next_pts; + unsigned char throw_pb_flag; + struct pic_pts_s pic_pts[PIC_PTS_NUM]; + int pic_pts_wr_pos; + +#ifdef DEBUG_PTS + u32 pts_hit; + u32 pts_missed; + u32 pts_i_hit; + u32 pts_i_missed; +#endif +#ifdef ENABLE_USER_DATA + struct work_struct userdata_push_work; + void *user_data_buffer; + dma_addr_t user_data_buffer_phys; +#endif + dma_addr_t lmem_addr; + ulong lmem_phy_addr; + + u32 buf_offset; + + struct dec_sysinfo vavs_amstream_dec_info; + struct vdec_info *gvs; + u32 fr_hint_status; + struct work_struct set_clk_work; + bool is_reset; + + /*debug*/ + u32 ucode_pause_pos; + /**/ + u32 decode_pic_count; + u8 reset_decode_flag; + u32 display_frame_count; + u32 buf_status; + u32 pre_parser_wr_ptr; + /* + buffer_status &= ~buf_recycle_status + */ + u32 buf_recycle_status; + u32 seqinfo; + u32 ctx_valid; + u32 dec_control; + void *mm_blk_handle; + struct vframe_chunk_s *chunk; + u32 stat; + u8 init_flag; + unsigned long buf_start; + u32 buf_size; + + u32 reg_scratch_0; + u32 reg_scratch_1; + u32 reg_scratch_2; + u32 reg_scratch_3; + u32 reg_scratch_4; + u32 reg_scratch_5; + u32 reg_scratch_6; + u32 reg_scratch_7; + u32 reg_scratch_8; + u32 reg_scratch_9; + u32 reg_scratch_A; + u32 reg_scratch_B; + u32 reg_scratch_C; + u32 reg_scratch_D; + u32 reg_scratch_E; + u32 reg_scratch_F; + u32 reg_scratch_G; + u32 reg_scratch_H; + u32 reg_scratch_I; + u32 reg_mb_width; + u32 reg_viff_bit_cnt; + u32 reg_canvas_addr; + u32 reg_dbkr_canvas_addr; + u32 reg_dbkw_canvas_addr; + u32 reg_anc2_canvas_addr; + u32 reg_anc0_canvas_addr; + u32 reg_anc1_canvas_addr; + u32 reg_anc3_canvas_addr; + u32 reg_anc4_canvas_addr; + u32 reg_anc5_canvas_addr; + u32 slice_ver_pos_pic_type; + u32 vc1_control_reg; + u32 avs_co_mb_wr_addr; + u32 slice_start_byte_01; + u32 slice_start_byte_23; + u32 vcop_ctrl_reg; + u32 iqidct_control; + u32 rv_ai_mb_count; + u32 slice_qp; + u32 dc_scaler; + u32 avsp_iq_wq_param_01; + u32 avsp_iq_wq_param_23; + u32 avsp_iq_wq_param_45; + u32 avs_co_mb_rd_addr; + u32 dblk_mb_wid_height; + u32 mc_pic_w_h; + u32 avs_co_mb_rw_ctl; + u32 vld_decode_control; + + struct timer_list check_timer; + u32 decode_timeout_count; + unsigned long int start_process_time; + u32 last_vld_level; + u32 eos; + u32 canvas_spec[DECODE_BUFFER_NUM_MAX]; + struct canvas_config_s canvas_config[DECODE_BUFFER_NUM_MAX][2]; + + s32 refs[2]; + int dec_result; + struct timer_list recycle_timer; + struct work_struct work; + struct work_struct notify_work; + atomic_t error_handler_run; + struct work_struct fatal_error_wd_work; + void (*vdec_cb)(struct vdec_s *, void *); + void *vdec_cb_arg; +/* for error handling */ + u32 run_count; + u32 not_run_ready; + u32 input_empty; + atomic_t prepare_num; + atomic_t put_num; + atomic_t peek_num; + atomic_t get_num; + u32 drop_frame_count; + u32 buffer_not_ready; + int frameinfo_enable; + struct firmware_s *fw; + u32 old_udebug_flag; + u32 decode_status_skip_pic_done_flag; + u32 decode_decode_cont_start_code; + int vdec_pg_enable_flag; + char vdec_name[32]; + char pts_name[32]; + char new_q_name[32]; + char disp_q_name[32]; +}; + +static void reset_process_time(struct vdec_avs_hw_s *hw); +static void start_process_time(struct vdec_avs_hw_s *hw); +static void vavs_save_regs(struct vdec_avs_hw_s *hw); + +struct vdec_avs_hw_s *ghw; + +#define MULTI_INSTANCE_PROVIDER_NAME "vdec.avs" + +#define DEC_RESULT_NONE 0 +#define DEC_RESULT_DONE 1 +#define DEC_RESULT_AGAIN 2 +#define DEC_RESULT_ERROR 3 +#define DEC_RESULT_FORCE_EXIT 4 +#define DEC_RESULT_EOS 5 +#define DEC_RESULT_GET_DATA 6 +#define DEC_RESULT_GET_DATA_RETRY 7 +#define DEC_RESULT_USERDATA 8 + +#define DECODE_ID(hw) (hw->m_ins_flag? hw_to_vdec(hw)->id : 0) + +#define PRINT_FLAG_ERROR 0x0 +#define PRINT_FLAG_RUN_FLOW 0X0001 +#define PRINT_FLAG_DECODING 0x0002 +#define PRINT_FLAG_PTS 0x0004 +#define PRINT_FLAG_VFRAME_DETAIL 0x0010 +#define PRINT_FLAG_VLD_DETAIL 0x0020 +#define PRINT_FLAG_DEC_DETAIL 0x0040 +#define PRINT_FLAG_BUFFER_DETAIL 0x0080 +#define PRINT_FLAG_FORCE_DONE 0x0100 +#define PRINT_FLAG_COUNTER 0X0200 +#define PRINT_FRAMEBASE_DATA 0x0400 +#define PRINT_FLAG_PARA_DATA 0x1000 +#define DEBUG_FLAG_PREPARE_MORE_INPUT 0x2000 +#define DEBUG_FLAG_PRINT_REG 0x4000 +#define DEBUG_FLAG_DISABLE_TIMEOUT 0x10000 +#define DEBUG_WAIT_DECODE_DONE_WHEN_STOP 0x20000 +#define DEBUG_PIC_DONE_WHEN_UCODE_PAUSE 0x40000 + + +#undef DEBUG_REG +#ifdef DEBUG_REG +static void WRITE_VREG_DBG2(unsigned adr, unsigned val) +{ + if (debug & DEBUG_FLAG_PRINT_REG) + pr_info("%s(%x, %x)\n", __func__, adr, val); + if (adr != 0) + WRITE_VREG(adr, val); +} + +#undef WRITE_VREG +#define WRITE_VREG WRITE_VREG_DBG2 +#endif + +#undef pr_info +#define pr_info printk +static int debug_print(struct vdec_avs_hw_s *hw, + int flag, const char *fmt, ...) +{ +#define AVS_PRINT_BUF 256 + unsigned char buf[AVS_PRINT_BUF]; + int len = 0; + int index = 0; + if (hw) + index = hw->m_ins_flag ? DECODE_ID(hw) : 0; + if (hw == NULL || + (flag == 0) || + ((debug_mask & + (1 << index)) + && (debug & flag))) { + va_list args; + + va_start(args, fmt); + if (hw) + len = sprintf(buf, "[%d]", index); + vsnprintf(buf + len, AVS_PRINT_BUF - len, fmt, args); + pr_info("%s", buf); + va_end(args); + } + return 0; +} + +static int debug_print_cont(struct vdec_avs_hw_s *hw, + int flag, const char *fmt, ...) +{ + unsigned char buf[AVS_PRINT_BUF]; + int len = 0; + int index = 0; + if (hw) + index = hw->m_ins_flag ? DECODE_ID(hw) : 0; + if (hw == NULL || + (flag == 0) || + ((debug_mask & + (1 << index)) + && (debug & flag))) { + va_list args; + + va_start(args, fmt); + vsnprintf(buf + len, AVS_PRINT_BUF - len, fmt, args); + pr_info("%s", buf); + va_end(args); + } + return 0; +} + +static void avs_pts_check_in(struct vdec_avs_hw_s *hw, + unsigned short decode_pic_count, struct vframe_chunk_s *chunk) +{ + if (chunk) + debug_print(hw, PRINT_FLAG_PTS, + "%s %d (wr pos %d), pts %d pts64 %ld timestamp %ld\n", + __func__, decode_pic_count, hw->pic_pts_wr_pos, + chunk->pts, (u64)(chunk->pts64), (u64)(chunk->timestamp)); + else + debug_print(hw, PRINT_FLAG_PTS, + "%s %d, chunk is null\n", + __func__, decode_pic_count); + + if (chunk) { + hw->pic_pts[hw->pic_pts_wr_pos].pts = chunk->pts; + hw->pic_pts[hw->pic_pts_wr_pos].pts64 = chunk->pts64; + hw->pic_pts[hw->pic_pts_wr_pos].timestamp = chunk->timestamp; + } else { + hw->pic_pts[hw->pic_pts_wr_pos].pts = 0; + hw->pic_pts[hw->pic_pts_wr_pos].pts64 = 0; + hw->pic_pts[hw->pic_pts_wr_pos].timestamp = 0; + } + hw->pic_pts[hw->pic_pts_wr_pos].decode_pic_count + = decode_pic_count; + hw->pic_pts_wr_pos++; + if (hw->pic_pts_wr_pos >= PIC_PTS_NUM) + hw->pic_pts_wr_pos = 0; + return; +} + +static void clear_pts_buf(struct vdec_avs_hw_s *hw) +{ + int i; + debug_print(hw, PRINT_FLAG_PTS, + "%s\n", __func__); + hw->pic_pts_wr_pos = 0; + for (i = 0; i < PIC_PTS_NUM; i++) { + hw->pic_pts[hw->pic_pts_wr_pos].pts = 0; + hw->pic_pts[hw->pic_pts_wr_pos].pts64 = 0; + hw->pic_pts[hw->pic_pts_wr_pos].timestamp = 0; + hw->pic_pts[hw->pic_pts_wr_pos].decode_pic_count = 0; + } +} + +static int set_vframe_pts(struct vdec_avs_hw_s *hw, + unsigned short decode_pic_count, struct vframe_s *vf) +{ + int i; + int ret = -1; + for (i = 0; i < PIC_PTS_NUM; i++) { + if (hw->pic_pts[i].decode_pic_count == decode_pic_count) { + vf->pts = hw->pic_pts[i].pts; + vf->pts_us64 = hw->pic_pts[i].pts64; + vf->timestamp = hw->pic_pts[i].timestamp; + ret = 0; + debug_print(hw, PRINT_FLAG_PTS, + "%s %d (rd pos %d), pts %d pts64 %ld timestamp %ld\n", + __func__, decode_pic_count, i, + vf->pts, vf->pts_us64, vf->timestamp); + + break; + } + } + return ret; +} + +static void avs_vf_notify_receiver(struct vdec_avs_hw_s *hw, + const char *provider_name, int event_type, void *data) +{ + if (hw->m_ins_flag) + vf_notify_receiver(hw_to_vdec(hw)->vf_provider_name, + event_type, data); + else + vf_notify_receiver(provider_name, event_type, data); +} + +static void set_frame_info(struct vdec_avs_hw_s *hw, struct vframe_s *vf, + unsigned int *duration) +{ + int ar = 0; + + unsigned int pixel_ratio = READ_VREG(AVS_PIC_RATIO); + atomic_add(1, &hw->prepare_num); +#ifndef USE_AVS_SEQ_INFO + if (hw->vavs_amstream_dec_info.width > 0 + && hw->vavs_amstream_dec_info.height > 0) { + vf->width = hw->vavs_amstream_dec_info.width; + vf->height = hw->vavs_amstream_dec_info.height; + } else +#endif + { + vf->width = READ_VREG(AVS_PIC_WIDTH); + vf->height = READ_VREG(AVS_PIC_HEIGHT); + hw->frame_width = vf->width; + hw->frame_height = vf->height; + /* pr_info("%s: (%d,%d)\n", __func__,vf->width, vf->height);*/ + } + +#ifndef USE_AVS_SEQ_INFO + if (hw->vavs_amstream_dec_info.rate > 0) + *duration = hw->vavs_amstream_dec_info.rate; + else +#endif + { + *duration = frame_rate_tab[READ_VREG(AVS_FRAME_RATE) & 0xf]; + /* pr_info("%s: duration = %d\n", __func__, *duration); */ + hw->frame_dur = *duration; + schedule_work(&hw->notify_work); + } + + if (hw->vavs_ratio == 0) { + /* always stretch to 16:9 */ + vf->ratio_control |= (0x90 << + DISP_RATIO_ASPECT_RATIO_BIT); + vf->sar_width = 1; + vf->sar_height = 1; + } else { + switch (pixel_ratio) { + case 1: + vf->sar_width = 1; + vf->sar_height = 1; + ar = (vf->height * hw->vavs_ratio) / vf->width; + break; + case 2: + vf->sar_width = 4; + vf->sar_height = 3; + ar = (vf->height * 3 * hw->vavs_ratio) / (vf->width * 4); + break; + case 3: + vf->sar_width = 16; + vf->sar_height = 9; + ar = (vf->height * 9 * hw->vavs_ratio) / (vf->width * 16); + break; + case 4: + vf->sar_width = 221; + vf->sar_height = 100; + ar = (vf->height * 100 * hw->vavs_ratio) / (vf->width * + 221); + break; + default: + vf->sar_width = 1; + vf->sar_height = 1; + ar = (vf->height * hw->vavs_ratio) / vf->width; + break; + } + } + + ar = min(ar, DISP_RATIO_ASPECT_RATIO_MAX); + + vf->ratio_control = (ar << DISP_RATIO_ASPECT_RATIO_BIT); + /*vf->ratio_control |= DISP_RATIO_FORCECONFIG | DISP_RATIO_KEEPRATIO; */ + + vf->flag = 0; + buf_of_vf(vf)->detached = 0; + +} + +#ifdef ENABLE_USER_DATA + +/*static struct work_struct userdata_push_work;*/ +/* +#define DUMP_LAST_REPORTED_USER_DATA +*/ +static void userdata_push_process(struct vdec_avs_hw_s *hw) +{ + unsigned int user_data_flags; + unsigned int user_data_wp; + unsigned int user_data_length; + struct userdata_poc_info_t user_data_poc; +#ifdef DUMP_LAST_REPORTED_USER_DATA + int user_data_len; + int wp_start; + unsigned char *pdata; + int nLeft; +#endif + + user_data_flags = READ_VREG(AV_SCRATCH_N); + user_data_wp = (user_data_flags >> 16) & 0xffff; + user_data_length = user_data_flags & 0x7fff; + +#ifdef DUMP_LAST_REPORTED_USER_DATA + dma_sync_single_for_cpu(amports_get_dma_device(), + hw->user_data_buffer_phys, USER_DATA_SIZE, + DMA_FROM_DEVICE); + + if (user_data_length & 0x07) + user_data_len = (user_data_length + 8) & 0xFFFFFFF8; + else + user_data_len = user_data_length; + + if (user_data_wp >= user_data_len) { + wp_start = user_data_wp - user_data_len; + + pdata = (unsigned char *)hw->user_data_buffer; + pdata += wp_start; + nLeft = user_data_len; + while (nLeft >= 8) { + pr_info("%02x %02x %02x %02x %02x %02x %02x %02x\n", + pdata[0], pdata[1], pdata[2], pdata[3], + pdata[4], pdata[5], pdata[6], pdata[7]); + nLeft -= 8; + pdata += 8; + } + } else { + wp_start = user_data_wp + + USER_DATA_SIZE - user_data_len; + + pdata = (unsigned char *)hw->user_data_buffer; + pdata += wp_start; + nLeft = USER_DATA_SIZE - wp_start; + + while (nLeft >= 8) { + pr_info("%02x %02x %02x %02x %02x %02x %02x %02x\n", + pdata[0], pdata[1], pdata[2], pdata[3], + pdata[4], pdata[5], pdata[6], pdata[7]); + nLeft -= 8; + pdata += 8; + } + + pdata = (unsigned char *)hw->user_data_buffer; + nLeft = user_data_wp; + while (nLeft >= 8) { + pr_info("%02x %02x %02x %02x %02x %02x %02x %02x\n", + pdata[0], pdata[1], pdata[2], pdata[3], + pdata[4], pdata[5], pdata[6], pdata[7]); + nLeft -= 8; + pdata += 8; + } + } +#endif + +/* + pr_info("pocinfo 0x%x, poc %d, wp 0x%x, len %d\n", + READ_VREG(AV_SCRATCH_L), READ_VREG(AV_SCRATCH_M), + user_data_wp, user_data_length); +*/ + user_data_poc.poc_info = READ_VREG(AV_SCRATCH_L); + user_data_poc.poc_number = READ_VREG(AV_SCRATCH_M); + + WRITE_VREG(AV_SCRATCH_N, 0); +/* + wakeup_userdata_poll(user_data_poc, user_data_wp, + (unsigned long)hw->user_data_buffer, + USER_DATA_SIZE, user_data_length); +*/ +} + +static void userdata_push_do_work(struct work_struct *work) +{ + struct vdec_avs_hw_s *hw = + container_of(work, struct vdec_avs_hw_s, userdata_push_work); + userdata_push_process(hw); +} + +static u8 UserDataHandler(struct vdec_avs_hw_s *hw) +{ + unsigned int user_data_flags; + + user_data_flags = READ_VREG(AV_SCRATCH_N); + if (user_data_flags & (1 << 15)) { /* data ready */ + if (hw->m_ins_flag) { + hw->dec_result = DEC_RESULT_USERDATA; + vdec_schedule_work(&hw->work); + return 1; + } else + schedule_work(&hw->userdata_push_work); + } + return 0; +} +#endif + + +static inline void avs_update_gvs(struct vdec_avs_hw_s *hw) +{ + if (hw->gvs->frame_height != hw->frame_height) { + hw->gvs->frame_width = hw->frame_width; + hw->gvs->frame_height = hw->frame_height; + } + if (hw->gvs->frame_dur != hw->frame_dur) { + hw->gvs->frame_dur = hw->frame_dur; + if (hw->frame_dur != 0) + hw->gvs->frame_rate = ((96000 * 10 / hw->frame_dur) % 10) < 5 ? + 96000 / hw->frame_dur : (96000 / hw->frame_dur +1); + else + hw->gvs->frame_rate = -1; + } + + hw->gvs->status = hw->stat; + hw->gvs->error_count = READ_VREG(AV_SCRATCH_C); + hw->gvs->drop_frame_count = hw->drop_frame_count; + +} + +#ifdef HANDLE_AVS_IRQ +static irqreturn_t vavs_isr(int irq, void *dev_id) +#else +static void vavs_isr(void) +#endif +{ + WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); + + return IRQ_WAKE_THREAD; +} +/* + *static int run_flag = 1; + *static int step_flag; + */ +static int error_recovery_mode; /*0: blocky 1: mosaic*/ +/* + *static uint error_watchdog_threshold=10; + *static uint error_watchdog_count; + *static uint error_watchdog_buf_threshold = 0x4000000; + */ + +static struct vframe_s *vavs_vf_peek(void *op_arg) +{ + struct vframe_s *vf; + struct vdec_avs_hw_s *hw = + (struct vdec_avs_hw_s *)op_arg; + atomic_add(1, &hw->peek_num); + if (step == 2) + return NULL; + if (hw->recover_flag) + return NULL; + + if (kfifo_peek(&hw->display_q, &vf)) { + if (vf) { + if (force_fps & 0x100) { + u32 rate = force_fps & 0xff; + + if (rate) + vf->duration = 96000/rate; + else + vf->duration = 0; + } + + } + return vf; + } + + return NULL; + +} + +static struct vframe_s *vavs_vf_get(void *op_arg) +{ + struct vframe_s *vf; + struct vdec_avs_hw_s *hw = + (struct vdec_avs_hw_s *)op_arg; + unsigned long flags; + + if (hw->recover_flag) + return NULL; + + if (step == 2) + return NULL; + else if (step == 1) + step = 2; + + spin_lock_irqsave(&lock, flags); + if (kfifo_get(&hw->display_q, &vf)) { + if (vf) { + vf->index_disp = atomic_read(&hw->get_num); + atomic_add(1, &hw->get_num); + if (force_fps & 0x100) { + u32 rate = force_fps & 0xff; + + if (rate) + vf->duration = 96000/rate; + else + vf->duration = 0; + } + + debug_print(hw, PRINT_FLAG_VFRAME_DETAIL, + "%s, index = %d, w %d h %d, type 0x%x detached %d\n", + __func__, + vf->index, + vf->width, + vf->height, + vf->type, + buf_of_vf(vf)->detached); + } + spin_unlock_irqrestore(&lock, flags); + return vf; + } + spin_unlock_irqrestore(&lock, flags); + + return NULL; + +} + +static void vavs_vf_put(struct vframe_s *vf, void *op_arg) +{ + int i; + struct vdec_avs_hw_s *hw = + (struct vdec_avs_hw_s *)op_arg; + + if (vf) { + atomic_add(1, &hw->put_num); + debug_print(hw, PRINT_FLAG_VFRAME_DETAIL, + "%s, index = %d, w %d h %d, type 0x%x detached 0x%x\n", + __func__, + vf->index, + vf->width, + vf->height, + vf->type, + buf_of_vf(vf)->detached); + } + if (hw->recover_flag) + return; + + for (i = 0; i < VF_POOL_SIZE; i++) { + if (vf == &hw->vfpool[i].vf) + break; + } + if (i < VF_POOL_SIZE) + + kfifo_put(&hw->recycle_q, (const struct vframe_s *)vf); + +} + +static int vavs_event_cb(int type, void *data, void *private_data) +{ + struct vdec_avs_hw_s *hw = (struct vdec_avs_hw_s *)private_data; + + if (type & VFRAME_EVENT_RECEIVER_REQ_STATE) { + struct provider_state_req_s *req = + (struct provider_state_req_s *)data; + if (req->req_type == REQ_STATE_SECURE) + req->req_result[0] = vdec_secure(hw_to_vdec(hw)); + else + req->req_result[0] = 0xffffffff; + } + + return 0; +} + +static int vavs_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus) +{ + struct vdec_avs_hw_s *hw = + (struct vdec_avs_hw_s *)vdec->private; + /*if (!(hw->stat & STAT_VDEC_RUN)) + return -1;*/ + if (!hw) + return -1; + + vstatus->frame_width = hw->frame_width; + vstatus->frame_height = hw->frame_height; + if (hw->frame_dur != 0) + vstatus->frame_rate = ((96000 * 10 / hw->frame_dur) % 10) < 5 ? + 96000 / hw->frame_dur : (96000 / hw->frame_dur +1); + else + vstatus->frame_rate = -1; + vstatus->error_count = READ_VREG(AV_SCRATCH_C); + vstatus->status = hw->stat; + vstatus->bit_rate = hw->gvs->bit_rate; + vstatus->frame_dur = hw->frame_dur; + vstatus->frame_data = hw->gvs->frame_data; + vstatus->total_data = hw->gvs->total_data; + vstatus->frame_count = hw->gvs->frame_count; + vstatus->error_frame_count = hw->gvs->error_frame_count; + vstatus->drop_frame_count = hw->gvs->drop_frame_count; + vstatus->i_decoded_frames = hw->gvs->i_decoded_frames; + vstatus->i_lost_frames = hw->gvs->i_lost_frames; + vstatus->i_concealed_frames = hw->gvs->i_concealed_frames; + vstatus->p_decoded_frames = hw->gvs->p_decoded_frames; + vstatus->p_lost_frames = hw->gvs->p_lost_frames; + vstatus->p_concealed_frames = hw->gvs->p_concealed_frames; + vstatus->b_decoded_frames = hw->gvs->b_decoded_frames; + vstatus->b_lost_frames = hw->gvs->b_lost_frames; + vstatus->b_concealed_frames = hw->gvs->b_concealed_frames; + vstatus->total_data = hw->gvs->total_data; + vstatus->samp_cnt = hw->gvs->samp_cnt; + vstatus->offset = hw->gvs->offset; + snprintf(vstatus->vdec_name, sizeof(vstatus->vdec_name), + "%s", DRIVER_NAME); + + return 0; +} + +static int vavs_set_isreset(struct vdec_s *vdec, int isreset) +{ + struct vdec_avs_hw_s *hw = + (struct vdec_avs_hw_s *)vdec->private; + + hw->is_reset = isreset; + return 0; +} + +static int vavs_vdec_info_init(struct vdec_avs_hw_s *hw) +{ + + hw->gvs = kzalloc(sizeof(struct vdec_info), GFP_KERNEL); + if (NULL == hw->gvs) { + pr_info("the struct of vdec status malloc failed.\n"); + return -ENOMEM; + } + + return 0; +} +/****************************************/ +static int vavs_canvas_init(struct vdec_avs_hw_s *hw) +{ + int i, ret; + u32 canvas_width, canvas_height; + u32 decbuf_size, decbuf_y_size, decbuf_uv_size; + unsigned long buf_start; + int need_alloc_buf_num; + struct vdec_s *vdec = NULL; + + if (hw->m_ins_flag) + vdec = hw_to_vdec(hw); + + if (buf_size <= 0x00400000) { + /* SD only */ + canvas_width = 768; + canvas_height = 576; + decbuf_y_size = 0x80000; + decbuf_uv_size = 0x20000; + decbuf_size = 0x100000; + } else { + /* HD & SD */ + canvas_width = 1920; + canvas_height = 1088; + decbuf_y_size = 0x200000; + decbuf_uv_size = 0x80000; + decbuf_size = 0x300000; + } + +#ifdef AVSP_LONG_CABAC + need_alloc_buf_num = hw->vf_buf_num_used + 2; +#else + need_alloc_buf_num = hw->vf_buf_num_used + 1; +#endif + for (i = 0; i < need_alloc_buf_num; i++) { + + if (i == (need_alloc_buf_num - 1)) + decbuf_size = WORKSPACE_SIZE; +#ifdef AVSP_LONG_CABAC + else if (i == (need_alloc_buf_num - 2)) + decbuf_size = WORKSPACE_SIZE_A; +#endif + ret = decoder_bmmu_box_alloc_buf_phy(hw->mm_blk_handle, i, + decbuf_size, DRIVER_NAME, &buf_start); + if (ret < 0) + return ret; + if (i == (need_alloc_buf_num - 1)) { + if (firmware_sel == 1) + hw->buf_offset = buf_start - + RV_AI_BUFF_START_ADDR; + else + hw->buf_offset = buf_start - + LONG_CABAC_RV_AI_BUFF_START_ADDR; + continue; + } +#ifdef AVSP_LONG_CABAC + else if (i == (need_alloc_buf_num - 2)) { + avsp_heap_adr = codec_mm_phys_to_virt(buf_start); + continue; + } +#endif + if (hw->m_ins_flag) { + unsigned canvas; + + if (vdec->parallel_dec == 1) { + unsigned tmp; + if (canvas_u(hw->canvas_spec[i]) == 0xff) { + tmp = + vdec->get_canvas_ex(CORE_MASK_VDEC_1, vdec->id); + hw->canvas_spec[i] &= ~(0xffff << 8); + hw->canvas_spec[i] |= tmp << 8; + hw->canvas_spec[i] |= tmp << 16; + } + if (canvas_y(hw->canvas_spec[i]) == 0xff) { + tmp = + vdec->get_canvas_ex(CORE_MASK_VDEC_1, vdec->id); + hw->canvas_spec[i] &= ~0xff; + hw->canvas_spec[i] |= tmp; + } + canvas = hw->canvas_spec[i]; + } else { + canvas = vdec->get_canvas(i, 2); + hw->canvas_spec[i] = canvas; + } + + hw->canvas_config[i][0].phy_addr = + buf_start; + hw->canvas_config[i][0].width = + canvas_width; + hw->canvas_config[i][0].height = + canvas_height; + hw->canvas_config[i][0].block_mode = + CANVAS_BLKMODE_32X32; + + hw->canvas_config[i][1].phy_addr = + buf_start + decbuf_y_size; + hw->canvas_config[i][1].width = + canvas_width; + hw->canvas_config[i][1].height = + canvas_height / 2; + hw->canvas_config[i][1].block_mode = + CANVAS_BLKMODE_32X32; + + } else { +#ifdef NV21 + config_cav_lut_ex(canvas_base + canvas_num * i + 0, + buf_start, + canvas_width, canvas_height, + CANVAS_ADDR_NOWRAP, + CANVAS_BLKMODE_32X32, 0, VDEC_1); + config_cav_lut_ex(canvas_base + canvas_num * i + 1, + buf_start + + decbuf_y_size, canvas_width, + canvas_height / 2, + CANVAS_ADDR_NOWRAP, + CANVAS_BLKMODE_32X32, 0, VDEC_1); +#else + config_cav_lut_ex(canvas_num * i + 0, + buf_start, + canvas_width, canvas_height, + CANVAS_ADDR_NOWRAP, + CANVAS_BLKMODE_32X32, 0, VDEC_1); + config_cav_lut_ex(canvas_num * i + 1, + buf_start + + decbuf_y_size, canvas_width / 2, + canvas_height / 2, + CANVAS_ADDR_NOWRAP, + CANVAS_BLKMODE_32X32, 0, VDEC_1); + config_cav_lut_ex(canvas_num * i + 2, + buf_start + + decbuf_y_size + decbuf_uv_size, + canvas_width / 2, canvas_height / 2, + CANVAS_ADDR_NOWRAP, + CANVAS_BLKMODE_32X32, 0, VDEC_1); +#endif + debug_print(hw, PRINT_FLAG_VFRAME_DETAIL, + "canvas config %d, addr %p\n", i, + (void *)buf_start); + } + } + return 0; +} + +static void vavs_recover(struct vdec_avs_hw_s *hw) +{ + vavs_canvas_init(hw); + + WRITE_VREG(DOS_SW_RESET0, (1 << 7) | (1 << 6) | (1 << 4)); + WRITE_VREG(DOS_SW_RESET0, 0); + + READ_VREG(DOS_SW_RESET0); + + WRITE_VREG(DOS_SW_RESET0, (1 << 7) | (1 << 6) | (1 << 4)); + WRITE_VREG(DOS_SW_RESET0, 0); + + WRITE_VREG(DOS_SW_RESET0, (1 << 9) | (1 << 8)); + WRITE_VREG(DOS_SW_RESET0, 0); + + if (firmware_sel == 1) { + WRITE_VREG(POWER_CTL_VLD, 0x10); + WRITE_VREG_BITS(VLD_MEM_VIFIFO_CONTROL, 2, + MEM_FIFO_CNT_BIT, 2); + WRITE_VREG_BITS(VLD_MEM_VIFIFO_CONTROL, 8, + MEM_LEVEL_CNT_BIT, 6); + } + + + if (firmware_sel == 0) { + /* fixed canvas index */ + WRITE_VREG(AV_SCRATCH_0, canvas_base); + WRITE_VREG(AV_SCRATCH_1, hw->vf_buf_num_used); + } else { + int ii; +#ifndef USE_DYNAMIC_BUF_NUM + for (ii = 0; ii < 4; ii++) { + WRITE_VREG(AV_SCRATCH_0 + ii, + (canvas_base + canvas_num * ii) | + ((canvas_base + canvas_num * ii + 1) + << 8) | + ((canvas_base + canvas_num * ii + 1) + << 16) + ); + } +#else + for (ii = 0; ii < hw->vf_buf_num_used; ii += 2) { + WRITE_VREG(buf_spec_reg[ii >> 1], + (canvas_base + canvas_num * ii) | + ((canvas_base + canvas_num * ii + 1) + << 8) | + ((canvas_base + canvas_num * ii + 2) + << 16) | + ((canvas_base + canvas_num * ii + 3) + << 24) + ); + } +#endif + } + + /* notify ucode the buffer offset */ + WRITE_VREG(AV_SCRATCH_F, hw->buf_offset); + + /* disable PSCALE for hardware sharing */ + WRITE_VREG(PSCALE_CTRL, 0); + +#ifndef USE_DYNAMIC_BUF_NUM + WRITE_VREG(AVS_SOS_COUNT, 0); +#endif + WRITE_VREG(AVS_BUFFERIN, 0); + WRITE_VREG(AVS_BUFFEROUT, 0); + if (error_recovery_mode) + WRITE_VREG(AVS_ERROR_RECOVERY_MODE, 0); + else + WRITE_VREG(AVS_ERROR_RECOVERY_MODE, 1); + /* clear mailbox interrupt */ + WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); + + /* enable mailbox interrupt */ + WRITE_VREG(ASSIST_MBOX1_MASK, 1); +#ifndef USE_DYNAMIC_BUF_NUM /* def DEBUG_UCODE */ + WRITE_VREG(AV_SCRATCH_D, 0); +#endif + +#ifdef NV21 + SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17); +#endif + SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 16); + +#ifdef PIC_DC_NEED_CLEAR + CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 31); +#endif + +#ifdef AVSP_LONG_CABAC + if (firmware_sel == 0) { + WRITE_VREG(LONG_CABAC_DES_ADDR, es_write_addr_phy); + WRITE_VREG(LONG_CABAC_REQ, 0); + WRITE_VREG(LONG_CABAC_PIC_SIZE, 0); + WRITE_VREG(LONG_CABAC_SRC_ADDR, 0); + } +#endif + WRITE_VREG(AV_SCRATCH_5, 0); + +} + +#define MBY_MBX MB_MOTION_MODE /*0xc07*/ +#define AVS_CO_MB_WR_ADDR 0xc38 +#define AVS_CO_MB_RW_CTL 0xc3d +#define AVS_CO_MB_RD_ADDR 0xc39 +#define AVSP_IQ_WQ_PARAM_01 0x0e19 +#define AVSP_IQ_WQ_PARAM_23 0x0e1a +#define AVSP_IQ_WQ_PARAM_45 0x0e1b + +static void vavs_save_regs(struct vdec_avs_hw_s *hw) +{ + hw->reg_scratch_0 = READ_VREG(AV_SCRATCH_0); + hw->reg_scratch_1 = READ_VREG(AV_SCRATCH_1); + hw->reg_scratch_2 = READ_VREG(AV_SCRATCH_2); + hw->reg_scratch_3 = READ_VREG(AV_SCRATCH_3); + hw->reg_scratch_4 = READ_VREG(AV_SCRATCH_4); + hw->reg_scratch_5 = READ_VREG(AV_SCRATCH_5); + hw->reg_scratch_6 = READ_VREG(AV_SCRATCH_6); + hw->reg_scratch_7 = READ_VREG(AV_SCRATCH_7); + hw->reg_scratch_8 = READ_VREG(AV_SCRATCH_8); + hw->reg_scratch_9 = READ_VREG(AV_SCRATCH_9); + hw->reg_scratch_A = READ_VREG(AV_SCRATCH_A); + hw->reg_scratch_B = READ_VREG(AV_SCRATCH_B); + hw->reg_scratch_C = READ_VREG(AV_SCRATCH_C); + hw->reg_scratch_D = READ_VREG(AV_SCRATCH_D); + hw->reg_scratch_E = READ_VREG(AV_SCRATCH_E); + hw->reg_scratch_F = READ_VREG(AV_SCRATCH_F); + hw->reg_scratch_G = READ_VREG(AV_SCRATCH_G); + hw->reg_scratch_H = READ_VREG(AV_SCRATCH_H); + hw->reg_scratch_I = READ_VREG(AV_SCRATCH_I); + + hw->reg_mb_width = READ_VREG(MB_WIDTH); + hw->reg_viff_bit_cnt = READ_VREG(VIFF_BIT_CNT); + + hw->reg_canvas_addr = READ_VREG(REC_CANVAS_ADDR); + hw->reg_dbkr_canvas_addr = READ_VREG(DBKR_CANVAS_ADDR); + hw->reg_dbkw_canvas_addr = READ_VREG(DBKW_CANVAS_ADDR); + hw->reg_anc2_canvas_addr = READ_VREG(ANC2_CANVAS_ADDR); + hw->reg_anc0_canvas_addr = READ_VREG(ANC0_CANVAS_ADDR); + hw->reg_anc1_canvas_addr = READ_VREG(ANC1_CANVAS_ADDR); + hw->reg_anc3_canvas_addr = READ_VREG(ANC3_CANVAS_ADDR); + hw->reg_anc4_canvas_addr = READ_VREG(ANC4_CANVAS_ADDR); + hw->reg_anc5_canvas_addr = READ_VREG(ANC5_CANVAS_ADDR); + + hw->slice_ver_pos_pic_type = READ_VREG(SLICE_VER_POS_PIC_TYPE); + + hw->vc1_control_reg = READ_VREG(VC1_CONTROL_REG); + hw->avs_co_mb_wr_addr = READ_VREG(AVS_CO_MB_WR_ADDR); + hw->slice_start_byte_01 = READ_VREG(SLICE_START_BYTE_01); + hw->slice_start_byte_23 = READ_VREG(SLICE_START_BYTE_23); + hw->vcop_ctrl_reg = READ_VREG(VCOP_CTRL_REG); + hw->iqidct_control = READ_VREG(IQIDCT_CONTROL); + hw->rv_ai_mb_count = READ_VREG(RV_AI_MB_COUNT); + hw->slice_qp = READ_VREG(SLICE_QP); + + hw->dc_scaler = READ_VREG(DC_SCALER); + hw->avsp_iq_wq_param_01 = READ_VREG(AVSP_IQ_WQ_PARAM_01); + hw->avsp_iq_wq_param_23 = READ_VREG(AVSP_IQ_WQ_PARAM_23); + hw->avsp_iq_wq_param_45 = READ_VREG(AVSP_IQ_WQ_PARAM_45); + hw->avs_co_mb_rd_addr = READ_VREG(AVS_CO_MB_RD_ADDR); + hw->dblk_mb_wid_height = READ_VREG(DBLK_MB_WID_HEIGHT); + hw->mc_pic_w_h = READ_VREG(MC_PIC_W_H); + hw->avs_co_mb_rw_ctl = READ_VREG(AVS_CO_MB_RW_CTL); + + hw->vld_decode_control = READ_VREG(VLD_DECODE_CONTROL); +} + +static void vavs_restore_regs(struct vdec_avs_hw_s *hw) +{ + debug_print(hw, PRINT_FLAG_DECODING, + "%s scratch_8 (AVS_BUFFERIN) 0x%x, decode_pic_count = %d\n", + __func__, hw->reg_scratch_8, hw->decode_pic_count); + + WRITE_VREG(AV_SCRATCH_0, hw->reg_scratch_0); + WRITE_VREG(AV_SCRATCH_1, hw->reg_scratch_1); + WRITE_VREG(AV_SCRATCH_2, hw->reg_scratch_2); + WRITE_VREG(AV_SCRATCH_3, hw->reg_scratch_3); + WRITE_VREG(AV_SCRATCH_4, hw->reg_scratch_4); + WRITE_VREG(AV_SCRATCH_5, hw->reg_scratch_5); + WRITE_VREG(AV_SCRATCH_6, hw->reg_scratch_6); + WRITE_VREG(AV_SCRATCH_7, hw->reg_scratch_7); + WRITE_VREG(AV_SCRATCH_8, hw->reg_scratch_8); + WRITE_VREG(AV_SCRATCH_9, hw->reg_scratch_9); + WRITE_VREG(AV_SCRATCH_A, hw->reg_scratch_A); + WRITE_VREG(AV_SCRATCH_B, hw->reg_scratch_B); + WRITE_VREG(AV_SCRATCH_C, hw->reg_scratch_C); + WRITE_VREG(AV_SCRATCH_D, hw->reg_scratch_D); + WRITE_VREG(AV_SCRATCH_E, hw->reg_scratch_E); + WRITE_VREG(AV_SCRATCH_F, hw->reg_scratch_F); + WRITE_VREG(AV_SCRATCH_G, hw->reg_scratch_G); + WRITE_VREG(AV_SCRATCH_H, hw->reg_scratch_H); + WRITE_VREG(AV_SCRATCH_I, hw->reg_scratch_I); + + WRITE_VREG(MB_WIDTH, hw->reg_mb_width); + WRITE_VREG(VIFF_BIT_CNT, hw->reg_viff_bit_cnt); + + WRITE_VREG(REC_CANVAS_ADDR, hw->reg_canvas_addr); + WRITE_VREG(DBKR_CANVAS_ADDR, hw->reg_dbkr_canvas_addr); + WRITE_VREG(DBKW_CANVAS_ADDR, hw->reg_dbkw_canvas_addr); + WRITE_VREG(ANC2_CANVAS_ADDR, hw->reg_anc2_canvas_addr); + WRITE_VREG(ANC0_CANVAS_ADDR, hw->reg_anc0_canvas_addr); + WRITE_VREG(ANC1_CANVAS_ADDR, hw->reg_anc1_canvas_addr); + WRITE_VREG(ANC3_CANVAS_ADDR, hw->reg_anc3_canvas_addr); + WRITE_VREG(ANC4_CANVAS_ADDR, hw->reg_anc4_canvas_addr); + WRITE_VREG(ANC5_CANVAS_ADDR, hw->reg_anc5_canvas_addr); + + WRITE_VREG(SLICE_VER_POS_PIC_TYPE, hw->slice_ver_pos_pic_type); + + WRITE_VREG(VC1_CONTROL_REG, hw->vc1_control_reg); + WRITE_VREG(AVS_CO_MB_WR_ADDR, hw->avs_co_mb_wr_addr); + WRITE_VREG(SLICE_START_BYTE_01, hw->slice_start_byte_01); + WRITE_VREG(SLICE_START_BYTE_23, hw->slice_start_byte_23); + WRITE_VREG(VCOP_CTRL_REG, hw->vcop_ctrl_reg); + WRITE_VREG(IQIDCT_CONTROL, hw->iqidct_control); + WRITE_VREG(RV_AI_MB_COUNT, hw->rv_ai_mb_count); + WRITE_VREG(SLICE_QP, hw->slice_qp); + + WRITE_VREG(DC_SCALER, hw->dc_scaler); + WRITE_VREG(AVSP_IQ_WQ_PARAM_01, hw->avsp_iq_wq_param_01); + WRITE_VREG(AVSP_IQ_WQ_PARAM_23, hw->avsp_iq_wq_param_23); + WRITE_VREG(AVSP_IQ_WQ_PARAM_45, hw->avsp_iq_wq_param_45); + WRITE_VREG(AVS_CO_MB_RD_ADDR, hw->avs_co_mb_rd_addr); + WRITE_VREG(DBLK_MB_WID_HEIGHT, hw->dblk_mb_wid_height); + WRITE_VREG(MC_PIC_W_H, hw->mc_pic_w_h); + WRITE_VREG(AVS_CO_MB_RW_CTL, hw->avs_co_mb_rw_ctl); + + WRITE_VREG(VLD_DECODE_CONTROL, hw->vld_decode_control); + +} + +static int vavs_prot_init(struct vdec_avs_hw_s *hw) +{ + int r = 0; +#if DEBUG_MULTI_FLAG > 0 + if (hw->decode_pic_count == 0) { +#endif +#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */ + WRITE_VREG(DOS_SW_RESET0, (1 << 7) | (1 << 6) | (1 << 4)); + WRITE_VREG(DOS_SW_RESET0, 0); + + READ_VREG(DOS_SW_RESET0); + + WRITE_VREG(DOS_SW_RESET0, (1 << 7) | (1 << 6) | (1 << 4)); + WRITE_VREG(DOS_SW_RESET0, 0); + + WRITE_VREG(DOS_SW_RESET0, (1 << 9) | (1 << 8)); + WRITE_VREG(DOS_SW_RESET0, 0); + +#else + WRITE_RESET_REG(RESET0_REGISTER, + RESET_IQIDCT | RESET_MC | RESET_VLD_PART); + READ_RESET_REG(RESET0_REGISTER); + WRITE_RESET_REG(RESET0_REGISTER, + RESET_IQIDCT | RESET_MC | RESET_VLD_PART); + + WRITE_RESET_REG(RESET2_REGISTER, RESET_PIC_DC | RESET_DBLK); +#endif +#if DEBUG_MULTI_FLAG > 0 + } +#endif + /***************** reset vld **********************************/ + WRITE_VREG(POWER_CTL_VLD, 0x10); + WRITE_VREG_BITS(VLD_MEM_VIFIFO_CONTROL, 2, MEM_FIFO_CNT_BIT, 2); + WRITE_VREG_BITS(VLD_MEM_VIFIFO_CONTROL, 8, MEM_LEVEL_CNT_BIT, 6); + /*************************************************************/ + if (hw->m_ins_flag) { + int i; + if (hw->decode_pic_count == 0) { + r = vavs_canvas_init(hw); +#ifndef USE_DYNAMIC_BUF_NUM + for (i = 0; i < 4; i++) { + WRITE_VREG(AV_SCRATCH_0 + i, + hw->canvas_spec[i] + ); + } +#else + for (i = 0; i < hw->vf_buf_num_used; i++) + WRITE_VREG(buf_spec_reg[i], 0); + for (i = 0; i < hw->vf_buf_num_used; i += 2) { + WRITE_VREG(buf_spec_reg[i >> 1], + (hw->canvas_spec[i] & 0xffff) | + ((hw->canvas_spec[i + 1] & 0xffff) + << 16) + ); + debug_print(hw, PRINT_FLAG_DECODING, + "%s WRITE_VREG(0x%x, 0x%x)\n", + __func__, buf_spec_reg[i >> 1], READ_VREG(buf_spec_reg[i >> 1])); + } +#endif + } else + vavs_restore_regs(hw); + + for (i = 0; i < hw->vf_buf_num_used; i++) { + config_cav_lut_ex(canvas_y(hw->canvas_spec[i]), + hw->canvas_config[i][0].phy_addr, + hw->canvas_config[i][0].width, + hw->canvas_config[i][0].height, + CANVAS_ADDR_NOWRAP, + hw->canvas_config[i][0].block_mode, + 0, VDEC_1); + + config_cav_lut_ex(canvas_u(hw->canvas_spec[i]), + hw->canvas_config[i][1].phy_addr, + hw->canvas_config[i][1].width, + hw->canvas_config[i][1].height, + CANVAS_ADDR_NOWRAP, + hw->canvas_config[i][1].block_mode, + 0, VDEC_1); + } + } else { + r = vavs_canvas_init(hw); +#ifdef NV21 + if (firmware_sel == 0) { + /* fixed canvas index */ + WRITE_VREG(AV_SCRATCH_0, canvas_base); + WRITE_VREG(AV_SCRATCH_1, hw->vf_buf_num_used); + } else { + int ii; +#ifndef USE_DYNAMIC_BUF_NUM + for (ii = 0; ii < 4; ii++) { + WRITE_VREG(AV_SCRATCH_0 + ii, + (canvas_base + canvas_num * ii) | + ((canvas_base + canvas_num * ii + 1) + << 8) | + ((canvas_base + canvas_num * ii + 1) + << 16) + ); + } +#else + for (ii = 0; ii < hw->vf_buf_num_used; ii += 2) { + WRITE_VREG(buf_spec_reg[ii >> 1], + (canvas_base + canvas_num * ii) | + ((canvas_base + canvas_num * ii + 1) + << 8) | + ((canvas_base + canvas_num * ii + 2) + << 16) | + ((canvas_base + canvas_num * ii + 3) + << 24) + ); + } +#endif + /* + *WRITE_VREG(AV_SCRATCH_0, 0x010100); + *WRITE_VREG(AV_SCRATCH_1, 0x040403); + *WRITE_VREG(AV_SCRATCH_2, 0x070706); + *WRITE_VREG(AV_SCRATCH_3, 0x0a0a09); + */ + } +#else + /* index v << 16 | u << 8 | y */ + WRITE_VREG(AV_SCRATCH_0, 0x020100); + WRITE_VREG(AV_SCRATCH_1, 0x050403); + WRITE_VREG(AV_SCRATCH_2, 0x080706); + WRITE_VREG(AV_SCRATCH_3, 0x0b0a09); +#endif + } + /* notify ucode the buffer offset */ + if (hw->decode_pic_count == 0) + WRITE_VREG(AV_SCRATCH_F, hw->buf_offset); + + /* disable PSCALE for hardware sharing */ + WRITE_VREG(PSCALE_CTRL, 0); + + if (hw->decode_pic_count == 0) { +#ifndef USE_DYNAMIC_BUF_NUM + WRITE_VREG(AVS_SOS_COUNT, 0); +#endif + WRITE_VREG(AVS_BUFFERIN, 0); + WRITE_VREG(AVS_BUFFEROUT, 0); + } + if (error_recovery_mode) + WRITE_VREG(AVS_ERROR_RECOVERY_MODE, 0); + else + WRITE_VREG(AVS_ERROR_RECOVERY_MODE, 1); + /* clear mailbox interrupt */ + WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); + + /* enable mailbox interrupt */ + WRITE_VREG(ASSIST_MBOX1_MASK, 1); +#ifndef USE_DYNAMIC_BUF_NUM /* def DEBUG_UCODE */ + if (hw->decode_pic_count == 0) + WRITE_VREG(AV_SCRATCH_D, 0); +#endif + +#ifdef NV21 + SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17); +#endif + /* V4L2_PIX_FMT_NV21 V4L2_PIX_FMT_NV21M */ + SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 16); + +#ifdef PIC_DC_NEED_CLEAR + CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 31); +#endif + if (hw->m_ins_flag && start_decoding_delay > 0) + msleep(start_decoding_delay); + + //pr_info("+++++++++++++++++++++++++++++++\n"); + //pr_info("+++++++++++++++++++++++++++++++\n"); + //pr_info("+++++++++++++++++++++++++++++++\n"); +#ifdef AVSP_LONG_CABAC + if (firmware_sel == 0) { + WRITE_VREG(LONG_CABAC_DES_ADDR, es_write_addr_phy); + WRITE_VREG(LONG_CABAC_REQ, 0); + WRITE_VREG(LONG_CABAC_PIC_SIZE, 0); + WRITE_VREG(LONG_CABAC_SRC_ADDR, 0); + } +#endif + +#ifdef ENABLE_USER_DATA + if (hw->decode_pic_count == 0) { + WRITE_VREG(AV_SCRATCH_N, (u32)(hw->user_data_buffer_phys - hw->buf_offset)); + pr_debug("AV_SCRATCH_N = 0x%x\n", READ_VREG(AV_SCRATCH_N)); + } else + WRITE_VREG(AV_SCRATCH_N, 0); +#endif + if (hw->m_ins_flag) { + if (vdec_frame_based(hw_to_vdec(hw))) + WRITE_VREG(DECODE_MODE, DECODE_MODE_MULTI_FRAMEBASE); + else { + if (hw->decode_status_skip_pic_done_flag) { + WRITE_VREG(DECODE_CFG, hw->decode_decode_cont_start_code); + WRITE_VREG(DECODE_MODE, DECODE_MODE_MULTI_STREAMBASE_CONT); + } else + WRITE_VREG(DECODE_MODE, DECODE_MODE_MULTI_STREAMBASE); + } + WRITE_VREG(DECODE_LMEM_BUF_ADR, (u32)hw->lmem_phy_addr); + } else + WRITE_VREG(DECODE_MODE, DECODE_MODE_SINGLE); + + if (ins_udebug_flag[DECODE_ID(hw)] && + (ins_udebug_flag[DECODE_ID(hw)] >> 16) == hw->decode_pic_count) { + WRITE_VREG(DECODE_STOP_POS, + ins_udebug_flag[DECODE_ID(hw)] & 0xffff); + } + else + WRITE_VREG(DECODE_STOP_POS, udebug_flag); + hw->old_udebug_flag = udebug_flag; + + return r; +} + + +#ifdef AVSP_LONG_CABAC +static unsigned char es_write_addr[MAX_CODED_FRAME_SIZE] __aligned(64); +#endif +static void vavs_local_init(struct vdec_avs_hw_s *hw) +{ + int i; + + hw->vf_buf_num_used = vf_buf_num; + + hw->vavs_ratio = hw->vavs_amstream_dec_info.ratio; + + hw->avi_flag = (unsigned long) hw->vavs_amstream_dec_info.param; + + hw->frame_width = hw->frame_height = hw->frame_dur = hw->frame_prog = 0; + + hw->throw_pb_flag = 1; + + hw->total_frame = 0; + hw->saved_resolution = 0; + hw->next_pts = 0; + +#ifdef DEBUG_PTS + hw->pts_hit = hw->pts_missed = hw->pts_i_hit = hw->pts_i_missed = 0; +#endif + INIT_KFIFO(hw->display_q); + INIT_KFIFO(hw->recycle_q); + INIT_KFIFO(hw->newframe_q); + + for (i = 0; i < VF_POOL_SIZE; i++) { + const struct vframe_s *vf = &hw->vfpool[i].vf; + + hw->vfpool[i].vf.index = hw->vf_buf_num_used; + hw->vfpool[i].vf.bufWidth = 1920; + hw->vfpool[i].detached = 0; + kfifo_put(&hw->newframe_q, vf); + } + for (i = 0; i < hw->vf_buf_num_used; i++) + hw->vfbuf_use[i] = 0; + + /*cur_vfpool = vfpool;*/ + + if (hw->recover_flag == 1) + return; + + if (hw->mm_blk_handle) { + pr_info("decoder_bmmu_box_free\n"); + decoder_bmmu_box_free(hw->mm_blk_handle); + hw->mm_blk_handle = NULL; + } + + hw->mm_blk_handle = decoder_bmmu_box_alloc_box( + DRIVER_NAME, + 0, + MAX_BMMU_BUFFER_NUM, + 4 + PAGE_SHIFT, + CODEC_MM_FLAGS_CMA_CLEAR | + CODEC_MM_FLAGS_FOR_VDECODER); + if (hw->mm_blk_handle == NULL) + pr_info("Error, decoder_bmmu_box_alloc_box fail\n"); + +} + +static int vavs_vf_states(struct vframe_states *states, void *op_arg) +{ + unsigned long flags; + struct vdec_avs_hw_s *hw = + (struct vdec_avs_hw_s *)op_arg; + + + spin_lock_irqsave(&lock, flags); + states->vf_pool_size = VF_POOL_SIZE; + states->buf_free_num = kfifo_len(&hw->newframe_q); + states->buf_avail_num = kfifo_len(&hw->display_q); + states->buf_recycle_num = kfifo_len(&hw->recycle_q); + if (step == 2) + states->buf_avail_num = 0; + spin_unlock_irqrestore(&lock, flags); + return 0; +} + +#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER +static void vavs_ppmgr_reset(void) +{ + vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_RESET, NULL); + + vavs_local_init(ghw); + + pr_info("vavs: vf_ppmgr_reset\n"); +} +#endif + +static void vavs_local_reset(struct vdec_avs_hw_s *hw) +{ + mutex_lock(&vavs_mutex); + hw->recover_flag = 1; + pr_info("error, local reset\n"); + amvdec_stop(); + msleep(100); + avs_vf_notify_receiver(hw, PROVIDER_NAME, VFRAME_EVENT_PROVIDER_RESET, NULL); + vavs_local_init(hw); + vavs_recover(hw); + +#ifdef ENABLE_USER_DATA + reset_userdata_fifo(1); +#endif + + amvdec_start(); + hw->recover_flag = 0; +#if 0 + error_watchdog_count = 0; + + pr_info("pc %x stream buf wp %x rp %x level %x\n", + READ_VREG(MPC_E), + READ_VREG(VLD_MEM_VIFIFO_WP), + READ_VREG(VLD_MEM_VIFIFO_RP), + READ_VREG(VLD_MEM_VIFIFO_LEVEL)); +#endif + + + + mutex_unlock(&vavs_mutex); +} + +#if 0 +static struct work_struct fatal_error_wd_work; +static struct work_struct notify_work; +static atomic_t error_handler_run = ATOMIC_INIT(0); +#endif +static void vavs_fatal_error_handler(struct work_struct *work) +{ + struct vdec_avs_hw_s *hw = + container_of(work, struct vdec_avs_hw_s, fatal_error_wd_work); + if (debug & AVS_DEBUG_OLD_ERROR_HANDLE) { + mutex_lock(&vavs_mutex); + pr_info("vavs fatal error reset !\n"); + amvdec_stop(); +#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER + vavs_ppmgr_reset(); +#else + vf_light_unreg_provider(&vavs_vf_prov); + vavs_local_init(hw); + vf_reg_provider(&vavs_vf_prov); +#endif + vavs_recover(hw); + amvdec_start(); + mutex_unlock(&vavs_mutex); + } else { + pr_info("avs fatal_error_handler\n"); + vavs_local_reset(hw); + } + atomic_set(&hw->error_handler_run, 0); +} + +static void vavs_notify_work(struct work_struct *work) +{ + struct vdec_avs_hw_s *hw = + container_of(work, struct vdec_avs_hw_s, notify_work); + if (hw->fr_hint_status == VDEC_NEED_HINT) { + avs_vf_notify_receiver(hw, PROVIDER_NAME , + VFRAME_EVENT_PROVIDER_FR_HINT , + (void *)((unsigned long)hw->frame_dur)); + hw->fr_hint_status = VDEC_HINTED; + } + return; +} + +static void avs_set_clk(struct work_struct *work) +{ + struct vdec_avs_hw_s *hw = + container_of(work, struct vdec_avs_hw_s, set_clk_work); + if (hw->frame_dur > 0 && hw->saved_resolution != + hw->frame_width * hw->frame_height * (96000 / hw->frame_dur)) { + int fps = 96000 / hw->frame_dur; + + hw->saved_resolution = hw->frame_width * hw->frame_height * fps; + if (firmware_sel == 0 && + (debug & AVS_DEBUG_USE_FULL_SPEED)) { + vdec_source_changed(VFORMAT_AVS, + 4096, 2048, 60); + } else { + vdec_source_changed(VFORMAT_AVS, + hw->frame_width, hw->frame_height, fps); + } + + } +} + +#ifdef DEBUG_MULTI_WITH_AUTOMODE +int delay_count = 0; +#endif +static void vavs_put_timer_func(struct timer_list *arg) +{ + struct vdec_avs_hw_s *hw = container_of(arg, + struct vdec_avs_hw_s, recycle_timer); + struct timer_list *timer = &hw->recycle_timer; + +#ifndef HANDLE_AVS_IRQ + vavs_isr(); +#endif +#ifdef DEBUG_MULTI_WITH_AUTOMODE + if (delay_count > 0) { + if (delay_count == 1) + amvdec_start(); + delay_count--; + } +#endif + if (READ_VREG(AVS_SOS_COUNT)) { + if (!error_recovery_mode) { +#if 0 + if (debug & AVS_DEBUG_OLD_ERROR_HANDLE) { + mutex_lock(&vavs_mutex); + pr_info("vavs fatal error reset !\n"); + amvdec_stop(); +#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER + vavs_ppmgr_reset(); +#else + vf_light_unreg_provider(&vavs_vf_prov); + vavs_local_init(); + vf_reg_provider(&vavs_vf_prov); +#endif + vavs_recover(); + amvdec_start(); + mutex_unlock(&vavs_mutex); + } else { + vavs_local_reset(); + } +#else + if (!atomic_read(&hw->error_handler_run)) { + atomic_set(&hw->error_handler_run, 1); + pr_info("AVS_SOS_COUNT = %d\n", + READ_VREG(AVS_SOS_COUNT)); + pr_info("WP = 0x%x, RP = 0x%x, LEVEL = 0x%x, AVAIL = 0x%x, CUR_PTR = 0x%x\n", + READ_VREG(VLD_MEM_VIFIFO_WP), + READ_VREG(VLD_MEM_VIFIFO_RP), + READ_VREG(VLD_MEM_VIFIFO_LEVEL), + READ_VREG(VLD_MEM_VIFIFO_BYTES_AVAIL), + READ_VREG(VLD_MEM_VIFIFO_CURR_PTR)); + schedule_work(&hw->fatal_error_wd_work); + } +#endif + } + } +#if 0 + if (long_cabac_busy == 0 && + error_watchdog_threshold > 0 && + kfifo_len(&hw->display_q) == 0 && + READ_VREG(VLD_MEM_VIFIFO_LEVEL) > + error_watchdog_buf_threshold) { + pr_info("newq %d dispq %d recyq %d\r\n", + kfifo_len(&hw->newframe_q), + kfifo_len(&hw->display_q), + kfifo_len(&hw->recycle_q)); + pr_info("pc %x stream buf wp %x rp %x level %x\n", + READ_VREG(MPC_E), + READ_VREG(VLD_MEM_VIFIFO_WP), + READ_VREG(VLD_MEM_VIFIFO_RP), + READ_VREG(VLD_MEM_VIFIFO_LEVEL)); + error_watchdog_count++; + if (error_watchdog_count >= error_watchdog_threshold) + vavs_local_reset(); + } else + error_watchdog_count = 0; +#endif + if (radr != 0) { + if (rval != 0) { + WRITE_VREG(radr, rval); + pr_info("WRITE_VREG(%x,%x)\n", radr, rval); + } else + pr_info("READ_VREG(%x)=%x\n", radr, READ_VREG(radr)); + rval = 0; + radr = 0; + } + if ((hw->ucode_pause_pos != 0) && + (hw->ucode_pause_pos != 0xffffffff) && + udebug_pause_pos != hw->ucode_pause_pos) { + hw->ucode_pause_pos = 0; + WRITE_VREG(DEBUG_REG1, 0); + } + + if (!kfifo_is_empty(&hw->recycle_q) && (READ_VREG(AVS_BUFFERIN) == 0)) { + struct vframe_s *vf; + + if (kfifo_get(&hw->recycle_q, &vf)) { + if ((vf->index < hw->vf_buf_num_used) && + (--hw->vfbuf_use[vf->index] == 0)) { + debug_print(hw, PRINT_FLAG_DECODING, + "%s WRITE_VREG(AVS_BUFFERIN, 0x%x) for vf index of %d\n", + __func__, + ~(1 << vf->index), vf->index); + WRITE_VREG(AVS_BUFFERIN, ~(1 << vf->index)); + vf->index = hw->vf_buf_num_used; + } + kfifo_put(&hw->newframe_q, + (const struct vframe_s *)vf); + } + + } + + schedule_work(&hw->set_clk_work); + + timer->expires = jiffies + PUT_INTERVAL; + + add_timer(timer); +} + +#ifdef AVSP_LONG_CABAC + +static void long_cabac_do_work(struct work_struct *work) +{ + int status = 0; + struct vdec_avs_hw_s *hw = gw; +#ifdef PERFORMANCE_DEBUG + pr_info("enter %s buf level (new %d, display %d, recycle %d)\r\n", + __func__, + kfifo_len(&hw->newframe_q), + kfifo_len(&hw->display_q), + kfifo_len(&hw->recycle_q) + ); +#endif + mutex_lock(&vavs_mutex); + long_cabac_busy = 1; + while (READ_VREG(LONG_CABAC_REQ)) { + if (process_long_cabac() < 0) { + status = -1; + break; + } + } + long_cabac_busy = 0; + mutex_unlock(&vavs_mutex); +#ifdef PERFORMANCE_DEBUG + pr_info("exit %s buf level (new %d, display %d, recycle %d)\r\n", + __func__, + kfifo_len(&hw->newframe_q), + kfifo_len(&hw->display_q), + kfifo_len(&hw->recycle_q) + ); +#endif + if (status < 0) { + pr_info("transcoding error, local reset\r\n"); + vavs_local_reset(hw); + } + +} +#endif + +#ifdef AVSP_LONG_CABAC +static void init_avsp_long_cabac_buf(void) +{ +#if 0 + es_write_addr_phy = (unsigned long)codec_mm_alloc_for_dma( + "vavs", + PAGE_ALIGN(MAX_CODED_FRAME_SIZE)/PAGE_SIZE, + 0, CODEC_MM_FLAGS_DMA_CPU); + es_write_addr_virt = codec_mm_phys_to_virt(es_write_addr_phy); + +#elif 0 + es_write_addr_virt = + (void *)dma_alloc_coherent(amports_get_dma_device(), + MAX_CODED_FRAME_SIZE, &es_write_addr_phy, + GFP_KERNEL); +#else + /*es_write_addr_virt = kmalloc(MAX_CODED_FRAME_SIZE, GFP_KERNEL); + * es_write_addr_virt = (void *)__get_free_pages(GFP_KERNEL, + * get_order(MAX_CODED_FRAME_SIZE)); + */ + es_write_addr_virt = &es_write_addr[0]; + if (es_write_addr_virt == NULL) { + pr_err("%s: failed to alloc es_write_addr_virt buffer\n", + __func__); + return; + } + + es_write_addr_phy = dma_map_single(amports_get_dma_device(), + es_write_addr_virt, + MAX_CODED_FRAME_SIZE, DMA_BIDIRECTIONAL); + if (dma_mapping_error(amports_get_dma_device(), + es_write_addr_phy)) { + pr_err("%s: failed to map es_write_addr_virt buffer\n", + __func__); + /*kfree(es_write_addr_virt);*/ + es_write_addr_virt = NULL; + return; + } +#endif + + +#ifdef BITSTREAM_READ_TMP_NO_CACHE + bitstream_read_tmp = + (void *)dma_alloc_coherent(amports_get_dma_device(), + SVA_STREAM_BUF_SIZE, &bitstream_read_tmp_phy, + GFP_KERNEL); + +#else + + bitstream_read_tmp = kmalloc(SVA_STREAM_BUF_SIZE, GFP_KERNEL); + /*bitstream_read_tmp = (void *)__get_free_pages(GFP_KERNEL, + *get_order(MAX_CODED_FRAME_SIZE)); + */ + if (bitstream_read_tmp == NULL) { + pr_err("%s: failed to alloc bitstream_read_tmp buffer\n", + __func__); + return; + } + + bitstream_read_tmp_phy = dma_map_single(amports_get_dma_device(), + bitstream_read_tmp, + SVA_STREAM_BUF_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(amports_get_dma_device(), + bitstream_read_tmp_phy)) { + pr_err("%s: failed to map rpm buffer\n", __func__); + kfree(bitstream_read_tmp); + bitstream_read_tmp = NULL; + return; + } +#endif +} +#endif + + +static s32 vavs_init(struct vdec_avs_hw_s *hw) +{ + int ret, size = -1; + struct firmware_s *fw; + u32 fw_size = 0x1000 * 16; + /*char *buf = vmalloc(0x1000 * 16); + + if (IS_ERR_OR_NULL(buf)) + return -ENOMEM; + */ + fw = vmalloc(sizeof(struct firmware_s) + fw_size); + if (IS_ERR_OR_NULL(fw)) + return -ENOMEM; + + pr_info("vavs_init\n"); + //init_timer(&hw->recycle_timer); + + //hw->stat |= STAT_TIMER_INIT; + + //amvdec_enable(); + + //vdec_enable_DMC(NULL); + + vavs_local_init(hw); + + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXM) + size = get_firmware_data(VIDEO_DEC_AVS_MULTI, fw->data); + else { + if (firmware_sel == 1) + size = get_firmware_data(VIDEO_DEC_AVS_NOCABAC, fw->data); +#ifdef AVSP_LONG_CABAC + else { + init_avsp_long_cabac_buf(); + size = get_firmware_data(VIDEO_DEC_AVS_MULTI, fw->data); + } +#endif + } + + if (size < 0) { + amvdec_disable(); + pr_err("get firmware fail."); + vfree(fw); + return -1; + } + + fw->len = size; + hw->fw = fw; + + if (hw->m_ins_flag) { + timer_setup(&hw->check_timer, check_timer_func, 0); + //init_timer(&hw->check_timer); + //hw->check_timer.data = (ulong) hw; + //hw->check_timer.function = check_timer_func; + hw->check_timer.expires = jiffies + CHECK_INTERVAL; + + + //add_timer(&hw->check_timer); + hw->stat |= STAT_TIMER_ARM; + + INIT_WORK(&hw->work, vavs_work); + + hw->fw = fw; + return 0; + } + + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXM) + ret = amvdec_loadmc_ex(VFORMAT_AVS, NULL, fw->data); + else if (firmware_sel == 1) + ret = amvdec_loadmc_ex(VFORMAT_AVS, "avs_no_cabac", fw->data); + else + ret = amvdec_loadmc_ex(VFORMAT_AVS, NULL, fw->data); + + if (ret < 0) { + amvdec_disable(); + /*vfree(buf);*/ + pr_err("AVS: the %s fw loading failed, err: %x\n", + tee_enabled() ? "TEE" : "local", ret); + return -EBUSY; + } + + /*vfree(buf);*/ + + hw->stat |= STAT_MC_LOAD; + + + /* enable AMRISC side protocol */ + ret = vavs_prot_init(hw); + if (ret < 0) + return ret; + +#ifdef HANDLE_AVS_IRQ + if (vdec_request_irq(VDEC_IRQ_1, vavs_isr, + "vavs-irq", (void *)hw)) { + amvdec_disable(); + pr_info("vavs irq register error.\n"); + return -ENOENT; + } +#endif + + hw->stat |= STAT_ISR_REG; + +#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER + vf_provider_init(&vavs_vf_prov, PROVIDER_NAME, &vavs_vf_provider, hw); + vf_reg_provider(&vavs_vf_prov); + avs_vf_notify_receiver(hw, PROVIDER_NAME, VFRAME_EVENT_PROVIDER_START, NULL); +#else + vf_provider_init(&vavs_vf_prov, PROVIDER_NAME, &vavs_vf_provider, hw); + vf_reg_provider(&vavs_vf_prov); +#endif + + if (hw->vavs_amstream_dec_info.rate != 0) { + if (!hw->is_reset) + avs_vf_notify_receiver(hw, PROVIDER_NAME, + VFRAME_EVENT_PROVIDER_FR_HINT, + (void *)((unsigned long) + hw->vavs_amstream_dec_info.rate)); + hw->fr_hint_status = VDEC_HINTED; + } else + hw->fr_hint_status = VDEC_NEED_HINT; + + hw->stat |= STAT_VF_HOOK; + + timer_setup(&hw->recycle_timer, vavs_put_timer_func, 0); + //hw->recycle_timer.data = (ulong)(hw); + //hw->recycle_timer.function = vavs_put_timer_func; + hw->recycle_timer.expires = jiffies + PUT_INTERVAL; + + add_timer(&hw->recycle_timer); + + hw->stat |= STAT_TIMER_ARM; + +#ifdef AVSP_LONG_CABAC + if (firmware_sel == 0) + INIT_WORK(&long_cabac_wd_work, long_cabac_do_work); +#endif + vdec_source_changed(VFORMAT_AVS, + 1920, 1080, 30); +#ifdef DEBUG_MULTI_WITH_AUTOMODE + if (start_decoding_delay == 0) + amvdec_start(); + else + delay_count = start_decoding_delay/10; +#else + amvdec_start(); +#endif + hw->stat |= STAT_VDEC_RUN; + return 0; +} + +static int amvdec_avs_probe(struct platform_device *pdev) +{ + struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data; + struct vdec_avs_hw_s *hw = NULL; + + if (pdata == NULL) { + pr_info("amvdec_avs memory resource undefined.\n"); + return -EFAULT; + } + + hw = (struct vdec_avs_hw_s *)vzalloc(sizeof(struct vdec_avs_hw_s)); + if (hw == NULL) { + pr_info("\nammvdec_avs decoder driver alloc failed\n"); + return -ENOMEM; + } + pdata->private = hw; + ghw = hw; + atomic_set(&hw->error_handler_run, 0); + hw->m_ins_flag = 0; + + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXM || disable_longcabac_trans) + firmware_sel = 1; + + if (firmware_sel == 1) { +#ifndef USE_DYNAMIC_BUF_NUM + vf_buf_num = 4; +#endif + canvas_base = 0; + canvas_num = 3; + } else { + + canvas_base = 128; + canvas_num = 2; /*NV21*/ + } + + + if (pdata->sys_info) + hw->vavs_amstream_dec_info = *pdata->sys_info; + + pr_info("%s (%d,%d) %d\n", __func__, hw->vavs_amstream_dec_info.width, + hw->vavs_amstream_dec_info.height, hw->vavs_amstream_dec_info.rate); + + pdata->dec_status = vavs_dec_status; + pdata->set_isreset = vavs_set_isreset; + hw->is_reset = 0; + + pdata->user_data_read = NULL; + pdata->reset_userdata_fifo = NULL; + + vavs_vdec_info_init(hw); + +#ifdef ENABLE_USER_DATA + if (NULL == hw->user_data_buffer) { + hw->user_data_buffer = + dma_alloc_coherent(amports_get_dma_device(), + USER_DATA_SIZE, + &hw->user_data_buffer_phys, GFP_KERNEL); + if (!hw->user_data_buffer) { + pr_info("%s: Can not allocate hw->user_data_buffer\n", + __func__); + return -ENOMEM; + } + pr_debug("hw->user_data_buffer = 0x%p, hw->user_data_buffer_phys = 0x%x\n", + hw->user_data_buffer, (u32)hw->user_data_buffer_phys); + } +#endif + INIT_WORK(&hw->set_clk_work, avs_set_clk); + if (vavs_init(hw) < 0) { + pr_info("amvdec_avs init failed.\n"); + kfree(hw->gvs); + hw->gvs = NULL; + pdata->dec_status = NULL; + if (hw->fw) + vfree(hw->fw); + hw->fw = NULL; + return -ENODEV; + } + /*vdec = pdata;*/ + + INIT_WORK(&hw->fatal_error_wd_work, vavs_fatal_error_handler); + atomic_set(&hw->error_handler_run, 0); +#ifdef ENABLE_USER_DATA + INIT_WORK(&hw->userdata_push_work, userdata_push_do_work); +#endif + INIT_WORK(&hw->notify_work, vavs_notify_work); + + return 0; +} + +static int amvdec_avs_remove(struct platform_device *pdev) +{ + struct vdec_avs_hw_s *hw = ghw; + + cancel_work_sync(&hw->fatal_error_wd_work); + atomic_set(&hw->error_handler_run, 0); +#ifdef ENABLE_USER_DATA + cancel_work_sync(&hw->userdata_push_work); +#endif + cancel_work_sync(&hw->notify_work); + cancel_work_sync(&hw->set_clk_work); + if (hw->stat & STAT_VDEC_RUN) { + amvdec_stop(); + hw->stat &= ~STAT_VDEC_RUN; + } + + if (hw->stat & STAT_ISR_REG) { + vdec_free_irq(VDEC_IRQ_1, (void *)vavs_dec_id); + hw->stat &= ~STAT_ISR_REG; + } + + if (hw->stat & STAT_TIMER_ARM) { + del_timer_sync(&hw->recycle_timer); + hw->stat &= ~STAT_TIMER_ARM; + } +#ifdef AVSP_LONG_CABAC + if (firmware_sel == 0) { + mutex_lock(&vavs_mutex); + cancel_work_sync(&long_cabac_wd_work); + mutex_unlock(&vavs_mutex); + + if (es_write_addr_virt) { +#if 0 + codec_mm_free_for_dma("vavs", es_write_addr_phy); +#else + dma_unmap_single(amports_get_dma_device(), + es_write_addr_phy, + MAX_CODED_FRAME_SIZE, DMA_FROM_DEVICE); + /*kfree(es_write_addr_virt);*/ + es_write_addr_virt = NULL; +#endif + } + +#ifdef BITSTREAM_READ_TMP_NO_CACHE + if (bitstream_read_tmp) { + dma_free_coherent(amports_get_dma_device(), + SVA_STREAM_BUF_SIZE, bitstream_read_tmp, + bitstream_read_tmp_phy); + bitstream_read_tmp = NULL; + } +#else + if (bitstream_read_tmp) { + dma_unmap_single(amports_get_dma_device(), + bitstream_read_tmp_phy, + SVA_STREAM_BUF_SIZE, DMA_FROM_DEVICE); + kfree(bitstream_read_tmp); + bitstream_read_tmp = NULL; + } +#endif + } +#endif + if (hw->stat & STAT_VF_HOOK) { + if (hw->fr_hint_status == VDEC_HINTED && !hw->is_reset) + avs_vf_notify_receiver(hw, PROVIDER_NAME, + VFRAME_EVENT_PROVIDER_FR_END_HINT, NULL); + hw->fr_hint_status = VDEC_NO_NEED_HINT; + vf_unreg_provider(&vavs_vf_prov); + hw->stat &= ~STAT_VF_HOOK; + } + +#ifdef ENABLE_USER_DATA + if (hw->user_data_buffer != NULL) { + dma_free_coherent( + amports_get_dma_device(), + USER_DATA_SIZE, + hw->user_data_buffer, + hw->user_data_buffer_phys); + hw->user_data_buffer = NULL; + hw->user_data_buffer_phys = 0; + } +#endif + + if (hw->fw) { + vfree(hw->fw); + hw->fw = NULL; + } + + //amvdec_disable(); + //vdec_disable_DMC(NULL); + + hw->pic_type = 0; + if (hw->mm_blk_handle) { + decoder_bmmu_box_free(hw->mm_blk_handle); + hw->mm_blk_handle = NULL; + } +#ifdef DEBUG_PTS + pr_debug("pts hit %d, pts missed %d, i hit %d, missed %d\n", hw->pts_hit, + hw->pts_missed, hw->pts_i_hit, hw->pts_i_missed); + pr_debug("total frame %d, hw->avi_flag %d, rate %d\n", hw->total_frame, hw->avi_flag, + hw->vavs_amstream_dec_info.rate); +#endif + kfree(hw->gvs); + hw->gvs = NULL; + vfree(hw); + return 0; +} + +/****************************************/ +#if 0 +static struct platform_driver amvdec_avs_driver = { + .probe = amvdec_avs_probe, + .remove = amvdec_avs_remove, + .driver = { + .name = DRIVER_NAME, + } +}; +#endif + +static void recycle_frames(struct vdec_avs_hw_s *hw); + +static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) +{ + struct vdec_avs_hw_s *hw = + (struct vdec_avs_hw_s *)vdec->private; + int ret = 1; + unsigned buf_busy_mask = (1 << hw->vf_buf_num_used) - 1; +#ifdef DEBUG_MULTI_FRAME_INS + if ((DECODE_ID(hw) == 0) && run_count[0] > run_count[1] && + run_count[1] < max_run_count[1]) + return 0; + + if ((DECODE_ID(hw) == 1) && run_count[1] >= run_count[0] && + run_count[0] < max_run_count[0]) + return 0; + + if (max_run_count[DECODE_ID(hw)] > 0 && + run_count[DECODE_ID(hw)] >= max_run_count[DECODE_ID(hw)]) + return 0; +#endif + if (vdec_stream_based(vdec) && (hw->init_flag == 0) + && pre_decode_buf_level != 0) { + u32 rp, wp, level; + + rp = STBUF_READ(&vdec->vbuf, get_rp); + wp = STBUF_READ(&vdec->vbuf, get_wp); + if (wp < rp) + level = vdec->input.size + wp - rp; + else + level = wp - rp; + + if (level < pre_decode_buf_level) { + hw->not_run_ready++; + return 0; + } + } + + if (hw->reset_decode_flag == 0 && + hw->again_flag == 0 && + (hw->buf_status & buf_busy_mask) == buf_busy_mask) { + recycle_frames(hw); + if (hw->buf_recycle_status == 0) + ret = 0; + } + + if (again_threshold > 0 && + hw->pre_parser_wr_ptr != 0 && + hw->again_flag && + (!vdec_frame_based(vdec))) { + u32 parser_wr_ptr = + STBUF_READ(&vdec->vbuf, get_rp); + if (parser_wr_ptr >= hw->pre_parser_wr_ptr && + (parser_wr_ptr - hw->pre_parser_wr_ptr) < + again_threshold) { + int r = vdec_sync_input(vdec); + debug_print(hw, PRINT_FLAG_VFRAME_DETAIL, + "%s buf lelvel:%x\n", __func__, r); + ret = 0; + } + } + + if (ret) + hw->not_run_ready = 0; + else + hw->not_run_ready++; + + if (ret != 0) { + if (vdec->parallel_dec == 1) + return (unsigned long)(CORE_MASK_VDEC_1); + else + return (unsigned long)(CORE_MASK_VDEC_1 | CORE_MASK_HEVC); + } else + return 0; +} + +static void vavs_work(struct work_struct *work) +{ + struct vdec_avs_hw_s *hw = + container_of(work, struct vdec_avs_hw_s, work); + struct vdec_s *vdec = hw_to_vdec(hw); + if (hw->dec_result != DEC_RESULT_AGAIN) + debug_print(hw, PRINT_FLAG_RUN_FLOW, + "ammvdec_avs: vavs_work,result=%d,status=%d\n", + hw->dec_result, hw_to_vdec(hw)->next_status); + hw->again_flag = 0; + if (hw->dec_result == DEC_RESULT_USERDATA) { + userdata_push_process(hw); + return; + } else if (hw->dec_result == DEC_RESULT_DONE) { + + if (!hw->ctx_valid) + hw->ctx_valid = 1; +#ifdef DEBUG_MULTI_FRAME_INS + msleep(delay); +#endif + vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk); + } else if (hw->dec_result == DEC_RESULT_AGAIN + && (hw_to_vdec(hw)->next_status != + VDEC_STATUS_DISCONNECTED)) { + /* + stream base: stream buf empty or timeout + frame base: vdec_prepare_input fail + */ + hw->again_flag = 1; + if (!vdec_has_more_input(hw_to_vdec(hw))) { + hw->dec_result = DEC_RESULT_EOS; + vdec_schedule_work(&hw->work); + return; + } + } else if (hw->dec_result == DEC_RESULT_GET_DATA + && (hw_to_vdec(hw)->next_status != + VDEC_STATUS_DISCONNECTED)) { + if (!vdec_has_more_input(hw_to_vdec(hw))) { + hw->dec_result = DEC_RESULT_EOS; + vdec_schedule_work(&hw->work); + return; + } + debug_print(hw, PRINT_FLAG_VLD_DETAIL, + "%s DEC_RESULT_GET_DATA %x %x %x\n", + __func__, + READ_VREG(VLD_MEM_VIFIFO_LEVEL), + READ_VREG(VLD_MEM_VIFIFO_WP), + READ_VREG(VLD_MEM_VIFIFO_RP)); + vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk); + vdec_clean_input(hw_to_vdec(hw)); + return; + } else if (hw->dec_result == DEC_RESULT_FORCE_EXIT) { + debug_print(hw, PRINT_FLAG_ERROR, + "%s: force exit\n", __func__); + if (hw->stat & STAT_ISR_REG) { + amvdec_stop(); + /*disable mbox interrupt */ + WRITE_VREG(ASSIST_MBOX1_MASK, 0); + vdec_free_irq(VDEC_IRQ_1, (void *)hw); + hw->stat &= ~STAT_ISR_REG; + } + } else if (hw->dec_result == DEC_RESULT_EOS) { + debug_print(hw, PRINT_FLAG_DECODING, + "%s: end of stream\n", __func__); + if (hw->stat & STAT_VDEC_RUN) { + amvdec_stop(); + hw->stat &= ~STAT_VDEC_RUN; + } + hw->eos = 1; + vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk); + vdec_clean_input(hw_to_vdec(hw)); + } + if (hw->stat & STAT_VDEC_RUN) { +#if DEBUG_MULTI_FLAG == 1 +#else + amvdec_stop(); +#endif + hw->stat &= ~STAT_VDEC_RUN; + } + /*wait_vmmpeg12_search_done(hw);*/ + if (hw->stat & STAT_TIMER_ARM) { + del_timer_sync(&hw->check_timer); + hw->stat &= ~STAT_TIMER_ARM; + } + if (hw->dec_result == DEC_RESULT_DONE) + hw->buf_recycle_status = 0; + debug_print(hw, PRINT_FLAG_RUN_FLOW, "work end %d\n", hw->dec_result); + if (vdec->parallel_dec == 1) + vdec_core_finish_run(hw_to_vdec(hw), CORE_MASK_VDEC_1); + else + vdec_core_finish_run(hw_to_vdec(hw), CORE_MASK_VDEC_1 | CORE_MASK_HEVC); + + if (hw->vdec_cb) { + hw->vdec_cb(hw_to_vdec(hw), hw->vdec_cb_arg); + debug_print(hw, 0x80000, + "%s:\n", __func__); + } +} + + +static void reset_process_time(struct vdec_avs_hw_s *hw) +{ + if (!hw->m_ins_flag) + return; + if (hw->start_process_time) { + unsigned process_time = + 1000 * (jiffies - hw->start_process_time) / HZ; + hw->start_process_time = 0; + if (process_time > max_process_time[DECODE_ID(hw)]) + max_process_time[DECODE_ID(hw)] = process_time; + } +} +static void start_process_time(struct vdec_avs_hw_s *hw) +{ + hw->decode_timeout_count = 2; + hw->start_process_time = jiffies; +} + +static void handle_decoding_error(struct vdec_avs_hw_s *hw) +{ + int i; + unsigned long flags; + struct vframe_s *vf; + spin_lock_irqsave(&lock, flags); + for (i = 0; i < VF_POOL_SIZE; i++) { + vf = &hw->vfpool[i].vf; + if (vf->index < hw->vf_buf_num_used) { + hw->vfpool[i].detached = 1; + hw->vfbuf_use[vf->index] = 0; + } + } + if (error_handle_policy & 0x2) { + while (!kfifo_is_empty(&hw->display_q)) { + if (kfifo_get(&hw->display_q, &vf)) { + if (buf_of_vf(vf)->detached !=0) { + debug_print(hw, PRINT_FLAG_DECODING, + "%s recycle %d => newframe_q\n", + __func__, + vf->index); + vf->index = hw->vf_buf_num_used; + buf_of_vf(vf)->detached = 0; + kfifo_put(&hw->newframe_q, + (const struct vframe_s *)vf); + } + } + + } + } + clear_pts_buf(hw); + hw->decode_pic_count = 0; + hw->reset_decode_flag = 1; + hw->pre_parser_wr_ptr = 0; + hw->buf_status = 0; + hw->throw_pb_flag = 1; + spin_unlock_irqrestore(&lock, flags); +} + +static void timeout_process(struct vdec_avs_hw_s *hw) +{ + struct vdec_s *vdec = hw_to_vdec(hw); + amvdec_stop(); + if (error_handle_policy & 0x1) { + handle_decoding_error(hw); + } else { + vavs_save_regs(hw); + + //if (hw->decode_pic_count == 0) + hw->decode_pic_count++; + if ((hw->decode_pic_count & 0xffff) == 0) { + /*make ucode do not handle it as first picture*/ + hw->decode_pic_count++; + } + } + hw->dec_result = DEC_RESULT_DONE; + + debug_print(hw, PRINT_FLAG_ERROR, + "%s decoder timeout, status=%d, level=%d, bit_cnt=0x%x\n", + __func__, vdec->status, READ_VREG(VLD_MEM_VIFIFO_LEVEL), READ_VREG(VIFF_BIT_CNT)); + reset_process_time(hw); + vdec_schedule_work(&hw->work); +} + + +static void recycle_frame_bufferin(struct vdec_avs_hw_s *hw) +{ + if (!kfifo_is_empty(&hw->recycle_q) && (READ_VREG(AVS_BUFFERIN) == 0)) { + struct vframe_s *vf; + + if (kfifo_get(&hw->recycle_q, &vf)) { + if (buf_of_vf(vf)->detached) { + debug_print(hw, 0, + "%s recycle detached vf, index=%d detched %d used %d\n", + __func__, vf->index, + buf_of_vf(vf)->detached, + hw->vfbuf_use[vf->index]); + } + if ((vf->index < hw->vf_buf_num_used) && + (buf_of_vf(vf)->detached == 0) && + (--hw->vfbuf_use[vf->index] == 0)) { + hw->buf_recycle_status |= (1 << vf->index); + WRITE_VREG(AVS_BUFFERIN, ~(1 << vf->index)); + debug_print(hw, PRINT_FLAG_DECODING, + "%s WRITE_VREG(AVS_BUFFERIN, 0x%x) for vf index of %d => buf_recycle_status 0x%x\n", + __func__, + READ_VREG(AVS_BUFFERIN), vf->index, + hw->buf_recycle_status); + } + vf->index = hw->vf_buf_num_used; + buf_of_vf(vf)->detached = 0; + kfifo_put(&hw->newframe_q, + (const struct vframe_s *)vf); + } + + } + +} + +static void recycle_frames(struct vdec_avs_hw_s *hw) +{ + while (!kfifo_is_empty(&hw->recycle_q)) { + struct vframe_s *vf; + + if (kfifo_get(&hw->recycle_q, &vf)) { + if (buf_of_vf(vf)->detached) { + debug_print(hw, 0, + "%s recycle detached vf, index=%d detched %d used %d\n", + __func__, vf->index, + buf_of_vf(vf)->detached, + hw->vfbuf_use[vf->index]); + } + + + if ((vf->index < hw->vf_buf_num_used) && + (buf_of_vf(vf)->detached == 0) && + (--hw->vfbuf_use[vf->index] == 0)) { + hw->buf_recycle_status |= (1 << vf->index); + debug_print(hw, PRINT_FLAG_DECODING, + "%s for vf index of %d => buf_recycle_status 0x%x\n", + __func__, + vf->index, + hw->buf_recycle_status); + } + vf->index = hw->vf_buf_num_used; + buf_of_vf(vf)->detached = 0; + kfifo_put(&hw->newframe_q, + (const struct vframe_s *)vf); + } + + } + +} + + +static void check_timer_func(struct timer_list *timer) +{ + struct vdec_avs_hw_s *hw = container_of(timer, + struct vdec_avs_hw_s, check_timer); + struct vdec_s *vdec = hw_to_vdec(hw); + unsigned int timeout_val = decode_timeout_val; + unsigned long flags; + + if (hw->m_ins_flag && + (debug & + DEBUG_WAIT_DECODE_DONE_WHEN_STOP) == 0 && + vdec->next_status == + VDEC_STATUS_DISCONNECTED) { + hw->dec_result = DEC_RESULT_FORCE_EXIT; + vdec_schedule_work(&hw->work); + debug_print(hw, + 0, "vdec requested to be disconnected\n"); + return; + } + + /*recycle*/ + if (!hw->m_ins_flag) { + spin_lock_irqsave(&lock, flags); + recycle_frame_bufferin(hw); + spin_unlock_irqrestore(&lock, flags); + } + + if (hw->m_ins_flag) { + if ((READ_VREG(AV_SCRATCH_5) & 0xf) != 0 && + (READ_VREG(AV_SCRATCH_5) & 0xff00) != 0){ + /*ucode buffer empty*/ + if ((kfifo_len(&hw->recycle_q) == 0) && + (kfifo_len(&hw->display_q) == 0)) { + debug_print(hw, + 0, "AV_SCRATCH_5=0x%x, recover ucode buffer_status\n", + READ_VREG(AV_SCRATCH_5)); + WRITE_VREG(AV_SCRATCH_5, 0x10); + /*let ucode to recover buffer_status*/ + } + } + } + if (radr != 0) { + if (rval != 0) { + WRITE_VREG(radr, rval); + pr_info("WRITE_VREG(%x,%x)\n", radr, rval); + } else + pr_info("READ_VREG(%x)=%x\n", radr, READ_VREG(radr)); + rval = 0; + radr = 0; + } + + if (udebug_flag != hw->old_udebug_flag) { + WRITE_VREG(DECODE_STOP_POS, udebug_flag); + hw->old_udebug_flag = udebug_flag; + } + if (dbg_cmd != 0) { + if (dbg_cmd == 1) { + int r = vdec_sync_input(vdec); + dbg_cmd = 0; + pr_info( + "vdec_sync_input=>0x%x, (lev %x, wp %x rp %x, prp %x, pwp %x)\n", + r, + READ_VREG(VLD_MEM_VIFIFO_LEVEL), + READ_VREG(VLD_MEM_VIFIFO_WP), + READ_VREG(VLD_MEM_VIFIFO_RP), + STBUF_READ(&vdec->vbuf, get_rp), + STBUF_READ(&vdec->vbuf, get_wp)); + } + } + + if ((debug & DEBUG_FLAG_DISABLE_TIMEOUT) == 0 && + (timeout_val > 0) && + (hw->start_process_time > 0) && + ((1000 * (jiffies - hw->start_process_time) / HZ) + > timeout_val)) { + if (hw->last_vld_level == READ_VREG(VLD_MEM_VIFIFO_LEVEL)) { + if (hw->decode_timeout_count > 0) + hw->decode_timeout_count--; + if (hw->decode_timeout_count == 0) + timeout_process(hw); + } + hw->last_vld_level = READ_VREG(VLD_MEM_VIFIFO_LEVEL); + } + + if (READ_VREG(AVS_SOS_COUNT)) { + if (!error_recovery_mode) { + amvdec_stop(); + if (error_handle_policy & 0x1) { + handle_decoding_error(hw); + } else { + vavs_save_regs(hw); + + //if (hw->decode_pic_count == 0) + hw->decode_pic_count++; + if ((hw->decode_pic_count & 0xffff) == 0) { + /*make ucode do not handle it as first picture*/ + hw->decode_pic_count++; + } + } + hw->dec_result = DEC_RESULT_DONE; + + debug_print(hw, PRINT_FLAG_ERROR, + "%s decoder error, status=%d, level=%d, AVS_SOS_COUNT=0x%x\n", + __func__, vdec->status, READ_VREG(VLD_MEM_VIFIFO_LEVEL), + READ_VREG(AVS_SOS_COUNT)); + reset_process_time(hw); + vdec_schedule_work(&hw->work); + } + } + + if ((hw->ucode_pause_pos != 0) && + (hw->ucode_pause_pos != 0xffffffff) && + udebug_pause_pos != hw->ucode_pause_pos) { + hw->ucode_pause_pos = 0; + WRITE_VREG(DEBUG_REG1, 0); + } + + if (vdec->next_status == VDEC_STATUS_DISCONNECTED) { + hw->dec_result = DEC_RESULT_FORCE_EXIT; + vdec_schedule_work(&hw->work); + pr_info("vdec requested to be disconnected\n"); + return; + } + + mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL); +} + +static int avs_hw_ctx_restore(struct vdec_avs_hw_s *hw) +{ + /*int r = 0;*/ + vavs_prot_init(hw); + + return 0; +} + +static unsigned char get_data_check_sum + (struct vdec_avs_hw_s *hw, int size) +{ + int jj; + int sum = 0; + u8 *data = NULL; + + if (!hw->chunk->block->is_mapped) + data = codec_mm_vmap(hw->chunk->block->start + + hw->chunk->offset, size); + else + data = ((u8 *)hw->chunk->block->start_virt) + + hw->chunk->offset; + + for (jj = 0; jj < size; jj++) + sum += data[jj]; + + if (!hw->chunk->block->is_mapped) + codec_mm_unmap_phyaddr(data); + return sum; +} + +static void run(struct vdec_s *vdec, unsigned long mask, +void (*callback)(struct vdec_s *, void *), + void *arg) +{ + struct vdec_avs_hw_s *hw = + (struct vdec_avs_hw_s *)vdec->private; + int save_reg; + int size, ret; + if (!hw->vdec_pg_enable_flag) { + hw->vdec_pg_enable_flag = 1; + amvdec_enable(); + } + save_reg = READ_VREG(POWER_CTL_VLD); + /* reset everything except DOS_TOP[1] and APB_CBUS[0]*/ + debug_print(hw, PRINT_FLAG_RUN_FLOW,"run in\n"); + if (vdec_stream_based(vdec)) { + hw->pre_parser_wr_ptr = + STBUF_READ(&vdec->vbuf, get_wp); + } +#if 1 +#if DEBUG_MULTI_FLAG > 0 + if (hw->decode_pic_count == 0) { +#endif + WRITE_VREG(DOS_SW_RESET0, 0xfffffff0); + WRITE_VREG(DOS_SW_RESET0, 0); + WRITE_VREG(POWER_CTL_VLD, save_reg); + hw->run_count++; + run_count[DECODE_ID(hw)] = hw->run_count; + vdec_reset_core(vdec); +#if DEBUG_MULTI_FLAG > 0 + } +#endif +#else + vdec_reset_core(vdec); +#endif + hw->vdec_cb_arg = arg; + hw->vdec_cb = callback; + + size = vdec_prepare_input(vdec, &hw->chunk); + if (debug & DEBUG_FLAG_PREPARE_MORE_INPUT) { + if (size < start_decode_buf_level) { + /*debug_print(hw, PRINT_FLAG_VLD_DETAIL, + "DEC_RESULT_AGAIN %x %x %x\n", + READ_VREG(VLD_MEM_VIFIFO_LEVEL), + READ_VREG(VLD_MEM_VIFIFO_WP), + READ_VREG(VLD_MEM_VIFIFO_RP));*/ + + hw->input_empty++; + hw->dec_result = DEC_RESULT_AGAIN; + vdec_schedule_work(&hw->work); + return; + } + } else { + if (size < 0) { + hw->input_empty++; + hw->dec_result = DEC_RESULT_AGAIN; + vdec_schedule_work(&hw->work); + return; + } + } + if (input_frame_based(vdec)) { + u8 *data = NULL; + + if (!hw->chunk->block->is_mapped) + data = codec_mm_vmap(hw->chunk->block->start + + hw->chunk->offset, size); + else + data = ((u8 *)hw->chunk->block->start_virt) + + hw->chunk->offset; + + if (debug & PRINT_FLAG_RUN_FLOW + ) { + debug_print(hw, 0, + "%s decode_pic_count %d buf_recycle_status 0x%x: size 0x%x sum 0x%x %02x %02x %02x %02x %02x %02x .. %02x %02x %02x %02x\n", + __func__, hw->decode_pic_count, + hw->buf_recycle_status, + size, get_data_check_sum(hw, size), + data[0], data[1], data[2], data[3], + data[4], data[5], data[size - 4], + data[size - 3], data[size - 2], + data[size - 1]); + } + if (debug & PRINT_FRAMEBASE_DATA + ) { + int jj; + + for (jj = 0; jj < size; jj++) { + if ((jj & 0xf) == 0) + debug_print(hw, + PRINT_FRAMEBASE_DATA, + "%06x:", jj); + debug_print(hw, + PRINT_FRAMEBASE_DATA, + "%02x ", data[jj]); + if (((jj + 1) & 0xf) == 0) + debug_print(hw, + PRINT_FRAMEBASE_DATA, + "\n"); + } + } + + if (!hw->chunk->block->is_mapped) + codec_mm_unmap_phyaddr(data); + } else + debug_print(hw, PRINT_FLAG_RUN_FLOW, + "%s decode_pic_count %d buf_recycle_status 0x%x: %x %x %x %x %x size 0x%x\n", + __func__, + hw->decode_pic_count, + hw->buf_recycle_status, + READ_VREG(VLD_MEM_VIFIFO_LEVEL), + READ_VREG(VLD_MEM_VIFIFO_WP), + READ_VREG(VLD_MEM_VIFIFO_RP), + STBUF_READ(&vdec->vbuf, get_rp), + STBUF_READ(&vdec->vbuf, get_wp), + size); + + + hw->input_empty = 0; + debug_print(hw, PRINT_FLAG_RUN_FLOW, + "%s,%d, size=%d\n", __func__, __LINE__, size); + + /*vdec_enable_input(vdec); + need run after VC1_CONTROL_REG is configured + */ + hw->init_flag = 1; + + if (hw->chunk) + debug_print(hw, PRINT_FLAG_RUN_FLOW, + "input chunk offset %d, size %d\n", + hw->chunk->offset, hw->chunk->size); + + hw->dec_result = DEC_RESULT_NONE; + /*vdec->mc_loaded = 0;*/ + if (vdec->mc_loaded) { + /*firmware have load before, + and not changes to another. + ignore reload. + */ + } else { + ret = amvdec_vdec_loadmc_buf_ex(VFORMAT_AVS, "avs_multi", vdec, + hw->fw->data, hw->fw->len); + if (ret < 0) { + pr_err("[%d] %s: the %s fw loading failed, err: %x\n", vdec->id, + hw->fw->name, tee_enabled() ? "TEE" : "local", ret); + hw->dec_result = DEC_RESULT_FORCE_EXIT; + vdec_schedule_work(&hw->work); + return; + } + vdec->mc_loaded = 1; + vdec->mc_type = VFORMAT_AVS; + } + if (avs_hw_ctx_restore(hw) < 0) { + hw->dec_result = DEC_RESULT_ERROR; + debug_print(hw, PRINT_FLAG_ERROR, + "ammvdec_avs: error HW context restore\n"); + vdec_schedule_work(&hw->work); + return; + } + + /* + This configureation of VC1_CONTROL_REG will + pop bits (even no data in the stream buffer) if input is enabled, + so it can only be configured before vdec_enable_input() is called. + So move this code from ucode to here + */ +#define DISABLE_DBLK_HCMD 0 +#define DISABLE_MC_HCMD 0 + WRITE_VREG(VC1_CONTROL_REG, (DISABLE_DBLK_HCMD<<6) | + (DISABLE_MC_HCMD<<5) | (1 << 7) | (0xc <<8) | (1<<14)); + if (vdec_frame_based(vdec)) { + size = hw->chunk->size + + (hw->chunk->offset & (VDEC_FIFO_ALIGN - 1)); + } + + + vdec_enable_input(vdec); + /**/ + + /*wmb();*/ + hw->stat |= STAT_MC_LOAD; + hw->last_vld_level = 0; + + debug_print(hw, PRINT_FLAG_DECODING, + "%s READ_VREG(AVS_BUFFERIN)=0x%x, recycle_q num %d\n", + __func__, READ_VREG(AVS_BUFFERIN), + kfifo_len(&hw->recycle_q)); + + WRITE_VREG(VIFF_BIT_CNT, size * 8); + if (hw->reset_decode_flag) + WRITE_VREG(DECODE_STATUS, 0); + else { + recycle_frames(hw); + avs_pts_check_in(hw, + hw->decode_pic_count & 0xffff, + hw->chunk); + + WRITE_VREG(DECODE_STATUS, + (hw->decode_pic_count & 0xffff) | + ((~hw->buf_recycle_status) << 16)); + } + + hw->reset_decode_flag = 0; + //hw->decode_status_skip_pic_done_flag = 0; + start_process_time(hw); +#if DEBUG_MULTI_FLAG == 1 + if (hw->decode_pic_count > 0) + WRITE_VREG(DECODE_STATUS, 0xff); + else +#endif + amvdec_start(); + hw->stat |= STAT_VDEC_RUN; + + hw->stat |= STAT_TIMER_ARM; + + mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL); +} + +static void reset(struct vdec_s *vdec) +{ +} + +static irqreturn_t vmavs_isr_thread_fn(struct vdec_s *vdec, int irq) +{ + struct vdec_avs_hw_s *hw = + (struct vdec_avs_hw_s *)vdec->private; + u32 reg; + struct vframe_s *vf = NULL; + u32 dur; + u32 repeat_count; + u32 picture_type; + u32 buffer_index; + u32 frame_size; + bool force_interlaced_frame = false; + unsigned int pts, pts_valid = 0, offset = 0; + u64 pts_us64; + u32 debug_tag; + u32 buffer_status_debug; + //struct vdec_avs_hw_s *hw = (struct vdec_avs_hw_s *)dev_id; + + /*if (debug & AVS_DEBUG_UCODE) { + if (READ_VREG(AV_SCRATCH_E) != 0) { + pr_info("dbg%x: %x\n", READ_VREG(AV_SCRATCH_E), + READ_VREG(AV_SCRATCH_D)); + WRITE_VREG(AV_SCRATCH_E, 0); + } + }*/ + + debug_print(hw, PRINT_FLAG_RUN_FLOW, "READ_VREG(AVS_BUFFEROUT) 0x%x, READ_VREG(DECODE_STATUS) 0x%x READ_VREG(AV_SCRATCH_N) 0x%x, READ_VREG(DEBUG_REG1) 0x%x\n", + READ_VREG(AVS_BUFFEROUT),READ_VREG(DECODE_STATUS), READ_VREG(AV_SCRATCH_N), READ_VREG(DEBUG_REG1)); + + debug_tag = READ_VREG(DEBUG_REG1); + buffer_status_debug = debug_tag >> 16; + debug_tag &= 0xffff; + /* if (debug_tag & 0x10000) { + int i; + dma_sync_single_for_cpu( + amports_get_dma_device(), + hw->lmem_phy_addr, + LMEM_BUF_SIZE, + DMA_FROM_DEVICE); + + debug_print(hw, 0, + "LMEM<tag %x>:\n", debug_tag); + + for (i = 0; i < 0x400; i += 4) { + int ii; + unsigned short *lmem_ptr = hw->lmem_addr; + if ((i & 0xf) == 0) + debug_print_cont(hw, 0, "%03x: ", i); + for (ii = 0; ii < 4; ii++) { + debug_print_cont(hw, 0, "%04x ", + lmem_ptr[i + 3 - ii]); + } + if (((i + ii) & 0xf) == 0) + debug_print_cont(hw, 0, "\n"); + } + + if (((udebug_pause_pos & 0xffff) + == (debug_tag & 0xffff)) && + (udebug_pause_decode_idx == 0 || + udebug_pause_decode_idx == hw->decode_pic_count) && + (udebug_pause_val == 0 || + udebug_pause_val == READ_VREG(DEBUG_REG2))) { + udebug_pause_pos &= 0xffff; + hw->ucode_pause_pos = udebug_pause_pos; + } + else if (debug_tag & 0x20000) + hw->ucode_pause_pos = 0xffffffff; + if (hw->ucode_pause_pos) + reset_process_time(hw); + else + WRITE_VREG(DEBUG_REG1, 0); + } else*/ if (debug_tag != 0) { + debug_print(hw, 1, + "dbg%x: %x buffer_status 0x%x l/w/r %x %x %x bitcnt %x AVAIL %x\n", + debug_tag, + READ_VREG(DEBUG_REG2), + buffer_status_debug, + READ_VREG(VLD_MEM_VIFIFO_LEVEL), + READ_VREG(VLD_MEM_VIFIFO_WP), + READ_VREG(VLD_MEM_VIFIFO_RP), + READ_VREG(VIFF_BIT_CNT), + READ_VREG(VLD_MEM_VIFIFO_BYTES_AVAIL)); + + if (((udebug_pause_pos & 0xffff) + == (debug_tag & 0xffff)) && + (udebug_pause_decode_idx == 0 || + udebug_pause_decode_idx == hw->decode_pic_count) && + (udebug_pause_val == 0 || + udebug_pause_val == READ_VREG(DEBUG_REG2)) && + (udebug_pause_ins_id == 0 || + DECODE_ID(hw) == (udebug_pause_ins_id -1))) { + udebug_pause_pos &= 0xffff; + hw->ucode_pause_pos = udebug_pause_pos; + if (debug & DEBUG_PIC_DONE_WHEN_UCODE_PAUSE) { + hw->decode_pic_count++; + if ((hw->decode_pic_count & 0xffff) == 0) { + /*make ucode do not handle it as first picture*/ + hw->decode_pic_count++; + } + reset_process_time(hw); + hw->dec_result = DEC_RESULT_DONE; + amvdec_stop(); + vavs_save_regs(hw); + debug_print(hw, PRINT_FLAG_DECODING, + "%s ucode pause, force done, decode_pic_count = %d, bit_cnt=0x%x\n", + __func__, + hw->decode_pic_count, + READ_VREG(VIFF_BIT_CNT)); + vdec_schedule_work(&hw->work); + return IRQ_HANDLED; + } + } + if (hw->ucode_pause_pos) + reset_process_time(hw); + else + WRITE_VREG(DEBUG_REG1, 0); + return IRQ_HANDLED; + } else { + debug_print(hw, PRINT_FLAG_DECODING, + "%s decode_status 0x%x, buffer_status 0x%x\n", + __func__, + READ_VREG(DECODE_STATUS), + buffer_status_debug); + } + +#ifdef AVSP_LONG_CABAC + if (firmware_sel == 0 && READ_VREG(LONG_CABAC_REQ)) { +#ifdef PERFORMANCE_DEBUG + pr_info("%s:schedule long_cabac_wd_work\r\n", __func__); +#endif + pr_info("schedule long_cabac_wd_work and requested from %d\n", + (READ_VREG(LONG_CABAC_REQ) >> 8)&0xFF); + schedule_work(&long_cabac_wd_work); + } +#endif + +#ifdef ENABLE_USER_DATA + if (UserDataHandler(hw)) + return IRQ_HANDLED; +#endif + reg = READ_VREG(AVS_BUFFEROUT); + if (reg) { + unsigned short decode_pic_count + = READ_VREG(DECODE_PIC_COUNT); + debug_print(hw, PRINT_FLAG_DECODING, "AVS_BUFFEROUT=0x%x decode_pic_count %d\n", + reg, decode_pic_count); + if (pts_by_offset) { + offset = READ_VREG(AVS_OFFSET_REG); + debug_print(hw, PRINT_FLAG_DECODING, "AVS OFFSET=%x\n", offset); + if ((vdec->vbuf.no_parser == 0) || (vdec->vbuf.use_ptsserv)) { + if (pts_lookup_offset_us64(PTS_TYPE_VIDEO, offset, &pts, + &frame_size, 0, &pts_us64) == 0) { + pts_valid = 1; +#ifdef DEBUG_PTS + hw->pts_hit++; +#endif + } else { +#ifdef DEBUG_PTS + hw->pts_missed++; +#endif + } + } + } + + repeat_count = READ_VREG(AVS_REPEAT_COUNT); +#ifdef USE_DYNAMIC_BUF_NUM + buffer_index = + ((reg & 0x7) + + (((reg >> 8) & 0x3) << 3) - 1) & 0x1f; +#else + if (firmware_sel == 0) + buffer_index = + ((reg & 0x7) + + (((reg >> 8) & 0x3) << 3) - 1) & 0x1f; + else + buffer_index = + ((reg & 0x7) - 1) & 3; +#endif + picture_type = (reg >> 3) & 7; +#ifdef DEBUG_PTS + if (picture_type == I_PICTURE) { + /* pr_info("I offset 0x%x, pts_valid %d\n", + * offset, pts_valid); + */ + if (!pts_valid) + hw->pts_i_missed++; + else + hw->pts_i_hit++; + } +#endif + + if ((dec_control & DEC_CONTROL_FLAG_FORCE_2500_1080P_INTERLACE) + && hw->frame_width == 1920 && hw->frame_height == 1080) { + force_interlaced_frame = true; + } + + if (hw->throw_pb_flag && picture_type != I_PICTURE) { + + debug_print(hw, PRINT_FLAG_DECODING, + "%s WRITE_VREG(AVS_BUFFERIN, 0x%x) for throwing picture with type of %d\n", + __func__, + ~(1 << buffer_index), picture_type); + + WRITE_VREG(AVS_BUFFERIN, ~(1 << buffer_index)); + } else if (reg & INTERLACE_FLAG || force_interlaced_frame) { /* interlace */ + hw->throw_pb_flag = 0; + + debug_print(hw, PRINT_FLAG_VFRAME_DETAIL, + "interlace, picture type %d\n", + picture_type); + + if (kfifo_get(&hw->newframe_q, &vf) == 0) { + pr_info + ("fatal error, no available buffer slot."); + return IRQ_HANDLED; + } + set_frame_info(hw, vf, &dur); + vf->bufWidth = 1920; + hw->pic_type = 2; + if ((picture_type == I_PICTURE) && pts_valid) { + vf->pts = pts; + vf->pts_us64 = pts_us64; + if ((repeat_count > 1) && hw->avi_flag) { + /* hw->next_pts = pts + + * (hw->vavs_amstream_dec_info.rate * + * repeat_count >> 1)*15/16; + */ + hw->next_pts = + pts + + (dur * repeat_count >> 1) * + 15 / 16; + } else + hw->next_pts = 0; + } else { + vf->pts = hw->next_pts; + if (vf->pts == 0) { + vf->pts_us64 = 0; + } + if ((repeat_count > 1) && hw->avi_flag) { + /* vf->duration = + * hw->vavs_amstream_dec_info.rate * + * repeat_count >> 1; + */ + vf->duration = dur * repeat_count >> 1; + if (hw->next_pts != 0) { + hw->next_pts += + ((vf->duration) - + ((vf->duration) >> 4)); + } + } else { + /* vf->duration = + * hw->vavs_amstream_dec_info.rate >> 1; + */ + vf->duration = dur >> 1; + hw->next_pts = 0; + } + } + vf->signal_type = 0; + vf->index = buffer_index; + vf->duration_pulldown = 0; + if (force_interlaced_frame) { + vf->type = VIDTYPE_INTERLACE_TOP; + }else{ + vf->type = + (reg & TOP_FIELD_FIRST_FLAG) + ? VIDTYPE_INTERLACE_TOP + : VIDTYPE_INTERLACE_BOTTOM; + } +#ifdef NV21 + vf->type |= VIDTYPE_VIU_NV21; +#endif + if (hw->m_ins_flag) { + vf->canvas0Addr = vf->canvas1Addr = -1; + vf->plane_num = 2; + + vf->canvas0_config[0] = hw->canvas_config[buffer_index][0]; + vf->canvas0_config[1] = hw->canvas_config[buffer_index][1]; + + vf->canvas1_config[0] = hw->canvas_config[buffer_index][0]; + vf->canvas1_config[1] = hw->canvas_config[buffer_index][1]; + } else + vf->canvas0Addr = vf->canvas1Addr = + index2canvas(buffer_index); + vf->type_original = vf->type; + + debug_print(hw, PRINT_FLAG_VFRAME_DETAIL, + "buffer_index %d, canvas addr %x\n", + buffer_index, vf->canvas0Addr); + vf->pts = (pts_valid)?pts:0; + //vf->pts_us64 = (pts_valid) ? pts_us64 : 0; + hw->vfbuf_use[buffer_index]++; + vf->mem_handle = + decoder_bmmu_box_get_mem_handle( + hw->mm_blk_handle, + buffer_index); + + if (hw->m_ins_flag && vdec_frame_based(hw_to_vdec(hw))) + set_vframe_pts(hw, decode_pic_count, vf); + + if (vdec_stream_based(vdec) && (!vdec->vbuf.use_ptsserv)) { + vf->pts_us64 = + (((u64)vf->duration << 32) & 0xffffffff00000000) | offset; + vf->pts = 0; + } + + debug_print(hw, PRINT_FLAG_PTS, + "interlace1 vf->pts = %d, vf->pts_us64 = %lld, pts_valid = %d\n", vf->pts, vf->pts_us64, pts_valid); + vdec_vframe_ready(vdec, vf); + kfifo_put(&hw->display_q, (const struct vframe_s *)vf); + ATRACE_COUNTER(hw->pts_name, vf->timestamp); + avs_vf_notify_receiver(hw, PROVIDER_NAME, + VFRAME_EVENT_PROVIDER_VFRAME_READY, + NULL); + + if (kfifo_get(&hw->newframe_q, &vf) == 0) { + pr_info("fatal error, no available buffer slot."); + return IRQ_HANDLED; + } + set_frame_info(hw, vf, &dur); + vf->bufWidth = 1920; + if (force_interlaced_frame) + vf->pts = 0; + else + vf->pts = hw->next_pts; + + if (vf->pts == 0) { + vf->pts_us64 = 0; + } + + if ((repeat_count > 1) && hw->avi_flag) { + /* vf->duration = hw->vavs_amstream_dec_info.rate * + * repeat_count >> 1; + */ + vf->duration = dur * repeat_count >> 1; + if (hw->next_pts != 0) { + hw->next_pts += + ((vf->duration) - + ((vf->duration) >> 4)); + } + } else { + /* vf->duration = hw->vavs_amstream_dec_info.rate + * >> 1; + */ + vf->duration = dur >> 1; + hw->next_pts = 0; + } + vf->signal_type = 0; + vf->index = buffer_index; + vf->duration_pulldown = 0; + if (force_interlaced_frame) { + vf->type = VIDTYPE_INTERLACE_BOTTOM; + } else { + vf->type = + (reg & TOP_FIELD_FIRST_FLAG) ? + VIDTYPE_INTERLACE_BOTTOM : + VIDTYPE_INTERLACE_TOP; + } +#ifdef NV21 + vf->type |= VIDTYPE_VIU_NV21; +#endif + if (hw->m_ins_flag) { + vf->canvas0Addr = vf->canvas1Addr = -1; + vf->plane_num = 2; + + vf->canvas0_config[0] = hw->canvas_config[buffer_index][0]; + vf->canvas0_config[1] = hw->canvas_config[buffer_index][1]; + + vf->canvas1_config[0] = hw->canvas_config[buffer_index][0]; + vf->canvas1_config[1] = hw->canvas_config[buffer_index][1]; + } else + vf->canvas0Addr = vf->canvas1Addr = + index2canvas(buffer_index); + vf->type_original = vf->type; + vf->pts_us64 = 0; + hw->vfbuf_use[buffer_index]++; + vf->mem_handle = + decoder_bmmu_box_get_mem_handle( + hw->mm_blk_handle, + buffer_index); + + if (hw->m_ins_flag && vdec_frame_based(hw_to_vdec(hw))) + set_vframe_pts(hw, decode_pic_count, vf); + + if (vdec_stream_based(vdec) && (!vdec->vbuf.use_ptsserv)) { + vf->pts_us64 = (u64)-1; + vf->pts = 0; + } + debug_print(hw, PRINT_FLAG_PTS, + "interlace2 vf->pts = %d, vf->pts_us64 = %lld, pts_valid = %d\n", vf->pts, vf->pts_us64, pts_valid); + vdec_vframe_ready(vdec, vf); + kfifo_put(&hw->display_q, (const struct vframe_s *)vf); + ATRACE_COUNTER(hw->pts_name, vf->timestamp); + avs_vf_notify_receiver(hw, PROVIDER_NAME, + VFRAME_EVENT_PROVIDER_VFRAME_READY, + NULL); + hw->total_frame++; + } else { /* progressive */ + hw->throw_pb_flag = 0; + + debug_print(hw, PRINT_FLAG_VFRAME_DETAIL, + "progressive picture type %d\n", + picture_type); + if (kfifo_get(&hw->newframe_q, &vf) == 0) { + pr_info + ("fatal error, no available buffer slot."); + return IRQ_HANDLED; + } + set_frame_info(hw, vf, &dur); + vf->bufWidth = 1920; + hw->pic_type = 1; + + if ((picture_type == I_PICTURE) && pts_valid) { + vf->pts = pts; + if ((repeat_count > 1) && hw->avi_flag) { + /* hw->next_pts = pts + + * (hw->vavs_amstream_dec_info.rate * + * repeat_count)*15/16; + */ + hw->next_pts = + pts + + (dur * repeat_count) * 15 / 16; + } else + hw->next_pts = 0; + } else { + vf->pts = hw->next_pts; + if (vf->pts == 0) { + vf->pts_us64 = 0; + } + if ((repeat_count > 1) && hw->avi_flag) { + /* vf->duration = + * hw->vavs_amstream_dec_info.rate * + * repeat_count; + */ + vf->duration = dur * repeat_count; + if (hw->next_pts != 0) { + hw->next_pts += + ((vf->duration) - + ((vf->duration) >> 4)); + } + } else { + /* vf->duration = + * hw->vavs_amstream_dec_info.rate; + */ + vf->duration = dur; + hw->next_pts = 0; + } + } + vf->signal_type = 0; + vf->index = buffer_index; + vf->duration_pulldown = 0; + vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD; +#ifdef NV21 + vf->type |= VIDTYPE_VIU_NV21; +#endif + if (hw->m_ins_flag) { + vf->canvas0Addr = vf->canvas1Addr = -1; + vf->plane_num = 2; + + vf->canvas0_config[0] = hw->canvas_config[buffer_index][0]; + vf->canvas0_config[1] = hw->canvas_config[buffer_index][1]; + + vf->canvas1_config[0] = hw->canvas_config[buffer_index][0]; + vf->canvas1_config[1] = hw->canvas_config[buffer_index][1]; + } else + vf->canvas0Addr = vf->canvas1Addr = + index2canvas(buffer_index); + vf->type_original = vf->type; + + vf->pts = (pts_valid)?pts:0; + //vf->pts_us64 = (pts_valid) ? pts_us64 : 0; + debug_print(hw, PRINT_FLAG_VFRAME_DETAIL, + "buffer_index %d, canvas addr %x\n", + buffer_index, vf->canvas0Addr); + debug_print(hw, PRINT_FLAG_PTS, + "progressive vf->pts = %d, vf->pts_us64 = %lld, pts_valid = %d\n", vf->pts, vf->pts_us64, pts_valid); + hw->vfbuf_use[buffer_index]++; + vf->mem_handle = + decoder_bmmu_box_get_mem_handle( + hw->mm_blk_handle, + buffer_index); + + if (hw->m_ins_flag && vdec_frame_based(hw_to_vdec(hw))) + set_vframe_pts(hw, decode_pic_count, vf); + + if (vdec_stream_based(vdec) && (!vdec->vbuf.use_ptsserv)) { + vf->pts_us64 = + (((u64)vf->duration << 32) & 0xffffffff00000000) | offset; + vf->pts = 0; + } + decoder_do_frame_check(hw_to_vdec(hw), vf); + vdec_vframe_ready(vdec, vf); + kfifo_put(&hw->display_q, (const struct vframe_s *)vf); + ATRACE_COUNTER(hw->pts_name, vf->timestamp); + ATRACE_COUNTER(hw->new_q_name, kfifo_len(&hw->newframe_q)); + ATRACE_COUNTER(hw->disp_q_name, kfifo_len(&hw->display_q)); + avs_vf_notify_receiver(hw, PROVIDER_NAME, + VFRAME_EVENT_PROVIDER_VFRAME_READY, + NULL); + hw->total_frame++; + } + + /*count info*/ + vdec_count_info(hw->gvs, 0, offset); + if (offset) { + if (picture_type == I_PICTURE) { + hw->gvs->i_decoded_frames++; + } else if (picture_type == P_PICTURE) { + hw->gvs->p_decoded_frames++; + } else if (picture_type == B_PICTURE) { + hw->gvs->b_decoded_frames++; + } + } + avs_update_gvs(hw); + vdec_fill_vdec_frame(hw_to_vdec(hw), NULL, hw->gvs, vf, 0); + + /* pr_info("PicType = %d, PTS = 0x%x\n", + * picture_type, vf->pts); + */ + WRITE_VREG(AVS_BUFFEROUT, 0); + } + //WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); + + + if (hw->m_ins_flag) { + u32 status_reg = READ_VREG(DECODE_STATUS); + u32 decode_status = status_reg & 0xff; + if (hw->dec_result == DEC_RESULT_DONE || + hw->dec_result == DEC_RESULT_AGAIN) { + debug_print(hw, PRINT_FLAG_DECODING, + "%s !!! READ_VREG(DECODE_STATUS) = 0x%x, decode_status 0x%x, buf_status 0x%x, dec_result = 0x%x, decode_pic_count = %d bit_cnt=0x%x\n", + __func__, status_reg, decode_status, + hw->buf_status, + hw->dec_result, hw->decode_pic_count, + READ_VREG(VIFF_BIT_CNT)); + return IRQ_HANDLED; + } else if (decode_status == DECODE_STATUS_PIC_DONE || + decode_status == DECODE_STATUS_SKIP_PIC_DONE) { + hw->buf_status = (status_reg >> 16) & 0xffff; + if (decode_status == DECODE_STATUS_SKIP_PIC_DONE) { + hw->decode_status_skip_pic_done_flag = 1; + hw->decode_decode_cont_start_code = (status_reg >> 8) & 0xff; + } else + hw->decode_status_skip_pic_done_flag = 0; + hw->decode_pic_count++; + if ((hw->decode_pic_count & 0xffff) == 0) { + /*make ucode do not handle it as first picture*/ + hw->decode_pic_count++; + } + reset_process_time(hw); + hw->dec_result = DEC_RESULT_DONE; +#if DEBUG_MULTI_FLAG == 1 + WRITE_VREG(DECODE_STATUS, 0); +#else + amvdec_stop(); +#endif + vavs_save_regs(hw); + debug_print(hw, PRINT_FLAG_DECODING, + "%s %s, READ_VREG(DECODE_STATUS) = 0x%x, decode_status 0x%x, buf_status 0x%x, dec_result = 0x%x, decode_pic_count = %d, bit_cnt=0x%x\n", + __func__, + (decode_status == DECODE_STATUS_PIC_DONE) ? + "DECODE_STATUS_PIC_DONE" : "DECODE_STATUS_SKIP_PIC_DONE", + status_reg, decode_status, + hw->buf_status, + hw->dec_result, hw->decode_pic_count, + READ_VREG(VIFF_BIT_CNT)); + vdec_schedule_work(&hw->work); + return IRQ_HANDLED; + } else if (decode_status == DECODE_STATUS_DECODE_BUF_EMPTY || + decode_status == DECODE_STATUS_SEARCH_BUF_EMPTY) { + hw->buf_status = (status_reg >> 16) & 0xffff; + reset_process_time(hw); +#if DEBUG_MULTI_FLAG == 1 + WRITE_VREG(DECODE_STATUS, 0); +#else + amvdec_stop(); +#endif + if (vdec_frame_based(hw_to_vdec(hw))) { + hw->dec_result = DEC_RESULT_DONE; + //if (hw->decode_pic_count == 0) { + hw->decode_pic_count++; + //} + if ((hw->decode_pic_count & 0xffff) == 0) { + /*make ucode do not handle it as first picture*/ + hw->decode_pic_count++; + } + vavs_save_regs(hw); + } else + hw->dec_result = DEC_RESULT_AGAIN; + + debug_print(hw, PRINT_FLAG_DECODING, + "%s BUF_EMPTY, READ_VREG(DECODE_STATUS) = 0x%x, decode_status 0x%x, buf_status 0x%x, scratch_8 (AVS_BUFFERIN) 0x%x, dec_result = 0x%x, decode_pic_count = %d, bit_cnt=0x%x, hw->decode_status_skip_pic_done_flag = %d, hw->decode_decode_cont_start_code = 0x%x\n", + __func__, status_reg, decode_status, + hw->buf_status, + hw->reg_scratch_8, + hw->dec_result, hw->decode_pic_count, + READ_VREG(VIFF_BIT_CNT), hw->decode_status_skip_pic_done_flag, hw->decode_decode_cont_start_code); + vdec_schedule_work(&hw->work); + return IRQ_HANDLED; + } + } + + +#ifdef HANDLE_AVS_IRQ + return IRQ_HANDLED; +#else + return; +#endif +} + +static irqreturn_t vmavs_isr(struct vdec_s *vdec, int irq) +{ + + WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); + + return IRQ_WAKE_THREAD; + //return vavs_isr(0, hw); + +} + +static void vmavs_dump_state(struct vdec_s *vdec) +{ + struct vdec_avs_hw_s *hw = + (struct vdec_avs_hw_s *)vdec->private; + int i; + debug_print(hw, 0, + "====== %s\n", __func__); + + debug_print(hw, 0, + "width/height (%d/%d), dur %d\n", + hw->frame_width, + hw->frame_height, + hw->frame_dur + ); + + debug_print(hw, 0, + "is_framebase(%d), decode_status 0x%x, buf_status 0x%x, buf_recycle_status 0x%x, throw %d, eos %d, state 0x%x, dec_result 0x%x dec_frm %d disp_frm %d run %d not_run_ready %d input_empty %d\n", + vdec_frame_based(vdec), + READ_VREG(DECODE_STATUS) & 0xff, + hw->buf_status, + hw->buf_recycle_status, + hw->throw_pb_flag, + hw->eos, + hw->stat, + hw->dec_result, + hw->decode_pic_count, + hw->display_frame_count, + hw->run_count, + hw->not_run_ready, + hw->input_empty + ); + + if (vf_get_receiver(vdec->vf_provider_name)) { + enum receviver_start_e state = + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_QUREY_STATE, + NULL); + debug_print(hw, 0, + "\nreceiver(%s) state %d\n", + vdec->vf_provider_name, + state); + } + + debug_print(hw, 0, + "%s, newq(%d/%d), dispq(%d/%d)recycleq(%d/%d) drop %d vf peek %d, prepare/get/put (%d/%d/%d)\n", + __func__, + kfifo_len(&hw->newframe_q), + VF_POOL_SIZE, + kfifo_len(&hw->display_q), + VF_POOL_SIZE, + kfifo_len(&hw->recycle_q), + VF_POOL_SIZE, + hw->drop_frame_count, + hw->peek_num, + hw->prepare_num, + hw->get_num, + hw->put_num + ); + + debug_print(hw, 0, "vfbuf_use:\n"); + for (i = 0; i < hw->vf_buf_num_used; i++) + debug_print(hw, 0, "%d: vf_buf_use %d\n", + i, hw->vfbuf_use[i]); + + debug_print(hw, 0, + "DECODE_STATUS=0x%x\n", + READ_VREG(DECODE_STATUS)); + debug_print(hw, 0, + "MPC_E=0x%x\n", + READ_VREG(MPC_E)); + debug_print(hw, 0, + "DECODE_MODE=0x%x\n", + READ_VREG(DECODE_MODE)); + debug_print(hw, 0, + "wait_buf_status, AV_SCRATCH_5=0x%x\n", + READ_VREG(AV_SCRATCH_5)); + debug_print(hw, 0, + "MBY_MBX=0x%x\n", + READ_VREG(MBY_MBX)); + debug_print(hw, 0, + "VIFF_BIT_CNT=0x%x\n", + READ_VREG(VIFF_BIT_CNT)); + debug_print(hw, 0, + "VLD_MEM_VIFIFO_LEVEL=0x%x\n", + READ_VREG(VLD_MEM_VIFIFO_LEVEL)); + debug_print(hw, 0, + "VLD_MEM_VIFIFO_WP=0x%x\n", + READ_VREG(VLD_MEM_VIFIFO_WP)); + debug_print(hw, 0, + "VLD_MEM_VIFIFO_RP=0x%x\n", + READ_VREG(VLD_MEM_VIFIFO_RP)); + debug_print(hw, 0, + "PARSER_VIDEO_RP=0x%x\n", + STBUF_READ(&vdec->vbuf, get_rp)); + debug_print(hw, 0, + "PARSER_VIDEO_WP=0x%x\n", + STBUF_READ(&vdec->vbuf, get_wp)); + + if (vdec_frame_based(vdec) && + (debug & PRINT_FRAMEBASE_DATA) + ) { + int jj; + if (hw->chunk && hw->chunk->block && + hw->chunk->size > 0) { + u8 *data = NULL; + + if (!hw->chunk->block->is_mapped) + data = codec_mm_vmap(hw->chunk->block->start + + hw->chunk->offset, hw->chunk->size); + else + data = ((u8 *)hw->chunk->block->start_virt) + + hw->chunk->offset; + + debug_print(hw, 0, + "frame data size 0x%x\n", + hw->chunk->size); + for (jj = 0; jj < hw->chunk->size; jj++) { + if ((jj & 0xf) == 0) + debug_print(hw, + PRINT_FRAMEBASE_DATA, + "%06x:", jj); + debug_print_cont(hw, + PRINT_FRAMEBASE_DATA, + "%02x ", data[jj]); + if (((jj + 1) & 0xf) == 0) + debug_print_cont(hw, + PRINT_FRAMEBASE_DATA, + "\n"); + } + + if (!hw->chunk->block->is_mapped) + codec_mm_unmap_phyaddr(data); + } + } + +} + + int ammvdec_avs_probe(struct platform_device *pdev) +{ + struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data; + struct vdec_avs_hw_s *hw = NULL; + int r = 0; + + if (vdec_get_debug_flags() & 0x8) + return amvdec_avs_probe(pdev); + + pr_info("ammvdec_avs probe start.\n"); + + if (pdata == NULL) { + pr_info("ammvdec_avs platform data undefined.\n"); + return -EFAULT; + } + + hw = (struct vdec_avs_hw_s *)vzalloc(sizeof(struct vdec_avs_hw_s)); + if (hw == NULL) { + pr_info("\nammvdec_avs decoder driver alloc failed\n"); + return -ENOMEM; + } + /*atomic_set(&hw->error_handler_run, 0);*/ + hw->m_ins_flag = 1; + + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXM || disable_longcabac_trans) + firmware_sel = 1; + + if (firmware_sel == 1) { +#ifndef USE_DYNAMIC_BUF_NUM + vf_buf_num = 4; +#endif + canvas_base = 0; + canvas_num = 3; + } else { + pr_info("Error, do not support longcabac work around!!!"); + r = -ENOMEM; + goto error1; + } + + if (pdata->sys_info) + hw->vavs_amstream_dec_info = *pdata->sys_info; + + hw->is_reset = 0; + pdata->user_data_read = NULL; + pdata->reset_userdata_fifo = NULL; + + pdata->private = hw; + pdata->dec_status = vavs_dec_status; + pdata->set_isreset = vavs_set_isreset; + pdata->run_ready = run_ready; + pdata->run = run; + pdata->reset = reset; + pdata->irq_handler = vmavs_isr; + pdata->threaded_irq_handler = vmavs_isr_thread_fn; + pdata->dump_state = vmavs_dump_state; + + snprintf(hw->vdec_name, sizeof(hw->vdec_name), + "avs-%d", pdev->id); + snprintf(hw->pts_name, sizeof(hw->pts_name), + "%s-timestamp", hw->vdec_name); + snprintf(hw->new_q_name, sizeof(hw->new_q_name), + "%s-newframe_q", hw->vdec_name); + snprintf(hw->disp_q_name, sizeof(hw->disp_q_name), + "%s-dispframe_q", hw->vdec_name); + + vavs_vdec_info_init(hw); + +#ifdef ENABLE_USER_DATA + if (NULL == hw->user_data_buffer) { + hw->user_data_buffer = + dma_alloc_coherent(amports_get_dma_device(), + USER_DATA_SIZE, + &hw->user_data_buffer_phys, GFP_KERNEL); + if (!hw->user_data_buffer) { + pr_info("%s: Can not allocate hw->user_data_buffer\n", + __func__); + r = -ENOMEM; + goto error2; + } + pr_debug("hw->user_data_buffer = 0x%p, hw->user_data_buffer_phys = 0x%x\n", + hw->user_data_buffer, (u32)hw->user_data_buffer_phys); + } +#endif + /*hw->lmem_addr = kmalloc(LMEM_BUF_SIZE, GFP_KERNEL); + if (hw->lmem_addr == NULL) { + pr_err("%s: failed to alloc lmem buffer\n", __func__); + return -1; + } + hw->lmem_phy_addr = dma_map_single(amports_get_dma_device(), + hw->lmem_addr, LMEM_BUF_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(amports_get_dma_device(), + hw->lmem_phy_addr)) { + pr_err("%s: failed to map lmem buffer\n", __func__); + kfree(hw->lmem_addr); + hw->lmem_addr = NULL; + return -1; + }*/ + /*INIT_WORK(&hw->set_clk_work, avs_set_clk);*/ + hw->lmem_addr = (dma_addr_t)dma_alloc_coherent(amports_get_dma_device(), + LMEM_BUF_SIZE, (dma_addr_t *)&hw->lmem_phy_addr, GFP_KERNEL); + if (hw->lmem_addr == 0) { + pr_err("%s: failed to alloc lmem buffer\n", __func__); + r = -1; + goto error3; + } + + if (vavs_init(hw) < 0) { + pr_info("amvdec_avs init failed.\n"); + r = -ENODEV; + goto error4; + } + + /*INIT_WORK(&hw->fatal_error_wd_work, vavs_fatal_error_handler); + atomic_set(&hw->error_handler_run, 0);*/ +#if 0 +#ifdef ENABLE_USER_DATA + INIT_WORK(&hw->userdata_push_work, userdata_push_do_work); +#endif +#endif + INIT_WORK(&hw->notify_work, vavs_notify_work); + + if (pdata->use_vfm_path) { + snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE, + VFM_DEC_PROVIDER_NAME); + hw->frameinfo_enable = 1; + } + else + snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE, + MULTI_INSTANCE_PROVIDER_NAME ".%02x", pdev->id & 0xff); + if (pdata->parallel_dec == 1) { + int i; + for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) + hw->canvas_spec[i] = 0xffffff; + } + vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name, + &vavs_vf_provider, hw); + + platform_set_drvdata(pdev, pdata); + + hw->platform_dev = pdev; + + vdec_set_prepare_level(pdata, start_decode_buf_level); + + vdec_set_vframe_comm(pdata, DRIVER_NAME); + + if (pdata->parallel_dec == 1) + vdec_core_request(pdata, CORE_MASK_VDEC_1); + else { + vdec_core_request(pdata, CORE_MASK_VDEC_1 | CORE_MASK_HEVC + | CORE_MASK_COMBINE); + } + + /*INIT_WORK(&hw->userdata_push_work, userdata_push_do_work);*/ + + return 0; + +error4: + dma_free_coherent(amports_get_dma_device(), + LMEM_BUF_SIZE, (void *)hw->lmem_addr, + hw->lmem_phy_addr); +error3: + dma_free_coherent( + amports_get_dma_device(), + USER_DATA_SIZE, + hw->user_data_buffer, + hw->user_data_buffer_phys); +error2: + kfree(hw->gvs); + hw->gvs = NULL; + pdata->dec_status = NULL; +error1: + vfree(hw); + return r; +} + + int ammvdec_avs_remove(struct platform_device *pdev) +{ + + if (vdec_get_debug_flags() & 0x8) + return amvdec_avs_remove(pdev); + else { + struct vdec_avs_hw_s *hw = + (struct vdec_avs_hw_s *) + (((struct vdec_s *)(platform_get_drvdata(pdev)))->private); + struct vdec_s *vdec = hw_to_vdec(hw); + int i; + + if (hw->stat & STAT_VDEC_RUN) { + amvdec_stop(); + hw->stat &= ~STAT_VDEC_RUN; + } + + if (hw->stat & STAT_ISR_REG) { + vdec_free_irq(VDEC_IRQ_1, (void *)hw); + hw->stat &= ~STAT_ISR_REG; + } + + if (hw->stat & STAT_TIMER_ARM) { + del_timer_sync(&hw->check_timer); + hw->stat &= ~STAT_TIMER_ARM; + } + + cancel_work_sync(&hw->work); + cancel_work_sync(&hw->notify_work); + + if (hw->mm_blk_handle) { + decoder_bmmu_box_free(hw->mm_blk_handle); + hw->mm_blk_handle = NULL; + } + if (vdec->parallel_dec == 1) + vdec_core_release(hw_to_vdec(hw), CORE_MASK_VDEC_1); + else + vdec_core_release(hw_to_vdec(hw), CORE_MASK_VDEC_1 | CORE_MASK_HEVC); + vdec_set_status(hw_to_vdec(hw), VDEC_STATUS_DISCONNECTED); + + if (vdec->parallel_dec == 1) { + for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) { + vdec->free_canvas_ex(canvas_y(hw->canvas_spec[i]), vdec->id); + vdec->free_canvas_ex(canvas_u(hw->canvas_spec[i]), vdec->id); + } + } + #ifdef ENABLE_USER_DATA + if (hw->user_data_buffer != NULL) { + dma_free_coherent( + amports_get_dma_device(), + USER_DATA_SIZE, + hw->user_data_buffer, + hw->user_data_buffer_phys); + hw->user_data_buffer = NULL; + hw->user_data_buffer_phys = 0; + } + #endif + /*if (hw->lmem_addr) { + dma_unmap_single(amports_get_dma_device(), + hw->lmem_phy_addr, LMEM_BUF_SIZE, DMA_FROM_DEVICE); + kfree(hw->lmem_addr); + hw->lmem_addr = NULL; + }*/ + if (hw->lmem_addr) { + dma_free_coherent(amports_get_dma_device(), + LMEM_BUF_SIZE, (void *)hw->lmem_addr, + hw->lmem_phy_addr); + hw->lmem_addr = 0; + } + + if (hw->fw) { + vfree(hw->fw); + hw->fw = NULL; + } + + pr_info("ammvdec_avs removed.\n"); + if (hw->gvs) { + kfree(hw->gvs); + hw->gvs = NULL; + } + + vfree(hw); + return 0; + } +} + + +#ifdef DEBUG_MULTI_WITH_AUTOMODE +struct stream_buf_s *get_vbuf(void); +s32 esparser_init(struct stream_buf_s *buf, struct vdec_s *vdec); + + +static s32 vavs_init2(struct vdec_avs_hw_s *hw) +{ + int size = -1; + struct firmware_s *fw; + u32 fw_size = 0x1000 * 16; + + fw = vmalloc(sizeof(struct firmware_s) + fw_size); + if (IS_ERR_OR_NULL(fw)) + return -ENOMEM; + + pr_info("vavs_init\n"); + + amvdec_enable(); + + + vavs_local_init(hw); + + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXM) + size = get_firmware_data(VIDEO_DEC_AVS_MULTI, fw->data); + else { + if (firmware_sel == 1) + size = get_firmware_data(VIDEO_DEC_AVS_NOCABAC, fw->data); +#ifdef AVSP_LONG_CABAC + else { + init_avsp_long_cabac_buf(); + size = get_firmware_data(VIDEO_DEC_AVS_MULTI, fw->data); + } +#endif + } + + if (size < 0) { + amvdec_disable(); + pr_err("get firmware fail."); + /*vfree(buf);*/ + return -1; + } + + fw->len = size; + hw->fw = fw; + if (hw->m_ins_flag) { + init_timer(&hw->check_timer); + hw->check_timer.data = (ulong) hw; + hw->check_timer.function = check_timer_func; + hw->check_timer.expires = jiffies + CHECK_INTERVAL; + + + //add_timer(&hw->check_timer); + hw->stat |= STAT_TIMER_ARM; + + INIT_WORK(&hw->work, vavs_work); + + hw->fw = fw; + } + return 0; +} + +unsigned int debug_flag2; +static int vavs_prot_init2(struct vdec_avs_hw_s *hw, unsigned char post_flag) +{ + int r = 0; + /* + * 2: assist + * 3: vld_reset + * 4: vld_part_reset + * 5: vfifo reset + * 6: iqidct + * 7: mc + * 8: dblk + * 9: pic_dc + * 10: psc + * 11: mcpu + * 12: ccpu + * 13: ddr + * 14: afifo + */ + unsigned char run_flag; +#ifdef OOO + WRITE_VREG(DOS_SW_RESET0, (1 << 7) | (1 << 6) /*| (1 << 4)*/); + WRITE_VREG(DOS_SW_RESET0, 0); + + READ_VREG(DOS_SW_RESET0); + + WRITE_VREG(DOS_SW_RESET0, (1 << 7) | (1 << 6) /*| (1 << 4)*/); + WRITE_VREG(DOS_SW_RESET0, 0); + + WRITE_VREG(DOS_SW_RESET0, (1 << 9) | (1 << 8)); + WRITE_VREG(DOS_SW_RESET0, 0); +#endif + /***************** reset vld **********************************/ +#ifdef OOO + WRITE_VREG(POWER_CTL_VLD, 0x10); + WRITE_VREG_BITS(VLD_MEM_VIFIFO_CONTROL, 2, MEM_FIFO_CNT_BIT, 2); + WRITE_VREG_BITS(VLD_MEM_VIFIFO_CONTROL, 8, MEM_LEVEL_CNT_BIT, 6); +#endif + if (start_decoding_delay & 0x80000) + msleep(start_decoding_delay&0xffff); + +if (debug_flag2 & 0x1) + run_flag = post_flag; +else + run_flag = !post_flag; +if (run_flag) { + if (hw->m_ins_flag) { + int i; + if (hw->decode_pic_count == 0) { + r = vavs_canvas_init(hw); +#ifndef USE_DYNAMIC_BUF_NUM + for (i = 0; i < 4; i++) { + WRITE_VREG(AV_SCRATCH_0 + i, + hw->canvas_spec[i] + ); + } +#else + for (i = 0; i < hw->vf_buf_num_used; i += 2) { + WRITE_VREG(buf_spec_reg[i >> 1], + (hw->canvas_spec[i] & 0xffff) | + ((hw->canvas_spec[i + 1] & 0xffff) + << 16) + ); + } +#endif + } else + vavs_restore_regs(hw); + + for (i = 0; i < hw->vf_buf_num_used; i++) { + config_cav_lut_ex(canvas_y(hw->canvas_spec[i]), + hw->canvas_config[i][0].phy_addr, + hw->canvas_config[i][0].width, + hw->canvas_config[i][0].height, + CANVAS_ADDR_NOWRAP, + hw->canvas_config[i][0].block_mode, + 0, VDEC_1); + + config_cav_lut_ex(canvas_u(hw->canvas_spec[i]), + hw->canvas_config[i][1].phy_addr, + hw->canvas_config[i][1].width, + hw->canvas_config[i][1].height, + CANVAS_ADDR_NOWRAP, + hw->canvas_config[i][1].block_mode, + 0, VDEC_1); + } + } +} + +if (debug_flag2 & 0x2) + run_flag = post_flag; +else + run_flag = !post_flag; +if (run_flag) { + + /* notify ucode the buffer offset */ + if (hw->decode_pic_count == 0) + WRITE_VREG(AV_SCRATCH_F, hw->buf_offset); +#ifdef OOO + /* disable PSCALE for hardware sharing */ + WRITE_VREG(PSCALE_CTRL, 0); +#endif + } + if (start_decoding_delay & 0x40000) + msleep(start_decoding_delay&0xffff); + + if (debug_flag2 & 0x4) + run_flag = post_flag; + else + run_flag = !post_flag; + if (run_flag) { + if (hw->decode_pic_count == 0) { +#ifndef USE_DYNAMIC_BUF_NUM + WRITE_VREG(AVS_SOS_COUNT, 0); +#endif + WRITE_VREG(AVS_BUFFERIN, 0); + WRITE_VREG(AVS_BUFFEROUT, 0); + } + if (error_recovery_mode) + WRITE_VREG(AVS_ERROR_RECOVERY_MODE, 0); + else + WRITE_VREG(AVS_ERROR_RECOVERY_MODE, 1); + /* clear mailbox interrupt */ + WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); + + /* enable mailbox interrupt */ + WRITE_VREG(ASSIST_MBOX1_MASK, 1); +} + +if (debug_flag2 & 0x8) + run_flag = post_flag; +else + run_flag = !post_flag; +if (run_flag) { + +#ifndef USE_DYNAMIC_BUF_NUM /* def DEBUG_UCODE */ + if (hw->decode_pic_count == 0) + WRITE_VREG(AV_SCRATCH_D, 0); +#endif + if (start_decoding_delay & 0x10000) + msleep(start_decoding_delay&0xffff); +#ifdef NV21 + SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17); +#endif + /* V4L2_PIX_FMT_NV21 V4L2_PIX_FMT_NV21M */ + SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 16); + + if (start_decoding_delay & 0x20000) + msleep(start_decoding_delay&0xffff); + + +#ifdef PIC_DC_NEED_CLEAR + CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 31); +#endif +} +if (debug_flag2 & 0x10) + run_flag = post_flag; +else + run_flag = !post_flag; +if (run_flag) { +#ifdef ENABLE_USER_DATA + if (firmware_sel == 0) { + pr_info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! firmware_sel is 0\n"); + WRITE_VREG(AV_SCRATCH_N, (u32)(hw->user_data_buffer_phys - hw->buf_offset)); + pr_debug("AV_SCRATCH_N = 0x%x\n", READ_VREG(AV_SCRATCH_N)); + } +#endif +} + +if (debug_flag2 & 0x20) + run_flag = post_flag; +else + run_flag = !post_flag; +if (run_flag) { + if (hw->m_ins_flag) { + if (vdec_frame_based(hw_to_vdec(hw))) + WRITE_VREG(DECODE_MODE, DECODE_MODE_MULTI_FRAMEBASE); + else + WRITE_VREG(DECODE_MODE, DECODE_MODE_MULTI_STREAMBASE); + WRITE_VREG(DECODE_LMEM_BUF_ADR, (u32)hw->lmem_phy_addr); + } else + WRITE_VREG(DECODE_MODE, DECODE_MODE_SINGLE); + WRITE_VREG(DECODE_STOP_POS, udebug_flag); + hw->old_udebug_flag = udebug_flag; +} + return r; +} + +static void init_hw(struct vdec_s *vdec) +{ + struct vdec_avs_hw_s *hw = + (struct vdec_avs_hw_s *)vdec->private; + int ret; + pr_info("%s, %d\n", __func__, __LINE__); + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXM) + ret = amvdec_loadmc_ex(VFORMAT_AVS, NULL, hw->fw->data); + else if (firmware_sel == 1) + ret = amvdec_loadmc_ex(VFORMAT_AVS, "avs_no_cabac", hw->fw->data); + else + ret = amvdec_loadmc_ex(VFORMAT_AVS, NULL, hw->fw->data); + + if (ret < 0) { + amvdec_disable(); + /*vfree(buf);*/ + pr_err("AVS: the %s fw loading failed, err: %x\n", + tee_enabled() ? "TEE" : "local", ret); + } + pr_info("%s, %d\n", __func__, __LINE__); + + /*vfree(buf);*/ + + hw->stat |= STAT_MC_LOAD; + + /* enable AMRISC side protocol */ + ret = vavs_prot_init2(hw, 0); + if (ret < 0) + return; + pr_info("%s, %d\n", __func__, __LINE__); + +} + + +static unsigned long run_ready2(struct vdec_s *vdec, unsigned long mask) +{ + return 1; +} + +static void run2(struct vdec_s *vdec, unsigned long mask, +void (*callback)(struct vdec_s *, void *), + void *arg) +{ + struct vdec_avs_hw_s *hw = + (struct vdec_avs_hw_s *)vdec->private; + pr_info("%s, %d\n", __func__, __LINE__); + + vavs_prot_init2(hw, 1); + + vdec_source_changed(VFORMAT_AVS, + 1920, 1080, 30); + + amvdec_start(); + + hw->stat |= STAT_VDEC_RUN; + pr_info("%s %d\n", __func__, __LINE__); + +} + +static int ammvdec_avs_probe2(struct platform_device *pdev) +{ + struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data; + struct vdec_avs_hw_s *hw = NULL; + + pr_info("ammvdec_avs probe start.\n"); + + if (pdata == NULL) { + pr_info("ammvdec_avs platform data undefined.\n"); + return -EFAULT; + } + pr_info("%s %d\n", __func__, __LINE__); + + hw = (struct vdec_avs_hw_s *)vzalloc(sizeof(struct vdec_avs_hw_s)); + if (hw == NULL) { + pr_info("\nammvdec_avs decoder driver alloc failed\n"); + return -ENOMEM; + } + pr_info("%s %d\n", __func__, __LINE__); + /*atomic_set(&hw->error_handler_run, 0);*/ + hw->m_ins_flag = 1; + pr_info("%s %d\n", __func__, __LINE__); + + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXM || disable_longcabac_trans) + firmware_sel = 1; + pr_info("%s %d\n", __func__, __LINE__); + + if (firmware_sel == 1) { +#ifndef USE_DYNAMIC_BUF_NUM + vf_buf_num = 4; +#endif + canvas_base = 0; + canvas_num = 3; + } else { + pr_info("Error, do not support longcabac work around!!!"); + return -ENOMEM; + } + pr_info("%s %d\n", __func__, __LINE__); + + if (pdata->sys_info) + hw->vavs_amstream_dec_info = *pdata->sys_info; + pr_info("%s %d\n", __func__, __LINE__); + + hw->is_reset = 0; + pdata->user_data_read = NULL; + pdata->reset_userdata_fifo = NULL; + + pr_info("%s %d\n", __func__, __LINE__); + + pdata->private = hw; + pdata->dec_status = vavs_dec_status; + pdata->set_isreset = vavs_set_isreset; + pdata->run_ready = run_ready2; + pdata->run = run2; + pdata->reset = reset; + pdata->irq_handler = vmavs_isr; + pdata->threaded_irq_handler = vmavs_isr_thread_fn; + pdata->dump_state = vmavs_dump_state; + + pr_info("%s %d\n", __func__, __LINE__); + + vavs_vdec_info_init(hw); + + pr_info("%s %d\n", __func__, __LINE__); + +#ifdef ENABLE_USER_DATA + if (NULL == hw->user_data_buffer) { + hw->user_data_buffer = + dma_alloc_coherent(amports_get_dma_device(), + USER_DATA_SIZE, + &hw->user_data_buffer_phys, GFP_KERNEL); + if (!hw->user_data_buffer) { + pr_info("%s: Can not allocate hw->user_data_buffer\n", + __func__); + return -ENOMEM; + } + pr_debug("hw->user_data_buffer = 0x%p, hw->user_data_buffer_phys = 0x%x\n", + hw->user_data_buffer, (u32)hw->user_data_buffer_phys); + } +#endif + hw->lmem_addr = kmalloc(LMEM_BUF_SIZE, GFP_KERNEL); + if (hw->lmem_addr == NULL) { + pr_err("%s: failed to alloc lmem buffer\n", __func__); + return -1; + } + hw->lmem_phy_addr = dma_map_single(amports_get_dma_device(), + hw->lmem_addr, LMEM_BUF_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(amports_get_dma_device(), + hw->lmem_phy_addr)) { + pr_err("%s: failed to map lmem buffer\n", __func__); + kfree(hw->lmem_addr); + hw->lmem_addr = NULL; + return -1; + } + + pr_info("%s %d\n", __func__, __LINE__); + + /*INIT_WORK(&hw->set_clk_work, avs_set_clk);*/ + + pr_info("%s %d\n", __func__, __LINE__); + + if (vavs_init2(hw) < 0) { + pr_info("amvdec_avs init failed.\n"); + kfree(hw->gvs); + hw->gvs = NULL; + pdata->dec_status = NULL; + return -ENODEV; + } + /*vdec = pdata;*/ + pr_info("%s, %d\n", __func__, __LINE__); + +if (hw->m_ins_flag) { + INIT_WORK(&hw->notify_work, vavs_notify_work); +#if 1 + if (pdata->use_vfm_path) { + snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE, + VFM_DEC_PROVIDER_NAME); + hw->frameinfo_enable = 1; + } + else + snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE, + MULTI_INSTANCE_PROVIDER_NAME ".%02x", pdev->id & 0xff); + if (pdata->parallel_dec == 1) { + int i; + for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) + hw->canvas_spec[i] = 0xffffff; + } + vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name, + &vavs_vf_provider, hw); + + platform_set_drvdata(pdev, pdata); + + hw->platform_dev = pdev; + + vdec_set_prepare_level(pdata, start_decode_buf_level); + + if (pdata->parallel_dec == 1) + vdec_core_request(pdata, CORE_MASK_VDEC_1); + else { + vdec_core_request(pdata, CORE_MASK_VDEC_1 | CORE_MASK_HEVC + | CORE_MASK_COMBINE); + } + pr_info("%s, %d\n", __func__, __LINE__); +#endif +}else{ + /*INIT_WORK(&hw->fatal_error_wd_work, vavs_fatal_error_handler); + atomic_set(&hw->error_handler_run, 0);*/ +#ifdef ENABLE_USER_DATA + INIT_WORK(&hw->userdata_push_work, userdata_push_do_work); +#endif + INIT_WORK(&hw->notify_work, vavs_notify_work); +} + + init_hw(pdata); + return 0; +} + +static int ammvdec_avs_remove2(struct platform_device *pdev) +{ + struct vdec_avs_hw_s *hw = ghw; + + cancel_work_sync(&hw->fatal_error_wd_work); + atomic_set(&hw->error_handler_run, 0); +#ifdef ENABLE_USER_DATA + cancel_work_sync(&hw->userdata_push_work); +#endif + cancel_work_sync(&hw->notify_work); + cancel_work_sync(&hw->set_clk_work); + if (hw->stat & STAT_VDEC_RUN) { + amvdec_stop(); + hw->stat &= ~STAT_VDEC_RUN; + } + + if (hw->stat & STAT_ISR_REG) { + vdec_free_irq(VDEC_IRQ_1, (void *)vavs_dec_id); + hw->stat &= ~STAT_ISR_REG; + } + + if (hw->stat & STAT_TIMER_ARM) { + del_timer_sync(&hw->recycle_timer); + hw->stat &= ~STAT_TIMER_ARM; + } +#ifdef AVSP_LONG_CABAC + if (firmware_sel == 0) { + mutex_lock(&vavs_mutex); + cancel_work_sync(&long_cabac_wd_work); + mutex_unlock(&vavs_mutex); + + if (es_write_addr_virt) { +#if 0 + codec_mm_free_for_dma("vavs", es_write_addr_phy); +#else + dma_unmap_single(amports_get_dma_device(), + es_write_addr_phy, + MAX_CODED_FRAME_SIZE, DMA_FROM_DEVICE); + /*kfree(es_write_addr_virt);*/ + es_write_addr_virt = NULL; +#endif + } + +#ifdef BITSTREAM_READ_TMP_NO_CACHE + if (bitstream_read_tmp) { + dma_free_coherent(amports_get_dma_device(), + SVA_STREAM_BUF_SIZE, bitstream_read_tmp, + bitstream_read_tmp_phy); + bitstream_read_tmp = NULL; + } +#else + if (bitstream_read_tmp) { + dma_unmap_single(amports_get_dma_device(), + bitstream_read_tmp_phy, + SVA_STREAM_BUF_SIZE, DMA_FROM_DEVICE); + kfree(bitstream_read_tmp); + bitstream_read_tmp = NULL; + } +#endif + } +#endif + if (hw->stat & STAT_VF_HOOK) { + if (hw->fr_hint_status == VDEC_HINTED && !hw->is_reset) + avs_vf_notify_receiver(hw, PROVIDER_NAME, + VFRAME_EVENT_PROVIDER_FR_END_HINT, NULL); + hw->fr_hint_status = VDEC_NO_NEED_HINT; + vf_unreg_provider(&vavs_vf_prov); + hw->stat &= ~STAT_VF_HOOK; + } + +#ifdef ENABLE_USER_DATA + if (hw->user_data_buffer != NULL) { + dma_free_coherent( + amports_get_dma_device(), + USER_DATA_SIZE, + hw->user_data_buffer, + hw->user_data_buffer_phys); + hw->user_data_buffer = NULL; + hw->user_data_buffer_phys = 0; + } +#endif + + if (hw->fw) { + vfree(hw->fw); + hw->fw = NULL; + } + + amvdec_disable(); + /*vdec_disable_DMC(NULL);*/ + + hw->pic_type = 0; + if (hw->mm_blk_handle) { + decoder_bmmu_box_free(hw->mm_blk_handle); + hw->mm_blk_handle = NULL; + } +#ifdef DEBUG_PTS + pr_debug("pts hit %d, pts missed %d, i hit %d, missed %d\n", hw->pts_hit, + hw->pts_missed, hw->pts_i_hit, hw->pts_i_missed); + pr_debug("total frame %d, hw->avi_flag %d, rate %d\n", hw->total_frame, hw->avi_flag, + hw->vavs_amstream_dec_info.rate); +#endif + kfree(hw->gvs); + hw->gvs = NULL; + vfree(hw); + return 0; +} +#endif + +static struct platform_driver ammvdec_avs_driver = { +#ifdef DEBUG_MULTI_WITH_AUTOMODE + .probe = ammvdec_avs_probe2, + .remove = ammvdec_avs_remove2, +#else + .probe = ammvdec_avs_probe, + .remove = ammvdec_avs_remove, +#endif +#ifdef CONFIG_PM + .suspend = amvdec_suspend, + .resume = amvdec_resume, +#endif + .driver = { + .name = MULTI_DRIVER_NAME, + } +}; + +static struct codec_profile_t ammvdec_avs_profile = { + .name = "AVS-V4L", + .profile = "" +}; + +static struct mconfig mavs_configs[] = { + /*MC_PU32("stat", &stat), + MC_PU32("debug_flag", &debug_flag), + MC_PU32("error_recovery_mode", &error_recovery_mode), + MC_PU32("hw->pic_type", &hw->pic_type), + MC_PU32("radr", &radr), + MC_PU32("vf_buf_num", &vf_buf_num), + MC_PU32("vf_buf_num_used", &vf_buf_num_used), + MC_PU32("canvas_base", &canvas_base), + MC_PU32("firmware_sel", &firmware_sel), + */ +}; +static struct mconfig_node mavs_node; + + +static int __init ammvdec_avs_driver_init_module(void) +{ + pr_debug("ammvdec_avs module init\n"); + + if (platform_driver_register(&ammvdec_avs_driver)) { + pr_err("failed to register ammvdec_avs driver\n"); + return -ENODEV; + } + + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXBB) + ammvdec_avs_profile.profile = "mavs+"; + + vcodec_profile_register(&ammvdec_avs_profile); + INIT_REG_NODE_CONFIGS("media.decoder", &mavs_node, + "mavs-v4l", mavs_configs, CONFIG_FOR_RW); + vcodec_feature_register(VFORMAT_AVS, 1); + return 0; +} + + + +static void __exit ammvdec_avs_driver_remove_module(void) +{ + pr_debug("ammvdec_avs module remove.\n"); + + platform_driver_unregister(&ammvdec_avs_driver); +} + +/****************************************/ +/* +module_param(stat, uint, 0664); +MODULE_PARM_DESC(stat, "\n amvdec_avs stat\n"); +*/ +/****************************************** + *module_param(run_flag, uint, 0664); + *MODULE_PARM_DESC(run_flag, "\n run_flag\n"); + * + *module_param(step_flag, uint, 0664); + *MODULE_PARM_DESC(step_flag, "\n step_flag\n"); + ******************************************* + */ +module_param(step, uint, 0664); +MODULE_PARM_DESC(step, "\n step\n"); + +module_param(debug, uint, 0664); +MODULE_PARM_DESC(debug, "\n debug\n"); + +module_param(debug_mask, uint, 0664); +MODULE_PARM_DESC(debug_mask, "\n debug_mask\n"); + +module_param(error_recovery_mode, uint, 0664); +MODULE_PARM_DESC(error_recovery_mode, "\n error_recovery_mode\n"); + +/****************************************** + *module_param(error_watchdog_threshold, uint, 0664); + *MODULE_PARM_DESC(error_watchdog_threshold, "\n error_watchdog_threshold\n"); + * + *module_param(error_watchdog_buf_threshold, uint, 0664); + *MODULE_PARM_DESC(error_watchdog_buf_threshold, + * "\n error_watchdog_buf_threshold\n"); + ******************************************* + */ +/* +module_param(pic_type, uint, 0444); +MODULE_PARM_DESC(pic_type, "\n amdec_vas picture type\n"); +*/ +module_param(radr, uint, 0664); +MODULE_PARM_DESC(radr, "\nradr\n"); + +module_param(rval, uint, 0664); +MODULE_PARM_DESC(rval, "\nrval\n"); + +module_param(dbg_cmd, uint, 0664); +MODULE_PARM_DESC(dbg_cmd, "\n dbg_cmd\n"); + +module_param(vf_buf_num, uint, 0664); +MODULE_PARM_DESC(vf_buf_num, "\nvf_buf_num\n"); + +/* +module_param(vf_buf_num_used, uint, 0664); +MODULE_PARM_DESC(vf_buf_num_used, "\nvf_buf_num_used\n"); +*/ +module_param(canvas_base, uint, 0664); +MODULE_PARM_DESC(canvas_base, "\ncanvas_base\n"); + + +module_param(firmware_sel, uint, 0664); +MODULE_PARM_DESC(firmware_sel, "\n firmware_sel\n"); + +module_param(disable_longcabac_trans, uint, 0664); +MODULE_PARM_DESC(disable_longcabac_trans, "\n disable_longcabac_trans\n"); + +module_param(dec_control, uint, 0664); +MODULE_PARM_DESC(dec_control, "\n amvdec_vavs decoder control\n"); + +module_param(start_decode_buf_level, int, 0664); +MODULE_PARM_DESC(start_decode_buf_level, + "\n avs start_decode_buf_level\n"); + +module_param(decode_timeout_val, uint, 0664); +MODULE_PARM_DESC(decode_timeout_val, + "\n avs decode_timeout_val\n"); + +module_param(error_handle_policy, uint, 0664); +MODULE_PARM_DESC(error_handle_policy, + "\n avs error_handle_policy\n"); + +module_param(again_threshold, uint, 0664); +MODULE_PARM_DESC(again_threshold, "\n again_threshold\n"); + +module_param(udebug_flag, uint, 0664); +MODULE_PARM_DESC(udebug_flag, "\n amvdec_h265 udebug_flag\n"); + +module_param(udebug_pause_pos, uint, 0664); +MODULE_PARM_DESC(udebug_pause_pos, "\n udebug_pause_pos\n"); + +module_param(udebug_pause_val, uint, 0664); +MODULE_PARM_DESC(udebug_pause_val, "\n udebug_pause_val\n"); + +module_param(udebug_pause_decode_idx, uint, 0664); +MODULE_PARM_DESC(udebug_pause_decode_idx, "\n udebug_pause_decode_idx\n"); + +module_param(udebug_pause_ins_id, uint, 0664); +MODULE_PARM_DESC(udebug_pause_ins_id, "\n udebug_pause_ins_id\n"); + +module_param(start_decoding_delay, uint, 0664); +MODULE_PARM_DESC(start_decoding_delay, "\n start_decoding_delay\n"); + +module_param(pre_decode_buf_level, int, 0664); +MODULE_PARM_DESC(pre_decode_buf_level, + "\n ammvdec_mavs pre_decode_buf_level\n"); + + +#ifdef DEBUG_MULTI_WITH_AUTOMODE +module_param(debug_flag2, uint, 0664); +MODULE_PARM_DESC(debug_flag2, "\n debug_flag2\n"); +#endif +module_param(force_fps, uint, 0664); +MODULE_PARM_DESC(force_fps, "\n force_fps\n"); + +#ifdef DEBUG_MULTI_FRAME_INS +module_param(delay, uint, 0664); +MODULE_PARM_DESC(delay, "\n delay\n"); + +module_param_array(max_run_count, uint, &max_decode_instance_num, 0664); + +#endif + +module_param_array(ins_udebug_flag, uint, &max_decode_instance_num, 0664); + +module_param_array(max_process_time, uint, &max_decode_instance_num, 0664); + +module_param_array(run_count, uint, &max_decode_instance_num, 0664); + +module_param_array(max_get_frame_interval, uint, + &max_decode_instance_num, 0664); + + +module_init(ammvdec_avs_driver_init_module); +module_exit(ammvdec_avs_driver_remove_module); + +MODULE_DESCRIPTION("AMLOGIC AVS Video Decoder Driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Qi Wang <qi.wang@amlogic.com>");
diff --git a/drivers/frame_provider/decoder_v4l/avs_multi/avs_multi.h b/drivers/frame_provider/decoder_v4l/avs_multi/avs_multi.h new file mode 100644 index 0000000..8922b40 --- /dev/null +++ b/drivers/frame_provider/decoder_v4l/avs_multi/avs_multi.h
@@ -0,0 +1,90 @@ +/* +* Copyright (C) 2017 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. +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, write to the Free Software Foundation, Inc., +* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +* Description: +*/ +#ifndef AVS_H_ +#define AVS_H_ + +#ifdef CONFIG_AMLOGIC_AVSP_LONG_CABAC +#define AVSP_LONG_CABAC +#endif +/*#define BITSTREAM_READ_TMP_NO_CACHE*/ + +#ifdef AVSP_LONG_CABAC +#define MAX_CODED_FRAME_SIZE 1500000 /*!< bytes for one frame*/ +#define LOCAL_HEAP_SIZE (1024*1024*10) +/* + *#define MAX_CODED_FRAME_SIZE 240000 + *#define MAX_CODED_FRAME_SIZE 700000 + */ +#define SVA_STREAM_BUF_SIZE 1024 + +extern void *es_write_addr_virt; +extern dma_addr_t es_write_addr_phy; + +extern void *bitstream_read_tmp; +extern dma_addr_t bitstream_read_tmp_phy; +extern void *avsp_heap_adr; + +int avs_get_debug_flag(void); + +int process_long_cabac(void); + +/* bit [6] - skip_mode_flag + * bit [5:4] - picture_type + * bit [3] - picture_structure (0-Field, 1-Frame) + * bit [2] - fixed_picture_qp + * bit [1] - progressive_sequence + * bit [0] - active + */ +#define LONG_CABAC_REQ AV_SCRATCH_K +#define LONG_CABAC_SRC_ADDR AV_SCRATCH_H +#define LONG_CABAC_DES_ADDR AV_SCRATCH_I +/* bit[31:16] - vertical_size + * bit[15:0] - horizontal_size + */ +#define LONG_CABAC_PIC_SIZE AV_SCRATCH_J + +#endif + +/* + *#define PERFORMANCE_DEBUG + *#define DUMP_DEBUG + */ +#define AVS_DEBUG_PRINT 0x01 +#define AVS_DEBUG_OLD_ERROR_HANDLE 0x10 +#define AVS_DEBUG_USE_FULL_SPEED 0x80 +#define AEC_DUMP 0x100 +#define STREAM_INFO_DUMP 0x200 +#define SLICE_INFO_DUMP 0x400 +#define MB_INFO_DUMP 0x800 +#define MB_NUM_DUMP 0x1000 +#define BLOCK_NUM_DUMP 0x2000 +#define COEFF_DUMP 0x4000 +#define ES_DUMP 0x8000 +#define DQUANT_DUMP 0x10000 +#define STREAM_INFO_DUMP_MORE 0x20000 +#define STREAM_INFO_DUMP_MORE2 0x40000 + +extern void *es_write_addr_virt; +extern void *bitstream_read_tmp; +extern dma_addr_t bitstream_read_tmp_phy; +int read_bitstream(unsigned char *Buf, int size); +int u_v(int LenInBits, char *tracestring); + +#endif
diff --git a/drivers/frame_provider/decoder_v4l/h264_multi/Makefile b/drivers/frame_provider/decoder_v4l/h264_multi/Makefile new file mode 100644 index 0000000..48f2c5a --- /dev/null +++ b/drivers/frame_provider/decoder_v4l/h264_multi/Makefile
@@ -0,0 +1,2 @@ +obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_H264_MULTI) += amvdec_mh264_v4l.o +amvdec_mh264_v4l-objs += vmh264.o h264_dpb.o
diff --git a/drivers/frame_provider/decoder_v4l/h264_multi/h264_dpb.c b/drivers/frame_provider/decoder_v4l/h264_multi/h264_dpb.c new file mode 100644 index 0000000..8ab097e --- /dev/null +++ b/drivers/frame_provider/decoder_v4l/h264_multi/h264_dpb.c
@@ -0,0 +1,6036 @@ +/* +* Copyright (C) 2017 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. +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, write to the Free Software Foundation, Inc., +* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +* Description: +*/ +#define DEBUG +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/errno.h> + +#include <linux/amlogic/media/utils/vdec_reg.h> +#include "../../decoder/utils/vdec.h" +#include "../../decoder/utils/amvdec.h" + +#include "h264_dpb.h" + +#define FRAME_NUM_MAX_SIZE 0x10000 + +#undef pr_info +#define pr_info printk +int dpb_print(int index, int debug_flag, const char *fmt, ...) +{ + if (((h264_debug_flag & debug_flag) && + ((1 << index) & h264_debug_mask)) + || (debug_flag == PRINT_FLAG_ERROR)) { + unsigned char *buf = kzalloc(512, GFP_ATOMIC); + int len = 0; + va_list args; + + if (!buf) + return 0; + + va_start(args, fmt); + len = sprintf(buf, "%d: ", index); + vsnprintf(buf + len, 512-len, fmt, args); + pr_debug("%s", buf); + va_end(args); + kfree(buf); + } + return 0; +} + +int dpb_print_cont(int index, int debug_flag, const char *fmt, ...) +{ + if (((h264_debug_flag & debug_flag) && + ((1 << index) & h264_debug_mask)) + || (debug_flag == PRINT_FLAG_ERROR)) { + unsigned char *buf = kzalloc(512, GFP_ATOMIC); + int len = 0; + va_list args; + + if (!buf) + return 0; + + va_start(args, fmt); + vsnprintf(buf + len, 512-len, fmt, args); + pr_info("%s", buf); + va_end(args); + kfree(buf); + } + return 0; +} + +unsigned char dpb_is_debug(int index, int debug_flag) +{ + if (((h264_debug_flag & debug_flag) && + ((1 << index) & h264_debug_mask)) + || (debug_flag == PRINT_FLAG_ERROR)) + return 1; + return 0; +} + +#define CHECK_VALID(list_size, mark) {\ + if (list_size > MAX_LIST_SIZE || list_size < 0) { \ + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_ERROR, \ + "%s(%d): listXsize[%d] %d is larger than max size\r\n",\ + __func__, __LINE__, mark, list_size);\ + list_size = 0; \ + p_H264_Dpb->dpb_error_flag = __LINE__;\ + } \ + } + +static struct DecRefPicMarking_s + dummy_dec_ref_pic_marking_buffer + [DEC_REF_PIC_MARKING_BUFFER_NUM_MAX]; +static struct StorablePicture dummy_pic; +static struct FrameStore dummy_fs; +static struct StorablePicture *get_new_pic( + struct h264_dpb_stru *p_H264_Dpb, + enum PictureStructure structure, unsigned char is_output); + + +static void init_dummy_fs(void) +{ + dummy_fs.frame = &dummy_pic; + dummy_fs.top_field = &dummy_pic; + dummy_fs.bottom_field = &dummy_pic; + + dummy_pic.top_field = &dummy_pic; + dummy_pic.bottom_field = &dummy_pic; + dummy_pic.frame = &dummy_pic; + + dummy_pic.dec_ref_pic_marking_buffer = + &dummy_dec_ref_pic_marking_buffer[0]; +} + +enum { + LIST_0 = 0, + LIST_1 = 1, + BI_PRED = 2, + BI_PRED_L0 = 3, + BI_PRED_L1 = 4 +}; + +void ref_pic_list_reordering(struct h264_dpb_stru *p_H264_Dpb, + struct Slice *currSlice) +{ + /* struct VideoParameters *p_Vid = currSlice->p_Vid; + * byte dP_nr = assignSE2partition[currSlice->dp_mode][SE_HEADER]; + * DataPartition *partition = &(currSlice->partArr[dP_nr]); + * Bitstream *currStream = partition->bitstream; + */ + int i, j, val; + unsigned short *reorder_cmd = + &p_H264_Dpb->dpb_param.mmco.l0_reorder_cmd[0]; + /* alloc_ref_pic_list_reordering_buffer(currSlice); */ + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s\n", __func__); + if (currSlice->slice_type != I_SLICE && + currSlice->slice_type != SI_SLICE) { + /* val = currSlice->ref_pic_list_reordering_flag[LIST_0] = + * read_u_1 ("SH: ref_pic_list_reordering_flag_l0", + * currStream, &p_Dec->UsedBits); + */ + if (reorder_cmd[0] != 3) { + val = currSlice-> + ref_pic_list_reordering_flag[LIST_0] = 1; + } else { + val = currSlice-> + ref_pic_list_reordering_flag[LIST_0] = 0; + } + if (val) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "%s, ref_pic_list_reordering_flag[LIST_0] is 1\n", + __func__); + + j = 0; + i = 0; + do { + val = currSlice-> + modification_of_pic_nums_idc[LIST_0][i] = + reorder_cmd[j++]; + /* read_ue_v( + * "SH: modification_of_pic_nums_idc_l0", + * currStream, &p_Dec->UsedBits); + */ + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "%d(%d):val %x\n", i, j, val); + if (j >= 66) { + currSlice-> + ref_pic_list_reordering_flag[LIST_0] = + 0; /* by rain */ + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_ERROR, + "%s error\n", __func__); + break; + } + if (val == 0 || val == 1) { + currSlice-> + abs_diff_pic_num_minus1[LIST_0][i] = + reorder_cmd[j++]; + /* read_ue_v("SH: " + *"abs_diff_pic_num_minus1_l0", + *currStream, &p_Dec->UsedBits); + */ + } else { + if (val == 2) { + currSlice-> + long_term_pic_idx[LIST_0][i] = + reorder_cmd[j++]; + /* read_ue_v( + *"SH: long_term_pic_idx_l0", + *currStream, + *&p_Dec->UsedBits); + */ + } + } + i++; + /* assert (i>currSlice-> + * num_ref_idx_active[LIST_0]); + */ + if ( + +/* + * i>currSlice->num_ref_idx_active[LIST_0] || + */ + i >= REORDERING_COMMAND_MAX_SIZE) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "%s error %d %d\n", + __func__, i, + currSlice-> + num_ref_idx_active[LIST_0]); + currSlice-> + ref_pic_list_reordering_flag[LIST_0] = + 0; /* by rain */ + break; + } + if (j >= 66) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_ERROR, "%s error\n", + __func__); + currSlice-> + ref_pic_list_reordering_flag[LIST_0] = + 0; /* by rain */ + break; + } + + } while (val != 3); + } + } + + if (currSlice->slice_type == B_SLICE) { + reorder_cmd = &p_H264_Dpb->dpb_param.mmco.l1_reorder_cmd[0]; + /* val = currSlice->ref_pic_list_reordering_flag[LIST_1] + *= read_u_1 ("SH: ref_pic_list_reordering_flag_l1", + *currStream, + *&p_Dec->UsedBits); + */ + + if (reorder_cmd[0] != 3) { + val = + currSlice->ref_pic_list_reordering_flag[LIST_1] = 1; + } else { + val = + currSlice->ref_pic_list_reordering_flag[LIST_1] = 0; + } + + if (val) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "%s, ref_pic_list_reordering_flag[LIST_1] is 1\n", + __func__); + + j = 0; + i = 0; + do { + val = currSlice-> + modification_of_pic_nums_idc[LIST_1][i] = + reorder_cmd[j++]; + /* read_ue_v( + *"SH: modification_of_pic_nums_idc_l1", + *currStream, + *&p_Dec->UsedBits); + */ + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "%d(%d):val %x\n", + i, j, val); + if (j >= 66) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_ERROR, "%s error\n", + __func__); + currSlice-> + ref_pic_list_reordering_flag[LIST_1] = + 0; /* by rain */ + break; + } + if (val == 0 || val == 1) { + currSlice-> + abs_diff_pic_num_minus1[LIST_1][i] = + reorder_cmd[j++]; + /* read_ue_v( + *"SH: abs_diff_pic_num_minus1_l1", + *currStream, &p_Dec->UsedBits); + */ + } else { + if (val == 2) { + currSlice-> + long_term_pic_idx[LIST_1][i] = + reorder_cmd[j++]; + /* read_ue_v( + *"SH: long_term_pic_idx_l1", + *currStream, + *&p_Dec->UsedBits); + */ + } + } + i++; + /* assert(i>currSlice-> + * num_ref_idx_active[LIST_1]); + */ + if ( + /*i>currSlice->num_ref_idx_active[LIST_1] || */ + i >= REORDERING_COMMAND_MAX_SIZE) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "%s error %d %d\n", + __func__, i, + currSlice-> + num_ref_idx_active[LIST_0]); + currSlice-> + ref_pic_list_reordering_flag[LIST_1] = + 0; /* by rain */ + break; + } + if (j >= 66) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_ERROR, + "%s error\n", __func__); + break; + } + } while (val != 3); + } + } + + /* set reference index of redundant slices. */ + /* + *if (currSlice->redundant_pic_cnt && + *(currSlice->slice_type != I_SLICE)) + *{ + * currSlice->redundant_slice_ref_idx = + * currSlice->abs_diff_pic_num_minus1[LIST_0][0] + 1; + *} + */ +} + +void slice_prepare(struct h264_dpb_stru *p_H264_Dpb, + struct DecodedPictureBuffer *p_Dpb, + struct VideoParameters *p_Vid, + struct SPSParameters *sps, struct Slice *pSlice) +{ + int i, j; + /* p_Vid->active_sps = sps; */ + unsigned short *mmco_cmd = &p_H264_Dpb->dpb_param.mmco.mmco_cmd[0]; + /* for decode_poc */ + sps->pic_order_cnt_type = + p_H264_Dpb->dpb_param.l.data[PIC_ORDER_CNT_TYPE]; + sps->log2_max_pic_order_cnt_lsb_minus4 = + p_H264_Dpb->dpb_param.l.data[LOG2_MAX_PIC_ORDER_CNT_LSB] - 4; + sps->num_ref_frames_in_pic_order_cnt_cycle = + p_H264_Dpb-> + dpb_param.l.data[NUM_REF_FRAMES_IN_PIC_ORDER_CNT_CYCLE]; + for (i = 0; i < 128; i++) + sps->offset_for_ref_frame[i] = + (short) p_H264_Dpb-> + dpb_param.mmco.offset_for_ref_frame_base[i]; + sps->offset_for_non_ref_pic = + (short) p_H264_Dpb->dpb_param.l.data[OFFSET_FOR_NON_REF_PIC]; + sps->offset_for_top_to_bottom_field = + (short) p_H264_Dpb->dpb_param.l.data + [OFFSET_FOR_TOP_TO_BOTTOM_FIELD]; + + pSlice->frame_num = p_H264_Dpb->dpb_param.dpb.frame_num; + pSlice->idr_flag = + (p_H264_Dpb->dpb_param.dpb.NAL_info_mmco & 0x1f) + == 5 ? 1 : 0; + pSlice->nal_reference_idc = + (p_H264_Dpb->dpb_param.dpb.NAL_info_mmco >> 5) + & 0x3; + pSlice->pic_order_cnt_lsb = + p_H264_Dpb->dpb_param.dpb.pic_order_cnt_lsb; + pSlice->field_pic_flag = 0; + pSlice->bottom_field_flag = 0; + pSlice->delta_pic_order_cnt_bottom = val( + p_H264_Dpb->dpb_param.dpb.delta_pic_order_cnt_bottom); + pSlice->delta_pic_order_cnt[0] = val( + p_H264_Dpb->dpb_param.dpb.delta_pic_order_cnt_0); + pSlice->delta_pic_order_cnt[1] = val( + p_H264_Dpb->dpb_param.dpb.delta_pic_order_cnt_1); + + p_Vid->last_has_mmco_5 = 0; + /* last memory_management_control_operation is 5 */ + p_Vid->last_pic_bottom_field = 0; + p_Vid->max_frame_num = 1 << + (p_H264_Dpb->dpb_param.l.data[LOG2_MAX_FRAME_NUM]); + + /**/ + pSlice->structure = (p_H264_Dpb-> + dpb_param.l.data[NEW_PICTURE_STRUCTURE] == 3) ? + FRAME : p_H264_Dpb->dpb_param.l.data[NEW_PICTURE_STRUCTURE]; + if (pSlice->structure == FRAME) { + pSlice->field_pic_flag = 0; + pSlice->bottom_field_flag = 0; + } else { + pSlice->field_pic_flag = 1; + if (pSlice->structure == TOP_FIELD) + pSlice->bottom_field_flag = 0; + else + pSlice->bottom_field_flag = 1; + } + pSlice->pic_struct = p_H264_Dpb->dpb_param.l.data[PICTURE_STRUCT]; + + sps->num_ref_frames = p_H264_Dpb-> + dpb_param.l.data[MAX_REFERENCE_FRAME_NUM]; + sps->profile_idc = + (p_H264_Dpb->dpb_param.l.data[PROFILE_IDC_MMCO] >> 8) & 0xff; + /*sps->max_dpb_size = p_H264_Dpb->dpb_param.l.data[MAX_DPB_SIZE];*/ + if (pSlice->idr_flag) { + pSlice->long_term_reference_flag = mmco_cmd[0] & 1; + pSlice->no_output_of_prior_pics_flag = (mmco_cmd[0] >> 1) & 1; + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "IDR: long_term_reference_flag %d no_output_of_prior_pics_flag %d\r\n", + pSlice->long_term_reference_flag, + pSlice->no_output_of_prior_pics_flag); + + p_H264_Dpb->long_term_reference_flag = pSlice->long_term_reference_flag; + + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "idr set pre_frame_num(%d) to frame_num (%d)\n", + p_Vid->pre_frame_num, pSlice->frame_num); + + p_Vid->pre_frame_num = pSlice->frame_num; + } else if (p_H264_Dpb->mDPB.first_pic_done == 0) { + /* by rain + handle the case when first slice is I instead of IDR + */ + p_Vid->pre_frame_num = pSlice->frame_num; + } + /* pSlice->adaptive_ref_pic_buffering_flag; */ + sps->log2_max_frame_num_minus4 = + p_H264_Dpb->dpb_param.l.data[LOG2_MAX_FRAME_NUM] - 4; + sps->frame_num_gap_allowed = p_H264_Dpb->dpb_param.l.data[FRAME_NUM_GAP_ALLOWED]; + + p_Vid->non_conforming_stream = + p_H264_Dpb->dpb_param.l.data[NON_CONFORMING_STREAM]; + p_Vid->recovery_point = + p_H264_Dpb->dpb_param.l.data[RECOVERY_POINT]; + switch (p_H264_Dpb->dpb_param.l.data[SLICE_TYPE]) { + case I_Slice: + pSlice->slice_type = I_SLICE; + break; + case P_Slice: + pSlice->slice_type = P_SLICE; + break; + case B_Slice: + pSlice->slice_type = B_SLICE; + break; + default: + pSlice->slice_type = NUM_SLICE_TYPES; + break; + } + + pSlice->num_ref_idx_active[LIST_0] = + p_H264_Dpb->dpb_param.dpb.num_ref_idx_l0_active_minus1 + + 1; + /* p_H264_Dpb->dpb_param.l.data[PPS_NUM_REF_IDX_L0_ACTIVE_MINUS1]; */ + pSlice->num_ref_idx_active[LIST_1] = + p_H264_Dpb->dpb_param.dpb.num_ref_idx_l1_active_minus1 + + 1; + /* p_H264_Dpb->dpb_param.l.data[PPS_NUM_REF_IDX_L1_ACTIVE_MINUS1]; */ + + pSlice->p_Vid = p_Vid; + pSlice->p_Dpb = p_Dpb; + /* + p_H264_Dpb->colocated_buf_size = + p_H264_Dpb->dpb_param.l.data[FRAME_SIZE_IN_MB] * 96;*/ + pSlice->first_mb_in_slice = + p_H264_Dpb->dpb_param.l.data[FIRST_MB_IN_SLICE]; + pSlice->mode_8x8_flags = p_H264_Dpb->dpb_param.l.data[MODE_8X8_FLAGS]; + pSlice->picture_structure_mmco = + p_H264_Dpb->dpb_param.dpb.picture_structure_mmco; + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s slice_type is %d, num_ref_idx_active[0,1]=%d,%d nal_reference_idc %d pic struct 0x%x(mmco stru 0x%x)\n", + __func__, pSlice->slice_type, + pSlice->num_ref_idx_active[LIST_0], + pSlice->num_ref_idx_active[LIST_1], + pSlice->nal_reference_idc, + pSlice->structure, + pSlice->picture_structure_mmco); +#ifdef ERROR_CHECK + if (pSlice->num_ref_idx_active[LIST_0] >= MAX_LIST_SIZE) { + pSlice->num_ref_idx_active[LIST_0] = MAX_LIST_SIZE - 1; + p_H264_Dpb->dpb_error_flag = __LINE__; + } + if (pSlice->num_ref_idx_active[LIST_1] >= MAX_LIST_SIZE) { + pSlice->num_ref_idx_active[LIST_1] = MAX_LIST_SIZE - 1; + p_H264_Dpb->dpb_error_flag = __LINE__; + } +#endif + +#if 1 + /* dec_ref_pic_marking_buffer */ + pSlice->adaptive_ref_pic_buffering_flag = 0; + if (pSlice->nal_reference_idc) { + for (i = 0, j = 0; i < 44; j++) { + unsigned short val; + struct DecRefPicMarking_s *tmp_drpm = + &pSlice->dec_ref_pic_marking_buffer[j]; + memset(tmp_drpm, 0, sizeof(struct DecRefPicMarking_s)); + val = tmp_drpm-> + memory_management_control_operation = + mmco_cmd[i++]; + tmp_drpm->Next = NULL; + if (j > 0) { + pSlice-> + dec_ref_pic_marking_buffer[j - 1].Next = + tmp_drpm; + } + if (val == 0 || i >= 44) + break; + pSlice->adaptive_ref_pic_buffering_flag = 1; + if ((val == 1) || (val == 3)) { + tmp_drpm->difference_of_pic_nums_minus1 = + mmco_cmd[i++]; + } + if (val == 2) + tmp_drpm->long_term_pic_num = mmco_cmd[i++]; + if (i >= 44) + break; + if ((val == 3) || (val == 6)) + tmp_drpm->long_term_frame_idx = mmco_cmd[i++]; + if (val == 4) { + tmp_drpm->max_long_term_frame_idx_plus1 = + mmco_cmd[i++]; + } + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "dec_ref_pic_marking_buffer[%d]:operation %x diff_pic_minus1 %x long_pic_num %x long_frame_idx %x max_long_frame_idx_plus1 %x\n", + j, + tmp_drpm->memory_management_control_operation, + tmp_drpm->difference_of_pic_nums_minus1, + tmp_drpm->long_term_pic_num, + tmp_drpm->long_term_frame_idx, + tmp_drpm->max_long_term_frame_idx_plus1); + } + } + + ref_pic_list_reordering(p_H264_Dpb, pSlice); +#endif + + /*VUI*/ + p_H264_Dpb->vui_status = p_H264_Dpb->dpb_param.l.data[VUI_STATUS]; + p_H264_Dpb->aspect_ratio_idc = + p_H264_Dpb->dpb_param.l.data[ASPECT_RATIO_IDC]; + p_H264_Dpb->aspect_ratio_sar_width = + p_H264_Dpb->dpb_param.l.data[ASPECT_RATIO_SAR_WIDTH]; + p_H264_Dpb->aspect_ratio_sar_height = + p_H264_Dpb->dpb_param.l.data[ASPECT_RATIO_SAR_HEIGHT]; + + p_H264_Dpb->fixed_frame_rate_flag = p_H264_Dpb->dpb_param.l.data[ + FIXED_FRAME_RATE_FLAG]; + p_H264_Dpb->num_units_in_tick = + p_H264_Dpb->dpb_param.l.data[NUM_UNITS_IN_TICK]; + p_H264_Dpb->time_scale = p_H264_Dpb->dpb_param.l.data[TIME_SCALE] | + (p_H264_Dpb->dpb_param.l.data[TIME_SCALE + 1] << 16); + + p_H264_Dpb->bitstream_restriction_flag = + (p_H264_Dpb->dpb_param.l.data[SPS_FLAGS2] >> 3) & 0x1; + p_H264_Dpb->num_reorder_frames = + p_H264_Dpb->dpb_param.l.data[NUM_REORDER_FRAMES]; + p_H264_Dpb->max_dec_frame_buffering = + p_H264_Dpb->dpb_param.l.data[MAX_BUFFER_FRAME]; + + /**/ + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s return\n", __func__); +} + +static void decode_poc(struct VideoParameters *p_Vid, struct Slice *pSlice) +{ + struct h264_dpb_stru *p_H264_Dpb = container_of(p_Vid, + struct h264_dpb_stru, mVideo); + struct SPSParameters *active_sps = p_Vid->active_sps; + int i; + /* for POC mode 0: */ + unsigned int MaxPicOrderCntLsb = (1 << + (active_sps->log2_max_pic_order_cnt_lsb_minus4 + 4)); + + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DEBUG_POC, + "%s:pic_order_cnt_type %d, idr_flag %d last_has_mmco_5 %d last_pic_bottom_field %d pic_order_cnt_lsb %d PrevPicOrderCntLsb %d\r\n", + __func__, + active_sps->pic_order_cnt_type, + pSlice->idr_flag, + p_Vid->last_has_mmco_5, + p_Vid->last_pic_bottom_field, + pSlice->pic_order_cnt_lsb, + p_Vid->PrevPicOrderCntLsb + ); + + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DEBUG_POC, + "%s:field_pic_flag %d, bottom_field_flag %d frame_num %d PreviousFrameNum %d PreviousFrameNumOffset %d ax_frame_num %d num_ref_frames_in_pic_order_cnt_cycle %d offset_for_non_ref_pic %d\r\n", + __func__, + pSlice->field_pic_flag, + pSlice->bottom_field_flag, + pSlice->frame_num, + p_Vid->PreviousFrameNum, + p_Vid->PreviousFrameNumOffset, + p_Vid->max_frame_num, + active_sps->num_ref_frames_in_pic_order_cnt_cycle, + active_sps->offset_for_non_ref_pic + ); + + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DEBUG_POC, + "%s: delta_pic_order_cnt %d %d nal_reference_idc %d\r\n", + __func__, + pSlice->delta_pic_order_cnt[0], pSlice->delta_pic_order_cnt[1], + pSlice->nal_reference_idc + ); + + + switch (active_sps->pic_order_cnt_type) { + case 0: /* POC MODE 0 */ + /* 1st */ + if (pSlice->idr_flag) { + p_Vid->PrevPicOrderCntMsb = 0; + p_Vid->PrevPicOrderCntLsb = 0; + } else { + if (p_Vid->last_has_mmco_5) { + if (p_Vid->last_pic_bottom_field) { + p_Vid->PrevPicOrderCntMsb = 0; + p_Vid->PrevPicOrderCntLsb = 0; + } else { + p_Vid->PrevPicOrderCntMsb = 0; + p_Vid->PrevPicOrderCntLsb = + pSlice->toppoc; + } + } + } + /* Calculate the MSBs of current picture */ + if (pSlice->pic_order_cnt_lsb < p_Vid->PrevPicOrderCntLsb && + (p_Vid->PrevPicOrderCntLsb - pSlice->pic_order_cnt_lsb) >= + (MaxPicOrderCntLsb / 2)) + pSlice->PicOrderCntMsb = p_Vid->PrevPicOrderCntMsb + + MaxPicOrderCntLsb; + else if (pSlice->pic_order_cnt_lsb > + p_Vid->PrevPicOrderCntLsb && + (pSlice->pic_order_cnt_lsb - + p_Vid->PrevPicOrderCntLsb) > + (MaxPicOrderCntLsb / 2)) + pSlice->PicOrderCntMsb = p_Vid->PrevPicOrderCntMsb - + MaxPicOrderCntLsb; + else + pSlice->PicOrderCntMsb = p_Vid->PrevPicOrderCntMsb; + + /* 2nd */ + if (pSlice->field_pic_flag == 0) { + /* frame pix */ + pSlice->toppoc = pSlice->PicOrderCntMsb + + pSlice->pic_order_cnt_lsb; + pSlice->bottompoc = pSlice->toppoc + + pSlice->delta_pic_order_cnt_bottom; + pSlice->ThisPOC = pSlice->framepoc = + (pSlice->toppoc < pSlice->bottompoc) ? + pSlice->toppoc : pSlice->bottompoc; + /* POC200301 */ + } else if (pSlice->bottom_field_flag == 0) { + /* top field */ + pSlice->ThisPOC = pSlice->toppoc = + pSlice->PicOrderCntMsb + + pSlice->pic_order_cnt_lsb; + } else { + /* bottom field */ + pSlice->ThisPOC = pSlice->bottompoc = + pSlice->PicOrderCntMsb + + pSlice->pic_order_cnt_lsb; + } + pSlice->framepoc = pSlice->ThisPOC; + + p_Vid->ThisPOC = pSlice->ThisPOC; + + /* if ( pSlice->frame_num != p_Vid->PreviousFrameNum) + * Seems redundant + */ + p_Vid->PreviousFrameNum = pSlice->frame_num; + + if (pSlice->nal_reference_idc) { + p_Vid->PrevPicOrderCntLsb = pSlice->pic_order_cnt_lsb; + p_Vid->PrevPicOrderCntMsb = pSlice->PicOrderCntMsb; + } + + break; + + case 1: /* POC MODE 1 */ + /* 1st */ + if (pSlice->idr_flag) { + p_Vid->FrameNumOffset = 0; /* first pix of IDRGOP */ + if (pSlice->frame_num) + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "frame_num not equal to zero in IDR picture %d", + -1020); + } else { + if (p_Vid->last_has_mmco_5) { + p_Vid->PreviousFrameNumOffset = 0; + p_Vid->PreviousFrameNum = 0; + } + if (pSlice->frame_num < p_Vid->PreviousFrameNum) { + /* not first pix of IDRGOP */ + p_Vid->FrameNumOffset = + p_Vid->PreviousFrameNumOffset + + p_Vid->max_frame_num; + } else { + p_Vid->FrameNumOffset = + p_Vid->PreviousFrameNumOffset; + } + } + + /* 2nd */ + if (active_sps->num_ref_frames_in_pic_order_cnt_cycle) + pSlice->AbsFrameNum = + p_Vid->FrameNumOffset + pSlice->frame_num; + else + pSlice->AbsFrameNum = 0; + if ((!pSlice->nal_reference_idc) && pSlice->AbsFrameNum > 0) + pSlice->AbsFrameNum--; + + /* 3rd */ + p_Vid->ExpectedDeltaPerPicOrderCntCycle = 0; + + if (active_sps->num_ref_frames_in_pic_order_cnt_cycle) + for (i = 0; i < (int) active_sps-> + num_ref_frames_in_pic_order_cnt_cycle; i++) { + p_Vid->ExpectedDeltaPerPicOrderCntCycle += + active_sps->offset_for_ref_frame[i]; + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DEBUG_POC, + "%s: offset_for_ref_frame %d\r\n", + __func__, + active_sps-> + offset_for_ref_frame[i]); + } + + if (pSlice->AbsFrameNum) { + p_Vid->PicOrderCntCycleCnt = + (pSlice->AbsFrameNum - 1) / + active_sps-> + num_ref_frames_in_pic_order_cnt_cycle; + p_Vid->FrameNumInPicOrderCntCycle = + (pSlice->AbsFrameNum - 1) % + active_sps-> + num_ref_frames_in_pic_order_cnt_cycle; + p_Vid->ExpectedPicOrderCnt = + p_Vid->PicOrderCntCycleCnt * + p_Vid->ExpectedDeltaPerPicOrderCntCycle; + for (i = 0; i <= (int)p_Vid-> + FrameNumInPicOrderCntCycle; i++) { + p_Vid->ExpectedPicOrderCnt += + active_sps->offset_for_ref_frame[i]; + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DEBUG_POC, + "%s: offset_for_ref_frame %d\r\n", + __func__, + active_sps-> + offset_for_ref_frame[i]); + } + } else + p_Vid->ExpectedPicOrderCnt = 0; + + if (!pSlice->nal_reference_idc) + p_Vid->ExpectedPicOrderCnt += + active_sps->offset_for_non_ref_pic; + + if (pSlice->field_pic_flag == 0) { + /* frame pix */ + pSlice->toppoc = p_Vid->ExpectedPicOrderCnt + + pSlice->delta_pic_order_cnt[0]; + pSlice->bottompoc = pSlice->toppoc + + active_sps->offset_for_top_to_bottom_field + + pSlice->delta_pic_order_cnt[1]; + pSlice->ThisPOC = pSlice->framepoc = + (pSlice->toppoc < pSlice->bottompoc) ? + pSlice->toppoc : pSlice->bottompoc; + /* POC200301 */ + } else if (pSlice->bottom_field_flag == 0) { + /* top field */ + pSlice->ThisPOC = pSlice->toppoc = + p_Vid->ExpectedPicOrderCnt + + pSlice->delta_pic_order_cnt[0]; + } else { + /* bottom field */ + pSlice->ThisPOC = pSlice->bottompoc = + p_Vid->ExpectedPicOrderCnt + + active_sps->offset_for_top_to_bottom_field + + pSlice->delta_pic_order_cnt[0]; + } + pSlice->framepoc = pSlice->ThisPOC; + + p_Vid->PreviousFrameNum = pSlice->frame_num; + p_Vid->PreviousFrameNumOffset = p_Vid->FrameNumOffset; + + break; + + + case 2: /* POC MODE 2 */ + if (pSlice->idr_flag) { /* IDR picture */ + p_Vid->FrameNumOffset = 0; /* first pix of IDRGOP */ + pSlice->ThisPOC = pSlice->framepoc = pSlice->toppoc = + pSlice->bottompoc = 0; + if (pSlice->frame_num) + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "frame_num not equal to zero in IDR picture %d", + -1020); + } else { + if (p_Vid->last_has_mmco_5) { + p_Vid->PreviousFrameNum = 0; + p_Vid->PreviousFrameNumOffset = 0; + } + if (pSlice->frame_num < p_Vid->PreviousFrameNum) + p_Vid->FrameNumOffset = + p_Vid->PreviousFrameNumOffset + + p_Vid->max_frame_num; + else + p_Vid->FrameNumOffset = + p_Vid->PreviousFrameNumOffset; + + pSlice->AbsFrameNum = p_Vid->FrameNumOffset + + pSlice->frame_num; + if (!pSlice->nal_reference_idc) + pSlice->ThisPOC = + (2 * pSlice->AbsFrameNum - 1); + else + pSlice->ThisPOC = (2 * pSlice->AbsFrameNum); + + if (pSlice->field_pic_flag == 0) + pSlice->toppoc = pSlice->bottompoc = + pSlice->framepoc = pSlice->ThisPOC; + else if (pSlice->bottom_field_flag == 0) + pSlice->toppoc = pSlice->framepoc = + pSlice->ThisPOC; + else + pSlice->bottompoc = pSlice->framepoc = + pSlice->ThisPOC; + } + + p_Vid->PreviousFrameNum = pSlice->frame_num; + p_Vid->PreviousFrameNumOffset = p_Vid->FrameNumOffset; + break; + + + default: + /* error must occurs */ + /* assert( 1==0 ); */ + break; + } +} + +void fill_frame_num_gap(struct VideoParameters *p_Vid, struct Slice *currSlice) +{ + struct h264_dpb_stru *p_H264_Dpb = + container_of(p_Vid, struct h264_dpb_stru, mVideo); + struct SPSParameters *active_sps = p_Vid->active_sps; + int CurrFrameNum; + int UnusedShortTermFrameNum; + struct StorablePicture *picture = NULL; + int tmp1 = currSlice->delta_pic_order_cnt[0]; + int tmp2 = currSlice->delta_pic_order_cnt[1]; + int ret; + + currSlice->delta_pic_order_cnt[0] = + currSlice->delta_pic_order_cnt[1] = 0; + + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "A gap in frame number is found, try to fill it.(pre_frame_num %d, max_frame_num %d\n", + p_Vid->pre_frame_num, p_Vid->max_frame_num + ); + + UnusedShortTermFrameNum = (p_Vid->pre_frame_num + 1) + % p_Vid->max_frame_num; + CurrFrameNum = currSlice->frame_num; /*p_Vid->frame_num;*/ + + while (CurrFrameNum != UnusedShortTermFrameNum) { + /*pr_err("CurrFrameNum = %d, UnusedShortTermFrameNum = %d\n", CurrFrameNum, UnusedShortTermFrameNum);*/ + /*picture = alloc_storable_picture + *(p_Vid, FRAME, p_Vid->width, + *p_Vid->height, + *p_Vid->width_cr, + *p_Vid->height_cr, 1); + */ + picture = get_new_pic(p_H264_Dpb, + p_H264_Dpb->mSlice.structure, + /*p_Vid->width, p_Vid->height, + *p_Vid->width_cr, + p_Vid->height_cr,*/ 1); + + if (picture == NULL) { + struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; + + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_ERROR, + "%s Error: get_new_pic return NULL\r\n", + __func__); + /*h264_debug_flag |= PRINT_FLAG_DUMP_DPB;*/ + dump_dpb(p_Dpb, 0); + return; + } + + picture->colocated_buf_index = -1; + picture->buf_spec_num = -1; + picture->buf_spec_is_alloced = 0; + + picture->coded_frame = 1; + picture->pic_num = UnusedShortTermFrameNum; + picture->frame_num = UnusedShortTermFrameNum; + picture->non_existing = 1; + picture->is_output = 1; + picture->used_for_reference = 1; + picture->adaptive_ref_pic_buffering_flag = 0; + #if (MVC_EXTENSION_ENABLE) + picture->view_id = currSlice->view_id; + #endif + + currSlice->frame_num = UnusedShortTermFrameNum; + if (active_sps->pic_order_cnt_type != 0) { + /*decode_poc(p_Vid, p_Vid->ppSliceList[0]);*/ + decode_poc(&p_H264_Dpb->mVideo, &p_H264_Dpb->mSlice); + } + picture->top_poc = currSlice->toppoc; + picture->bottom_poc = currSlice->bottompoc; + picture->frame_poc = currSlice->framepoc; + picture->poc = currSlice->framepoc; + + ret = store_picture_in_dpb(p_H264_Dpb, picture, 0); + if (ret == -1) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_ERROR, + "%s Error: store_picture_in_dpb failed, break\n", + __func__); + release_picture(p_H264_Dpb, picture); + bufmgr_force_recover(p_H264_Dpb); + return; + } else if (ret == -2) + release_picture(p_H264_Dpb, picture); + + picture = NULL; + p_Vid->pre_frame_num = UnusedShortTermFrameNum; + UnusedShortTermFrameNum = + (UnusedShortTermFrameNum + 1) % + p_Vid->max_frame_num; + } + currSlice->delta_pic_order_cnt[0] = tmp1; + currSlice->delta_pic_order_cnt[1] = tmp2; + currSlice->frame_num = CurrFrameNum; +} + +void dpb_init_global(struct h264_dpb_stru *p_H264_Dpb, + int id, int actual_dpb_size, int max_reference_size) +{ + int i; + + init_dummy_fs(); + + memset(&p_H264_Dpb->mDPB, 0, sizeof(struct DecodedPictureBuffer)); + + memset(&p_H264_Dpb->mSlice, 0, sizeof(struct Slice)); + memset(&p_H264_Dpb->mVideo, 0, sizeof(struct VideoParameters)); + memset(&p_H264_Dpb->mSPS, 0, sizeof(struct SPSParameters)); + + for (i = 0; i < DPB_SIZE_MAX; i++) { + memset(&(p_H264_Dpb->mFrameStore[i]), 0, + sizeof(struct FrameStore)); + } + + for (i = 0; i < MAX_PIC_BUF_NUM; i++) { + memset(&(p_H264_Dpb->m_PIC[i]), 0, + sizeof(struct StorablePicture)); + p_H264_Dpb->m_PIC[i].index = i; + } + p_H264_Dpb->decoder_index = id; + + /* make sure dpb_init_global + *can be called during decoding + *(in DECODE_STATE_IDLE or DECODE_STATE_READY state) + */ + p_H264_Dpb->mDPB.size = actual_dpb_size; + p_H264_Dpb->max_reference_size = max_reference_size; + p_H264_Dpb->poc_even_odd_flag = 0; +} + +static void init_picture(struct h264_dpb_stru *p_H264_Dpb, + struct Slice *currSlice, + struct StorablePicture *dec_picture) +{ + /* struct VideoParameters *p_Vid = &(p_H264_Dpb->mVideo); */ + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s dec_picture %p\n", __func__, dec_picture); + dec_picture->top_poc = currSlice->toppoc; + dec_picture->bottom_poc = currSlice->bottompoc; + dec_picture->frame_poc = currSlice->framepoc; + switch (currSlice->structure) { + case TOP_FIELD: { + dec_picture->poc = currSlice->toppoc; + /* p_Vid->number *= 2; */ + break; + } + case BOTTOM_FIELD: { + dec_picture->poc = currSlice->bottompoc; + /* p_Vid->number = p_Vid->number * 2 + 1; */ + break; + } + case FRAME: { + dec_picture->poc = currSlice->framepoc; + break; + } + default: + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "p_Vid->structure not initialized %d\n", 235); + } + + /* dec_picture->slice_type = p_Vid->type; */ + dec_picture->used_for_reference = (currSlice->nal_reference_idc != 0); + dec_picture->idr_flag = currSlice->idr_flag; + dec_picture->no_output_of_prior_pics_flag = + currSlice->no_output_of_prior_pics_flag; + dec_picture->long_term_reference_flag = + currSlice->long_term_reference_flag; +#if 1 + dec_picture->adaptive_ref_pic_buffering_flag = + currSlice->adaptive_ref_pic_buffering_flag; + dec_picture->dec_ref_pic_marking_buffer = + &currSlice->dec_ref_pic_marking_buffer[0]; +#endif + /* currSlice->dec_ref_pic_marking_buffer = NULL; */ + + /* dec_picture->mb_aff_frame_flag = currSlice->mb_aff_frame_flag; */ + /* dec_picture->PicWidthInMbs = p_Vid->PicWidthInMbs; */ + + /* p_Vid->get_mb_block_pos = + * dec_picture->mb_aff_frame_flag ? get_mb_block_pos_mbaff : + * get_mb_block_pos_normal; + */ + /* p_Vid->getNeighbour = + * dec_picture->mb_aff_frame_flag ? getAffNeighbour : + * getNonAffNeighbour; + */ + + dec_picture->pic_num = currSlice->frame_num; + dec_picture->frame_num = currSlice->frame_num; + + /* dec_picture->recovery_frame = + * (unsigned int) ((int) currSlice->frame_num == + * p_Vid->recovery_frame_num); + */ + + dec_picture->coded_frame = (currSlice->structure == FRAME); + + /* dec_picture->chroma_format_idc = active_sps->chroma_format_idc; */ + + /* dec_picture->frame_mbs_only_flag = + * active_sps->frame_mbs_only_flag; + */ + /* dec_picture->frame_cropping_flag = + * active_sps->frame_cropping_flag; + */ + + if ((currSlice->picture_structure_mmco & 0x3) == 3) { + dec_picture->mb_aff_frame_flag = 1; + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s, picture_structure_mmco is %x, set mb_aff_frame_flag to 1\n", + __func__, + currSlice->picture_structure_mmco); + } + + if (currSlice->pic_struct < PIC_INVALID) { + dec_picture->pic_struct = currSlice->pic_struct; + } else { + dec_picture->pic_struct = PIC_INVALID; + } + + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s pic_struct = %d\n", __func__, dec_picture->pic_struct); +} + +void dump_pic(struct h264_dpb_stru *p_H264_Dpb) +{ + int ii; + struct StorablePicture *pic; + for (ii = 0; ii < MAX_PIC_BUF_NUM; ii++) { + pic = &(p_H264_Dpb->m_PIC[ii]); + if (pic->is_used) { + dpb_print(p_H264_Dpb->decoder_index, 0, + "pic(%d,%d) poc %d is_used %d bufspec %d colbuf %d for_ref %d long_term %d pre_out %d output %d nonexist %d data_flag 0x%x\n", + ii, pic->index, + pic->poc, + pic->is_used, + pic->buf_spec_num, + pic->colocated_buf_index, + pic->used_for_reference, + pic->is_long_term, + pic->pre_output, + pic->is_output, + pic->non_existing, + pic->data_flag); + } + } +} + +/* +static void is_pic_used_by_dpb(struct h264_dpb_stru *p_H264_Dpb, + struct StorablePicture *pic) +{ + struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; + unsigned i; + for (i = 0; i < p_Dpb->used_size; i++) { + if (p_Dpb->fs[i]->top_field == pic || + p_Dpb->fs[i]->bottom_field == pic || + p_Dpb->fs[i]->frame == pic + ) + break; + } + if (i < p_Dpb->used_size) + return 1; + return 0; +} +*/ + +static struct StorablePicture *get_new_pic(struct h264_dpb_stru *p_H264_Dpb, + enum PictureStructure structure, unsigned char is_output) +{ + struct StorablePicture *s = NULL; + struct StorablePicture *pic; + struct VideoParameters *p_Vid = &(p_H264_Dpb->mVideo); + /* recycle un-used pic */ + int ii = 0; + + for (ii = 0; ii < MAX_PIC_BUF_NUM; ii++) { + pic = &(p_H264_Dpb->m_PIC[ii]); + if (pic->is_used == 0) { + pic->is_used = 1; + s = pic; + break; + } + } + + if (s) { + s->buf_spec_is_alloced = 0; + s->pic_num = 0; + s->frame_num = 0; + s->long_term_frame_idx = 0; + s->long_term_pic_num = 0; + s->used_for_reference = 0; + s->is_long_term = 0; + s->non_existing = 0; + s->is_output = 0; + s->pre_output = 0; + s->max_slice_id = 0; + s->data_flag &= ~(ERROR_FLAG | NODISP_FLAG); +#if (MVC_EXTENSION_ENABLE) + s->view_id = -1; +#endif + + s->structure = structure; + +#if 0 + s->size_x = size_x; + s->size_y = size_y; + s->size_x_cr = size_x_cr; + s->size_y_cr = size_y_cr; + s->size_x_m1 = size_x - 1; + s->size_y_m1 = size_y - 1; + s->size_x_cr_m1 = size_x_cr - 1; + s->size_y_cr_m1 = size_y_cr - 1; + + s->top_field = p_Vid->no_reference_picture; + s->bottom_field = p_Vid->no_reference_picture; + s->frame = p_Vid->no_reference_picture; +#endif + /* s->dec_ref_pic_marking_buffer = NULL; */ + + s->coded_frame = 0; + s->mb_aff_frame_flag = 0; + + s->top_poc = s->bottom_poc = s->poc = 0; + s->seiHasTone_mapping = 0; + s->frame_mbs_only_flag = p_Vid->active_sps->frame_mbs_only_flag; + + if (!p_Vid->active_sps->frame_mbs_only_flag && + structure != FRAME) { + int i, j; + + for (j = 0; j < MAX_NUM_SLICES; j++) { + for (i = 0; i < 2; i++) { + /* s->listX[j][i] = + *calloc(MAX_LIST_SIZE, + *sizeof (struct StorablePicture *)); + *+1 for reordering ??? + + *if (NULL == s->listX[j][i]) + *no_mem_exit("alloc_storable_picture: + *s->listX[i]"); + */ + } + } + } + } else + p_H264_Dpb->buf_alloc_fail = 1; + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s %p\n", __func__, s); + return s; +} + +static void free_picture(struct h264_dpb_stru *p_H264_Dpb, + struct StorablePicture *pic) +{ + if (pic == NULL || pic->index < 0 || + pic->index >= MAX_PIC_BUF_NUM) + return; + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s %p %d\n", __func__, pic, pic->index); + /* assert(pic->index<MAX_PIC_BUF_NUM); */ + p_H264_Dpb->m_PIC[pic->index].is_used = 0; +} + +static void gen_field_ref_ids(struct VideoParameters *p_Vid, + struct StorablePicture *p) +{ + int i, j; + struct h264_dpb_stru *p_H264_Dpb = container_of(p_Vid, + struct h264_dpb_stru, mVideo); + /* ! Generate Frame parameters from field information. */ + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s\n", __func__); + + /* copy the list; */ + for (j = 0; j < p_Vid->iSliceNumOfCurrPic; j++) { + if (p->listX[j][LIST_0]) { + p->listXsize[j][LIST_0] = + p_Vid->ppSliceList[j]->listXsize[LIST_0]; + for (i = 0; i < p->listXsize[j][LIST_0]; i++) + p->listX[j][LIST_0][i] = + p_Vid->ppSliceList[j]->listX[LIST_0][i]; + } + if (p->listX[j][LIST_1]) { + p->listXsize[j][LIST_1] = + p_Vid->ppSliceList[j]->listXsize[LIST_1]; + for (i = 0; i < p->listXsize[j][LIST_1]; i++) + p->listX[j][LIST_1][i] = + p_Vid->ppSliceList[j]->listX[LIST_1][i]; + } + } +} + +static void init_dpb(struct h264_dpb_stru *p_H264_Dpb, int type) +{ + unsigned int i; + struct VideoParameters *p_Vid = &p_H264_Dpb->mVideo; + struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; + struct SPSParameters *active_sps = &p_H264_Dpb->mSPS; + + p_Vid->active_sps = active_sps; + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s\n", __func__); + + p_Dpb->p_Vid = p_Vid; + if (p_Dpb->init_done) { + /* free_dpb(p_Dpb); */ + if (p_Vid->no_reference_picture) { + free_picture(p_H264_Dpb, p_Vid->no_reference_picture); + p_Vid->no_reference_picture = NULL; + } + p_Dpb->init_done = 0; + } + + /* p_Dpb->size = 10; //active_sps->max_dpb_size; //16; + * getDpbSize(p_Vid, active_sps) + + * p_Vid->p_Inp->dpb_plus[type==2? 1: 0]; + * p_Dpb->size = active_sps->max_dpb_size; //16; + * getDpbSize(p_Vid, active_sps) + + * p_Vid->p_Inp->dpb_plus[type==2? 1: 0]; + * p_Dpb->size initialzie in vh264.c + */ + p_Dpb->num_ref_frames = active_sps->num_ref_frames; + /* p_Dpb->num_ref_frames initialzie in vh264.c */ + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s dpb_size is %d num_ref_frames = %d (%d)\n", + __func__, p_Dpb->size, + p_Dpb->num_ref_frames, + active_sps->num_ref_frames); + if (active_sps->num_ref_frames == 0xffff) { + dpb_print(p_H264_Dpb->decoder_index, 0, + "!!!Warning, num_ref_frames = %d is invalid\n", + active_sps->num_ref_frames); + } + +#if 0 + /* ??? */ +#if (MVC_EXTENSION_ENABLE) + if ((unsigned int)active_sps->max_dec_frame_buffering < + active_sps->num_ref_frames) { +#else + if (p_Dpb->size < active_sps->num_ref_frames) { +#endif + error( + "DPB size at specified level is smaller than the specified number of reference frames. This is not allowed.\n", + 1000); + } +#endif + + p_Dpb->used_size = 0; + p_Dpb->last_picture = NULL; + + p_Dpb->ref_frames_in_buffer = 0; + p_Dpb->ltref_frames_in_buffer = 0; + +#if 0 + p_Dpb->fs = calloc(p_Dpb->size, sizeof(struct FrameStore *)); + if (NULL == p_Dpb->fs) + no_mem_exit("init_dpb: p_Dpb->fs"); + + p_Dpb->fs_ref = calloc(p_Dpb->size, sizeof(struct FrameStore *)); + if (NULL == p_Dpb->fs_ref) + no_mem_exit("init_dpb: p_Dpb->fs_ref"); + + p_Dpb->fs_ltref = calloc(p_Dpb->size, sizeof(struct FrameStore *)); + if (NULL == p_Dpb->fs_ltref) + no_mem_exit("init_dpb: p_Dpb->fs_ltref"); +#endif + +#if (MVC_EXTENSION_ENABLE) + p_Dpb->fs_ilref = calloc(1, sizeof(struct FrameStore *)); + if (NULL == p_Dpb->fs_ilref) + no_mem_exit("init_dpb: p_Dpb->fs_ilref"); +#endif + + for (i = 0; i < p_Dpb->size; i++) { + p_Dpb->fs[i] = &(p_H264_Dpb->mFrameStore[i]); + /* alloc_frame_store(); */ + p_Dpb->fs[i]->index = i; + p_Dpb->fs_ref[i] = NULL; + p_Dpb->fs_ltref[i] = NULL; + p_Dpb->fs[i]->layer_id = 0; /* MVC_INIT_VIEW_ID; */ +#if (MVC_EXTENSION_ENABLE) + p_Dpb->fs[i]->view_id = MVC_INIT_VIEW_ID; + p_Dpb->fs[i]->inter_view_flag[0] = + p_Dpb->fs[i]->inter_view_flag[1] = 0; + p_Dpb->fs[i]->anchor_pic_flag[0] = + p_Dpb->fs[i]->anchor_pic_flag[1] = 0; +#endif + } +#if (MVC_EXTENSION_ENABLE) + if (type == 2) { + p_Dpb->fs_ilref[0] = alloc_frame_store(); + /* These may need some cleanups */ + p_Dpb->fs_ilref[0]->view_id = MVC_INIT_VIEW_ID; + p_Dpb->fs_ilref[0]->inter_view_flag[0] = + p_Dpb->fs_ilref[0]->inter_view_flag[1] = 0; + p_Dpb->fs_ilref[0]->anchor_pic_flag[0] = + p_Dpb->fs_ilref[0]->anchor_pic_flag[1] = 0; + /* given that this is in a different buffer, + * do we even need proc_flag anymore? + */ + } else + p_Dpb->fs_ilref[0] = NULL; +#endif + + /* + *for (i = 0; i < 6; i++) + *{ + *currSlice->listX[i] = + * calloc(MAX_LIST_SIZE, sizeof (struct StorablePicture *)); + * +1 for reordering + *if (NULL == currSlice->listX[i]) + *no_mem_exit("init_dpb: currSlice->listX[i]"); + *} + */ + /* allocate a dummy storable picture */ + if (!p_Vid->no_reference_picture) { + p_Vid->no_reference_picture = get_new_pic(p_H264_Dpb, + FRAME, + /*p_Vid->width, p_Vid->height, + *p_Vid->width_cr, p_Vid->height_cr, + */ + 1); + p_Vid->no_reference_picture->top_field = + p_Vid->no_reference_picture; + p_Vid->no_reference_picture->bottom_field = + p_Vid->no_reference_picture; + p_Vid->no_reference_picture->frame = + p_Vid->no_reference_picture; + } + p_Dpb->last_output_poc = INT_MIN; + +#if (MVC_EXTENSION_ENABLE) + p_Dpb->last_output_view_id = -1; +#endif + + p_Vid->last_has_mmco_5 = 0; + + init_colocate_buf(p_H264_Dpb, p_H264_Dpb->max_reference_size); + + p_Dpb->init_done = 1; + +#if 0 +/* ??? */ + /* picture error concealment */ + if (p_Vid->conceal_mode != 0 && !p_Vid->last_out_fs) + p_Vid->last_out_fs = alloc_frame_store(); +#endif +} + +static void dpb_split_field(struct h264_dpb_stru *p_H264_Dpb, + struct FrameStore *fs) +{ + struct StorablePicture *fs_top = NULL, *fs_btm = NULL; + struct StorablePicture *frame = fs->frame; + + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s %p %p\n", __func__, fs, frame); + + fs->poc = frame->poc; + + if (!frame->frame_mbs_only_flag) { + fs_top = fs->top_field = get_new_pic(p_H264_Dpb, + TOP_FIELD, + /* frame->size_x, frame->size_y, + *frame->size_x_cr, frame->size_y_cr, + */ + 1); + fs_btm = fs->bottom_field = get_new_pic(p_H264_Dpb, + BOTTOM_FIELD, + /*frame->size_x, frame->size_y, + *frame->size_x_cr, frame->size_y_cr, + */ + 1); + if (fs_top == NULL || fs_btm == NULL) + return; +#if 1 +/* rain */ + fs_top->buf_spec_num = frame->buf_spec_num; + fs_btm->buf_spec_num = frame->buf_spec_num; + + fs_top->colocated_buf_index = frame->colocated_buf_index; + fs_btm->colocated_buf_index = frame->colocated_buf_index; + + fs_top->data_flag = frame->data_flag; + fs_btm->data_flag = frame->data_flag; +#endif + fs_top->poc = frame->top_poc; + fs_btm->poc = frame->bottom_poc; + +#if (MVC_EXTENSION_ENABLE) + fs_top->view_id = frame->view_id; + fs_btm->view_id = frame->view_id; +#endif + + fs_top->frame_poc = frame->frame_poc; + + fs_top->bottom_poc = fs_btm->bottom_poc = frame->bottom_poc; + fs_top->top_poc = fs_btm->top_poc = frame->top_poc; + fs_btm->frame_poc = frame->frame_poc; + + fs_top->used_for_reference = fs_btm->used_for_reference + = frame->used_for_reference; + fs_top->is_long_term = fs_btm->is_long_term + = frame->is_long_term; + fs->long_term_frame_idx = fs_top->long_term_frame_idx + = fs_btm->long_term_frame_idx + = frame->long_term_frame_idx; + + fs_top->coded_frame = fs_btm->coded_frame = 1; + fs_top->mb_aff_frame_flag = fs_btm->mb_aff_frame_flag + = frame->mb_aff_frame_flag; + + frame->top_field = fs_top; + frame->bottom_field = fs_btm; + frame->frame = frame; + fs_top->bottom_field = fs_btm; + fs_top->frame = frame; + fs_top->top_field = fs_top; + fs_btm->top_field = fs_top; + fs_btm->frame = frame; + fs_btm->bottom_field = fs_btm; + +#if (MVC_EXTENSION_ENABLE) + fs_top->view_id = fs_btm->view_id = fs->view_id; + fs_top->inter_view_flag = fs->inter_view_flag[0]; + fs_btm->inter_view_flag = fs->inter_view_flag[1]; +#endif + + fs_top->chroma_format_idc = fs_btm->chroma_format_idc = + frame->chroma_format_idc; + fs_top->iCodingType = fs_btm->iCodingType = frame->iCodingType; + } else { + fs->top_field = NULL; + fs->bottom_field = NULL; + frame->top_field = NULL; + frame->bottom_field = NULL; + frame->frame = frame; + } + +} + + +static void dpb_combine_field(struct h264_dpb_stru *p_H264_Dpb, + struct FrameStore *fs) +{ + + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s\n", __func__); + + if (!fs->frame) { + fs->frame = get_new_pic(p_H264_Dpb, + FRAME, + /* fs->top_field->size_x, fs->top_field->size_y*2, + *fs->top_field->size_x_cr, fs->top_field->size_y_cr*2, + */ + 1); + } + if (!fs->frame) + return; +#if 1 +/* rain */ + fs->frame->buf_spec_num = fs->top_field->buf_spec_num; + fs->frame->colocated_buf_index = fs->top_field->colocated_buf_index; + fs->frame->data_flag = fs->top_field->data_flag; + fs->frame->slice_type = fs->top_field->slice_type; + if (fs->bottom_field) + fs->frame->data_flag |= (fs->bottom_field->data_flag & 0xf0); +#endif + + if (fs->bottom_field) { + fs->poc = fs->frame->poc = fs->frame->frame_poc = imin( + fs->top_field->poc, fs->bottom_field->poc); + + fs->bottom_field->frame_poc = fs->top_field->frame_poc = fs->frame->poc; + + fs->bottom_field->top_poc = fs->frame->top_poc = fs->top_field->poc; + fs->top_field->bottom_poc = fs->frame->bottom_poc = + fs->bottom_field->poc; + + fs->frame->used_for_reference = (fs->top_field->used_for_reference && + fs->bottom_field->used_for_reference); + fs->frame->is_long_term = (fs->top_field->is_long_term && + fs->bottom_field->is_long_term); + } + + if (fs->frame->is_long_term) + fs->frame->long_term_frame_idx = fs->long_term_frame_idx; + + fs->frame->top_field = fs->top_field; + if (fs->bottom_field) + fs->frame->bottom_field = fs->bottom_field; + fs->frame->frame = fs->frame; + + fs->frame->coded_frame = 0; + + fs->frame->chroma_format_idc = fs->top_field->chroma_format_idc; + fs->frame->frame_cropping_flag = fs->top_field->frame_cropping_flag; + if (fs->frame->frame_cropping_flag) { + fs->frame->frame_crop_top_offset = + fs->top_field->frame_crop_top_offset; + fs->frame->frame_crop_bottom_offset = + fs->top_field->frame_crop_bottom_offset; + fs->frame->frame_crop_left_offset = + fs->top_field->frame_crop_left_offset; + fs->frame->frame_crop_right_offset = + fs->top_field->frame_crop_right_offset; + } + if (fs->bottom_field) { + fs->top_field->frame = fs->bottom_field->frame = fs->frame; + fs->top_field->top_field = fs->top_field; + fs->top_field->bottom_field = fs->bottom_field; + fs->bottom_field->top_field = fs->top_field; + fs->bottom_field->bottom_field = fs->bottom_field; + } + + /**/ +#if (MVC_EXTENSION_ENABLE) + fs->frame->view_id = fs->view_id; +#endif + fs->frame->iCodingType = fs->top_field->iCodingType; + if (fs->bottom_field && fs->top_field->poc < fs->bottom_field->poc) { + fs->pts = fs->top_field->pts; + fs->pts64 = fs->top_field->pts64; + /*SWPL-7105 fix */ + if ((fs->frame->slice_type == B_SLICE) + && (!fs->bottom_field->pts) &&(!fs->bottom_field->pts64)) { + fs->pts = 0; + fs->pts64 = 0; + } + fs->offset_delimiter = fs->top_field->offset_delimiter; + fs->decoded_frame_size = fs->top_field->pic_size + fs->bottom_field->pic_size; + } else if (fs->bottom_field) { + fs->pts = fs->bottom_field->pts; + fs->pts64 = fs->bottom_field->pts64; + fs->offset_delimiter = fs->bottom_field->offset_delimiter; + fs->decoded_frame_size = fs->top_field->pic_size + fs->bottom_field->pic_size; + } + /* FIELD_CODING ;*/ +} + +static void calculate_frame_no(struct VideoParameters *p_Vid, + struct StorablePicture *p) +{ +#if 0 +/* ??? */ + InputParameters *p_Inp = p_Vid->p_Inp; + /* calculate frame number */ + int psnrPOC = p_Vid->active_sps->mb_adaptive_frame_field_flag ? + p->poc / (p_Inp->poc_scale) : p->poc / (p_Inp->poc_scale); + + if (psnrPOC == 0) { /* && p_Vid->psnr_number) */ + p_Vid->idr_psnr_number = + p_Vid->g_nFrame * p_Vid->ref_poc_gap / (p_Inp->poc_scale); + } + p_Vid->psnr_number = imax(p_Vid->psnr_number, + p_Vid->idr_psnr_number + psnrPOC); + + p_Vid->frame_no = p_Vid->idr_psnr_number + psnrPOC; +#endif +} + +static void insert_picture_in_dpb(struct h264_dpb_stru *p_H264_Dpb, + struct FrameStore *fs, + struct StorablePicture *p, + unsigned char data_flag) +{ + struct vdec_frames_s *mvfrm = p_H264_Dpb->vdec->mvfrm; + struct VideoParameters *p_Vid = &p_H264_Dpb->mVideo; + /* InputParameters *p_Inp = p_Vid->p_Inp; + * dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + * "insert (%s) pic with frame_num #%d, poc %d\n", + * (p->structure == FRAME)?"FRAME": + * (p->structure == TOP_FIELD)?"TOP_FIELD": + * "BOTTOM_FIELD", p->pic_num, p->poc); + * assert (p!=NULL); + * assert (fs!=NULL); + */ + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s %p %p\n", __func__, fs, p); + p_H264_Dpb->dpb_frame_count++; + fs->dpb_frame_count = p_H264_Dpb->dpb_frame_count; +#if 1 +/* rain */ +/* p->buf_spec_num = fs->index; */ + p->data_flag = data_flag; + fs->data_flag |= data_flag; + fs->buf_spec_num = p->buf_spec_num; + fs->colocated_buf_index = p->colocated_buf_index; +#endif + p->slice_type = p_H264_Dpb->mSlice.slice_type; + switch (p->structure) { + case FRAME: + fs->frame = p; + fs->is_used = 3; + fs->slice_type = p->slice_type; + fs->frame_size = p->frame_size; + fs->offset_delimiter = p->offset_delimiter; + fs->decoded_frame_size = p->pic_size; + if (p->used_for_reference) { + fs->is_reference = 3; + fs->is_orig_reference = 3; + if (p->is_long_term) { + fs->is_long_term = 3; + fs->long_term_frame_idx = + p->long_term_frame_idx; + } + } + fs->pts = p->pts; + fs->pts64 = p->pts64; + fs->layer_id = p->layer_id; +#if (MVC_EXTENSION_ENABLE) + fs->view_id = p->view_id; + fs->inter_view_flag[0] = fs->inter_view_flag[1] = + p->inter_view_flag; + fs->anchor_pic_flag[0] = fs->anchor_pic_flag[1] = + p->anchor_pic_flag; +#endif + /* generate field views */ + /* return; */ + dpb_split_field(p_H264_Dpb, fs); + /* return; */ + break; + case TOP_FIELD: + fs->top_field = p; + fs->is_used |= 1; + fs->layer_id = p->layer_id; + if (fs->frame_size == 0) { + fs->slice_type = p->slice_type; +// fs->pts = p->pts; +// fs->pts64 = p->pts64; + } + fs->frame_size += p->frame_size; +#if (MVC_EXTENSION_ENABLE) + fs->view_id = p->view_id; + fs->inter_view_flag[0] = p->inter_view_flag; + fs->anchor_pic_flag[0] = p->anchor_pic_flag; +#endif + if (p->used_for_reference) { + fs->is_reference |= 1; + fs->is_orig_reference |= 1; + if (p->is_long_term) { + fs->is_long_term |= 1; + fs->long_term_frame_idx = + p->long_term_frame_idx; + } + } + if (fs->is_used == 3) { + /* generate frame view */ + dpb_combine_field(p_H264_Dpb, fs); + } else { + fs->poc = p->poc; + } + gen_field_ref_ids(p_Vid, p); + break; + case BOTTOM_FIELD: + fs->bottom_field = p; + fs->is_used |= 2; + fs->layer_id = p->layer_id; + if (fs->frame_size == 0) { + fs->slice_type = p->slice_type; +// fs->pts = p->pts; +// fs->pts64 = p->pts64; + } + fs->frame_size += p->frame_size; +#if (MVC_EXTENSION_ENABLE) + fs->view_id = p->view_id; + fs->inter_view_flag[1] = p->inter_view_flag; + fs->anchor_pic_flag[1] = p->anchor_pic_flag; +#endif + if (p->used_for_reference) { + fs->is_reference |= 2; + fs->is_orig_reference |= 2; + if (p->is_long_term) { + fs->is_long_term |= 2; + fs->long_term_frame_idx = + p->long_term_frame_idx; + } + } + if (fs->is_used == 3) { + /* generate frame view */ + dpb_combine_field(p_H264_Dpb, fs); + } else { + fs->poc = p->poc; + } + gen_field_ref_ids(p_Vid, p); + break; + } + fs->frame_num = p->pic_num; + fs->recovery_frame = p->recovery_frame; + + fs->is_output = p->is_output; + fs->pre_output = p->pre_output; + + /* picture qos infomation*/ + fs->max_mv = p->max_mv; + fs->avg_mv = p->avg_mv; + fs->min_mv = p->min_mv; + + fs->max_qp = p->max_qp; + fs->avg_qp = p->avg_qp; + fs->min_qp = p->min_qp; + + fs->max_skip = p->max_skip; + fs->avg_skip = p->avg_skip; + fs->min_skip = p->min_skip; + + if (fs->is_used == 3) { + calculate_frame_no(p_Vid, p); +#if 0 +/* ??? */ + if (-1 != p_Vid->p_ref && !p_Inp->silent) + find_snr(p_Vid, fs->frame, &p_Vid->p_ref); +#endif + //fs->pts = p->pts; + //fs->pts64 = p->pts64; + } + if ((fs->frame != NULL) && + ((fs->bottom_field != NULL) || (fs->top_field != NULL))) { + fs->last_field_timestamp = fs->timestamp; + fs->timestamp = p->timestamp; + } else { + fs->timestamp = p->timestamp; + } + if (mvfrm) { + fs->frame_size2 = mvfrm->frame_size; + fs->hw_decode_time = mvfrm->hw_decode_time; + } +} + +void reset_frame_store(struct h264_dpb_stru *p_H264_Dpb, + struct FrameStore *f) +{ + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s\n", __func__); + + if (f) { + if (f->frame) { + free_picture(p_H264_Dpb, f->frame); + f->frame = NULL; + } + if (f->top_field) { + free_picture(p_H264_Dpb, f->top_field); + f->top_field = NULL; + } + if (f->bottom_field) { + free_picture(p_H264_Dpb, f->bottom_field); + f->bottom_field = NULL; + } + + /**/ + f->is_used = 0; + f->is_reference = 0; + f->is_long_term = 0; + f->is_orig_reference = 0; + + f->is_output = 0; + f->pre_output = 0; + f->show_frame = false; + + f->frame = NULL; + f->top_field = NULL; + f->bottom_field = NULL; + + /* free(f); */ + } +} + +void unmark_for_reference(struct DecodedPictureBuffer *p_Dpb, + struct FrameStore *fs) +{ + struct h264_dpb_stru *p_H264_Dpb = container_of(p_Dpb, + struct h264_dpb_stru, mDPB); + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s %p %p %p %p\n", __func__, + fs, fs->frame, fs->top_field, fs->bottom_field); + /* return; */ + if (fs->is_used & 1) { + if (fs->top_field) + fs->top_field->used_for_reference = 0; + } + if (fs->is_used & 2) { + if (fs->bottom_field) + fs->bottom_field->used_for_reference = 0; + } + if (fs->is_used == 3) { + if (fs->top_field && fs->bottom_field) { + fs->top_field->used_for_reference = 0; + fs->bottom_field->used_for_reference = 0; + } + fs->frame->used_for_reference = 0; + } + + fs->is_reference = 0; + +} + +static void unmark_for_long_term_reference(struct FrameStore *fs) +{ + if (fs->is_used & 1) { + if (fs->top_field) { + fs->top_field->used_for_reference = 0; + fs->top_field->is_long_term = 0; + } + } + if (fs->is_used & 2) { + if (fs->bottom_field) { + fs->bottom_field->used_for_reference = 0; + fs->bottom_field->is_long_term = 0; + } + } + if (fs->is_used == 3) { + if (fs->top_field && fs->bottom_field) { + fs->top_field->used_for_reference = 0; + fs->top_field->is_long_term = 0; + fs->bottom_field->used_for_reference = 0; + fs->bottom_field->is_long_term = 0; + } + fs->frame->used_for_reference = 0; + fs->frame->is_long_term = 0; + } + + fs->is_reference = 0; + fs->is_long_term = 0; +} + +int get_long_term_flag_by_buf_spec_num(struct h264_dpb_stru *p_H264_Dpb, + int buf_spec_num) +{ + struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; + unsigned int i; + + for (i = 0; i < p_Dpb->used_size; i++) { + if (p_Dpb->fs[i]->buf_spec_num == buf_spec_num) + return p_Dpb->fs[i]->is_long_term; + } + return -1; +} + +static void update_pic_num(struct h264_dpb_stru *p_H264_Dpb) +{ + unsigned int i; + struct Slice *currSlice = &p_H264_Dpb->mSlice; + struct VideoParameters *p_Vid = currSlice->p_Vid; + struct DecodedPictureBuffer *p_Dpb = currSlice->p_Dpb; + struct SPSParameters *active_sps = p_Vid->active_sps; + int add_top = 0, add_bottom = 0; + int max_frame_num = 1 << (active_sps->log2_max_frame_num_minus4 + 4); + + if (currSlice->structure == FRAME) { + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i] == NULL || + p_Dpb->fs_ref[i]->frame == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if (p_Dpb->fs_ref[i]->is_used == 3) { + if ((p_Dpb->fs_ref[i]->frame-> + used_for_reference) && + (!p_Dpb->fs_ref[i]->frame-> + is_long_term)) { + if (p_Dpb->fs_ref[i]->frame_num > + currSlice->frame_num) { + p_Dpb->fs_ref[i]-> + frame_num_wrap = + p_Dpb->fs_ref[i]->frame_num + - max_frame_num; + } else { + p_Dpb->fs_ref[i]-> + frame_num_wrap = + p_Dpb->fs_ref[i]->frame_num; + } + p_Dpb->fs_ref[i]->frame->pic_num = + p_Dpb->fs_ref[i]->frame_num_wrap; + } + } + } + /* update long_term_pic_num */ + for (i = 0; i < p_Dpb->ltref_frames_in_buffer; i++) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ltref[i] == NULL || + p_Dpb->fs_ltref[i]->frame == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if (p_Dpb->fs_ltref[i]->is_used == 3) { + if (p_Dpb->fs_ltref[i]->frame->is_long_term) { + p_Dpb->fs_ltref[i]->frame-> + long_term_pic_num = + p_Dpb->fs_ltref[i]->frame-> + long_term_frame_idx; + } + } + } + } else { + if (currSlice->structure == TOP_FIELD) { + add_top = 1; + add_bottom = 0; + } else { + add_top = 0; + add_bottom = 1; + } + + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i] == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if (p_Dpb->fs_ref[i]->is_reference) { + if (p_Dpb->fs_ref[i]->frame_num > currSlice-> + frame_num) { + p_Dpb->fs_ref[i]->frame_num_wrap = + p_Dpb->fs_ref[i]->frame_num - + max_frame_num; + } else { + p_Dpb->fs_ref[i]->frame_num_wrap = + p_Dpb->fs_ref[i]->frame_num; + } + if (p_Dpb->fs_ref[i]->is_reference & 1) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i]->top_field + == NULL) { + p_H264_Dpb->dpb_error_flag = + __LINE__; + continue; + } +#endif + p_Dpb->fs_ref[i]->top_field-> + pic_num = (2 * p_Dpb->fs_ref[i]-> + frame_num_wrap) + add_top; + } + if (p_Dpb->fs_ref[i]->is_reference & 2) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i]->bottom_field + == NULL) { + p_H264_Dpb->dpb_error_flag = + __LINE__; + continue; + } +#endif + p_Dpb->fs_ref[i]->bottom_field-> + pic_num = (2 * p_Dpb->fs_ref[i]-> + frame_num_wrap) + add_bottom; + } + } + } + /* update long_term_pic_num */ + for (i = 0; i < p_Dpb->ltref_frames_in_buffer; i++) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ltref[i] == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if (p_Dpb->fs_ltref[i]->is_long_term & 1) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ltref[i]->top_field == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + p_Dpb->fs_ltref[i]->top_field-> + long_term_pic_num = 2 * + p_Dpb->fs_ltref[i]->top_field-> + long_term_frame_idx + add_top; + } + if (p_Dpb->fs_ltref[i]->is_long_term & 2) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ltref[i]->bottom_field == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + p_Dpb->fs_ltref[i]->bottom_field-> + long_term_pic_num = 2 * + p_Dpb->fs_ltref[i]->bottom_field-> + long_term_frame_idx + add_bottom; + } + } + } +} + +static void remove_frame_from_dpb(struct h264_dpb_stru *p_H264_Dpb, int pos) +{ + struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; + struct FrameStore *fs = p_Dpb->fs[pos]; + struct FrameStore *tmp; + unsigned int i; + + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s pos %d %p\n", __func__, pos, fs); + + /* dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + * "remove frame with frame_num #%d\n", fs->frame_num); + */ + switch (fs->is_used) { + case 3: + free_picture(p_H264_Dpb, fs->frame); + free_picture(p_H264_Dpb, fs->top_field); + free_picture(p_H264_Dpb, fs->bottom_field); + fs->frame = NULL; + fs->top_field = NULL; + fs->bottom_field = NULL; + break; + case 2: + free_picture(p_H264_Dpb, fs->bottom_field); + fs->bottom_field = NULL; + break; + case 1: + free_picture(p_H264_Dpb, fs->top_field); + fs->top_field = NULL; + break; + case 0: + break; + default: + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "invalid frame store type %x", 500); + } + fs->data_flag = 0; + fs->is_used = 0; + fs->is_long_term = 0; + fs->is_reference = 0; + fs->is_orig_reference = 0; + fs->frame_size = 0; + /* move empty framestore to end of buffer */ + tmp = p_Dpb->fs[pos]; + + for (i = pos; i < p_Dpb->used_size - 1; i++) + p_Dpb->fs[i] = p_Dpb->fs[i + 1]; + p_Dpb->fs[p_Dpb->used_size - 1] = tmp; + + if (p_Dpb->used_size) + p_Dpb->used_size--; +} + +int is_used_for_reference(struct FrameStore *fs) +{ + if (fs->is_reference) + return 1; + + if (fs->is_used == 3) { /* frame */ + if (fs->frame->used_for_reference) + return 1; + } + + if (fs->is_used & 1) { /* top field */ + if (fs->top_field) { + if (fs->top_field->used_for_reference) + return 1; + } + } + + if (fs->is_used & 2) { /* bottom field */ + if (fs->bottom_field) { + if (fs->bottom_field->used_for_reference) + return 1; + } + } + return 0; +} + +static int remove_unused_frame_from_dpb(struct h264_dpb_stru *p_H264_Dpb) +{ + unsigned int i; + struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; + /* check for frames that were already output and no longer + * used for reference + */ + for (i = 0; i < p_Dpb->used_size; i++) { + if ((!is_used_for_reference(p_Dpb->fs[i])) && + (p_Dpb->fs[i]->colocated_buf_index >= 0)) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "release_colocate_buf[%d] for fs[%d]\n", + p_Dpb->fs[i]->colocated_buf_index, i); + + release_colocate_buf(p_H264_Dpb, + p_Dpb->fs[i]->colocated_buf_index); /* rain */ + p_Dpb->fs[i]->colocated_buf_index = -1; + } + } + + for (i = 0; i < p_Dpb->used_size; i++) { + if (p_Dpb->fs[i]->is_output && + (!is_used_for_reference(p_Dpb->fs[i]))) { + release_buf_spec_num(p_H264_Dpb->vdec, + p_Dpb->fs[i]->buf_spec_num); + p_Dpb->fs[i]->buf_spec_num = -1; + remove_frame_from_dpb(p_H264_Dpb, i); + + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "%s[%d]\n", + __func__, i); + + return 1; + } + } + return 0; +} + +static int unmark_one_error_out_frame(struct h264_dpb_stru *p_H264_Dpb) +{ + int ret = 0; + unsigned i; + struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; + + for (i = 0; i < p_Dpb->used_size; i++) { + if (p_Dpb->fs[i]->is_output && + ((p_Dpb->fs[i]->data_flag & ERROR_FLAG) || + (p_Dpb->fs[i]->data_flag & NULL_FLAG)) + ) { + unmark_for_reference(p_Dpb, p_Dpb->fs[i]); + + ret = 1; + break; + } + } + return ret; +} + +static int unmark_one_out_frame(struct h264_dpb_stru *p_H264_Dpb) +{ + int ret = 0; + unsigned i; + struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; + + for (i = 0; i < p_Dpb->used_size; i++) { + if (p_Dpb->fs[i]->is_output) { + unmark_for_reference(p_Dpb, p_Dpb->fs[i]); + + ret = 1; + } + } + return ret; +} +/* + force_flag, + 1, remove one error buf (is_out is 1) if there is no un-used buf + 2, remove one buf (is_out is 1) if there is no un-used buf +*/ +void bufmgr_h264_remove_unused_frame(struct h264_dpb_stru *p_H264_Dpb, + u8 force_flag) +{ + struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; + int ret = 0; + unsigned char removed_flag = 0; + do { + ret = remove_unused_frame_from_dpb(p_H264_Dpb); + if (ret != 0) + removed_flag = 1; + } while (ret != 0); + if (removed_flag) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "%s\r\n", __func__); + dump_dpb(p_Dpb, 0); + } else if (force_flag == 2) { + if (unmark_one_out_frame(p_H264_Dpb)) { + dpb_print(p_H264_Dpb->decoder_index, + 0, "%s, Warnning, force unmark one frame\r\n", + __func__); + update_ref_list(p_Dpb); + remove_unused_frame_from_dpb(p_H264_Dpb); + dump_dpb(p_Dpb, 0); + } + } else if (force_flag == 1) { + if (unmark_one_error_out_frame(p_H264_Dpb)) { + dpb_print(p_H264_Dpb->decoder_index, + 0, "%s, unmark error frame\r\n", + __func__); + update_ref_list(p_Dpb); + remove_unused_frame_from_dpb(p_H264_Dpb); + dump_dpb(p_Dpb, 0); + } + } +} + +#ifdef OUTPUT_BUFFER_IN_C +int is_there_unused_frame_from_dpb(struct DecodedPictureBuffer *p_Dpb) +{ + unsigned int i; + + /* check for frames that were already output and no longer + * used for reference + */ + for (i = 0; i < p_Dpb->used_size; i++) { + if (p_Dpb->fs[i]->is_output && + (!is_used_for_reference(p_Dpb->fs[i]))) { + return 1; + } + } + return 0; +} +#endif + +static void get_smallest_poc(struct DecodedPictureBuffer *p_Dpb, int *poc, + int *pos) +{ + unsigned int i; + unsigned long flags; + struct h264_dpb_stru *p_H264_Dpb = container_of(p_Dpb, + struct h264_dpb_stru, mDPB); + struct vdec_s *vdec= (struct vdec_s *)p_H264_Dpb->vdec; + void *p = vh264_get_bufspec_lock(vdec); + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "%s\n", __func__); + if (p_Dpb->used_size < 1) { + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "Cannot determine smallest POC, DPB empty. %d\n", + 150); + } + + *pos = -1; + *poc = INT_MAX; + if (p == NULL) + return; + spin_lock_irqsave(p, flags); + for (i = 0; i < p_Dpb->used_size; i++) { +#ifdef OUTPUT_BUFFER_IN_C + /* rain */ + if ((*poc > p_Dpb->fs[i]->poc) && + (!p_Dpb->fs[i]->is_output) && + (!p_Dpb->fs[i]->pre_output)) { +#else + if ((*poc > p_Dpb->fs[i]->poc) && (!p_Dpb->fs[i]->is_output)) { +#endif + *poc = p_Dpb->fs[i]->poc; + *pos = i; + } + } + spin_unlock_irqrestore(p, flags); +} + +int output_frames(struct h264_dpb_stru *p_H264_Dpb, unsigned char flush_flag) +{ + int poc, pos; + struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; + int i; + int none_displayed_num = 0; + unsigned char fast_output_flag = 0; + + /* + * When the sei data(dv data) after the PIC done and no flush, + * it is necessary to output a frame of data until + * the number of frames not displayed is greater than the reorder. + */ + if ((p_H264_Dpb->wait_aux_data_flag) && (!flush_flag)) { + int no_output_num = 0; + + for (i = 0; i < p_Dpb->used_size; i++) { + if ((!p_Dpb->fs[i]->is_output) && + (!p_Dpb->fs[i]->pre_output) && + ((p_Dpb->fs[i]->is_used == 3) || + (p_Dpb->fs[i]->data_flag & ERROR_FLAG))) + no_output_num++; + } + + if (no_output_num <= p_H264_Dpb->reorder_output) + return 0; + } + + if (!flush_flag) { + for (i = 0; i < p_Dpb->used_size; i++) { + if ((!p_Dpb->fs[i]->is_output) && + (!p_Dpb->fs[i]->pre_output) &&((p_Dpb->fs[i]->is_used == 3 + ||p_Dpb->fs[i]->data_flag & ERROR_FLAG ))) { + none_displayed_num++; + if ((p_H264_Dpb->first_insert_frame == FirstInsertFrm_IDLE || + p_H264_Dpb->first_insert_frame == FirstInsertFrm_RESET) + && (p_Dpb->fs[i]->is_used == 3) + && (p_Dpb->last_output_poc == INT_MIN)) { + if (p_H264_Dpb->first_insert_frame == FirstInsertFrm_IDLE) + fast_output_flag = 1; + p_H264_Dpb->first_insert_frame = FirstInsertFrm_OUT; + p_H264_Dpb->first_output_poc = p_Dpb->fs[i]->poc; + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s first insert frame i %d poc %d frame_num %x\n", + __func__, i, p_Dpb->fs[i]->poc, p_Dpb->fs[i]->frame_num); + } + + /*check poc even/odd*/ + if (p_H264_Dpb->poc_even_odd_flag == 0 && + p_H264_Dpb->decode_pic_count >= 3) + p_H264_Dpb->poc_even_odd_flag = 2; + if (p_Dpb->fs[i]->poc & 0x1) + p_H264_Dpb->poc_even_odd_flag = 1; + /**/ + + if ((p_H264_Dpb->fast_output_enable & 0x1) && + (p_Dpb->fs[i]->data_flag & IDR_FLAG)) + fast_output_flag = 1; + if ((p_H264_Dpb->fast_output_enable & 0x2) && + ((p_Dpb->fs[i]->poc - + p_Dpb->last_output_poc) + == 1)) + fast_output_flag = 1; + if ((p_H264_Dpb->fast_output_enable & 0x4) && + (p_H264_Dpb->poc_even_odd_flag == 2) && + (p_Dpb->fs[i]->is_used == 3) && + ((p_Dpb->fs[i]->poc - + p_Dpb->last_output_poc) + == 2)) + fast_output_flag = 1; + } + } + if (fast_output_flag) + ; + else if (none_displayed_num < + p_H264_Dpb->reorder_output) + return 0; + } + + get_smallest_poc(p_Dpb, &poc, &pos); + + if (pos == -1) + return 0; +#if 0 + if (is_used_for_reference(p_Dpb->fs[pos])) + return 0; +#endif + if (p_H264_Dpb->first_insert_frame == FirstInsertFrm_OUT) { + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s pos %d pos->poc %d first_output_poc %d \n", + __func__, pos, p_Dpb->fs[pos]->poc, p_H264_Dpb->first_output_poc); + + if (p_Dpb->fs[pos]->poc < p_H264_Dpb->first_output_poc) + p_Dpb->fs[pos]->data_flag |= NODISP_FLAG; + else if (p_Dpb->last_output_poc != INT_MIN) + p_H264_Dpb->first_insert_frame = FirstInsertFrm_SKIPDONE; + + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s first_insert_frame %d \n", __func__, p_H264_Dpb->first_insert_frame); + } + if (prepare_display_buf(p_H264_Dpb->vdec, p_Dpb->fs[pos]) >= 0) { + if (!p_H264_Dpb->without_display_mode && + p_Dpb->fs[pos]->show_frame != false) + p_Dpb->fs[pos]->pre_output = 1; + } else { + if (h264_debug_flag & PRINT_FLAG_DPB_DETAIL) { + dpb_print(p_H264_Dpb->decoder_index, 0, + "%s[%d] poc:%d last_output_poc:%d poc_even_odd_flag:%d\n", + __func__, pos, poc, + p_Dpb->last_output_poc, + p_H264_Dpb->poc_even_odd_flag); + dump_dpb(p_Dpb, 1); + } + return 0; + } + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s[%d] poc %d last_output_poc %d poc_even_odd_flag %d\n", + __func__, pos, poc, + p_Dpb->last_output_poc, + p_H264_Dpb->poc_even_odd_flag); + + p_Dpb->last_output_poc = poc; + return 1; + +} + + +void flush_dpb(struct h264_dpb_stru *p_H264_Dpb) +{ + /* struct VideoParameters *p_Vid = p_Dpb->p_Vid; */ + struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; + unsigned int i; + + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s\n", __func__); + + /* diagnostics */ + /* dpb_print(p_H264_Dpb->decoder_index, + *PRINT_FLAG_DPB_DETAIL, + *"Flush remaining frames from the dpb." + *"p_Dpb->size = %d, p_Dpb->used_size = %d\n", + *p_Dpb->size, p_Dpb->used_size); + */ + + if (!p_Dpb->init_done) + return; +/* if(p_Vid->conceal_mode == 0) */ +#if 0 +/* ??? */ + if (p_Vid->conceal_mode != 0) + conceal_non_ref_pics(p_Dpb, 0); +#endif + /* mark all frames unused */ + for (i = 0; i < p_Dpb->used_size; i++) { +#if MVC_EXTENSION_ENABLE + assert(p_Dpb->fs[i]->view_id == p_Dpb->layer_id); +#endif + unmark_for_reference(p_Dpb, p_Dpb->fs[i]); + + } + + while (remove_unused_frame_from_dpb(p_H264_Dpb)) + ; + + /* output frames in POC order */ + while (output_frames(p_H264_Dpb, 1)) + ; + + + p_Dpb->last_output_poc = INT_MIN; +} + +static int is_short_term_reference(struct DecodedPictureBuffer *p_Dpb, + struct FrameStore *fs) +{ + struct h264_dpb_stru *p_H264_Dpb = container_of(p_Dpb, + struct h264_dpb_stru, mDPB); + if (fs->is_used == 3) { /* frame */ + if ((fs->frame->used_for_reference) && + (!fs->frame->is_long_term)) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "[[%s 1]]", + __func__); + return 1; + } + } + + if (fs->is_used & 1) { /* top field */ + if (fs->top_field) { + if ((fs->top_field->used_for_reference) && + (!fs->top_field->is_long_term)) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "[[%s 2]]", + __func__); + return 1; + } + } + } + + if (fs->is_used & 2) { /* bottom field */ + if (fs->bottom_field) { + if ((fs->bottom_field->used_for_reference) && + (!fs->bottom_field->is_long_term)) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "[[%s 3]]", + __func__); + return 1; + } + } + } + return 0; +} + +static int is_long_term_reference(struct FrameStore *fs) +{ + + if (fs->is_used == 3) { /* frame */ + if ((fs->frame->used_for_reference) && + (fs->frame->is_long_term)) { + return 1; + } + } + + if (fs->is_used & 1) { /* top field */ + if (fs->top_field) { + if ((fs->top_field->used_for_reference) && + (fs->top_field->is_long_term)) { + return 1; + } + } + } + + if (fs->is_used & 2) { /* bottom field */ + if (fs->bottom_field) { + if ((fs->bottom_field->used_for_reference) && + (fs->bottom_field->is_long_term)) { + return 1; + } + } + } + return 0; +} + +void update_ref_list(struct DecodedPictureBuffer *p_Dpb) +{ + unsigned int i, j; + + struct h264_dpb_stru *p_H264_Dpb = container_of(p_Dpb, + struct h264_dpb_stru, mDPB); + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s (%d, %d)\n", __func__, p_Dpb->size, p_Dpb->used_size); + for (i = 0, j = 0; i < p_Dpb->used_size; i++) { +#if 1 + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "fs[%d]: fs %p frame %p is_reference %d %d %d\n", + i, p_Dpb->fs[i], p_Dpb->fs[i]->frame, + p_Dpb->fs[i]->frame != NULL ? + p_Dpb->fs[i]->frame->used_for_reference : 0, + p_Dpb->fs[i]->top_field != NULL ? + p_Dpb->fs[i]->top_field->used_for_reference : + 0, + p_Dpb->fs[i]->bottom_field != NULL ? + p_Dpb->fs[i]->bottom_field->used_for_reference : 0); +#endif + if (is_short_term_reference(p_Dpb, p_Dpb->fs[i])) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "fs_ref[%d]=fs[%d]: fs %p\n", j, i, p_Dpb->fs[i]); + p_Dpb->fs_ref[j++] = p_Dpb->fs[i]; + } + } + + p_Dpb->ref_frames_in_buffer = j; + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s dpb size is %d, %d\n", __func__, p_Dpb->size, j); + while (j < p_Dpb->size) { + /* dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + *"fs_ref[%d]=null\n", j); + */ + p_Dpb->fs_ref[j++] = NULL; + } +#ifdef ERROR_CHECK + for (i = 0; i < DPB_SIZE_MAX; i++) { + if (p_Dpb->fs_ref[i] == NULL) + p_Dpb->fs_ref[i] = &dummy_fs; + } +#endif +} + +static void update_ltref_list(struct DecodedPictureBuffer *p_Dpb) +{ + unsigned int i, j; + struct h264_dpb_stru *p_H264_Dpb = container_of(p_Dpb, + struct h264_dpb_stru, mDPB); + + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s\n", __func__); + for (i = 0, j = 0; i < p_Dpb->used_size; i++) { + if (is_long_term_reference(p_Dpb->fs[i])) + p_Dpb->fs_ltref[j++] = p_Dpb->fs[i]; + } + + p_Dpb->ltref_frames_in_buffer = j; + + while (j < p_Dpb->size) + p_Dpb->fs_ltref[j++] = NULL; +#ifdef ERROR_CHECK + for (i = 0; i < DPB_SIZE_MAX; i++) { + if (p_Dpb->fs_ltref[i] == NULL) + p_Dpb->fs_ltref[i] = &dummy_fs; + } +#endif +} + +static void idr_memory_management(struct h264_dpb_stru *p_H264_Dpb, + struct StorablePicture *p) +{ + struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; + + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s ref_frames_in_buffer %d ltref_frames_in_buffer %d\n", + __func__, p_Dpb->ref_frames_in_buffer, + p_Dpb->ltref_frames_in_buffer); + + + if (p->no_output_of_prior_pics_flag) { + int i; + for (i = 0; i < p_Dpb->used_size; i++) { + unmark_for_reference(p_Dpb, p_Dpb->fs[i]); + if (p_Dpb->fs[i]->is_long_term) + unmark_for_long_term_reference(p_Dpb->fs[i]); + if (!p_Dpb->fs[i]->is_output && !p_Dpb->fs[i]->pre_output) + set_frame_output_flag(p_H264_Dpb, i); + } +#if 0 + /*???*/ + /* free all stored pictures */ + int i; + + for (i = 0; i < p_Dpb->used_size; i++) { + /* reset all reference settings + * free_frame_store(p_Dpb->fs[i]); + * p_Dpb->fs[i] = alloc_frame_store(); + */ + reset_frame_store(p_H264_Dpb, p_Dpb->fs[i]); /* ??? */ + } + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) + p_Dpb->fs_ref[i] = NULL; + for (i = 0; i < p_Dpb->ltref_frames_in_buffer; i++) + p_Dpb->fs_ltref[i] = NULL; + p_Dpb->used_size = 0; +#endif + } else { + flush_dpb(p_H264_Dpb); + } + p_Dpb->last_picture = NULL; + + update_ref_list(p_Dpb); + update_ltref_list(p_Dpb); + p_Dpb->last_output_poc = INT_MIN; + + if (p->long_term_reference_flag) { + p_Dpb->max_long_term_pic_idx = 0; + p->is_long_term = 1; + p->long_term_frame_idx = 0; + } else { + p_Dpb->max_long_term_pic_idx = -1; + p->is_long_term = 0; + } + +#if (MVC_EXTENSION_ENABLE) + p_Dpb->last_output_view_id = -1; +#endif + +} + +static void sliding_window_memory_management( + struct DecodedPictureBuffer *p_Dpb, + struct StorablePicture *p) +{ + unsigned int i; + struct h264_dpb_stru *p_H264_Dpb = container_of(p_Dpb, + struct h264_dpb_stru, mDPB); + unsigned char slide_flag = 0; + unsigned int sliding_margin = imax( + 1, p_Dpb->num_ref_frames) - p_Dpb->ltref_frames_in_buffer; + /* assert (!p->idr_flag); */ + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s ref_frames_in_buffer %d ltref_frames_in_buffer %d\n", + __func__, p_Dpb->ref_frames_in_buffer, + p_Dpb->ltref_frames_in_buffer); + /* if this is a reference pic with sliding window, + unmark first ref frame */ + if (p_Dpb->ref_frames_in_buffer == sliding_margin) + slide_flag = 1; + /*else if ((h264_error_proc_policy & 0x8) && + (p_Dpb->ref_frames_in_buffer > sliding_margin)) + slide_flag = 1;*/ + + if (slide_flag) { + for (i = 0; i < p_Dpb->used_size; i++) { + if (p_Dpb->fs[i]->is_reference && + (!(p_Dpb->fs[i]->is_long_term))) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "unmark %d\n", i); + unmark_for_reference(p_Dpb, p_Dpb->fs[i]); + update_ref_list(p_Dpb); + break; + } + } + } + + p->is_long_term = 0; +} + +static void check_num_ref(struct DecodedPictureBuffer *p_Dpb) +{ + if ((int)(p_Dpb->ltref_frames_in_buffer + + p_Dpb->ref_frames_in_buffer) > + imax(1, p_Dpb->num_ref_frames)) { + struct h264_dpb_stru *p_H264_Dpb = container_of(p_Dpb, + struct h264_dpb_stru, mDPB); + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "Max. number of reference frames exceeded. Invalid stream. lt %d ref %d mum_ref %d\n", + p_Dpb->ltref_frames_in_buffer, + p_Dpb->ref_frames_in_buffer, + p_Dpb->num_ref_frames); + } +} + +void dump_dpb(struct DecodedPictureBuffer *p_Dpb, u8 force) +{ + unsigned int i; + unsigned char *buf = NULL; + unsigned int buf_size = 512, len = 0; + struct h264_dpb_stru *p_H264_Dpb = + container_of(p_Dpb, struct h264_dpb_stru, mDPB); + +#define DPB_STRCAT(args...) do { \ + len += snprintf(buf + len, \ + buf_size - len, ##args);\ + } while (0) + + if ((h264_debug_flag & PRINT_FLAG_DUMP_DPB) == 0 && + force == 0) + return; + + buf = kzalloc(buf_size, GFP_ATOMIC); + if (buf == NULL) + return; + + for (i = 0; i < p_Dpb->used_size; i++) { + len = 0; + memset(buf, 0, buf_size); + DPB_STRCAT("fn=%d is_used %d ", + p_Dpb->fs[i]->frame_num, + p_Dpb->fs[i]->is_used); + + if (p_Dpb->fs[i]->is_used & 1) { + if (p_Dpb->fs[i]->top_field) + DPB_STRCAT("T: poc=%d pic_num=%d ", + p_Dpb->fs[i]->top_field->poc, + p_Dpb->fs[i]->top_field->pic_num); + else + DPB_STRCAT("T: poc=%d ", + p_Dpb->fs[i]->frame->top_poc); + } + if (p_Dpb->fs[i]->is_used & 2) { + if (p_Dpb->fs[i]->bottom_field) + DPB_STRCAT("B: poc=%d pic_num=%d ", + p_Dpb->fs[i]->bottom_field->poc, + p_Dpb->fs[i]->bottom_field->pic_num); + else + DPB_STRCAT("B: poc=%d ", + p_Dpb->fs[i]->frame->bottom_poc); + } + if (p_Dpb->fs[i]->is_used == 3) { + if (p_Dpb->fs[i]->frame != NULL) + DPB_STRCAT("F: poc=%d pic_num=%d ", + p_Dpb->fs[i]->frame->poc, + p_Dpb->fs[i]->frame->pic_num); + else + DPB_STRCAT("fs[%d] frame is null ", i); + } + DPB_STRCAT("G: poc=%d) ", p_Dpb->fs[i]->poc); + if (p_Dpb->fs[i]->is_reference) + DPB_STRCAT("ref (%d) ", p_Dpb->fs[i]->is_reference); + if (p_Dpb->fs[i]->is_long_term) + DPB_STRCAT("lt_ref (%d) ", p_Dpb->fs[i]->is_reference); + if (p_Dpb->fs[i]->is_output) + DPB_STRCAT("out(displayed) "); + if (p_Dpb->fs[i]->pre_output) + DPB_STRCAT("pre_output(in dispq or displaying) "); + if (p_Dpb->fs[i]->is_used == 3) { + if (p_Dpb->fs[i]->frame != NULL && p_Dpb->fs[i]->frame->non_existing) + DPB_STRCAT("non_existing "); + else + DPB_STRCAT("fs[%d] frame is null ", i); + } + DPB_STRCAT("dpb_frame_count %d ", + p_Dpb->fs[i]->dpb_frame_count); + +#if (MVC_EXTENSION_ENABLE) + if (p_Dpb->fs[i]->is_reference) + DPB_STRCAT("view_id (%d) ", p_Dpb->fs[i]->view_id); +#endif + if (p_Dpb->fs[i]->data_flag) { + DPB_STRCAT("data_flag(0x%x)", + p_Dpb->fs[i]->data_flag); + } + DPB_STRCAT(" bufspec %d\n", + p_Dpb->fs[i]->buf_spec_num); + dpb_print(p_H264_Dpb->decoder_index, 0, "%s", buf); + } + + kfree(buf); +} + +/*! + ************************************************************************ + * \brief + * adaptive memory management + * + ************************************************************************ + */ + +static int get_pic_num_x(struct StorablePicture *p, + int difference_of_pic_nums_minus1) +{ + int currPicNum; + + if (p->structure == FRAME) + currPicNum = p->frame_num; + else + currPicNum = 2 * p->frame_num + 1; + + return currPicNum - (difference_of_pic_nums_minus1 + 1); +} + +/*! + ************************************************************************ + * \brief + * Adaptive Memory Management: Mark short term picture unused + ************************************************************************ + */ +static void mm_unmark_short_term_for_reference(struct DecodedPictureBuffer + *p_Dpb, struct StorablePicture *p, + int difference_of_pic_nums_minus1) +{ + struct h264_dpb_stru *p_H264_Dpb = + container_of(p_Dpb, struct h264_dpb_stru, mDPB); + int picNumX; + + unsigned int i; + + picNumX = get_pic_num_x(p, difference_of_pic_nums_minus1); + + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i] == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if (p->structure == FRAME) { + if ((p_Dpb->fs_ref[i]->is_reference == 3) && + (p_Dpb->fs_ref[i]->is_long_term == 0)) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i]->frame == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if (p_Dpb->fs_ref[i]->frame->pic_num == + picNumX) { + unmark_for_reference(p_Dpb, + p_Dpb->fs_ref[i]); + return; + } + } + } else { + if ((p_Dpb->fs_ref[i]->is_reference & 1) && + (!(p_Dpb->fs_ref[i]->is_long_term & 1))) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i]->top_field == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if (p_Dpb->fs_ref[i]->top_field->pic_num == + picNumX) { + p_Dpb->fs_ref[i]-> + top_field->used_for_reference = 0; + p_Dpb->fs_ref[i]->is_reference &= 2; + if ((p_Dpb->fs_ref[i]->is_used == 3) +#ifdef ERROR_CHECK + && p_Dpb->fs_ref[i]->frame +#endif + ) { + p_Dpb->fs_ref[i]->frame-> + used_for_reference = 0; + } + return; + } + } + if ((p_Dpb->fs_ref[i]->is_reference & 2) && + (!(p_Dpb->fs_ref[i]->is_long_term & 2))) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i]->bottom_field == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if (p_Dpb->fs_ref[i]->bottom_field->pic_num == + picNumX) { + p_Dpb->fs_ref[i]->bottom_field-> + used_for_reference = 0; + p_Dpb->fs_ref[i]->is_reference &= 1; + if ((p_Dpb->fs_ref[i]->is_used == 3) +#ifdef ERROR_CHECK + && p_Dpb->fs_ref[i]->frame +#endif + ) { + p_Dpb->fs_ref[i]->frame-> + used_for_reference = 0; + } + return; + } + } + } + } +} + +/*! + ************************************************************************ + * \brief + * Adaptive Memory Management: Mark long term picture unused + ************************************************************************ + */ +static void mm_unmark_long_term_for_reference(struct DecodedPictureBuffer + *p_Dpb, struct StorablePicture *p, int long_term_pic_num) +{ + unsigned int i; + + for (i = 0; i < p_Dpb->ltref_frames_in_buffer; i++) { + if (p->structure == FRAME) { + if ((p_Dpb->fs_ltref[i]->is_reference == 3) && + (p_Dpb->fs_ltref[i]->is_long_term == 3)) { + if (p_Dpb->fs_ltref[i]->frame-> + long_term_pic_num == + long_term_pic_num) { + unmark_for_long_term_reference( + p_Dpb->fs_ltref[i]); + } + } + } else { + if ((p_Dpb->fs_ltref[i]->is_reference & 1) && + ((p_Dpb->fs_ltref[i]->is_long_term & 1))) { + if (p_Dpb->fs_ltref[i]->top_field-> + long_term_pic_num == + long_term_pic_num) { + p_Dpb->fs_ltref[i]->top_field-> + used_for_reference = 0; + p_Dpb->fs_ltref[i]->top_field-> + is_long_term = 0; + p_Dpb->fs_ltref[i]->is_reference &= 2; + p_Dpb->fs_ltref[i]->is_long_term &= 2; + if (p_Dpb->fs_ltref[i]->is_used == 3) { + p_Dpb->fs_ltref[i]->frame-> + used_for_reference = 0; + p_Dpb->fs_ltref[i]->frame-> + is_long_term = 0; + } + return; + } + } + if ((p_Dpb->fs_ltref[i]->is_reference & 2) && + ((p_Dpb->fs_ltref[i]->is_long_term & 2))) { + if (p_Dpb->fs_ltref[i]->bottom_field-> + long_term_pic_num == + long_term_pic_num) { + p_Dpb->fs_ltref[i]->bottom_field-> + used_for_reference = 0; + p_Dpb->fs_ltref[i]->bottom_field-> + is_long_term = 0; + p_Dpb->fs_ltref[i]->is_reference &= 1; + p_Dpb->fs_ltref[i]->is_long_term &= 1; + if (p_Dpb->fs_ltref[i]->is_used == 3) { + p_Dpb->fs_ltref[i]->frame-> + used_for_reference = 0; + p_Dpb->fs_ltref[i]->frame-> + is_long_term = 0; + } + return; + } + } + } + } +} + + +/*! + ************************************************************************ + * \brief + * Mark a long-term reference frame or complementary + * field pair unused for referemce + ************************************************************************ + */ +static void unmark_long_term_frame_for_reference_by_frame_idx( + struct DecodedPictureBuffer *p_Dpb, int long_term_frame_idx) +{ + unsigned int i; + + for (i = 0; i < p_Dpb->ltref_frames_in_buffer; i++) { + if (p_Dpb->fs_ltref[i]->long_term_frame_idx == + long_term_frame_idx) + unmark_for_long_term_reference(p_Dpb->fs_ltref[i]); + } +} + + +static void unmark1(struct DecodedPictureBuffer *p_Dpb, + unsigned int curr_frame_num, int i) +{ + if (p_Dpb->last_picture) { + /*if ((p_Dpb->last_picture != p_Dpb->fs_ltref[i]) || + p_Dpb->last_picture->frame_num != curr_frame_num) {*/ + unmark_for_long_term_reference(p_Dpb->fs_ltref[i]); + /*} else { + unmark_for_long_term_reference(p_Dpb->fs_ltref[i]); + }*/ + } +} + +static void unmark2(struct DecodedPictureBuffer *p_Dpb, + int curr_pic_num, int i) +{ + if ((p_Dpb->fs_ltref[i]->frame_num) != + (unsigned int)(curr_pic_num >> 1)) + unmark_for_long_term_reference(p_Dpb->fs_ltref[i]); +} + +static void unmark3_top(struct DecodedPictureBuffer *p_Dpb, + unsigned int curr_frame_num, int curr_pic_num, int mark_current, int i) +{ + if (p_Dpb->fs_ltref[i]->is_long_term == 3) { + unmark_for_long_term_reference(p_Dpb->fs_ltref[i]); + } else { + if (p_Dpb->fs_ltref[i]->is_long_term == 1) { + unmark_for_long_term_reference(p_Dpb->fs_ltref[i]); + } else { + if (mark_current) + unmark1(p_Dpb, curr_frame_num, i); + else + unmark2(p_Dpb, curr_pic_num, i); + } + } +} + +static void unmark3_bottom(struct DecodedPictureBuffer *p_Dpb, + unsigned int curr_frame_num, int curr_pic_num, int mark_current, int i) +{ + if (p_Dpb->fs_ltref[i]->is_long_term == 2) { + unmark_for_long_term_reference(p_Dpb->fs_ltref[i]); + } else { + if (mark_current) + unmark1(p_Dpb, curr_frame_num, i); + else + unmark2(p_Dpb, curr_pic_num, i); + } +} + +static void unmark_long_term_field_for_reference_by_frame_idx( + struct DecodedPictureBuffer *p_Dpb, enum PictureStructure structure, + int long_term_frame_idx, int mark_current, unsigned int curr_frame_num, + int curr_pic_num) +{ + struct VideoParameters *p_Vid = p_Dpb->p_Vid; + unsigned int i; + + /* assert(structure!=FRAME); */ + if (curr_pic_num < 0) + curr_pic_num += (2 * p_Vid->max_frame_num); + + for (i = 0; i < p_Dpb->ltref_frames_in_buffer; i++) { + if (p_Dpb->fs_ltref[i]->long_term_frame_idx == + long_term_frame_idx) { + if (structure == TOP_FIELD) + unmark3_top(p_Dpb, curr_frame_num, + curr_pic_num, mark_current, i); + + if (structure == BOTTOM_FIELD) + unmark3_bottom(p_Dpb, curr_frame_num, + curr_pic_num, mark_current, i); + } + } +} + +/*! + ************************************************************************ + * \brief + * mark a picture as long-term reference + ************************************************************************ + */ +static void mark_pic_long_term(struct DecodedPictureBuffer *p_Dpb, + struct StorablePicture *p, + int long_term_frame_idx, int picNumX) +{ + struct h264_dpb_stru *p_H264_Dpb = container_of(p_Dpb, + struct h264_dpb_stru, mDPB); + unsigned int i; + int add_top, add_bottom; + + if (p->structure == FRAME) { + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i] == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if (p_Dpb->fs_ref[i]->is_reference == 3) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i]->frame == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if ((!p_Dpb->fs_ref[i]->frame-> + is_long_term) && + (p_Dpb->fs_ref[i]->frame->pic_num == + picNumX)) { + p_Dpb->fs_ref[i]-> + long_term_frame_idx = + p_Dpb->fs_ref[i]->frame-> + long_term_frame_idx = + long_term_frame_idx; + p_Dpb->fs_ref[i]->frame-> + long_term_pic_num = + long_term_frame_idx; + p_Dpb->fs_ref[i]->frame-> + is_long_term = 1; + + if (p_Dpb->fs_ref[i]->top_field && + p_Dpb->fs_ref[i]->bottom_field) { + p_Dpb->fs_ref[i]->top_field-> + long_term_frame_idx = + p_Dpb->fs_ref[i]-> + bottom_field-> + long_term_frame_idx = + long_term_frame_idx; + p_Dpb->fs_ref[i]->top_field-> + long_term_pic_num = + long_term_frame_idx; + p_Dpb->fs_ref[i]-> + bottom_field-> + long_term_pic_num = + long_term_frame_idx; + + p_Dpb->fs_ref[i]->top_field-> + is_long_term = + p_Dpb->fs_ref[i]-> + bottom_field-> + is_long_term + = 1; + + } + p_Dpb->fs_ref[i]->is_long_term = 3; + return; + } + } + } + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "Warning: reference frame for long term marking not found\n"); + } else { + if (p->structure == TOP_FIELD) { + add_top = 1; + add_bottom = 0; + } else { + add_top = 0; + add_bottom = 1; + } + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i] == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if (p_Dpb->fs_ref[i]->is_reference & 1) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i]->top_field == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if ((!p_Dpb->fs_ref[i]->top_field-> + is_long_term) && + (p_Dpb->fs_ref[i]->top_field->pic_num == + picNumX)) { + if ((p_Dpb->fs_ref[i]-> + is_long_term) && + (p_Dpb->fs_ref[i]-> + long_term_frame_idx != + long_term_frame_idx)) { + dpb_print(p_H264_Dpb-> + decoder_index, + PRINT_FLAG_DPB_DETAIL, + "Warning: assigning long_term_frame_idx different from other field\n"); + } + + p_Dpb->fs_ref[i]-> + long_term_frame_idx = + p_Dpb->fs_ref[i]->top_field-> + long_term_frame_idx + = long_term_frame_idx; + p_Dpb->fs_ref[i]->top_field-> + long_term_pic_num = + 2 * long_term_frame_idx + + add_top; + p_Dpb->fs_ref[i]->top_field-> + is_long_term = 1; + p_Dpb->fs_ref[i]->is_long_term |= 1; + if ((p_Dpb->fs_ref[i]->is_long_term + == 3) +#ifdef ERROR_CHECK + && p_Dpb->fs_ref[i]->frame +#endif + ) { + p_Dpb->fs_ref[i]->frame-> + is_long_term = 1; + p_Dpb->fs_ref[i]->frame-> + long_term_frame_idx = + p_Dpb->fs_ref[i]-> + frame-> + long_term_pic_num = + long_term_frame_idx; + } + return; + } + } + if (p_Dpb->fs_ref[i]->is_reference & 2) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i]->bottom_field == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if ((!p_Dpb->fs_ref[i]->bottom_field-> + is_long_term) && + (p_Dpb->fs_ref[i]->bottom_field->pic_num + == picNumX)) { + if ((p_Dpb->fs_ref[i]-> + is_long_term) && + (p_Dpb->fs_ref[i]-> + long_term_frame_idx != + long_term_frame_idx)) { + dpb_print(p_H264_Dpb-> + decoder_index, + PRINT_FLAG_DPB_DETAIL, + "Warning: assigning long_term_frame_idx different from other field\n"); + } + + p_Dpb->fs_ref[i]-> + long_term_frame_idx = + p_Dpb->fs_ref[i]->bottom_field + ->long_term_frame_idx + = long_term_frame_idx; + p_Dpb->fs_ref[i]->bottom_field-> + long_term_pic_num = 2 * + long_term_frame_idx + + add_bottom; + p_Dpb->fs_ref[i]->bottom_field-> + is_long_term = 1; + p_Dpb->fs_ref[i]->is_long_term |= 2; + if ((p_Dpb->fs_ref[i]-> + is_long_term == 3) +#ifdef ERROR_CHECK + && p_Dpb->fs_ref[i]->frame +#endif + ) { + p_Dpb->fs_ref[i]->frame-> + is_long_term = 1; + p_Dpb->fs_ref[i]->frame-> + long_term_frame_idx = + p_Dpb->fs_ref[i]-> + frame-> + long_term_pic_num = + long_term_frame_idx; + } + return; + } + } + } + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "Warning: reference field for long term marking not found\n"); + } +} + + +/*! + ************************************************************************ + * \brief + * Assign a long term frame index to a short term picture + ************************************************************************ + */ +static void mm_assign_long_term_frame_idx(struct DecodedPictureBuffer *p_Dpb, + struct StorablePicture *p, int difference_of_pic_nums_minus1, + int long_term_frame_idx) +{ + struct h264_dpb_stru *p_H264_Dpb = container_of(p_Dpb, + struct h264_dpb_stru, mDPB); + int picNumX = get_pic_num_x(p, difference_of_pic_nums_minus1); + + /* remove frames/fields with same long_term_frame_idx */ + if (p->structure == FRAME) { + unmark_long_term_frame_for_reference_by_frame_idx(p_Dpb, + long_term_frame_idx); + } else { + unsigned int i; + enum PictureStructure structure = FRAME; + + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i] == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if (p_Dpb->fs_ref[i]->is_reference & 1) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i]->top_field == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if (p_Dpb->fs_ref[i]->top_field-> + pic_num == picNumX) { + structure = TOP_FIELD; + break; + } + } + if (p_Dpb->fs_ref[i]->is_reference & 2) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i]->bottom_field == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if (p_Dpb->fs_ref[i]->bottom_field-> + pic_num == picNumX) { + structure = BOTTOM_FIELD; + break; + } + } + } + if (structure == FRAME) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "field for long term marking not found %d", + 200); + } + + unmark_long_term_field_for_reference_by_frame_idx(p_Dpb, + structure, + long_term_frame_idx, 0, 0, picNumX); + } + + mark_pic_long_term(p_Dpb, p, long_term_frame_idx, picNumX); +} + +/*! + ************************************************************************ + * \brief + * Set new max long_term_frame_idx + ************************************************************************ + */ +static void mm_update_max_long_term_frame_idx(struct DecodedPictureBuffer + *p_Dpb, int max_long_term_frame_idx_plus1) +{ + unsigned int i; + + p_Dpb->max_long_term_pic_idx = max_long_term_frame_idx_plus1 - 1; + + /* check for invalid frames */ + for (i = 0; i < p_Dpb->ltref_frames_in_buffer; i++) { + if (p_Dpb->fs_ltref[i]->long_term_frame_idx > + p_Dpb->max_long_term_pic_idx) { + unmark_for_long_term_reference(p_Dpb->fs_ltref[i]); + } + } +} + + +/*! + ************************************************************************ + * \brief + * Mark all long term reference pictures unused for reference + ************************************************************************ + */ +static void mm_unmark_all_long_term_for_reference(struct DecodedPictureBuffer + *p_Dpb) +{ + mm_update_max_long_term_frame_idx(p_Dpb, 0); +} + +/*! + ************************************************************************ + * \brief + * Mark all short term reference pictures unused for reference + ************************************************************************ + */ +static void mm_unmark_all_short_term_for_reference(struct DecodedPictureBuffer + *p_Dpb) +{ + unsigned int i; + + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) + unmark_for_reference(p_Dpb, p_Dpb->fs_ref[i]); + update_ref_list(p_Dpb); +} + + +/*! + ************************************************************************ + * \brief + * Mark the current picture used for long term reference + ************************************************************************ + */ +static void mm_mark_current_picture_long_term(struct DecodedPictureBuffer + *p_Dpb, struct StorablePicture *p, int long_term_frame_idx) +{ + /* remove long term pictures with same long_term_frame_idx */ + if (p->structure == FRAME) { + unmark_long_term_frame_for_reference_by_frame_idx(p_Dpb, + long_term_frame_idx); + } else { + unmark_long_term_field_for_reference_by_frame_idx(p_Dpb, + p->structure, long_term_frame_idx, + 1, p->pic_num, 0); + } + + p->is_long_term = 1; + p->long_term_frame_idx = long_term_frame_idx; +} + +static void adaptive_memory_management(struct h264_dpb_stru *p_H264_Dpb, + struct StorablePicture *p) +{ + struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; + struct DecRefPicMarking_s *tmp_drpm; + struct VideoParameters *p_Vid = p_Dpb->p_Vid; + + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s\n", __func__); + p_Vid->last_has_mmco_5 = 0; + + /* assert (!p->idr_flag); */ + /* assert (p->adaptive_ref_pic_buffering_flag); */ + + while (p->dec_ref_pic_marking_buffer) { + tmp_drpm = p->dec_ref_pic_marking_buffer; + switch (tmp_drpm->memory_management_control_operation) { + case 0: + if (tmp_drpm->Next != NULL) + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_ERROR, + "error, memory_management_control_operation = 0 not last operation in buffer\n"); + break; + case 1: + mm_unmark_short_term_for_reference(p_Dpb, p, + tmp_drpm->difference_of_pic_nums_minus1); + update_ref_list(p_Dpb); + break; + case 2: + mm_unmark_long_term_for_reference(p_Dpb, p, + tmp_drpm->long_term_pic_num); + update_ltref_list(p_Dpb); + break; + case 3: + mm_assign_long_term_frame_idx(p_Dpb, p, + tmp_drpm->difference_of_pic_nums_minus1, + tmp_drpm->long_term_frame_idx); + update_ref_list(p_Dpb); + update_ltref_list(p_Dpb); + break; + case 4: + mm_update_max_long_term_frame_idx(p_Dpb, + tmp_drpm->max_long_term_frame_idx_plus1); + update_ltref_list(p_Dpb); + break; + case 5: + mm_unmark_all_short_term_for_reference(p_Dpb); + mm_unmark_all_long_term_for_reference(p_Dpb); + p_Vid->last_has_mmco_5 = 1; + break; + case 6: + mm_mark_current_picture_long_term(p_Dpb, p, + tmp_drpm->long_term_frame_idx); + check_num_ref(p_Dpb); + break; + default: + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_ERROR, + "error, invalid memory_management_control_operation in buffer\n"); + } + p->dec_ref_pic_marking_buffer = tmp_drpm->Next; + /* free (tmp_drpm); */ + } + if (p_Vid->last_has_mmco_5) { + p->pic_num = p->frame_num = 0; + + switch (p->structure) { + case TOP_FIELD: { + /* p->poc = p->top_poc = p_Vid->toppoc =0; */ + p->poc = p->top_poc = 0; + break; + } + case BOTTOM_FIELD: { + /* p->poc = p->bottom_poc = p_Vid->bottompoc = 0; */ + p->poc = p->bottom_poc = 0; + break; + } + case FRAME: { + p->top_poc -= p->poc; + p->bottom_poc -= p->poc; + + /* p_Vid->toppoc = p->top_poc; */ + /* p_Vid->bottompoc = p->bottom_poc; */ + + p->poc = imin(p->top_poc, p->bottom_poc); + /* p_Vid->framepoc = p->poc; */ + break; + } + } + /* currSlice->ThisPOC = p->poc; */ +#if (MVC_EXTENSION_ENABLE) + if (p->view_id == 0) { + flush_dpb(p_Vid->p_Dpb_layer[0]); + flush_dpb(p_Vid->p_Dpb_layer[1]); + } else { + flush_dpb(p_Dpb); + } +#else + flush_dpb(p_H264_Dpb); +#endif + } +} + + +int store_picture_in_dpb(struct h264_dpb_stru *p_H264_Dpb, + struct StorablePicture *p, + unsigned char data_flag) +{ + /* struct VideoParameters *p_Vid = p_Dpb->p_Vid; */ + struct VideoParameters *p_Vid = &p_H264_Dpb->mVideo; + struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; + unsigned int i, frame_outside_count = 0; +#if 0 + int poc, pos; +#endif + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s p_Vid %p\n", __func__, p_Vid); + + /* picture error concealment */ + + /* diagnostics */ + /* dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + * "Storing (%s) non-ref pic with frame_num #%d\n", + * (p->type == FRAME)?"FRAME":(p->type == TOP_FIELD)? + * "TOP_FIELD":"BOTTOM_FIELD", p->pic_num); + */ + /* if frame, check for new store, */ + /* assert (p!=NULL); */ + + p_Vid->last_has_mmco_5 = 0; + p_Vid->last_pic_bottom_field = (p->structure == BOTTOM_FIELD); + if (p->idr_flag) { + idr_memory_management(p_H264_Dpb, p); + if (p_H264_Dpb->first_insert_frame == FirstInsertFrm_OUT) + p_H264_Dpb->first_insert_frame = FirstInsertFrm_SKIPDONE; +#if 0 +/* ??? */ + /* picture error concealment */ + memset(p_Vid->pocs_in_dpb, 0, sizeof(int) * 100); +#endif + } else { +#if 1 +/* ??? */ + /* adaptive memory management */ + if (p->used_for_reference && + (p->adaptive_ref_pic_buffering_flag)) + adaptive_memory_management(p_H264_Dpb, p); +#endif + } + + if ((p->structure == TOP_FIELD) || (p->structure == BOTTOM_FIELD)) { + /* check for frame store with same pic_number */ + if (p_Dpb->last_picture) { + if ((int)p_Dpb->last_picture->frame_num == + p->pic_num) { + if (((p->structure == TOP_FIELD) && + (p_Dpb->last_picture->is_used == 2)) || + ((p->structure == BOTTOM_FIELD) && + (p_Dpb->last_picture->is_used == 1))) { + if ((p->used_for_reference && + (p_Dpb->last_picture-> + is_orig_reference != 0)) || + (!p->used_for_reference && + (p_Dpb->last_picture-> + is_orig_reference == 0))) { + insert_picture_in_dpb( + p_H264_Dpb, + p_Dpb->last_picture, + p, data_flag); + update_ref_list(p_Dpb); + update_ltref_list(p_Dpb); + dump_dpb(p_Dpb, 0); + p_Dpb->last_picture = NULL; + return 0; + } + } + } + } + } + /* this is a frame or a field which has no stored + * complementary field + */ + + /* sliding window, if necessary */ + if ((!p->idr_flag) && (p->used_for_reference && + (!p->adaptive_ref_pic_buffering_flag))) { + sliding_window_memory_management(p_Dpb, p); + } + + /* picture error concealment */ + if (p_Vid->conceal_mode != 0) { + for (i = 0; i < p_Dpb->size; i++) + if (p_Dpb->fs[i]->is_reference) + p_Dpb->fs[i]->concealment_reference = 1; + } + + while (remove_unused_frame_from_dpb(p_H264_Dpb)) + ; + + while (output_frames(p_H264_Dpb, 0)) + ; + + /* check for duplicate frame number in short term reference buffer */ + if ((p->used_for_reference) && (!p->is_long_term)) { + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i] == NULL) + continue; +#endif + if (p_Dpb->fs_ref[i]->frame_num == p->frame_num) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "duplicate frame_num in short-term reference picture buffer %d\n", + 500); + if (p_Dpb->fs_ref[i]->dpb_frame_count == p_H264_Dpb->dpb_frame_count) { + dpb_print(p_H264_Dpb->decoder_index, + 0, "duplicate frame, no insert to dpb\n"); + return -2; + } else { + dpb_print(p_H264_Dpb->decoder_index, + 0, "duplicate frame_num release defore ref\n"); + unmark_for_reference(p_Dpb, p_Dpb->fs_ref[i]); + update_ref_list(p_Dpb); + } + } + } + } + /* store at end of buffer */ + + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s p_Dpb->used_size %d\n", __func__, p_Dpb->used_size); + if (p_Dpb->used_size >= p_Dpb->size) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_ERROR, + "%s Error: used_sizd %d is large than dpb size\r\n", + __func__, p_Dpb->used_size); + /*h264_debug_flag |= PRINT_FLAG_DUMP_DPB;*/ + dump_dpb(p_Dpb, 0); + return -1; + } + + insert_picture_in_dpb(p_H264_Dpb, p_Dpb->fs[p_Dpb->used_size], + p, data_flag); + + /* picture error concealment */ + if (p->idr_flag) + p_Vid->earlier_missing_poc = 0; + + if (p->structure != FRAME) + p_Dpb->last_picture = p_Dpb->fs[p_Dpb->used_size]; + else + p_Dpb->last_picture = NULL; + + p_Dpb->used_size++; +#if 0 +/* ??? */ + if (p_Vid->conceal_mode != 0) + p_Vid->pocs_in_dpb[p_Dpb->used_size - 1] = p->poc; +#endif + update_ref_list(p_Dpb); + update_ltref_list(p_Dpb); + + check_num_ref(p_Dpb); + for (i = 0; i < p_Dpb->used_size; i++) { + if (p_Dpb->fs[i]->pre_output) + frame_outside_count++; + } + + if (p_H264_Dpb->fast_output_enable == H264_OUTPUT_MODE_FAST) + i = 1; + else + i = 0; + + if (i || (p_H264_Dpb->first_insert_frame < FirstInsertFrm_SKIPDONE)) { + while (output_frames(p_H264_Dpb, i)) + ; + } + + dump_dpb(p_Dpb, 0); + p_Dpb->first_pic_done = 1; /*by rain*/ + + return 0; +} + +void bufmgr_post(struct h264_dpb_stru *p_H264_Dpb) +{ + /*VideoParameters *p_Vid = p_Dpb->p_Vid;*/ + struct VideoParameters *p_Vid = &p_H264_Dpb->mVideo; + + if (p_Vid->last_has_mmco_5) + p_Vid->pre_frame_num = 0; +} +/********************************** + * + * Initialize reference lists + ********************************** + */ +#define __COMPARE(context, p1, p2) comp(p1, p2) +#define __SHORTSORT(lo, hi, width, comp, context) \ + shortsort(lo, hi, width, comp) +#define CUTOFF 8 /* testing shows that this is good value */ +#define STKSIZ (8*sizeof(void *) - 2) + +#undef swap +static void swap( + char *a, + char *b, + size_t width +) +{ + char tmp; + + if (a != b) + /* Do the swap one character at a time to avoid potential + * alignment problems. + */ + while (width--) { + tmp = *a; + *a++ = *b; + *b++ = tmp; + } +} + +static void shortsort( + char *lo, + char *hi, + size_t width, + int (*comp)(const void *, const void *) +) +{ + char *p, *max; + + /* Note: in assertions below, i and j are alway inside original + * bound of array to sort. + */ + + while (hi > lo) { + /* A[i] <= A[j] for i <= j, j > hi */ + max = lo; + for (p = lo + width; p <= hi; p += width) { + /* A[i] <= A[max] for lo <= i < p */ + if (__COMPARE(context, p, max) > 0) + max = p; + /* A[i] <= A[max] for lo <= i <= p */ + } + + /* A[i] <= A[max] for lo <= i <= hi */ + + swap(max, hi, width); + + /* A[i] <= A[hi] for i <= hi, so A[i] <= A[j] for i <= j, + * j >= hi + */ + + hi -= width; + + /* A[i] <= A[j] for i <= j, j > hi, loop top condition + * established + */ + } + /* A[i] <= A[j] for i <= j, j > lo, which implies A[i] <= A[j] + * for i < j, so array is sorted + */ +} + +static void qsort( + void *base, + size_t num, + size_t width, + int (*comp)(const void *, const void *) +) +{ + char *lo, *hi; /* ends of sub-array currently sorting */ + char *mid; /* points to middle of subarray */ + char *loguy, *higuy; /* traveling pointers for partition step */ + size_t size; /* size of the sub-array */ + char *lostk[STKSIZ], *histk[STKSIZ]; + int stkptr; + +/* stack for saving sub-array to be + * processed + */ +#if 0 + /* validation section */ + _VALIDATE_RETURN_VOID(base != NULL || num == 0, EINVAL); + _VALIDATE_RETURN_VOID(width > 0, EINVAL); + _VALIDATE_RETURN_VOID(comp != NULL, EINVAL); +#endif + if (num < 2) + return; /* nothing to do */ + + stkptr = 0; /* initialize stack */ + + lo = (char *)base; + hi = (char *)base + width * (num - 1); /* initialize limits */ + + /* this entry point is for pseudo-recursion calling: setting + * lo and hi and jumping to here is like recursion, but stkptr is + * preserved, locals aren't, so we preserve stuff on the stack + */ +recurse: + + size = (hi - lo) / width + 1; /* number of el's to sort */ + + /* below a certain size, it is faster to use a O(n^2) sorting method */ + if (size <= CUTOFF) { + __SHORTSORT(lo, hi, width, comp, context); + } else { + /* First we pick a partitioning element. The efficiency of + * the algorithm demands that we find one that is approximately + * the median of the values, but also that we select one fast. + * We choose the median of the first, middle, and last + * elements, to avoid bad performance in the face of already + * sorted data, or data that is made up of multiple sorted + * runs appended together. Testing shows that a + * median-of-three algorithm provides better performance than + * simply picking the middle element for the latter case. + */ + + mid = lo + (size / 2) * width; /* find middle element */ + + /* Sort the first, middle, last elements into order */ + if (__COMPARE(context, lo, mid) > 0) + swap(lo, mid, width); + if (__COMPARE(context, lo, hi) > 0) + swap(lo, hi, width); + if (__COMPARE(context, mid, hi) > 0) + swap(mid, hi, width); + + /* We now wish to partition the array into three pieces, one + * consisting of elements <= partition element, one of elements + * equal to the partition element, and one of elements > than + * it. This is done below; comments indicate conditions + * established at every step. + */ + + loguy = lo; + higuy = hi; + + /* Note that higuy decreases and loguy increases on every + * iteration, so loop must terminate. + */ + for (;;) { + /* lo <= loguy < hi, lo < higuy <= hi, + * A[i] <= A[mid] for lo <= i <= loguy, + * A[i] > A[mid] for higuy <= i < hi, + * A[hi] >= A[mid] + */ + + /* The doubled loop is to avoid calling comp(mid,mid), + * since some existing comparison funcs don't work + * when passed the same value for both pointers. + */ + + if (mid > loguy) { + do { + loguy += width; + } while (loguy < mid && + __COMPARE(context, loguy, mid) <= 0); + } + if (mid <= loguy) { + do { + loguy += width; + } while (loguy <= hi && + __COMPARE(context, loguy, mid) <= 0); + } + + /* lo < loguy <= hi+1, A[i] <= A[mid] for + * lo <= i < loguy, + * either loguy > hi or A[loguy] > A[mid] + */ + + do { + higuy -= width; + } while (higuy > mid && + __COMPARE(context, higuy, mid) > 0); + + /* lo <= higuy < hi, A[i] > A[mid] for higuy < i < hi, + * either higuy == lo or A[higuy] <= A[mid] + */ + + if (higuy < loguy) + break; + + /* if loguy > hi or higuy == lo, then we would have + * exited, so A[loguy] > A[mid], A[higuy] <= A[mid], + * loguy <= hi, higuy > lo + */ + + swap(loguy, higuy, width); + + /* If the partition element was moved, follow it. + * Only need to check for mid == higuy, since before + * the swap, A[loguy] > A[mid] implies loguy != mid. + */ + + if (mid == higuy) + mid = loguy; + + /* A[loguy] <= A[mid], A[higuy] > A[mid]; so condition + * at top of loop is re-established + */ + } + + /* A[i] <= A[mid] for lo <= i < loguy, + * A[i] > A[mid] for higuy < i < hi, + * A[hi] >= A[mid] + * higuy < loguy + * implying: + * higuy == loguy-1 + * or higuy == hi - 1, loguy == hi + 1, A[hi] == A[mid] + */ + + /* Find adjacent elements equal to the partition element. The + * doubled loop is to avoid calling comp(mid,mid), since some + * existing comparison funcs don't work when passed the same + * value for both pointers. + */ + + higuy += width; + if (mid < higuy) { + do { + higuy -= width; + } while (higuy > mid && + __COMPARE(context, higuy, mid) == 0); + } + if (mid >= higuy) { + do { + higuy -= width; + } while (higuy > lo && + __COMPARE(context, higuy, mid) == 0); + } + + /* OK, now we have the following: + * higuy < loguy + * lo <= higuy <= hi + * A[i] <= A[mid] for lo <= i <= higuy + * A[i] == A[mid] for higuy < i < loguy + * A[i] > A[mid] for loguy <= i < hi + * A[hi] >= A[mid] + */ + + /* We've finished the partition, now we want to sort the + * subarrays [lo, higuy] and [loguy, hi]. + * We do the smaller one first to minimize stack usage. + * We only sort arrays of length 2 or more. + */ + + if (higuy - lo >= hi - loguy) { + if (lo < higuy) { + lostk[stkptr] = lo; + histk[stkptr] = higuy; + ++stkptr; + } /* save big recursion for later */ + + if (loguy < hi) { + lo = loguy; + goto recurse; /* do small recursion */ + } + } else { + if (loguy < hi) { + lostk[stkptr] = loguy; + histk[stkptr] = hi; + ++stkptr; /* save big recursion for later */ + } + + if (lo < higuy) { + hi = higuy; + goto recurse; /* do small recursion */ + } + } + } + + /* We have sorted the array, except for any pending sorts on the stack. + * Check if there are any, and do them. + */ + + --stkptr; + if (stkptr >= 0) { + lo = lostk[stkptr]; + hi = histk[stkptr]; + goto recurse; /* pop subarray from stack */ + } else + return; /* all subarrays done */ +} + +/*! + ************************************************************************ + * \brief + * compares two stored pictures by picture number for qsort in + * descending order + * + ************************************************************************ + */ +static inline int compare_pic_by_pic_num_desc(const void *arg1, + const void *arg2) +{ + int pic_num1 = (*(struct StorablePicture **)arg1)->pic_num; + int pic_num2 = (*(struct StorablePicture **)arg2)->pic_num; + + if (pic_num1 < pic_num2) + return 1; + if (pic_num1 > pic_num2) + return -1; + else + return 0; +} + +/*! + ************************************************************************ + * \brief + * compares two stored pictures by picture number for qsort in + * descending order + * + ************************************************************************ + */ +static inline int compare_pic_by_lt_pic_num_asc(const void *arg1, + const void *arg2) +{ + int long_term_pic_num1 = + (*(struct StorablePicture **)arg1)->long_term_pic_num; + int long_term_pic_num2 = + (*(struct StorablePicture **)arg2)->long_term_pic_num; + + if (long_term_pic_num1 < long_term_pic_num2) + return -1; + if (long_term_pic_num1 > long_term_pic_num2) + return 1; + else + return 0; +} + +/*! + ************************************************************************ + * \brief + * compares two frame stores by pic_num for qsort in descending order + * + ************************************************************************ + */ +static inline int compare_fs_by_frame_num_desc(const void *arg1, + const void *arg2) +{ + int frame_num_wrap1 = (*(struct FrameStore **)arg1)->frame_num_wrap; + int frame_num_wrap2 = (*(struct FrameStore **)arg2)->frame_num_wrap; + + if (frame_num_wrap1 < frame_num_wrap2) + return 1; + if (frame_num_wrap1 > frame_num_wrap2) + return -1; + else + return 0; +} + + +/*! + ************************************************************************ + * \brief + * compares two frame stores by lt_pic_num for qsort in descending order + * + ************************************************************************ + */ +static inline int compare_fs_by_lt_pic_idx_asc(const void *arg1, + const void *arg2) +{ + int long_term_frame_idx1 = + (*(struct FrameStore **)arg1)->long_term_frame_idx; + int long_term_frame_idx2 = + (*(struct FrameStore **)arg2)->long_term_frame_idx; + + if (long_term_frame_idx1 < long_term_frame_idx2) + return -1; + else if (long_term_frame_idx1 > long_term_frame_idx2) + return 1; + else + return 0; +} + + +/*! + ************************************************************************ + * \brief + * compares two stored pictures by poc for qsort in ascending order + * + ************************************************************************ + */ +static inline int compare_pic_by_poc_asc(const void *arg1, const void *arg2) +{ + int poc1 = (*(struct StorablePicture **)arg1)->poc; + int poc2 = (*(struct StorablePicture **)arg2)->poc; + + if (poc1 < poc2) + return -1; + else if (poc1 > poc2) + return 1; + else + return 0; +} + + +/*! + ************************************************************************ + * \brief + * compares two stored pictures by poc for qsort in descending order + * + ************************************************************************ + */ +static inline int compare_pic_by_poc_desc(const void *arg1, const void *arg2) +{ + int poc1 = (*(struct StorablePicture **)arg1)->poc; + int poc2 = (*(struct StorablePicture **)arg2)->poc; + + if (poc1 < poc2) + return 1; + else if (poc1 > poc2) + return -1; + else + return 0; +} + + +/*! + ************************************************************************ + * \brief + * compares two frame stores by poc for qsort in ascending order + * + ************************************************************************ + */ +static inline int compare_fs_by_poc_asc(const void *arg1, const void *arg2) +{ + int poc1 = (*(struct FrameStore **)arg1)->poc; + int poc2 = (*(struct FrameStore **)arg2)->poc; + + if (poc1 < poc2) + return -1; + else if (poc1 > poc2) + return 1; + else + return 0; +} + + +/*! + ************************************************************************ + * \brief + * compares two frame stores by poc for qsort in descending order + * + ************************************************************************ + */ +static inline int compare_fs_by_poc_desc(const void *arg1, const void *arg2) +{ + int poc1 = (*(struct FrameStore **)arg1)->poc; + int poc2 = (*(struct FrameStore **)arg2)->poc; + + if (poc1 < poc2) + return 1; + else if (poc1 > poc2) + return -1; + else + return 0; +} + +/*! + ************************************************************************ + * \brief + * returns true, if picture is short term reference picture + * + ************************************************************************ + */ +static inline int is_short_ref(struct StorablePicture *s) +{ +#ifdef ERROR_CHECK + return (s && + (s->used_for_reference) && (!(s->is_long_term))); +#else + return (s->used_for_reference) && (!(s->is_long_term)); +#endif +} + + +/*! + ************************************************************************ + * \brief + * returns true, if picture is long term reference picture + * + ************************************************************************ + */ +static inline int is_long_ref(struct StorablePicture *s) +{ +#ifdef ERROR_CHECK + return (s && + s->used_for_reference) && (s->is_long_term); +#else + return (s->used_for_reference) && (s->is_long_term); +#endif +} + +/*! + ************************************************************************ + * \brief + * Initialize reference lists for a P Slice + * + ************************************************************************ + */ +/*! + ************************************************************************ + * \brief + * Generates a alternating field list from a given FrameStore list + * + ************************************************************************ + */ +static void gen_pic_list_from_frame_list(enum PictureStructure currStructure, + struct FrameStore **fs_list, int list_idx, + struct StorablePicture **list, + char *list_size, int long_term) +{ + int top_idx = 0; + int bot_idx = 0; + + int (*is_ref)(struct StorablePicture *s) = (long_term) ? is_long_ref : + is_short_ref; + + + if (currStructure == TOP_FIELD) { + while ((top_idx < list_idx) || (bot_idx < list_idx)) { + for (; top_idx < list_idx; top_idx++) { + if (fs_list[top_idx]->is_used & 1) { + if (is_ref(fs_list[top_idx]-> + top_field)) { + /* short term ref pic */ + list[(short) *list_size] = + fs_list[top_idx]->top_field; + (*list_size)++; + top_idx++; + break; + } + } + } + for (; bot_idx < list_idx; bot_idx++) { + if (fs_list[bot_idx]->is_used & 2) { + if (is_ref(fs_list[bot_idx]-> + bottom_field)) { + /* short term ref pic */ + list[(short) *list_size] = + fs_list[bot_idx]->bottom_field; + (*list_size)++; + bot_idx++; + break; + } + } + } + } + } + if (currStructure == BOTTOM_FIELD) { + while ((top_idx < list_idx) || (bot_idx < list_idx)) { + for (; bot_idx < list_idx; bot_idx++) { + if (fs_list[bot_idx]->is_used & 2) { + if (is_ref(fs_list[bot_idx]-> + bottom_field)) { + /* short term ref pic */ + list[(short) *list_size] = + fs_list[bot_idx]->bottom_field; + (*list_size)++; + bot_idx++; + break; + } + } + } + for (; top_idx < list_idx; top_idx++) { + if (fs_list[top_idx]->is_used & 1) { + if (is_ref(fs_list[top_idx]-> + top_field)) { + /* short term ref pic */ + list[(short) *list_size] = + fs_list[top_idx]->top_field; + (*list_size)++; + top_idx++; + break; + } + } + } + } + } +} + +static void init_lists_p_slice(struct Slice *currSlice) +{ + struct VideoParameters *p_Vid = currSlice->p_Vid; + struct DecodedPictureBuffer *p_Dpb = currSlice->p_Dpb; + struct h264_dpb_stru *p_H264_Dpb = container_of(p_Dpb, + struct h264_dpb_stru, mDPB); + + unsigned int i; + + int list0idx = 0; + int listltidx = 0; + + struct FrameStore **fs_list0; + struct FrameStore **fs_listlt; + +#if (MVC_EXTENSION_ENABLE) + currSlice->listinterviewidx0 = 0; + currSlice->listinterviewidx1 = 0; +#endif + + if (currSlice->structure == FRAME) { + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i] == NULL || + p_Dpb->fs_ref[i]->frame == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if (p_Dpb->fs_ref[i]->is_used == 3) { + if ((p_Dpb->fs_ref[i]->frame-> + used_for_reference) && + (!p_Dpb->fs_ref[i]->frame-> + is_long_term)) { + currSlice->listX[0][list0idx++] = + p_Dpb->fs_ref[i]->frame; + } + } + } + /* order list 0 by PicNum */ + qsort((void *)currSlice->listX[0], list0idx, + sizeof(struct StorablePicture *), + compare_pic_by_pic_num_desc); + currSlice->listXsize[0] = (char) list0idx; + CHECK_VALID(currSlice->listXsize[0], 0); + if (h264_debug_flag & PRINT_FLAG_DPB_DETAIL) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "listX[0] (PicNum): "); + for (i = 0; i < list0idx; i++) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "%d ", + currSlice->listX[0][i]->pic_num); + } + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "\n"); + } + /* long term handling */ + for (i = 0; i < p_Dpb->ltref_frames_in_buffer; i++) { + if (p_Dpb->fs_ltref[i]->is_used == 3) { + if (p_Dpb->fs_ltref[i]->frame->is_long_term) { + currSlice->listX[0][list0idx++] = + p_Dpb->fs_ltref[i]->frame; + } + } + } + qsort((void *)&currSlice->listX[0][ + (short) currSlice->listXsize[0]], + list0idx - currSlice->listXsize[0], + sizeof(struct StorablePicture *), + compare_pic_by_lt_pic_num_asc); + currSlice->listXsize[0] = (char) list0idx; + CHECK_VALID(currSlice->listXsize[0], 0); + } else { +#if 0 + fs_list0 = calloc(p_Dpb->size, sizeof(struct FrameStore *)); + if (fs_list0 == NULL) + no_mem_exit("init_lists: fs_list0"); + fs_listlt = calloc(p_Dpb->size, sizeof(struct FrameStore *)); + if (fs_listlt == NULL) + no_mem_exit("init_lists: fs_listlt"); +#else + fs_list0 = &(p_Dpb->fs_list0[0]); + fs_listlt = &(p_Dpb->fs_listlt[0]); +#endif + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i] == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if (p_Dpb->fs_ref[i]->is_reference) + fs_list0[list0idx++] = p_Dpb->fs_ref[i]; + } + + qsort((void *)fs_list0, list0idx, sizeof(struct FrameStore *), + compare_fs_by_frame_num_desc); + + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "fs_list0 (FrameNum): "); + for (i = 0; i < list0idx; i++) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "%d ", + fs_list0[i]->frame_num_wrap); + } + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "\n"); + + currSlice->listXsize[0] = 0; + gen_pic_list_from_frame_list(currSlice->structure, fs_list0, + list0idx, currSlice->listX[0], + &currSlice->listXsize[0], 0); + + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "listX[0] (PicNum): "); + for (i = 0; i < currSlice->listXsize[0]; i++) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "%d ", + currSlice->listX[0][i]->pic_num); + } + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "\n"); + + /* long term handling */ + for (i = 0; i < p_Dpb->ltref_frames_in_buffer; i++) + fs_listlt[listltidx++] = p_Dpb->fs_ltref[i]; + + qsort((void *)fs_listlt, listltidx, sizeof(struct FrameStore *), + compare_fs_by_lt_pic_idx_asc); + + gen_pic_list_from_frame_list(currSlice->structure, fs_listlt, + listltidx, currSlice->listX[0], + &currSlice->listXsize[0], 1); + + /* free(fs_list0); */ + /* free(fs_listlt); */ + } + currSlice->listXsize[1] = 0; + + + /* set max size */ + currSlice->listXsize[0] = (char) imin(currSlice->listXsize[0], + currSlice->num_ref_idx_active[LIST_0]); + currSlice->listXsize[1] = (char) imin(currSlice->listXsize[1], + currSlice->num_ref_idx_active[LIST_1]); + CHECK_VALID(currSlice->listXsize[0], 0); + CHECK_VALID(currSlice->listXsize[1], 1); + + /* set the unused list entries to NULL */ + for (i = currSlice->listXsize[0]; i < (MAX_LIST_SIZE); i++) + currSlice->listX[0][i] = p_Vid->no_reference_picture; + for (i = currSlice->listXsize[1]; i < (MAX_LIST_SIZE); i++) + currSlice->listX[1][i] = p_Vid->no_reference_picture; + +#if PRINTREFLIST +#if (MVC_EXTENSION_ENABLE) + /* print out for h264_debug_flag purpose */ + if ((p_Vid->profile_idc == MVC_HIGH || + p_Vid->profile_idc == STEREO_HIGH) && + currSlice->current_slice_nr == 0) { + if (currSlice->listXsize[0] > 0) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "\n"); + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + " ** (CurViewID:%d %d) %s Ref Pic List 0 ****\n", + currSlice->view_id, + currSlice->ThisPOC, + currSlice->structure == FRAME ? "FRM" : + (currSlice->structure == TOP_FIELD ? + "TOP" : "BOT")); + for (i = 0; i < (unsigned int)(currSlice-> + listXsize[0]); i++) { /* ref list 0 */ + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + " %2d -> POC: %4d PicNum: %4d ViewID: %d\n", + i, + currSlice->listX[0][i]->poc, + currSlice->listX[0][i]->pic_num, + currSlice->listX[0][i]->view_id); + } + } + } +#endif +#endif +} + + +/*! + ************************************************************************ + * \brief + * Initialize reference lists + * + ************************************************************************ + */ +static void init_mbaff_lists(struct h264_dpb_stru *p_H264_Dpb, + struct Slice *currSlice) +{ + unsigned int j; + int i; + struct VideoParameters *p_Vid = &p_H264_Dpb->mVideo; + for (i = 2; i < 6; i++) { + for (j = 0; j < MAX_LIST_SIZE; j++) + currSlice->listX[i][j] = p_Vid->no_reference_picture; + currSlice->listXsize[i] = 0; + } + + for (i = 0; i < currSlice->listXsize[0]; i++) { +#ifdef ERROR_CHECK + if (currSlice->listX[0][i] == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + pr_info( + "error currSlice->listX[0][%d] is NULL\r\n", i); + break; + } +#endif + currSlice->listX[2][2 * i] = + currSlice->listX[0][i]->top_field; + currSlice->listX[2][2 * i + 1] = + currSlice->listX[0][i]->bottom_field; + currSlice->listX[4][2 * i] = + currSlice->listX[0][i]->bottom_field; + currSlice->listX[4][2 * i + 1] = + currSlice->listX[0][i]->top_field; + } + currSlice->listXsize[2] = currSlice->listXsize[4] = + currSlice->listXsize[0] * 2; + + for (i = 0; i < currSlice->listXsize[1]; i++) { +#ifdef ERROR_CHECK + if (currSlice->listX[1][i] == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + pr_info( + "error currSlice->listX[1][%d] is NULL\r\n", i); + break; + } +#endif + currSlice->listX[3][2 * i] = + currSlice->listX[1][i]->top_field; + currSlice->listX[3][2 * i + 1] = + currSlice->listX[1][i]->bottom_field; + currSlice->listX[5][2 * i] = + currSlice->listX[1][i]->bottom_field; + currSlice->listX[5][2 * i + 1] = + currSlice->listX[1][i]->top_field; + } + currSlice->listXsize[3] = currSlice->listXsize[5] = + currSlice->listXsize[1] * 2; +} + + + +static void init_lists_i_slice(struct Slice *currSlice) +{ + +#if (MVC_EXTENSION_ENABLE) + currSlice->listinterviewidx0 = 0; + currSlice->listinterviewidx1 = 0; +#endif + + currSlice->listXsize[0] = 0; + currSlice->listXsize[1] = 0; +} + +static void init_lists_b_slice(struct Slice *currSlice) +{ + struct VideoParameters *p_Vid = currSlice->p_Vid; + struct DecodedPictureBuffer *p_Dpb = currSlice->p_Dpb; + struct h264_dpb_stru *p_H264_Dpb = container_of(p_Dpb, + struct h264_dpb_stru, mDPB); + + unsigned int i; + int j; + + int list0idx = 0; + int list0idx_1 = 0; + int listltidx = 0; + + struct FrameStore **fs_list0; + struct FrameStore **fs_list1; + struct FrameStore **fs_listlt; + +#if (MVC_EXTENSION_ENABLE) + currSlice->listinterviewidx0 = 0; + currSlice->listinterviewidx1 = 0; +#endif + + { + /* B-Slice */ + if (currSlice->structure == FRAME) { + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i] == NULL || + p_Dpb->fs_ref[i]->frame == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if ((p_Dpb->fs_ref[i]->is_used == 3) && + ((p_Dpb->fs_ref[i]->frame-> + used_for_reference) && + (!p_Dpb->fs_ref[i]->frame-> + is_long_term)) && + (currSlice->framepoc >= + p_Dpb->fs_ref[i]->frame->poc)) { + /* !KS use >= for error + * concealment + */ + currSlice->listX[0][list0idx++] = + p_Dpb->fs_ref[i]->frame; + } + } + qsort((void *)currSlice->listX[0], list0idx, + sizeof(struct StorablePicture *), + compare_pic_by_poc_desc); + + /* get the backward reference picture + * (POC>current POC) in list0; + */ + list0idx_1 = list0idx; + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i] == NULL || + p_Dpb->fs_ref[i]->frame == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if ((p_Dpb->fs_ref[i]->is_used == 3) && + ((p_Dpb->fs_ref[i]->frame-> + used_for_reference) && + (!p_Dpb->fs_ref[i]->frame-> + is_long_term)) && + (currSlice->framepoc < + p_Dpb->fs_ref[i]->frame->poc)) { + currSlice-> + listX[0][list0idx++] = + p_Dpb->fs_ref[i]->frame; + } + } + qsort((void *)&currSlice->listX[0][list0idx_1], + list0idx - list0idx_1, + sizeof(struct StorablePicture *), + compare_pic_by_poc_asc); + + for (j = 0; j < list0idx_1; j++) { + currSlice-> + listX[1][list0idx - list0idx_1 + j] = + currSlice->listX[0][j]; + } + for (j = list0idx_1; j < list0idx; j++) { + currSlice->listX[1][j - list0idx_1] = + currSlice->listX[0][j]; + } + + currSlice->listXsize[0] = currSlice->listXsize[1] = + (char) list0idx; + CHECK_VALID(currSlice->listXsize[0], 0); + CHECK_VALID(currSlice->listXsize[1], 1); + + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "listX[0] (PicNum): "); + for (i = 0; i < currSlice->listXsize[0]; i++) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "%d ", + currSlice->listX[0][i]->pic_num); + } + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "\n"); + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "listX[1] (PicNum): "); + for (i = 0; i < currSlice->listXsize[1]; i++) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "%d ", + currSlice->listX[1][i]->pic_num); + } + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "\n"); + /* dpb_print(p_H264_Dpb->decoder_index, + * PRINT_FLAG_DPB_DETAIL, + * "currSlice->listX[0] currPoc=%d (Poc): ", + * p_Vid->framepoc); + * for (i=0; i<currSlice->listXsize[0]; i++) { + * dpb_print(p_H264_Dpb->decoder_index, + * PRINT_FLAG_DPB_DETAIL, + * "%d ", currSlice->listX[0][i]->poc); + * } + * dpb_print(p_H264_Dpb->decoder_index, + * PRINT_FLAG_DPB_DETAIL, "\n"); + * dpb_print(p_H264_Dpb->decoder_index, + * PRINT_FLAG_DPB_DETAIL, + * "currSlice->listX[1] currPoc=%d (Poc): ", + * p_Vid->framepoc); + * for (i=0; i<currSlice->listXsize[1]; i++) { + * dpb_print(p_H264_Dpb->decoder_index, + * PRINT_FLAG_DPB_DETAIL, + * "%d ", + * currSlice->listX[1][i]->poc); + * } + * dpb_print(p_H264_Dpb->decoder_index, + * PRINT_FLAG_DPB_DETAIL, "\n"); + */ + + /* long term handling */ + for (i = 0; i < p_Dpb->ltref_frames_in_buffer; i++) { + if (p_Dpb->fs_ltref[i]->is_used == 3) { + if (p_Dpb->fs_ltref[i]->frame-> + is_long_term) { + currSlice-> + listX[0][list0idx] = + p_Dpb->fs_ltref[i]->frame; + currSlice-> + listX[1][list0idx++] = + p_Dpb->fs_ltref[i]->frame; + } + } + } + qsort((void *)&currSlice-> + listX[0][(short) currSlice->listXsize[0]], + list0idx - currSlice->listXsize[0], + sizeof(struct StorablePicture *), + compare_pic_by_lt_pic_num_asc); + qsort((void *)&currSlice-> + listX[1][(short) currSlice->listXsize[0]], + list0idx - currSlice->listXsize[0], + sizeof(struct StorablePicture *), + compare_pic_by_lt_pic_num_asc); + currSlice->listXsize[0] = currSlice->listXsize[1] = + (char) list0idx; + CHECK_VALID(currSlice->listXsize[0], 0); + CHECK_VALID(currSlice->listXsize[1], 1); + } else { +#if 0 + fs_list0 = calloc(p_Dpb->size, + sizeof(struct FrameStore *)); + if (fs_list0 == NULL) + no_mem_exit("init_lists: fs_list0"); + fs_list1 = calloc(p_Dpb->size, + sizeof(struct FrameStore *)); + if (fs_list1 == NULL) + no_mem_exit("init_lists: fs_list1"); + fs_listlt = calloc(p_Dpb->size, + sizeof(struct FrameStore *)); + if (fs_listlt == NULL) + no_mem_exit("init_lists: fs_listlt"); +#else + fs_list0 = &(p_Dpb->fs_list0[0]); + fs_list1 = &(p_Dpb->fs_list1[0]); + fs_listlt = &(p_Dpb->fs_listlt[0]); + +#endif + currSlice->listXsize[0] = 0; + currSlice->listXsize[1] = 1; + + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i] == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if (p_Dpb->fs_ref[i]->is_used) { + if (currSlice->ThisPOC >= + p_Dpb->fs_ref[i]->poc) { + fs_list0[list0idx++] = + p_Dpb->fs_ref[i]; + } + } + } + qsort((void *)fs_list0, list0idx, + sizeof(struct FrameStore *), + compare_fs_by_poc_desc); + list0idx_1 = list0idx; + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i] == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if (p_Dpb->fs_ref[i]->is_used) { + if (currSlice->ThisPOC < + p_Dpb->fs_ref[i]->poc) { + fs_list0[list0idx++] = + p_Dpb->fs_ref[i]; + } + } + } + qsort((void *)&fs_list0[list0idx_1], + list0idx - list0idx_1, + sizeof(struct FrameStore *), + compare_fs_by_poc_asc); + + for (j = 0; j < list0idx_1; j++) { + fs_list1[list0idx - list0idx_1 + j] = + fs_list0[j]; + } + for (j = list0idx_1; j < list0idx; j++) + fs_list1[j - list0idx_1] = fs_list0[j]; + + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "fs_list0 currPoc=%d (Poc): ", + currSlice->ThisPOC); + for (i = 0; i < list0idx; i++) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "%d ", + fs_list0[i]->poc); + } + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "\n"); + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "fs_list1 currPoc=%d (Poc): ", + currSlice->ThisPOC); + for (i = 0; i < list0idx; i++) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "%d ", + fs_list1[i]->poc); + } + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "\n"); + + currSlice->listXsize[0] = 0; + currSlice->listXsize[1] = 0; + gen_pic_list_from_frame_list(currSlice->structure, + fs_list0, list0idx, + currSlice->listX[0], + &currSlice->listXsize[0], 0); + gen_pic_list_from_frame_list(currSlice->structure, + fs_list1, list0idx, + currSlice->listX[1], + &currSlice->listXsize[1], 0); + + /* dpb_print(p_H264_Dpb->decoder_index, + * PRINT_FLAG_DPB_DETAIL, + * "currSlice->listX[0] currPoc=%d (Poc): ", + * p_Vid->framepoc); + * for (i=0; i<currSlice->listXsize[0]; i++) { + * dpb_print(p_H264_Dpb->decoder_index, + * PRINT_FLAG_DPB_DETAIL, "%d ", + * currSlice->listX[0][i]->poc); + * } + * dpb_print(p_H264_Dpb->decoder_index, + * PRINT_FLAG_DPB_DETAIL, "\n"); + */ + /* dpb_print(p_H264_Dpb->decoder_index, + * PRINT_FLAG_DPB_DETAIL, + * "currSlice->listX[1] currPoc=%d (Poc): ", + * p_Vid->framepoc); + * for (i=0; i<currSlice->listXsize[1]; i++) { + * dpb_print(p_H264_Dpb->decoder_index, + * PRINT_FLAG_DPB_DETAIL, "%d ", + * currSlice->listX[1][i]->poc); + * } + * dpb_print(p_H264_Dpb->decoder_index, + * PRINT_FLAG_DPB_DETAIL, + * "\n"); + */ + + /* long term handling */ + for (i = 0; i < p_Dpb->ltref_frames_in_buffer; i++) + fs_listlt[listltidx++] = p_Dpb->fs_ltref[i]; + + qsort((void *)fs_listlt, listltidx, + sizeof(struct FrameStore *), + compare_fs_by_lt_pic_idx_asc); + + gen_pic_list_from_frame_list(currSlice->structure, + fs_listlt, listltidx, + currSlice->listX[0], + &currSlice->listXsize[0], 1); + gen_pic_list_from_frame_list(currSlice->structure, + fs_listlt, listltidx, + currSlice->listX[1], + &currSlice->listXsize[1], 1); + + /* free(fs_list0); */ + /* free(fs_list1); */ + /* free(fs_listlt); */ + } + } + + if ((currSlice->listXsize[0] == currSlice->listXsize[1]) && + (currSlice->listXsize[0] > 1)) { + /* check if lists are identical, + *if yes swap first two elements of currSlice->listX[1] + */ + int diff = 0; + + for (j = 0; j < currSlice->listXsize[0]; j++) { + if (currSlice->listX[0][j] != + currSlice->listX[1][j]) { + diff = 1; + break; + } + } + if (!diff) { + struct StorablePicture *tmp_s = + currSlice->listX[1][0]; + currSlice->listX[1][0] = currSlice->listX[1][1]; + currSlice->listX[1][1] = tmp_s; + } + } + + /* set max size */ + currSlice->listXsize[0] = (char) imin(currSlice->listXsize[0], + currSlice->num_ref_idx_active[LIST_0]); + currSlice->listXsize[1] = (char) imin(currSlice->listXsize[1], + currSlice->num_ref_idx_active[LIST_1]); + CHECK_VALID(currSlice->listXsize[0], 0); + CHECK_VALID(currSlice->listXsize[1], 1); + + /* set the unused list entries to NULL */ + for (i = currSlice->listXsize[0]; i < (MAX_LIST_SIZE); i++) + currSlice->listX[0][i] = p_Vid->no_reference_picture; + for (i = currSlice->listXsize[1]; i < (MAX_LIST_SIZE); i++) + currSlice->listX[1][i] = p_Vid->no_reference_picture; + +#if PRINTREFLIST +#if (MVC_EXTENSION_ENABLE) + /* print out for h264_debug_flag purpose */ + if ((p_Vid->profile_idc == MVC_HIGH || + p_Vid->profile_idc == STEREO_HIGH) && + currSlice->current_slice_nr == 0) { + if ((currSlice->listXsize[0] > 0) || + (currSlice->listXsize[1] > 0)) + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "\n"); + if (currSlice->listXsize[0] > 0) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + " ** (CurViewID:%d %d) %s Ref Pic List 0 ****\n", + currSlice->view_id, + currSlice->ThisPOC, + currSlice->structure == FRAME ? "FRM" : + (currSlice->structure == TOP_FIELD ? + "TOP" : "BOT")); + for (i = 0; i < (unsigned int)(currSlice-> + listXsize[0]); i++) { /* ref list 0 */ + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + " %2d -> POC: %4d PicNum: %4d ViewID: %d\n", + i, + currSlice->listX[0][i]->poc, + currSlice->listX[0][i]->pic_num, + currSlice->listX[0][i]->view_id); + } + } + if (currSlice->listXsize[1] > 0) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + " ** (CurViewID:%d %d) %s Ref Pic List 1 ****\n", + currSlice->view_id, + currSlice->ThisPOC, + currSlice->structure == FRAME ? "FRM" : + (currSlice->structure == TOP_FIELD ? "TOP" : + "BOT")); + for (i = 0; i < (unsigned int)(currSlice-> + listXsize[1]); i++) { /* ref list 1 */ + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + " %2d -> POC: %4d PicNum: %4d ViewID: %d\n", + i, + currSlice->listX[1][i]->poc, + currSlice->listX[1][i]->pic_num, + currSlice->listX[1][i]->view_id); + } + } + } +#endif +#endif +} + +static struct StorablePicture *get_short_term_pic(struct Slice *currSlice, + struct DecodedPictureBuffer *p_Dpb, int picNum) +{ + unsigned int i; + struct h264_dpb_stru *p_H264_Dpb = container_of(p_Dpb, + struct h264_dpb_stru, mDPB); + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) { + if (currSlice->structure == FRAME) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i] == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if (p_Dpb->fs_ref[i]->is_reference == 3) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i]->frame == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if ((!p_Dpb->fs_ref[i]->frame-> + is_long_term) && + (p_Dpb->fs_ref[i]->frame-> + pic_num == picNum)) + return p_Dpb->fs_ref[i]->frame; + } + } else { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i] == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if (p_Dpb->fs_ref[i]->is_reference & 1) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i]->top_field == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if ((!p_Dpb->fs_ref[i]->top_field-> + is_long_term) && + (p_Dpb->fs_ref[i]->top_field-> + pic_num == picNum)) + return p_Dpb->fs_ref[i]->top_field; + } + if (p_Dpb->fs_ref[i]->is_reference & 2) { +#ifdef ERROR_CHECK + if (p_Dpb->fs_ref[i]->bottom_field == NULL) { + p_H264_Dpb->dpb_error_flag = __LINE__; + continue; + } +#endif + if ((!p_Dpb->fs_ref[i]->bottom_field-> + is_long_term) && + (p_Dpb->fs_ref[i]->bottom_field-> + pic_num == picNum)) + return p_Dpb->fs_ref[i]->bottom_field; + } + } + } + + return currSlice->p_Vid->no_reference_picture; +} + + +static void reorder_short_term(struct Slice *currSlice, int cur_list, + int num_ref_idx_lX_active_minus1, + int picNumLX, int *refIdxLX) +{ + struct h264_dpb_stru *p_H264_Dpb = container_of(currSlice->p_Vid, + struct h264_dpb_stru, mVideo); + + struct StorablePicture **RefPicListX = currSlice->listX[cur_list]; + int cIdx, nIdx; + + struct StorablePicture *picLX; + + picLX = get_short_term_pic(currSlice, currSlice->p_Dpb, picNumLX); + + for (cIdx = num_ref_idx_lX_active_minus1 + 1; cIdx > *refIdxLX; + cIdx--) { + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s: RefPicListX[ %d ] = RefPicListX[ %d ]\n", + __func__, cIdx, cIdx - 1); + RefPicListX[cIdx] = RefPicListX[cIdx - 1]; + } + + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s: RefPicListX[ %d ] = pic %x (%d)\n", __func__, + *refIdxLX, picLX, picNumLX); + + RefPicListX[(*refIdxLX)++] = picLX; + + nIdx = *refIdxLX; + + for (cIdx = *refIdxLX; cIdx <= num_ref_idx_lX_active_minus1 + 1; + cIdx++) { + if (RefPicListX[cIdx]) + if ((RefPicListX[cIdx]->is_long_term) || + (RefPicListX[cIdx]->pic_num != picNumLX)) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "%s: RefPicListX[ %d ] = RefPicListX[ %d ]\n", + __func__, nIdx, cIdx); + RefPicListX[nIdx++] = RefPicListX[cIdx]; + } + } +} + + +static struct StorablePicture *get_long_term_pic(struct Slice *currSlice, + struct DecodedPictureBuffer *p_Dpb, int LongtermPicNum) +{ + unsigned int i; + + for (i = 0; i < p_Dpb->ltref_frames_in_buffer; i++) { + if (currSlice->structure == FRAME) { + if (p_Dpb->fs_ltref[i]->is_reference == 3) + if ((p_Dpb->fs_ltref[i]->frame) && + (p_Dpb->fs_ltref[i]->frame-> + is_long_term) && + (p_Dpb->fs_ltref[i]->frame-> + long_term_pic_num == + LongtermPicNum)) + return p_Dpb->fs_ltref[i]->frame; + } else { + if (p_Dpb->fs_ltref[i]->is_reference & 1) + if ((p_Dpb->fs_ltref[i]->top_field) && + (p_Dpb->fs_ltref[i]->top_field-> + is_long_term) && + (p_Dpb->fs_ltref[i]->top_field-> + long_term_pic_num == LongtermPicNum)) + return p_Dpb->fs_ltref[i]->top_field; + + if (p_Dpb->fs_ltref[i]->is_reference & 2) + if ((p_Dpb->fs_ltref[i]->bottom_field) && + (p_Dpb->fs_ltref[i]->bottom_field-> + is_long_term) && + (p_Dpb->fs_ltref[i]->bottom_field-> + long_term_pic_num == + LongtermPicNum)) + return p_Dpb->fs_ltref[i]-> + bottom_field; + } + } + return NULL; +} + +/*! + ************************************************************************ + * \brief + * Reordering process for long-term reference pictures + * + ************************************************************************ + */ +static void reorder_long_term(struct Slice *currSlice, + struct StorablePicture **RefPicListX, + int num_ref_idx_lX_active_minus1, + int LongTermPicNum, int *refIdxLX) +{ + int cIdx, nIdx; + + struct StorablePicture *picLX; + + picLX = get_long_term_pic(currSlice, currSlice->p_Dpb, LongTermPicNum); + + for (cIdx = num_ref_idx_lX_active_minus1 + 1; cIdx > *refIdxLX; cIdx--) + RefPicListX[cIdx] = RefPicListX[cIdx - 1]; + + RefPicListX[(*refIdxLX)++] = picLX; + + nIdx = *refIdxLX; + + for (cIdx = *refIdxLX; cIdx <= num_ref_idx_lX_active_minus1 + 1; + cIdx++) { + if (RefPicListX[cIdx]) { + if ((!RefPicListX[cIdx]->is_long_term) || + (RefPicListX[cIdx]->long_term_pic_num != + LongTermPicNum)) + RefPicListX[nIdx++] = RefPicListX[cIdx]; + } + } +} + +static void reorder_ref_pic_list(struct Slice *currSlice, int cur_list) +{ + int *modification_of_pic_nums_idc = + currSlice->modification_of_pic_nums_idc[cur_list]; + int *abs_diff_pic_num_minus1 = + currSlice->abs_diff_pic_num_minus1[cur_list]; + int *long_term_pic_idx = currSlice->long_term_pic_idx[cur_list]; + int num_ref_idx_lX_active_minus1 = + currSlice->num_ref_idx_active[cur_list] - 1; + + struct VideoParameters *p_Vid = currSlice->p_Vid; + int i; + + int maxPicNum, currPicNum, picNumLXNoWrap, picNumLXPred, picNumLX; + int refIdxLX = 0; + + if (currSlice->structure == FRAME) { + maxPicNum = p_Vid->max_frame_num; + currPicNum = currSlice->frame_num; + } else { + maxPicNum = 2 * p_Vid->max_frame_num; + currPicNum = 2 * currSlice->frame_num + 1; + } + + picNumLXPred = currPicNum; + + for (i = 0; i < REORDERING_COMMAND_MAX_SIZE && + modification_of_pic_nums_idc[i] != 3; i++) { + if (modification_of_pic_nums_idc[i] > 3) { + struct h264_dpb_stru *p_H264_Dpb = + container_of(p_Vid, struct h264_dpb_stru, mVideo); + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_ERROR, + "error, Invalid modification_of_pic_nums_idc command\n"); + /*h264_debug_flag = 0x1f;*/ + break; + } + if (modification_of_pic_nums_idc[i] < 2) { + if (modification_of_pic_nums_idc[i] == 0) { + if (picNumLXPred - (abs_diff_pic_num_minus1[i] + + 1) < 0) + picNumLXNoWrap = picNumLXPred - + (abs_diff_pic_num_minus1[i] + 1) + + maxPicNum; + else + picNumLXNoWrap = picNumLXPred - + (abs_diff_pic_num_minus1[i] + 1); + } else { /* (modification_of_pic_nums_idc[i] == 1) */ + if (picNumLXPred + (abs_diff_pic_num_minus1[i] + + 1) >= maxPicNum) + picNumLXNoWrap = picNumLXPred + + (abs_diff_pic_num_minus1[i] + 1) - + maxPicNum; + else + picNumLXNoWrap = picNumLXPred + + (abs_diff_pic_num_minus1[i] + 1); + } + picNumLXPred = picNumLXNoWrap; + + if (picNumLXNoWrap > currPicNum) + picNumLX = picNumLXNoWrap - maxPicNum; + else + picNumLX = picNumLXNoWrap; + +#if (MVC_EXTENSION_ENABLE) + reorder_short_term(currSlice, cur_list, + num_ref_idx_lX_active_minus1, picNumLX, + &refIdxLX, -1); +#else + reorder_short_term(currSlice, cur_list, + num_ref_idx_lX_active_minus1, picNumLX, + &refIdxLX); +#endif + } else { /* (modification_of_pic_nums_idc[i] == 2) */ +#if (MVC_EXTENSION_ENABLE) + reorder_long_term(currSlice, currSlice->listX[cur_list], + num_ref_idx_lX_active_minus1, + long_term_pic_idx[i], &refIdxLX, -1); +#else + reorder_long_term(currSlice, currSlice->listX[cur_list], + num_ref_idx_lX_active_minus1, + long_term_pic_idx[i], &refIdxLX); +#endif + } + + } + /* that's a definition */ + currSlice->listXsize[cur_list] = + (char)(num_ref_idx_lX_active_minus1 + 1); +} + +static void reorder_lists(struct Slice *currSlice) +{ + struct VideoParameters *p_Vid = currSlice->p_Vid; + struct h264_dpb_stru *p_H264_Dpb = container_of(p_Vid, + struct h264_dpb_stru, mVideo); + int i; + + if ((currSlice->slice_type != I_SLICE) && + (currSlice->slice_type != SI_SLICE)) { + if (currSlice->ref_pic_list_reordering_flag[LIST_0]) + reorder_ref_pic_list(currSlice, LIST_0); + if (p_Vid->no_reference_picture == + currSlice-> + listX[0][currSlice->num_ref_idx_active[LIST_0] - 1]) { + if (p_Vid->non_conforming_stream) + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "RefPicList0[ %d ] is equal to 'no reference picture'\n", + currSlice-> + num_ref_idx_active[LIST_0] - 1); + else + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "RefPicList0 [ num_ref_idx_l0_active_minus1 ] is equal to 'no reference picture', invalid bitstream %d\n", + 500); + } + /* that's a definition */ + currSlice->listXsize[0] = + (char) imin(currSlice->listXsize[0], + currSlice->num_ref_idx_active[LIST_0]); + CHECK_VALID(currSlice->listXsize[0], 0); + if (h264_debug_flag & PRINT_FLAG_DPB_DETAIL) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "listX[0] reorder (PicNum): "); + for (i = 0; i < currSlice->listXsize[0]; i++) { + dpb_print_cont(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "%d ", + currSlice->listX[0][i]->pic_num); + } + dpb_print_cont(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "\n"); + } + } + + if (currSlice->slice_type == B_SLICE) { + if (currSlice->ref_pic_list_reordering_flag[LIST_1]) + reorder_ref_pic_list(currSlice, LIST_1); + if (p_Vid->no_reference_picture == + currSlice->listX[1][currSlice-> + num_ref_idx_active[LIST_1] - 1]) { + if (p_Vid->non_conforming_stream) + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "RefPicList1[ %d ] is equal to 'no reference picture'\n", + currSlice-> + num_ref_idx_active[LIST_1] - 1); + else + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "RefPicList1 [ num_ref_idx_l1_active_minus1 ] is equal to 'no reference picture', invalid bitstream %d\n", + 500); + } + /* that's a definition */ + currSlice->listXsize[1] = + (char)currSlice->num_ref_idx_active[LIST_1]; + if (h264_debug_flag & PRINT_FLAG_DPB_DETAIL) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "listX[1] reorder (PicNum): "); + for (i = 0; i < currSlice->listXsize[1]; i++) { + if (currSlice->listX[1][i]) + dpb_print_cont(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "%d ", + currSlice->listX[1][i]->pic_num); + } + dpb_print_cont(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "\n"); + } + } + + /* free_ref_pic_list_reordering_buffer(currSlice); */ + + if (currSlice->slice_type == P_SLICE) { +#if PRINTREFLIST + unsigned int i; +#if (MVC_EXTENSION_ENABLE) + /* print out for h264_debug_flag purpose */ + if ((p_Vid->profile_idc == MVC_HIGH || + p_Vid->profile_idc == STEREO_HIGH) && + currSlice->current_slice_nr == 0) { + if (currSlice->listXsize[0] > 0 + && (h264_debug_flag & PRINT_FLAG_DPB_DETAIL)) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "\n"); + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + " ** (FinalViewID:%d) %s Ref Pic List 0 ****\n", + currSlice->view_id, + currSlice->structure == FRAME ? + "FRM" : + (currSlice->structure == TOP_FIELD ? + "TOP" : "BOT")); + for (i = 0; i < (unsigned int)(currSlice-> + listXsize[0]); i++) { /* ref list 0 */ + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + " %2d -> POC: %4d PicNum: %4d ViewID: %d\n", + i, + currSlice->listX[0][i]->poc, + currSlice->listX[0][i]-> + pic_num, + currSlice->listX[0][i]-> + view_id); + } + } + } +#endif +#endif + } else if (currSlice->slice_type == B_SLICE) { +#if PRINTREFLIST + unsigned int i; +#if (MVC_EXTENSION_ENABLE) + /* print out for h264_debug_flag purpose */ + if ((p_Vid->profile_idc == MVC_HIGH || + p_Vid->profile_idc == STEREO_HIGH) && + currSlice->current_slice_nr == 0) { + if ((currSlice->listXsize[0] > 0) || + (currSlice->listXsize[1] > 0)) + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, "\n"); + if (currSlice->listXsize[0] > 0 + && (h264_debug_flag & PRINT_FLAG_DPB_DETAIL)) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + " ** (FinalViewID:%d) %s Ref Pic List 0 ****\n", + currSlice->view_id, + currSlice->structure == FRAME ? + "FRM" : + (currSlice->structure == TOP_FIELD ? + "TOP" : "BOT")); + for (i = 0; i < (unsigned int)(currSlice-> + listXsize[0]); i++) { /* ref list 0 */ + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + " %2d -> POC: %4d PicNum: %4d ViewID: %d\n", + i, + currSlice->listX[0][i]->poc, + currSlice->listX[0][i]-> + pic_num, + currSlice->listX[0][i]-> + view_id); + } + } + if (currSlice->listXsize[1] > 0 + && (h264_debug_flag & PRINT_FLAG_DPB_DETAIL)) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + " ** (FinalViewID:%d) %s Ref Pic List 1 ****\n", + currSlice->view_id, + currSlice->structure == FRAME ? + "FRM" : + (currSlice->structure == TOP_FIELD ? + "TOP" : "BOT")); + for (i = 0; i < (unsigned int)(currSlice-> + listXsize[1]); i++) { /* ref list 1 */ + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + " %2d -> POC: %4d PicNum: %4d ViewID: %d\n", + i, + currSlice->listX[1][i]->poc, + currSlice->listX[1][i]-> + pic_num, + currSlice->listX[1][i]-> + view_id); + } + } + } +#endif + +#endif + } +} + +void init_colocate_buf(struct h264_dpb_stru *p_H264_Dpb, int count) +{ + p_H264_Dpb->colocated_buf_map = 0; + p_H264_Dpb->colocated_buf_count = count; +} + +int allocate_colocate_buf(struct h264_dpb_stru *p_H264_Dpb) +{ + int i; + + for (i = 0; i < p_H264_Dpb->colocated_buf_count; i++) { + if (((p_H264_Dpb->colocated_buf_map >> i) & 0x1) == 0) { + p_H264_Dpb->colocated_buf_map |= (1 << i); + break; + } + } + if (i == p_H264_Dpb->colocated_buf_count) { + i = -1; + p_H264_Dpb->buf_alloc_fail = 1; + } + return i; +} + +int release_colocate_buf(struct h264_dpb_stru *p_H264_Dpb, int index) +{ + if (index >= 0) { + if (index >= p_H264_Dpb->colocated_buf_count) { + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_ERROR, + "%s error, index %d is bigger than buf count %d\n", + __func__, index, + p_H264_Dpb->colocated_buf_count); + } else { + if (((p_H264_Dpb->colocated_buf_map >> + index) & 0x1) == 0x1) { + p_H264_Dpb->colocated_buf_map &= + (~(1 << index)); + } else { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_ERROR, + "%s error, index %d is not allocated\n", + __func__, index); + } + } + } + return 0; +} + +void set_frame_output_flag(struct h264_dpb_stru *p_H264_Dpb, int index) +{ + struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; + + p_H264_Dpb->mFrameStore[index].is_output = 1; + p_H264_Dpb->mFrameStore[index].pre_output = 0; + p_H264_Dpb->mFrameStore[index].show_frame = false; + dump_dpb(p_Dpb, 0); +} + +#if 0 +void init_old_slice(OldSliceParams *p_old_slice) +{ + p_old_slice->field_pic_flag = 0; + p_old_slice->pps_id = INT_MAX; + p_old_slice->frame_num = INT_MAX; + p_old_slice->nal_ref_idc = INT_MAX; + p_old_slice->idr_flag = 0; + + p_old_slice->pic_oder_cnt_lsb = UINT_MAX; + p_old_slice->delta_pic_oder_cnt_bottom = INT_MAX; + + p_old_slice->delta_pic_order_cnt[0] = INT_MAX; + p_old_slice->delta_pic_order_cnt[1] = INT_MAX; +} + + +void copy_slice_info(struct Slice *currSlice, OldSliceParams *p_old_slice) +{ + struct VideoParameters *p_Vid = currSlice->p_Vid; + + p_old_slice->pps_id = currSlice->pic_parameter_set_id; + p_old_slice->frame_num = currSlice->frame_num; + /* p_Vid->frame_num; */ + p_old_slice->field_pic_flag = + currSlice->field_pic_flag; + /* p_Vid->field_pic_flag; */ + + if (currSlice->field_pic_flag) + p_old_slice->bottom_field_flag = currSlice->bottom_field_flag; + + p_old_slice->nal_ref_idc = currSlice->nal_reference_idc; + p_old_slice->idr_flag = (byte) currSlice->idr_flag; + + if (currSlice->idr_flag) + p_old_slice->idr_pic_id = currSlice->idr_pic_id; + + if (p_Vid->active_sps->pic_order_cnt_type == 0) { + p_old_slice->pic_oder_cnt_lsb = + currSlice->pic_order_cnt_lsb; + p_old_slice->delta_pic_oder_cnt_bottom = + currSlice->delta_pic_order_cnt_bottom; + } + + if (p_Vid->active_sps->pic_order_cnt_type == 1) { + p_old_slice->delta_pic_order_cnt[0] = + currSlice->delta_pic_order_cnt[0]; + p_old_slice->delta_pic_order_cnt[1] = + currSlice->delta_pic_order_cnt[1]; + } +#if (MVC_EXTENSION_ENABLE) + p_old_slice->view_id = currSlice->view_id; + p_old_slice->inter_view_flag = currSlice->inter_view_flag; + p_old_slice->anchor_pic_flag = currSlice->anchor_pic_flag; +#endif + p_old_slice->layer_id = currSlice->layer_id; +} + +int is_new_picture(StorablePicture *dec_picture, struct Slice *currSlice, + OldSliceParams *p_old_slice) +{ + struct VideoParameters *p_Vid = currSlice->p_Vid; + + int result = 0; + + result |= (dec_picture == NULL); + + result |= (p_old_slice->pps_id != currSlice->pic_parameter_set_id); + + result |= (p_old_slice->frame_num != currSlice->frame_num); + + result |= (p_old_slice->field_pic_flag != currSlice->field_pic_flag); + + if (currSlice->field_pic_flag && p_old_slice->field_pic_flag) { + result |= (p_old_slice->bottom_field_flag != + currSlice->bottom_field_flag); + } + + result |= (p_old_slice->nal_ref_idc != + currSlice->nal_reference_idc) && + ((p_old_slice->nal_ref_idc == 0) || + (currSlice->nal_reference_idc == 0)); + result |= (p_old_slice->idr_flag != currSlice->idr_flag); + + if (currSlice->idr_flag && p_old_slice->idr_flag) + result |= (p_old_slice->idr_pic_id != currSlice->idr_pic_id); + + if (p_Vid->active_sps->pic_order_cnt_type == 0) { + result |= (p_old_slice->pic_oder_cnt_lsb != + currSlice->pic_order_cnt_lsb); + if (p_Vid->active_pps-> + bottom_field_pic_order_in_frame_present_flag == 1 && + !currSlice->field_pic_flag) { + result |= (p_old_slice->delta_pic_oder_cnt_bottom != + currSlice->delta_pic_order_cnt_bottom); + } + } + + if (p_Vid->active_sps->pic_order_cnt_type == 1) { + if (!p_Vid->active_sps->delta_pic_order_always_zero_flag) { + result |= (p_old_slice->delta_pic_order_cnt[0] != + currSlice->delta_pic_order_cnt[0]); + if (p_Vid->active_pps-> + bottom_field_pic_order_in_frame_present_flag == 1 && + !currSlice->field_pic_flag) { + result |= (p_old_slice-> + delta_pic_order_cnt[1] != + currSlice->delta_pic_order_cnt[1]); + } + } + } + +#if (MVC_EXTENSION_ENABLE) + result |= (currSlice->view_id != p_old_slice->view_id); + result |= (currSlice->inter_view_flag != p_old_slice->inter_view_flag); + result |= (currSlice->anchor_pic_flag != p_old_slice->anchor_pic_flag); +#endif + result |= (currSlice->layer_id != p_old_slice->layer_id); + return result; +} +#else +int is_new_picture(struct StorablePicture *dec_picture, + struct h264_dpb_stru *p_H264_Dpb, + struct OldSliceParams *p_old_slice) +{ + int ret = 0; + + if (p_H264_Dpb->dpb_param.l.data[FIRST_MB_IN_SLICE] == 0) + ret = 1; + return ret; +} + +#endif + +/* +* release bufspec and pic for picture not in dpb buf +*/ +int release_picture(struct h264_dpb_stru *p_H264_Dpb, + struct StorablePicture *pic) +{ + struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; + + if (p_Dpb->last_picture == NULL) { + if (pic->colocated_buf_index >= 0) { + release_colocate_buf(p_H264_Dpb, + pic->colocated_buf_index); + pic->colocated_buf_index = -1; + } + release_buf_spec_num(p_H264_Dpb->vdec, pic->buf_spec_num); + } else { + if (pic->buf_spec_is_alloced == 1) + release_buf_spec_num(p_H264_Dpb->vdec, + pic->buf_spec_num); + } + + free_picture(p_H264_Dpb, pic); + return 0; +} + +#ifdef ERROR_HANDLE_TEST +/* +* remove all pictures in dpb and release bufspec/pic of them +*/ +void remove_dpb_pictures(struct h264_dpb_stru *p_H264_Dpb) +{ + /* struct VideoParameters *p_Vid = p_Dpb->p_Vid; */ + struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; + struct Slice *currSlice = &p_H264_Dpb->mSlice; + unsigned i, j; + + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s\n", __func__); + + if (!p_Dpb->init_done) + return; + + for (i = 0; i < p_Dpb->used_size; i++) { + if (p_Dpb->fs[i]->colocated_buf_index >= 0) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "release_colocate_buf[%d] for fs[%d]\n", + p_Dpb->fs[i]->colocated_buf_index, i); + + release_colocate_buf(p_H264_Dpb, + p_Dpb->fs[i]->colocated_buf_index); /* rain */ + p_Dpb->fs[i]->colocated_buf_index = -1; + } + if (!p_Dpb->fs[i]->pre_output) { + release_buf_spec_num(p_H264_Dpb->vdec, + p_Dpb->fs[i]->buf_spec_num); + p_Dpb->fs[i]->buf_spec_num = -1; + } + remove_frame_from_dpb(p_H264_Dpb, i); + } + + for (i = 0; i < p_Dpb->used_size; i++) { + p_Dpb->fs_ref[i] = NULL; + p_Dpb->fs_ltref[i] = NULL; + p_Dpb->fs_list0[i] = NULL; + p_Dpb->fs_list1[i] = NULL; + p_Dpb->fs_listlt[i] = NULL; + } + for (i = 0; i < 2; i++) { + currSlice->listXsize[i] = 0; + for (j = 0; j < (MAX_LIST_SIZE * 2); j++) + currSlice->listX[i][j] = NULL; + } + p_Dpb->ref_frames_in_buffer = 0; + p_Dpb->ltref_frames_in_buffer = 0; + p_Dpb->last_output_poc = INT_MIN; +} +#endif + +static void check_frame_store_same_pic_num(struct DecodedPictureBuffer *p_Dpb, + struct StorablePicture *p, struct Slice *currSlice) +{ + if (p_Dpb->last_picture) { + if ((int)p_Dpb->last_picture->frame_num == p->pic_num) { + if (((p->structure == TOP_FIELD) && + (p_Dpb->last_picture->is_used == 2)) || + ((p->structure == BOTTOM_FIELD) && + (p_Dpb->last_picture->is_used == 1))) { + if ((p->used_for_reference && + (p_Dpb->last_picture-> + is_orig_reference != 0)) || + (!p->used_for_reference && + (p_Dpb->last_picture-> + is_orig_reference == 0))) { + p->buf_spec_num = + p_Dpb->last_picture-> + buf_spec_num; + p->buf_spec_is_alloced = 0; + p->colocated_buf_index = p_Dpb-> + last_picture-> + colocated_buf_index; + if (currSlice->structure == + TOP_FIELD) { + p->bottom_poc = + p_Dpb->last_picture-> + bottom_field->poc; + } else { + p->top_poc = + p_Dpb->last_picture-> + top_field->poc; + } + p->frame_poc = imin(p->bottom_poc, + p->top_poc); + } + } + } + } +} + +int h264_slice_header_process(struct h264_dpb_stru *p_H264_Dpb, int *frame_num_gap) +{ + + int new_pic_flag = 0; + struct Slice *currSlice = &p_H264_Dpb->mSlice; + struct VideoParameters *p_Vid = &p_H264_Dpb->mVideo; + struct DecodedPictureBuffer *p_Dpb = + &p_H264_Dpb->mDPB; +#if 0 + new_pic_flag = is_new_picture(p_H264_Dpb->mVideo.dec_picture, + p_H264_Dpb, + &p_H264_Dpb->mVideo.old_slice); + + if (new_pic_flag) { /* new picture */ + if (p_H264_Dpb->mVideo.dec_picture) { + store_picture_in_dpb(p_H264_Dpb, + p_H264_Dpb->mVideo.dec_picture); + /* dump_dpb(&p_H264_Dpb->mDPB); */ + } + } +#else + new_pic_flag = (p_H264_Dpb->mVideo.dec_picture == NULL); +#endif + p_H264_Dpb->buf_alloc_fail = 0; + p_H264_Dpb->dpb_error_flag = 0; + slice_prepare(p_H264_Dpb, &p_H264_Dpb->mDPB, &p_H264_Dpb->mVideo, + &p_H264_Dpb->mSPS, &p_H264_Dpb->mSlice); + + if (p_Dpb->num_ref_frames != p_H264_Dpb->mSPS.num_ref_frames) { + dpb_print(p_H264_Dpb->decoder_index, 0, + "num_ref_frames change from %d to %d\r\n", + p_Dpb->num_ref_frames, p_H264_Dpb->mSPS.num_ref_frames); + p_Dpb->num_ref_frames = p_H264_Dpb->mSPS.num_ref_frames; + } + /* if (p_Vid->active_sps != sps) { */ + if (p_H264_Dpb->mDPB.init_done == 0) { + /*init_global_buffers(p_Vid, 0); + * ** * *if (!p_Vid->no_output_of_prior_pics_flag) + ** * *{ + ** * * flush_dpb(p_Vid->p_Dpb_layer[0]); + ** * *} + ** * *init_dpb(p_Vid, p_Vid->p_Dpb_layer[0], 0); + */ + init_dpb(p_H264_Dpb, 0); + } + + + if (new_pic_flag) { /* new picture */ + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "check frame_num gap: cur frame_num %d pre_frame_num %d max_frmae_num %d\r\n", + currSlice->frame_num, + p_Vid->pre_frame_num, + p_Vid->max_frame_num); + if (p_Vid->recovery_point == 0 && + p_Vid->max_frame_num <= FRAME_NUM_MAX_SIZE && + currSlice->frame_num != p_Vid->pre_frame_num && + currSlice->frame_num != + (p_Vid->pre_frame_num + 1) % p_Vid->max_frame_num) { + struct SPSParameters *active_sps = p_Vid->active_sps; + /*if (active_sps-> + *gaps_in_frame_num_value_allowed_flag + *== 0) { + * error("An unintentional + * loss of pictures occurs! Exit\n", + * 100); + *} + *if (p_Vid->conceal_mode == 0) + */ + if (active_sps->frame_num_gap_allowed) + fill_frame_num_gap(p_Vid, currSlice); + *frame_num_gap = 1; + } + + if (currSlice->nal_reference_idc) { + dpb_print(p_H264_Dpb->decoder_index, + PRINT_FLAG_DPB_DETAIL, + "nal_reference_idc not 0, set pre_frame_num(%d) to frame_num (%d)\n", + p_Vid->pre_frame_num, currSlice->frame_num); + p_Vid->pre_frame_num = currSlice->frame_num; + } + + decode_poc(&p_H264_Dpb->mVideo, &p_H264_Dpb->mSlice); + p_H264_Dpb->mVideo.dec_picture = get_new_pic(p_H264_Dpb, + p_H264_Dpb->mSlice.structure, + /*p_Vid->width, p_Vid->height, + * p_Vid->width_cr, + * p_Vid->height_cr, + */ + 1); + if (p_H264_Dpb->mVideo.dec_picture) { + u32 offset_lo, offset_hi; + struct DecodedPictureBuffer *p_Dpb = + &p_H264_Dpb->mDPB; + struct StorablePicture *p = + p_H264_Dpb->mVideo.dec_picture; + init_picture(p_H264_Dpb, &p_H264_Dpb->mSlice, + p_H264_Dpb->mVideo.dec_picture); +#if 1 + /* rain */ + offset_lo = + p_H264_Dpb->dpb_param.l.data[OFFSET_DELIMITER_LO]; + offset_hi = + p_H264_Dpb->dpb_param.l.data[OFFSET_DELIMITER_HI]; + p_H264_Dpb->mVideo.dec_picture->offset_delimiter = + (offset_lo | offset_hi << 16); + p_H264_Dpb->mVideo.dec_picture->buf_spec_num = -1; + p_H264_Dpb->mVideo.dec_picture-> + colocated_buf_index = -1; + update_pic_num(p_H264_Dpb); + + if ((currSlice->structure == TOP_FIELD) || + (currSlice->structure == BOTTOM_FIELD)) { + /* check for frame store with same + * pic_number + */ + check_frame_store_same_pic_num(p_Dpb, p, + currSlice); + } + + if (p_H264_Dpb->mVideo.dec_picture->buf_spec_num == + -1) { + p_H264_Dpb->mVideo.dec_picture->buf_spec_num = + get_free_buf_idx(p_H264_Dpb->vdec); + if (p_H264_Dpb->mVideo.dec_picture->buf_spec_num + < 0) { + p_H264_Dpb->buf_alloc_fail = 1; + p_H264_Dpb->mVideo.dec_picture-> + buf_spec_is_alloced = 0; + } else + p_H264_Dpb->mVideo.dec_picture-> + buf_spec_is_alloced = 1; + + if (p_H264_Dpb->mVideo.dec_picture-> + used_for_reference) { + p_H264_Dpb->mVideo.dec_picture-> + colocated_buf_index = + allocate_colocate_buf( + p_H264_Dpb); + } + } +#endif + if (post_picture_early(p_H264_Dpb->vdec, + p_H264_Dpb->mVideo.dec_picture->buf_spec_num)) + return -1; + } + } + + if (p_H264_Dpb->buf_alloc_fail) + return -1; + + if (p_H264_Dpb->mSlice.slice_type == P_SLICE) + init_lists_p_slice(&p_H264_Dpb->mSlice); + else if (p_H264_Dpb->mSlice.slice_type == B_SLICE) + init_lists_b_slice(&p_H264_Dpb->mSlice); + else + init_lists_i_slice(&p_H264_Dpb->mSlice); + + reorder_lists(&p_H264_Dpb->mSlice); + + if (p_H264_Dpb->mSlice.structure == FRAME) + init_mbaff_lists(p_H264_Dpb, &p_H264_Dpb->mSlice); + + if (new_pic_flag) + return 1; + + return 0; +} + +enum PictureStructure get_cur_slice_picture_struct( + struct h264_dpb_stru *p_H264_Dpb) +{ + struct Slice *currSlice = &p_H264_Dpb->mSlice; + return currSlice->structure; +} + +static unsigned char is_pic_in_dpb(struct h264_dpb_stru *p_H264_Dpb, + struct StorablePicture *pic) +{ + unsigned char ret = 0; + int i; + struct DecodedPictureBuffer *p_Dpb = + &p_H264_Dpb->mDPB; + for (i = 0; i < p_Dpb->used_size; i++) { + if (p_Dpb->fs[i]->top_field == pic || + p_Dpb->fs[i]->bottom_field == pic || + p_Dpb->fs[i]->frame == pic) { + ret = 1; + break; + } + } + return ret; +} + +int dpb_check_ref_list_error( + struct h264_dpb_stru *p_H264_Dpb) +{ + int i; + /*int j;*/ + struct Slice *currSlice = &p_H264_Dpb->mSlice; + /* in first output, ignore ref check */ + if ((p_H264_Dpb->first_insert_frame == FirstInsertFrm_OUT) && + (p_H264_Dpb->mVideo.dec_picture) && + p_H264_Dpb->first_output_poc > p_H264_Dpb->mVideo.dec_picture->poc) { + + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "p_H264_Dpb->first_output_poc %d, p_H264_Dpb->mVideo.dec_picture->poc %d\n", + p_H264_Dpb->first_output_poc, p_H264_Dpb->mVideo.dec_picture->poc); + return 0; + } + if ((currSlice->slice_type != I_SLICE) && + (currSlice->slice_type != SI_SLICE)) { + for (i = 0; i < currSlice->listXsize[0]; i++) { + /*for (j = i + 1; j < currSlice->listXsize[0]; j++) { + if(currSlice->listX[0][i]->pic_num == + currSlice->listX[0][j]->pic_num) + return 1; + }*/ + if (currSlice->listX[0][i] == NULL) + return 5; + if (!is_pic_in_dpb(p_H264_Dpb, + currSlice->listX[0][i])) + return 1; + if (currSlice->listX[0][i]->frame && + currSlice->listX[0][i]->frame->non_existing) + return 3; + } + } + + if (currSlice->slice_type == B_SLICE) { + for (i = 0; i < currSlice->listXsize[1]; i++) { + /*for (j = i + 1; j < currSlice->listXsize[1]; j++) { + if(currSlice->listX[1][i]->pic_num == + currSlice->listX[1][j]->pic_num) + return 2; + } + for (j = 0; j < currSlice->listXsize[0]; j++) { + if(currSlice->listX[1][i]->pic_num == + currSlice->listX[0][j]->pic_num) + return 3; + }*/ + if (currSlice->listX[1][i] == NULL) + return 6; + if (!is_pic_in_dpb(p_H264_Dpb, + currSlice->listX[1][i])) + return 2; + if (currSlice->listX[1][i]->frame && + currSlice->listX[1][i]->frame->non_existing) + return 4; +#if 0 + if (currSlice->listXsize[0] == 1 && + currSlice->listXsize[1] == 1 && + currSlice->listX[1][0] == + currSlice->listX[0][0]) + return 3; +#endif + } + } + return 0; +} +
diff --git a/drivers/frame_provider/decoder_v4l/h264_multi/h264_dpb.h b/drivers/frame_provider/decoder_v4l/h264_multi/h264_dpb.h new file mode 100644 index 0000000..e1d1ab4 --- /dev/null +++ b/drivers/frame_provider/decoder_v4l/h264_multi/h264_dpb.h
@@ -0,0 +1,1008 @@ +/* +* Copyright (C) 2017 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. +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, write to the Free Software Foundation, Inc., +* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +* Description: +*/ +#ifndef H264_DPB_H_ +#define H264_DPB_H_ + +#define ERROR_CHECK + +#define OUTPUT_BUFFER_IN_C + +#define PRINT_FLAG_ERROR 0x0 +#define PRINT_FLAG_VDEC_STATUS 0X0001 +#define PRINT_FLAG_UCODE_EVT 0x0002 +#define PRINT_FLAG_MMU_DETAIL 0x0004 +#define PRINT_FLAG_ERRORFLAG_DBG 0x0008 +#define PRINT_FLAG_DPB_DETAIL 0x0010 +#define PRINT_FLAG_DEC_DETAIL 0x0020 +#define PRINT_FLAG_VDEC_DETAIL 0x0040 +#define PRINT_FLAG_DUMP_DPB 0x0080 +#define PRINT_FRAMEBASE_DATA 0x0100 +#define PRINT_FLAG_DEBUG_POC 0x0200 +#define RRINT_FLAG_RPM 0x0400 +#define DEBUG_DISABLE_RUNREADY_RMBUF 0x0800 +#define PRINT_FLAG_DUMP_BUFSPEC 0x1000 +#define PRINT_FLAG_FCC_STATUS 0x2000 +#define PRINT_FLAG_SEI_DETAIL 0x4000 +#define PRINT_FLAG_V4L_DETAIL 0x8000 +#define DISABLE_ERROR_HANDLE 0x10000 +#define DEBUG_DUMP_STAT 0x80000 +#define DEBUG_TIMEOUT_DEC_STAT 0x800000 + +/*setting canvas mode and endian. + if this flag is set, value of canvas mode + will according to the value of mem_map_mode. + endian will be forced set to 0 in + CANVAS_BLKMODE_LINEAR mode. + otherwise picture will display abnormal. + if this flag is not set, value of canvas mode + will be determined by the user speace config. + endian will be set 7 in CANVAS_BLKMODE_LINEAR mode. +*/ +#define IGNORE_PARAM_FROM_CONFIG 0x8000000 + +#define MVC_EXTENSION_ENABLE 0 +#define PRINTREFLIST 0 + +#define MAX_LIST_SIZE 33 + +#define H264_OUTPUT_MODE_NORMAL 0x4 +#define H264_OUTPUT_MODE_FAST 0x8 + +//#define FALSE 0 + +#define H264_SLICE_HEAD_DONE 0x01 +#define H264_PIC_DATA_DONE 0x02 +/*#define H264_SPS_DONE 0x03*/ +/*#define H264_PPS_DONE 0x04*/ +/*#define H264_SLICE_DATA_DONE 0x05*/ +/*#define H264_DATA_END 0x06*/ + +#define H264_CONFIG_REQUEST 0x11 +#define H264_DATA_REQUEST 0x12 +#define H264_WRRSP_REQUEST 0x13 +#define H264_WRRSP_DONE 0x14 + +#define H264_DECODE_BUFEMPTY 0x20 +#define H264_DECODE_TIMEOUT 0x21 +#define H264_SEARCH_BUFEMPTY 0x22 +#define H264_DECODE_OVER_SIZE 0x23 + +#define VIDEO_SIGNAL_LOW 0x26 +#define VIDEO_SIGNAL_HIGHT 0x27 + + +#define H264_FIND_NEXT_PIC_NAL 0x50 +#define H264_FIND_NEXT_DVEL_NAL 0x51 +#define H264_AUX_DATA_READY 0x52 + +#define H264_SEI_DATA_READY 0x53 +#define H264_SEI_DATA_DONE 0x54 + + /* 0x8x, search state*/ +#define H264_STATE_SEARCH_AFTER_SPS 0x80 +#define H264_STATE_SEARCH_AFTER_PPS 0x81 +#define H264_STATE_PARSE_SLICE_HEAD 0x82 +#define H264_STATE_SEARCH_HEAD 0x83 + /**/ +#define H264_ACTION_SEARCH_HEAD 0xf0 +#define H264_ACTION_DECODE_SLICE 0xf1 +#define H264_ACTION_CONFIG_DONE 0xf2 +#define H264_ACTION_DECODE_NEWPIC 0xf3 +#define H264_ACTION_DECODE_START 0xff + +#define RPM_BEGIN 0x0 +#define RPM_END 0x400 + +#define val(s) (s[0]|(s[1]<<16)) + +#define FRAME_IN_DPB 24 +#define DPB_OFFSET 0x100 +#define MMCO_OFFSET 0x200 +union param { +#if 0 +#define H_TIME_STAMP_START 0X00 +#define H_TIME_STAMP_END 0X17 +#define PTS_ZERO_0 0X18 +#define PTS_ZERO_1 0X19 +#endif +#define FIXED_FRAME_RATE_FLAG 0X21 + +#define OFFSET_DELIMITER_LO 0x2f +#define OFFSET_DELIMITER_HI 0x30 + + +#define SLICE_IPONLY_BREAK 0X5C +#define PREV_MAX_REFERENCE_FRAME_NUM 0X5D +#define EOS 0X5E +#define FRAME_PACKING_TYPE 0X5F +#define OLD_POC_PAR_1 0X60 +#define OLD_POC_PAR_2 0X61 +#define PREV_MBX 0X62 +#define PREV_MBY 0X63 +#define ERROR_SKIP_MB_NUM 0X64 +#define ERROR_MB_STATUS 0X65 +#define L0_PIC0_STATUS 0X66 +#define TIMEOUT_COUNTER 0X67 +#define BUFFER_SIZE 0X68 +#define BUFFER_SIZE_HI 0X69 +#define CROPPING_LEFT_RIGHT 0X6A +#define CROPPING_TOP_BOTTOM 0X6B +#if 1 + /* sps_flags2: + *bit 3, bitstream_restriction_flag + *bit 2, pic_struct_present_flag + *bit 1, vcl_hrd_parameters_present_flag + *bit 0, nal_hrd_parameters_present_flag + */ +#define SPS_FLAGS2 0x6c +#define NUM_REORDER_FRAMES 0x6d +#else +#define POC_SELECT_NEED_SWAP 0X6C +#define POC_SELECT_SWAP 0X6D +#endif +#define MAX_BUFFER_FRAME 0X6E + +#define NON_CONFORMING_STREAM 0X70 +#define RECOVERY_POINT 0X71 +#define POST_CANVAS 0X72 +#define POST_CANVAS_H 0X73 +#define SKIP_PIC_COUNT 0X74 +#define TARGET_NUM_SCALING_LIST 0X75 +#define FF_POST_ONE_FRAME 0X76 +#define PREVIOUS_BIT_CNT 0X77 +#define MB_NOT_SHIFT_COUNT 0X78 +#define PIC_STATUS 0X79 +#define FRAME_COUNTER 0X7A +#define NEW_SLICE_TYPE 0X7B +#define NEW_PICTURE_STRUCTURE 0X7C +#define NEW_FRAME_NUM 0X7D +#define NEW_IDR_PIC_ID 0X7E +#define IDR_PIC_ID 0X7F + +/* h264 LOCAL */ +#define NAL_UNIT_TYPE 0X80 +#define NAL_REF_IDC 0X81 +#define SLICE_TYPE 0X82 +#define LOG2_MAX_FRAME_NUM 0X83 +#define FRAME_MBS_ONLY_FLAG 0X84 +#define PIC_ORDER_CNT_TYPE 0X85 +#define LOG2_MAX_PIC_ORDER_CNT_LSB 0X86 +#define PIC_ORDER_PRESENT_FLAG 0X87 +#define REDUNDANT_PIC_CNT_PRESENT_FLAG 0X88 +#define PIC_INIT_QP_MINUS26 0X89 +#define DEBLOCKING_FILTER_CONTROL_PRESENT_FLAG 0X8A +#define NUM_SLICE_GROUPS_MINUS1 0X8B +#define MODE_8X8_FLAGS 0X8C +#define ENTROPY_CODING_MODE_FLAG 0X8D +#define SLICE_QUANT 0X8E +#define TOTAL_MB_HEIGHT 0X8F +#define PICTURE_STRUCTURE 0X90 +#define TOP_INTRA_TYPE 0X91 +#define RV_AI_STATUS 0X92 +#define AI_READ_START 0X93 +#define AI_WRITE_START 0X94 +#define AI_CUR_BUFFER 0X95 +#define AI_DMA_BUFFER 0X96 +#define AI_READ_OFFSET 0X97 +#define AI_WRITE_OFFSET 0X98 +#define AI_WRITE_OFFSET_SAVE 0X99 +#define RV_AI_BUFF_START 0X9A +#define I_PIC_MB_COUNT 0X9B +#define AI_WR_DCAC_DMA_CTRL 0X9C +#define SLICE_MB_COUNT 0X9D +#define PICTYPE 0X9E +#define SLICE_GROUP_MAP_TYPE 0X9F +#define MB_TYPE 0XA0 +#define MB_AFF_ADDED_DMA 0XA1 +#define PREVIOUS_MB_TYPE 0XA2 +#define WEIGHTED_PRED_FLAG 0XA3 +#define WEIGHTED_BIPRED_IDC 0XA4 +/* bit 3:2 - PICTURE_STRUCTURE + * bit 1 - MB_ADAPTIVE_FRAME_FIELD_FLAG + * bit 0 - FRAME_MBS_ONLY_FLAG + */ +#define MBFF_INFO 0XA5 +#define TOP_INTRA_TYPE_TOP 0XA6 + +#define RV_AI_BUFF_INC 0xa7 + +#define DEFAULT_MB_INFO_LO 0xa8 + +/* 0 -- no need to read + * 1 -- need to wait Left + * 2 -- need to read Intra + * 3 -- need to read back MV + */ +#define NEED_READ_TOP_INFO 0xa9 +/* 0 -- idle + * 1 -- wait Left + * 2 -- reading top Intra + * 3 -- reading back MV + */ +#define READ_TOP_INFO_STATE 0xaa +#define DCAC_MBX 0xab +#define TOP_MB_INFO_OFFSET 0xac +#define TOP_MB_INFO_RD_IDX 0xad +#define TOP_MB_INFO_WR_IDX 0xae + +#define VLD_NO_WAIT 0 +#define VLD_WAIT_BUFFER 1 +#define VLD_WAIT_HOST 2 +#define VLD_WAIT_GAP 3 + +#define VLD_WAITING 0xaf + +#define MB_X_NUM 0xb0 +/* #define MB_WIDTH 0xb1 */ +#define MB_HEIGHT 0xb2 +#define MBX 0xb3 +#define TOTAL_MBY 0xb4 +#define INTR_MSK_SAVE 0xb5 + +/* #define has_time_stamp 0xb6 */ +#define NEED_DISABLE_PPE 0xb6 +#define IS_NEW_PICTURE 0XB7 +#define PREV_NAL_REF_IDC 0XB8 +#define PREV_NAL_UNIT_TYPE 0XB9 +#define FRAME_MB_COUNT 0XBA +#define SLICE_GROUP_UCODE 0XBB +#define SLICE_GROUP_CHANGE_RATE 0XBC +#define SLICE_GROUP_CHANGE_CYCLE_LEN 0XBD +#define DELAY_LENGTH 0XBE +#define PICTURE_STRUCT 0XBF +/* #define pre_picture_struct 0xc0 */ +#define DCAC_PREVIOUS_MB_TYPE 0xc1 + +#define TIME_STAMP 0XC2 +#define H_TIME_STAMP 0XC3 +#define VPTS_MAP_ADDR 0XC4 +#define H_VPTS_MAP_ADDR 0XC5 + +/*#define MAX_DPB_SIZE 0XC6*/ +#define PIC_INSERT_FLAG 0XC7 + +#define TIME_STAMP_START 0XC8 +#define TIME_STAMP_END 0XDF + +#define OFFSET_FOR_NON_REF_PIC 0XE0 +#define OFFSET_FOR_TOP_TO_BOTTOM_FIELD 0XE2 +#define MAX_REFERENCE_FRAME_NUM 0XE4 +#define FRAME_NUM_GAP_ALLOWED 0XE5 +#define NUM_REF_FRAMES_IN_PIC_ORDER_CNT_CYCLE 0XE6 +#define PROFILE_IDC_MMCO 0XE7 +#define LEVEL_IDC_MMCO 0XE8 +#define FRAME_SIZE_IN_MB 0XE9 +#define DELTA_PIC_ORDER_ALWAYS_ZERO_FLAG 0XEA +#define PPS_NUM_REF_IDX_L0_ACTIVE_MINUS1 0XEB +#define PPS_NUM_REF_IDX_L1_ACTIVE_MINUS1 0XEC +#define CURRENT_SPS_ID 0XED +#define CURRENT_PPS_ID 0XEE +/* bit 0 - sequence parameter set may change + * bit 1 - picture parameter set may change + * bit 2 - new dpb just inited + * bit 3 - IDR picture not decoded yet + * bit 5:4 - 0: mb level code loaded 1: picture + * level code loaded 2: slice level code loaded + */ +#define DECODE_STATUS 0XEF +#define FIRST_MB_IN_SLICE 0XF0 +#define PREV_MB_WIDTH 0XF1 +#define PREV_FRAME_SIZE_IN_MB 0XF2 +/*#define MAX_REFERENCE_FRAME_NUM_IN_MEM 0XF3*/ +/* bit 0 - aspect_ratio_info_present_flag + * bit 1 - timing_info_present_flag + * bit 2 - nal_hrd_parameters_present_flag + * bit 3 - vcl_hrd_parameters_present_flag + * bit 4 - pic_struct_present_flag + * bit 5 - bitstream_restriction_flag + */ +#define VUI_STATUS 0XF4 +#define ASPECT_RATIO_IDC 0XF5 +#define ASPECT_RATIO_SAR_WIDTH 0XF6 +#define ASPECT_RATIO_SAR_HEIGHT 0XF7 +#define NUM_UNITS_IN_TICK 0XF8 +#define TIME_SCALE 0XFA +#define CURRENT_PIC_INFO 0XFC +#define DPB_BUFFER_INFO 0XFD +#define REFERENCE_POOL_INFO 0XFE +#define REFERENCE_LIST_INFO 0XFF + struct{ + unsigned short data[RPM_END-RPM_BEGIN]; + } l; + struct{ + unsigned short dump[DPB_OFFSET]; + unsigned short dpb_base[FRAME_IN_DPB<<3]; + + unsigned short dpb_max_buffer_frame; + unsigned short actual_dpb_size; + + unsigned short colocated_buf_status; + + unsigned short num_forward_short_term_reference_pic; + unsigned short num_short_term_reference_pic; + unsigned short num_reference_pic; + + unsigned short current_dpb_index; + unsigned short current_decoded_frame_num; + unsigned short current_reference_frame_num; + + unsigned short l0_size; + unsigned short l1_size; + + /* [6:5] : nal_ref_idc */ + /* [4:0] : nal_unit_type */ + unsigned short NAL_info_mmco; + + /* [1:0] : 00 - top field, 01 - bottom field, + * 10 - frame, 11 - mbaff frame + */ + unsigned short picture_structure_mmco; + + unsigned short frame_num; + unsigned short pic_order_cnt_lsb; + + unsigned short num_ref_idx_l0_active_minus1; + unsigned short num_ref_idx_l1_active_minus1; + + unsigned short PrevPicOrderCntLsb; + unsigned short PreviousFrameNum; + + /* 32 bits variables */ + unsigned short delta_pic_order_cnt_bottom[2]; + unsigned short delta_pic_order_cnt_0[2]; + unsigned short delta_pic_order_cnt_1[2]; + + unsigned short PrevPicOrderCntMsb[2]; + unsigned short PrevFrameNumOffset[2]; + + unsigned short frame_pic_order_cnt[2]; + unsigned short top_field_pic_order_cnt[2]; + unsigned short bottom_field_pic_order_cnt[2]; + + unsigned short colocated_mv_addr_start[2]; + unsigned short colocated_mv_addr_end[2]; + unsigned short colocated_mv_wr_addr[2]; + + unsigned short frame_crop_left_offset; + unsigned short frame_crop_right_offset; + unsigned short frame_crop_top_offset; + unsigned short frame_crop_bottom_offset; + unsigned short chroma_format_idc; + } dpb; + struct { + unsigned short dump[MMCO_OFFSET]; + + /* array base address for offset_for_ref_frame */ + unsigned short offset_for_ref_frame_base[128]; + + /* 0 - Index in DPB + * 1 - Picture Flag + * [ 2] : 0 - short term reference, + * 1 - long term reference + * [ 1] : bottom field + * [ 0] : top field + * 2 - Picture Number (short term or long term) low 16 bits + * 3 - Picture Number (short term or long term) high 16 bits + */ + unsigned short reference_base[128]; + + /* command and parameter, until command is 3 */ + unsigned short l0_reorder_cmd[66]; + unsigned short l1_reorder_cmd[66]; + + /* command and parameter, until command is 0 */ + unsigned short mmco_cmd[44]; + + unsigned short l0_base[40]; + unsigned short l1_base[40]; + } mmco; + struct { + /* from ucode lmem, do not change this struct */ + } p; +}; + + +struct StorablePicture; +struct VideoParameters; +struct DecodedPictureBuffer; + +/* New enum for field processing */ +enum PictureStructure { + FRAME, + TOP_FIELD, + BOTTOM_FIELD +}; + +typedef enum { + PIC_SINGLE_FRAME = 0, + PIC_TOP, + PIC_BOT, + PIC_TOP_BOT, + PIC_BOT_TOP, + PIC_TOP_BOT_TOP = 5, + PIC_BOT_TOP_BOT, + PIC_DOUBLE_FRAME, + PIC_TRIPLE_FRAME, + PIC_INVALID, +} PicStruct_E; + +#define I_Slice 2 +#define P_Slice 5 +#define B_Slice 6 +#define P_Slice_0 0 +#define B_Slice_1 1 +#define I_Slice_7 7 + +enum SliceType { + P_SLICE = 0, + B_SLICE = 1, + I_SLICE = 2, + SP_SLICE = 3, + SI_SLICE = 4, + NUM_SLICE_TYPES = 5 +}; + +enum ProfileIDC { + FREXT_CAVLC444 = 44, /*!< YUV 4:4:4/14 "CAVLC 4:4:4"*/ + BASELINE = 66, /*!< YUV 4:2:0/8 "Baseline"*/ + MAIN = 77, /*!< YUV 4:2:0/8 "Main"*/ + EXTENDED = 88, /*!< YUV 4:2:0/8 "Extended"*/ + FREXT_HP = 100, /*!< YUV 4:2:0/8 "High"*/ + FREXT_Hi10P = 110, /*!< YUV 4:2:0/10 "High 10"*/ + FREXT_Hi422 = 122, /*!< YUV 4:2:2/10 "High 4:2:2"*/ + FREXT_Hi444 = 244, /*!< YUV 4:4:4/14 "High 4:4:4"*/ + MVC_HIGH = 118, /*!< YUV 4:2:0/8 "Multiview High"*/ + STEREO_HIGH = 128 /*!< YUV 4:2:0/8 "Stereo High"*/ +}; + +enum FirstInsertFrm_State { + FirstInsertFrm_IDLE = 0, + FirstInsertFrm_OUT = 1, + FirstInsertFrm_RESET = 2, + FirstInsertFrm_SKIPDONE = 3, +}; + + +struct SPSParameters { + unsigned int profile_idc; + unsigned int level_idc; + int pic_order_cnt_type; + int log2_max_pic_order_cnt_lsb_minus4; + int num_ref_frames_in_pic_order_cnt_cycle; + short offset_for_ref_frame[128]; + short offset_for_non_ref_pic; + short offset_for_top_to_bottom_field; + + /**/ + int frame_mbs_only_flag; + int num_ref_frames; + int max_dpb_size; + int log2_max_frame_num_minus4; + int frame_num_gap_allowed; +}; + +#define DEC_REF_PIC_MARKING_BUFFER_NUM_MAX 45 +struct DecRefPicMarking_s { + int memory_management_control_operation; + int difference_of_pic_nums_minus1; + int long_term_pic_num; + int long_term_frame_idx; + int max_long_term_frame_idx_plus1; + struct DecRefPicMarking_s *Next; +}; + +#define REORDERING_COMMAND_MAX_SIZE 33 +struct Slice { + int first_mb_in_slice; + int mode_8x8_flags; + int picture_structure_mmco; + + int frame_num; + int idr_flag; + int toppoc; + int bottompoc; + int framepoc; + int pic_order_cnt_lsb; + int PicOrderCntMsb; + unsigned char field_pic_flag; + unsigned char bottom_field_flag; + int ThisPOC; + int nal_reference_idc; + int AbsFrameNum; + int delta_pic_order_cnt_bottom; + int delta_pic_order_cnt[2]; + + /**/ + char listXsize[6]; + struct StorablePicture *listX[6][MAX_LIST_SIZE * 2]; + + /**/ + enum PictureStructure structure; + int long_term_reference_flag; + int no_output_of_prior_pics_flag; + int adaptive_ref_pic_buffering_flag; + + struct VideoParameters *p_Vid; + struct DecodedPictureBuffer *p_Dpb; + int num_ref_idx_active[2]; /* number of available list references */ + + /*modification*/ + int slice_type; /* slice type */ + int ref_pic_list_reordering_flag[2]; + int modification_of_pic_nums_idc[2][REORDERING_COMMAND_MAX_SIZE]; + int abs_diff_pic_num_minus1[2][REORDERING_COMMAND_MAX_SIZE]; + int long_term_pic_idx[2][REORDERING_COMMAND_MAX_SIZE]; + /**/ + unsigned char dec_ref_pic_marking_buffer_valid; + struct DecRefPicMarking_s + dec_ref_pic_marking_buffer[DEC_REF_PIC_MARKING_BUFFER_NUM_MAX]; + int pic_struct; +}; + +struct OldSliceParams { + unsigned int field_pic_flag; + unsigned int frame_num; + int nal_ref_idc; + unsigned int pic_oder_cnt_lsb; + int delta_pic_oder_cnt_bottom; + int delta_pic_order_cnt[2]; + unsigned char bottom_field_flag; + unsigned char idr_flag; + int idr_pic_id; + int pps_id; +#if (MVC_EXTENSION_ENABLE) + int view_id; + int inter_view_flag; + int anchor_pic_flag; +#endif + int layer_id; +}; + +struct VideoParameters { + int PrevPicOrderCntMsb; + int PrevPicOrderCntLsb; + unsigned char last_has_mmco_5; + unsigned char last_pic_bottom_field; + int ThisPOC; + int PreviousFrameNum; + int FrameNumOffset; + int PreviousFrameNumOffset; + int max_frame_num; + unsigned int pre_frame_num; + int ExpectedDeltaPerPicOrderCntCycle; + int PicOrderCntCycleCnt; + int FrameNumInPicOrderCntCycle; + int ExpectedPicOrderCnt; + + /**/ + struct SPSParameters *active_sps; + struct Slice **ppSliceList; + int iSliceNumOfCurrPic; + int conceal_mode; + int earlier_missing_poc; + int pocs_in_dpb[100]; + + struct OldSliceParams old_slice; + /**/ + struct StorablePicture *dec_picture; + struct StorablePicture *no_reference_picture; + + /*modification*/ + int non_conforming_stream; + int recovery_point; +}; + +static inline int imin(int a, int b) +{ + return ((a) < (b)) ? (a) : (b); +} + +static inline int imax(int a, int b) +{ + return ((a) > (b)) ? (a) : (b); +} + +#define MAX_PIC_BUF_NUM 128 +#define MAX_NUM_SLICES 50 + +struct StorablePicture { +/**/ + int width; + int height; + + int y_canvas_index; + int u_canvas_index; + int v_canvas_index; +/**/ + int index; + unsigned char is_used; + + enum PictureStructure structure; + + int poc; + int top_poc; + int bottom_poc; + int frame_poc; + unsigned int frame_num; + unsigned int recovery_frame; + + int pic_num; + int buf_spec_num; + int buf_spec_is_alloced; + int colocated_buf_index; + int long_term_pic_num; + int long_term_frame_idx; + + unsigned char is_long_term; + int used_for_reference; + int is_output; +#if 1 + /* rain */ + int pre_output; +#endif + int non_existing; + int separate_colour_plane_flag; + + short max_slice_id; + + int size_x, size_y, size_x_cr, size_y_cr; + int size_x_m1, size_y_m1, size_x_cr_m1, size_y_cr_m1; + int coded_frame; + int mb_aff_frame_flag; + unsigned int PicWidthInMbs; + unsigned int PicSizeInMbs; + int iLumaPadY, iLumaPadX; + int iChromaPadY, iChromaPadX; + + /* for mb aff, if frame for referencing the top field */ + struct StorablePicture *top_field; + /* for mb aff, if frame for referencing the bottom field */ + struct StorablePicture *bottom_field; + /* for mb aff, if field for referencing the combined frame */ + struct StorablePicture *frame; + + int slice_type; + int idr_flag; + int no_output_of_prior_pics_flag; + int long_term_reference_flag; + int adaptive_ref_pic_buffering_flag; + + int chroma_format_idc; + int frame_mbs_only_flag; + int frame_cropping_flag; + int frame_crop_left_offset; + int frame_crop_right_offset; + int frame_crop_top_offset; + int frame_crop_bottom_offset; + int qp; + int chroma_qp_offset[2]; + int slice_qp_delta; + /* stores the memory management control operations */ + struct DecRefPicMarking_s *dec_ref_pic_marking_buffer; + + /* picture error concealment */ + /*indicates if this is a concealed picture */ + int concealed_pic; + + /* variables for tone mapping */ + int seiHasTone_mapping; + int tone_mapping_model_id; + int tonemapped_bit_depth; + /* imgpel* tone_mapping_lut; tone mapping look up table */ + + int proc_flag; +#if (MVC_EXTENSION_ENABLE) + int view_id; + int inter_view_flag; + int anchor_pic_flag; +#endif + int iLumaStride; + int iChromaStride; + int iLumaExpandedHeight; + int iChromaExpandedHeight; + /* imgpel **cur_imgY; for more efficient get_block_luma */ + int no_ref; + int iCodingType; + + char listXsize[MAX_NUM_SLICES][2]; + struct StorablePicture **listX[MAX_NUM_SLICES][2]; + int layer_id; + u32 offset_delimiter; + u32 pts; + u64 pts64; + u64 timestamp; + unsigned char data_flag; + int pic_struct; + + /* picture qos infomation*/ + int frame_size; + int max_qp; + int avg_qp; + int min_qp; + int max_skip; + int avg_skip; + int min_skip; + int max_mv; + int min_mv; + int avg_mv; + u32 pic_size; +}; + +struct FrameStore { + /* rain */ + int buf_spec_num; + /* rain */ + int colocated_buf_index; + + /* 0=empty; 1=top; 2=bottom; 3=both fields (or frame) */ + int is_used; + /* 0=not used for ref; 1=top used; 2=bottom used; + * 3=both fields (or frame) used + */ + int is_reference; + /* 0=not used for ref; 1=top used; 2=bottom used; + * 3=both fields (or frame) used + */ + int is_long_term; + /* original marking by nal_ref_idc: 0=not used for ref; 1=top used; + * 2=bottom used; 3=both fields (or frame) used + */ + int is_orig_reference; + + int is_non_existent; + + unsigned int frame_num; + unsigned int recovery_frame; + + int frame_num_wrap; + int long_term_frame_idx; + int is_output; +#if 1 + /* rain */ + int pre_output; + /* index in gFrameStore */ + int index; +#define I_FLAG 0x01 +#define IDR_FLAG 0x02 +#define ERROR_FLAG 0x10 +#define NULL_FLAG 0x20 +#define NODISP_FLAG 0x80 + unsigned char data_flag; +#endif + int poc; + + /* picture error concealment */ + int concealment_reference; + + struct StorablePicture *frame; + struct StorablePicture *top_field; + struct StorablePicture *bottom_field; + +#if (MVC_EXTENSION_ENABLE) + int view_id; + int inter_view_flag[2]; + int anchor_pic_flag[2]; +#endif + int layer_id; + u32 offset_delimiter; + u32 pts; + u64 pts64; + u64 timestamp; + + + /* picture qos infomation*/ + int slice_type; + int frame_size; + + int max_qp; + int avg_qp; + int min_qp; + int max_skip; + int avg_skip; + int min_skip; + int max_mv; + int min_mv; + int avg_mv; + int dpb_frame_count; + u32 hw_decode_time; + u32 frame_size2; // For recording the chunk->size in frame mode + bool show_frame; + struct dma_fence *fence; + u32 decoded_frame_size; + u64 last_field_timestamp; +}; + +/* #define DPB_SIZE_MAX 16 */ +#define DPB_SIZE_MAX 32 +struct DecodedPictureBuffer { + struct VideoParameters *p_Vid; + /* InputParameters *p_Inp; ??? */ + struct FrameStore *fs[DPB_SIZE_MAX]; + struct FrameStore *fs_ref[DPB_SIZE_MAX]; + struct FrameStore *fs_ltref[DPB_SIZE_MAX]; + /* inter-layer reference (for multi-layered codecs) */ + struct FrameStore *fs_ilref[DPB_SIZE_MAX]; + /**/ + struct FrameStore *fs_list0[DPB_SIZE_MAX]; + struct FrameStore *fs_list1[DPB_SIZE_MAX]; + struct FrameStore *fs_listlt[DPB_SIZE_MAX]; + + /**/ + unsigned int size; + unsigned int used_size; + unsigned int ref_frames_in_buffer; + unsigned int ltref_frames_in_buffer; + int last_output_poc; +#if (MVC_EXTENSION_ENABLE) + int last_output_view_id; +#endif + int max_long_term_pic_idx; + + + int init_done; + int first_pic_done; /*by rain*/ + int num_ref_frames; + + struct FrameStore *last_picture; + unsigned int used_size_il; + int layer_id; + + /* DPB related function; */ +}; + +struct h264_dpb_stru { + struct vdec_s *vdec; + int decoder_index; + + union param dpb_param; + + int decode_idx; + int buf_num; + int curr_POC; + int reorder_pic_num; + unsigned int dec_dpb_size; + u8 fast_output_enable; + /*poc_even_flag: + 0, init; 1, odd; 2, even*/ + u8 poc_even_odd_flag; + u32 decode_pic_count; + /**/ + unsigned int max_reference_size; + + unsigned int colocated_buf_map; + unsigned int colocated_buf_count; + unsigned int colocated_mv_addr_start; + unsigned int colocated_mv_addr_end; + unsigned int colocated_buf_size; + + struct DecodedPictureBuffer mDPB; + struct Slice mSlice; + struct VideoParameters mVideo; + struct SPSParameters mSPS; + + struct StorablePicture m_PIC[MAX_PIC_BUF_NUM]; + struct FrameStore mFrameStore[DPB_SIZE_MAX]; + + /*vui*/ + unsigned int vui_status; + unsigned int num_units_in_tick; + unsigned int time_scale; + unsigned int fixed_frame_rate_flag; + unsigned int aspect_ratio_idc; + unsigned int aspect_ratio_sar_width; + unsigned int aspect_ratio_sar_height; + u8 bitstream_restriction_flag; + u16 num_reorder_frames; + u16 max_dec_frame_buffering; + + unsigned int frame_crop_left_offset; + unsigned int frame_crop_right_offset; + unsigned int frame_crop_top_offset; + unsigned int frame_crop_bottom_offset; + unsigned int chroma_format_idc; + + unsigned int dec_dpb_status; + unsigned int last_dpb_status; + unsigned char buf_alloc_fail; + unsigned int dpb_error_flag; + unsigned int reorder_output; + unsigned int first_insert_frame; + int first_output_poc; + int dpb_frame_count; + /* need wait aux data when there is data after pic done in dv stream */ + bool wait_aux_data_flag; + u32 without_display_mode; + int long_term_reference_flag; +}; + + +extern unsigned int h264_debug_flag; +extern unsigned int h264_debug_mask; + +int dpb_print(int indext, int debug_flag, const char *fmt, ...); + +int dpb_print_cont(int index, int debug_flag, const char *fmt, ...); + +unsigned char dpb_is_debug(int index, int debug_flag); + +int prepare_display_buf(struct vdec_s *vdec, struct FrameStore *frame); + +int release_buf_spec_num(struct vdec_s *vdec, int buf_spec_num); + +void set_frame_output_flag(struct h264_dpb_stru *p_H264_Dpb, int index); + +int is_there_unused_frame_from_dpb(struct DecodedPictureBuffer *p_Dpb); + +int h264_slice_header_process(struct h264_dpb_stru *p_H264_Dpb, int *frame_num_gap); + +void dpb_init_global(struct h264_dpb_stru *p_H264_Dpb, + int id, int actual_dpb_size, int max_reference_size); + +void init_colocate_buf(struct h264_dpb_stru *p_H264_Dpb, int count); + +int release_colocate_buf(struct h264_dpb_stru *p_H264_Dpb, int index); + +int get_free_buf_idx(struct vdec_s *vdec); + +int store_picture_in_dpb(struct h264_dpb_stru *p_H264_Dpb, + struct StorablePicture *p, unsigned char data_flag); + +int release_picture(struct h264_dpb_stru *p_H264_Dpb, + struct StorablePicture *pic); + +void remove_dpb_pictures(struct h264_dpb_stru *p_H264_Dpb); + +void bufmgr_post(struct h264_dpb_stru *p_H264_Dpb); + +void bufmgr_force_recover(struct h264_dpb_stru *p_H264_Dpb); + +int get_long_term_flag_by_buf_spec_num(struct h264_dpb_stru *p_H264_Dpb, + int buf_spec_num); + +void bufmgr_h264_remove_unused_frame(struct h264_dpb_stru *p_H264_Dpb, + u8 force_flag); + +void flush_dpb(struct h264_dpb_stru *p_H264_Dpb); + +void print_pic_info(int decindex, const char *info, + struct StorablePicture *pic, + int slice_type); +void dump_dpb(struct DecodedPictureBuffer *p_Dpb, u8 force); + +void dump_pic(struct h264_dpb_stru *p_H264_Dpb); + +void * vh264_get_bufspec_lock(struct vdec_s *vdec); + +enum PictureStructure get_cur_slice_picture_struct( + struct h264_dpb_stru *p_H264_Dpb); + +int dpb_check_ref_list_error( + struct h264_dpb_stru *p_H264_Dpb); + +void unmark_for_reference(struct DecodedPictureBuffer *p_Dpb, + struct FrameStore *fs); + +void update_ref_list(struct DecodedPictureBuffer *p_Dpb); + +int post_picture_early(struct vdec_s *vdec, int index); + +int is_used_for_reference(struct FrameStore *fs); + +#endif
diff --git a/drivers/frame_provider/decoder/real/vreal.h b/drivers/frame_provider/decoder_v4l/h264_multi/vh264.h similarity index 63% copy from drivers/frame_provider/decoder/real/vreal.h copy to drivers/frame_provider/decoder_v4l/h264_multi/vh264.h index 734cc6f..6c8e4ad 100644 --- a/drivers/frame_provider/decoder/real/vreal.h +++ b/drivers/frame_provider/decoder_v4l/h264_multi/vh264.h
@@ -1,7 +1,7 @@ /* - * drivers/amlogic/amports/vreal.h + * drivers/amlogic/media/frame_provider/decoder/h264/vh264.h * - * Copyright (C) 2015 Amlogic, Inc. All rights reserved. + * 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 @@ -15,12 +15,13 @@ * */ -#ifndef VREAL_H -#define VREAL_H +#ifndef VH264_H +#define VH264_H -#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */ -/* TODO: move to register headers */ -#define VPP_VD1_POSTBLEND (1 << 10) -#endif +extern int query_video_status(int type, int *value); -#endif /* VREAL_H */ +/* extern s32 vh264_init(void); */ + +extern s32 vh264_release(void); + +#endif /* VMPEG4_H */
diff --git a/drivers/frame_provider/decoder_v4l/h264_multi/vmh264.c b/drivers/frame_provider/decoder_v4l/h264_multi/vmh264.c new file mode 100644 index 0000000..e513272 --- /dev/null +++ b/drivers/frame_provider/decoder_v4l/h264_multi/vmh264.c
@@ -0,0 +1,11466 @@ +/* + * drivers/amlogic/amports/vh264.c + * + * Copyright (C) 2015 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. + * + */ +#define DEBUG +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/timer.h> +#include <linux/kfifo.h> +#include <linux/platform_device.h> +#include <linux/random.h> +#include <linux/amlogic/media/utils/amstream.h> +#include <linux/amlogic/media/frame_sync/ptsserv.h> +#include <linux/amlogic/media/canvas/canvas.h> +#include <linux/amlogic/media/vfm/vframe.h> +#include <linux/amlogic/media/vfm/vframe_provider.h> +#include <linux/amlogic/media/vfm/vframe_receiver.h> +#include <linux/amlogic/media/utils/vformat.h> +#include <linux/amlogic/media/frame_sync/tsync.h> +#include <linux/workqueue.h> +#include <linux/dma-mapping.h> +#include <linux/atomic.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/dma-mapping.h> +#include <linux/dma-contiguous.h> +#include "../../../stream_input/amports/amports_priv.h" +#include <linux/amlogic/media/codec_mm/codec_mm.h> +#include "../../decoder/utils/vdec_input.h" +//#include <linux/amlogic/tee.h> +#include <uapi/linux/tee.h> +#include <linux/sched/clock.h> +#include <linux/amlogic/media/utils/vdec_reg.h> +#include "../../decoder/utils/vdec.h" +#include "../../decoder/utils/amvdec.h" +#include "vh264.h" +#include "../../../stream_input/amports/streambuf.h" +#include <linux/delay.h> +#include <linux/amlogic/media/codec_mm/configs.h> +#include "../../decoder/utils/decoder_mmu_box.h" +#include "../../decoder/utils/decoder_bmmu_box.h" +#include "../../decoder/utils/firmware.h" +#include <linux/uaccess.h> +#include "../../decoder/utils/config_parser.h" +#include "../../../common/chips/decoder_cpu_ver_info.h" +#include "../../decoder/utils/vdec_v4l2_buffer_ops.h" +#include <linux/crc32.h> +#include <media/v4l2-mem2mem.h> +#include "../../decoder/utils/vdec_feature.h" + +#define DETECT_WRONG_MULTI_SLICE + +/* +to enable DV of frame mode +#define DOLBY_META_SUPPORT in ucode +*/ + +#undef pr_info +#define pr_info printk +#define VDEC_DW +#define DEBUG_UCODE +#define MEM_NAME "codec_m264" +#define MULTI_INSTANCE_FRAMEWORK +/* #define ONE_COLOCATE_BUF_PER_DECODE_BUF */ +#include "h264_dpb.h" +/* #define SEND_PARAM_WITH_REG */ + +#define DRIVER_NAME "ammvdec_h264_v4l" +#define DRIVER_HEADER_NAME "ammvdec_h264_header" + +#define CHECK_INTERVAL (HZ/100) + +#define SEI_DATA_SIZE (8*1024) +#define SEI_ITU_DATA_SIZE (4*1024) + +#define RATE_MEASURE_NUM 8 +#define RATE_CORRECTION_THRESHOLD 5 +#define RATE_2397_FPS 4004 /* 23.97 */ +#define RATE_25_FPS 3840 /* 25 */ +#define RATE_2997_FPS 3203 /* 29.97 */ +#define RATE_5994_FPS 1601 /* 59.94 */ +#define RATE_11990_FPS 800 /* 119.90 */ +#define DUR2PTS(x) ((x)*90/96) +#define PTS2DUR(x) ((x)*96/90) +#define DUR2PTS_REM(x) (x*90 - DUR2PTS(x)*96) +#define FIX_FRAME_RATE_CHECK_IFRAME_NUM 2 + +#define FIX_FRAME_RATE_OFF 0 +#define FIX_FRAME_RATE_ON 1 +#define FIX_FRAME_RATE_SMOOTH_CHECKING 2 + +#define DEC_CONTROL_FLAG_FORCE_2997_1080P_INTERLACE 0x0001 +#define DEC_CONTROL_FLAG_FORCE_2500_576P_INTERLACE 0x0002 +#define DEC_CONTROL_FLAG_FORCE_RATE_2397_FPS_FIX_FRAME_RATE 0x0010 +#define DEC_CONTROL_FLAG_FORCE_RATE_2997_FPS_FIX_FRAME_RATE 0x0020 + +#define DECODE_ID(hw) (hw_to_vdec(hw)->id) + +#define RATE_MEASURE_NUM 8 +#define RATE_CORRECTION_THRESHOLD 5 +#define RATE_24_FPS 4004 /* 23.97 */ +#define RATE_25_FPS 3840 /* 25 */ +#define DUR2PTS(x) ((x)*90/96) +#define PTS2DUR(x) ((x)*96/90) +#define DUR2PTS_REM(x) (x*90 - DUR2PTS(x)*96) +#define FIX_FRAME_RATE_CHECK_IDRFRAME_NUM 2 + +#define ALIGN_WIDTH(x) (ALIGN((x), 64)) +#define ALIGN_HEIGHT(x) (ALIGN((x), 32)) + +#define H264_DEV_NUM 9 + +#define CONSTRAIN_MAX_BUF_NUM + +#define H264_MMU +#define VIDEO_SIGNAL_TYPE_AVAILABLE_MASK 0x20000000 +#define INVALID_IDX -1 /* Invalid buffer index.*/ + +static int mmu_enable; +/*mmu do not support mbaff*/ +static int force_enable_mmu = 0; +unsigned int h264_debug_flag; /* 0xa0000000; */ +unsigned int h264_debug_mask = 0xff; + /* + *h264_debug_cmd: + * 0x1xx, force decoder id of xx to be disconnected + */ +unsigned int h264_debug_cmd; + +static int ref_b_frame_error_max_count = 50; + +static unsigned int dec_control = + DEC_CONTROL_FLAG_FORCE_2997_1080P_INTERLACE | + DEC_CONTROL_FLAG_FORCE_2500_576P_INTERLACE; + +static unsigned int force_rate_streambase; +static unsigned int force_rate_framebase; +static unsigned int force_disp_bufspec_num; +static unsigned int fixed_frame_rate_mode; +static unsigned int error_recovery_mode_in; +static int start_decode_buf_level = 0x4000; +static int pre_decode_buf_level = 0x1000; +static int stream_mode_start_num = 4; +static unsigned int colocate_old_cal; + +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION +/*to make reorder size difference of bl and el not too big*/ +static unsigned int reorder_dpb_size_margin_dv = 16; +#endif +static unsigned int reorder_dpb_size_margin = 6; +static unsigned int reference_buf_margin = 4; + +#ifdef CONSTRAIN_MAX_BUF_NUM +static u32 run_ready_max_vf_only_num; +static u32 run_ready_display_q_num; + /*0: not check + 0xff: mDPB.size + */ +static u32 run_ready_max_buf_num = 0xff; +#endif + +static u32 run_ready_min_buf_num = 2; + +#define VDEC_ASSIST_CANVAS_BLK32 0x5 + + +static unsigned int max_alloc_buf_count; +static unsigned int decode_timeout_val = 100; +static unsigned int errordata_timeout_val = 50; +static unsigned int get_data_timeout_val = 2000; +#if 1 +/* H264_DATA_REQUEST does not work, disable it, +decode has error for data in none continuous address +*/ +static unsigned int frame_max_data_packet; +#else +static unsigned int frame_max_data_packet = 8; +#endif +static unsigned int radr; +static unsigned int rval; +static u32 endian = 0xff0; + +/* + udebug_flag: + bit 0, enable ucode print + bit 1, enable ucode detail print + bit 3, disable ucode watchdog + bit [31:16] not 0, pos to dump lmem + bit 2, pop bits to lmem + bit [11:8], pre-pop bits for alignment (when bit 2 is 1) +*/ +static u32 udebug_flag; +/* + when udebug_flag[1:0] is not 0 + udebug_pause_pos not 0, + pause position +*/ +static u32 udebug_pause_pos; +/* + when udebug_flag[1:0] is not 0 + and udebug_pause_pos is not 0, + pause only when DEBUG_REG2 is equal to this val +*/ +static u32 udebug_pause_val; + +static u32 udebug_pause_decode_idx; + +static unsigned int disp_vframe_valve_level; + +static unsigned int max_decode_instance_num = H264_DEV_NUM; +static unsigned int decode_frame_count[H264_DEV_NUM]; +static unsigned int display_frame_count[H264_DEV_NUM]; +static unsigned int max_process_time[H264_DEV_NUM]; +static unsigned int max_get_frame_interval[H264_DEV_NUM]; +static unsigned int run_count[H264_DEV_NUM]; +static unsigned int input_empty[H264_DEV_NUM]; +static unsigned int not_run_ready[H264_DEV_NUM]; +static unsigned int ref_frame_mark_flag[H264_DEV_NUM] = +{1, 1, 1, 1, 1, 1, 1, 1, 1}; + +#define VDEC_CLOCK_ADJUST_FRAME 30 +static unsigned int clk_adj_frame_count; + +/* + *bit[3:0]: 0, run ; 1, pause; 3, step + *bit[4]: 1, schedule run + */ +static unsigned int step[H264_DEV_NUM]; + +#define AUX_BUF_ALIGN(adr) ((adr + 0xf) & (~0xf)) +static u32 prefix_aux_buf_size = (16 * 1024); +static u32 suffix_aux_buf_size; + +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION +static u32 dv_toggle_prov_name; + +static u32 dolby_meta_with_el; +#endif + +/* + bit[8] + 0: use sys_info[bit 3] + not 0:use i_only_flag[7:0] + bit[7:0]: + bit 0, 1: only display I picture; + bit 1, 1: only decode I picture; +*/ +static unsigned int i_only_flag; + +/* + error_proc_policy: + bit[0] send_error_frame_flag; + (valid when bit[31] is 1, otherwise use sysinfo) + bit[1] do not decode if config_decode_buf() fail + bit[2] force release buf if in deadlock + bit[3] force sliding window ref_frames_in_buffer > num_ref_frames + bit[4] check inactive of receiver + bit[5] reset buffmgr if in deadlock + bit[6] reset buffmgr if bufspec, collocate buf, pic alloc fail + bit[7] reset buffmgr if dpb error + + bit[8] check total mbx/mby of decoded frame + bit[9] check ERROR_STATUS_REG + bit[10] check reference list + bit[11] mark error if dpb error + bit[12] i_only when error happen + bit[13] 0: mark error according to last pic, 1: ignore mark error + bit[14] 0: result done when timeout from ucode. 1: reset bufmgr when timeout. + bit[15] 1: dpb_frame_count If the dpb_frame_count difference is large, it moves out of the DPB buffer. + bit[16] 1: check slice header number. + bit[17] 1: If the decoded Mb count is insufficient but greater than the threshold, it is considered the correct frame. + bit[18] 1: time out status, store pic to dpb buffer. + bit[19] 1: If a lot b frames are wrong consecutively, the DPB queue reset. + bit[20] 1: fixed some error stream will lead to the diffusion of the error, resulting playback stuck. + bit[21] 1: fixed DVB loop playback cause jetter issue. + bit[22] 1: In streaming mode, support for discarding data. + bit[23] 0: set error flag on frame number gap error and drop it, 1: ignore error. +*/ +static unsigned int error_proc_policy = 0x3fCfb6; /*0x1f14*/ + +static unsigned int v4l_error_policy = 0x8017C3B5; //default + +/* + error_skip_count: + bit[11:0] error skip frame count + bit[15:12] error skip i picture count +*/ +static unsigned int error_skip_count = (0x2 << 12) | 0x40; + +static unsigned int force_sliding_margin; +/* + bit[1:0]: + 0, start playing from any frame + 1, start playing from I frame + bit[15:8]: the count of skip frames after first I + 2, start playing from second I frame (decode from the first I) + bit[15:8]: the max count of skip frames after first I + 3, start playing from IDR +*/ +static unsigned int first_i_policy = 1; + +/* + fast_output_enable: + bit [0], output frame if there is IDR in list + bit [1], output frame if the current poc is 1 big than the previous poc + bit [2], if even poc only, output frame ifthe cuurent poc + is 2 big than the previous poc + bit [3], ip only +*/ +static unsigned int fast_output_enable = H264_OUTPUT_MODE_NORMAL; + +static unsigned int enable_itu_t35 = 1; + +static unsigned int frmbase_cont_bitlevel = 0x40; + +static unsigned int frmbase_cont_bitlevel2 = 0x1; + +static unsigned int check_slice_num = 30; + +static unsigned int mb_count_threshold = 5; /*percentage*/ + +#define MH264_USERDATA_ENABLE + +/* DOUBLE_WRITE_MODE is enabled only when NV21 8 bit output is needed */ +/* hevc->double_write_mode: + 0, no double write + 1, 1:1 ratio + 2, (1/4):(1/4) ratio + 3, (1/4):(1/4) ratio, with both compressed frame included + 4, (1/2):(1/2) ratio + 0x10, double write only + 0x10000: vdec dw horizotal 1/2 + 0x20000: vdec dw horizotal/vertical 1/2 +*/ +static u32 double_write_mode; +static u32 without_display_mode; + +static int loop_playback_poc_threshold = 400; +static int poc_threshold = 50; + +static u32 lookup_check_conut = 30; + + +/* + *[3:0] 0: default use config from omx. + * 1: force enable fence. + * 2: disable fence. + *[7:4] 0: fence use for driver. + * 1: fence fd use for app. + */ +static u32 force_config_fence; + +static u32 adjust_dpb_size = 13; + +#define IS_VDEC_DW(hw) (hw->double_write_mode >> 16 & 0xf) + +static void vmh264_dump_state(struct vdec_s *vdec); + +#define is_in_parsing_state(status) \ + ((status == H264_ACTION_SEARCH_HEAD) || \ + ((status & 0xf0) == 0x80)) + +#define is_interlace(frame) \ + ((frame->frame &&\ + frame->top_field &&\ + frame->bottom_field &&\ + (!frame->frame->coded_frame)) || \ + (frame->frame && \ + frame->frame->coded_frame && \ + (!frame->frame->frame_mbs_only_flag) && \ + frame->frame->structure == FRAME)) + +static inline bool close_to(int a, int b, int m) +{ + return (abs(a - b) < m) ? true : false; +} + +#if 0 +#define h264_alloc_hw_stru(dev, size, opt) devm_kzalloc(dev, size, opt) +#define h264_free_hw_stru(dev, hw) devm_kfree(dev, hw) +#else +#define h264_alloc_hw_stru(dev, size, opt) vzalloc(size) +#define h264_free_hw_stru(dev, hw) vfree(hw) +#endif + +/* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */ +#define NV21 +/* #endif */ + +/* 12M for L41 */ +#define MAX_DPB_BUFF_SIZE (12*1024*1024) +#define DEFAULT_MEM_SIZE (32*1024*1024) +#define AVIL_DPB_BUFF_SIZE 0x01ec2000 + +#define DEF_BUF_START_ADDR 0x00000000 +#define mem_sps_base 0x01c3c00 +#define mem_pps_base 0x01cbc00 +/*#define V_BUF_ADDR_OFFSET (0x13e000)*/ +u32 V_BUF_ADDR_OFFSET = 0x200000; +#define DCAC_READ_MARGIN (64 * 1024) + + +#define EXTEND_SAR 0xff +#define BUFSPEC_POOL_SIZE 64 +#define VF_POOL_SIZE 64 +#define VF_POOL_NUM 2 +#define MAX_VF_BUF_NUM 27 +#define BMMU_MAX_BUFFERS (BUFSPEC_POOL_SIZE + 3) +#define BMMU_REF_IDX (BUFSPEC_POOL_SIZE) +#define BMMU_DPB_IDX (BUFSPEC_POOL_SIZE + 1) +#define BMMU_EXTIF_IDX (BUFSPEC_POOL_SIZE + 2) +#define EXTIF_BUF_SIZE (0x10000 * 2) + +#define HEADER_BUFFER_IDX(n) (n) +#define VF_BUFFER_IDX(n) (n) + + +#define PUT_INTERVAL (HZ/100) +#define NO_DISP_WD_COUNT (3 * HZ / PUT_INTERVAL) + +#define MMU_MAX_BUFFERS BUFSPEC_POOL_SIZE +#define SWITCHING_STATE_OFF 0 +#define SWITCHING_STATE_ON_CMD3 1 +#define SWITCHING_STATE_ON_CMD1 2 + + + +#define INCPTR(p) ptr_atomic_wrap_inc(&p) + +#define SLICE_TYPE_I 2 +#define SLICE_TYPE_P 5 +#define SLICE_TYPE_B 6 + +struct buffer_spec_s { + /* + used: + -1, none allocated + 0, allocated, free + 1, used by dpb + 2, in disp queue; + 3, in disp queue, isolated, + do not use for dpb when vf_put; + 4, to release + 5, in disp queue, isolated (but not to release) + do not use for dpb when vf_put; + */ + unsigned int used; + unsigned int info0; + unsigned int info1; + unsigned int info2; + unsigned int y_addr; + unsigned int u_addr; + unsigned int v_addr; + + int y_canvas_index; + int u_canvas_index; + int v_canvas_index; + +#ifdef VDEC_DW + unsigned int vdec_dw_y_addr; + unsigned int vdec_dw_u_addr; + unsigned int vdec_dw_v_addr; + + int vdec_dw_y_canvas_index; + int vdec_dw_u_canvas_index; + int vdec_dw_v_canvas_index; +#ifdef NV21 + struct canvas_config_s vdec_dw_canvas_config[2]; +#else + struct canvas_config_s vdec_dw_canvas_config[3]; +#endif +#endif + +#ifdef NV21 + struct canvas_config_s canvas_config[2]; +#else + struct canvas_config_s canvas_config[3]; +#endif + unsigned long cma_alloc_addr; + unsigned int buf_adr; +#ifdef H264_MMU + unsigned long alloc_header_addr; +#endif + char *aux_data_buf; + int aux_data_size; +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + unsigned char dv_enhance_exist; +#endif + int canvas_pos; + int vf_ref; + /*unsigned int comp_body_size;*/ + unsigned int dw_y_adr; + unsigned int dw_u_v_adr; + int fs_idx; + int ctx_buf_idx; +}; + +#define AUX_DATA_SIZE(pic) (hw->buffer_spec[pic->buf_spec_num].aux_data_size) +#define AUX_DATA_BUF(pic) (hw->buffer_spec[pic->buf_spec_num].aux_data_buf) +#define DEL_EXIST(h, p) (h->buffer_spec[p->buf_spec_num].dv_enhance_exist) + + +#define vdec_dw_spec2canvas(x) \ + (((x)->vdec_dw_v_canvas_index << 16) | \ + ((x)->vdec_dw_u_canvas_index << 8) | \ + ((x)->vdec_dw_y_canvas_index << 0)) + + +#define spec2canvas(x) \ + (((x)->v_canvas_index << 16) | \ + ((x)->u_canvas_index << 8) | \ + ((x)->y_canvas_index << 0)) + +#define FRAME_INDEX(vf_index) (vf_index & 0xff) +#define BUFSPEC_INDEX(vf_index) ((vf_index >> 8) & 0xff) +#define VF_INDEX(frm_idx, bufspec_idx) (frm_idx | (bufspec_idx << 8)) + +static struct vframe_s *vh264_vf_peek(void *); +static struct vframe_s *vh264_vf_get(void *); +static void vh264_vf_put(struct vframe_s *, void *); +static int vh264_vf_states(struct vframe_states *states, void *); +static int vh264_event_cb(int type, void *data, void *private_data); +static void vh264_work(struct work_struct *work); +static void vh264_timeout_work(struct work_struct *work); +static void vh264_notify_work(struct work_struct *work); +#ifdef MH264_USERDATA_ENABLE +static void user_data_ready_notify_work(struct work_struct *work); +static void vmh264_wakeup_userdata_poll(struct vdec_s *vdec); +#endif + +static const char vh264_dec_id[] = "vh264-dev"; + +#define PROVIDER_NAME "vdec.h264" + +static const struct vframe_operations_s vf_provider_ops = { + .peek = vh264_vf_peek, + .get = vh264_vf_get, + .put = vh264_vf_put, + .event_cb = vh264_event_cb, + .vf_states = vh264_vf_states, +}; + +#define DEC_RESULT_NONE 0 +#define DEC_RESULT_DONE 1 +#define DEC_RESULT_AGAIN 2 +#define DEC_RESULT_CONFIG_PARAM 3 +#define DEC_RESULT_GET_DATA 4 +#define DEC_RESULT_GET_DATA_RETRY 5 +#define DEC_RESULT_ERROR 6 +#define DEC_RESULT_EOS 7 +#define DEC_RESULT_FORCE_EXIT 8 +#define DEC_RESULT_TIMEOUT 9 +#define DEC_RESULT_NEED_MORE_BUFFER 10 + + +/* + *static const char *dec_result_str[] = { + * "DEC_RESULT_NONE ", + * "DEC_RESULT_DONE ", + * "DEC_RESULT_AGAIN ", + * "DEC_RESULT_CONFIG_PARAM", + * "DEC_RESULT_GET_DATA ", + * "DEC_RESULT_GET_DA_RETRY", + * "DEC_RESULT_ERROR ", + *}; + */ + +#define UCODE_IP_ONLY 2 +#define UCODE_IP_ONLY_PARAM 1 + +#define MC_OFFSET_HEADER 0x0000 +#define MC_OFFSET_DATA 0x1000 +#define MC_OFFSET_MMCO 0x2000 +#define MC_OFFSET_LIST 0x3000 +#define MC_OFFSET_SLICE 0x4000 +#define MC_OFFSET_MAIN 0x5000 + +#define MC_TOTAL_SIZE ((20+16)*SZ_1K) +#define MC_SWAP_SIZE (4*SZ_1K) +#define MODE_ERROR 0 +#define MODE_FULL 1 + +#define DFS_HIGH_THEASHOLD 3 + +#define INIT_FLAG_REG AV_SCRATCH_2 +#define HEAD_PADING_REG AV_SCRATCH_3 +#define UCODE_WATCHDOG_REG AV_SCRATCH_7 +#define LMEM_DUMP_ADR AV_SCRATCH_L +#define DEBUG_REG1 AV_SCRATCH_M +#define DEBUG_REG2 AV_SCRATCH_N +#define FRAME_COUNTER_REG AV_SCRATCH_I +#define RPM_CMD_REG AV_SCRATCH_A +#define H264_DECODE_SIZE AV_SCRATCH_E +#define H264_DECODE_MODE AV_SCRATCH_4 +#define H264_DECODE_SEQINFO AV_SCRATCH_5 +#define H264_AUX_ADR AV_SCRATCH_C +#define H264_AUX_DATA_SIZE AV_SCRATCH_H + +#define H264_DECODE_INFO M4_CONTROL_REG /* 0xc29 */ +#define DPB_STATUS_REG AV_SCRATCH_J +#define ERROR_STATUS_REG AV_SCRATCH_9 + /* + NAL_SEARCH_CTL: bit 0, enable itu_t35 + NAL_SEARCH_CTL: bit 1, enable mmu + NAL_SEARCH_CTL: bit 2, detect frame_mbs_only_flag whether switch resolution + NAL_SEARCH_CTL: bit 7-14,level_idc + NAL_SEARCH_CTL: bit 15,bitstream_restriction_flag + */ +#define NAL_SEARCH_CTL AV_SCRATCH_9 +#define MBY_MBX MB_MOTION_MODE /*0xc07*/ + +#define DECODE_MODE_SINGLE 0x0 +#define DECODE_MODE_MULTI_FRAMEBASE 0x1 +#define DECODE_MODE_MULTI_STREAMBASE 0x2 +#define DECODE_MODE_MULTI_DVBAL 0x3 +#define DECODE_MODE_MULTI_DVENL 0x4 +static DEFINE_MUTEX(vmh264_mutex); +static DEFINE_MUTEX(reset_mutex); + + + +#ifdef MH264_USERDATA_ENABLE + +struct mh264_userdata_record_t { + struct userdata_meta_info_t meta_info; + u32 rec_start; + u32 rec_len; +}; + +struct mh264_ud_record_wait_node_t { + struct list_head list; + struct mh264_userdata_record_t ud_record; +}; +#define USERDATA_FIFO_NUM 256 +#define MAX_FREE_USERDATA_NODES 5 + +struct mh264_userdata_info_t { + struct mh264_userdata_record_t records[USERDATA_FIFO_NUM]; + u8 *data_buf; + u8 *data_buf_end; + u32 buf_len; + u32 read_index; + u32 write_index; + u32 last_wp; +}; + + +#endif + +struct mh264_fence_vf_t { + u32 used_size; + struct vframe_s *fence_vf[VF_POOL_SIZE]; +}; + + +struct vdec_h264_hw_s { + spinlock_t lock; + spinlock_t bufspec_lock; + int id; + struct platform_device *platform_dev; + unsigned long cma_alloc_addr; + /* struct page *collocate_cma_alloc_pages; */ + unsigned long collocate_cma_alloc_addr; + + u32 prefix_aux_size; + u32 suffix_aux_size; + void *aux_addr; + dma_addr_t aux_phy_addr; + + /* buffer for store all sei data */ + void *sei_data_buf; + u32 sei_data_len; + + /* buffer for storing one itu35 recored */ + void *sei_itu_data_buf; + u32 sei_itu_data_len; + + /* recycle buffer for user data storing all itu35 records */ + void *sei_user_data_buffer; + u32 sei_user_data_wp; +#ifdef MH264_USERDATA_ENABLE + struct work_struct user_data_ready_work; +#endif + struct StorablePicture *last_dec_picture; + + ulong lmem_phy_addr; + dma_addr_t lmem_addr; + + void *bmmu_box; +#ifdef H264_MMU + void *mmu_box; + void *frame_mmu_map_addr; + dma_addr_t frame_mmu_map_phy_addr; + u32 hevc_cur_buf_idx; + u32 losless_comp_body_size; + u32 losless_comp_body_size_sao; + u32 losless_comp_header_size; + u32 mc_buffer_size_u_v; + u32 mc_buffer_size_u_v_h; + u32 is_idr_frame; + u32 is_new_pic; + u32 frame_done; + u32 frame_busy; + unsigned long extif_addr; + int double_write_mode; + int mmu_enable; +#endif + + DECLARE_KFIFO(newframe_q, struct vframe_s *, VF_POOL_SIZE); + DECLARE_KFIFO(display_q, struct vframe_s *, VF_POOL_SIZE); + + int cur_pool; + struct vframe_s vfpool[VF_POOL_NUM][VF_POOL_SIZE]; + struct buffer_spec_s buffer_spec[BUFSPEC_POOL_SIZE]; + struct vframe_s switching_fense_vf; + struct h264_dpb_stru dpb; + u8 init_flag; + u8 first_sc_checked; + u8 has_i_frame; + u8 config_bufmgr_done; + u32 max_reference_size; + u32 decode_pic_count; + u32 reflist_error_count; + int start_search_pos; + u32 reg_iqidct_control; + bool reg_iqidct_control_init_flag; + u32 reg_vcop_ctrl_reg; + u32 reg_rv_ai_mb_count; + u32 vld_dec_control; + struct vframe_s vframe_dummy; + + unsigned char buffer_empty_flag; + + u32 frame_width; + u32 frame_height; + u32 frame_dur; + u32 frame_prog; + u32 frame_packing_type; + + struct vframe_chunk_s *chunk; + + u32 stat; + unsigned long buf_start; + u32 buf_offset; + u32 buf_size; + /* u32 ucode_map_start; */ + u32 pts_outside; + u32 sync_outside; + u32 vh264_ratio; + u32 vh264_rotation; + u32 use_idr_framerate; + + u32 seq_info; + u32 seq_info2; + u32 seq_info3; + u32 video_signal_from_vui; /*to do .. */ + u32 timing_info_present_flag; + u32 fixed_frame_rate_flag; + u32 bitstream_restriction_flag; + u32 num_reorder_frames; + u32 max_dec_frame_buffering; + u32 iframe_count; + u32 aspect_ratio_info; + u32 num_units_in_tick; + u32 time_scale; + u32 h264_ar; + bool h264_first_valid_pts_ready; + u32 h264pts1; + u32 h264pts2; + u32 pts_duration; + u32 h264_pts_count; + u32 duration_from_pts_done; + u32 pts_unstable; + u32 unstable_pts; + u32 last_checkout_pts; + u32 max_refer_buf; + + s32 vh264_stream_switching_state; + struct vframe_s *p_last_vf; + u32 last_pts; + u32 last_pts_remainder; + u32 last_duration; + u32 last_mb_width, last_mb_height; + bool check_pts_discontinue; + bool pts_discontinue; + u32 wait_buffer_counter; + u32 first_offset; + u32 first_pts; + u64 first_pts64; + bool first_pts_cached; + u64 last_pts64; +#if 0 + void *sei_data_buffer; + dma_addr_t sei_data_buffer_phys; +#endif + + uint error_recovery_mode; + uint mb_total; + uint mb_width; + uint mb_height; + + uint i_only; + int skip_frame_count; + bool no_poc_reorder_flag; + bool send_error_frame_flag; + dma_addr_t mc_dma_handle; + void *mc_cpu_addr; + int vh264_reset; + + atomic_t vh264_active; + + struct dec_sysinfo vh264_amstream_dec_info; + + int dec_result; + u32 timeout_processing; + struct work_struct work; + struct work_struct notify_work; + struct work_struct timeout_work; + void (*vdec_cb)(struct vdec_s *, void *); + void *vdec_cb_arg; + + struct timer_list check_timer; + + /**/ + unsigned int last_frame_time; + atomic_t vf_pre_count; + atomic_t vf_get_count; + atomic_t vf_put_count; + + /* timeout handle */ + unsigned long int start_process_time; + unsigned int last_mby_mbx; + unsigned int last_vld_level; + unsigned int decode_timeout_count; + unsigned int timeout_num; + unsigned int search_dataempty_num; + unsigned int decode_timeout_num; + unsigned int decode_dataempty_num; + unsigned int buffer_empty_recover_num; + + unsigned get_data_count; + unsigned get_data_start_time; + /**/ + + /*log*/ + unsigned int packet_write_success_count; + unsigned int packet_write_EAGAIN_count; + unsigned int packet_write_ENOMEM_count; + unsigned int packet_write_EFAULT_count; + unsigned int total_read_size_pre; + unsigned int total_read_size; + unsigned int frame_count_pre; +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + u8 switch_dvlayer_flag; + u8 got_valid_nal; +#endif + u8 eos; + u8 data_flag; + u32 no_error_count; + u32 no_error_i_count; + /* + NODISP_FLAG + */ + u8 dec_flag; + + u32 ucode_pause_pos; + + u8 reset_bufmgr_flag; + u32 reset_bufmgr_count; + ulong timeout; + u32 timeout_flag; + u32 cfg_param1; + u32 cfg_param2; + u32 cfg_param3; + u32 cfg_param4; + u32 cfg_bitstream_restriction_flag; + int valve_count; + u8 next_again_flag; + u32 pre_parser_wr_ptr; + struct firmware_s *fw; + struct firmware_s *fw_mmu; +#ifdef MH264_USERDATA_ENABLE + /*user data*/ + struct mutex userdata_mutex; + struct mh264_userdata_info_t userdata_info; + struct mh264_userdata_record_t ud_record; + int wait_for_udr_send; +#endif + u32 no_mem_count; + u32 canvas_mode; + bool is_used_v4l; + void *v4l2_ctx; + bool v4l_params_parsed; + wait_queue_head_t wait_q; + u32 reg_g_status; + struct mutex chunks_mutex; + int need_cache_size; + u64 sc_start_time; + u8 frmbase_cont_flag; + struct vframe_qos_s vframe_qos; + int frameinfo_enable; + bool first_head_check_flag; + unsigned int height_aspect_ratio; + unsigned int width_aspect_ratio; + unsigned int first_i_policy; + u32 reorder_dpb_size_margin; + bool wait_reset_done_flag; +#ifdef DETECT_WRONG_MULTI_SLICE + unsigned int multi_slice_pic_check_count; + /* multi_slice_pic_flag: + 0, unknown; + 1, single slice; + 2, multi slice + */ + unsigned int multi_slice_pic_flag; + unsigned int picture_slice_count; + unsigned int cur_picture_slice_count; + unsigned char force_slice_as_picture_flag; + unsigned int last_picture_slice_count; + unsigned int first_pre_frame_num; +#endif + u32 res_ch_flag; + u32 b_frame_error_count; + struct vdec_info gvs; + u32 kpi_first_i_comming; + u32 kpi_first_i_decoded; + int sidebind_type; + int sidebind_channel_id; + u32 low_latency_mode; + int ip_field_error_count; + int buffer_wrap[BUFSPEC_POOL_SIZE]; + int loop_flag; + int loop_last_poc; + bool enable_fence; + int fence_usage; + bool discard_dv_data; + u32 metadata_config_flag; + int vdec_pg_enable_flag; + u32 save_reg_f; + u32 start_bit_cnt; + u32 right_frame_count; + u32 wrong_frame_count; + u32 error_frame_width; + u32 error_frame_height; + ulong fb_token; + struct mh264_fence_vf_t fence_vf_s; + struct mutex fence_mutex; + u32 no_decoder_buffer_flag; + u32 video_signal_type; + bool need_free_aux_data; + u32 error_proc_policy; + struct trace_decoder_name trace; + bool high_bandwidth_flag; + bool hevc_enable_flag; +}; + +static u32 again_threshold; + +static void timeout_process(struct vdec_h264_hw_s *hw); +static void dump_bufspec(struct vdec_h264_hw_s *hw, + const char *caller); +static void h264_reconfig(struct vdec_h264_hw_s *hw); +static void h264_reset_bufmgr_v4l(struct vdec_s *vdec, int flush_flag); +static void vh264_local_init(struct vdec_h264_hw_s *hw, bool is_reset); +static int vh264_hw_ctx_restore(struct vdec_h264_hw_s *hw); +static int vh264_stop(struct vdec_h264_hw_s *hw); +static s32 vh264_init(struct vdec_h264_hw_s *hw); +static void set_frame_info(struct vdec_h264_hw_s *hw, struct vframe_s *vf, + u32 index); +static void release_aux_data(struct vdec_h264_hw_s *hw, + int buf_spec_num); +#ifdef ERROR_HANDLE_TEST +static void h264_clear_dpb(struct vdec_h264_hw_s *hw); +#endif + +#define H265_PUT_SAO_4K_SET 0x03 +#define H265_ABORT_SAO_4K_SET 0x04 +#define H265_ABORT_SAO_4K_SET_DONE 0x05 + +#define SYS_COMMAND HEVC_ASSIST_SCRATCH_0 +#define H265_CHECK_AXI_INFO_BASE HEVC_ASSIST_SCRATCH_8 +#define H265_SAO_4K_SET_BASE HEVC_ASSIST_SCRATCH_9 +#define H265_SAO_4K_SET_COUNT HEVC_ASSIST_SCRATCH_A +#define HEVCD_MPP_ANC2AXI_TBL_DATA 0x3464 + + +#define HEVC_CM_HEADER_START_ADDR 0x3628 +#define HEVC_CM_BODY_START_ADDR 0x3626 +#define HEVC_CM_BODY_LENGTH 0x3627 +#define HEVC_CM_HEADER_LENGTH 0x3629 +#define HEVC_CM_HEADER_OFFSET 0x362b +#define HEVC_SAO_CTRL9 0x362d +#define HEVCD_MPP_DECOMP_CTL3 0x34c4 +#define HEVCD_MPP_VDEC_MCR_CTL 0x34c8 +#define HEVC_DBLK_CFGB 0x350b +#define HEVC_ASSIST_MMU_MAP_ADDR 0x3009 + +#define H265_DW_NO_SCALE +#define H265_MEM_MAP_MODE 0 /*0:linear 1:32x32 2:64x32*/ +#define H265_LOSLESS_COMPRESS_MODE +#define MAX_FRAME_4K_NUM 0x1200 +#define FRAME_MMU_MAP_SIZE (MAX_FRAME_4K_NUM * 4) + +/* 0:linear 1:32x32 2:64x32 ; m8baby test1902 */ +static u32 mem_map_mode = H265_MEM_MAP_MODE; + +#define MAX_SIZE_4K (4096 * 2304) +#define MAX_SIZE_2K (1920 * 1088) + + + +static int is_oversize(int w, int h) +{ + int max = MAX_SIZE_4K; + + if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5D) + max = MAX_SIZE_2K; + + if (w < 0 || h < 0) + return true; + + if (h != 0 && (w > max / h)) + return true; + + return false; +} + +static void vmh264_udc_fill_vpts(struct vdec_h264_hw_s *hw, + int frame_type, + u32 vpts, + u32 vpts_valid); +static int compute_losless_comp_body_size(int width, + int height, int bit_depth_10); +static int compute_losless_comp_header_size(int width, int height); + +static int hevc_alloc_mmu(struct vdec_h264_hw_s *hw, int pic_idx, + int pic_width, int pic_height, u16 bit_depth, + unsigned int *mmu_index_adr) { + int cur_buf_idx; + int bit_depth_10 = (bit_depth != 0x00); + int picture_size; + u32 cur_mmu_4k_number; + + WRITE_VREG(CURR_CANVAS_CTRL, pic_idx<<24); + cur_buf_idx = READ_VREG(CURR_CANVAS_CTRL)&0xff; + picture_size = compute_losless_comp_body_size(pic_width, + pic_height, bit_depth_10); + cur_mmu_4k_number = ((picture_size+(1<<12)-1) >> 12); + dpb_print(DECODE_ID(hw), + PRINT_FLAG_MMU_DETAIL, + "alloc_mmu new_fb_idx %d picture_size %d cur_mmu_4k_number %d\n", + cur_buf_idx, picture_size, cur_mmu_4k_number); + + if (cur_mmu_4k_number > MAX_FRAME_4K_NUM) { + pr_err("hevc_alloc_mmu cur_mmu_4k_number %d unsupport\n", + cur_mmu_4k_number); + return -1; + } + + return decoder_mmu_box_alloc_idx( + hw->mmu_box, + cur_buf_idx, + cur_mmu_4k_number, + mmu_index_adr); +} + +static int compute_losless_comp_body_size(int width, + int height, int bit_depth_10) +{ + int width_x64; + int height_x32; + int bsize; + + width_x64 = width + 63; + width_x64 >>= 6; + + height_x32 = height + 31; + height_x32 >>= 5; + +#ifdef H264_MMU + bsize = (bit_depth_10 ? 4096 : 3264) * width_x64*height_x32; +#else + bsize = (bit_depth_10 ? 4096 : 3072) * width_x64*height_x32; +#endif + return bsize; +} + +static int compute_losless_comp_header_size(int width, int height) +{ + int width_x64; + int width_x128; + int height_x64; + int hsize; + + width_x64 = width + 63; + width_x64 >>= 6; + + width_x128 = width + 127; + width_x128 >>= 7; + + height_x64 = height + 63; + height_x64 >>= 6; + +#ifdef H264_MMU + hsize = 128*width_x64*height_x64; +#else + hsize = 32*width_x128*height_x64; +#endif + return hsize; +} + +static int get_dw_size(struct vdec_h264_hw_s *hw, u32 *pdw_buffer_size_u_v_h) +{ + int pic_width, pic_height; + int lcu_size = 16; + int dw_buf_size; + u32 dw_buffer_size_u_v; + u32 dw_buffer_size_u_v_h; + int dw_mode = hw->double_write_mode; + + pic_width = hw->frame_width; + pic_height = hw->frame_height; + + if (dw_mode) { + int pic_width_dw = pic_width / + get_double_write_ratio(hw->double_write_mode); + int pic_height_dw = pic_height / + get_double_write_ratio(hw->double_write_mode); + + int pic_width_lcu_dw = (pic_width_dw % lcu_size) ? + pic_width_dw / lcu_size + 1 : + pic_width_dw / lcu_size; + int pic_height_lcu_dw = (pic_height_dw % lcu_size) ? + pic_height_dw / lcu_size + 1 : + pic_height_dw / lcu_size; + int lcu_total_dw = pic_width_lcu_dw * pic_height_lcu_dw; + + + dw_buffer_size_u_v = lcu_total_dw * lcu_size * lcu_size / 2; + dw_buffer_size_u_v_h = (dw_buffer_size_u_v + 0xffff) >> 16; + /*64k alignment*/ + dw_buf_size = ((dw_buffer_size_u_v_h << 16) * 3); + *pdw_buffer_size_u_v_h = dw_buffer_size_u_v_h; + } else { + *pdw_buffer_size_u_v_h = 0; + dw_buf_size = 0; + } + + return dw_buf_size; +} + + +static void hevc_mcr_config_canv2axitbl(struct vdec_h264_hw_s *hw, int restore) +{ + int i, size; + u32 canvas_addr; + unsigned long maddr; + int num_buff = hw->dpb.mDPB.size; + int dw_size = 0; + u32 dw_buffer_size_u_v_h; + u32 blkmode = hw->canvas_mode; + int dw_mode = hw->double_write_mode; + + canvas_addr = ANC0_CANVAS_ADDR; + for (i = 0; i < num_buff; i++) + WRITE_VREG((canvas_addr + i), i | (i << 8) | (i << 16)); + + WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, (0x1 << 1) | (0x1 << 2)); + size = hw->losless_comp_body_size + hw->losless_comp_header_size; + + + dw_size = get_dw_size(hw, &dw_buffer_size_u_v_h); + size += dw_size; + if (size > 0) + size += 0x10000; + + dpb_print(DECODE_ID(hw), PRINT_FLAG_MMU_DETAIL, + "dw_buffer_size_u_v_h = %d, dw_size = 0x%x, size = 0x%x\n", + dw_buffer_size_u_v_h, dw_size, size); + + dpb_print(DECODE_ID(hw), PRINT_FLAG_MMU_DETAIL, + "body_size = %d, header_size = %d, body_size_sao = %d\n", + hw->losless_comp_body_size, + hw->losless_comp_header_size, + hw->losless_comp_body_size_sao); + + for (i = 0; i < num_buff; i++) { + if (!restore) { + if (decoder_bmmu_box_alloc_buf_phy(hw->bmmu_box, + HEADER_BUFFER_IDX(i), size, + DRIVER_HEADER_NAME, &maddr) < 0) { + dpb_print(DECODE_ID(hw), 0, + "%s malloc compress header failed %d\n", + DRIVER_HEADER_NAME, i); + return; + } + } else + maddr = hw->buffer_spec[i].alloc_header_addr; + WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA, maddr >> 5); + hw->buffer_spec[i].alloc_header_addr = maddr; + dpb_print(DECODE_ID(hw), PRINT_FLAG_MMU_DETAIL, + "%s : canvas: %d axiaddr:%x size 0x%x\n", + __func__, i, (u32)maddr, size); + + if (dw_mode) { + u32 addr; + int canvas_w; + int canvas_h; + + canvas_w = hw->frame_width / + get_double_write_ratio(hw->double_write_mode); + canvas_h = hw->frame_height / + get_double_write_ratio(hw->double_write_mode); + + if (hw->canvas_mode == 0) + canvas_w = ALIGN(canvas_w, 32); + else + canvas_w = ALIGN(canvas_w, 64); + canvas_h = ALIGN(canvas_h, 32); + + hw->buffer_spec[i].dw_y_adr = + maddr + hw->losless_comp_header_size; + + hw->buffer_spec[i].dw_y_adr = + ((hw->buffer_spec[i].dw_y_adr + 0xffff) >> 16) + << 16; + hw->buffer_spec[i].dw_u_v_adr = + hw->buffer_spec[i].dw_y_adr + + (dw_buffer_size_u_v_h << 16) * 2; + + + hw->buffer_spec[i].buf_adr + = hw->buffer_spec[i].dw_y_adr; + addr = hw->buffer_spec[i].buf_adr; + + + dpb_print(DECODE_ID(hw), PRINT_FLAG_MMU_DETAIL, + "dw_y_adr = 0x%x, dw_u_v_adr = 0x%x, y_addr = 0x%x, u_addr = 0x%x, v_addr = 0x%x, width = %d, height = %d\n", + hw->buffer_spec[i].dw_y_adr, + hw->buffer_spec[i].dw_u_v_adr, + hw->buffer_spec[i].y_addr, + hw->buffer_spec[i].u_addr, + hw->buffer_spec[i].v_addr, + canvas_w, + canvas_h); + + hw->buffer_spec[i].canvas_config[0].phy_addr = + hw->buffer_spec[i].dw_y_adr; + hw->buffer_spec[i].canvas_config[0].width = canvas_w; + hw->buffer_spec[i].canvas_config[0].height = canvas_h; + hw->buffer_spec[i].canvas_config[0].block_mode = + blkmode; + hw->buffer_spec[i].canvas_config[0].endian = 7; + + hw->buffer_spec[i].canvas_config[1].phy_addr = + hw->buffer_spec[i].dw_u_v_adr; + hw->buffer_spec[i].canvas_config[1].width = canvas_w; + hw->buffer_spec[i].canvas_config[1].height = canvas_h; + hw->buffer_spec[i].canvas_config[1].block_mode = + blkmode; + hw->buffer_spec[i].canvas_config[1].endian = 7; + } + } + WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0x1); + + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, (0 << 8) | (0<<1) | 1); + for (i = 0; i < 32; i++) + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); + return; +} +static void hevc_mcr_config_mc_ref(struct vdec_h264_hw_s *hw) +{ + u32 i; + u32 ref_canv; + struct Slice *pSlice = &(hw->dpb.mSlice); + /*REFLIST[0]*/ + for (i = 0; i < (unsigned int)(pSlice->listXsize[0]); i++) { + struct StorablePicture *ref = pSlice->listX[0][i]; + if (ref == NULL) + return; + WRITE_VREG(CURR_CANVAS_CTRL, ref->buf_spec_num<<24); + ref_canv = READ_VREG(CURR_CANVAS_CTRL)&0xffffff; + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, + (ref->buf_spec_num & 0x3f) << 8); + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, ref_canv); + } + /*REFLIST[1]*/ + for (i = 0; i < (unsigned int)(pSlice->listXsize[1]); i++) { + struct StorablePicture *ref = pSlice->listX[1][i]; + if (ref == NULL) + return; + WRITE_VREG(CURR_CANVAS_CTRL, ref->buf_spec_num<<24); + ref_canv = READ_VREG(CURR_CANVAS_CTRL)&0xffffff; + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, + (ref->buf_spec_num & 0x3f) << 8); + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, ref_canv); + } + return; +} + +static void hevc_mcr_config_mcrcc(struct vdec_h264_hw_s *hw) +{ + u32 rdata32; + u32 rdata32_2; + u32 slice_type; + struct StorablePicture *ref; + struct Slice *pSlice; + slice_type = hw->dpb.mSlice.slice_type; + pSlice = &(hw->dpb.mSlice); + WRITE_VREG(HEVCD_MCRCC_CTL1, 0x2); + if (slice_type == I_SLICE) { + WRITE_VREG(HEVCD_MCRCC_CTL1, 0x0); + return; + } + if (slice_type == B_SLICE) { + ref = pSlice->listX[0][0]; + if (ref == NULL) + return; + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, + ((ref->buf_spec_num & 0x3f) << 8)); + rdata32 = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR); + rdata32 = rdata32 & 0xffff; + rdata32 = rdata32 | (rdata32 << 16); + WRITE_VREG(HEVCD_MCRCC_CTL2, rdata32); + + ref = pSlice->listX[1][0]; + if (ref == NULL) + return; + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, + ((ref->buf_spec_num & 0x3f) << 8)); + rdata32_2 = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR); + rdata32_2 = rdata32_2 & 0xffff; + rdata32_2 = rdata32_2 | (rdata32_2 << 16); + if (rdata32 == rdata32_2) { + ref = pSlice->listX[1][1]; + if (ref == NULL) + return; + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, + ((ref->buf_spec_num & 0x3f) << 8)); + rdata32_2 = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR); + rdata32_2 = rdata32_2 & 0xffff; + rdata32_2 = rdata32_2 | (rdata32_2 << 16); + } + WRITE_VREG(HEVCD_MCRCC_CTL3, rdata32_2); + } else { /*P-PIC*/ + ref = pSlice->listX[0][0]; + if (ref == NULL) + return; + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, + ((ref->buf_spec_num & 0x3f) << 8)); + rdata32 = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR); + rdata32 = rdata32 & 0xffff; + rdata32 = rdata32 | (rdata32 << 16); + WRITE_VREG(HEVCD_MCRCC_CTL2, rdata32); + + ref = pSlice->listX[0][1]; + if (ref == NULL) + return; + WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, + ((ref->buf_spec_num & 0x3f) << 8)); + rdata32 = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR); + rdata32 = rdata32 & 0xffff; + rdata32 = rdata32 | (rdata32 << 16); + WRITE_VREG(HEVCD_MCRCC_CTL3, rdata32); + } + WRITE_VREG(HEVCD_MCRCC_CTL1, 0xff0); + return; +} + + +static void hevc_mcr_sao_global_hw_init(struct vdec_h264_hw_s *hw, + u32 width, u32 height) { + u32 data32; + u32 lcu_x_num, lcu_y_num; + u32 lcu_total; + u32 mc_buffer_size_u_v; + u32 mc_buffer_size_u_v_h; + int dw_mode = hw->double_write_mode; + + /*lcu_x_num = (width + 15) >> 4;*/ + // width need to be round to 64 pixel -- case0260 1/10/2020 + lcu_x_num = (((width + 63) >> 6) << 2); + lcu_y_num = (height + 15) >> 4; + lcu_total = lcu_x_num * lcu_y_num; + + hw->mc_buffer_size_u_v = mc_buffer_size_u_v = lcu_total*16*16/2; + hw->mc_buffer_size_u_v_h = + mc_buffer_size_u_v_h = (mc_buffer_size_u_v + 0xffff)>>16; + + hw->losless_comp_body_size = 0; + + hw->losless_comp_body_size_sao = + compute_losless_comp_body_size(width, height, 0); + hw->losless_comp_header_size = + compute_losless_comp_header_size(width, height); + + WRITE_VREG(HEVCD_IPP_TOP_CNTL, 0x1); /*sw reset ipp10b_top*/ + WRITE_VREG(HEVCD_IPP_TOP_CNTL, 0x0); /*sw reset ipp10b_top*/ + + /* setup lcu_size = 16*/ + WRITE_VREG(HEVCD_IPP_TOP_LCUCONFIG, 16); /*set lcu size = 16*/ + /*pic_width/pic_height*/ + WRITE_VREG(HEVCD_IPP_TOP_FRMCONFIG, + (height & 0xffff) << 16 | (width & 0xffff)); + /* bitdepth_luma = 8*/ + /* bitdepth_chroma = 8*/ + WRITE_VREG(HEVCD_IPP_BITDEPTH_CONFIG, 0x0);/*set bit-depth 8 */ + +#ifdef H265_LOSLESS_COMPRESS_MODE + WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0x1 << 4)); + WRITE_VREG(HEVCD_MPP_DECOMP_CTL2, 0x0); +#else + WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31); +#endif + data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG); + data32 &= (~0x30); + data32 |= (hw->canvas_mode << 4); + WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32); + + WRITE_VREG(HEVCD_MPP_DECOMP_CTL3, + (0x80 << 20) | (0x80 << 10) | (0xff)); + + WRITE_VREG(HEVCD_MPP_VDEC_MCR_CTL, 0x1 | (0x1 << 4)); + + /*comfig vdec:h264:mdec to use hevc mcr/mcrcc/decomp*/ + WRITE_VREG(MDEC_PIC_DC_MUX_CTRL, + READ_VREG(MDEC_PIC_DC_MUX_CTRL) | 0x1 << 31); + /* ipp_enable*/ + WRITE_VREG(HEVCD_IPP_TOP_CNTL, 0x1 << 1); + + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { + WRITE_VREG(HEVC_DBLK_CFG1, 0x2); // set ctusize==16 + WRITE_VREG(HEVC_DBLK_CFG2, ((height & 0xffff)<<16) | (width & 0xffff)); + if (dw_mode & 0x10) + WRITE_VREG(HEVC_DBLK_CFGB, 0x40405603); + else if (dw_mode) + WRITE_VREG(HEVC_DBLK_CFGB, 0x40405703); + else + WRITE_VREG(HEVC_DBLK_CFGB, 0x40405503); + } + + data32 = READ_VREG(HEVC_SAO_CTRL0); + data32 &= (~0xf); + data32 |= 0x4; + WRITE_VREG(HEVC_SAO_CTRL0, data32); + WRITE_VREG(HEVC_SAO_PIC_SIZE, (height & 0xffff) << 16 | + (width & 0xffff)); + data32 = ((lcu_x_num-1) | (lcu_y_num-1) << 16); + + WRITE_VREG(HEVC_SAO_PIC_SIZE_LCU, data32); + data32 = (lcu_x_num | lcu_y_num << 16); + WRITE_VREG(HEVC_SAO_TILE_SIZE_LCU, data32); + data32 = (mc_buffer_size_u_v_h << 16) << 1; + WRITE_VREG(HEVC_SAO_Y_LENGTH, data32); + data32 = (mc_buffer_size_u_v_h << 16); + WRITE_VREG(HEVC_SAO_C_LENGTH, data32); + + data32 = READ_VREG(HEVC_SAO_CTRL1); + data32 &= (~0x3000); + data32 &= (~0xff0); + data32 |= endian; /* Big-Endian per 64-bit */ + + if (hw->mmu_enable && (dw_mode & 0x10)) + data32 |= ((hw->canvas_mode << 12) |1); + else if (hw->mmu_enable && dw_mode) + data32 |= ((hw->canvas_mode << 12)); + else + data32 |= ((hw->canvas_mode << 12)|2); + + WRITE_VREG(HEVC_SAO_CTRL1, data32); + +#ifdef H265_DW_NO_SCALE + WRITE_VREG(HEVC_SAO_CTRL5, READ_VREG(HEVC_SAO_CTRL5) & ~(0xff << 16)); + if (hw->mmu_enable && dw_mode) { + data32 = READ_VREG(HEVC_SAO_CTRL5); + data32 &= (~(0xff << 16)); + if (dw_mode == 2 || + dw_mode == 3) + data32 |= (0xff<<16); + else if (dw_mode == 4) + data32 |= (0x33<<16); + WRITE_VREG(HEVC_SAO_CTRL5, data32); + } + + +#endif + + +#ifdef H265_LOSLESS_COMPRESS_MODE + data32 = READ_VREG(HEVC_SAO_CTRL5); + data32 |= (1<<9); /*8-bit smem-mode*/ + WRITE_VREG(HEVC_SAO_CTRL5, data32); + + WRITE_VREG(HEVC_CM_BODY_LENGTH, hw->losless_comp_body_size_sao); + WRITE_VREG(HEVC_CM_HEADER_OFFSET, hw->losless_comp_body_size); + WRITE_VREG(HEVC_CM_HEADER_LENGTH, hw->losless_comp_header_size); +#endif + +#ifdef H265_LOSLESS_COMPRESS_MODE + WRITE_VREG(HEVC_SAO_CTRL9, READ_VREG(HEVC_SAO_CTRL9) | (0x1 << 1)); + WRITE_VREG(HEVC_SAO_CTRL5, READ_VREG(HEVC_SAO_CTRL5) | (0x1 << 10)); +#endif + + WRITE_VREG(HEVC_SAO_CTRL9, READ_VREG(HEVC_SAO_CTRL9) | 0x1 << 7); + + memset(hw->frame_mmu_map_addr, 0, FRAME_MMU_MAP_SIZE); + + WRITE_VREG(MDEC_EXTIF_CFG0, hw->extif_addr); + WRITE_VREG(MDEC_EXTIF_CFG1, 0x80000000); + return; +} + +static void hevc_sao_set_slice_type(struct vdec_h264_hw_s *hw, + u32 is_new_pic, u32 is_idr) +{ + hw->is_new_pic = is_new_pic; + hw->is_idr_frame = is_idr; + return; +} + +static void hevc_sao_set_pic_buffer(struct vdec_h264_hw_s *hw, + struct StorablePicture *pic) { + u32 mc_y_adr; + u32 mc_u_v_adr; + u32 dw_y_adr; + u32 dw_u_v_adr; + u32 canvas_addr; + int ret; + int dw_mode = hw->double_write_mode; + if (hw->is_new_pic != 1) + return; + + if (hw->is_idr_frame) { + /* William TBD */ + memset(hw->frame_mmu_map_addr, 0, FRAME_MMU_MAP_SIZE); + } + + WRITE_VREG(CURR_CANVAS_CTRL, pic->buf_spec_num << 24); + canvas_addr = READ_VREG(CURR_CANVAS_CTRL)&0xffffff; + WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, (0x0 << 1) | + (0x0 << 2) | ((canvas_addr & 0xff) << 8)); + mc_y_adr = READ_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA) << 5; + WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, (0x0 << 1) | + (0x0 << 2) | (((canvas_addr >> 8) & 0xff) << 8)); + mc_u_v_adr = READ_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA) << 5; + WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0x1); + + + if (dw_mode) { + dw_y_adr = hw->buffer_spec[pic->buf_spec_num].dw_y_adr; + dw_u_v_adr = hw->buffer_spec[pic->buf_spec_num].dw_u_v_adr; + } else { + dw_y_adr = 0; + dw_u_v_adr = 0; + } +#ifdef H265_LOSLESS_COMPRESS_MODE + if (dw_mode) + WRITE_VREG(HEVC_SAO_Y_START_ADDR, dw_y_adr); + WRITE_VREG(HEVC_CM_BODY_START_ADDR, mc_y_adr); +#ifdef H264_MMU + WRITE_VREG(HEVC_CM_HEADER_START_ADDR, mc_y_adr); +#else + WRITE_VREG(HEVC_CM_HEADER_START_ADDR, + (mc_y_adr + hw->losless_comp_body_size)); +#endif +#else + WRITE_VREG(HEVC_SAO_Y_START_ADDR, mc_y_adr); +#endif + +#ifndef H265_LOSLESS_COMPRESS_MODE + WRITE_VREG(HEVC_SAO_C_START_ADDR, mc_u_v_adr); +#else + if (dw_mode) + WRITE_VREG(HEVC_SAO_C_START_ADDR, dw_u_v_adr); +#endif + +#ifndef LOSLESS_COMPRESS_MODE + if (dw_mode) { + WRITE_VREG(HEVC_SAO_Y_WPTR, mc_y_adr); + WRITE_VREG(HEVC_SAO_C_WPTR, mc_u_v_adr); + } +#else + WRITE_VREG(HEVC_SAO_Y_WPTR, dw_y_adr); + WRITE_VREG(HEVC_SAO_C_WPTR, dw_u_v_adr); +#endif + + ret = hevc_alloc_mmu(hw, pic->buf_spec_num, + (hw->mb_width << 4), (hw->mb_height << 4), 0x0, + hw->frame_mmu_map_addr); + if (ret != 0) { + dpb_print(DECODE_ID(hw), + PRINT_FLAG_MMU_DETAIL, "can't alloc need mmu1,idx %d ret =%d\n", + pic->buf_spec_num, + ret); + return; + } + + /*Reset SAO + Enable SAO slice_start*/ + if (hw->mmu_enable && get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) + WRITE_VREG(HEVC_DBLK_CFG0, 0x1); // reset buffer32x4 in lpf for every picture + WRITE_VREG(HEVC_SAO_INT_STATUS, + READ_VREG(HEVC_SAO_INT_STATUS) | 0x1 << 28); + WRITE_VREG(HEVC_SAO_INT_STATUS, + READ_VREG(HEVC_SAO_INT_STATUS) | 0x1 << 31); + /*pr_info("hevc_sao_set_pic_buffer:mc_y_adr: %x\n", mc_y_adr);*/ + /*Send coommand to hevc-code to supply 4k buffers to sao*/ + + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_G12A) { + WRITE_VREG(H265_SAO_4K_SET_BASE, (u32)hw->frame_mmu_map_phy_addr); + WRITE_VREG(H265_SAO_4K_SET_COUNT, MAX_FRAME_4K_NUM); + } else + WRITE_VREG(HEVC_ASSIST_MMU_MAP_ADDR, (u32)hw->frame_mmu_map_phy_addr); + WRITE_VREG(SYS_COMMAND, H265_PUT_SAO_4K_SET); + hw->frame_busy = 1; + return; +} + + +static void hevc_set_unused_4k_buff_idx(struct vdec_h264_hw_s *hw, + u32 buf_spec_num) { + WRITE_VREG(CURR_CANVAS_CTRL, buf_spec_num<<24); + hw->hevc_cur_buf_idx = READ_VREG(CURR_CANVAS_CTRL)&0xff; + dpb_print(DECODE_ID(hw), + PRINT_FLAG_MMU_DETAIL, " %s cur_buf_idx %d buf_spec_num %d\n", + __func__, hw->hevc_cur_buf_idx, buf_spec_num); + return; +} + + +static void hevc_set_frame_done(struct vdec_h264_hw_s *hw) +{ + ulong timeout = jiffies + HZ; + dpb_print(DECODE_ID(hw), + PRINT_FLAG_MMU_DETAIL, "hevc_frame_done...set\n"); + while ((READ_VREG(HEVC_SAO_INT_STATUS) & 0x1) == 0) { + if (time_after(jiffies, timeout)) { + dpb_print(DECODE_ID(hw), + PRINT_FLAG_MMU_DETAIL, " %s..timeout!\n", __func__); + break; + } + } + timeout = jiffies + HZ; + while (READ_VREG(HEVC_CM_CORE_STATUS) & 0x1) { + if (time_after(jiffies, timeout)) { + dpb_print(DECODE_ID(hw), + PRINT_FLAG_MMU_DETAIL, " %s cm_core..timeout!\n", __func__); + break; + } + } + WRITE_VREG(HEVC_SAO_INT_STATUS, 0x1); + hw->frame_done = 1; + return; +} + +static void release_cur_decoding_buf(struct vdec_h264_hw_s *hw) +{ + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + if (p_H264_Dpb->mVideo.dec_picture) { + release_picture(p_H264_Dpb, + p_H264_Dpb->mVideo.dec_picture); + p_H264_Dpb->mVideo.dec_picture->data_flag &= ~ERROR_FLAG; + p_H264_Dpb->mVideo.dec_picture = NULL; + if (hw->mmu_enable) + hevc_set_frame_done(hw); + } +} + +static void hevc_sao_wait_done(struct vdec_h264_hw_s *hw) +{ + ulong timeout = jiffies + HZ; + dpb_print(DECODE_ID(hw), + PRINT_FLAG_MMU_DETAIL, "hevc_sao_wait_done...start\n"); + while ((READ_VREG(HEVC_SAO_INT_STATUS) >> 31)) { + if (time_after(jiffies, timeout)) { + dpb_print(DECODE_ID(hw), + PRINT_FLAG_MMU_DETAIL, + "hevc_sao_wait_done...wait timeout!\n"); + break; + } + } + timeout = jiffies + HZ; + if ((hw->frame_busy == 1) && (hw->frame_done == 1) ) { + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_G12A) { + WRITE_VREG(SYS_COMMAND, H265_ABORT_SAO_4K_SET); + while ((READ_VREG(SYS_COMMAND) & 0xff) != + H265_ABORT_SAO_4K_SET_DONE) { + if (time_after(jiffies, timeout)) { + dpb_print(DECODE_ID(hw), + PRINT_FLAG_MMU_DETAIL, + "wait h265_abort_sao_4k_set_done timeout!\n"); + break; + } + } + } + amhevc_stop(); + hw->frame_busy = 0; + hw->frame_done = 0; + dpb_print(DECODE_ID(hw), + PRINT_FLAG_MMU_DETAIL, + "sao wait done ,hevc stop!\n"); + } + return; +} +static void buf_spec_init(struct vdec_h264_hw_s *hw, bool buffer_reset_flag) +{ + int i; + unsigned long flags; + spin_lock_irqsave(&hw->bufspec_lock, flags); + + for (i = 0; i < VF_POOL_SIZE; i++) { + struct vframe_s *vf = &hw->vfpool[hw->cur_pool][i]; + u32 ref_idx = BUFSPEC_INDEX(vf->index); + if ((vf->index != -1) && + (hw->buffer_spec[ref_idx].vf_ref == 0) && + (hw->buffer_spec[ref_idx].used != -1)) { + vf->index = -1; + } + } + + hw->cur_pool++; + if (hw->cur_pool >= VF_POOL_NUM) + hw->cur_pool = 0; + + for (i = 0; i < VF_POOL_SIZE; i++) { + struct vframe_s *vf = &hw->vfpool[hw->cur_pool][i]; + u32 ref_idx = BUFSPEC_INDEX(vf->index); + if ((vf->index != -1) && + (hw->buffer_spec[ref_idx].vf_ref == 0) && + (hw->buffer_spec[ref_idx].used != -1)) { + vf->index = -1; + } + } + /* buffers are alloced when error reset, v4l must find buffer by buffer_wrap[] */ + if (hw->reset_bufmgr_flag && buffer_reset_flag) { + for (i = 0; i < BUFSPEC_POOL_SIZE; i++) { + if (hw->buffer_spec[i].used == 1 || hw->buffer_spec[i].used == 2) + hw->buffer_spec[i].used = 0; + } + } else { + for (i = 0; i < BUFSPEC_POOL_SIZE; i++) { + hw->buffer_spec[i].used = -1; + hw->buffer_spec[i].canvas_pos = -1; + hw->buffer_wrap[i] = -1; + } + } + + if (dpb_is_debug(DECODE_ID(hw), + PRINT_FLAG_DUMP_BUFSPEC)) + dump_bufspec(hw, __func__); + spin_unlock_irqrestore(&hw->bufspec_lock, flags); +} + + +/*is active in buf management */ +static unsigned char is_buf_spec_in_use(struct vdec_h264_hw_s *hw, + int buf_spec_num) +{ + unsigned char ret = 0; + if (hw->buffer_spec[buf_spec_num].used == 1 || + hw->buffer_spec[buf_spec_num].used == 2 || + hw->buffer_spec[buf_spec_num].used == 3 || + hw->buffer_spec[buf_spec_num].used == 5) + ret = 1; + return ret; +} + +static unsigned char is_buf_spec_in_disp_q(struct vdec_h264_hw_s *hw, + int buf_spec_num) +{ + unsigned char ret = 0; + if (hw->buffer_spec[buf_spec_num].used == 2 || + hw->buffer_spec[buf_spec_num].used == 3 || + hw->buffer_spec[buf_spec_num].used == 5) + ret = 1; + return ret; +} + +static int alloc_one_buf_spec(struct vdec_h264_hw_s *hw, int i) +{ + struct vdec_s *vdec = hw_to_vdec(hw); + if (hw->mmu_enable) { + if (hw->buffer_spec[i].alloc_header_addr) + return 0; + else + return -1; + } else { + + int buf_size = (hw->mb_total << 8) + (hw->mb_total << 7); + int addr; +#ifdef VDEC_DW + int orig_buf_size; + orig_buf_size = buf_size; + if (IS_VDEC_DW(hw) == 1) + buf_size += (hw->mb_total << 7) + (hw->mb_total << 6); + else if (IS_VDEC_DW(hw) == 2) + buf_size += (hw->mb_total << 6) + (hw->mb_total << 5); + else if (IS_VDEC_DW(hw) == 4) + buf_size += (hw->mb_total << 4) + (hw->mb_total << 3); + else if (IS_VDEC_DW(hw) == 8) + buf_size += (hw->mb_total << 2) + (hw->mb_total << 1); + if (IS_VDEC_DW(hw)) { + u32 align_size; + /* add align padding size for blk64x32: (mb_w<<4)*32, (mb_h<<4)*64 */ + align_size = ((hw->mb_width << 9) + (hw->mb_height << 10)) / IS_VDEC_DW(hw); + /* double align padding size for uv*/ + align_size <<= 1; + buf_size += align_size + PAGE_SIZE; + } +#endif + if (hw->buffer_spec[i].cma_alloc_addr) + return 0; + + if (decoder_bmmu_box_alloc_buf_phy(hw->bmmu_box, i, + PAGE_ALIGN(buf_size), DRIVER_NAME, + &hw->buffer_spec[i].cma_alloc_addr) < 0) { + hw->buffer_spec[i].cma_alloc_addr = 0; + if (hw->no_mem_count++ > 3) { + hw->stat |= DECODER_FATAL_ERROR_NO_MEM; + hw->reset_bufmgr_flag = 1; + } + dpb_print(DECODE_ID(hw), 0, + "%s, fail to alloc buf for bufspec%d, try later\n", + __func__, i + ); + return -1; + } else { + hw->no_mem_count = 0; + hw->stat &= ~DECODER_FATAL_ERROR_NO_MEM; + } + if (!vdec_secure(vdec)) { + /*init internal buf*/ + char *tmpbuf = (char *)codec_mm_phys_to_virt(hw->buffer_spec[i].cma_alloc_addr); + if (tmpbuf) { + memset(tmpbuf, 0, PAGE_ALIGN(buf_size)); + codec_mm_dma_flush(tmpbuf, + PAGE_ALIGN(buf_size), + DMA_TO_DEVICE); + } else { + tmpbuf = codec_mm_vmap(hw->buffer_spec[i].cma_alloc_addr, PAGE_ALIGN(buf_size)); + if (tmpbuf) { + memset(tmpbuf, 0, PAGE_ALIGN(buf_size)); + codec_mm_dma_flush(tmpbuf, + PAGE_ALIGN(buf_size), + DMA_TO_DEVICE); + codec_mm_unmap_phyaddr(tmpbuf); + } + } + } + hw->buffer_spec[i].buf_adr = + hw->buffer_spec[i].cma_alloc_addr; + addr = hw->buffer_spec[i].buf_adr; + + + hw->buffer_spec[i].y_addr = addr; + addr += hw->mb_total << 8; + hw->buffer_spec[i].u_addr = addr; + hw->buffer_spec[i].v_addr = addr; + addr += hw->mb_total << 7; + + hw->buffer_spec[i].canvas_config[0].phy_addr = + hw->buffer_spec[i].y_addr; + hw->buffer_spec[i].canvas_config[0].width = + hw->mb_width << 4; + hw->buffer_spec[i].canvas_config[0].height = + hw->mb_height << 4; + hw->buffer_spec[i].canvas_config[0].block_mode = + hw->canvas_mode; + + hw->buffer_spec[i].canvas_config[1].phy_addr = + hw->buffer_spec[i].u_addr; + hw->buffer_spec[i].canvas_config[1].width = + hw->mb_width << 4; + hw->buffer_spec[i].canvas_config[1].height = + hw->mb_height << 3; + hw->buffer_spec[i].canvas_config[1].block_mode = + hw->canvas_mode; + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s, alloc buf for bufspec%d\n", + __func__, i); +#ifdef VDEC_DW + if (!IS_VDEC_DW(hw)) + return 0; + else { + int w_shift = 3, h_shift = 3; + + if (IS_VDEC_DW(hw) == 1) { + w_shift = 3; + h_shift = 4; + } else if (IS_VDEC_DW(hw) == 2) { + w_shift = 3; + h_shift = 3; + } else if (IS_VDEC_DW(hw) == 4) { + w_shift = 2; + h_shift = 2; + } else if (IS_VDEC_DW(hw) == 8) { + w_shift = 1; + h_shift = 1; + } + + addr = hw->buffer_spec[i].cma_alloc_addr + PAGE_ALIGN(orig_buf_size); + hw->buffer_spec[i].vdec_dw_y_addr = addr; + addr += ALIGN_WIDTH(hw->mb_width << w_shift) * ALIGN_HEIGHT(hw->mb_height << h_shift); + hw->buffer_spec[i].vdec_dw_u_addr = addr; + hw->buffer_spec[i].vdec_dw_v_addr = addr; + addr += hw->mb_total << (w_shift + h_shift - 1); + + hw->buffer_spec[i].vdec_dw_canvas_config[0].phy_addr = + hw->buffer_spec[i].vdec_dw_y_addr; + hw->buffer_spec[i].vdec_dw_canvas_config[0].width = + ALIGN_WIDTH(hw->mb_width << w_shift); + hw->buffer_spec[i].vdec_dw_canvas_config[0].height = + ALIGN_HEIGHT(hw->mb_height << h_shift); + hw->buffer_spec[i].vdec_dw_canvas_config[0].block_mode = + hw->canvas_mode; + + hw->buffer_spec[i].vdec_dw_canvas_config[1].phy_addr = + hw->buffer_spec[i].vdec_dw_u_addr; + hw->buffer_spec[i].vdec_dw_canvas_config[1].width = + ALIGN_WIDTH(hw->mb_width << w_shift); + hw->buffer_spec[i].vdec_dw_canvas_config[1].height = + ALIGN_HEIGHT(hw->mb_height << (h_shift - 1)); + hw->buffer_spec[i].vdec_dw_canvas_config[1].block_mode = + hw->canvas_mode; + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s, vdec_dw: alloc buf for bufspec%d blkmod %d\n", + __func__, i, hw->canvas_mode); + } +#endif + } + return 0; +} + +static void vh264_put_video_frame(void *vdec_ctx, struct vframe_s *vf) +{ + vh264_vf_put(vf, vdec_ctx); +} + +static void vh264_get_video_frame(void *vdec_ctx, struct vframe_s **vf) +{ + *vf = vh264_vf_get(vdec_ctx); +} + +static struct task_ops_s task_dec_ops = { + .type = TASK_TYPE_DEC, + .get_vframe = vh264_get_video_frame, + .put_vframe = vh264_put_video_frame, +}; + +static int alloc_one_buf_spec_from_queue(struct vdec_h264_hw_s *hw, int idx) +{ + int ret = 0; + struct aml_vcodec_ctx *ctx = NULL; + struct buffer_spec_s *bs = &hw->buffer_spec[idx]; + struct canvas_config_s *y_canvas_cfg = NULL; + struct canvas_config_s *c_canvas_cfg = NULL; + struct vdec_v4l2_buffer *fb = NULL; + unsigned int y_addr = 0, c_addr = 0; + + if (IS_ERR_OR_NULL(hw->v4l2_ctx)) { + pr_err("the v4l context has err.\n"); + return -1; + } + + if (bs->cma_alloc_addr) + return 0; + + ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + dpb_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL, + "[%d] %s(), try alloc from v4l queue buf size: %d\n", + ctx->id, __func__, + (hw->mb_total << 8) + (hw->mb_total << 7)); + + ret = ctx->fb_ops.alloc(&ctx->fb_ops, hw->fb_token, &fb, AML_FB_REQ_DEC); + if (ret < 0) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL, + "[%d] get fb fail.\n", ctx->id); + return ret; + } + + bs->cma_alloc_addr = (unsigned long)fb; + dpb_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL, + "[%d] %s(), cma alloc addr: 0x%x, out %d dec %d\n", + ctx->id, __func__, bs->cma_alloc_addr, + ctx->cap_pool.out, ctx->cap_pool.dec); + + if (fb->num_planes == 1) { + y_addr = fb->m.mem[0].addr; + c_addr = fb->m.mem[0].addr + fb->m.mem[0].offset; + fb->m.mem[0].bytes_used = fb->m.mem[0].size; + } else if (fb->num_planes == 2) { + y_addr = fb->m.mem[0].addr; + c_addr = fb->m.mem[1].addr; + fb->m.mem[0].bytes_used = fb->m.mem[0].size; + fb->m.mem[1].bytes_used = fb->m.mem[1].size; + } + + fb->task->attach(fb->task, &task_dec_ops, hw_to_vdec(hw)); + fb->status = FB_ST_DECODER; + + dpb_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL, + "[%d] %s(), y_addr: %x, size: %u\n", + ctx->id, __func__, y_addr, fb->m.mem[0].size); + dpb_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL, + "[%d] %s(), c_addr: %x, size: %u\n", + ctx->id, __func__, c_addr, fb->m.mem[1].size); + + bs->y_addr = y_addr; + bs->u_addr = c_addr; + bs->v_addr = c_addr; + + y_canvas_cfg = &bs->canvas_config[0]; + c_canvas_cfg = &bs->canvas_config[1]; + + y_canvas_cfg->phy_addr = y_addr; + y_canvas_cfg->width = hw->mb_width << 4; + y_canvas_cfg->height = hw->mb_height << 4; + y_canvas_cfg->block_mode = hw->canvas_mode; + //fb->m.mem[0].bytes_used = y_canvas_cfg->width * y_canvas_cfg->height; + dpb_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL, + "[%d] %s(), y_w: %d, y_h: %d\n", ctx->id, __func__, + y_canvas_cfg->width,y_canvas_cfg->height); + + c_canvas_cfg->phy_addr = c_addr; + c_canvas_cfg->width = hw->mb_width << 4; + c_canvas_cfg->height = hw->mb_height << 3; + c_canvas_cfg->block_mode = hw->canvas_mode; + //fb->m.mem[1].bytes_used = c_canvas_cfg->width * c_canvas_cfg->height; + dpb_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL, + "[%d] %s(), c_w: %d, c_h: %d\n", ctx->id, __func__, + c_canvas_cfg->width, c_canvas_cfg->height); + + dpb_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL, + "[%d] %s(), alloc buf for bufspec%d\n", ctx->id, __func__, idx); + + return ret; +} + +static void config_decode_canvas(struct vdec_h264_hw_s *hw, int i) +{ + int blkmode = hw->canvas_mode; + int endian = 0; + + if (blkmode == CANVAS_BLKMODE_LINEAR) { + if ((h264_debug_flag & IGNORE_PARAM_FROM_CONFIG) == 0) + endian = 7; + else + endian = 0; + } + + if (hw->is_used_v4l) + endian = 7; + + config_cav_lut_ex(hw->buffer_spec[i]. + y_canvas_index, + hw->buffer_spec[i].y_addr, + hw->mb_width << 4, + hw->mb_height << 4, + CANVAS_ADDR_NOWRAP, + blkmode, + endian, + VDEC_1); + + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { + WRITE_VREG(VDEC_ASSIST_CANVAS_BLK32, + (1 << 11) | /* canvas_blk32_wr */ + (blkmode << 10) | /* canvas_blk32*/ + (1 << 8) | /* canvas_index_wr*/ + (hw->buffer_spec[i].y_canvas_index << 0) /* canvas index*/ + ); + } + + config_cav_lut_ex(hw->buffer_spec[i]. + u_canvas_index, + hw->buffer_spec[i].u_addr, + hw->mb_width << 4, + hw->mb_height << 3, + CANVAS_ADDR_NOWRAP, + blkmode, + endian, + VDEC_1); + + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { + WRITE_VREG(VDEC_ASSIST_CANVAS_BLK32, + (1 << 11) | + (blkmode << 10) | + (1 << 8) | + (hw->buffer_spec[i].u_canvas_index << 0)); + } + + WRITE_VREG(ANC0_CANVAS_ADDR + hw->buffer_spec[i].canvas_pos, + spec2canvas(&hw->buffer_spec[i])); + + +#ifdef VDEC_DW + if (!IS_VDEC_DW(hw)) + return; + else { + config_cav_lut_ex(hw->buffer_spec[i]. + vdec_dw_y_canvas_index, + hw->buffer_spec[i].vdec_dw_canvas_config[0].phy_addr, + hw->buffer_spec[i].vdec_dw_canvas_config[0].width, + hw->buffer_spec[i].vdec_dw_canvas_config[0].height, + CANVAS_ADDR_NOWRAP, + blkmode, + endian, + VDEC_1); + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { + WRITE_VREG(VDEC_ASSIST_CANVAS_BLK32, + (1 << 11) | + (blkmode << 10) | + (1 << 8) | + (hw->buffer_spec[i].vdec_dw_y_canvas_index << 0)); + } + + config_cav_lut_ex(hw->buffer_spec[i]. + vdec_dw_u_canvas_index, + hw->buffer_spec[i].vdec_dw_canvas_config[1].phy_addr, + hw->buffer_spec[i].vdec_dw_canvas_config[1].width, + hw->buffer_spec[i].vdec_dw_canvas_config[1].height, + CANVAS_ADDR_NOWRAP, + blkmode, + endian, + VDEC_1); + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { + WRITE_VREG(VDEC_ASSIST_CANVAS_BLK32, + (1 << 11) | + (blkmode << 10) | + (1 << 8) | + (hw->buffer_spec[i].vdec_dw_u_canvas_index << 0)); + } + } +#endif +} + +static void config_decode_canvas_ex(struct vdec_h264_hw_s *hw, int i) +{ + u32 blkmode = hw->canvas_mode; + int canvas_w; + int canvas_h; + + canvas_w = hw->frame_width / + get_double_write_ratio(hw->double_write_mode); + canvas_h = hw->frame_height / + get_double_write_ratio(hw->double_write_mode); + + if (hw->canvas_mode == 0) + canvas_w = ALIGN(canvas_w, 32); + else + canvas_w = ALIGN(canvas_w, 64); + canvas_h = ALIGN(canvas_h, 32); + + config_cav_lut_ex(hw->buffer_spec[i]. + y_canvas_index, + hw->buffer_spec[i].dw_y_adr, + canvas_w, + canvas_h, + CANVAS_ADDR_NOWRAP, + blkmode, + 7, + VDEC_HEVC); + + config_cav_lut_ex(hw->buffer_spec[i]. + u_canvas_index, + hw->buffer_spec[i].dw_u_v_adr, + canvas_w, + canvas_h, + CANVAS_ADDR_NOWRAP, + blkmode, + 7, + VDEC_HEVC); +} + +static int v4l_get_free_buffer_spec(struct vdec_h264_hw_s *hw) +{ + int i; + + for (i = 0; i < BUFSPEC_POOL_SIZE; i++) { + if (hw->buffer_spec[i].cma_alloc_addr == 0) + return i; + } + + return -1; +} + +static int v4l_find_buffer_spec_idx(struct vdec_h264_hw_s *hw, unsigned int v4l_indx) +{ + int i; + + for (i = 0; i < BUFSPEC_POOL_SIZE; i++) { + if (hw->buffer_wrap[i] == v4l_indx) + return i; + } + return -1; +} + +static int v4l_get_free_buf_idx(struct vdec_s *vdec) +{ + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; + struct aml_vcodec_ctx * v4l = hw->v4l2_ctx; + struct v4l_buff_pool *pool = &v4l->cap_pool; + struct buffer_spec_s *pic = NULL; + int i, rt, idx = INVALID_IDX; + ulong flags; + u32 state = 0, index; + + spin_lock_irqsave(&hw->bufspec_lock, flags); + for (i = 0; i < pool->in; ++i) { + state = (pool->seq[i] >> 16); + index = (pool->seq[i] & 0xffff); + + switch (state) { + case V4L_CAP_BUFF_IN_DEC: + rt = v4l_find_buffer_spec_idx(hw, index); + if (rt >= 0) { + pic = &hw->buffer_spec[rt]; + if ((pic->vf_ref == 0) && + (pic->used == 0) && + pic->cma_alloc_addr) { + idx = rt; + } + } + break; + case V4L_CAP_BUFF_IN_M2M: + rt = v4l_get_free_buffer_spec(hw); + if (rt >= 0) { + pic = &hw->buffer_spec[rt]; + if (!alloc_one_buf_spec_from_queue(hw, rt)) { + struct vdec_v4l2_buffer *fb; + config_decode_canvas(hw, rt); + fb = (struct vdec_v4l2_buffer *)pic->cma_alloc_addr; + hw->buffer_wrap[rt] = fb->buf_idx; + idx = rt; + } + } + break; + default: + break; + } + + if (idx != INVALID_IDX) { + pic->used = 1; + break; + } + } + spin_unlock_irqrestore(&hw->bufspec_lock, flags); + + if (idx < 0) { + dpb_print(DECODE_ID(hw), 0, "%s fail, state %d\n", __func__, state); + for (i = 0; i < BUFSPEC_POOL_SIZE; i++) { + dpb_print(DECODE_ID(hw), 0, "%s, %d\n", + __func__, hw->buffer_wrap[i]); + } + vmh264_dump_state(vdec); + } else { + struct vdec_v4l2_buffer *fb = + (struct vdec_v4l2_buffer *)pic->cma_alloc_addr; + + fb->status = FB_ST_DECODER; + + v4l->aux_infos.bind_sei_buffer(v4l, &pic->aux_data_buf, + &pic->aux_data_size, &pic->ctx_buf_idx); + } + + return idx; +} + +int get_free_buf_idx(struct vdec_s *vdec) +{ + int i; + unsigned long addr, flags; + int index = -1; + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; + int buf_total = BUFSPEC_POOL_SIZE; + + if (hw->is_used_v4l) + return v4l_get_free_buf_idx(vdec); + + spin_lock_irqsave(&hw->bufspec_lock, flags); + /*hw->start_search_pos = 0;*/ + for (i = hw->start_search_pos; i < buf_total; i++) { + if (hw->mmu_enable) + addr = hw->buffer_spec[i].alloc_header_addr; + else + addr = hw->buffer_spec[i].cma_alloc_addr; + + if (hw->buffer_spec[i].vf_ref == 0 && + hw->buffer_spec[i].used == 0 && addr) { + hw->buffer_spec[i].used = 1; + hw->start_search_pos = i+1; + index = i; + hw->buffer_wrap[i] = index; + break; + } + } + if (index < 0) { + for (i = 0; i < hw->start_search_pos; i++) { + if (hw->mmu_enable) + addr = hw->buffer_spec[i].alloc_header_addr; + else + addr = hw->buffer_spec[i].cma_alloc_addr; + + if (hw->buffer_spec[i].vf_ref == 0 && + hw->buffer_spec[i].used == 0 && addr) { + hw->buffer_spec[i].used = 1; + hw->start_search_pos = i+1; + index = i; + hw->buffer_wrap[i] = index; + break; + } + } + } + + spin_unlock_irqrestore(&hw->bufspec_lock, flags); + if (hw->start_search_pos >= buf_total) + hw->start_search_pos = 0; + dpb_print(DECODE_ID(hw), PRINT_FLAG_DPB_DETAIL, + "%s, buf_spec_num %d\n", __func__, index); + + if (index < 0) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_ERROR, + "%s fail\n", __func__); + vmh264_dump_state(vdec); + } + + if (dpb_is_debug(DECODE_ID(hw), + PRINT_FLAG_DUMP_BUFSPEC)) + dump_bufspec(hw, __func__); + return index; +} + +int release_buf_spec_num(struct vdec_s *vdec, int buf_spec_num) +{ + /*u32 cur_buf_idx;*/ + unsigned long flags; + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; + dpb_print(DECODE_ID(hw), PRINT_FLAG_MMU_DETAIL, + "%s buf_spec_num %d used %d\n", + __func__, buf_spec_num, + buf_spec_num > 0 ? hw->buffer_spec[buf_spec_num].used : 0); + if (buf_spec_num >= 0 && + buf_spec_num < BUFSPEC_POOL_SIZE + ) { + spin_lock_irqsave(&hw->bufspec_lock, flags); + hw->buffer_spec[buf_spec_num].used = 0; + spin_unlock_irqrestore(&hw->bufspec_lock, flags); + if (hw->mmu_enable) { + /*WRITE_VREG(CURR_CANVAS_CTRL, buf_spec_num<<24); + cur_buf_idx = READ_VREG(CURR_CANVAS_CTRL); + cur_buf_idx = cur_buf_idx&0xff;*/ + decoder_mmu_box_free_idx(hw->mmu_box, buf_spec_num); + } + release_aux_data(hw, buf_spec_num); + } + if (dpb_is_debug(DECODE_ID(hw), + PRINT_FLAG_DUMP_BUFSPEC)) + dump_bufspec(hw, __func__); + return 0; +} + +static void config_buf_specs(struct vdec_s *vdec) +{ + int i, j; + unsigned long flags; + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; + int mode = IS_VDEC_DW(hw) ? 2 : 1; + + spin_lock_irqsave(&hw->bufspec_lock, flags); + for (i = 0, j = 0; + j < hw->dpb.mDPB.size + && i < BUFSPEC_POOL_SIZE; + i++) { + int canvas; + if (hw->buffer_spec[i].used != -1) + continue; + if (vdec->parallel_dec == 1) { + if (hw->buffer_spec[i].y_canvas_index == -1) + hw->buffer_spec[i].y_canvas_index = vdec->get_canvas_ex(CORE_MASK_VDEC_1, vdec->id); + if (hw->buffer_spec[i].u_canvas_index == -1) { + hw->buffer_spec[i].u_canvas_index = vdec->get_canvas_ex(CORE_MASK_VDEC_1, vdec->id); + hw->buffer_spec[i].v_canvas_index = hw->buffer_spec[i].u_canvas_index; + } +#ifdef VDEC_DW + if (IS_VDEC_DW(hw)) { + if (hw->buffer_spec[i].vdec_dw_y_canvas_index == -1) + hw->buffer_spec[i].vdec_dw_y_canvas_index = + vdec->get_canvas_ex(CORE_MASK_VDEC_1, vdec->id); + if (hw->buffer_spec[i].vdec_dw_u_canvas_index == -1) { + hw->buffer_spec[i].vdec_dw_u_canvas_index = + vdec->get_canvas_ex(CORE_MASK_VDEC_1, vdec->id); + hw->buffer_spec[i].vdec_dw_v_canvas_index = + hw->buffer_spec[i].vdec_dw_u_canvas_index; + } + } +#endif + } else { + canvas = vdec->get_canvas(j * mode, 2); + hw->buffer_spec[i].y_canvas_index = canvas_y(canvas); + hw->buffer_spec[i].u_canvas_index = canvas_u(canvas); + hw->buffer_spec[i].v_canvas_index = canvas_v(canvas); + dpb_print(DECODE_ID(hw), + PRINT_FLAG_DPB_DETAIL, + "config canvas (%d) %x for bufspec %d\r\n", + j, canvas, i); +#ifdef VDEC_DW + if (IS_VDEC_DW(hw)) { + canvas = vdec->get_canvas(j * mode + 1, 2); + hw->buffer_spec[i].vdec_dw_y_canvas_index = canvas_y(canvas); + hw->buffer_spec[i].vdec_dw_u_canvas_index = canvas_u(canvas); + hw->buffer_spec[i].vdec_dw_v_canvas_index = canvas_v(canvas); + dpb_print(DECODE_ID(hw), + PRINT_FLAG_DPB_DETAIL, + "vdec_dw: config canvas (%d) %x for bufspec %d\r\n", + j, canvas, i); + } +#endif + } + + hw->buffer_spec[i].used = 0; + hw->buffer_spec[i].canvas_pos = j; + + + j++; + } + spin_unlock_irqrestore(&hw->bufspec_lock, flags); +} + +static void config_buf_specs_ex(struct vdec_s *vdec) +{ + int i, j; + unsigned long flags; + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; + int mode = IS_VDEC_DW(hw) ? 2 : 1; + + spin_lock_irqsave(&hw->bufspec_lock, flags); + for (i = 0, j = 0; + j < hw->dpb.mDPB.size + && i < BUFSPEC_POOL_SIZE; + i++) { + int canvas = 0; + if (hw->buffer_spec[i].used != -1) + continue; + if (vdec->parallel_dec == 1) { + if (hw->buffer_spec[i].y_canvas_index == -1) + hw->buffer_spec[i].y_canvas_index = vdec->get_canvas_ex(CORE_MASK_VDEC_1, vdec->id); + if (hw->buffer_spec[i].u_canvas_index == -1) { + hw->buffer_spec[i].u_canvas_index = vdec->get_canvas_ex(CORE_MASK_VDEC_1, vdec->id); + hw->buffer_spec[i].v_canvas_index = hw->buffer_spec[i].u_canvas_index; + } +#ifdef VDEC_DW + if (IS_VDEC_DW(hw)) { + if (hw->buffer_spec[i].vdec_dw_y_canvas_index == -1) + hw->buffer_spec[i].vdec_dw_y_canvas_index = + vdec->get_canvas_ex(CORE_MASK_VDEC_1, vdec->id); + if (hw->buffer_spec[i].vdec_dw_u_canvas_index == -1) { + hw->buffer_spec[i].vdec_dw_u_canvas_index = + vdec->get_canvas_ex(CORE_MASK_VDEC_1, vdec->id); + hw->buffer_spec[i].vdec_dw_v_canvas_index = + hw->buffer_spec[i].vdec_dw_u_canvas_index; + } + } +#endif + } else { + canvas = vdec->get_canvas(j* mode, 2); + hw->buffer_spec[i].y_canvas_index = canvas_y(canvas); + hw->buffer_spec[i].u_canvas_index = canvas_u(canvas); + hw->buffer_spec[i].v_canvas_index = canvas_v(canvas); + + dpb_print(DECODE_ID(hw), + PRINT_FLAG_DPB_DETAIL, + "config canvas (%d) %x for bufspec %d\r\n", + j, canvas, i); +#ifdef VDEC_DW + if (IS_VDEC_DW(hw)) { + canvas = vdec->get_canvas(j*mode + 1, 2); + hw->buffer_spec[i].vdec_dw_y_canvas_index = canvas_y(canvas); + hw->buffer_spec[i].vdec_dw_u_canvas_index = canvas_u(canvas); + hw->buffer_spec[i].vdec_dw_v_canvas_index = canvas_v(canvas); + dpb_print(DECODE_ID(hw), + PRINT_FLAG_DPB_DETAIL, + "vdec_dw: config canvas (%d) %x for bufspec %d\r\n", + j, canvas, i); + } +#endif + } + + hw->buffer_spec[i].used = 0; + hw->buffer_spec[i].alloc_header_addr = 0; + hw->buffer_spec[i].canvas_pos = j; + + j++; + } + spin_unlock_irqrestore(&hw->bufspec_lock, flags); +} + + +static void dealloc_buf_specs(struct vdec_h264_hw_s *hw, + unsigned char release_all) +{ + int i; + unsigned long flags; + unsigned char dealloc_flag = 0; + for (i = 0; i < BUFSPEC_POOL_SIZE; i++) { + if (hw->buffer_spec[i].used == 4 || + release_all) { + dealloc_flag = 1; + dpb_print(DECODE_ID(hw), + PRINT_FLAG_DPB_DETAIL, + "%s buf_spec_num %d\n", + __func__, i + ); + spin_lock_irqsave + (&hw->bufspec_lock, flags); + hw->buffer_spec[i].used = -1; + spin_unlock_irqrestore + (&hw->bufspec_lock, flags); + release_aux_data(hw, i); + + if (!hw->mmu_enable) { + if (hw->buffer_spec[i].cma_alloc_addr) { + if (!hw->is_used_v4l) { + decoder_bmmu_box_free_idx( + hw->bmmu_box, + i); + } + spin_lock_irqsave + (&hw->bufspec_lock, flags); + hw->buffer_spec[i].cma_alloc_addr = 0; + hw->buffer_spec[i].buf_adr = 0; + spin_unlock_irqrestore + (&hw->bufspec_lock, flags); + } + } else { + if (hw->buffer_spec[i].alloc_header_addr) { + decoder_mmu_box_free_idx( + hw->mmu_box, + i); + spin_lock_irqsave + (&hw->bufspec_lock, flags); + hw->buffer_spec[i]. + alloc_header_addr = 0; + hw->buffer_spec[i].buf_adr = 0; + spin_unlock_irqrestore + (&hw->bufspec_lock, flags); + } + } + } + } + if (dealloc_flag && + dpb_is_debug(DECODE_ID(hw), + PRINT_FLAG_DUMP_BUFSPEC)) + dump_bufspec(hw, __func__); + return; +} + +unsigned char have_free_buf_spec(struct vdec_s *vdec) +{ + int i; + unsigned long addr; + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; + struct aml_vcodec_ctx * ctx = hw->v4l2_ctx; + int canvas_pos_min = BUFSPEC_POOL_SIZE; + int index = -1; + int ret = 0; + int allocated_count = 0; + + if (hw->is_used_v4l) { + struct h264_dpb_stru *dpb = &hw->dpb; + int free_count = 0; + int used_count = 0; + + /* trigger to parse head data. */ + if (!hw->v4l_params_parsed) + return 1; + + if (dpb->mDPB.used_size >= dpb->mDPB.size - 1) + return 0; + + if (ctx->cap_pool.dec < hw->dpb.mDPB.size) { + if (ctx->fb_ops.query(&ctx->fb_ops, &hw->fb_token)) { + free_count = + v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) + 1; + } + } + + for (i = 0; i < hw->dpb.mDPB.size; i++) { + if (hw->buffer_spec[i].used == 0 && + hw->buffer_spec[i].vf_ref == 0 && + hw->buffer_spec[i].cma_alloc_addr) { + free_count++; + } else if (hw->buffer_spec[i].cma_alloc_addr) + used_count++; + } + + ATRACE_COUNTER("V_ST_DEC-free_buff_count", free_count); + ATRACE_COUNTER("V_ST_DEC-used_buff_count", used_count); + + return free_count >= run_ready_min_buf_num ? 1 : 0; + } + + for (i = 0; i < BUFSPEC_POOL_SIZE; i++) { + if (hw->mmu_enable) + addr = hw->buffer_spec[i].alloc_header_addr; + else + addr = hw->buffer_spec[i].cma_alloc_addr; + if (hw->buffer_spec[i].used == 0 && + hw->buffer_spec[i].vf_ref == 0) { + + if (addr) + return 1; + if (hw->buffer_spec[i].canvas_pos < canvas_pos_min) { + canvas_pos_min = hw->buffer_spec[i].canvas_pos; + index = i; + } + } + if (addr) + allocated_count++; + } + if (index >= 0) { + mutex_lock(&vmh264_mutex); + dealloc_buf_specs(hw, 0); + if (max_alloc_buf_count == 0 || + allocated_count < max_alloc_buf_count) { + if (alloc_one_buf_spec(hw, index) >= 0) + ret = 1; + } + mutex_unlock(&vmh264_mutex); + } + + return ret; +} + +static int get_buf_spec_by_canvas_pos(struct vdec_h264_hw_s *hw, + int canvas_pos) +{ + int i; + int j = 0; + for (i = 0; i < BUFSPEC_POOL_SIZE; i++) { + if (hw->buffer_spec[i].canvas_pos >= 0) { + if (j == canvas_pos) + return i; + j++; + } + } + return -1; +} +static void update_vf_memhandle(struct vdec_h264_hw_s *hw, + struct vframe_s *vf, int index) +{ + if (index < 0) { + vf->mem_handle = NULL; + vf->mem_head_handle = NULL; + } else if (vf->type & VIDTYPE_SCATTER) { + vf->mem_handle = + decoder_mmu_box_get_mem_handle( + hw->mmu_box, index); + vf->mem_head_handle = + decoder_bmmu_box_get_mem_handle( + hw->bmmu_box, HEADER_BUFFER_IDX(index)); + } else { + vf->mem_handle = + decoder_bmmu_box_get_mem_handle( + hw->bmmu_box, VF_BUFFER_IDX(index)); + /* vf->mem_head_handle = + decoder_bmmu_box_get_mem_handle( + hw->bmmu_box, HEADER_BUFFER_IDX(index));*/ + } + return; +} +static int check_force_interlace(struct vdec_h264_hw_s *hw, + struct FrameStore *frame) +{ + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + int bForceInterlace = 0; + /* no di in secure mode, disable force di */ + if (vdec_secure(hw_to_vdec(hw))) + return 0; + + if (hw->is_used_v4l) + return 0; + + if ((dec_control & DEC_CONTROL_FLAG_FORCE_2997_1080P_INTERLACE) + && hw->bitstream_restriction_flag + && (hw->frame_width == 1920) + && (hw->frame_height >= 1080) /* For being compatible with a fake progressive stream which is interlaced actually*/ + && (hw->frame_dur == 3203 || (hw->frame_dur == 3840 && p_H264_Dpb->mSPS.profile_idc == 100 && + p_H264_Dpb->mSPS.level_idc == 40))) { + bForceInterlace = 1; + } else if ((dec_control & DEC_CONTROL_FLAG_FORCE_2500_576P_INTERLACE) + && (hw->frame_width == 720) + && (hw->frame_height == 576) + && (hw->frame_dur == 3840)) { + bForceInterlace = 1; + } + if (hw->is_used_v4l && (bForceInterlace == 0) && frame->frame) { + bForceInterlace = (frame->frame->mb_aff_frame_flag)?1:0; + } + return bForceInterlace; +} + +static void fill_frame_info(struct vdec_h264_hw_s *hw, struct FrameStore *frame) +{ + struct vframe_qos_s *vframe_qos = &hw->vframe_qos; + + if (frame->slice_type == I_SLICE) + vframe_qos->type = 1; + else if (frame->slice_type == P_SLICE) + vframe_qos->type = 2; + else if (frame->slice_type == B_SLICE) + vframe_qos->type = 3; + + if (input_frame_based(hw_to_vdec(hw))) + vframe_qos->size = frame->frame_size2; + else + vframe_qos->size = frame->frame_size; + vframe_qos->pts = frame->pts64; + + vframe_qos->max_mv = frame->max_mv; + vframe_qos->avg_mv = frame->avg_mv; + vframe_qos->min_mv = frame->min_mv; +/* + pr_info("mv: max:%d, avg:%d, min:%d\n", + vframe_qos->max_mv, + vframe_qos->avg_mv, + vframe_qos->min_mv); +*/ + + vframe_qos->max_qp = frame->max_qp; + vframe_qos->avg_qp = frame->avg_qp; + vframe_qos->min_qp = frame->min_qp; +/* + pr_info("qp: max:%d, avg:%d, min:%d\n", + vframe_qos->max_qp, + vframe_qos->avg_qp, + vframe_qos->min_qp); +*/ + + vframe_qos->max_skip = frame->max_skip; + vframe_qos->avg_skip = frame->avg_skip; + vframe_qos->min_skip = frame->min_skip; +/* + pr_info("skip: max:%d, avg:%d, min:%d\n", + vframe_qos->max_skip, + vframe_qos->avg_skip, + vframe_qos->min_skip); +*/ + vframe_qos->num++; +} + +static int is_iframe(struct FrameStore *frame) { + + if (frame->frame && frame->frame->slice_type == I_SLICE) { + return 1; + } + return 0; +} + +static int post_prepare_process(struct vdec_s *vdec, struct FrameStore *frame) +{ + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; + int buffer_index = frame->buf_spec_num; + + if (buffer_index < 0 || buffer_index >= BUFSPEC_POOL_SIZE) { + dpb_print(DECODE_ID(hw), 0, + "%s, buffer_index 0x%x is beyond range\n", + __func__, buffer_index); + return -1; + } + + if (force_disp_bufspec_num & 0x100) { + /*recycle directly*/ + if (hw->buffer_spec[frame->buf_spec_num].used != 3 && + hw->buffer_spec[frame->buf_spec_num].used != 5) + set_frame_output_flag(&hw->dpb, frame->index); + + /*make pre_output not set*/ + return -1; + } + if (hw->error_proc_policy & 0x1000) { + int error_skip_i_count = (error_skip_count >> 12) & 0xf; + int error_skip_frame_count = error_skip_count & 0xfff; + if (((hw->no_error_count < error_skip_frame_count) + && (error_skip_i_count == 0 || + hw->no_error_i_count < error_skip_i_count)) + && (!(frame->data_flag & I_FLAG))) + frame->data_flag |= ERROR_FLAG; + } + + dpb_print(DECODE_ID(hw), PRINT_FLAG_ERRORFLAG_DBG, + "%s, buffer_index 0x%x frame_error %x poc %d hw error %x hw error_proc_policy %x\n", + __func__, buffer_index, + frame->data_flag & ERROR_FLAG, + frame->poc, hw->data_flag & ERROR_FLAG, + hw->error_proc_policy); + + if (frame->frame == NULL && + ((frame->is_used == 1 && frame->top_field) + || (frame->is_used == 2 && frame->bottom_field))) { + if (hw->i_only) { + if (frame->is_used == 1) + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s No bottom_field !! frame_num %d used %d\n", + __func__, frame->frame_num, frame->is_used); + if (frame->is_used == 2) + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s No top_field !! frame_num %d used %d\n", + __func__, frame->frame_num, frame->is_used); + } + else { + frame->data_flag |= ERROR_FLAG; + dpb_print(DECODE_ID(hw), PRINT_FLAG_ERRORFLAG_DBG, + "%s Error frame_num %d used %d\n", + __func__, frame->frame_num, frame->is_used); + } + } + if (vdec_stream_based(vdec) && !(frame->data_flag & NODISP_FLAG)) { + if ((vdec->vbuf.no_parser == 0) || (vdec->vbuf.use_ptsserv)) { + if ((pts_lookup_offset_us64(PTS_TYPE_VIDEO, + frame->offset_delimiter, &frame->pts, &frame->frame_size, + 0, &frame->pts64) == 0)) { + if ((lookup_check_conut && (atomic_read(&hw->vf_pre_count) > lookup_check_conut) && + (hw->wrong_frame_count > hw->right_frame_count)) && + ((frame->decoded_frame_size * 2 < frame->frame_size))) { + /*resolve many frame only one check in pts, cause playback unsmooth issue*/ + frame->pts64 = hw->last_pts64 +DUR2PTS(hw->frame_dur) ; + frame->pts = hw->last_pts + DUR2PTS(hw->frame_dur); + } + hw->right_frame_count++; + } else { + frame->pts64 = hw->last_pts64 +DUR2PTS(hw->frame_dur) ; + frame->pts = hw->last_pts + DUR2PTS(hw->frame_dur); + hw->wrong_frame_count++; + } + } + + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s error= 0x%x poc = %d offset= 0x%x pts= 0x%x last_pts =0x%x pts64 = %lld last_pts64= %lld duration = %d\n", + __func__, (frame->data_flag & ERROR_FLAG), frame->poc, + frame->offset_delimiter, frame->pts,hw->last_pts, + frame->pts64, hw->last_pts64, hw->frame_dur); + hw->last_pts64 = frame->pts64; + hw->last_pts = frame->pts; + } + + /* SWPL-18973 96000/15=6400, less than 15fps check */ + if ((!hw->duration_from_pts_done) && (hw->frame_dur > 6400ULL)) { + if ((check_force_interlace(hw, frame)) && + (frame->slice_type == I_SLICE) && + (hw->pts_outside)) { + if ((!hw->h264_pts_count) || (!hw->h264pts1)) { + hw->h264pts1 = frame->pts; + hw->h264_pts_count = 0; + } else if (frame->pts > hw->h264pts1) { + u32 calc_dur = + PTS2DUR(frame->pts - hw->h264pts1); + calc_dur = ((calc_dur/hw->h264_pts_count) << 1); + if (hw->frame_dur < (calc_dur + 200) && + hw->frame_dur > (calc_dur - 200)) { + hw->frame_dur >>= 1; + vdec_schedule_work(&hw->notify_work); + dpb_print(DECODE_ID(hw), 0, + "correct frame_dur %d, calc_dur %d, count %d\n", + hw->frame_dur, (calc_dur >> 1), hw->h264_pts_count); + hw->duration_from_pts_done = 1; + hw->h264_pts_count = 0; + } + } + } + hw->h264_pts_count++; + } + + if (frame->data_flag & ERROR_FLAG) { + vdec_count_info(&hw->gvs, 1, 0); + if (frame->slice_type == I_SLICE) { + hw->gvs.i_concealed_frames++; + } else if (frame->slice_type == P_SLICE) { + hw->gvs.p_concealed_frames++; + } else if (frame->slice_type == B_SLICE) { + hw->gvs.b_concealed_frames++; + } + if (!hw->send_error_frame_flag) { + hw->gvs.drop_frame_count++; + if (frame->slice_type == I_SLICE) { + hw->gvs.i_lost_frames++; + } else if (frame->slice_type == P_SLICE) { + hw->gvs.p_lost_frames++; + } else if (frame->slice_type == B_SLICE) { + hw->gvs.b_lost_frames++; + } + } + + } + + if ((!hw->enable_fence) && + ((frame->data_flag & NODISP_FLAG) || + (frame->data_flag & NULL_FLAG) || + ((!hw->send_error_frame_flag) && + (frame->data_flag & ERROR_FLAG)) || + ((hw->i_only & 0x1) && + (!(frame->data_flag & I_FLAG))))) { + frame->show_frame = false; + return 0; + } + + if (dpb_is_debug(DECODE_ID(hw), PRINT_FLAG_DPB_DETAIL)) { + dpb_print(DECODE_ID(hw), 0, + "%s, fs[%d] poc %d, buf_spec_num %d\n", + __func__, frame->index, frame->poc, + frame->buf_spec_num); + print_pic_info(DECODE_ID(hw), "predis_frm", + frame->frame, -1); + print_pic_info(DECODE_ID(hw), "predis_top", + frame->top_field, -1); + print_pic_info(DECODE_ID(hw), "predis_bot", + frame->bottom_field, -1); + } + + frame->show_frame = true; + + return 0; +} + +static int post_video_frame(struct vdec_s *vdec, struct FrameStore *frame) +{ + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; + struct vframe_s *vf = NULL; + int buffer_index = frame->buf_spec_num; + struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx; + struct vdec_v4l2_buffer *fb = NULL; + ulong nv_order = VIDTYPE_VIU_NV21; + int bForceInterlace = 0; + int vf_count = 1; + int i; + + /* swap uv */ + if (hw->is_used_v4l) { + if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12) || + (v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12M)) + nv_order = VIDTYPE_VIU_NV12; + } + + if (!is_interlace(frame)) + vf_count = 1; + else + vf_count = 2; + + bForceInterlace = check_force_interlace(hw, frame); + if (bForceInterlace) + vf_count = 2; + + if (!hw->enable_fence) + hw->buffer_spec[buffer_index].vf_ref = 0; + fill_frame_info(hw, frame); + + if ((hw->is_used_v4l) && + ((vdec->prog_only) || (!v4l2_ctx->vpp_is_need))) + vf_count = 1; + + for (i = 0; i < vf_count; i++) { + if (kfifo_get(&hw->newframe_q, &vf) == 0 || + vf == NULL) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_ERROR, + "%s fatal error, no available buffer slot.\n", + __func__); + return -1; + } + vf->duration_pulldown = 0; + if (!(is_iframe(frame)) && hw->unstable_pts) { + vf->pts = 0; + vf->pts_us64 = 0; + vf->timestamp = 0; + vf->index = VF_INDEX(frame->index, buffer_index); + } else { + if ((i == 0) && (vf_count == 2)) + vf->timestamp = frame->last_field_timestamp; + else + vf->timestamp = frame->timestamp; + vf->pts = frame->pts; + vf->pts_us64 = frame->pts64; + if ((i > 0) && v4l2_ctx->second_field_pts_mode) { + vf->timestamp = 0; + } + vf->index = VF_INDEX(frame->index, buffer_index); + } + + if (hw->is_used_v4l) { + vf->v4l_mem_handle + = hw->buffer_spec[buffer_index].cma_alloc_addr; + fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; + } + + if (hw->enable_fence) { + /* fill fence information. */ + if (hw->fence_usage == FENCE_USE_FOR_DRIVER) + vf->fence = frame->fence; + } + + if (hw->mmu_enable) { + if (hw->double_write_mode & 0x10) { + /* double write only */ + vf->compBodyAddr = 0; + vf->compHeadAddr = 0; + } else { + /*head adr*/ + vf->compHeadAddr = + hw->buffer_spec[buffer_index].alloc_header_addr; + /*body adr*/ + vf->compBodyAddr = 0; + vf->canvas0Addr = vf->canvas1Addr = 0; + } + + vf->type = VIDTYPE_SCATTER; + + if (hw->double_write_mode) { + vf->type |= VIDTYPE_PROGRESSIVE + | VIDTYPE_VIU_FIELD; + vf->type |= nv_order; + if (hw->double_write_mode == 3) + vf->type |= VIDTYPE_COMPRESS; + + vf->canvas0Addr = vf->canvas1Addr = -1; + vf->plane_num = 2; + vf->canvas0_config[0] = + hw->buffer_spec[buffer_index]. + canvas_config[0]; + vf->canvas0_config[1] = + hw->buffer_spec[buffer_index]. + canvas_config[1]; + + vf->canvas1_config[0] = + hw->buffer_spec[buffer_index]. + canvas_config[0]; + vf->canvas1_config[1] = + hw->buffer_spec[buffer_index]. + canvas_config[1]; + + } else { + vf->type |= + VIDTYPE_COMPRESS | VIDTYPE_VIU_FIELD; + vf->canvas0Addr = vf->canvas1Addr = 0; + } + + vf->bitdepth = + BITDEPTH_Y8 | BITDEPTH_U8 | BITDEPTH_V8; + + vf->compWidth = hw->frame_width; + vf->compHeight = hw->frame_height; + } else { + vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD | + nv_order; + + vf->canvas0Addr = vf->canvas1Addr = + spec2canvas(&hw->buffer_spec[buffer_index]); +#ifdef VDEC_DW + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_T7) { + if (IS_VDEC_DW(hw)) + vf->canvas0Addr = vf->canvas1Addr = + vdec_dw_spec2canvas(&hw->buffer_spec[buffer_index]); + } else { + if (IS_VDEC_DW(hw)) + vf->canvas0Addr = vf->canvas1Addr = -1; + } +#endif + + } + if (frame->data_flag & ERROR_FLAG) { + vf->frame_type |= V4L2_BUF_FLAG_ERROR; + } + + set_frame_info(hw, vf, buffer_index); + if (hw->discard_dv_data) { + vf->discard_dv_data = true; + } + + if (hw->mmu_enable && hw->double_write_mode) { + vf->width = hw->frame_width / + get_double_write_ratio(hw->double_write_mode); + vf->height = hw->frame_height / + get_double_write_ratio(hw->double_write_mode); + } + + if (frame->slice_type == I_SLICE) { + vf->frame_type |= V4L2_BUF_FLAG_KEYFRAME; + } else if (frame->slice_type == P_SLICE) { + vf->frame_type |= V4L2_BUF_FLAG_PFRAME; + } else if (frame->slice_type == B_SLICE) { + vf->frame_type |= V4L2_BUF_FLAG_BFRAME; + } + + vf->flag = 0; + if (frame->data_flag & I_FLAG) + vf->flag |= VFRAME_FLAG_SYNCFRAME; + if (frame->data_flag & ERROR_FLAG) + vf->flag |= VFRAME_FLAG_ERROR_RECOVERY; + update_vf_memhandle(hw, vf, buffer_index); + + if (!hw->enable_fence) { + hw->buffer_spec[buffer_index].used = 2; + hw->buffer_spec[buffer_index].vf_ref++; + } + + dpb_print(DECODE_ID(hw), PRINT_FLAG_DPB_DETAIL, + "%s %d frame = %p top_field = %p bottom_field = %p\n", __func__, __LINE__, frame->frame, + frame->top_field, frame->bottom_field); + + if (frame->frame != NULL) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_DPB_DETAIL, + "%s %d coded_frame = %d frame_mbs_only_flag = %d structure = %d\n", __func__, __LINE__, + frame->frame->coded_frame, frame->frame->frame_mbs_only_flag, frame->frame->structure); + } + + if (bForceInterlace || is_interlace(frame)) { + vf->type = + VIDTYPE_INTERLACE_FIRST | + nv_order; + + if (frame->frame != NULL && + (frame->frame->pic_struct == PIC_TOP_BOT || + frame->frame->pic_struct == PIC_BOT_TOP) && + frame->frame->coded_frame) { + if (frame->frame != NULL && frame->frame->pic_struct == PIC_TOP_BOT) { + vf->type |= (i == 0 ? + VIDTYPE_INTERLACE_TOP : + VIDTYPE_INTERLACE_BOTTOM); + } else if (frame->frame != NULL && frame->frame->pic_struct == PIC_BOT_TOP) { + vf->type |= (i == 0 ? + VIDTYPE_INTERLACE_BOTTOM : + VIDTYPE_INTERLACE_TOP); + } + } else if (frame->top_field != NULL && frame->bottom_field != NULL) {/*top first*/ + if (frame->top_field->poc <= frame->bottom_field->poc) + vf->type |= (i == 0 ? + VIDTYPE_INTERLACE_TOP : + VIDTYPE_INTERLACE_BOTTOM); + else + vf->type |= (i == 0 ? + VIDTYPE_INTERLACE_BOTTOM : + VIDTYPE_INTERLACE_TOP); + } else { + vf->type |= (i == 0 ? + VIDTYPE_INTERLACE_TOP : + VIDTYPE_INTERLACE_BOTTOM); + } + vf->duration = vf->duration/2; + if (i == 1) { + vf->pts = 0; + vf->pts_us64 = 0; + } + + if (frame->frame) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_DPB_DETAIL, + "%s %d type = 0x%x pic_struct = %d pts = 0x%x pts_us64 = 0x%llx bForceInterlace = %d\n", + __func__, __LINE__, vf->type, frame->frame->pic_struct, + vf->pts, vf->pts_us64, bForceInterlace); + } + } + + if (hw->i_only) { + if (vf_count == 1 && frame->is_used == 1 && frame->top_field + && frame->bottom_field == NULL && frame->frame == NULL) { + vf->type = + VIDTYPE_INTERLACE_FIRST | + nv_order; + vf->type |= VIDTYPE_INTERLACE_TOP; + vf->duration = vf->duration/2; + } + + if (vf_count == 1 && frame->is_used == 2 && frame->bottom_field + && frame->top_field == NULL && frame->frame == NULL) { + vf->type = + VIDTYPE_INTERLACE_FIRST | + nv_order; + vf->type |= VIDTYPE_INTERLACE_BOTTOM; + vf->duration = vf->duration/2; + } + } + + /*vf->ratio_control |= (0x3FF << DISP_RATIO_ASPECT_RATIO_BIT);*/ + vf->sar_width = hw->width_aspect_ratio; + vf->sar_height = hw->height_aspect_ratio; + if (!vdec->vbuf.use_ptsserv && vdec_stream_based(vdec)) { + /* offset for tsplayer pts lookup */ + if (i == 0) { + vf->pts_us64 = + (((u64)vf->duration << 32) & + 0xffffffff00000000) | frame->offset_delimiter; + vf->pts = 0; + } else { + vf->pts_us64 = (u64)-1; + vf->pts = 0; + } + } + atomic_add(1, &hw->vf_pre_count); + vdec_vframe_ready(hw_to_vdec(hw), vf); + if (!frame->show_frame) { + vh264_vf_put(vf, vdec); + atomic_add(1, &hw->vf_get_count); + continue; + } + + if (i == 0) { + struct vdec_s *pvdec; + struct vdec_info vs; + + pvdec = hw_to_vdec(hw); + memset(&vs, 0, sizeof(struct vdec_info)); + pvdec->dec_status(pvdec, &vs); + decoder_do_frame_check(pvdec, vf); + vdec_fill_vdec_frame(pvdec, &hw->vframe_qos, &vs, vf, frame->hw_decode_time); + + dpb_print(DECODE_ID(hw), PRINT_FLAG_DPB_DETAIL, + "[%s:%d] i_decoded_frame = %d p_decoded_frame = %d b_decoded_frame = %d\n", + __func__, __LINE__,vs.i_decoded_frames,vs.p_decoded_frames,vs.b_decoded_frames); + } + + kfifo_put(&hw->display_q, (const struct vframe_s *)vf); + ATRACE_COUNTER(hw->trace.pts_name, vf->timestamp); + ATRACE_COUNTER(hw->trace.disp_q_name, kfifo_len(&hw->display_q)); + ATRACE_COUNTER(hw->trace.new_q_name, kfifo_len(&hw->newframe_q)); + vdec->vdec_fps_detec(vdec->id); +#ifdef AUX_DATA_CRC + decoder_do_aux_data_check(vdec, hw->buffer_spec[buffer_index].aux_data_buf, + hw->buffer_spec[buffer_index].aux_data_size); +#endif + + dpb_print(DECODE_ID(hw), PRINT_FLAG_SEI_DETAIL, "aux_data_size: %d, signal_type: 0x%x\n", + hw->buffer_spec[buffer_index].aux_data_size, hw->video_signal_type); + + if (dpb_is_debug(DECODE_ID(hw), PRINT_FLAG_SEI_DETAIL)) { + int i = 0; + PR_INIT(128); + + for (i = 0; i < hw->buffer_spec[buffer_index].aux_data_size; i++) { + PR_FILL("%02x ", hw->buffer_spec[buffer_index].aux_data_buf[i]); + if (((i + 1) & 0xf) == 0) + PR_INFO(hw->id); + } + PR_INFO(hw->id); + } + + if (hw->is_used_v4l) { + if ((hw->buffer_spec[buffer_index].aux_data_size == 0) && + (frame->slice_type == I_SLICE) && + (atomic_read(&hw->vf_pre_count) == 1)) { + hw->need_free_aux_data = true; + } + + if (hw->need_free_aux_data) { + v4l2_ctx->aux_infos.free_one_sei_buffer(v4l2_ctx, + &hw->buffer_spec[buffer_index].aux_data_buf, + &hw->buffer_spec[buffer_index].aux_data_size, + hw->buffer_spec[buffer_index].ctx_buf_idx); + } else { + if (!hw->discard_dv_data) + v4l2_ctx->aux_infos.bind_dv_buffer(v4l2_ctx, + &vf->src_fmt.comp_buf, + &vf->src_fmt.md_buf); + update_vframe_src_fmt(vf, + hw->buffer_spec[buffer_index].aux_data_buf, + hw->buffer_spec[buffer_index].aux_data_size, + false, vdec->vf_provider_name, NULL); + } + } + + if (without_display_mode == 0) { + if (hw->is_used_v4l) { + if (v4l2_ctx->is_stream_off) { + vh264_vf_put(vh264_vf_get(vdec), vdec); + } else { + set_meta_data_to_vf(vf, UVM_META_DATA_VF_BASE_INFOS, hw->v4l2_ctx); + ATRACE_COUNTER("VC_OUT_DEC-submit", fb->buf_idx); + fb->task->submit(fb->task, TASK_TYPE_DEC); + } + } else + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + } else + vh264_vf_put(vh264_vf_get(vdec), vdec); + } + if (dpb_is_debug(DECODE_ID(hw), + PRINT_FLAG_DUMP_BUFSPEC)) + dump_bufspec(hw, __func__); + + return 0; +} + +int post_picture_early(struct vdec_s *vdec, int index) +{ + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; + struct h264_dpb_stru *dpb_stru = &hw->dpb; + struct FrameStore fs; + u32 offset_lo, offset_hi; + + if (!hw->enable_fence) + return 0; + + /* create fence for each buffers. */ + if (vdec_timeline_create_fence(vdec->sync)) + return -1; + + memset(&fs, 0, sizeof(fs)); + + fs.buf_spec_num = index; + fs.fence = vdec->sync->fence; + fs.slice_type = dpb_stru->mSlice.slice_type; + fs.dpb_frame_count = dpb_stru->dpb_frame_count; + + offset_lo = dpb_stru->dpb_param.l.data[OFFSET_DELIMITER_LO]; + offset_hi = dpb_stru->dpb_param.l.data[OFFSET_DELIMITER_HI]; + fs.offset_delimiter = (offset_lo | offset_hi << 16); + + if (hw->chunk) { + fs.pts = hw->chunk->pts; + fs.pts64 = hw->chunk->pts64; + fs.timestamp = hw->chunk->timestamp; + } + fs.show_frame = true; + post_video_frame(vdec, &fs); + + display_frame_count[DECODE_ID(hw)]++; + return 0; +} + +int prepare_display_buf(struct vdec_s *vdec, struct FrameStore *frame) +{ + struct vdec_h264_hw_s *hw = + (struct vdec_h264_hw_s *)vdec->private; + + if (hw->enable_fence) { + int i, j, used_size, ret; + int signed_count = 0; + struct vframe_s *signed_fence[VF_POOL_SIZE]; + + post_prepare_process(vdec, frame); + + if (!frame->show_frame) + pr_info("do not display.\n"); + + hw->buffer_spec[frame->buf_spec_num].used = 2; + hw->buffer_spec[frame->buf_spec_num].vf_ref = 1; + hw->buffer_spec[frame->buf_spec_num].fs_idx = frame->index; + + /* notify signal to wake up wq of fence. */ + vdec_timeline_increase(vdec->sync, 1); + + mutex_lock(&hw->fence_mutex); + used_size = hw->fence_vf_s.used_size; + if (used_size) { + for (i = 0, j = 0; i < VF_POOL_SIZE && j < used_size; i++) { + if (hw->fence_vf_s.fence_vf[i] != NULL) { + ret = dma_fence_get_status(hw->fence_vf_s.fence_vf[i]->fence); + if (ret == 1) { + signed_fence[signed_count] = hw->fence_vf_s.fence_vf[i]; + hw->fence_vf_s.fence_vf[i] = NULL; + hw->fence_vf_s.used_size--; + signed_count++; + } + j++; + } + } + } + mutex_unlock(&hw->fence_mutex); + if (signed_count != 0) { + for (i = 0; i < signed_count; i++) + vh264_vf_put(signed_fence[i], vdec); + } + + return 0; + } + + if (post_prepare_process(vdec, frame)) + return -1; + + if (post_video_frame(vdec, frame)) + return -1; + + display_frame_count[DECODE_ID(hw)]++; + return 0; +} + +int notify_v4l_eos(struct vdec_s *vdec) +{ + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; + struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + struct vframe_s *vf = &hw->vframe_dummy; + struct vdec_v4l2_buffer *fb = NULL; + int index = INVALID_IDX; + ulong expires; + + if (hw->eos) { + expires = jiffies + msecs_to_jiffies(2000); + while (!have_free_buf_spec(vdec)) { + if (time_after(jiffies, expires)) { + pr_err("[%d] H264 isn't enough buff for notify eos.\n", ctx->id); + return 0; + } + } + + index = v4l_get_free_buf_idx(vdec); + if (INVALID_IDX == index) { + pr_err("[%d] H264 EOS get free buff fail.\n", ctx->id); + return 0; + } + + fb = (struct vdec_v4l2_buffer *) + hw->buffer_spec[index].cma_alloc_addr; + + vf->type |= VIDTYPE_V4L_EOS; + vf->timestamp = ULONG_MAX; + vf->flag = VFRAME_FLAG_EMPTY_FRAME_V4L; + vf->v4l_mem_handle = (ulong)fb; + + vdec_vframe_ready(vdec, vf); + kfifo_put(&hw->display_q, (const struct vframe_s *)vf); + + ATRACE_COUNTER(hw->trace.pts_name, vf->timestamp); + + ATRACE_COUNTER("VC_OUT_DEC-submit", fb->buf_idx); + fb->task->submit(fb->task, TASK_TYPE_DEC); + + pr_info("[%d] H264 EOS notify.\n", ctx->id); + } + + return 0; +} + +/****************** + * Hardware config + */ +char *slice_type_name[] = { + "P_SLICE ", + "B_SLICE ", + "I_SLICE ", + "SP_SLICE", + "SI_SLICE", +}; + +char *picture_structure_name[] = { + "FRAME", + "TOP_FIELD", + "BOTTOM_FIELD" +}; + +void print_pic_info(int decindex, const char *info, + struct StorablePicture *pic, + int slice_type) +{ + if (pic) + dpb_print(decindex, PRINT_FLAG_DEC_DETAIL, + "%s: %s (original %s), %s, mb_aff_frame_flag %d poc %d, pic_num %d, buf_spec_num %d data_flag 0x%x\n", + info, + picture_structure_name[pic->structure], + pic->coded_frame ? "Frame" : "Field", + (slice_type < 0 || + slice_type >= (sizeof(slice_type_name) / sizeof(slice_type_name[0]))) ? "" : slice_type_name[slice_type], + pic->mb_aff_frame_flag, + pic->poc, + pic->pic_num, + pic->buf_spec_num, + pic->data_flag); +} + +static void reset_process_time(struct vdec_h264_hw_s *hw) +{ + if (hw->start_process_time) { + unsigned process_time = + 1000 * (jiffies - hw->start_process_time) / HZ; + hw->start_process_time = 0; + if (process_time > max_process_time[DECODE_ID(hw)]) + max_process_time[DECODE_ID(hw)] = process_time; + } +} + +static void start_process_time(struct vdec_h264_hw_s *hw) +{ + hw->decode_timeout_count = 10; + hw->start_process_time = jiffies; +} + +static void config_aux_buf(struct vdec_h264_hw_s *hw) +{ + WRITE_VREG(H264_AUX_ADR, hw->aux_phy_addr); + WRITE_VREG(H264_AUX_DATA_SIZE, + ((hw->prefix_aux_size >> 4) << 16) | + (hw->suffix_aux_size >> 4) + ); +} + +/* +* dv_meta_flag: 1, dolby meta only; 2, not include dolby meta +*/ +static void set_aux_data(struct vdec_h264_hw_s *hw, + struct StorablePicture *pic, unsigned char suffix_flag, + unsigned char dv_meta_flag, struct vdec_h264_hw_s *hw_b) +{ + int i; + unsigned short *aux_adr; + unsigned size_reg_val = + READ_VREG(H264_AUX_DATA_SIZE); + unsigned aux_count = 0; + int aux_size = 0; + struct vdec_h264_hw_s *hw_buf = hw_b ? hw_b : hw; + if (pic == NULL || pic->buf_spec_num < 0 || pic->buf_spec_num >= BUFSPEC_POOL_SIZE + || (!is_buf_spec_in_use(hw, pic->buf_spec_num))) + return; + + if (suffix_flag) { + aux_adr = (unsigned short *) + (hw_buf->aux_addr + + hw_buf->prefix_aux_size); + aux_count = + ((size_reg_val & 0xffff) << 4) + >> 1; + aux_size = + hw_buf->suffix_aux_size; + } else { + aux_adr = + (unsigned short *)hw_buf->aux_addr; + aux_count = + ((size_reg_val >> 16) << 4) + >> 1; + aux_size = + hw_buf->prefix_aux_size; + } + if (dpb_is_debug(DECODE_ID(hw), + PRINT_FLAG_SEI_DETAIL)) { + dpb_print(DECODE_ID(hw), 0, + "%s:poc %d old size %d count %d,suf %d dv_flag %d\r\n", + __func__, pic->poc, AUX_DATA_SIZE(pic), + aux_count, suffix_flag, dv_meta_flag); + } + if (aux_size > 0 && aux_count > 0) { + int heads_size = 0; + + for (i = 0; i < aux_count; i++) { + unsigned char tag = aux_adr[i] >> 8; + if (tag != 0 && tag != 0xff) { + if (dv_meta_flag == 0) + heads_size += 8; + else if (dv_meta_flag == 1 && tag == 0x1) + heads_size += 8; + else if (dv_meta_flag == 2 && tag != 0x1) + heads_size += 8; + } + } + + if (AUX_DATA_BUF(pic)) { + unsigned char valid_tag = 0; + unsigned char *h = + AUX_DATA_BUF(pic) + + AUX_DATA_SIZE(pic); + unsigned char *p = h + 8; + int len = 0; + int padding_len = 0; + for (i = 0; i < aux_count; i += 4) { + int ii; + unsigned char tag = aux_adr[i + 3] >> 8; + if (tag != 0 && tag != 0xff) { + if (dv_meta_flag == 0) + valid_tag = 1; + else if (dv_meta_flag == 1 + && tag == 0x1) + valid_tag = 1; + else if (dv_meta_flag == 2 + && tag != 0x1) + valid_tag = 1; + else + valid_tag = 0; + if (valid_tag && len > 0) { + AUX_DATA_SIZE(pic) += + (len + 8); + h[0] = + (len >> 24) & 0xff; + h[1] = + (len >> 16) & 0xff; + h[2] = + (len >> 8) & 0xff; + h[3] = + (len >> 0) & 0xff; + h[6] = + (padding_len >> 8) + & 0xff; + h[7] = + (padding_len) & 0xff; + h += (len + 8); + p += 8; + len = 0; + padding_len = 0; + } + if (valid_tag) { + h[4] = tag; + h[5] = 0; + h[6] = 0; + h[7] = 0; + } + } + if (valid_tag) { + for (ii = 0; ii < 4; ii++) { + unsigned short aa = + aux_adr[i + 3 + - ii]; + *p = aa & 0xff; + p++; + len++; + /*if ((aa >> 8) == 0xff) + padding_len++;*/ + } + } + } + if (len > 0) { + AUX_DATA_SIZE(pic) += (len + 8); + h[0] = (len >> 24) & 0xff; + h[1] = (len >> 16) & 0xff; + h[2] = (len >> 8) & 0xff; + h[3] = (len >> 0) & 0xff; + h[6] = (padding_len >> 8) & 0xff; + h[7] = (padding_len) & 0xff; + } + if (dpb_is_debug(DECODE_ID(hw), + PRINT_FLAG_SEI_DETAIL)) { + dpb_print(DECODE_ID(hw), 0, + "aux: (size %d) suffix_flag %d\n", + AUX_DATA_SIZE(pic), suffix_flag); + for (i = 0; i < AUX_DATA_SIZE(pic); i++) { + dpb_print_cont(DECODE_ID(hw), 0, + "%02x ", AUX_DATA_BUF(pic)[i]); + if (((i + 1) & 0xf) == 0) + dpb_print_cont( + DECODE_ID(hw), + 0, "\n"); + } + dpb_print_cont(DECODE_ID(hw), + 0, "\n"); + } + } + } + +} + +static void release_aux_data(struct vdec_h264_hw_s *hw, + int buf_spec_num) +{ +#if 0 + kfree(hw->buffer_spec[buf_spec_num].aux_data_buf); + hw->buffer_spec[buf_spec_num].aux_data_buf = NULL; + hw->buffer_spec[buf_spec_num].aux_data_size = 0; +#endif +} + +static void dump_aux_buf(struct vdec_h264_hw_s *hw) +{ + int i; + unsigned short *aux_adr = + (unsigned short *) + hw->aux_addr; + unsigned aux_size = + (READ_VREG(H264_AUX_DATA_SIZE) + >> 16) << 4; + + if (hw->prefix_aux_size > 0) { + dpb_print(DECODE_ID(hw), + 0, + "prefix aux: (size %d)\n", + aux_size); + for (i = 0; i < + (aux_size >> 1); i++) { + dpb_print_cont(DECODE_ID(hw), + 0, + "%04x ", + *(aux_adr + i)); + if (((i + 1) & 0xf) + == 0) + dpb_print_cont( + DECODE_ID(hw), + 0, "\n"); + } + } + if (hw->suffix_aux_size > 0) { + aux_adr = (unsigned short *) + (hw->aux_addr + + hw->prefix_aux_size); + aux_size = + (READ_VREG(H264_AUX_DATA_SIZE) & 0xffff) + << 4; + dpb_print(DECODE_ID(hw), + 0, + "suffix aux: (size %d)\n", + aux_size); + for (i = 0; i < + (aux_size >> 1); i++) { + dpb_print_cont(DECODE_ID(hw), + 0, + "%04x ", *(aux_adr + i)); + if (((i + 1) & 0xf) == 0) + dpb_print_cont(DECODE_ID(hw), + 0, "\n"); + } + } +} + +#ifdef VDEC_DW + +struct vdec_dw_param_set{ + char dw_x_shrink_1st; + char dw_x_shrink_2nd; + char dw_x_shrink_3rd; + char dw_y_shrink_1st; + char dw_y_shrink_2nd; + char dw_y_shrink_3rd; + char dw_merge_8to16; + char dw_merge_16to32; + char dw_dma_blk_mode; + char dw_bwsave_mode; +}; +//#define FOR_LPDDR4_EFFICIENCY + +static void h264_vdec_dw_cfg(struct vdec_h264_hw_s *hw, int canvas_pos) +{ + u32 data32 = 0, stride = 0; + struct vdec_dw_param_set *p = NULL; + struct vdec_dw_param_set dw_param_set_pool[] = { + /*x1, x2, x3, y1, y2, y3, m8t6, m16to32 */ + //{0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, /* 1/1, 1/1 */ + {1, 0, 0, 0, 0, 0, 0, 0, 0, 1}, /* 1/2, 1/1 */ + {1, 0, 0, 1, 0, 0, 0, 0, 0, 1}, /* 1/2, 1/2 */ + //{1, 0, 0, 1, 1, 0, 0, 0, 0, 1}, /* 1/4, 1/2 */ + {2, 0, 1, 1, 3, 0, 0, 1, 0, 1}, /* 1/4, 1/4 */ + //{1, 1, 1, 0, 1, 1, 1, 1, 0, 1}, /*> 1080p 1/8, 1/4 */ + {1, 1, 1, 1, 1, 1, 1, 1, 0, 1}, /*> 1080p 1/8, 1/8 */ + }; + + if (IS_VDEC_DW(hw)) + p = &dw_param_set_pool[__ffs(IS_VDEC_DW(hw))]; + else + return; + + WRITE_VREG(MDEC_DOUBLEW_CFG3, + hw->buffer_spec[canvas_pos].vdec_dw_y_addr); // luma start address + WRITE_VREG(MDEC_DOUBLEW_CFG4, + hw->buffer_spec[canvas_pos].vdec_dw_u_addr); // chroma start address + + stride = ALIGN_WIDTH((hw->mb_width << 4) / (IS_VDEC_DW(hw))); + if ((IS_VDEC_DW(hw)) == 1) //width 1/2 + stride >>= 1; + data32 = (stride << 16) | stride; + WRITE_VREG(MDEC_DOUBLEW_CFG5, data32); // chroma stride | luma stride + + data32 = 0; + p->dw_dma_blk_mode = hw->canvas_mode; + data32 |= ((p->dw_x_shrink_1st << 0 ) | // 1st down-scale horizontal, 00:no-scale 01:1/2avg 10:left 11:right + (p->dw_y_shrink_1st << 2 ) | // 1st down-scale vertical, 00:no-scale 01:1/2avg 10:up 11:down + (p->dw_x_shrink_2nd << 4 ) | // 2nd down-scale horizontal, 00:no-scale 01:1/2avg 10:left 11:right + (p->dw_y_shrink_2nd << 6 ) | // 2nd down-scale vertical, 00:no-scale 01:1/2avg 10:up 11:down + (p->dw_x_shrink_3rd << 8 ) | // 3rd down-scale horizontal, 00:no-scale 01:1/2avg 10:left 11:right + (p->dw_y_shrink_3rd << 10) | // 3rd down-scale vertical, 00:no-scale 01:1/2avg 10:up 11:down + (p->dw_merge_8to16 << 12 ) | // 8->16 horizontal block merge for better ddr efficiency + (p->dw_merge_16to32 << 13) | // 16->32 horizontal block merge for better ddr efficiency + (p->dw_dma_blk_mode << 14) | // DMA block mode, 0:linear 1:32x32 2:64x32 +#ifdef FOR_LPDDR4_EFFICIENCY + (1 << 19) | +#endif + (p->dw_bwsave_mode << 22)); // Save line buffers to save band width + WRITE_VREG(MDEC_DOUBLEW_CFG1, data32); // add some special tests here + + data32 = 0; + data32 |= (1 << 0) | (0 << 27); + WRITE_VREG(MDEC_DOUBLEW_CFG0, data32); // Double Write Enable | source from dblk + + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "vdec_double_write mode %d\n", + IS_VDEC_DW(hw)); + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "param {%d, %d, %d, %d, %d, %d, %d, %d, %d}\n", + p->dw_x_shrink_1st, + p->dw_y_shrink_1st, + p->dw_x_shrink_2nd, + p->dw_y_shrink_2nd, + p->dw_x_shrink_3rd, + p->dw_y_shrink_3rd, + p->dw_merge_8to16, + p->dw_merge_16to32, + p->dw_dma_blk_mode); + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "cfg0,1,3,4,5 = {%x, %x, %x, %x, %x}\n", + READ_VREG(MDEC_DOUBLEW_CFG0), + READ_VREG(MDEC_DOUBLEW_CFG1), + READ_VREG(MDEC_DOUBLEW_CFG3), + READ_VREG(MDEC_DOUBLEW_CFG4), + READ_VREG(MDEC_DOUBLEW_CFG5)); +} +#endif + +static void config_decode_mode(struct vdec_h264_hw_s *hw) +{ +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + struct vdec_s *vdec = hw_to_vdec(hw); +#endif + if (input_frame_based(hw_to_vdec(hw))) + WRITE_VREG(H264_DECODE_MODE, + DECODE_MODE_MULTI_FRAMEBASE); +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + else if (vdec->slave) + WRITE_VREG(H264_DECODE_MODE, + (hw->got_valid_nal << 8) | + DECODE_MODE_MULTI_DVBAL); + else if (vdec->master) + WRITE_VREG(H264_DECODE_MODE, + (hw->got_valid_nal << 8) | + DECODE_MODE_MULTI_DVENL); +#endif + else + WRITE_VREG(H264_DECODE_MODE, + DECODE_MODE_MULTI_STREAMBASE); + WRITE_VREG(H264_DECODE_SEQINFO, 0); + WRITE_VREG(HEAD_PADING_REG, 0); + + if (hw->init_flag == 0) + WRITE_VREG(INIT_FLAG_REG, 0); + else + WRITE_VREG(INIT_FLAG_REG, 1); +} + +int config_decode_buf(struct vdec_h264_hw_s *hw, struct StorablePicture *pic) +{ + /* static int count = 0; */ + int ret = 0; + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + struct Slice *pSlice = &(p_H264_Dpb->mSlice); + unsigned int colocate_adr_offset; + unsigned int val; + struct StorablePicture *last_pic = hw->last_dec_picture; + +#ifdef ONE_COLOCATE_BUF_PER_DECODE_BUF + int colocate_buf_index; +#endif +#define H264_BUFFER_INFO_INDEX PMV3_X /* 0xc24 */ +#define H264_BUFFER_INFO_DATA PMV2_X /* 0xc22 */ +#define H264_CURRENT_POC_IDX_RESET LAST_SLICE_MV_ADDR /* 0xc30 */ +#define H264_CURRENT_POC LAST_MVY /* 0xc32 shared with conceal MV */ + +#define H264_CO_MB_WR_ADDR VLD_C38 /* 0xc38 */ +/* bit 31:30 -- L1[0] picture coding structure, + * 00 - top field, 01 - bottom field, + * 10 - frame, 11 - mbaff frame + * bit 29 - L1[0] top/bot for B field pciture , 0 - top, 1 - bot + * bit 28:0 h264_co_mb_mem_rd_addr[31:3] + * -- only used for B Picture Direct mode [2:0] will set to 3'b000 + */ +#define H264_CO_MB_RD_ADDR VLD_C39 /* 0xc39 */ + +/* bit 15 -- flush co_mb_data to DDR -- W-Only + * bit 14 -- h264_co_mb_mem_wr_addr write Enable -- W-Only + * bit 13 -- h264_co_mb_info_wr_ptr write Enable -- W-Only + * bit 9 -- soft_reset -- W-Only + * bit 8 -- upgent + * bit 7:2 -- h264_co_mb_mem_wr_addr + * bit 1:0 -- h264_co_mb_info_wr_ptr + */ +#define H264_CO_MB_RW_CTL VLD_C3D /* 0xc3d */ +#define DCAC_DDR_BYTE64_CTL 0x0e1d + unsigned long canvas_adr; + unsigned int ref_reg_val; + unsigned int one_ref_cfg = 0; + int h264_buffer_info_data_write_count; + int i, j; + unsigned int colocate_wr_adr; + unsigned int colocate_rd_adr; + unsigned char use_direct_8x8; + int canvas_pos; + canvas_pos = hw->buffer_spec[pic->buf_spec_num].canvas_pos; + WRITE_VREG(H264_CURRENT_POC_IDX_RESET, 0); + WRITE_VREG(H264_CURRENT_POC, pic->frame_poc); + WRITE_VREG(H264_CURRENT_POC, pic->top_poc); + WRITE_VREG(H264_CURRENT_POC, pic->bottom_poc); + + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "%s: pic_num is %d, poc is %d (%d, %d, %d), buf_spec_num %d canvas_pos %d\n", + __func__, pic->pic_num, pic->poc, pic->frame_poc, + pic->top_poc, pic->bottom_poc, pic->buf_spec_num, + canvas_pos); + print_pic_info(DECODE_ID(hw), "cur", pic, pSlice->slice_type); + +#ifdef VDEC_DW + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_T7) { + if (IS_VDEC_DW(hw) && pic->mb_aff_frame_flag) + WRITE_VREG(MDEC_DOUBLEW_CFG0, + (READ_VREG(MDEC_DOUBLEW_CFG0) & (~(1 << 30)))); + } +#endif + WRITE_VREG(CURR_CANVAS_CTRL, canvas_pos << 24); + canvas_adr = READ_VREG(CURR_CANVAS_CTRL) & 0xffffff; + + if (!hw->mmu_enable) { + WRITE_VREG(REC_CANVAS_ADDR, canvas_adr); + WRITE_VREG(DBKR_CANVAS_ADDR, canvas_adr); + WRITE_VREG(DBKW_CANVAS_ADDR, canvas_adr); +#ifdef VDEC_DW + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_T7) { + WRITE_VREG(MDEC_DOUBLEW_CFG1, + (hw->buffer_spec[canvas_pos].vdec_dw_y_canvas_index | + (hw->buffer_spec[canvas_pos].vdec_dw_u_canvas_index << 8))); + } else { + h264_vdec_dw_cfg(hw, canvas_pos); + } +#endif + } else + hevc_sao_set_pic_buffer(hw, pic); + + if (pic->mb_aff_frame_flag) + hw->buffer_spec[pic->buf_spec_num].info0 = 0xf4c0; + else if (pic->structure == TOP_FIELD) + hw->buffer_spec[pic->buf_spec_num].info0 = 0xf400; + else if (pic->structure == BOTTOM_FIELD) + hw->buffer_spec[pic->buf_spec_num].info0 = 0xf440; + else + hw->buffer_spec[pic->buf_spec_num].info0 = 0xf480; + + if (pic->bottom_poc < pic->top_poc) + hw->buffer_spec[pic->buf_spec_num].info0 |= 0x100; + + hw->buffer_spec[pic->buf_spec_num].info1 = pic->top_poc; + hw->buffer_spec[pic->buf_spec_num].info2 = pic->bottom_poc; + WRITE_VREG(H264_BUFFER_INFO_INDEX, 16); + + for (j = 0; j < hw->dpb.mDPB.size; j++) { + int long_term_flag; + i = get_buf_spec_by_canvas_pos(hw, j); + if (i < 0) + break; + long_term_flag = + get_long_term_flag_by_buf_spec_num(p_H264_Dpb, i); + if (long_term_flag > 0) { + if (long_term_flag & 0x1) + hw->buffer_spec[i].info0 |= (1 << 4); + else + hw->buffer_spec[i].info0 &= ~(1 << 4); + + if (long_term_flag & 0x2) + hw->buffer_spec[i].info0 |= (1 << 5); + else + hw->buffer_spec[i].info0 &= ~(1 << 5); + } + + if (i == pic->buf_spec_num) + WRITE_VREG(H264_BUFFER_INFO_DATA, + hw->buffer_spec[i].info0 | 0xf); + else + WRITE_VREG(H264_BUFFER_INFO_DATA, + hw->buffer_spec[i].info0); + WRITE_VREG(H264_BUFFER_INFO_DATA, hw->buffer_spec[i].info1); + WRITE_VREG(H264_BUFFER_INFO_DATA, hw->buffer_spec[i].info2); + } + + /* config reference buffer */ + if (hw->mmu_enable) { + hevc_mcr_config_mc_ref(hw); + hevc_mcr_config_mcrcc(hw); + } + + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "list0 size %d\n", pSlice->listXsize[0]); + WRITE_VREG(H264_BUFFER_INFO_INDEX, 0); + ref_reg_val = 0; + j = 0; + h264_buffer_info_data_write_count = 0; + + //disable this read cache when frame width <= 64 (4MBs) + //IQIDCT_CONTROL, bit[16] dcac_dma_read_cache_disable + if (hw->frame_width <= 64) { + SET_VREG_MASK(IQIDCT_CONTROL,(1 << 16)); + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)) + // Disable DDR_BYTE64_CACHE + WRITE_VREG(DCAC_DDR_BYTE64_CTL, + (READ_VREG(DCAC_DDR_BYTE64_CTL) & (~0xf)) | 0xa); + } + else + CLEAR_VREG_MASK(IQIDCT_CONTROL,(1 << 16)); + + if (last_pic) + dpb_print(DECODE_ID(hw), PRINT_FLAG_ERRORFLAG_DBG, + "last_pic->data_flag %x slice_type %x last_pic->slice_type %x\n", + last_pic->data_flag, pSlice->slice_type, last_pic->slice_type); + if (!hw->i_only && !(hw->error_proc_policy & 0x2000) && + last_pic && (last_pic->data_flag & ERROR_FLAG) + && (!(last_pic->slice_type == B_SLICE)) + && (!(pSlice->slice_type == I_SLICE))) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_ERRORFLAG_DBG, + "no i/idr error mark\n"); + hw->data_flag |= ERROR_FLAG; + pic->data_flag |= ERROR_FLAG; + } + + for (i = 0; i < (unsigned int)(pSlice->listXsize[0]); i++) { + /*ref list 0 */ + struct StorablePicture *ref = pSlice->listX[0][i]; + unsigned int cfg; + /* bit[6:5] - frame/field info, + * 01 - top, 10 - bottom, 11 - frame + */ + #ifdef ERROR_CHECK + if (ref == NULL) { + hw->data_flag |= ERROR_FLAG; + pic->data_flag |= ERROR_FLAG; + dpb_print(DECODE_ID(hw), PRINT_FLAG_ERRORFLAG_DBG, " ref list0 NULL\n"); + return -1; + } + if ((ref->data_flag & ERROR_FLAG) && ref_frame_mark_flag[DECODE_ID(hw)]) { + hw->data_flag |= ERROR_FLAG; + pic->data_flag |= ERROR_FLAG; + dpb_print(DECODE_ID(hw), PRINT_FLAG_ERRORFLAG_DBG, " ref error mark1 \n"); + } + + if (hw->error_proc_policy & 0x80000) { + if (ref_b_frame_error_max_count && + ref->slice_type == B_SLICE) { + if (ref->data_flag & ERROR_FLAG) + hw->b_frame_error_count++; + else + hw->b_frame_error_count = 0; + if (hw->b_frame_error_count > ref_b_frame_error_max_count) { + hw->b_frame_error_count = 0; + dpb_print(DECODE_ID(hw), 0, + "error %d B frame, reset dpb buffer\n", + ref_b_frame_error_max_count); + return -1; + } + } + } + + if (ref->data_flag & NULL_FLAG) + hw->data_flag |= NULL_FLAG; +#endif + canvas_pos = hw->buffer_spec[ref->buf_spec_num].canvas_pos; + + if (ref->structure == TOP_FIELD) + cfg = 0x1; + else if (ref->structure == BOTTOM_FIELD) + cfg = 0x2; + else /* FRAME */ + cfg = 0x3; + + one_ref_cfg = (canvas_pos & 0x1f) | (cfg << 5); + ref_reg_val <<= 8; + ref_reg_val |= one_ref_cfg; + j++; + + if (j == 4) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "H264_BUFFER_INFO_DATA: %x\n", ref_reg_val); + WRITE_VREG(H264_BUFFER_INFO_DATA, ref_reg_val); + h264_buffer_info_data_write_count++; + j = 0; + } + print_pic_info(DECODE_ID(hw), "list0", + pSlice->listX[0][i], -1); + } + if (j != 0) { + while (j != 4) { + ref_reg_val <<= 8; + ref_reg_val |= one_ref_cfg; + j++; + } + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "H264_BUFFER_INFO_DATA: %x\n", + ref_reg_val); + WRITE_VREG(H264_BUFFER_INFO_DATA, ref_reg_val); + h264_buffer_info_data_write_count++; + } + ref_reg_val = (one_ref_cfg << 24) | (one_ref_cfg<<16) | + (one_ref_cfg << 8) | one_ref_cfg; + for (i = h264_buffer_info_data_write_count; i < 8; i++) + WRITE_VREG(H264_BUFFER_INFO_DATA, ref_reg_val); + + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "list1 size %d\n", pSlice->listXsize[1]); + WRITE_VREG(H264_BUFFER_INFO_INDEX, 8); + ref_reg_val = 0; + j = 0; + + for (i = 0; i < (unsigned int)(pSlice->listXsize[1]); i++) { + /* ref list 0 */ + struct StorablePicture *ref = pSlice->listX[1][i]; + unsigned int cfg; + /* bit[6:5] - frame/field info, + * 01 - top, 10 - bottom, 11 - frame + */ + + #ifdef ERROR_CHECK + if (ref == NULL) { + hw->data_flag |= ERROR_FLAG; + pic->data_flag |= ERROR_FLAG; + dpb_print(DECODE_ID(hw), PRINT_FLAG_ERRORFLAG_DBG, " ref error list1 NULL\n"); + return -2; + } + if ((ref->data_flag & ERROR_FLAG) && (ref_frame_mark_flag[DECODE_ID(hw)])) { + pic->data_flag |= ERROR_FLAG; + hw->data_flag |= ERROR_FLAG; + dpb_print(DECODE_ID(hw), PRINT_FLAG_ERRORFLAG_DBG, " ref error mark2\n"); + } + if (ref->data_flag & NULL_FLAG) + hw->data_flag |= NULL_FLAG; +#endif + canvas_pos = hw->buffer_spec[ref->buf_spec_num].canvas_pos; + if (ref->structure == TOP_FIELD) + cfg = 0x1; + else if (ref->structure == BOTTOM_FIELD) + cfg = 0x2; + else /* FRAME */ + cfg = 0x3; + one_ref_cfg = (canvas_pos & 0x1f) | (cfg << 5); + ref_reg_val <<= 8; + ref_reg_val |= one_ref_cfg; + j++; + + if (j == 4) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "H264_BUFFER_INFO_DATA: %x\n", + ref_reg_val); + WRITE_VREG(H264_BUFFER_INFO_DATA, ref_reg_val); + j = 0; + } + print_pic_info(DECODE_ID(hw), "list1", + pSlice->listX[1][i], -1); + } + if (j != 0) { + while (j != 4) { + ref_reg_val <<= 8; + ref_reg_val |= one_ref_cfg; + j++; + } + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "H264_BUFFER_INFO_DATA: %x\n", ref_reg_val); + WRITE_VREG(H264_BUFFER_INFO_DATA, ref_reg_val); + } + + /* configure co-locate buffer */ + while ((READ_VREG(H264_CO_MB_RW_CTL) >> 11) & 0x1) + ; + if ((pSlice->mode_8x8_flags & 0x4) && + (pSlice->mode_8x8_flags & 0x2)) + use_direct_8x8 = 1; + else + use_direct_8x8 = 0; + +#ifndef ONE_COLOCATE_BUF_PER_DECODE_BUF + colocate_adr_offset = + ((pic->structure == FRAME && pic->mb_aff_frame_flag == 0) + ? 1 : 2) * 96; + if (use_direct_8x8) + colocate_adr_offset >>= 2; + + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "colocate buf size of each mb 0x%x first_mb_in_slice 0x%x colocate_adr_offset 0x%x\r\n", + colocate_adr_offset, pSlice->first_mb_in_slice, + colocate_adr_offset * pSlice->first_mb_in_slice); + + colocate_adr_offset *= pSlice->first_mb_in_slice; + + if ((pic->colocated_buf_index >= 0) && + (pic->colocated_buf_index < p_H264_Dpb->colocated_buf_count)) { + colocate_wr_adr = p_H264_Dpb->colocated_mv_addr_start + + ((p_H264_Dpb->colocated_buf_size * + pic->colocated_buf_index) + >> (use_direct_8x8 ? 2 : 0)); + if ((colocate_wr_adr + p_H264_Dpb->colocated_buf_size) > + p_H264_Dpb->colocated_mv_addr_end) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_ERROR, + "Error, colocate buf is not enough, index is %d\n", + pic->colocated_buf_index); + ret = -3; + } + val = colocate_wr_adr + colocate_adr_offset; + WRITE_VREG(H264_CO_MB_WR_ADDR, val); + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "WRITE_VREG(H264_CO_MB_WR_ADDR) = %x, first_mb_in_slice %x pic_structure %x colocate_adr_offset %x mode_8x8_flags %x colocated_buf_size %x\n", + val, pSlice->first_mb_in_slice, pic->structure, + colocate_adr_offset, pSlice->mode_8x8_flags, + p_H264_Dpb->colocated_buf_size); + } else { + WRITE_VREG(H264_CO_MB_WR_ADDR, 0xffffffff); + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "WRITE_VREG(H264_CO_MB_WR_ADDR) = 0xffffffff\n"); + } +#else + colocate_buf_index = hw->buffer_spec[pic->buf_spec_num].canvas_pos; + colocate_adr_offset = + ((pic->structure == FRAME && pic->mb_aff_frame_flag == 0) ? 1 : 2) * 96; + if (use_direct_8x8) + colocate_adr_offset >>= 2; + + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "colocate buf size of each mb 0x%x first_mb_in_slice 0x%x colocate_adr_offset 0x%x\r\n", + colocate_adr_offset, pSlice->first_mb_in_slice, + colocate_adr_offset * pSlice->first_mb_in_slice); + + colocate_adr_offset *= pSlice->first_mb_in_slice; + + colocate_wr_adr = p_H264_Dpb->colocated_mv_addr_start + + ((p_H264_Dpb->colocated_buf_size * colocate_buf_index) >> + (use_direct_8x8 ? 2 : 0)); + + if ((colocate_wr_adr + p_H264_Dpb->colocated_buf_size) > + p_H264_Dpb->colocated_mv_addr_end) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_ERROR, + "Error, colocate buf is not enough, col buf index is %d\n", + colocate_buf_index); + ret = -4; + } + val = colocate_wr_adr + colocate_adr_offset; + WRITE_VREG(H264_CO_MB_WR_ADDR, val); + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "WRITE_VREG(H264_CO_MB_WR_ADDR) = %x, first_mb_in_slice %x pic_structure %x colocate_adr_offset %x mode_8x8_flags %x colocated_buf_size %x\n", + val, pSlice->first_mb_in_slice, pic->structure, + colocate_adr_offset, pSlice->mode_8x8_flags, + p_H264_Dpb->colocated_buf_size); +#endif + if (pSlice->listXsize[1] > 0) { + struct StorablePicture *colocate_pic = pSlice->listX[1][0]; + /* H264_CO_MB_RD_ADDR[bit 31:30], + * original picture structure of L1[0], + * 00 - top field, 01 - bottom field, + * 10 - frame, 11 - mbaff frame + */ + int l10_structure, cur_structure; + int cur_colocate_ref_type; + /* H264_CO_MB_RD_ADDR[bit 29], top/bot for B field pciture, + * 0 - top, 1 - bot + */ + unsigned int val; + unsigned int colocate_rd_adr_offset; + unsigned int mby_mbx; + unsigned int mby, mbx; +#ifdef ERROR_CHECK + if (colocate_pic == NULL) { + hw->data_flag |= ERROR_FLAG; + pic->data_flag |= ERROR_FLAG; + dpb_print(DECODE_ID(hw), PRINT_FLAG_ERRORFLAG_DBG, " colocate error pic NULL\n"); + return -5; + } + if (colocate_pic->data_flag & ERROR_FLAG) { + pic->data_flag |= ERROR_FLAG; + hw->data_flag |= ERROR_FLAG; + dpb_print(DECODE_ID(hw), PRINT_FLAG_ERRORFLAG_DBG, " colocare ref error mark\n"); + } + if (colocate_pic->data_flag & NULL_FLAG) + hw->data_flag |= NULL_FLAG; +#endif + + if (colocate_pic->mb_aff_frame_flag) + l10_structure = 3; + else { + if (colocate_pic->coded_frame) + l10_structure = 2; + else + l10_structure = (colocate_pic->structure == + BOTTOM_FIELD) ? 1 : 0; + } + + //ALLEGRO_FIX, ported from single mode ucode + mby_mbx = READ_VREG(MBY_MBX); + mby = pSlice->first_mb_in_slice / hw->mb_width; + mbx = pSlice->first_mb_in_slice % hw->mb_width; + if (pic->mb_aff_frame_flag) + cur_structure = 3; + else { + if (pic->coded_frame) + cur_structure = 2; + else + cur_structure = (pic->structure == + BOTTOM_FIELD) ? 1 : 0; + } + if (cur_structure < 2) { + //current_field_structure + if (l10_structure != 2) { + colocate_rd_adr_offset = pSlice->first_mb_in_slice * 2; + } else { + // field_ref_from_frame co_mv_rd_addr : + // mby*2*mb_width + mbx + colocate_rd_adr_offset = mby * 2 * hw->mb_width + mbx; + } + + } else { + //current_frame_structure + if (l10_structure < 2) { + //calculate_co_mv_offset_frame_ref_field: + // frame_ref_from_field co_mv_rd_addr : + // (mby/2*mb_width+mbx)*2 + colocate_rd_adr_offset = ((mby / 2) * hw->mb_width + mbx) * 2; + } else if (cur_structure == 2) { + colocate_rd_adr_offset = pSlice->first_mb_in_slice; + } else { + //mbaff frame case1196 + colocate_rd_adr_offset = pSlice->first_mb_in_slice * 2; + } + + } + + colocate_rd_adr_offset *= 96; + if (use_direct_8x8) + colocate_rd_adr_offset >>= 2; + + if (colocate_old_cal) + colocate_rd_adr_offset = colocate_adr_offset; + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "first_mb_in_slice 0x%x 0x%x 0x%x (MBY_MBX reg 0x%x) use_direct_8x8 %d cur %d (mb_aff_frame_flag %d, coded_frame %d structure %d) col %d (mb_aff_frame_flag %d, coded_frame %d structure %d) offset 0x%x rdoffset 0x%x\n", + pSlice->first_mb_in_slice, mby, mbx, mby_mbx, use_direct_8x8, + cur_structure, pic->mb_aff_frame_flag, pic->coded_frame, pic->structure, + l10_structure, colocate_pic->mb_aff_frame_flag, colocate_pic->coded_frame, colocate_pic->structure, + colocate_adr_offset, + colocate_rd_adr_offset); + +#if 0 + /*case0016, p16, + *cur_colocate_ref_type should be configured base on current pic + */ + if (pic->structure == FRAME && + pic->mb_aff_frame_flag) + cur_colocate_ref_type = 0; + else if (pic->structure == BOTTOM_FIELD) + cur_colocate_ref_type = 1; + else + cur_colocate_ref_type = 0; +#else + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + " CUR TMP DEBUG : mb_aff_frame_flag : %d, structure : %d coded_frame %d\n", + pic->mb_aff_frame_flag, + pic->structure, + pic->coded_frame); + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + " COL TMP DEBUG : mb_aff_frame_flag : %d, structure : %d coded_frame %d\n", + colocate_pic->mb_aff_frame_flag, + colocate_pic->structure, + colocate_pic->coded_frame); + if (pic->structure == FRAME || pic->mb_aff_frame_flag) { + cur_colocate_ref_type = + (abs(pic->poc - colocate_pic->top_poc) + < abs(pic->poc - + colocate_pic->bottom_poc)) ? 0 : 1; + } else + cur_colocate_ref_type = + (colocate_pic->structure + == BOTTOM_FIELD) ? 1 : 0; +#endif + +#ifndef ONE_COLOCATE_BUF_PER_DECODE_BUF + if ((colocate_pic->colocated_buf_index >= 0) && + (colocate_pic->colocated_buf_index < + p_H264_Dpb->colocated_buf_count)) { + colocate_rd_adr = p_H264_Dpb->colocated_mv_addr_start + + ((p_H264_Dpb->colocated_buf_size * + colocate_pic->colocated_buf_index) + >> (use_direct_8x8 ? 2 : 0)); + if ((colocate_rd_adr + p_H264_Dpb->colocated_buf_size) > + p_H264_Dpb->colocated_mv_addr_end) { + dpb_print(DECODE_ID(hw), + PRINT_FLAG_ERROR, + "Error, colocate buf is not enough, index is %d\n", + colocate_pic->colocated_buf_index); + ret = -6; + } + /* bit 31:30 -- L1[0] picture coding structure, + * 00 - top field, 01 - bottom field, + * 10 - frame, 11 - mbaff frame + * bit 29 - L1[0] top/bot for B field pciture, + * 0 - top, 1 - bot + * bit 28:0 h264_co_mb_mem_rd_addr[31:3] + * -- only used for B Picture Direct mode + * [2:0] will set to 3'b000 + */ + /* #define H264_CO_MB_RD_ADDR VLD_C39 0xc39 */ + val = ((colocate_rd_adr+colocate_rd_adr_offset) >> 3) | + (l10_structure << 30) | + (cur_colocate_ref_type << 29); + WRITE_VREG(H264_CO_MB_RD_ADDR, val); + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "co idx %d, WRITE_VREG(H264_CO_MB_RD_ADDR) = %x, addr %x L1(0) pic_structure %d mbaff %d\n", + colocate_pic->colocated_buf_index, + val, colocate_rd_adr + colocate_rd_adr_offset, + colocate_pic->structure, + colocate_pic->mb_aff_frame_flag); + } else { + dpb_print(DECODE_ID(hw), PRINT_FLAG_ERROR, + "Error, reference pic has no colocated buf\n"); + ret = -7; + } +#else + colocate_buf_index = + hw->buffer_spec[colocate_pic->buf_spec_num].canvas_pos; + colocate_rd_adr = p_H264_Dpb->colocated_mv_addr_start + + ((p_H264_Dpb->colocated_buf_size * + colocate_buf_index) + >> (use_direct_8x8 ? 2 : 0)); + if ((colocate_rd_adr + p_H264_Dpb->colocated_buf_size) > + p_H264_Dpb->colocated_mv_addr_end) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_ERROR, + "Error, colocate buf is not enough, col buf index is %d\n", + colocate_buf_index); + ret = -8; + } + /* bit 31:30 -- L1[0] picture coding structure, + * 00 - top field, 01 - bottom field, + * 10 - frame, 11 - mbaff frame + * bit 29 - L1[0] top/bot for B field pciture, + * 0 - top, 1 - bot + * bit 28:0 h264_co_mb_mem_rd_addr[31:3] + * -- only used for B Picture Direct mode + * [2:0] will set to 3'b000 + */ + /* #define H264_CO_MB_RD_ADDR VLD_C39 0xc39 */ + val = ((colocate_rd_adr+colocate_rd_adr_offset)>>3) | + (l10_structure << 30) | (cur_colocate_ref_type << 29); + WRITE_VREG(H264_CO_MB_RD_ADDR, val); + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "WRITE_VREG(H264_CO_MB_RD_ADDR) = %x, L1(0) pic_structure %d mbaff %d\n", + val, colocate_pic->structure, + colocate_pic->mb_aff_frame_flag); +#endif + } + return ret; +} + +static int vh264_vf_states(struct vframe_states *states, void *op_arg) +{ + unsigned long flags; + struct vdec_s *vdec = op_arg; + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; + + spin_lock_irqsave(&hw->lock, flags); + + states->vf_pool_size = VF_POOL_SIZE; + states->buf_free_num = kfifo_len(&hw->newframe_q); + states->buf_avail_num = kfifo_len(&hw->display_q); + + spin_unlock_irqrestore(&hw->lock, flags); + + return 0; +} + +static struct vframe_s *vh264_vf_peek(void *op_arg) +{ + struct vframe_s *vf[2] = {0, 0}; + struct vdec_s *vdec = op_arg; + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; + + if (!hw) + return NULL; + + if (force_disp_bufspec_num & 0x100) { + if (force_disp_bufspec_num & 0x200) + return NULL; + return &hw->vframe_dummy; + } + + if (kfifo_out_peek(&hw->display_q, (void *)&vf, 2)) { + if (vf[1]) { + vf[0]->next_vf_pts_valid = true; + vf[0]->next_vf_pts = vf[1]->pts; + } else + vf[0]->next_vf_pts_valid = false; + return vf[0]; + } + + return NULL; +} + +static struct vframe_s *vh264_vf_get(void *op_arg) +{ + struct vframe_s *vf; + struct vdec_s *vdec = op_arg; + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; + struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx; + ulong nv_order = VIDTYPE_VIU_NV21; + + if (!hw) + return NULL; + + /* swap uv */ + if (hw->is_used_v4l) { + if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12) || + (v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12M)) + nv_order = VIDTYPE_VIU_NV12; + } + + if (force_disp_bufspec_num & 0x100) { + int buffer_index = force_disp_bufspec_num & 0xff; + if (force_disp_bufspec_num & 0x200) + return NULL; + + vf = &hw->vframe_dummy; + vf->duration_pulldown = 0; + vf->pts = 0; + vf->pts_us64 = 0; + set_frame_info(hw, vf, buffer_index); + vf->flag = 0; + if (hw->mmu_enable) { + if (hw->double_write_mode & 0x10) { + /* double write only */ + vf->compBodyAddr = 0; + vf->compHeadAddr = 0; + } else { + /*head adr*/ + vf->compHeadAddr = + hw->buffer_spec[buffer_index].alloc_header_addr; + /*body adr*/ + vf->compBodyAddr = 0; + vf->canvas0Addr = vf->canvas1Addr = 0; + } + + vf->type = VIDTYPE_SCATTER; + + if (hw->double_write_mode) { + vf->type |= VIDTYPE_PROGRESSIVE + | VIDTYPE_VIU_FIELD; + vf->type |= nv_order; + if (hw->double_write_mode == 3) + vf->type |= VIDTYPE_COMPRESS; + + vf->canvas0Addr = vf->canvas1Addr = -1; + vf->plane_num = 2; + vf->canvas0_config[0] = + hw->buffer_spec[buffer_index]. + canvas_config[0]; + vf->canvas0_config[1] = + hw->buffer_spec[buffer_index]. + canvas_config[1]; + + vf->canvas1_config[0] = + hw->buffer_spec[buffer_index]. + canvas_config[0]; + vf->canvas1_config[1] = + hw->buffer_spec[buffer_index]. + canvas_config[1]; + } else { + vf->type |= + VIDTYPE_COMPRESS | VIDTYPE_VIU_FIELD; + vf->canvas0Addr = vf->canvas1Addr = 0; + } + vf->bitdepth = + BITDEPTH_Y8 | BITDEPTH_U8 | BITDEPTH_V8; + + vf->compWidth = hw->frame_width; + vf->compHeight = hw->frame_height; + + if (hw->double_write_mode) { + vf->width = hw->frame_width / + get_double_write_ratio(hw->double_write_mode); + vf->height = hw->frame_height / + get_double_write_ratio(hw->double_write_mode); + } + } else { + vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD | + nv_order; + vf->canvas0Addr = vf->canvas1Addr = + spec2canvas(&hw->buffer_spec[buffer_index]); + } + + /*vf->mem_handle = decoder_bmmu_box_get_mem_handle( + hw->bmmu_box, buffer_index);*/ + update_vf_memhandle(hw, vf, buffer_index); + force_disp_bufspec_num |= 0x200; + return vf; + } + + if (kfifo_get(&hw->display_q, &vf)) { + int time = jiffies; + unsigned int frame_interval = + 1000*(time - hw->last_frame_time)/HZ; + struct vframe_s *next_vf = NULL; + ATRACE_COUNTER(hw->trace.disp_q_name, kfifo_len(&hw->display_q)); + if (dpb_is_debug(DECODE_ID(hw), + PRINT_FLAG_VDEC_DETAIL)) { + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + int frame_index = FRAME_INDEX(vf->index); + if (frame_index < 0 || + frame_index >= DPB_SIZE_MAX) { + dpb_print(DECODE_ID(hw), 0, + "%s vf index 0x%x error\r\n", + __func__, vf->index); + } else { + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_DETAIL, + "%s buf_spec_num %d vf %p poc %d dur %d pts %d interval %dms, ts: %lld\n", + __func__, BUFSPEC_INDEX(vf->index), vf, + p_H264_Dpb->mFrameStore[frame_index].poc, + vf->duration, vf->pts, frame_interval, vf->timestamp); + } + } + if (hw->last_frame_time > 0) { + if (frame_interval > + max_get_frame_interval[DECODE_ID(hw)]) + max_get_frame_interval[DECODE_ID(hw)] + = frame_interval; + } + hw->last_frame_time = time; + vf->index_disp = atomic_read(&hw->vf_get_count); + atomic_add(1, &hw->vf_get_count); + if (kfifo_peek(&hw->display_q, &next_vf) && next_vf) { + vf->next_vf_pts_valid = true; + vf->next_vf_pts = next_vf->pts; + } else + vf->next_vf_pts_valid = false; + + return vf; + } + + return NULL; +} + +static bool vf_valid_check(struct vframe_s *vf, struct vdec_h264_hw_s *hw) { + int i,j; + if (hw->is_used_v4l) + return true; + for (i = 0; i < VF_POOL_SIZE; i++) { + for (j = 0; j < VF_POOL_NUM; j ++) { + if (vf == &(hw->vfpool[j][i]) || vf == &hw->vframe_dummy) + return true; + } + } + dpb_print(DECODE_ID(hw), 0, " invalid vf been put, vf = %p\n", vf); + for (i = 0; i < VF_POOL_SIZE; i++) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "dump vf [%d]= %p\n", i, &(hw->vfpool[hw->cur_pool][i])); + } + return false; +} + +static void vh264_vf_put(struct vframe_s *vf, void *op_arg) +{ + struct vdec_s *vdec = op_arg; + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; + unsigned long flags; + int buf_spec_num; + int frame_index; + + if (vf == (&hw->vframe_dummy)) + return; + + if (!vf) + return; + + if (vf->index == -1) { + dpb_print(DECODE_ID(hw), 0, + "Warning: %s vf %p invalid index\r\n", + __func__, vf); + return; + } + + if (hw->enable_fence && vf->fence) { + int ret, i; + + mutex_lock(&hw->fence_mutex); + ret = dma_fence_get_status(vf->fence); + if (ret == 0) { + for (i = 0; i < VF_POOL_SIZE; i++) { + if (hw->fence_vf_s.fence_vf[i] == NULL) { + hw->fence_vf_s.fence_vf[i] = vf; + hw->fence_vf_s.used_size++; + mutex_unlock(&hw->fence_mutex); + return; + } + } + } + mutex_unlock(&hw->fence_mutex); + } + + buf_spec_num = BUFSPEC_INDEX(vf->index); + if (hw->enable_fence) + frame_index = hw->buffer_spec[buf_spec_num].fs_idx; + else + frame_index = FRAME_INDEX(vf->index); + + if (frame_index < 0 || + frame_index >= DPB_SIZE_MAX || + buf_spec_num < 0 || + buf_spec_num >= BUFSPEC_POOL_SIZE) { + dpb_print(DECODE_ID(hw), 0, + "%s vf index 0x%x error\r\n", + __func__, vf->index); + return; + } + /*get_buf_spec_idx_by_canvas_config(hw, + &vf->canvas0_config[0]);*/ + + if (hw->enable_fence && vf->fence) { + vdec_fence_put(vf->fence); + vf->fence = NULL; + } + + if (vf->meta_data_buf) { + vf->meta_data_buf = NULL; + vf->meta_data_size = 0; + } + + spin_lock_irqsave(&hw->bufspec_lock, flags); + if (hw->buffer_spec[buf_spec_num].used == 2) { + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s %p to fs[%d], poc %d buf_spec_num %d used %d vf_ref %d\n", + __func__, vf, frame_index, + p_H264_Dpb->mFrameStore[frame_index].poc, + buf_spec_num, + hw->buffer_spec[buf_spec_num].used, + hw->buffer_spec[buf_spec_num].vf_ref); + hw->buffer_spec[buf_spec_num].vf_ref--; + if (hw->buffer_spec[buf_spec_num].vf_ref <= 0) + set_frame_output_flag(&hw->dpb, frame_index); + } else { + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s %p isolated vf, buf_spec_num %d used %d vf_ref %d\n", + __func__, vf, buf_spec_num, + hw->buffer_spec[buf_spec_num].used, + hw->buffer_spec[buf_spec_num].vf_ref); + hw->buffer_spec[buf_spec_num].vf_ref--; + if (hw->buffer_spec[buf_spec_num].vf_ref <= 0) { + if (hw->buffer_spec[buf_spec_num].used == 3) + hw->buffer_spec[buf_spec_num].used = 4; + else if (hw->buffer_spec[buf_spec_num].used == 5) + hw->buffer_spec[buf_spec_num].used = 0; + } + if (dpb_is_debug(DECODE_ID(hw), + PRINT_FLAG_DUMP_BUFSPEC)) + dump_bufspec(hw, __func__); + + } + + if (hw->is_used_v4l) { + struct buffer_spec_s *pic = &hw->buffer_spec[buf_spec_num]; + + if (vf->v4l_mem_handle != pic->cma_alloc_addr) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL, + "H264 update fb handle, old:%llx, new:%llx\n", + pic->cma_alloc_addr, vf->v4l_mem_handle); + + pic->cma_alloc_addr = vf->v4l_mem_handle; + } + } + + if (vf && (vf_valid_check(vf, hw) == true)) { + atomic_add(1, &hw->vf_put_count); + kfifo_put(&hw->newframe_q, (const struct vframe_s *)vf); + ATRACE_COUNTER(hw->trace.new_q_name, kfifo_len(&hw->newframe_q)); + } +#define ASSIST_MBOX1_IRQ_REG VDEC_ASSIST_MBOX1_IRQ_REG + if (hw->buffer_empty_flag) + WRITE_VREG(ASSIST_MBOX1_IRQ_REG, 0x1); + spin_unlock_irqrestore(&hw->bufspec_lock, flags); +} + + +void * vh264_get_bufspec_lock(struct vdec_s *vdec) +{ + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; + if (hw) + return (&hw->bufspec_lock); + else + return NULL; +} +static int vh264_event_cb(int type, void *data, void *op_arg) +{ + unsigned long flags; + struct vdec_s *vdec = op_arg; + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; + + if (type & VFRAME_EVENT_RECEIVER_GET_AUX_DATA) { + struct provider_aux_req_s *req = + (struct provider_aux_req_s *)data; + int buf_spec_num; + + if (!req->vf) { + req->aux_size = atomic_read(&hw->vf_put_count); + return 0; + } + buf_spec_num = BUFSPEC_INDEX(req->vf->index); + spin_lock_irqsave(&hw->lock, flags); + req->aux_buf = NULL; + req->aux_size = 0; + if (buf_spec_num >= 0 && + buf_spec_num < BUFSPEC_POOL_SIZE && + is_buf_spec_in_disp_q(hw, buf_spec_num) + ) { + req->aux_buf = + hw->buffer_spec[buf_spec_num].aux_data_buf; + req->aux_size = + hw->buffer_spec[buf_spec_num].aux_data_size; +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + req->dv_enhance_exist = + hw->buffer_spec[buf_spec_num].dv_enhance_exist; +#else + req->dv_enhance_exist = 0; +#endif + } + spin_unlock_irqrestore(&hw->lock, flags); + + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s(type 0x%x vf buf_spec_num 0x%x)=>size 0x%x\n", + __func__, type, buf_spec_num, req->aux_size); + } else if (type & VFRAME_EVENT_RECEIVER_REQ_STATE) { + struct provider_state_req_s *req = + (struct provider_state_req_s *)data; + if (req->req_type == REQ_STATE_SECURE) + req->req_result[0] = vdec_secure(vdec); + else + req->req_result[0] = 0xffffffff; + } + + return 0; +} + +static void set_frame_info(struct vdec_h264_hw_s *hw, struct vframe_s *vf, + u32 index) +{ + int endian_tmp; + struct canvas_config_s *p_canvas_config; + int force_rate = input_frame_based(hw_to_vdec(hw)) ? + force_rate_framebase : force_rate_streambase; + dpb_print(DECODE_ID(hw), PRINT_FLAG_DPB_DETAIL, + "%s (%d,%d) dur %d, vf %p, index %d\n", __func__, + hw->frame_width, hw->frame_height, hw->frame_dur, vf, index); + + /* signal_type */ + if (hw->video_signal_from_vui & VIDEO_SIGNAL_TYPE_AVAILABLE_MASK) { + vf->signal_type = hw->video_signal_from_vui; + if (hw->is_used_v4l) { + struct aml_vdec_hdr_infos hdr; + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + + memset(&hdr, 0, sizeof(hdr)); + hdr.signal_type = hw->video_signal_from_vui; + vdec_v4l_set_hdr_infos(ctx, &hdr); + } + } else + vf->signal_type = 0; + hw->video_signal_type = vf->signal_type; + + vf->width = hw->frame_width; + vf->height = hw->frame_height; + if (force_rate) { + if (force_rate == -1) + vf->duration = 0; + else + vf->duration = 96000/force_rate; + } else + vf->duration = hw->frame_dur; + vf->ratio_control = + (min(hw->h264_ar, (u32) DISP_RATIO_ASPECT_RATIO_MAX)) << + DISP_RATIO_ASPECT_RATIO_BIT; + vf->orientation = hw->vh264_rotation; + + vf->sidebind_type = hw->sidebind_type; + vf->sidebind_channel_id = hw->sidebind_channel_id; + + if (hw->mmu_enable) + return; + + vf->canvas0Addr = vf->canvas1Addr = -1; +#ifdef NV21 + vf->plane_num = 2; +#else + vf->plane_num = 3; +#endif + + if (IS_VDEC_DW(hw)) { + if (IS_VDEC_DW(hw) == 1) + vf->width = hw->frame_width / 2; + else + vf->width = (hw->frame_width / IS_VDEC_DW(hw)); + vf->height = (hw->frame_height / IS_VDEC_DW(hw)); + p_canvas_config = &hw->buffer_spec[index].vdec_dw_canvas_config[0]; + } else + p_canvas_config = &hw->buffer_spec[index].canvas_config[0]; + + vf->canvas0_config[0] = p_canvas_config[0]; + vf->canvas0_config[1] = p_canvas_config[1]; + vf->canvas1_config[0] = p_canvas_config[0]; + vf->canvas1_config[1] = p_canvas_config[1]; +#ifndef NV21 + vf->canvas0_config[2] = p_canvas_config[2]; + vf->canvas1_config[2] = p_canvas_config[2]; +#endif + if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T7) { + endian_tmp = (hw->canvas_mode == CANVAS_BLKMODE_LINEAR) ? 7 : 0; + } else { + endian_tmp = (hw->canvas_mode == CANVAS_BLKMODE_LINEAR) ? 0 : 7; + } + vf->canvas0_config[0].endian = endian_tmp; + vf->canvas0_config[1].endian = endian_tmp; + vf->canvas1_config[0].endian = endian_tmp; + vf->canvas1_config[1].endian = endian_tmp; +#ifndef NV21 + vf->canvas0_config[2].endian = endian_tmp; + vf->canvas1_config[2].endian = endian_tmp; +#endif +} + +static void get_picture_qos_info(struct StorablePicture *picture) +{ + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_G12A) { + unsigned char a[3]; + unsigned char i, j, t; + unsigned long data; + + get_random_bytes(&data, sizeof(unsigned long)); + if (picture->slice_type == I_SLICE) + data = 0; + a[0] = data & 0xff; + a[1] = (data >> 8) & 0xff; + a[2] = (data >> 16) & 0xff; + + for (i = 0; i < 3; i++) + for (j = i+1; j < 3; j++) { + if (a[j] < a[i]) { + t = a[j]; + a[j] = a[i]; + a[i] = t; + } else if (a[j] == a[i]) { + a[i]++; + t = a[j]; + a[j] = a[i]; + a[i] = t; + } + } + picture->max_mv = a[2]; + picture->avg_mv = a[1]; + picture->min_mv = a[0]; + /* + pr_info("mv data %x a[0]= %x a[1]= %x a[2]= %x\n", + data, a[0], a[1], a[2]); + */ + + get_random_bytes(&data, sizeof(unsigned long)); + a[0] = data & 0x1f; + a[1] = (data >> 8) & 0x3f; + a[2] = (data >> 16) & 0x7f; + + for (i = 0; i < 3; i++) + for (j = i+1; j < 3; j++) { + if (a[j] < a[i]) { + t = a[j]; + a[j] = a[i]; + a[i] = t; + } else if (a[j] == a[i]) { + a[i]++; + t = a[j]; + a[j] = a[i]; + a[i] = t; + } + } + picture->max_qp = a[2]; + picture->avg_qp = a[1]; + picture->min_qp = a[0]; + /* + pr_info("qp data %x a[0]= %x a[1]= %x a[2]= %x\n", + data, a[0], a[1], a[2]); + */ + + get_random_bytes(&data, sizeof(unsigned long)); + a[0] = data & 0x1f; + a[1] = (data >> 8) & 0x3f; + a[2] = (data >> 16) & 0x7f; + + for (i = 0; i < 3; i++) + for (j = i+1; j < 3; j++) { + if (a[j] < a[i]) { + t = a[j]; + a[j] = a[i]; + a[i] = t; + } else if (a[j] == a[i]) { + a[i]++; + t = a[j]; + a[j] = a[i]; + a[i] = t; + } + } + picture->max_skip = a[2]; + picture->avg_skip = a[1]; + picture->min_skip = a[0]; + + + /* + pr_info("skip data %x a[0]= %x a[1]= %x a[2]= %x\n", + data,a[0], a[1], a[2]); + */ + } else { + uint32_t blk88_y_count; + uint32_t blk88_c_count; + uint32_t blk22_mv_count; + uint32_t rdata32; + int32_t mv_hi; + int32_t mv_lo; + uint32_t rdata32_l; + uint32_t mvx_L0_hi; + uint32_t mvy_L0_hi; + uint32_t mvx_L1_hi; + uint32_t mvy_L1_hi; + int64_t value; + uint64_t temp_value; +/* +#define DEBUG_QOS +*/ +#ifdef DEBUG_QOS + int pic_number = picture->poc; +#endif + + picture->max_mv = 0; + picture->avg_mv = 0; + picture->min_mv = 0; + + picture->max_skip = 0; + picture->avg_skip = 0; + picture->min_skip = 0; + + picture->max_qp = 0; + picture->avg_qp = 0; + picture->min_qp = 0; + + + + + + /* set rd_idx to 0 */ + WRITE_VREG(VDEC_PIC_QUALITY_CTRL, 0); + blk88_y_count = READ_VREG(VDEC_PIC_QUALITY_DATA); + if (blk88_y_count == 0) { +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] NO Data yet.\n", + pic_number); +#endif + /* reset all counts */ + WRITE_VREG(VDEC_PIC_QUALITY_CTRL, (1<<8)); + return; + } + /* qp_y_sum */ + rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] Y QP AVG : %d (%d/%d)\n", + pic_number, rdata32/blk88_y_count, + rdata32, blk88_y_count); +#endif + picture->avg_qp = rdata32/blk88_y_count; + /* intra_y_count */ + rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] Y intra rate : %d%c (%d)\n", + pic_number, rdata32*100/blk88_y_count, + '%', rdata32); +#endif + /* skipped_y_count */ + rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] Y skipped rate : %d%c (%d)\n", + pic_number, rdata32*100/blk88_y_count, + '%', rdata32); +#endif + picture->avg_skip = rdata32*100/blk88_y_count; + /* coeff_non_zero_y_count */ + rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] Y ZERO_Coeff rate : %d%c (%d)\n", + pic_number, (100 - rdata32*100/(blk88_y_count*1)), + '%', rdata32); +#endif + /* blk66_c_count */ + blk88_c_count = READ_VREG(VDEC_PIC_QUALITY_DATA); + if (blk88_c_count == 0) { +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] NO Data yet.\n", + pic_number); +#endif + /* reset all counts */ + WRITE_VREG(VDEC_PIC_QUALITY_CTRL, (1<<8)); + return; + } + /* qp_c_sum */ + rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] C QP AVG : %d (%d/%d)\n", + pic_number, rdata32/blk88_c_count, + rdata32, blk88_c_count); +#endif + /* intra_c_count */ + rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] C intra rate : %d%c (%d)\n", + pic_number, rdata32*100/blk88_c_count, + '%', rdata32); +#endif + /* skipped_cu_c_count */ + rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] C skipped rate : %d%c (%d)\n", + pic_number, rdata32*100/blk88_c_count, + '%', rdata32); +#endif + /* coeff_non_zero_c_count */ + rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] C ZERO_Coeff rate : %d%c (%d)\n", + pic_number, (100 - rdata32*100/(blk88_c_count*1)), + '%', rdata32); +#endif + + /* 1'h0, qp_c_max[6:0], 1'h0, qp_c_min[6:0], + 1'h0, qp_y_max[6:0], 1'h0, qp_y_min[6:0] */ + rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] Y QP min : %d\n", + pic_number, (rdata32>>0)&0xff); +#endif + picture->min_qp = (rdata32>>0)&0xff; + +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] Y QP max : %d\n", + pic_number, (rdata32>>8)&0xff); +#endif + picture->max_qp = (rdata32>>8)&0xff; + +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] C QP min : %d\n", + pic_number, (rdata32>>16)&0xff); + pr_info(" [Picture %d Quality] C QP max : %d\n", + pic_number, (rdata32>>24)&0xff); +#endif + + /* blk22_mv_count */ + blk22_mv_count = READ_VREG(VDEC_PIC_QUALITY_DATA); + if (blk22_mv_count == 0) { +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] NO MV Data yet.\n", + pic_number); +#endif + /* reset all counts */ + WRITE_VREG(VDEC_PIC_QUALITY_CTRL, (1<<8)); + return; + } + /* mvy_L1_count[39:32], mvx_L1_count[39:32], + mvy_L0_count[39:32], mvx_L0_count[39:32] */ + rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); + /* should all be 0x00 or 0xff */ +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] MV AVG High Bits: 0x%X\n", + pic_number, rdata32); +#endif + mvx_L0_hi = ((rdata32>>0)&0xff); + mvy_L0_hi = ((rdata32>>8)&0xff); + mvx_L1_hi = ((rdata32>>16)&0xff); + mvy_L1_hi = ((rdata32>>24)&0xff); + + /* mvx_L0_count[31:0] */ + rdata32_l = READ_VREG(VDEC_PIC_QUALITY_DATA); + temp_value = mvx_L0_hi; + temp_value = (temp_value << 32) | rdata32_l; + + if (mvx_L0_hi & 0x80) + value = 0xFFFFFFF000000000 | temp_value; + else + value = temp_value; + value = div_s64(value, blk22_mv_count); +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] MVX_L0 AVG : %d (%lld/%d)\n", + pic_number, (int)(value), + value, blk22_mv_count); +#endif + picture->avg_mv = value; + + /* mvy_L0_count[31:0] */ + rdata32_l = READ_VREG(VDEC_PIC_QUALITY_DATA); + temp_value = mvy_L0_hi; + temp_value = (temp_value << 32) | rdata32_l; + + if (mvy_L0_hi & 0x80) + value = 0xFFFFFFF000000000 | temp_value; + else + value = temp_value; +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] MVY_L0 AVG : %d (%lld/%d)\n", + pic_number, rdata32_l/blk22_mv_count, + value, blk22_mv_count); +#endif + + /* mvx_L1_count[31:0] */ + rdata32_l = READ_VREG(VDEC_PIC_QUALITY_DATA); + temp_value = mvx_L1_hi; + temp_value = (temp_value << 32) | rdata32_l; + if (mvx_L1_hi & 0x80) + value = 0xFFFFFFF000000000 | temp_value; + else + value = temp_value; +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] MVX_L1 AVG : %d (%lld/%d)\n", + pic_number, rdata32_l/blk22_mv_count, + value, blk22_mv_count); +#endif + + /* mvy_L1_count[31:0] */ + rdata32_l = READ_VREG(VDEC_PIC_QUALITY_DATA); + temp_value = mvy_L1_hi; + temp_value = (temp_value << 32) | rdata32_l; + if (mvy_L1_hi & 0x80) + value = 0xFFFFFFF000000000 | temp_value; + else + value = temp_value; +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] MVY_L1 AVG : %d (%lld/%d)\n", + pic_number, rdata32_l/blk22_mv_count, + value, blk22_mv_count); +#endif + + /* {mvx_L0_max, mvx_L0_min} // format : {sign, abs[14:0]} */ + rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); + mv_hi = (rdata32>>16)&0xffff; + if (mv_hi & 0x8000) + mv_hi = 0x8000 - mv_hi; +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] MVX_L0 MAX : %d\n", + pic_number, mv_hi); +#endif + picture->max_mv = mv_hi; + + mv_lo = (rdata32>>0)&0xffff; + if (mv_lo & 0x8000) + mv_lo = 0x8000 - mv_lo; +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] MVX_L0 MIN : %d\n", + pic_number, mv_lo); +#endif + picture->min_mv = mv_lo; + +#ifdef DEBUG_QOS + /* {mvy_L0_max, mvy_L0_min} */ + rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); + mv_hi = (rdata32>>16)&0xffff; + if (mv_hi & 0x8000) + mv_hi = 0x8000 - mv_hi; + pr_info(" [Picture %d Quality] MVY_L0 MAX : %d\n", + pic_number, mv_hi); + + + mv_lo = (rdata32>>0)&0xffff; + if (mv_lo & 0x8000) + mv_lo = 0x8000 - mv_lo; + + pr_info(" [Picture %d Quality] MVY_L0 MIN : %d\n", + pic_number, mv_lo); + + + /* {mvx_L1_max, mvx_L1_min} */ + rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); + mv_hi = (rdata32>>16)&0xffff; + if (mv_hi & 0x8000) + mv_hi = 0x8000 - mv_hi; + + pr_info(" [Picture %d Quality] MVX_L1 MAX : %d\n", + pic_number, mv_hi); + + + mv_lo = (rdata32>>0)&0xffff; + if (mv_lo & 0x8000) + mv_lo = 0x8000 - mv_lo; + + pr_info(" [Picture %d Quality] MVX_L1 MIN : %d\n", + pic_number, mv_lo); + + + /* {mvy_L1_max, mvy_L1_min} */ + rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); + mv_hi = (rdata32>>16)&0xffff; + if (mv_hi & 0x8000) + mv_hi = 0x8000 - mv_hi; + + pr_info(" [Picture %d Quality] MVY_L1 MAX : %d\n", + pic_number, mv_hi); + + mv_lo = (rdata32>>0)&0xffff; + if (mv_lo & 0x8000) + mv_lo = 0x8000 - mv_lo; + + pr_info(" [Picture %d Quality] MVY_L1 MIN : %d\n", + pic_number, mv_lo); +#endif + + rdata32 = READ_VREG(VDEC_PIC_QUALITY_CTRL); +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] After Read : VDEC_PIC_QUALITY_CTRL : 0x%x\n", + pic_number, rdata32); +#endif + /* reset all counts */ + WRITE_VREG(VDEC_PIC_QUALITY_CTRL, (1<<8)); + } +} + +static int get_dec_dpb_size(struct vdec_h264_hw_s *hw, int mb_width, + int mb_height, int level_idc) +{ + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + int pic_size = mb_width * mb_height * 384; + int size = 0, size_vui; + + switch (level_idc) { + case 9: + size = 152064; + break; + case 10: + size = 152064; + break; + case 11: + size = 345600; + break; + case 12: + size = 912384; + break; + case 13: + size = 912384; + break; + case 20: + size = 912384; + break; + case 21: + size = 1824768; + break; + case 22: + size = 3110400; + break; + case 30: + size = 3110400; + break; + case 31: + size = 6912000; + break; + case 32: + size = 7864320; + break; + case 40: + size = 12582912; + break; + case 41: + size = 12582912; + break; + case 42: + size = 13369344; + break; + case 50: + size = 42393600; + break; + case 51: + case 52: + default: + size = 70778880; + break; + } + + size /= pic_size; + size = imin(size, 16); + dpb_print(DECODE_ID(hw), 0, + "level_idc = %d pic_size = %d size = %d\n", + level_idc, pic_size, size); + if (p_H264_Dpb->bitstream_restriction_flag) { + if ((int)p_H264_Dpb->max_dec_frame_buffering > size) { + dpb_print(DECODE_ID(hw), 0, + "max_dec_frame_buffering larger than MaxDpbSize.\n"); + } + size_vui = imax (1, p_H264_Dpb->max_dec_frame_buffering); + if (size_vui < size) { + dpb_print(DECODE_ID(hw), 0, + "Warning: max_dec_frame_buffering(%d) is less than DPB size(%d) calculated from Profile/Level.\n", + size_vui, size); + } + size = size_vui; + } + + size += 2; /* need two more buffer */ + + if (!hw->discard_dv_data) { + size += 1; + dpb_print(DECODE_ID(hw), 0, "dv stream need one more buffer.\n"); + } + + return size; +} + +static int get_dec_dpb_size_active(struct vdec_h264_hw_s *hw, u32 param1, u32 param4) +{ + int mb_width, mb_total; + int mb_height = 0; + int dec_dpb_size; + int level_idc = param4 & 0xff; + + mb_width = param1 & 0xff; + mb_total = (param1 >> 8) & 0xffff; + if (!mb_width && mb_total) /*for 4k2k*/ + mb_width = 256; + if (mb_width) + mb_height = mb_total/mb_width; + if (mb_width <= 0 || mb_height <= 0 || + is_oversize(mb_width << 4, mb_height << 4)) { + dpb_print(DECODE_ID(hw), 0, + "!!!wrong param1 0x%x mb_width/mb_height (0x%x/0x%x) %x\r\n", + param1, + mb_width, + mb_height); + hw->error_frame_width = mb_width << 4; + hw->error_frame_height = mb_height << 4; + return -1; + } + hw->error_frame_width = 0; + hw->error_frame_height = 0; + + dec_dpb_size = get_dec_dpb_size(hw , mb_width, mb_height, level_idc); + + if (hw->no_poc_reorder_flag) + dec_dpb_size = 1; + + return dec_dpb_size; +} + +static void vh264_config_canvs_for_mmu(struct vdec_h264_hw_s *hw) +{ + int i, j; + + if (hw->double_write_mode) { + mutex_lock(&vmh264_mutex); + if (hw->decode_pic_count == 0) { + for (j = 0; j < hw->dpb.mDPB.size; j++) { + i = get_buf_spec_by_canvas_pos(hw, j); + if (i >= 0) + config_decode_canvas_ex(hw, i); + } + } + mutex_unlock(&vmh264_mutex); + } +} + +static int vh264_set_params(struct vdec_h264_hw_s *hw, + u32 param1, u32 param2, u32 param3, u32 param4, bool buffer_reset_flag) +{ + int i, j; + int mb_width, mb_total; + int max_reference_size, level_idc; + int mb_height = 0; + unsigned long flags; + /*int mb_mv_byte;*/ + struct vdec_s *vdec = hw_to_vdec(hw); + u32 seq_info2; + u32 seq_info3; + int ret = 0; + int active_buffer_spec_num; + unsigned int buf_size; + unsigned int frame_mbs_only_flag; + unsigned int chroma_format_idc; + unsigned int crop_bottom, crop_right; + unsigned int used_reorder_dpb_size_margin + = hw->reorder_dpb_size_margin; + u8 *colocate_vaddr = NULL; + int dec_dpb_size_change = 0; + +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + if (vdec->master || vdec->slave) + used_reorder_dpb_size_margin = + reorder_dpb_size_margin_dv; +#endif + seq_info2 = param1; + seq_info3 = param4; + hw->seq_info = param2; + + mb_width = seq_info2 & 0xff; + mb_total = (seq_info2 >> 8) & 0xffff; + if (!mb_width && mb_total) /*for 4k2k*/ + mb_width = 256; + if (mb_width) + mb_height = mb_total/mb_width; + if (mb_width <= 0 || mb_height <= 0 || + is_oversize(mb_width << 4, mb_height << 4)) { + dpb_print(DECODE_ID(hw), 0, + "!!!wrong seq_info2 0x%x mb_width/mb_height (0x%x/0x%x) %x\r\n", + seq_info2, + mb_width, + mb_height); + hw->error_frame_width = mb_width << 4; + hw->error_frame_height = mb_height << 4; + return -1; + } + hw->error_frame_width = 0; + hw->error_frame_height = 0; + + dec_dpb_size_change = hw->dpb.dec_dpb_size != get_dec_dpb_size_active(hw, param1, param4); + + if (((seq_info2 != 0 && + (hw->seq_info2 & 0x80ffffff) != (param1 & 0x80ffffff)) || dec_dpb_size_change) && + hw->seq_info2 != 0 + ) { /*picture size changed*/ + h264_reconfig(hw); + } else { + /*someting changes and not including dpb_size, width, height, ...*/ + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + u32 reg_val = param4; + level_idc = reg_val & 0xff; + p_H264_Dpb->mSPS.level_idc = level_idc; + max_reference_size = (reg_val >> 8) & 0xff; + hw->dpb.reorder_output = max_reference_size; + + hw->cfg_param1 = param1; + hw->cfg_bitstream_restriction_flag = hw->bitstream_restriction_flag; + + hw->seq_info2 = seq_info2; + hw->seq_info3 = seq_info3; + + if (p_H264_Dpb->bitstream_restriction_flag && + p_H264_Dpb->num_reorder_frames <= p_H264_Dpb->max_dec_frame_buffering && + p_H264_Dpb->num_reorder_frames >= 0) { + hw->dpb.reorder_output = hw->num_reorder_frames + 1; + } + + hw->max_reference_size = + max_reference_size + reference_buf_margin; + + if (hw->max_reference_size > MAX_VF_BUF_NUM) + hw->max_reference_size = MAX_VF_BUF_NUM; + hw->dpb.max_reference_size = hw->max_reference_size; + } + + if (hw->config_bufmgr_done == 0) { + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + u32 reg_val; + int sub_width_c = 0, sub_height_c = 0; + + hw->cfg_param1 = param1; + hw->cfg_param2 = param2; + hw->cfg_param3 = param3; + hw->cfg_param4 = param4; + hw->cfg_bitstream_restriction_flag = hw->bitstream_restriction_flag; + + hw->seq_info2 = seq_info2; + hw->seq_info3 = seq_info3; + dpb_print(DECODE_ID(hw), 0, + "AV_SCRATCH_1 = %x, AV_SCRATCH_2 = %x, AV_SCRATCH_B: = %x\n", + seq_info2, hw->seq_info, seq_info3); + + dpb_init_global(&hw->dpb, + DECODE_ID(hw), 0, 0); + + p_H264_Dpb->fast_output_enable = fast_output_enable; + /*mb_mv_byte = (seq_info2 & 0x80000000) ? 24 : 96;*/ + + if (hw->enable_fence) + p_H264_Dpb->fast_output_enable = H264_OUTPUT_MODE_FAST; + +#if 1 + /*crop*/ + /* AV_SCRATCH_2 + bit 15: frame_mbs_only_flag + bit 13-14: chroma_format_idc */ + frame_mbs_only_flag = (hw->seq_info >> 15) & 0x01; + if (p_H264_Dpb->mSPS.profile_idc != 100 && + p_H264_Dpb->mSPS.profile_idc != 110 && + p_H264_Dpb->mSPS.profile_idc != 122 && + p_H264_Dpb->mSPS.profile_idc != 144) { + p_H264_Dpb->chroma_format_idc = 1; + } + chroma_format_idc = p_H264_Dpb->chroma_format_idc; + + /* @AV_SCRATCH_6.31-16 = (left << 8 | right ) << 1 + @AV_SCRATCH_6.15-0 = (top << 8 | bottom ) << + (2 - frame_mbs_only_flag) */ + + switch (chroma_format_idc) { + case 1: + sub_width_c = 2; + sub_height_c = 2; + break; + + case 2: + sub_width_c = 2; + sub_height_c = 1; + break; + + case 3: + sub_width_c = 1; + sub_height_c = 1; + break; + + default: + break; + } + + if (chroma_format_idc == 0) { + crop_right = p_H264_Dpb->frame_crop_right_offset; + crop_bottom = p_H264_Dpb->frame_crop_bottom_offset * + (2 - frame_mbs_only_flag); + } else { + crop_right = sub_width_c * p_H264_Dpb->frame_crop_right_offset; + crop_bottom = sub_height_c * p_H264_Dpb->frame_crop_bottom_offset * + (2 - frame_mbs_only_flag); + } + + p_H264_Dpb->mSPS.frame_mbs_only_flag = frame_mbs_only_flag; + hw->frame_width = mb_width << 4; + hw->frame_height = mb_height << 4; + + hw->frame_width = hw->frame_width - crop_right; + hw->frame_height = hw->frame_height - crop_bottom; + + dpb_print(DECODE_ID(hw), 0, + "chroma_format_idc = %d frame_mbs_only_flag %d, crop_bottom %d, frame_height %d,\n", + chroma_format_idc, frame_mbs_only_flag, crop_bottom, hw->frame_height); + dpb_print(DECODE_ID(hw), 0, + "mb_height %d,crop_right %d, frame_width %d, mb_width %d\n", + mb_height, crop_right, + hw->frame_width, mb_width); + + if (hw->frame_height == 1088 && (crop_right != 0 || crop_bottom != 0)) + hw->frame_height = 1080; +#endif + reg_val = param4; + level_idc = reg_val & 0xff; + p_H264_Dpb->mSPS.level_idc = level_idc; + max_reference_size = (reg_val >> 8) & 0xff; + hw->dpb.reorder_output = max_reference_size; + hw->dpb.dec_dpb_size = + get_dec_dpb_size(hw , mb_width, mb_height, level_idc); + if (!hw->mmu_enable) { + mb_width = (mb_width+3) & 0xfffffffc; + mb_height = (mb_height+3) & 0xfffffffc; + } + mb_total = mb_width * mb_height; + hw->mb_width = mb_width; + hw->mb_height = mb_height; + hw->mb_total = mb_total; + if (hw->mmu_enable) + hevc_mcr_sao_global_hw_init(hw, + (hw->mb_width << 4), (hw->mb_height << 4)); + + dpb_print(DECODE_ID(hw), 0, + "mb height/widht/total: %x/%x/%x level_idc %x max_ref_num %x\n", + mb_height, mb_width, mb_total, + level_idc, max_reference_size); + + p_H264_Dpb->colocated_buf_size = mb_total * 96; + + dpb_print(DECODE_ID(hw), 0, + "restriction_flag=%d, max_dec_frame_buffering=%d, dec_dpb_size=%d num_reorder_frames %d used_reorder_dpb_size_margin %d\n", + hw->bitstream_restriction_flag, + hw->max_dec_frame_buffering, + hw->dpb.dec_dpb_size, + hw->num_reorder_frames, + used_reorder_dpb_size_margin); + + if (p_H264_Dpb->bitstream_restriction_flag && + p_H264_Dpb->num_reorder_frames <= p_H264_Dpb->max_dec_frame_buffering && + p_H264_Dpb->num_reorder_frames >= 0) { + hw->dpb.reorder_output = hw->num_reorder_frames + 1; + } + + active_buffer_spec_num = + hw->dpb.dec_dpb_size + + used_reorder_dpb_size_margin; + hw->max_reference_size = + max_reference_size + reference_buf_margin; + + if (active_buffer_spec_num > MAX_VF_BUF_NUM) { + active_buffer_spec_num = MAX_VF_BUF_NUM; + hw->dpb.dec_dpb_size = active_buffer_spec_num + - used_reorder_dpb_size_margin; + dpb_print(DECODE_ID(hw), 0, + "active_buffer_spec_num is larger than MAX %d, set dec_dpb_size to %d\n", + MAX_VF_BUF_NUM, hw->dpb.dec_dpb_size); + } + + if (hw->is_used_v4l) { + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + struct vdec_pic_info pic; + + vdec_v4l_get_pic_info(ctx, &pic); + + active_buffer_spec_num = pic.dpb_frames + + pic.dpb_margin; + } + + hw->dpb.mDPB.size = active_buffer_spec_num; + if (hw->max_reference_size > MAX_VF_BUF_NUM) + hw->max_reference_size = MAX_VF_BUF_NUM; + hw->dpb.max_reference_size = hw->max_reference_size; + + if (hw->no_poc_reorder_flag) + hw->dpb.dec_dpb_size = 1; + dpb_print(DECODE_ID(hw), 0, + "%s active_buf_spec_num %d dec_dpb_size %d collocate_buf_num %d\r\n", + __func__, active_buffer_spec_num, + hw->dpb.dec_dpb_size, + hw->max_reference_size); + + if (hw->kpi_first_i_comming == 0) { + hw->kpi_first_i_comming = 1; + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_DETAIL, + "[vdec_kpi][%s] First I frame comming.\n", __func__); + } + + buf_size = (hw->mb_total << 8) + (hw->mb_total << 7); + + mutex_lock(&vmh264_mutex); + if (!hw->mmu_enable) { + if (!buffer_reset_flag) + config_buf_specs(vdec); + i = get_buf_spec_by_canvas_pos(hw, 0); + + if (hw->is_used_v4l) { + if (i != -1) { + pr_info("v4l: delay alloc the buffer.\n"); + } + } else { + if ((i != -1) && alloc_one_buf_spec(hw, i) >= 0) + config_decode_canvas(hw, i); + else + ret = -1; + } + } else { + if (hw->double_write_mode) { + config_buf_specs_ex(vdec); + } else { + spin_lock_irqsave(&hw->bufspec_lock, flags); + for (i = 0, j = 0; + j < active_buffer_spec_num + && i < BUFSPEC_POOL_SIZE; + i++) { + if (hw->buffer_spec[i].used != -1) + continue; + hw->buffer_spec[i].used = 0; + hw->buffer_spec[i]. + alloc_header_addr = 0; + hw->buffer_spec[i].canvas_pos = j; + j++; + } + spin_unlock_irqrestore(&hw->bufspec_lock, + flags); + } + hevc_mcr_config_canv2axitbl(hw, 0); + } + mutex_unlock(&vmh264_mutex); + if (dpb_is_debug(DECODE_ID(hw), + PRINT_FLAG_DUMP_BUFSPEC)) + dump_bufspec(hw, __func__); + +#ifdef ONE_COLOCATE_BUF_PER_DECODE_BUF + buf_size = PAGE_ALIGN( + p_H264_Dpb->colocated_buf_size * + active_buffer_spec_num); +#else + buf_size = PAGE_ALIGN( + p_H264_Dpb->colocated_buf_size * + hw->max_reference_size); +#endif + + if (decoder_bmmu_box_alloc_buf_phy(hw->bmmu_box, BMMU_REF_IDX, + buf_size, DRIVER_NAME, + &hw->collocate_cma_alloc_addr) < 0) + return -1; + if (!vdec_secure(vdec)) { + /* clear for some mosaic problem after reset bufmgr */ + colocate_vaddr = codec_mm_vmap(hw->collocate_cma_alloc_addr, buf_size); + if (colocate_vaddr != NULL) { + memset(colocate_vaddr, 0, buf_size); + codec_mm_dma_flush(colocate_vaddr, buf_size, DMA_TO_DEVICE); + codec_mm_unmap_phyaddr(colocate_vaddr); + } + } + + hw->dpb.colocated_mv_addr_start = + hw->collocate_cma_alloc_addr; +#ifdef ONE_COLOCATE_BUF_PER_DECODE_BUF + hw->dpb.colocated_mv_addr_end = + hw->dpb.colocated_mv_addr_start + + (p_H264_Dpb->colocated_buf_size * + active_buffer_spec_num); +#else + hw->dpb.colocated_mv_addr_end = + hw->dpb.colocated_mv_addr_start + + (p_H264_Dpb->colocated_buf_size * + hw->max_reference_size); +#endif + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "callocate cma, %lx, %x\n", + hw->collocate_cma_alloc_addr, + hw->dpb.colocated_mv_addr_start); + + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "colocated_mv_addr_start %x colocated_mv_addr_end %x\n", + hw->dpb.colocated_mv_addr_start, + hw->dpb.colocated_mv_addr_end); + if (!hw->mmu_enable) { + mutex_lock(&vmh264_mutex); + if (ret >= 0 && hw->decode_pic_count == 0) { + int buf_cnt; + /* h264_reconfig: alloc later*/ + buf_cnt = hw->dpb.mDPB.size; + + for (j = 1; j < buf_cnt; j++) { + i = get_buf_spec_by_canvas_pos(hw, j); + + if (hw->is_used_v4l) { + pr_info("v4l: delay alloc the buffer.\n"); + break; + } else if (alloc_one_buf_spec(hw, i) < 0) + break; + + config_decode_canvas(hw, i); + } + } + mutex_unlock(&vmh264_mutex); + } else { + vh264_config_canvs_for_mmu(hw); + } + + hw->config_bufmgr_done = 1; + + /*end of config_bufmgr_done */ + } + + return ret; +} + +static void vui_config(struct vdec_h264_hw_s *hw) +{ + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + int aspect_ratio_info_present_flag, aspect_ratio_idc; + /*time*/ + hw->num_units_in_tick = p_H264_Dpb->num_units_in_tick; + hw->time_scale = p_H264_Dpb->time_scale; + hw->timing_info_present_flag = p_H264_Dpb->vui_status & 0x2; + + hw->bitstream_restriction_flag = + p_H264_Dpb->bitstream_restriction_flag; + hw->num_reorder_frames = + p_H264_Dpb->num_reorder_frames; + hw->max_dec_frame_buffering = + p_H264_Dpb->max_dec_frame_buffering; + + dpb_print(DECODE_ID(hw), PRINT_FLAG_DPB_DETAIL, + "vui_config: pdb %d, %d, %d\n", + p_H264_Dpb->bitstream_restriction_flag, + p_H264_Dpb->num_reorder_frames, + p_H264_Dpb->max_dec_frame_buffering); + + hw->fixed_frame_rate_flag = 0; + if (hw->timing_info_present_flag) { + hw->fixed_frame_rate_flag = + p_H264_Dpb->fixed_frame_rate_flag; + + if (hw->is_used_v4l && (p_H264_Dpb->dpb_param.l.data[SLICE_TYPE] == I_Slice) && + (hw->num_units_in_tick != 0)) { + if (hw->num_units_in_tick % 1001 == 0) { + int multiple = hw->num_units_in_tick / 1001; + + if (hw->time_scale / multiple == 120000) { + hw->frame_dur = RATE_11990_FPS; + if (hw->fixed_frame_rate_flag == 1) + hw->frame_dur = RATE_5994_FPS; + } else if (hw->time_scale / multiple == 60000) { + hw->frame_dur = RATE_5994_FPS; + if (hw->fixed_frame_rate_flag == 1) + hw->frame_dur = RATE_2997_FPS; + } else if ((hw->time_scale / multiple == 48000) && + (hw->fixed_frame_rate_flag == 1)) { + hw->frame_dur = RATE_2397_FPS; + } else if (hw->time_scale / multiple == 30000) { + hw->frame_dur = RATE_2997_FPS; + } else if (hw->time_scale / multiple == 24000) { + hw->frame_dur = RATE_2397_FPS; + } + } else { + u32 frame_rate = hw->time_scale / hw->num_units_in_tick; + + if (hw->fixed_frame_rate_flag == 1) { + frame_rate = frame_rate / 2; + } + hw->frame_dur = 96000 / frame_rate; + } + } + + if (((hw->num_units_in_tick * 120) >= hw->time_scale && + ((!hw->sync_outside) || + (!hw->frame_dur))) + && hw->num_units_in_tick && hw->time_scale) { + if (hw->use_idr_framerate || + hw->fixed_frame_rate_flag || + !hw->frame_dur || + !hw->duration_from_pts_done + /*|| vh264_running*/) { + u32 frame_dur_es = + div_u64(96000ULL * 2 * hw->num_units_in_tick, + hw->time_scale); + if (hw->frame_dur != frame_dur_es) { + hw->h264_first_valid_pts_ready = false; + hw->h264pts1 = 0; + hw->h264pts2 = 0; + hw->h264_pts_count = 0; + hw->duration_from_pts_done = 0; + fixed_frame_rate_mode = + FIX_FRAME_RATE_OFF; + hw->pts_duration = 0; + hw->frame_dur = frame_dur_es; + if (!hw->fixed_frame_rate_flag && (p_H264_Dpb->mSPS.profile_idc != BASELINE)) { + if (frame_dur_es == 7680) + hw->frame_dur = frame_dur_es /2; + } + vdec_schedule_work(&hw->notify_work); + dpb_print(DECODE_ID(hw), + PRINT_FLAG_DEC_DETAIL, + "frame_dur %d from timing_info\n", + hw->frame_dur); + } + + /*hack to avoid use ES frame duration when + *it's half of the rate from system info + * sometimes the encoder is given a wrong + * frame rate but the system side information + * is more reliable + *if ((frame_dur * 2) != frame_dur_es) { + * frame_dur = frame_dur_es; + *} + */ + } + } + } else { + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "H.264: timing_info not present\n"); + } + + /*aspect ratio*/ + aspect_ratio_info_present_flag = + p_H264_Dpb->vui_status & 0x1; + aspect_ratio_idc = p_H264_Dpb->aspect_ratio_idc; + + if (aspect_ratio_info_present_flag) { + if (aspect_ratio_idc == EXTEND_SAR) { + hw->h264_ar = 0x3ff; + hw->height_aspect_ratio = + p_H264_Dpb->aspect_ratio_sar_height; + hw->width_aspect_ratio = + p_H264_Dpb->aspect_ratio_sar_width; + } else { + /* pr_info("v264dec: aspect_ratio_idc = %d\n", + aspect_ratio_idc); */ + + switch (aspect_ratio_idc) { + case 1: + hw->h264_ar = 0x3ff; + hw->height_aspect_ratio = 1; + hw->width_aspect_ratio = 1; + break; + case 2: + hw->h264_ar = 0x3ff; + hw->height_aspect_ratio = 11; + hw->width_aspect_ratio = 12; + break; + case 3: + hw->h264_ar = 0x3ff; + hw->height_aspect_ratio = 11; + hw->width_aspect_ratio = 10; + break; + case 4: + hw->h264_ar = 0x3ff; + hw->height_aspect_ratio = 11; + hw->width_aspect_ratio = 16; + break; + case 5: + hw->h264_ar = 0x3ff; + hw->height_aspect_ratio = 33; + hw->width_aspect_ratio = 40; + break; + case 6: + hw->h264_ar = 0x3ff; + hw->height_aspect_ratio = 11; + hw->width_aspect_ratio = 24; + break; + case 7: + hw->h264_ar = 0x3ff; + hw->height_aspect_ratio = 11; + hw->width_aspect_ratio = 20; + break; + case 8: + hw->h264_ar = 0x3ff; + hw->height_aspect_ratio = 11; + hw->width_aspect_ratio = 32; + break; + case 9: + hw->h264_ar = 0x3ff; + hw->height_aspect_ratio = 33; + hw->width_aspect_ratio = 80; + break; + case 10: + hw->h264_ar = 0x3ff; + hw->height_aspect_ratio = 11; + hw->width_aspect_ratio = 18; + break; + case 11: + hw->h264_ar = 0x3ff; + hw->height_aspect_ratio = 11; + hw->width_aspect_ratio = 15; + break; + case 12: + hw->h264_ar = 0x3ff; + hw->height_aspect_ratio = 33; + hw->width_aspect_ratio = 64; + break; + case 13: + hw->h264_ar = 0x3ff; + hw->height_aspect_ratio = 99; + hw->width_aspect_ratio = 160; + break; + case 14: + hw->h264_ar = 0x3ff; + hw->height_aspect_ratio = 3; + hw->width_aspect_ratio = 4; + break; + case 15: + hw->h264_ar = 0x3ff; + hw->height_aspect_ratio = 2; + hw->width_aspect_ratio = 3; + break; + case 16: + hw->h264_ar = 0x3ff; + hw->height_aspect_ratio = 1; + hw->width_aspect_ratio = 2; + break; + default: + if (hw->vh264_ratio >> 16) { + hw->h264_ar = (hw->frame_height * + (hw->vh264_ratio & 0xffff) * + 0x100 + + ((hw->vh264_ratio >> 16) * + hw->frame_width / 2)) / + ((hw->vh264_ratio >> 16) * + hw->frame_width); + hw->height_aspect_ratio = 1; + hw->width_aspect_ratio = 1; + } else { + hw->h264_ar = 0x3ff; + hw->height_aspect_ratio = 1; + hw->width_aspect_ratio = 1; + } + break; + } + } + } else { + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "v264dec: aspect_ratio not available from source\n"); + if (hw->vh264_ratio >> 16) { + /* high 16 bit is width, low 16 bit is height */ + hw->h264_ar = + ((hw->vh264_ratio & 0xffff) * + hw->frame_height * 0x100 + + (hw->vh264_ratio >> 16) * + hw->frame_width / 2) / + ((hw->vh264_ratio >> 16) * + hw->frame_width); + hw->height_aspect_ratio = 1; + hw->width_aspect_ratio = 1; + } else { + hw->h264_ar = 0x3ff; + hw->height_aspect_ratio = 1; + hw->width_aspect_ratio = 1; + } + } + + if (hw->pts_unstable && (hw->fixed_frame_rate_flag == 0)) { + if (((hw->frame_dur == RATE_2397_FPS) + && (dec_control + & DEC_CONTROL_FLAG_FORCE_RATE_2397_FPS_FIX_FRAME_RATE)) + || ((RATE_2997_FPS == + hw->frame_dur) && + (dec_control & + DEC_CONTROL_FLAG_FORCE_RATE_2997_FPS_FIX_FRAME_RATE))) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "force fix frame rate\n"); + hw->fixed_frame_rate_flag = 0x40; + } + } + + /*video_signal_from_vui: to do .. */ +} + +static void bufmgr_recover(struct vdec_h264_hw_s *hw) +{ + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + + bufmgr_h264_remove_unused_frame(p_H264_Dpb, 2); + if (hw->error_proc_policy & 0x20) { + if (!hw->is_used_v4l) + hw->reset_bufmgr_flag = 1; + } +} + +void bufmgr_force_recover(struct h264_dpb_stru *p_H264_Dpb) +{ + struct vdec_h264_hw_s *hw = + container_of(p_H264_Dpb, struct vdec_h264_hw_s, dpb); + + dpb_print(DECODE_ID(hw), 0, "call %s\n", __func__); + + bufmgr_h264_remove_unused_frame(p_H264_Dpb, 2); + hw->reset_bufmgr_flag = 1; +} + +#ifdef CONSTRAIN_MAX_BUF_NUM +static int get_vf_ref_only_buf_count(struct vdec_h264_hw_s *hw) +{ + int i; + int count = 0; + for (i = 0; i < BUFSPEC_POOL_SIZE; i++) { + if (is_buf_spec_in_disp_q(hw, i) && + hw->buffer_spec[i].vf_ref > 0) + count++; + } + return count; +} + +static int get_used_buf_count(struct vdec_h264_hw_s *hw) +{ + int i; + int count = 0; + for (i = 0; i < BUFSPEC_POOL_SIZE; i++) { + if (is_buf_spec_in_use(hw, i)) + count++; + } + return count; +} +#endif + + +static bool is_buffer_available(struct vdec_s *vdec) +{ + bool buffer_available = 1; + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)(vdec->private); + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; + int i, frame_outside_count = 0, inner_size = 0; + if ((kfifo_len(&hw->newframe_q) <= 0) || + ((hw->config_bufmgr_done) && (!have_free_buf_spec(vdec))) || + ((p_H264_Dpb->mDPB.init_done) && + (p_H264_Dpb->mDPB.used_size >= (p_H264_Dpb->mDPB.size - 1)) && + (is_there_unused_frame_from_dpb(&p_H264_Dpb->mDPB) == 0))) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_DETAIL, + "%s, empty, newq(%d), free_spec(%d), initdon(%d), used_size(%d/%d), unused_fr_dpb(%d)\n", + __func__, + kfifo_len(&hw->newframe_q), + have_free_buf_spec(vdec), + p_H264_Dpb->mDPB.init_done, + p_H264_Dpb->mDPB.used_size, p_H264_Dpb->mDPB.size, + is_there_unused_frame_from_dpb(&p_H264_Dpb->mDPB) + ); + buffer_available = 0; + if (dpb_is_debug(DECODE_ID(hw), + DEBUG_DISABLE_RUNREADY_RMBUF)) + return buffer_available; + + if ((hw->error_proc_policy & 0x4) && + (hw->error_proc_policy & 0x8)) { + if ((kfifo_len(&hw->display_q) <= 0) && + (p_H264_Dpb->mDPB.used_size >= + (p_H264_Dpb->mDPB.size - 1)) && + (p_Dpb->ref_frames_in_buffer > + (imax( + 1, p_Dpb->num_ref_frames) + - p_Dpb->ltref_frames_in_buffer + + force_sliding_margin))){ + bufmgr_recover(hw); + } else { + bufmgr_h264_remove_unused_frame(p_H264_Dpb, 1); + } + } else if ((hw->error_proc_policy & 0x4) && + (kfifo_len(&hw->display_q) <= 0) && + ((p_H264_Dpb->mDPB.used_size >= + (p_H264_Dpb->mDPB.size - 1)) || + (!have_free_buf_spec(vdec))) && + (hw->discard_dv_data)) { + unsigned long flags; + spin_lock_irqsave(&hw->bufspec_lock, flags); + + for (i = 0; i < p_Dpb->used_size; i++) { + if (p_Dpb->fs[i]->pre_output) + frame_outside_count++; + else if (p_Dpb->fs[i]->is_output && !is_used_for_reference(p_Dpb->fs[i])) { + spin_unlock_irqrestore(&hw->bufspec_lock, flags); + bufmgr_h264_remove_unused_frame(p_H264_Dpb, 0); + return 0; + } + } + spin_unlock_irqrestore(&hw->bufspec_lock, flags); + inner_size = p_Dpb->size - frame_outside_count; + + if (inner_size >= p_H264_Dpb->dec_dpb_size) { + if (p_H264_Dpb->mDPB.used_size >= + p_H264_Dpb->mDPB.size) { + bufmgr_recover(hw); + } else if (p_H264_Dpb->mDPB.used_size >= + (p_H264_Dpb->mDPB.size - 1)) { + if (inner_size > p_H264_Dpb->dec_dpb_size) { + bufmgr_recover(hw); + } + } + } + bufmgr_h264_remove_unused_frame(p_H264_Dpb, 0); + } else if ((hw->error_proc_policy & 0x8) && + (p_Dpb->ref_frames_in_buffer > + (imax( + 1, p_Dpb->num_ref_frames) + - p_Dpb->ltref_frames_in_buffer + + force_sliding_margin))) + bufmgr_recover(hw); + else + bufmgr_h264_remove_unused_frame(p_H264_Dpb, 1); + + if (hw->reset_bufmgr_flag == 1) + buffer_available = 1; + } + + if (hw->is_used_v4l) + buffer_available = have_free_buf_spec(vdec); + + return buffer_available; +} + +#define AUX_TAG_SEI 0x2 + +#define SEI_BUFFERING_PERIOD 0 +#define SEI_PicTiming 1 +#define SEI_USER_DATA 4 +#define SEI_RECOVERY_POINT 6 + +/* + ************************************************************************* + * Function:Reads bits from the bitstream buffer + * Input: + byte buffer[] + containing sei message data bits + int totbitoffset + bit offset from start of partition + int bytecount + total bytes in bitstream + int numbits + number of bits to read + * Output: + int *info + * Return: + -1: failed + > 0: the count of bit read + * Attention: + ************************************************************************* + */ + +static int get_bits(unsigned char buffer[], + int totbitoffset, + int *info, + int bytecount, + int numbits) +{ + register int inf; + long byteoffset; + int bitoffset; + + int bitcounter = numbits; + + byteoffset = totbitoffset / 8; + bitoffset = 7 - (totbitoffset % 8); + + inf = 0; + while (numbits) { + inf <<= 1; + inf |= (buffer[byteoffset] & (0x01 << bitoffset)) >> bitoffset; + numbits--; + bitoffset--; + if (bitoffset < 0) { + byteoffset++; + bitoffset += 8; + if (byteoffset > bytecount) + return -1; + } + } + + *info = inf; + + + return bitcounter; +} + +static int parse_one_sei_record(struct vdec_h264_hw_s *hw, + u8 *sei_data_buf, + u8 *sei_data_buf_end) +{ + int payload_type; + int payload_size; + u8 *p_sei; + int temp = 0; + int bit_offset; + int read_size; + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + + p_sei = sei_data_buf; + read_size = 0; + payload_type = 0; + do { + if (p_sei >= sei_data_buf_end) + return read_size; + + payload_type += *p_sei; + read_size++; + } while (*p_sei++ == 255); + + + payload_size = 0; + do { + if (p_sei >= sei_data_buf_end) + return read_size; + + payload_size += *p_sei; + read_size++; + } while (*p_sei++ == 255); + + + if (p_sei + payload_size > sei_data_buf_end) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_DPB_DETAIL, + "%s: payload_type = %d, payload_size = %d is over\n", + __func__, payload_type, payload_size); + return read_size; + } + bit_offset = 0; + + if (payload_size <= 0) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_DPB_DETAIL, + "%s warning: this is a null sei message for payload_type = %d\n", + __func__, payload_type); + return read_size; + } + p_H264_Dpb->vui_status = p_H264_Dpb->dpb_param.l.data[VUI_STATUS]; + switch (payload_type) { + case SEI_BUFFERING_PERIOD: + break; + case SEI_PicTiming: + if (p_H264_Dpb->vui_status & 0xc) { + int cpb_removal_delay; + int dpb_output_delay; + u32 delay_len; + + delay_len = p_H264_Dpb->dpb_param.l.data[DELAY_LENGTH]; + cpb_removal_delay + = (delay_len & 0x1F) + 1; + dpb_output_delay + = ((delay_len >> 5) & 0x1F) + 1; + + get_bits(p_sei, bit_offset, + &temp, payload_size, + dpb_output_delay+cpb_removal_delay); + bit_offset += dpb_output_delay+cpb_removal_delay; + } + if (p_H264_Dpb->vui_status & 0x10) { + get_bits(p_sei, bit_offset, &temp, payload_size, 4); + bit_offset += 4; + p_H264_Dpb->dpb_param.l.data[PICTURE_STRUCT] = temp; + } + break; + case SEI_USER_DATA: + if (enable_itu_t35) { + int i; + int j; + int data_len; + u8 *user_data_buf; + + user_data_buf + = hw->sei_itu_data_buf + hw->sei_itu_data_len; + /* user data length should be align with 8 bytes, + if not, then padding with zero*/ + for (i = 0; i < payload_size; i += 8) { + if (hw->sei_itu_data_len + i >= SEI_ITU_DATA_SIZE) + break; // Avoid out-of-bound writing + for (j = 0; j < 8; j++) { + int index; + + index = i+7-j; + if (index >= payload_size) + user_data_buf[i+j] = 0; + else + user_data_buf[i+j] + = p_sei[i+7-j]; + } + } + + data_len = payload_size; + if (payload_size % 8) + data_len = ((payload_size + 8) >> 3) << 3; + + hw->sei_itu_data_len += data_len; + if (hw->sei_itu_data_len >= SEI_ITU_DATA_SIZE) + hw->sei_itu_data_len = SEI_ITU_DATA_SIZE; + /* + dpb_print(DECODE_ID(hw), 0, + "%s: user data, and len = %d:\n", + __func__, hw->sei_itu_data_len); + */ + } + break; + case SEI_RECOVERY_POINT: + p_H264_Dpb->dpb_param.l.data[RECOVERY_POINT] = 1; + break; + } + + return read_size + payload_size; +} + +static void parse_sei_data(struct vdec_h264_hw_s *hw, + u8 *sei_data_buf, + int len) +{ + char *p_sei; + char *p_sei_end; + int parsed_size; + int read_size; + + + p_sei = sei_data_buf; + p_sei_end = p_sei + len; + parsed_size = 0; + while (parsed_size < len) { + read_size = parse_one_sei_record(hw, p_sei, p_sei_end); + p_sei += read_size; + parsed_size += read_size; + if (*p_sei == 0x80) { + p_sei++; + parsed_size++; + } + } +} + +static void check_decoded_pic_error(struct vdec_h264_hw_s *hw) +{ + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + struct StorablePicture *p = p_H264_Dpb->mVideo.dec_picture; + unsigned mby_mbx = READ_VREG(MBY_MBX); + unsigned mb_total = (hw->seq_info2 >> 8) & 0xffff; + unsigned mb_width = hw->seq_info2 & 0xff; + unsigned decode_mb_count; + if (!mb_width && mb_total) /*for 4k2k*/ + mb_width = 256; + decode_mb_count = ((mby_mbx & 0xff) * mb_width + + (((mby_mbx >> 8) & 0xff) + 1)); + if ((mby_mbx == 0) && (p_H264_Dpb->dec_dpb_status != H264_SLICE_HEAD_DONE)) { + dpb_print(DECODE_ID(hw), 0, + "mby_mbx is zero\n"); + return; + } + if (get_cur_slice_picture_struct(p_H264_Dpb) != FRAME) + mb_total /= 2; + + if ((hw->error_proc_policy & 0x200) && + READ_VREG(ERROR_STATUS_REG) != 0) { + p->data_flag |= ERROR_FLAG; + } + + if (error_proc_policy & 0x100 && !(p->data_flag & ERROR_FLAG)) { + if (decode_mb_count < mb_total) { + p->data_flag |= ERROR_FLAG; + if (((error_proc_policy & 0x20000) && + decode_mb_count >= mb_total * (100 - mb_count_threshold) / 100)) { + p->data_flag &= ~ERROR_FLAG; + } + } + } + + if ((hw->error_proc_policy & 0x100000) && + hw->last_dec_picture && + (hw->last_dec_picture->slice_type == I_SLICE) && + (hw->dpb.mSlice.slice_type == P_SLICE)) { + if ((p->data_flag & ERROR_FLAG) && + (decode_mb_count >= mb_total)) { + hw->ip_field_error_count++; + if (hw->ip_field_error_count == 4) { + unsigned int i; + struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) { + if (p_Dpb->fs_ref[i]->top_field) + p_Dpb->fs_ref[i]->top_field->data_flag &= ~ERROR_FLAG; + if (p_Dpb->fs_ref[i]->bottom_field) + p_Dpb->fs_ref[i]->bottom_field->data_flag &= ~ERROR_FLAG; + if (p_Dpb->fs_ref[i]->frame) + p_Dpb->fs_ref[i]->frame->data_flag &= ~ERROR_FLAG; + } + hw->ip_field_error_count = 0; + p->data_flag &= ~ERROR_FLAG; + hw->data_flag &= ~ERROR_FLAG; + dpb_print(DECODE_ID(hw), 0, + "clear all ref frame error flag\n"); + } + } else { + if (hw->ip_field_error_count > 0) + dpb_print(DECODE_ID(hw), 0, + "clear error count %d\n", hw->ip_field_error_count); + hw->ip_field_error_count = 0; + } + } + + if (p->data_flag & ERROR_FLAG) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_ERRORFLAG_DBG, + "%s: decode error, seq_info2 0x%x, mby_mbx 0x%x, mb_total %d decoded mb_count %d ERROR_STATUS_REG 0x%x\n", + __func__, + hw->seq_info2, + mby_mbx, + mb_total, + decode_mb_count, + READ_VREG(ERROR_STATUS_REG) + ); + + } +} + +static int vh264_pic_done_proc(struct vdec_s *vdec) +{ + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)(vdec->private); + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + int ret; + int i; + struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; + + if (vdec->mvfrm) + vdec->mvfrm->hw_decode_time = + local_clock() - vdec->mvfrm->hw_decode_start; + + if (input_frame_based(vdec) && + (!(hw->i_only & 0x2)) && + frmbase_cont_bitlevel != 0 && + READ_VREG(VIFF_BIT_CNT) > + frmbase_cont_bitlevel) { + /*handle the case: multi pictures in one packet*/ + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s H264_PIC_DATA_DONE decode slice count %d, continue (bitcnt 0x%x)\n", + __func__, + hw->decode_pic_count, + READ_VREG(VIFF_BIT_CNT)); + hw->frmbase_cont_flag = 1; + } else + hw->frmbase_cont_flag = 0; + + if (p_H264_Dpb->mVideo.dec_picture) { + get_picture_qos_info(p_H264_Dpb->mVideo.dec_picture); +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + DEL_EXIST(hw, + p_H264_Dpb->mVideo.dec_picture) = 0; + if (vdec->master) { + struct vdec_h264_hw_s *hw_ba = + (struct vdec_h264_hw_s *) + vdec->master->private; + if (hw_ba->last_dec_picture) + DEL_EXIST(hw_ba, + hw_ba->last_dec_picture) + = 1; + } +#endif + mutex_lock(&hw->chunks_mutex); + if (hw->chunk) { + p_H264_Dpb->mVideo.dec_picture->pts = + hw->chunk->pts; + p_H264_Dpb->mVideo.dec_picture->pts64 = + hw->chunk->pts64; + p_H264_Dpb->mVideo.dec_picture->timestamp = + hw->chunk->timestamp; +#ifdef MH264_USERDATA_ENABLE + vmh264_udc_fill_vpts(hw, + p_H264_Dpb->mSlice.slice_type, + hw->chunk->pts, 1); +#endif + +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + } else if (vdec->master) { + /*dv enhance layer, + do not checkout pts*/ + struct StorablePicture *pic = + p_H264_Dpb->mVideo.dec_picture; + pic->pts = 0; + pic->pts64 = 0; +#endif + } else { + struct StorablePicture *pic = + p_H264_Dpb->mVideo.dec_picture; + u32 offset = pic->offset_delimiter; + pic->pic_size = (hw->start_bit_cnt - READ_VREG(VIFF_BIT_CNT)) >> 3; + if (pts_pickout_offset_us64(PTS_TYPE_VIDEO, + offset, &pic->pts, 0, &pic->pts64)) { + pic->pts = 0; + pic->pts64 = 0; +#ifdef MH264_USERDATA_ENABLE + vmh264_udc_fill_vpts(hw, + p_H264_Dpb->mSlice.slice_type, + pic->pts, 0); +#endif + } else { +#ifdef MH264_USERDATA_ENABLE + vmh264_udc_fill_vpts(hw, + p_H264_Dpb->mSlice.slice_type, + pic->pts, 1); +#endif + } + + } + mutex_unlock(&hw->chunks_mutex); + + check_decoded_pic_error(hw); +#ifdef ERROR_HANDLE_TEST + if ((hw->data_flag & ERROR_FLAG) + && (hw->error_proc_policy & 0x80)) { + release_cur_decoding_buf(hw); + h264_clear_dpb(hw); + hw->dec_flag = 0; + hw->data_flag = 0; + hw->skip_frame_count = 0; + hw->has_i_frame = 0; + hw->no_error_count = 0xfff; + hw->no_error_i_count = 0xf; + } else +#endif + if (hw->error_proc_policy & 0x200000) { + if (!hw->loop_flag) { + for (i = 0; i < p_Dpb->used_size; i++) { + if ((p_H264_Dpb->mVideo.dec_picture->poc + loop_playback_poc_threshold < p_Dpb->fs[i]->poc) && + !p_Dpb->fs[i]->is_output && + !p_Dpb->fs[i]->pre_output) { + hw->loop_flag = 1; + hw->loop_last_poc = p_H264_Dpb->mVideo.dec_picture->poc; + break; + } + } + } else { + if ((p_H264_Dpb->mVideo.dec_picture->poc >= hw->loop_last_poc - poc_threshold) && + (p_H264_Dpb->mVideo.dec_picture->poc <= hw->loop_last_poc + poc_threshold)) { + if (hw->loop_flag >= 5) { + for (i = 0; i < p_Dpb->used_size; i++) { + if ((hw->loop_last_poc + loop_playback_poc_threshold < p_Dpb->fs[i]->poc) && + !p_Dpb->fs[i]->is_output && + !p_Dpb->fs[i]->pre_output) { + p_Dpb->fs[i]->is_output = 1; + } + } + hw->loop_flag = 0; + } else + hw->loop_flag++; + } else + hw->loop_flag = 0; + } + } + p_H264_Dpb->wait_aux_data_flag = ((!hw->discard_dv_data) && (hw->frmbase_cont_flag)); + ret = store_picture_in_dpb(p_H264_Dpb, + p_H264_Dpb->mVideo.dec_picture, + hw->data_flag | hw->dec_flag | + p_H264_Dpb->mVideo.dec_picture->data_flag); + + + + if (ret == -1) { + release_cur_decoding_buf(hw); + bufmgr_force_recover(p_H264_Dpb); + } else if (ret == -2) { + release_cur_decoding_buf(hw); + } else { + if (hw->data_flag & ERROR_FLAG) { + hw->no_error_count = 0; + hw->no_error_i_count = 0; + } else { + hw->no_error_count++; + if (hw->data_flag & I_FLAG) + hw->no_error_i_count++; + } + if (hw->mmu_enable) + hevc_set_unused_4k_buff_idx(hw, + p_H264_Dpb->mVideo. + dec_picture->buf_spec_num); + bufmgr_post(p_H264_Dpb); + hw->last_dec_picture = + p_H264_Dpb->mVideo.dec_picture; + p_H264_Dpb->mVideo.dec_picture = NULL; + /* dump_dpb(&p_H264_Dpb->mDPB); */ + hw->has_i_frame = 1; + if (hw->mmu_enable) + hevc_set_frame_done(hw); + hw->decode_pic_count++; + p_H264_Dpb->decode_pic_count = hw->decode_pic_count; + if (hw->skip_frame_count > 0) { + /*skip n frame after first I */ + hw->skip_frame_count--; + if (hw->skip_frame_count == 0) + hw->dec_flag &= (~NODISP_FLAG); + } else if (hw->skip_frame_count < -1) { + /*skip n frame after first I until second I */ + hw->skip_frame_count++; + if (hw->skip_frame_count == -1) + hw->dec_flag &= (~NODISP_FLAG); + } + } + } + return 0; +} + +static irqreturn_t vh264_isr_thread_fn(struct vdec_s *vdec, int irq) +{ + int i; + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)(vdec->private); + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + unsigned int dec_dpb_status = p_H264_Dpb->dec_dpb_status; + u32 debug_tag; + + if (dec_dpb_status == H264_SLICE_HEAD_DONE || + p_H264_Dpb->dec_dpb_status == H264_CONFIG_REQUEST) { + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_START); + } + else if (dec_dpb_status == H264_PIC_DATA_DONE) { + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_PIC_DONE_START); + } + else if (dec_dpb_status == H264_SEI_DATA_READY) + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_SEI_START); + else if (dec_dpb_status == H264_AUX_DATA_READY) + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_AUX_START); + + if (dec_dpb_status == H264_CONFIG_REQUEST) { +#if 1 + unsigned short *p = (unsigned short *)hw->lmem_addr; + for (i = 0; i < (RPM_END-RPM_BEGIN); i += 4) { + int ii; + for (ii = 0; ii < 4; ii++) { + p_H264_Dpb->dpb_param.l.data[i+ii] = + p[i+3-ii]; + if (dpb_is_debug(DECODE_ID(hw), + RRINT_FLAG_RPM)) { + if (((i + ii) & 0xf) == 0) + dpb_print(DECODE_ID(hw), + 0, "%04x:", + i); + dpb_print_cont(DECODE_ID(hw), + 0, "%04x ", + p[i+3-ii]); + if (((i + ii + 1) & 0xf) == 0) + dpb_print_cont( + DECODE_ID(hw), + 0, "\r\n"); + } + } + } + + if (p_H264_Dpb->bitstream_restriction_flag != + ((p_H264_Dpb->dpb_param.l.data[SPS_FLAGS2] >> 3) & 0x1)) { + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "p_H264_Dpb->bitstream_restriction_flag 0x%x, new 0x%x\n", + p_H264_Dpb->bitstream_restriction_flag, ((p_H264_Dpb->dpb_param.l.data[SPS_FLAGS2] >> 3) & 0x1)); + } + p_H264_Dpb->bitstream_restriction_flag = + (p_H264_Dpb->dpb_param.l.data[SPS_FLAGS2] >> 3) & 0x1; + p_H264_Dpb->num_reorder_frames = + p_H264_Dpb->dpb_param.l.data[NUM_REORDER_FRAMES]; + p_H264_Dpb->max_dec_frame_buffering = + p_H264_Dpb->dpb_param.l.data[MAX_BUFFER_FRAME]; + + dpb_print(DECODE_ID(hw), PRINT_FLAG_DPB_DETAIL, + "H264_CONFIG_REQUEST: pdb %d, %d, %d\n", + p_H264_Dpb->bitstream_restriction_flag, + p_H264_Dpb->num_reorder_frames, + p_H264_Dpb->max_dec_frame_buffering); + hw->bitstream_restriction_flag = + p_H264_Dpb->bitstream_restriction_flag; + hw->num_reorder_frames = + p_H264_Dpb->num_reorder_frames; + hw->max_dec_frame_buffering = + p_H264_Dpb->max_dec_frame_buffering; + + /*crop*/ + p_H264_Dpb->chroma_format_idc = p_H264_Dpb->dpb_param.dpb.chroma_format_idc; + p_H264_Dpb->frame_crop_left_offset = p_H264_Dpb->dpb_param.dpb.frame_crop_left_offset; + p_H264_Dpb->frame_crop_right_offset = p_H264_Dpb->dpb_param.dpb.frame_crop_right_offset; + p_H264_Dpb->frame_crop_top_offset = p_H264_Dpb->dpb_param.dpb.frame_crop_top_offset; + p_H264_Dpb->frame_crop_bottom_offset = p_H264_Dpb->dpb_param.dpb.frame_crop_bottom_offset; + + dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL, + "%s chroma_format_idc %d crop offset: left %d right %d top %d bottom %d\n", + __func__, p_H264_Dpb->chroma_format_idc, + p_H264_Dpb->frame_crop_left_offset, + p_H264_Dpb->frame_crop_right_offset, + p_H264_Dpb->frame_crop_top_offset, + p_H264_Dpb->frame_crop_bottom_offset); +#endif + + WRITE_VREG(DPB_STATUS_REG, H264_ACTION_CONFIG_DONE); + reset_process_time(hw); + hw->reg_iqidct_control = READ_VREG(IQIDCT_CONTROL); + hw->reg_iqidct_control_init_flag = 1; + hw->dec_result = DEC_RESULT_CONFIG_PARAM; +#ifdef DETECT_WRONG_MULTI_SLICE + /*restart check count and set 'unknown'*/ + dpb_print(DECODE_ID(hw), PRINT_FLAG_UCODE_EVT, + "%s MULTI_SLICE_DETECT (check_count %d slice_count %d cur_slice_count %d flag %d), H264_CONFIG_REQUEST => restart check\n", + __func__, + hw->multi_slice_pic_check_count, + hw->picture_slice_count, + hw->cur_picture_slice_count, + hw->multi_slice_pic_flag); + + hw->multi_slice_pic_check_count = 0; + hw->multi_slice_pic_flag = 0; + hw->picture_slice_count = 0; +#endif + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_END); + vdec_schedule_work(&hw->work); + } else if (dec_dpb_status == H264_SLICE_HEAD_DONE) { + u16 data_hight; + u16 data_low; + u32 video_signal; + + int slice_header_process_status = 0; + int I_flag; + int frame_num_gap = 0; + union param dpb_param_bak; + /*unsigned char is_idr;*/ + unsigned short *p = (unsigned short *)hw->lmem_addr; + unsigned mb_width = hw->seq_info2 & 0xff; + unsigned short first_mb_in_slice; + unsigned int decode_mb_count, mby_mbx; + struct StorablePicture *pic = p_H264_Dpb->mVideo.dec_picture; + reset_process_time(hw); + hw->frmbase_cont_flag = 0; + + if ((pic != NULL) && (pic->mb_aff_frame_flag == 1)) + first_mb_in_slice = p[FIRST_MB_IN_SLICE + 3] * 2; + else + first_mb_in_slice = p[FIRST_MB_IN_SLICE + 3]; + +#ifdef DETECT_WRONG_MULTI_SLICE + hw->cur_picture_slice_count++; + + if ((hw->error_proc_policy & 0x10000) && + (hw->cur_picture_slice_count > 1) && + (first_mb_in_slice == 0) && + (hw->multi_slice_pic_flag == 0)) + hw->multi_slice_pic_check_count = 0; + + if ((hw->error_proc_policy & 0x10000) && + (hw->cur_picture_slice_count > 1) && + (hw->multi_slice_pic_flag == 1)) { + dpb_print(DECODE_ID(hw), 0, + "%s MULTI_SLICE_DETECT (check_count %d slice_count %d cur_slice_count %d flag %d), WRONG_MULTI_SLICE detected, insert picture\n", + __func__, + hw->multi_slice_pic_check_count, + hw->picture_slice_count, + hw->cur_picture_slice_count, + hw->multi_slice_pic_flag); + + mby_mbx = READ_VREG(MBY_MBX); + decode_mb_count = ((mby_mbx & 0xff) * mb_width + + (((mby_mbx >> 8) & 0xff) + 1)); + + if (first_mb_in_slice == decode_mb_count && + first_mb_in_slice != 0) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s first_mb_in_slice = %d \n", + __func__, first_mb_in_slice); + + hw->multi_slice_pic_flag = 0; + hw->multi_slice_pic_check_count = 0; + } else if (hw->cur_picture_slice_count > hw->last_picture_slice_count) { + vh264_pic_done_proc(vdec); + //if (p_H264_Dpb->mDPB.used_size == p_H264_Dpb->mDPB.size) { + if (!have_free_buf_spec(vdec)) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, "dpb full, wait buffer\n"); + p_H264_Dpb->mVideo.pre_frame_num = hw->first_pre_frame_num; + hw->last_picture_slice_count = hw->cur_picture_slice_count; + hw->no_decoder_buffer_flag = 1; + hw->dec_result = DEC_RESULT_AGAIN; + vdec_schedule_work(&hw->work); + return IRQ_HANDLED; + } + } + else { + if (p_H264_Dpb->mVideo.dec_picture) { + if (p_H264_Dpb->mVideo.dec_picture->colocated_buf_index >= 0) { + release_colocate_buf(p_H264_Dpb, + p_H264_Dpb->mVideo.dec_picture->colocated_buf_index); + p_H264_Dpb->mVideo.dec_picture->colocated_buf_index = -1; + } + } + release_cur_decoding_buf(hw); + } + } +#endif + + hw->reg_iqidct_control = READ_VREG(IQIDCT_CONTROL); + hw->reg_iqidct_control_init_flag = 1; + hw->reg_vcop_ctrl_reg = READ_VREG(VCOP_CTRL_REG); + hw->reg_rv_ai_mb_count = READ_VREG(RV_AI_MB_COUNT); + hw->vld_dec_control = READ_VREG(VLD_DECODE_CONTROL); + if (input_frame_based(vdec) && + frmbase_cont_bitlevel2 != 0 && + READ_VREG(VIFF_BIT_CNT) < + frmbase_cont_bitlevel2 && + hw->get_data_count >= 0x70000000) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s H264_SLICE_HEAD_DONE with small bitcnt %d, goto empty_proc\n", + __func__, + READ_VREG(VIFF_BIT_CNT)); + + goto empty_proc; + } + +#if 0 + if (p_H264_Dpb->mVideo.dec_picture == NULL) { + if (!is_buffer_available(vdec)) { + hw->buffer_empty_flag = 1; + dpb_print(DECODE_ID(hw), + PRINT_FLAG_UCODE_EVT, + "%s, buffer_empty, newframe_q(%d), have_free_buf_spec(%d), init_done(%d), used_size(%d/%d), is_there_unused_frame_from_dpb(%d)\n", + __func__, + kfifo_len(&hw->newframe_q), + have_free_buf_spec(vdec), + p_H264_Dpb->mDPB.init_done, + p_H264_Dpb->mDPB.used_size, + p_H264_Dpb->mDPB.size, + is_there_unused_frame_from_dpb( + &p_H264_Dpb->mDPB)); + return IRQ_HANDLED; + } + } + + hw->buffer_empty_flag = 0; +#endif +#ifdef SEND_PARAM_WITH_REG + for (i = 0; i < (RPM_END-RPM_BEGIN); i++) { + unsigned int data32; + + do { + data32 = READ_VREG(RPM_CMD_REG); + /* printk("%x\n", data32); */ + } while ((data32&0x10000) == 0); + p_H264_Dpb->dpb_param.l.data[i] = data32 & 0xffff; + WRITE_VREG(RPM_CMD_REG, 0); + /* printk("%x:%x\n", i,data32); */ + } +#else + dpb_param_bak = p_H264_Dpb->dpb_param; + ATRACE_COUNTER(hw->trace.decode_header_time_name, TRACE_HEADER_RPM_START); + for (i = 0; i < (RPM_END-RPM_BEGIN); i += 4) { + int ii; + + for (ii = 0; ii < 4; ii++) { + p_H264_Dpb->dpb_param.l.data[i+ii] = + p[i+3-ii]; + if (dpb_is_debug(DECODE_ID(hw), + RRINT_FLAG_RPM)) { + if (((i + ii) & 0xf) == 0) + dpb_print(DECODE_ID(hw), + 0, "%04x:", + i); + dpb_print_cont(DECODE_ID(hw), + 0, "%04x ", + p[i+3-ii]); + if (((i + ii + 1) & 0xf) == 0) + dpb_print_cont( + DECODE_ID(hw), + 0, "\r\n"); + } + } + } + ATRACE_COUNTER(hw->trace.decode_header_time_name, TRACE_HEADER_RPM_END); +#endif +#ifdef DETECT_WRONG_MULTI_SLICE + + if (p_H264_Dpb->mVideo.dec_picture && + hw->multi_slice_pic_flag == 2 && + (p_H264_Dpb->dpb_param.l.data[SLICE_TYPE] != dpb_param_bak.l.data[SLICE_TYPE] || + dpb_param_bak.l.data[FIRST_MB_IN_SLICE] > p_H264_Dpb->dpb_param.l.data[FIRST_MB_IN_SLICE])) { + dpb_print(DECODE_ID(hw), 0, + "decode next pic, save before, SLICE_TYPE BAK %d, SLICE_TYPE %d, FIRST_MB_IN_SLICE BAK %d, FIRST_MB_IN_SLICE %d\n", + dpb_param_bak.l.data[SLICE_TYPE], p_H264_Dpb->dpb_param.l.data[SLICE_TYPE], + dpb_param_bak.l.data[FIRST_MB_IN_SLICE], p_H264_Dpb->dpb_param.l.data[FIRST_MB_IN_SLICE]); + vh264_pic_done_proc(vdec); + } +#endif + data_low = p_H264_Dpb->dpb_param.l.data[VIDEO_SIGNAL_LOW]; + data_hight = p_H264_Dpb->dpb_param.l.data[VIDEO_SIGNAL_HIGHT]; + + video_signal = (data_hight << 16) | data_low; + hw->video_signal_from_vui = + ((video_signal & 0xffff) << 8) | + ((video_signal & 0xff0000) >> 16) | + ((video_signal & 0x3f000000)); + + + /*dpb_print(DECODE_ID(hw), + 0, + "video_signal_from_vui:0x%x, " + "data_low:0x%x, data_hight:0x%x\n", + hw->video_signal_from_vui, + data_low, + data_hight);*/ + + parse_sei_data(hw, hw->sei_data_buf, hw->sei_data_len); + + if (hw->config_bufmgr_done == 0) { + hw->dec_result = DEC_RESULT_DONE; + vdec_schedule_work(&hw->work); + dpb_print(DECODE_ID(hw), + PRINT_FLAG_UCODE_EVT, + "config_bufmgr not done, discard frame\n"); + return IRQ_HANDLED; + } else if ((hw->first_i_policy & 0x3) != 0) { + unsigned char is_i_slice = + (p_H264_Dpb->dpb_param.l.data[SLICE_TYPE] + == I_Slice) + ? 1 : 0; + unsigned char is_idr = + ((p_H264_Dpb->dpb_param.dpb.NAL_info_mmco & 0x1f) + == 5); + if ((hw->first_i_policy & 0x3) == 0x3) + is_i_slice = is_idr; + if (!is_i_slice) { + if (hw->has_i_frame == 0) { + amvdec_stop(); + vdec->mc_loaded = 0; + hw->dec_result = DEC_RESULT_DONE; + vdec_schedule_work(&hw->work); + dpb_print(DECODE_ID(hw), + PRINT_FLAG_UCODE_EVT, + "has_i_frame is 0, discard none I(DR) frame silce_type %d is_idr %d\n", p_H264_Dpb->dpb_param.l.data[SLICE_TYPE], is_idr); + return IRQ_HANDLED; + } + } else { + if (hw->skip_frame_count < 0 || is_idr) { + /* second I */ + hw->dec_flag &= (~NODISP_FLAG); + hw->skip_frame_count = 0; + } + if (hw->has_i_frame == 0 && + (!is_idr)) { + int skip_count = + (hw->first_i_policy >> 8) & 0xff; + /* first I (not IDR) */ + if ((hw->first_i_policy & 0x3) == 2) + hw->skip_frame_count = + -1 - skip_count; + else + hw->skip_frame_count = + skip_count; + if (hw->skip_frame_count != 0) + hw->dec_flag |= NODISP_FLAG; + } + } + } + dpb_print(DECODE_ID(hw), PRINT_FLAG_UCODE_EVT, + "current dpb index %d, poc %d, top/bot poc (%d,%d)\n", + p_H264_Dpb->dpb_param.dpb.current_dpb_index, + val(p_H264_Dpb->dpb_param.dpb.frame_pic_order_cnt), + val(p_H264_Dpb->dpb_param.dpb.top_field_pic_order_cnt), + val(p_H264_Dpb->dpb_param.dpb.top_field_pic_order_cnt)); + I_flag = (p_H264_Dpb->dpb_param.l.data[SLICE_TYPE] == I_Slice) + ? I_FLAG : 0; + + if ((hw->i_only & 0x2) && (I_flag & I_FLAG)) + flush_dpb(p_H264_Dpb); + + if ((hw->i_only & 0x2) && (!(I_flag & I_FLAG)) && + (p_H264_Dpb->mSlice.structure == FRAME)) { + hw->data_flag = NULL_FLAG; + goto pic_done_proc; + } + + slice_header_process_status = + h264_slice_header_process(p_H264_Dpb, &frame_num_gap); + if (hw->mmu_enable) + hevc_sao_set_slice_type(hw, + slice_header_process_status, + hw->dpb.mSlice.idr_flag); + vui_config(hw); + + if (slice_header_process_status == -1) { + amvdec_stop(); + hw->dec_result = DEC_RESULT_DONE; + vdec_schedule_work(&hw->work); + return IRQ_HANDLED; + } + + if (p_H264_Dpb->mVideo.dec_picture) { + int cfg_ret = 0; + bool field_pic_flag = false; + unsigned mby_mbx = READ_VREG(MBY_MBX); + struct StorablePicture *p = + p_H264_Dpb->mVideo.dec_picture; + + if (slice_header_process_status == 1) { + if (!p_H264_Dpb->mSPS.frame_mbs_only_flag) { + field_pic_flag = + (p_H264_Dpb->mSlice.structure == TOP_FIELD || + p_H264_Dpb->mSlice.structure == BOTTOM_FIELD) ? + true : false; + } + + vdec_set_profile_level(vdec, p_H264_Dpb->mSPS.profile_idc, + p_H264_Dpb->mSPS.level_idc); + + if (!field_pic_flag && (((p_H264_Dpb->mSPS.profile_idc == BASELINE) && + (p_H264_Dpb->dec_dpb_size < 2)) || + (((unsigned long)(hw->vh264_amstream_dec_info + .param)) & 0x8) || hw->low_latency_mode & 0x8)) { + p_H264_Dpb->fast_output_enable = + H264_OUTPUT_MODE_FAST; + } + else + p_H264_Dpb->fast_output_enable + = fast_output_enable; + if (hw->enable_fence) + p_H264_Dpb->fast_output_enable = H264_OUTPUT_MODE_FAST; + + hw->data_flag = I_flag; + if ((p_H264_Dpb-> + dpb_param.dpb.NAL_info_mmco & 0x1f) + == 5) + hw->data_flag |= IDR_FLAG; + if ((p_H264_Dpb->dpb_param.l.data[FIRST_MB_IN_SLICE]) && !mby_mbx) { + p->data_flag |= ERROR_FLAG; + dpb_print(DECODE_ID(hw), + PRINT_FLAG_VDEC_STATUS, + "one slice error in muulti-slice first_mb 0x%x mby_mbx 0x%x slice_type %d\n", + p_H264_Dpb->dpb_param.l. + data[FIRST_MB_IN_SLICE], + READ_VREG(MBY_MBX), + p->slice_type); + } + dpb_print(DECODE_ID(hw), + PRINT_FLAG_VDEC_STATUS, + "==================> frame count %d to skip %d\n", + hw->decode_pic_count+1, + hw->skip_frame_count); + } else if (hw->error_proc_policy & 0x100){ + unsigned decode_mb_count = + ((mby_mbx & 0xff) * hw->mb_width + + (((mby_mbx >> 8) & 0xff) + 1)); + if (decode_mb_count < + ((p_H264_Dpb->dpb_param.l.data[FIRST_MB_IN_SLICE]) * + (1 + p->mb_aff_frame_flag)) && decode_mb_count) { + dpb_print(DECODE_ID(hw), + PRINT_FLAG_VDEC_STATUS, + "Error detect! first_mb 0x%x mby_mbx 0x%x decode_mb 0x%x\n", + p_H264_Dpb->dpb_param.l. + data[FIRST_MB_IN_SLICE], + READ_VREG(MBY_MBX), + decode_mb_count); + p->data_flag |= ERROR_FLAG; + }/* else if (!p_H264_Dpb->dpb_param.l.data[FIRST_MB_IN_SLICE] && decode_mb_count) { + p->data_flag |= ERROR_FLAG; + goto pic_done_proc; + }*/ + } + + if (!I_flag && frame_num_gap && !p_H264_Dpb->long_term_reference_flag) { + if (!(hw->error_proc_policy & 0x800000)) { + hw->data_flag |= ERROR_FLAG; + p_H264_Dpb->mVideo.dec_picture->data_flag |= ERROR_FLAG; + dpb_print(DECODE_ID(hw), 0, "frame number gap error\n"); + } + } + + if (hw->error_proc_policy & 0x400) { + int ret = dpb_check_ref_list_error(p_H264_Dpb); + if (ret != 0) { + hw->reflist_error_count ++; + dpb_print(DECODE_ID(hw), 0, + "reference list error %d frame count %d to skip %d reflist_error_count %d\n", + ret, + hw->decode_pic_count+1, + hw->skip_frame_count, + hw->reflist_error_count); + + p_H264_Dpb->mVideo.dec_picture->data_flag = NODISP_FLAG; + if (((hw->error_proc_policy & 0x80) + && ((hw->dec_flag & + NODISP_FLAG) == 0)) ||(hw->reflist_error_count > 50)) { + hw->reset_bufmgr_flag = 1; + hw->reflist_error_count =0; + amvdec_stop(); + vdec->mc_loaded = 0; + hw->dec_result = DEC_RESULT_DONE; + vdec_schedule_work(&hw->work); + return IRQ_HANDLED; + } + } else + hw->reflist_error_count = 0; + } + if ((hw->error_proc_policy & 0x800) && (!(hw->i_only & 0x2)) + && p_H264_Dpb->dpb_error_flag != 0) { + dpb_print(DECODE_ID(hw), 0, + "dpb error %d\n", + p_H264_Dpb->dpb_error_flag); + hw->data_flag |= ERROR_FLAG; + p_H264_Dpb->mVideo.dec_picture->data_flag |= ERROR_FLAG; + if ((hw->error_proc_policy & 0x80) && + ((hw->dec_flag & NODISP_FLAG) == 0)) { + hw->reset_bufmgr_flag = 1; + amvdec_stop(); + vdec->mc_loaded = 0; + hw->dec_result = DEC_RESULT_DONE; + vdec_schedule_work(&hw->work); + return IRQ_HANDLED; + } + } + ATRACE_COUNTER(hw->trace.decode_header_time_name, TRACE_HEADER_REGISTER_START); + cfg_ret = config_decode_buf(hw, + p_H264_Dpb->mVideo.dec_picture); + ATRACE_COUNTER(hw->trace.decode_header_time_name, TRACE_HEADER_REGISTER_END); + if (cfg_ret < 0) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_ERROR, + "config_decode_buf fail (%d)\n", + cfg_ret); + if (hw->error_proc_policy & 0x2) { + release_cur_decoding_buf(hw); + /*hw->data_flag |= ERROR_FLAG;*/ + hw->reset_bufmgr_flag = 1; + hw->dec_result = DEC_RESULT_DONE; + vdec_schedule_work(&hw->work); + return IRQ_HANDLED; + } else + hw->data_flag |= ERROR_FLAG; + p_H264_Dpb->mVideo.dec_picture->data_flag |= ERROR_FLAG; + } + } + + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_HEAD_END); + + if (slice_header_process_status == 1) + WRITE_VREG(DPB_STATUS_REG, H264_ACTION_DECODE_NEWPIC); + else + WRITE_VREG(DPB_STATUS_REG, H264_ACTION_DECODE_SLICE); + hw->last_mby_mbx = 0; + hw->last_vld_level = 0; + start_process_time(hw); + } else if (dec_dpb_status == H264_PIC_DATA_DONE + ||((dec_dpb_status == H264_DATA_REQUEST) && input_frame_based(vdec))) { +#ifdef DETECT_WRONG_MULTI_SLICE + dpb_print(DECODE_ID(hw), PRINT_FLAG_UCODE_EVT, + "%s MULTI_SLICE_DETECT (check_count %d slice_count %d cur_slice_count %d flag %d), H264_PIC_DATA_DONE\n", + __func__, + hw->multi_slice_pic_check_count, + hw->picture_slice_count, + hw->cur_picture_slice_count, + hw->multi_slice_pic_flag); + + if (hw->multi_slice_pic_check_count < check_slice_num) { + hw->multi_slice_pic_check_count++; + if (hw->cur_picture_slice_count != + hw->picture_slice_count) { + /*restart check count and set 'unknown'*/ + hw->multi_slice_pic_check_count = 0; + hw->multi_slice_pic_flag = 0; + } + hw->picture_slice_count = + hw->cur_picture_slice_count; + } else if (hw->multi_slice_pic_check_count >= check_slice_num) { + if (hw->picture_slice_count > 1) + hw->multi_slice_pic_flag = 2; + else + hw->multi_slice_pic_flag = 1; + } +#endif + +pic_done_proc: + reset_process_time(hw); + if ((dec_dpb_status == H264_SEARCH_BUFEMPTY) || + (dec_dpb_status == H264_DECODE_BUFEMPTY) || + (dec_dpb_status == H264_DECODE_TIMEOUT) || + ((dec_dpb_status == H264_DATA_REQUEST) && input_frame_based(vdec))) { + hw->data_flag |= ERROR_FLAG; + if (hw->dpb.mVideo.dec_picture) + hw->dpb.mVideo.dec_picture->data_flag |= ERROR_FLAG; + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_DETAIL, + "%s, mark err_frame\n", __func__); + } + vh264_pic_done_proc(vdec); + + if (hw->frmbase_cont_flag) { + bufmgr_h264_remove_unused_frame(p_H264_Dpb, 0); + if (!have_free_buf_spec(vdec)) { + hw->dec_result = DEC_RESULT_NEED_MORE_BUFFER; + vdec_schedule_work(&hw->work); + return IRQ_HANDLED; + } + /*do not DEC_RESULT_GET_DATA*/ + hw->get_data_count = 0x7fffffff; + WRITE_VREG(DPB_STATUS_REG, H264_ACTION_SEARCH_HEAD); + decode_frame_count[DECODE_ID(hw)]++; + if (p_H264_Dpb->mSlice.slice_type == I_SLICE) { + hw->gvs.i_decoded_frames++; + } else if (p_H264_Dpb->mSlice.slice_type == P_SLICE) { + hw->gvs.p_decoded_frames++; + } else if (p_H264_Dpb->mSlice.slice_type == B_SLICE) { + hw->gvs.b_decoded_frames++; + } + start_process_time(hw); + return IRQ_HANDLED; + } + amvdec_stop(); + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s %s decode slice count %d\n", + __func__, + (dec_dpb_status == H264_PIC_DATA_DONE) ? + "H264_PIC_DATA_DONE" : + (dec_dpb_status == H264_FIND_NEXT_PIC_NAL) ? + "H264_FIND_NEXT_PIC_NAL" : "H264_FIND_NEXT_DVEL_NAL", + hw->decode_pic_count); + if (hw->kpi_first_i_decoded == 0) { + hw->kpi_first_i_decoded = 1; + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_DETAIL, + "[vdec_kpi][%s] First I frame decoded.\n", __func__); + } + /* WRITE_VREG(DPB_STATUS_REG, H264_ACTION_SEARCH_HEAD); */ + hw->dec_result = DEC_RESULT_DONE; +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + if (vdec->slave && + dec_dpb_status == H264_FIND_NEXT_DVEL_NAL) { + struct vdec_h264_hw_s *hw_el = + (struct vdec_h264_hw_s *)(vdec->slave->private); + hw_el->got_valid_nal = 0; + hw->switch_dvlayer_flag = 1; + } else if (vdec->master && + dec_dpb_status == H264_FIND_NEXT_PIC_NAL) { + struct vdec_h264_hw_s *hw_bl = + (struct vdec_h264_hw_s *)(vdec->master->private); + hw_bl->got_valid_nal = 0; + hw->switch_dvlayer_flag = 1; + } else { + hw->switch_dvlayer_flag = 0; + hw->got_valid_nal = 1; + } +#endif + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_EDN); + + hw->dec_result = DEC_RESULT_DONE; + vdec_schedule_work(&hw->work); + +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + } else if ( + (dec_dpb_status == H264_FIND_NEXT_PIC_NAL) || + (dec_dpb_status == H264_FIND_NEXT_DVEL_NAL)) { + goto pic_done_proc; +#endif + } else if (dec_dpb_status == H264_AUX_DATA_READY) { + reset_process_time(hw); + if (READ_VREG(H264_AUX_DATA_SIZE) != 0) { + if (dpb_is_debug(DECODE_ID(hw), + PRINT_FLAG_SEI_DETAIL)) + dump_aux_buf(hw); +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + if (vdec_frame_based(vdec)) { + if (hw->last_dec_picture) + set_aux_data(hw, + hw->last_dec_picture, 0, 0, NULL); + } else if (vdec->dolby_meta_with_el || vdec->slave) { + if (hw->last_dec_picture) + set_aux_data(hw, hw->last_dec_picture, + 0, 0, NULL); + } else { + if (vdec->master) { + struct vdec_h264_hw_s *hw_bl = + (struct vdec_h264_hw_s *) + (vdec->master->private); + if (hw_bl->last_dec_picture != NULL) { + set_aux_data(hw_bl, + hw_bl->last_dec_picture, + 0, 1, hw); + } + set_aux_data(hw, + hw->last_dec_picture, + 0, 2, NULL); + } + } +#else + if (hw->last_dec_picture) + set_aux_data(hw, + hw->last_dec_picture, 0, 0, NULL); +#endif + } +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + hw->switch_dvlayer_flag = 0; + hw->got_valid_nal = 1; +#endif + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s H264_AUX_DATA_READY\n", __func__); + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_EDN); + hw->dec_result = DEC_RESULT_DONE; + vdec_schedule_work(&hw->work); + } else if (/*(dec_dpb_status == H264_DATA_REQUEST) ||*/ + (dec_dpb_status == H264_SEARCH_BUFEMPTY) || + (dec_dpb_status == H264_DECODE_BUFEMPTY) || + (dec_dpb_status == H264_DECODE_TIMEOUT)) { +empty_proc: + reset_process_time(hw); + if ((hw->error_proc_policy & 0x40000) && + ((dec_dpb_status == H264_DECODE_TIMEOUT) || + (!hw->frmbase_cont_flag && (dec_dpb_status == H264_SEARCH_BUFEMPTY || dec_dpb_status == H264_DECODE_BUFEMPTY) && input_frame_based(vdec)))) + goto pic_done_proc; + if (!hw->frmbase_cont_flag) + release_cur_decoding_buf(hw); + + if (input_frame_based(vdec) || + (READ_VREG(VLD_MEM_VIFIFO_LEVEL) > 0x200)) { + if (h264_debug_flag & + DISABLE_ERROR_HANDLE) { + dpb_print(DECODE_ID(hw), + PRINT_FLAG_ERROR, + "%s decoding error, level 0x%x\n", + __func__, + READ_VREG(VLD_MEM_VIFIFO_LEVEL)); + goto send_again; + } + amvdec_stop(); + vdec->mc_loaded = 0; + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s %s\n", __func__, + (dec_dpb_status == H264_SEARCH_BUFEMPTY) ? + "H264_SEARCH_BUFEMPTY" : + (dec_dpb_status == H264_DECODE_BUFEMPTY) ? + "H264_DECODE_BUFEMPTY" : + (dec_dpb_status == H264_DECODE_TIMEOUT) ? + "H264_DECODE_TIMEOUT" : + "OTHER"); + hw->dec_result = DEC_RESULT_DONE; + + if (dec_dpb_status == H264_SEARCH_BUFEMPTY) + hw->search_dataempty_num++; + else if (dec_dpb_status == H264_DECODE_TIMEOUT) { + hw->decode_timeout_num++; + if (hw->error_proc_policy & 0x4000) { + hw->data_flag |= ERROR_FLAG; + if ((p_H264_Dpb->last_dpb_status == H264_DECODE_TIMEOUT) || + (p_H264_Dpb->last_dpb_status == H264_PIC_DATA_DONE) || + ((p_H264_Dpb->last_dpb_status == H264_SLICE_HEAD_DONE) && + (p_H264_Dpb->mSlice.slice_type != B_SLICE))) { + dpb_print(DECODE_ID(hw), + PRINT_FLAG_ERROR, "%s last dpb status 0x%x need bugmgr reset \n", + p_H264_Dpb->last_dpb_status, __func__); + hw->reset_bufmgr_flag = 1; + } + } + } else if (dec_dpb_status == H264_DECODE_BUFEMPTY) + hw->decode_dataempty_num++; + if (!hw->frmbase_cont_flag) + hw->data_flag |= ERROR_FLAG; + + vdec_schedule_work(&hw->work); + } else { + /* WRITE_VREG(DPB_STATUS_REG, H264_ACTION_INIT); */ +#ifdef DETECT_WRONG_MULTI_SLICE + if (hw->error_proc_policy & 0x10000) { + p_H264_Dpb->mVideo.pre_frame_num = hw->first_pre_frame_num; + } + hw->last_picture_slice_count = hw->cur_picture_slice_count; +#endif + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s DEC_RESULT_AGAIN\n", __func__); +send_again: + hw->dec_result = DEC_RESULT_AGAIN; + vdec_schedule_work(&hw->work); + } + } else if (dec_dpb_status == H264_DATA_REQUEST) { + reset_process_time(hw); + if (input_frame_based(vdec)) { + dpb_print(DECODE_ID(hw), + PRINT_FLAG_VDEC_STATUS, + "%s H264_DATA_REQUEST (%d)\n", + __func__, hw->get_data_count); + hw->dec_result = DEC_RESULT_GET_DATA; + hw->reg_iqidct_control = READ_VREG(IQIDCT_CONTROL); + hw->reg_iqidct_control_init_flag = 1; + hw->get_data_start_time = jiffies; + hw->get_data_count++; + if (hw->get_data_count >= frame_max_data_packet) + goto empty_proc; + vdec_schedule_work(&hw->work); + } else + goto empty_proc; + } else if (dec_dpb_status == H264_DECODE_OVER_SIZE) { + dpb_print(DECODE_ID(hw), 0, + "vmh264 decode oversize !!\n"); + release_cur_decoding_buf(hw); + hw->data_flag |= ERROR_FLAG; + hw->stat |= DECODER_FATAL_ERROR_SIZE_OVERFLOW; + reset_process_time(hw); + hw->dec_result = DEC_RESULT_DONE; + vdec_schedule_work(&hw->work); + return IRQ_HANDLED; + } else if (dec_dpb_status == H264_SEI_DATA_READY) { + int aux_data_len; + aux_data_len = + (READ_VREG(H264_AUX_DATA_SIZE) >> 16) << 4; + + if (aux_data_len > SEI_DATA_SIZE) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_ERROR, + "sei data size more than 4K: %d, discarded it\n", + hw->sei_itu_data_len); + hw->sei_itu_data_len = 0; + } + + if (aux_data_len != 0) { + u8 *trans_data_buf; + u8 *sei_data_buf; + u8 swap_byte; + +#if 0 + dump_aux_buf(hw); +#endif + trans_data_buf = (u8 *)hw->aux_addr; + + if (trans_data_buf[7] == AUX_TAG_SEI) { + int left_len; + + sei_data_buf = (u8 *)hw->sei_data_buf + + hw->sei_data_len; + left_len = SEI_DATA_SIZE - hw->sei_data_len; + if (aux_data_len/2 <= left_len) { + for (i = 0; i < aux_data_len/2; i++) + sei_data_buf[i] + = trans_data_buf[i*2]; + + aux_data_len = aux_data_len / 2; + for (i = 0; i < aux_data_len; i = i+4) { + swap_byte = sei_data_buf[i]; + sei_data_buf[i] + = sei_data_buf[i+3]; + sei_data_buf[i+3] = swap_byte; + + swap_byte = sei_data_buf[i+1]; + sei_data_buf[i+1] + = sei_data_buf[i+2]; + sei_data_buf[i+2] = swap_byte; + } + + for (i = aux_data_len-1; i >= 0; i--) + if (sei_data_buf[i] != 0) + break; + + hw->sei_data_len += i+1; + } else + dpb_print(DECODE_ID(hw), + PRINT_FLAG_ERROR, + "sei data size %d and more than left space: %d, discarded it\n", + hw->sei_itu_data_len, + left_len); + } + } + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_THREAD_EDN); + WRITE_VREG(DPB_STATUS_REG, H264_SEI_DATA_DONE); + + return IRQ_HANDLED; + } + + + /* ucode debug */ + debug_tag = READ_VREG(DEBUG_REG1); + if (debug_tag & 0x10000) { + unsigned short *p = (unsigned short *)hw->lmem_addr; + + dpb_print(DECODE_ID(hw), 0, + "LMEM<tag %x>:\n", debug_tag); + for (i = 0; i < 0x400; i += 4) { + int ii; + if ((i & 0xf) == 0) + dpb_print_cont(DECODE_ID(hw), 0, + "%03x: ", i); + for (ii = 0; ii < 4; ii++) + dpb_print_cont(DECODE_ID(hw), 0, + "%04x ", p[i+3-ii]); + if (((i+ii) & 0xf) == 0) + dpb_print_cont(DECODE_ID(hw), 0, + "\n"); + } + if (((udebug_pause_pos & 0xffff) + == (debug_tag & 0xffff)) && + (udebug_pause_decode_idx == 0 || + udebug_pause_decode_idx == + hw->decode_pic_count) && + (udebug_pause_val == 0 || + udebug_pause_val == READ_VREG(DEBUG_REG2))) { + udebug_pause_pos &= 0xffff; + hw->ucode_pause_pos = udebug_pause_pos; + } + else if (debug_tag & 0x20000) + hw->ucode_pause_pos = 0xffffffff; + if (hw->ucode_pause_pos) + reset_process_time(hw); + else + WRITE_VREG(DEBUG_REG1, 0); + } else if (debug_tag != 0) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_UCODE_EVT, + "dbg%x: %x\n", debug_tag, + READ_VREG(DEBUG_REG2)); + if (((udebug_pause_pos & 0xffff) + == (debug_tag & 0xffff)) && + (udebug_pause_decode_idx == 0 || + udebug_pause_decode_idx == + hw->decode_pic_count) && + (udebug_pause_val == 0 || + udebug_pause_val == READ_VREG(DEBUG_REG2))) { + udebug_pause_pos &= 0xffff; + hw->ucode_pause_pos = udebug_pause_pos; + } + if (hw->ucode_pause_pos) + reset_process_time(hw); + else + WRITE_VREG(DEBUG_REG1, 0); + } + /**/ + return IRQ_HANDLED; +} + +static irqreturn_t vh264_isr(struct vdec_s *vdec, int irq) +{ + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)(vdec->private); + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + + + WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); + + if (!hw) + return IRQ_HANDLED; + + if (hw->eos) + return IRQ_HANDLED; + + p_H264_Dpb->vdec = vdec; + p_H264_Dpb->dec_dpb_status = READ_VREG(DPB_STATUS_REG); + + if (p_H264_Dpb->dec_dpb_status == H264_SLICE_HEAD_DONE || + p_H264_Dpb->dec_dpb_status == H264_CONFIG_REQUEST) { + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_HEAD_DONE); + } + else if (p_H264_Dpb->dec_dpb_status == H264_PIC_DATA_DONE) { + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_PIC_DONE); + } + else if (p_H264_Dpb->dec_dpb_status == H264_SEI_DATA_READY) + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_SEI_DONE); + else if (p_H264_Dpb->dec_dpb_status == H264_AUX_DATA_READY) + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_AUX_DONE); + + dpb_print(DECODE_ID(hw), PRINT_FLAG_UCODE_EVT, + "%s DPB_STATUS_REG: 0x%x, run(%d) last_state (%x) ERROR_STATUS_REG 0x%x, sb (0x%x 0x%x 0x%x) bitcnt 0x%x mby_mbx 0x%x\n", + __func__, + p_H264_Dpb->dec_dpb_status, + run_count[DECODE_ID(hw)], + hw->dec_result, + READ_VREG(ERROR_STATUS_REG), + READ_VREG(VLD_MEM_VIFIFO_LEVEL), + READ_VREG(VLD_MEM_VIFIFO_WP), + READ_VREG(VLD_MEM_VIFIFO_RP), + READ_VREG(VIFF_BIT_CNT), + READ_VREG(MBY_MBX)); + + ATRACE_COUNTER("V_ST_DEC-decode_state", p_H264_Dpb->dec_dpb_status); + + if (p_H264_Dpb->dec_dpb_status == H264_WRRSP_REQUEST) { + if (hw->mmu_enable) + hevc_sao_wait_done(hw); + WRITE_VREG(DPB_STATUS_REG, H264_WRRSP_DONE); + return IRQ_HANDLED; + } + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_ISR_END); + return IRQ_WAKE_THREAD; + +} + +static void timeout_process(struct vdec_h264_hw_s *hw) +{ + struct vdec_s *vdec = hw_to_vdec(hw); + + /* + * In this very timeout point,the vh264_work arrives, + * or in some cases the system become slow, then come + * this second timeout. In both cases we return. + */ + if (work_pending(&hw->work) || + work_busy(&hw->work) || + work_busy(&hw->timeout_work) || + work_pending(&hw->timeout_work)) { + pr_err("%s h264[%d] work pending, do nothing.\n",__func__, vdec->id); + return; + } + + hw->timeout_num++; + amvdec_stop(); + vdec->mc_loaded = 0; + if (hw->mmu_enable) { + hevc_set_frame_done(hw); + hevc_sao_wait_done(hw); + } + dpb_print(DECODE_ID(hw), + PRINT_FLAG_ERROR, "%s decoder timeout, DPB_STATUS_REG 0x%x\n", __func__, READ_VREG(DPB_STATUS_REG)); + release_cur_decoding_buf(hw); + hw->dec_result = DEC_RESULT_TIMEOUT; + hw->data_flag |= ERROR_FLAG; + + if (work_pending(&hw->work)) + return; + vdec_schedule_work(&hw->timeout_work); +} + +static void dump_bufspec(struct vdec_h264_hw_s *hw, + const char *caller) +{ + int i; + dpb_print(DECODE_ID(hw), 0, + "%s in %s:\n", __func__, caller); + for (i = 0; i < BUFSPEC_POOL_SIZE; i++) { + if (hw->buffer_spec[i].used == -1) + continue; + dpb_print(DECODE_ID(hw), 0, + "bufspec (%d): used %d adr 0x%x(%lx) canvas(%d) vf_ref(%d) ", + i, hw->buffer_spec[i].used, + hw->buffer_spec[i].buf_adr, + hw->buffer_spec[i].cma_alloc_addr, + hw->buffer_spec[i].canvas_pos, + hw->buffer_spec[i].vf_ref + ); +#ifdef CONFIG_AM_VDEC_DV + dpb_print_cont(DECODE_ID(hw), 0, + "dv_el_exist %d", + hw->buffer_spec[i].dv_enhance_exist + ); +#endif + dpb_print_cont(DECODE_ID(hw), 0, "\n"); + } + +} + +static void vmh264_dump_state(struct vdec_s *vdec) +{ + struct vdec_h264_hw_s *hw = + (struct vdec_h264_hw_s *)(vdec->private); + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + dpb_print(DECODE_ID(hw), 0, + "====== %s\n", __func__); + dpb_print(DECODE_ID(hw), 0, + "width/height (%d/%d), num_reorder_frames %d dec_dpb_size %d dpb size(bufspec count) %d max_reference_size(collocate count) %d i_only %d signal_type 0x%x send_err %d\n", + hw->frame_width, + hw->frame_height, + hw->num_reorder_frames, + hw->dpb.dec_dpb_size, + hw->dpb.mDPB.size, + hw->max_reference_size, + hw->i_only, + hw->video_signal_type, + hw->send_error_frame_flag + ); + + dpb_print(DECODE_ID(hw), 0, + "is_framebase(%d), eos %d, state 0x%x, dec_result 0x%x dec_frm %d disp_frm %d run %d not_run_ready %d input_empty %d bufmgr_reset_cnt %d error_frame_count = %d, drop_frame_count = %d\n", + input_frame_based(vdec), + hw->eos, + hw->stat, + hw->dec_result, + decode_frame_count[DECODE_ID(hw)], + display_frame_count[DECODE_ID(hw)], + run_count[DECODE_ID(hw)], + not_run_ready[DECODE_ID(hw)], + input_empty[DECODE_ID(hw)], + hw->reset_bufmgr_count, + hw->gvs.error_frame_count, + hw->gvs.drop_frame_count + ); + +#ifdef DETECT_WRONG_MULTI_SLICE + dpb_print(DECODE_ID(hw), 0, + "MULTI_SLICE_DETECT (check_count %d slice_count %d cur_slice_count %d flag %d)\n", + hw->multi_slice_pic_check_count, + hw->picture_slice_count, + hw->cur_picture_slice_count, + hw->multi_slice_pic_flag); +#endif + if (!hw->is_used_v4l && vf_get_receiver(vdec->vf_provider_name)) { + enum receviver_start_e state = + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_QUREY_STATE, + NULL); + dpb_print(DECODE_ID(hw), 0, + "\nreceiver(%s) state %d\n", + vdec->vf_provider_name, + state); + } + + dpb_print(DECODE_ID(hw), 0, + "%s, newq(%d/%d), dispq(%d/%d) vf prepare/get/put (%d/%d/%d), free_spec(%d), initdon(%d), used_size(%d/%d), unused_fr_dpb(%d) fast_output_enable %x \n", + __func__, + kfifo_len(&hw->newframe_q), + VF_POOL_SIZE, + kfifo_len(&hw->display_q), + VF_POOL_SIZE, + hw->vf_pre_count, + hw->vf_get_count, + hw->vf_put_count, + have_free_buf_spec(vdec), + p_H264_Dpb->mDPB.init_done, + p_H264_Dpb->mDPB.used_size, p_H264_Dpb->mDPB.size, + is_there_unused_frame_from_dpb(&p_H264_Dpb->mDPB), + p_H264_Dpb->fast_output_enable + ); + + dump_dpb(&p_H264_Dpb->mDPB, 1); + dump_pic(p_H264_Dpb); + dump_bufspec(hw, __func__); + + dpb_print(DECODE_ID(hw), 0, + "DPB_STATUS_REG=0x%x\n", + READ_VREG(DPB_STATUS_REG)); + dpb_print(DECODE_ID(hw), 0, + "MPC_E=0x%x\n", + READ_VREG(MPC_E)); + dpb_print(DECODE_ID(hw), 0, + "H264_DECODE_MODE=0x%x\n", + READ_VREG(H264_DECODE_MODE)); + dpb_print(DECODE_ID(hw), 0, + "MBY_MBX=0x%x\n", + READ_VREG(MBY_MBX)); + dpb_print(DECODE_ID(hw), 0, + "H264_DECODE_SIZE=0x%x\n", + READ_VREG(H264_DECODE_SIZE)); + dpb_print(DECODE_ID(hw), 0, + "VIFF_BIT_CNT=0x%x\n", + READ_VREG(VIFF_BIT_CNT)); + dpb_print(DECODE_ID(hw), 0, + "VLD_MEM_VIFIFO_LEVEL=0x%x\n", + READ_VREG(VLD_MEM_VIFIFO_LEVEL)); + dpb_print(DECODE_ID(hw), 0, + "VLD_MEM_VIFIFO_WP=0x%x\n", + READ_VREG(VLD_MEM_VIFIFO_WP)); + dpb_print(DECODE_ID(hw), 0, + "VLD_MEM_VIFIFO_RP=0x%x\n", + READ_VREG(VLD_MEM_VIFIFO_RP)); + dpb_print(DECODE_ID(hw), 0, + "PARSER_VIDEO_RP=0x%x\n", + STBUF_READ(&vdec->vbuf, get_rp)); + dpb_print(DECODE_ID(hw), 0, + "PARSER_VIDEO_WP=0x%x\n", + STBUF_READ(&vdec->vbuf, get_wp)); + + if (input_frame_based(vdec) && + dpb_is_debug(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA) + ) { + int jj; + if (hw->chunk && hw->chunk->block && + hw->chunk->size > 0) { + u8 *data = NULL; + + if (!hw->chunk->block->is_mapped) + data = codec_mm_vmap(hw->chunk->block->start + + hw->chunk->offset, hw->chunk->size); + else + data = ((u8 *)hw->chunk->block->start_virt) + + hw->chunk->offset; + + dpb_print(DECODE_ID(hw), 0, + "frame data size 0x%x\n", + hw->chunk->size); + for (jj = 0; jj < hw->chunk->size; jj++) { + if ((jj & 0xf) == 0) + dpb_print(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA, + "%06x:", jj); + dpb_print_cont(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA, + "%02x ", data[jj]); + if (((jj + 1) & 0xf) == 0) + dpb_print_cont(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA, + "\n"); + } + + if (!hw->chunk->block->is_mapped) + codec_mm_unmap_phyaddr(data); + } + } +} + + +static void check_timer_func(struct timer_list *timer) +{ + struct vdec_h264_hw_s *hw = container_of(timer, + struct vdec_h264_hw_s, check_timer); + struct vdec_s *vdec = hw_to_vdec(hw); + int error_skip_frame_count = error_skip_count & 0xfff; + unsigned int timeout_val = decode_timeout_val; + if (timeout_val != 0 && + hw->no_error_count < error_skip_frame_count) + timeout_val = errordata_timeout_val; + if ((h264_debug_cmd & 0x100) != 0 && + DECODE_ID(hw) == (h264_debug_cmd & 0xff)) { + hw->dec_result = DEC_RESULT_DONE; + vdec_schedule_work(&hw->work); + pr_info("vdec %d is forced to be disconnected\n", + h264_debug_cmd & 0xff); + h264_debug_cmd = 0; + return; + } + if ((h264_debug_cmd & 0x200) != 0 && + DECODE_ID(hw) == (h264_debug_cmd & 0xff)) { + pr_debug("vdec %d is forced to reset bufmgr\n", + h264_debug_cmd & 0xff); + hw->reset_bufmgr_flag = 1; + h264_debug_cmd = 0; + return; + } + + if (vdec->next_status == VDEC_STATUS_DISCONNECTED && + !hw->is_used_v4l) { + hw->dec_result = DEC_RESULT_FORCE_EXIT; + vdec_schedule_work(&hw->work); + pr_debug("vdec requested to be disconnected\n"); + return; + } + + if (radr != 0) { + if (rval != 0) { + WRITE_VREG(radr, rval); + pr_info("WRITE_VREG(%x,%x)\n", radr, rval); + } else + pr_info("READ_VREG(%x)=%x\n", radr, READ_VREG(radr)); + rval = 0; + radr = 0; + } + + if (((h264_debug_flag & DISABLE_ERROR_HANDLE) == 0) && + (timeout_val > 0) && + (hw->start_process_time > 0) && + ((1000 * (jiffies - hw->start_process_time) / HZ) + > timeout_val) + ) { + u32 dpb_status = READ_VREG(DPB_STATUS_REG); + u32 mby_mbx = READ_VREG(MBY_MBX); + if ((dpb_status == H264_ACTION_DECODE_NEWPIC) || + (dpb_status == H264_ACTION_DECODE_SLICE) || + (dpb_status == H264_SEI_DATA_DONE) || + (dpb_status == H264_STATE_SEARCH_HEAD) || + (dpb_status == H264_SLICE_HEAD_DONE) || + (dpb_status == H264_SEI_DATA_READY)) { + if (h264_debug_flag & DEBUG_TIMEOUT_DEC_STAT) + pr_debug("%s dpb_status = 0x%x last_mby_mbx = %u mby_mbx = %u\n", + __func__, dpb_status, hw->last_mby_mbx, mby_mbx); + + if (hw->last_mby_mbx == mby_mbx) { + if (hw->decode_timeout_count > 0) + hw->decode_timeout_count--; + if (hw->decode_timeout_count == 0) + { + reset_process_time(hw); + timeout_process(hw); + } + } else + start_process_time(hw); + } else if (is_in_parsing_state(dpb_status)) { + if (hw->last_vld_level == + READ_VREG(VLD_MEM_VIFIFO_LEVEL)) { + if (hw->decode_timeout_count > 0) + hw->decode_timeout_count--; + if (hw->decode_timeout_count == 0) + { + reset_process_time(hw); + timeout_process(hw); + } + } + } + hw->last_vld_level = + READ_VREG(VLD_MEM_VIFIFO_LEVEL); + hw->last_mby_mbx = mby_mbx; + } + + if ((hw->ucode_pause_pos != 0) && + (hw->ucode_pause_pos != 0xffffffff) && + udebug_pause_pos != hw->ucode_pause_pos) { + hw->ucode_pause_pos = 0; + WRITE_VREG(DEBUG_REG1, 0); + } + + mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL); +} + +static int dec_status(struct vdec_s *vdec, struct vdec_info *vstatus) +{ + u32 ar, ar_tmp; + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; + + if (!hw) + return -1; + + vstatus->frame_width = hw->frame_width; + vstatus->frame_height = hw->frame_height; + if (hw->error_frame_width && + hw->error_frame_height) { + vstatus->frame_width = hw->error_frame_width; + vstatus->frame_height = hw->error_frame_height; + } + if (hw->frame_dur != 0) { + vstatus->frame_dur = hw->frame_dur; + vstatus->frame_rate = ((96000 * 10 / hw->frame_dur) % 10) < 5 ? + 96000 / hw->frame_dur : (96000 / hw->frame_dur +1); + } + else + vstatus->frame_rate = -1; + vstatus->error_count = hw->gvs.error_frame_count; + vstatus->status = hw->stat; + if (hw->h264_ar == 0x3ff) + ar_tmp = (0x100 * + hw->frame_height * hw->height_aspect_ratio) / + (hw->frame_width * hw->width_aspect_ratio); + else + ar_tmp = hw->h264_ar; + ar = min_t(u32, + ar_tmp, + DISP_RATIO_ASPECT_RATIO_MAX); + vstatus->ratio_control = + ar << DISP_RATIO_ASPECT_RATIO_BIT; + + vstatus->error_frame_count = hw->gvs.error_frame_count; + vstatus->drop_frame_count = hw->gvs.drop_frame_count; + vstatus->frame_count = decode_frame_count[DECODE_ID(hw)]; + vstatus->i_decoded_frames = hw->gvs.i_decoded_frames; + vstatus->i_lost_frames = hw->gvs.i_lost_frames; + vstatus->i_concealed_frames = hw->gvs.i_concealed_frames; + vstatus->p_decoded_frames = hw->gvs.p_decoded_frames; + vstatus->p_lost_frames = hw->gvs.p_lost_frames; + vstatus->p_concealed_frames = hw->gvs.p_concealed_frames; + vstatus->b_decoded_frames = hw->gvs.b_decoded_frames; + vstatus->b_lost_frames = hw->gvs.b_lost_frames; + vstatus->b_concealed_frames = hw->gvs.b_concealed_frames; + snprintf(vstatus->vdec_name, sizeof(vstatus->vdec_name), + "%s-%02d", DRIVER_NAME, hw->id); + + return 0; +} + +static int vh264_hw_ctx_restore(struct vdec_h264_hw_s *hw) +{ + int i, j; + struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx; + hw->frmbase_cont_flag = 0; + + /* if (hw->init_flag == 0) { */ + if (h264_debug_flag & 0x40000000) { + /* if (1) */ + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s, reset register\n", __func__); + + while (READ_VREG(DCAC_DMA_CTRL) & 0x8000) + ; + while (READ_VREG(LMEM_DMA_CTRL) & 0x8000) + ; /* reg address is 0x350 */ + +#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */ + WRITE_VREG(DOS_SW_RESET0, (1<<7) | (1<<6) | (1<<4)); + WRITE_VREG(DOS_SW_RESET0, 0); + + READ_VREG(DOS_SW_RESET0); + READ_VREG(DOS_SW_RESET0); + READ_VREG(DOS_SW_RESET0); + + WRITE_VREG(DOS_SW_RESET0, (1<<7) | (1<<6) | (1<<4)); + WRITE_VREG(DOS_SW_RESET0, 0); + + WRITE_VREG(DOS_SW_RESET0, (1<<9) | (1<<8)); + WRITE_VREG(DOS_SW_RESET0, 0); + + READ_VREG(DOS_SW_RESET0); + READ_VREG(DOS_SW_RESET0); + READ_VREG(DOS_SW_RESET0); + +#else + WRITE_RESET_REG(RESET0_REGISTER, + RESET_IQIDCT | RESET_MC | RESET_VLD_PART); + READ_RESET_REG(RESET0_REGISTER); + WRITE_RESET_REG(RESET0_REGISTER, + RESET_IQIDCT | RESET_MC | RESET_VLD_PART); + + WRITE_RESET_REG(RESET2_REGISTER, RESET_PIC_DC | RESET_DBLK); +#endif + WRITE_VREG(POWER_CTL_VLD, + READ_VREG(POWER_CTL_VLD) | (0 << 10) | + (1 << 9) | (1 << 6)); + } else { + /* WRITE_VREG(POWER_CTL_VLD, + * READ_VREG(POWER_CTL_VLD) | (0 << 10) | (1 << 9) ); + */ + WRITE_VREG(POWER_CTL_VLD, + READ_VREG(POWER_CTL_VLD) | + (0 << 10) | (1 << 9) | (1 << 6)); + } + /* disable PSCALE for hardware sharing */ + WRITE_VREG(PSCALE_CTRL, 0); + + /* clear mailbox interrupt */ + WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); + + /* enable mailbox interrupt */ + WRITE_VREG(ASSIST_MBOX1_MASK, 1); + +#ifdef NV21 + SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1<<17); +#endif + + /* cbcr_merge_swap_en */ + if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T7) { + if ((v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21) || + (v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21M)) + CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 16); + else + SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 16); + } else { + if ((v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21) || + (v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21M)) + SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 16); + else + CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 16); + } + + SET_VREG_MASK(MDEC_PIC_DC_CTRL, 0xbf << 24); + CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 0xbf << 24); + + CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 31); + if (hw->mmu_enable) { + SET_VREG_MASK(MDEC_PIC_DC_MUX_CTRL, 1<<31); + /* sw reset to extif hardware */ + SET_VREG_MASK(MDEC_EXTIF_CFG1, 1<<30); + CLEAR_VREG_MASK(MDEC_EXTIF_CFG1, 1<<30); + } else { + CLEAR_VREG_MASK(MDEC_PIC_DC_MUX_CTRL, 1 << 31); + WRITE_VREG(MDEC_EXTIF_CFG1, 0); + } + + +#if 1 /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ + /* pr_info("vh264 meson8 prot init\n"); */ + WRITE_VREG(MDEC_PIC_DC_THRESH, 0x404038aa); +#endif + +#ifdef VDEC_DW + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_T7) { + if (IS_VDEC_DW(hw)) { + u32 data = ((1 << 30) |(1 << 0) |(1 << 8)); + + if (IS_VDEC_DW(hw) == 2) + data |= (1 << 9); + WRITE_VREG(MDEC_DOUBLEW_CFG0, data); /* Double Write Enable*/ + } + } +#endif + if (hw->dpb.mDPB.size > 0) { + WRITE_VREG(AV_SCRATCH_7, (hw->max_reference_size << 24) | + (hw->dpb.mDPB.size << 16) | + (hw->dpb.mDPB.size << 8)); + + for (j = 0; j < hw->dpb.mDPB.size; j++) { + i = get_buf_spec_by_canvas_pos(hw, j); + if (i < 0) + break; + + if (!hw->mmu_enable && + hw->buffer_spec[i].cma_alloc_addr) + config_decode_canvas(hw, i); + if (hw->mmu_enable && hw->double_write_mode) + config_decode_canvas_ex(hw, i); + } + } else { + WRITE_VREG(AV_SCRATCH_0, 0); + WRITE_VREG(AV_SCRATCH_9, 0); + } + + if (hw->init_flag == 0) + WRITE_VREG(DPB_STATUS_REG, 0); + else + WRITE_VREG(DPB_STATUS_REG, H264_ACTION_DECODE_START); + + WRITE_VREG(FRAME_COUNTER_REG, hw->decode_pic_count); + WRITE_VREG(AV_SCRATCH_8, hw->buf_offset); + if (!tee_enabled()) + WRITE_VREG(AV_SCRATCH_G, hw->mc_dma_handle); + + /* hw->error_recovery_mode = (error_recovery_mode != 0) ? + * error_recovery_mode : error_recovery_mode_in; + */ + /* WRITE_VREG(AV_SCRATCH_F, + * (READ_VREG(AV_SCRATCH_F) & 0xffffffc3) ); + */ + WRITE_VREG(AV_SCRATCH_F, (hw->save_reg_f & 0xffffffc3) | + ((error_recovery_mode_in & 0x1) << 4)); + /*if (hw->ucode_type == UCODE_IP_ONLY_PARAM) + SET_VREG_MASK(AV_SCRATCH_F, 1 << 6); + else*/ + CLEAR_VREG_MASK(AV_SCRATCH_F, 1 << 6); + + WRITE_VREG(LMEM_DUMP_ADR, (u32)hw->lmem_phy_addr); +#if 1 /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ + WRITE_VREG(MDEC_PIC_DC_THRESH, 0x404038aa); +#endif + + WRITE_VREG(DEBUG_REG1, 0); + WRITE_VREG(DEBUG_REG2, 0); + + /*Because CSD data is not found at playback start, + the IQIDCT_CONTROL register is not saved, + the initialized value 0x200 of IQIDCT_CONTROL is set*/ + if (hw->init_flag && (hw->reg_iqidct_control_init_flag == 0)) + WRITE_VREG(IQIDCT_CONTROL, 0x200); + + if (hw->reg_iqidct_control) + WRITE_VREG(IQIDCT_CONTROL, hw->reg_iqidct_control); + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "IQIDCT_CONTROL = 0x%x\n", READ_VREG(IQIDCT_CONTROL)); + + if (hw->reg_vcop_ctrl_reg) + WRITE_VREG(VCOP_CTRL_REG, hw->reg_vcop_ctrl_reg); + if (hw->vld_dec_control) + WRITE_VREG(VLD_DECODE_CONTROL, hw->vld_dec_control); + return 0; +} + +static int vmh264_set_trickmode(struct vdec_s *vdec, unsigned long trickmode) +{ + struct vdec_h264_hw_s *hw = + (struct vdec_h264_hw_s *)vdec->private; + if (i_only_flag & 0x100) + return 0; + if (trickmode == TRICKMODE_I) + hw->i_only = 0x3; + else if (trickmode == TRICKMODE_NONE) + hw->i_only = 0x0; + return 0; +} + +static unsigned char amvdec_enable_flag; +static void vh264_local_init(struct vdec_h264_hw_s *hw, bool is_reset) +{ + int i; + hw->init_flag = 0; + hw->first_sc_checked= 0; + hw->eos = 0; + hw->valve_count = 0; + hw->config_bufmgr_done = 0; + hw->start_process_time = 0; + hw->has_i_frame = 0; + hw->no_error_count = 0xfff; + hw->no_error_i_count = 0xf; + + hw->dec_flag = 0; + hw->data_flag = 0; + hw->skip_frame_count = 0; + hw->reg_iqidct_control = 0; + hw->reg_iqidct_control_init_flag = 0; + hw->reg_vcop_ctrl_reg = 0; + hw->reg_rv_ai_mb_count = 0; + hw->vld_dec_control = 0; + hw->decode_timeout_count = 0; + hw->no_mem_count = 0; + hw->vh264_ratio = hw->vh264_amstream_dec_info.ratio; + /* vh264_ratio = 0x100; */ + + hw->vh264_rotation = (((unsigned long) + hw->vh264_amstream_dec_info.param) >> 16) & 0xffff; + + hw->frame_prog = 0; + hw->frame_width = hw->vh264_amstream_dec_info.width; + hw->frame_height = hw->vh264_amstream_dec_info.height; + hw->frame_dur = hw->vh264_amstream_dec_info.rate; + hw->pts_outside = ((unsigned long) + hw->vh264_amstream_dec_info.param) & 0x01; + hw->sync_outside = ((unsigned long) + hw->vh264_amstream_dec_info.param & 0x02) >> 1; + hw->use_idr_framerate = ((unsigned long) + hw->vh264_amstream_dec_info.param & 0x04) >> 2; + hw->max_refer_buf = !(((unsigned long) + hw->vh264_amstream_dec_info.param & 0x10) >> 4); + if (hw->frame_dur < 96000/960) { + /*more than 960fps,it should not be a correct value, + *give default 30fps + */ + hw->frame_dur = 96000/30; + } + + hw->unstable_pts = (((unsigned long) hw->vh264_amstream_dec_info.param & 0x40) >> 6); + + hw->first_i_policy = first_i_policy; + + pr_info("H264 sysinfo: %dx%d duration=%d, pts_outside=%d\n", + hw->frame_width, hw->frame_height, hw->frame_dur, hw->pts_outside); + pr_debug("sync_outside=%d, use_idr_framerate=%d, is_used_v4l: %d\n", + hw->sync_outside, hw->use_idr_framerate, hw->is_used_v4l); + + if (i_only_flag & 0x100) + hw->i_only = i_only_flag & 0xff; + if (hw->i_only) + hw->dpb.first_insert_frame = FirstInsertFrm_SKIPDONE; + + if ((unsigned long) hw->vh264_amstream_dec_info.param + & 0x08) + hw->no_poc_reorder_flag = 1; + + error_recovery_mode_in = 1; /*ucode control?*/ + if (hw->error_proc_policy & 0x80000000) + hw->send_error_frame_flag = hw->error_proc_policy & 0x1; + else if ((unsigned long) hw->vh264_amstream_dec_info.param & 0x20) + hw->send_error_frame_flag = 0; /*Don't display mark err frames*/ + + if (!is_reset) { + INIT_KFIFO(hw->display_q); + INIT_KFIFO(hw->newframe_q); + + for (i = 0; i < VF_POOL_SIZE; i++) { + const struct vframe_s *vf = &(hw->vfpool[hw->cur_pool][i]); + hw->vfpool[hw->cur_pool][i].index = -1; /* VF_BUF_NUM; */ + hw->vfpool[hw->cur_pool][i].bufWidth = 1920; + kfifo_put(&hw->newframe_q, vf); + } + } + + hw->duration_from_pts_done = 0; + + hw->p_last_vf = NULL; + hw->vh264_stream_switching_state = SWITCHING_STATE_OFF; + hw->hevc_cur_buf_idx = 0xffff; + + init_waitqueue_head(&hw->wait_q); + + return; +} + +static s32 vh264_init(struct vdec_h264_hw_s *hw) +{ + int size = -1; + int fw_size = 0x1000 * 16; + int fw_mmu_size = 0x1000 * 16; + struct firmware_s *fw = NULL, *fw_mmu = NULL; + + /* int trickmode_fffb = 0; */ + + /* pr_info("\nvh264_init\n"); */ + /* init_timer(&hw->recycle_timer); */ + + /* timer init */ + timer_setup(&hw->check_timer, check_timer_func, 0); + hw->check_timer.expires = jiffies + CHECK_INTERVAL; + + /* add_timer(&hw->check_timer); */ + hw->stat |= STAT_TIMER_ARM; + hw->stat |= STAT_ISR_REG; + + mutex_init(&hw->chunks_mutex); + vh264_local_init(hw, false); + INIT_WORK(&hw->work, vh264_work); + INIT_WORK(&hw->notify_work, vh264_notify_work); + INIT_WORK(&hw->timeout_work, vh264_timeout_work); +#ifdef MH264_USERDATA_ENABLE + INIT_WORK(&hw->user_data_ready_work, user_data_ready_notify_work); +#endif + + /*if (!amvdec_enable_flag) { + amvdec_enable_flag = true; + amvdec_enable(); + if (hw->mmu_enable) + amhevc_enable(); + }*/ + if (hw->mmu_enable) { + + hw->frame_mmu_map_addr = + dma_alloc_coherent(amports_get_dma_device(), + FRAME_MMU_MAP_SIZE, + &hw->frame_mmu_map_phy_addr, GFP_KERNEL); + if (hw->frame_mmu_map_addr == NULL) { + pr_err("%s: failed to alloc count_buffer\n", __func__); + return -ENOMEM; + } + } + + fw = vmalloc(sizeof(struct firmware_s) + fw_size); + if (IS_ERR_OR_NULL(fw)) + return -ENOMEM; + + size = get_firmware_data(VIDEO_DEC_H264_MULTI, fw->data); + if (size < 0) { + pr_err("get firmware fail.\n"); + vfree(fw); + return -1; + } + + fw->len = size; + hw->fw = fw; + + if (hw->mmu_enable) { + fw_mmu = vmalloc(sizeof(struct firmware_s) + fw_mmu_size); + if (IS_ERR_OR_NULL(fw_mmu)) + return -ENOMEM; + + size = get_firmware_data(VIDEO_DEC_H264_MULTI_MMU, fw_mmu->data); + if (size < 0) { + pr_err("get mmu fw fail.\n"); + vfree(fw_mmu); + return -1; + } + + fw_mmu->len = size; + hw->fw_mmu = fw_mmu; + } + + if (!tee_enabled()) { + /* -- ucode loading (amrisc and swap code) */ + hw->mc_cpu_addr = + dma_alloc_coherent(amports_get_dma_device(), MC_TOTAL_SIZE, + &hw->mc_dma_handle, GFP_KERNEL); + if (!hw->mc_cpu_addr) { + amvdec_enable_flag = false; + amvdec_disable(); + hw->vdec_pg_enable_flag = 0; + if (hw->mmu_enable) + amhevc_disable(); + pr_info("vh264_init: Can not allocate mc memory.\n"); + return -ENOMEM; + } + + /*pr_info("264 ucode swap area: phyaddr %p, cpu vaddr %p\n", + (void *)hw->mc_dma_handle, hw->mc_cpu_addr); + */ + + /*ret = amvdec_loadmc_ex(VFORMAT_H264, NULL, buf);*/ + + /*header*/ + memcpy((u8 *) hw->mc_cpu_addr + MC_OFFSET_HEADER, + fw->data + 0x4000, MC_SWAP_SIZE); + /*data*/ + memcpy((u8 *) hw->mc_cpu_addr + MC_OFFSET_DATA, + fw->data + 0x2000, MC_SWAP_SIZE); + /*mmco*/ + memcpy((u8 *) hw->mc_cpu_addr + MC_OFFSET_MMCO, + fw->data + 0x6000, MC_SWAP_SIZE); + /*list*/ + memcpy((u8 *) hw->mc_cpu_addr + MC_OFFSET_LIST, + fw->data + 0x3000, MC_SWAP_SIZE); + /*slice*/ + memcpy((u8 *) hw->mc_cpu_addr + MC_OFFSET_SLICE, + fw->data + 0x5000, MC_SWAP_SIZE); + /*main*/ + memcpy((u8 *) hw->mc_cpu_addr + MC_OFFSET_MAIN, + fw->data, 0x2000); + /*data*/ + memcpy((u8 *) hw->mc_cpu_addr + MC_OFFSET_MAIN + 0x2000, + fw->data + 0x2000, 0x1000); + /*slice*/ + memcpy((u8 *) hw->mc_cpu_addr + MC_OFFSET_MAIN + 0x3000, + fw->data + 0x5000, 0x1000); + } + +#if 1 /* #ifdef BUFFER_MGR_IN_C */ + hw->lmem_addr = (dma_addr_t)dma_alloc_coherent(amports_get_dma_device(), + PAGE_SIZE, (dma_addr_t *)&hw->lmem_phy_addr, GFP_KERNEL); + + if (hw->lmem_addr == 0) { + pr_err("%s: failed to alloc lmem buffer\n", __func__); + return -1; + } + pr_debug("%s, phy_addr=%lx vaddr=%p\n", + __func__, hw->lmem_phy_addr, (void *)hw->lmem_addr); + + if (prefix_aux_buf_size > 0 || + suffix_aux_buf_size > 0) { + u32 aux_buf_size; + hw->prefix_aux_size = AUX_BUF_ALIGN(prefix_aux_buf_size); + hw->suffix_aux_size = AUX_BUF_ALIGN(suffix_aux_buf_size); + aux_buf_size = hw->prefix_aux_size + hw->suffix_aux_size; + hw->aux_addr = dma_alloc_coherent(amports_get_dma_device(), + aux_buf_size, &hw->aux_phy_addr, + GFP_KERNEL); + if (hw->aux_addr == NULL) { + pr_err("%s: failed to alloc rpm buffer\n", __func__); + return -1; + } + + hw->sei_data_buf = kmalloc(SEI_DATA_SIZE, GFP_KERNEL); + if (hw->sei_data_buf == NULL) { + pr_err("%s: failed to alloc sei itu data buffer\n", + __func__); + return -1; + } + hw->sei_itu_data_buf = kmalloc(SEI_ITU_DATA_SIZE, GFP_KERNEL); + if (hw->sei_itu_data_buf == NULL) { + pr_err("%s: failed to alloc sei itu data buffer\n", + __func__); + dma_free_coherent(amports_get_dma_device(), + hw->prefix_aux_size + hw->suffix_aux_size, hw->aux_addr, + hw->aux_phy_addr); + hw->aux_addr = NULL; + kfree(hw->sei_data_buf); + hw->sei_data_buf = NULL; + + return -1; + } + + if (NULL == hw->sei_user_data_buffer) { + hw->sei_user_data_buffer = kmalloc(USER_DATA_SIZE, + GFP_KERNEL); + if (!hw->sei_user_data_buffer) { + pr_info("%s: Can not allocate sei_data_buffer\n", + __func__); + dma_free_coherent(amports_get_dma_device(), + hw->prefix_aux_size + hw->suffix_aux_size, hw->aux_addr, + hw->aux_phy_addr); + hw->aux_addr = NULL; + kfree(hw->sei_data_buf); + hw->sei_data_buf = NULL; + kfree(hw->sei_itu_data_buf); + hw->sei_itu_data_buf = NULL; + + return -1; + } + hw->sei_user_data_wp = 0; + } + } +/* BUFFER_MGR_IN_C */ +#endif + hw->stat |= STAT_MC_LOAD; + + /* add memory barrier */ + wmb(); + + return 0; +} + +static int vh264_stop(struct vdec_h264_hw_s *hw) +{ + if (hw->stat & STAT_VDEC_RUN) { + amvdec_stop(); + hw->stat &= ~STAT_VDEC_RUN; + } +#ifdef VDEC_DW + WRITE_VREG(MDEC_DOUBLEW_CFG0, 0); + WRITE_VREG(MDEC_DOUBLEW_CFG1, 0); +#endif +#ifdef MH264_USERDATA_ENABLE + cancel_work_sync(&hw->user_data_ready_work); +#endif + cancel_work_sync(&hw->notify_work); + cancel_work_sync(&hw->timeout_work); + cancel_work_sync(&hw->work); + + if (hw->stat & STAT_MC_LOAD) { + if (hw->mc_cpu_addr != NULL) { + dma_free_coherent(amports_get_dma_device(), + MC_TOTAL_SIZE, hw->mc_cpu_addr, + hw->mc_dma_handle); + hw->mc_cpu_addr = NULL; + } + if (hw->frame_mmu_map_addr != NULL) { + dma_free_coherent(amports_get_dma_device(), + FRAME_MMU_MAP_SIZE, hw->frame_mmu_map_addr, + hw->frame_mmu_map_phy_addr); + hw->frame_mmu_map_addr = NULL; + } + + } + if (hw->stat & STAT_ISR_REG) { + vdec_free_irq(VDEC_IRQ_1, (void *)hw); + hw->stat &= ~STAT_ISR_REG; + } + if (hw->lmem_addr) { + dma_free_coherent(amports_get_dma_device(), + PAGE_SIZE, (void *)hw->lmem_addr, + hw->lmem_phy_addr); + hw->lmem_addr = 0; + } + + if (hw->aux_addr) { + dma_free_coherent(amports_get_dma_device(), + hw->prefix_aux_size + hw->suffix_aux_size, hw->aux_addr, + hw->aux_phy_addr); + hw->aux_addr = NULL; + } + if (hw->sei_data_buf != NULL) { + kfree(hw->sei_data_buf); + hw->sei_data_buf = NULL; + } + if (hw->sei_itu_data_buf != NULL) { + kfree(hw->sei_itu_data_buf); + hw->sei_itu_data_buf = NULL; + } + if (hw->sei_user_data_buffer != NULL) { + kfree(hw->sei_user_data_buffer); + hw->sei_user_data_buffer = NULL; + } + /* amvdec_disable(); */ + + vfree(hw->fw); + hw->fw = NULL; + + if (hw->mmu_enable) { + vfree(hw->fw_mmu); + hw->fw_mmu = NULL; + } + + dpb_print(DECODE_ID(hw), 0, + "%s\n", + __func__); + return 0; +} + +static void wait_vmh264_search_done(struct vdec_h264_hw_s *hw) +{ + u32 vld_rp = READ_VREG(VLD_MEM_VIFIFO_RP); + int count = 0; + do { + usleep_range(100, 500); + if (vld_rp == READ_VREG(VLD_MEM_VIFIFO_RP)) + break; + if (count > 2000) { + dpb_print(DECODE_ID(hw), + PRINT_FLAG_ERROR, "%s timeout count %d vld_rp 0x%x VLD_MEM_VIFIFO_RP 0x%x\n", + __func__, count, vld_rp, READ_VREG(VLD_MEM_VIFIFO_RP)); + break; + } else + vld_rp = READ_VREG(VLD_MEM_VIFIFO_RP); + count++; + } while (1); +} + +static void vh264_notify_work(struct work_struct *work) +{ + struct vdec_h264_hw_s *hw = container_of(work, + struct vdec_h264_hw_s, notify_work); + struct vdec_s *vdec = hw_to_vdec(hw); + + if (hw->is_used_v4l) + return; + + if (vdec->fr_hint_state == VDEC_NEED_HINT) { + vf_notify_receiver(vdec->vf_provider_name, + VFRAME_EVENT_PROVIDER_FR_HINT, + (void *)((unsigned long)hw->frame_dur)); + vdec->fr_hint_state = VDEC_HINTED; + } + + return; +} + +#ifdef MH264_USERDATA_ENABLE +static void vmh264_reset_udr_mgr(struct vdec_h264_hw_s *hw) +{ + hw->wait_for_udr_send = 0; + hw->sei_itu_data_len = 0; + memset(&hw->ud_record, 0, sizeof(hw->ud_record)); +} + +static void vmh264_crate_userdata_manager( + struct vdec_h264_hw_s *hw, + u8 *userdata_buf, + int buf_len) +{ + if (hw) { + + + mutex_init(&hw->userdata_mutex); + + memset(&hw->userdata_info, 0, + sizeof(struct mh264_userdata_info_t)); + hw->userdata_info.data_buf = userdata_buf; + hw->userdata_info.buf_len = buf_len; + hw->userdata_info.data_buf_end = userdata_buf + buf_len; + + vmh264_reset_udr_mgr(hw); + + } +} + +static void vmh264_destroy_userdata_manager(struct vdec_h264_hw_s *hw) +{ + if (hw) + memset(&hw->userdata_info, + 0, + sizeof(struct mh264_userdata_info_t)); +} + +/* +#define DUMP_USERDATA_RECORD +*/ +#ifdef DUMP_USERDATA_RECORD + +#define MAX_USER_DATA_SIZE 3145728 +static void *user_data_buf; +static unsigned char *pbuf_start; +static int total_len; +static int bskip; +static int n_userdata_id; + +static void print_data(unsigned char *pdata, + int len, + unsigned int poc_number, + unsigned int flag, + unsigned int duration, + unsigned int vpts, + unsigned int vpts_valid, + int rec_id) +{ + int nLeft; + + nLeft = len; +#if 0 + pr_info("%d len:%d, flag:%d, dur:%d, vpts:0x%x, valid:%d, poc:%d\n", + rec_id, len, flag, + duration, vpts, vpts_valid, poc_number); +#endif + pr_info("%d len = %d, flag = %d, vpts = 0x%x\n", + rec_id, len, flag, vpts); + + if (len == 96) { + int i; + nLeft = 72; + while (nLeft >= 16) { + pr_info("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + pdata[0], pdata[1], pdata[2], pdata[3], + pdata[4], pdata[5], pdata[6], pdata[7], + pdata[8], pdata[9], pdata[10], pdata[11], + pdata[12], pdata[13], pdata[14], pdata[15]); + nLeft -= 16; + pdata += 16; + } + + + while (nLeft > 0) { + pr_info("%02x %02x %02x %02x %02x %02x %02x %02x\n", + pdata[0], pdata[1], pdata[2], pdata[3], + pdata[4], pdata[5], pdata[6], pdata[7]); + nLeft -= 8; + pdata += 8; + } + + i = 0; + nLeft = 96-72; + while (i < nLeft) { + if (pdata[0] != 0) { + pr_info("some data error\n"); + break; + } + pdata++; + i++; + } + } else { + while (nLeft >= 16) { + pr_info("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + pdata[0], pdata[1], pdata[2], pdata[3], + pdata[4], pdata[5], pdata[6], pdata[7], + pdata[8], pdata[9], pdata[10], pdata[11], + pdata[12], pdata[13], pdata[14], pdata[15]); + nLeft -= 16; + pdata += 16; + } + + + while (nLeft > 0) { + pr_info("%02x %02x %02x %02x %02x %02x %02x %02x\n", + pdata[0], pdata[1], pdata[2], pdata[3], + pdata[4], pdata[5], pdata[6], pdata[7]); + nLeft -= 8; + pdata += 8; + } + + } +} + +static void push_to_buf(struct vdec_h264_hw_s *hw, + u8 *pdata, + int len, + struct userdata_meta_info_t *pmeta); + +static void dump_userdata_record(struct vdec_h264_hw_s *hw, + struct mh264_userdata_record_t *record) +{ + if (record && hw) { + u8 *pdata; + + pdata = hw->userdata_info.data_buf + record->rec_start; +/* + print_data(pdata, + record->rec_len, + record->meta_info.flags, + record->meta_info.duration, + record->meta_info.vpts, + record->meta_info.vpts_valid, + n_record_id); +*/ + push_to_buf(hw, pdata, record->rec_len, &record->meta_info); + n_userdata_id++; + } +} + + +static void push_to_buf(struct vdec_h264_hw_s *hw, + u8 *pdata, int len, + struct userdata_meta_info_t *pmeta) +{ + u32 *pLen; + int info_cnt; + u8 *pbuf_end; + + if (!user_data_buf) + return; + + if (bskip) { + pr_info("over size, skip\n"); + return; + } + info_cnt = 0; + pLen = (u32 *)pbuf_start; + + *pLen = len; + pbuf_start += sizeof(u32); + info_cnt++; + pLen++; + + *pLen = pmeta->poc_number; + pbuf_start += sizeof(u32); + info_cnt++; + pLen++; + + *pLen = pmeta->duration; + pbuf_start += sizeof(u32); + info_cnt++; + pLen++; + + *pLen = pmeta->flags; + pbuf_start += sizeof(u32); + info_cnt++; + pLen++; + + *pLen = pmeta->vpts; + pbuf_start += sizeof(u32); + info_cnt++; + pLen++; + + *pLen = pmeta->vpts_valid; + pbuf_start += sizeof(u32); + info_cnt++; + pLen++; + + + *pLen = n_userdata_id; + pbuf_start += sizeof(u32); + info_cnt++; + pLen++; + + + + pbuf_end = (u8 *)hw->sei_user_data_buffer + USER_DATA_SIZE; + if (pdata + len > pbuf_end) { + int first_section_len; + + first_section_len = pbuf_end - pdata; + memcpy(pbuf_start, pdata, first_section_len); + pdata = (u8 *)hw->sei_user_data_buffer; + pbuf_start += first_section_len; + memcpy(pbuf_start, pdata, len - first_section_len); + pbuf_start += len - first_section_len; + } else { + memcpy(pbuf_start, pdata, len); + pbuf_start += len; + } + + total_len += len + info_cnt * sizeof(u32); + if (total_len >= MAX_USER_DATA_SIZE-4096) + bskip = 1; +} + +static void show_user_data_buf(void) +{ + u8 *pbuf; + int len; + unsigned int flag; + unsigned int duration; + unsigned int vpts; + unsigned int vpts_valid; + unsigned int poc_number; + int rec_id; + + pr_info("show user data buf\n"); + pbuf = user_data_buf; + + while (pbuf < pbuf_start) { + u32 *pLen; + + pLen = (u32 *)pbuf; + + len = *pLen; + pLen++; + pbuf += sizeof(u32); + + poc_number = *pLen; + pLen++; + pbuf += sizeof(u32); + + duration = *pLen; + pLen++; + pbuf += sizeof(u32); + + flag = *pLen; + pLen++; + pbuf += sizeof(u32); + + vpts = *pLen; + pLen++; + pbuf += sizeof(u32); + + vpts_valid = *pLen; + pLen++; + pbuf += sizeof(u32); + + rec_id = *pLen; + pLen++; + pbuf += sizeof(u32); + + print_data(pbuf, len, poc_number, flag, + duration, vpts, + vpts_valid, rec_id); + pbuf += len; + msleep(30); + } +} + +static int vmh264_init_userdata_dump(void) +{ + user_data_buf = kmalloc(MAX_USER_DATA_SIZE, GFP_KERNEL); + if (user_data_buf) + return 1; + else + return 0; +} + +static void vmh264_dump_userdata(void) +{ + if (user_data_buf) { + show_user_data_buf(); + kfree(user_data_buf); + user_data_buf = NULL; + } +} + +static void vmh264_reset_user_data_buf(void) +{ + total_len = 0; + pbuf_start = user_data_buf; + bskip = 0; + n_userdata_id = 0; +} +#endif + + +static void vmh264_udc_fill_vpts(struct vdec_h264_hw_s *hw, + int frame_type, + u32 vpts, + u32 vpts_valid) +{ + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + + unsigned char *pdata; + u8 *pmax_sei_data_buffer; + u8 *sei_data_buf; + int i; + int wp; + int data_length; + struct mh264_userdata_record_t *p_userdata_rec; + + +#ifdef MH264_USERDATA_ENABLE + struct userdata_meta_info_t meta_info; + memset(&meta_info, 0, sizeof(meta_info)); +#endif + + if (hw->sei_itu_data_len <= 0) + return; + + pdata = (u8 *)hw->sei_user_data_buffer + hw->sei_user_data_wp; + pmax_sei_data_buffer = (u8 *)hw->sei_user_data_buffer + USER_DATA_SIZE; + sei_data_buf = (u8 *)hw->sei_itu_data_buf; + for (i = 0; i < hw->sei_itu_data_len; i++) { + *pdata++ = sei_data_buf[i]; + if (pdata >= pmax_sei_data_buffer) + pdata = (u8 *)hw->sei_user_data_buffer; + } + + hw->sei_user_data_wp = (hw->sei_user_data_wp + + hw->sei_itu_data_len) % USER_DATA_SIZE; + hw->sei_itu_data_len = 0; + +#ifdef MH264_USERDATA_ENABLE + meta_info.duration = hw->frame_dur; + meta_info.flags |= (VFORMAT_H264 << 3); + + meta_info.vpts = vpts; + meta_info.vpts_valid = vpts_valid; + meta_info.poc_number = + p_H264_Dpb->mVideo.dec_picture->poc; + + + wp = hw->sei_user_data_wp; + + if (hw->sei_user_data_wp > hw->userdata_info.last_wp) + data_length = wp - hw->userdata_info.last_wp; + else + data_length = wp + hw->userdata_info.buf_len + - hw->userdata_info.last_wp; + + if (data_length & 0x7) + data_length = (((data_length + 8) >> 3) << 3); + + p_userdata_rec = &hw->ud_record; + p_userdata_rec->meta_info = meta_info; + p_userdata_rec->rec_start = hw->userdata_info.last_wp; + p_userdata_rec->rec_len = data_length; + hw->userdata_info.last_wp = wp; + + p_userdata_rec->meta_info.flags |= + p_H264_Dpb->mVideo.dec_picture->pic_struct << 12; + + hw->wait_for_udr_send = 1; + vdec_schedule_work(&hw->user_data_ready_work); +#endif +} + + +static void user_data_ready_notify_work(struct work_struct *work) +{ + struct vdec_h264_hw_s *hw = container_of(work, + struct vdec_h264_hw_s, user_data_ready_work); + + + mutex_lock(&hw->userdata_mutex); + + hw->userdata_info.records[hw->userdata_info.write_index] + = hw->ud_record; + hw->userdata_info.write_index++; + if (hw->userdata_info.write_index >= USERDATA_FIFO_NUM) + hw->userdata_info.write_index = 0; + + mutex_unlock(&hw->userdata_mutex); + +#ifdef DUMP_USERDATA_RECORD + dump_userdata_record(hw, &hw->ud_record); +#endif + vdec_wakeup_userdata_poll(hw_to_vdec(hw)); + + hw->wait_for_udr_send = 0; +} + +static int vmh264_user_data_read(struct vdec_s *vdec, + struct userdata_param_t *puserdata_para) +{ + struct vdec_h264_hw_s *hw = NULL; + int rec_ri, rec_wi; + int rec_len; + u8 *rec_data_start; + u8 *pdest_buf; + struct mh264_userdata_record_t *p_userdata_rec; + u32 data_size; + u32 res; + int copy_ok = 1; + + hw = (struct vdec_h264_hw_s *)vdec->private; + + pdest_buf = puserdata_para->pbuf_addr; + + mutex_lock(&hw->userdata_mutex); + +/* + pr_info("ri = %d, wi = %d\n", + lg_p_mpeg12_userdata_info->read_index, + lg_p_mpeg12_userdata_info->write_index); +*/ + rec_ri = hw->userdata_info.read_index; + rec_wi = hw->userdata_info.write_index; + + if (rec_ri == rec_wi) { + mutex_unlock(&hw->userdata_mutex); + return 0; + } + + p_userdata_rec = hw->userdata_info.records + rec_ri; + + rec_len = p_userdata_rec->rec_len; + rec_data_start = p_userdata_rec->rec_start + hw->userdata_info.data_buf; +/* + pr_info("rec_len:%d, rec_start:%d, buf_len:%d\n", + p_userdata_rec->rec_len, + p_userdata_rec->rec_start, + puserdata_para->buf_len); +*/ + if (rec_len <= puserdata_para->buf_len) { + /* dvb user data buffer is enought to + copy the whole recored. */ + data_size = rec_len; + if (rec_data_start + data_size + > hw->userdata_info.data_buf_end) { + int first_section_len; + + first_section_len = hw->userdata_info.buf_len - + p_userdata_rec->rec_start; + res = (u32)copy_to_user((void *)pdest_buf, + (void *)rec_data_start, + first_section_len); + if (res) { + pr_info("p1 read not end res=%d, request=%d\n", + res, first_section_len); + copy_ok = 0; + + p_userdata_rec->rec_len -= + first_section_len - res; + p_userdata_rec->rec_start += + first_section_len - res; + puserdata_para->data_size = + first_section_len - res; + } else { + res = (u32)copy_to_user( + (void *)(pdest_buf+first_section_len), + (void *)hw->userdata_info.data_buf, + data_size - first_section_len); + if (res) { + pr_info("p2 read not end res=%d, request=%d\n", + res, data_size); + copy_ok = 0; + } + p_userdata_rec->rec_len -= + data_size - res; + p_userdata_rec->rec_start = + data_size - first_section_len - res; + puserdata_para->data_size = + data_size - res; + } + } else { + res = (u32)copy_to_user((void *)pdest_buf, + (void *)rec_data_start, + data_size); + if (res) { + pr_info("p3 read not end res=%d, request=%d\n", + res, data_size); + copy_ok = 0; + } + p_userdata_rec->rec_len -= data_size - res; + p_userdata_rec->rec_start += data_size - res; + puserdata_para->data_size = data_size - res; + } + + if (copy_ok) { + hw->userdata_info.read_index++; + if (hw->userdata_info.read_index >= USERDATA_FIFO_NUM) + hw->userdata_info.read_index = 0; + } + } else { + /* dvb user data buffer is not enought + to copy the whole recored. */ + data_size = puserdata_para->buf_len; + if (rec_data_start + data_size + > hw->userdata_info.data_buf_end) { + int first_section_len; + + first_section_len = hw->userdata_info.buf_len - + p_userdata_rec->rec_start; + res = (u32)copy_to_user((void *)pdest_buf, + (void *)rec_data_start, + first_section_len); + if (res) { + pr_info("p4 read not end res=%d, request=%d\n", + res, first_section_len); + copy_ok = 0; + p_userdata_rec->rec_len -= + first_section_len - res; + p_userdata_rec->rec_start += + first_section_len - res; + puserdata_para->data_size = + first_section_len - res; + } else { + /* first secton copy is ok*/ + res = (u32)copy_to_user( + (void *)(pdest_buf+first_section_len), + (void *)hw->userdata_info.data_buf, + data_size - first_section_len); + if (res) { + pr_info("p5 read not end res=%d, request=%d\n", + res, + data_size - first_section_len); + copy_ok = 0; + } + + p_userdata_rec->rec_len -= + data_size - res; + p_userdata_rec->rec_start = + data_size - first_section_len - res; + puserdata_para->data_size = + data_size - res; + } + } else { + res = (u32)copy_to_user((void *)pdest_buf, + (void *)rec_data_start, + data_size); + if (res) { + pr_info("p6 read not end res=%d, request=%d\n", + res, data_size); + copy_ok = 0; + } + + p_userdata_rec->rec_len -= data_size - res; + p_userdata_rec->rec_start += data_size - res; + puserdata_para->data_size = data_size - res; + } + + if (copy_ok) { + hw->userdata_info.read_index++; + if (hw->userdata_info.read_index >= USERDATA_FIFO_NUM) + hw->userdata_info.read_index = 0; + } + + } + puserdata_para->meta_info = p_userdata_rec->meta_info; + + if (hw->userdata_info.read_index <= hw->userdata_info.write_index) + puserdata_para->meta_info.records_in_que = + hw->userdata_info.write_index - + hw->userdata_info.read_index; + else + puserdata_para->meta_info.records_in_que = + hw->userdata_info.write_index + + USERDATA_FIFO_NUM - + hw->userdata_info.read_index; + + puserdata_para->version = (0<<24|0<<16|0<<8|1); + + mutex_unlock(&hw->userdata_mutex); + + return 1; +} + +static void vmh264_reset_userdata_fifo(struct vdec_s *vdec, int bInit) +{ + struct vdec_h264_hw_s *hw = NULL; + + hw = (struct vdec_h264_hw_s *)vdec->private; + + if (hw) { + mutex_lock(&hw->userdata_mutex); + pr_info("vmh264_reset_userdata_fifo: bInit: %d, ri: %d, wi: %d\n", + bInit, + hw->userdata_info.read_index, + hw->userdata_info.write_index); + hw->userdata_info.read_index = 0; + hw->userdata_info.write_index = 0; + + if (bInit) + hw->userdata_info.last_wp = 0; + mutex_unlock(&hw->userdata_mutex); + } +} + +static void vmh264_wakeup_userdata_poll(struct vdec_s *vdec) +{ + amstream_wakeup_userdata_poll(vdec); +} + +#endif + +static int vmh264_get_ps_info(struct vdec_h264_hw_s *hw, + u32 param1, u32 param2, u32 param3, u32 param4, + struct aml_vdec_ps_infos *ps) +{ +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + struct vdec_s *vdec = hw_to_vdec(hw); +#endif + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + struct vdec_pic_info pic; + int mb_width, mb_total; + int mb_height = 0; + int active_buffer_spec_num, dec_dpb_size; + int max_reference_size ,level_idc; + u32 frame_mbs_only_flag; + u32 chroma_format_idc; + u32 crop_bottom, crop_right; + int sub_width_c = 0, sub_height_c = 0; + u32 frame_width, frame_height; + u32 used_reorder_dpb_size_margin + = hw->reorder_dpb_size_margin; + + level_idc = param4 & 0xff; + max_reference_size = (param4 >> 8) & 0xff; + hw->dpb.mSPS.level_idc = level_idc; + +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + if (vdec->master || vdec->slave) + used_reorder_dpb_size_margin = + reorder_dpb_size_margin_dv; +#endif + mb_width = param1 & 0xff; + mb_total = (param1 >> 8) & 0xffff; + if (!mb_width && mb_total) /*for 4k2k*/ + mb_width = 256; + if (mb_width) + mb_height = mb_total/mb_width; + if (mb_width <= 0 || mb_height <= 0 || + is_oversize(mb_width << 4, mb_height << 4)) { + dpb_print(DECODE_ID(hw), 0, + "!!!wrong param1 0x%x mb_width/mb_height (0x%x/0x%x) %x\r\n", + param1, + mb_width, + mb_height); + hw->error_frame_width = mb_width << 4; + hw->error_frame_height = mb_height << 4; + return -1; + } + hw->error_frame_width = 0; + hw->error_frame_height = 0; + + dec_dpb_size = get_dec_dpb_size(hw , mb_width, mb_height, level_idc); + + dpb_print(DECODE_ID(hw), 0, + "v4l restriction:%d, max buffering:%d, DPB size:%d, reorder frames:%d, margin:%d\n", + hw->bitstream_restriction_flag, + hw->max_dec_frame_buffering, + dec_dpb_size, + hw->num_reorder_frames, + used_reorder_dpb_size_margin); + + active_buffer_spec_num = + dec_dpb_size + + used_reorder_dpb_size_margin; + + if (active_buffer_spec_num > MAX_VF_BUF_NUM) { + active_buffer_spec_num = MAX_VF_BUF_NUM; + dec_dpb_size = active_buffer_spec_num + - used_reorder_dpb_size_margin; + } + + hw->dpb.mDPB.size = active_buffer_spec_num; + + if (hw->no_poc_reorder_flag) + dec_dpb_size = 1; + + /* + * crop + * AV_SCRATCH_2 + * bit 15: frame_mbs_only_flag + * bit 13-14: chroma_format_idc + */ + hw->seq_info = param2; + frame_mbs_only_flag = (hw->seq_info >> 15) & 0x01; + if (hw->dpb.mSPS.profile_idc != 100 && + hw->dpb.mSPS.profile_idc != 110 && + hw->dpb.mSPS.profile_idc != 122 && + hw->dpb.mSPS.profile_idc != 144) { + hw->dpb.chroma_format_idc = 1; + } + chroma_format_idc = hw->dpb.chroma_format_idc; + + /* + * AV_SCRATCH_6 bit 31-16 = (left << 8 | right ) << 1 + * AV_SCRATCH_6 bit 15-0 = (top << 8 | bottom ) << + * (2 - frame_mbs_only_flag) + */ + switch (chroma_format_idc) { + case 1: + sub_width_c = 2; + sub_height_c = 2; + break; + + case 2: + sub_width_c = 2; + sub_height_c = 1; + break; + + case 3: + sub_width_c = 1; + sub_height_c = 1; + break; + + default: + break; + } + + if (chroma_format_idc == 0) { + crop_right = hw->dpb.frame_crop_right_offset; + crop_bottom = hw->dpb.frame_crop_bottom_offset * + (2 - frame_mbs_only_flag); + } else { + crop_right = sub_width_c * hw->dpb.frame_crop_right_offset; + crop_bottom = sub_height_c * hw->dpb.frame_crop_bottom_offset * + (2 - frame_mbs_only_flag); + } + + frame_width = mb_width << 4; + frame_height = mb_height << 4; + + frame_width = frame_width - crop_right; + frame_height = frame_height - crop_bottom; + + ps->profile = level_idc; + ps->ref_frames = max_reference_size; + ps->mb_width = mb_width; + ps->mb_height = mb_height; + ps->visible_width = frame_width; + ps->visible_height = frame_height; + ps->coded_width = ALIGN(mb_width << 4, 64); + ps->coded_height = ALIGN(mb_height << 4, 64); + ps->dpb_frames = dec_dpb_size + 1; /* +1 for two frames in one packet */ + ps->dpb_margin = used_reorder_dpb_size_margin; + ps->dpb_size = active_buffer_spec_num; + ps->field = frame_mbs_only_flag ? + V4L2_FIELD_NONE : V4L2_FIELD_INTERLACED; + + /* update reoder and margin num. */ + if (hw->res_ch_flag) { + vdec_v4l_get_pic_info(ctx, &pic); + ps->dpb_frames = pic.dpb_frames; + ps->dpb_margin = pic.dpb_margin; + } + + if ((ps->dpb_frames >= 16) && (ps->coded_width > 1280) && + (ps->coded_height > 768)) { + if (ps->field == V4L2_FIELD_NONE) { + ps->dpb_frames = adjust_dpb_size; + } else { + ps->dpb_frames = adjust_dpb_size - 2; + } + } + + dpb_print(DECODE_ID(hw), 0, + "Res:%dx%d, DPB size:%d, margin:%d, scan:%s\n", + ps->visible_width, ps->visible_height, + ps->dpb_frames, ps->dpb_margin, + (ps->field == V4L2_FIELD_NONE) ? "P" : "I"); + + return 0; +} + +static int v4l_res_change(struct vdec_h264_hw_s *hw, + u32 param1, u32 param2, + u32 param3, u32 param4) +{ + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + int ret = 0; + int dec_dpb_size_change = hw->dpb.dec_dpb_size != get_dec_dpb_size_active(hw, param1, param4); + + if (ctx->param_sets_from_ucode && + hw->res_ch_flag == 0) { + if (((param1 != 0 && + (hw->seq_info2 & 0x80ffffff) != (param1 & 0x80ffffff)) || dec_dpb_size_change) && + hw->seq_info2 != 0) { /*picture size changed*/ + struct aml_vdec_ps_infos ps; + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, + "h264 res_change\n"); + if (vmh264_get_ps_info(hw, param1, + param2, param3, param4, &ps) < 0) { + dpb_print(DECODE_ID(hw), 0, + "set parameters error\n"); + } + hw->v4l_params_parsed = false; + vdec_v4l_set_ps_infos(ctx, &ps); + vdec_v4l_res_ch_event(ctx); + hw->res_ch_flag = 1; + ctx->v4l_resolution_change = 1; + hw->bitstream_restriction_flag = hw->cfg_bitstream_restriction_flag; // restore the old value when v4l res change + amvdec_stop(); + if (hw->mmu_enable) + amhevc_stop(); + hw->eos = 1; + flush_dpb(p_H264_Dpb); + //del_timer_sync(&hw->check_timer); + ATRACE_COUNTER("V_ST_DEC-submit_eos", __LINE__); + notify_v4l_eos(hw_to_vdec(hw)); + ATRACE_COUNTER("V_ST_DEC-submit_eos", 0); + ret = 1; + } + } + + return ret; + +} + +static void vh264_work_implement(struct vdec_h264_hw_s *hw, + struct vdec_s *vdec, int from) +{ + /* finished decoding one frame or error, + * notify vdec core to switch context + */ + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + + if (hw->dec_result == DEC_RESULT_DONE) { + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_WORKER_START); + } else if (hw->dec_result == DEC_RESULT_AGAIN) + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_WORKER_AGAIN); + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_DETAIL, + "%s dec_result %d %x %x %x\n", + __func__, + hw->dec_result, + READ_VREG(VLD_MEM_VIFIFO_LEVEL), + READ_VREG(VLD_MEM_VIFIFO_WP), + READ_VREG(VLD_MEM_VIFIFO_RP)); + + ATRACE_COUNTER("V_ST_DEC-work_state", hw->dec_result); + + if (!hw->mmu_enable) { + mutex_lock(&vmh264_mutex); + dealloc_buf_specs(hw, 0); + mutex_unlock(&vmh264_mutex); + } + hw->save_reg_f = READ_VREG(AV_SCRATCH_F); + hw->dpb.last_dpb_status = hw->dpb.dec_dpb_status; + if (hw->dec_result == DEC_RESULT_CONFIG_PARAM) { + u32 param1 = READ_VREG(AV_SCRATCH_1); + u32 param2 = READ_VREG(AV_SCRATCH_2); + u32 param3 = READ_VREG(AV_SCRATCH_6); + u32 param4 = READ_VREG(AV_SCRATCH_B); + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + + if (hw->is_used_v4l && + ctx->param_sets_from_ucode) { + if (!v4l_res_change(hw, param1, param2, param3, param4)) { + if (!hw->v4l_params_parsed) { + struct aml_vdec_ps_infos ps; + dpb_print(DECODE_ID(hw), + PRINT_FLAG_DEC_DETAIL, + "h264 parsered csd data\n"); + if (vmh264_get_ps_info(hw, + param1, param2, + param3, param4, &ps) < 0) { + dpb_print(DECODE_ID(hw), 0, + "set parameters error\n"); + } + hw->v4l_params_parsed = true; + vdec_v4l_set_ps_infos(ctx, &ps); + + amvdec_stop(); + if (hw->mmu_enable) + amhevc_stop(); + ATRACE_COUNTER(hw->trace.decode_time_name, DECODER_WORKER_START); + } else { + if (vh264_set_params(hw, param1, + param2, param3, param4, false) < 0) { + hw->init_flag = 0; + dpb_print(DECODE_ID(hw), 0, "set parameters error, init_flag: %u\n", + hw->init_flag); + } + + WRITE_VREG(AV_SCRATCH_0, (hw->max_reference_size<<24) | + (hw->dpb.mDPB.size<<16) | + (hw->dpb.mDPB.size<<8)); + hw->res_ch_flag = 0; + start_process_time(hw); + return; + } + } + } else { + if (vh264_set_params(hw, param1, + param2, param3, param4, false) < 0) { + hw->init_flag = 0; + dpb_print(DECODE_ID(hw), 0, "set parameters error, init_flag: %u\n", + hw->init_flag); + } + + WRITE_VREG(AV_SCRATCH_0, (hw->max_reference_size<<24) | + (hw->dpb.mDPB.size<<16) | + (hw->dpb.mDPB.size<<8)); + start_process_time(hw); + return; + } + } else + if (((hw->dec_result == DEC_RESULT_GET_DATA) || + (hw->dec_result == DEC_RESULT_GET_DATA_RETRY)) + && (hw_to_vdec(hw)->next_status != + VDEC_STATUS_DISCONNECTED)) { + if (!vdec_has_more_input(vdec)) { + hw->dec_result = DEC_RESULT_EOS; + vdec_schedule_work(&hw->work); + return; + } + + if (hw->dec_result == DEC_RESULT_GET_DATA) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s DEC_RESULT_GET_DATA %x %x %x\n", + __func__, + READ_VREG(VLD_MEM_VIFIFO_LEVEL), + READ_VREG(VLD_MEM_VIFIFO_WP), + READ_VREG(VLD_MEM_VIFIFO_RP)); + mutex_lock(&hw->chunks_mutex); + vdec_vframe_dirty(vdec, hw->chunk); + hw->chunk = NULL; + mutex_unlock(&hw->chunks_mutex); + vdec_clean_input(vdec); + } + if ((hw->dec_result == DEC_RESULT_GET_DATA_RETRY) && + ((1000 * (jiffies - hw->get_data_start_time) / HZ) + > get_data_timeout_val)) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s DEC_RESULT_GET_DATA_RETRY timeout\n", + __func__); + goto result_done; + } + if (is_buffer_available(vdec)) { + int r; + int decode_size; + r = vdec_prepare_input(vdec, &hw->chunk); + if (r < 0 && (hw_to_vdec(hw)->next_status != + VDEC_STATUS_DISCONNECTED)) { + hw->dec_result = DEC_RESULT_GET_DATA_RETRY; + + dpb_print(DECODE_ID(hw), + PRINT_FLAG_VDEC_DETAIL, + "vdec_prepare_input: Insufficient data\n"); + vdec_schedule_work(&hw->work); + return; + } + hw->dec_result = DEC_RESULT_NONE; + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s: chunk size 0x%x\n", + __func__, hw->chunk->size); + + if (dpb_is_debug(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA)) { + int jj; + u8 *data = NULL; + + if (!hw->chunk->block->is_mapped) + data = codec_mm_vmap( + hw->chunk->block->start + + hw->chunk->offset, r); + else + data = ((u8 *) + hw->chunk->block->start_virt) + + hw->chunk->offset; + + for (jj = 0; jj < r; jj++) { + if ((jj & 0xf) == 0) + dpb_print(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA, + "%06x:", jj); + dpb_print_cont(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA, + "%02x ", data[jj]); + if (((jj + 1) & 0xf) == 0) + dpb_print_cont(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA, + "\n"); + } + + if (!hw->chunk->block->is_mapped) + codec_mm_unmap_phyaddr(data); + } + WRITE_VREG(POWER_CTL_VLD, + READ_VREG(POWER_CTL_VLD) | + (0 << 10) | (1 << 9) | (1 << 6)); + WRITE_VREG(H264_DECODE_INFO, (1<<13)); + decode_size = hw->chunk->size + + (hw->chunk->offset & (VDEC_FIFO_ALIGN - 1)); + WRITE_VREG(H264_DECODE_SIZE, decode_size); + WRITE_VREG(VIFF_BIT_CNT, decode_size * 8); + vdec_enable_input(vdec); + + WRITE_VREG(DPB_STATUS_REG, H264_ACTION_SEARCH_HEAD); + start_process_time(hw); + } else{ + if (hw_to_vdec(hw)->next_status + != VDEC_STATUS_DISCONNECTED) { + hw->dec_result = DEC_RESULT_GET_DATA_RETRY; + vdec_schedule_work(&hw->work); + } + } + return; + } else if (hw->dec_result == DEC_RESULT_DONE || + hw->dec_result == DEC_RESULT_TIMEOUT) { + /* if (!hw->ctx_valid) + hw->ctx_valid = 1; */ + if ((hw->dec_result == DEC_RESULT_TIMEOUT) && + !hw->i_only && (hw->error_proc_policy & 0x2)) { + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + dpb_print(DECODE_ID(hw), 0, + "%s, decode timeout flush dpb\n", + __func__); + flush_dpb(p_H264_Dpb); + } +result_done: + { + if (hw->error_proc_policy & 0x8000) { + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + int i; + struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB; + + for (i = 0; i < p_Dpb->used_size; i++) { + int i_flag = p_Dpb->fs[i]->bottom_field || p_Dpb->fs[i]->top_field; + int threshold = (i_flag || (hw->max_reference_size >= 12)) ? ((50 + p_Dpb->used_size) * 2) : 50 + p_Dpb->used_size; + if ((p_Dpb->fs[i]->dpb_frame_count + threshold + < p_H264_Dpb->dpb_frame_count) && + p_Dpb->fs[i]->is_reference && + !p_Dpb->fs[i]->is_long_term && + p_Dpb->fs[i]->is_output) { + dpb_print(DECODE_ID(hw), + 0, + "unmark reference dpb_frame_count diffrence large in dpb\n"); + unmark_for_reference(p_Dpb, p_Dpb->fs[i]); + update_ref_list(p_Dpb); + } + } + } + } + if (hw->mmu_enable + && hw->frame_busy && hw->frame_done) { + long used_4k_num; + hevc_sao_wait_done(hw); + if (hw->hevc_cur_buf_idx != 0xffff) { + used_4k_num = + (READ_VREG(HEVC_SAO_MMU_STATUS) >> 16); + if (used_4k_num >= 0) + dpb_print(DECODE_ID(hw), + PRINT_FLAG_MMU_DETAIL, + "release unused buf , used_4k_num %ld index %d\n", + used_4k_num, hw->hevc_cur_buf_idx); + hevc_mmu_dma_check(hw_to_vdec(hw)); + decoder_mmu_box_free_idx_tail( + hw->mmu_box, + hw->hevc_cur_buf_idx, + used_4k_num); + hw->hevc_cur_buf_idx = 0xffff; + } + } + decode_frame_count[DECODE_ID(hw)]++; + if (hw->dpb.mSlice.slice_type == I_SLICE) { + hw->gvs.i_decoded_frames++; + } else if (hw->dpb.mSlice.slice_type == P_SLICE) { + hw->gvs.p_decoded_frames++; + } else if (hw->dpb.mSlice.slice_type == B_SLICE) { + hw->gvs.b_decoded_frames++; + } + amvdec_stop(); + + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s dec_result %d %x %x %x\n", + __func__, + hw->dec_result, + READ_VREG(VLD_MEM_VIFIFO_LEVEL), + READ_VREG(VLD_MEM_VIFIFO_WP), + READ_VREG(VLD_MEM_VIFIFO_RP)); + mutex_lock(&hw->chunks_mutex); + vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk); + hw->chunk = NULL; + mutex_unlock(&hw->chunks_mutex); + } else if (hw->dec_result == DEC_RESULT_AGAIN) { + /* + stream base: stream buf empty or timeout + frame base: vdec_prepare_input fail + */ + if (!vdec_has_more_input(vdec) && (hw_to_vdec(hw)->next_status != + VDEC_STATUS_DISCONNECTED) && (hw->no_decoder_buffer_flag == 0)) { + hw->dec_result = DEC_RESULT_EOS; + vdec_schedule_work(&hw->work); + return; + } + amvdec_stop(); + if (hw->mmu_enable) + amhevc_stop(); + hw->no_decoder_buffer_flag = 0; + hw->next_again_flag = 1; + } else if (hw->dec_result == DEC_RESULT_EOS) { + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s: end of stream\n", + __func__); + amvdec_stop(); + if (hw->mmu_enable) + amhevc_stop(); + hw->eos = 1; + flush_dpb(p_H264_Dpb); + if (hw->is_used_v4l) { + ATRACE_COUNTER("V_ST_DEC-submit_eos", __LINE__); + notify_v4l_eos(hw_to_vdec(hw)); + ATRACE_COUNTER("V_ST_DEC-submit_eos", 0); + } + mutex_lock(&hw->chunks_mutex); + vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk); + hw->chunk = NULL; + mutex_unlock(&hw->chunks_mutex); + vdec_clean_input(vdec); + } else if (hw->dec_result == DEC_RESULT_FORCE_EXIT) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s: force exit\n", + __func__); + amvdec_stop(); + if (hw->mmu_enable) + amhevc_stop(); + if (hw->stat & STAT_ISR_REG) { + vdec_free_irq(VDEC_IRQ_1, (void *)hw); + hw->stat &= ~STAT_ISR_REG; + } + } else if (hw->dec_result == DEC_RESULT_NEED_MORE_BUFFER) { + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + bufmgr_h264_remove_unused_frame(p_H264_Dpb, 0); + if (!have_free_buf_spec(vdec)) { + if (vdec->next_status == VDEC_STATUS_DISCONNECTED) + hw->dec_result = DEC_RESULT_AGAIN; + else + hw->dec_result = DEC_RESULT_NEED_MORE_BUFFER; + vdec_schedule_work(&hw->work); + } else { + hw->get_data_count = 0x7fffffff; + WRITE_VREG(DPB_STATUS_REG, H264_ACTION_SEARCH_HEAD); + decode_frame_count[DECODE_ID(hw)]++; + if (p_H264_Dpb->mSlice.slice_type == I_SLICE) { + hw->gvs.i_decoded_frames++; + } else if (p_H264_Dpb->mSlice.slice_type == P_SLICE) { + hw->gvs.p_decoded_frames++; + } else if (p_H264_Dpb->mSlice.slice_type == B_SLICE) { + hw->gvs.b_decoded_frames++; + } + start_process_time(hw); + } + return; + } + + if (p_H264_Dpb->mVideo.dec_picture) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s, release decoded picture\n", __func__); + release_cur_decoding_buf(hw); + } + + WRITE_VREG(ASSIST_MBOX1_MASK, 0); + del_timer_sync(&hw->check_timer); + hw->stat &= ~STAT_TIMER_ARM; +#ifdef DETECT_WRONG_MULTI_SLICE + if (hw->dec_result != DEC_RESULT_AGAIN) + hw->last_picture_slice_count = 0; +#endif + ATRACE_COUNTER(hw->trace.decode_work_time_name, TRACE_WORK_WAIT_SEARCH_DONE_START); + wait_vmh264_search_done(hw); + ATRACE_COUNTER(hw->trace.decode_work_time_name, TRACE_WORK_WAIT_SEARCH_DONE_END); + /* mark itself has all HW resource released and input released */ + +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + if (hw->switch_dvlayer_flag) { + if (vd