Project import generated by Copybara. GitOrigin-RevId: df5bf87eca1b9de24d3afd9ee49b125f95dc1351
diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..7481eee --- /dev/null +++ b/Makefile
@@ -0,0 +1,51 @@ +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 \ + 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_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-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) $(KBUILD_CFLAGS_MODULE) ${VERSION_CONTROL_CFLAGS}" $(CONFIGS) + +all: modules + +modules_install: + $(MAKE) INSTALL_MOD_STRIP=1 M=$(M)/drivers -C $(KERNEL_SRC) modules_install + mkdir -p ${OUT_DIR}/../vendor_lib/modules + cd ${OUT_DIR}/$(M)/; find -name "*.ko" -exec cp {} ${OUT_DIR}/../vendor_lib/modules/ \; + mkdir -p ${OUT_DIR}/../vendor_lib/firmware/video + cp $(KERNEL_SRC)/$(M)/firmware/* ${OUT_DIR}/../vendor_lib/firmware/video/ + +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(M) clean
diff --git a/Media.mk b/Media.mk new file mode 100644 index 0000000..58db63b --- /dev/null +++ b/Media.mk
@@ -0,0 +1,110 @@ +ifeq ($(KERNEL_A32_SUPPORT), true) +KERNEL_ARCH := arm +else +KERNEL_ARCH := arm64 +endif + +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_AVS2=m \ + CONFIG_AMLOGIC_MEDIA_VENC_H264=m \ + CONFIG_AMLOGIC_MEDIA_VENC_H265=m \ + 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"),\ + $(shell cp $(m) $(strip $(2)) -rfa)) +endef + +ifneq (,$(TOP)) +KDIR := $(shell pwd)/$(PRODUCT_OUT)/obj/KERNEL_OBJ/ + +MEDIA_DRIVERS := $(TOP)/hardware/amlogic/media_modules/drivers +ifeq (,$(wildcard $(MEDIA_DRIVERS))) +$(error No find the dir of drivers.) +endif + +INCLUDE := $(MEDIA_DRIVERS)/include +ifeq (,$(wildcard $(INCLUDE))) +$(error No find the dir of include.) +endif + +MEDIA_MODULES := $(shell pwd)/$(PRODUCT_OUT)/obj/media_modules +ifeq (,$(wildcard $(MEDIA_MODULES))) +$(shell mkdir $(MEDIA_MODULES) -p) +endif + +MODS_OUT := $(shell pwd)/$(PRODUCT_OUT)/obj/lib_vendor +ifeq (,$(wildcard $(MODS_OUT))) +$(shell mkdir $(MODS_OUT) -p) +endif + +UCODE_OUT := $(shell pwd)/$(PRODUCT_OUT)/$(TARGET_COPY_OUT_VENDOR)/lib/firmware/video +ifeq (,$(wildcard $(UCODE_OUT))) +$(shell mkdir $(UCODE_OUT) -p) +endif + +$(shell cp $(MEDIA_DRIVERS)/../firmware/* $(UCODE_OUT) -rfa) +$(shell cp $(MEDIA_DRIVERS)/* $(MEDIA_MODULES) -rfa) + +define media-modules + 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 +KDIR := $(PWD)/kernel +ifeq (,$(wildcard $(KDIR))) +$(error No find the dir of kernel.) +endif + +MEDIA_DRIVERS := $(PWD)/media_modules/drivers +ifeq (,$(wildcard $(MEDIA_DRIVERS))) +$(error No find the dir of drivers.) +endif + +INCLUDE := $(MEDIA_DRIVERS)/include +ifeq (,$(wildcard $(INCLUDE))) +$(error No find the dir of include.) +endif + +MODS_OUT ?= $(MEDIA_DRIVERS)/../modules +ifeq (,$(wildcard $(MODS_OUT))) +$(shell mkdir $(MODS_OUT) -p) +endif + +modules: + 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." + mkdir -p $(MODS_OUT) + $(call copy-media-modules, $(MEDIA_DRIVERS), $(MODS_OUT)) + +all: modules copy-modules + + +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/drivers/Makefile b/drivers/Makefile new file mode 100644 index 0000000..e96ba44 --- /dev/null +++ b/drivers/Makefile
@@ -0,0 +1,8 @@ +obj-y += common/ +obj-y += frame_provider/ +obj-y += frame_sink/ +obj-y += stream_input/ +obj-y += amvdec_ports/ +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 new file mode 100644 index 0000000..2e7cff4 --- /dev/null +++ b/drivers/amvdec_ports/Makefile
@@ -0,0 +1,26 @@ +obj-m += amvdec_ports.o +amvdec_ports-objs += aml_vcodec_dec_drv.o +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_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 +amvdec_ports-objs += decoder/vdec_mpeg12_if.o +amvdec_ports-objs += decoder/vdec_mpeg4_if.o +amvdec_ports-objs += decoder/vdec_mjpeg_if.o +amvdec_ports-objs += decoder/vdec_av1_if.o +ifdef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER +amvdec_ports-objs += decoder/aml_h264_parser.o +amvdec_ports-objs += decoder/aml_hevc_parser.o +amvdec_ports-objs += decoder/aml_vp9_parser.o +amvdec_ports-objs += decoder/aml_mpeg12_parser.o +amvdec_ports-objs += decoder/aml_mpeg4_parser.o +amvdec_ports-objs += decoder/aml_mjpeg_parser.o +amvdec_ports-objs += utils/golomb.o +endif +amvdec_ports-objs += utils/common.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 new file mode 100644 index 0000000..7e08371 --- /dev/null +++ b/drivers/amvdec_ports/aml_vcodec_adapt.c
@@ -0,0 +1,591 @@ +/* +* 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/amlogic/media/utils/amstream.h> +#include <linux/amlogic/media/utils/vformat.h> +#include <linux/amlogic/media/utils/aformat.h> +#include <linux/amlogic/media/frame_sync/tsync.h> +#include <linux/amlogic/media/frame_sync/ptsserv.h> +#include <linux/amlogic/media/frame_sync/timestamp.h> +#include <linux/amlogic/media/utils/amports_config.h> +#include <linux/amlogic/media/frame_sync/tsync_pcr.h> +#include <linux/amlogic/media/codec_mm/codec_mm.h> +#include <linux/amlogic/media/codec_mm/configs.h> +#include <linux/amlogic/media/utils/vformat.h> +#include <linux/amlogic/media/utils/aformat.h> +#include <linux/amlogic/media/registers/register.h> +#include "../stream_input/amports/adec.h" +#include "../stream_input/amports/streambuf.h" +#include "../stream_input/amports/streambuf_reg.h" +#include "../stream_input/parser/tsdemux.h" +#include "../stream_input/parser/psparser.h" +#include "../stream_input/parser/esparser.h" +#include "../frame_provider/decoder/utils/vdec.h" +#include "../common/media_clock/switch/amports_gate.h" +#include <linux/delay.h> +#include "aml_vcodec_adapt.h" +#include <linux/crc32.h> + +#define DEFAULT_VIDEO_BUFFER_SIZE (1024 * 1024 * 3) +#define DEFAULT_VIDEO_BUFFER_SIZE_4K (1024 * 1024 * 6) +#define DEFAULT_VIDEO_BUFFER_SIZE_TVP (1024 * 1024 * 10) +#define DEFAULT_VIDEO_BUFFER_SIZE_4K_TVP (1024 * 1024 * 15) +#define DEFAULT_AUDIO_BUFFER_SIZE (1024*768*2) +#define DEFAULT_SUBTITLE_BUFFER_SIZE (1024*256) + +#define PTS_OUTSIDE (1) +#define SYNC_OUTSIDE (2) + +//#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 slow_input = 0; + +static struct stream_buf_s bufs[BUF_MAX_NUM] = { + { + .reg_base = VLD_MEM_VIFIFO_REG_BASE, + .type = BUF_TYPE_VIDEO, + .buf_start = 0, + .buf_size = DEFAULT_VIDEO_BUFFER_SIZE, + .default_buf_size = DEFAULT_VIDEO_BUFFER_SIZE, + .first_tstamp = INVALID_PTS + }, + { + .reg_base = AIU_MEM_AIFIFO_REG_BASE, + .type = BUF_TYPE_AUDIO, + .buf_start = 0, + .buf_size = DEFAULT_AUDIO_BUFFER_SIZE, + .default_buf_size = DEFAULT_AUDIO_BUFFER_SIZE, + .first_tstamp = INVALID_PTS + }, + { + .reg_base = 0, + .type = BUF_TYPE_SUBTITLE, + .buf_start = 0, + .buf_size = DEFAULT_SUBTITLE_BUFFER_SIZE, + .default_buf_size = DEFAULT_SUBTITLE_BUFFER_SIZE, + .first_tstamp = INVALID_PTS + }, + { + .reg_base = 0, + .type = BUF_TYPE_USERDATA, + .buf_start = 0, + .buf_size = 0, + .first_tstamp = INVALID_PTS + }, + { + .reg_base = HEVC_STREAM_REG_BASE, + .type = BUF_TYPE_HEVC, + .buf_start = 0, + .buf_size = DEFAULT_VIDEO_BUFFER_SIZE_4K, + .default_buf_size = DEFAULT_VIDEO_BUFFER_SIZE_4K, + .first_tstamp = INVALID_PTS + }, +}; + +extern int aml_set_vfm_path, aml_set_vdec_type; +extern bool aml_set_vfm_enable, aml_set_vdec_type_enable; + +static void set_default_params(struct aml_vdec_adapt *vdec) +{ + ulong sync_mode = (PTS_OUTSIDE | SYNC_OUTSIDE); + + vdec->dec_prop.param = (void *)sync_mode; + vdec->dec_prop.format = vdec->format; + vdec->dec_prop.width = 1920; + vdec->dec_prop.height = 1088; + vdec->dec_prop.rate = 3200; +} + +static int enable_hardware(struct stream_port_s *port) +{ + if (get_cpu_type() < MESON_CPU_MAJOR_ID_M6) + return -1; + + amports_switch_gate("demux", 1); + if (get_cpu_type() >= MESON_CPU_MAJOR_ID_M8) + amports_switch_gate("parser_top", 1); + + if (port->type & PORT_TYPE_VIDEO) { + amports_switch_gate("vdec", 1); + + if (has_hevc_vdec()) { + if (port->type & PORT_TYPE_HEVC) + vdec_poweron(VDEC_HEVC); + else + vdec_poweron(VDEC_1); + } else { + if (get_cpu_type() >= MESON_CPU_MAJOR_ID_M8) + vdec_poweron(VDEC_1); + } + } + + return 0; +} + +static int disable_hardware(struct stream_port_s *port) +{ + if (get_cpu_type() < MESON_CPU_MAJOR_ID_M6) + return -1; + + if (port->type & PORT_TYPE_VIDEO) { + if (has_hevc_vdec()) { + if (port->type & PORT_TYPE_HEVC) + vdec_poweroff(VDEC_HEVC); + else + vdec_poweroff(VDEC_1); + } + + amports_switch_gate("vdec", 0); + } + + if (get_cpu_type() >= MESON_CPU_MAJOR_ID_M8) + amports_switch_gate("parser_top", 0); + + amports_switch_gate("demux", 0); + + return 0; +} + +static void user_buffer_init(void) +{ + struct stream_buf_s *pubuf = &bufs[BUF_TYPE_USERDATA]; + + pubuf->buf_size = 0; + pubuf->buf_start = 0; + pubuf->buf_wp = 0; + pubuf->buf_rp = 0; +} + +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; + + vdec_release(vdec); + +} + +static int video_component_init(struct stream_port_s *port, + struct stream_buf_s *pbuf) +{ + int ret = -1; + struct aml_vdec_adapt *ada_ctx + = container_of(port, struct aml_vdec_adapt, port); + struct vdec_s *vdec = ada_ctx->vdec; + + if ((vdec->port_flag & PORT_FLAG_VFORMAT) == 0) { + v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_ERROR, "vformat not set\n"); + return -EPERM; + } + + if ((vdec->sys_info->height * vdec->sys_info->width) > 1920 * 1088 + || port->vformat == VFORMAT_H264_4K2K) { + port->is_4k = true; + if (get_cpu_type() >= MESON_CPU_MAJOR_ID_TXLX + && (port->vformat == VFORMAT_H264)) + vdec_poweron(VDEC_HEVC); + } else + port->is_4k = false; + + 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); + return ret; + } + } + + return 0; +} + +static int vdec_ports_release(struct stream_port_s *port) +{ + struct stream_buf_s *pvbuf = &bufs[BUF_TYPE_VIDEO]; + + if (has_hevc_vdec()) { + if (port->vformat == VFORMAT_HEVC || + port->vformat == VFORMAT_VP9) + pvbuf = &bufs[BUF_TYPE_HEVC]; + } + + if (port->type & PORT_TYPE_MPTS) { + tsync_pcr_stop(); + tsdemux_release(); + } + + if (port->type & PORT_TYPE_MPPS) + psparser_release(); + + if (port->type & PORT_TYPE_VIDEO) + video_component_release(port); + + port->pcr_inited = 0; + port->flag = 0; + + return 0; +} + +static void set_vdec_properity(struct vdec_s *vdec, + struct aml_vdec_adapt *ada_ctx) +{ + vdec->sys_info = &ada_ctx->dec_prop; + vdec->port = &ada_ctx->port; + vdec->format = ada_ctx->video_type; + vdec->sys_info_store = ada_ctx->dec_prop; + + /* binding v4l2 ctx to vdec. */ + vdec->private = ada_ctx->ctx; + + /* set video format, sys info and vfm map.*/ + vdec->port->vformat = vdec->format; + vdec->port->type |= PORT_TYPE_VIDEO; + vdec->port_flag |= (vdec->port->flag | PORT_FLAG_VFORMAT); + if (vdec->slave) { + vdec->slave->format = ada_ctx->dec_prop.format; + vdec->slave->port_flag |= PORT_FLAG_VFORMAT; + } + + vdec->type = VDEC_TYPE_FRAME_BLOCK; + vdec->port->type |= PORT_TYPE_FRAME; + vdec->frame_base_video_path = FRAME_BASE_PATH_V4L_OSD; + + if (aml_set_vdec_type_enable) { + if (aml_set_vdec_type == VDEC_TYPE_STREAM_PARSER) { + vdec->type = VDEC_TYPE_STREAM_PARSER; + vdec->port->type &= ~PORT_TYPE_FRAME; + vdec->port->type |= PORT_TYPE_ES; + } else if (aml_set_vdec_type == VDEC_TYPE_FRAME_BLOCK) { + vdec->type = VDEC_TYPE_FRAME_BLOCK; + vdec->port->type &= ~PORT_TYPE_ES; + vdec->port->type |= PORT_TYPE_FRAME; + } + } + + if (aml_set_vfm_enable) + vdec->frame_base_video_path = aml_set_vfm_path; + + vdec->port->flag = vdec->port_flag; + + vdec->config_len = ada_ctx->config.length > + PAGE_SIZE ? PAGE_SIZE : ada_ctx->config.length; + memcpy(vdec->config, ada_ctx->config.buf, vdec->config_len); + + ada_ctx->vdec = vdec; +} + +static int vdec_ports_init(struct aml_vdec_adapt *ada_ctx) +{ + int ret = -1; + struct stream_buf_s *pvbuf = &bufs[BUF_TYPE_VIDEO]; + struct vdec_s *vdec = NULL; + + /* create the vdec instance.*/ + vdec = vdec_create(&ada_ctx->port, NULL); + if (IS_ERR_OR_NULL(vdec)) + return -1; + + vdec->disable_vfm = true; + set_vdec_properity(vdec, ada_ctx); + + /* init hw and gate*/ + ret = enable_hardware(vdec->port); + if (ret < 0) { + v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_ERROR, "enable hw fail.\n"); + return ret; + } + + stbuf_fetch_init(); + user_buffer_init(); + + if ((vdec->port->type & PORT_TYPE_VIDEO) + && (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) + pvbuf = &bufs[BUF_TYPE_HEVC]; + } + + ret = video_component_init(vdec->port, pvbuf); + if (ret < 0) { + v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_ERROR, "video_component_init failed\n"); + return ret; + } + + /* connect vdec at the end after all HW initialization */ + vdec_connect(vdec); + } + + return 0; +} + +int video_decoder_init(struct aml_vdec_adapt *vdec) +{ + int ret = -1; + + /* sets configure data */ + set_default_params(vdec); + + /* init the buffer work space and connect vdec.*/ + ret = vdec_ports_init(vdec); + if (ret < 0) { + v4l_dbg(vdec->ctx, V4L_DEBUG_CODEC_ERROR, "vdec ports init fail.\n"); + goto out; + } +out: + return ret; +} + +int video_decoder_release(struct aml_vdec_adapt *vdec) +{ + int ret = -1; + struct stream_port_s *port = &vdec->port; + + ret = vdec_ports_release(port); + if (ret < 0) { + v4l_dbg(vdec->ctx, V4L_DEBUG_CODEC_ERROR, "vdec ports release fail.\n"); + goto out; + } + + /* disable gates */ + ret = disable_hardware(port); + if (ret < 0) { + v4l_dbg(vdec->ctx, V4L_DEBUG_CODEC_ERROR, "disable hw fail.\n"); + goto out; + } +out: + return ret; +} + +void dump(const char* path, const char *data, unsigned int size) +{ + struct file *fp; + + fp = filp_open(path, + O_CREAT | O_RDWR | O_LARGEFILE | O_APPEND, 0600); + 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) +{ + int ret = -1; + int try_cnt = 100; + struct stream_port_s *port = &ada_ctx->port; + struct vdec_s *vdec = ada_ctx->vdec; + struct stream_buf_s *pbuf = NULL; + + if (has_hevc_vdec()) { + pbuf = (port->type & PORT_TYPE_HEVC) ? &bufs[BUF_TYPE_HEVC] : + &bufs[BUF_TYPE_VIDEO]; + } else + pbuf = &bufs[BUF_TYPE_VIDEO]; + + /*if (!(port_get_inited(priv))) { + r = video_decoder_init(priv); + if (r < 0) + return r; + }*/ + + do { + if (vdec->port_flag & PORT_FLAG_DRM) + ret = drm_write(ada_ctx->filp, pbuf, buf, count); + else + ret = esparser_write(ada_ctx->filp, pbuf, buf, count); + + if (ret == -EAGAIN) + msleep(30); + } while (ret == -EAGAIN && try_cnt--); + + if (slow_input) { + v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_PRINFO, + "slow_input: es codec write size %x\n", ret); + msleep(10); + } + +#ifdef DATA_DEBUG + /* dump to file */ + //dump_write(vbuf, size); + //v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_PRINFO, "vbuf: %p, size: %u, ret: %d\n", vbuf, size, ret); +#endif + + return ret; +} + +bool vdec_input_full(struct aml_vdec_adapt *ada_ctx) +{ + struct vdec_s *vdec = ada_ctx->vdec; + + 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, ulong meta_ptr) +{ + int ret = -1; + struct vdec_s *vdec = ada_ctx->vdec; + + /* 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) { + v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_PRINFO, + "slow_input: frame codec write size %d\n", ret); + msleep(30); + } + + 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, + "write frames, vbuf: %p, size: %u, ret: %d, crc: %x, ts: %llu\n", + buf, count, ret, crc32_le(0, buf, count), timestamp); + + return ret; +} + +void vdec_vframe_input_free(void *priv, u32 handle) +{ + struct aml_vcodec_ctx *ctx = priv; + + aml_recycle_dma_buffers(ctx, handle); +} + +int vdec_vframe_write_with_dma(struct aml_vdec_adapt *ada_ctx, + ulong addr, u32 count, u64 timestamp, u32 handle, + chunk_free free, void* priv) +{ + int ret = -1; + struct vdec_s *vdec = ada_ctx->vdec; + + /* set timestamp */ + vdec_set_timestamp(vdec, timestamp); + + ret = vdec_write_vframe_with_dma(vdec, addr, count, + handle, free, priv); + + if (slow_input) { + v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_PRINFO, + "slow_input: frame codec write size %d\n", ret); + msleep(30); + } + + v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_INPUT, + "write frames, vbuf: %lx, size: %u, ret: %d, ts: %llu\n", + addr, count, ret, timestamp); + + return ret; +} + +void aml_decoder_flush(struct aml_vdec_adapt *ada_ctx) +{ + struct vdec_s *vdec = ada_ctx->vdec; + + if (vdec) + vdec_set_eos(vdec, true); +} + +int aml_codec_reset(struct aml_vdec_adapt *ada_ctx, int *mode) +{ + struct vdec_s *vdec = ada_ctx->vdec; + int ret = 0; + + if (vdec) { + if (ada_ctx->ctx->v4l_resolution_change) + *mode = V4L_RESET_MODE_LIGHT; + else + vdec_set_eos(vdec, false); + + v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_PRINFO, + "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; + } + + return ret; +} + +bool is_input_ready(struct aml_vdec_adapt *ada_ctx) +{ + struct vdec_s *vdec = ada_ctx->vdec; + int state = VDEC_STATUS_UNINITIALIZED; + + if (vdec) { + state = vdec_get_status(vdec); + + if (state == VDEC_STATUS_CONNECTED + || state == VDEC_STATUS_ACTIVE) + return true; + } + + return false; +} + +int vdec_frame_number(struct aml_vdec_adapt *ada_ctx) +{ + struct vdec_s *vdec = ada_ctx->vdec; + + if (vdec) + return vdec_get_frame_num(vdec); + else + 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; + + 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 new file mode 100644 index 0000000..c8641ce --- /dev/null +++ b/drivers/amvdec_ports/aml_vcodec_adapt.h
@@ -0,0 +1,79 @@ +/* +* 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 VDEC_ADAPT_H +#define VDEC_ADAPT_H + +#include <linux/amlogic/media/utils/vformat.h> +#include <linux/amlogic/media/utils/amstream.h> +#include "../stream_input/amports/streambuf.h" +#include "../frame_provider/decoder/utils/vdec_input.h" +#include "aml_vcodec_drv.h" + +struct aml_vdec_adapt { + int format; + void *vsi; + int32_t failure; + uint32_t inst_addr; + unsigned int signaled; + struct aml_vcodec_ctx *ctx; + wait_queue_head_t wq; + struct file *filp; + struct vdec_s *vdec; + struct stream_port_s port; + struct dec_sysinfo dec_prop; + struct v4l2_config_parm config; + int video_type; + char *frm_name; +}; + +int video_decoder_init(struct aml_vdec_adapt *ada_ctx); + +int video_decoder_release(struct aml_vdec_adapt *ada_ctx); + +int vdec_vbuf_write(struct aml_vdec_adapt *ada_ctx, + const char *buf, unsigned int count); + +int vdec_vframe_write(struct aml_vdec_adapt *ada_ctx, + const char *buf, unsigned int count, u64 timestamp, ulong meta_ptr); + +void vdec_vframe_input_free(void *priv, u32 handle); + +int vdec_vframe_write_with_dma(struct aml_vdec_adapt *ada_ctx, + ulong addr, u32 count, u64 timestamp, u32 handle, + chunk_free free, void *priv); + +bool vdec_input_full(struct aml_vdec_adapt *ada_ctx); + +void aml_decoder_flush(struct aml_vdec_adapt *ada_ctx); + +int aml_codec_reset(struct aml_vdec_adapt *ada_ctx, int *flag); + +extern void dump_write(const char __user *buf, size_t count); + +bool is_input_ready(struct aml_vdec_adapt *ada_ctx); + +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 new file mode 100644 index 0000000..2bbfb6e --- /dev/null +++ b/drivers/amvdec_ports/aml_vcodec_dec.c
@@ -0,0 +1,4593 @@ +/* +* 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 <media/v4l2-event.h> +#include <media/v4l2-mem2mem.h> +#include <media/videobuf2-dma-contig.h> +#include <media/videobuf2-dma-sg.h> + +#include <linux/delay.h> +#include <linux/atomic.h> +#include <linux/crc32.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_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 (9) //capture nv21 +#define CAP_FMT_I420_IDX (12) //use for mjpeg + +#define AML_VDEC_MIN_W 64U +#define AML_VDEC_MIN_H 64U +#define DFT_CFG_WIDTH AML_VDEC_MIN_W +#define DFT_CFG_HEIGHT AML_VDEC_MIN_H + +#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 + +#define call_void_memop(vb, op, args...) \ + do { \ + if ((vb)->vb2_queue->mem_ops->op) \ + (vb)->vb2_queue->mem_ops->op(args); \ + } while (0) + +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[] = { + { + .fourcc = V4L2_PIX_FMT_H264, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, + }, + { + .fourcc = V4L2_PIX_FMT_HEVC, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, + }, + { + .fourcc = V4L2_PIX_FMT_VP9, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, + }, + { + .fourcc = V4L2_PIX_FMT_MPEG1, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, + }, + { + .fourcc = V4L2_PIX_FMT_MPEG2, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, + }, + { + .fourcc = V4L2_PIX_FMT_MPEG4, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, + }, + { + .fourcc = V4L2_PIX_FMT_MJPEG, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + 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}, + }, + { + .fourcc = V4L2_PIX_FMT_NV21M, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, + }, + { + .fourcc = V4L2_PIX_FMT_NV12, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, + }, + { + .fourcc = V4L2_PIX_FMT_NV12M, + .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 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) +{ + ulong flags; + + spin_lock_irqsave(&ctx->slock, flags); + + return flags; +} + +static void aml_vcodec_ctx_unlock(struct aml_vcodec_ctx *ctx, ulong flags) +{ + 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; + unsigned int k; + + for (k = 0; k < NUM_FORMATS; k++) { + fmt = &aml_video_formats[k]; + if (fmt->fourcc == f->fmt.pix_mp.pixelformat) + return fmt; + } + + return NULL; +} + +static struct aml_q_data *aml_vdec_get_q_data(struct aml_vcodec_ctx *ctx, + enum v4l2_buf_type type) +{ + if (V4L2_TYPE_IS_OUTPUT(type)) + return &ctx->q_data[AML_Q_DATA_SRC]; + + return &ctx->q_data[AML_Q_DATA_DST]; +} + +void aml_vdec_dispatch_event(struct aml_vcodec_ctx *ctx, u32 changes) +{ + struct v4l2_event event = {0}; + + switch (changes) { + case V4L2_EVENT_SRC_CH_RESOLUTION: + case V4L2_EVENT_SRC_CH_HDRINFO: + case V4L2_EVENT_REQUEST_RESET: + case V4L2_EVENT_REQUEST_EXIT: + event.type = V4L2_EVENT_SOURCE_CHANGE; + event.u.src_change.changes = changes; + break; + case V4L2_EVENT_SEND_EOS: + event.type = V4L2_EVENT_EOS; + break; + default: + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "unsupport dispatch event %x\n", changes); + return; + } + + v4l2_event_queue_fh(&ctx->fh, &event); + if (changes != V4L2_EVENT_SRC_CH_HDRINFO) + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "changes: %x\n", changes); + else + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, "changes: %x\n", changes); +} + +static void aml_vdec_flush_decoder(struct aml_vcodec_ctx *ctx) +{ + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, "%s\n", __func__); + + aml_decoder_flush(ctx->ada_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) +{ + 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"); + 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) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "Cannot get correct pic info\n"); + return; + } + + /*if ((ctx->last_decoded_picinfo.visible_width == ctx->picinfo.visible_width) || + (ctx->last_decoded_picinfo.visible_height == ctx->picinfo.visible_height)) + return;*/ + + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + "new(%d,%d), old(%d,%d), real(%d,%d)\n", + ctx->last_decoded_picinfo.visible_width, + ctx->last_decoded_picinfo.visible_height, + ctx->picinfo.visible_width, ctx->picinfo.visible_height, + ctx->last_decoded_picinfo.coded_width, + ctx->last_decoded_picinfo.coded_width); + + ctx->picinfo = ctx->last_decoded_picinfo; + + if (ctx->vpp_is_need) + ctx->vpp_cfg.is_vpp_reset = true; + + v4l_buf_size_decision(ctx); + + 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_ctx *ctx = (struct aml_vcodec_ctx *) + priv_data->v4l_dec_ctx; + struct aml_video_dec_buf *vb = (struct aml_video_dec_buf *) + priv_data->vb_handle; + struct uvm_hook_mod_info *uvm = NULL; + + 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); +} + +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; + + flags = aml_vcodec_ctx_lock(ctx); + + 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; + } + + aml_vcodec_ctx_unlock(ctx, flags); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "%s done\n", __func__); +} + +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) +{ + 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 (!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; + } + } + + aml_vcodec_ctx_unlock(ctx, flags); + + 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); + } +} + +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) +{ + 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, + "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", + 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); + + vb2_v4l2 = container_of(vb2_buf, struct vb2_v4l2_buffer, vb2_buf); + + if (dstbuf->frame_buffer.num_planes == 1) { + 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(vb2_buf, 0, fb->m.mem[0].bytes_used); + vb2_set_plane_payload(vb2_buf, 1, fb->m.mem[1].bytes_used); + } + vb2_buf->timestamp = vf->timestamp; + dstbuf->vb.flags |= vf->frame_type; + + 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; + 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 = 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].length, 0); + pr_info("dump idx: %d %dx%d\n", dump_capture_frame, vf->width, vf->height); + 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(vb2_buf, 0, 0); + } else if (dstbuf->frame_buffer.num_planes == 2) { + 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", + vb2_buf->index, vb2_buf->state); + } + + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + "receive vbuf idx: %d, state: %d\n", + vb2_buf->index, vb2_buf->state); + + if (vf->flag & VFRAME_FLAG_EMPTY_FRAME_V4L) { + 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 + * before the resolution change point ready to be + * dequeued on the CAPTURE queue, the driver sends a + * V4L2_EVENT_SOURCE_CHANGE event for source change + * type V4L2_EVENT_SRC_CH_RESOLUTION, also the upper + * layer will get new information from cts->picinfo. + */ + aml_vdec_dispatch_event(ctx, V4L2_EVENT_SRC_CH_RESOLUTION); + } else + aml_vdec_dispatch_event(ctx, V4L2_EVENT_SEND_EOS); + } + + if (dstbuf->vb.vb2_buf.state == VB2_BUF_STATE_ACTIVE) { + /* binding vframe handle. */ + 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; + } + + 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("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 void fill_capture_done_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; + 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; + + if (ctx->is_stream_off) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_INPUT, + "ignore buff idx: %d streamoff\n", fb->buf_idx); + return; + } + + 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) { + /* + * make sure enough dst bufs for decoding. + */ + if ((ctx->dpb_size) && (ctx->cap_pool.in >= ctx->dpb_size)) + ctx->v4l_codec_dpb_ready = true; + + v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, + "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; + + if (!is_input_ready(ctx->ada_ctx)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "the decoder input has not ready.\n"); + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + return 0; + } + + if (ctx->state == AML_STATE_PROBE) { + mutex_lock(&ctx->state_lock); + if (ctx->state == AML_STATE_PROBE) { + ctx->state = AML_STATE_READY; + ATRACE_COUNTER("V_ST_VSINK-state", ctx->state); + v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, + "vcodec state (AML_STATE_READY)\n"); + } + mutex_unlock(&ctx->state_lock); + } + + mutex_lock(&ctx->state_lock); + if (ctx->state == AML_STATE_READY) { + if (ctx->m2m_ctx->out_q_ctx.q.streaming && + ctx->m2m_ctx->cap_q_ctx.q.streaming) { + ctx->state = AML_STATE_ACTIVE; + ATRACE_COUNTER("V_ST_VSINK-state", ctx->state); + v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, + "vcodec state (AML_STATE_ACTIVE)\n"); + } + } + mutex_unlock(&ctx->state_lock); + + /* check dpb ready */ + //aml_check_dpb_ready(ctx); + + return 1; +} + +static bool is_enough_work_items(struct aml_vcodec_ctx *ctx) +{ + struct aml_vcodec_dev *dev = ctx->dev; + + if (vdec_frame_number(ctx->ada_ctx) >= WORK_ITEMS_MAX) { + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + return false; + } + + return true; +} + +static void aml_wait_buf_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)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "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_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 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]); + + 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) +{ + struct aml_vcodec_ctx *ctx = + container_of(work, struct aml_vcodec_ctx, decode_work); + struct aml_vcodec_dev *dev = ctx->dev; + 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; + + if (ctx->state < AML_STATE_INIT || + ctx->state > AML_STATE_FLUSHED) { + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + goto out; + } + + if (!is_vdec_ready(ctx)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "the decoder has not ready.\n"); + goto out; + } + + 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; + + aml_buf = container_of(vb2_v4l2, struct aml_video_dec_buf, vb); + if (aml_buf->lastframe) { + ulong expires; + + /*the empty data use to flushed the decoder.*/ + v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, + "Got empty flush input buffer.\n"); + + /* + * 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. + */ + 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("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); + + 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. */ + aml_vdec_flush_decoder(ctx); + + goto out; + } + + 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", vb->index); + goto out; + } + + aml_buf->used = true; + + /* v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + "size: 0x%zx, crc: 0x%x\n", + buf.size, crc32(0, buf.va, buf.size));*/ + + /* pts = (time / 10e6) * (90k / fps) */ + /*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. + */ + 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-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_buf_ready(ctx); + + aml_buf->used = false; + aml_vdec_pic_info_update(ctx); + /* + * On encountering a resolution change in the stream. + * The driver must first process and decode all + * remaining buffers from before the resolution change + * point, so call flush decode here + */ + mutex_lock(&ctx->state_lock); + if (ctx->state == AML_STATE_ACTIVE) { + ctx->state = AML_STATE_FLUSHING;// prepare flushing + 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->v4l_resolution_change = true; + while (ctx->m2m_ctx->job_flags & TRANS_RUNNING) { + v4l2_m2m_job_pause(dev->m2m_dev_dec, ctx->m2m_ctx); + } + + aml_vdec_flush_decoder(ctx); + + goto out; + } else { + ATRACE_COUNTER("VO_OUT_VSINK-1.write_again", buf.size); + /* decoder is lack of resource, retry after short delay */ + if (vdec_get_instance_num() < 2) + usleep_range(2000, 4000); + } + + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); +out: + return; +} + +static void aml_vdec_reset(struct aml_vcodec_ctx *ctx) +{ + if (ctx->state == AML_STATE_ABORT) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "the decoder will be exited.\n"); + goto out; + } + + if (aml_codec_reset(ctx->ada_ctx, &ctx->reset_flag)) { + ctx->state = AML_STATE_ABORT; + ATRACE_COUNTER("V_ST_VSINK-state", ctx->state); + v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, + "vcodec state (AML_STATE_ABORT).\n"); + } +out: + complete(&ctx->comp); + return; +} + +void wait_vcodec_ending(struct aml_vcodec_ctx *ctx) +{ + /* disable queue output item to worker. */ + ctx->output_thread_ready = false; + ctx->is_stream_off = true; + + /* flush output buffer worker. */ + 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) + aml_vdec_reset(ctx); + + /* pause the job and clean trans status. */ + while (ctx->m2m_ctx->job_flags & TRANS_RUNNING) { + v4l2_m2m_job_pause(ctx->dev->m2m_dev_dec, ctx->m2m_ctx); + } + + ctx->v4l_codec_dpb_ready = false; +} + +void aml_thread_capture_worker(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; + + 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); + } +} +EXPORT_SYMBOL_GPL(aml_thread_capture_worker); + +static int vdec_capture_thread(void *data) +{ + struct aml_vdec_thread *thread = + (struct aml_vdec_thread *) data; + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *) thread->priv; + + for (;;) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + "%s, state: %d\n", __func__, ctx->state); + + if (down_interruptible(&thread->sem)) + break; + + if (thread->stop) + break; + + /* handle event. */ + thread->func(ctx); + } + + while (!kthread_should_stop()) { + usleep_range(1000, 2000); + } + + return 0; +} + +void aml_thread_post_task(struct aml_vcodec_ctx *ctx, + enum aml_thread_type type) +{ + struct aml_vdec_thread *thread = NULL; + ulong flags; + + spin_lock_irqsave(&ctx->tsplock, flags); + list_for_each_entry(thread, &ctx->vdec_thread_list, node) { + if (thread->task == NULL) + continue; + + if (thread->type == type) + up(&thread->sem); + } + spin_unlock_irqrestore(&ctx->tsplock, flags); +} +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) +{ + struct aml_vdec_thread *thread; + struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; + int ret = 0; + + thread = kzalloc(sizeof(*thread), GFP_KERNEL); + if (thread == NULL) + return -ENOMEM; + + thread->type = type; + thread->func = func; + thread->priv = ctx; + sema_init(&thread->sem, 0); + + 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; + goto err; + } + 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; + +err: + kfree(thread); + + return ret; +} +EXPORT_SYMBOL_GPL(aml_thread_start); + +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); + spin_lock_irqsave(&ctx->tsplock, flags); + list_del(&thread->node); + spin_unlock_irqrestore(&ctx->tsplock, flags); + + thread->stop = true; + up(&thread->sem); + kthread_stop(thread->task); + thread->task = NULL; + kfree(thread); + } +} +EXPORT_SYMBOL_GPL(aml_thread_stop); + +static int vidioc_try_decoder_cmd(struct file *file, void *priv, + struct v4l2_decoder_cmd *cmd) +{ + struct aml_vcodec_ctx *ctx = fh_to_ctx(priv); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, + "%s, cmd: %u\n", __func__, cmd->cmd); + + switch (cmd->cmd) { + case V4L2_DEC_CMD_STOP: + case V4L2_DEC_CMD_START: + 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; + } + break; + default: + return -EINVAL; + } + + return 0; +} + +static int vidioc_decoder_cmd(struct file *file, void *priv, + struct v4l2_decoder_cmd *cmd) +{ + struct aml_vcodec_ctx *ctx = fh_to_ctx(priv); + struct vb2_queue *src_vq, *dst_vq; + int ret; + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, + "%s, cmd: %u\n", __func__, cmd->cmd); + + ret = vidioc_try_decoder_cmd(file, priv, cmd); + if (ret) + return ret; + + switch (cmd->cmd) { + case V4L2_DEC_CMD_STOP: + src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (!vb2_is_streaming(src_vq)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "Output stream is off. No need to flush.\n"); + 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: + 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: + return -EINVAL; + } + + 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) +{ + struct v4l2_fh *fh = file->private_data; + struct aml_vcodec_ctx *ctx = fh_to_ctx(fh); + struct vb2_queue *q; + + q = v4l2_m2m_get_vq(fh->m2m_ctx, i); + if (!V4L2_TYPE_IS_OUTPUT(q->type) && + ctx->is_stream_off) { + if (ctx->vpp_is_need) { + int ret; + + 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; + } + 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; + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, + "%s, type: %d\n", __func__, q->type); + + return v4l2_m2m_ioctl_streamon(file, priv, i); +} + +static int vidioc_decoder_streamoff(struct file *file, void *priv, + enum v4l2_buf_type i) +{ + 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); + + 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); + + return v4l2_m2m_ioctl_streamoff(file, priv, i); +} + +static int vidioc_decoder_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *rb) +{ + struct aml_vcodec_ctx *ctx = fh_to_ctx(priv); + struct v4l2_fh *fh = file->private_data; + struct vb2_queue *q; + + q = v4l2_m2m_get_vq(fh->m2m_ctx, rb->type); + + 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 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_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 { + ctx->output_dma_mode = + (rb->memory == VB2_MEMORY_DMABUF) ? 1 : 0; + + v4l_dbg(ctx, V4L_DEBUG_CODEC_INPUT, + "output buffer memory mode is %d\n", rb->memory); + } + + return v4l2_m2m_ioctl_reqbufs(file, priv, rb); +} + +static int vidioc_vdec_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct aml_vcodec_ctx *ctx = fh_to_ctx(priv); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, + "%s, type: %d\n", __func__, buf->type); + + return v4l2_m2m_ioctl_querybuf(file, priv, buf); +} + +static int vidioc_vdec_expbuf(struct file *file, void *priv, + struct v4l2_exportbuffer *eb) +{ + struct aml_vcodec_ctx *ctx = fh_to_ctx(priv); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, + "%s, type: %d\n", __func__, eb->type); + + return v4l2_m2m_ioctl_expbuf(file, priv, eb); +} + +void aml_vcodec_dec_release(struct aml_vcodec_ctx *ctx) +{ + 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("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); + + vdec_if_deinit(ctx); +} + +void aml_vcodec_dec_set_default_params(struct aml_vcodec_ctx *ctx) +{ + struct aml_q_data *q_data; + + ctx->m2m_ctx->q_lock = &ctx->dev->dev_mutex; + ctx->fh.m2m_ctx = ctx->m2m_ctx; + ctx->fh.ctrl_handler = &ctx->ctrl_hdl; + INIT_WORK(&ctx->decode_work, aml_vdec_worker); + ctx->colorspace = V4L2_COLORSPACE_REC709; + ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + ctx->quantization = V4L2_QUANTIZATION_DEFAULT; + ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT; + ctx->dev->dec_capability = 0;//VCODEC_CAPABILITY_4K_DISABLED;//disable 4k + + q_data = &ctx->q_data[AML_Q_DATA_SRC]; + 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; + + q_data->sizeimage[0] = (1024 * 1024);//DFT_CFG_WIDTH * DFT_CFG_HEIGHT; //1m + q_data->bytesperline[0] = 0; + + q_data = &ctx->q_data[AML_Q_DATA_DST]; + 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[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, + AML_VDEC_MIN_W, + AML_VDEC_MAX_W, 4, + &q_data->coded_height, + AML_VDEC_MIN_H, + AML_VDEC_MAX_H, 5, 6); + + q_data->sizeimage[0] = q_data->coded_width * q_data->coded_height; + q_data->bytesperline[0] = q_data->coded_width; + q_data->sizeimage[1] = q_data->sizeimage[0] / 2; + 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("V_ST_VSINK-state", ctx->state); + v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, + "vcodec state (AML_STATE_IDLE)\n"); +} + +static int vidioc_vdec_qbuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct aml_vcodec_ctx *ctx = fh_to_ctx(priv); + int ret; + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, + "%s, type: %d\n", __func__, buf->type); + + if (ctx->state == AML_STATE_ABORT) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "Call on QBUF after unrecoverable error, type = %s\n", + V4L2_TYPE_IS_OUTPUT(buf->type) ? "OUT" : "IN"); + return -EIO; + } + + 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("VC_IN_VSINK-1.que_again", buf->index); + else + ATRACE_COUNTER("VC_IN_VSINK-0.que", buf->index); + } + + return ret; +} + +static int vidioc_vdec_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct aml_vcodec_ctx *ctx = fh_to_ctx(priv); + int ret; + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, + "%s, type: %d\n", __func__, buf->type); + + if (ctx->state == AML_STATE_ABORT) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "Call on DQBUF after unrecoverable error, type = %s\n", + V4L2_TYPE_IS_OUTPUT(buf->type) ? "OUT" : "IN"); + if (!V4L2_TYPE_IS_OUTPUT(buf->type)) + return -EIO; + } + + ret = v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); + 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) aml_buf; + aml_buf->privdata.v4l_dec_ctx = (ulong) ctx; + + file = fget(vb2_v4l2->private); + if (file && is_v4l2_buf_file(file)) { + dmabuf_fd_install_data(vb2_v4l2->private, + (void*)&aml_buf->privdata, + sizeof(struct file_private_data)); + 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); + } + } + + 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; +} + +static int vidioc_vdec_querycap(struct file *file, void *priv, + 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); + + return 0; +} + +static int vidioc_vdec_subscribe_evt(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + struct aml_vcodec_ctx *ctx = fh_to_ctx(fh); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, + "%s, type: %d\n", __func__, sub->type); + + switch (sub->type) { + case V4L2_EVENT_EOS: + return v4l2_event_subscribe(fh, sub, 2, NULL); + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_src_change_event_subscribe(fh, sub); + default: + return v4l2_ctrl_subscribe_event(fh, sub); + } +} + +static int vidioc_vdec_event_unsubscribe(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + struct aml_vcodec_ctx *ctx = fh_to_ctx(fh); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s, type: %d\n", + __func__, sub->type); + + return v4l2_event_unsubscribe(fh, sub); +} + +static int vidioc_try_fmt(struct v4l2_format *f, struct aml_video_fmt *fmt) +{ + int i; + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct v4l2_pix_format *pix = &f->fmt.pix; + + 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; + + 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; + + 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); + + pix_mp->num_planes = fmt->num_planes; + + pix_mp->plane_fmt[0].bytesperline = pix_mp->width; + pix_mp->plane_fmt[0].sizeimage = + pix_mp->width * pix_mp->height; + + 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; + } + + return 0; +} + +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: %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; + + 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, + struct v4l2_selection *s) +{ + 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: + 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 / ratio; + s->r.height = ctx->picinfo.coded_height / ratio; + break; + default: + return -EINVAL; + } + + if (ctx->state < AML_STATE_PROBE) { + /* 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; + } + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s, type: %d\n", + __func__, s->type); + + return 0; +} + +static int vidioc_vdec_s_selection(struct file *file, void *priv, + 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); + + 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 / ratio; + s->r.height = ctx->picinfo.visible_height / ratio; + break; + default: + return -EINVAL; + } + + return 0; +} + +/* called when it is beyong AML_STATE_PROBE */ +static void update_ctx_dimension(struct aml_vcodec_ctx *ctx, u32 type) +{ + struct aml_q_data *q_data; + unsigned int dw_mode = VDEC_DW_NO_AFBC; + int ratio = 1; + + 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); + } + + 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) +{ + 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: %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; + + 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 (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) { + q_data->sizeimage[0] = pix_mp->plane_fmt[0].sizeimage; + q_data->coded_width = pix_mp->width; + q_data->coded_height = pix_mp->height; + + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + "w: %d, h: %d, size: %d\n", + 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; + ctx->xfer_func = f->fmt.pix_mp.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"); + } + 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"); + } + mutex_unlock(&ctx->state_lock); + } + + if (!V4L2_TYPE_IS_OUTPUT(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; +} + +static int vidioc_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) +{ + int i = 0; + struct aml_vcodec_ctx *ctx = fh_to_ctx(priv); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s, idx: %d, pix fmt: %x\n", + __func__, fsize->index, fsize->pixel_format); + + if (fsize->index != 0) + return -EINVAL; + + for (i = 0; i < NUM_SUPPORTED_FRAMESIZE; ++i) { + if (fsize->pixel_format != aml_vdec_framesizes[i].fourcc) + continue; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise = aml_vdec_framesizes[i].stepwise; + if (!(ctx->dev->dec_capability & + VCODEC_CAPABILITY_4K_DISABLED)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, "4K is enabled\n"); + fsize->stepwise.max_width = + VCODEC_DEC_4K_CODED_WIDTH; + fsize->stepwise.max_height = + VCODEC_DEC_4K_CODED_HEIGHT; + } + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + "%x, %d %d %d %d %d %d\n", + ctx->dev->dec_capability, + fsize->stepwise.min_width, + fsize->stepwise.max_width, + fsize->stepwise.step_width, + fsize->stepwise.min_height, + fsize->stepwise.max_height, + fsize->stepwise.step_height); + return 0; + } + + return -EINVAL; +} + +static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) +{ + struct aml_video_fmt *fmt; + int i = 0, j = 0; + + /* 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 && (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) { + f->pixelformat = fmt->fourcc; + return 0; + } + ++j; + } + + return -EINVAL; +} + +static int vidioc_vdec_enum_fmt_vid_cap_mplane(struct file *file, + void *priv, struct v4l2_fmtdesc *f) +{ + struct aml_vcodec_ctx *ctx = fh_to_ctx(priv); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s\n", __func__); + + return vidioc_enum_fmt(f, false); +} + +static int vidioc_vdec_enum_fmt_vid_out_mplane(struct file *file, + void *priv, struct v4l2_fmtdesc *f) +{ + struct aml_vcodec_ctx *ctx = fh_to_ctx(priv); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s\n", __func__); + + return vidioc_enum_fmt(f, true); +} + +static int vidioc_vdec_g_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 = &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; + + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + if (!vq) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "no vb2 queue for type=%d\n", f->type); + 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)) { + pix_mp->field = ret ? V4L2_FIELD_NONE : ctx->picinfo.field; + pix_mp->colorspace = ctx->colorspace; + pix_mp->ycbcr_enc = ctx->ycbcr_enc; + pix_mp->quantization = ctx->quantization; + pix_mp->xfer_func = ctx->xfer_func; + } else { + pix->field = ret ? V4L2_FIELD_NONE : ctx->picinfo.field; + pix->colorspace = ctx->colorspace; + pix->ycbcr_enc = ctx->ycbcr_enc; + pix->quantization = ctx->quantization; + pix->xfer_func = ctx->xfer_func; + } + + if ((!V4L2_TYPE_IS_OUTPUT(f->type)) && + (ctx->state >= AML_STATE_PROBE)) { + 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 + * The buffer contains compressed image + * so width and height have no meaning. + * Assign value here to pass v4l2-compliance test + */ + copy_v4l2_format_dimention(pix_mp, pix, q_data, f->type); + } else { + 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); + } + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, + "%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; +} + +static int vidioc_vdec_create_bufs(struct file *file, void *priv, + struct v4l2_create_buffers *create) +{ + struct aml_vcodec_ctx *ctx = fh_to_ctx(priv); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, + "%s, type: %u, count: %u\n", + __func__, create->format.type, create->count); + + return v4l2_m2m_ioctl_create_bufs(file, priv, create); +} + +/*int vidioc_vdec_g_ctrl(struct file *file, void *fh, + struct v4l2_control *a) +{ + struct aml_vcodec_ctx *ctx = fh_to_ctx(fh); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, + "%s, id: %d\n", __func__, a->id); + + if (a->id == V4L2_CID_MIN_BUFFERS_FOR_CAPTURE) + a->value = 4; + else if (a->id == V4L2_CID_MIN_BUFFERS_FOR_OUTPUT) + a->value = 8; + + return 0; +}*/ + +static int vb2ops_vdec_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, + unsigned int *nplanes, + unsigned int sizes[], struct device *alloc_devs[]) +{ + struct aml_vcodec_ctx *ctx = vb2_get_drv_priv(vq); + struct aml_q_data *q_data; + unsigned int i; + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s, type: %d\n", + __func__, vq->type); + + q_data = aml_vdec_get_q_data(ctx, vq->type); + if (q_data == NULL) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "vq->type=%d err\n", vq->type); + return -EINVAL; + } + + if (*nplanes) { + for (i = 0; i < *nplanes; i++) { + if (sizes[i] < q_data->sizeimage[i]) + return -EINVAL; + 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] = 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(); + } + } + + v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, + "type: %d, plane: %d, buf cnt: %d, size: [Y: %u, C: %u]\n", + vq->type, *nplanes, *nbuffers, sizes[0], sizes[1]); + + return 0; +} + +static int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb) +{ + 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, + "%s, type: %d, idx: %d\n", + __func__, vb->vb2_queue->type, vb->index); + + if (vb->memory == VB2_MEMORY_DMABUF + && V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) + return 0; + + q_data = aml_vdec_get_q_data(ctx, vb->vb2_queue->type); + + for (i = 0; i < q_data->fmt->num_planes; i++) { + if (vb2_plane_size(vb, i) < q_data->sizeimage[i]) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "data will not fit into plane %d (%lu < %d)\n", + i, vb2_plane_size(vb, i), + q_data->sizeimage[i]); + } + } + + 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 = 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; + + 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)) { + u32 dw_mode = VDEC_DW_NO_AFBC; + + 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)); + + /* 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 { + struct vframe_s *vf = fb->vframe; + struct task_chain_s *task = fb->task; + + 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; + } + + v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb)); + + if (ctx->state != AML_STATE_INIT) { + 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 = 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)) { + wake_up_interruptible(&ctx->wq); + } else { + v4l2_buff_done(to_vb2_v4l2_buffer(vb), + VB2_BUF_STATE_DONE); + } + + return; + } + + /* + * If on model dmabuf must remove the buffer + * because this data has been consumed by hw. + */ + 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_buff_done(to_vb2_v4l2_buffer(vb), + VB2_BUF_STATE_DONE); + } + + if (vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, &ctx->picinfo)) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "GET_PARAM_PICTURE_INFO err\n"); + return; + } + + if (!ctx->picinfo.dpb_frames) + return; + + 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("V_ST_VSINK-state", ctx->state); + v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, + "vcodec state (AML_STATE_PROBE)\n"); + } + mutex_unlock(&ctx->state_lock); +} + +static void vb2ops_vdec_buf_finish(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; + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, + "%s, type: %d, idx: %d\n", + __func__, vb->vb2_queue->type, vb->index); + + vb2_v4l2 = to_vb2_v4l2_buffer(vb); + buf = container_of(vb2_v4l2, struct aml_video_dec_buf, vb); + + if (buf->error) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "Unrecoverable error on buffer.\n"); + ctx->state = AML_STATE_ABORT; + ATRACE_COUNTER("V_ST_VSINK-state", ctx->state); + v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, + "vcodec state (AML_STATE_ABORT)\n"); + } +} + +static int vb2ops_vdec_buf_init(struct vb2_buffer *vb) +{ + 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; + 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->lastframe = false; + } + + /* codec_mm buffers count */ + if (!V4L2_TYPE_IS_OUTPUT(vb->type)) { + if (vb->memory == VB2_MEMORY_MMAP) { + 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); + + 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; + + for (i = 0; i < vb->num_planes; i++) { + struct dma_buf * dma; + + 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"); + } + } + } + + 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 vb2ops_vdec_buf_cleanup(struct vb2_buffer *vb) +{ + 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;; + + 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->type)) { + if (vb->memory == VB2_MEMORY_MMAP) { + int i; + + 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 (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); + } + } + } +} + +static int vb2ops_vdec_start_streaming(struct vb2_queue *q, unsigned int count) +{ + 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); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, + "%s, type: %d\n", __func__, q->type); + + return 0; +} + +static void vb2ops_vdec_stop_streaming(struct vb2_queue *q) +{ + struct aml_video_dec_buf *buf = NULL; + struct vb2_v4l2_buffer *vb2_v4l2 = NULL; + struct aml_vcodec_ctx *ctx = vb2_get_drv_priv(q); + int i; + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, + "%s, type: %d, state: %x, frame_cnt: %d\n", + __func__, q->type, ctx->state, ctx->decoded_frame_cnt); + + 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_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_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) { + 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_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_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_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; + ctx->cap_pool.dec = 0; + ctx->cap_pool.vpp = 0; + } +} + +static void m2mops_vdec_device_run(void *priv) +{ + struct aml_vcodec_ctx *ctx = priv; + struct aml_vcodec_dev *dev = ctx->dev; + + if (ctx->output_thread_ready) + queue_work(dev->decode_workqueue, &ctx->decode_work); +} + +static int m2mops_vdec_job_ready(void *m2m_priv) +{ + struct aml_vcodec_ctx *ctx = m2m_priv; + + if (ctx->state < AML_STATE_PROBE || + ctx->state > AML_STATE_FLUSHED) + return 0; + + return 1; +} + +static void m2mops_vdec_job_abort(void *priv) +{ + struct aml_vcodec_ctx *ctx = priv; + + v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, "%s\n", __func__); +} + +static int aml_vdec_g_v_ctrl(struct v4l2_ctrl *ctrl) +{ + struct aml_vcodec_ctx *ctx = ctrl_to_ctx(ctrl); + int ret = 0; + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, + "%s, id: %d\n", __func__, ctrl->id); + + switch (ctrl->id) { + case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: + if (ctx->state >= AML_STATE_PROBE) { + ctrl->val = CTX_BUF_TOTAL(ctx); + } else { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "Seqinfo not ready.\n"); + ctrl->val = 0; + } + 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; + } + return ret; +} + +static int aml_vdec_try_s_v_ctrl(struct v4l2_ctrl *ctrl) +{ + struct aml_vcodec_ctx *ctx = ctrl_to_ctx(ctrl); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s\n", __func__); + + if (ctrl->id == AML_V4L2_SET_DRMMODE) { + ctx->is_drm_mode = ctrl->val; + 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; +} + +static const struct v4l2_ctrl_ops aml_vcodec_dec_ctrl_ops = { + .g_volatile_ctrl = aml_vdec_g_v_ctrl, + .try_ctrl = aml_vdec_try_s_v_ctrl, +}; + +static const struct v4l2_ctrl_config ctrl_st_mode = { + .name = "drm mode", + .id = AML_V4L2_SET_DRMMODE, + .ops = &aml_vcodec_dec_ctrl_ops, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .flags = V4L2_CTRL_FLAG_WRITE_ONLY, + .min = 0, + .max = 1, + .step = 1, + .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; + struct v4l2_ctrl *ctrl; + + v4l2_ctrl_handler_init(&ctx->ctrl_hdl, 3); + ctrl = v4l2_ctrl_new_std(&ctx->ctrl_hdl, + &aml_vcodec_dec_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + 0, 32, 1, 2); + 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; + + 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_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; + } + + v4l2_ctrl_handler_setup(&ctx->ctrl_hdl); + + return 0; +err: + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "Adding control failed %d\n", + ctx->ctrl_hdl.error); + v4l2_ctrl_handler_free(&ctx->ctrl_hdl); + return ret; +} + +static int vidioc_vdec_g_parm(struct file *file, void *fh, + struct v4l2_streamparm *a) +{ + struct aml_vcodec_ctx *ctx = fh_to_ctx(fh); + struct vb2_queue *dst_vq; + + 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"); + 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__); + + 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__); + + 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 (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) + dec->hdr = in->hdr; + if (in->parms_status & V4L2_CONFIG_PARM_DECODE_CNTINFO) + 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; +} + + +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, +}; + +static const struct vb2_ops aml_vdec_vb2_ops = { + .queue_setup = vb2ops_vdec_queue_setup, + .buf_prepare = vb2ops_vdec_buf_prepare, + .buf_queue = vb2ops_vdec_buf_queue, + .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, +}; + +const struct v4l2_ioctl_ops aml_vdec_ioctl_ops = { + .vidioc_streamon = vidioc_decoder_streamon, + .vidioc_streamoff = vidioc_decoder_streamoff, + .vidioc_reqbufs = vidioc_decoder_reqbufs, + .vidioc_querybuf = vidioc_vdec_querybuf, + .vidioc_expbuf = vidioc_vdec_expbuf, + //.vidioc_g_ctrl = vidioc_vdec_g_ctrl, + + .vidioc_qbuf = vidioc_vdec_qbuf, + .vidioc_dqbuf = vidioc_vdec_dqbuf, + + .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, + .vidioc_s_fmt_vid_out_mplane = vidioc_vdec_s_fmt, + .vidioc_s_fmt_vid_out = vidioc_vdec_s_fmt, + .vidioc_g_fmt_vid_cap_mplane = vidioc_vdec_g_fmt, + .vidioc_g_fmt_vid_cap = vidioc_vdec_g_fmt, + .vidioc_g_fmt_vid_out_mplane = vidioc_vdec_g_fmt, + .vidioc_g_fmt_vid_out = vidioc_vdec_g_fmt, + + .vidioc_create_bufs = vidioc_vdec_create_bufs, + + //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 = 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_decoder_cmd = vidioc_decoder_cmd, + .vidioc_try_decoder_cmd = vidioc_try_decoder_cmd, + + .vidioc_g_parm = vidioc_vdec_g_parm, + .vidioc_s_parm = vidioc_vdec_s_parm, +}; + +int aml_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct aml_vcodec_ctx *ctx = priv; + int ret = 0; + + 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 | 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_sg_memops; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = &ctx->dev->dev_mutex; + ret = vb2_queue_init(src_vq); + if (ret) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "Failed to initialize videobuf2 queue(output)\n"); + return ret; + } + + dst_vq->type = multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : + V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR; + dst_vq->drv_priv = ctx; + dst_vq->buf_struct_size = sizeof(struct aml_video_dec_buf); + dst_vq->ops = &aml_vdec_vb2_ops; + 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); + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "Failed to initialize videobuf2 queue(capture)\n"); + } + + return ret; +} +
diff --git a/drivers/amvdec_ports/aml_vcodec_dec.h b/drivers/amvdec_ports/aml_vcodec_dec.h new file mode 100644 index 0000000..a23522c --- /dev/null +++ b/drivers/amvdec_ports/aml_vcodec_dec.h
@@ -0,0 +1,148 @@ +/* +* 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_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 +#define VCODEC_DEC_4K_CODED_HEIGHT 2304U +#define AML_VDEC_MAX_W 2048U +#define AML_VDEC_MAX_H 1088U + +#define AML_VDEC_IRQ_STATUS_DEC_SUCCESS 0x10000 +#define V4L2_BUF_FLAG_LAST 0x00100000 + +#define VDEC_GATHER_MEMORY_TYPE 0 +#define VDEC_SCATTER_MEMORY_TYPE 1 + +#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 + * @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 { + int mem_type; + int num_planes; + union { + struct aml_vcodec_mem mem[4]; + u32 vf_fd; + } m; + u32 status; + u32 buf_idx; + void *vframe; + + struct task_chain_s *task; +}; + +/** + * struct aml_video_dec_buf - Private data related to each VB2 buffer. + * @b: VB2 buffer + * @list: link list + * @used: Capture buffer contain decoded frame data and keep in + * codec data structure + * @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 + * + * Note : These status information help us track and debug buffer state + */ +struct aml_video_dec_buf { + struct vb2_v4l2_buffer vb; + struct list_head list; + + struct vdec_v4l2_buffer frame_buffer; + struct file_private_data privdata; + struct codec_mm_s *mem[2]; + char mem_onwer[32]; + bool used; + bool que_in_m2m; + 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; +extern const struct v4l2_m2m_ops aml_vdec_m2m_ops; + +/* + * aml_vdec_lock/aml_vdec_unlock are for ctx instance to + * get/release lock before/after access decoder hw. + * aml_vdec_lock get decoder hw lock and set curr_ctx + * to ctx instance that get lock + */ +void aml_vdec_unlock(struct aml_vcodec_ctx *ctx); +void aml_vdec_lock(struct aml_vcodec_ctx *ctx); +int aml_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq); +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 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 new file mode 100644 index 0000000..18f0254 --- /dev/null +++ b/drivers/amvdec_ports/aml_vcodec_dec_drv.c
@@ -0,0 +1,754 @@ +/* +* 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/slab.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/of.h> +#include <media/v4l2-event.h> +#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_vpp.h" +#include <linux/file.h> +#include <linux/anon_inodes.h> + +#define VDEC_HW_ACTIVE 0x10 +#define VDEC_IRQ_CFG 0x11 +#define VDEC_IRQ_CLR 0x10 +#define VDEC_IRQ_CFG_REG 0xa4 + +#define V4LVIDEO_IOC_MAGIC 'I' +#define V4LVIDEO_IOCTL_ALLOC_FD _IOW(V4LVIDEO_IOC_MAGIC, 0x02, int) +#define V4LVIDEO_IOCTL_CHECK_FD _IOW(V4LVIDEO_IOC_MAGIC, 0x03, int) +#define V4LVIDEO_IOCTL_SET_CONFIG_PARAMS _IOWR(V4LVIDEO_IOC_MAGIC, 0x04, struct v4l2_config_parm) +#define V4LVIDEO_IOCTL_GET_CONFIG_PARAMS _IOWR(V4LVIDEO_IOC_MAGIC, 0x05, struct v4l2_config_parm) + +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) +{ + struct aml_vcodec_dev *dev = video_drvdata(file); + struct aml_vcodec_ctx *ctx = NULL; + struct aml_video_dec_buf *aml_buf = NULL; + int ret = 0; + struct vb2_queue *src_vq; + + 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++; + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; + 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->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) { + ctx->is_drm_mode = true; + ctx->param_sets_from_ucode = true; + } + + ctx->type = AML_INST_DECODER; + ret = aml_vcodec_dec_ctrls_setup(ctx); + if (ret) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "Failed to setup vcodec controls\n"); + goto err_ctrls_setup; + } + ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev_dec, ctx, + &aml_vcodec_dec_queue_init); + if (IS_ERR((__force void *)ctx->m2m_ctx)) { + ret = PTR_ERR((__force void *)ctx->m2m_ctx); + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "Failed to v4l2_m2m_ctx_init() (%d)\n", ret); + goto err_m2m_ctx_init; + } + src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + 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; + + 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"); + goto err_creat_thread; + } + + list_add(&ctx->list, &dev->ctx_list); + + mutex_unlock(&dev->dev_mutex); + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "%s decoder %lx\n", + dev_name(&dev->plat_dev->dev), (ulong)ctx); + + return 0; + + /* Deinit when failure occurred */ +err_creat_thread: + v4l2_m2m_ctx_release(ctx->m2m_ctx); +err_m2m_ctx_init: + v4l2_ctrl_handler_free(&ctx->ctrl_hdl); +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); + + return ret; +} + +static int fops_vcodec_release(struct file *file) +{ + struct aml_vcodec_dev *dev = video_drvdata(file); + struct aml_vcodec_ctx *ctx = fh_to_ctx(file->private_data); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "release decoder %lx\n", (ulong) ctx); + mutex_lock(&dev->dev_mutex); + + aml_thread_stop(ctx); + wait_vcodec_ending(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); + kref_put(&ctx->ctx_ref, aml_v4l_ctx_release); + mutex_unlock(&dev->dev_mutex); + return 0; +} + +static int v4l2video_file_release(struct inode *inode, struct file *file) +{ + v4l_dbg(0, V4L_DEBUG_CODEC_BUFMGR, "file: %lx, data: %lx\n", + (ulong) file, (ulong) file->private_data); + + if (file->private_data) + vdec_frame_buffer_release(file->private_data); + + return 0; +} + +const struct file_operations v4l2_file_fops = { + .release = v4l2video_file_release, +}; + +int v4l2_alloc_fd(int *fd) +{ + struct file *file = NULL; + int file_fd = get_unused_fd_flags(O_CLOEXEC); + + if (file_fd < 0) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "get unused fd fail\n"); + return -ENODEV; + } + + file = anon_inode_getfile("v4l2_meta_file", &v4l2_file_fops, NULL, 0); + if (IS_ERR(file)) { + put_unused_fd(file_fd); + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "anon_inode_getfile fail\n"); + return -ENODEV; + } + + file->private_data = + kzalloc(sizeof(struct file_private_data), GFP_KERNEL); + if (!file->private_data) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "alloc priv data faild.\n"); + return -ENOMEM; + } + + v4l_dbg(0, V4L_DEBUG_CODEC_BUFMGR, "fd %d, file %lx, data: %lx\n", + file_fd, (ulong) file, (ulong) file->private_data); + + fd_install(file_fd, file); + *fd = file_fd; + + return 0; +} + +extern const struct file_operations v4l2_file_fops; +bool is_v4l2_buf_file(struct file *file) +{ + return file->f_op == &v4l2_file_fops; +} + +int v4l2_check_fd(int fd) +{ + struct file *file; + + file = fget(fd); + + if (!file) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "fget fd %d fail!\n", fd); + return -EBADF; + } + + if (!is_v4l2_buf_file(file)) { + fput(file); + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "is_v4l2_buf_file fail!\n"); + return -1; + } + + fput(file); + + v4l_dbg(0, V4L_DEBUG_CODEC_EXINFO, + "ioctl ok, comm %s, pid %d\n", + current->comm, current->pid); + + return 0; +} + +int dmabuf_fd_install_data(int fd, void* data, u32 size) +{ + struct file *file; + + file = fget(fd); + + if (!file) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "fget fd %d fail!, comm %s, pid %d\n", + fd, current->comm, current->pid); + return -EBADF; + } + + if (!is_v4l2_buf_file(file)) { + fput(file); + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "the buf file checked fail!\n"); + return -EBADF; + } + + memcpy(file->private_data, data, size); + + fput(file); + + return 0; +} + +void* v4l_get_vf_handle(int fd) +{ + struct file *file; + struct file_private_data *data = NULL; + void *vf_handle = 0; + + file = fget(fd); + + if (!file) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "fget fd %d fail!, comm %s, pid %d\n", + fd, current->comm, current->pid); + return NULL; + } + + 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; + } + + data = (struct file_private_data*) file->private_data; + if (data) { + vf_handle = &data->vf; + v4l_dbg(0, V4L_DEBUG_CODEC_BUFMGR, "file: %lx, data: %lx\n", + (ulong) file, (ulong) data); + } + + fput(file); + + return vf_handle; +} + + +static long v4l2_vcodec_ioctl(struct file *file, + unsigned int cmd, + ulong arg) +{ + long ret = 0; + void __user *argp = (void __user *)arg; + + switch (cmd) { + case V4LVIDEO_IOCTL_ALLOC_FD: + { + u32 v4lvideo_fd = 0; + + ret = v4l2_alloc_fd(&v4lvideo_fd); + if (ret != 0) + break; + put_user(v4lvideo_fd, (u32 __user *)argp); + v4l_dbg(0, V4L_DEBUG_CODEC_EXINFO, + "V4LVIDEO_IOCTL_ALLOC_FD fd %d\n", + v4lvideo_fd); + break; + } + case V4LVIDEO_IOCTL_CHECK_FD: + { + u32 v4lvideo_fd = 0; + + get_user(v4lvideo_fd, (u32 __user *)argp); + ret = v4l2_check_fd(v4lvideo_fd); + if (ret != 0) + break; + v4l_dbg(0, V4L_DEBUG_CODEC_EXINFO, + "V4LVIDEO_IOCTL_CHECK_FD fd %d\n", + v4lvideo_fd); + break; + } + case V4LVIDEO_IOCTL_SET_CONFIG_PARAMS: + { + struct aml_vcodec_ctx *ctx = NULL; + + if (is_v4l2_buf_file(file)) + break; + + ctx = fh_to_ctx(file->private_data); + if (copy_from_user((void *)&ctx->config, + (void *)argp, sizeof(ctx->config))) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "set config parm err\n"); + return -EFAULT; + } + break; + } + case V4LVIDEO_IOCTL_GET_CONFIG_PARAMS: + { + struct aml_vcodec_ctx *ctx = NULL; + + if (is_v4l2_buf_file(file)) + break; + + ctx = fh_to_ctx(file->private_data); + if (copy_to_user((void *)argp, + (void *)&ctx->config, sizeof(ctx->config))) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "get config parm err\n"); + return -EFAULT; + } + break; + } + default: + return video_ioctl2(file, cmd, arg); + } + return ret; +} + +#ifdef CONFIG_COMPAT +static long v4l2_compat_ioctl(struct file *file, + unsigned int cmd, ulong arg) +{ + long ret = 0; + + ret = v4l2_vcodec_ioctl(file, cmd, (ulong)compat_ptr(arg)); + return ret; +} +#endif + +static const struct v4l2_file_operations aml_vcodec_fops = { + .owner = THIS_MODULE, + .open = fops_vcodec_open, + .release = fops_vcodec_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = v4l2_vcodec_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = v4l2_compat_ioctl, +#endif + .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; + struct video_device *vfd_dec; + int ret = 0; + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + 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); + spin_lock_init(&dev->irqlock); + + snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s", + "[/AML_V4L2_VDEC]"); + + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + if (ret) { + dev_err(&pdev->dev, "v4l2_device_register err=%d\n", ret); + goto err_res; + } + + init_waitqueue_head(&dev->queue); + + vfd_dec = video_device_alloc(); + if (!vfd_dec) { + dev_err(&pdev->dev, "Failed to allocate video device\n"); + ret = -ENOMEM; + goto err_dec_alloc; + } + + vfd_dec->fops = &aml_vcodec_fops; + vfd_dec->ioctl_ops = &aml_vdec_ioctl_ops; + vfd_dec->release = video_device_release; + vfd_dec->lock = &dev->dev_mutex; + 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; + + snprintf(vfd_dec->name, sizeof(vfd_dec->name), "%s", + AML_VCODEC_DEC_NAME); + video_set_drvdata(vfd_dec, dev); + dev->vfd_dec = vfd_dec; + platform_set_drvdata(pdev, dev); + + dev->m2m_dev_dec = v4l2_m2m_init(&aml_vdec_m2m_ops); + if (IS_ERR((__force void *)dev->m2m_dev_dec)) { + 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("output-worker", + __WQ_LEGACY | WQ_MEM_RECLAIM | WQ_HIGHPRI); + if (!dev->decode_workqueue) { + dev_err(&pdev->dev, "Failed to create decode workqueue\n"); + ret = -EINVAL; + goto err_event_workq; + } + + //dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num); + + ret = video_register_device(vfd_dec, VFL_TYPE_GRABBER, 26); + if (ret) { + dev_err(&pdev->dev, "Failed to register video device\n"); + goto err_dec_reg; + } + + /*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: + v4l2_m2m_release(dev->m2m_dev_dec); +err_dec_mem_init: + video_unregister_device(vfd_dec); +err_dec_alloc: + v4l2_device_unregister(&dev->v4l2_dev); +err_res: + + return ret; +} + +static int aml_vcodec_dec_remove(struct platform_device *pdev) +{ + struct aml_vcodec_dev *dev = platform_get_drvdata(pdev); + + 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); + + if (dev->vfd_dec) + video_unregister_device(dev->vfd_dec); + + v4l2_device_unregister(&dev->v4l2_dev); + + dev_info(&pdev->dev, "v4ldec removed.\n"); + + return 0; +} + +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, + .remove = aml_vcodec_dec_remove, + .driver = { + .name = AML_VCODEC_DEC_NAME, + .of_match_table = aml_vcodec_match, + }, +}; + +static int __init amvdec_ports_init(void) +{ + pr_info("v4l dec module init\n"); + + if (platform_driver_register(&aml_vcodec_dec_driver)) { + pr_err("failed to register v4l dec driver\n"); + return -ENODEV; + } + + return 0; +} + +static void __exit amvdec_ports_exit(void) +{ + pr_info("v4l dec module exit\n"); + + platform_driver_unregister(&aml_vcodec_dec_driver); +} + +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); + +int aml_set_vfm_path; +EXPORT_SYMBOL(aml_set_vfm_path); +module_param(aml_set_vfm_path, int, 0644); + +bool aml_set_vdec_type_enable; +EXPORT_SYMBOL(aml_set_vdec_type_enable); +module_param(aml_set_vdec_type_enable, bool, 0644); + +int aml_set_vdec_type; +EXPORT_SYMBOL(aml_set_vdec_type); +module_param(aml_set_vdec_type, int, 0644); + +int vp9_need_prefix; +EXPORT_SYMBOL(vp9_need_prefix); +module_param(vp9_need_prefix, int, 0644); + +int av1_need_prefix; +EXPORT_SYMBOL(av1_need_prefix); +module_param(av1_need_prefix, int, 0644); + +bool multiplanar; +EXPORT_SYMBOL(multiplanar); +module_param(multiplanar, bool, 0644); + +int dump_capture_frame; +EXPORT_SYMBOL(dump_capture_frame); +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 new file mode 100644 index 0000000..522fe67 --- /dev/null +++ b/drivers/amvdec_ports/aml_vcodec_drv.h
@@ -0,0 +1,788 @@ +/* +* 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_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" +#define AML_VCODEC_ENC_NAME "aml-vcodec-enc" +#define AML_PLATFORM_STR "platform:amlogic" + +#define AML_VCODEC_MAX_PLANES 3 +#define AML_V4L2_BENCHMARK 0 +#define WAIT_INTR_TIMEOUT_MS 1000 + +/* codec types of get/set parms. */ +#define V4L2_CONFIG_PARM_ENCODE (0) +#define V4L2_CONFIG_PARM_DECODE (1) + +/* types of decode parms. */ +#define V4L2_CONFIG_PARM_DECODE_CFGINFO (1 << 0) +#define V4L2_CONFIG_PARM_DECODE_PSINFO (1 << 1) +#define V4L2_CONFIG_PARM_DECODE_HDRINFO (1 << 2) +#define V4L2_CONFIG_PARM_DECODE_CNTINFO (1 << 3) + +/* amlogic event define. */ +/* #define V4L2_EVENT_SRC_CH_RESOLUTION (1 << 0) */ +#define V4L2_EVENT_SRC_CH_HDRINFO (1 << 1) +#define V4L2_EVENT_SRC_CH_PSINFO (1 << 2) +#define V4L2_EVENT_SRC_CH_CNTINFO (1 << 3) + +/* exception handing */ +#define V4L2_EVENT_REQUEST_RESET (1 << 8) +#define V4L2_EVENT_REQUEST_EXIT (1 << 9) + +/* eos event */ +#define V4L2_EVENT_SEND_EOS (1 << 16) + +/* v4l buffer pool */ +#define V4L_CAP_BUFF_MAX (32) +#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. */ +#define V4L_RESET_MODE_LIGHT (1 << 1) /* just only reset decoder. */ + +/* m2m job queue's status */ +/* Instance is already queued on the job_queue */ +#define TRANS_QUEUED (1 << 0) +/* Instance is currently running in hardware */ +#define TRANS_RUNNING (1 << 1) +/* 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 + */ +enum aml_hw_reg_idx { + VDEC_SYS, + VDEC_MISC, + VDEC_LD, + VDEC_TOP, + VDEC_CM, + VDEC_AD, + VDEC_AV, + VDEC_PP, + VDEC_HWD, + VDEC_HWQ, + VDEC_HWB, + VDEC_HWG, + NUM_MAX_VDEC_REG_BASE, + /* h264 encoder */ + VENC_SYS = NUM_MAX_VDEC_REG_BASE, + /* vp8 encoder */ + VENC_LT_SYS, + NUM_MAX_VCODEC_REG_BASE +}; + +/** + * enum aml_instance_type - The type of an AML Vcodec instance. + */ +enum aml_instance_type { + AML_INST_DECODER = 0, + AML_INST_ENCODER = 1, +}; + +/** + * enum aml_instance_state - The state of an AML Vcodec instance. + * @AML_STATE_IDLE - default state when instance is created + * @AML_STATE_INIT - vcodec instance is initialized + * @AML_STATE_PROBE - vdec/venc had sps/pps header parsed/encoded + * @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_ABORT - vcodec should be aborted + */ +enum aml_instance_state { + AML_STATE_IDLE, + AML_STATE_INIT, + AML_STATE_PROBE, + AML_STATE_READY, + AML_STATE_ACTIVE, + AML_STATE_FLUSHING, + AML_STATE_FLUSHED, + AML_STATE_ABORT, +}; + +/** + * struct aml_encode_param - General encoding parameters type + */ +enum aml_encode_param { + AML_ENCODE_PARAM_NONE = 0, + AML_ENCODE_PARAM_BITRATE = (1 << 0), + AML_ENCODE_PARAM_FRAMERATE = (1 << 1), + AML_ENCODE_PARAM_INTRA_PERIOD = (1 << 2), + AML_ENCODE_PARAM_FORCE_INTRA = (1 << 3), + AML_ENCODE_PARAM_GOP_SIZE = (1 << 4), +}; + +enum aml_fmt_type { + AML_FMT_DEC = 0, + AML_FMT_ENC = 1, + AML_FMT_FRAME = 2, +}; + +/** + * struct aml_video_fmt - Structure used to store information about pixelformats + */ +struct aml_video_fmt { + u32 fourcc; + enum aml_fmt_type type; + u32 num_planes; + const u8 *name; +}; + +/** + * struct aml_codec_framesizes - Structure used to store information about + * framesizes + */ +struct aml_codec_framesizes { + u32 fourcc; + struct v4l2_frmsize_stepwise stepwise; +}; + +/** + * struct aml_q_type - Type of queue + */ +enum aml_q_type { + AML_Q_DATA_SRC = 0, + AML_Q_DATA_DST = 1, +}; + + +/** + * struct aml_q_data - Structure used to store information about queue + */ +struct aml_q_data { + u32 visible_width; + u32 visible_height; + u32 coded_width; + u32 coded_height; + enum v4l2_field field; + u32 bytesperline[AML_VCODEC_MAX_PLANES]; + u32 sizeimage[AML_VCODEC_MAX_PLANES]; + struct aml_video_fmt *fmt; + bool resolution_changed; +}; + +/** + * struct aml_enc_params - General encoding parameters + * @bitrate: target bitrate in bits per second + * @num_b_frame: number of b frames between p-frame + * @rc_frame: frame based rate control + * @rc_mb: macroblock based rate control + * @seq_hdr_mode: H.264 sequence header is encoded separately or joined + * with the first frame + * @intra_period: I frame period + * @gop_size: group of picture size, it's used as the intra frame period + * @framerate_num: frame rate numerator. ex: framerate_num=30 and + * framerate_denom=1 menas FPS is 30 + * @framerate_denom: frame rate denominator. ex: framerate_num=30 and + * framerate_denom=1 menas FPS is 30 + * @h264_max_qp: Max value for H.264 quantization parameter + * @h264_profile: V4L2 defined H.264 profile + * @h264_level: V4L2 defined H.264 level + * @force_intra: force/insert intra frame + */ +struct aml_enc_params { + 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; +}; + +/** + * struct vdec_pic_info - picture size information + * @visible_width: picture width + * @visible_height: picture height + * @coded_width: picture buffer width (64 aligned up from pic_w) + * @coded_height: picture buffer heiht (64 aligned up from pic_h) + * @y_bs_sz: Y bitstream size + * @c_bs_sz: CbCr bitstream size + * @y_len_sz: additional size required to store decompress information for y + * plane + * @c_len_sz: additional size required to store decompress information for cbcr + * 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 { + 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; + 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 { + u32 double_write_mode; + u32 init_width; + u32 init_height; + u32 ref_buf_margin; + 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 { + /* + * bit 29 : present_flag + * bit 28-26: video_format "component", "PAL", "NTSC", "SECAM", "MAC", "unspecified" + * bit 25 : range "limited", "full_range" + * bit 24 : color_description_present_flag + * bit 23-16: color_primaries "unknown", "bt709", "undef", "bt601", + * "bt470m", "bt470bg", "smpte170m", "smpte240m", "film", "bt2020" + * bit 15-8 : transfer_characteristic unknown", "bt709", "undef", "bt601", + * "bt470m", "bt470bg", "smpte170m", "smpte240m", + * "linear", "log100", "log316", "iec61966-2-4", + * "bt1361e", "iec61966-2-1", "bt2020-10", "bt2020-12", + * "smpte-st-2084", "smpte-st-428" + * bit 7-0 : matrix_coefficient "GBR", "bt709", "undef", "bt601", + * "fcc", "bt470bg", "smpte170m", "smpte240m", + * "YCgCo", "bt2020nc", "bt2020c" + */ + u32 signal_type; + struct vframe_master_display_colour_s color_parms; +}; + +struct aml_vdec_ps_infos { + u32 visible_width; + u32 visible_height; + u32 coded_width; + u32 coded_height; + u32 profile; + u32 mb_width; + u32 mb_height; + u32 dpb_size; + u32 ref_frames; + u32 dpb_frames; + u32 dpb_margin; + u32 field; + u32 data[3]; +}; + +struct aml_vdec_cnt_infos { + u32 bit_rate; + u32 frame_count; + u32 error_frame_count; + u32 drop_frame_count; + u32 total_data; +}; + +struct aml_dec_params { + u32 parms_status; + struct aml_vdec_cfg_infos cfg; + struct aml_vdec_ps_infos ps; + struct aml_vdec_hdr_infos hdr; + struct aml_vdec_cnt_infos cnt; +}; + +struct v4l2_config_parm { + u32 type; + u32 length; + union { + struct aml_dec_params dec; + struct aml_enc_params enc; + u8 data[200]; + } parm; + u8 buf[4096]; +}; + +struct v4l_buff_pool { + /* + * bit 31-16: buffer state + * bit 15- 0: buffer index + */ + u32 seq[V4L_CAP_BUFF_MAX]; + u32 in, out; + u32 dec, vpp, ge2d; +}; + +enum aml_thread_type { + AML_THREAD_OUTPUT, + AML_THREAD_CAPTURE, +}; + +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; + + 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. + * @state_lock: protect the codec status. + * @state: state of the context. + * @decode_work: decoder work be used to output buffer. + * @output_thread_ready: indicate the output thread ready. + * @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. + # @v4l_resolution_change: indicate resolution change happend. + * @comp: comp be used for sync picture information with decoder. + * @config: used to set or get parms for application. + * @picinfo: store picture info after header parsing. + * @last_decoded_picinfo: pic information get from latest decode. + * @colorspace: enum v4l2_colorspace; supplemental to pixelformat. + * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding. + * @quantization: enum v4l2_quantization, colorspace quantization. + * @xfer_func: enum v4l2_xfer_func, colorspace transfer function. + * @cap_pix_fmt: the picture format used to switch nv21 or nv12. + * @has_receive_eos: if receive last frame of capture that be set. + * @is_drm_mode: decoding work on drm mode if that set. + * @is_stream_mode: vdec input used to stream mode, default frame mode. + * @is_stream_off: the value used to handle reset active. + * @is_out_stream_off: streamoff called for output port. + * @receive_cmd_stop: if receive the cmd flush decoder. + * @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 state_lock; + enum aml_instance_state state; + struct work_struct decode_work; + bool output_thread_ready; + struct v4l_buff_pool cap_pool; + 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; + struct completion comp; + struct v4l2_config_parm config; + struct vdec_pic_info picinfo; + struct vdec_pic_info last_decoded_picinfo; + enum v4l2_colorspace colorspace; + enum v4l2_ycbcr_encoding ycbcr_enc; + 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; + bool output_dma_mode; + bool is_stream_off; + bool is_out_stream_off; + bool receive_cmd_stop; + 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. + * @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 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) +{ + return container_of(fh, struct aml_vcodec_ctx, fh); +} + +static inline struct aml_vcodec_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl) +{ + 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 new file mode 100644 index 0000000..54b0d06 --- /dev/null +++ b/drivers/amvdec_ports/aml_vcodec_util.c
@@ -0,0 +1,46 @@ +/* +* 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/module.h> + +#include "aml_vcodec_drv.h" +#include "aml_vcodec_util.h" + +void aml_vcodec_set_curr_ctx(struct aml_vcodec_dev *dev, + struct aml_vcodec_ctx *ctx) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->irqlock, flags); + dev->curr_ctx = ctx; + spin_unlock_irqrestore(&dev->irqlock, flags); +} +EXPORT_SYMBOL(aml_vcodec_set_curr_ctx); + +struct aml_vcodec_ctx *aml_vcodec_get_curr_ctx(struct aml_vcodec_dev *dev) +{ + unsigned long flags; + struct aml_vcodec_ctx *ctx; + + spin_lock_irqsave(&dev->irqlock, flags); + ctx = dev->curr_ctx; + spin_unlock_irqrestore(&dev->irqlock, flags); + return ctx; +} +EXPORT_SYMBOL(aml_vcodec_get_curr_ctx);
diff --git a/drivers/amvdec_ports/aml_vcodec_util.h b/drivers/amvdec_ports/aml_vcodec_util.h new file mode 100644 index 0000000..96c5453 --- /dev/null +++ b/drivers/amvdec_ports/aml_vcodec_util.h
@@ -0,0 +1,106 @@ +/* +* 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_UTIL_H_ +#define _AML_VCODEC_UTIL_H_ + +#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)) + +#define BUFF_IDX(h, i)\ + (((ulong)(h) << 8) | (u8)(i)) + +struct aml_vcodec_mem { + int index; + ulong addr; + u32 size; + void *vaddr; + u32 bytes_used; + u32 offset; + u64 timestamp; + 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 +#endif + +/* v4l debug define. */ +#define V4L_DEBUG_CODEC_ERROR (0) +#define V4L_DEBUG_CODEC_PRINFO (1 << 0) +#define V4L_DEBUG_CODEC_STATE (1 << 1) +#define V4L_DEBUG_CODEC_BUFMGR (1 << 2) +#define V4L_DEBUG_CODEC_INPUT (1 << 3) +#define V4L_DEBUG_CODEC_OUTPUT (1 << 4) +#define V4L_DEBUG_CODEC_COUNT (1 << 5) +#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 { \ + if (h) \ + pr_info("[%d]: " fmt, id, ##args); \ + else \ + pr_info(fmt, ##args); \ + } while (0) + +#define v4l_dbg(h, flags, fmt, args...) \ + do { \ + struct aml_vcodec_ctx *__ctx = (struct aml_vcodec_ctx *) h; \ + if ((flags == V4L_DEBUG_CODEC_ERROR) || \ + (flags == V4L_DEBUG_CODEC_PRINFO) || \ + (debug_mode & flags)) { \ + if (flags == V4L_DEBUG_CODEC_ERROR) { \ + __v4l_dbg(h, __ctx->id, "[ERR]: " fmt, ##args); \ + } else { \ + __v4l_dbg(h, __ctx->id, fmt, ##args); \ + } \ + } \ + } while (0) + +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); + +#endif /* _AML_VCODEC_UTIL_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 new file mode 100644 index 0000000..d0d0198 --- /dev/null +++ b/drivers/amvdec_ports/decoder/aml_h264_parser.c
@@ -0,0 +1,713 @@ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/vmalloc.h> +#include <linux/mm.h> +#include <linux/string.h> + +#include "aml_h264_parser.h" +#include "../utils/get_bits.h" +#include "../utils/put_bits.h" +#include "../utils/golomb.h" +#include "../utils/common.h" +#include "utils.h" + +#define MAX_DELAYED_PIC_COUNT (16) +#define MAX_LOG2_MAX_FRAME_NUM (12 + 4) +#define MIN_LOG2_MAX_FRAME_NUM (4) +#define MAX_SPS_COUNT (32) +#define EXTENDED_SAR (255) + +static const struct rational h264_pixel_aspect[17] = { + { 0, 1 }, + { 1, 1 }, + { 12, 11 }, + { 10, 11 }, + { 16, 11 }, + { 40, 33 }, + { 24, 11 }, + { 20, 11 }, + { 32, 11 }, + { 80, 33 }, + { 18, 11 }, + { 15, 11 }, + { 64, 33 }, + { 160, 99 }, + { 4, 3 }, + { 3, 2 }, + { 2, 1 }, +}; + +/* maximum number of MBs in the DPB for a given level */ +static const int level_max_dpb_mbs[][2] = { + { 10, 396 }, + { 11, 900 }, + { 12, 2376 }, + { 13, 2376 }, + { 20, 2376 }, + { 21, 4752 }, + { 22, 8100 }, + { 30, 8100 }, + { 31, 18000 }, + { 32, 20480 }, + { 40, 32768 }, + { 41, 32768 }, + { 42, 34816 }, + { 50, 110400 }, + { 51, 184320 }, + { 52, 184320 }, +}; + +static const u8 default_scaling4[2][16] = { + { 6, 13, 20, 28, 13, 20, 28, 32, + 20, 28, 32, 37, 28, 32, 37, 42}, + { 10, 14, 20, 24, 14, 20, 24, 27, + 20, 24, 27, 30, 24, 27, 30, 34 } +}; + +static const u8 default_scaling8[2][64] = { + { 6, 10, 13, 16, 18, 23, 25, 27, + 10, 11, 16, 18, 23, 25, 27, 29, + 13, 16, 18, 23, 25, 27, 29, 31, + 16, 18, 23, 25, 27, 29, 31, 33, + 18, 23, 25, 27, 29, 31, 33, 36, + 23, 25, 27, 29, 31, 33, 36, 38, + 25, 27, 29, 31, 33, 36, 38, 40, + 27, 29, 31, 33, 36, 38, 40, 42 }, + { 9, 13, 15, 17, 19, 21, 22, 24, + 13, 13, 17, 19, 21, 22, 24, 25, + 15, 17, 19, 21, 22, 24, 25, 27, + 17, 19, 21, 22, 24, 25, 27, 28, + 19, 21, 22, 24, 25, 27, 28, 30, + 21, 22, 24, 25, 27, 28, 30, 32, + 22, 24, 25, 27, 28, 30, 32, 33, + 24, 25, 27, 28, 30, 32, 33, 35 } +}; + +extern const u8 ff_zigzag_scan[16 + 1]; +extern const u8 ff_zigzag_direct[64]; + +static int decode_scaling_list(struct get_bits_context *gb, + u8 *factors, int size, + const u8 *jvt_list, + const u8 *fallback_list) +{ + int i, last = 8, next = 8; + const u8 *scan = size == 16 ? ff_zigzag_scan : ff_zigzag_direct; + + if (!get_bits1(gb)) /* matrix not written, we use the predicted one */ + memcpy(factors, fallback_list, size * sizeof(u8)); + else + for (i = 0; i < size; i++) { + if (next) { + int v = get_se_golomb(gb); + /*if (v < -128 || v > 127) { //JM19 has not check. + pr_err( "delta scale %d is invalid\n", v); + return -1; + }*/ + next = (last + v) & 0xff; + } + if (!i && !next) { /* matrix not written, we use the preset one */ + memcpy(factors, jvt_list, size * sizeof(u8)); + break; + } + last = factors[scan[i]] = next ? next : last; + } + return 0; +} + +/* returns non zero if the provided SPS scaling matrix has been filled */ +static int decode_scaling_matrices(struct get_bits_context *gb, + const struct h264_SPS_t *sps, + const struct h264_PPS_t *pps, int is_sps, + u8(*scaling_matrix4)[16], + u8(*scaling_matrix8)[64]) +{ + int ret = 0; + int fallback_sps = !is_sps && sps->scaling_matrix_present; + const u8 *fallback[4] = { + fallback_sps ? sps->scaling_matrix4[0] : default_scaling4[0], + fallback_sps ? sps->scaling_matrix4[3] : default_scaling4[1], + fallback_sps ? sps->scaling_matrix8[0] : default_scaling8[0], + fallback_sps ? sps->scaling_matrix8[3] : default_scaling8[1] + }; + + if (get_bits1(gb)) { + ret |= decode_scaling_list(gb, scaling_matrix4[0], 16, default_scaling4[0], fallback[0]); // Intra, Y + ret |= decode_scaling_list(gb, scaling_matrix4[1], 16, default_scaling4[0], scaling_matrix4[0]); // Intra, Cr + ret |= decode_scaling_list(gb, scaling_matrix4[2], 16, default_scaling4[0], scaling_matrix4[1]); // Intra, Cb + ret |= decode_scaling_list(gb, scaling_matrix4[3], 16, default_scaling4[1], fallback[1]); // Inter, Y + ret |= decode_scaling_list(gb, scaling_matrix4[4], 16, default_scaling4[1], scaling_matrix4[3]); // Inter, Cr + ret |= decode_scaling_list(gb, scaling_matrix4[5], 16, default_scaling4[1], scaling_matrix4[4]); // Inter, Cb + if (is_sps || pps->transform_8x8_mode) { + ret |= decode_scaling_list(gb, scaling_matrix8[0], 64, default_scaling8[0], fallback[2]); // Intra, Y + ret |= decode_scaling_list(gb, scaling_matrix8[3], 64, default_scaling8[1], fallback[3]); // Inter, Y + if (sps->chroma_format_idc == 3) { + ret |= decode_scaling_list(gb, scaling_matrix8[1], 64, default_scaling8[0], scaling_matrix8[0]); // Intra, Cr + ret |= decode_scaling_list(gb, scaling_matrix8[4], 64, default_scaling8[1], scaling_matrix8[3]); // Inter, Cr + ret |= decode_scaling_list(gb, scaling_matrix8[2], 64, default_scaling8[0], scaling_matrix8[1]); // Intra, Cb + ret |= decode_scaling_list(gb, scaling_matrix8[5], 64, default_scaling8[1], scaling_matrix8[4]); // Inter, Cb + } + } + if (!ret) + ret = is_sps; + } + + return ret; +} + +static int decode_hrd_parameters(struct get_bits_context *gb, + struct h264_SPS_t *sps) +{ + int cpb_count, i; + + cpb_count = get_ue_golomb_31(gb) + 1; + if (cpb_count > 32U) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "cpb_count %d invalid\n", cpb_count); + return -1; + } + + get_bits(gb, 4); /* bit_rate_scale */ + get_bits(gb, 4); /* cpb_size_scale */ + for (i = 0; i < cpb_count; i++) { + get_ue_golomb_long(gb); /* bit_rate_value_minus1 */ + get_ue_golomb_long(gb); /* cpb_size_value_minus1 */ + get_bits1(gb); /* cbr_flag */ + } + + sps->initial_cpb_removal_delay_length = get_bits(gb, 5) + 1; + sps->cpb_removal_delay_length = get_bits(gb, 5) + 1; + sps->dpb_output_delay_length = get_bits(gb, 5) + 1; + sps->time_offset_length = get_bits(gb, 5); + sps->cpb_cnt = cpb_count; + + return 0; +} + +static int decode_vui_parameters(struct get_bits_context *gb, struct h264_SPS_t *sps) +{ + int aspect_ratio_info_present_flag; + u32 aspect_ratio_idc; + + aspect_ratio_info_present_flag = get_bits1(gb); + + if (aspect_ratio_info_present_flag) { + aspect_ratio_idc = get_bits(gb, 8); + if (aspect_ratio_idc == EXTENDED_SAR) { + sps->sar.num = get_bits(gb, 16); + sps->sar.den = get_bits(gb, 16); + } else if (aspect_ratio_idc < ARRAY_SIZE(h264_pixel_aspect)) { + sps->sar = h264_pixel_aspect[aspect_ratio_idc]; + } else { + return -1; + } + } else { + sps->sar.num = + sps->sar.den = 0; + } + + if (get_bits1(gb)) /* overscan_info_present_flag */ + get_bits1(gb); /* overscan_appropriate_flag */ + + sps->video_signal_type_present_flag = get_bits1(gb); + if (sps->video_signal_type_present_flag) { + get_bits(gb, 3); /* video_format */ + sps->full_range = get_bits1(gb); /* video_full_range_flag */ + + sps->colour_description_present_flag = get_bits1(gb); + if (sps->colour_description_present_flag) { + sps->color_primaries = get_bits(gb, 8); /* colour_primaries */ + sps->color_trc = get_bits(gb, 8); /* transfer_characteristics */ + sps->colorspace = get_bits(gb, 8); /* matrix_coefficients */ + + // Set invalid values to "unspecified" + if (!av_color_primaries_name(sps->color_primaries)) + sps->color_primaries = AVCOL_PRI_UNSPECIFIED; + if (!av_color_transfer_name(sps->color_trc)) + sps->color_trc = AVCOL_TRC_UNSPECIFIED; + if (!av_color_space_name(sps->colorspace)) + sps->colorspace = AVCOL_SPC_UNSPECIFIED; + } + } + + /* chroma_location_info_present_flag */ + if (get_bits1(gb)) { + /* chroma_sample_location_type_top_field */ + //avctx->chroma_sample_location = get_ue_golomb(gb) + 1; + get_ue_golomb(gb); /* chroma_sample_location_type_bottom_field */ + } + + if (show_bits1(gb) && get_bits_left(gb) < 10) { + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Truncated VUI\n"); + return 0; + } + + sps->timing_info_present_flag = get_bits1(gb); + if (sps->timing_info_present_flag) { + unsigned num_units_in_tick = get_bits_long(gb, 32); + unsigned time_scale = get_bits_long(gb, 32); + if (!num_units_in_tick || !time_scale) { + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, + "time_scale/num_units_in_tick invalid or unsupported (%u/%u)\n", + time_scale, num_units_in_tick); + sps->timing_info_present_flag = 0; + } else { + sps->num_units_in_tick = num_units_in_tick; + sps->time_scale = time_scale; + } + sps->fixed_frame_rate_flag = get_bits1(gb); + } + + sps->nal_hrd_parameters_present_flag = get_bits1(gb); + if (sps->nal_hrd_parameters_present_flag) + if (decode_hrd_parameters(gb, sps) < 0) + return -1; + sps->vcl_hrd_parameters_present_flag = get_bits1(gb); + if (sps->vcl_hrd_parameters_present_flag) + if (decode_hrd_parameters(gb, sps) < 0) + return -1; + if (sps->nal_hrd_parameters_present_flag || + sps->vcl_hrd_parameters_present_flag) + get_bits1(gb); /* low_delay_hrd_flag */ + sps->pic_struct_present_flag = get_bits1(gb); + if (!get_bits_left(gb)) + return 0; + sps->bitstream_restriction_flag = get_bits1(gb); + if (sps->bitstream_restriction_flag) { + get_bits1(gb); /* motion_vectors_over_pic_boundaries_flag */ + get_ue_golomb(gb); /* max_bytes_per_pic_denom */ + get_ue_golomb(gb); /* max_bits_per_mb_denom */ + get_ue_golomb(gb); /* log2_max_mv_length_horizontal */ + get_ue_golomb(gb); /* log2_max_mv_length_vertical */ + sps->num_reorder_frames = get_ue_golomb(gb); + sps->max_dec_frame_buffering = get_ue_golomb(gb); /*max_dec_frame_buffering*/ + + if (get_bits_left(gb) < 0) { + sps->num_reorder_frames = 0; + sps->bitstream_restriction_flag = 0; + } + + if (sps->num_reorder_frames > 16U + /* max_dec_frame_buffering || max_dec_frame_buffering > 16 */) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "Clipping illegal num_reorder_frames %d\n", + sps->num_reorder_frames); + sps->num_reorder_frames = 16; + return -1; + } + } + + return 0; +} + +static int aml_h264_parser_sps(struct get_bits_context *gb, struct h264_SPS_t *sps) +{ + int ret; + u32 sps_id; + int profile_idc, level_idc, constraint_set_flags = 0; + int i, log2_max_frame_num_minus4; + + profile_idc = get_bits(gb, 8); + constraint_set_flags |= get_bits1(gb) << 0; // constraint_set0_flag + constraint_set_flags |= get_bits1(gb) << 1; // constraint_set1_flag + constraint_set_flags |= get_bits1(gb) << 2; // constraint_set2_flag + constraint_set_flags |= get_bits1(gb) << 3; // constraint_set3_flag + constraint_set_flags |= get_bits1(gb) << 4; // constraint_set4_flag + constraint_set_flags |= get_bits1(gb) << 5; // constraint_set5_flag + skip_bits(gb, 2); // reserved_zero_2bits + level_idc = get_bits(gb, 8); + sps_id = get_ue_golomb_31(gb); + + if (sps_id >= MAX_SPS_COUNT) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "sps_id %u out of range\n", sps_id); + goto fail; + } + + sps->sps_id = sps_id; + sps->time_offset_length = 24; + sps->profile_idc = profile_idc; + sps->constraint_set_flags = constraint_set_flags; + sps->level_idc = level_idc; + sps->full_range = -1; + + memset(sps->scaling_matrix4, 16, sizeof(sps->scaling_matrix4)); + memset(sps->scaling_matrix8, 16, sizeof(sps->scaling_matrix8)); + sps->scaling_matrix_present = 0; + sps->colorspace = 2; //AVCOL_SPC_UNSPECIFIED + + if (sps->profile_idc == 100 || // High profile + sps->profile_idc == 110 || // High10 profile + sps->profile_idc == 122 || // High422 profile + sps->profile_idc == 244 || // High444 Predictive profile + sps->profile_idc == 44 || // Cavlc444 profile + sps->profile_idc == 83 || // Scalable Constrained High profile (SVC) + sps->profile_idc == 86 || // Scalable High Intra profile (SVC) + sps->profile_idc == 118 || // Stereo High profile (MVC) + sps->profile_idc == 128 || // Multiview High profile (MVC) + sps->profile_idc == 138 || // Multiview Depth High profile (MVCD) + sps->profile_idc == 144) { // old High444 profile + sps->chroma_format_idc = get_ue_golomb_31(gb); + + if (sps->chroma_format_idc > 3U) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "chroma_format_idc %u\n", sps->chroma_format_idc); + goto fail; + } else if (sps->chroma_format_idc == 3) { + sps->residual_color_transform_flag = get_bits1(gb); + if (sps->residual_color_transform_flag) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "separate color planes are not supported\n"); + goto fail; + } + } + + sps->bit_depth_luma = get_ue_golomb(gb) + 8; + sps->bit_depth_chroma = get_ue_golomb(gb) + 8; + if (sps->bit_depth_chroma != sps->bit_depth_luma) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "Different chroma and luma bit depth\n"); + goto fail; + } + + if (sps->bit_depth_luma < 8 || sps->bit_depth_luma > 14 || + sps->bit_depth_chroma < 8 || sps->bit_depth_chroma > 14) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "illegal bit depth value (%d, %d)\n", + sps->bit_depth_luma, sps->bit_depth_chroma); + goto fail; + } + + sps->transform_bypass = get_bits1(gb); + ret = decode_scaling_matrices(gb, sps, NULL, 1, + sps->scaling_matrix4, sps->scaling_matrix8); + if (ret < 0) + goto fail; + sps->scaling_matrix_present |= ret; + } else { + sps->chroma_format_idc = 1; + sps->bit_depth_luma = 8; + sps->bit_depth_chroma = 8; + } + + log2_max_frame_num_minus4 = get_ue_golomb(gb); + if (log2_max_frame_num_minus4 < MIN_LOG2_MAX_FRAME_NUM - 4 || + log2_max_frame_num_minus4 > MAX_LOG2_MAX_FRAME_NUM - 4) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "log2_max_frame_num_minus4 out of range (0-12): %d\n", + log2_max_frame_num_minus4); + goto fail; + } + sps->log2_max_frame_num = log2_max_frame_num_minus4 + 4; + + sps->poc_type = get_ue_golomb_31(gb); + if (sps->poc_type == 0) { // FIXME #define + u32 t = get_ue_golomb(gb); + if (t > 12) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "log2_max_poc_lsb (%d) is out of range\n", t); + goto fail; + } + sps->log2_max_poc_lsb = t + 4; + } else if (sps->poc_type == 1) { // FIXME #define + sps->delta_pic_order_always_zero_flag = get_bits1(gb); + sps->offset_for_non_ref_pic = get_se_golomb_long(gb); + sps->offset_for_top_to_bottom_field = get_se_golomb_long(gb); + + sps->poc_cycle_length = get_ue_golomb(gb); + if ((u32)sps->poc_cycle_length >= ARRAY_SIZE(sps->offset_for_ref_frame)) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "poc_cycle_length overflow %d\n", sps->poc_cycle_length); + goto fail; + } + + for (i = 0; i < sps->poc_cycle_length; i++) + sps->offset_for_ref_frame[i] = get_se_golomb_long(gb); + } else if (sps->poc_type != 2) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "illegal POC type %d\n", sps->poc_type); + goto fail; + } + + sps->ref_frame_count = get_ue_golomb_31(gb); + if (sps->ref_frame_count > MAX_DELAYED_PIC_COUNT) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "too many reference frames %d\n", sps->ref_frame_count); + goto fail; + } + sps->gaps_in_frame_num_allowed_flag = get_bits1(gb); + sps->mb_width = get_ue_golomb(gb) + 1; + sps->mb_height = get_ue_golomb(gb) + 1; + + sps->frame_mbs_only_flag = get_bits1(gb); + + if (sps->mb_height >= INT_MAX / 2U) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "height overflow\n"); + goto fail; + } + sps->mb_height *= 2 - sps->frame_mbs_only_flag; + + if (!sps->frame_mbs_only_flag) + sps->mb_aff = get_bits1(gb); + else + sps->mb_aff = 0; + + if ((u32)sps->mb_width >= INT_MAX / 16 || + (u32)sps->mb_height >= INT_MAX / 16) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "mb_width/height overflow\n"); + goto fail; + } + + sps->direct_8x8_inference_flag = get_bits1(gb); + + sps->crop = get_bits1(gb); + if (sps->crop) { + u32 crop_left = get_ue_golomb(gb); + u32 crop_right = get_ue_golomb(gb); + u32 crop_top = get_ue_golomb(gb); + u32 crop_bottom = get_ue_golomb(gb); + int width = 16 * sps->mb_width; + int height = 16 * sps->mb_height; + int vsub = (sps->chroma_format_idc == 1) ? 1 : 0; + int hsub = (sps->chroma_format_idc == 1 || sps->chroma_format_idc == 2) ? 1 : 0; + int step_x = 1 << hsub; + int step_y = (2 - sps->frame_mbs_only_flag) << vsub; + + if (crop_left > (u32)INT_MAX / 4 / step_x || + crop_right > (u32)INT_MAX / 4 / step_x || + crop_top > (u32)INT_MAX / 4 / step_y || + crop_bottom > (u32)INT_MAX / 4 / step_y || + (crop_left + crop_right ) * step_x >= width || + (crop_top + crop_bottom) * step_y >= height) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "crop values invalid %u %u %u %u / %d %d\n", + crop_left, crop_right, crop_top, crop_bottom, width, height); + goto fail; + } + + sps->crop_left = crop_left * step_x; + sps->crop_right = crop_right * step_x; + sps->crop_top = crop_top * step_y; + sps->crop_bottom = crop_bottom * step_y; + } else { + sps->crop_left = + sps->crop_right = + sps->crop_top = + sps->crop_bottom = + sps->crop = 0; + } + + sps->vui_parameters_present_flag = get_bits1(gb); + if (sps->vui_parameters_present_flag) { + int ret = decode_vui_parameters(gb, sps); + if (ret < 0) + goto fail; + } + + if (get_bits_left(gb) < 0) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "Overread %s by %d bits\n", + sps->vui_parameters_present_flag ? "VUI" : "SPS", -get_bits_left(gb)); + /*goto out;*/ + } + +#if 0 + /* if the maximum delay is not stored in the SPS, derive it based on the level */ + if (!sps->bitstream_restriction_flag && sps->ref_frame_count) { + sps->num_reorder_frames = MAX_DELAYED_PIC_COUNT - 1; + for (i = 0; i < ARRAY_SIZE(level_max_dpb_mbs); i++) { + if (level_max_dpb_mbs[i][0] == sps->level_idc) { + sps->num_reorder_frames = + MIN(level_max_dpb_mbs[i][1] / (sps->mb_width * sps->mb_height), + sps->num_reorder_frames); + break; + } + } + } +#endif + + sps->num_reorder_frames = MAX_DELAYED_PIC_COUNT - 1; + for (i = 0; i < ARRAY_SIZE(level_max_dpb_mbs); i++) { + if (level_max_dpb_mbs[i][0] == sps->level_idc) { + sps->num_reorder_frames = + MIN(level_max_dpb_mbs[i][1] / (sps->mb_width * sps->mb_height), + sps->num_reorder_frames); + sps->num_reorder_frames += 1; + if (sps->max_dec_frame_buffering > sps->num_reorder_frames) + sps->num_reorder_frames = sps->max_dec_frame_buffering; + break; + } + } + + if ((sps->bitstream_restriction_flag) && + (sps->max_dec_frame_buffering < + sps->num_reorder_frames)) { + sps->num_reorder_frames = sps->max_dec_frame_buffering; + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, + "set reorder_pic_num to %d\n", + sps->num_reorder_frames); + } + + if (!sps->sar.den) + sps->sar.den = 1; +/*out:*/ + if (1) { + static const char csp[4][5] = { "Gray", "420", "422", "444" }; + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, + "sps:%u profile:%d/%d poc:%d ref:%d %dx%d %s %s crop:%u/%u/%u/%u %s %s %d/%d b%d reo:%d\n", + sps_id, sps->profile_idc, sps->level_idc, + sps->poc_type, + sps->ref_frame_count, + sps->mb_width, sps->mb_height, + sps->frame_mbs_only_flag ? "FRM" : (sps->mb_aff ? "MB-AFF" : "PIC-AFF"), + sps->direct_8x8_inference_flag ? "8B8" : "", + sps->crop_left, sps->crop_right, + sps->crop_top, sps->crop_bottom, + sps->vui_parameters_present_flag ? "VUI" : "", + csp[sps->chroma_format_idc], + sps->timing_info_present_flag ? sps->num_units_in_tick : 0, + sps->timing_info_present_flag ? sps->time_scale : 0, + sps->bit_depth_luma, + sps->bitstream_restriction_flag ? sps->num_reorder_frames : -1); + } + + return 0; + +fail: + return -1; +} + +static const char *h264_nal_type_name[32] = { + "Unspecified 0", //H264_NAL_UNSPECIFIED + "Coded slice of a non-IDR picture", // H264_NAL_SLICE + "Coded slice data partition A", // H264_NAL_DPA + "Coded slice data partition B", // H264_NAL_DPB + "Coded slice data partition C", // H264_NAL_DPC + "IDR", // H264_NAL_IDR_SLICE + "SEI", // H264_NAL_SEI + "SPS", // H264_NAL_SPS + "PPS", // H264_NAL_PPS + "AUD", // H264_NAL_AUD + "End of sequence", // H264_NAL_END_SEQUENCE + "End of stream", // H264_NAL_END_STREAM + "Filler data", // H264_NAL_FILLER_DATA + "SPS extension", // H264_NAL_SPS_EXT + "Prefix", // H264_NAL_PREFIX + "Subset SPS", // H264_NAL_SUB_SPS + "Depth parameter set", // H264_NAL_DPS + "Reserved 17", // H264_NAL_RESERVED17 + "Reserved 18", // H264_NAL_RESERVED18 + "Auxiliary coded picture without partitioning", // H264_NAL_AUXILIARY_SLICE + "Slice extension", // H264_NAL_EXTEN_SLICE + "Slice extension for a depth view or a 3D-AVC texture view", // H264_NAL_DEPTH_EXTEN_SLICE + "Reserved 22", // H264_NAL_RESERVED22 + "Reserved 23", // H264_NAL_RESERVED23 + "Unspecified 24", // H264_NAL_UNSPECIFIED24 + "Unspecified 25", // H264_NAL_UNSPECIFIED25 + "Unspecified 26", // H264_NAL_UNSPECIFIED26 + "Unspecified 27", // H264_NAL_UNSPECIFIED27 + "Unspecified 28", // H264_NAL_UNSPECIFIED28 + "Unspecified 29", // H264_NAL_UNSPECIFIED29 + "Unspecified 30", // H264_NAL_UNSPECIFIED30 + "Unspecified 31", // H264_NAL_UNSPECIFIED31 +}; + +static const char *h264_nal_unit_name(int nal_type) +{ + return h264_nal_type_name[nal_type]; +} + +static int decode_extradata_ps(u8 *data, int size, struct h264_param_sets *ps) +{ + int ret = 0; + struct get_bits_context gb; + u32 src_len, rbsp_size = 0; + u8 *rbsp_buf = NULL; + int ref_idc, nalu_pos; + u32 nal_type; + u8 *p = data; + u32 len = size; + + nalu_pos = find_start_code(p, len); + if (nalu_pos < 0) + return -1; + + src_len = calc_nal_len(p + nalu_pos, size - nalu_pos); + rbsp_buf = nal_unit_extract_rbsp(p + nalu_pos, src_len, &rbsp_size); + if (rbsp_buf == NULL) + return -ENOMEM; + + ret = init_get_bits8(&gb, rbsp_buf, rbsp_size); + if (ret < 0) + goto out; + + if (get_bits1(&gb) != 0) { + ret = -1; + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "invalid h264 data,return!\n"); + goto out; + } + + ref_idc = get_bits(&gb, 2); + nal_type = get_bits(&gb, 5); + + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, + "nal_unit_type: %d(%s), nal_ref_idc: %d\n", + nal_type, h264_nal_unit_name(nal_type), ref_idc); + + switch (nal_type) { + case H264_NAL_SPS: + ret = aml_h264_parser_sps(&gb, &ps->sps); + if (ret < 0) + goto out; + ps->sps_parsed = true; + break; + /*case H264_NAL_PPS: + ret = ff_h264_decode_picture_parameter_set(&gb, &ps->pps, rbsp_size); + if (ret < 0) + goto fail; + ps->pps_parsed = true; + break;*/ + default: + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "Unsupport parser nal type (%s).\n", + h264_nal_unit_name(nal_type)); + break; + } + +out: + vfree(rbsp_buf); + + return ret; +} + +int h264_decode_extradata_ps(u8 *buf, int size, struct h264_param_sets *ps) +{ + int ret = 0, i = 0, j = 0; + u8 *p = buf; + int len = size; + + for (i = 4; i < size; i++) { + j = find_start_code(p, len); + if (j > 0) { + len = size - (p - buf); + ret = decode_extradata_ps(p, len, ps); + if (ret) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "parse extra data failed. err: %d\n", ret); + return ret; + } + + if (ps->sps_parsed) + break; + + p += j; + } + p++; + } + + return ret; +} + +
diff --git a/drivers/amvdec_ports/decoder/aml_h264_parser.h b/drivers/amvdec_ports/decoder/aml_h264_parser.h new file mode 100644 index 0000000..def00dd --- /dev/null +++ b/drivers/amvdec_ports/decoder/aml_h264_parser.h
@@ -0,0 +1,210 @@ +/* + * drivers/amvdec_ports/decoder/aml_h264_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_H264_PARSER_H +#define AML_H264_PARSER_H + +#include "../aml_vcodec_drv.h" +#ifdef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER +#include "../utils/pixfmt.h" +#endif + +#define QP_MAX_NUM (51 + 6 * 6) // The maximum supported qp + +/* NAL unit types */ +enum { + H264_NAL_SLICE = 1, + H264_NAL_DPA = 2, + H264_NAL_DPB = 3, + H264_NAL_DPC = 4, + H264_NAL_IDR_SLICE = 5, + H264_NAL_SEI = 6, + H264_NAL_SPS = 7, + H264_NAL_PPS = 8, + H264_NAL_AUD = 9, + H264_NAL_END_SEQUENCE = 10, + H264_NAL_END_STREAM = 11, + H264_NAL_FILLER_DATA = 12, + H264_NAL_SPS_EXT = 13, + H264_NAL_AUXILIARY_SLICE = 19, +}; + +enum { + // 7.4.2.1.1: seq_parameter_set_id is in [0, 31]. + H264_MAX_SPS_COUNT = 32, + // 7.4.2.2: pic_parameter_set_id is in [0, 255]. + H264_MAX_PPS_COUNT = 256, + + // A.3: MaxDpbFrames is bounded above by 16. + H264_MAX_DPB_FRAMES = 16, + // 7.4.2.1.1: max_num_ref_frames is in [0, MaxDpbFrames], and + // each reference frame can have two fields. + H264_MAX_REFS = 2 * H264_MAX_DPB_FRAMES, + + // 7.4.3.1: modification_of_pic_nums_idc is not equal to 3 at most + // num_ref_idx_lN_active_minus1 + 1 times (that is, once for each + // possible reference), then equal to 3 once. + H264_MAX_RPLM_COUNT = H264_MAX_REFS + 1, + + // 7.4.3.3: in the worst case, we begin with a full short-term + // reference picture list. Each picture in turn is moved to the + // long-term list (type 3) and then discarded from there (type 2). + // Then, we set the length of the long-term list (type 4), mark + // the current picture as long-term (type 6) and terminate the + // process (type 0). + H264_MAX_MMCO_COUNT = H264_MAX_REFS * 2 + 3, + + // A.2.1, A.2.3: profiles supporting FMO constrain + // num_slice_groups_minus1 to be in [0, 7]. + H264_MAX_SLICE_GROUPS = 8, + + // E.2.2: cpb_cnt_minus1 is in [0, 31]. + H264_MAX_CPB_CNT = 32, + + // A.3: in table A-1 the highest level allows a MaxFS of 139264. + H264_MAX_MB_PIC_SIZE = 139264, + // A.3.1, A.3.2: PicWidthInMbs and PicHeightInMbs are constrained + // to be not greater than sqrt(MaxFS * 8). Hence height/width are + // bounded above by sqrt(139264 * 8) = 1055.5 macroblocks. + H264_MAX_MB_WIDTH = 1055, + H264_MAX_MB_HEIGHT = 1055, + H264_MAX_WIDTH = H264_MAX_MB_WIDTH * 16, + H264_MAX_HEIGHT = H264_MAX_MB_HEIGHT * 16, +}; + +/** + * Rational number (pair of numerator and denominator). + */ +struct rational{ + int num; ///< Numerator + int den; ///< Denominator +}; + +/** + * Sequence parameter set + */ +struct h264_SPS_t { + u32 sps_id; + int profile_idc; + int level_idc; + int chroma_format_idc; + int transform_bypass; ///< qpprime_y_zero_transform_bypass_flag + int log2_max_frame_num; ///< log2_max_frame_num_minus4 + 4 + int poc_type; ///< pic_order_cnt_type + int log2_max_poc_lsb; ///< log2_max_pic_order_cnt_lsb_minus4 + int delta_pic_order_always_zero_flag; + int offset_for_non_ref_pic; + int offset_for_top_to_bottom_field; + int poc_cycle_length; ///< num_ref_frames_in_pic_order_cnt_cycle + int ref_frame_count; ///< num_ref_frames + int gaps_in_frame_num_allowed_flag; + int mb_width; ///< pic_width_in_mbs_minus1 + 1 + ///< (pic_height_in_map_units_minus1 + 1) * (2 - frame_mbs_only_flag) + int mb_height; + int frame_mbs_only_flag; + int mb_aff; ///< mb_adaptive_frame_field_flag + int direct_8x8_inference_flag; + int crop; ///< frame_cropping_flag + + /* those 4 are already in luma samples */ + u32 crop_left; ///< frame_cropping_rect_left_offset + u32 crop_right; ///< frame_cropping_rect_right_offset + u32 crop_top; ///< frame_cropping_rect_top_offset + u32 crop_bottom; ///< frame_cropping_rect_bottom_offset + int vui_parameters_present_flag; + struct rational sar; + int video_signal_type_present_flag; + int full_range; + int colour_description_present_flag; +#ifdef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER + enum AVColorPrimaries color_primaries; + enum AVColorTransferCharacteristic color_trc; + enum AVColorSpace colorspace; +#endif + int timing_info_present_flag; + u32 num_units_in_tick; + u32 time_scale; + int fixed_frame_rate_flag; + int32_t offset_for_ref_frame[256]; + int bitstream_restriction_flag; + int num_reorder_frames; + int max_dec_frame_buffering; + int scaling_matrix_present; + u8 scaling_matrix4[6][16]; + u8 scaling_matrix8[6][64]; + int nal_hrd_parameters_present_flag; + int vcl_hrd_parameters_present_flag; + int pic_struct_present_flag; + int time_offset_length; + int cpb_cnt; ///< See H.264 E.1.2 + int initial_cpb_removal_delay_length; ///< initial_cpb_removal_delay_length_minus1 + 1 + int cpb_removal_delay_length; ///< cpb_removal_delay_length_minus1 + 1 + int dpb_output_delay_length; ///< dpb_output_delay_length_minus1 + 1 + int bit_depth_luma; ///< bit_depth_luma_minus8 + 8 + int bit_depth_chroma; ///< bit_depth_chroma_minus8 + 8 + int residual_color_transform_flag; ///< residual_colour_transform_flag + int constraint_set_flags; ///< constraint_set[0-3]_flag +} ; + +/** + * Picture parameter set + */ +struct h264_PPS_t { + u32 sps_id; + int cabac; ///< entropy_coding_mode_flag + int pic_order_present; ///< pic_order_present_flag + int slice_group_count; ///< num_slice_groups_minus1 + 1 + int mb_slice_group_map_type; + u32 ref_count[2]; ///< num_ref_idx_l0/1_active_minus1 + 1 + int weighted_pred; ///< weighted_pred_flag + int weighted_bipred_idc; + int init_qp; ///< pic_init_qp_minus26 + 26 + int init_qs; ///< pic_init_qs_minus26 + 26 + int chroma_qp_index_offset[2]; + int deblocking_filter_parameters_present; ///< deblocking_filter_parameters_present_flag + int constrained_intra_pred; ///< constrained_intra_pred_flag + int redundant_pic_cnt_present; ///< redundant_pic_cnt_present_flag + int transform_8x8_mode; ///< transform_8x8_mode_flag + u8 scaling_matrix4[6][16]; + u8 scaling_matrix8[6][64]; + u8 chroma_qp_table[2][87+1]; ///< pre-scaled (with chroma_qp_index_offset) version of qp_table + int chroma_qp_diff; + u8 data[4096]; + int data_size; + + u32 dequant4_buffer[6][87 + 1][16]; + u32 dequant8_buffer[6][87 + 1][64]; + u32(*dequant4_coeff[6])[16]; + u32(*dequant8_coeff[6])[64]; +} ; + +struct h264_param_sets { + bool sps_parsed; + bool pps_parsed; + struct h264_SPS_t sps; + struct h264_PPS_t pps; +}; + + +#ifdef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER +int h264_decode_extradata_ps(u8 *data, int size, struct h264_param_sets *ps); +#else +inline int h264_decode_extradata_ps(u8 *data, int size, struct h264_param_sets *ps) { return -1; } +#endif + +#endif /* AML_H264_PARSER_H */ +
diff --git a/drivers/amvdec_ports/decoder/aml_hevc_parser.c b/drivers/amvdec_ports/decoder/aml_hevc_parser.c new file mode 100644 index 0000000..24977a8 --- /dev/null +++ b/drivers/amvdec_ports/decoder/aml_hevc_parser.c
@@ -0,0 +1,1282 @@ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/vmalloc.h> +#include <linux/mm.h> +#include <linux/string.h> + +#include "aml_hevc_parser.h" +#include "../utils/get_bits.h" +#include "../utils/put_bits.h" +#include "../utils/golomb.h" +#include "../utils/common.h" +#include "utils.h" + +const u8 ff_hevc_diag_scan4x4_x[16] = { + 0, 0, 1, 0, + 1, 2, 0, 1, + 2, 3, 1, 2, + 3, 2, 3, 3, +}; + +const u8 ff_hevc_diag_scan4x4_y[16] = { + 0, 1, 0, 2, + 1, 0, 3, 2, + 1, 0, 3, 2, + 1, 3, 2, 3, +}; + +const u8 ff_hevc_diag_scan8x8_x[64] = { + 0, 0, 1, 0, + 1, 2, 0, 1, + 2, 3, 0, 1, + 2, 3, 4, 0, + 1, 2, 3, 4, + 5, 0, 1, 2, + 3, 4, 5, 6, + 0, 1, 2, 3, + 4, 5, 6, 7, + 1, 2, 3, 4, + 5, 6, 7, 2, + 3, 4, 5, 6, + 7, 3, 4, 5, + 6, 7, 4, 5, + 6, 7, 5, 6, + 7, 6, 7, 7, +}; + +const u8 ff_hevc_diag_scan8x8_y[64] = { + 0, 1, 0, 2, + 1, 0, 3, 2, + 1, 0, 4, 3, + 2, 1, 0, 5, + 4, 3, 2, 1, + 0, 6, 5, 4, + 3, 2, 1, 0, + 7, 6, 5, 4, + 3, 2, 1, 0, + 7, 6, 5, 4, + 3, 2, 1, 7, + 6, 5, 4, 3, + 2, 7, 6, 5, + 4, 3, 7, 6, + 5, 4, 7, 6, + 5, 7, 6, 7, +}; + +static const u8 default_scaling_list_intra[] = { + 16, 16, 16, 16, 17, 18, 21, 24, + 16, 16, 16, 16, 17, 19, 22, 25, + 16, 16, 17, 18, 20, 22, 25, 29, + 16, 16, 18, 21, 24, 27, 31, 36, + 17, 17, 20, 24, 30, 35, 41, 47, + 18, 19, 22, 27, 35, 44, 54, 65, + 21, 22, 25, 31, 41, 54, 70, 88, + 24, 25, 29, 36, 47, 65, 88, 115 +}; + +static const u8 default_scaling_list_inter[] = { + 16, 16, 16, 16, 17, 18, 20, 24, + 16, 16, 16, 17, 18, 20, 24, 25, + 16, 16, 17, 18, 20, 24, 25, 28, + 16, 17, 18, 20, 24, 25, 28, 33, + 17, 18, 20, 24, 25, 28, 33, 41, + 18, 20, 24, 25, 28, 33, 41, 54, + 20, 24, 25, 28, 33, 41, 54, 71, + 24, 25, 28, 33, 41, 54, 71, 91 +}; + +static const struct AVRational vui_sar[] = { + { 0, 1 }, + { 1, 1 }, + { 12, 11 }, + { 10, 11 }, + { 16, 11 }, + { 40, 33 }, + { 24, 11 }, + { 20, 11 }, + { 32, 11 }, + { 80, 33 }, + { 18, 11 }, + { 15, 11 }, + { 64, 33 }, + { 160, 99 }, + { 4, 3 }, + { 3, 2 }, + { 2, 1 }, +}; + +static const u8 hevc_sub_width_c[] = { + 1, 2, 2, 1 +}; + +static const u8 hevc_sub_height_c[] = { + 1, 2, 1, 1 +}; + +static int decode_profile_tier_level(struct get_bits_context *gb, struct PTLCommon *ptl) +{ + int i; + + if (get_bits_left(gb) < 2+1+5 + 32 + 4 + 16 + 16 + 12) + return -1; + + ptl->profile_space = get_bits(gb, 2); + ptl->tier_flag = get_bits1(gb); + ptl->profile_idc = get_bits(gb, 5); + if (ptl->profile_idc == FF_PROFILE_HEVC_MAIN) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Main profile bitstream\n"); + else if (ptl->profile_idc == FF_PROFILE_HEVC_MAIN_10) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Main 10 profile bitstream\n"); + else if (ptl->profile_idc == FF_PROFILE_HEVC_MAIN_STILL_PICTURE) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Main Still Picture profile bitstream\n"); + else if (ptl->profile_idc == FF_PROFILE_HEVC_REXT) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Range Extension profile bitstream\n"); + else + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Unknown HEVC profile: %d\n", ptl->profile_idc); + + for (i = 0; i < 32; i++) { + ptl->profile_compatibility_flag[i] = get_bits1(gb); + + if (ptl->profile_idc == 0 && i > 0 && ptl->profile_compatibility_flag[i]) + ptl->profile_idc = i; + } + ptl->progressive_source_flag = get_bits1(gb); + ptl->interlaced_source_flag = get_bits1(gb); + ptl->non_packed_constraint_flag = get_bits1(gb); + ptl->frame_only_constraint_flag = get_bits1(gb); + + skip_bits(gb, 16); // XXX_reserved_zero_44bits[0..15] + skip_bits(gb, 16); // XXX_reserved_zero_44bits[16..31] + skip_bits(gb, 12); // XXX_reserved_zero_44bits[32..43] + + return 0; +} + +static int parse_ptl(struct get_bits_context *gb, struct PTL *ptl, int max_num_sub_layers) +{ + int i; + if (decode_profile_tier_level(gb, &ptl->general_ptl) < 0 || + get_bits_left(gb) < 8 + (8*2 * (max_num_sub_layers - 1 > 0))) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "PTL information too short\n"); + return -1; + } + + ptl->general_ptl.level_idc = get_bits(gb, 8); + + for (i = 0; i < max_num_sub_layers - 1; i++) { + ptl->sub_layer_profile_present_flag[i] = get_bits1(gb); + ptl->sub_layer_level_present_flag[i] = get_bits1(gb); + } + + if (max_num_sub_layers - 1> 0) + for (i = max_num_sub_layers - 1; i < 8; i++) + skip_bits(gb, 2); // reserved_zero_2bits[i] + for (i = 0; i < max_num_sub_layers - 1; i++) { + if (ptl->sub_layer_profile_present_flag[i] && + decode_profile_tier_level(gb, &ptl->sub_layer_ptl[i]) < 0) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "PTL information for sublayer %i too short\n", i); + return -1; + } + if (ptl->sub_layer_level_present_flag[i]) { + if (get_bits_left(gb) < 8) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Not enough data for sublayer %i level_idc\n", i); + return -1; + } else + ptl->sub_layer_ptl[i].level_idc = get_bits(gb, 8); + } + } + + return 0; +} + +static void decode_sublayer_hrd(struct get_bits_context *gb, + u32 nb_cpb, int subpic_params_present) +{ + int i; + + for (i = 0; i < nb_cpb; i++) { + get_ue_golomb_long(gb); // bit_rate_value_minus1 + get_ue_golomb_long(gb); // cpb_size_value_minus1 + + if (subpic_params_present) { + get_ue_golomb_long(gb); // cpb_size_du_value_minus1 + get_ue_golomb_long(gb); // bit_rate_du_value_minus1 + } + skip_bits1(gb); // cbr_flag + } +} + +static int decode_hrd(struct get_bits_context *gb, + int common_inf_present, int max_sublayers) +{ + int nal_params_present = 0, vcl_params_present = 0; + int subpic_params_present = 0; + int i; + + if (common_inf_present) { + nal_params_present = get_bits1(gb); + vcl_params_present = get_bits1(gb); + + if (nal_params_present || vcl_params_present) { + subpic_params_present = get_bits1(gb); + + if (subpic_params_present) { + skip_bits(gb, 8); // tick_divisor_minus2 + skip_bits(gb, 5); // du_cpb_removal_delay_increment_length_minus1 + skip_bits(gb, 1); // sub_pic_cpb_params_in_pic_timing_sei_flag + skip_bits(gb, 5); // dpb_output_delay_du_length_minus1 + } + + skip_bits(gb, 4); // bit_rate_scale + skip_bits(gb, 4); // cpb_size_scale + + if (subpic_params_present) + skip_bits(gb, 4); // cpb_size_du_scale + + skip_bits(gb, 5); // initial_cpb_removal_delay_length_minus1 + skip_bits(gb, 5); // au_cpb_removal_delay_length_minus1 + skip_bits(gb, 5); // dpb_output_delay_length_minus1 + } + } + + for (i = 0; i < max_sublayers; i++) { + int low_delay = 0; + u32 nb_cpb = 1; + int fixed_rate = get_bits1(gb); + + if (!fixed_rate) + fixed_rate = get_bits1(gb); + + if (fixed_rate) + get_ue_golomb_long(gb); // elemental_duration_in_tc_minus1 + else + low_delay = get_bits1(gb); + + if (!low_delay) { + nb_cpb = get_ue_golomb_long(gb) + 1; + if (nb_cpb < 1 || nb_cpb > 32) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "nb_cpb %d invalid\n", nb_cpb); + return -1; + } + } + + if (nal_params_present) + decode_sublayer_hrd(gb, nb_cpb, subpic_params_present); + if (vcl_params_present) + decode_sublayer_hrd(gb, nb_cpb, subpic_params_present); + } + return 0; +} + +int ff_hevc_parse_vps(struct get_bits_context *gb, struct h265_VPS_t *vps) +{ + int i,j; + int vps_id = 0; + + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Decoding VPS\n"); + + vps_id = get_bits(gb, 4); + if (vps_id >= HEVC_MAX_VPS_COUNT) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "VPS id out of range: %d\n", vps_id); + goto err; + } + + if (get_bits(gb, 2) != 3) { // vps_reserved_three_2bits + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "vps_reserved_three_2bits is not three\n"); + goto err; + } + + vps->vps_max_layers = get_bits(gb, 6) + 1; + vps->vps_max_sub_layers = get_bits(gb, 3) + 1; + vps->vps_temporal_id_nesting_flag = get_bits1(gb); + + if (get_bits(gb, 16) != 0xffff) { // vps_reserved_ffff_16bits + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "vps_reserved_ffff_16bits is not 0xffff\n"); + goto err; + } + + if (vps->vps_max_sub_layers > HEVC_MAX_SUB_LAYERS) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "vps_max_sub_layers out of range: %d\n", + vps->vps_max_sub_layers); + goto err; + } + + if (parse_ptl(gb, &vps->ptl, vps->vps_max_sub_layers) < 0) + goto err; + + vps->vps_sub_layer_ordering_info_present_flag = get_bits1(gb); + + i = vps->vps_sub_layer_ordering_info_present_flag ? 0 : vps->vps_max_sub_layers - 1; + for (; i < vps->vps_max_sub_layers; i++) { + vps->vps_max_dec_pic_buffering[i] = get_ue_golomb_long(gb) + 1; + vps->vps_num_reorder_pics[i] = get_ue_golomb_long(gb); + vps->vps_max_latency_increase[i] = get_ue_golomb_long(gb) - 1; + + if (vps->vps_max_dec_pic_buffering[i] > HEVC_MAX_DPB_SIZE || !vps->vps_max_dec_pic_buffering[i]) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "vps_max_dec_pic_buffering_minus1 out of range: %d\n", + vps->vps_max_dec_pic_buffering[i] - 1); + goto err; + } + if (vps->vps_num_reorder_pics[i] > vps->vps_max_dec_pic_buffering[i] - 1) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "vps_max_num_reorder_pics out of range: %d\n", + vps->vps_num_reorder_pics[i]); + goto err; + } + } + + vps->vps_max_layer_id = get_bits(gb, 6); + vps->vps_num_layer_sets = get_ue_golomb_long(gb) + 1; + if (vps->vps_num_layer_sets < 1 || vps->vps_num_layer_sets > 1024 || + (vps->vps_num_layer_sets - 1LL) * (vps->vps_max_layer_id + 1LL) > get_bits_left(gb)) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "too many layer_id_included_flags\n"); + goto err; + } + + for (i = 1; i < vps->vps_num_layer_sets; i++) + for (j = 0; j <= vps->vps_max_layer_id; j++) + skip_bits(gb, 1); // layer_id_included_flag[i][j] + + vps->vps_timing_info_present_flag = get_bits1(gb); + if (vps->vps_timing_info_present_flag) { + vps->vps_num_units_in_tick = get_bits_long(gb, 32); + vps->vps_time_scale = get_bits_long(gb, 32); + vps->vps_poc_proportional_to_timing_flag = get_bits1(gb); + if (vps->vps_poc_proportional_to_timing_flag) + vps->vps_num_ticks_poc_diff_one = get_ue_golomb_long(gb) + 1; + vps->vps_num_hrd_parameters = get_ue_golomb_long(gb); + if (vps->vps_num_hrd_parameters > (u32)vps->vps_num_layer_sets) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "vps_num_hrd_parameters %d is invalid\n", vps->vps_num_hrd_parameters); + goto err; + } + for (i = 0; i < vps->vps_num_hrd_parameters; i++) { + int common_inf_present = 1; + + get_ue_golomb_long(gb); // hrd_layer_set_idx + if (i) + common_inf_present = get_bits1(gb); + decode_hrd(gb, common_inf_present, vps->vps_max_sub_layers); + } + } + get_bits1(gb); /* vps_extension_flag */ + + if (get_bits_left(gb) < 0) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Overread VPS by %d bits\n", -get_bits_left(gb)); + goto err; + } + + return 0; +err: + return -1; +} + +static int map_pixel_format(struct h265_SPS_t *sps) +{ + /*const AVPixFmtDescriptor *desc;*/ + switch (sps->bit_depth) { + case 8: + if (sps->chroma_format_idc == 0) sps->pix_fmt = AV_PIX_FMT_GRAY8; + if (sps->chroma_format_idc == 1) sps->pix_fmt = AV_PIX_FMT_YUV420P; + if (sps->chroma_format_idc == 2) sps->pix_fmt = AV_PIX_FMT_YUV422P; + if (sps->chroma_format_idc == 3) sps->pix_fmt = AV_PIX_FMT_YUV444P; + break; + case 9: + if (sps->chroma_format_idc == 0) sps->pix_fmt = AV_PIX_FMT_GRAY9; + if (sps->chroma_format_idc == 1) sps->pix_fmt = AV_PIX_FMT_YUV420P9; + if (sps->chroma_format_idc == 2) sps->pix_fmt = AV_PIX_FMT_YUV422P9; + if (sps->chroma_format_idc == 3) sps->pix_fmt = AV_PIX_FMT_YUV444P9; + break; + case 10: + if (sps->chroma_format_idc == 0) sps->pix_fmt = AV_PIX_FMT_GRAY10; + if (sps->chroma_format_idc == 1) sps->pix_fmt = AV_PIX_FMT_YUV420P10; + if (sps->chroma_format_idc == 2) sps->pix_fmt = AV_PIX_FMT_YUV422P10; + if (sps->chroma_format_idc == 3) sps->pix_fmt = AV_PIX_FMT_YUV444P10; + break; + case 12: + if (sps->chroma_format_idc == 0) sps->pix_fmt = AV_PIX_FMT_GRAY12; + if (sps->chroma_format_idc == 1) sps->pix_fmt = AV_PIX_FMT_YUV420P12; + if (sps->chroma_format_idc == 2) sps->pix_fmt = AV_PIX_FMT_YUV422P12; + if (sps->chroma_format_idc == 3) sps->pix_fmt = AV_PIX_FMT_YUV444P12; + break; + default: + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "The following bit-depths are currently specified: 8, 9, 10 and 12 bits, " + "chroma_format_idc is %d, depth is %d\n", + sps->chroma_format_idc, sps->bit_depth); + return -1; + } + + /*desc = av_pix_fmt_desc_get(sps->pix_fmt); + if (!desc) + return AVERROR(EINVAL); + + sps->hshift[0] = sps->vshift[0] = 0; + sps->hshift[2] = sps->hshift[1] = desc->log2_chroma_w; + sps->vshift[2] = sps->vshift[1] = desc->log2_chroma_h;*/ + + sps->pixel_shift = sps->bit_depth > 8; + + return 0; +} + +static void set_default_scaling_list_data(struct ScalingList *sl) +{ + int matrixId; + + for (matrixId = 0; matrixId < 6; matrixId++) { + // 4x4 default is 16 + memset(sl->sl[0][matrixId], 16, 16); + sl->sl_dc[0][matrixId] = 16; // default for 16x16 + sl->sl_dc[1][matrixId] = 16; // default for 32x32 + } + memcpy(sl->sl[1][0], default_scaling_list_intra, 64); + memcpy(sl->sl[1][1], default_scaling_list_intra, 64); + memcpy(sl->sl[1][2], default_scaling_list_intra, 64); + memcpy(sl->sl[1][3], default_scaling_list_inter, 64); + memcpy(sl->sl[1][4], default_scaling_list_inter, 64); + memcpy(sl->sl[1][5], default_scaling_list_inter, 64); + memcpy(sl->sl[2][0], default_scaling_list_intra, 64); + memcpy(sl->sl[2][1], default_scaling_list_intra, 64); + memcpy(sl->sl[2][2], default_scaling_list_intra, 64); + memcpy(sl->sl[2][3], default_scaling_list_inter, 64); + memcpy(sl->sl[2][4], default_scaling_list_inter, 64); + memcpy(sl->sl[2][5], default_scaling_list_inter, 64); + memcpy(sl->sl[3][0], default_scaling_list_intra, 64); + memcpy(sl->sl[3][1], default_scaling_list_intra, 64); + memcpy(sl->sl[3][2], default_scaling_list_intra, 64); + memcpy(sl->sl[3][3], default_scaling_list_inter, 64); + memcpy(sl->sl[3][4], default_scaling_list_inter, 64); + memcpy(sl->sl[3][5], default_scaling_list_inter, 64); +} + +static int scaling_list_data(struct get_bits_context *gb, + struct ScalingList *sl, struct h265_SPS_t *sps) +{ + u8 scaling_list_pred_mode_flag; + int scaling_list_dc_coef[2][6]; + int size_id, matrix_id, pos; + int i; + + for (size_id = 0; size_id < 4; size_id++) + for (matrix_id = 0; matrix_id < 6; matrix_id += ((size_id == 3) ? 3 : 1)) { + scaling_list_pred_mode_flag = get_bits1(gb); + if (!scaling_list_pred_mode_flag) { + u32 delta = get_ue_golomb_long(gb); + /* Only need to handle non-zero delta. Zero means default, + * which should already be in the arrays. */ + if (delta) { + // Copy from previous array. + delta *= (size_id == 3) ? 3 : 1; + if (matrix_id < delta) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Invalid delta in scaling list data: %d.\n", delta); + return -1; + } + + memcpy(sl->sl[size_id][matrix_id], + sl->sl[size_id][matrix_id - delta], + size_id > 0 ? 64 : 16); + if (size_id > 1) + sl->sl_dc[size_id - 2][matrix_id] = sl->sl_dc[size_id - 2][matrix_id - delta]; + } + } else { + int next_coef, coef_num; + int scaling_list_delta_coef; + + next_coef = 8; + coef_num = FFMIN(64, 1 << (4 + (size_id << 1))); + if (size_id > 1) { + scaling_list_dc_coef[size_id - 2][matrix_id] = get_se_golomb(gb) + 8; + next_coef = scaling_list_dc_coef[size_id - 2][matrix_id]; + sl->sl_dc[size_id - 2][matrix_id] = next_coef; + } + for (i = 0; i < coef_num; i++) { + if (size_id == 0) + pos = 4 * ff_hevc_diag_scan4x4_y[i] + + ff_hevc_diag_scan4x4_x[i]; + else + pos = 8 * ff_hevc_diag_scan8x8_y[i] + + ff_hevc_diag_scan8x8_x[i]; + + scaling_list_delta_coef = get_se_golomb(gb); + next_coef = (next_coef + 256U + scaling_list_delta_coef) % 256; + sl->sl[size_id][matrix_id][pos] = next_coef; + } + } + } + + if (sps->chroma_format_idc == 3) { + for (i = 0; i < 64; i++) { + sl->sl[3][1][i] = sl->sl[2][1][i]; + sl->sl[3][2][i] = sl->sl[2][2][i]; + sl->sl[3][4][i] = sl->sl[2][4][i]; + sl->sl[3][5][i] = sl->sl[2][5][i]; + } + sl->sl_dc[1][1] = sl->sl_dc[0][1]; + sl->sl_dc[1][2] = sl->sl_dc[0][2]; + sl->sl_dc[1][4] = sl->sl_dc[0][4]; + sl->sl_dc[1][5] = sl->sl_dc[0][5]; + } + + return 0; +} + +int ff_hevc_decode_short_term_rps(struct get_bits_context *gb, + struct ShortTermRPS *rps, const struct h265_SPS_t *sps, int is_slice_header) +{ + u8 rps_predict = 0; + int delta_poc; + int k0 = 0; + int k1 = 0; + int k = 0; + int i; + + if (rps != sps->st_rps && sps->nb_st_rps) + rps_predict = get_bits1(gb); + + if (rps_predict) { + const struct ShortTermRPS *rps_ridx; + int delta_rps; + u32 abs_delta_rps; + u8 use_delta_flag = 0; + u8 delta_rps_sign; + + if (is_slice_header) { + u32 delta_idx = get_ue_golomb_long(gb) + 1; + if (delta_idx > sps->nb_st_rps) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Invalid value of delta_idx in slice header RPS: %d > %d.\n", + delta_idx, sps->nb_st_rps); + return -1; + } + rps_ridx = &sps->st_rps[sps->nb_st_rps - delta_idx]; + rps->rps_idx_num_delta_pocs = rps_ridx->num_delta_pocs; + } else + rps_ridx = &sps->st_rps[rps - sps->st_rps - 1]; + + delta_rps_sign = get_bits1(gb); + abs_delta_rps = get_ue_golomb_long(gb) + 1; + if (abs_delta_rps < 1 || abs_delta_rps > 32768) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Invalid value of abs_delta_rps: %d\n", + abs_delta_rps); + return -1; + } + delta_rps = (1 - (delta_rps_sign << 1)) * abs_delta_rps; + for (i = 0; i <= rps_ridx->num_delta_pocs; i++) { + int used = rps->used[k] = get_bits1(gb); + + if (!used) + use_delta_flag = get_bits1(gb); + + if (used || use_delta_flag) { + if (i < rps_ridx->num_delta_pocs) + delta_poc = delta_rps + rps_ridx->delta_poc[i]; + else + delta_poc = delta_rps; + rps->delta_poc[k] = delta_poc; + if (delta_poc < 0) + k0++; + else + k1++; + k++; + } + } + + if (k >= ARRAY_SIZE(rps->used)) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Invalid num_delta_pocs: %d\n", k); + return -1; + } + + rps->num_delta_pocs = k; + rps->num_negative_pics = k0; + // sort in increasing order (smallest first) + if (rps->num_delta_pocs != 0) { + int used, tmp; + for (i = 1; i < rps->num_delta_pocs; i++) { + delta_poc = rps->delta_poc[i]; + used = rps->used[i]; + for (k = i - 1; k >= 0; k--) { + tmp = rps->delta_poc[k]; + if (delta_poc < tmp) { + rps->delta_poc[k + 1] = tmp; + rps->used[k + 1] = rps->used[k]; + rps->delta_poc[k] = delta_poc; + rps->used[k] = used; + } + } + } + } + if ((rps->num_negative_pics >> 1) != 0) { + int used; + k = rps->num_negative_pics - 1; + // flip the negative values to largest first + for (i = 0; i < rps->num_negative_pics >> 1; i++) { + delta_poc = rps->delta_poc[i]; + used = rps->used[i]; + rps->delta_poc[i] = rps->delta_poc[k]; + rps->used[i] = rps->used[k]; + rps->delta_poc[k] = delta_poc; + rps->used[k] = used; + k--; + } + } + } else { + u32 prev, nb_positive_pics; + rps->num_negative_pics = get_ue_golomb_long(gb); + nb_positive_pics = get_ue_golomb_long(gb); + + if (rps->num_negative_pics >= HEVC_MAX_REFS || + nb_positive_pics >= HEVC_MAX_REFS) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Too many refs in a short term RPS.\n"); + return -1; + } + + rps->num_delta_pocs = rps->num_negative_pics + nb_positive_pics; + if (rps->num_delta_pocs) { + prev = 0; + for (i = 0; i < rps->num_negative_pics; i++) { + delta_poc = get_ue_golomb_long(gb) + 1; + if (delta_poc < 1 || delta_poc > 32768) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Invalid value of delta_poc: %d\n", + delta_poc); + return -1; + } + prev -= delta_poc; + rps->delta_poc[i] = prev; + rps->used[i] = get_bits1(gb); + } + prev = 0; + for (i = 0; i < nb_positive_pics; i++) { + delta_poc = get_ue_golomb_long(gb) + 1; + if (delta_poc < 1 || delta_poc > 32768) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Invalid value of delta_poc: %d\n", + delta_poc); + return -1; + } + prev += delta_poc; + rps->delta_poc[rps->num_negative_pics + i] = prev; + rps->used[rps->num_negative_pics + i] = get_bits1(gb); + } + } + } + return 0; +} + +static void decode_vui(struct get_bits_context *gb, struct h265_SPS_t *sps) +{ + struct VUI backup_vui, *vui = &sps->vui; + struct get_bits_context backup; + int sar_present, alt = 0; + + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Decoding VUI\n"); + + sar_present = get_bits1(gb); + if (sar_present) { + u8 sar_idx = get_bits(gb, 8); + if (sar_idx < ARRAY_SIZE(vui_sar)) + vui->sar = vui_sar[sar_idx]; + else if (sar_idx == 255) { + vui->sar.num = get_bits(gb, 16); + vui->sar.den = get_bits(gb, 16); + } else + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, + "Unknown SAR index: %u.\n", sar_idx); + } + + vui->overscan_info_present_flag = get_bits1(gb); + if (vui->overscan_info_present_flag) + vui->overscan_appropriate_flag = get_bits1(gb); + + vui->video_signal_type_present_flag = get_bits1(gb); + if (vui->video_signal_type_present_flag) { + vui->video_format = get_bits(gb, 3); + vui->video_full_range_flag = get_bits1(gb); + vui->colour_description_present_flag = get_bits1(gb); + if (vui->video_full_range_flag && sps->pix_fmt == AV_PIX_FMT_YUV420P) + sps->pix_fmt = AV_PIX_FMT_YUVJ420P; + if (vui->colour_description_present_flag) { + vui->colour_primaries = get_bits(gb, 8); + vui->transfer_characteristic = get_bits(gb, 8); + vui->matrix_coeffs = get_bits(gb, 8); + + // Set invalid values to "unspecified" + if (!av_color_primaries_name(vui->colour_primaries)) + vui->colour_primaries = AVCOL_PRI_UNSPECIFIED; + if (!av_color_transfer_name(vui->transfer_characteristic)) + vui->transfer_characteristic = AVCOL_TRC_UNSPECIFIED; + if (!av_color_space_name(vui->matrix_coeffs)) + vui->matrix_coeffs = AVCOL_SPC_UNSPECIFIED; + if (vui->matrix_coeffs == AVCOL_SPC_RGB) { + switch (sps->pix_fmt) { + case AV_PIX_FMT_YUV444P: + sps->pix_fmt = AV_PIX_FMT_GBRP; + break; + case AV_PIX_FMT_YUV444P10: + sps->pix_fmt = AV_PIX_FMT_GBRP10; + break; + case AV_PIX_FMT_YUV444P12: + sps->pix_fmt = AV_PIX_FMT_GBRP12; + break; + } + } + } + } + + vui->chroma_loc_info_present_flag = get_bits1(gb); + if (vui->chroma_loc_info_present_flag) { + vui->chroma_sample_loc_type_top_field = get_ue_golomb_long(gb); + vui->chroma_sample_loc_type_bottom_field = get_ue_golomb_long(gb); + } + + vui->neutra_chroma_indication_flag = get_bits1(gb); + vui->field_seq_flag = get_bits1(gb); + vui->frame_field_info_present_flag = get_bits1(gb); + + // Backup context in case an alternate header is detected + memcpy(&backup, gb, sizeof(backup)); + memcpy(&backup_vui, vui, sizeof(backup_vui)); + if (get_bits_left(gb) >= 68 && show_bits_long(gb, 21) == 0x100000) { + vui->default_display_window_flag = 0; + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Invalid default display window\n"); + } else + vui->default_display_window_flag = get_bits1(gb); + + if (vui->default_display_window_flag) { + int vert_mult = hevc_sub_height_c[sps->chroma_format_idc]; + int horiz_mult = hevc_sub_width_c[sps->chroma_format_idc]; + vui->def_disp_win.left_offset = get_ue_golomb_long(gb) * horiz_mult; + vui->def_disp_win.right_offset = get_ue_golomb_long(gb) * horiz_mult; + vui->def_disp_win.top_offset = get_ue_golomb_long(gb) * vert_mult; + vui->def_disp_win.bottom_offset = get_ue_golomb_long(gb) * vert_mult; + } + +timing_info: + vui->vui_timing_info_present_flag = get_bits1(gb); + + if (vui->vui_timing_info_present_flag) { + if (get_bits_left(gb) < 66 && !alt) { + // The alternate syntax seem to have timing info located + // at where def_disp_win is normally located + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Strange VUI timing information, retrying...\n"); + memcpy(vui, &backup_vui, sizeof(backup_vui)); + memcpy(gb, &backup, sizeof(backup)); + alt = 1; + goto timing_info; + } + vui->vui_num_units_in_tick = get_bits_long(gb, 32); + vui->vui_time_scale = get_bits_long(gb, 32); + if (alt) { + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Retry got %u/%u fps\n", + vui->vui_time_scale, vui->vui_num_units_in_tick); + } + vui->vui_poc_proportional_to_timing_flag = get_bits1(gb); + if (vui->vui_poc_proportional_to_timing_flag) + vui->vui_num_ticks_poc_diff_one_minus1 = get_ue_golomb_long(gb); + vui->vui_hrd_parameters_present_flag = get_bits1(gb); + if (vui->vui_hrd_parameters_present_flag) + decode_hrd(gb, 1, sps->max_sub_layers); + } + + vui->bitstream_restriction_flag = get_bits1(gb); + if (vui->bitstream_restriction_flag) { + if (get_bits_left(gb) < 8 && !alt) { + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Strange VUI bitstream restriction information, retrying" + " from timing information...\n"); + memcpy(vui, &backup_vui, sizeof(backup_vui)); + memcpy(gb, &backup, sizeof(backup)); + alt = 1; + goto timing_info; + } + vui->tiles_fixed_structure_flag = get_bits1(gb); + vui->motion_vectors_over_pic_boundaries_flag = get_bits1(gb); + vui->restricted_ref_pic_lists_flag = get_bits1(gb); + vui->min_spatial_segmentation_idc = get_ue_golomb_long(gb); + vui->max_bytes_per_pic_denom = get_ue_golomb_long(gb); + vui->max_bits_per_min_cu_denom = get_ue_golomb_long(gb); + vui->log2_max_mv_length_horizontal = get_ue_golomb_long(gb); + vui->log2_max_mv_length_vertical = get_ue_golomb_long(gb); + } + + if (get_bits_left(gb) < 1 && !alt) { + // XXX: Alternate syntax when sps_range_extension_flag != 0? + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Overread in VUI, retrying from timing information...\n"); + memcpy(vui, &backup_vui, sizeof(backup_vui)); + memcpy(gb, &backup, sizeof(backup)); + alt = 1; + goto timing_info; + } +} + +int ff_hevc_parse_sps(struct get_bits_context *gb, struct h265_SPS_t *sps) +{ + int i, ret = 0; + int log2_diff_max_min_transform_block_size; + int bit_depth_chroma, start, vui_present, sublayer_ordering_info; + struct HEVCWindow *ow; + + sps->vps_id = get_bits(gb, 4); + if (sps->vps_id >= HEVC_MAX_VPS_COUNT) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "VPS id out of range: %d\n", sps->vps_id); + return -1; + } + + sps->max_sub_layers = get_bits(gb, 3) + 1; + if (sps->max_sub_layers > HEVC_MAX_SUB_LAYERS) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "sps_max_sub_layers out of range: %d\n", + sps->max_sub_layers); + return -1; + } + + sps->temporal_id_nesting_flag = get_bits(gb, 1); + + if ((ret = parse_ptl(gb, &sps->ptl, sps->max_sub_layers)) < 0) + return ret; + + sps->sps_id = get_ue_golomb_long(gb); + if (sps->sps_id >= HEVC_MAX_SPS_COUNT) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "SPS id out of range: %d\n", sps->sps_id); + return -1; + } + + sps->chroma_format_idc = get_ue_golomb_long(gb); + if (sps->chroma_format_idc > 3U) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "chroma_format_idc %d is invalid\n", sps->chroma_format_idc); + return -1; + } + + if (sps->chroma_format_idc == 3) + sps->separate_colour_plane_flag = get_bits1(gb); + + if (sps->separate_colour_plane_flag) + sps->chroma_format_idc = 0; + + sps->width = get_ue_golomb_long(gb); + sps->height = get_ue_golomb_long(gb); + if (sps->width > 8192 || sps->height > 8192) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "width or height oversize.\n"); + return -1; + } + + if (get_bits1(gb)) { // pic_conformance_flag + int vert_mult = hevc_sub_height_c[sps->chroma_format_idc]; + int horiz_mult = hevc_sub_width_c[sps->chroma_format_idc]; + sps->pic_conf_win.left_offset = get_ue_golomb_long(gb) * horiz_mult; + sps->pic_conf_win.right_offset = get_ue_golomb_long(gb) * horiz_mult; + sps->pic_conf_win.top_offset = get_ue_golomb_long(gb) * vert_mult; + sps->pic_conf_win.bottom_offset = get_ue_golomb_long(gb) * vert_mult; + sps->output_window = sps->pic_conf_win; + } + + sps->bit_depth = get_ue_golomb_long(gb) + 8; + bit_depth_chroma = get_ue_golomb_long(gb) + 8; + if (sps->chroma_format_idc && bit_depth_chroma != sps->bit_depth) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Luma bit depth (%d) is different from chroma bit depth (%d), this is unsupported.\n", + sps->bit_depth, bit_depth_chroma); + return -1; + } + sps->bit_depth_chroma = bit_depth_chroma; + + ret = map_pixel_format(sps); + if (ret < 0) + return ret; + + sps->log2_max_poc_lsb = get_ue_golomb_long(gb) + 4; + if (sps->log2_max_poc_lsb > 16) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "log2_max_pic_order_cnt_lsb_minus4 out range: %d\n", + sps->log2_max_poc_lsb - 4); + return -1; + } + + sublayer_ordering_info = get_bits1(gb); + start = sublayer_ordering_info ? 0 : sps->max_sub_layers - 1; + for (i = start; i < sps->max_sub_layers; i++) { + sps->temporal_layer[i].max_dec_pic_buffering = get_ue_golomb_long(gb) + 1; + sps->temporal_layer[i].num_reorder_pics = get_ue_golomb_long(gb); + sps->temporal_layer[i].max_latency_increase = get_ue_golomb_long(gb) - 1; + if (sps->temporal_layer[i].max_dec_pic_buffering > (u32)HEVC_MAX_DPB_SIZE) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "sps_max_dec_pic_buffering_minus1 out of range: %d\n", + sps->temporal_layer[i].max_dec_pic_buffering - 1U); + return -1; + } + if (sps->temporal_layer[i].num_reorder_pics > sps->temporal_layer[i].max_dec_pic_buffering - 1) { + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "sps_max_num_reorder_pics out of range: %d\n", + sps->temporal_layer[i].num_reorder_pics); + if (sps->temporal_layer[i].num_reorder_pics > HEVC_MAX_DPB_SIZE - 1) { + return -1; + } + sps->temporal_layer[i].max_dec_pic_buffering = sps->temporal_layer[i].num_reorder_pics + 1; + } + } + + if (!sublayer_ordering_info) { + for (i = 0; i < start; i++) { + sps->temporal_layer[i].max_dec_pic_buffering = sps->temporal_layer[start].max_dec_pic_buffering; + sps->temporal_layer[i].num_reorder_pics = sps->temporal_layer[start].num_reorder_pics; + sps->temporal_layer[i].max_latency_increase = sps->temporal_layer[start].max_latency_increase; + } + } + + sps->log2_min_cb_size = get_ue_golomb_long(gb) + 3; + sps->log2_diff_max_min_coding_block_size = get_ue_golomb_long(gb); + sps->log2_min_tb_size = get_ue_golomb_long(gb) + 2; + log2_diff_max_min_transform_block_size = get_ue_golomb_long(gb); + sps->log2_max_trafo_size = log2_diff_max_min_transform_block_size + sps->log2_min_tb_size; + + if (sps->log2_min_cb_size < 3 || sps->log2_min_cb_size > 30) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Invalid value %d for log2_min_cb_size", sps->log2_min_cb_size); + return -1; + } + + if (sps->log2_diff_max_min_coding_block_size > 30) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Invalid value %d for log2_diff_max_min_coding_block_size", sps->log2_diff_max_min_coding_block_size); + return -1; + } + + if (sps->log2_min_tb_size >= sps->log2_min_cb_size || sps->log2_min_tb_size < 2) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Invalid value for log2_min_tb_size"); + return -1; + } + + if (log2_diff_max_min_transform_block_size < 0 || log2_diff_max_min_transform_block_size > 30) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Invalid value %d for log2_diff_max_min_transform_block_size", log2_diff_max_min_transform_block_size); + return -1; + } + + sps->max_transform_hierarchy_depth_inter = get_ue_golomb_long(gb); + sps->max_transform_hierarchy_depth_intra = get_ue_golomb_long(gb); + + sps->scaling_list_enable_flag = get_bits1(gb); + if (sps->scaling_list_enable_flag) { + set_default_scaling_list_data(&sps->scaling_list); + + if (get_bits1(gb)) { + ret = scaling_list_data(gb, &sps->scaling_list, sps); + if (ret < 0) + return ret; + } + } + + sps->amp_enabled_flag = get_bits1(gb); + sps->sao_enabled = get_bits1(gb); + + sps->pcm_enabled_flag = get_bits1(gb); + if (sps->pcm_enabled_flag) { + sps->pcm.bit_depth = get_bits(gb, 4) + 1; + sps->pcm.bit_depth_chroma = get_bits(gb, 4) + 1; + sps->pcm.log2_min_pcm_cb_size = get_ue_golomb_long(gb) + 3; + sps->pcm.log2_max_pcm_cb_size = sps->pcm.log2_min_pcm_cb_size + + get_ue_golomb_long(gb); + if (FFMAX(sps->pcm.bit_depth, sps->pcm.bit_depth_chroma) > sps->bit_depth) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "PCM bit depth (%d, %d) is greater than normal bit depth (%d)\n", + sps->pcm.bit_depth, sps->pcm.bit_depth_chroma, sps->bit_depth); + return -1; + } + + sps->pcm.loop_filter_disable_flag = get_bits1(gb); + } + + sps->nb_st_rps = get_ue_golomb_long(gb); + if (sps->nb_st_rps > HEVC_MAX_SHORT_TERM_REF_PIC_SETS) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Too many short term RPS: %d.\n", sps->nb_st_rps); + return -1; + } + for (i = 0; i < sps->nb_st_rps; i++) { + if ((ret = ff_hevc_decode_short_term_rps(gb, &sps->st_rps[i], sps, 0)) < 0) + return ret; + } + + sps->long_term_ref_pics_present_flag = get_bits1(gb); + if (sps->long_term_ref_pics_present_flag) { + sps->num_long_term_ref_pics_sps = get_ue_golomb_long(gb); + if (sps->num_long_term_ref_pics_sps > HEVC_MAX_LONG_TERM_REF_PICS) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Too many long term ref pics: %d.\n", + sps->num_long_term_ref_pics_sps); + return -1; + } + for (i = 0; i < sps->num_long_term_ref_pics_sps; i++) { + sps->lt_ref_pic_poc_lsb_sps[i] = get_bits(gb, sps->log2_max_poc_lsb); + sps->used_by_curr_pic_lt_sps_flag[i] = get_bits1(gb); + } + } + + sps->sps_temporal_mvp_enabled_flag = get_bits1(gb); + sps->sps_strong_intra_smoothing_enable_flag = get_bits1(gb); + sps->vui.sar = (struct AVRational){0, 1}; + vui_present = get_bits1(gb); + if (vui_present) + decode_vui(gb, sps); + + if (get_bits1(gb)) { // sps_extension_flag + sps->sps_range_extension_flag = get_bits1(gb); + skip_bits(gb, 7); //sps_extension_7bits = get_bits(gb, 7); + if (sps->sps_range_extension_flag) { + sps->transform_skip_rotation_enabled_flag = get_bits1(gb); + sps->transform_skip_context_enabled_flag = get_bits1(gb); + sps->implicit_rdpcm_enabled_flag = get_bits1(gb); + sps->explicit_rdpcm_enabled_flag = get_bits1(gb); + sps->extended_precision_processing_flag = get_bits1(gb); + if (sps->extended_precision_processing_flag) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "extended_precision_processing_flag not yet implemented\n"); + + sps->intra_smoothing_disabled_flag = get_bits1(gb); + sps->high_precision_offsets_enabled_flag = get_bits1(gb); + if (sps->high_precision_offsets_enabled_flag) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "high_precision_offsets_enabled_flag not yet implemented\n"); + + sps->persistent_rice_adaptation_enabled_flag = get_bits1(gb); + sps->cabac_bypass_alignment_enabled_flag = get_bits1(gb); + if (sps->cabac_bypass_alignment_enabled_flag) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "cabac_bypass_alignment_enabled_flag not yet implemented\n"); + } + } + + ow = &sps->output_window; + if (ow->left_offset >= INT_MAX - ow->right_offset || + ow->top_offset >= INT_MAX - ow->bottom_offset || + ow->left_offset + ow->right_offset >= sps->width || + ow->top_offset + ow->bottom_offset >= sps->height) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Invalid cropping offsets: %u/%u/%u/%u\n", + ow->left_offset, ow->right_offset, ow->top_offset, ow->bottom_offset); + return -1; + } + + // Inferred parameters + sps->log2_ctb_size = sps->log2_min_cb_size + + sps->log2_diff_max_min_coding_block_size; + sps->log2_min_pu_size = sps->log2_min_cb_size - 1; + + if (sps->log2_ctb_size > HEVC_MAX_LOG2_CTB_SIZE) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "CTB size out of range: 2^%d\n", sps->log2_ctb_size); + return -1; + } + if (sps->log2_ctb_size < 4) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "log2_ctb_size %d differs from the bounds of any known profile\n", sps->log2_ctb_size); + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "log2_ctb_size %d", sps->log2_ctb_size); + return -1; + } + + sps->ctb_width = (sps->width + (1 << sps->log2_ctb_size) - 1) >> sps->log2_ctb_size; + sps->ctb_height = (sps->height + (1 << sps->log2_ctb_size) - 1) >> sps->log2_ctb_size; + sps->ctb_size = sps->ctb_width * sps->ctb_height; + + sps->min_cb_width = sps->width >> sps->log2_min_cb_size; + sps->min_cb_height = sps->height >> sps->log2_min_cb_size; + sps->min_tb_width = sps->width >> sps->log2_min_tb_size; + sps->min_tb_height = sps->height >> sps->log2_min_tb_size; + sps->min_pu_width = sps->width >> sps->log2_min_pu_size; + sps->min_pu_height = sps->height >> sps->log2_min_pu_size; + sps->tb_mask = (1 << (sps->log2_ctb_size - sps->log2_min_tb_size)) - 1; + sps->qp_bd_offset = 6 * (sps->bit_depth - 8); + + if (av_mod_uintp2(sps->width, sps->log2_min_cb_size) || + av_mod_uintp2(sps->height, sps->log2_min_cb_size)) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Invalid coded frame dimensions.\n"); + return -1; + } + + if (sps->max_transform_hierarchy_depth_inter > sps->log2_ctb_size - sps->log2_min_tb_size) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "max_transform_hierarchy_depth_inter out of range: %d\n", + sps->max_transform_hierarchy_depth_inter); + return -1; + } + if (sps->max_transform_hierarchy_depth_intra > sps->log2_ctb_size - sps->log2_min_tb_size) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "max_transform_hierarchy_depth_intra out of range: %d\n", + sps->max_transform_hierarchy_depth_intra); + return -1; + } + if (sps->log2_max_trafo_size > FFMIN(sps->log2_ctb_size, 5)) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "max transform block size out of range: %d\n", + sps->log2_max_trafo_size); + return -1; + } + + if (get_bits_left(gb) < 0) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Overread SPS by %d bits\n", -get_bits_left(gb)); + return -1; + } + + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Parsed SPS: id %d; ref: %d, coded wxh: %dx%d, cropped wxh: %dx%d; pix_fmt: %d.\n", + sps->sps_id, sps->temporal_layer[0].num_reorder_pics, sps->width, sps->height, + sps->width - (sps->output_window.left_offset + sps->output_window.right_offset), + sps->height - (sps->output_window.top_offset + sps->output_window.bottom_offset), + sps->pix_fmt); + + return 0; +} + +const char *hevc_nal_type_name[64] = { + "TRAIL_N", // HEVC_NAL_TRAIL_N + "TRAIL_R", // HEVC_NAL_TRAIL_R + "TSA_N", // HEVC_NAL_TSA_N + "TSA_R", // HEVC_NAL_TSA_R + "STSA_N", // HEVC_NAL_STSA_N + "STSA_R", // HEVC_NAL_STSA_R + "RADL_N", // HEVC_NAL_RADL_N + "RADL_R", // HEVC_NAL_RADL_R + "RASL_N", // HEVC_NAL_RASL_N + "RASL_R", // HEVC_NAL_RASL_R + "RSV_VCL_N10", // HEVC_NAL_VCL_N10 + "RSV_VCL_R11", // HEVC_NAL_VCL_R11 + "RSV_VCL_N12", // HEVC_NAL_VCL_N12 + "RSV_VLC_R13", // HEVC_NAL_VCL_R13 + "RSV_VCL_N14", // HEVC_NAL_VCL_N14 + "RSV_VCL_R15", // HEVC_NAL_VCL_R15 + "BLA_W_LP", // HEVC_NAL_BLA_W_LP + "BLA_W_RADL", // HEVC_NAL_BLA_W_RADL + "BLA_N_LP", // HEVC_NAL_BLA_N_LP + "IDR_W_RADL", // HEVC_NAL_IDR_W_RADL + "IDR_N_LP", // HEVC_NAL_IDR_N_LP + "CRA_NUT", // HEVC_NAL_CRA_NUT + "IRAP_IRAP_VCL22", // HEVC_NAL_IRAP_VCL22 + "IRAP_IRAP_VCL23", // HEVC_NAL_IRAP_VCL23 + "RSV_VCL24", // HEVC_NAL_RSV_VCL24 + "RSV_VCL25", // HEVC_NAL_RSV_VCL25 + "RSV_VCL26", // HEVC_NAL_RSV_VCL26 + "RSV_VCL27", // HEVC_NAL_RSV_VCL27 + "RSV_VCL28", // HEVC_NAL_RSV_VCL28 + "RSV_VCL29", // HEVC_NAL_RSV_VCL29 + "RSV_VCL30", // HEVC_NAL_RSV_VCL30 + "RSV_VCL31", // HEVC_NAL_RSV_VCL31 + "VPS", // HEVC_NAL_VPS + "SPS", // HEVC_NAL_SPS + "PPS", // HEVC_NAL_PPS + "AUD", // HEVC_NAL_AUD + "EOS_NUT", // HEVC_NAL_EOS_NUT + "EOB_NUT", // HEVC_NAL_EOB_NUT + "FD_NUT", // HEVC_NAL_FD_NUT + "SEI_PREFIX", // HEVC_NAL_SEI_PREFIX + "SEI_SUFFIX", // HEVC_NAL_SEI_SUFFIX + "RSV_NVCL41", // HEVC_NAL_RSV_NVCL41 + "RSV_NVCL42", // HEVC_NAL_RSV_NVCL42 + "RSV_NVCL43", // HEVC_NAL_RSV_NVCL43 + "RSV_NVCL44", // HEVC_NAL_RSV_NVCL44 + "RSV_NVCL45", // HEVC_NAL_RSV_NVCL45 + "RSV_NVCL46", // HEVC_NAL_RSV_NVCL46 + "RSV_NVCL47", // HEVC_NAL_RSV_NVCL47 + "UNSPEC48", // HEVC_NAL_UNSPEC48 + "UNSPEC49", // HEVC_NAL_UNSPEC49 + "UNSPEC50", // HEVC_NAL_UNSPEC50 + "UNSPEC51", // HEVC_NAL_UNSPEC51 + "UNSPEC52", // HEVC_NAL_UNSPEC52 + "UNSPEC53", // HEVC_NAL_UNSPEC53 + "UNSPEC54", // HEVC_NAL_UNSPEC54 + "UNSPEC55", // HEVC_NAL_UNSPEC55 + "UNSPEC56", // HEVC_NAL_UNSPEC56 + "UNSPEC57", // HEVC_NAL_UNSPEC57 + "UNSPEC58", // HEVC_NAL_UNSPEC58 + "UNSPEC59", // HEVC_NAL_UNSPEC59 + "UNSPEC60", // HEVC_NAL_UNSPEC60 + "UNSPEC61", // HEVC_NAL_UNSPEC61 + "UNSPEC62", // HEVC_NAL_UNSPEC62 + "UNSPEC63", // HEVC_NAL_UNSPEC63 +}; + +static const char *hevc_nal_unit_name(int nal_type) +{ + return hevc_nal_type_name[nal_type]; +} + +/** +* Parse NAL units of found picture and decode some basic information. +* +* @param s parser context. +* @param avctx codec context. +* @param buf buffer with field/frame data. +* @param buf_size size of the buffer. +*/ +static int decode_extradata_ps(u8 *data, int size, struct h265_param_sets *ps) +{ + int ret = 0; + struct get_bits_context gb; + u32 src_len, rbsp_size = 0; + u8 *rbsp_buf = NULL; + int nalu_pos, nuh_layer_id, temporal_id; + u32 nal_type; + u8 *p = data; + u32 len = size; + + nalu_pos = find_start_code(p, len); + if (nalu_pos < 0) + return -1; + + src_len = calc_nal_len(p + nalu_pos, size - nalu_pos); + rbsp_buf = nal_unit_extract_rbsp(p + nalu_pos, src_len, &rbsp_size); + if (rbsp_buf == NULL) + return -ENOMEM; + + ret = init_get_bits8(&gb, rbsp_buf, rbsp_size); + if (ret < 0) + goto out; + + if (get_bits1(&gb) != 0) { + ret = -1; + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "invalid data, return!\n"); + goto out; + } + + nal_type = get_bits(&gb, 6); + nuh_layer_id = get_bits(&gb, 6); + temporal_id = get_bits(&gb, 3) - 1; + if (temporal_id < 0) { + ret = -1; + goto out; + } + + /*pr_info("nal_unit_type: %d(%s), nuh_layer_id: %d, temporal_id: %d\n", + nal_type, hevc_nal_unit_name(nal_type), + nuh_layer_id, temporal_id);*/ + + switch (nal_type) { + case HEVC_NAL_VPS: + ret = ff_hevc_parse_vps(&gb, &ps->vps); + if (ret < 0) + goto out; + ps->vps_parsed = true; + break; + case HEVC_NAL_SPS: + ret = ff_hevc_parse_sps(&gb, &ps->sps); + if (ret < 0) + goto out; + ps->sps_parsed = true; + break; + /*case HEVC_NAL_PPS: + ret = ff_hevc_decode_nal_pps(&gb, NULL, ps); + if (ret < 0) + goto out; + ps->pps_parsed = true; + break;*/ + default: + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Unsupport parser nal type (%s).\n", + hevc_nal_unit_name(nal_type)); + break; + } + +out: + vfree(rbsp_buf); + + return ret; +} + +int h265_decode_extradata_ps(u8 *buf, int size, struct h265_param_sets *ps) +{ + int ret = 0, i = 0, j = 0; + u8 *p = buf; + int len = size; + + for (i = 4; i < size; i++) { + j = find_start_code(p, len); + if (j > 0) { + len = size - (p - buf); + ret = decode_extradata_ps(p, len, ps); + if (ret) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "parse extra data failed. err: %d\n", ret); + return ret; + } + + if (ps->sps_parsed) + break; + + p += j; + } + p++; + } + + return ret; +} +
diff --git a/drivers/amvdec_ports/decoder/aml_hevc_parser.h b/drivers/amvdec_ports/decoder/aml_hevc_parser.h new file mode 100644 index 0000000..9223639 --- /dev/null +++ b/drivers/amvdec_ports/decoder/aml_hevc_parser.h
@@ -0,0 +1,562 @@ +/* + * drivers/amvdec_ports/decoder/aml_hevc_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_HEVC_PARSER_H +#define AML_HEVC_PARSER_H + +#include "../aml_vcodec_drv.h" +#include "../utils/common.h" + +#define MAX_DPB_SIZE 16 // A.4.1 +#define MAX_REFS 16 + +#define MAX_NB_THREADS 16 +#define SHIFT_CTB_WPP 2 + +/** + * 7.4.2.1 + */ +#define MAX_SUB_LAYERS 7 +#define MAX_VPS_COUNT 16 +#define MAX_SPS_COUNT 32 +#define MAX_PPS_COUNT 256 +#define MAX_SHORT_TERM_RPS_COUNT 64 +#define MAX_CU_SIZE 128 + +//TODO: check if this is really the maximum +#define MAX_TRANSFORM_DEPTH 5 + +#define MAX_TB_SIZE 32 +#define MAX_PB_SIZE 64 +#define MAX_LOG2_CTB_SIZE 6 +#define MAX_QP 51 +#define DEFAULT_INTRA_TC_OFFSET 2 + +#define HEVC_CONTEXTS 183 + +#define MRG_MAX_NUM_CANDS 5 + +#define L0 0 +#define L1 1 + +#define EPEL_EXTRA_BEFORE 1 +#define EPEL_EXTRA_AFTER 2 +#define EPEL_EXTRA 3 + +#define FF_PROFILE_HEVC_MAIN 1 +#define FF_PROFILE_HEVC_MAIN_10 2 +#define FF_PROFILE_HEVC_MAIN_STILL_PICTURE 3 +#define FF_PROFILE_HEVC_REXT 4 + +/** + * Value of the luma sample at position (x, y) in the 2D array tab. + */ +#define SAMPLE(tab, x, y) ((tab)[(y) * s->sps->width + (x)]) +#define SAMPLE_CTB(tab, x, y) ((tab)[(y) * min_cb_width + (x)]) +#define SAMPLE_CBF(tab, x, y) ((tab)[((y) & ((1<<log2_trafo_size)-1)) * MAX_CU_SIZE + ((x) & ((1<<log2_trafo_size)-1))]) + +#define IS_IDR(s) (s->nal_unit_type == NAL_IDR_W_RADL || s->nal_unit_type == NAL_IDR_N_LP) +#define IS_BLA(s) (s->nal_unit_type == NAL_BLA_W_RADL || s->nal_unit_type == NAL_BLA_W_LP || \ + s->nal_unit_type == NAL_BLA_N_LP) +#define IS_IRAP(s) (s->nal_unit_type >= 16 && s->nal_unit_type <= 23) + +/** + * Table 7-3: NAL unit type codes + */ +enum HEVCNALUnitType { + HEVC_NAL_TRAIL_N = 0, + HEVC_NAL_TRAIL_R = 1, + HEVC_NAL_TSA_N = 2, + HEVC_NAL_TSA_R = 3, + HEVC_NAL_STSA_N = 4, + HEVC_NAL_STSA_R = 5, + HEVC_NAL_RADL_N = 6, + HEVC_NAL_RADL_R = 7, + HEVC_NAL_RASL_N = 8, + HEVC_NAL_RASL_R = 9, + HEVC_NAL_VCL_N10 = 10, + HEVC_NAL_VCL_R11 = 11, + HEVC_NAL_VCL_N12 = 12, + HEVC_NAL_VCL_R13 = 13, + HEVC_NAL_VCL_N14 = 14, + HEVC_NAL_VCL_R15 = 15, + HEVC_NAL_BLA_W_LP = 16, + HEVC_NAL_BLA_W_RADL = 17, + HEVC_NAL_BLA_N_LP = 18, + HEVC_NAL_IDR_W_RADL = 19, + HEVC_NAL_IDR_N_LP = 20, + HEVC_NAL_CRA_NUT = 21, + HEVC_NAL_IRAP_VCL22 = 22, + HEVC_NAL_IRAP_VCL23 = 23, + HEVC_NAL_RSV_VCL24 = 24, + HEVC_NAL_RSV_VCL25 = 25, + HEVC_NAL_RSV_VCL26 = 26, + HEVC_NAL_RSV_VCL27 = 27, + HEVC_NAL_RSV_VCL28 = 28, + HEVC_NAL_RSV_VCL29 = 29, + HEVC_NAL_RSV_VCL30 = 30, + HEVC_NAL_RSV_VCL31 = 31, + HEVC_NAL_VPS = 32, + HEVC_NAL_SPS = 33, + HEVC_NAL_PPS = 34, + HEVC_NAL_AUD = 35, + HEVC_NAL_EOS_NUT = 36, + HEVC_NAL_EOB_NUT = 37, + HEVC_NAL_FD_NUT = 38, + HEVC_NAL_SEI_PREFIX = 39, + HEVC_NAL_SEI_SUFFIX = 40, +}; + +enum HEVCSliceType { + HEVC_SLICE_B = 0, + HEVC_SLICE_P = 1, + HEVC_SLICE_I = 2, +}; + +enum { + // 7.4.3.1: vps_max_layers_minus1 is in [0, 62]. + HEVC_MAX_LAYERS = 63, + // 7.4.3.1: vps_max_sub_layers_minus1 is in [0, 6]. + HEVC_MAX_SUB_LAYERS = 7, + // 7.4.3.1: vps_num_layer_sets_minus1 is in [0, 1023]. + HEVC_MAX_LAYER_SETS = 1024, + + // 7.4.2.1: vps_video_parameter_set_id is u(4). + HEVC_MAX_VPS_COUNT = 16, + // 7.4.3.2.1: sps_seq_parameter_set_id is in [0, 15]. + HEVC_MAX_SPS_COUNT = 16, + // 7.4.3.3.1: pps_pic_parameter_set_id is in [0, 63]. + HEVC_MAX_PPS_COUNT = 64, + + // A.4.2: MaxDpbSize is bounded above by 16. + HEVC_MAX_DPB_SIZE = 16, + // 7.4.3.1: vps_max_dec_pic_buffering_minus1[i] is in [0, MaxDpbSize - 1]. + HEVC_MAX_REFS = HEVC_MAX_DPB_SIZE, + + // 7.4.3.2.1: num_short_term_ref_pic_sets is in [0, 64]. + HEVC_MAX_SHORT_TERM_REF_PIC_SETS = 64, + // 7.4.3.2.1: num_long_term_ref_pics_sps is in [0, 32]. + HEVC_MAX_LONG_TERM_REF_PICS = 32, + + // A.3: all profiles require that CtbLog2SizeY is in [4, 6]. + HEVC_MIN_LOG2_CTB_SIZE = 4, + HEVC_MAX_LOG2_CTB_SIZE = 6, + + // E.3.2: cpb_cnt_minus1[i] is in [0, 31]. + HEVC_MAX_CPB_CNT = 32, + + // A.4.1: in table A.6 the highest level allows a MaxLumaPs of 35 651 584. + HEVC_MAX_LUMA_PS = 35651584, + // A.4.1: pic_width_in_luma_samples and pic_height_in_luma_samples are + // constrained to be not greater than sqrt(MaxLumaPs * 8). Hence height/ + // width are bounded above by sqrt(8 * 35651584) = 16888.2 samples. + HEVC_MAX_WIDTH = 16888, + HEVC_MAX_HEIGHT = 16888, + + // A.4.1: table A.6 allows at most 22 tile rows for any level. + HEVC_MAX_TILE_ROWS = 22, + // A.4.1: table A.6 allows at most 20 tile columns for any level. + HEVC_MAX_TILE_COLUMNS = 20, + + // 7.4.7.1: in the worst case (tiles_enabled_flag and + // entropy_coding_sync_enabled_flag are both set), entry points can be + // placed at the beginning of every Ctb row in every tile, giving an + // upper bound of (num_tile_columns_minus1 + 1) * PicHeightInCtbsY - 1. + // Only a stream with very high resolution and perverse parameters could + // get near that, though, so set a lower limit here with the maximum + // possible value for 4K video (at most 135 16x16 Ctb rows). + HEVC_MAX_ENTRY_POINT_OFFSETS = HEVC_MAX_TILE_COLUMNS * 135, +}; + +struct ShortTermRPS { + u32 num_negative_pics; + int num_delta_pocs; + int rps_idx_num_delta_pocs; + int delta_poc[32]; + u8 used[32]; +}; + +struct LongTermRPS { + int poc[32]; + u8 used[32]; + u8 nb_refs; +}; + +struct SliceHeader { + u32 pps_id; + + ///< address (in raster order) of the first block in the current slice segment + u32 slice_segment_addr; + ///< address (in raster order) of the first block in the current slice + u32 slice_addr; + + enum HEVCSliceType slice_type; + + int pic_order_cnt_lsb; + + u8 first_slice_in_pic_flag; + u8 dependent_slice_segment_flag; + u8 pic_output_flag; + u8 colour_plane_id; + + ///< RPS coded in the slice header itself is stored here + int short_term_ref_pic_set_sps_flag; + int short_term_ref_pic_set_size; + struct ShortTermRPS slice_rps; + const struct ShortTermRPS *short_term_rps; + int long_term_ref_pic_set_size; + struct LongTermRPS long_term_rps; + u32 list_entry_lx[2][32]; + + u8 rpl_modification_flag[2]; + u8 no_output_of_prior_pics_flag; + u8 slice_temporal_mvp_enabled_flag; + + u32 nb_refs[2]; + + u8 slice_sample_adaptive_offset_flag[3]; + u8 mvd_l1_zero_flag; + + u8 cabac_init_flag; + u8 disable_deblocking_filter_flag; ///< slice_header_disable_deblocking_filter_flag + u8 slice_loop_filter_across_slices_enabled_flag; + u8 collocated_list; + + u32 collocated_ref_idx; + + int slice_qp_delta; + int slice_cb_qp_offset; + int slice_cr_qp_offset; + + u8 cu_chroma_qp_offset_enabled_flag; + + int beta_offset; ///< beta_offset_div2 * 2 + int tc_offset; ///< tc_offset_div2 * 2 + + u32 max_num_merge_cand; ///< 5 - 5_minus_max_num_merge_cand + + u8 *entry_point_offset; + int * offset; + int * size; + int num_entry_point_offsets; + + char slice_qp; + + u8 luma_log2_weight_denom; + s16 chroma_log2_weight_denom; + + s16 luma_weight_l0[16]; + s16 chroma_weight_l0[16][2]; + s16 chroma_weight_l1[16][2]; + s16 luma_weight_l1[16]; + + s16 luma_offset_l0[16]; + s16 chroma_offset_l0[16][2]; + + s16 luma_offset_l1[16]; + s16 chroma_offset_l1[16][2]; + + int slice_ctb_addr_rs; +}; + +struct HEVCWindow { + u32 left_offset; + u32 right_offset; + u32 top_offset; + u32 bottom_offset; +}; + +struct VUI { +#ifdef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER + struct AVRational sar; +#endif + int overscan_info_present_flag; + int overscan_appropriate_flag; + + int video_signal_type_present_flag; + int video_format; + int video_full_range_flag; + int colour_description_present_flag; + u8 colour_primaries; + u8 transfer_characteristic; + u8 matrix_coeffs; + + int chroma_loc_info_present_flag; + int chroma_sample_loc_type_top_field; + int chroma_sample_loc_type_bottom_field; + int neutra_chroma_indication_flag; + + int field_seq_flag; + int frame_field_info_present_flag; + + int default_display_window_flag; + struct HEVCWindow def_disp_win; + + int vui_timing_info_present_flag; + u32 vui_num_units_in_tick; + u32 vui_time_scale; + int vui_poc_proportional_to_timing_flag; + int vui_num_ticks_poc_diff_one_minus1; + int vui_hrd_parameters_present_flag; + + int bitstream_restriction_flag; + int tiles_fixed_structure_flag; + int motion_vectors_over_pic_boundaries_flag; + int restricted_ref_pic_lists_flag; + int min_spatial_segmentation_idc; + int max_bytes_per_pic_denom; + int max_bits_per_min_cu_denom; + int log2_max_mv_length_horizontal; + int log2_max_mv_length_vertical; +}; + +struct PTLCommon { + u8 profile_space; + u8 tier_flag; + u8 profile_idc; + u8 profile_compatibility_flag[32]; + u8 level_idc; + u8 progressive_source_flag; + u8 interlaced_source_flag; + u8 non_packed_constraint_flag; + u8 frame_only_constraint_flag; +}; + +struct PTL { + struct PTLCommon general_ptl; + struct PTLCommon sub_layer_ptl[HEVC_MAX_SUB_LAYERS]; + + u8 sub_layer_profile_present_flag[HEVC_MAX_SUB_LAYERS]; + u8 sub_layer_level_present_flag[HEVC_MAX_SUB_LAYERS]; +}; + +struct h265_VPS_t { + u8 vps_temporal_id_nesting_flag; + int vps_max_layers; + int vps_max_sub_layers; ///< vps_max_temporal_layers_minus1 + 1 + + struct PTL ptl; + int vps_sub_layer_ordering_info_present_flag; + u32 vps_max_dec_pic_buffering[HEVC_MAX_SUB_LAYERS]; + u32 vps_num_reorder_pics[HEVC_MAX_SUB_LAYERS]; + u32 vps_max_latency_increase[HEVC_MAX_SUB_LAYERS]; + int vps_max_layer_id; + int vps_num_layer_sets; ///< vps_num_layer_sets_minus1 + 1 + u8 vps_timing_info_present_flag; + u32 vps_num_units_in_tick; + u32 vps_time_scale; + u8 vps_poc_proportional_to_timing_flag; + int vps_num_ticks_poc_diff_one; ///< vps_num_ticks_poc_diff_one_minus1 + 1 + int vps_num_hrd_parameters; +}; + +struct ScalingList { + /* This is a little wasteful, since sizeID 0 only needs 8 coeffs, + * and size ID 3 only has 2 arrays, not 6. */ + u8 sl[4][6][64]; + u8 sl_dc[2][6]; +}; + +struct h265_SPS_t { + u8 vps_id; + u8 sps_id; + int chroma_format_idc; + u8 separate_colour_plane_flag; + + struct HEVCWindow output_window; + struct HEVCWindow pic_conf_win; + + int bit_depth; + int bit_depth_chroma; + int pixel_shift; + int pix_fmt; + + u32 log2_max_poc_lsb; + int pcm_enabled_flag; + + int max_sub_layers; + struct { + int max_dec_pic_buffering; + int num_reorder_pics; + int max_latency_increase; + } temporal_layer[HEVC_MAX_SUB_LAYERS]; + u8 temporal_id_nesting_flag; + + struct VUI vui; + struct PTL ptl; + + u8 scaling_list_enable_flag; + struct ScalingList scaling_list; + + u32 nb_st_rps; + struct ShortTermRPS st_rps[HEVC_MAX_SHORT_TERM_REF_PIC_SETS]; + + u8 amp_enabled_flag; + u8 sao_enabled; + + u8 long_term_ref_pics_present_flag; + u16 lt_ref_pic_poc_lsb_sps[HEVC_MAX_LONG_TERM_REF_PICS]; + u8 used_by_curr_pic_lt_sps_flag[HEVC_MAX_LONG_TERM_REF_PICS]; + u8 num_long_term_ref_pics_sps; + + struct { + u8 bit_depth; + u8 bit_depth_chroma; + u32 log2_min_pcm_cb_size; + u32 log2_max_pcm_cb_size; + u8 loop_filter_disable_flag; + } pcm; + u8 sps_temporal_mvp_enabled_flag; + u8 sps_strong_intra_smoothing_enable_flag; + + u32 log2_min_cb_size; + u32 log2_diff_max_min_coding_block_size; + u32 log2_min_tb_size; + u32 log2_max_trafo_size; + u32 log2_ctb_size; + u32 log2_min_pu_size; + + int max_transform_hierarchy_depth_inter; + int max_transform_hierarchy_depth_intra; + + int sps_range_extension_flag; + int transform_skip_rotation_enabled_flag; + int transform_skip_context_enabled_flag; + int implicit_rdpcm_enabled_flag; + int explicit_rdpcm_enabled_flag; + int extended_precision_processing_flag; + int intra_smoothing_disabled_flag; + int high_precision_offsets_enabled_flag; + int persistent_rice_adaptation_enabled_flag; + int cabac_bypass_alignment_enabled_flag; + + ///< coded frame dimension in various units + int width; + int height; + int ctb_width; + int ctb_height; + int ctb_size; + int min_cb_width; + int min_cb_height; + int min_tb_width; + int min_tb_height; + int min_pu_width; + int min_pu_height; + int tb_mask; + + int hshift[3]; + int vshift[3]; + + int qp_bd_offset; + + u8 data[4096]; + int data_size; +}; + +struct h265_PPS_t { + u32 sps_id; ///< seq_parameter_set_id + + u8 sign_data_hiding_flag; + + u8 cabac_init_present_flag; + + int num_ref_idx_l0_default_active; ///< num_ref_idx_l0_default_active_minus1 + 1 + int num_ref_idx_l1_default_active; ///< num_ref_idx_l1_default_active_minus1 + 1 + int pic_init_qp_minus26; + + u8 constrained_intra_pred_flag; + u8 transform_skip_enabled_flag; + + u8 cu_qp_delta_enabled_flag; + int diff_cu_qp_delta_depth; + + int cb_qp_offset; + int cr_qp_offset; + u8 pic_slice_level_chroma_qp_offsets_present_flag; + u8 weighted_pred_flag; + u8 weighted_bipred_flag; + u8 output_flag_present_flag; + u8 transquant_bypass_enable_flag; + + u8 dependent_slice_segments_enabled_flag; + u8 tiles_enabled_flag; + u8 entropy_coding_sync_enabled_flag; + + int num_tile_columns; ///< num_tile_columns_minus1 + 1 + int num_tile_rows; ///< num_tile_rows_minus1 + 1 + u8 uniform_spacing_flag; + u8 loop_filter_across_tiles_enabled_flag; + + u8 seq_loop_filter_across_slices_enabled_flag; + + u8 deblocking_filter_control_present_flag; + u8 deblocking_filter_override_enabled_flag; + u8 disable_dbf; + int beta_offset; ///< beta_offset_div2 * 2 + int tc_offset; ///< tc_offset_div2 * 2 + + u8 scaling_list_data_present_flag; + struct ScalingList scaling_list; + + u8 lists_modification_present_flag; + int log2_parallel_merge_level; ///< log2_parallel_merge_level_minus2 + 2 + int num_extra_slice_header_bits; + u8 slice_header_extension_present_flag; + u8 log2_max_transform_skip_block_size; + u8 cross_component_prediction_enabled_flag; + u8 chroma_qp_offset_list_enabled_flag; + u8 diff_cu_chroma_qp_offset_depth; + u8 chroma_qp_offset_list_len_minus1; + char cb_qp_offset_list[6]; + char cr_qp_offset_list[6]; + u8 log2_sao_offset_scale_luma; + u8 log2_sao_offset_scale_chroma; + + // Inferred parameters + u32 *column_width; ///< ColumnWidth + u32 *row_height; ///< RowHeight + u32 *col_bd; ///< ColBd + u32 *row_bd; ///< RowBd + int *col_idxX; + + int *ctb_addr_rs_to_ts; ///< CtbAddrRSToTS + int *ctb_addr_ts_to_rs; ///< CtbAddrTSToRS + int *tile_id; ///< TileId + int *tile_pos_rs; ///< TilePosRS + int *min_tb_addr_zs; ///< MinTbAddrZS + int *min_tb_addr_zs_tab;///< MinTbAddrZS +}; + +struct h265_param_sets { + bool vps_parsed; + bool sps_parsed; + bool pps_parsed; + /* currently active parameter sets */ + struct h265_VPS_t vps; + struct h265_SPS_t sps; + struct h265_PPS_t pps; +}; + +#ifdef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER +int h265_decode_extradata_ps(u8 *data, int size, struct h265_param_sets *ps); +#else +inline int h265_decode_extradata_ps(u8 *data, int size, struct h265_param_sets *ps) { return -1; } +#endif + +#endif /* AML_HEVC_PARSER_H */ +
diff --git a/drivers/amvdec_ports/decoder/aml_mjpeg_parser.c b/drivers/amvdec_ports/decoder/aml_mjpeg_parser.c new file mode 100644 index 0000000..c582ab0 --- /dev/null +++ b/drivers/amvdec_ports/decoder/aml_mjpeg_parser.c
@@ -0,0 +1,397 @@ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/vmalloc.h> +#include <linux/mm.h> +#include <linux/string.h> + +#include "aml_mjpeg_parser.h" +#include "../utils/get_bits.h" +#include "../utils/put_bits.h" +#include "../utils/golomb.h" +#include "../utils/common.h" +#include "utils.h" + +/* return the 8 bit start code value and update the search +state. Return -1 if no start code found */ +static int find_marker(const u8 **pbuf_ptr, const u8 *buf_end) +{ + const u8 *buf_ptr; + u32 v, v2; + int val; + int skipped = 0; + + buf_ptr = *pbuf_ptr; + while (buf_end - buf_ptr > 1) { + v = *buf_ptr++; + v2 = *buf_ptr; + if ((v == 0xff) && (v2 >= 0xc0) && (v2 <= 0xfe) && buf_ptr < buf_end) { + val = *buf_ptr++; + goto found; + } + skipped++; + } + buf_ptr = buf_end; + val = -1; +found: + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "find_marker skipped %d bytes\n", skipped); + *pbuf_ptr = buf_ptr; + + return val; +} + +int ff_mjpeg_find_marker(struct MJpegDecodeContext *s, + const u8 **buf_ptr, const u8 *buf_end, + const u8 **unescaped_buf_ptr, + int *unescaped_buf_size) +{ + int start_code; + + start_code = find_marker(buf_ptr, buf_end); + + /* unescape buffer of SOS, use special treatment for JPEG-LS */ + if (start_code == SOS && !s->ls) { + const u8 *src = *buf_ptr; + const u8 *ptr = src; + u8 *dst = s->buffer; + + #define copy_data_segment(skip) do { \ + int length = (ptr - src) - (skip); \ + if (length > 0) { \ + memcpy(dst, src, length); \ + dst += length; \ + src = ptr; \ + } \ + } while (0) + + + while (ptr < buf_end) { + u8 x = *(ptr++); + + if (x == 0xff) { + int skip = 0; + while (ptr < buf_end && x == 0xff) { + x = *(ptr++); + skip++; + } + + /* 0xFF, 0xFF, ... */ + if (skip > 1) { + copy_data_segment(skip); + + /* decrement src as it is equal to ptr after the + * copy_data_segment macro and we might want to + * copy the current value of x later on */ + src--; + } + + if (x < 0xd0 || x > 0xd7) { + copy_data_segment(1); + if (x) + break; + } + } + if (src < ptr) + copy_data_segment(0); + } + #undef copy_data_segment + + *unescaped_buf_ptr = s->buffer; + *unescaped_buf_size = dst - s->buffer; + memset(s->buffer + *unescaped_buf_size, 0, + AV_INPUT_BUFFER_PADDING_SIZE); + + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "escaping removed %d bytes\n", + (int)((buf_end - *buf_ptr) - (dst - s->buffer))); + } else if (start_code == SOS && s->ls) { + const u8 *src = *buf_ptr; + u8 *dst = s->buffer; + int bit_count = 0; + int t = 0, b = 0; + struct put_bits_context pb; + + /* find marker */ + while (src + t < buf_end) { + u8 x = src[t++]; + if (x == 0xff) { + while ((src + t < buf_end) && x == 0xff) + x = src[t++]; + if (x & 0x80) { + t -= FFMIN(2, t); + break; + } + } + } + bit_count = t * 8; + init_put_bits(&pb, dst, t); + + /* unescape bitstream */ + while (b < t) { + u8 x = src[b++]; + put_bits(&pb, 8, x); + if (x == 0xFF && b < t) { + x = src[b++]; + if (x & 0x80) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Invalid escape sequence\n"); + x &= 0x7f; + } + put_bits(&pb, 7, x); + bit_count--; + } + } + flush_put_bits(&pb); + + *unescaped_buf_ptr = dst; + *unescaped_buf_size = (bit_count + 7) >> 3; + memset(s->buffer + *unescaped_buf_size, 0, + AV_INPUT_BUFFER_PADDING_SIZE); + } else { + *unescaped_buf_ptr = *buf_ptr; + *unescaped_buf_size = buf_end - *buf_ptr; + } + + return start_code; +} + + +int ff_mjpeg_decode_sof(struct MJpegDecodeContext *s) +{ + int len, nb_components, i, width, height, bits, size_change; + int h_count[MAX_COMPONENTS] = { 0 }; + int v_count[MAX_COMPONENTS] = { 0 }; + + s->cur_scan = 0; + memset(s->upscale_h, 0, sizeof(s->upscale_h)); + memset(s->upscale_v, 0, sizeof(s->upscale_v)); + + /* XXX: verify len field validity */ + len = get_bits(&s->gb, 16); + bits = get_bits(&s->gb, 8); + + if (bits > 16 || bits < 1) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "bits %d is invalid\n", bits); + return -1; + } + + height = get_bits(&s->gb, 16); + width = get_bits(&s->gb, 16); + + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "sof0: picture: %dx%d\n", width, height); + + nb_components = get_bits(&s->gb, 8); + if (nb_components <= 0 || + nb_components > MAX_COMPONENTS) + return -1; + + s->nb_components = nb_components; + s->h_max = 1; + s->v_max = 1; + for (i = 0; i < nb_components; i++) { + /* component id */ + s->component_id[i] = get_bits(&s->gb, 8) - 1; + h_count[i] = get_bits(&s->gb, 4); + v_count[i] = get_bits(&s->gb, 4); + /* compute hmax and vmax (only used in interleaved case) */ + if (h_count[i] > s->h_max) + s->h_max = h_count[i]; + if (v_count[i] > s->v_max) + s->v_max = v_count[i]; + s->quant_index[i] = get_bits(&s->gb, 8); + if (s->quant_index[i] >= 4) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "quant_index is invalid\n"); + return -1; + } + if (!h_count[i] || !v_count[i]) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Invalid sampling factor in component %d %d:%d\n", + i, h_count[i], v_count[i]); + return -1; + } + + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "component %d %d:%d id: %d quant:%d\n", + i, h_count[i], v_count[i], + s->component_id[i], s->quant_index[i]); + } + if (nb_components == 4 + && s->component_id[0] == 'C' - 1 + && s->component_id[1] == 'M' - 1 + && s->component_id[2] == 'Y' - 1 + && s->component_id[3] == 'K' - 1) + s->adobe_transform = 0; + + /* if different size, realloc/alloc picture */ + if (width != s->width || height != s->height || bits != s->bits || + memcmp(s->h_count, h_count, sizeof(h_count)) || + memcmp(s->v_count, v_count, sizeof(v_count))) { + size_change = 1; + + s->width = width; + s->height = height; + s->bits = bits; + memcpy(s->h_count, h_count, sizeof(h_count)); + memcpy(s->v_count, v_count, sizeof(v_count)); + s->interlaced = 0; + s->got_picture = 0; + } else { + size_change = 0; + } + + return 0; +} + +static int ff_mjpeg_decode_frame(u8 *buf, int buf_size, struct MJpegDecodeContext *s) +{ + const u8 *buf_end, *buf_ptr; + const u8 *unescaped_buf_ptr; + int unescaped_buf_size; + int start_code; + int ret = 0; + + buf_ptr = buf; + buf_end = buf + buf_size; + while (buf_ptr < buf_end) { + /* find start next marker */ + start_code = ff_mjpeg_find_marker(s, &buf_ptr, buf_end, + &unescaped_buf_ptr, + &unescaped_buf_size); + /* EOF */ + if (start_code < 0) { + break; + } else if (unescaped_buf_size > INT_MAX / 8) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "MJPEG packet 0x%x too big (%d/%d), corrupt data?\n", + start_code, unescaped_buf_size, buf_size); + return -1; + } + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "marker=%x avail_size_in_buf=%d\n", + start_code, (int)(buf_end - buf_ptr)); + + ret = init_get_bits8(&s->gb, unescaped_buf_ptr, unescaped_buf_size); + if (ret < 0) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "invalid buffer\n"); + goto fail; + } + + s->start_code = start_code; + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "startcode: %X\n", start_code); + + switch (start_code) { + case SOF0: + case SOF1: + case SOF2: + case SOF3: + case SOF48: + case SOI: + case SOS: + case EOI: + break; + default: + goto skip; + } + + switch (start_code) { + case SOI: + s->restart_interval = 0; + s->restart_count = 0; + s->raw_image_buffer = buf_ptr; + s->raw_image_buffer_size = buf_end - buf_ptr; + /* nothing to do on SOI */ + break; + case SOF0: + case SOF1: + if (start_code == SOF0) + s->profile = FF_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT; + else + s->profile = FF_PROFILE_MJPEG_HUFFMAN_EXTENDED_SEQUENTIAL_DCT; + s->lossless = 0; + s->ls = 0; + s->progressive = 0; + if ((ret = ff_mjpeg_decode_sof(s)) < 0) + goto fail; + break; + case SOF2: + s->profile = FF_PROFILE_MJPEG_HUFFMAN_PROGRESSIVE_DCT; + s->lossless = 0; + s->ls = 0; + s->progressive = 1; + if ((ret = ff_mjpeg_decode_sof(s)) < 0) + goto fail; + break; + case SOF3: + s->profile = FF_PROFILE_MJPEG_HUFFMAN_LOSSLESS; + s->properties |= FF_CODEC_PROPERTY_LOSSLESS; + s->lossless = 1; + s->ls = 0; + s->progressive = 0; + if ((ret = ff_mjpeg_decode_sof(s)) < 0) + goto fail; + break; + case SOF48: + s->profile = FF_PROFILE_MJPEG_JPEG_LS; + s->properties |= FF_CODEC_PROPERTY_LOSSLESS; + s->lossless = 1; + s->ls = 1; + s->progressive = 0; + if ((ret = ff_mjpeg_decode_sof(s)) < 0) + goto fail; + break; + case EOI: + goto the_end; + case DHT: + case LSE: + case SOS: + case DRI: + case SOF5: + case SOF6: + case SOF7: + case SOF9: + case SOF10: + case SOF11: + case SOF13: + case SOF14: + case SOF15: + case JPG: + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "mjpeg: unsupported coding type (%x)\n", start_code); + break; + } +skip: + /* eof process start code */ + buf_ptr += (get_bits_count(&s->gb) + 7) / 8; + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "marker parser used %d bytes (%d bits)\n", + (get_bits_count(&s->gb) + 7) / 8, get_bits_count(&s->gb)); + } + + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "No JPEG data found in image\n"); + return -1; +fail: + s->got_picture = 0; + return ret; +the_end: + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "decode frame unused %d bytes\n", (int)(buf_end - buf_ptr)); + + return 0; +} + +int mjpeg_decode_extradata_ps(u8 *buf, int size, struct mjpeg_param_sets *ps) +{ + int ret; + + ps->head_parsed = false; + + ps->dec_ps.buf_size = size; + ps->dec_ps.buffer = vzalloc(size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!ps->dec_ps.buffer) + return -1; + + ret = ff_mjpeg_decode_frame(buf, size, &ps->dec_ps); + if (ret) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "parse extra data failed. err: %d\n", ret); + vfree(ps->dec_ps.buffer); + return ret; + } + + if (ps->dec_ps.width && ps->dec_ps.height) + ps->head_parsed = true; + + vfree(ps->dec_ps.buffer); + + return 0; +} +
diff --git a/drivers/amvdec_ports/decoder/aml_mjpeg_parser.h b/drivers/amvdec_ports/decoder/aml_mjpeg_parser.h new file mode 100644 index 0000000..4704ba0 --- /dev/null +++ b/drivers/amvdec_ports/decoder/aml_mjpeg_parser.h
@@ -0,0 +1,170 @@ +#ifndef AML_MJPEG_PARSER_H +#define AML_MJPEG_PARSER_H + +#include "../aml_vcodec_drv.h" +#include "../utils/common.h" +#ifdef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER +#include "../utils/get_bits.h" +#endif + +#define FF_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT 0xc0 +#define FF_PROFILE_MJPEG_HUFFMAN_EXTENDED_SEQUENTIAL_DCT 0xc1 +#define FF_PROFILE_MJPEG_HUFFMAN_PROGRESSIVE_DCT 0xc2 +#define FF_PROFILE_MJPEG_HUFFMAN_LOSSLESS 0xc3 +#define FF_PROFILE_MJPEG_JPEG_LS 0xf7 + +#define FF_CODEC_PROPERTY_LOSSLESS 0x00000001 +#define FF_CODEC_PROPERTY_CLOSED_CAPTIONS 0x00000002 + +#define MAX_COMPONENTS 4 + +/* JPEG marker codes */ +enum JpegMarker { + /* start of frame */ + SOF0 = 0xc0, /* baseline */ + SOF1 = 0xc1, /* extended sequential, huffman */ + SOF2 = 0xc2, /* progressive, huffman */ + SOF3 = 0xc3, /* lossless, huffman */ + + SOF5 = 0xc5, /* differential sequential, huffman */ + SOF6 = 0xc6, /* differential progressive, huffman */ + SOF7 = 0xc7, /* differential lossless, huffman */ + JPG = 0xc8, /* reserved for JPEG extension */ + SOF9 = 0xc9, /* extended sequential, arithmetic */ + SOF10 = 0xca, /* progressive, arithmetic */ + SOF11 = 0xcb, /* lossless, arithmetic */ + + SOF13 = 0xcd, /* differential sequential, arithmetic */ + SOF14 = 0xce, /* differential progressive, arithmetic */ + SOF15 = 0xcf, /* differential lossless, arithmetic */ + + DHT = 0xc4, /* define huffman tables */ + + DAC = 0xcc, /* define arithmetic-coding conditioning */ + + /* restart with modulo 8 count "m" */ + RST0 = 0xd0, + RST1 = 0xd1, + RST2 = 0xd2, + RST3 = 0xd3, + RST4 = 0xd4, + RST5 = 0xd5, + RST6 = 0xd6, + RST7 = 0xd7, + + SOI = 0xd8, /* start of image */ + EOI = 0xd9, /* end of image */ + SOS = 0xda, /* start of scan */ + DQT = 0xdb, /* define quantization tables */ + DNL = 0xdc, /* define number of lines */ + DRI = 0xdd, /* define restart interval */ + DHP = 0xde, /* define hierarchical progression */ + EXP = 0xdf, /* expand reference components */ + + APP0 = 0xe0, + APP1 = 0xe1, + APP2 = 0xe2, + APP3 = 0xe3, + APP4 = 0xe4, + APP5 = 0xe5, + APP6 = 0xe6, + APP7 = 0xe7, + APP8 = 0xe8, + APP9 = 0xe9, + APP10 = 0xea, + APP11 = 0xeb, + APP12 = 0xec, + APP13 = 0xed, + APP14 = 0xee, + APP15 = 0xef, + + JPG0 = 0xf0, + JPG1 = 0xf1, + JPG2 = 0xf2, + JPG3 = 0xf3, + JPG4 = 0xf4, + JPG5 = 0xf5, + JPG6 = 0xf6, + SOF48 = 0xf7, ///< JPEG-LS + LSE = 0xf8, ///< JPEG-LS extension parameters + JPG9 = 0xf9, + JPG10 = 0xfa, + JPG11 = 0xfb, + JPG12 = 0xfc, + JPG13 = 0xfd, + + COM = 0xfe, /* comment */ + + TEM = 0x01, /* temporary private use for arithmetic coding */ + + /* 0x02 -> 0xbf reserved */ +}; + +struct VLC { + int bits; + short (*table)[2]; ///< code, bits + int table_size, table_allocated; +}; + +struct MJpegDecodeContext { +#ifdef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER + struct get_bits_context gb; +#endif + int buf_size; + + int start_code; /* current start code */ + int buffer_size; + u8 *buffer; + + u16 quant_matrixes[4][64]; + struct VLC vlcs[3][4]; + int qscale[4]; ///< quantizer scale calculated from quant_matrixes + + int first_picture; /* true if decoding first picture */ + int interlaced; /* true if interlaced */ + int bottom_field; /* true if bottom field */ + int lossless; + int ls; + int progressive; + u8 upscale_h[4]; + u8 upscale_v[4]; + int bits; /* bits per component */ + int adobe_transform; + + int width, height; + int mb_width, mb_height; + int nb_components; + int block_stride[MAX_COMPONENTS]; + int component_id[MAX_COMPONENTS]; + int h_count[MAX_COMPONENTS]; /* horizontal and vertical count for each component */ + int v_count[MAX_COMPONENTS]; + int h_scount[MAX_COMPONENTS]; + int v_scount[MAX_COMPONENTS]; + int h_max, v_max; /* maximum h and v counts */ + int quant_index[4]; /* quant table index for each component */ + int got_picture; ///< we found a SOF and picture is valid, too. + int restart_interval; + int restart_count; + int cur_scan; /* current scan, used by JPEG-LS */ + + // Raw stream data for hwaccel use. + const u8 *raw_image_buffer; + int raw_image_buffer_size; + + int profile; + u32 properties; +}; + +struct mjpeg_param_sets { + bool head_parsed; + /* currently active parameter sets */ + struct MJpegDecodeContext dec_ps; +}; + +#ifdef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER +int mjpeg_decode_extradata_ps(u8 *buf, int size, struct mjpeg_param_sets *ps); +#else +inline int mjpeg_decode_extradata_ps(u8 *buf, int size, struct mjpeg_param_sets *ps) { return -1; } +#endif + +#endif
diff --git a/drivers/amvdec_ports/decoder/aml_mpeg12_parser.c b/drivers/amvdec_ports/decoder/aml_mpeg12_parser.c new file mode 100644 index 0000000..748a83f --- /dev/null +++ b/drivers/amvdec_ports/decoder/aml_mpeg12_parser.c
@@ -0,0 +1,198 @@ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/vmalloc.h> +#include <linux/mm.h> +#include <linux/string.h> + +#include "aml_mpeg12_parser.h" +#include "../utils/get_bits.h" +#include "../utils/put_bits.h" +#include "../utils/golomb.h" +#include "../utils/common.h" +#include "utils.h" + +const struct AVRational ff_mpeg12_frame_rate_tab[16] = { + { 0, 0}, + {24000, 1001}, + { 24, 1}, + { 25, 1}, + {30000, 1001}, + { 30, 1}, + { 50, 1}, + {60000, 1001}, + { 60, 1}, + // Xing's 15fps: (9) + { 15, 1}, + // libmpeg3's "Unofficial economy rates": (10-13) + { 5, 1}, + { 10, 1}, + { 12, 1}, + { 15, 1}, + { 0, 0}, +}; + +const u8 *avpriv_find_start_code(const u8 *p, const u8 *end, u32 *state) +{ + int i; + + if (p >= end) + return end; + + for (i = 0; i < 3; i++) { + u32 tmp = *state << 8; + *state = tmp + *(p++); + if (tmp == 0x100 || p == end) + return p; + } + + while (p < end) { + if (p[-1] > 1 ) p += 3; + else if (p[-2] ) p += 2; + else if (p[-3]|(p[-1]-1)) p++; + else { + p++; + break; + } + } + + p = FFMIN(p, end) - 4; + *state = AV_RB32(p); + + return p + 4; +} + +static void mpegvideo_extract_headers(const u8 *buf, int buf_size, + struct mpeg12_param_sets *ps) +{ + struct MpvParseContext *pc = &ps->dec_ps; + const u8 *buf_end = buf + buf_size; + u32 start_code; + int frame_rate_index, ext_type, bytes_left; + int frame_rate_ext_n, frame_rate_ext_d; + int top_field_first, repeat_first_field, progressive_frame; + int horiz_size_ext, vert_size_ext, bit_rate_ext; + int bit_rate = 0; + int vbv_delay = 0; + int chroma_format; + enum AVPixelFormat pix_fmt = AV_PIX_FMT_NONE; + //FIXME replace the crap with get_bits() + pc->repeat_pict = 0; + + while (buf < buf_end) { + start_code= -1; + buf= avpriv_find_start_code(buf, buf_end, &start_code); + bytes_left = buf_end - buf; + switch (start_code) { + case PICTURE_START_CODE: + if (bytes_left >= 2) { + pc->pict_type = (buf[1] >> 3) & 7; + if (bytes_left >= 4) + vbv_delay = ((buf[1] & 0x07) << 13) | (buf[2] << 5) | (buf[3] >> 3); + } + break; + case SEQ_START_CODE: + if (bytes_left >= 7) { + pc->width = (buf[0] << 4) | (buf[1] >> 4); + pc->height = ((buf[1] & 0x0f) << 8) | buf[2]; + + pix_fmt = AV_PIX_FMT_YUV420P; + frame_rate_index = buf[3] & 0xf; + pc->frame_rate = ff_mpeg12_frame_rate_tab[frame_rate_index]; + bit_rate = (buf[4]<<10) | (buf[5]<<2) | (buf[6]>>6); + pc->ticks_per_frame = 1; + } + break; + case EXT_START_CODE: + if (bytes_left >= 1) { + ext_type = (buf[0] >> 4); + switch (ext_type) { + case 0x1: /* sequence extension */ + if (bytes_left >= 6) { + horiz_size_ext = ((buf[1] & 1) << 1) | (buf[2] >> 7); + vert_size_ext = (buf[2] >> 5) & 3; + bit_rate_ext = ((buf[2] & 0x1F)<<7) | (buf[3]>>1); + frame_rate_ext_n = (buf[5] >> 5) & 3; + frame_rate_ext_d = (buf[5] & 0x1f); + pc->progressive_sequence = buf[1] & (1 << 3); + pc->has_b_frames= !(buf[5] >> 7); + + chroma_format = (buf[1] >> 1) & 3; + switch (chroma_format) { + case 1: pix_fmt = AV_PIX_FMT_YUV420P; break; + case 2: pix_fmt = AV_PIX_FMT_YUV422P; break; + case 3: pix_fmt = AV_PIX_FMT_YUV444P; break; + } + + pc->width = (pc->width & 0xFFF) | (horiz_size_ext << 12); + pc->height = (pc->height& 0xFFF) | ( vert_size_ext << 12); + bit_rate = (bit_rate&0x3FFFF) | (bit_rate_ext << 18); + //if(did_set_size) + //set_dim_ret = ff_set_dimensions(avctx, pc->width, pc->height); + pc->framerate.num = pc->frame_rate.num * (frame_rate_ext_n + 1); + pc->framerate.den = pc->frame_rate.den * (frame_rate_ext_d + 1); + pc->ticks_per_frame = 2; + } + break; + case 0x8: /* picture coding extension */ + if (bytes_left >= 5) { + top_field_first = buf[3] & (1 << 7); + repeat_first_field = buf[3] & (1 << 1); + progressive_frame = buf[4] & (1 << 7); + + /* check if we must repeat the frame */ + pc->repeat_pict = 1; + if (repeat_first_field) { + if (pc->progressive_sequence) { + if (top_field_first) + pc->repeat_pict = 5; + else + pc->repeat_pict = 3; + } else if (progressive_frame) { + pc->repeat_pict = 2; + } + } + + if (!pc->progressive_sequence && !progressive_frame) { + if (top_field_first) + pc->field_order = AV_FIELD_TT; + else + pc->field_order = AV_FIELD_BB; + } else + pc->field_order = AV_FIELD_PROGRESSIVE; + } + break; + } + } + break; + case -1: + goto the_end; + default: + /* we stop parsing when we encounter a slice. It ensures + that this function takes a negligible amount of time */ + if (start_code >= SLICE_MIN_START_CODE && + start_code <= SLICE_MAX_START_CODE) + goto the_end; + break; + } + } +the_end: + + if (pix_fmt != AV_PIX_FMT_NONE) { + pc->format = pix_fmt; + pc->coded_width = ALIGN(pc->width, 16); + pc->coded_height = ALIGN(pc->height, 16); + } +} + +int mpeg12_decode_extradata_ps(u8 *buf, int size, struct mpeg12_param_sets *ps) +{ + ps->head_parsed = false; + + mpegvideo_extract_headers(buf, size, ps); + + if (ps->dec_ps.width && ps->dec_ps.height) + ps->head_parsed = true; + + return 0; +} +
diff --git a/drivers/amvdec_ports/decoder/aml_mpeg12_parser.h b/drivers/amvdec_ports/decoder/aml_mpeg12_parser.h new file mode 100644 index 0000000..c06d632 --- /dev/null +++ b/drivers/amvdec_ports/decoder/aml_mpeg12_parser.h
@@ -0,0 +1,81 @@ +#ifndef AML_MPEG12_PARSER_H +#define AML_MPEG12_PARSER_H + +#include "../aml_vcodec_drv.h" +#include "../utils/common.h" +#ifdef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER +#include "../utils/pixfmt.h" +#endif + +/* Start codes. */ +#define SEQ_END_CODE 0x000001b7 +#define SEQ_START_CODE 0x000001b3 +#define GOP_START_CODE 0x000001b8 +#define PICTURE_START_CODE 0x00000100 +#define SLICE_MIN_START_CODE 0x00000101 +#define SLICE_MAX_START_CODE 0x000001af +#define EXT_START_CODE 0x000001b5 +#define USER_START_CODE 0x000001b2 +#define SLICE_START_CODE 0x000001b7 + +enum AVFieldOrder { + AV_FIELD_UNKNOWN, + AV_FIELD_PROGRESSIVE, + AV_FIELD_TT, //< Top coded_first, top displayed first + AV_FIELD_BB, //< Bottom coded first, bottom displayed first + AV_FIELD_TB, //< Top coded first, bottom displayed first + AV_FIELD_BT, //< Bottom coded first, top displayed first +}; + +struct MpvParseContext { + struct AVRational frame_rate; + int progressive_sequence; + int width, height; + + int repeat_pict; /* XXX: Put it back in AVCodecContext. */ + int pict_type; /* XXX: Put it back in AVCodecContext. */ + enum AVFieldOrder field_order; + int format; + /** + * Dimensions of the coded video. + */ + int coded_width; + int coded_height; + /** + * For some codecs, the time base is closer to the field rate than the frame rate. + * Most notably, H.264 and MPEG-2 specify time_base as half of frame duration + * if no telecine is used ... + * + * Set to time_base ticks per frame. Default 1, e.g., H.264/MPEG-2 set it to 2. + */ + int ticks_per_frame; + /** + * Size of the frame reordering buffer in the decoder. + * For MPEG-2 it is 1 IPB or 0 low delay IP. + * - encoding: Set by libavcodec. + * - decoding: Set by libavcodec. + */ + int has_b_frames; + /** + * - decoding: For codecs that store a framerate value in the compressed + * bitstream, the decoder may export it here. { 0, 1} when + * unknown. + * - encoding: May be used to signal the framerate of CFR content to an + * encoder. + */ + struct AVRational framerate; +}; + +struct mpeg12_param_sets { + bool head_parsed; + /* currently active parameter sets */ + struct MpvParseContext dec_ps; +}; + +#ifdef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER +int mpeg12_decode_extradata_ps(u8 *buf, int size, struct mpeg12_param_sets *ps); +#else +inline int mpeg12_decode_extradata_ps(u8 *buf, int size, struct mpeg12_param_sets *ps) { return -1; } +#endif + +#endif
diff --git a/drivers/amvdec_ports/decoder/aml_mpeg4_parser.c b/drivers/amvdec_ports/decoder/aml_mpeg4_parser.c new file mode 100644 index 0000000..9c47c08 --- /dev/null +++ b/drivers/amvdec_ports/decoder/aml_mpeg4_parser.c
@@ -0,0 +1,1231 @@ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/vmalloc.h> +#include <linux/mm.h> +#include <linux/string.h> + +#include "aml_mpeg4_parser.h" +#include "../utils/get_bits.h" +#include "../utils/put_bits.h" +#include "../utils/golomb.h" +#include "../utils/common.h" +#include "utils.h" + +const u8 ff_mpeg4_dc_threshold[8]={ + 99, 13, 15, 17, 19, 21, 23, 0 +}; + +/* these matrixes will be permuted for the idct */ +const int16_t ff_mpeg4_default_intra_matrix[64] = { + 8, 17, 18, 19, 21, 23, 25, 27, + 17, 18, 19, 21, 23, 25, 27, 28, + 20, 21, 22, 23, 24, 26, 28, 30, + 21, 22, 23, 24, 26, 28, 30, 32, + 22, 23, 24, 26, 28, 30, 32, 35, + 23, 24, 26, 28, 30, 32, 35, 38, + 25, 26, 28, 30, 32, 35, 38, 41, + 27, 28, 30, 32, 35, 38, 41, 45, +}; + +const int16_t ff_mpeg4_default_non_intra_matrix[64] = { + 16, 17, 18, 19, 20, 21, 22, 23, + 17, 18, 19, 20, 21, 22, 23, 24, + 18, 19, 20, 21, 22, 23, 24, 25, + 19, 20, 21, 22, 23, 24, 26, 27, + 20, 21, 22, 23, 25, 26, 27, 28, + 21, 22, 23, 24, 26, 27, 28, 30, + 22, 23, 24, 26, 27, 28, 30, 31, + 23, 24, 25, 27, 28, 30, 31, 33, +}; + +const struct AVRational ff_h263_pixel_aspect[16] = { + { 0, 1 }, + { 1, 1 }, + { 12, 11 }, + { 10, 11 }, + { 16, 11 }, + { 40, 33 }, + { 0, 1 }, + { 0, 1 }, + { 0, 1 }, + { 0, 1 }, + { 0, 1 }, + { 0, 1 }, + { 0, 1 }, + { 0, 1 }, + { 0, 1 }, + { 0, 1 }, +}; + +/* As per spec, studio start code search isn't the same as the old type of start code */ +static void next_start_code_studio(struct get_bits_context *gb) +{ + align_get_bits(gb); + + while (get_bits_left(gb) >= 24 && show_bits_long(gb, 24) != 0x1) { + get_bits(gb, 8); + } +} + +static int read_quant_matrix_ext(struct MpegEncContext *s, struct get_bits_context *gb) +{ + int i, /*j,*/ v; + + if (get_bits1(gb)) { + if (get_bits_left(gb) < 64*8) + return -1; + /* intra_quantiser_matrix */ + for (i = 0; i < 64; i++) { + v = get_bits(gb, 8); + //j = s->idsp.idct_permutation[ff_zigzag_direct[i]]; + //s->intra_matrix[j] = v; + //s->chroma_intra_matrix[j] = v; + } + } + + if (get_bits1(gb)) { + if (get_bits_left(gb) < 64*8) + return -1; + /* non_intra_quantiser_matrix */ + for (i = 0; i < 64; i++) { + get_bits(gb, 8); + } + } + + if (get_bits1(gb)) { + if (get_bits_left(gb) < 64*8) + return -1; + /* chroma_intra_quantiser_matrix */ + for (i = 0; i < 64; i++) { + v = get_bits(gb, 8); + //j = s->idsp.idct_permutation[ff_zigzag_direct[i]]; + //s->chroma_intra_matrix[j] = v; + } + } + + if (get_bits1(gb)) { + if (get_bits_left(gb) < 64*8) + return -1; + /* chroma_non_intra_quantiser_matrix */ + for (i = 0; i < 64; i++) { + get_bits(gb, 8); + } + } + + next_start_code_studio(gb); + return 0; +} + +static void extension_and_user_data(struct MpegEncContext *s, struct get_bits_context *gb, int id) +{ + u32 startcode; + u8 extension_type; + + startcode = show_bits_long(gb, 32); + if (startcode == USER_DATA_STARTCODE || startcode == EXT_STARTCODE) { + if ((id == 2 || id == 4) && startcode == EXT_STARTCODE) { + skip_bits_long(gb, 32); + extension_type = get_bits(gb, 4); + if (extension_type == QUANT_MATRIX_EXT_ID) + read_quant_matrix_ext(s, gb); + } + } +} + + +static int decode_studio_vol_header(struct mpeg4_dec_param *ctx, struct get_bits_context *gb) +{ + struct MpegEncContext *s = &ctx->m; + int width, height; + int bits_per_raw_sample; + + // random_accessible_vol and video_object_type_indication have already + // been read by the caller decode_vol_header() + skip_bits(gb, 4); /* video_object_layer_verid */ + ctx->shape = get_bits(gb, 2); /* video_object_layer_shape */ + skip_bits(gb, 4); /* video_object_layer_shape_extension */ + skip_bits1(gb); /* progressive_sequence */ + if (ctx->shape != BIN_ONLY_SHAPE) { + ctx->rgb = get_bits1(gb); /* rgb_components */ + s->chroma_format = get_bits(gb, 2); /* chroma_format */ + if (!s->chroma_format) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "illegal chroma format\n"); + return -1; + } + + bits_per_raw_sample = get_bits(gb, 4); /* bit_depth */ + if (bits_per_raw_sample == 10) { + if (ctx->rgb) { + ctx->pix_fmt = AV_PIX_FMT_GBRP10; + } else { + ctx->pix_fmt = s->chroma_format == CHROMA_422 ? AV_PIX_FMT_YUV422P10 : AV_PIX_FMT_YUV444P10; + } + } + else { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "MPEG-4 Studio profile bit-depth %u", bits_per_raw_sample); + return -1; + } + ctx->bits_per_raw_sample = bits_per_raw_sample; + } + if (ctx->shape == RECT_SHAPE) { + check_marker(gb, "before video_object_layer_width"); + width = get_bits(gb, 14); /* video_object_layer_width */ + check_marker(gb, "before video_object_layer_height"); + height = get_bits(gb, 14); /* video_object_layer_height */ + check_marker(gb, "after video_object_layer_height"); + + /* Do the same check as non-studio profile */ + if (width && height) { + if (s->width && s->height && + (s->width != width || s->height != height)) + s->context_reinit = 1; + s->width = width; + s->height = height; + } + } + s->aspect_ratio_info = get_bits(gb, 4); + if (s->aspect_ratio_info == FF_ASPECT_EXTENDED) { + ctx->sample_aspect_ratio.num = get_bits(gb, 8); // par_width + ctx->sample_aspect_ratio.den = get_bits(gb, 8); // par_height + } else { + ctx->sample_aspect_ratio = ff_h263_pixel_aspect[s->aspect_ratio_info]; + } + skip_bits(gb, 4); /* frame_rate_code */ + skip_bits(gb, 15); /* first_half_bit_rate */ + check_marker(gb, "after first_half_bit_rate"); + skip_bits(gb, 15); /* latter_half_bit_rate */ + check_marker(gb, "after latter_half_bit_rate"); + skip_bits(gb, 15); /* first_half_vbv_buffer_size */ + check_marker(gb, "after first_half_vbv_buffer_size"); + skip_bits(gb, 3); /* latter_half_vbv_buffer_size */ + skip_bits(gb, 11); /* first_half_vbv_buffer_size */ + check_marker(gb, "after first_half_vbv_buffer_size"); + skip_bits(gb, 15); /* latter_half_vbv_occupancy */ + check_marker(gb, "after latter_half_vbv_occupancy"); + s->low_delay = get_bits1(gb); + s->mpeg_quant = get_bits1(gb); /* mpeg2_stream */ + + next_start_code_studio(gb); + extension_and_user_data(s, gb, 2); + + return 0; +} + +static int decode_vol_header(struct mpeg4_dec_param *ctx, struct get_bits_context *gb) +{ + struct MpegEncContext *s = &ctx->m; + int width, height, vo_ver_id; + + /* vol header */ + skip_bits(gb, 1); /* random access */ + s->vo_type = get_bits(gb, 8); + + /* If we are in studio profile (per vo_type), check if its all consistent + * and if so continue pass control to decode_studio_vol_header(). + * elIf something is inconsistent, error out + * else continue with (non studio) vol header decpoding. + */ + if (s->vo_type == CORE_STUDIO_VO_TYPE || + s->vo_type == SIMPLE_STUDIO_VO_TYPE) { + if (ctx->profile != FF_PROFILE_UNKNOWN && ctx->profile != FF_PROFILE_MPEG4_SIMPLE_STUDIO) + return -1; + s->studio_profile = 1; + ctx->profile = FF_PROFILE_MPEG4_SIMPLE_STUDIO; + return decode_studio_vol_header(ctx, gb); + } else if (s->studio_profile) { + return -1; + } + + if (get_bits1(gb) != 0) { /* is_ol_id */ + vo_ver_id = get_bits(gb, 4); /* vo_ver_id */ + skip_bits(gb, 3); /* vo_priority */ + } else { + vo_ver_id = 1; + } + s->aspect_ratio_info = get_bits(gb, 4); + if (s->aspect_ratio_info == FF_ASPECT_EXTENDED) { + ctx->sample_aspect_ratio.num = get_bits(gb, 8); // par_width + ctx->sample_aspect_ratio.den = get_bits(gb, 8); // par_height + } else { + ctx->sample_aspect_ratio = ff_h263_pixel_aspect[s->aspect_ratio_info]; + } + + if ((ctx->vol_control_parameters = get_bits1(gb))) { /* vol control parameter */ + int chroma_format = get_bits(gb, 2); + if (chroma_format != CHROMA_420) + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "illegal chroma format\n"); + + s->low_delay = get_bits1(gb); + if (get_bits1(gb)) { /* vbv parameters */ + get_bits(gb, 15); /* first_half_bitrate */ + check_marker(gb, "after first_half_bitrate"); + get_bits(gb, 15); /* latter_half_bitrate */ + check_marker(gb, "after latter_half_bitrate"); + get_bits(gb, 15); /* first_half_vbv_buffer_size */ + check_marker(gb, "after first_half_vbv_buffer_size"); + get_bits(gb, 3); /* latter_half_vbv_buffer_size */ + get_bits(gb, 11); /* first_half_vbv_occupancy */ + check_marker(gb, "after first_half_vbv_occupancy"); + get_bits(gb, 15); /* latter_half_vbv_occupancy */ + check_marker(gb, "after latter_half_vbv_occupancy"); + } + } else { + /* is setting low delay flag only once the smartest thing to do? + * low delay detection will not be overridden. */ + if (s->picture_number == 0) { + switch (s->vo_type) { + case SIMPLE_VO_TYPE: + case ADV_SIMPLE_VO_TYPE: + s->low_delay = 1; + break; + default: + s->low_delay = 0; + } + } + } + + ctx->shape = get_bits(gb, 2); /* vol shape */ + if (ctx->shape != RECT_SHAPE) + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "only rectangular vol supported\n"); + if (ctx->shape == GRAY_SHAPE && vo_ver_id != 1) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Gray shape not supported\n"); + skip_bits(gb, 4); /* video_object_layer_shape_extension */ + } + + check_marker(gb, "before time_increment_resolution"); + + ctx->framerate.num = get_bits(gb, 16); + if (!ctx->framerate.num) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "framerate==0\n"); + return -1; + } + + ctx->time_increment_bits = av_log2(ctx->framerate.num - 1) + 1; + if (ctx->time_increment_bits < 1) + ctx->time_increment_bits = 1; + + check_marker(gb, "before fixed_vop_rate"); + + if (get_bits1(gb) != 0) /* fixed_vop_rate */ + ctx->framerate.den = get_bits(gb, ctx->time_increment_bits); + else + ctx->framerate.den = 1; + + //ctx->time_base = av_inv_q(av_mul_q(ctx->framerate, (AVRational){ctx->ticks_per_frame, 1})); + + ctx->t_frame = 0; + + if (ctx->shape != BIN_ONLY_SHAPE) { + if (ctx->shape == RECT_SHAPE) { + check_marker(gb, "before width"); + width = get_bits(gb, 13); + check_marker(gb, "before height"); + height = get_bits(gb, 13); + check_marker(gb, "after height"); + if (width && height && /* they should be non zero but who knows */ + !(s->width && s->codec_tag == AV_RL32("MP4S"))) { + if (s->width && s->height && + (s->width != width || s->height != height)) + s->context_reinit = 1; + s->width = width; + s->height = height; + } + } + + s->progressive_sequence = + s->progressive_frame = get_bits1(gb) ^ 1; + s->interlaced_dct = 0; + if (!get_bits1(gb)) /* OBMC Disable */ + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "MPEG-4 OBMC not supported (very likely buggy encoder)\n"); + if (vo_ver_id == 1) + ctx->vol_sprite_usage = get_bits1(gb); /* vol_sprite_usage */ + else + ctx->vol_sprite_usage = get_bits(gb, 2); /* vol_sprite_usage */ + + if (ctx->vol_sprite_usage == STATIC_SPRITE) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Static Sprites not supported\n"); + if (ctx->vol_sprite_usage == STATIC_SPRITE || + ctx->vol_sprite_usage == GMC_SPRITE) { + if (ctx->vol_sprite_usage == STATIC_SPRITE) { + skip_bits(gb, 13); // sprite_width + check_marker(gb, "after sprite_width"); + skip_bits(gb, 13); // sprite_height + check_marker(gb, "after sprite_height"); + skip_bits(gb, 13); // sprite_left + check_marker(gb, "after sprite_left"); + skip_bits(gb, 13); // sprite_top + check_marker(gb, "after sprite_top"); + } + ctx->num_sprite_warping_points = get_bits(gb, 6); + if (ctx->num_sprite_warping_points > 3) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "%d sprite_warping_points\n", + ctx->num_sprite_warping_points); + ctx->num_sprite_warping_points = 0; + return -1; + } + s->sprite_warping_accuracy = get_bits(gb, 2); + ctx->sprite_brightness_change = get_bits1(gb); + if (ctx->vol_sprite_usage == STATIC_SPRITE) + skip_bits1(gb); // low_latency_sprite + } + // FIXME sadct disable bit if verid!=1 && shape not rect + + if (get_bits1(gb) == 1) { /* not_8_bit */ + s->quant_precision = get_bits(gb, 4); /* quant_precision */ + if (get_bits(gb, 4) != 8) /* bits_per_pixel */ + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "N-bit not supported\n"); + if (s->quant_precision != 5) + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "quant precision %d\n", s->quant_precision); + if (s->quant_precision<3 || s->quant_precision>9) { + s->quant_precision = 5; + } + } else { + s->quant_precision = 5; + } + + // FIXME a bunch of grayscale shape things + + if ((s->mpeg_quant = get_bits1(gb))) { /* vol_quant_type */ + int i, v; + + //mpeg4_load_default_matrices(s); + + /* load custom intra matrix */ + if (get_bits1(gb)) { + int last = 0; + for (i = 0; i < 64; i++) { + //int j; + if (get_bits_left(gb) < 8) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "insufficient data for custom matrix\n"); + return -1; + } + v = get_bits(gb, 8); + if (v == 0) + break; + + last = v; + //j = s->idsp.idct_permutation[ff_zigzag_direct[i]]; + //s->intra_matrix[j] = last; + //s->chroma_intra_matrix[j] = last; + } + + /* replicate last value */ + //for (; i < 64; i++) { + //int j = s->idsp.idct_permutation[ff_zigzag_direct[i]]; + //s->intra_matrix[j] = last; + //s->chroma_intra_matrix[j] = last; + //} + } + + /* load custom non intra matrix */ + if (get_bits1(gb)) { + int last = 0; + for (i = 0; i < 64; i++) { + //int j; + if (get_bits_left(gb) < 8) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "insufficient data for custom matrix\n"); + return -1; + } + v = get_bits(gb, 8); + if (v == 0) + break; + + last = v; + //j = s->idsp.idct_permutation[ff_zigzag_direct[i]]; + //s->inter_matrix[j] = v; + //s->chroma_inter_matrix[j] = v; + } + + /* replicate last value */ + //for (; i < 64; i++) { + //int j = s->idsp.idct_permutation[ff_zigzag_direct[i]]; + //s->inter_matrix[j] = last; + //s->chroma_inter_matrix[j] = last; + //} + } + + // FIXME a bunch of grayscale shape things + } + + if (vo_ver_id != 1) + s->quarter_sample = get_bits1(gb); + else + s->quarter_sample = 0; + + if (get_bits_left(gb) < 4) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "VOL Header truncated\n"); + return -1; + } + + if (!get_bits1(gb)) { + int pos = get_bits_count(gb); + int estimation_method = get_bits(gb, 2); + if (estimation_method < 2) { + if (!get_bits1(gb)) { + ctx->cplx_estimation_trash_i += 8 * get_bits1(gb); /* opaque */ + ctx->cplx_estimation_trash_i += 8 * get_bits1(gb); /* transparent */ + ctx->cplx_estimation_trash_i += 8 * get_bits1(gb); /* intra_cae */ + ctx->cplx_estimation_trash_i += 8 * get_bits1(gb); /* inter_cae */ + ctx->cplx_estimation_trash_i += 8 * get_bits1(gb); /* no_update */ + ctx->cplx_estimation_trash_i += 8 * get_bits1(gb); /* upsampling */ + } + if (!get_bits1(gb)) { + ctx->cplx_estimation_trash_i += 8 * get_bits1(gb); /* intra_blocks */ + ctx->cplx_estimation_trash_p += 8 * get_bits1(gb); /* inter_blocks */ + ctx->cplx_estimation_trash_p += 8 * get_bits1(gb); /* inter4v_blocks */ + ctx->cplx_estimation_trash_i += 8 * get_bits1(gb); /* not coded blocks */ + } + if (!check_marker(gb, "in complexity estimation part 1")) { + skip_bits_long(gb, pos - get_bits_count(gb)); + goto no_cplx_est; + } + if (!get_bits1(gb)) { + ctx->cplx_estimation_trash_i += 8 * get_bits1(gb); /* dct_coeffs */ + ctx->cplx_estimation_trash_i += 8 * get_bits1(gb); /* dct_lines */ + ctx->cplx_estimation_trash_i += 8 * get_bits1(gb); /* vlc_syms */ + ctx->cplx_estimation_trash_i += 4 * get_bits1(gb); /* vlc_bits */ + } + if (!get_bits1(gb)) { + ctx->cplx_estimation_trash_p += 8 * get_bits1(gb); /* apm */ + ctx->cplx_estimation_trash_p += 8 * get_bits1(gb); /* npm */ + ctx->cplx_estimation_trash_b += 8 * get_bits1(gb); /* interpolate_mc_q */ + ctx->cplx_estimation_trash_p += 8 * get_bits1(gb); /* forwback_mc_q */ + ctx->cplx_estimation_trash_p += 8 * get_bits1(gb); /* halfpel2 */ + ctx->cplx_estimation_trash_p += 8 * get_bits1(gb); /* halfpel4 */ + } + if (!check_marker(gb, "in complexity estimation part 2")) { + skip_bits_long(gb, pos - get_bits_count(gb)); + goto no_cplx_est; + } + if (estimation_method == 1) { + ctx->cplx_estimation_trash_i += 8 * get_bits1(gb); /* sadct */ + ctx->cplx_estimation_trash_p += 8 * get_bits1(gb); /* qpel */ + } + } else + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Invalid Complexity estimation method %d\n", + estimation_method); + } else { + +no_cplx_est: + ctx->cplx_estimation_trash_i = + ctx->cplx_estimation_trash_p = + ctx->cplx_estimation_trash_b = 0; + } + + ctx->resync_marker = !get_bits1(gb); /* resync_marker_disabled */ + + s->data_partitioning = get_bits1(gb); + if (s->data_partitioning) + ctx->rvlc = get_bits1(gb); + + if (vo_ver_id != 1) { + ctx->new_pred = get_bits1(gb); + if (ctx->new_pred) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "new pred not supported\n"); + skip_bits(gb, 2); /* requested upstream message type */ + skip_bits1(gb); /* newpred segment type */ + } + if (get_bits1(gb)) // reduced_res_vop + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "reduced resolution VOP not supported\n"); + } else { + ctx->new_pred = 0; + } + + ctx->scalability = get_bits1(gb); + + if (ctx->scalability) { + struct get_bits_context bak = *gb; + int h_sampling_factor_n; + int h_sampling_factor_m; + int v_sampling_factor_n; + int v_sampling_factor_m; + + skip_bits1(gb); // hierarchy_type + skip_bits(gb, 4); /* ref_layer_id */ + skip_bits1(gb); /* ref_layer_sampling_dir */ + h_sampling_factor_n = get_bits(gb, 5); + h_sampling_factor_m = get_bits(gb, 5); + v_sampling_factor_n = get_bits(gb, 5); + v_sampling_factor_m = get_bits(gb, 5); + ctx->enhancement_type = get_bits1(gb); + + if (h_sampling_factor_n == 0 || h_sampling_factor_m == 0 || + v_sampling_factor_n == 0 || v_sampling_factor_m == 0) { + /* illegal scalability header (VERY broken encoder), + * trying to workaround */ + ctx->scalability = 0; + *gb = bak; + } else + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "scalability not supported\n"); + + // bin shape stuff FIXME + } + } + + if (1) { + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "tb %d/%d, tincrbits:%d, qp_prec:%d, ps:%d, low_delay:%d %s%s%s%s\n", + ctx->framerate.den, ctx->framerate.num, + ctx->time_increment_bits, + s->quant_precision, + s->progressive_sequence, + s->low_delay, + ctx->scalability ? "scalability " :"" , s->quarter_sample ? "qpel " : "", + s->data_partitioning ? "partition " : "", ctx->rvlc ? "rvlc " : ""); + } + + return 0; +} + + +/** + * Decode the user data stuff in the header. + * Also initializes divx/xvid/lavc_version/build. + */ +static int decode_user_data(struct mpeg4_dec_param *ctx, struct get_bits_context *gb) +{ + struct MpegEncContext *s = &ctx->m; + char buf[256]; + int i; + int e; + int ver = 0, build = 0, ver2 = 0, ver3 = 0; + char last; + + for (i = 0; i < 255 && get_bits_count(gb) < gb->size_in_bits; i++) { + if (show_bits(gb, 23) == 0) + break; + buf[i] = get_bits(gb, 8); + } + buf[i] = 0; + + /* divx detection */ + e = sscanf(buf, "DivX%dBuild%d%c", &ver, &build, &last); + if (e < 2) + e = sscanf(buf, "DivX%db%d%c", &ver, &build, &last); + if (e >= 2) { + ctx->divx_version = ver; + ctx->divx_build = build; + s->divx_packed = e == 3 && last == 'p'; + } + + /* libavcodec detection */ + e = sscanf(buf, "FFmpe%*[^b]b%d", &build) + 3; + if (e != 4) + e = sscanf(buf, "FFmpeg v%d.%d.%d / libavcodec build: %d", &ver, &ver2, &ver3, &build); + if (e != 4) { + e = sscanf(buf, "Lavc%d.%d.%d", &ver, &ver2, &ver3) + 1; + if (e > 1) { + if (ver > 0xFFU || ver2 > 0xFFU || ver3 > 0xFFU) { + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Unknown Lavc version string encountered, %d.%d.%d; " + "clamping sub-version values to 8-bits.\n", + ver, ver2, ver3); + } + build = ((ver & 0xFF) << 16) + ((ver2 & 0xFF) << 8) + (ver3 & 0xFF); + } + } + if (e != 4) { + if (strcmp(buf, "ffmpeg") == 0) + ctx->lavc_build = 4600; + } + if (e == 4) + ctx->lavc_build = build; + + /* Xvid detection */ + e = sscanf(buf, "XviD%d", &build); + if (e == 1) + ctx->xvid_build = build; + + return 0; +} + + +static int mpeg4_decode_gop_header(struct MpegEncContext *s, struct get_bits_context *gb) +{ + int hours, minutes, seconds; + + if (!show_bits(gb, 23)) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "GOP header invalid\n"); + return -1; + } + + hours = get_bits(gb, 5); + minutes = get_bits(gb, 6); + check_marker(gb, "in gop_header"); + seconds = get_bits(gb, 6); + + s->time_base = seconds + 60*(minutes + 60*hours); + + skip_bits1(gb); + skip_bits1(gb); + + return 0; +} + + +static int mpeg4_decode_profile_level(struct MpegEncContext *s, struct get_bits_context *gb, int *profile, int *level) +{ + + *profile = get_bits(gb, 4); + *level = get_bits(gb, 4); + + // for Simple profile, level 0 + if (*profile == 0 && *level == 8) { + *level = 0; + } + + return 0; +} + + +static int decode_studiovisualobject(struct mpeg4_dec_param *ctx, struct get_bits_context *gb) +{ + struct MpegEncContext *s = &ctx->m; + int visual_object_type; + + skip_bits(gb, 4); /* visual_object_verid */ + visual_object_type = get_bits(gb, 4); + if (visual_object_type != VOT_VIDEO_ID) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "VO type %u", visual_object_type); + return -1; + } + + next_start_code_studio(gb); + extension_and_user_data(s, gb, 1); + + return 0; +} + + +static int mpeg4_decode_visual_object(struct MpegEncContext *s, struct get_bits_context *gb) +{ + int visual_object_type; + int is_visual_object_identifier = get_bits1(gb); + + if (is_visual_object_identifier) { + skip_bits(gb, 4+3); + } + visual_object_type = get_bits(gb, 4); + + if (visual_object_type == VOT_VIDEO_ID || + visual_object_type == VOT_STILL_TEXTURE_ID) { + int video_signal_type = get_bits1(gb); + if (video_signal_type) { + int video_range, color_description; + skip_bits(gb, 3); // video_format + video_range = get_bits1(gb); + color_description = get_bits1(gb); + + s->ctx->color_range = video_range ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; + + if (color_description) { + s->ctx->color_primaries = get_bits(gb, 8); + s->ctx->color_trc = get_bits(gb, 8); + s->ctx->colorspace = get_bits(gb, 8); + } + } + } + + return 0; +} + +static void decode_smpte_tc(struct mpeg4_dec_param *ctx, struct get_bits_context *gb) +{ + skip_bits(gb, 16); /* Time_code[63..48] */ + check_marker(gb, "after Time_code[63..48]"); + skip_bits(gb, 16); /* Time_code[47..32] */ + check_marker(gb, "after Time_code[47..32]"); + skip_bits(gb, 16); /* Time_code[31..16] */ + check_marker(gb, "after Time_code[31..16]"); + skip_bits(gb, 16); /* Time_code[15..0] */ + check_marker(gb, "after Time_code[15..0]"); + skip_bits(gb, 4); /* reserved_bits */ +} + +static void reset_studio_dc_predictors(struct MpegEncContext *s) +{ + /* Reset DC Predictors */ + s->last_dc[0] = + s->last_dc[1] = + s->last_dc[2] = 1 << (s->ctx->bits_per_raw_sample + s->dct_precision + s->intra_dc_precision - 1); +} + +/** + * Decode the next studio vop header. + * @return <0 if something went wrong + */ +static int decode_studio_vop_header(struct mpeg4_dec_param *ctx, struct get_bits_context *gb) +{ + struct MpegEncContext *s = &ctx->m; + + if (get_bits_left(gb) <= 32) + return 0; + + //s->decode_mb = mpeg4_decode_studio_mb; + + decode_smpte_tc(ctx, gb); + + skip_bits(gb, 10); /* temporal_reference */ + skip_bits(gb, 2); /* vop_structure */ + s->pict_type = get_bits(gb, 2) + AV_PICTURE_TYPE_I; /* vop_coding_type */ + if (get_bits1(gb)) { /* vop_coded */ + skip_bits1(gb); /* top_field_first */ + skip_bits1(gb); /* repeat_first_field */ + s->progressive_frame = get_bits1(gb) ^ 1; /* progressive_frame */ + } + + if (s->pict_type == AV_PICTURE_TYPE_I) { + if (get_bits1(gb)) + reset_studio_dc_predictors(s); + } + + if (ctx->shape != BIN_ONLY_SHAPE) { + s->alternate_scan = get_bits1(gb); + s->frame_pred_frame_dct = get_bits1(gb); + s->dct_precision = get_bits(gb, 2); + s->intra_dc_precision = get_bits(gb, 2); + s->q_scale_type = get_bits1(gb); + } + + //if (s->alternate_scan) { } + + //mpeg4_load_default_matrices(s); + + next_start_code_studio(gb); + extension_and_user_data(s, gb, 4); + + return 0; +} + +static int decode_new_pred(struct mpeg4_dec_param *ctx, struct get_bits_context *gb) +{ + int len = FFMIN(ctx->time_increment_bits + 3, 15); + + get_bits(gb, len); + if (get_bits1(gb)) + get_bits(gb, len); + check_marker(gb, "after new_pred"); + + return 0; +} + +static int decode_vop_header(struct mpeg4_dec_param *ctx, struct get_bits_context *gb) +{ + struct MpegEncContext *s = &ctx->m; + int time_incr, time_increment; + int64_t pts; + + s->mcsel = 0; + s->pict_type = get_bits(gb, 2) + AV_PICTURE_TYPE_I; /* pict type: I = 0 , P = 1 */ + if (s->pict_type == AV_PICTURE_TYPE_B && s->low_delay && + ctx->vol_control_parameters == 0) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "low_delay flag set incorrectly, clearing it\n"); + s->low_delay = 0; + } + + s->partitioned_frame = s->data_partitioning && s->pict_type != AV_PICTURE_TYPE_B; + /*if (s->partitioned_frame) + s->decode_mb = mpeg4_decode_partitioned_mb; + else + s->decode_mb = mpeg4_decode_mb;*/ + + time_incr = 0; + while (get_bits1(gb) != 0) + time_incr++; + + check_marker(gb, "before time_increment"); + + if (ctx->time_increment_bits == 0 || + !(show_bits(gb, ctx->time_increment_bits + 1) & 1)) { + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "time_increment_bits %d is invalid in relation to the current bitstream, this is likely caused by a missing VOL header\n", ctx->time_increment_bits); + + for (ctx->time_increment_bits = 1; + ctx->time_increment_bits < 16; + ctx->time_increment_bits++) { + if (s->pict_type == AV_PICTURE_TYPE_P || + (s->pict_type == AV_PICTURE_TYPE_S && + ctx->vol_sprite_usage == GMC_SPRITE)) { + if ((show_bits(gb, ctx->time_increment_bits + 6) & 0x37) == 0x30) + break; + } else if ((show_bits(gb, ctx->time_increment_bits + 5) & 0x1F) == 0x18) + break; + } + + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "time_increment_bits set to %d bits, based on bitstream analysis\n", ctx->time_increment_bits); + if (ctx->framerate.num && 4*ctx->framerate.num < 1<<ctx->time_increment_bits) { + ctx->framerate.num = 1<<ctx->time_increment_bits; + //ctx->time_base = av_inv_q(av_mul_q(ctx->framerate, (AVRational){ctx->ticks_per_frame, 1})); + } + } + + if (IS_3IV1) + time_increment = get_bits1(gb); // FIXME investigate further + else + time_increment = get_bits(gb, ctx->time_increment_bits); + + if (s->pict_type != AV_PICTURE_TYPE_B) { + s->last_time_base = s->time_base; + s->time_base += time_incr; + s->time = s->time_base * (int64_t)ctx->framerate.num + time_increment; + //if (s->workaround_bugs & FF_BUG_UMP4) { } + s->pp_time = s->time - s->last_non_b_time; + s->last_non_b_time = s->time; + } else { + s->time = (s->last_time_base + time_incr) * (int64_t)ctx->framerate.num + time_increment; + s->pb_time = s->pp_time - (s->last_non_b_time - s->time); + if (s->pp_time <= s->pb_time || + s->pp_time <= s->pp_time - s->pb_time || + s->pp_time <= 0) { + /* messed up order, maybe after seeking? skipping current B-frame */ + return FRAME_SKIPPED; + } + //ff_mpeg4_init_direct_mv(s); + + if (ctx->t_frame == 0) + ctx->t_frame = s->pb_time; + if (ctx->t_frame == 0) + ctx->t_frame = 1; // 1/0 protection + s->pp_field_time = (ROUNDED_DIV(s->last_non_b_time, ctx->t_frame) - + ROUNDED_DIV(s->last_non_b_time - s->pp_time, ctx->t_frame)) * 2; + s->pb_field_time = (ROUNDED_DIV(s->time, ctx->t_frame) - + ROUNDED_DIV(s->last_non_b_time - s->pp_time, ctx->t_frame)) * 2; + if (s->pp_field_time <= s->pb_field_time || s->pb_field_time <= 1) { + s->pb_field_time = 2; + s->pp_field_time = 4; + if (!s->progressive_sequence) + return FRAME_SKIPPED; + } + } + + if (ctx->framerate.den) + pts = ROUNDED_DIV(s->time, ctx->framerate.den); + else + pts = AV_NOPTS_VALUE; + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "MPEG4 PTS: %lld\n", pts); + + check_marker(gb, "before vop_coded"); + + /* vop coded */ + if (get_bits1(gb) != 1) { + if (1) + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "vop not coded\n"); + return FRAME_SKIPPED; + } + if (ctx->new_pred) + decode_new_pred(ctx, gb); + + if (ctx->shape != BIN_ONLY_SHAPE && + (s->pict_type == AV_PICTURE_TYPE_P || + (s->pict_type == AV_PICTURE_TYPE_S && + ctx->vol_sprite_usage == GMC_SPRITE))) { + /* rounding type for motion estimation */ + s->no_rounding = get_bits1(gb); + } else { + s->no_rounding = 0; + } + // FIXME reduced res stuff + + if (ctx->shape != RECT_SHAPE) { + if (ctx->vol_sprite_usage != 1 || s->pict_type != AV_PICTURE_TYPE_I) { + skip_bits(gb, 13); /* width */ + check_marker(gb, "after width"); + skip_bits(gb, 13); /* height */ + check_marker(gb, "after height"); + skip_bits(gb, 13); /* hor_spat_ref */ + check_marker(gb, "after hor_spat_ref"); + skip_bits(gb, 13); /* ver_spat_ref */ + } + skip_bits1(gb); /* change_CR_disable */ + + if (get_bits1(gb) != 0) + skip_bits(gb, 8); /* constant_alpha_value */ + } + + // FIXME complexity estimation stuff + + if (ctx->shape != BIN_ONLY_SHAPE) { + skip_bits_long(gb, ctx->cplx_estimation_trash_i); + if (s->pict_type != AV_PICTURE_TYPE_I) + skip_bits_long(gb, ctx->cplx_estimation_trash_p); + if (s->pict_type == AV_PICTURE_TYPE_B) + skip_bits_long(gb, ctx->cplx_estimation_trash_b); + + if (get_bits_left(gb) < 3) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Header truncated\n"); + return -1; + } + ctx->intra_dc_threshold = ff_mpeg4_dc_threshold[get_bits(gb, 3)]; + if (!s->progressive_sequence) { + s->top_field_first = get_bits1(gb); + s->alternate_scan = get_bits1(gb); + } else + s->alternate_scan = 0; + } + + /*if (s->alternate_scan) { } */ + + if (s->pict_type == AV_PICTURE_TYPE_S) { + if((ctx->vol_sprite_usage == STATIC_SPRITE || + ctx->vol_sprite_usage == GMC_SPRITE)) { + //if (mpeg4_decode_sprite_trajectory(ctx, gb) < 0) + //return -1; + if (ctx->sprite_brightness_change) + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "sprite_brightness_change not supported\n"); + if (ctx->vol_sprite_usage == STATIC_SPRITE) + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "static sprite not supported\n"); + } else { + memset(s->sprite_offset, 0, sizeof(s->sprite_offset)); + memset(s->sprite_delta, 0, sizeof(s->sprite_delta)); + } + } + + if (ctx->shape != BIN_ONLY_SHAPE) { + s->chroma_qscale = s->qscale = get_bits(gb, s->quant_precision); + if (s->qscale == 0) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Error, header damaged or not MPEG-4 header (qscale=0)\n"); + return -1; // makes no sense to continue, as there is nothing left from the image then + } + + if (s->pict_type != AV_PICTURE_TYPE_I) { + s->f_code = get_bits(gb, 3); /* fcode_for */ + if (s->f_code == 0) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Error, header damaged or not MPEG-4 header (f_code=0)\n"); + s->f_code = 1; + return -1; // makes no sense to continue, as there is nothing left from the image then + } + } else + s->f_code = 1; + + if (s->pict_type == AV_PICTURE_TYPE_B) { + s->b_code = get_bits(gb, 3); + if (s->b_code == 0) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Error, header damaged or not MPEG4 header (b_code=0)\n"); + s->b_code=1; + return -1; // makes no sense to continue, as the MV decoding will break very quickly + } + } else + s->b_code = 1; + + if (1) { + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "qp:%d fc:%d,%d %s size:%d pro:%d alt:%d top:%d %spel part:%d resync:%d w:%d a:%d rnd:%d vot:%d%s dc:%d ce:%d/%d/%d time:%ld tincr:%d\n", + s->qscale, s->f_code, s->b_code, + s->pict_type == AV_PICTURE_TYPE_I ? "I" : (s->pict_type == AV_PICTURE_TYPE_P ? "P" : (s->pict_type == AV_PICTURE_TYPE_B ? "B" : "S")), + gb->size_in_bits,s->progressive_sequence, s->alternate_scan, + s->top_field_first, s->quarter_sample ? "q" : "h", + s->data_partitioning, ctx->resync_marker, + ctx->num_sprite_warping_points, s->sprite_warping_accuracy, + 1 - s->no_rounding, s->vo_type, + ctx->vol_control_parameters ? " VOLC" : " ", ctx->intra_dc_threshold, + ctx->cplx_estimation_trash_i, ctx->cplx_estimation_trash_p, + ctx->cplx_estimation_trash_b, + s->time, + time_increment); + } + + if (!ctx->scalability) { + if (ctx->shape != RECT_SHAPE && s->pict_type != AV_PICTURE_TYPE_I) + skip_bits1(gb); // vop shape coding type + } else { + if (ctx->enhancement_type) { + int load_backward_shape = get_bits1(gb); + if (load_backward_shape) + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "load backward shape isn't supported\n"); + } + skip_bits(gb, 2); // ref_select_code + } + } + /* detect buggy encoders which don't set the low_delay flag + * (divx4/xvid/opendivx). Note we cannot detect divx5 without B-frames + * easily (although it's buggy too) */ + if (s->vo_type == 0 && ctx->vol_control_parameters == 0 && + ctx->divx_version == -1 && s->picture_number == 0) { + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "looks like this file was encoded with (divx4/(old)xvid/opendivx) -> forcing low_delay flag\n"); + s->low_delay = 1; + } + + s->picture_number++; // better than pic number==0 always ;) + + // FIXME add short header support + //s->y_dc_scale_table = ff_mpeg4_y_dc_scale_table; + //s->c_dc_scale_table = ff_mpeg4_c_dc_scale_table; + + return 0; +} + +/** + * Decode MPEG-4 headers. + * @return <0 if no VOP found (or a damaged one) + * FRAME_SKIPPED if a not coded VOP is found + * 0 if a VOP is found + */ +int ff_mpeg4_decode_picture_header(struct mpeg4_dec_param *ctx, struct get_bits_context *gb) +{ + struct MpegEncContext *s = &ctx->m; + + unsigned startcode, v; + int ret; + int vol = 0; + int bits_per_raw_sample = 0; + + s->ctx = ctx; + + /* search next start code */ + align_get_bits(gb); + + // If we have not switched to studio profile than we also did not switch bps + // that means something else (like a previous instance) outside set bps which + // would be inconsistant with the currect state, thus reset it + if (!s->studio_profile && bits_per_raw_sample != 8) + bits_per_raw_sample = 0; + + if (show_bits(gb, 24) == 0x575630) { + skip_bits(gb, 24); + if (get_bits(gb, 8) == 0xF0) + goto end; + } + + startcode = 0xff; + for (;;) { + if (get_bits_count(gb) >= gb->size_in_bits) { + if (gb->size_in_bits == 8) { + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "frame skip %d\n", gb->size_in_bits); + return FRAME_SKIPPED; // divx bug + } else + return -1; // end of stream + } + + /* use the bits after the test */ + v = get_bits(gb, 8); + startcode = ((startcode << 8) | v) & 0xffffffff; + + if ((startcode & 0xFFFFFF00) != 0x100) + continue; // no startcode + + if (1) { //debug + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "startcode: %3X \n", startcode); + if (startcode <= 0x11F) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Video Object Start\n"); + else if (startcode <= 0x12F) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Video Object Layer Start\n"); + else if (startcode <= 0x13F) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Reserved\n"); + else if (startcode <= 0x15F) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "FGS bp start\n"); + else if (startcode <= 0x1AF) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Reserved\n"); + else if (startcode == 0x1B0) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Visual Object Seq Start\n"); + else if (startcode == 0x1B1) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Visual Object Seq End\n"); + else if (startcode == 0x1B2) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "User Data\n"); + else if (startcode == 0x1B3) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Group of VOP start\n"); + else if (startcode == 0x1B4) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Video Session Error\n"); + else if (startcode == 0x1B5) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Visual Object Start\n"); + else if (startcode == 0x1B6) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Video Object Plane start\n"); + else if (startcode == 0x1B7) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "slice start\n"); + else if (startcode == 0x1B8) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "extension start\n"); + else if (startcode == 0x1B9) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "fgs start\n"); + else if (startcode == 0x1BA) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "FBA Object start\n"); + else if (startcode == 0x1BB) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "FBA Object Plane start\n"); + else if (startcode == 0x1BC) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Mesh Object start\n"); + else if (startcode == 0x1BD) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Mesh Object Plane start\n"); + else if (startcode == 0x1BE) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Still Texture Object start\n"); + else if (startcode == 0x1BF) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Texture Spatial Layer start\n"); + else if (startcode == 0x1C0) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Texture SNR Layer start\n"); + else if (startcode == 0x1C1) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Texture Tile start\n"); + else if (startcode == 0x1C2) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "Texture Shape Layer start\n"); + else if (startcode == 0x1C3) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "stuffing start\n"); + else if (startcode <= 0x1C5) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "reserved\n"); + else if (startcode <= 0x1FF) + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "System start\n"); + } + + if (startcode >= 0x120 && startcode <= 0x12F) { + if (vol) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Ignoring multiple VOL headers\n"); + continue; + } + vol++; + if ((ret = decode_vol_header(ctx, gb)) < 0) + return ret; + } else if (startcode == USER_DATA_STARTCODE) { + decode_user_data(ctx, gb); + } else if (startcode == GOP_STARTCODE) { + mpeg4_decode_gop_header(s, gb); + } else if (startcode == VOS_STARTCODE) { + int profile, level; + mpeg4_decode_profile_level(s, gb, &profile, &level); + if (profile == FF_PROFILE_MPEG4_SIMPLE_STUDIO && + (level > 0 && level < 9)) { + s->studio_profile = 1; + next_start_code_studio(gb); + extension_and_user_data(s, gb, 0); + } else if (s->studio_profile) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Mixes studio and non studio profile\n"); + return -1; + } + ctx->profile = profile; + ctx->level = level; + } else if (startcode == VISUAL_OBJ_STARTCODE) { + if (s->studio_profile) { + if ((ret = decode_studiovisualobject(ctx, gb)) < 0) + return ret; + } else + mpeg4_decode_visual_object(s, gb); + } else if (startcode == VOP_STARTCODE) { + break; + } + + align_get_bits(gb); + startcode = 0xff; + } + +end: + if (s->studio_profile) { + if (!bits_per_raw_sample) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Missing VOL header\n"); + return -1; + } + return decode_studio_vop_header(ctx, gb); + } else + return decode_vop_header(ctx, gb); +} + +int mpeg4_decode_extradata_ps(u8 *buf, int size, struct mpeg4_param_sets *ps) +{ + int ret = 0; + struct get_bits_context gb; + + ps->head_parsed = false; + + init_get_bits8(&gb, buf, size); + + ret = ff_mpeg4_decode_picture_header(&ps->dec_ps, &gb); + if (ret < -1) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Failed to parse extradata\n"); + return ret; + } + + if (ps->dec_ps.m.width && ps->dec_ps.m.height) + ps->head_parsed = true; + + return 0; +} +
diff --git a/drivers/amvdec_ports/decoder/aml_mpeg4_parser.h b/drivers/amvdec_ports/decoder/aml_mpeg4_parser.h new file mode 100644 index 0000000..f9b71cf --- /dev/null +++ b/drivers/amvdec_ports/decoder/aml_mpeg4_parser.h
@@ -0,0 +1,259 @@ +#ifndef AVCODEC_MPEG4VIDEO_H +#define AVCODEC_MPEG4VIDEO_H + +#include "../aml_vcodec_drv.h" +#include "../utils/common.h" +#ifdef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER +#include "../utils/pixfmt.h" +#endif + +//mpeg4 profile +#define FF_PROFILE_MPEG4_SIMPLE 0 +#define FF_PROFILE_MPEG4_SIMPLE_SCALABLE 1 +#define FF_PROFILE_MPEG4_CORE 2 +#define FF_PROFILE_MPEG4_MAIN 3 +#define FF_PROFILE_MPEG4_N_BIT 4 +#define FF_PROFILE_MPEG4_SCALABLE_TEXTURE 5 +#define FF_PROFILE_MPEG4_SIMPLE_FACE_ANIMATION 6 +#define FF_PROFILE_MPEG4_BASIC_ANIMATED_TEXTURE 7 +#define FF_PROFILE_MPEG4_HYBRID 8 +#define FF_PROFILE_MPEG4_ADVANCED_REAL_TIME 9 +#define FF_PROFILE_MPEG4_CORE_SCALABLE 10 +#define FF_PROFILE_MPEG4_ADVANCED_CODING 11 +#define FF_PROFILE_MPEG4_ADVANCED_CORE 12 +#define FF_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE 13 +#define FF_PROFILE_MPEG4_SIMPLE_STUDIO 14 +#define FF_PROFILE_MPEG4_ADVANCED_SIMPLE 15 + +// shapes +#define RECT_SHAPE 0 +#define BIN_SHAPE 1 +#define BIN_ONLY_SHAPE 2 +#define GRAY_SHAPE 3 + +#define SIMPLE_VO_TYPE 1 +#define CORE_VO_TYPE 3 +#define MAIN_VO_TYPE 4 +#define NBIT_VO_TYPE 5 +#define ARTS_VO_TYPE 10 +#define ACE_VO_TYPE 12 +#define SIMPLE_STUDIO_VO_TYPE 14 +#define CORE_STUDIO_VO_TYPE 15 +#define ADV_SIMPLE_VO_TYPE 17 + +#define VOT_VIDEO_ID 1 +#define VOT_STILL_TEXTURE_ID 2 + +#define FF_PROFILE_UNKNOWN -99 +#define FF_PROFILE_RESERVED -100 + +// aspect_ratio_info +#define EXTENDED_PAR 15 + +//vol_sprite_usage / sprite_enable +#define STATIC_SPRITE 1 +#define GMC_SPRITE 2 + +#define MOTION_MARKER 0x1F001 +#define DC_MARKER 0x6B001 + +#define VOS_STARTCODE 0x1B0 +#define USER_DATA_STARTCODE 0x1B2 +#define GOP_STARTCODE 0x1B3 +#define VISUAL_OBJ_STARTCODE 0x1B5 +#define VOP_STARTCODE 0x1B6 +#define SLICE_STARTCODE 0x1B7 +#define EXT_STARTCODE 0x1B8 + +#define QUANT_MATRIX_EXT_ID 0x3 + +/* smaller packets likely don't contain a real frame */ +#define MAX_NVOP_SIZE 19 + +#define IS_3IV1 0 + +#define CHROMA_420 1 +#define CHROMA_422 2 +#define CHROMA_444 3 + +#define FF_ASPECT_EXTENDED 15 + +#define AV_NOPTS_VALUE (LONG_MIN) + +/** + * Return value for header parsers if frame is not coded. + * */ +#define FRAME_SKIPPED 100 + +enum AVPictureType { + AV_PICTURE_TYPE_NONE = 0, ///< Undefined + AV_PICTURE_TYPE_I, ///< Intra + AV_PICTURE_TYPE_P, ///< Predicted + AV_PICTURE_TYPE_B, ///< Bi-dir predicted + AV_PICTURE_TYPE_S, ///< S(GMC)-VOP MPEG-4 + AV_PICTURE_TYPE_SI, ///< Switching Intra + AV_PICTURE_TYPE_SP, ///< Switching Predicted + AV_PICTURE_TYPE_BI, ///< BI type +}; + +struct VLC { + int bits; + short (*table)[2]; ///< code, bits + int table_size, table_allocated; +}; + +/** + * MpegEncContext. + */ +struct MpegEncContext { + struct mpeg4_dec_param *ctx; + + /* the following parameters must be initialized before encoding */ + int width, height;///< picture size. must be a multiple of 16 + int codec_tag; ///< internal codec_tag upper case converted from avctx codec_tag + int picture_number; //FIXME remove, unclear definition + + /** matrix transmitted in the bitstream */ + u16 intra_matrix[64]; + u16 chroma_intra_matrix[64]; + u16 inter_matrix[64]; + u16 chroma_inter_matrix[64]; + + /* MPEG-4 specific */ + int studio_profile; + int time_base; ///< time in seconds of last I,P,S Frame + int quant_precision; + int quarter_sample; ///< 1->qpel, 0->half pel ME/MC + int aspect_ratio_info; //FIXME remove + int sprite_warping_accuracy; + int data_partitioning; ///< data partitioning flag from header + int low_delay; ///< no reordering needed / has no B-frames + int vo_type; + int mpeg_quant; + + /* divx specific, used to workaround (many) bugs in divx5 */ + int divx_packed; + + /* MPEG-2-specific - I wished not to have to support this mess. */ + int progressive_sequence; + + int progressive_frame; + int interlaced_dct; + + int h_edge_pos, v_edge_pos;///< horizontal / vertical position of the right/bottom edge (pixel replication) + const u8 *y_dc_scale_table; ///< qscale -> y_dc_scale table + const u8 *c_dc_scale_table; ///< qscale -> c_dc_scale table + int qscale; ///< QP + int chroma_qscale; ///< chroma QP + int pict_type; ///< AV_PICTURE_TYPE_I, AV_PICTURE_TYPE_P, AV_PICTURE_TYPE_B, ... + int f_code; ///< forward MV resolution + int b_code; ///< backward MV resolution for B-frames (MPEG-4) + int no_rounding; /**< apply no rounding to motion compensation (MPEG-4, msmpeg4, ...) + for B-frames rounding mode is always 0 */ + int last_time_base; + long time; ///< time of current frame + long last_non_b_time; + u16 pp_time; ///< time distance between the last 2 p,s,i frames + u16 pb_time; ///< time distance between the last b and p,s,i frame + u16 pp_field_time; + u16 pb_field_time; ///< like above, just for interlaced + int real_sprite_warping_points; + int sprite_offset[2][2]; ///< sprite offset[isChroma][isMVY] + int sprite_delta[2][2]; ///< sprite_delta [isY][isMVY] + int mcsel; + int partitioned_frame; ///< is current frame partitioned + int top_field_first; + int alternate_scan; + int last_dc[3]; ///< last DC values for MPEG-1 + int dct_precision; + int intra_dc_precision; + int frame_pred_frame_dct; + int q_scale_type; + int context_reinit; + int chroma_format; +}; + +struct mpeg4_dec_param { + struct MpegEncContext m; + + /// number of bits to represent the fractional part of time + int time_increment_bits; + int shape; + int vol_sprite_usage; + int sprite_brightness_change; + int num_sprite_warping_points; + /// sprite trajectory points + u16 sprite_traj[4][2]; + /// sprite shift [isChroma] + int sprite_shift[2]; + + // reversible vlc + int rvlc; + /// could this stream contain resync markers + int resync_marker; + /// time distance of first I -> B, used for interlaced B-frames + int t_frame; + + int new_pred; + int enhancement_type; + int scalability; + int use_intra_dc_vlc; + + /// QP above which the ac VLC should be used for intra dc + int intra_dc_threshold; + + /* bug workarounds */ + int divx_version; + int divx_build; + int xvid_build; + int lavc_build; + + /// flag for having shown the warning about invalid Divx B-frames + int showed_packed_warning; + /** does the stream contain the low_delay flag, + * used to work around buggy encoders. */ + int vol_control_parameters; + int cplx_estimation_trash_i; + int cplx_estimation_trash_p; + int cplx_estimation_trash_b; + + struct VLC studio_intra_tab[12]; + struct VLC studio_luma_dc; + struct VLC studio_chroma_dc; + + int rgb; + + struct AVRational time_base; + int ticks_per_frame; + struct AVRational sample_aspect_ratio; + enum AVColorPrimaries color_primaries; + enum AVColorTransferCharacteristic color_trc; + enum AVColorSpace colorspace; +#ifdef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER + enum AVPixelFormat pix_fmt; + enum AVColorRange color_range; + enum AVChromaLocation chroma_sample_location; +#endif + int err_recognition; + int idct_algo; + int bits_per_raw_sample; + int profile; + int level; + struct AVRational framerate; + int flags; +}; + +struct mpeg4_param_sets { + bool head_parsed; + /* currently active parameter sets */ + struct mpeg4_dec_param dec_ps; +}; + +#ifdef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER +int mpeg4_decode_extradata_ps(u8 *buf, int size, struct mpeg4_param_sets *ps); +#else +inline int mpeg4_decode_extradata_ps(u8 *buf, int size, struct mpeg4_param_sets *ps) { return -1; } +#endif + +#endif +
diff --git a/drivers/amvdec_ports/decoder/aml_vp9_parser.c b/drivers/amvdec_ports/decoder/aml_vp9_parser.c new file mode 100644 index 0000000..21d5283 --- /dev/null +++ b/drivers/amvdec_ports/decoder/aml_vp9_parser.c
@@ -0,0 +1,299 @@ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/vmalloc.h> +#include <linux/mm.h> +#include <linux/string.h> + +#include "aml_vp9_parser.h" +#include "../utils/get_bits.h" +#include "../utils/put_bits.h" +#include "../utils/golomb.h" +#include "../utils/common.h" +#include "utils.h" + +#define VP9_SYNCCODE 0x498342 + +static int read_colorspace_details(struct VP9Context *s, int profile) +{ + static const enum AVColorSpace colorspaces[8] = { + AVCOL_SPC_UNSPECIFIED, AVCOL_SPC_BT470BG, AVCOL_SPC_BT709, AVCOL_SPC_SMPTE170M, + AVCOL_SPC_SMPTE240M, AVCOL_SPC_BT2020_NCL, AVCOL_SPC_RESERVED, AVCOL_SPC_RGB, + }; + + enum AVColorSpace colorspace; + int color_range; + int bits = profile <= 1 ? 0 : 1 + get_bits1(&s->gb); // 0:8, 1:10, 2:12 + + s->bpp_index = bits; + s->s.h.bpp = 8 + bits * 2; + s->bytesperpixel = (7 + s->s.h.bpp) >> 3; + colorspace = colorspaces[get_bits(&s->gb, 3)]; + if (colorspace == AVCOL_SPC_RGB) { // RGB = profile 1 + if (profile & 1) { + if (get_bits1(&s->gb)) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Reserved bit set in RGB\n"); + return -1; + } + } else { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "RGB not supported in profile %d\n", profile); + return -1; + } + } else { + static const enum AVPixelFormat pix_fmt_for_ss[3][2 /* v */][2 /* h */] = { + { { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P }, + { AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV420P } }, + { { AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10 }, + { AV_PIX_FMT_YUV440P10, AV_PIX_FMT_YUV420P10 } }, + { { AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12 }, + { AV_PIX_FMT_YUV440P12, AV_PIX_FMT_YUV420P12 } }}; + color_range = get_bits1(&s->gb) ? 2 : 1; + if (profile & 1) { + s->ss_h = get_bits1(&s->gb); + s->ss_v = get_bits1(&s->gb); + s->pix_fmt = pix_fmt_for_ss[bits][s->ss_v][s->ss_h]; + if (s->pix_fmt == AV_PIX_FMT_YUV420P) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "YUV 4:2:0 not supported in profile %d\n", profile); + return -1; + } else if (get_bits1(&s->gb)) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Profile %d color details reserved bit set\n", profile); + return -1; + } + } else { + s->ss_h = s->ss_v = 1; + s->pix_fmt = pix_fmt_for_ss[bits][1][1]; + } + } + + return 0; +} + +int decode_frame_header(const u8 *data, int size, struct VP9Context *s, int *ref) +{ + int ret, last_invisible, profile; + + /* general header */ + if ((ret = init_get_bits8(&s->gb, data, size)) < 0) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Failed to initialize bitstream reader\n"); + return ret; + } + + if (get_bits(&s->gb, 2) != 0x2) { // frame marker + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Invalid frame marker\n"); + return -1; + } + + profile = get_bits1(&s->gb); + profile |= get_bits1(&s->gb) << 1; + if (profile == 3) + profile += get_bits1(&s->gb); + + if (profile > 3) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Profile %d is not yet supported\n", profile); + return -1; + } + + s->s.h.profile = profile; + if (get_bits1(&s->gb)) { + *ref = get_bits(&s->gb, 3); + return 0; + } + + s->last_keyframe = s->s.h.keyframe; + s->s.h.keyframe = !get_bits1(&s->gb); + + last_invisible = s->s.h.invisible; + s->s.h.invisible = !get_bits1(&s->gb); + s->s.h.errorres = get_bits1(&s->gb); + s->s.h.use_last_frame_mvs = !s->s.h.errorres && !last_invisible; + + if (s->s.h.keyframe) { + if (get_bits_long(&s->gb, 24) != VP9_SYNCCODE) { // synccode + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Invalid sync code\n"); + return -1; + } + if ((ret = read_colorspace_details(s,profile)) < 0) + return ret; + // for profile 1, here follows the subsampling bits + s->s.h.refreshrefmask = 0xff; + s->width = get_bits(&s->gb, 16) + 1; + s->height = get_bits(&s->gb, 16) + 1; + if (get_bits1(&s->gb)) { // has scaling + s->render_width = get_bits(&s->gb, 16) + 1; + s->render_height = get_bits(&s->gb, 16) + 1; + } else { + s->render_width = s->width; + s->render_height = s->height; + } + /*pr_info("keyframe res: (%d x %d), render size: (%d x %d)\n", + s->width, s->height, s->render_width, s->render_height);*/ + } else { + s->s.h.intraonly = s->s.h.invisible ? get_bits1(&s->gb) : 0; + s->s.h.resetctx = s->s.h.errorres ? 0 : get_bits(&s->gb, 2); + if (s->s.h.intraonly) { + if (get_bits_long(&s->gb, 24) != VP9_SYNCCODE) { // synccode + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Invalid sync code\n"); + return -1; + } + if (profile >= 1) { + if ((ret = read_colorspace_details(s, profile)) < 0) + return ret; + } else { + s->ss_h = s->ss_v = 1; + s->s.h.bpp = 8; + s->bpp_index = 0; + s->bytesperpixel = 1; + s->pix_fmt = AV_PIX_FMT_YUV420P; + } + s->s.h.refreshrefmask = get_bits(&s->gb, 8); + s->width = get_bits(&s->gb, 16) + 1; + s->height = get_bits(&s->gb, 16) + 1; + if (get_bits1(&s->gb)) { // has scaling + s->render_width = get_bits(&s->gb, 16) + 1; + s->render_height = get_bits(&s->gb, 16) + 1; + } else { + s->render_width = s->width; + s->render_height = s->height; + } + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "intra res: (%d x %d), render size: (%d x %d)\n", + s->width, s->height, s->render_width, s->render_height); + } else { + s->s.h.refreshrefmask = get_bits(&s->gb, 8); + s->s.h.refidx[0] = get_bits(&s->gb, 3); + s->s.h.signbias[0] = get_bits1(&s->gb) && !s->s.h.errorres; + s->s.h.refidx[1] = get_bits(&s->gb, 3); + s->s.h.signbias[1] = get_bits1(&s->gb) && !s->s.h.errorres; + s->s.h.refidx[2] = get_bits(&s->gb, 3); + s->s.h.signbias[2] = get_bits1(&s->gb) && !s->s.h.errorres; + + /*refresh_frame_flags; + for (i = 0; i < REFS_PER_FRAME; ++i) { + frame_refs[i]; + ref_frame_sign_biases[i]; + } + frame_size_from_refs(); + high_precision_mv; + interp_filter();*/ + + return -1; + } + } + + return 0; +} + +int vp9_superframe_split_filter(struct vp9_superframe_split *s) +{ + int i, j, ret, marker; + bool is_superframe = false; + int *prefix = (int *)s->data; + + if (!s->data) + return -1; + + #define AML_PREFIX ('V' << 24 | 'L' << 16 | 'M' << 8 | 'A') + if (prefix[3] == AML_PREFIX) { + s->prefix_size = 16; + /*pr_info("the frame data has beed added header\n");*/ + } + + marker = s->data[s->data_size - 1]; + if ((marker & 0xe0) == 0xc0) { + int length_size = 1 + ((marker >> 3) & 0x3); + int nb_frames = 1 + (marker & 0x7); + int idx_size = 2 + nb_frames * length_size; + + if (s->data_size >= idx_size && + s->data[s->data_size - idx_size] == marker) { + s64 total_size = 0; + int idx = s->data_size + 1 - idx_size; + + for (i = 0; i < nb_frames; i++) { + int frame_size = 0; + for (j = 0; j < length_size; j++) + frame_size |= s->data[idx++] << (j * 8); + + total_size += frame_size; + if (frame_size < 0 || + total_size > s->data_size - idx_size) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Invalid frame size in a sframe: %d\n", + frame_size); + ret = -EINVAL; + goto fail; + } + s->sizes[i] = frame_size; + } + + s->nb_frames = nb_frames; + s->size = total_size; + s->next_frame = 0; + s->next_frame_offset = 0; + is_superframe = true; + } + }else { + s->nb_frames = 1; + s->sizes[0] = s->data_size; + s->size = s->data_size; + } + + /*pr_info("sframe: %d, frames: %d, IN: %x, OUT: %x\n", + is_superframe, s->nb_frames, + s->data_size, s->size);*/ + + /* parse uncompressed header. */ + if (is_superframe) { + /* bitstream profile. */ + /* frame type. (intra or inter) */ + /* colorspace descriptor */ + /* ... */ + + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "the frame is a superframe.\n"); + } + + /*pr_err("in: %x, %d, out: %x, sizes %d,%d,%d,%d,%d,%d,%d,%d\n", + s->data_size, + s->nb_frames, + s->size, + s->sizes[0], + s->sizes[1], + s->sizes[2], + s->sizes[3], + s->sizes[4], + s->sizes[5], + s->sizes[6], + s->sizes[7]);*/ + + return 0; +fail: + return ret; +} + +int vp9_decode_extradata_ps(u8 *data, int size, struct vp9_param_sets *ps) +{ + int i, ref = -1, ret = 0; + struct vp9_superframe_split s = {0}; + + /*parse superframe.*/ + s.data = data; + s.data_size = size; + ret = vp9_superframe_split_filter(&s); + if (ret) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "parse frames failed.\n"); + return ret; + } + + for (i = 0; i < s.nb_frames; i++) { + u32 len = s.sizes[i] - s.prefix_size; + u8 *buf = s.data + s.next_frame_offset + s.prefix_size; + + ret = decode_frame_header(buf, len, &ps->ctx, &ref); + if (!ret) { + ps->head_parsed = ref < 0 ? true : false; + return 0; + } + + s.next_frame_offset = len + s.prefix_size; + } + + return ret; +} +
diff --git a/drivers/amvdec_ports/decoder/aml_vp9_parser.h b/drivers/amvdec_ports/decoder/aml_vp9_parser.h new file mode 100644 index 0000000..ddeddec --- /dev/null +++ b/drivers/amvdec_ports/decoder/aml_vp9_parser.h
@@ -0,0 +1,184 @@ +/* + * drivers/amvdec_ports/decoder/aml_vp9_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_VP9_PARSER_H +#define AML_VP9_PARSER_H + +#include "../aml_vcodec_drv.h" +#ifdef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER +#include "../utils/pixfmt.h" +#include "../utils/get_bits.h" +#endif + +#define MAX_SEGMENT 8 + +struct VP9BitstreamHeader { + // bitstream header + u8 profile; + u8 bpp; + u8 keyframe; + u8 invisible; + u8 errorres; + u8 intraonly; + u8 resetctx; + u8 refreshrefmask; + u8 highprecisionmvs; + u8 allowcompinter; + u8 refreshctx; + u8 parallelmode; + u8 framectxid; + u8 use_last_frame_mvs; + u8 refidx[3]; + u8 signbias[3]; + u8 fixcompref; + u8 varcompref[2]; + struct { + u8 level; + char sharpness; + } filter; + struct { + u8 enabled; + u8 updated; + char mode[2]; + char ref[4]; + } lf_delta; + u8 yac_qi; + char ydc_qdelta, uvdc_qdelta, uvac_qdelta; + u8 lossless; + struct { + u8 enabled; + u8 temporal; + u8 absolute_vals; + u8 update_map; + u8 prob[7]; + u8 pred_prob[3]; + struct { + u8 q_enabled; + u8 lf_enabled; + u8 ref_enabled; + u8 skip_enabled; + u8 ref_val; + int16_t q_val; + char lf_val; + int16_t qmul[2][2]; + u8 lflvl[4][2]; + } feat[MAX_SEGMENT]; + } segmentation; + struct { + u32 log2_tile_cols, log2_tile_rows; + u32 tile_cols, tile_rows; + } tiling; + + int uncompressed_header_size; + int compressed_header_size; +}; + +struct VP9SharedContext { + struct VP9BitstreamHeader h; + + //struct ThreadFrame refs[8]; +#define CUR_FRAME 0 +#define REF_FRAME_MVPAIR 1 +#define REF_FRAME_SEGMAP 2 + //struct VP9Frame frames[3]; +}; + +struct VP9Context { + struct VP9SharedContext s; +#ifdef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER + struct get_bits_context gb; +#endif + int pass, active_tile_cols; + + u8 ss_h, ss_v; + u8 last_bpp, bpp_index, bytesperpixel; + u8 last_keyframe; + // sb_cols/rows, rows/cols and last_fmt are used for allocating all internal + // arrays, and are thus per-thread. w/h and gf_fmt are synced between threads + // and are therefore per-stream. pix_fmt represents the value in the header + // of the currently processed frame. + int width; + int height; + + int render_width; + int render_height; +#ifdef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER + enum AVPixelFormat pix_fmt, last_fmt, gf_fmt; +#endif + u32 sb_cols, sb_rows, rows, cols; + + struct { + u8 lim_lut[64]; + u8 mblim_lut[64]; + } filter_lut; + struct { + u8 coef[4][2][2][6][6][3]; + } prob_ctx[4]; + struct { + u8 coef[4][2][2][6][6][11]; + } prob; + + // contextual (above) cache + u8 *above_partition_ctx; + u8 *above_mode_ctx; + // FIXME maybe merge some of the below in a flags field? + u8 *above_y_nnz_ctx; + u8 *above_uv_nnz_ctx[2]; + u8 *above_skip_ctx; // 1bit + u8 *above_txfm_ctx; // 2bit + u8 *above_segpred_ctx; // 1bit + u8 *above_intra_ctx; // 1bit + u8 *above_comp_ctx; // 1bit + u8 *above_ref_ctx; // 2bit + u8 *above_filter_ctx; + + // whole-frame cache + u8 *intra_pred_data[3]; + + // block reconstruction intermediates + int block_alloc_using_2pass; + uint16_t mvscale[3][2]; + u8 mvstep[3][2]; +}; + +struct vp9_superframe_split { + /*in data*/ + u8 *data; + u32 data_size; + + /*out data*/ + int nb_frames; + int size; + int next_frame; + u32 next_frame_offset; + int prefix_size; + int sizes[8]; +}; + +struct vp9_param_sets { + bool head_parsed; + struct VP9Context ctx; +}; + +#ifdef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER +int vp9_superframe_split_filter(struct vp9_superframe_split *s); +int vp9_decode_extradata_ps(u8 *data, int size, struct vp9_param_sets *ps); +#else +inline int vp9_decode_extradata_ps(u8 *data, int size, struct vp9_param_sets *ps) { return -1; } +#endif + +#endif //AML_VP9_PARSER_H
diff --git a/drivers/amvdec_ports/decoder/utils.h b/drivers/amvdec_ports/decoder/utils.h new file mode 100644 index 0000000..26b1552 --- /dev/null +++ b/drivers/amvdec_ports/decoder/utils.h
@@ -0,0 +1,31 @@ +/* + * drivers/amlogic/media_modules/amvdec_ports/decoder/utils.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 _UTILS_H +#define _UTILS_H + +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define CLAMP(x, low, high) \ + (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) +#define BITAT(x, n) ((x & (1 << n)) == (1 << n)) + +typedef unsigned char uint8_t; +typedef int int32_t; +typedef unsigned int uint32_t; + +#endif //_UTILS_H
diff --git a/drivers/amvdec_ports/decoder/vdec_av1_if.c b/drivers/amvdec_ports/decoder/vdec_av1_if.c new file mode 100644 index 0000000..c28ca10 --- /dev/null +++ b/drivers/amvdec_ports/decoder/vdec_av1_if.c
@@ -0,0 +1,1374 @@ +/* +* 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/module.h> +#include <linux/slab.h> +#include <linux/timer.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <uapi/linux/swab.h> +#include "../vdec_drv_if.h" +#include "../aml_vcodec_util.h" +#include "../aml_vcodec_dec.h" +#include "../aml_vcodec_drv.h" +#include "../aml_vcodec_adapt.h" +#include "../vdec_drv_base.h" +#include "../utils/common.h" + +#define KERNEL_ATRACE_TAG KERNEL_ATRACE_TAG_V4L2 +#include <trace/events/meson_atrace.h> + +#define PREFIX_SIZE (16) + +#define HEADER_BUFFER_SIZE (32 * 1024) +#define SYNC_CODE (0x498342) + +extern int av1_need_prefix; + +/** + * struct av1_fb - av1 decode frame buffer information + * @vdec_fb_va : virtual address of struct vdec_fb + * @y_fb_dma : dma address of Y frame buffer (luma) + * @c_fb_dma : dma address of C frame buffer (chroma) + * @poc : picture order count of frame buffer + * @reserved : for 8 bytes alignment + */ +struct av1_fb { + uint64_t vdec_fb_va; + uint64_t y_fb_dma; + uint64_t c_fb_dma; + int32_t poc; + uint32_t reserved; +}; + +/** + * struct vdec_av1_dec_info - decode information + * @dpb_sz : decoding picture buffer size + * @resolution_changed : resoltion change happen + * @reserved : for 8 bytes alignment + * @bs_dma : Input bit-stream buffer dma address + * @y_fb_dma : Y frame buffer dma address + * @c_fb_dma : C frame buffer dma address + * @vdec_fb_va : VDEC frame buffer struct virtual address + */ +struct vdec_av1_dec_info { + uint32_t dpb_sz; + uint32_t resolution_changed; + uint32_t reserved; + uint64_t bs_dma; + uint64_t y_fb_dma; + uint64_t c_fb_dma; + uint64_t vdec_fb_va; +}; + +/** + * struct vdec_av1_vsi - shared memory for decode information exchange + * between VPU and Host. + * The memory is allocated by VPU then mapping to Host + * in vpu_dec_init() and freed in vpu_dec_deinit() + * by VPU. + * AP-W/R : AP is writer/reader on this item + * VPU-W/R: VPU is write/reader on this item + * @hdr_buf : Header parsing buffer (AP-W, VPU-R) + * @list_free : free frame buffer ring list (AP-W/R, VPU-W) + * @list_disp : display frame buffer ring list (AP-R, VPU-W) + * @dec : decode information (AP-R, VPU-W) + * @pic : picture information (AP-R, VPU-W) + * @crop : crop information (AP-R, VPU-W) + */ +struct vdec_av1_vsi { + char *header_buf; + int sps_size; + int pps_size; + int sei_size; + int head_offset; + struct vdec_av1_dec_info dec; + struct vdec_pic_info pic; + struct vdec_pic_info cur_pic; + struct v4l2_rect crop; + bool is_combine; + int nalu_pos; +}; + +/** + * struct vdec_av1_inst - av1 decoder instance + * @num_nalu : how many nalus be decoded + * @ctx : point to aml_vcodec_ctx + * @vsi : VPU shared information + */ +struct vdec_av1_inst { + unsigned int num_nalu; + struct aml_vcodec_ctx *ctx; + struct aml_vdec_adapt vdec; + struct vdec_av1_vsi *vsi; + struct aml_dec_params parms; + struct completion comp; + struct vdec_comp_buf_info comp_info; +}; + +/*!\brief OBU types. */ +enum OBU_TYPE { + OBU_SEQUENCE_HEADER = 1, + OBU_TEMPORAL_DELIMITER = 2, + OBU_FRAME_HEADER = 3, + OBU_TILE_GROUP = 4, + OBU_METADATA = 5, + OBU_FRAME = 6, + OBU_REDUNDANT_FRAME_HEADER = 7, + OBU_TILE_LIST = 8, + OBU_PADDING = 15, +}; + +/*!\brief OBU metadata types. */ +enum OBU_METADATA_TYPE { + OBU_METADATA_TYPE_RESERVED_0 = 0, + OBU_METADATA_TYPE_HDR_CLL = 1, + OBU_METADATA_TYPE_HDR_MDCV = 2, + OBU_METADATA_TYPE_SCALABILITY = 3, + OBU_METADATA_TYPE_ITUT_T35 = 4, + OBU_METADATA_TYPE_TIMECODE = 5, +}; + +struct ObuHeader { + size_t size; // Size (1 or 2 bytes) of the OBU header (including the + // optional OBU extension header) in the bitstream. + enum OBU_TYPE type; + int has_size_field; + int has_extension; + // The following fields come from the OBU extension header and therefore are + // only used if has_extension is true. + int temporal_layer_id; + int spatial_layer_id; +}; + +static const size_t kMaximumLeb128Size = 8; +static const u8 kLeb128ByteMask = 0x7f; // Binary: 01111111 + +// Disallow values larger than 32-bits to ensure consistent behavior on 32 and +// 64 bit targets: value is typically used to determine buffer allocation size +// when decoded. +static const u64 kMaximumLeb128Value = ULONG_MAX; + +char obu_type_name[16][32] = { + "UNKNOWN", + "OBU_SEQUENCE_HEADER", + "OBU_TEMPORAL_DELIMITER", + "OBU_FRAME_HEADER", + "OBU_TILE_GROUP", + "OBU_METADATA", + "OBU_FRAME", + "OBU_REDUNDANT_FRAME_HEADER", + "OBU_TILE_LIST", + "UNKNOWN", + "UNKNOWN", + "UNKNOWN", + "UNKNOWN", + "UNKNOWN", + "UNKNOWN", + "OBU_PADDING" +}; + +char meta_type_name[6][32] = { + "OBU_METADATA_TYPE_RESERVED_0", + "OBU_METADATA_TYPE_HDR_CLL", + "OBU_METADATA_TYPE_HDR_MDCV", + "OBU_METADATA_TYPE_SCALABILITY", + "OBU_METADATA_TYPE_ITUT_T35", + "OBU_METADATA_TYPE_TIMECODE" +}; + +struct read_bit_buffer { + const u8 *bit_buffer; + const u8 *bit_buffer_end; + u32 bit_offset; +}; + +struct DataBuffer { + const u8 *data; + size_t size; +}; + +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) +{ + *pic = inst->vsi->pic; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "pic(%d, %d), buf(%d, %d)\n", + pic->visible_width, pic->visible_height, + pic->coded_width, pic->coded_height); + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "Y(%d, %d), C(%d, %d)\n", + pic->y_bs_sz, pic->y_len_sz, + pic->c_bs_sz, pic->c_len_sz); +} + +static void get_crop_info(struct vdec_av1_inst *inst, struct v4l2_rect *cr) +{ + cr->left = inst->vsi->crop.left; + cr->top = inst->vsi->crop.top; + cr->width = inst->vsi->crop.width; + cr->height = inst->vsi->crop.height; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "l=%d, t=%d, w=%d, h=%d\n", + cr->left, cr->top, cr->width, cr->height); +} + +static void get_dpb_size(struct vdec_av1_inst *inst, unsigned int *dpb_sz) +{ + *dpb_sz = inst->vsi->dec.dpb_sz; + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "sz=%d\n", *dpb_sz); +} + +static u32 vdec_config_default_parms(u8 *parm) +{ + u8 *pbuf = parm; + + pbuf += sprintf(pbuf, "parm_v4l_codec_enable:1;"); + 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: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;"); + pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_endian:0;"); + + return parm - pbuf; +} + +static void vdec_parser_parms(struct vdec_av1_inst *inst) +{ + 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; + + pbuf += sprintf(pbuf, "parm_v4l_codec_enable:1;"); + pbuf += sprintf(pbuf, "parm_v4l_buffer_margin:%d;", + 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: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;", + ctx->config.parm.dec.cfg.canvas_mem_mode); + pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_endian:%d;", + 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 = 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) && + 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;", + ctx->config.parm.dec.hdr.color_parms.primaries[0][1]); + pbuf += sprintf(pbuf, "mB.x:%d;", + ctx->config.parm.dec.hdr.color_parms.primaries[1][0]); + pbuf += sprintf(pbuf, "mB.y:%d;", + ctx->config.parm.dec.hdr.color_parms.primaries[1][1]); + pbuf += sprintf(pbuf, "mR.x:%d;", + ctx->config.parm.dec.hdr.color_parms.primaries[2][0]); + pbuf += sprintf(pbuf, "mR.y:%d;", + ctx->config.parm.dec.hdr.color_parms.primaries[2][1]); + pbuf += sprintf(pbuf, "mW.x:%d;", + ctx->config.parm.dec.hdr.color_parms.white_point[0]); + pbuf += sprintf(pbuf, "mW.y:%d;", + ctx->config.parm.dec.hdr.color_parms.white_point[1]); + pbuf += sprintf(pbuf, "mMaxDL:%d;", + ctx->config.parm.dec.hdr.color_parms.luminance[0] * 1000); + pbuf += sprintf(pbuf, "mMinDL:%d;", + ctx->config.parm.dec.hdr.color_parms.luminance[1]); + pbuf += sprintf(pbuf, "mMaxCLL:%d;", + ctx->config.parm.dec.hdr.color_parms.content_light_level.max_content); + pbuf += sprintf(pbuf, "mMaxFALL:%d;", + ctx->config.parm.dec.hdr.color_parms.content_light_level.max_pic_average); + ctx->config.length = pbuf - ctx->config.buf; + 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; + inst->parms.parms_status |= V4L2_CONFIG_PARM_DECODE_CFGINFO; +} + +static int vdec_av1_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) +{ + struct vdec_av1_inst *inst = NULL; + int ret = -1; + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + 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; + inst->ctx = ctx; + + vdec_parser_parms(inst); + + /* set play mode.*/ + if (ctx->is_drm_mode) + inst->vdec.port.flag |= PORT_FLAG_DRM; + + /* to eable av1 hw.*/ + inst->vdec.port.type = PORT_TYPE_HEVC; + + /* probe info from the stream */ + inst->vsi = kzalloc(sizeof(struct vdec_av1_vsi), GFP_KERNEL); + if (!inst->vsi) { + ret = -ENOMEM; + goto err; + } + + /* alloc the header buffer to be used cache sps or spp etc.*/ + 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; + + /* init decoder. */ + ret = video_decoder_init(&inst->vdec); + if (ret) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "vdec_av1 init err=%d\n", ret); + goto err; + } + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + "av1 Instance >> %lx\n", (ulong) inst); + + return 0; +err: + if (inst && inst->vsi && inst->vsi->header_buf) + vfree(inst->vsi->header_buf); + if (inst && inst->vsi) + kfree(inst->vsi); + if (inst) + kfree(inst); + *h_vdec = 0; + + return ret; +} + +static int parse_stream_ucode(struct vdec_av1_inst *inst, + u8 *buf, u32 size, u64 timestamp) +{ + int ret = 0; + + ret = vdec_write_nalu(inst, buf, size, timestamp); + if (ret < 0) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "write data failed. size: %d, err: %d\n", size, ret); + return ret; + } + + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); + + return inst->vsi->pic.dpb_frames ? 0 : -1; +} + +static int parse_stream_ucode_dma(struct vdec_av1_inst *inst, + ulong buf, u32 size, u64 timestamp, u32 handle) +{ + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; + + ret = vdec_vframe_write_with_dma(vdec, buf, size, timestamp, handle, + vdec_vframe_input_free, inst->ctx); + if (ret < 0) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "write frame data failed. err: %d\n", ret); + return ret; + } + + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); + + return inst->vsi->pic.dpb_frames ? 0 : -1; +} + +static int parse_stream_cpu(struct vdec_av1_inst *inst, u8 *buf, u32 size) +{ + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "can not suppport parse stream by cpu.\n"); + + return -1; +} + +static int vdec_av1_probe(unsigned long h_vdec, + struct aml_vcodec_mem *bs, void *out) +{ + struct vdec_av1_inst *inst = + (struct vdec_av1_inst *)h_vdec; + u8 *buf = (u8 *)bs->vaddr; + u32 size = bs->size; + int ret = 0; + + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if ((s->magic != AML_VIDEO_MAGIC) && + (s->type != V4L_STREAM_TYPE_MATEDATA)) + return -1; + + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, s->data, + s->len, bs->timestamp); + } else { + ret = parse_stream_cpu(inst, s->data, s->len); + } + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = parse_stream_ucode_dma(inst, bs->addr, size, + bs->timestamp, BUFF_IDX(bs, bs->index)); + } + } else { + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, buf, size, bs->timestamp); + } else { + ret = parse_stream_cpu(inst, buf, size); + } + } + + inst->vsi->cur_pic = inst->vsi->pic; + + return ret; +} + +static void vdec_av1_deinit(unsigned long h_vdec) +{ + struct vdec_av1_inst *inst = (struct vdec_av1_inst *)h_vdec; + struct aml_vcodec_ctx *ctx = inst->ctx; + + video_decoder_release(&inst->vdec); + + if (inst->vsi && inst->vsi->header_buf) + vfree(inst->vsi->header_buf); + + if (inst->vsi) + kfree(inst->vsi); + + kfree(inst); + + ctx->drv_handle = 0; +} + +// Returns 1 when OBU type is valid, and 0 otherwise. +static int valid_obu_type(int obu_type) +{ + int valid_type = 0; + + switch (obu_type) { + case OBU_SEQUENCE_HEADER: + case OBU_TEMPORAL_DELIMITER: + case OBU_FRAME_HEADER: + case OBU_TILE_GROUP: + case OBU_METADATA: + case OBU_FRAME: + case OBU_REDUNDANT_FRAME_HEADER: + case OBU_TILE_LIST: + case OBU_PADDING: + valid_type = 1; + break; + default: + break; + } + + return valid_type; +} + +size_t uleb_size_in_bytes(u64 value) +{ + size_t size = 0; + + do { + ++size; + } while ((value >>= 7) != 0); + + return size; +} + +int uleb_decode(const u8 *buffer, size_t available, + u64 *value, size_t *length) +{ + int i; + + if (buffer && value) { + *value = 0; + + for (i = 0; i < kMaximumLeb128Size && i < available; ++i) { + const u8 decoded_byte = *(buffer + i) & kLeb128ByteMask; + + *value |= ((u64)decoded_byte) << (i * 7); + if ((*(buffer + i) >> 7) == 0) { + if (length) { + *length = i + 1; + } + + // Fail on values larger than 32-bits to ensure consistent behavior on + // 32 and 64 bit targets: value is typically used to determine buffer + // allocation size. + if (*value > ULONG_MAX) + return -1; + + return 0; + } + } + } + + // If we get here, either the buffer/value pointers were invalid, + // or we ran over the available space + return -1; +} + +int uleb_encode(u64 value, size_t available, + u8 *coded_value, size_t *coded_size) +{ + int i; + const size_t leb_size = uleb_size_in_bytes(value); + + if (value > kMaximumLeb128Value || leb_size > kMaximumLeb128Size || + leb_size > available || !coded_value || !coded_size) { + return -1; + } + + for (i = 0; i < leb_size; ++i) { + u8 byte = value & 0x7f; + + value >>= 7; + if (value != 0) byte |= 0x80; // Signal that more bytes follow. + + *(coded_value + i) = byte; + } + + *coded_size = leb_size; + + return 0; +} + +static int rb_read_bit(struct read_bit_buffer *rb) +{ + const u32 off = rb->bit_offset; + const u32 p = off >> 3; + const int q = 7 - (int)(off & 0x7); + + if (rb->bit_buffer + p < rb->bit_buffer_end) { + const int bit = (rb->bit_buffer[p] >> q) & 1; + + rb->bit_offset = off + 1; + return bit; + } else { + return 0; + } +} + +static int rb_read_literal(struct read_bit_buffer *rb, int bits) +{ + int value = 0, bit; + + for (bit = bits - 1; bit >= 0; bit--) + value |= rb_read_bit(rb) << bit; + + return value; +} + +static int read_obu_size(const u8 *data, + size_t bytes_available, + size_t *const obu_size, + size_t *const length_field_size) +{ + u64 u_obu_size = 0; + + if (uleb_decode(data, bytes_available, &u_obu_size, length_field_size) != 0) { + return -1; + } + + if (u_obu_size > ULONG_MAX) + return -1; + + *obu_size = (size_t) u_obu_size; + + return 0; +} + +// Parses OBU header and stores values in 'header'. +static int read_obu_header(struct read_bit_buffer *rb, + int is_annexb, struct ObuHeader *header) +{ + const int bit_buffer_byte_length = + rb->bit_buffer_end - rb->bit_buffer; + + if (!rb || !header) + return -1; + + if (bit_buffer_byte_length < 1) + return -1; + + header->size = 1; + + if (rb_read_bit(rb) != 0) { + // Forbidden bit. Must not be set. + return -1; + } + + header->type = (enum OBU_TYPE) rb_read_literal(rb, 4); + if (!valid_obu_type(header->type)) + return -1; + + header->has_extension = rb_read_bit(rb); + header->has_size_field = rb_read_bit(rb); + + if (!header->has_size_field && !is_annexb) { + // section 5 obu streams must have obu_size field set. + return -1; + } + + if (rb_read_bit(rb) != 0) { + // obu_reserved_1bit must be set to 0. + return -1; + } + + if (header->has_extension) { + if (bit_buffer_byte_length == 1) + return -1; + + header->size += 1; + header->temporal_layer_id = rb_read_literal(rb, 3); + header->spatial_layer_id = rb_read_literal(rb, 2); + if (rb_read_literal(rb, 3) != 0) { + // extension_header_reserved_3bits must be set to 0. + return -1; + } + } + + return 0; +} + +int read_obu_header_and_size(const u8 *data, + size_t bytes_available, + int is_annexb, + struct ObuHeader *obu_header, + size_t *const payload_size, + size_t *const bytes_read) +{ + size_t length_field_size_obu = 0; + size_t length_field_size_payload = 0; + size_t obu_size = 0; + int status = 0; + struct read_bit_buffer rb = { data + length_field_size_obu, + data + bytes_available, 0}; + + if (is_annexb) { + // Size field comes before the OBU header, and includes the OBU header + status = read_obu_size(data, bytes_available, &obu_size, &length_field_size_obu); + if (status != 0) + return status; + } + + status = read_obu_header(&rb, is_annexb, obu_header); + if (status != 0) + return status; + + if (!obu_header->has_size_field) { + // Derive the payload size from the data we've already read + if (obu_size < obu_header->size) + return -1; + + *payload_size = obu_size - obu_header->size; + } else { + // Size field comes after the OBU header, and is just the payload size + status = read_obu_size(data + length_field_size_obu + obu_header->size, + bytes_available - length_field_size_obu - obu_header->size, + payload_size, &length_field_size_payload); + if (status != 0) + return status; + } + + *bytes_read = length_field_size_obu + obu_header->size + length_field_size_payload; + + return 0; +} + +int parser_frame(int is_annexb, u8 *data, const u8 *data_end, + u8 *dst_data, u32 *frame_len, u8 *meta_buf, u32 *meta_len) +{ + int frame_decoding_finished = 0; + u32 obu_size = 0; + int seen_frame_header = 0; + int next_start_tile = 0; + struct DataBuffer obu_size_hdr; + u8 header[20] = {0}; + u8 *p = NULL; + u32 rpu_size = 0; + struct ObuHeader obu_header; + + memset(&obu_header, 0, sizeof(obu_header)); + + // decode frame as a series of OBUs + while (!frame_decoding_finished) { + // struct read_bit_buffer rb; + size_t payload_size = 0; + size_t header_size = 0; + size_t bytes_read = 0; + const size_t bytes_available = data_end - data; + enum OBU_METADATA_TYPE meta_type; + int status; + u64 type; + u32 i; + + if (bytes_available == 0 && !seen_frame_header) { + break; + } + + status = read_obu_header_and_size(data, bytes_available, is_annexb, + &obu_header, &payload_size, &bytes_read); + if (status != 0) { + return -1; + } + + // Record obu size header information. + obu_size_hdr.data = data + obu_header.size; + obu_size_hdr.size = bytes_read - obu_header.size; + + // Note: read_obu_header_and_size() takes care of checking that this + // doesn't cause 'data' to advance past 'data_end'. + + if ((size_t)(data_end - data - bytes_read) < payload_size) { + return -1; + } + + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "obu %s len %zu+%zu\n", + obu_type_name[obu_header.type], + bytes_read, payload_size); + + if (!is_annexb) { + obu_size = bytes_read + payload_size + 4; + header_size = 20; + } else { + obu_size = bytes_read + payload_size; + header_size = 16; + } + + header[0] = ((obu_size + 4) >> 24) & 0xff; + header[1] = ((obu_size + 4) >> 16) & 0xff; + header[2] = ((obu_size + 4) >> 8) & 0xff; + header[3] = ((obu_size + 4) >> 0) & 0xff; + header[4] = header[0] ^ 0xff; + header[5] = header[1] ^ 0xff; + header[6] = header[2] ^ 0xff; + header[7] = header[3] ^ 0xff; + header[8] = 0; + header[9] = 0; + header[10] = 0; + header[11] = 1; + header[12] = 'A'; + header[13] = 'M'; + header[14] = 'L'; + header[15] = 'V'; + + // put new size to here as annexb + header[16] = (obu_size & 0xff) | 0x80; + header[17] = ((obu_size >> 7) & 0xff) | 0x80; + header[18] = ((obu_size >> 14) & 0xff) | 0x80; + header[19] = ((obu_size >> 21) & 0xff) | 0x00; + + memcpy(dst_data, header, header_size); + dst_data += header_size; + memcpy(dst_data, data, bytes_read + payload_size); + dst_data += (bytes_read + payload_size); + + data += bytes_read; + *frame_len += (header_size + bytes_read + payload_size); + + switch (obu_header.type) { + case OBU_TEMPORAL_DELIMITER: + seen_frame_header = 0; + next_start_tile = 0; + break; + case OBU_SEQUENCE_HEADER: + // The sequence header should not change in the middle of a frame. + if (seen_frame_header) { + return -1; + } + break; + case OBU_FRAME_HEADER: + if (data_end == data + payload_size) { + frame_decoding_finished = 1; + } else { + seen_frame_header = 1; + } + break; + case OBU_REDUNDANT_FRAME_HEADER: + case OBU_FRAME: + if (obu_header.type == OBU_REDUNDANT_FRAME_HEADER) { + if (!seen_frame_header) { + return -1; + } + } else { + // OBU_FRAME_HEADER or OBU_FRAME. + if (seen_frame_header) { + return -1; + } + } + if (obu_header.type == OBU_FRAME) { + if (data_end == data + payload_size) { + frame_decoding_finished = 1; + seen_frame_header = 0; + } + } + break; + case OBU_TILE_GROUP: + if (!seen_frame_header) { + return -1; + } + if (data + payload_size == data_end) + frame_decoding_finished = 1; + if (frame_decoding_finished) + seen_frame_header = 0; + break; + case OBU_METADATA: + uleb_decode(data, 8, &type, &bytes_read); + if (type < 6) + meta_type = type; + else + meta_type = 0; + p = data + bytes_read; + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, + "meta type %s %zu+%zu\n", + meta_type_name[type], + bytes_read, + payload_size - bytes_read); + + if (meta_type == OBU_METADATA_TYPE_ITUT_T35) { +#if 0 /* for dumping original obu payload */ + for (i = 0; i < payload_size - bytes_read; i++) { + pr_info("%02x ", p[i]); + if (i % 16 == 15) + pr_info("\n"); + } + if (i % 16 != 0) + pr_info("\n"); +#endif + if ((p[0] == 0xb5) /* country code */ + && ((p[1] == 0x00) && (p[2] == 0x3b)) /* terminal_provider_code */ + && ((p[3] == 0x00) && (p[4] == 0x00) && (p[5] == 0x08) && (p[6] == 0x00))) { /* terminal_provider_oriented_code */ + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, + "dolbyvison rpu\n"); + meta_buf[0] = meta_buf[1] = meta_buf[2] = 0; + meta_buf[3] = 0x01; + meta_buf[4] = 0x19; + + if (p[11] & 0x10) { + rpu_size = 0x100; + rpu_size |= (p[11] & 0x0f) << 4; + rpu_size |= (p[12] >> 4) & 0x0f; + if (p[12] & 0x08) { + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, + "meta rpu in obu exceed 512 bytes\n"); + break; + } + for (i = 0; i < rpu_size; i++) { + meta_buf[5 + i] = (p[12 + i] & 0x07) << 5; + meta_buf[5 + i] |= (p[13 + i] >> 3) & 0x1f; + } + rpu_size += 5; + } else { + rpu_size = (p[10] & 0x1f) << 3; + rpu_size |= (p[11] >> 5) & 0x07; + for (i = 0; i < rpu_size; i++) { + meta_buf[5 + i] = (p[11 + i] & 0x0f) << 4; + meta_buf[5 + i] |= (p[12 + i] >> 4) & 0x0f; + } + rpu_size += 5; + } + *meta_len = rpu_size; + } + } else if (meta_type == OBU_METADATA_TYPE_HDR_CLL) { + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "hdr10 cll:\n"); + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "max_cll = %x\n", (p[0] << 8) | p[1]); + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "max_fall = %x\n", (p[2] << 8) | p[3]); + } else if (meta_type == OBU_METADATA_TYPE_HDR_MDCV) { + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "hdr10 primaries[r,g,b] = \n"); + for (i = 0; i < 3; i++) { + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, " %x, %x\n", + (p[i * 4] << 8) | p[i * 4 + 1], + (p[i * 4 + 2] << 8) | p[i * 4 + 3]); + } + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, + "white point = %x, %x\n", (p[12] << 8) | p[13], (p[14] << 8) | p[15]); + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, + "maxl = %x\n", (p[16] << 24) | (p[17] << 16) | (p[18] << 8) | p[19]); + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, + "minl = %x\n", (p[20] << 24) | (p[21] << 16) | (p[22] << 8) | p[23]); + } + break; + case OBU_TILE_LIST: + break; + case OBU_PADDING: + break; + default: + // Skip unrecognized OBUs + break; + } + + data += payload_size; + } + + return 0; +} + +static int vdec_write_nalu(struct vdec_av1_inst *inst, + u8 *buf, u32 size, u64 ts) +{ + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; + u8 *data = NULL; + u32 length = 0; + bool need_prefix = av1_need_prefix; + + if (need_prefix) { + u8 meta_buffer[1024] = {0}; + u32 meta_size = 0; + u8 *src = buf; + + data = vzalloc(size + 0x1000); + if (!data) + return -ENOMEM; + + parser_frame(0, src, src + size, data, &length, meta_buffer, &meta_size); + + if (length) + ret = vdec_vframe_write(vdec, data, length, ts, 0); + else + ret = -1; + + vfree(data); + } else { + ret = vdec_vframe_write(vdec, buf, size, ts, 0); + } + + return ret; +} + +static bool monitor_res_change(struct vdec_av1_inst *inst, u8 *buf, u32 size) +{ + int ret = -1; + u8 *p = buf; + int len = size; + u32 synccode = av1_need_prefix ? + ((p[1] << 16) | (p[2] << 8) | p[3]) : + ((p[17] << 16) | (p[18] << 8) | p[19]); + + if (synccode == SYNC_CODE) { + ret = parse_stream_cpu(inst, p, len); + if (!ret && (inst->vsi->cur_pic.coded_width != + inst->vsi->pic.coded_width || + inst->vsi->cur_pic.coded_height != + inst->vsi->pic.coded_height)) { + inst->vsi->cur_pic = inst->vsi->pic; + return true; + } + } + + return false; +} + +static int vdec_av1_decode(unsigned long h_vdec, + struct aml_vcodec_mem *bs, bool *res_chg) +{ + struct vdec_av1_inst *inst = (struct vdec_av1_inst *)h_vdec; + struct aml_vdec_adapt *vdec = &inst->vdec; + u8 *buf = (u8 *) bs->vaddr; + u32 size = bs->size; + int ret = -1; + + if (bs == NULL) + return -1; + + if (vdec_input_full(vdec)) { + return -EAGAIN; + } + + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if (s->magic != AML_VIDEO_MAGIC) + return -1; + + if (!inst->ctx->param_sets_from_ucode && + (s->type == V4L_STREAM_TYPE_MATEDATA)) { + if ((*res_chg = monitor_res_change(inst, + s->data, s->len))) + return 0; + } + + ret = vdec_vframe_write(vdec, + s->data, + s->len, + bs->timestamp, + 0); + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = vdec_vframe_write_with_dma(vdec, + bs->addr, size, bs->timestamp, + BUFF_IDX(bs, bs->index), + vdec_vframe_input_free, inst->ctx); + } + } else { + /*checked whether the resolution changes.*/ + 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); + } + + return ret; +} + + 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) { + /* 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) + parms->hdr = inst->parms.hdr; + if (inst->parms.parms_status & V4L2_CONFIG_PARM_DECODE_CNTINFO) + parms->cnt = inst->parms.cnt; + + parms->parms_status |= inst->parms.parms_status; + + 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) +{ + int ret = 0; + struct vdec_av1_inst *inst = (struct vdec_av1_inst *)h_vdec; + + if (!inst) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "the av1 inst of dec is invalid.\n"); + return -1; + } + + switch (type) { + case GET_PARAM_PIC_INFO: + get_pic_info(inst, out); + break; + + case GET_PARAM_DPB_SIZE: + get_dpb_size(inst, out); + break; + + case GET_PARAM_CROP_INFO: + get_crop_info(inst, out); + break; + + 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); + ret = -EINVAL; + } + + return ret; +} + +static void set_param_write_sync(struct vdec_av1_inst *inst) +{ + 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; + pic->visible_height = ps->visible_height; + + /* calc visible ares. */ + rect->left = 0; + rect->top = 0; + rect->width = pic->visible_width; + rect->height = pic->visible_height; + + /* config canvas size that be used for decoder. */ + pic->coded_width = ps->coded_width; + pic->coded_height = ps->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 |= + V4L2_CONFIG_PARM_DECODE_PSINFO; + + /*wake up*/ + complete(&inst->comp); + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + "Parse from ucode, visible(%d x %d), coded(%d x %d)\n", + ps->visible_width, ps->visible_height, + 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 (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_EXINFO, + "av1 set HDR infos\n"); + } +} + +static void set_param_post_event(struct vdec_av1_inst *inst, u32 *event) +{ + aml_vdec_dispatch_event(inst->ctx, *event); + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + "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) +{ + int ret = 0; + struct vdec_av1_inst *inst = (struct vdec_av1_inst *)h_vdec; + + if (!inst) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "the av1 inst of dec is invalid.\n"); + return -1; + } + + switch (type) { + 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_COMP_BUF_INFO: + set_param_comp_buf_info(inst, in); + break; + + case SET_PARAM_HDR_INFO: + set_param_hdr_info(inst, in); + break; + + 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); + ret = -EINVAL; + } + + return ret; +} + +static struct vdec_common_if vdec_av1_if = { + .init = vdec_av1_init, + .probe = vdec_av1_probe, + .decode = vdec_av1_decode, + .get_param = vdec_av1_get_param, + .set_param = vdec_av1_set_param, + .deinit = vdec_av1_deinit, +}; + +struct vdec_common_if *get_av1_dec_comm_if(void); + +struct vdec_common_if *get_av1_dec_comm_if(void) +{ + return &vdec_av1_if; +} +
diff --git a/drivers/amvdec_ports/decoder/vdec_h264_if.c b/drivers/amvdec_ports/decoder/vdec_h264_if.c new file mode 100644 index 0000000..911c91d --- /dev/null +++ b/drivers/amvdec_ports/decoder/vdec_h264_if.c
@@ -0,0 +1,1066 @@ +/* +* 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/module.h> +#include <linux/slab.h> +#include <linux/timer.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <uapi/linux/swab.h> + +#include "../vdec_drv_if.h" +#include "../aml_vcodec_util.h" +#include "../aml_vcodec_dec.h" +#include "../aml_vcodec_drv.h" +#include "../aml_vcodec_adapt.h" +#include "../vdec_drv_base.h" +#include "aml_h264_parser.h" +#include "../utils/common.h" + +/* h264 NALU type */ +#define NAL_NON_IDR_SLICE 0x01 +#define NAL_IDR_SLICE 0x05 +#define NAL_H264_SEI 0x06 +#define NAL_H264_SPS 0x07 +#define NAL_H264_PPS 0x08 +#define NAL_H264_AUD 0x09 + +#define AVC_NAL_TYPE(value) ((value) & 0x1F) + +#define BUF_PREDICTION_SZ (64 * 1024)//(32 * 1024) + +#define MB_UNIT_LEN 16 + +/* motion vector size (bytes) for every macro block */ +#define HW_MB_STORE_SZ 64 + +#define H264_MAX_FB_NUM 17 +#define HDR_PARSING_BUF_SZ 1024 + +#define HEADER_BUFFER_SIZE (128 * 1024) + +/** + * struct h264_fb - h264 decode frame buffer information + * @vdec_fb_va : virtual address of struct vdec_fb + * @y_fb_dma : dma address of Y frame buffer (luma) + * @c_fb_dma : dma address of C frame buffer (chroma) + * @poc : picture order count of frame buffer + * @reserved : for 8 bytes alignment + */ +struct h264_fb { + uint64_t vdec_fb_va; + uint64_t y_fb_dma; + uint64_t c_fb_dma; + int32_t poc; + uint32_t reserved; +}; + +/** + * struct h264_ring_fb_list - ring frame buffer list + * @fb_list : frame buffer arrary + * @read_idx : read index + * @write_idx : write index + * @count : buffer count in list + */ +struct h264_ring_fb_list { + struct h264_fb fb_list[H264_MAX_FB_NUM]; + unsigned int read_idx; + unsigned int write_idx; + unsigned int count; + unsigned int reserved; +}; + +/** + * struct vdec_h264_dec_info - decode information + * @dpb_sz : decoding picture buffer size + * @realloc_mv_buf : flag to notify driver to re-allocate mv buffer + * @reserved : for 8 bytes alignment + * @bs_dma : Input bit-stream buffer dma address + * @y_fb_dma : Y frame buffer dma address + * @c_fb_dma : C frame buffer dma address + * @vdec_fb_va : VDEC frame buffer struct virtual address + */ +struct vdec_h264_dec_info { + uint32_t dpb_sz; + uint32_t realloc_mv_buf; + uint32_t reserved; + uint64_t bs_dma; + uint64_t y_fb_dma; + uint64_t c_fb_dma; + uint64_t vdec_fb_va; +}; + +/** + * struct vdec_h264_vsi - shared memory for decode information exchange + * between VPU and Host. + * The memory is allocated by VPU then mapping to Host + * in vpu_dec_init() and freed in vpu_dec_deinit() + * by VPU. + * AP-W/R : AP is writer/reader on this item + * VPU-W/R: VPU is write/reader on this item + * @dec : decode information (AP-R, VPU-W) + * @pic : picture information (AP-R, VPU-W) + * @crop : crop information (AP-R, VPU-W) + */ +struct vdec_h264_vsi { + unsigned char hdr_buf[HDR_PARSING_BUF_SZ]; + char *header_buf; + int sps_size; + int pps_size; + int sei_size; + int head_offset; + struct vdec_h264_dec_info dec; + struct vdec_pic_info pic; + struct vdec_pic_info cur_pic; + struct v4l2_rect crop; + bool is_combine; + int nalu_pos; +}; + +/** + * struct vdec_h264_inst - h264 decoder instance + * @num_nalu : how many nalus be decoded + * @ctx : point to aml_vcodec_ctx + * @pred_buf : HW working predication buffer + * @mv_buf : HW working motion vector buffer + * @vpu : VPU instance + * @vsi : VPU shared information + */ +struct vdec_h264_inst { + unsigned int num_nalu; + struct aml_vcodec_ctx *ctx; + struct aml_vcodec_mem pred_buf; + struct aml_vcodec_mem mv_buf[H264_MAX_FB_NUM]; + struct aml_vdec_adapt vdec; + struct vdec_h264_vsi *vsi; + struct aml_dec_params parms; + struct completion comp; +}; + +#if 0 +#define DUMP_FILE_NAME "/data/dump/dump.tmp" +static struct file *filp; +static loff_t file_pos; + +void dump_write(const char __user *buf, size_t count) +{ + mm_segment_t old_fs; + + if (!filp) + return; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + if (count != vfs_write(filp, buf, count, &file_pos)) + pr_err("Failed to write file\n"); + + set_fs(old_fs); +} + +void dump_init(void) +{ + filp = filp_open(DUMP_FILE_NAME, O_CREAT | O_RDWR, 0644); + if (IS_ERR(filp)) { + pr_err("open dump file failed\n"); + filp = NULL; + } +} + +void dump_deinit(void) +{ + if (filp) { + filp_close(filp, current->files); + filp = NULL; + file_pos = 0; + } +} + +void swap_uv(void *uv, int size) +{ + int i; + __u16 *p = uv; + + size /= 2; + + for (i = 0; i < size; i++, p++) + *p = __swab16(*p); +} +#endif + +static void get_pic_info(struct vdec_h264_inst *inst, + struct vdec_pic_info *pic) +{ + *pic = inst->vsi->pic; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "pic(%d, %d), buf(%d, %d)\n", + pic->visible_width, pic->visible_height, + pic->coded_width, pic->coded_height); + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "Y(%d, %d), C(%d, %d)\n", pic->y_bs_sz, + pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz); +} + +static void get_crop_info(struct vdec_h264_inst *inst, struct v4l2_rect *cr) +{ + cr->left = inst->vsi->crop.left; + cr->top = inst->vsi->crop.top; + cr->width = inst->vsi->crop.width; + cr->height = inst->vsi->crop.height; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "l=%d, t=%d, w=%d, h=%d\n", + cr->left, cr->top, cr->width, cr->height); +} + +static void get_dpb_size(struct vdec_h264_inst *inst, unsigned int *dpb_sz) +{ + *dpb_sz = inst->vsi->dec.dpb_sz; + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "sz=%d\n", *dpb_sz); +} + +static void skip_aud_data(u8 **data, u32 *size) +{ + int i; + + i = find_start_code(*data, *size); + if (i > 0 && (*data)[i++] == 0x9 && (*data)[i++] == 0xf0) { + *size -= i; + *data += i; + } +} + +static u32 vdec_config_default_parms(u8 *parm) +{ + u8 *pbuf = parm; + + pbuf += sprintf(pbuf, "parm_v4l_codec_enable:1;"); + pbuf += sprintf(pbuf, "mh264_double_write_mode:16;"); + pbuf += sprintf(pbuf, "parm_v4l_buffer_margin:7;"); + pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_mode:0;"); + pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_endian:0;"); + + return parm - pbuf; +} + +static void vdec_parser_parms(struct vdec_h264_inst *inst) +{ + struct aml_vcodec_ctx *ctx = inst->ctx; + + if (ctx->config.parm.dec.parms_status & + V4L2_CONFIG_PARM_DECODE_CFGINFO) { + u8 *pbuf = ctx->config.buf; + + pbuf += sprintf(pbuf, "parm_v4l_codec_enable:1;"); + pbuf += sprintf(pbuf, "mh264_double_write_mode:%d;", + ctx->config.parm.dec.cfg.double_write_mode); + pbuf += sprintf(pbuf, "parm_v4l_buffer_margin:%d;", + ctx->config.parm.dec.cfg.ref_buf_margin); + pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_mode:%d;", + ctx->config.parm.dec.cfg.canvas_mem_mode); + pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_endian:%d;", + 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.ref_buf_margin = 7; + ctx->config.length = vdec_config_default_parms(ctx->config.buf); + } + + inst->vdec.config = ctx->config; + inst->parms.cfg = ctx->config.parm.dec.cfg; + inst->parms.parms_status |= V4L2_CONFIG_PARM_DECODE_CFGINFO; +} + +static int vdec_h264_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) +{ + struct vdec_h264_inst *inst = NULL; + int ret = -1; + + inst = vzalloc(sizeof(*inst)); + if (!inst) + return -ENOMEM; + + inst->vdec.frm_name = "H.264"; + inst->vdec.video_type = VFORMAT_H264; + inst->vdec.filp = ctx->dev->filp; + inst->vdec.ctx = ctx; + inst->ctx = ctx; + + vdec_parser_parms(inst); + + /* set play mode.*/ + if (ctx->is_drm_mode) + inst->vdec.port.flag |= PORT_FLAG_DRM; + + /* probe info from the stream */ + 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 = 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_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 (inst && inst->vsi && inst->vsi->header_buf) + vfree(inst->vsi->header_buf); + if (inst && inst->vsi) + vfree(inst->vsi); + if (inst) + vfree(inst); + *h_vdec = 0; + + return ret; +} + +#if 0 +static int refer_buffer_num(int level_idc, int max_poc_cnt, + int mb_width, int mb_height) +{ + int size; + int pic_size = mb_width * mb_height * 384; + + 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 more buffers */ + + if (size > max_poc_cnt) + size = max_poc_cnt; + + return size; +} +#endif + +static void vdec_config_dw_mode(struct vdec_pic_info *pic, int dw_mode) +{ + switch (dw_mode) { + case 0x1: /* (w x h) + (w/2 x h) */ + pic->coded_width += pic->coded_width >> 1; + pic->y_len_sz = pic->coded_width * pic->coded_height; + pic->c_len_sz = pic->y_len_sz >> 1; + break; + case 0x2: /* (w x h) + (w/2 x h/2) */ + pic->coded_width += pic->coded_width >> 1; + pic->coded_height += pic->coded_height >> 1; + pic->y_len_sz = pic->coded_width * pic->coded_height; + pic->c_len_sz = pic->y_len_sz >> 1; + break; + default: /* nothing to do */ + break; + } +} + +static void fill_vdec_params(struct vdec_h264_inst *inst, struct h264_SPS_t *sps) +{ + struct vdec_pic_info *pic = &inst->vsi->pic; + struct vdec_h264_dec_info *dec = &inst->vsi->dec; + struct v4l2_rect *rect = &inst->vsi->crop; + int dw = inst->parms.cfg.double_write_mode; + int margin = inst->parms.cfg.ref_buf_margin; + u32 mb_w, mb_h, width, height; + + mb_w = sps->mb_width; + mb_h = sps->mb_height; + + width = mb_w << 4; + height = mb_h << 4; + + width -= (sps->crop_left + sps->crop_right); + height -= (sps->crop_top + sps->crop_bottom); + + /* fill visible area size that be used for EGL. */ + pic->visible_width = width; + pic->visible_height = height; + + /* calc visible ares. */ + rect->left = 0; + rect->top = 0; + rect->width = pic->visible_width; + rect->height = pic->visible_height; + + /* config canvas size that be used for decoder. */ + pic->coded_width = ALIGN(mb_w, 4) << 4; + pic->coded_height = ALIGN(mb_h, 4) << 4; + 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; + /* calc DPB size */ + dec->dpb_sz = sps->num_reorder_frames + margin; + + inst->parms.ps.visible_width = pic->visible_width; + inst->parms.ps.visible_height = pic->visible_height; + inst->parms.ps.coded_width = pic->coded_width; + inst->parms.ps.coded_height = pic->coded_height; + inst->parms.ps.profile = sps->profile_idc; + 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.dpb_frames = sps->num_reorder_frames; + inst->parms.ps.dpb_size = dec->dpb_sz; + inst->parms.parms_status |= V4L2_CONFIG_PARM_DECODE_PSINFO; + + vdec_config_dw_mode(pic, dw); + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_BUFMGR, + "The stream infos, dw: %d, coded:(%d x %d), visible:(%d x %d), DPB: %d, margin: %d\n", + dw, pic->coded_width, pic->coded_height, + pic->visible_width, pic->visible_height, + dec->dpb_sz - margin, margin); +} + +static bool check_frame_combine(u8 *buf, u32 size, int *pos) +{ + bool combine = false; + int i = 0, j = 0, cnt = 0; + u8 *p = buf; + + for (i = 4; i < size; i++) { + j = find_start_code(p, 7); + if (j > 0) { + if (++cnt > 1) { + combine = true; + break; + } + + *pos = p - buf + j; + p += j; + i += j; + } + p++; + } + + //pr_info("nal pos: %d, is_combine: %d\n",*pos, *is_combine); + return combine; +} + +static int vdec_search_startcode(u8 *buf, u32 range) +{ + int pos = -1; + int i = 0, j = 0; + u8 *p = buf; + + for (i = 4; i < range; i++) { + j = find_start_code(p, 7); + if (j > 0) { + pos = p - buf + j; + break; + } + p++; + } + + return pos; +} + +static int parse_stream_ucode(struct vdec_h264_inst *inst, + u8 *buf, u32 size, u64 timestamp) +{ + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; + + 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); + return ret; + } + + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); + + return inst->vsi->pic.dpb_frames ? 0 : -1; +} + +static int parse_stream_ucode_dma(struct vdec_h264_inst *inst, + ulong buf, u32 size, u64 timestamp, u32 handle) +{ + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; + + ret = vdec_vframe_write_with_dma(vdec, buf, size, timestamp, handle, + vdec_vframe_input_free, inst->ctx); + if (ret < 0) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "write frame data failed. err: %d\n", ret); + return ret; + } + + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); + + return inst->vsi->pic.dpb_frames ? 0 : -1; +} + +static int parse_stream_cpu(struct vdec_h264_inst *inst, u8 *buf, u32 size) +{ + int ret = 0; + struct h264_param_sets *ps; + int nal_idx = 0; + bool is_combine = false; + + is_combine = check_frame_combine(buf, size, &nal_idx); + if (nal_idx < 0) + return -1; + + /* if the st compose from csd + slice that is the combine data. */ + inst->vsi->is_combine = is_combine; + inst->vsi->nalu_pos = nal_idx; + + ps = vzalloc(sizeof(struct h264_param_sets)); + if (ps == NULL) + return -ENOMEM; + + ret = h264_decode_extradata_ps(buf, size, ps); + if (ret) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "parse extra data failed. err: %d\n", ret); + goto out; + } + + if (ps->sps_parsed) + fill_vdec_params(inst, &ps->sps); + + ret = ps->sps_parsed ? 0 : -1; +out: + vfree(ps); + + return ret; +} + +static int vdec_h264_probe(unsigned long h_vdec, + struct aml_vcodec_mem *bs, void *out) +{ + struct vdec_h264_inst *inst = + (struct vdec_h264_inst *)h_vdec; + u8 *buf = (u8 *) bs->vaddr; + u32 size = bs->size; + int ret = 0; + + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if ((s->magic != AML_VIDEO_MAGIC) && + (s->type != V4L_STREAM_TYPE_MATEDATA)) + return -1; + + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, s->data, + s->len, bs->timestamp); + } else { + skip_aud_data((u8 **)&s->data, &s->len); + ret = parse_stream_cpu(inst, s->data, s->len); + } + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = parse_stream_ucode_dma(inst, bs->addr, size, + bs->timestamp, BUFF_IDX(bs, bs->index)); + } + } else { + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, buf, size, bs->timestamp); + } else { + skip_aud_data(&buf, &size); + ret = parse_stream_cpu(inst, buf, size); + } + } + + inst->vsi->cur_pic = inst->vsi->pic; + + return ret; +} + +static void vdec_h264_deinit(unsigned long h_vdec) +{ + struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec; + struct aml_vcodec_ctx *ctx = inst->ctx; + + video_decoder_release(&inst->vdec); + + if (inst->vsi && inst->vsi->header_buf) + vfree(inst->vsi->header_buf); + + if (inst->vsi) + vfree(inst->vsi); + + vfree(inst); + + ctx->drv_handle = 0; +} + +static int vdec_write_nalu(struct vdec_h264_inst *inst, + u8 *buf, u32 size, u64 ts) +{ + int ret = -1; + struct aml_vdec_adapt *vdec = &inst->vdec; + bool is_combine = inst->vsi->is_combine; + int nalu_pos; + u32 nal_type; + + /*print_hex_debug(buf, size, 32);*/ + + nalu_pos = vdec_search_startcode(buf, 16); + if (nalu_pos < 0) + goto err; + + nal_type = AVC_NAL_TYPE(buf[nalu_pos]); + //v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, "NALU type: %d, size: %u\n", nal_type, size); + + if (nal_type == NAL_H264_SPS && !is_combine) { + if (inst->vsi->head_offset + size > HEADER_BUFFER_SIZE) { + ret = -EILSEQ; + goto err; + } + inst->vsi->sps_size = size; + memcpy(inst->vsi->header_buf + inst->vsi->head_offset, buf, size); + inst->vsi->head_offset += inst->vsi->sps_size; + ret = size; + } else if (nal_type == NAL_H264_PPS && !is_combine) { + //buf_sz -= nal_start_idx; + if (inst->vsi->head_offset + size > HEADER_BUFFER_SIZE) { + ret = -EILSEQ; + goto err; + } + inst->vsi->pps_size = size; + memcpy(inst->vsi->header_buf + inst->vsi->head_offset, buf, size); + inst->vsi->head_offset += inst->vsi->pps_size; + ret = size; + } else if (nal_type == NAL_H264_SEI && !is_combine) { + if (inst->vsi->head_offset + size > HEADER_BUFFER_SIZE) { + ret = -EILSEQ; + goto err; + } + inst->vsi->sei_size = size; + memcpy(inst->vsi->header_buf + inst->vsi->head_offset, buf, size); + 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, 0); + } else { + char *write_buf = vmalloc(inst->vsi->head_offset + size); + if (!write_buf) { + ret = -ENOMEM; + goto err; + } + + memcpy(write_buf, inst->vsi->header_buf, inst->vsi->head_offset); + memcpy(write_buf + inst->vsi->head_offset, buf, size); + + ret = vdec_vframe_write(vdec, write_buf, + inst->vsi->head_offset + size, ts, 0); + + memset(inst->vsi->header_buf, 0, HEADER_BUFFER_SIZE); + inst->vsi->head_offset = 0; + inst->vsi->sps_size = 0; + inst->vsi->pps_size = 0; + inst->vsi->sei_size = 0; + + vfree(write_buf); + } + + return ret; +err: + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "err(%d)", ret); + return ret; +} + +static bool monitor_res_change(struct vdec_h264_inst *inst, u8 *buf, u32 size) +{ + int ret = 0, i = 0, j = 0; + u8 *p = buf; + int len = size; + u32 type; + + for (i = 4; i < size; i++) { + j = find_start_code(p, len); + if (j > 0) { + len = size - (p - buf); + type = AVC_NAL_TYPE(p[j]); + if (type != NAL_H264_AUD && + (type > NAL_H264_PPS || type < NAL_H264_SEI)) + break; + + if (type == NAL_H264_SPS) { + ret = parse_stream_cpu(inst, p, len); + if (ret) + break; + } + p += j; + } + p++; + } + + if (!ret && ((inst->vsi->cur_pic.coded_width != + inst->vsi->pic.coded_width || + inst->vsi->cur_pic.coded_height != + inst->vsi->pic.coded_height) || + (inst->vsi->pic.profile_idc != + 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; + } + + return false; +} + +static int vdec_h264_decode(unsigned long h_vdec, + struct aml_vcodec_mem *bs, bool *res_chg) +{ + struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec; + struct aml_vdec_adapt *vdec = &inst->vdec; + u8 *buf = (u8 *) bs->vaddr; + u32 size = bs->size; + int ret = -1; + + if (bs == NULL) + return -1; + + if (vdec_input_full(vdec)) + return -EAGAIN; + + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if (s->magic != AML_VIDEO_MAGIC) + return -1; + + if (!inst->ctx->param_sets_from_ucode && + (s->type == V4L_STREAM_TYPE_MATEDATA)) { + if ((*res_chg = monitor_res_change(inst, + s->data, s->len))) + return 0; + } + + ret = vdec_vframe_write(vdec, + s->data, + s->len, + bs->timestamp, + 0); + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = vdec_vframe_write_with_dma(vdec, + bs->addr, size, bs->timestamp, + BUFF_IDX(bs, bs->index), + vdec_vframe_input_free, inst->ctx); + } + } else { + if (inst->ctx->param_sets_from_ucode) { + int nal_idx = 0; + /* if the st compose from csd + slice that is the combine data. */ + inst->vsi->is_combine = check_frame_combine(buf, size, &nal_idx); + /*if (nal_idx < 0) + return -1;*/ + } else { + /*checked whether the resolution changes.*/ + if ((*res_chg = monitor_res_change(inst, buf, size))) { + return 0; + } + } + ret = vdec_write_nalu(inst, buf, size, bs->timestamp); + } + + return ret; +} + +static void get_param_config_info(struct vdec_h264_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_PSINFO) + parms->ps = inst->parms.ps; + if (inst->parms.parms_status & V4L2_CONFIG_PARM_DECODE_HDRINFO) + parms->hdr = inst->parms.hdr; + if (inst->parms.parms_status & V4L2_CONFIG_PARM_DECODE_CNTINFO) + parms->cnt = inst->parms.cnt; + + 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_h264_get_param(unsigned long h_vdec, + enum vdec_get_param_type type, void *out) +{ + int ret = 0; + struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec; + + if (!inst) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "the h264 inst of dec is invalid.\n"); + return -1; + } + + switch (type) { + case GET_PARAM_PIC_INFO: + get_pic_info(inst, out); + break; + + case GET_PARAM_DPB_SIZE: + get_dpb_size(inst, out); + break; + + case GET_PARAM_CROP_INFO: + 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 = 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); + ret = -EINVAL; + } + + return ret; +} + +static void set_param_write_sync(struct vdec_h264_inst *inst) +{ + complete(&inst->comp); +} + +static void set_param_ps_info(struct vdec_h264_inst *inst, + struct aml_vdec_ps_infos *ps) +{ + struct vdec_pic_info *pic = &inst->vsi->pic; + struct vdec_h264_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; + pic->visible_height = ps->visible_height; + + /* calc visible ares. */ + rect->left = 0; + rect->top = 0; + rect->width = pic->visible_width; + rect->height = pic->visible_height; + + /* config canvas size that be used for decoder. */ + 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 >> 1; + pic->profile_idc = ps->profile; + 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; + inst->parms.parms_status |= + V4L2_CONFIG_PARM_DECODE_PSINFO; + + vdec_config_dw_mode(pic, dw); + + /*wake up*/ + complete(&inst->comp); + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + "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, + ps->field == V4L2_FIELD_NONE ? "P" : "I"); +} + +static void set_param_hdr_info(struct vdec_h264_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, + "H264 set HDR infos\n"); + } +} + +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); + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + "H264 post event: %d\n", *event); +} + +static int vdec_h264_set_param(unsigned long h_vdec, + enum vdec_set_param_type type, void *in) +{ + int ret = 0; + struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec; + + if (!inst) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "the h264 inst of dec is invalid.\n"); + return -1; + } + + switch (type) { + 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_HDR_INFO: + set_param_hdr_info(inst, in); + break; + + 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); + ret = -EINVAL; + } + + return ret; +} + +static struct vdec_common_if vdec_h264_if = { + .init = vdec_h264_init, + .probe = vdec_h264_probe, + .decode = vdec_h264_decode, + .get_param = vdec_h264_get_param, + .set_param = vdec_h264_set_param, + .deinit = vdec_h264_deinit, +}; + +struct vdec_common_if *get_h264_dec_comm_if(void); + +struct vdec_common_if *get_h264_dec_comm_if(void) +{ + return &vdec_h264_if; +}
diff --git a/drivers/amvdec_ports/decoder/vdec_hevc_if.c b/drivers/amvdec_ports/decoder/vdec_hevc_if.c new file mode 100644 index 0000000..56d492a --- /dev/null +++ b/drivers/amvdec_ports/decoder/vdec_hevc_if.c
@@ -0,0 +1,866 @@ +/* +* 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/module.h> +#include <linux/slab.h> +#include <linux/timer.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <uapi/linux/swab.h> +#include "../vdec_drv_if.h" +#include "../aml_vcodec_util.h" +#include "../aml_vcodec_dec.h" +#include "../aml_vcodec_drv.h" +#include "../aml_vcodec_adapt.h" +#include "../vdec_drv_base.h" +#include "aml_hevc_parser.h" + +#define HEVC_NAL_TYPE(value) ((value >> 1) & 0x3F) +#define HEADER_BUFFER_SIZE (32 * 1024) + +/** + * struct hevc_fb - hevc decode frame buffer information + * @vdec_fb_va : virtual address of struct vdec_fb + * @y_fb_dma : dma address of Y frame buffer (luma) + * @c_fb_dma : dma address of C frame buffer (chroma) + * @poc : picture order count of frame buffer + * @reserved : for 8 bytes alignment + */ +struct hevc_fb { + uint64_t vdec_fb_va; + uint64_t y_fb_dma; + uint64_t c_fb_dma; + int32_t poc; + uint32_t reserved; +}; + +/** + * struct vdec_hevc_dec_info - decode information + * @dpb_sz : decoding picture buffer size + * @resolution_changed : resoltion change happen + * @reserved : for 8 bytes alignment + * @bs_dma : Input bit-stream buffer dma address + * @y_fb_dma : Y frame buffer dma address + * @c_fb_dma : C frame buffer dma address + * @vdec_fb_va : VDEC frame buffer struct virtual address + */ +struct vdec_hevc_dec_info { + uint32_t dpb_sz; + uint32_t resolution_changed; + uint32_t reserved; + uint64_t bs_dma; + uint64_t y_fb_dma; + uint64_t c_fb_dma; + uint64_t vdec_fb_va; +}; + +/** + * struct vdec_hevc_vsi - shared memory for decode information exchange + * between VPU and Host. + * The memory is allocated by VPU then mapping to Host + * in vpu_dec_init() and freed in vpu_dec_deinit() + * by VPU. + * AP-W/R : AP is writer/reader on this item + * VPU-W/R: VPU is write/reader on this item + * @hdr_buf : Header parsing buffer (AP-W, VPU-R) + * @list_free : free frame buffer ring list (AP-W/R, VPU-W) + * @list_disp : display frame buffer ring list (AP-R, VPU-W) + * @dec : decode information (AP-R, VPU-W) + * @pic : picture information (AP-R, VPU-W) + * @crop : crop information (AP-R, VPU-W) + */ +struct vdec_hevc_vsi { + char *header_buf; + int sps_size; + int pps_size; + int sei_size; + int head_offset; + struct vdec_hevc_dec_info dec; + struct vdec_pic_info pic; + struct vdec_pic_info cur_pic; + struct v4l2_rect crop; + bool is_combine; + int nalu_pos; + struct h265_param_sets ps; +}; + +/** + * struct vdec_hevc_inst - hevc decoder instance + * @num_nalu : how many nalus be decoded + * @ctx : point to aml_vcodec_ctx + * @vsi : VPU shared information + */ +struct vdec_hevc_inst { + unsigned int num_nalu; + struct aml_vcodec_ctx *ctx; + struct aml_vdec_adapt vdec; + struct vdec_hevc_vsi *vsi; + 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, + struct vdec_pic_info *pic) +{ + *pic = inst->vsi->pic; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "pic(%d, %d), buf(%d, %d)\n", + pic->visible_width, pic->visible_height, + pic->coded_width, pic->coded_height); + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "Y(%d, %d), C(%d, %d)\n", pic->y_bs_sz, + pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz); +} + +static void get_crop_info(struct vdec_hevc_inst *inst, struct v4l2_rect *cr) +{ + cr->left = inst->vsi->crop.left; + cr->top = inst->vsi->crop.top; + cr->width = inst->vsi->crop.width; + cr->height = inst->vsi->crop.height; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "l=%d, t=%d, w=%d, h=%d\n", + cr->left, cr->top, cr->width, cr->height); +} + +static void get_dpb_size(struct vdec_hevc_inst *inst, unsigned int *dpb_sz) +{ + *dpb_sz = inst->vsi->dec.dpb_sz; + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "sz=%d\n", *dpb_sz); +} + +static u32 vdec_config_default_parms(u8 *parm) +{ + u8 *pbuf = parm; + + pbuf += sprintf(pbuf, "parm_v4l_codec_enable:1;"); + pbuf += sprintf(pbuf, "parm_v4l_buffer_margin:7;"); + 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;"); + pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_mode:0;"); + pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_endian:0;"); + + return parm - pbuf; +} + +static void vdec_parser_parms(struct vdec_hevc_inst *inst) +{ + struct aml_vcodec_ctx *ctx = inst->ctx; + + if (ctx->config.parm.dec.parms_status & + V4L2_CONFIG_PARM_DECODE_CFGINFO) { + u8 *pbuf = ctx->config.buf; + + pbuf += sprintf(pbuf, "parm_v4l_codec_enable:1;"); + pbuf += sprintf(pbuf, "parm_v4l_buffer_margin:%d;", + ctx->config.parm.dec.cfg.ref_buf_margin); + pbuf += sprintf(pbuf, "hevc_double_write_mode:%d;", + ctx->config.parm.dec.cfg.double_write_mode); + pbuf += sprintf(pbuf, "hevc_buf_width:4096;"); + pbuf += sprintf(pbuf, "hevc_buf_height:2304;"); + pbuf += sprintf(pbuf, "save_buffer_mode:0;"); + pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_mode:%d;", + ctx->config.parm.dec.cfg.canvas_mem_mode); + pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_endian:%d;", + 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 = 1; + ctx->config.parm.dec.cfg.ref_buf_margin = 7; + ctx->config.length = vdec_config_default_parms(ctx->config.buf); + } + + inst->vdec.config = ctx->config; + inst->parms.cfg = ctx->config.parm.dec.cfg; + inst->parms.parms_status |= V4L2_CONFIG_PARM_DECODE_CFGINFO; +} + +static int vdec_hevc_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) +{ + struct vdec_hevc_inst *inst = NULL; + int ret = -1; + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + inst->vdec.frm_name = "H.265"; + inst->vdec.video_type = VFORMAT_HEVC; + inst->vdec.filp = ctx->dev->filp; + inst->vdec.ctx = ctx; + inst->ctx = ctx; + + vdec_parser_parms(inst); + + /* set play mode.*/ + if (ctx->is_drm_mode) + inst->vdec.port.flag |= PORT_FLAG_DRM; + + /* to eable hevc hw.*/ + inst->vdec.port.type = PORT_TYPE_HEVC; + + /* probe info from the stream */ + inst->vsi = kzalloc(sizeof(struct vdec_hevc_vsi), GFP_KERNEL); + if (!inst->vsi) { + ret = -ENOMEM; + goto err; + } + + /* alloc the header buffer to be used cache sps or spp etc.*/ + 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_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 (inst && inst->vsi && inst->vsi->header_buf) + vfree(inst->vsi->header_buf); + if (inst && inst->vsi) + kfree(inst->vsi); + if (inst) + kfree(inst); + *h_vdec = 0; + + return ret; +} + + +static int refer_buffer_num(struct h265_SPS_t *sps) +{ + int used_buf_num = 0; + int sps_pic_buf_diff = 0; + + if ((!sps->temporal_layer[0].num_reorder_pics) && + (sps->temporal_layer[0].max_dec_pic_buffering)) { + /* the range of sps_num_reorder_pics_0 is in + [0, sps_max_dec_pic_buffering_minus1_0] */ + used_buf_num = sps->temporal_layer[0].max_dec_pic_buffering; + } else + used_buf_num = sps->temporal_layer[0].num_reorder_pics; + + sps_pic_buf_diff = sps->temporal_layer[0].max_dec_pic_buffering - + sps->temporal_layer[0].num_reorder_pics - 1; + + if (sps_pic_buf_diff >= 4) + used_buf_num += 1; + + /*need one more for multi instance, as + apply_ref_pic_set() has no chanch to run to + to clear referenced flag in some case */ + used_buf_num++; + + /* for eos add more buffer to flush.*/ + used_buf_num++; + + return used_buf_num; +} + +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->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_hevc_inst *inst, int length, int dw_mode) +{ + int ret = 64; + + switch (vdec_get_dw_mode(inst, dw_mode)) { + case 0x0: /* 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 fill_vdec_params(struct vdec_hevc_inst *inst, struct h265_SPS_t *sps) +{ + 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; + int margin = inst->parms.cfg.ref_buf_margin; + + /* fill visible area size that be used for EGL. */ + pic->visible_width = sps->width - (sps->output_window.left_offset + + sps->output_window.right_offset); + pic->visible_height = sps->height - (sps->output_window.top_offset + + sps->output_window.bottom_offset); + pic->visible_width = vdec_pic_scale(inst, pic->visible_width, dw); + pic->visible_height = vdec_pic_scale(inst, pic->visible_height, dw); + + /* calc visible ares. */ + rect->left = 0; + rect->top = 0; + rect->width = pic->visible_width; + rect->height = pic->visible_height; + + /* config canvas size that be used for decoder. */ + pic->coded_width = vdec_pic_scale(inst, ALIGN(sps->width, 32), dw); + pic->coded_height = vdec_pic_scale(inst, ALIGN(sps->height, 32), dw); + + pic->y_len_sz = pic->coded_width * pic->coded_height; + pic->c_len_sz = pic->y_len_sz >> 1; + + /* calc DPB size */ + dec->dpb_sz = refer_buffer_num(sps) + margin; + + inst->parms.ps.visible_width = pic->visible_width; + inst->parms.ps.visible_height = pic->visible_height; + inst->parms.ps.coded_width = pic->coded_width; + inst->parms.ps.coded_height = pic->coded_height; + inst->parms.ps.dpb_size = dec->dpb_sz; + inst->parms.parms_status |= V4L2_CONFIG_PARM_DECODE_PSINFO; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_BUFMGR, + "The stream infos, dw: %d, coded:(%d x %d), visible:(%d x %d), DPB: %d, margin: %d\n", + dw, pic->coded_width, pic->coded_height, + pic->visible_width, pic->visible_height, + dec->dpb_sz - margin, margin); +} + +static int parse_stream_ucode(struct vdec_hevc_inst *inst, + u8 *buf, u32 size, u64 timestamp) +{ + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; + + 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); + return ret; + } + + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); + + return inst->vsi->pic.dpb_frames ? 0 : -1; +} + +static int parse_stream_ucode_dma(struct vdec_hevc_inst *inst, + ulong buf, u32 size, u64 timestamp, u32 handle) +{ + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; + + ret = vdec_vframe_write_with_dma(vdec, buf, size, timestamp, handle, + vdec_vframe_input_free, inst->ctx); + if (ret < 0) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "write frame data failed. err: %d\n", ret); + return ret; + } + + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); + + return inst->vsi->pic.dpb_frames ? 0 : -1; +} + +static int parse_stream_cpu(struct vdec_hevc_inst *inst, u8 *buf, u32 size) +{ + int ret = 0; + struct h265_param_sets *ps = NULL; + + ps = vzalloc(sizeof(struct h265_param_sets)); + if (ps == NULL) + return -ENOMEM; + + ret = h265_decode_extradata_ps(buf, size, ps); + if (ret) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "parse extra data failed. err: %d\n", ret); + goto out; + } + + if (ps->sps_parsed) + fill_vdec_params(inst, &ps->sps); + + ret = ps->sps_parsed ? 0 : -1; +out: + vfree(ps); + + return ret; +} + +static int vdec_hevc_probe(unsigned long h_vdec, + struct aml_vcodec_mem *bs, void *out) +{ + struct vdec_hevc_inst *inst = + (struct vdec_hevc_inst *)h_vdec; + u8 *buf = (u8 *)bs->vaddr; + u32 size = bs->size; + int ret = 0; + + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if ((s->magic != AML_VIDEO_MAGIC) && + (s->type != V4L_STREAM_TYPE_MATEDATA)) + return -1; + + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, s->data, + s->len, bs->timestamp); + } else { + ret = parse_stream_cpu(inst, s->data, s->len); + } + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = parse_stream_ucode_dma(inst, bs->addr, size, + bs->timestamp, BUFF_IDX(bs, bs->index)); + } + } else { + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, buf, size, bs->timestamp); + } else { + ret = parse_stream_cpu(inst, buf, size); + } + } + + inst->vsi->cur_pic = inst->vsi->pic; + + return ret; +} + +static void vdec_hevc_deinit(unsigned long h_vdec) +{ + struct vdec_hevc_inst *inst = (struct vdec_hevc_inst *)h_vdec; + struct aml_vcodec_ctx *ctx = inst->ctx; + + video_decoder_release(&inst->vdec); + + if (inst->vsi && inst->vsi->header_buf) + vfree(inst->vsi->header_buf); + + if (inst->vsi) + kfree(inst->vsi); + + kfree(inst); + + ctx->drv_handle = 0; +} + +static int vdec_write_nalu(struct vdec_hevc_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, 0); + + return ret; +} + +static bool monitor_res_change(struct vdec_hevc_inst *inst, u8 *buf, u32 size) +{ + int ret = 0, i = 0, j = 0; + u8 *p = buf; + int len = size; + u32 type; + + for (i = 4; i < size; i++) { + j = find_start_code(p, len); + if (j > 0) { + len = size - (p - buf); + type = HEVC_NAL_TYPE(p[j]); + if (type != HEVC_NAL_AUD && + (type > HEVC_NAL_PPS || type < HEVC_NAL_VPS)) + break; + + if (type == HEVC_NAL_SPS) { + ret = parse_stream_cpu(inst, p, len); + if (ret) + break; + } + p += j; + } + p++; + } + + if (!ret && (inst->vsi->cur_pic.coded_width != + inst->vsi->pic.coded_width || + inst->vsi->cur_pic.coded_height != + inst->vsi->pic.coded_height)) { + inst->vsi->cur_pic = inst->vsi->pic; + return true; + } + + return false; +} + +static int vdec_hevc_decode(unsigned long h_vdec, + struct aml_vcodec_mem *bs, bool *res_chg) +{ + struct vdec_hevc_inst *inst = (struct vdec_hevc_inst *)h_vdec; + struct aml_vdec_adapt *vdec = &inst->vdec; + u8 *buf = (u8 *) bs->vaddr; + u32 size = bs->size; + int ret = -1; + + if (bs == NULL) + return -1; + + if (vdec_input_full(vdec)) + return -EAGAIN; + + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if (s->magic != AML_VIDEO_MAGIC) + return -1; + + if (!inst->ctx->param_sets_from_ucode && + (s->type == V4L_STREAM_TYPE_MATEDATA)) { + if ((*res_chg = monitor_res_change(inst, + s->data, s->len))) + return 0; + } + + ret = vdec_vframe_write(vdec, + s->data, + s->len, + bs->timestamp, + 0); + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = vdec_vframe_write_with_dma(vdec, + bs->addr, size, bs->timestamp, + BUFF_IDX(bs, bs->index), + vdec_vframe_input_free, inst->ctx); + } + } else { + if (!inst->ctx->param_sets_from_ucode) { + /*checked whether the resolution changes.*/ + if ((*res_chg = monitor_res_change(inst, buf, size))) + return 0; + } + ret = vdec_write_nalu(inst, buf, size, bs->timestamp); + } + + return ret; +} + + static void get_param_config_info(struct vdec_hevc_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_PSINFO) + parms->ps = inst->parms.ps; + if (inst->parms.parms_status & V4L2_CONFIG_PARM_DECODE_HDRINFO) + parms->hdr = inst->parms.hdr; + if (inst->parms.parms_status & V4L2_CONFIG_PARM_DECODE_CNTINFO) + parms->cnt = inst->parms.cnt; + + parms->parms_status |= inst->parms.parms_status; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + "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) +{ + int ret = 0; + struct vdec_hevc_inst *inst = (struct vdec_hevc_inst *)h_vdec; + + if (!inst) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "the hevc inst of dec is invalid.\n"); + return -1; + } + + switch (type) { + case GET_PARAM_PIC_INFO: + get_pic_info(inst, out); + break; + + case GET_PARAM_DPB_SIZE: + get_dpb_size(inst, out); + break; + + case GET_PARAM_CROP_INFO: + get_crop_info(inst, out); + break; + + 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); + ret = -EINVAL; + } + + return ret; +} + +static void set_param_write_sync(struct vdec_hevc_inst *inst) +{ + complete(&inst->comp); +} + +static void set_param_ps_info(struct vdec_hevc_inst *inst, + struct aml_vdec_ps_infos *ps) +{ + 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; + pic->visible_height = ps->visible_height; + + /* calc visible ares. */ + rect->left = 0; + rect->top = 0; + rect->width = pic->visible_width; + rect->height = pic->visible_height; + + /* config canvas size that be used for decoder. */ + + pic->coded_width = ps->coded_width; + pic->coded_height = ps->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; + + inst->parms.ps = *ps; + inst->parms.parms_status |= + V4L2_CONFIG_PARM_DECODE_PSINFO; + + /*wake up*/ + complete(&inst->comp); + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + "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, + 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) +{ + 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, + "H265 set HDR infos\n"); + } +} + +static void set_param_post_event(struct vdec_hevc_inst *inst, u32 *event) +{ + aml_vdec_dispatch_event(inst->ctx, *event); + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + "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) +{ + int ret = 0; + struct vdec_hevc_inst *inst = (struct vdec_hevc_inst *)h_vdec; + + if (!inst) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "the hevc inst of dec is invalid.\n"); + return -1; + } + + switch (type) { + case SET_PARAM_WRITE_FRAME_SYNC: + 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; + + 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); + ret = -EINVAL; + } + + return ret; +} + +static struct vdec_common_if vdec_hevc_if = { + .init = vdec_hevc_init, + .probe = vdec_hevc_probe, + .decode = vdec_hevc_decode, + .get_param = vdec_hevc_get_param, + .set_param = vdec_hevc_set_param, + .deinit = vdec_hevc_deinit, +}; + +struct vdec_common_if *get_hevc_dec_comm_if(void); + +struct vdec_common_if *get_hevc_dec_comm_if(void) +{ + return &vdec_hevc_if; +}
diff --git a/drivers/amvdec_ports/decoder/vdec_mjpeg_if.c b/drivers/amvdec_ports/decoder/vdec_mjpeg_if.c new file mode 100644 index 0000000..8332956 --- /dev/null +++ b/drivers/amvdec_ports/decoder/vdec_mjpeg_if.c
@@ -0,0 +1,620 @@ +/* +* 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/module.h> +#include <linux/slab.h> +#include <linux/timer.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <uapi/linux/swab.h> +#include "../vdec_drv_if.h" +#include "../aml_vcodec_util.h" +#include "../aml_vcodec_dec.h" +#include "../aml_vcodec_adapt.h" +#include "../vdec_drv_base.h" +#include "aml_mjpeg_parser.h" +#include <media/v4l2-mem2mem.h> + +#define NAL_TYPE(value) ((value) & 0x1F) +#define HEADER_BUFFER_SIZE (32 * 1024) + +/** + * struct mjpeg_fb - mjpeg decode frame buffer information + * @vdec_fb_va : virtual address of struct vdec_fb + * @y_fb_dma : dma address of Y frame buffer (luma) + * @c_fb_dma : dma address of C frame buffer (chroma) + * @poc : picture order count of frame buffer + * @reserved : for 8 bytes alignment + */ +struct mjpeg_fb { + uint64_t vdec_fb_va; + uint64_t y_fb_dma; + uint64_t c_fb_dma; + int32_t poc; + uint32_t reserved; +}; + +/** + * struct vdec_mjpeg_dec_info - decode information + * @dpb_sz : decoding picture buffer size + * @resolution_changed : resoltion change happen + * @reserved : for 8 bytes alignment + * @bs_dma : Input bit-stream buffer dma address + * @y_fb_dma : Y frame buffer dma address + * @c_fb_dma : C frame buffer dma address + * @vdec_fb_va : VDEC frame buffer struct virtual address + */ +struct vdec_mjpeg_dec_info { + uint32_t dpb_sz; + uint32_t resolution_changed; + uint32_t reserved; + uint64_t bs_dma; + uint64_t y_fb_dma; + uint64_t c_fb_dma; + uint64_t vdec_fb_va; +}; + +/** + * struct vdec_mjpeg_vsi - shared memory for decode information exchange + * between VPU and Host. + * The memory is allocated by VPU then mapping to Host + * in vpu_dec_init() and freed in vpu_dec_deinit() + * by VPU. + * AP-W/R : AP is writer/reader on this item + * VPU-W/R: VPU is write/reader on this item + * @hdr_buf : Header parsing buffer (AP-W, VPU-R) + * @list_free : free frame buffer ring list (AP-W/R, VPU-W) + * @list_disp : display frame buffer ring list (AP-R, VPU-W) + * @dec : decode information (AP-R, VPU-W) + * @pic : picture information (AP-R, VPU-W) + * @crop : crop information (AP-R, VPU-W) + */ +struct vdec_mjpeg_vsi { + char *header_buf; + int sps_size; + int pps_size; + int sei_size; + int head_offset; + struct vdec_mjpeg_dec_info dec; + struct vdec_pic_info pic; + struct vdec_pic_info cur_pic; + struct v4l2_rect crop; + bool is_combine; + int nalu_pos; + //struct mjpeg_param_sets ps; +}; + +/** + * struct vdec_mjpeg_inst - mjpeg decoder instance + * @num_nalu : how many nalus be decoded + * @ctx : point to aml_vcodec_ctx + * @vsi : VPU shared information + */ +struct vdec_mjpeg_inst { + unsigned int num_nalu; + struct aml_vcodec_ctx *ctx; + struct aml_vdec_adapt vdec; + struct vdec_mjpeg_vsi *vsi; + struct aml_dec_params parms; + struct completion comp; +}; + +static void get_pic_info(struct vdec_mjpeg_inst *inst, + struct vdec_pic_info *pic) +{ + *pic = inst->vsi->pic; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "pic(%d, %d), buf(%d, %d)\n", + pic->visible_width, pic->visible_height, + pic->coded_width, pic->coded_height); + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "Y(%d, %d), C(%d, %d)\n", + pic->y_bs_sz, pic->y_len_sz, + pic->c_bs_sz, pic->c_len_sz); +} + +static void get_crop_info(struct vdec_mjpeg_inst *inst, struct v4l2_rect *cr) +{ + cr->left = inst->vsi->crop.left; + cr->top = inst->vsi->crop.top; + cr->width = inst->vsi->crop.width; + cr->height = inst->vsi->crop.height; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "l=%d, t=%d, w=%d, h=%d\n", + cr->left, cr->top, cr->width, cr->height); +} + +static void get_dpb_size(struct vdec_mjpeg_inst *inst, unsigned int *dpb_sz) +{ + *dpb_sz = inst->vsi->dec.dpb_sz; + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "sz=%d\n", *dpb_sz); +} + +static u32 vdec_config_default_parms(u8 *parm) +{ + u8 *pbuf = parm; + + 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; +} + +static void vdec_parser_parms(struct vdec_mjpeg_inst *inst) +{ + struct aml_vcodec_ctx *ctx = inst->ctx; + + if (ctx->config.parm.dec.parms_status & + V4L2_CONFIG_PARM_DECODE_CFGINFO) { + u8 *pbuf = ctx->config.buf; + + pbuf += sprintf(pbuf, "parm_v4l_codec_enable:1;"); + pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_mode:%d;", + 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_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); + } + + inst->vdec.config = ctx->config; + inst->parms.cfg = ctx->config.parm.dec.cfg; + inst->parms.parms_status |= V4L2_CONFIG_PARM_DECODE_CFGINFO; +} + + +static int vdec_mjpeg_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) +{ + struct vdec_mjpeg_inst *inst = NULL; + int ret = -1; + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + inst->vdec.frm_name = "MJPEG"; + inst->vdec.video_type = VFORMAT_MJPEG; + inst->vdec.filp = ctx->dev->filp; + inst->vdec.config = ctx->config; + inst->vdec.ctx = ctx; + inst->ctx = ctx; + + vdec_parser_parms(inst); + /* set play mode.*/ + if (ctx->is_drm_mode) + inst->vdec.port.flag |= PORT_FLAG_DRM; + + /* to eable mjpeg hw.*/ + inst->vdec.port.type = PORT_TYPE_VIDEO; + + /* probe info from the stream */ + inst->vsi = kzalloc(sizeof(struct vdec_mjpeg_vsi), GFP_KERNEL); + if (!inst->vsi) { + ret = -ENOMEM; + goto err; + } + + /* alloc the header buffer to be used cache sps or spp etc.*/ + 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); + + return 0; + +err: + if (inst && inst->vsi && inst->vsi->header_buf) + vfree(inst->vsi->header_buf); + if (inst && inst->vsi) + kfree(inst->vsi); + if (inst) + kfree(inst); + *h_vdec = 0; + + return ret; +} + +#if 0 +static int refer_buffer_num(int level_idc, int poc_cnt, + int mb_width, int mb_height) +{ + return 20; +} +#endif + +static void fill_vdec_params(struct vdec_mjpeg_inst *inst, + struct MJpegDecodeContext *ps) +{ + struct vdec_pic_info *pic = &inst->vsi->pic; + struct vdec_mjpeg_dec_info *dec = &inst->vsi->dec; + struct v4l2_rect *rect = &inst->vsi->crop; + + /* fill visible area size that be used for EGL. */ + pic->visible_width = ps->width; + pic->visible_height = ps->height; + + /* calc visible ares. */ + rect->left = 0; + rect->top = 0; + rect->width = pic->visible_width; + rect->height = pic->visible_height; + + /* config canvas size that be used for decoder. */ + pic->coded_width = ALIGN(ps->width, 64); + pic->coded_height = ALIGN(ps->height, 64); + + pic->y_len_sz = pic->coded_width * pic->coded_height; + pic->c_len_sz = pic->y_len_sz; + + /*8(DECODE_BUFFER_NUM_DEF) */ + dec->dpb_sz = 8; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_BUFMGR, + "The stream infos, coded:(%d x %d), visible:(%d x %d)\n", + pic->coded_width, pic->coded_height, + pic->visible_width, pic->visible_height); +} + +static int parse_stream_ucode(struct vdec_mjpeg_inst *inst, + u8 *buf, u32 size, u64 timestamp) +{ + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; + + 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); + return ret; + } + + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); + + return inst->vsi->pic.dpb_frames ? 0 : -1; +} + +static int parse_stream_ucode_dma(struct vdec_mjpeg_inst *inst, + ulong buf, u32 size, u64 timestamp, u32 handle) +{ + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; + + ret = vdec_vframe_write_with_dma(vdec, buf, size, timestamp, handle, + vdec_vframe_input_free, inst->ctx); + if (ret < 0) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "write frame data failed. err: %d\n", ret); + return ret; + } + + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); + + return inst->vsi->pic.dpb_frames ? 0 : -1; +} + +static int parse_stream_cpu(struct vdec_mjpeg_inst *inst, u8 *buf, u32 size) +{ + int ret = 0; + struct mjpeg_param_sets *ps = NULL; + + ps = kzalloc(sizeof(struct mjpeg_param_sets), GFP_KERNEL); + if (ps == NULL) + return -ENOMEM; + + ret = mjpeg_decode_extradata_ps(buf, size, ps); + if (ret) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "parse extra data failed. err: %d\n", ret); + goto out; + } + + if (ps->head_parsed) + fill_vdec_params(inst, &ps->dec_ps); + + ret = ps->head_parsed ? 0 : -1; +out: + kfree(ps); + + return ret; +} + +static int vdec_mjpeg_probe(unsigned long h_vdec, + struct aml_vcodec_mem *bs, void *out) +{ + struct vdec_mjpeg_inst *inst = + (struct vdec_mjpeg_inst *)h_vdec; + u8 *buf = (u8 *)bs->vaddr; + u32 size = bs->size; + int ret = 0; + + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if ((s->magic != AML_VIDEO_MAGIC) && + (s->type != V4L_STREAM_TYPE_MATEDATA)) + return -1; + + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, s->data, + s->len, bs->timestamp); + } else { + ret = parse_stream_cpu(inst, s->data, s->len); + } + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = parse_stream_ucode_dma(inst, bs->addr, size, + bs->timestamp, BUFF_IDX(bs, bs->index)); + } + } else { + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, buf, size, bs->timestamp); + } else { + ret = parse_stream_cpu(inst, buf, size); + } + } + + inst->vsi->cur_pic = inst->vsi->pic; + + return ret; +} + +static void vdec_mjpeg_deinit(unsigned long h_vdec) +{ + struct vdec_mjpeg_inst *inst = (struct vdec_mjpeg_inst *)h_vdec; + + if (!inst) + return; + + video_decoder_release(&inst->vdec); + + if (inst->vsi && inst->vsi->header_buf) + vfree(inst->vsi->header_buf); + + if (inst->vsi) + kfree(inst->vsi); + + kfree(inst); +} + +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, 0); + + return ret; +} + +static int vdec_mjpeg_decode(unsigned long h_vdec, + struct aml_vcodec_mem *bs, bool *res_chg) +{ + struct vdec_mjpeg_inst *inst = (struct vdec_mjpeg_inst *)h_vdec; + struct aml_vdec_adapt *vdec = &inst->vdec; + u8 *buf = (u8 *) bs->vaddr; + u32 size = bs->size; + int ret = -1; + + if (vdec_input_full(vdec)) + return -EAGAIN; + + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if (s->magic != AML_VIDEO_MAGIC) + return -1; + + ret = vdec_vframe_write(vdec, + s->data, + s->len, + bs->timestamp, + 0); + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = vdec_vframe_write_with_dma(vdec, + bs->addr, size, bs->timestamp, + BUFF_IDX(bs, bs->index), + vdec_vframe_input_free, inst->ctx); + } + } else { + ret = vdec_write_nalu(inst, buf, size, bs->timestamp); + } + + return ret; +} + +static int vdec_mjpeg_get_param(unsigned long h_vdec, + enum vdec_get_param_type type, void *out) +{ + int ret = 0; + struct vdec_mjpeg_inst *inst = (struct vdec_mjpeg_inst *)h_vdec; + + if (!inst) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "the mjpeg inst of dec is invalid.\n"); + return -1; + } + + switch (type) { + case GET_PARAM_PIC_INFO: + get_pic_info(inst, out); + break; + + case GET_PARAM_DPB_SIZE: + get_dpb_size(inst, out); + break; + + 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_ERROR, + "invalid get parameter type=%d\n", type); + ret = -EINVAL; + } + + return ret; +} + +static void set_param_ps_info(struct vdec_mjpeg_inst *inst, + struct aml_vdec_ps_infos *ps) +{ + struct vdec_pic_info *pic = &inst->vsi->pic; + struct vdec_mjpeg_dec_info *dec = &inst->vsi->dec; + struct v4l2_rect *rect = &inst->vsi->crop; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, "%s in\n", __func__); + /* fill visible area size that be used for EGL. */ + pic->visible_width = ps->visible_width; + pic->visible_height = ps->visible_height; + + /* calc visible ares. */ + rect->left = 0; + rect->top = 0; + rect->width = pic->visible_width; + rect->height = pic->visible_height; + + /* config canvas size that be used for decoder. */ + 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 >> 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 |= + V4L2_CONFIG_PARM_DECODE_PSINFO; + + /*wake up*/ + complete(&inst->comp); + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + "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, + pic->field == V4L2_FIELD_NONE ? "P" : "I"); +} + +static void set_param_write_sync(struct vdec_mjpeg_inst *inst) +{ + 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) +{ + int ret = 0; + struct vdec_mjpeg_inst *inst = (struct vdec_mjpeg_inst *)h_vdec; + + if (!inst) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "the mjpeg inst of dec is invalid.\n"); + return -1; + } + + switch (type) { + 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); + ret = -EINVAL; + } + + return ret; +} + +static struct vdec_common_if vdec_mjpeg_if = { + .init = vdec_mjpeg_init, + .probe = vdec_mjpeg_probe, + .decode = vdec_mjpeg_decode, + .get_param = vdec_mjpeg_get_param, + .set_param = vdec_mjpeg_set_param, + .deinit = vdec_mjpeg_deinit, +}; + +struct vdec_common_if *get_mjpeg_dec_comm_if(void); + +struct vdec_common_if *get_mjpeg_dec_comm_if(void) +{ + return &vdec_mjpeg_if; +}
diff --git a/drivers/amvdec_ports/decoder/vdec_mpeg12_if.c b/drivers/amvdec_ports/decoder/vdec_mpeg12_if.c new file mode 100644 index 0000000..2472ac1 --- /dev/null +++ b/drivers/amvdec_ports/decoder/vdec_mpeg12_if.c
@@ -0,0 +1,645 @@ +/* +* 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/module.h> +#include <linux/slab.h> +#include <linux/timer.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <uapi/linux/swab.h> +#include "../vdec_drv_if.h" +#include "../aml_vcodec_util.h" +#include "../aml_vcodec_dec.h" +#include "../aml_vcodec_adapt.h" +#include "../vdec_drv_base.h" +#include "aml_mpeg12_parser.h" + +#define NAL_TYPE(value) ((value) & 0x1F) +#define HEADER_BUFFER_SIZE (32 * 1024) + +/** + * struct mpeg12_fb - mpeg12 decode frame buffer information + * @vdec_fb_va : virtual address of struct vdec_fb + * @y_fb_dma : dma address of Y frame buffer (luma) + * @c_fb_dma : dma address of C frame buffer (chroma) + * @poc : picture order count of frame buffer + * @reserved : for 8 bytes alignment + */ +struct mpeg12_fb { + uint64_t vdec_fb_va; + uint64_t y_fb_dma; + uint64_t c_fb_dma; + int32_t poc; + uint32_t reserved; +}; + +/** + * struct vdec_mpeg12_dec_info - decode information + * @dpb_sz : decoding picture buffer size + * @resolution_changed : resoltion change happen + * @reserved : for 8 bytes alignment + * @bs_dma : Input bit-stream buffer dma address + * @y_fb_dma : Y frame buffer dma address + * @c_fb_dma : C frame buffer dma address + * @vdec_fb_va : VDEC frame buffer struct virtual address + */ +struct vdec_mpeg12_dec_info { + uint32_t dpb_sz; + uint32_t resolution_changed; + uint32_t reserved; + uint64_t bs_dma; + uint64_t y_fb_dma; + uint64_t c_fb_dma; + uint64_t vdec_fb_va; +}; + +/** + * struct vdec_mpeg12_vsi - shared memory for decode information exchange + * between VPU and Host. + * The memory is allocated by VPU then mapping to Host + * in vpu_dec_init() and freed in vpu_dec_deinit() + * by VPU. + * AP-W/R : AP is writer/reader on this item + * VPU-W/R: VPU is write/reader on this item + * @hdr_buf : Header parsing buffer (AP-W, VPU-R) + * @list_free : free frame buffer ring list (AP-W/R, VPU-W) + * @list_disp : display frame buffer ring list (AP-R, VPU-W) + * @dec : decode information (AP-R, VPU-W) + * @pic : picture information (AP-R, VPU-W) + * @crop : crop information (AP-R, VPU-W) + */ +struct vdec_mpeg12_vsi { + char *header_buf; + int sps_size; + int pps_size; + int sei_size; + int head_offset; + struct vdec_mpeg12_dec_info dec; + struct vdec_pic_info pic; + struct vdec_pic_info cur_pic; + struct v4l2_rect crop; + bool is_combine; + int nalu_pos; + //struct mpeg12_param_sets ps; +}; + +/** + * struct vdec_mpeg12_inst - mpeg12 decoder instance + * @num_nalu : how many nalus be decoded + * @ctx : point to aml_vcodec_ctx + * @vsi : VPU shared information + */ +struct vdec_mpeg12_inst { + unsigned int num_nalu; + struct aml_vcodec_ctx *ctx; + struct aml_vdec_adapt vdec; + struct vdec_mpeg12_vsi *vsi; + struct aml_dec_params parms; + struct completion comp; +}; + +static void get_pic_info(struct vdec_mpeg12_inst *inst, + struct vdec_pic_info *pic) +{ + *pic = inst->vsi->pic; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "pic(%d, %d), buf(%d, %d)\n", + pic->visible_width, pic->visible_height, + pic->coded_width, pic->coded_height); + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "Y(%d, %d), C(%d, %d)\n", + pic->y_bs_sz, pic->y_len_sz, + pic->c_bs_sz, pic->c_len_sz); +} + +static void get_crop_info(struct vdec_mpeg12_inst *inst, struct v4l2_rect *cr) +{ + cr->left = inst->vsi->crop.left; + cr->top = inst->vsi->crop.top; + cr->width = inst->vsi->crop.width; + cr->height = inst->vsi->crop.height; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "l=%d, t=%d, w=%d, h=%d\n", + cr->left, cr->top, cr->width, cr->height); +} + +static void get_dpb_size(struct vdec_mpeg12_inst *inst, unsigned int *dpb_sz) +{ + *dpb_sz = inst->vsi->dec.dpb_sz; + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "sz=%d\n", *dpb_sz); +} + +static u32 vdec_config_default_parms(u8 *parm) +{ + u8 *pbuf = parm; + + 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;"); + + return pbuf - parm; +} + +static void vdec_parser_parms(struct vdec_mpeg12_inst *inst) +{ + struct aml_vcodec_ctx *ctx = inst->ctx; + + if (ctx->config.parm.dec.parms_status & + V4L2_CONFIG_PARM_DECODE_CFGINFO) { + u8 *pbuf = ctx->config.buf; + + pbuf += sprintf(pbuf, "parm_v4l_codec_enable:1;"); + pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_mode:%d;", + 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); + } + + inst->vdec.config = ctx->config; + inst->parms.cfg = ctx->config.parm.dec.cfg; + inst->parms.parms_status |= V4L2_CONFIG_PARM_DECODE_CFGINFO; +} + +static int vdec_mpeg12_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) +{ + struct vdec_mpeg12_inst *inst = NULL; + int ret = -1; + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + inst->vdec.frm_name = "MPEG2"; + inst->vdec.video_type = VFORMAT_MPEG12; + inst->vdec.filp = ctx->dev->filp; + inst->vdec.config = ctx->config; + inst->vdec.ctx = ctx; + inst->ctx = ctx; + + vdec_parser_parms(inst); + + /* set play mode.*/ + if (ctx->is_drm_mode) + inst->vdec.port.flag |= PORT_FLAG_DRM; + + /* to eable mpeg12 hw.*/ + inst->vdec.port.type = PORT_TYPE_VIDEO; + + /* probe info from the stream */ + inst->vsi = kzalloc(sizeof(struct vdec_mpeg12_vsi), GFP_KERNEL); + if (!inst->vsi) { + ret = -ENOMEM; + goto err; + } + + /* alloc the header buffer to be used cache sps or spp etc.*/ + 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_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 (inst && inst->vsi && inst->vsi->header_buf) + vfree(inst->vsi->header_buf); + if (inst && inst->vsi) + kfree(inst->vsi); + if (inst) + kfree(inst); + *h_vdec = 0; + + return ret; +} + +static void fill_vdec_params(struct vdec_mpeg12_inst *inst, + struct MpvParseContext *dec_ps) +{ + struct vdec_pic_info *pic = &inst->vsi->pic; + struct vdec_mpeg12_dec_info *dec = &inst->vsi->dec; + struct v4l2_rect *rect = &inst->vsi->crop; + + /* fill visible area size that be used for EGL. */ + pic->visible_width = dec_ps->width; + pic->visible_height = dec_ps->height; + + /* calc visible ares. */ + rect->left = 0; + rect->top = 0; + rect->width = pic->visible_width; + rect->height = pic->visible_height; + + /* config canvas size that be used for decoder. */ + pic->coded_width = ALIGN(dec_ps->coded_width, 64); + pic->coded_height = ALIGN(dec_ps->coded_height, 32); + + pic->y_len_sz = pic->coded_width * pic->coded_height; + pic->c_len_sz = pic->y_len_sz >> 1; + + /*7(parm_v4l_buffer_margin) + 8(DECODE_BUFFER_NUM_DEF)*/ + dec->dpb_sz = 15; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_BUFMGR, + "The stream infos, coded:(%d x %d), visible:(%d x %d), DPB: %d\n", + pic->coded_width, pic->coded_height, + pic->visible_width, pic->visible_height, dec->dpb_sz); +} + +static int parse_stream_ucode(struct vdec_mpeg12_inst *inst, + u8 *buf, u32 size, u64 timestamp) +{ + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; + + 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); + return ret; + } + + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); + + return inst->vsi->pic.dpb_frames ? 0 : -1; +} + +static int parse_stream_ucode_dma(struct vdec_mpeg12_inst *inst, + ulong buf, u32 size, u64 timestamp, u32 handle) +{ + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; + + ret = vdec_vframe_write_with_dma(vdec, buf, size, timestamp, handle, + vdec_vframe_input_free, inst->ctx); + if (ret < 0) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "write frame data failed. err: %d\n", ret); + return ret; + } + + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); + + return inst->vsi->pic.dpb_frames ? 0 : -1; +} + +static int parse_stream_cpu(struct vdec_mpeg12_inst *inst, u8 *buf, u32 size) +{ + int ret = 0; + struct mpeg12_param_sets *ps = NULL; + + ps = kzalloc(sizeof(struct mpeg12_param_sets), GFP_KERNEL); + if (ps == NULL) + return -ENOMEM; + + ret = mpeg12_decode_extradata_ps(buf, size, ps); + if (ret) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "parse extra data failed. err: %d\n", ret); + goto out; + } + + if (ps->head_parsed) + fill_vdec_params(inst, &ps->dec_ps); + + ret = ps->head_parsed ? 0 : -1; +out: + kfree(ps); + + return ret; +} + +static int vdec_mpeg12_probe(unsigned long h_vdec, + struct aml_vcodec_mem *bs, void *out) +{ + struct vdec_mpeg12_inst *inst = + (struct vdec_mpeg12_inst *)h_vdec; + u8 *buf = (u8 *)bs->vaddr; + u32 size = bs->size; + int ret = 0; + + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if ((s->magic != AML_VIDEO_MAGIC) && + (s->type != V4L_STREAM_TYPE_MATEDATA)) + return -1; + + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, s->data, + s->len, bs->timestamp); + } else { + ret = parse_stream_cpu(inst, s->data, s->len); + } + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = parse_stream_ucode_dma(inst, bs->addr, size, + bs->timestamp, BUFF_IDX(bs, bs->index)); + } + } else { + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, buf, size, bs->timestamp); + } else { + ret = parse_stream_cpu(inst, buf, size); + } + } + + inst->vsi->cur_pic = inst->vsi->pic; + + return ret; +} + +static void vdec_mpeg12_deinit(unsigned long h_vdec) +{ + struct vdec_mpeg12_inst *inst = (struct vdec_mpeg12_inst *)h_vdec; + + if (!inst) + return; + + video_decoder_release(&inst->vdec); + + if (inst->vsi && inst->vsi->header_buf) + vfree(inst->vsi->header_buf); + + if (inst->vsi) + kfree(inst->vsi); + + kfree(inst); +} + +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, 0); + + return ret; +} + +static int vdec_mpeg12_decode(unsigned long h_vdec, + struct aml_vcodec_mem *bs, bool *res_chg) +{ + struct vdec_mpeg12_inst *inst = (struct vdec_mpeg12_inst *)h_vdec; + struct aml_vdec_adapt *vdec = &inst->vdec; + u8 *buf = (u8 *) bs->vaddr; + u32 size = bs->size; + int ret = -1; + + if (vdec_input_full(vdec)) + return -EAGAIN; + + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if (s->magic != AML_VIDEO_MAGIC) + return -1; + + ret = vdec_vframe_write(vdec, + s->data, + s->len, + bs->timestamp, + 0); + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = vdec_vframe_write_with_dma(vdec, + bs->addr, size, bs->timestamp, + BUFF_IDX(bs, bs->index), + vdec_vframe_input_free, inst->ctx); + } + } else { + ret = vdec_write_nalu(inst, buf, size, bs->timestamp); + } + + 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) +{ + int ret = 0; + struct vdec_mpeg12_inst *inst = (struct vdec_mpeg12_inst *)h_vdec; + + if (!inst) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "the mpeg12 inst of dec is invalid.\n"); + return -1; + } + + switch (type) { + case GET_PARAM_PIC_INFO: + get_pic_info(inst, out); + break; + + case GET_PARAM_DPB_SIZE: + get_dpb_size(inst, out); + break; + + case GET_PARAM_CROP_INFO: + 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); + ret = -EINVAL; + } + + return ret; +} + +static void set_param_write_sync(struct vdec_mpeg12_inst *inst) +{ + 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) +{ + struct vdec_pic_info *pic = &inst->vsi->pic; + struct vdec_mpeg12_dec_info *dec = &inst->vsi->dec; + struct v4l2_rect *rect = &inst->vsi->crop; + + /* fill visible area size that be used for EGL. */ + pic->visible_width = ps->visible_width; + pic->visible_height = ps->visible_height; + + /* calc visible ares. */ + rect->left = 0; + rect->top = 0; + rect->width = pic->visible_width; + rect->height = pic->visible_height; + + /* config canvas size that be used for decoder. */ + 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 >> 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 |= + V4L2_CONFIG_PARM_DECODE_PSINFO; + + /*wake up*/ + complete(&inst->comp); + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + "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, + 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) +{ + int ret = 0; + struct vdec_mpeg12_inst *inst = (struct vdec_mpeg12_inst *)h_vdec; + + if (!inst) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "the mpeg12 inst of dec is invalid.\n"); + return -1; + } + + switch (type) { + 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); + ret = -EINVAL; + } + + return ret; +} + +static struct vdec_common_if vdec_mpeg12_if = { + .init = vdec_mpeg12_init, + .probe = vdec_mpeg12_probe, + .decode = vdec_mpeg12_decode, + .get_param = vdec_mpeg12_get_param, + .set_param = vdec_mpeg12_set_param, + .deinit = vdec_mpeg12_deinit, +}; + +struct vdec_common_if *get_mpeg12_dec_comm_if(void); + +struct vdec_common_if *get_mpeg12_dec_comm_if(void) +{ + return &vdec_mpeg12_if; +}
diff --git a/drivers/amvdec_ports/decoder/vdec_mpeg4_if.c b/drivers/amvdec_ports/decoder/vdec_mpeg4_if.c new file mode 100644 index 0000000..bc0af24 --- /dev/null +++ b/drivers/amvdec_ports/decoder/vdec_mpeg4_if.c
@@ -0,0 +1,615 @@ +/* +* 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/module.h> +#include <linux/slab.h> +#include <linux/timer.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <uapi/linux/swab.h> +#include "../vdec_drv_if.h" +#include "../aml_vcodec_util.h" +#include "../aml_vcodec_dec.h" +#include "../aml_vcodec_adapt.h" +#include "../vdec_drv_base.h" +#include "aml_mpeg4_parser.h" + +#define NAL_TYPE(value) ((value) & 0x1F) +#define HEADER_BUFFER_SIZE (32 * 1024) + +/** + * struct mpeg4_fb - mpeg4 decode frame buffer information + * @vdec_fb_va : virtual address of struct vdec_fb + * @y_fb_dma : dma address of Y frame buffer (luma) + * @c_fb_dma : dma address of C frame buffer (chroma) + * @poc : picture order count of frame buffer + * @reserved : for 8 bytes alignment + */ +struct mpeg4_fb { + uint64_t vdec_fb_va; + uint64_t y_fb_dma; + uint64_t c_fb_dma; + int32_t poc; + uint32_t reserved; +}; + +/** + * struct vdec_mpeg4_dec_info - decode information + * @dpb_sz : decoding picture buffer size + * @resolution_changed : resoltion change happen + * @reserved : for 8 bytes alignment + * @bs_dma : Input bit-stream buffer dma address + * @y_fb_dma : Y frame buffer dma address + * @c_fb_dma : C frame buffer dma address + * @vdec_fb_va : VDEC frame buffer struct virtual address + */ +struct vdec_mpeg4_dec_info { + uint32_t dpb_sz; + uint32_t resolution_changed; + uint32_t reserved; + uint64_t bs_dma; + uint64_t y_fb_dma; + uint64_t c_fb_dma; + uint64_t vdec_fb_va; +}; + +/** + * struct vdec_mpeg4_vsi - shared memory for decode information exchange + * between VPU and Host. + * The memory is allocated by VPU then mapping to Host + * in vpu_dec_init() and freed in vpu_dec_deinit() + * by VPU. + * AP-W/R : AP is writer/reader on this item + * VPU-W/R: VPU is write/reader on this item + * @hdr_buf : Header parsing buffer (AP-W, VPU-R) + * @list_free : free frame buffer ring list (AP-W/R, VPU-W) + * @list_disp : display frame buffer ring list (AP-R, VPU-W) + * @dec : decode information (AP-R, VPU-W) + * @pic : picture information (AP-R, VPU-W) + * @crop : crop information (AP-R, VPU-W) + */ +struct vdec_mpeg4_vsi { + char *header_buf; + int sps_size; + int pps_size; + int sei_size; + int head_offset; + struct vdec_mpeg4_dec_info dec; + struct vdec_pic_info pic; + struct vdec_pic_info cur_pic; + struct v4l2_rect crop; + bool is_combine; + int nalu_pos; + //struct mpeg4ParamSets ps; +}; + +/** + * struct vdec_mpeg4_inst - mpeg4 decoder instance + * @num_nalu : how many nalus be decoded + * @ctx : point to aml_vcodec_ctx + * @vsi : VPU shared information + */ +struct vdec_mpeg4_inst { + unsigned int num_nalu; + struct aml_vcodec_ctx *ctx; + struct aml_vdec_adapt vdec; + struct vdec_mpeg4_vsi *vsi; + struct aml_dec_params parms; + struct completion comp; +}; + +static void get_pic_info(struct vdec_mpeg4_inst *inst, + struct vdec_pic_info *pic) +{ + *pic = inst->vsi->pic; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "pic(%d, %d), buf(%d, %d)\n", + pic->visible_width, pic->visible_height, + pic->coded_width, pic->coded_height); + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "Y(%d, %d), C(%d, %d)\n", + pic->y_bs_sz, pic->y_len_sz, + pic->c_bs_sz, pic->c_len_sz); +} + +static void get_crop_info(struct vdec_mpeg4_inst *inst, struct v4l2_rect *cr) +{ + cr->left = inst->vsi->crop.left; + cr->top = inst->vsi->crop.top; + cr->width = inst->vsi->crop.width; + cr->height = inst->vsi->crop.height; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "l=%d, t=%d, w=%d, h=%d\n", + cr->left, cr->top, cr->width, cr->height); +} + +static void get_dpb_size(struct vdec_mpeg4_inst *inst, unsigned int *dpb_sz) +{ + *dpb_sz = inst->vsi->dec.dpb_sz; + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "sz=%d\n", *dpb_sz); +} + +static u32 vdec_config_default_parms(u8 *parm) +{ + u8 *pbuf = parm; + + 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;"); + + return pbuf - parm; +} + +static void vdec_parser_parms(struct vdec_mpeg4_inst *inst) +{ + struct aml_vcodec_ctx *ctx = inst->ctx; + + if (ctx->config.parm.dec.parms_status & + V4L2_CONFIG_PARM_DECODE_CFGINFO) { + u8 *pbuf = ctx->config.buf; + + pbuf += sprintf(pbuf, "parm_v4l_codec_enable:1;"); + pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_mode:%d;", + 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); + } + + inst->vdec.config = ctx->config; + inst->parms.cfg = ctx->config.parm.dec.cfg; + inst->parms.parms_status |= V4L2_CONFIG_PARM_DECODE_CFGINFO; +} + + +static int vdec_mpeg4_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) +{ + struct vdec_mpeg4_inst *inst = NULL; + int ret = -1; + + 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.filp = ctx->dev->filp; + inst->vdec.config = ctx->config; + inst->vdec.ctx = ctx; + inst->ctx = ctx; + + vdec_parser_parms(inst); + /* set play mode.*/ + if (ctx->is_drm_mode) + inst->vdec.port.flag |= PORT_FLAG_DRM; + + /* to eable mpeg4 hw.*/ + inst->vdec.port.type = PORT_TYPE_VIDEO; + + /* probe info from the stream */ + inst->vsi = kzalloc(sizeof(struct vdec_mpeg4_vsi), GFP_KERNEL); + if (!inst->vsi) { + ret = -ENOMEM; + goto err; + } + + /* alloc the header buffer to be used cache sps or spp etc.*/ + 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); + + return 0; + +err: + if (inst && inst->vsi && inst->vsi->header_buf) + vfree(inst->vsi->header_buf); + if (inst && inst->vsi) + kfree(inst->vsi); + if (inst) + kfree(inst); + *h_vdec = 0; + + return ret; +} + +#if 0 +static int refer_buffer_num(int level_idc, int poc_cnt, + int mb_width, int mb_height) +{ + return 20; +} +#endif + +static void fill_vdec_params(struct vdec_mpeg4_inst *inst, + struct mpeg4_dec_param *dec_ps) +{ + struct vdec_pic_info *pic = &inst->vsi->pic; + struct vdec_mpeg4_dec_info *dec = &inst->vsi->dec; + struct v4l2_rect *rect = &inst->vsi->crop; + + /* fill visible area size that be used for EGL. */ + pic->visible_width = dec_ps->m.width; + pic->visible_height = dec_ps->m.height; + + /* calc visible ares. */ + rect->left = 0; + rect->top = 0; + rect->width = pic->visible_width; + rect->height = pic->visible_height; + + /* config canvas size that be used for decoder. */ + pic->coded_width = ALIGN(dec_ps->m.width, 64); + pic->coded_height = ALIGN(dec_ps->m.height, 64); + + pic->y_len_sz = pic->coded_width * pic->coded_height; + pic->c_len_sz = pic->y_len_sz >> 1; + + /*8(DECODE_BUFFER_NUM_DEF) */ + 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", + pic->coded_width, pic->coded_height, + pic->visible_width, pic->visible_height, dec->dpb_sz); +} + +static int parse_stream_ucode(struct vdec_mpeg4_inst *inst, + u8 *buf, u32 size, u64 timestamp) +{ + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; + + 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); + return ret; + } + + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); + + return inst->vsi->pic.dpb_frames ? 0 : -1; +} + +static int parse_stream_ucode_dma(struct vdec_mpeg4_inst *inst, + ulong buf, u32 size, u64 timestamp, u32 handle) +{ + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; + + ret = vdec_vframe_write_with_dma(vdec, buf, size, timestamp, handle, + vdec_vframe_input_free, inst->ctx); + if (ret < 0) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "write frame data failed. err: %d\n", ret); + return ret; + } + + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); + + return inst->vsi->pic.dpb_frames ? 0 : -1; +} + +static int parse_stream_cpu(struct vdec_mpeg4_inst *inst, u8 *buf, u32 size) +{ + int ret = 0; + struct mpeg4_param_sets *ps = NULL; + + ps = kzalloc(sizeof(struct mpeg4_param_sets), GFP_KERNEL); + if (ps == NULL) + return -ENOMEM; + + ret = mpeg4_decode_extradata_ps(buf, size, ps); + if (ret) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "parse extra data failed. err: %d\n", ret); + goto out; + } + + if (ps->head_parsed) + fill_vdec_params(inst, &ps->dec_ps); + + ret = ps->head_parsed ? 0 : -1; +out: + kfree(ps); + + return ret; +} + +static int vdec_mpeg4_probe(unsigned long h_vdec, + struct aml_vcodec_mem *bs, void *out) +{ + struct vdec_mpeg4_inst *inst = + (struct vdec_mpeg4_inst *)h_vdec; + u8 *buf = (u8 *)bs->vaddr; + u32 size = bs->size; + int ret = 0; + + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if ((s->magic != AML_VIDEO_MAGIC) && + (s->type != V4L_STREAM_TYPE_MATEDATA)) + return -1; + + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, s->data, + s->len, bs->timestamp); + } else { + ret = parse_stream_cpu(inst, s->data, s->len); + } + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = parse_stream_ucode_dma(inst, bs->addr, size, + bs->timestamp, BUFF_IDX(bs, bs->index)); + } + } else { + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, buf, size, bs->timestamp); + } else { + ret = parse_stream_cpu(inst, buf, size); + } + } + + inst->vsi->cur_pic = inst->vsi->pic; + + return ret; +} + +static void vdec_mpeg4_deinit(unsigned long h_vdec) +{ + struct vdec_mpeg4_inst *inst = (struct vdec_mpeg4_inst *)h_vdec; + + if (!inst) + return; + + video_decoder_release(&inst->vdec); + + if (inst->vsi && inst->vsi->header_buf) + vfree(inst->vsi->header_buf); + + if (inst->vsi) + kfree(inst->vsi); + + kfree(inst); +} + +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, 0); + + return ret; +} + +static int vdec_mpeg4_decode(unsigned long h_vdec, + struct aml_vcodec_mem *bs, bool *res_chg) +{ + struct vdec_mpeg4_inst *inst = (struct vdec_mpeg4_inst *)h_vdec; + struct aml_vdec_adapt *vdec = &inst->vdec; + u8 *buf = (u8 *) bs->vaddr; + u32 size = bs->size; + int ret = -1; + + if (vdec_input_full(vdec)) + return -EAGAIN; + + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if (s->magic != AML_VIDEO_MAGIC) + return -1; + + ret = vdec_vframe_write(vdec, + s->data, + s->len, + bs->timestamp, + 0); + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = vdec_vframe_write_with_dma(vdec, + bs->addr, size, bs->timestamp, + BUFF_IDX(bs, bs->index), + vdec_vframe_input_free, inst->ctx); + } + } else { + ret = vdec_write_nalu(inst, buf, size, bs->timestamp); + } + + return ret; +} + +static int vdec_mpeg4_get_param(unsigned long h_vdec, + enum vdec_get_param_type type, void *out) +{ + int ret = 0; + struct vdec_mpeg4_inst *inst = (struct vdec_mpeg4_inst *)h_vdec; + + if (!inst) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "the mpeg4 inst of dec is invalid.\n"); + return -1; + } + + switch (type) { + case GET_PARAM_PIC_INFO: + get_pic_info(inst, out); + break; + + case GET_PARAM_DPB_SIZE: + get_dpb_size(inst, out); + break; + + 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, + "invalid get parameter type=%d\n", type); + ret = -EINVAL; + } + + return ret; +} + +static void set_param_ps_info(struct vdec_mpeg4_inst *inst, + struct aml_vdec_ps_infos *ps) +{ + struct vdec_pic_info *pic = &inst->vsi->pic; + struct vdec_mpeg4_dec_info *dec = &inst->vsi->dec; + struct v4l2_rect *rect = &inst->vsi->crop; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, "%s in\n", __func__); + /* fill visible area size that be used for EGL. */ + pic->visible_width = ps->visible_width; + pic->visible_height = ps->visible_height; + + /* calc visible ares. */ + rect->left = 0; + rect->top = 0; + rect->width = pic->visible_width; + rect->height = pic->visible_height; + + /* config canvas size that be used for decoder. */ + 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 >> 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 |= + V4L2_CONFIG_PARM_DECODE_PSINFO; + + /*wake up*/ + complete(&inst->comp); + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + "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, + pic->field == V4L2_FIELD_NONE ? "P" : "I"); +} + +static void set_param_write_sync(struct vdec_mpeg4_inst *inst) +{ + 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) +{ + int ret = 0; + struct vdec_mpeg4_inst *inst = (struct vdec_mpeg4_inst *)h_vdec; + + if (!inst) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "the mpeg4 inst of dec is invalid.\n"); + return -1; + } + + switch (type) { + 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); + ret = -EINVAL; + } + + return ret; +} + +static struct vdec_common_if vdec_mpeg4_if = { + .init = vdec_mpeg4_init, + .probe = vdec_mpeg4_probe, + .decode = vdec_mpeg4_decode, + .get_param = vdec_mpeg4_get_param, + .set_param = vdec_mpeg4_set_param, + .deinit = vdec_mpeg4_deinit, +}; + +struct vdec_common_if *get_mpeg4_dec_comm_if(void); + +struct vdec_common_if *get_mpeg4_dec_comm_if(void) +{ + return &vdec_mpeg4_if; +}
diff --git a/drivers/amvdec_ports/decoder/vdec_vp9_if.c b/drivers/amvdec_ports/decoder/vdec_vp9_if.c new file mode 100644 index 0000000..fe81ddd --- /dev/null +++ b/drivers/amvdec_ports/decoder/vdec_vp9_if.c
@@ -0,0 +1,1065 @@ +/* +* 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/module.h> +#include <linux/slab.h> +#include <linux/timer.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <uapi/linux/swab.h> +#include "../vdec_drv_if.h" +#include "../aml_vcodec_util.h" +#include "../aml_vcodec_dec.h" +#include "../aml_vcodec_drv.h" +#include "../aml_vcodec_adapt.h" +#include "../vdec_drv_base.h" +#include "aml_vp9_parser.h" +#include "vdec_vp9_trigger.h" + +#define KERNEL_ATRACE_TAG KERNEL_ATRACE_TAG_V4L2 +#include <trace/events/meson_atrace.h> + +#define PREFIX_SIZE (16) + +#define NAL_TYPE(value) ((value) & 0x1F) +#define HEADER_BUFFER_SIZE (32 * 1024) +#define SYNC_CODE (0x498342) + +extern int vp9_need_prefix; +bool need_trigger; +int dump_cnt = 0; + +/** + * struct vp9_fb - vp9 decode frame buffer information + * @vdec_fb_va : virtual address of struct vdec_fb + * @y_fb_dma : dma address of Y frame buffer (luma) + * @c_fb_dma : dma address of C frame buffer (chroma) + * @poc : picture order count of frame buffer + * @reserved : for 8 bytes alignment + */ +struct vp9_fb { + uint64_t vdec_fb_va; + uint64_t y_fb_dma; + uint64_t c_fb_dma; + int32_t poc; + uint32_t reserved; +}; + +/** + * struct vdec_vp9_dec_info - decode information + * @dpb_sz : decoding picture buffer size + * @resolution_changed : resoltion change happen + * @reserved : for 8 bytes alignment + * @bs_dma : Input bit-stream buffer dma address + * @y_fb_dma : Y frame buffer dma address + * @c_fb_dma : C frame buffer dma address + * @vdec_fb_va : VDEC frame buffer struct virtual address + */ +struct vdec_vp9_dec_info { + uint32_t dpb_sz; + uint32_t resolution_changed; + uint32_t reserved; + uint64_t bs_dma; + uint64_t y_fb_dma; + uint64_t c_fb_dma; + uint64_t vdec_fb_va; +}; + +/** + * struct vdec_vp9_vsi - shared memory for decode information exchange + * between VPU and Host. + * The memory is allocated by VPU then mapping to Host + * in vpu_dec_init() and freed in vpu_dec_deinit() + * by VPU. + * AP-W/R : AP is writer/reader on this item + * VPU-W/R: VPU is write/reader on this item + * @hdr_buf : Header parsing buffer (AP-W, VPU-R) + * @list_free : free frame buffer ring list (AP-W/R, VPU-W) + * @list_disp : display frame buffer ring list (AP-R, VPU-W) + * @dec : decode information (AP-R, VPU-W) + * @pic : picture information (AP-R, VPU-W) + * @crop : crop information (AP-R, VPU-W) + */ +struct vdec_vp9_vsi { + char *header_buf; + int sps_size; + int pps_size; + int sei_size; + int head_offset; + struct vdec_vp9_dec_info dec; + struct vdec_pic_info pic; + struct vdec_pic_info cur_pic; + struct v4l2_rect crop; + bool is_combine; + int nalu_pos; + struct vp9_param_sets ps; +}; + +/** + * struct vdec_vp9_inst - vp9 decoder instance + * @num_nalu : how many nalus be decoded + * @ctx : point to aml_vcodec_ctx + * @vsi : VPU shared information + */ +struct vdec_vp9_inst { + unsigned int num_nalu; + struct aml_vcodec_ctx *ctx; + struct aml_vdec_adapt vdec; + struct vdec_vp9_vsi *vsi; + 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, ulong meta_ptr); + +static void get_pic_info(struct vdec_vp9_inst *inst, + struct vdec_pic_info *pic) +{ + *pic = inst->vsi->pic; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "pic(%d, %d), buf(%d, %d)\n", + pic->visible_width, pic->visible_height, + pic->coded_width, pic->coded_height); + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "Y(%d, %d), C(%d, %d)\n", + pic->y_bs_sz, pic->y_len_sz, + pic->c_bs_sz, pic->c_len_sz); +} + +static void get_crop_info(struct vdec_vp9_inst *inst, struct v4l2_rect *cr) +{ + cr->left = inst->vsi->crop.left; + cr->top = inst->vsi->crop.top; + cr->width = inst->vsi->crop.width; + cr->height = inst->vsi->crop.height; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "l=%d, t=%d, w=%d, h=%d\n", + cr->left, cr->top, cr->width, cr->height); +} + +static void get_dpb_size(struct vdec_vp9_inst *inst, unsigned int *dpb_sz) +{ + *dpb_sz = inst->vsi->dec.dpb_sz; + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "sz=%d\n", *dpb_sz); +} + +static u32 vdec_config_default_parms(u8 *parm) +{ + u8 *pbuf = parm; + + pbuf += sprintf(pbuf, "parm_v4l_codec_enable:1;"); + pbuf += sprintf(pbuf, "parm_v4l_buffer_margin:7;"); + 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;"); + pbuf += sprintf(pbuf, "vp9_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;"); + pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_endian:0;"); + + return parm - pbuf; +} + +static void vdec_parser_parms(struct vdec_vp9_inst *inst) +{ + 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; + + pbuf += sprintf(pbuf, "parm_v4l_codec_enable:1;"); + pbuf += sprintf(pbuf, "parm_v4l_buffer_margin:%d;", + ctx->config.parm.dec.cfg.ref_buf_margin); + pbuf += sprintf(pbuf, "vp9_double_write_mode:%d;", + ctx->config.parm.dec.cfg.double_write_mode); + pbuf += sprintf(pbuf, "vp9_buf_width:%d;", + ctx->config.parm.dec.cfg.init_width); + pbuf += sprintf(pbuf, "vp9_buf_height:%d;", + ctx->config.parm.dec.cfg.init_height); + pbuf += sprintf(pbuf, "save_buffer_mode:0;"); + pbuf += sprintf(pbuf, "no_head:0;"); + pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_mode:%d;", + ctx->config.parm.dec.cfg.canvas_mem_mode); + pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_endian:%d;", + 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 = 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) && + 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;", + ctx->config.parm.dec.hdr.color_parms.primaries[0][1]); + pbuf += sprintf(pbuf, "mB.x:%d;", + ctx->config.parm.dec.hdr.color_parms.primaries[1][0]); + pbuf += sprintf(pbuf, "mB.y:%d;", + ctx->config.parm.dec.hdr.color_parms.primaries[1][1]); + pbuf += sprintf(pbuf, "mR.x:%d;", + ctx->config.parm.dec.hdr.color_parms.primaries[2][0]); + pbuf += sprintf(pbuf, "mR.y:%d;", + ctx->config.parm.dec.hdr.color_parms.primaries[2][1]); + pbuf += sprintf(pbuf, "mW.x:%d;", + ctx->config.parm.dec.hdr.color_parms.white_point[0]); + pbuf += sprintf(pbuf, "mW.y:%d;", + ctx->config.parm.dec.hdr.color_parms.white_point[1]); + pbuf += sprintf(pbuf, "mMaxDL:%d;", + ctx->config.parm.dec.hdr.color_parms.luminance[0] * 10000); + pbuf += sprintf(pbuf, "mMinDL:%d;", + ctx->config.parm.dec.hdr.color_parms.luminance[1]); + pbuf += sprintf(pbuf, "mMaxCLL:%d;", + ctx->config.parm.dec.hdr.color_parms.content_light_level.max_content); + pbuf += sprintf(pbuf, "mMaxFALL:%d;", + ctx->config.parm.dec.hdr.color_parms.content_light_level.max_pic_average); + ctx->config.length = pbuf - ctx->config.buf; + 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; + inst->parms.parms_status |= V4L2_CONFIG_PARM_DECODE_CFGINFO; +} + +static int vdec_vp9_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) +{ + struct vdec_vp9_inst *inst = NULL; + int ret = -1; + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + inst->vdec.frm_name = "VP9"; + inst->vdec.video_type = VFORMAT_VP9; + inst->vdec.filp = ctx->dev->filp; + inst->vdec.ctx = ctx; + inst->ctx = ctx; + + vdec_parser_parms(inst); + + /* set play mode.*/ + if (ctx->is_drm_mode) + inst->vdec.port.flag |= PORT_FLAG_DRM; + + /* to eable vp9 hw.*/ + inst->vdec.port.type = PORT_TYPE_HEVC; + + /* probe info from the stream */ + inst->vsi = kzalloc(sizeof(struct vdec_vp9_vsi), GFP_KERNEL); + if (!inst->vsi) { + ret = -ENOMEM; + goto err; + } + + /* alloc the header buffer to be used cache sps or spp etc.*/ + inst->vsi->header_buf = vzalloc(HEADER_BUFFER_SIZE); + if (!inst->vsi->header_buf) { + ret = -ENOMEM; + goto err; + } + + init_completion(&inst->comp); + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + "vp9 Instance >> %lx\n", (ulong) inst); + + ctx->ada_ctx = &inst->vdec; + *h_vdec = (unsigned long)inst; + + /* init decoder. */ + ret = video_decoder_init(&inst->vdec); + if (ret) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "vdec_vp9 init err=%d\n", ret); + goto err; + } + + return 0; +err: + if (inst && inst->vsi && inst->vsi->header_buf) + vfree(inst->vsi->header_buf); + if (inst && inst->vsi) + kfree(inst->vsi); + if (inst) + kfree(inst); + *h_vdec = 0; + + return ret; +} + +#if 0 +static int refer_buffer_num(int level_idc, int poc_cnt, + int mb_width, int mb_height) +{ + return 20; +} +#endif + +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->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_vp9_inst *inst, int length, int dw_mode) +{ + int ret = 64; + + switch (vdec_get_dw_mode(inst, dw_mode)) { + case 0x0: /* 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 fill_vdec_params(struct vdec_vp9_inst *inst, + struct VP9Context *vp9_ctx) +{ + 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; + int margin = inst->parms.cfg.ref_buf_margin; + + /* fill visible area size that be used for EGL. */ + pic->visible_width = vdec_pic_scale(inst, vp9_ctx->render_width, dw); + pic->visible_height = vdec_pic_scale(inst, vp9_ctx->render_height, dw); + + /* calc visible ares. */ + rect->left = 0; + rect->top = 0; + rect->width = pic->visible_width; + rect->height = pic->visible_height; + + /* config canvas size that be used for decoder. */ + pic->coded_width = vdec_pic_scale(inst, ALIGN(vp9_ctx->width, 32), dw); + pic->coded_height = vdec_pic_scale(inst, ALIGN(vp9_ctx->height, 32), dw); + + pic->y_len_sz = pic->coded_width * pic->coded_height; + pic->c_len_sz = pic->y_len_sz >> 1; + + /* calc DPB size */ + dec->dpb_sz = 5 + margin;//refer_buffer_num(sps->level_idc, poc_cnt, mb_w, mb_h); + + inst->parms.ps.visible_width = pic->visible_width; + inst->parms.ps.visible_height = pic->visible_height; + inst->parms.ps.coded_width = pic->coded_width; + inst->parms.ps.coded_height = pic->coded_height; + inst->parms.ps.dpb_size = dec->dpb_sz; + inst->parms.parms_status |= V4L2_CONFIG_PARM_DECODE_PSINFO; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_BUFMGR, + "The stream infos, dw: %d, coded:(%d x %d), visible:(%d x %d), DPB: %d, margin: %d\n", + dw, pic->coded_width, pic->coded_height, + pic->visible_width, pic->visible_height, + dec->dpb_sz - margin, margin); +} + +static int parse_stream_ucode(struct vdec_vp9_inst *inst, + u8 *buf, u32 size, u64 timestamp, ulong meta_ptr) +{ + int ret = 0; + + 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); + return ret; + } + + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); + + return inst->vsi->pic.dpb_frames ? 0 : -1; +} + +static int parse_stream_ucode_dma(struct vdec_vp9_inst *inst, + ulong buf, u32 size, u64 timestamp, u32 handle) +{ + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; + + ret = vdec_vframe_write_with_dma(vdec, buf, size, timestamp, handle, + vdec_vframe_input_free, inst->ctx); + if (ret < 0) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "write frame data failed. err: %d\n", ret); + return ret; + } + + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); + + return inst->vsi->pic.dpb_frames ? 0 : -1; +} + +static int parse_stream_cpu(struct vdec_vp9_inst *inst, u8 *buf, u32 size) +{ + int ret = 0; + struct vp9_param_sets *ps = NULL; + + ps = vzalloc(sizeof(struct vp9_param_sets)); + if (ps == NULL) + return -ENOMEM; + + ret = vp9_decode_extradata_ps(buf, size, ps); + if (ret) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "parse extra data failed. err: %d\n", ret); + goto out; + } + + if (ps->head_parsed) + fill_vdec_params(inst, &ps->ctx); + + ret = ps->head_parsed ? 0 : -1; +out: + vfree(ps); + + return ret; +} + +static int vdec_vp9_probe(unsigned long h_vdec, + struct aml_vcodec_mem *bs, void *out) +{ + struct vdec_vp9_inst *inst = + (struct vdec_vp9_inst *)h_vdec; + u8 *buf = (u8 *)bs->vaddr; + u32 size = bs->size; + int ret = 0; + + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if ((s->magic != AML_VIDEO_MAGIC) && + (s->type != V4L_STREAM_TYPE_MATEDATA)) + return -1; + + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, s->data, + s->len, bs->timestamp, 0); + } else { + ret = parse_stream_cpu(inst, s->data, s->len); + } + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = parse_stream_ucode_dma(inst, bs->addr, size, + bs->timestamp, BUFF_IDX(bs, bs->index)); + } + } else { + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, buf, size, bs->timestamp, bs->meta_ptr); + } else { + ret = parse_stream_cpu(inst, buf, size); + } + } + + inst->vsi->cur_pic = inst->vsi->pic; + + return ret; +} + +static void vdec_vp9_deinit(unsigned long h_vdec) +{ + struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec; + struct aml_vcodec_ctx *ctx = inst->ctx; + + video_decoder_release(&inst->vdec); + + if (inst->vsi && inst->vsi->header_buf) + vfree(inst->vsi->header_buf); + + if (inst->vsi) + kfree(inst->vsi); + + kfree(inst); + + ctx->drv_handle = 0; + + need_trigger = false; + dump_cnt = 0; +} + +static void add_prefix_data(struct vp9_superframe_split *s, + u8 **out, u32 *out_size) +{ + int i; + u8 *p = NULL; + u32 length; + + length = s->size + s->nb_frames * PREFIX_SIZE; + if (!length) + return; + p = vzalloc(length); + if (!p) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, + "alloc size %d failed.\n" ,length); + return; + } + + memcpy(p, s->data, s->size); + p += s->size; + + for (i = s->nb_frames; i > 0; i--) { + u32 frame_size = s->sizes[i - 1]; + u8 *prefix = NULL; + + p -= frame_size; + memmove(p + PREFIX_SIZE * i, p, frame_size); + prefix = p + PREFIX_SIZE * (i - 1); + + /*add amlogic frame headers.*/ + frame_size += 16; + prefix[0] = (frame_size >> 24) & 0xff; + prefix[1] = (frame_size >> 16) & 0xff; + prefix[2] = (frame_size >> 8 ) & 0xff; + prefix[3] = (frame_size >> 0 ) & 0xff; + prefix[4] = ((frame_size >> 24) & 0xff) ^ 0xff; + prefix[5] = ((frame_size >> 16) & 0xff) ^ 0xff; + prefix[6] = ((frame_size >> 8 ) & 0xff) ^ 0xff; + prefix[7] = ((frame_size >> 0 ) & 0xff) ^ 0xff; + prefix[8] = 0; + prefix[9] = 0; + prefix[10] = 0; + prefix[11] = 1; + prefix[12] = 'A'; + prefix[13] = 'M'; + prefix[14] = 'L'; + prefix[15] = 'V'; + frame_size -= 16; + } + + *out = p; + *out_size = length; +} + +#ifndef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER +static int vp9_superframe_split_filter(struct vp9_superframe_split *s) +{ + int i, j, ret, marker; + bool is_superframe = false; + int *prefix = (int *)s->data; + + if (!s->data) + return -1; + +#define AML_PREFIX ('V' << 24 | 'L' << 16 | 'M' << 8 | 'A') + if (prefix[3] == AML_PREFIX) { + s->prefix_size = 16; + /*pr_info("the frame data has beed added header\n");*/ + } + + marker = s->data[s->data_size - 1]; + if ((marker & 0xe0) == 0xc0) { + int length_size = 1 + ((marker >> 3) & 0x3); + int nb_frames = 1 + (marker & 0x7); + int idx_size = 2 + nb_frames * length_size; + + if (s->data_size >= idx_size && + s->data[s->data_size - idx_size] == marker) { + s64 total_size = 0; + int idx = s->data_size + 1 - idx_size; + + for (i = 0; i < nb_frames; i++) { + int frame_size = 0; + for (j = 0; j < length_size; j++) + frame_size |= s->data[idx++] << (j * 8); + + total_size += frame_size; + if (frame_size < 0 || + total_size > s->data_size - idx_size) { + v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "Invalid frame size in a sframe: %d\n", + frame_size); + ret = -EINVAL; + goto fail; + } + s->sizes[i] = frame_size; + } + + s->nb_frames = nb_frames; + s->size = total_size; + s->next_frame = 0; + s->next_frame_offset = 0; + is_superframe = true; + } + }else { + s->nb_frames = 1; + s->sizes[0] = s->data_size; + s->size = s->data_size; + } + + /*pr_info("sframe: %d, frames: %d, IN: %x, OUT: %x\n", + is_superframe, s->nb_frames, + s->data_size, s->size);*/ + + /* parse uncompressed header. */ + if (is_superframe) { + /* bitstream profile. */ + /* frame type. (intra or inter) */ + /* colorspace descriptor */ + /* ... */ + + v4l_dbg(0, V4L_DEBUG_CODEC_PARSER, "the frame is a superframe.\n"); + } + + /*pr_err("in: %x, %d, out: %x, sizes %d,%d,%d,%d,%d,%d,%d,%d\n", + s->data_size, + s->nb_frames, + s->size, + s->sizes[0], + s->sizes[1], + s->sizes[2], + s->sizes[3], + s->sizes[4], + s->sizes[5], + s->sizes[6], + s->sizes[7]);*/ + + return 0; +fail: + return ret; +} +#endif + +static void trigger_decoder(struct aml_vdec_adapt *vdec) +{ + int i, ret; + u32 frame_size = 0; + u8 *p = vp9_trigger_header; + + 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, 0); + v4l_dbg(vdec->ctx, V4L_DEBUG_CODEC_ERROR, + "write trigger frame %d\n", ret); + p += frame_size; + } +} + +static int vdec_write_nalu(struct vdec_vp9_inst *inst, + u8 *buf, u32 size, u64 ts, ulong meta_ptr) +{ + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; + struct vp9_superframe_split s; + u8 *data = NULL; + u32 length = 0; + bool need_prefix = vp9_need_prefix; + + memset(&s, 0, sizeof(s)); + + /*trigger.*/ + if (0 && !need_trigger) { + trigger_decoder(vdec); + need_trigger = true; + } + + if (need_prefix) { + /*parse superframe.*/ + s.data = buf; + s.data_size = size; + ret = vp9_superframe_split_filter(&s); + if (ret) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "parse frames failed.\n"); + return ret; + } + + /*add headers.*/ + add_prefix_data(&s, &data, &length); + ret = vdec_vframe_write(vdec, data, length, ts, 0); + vfree(data); + } else { + ret = vdec_vframe_write(vdec, buf, size, ts, meta_ptr); + } + + return ret; +} + +static bool monitor_res_change(struct vdec_vp9_inst *inst, u8 *buf, u32 size) +{ + int ret = -1; + u8 *p = buf; + int len = size; + u32 synccode = vp9_need_prefix ? + ((p[1] << 16) | (p[2] << 8) | p[3]) : + ((p[17] << 16) | (p[18] << 8) | p[19]); + + if (synccode == SYNC_CODE) { + ret = parse_stream_cpu(inst, p, len); + if (!ret && (inst->vsi->cur_pic.coded_width != + inst->vsi->pic.coded_width || + inst->vsi->cur_pic.coded_height != + inst->vsi->pic.coded_height)) { + inst->vsi->cur_pic = inst->vsi->pic; + return true; + } + } + + return false; +} + +static int vdec_vp9_decode(unsigned long h_vdec, + struct aml_vcodec_mem *bs, bool *res_chg) +{ + struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec; + struct aml_vdec_adapt *vdec = &inst->vdec; + u8 *buf = (u8 *) bs->vaddr; + u32 size = bs->size; + int ret = -1; + + if (bs == NULL) + return -1; + + if (vdec_input_full(vdec)) { + return -EAGAIN; + } + + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if (s->magic != AML_VIDEO_MAGIC) + return -1; + + if (!inst->ctx->param_sets_from_ucode && + (s->type == V4L_STREAM_TYPE_MATEDATA)) { + if ((*res_chg = monitor_res_change(inst, + s->data, s->len))) + return 0; + } + + ret = vdec_vframe_write(vdec, + s->data, + s->len, + bs->timestamp, + 0); + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = vdec_vframe_write_with_dma(vdec, + bs->addr, size, bs->timestamp, + BUFF_IDX(bs, bs->index), + vdec_vframe_input_free, inst->ctx); + } + } else { + /*checked whether the resolution changes.*/ + 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, bs->meta_ptr); + } + + return ret; +} + + static void get_param_config_info(struct vdec_vp9_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_PSINFO) + parms->ps = inst->parms.ps; + if (inst->parms.parms_status & V4L2_CONFIG_PARM_DECODE_HDRINFO) + parms->hdr = inst->parms.hdr; + if (inst->parms.parms_status & V4L2_CONFIG_PARM_DECODE_CNTINFO) + parms->cnt = inst->parms.cnt; + + parms->parms_status |= inst->parms.parms_status; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, + "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) +{ + int ret = 0; + struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec; + + if (!inst) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "the vp9 inst of dec is invalid.\n"); + return -1; + } + + switch (type) { + case GET_PARAM_PIC_INFO: + get_pic_info(inst, out); + break; + + case GET_PARAM_DPB_SIZE: + get_dpb_size(inst, out); + break; + + case GET_PARAM_CROP_INFO: + get_crop_info(inst, out); + break; + + 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); + ret = -EINVAL; + } + + return ret; +} + +static void set_param_write_sync(struct vdec_vp9_inst *inst) +{ + complete(&inst->comp); +} + +static void set_param_ps_info(struct vdec_vp9_inst *inst, + struct aml_vdec_ps_infos *ps) +{ + 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; + pic->visible_height = ps->visible_height; + + /* calc visible ares. */ + rect->left = 0; + rect->top = 0; + rect->width = pic->visible_width; + rect->height = pic->visible_height; + + /* config canvas size that be used for decoder. */ + pic->coded_width = ps->coded_width; + pic->coded_height = ps->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 |= + V4L2_CONFIG_PARM_DECODE_PSINFO; + + /*wake up*/ + complete(&inst->comp); + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + "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, + struct aml_vdec_hdr_infos *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_EXINFO, + "VP9 set HDR infos\n"); + } +} + +static void set_param_post_event(struct vdec_vp9_inst *inst, u32 *event) +{ + aml_vdec_dispatch_event(inst->ctx, *event); + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + "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) +{ + int ret = 0; + struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec; + + if (!inst) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "the vp9 inst of dec is invalid.\n"); + return -1; + } + + switch (type) { + 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_COMP_BUF_INFO: + set_param_comp_buf_info(inst, in); + break; + + case SET_PARAM_HDR_INFO: + set_param_hdr_info(inst, in); + break; + + 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); + ret = -EINVAL; + } + + return ret; +} + +static struct vdec_common_if vdec_vp9_if = { + .init = vdec_vp9_init, + .probe = vdec_vp9_probe, + .decode = vdec_vp9_decode, + .get_param = vdec_vp9_get_param, + .set_param = vdec_vp9_set_param, + .deinit = vdec_vp9_deinit, +}; + +struct vdec_common_if *get_vp9_dec_comm_if(void); + +struct vdec_common_if *get_vp9_dec_comm_if(void) +{ + return &vdec_vp9_if; +} +
diff --git a/drivers/amvdec_ports/decoder/vdec_vp9_trigger.h b/drivers/amvdec_ports/decoder/vdec_vp9_trigger.h new file mode 100644 index 0000000..0097690 --- /dev/null +++ b/drivers/amvdec_ports/decoder/vdec_vp9_trigger.h
@@ -0,0 +1,860 @@ +/* + * drivers/amvdec_ports/decoder/vdec_vp9_trigger.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 _VDEC_VP9_TRIG_ +#define _VDEC_VP9_TRIG_ + +#define VP9_USE_TRIGGER_BIG_SIZE 1 + +static u8 vp9_trigger_header[] = { +#if VP9_USE_TRIGGER_BIG_SIZE + 0x00, 0x00, 0x15, 0x29, 0xff, 0xff, 0xea, 0xd6, 0x00, 0x00, 0x00, 0x01, 0x41, 0x4d, 0x4c, 0x56, + 0x82, 0x49, 0x83, 0x42, 0x00, 0x0c, 0x30, 0x0c, 0x34, 0x24, 0x38, 0x24, 0x1c, 0x19, 0x28, 0x00, + 0x02, 0x90, 0x7c, 0x52, 0xff, 0x19, 0x05, 0xfa, 0xbe, 0xa9, 0xed, 0x30, 0x72, 0xdd, 0x1b, 0xad, + 0xe8, 0xdd, 0xdc, 0xe2, 0x39, 0xb2, 0xb7, 0xd3, 0x37, 0xea, 0x4b, 0xe7, 0xd1, 0xfe, 0x57, 0xf0, + 0x7a, 0x9f, 0x51, 0xa4, 0x5e, 0xb7, 0x18, 0x80, 0x77, 0x60, 0x00, 0x7f, 0xdb, 0x4d, 0xea, 0xbb, + 0x00, 0x92, 0xed, 0xbc, 0xf6, 0x6e, 0x24, 0x2b, 0x3f, 0xd0, 0xb8, 0x09, 0x77, 0x11, 0x43, 0x65, + 0x62, 0x94, 0xed, 0x33, 0xe1, 0x6e, 0xe8, 0x1a, 0xd0, 0x4e, 0xb1, 0x72, 0x34, 0x8e, 0x24, 0xe5, + 0x1b, 0x26, 0x58, 0xdf, 0x19, 0x8d, 0x59, 0x82, 0x19, 0xae, 0xea, 0x12, 0x63, 0x6c, 0x89, 0x9c, + 0x7f, 0xc2, 0x67, 0x40, 0xed, 0xf2, 0x8c, 0xaa, 0x9f, 0xe1, 0x1e, 0x27, 0x12, 0xdb, 0x01, 0x86, + 0xcc, 0x47, 0xee, 0xaf, 0x5b, 0xaf, 0x44, 0x3d, 0x8e, 0x67, 0x2c, 0x57, 0xd9, 0xb9, 0xb5, 0x7a, + 0x83, 0x28, 0xab, 0xf4, 0xe0, 0x86, 0xf0, 0x14, 0xd0, 0x5d, 0xa4, 0x73, 0x28, 0x04, 0x3e, 0x99, + 0xa3, 0xd7, 0xb5, 0xc6, 0xf7, 0xb1, 0xd9, 0x11, 0x06, 0x34, 0x1b, 0x91, 0x6d, 0x31, 0xee, 0x26, + 0x95, 0xde, 0x0e, 0x55, 0x8f, 0xf1, 0x59, 0xe5, 0xc8, 0xb7, 0x74, 0x8a, 0x56, 0x99, 0xe5, 0xf7, + 0x04, 0x49, 0xa5, 0x66, 0xa2, 0x15, 0xaf, 0x3c, 0xe5, 0xce, 0x26, 0xb0, 0x66, 0x63, 0xae, 0x7b, + 0xf1, 0x09, 0xd2, 0x62, 0xb5, 0xe1, 0x4f, 0x0c, 0x54, 0xad, 0xe5, 0x00, 0x86, 0x14, 0x4b, 0x06, + 0x82, 0xad, 0x62, 0x95, 0x6d, 0x3a, 0x99, 0x67, 0x1d, 0x1b, 0x85, 0xf6, 0xe7, 0x69, 0xd8, 0x00, + 0xde, 0x63, 0xb5, 0x35, 0xf1, 0x44, 0x42, 0x21, 0xd3, 0xf3, 0xc9, 0x07, 0x23, 0x67, 0xe5, 0xea, + 0x5e, 0xd2, 0x63, 0x78, 0xb9, 0x7b, 0xeb, 0xd7, 0x2d, 0x4c, 0x5e, 0x44, 0x6a, 0x46, 0x68, 0xeb, + 0x5d, 0x61, 0xaa, 0xc7, 0xce, 0xb5, 0xe3, 0x01, 0xc8, 0x24, 0xca, 0x72, 0xcc, 0xdf, 0x89, 0x34, + 0xb6, 0xab, 0xfd, 0x7b, 0xb9, 0xbd, 0xef, 0x33, 0xb0, 0x2b, 0x1e, 0xd3, 0x20, 0xa4, 0xcd, 0x8a, + 0x51, 0x2e, 0x9d, 0x2e, 0x5c, 0xc7, 0x52, 0xed, 0xb8, 0x29, 0x68, 0x5d, 0x63, 0xe1, 0x79, 0x98, + 0x2d, 0xb1, 0xf4, 0xa0, 0x01, 0x30, 0x2d, 0x10, 0xec, 0xe4, 0x6c, 0xed, 0x55, 0xb1, 0xf9, 0x0f, + 0xd4, 0xae, 0x0f, 0x75, 0x5d, 0x81, 0x76, 0xfe, 0x94, 0x44, 0x1c, 0xcc, 0x8c, 0x7e, 0x0f, 0x4c, + 0xda, 0x88, 0x61, 0x6a, 0x17, 0x70, 0x14, 0xf5, 0x0d, 0x7c, 0xd1, 0xf8, 0x0f, 0x19, 0xa2, 0x05, + 0xe3, 0x98, 0xdc, 0xe1, 0xb4, 0x6a, 0x74, 0xa0, 0x8f, 0x1b, 0xc8, 0x12, 0xb4, 0xde, 0x62, 0x88, + 0xd4, 0x0d, 0xed, 0x0b, 0x76, 0xae, 0xe0, 0x92, 0xa2, 0x13, 0x70, 0x03, 0x08, 0x26, 0x8f, 0xed, + 0xa7, 0x5c, 0x5a, 0x55, 0x6e, 0x92, 0x76, 0xd0, 0xc2, 0x9c, 0x24, 0x77, 0x78, 0x9b, 0x33, 0xe5, + 0x88, 0xc6, 0x08, 0x8a, 0x28, 0x46, 0x9f, 0xb4, 0xd9, 0xd7, 0x86, 0x82, 0xe4, 0xba, 0x97, 0x3d, + 0x36, 0xd5, 0x31, 0x61, 0x7f, 0x8e, 0xb9, 0xa1, 0xab, 0x68, 0xa6, 0x8c, 0xa8, 0x47, 0x8d, 0x5c, + 0x97, 0xe9, 0xf0, 0x8f, 0xa4, 0xe8, 0x13, 0x2b, 0x9c, 0x4d, 0xff, 0x95, 0x8e, 0x98, 0x08, 0x75, + 0xd4, 0xed, 0x5e, 0x86, 0xe5, 0x68, 0x4b, 0x01, 0x0b, 0xd2, 0x13, 0xb0, 0x94, 0xd1, 0x28, 0x22, + 0x13, 0x6b, 0x95, 0x30, 0x79, 0xb6, 0xd9, 0x55, 0x2e, 0x3b, 0x36, 0x18, 0xef, 0x39, 0x16, 0x97, + 0x1e, 0xc4, 0x03, 0xb4, 0x75, 0xbe, 0xfd, 0x04, 0x2e, 0xd5, 0xac, 0x95, 0xac, 0x70, 0x40, 0xb3, + 0x1a, 0x61, 0x03, 0x9a, 0x9f, 0xbf, 0x93, 0x14, 0xcc, 0xc0, 0x28, 0xf8, 0x93, 0xa6, 0x7f, 0x07, + 0x12, 0xe1, 0xc2, 0x86, 0xe3, 0x87, 0x0d, 0x4d, 0x20, 0x75, 0xf7, 0xa0, 0x14, 0x49, 0x6f, 0x52, + 0xc6, 0x6e, 0x9d, 0xa8, 0x8e, 0x14, 0x3a, 0x9f, 0xa6, 0xac, 0xdc, 0x56, 0x9c, 0xdf, 0xf4, 0x75, + 0x6a, 0x31, 0x94, 0x50, 0x9c, 0x43, 0xd5, 0x6b, 0x20, 0xe4, 0xbc, 0x20, 0xd0, 0x9a, 0x7f, 0x84, + 0x6e, 0xd5, 0x7c, 0x2e, 0x93, 0xf8, 0x25, 0x50, 0x4f, 0xcb, 0x13, 0x74, 0x78, 0x08, 0x82, 0x0d, + 0xd0, 0x39, 0xaf, 0x4c, 0x6e, 0x9e, 0x25, 0x37, 0xbf, 0x7d, 0xe3, 0x93, 0xbd, 0x91, 0xb9, 0x52, + 0xac, 0x6d, 0xa6, 0xcd, 0x78, 0x50, 0x78, 0x3a, 0xc0, 0xc4, 0x13, 0xc0, 0x4e, 0xa5, 0x09, 0x09, + 0x80, 0xd8, 0x08, 0xfc, 0x63, 0xd4, 0x28, 0x3d, 0xef, 0xfd, 0xf8, 0x30, 0x3e, 0x09, 0x3a, 0x56, + 0xf8, 0x11, 0xa3, 0x67, 0xdd, 0x51, 0x15, 0xde, 0x20, 0x8d, 0xd8, 0x66, 0xac, 0x08, 0x70, 0x9c, + 0x8e, 0xb2, 0xff, 0x26, 0x5a, 0x82, 0x14, 0x1d, 0xf5, 0xf3, 0x1c, 0xf9, 0x6a, 0x00, 0x25, 0x84, + 0x94, 0xc9, 0x6f, 0x16, 0x75, 0xf6, 0xd2, 0x13, 0xa2, 0x70, 0xe0, 0x94, 0x4b, 0xe7, 0xe4, 0x6d, + 0xf1, 0xd2, 0xa3, 0x94, 0x65, 0x25, 0x38, 0xb4, 0x31, 0x8b, 0xdf, 0x1c, 0xb6, 0x22, 0x2b, 0x4b, + 0x03, 0xd2, 0x92, 0xcc, 0xa1, 0xcf, 0xb6, 0xf5, 0x28, 0x02, 0xb8, 0xe0, 0x44, 0x69, 0x34, 0xa8, + 0xb3, 0xaa, 0xea, 0x48, 0x6e, 0xf0, 0x67, 0x39, 0x0e, 0xbd, 0xfd, 0x20, 0x9d, 0x8d, 0xc8, 0x0b, + 0xa3, 0x7e, 0x66, 0x5b, 0xde, 0x21, 0xcc, 0x19, 0xae, 0xfd, 0x82, 0x73, 0x75, 0x09, 0x35, 0x2f, + 0xbf, 0x91, 0xaa, 0xfa, 0x1d, 0xa4, 0x44, 0x7b, 0xf9, 0xac, 0xa9, 0x02, 0xb4, 0x39, 0xf8, 0x96, + 0x90, 0x01, 0xff, 0x73, 0xe6, 0x52, 0xa1, 0x22, 0xfe, 0x04, 0xe3, 0x3e, 0x8a, 0x6d, 0xa0, 0x19, + 0x4e, 0x11, 0x90, 0x9a, 0x05, 0xb2, 0x7a, 0x8d, 0x98, 0xfc, 0xda, 0x1c, 0x5f, 0x86, 0x94, 0x7f, + 0x58, 0x20, 0xdf, 0xb6, 0xc0, 0x11, 0xd0, 0x8c, 0xc2, 0x11, 0x61, 0x75, 0x47, 0xbe, 0xec, 0x92, + 0x82, 0xa3, 0xfe, 0xcd, 0x13, 0xdd, 0xe0, 0xe6, 0x5a, 0x0a, 0xc1, 0x9f, 0x31, 0x6d, 0x78, 0x31, + 0xb6, 0x60, 0xbe, 0x0b, 0xd5, 0x81, 0x24, 0xe6, 0xc7, 0xe7, 0xe8, 0x08, 0x53, 0x27, 0xf3, 0x9a, + 0xf2, 0x7e, 0xb7, 0xc8, 0xd9, 0x74, 0x72, 0x45, 0xe6, 0xf8, 0xba, 0xb9, 0x40, 0xff, 0xa4, 0xfb, + 0x6a, 0xd0, 0x98, 0x4d, 0x4d, 0xcc, 0x4a, 0x38, 0xcb, 0xa0, 0xf0, 0x08, 0x7d, 0xd7, 0x70, 0xca, + 0xdf, 0xe6, 0x16, 0xa2, 0xd1, 0x9d, 0xaf, 0xcc, 0xd7, 0x6c, 0x5a, 0xfd, 0xac, 0x42, 0xab, 0x16, + 0x33, 0xc0, 0x2a, 0x68, 0xdd, 0x58, 0xb2, 0x41, 0xc5, 0x05, 0x61, 0x09, 0x60, 0xc8, 0x72, 0x29, + 0xb8, 0x1c, 0x90, 0xc5, 0x02, 0x76, 0xdc, 0xcb, 0x45, 0x5c, 0x6c, 0x16, 0x37, 0xe6, 0x11, 0xce, + 0x4e, 0x2e, 0xfa, 0xf4, 0x2c, 0x4f, 0x80, 0x64, 0x85, 0xf4, 0xbd, 0x03, 0x03, 0xd2, 0x86, 0x3e, + 0x97, 0xbb, 0x07, 0x22, 0x82, 0x3f, 0xc8, 0xc5, 0xc4, 0x8d, 0x4f, 0x66, 0x18, 0xc7, 0x74, 0xe6, + 0x19, 0x5e, 0xe7, 0xc8, 0xc8, 0xfd, 0xb1, 0xc5, 0x51, 0xc4, 0x25, 0xec, 0x2d, 0x0b, 0xed, 0xd0, + 0x53, 0x5b, 0x5d, 0x80, 0x2c, 0x28, 0xd0, 0x19, 0xe2, 0x1d, 0xd8, 0x25, 0x1b, 0xb1, 0xb2, 0x99, + 0x26, 0x93, 0xec, 0x08, 0x14, 0x16, 0x60, 0x28, 0xeb, 0x88, 0x0a, 0x84, 0x2d, 0xde, 0x41, 0xe3, + 0x67, 0x0f, 0x74, 0x7c, 0xf9, 0xcc, 0x38, 0xea, 0xf8, 0xa7, 0x13, 0x53, 0xfb, 0xea, 0x8b, 0x50, + 0x9c, 0x37, 0xff, 0x23, 0x4a, 0xdf, 0xc5, 0xe0, 0x04, 0x72, 0x8d, 0x2b, 0xca, 0x1c, 0x2c, 0x33, + 0x7a, 0x3d, 0x25, 0xa3, 0x76, 0x15, 0xcb, 0x8d, 0xb8, 0x24, 0xa4, 0xa3, 0xf8, 0xc2, 0x69, 0x33, + 0x27, 0x58, 0x51, 0xd9, 0x3c, 0x4c, 0x3b, 0x4a, 0xd7, 0x4e, 0x0b, 0xb5, 0xe2, 0x68, 0xeb, 0xa3, + 0xf8, 0x93, 0xc1, 0x92, 0x58, 0xf4, 0xc2, 0xf6, 0x1e, 0x7d, 0xa3, 0x13, 0x20, 0x50, 0x5b, 0xb3, + 0x3f, 0x07, 0xb3, 0x7e, 0xf5, 0x71, 0x1e, 0xf0, 0x23, 0x97, 0x95, 0x64, 0x70, 0xc2, 0xb9, 0x4a, + 0x16, 0x9b, 0xbb, 0xaf, 0xd2, 0x1d, 0xc6, 0xae, 0x3f, 0xa2, 0x7e, 0x23, 0x55, 0xdc, 0x68, 0x64, + 0x56, 0x33, 0xf8, 0xd4, 0x4e, 0xf4, 0x94, 0x0c, 0x09, 0xea, 0xae, 0xaf, 0xfb, 0x12, 0x31, 0x72, + 0xda, 0xc1, 0x23, 0x72, 0xb7, 0x69, 0xe6, 0x2b, 0x36, 0x8b, 0xe5, 0xdc, 0xd5, 0xcd, 0x3e, 0xdd, + 0x2c, 0x8e, 0x72, 0x23, 0xc8, 0x1f, 0x52, 0xea, 0x95, 0x21, 0xeb, 0xc6, 0x19, 0x9b, 0x6d, 0x80, + 0x4e, 0x3a, 0x5b, 0x2f, 0x3b, 0x81, 0x91, 0x12, 0xed, 0xbc, 0x45, 0x4f, 0x93, 0x5c, 0xdf, 0xf0, + 0xb7, 0x5a, 0xfd, 0x35, 0x54, 0xea, 0x68, 0x70, 0x4d, 0x4c, 0xb3, 0x56, 0x6c, 0x38, 0xbf, 0xaa, + 0x29, 0xe6, 0x9c, 0x78, 0x7f, 0x5e, 0x7b, 0xa3, 0x04, 0xeb, 0x3d, 0x25, 0xce, 0x56, 0x5e, 0x62, + 0x69, 0x87, 0xee, 0x7d, 0xf1, 0x1d, 0xb6, 0x1d, 0x7b, 0x4f, 0x47, 0x70, 0x5e, 0x06, 0x7b, 0x48, + 0x02, 0x1d, 0x01, 0xfd, 0xbb, 0xa6, 0xa3, 0x6f, 0x90, 0xe3, 0xb2, 0x10, 0xa1, 0xc9, 0x40, 0x96, + 0x6c, 0x4e, 0x35, 0x47, 0x71, 0x22, 0x80, 0x40, 0x52, 0xa8, 0x8f, 0x02, 0x62, 0x6a, 0xb5, 0x72, + 0xa0, 0x65, 0x55, 0xdc, 0x69, 0x63, 0x2e, 0xae, 0x9f, 0xcd, 0xa7, 0x3a, 0x32, 0x4a, 0x76, 0x03, + 0xc7, 0xf4, 0x7a, 0xde, 0x29, 0x1d, 0x7c, 0xad, 0x46, 0xe9, 0x90, 0x3b, 0xff, 0x4f, 0xa3, 0xe1, + 0x40, 0xe1, 0xe7, 0x2a, 0xd6, 0x2d, 0x6b, 0x23, 0x42, 0x1b, 0xe8, 0xdf, 0x76, 0xe6, 0x11, 0x7d, + 0xb2, 0xbe, 0xd1, 0x83, 0x81, 0x86, 0xb6, 0x5d, 0xc2, 0x29, 0xdf, 0xf4, 0xfe, 0x82, 0x14, 0x81, + 0xed, 0xe3, 0x77, 0xbc, 0xe3, 0x42, 0xba, 0x14, 0x82, 0x85, 0x84, 0xca, 0x00, 0x37, 0x0e, 0xbc, + 0x88, 0xa6, 0xa9, 0x63, 0x67, 0x3b, 0x9f, 0x42, 0xa2, 0x7a, 0xe4, 0x71, 0x11, 0xd0, 0x0a, 0xd8, + 0x2e, 0xcb, 0x95, 0xe9, 0x8f, 0xb3, 0x85, 0x17, 0x78, 0x4e, 0xa7, 0xce, 0x0d, 0xc4, 0x56, 0xf0, + 0x22, 0x0b, 0x65, 0xc0, 0xf4, 0x13, 0x55, 0x89, 0x00, 0x99, 0x7f, 0x19, 0xba, 0xa6, 0xe0, 0xa6, + 0xa0, 0x60, 0x27, 0xd0, 0x24, 0xb7, 0x69, 0x33, 0x95, 0xc8, 0x9b, 0x18, 0x38, 0x62, 0xc8, 0xde, + 0xef, 0xbe, 0x88, 0x5f, 0x21, 0x42, 0x0b, 0x59, 0x10, 0x0c, 0x9e, 0x9e, 0x66, 0x4a, 0xb7, 0xd6, + 0x4f, 0x7a, 0xa8, 0xcd, 0x20, 0x6a, 0x70, 0x3a, 0x3e, 0xc9, 0x3c, 0x4d, 0x35, 0xfe, 0xaa, 0xad, + 0x4f, 0x15, 0x77, 0x39, 0x29, 0x20, 0xac, 0x8a, 0x19, 0xdc, 0xd5, 0x61, 0x24, 0x59, 0x2a, 0x33, + 0xa5, 0xdb, 0x05, 0xcf, 0x93, 0x70, 0x77, 0xb3, 0x0e, 0xdf, 0xeb, 0x58, 0x78, 0xd4, 0x6c, 0xc3, + 0xe0, 0x7a, 0x09, 0xcf, 0xaa, 0x09, 0xaf, 0xbd, 0x2c, 0x01, 0x09, 0x11, 0x20, 0x00, 0x57, 0x8a, + 0x32, 0xd7, 0xf9, 0x20, 0x19, 0xe8, 0x80, 0xf6, 0x96, 0xcf, 0xad, 0xf9, 0x2c, 0xe8, 0x4d, 0x6d, + 0xe3, 0xd4, 0xfc, 0x2e, 0x8a, 0xce, 0x4a, 0x06, 0x51, 0x20, 0x23, 0x58, 0xe5, 0x8a, 0xcb, 0xa1, + 0xcc, 0x12, 0x9f, 0x34, 0x17, 0x1e, 0x69, 0x66, 0x02, 0xeb, 0x2e, 0x71, 0x6b, 0x25, 0xde, 0x7c, + 0x96, 0x17, 0xca, 0xac, 0x43, 0x41, 0x22, 0x3b, 0x87, 0xb9, 0x46, 0x85, 0x20, 0xac, 0x75, 0xbb, + 0x0b, 0x48, 0x6c, 0x7f, 0xfe, 0x1b, 0xa5, 0x6c, 0x98, 0xfd, 0xb5, 0x8d, 0x93, 0x7a, 0xfb, 0x5b, + 0x22, 0x26, 0x25, 0xda, 0x92, 0x96, 0x41, 0xe7, 0x75, 0xaf, 0xf0, 0x32, 0xea, 0xaa, 0xad, 0xc1, + 0x5a, 0xb0, 0x78, 0xa7, 0x03, 0xdf, 0x57, 0xaf, 0xac, 0x69, 0xb3, 0xa3, 0xa9, 0x02, 0x9f, 0x31, + 0xd5, 0xcf, 0x39, 0xc0, 0xc4, 0x83, 0xda, 0xc2, 0xa4, 0x5f, 0x9a, 0x31, 0x90, 0xc8, 0xd6, 0x29, + 0x57, 0xf8, 0x31, 0xa6, 0x4a, 0x51, 0x80, 0x70, 0x12, 0x7f, 0x5d, 0xc0, 0x6f, 0x0e, 0x62, 0x99, + 0xc0, 0x03, 0xdb, 0x16, 0x0a, 0x06, 0x79, 0x9a, 0xd2, 0x84, 0xc5, 0x4e, 0xb9, 0x05, 0x0b, 0xb5, + 0x2a, 0xd2, 0x98, 0x8c, 0xf0, 0xd3, 0x43, 0xc6, 0xfd, 0x73, 0x3d, 0x96, 0x28, 0xe3, 0x18, 0xbc, + 0x6c, 0x2f, 0xfd, 0x10, 0x9a, 0x90, 0x13, 0x8c, 0x17, 0xfe, 0xe1, 0xec, 0xb8, 0x44, 0xe7, 0xed, + 0xcf, 0x01, 0xbb, 0x47, 0x08, 0xc1, 0x0c, 0x49, 0x22, 0xc4, 0x8b, 0x2a, 0xe8, 0x89, 0x6d, 0x01, + 0x17, 0xdc, 0x58, 0x94, 0x1c, 0x52, 0xa7, 0x7f, 0x19, 0xda, 0x79, 0x92, 0x40, 0xdb, 0x28, 0x93, + 0x1b, 0xdf, 0xdb, 0x4f, 0xc0, 0x10, 0x95, 0x6d, 0x81, 0x62, 0x8d, 0x0a, 0xbe, 0x3e, 0x3b, 0x53, + 0x59, 0xca, 0x9f, 0x70, 0xc8, 0x32, 0xc3, 0x39, 0xbe, 0x44, 0x99, 0x96, 0x02, 0x46, 0xa9, 0xa9, + 0xe4, 0xe2, 0xa6, 0x1f, 0xce, 0xf0, 0x3a, 0xdc, 0x42, 0xae, 0x6b, 0xa7, 0x95, 0xa1, 0x2a, 0x1f, + 0xa2, 0xd5, 0x44, 0x2a, 0x85, 0xd4, 0x43, 0x0d, 0xf6, 0xa6, 0xbd, 0xcc, 0xb0, 0xab, 0xd0, 0xf6, + 0x2f, 0xac, 0x2c, 0x61, 0xb0, 0x52, 0xba, 0xcf, 0x3f, 0xb5, 0xea, 0xdf, 0x9f, 0x46, 0xbf, 0x58, + 0x1b, 0xf9, 0x16, 0xdb, 0x60, 0xce, 0xea, 0xf5, 0x72, 0xc2, 0x74, 0x32, 0xae, 0x7b, 0x41, 0x4d, + 0xa2, 0x33, 0x88, 0xf8, 0x7b, 0x89, 0xe0, 0x18, 0xe4, 0x7d, 0x6c, 0xab, 0xce, 0x9e, 0xb4, 0xcd, + 0xd2, 0x9a, 0xa5, 0x55, 0xfb, 0x83, 0x05, 0x9b, 0x06, 0x5a, 0xcf, 0xb7, 0x1a, 0xbe, 0xb9, 0x6a, + 0xe1, 0x0a, 0x48, 0x98, 0x25, 0xcd, 0xb8, 0xa6, 0x7e, 0x95, 0x22, 0xb4, 0x55, 0x2c, 0x21, 0x1c, + 0x07, 0xe7, 0x94, 0xe4, 0x78, 0x92, 0x09, 0x89, 0x05, 0xec, 0xf0, 0xce, 0x3f, 0x4f, 0x31, 0x30, + 0xb5, 0x61, 0x38, 0xce, 0x55, 0x54, 0x96, 0xf6, 0x5e, 0x42, 0xa0, 0xd7, 0xd4, 0x41, 0xd6, 0x4f, + 0x71, 0xc0, 0xc7, 0x45, 0x12, 0x89, 0x2c, 0x0d, 0x7e, 0xd2, 0xf9, 0x43, 0xaa, 0xa9, 0xeb, 0xc2, + 0x46, 0xa4, 0x97, 0xd9, 0x16, 0xb6, 0xa4, 0xd2, 0xeb, 0xfe, 0xbd, 0xcd, 0x62, 0xab, 0xbc, 0xc2, + 0xc4, 0x39, 0x07, 0x9f, 0x03, 0xed, 0x5c, 0x13, 0x5e, 0x92, 0x7c, 0x1a, 0xf3, 0xa6, 0x7f, 0x9a, + 0x07, 0x5a, 0xff, 0xa6, 0xbf, 0x57, 0xf9, 0xeb, 0xd2, 0x56, 0x78, 0x3f, 0x74, 0xb3, 0x2d, 0xbe, + 0xc9, 0x2d, 0xb2, 0x52, 0x5b, 0x7b, 0x79, 0x32, 0xb8, 0xfb, 0x5f, 0xfc, 0x3f, 0x62, 0x90, 0xe6, + 0x22, 0xe8, 0x5e, 0xed, 0x41, 0x4c, 0xb0, 0xf9, 0xe4, 0x7d, 0x6e, 0x96, 0x97, 0x8c, 0xa7, 0xf4, + 0xf1, 0xad, 0x3c, 0xa2, 0xdb, 0xa7, 0x8f, 0x81, 0xc0, 0xe5, 0xf6, 0x06, 0xd7, 0xae, 0xf5, 0x8b, + 0x66, 0xf9, 0x84, 0xec, 0x3f, 0xe6, 0x76, 0xce, 0x91, 0x64, 0xce, 0x1d, 0x78, 0x8b, 0x3e, 0x85, + 0xa5, 0x75, 0xd7, 0xcd, 0x6c, 0x57, 0x28, 0xd5, 0x6f, 0x62, 0x3d, 0x03, 0x47, 0x9e, 0xb5, 0xf8, + 0x12, 0x83, 0xdb, 0xf7, 0x3b, 0xf2, 0x8d, 0x03, 0x1e, 0x70, 0x53, 0x9e, 0x62, 0x54, 0x9d, 0xf6, + 0x94, 0x46, 0xdf, 0x68, 0xb8, 0xaa, 0x02, 0x19, 0xad, 0xfd, 0x3b, 0xf9, 0xdc, 0xb7, 0xe0, 0x78, + 0xf8, 0x83, 0x18, 0x1a, 0x42, 0x8c, 0x5b, 0x5e, 0x64, 0x28, 0x0c, 0xe5, 0xa7, 0x80, 0x8b, 0x07, + 0xdd, 0x93, 0x39, 0x76, 0x5b, 0x4a, 0x5c, 0x92, 0xab, 0xa6, 0xf6, 0xf4, 0x1e, 0x22, 0xc9, 0xb3, + 0x94, 0x55, 0x81, 0x32, 0xc2, 0xe0, 0x19, 0x64, 0x14, 0xe0, 0xd5, 0x4a, 0xb8, 0x0c, 0x21, 0xd1, + 0x7b, 0x38, 0x4b, 0x99, 0xff, 0x8e, 0xbb, 0x1d, 0xbb, 0xcc, 0xa4, 0xb7, 0x64, 0x30, 0xc7, 0x2b, + 0x11, 0x8f, 0xfc, 0xba, 0xb6, 0xae, 0xf1, 0xbc, 0x24, 0x1b, 0x0e, 0x7e, 0x06, 0xd6, 0xbc, 0x27, + 0x3b, 0x7e, 0x3b, 0x08, 0xcb, 0xbb, 0x23, 0x51, 0x0a, 0x6e, 0xce, 0xf6, 0x07, 0x0b, 0xd1, 0x1a, + 0x04, 0xfc, 0x88, 0xb5, 0xf3, 0x01, 0x17, 0xfc, 0x99, 0xef, 0x2c, 0x20, 0x2f, 0x50, 0x9f, 0xd0, + 0xe6, 0xec, 0x46, 0x9e, 0xf2, 0x25, 0xed, 0x99, 0x84, 0x26, 0x64, 0xce, 0xca, 0xb9, 0x2e, 0xf3, + 0x45, 0xe7, 0x1e, 0x56, 0x87, 0x1a, 0x1f, 0x40, 0xd2, 0x5f, 0x9c, 0x46, 0x6a, 0x0b, 0xda, 0x6a, + 0x57, 0xbd, 0x74, 0x76, 0x0b, 0xbf, 0x5b, 0x5b, 0xcd, 0x6c, 0x4a, 0x34, 0x73, 0x18, 0x57, 0xa3, + 0x1b, 0x32, 0x44, 0xd9, 0x76, 0x53, 0x5b, 0xde, 0x92, 0x2d, 0xb4, 0xab, 0x90, 0xa3, 0x58, 0xc2, + 0x1e, 0x7d, 0xdf, 0x9e, 0x98, 0xdf, 0x70, 0x66, 0x88, 0xa5, 0x1c, 0xc7, 0xb8, 0x65, 0x12, 0x62, + 0x3e, 0x7f, 0x00, 0x14, 0xf9, 0x3f, 0x70, 0x90, 0xfa, 0x94, 0x4c, 0x6e, 0x32, 0x26, 0xc3, 0x97, + 0x98, 0xe2, 0xa5, 0x33, 0xb9, 0xa8, 0xec, 0x9e, 0x41, 0x16, 0xf6, 0xa4, 0x8b, 0x14, 0x61, 0x35, + 0xf2, 0xc5, 0xb4, 0xca, 0x90, 0xd1, 0xac, 0xef, 0x9a, 0x4c, 0x24, 0x19, 0x5d, 0x9b, 0x15, 0xa5, + 0xca, 0xd7, 0x1c, 0x7e, 0x8e, 0xc5, 0x50, 0x86, 0x64, 0x13, 0xbc, 0x2c, 0xf3, 0x77, 0xb2, 0x59, + 0xa8, 0x6e, 0x3f, 0x75, 0xb4, 0x8d, 0x1c, 0xad, 0xad, 0xf5, 0x76, 0x54, 0xc6, 0x00, 0x76, 0x94, + 0xfc, 0x88, 0x71, 0x33, 0xbc, 0xf4, 0xed, 0xa4, 0x31, 0x76, 0x66, 0x7f, 0x05, 0x57, 0xeb, 0xe8, + 0xb9, 0x25, 0xc0, 0x30, 0x2b, 0x0f, 0xe7, 0xa0, 0x96, 0xaf, 0x7e, 0x6a, 0xc4, 0x5a, 0x39, 0x4a, + 0xbc, 0x14, 0x7c, 0x6e, 0x00, 0xdf, 0x53, 0x8d, 0x97, 0x5a, 0xe2, 0x49, 0xe9, 0x89, 0x74, 0xff, + 0xec, 0x94, 0x22, 0xa5, 0x3a, 0xc5, 0xae, 0x14, 0xcd, 0xc3, 0x46, 0xf6, 0x17, 0x53, 0x2c, 0xcd, + 0x59, 0x94, 0xc7, 0x3c, 0xad, 0xdb, 0x43, 0xb0, 0x1d, 0x8e, 0x0d, 0xae, 0x1a, 0x04, 0xad, 0xa2, + 0x94, 0xe4, 0x90, 0x5c, 0x80, 0xa1, 0x42, 0xa2, 0x08, 0x61, 0xe3, 0x5a, 0x9e, 0x7c, 0xc4, 0x4d, + 0x18, 0x1b, 0x8d, 0x0f, 0x61, 0x09, 0x78, 0xbb, 0xc5, 0x98, 0xb1, 0xe0, 0x1d, 0x8d, 0x09, 0x74, + 0x7d, 0x26, 0xcb, 0x13, 0x21, 0x2d, 0x13, 0x2b, 0xd1, 0xc8, 0x05, 0x2b, 0xf8, 0x29, 0x27, 0xb0, + 0xf9, 0x94, 0xbb, 0xa4, 0xaf, 0xf7, 0xea, 0x51, 0x47, 0x04, 0x86, 0x4e, 0x14, 0x01, 0xdb, 0xfa, + 0x9b, 0xee, 0x0c, 0x9f, 0x77, 0x8d, 0xb2, 0x2d, 0xb6, 0x30, 0x02, 0x91, 0x6e, 0x8f, 0x53, 0xe0, + 0x44, 0x8f, 0xee, 0xd8, 0x35, 0x0b, 0x94, 0xa1, 0x6a, 0x8b, 0xf5, 0xd3, 0x2c, 0xd1, 0x3d, 0xe3, + 0xfb, 0x56, 0xb9, 0x02, 0x7a, 0x85, 0xc7, 0x3d, 0x64, 0x64, 0x46, 0x47, 0x14, 0x5c, 0xe4, 0xcc, + 0xb0, 0x16, 0xb3, 0x0d, 0xa7, 0x8d, 0xf5, 0xc9, 0xa5, 0x83, 0xc9, 0x66, 0x64, 0x19, 0x0d, 0x32, + 0x3d, 0x10, 0xc2, 0xc0, 0x8b, 0x12, 0xb3, 0x90, 0xf4, 0x6c, 0x34, 0x39, 0x24, 0x89, 0x93, 0x26, + 0x49, 0x79, 0xd8, 0x9f, 0x6c, 0x44, 0x02, 0x8f, 0xd8, 0x22, 0x1b, 0x6f, 0xf3, 0xb7, 0xf1, 0x8b, + 0x99, 0x90, 0x0f, 0x95, 0xb8, 0x92, 0x23, 0x1a, 0x20, 0xa3, 0x74, 0x6f, 0x40, 0x8a, 0xaf, 0x6a, + 0x33, 0xf1, 0xf0, 0x5a, 0xe9, 0x50, 0x58, 0x0b, 0x76, 0x87, 0xe7, 0x42, 0x34, 0x3a, 0x50, 0xff, + 0x10, 0x0d, 0x91, 0xc2, 0x63, 0x35, 0x51, 0xde, 0x67, 0xaa, 0x41, 0xdc, 0x0d, 0x0a, 0x6a, 0xf4, + 0x07, 0xe6, 0xd8, 0xe1, 0xff, 0x01, 0x33, 0x10, 0x7f, 0xc8, 0x1d, 0x30, 0x3a, 0xc5, 0xce, 0x72, + 0xcb, 0x05, 0x9d, 0x2f, 0xcb, 0x48, 0xf2, 0xc5, 0x7d, 0xfb, 0x4c, 0xe5, 0x64, 0x63, 0x26, 0x18, + 0x95, 0x6c, 0x87, 0x13, 0xcd, 0x44, 0x26, 0x9b, 0x31, 0x02, 0xcf, 0xee, 0x65, 0xf6, 0x1c, 0x49, + 0x1e, 0xd3, 0xb5, 0x91, 0xc1, 0x1e, 0xe9, 0xf2, 0x81, 0x87, 0x55, 0x6c, 0x18, 0xaf, 0xaf, 0x93, + 0x8b, 0x86, 0xf2, 0xe9, 0x69, 0x13, 0xe2, 0x25, 0x1f, 0x32, 0xc4, 0x36, 0xa2, 0xfd, 0xdb, 0x6b, + 0x93, 0x2d, 0x15, 0xec, 0x80, 0x55, 0xa8, 0x58, 0x4f, 0x1f, 0xd8, 0xbe, 0x2b, 0x8e, 0x26, 0x06, + 0xf3, 0x73, 0x2a, 0xae, 0x87, 0xe4, 0x95, 0x7b, 0xb3, 0x8b, 0xb1, 0x0f, 0xe3, 0x9d, 0x47, 0x67, + 0x4f, 0x1d, 0xae, 0xd8, 0xe0, 0x76, 0x1a, 0xc2, 0x0b, 0x3e, 0x89, 0x22, 0x62, 0xdc, 0x15, 0x05, + 0x15, 0x51, 0x22, 0x2c, 0xce, 0x2f, 0xe2, 0x99, 0x74, 0x75, 0xc3, 0x7e, 0xcd, 0x66, 0x4e, 0xdf, + 0x97, 0x95, 0xea, 0xfa, 0x54, 0xae, 0x01, 0x58, 0x4a, 0xa6, 0x90, 0xfe, 0x6a, 0xe5, 0xf8, 0xce, + 0x78, 0x13, 0x1b, 0x20, 0x55, 0x33, 0xaf, 0xc7, 0x0a, 0x96, 0x14, 0x99, 0xb4, 0x22, 0xec, 0xcf, + 0x3c, 0x6a, 0x5c, 0x9d, 0x46, 0x92, 0x81, 0xee, 0x72, 0x7a, 0x6c, 0x5c, 0xe5, 0xa1, 0xcc, 0x5c, + 0x7b, 0x99, 0xae, 0x53, 0x3d, 0x05, 0xaf, 0x21, 0xf2, 0x4b, 0x6a, 0xf8, 0xd6, 0xc5, 0xce, 0xf9, + 0x15, 0xce, 0xc8, 0xa5, 0x37, 0x58, 0x3c, 0xe1, 0x83, 0xd4, 0xbe, 0x3e, 0x1e, 0x7a, 0x6e, 0x9e, + 0x6a, 0x94, 0x03, 0xa7, 0x25, 0x9c, 0x1c, 0x26, 0x84, 0x8e, 0xc4, 0xf1, 0x52, 0x8d, 0xc7, 0x76, + 0xd7, 0xa4, 0x7f, 0xc2, 0x52, 0x5c, 0x6b, 0x3a, 0xb3, 0xb2, 0xa9, 0x9a, 0x4b, 0xff, 0xc1, 0x89, + 0x99, 0xc5, 0x77, 0xac, 0x0d, 0x09, 0x69, 0xde, 0x50, 0x49, 0x03, 0xd2, 0xf7, 0x7a, 0xc9, 0xe9, + 0x48, 0x9f, 0x66, 0xa3, 0x91, 0x0d, 0x8e, 0x4f, 0xe1, 0x70, 0xc8, 0x74, 0x93, 0xd8, 0x76, 0x2b, + 0x9f, 0x4f, 0x15, 0xd5, 0xff, 0xb0, 0x5a, 0x4f, 0x06, 0xaa, 0xe0, 0xca, 0xdd, 0x0b, 0xd7, 0x6d, + 0x28, 0xa7, 0x20, 0x32, 0x6b, 0x20, 0x57, 0x51, 0x15, 0xbc, 0xc0, 0xc7, 0xa2, 0x21, 0xfa, 0x92, + 0x45, 0xf0, 0x24, 0x88, 0xc3, 0x22, 0x65, 0x32, 0x27, 0x45, 0x96, 0x1b, 0x6f, 0xdb, 0x8b, 0x22, + 0x17, 0x78, 0xa0, 0x78, 0xe1, 0xd5, 0x6a, 0x9e, 0x6a, 0xc9, 0xde, 0xe3, 0x71, 0x1b, 0x9d, 0x31, + 0x27, 0xb2, 0x25, 0x80, 0xfd, 0x47, 0x85, 0xa7, 0xb7, 0xcd, 0x63, 0xb3, 0x54, 0xc7, 0xf2, 0x53, + 0xbf, 0x22, 0x58, 0x95, 0xc4, 0x39, 0x19, 0x9d, 0xce, 0xbe, 0x54, 0xd5, 0x58, 0x68, 0x01, 0xf8, + 0x0d, 0x28, 0xaa, 0xf8, 0x27, 0x71, 0x68, 0x3b, 0x13, 0x53, 0x07, 0xd4, 0x42, 0xb0, 0x02, 0x66, + 0x35, 0x2b, 0xec, 0x62, 0x84, 0x85, 0x2b, 0x2c, 0xe7, 0x09, 0xa5, 0xe6, 0x1a, 0x77, 0x18, 0x28, + 0x94, 0xff, 0x1b, 0x3e, 0xcf, 0xdd, 0x21, 0x2a, 0xe2, 0x49, 0xa4, 0x27, 0xcf, 0x3a, 0x72, 0xcc, + 0x3e, 0xbe, 0x24, 0x61, 0xe2, 0x43, 0x4b, 0x3e, 0xcb, 0xe5, 0x18, 0x63, 0xfc, 0xd0, 0xb3, 0x49, + 0xcc, 0xd1, 0xce, 0xd5, 0x1d, 0x38, 0x72, 0x07, 0xbc, 0xa5, 0x68, 0xa5, 0xb1, 0x30, 0xc7, 0x5b, + 0xfc, 0x15, 0xcf, 0xf5, 0xa0, 0xf7, 0xe9, 0x38, 0x7d, 0xd3, 0xcb, 0xc0, 0x77, 0x16, 0x2a, 0x37, + 0xff, 0x62, 0x09, 0x5c, 0xe7, 0x5e, 0x5b, 0xfc, 0xaf, 0xcc, 0xe4, 0xcf, 0x63, 0x13, 0xb0, 0x53, + 0xbf, 0xf2, 0x94, 0x76, 0xb5, 0xd3, 0x60, 0x72, 0x0c, 0xf1, 0x71, 0x43, 0xa0, 0x04, 0xaa, 0xe5, + 0x87, 0x8c, 0x57, 0x66, 0x20, 0xe2, 0x9c, 0x39, 0xb4, 0xc0, 0xb4, 0x40, 0x55, 0x34, 0xe6, 0x31, + 0x75, 0x03, 0xdf, 0xf3, 0x5c, 0xd8, 0x15, 0x16, 0x35, 0x40, 0xc5, 0xcf, 0xc7, 0x51, 0x3b, 0x03, + 0xb4, 0x8f, 0x21, 0x96, 0x3d, 0x4f, 0x32, 0xb8, 0x05, 0xdf, 0x66, 0xb4, 0xcd, 0x42, 0xd4, 0x36, + 0x2e, 0x2d, 0x73, 0x76, 0xc5, 0x59, 0x92, 0xe7, 0x0f, 0xe6, 0x42, 0x1f, 0x34, 0xc6, 0x9c, 0x28, + 0x5e, 0xee, 0x14, 0x24, 0xd6, 0x66, 0xa9, 0x1a, 0xd0, 0xd5, 0x60, 0xa2, 0xc0, 0x73, 0x30, 0x1a, + 0x40, 0xc3, 0xf3, 0x77, 0x8b, 0x96, 0xef, 0xcb, 0x30, 0x83, 0x09, 0x62, 0x08, 0x1e, 0x50, 0x2d, + 0x26, 0xde, 0xaa, 0xa4, 0x74, 0x85, 0x5b, 0xd3, 0x4d, 0xbe, 0x70, 0x03, 0x26, 0xf6, 0x59, 0x0c, + 0x3e, 0x06, 0x5a, 0xfb, 0xfb, 0xd1, 0x3b, 0x32, 0xc9, 0x71, 0x67, 0x89, 0x38, 0x07, 0xce, 0x24, + 0xe3, 0x9e, 0x26, 0x06, 0x66, 0x06, 0xbb, 0x90, 0x1e, 0x67, 0xd5, 0x00, 0x3e, 0x8b, 0xeb, 0x49, + 0xce, 0xdf, 0x3d, 0xb6, 0x54, 0x4c, 0xef, 0xd2, 0x98, 0x7c, 0x49, 0x49, 0xd9, 0xb8, 0x06, 0xac, + 0x89, 0xa8, 0x94, 0x78, 0xe5, 0x83, 0x04, 0x49, 0xfb, 0x5a, 0x87, 0x7d, 0x10, 0x9c, 0x56, 0x3f, + 0x42, 0xd6, 0x6f, 0x97, 0x66, 0xe1, 0x18, 0xbc, 0x71, 0xc1, 0x03, 0x24, 0xaf, 0xdf, 0x36, 0x04, + 0x66, 0x02, 0x55, 0xd8, 0xae, 0x19, 0x96, 0x48, 0xc5, 0x6f, 0x4c, 0x7c, 0x34, 0x2c, 0x01, 0x24, + 0xd0, 0x49, 0xf5, 0x85, 0x76, 0xcc, 0x69, 0x56, 0x7a, 0x2f, 0x57, 0x3c, 0x5c, 0x81, 0x76, 0x73, + 0x13, 0x84, 0xa5, 0xd7, 0x3a, 0xfa, 0x3c, 0x84, 0x67, 0x3e, 0x11, 0x1d, 0x34, 0xe9, 0x33, 0x0b, + 0x47, 0x96, 0x02, 0x92, 0x4e, 0x43, 0x0b, 0xab, 0x56, 0x64, 0x53, 0xdf, 0x1d, 0x37, 0x1a, 0x57, + 0x00, 0x7d, 0x0d, 0x99, 0x1a, 0x7c, 0x6d, 0x68, 0xf7, 0xb2, 0x7e, 0x07, 0xeb, 0x65, 0xf4, 0x4c, + 0xbb, 0x2d, 0xe7, 0xd9, 0xc7, 0xa7, 0x52, 0x58, 0x36, 0x27, 0x2a, 0x51, 0xd9, 0x0e, 0x6b, 0x70, + 0xfe, 0xb9, 0xa2, 0x34, 0x41, 0x72, 0x68, 0xc5, 0x9c, 0xcc, 0xd4, 0x7a, 0x90, 0xf0, 0x62, 0xa0, + 0xf6, 0x05, 0x4b, 0xd6, 0x70, 0x9c, 0x04, 0xd9, 0x76, 0xde, 0xb6, 0x09, 0xb4, 0xc5, 0x24, 0x4b, + 0x8e, 0x79, 0x11, 0x91, 0xaf, 0x89, 0x10, 0x68, 0x8c, 0xed, 0xb5, 0xf2, 0x39, 0x8d, 0xe8, 0x0d, + 0xed, 0xb9, 0x22, 0x20, 0xe0, 0x45, 0x8a, 0xc2, 0x7d, 0x23, 0xb2, 0xb0, 0xb2, 0xde, 0xdb, 0x0f, + 0xa1, 0x6b, 0x8b, 0xf0, 0x94, 0x8b, 0xa5, 0x40, 0x1b, 0x2b, 0xcb, 0x41, 0x35, 0x39, 0x28, 0x3d, + 0x4e, 0x13, 0x6b, 0x2c, 0xbf, 0xa7, 0x6d, 0xd0, 0x11, 0xdf, 0x43, 0xd6, 0xf3, 0xc5, 0x54, 0x79, + 0x86, 0x07, 0x7c, 0xef, 0x1a, 0x51, 0xc3, 0xb2, 0xc6, 0xaa, 0x04, 0x68, 0xfb, 0xcb, 0xf0, 0x1b, + 0x1f, 0xf3, 0x45, 0xe0, 0x6e, 0x6d, 0xab, 0xb7, 0x7c, 0x42, 0x58, 0xc9, 0xbb, 0x35, 0xd9, 0x1f, + 0x9a, 0x88, 0x26, 0x12, 0x54, 0xda, 0x1d, 0x0d, 0xc4, 0x3e, 0x50, 0xd5, 0x17, 0x00, 0x08, 0x54, + 0xd3, 0x11, 0x01, 0xea, 0xb4, 0x47, 0xd7, 0x5c, 0x8f, 0x7a, 0x58, 0xfb, 0x07, 0x2a, 0xb7, 0x53, + 0xd6, 0x2b, 0x59, 0x13, 0xaf, 0x78, 0x22, 0x70, 0x1f, 0x10, 0xe3, 0x48, 0xae, 0x4f, 0xda, 0x98, + 0xca, 0xdd, 0x53, 0xab, 0xb8, 0x02, 0xa5, 0x95, 0xc8, 0xe0, 0x1c, 0x99, 0xf6, 0x9c, 0x18, 0x55, + 0x18, 0xcf, 0x67, 0x91, 0x46, 0xbb, 0x21, 0x1b, 0xea, 0x26, 0xbd, 0x5f, 0x90, 0x00, 0x7b, 0xbc, + 0xe5, 0x6f, 0xa0, 0xaf, 0xd8, 0xe6, 0xcd, 0x18, 0x75, 0x50, 0x3c, 0x08, 0x98, 0x56, 0x67, 0xfd, + 0x1a, 0x58, 0x64, 0xc0, 0x89, 0x11, 0xf0, 0x39, 0x65, 0x8a, 0x5f, 0x8c, 0x04, 0xd3, 0x93, 0x83, + 0xf0, 0x7d, 0xd8, 0xdf, 0xee, 0x0a, 0x2e, 0x8b, 0xc2, 0x12, 0x0e, 0x21, 0xe0, 0x75, 0xe2, 0x1d, + 0x6c, 0x22, 0x08, 0x5a, 0xaf, 0xdb, 0x17, 0x5a, 0x29, 0xc7, 0x76, 0xa8, 0xfc, 0x9a, 0x74, 0x1a, + 0xbd, 0xfe, 0x89, 0xc6, 0x23, 0xf8, 0x09, 0x58, 0xfe, 0xf2, 0x9d, 0xf0, 0xc3, 0x3e, 0xa9, 0x06, + 0x57, 0x2d, 0x5f, 0x41, 0x76, 0xd7, 0xa9, 0xec, 0x3b, 0x08, 0xac, 0x3d, 0x62, 0x0e, 0x66, 0x25, + 0xca, 0x2f, 0x10, 0xc5, 0xc7, 0x47, 0x2b, 0xc2, 0x3a, 0xda, 0x69, 0x55, 0xe6, 0x88, 0xb6, 0x4d, + 0x82, 0x0e, 0xe7, 0x40, 0x95, 0x2e, 0xe6, 0x6b, 0x4f, 0xb3, 0xc3, 0x30, 0x1e, 0x90, 0x44, 0x42, + 0xef, 0x46, 0x53, 0xf2, 0x46, 0xe7, 0xb5, 0x3b, 0x12, 0xae, 0x20, 0x99, 0xa0, 0xfc, 0x65, 0x3c, + 0x80, 0xec, 0x5c, 0xf5, 0x56, 0x9c, 0x94, 0x15, 0xb1, 0xa8, 0xe3, 0xa1, 0xde, 0xd7, 0xdc, 0x67, + 0xa0, 0x89, 0x4a, 0x04, 0x00, 0x4f, 0x8f, 0xb4, 0xe6, 0x81, 0xb5, 0x4f, 0x36, 0xcb, 0xa8, 0x71, + 0xcd, 0x33, 0xc6, 0x16, 0x0c, 0x9e, 0xa8, 0x2e, 0x4b, 0x56, 0x04, 0x5f, 0x24, 0x6b, 0x0a, 0x02, + 0x92, 0x36, 0x67, 0xa2, 0x01, 0xb8, 0xde, 0x46, 0x20, 0x27, 0x69, 0x1c, 0x3c, 0x96, 0x82, 0x60, + 0x01, 0xda, 0xa7, 0x19, 0xfd, 0x00, 0xab, 0x54, 0x9b, 0x66, 0xf8, 0xa8, 0xe3, 0x7d, 0xe8, 0x94, + 0x5e, 0xc4, 0xc2, 0x34, 0x5d, 0xa9, 0x91, 0x41, 0x7e, 0xa6, 0xe5, 0x84, 0xcb, 0x3d, 0x10, 0xbf, + 0xab, 0x02, 0xd1, 0x9d, 0xc3, 0xae, 0xe3, 0x0b, 0x03, 0x08, 0x19, 0x77, 0x4e, 0xb5, 0x55, 0x35, + 0x42, 0xc1, 0x03, 0x99, 0x3c, 0xd6, 0x33, 0x7a, 0x58, 0xb9, 0xcc, 0x23, 0x71, 0x3c, 0x67, 0xab, + 0x33, 0x26, 0xf5, 0x68, 0xe6, 0xb2, 0x23, 0x89, 0x1b, 0xd9, 0xb6, 0xf3, 0x5b, 0xba, 0xea, 0x41, + 0xb1, 0xd9, 0x7b, 0xc5, 0xe9, 0xeb, 0xec, 0x45, 0x09, 0x4b, 0x1f, 0x6c, 0x17, 0x54, 0x3f, 0x2a, + 0x68, 0xf5, 0xe9, 0xdb, 0xcb, 0xa4, 0x99, 0x0a, 0xae, 0x4b, 0xe4, 0x9f, 0x09, 0x84, 0xd1, 0x82, + 0x79, 0xf3, 0x8c, 0xd5, 0x10, 0x6d, 0x79, 0xc9, 0x2d, 0xe3, 0x47, 0xfd, 0x81, 0x6a, 0x9a, 0x38, + 0x3d, 0x7b, 0x25, 0x5d, 0x96, 0x35, 0x3a, 0x59, 0xbb, 0xb3, 0x6b, 0x31, 0x03, 0x43, 0xf0, 0x9b, + 0x72, 0xe5, 0xed, 0x2a, 0x18, 0x2f, 0xb4, 0x5f, 0x87, 0x54, 0x0e, 0x06, 0xc4, 0x58, 0x85, 0x80, + 0x29, 0xda, 0x85, 0x21, 0x2f, 0x11, 0x8b, 0x3c, 0x9f, 0xde, 0xb3, 0x53, 0x7e, 0x12, 0x19, 0x01, + 0xc9, 0xb7, 0x51, 0x35, 0x7d, 0x79, 0x38, 0x0e, 0xc2, 0xc6, 0x66, 0xab, 0x14, 0xba, 0x94, 0xff, + 0x64, 0x0b, 0xa7, 0x0e, 0x92, 0x6c, 0x55, 0x0a, 0xd0, 0x7a, 0xae, 0x88, 0x99, 0xaa, 0x52, 0x06, + 0x43, 0x3b, 0xa6, 0xef, 0x2b, 0x4e, 0xa1, 0xc9, 0xdf, 0x47, 0x26, 0xc1, 0x62, 0x7d, 0xe3, 0x66, + 0x40, 0x9c, 0x87, 0x2f, 0xf8, 0xd6, 0xe9, 0x3a, 0x51, 0xff, 0xd6, 0x68, 0xf8, 0x72, 0xf1, 0xcc, + 0xb7, 0x37, 0x95, 0x19, 0xdf, 0x4e, 0x39, 0x6f, 0x5a, 0x73, 0xe6, 0xc5, 0x37, 0x94, 0xc9, 0xb3, + 0xf1, 0x39, 0xfa, 0x1b, 0x15, 0x28, 0xd6, 0x25, 0xaf, 0x71, 0x5f, 0x51, 0x65, 0x3a, 0xd1, 0xc6, + 0xa4, 0x87, 0x88, 0x9d, 0xee, 0x9c, 0x56, 0x8a, 0xd5, 0xe2, 0xd6, 0x40, 0x4a, 0xfb, 0x2b, 0x7c, + 0xb4, 0x6f, 0xef, 0x21, 0x5d, 0x40, 0x74, 0x0b, 0xee, 0x59, 0x53, 0xa3, 0x45, 0x5e, 0x33, 0x97, + 0x59, 0xec, 0x8c, 0x6b, 0x97, 0xf8, 0xa3, 0x4c, 0xb4, 0xea, 0x0c, 0x27, 0x04, 0xc9, 0xb7, 0xb6, + 0xe2, 0x1b, 0xd6, 0x6a, 0xec, 0x60, 0x89, 0x10, 0xc2, 0xd1, 0x77, 0xc1, 0x26, 0xd6, 0xf5, 0x15, + 0xa2, 0x5c, 0x83, 0xbd, 0xe2, 0x92, 0x29, 0x18, 0x51, 0xc8, 0x2c, 0x61, 0xef, 0x90, 0x9c, 0xfa, + 0x2c, 0xd2, 0xee, 0x4b, 0x9f, 0x4b, 0xea, 0x13, 0x06, 0xde, 0x84, 0x43, 0x83, 0x4e, 0x65, 0xbf, + 0x12, 0x02, 0x54, 0xf5, 0xb8, 0x7e, 0x87, 0x6a, 0x98, 0xd9, 0xb3, 0x0d, 0xd9, 0xd1, 0x87, 0x96, + 0x9a, 0xaa, 0x93, 0x05, 0xc6, 0x13, 0x9b, 0xba, 0x23, 0x63, 0x41, 0x80, 0xf9, 0x91, 0x3b, 0xa2, + 0xfd, 0xd7, 0xa3, 0x0c, 0x33, 0x7c, 0x3b, 0xc9, 0x34, 0x54, 0x74, 0xf4, 0xb5, 0x9e, 0xd5, 0x2b, + 0xb1, 0xaa, 0x0f, 0x86, 0x53, 0x1c, 0x66, 0x6f, 0x6a, 0x38, 0x3d, 0x02, 0x20, 0xb7, 0xab, 0x9e, + 0x53, 0x15, 0x19, 0x2e, 0xdd, 0xd3, 0x82, 0xf5, 0xb5, 0x69, 0x6a, 0x97, 0x47, 0xe9, 0x04, 0xea, + 0x34, 0x2d, 0x67, 0xec, 0x82, 0x0f, 0x36, 0xd1, 0x79, 0x96, 0x89, 0xa1, 0x4d, 0x73, 0x1c, 0x7a, + 0x78, 0xf5, 0xe9, 0x62, 0x9d, 0x87, 0x93, 0x50, 0x00, 0x97, 0x75, 0x46, 0xc1, 0x9c, 0x66, 0x16, + 0x72, 0xab, 0x67, 0x22, 0xb2, 0x6b, 0x0c, 0x23, 0x88, 0x01, 0xcc, 0xc3, 0xf0, 0x1e, 0xf0, 0x9d, + 0x9e, 0x5a, 0xd3, 0xe2, 0x0f, 0x59, 0x18, 0x38, 0xb5, 0x38, 0x6d, 0x9c, 0x5c, 0xf8, 0xe0, 0xa9, + 0x2d, 0x1a, 0x72, 0x38, 0x35, 0xf3, 0x8a, 0x92, 0x4a, 0xc7, 0xba, 0x5a, 0xf1, 0x5a, 0x85, 0x2f, + 0x13, 0x2a, 0x93, 0xaf, 0x12, 0xd3, 0x83, 0xcb, 0xb0, 0x40, 0x3d, 0xee, 0x3b, 0x6a, 0x6e, 0x3e, + 0xb2, 0xd2, 0x7e, 0xb7, 0x07, 0x1e, 0x54, 0xc8, 0x8e, 0xc0, 0xf7, 0x23, 0xb1, 0xa0, 0xbd, 0x78, + 0xb7, 0x8b, 0x83, 0x59, 0x2d, 0xd5, 0x3b, 0x5f, 0x44, 0x3a, 0x63, 0x8b, 0x88, 0x84, 0x69, 0x3c, + 0x7b, 0xae, 0xfe, 0x21, 0xe8, 0xff, 0x03, 0xd8, 0x23, 0xc3, 0x83, 0x31, 0x06, 0xe2, 0x3f, 0x8a, + 0x21, 0x14, 0xee, 0x4b, 0xd3, 0xca, 0xb1, 0x0a, 0xd9, 0xc7, 0x31, 0xbf, 0xbc, 0xab, 0x35, 0x16, + 0x0e, 0x13, 0x5d, 0x40, 0xc2, 0xb1, 0xe5, 0xd3, 0xb2, 0x76, 0xc5, 0x38, 0x48, 0x49, 0xcc, 0x97, + 0x70, 0x35, 0xa1, 0x0d, 0x6e, 0xc6, 0xa8, 0x29, 0xe6, 0xaa, 0xc2, 0xe1, 0x63, 0x95, 0x5b, 0x77, + 0x63, 0x7f, 0x09, 0xf5, 0x66, 0xd1, 0xe7, 0x60, 0x97, 0x53, 0x05, 0x22, 0x1d, 0x77, 0x07, 0xc6, + 0x30, 0xa0, 0x9e, 0x78, 0x7f, 0x92, 0xd2, 0x76, 0x9c, 0x63, 0x9d, 0xf3, 0xa3, 0x6f, 0xb0, 0xb8, + 0x30, 0x73, 0xda, 0xbd, 0x50, 0xad, 0xa8, 0x30, 0xa4, 0x17, 0x38, 0x6d, 0x57, 0x17, 0x9d, 0x09, + 0xa6, 0x7c, 0x4a, 0x30, 0xcc, 0xcc, 0x89, 0x16, 0x11, 0x81, 0x61, 0x29, 0x9b, 0x61, 0x07, 0x89, + 0x82, 0x28, 0x1c, 0xc9, 0x6b, 0xca, 0x75, 0x83, 0x55, 0xe8, 0x30, 0xe1, 0x63, 0xab, 0xa8, 0x7e, + 0x6e, 0x6a, 0xa8, 0xdc, 0x89, 0x03, 0x57, 0xfe, 0x32, 0x0a, 0xfa, 0xdd, 0x87, 0xa3, 0xc2, 0x1d, + 0x41, 0xc7, 0x55, 0x94, 0x38, 0x5d, 0xec, 0x4c, 0x06, 0xf8, 0xd5, 0x29, 0xa6, 0x64, 0x4b, 0x93, + 0x38, 0x14, 0x63, 0x51, 0x53, 0x03, 0x09, 0x4b, 0x67, 0x74, 0x3d, 0x41, 0xc6, 0x5d, 0x69, 0xc9, + 0xd2, 0x76, 0xba, 0x1a, 0x07, 0x6f, 0x72, 0x85, 0xb1, 0xb2, 0x1a, 0x9c, 0xe7, 0xed, 0xf5, 0x1e, + 0xd6, 0xe7, 0x5f, 0xc7, 0x7d, 0x64, 0x35, 0xc7, 0x10, 0xc7, 0xae, 0x93, 0x87, 0x54, 0x49, 0xdb, + 0x1e, 0x7d, 0xaa, 0x94, 0x3e, 0x5b, 0xf3, 0x79, 0x72, 0xcf, 0xba, 0xa2, 0x59, 0x42, 0x7c, 0xad, + 0x0f, 0x19, 0x6b, 0xe8, 0xef, 0xa7, 0x01, 0x98, 0xce, 0x34, 0xf6, 0xf0, 0xfc, 0x8d, 0xef, 0x32, + 0x10, 0x57, 0x25, 0xdc, 0xb6, 0x43, 0x46, 0xd3, 0xf7, 0xf4, 0x5c, 0xd1, 0x6c, 0xc8, 0x64, 0xc5, + 0x44, 0x55, 0x28, 0x10, 0x3d, 0x19, 0x40, 0xf1, 0xba, 0xd2, 0x47, 0x9d, 0xf0, 0x8e, 0x0a, 0x61, + 0x04, 0x71, 0x2f, 0x32, 0xec, 0x9b, 0x91, 0xa9, 0x6a, 0x73, 0x1c, 0xc5, 0xd7, 0x25, 0x07, 0xaf, + 0x8e, 0x6e, 0x98, 0x09, 0xd4, 0xa7, 0xa7, 0xf7, 0x27, 0x55, 0x42, 0xe3, 0xf7, 0xf5, 0xf1, 0x15, + 0x3b, 0x3c, 0x0e, 0x4d, 0x99, 0x86, 0xb1, 0xd4, 0x9c, 0x2e, 0x28, 0x6a, 0xb5, 0xa9, 0xe1, 0x92, + 0xfe, 0x9d, 0xb7, 0x4f, 0x86, 0x4b, 0x21, 0x75, 0xee, 0xb8, 0xc6, 0xff, 0xe5, 0x0a, 0x9b, 0x1b, + 0x1e, 0xf6, 0x8a, 0x9b, 0x6d, 0xb1, 0x76, 0x93, 0x2d, 0x8c, 0xf7, 0x61, 0x51, 0x34, 0x14, 0x16, + 0xd3, 0xb9, 0xde, 0x38, 0x50, 0x03, 0xc2, 0x3c, 0x5d, 0xf9, 0xc2, 0xac, 0x27, 0x14, 0x65, 0x4f, + 0xbd, 0x56, 0x67, 0xc5, 0x1a, 0xe6, 0xb4, 0x95, 0x1a, 0x73, 0x1f, 0x44, 0x4d, 0xc1, 0x96, 0xba, + 0xef, 0x59, 0x2d, 0x05, 0x7c, 0xda, 0xbc, 0x3d, 0x4d, 0x34, 0x5d, 0x2f, 0xfb, 0xa3, 0x9e, 0xe9, + 0xa8, 0x76, 0x86, 0x05, 0xbd, 0xa2, 0xdc, 0xca, 0x83, 0x01, 0xf5, 0xb7, 0x6f, 0x50, 0xf9, 0xa7, + 0xbe, 0xc1, 0xe1, 0xb4, 0x24, 0x1e, 0x42, 0xdd, 0xb2, 0xc2, 0x35, 0x12, 0xb4, 0xab, 0x60, 0x20, + 0x9e, 0x10, 0x22, 0x98, 0xc6, 0xdf, 0x87, 0xcb, 0xd8, 0x9b, 0xab, 0xae, 0x9d, 0xd9, 0xa8, 0x63, + 0x51, 0x29, 0x17, 0xdb, 0x28, 0xe5, 0x89, 0xc9, 0x9f, 0x3d, 0x8b, 0xbe, 0x4f, 0x54, 0xf2, 0xf0, + 0xfd, 0xa5, 0x61, 0xa7, 0x06, 0x69, 0xe4, 0x37, 0x12, 0x86, 0x5a, 0x37, 0x3a, 0x1f, 0x04, 0xb1, + 0x2e, 0xa3, 0x8b, 0x03, 0x5f, 0xfa, 0xc1, 0xdd, 0x4c, 0xf8, 0x64, 0xa7, 0x9e, 0xb6, 0x45, 0x6a, + 0x93, 0xb2, 0xc0, 0x0f, 0x60, 0x31, 0x1d, 0xe7, 0xf5, 0xf6, 0x2d, 0x38, 0xf6, 0x72, 0xe5, 0xcf, + 0x2d, 0xe7, 0x44, 0x96, 0x74, 0x19, 0xd9, 0x70, 0x9e, 0x76, 0x7b, 0x74, 0x8a, 0x8b, 0x5a, 0x88, + 0xf1, 0x85, 0xc3, 0x87, 0x87, 0x27, 0x0e, 0x24, 0x03, 0x09, 0x15, 0x30, 0x8c, 0x15, 0x09, 0x5f, + 0x80, 0x4f, 0xdb, 0xa7, 0x93, 0x6c, 0x8b, 0x26, 0xba, 0x6e, 0xc6, 0xba, 0xf8, 0x68, 0x2b, 0xe6, + 0x52, 0x34, 0x00, 0x40, 0x9e, 0xe2, 0x33, 0xdf, 0xb6, 0xd2, 0xac, 0x24, 0x02, 0x72, 0x3b, 0xc6, + 0xbc, 0xeb, 0xf8, 0x2c, 0x95, 0x07, 0x65, 0x76, 0xda, 0xd9, 0x0c, 0x02, 0x72, 0xa8, 0xdb, 0x16, + 0x12, 0x5a, 0xb1, 0x51, 0x73, 0x5d, 0x76, 0x37, 0xd8, 0xdb, 0x60, 0x4f, 0xa2, 0x8e, 0x90, 0x96, + 0xe4, 0x78, 0x96, 0xcb, 0x67, 0xd2, 0x32, 0xca, 0xf7, 0x2f, 0x66, 0xbf, 0x82, 0x0f, 0x2a, 0x17, + 0x68, 0xb3, 0x95, 0x38, 0x4c, 0x08, 0x86, 0x00, 0xb4, 0x66, 0xa0, 0x20, 0xa4, 0x02, 0x97, 0x71, + 0x8c, 0x59, 0x04, 0xe9, 0x98, 0xba, 0x08, 0xf2, 0xd9, 0xcf, 0xaf, 0x73, 0x2e, 0x88, 0xb1, 0x68, + 0x30, 0x06, 0xdd, 0x05, 0xf4, 0x1f, 0x55, 0x13, 0x04, 0xe6, 0xb1, 0x40, 0x1f, 0xcf, 0x46, 0x83, + 0x26, 0x96, 0x8f, 0x41, 0x20, 0xec, 0x1c, 0x00, 0x78, 0x1d, 0xb4, 0x8c, 0x25, 0xb3, 0xe4, 0x2f, + 0x94, 0x2f, 0xfe, 0x98, 0x92, 0x3a, 0x12, 0xaf, 0x34, 0x37, 0xee, 0xaa, 0x51, 0x60, 0x6e, 0x9c, + 0x0a, 0x1f, 0xa9, 0x38, 0x00, 0x01, 0x17, 0xdd, 0x4c, 0x60, 0xbf, 0x0d, 0x08, 0x6f, 0xd3, 0xcf, + 0x4a, 0x23, 0x81, 0x5f, 0x3b, 0xca, 0x66, 0x4f, 0xf1, 0xf8, 0x15, 0x51, 0xf7, 0xe1, 0x6d, 0x9f, + 0x55, 0xd3, 0xd8, 0xb2, 0xb3, 0x94, 0x67, 0xa1, 0x24, 0xda, 0xfe, 0x60, 0xe9, 0x73, 0xf6, 0x93, + 0x49, 0x22, 0x51, 0x4a, 0xaf, 0x47, 0x77, 0xfa, 0xce, 0x03, 0x69, 0xb1, 0x65, 0x8c, 0xce, 0x48, + 0x62, 0xcc, 0x88, 0x61, 0xfb, 0x07, 0xcc, 0xdb, 0x4d, 0x01, 0x9d, 0x21, 0x65, 0x33, 0x1a, 0x72, + 0x93, 0x67, 0x90, 0xff, 0x45, 0xa1, 0x50, 0x33, 0x74, 0xaf, 0x62, 0xf3, 0x61, 0xcf, 0xdb, 0x7a, + 0xd5, 0x78, 0xce, 0x56, 0xbf, 0xee, 0xd6, 0x6b, 0x03, 0xd2, 0x7d, 0x69, 0xcd, 0x89, 0x81, 0xb1, + 0xc1, 0xb2, 0x21, 0xf5, 0xd8, 0xcf, 0x15, 0x79, 0xfb, 0xbd, 0x56, 0xf6, 0x06, 0x90, 0xa1, 0x98, + 0xc1, 0x6a, 0xb8, 0x70, 0xa7, 0xee, 0xbc, 0x02, 0xe3, 0x8a, 0xda, 0xac, 0x1f, 0x2b, 0x42, 0xa8, + 0xc4, 0x39, 0xcc, 0xa8, 0x2d, 0x6d, 0x62, 0x5b, 0xa7, 0x55, 0x83, 0x4a, 0x7f, 0x1c, 0xbd, 0x16, + 0xec, 0x9c, 0x03, 0x4d, 0xfb, 0x63, 0x33, 0x90, 0xab, 0x65, 0x2d, 0xa8, 0x7c, 0x55, 0x8b, 0xc8, + 0x89, 0x97, 0x97, 0x8a, 0x33, 0x26, 0x03, 0xe2, 0x97, 0x42, 0x87, 0xf5, 0xc9, 0x6d, 0xae, 0x00, + 0x00, 0x10, 0xc4, 0xc4, 0x6b, 0xfd, 0xcd, 0xb7, 0x58, 0x00, 0xee, 0xca, 0x51, 0x3d, 0x6d, 0x04, + 0xb0, 0x7d, 0x36, 0x2f, 0x54, 0xf2, 0xa6, 0xd5, 0x35, 0xf9, 0xa4, 0x28, 0x56, 0xfd, 0x08, 0xc6, + 0x7b, 0xd8, 0x0e, 0x38, 0x28, 0xd2, 0x67, 0x66, 0x51, 0x30, 0x06, 0x4f, 0x51, 0xcc, 0xa3, 0x46, + 0x8e, 0xcb, 0x95, 0xee, 0x48, 0x2f, 0xac, 0xd0, 0x31, 0x5b, 0xbe, 0xb1, 0xf0, 0xf1, 0x78, 0x13, + 0xd2, 0x2c, 0x16, 0x48, 0x18, 0x59, 0xe4, 0xee, 0x40, 0x7a, 0x4d, 0x9b, 0x10, 0x68, 0x0c, 0x89, + 0xc5, 0x0c, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x02, 0x43, 0xff, 0xff, 0xfd, 0xbc, 0x00, 0x00, 0x00, + 0x01, 0x41, 0x4d, 0x4c, 0x56, 0x86, 0x00, 0x40, 0x92, 0xe1, 0x81, 0x56, 0x00, 0x00, 0x18, 0x70, + 0x5a, 0x9a, 0x74, 0x00, 0x00, 0x7f, 0xe8, 0x2b, 0xfc, 0x0c, 0x29, 0x71, 0x4d, 0x17, 0x17, 0xe7, + 0xd9, 0x45, 0x16, 0x69, 0x89, 0x6b, 0x68, 0x73, 0xfe, 0x3a, 0xe9, 0x08, 0x96, 0xe2, 0x0f, 0xc5, + 0x5d, 0x8c, 0xb1, 0x77, 0xec, 0x64, 0x9e, 0xce, 0x03, 0x26, 0x59, 0xee, 0x37, 0xe8, 0xc1, 0x2a, + 0x2a, 0xdc, 0xfa, 0xa1, 0xb2, 0x5a, 0x4b, 0x59, 0xde, 0xa6, 0x91, 0xd1, 0x63, 0xa0, 0xa1, 0x81, + 0xb1, 0x8d, 0xab, 0x38, 0xb0, 0xa5, 0x45, 0xcf, 0x41, 0xe5, 0x6c, 0x54, 0x13, 0xac, 0x85, 0x72, + 0xd3, 0x7a, 0x0c, 0x7d, 0x47, 0xd0, 0xe5, 0x6c, 0xd5, 0x81, 0xb7, 0xf6, 0x8e, 0x53, 0x81, 0x42, + 0x9e, 0x74, 0xb0, 0x3b, 0x1c, 0x7d, 0xbc, 0x04, 0xfe, 0x15, 0xc6, 0x00, 0x01, 0x9c, 0x05, 0x97, + 0x44, 0x0e, 0xd6, 0xf0, 0x85, 0x0f, 0x28, 0x5b, 0x4d, 0x4b, 0x67, 0x07, 0x25, 0x16, 0xfe, 0x59, + 0x69, 0xe2, 0x28, 0x42, 0xc6, 0xd0, 0xb4, 0x2c, 0x4e, 0xcf, 0x78, 0x8c, 0x9c, 0x85, 0x02, 0x09, + 0xa3, 0x53, 0x53, 0xed, 0x0a, 0x52, 0xa7, 0x00, 0x48, 0x46, 0x12, 0x0f, 0x17, 0x7c, 0x6d, 0x99, + 0x0f, 0x06, 0x14, 0xac, 0x68, 0xa4, 0x09, 0x01, 0x1d, 0x97, 0x7d, 0x2b, 0x81, 0xc2, 0x02, 0xad, + 0x6e, 0x10, 0x82, 0xed, 0x3c, 0x51, 0xae, 0x23, 0xc6, 0xfb, 0x77, 0x54, 0x42, 0x7d, 0x46, 0x7e, + 0x71, 0xfa, 0xa9, 0x63, 0xda, 0x8b, 0x4b, 0xc7, 0x85, 0x61, 0x9a, 0x5e, 0x08, 0xab, 0x74, 0x27, + 0x35, 0x63, 0x21, 0x19, 0x09, 0xf4, 0xa3, 0x40, 0x19, 0x1a, 0xbd, 0x87, 0x00, 0x99, 0xd7, 0xd7, + 0xda, 0xcf, 0x01, 0xdf, 0xc2, 0x9b, 0x35, 0xd8, 0x89, 0x58, 0xdb, 0xf5, 0x0c, 0xfb, 0x67, 0xb1, + 0x54, 0x6f, 0x16, 0xc2, 0xed, 0x20, 0x2d, 0x67, 0xbb, 0xb7, 0xb5, 0x0b, 0xb7, 0xde, 0x2c, 0xfa, + 0xa9, 0xe5, 0x0f, 0xf1, 0x10, 0x0e, 0x80, 0x7f, 0x2d, 0x25, 0x79, 0x3a, 0xd2, 0x80, 0x23, 0x07, + 0x85, 0xc2, 0x80, 0x4f, 0x4f, 0x99, 0x6e, 0xf5, 0xd4, 0x4d, 0x9a, 0x23, 0x61, 0xa9, 0xe7, 0x6c, + 0x8e, 0x3d, 0xc1, 0x34, 0x7d, 0xbc, 0x47, 0xea, 0x7d, 0x36, 0x9d, 0x92, 0x7f, 0xe8, 0x10, 0xf0, + 0x6b, 0x63, 0x72, 0xee, 0xe7, 0x46, 0x35, 0xa6, 0xfc, 0xeb, 0x32, 0x27, 0xbe, 0x8e, 0x13, 0x58, + 0x6e, 0xa9, 0xe1, 0x71, 0x9f, 0x1a, 0xf5, 0xb1, 0x5e, 0x3e, 0x08, 0xdb, 0xb8, 0x61, 0xef, 0xdd, + 0xbb, 0x5c, 0x1b, 0x61, 0xe0, 0x12, 0xb6, 0xea, 0xfe, 0xfe, 0x75, 0xae, 0x71, 0x4f, 0x71, 0x97, + 0x3e, 0x04, 0x02, 0x2e, 0x7a, 0xfd, 0xbf, 0x2d, 0x36, 0xd5, 0x45, 0x57, 0x80, 0xd0, 0xe6, 0xc8, + 0x36, 0x63, 0x22, 0xda, 0x89, 0xc5, 0x90, 0xb3, 0x44, 0xff, 0x75, 0x4f, 0x25, 0xa7, 0xc1, 0xa9, + 0x0a, 0xe6, 0x0b, 0x3d, 0x7c, 0x90, 0xfa, 0x59, 0x11, 0x7b, 0xd1, 0xbb, 0xa0, 0x1e, 0x38, 0x7e, + 0xdd, 0xd2, 0x9a, 0xa5, 0xfb, 0x59, 0x63, 0x2a, 0x37, 0xc6, 0x06, 0x70, 0x54, 0x9e, 0x83, 0x35, + 0xc5, 0xfb, 0xa4, 0x7f, 0xa4, 0xb7, 0x48, 0xf3, 0x16, 0xe1, 0x4c, 0xc6, 0x66, 0x9f, 0x8d, 0xb4, + 0x3a, 0xb2, 0x8b, 0xb2, 0x9a, 0x88, 0x2f, 0xb7, 0x57, 0xd3, 0x91, 0xd1, 0x94, 0x1f, 0xfb, 0x85, + 0x0d, 0x86, 0x39, 0x65, 0xcd, 0xfa, 0xa3, 0x25, 0x32, 0x54, 0x81, 0xdf, 0x1e, 0x3c, 0xcf, 0x9e, + 0xe8, 0x74, 0xb1, 0x94, 0xdf, 0xae, 0x01, 0x10, 0x52, 0x43, 0xa4, 0x2c, 0xe7, 0xdd, 0x7f, 0x82, + 0x18, 0xbf, 0xc3, 0x8c, 0xb8, 0xf2, 0xab, 0x16, 0xe8, 0xe9, 0xc5, 0x1d, 0xe2, 0xc1, 0x58, 0xdc, + 0x93, 0x4e, 0x2e, 0x19, 0xc5, 0x83, 0x0f, 0xf7, 0x25, 0x28, 0x70, 0x1b, 0x70, 0xca, 0x53, 0x86, + 0xed, 0x59, 0x96, 0xf0, 0x04, 0xba, 0x47, 0x26, 0xe8, 0xae, 0x5a, 0xa8, 0xc8, 0x6b, 0x4a, 0xe4, + 0x46, 0xaf, 0x51, 0xf5, 0x2f, 0xb9, 0x03, 0xc5, 0xdb, 0x85, 0x28, 0x4f, 0xa2, 0xa9, 0x5c, 0xc4, + 0x4d, 0xc7, 0x58, 0xce, 0x6f, 0xc9, 0xa9, 0x21, 0x04, 0x57, 0x91, 0x61, 0x7f, 0x6b, 0xb5, 0x61, + 0x36, 0xd7, 0x90, 0x00, 0x00, 0x00, 0x03, 0x13, 0xff, 0xff, 0xfc, 0xec, 0x00, 0x00, 0x00, 0x01, + 0x41, 0x4d, 0x4c, 0x56, 0x86, 0x00, 0x40, 0x92, 0xe1, 0x81, 0x56, 0x00, 0x00, 0x14, 0x70, 0x12, + 0x20, 0x00, 0x00, 0x7f, 0xdb, 0xf4, 0x80, 0x58, 0xaf, 0x60, 0x9f, 0x03, 0x27, 0x50, 0xe2, 0x89, + 0x62, 0x11, 0xa5, 0x5a, 0x21, 0x51, 0x4f, 0xdb, 0x8c, 0x95, 0x4f, 0xfd, 0xec, 0x37, 0xd3, 0x3b, + 0x6e, 0x73, 0x15, 0x60, 0x6e, 0xfa, 0x66, 0xcd, 0x61, 0xff, 0xb3, 0xc7, 0x3d, 0x0e, 0xd5, 0x61, + 0x3e, 0xe1, 0x5b, 0x03, 0x7f, 0x08, 0xb7, 0x66, 0x6b, 0x57, 0xab, 0x77, 0x0c, 0x84, 0xed, 0xc7, + 0x81, 0xfe, 0x20, 0x80, 0x1f, 0x11, 0xf2, 0x02, 0x8d, 0x5c, 0x91, 0x5c, 0xeb, 0x61, 0x46, 0xe6, + 0x06, 0x2d, 0x90, 0x43, 0x76, 0xca, 0x4b, 0x01, 0x8f, 0x02, 0x01, 0x41, 0x07, 0x9a, 0xee, 0x97, + 0x99, 0x88, 0x5d, 0xa2, 0xbf, 0x93, 0x02, 0x8a, 0x02, 0x8a, 0x61, 0x08, 0x4f, 0xbc, 0xc4, 0x7e, + 0x40, 0x15, 0x8e, 0xaa, 0x14, 0x7e, 0xbe, 0xdb, 0x86, 0x18, 0xf1, 0xcc, 0xd8, 0x56, 0x50, 0xe5, + 0x14, 0xa0, 0x2c, 0x6b, 0x06, 0x30, 0xc4, 0x9f, 0x45, 0xe0, 0x8b, 0x33, 0x18, 0xe2, 0x47, 0x12, + 0x5a, 0x22, 0xb4, 0x68, 0x33, 0x8a, 0xe6, 0x75, 0x41, 0x5a, 0xcf, 0x0f, 0xc8, 0xed, 0xa7, 0x4e, + 0x90, 0xd0, 0x38, 0xe8, 0x51, 0x14, 0x37, 0x9c, 0x8e, 0x96, 0xe0, 0x22, 0x0a, 0xf8, 0xab, 0x63, + 0x67, 0xaa, 0x96, 0x47, 0x55, 0xbd, 0x86, 0x33, 0x0f, 0x57, 0x07, 0x3b, 0xae, 0x42, 0x44, 0x84, + 0x59, 0x36, 0x33, 0x4f, 0x41, 0xc7, 0x89, 0x35, 0x81, 0xba, 0x58, 0xc4, 0xd3, 0x97, 0x9b, 0xe6, + 0x48, 0x92, 0xf3, 0x5f, 0xf9, 0xe3, 0xd5, 0xa4, 0xfd, 0x35, 0x47, 0x9c, 0xdd, 0x68, 0xca, 0xbd, + 0x59, 0x36, 0xd5, 0x40, 0x65, 0xd7, 0xfa, 0x19, 0x6a, 0xcc, 0x17, 0xc0, 0x11, 0x2c, 0x72, 0x69, + 0x0a, 0x7a, 0x0f, 0x27, 0x21, 0x21, 0xca, 0xc7, 0x7f, 0x59, 0x27, 0x21, 0x87, 0x64, 0x8d, 0xc4, + 0xfd, 0x3b, 0x12, 0xfa, 0x96, 0xbe, 0x66, 0xd9, 0x4a, 0xf8, 0xa3, 0xd4, 0x32, 0x47, 0x81, 0x70, + 0xe1, 0x6c, 0x99, 0xe4, 0xec, 0xac, 0x2c, 0xc5, 0xb8, 0x7e, 0x2a, 0x61, 0x31, 0x1b, 0x5e, 0xfb, + 0x44, 0xbc, 0xab, 0x4c, 0x41, 0x32, 0xb1, 0xfc, 0xfa, 0x39, 0x04, 0xa9, 0x4a, 0x40, 0x50, 0x74, + 0xa3, 0x6f, 0x90, 0x1e, 0x60, 0x71, 0xb0, 0xfd, 0x6e, 0x51, 0x6b, 0xef, 0xea, 0x2f, 0xe7, 0xba, + 0x30, 0xa6, 0xe4, 0x29, 0x8b, 0x0b, 0xa2, 0xe4, 0xbf, 0x54, 0xc7, 0x38, 0xbf, 0x59, 0xab, 0x19, + 0xf2, 0xe4, 0x92, 0x88, 0x9c, 0x22, 0x4b, 0x20, 0x69, 0x83, 0x17, 0xee, 0x7b, 0x10, 0x19, 0x92, + 0xcf, 0x24, 0xd4, 0x01, 0xb5, 0x36, 0x9e, 0x93, 0x96, 0xe9, 0xe8, 0x5d, 0x77, 0x1a, 0x24, 0x9e, + 0x79, 0xef, 0x3e, 0x63, 0xe5, 0x53, 0xa7, 0x57, 0xdd, 0xab, 0x0e, 0x62, 0xa2, 0x8e, 0xc7, 0xb4, + 0xfb, 0xab, 0xa0, 0x9a, 0xdd, 0xb9, 0xe0, 0x1b, 0x66, 0x3c, 0x12, 0x9e, 0xb1, 0x9f, 0xf0, 0x5d, + 0xe0, 0x53, 0xd4, 0xb2, 0xd3, 0xeb, 0x6c, 0x86, 0xed, 0xdc, 0xe8, 0xbb, 0xa8, 0xf9, 0x92, 0x63, + 0xb2, 0xe7, 0xd9, 0x6e, 0x7b, 0x17, 0x0e, 0x7e, 0x6b, 0x84, 0x6f, 0x7d, 0x3c, 0x37, 0xe5, 0x50, + 0xef, 0x16, 0x87, 0xf5, 0xb1, 0x92, 0x9b, 0x58, 0x03, 0xef, 0x99, 0x6e, 0x3b, 0x79, 0x16, 0xb2, + 0x6c, 0x10, 0xb2, 0xa9, 0xcd, 0x6b, 0x0b, 0x71, 0x23, 0x95, 0xa9, 0xe3, 0xa7, 0x6e, 0x34, 0x31, + 0x29, 0xec, 0x0d, 0x72, 0x3d, 0xa7, 0xb9, 0x01, 0xd4, 0xcb, 0xbb, 0x11, 0xda, 0x71, 0xd1, 0xbe, + 0xbd, 0x3e, 0x53, 0xe6, 0xf8, 0x87, 0x0f, 0x2e, 0x63, 0xfe, 0x24, 0x46, 0xa9, 0x19, 0x94, 0xf5, + 0x4a, 0xdc, 0x65, 0x61, 0x7b, 0x8b, 0xce, 0xf7, 0x07, 0x3b, 0x25, 0xa3, 0x4c, 0x5c, 0x01, 0x88, + 0xd1, 0x3f, 0x5f, 0x21, 0x33, 0x26, 0xe9, 0xcd, 0x87, 0xb9, 0x69, 0xee, 0x8e, 0x45, 0xf1, 0x03, + 0x7d, 0xb5, 0x73, 0x97, 0x62, 0x9a, 0x3e, 0x80, 0xf1, 0x84, 0xdd, 0xea, 0xaa, 0x8b, 0xfd, 0x30, + 0x0e, 0x4c, 0xbb, 0xff, 0xfa, 0x74, 0x86, 0xe4, 0x35, 0x9f, 0x12, 0x04, 0x4f, 0xf7, 0x37, 0x14, + 0x05, 0xef, 0x9f, 0x56, 0xba, 0x9b, 0xb7, 0x75, 0xb5, 0x63, 0x6b, 0xa8, 0x8f, 0x75, 0x63, 0x01, + 0x10, 0x19, 0xb0, 0xea, 0xf7, 0xf4, 0x8f, 0xcb, 0x2c, 0x21, 0x35, 0x19, 0x15, 0x8d, 0xef, 0x10, + 0x4a, 0x61, 0xec, 0x09, 0xa3, 0xe0, 0xe5, 0x8b, 0x60, 0xa1, 0x04, 0xf5, 0x11, 0xe6, 0xc6, 0xba, + 0x66, 0x75, 0xa7, 0xe2, 0xed, 0x60, 0x7f, 0x53, 0xb4, 0xa7, 0x0a, 0xeb, 0x94, 0xa7, 0x33, 0x99, + 0x22, 0x36, 0xa7, 0xc1, 0xef, 0x0d, 0xfe, 0xde, 0x0d, 0x3c, 0xa6, 0x9e, 0xe7, 0x89, 0x94, 0xfd, + 0x2f, 0x40, 0xbf, 0x44, 0x42, 0xc3, 0x05, 0xcd, 0x3c, 0x8d, 0x4b, 0x70, 0xa2, 0x0a, 0x1f, 0x64, + 0x7c, 0x5e, 0x34, 0xb2, 0x49, 0x2d, 0xd2, 0x3c, 0xac, 0x6a, 0xcd, 0x8e, 0x4c, 0x1e, 0x23, 0xc6, + 0x71, 0x1d, 0x10, 0xcb, 0x61, 0x9b, 0xe8, 0xcb, 0xc8, 0x48, 0xb2, 0x7d, 0xf5, 0x0d, 0xa5, 0x6f, + 0x37, 0x2c, 0x98, 0xa6, 0x78, 0xa3, 0x87, 0x39, 0xd4, 0x19, 0x4e, 0x22, 0xb5, 0x7c, 0x09, 0xed, + 0xbe, 0x06, 0x33, 0x88, 0x57, 0xd8, 0x23, 0x25, 0xbb, 0xb4, 0xa0, 0xf2, 0xbb, 0x72, 0xa0, 0x96, + 0x25, 0xb7, 0xa1, 0x45, 0x34, 0x8c, 0x8d, 0x9d, 0x5c, 0x8f, 0xb1, 0x14, 0x88, 0x1d, 0x5c, 0xdf, + 0x7f, 0xfb, 0xa2, 0xae, 0x9c, 0x3a, 0x02, 0x92, 0xeb, 0x01, 0xf4, 0x0a, 0x55, 0x32, 0xb3, 0xdb, + 0xaa, 0xb2, 0x00, 0x42, 0xb4, 0xd7, 0x9b, 0x55, 0x64, 0x26, 0x07, 0xe9, 0x2c, 0x55, 0x88, 0xd2, + 0xea, 0x00, 0x00, 0x00, 0x00, 0x02, 0x83, 0xff, 0xff, 0xfd, 0x7c, 0x00, 0x00, 0x00, 0x01, 0x41, + 0x4d, 0x4c, 0x56, 0x86, 0x00, 0x40, 0x92, 0xe1, 0xa1, 0x56, 0x00, 0x00, 0x0c, 0x70, 0x00, 0x00, + 0x7b, 0xfb, 0xea, 0x59, 0x62, 0x8e, 0xaa, 0x5d, 0x87, 0x99, 0x92, 0xc1, 0xf4, 0x5b, 0xb2, 0xe7, + 0x85, 0x2b, 0xe7, 0x5d, 0x58, 0x57, 0xe1, 0x4e, 0xd8, 0xf4, 0xd2, 0x03, 0x54, 0x5a, 0x28, 0x1a, + 0x87, 0x5e, 0x10, 0xbb, 0x88, 0x87, 0x33, 0xba, 0x96, 0x1d, 0x8b, 0x44, 0x44, 0x27, 0x97, 0xaa, + 0x34, 0xe0, 0x4f, 0x25, 0x70, 0x75, 0x42, 0x8c, 0x03, 0x31, 0x68, 0xf4, 0x81, 0xc3, 0xb7, 0x6f, + 0x49, 0xf6, 0x75, 0xa0, 0x46, 0x0c, 0x6b, 0xb7, 0x62, 0x82, 0xda, 0xb5, 0xbf, 0x7a, 0xb7, 0xd6, + 0x3b, 0x77, 0x71, 0x44, 0xfd, 0xc2, 0xad, 0x8d, 0xfb, 0xba, 0xad, 0xab, 0xd8, 0x5c, 0x47, 0x1e, + 0x62, 0x4f, 0xfc, 0x8b, 0x02, 0xe6, 0x1a, 0x68, 0x88, 0xcc, 0x07, 0xb1, 0x56, 0xb8, 0x97, 0xba, + 0xd8, 0x66, 0x7e, 0xf1, 0xc0, 0x97, 0x20, 0xdf, 0x1d, 0x3f, 0xbc, 0xff, 0x59, 0xd5, 0xc8, 0xd6, + 0xec, 0xfe, 0xe1, 0xd8, 0x09, 0x10, 0xc4, 0x9d, 0xbf, 0x70, 0x6e, 0xe8, 0xeb, 0xa3, 0xef, 0xee, + 0xf4, 0x40, 0x70, 0x73, 0xe0, 0x16, 0x9c, 0x31, 0x3d, 0x86, 0xc8, 0x08, 0x37, 0x30, 0x4c, 0x80, + 0xf5, 0x6d, 0x57, 0x74, 0xb9, 0xd7, 0xda, 0x11, 0xa2, 0xd1, 0x1c, 0xf8, 0x04, 0xc0, 0xbc, 0x2e, + 0x51, 0x0e, 0xbb, 0xe8, 0x4b, 0x4e, 0xf8, 0xc2, 0xb1, 0xa4, 0x00, 0x93, 0xd1, 0x3f, 0xa1, 0x04, + 0x98, 0xcc, 0x12, 0xbf, 0x72, 0xa3, 0x2d, 0x27, 0x02, 0x17, 0x36, 0xc9, 0x90, 0x27, 0x91, 0xb4, + 0xe0, 0x40, 0xe0, 0xd4, 0x1d, 0xd1, 0x6b, 0xc0, 0x55, 0x9a, 0xc6, 0xdf, 0xed, 0x7c, 0x12, 0xc6, + 0x3a, 0xda, 0x65, 0xf8, 0xd3, 0x3b, 0x14, 0x02, 0xc4, 0x80, 0x9e, 0x9c, 0xed, 0x6c, 0xee, 0x1f, + 0x09, 0x9b, 0x32, 0x6b, 0xd7, 0x04, 0x06, 0xd4, 0xec, 0xcc, 0xf9, 0xf8, 0x06, 0xd7, 0xf7, 0x5a, + 0xfa, 0x24, 0x72, 0x8b, 0xd3, 0xfc, 0x2d, 0x9e, 0xea, 0x7a, 0xc2, 0x4c, 0xfc, 0xd2, 0xd0, 0x0f, + 0x49, 0x5a, 0x34, 0xf3, 0x25, 0xde, 0xaa, 0x99, 0xad, 0xba, 0x55, 0xcd, 0xa9, 0x5d, 0x15, 0x85, + 0xc1, 0x3f, 0x5a, 0x7c, 0x00, 0xe6, 0x26, 0x9a, 0x99, 0xa5, 0xad, 0x8f, 0xe3, 0x6a, 0xbc, 0xb4, + 0xae, 0x28, 0xa6, 0x9f, 0x66, 0xd2, 0x92, 0xb8, 0x9a, 0x16, 0x54, 0x8b, 0x9e, 0x50, 0xd6, 0xde, + 0xbd, 0x63, 0x75, 0x5c, 0x46, 0x69, 0xe1, 0x84, 0xa6, 0x8a, 0x78, 0x18, 0x9d, 0xbc, 0x3f, 0xeb, + 0xe9, 0x9f, 0xe2, 0x27, 0xd8, 0x1d, 0x99, 0x6e, 0xc4, 0x55, 0x2c, 0x48, 0x57, 0x84, 0xf0, 0x86, + 0x6c, 0x65, 0x05, 0x3c, 0xcb, 0x56, 0x0e, 0x68, 0xed, 0x71, 0x70, 0x98, 0x74, 0x6d, 0x2f, 0xf7, + 0xcf, 0x30, 0x2d, 0x48, 0x65, 0x9f, 0x06, 0xcc, 0x24, 0xe6, 0x3a, 0x3a, 0x36, 0x8d, 0xd0, 0xcd, + 0x2c, 0xd3, 0x63, 0x52, 0x83, 0x54, 0xf2, 0xe9, 0x7b, 0x89, 0x62, 0xe5, 0x3a, 0x3f, 0x54, 0xa4, + 0x2f, 0x08, 0xff, 0xae, 0x20, 0xf1, 0xae, 0xb6, 0xb2, 0xb0, 0x7b, 0xbc, 0x50, 0xda, 0xd9, 0xb7, + 0xed, 0x9b, 0xf0, 0xc7, 0xd2, 0x9d, 0xb9, 0x29, 0x9e, 0x11, 0x99, 0x4f, 0xa0, 0xce, 0x21, 0x47, + 0x2e, 0x79, 0x60, 0x1c, 0x17, 0x54, 0xbd, 0x54, 0xa4, 0x6f, 0xcb, 0x77, 0x39, 0x9b, 0x20, 0xc5, + 0x6b, 0x92, 0xae, 0x6d, 0x8b, 0xce, 0xb2, 0x1f, 0x75, 0x7e, 0x7a, 0x55, 0x9f, 0x42, 0xa4, 0xb1, + 0x02, 0xf2, 0xbc, 0x5a, 0x5b, 0x9c, 0xe2, 0xf1, 0x91, 0x93, 0x2f, 0x48, 0xeb, 0x46, 0x9c, 0xa1, + 0xa0, 0x27, 0x32, 0xde, 0xa3, 0x00, 0xfa, 0x6a, 0x1d, 0x7c, 0x56, 0x40, 0x37, 0xa7, 0xec, 0x1d, + 0xff, 0x12, 0x9a, 0xc4, 0xe8, 0xce, 0xfc, 0x57, 0xae, 0xeb, 0x17, 0x09, 0xe9, 0xab, 0xb8, 0x37, + 0x61, 0x30, 0x6d, 0xd4, 0xad, 0xa2, 0x47, 0xc1, 0x97, 0xd4, 0xd5, 0x94, 0x1a, 0x39, 0x3e, 0x45, + 0x43, 0x47, 0x8a, 0x67, 0xf4, 0x12, 0x5d, 0x52, 0xf1, 0xbf, 0x53, 0x55, 0x69, 0x82, 0x0f, 0x0a, + 0x05, 0xa5, 0x79, 0x57, 0xd4, 0xd5, 0x12, 0x26, 0x7e, 0xa5, 0xe6, 0x3c, 0xc1, 0x09, 0x31, 0x28, + 0x3e, 0x5c, 0xea, 0x0e, 0x95, 0xb3, 0x22, 0xc0, 0x0d, 0x37, 0x3f, 0x2b, 0x19, 0xc4, 0xe0, 0xab, + 0x66, 0xc9, 0x40, 0x02, 0x77, 0x6e, 0x99, 0x69, 0xdd, 0x70, 0x67, 0x83, 0xc9, 0x28, 0xe4, 0xb1, + 0x24, 0xf9, 0xb3, 0x5b, 0x43, 0x54, 0xa0, 0xac, 0x6f, 0x97, 0x8e, 0x5e, 0x22, 0x81, 0x4b, 0xb8, + 0xcb, 0x68, 0x3d, 0xda, 0xa1, 0xde, 0xa1, 0x67, 0x2a, 0x1b, 0x79, 0xc1, 0xdd, 0x70, 0x5c, 0x0a, + 0xd4, 0x00, 0x00, 0x00, 0x02, 0x83, 0xff, 0xff, 0xfd, 0x7c, 0x00, 0x00, 0x00, 0x01, 0x41, 0x4d, + 0x4c, 0x56, 0x86, 0x00, 0x40, 0x92, 0xe1, 0x91, 0x56, 0x00, 0x00, 0x0c, 0x70, 0x00, 0x00, 0x7f, + 0xd3, 0x15, 0x8a, 0x8a, 0xcd, 0xb2, 0xee, 0x76, 0x8b, 0xe2, 0x04, 0x22, 0xe9, 0x74, 0xee, 0x1d, + 0x6e, 0x7f, 0xa1, 0x7f, 0x27, 0x4e, 0xa8, 0x2c, 0x9a, 0xb9, 0x53, 0x00, 0x68, 0xcc, 0xf9, 0xb3, + 0xf8, 0xb6, 0xea, 0xfc, 0xe9, 0x7b, 0xac, 0x1f, 0x96, 0x4e, 0x4f, 0xdc, 0x18, 0x70, 0xfc, 0x16, + 0x66, 0x5d, 0x74, 0x5b, 0xe6, 0x5e, 0x28, 0x76, 0xbe, 0xb8, 0xc8, 0xaf, 0x1d, 0x9a, 0xa4, 0x55, + 0x26, 0x71, 0x80, 0x88, 0x5f, 0x0c, 0xbd, 0x88, 0xd5, 0x8d, 0x91, 0x54, 0x8f, 0xcb, 0xeb, 0x24, + 0xb4, 0x39, 0x99, 0xaa, 0xf2, 0x0a, 0x90, 0xe4, 0x41, 0x69, 0xe8, 0xf4, 0xce, 0x21, 0x67, 0xcc, + 0xdf, 0x86, 0x29, 0x47, 0x26, 0xf0, 0xf2, 0x5a, 0x81, 0x32, 0xe9, 0xc3, 0x86, 0x4d, 0xc9, 0xef, + 0xd6, 0x77, 0x51, 0xcc, 0x6b, 0x79, 0x45, 0x9c, 0xda, 0x96, 0x07, 0xa5, 0x0d, 0x03, 0x04, 0x43, + 0x07, 0x54, 0x56, 0xde, 0xb3, 0x6a, 0xf9, 0xbb, 0x3f, 0xf3, 0xf2, 0x8b, 0xb9, 0x2f, 0x98, 0x69, + 0xc8, 0xd3, 0x50, 0x2c, 0x3d, 0xdd, 0xab, 0x5c, 0x8c, 0x56, 0xc7, 0x61, 0xaf, 0xbd, 0x55, 0xe1, + 0x2e, 0xe2, 0x6f, 0x0f, 0x4b, 0x10, 0x07, 0xc1, 0x13, 0x14, 0xd6, 0x8a, 0xab, 0x6f, 0x9a, 0x52, + 0x6a, 0x41, 0x91, 0x30, 0xf3, 0x45, 0xce, 0x47, 0xf0, 0x16, 0x90, 0xb3, 0x06, 0xc6, 0xf7, 0x23, + 0x9c, 0x61, 0xad, 0xc6, 0x07, 0x5f, 0xef, 0x64, 0x2f, 0x73, 0x47, 0x4e, 0xe1, 0x23, 0xa7, 0xf6, + 0xa8, 0x3a, 0x79, 0xa1, 0x5f, 0xd5, 0x6e, 0xdb, 0x40, 0x6b, 0x26, 0xb9, 0x7e, 0x15, 0xc1, 0xf1, + 0x1b, 0xeb, 0x3c, 0x10, 0xbd, 0x53, 0xa6, 0x27, 0xdf, 0xb9, 0x8c, 0x09, 0xd2, 0x8d, 0x1d, 0x67, + 0xfd, 0xfb, 0xee, 0x5c, 0x9b, 0x4b, 0xc7, 0x68, 0x08, 0x02, 0x5d, 0x3d, 0xf2, 0xab, 0x8f, 0xf9, + 0x32, 0xac, 0x2c, 0x85, 0x14, 0x17, 0xae, 0x95, 0x7d, 0xea, 0x92, 0xf8, 0x45, 0x28, 0xa3, 0x84, + 0x93, 0x7a, 0xe2, 0x03, 0x07, 0x2f, 0x80, 0x18, 0xc7, 0x4f, 0xf0, 0x23, 0xe8, 0x1f, 0x20, 0x25, + 0x1d, 0xa3, 0x2b, 0x9b, 0xde, 0x0f, 0x35, 0x1b, 0x59, 0x93, 0x06, 0xab, 0x8a, 0xbf, 0x30, 0x04, + 0xae, 0xfb, 0xfa, 0x65, 0x4f, 0xab, 0x65, 0xe1, 0x9c, 0x57, 0x4e, 0x2f, 0xd7, 0x37, 0xfc, 0x95, + 0x64, 0xf4, 0x02, 0x84, 0xa0, 0x51, 0xae, 0xd4, 0x54, 0xff, 0xae, 0x16, 0x9d, 0xa5, 0x68, 0x94, + 0x15, 0xf2, 0xe1, 0xca, 0x57, 0x80, 0x83, 0x89, 0xcf, 0xfe, 0x66, 0x73, 0x26, 0x0c, 0x8e, 0xdc, + 0xad, 0x93, 0xa6, 0x98, 0x96, 0xf0, 0xe7, 0xcd, 0xeb, 0xc2, 0x78, 0x33, 0x05, 0x05, 0x98, 0x28, + 0xf5, 0x81, 0xba, 0xb6, 0xe7, 0xa7, 0x41, 0x9c, 0xb9, 0x96, 0xf1, 0xa4, 0x13, 0xb1, 0xbc, 0xd8, + 0x77, 0x1b, 0x98, 0x60, 0x35, 0x45, 0xb8, 0x54, 0x6c, 0x36, 0xb4, 0x38, 0xe2, 0xaa, 0xb9, 0x39, + 0x99, 0xbc, 0x59, 0x65, 0xfe, 0x01, 0x21, 0x15, 0x65, 0x8d, 0x2c, 0x88, 0x08, 0x5f, 0x7f, 0x38, + 0x73, 0x55, 0x7e, 0x3e, 0x06, 0x81, 0xf6, 0xa0, 0x5c, 0xa3, 0xfd, 0xce, 0xe2, 0x40, 0x42, 0xdf, + 0x8a, 0x9e, 0x72, 0x13, 0xe6, 0xd1, 0x71, 0x4e, 0x1c, 0x96, 0x59, 0x0a, 0x5c, 0xeb, 0xc9, 0x79, + 0x79, 0xc9, 0x5e, 0xfc, 0xd9, 0x65, 0xad, 0x55, 0x5f, 0x19, 0xd1, 0xe7, 0x20, 0x10, 0xe2, 0xb7, + 0x54, 0x46, 0x96, 0x92, 0x64, 0x79, 0x85, 0xc9, 0xb9, 0xdb, 0x02, 0x4b, 0xb3, 0xc6, 0x2c, 0xf0, + 0x0f, 0xc9, 0x2d, 0xa7, 0x8b, 0x32, 0x20, 0x30, 0xfd, 0xbd, 0x65, 0x1b, 0x86, 0xaf, 0x27, 0xc7, + 0x3c, 0xb0, 0xdb, 0xd1, 0x60, 0x94, 0xc2, 0x99, 0xa7, 0x37, 0xfb, 0x6a, 0x92, 0x21, 0x22, 0x61, + 0x7e, 0x59, 0xb1, 0x74, 0xe2, 0xcd, 0x98, 0x90, 0x2c, 0xf2, 0x48, 0x51, 0x3c, 0xec, 0xfa, 0xf7, + 0x7c, 0xd1, 0xa1, 0x00, 0x98, 0x30, 0x33, 0x02, 0x6d, 0xf3, 0xfd, 0x2a, 0x92, 0x8a, 0x76, 0x55, + 0x84, 0x99, 0x9d, 0xd1, 0x23, 0x80, 0x40, 0xde, 0x90, 0x0a, 0x57, 0xfe, 0x48, 0x05, 0x6e, 0x47, + 0x51, 0xa6, 0xd4, 0x7e, 0xd0, 0x43, 0x6f, 0x61, 0x18, 0xea, 0x05, 0xe3, 0x66, 0x6e, 0xdc, 0xed, + 0x48, 0x4d, 0x53, 0xfa, 0x3d, 0x27, 0xb6, 0xbb, 0x54, 0xb0, 0x14, 0xe7, 0xde, 0xb8, 0x02, 0xe2, + 0xf2, 0x75, 0x2e, 0xee, 0x47, 0x2b, 0x9e, 0xe6, 0x8a, 0xb6, 0x77, 0x95, 0xbb, 0xf1, 0x67, 0x0f, + 0x96, 0xbc, 0x06, 0x46, 0x0b, 0xa0, 0x4b, 0xef, 0x76, 0x84, 0x16, 0x14, 0x0c, 0x74, 0xd6, 0xf1, + 0x00, 0x00, 0x00, 0x02, 0x7b, 0xff, 0xff, 0xfd, 0x84, 0x00, 0x00, 0x00, 0x01, 0x41, 0x4d, 0x4c, + 0x56, 0x86, 0x00, 0x40, 0x92, 0xe1, 0x91, 0x56, 0x00, 0x00, 0x0c, 0x70, 0x00, 0x00, 0x7f, 0x76, + 0x8b, 0xd1, 0xc9, 0x38, 0x2b, 0x3f, 0xac, 0xf0, 0xee, 0x99, 0x34, 0xcc, 0x6e, 0xcb, 0x35, 0x6b, + 0xd1, 0xb6, 0x68, 0x0f, 0x76, 0x12, 0x2d, 0x32, 0x86, 0xce, 0x9b, 0x22, 0xaa, 0xe8, 0x2c, 0x54, + 0xe3, 0x30, 0xf3, 0x0a, 0xbe, 0xbb, 0x1c, 0x43, 0x8a, 0x4f, 0x5c, 0x89, 0xd0, 0x18, 0x0b, 0x74, + 0xc9, 0xf6, 0xe5, 0x16, 0xb8, 0xb5, 0x47, 0x23, 0x64, 0xb8, 0x38, 0xa8, 0x9d, 0xb8, 0x3f, 0xe5, + 0xa3, 0x36, 0xd0, 0x62, 0x2a, 0xd7, 0x6e, 0x5b, 0xff, 0x4c, 0x4a, 0xc8, 0xfa, 0x76, 0xc3, 0xe1, + 0x8c, 0x7b, 0xdd, 0xa8, 0xe8, 0x24, 0xbf, 0x2b, 0x9b, 0xcd, 0x6c, 0xa0, 0x82, 0x17, 0xef, 0x2c, + 0xf4, 0xb2, 0x97, 0xee, 0x99, 0x29, 0xd7, 0x0e, 0x54, 0x6a, 0xfe, 0xe1, 0x88, 0x3a, 0x16, 0x9c, + 0x1f, 0x1d, 0x91, 0xe4, 0x6f, 0xfc, 0xa4, 0x5a, 0xfd, 0x24, 0x57, 0x3d, 0x2d, 0x42, 0xb6, 0x64, + 0xda, 0x55, 0xfd, 0x28, 0x5c, 0x93, 0x2b, 0x8c, 0xa0, 0x0e, 0x2b, 0x93, 0x42, 0x2a, 0xe1, 0xcd, + 0xee, 0x10, 0xc1, 0x03, 0xdc, 0xa4, 0xc0, 0xf5, 0xf9, 0x7f, 0x33, 0xe2, 0xf4, 0x90, 0x27, 0x92, + 0x11, 0x20, 0xa1, 0x14, 0x42, 0xe4, 0xff, 0x0d, 0x07, 0x28, 0x6e, 0xbc, 0x3b, 0xbc, 0xe8, 0x72, + 0xe2, 0xe5, 0xbe, 0xa6, 0x27, 0x5b, 0x02, 0x5c, 0xcf, 0x9c, 0x09, 0x32, 0x25, 0xca, 0xf8, 0x03, + 0x94, 0xbd, 0x5c, 0x6f, 0x41, 0xff, 0x6d, 0x29, 0x8e, 0xfa, 0x05, 0xfe, 0xf0, 0x42, 0x2e, 0xa8, + 0xfa, 0x30, 0x4a, 0x22, 0x13, 0x21, 0x5e, 0xc5, 0xa0, 0x9e, 0xfe, 0xb2, 0x93, 0xb5, 0x6a, 0xb3, + 0x44, 0xf7, 0x51, 0x22, 0xdf, 0x02, 0x01, 0x0a, 0x28, 0xd8, 0x9f, 0xae, 0xf0, 0x9e, 0x89, 0x82, + 0x7b, 0x94, 0x3c, 0x50, 0x43, 0x5a, 0xc5, 0xbe, 0x43, 0x4e, 0x3e, 0xa3, 0xe0, 0x33, 0xa0, 0x99, + 0x7c, 0x4e, 0x3b, 0x5a, 0x85, 0x06, 0x94, 0xc7, 0xfd, 0xe8, 0x6a, 0x7d, 0xa2, 0x8b, 0x4d, 0x14, + 0xd9, 0xd8, 0xbf, 0x86, 0x53, 0xc0, 0xa0, 0x3d, 0xe3, 0x0f, 0x85, 0xa6, 0xe0, 0xc2, 0xc3, 0x73, + 0x6e, 0x27, 0xff, 0xbe, 0x30, 0x53, 0x3f, 0x76, 0x2d, 0x85, 0xb9, 0xf4, 0x39, 0x51, 0xb7, 0xae, + 0x4c, 0x08, 0x08, 0x5b, 0xd8, 0xe1, 0x6d, 0x8f, 0x01, 0x0f, 0x98, 0x70, 0xdb, 0x49, 0x21, 0x18, + 0x15, 0x4e, 0xce, 0xc4, 0xb6, 0xd5, 0xa0, 0x72, 0xc6, 0x4b, 0x6b, 0x82, 0x8b, 0x7b, 0x85, 0x39, + 0xdb, 0x97, 0xf2, 0xd4, 0x03, 0x07, 0x44, 0xc5, 0xbd, 0x9d, 0xc3, 0xb6, 0x86, 0x76, 0xca, 0xd1, + 0xd6, 0x5a, 0xf8, 0x41, 0x68, 0xe3, 0xa8, 0x5a, 0xa2, 0xe8, 0x0d, 0xf8, 0x3e, 0xcd, 0x28, 0x7d, + 0x5f, 0x9c, 0x38, 0x4d, 0x7c, 0x63, 0xd3, 0x8e, 0xa7, 0x5a, 0xa7, 0x21, 0x1f, 0xc4, 0xde, 0x64, + 0xf0, 0x7f, 0x05, 0xf5, 0xa8, 0xdd, 0x6c, 0xd5, 0x4f, 0x8c, 0x14, 0x65, 0x9b, 0xe9, 0x3e, 0xcb, + 0x0c, 0xf4, 0x94, 0x3b, 0x12, 0xb1, 0xec, 0xf5, 0x15, 0x22, 0x1e, 0x47, 0x02, 0x6d, 0xa4, 0x8f, + 0x08, 0xe1, 0x84, 0x2a, 0x26, 0xec, 0x95, 0x29, 0x7a, 0xf3, 0xcd, 0x48, 0x61, 0x65, 0xb0, 0xff, + 0xba, 0x0e, 0xd8, 0x56, 0x6b, 0x5f, 0x5e, 0xdd, 0xdc, 0x43, 0x12, 0x54, 0x1f, 0xa6, 0xea, 0x27, + 0x5d, 0x97, 0x5c, 0xfe, 0xd6, 0xb3, 0xaa, 0xc1, 0xd6, 0x37, 0x19, 0xdc, 0xa8, 0xfc, 0x76, 0xdb, + 0x81, 0x54, 0x10, 0xa6, 0xb7, 0xc1, 0xb1, 0xb9, 0x42, 0x54, 0xb8, 0x69, 0xd6, 0x5b, 0xdf, 0x8c, + 0xd2, 0x85, 0x4b, 0xdf, 0x80, 0x36, 0x1e, 0x31, 0x4d, 0xa1, 0x1a, 0x56, 0xb8, 0x2a, 0x6c, 0x59, + 0x33, 0x11, 0x1c, 0xe6, 0x36, 0x1b, 0xba, 0x6b, 0x55, 0x82, 0x8c, 0x69, 0x89, 0xe2, 0x7a, 0xf6, + 0x95, 0x53, 0xd9, 0x29, 0xd0, 0x06, 0xfb, 0x38, 0xf2, 0x38, 0xf6, 0x12, 0x8e, 0x54, 0x16, 0xd8, + 0x3b, 0xfa, 0x5a, 0x7e, 0x63, 0x01, 0xd7, 0x98, 0x7e, 0x74, 0xdf, 0x47, 0xc7, 0x84, 0x72, 0x2d, + 0x5d, 0x0a, 0xff, 0xac, 0xdf, 0x7f, 0x31, 0xa7, 0x6b, 0xf8, 0x63, 0x95, 0x4a, 0xfe, 0x81, 0x06, + 0x3a, 0x23, 0xba, 0x30, 0x9d, 0x2f, 0x00, 0x27, 0xd7, 0x54, 0xa3, 0xbd, 0xfa, 0x9f, 0xc8, 0x35, + 0x1d, 0x1f, 0x63, 0x1c, 0xe7, 0x67, 0xf2, 0xf4, 0xf2, 0x47, 0x7d, 0x9d, 0xce, 0xa5, 0xe6, 0x28, + 0x7d, 0x93, 0x5a, 0x85, 0xdc, 0x51, 0x4c, 0x63, 0x52, 0xfe, 0xe9, 0x46, 0x87, 0x42, 0x6f, 0xe2, + 0x59, 0x85, 0xb2, 0x51, 0xda, 0x55, 0x40, 0x00, 0x00, 0x00, 0x02, 0xf5, 0xff, 0xff, 0xfd, 0x0a, + 0x00, 0x00, 0x00, 0x01, 0x41, 0x4d, 0x4c, 0x56, 0x86, 0x00, 0x40, 0x92, 0xe1, 0x41, 0x56, 0x00, + 0x00, 0x0c, 0x70, 0x00, 0x00, 0x7f, 0x5f, 0x5a, 0x76, 0xc1, 0xa8, 0xce, 0xa1, 0x96, 0xe3, 0x34, + 0xa0, 0x35, 0x06, 0xd0, 0xd8, 0x43, 0x47, 0xf4, 0xe8, 0xed, 0xe6, 0xea, 0x69, 0xfa, 0xaa, 0x31, + 0xab, 0x53, 0x27, 0x82, 0x67, 0xc4, 0x30, 0xff, 0x82, 0xcf, 0xaa, 0xb8, 0x66, 0x4d, 0xdb, 0xd9, + 0xe4, 0xf1, 0x55, 0x11, 0x36, 0x9f, 0xa8, 0x11, 0x6a, 0xcb, 0x50, 0xdd, 0x95, 0x67, 0xf5, 0xba, + 0x2c, 0x69, 0x04, 0xb0, 0xb0, 0x11, 0xad, 0x21, 0xc6, 0xec, 0x3e, 0x2e, 0xe5, 0x28, 0x7f, 0x53, + 0x06, 0xd2, 0x5d, 0x66, 0x5e, 0x81, 0x21, 0x13, 0xa7, 0x62, 0x12, 0x84, 0x3d, 0x1e, 0xcc, 0x49, + 0x1c, 0x99, 0xb4, 0x33, 0xcf, 0xfb, 0xb1, 0x41, 0x5e, 0x88, 0x26, 0x2f, 0xd3, 0xbf, 0xcf, 0x2e, + 0x9d, 0x1c, 0x81, 0x9d, 0xbe, 0xcc, 0x8c, 0x0d, 0x5b, 0xd0, 0xb2, 0xb7, 0xc0, 0xb8, 0x53, 0xb0, + 0x7d, 0x3a, 0xb7, 0x63, 0x66, 0xa2, 0xc0, 0xd8, 0x08, 0x76, 0x26, 0xc7, 0xe0, 0x85, 0x98, 0x2b, + 0x39, 0xa6, 0x65, 0xe5, 0x1c, 0xad, 0xe4, 0x9e, 0x82, 0xa4, 0x7c, 0x71, 0x31, 0x07, 0xca, 0xec, + 0x47, 0xb4, 0x75, 0x3e, 0x2b, 0x65, 0x0c, 0x9b, 0x1c, 0x2d, 0xcc, 0xa3, 0x40, 0x40, 0xd6, 0xdd, + 0x21, 0xa1, 0x10, 0x76, 0x35, 0x13, 0xb3, 0x1a, 0xd3, 0x43, 0x87, 0xf2, 0xbc, 0x28, 0xde, 0x82, + 0x59, 0x4c, 0x3d, 0xad, 0x33, 0x8d, 0xc5, 0x96, 0x25, 0x86, 0xa3, 0x33, 0x95, 0x36, 0x85, 0x08, + 0xb1, 0x95, 0xd5, 0xb6, 0x5a, 0xaa, 0xb3, 0x77, 0xf9, 0xbd, 0xd0, 0xb4, 0x4a, 0xc7, 0x7c, 0x00, + 0x38, 0x72, 0x90, 0x37, 0xc8, 0x40, 0x00, 0xc8, 0xbb, 0x51, 0x0e, 0x77, 0x71, 0x48, 0x4f, 0xf9, + 0x92, 0x54, 0x01, 0xc9, 0x02, 0xe2, 0x36, 0xac, 0x41, 0x54, 0x64, 0xcd, 0xc5, 0x16, 0x64, 0x2e, + 0x6c, 0x8e, 0x63, 0xe8, 0xea, 0x48, 0x61, 0x74, 0x6a, 0xcb, 0xb6, 0x11, 0x97, 0x19, 0x68, 0xc3, + 0x86, 0x18, 0x8e, 0x1e, 0x28, 0x21, 0xe7, 0xa3, 0x4c, 0xed, 0x23, 0x3f, 0xbc, 0x26, 0xe5, 0x92, + 0xda, 0xc1, 0x9b, 0x63, 0xab, 0xda, 0xd9, 0xa3, 0x5a, 0x17, 0x48, 0xbd, 0x89, 0xd2, 0x3e, 0x14, + 0x3b, 0x1b, 0xc0, 0x6d, 0xe7, 0x3d, 0x86, 0x85, 0x45, 0xe2, 0x9e, 0x7f, 0xff, 0x63, 0x07, 0xe6, + 0x12, 0x23, 0xa9, 0x1c, 0x53, 0x24, 0xc8, 0xe1, 0x89, 0xee, 0xe7, 0x72, 0x07, 0x04, 0x11, 0x8c, + 0xcb, 0x66, 0x61, 0x23, 0x6d, 0x68, 0xe2, 0xaa, 0xb7, 0xf8, 0xb6, 0xd8, 0xb4, 0x6c, 0x13, 0xc4, + 0xd6, 0xba, 0x08, 0xa0, 0x05, 0x23, 0xdc, 0xad, 0xed, 0xff, 0x6d, 0x1b, 0x03, 0x3e, 0xf2, 0x1c, + 0xf6, 0xdd, 0x2a, 0xf1, 0x18, 0x76, 0x2e, 0x82, 0x38, 0xa4, 0xb7, 0x3e, 0xab, 0x74, 0x24, 0x79, + 0x83, 0x0b, 0x2e, 0x8e, 0x0b, 0x19, 0x05, 0x52, 0x20, 0x78, 0x9a, 0xe8, 0x57, 0x77, 0xde, 0xd5, + 0x36, 0xab, 0x60, 0x2b, 0xd5, 0x58, 0x6b, 0xf8, 0x64, 0xdf, 0xeb, 0x52, 0xad, 0x4b, 0xe5, 0x8b, + 0x05, 0x6a, 0x90, 0xcc, 0x72, 0x8a, 0x3a, 0x95, 0xd0, 0x31, 0xa5, 0x75, 0x3a, 0xdd, 0x08, 0xf5, + 0xd5, 0x3f, 0x76, 0x9e, 0x29, 0x7d, 0x4e, 0xb7, 0x93, 0x75, 0xc3, 0xd5, 0x38, 0xdf, 0x97, 0x7c, + 0xf0, 0x15, 0x4a, 0x5c, 0x52, 0x64, 0x3a, 0xf6, 0x1e, 0x26, 0x2f, 0xc6, 0xc8, 0xa3, 0x5a, 0x9f, + 0x40, 0x53, 0x7a, 0x4b, 0x5c, 0x94, 0xe2, 0x79, 0x07, 0x23, 0x06, 0x3e, 0xe5, 0xee, 0x4f, 0xed, + 0x0f, 0x37, 0x19, 0xd8, 0x84, 0xdb, 0x02, 0x69, 0x20, 0x57, 0x4d, 0x08, 0x81, 0xf9, 0x44, 0x13, + 0x41, 0x02, 0x79, 0x4b, 0x3f, 0xc9, 0x07, 0x16, 0xe2, 0xb1, 0x73, 0x43, 0x9d, 0x04, 0xea, 0x8c, + 0xda, 0x4f, 0x85, 0x30, 0x12, 0xc4, 0x87, 0xb4, 0x18, 0x0a, 0x18, 0x32, 0x0c, 0x77, 0xc4, 0x1e, + 0xa2, 0x23, 0xfa, 0xcf, 0xbd, 0x8b, 0x35, 0xf4, 0x4c, 0x4e, 0x75, 0x1a, 0x80, 0xf9, 0x2c, 0xc5, + 0x0b, 0x81, 0x7a, 0x40, 0x36, 0xa0, 0x58, 0x86, 0xf3, 0xdd, 0x2d, 0x71, 0xc7, 0x8f, 0x05, 0xd0, + 0x81, 0xf2, 0xb9, 0xb2, 0x7e, 0xd9, 0x65, 0x73, 0x4f, 0x8d, 0x1c, 0xed, 0x09, 0x9b, 0xcd, 0xdd, + 0xdd, 0x9a, 0xa0, 0x22, 0x5c, 0x5b, 0xc5, 0xf5, 0xda, 0x8d, 0x01, 0x87, 0x8e, 0x01, 0xe3, 0x12, + 0x5c, 0xb2, 0x23, 0x2a, 0x94, 0x65, 0xa6, 0x9a, 0x87, 0xf8, 0x63, 0x5f, 0x4c, 0xf0, 0x18, 0xe2, + 0x0c, 0xb8, 0x8d, 0xdc, 0x4d, 0x7c, 0x50, 0xa2, 0xe1, 0x87, 0x49, 0x86, 0xb4, 0x38, 0xec, 0xd3, + 0x5d, 0x22, 0x27, 0x42, 0xdc, 0xae, 0x8b, 0x7f, 0xbe, 0x4e, 0x1d, 0xad, 0x06, 0xc9, 0xd0, 0x98, + 0x1f, 0x67, 0x2a, 0x22, 0x19, 0x90, 0xbb, 0x8f, 0xef, 0x42, 0x23, 0xc1, 0xd2, 0x51, 0xd1, 0x9c, + 0x5b, 0xa0, 0x3a, 0x56, 0xae, 0x94, 0x4e, 0x0c, 0x17, 0x5e, 0x82, 0xe7, 0x21, 0xfd, 0x0e, 0xa6, + 0x66, 0xb7, 0x8e, 0x9c, 0x8d, 0x4b, 0x02, 0x63, 0xdf, 0x1c, 0x7a, 0x0c, 0xd9, 0xca, 0x24, 0xc5, + 0x1d, 0xb3, 0x29, 0xff, 0x48, 0x16, 0x48, 0x3d, 0x75, 0xd2, 0xb9, 0x44, 0x00, 0xdc, 0x3e, 0xcb, + 0x37, 0xd9, 0xee, 0x16, 0xce, 0xb7, 0x50, 0x10, 0xad, 0xa8, 0x1f, 0xa0, 0xdb, 0x2f, 0x57, 0xd1, + 0xb6, 0x44, 0x87, 0x00, 0x79, 0xc2, 0x25, 0x03, 0xa8, 0x7a, 0x94, 0xea, 0x02, 0x6b, 0x56, 0x6c, + 0x1c, 0x77, 0x35, 0xd8, 0x85, 0x82, 0xbb, 0x6e, 0x80, 0x00, 0x00, 0x03, 0x2a, 0xff, 0xff, 0xfc, + 0xd5, 0x00, 0x00, 0x00, 0x01, 0x41, 0x4d, 0x4c, 0x56, 0x86, 0x00, 0x40, 0x92, 0xe1, 0x81, 0x56, + 0x00, 0x00, 0x14, 0x70, 0x96, 0xc0, 0x00, 0x00, 0x7f, 0xfa, 0x45, 0x6a, 0x6e, 0xe1, 0x2e, 0x61, + 0x4a, 0x49, 0x88, 0x35, 0x59, 0x20, 0x91, 0xb6, 0x0d, 0xe2, 0xdf, 0xa8, 0xab, 0xf2, 0xb1, 0xb8, + 0xf6, 0x9c, 0x9e, 0xc6, 0x50, 0x06, 0xec, 0x2f, 0x9a, 0x9e, 0x91, 0x94, 0x36, 0x4d, 0x13, 0x75, + 0xf0, 0x4e, 0x63, 0xdc, 0x85, 0xa1, 0xdc, 0x3f, 0x09, 0x4a, 0x4b, 0xd4, 0x08, 0x70, 0x94, 0xc9, + 0x73, 0x5b, 0x50, 0x71, 0xa3, 0x32, 0x65, 0xe6, 0x9e, 0xe5, 0xd7, 0xc5, 0x4d, 0xa5, 0x02, 0x5a, + 0x00, 0x75, 0xd9, 0x80, 0xc9, 0x95, 0x79, 0x47, 0xb1, 0x30, 0xac, 0x8b, 0xf0, 0x3c, 0xd1, 0x57, + 0xe1, 0xf3, 0x6f, 0x39, 0xe0, 0x5c, 0x6c, 0x89, 0x7c, 0x80, 0x78, 0x32, 0x0e, 0x2a, 0x95, 0xf0, + 0x52, 0x88, 0x63, 0x30, 0xfc, 0x2f, 0xe2, 0x2d, 0x0a, 0xb6, 0x1e, 0xa4, 0xd5, 0x59, 0x32, 0x99, + 0x82, 0xc4, 0x2c, 0x77, 0x89, 0x5d, 0x28, 0xab, 0x0f, 0x07, 0xed, 0xa3, 0x02, 0xc2, 0x0c, 0x95, + 0x45, 0xdc, 0x0b, 0x2e, 0xa6, 0x96, 0x1d, 0x2a, 0x36, 0x90, 0xa9, 0x03, 0xcd, 0x09, 0x2e, 0xc9, + 0x95, 0x28, 0x73, 0xf2, 0x1b, 0x2b, 0x3a, 0x5e, 0x66, 0xf0, 0xf8, 0x50, 0xac, 0xf5, 0x23, 0x98, + 0xa0, 0xb2, 0xc0, 0xe7, 0x0b, 0xc4, 0x93, 0x97, 0x0a, 0xbe, 0x83, 0x82, 0x56, 0x4c, 0xa9, 0xd9, + 0x32, 0x0f, 0x88, 0xc5, 0xd8, 0x30, 0xac, 0x6f, 0x92, 0x42, 0x94, 0x64, 0xb1, 0x33, 0x95, 0x27, + 0x0b, 0x3a, 0x69, 0x4a, 0xbd, 0x60, 0x75, 0x9d, 0xb5, 0xc5, 0x82, 0x15, 0xa7, 0x0d, 0x27, 0xe9, + 0x5b, 0xf0, 0x1e, 0x40, 0x6c, 0x6b, 0x6d, 0x48, 0xff, 0x77, 0x4e, 0xfc, 0x58, 0x33, 0xc0, 0x00, + 0x58, 0x62, 0xfc, 0xe3, 0x0e, 0xa2, 0xc5, 0xf7, 0xd9, 0x38, 0x5d, 0xbb, 0x80, 0x4b, 0x1d, 0x36, + 0x3d, 0x63, 0xf0, 0x3c, 0xaa, 0x83, 0x9f, 0x12, 0x7b, 0x48, 0x98, 0xad, 0x67, 0xda, 0x18, 0x4a, + 0x4e, 0x79, 0x7c, 0xd9, 0xb9, 0xda, 0x2d, 0x32, 0xe3, 0x6a, 0x6b, 0x5c, 0xf4, 0xbb, 0xfe, 0x52, + 0x3e, 0xee, 0xe6, 0x37, 0xc3, 0x10, 0xfc, 0xd5, 0xf2, 0x7d, 0xca, 0xef, 0x60, 0x25, 0xa0, 0x0e, + 0x3e, 0xe2, 0xb3, 0x26, 0xba, 0xac, 0xea, 0x87, 0x66, 0xd8, 0xa6, 0xe6, 0x2d, 0x3b, 0x77, 0x25, + 0xe2, 0x84, 0x32, 0x85, 0x27, 0x7d, 0x20, 0x97, 0xd5, 0x5c, 0x49, 0x71, 0x16, 0x95, 0x10, 0x30, + 0x27, 0x67, 0xa3, 0xd4, 0x5e, 0x5a, 0x8c, 0xcf, 0x56, 0x37, 0xa9, 0x04, 0xb1, 0xec, 0xd8, 0x69, + 0x90, 0xca, 0x37, 0x0d, 0x4f, 0x82, 0x91, 0x58, 0x0e, 0xf6, 0xfe, 0x84, 0xa5, 0x7b, 0xa8, 0xac, + 0x99, 0x23, 0x01, 0xa6, 0x37, 0x8a, 0x50, 0x0e, 0x27, 0x47, 0x96, 0x37, 0xb6, 0x13, 0x47, 0xb1, + 0x6f, 0xe9, 0xb1, 0xeb, 0xe6, 0x73, 0x6b, 0xf2, 0xd8, 0x5a, 0x3c, 0x55, 0xb4, 0x87, 0x3f, 0x1c, + 0x96, 0x94, 0x84, 0xd9, 0x3d, 0x6f, 0x51, 0xc6, 0x06, 0xc6, 0x40, 0x5f, 0xde, 0x9a, 0x4a, 0x72, + 0x9b, 0x8d, 0x3e, 0x1e, 0x1d, 0x7d, 0xb7, 0x46, 0x90, 0x48, 0x7b, 0x30, 0x38, 0xef, 0x6b, 0x02, + 0x92, 0x10, 0x94, 0x81, 0x15, 0x66, 0x9b, 0xc3, 0xb0, 0x62, 0xab, 0xd6, 0x6c, 0xd8, 0xbd, 0x04, + 0xad, 0x69, 0x93, 0xb9, 0x0a, 0xd2, 0xc5, 0x39, 0xb7, 0xde, 0x20, 0xa6, 0x27, 0x58, 0x0a, 0x79, + 0x4a, 0xd5, 0xb0, 0xa9, 0x0a, 0x9f, 0x5d, 0x05, 0x20, 0xdd, 0x11, 0xa8, 0x8d, 0x82, 0xb3, 0xa9, + 0x28, 0x5f, 0xb7, 0x13, 0xa6, 0x7d, 0xf5, 0x48, 0x09, 0x5c, 0xdb, 0x4d, 0x92, 0xb7, 0x68, 0x57, + 0xd0, 0x0c, 0x94, 0x03, 0x99, 0xe4, 0xae, 0xb3, 0x5c, 0x9d, 0xe7, 0x73, 0x36, 0x16, 0x4e, 0x9f, + 0xea, 0x2e, 0x8c, 0x83, 0xfd, 0x7a, 0xb4, 0xef, 0xdd, 0x5d, 0x60, 0x24, 0x70, 0xa4, 0x1d, 0x11, + 0xd7, 0x44, 0xa1, 0x51, 0x18, 0x12, 0x78, 0x20, 0xf7, 0x22, 0x68, 0x32, 0xd8, 0x50, 0xd9, 0x73, + 0xa2, 0x00, 0xc8, 0x52, 0xfe, 0xb6, 0x06, 0x03, 0x05, 0xd3, 0xa0, 0x47, 0xc4, 0x2c, 0x9a, 0x7f, + 0x6a, 0x8f, 0xdc, 0x03, 0x7a, 0x4a, 0x96, 0x16, 0x86, 0x8b, 0x09, 0x73, 0x90, 0x22, 0x99, 0x9e, + 0x79, 0x01, 0xf9, 0xe8, 0x26, 0xcb, 0x80, 0x7e, 0x2f, 0xf7, 0x92, 0x56, 0xfa, 0xa1, 0x22, 0xd3, + 0x5d, 0x64, 0xa6, 0xe1, 0x14, 0x73, 0x3e, 0xa1, 0x67, 0x34, 0xc5, 0xc9, 0xac, 0xd4, 0xef, 0xd5, + 0x09, 0xc4, 0x9d, 0x38, 0xa8, 0xe9, 0x7a, 0xdd, 0xfc, 0x3c, 0xb8, 0x5d, 0x84, 0x55, 0xcc, 0x75, + 0xfd, 0x11, 0x12, 0x72, 0xe1, 0x46, 0x06, 0xd9, 0x8e, 0x6a, 0xee, 0xa3, 0xbd, 0xa3, 0xc5, 0x89, + 0x9e, 0x9b, 0x56, 0xb2, 0xe7, 0xd6, 0x13, 0x44, 0x96, 0xbd, 0x01, 0xae, 0xbb, 0xf6, 0xe5, 0x56, + 0x8d, 0xc0, 0x75, 0xd1, 0x7f, 0x85, 0x25, 0xb3, 0x98, 0xee, 0x97, 0xbf, 0xa2, 0x50, 0x47, 0x5a, + 0x2b, 0x31, 0x32, 0x42, 0x08, 0x80, 0x72, 0x70, 0x52, 0xb9, 0xb9, 0x76, 0x71, 0x02, 0x18, 0x3b, + 0xa0, 0xc3, 0xee, 0xbb, 0x44, 0x38, 0x4d, 0x25, 0xcb, 0xc9, 0x54, 0xfa, 0x26, 0x3c, 0xff, 0x5d, + 0xac, 0xa7, 0x30, 0x56, 0xfd, 0x81, 0xd7, 0xbb, 0x7c, 0x44, 0xf1, 0x48, 0x51, 0xc0, 0x09, 0x00, + 0x15, 0xdd, 0xf6, 0x4d, 0xbb, 0x59, 0x8a, 0x19, 0xb7, 0xab, 0x6b, 0x95, 0xb9, 0x46, 0x35, 0x03, + 0x38, 0x95, 0x51, 0x42, 0x9c, 0x10, 0x31, 0x98, 0xfd, 0x84, 0x65, 0xf0, 0xa7, 0x67, 0x51, 0xea, + 0x02, 0x20, 0xf8, 0xd0, 0xc1, 0x5a, 0x2c, 0xcc, 0x04, 0x1f, 0xf5, 0x2d, 0x58, 0x75, 0xe4, 0x56, + 0xda, 0xc5, 0x90, 0xd2, 0xc3, 0x08, 0x64, 0x4e, 0x3f, 0x48, 0x60, 0xf3, 0xa6, 0x52, 0x66, 0xec, + 0x77, 0xac, 0xf5, 0x0a, 0xae, 0xd0, 0x86, 0x9f, 0x28, 0x5f, 0x10, 0x95, 0xf3, 0xf4, 0x80, 0x00, + 0x00, 0x03, 0x57, 0xff, 0xff, 0xfc, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x41, 0x4d, 0x4c, 0x56, 0x86, + 0x00, 0x40, 0x92, 0xe1, 0x61, 0x56, 0x00, 0x00, 0x0c, 0x70, 0x00, 0x00, 0x7f, 0xdf, 0xbf, 0x28, + 0xf1, 0xca, 0x4e, 0xe8, 0xe2, 0x0b, 0xc7, 0x0d, 0xe4, 0x38, 0xbe, 0xfa, 0xb0, 0xd9, 0x0f, 0x0f, + 0x63, 0x4f, 0x57, 0x00, 0x2b, 0x01, 0x35, 0x8f, 0xe1, 0x82, 0xaf, 0xbd, 0x69, 0x53, 0x0c, 0x2d, + 0x6b, 0x68, 0xab, 0x4b, 0xf4, 0x60, 0xae, 0x73, 0x82, 0x1c, 0xe8, 0x95, 0x84, 0xed, 0xc2, 0x4e, + 0x81, 0x9a, 0xe5, 0xf5, 0x8e, 0x3f, 0xe2, 0x55, 0x6a, 0x1e, 0x18, 0xb5, 0x1b, 0xf5, 0xea, 0x3f, + 0x94, 0x82, 0xce, 0xbf, 0x35, 0xea, 0xd6, 0x8d, 0xb0, 0xaf, 0x9a, 0xf9, 0xdd, 0x4f, 0xff, 0xea, + 0x07, 0x63, 0x93, 0x8d, 0x17, 0x65, 0x54, 0xd3, 0x1d, 0x45, 0x70, 0x68, 0xf2, 0xbc, 0x40, 0x84, + 0xac, 0x8b, 0xff, 0x42, 0xa1, 0xa1, 0x29, 0x77, 0xc9, 0xc6, 0x81, 0xf9, 0x46, 0x45, 0xf7, 0x10, + 0x50, 0x85, 0x67, 0xe6, 0xab, 0xd6, 0x1e, 0xe0, 0xa9, 0xeb, 0x1b, 0x9f, 0x1a, 0xe3, 0xc2, 0x41, + 0x87, 0x71, 0x97, 0xc4, 0xc8, 0x6a, 0x2d, 0x64, 0xde, 0x4d, 0x02, 0x33, 0x42, 0xf7, 0xa9, 0xc2, + 0x6e, 0x20, 0x7f, 0xf3, 0x1a, 0xd3, 0x33, 0x92, 0x3e, 0xd8, 0xe3, 0x77, 0x24, 0x5f, 0x70, 0x4d, + 0x50, 0x0d, 0xc7, 0x18, 0x82, 0x82, 0x65, 0x1d, 0xe4, 0x49, 0x3e, 0x9f, 0x8e, 0xec, 0xd8, 0x29, + 0x8c, 0xd4, 0x67, 0xbf, 0xe6, 0x51, 0xc3, 0x66, 0x74, 0x0f, 0x8a, 0x8c, 0xae, 0xd4, 0x8f, 0xab, + 0xc3, 0x37, 0xee, 0xbe, 0xec, 0x81, 0x24, 0x77, 0x73, 0x4b, 0x84, 0x7e, 0x24, 0x62, 0x62, 0x6d, + 0x79, 0x5d, 0x68, 0x64, 0x3f, 0x98, 0xdd, 0x7e, 0x82, 0xa8, 0x0f, 0x45, 0x0e, 0x93, 0xcd, 0x3d, + 0x1d, 0x50, 0x16, 0xf5, 0xf5, 0x53, 0x29, 0xc0, 0xbb, 0xbb, 0xd6, 0x68, 0x87, 0x47, 0x5d, 0xda, + 0xdf, 0xe4, 0x84, 0xfe, 0x40, 0x21, 0xd4, 0x0b, 0xf0, 0x3d, 0x19, 0x32, 0x03, 0x85, 0x1b, 0xa8, + 0xa7, 0xea, 0x6f, 0xd9, 0xf5, 0x54, 0x58, 0xa3, 0xdc, 0xd7, 0xc0, 0xd5, 0x26, 0x2d, 0x39, 0xed, + 0xcc, 0xb7, 0xfb, 0x36, 0xeb, 0xc6, 0x21, 0x58, 0xe4, 0x52, 0xea, 0x81, 0xa0, 0xa2, 0x63, 0x8a, + 0xae, 0x0c, 0xb1, 0x1d, 0x79, 0xb9, 0xcd, 0x49, 0xb8, 0x31, 0x88, 0xe5, 0xe2, 0x5c, 0xbd, 0x7a, + 0xbe, 0xcc, 0x74, 0x47, 0xe7, 0x65, 0x2d, 0x3d, 0xe9, 0x41, 0x64, 0x67, 0x01, 0x76, 0xc8, 0x41, + 0x3b, 0x7e, 0xde, 0x3c, 0x65, 0xc6, 0x36, 0x8a, 0xeb, 0xe1, 0x77, 0xe8, 0x4b, 0x8f, 0x6b, 0xb0, + 0x09, 0x8b, 0xc3, 0xf9, 0x9e, 0x9c, 0xdb, 0x26, 0x45, 0x00, 0x52, 0x4d, 0xc1, 0xfb, 0x33, 0x0f, + 0xfc, 0x01, 0x31, 0xe1, 0x1a, 0x92, 0x5c, 0x57, 0x5d, 0xce, 0x65, 0x51, 0x16, 0x62, 0xa0, 0x4b, + 0x4f, 0x86, 0xf4, 0x7d, 0xb4, 0x3c, 0x01, 0x19, 0x32, 0x7a, 0x88, 0x4a, 0x50, 0x96, 0xbd, 0x99, + 0xe7, 0x3c, 0x9e, 0x38, 0xd8, 0x08, 0x42, 0x03, 0xae, 0xbc, 0x19, 0xf1, 0x2b, 0xe1, 0x7f, 0x2f, + 0xd6, 0x1e, 0xda, 0x8f, 0xf2, 0x0e, 0x88, 0x9e, 0x07, 0x76, 0x6a, 0xd8, 0xde, 0xfa, 0xac, 0x08, + 0x06, 0x34, 0x15, 0x18, 0xf4, 0x09, 0x47, 0x4e, 0x76, 0x91, 0xfc, 0x53, 0x03, 0xed, 0xc7, 0x53, + 0x9e, 0xbc, 0xc7, 0x5e, 0x17, 0xd4, 0x18, 0x29, 0x04, 0xb6, 0xe9, 0x57, 0x97, 0x5a, 0x36, 0x61, + 0xf7, 0x3a, 0x47, 0x62, 0x24, 0xb8, 0x53, 0x44, 0x41, 0x22, 0xb8, 0x4d, 0x75, 0x89, 0xe2, 0xce, + 0x01, 0x3a, 0xce, 0x33, 0xd0, 0xa6, 0x18, 0xd4, 0x3e, 0x51, 0x02, 0xbc, 0x02, 0x01, 0x26, 0x8e, + 0x44, 0x97, 0xa6, 0x2a, 0xd3, 0xe1, 0x43, 0xbb, 0xa6, 0xea, 0x15, 0x3b, 0xeb, 0xab, 0xf6, 0xfe, + 0x5d, 0xe7, 0x4c, 0x8f, 0x16, 0x47, 0xdd, 0xf6, 0xdd, 0xe4, 0x5a, 0x47, 0x8c, 0x6d, 0x1c, 0x66, + 0xfb, 0x6c, 0x00, 0xe2, 0xf6, 0x79, 0xae, 0x35, 0x4e, 0x81, 0xc8, 0xdd, 0xd6, 0xb8, 0x31, 0x52, + 0x4d, 0xee, 0x6b, 0x66, 0xf1, 0x17, 0x1c, 0x34, 0xa2, 0x9c, 0x1b, 0x9d, 0x0f, 0x29, 0x23, 0x9e, + 0xf1, 0xa8, 0x4a, 0x44, 0x5d, 0x8d, 0x6d, 0x75, 0x15, 0xe6, 0x29, 0x3d, 0xf9, 0x10, 0x7d, 0x2c, + 0x02, 0xb3, 0x42, 0x28, 0xfe, 0x70, 0x3d, 0x0f, 0x5a, 0xac, 0x5d, 0x81, 0x6e, 0xea, 0xb9, 0x05, + 0x94, 0x2a, 0xaf, 0xc5, 0x6a, 0x0d, 0x90, 0x72, 0xbf, 0x17, 0x34, 0x28, 0x4c, 0x92, 0x3b, 0xcf, + 0xbc, 0x45, 0xc1, 0xb5, 0xac, 0x1d, 0x60, 0x6f, 0xce, 0x7c, 0xe6, 0x81, 0x33, 0x5c, 0x30, 0xdf, + 0xae, 0x80, 0x8d, 0x1d, 0xc3, 0x66, 0x96, 0xf4, 0x59, 0x08, 0x15, 0x13, 0x09, 0x28, 0x3b, 0x15, + 0x42, 0x78, 0x15, 0xa7, 0x14, 0x73, 0x25, 0x98, 0xe5, 0x1d, 0x93, 0xf0, 0xa2, 0x7e, 0x3d, 0xdf, + 0x53, 0xcc, 0x32, 0xb1, 0x54, 0x55, 0xe1, 0xb5, 0x88, 0x46, 0x75, 0xcc, 0x61, 0x71, 0x71, 0x11, + 0xd5, 0x74, 0x99, 0x2c, 0xf9, 0x67, 0x4a, 0x7d, 0x70, 0xfb, 0xa4, 0x8b, 0x0e, 0xa8, 0x4d, 0x0b, + 0x5b, 0xd5, 0x8d, 0xa5, 0xb3, 0xb8, 0xda, 0x2d, 0x36, 0xf4, 0x80, 0x3c, 0xde, 0xbd, 0x29, 0xa2, + 0xe6, 0x57, 0xc7, 0x0b, 0x2a, 0x8f, 0x67, 0x37, 0xfb, 0xd6, 0x5f, 0xcb, 0xde, 0xb5, 0x4e, 0x2b, + 0x4b, 0x1a, 0x1b, 0x67, 0xdc, 0x4b, 0x3e, 0xd5, 0x2b, 0x3f, 0x96, 0x57, 0x00, 0xa3, 0xb4, 0x5a, + 0x30, 0x5d, 0x25, 0x1a, 0xa6, 0x49, 0x3e, 0xd6, 0xd5, 0x4e, 0x18, 0x9d, 0xe0, 0x88, 0xe7, 0xd1, + 0xc0, 0x09, 0x98, 0x2d, 0x1a, 0x7b, 0xee, 0xda, 0xc4, 0x35, 0xba, 0x60, 0x66, 0x72, 0x20, 0x1f, + 0x16, 0x9f, 0xa7, 0xc3, 0x96, 0x94, 0x22, 0x70, 0x05, 0x1e, 0x08, 0x63, 0x8f, 0xd8, 0x85, 0x71, + 0x94, 0xb4, 0x26, 0x4d, 0x7c, 0xcd, 0x46, 0x90, 0x6a, 0x07, 0x2c, 0x08, 0xe5, 0xa7, 0x04, 0x05, + 0xed, 0x2d, 0xea, 0x0e, 0xc1, 0x69, 0x6a, 0xa5, 0x57, 0x41, 0xb0, 0x91, 0xdf, 0xe2, 0x52, 0xad, + 0x68, 0x19, 0xef, 0x2f, 0x8f, 0x4b, 0x65, 0xea, 0x4a, 0xe7, 0x00, 0x2e, 0xfd, 0x7c, 0xd8, 0x0b, + 0xf9, 0x1e, 0x98, 0x44, 0x1b, 0xdc, 0x7e, 0x5e, 0xfe, 0xf3, 0x3d, 0xa5, 0xba, 0x5f, 0x3b, 0x37, + 0x64, 0x80, 0x00, 0x00, 0x03, 0xa5, 0xff, 0xff, 0xfc, 0x5a, 0x00, 0x00, 0x00, 0x01, 0x41, 0x4d, + 0x4c, 0x56, 0x86, 0x00, 0x40, 0x92, 0xe1, 0x41, 0x56, 0x00, 0x00, 0x0c, 0x70, 0x00, 0x00, 0x7d, + 0x9c, 0xe1, 0xf6, 0x1d, 0x70, 0x67, 0xf6, 0xf6, 0xf8, 0xc3, 0xff, 0x6e, 0xea, 0xb7, 0x4e, 0x1d, + 0xa0, 0xf6, 0xa7, 0x65, 0x73, 0x97, 0xd9, 0xd1, 0xdc, 0x5f, 0xc1, 0x5a, 0xf3, 0x6c, 0x5b, 0xf9, + 0x6a, 0x5a, 0x87, 0xdc, 0xd5, 0x6d, 0x6c, 0xd6, 0x48, 0x29, 0x2a, 0x94, 0x99, 0xea, 0xc9, 0xd0, + 0xf7, 0x06, 0x13, 0xf7, 0xcd, 0xda, 0x03, 0xc2, 0x95, 0x2e, 0x8c, 0xa8, 0x4c, 0xf3, 0xd5, 0x11, + 0x38, 0x31, 0x6f, 0xd8, 0x16, 0xeb, 0xd5, 0x72, 0xac, 0x62, 0xc2, 0xd9, 0xf7, 0x6f, 0xbb, 0xfc, + 0x4b, 0x12, 0x46, 0xd7, 0xc6, 0x23, 0x00, 0xb4, 0x2a, 0xe4, 0x18, 0x45, 0xa6, 0xf2, 0x0a, 0x1c, + 0xa6, 0x8a, 0xc7, 0x30, 0x3d, 0x73, 0xa1, 0xfb, 0x47, 0x07, 0x18, 0xf4, 0x63, 0x33, 0x44, 0xa7, + 0x7e, 0xdb, 0xd6, 0x25, 0xd5, 0x1b, 0x5a, 0x67, 0x46, 0x6b, 0x8d, 0x91, 0x09, 0x7d, 0xf4, 0x2c, + 0xc7, 0x45, 0xa1, 0xce, 0x6e, 0x90, 0x0f, 0x36, 0xa4, 0x57, 0x49, 0x7c, 0x03, 0x1b, 0x62, 0x33, + 0x09, 0x05, 0x59, 0xca, 0xdd, 0xfb, 0x13, 0x4a, 0x58, 0xfc, 0xdc, 0x8f, 0x5e, 0xda, 0x20, 0x7d, + 0x1f, 0x6a, 0x80, 0x01, 0x01, 0xea, 0x4d, 0xfc, 0xe4, 0x8d, 0x90, 0xb0, 0xf1, 0xa1, 0x16, 0x47, + 0x19, 0x4f, 0xab, 0x4f, 0x38, 0x32, 0xc8, 0x17, 0xb2, 0x99, 0xed, 0x71, 0x5b, 0x5c, 0x72, 0xda, + 0x64, 0x6e, 0xc5, 0x13, 0x5b, 0x51, 0xf3, 0x46, 0x04, 0x26, 0xcc, 0x47, 0xa0, 0x44, 0x91, 0x4c, + 0x75, 0x57, 0xbe, 0xb6, 0x88, 0x49, 0x6c, 0x4a, 0xec, 0xd0, 0x65, 0x3f, 0xf0, 0xc2, 0x15, 0x28, + 0x51, 0x28, 0x83, 0xfd, 0xfc, 0x86, 0x0f, 0x6b, 0xc1, 0x20, 0x60, 0x57, 0xbb, 0x15, 0x4c, 0x01, + 0x07, 0xc9, 0x2f, 0x8e, 0x19, 0xc1, 0xef, 0x73, 0x65, 0x3a, 0x9e, 0x00, 0x4f, 0x03, 0x88, 0x7c, + 0xc3, 0x04, 0x2b, 0x16, 0xee, 0xf1, 0x37, 0x42, 0x6e, 0x05, 0x93, 0x98, 0x65, 0x51, 0xef, 0x5b, + 0xb3, 0xe6, 0x0a, 0x08, 0xad, 0x02, 0xc2, 0xfa, 0xfc, 0xc7, 0x0e, 0x39, 0x74, 0x54, 0xef, 0xf0, + 0xdc, 0x7b, 0x19, 0xce, 0x35, 0x74, 0xe0, 0x35, 0x5c, 0xf3, 0x23, 0xe8, 0xc5, 0x71, 0x9f, 0x63, + 0x4c, 0x3f, 0xb9, 0x64, 0xcd, 0x37, 0x7d, 0x59, 0x28, 0x37, 0x83, 0x06, 0xcb, 0x4f, 0x22, 0xf9, + 0x03, 0x85, 0x2a, 0x18, 0xc7, 0xb0, 0xb7, 0x27, 0x3e, 0xc4, 0x8a, 0xa1, 0xbe, 0xf6, 0xe0, 0x31, + 0x75, 0x4b, 0xfe, 0x70, 0x96, 0x82, 0x8e, 0xfe, 0x82, 0x8c, 0xd6, 0x64, 0x02, 0x96, 0xed, 0xdf, + 0x14, 0x04, 0x27, 0xa2, 0x7b, 0x2c, 0xe0, 0xd4, 0x1e, 0x61, 0x0e, 0x0f, 0x2d, 0x5f, 0x93, 0xfc, + 0x89, 0xf1, 0xfe, 0xaf, 0xa4, 0xda, 0x53, 0x18, 0x12, 0xc4, 0x0c, 0xd9, 0x15, 0x47, 0x60, 0x31, + 0xc8, 0xea, 0x9d, 0x33, 0x78, 0x91, 0xbf, 0xe3, 0xc9, 0xe1, 0xdc, 0x26, 0xe9, 0xf8, 0x70, 0x55, + 0x8f, 0x2b, 0xa8, 0x5b, 0x4c, 0x11, 0x7d, 0xd1, 0xa1, 0xe2, 0xd0, 0xba, 0xe6, 0x62, 0x36, 0x67, + 0xe9, 0x5f, 0x01, 0x05, 0x71, 0x29, 0xba, 0x31, 0x36, 0xbe, 0x4b, 0xc0, 0x43, 0xa4, 0xb2, 0x9f, + 0x09, 0xa6, 0xc4, 0x9b, 0xfd, 0x1f, 0x46, 0x3c, 0x44, 0x48, 0x3c, 0xc7, 0x58, 0x34, 0x7e, 0xfa, + 0x8b, 0x73, 0xee, 0x0e, 0x04, 0x9e, 0x01, 0x10, 0x0a, 0xe1, 0x9f, 0x15, 0x92, 0xb3, 0x8b, 0x9c, + 0x10, 0x2f, 0xfa, 0xb3, 0x8d, 0x21, 0x48, 0x4d, 0x82, 0x45, 0x0b, 0x89, 0x47, 0xa1, 0xd2, 0x7c, + 0xeb, 0x30, 0x44, 0x51, 0xdd, 0x64, 0xb8, 0x7e, 0x3c, 0xce, 0xc9, 0x5b, 0xf1, 0x8a, 0xf9, 0xad, + 0x62, 0xe9, 0x7f, 0x06, 0x56, 0x31, 0xb3, 0xae, 0xb3, 0x7d, 0x8e, 0x11, 0xa4, 0x4e, 0xbd, 0x46, + 0xc3, 0x01, 0xce, 0x13, 0xb0, 0x3c, 0x2d, 0x6c, 0x7c, 0xbd, 0xa3, 0x00, 0x1e, 0x59, 0x1f, 0x92, + 0x49, 0x16, 0xbd, 0x4b, 0x1e, 0x24, 0x23, 0x4c, 0x91, 0xb9, 0xb5, 0xf2, 0x58, 0x76, 0x2f, 0xcb, + 0xda, 0xd4, 0xe4, 0xe0, 0x5b, 0x32, 0x93, 0x53, 0x40, 0x94, 0xe1, 0x7b, 0x12, 0xb7, 0xaa, 0xba, + 0x70, 0x93, 0x26, 0x93, 0x7d, 0x68, 0x5f, 0xda, 0x4f, 0x33, 0xac, 0xc4, 0xf9, 0x4b, 0xcb, 0xb0, + 0x8e, 0x7a, 0xda, 0x65, 0xdf, 0x5f, 0x31, 0xbb, 0x36, 0x0d, 0xdf, 0xd4, 0x8c, 0xf0, 0xd5, 0xa8, + 0x9d, 0x3c, 0x89, 0x3d, 0x1c, 0x0e, 0x25, 0x8e, 0x5a, 0xc9, 0x68, 0x38, 0xcd, 0x74, 0x5c, 0x2a, + 0xb7, 0x06, 0x7b, 0x8f, 0x0c, 0x11, 0x43, 0x9e, 0x13, 0x61, 0xdc, 0x72, 0x09, 0x92, 0x3e, 0x5f, + 0x9e, 0xaf, 0x5f, 0x5d, 0x69, 0x25, 0xf5, 0x23, 0x74, 0x74, 0xab, 0xc2, 0x2f, 0x94, 0xac, 0xa9, + 0xef, 0xcd, 0xf6, 0x48, 0x77, 0x91, 0xbb, 0x4f, 0xc8, 0x57, 0x8f, 0x1c, 0xc6, 0x09, 0xde, 0xcb, + 0x4f, 0xdc, 0x6f, 0xf9, 0xcc, 0xcc, 0xd1, 0xce, 0x9a, 0xb6, 0x4a, 0x16, 0xeb, 0x5c, 0x54, 0x26, + 0x48, 0xe8, 0x85, 0x9a, 0x53, 0xdf, 0xb3, 0xad, 0x9d, 0x59, 0x77, 0xdc, 0xca, 0xa7, 0x1d, 0xc2, + 0x39, 0x60, 0xd3, 0xb8, 0xb9, 0xd9, 0x51, 0xf8, 0x34, 0x26, 0xce, 0x87, 0xb8, 0x87, 0x9a, 0xb0, + 0xa6, 0x6f, 0xba, 0xe6, 0xff, 0xa0, 0xff, 0x57, 0x4b, 0xde, 0x20, 0x5f, 0x71, 0xad, 0xc3, 0xad, + 0xd5, 0x12, 0xee, 0xad, 0xd3, 0x3b, 0xdf, 0x6e, 0xa3, 0x38, 0xc0, 0x87, 0x39, 0x3e, 0xce, 0xfe, + 0xfe, 0x72, 0x84, 0x1c, 0xe7, 0xfd, 0xac, 0x88, 0xab, 0x79, 0x73, 0x97, 0xc4, 0x2d, 0x2b, 0xf3, + 0xa3, 0x69, 0x55, 0x64, 0x25, 0x1a, 0x32, 0xe0, 0x57, 0xc1, 0x10, 0x18, 0x0d, 0xdb, 0x20, 0x6c, + 0xa2, 0x3d, 0xc9, 0xbf, 0x93, 0x2e, 0x6a, 0x6f, 0xac, 0xa3, 0x9a, 0xc9, 0xe8, 0x6a, 0xd3, 0xfe, + 0x43, 0x05, 0x9d, 0xa0, 0x21, 0xa9, 0xbe, 0xe9, 0x87, 0x06, 0x75, 0xe3, 0x9e, 0xee, 0x40, 0x93, + 0x9d, 0x21, 0xec, 0xe9, 0xdc, 0x17, 0x62, 0xf4, 0xfc, 0x74, 0x4f, 0xf2, 0xf2, 0x5b, 0xed, 0x73, + 0x93, 0x79, 0x66, 0xf8, 0x6b, 0x38, 0xb1, 0xbe, 0x29, 0x11, 0x3f, 0x52, 0x78, 0x7c, 0xab, 0xb7, + 0x9a, 0x9e, 0x0a, 0xfa, 0x29, 0x0f, 0x41, 0x44, 0xd2, 0xd6, 0x38, 0xbb, 0x11, 0x83, 0x25, 0xf9, + 0xf8, 0x2a, 0x7c, 0x4a, 0x72, 0xa1, 0x42, 0x54, 0x41, 0xbd, 0x3a, 0x6f, 0x7e, 0x3a, 0xc6, 0xee, + 0x45, 0xf0, 0x90, 0xe5, 0x86, 0x6e, 0x91, 0xbc, 0x35, 0x21, 0x47, 0xa0, 0x0a, 0x2d, 0xd2, 0x5c, + 0xbc, 0x83, 0x21, 0x8b, 0x74, 0xb1, 0x11, 0x86, 0x60, 0x00, 0xab, 0x5b, 0x4f, 0x08, 0x26, 0xce, + 0xce, 0xe5, 0x36, 0x02, 0x0d, 0x42, 0x35, 0x1e, 0x4d, 0x28, 0x6e, 0xc0, 0xe4, 0x4a, 0x1c, 0x2c, + 0x7b, 0x93, 0x80 +#else + 0x00, 0x00, 0x01, 0x34, 0xff, 0xff, 0xfe, 0xcb, 0x00, 0x00, 0x00, 0x01, 0x41, 0x4d, 0x4c, 0x56, + 0x82, 0x49, 0x83, 0x42, 0x00, 0x04, 0x10, 0x04, 0x14, 0x0e, 0x38, 0x24, 0x1c, 0x19, 0xba, 0x00, + 0x00, 0x90, 0x7c, 0x11, 0xb4, 0xcc, 0x7e, 0x19, 0x86, 0x00, 0x00, 0x7f, 0xc3, 0xb6, 0x35, 0x54, + 0x45, 0x38, 0x12, 0xe2, 0xd7, 0xa9, 0x1b, 0x49, 0xef, 0xc6, 0xfc, 0x14, 0x34, 0x41, 0xc7, 0xa3, + 0x91, 0xf4, 0x76, 0x8a, 0x19, 0x6b, 0xb0, 0xa4, 0xa0, 0x04, 0x13, 0xb0, 0xbe, 0x10, 0x72, 0x80, + 0x0a, 0x58, 0xbc, 0x18, 0xf2, 0xd0, 0x4f, 0x62, 0x1b, 0xea, 0xc2, 0x0b, 0xba, 0xfc, 0x7b, 0xbc, + 0xb3, 0x6a, 0x97, 0x15, 0x1f, 0x3c, 0x21, 0x4e, 0x3f, 0xa2, 0xe9, 0xe9, 0xfc, 0x92, 0xc3, 0xe7, + 0x7d, 0xb2, 0x08, 0x87, 0x98, 0x8e, 0x77, 0x0f, 0x09, 0x7b, 0xa7, 0x41, 0x42, 0xff, 0x14, 0xa1, + 0x0e, 0xf3, 0x28, 0x2d, 0xe1, 0x13, 0x73, 0x49, 0x26, 0xed, 0x88, 0x22, 0x82, 0x6a, 0x02, 0x87, + 0xa5, 0xbe, 0x9c, 0xe5, 0x3f, 0xc7, 0xb5, 0x65, 0x3f, 0x7e, 0xa2, 0x82, 0x3e, 0x22, 0xa1, 0x03, + 0xe1, 0xcd, 0x89, 0xe6, 0xf0, 0x47, 0x62, 0x81, 0x89, 0xaa, 0x7e, 0xbc, 0x4a, 0xc1, 0x7c, 0x26, + 0xe4, 0xc0, 0xd4, 0xbc, 0xb8, 0xcc, 0xb8, 0x44, 0x07, 0x51, 0xb4, 0xb3, 0xb9, 0xf5, 0x04, 0xaf, + 0x3f, 0x41, 0x49, 0x56, 0x6a, 0x87, 0x46, 0x95, 0xa1, 0xe7, 0x69, 0xe7, 0x3c, 0x32, 0x06, 0xc2, + 0xa2, 0x66, 0x48, 0x1f, 0x14, 0x43, 0x81, 0xf0, 0xa0, 0x3c, 0xa4, 0x82, 0x7f, 0x18, 0x9b, 0xe4, + 0x22, 0x2d, 0x64, 0x2a, 0xd0, 0x4d, 0xb4, 0xfd, 0x14, 0x2d, 0x6d, 0x68, 0xaf, 0x19, 0x7d, 0x0f, + 0x0f, 0x60, 0xc4, 0x92, 0x73, 0x34, 0xc9, 0x51, 0x9a, 0xb6, 0xac, 0x06, 0x90, 0xaf, 0x11, 0x21, + 0x0c, 0xb0, 0x02, 0xd9, 0xd7, 0xd1, 0x06, 0xa0, 0x05, 0xb6, 0x75, 0x70, 0x5d, 0xbc, 0x84, 0x99, + 0x08, 0xfd, 0x8b, 0x60, 0x33, 0xf5, 0x0f, 0xab, 0x42, 0xab, 0x63, 0x1a, 0x37, 0x1c, 0x5a, 0x89, + 0xc1, 0x5f, 0x43, 0x5c, 0x65, 0x63, 0x60, 0xc4, 0xca, 0xe9, 0x59, 0x72, 0xea, 0x93, 0xf9, 0xcb, + 0x0d, 0x96, 0x5e, 0x33, 0x21, 0xa9, 0xe1, 0xf1, 0x37, 0xcc, 0x1b, 0x3c, 0x99, 0x36, 0x78, 0x40, + 0x00, 0x00, 0x00, 0x76, 0xff, 0xff, 0xff, 0x89, 0x00, 0x00, 0x00, 0x01, 0x41, 0x4d, 0x4c, 0x56, + 0x84, 0x00, 0x80, 0x49, 0x72, 0x58, 0xba, 0x00, 0x00, 0x06, 0x70, 0x00, 0x00, 0x7f, 0x0a, 0x55, + 0x64, 0x1f, 0x77, 0x22, 0x11, 0x64, 0x86, 0x41, 0x2e, 0x75, 0xe3, 0xba, 0x24, 0xf7, 0x02, 0xaa, + 0x1f, 0x9a, 0x97, 0x84, 0x24, 0x83, 0xa8, 0xa3, 0x92, 0x1c, 0x9c, 0xe7, 0x85, 0x71, 0x18, 0x49, + 0xc5, 0x09, 0x36, 0xf0, 0x9e, 0x04, 0x84, 0x88, 0xa0, 0xad, 0x9c, 0x8e, 0x75, 0x9d, 0x08, 0xfb, + 0xab, 0xfd, 0x3d, 0x68, 0xdd, 0x14, 0x93, 0x50, 0xa3, 0x48, 0x96, 0xf7, 0xe6, 0xa4, 0x54, 0x62, + 0x3b, 0x31, 0x18, 0x57, 0xef, 0x3b, 0xb7, 0x98, 0x8e, 0xe9, 0x3b, 0xdf, 0x63, 0x0c, 0xfa, 0x5d, + 0x30, 0x51, 0x4e, 0x61, 0x06, 0xf9, 0x1f, 0xe5, 0xc5, 0x90, 0xb0, 0x80, 0x7c, 0xa0, 0x04, 0x98, + 0x5b, 0x00, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0xcf, 0x00, 0x00, 0x00, 0x01, 0x41, 0x4d, + 0x4c, 0x56, 0x86, 0x00, 0x40, 0x96, 0x61, 0xf1, 0x78, 0x00, 0x00, 0x0c, 0x23, 0x18, 0x00, 0x7c, + 0xc1, 0x46, 0xab, 0x45, 0x25, 0x66, 0x9d, 0x6f, 0xa7, 0x18, 0x82, 0xbc, 0xc3, 0xd5, 0xa0, 0xba, + 0x42, 0x04, 0x49, 0x7d, 0x20, 0xb3, 0x0f, 0x4c, 0x78, 0x4c, 0xae, 0x9b, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x29, 0xff, 0xff, 0xff, 0xd6, 0x00, 0x00, 0x00, 0x01, 0x41, 0x4d, 0x4c, 0x56, 0x86, 0x00, + 0x40, 0x96, 0x61, 0x21, 0x78, 0x00, 0x00, 0x0c, 0x70, 0x50, 0x40, 0x78, 0xfc, 0x21, 0xff, 0xe1, + 0x45, 0x85, 0x50, 0x5b, 0xfa, 0x35, 0xc8, 0x10, 0x5f, 0x78, 0x01, 0xb7, 0x6b, 0x58, 0x7e, 0x58, + 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0xff, 0xff, 0xff, 0xc7, 0x00, 0x00, 0x00, 0x01, 0x41, + 0x4d, 0x4c, 0x56, 0x86, 0x00, 0x40, 0x96, 0x62, 0x51, 0x78, 0x00, 0x00, 0x0c, 0x60, 0x63, 0x00, + 0x7e, 0x6c, 0x4b, 0x84, 0x3e, 0x1d, 0xe4, 0x3e, 0x25, 0x9f, 0x3f, 0x5a, 0x2a, 0x19, 0xb6, 0xdd, + 0x80, 0x97, 0xf7, 0x65, 0x1e, 0xa1, 0x17, 0xe2, 0xff, 0xac, 0xb3, 0x4c, 0x5a, 0xfa, 0x5f, 0x60, + 0xcf, 0x78, 0xc3, 0x28, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0xff, 0xff, 0xff, 0xd8, 0x00, + 0x00, 0x00, 0x01, 0x41, 0x4d, 0x4c, 0x56, 0x86, 0x00, 0x40, 0x96, 0x18, 0x70, 0x5e, 0x00, 0x00, + 0x03, 0x23, 0xa8, 0x00, 0x76, 0x0f, 0xb4, 0x03, 0xdc, 0x4e, 0xaf, 0x53, 0xde, 0xfe, 0x91, 0xd9, + 0x66, 0x0b, 0xab, 0x76, 0xbb, 0x44, 0x2c, 0xa6, 0x90, 0x80, 0x00, 0x00, 0x00, 0x23, 0xff, 0xff, + 0xff, 0xdc, 0x00, 0x00, 0x00, 0x01, 0x41, 0x4d, 0x4c, 0x56, 0x86, 0x00, 0x40, 0x96, 0x18, 0x70, + 0x5e, 0x00, 0x00, 0x03, 0x23, 0xa8, 0x00, 0x5d, 0xfc, 0x15, 0x9d, 0x57, 0xb5, 0x81, 0x63, 0x84, + 0xbd, 0x2b, 0xee, 0x37, 0x7c, 0xa0, 0xb6, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x18, 0xff, 0xff, 0xff, + 0xe7, 0x00, 0x00, 0x00, 0x01, 0x41, 0x4d, 0x4c, 0x56, 0x86, 0x01, 0x00, 0x96, 0x18, 0x48, 0x5f, + 0xe0, 0x00, 0x03, 0x20, 0x00, 0x00, 0x46, 0x74, 0x8f, 0xef, 0xb7, 0x09, 0x80, 0x00, 0x00, 0x00, + 0x31, 0xff, 0xff, 0xff, 0xce, 0x00, 0x00, 0x00, 0x01, 0x41, 0x4d, 0x4c, 0x56, 0x86, 0x00, 0x41, + 0x0a, 0x61, 0xa1, 0x78, 0x00, 0x00, 0x0c, 0x20, 0x00, 0x00, 0x72, 0x25, 0x0b, 0x41, 0x5b, 0x2e, + 0x3e, 0x8d, 0x64, 0x6d, 0xf0, 0x11, 0x8f, 0xd9, 0x9f, 0x4f, 0x28, 0x72, 0xf6, 0xd5, 0x1e, 0x5f, + 0x92, 0x69, 0xb8, 0xb0, 0xf6, 0xe0, 0xc8, 0xd6, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x3e, 0xff, 0xff, + 0xff, 0xc1, 0x00, 0x00, 0x00, 0x01, 0x41, 0x4d, 0x4c, 0x56, 0x86, 0x00, 0x41, 0x0a, 0x62, 0x01, + 0x78, 0x00, 0x00, 0x0c, 0x70, 0x00, 0x00, 0x7d, 0x80, 0x9f, 0xc5, 0x19, 0x81, 0x7a, 0xcd, 0xc4, + 0xc5, 0x08, 0x1c, 0x79, 0x94, 0xce, 0xb4, 0x6f, 0xc4, 0xd8, 0x8c, 0x45, 0x0a, 0xcf, 0xcb, 0xb2, + 0x21, 0x84, 0xe2, 0x7e, 0x84, 0xeb, 0x73, 0xd9, 0x4c, 0xad, 0x10, 0x50, 0x48, 0x96, 0xc2, 0x17, + 0x24, 0xa2, 0x4c, 0x90, 0x00, 0x00, 0x00, 0x45, 0xff, 0xff, 0xff, 0xba, 0x00, 0x00, 0x00, 0x01, + 0x41, 0x4d, 0x4c, 0x56, 0x86, 0x00, 0x41, 0x0a, 0x62, 0x61, 0x78, 0x00, 0x00, 0x0c, 0x20, 0x00, + 0x00, 0x7b, 0xea, 0xae, 0x37, 0x81, 0xba, 0xc1, 0x88, 0x4f, 0xbd, 0xf1, 0x0c, 0xc5, 0xf3, 0x80, + 0x6c, 0x69, 0x9f, 0xee, 0xd1, 0x8d, 0x03, 0x08, 0x49, 0x19, 0x41, 0x50, 0x0f, 0xa8, 0x85, 0xbd, + 0x27, 0x49, 0xf0, 0xfa, 0x1e, 0x96, 0x3a, 0x4d, 0x54, 0xf6, 0x11, 0xfc, 0x1e, 0x10, 0xe3, 0x75, + 0x67, 0xe5, 0x33, 0x73, 0xb0 +#endif + }; + +#if VP9_USE_TRIGGER_BIG_SIZE + static u32 vp9_trigger_framesize[] = {5429,591,799,655,655,647,769,822,867,945}; +#else + static u32 vp9_trigger_framesize[] = {320,130,60,53,68,51,47,36,61,74,81}; +#endif + +#endif //_VDEC_VP9_TRIG_ +
diff --git a/drivers/amvdec_ports/test/Android.mk b/drivers/amvdec_ports/test/Android.mk new file mode 100644 index 0000000..d9652fb --- /dev/null +++ b/drivers/amvdec_ports/test/Android.mk
@@ -0,0 +1,23 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := vcode_m2m +LOCAL_MODULE_TAGS := optional +LOCAL_SRC_FILES := vcodec_m2m_test.c +LOCAL_ARM_MODE := arm + +LOCAL_C_INCLUDES := \ + $(JNI_H_INCLUDE) \ + $(BOARD_AML_VENDOR_PATH)/vendor/amlogic/external/ffmpeg + +LOCAL_SHARED_LIBRARIES := \ + libamffmpeg + +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) + +LOCAL_PREBUILT_LIBS:= \ +# libavcodec:ffmpeg/lib/libavcodec.so \ + +include $(BUILD_MULTI_PREBUILT)
diff --git a/drivers/amvdec_ports/test/vcodec_m2m_test.c b/drivers/amvdec_ports/test/vcodec_m2m_test.c new file mode 100644 index 0000000..bec040b --- /dev/null +++ b/drivers/amvdec_ports/test/vcodec_m2m_test.c
@@ -0,0 +1,343 @@ +/* +* 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <libavcodec/avcodec.h> +#include <libavformat/avformat.h> +#include <pthread.h> +#include <unistd.h> +#include <sys/stat.h> +#include <pthread.h> + +#define INBUF_SIZE (4096) +#define DUMP_DIR "/data/video_frames" +static int dump; + +typedef struct VcodecCtx { + AVFormatContext *fmt_ctx; + AVStream *stream; + int nb_streams; + int vst_idx; + char *filename; + pthread_t tid; + pthread_mutex_t pthread_mutex; + pthread_cond_t pthread_cond; +} VcodecCtx; + +static void dump_yuv(AVFrame *frame, char *filename) +{ + FILE *f; + + printf("name: %s, resolution: %dx%d, size: %d\n", + filename, frame->width, frame->height, + frame->buf[0]->size + frame->buf[1]->size); + + f = fopen(filename,"w+"); + + fwrite(frame->buf[0]->data, 1, frame->buf[0]->size, f); + fwrite(frame->buf[1]->data, 1, frame->buf[1]->size, f); + + fclose(f); +} + +static void decode(AVCodecContext *dec_ctx, AVFrame *frame, AVPacket *pkt, + const char *filename) +{ + char buf[1024]; + int ret; + + ret = avcodec_send_packet(dec_ctx, pkt); + if (ret < 0) { + fprintf(stderr, "Error sending a packet for decoding\n"); + return; + } + + while (ret >= 0) { + ret = avcodec_receive_frame(dec_ctx, frame); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) + return; + else if (ret < 0) { + fprintf(stderr, "Error during decoding, ret: %s\n", av_err2str(ret)); + break; + } + + //fprintf(stderr, "saving frame %3d\n", dec_ctx->frame_number); + fflush(stdout); + + /* the picture is allocated by the decoder. no need to free it */ + snprintf(buf, sizeof(buf), "%s/frame-%d", filename, dec_ctx->frame_number); + + if (dump) + dump_yuv(frame, buf); + } +} + +static void* read_thread(void *arg) +{ + int ret, err; + AVFormatContext *ic = NULL; + AVCodecContext *dec_ctx = NULL; + AVStream *stream = NULL; + AVCodec *codec = NULL; + AVPacket pkt1, *pkt = &pkt1; + AVFrame *frame = NULL; + int vst_idx = 0; + int has_video = 0; + unsigned int st_idx = 0; + VcodecCtx *vctx = arg; + const char *forced_codec_name = NULL; + + printf("entry read thread, tid: %ld.\n", vctx->tid); + + ic = avformat_alloc_context(); + if (!ic) { + fprintf(stderr, "Could not allocate avformat context.\n"); + goto out; + } + + err = avformat_open_input(&ic, vctx->filename, NULL, NULL); + if (err < 0) { + fprintf(stderr, "Could not open avformat input.\n"); + goto out; + } + + err = avformat_find_stream_info(ic, NULL); + if (err < 0) { + fprintf(stderr, "find stream info err.\n"); + goto out; + } + + for (st_idx = 0; st_idx < ic->nb_streams; st_idx++) { + AVStream *st = ic->streams[st_idx]; + + enum AVMediaType type = st->codecpar->codec_type; + st->discard = AVDISCARD_ALL; + + if (type == AVMEDIA_TYPE_VIDEO) { + st->discard = AVDISCARD_NONE; + vctx->vst_idx = st_idx; + has_video = 1; + break; + } + } + + if (!has_video) { + fprintf(stderr, "no video stream.\n"); + goto out; + } + + stream = ic->streams[vctx->vst_idx]; + + //codec = avcodec_find_decoder(stream->codecpar->codec_id); + switch (stream->codecpar->codec_id) { + case AV_CODEC_ID_H264: + forced_codec_name = "h264_v4l2m2m"; + break; + case AV_CODEC_ID_HEVC: + forced_codec_name = "hevc_v4l2m2m"; + break; + case AV_CODEC_ID_VP9: + forced_codec_name = "vp9_v4l2m2m"; + break; + case AV_CODEC_ID_MPEG1VIDEO: + forced_codec_name = "mpeg1_v4l2m2m"; + break; + case AV_CODEC_ID_MPEG2VIDEO: + forced_codec_name = "mpeg2_v4l2m2m"; + break; + case AV_CODEC_ID_VC1: + forced_codec_name = "vc1_v4l2m2m"; + break; + case AV_CODEC_ID_H263: + forced_codec_name = "h263_v4l2m2m"; + break; + case AV_CODEC_ID_MPEG4: + forced_codec_name = "mpeg4_v4l2m2m"; + break; + case AV_CODEC_ID_MJPEG: + forced_codec_name = "mjpeg_v4l2m2m"; + break; + } + + codec = avcodec_find_decoder_by_name(forced_codec_name); + if (!codec) { + fprintf(stderr, "Unsupported codec with id %d for input stream %d\n", + stream->codecpar->codec_id, stream->index); + goto out; + } + + dec_ctx = avcodec_alloc_context3(codec); + if (!dec_ctx) { + fprintf(stderr, "Could not allocate video codec context\n"); + goto out; + } + + err = avcodec_parameters_to_context(dec_ctx, stream->codecpar); + if (err < 0) { + fprintf(stderr, "Could not set paras to context\n"); + goto out; + } + + av_codec_set_pkt_timebase(dec_ctx, stream->time_base); + dec_ctx->framerate = stream->avg_frame_rate; + + if (avcodec_open2(dec_ctx, codec, NULL) < 0) { + fprintf(stderr, "Could not open codec for input stream %d\n", + stream->index); + goto out; + } + + printf("fmt ctx: %p, stream: %p, video st idx: %d, num: %d\n", + ic, stream, vst_idx, ic->nb_streams); + printf("format: %s\n",ic->iformat->name); + + ic->flags |= AVFMT_FLAG_GENPTS; + ic->debug = 0xff; + + //if (ic->pb) + // ic->pb->eof_reached = 0; + + frame = av_frame_alloc(); + if (!frame) { + fprintf(stderr, "Could not allocate video frame\n"); + goto out; + } + + for (;;) { + ret = av_read_frame(ic, pkt); + if (ret < 0) { + if (ret == AVERROR_EOF || avio_feof(ic->pb)) { + printf("read data end, ret: %d.\n", ret); + break; + } + + if (ic->pb && ic->pb->error) + break; + + printf("read data fail, ret: %d.\n", ret); + continue; + } + + if (pkt->stream_index == vctx->vst_idx) { + //packet_queue_put(&is->audioq, pkt); + //printf("read video data size: %d.\n", pkt->size); + if (pkt->size) + decode(dec_ctx, frame, pkt, DUMP_DIR); + } + + av_packet_unref(pkt); + + usleep(8 * 1000); + } + + /* flush the decoder */ + decode(dec_ctx, frame, NULL, DUMP_DIR); +out: + if (dec_ctx) + avcodec_free_context(&dec_ctx); + + if (frame) + av_frame_free(&frame); + + if (ic) { + avformat_close_input(&ic); + avformat_free_context(ic); + } + + printf("read thread exit.\n"); + + pthread_mutex_lock(&vctx->pthread_mutex); + pthread_cond_signal(&vctx->pthread_cond); + pthread_mutex_unlock(&vctx->pthread_mutex); + + return NULL; +} + +static int open_input_file(const char *filename) +{ + int ret; + VcodecCtx *vctx; + pthread_t pid = pthread_self(); + + vctx = av_mallocz(sizeof(VcodecCtx)); + if (!vctx) + return -1; + + vctx->filename = av_strdup(filename); + if (!vctx->filename) { + av_free(vctx); + return -1; + } + + pthread_mutex_init(&vctx->pthread_mutex, NULL); + pthread_cond_init(&vctx->pthread_cond, NULL); + + ret = pthread_create(&vctx->tid, NULL, read_thread, (void *)vctx); + if (ret == 0) { + pthread_setname_np(pid, "read_thread"); + + pthread_mutex_lock(&vctx->pthread_mutex); + pthread_cond_wait(&vctx->pthread_cond, &vctx->pthread_mutex); + pthread_join(vctx->tid, NULL); + pthread_mutex_unlock(&vctx->pthread_mutex); + } + + av_free(vctx->filename); + av_free(vctx); + + printf("creat the read thread, ret: %d.\n", ret); + + return 0; +} + +int main(int argc, char **argv) +{ + int ret; + const char *filename; + int log_level = 0; + + if (argc < 2) { + fprintf(stderr, "Usage: %s <input file>\n ==> %s/frame-123\n", argv[0], DUMP_DIR); + exit(0); + } + + filename = argv[1]; + if (argv[2]) { + if (!strcmp(argv[2], "dump")) + dump = 1; + else + log_level = atoi(argv[2]); + } + + mkdir(DUMP_DIR, 0664); + + /*set debug level*/ + av_log_set_level(log_level); //AV_LOG_DEBUG + + /* register all the codecs */ + avcodec_register_all(); + + ret = open_input_file(filename); + if (ret < 0) + fprintf(stderr, "open input file fail.\n"); + + return 0; +}
diff --git a/drivers/amvdec_ports/utils/common.c b/drivers/amvdec_ports/utils/common.c new file mode 100644 index 0000000..67cf93b --- /dev/null +++ b/drivers/amvdec_ports/utils/common.c
@@ -0,0 +1,232 @@ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/vmalloc.h> +#include <linux/mm.h> +#include <linux/string.h> + +#include "common.h" +#ifdef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER +#include "pixfmt.h" +#endif + +const u8 ff_zigzag_direct[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + +const u8 ff_zigzag_scan[16 + 1] = { + 0 + 0 * 4, 1 + 0 * 4, 0 + 1 * 4, 0 + 2 * 4, + 1 + 1 * 4, 2 + 0 * 4, 3 + 0 * 4, 2 + 1 * 4, + 1 + 2 * 4, 0 + 3 * 4, 1 + 3 * 4, 2 + 2 * 4, + 3 + 1 * 4, 3 + 2 * 4, 2 + 3 * 4, 3 + 3 * 4, +}; + +const char * const color_space_names[] = { + [AVCOL_SPC_RGB] = "gbr", + [AVCOL_SPC_BT709] = "bt709", + [AVCOL_SPC_UNSPECIFIED] = "unknown", + [AVCOL_SPC_RESERVED] = "reserved", + [AVCOL_SPC_FCC] = "fcc", + [AVCOL_SPC_BT470BG] = "bt470bg", + [AVCOL_SPC_SMPTE170M] = "smpte170m", + [AVCOL_SPC_SMPTE240M] = "smpte240m", + [AVCOL_SPC_YCGCO] = "ycgco", + [AVCOL_SPC_BT2020_NCL] = "bt2020nc", + [AVCOL_SPC_BT2020_CL] = "bt2020c", + [AVCOL_SPC_SMPTE2085] = "smpte2085", + [AVCOL_SPC_CHROMA_DERIVED_NCL] = "chroma-derived-nc", + [AVCOL_SPC_CHROMA_DERIVED_CL] = "chroma-derived-c", + [AVCOL_SPC_ICTCP] = "ictcp", +}; + +const char *av_color_space_name(enum AVColorSpace space) +{ + return (unsigned) space < AVCOL_SPC_NB ? + color_space_names[space] : NULL; +} + +const char * const color_primaries_names[AVCOL_PRI_NB] = { + [AVCOL_PRI_RESERVED0] = "reserved", + [AVCOL_PRI_BT709] = "bt709", + [AVCOL_PRI_UNSPECIFIED] = "unknown", + [AVCOL_PRI_RESERVED] = "reserved", + [AVCOL_PRI_BT470M] = "bt470m", + [AVCOL_PRI_BT470BG] = "bt470bg", + [AVCOL_PRI_SMPTE170M] = "smpte170m", + [AVCOL_PRI_SMPTE240M] = "smpte240m", + [AVCOL_PRI_FILM] = "film", + [AVCOL_PRI_BT2020] = "bt2020", + [AVCOL_PRI_SMPTE428] = "smpte428", + [AVCOL_PRI_SMPTE431] = "smpte431", + [AVCOL_PRI_SMPTE432] = "smpte432", + [AVCOL_PRI_JEDEC_P22] = "jedec-p22", +}; + +const char *av_color_primaries_name(enum AVColorPrimaries primaries) +{ + return (unsigned) primaries < AVCOL_PRI_NB ? + color_primaries_names[primaries] : NULL; +} + +const char * const color_transfer_names[] = { + [AVCOL_TRC_RESERVED0] = "reserved", + [AVCOL_TRC_BT709] = "bt709", + [AVCOL_TRC_UNSPECIFIED] = "unknown", + [AVCOL_TRC_RESERVED] = "reserved", + [AVCOL_TRC_GAMMA22] = "bt470m", + [AVCOL_TRC_GAMMA28] = "bt470bg", + [AVCOL_TRC_SMPTE170M] = "smpte170m", + [AVCOL_TRC_SMPTE240M] = "smpte240m", + [AVCOL_TRC_LINEAR] = "linear", + [AVCOL_TRC_LOG] = "log100", + [AVCOL_TRC_LOG_SQRT] = "log316", + [AVCOL_TRC_IEC61966_2_4] = "iec61966-2-4", + [AVCOL_TRC_BT1361_ECG] = "bt1361e", + [AVCOL_TRC_IEC61966_2_1] = "iec61966-2-1", + [AVCOL_TRC_BT2020_10] = "bt2020-10", + [AVCOL_TRC_BT2020_12] = "bt2020-12", + [AVCOL_TRC_SMPTE2084] = "smpte2084", + [AVCOL_TRC_SMPTE428] = "smpte428", + [AVCOL_TRC_ARIB_STD_B67] = "arib-std-b67", +}; + +const char *av_color_transfer_name(enum AVColorTransferCharacteristic transfer) +{ + return (unsigned) transfer < AVCOL_TRC_NB ? + color_transfer_names[transfer] : NULL; +} + +//math +const u8 ff_log2_tab[256]={ + 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 +}; + +int av_log2(u32 v) +{ + int n = 0; + + if (v & 0xffff0000) { + v >>= 16; + n += 16; + } + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} + +//bitstream +int find_start_code(u8 *data, int data_sz) +{ + if (data_sz > 3 && data[0] == 0 && data[1] == 0 && data[2] == 1) + return 3; + + if (data_sz > 4 && data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] == 1) + return 4; + + return -1; +} + +int calc_nal_len(u8 *data, int len) +{ + int i; + + for (i = 0; i < len - 4; i++) { + if (data[i]) + continue; + + if ((data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1) || + (data[i] == 0 && data[i + 1] == 0 && + data[i + 2]==0 && data[i + 3] == 1)) + return i; + } + return len; //Not find the end of nalu +} + +u8 *nal_unit_extract_rbsp(const u8 *src, u32 src_len, u32 *dst_len) +{ + u8 *dst; + u32 i, len; + + dst = vmalloc(src_len + AV_INPUT_BUFFER_PADDING_SIZE); + if (!dst) + return NULL; + + /* NAL unit header (2 bytes) */ + i = len = 0; + while (i < 2 && i < src_len) + dst[len++] = src[i++]; + + while (i + 2 < src_len) + if (!src[i] && !src[i + 1] && src[i + 2] == 3) { + dst[len++] = src[i++]; + dst[len++] = src[i++]; + i++; // remove emulation_prevention_three_byte + } else + dst[len++] = src[i++]; + + while (i < src_len) + dst[len++] = src[i++]; + + memset(dst + len, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + *dst_len = len; + + return dst; +} + +//debug +static void _pr_hex(const char *fmt, ...) +{ + u8 buf[512]; + int len = 0; + + va_list args; + va_start(args, fmt); + vsnprintf(buf + len, 512 - len, fmt, args); + printk("%s", buf); + va_end(args); +} + +void print_hex_debug(u8 *data, u32 len, int max) +{ + int i, l; + + l = len > max ? max : len; + + for (i = 0; i < l; i++) { + if ((i & 0xf) == 0) + _pr_hex("%06x:", i); + _pr_hex("%02x ", data[i]); + if ((((i + 1) & 0xf) == 0) || ((i + 1) == l)) + _pr_hex("\n"); + } + + _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 new file mode 100644 index 0000000..89ae50b --- /dev/null +++ b/drivers/amvdec_ports/utils/common.h
@@ -0,0 +1,155 @@ +#ifndef UTILS_COMMON_H +#define UTILS_COMMON_H + +#ifdef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER +#include "pixfmt.h" +#endif + +#define AV_INPUT_BUFFER_PADDING_SIZE 64 +#define MIN_CACHE_BITS 64 + +#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) +#define FFMAX3(a,b,c) FFMAX(FFMAX(a,b),c) +#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) +#define FFMIN3(a,b,c) FFMIN(FFMIN(a,b),c) + +#define AV_WL32(p, val) \ + do { \ + u32 d = (val); \ + ((u8*)(p))[0] = (d); \ + ((u8*)(p))[1] = (d) >> 8; \ + ((u8*)(p))[2] = (d) >> 16; \ + ((u8*)(p))[3] = (d) >> 24; \ + } while(0) + +#define AV_WB32(p, val) \ + do { u32 d = (val); \ + ((u8*)(p))[3] = (d); \ + ((u8*)(p))[2] = (d) >> 8; \ + ((u8*)(p))[1] = (d) >> 16; \ + ((u8*)(p))[0] = (d) >> 24; \ + } while(0) + +#define AV_RB32(x) \ + (((u32)((const u8*)(x))[0] << 24) | \ + (((const u8*)(x))[1] << 16) | \ + (((const u8*)(x))[2] << 8) | \ + ((const u8*)(x))[3]) + +#define AV_RL32(x) \ + (((u32)((const u8*)(x))[3] << 24) | \ + (((const u8*)(x))[2] << 16) | \ + (((const u8*)(x))[1] << 8) | \ + ((const u8*)(x))[0]) + +#define NEG_SSR32(a, s) (((int)(a)) >> ((s < 32) ? (32 - (s)) : 0)) +#define NEG_USR32(a, s) (((u32)(a)) >> ((s < 32) ? (32 - (s)) : 0)) + +//rounded division & shift +#define RSHIFT(a,b) ((a) > 0 ? ((a) + ((1<<(b))>>1))>>(b) : ((a) + ((1<<(b))>>1)-1)>>(b)) +/* assume b>0 */ +#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) + +struct AVRational{ + int num; ///< numerator + int den; ///< denominator +}; + +#ifndef CONFIG_AMLOGIC_MEDIA_V4L_SOFTWARE_PARSER +/** + * YUV colorspace type. + * 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) + AVCOL_SPC_BT709 = 1, ///< also ITU-R BT1361 / IEC 61966-2-4 xvYCC709 / SMPTE RP177 Annex B + AVCOL_SPC_UNSPECIFIED = 2, + AVCOL_SPC_RESERVED = 3, + AVCOL_SPC_FCC = 4, ///< FCC Title 47 Code of Federal Regulations 73.682 (a)(20) + AVCOL_SPC_BT470BG = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM / IEC 61966-2-4 xvYCC601 + AVCOL_SPC_SMPTE170M = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC + AVCOL_SPC_SMPTE240M = 7, ///< functionally identical to above + AVCOL_SPC_YCGCO = 8, ///< Used by Dirac / VC-2 and H.264 FRext, see ITU-T SG16 + AVCOL_SPC_YCOCG = AVCOL_SPC_YCGCO, + AVCOL_SPC_BT2020_NCL = 9, ///< ITU-R BT2020 non-constant luminance system + AVCOL_SPC_BT2020_CL = 10, ///< ITU-R BT2020 constant luminance system + AVCOL_SPC_SMPTE2085 = 11, ///< SMPTE 2085, Y'D'zD'x + AVCOL_SPC_CHROMA_DERIVED_NCL = 12, ///< Chromaticity-derived non-constant luminance system + AVCOL_SPC_CHROMA_DERIVED_CL = 13, ///< Chromaticity-derived constant luminance system + AVCOL_SPC_ICTCP = 14, ///< ITU-R BT.2100-0, ICtCp + AVCOL_SPC_NB ///< Not part of ABI +}; + +/** + * Chromaticity coordinates of the source primaries. + * These values match the ones defined by ISO/IEC 23001-8_2013 ¡ì 7.1. + */ +enum AVColorPrimaries { + AVCOL_PRI_RESERVED0 = 0, + AVCOL_PRI_BT709 = 1, ///< also ITU-R BT1361 / IEC 61966-2-4 / SMPTE RP177 Annex B + AVCOL_PRI_UNSPECIFIED = 2, + AVCOL_PRI_RESERVED = 3, + AVCOL_PRI_BT470M = 4, ///< also FCC Title 47 Code of Federal Regulations 73.682 (a)(20) + + AVCOL_PRI_BT470BG = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM + AVCOL_PRI_SMPTE170M = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC + AVCOL_PRI_SMPTE240M = 7, ///< functionally identical to above + AVCOL_PRI_FILM = 8, ///< colour filters using Illuminant C + AVCOL_PRI_BT2020 = 9, ///< ITU-R BT2020 + AVCOL_PRI_SMPTE428 = 10, ///< SMPTE ST 428-1 (CIE 1931 XYZ) + AVCOL_PRI_SMPTEST428_1 = AVCOL_PRI_SMPTE428, + AVCOL_PRI_SMPTE431 = 11, ///< SMPTE ST 431-2 (2011) / DCI P3 + AVCOL_PRI_SMPTE432 = 12, ///< SMPTE ST 432-1 (2010) / P3 D65 / Display P3 + AVCOL_PRI_JEDEC_P22 = 22, ///< JEDEC P22 phosphors + AVCOL_PRI_NB ///< Not part of ABI +}; + +/** + * Color Transfer Characteristic. + * These values match the ones defined by ISO/IEC 23001-8_2013 ¡ì 7.2. + */ +enum AVColorTransferCharacteristic { + AVCOL_TRC_RESERVED0 = 0, + AVCOL_TRC_BT709 = 1, ///< also ITU-R BT1361 + AVCOL_TRC_UNSPECIFIED = 2, + AVCOL_TRC_RESERVED = 3, + AVCOL_TRC_GAMMA22 = 4, ///< also ITU-R BT470M / ITU-R BT1700 625 PAL & SECAM + AVCOL_TRC_GAMMA28 = 5, ///< also ITU-R BT470BG + AVCOL_TRC_SMPTE170M = 6, ///< also ITU-R BT601-6 525 or 625 / ITU-R BT1358 525 or 625 / ITU-R BT1700 NTSC + AVCOL_TRC_SMPTE240M = 7, + AVCOL_TRC_LINEAR = 8, ///< "Linear transfer characteristics" + AVCOL_TRC_LOG = 9, ///< "Logarithmic transfer characteristic (100:1 range)" + AVCOL_TRC_LOG_SQRT = 10, ///< "Logarithmic transfer characteristic (100 * Sqrt(10) : 1 range)" + AVCOL_TRC_IEC61966_2_4 = 11, ///< IEC 61966-2-4 + AVCOL_TRC_BT1361_ECG = 12, ///< ITU-R BT1361 Extended Colour Gamut + AVCOL_TRC_IEC61966_2_1 = 13, ///< IEC 61966-2-1 (sRGB or sYCC) + AVCOL_TRC_BT2020_10 = 14, ///< ITU-R BT2020 for 10-bit system + AVCOL_TRC_BT2020_12 = 15, ///< ITU-R BT2020 for 12-bit system + AVCOL_TRC_SMPTE2084 = 16, ///< SMPTE ST 2084 for 10-, 12-, 14- and 16-bit systems + AVCOL_TRC_SMPTEST2084 = AVCOL_TRC_SMPTE2084, + AVCOL_TRC_SMPTE428 = 17, ///< SMPTE ST 428-1 + AVCOL_TRC_SMPTEST428_1 = AVCOL_TRC_SMPTE428, + 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); +const char *av_color_transfer_name(enum AVColorTransferCharacteristic transfer); + +//math +int av_log2(u32 v); + +//bitstream +int find_start_code(u8 *data, int data_sz); +int calc_nal_len(u8 *data, int len); +u8 *nal_unit_extract_rbsp(const u8 *src, u32 src_len, u32 *dst_len); + +//debug +void print_hex_debug(u8 *data, u32 len, int max); + +bool is_over_size(int w, int h, int size); + +#endif \ No newline at end of file
diff --git a/drivers/amvdec_ports/utils/get_bits.h b/drivers/amvdec_ports/utils/get_bits.h new file mode 100644 index 0000000..bb98ebd --- /dev/null +++ b/drivers/amvdec_ports/utils/get_bits.h
@@ -0,0 +1,590 @@ +#ifndef AVCODEC_GET_BITS_H +#define AVCODEC_GET_BITS_H + +#include <linux/kernel.h> +#include <linux/types.h> +#include "common.h" + +/* + * Safe bitstream reading: + * optionally, the get_bits API can check to ensure that we + * don't read past input buffer boundaries. This is protected + * with CONFIG_SAFE_BITSTREAM_READER at the global level, and + * then below that with UNCHECKED_BITSTREAM_READER at the per- + * decoder level. This means that decoders that check internally + * can "#define UNCHECKED_BITSTREAM_READER 1" to disable + * overread checks. + * Boundary checking causes a minor performance penalty so for + * applications that won't want/need this, it can be disabled + * globally using "#define CONFIG_SAFE_BITSTREAM_READER 0". + */ + +struct get_bits_context { + const u8 *buffer; + const u8 *buffer_end; + int index; + int size_in_bits; + int size_in_bits_plus8; +}; + +/* Bitstream reader API docs: + * name + * arbitrary name which is used as prefix for the internal variables + * + * gb + * struct get_bits_context + * + * OPEN_READER(name, gb) + * load gb into local variables + * + * CLOSE_READER(name, gb) + * store local vars in gb + * + * UPDATE_CACHE(name, gb) + * Refill the internal cache from the bitstream. + * After this call at least MIN_CACHE_BITS will be available. + * + * GET_CACHE(name, gb) + * Will output the contents of the internal cache, + * next bit is MSB of 32 or 64 bits (FIXME 64 bits). + * + * SHOW_UBITS(name, gb, num) + * Will return the next num bits. + * + * SHOW_SBITS(name, gb, num) + * Will return the next num bits and do sign extension. + * + * SKIP_BITS(name, gb, num) + * Will skip over the next num bits. + * Note, this is equivalent to SKIP_CACHE; SKIP_COUNTER. + * + * SKIP_CACHE(name, gb, num) + * Will remove the next num bits from the cache (note SKIP_COUNTER + * MUST be called before UPDATE_CACHE / CLOSE_READER). + * + * SKIP_COUNTER(name, gb, num) + * Will increment the internal bit counter (see SKIP_CACHE & SKIP_BITS). + * + * LAST_SKIP_BITS(name, gb, num) + * Like SKIP_BITS, to be used if next call is UPDATE_CACHE or CLOSE_READER. + * + * BITS_LEFT(name, gb) + * Return the number of bits left + * + * For examples see get_bits, show_bits, skip_bits, get_vlc. + */ + +#define OPEN_READER_NOSIZE(name, gb) \ + u32 name ## _index = (gb)->index; \ + u32 name ## _cache + +#define OPEN_READER(name, gb) OPEN_READER_NOSIZE(name, gb) +#define BITS_AVAILABLE(name, gb) 1 + +#define CLOSE_READER(name, gb) (gb)->index = name ## _index + +#define UPDATE_CACHE_LE(name, gb) name ##_cache = \ + AV_RL32((gb)->buffer + (name ## _index >> 3)) >> (name ## _index & 7) + +#define UPDATE_CACHE_BE(name, gb) name ## _cache = \ + AV_RB32((gb)->buffer + (name ## _index >> 3)) << (name ## _index & 7) + +#define SKIP_COUNTER(name, gb, num) name ## _index += (num) + +#define BITS_LEFT(name, gb) ((int)((gb)->size_in_bits - name ## _index)) + +#define SKIP_BITS(name, gb, num) \ + do { \ + SKIP_CACHE(name, gb, num); \ + SKIP_COUNTER(name, gb, num); \ + } while (0) + +#define GET_CACHE(name, gb) ((u32) name ## _cache) + +#define LAST_SKIP_BITS(name, gb, num) SKIP_COUNTER(name, gb, num) + +#define SHOW_UBITS_LE(name, gb, num) zero_extend(name ## _cache, num) +#define SHOW_SBITS_LE(name, gb, num) sign_extend(name ## _cache, num) + +#define SHOW_UBITS_BE(name, gb, num) NEG_USR32(name ## _cache, num) +#define SHOW_SBITS_BE(name, gb, num) NEG_SSR32(name ## _cache, num) + +#ifdef BITSTREAM_READER_LE +#define UPDATE_CACHE(name, gb) UPDATE_CACHE_LE(name, gb) +#define SKIP_CACHE(name, gb, num) name ## _cache >>= (num) + +#define SHOW_UBITS(name, gb, num) SHOW_UBITS_LE(name, gb, num) +#define SHOW_SBITS(name, gb, num) SHOW_SBITS_LE(name, gb, num) +#else +#define UPDATE_CACHE(name, gb) UPDATE_CACHE_BE(name, gb) +#define SKIP_CACHE(name, gb, num) name ## _cache <<= (num) + +#define SHOW_UBITS(name, gb, num) SHOW_UBITS_BE(name, gb, num) +#define SHOW_SBITS(name, gb, num) SHOW_SBITS_BE(name, gb, num) +#endif + +static inline const int sign_extend(int val, u32 bits) +{ + u32 shift = 8 * sizeof(int) - bits; + + union { u32 u; int s; } v = { (u32) val << shift }; + return v.s >> shift; +} + +static inline u32 zero_extend(u32 val, u32 bits) +{ + return (val << ((8 * sizeof(int)) - bits)) >> ((8 * sizeof(int)) - bits); +} + +static inline int get_bits_count(const struct get_bits_context *s) +{ + return s->index; +} + +/** + * Skips the specified number of bits. + * @param n the number of bits to skip, + * For the UNCHECKED_BITSTREAM_READER this must not cause the distance + * from the start to overflow int. Staying within the bitstream + padding + * is sufficient, too. + */ +static inline void skip_bits_long(struct get_bits_context *s, int n) +{ + s->index += n; +} + +/** + * Read MPEG-1 dc-style VLC (sign bit + mantissa with no MSB). + * if MSB not set it is negative + * @param n length in bits + */ +static inline int get_xbits(struct get_bits_context *s, int n) +{ + register int sign; + register int cache; + + OPEN_READER(re, s); + UPDATE_CACHE(re, s); + cache = GET_CACHE(re, s); + sign = ~cache >> 31; + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + + return (NEG_USR32(sign ^ cache, n) ^ sign) - sign; +} + + +static inline int get_xbits_le(struct get_bits_context *s, int n) +{ + register int sign; + register int cache; + + OPEN_READER(re, s); + UPDATE_CACHE_LE(re, s); + cache = GET_CACHE(re, s); + sign = sign_extend(~cache, n) >> 31; + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + + return (zero_extend(sign ^ cache, n) ^ sign) - sign; +} + +static inline int get_sbits(struct get_bits_context *s, int n) +{ + register int tmp; + + OPEN_READER(re, s); + UPDATE_CACHE(re, s); + tmp = SHOW_SBITS(re, s, n); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + + return tmp; +} + +/** + * Read 1-25 bits. + */ +static inline u32 get_bits(struct get_bits_context *s, int n) +{ + register u32 tmp; + + OPEN_READER(re, s); + UPDATE_CACHE(re, s); + tmp = SHOW_UBITS(re, s, n); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + + return tmp; +} + +/** + * Read 0-25 bits. + */ +static inline int get_bitsz(struct get_bits_context *s, int n) +{ + return n ? get_bits(s, n) : 0; +} + +static inline u32 get_bits_le(struct get_bits_context *s, int n) +{ + register int tmp; + + OPEN_READER(re, s); + UPDATE_CACHE_LE(re, s); + tmp = SHOW_UBITS_LE(re, s, n); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + + return tmp; +} + +/** + * Show 1-25 bits. + */ +static inline u32 show_bits(struct get_bits_context *s, int n) +{ + register u32 tmp; + + OPEN_READER_NOSIZE(re, s); + UPDATE_CACHE(re, s); + tmp = SHOW_UBITS(re, s, n); + + return tmp; +} + +static inline void skip_bits(struct get_bits_context *s, int n) +{ + u32 re_index = s->index; + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); +} + +static inline u32 get_bits1(struct get_bits_context *s) +{ + u32 index = s->index; + u8 result = s->buffer[index >> 3]; + +#ifdef BITSTREAM_READER_LE + result >>= index & 7; + result &= 1; +#else + result <<= index & 7; + result >>= 8 - 1; +#endif + + index++; + s->index = index; + + return result; +} + +static inline u32 show_bits1(struct get_bits_context *s) +{ + return show_bits(s, 1); +} + +static inline void skip_bits1(struct get_bits_context *s) +{ + skip_bits(s, 1); +} + +/** + * Read 0-32 bits. + */ +static inline u32 get_bits_long(struct get_bits_context *s, int n) +{ + if (!n) { + return 0; + } else if (n <= MIN_CACHE_BITS) { + return get_bits(s, n); + } else { +#ifdef BITSTREAM_READER_LE + u32 ret = get_bits(s, 16); + return ret | (get_bits(s, n - 16) << 16); +#else + u32 ret = get_bits(s, 16) << (n - 16); + return ret | get_bits(s, n - 16); +#endif + } +} + +/** + * Read 0-64 bits. + */ +static inline u64 get_bits64(struct get_bits_context *s, int n) +{ + if (n <= 32) { + return get_bits_long(s, n); + } else { +#ifdef BITSTREAM_READER_LE + u64 ret = get_bits_long(s, 32); + return ret | (u64) get_bits_long(s, n - 32) << 32; +#else + u64 ret = (u64) get_bits_long(s, n - 32) << 32; + return ret | get_bits_long(s, 32); +#endif + } +} + +/** + * Read 0-32 bits as a signed integer. + */ +static inline int get_sbits_long(struct get_bits_context *s, int n) +{ + if (!n) + return 0; + + return sign_extend(get_bits_long(s, n), n); +} + +/** + * Show 0-32 bits. + */ +static inline u32 show_bits_long(struct get_bits_context *s, int n) +{ + if (n <= MIN_CACHE_BITS) { + return show_bits(s, n); + } else { + struct get_bits_context gb = *s; + + return get_bits_long(&gb, n); + } +} + +static inline int check_marker(struct get_bits_context *s, const char *msg) +{ + int bit = get_bits1(s); + + if (!bit) + pr_err("Marker bit missing at %d of %d %s\n", + get_bits_count(s) - 1, s->size_in_bits, msg); + return bit; +} + +static inline int init_get_bits_xe(struct get_bits_context *s, + const u8 *buffer, int bit_size, int is_le) +{ + int buffer_size; + int ret = 0; + + if (bit_size >= INT_MAX - FFMAX(7, AV_INPUT_BUFFER_PADDING_SIZE * 8) || + bit_size < 0 || !buffer) { + bit_size = 0; + buffer = NULL; + ret = -1; + } + + buffer_size = (bit_size + 7) >> 3; + + s->buffer = buffer; + s->size_in_bits = bit_size; + s->size_in_bits_plus8 = bit_size + 8; + s->buffer_end = buffer + buffer_size; + s->index = 0; + + return ret; +} + +/** + * Initialize struct get_bits_context. + * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes + * larger than the actual read bits because some optimized bitstream + * readers read 32 or 64 bit at once and could read over the end + * @param bit_size the size of the buffer in bits + * @return 0 on success, -1 if the buffer_size would overflow. + */ +static inline int init_get_bits(struct get_bits_context *s, + const u8 *buffer, int bit_size) +{ +#ifdef BITSTREAM_READER_LE + return init_get_bits_xe(s, buffer, bit_size, 1); +#else + return init_get_bits_xe(s, buffer, bit_size, 0); +#endif +} + +/** + * Initialize struct get_bits_context. + * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes + * larger than the actual read bits because some optimized bitstream + * readers read 32 or 64 bit at once and could read over the end + * @param byte_size the size of the buffer in bytes + * @return 0 on success, -1 if the buffer_size would overflow. + */ +static inline int init_get_bits8(struct get_bits_context *s, + const u8 *buffer, int byte_size) +{ + if (byte_size > INT_MAX / 8 || byte_size < 0) + byte_size = -1; + return init_get_bits(s, buffer, byte_size * 8); +} + +static inline int init_get_bits8_le(struct get_bits_context *s, + const u8 *buffer, int byte_size) +{ + if (byte_size > INT_MAX / 8 || byte_size < 0) + byte_size = -1; + return init_get_bits_xe(s, buffer, byte_size * 8, 1); +} + +static inline const u8 *align_get_bits(struct get_bits_context *s) +{ + int n = -get_bits_count(s) & 7; + + if (n) + skip_bits(s, n); + return s->buffer + (s->index >> 3); +} + +/** + * If the vlc code is invalid and max_depth=1, then no bits will be removed. + * If the vlc code is invalid and max_depth>1, then the number of bits removed + * is undefined. + */ +#define GET_VLC(code, name, gb, table, bits, max_depth) \ + do { \ + int n, nb_bits; \ + u32 index; \ + \ + index = SHOW_UBITS(name, gb, bits); \ + code = table[index][0]; \ + n = table[index][1]; \ + \ + if (max_depth > 1 && n < 0) { \ + LAST_SKIP_BITS(name, gb, bits); \ + UPDATE_CACHE(name, gb); \ + \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + code; \ + code = table[index][0]; \ + n = table[index][1]; \ + if (max_depth > 2 && n < 0) { \ + LAST_SKIP_BITS(name, gb, nb_bits); \ + UPDATE_CACHE(name, gb); \ + \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + code; \ + code = table[index][0]; \ + n = table[index][1]; \ + } \ + } \ + SKIP_BITS(name, gb, n); \ + } while (0) + +#define GET_RL_VLC(level, run, name, gb, table, bits, \ + max_depth, need_update) \ + do { \ + int n, nb_bits; \ + u32 index; \ + \ + index = SHOW_UBITS(name, gb, bits); \ + level = table[index].level; \ + n = table[index].len; \ + \ + if (max_depth > 1 && n < 0) { \ + SKIP_BITS(name, gb, bits); \ + if (need_update) { \ + UPDATE_CACHE(name, gb); \ + } \ + \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + level; \ + level = table[index].level; \ + n = table[index].len; \ + if (max_depth > 2 && n < 0) { \ + LAST_SKIP_BITS(name, gb, nb_bits); \ + if (need_update) { \ + UPDATE_CACHE(name, gb); \ + } \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + level; \ + level = table[index].level; \ + n = table[index].len; \ + } \ + } \ + run = table[index].run; \ + SKIP_BITS(name, gb, n); \ + } while (0) + +/* Return the LUT element for the given bitstream configuration. */ +static inline int set_idx(struct get_bits_context *s, + int code, int *n, int *nb_bits, int (*table)[2]) +{ + u32 idx; + + *nb_bits = -*n; + idx = show_bits(s, *nb_bits) + code; + *n = table[idx][1]; + + return table[idx][0]; +} + +/** + * Parse a vlc code. + * @param bits is the number of bits which will be read at once, must be + * identical to nb_bits in init_vlc() + * @param max_depth is the number of times bits bits must be read to completely + * read the longest vlc code + * = (max_vlc_length + bits - 1) / bits + * @returns the code parsed or -1 if no vlc matches + */ +static inline int get_vlc2(struct get_bits_context *s, + int (*table)[2], int bits, int max_depth) +{ + int code; + + OPEN_READER(re, s); + UPDATE_CACHE(re, s); + + GET_VLC(code, re, s, table, bits, max_depth); + + CLOSE_READER(re, s); + + return code; +} + +static inline int decode012(struct get_bits_context *gb) +{ + int n; + + n = get_bits1(gb); + if (n == 0) + return 0; + else + return get_bits1(gb) + 1; +} + +static inline int decode210(struct get_bits_context *gb) +{ + if (get_bits1(gb)) + return 0; + else + return 2 - get_bits1(gb); +} + +static inline int get_bits_left(struct get_bits_context *gb) +{ + return gb->size_in_bits - get_bits_count(gb); +} + +static inline int skip_1stop_8data_bits(struct get_bits_context *gb) +{ + if (get_bits_left(gb) <= 0) + return -1; + + while (get_bits1(gb)) { + skip_bits(gb, 8); + if (get_bits_left(gb) <= 0) + return -1; + } + + return 0; +} + +#endif /* AVCODEC_GET_BITS_H */ +
diff --git a/drivers/amvdec_ports/utils/golomb.c b/drivers/amvdec_ports/utils/golomb.c new file mode 100644 index 0000000..21fcb6a --- /dev/null +++ b/drivers/amvdec_ports/utils/golomb.c
@@ -0,0 +1,147 @@ +#include <linux/kernel.h> +#include <linux/types.h> + +const u8 ff_golomb_vlc_len[512]={ + 19,17,15,15,13,13,13,13,11,11,11,11,11,11,11,11,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 +}; + +const u8 ff_ue_golomb_vlc_code[512]={ + 32,32,32,32,32,32,32,32,31,32,32,32,32,32,32,32,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9,10,10,10,10,11,11,11,11,12,12,12,12,13,13,13,13,14,14,14,14, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +const char ff_se_golomb_vlc_code[512]={ + 17, 17, 17, 17, 17, 17, 17, 17, 16, 17, 17, 17, 17, 17, 17, 17, 8, -8, 9, -9, 10,-10, 11,-11, 12,-12, 13,-13, 14,-14, 15,-15, + 4, 4, 4, 4, -4, -4, -4, -4, 5, 5, 5, 5, -5, -5, -5, -5, 6, 6, 6, 6, -6, -6, -6, -6, 7, 7, 7, 7, -7, -7, -7, -7, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +const u8 ff_ue_golomb_len[256]={ + 1, 3, 3, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,17, +}; + +const u8 ff_interleaved_golomb_vlc_len[256]={ + 9,9,7,7,9,9,7,7,5,5,5,5,5,5,5,5, + 9,9,7,7,9,9,7,7,5,5,5,5,5,5,5,5, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 9,9,7,7,9,9,7,7,5,5,5,5,5,5,5,5, + 9,9,7,7,9,9,7,7,5,5,5,5,5,5,5,5, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +}; + +const u8 ff_interleaved_ue_golomb_vlc_code[256]={ + 15,16,7, 7, 17,18,8, 8, 3, 3, 3, 3, 3, 3, 3, 3, + 19,20,9, 9, 21,22,10,10,4, 4, 4, 4, 4, 4, 4, 4, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 23,24,11,11,25,26,12,12,5, 5, 5, 5, 5, 5, 5, 5, + 27,28,13,13,29,30,14,14,6, 6, 6, 6, 6, 6, 6, 6, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +const char ff_interleaved_se_golomb_vlc_code[256]={ + 8, -8, 4, 4, 9, -9, -4, -4, 2, 2, 2, 2, 2, 2, 2, 2, + 10,-10, 5, 5, 11,-11, -5, -5, -2, -2, -2, -2, -2, -2, -2, -2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 12,-12, 6, 6, 13,-13, -6, -6, 3, 3, 3, 3, 3, 3, 3, 3, + 14,-14, 7, 7, 15,-15, -7, -7, -3, -3, -3, -3, -3, -3, -3, -3, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +const u8 ff_interleaved_dirac_golomb_vlc_code[256]={ + 0, 1, 0, 0, 2, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 5, 2, 2, 6, 7, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 9, 4, 4, 10,11,5, 5, 2, 2, 2, 2, 2, 2, 2, 2, + 12,13,6, 6, 14,15,7, 7, 3, 3, 3, 3, 3, 3, 3, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; +
diff --git a/drivers/amvdec_ports/utils/golomb.h b/drivers/amvdec_ports/utils/golomb.h new file mode 100644 index 0000000..d66c182 --- /dev/null +++ b/drivers/amvdec_ports/utils/golomb.h
@@ -0,0 +1,500 @@ +#ifndef AVCODEC_GOLOMB_H +#define AVCODEC_GOLOMB_H + +#include <linux/kernel.h> +#include <linux/types.h> + +#include "get_bits.h" +#include "put_bits.h" +#include "common.h" + +#define INVALID_VLC 0x80000000 + +extern const u8 ff_golomb_vlc_len[512]; +extern const u8 ff_ue_golomb_vlc_code[512]; +extern const char ff_se_golomb_vlc_code[512]; +extern const u8 ff_ue_golomb_len[256]; + +extern const u8 ff_interleaved_golomb_vlc_len[256]; +extern const u8 ff_interleaved_ue_golomb_vlc_code[256]; +extern const char ff_interleaved_se_golomb_vlc_code[256]; +extern const u8 ff_interleaved_dirac_golomb_vlc_code[256]; + +/** + * Read an u32 Exp-Golomb code in the range 0 to 8190. + * + * @returns the read value or a negative error code. + */ +static inline int get_ue_golomb(struct get_bits_context *gb) +{ + u32 buf; + + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + if (buf >= (1 << 27)) { + buf >>= 32 - 9; + LAST_SKIP_BITS(re, gb, ff_golomb_vlc_len[buf]); + CLOSE_READER(re, gb); + + return ff_ue_golomb_vlc_code[buf]; + } else { + int log = 2 * av_log2(buf) - 31; + LAST_SKIP_BITS(re, gb, 32 - log); + CLOSE_READER(re, gb); + if (log < 7) { + pr_err("Invalid UE golomb code\n"); + return -1; + } + buf >>= log; + buf--; + + return buf; + } +} + +/** + * Read an u32 Exp-Golomb code in the range 0 to UINT_MAX-1. + */ +static inline u32 get_ue_golomb_long(struct get_bits_context *gb) +{ + u32 buf, log; + + buf = show_bits_long(gb, 32); + log = 31 - av_log2(buf); + skip_bits_long(gb, log); + + return get_bits_long(gb, log + 1) - 1; +} + +/** + * read u32 exp golomb code, constraint to a max of 31. + * the return value is undefined if the stored value exceeds 31. + */ +static inline int get_ue_golomb_31(struct get_bits_context *gb) +{ + u32 buf; + + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + buf >>= 32 - 9; + LAST_SKIP_BITS(re, gb, ff_golomb_vlc_len[buf]); + CLOSE_READER(re, gb); + + return ff_ue_golomb_vlc_code[buf]; +} + +static inline u32 get_interleaved_ue_golomb(struct get_bits_context *gb) +{ + u32 buf; + + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + if (buf & 0xAA800000) { + buf >>= 32 - 8; + LAST_SKIP_BITS(re, gb, ff_interleaved_golomb_vlc_len[buf]); + CLOSE_READER(re, gb); + + return ff_interleaved_ue_golomb_vlc_code[buf]; + } else { + u32 ret = 1; + + do { + buf >>= 32 - 8; + LAST_SKIP_BITS(re, gb, + FFMIN(ff_interleaved_golomb_vlc_len[buf], 8)); + + if (ff_interleaved_golomb_vlc_len[buf] != 9) { + ret <<= (ff_interleaved_golomb_vlc_len[buf] - 1) >> 1; + ret |= ff_interleaved_dirac_golomb_vlc_code[buf]; + break; + } + ret = (ret << 4) | ff_interleaved_dirac_golomb_vlc_code[buf]; + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + } while (ret<0x8000000U && BITS_AVAILABLE(re, gb)); + + CLOSE_READER(re, gb); + return ret - 1; + } +} + +/** + * read u32 truncated exp golomb code. + */ +static inline int get_te0_golomb(struct get_bits_context *gb, int range) +{ + if (range == 1) + return 0; + else if (range == 2) + return get_bits1(gb) ^ 1; + else + return get_ue_golomb(gb); +} + +/** + * read u32 truncated exp golomb code. + */ +static inline int get_te_golomb(struct get_bits_context *gb, int range) +{ + if (range == 2) + return get_bits1(gb) ^ 1; + else + return get_ue_golomb(gb); +} + +/** + * read signed exp golomb code. + */ +static inline int get_se_golomb(struct get_bits_context *gb) +{ + u32 buf; + + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + if (buf >= (1 << 27)) { + buf >>= 32 - 9; + LAST_SKIP_BITS(re, gb, ff_golomb_vlc_len[buf]); + CLOSE_READER(re, gb); + + return ff_se_golomb_vlc_code[buf]; + } else { + int log = av_log2(buf), sign; + LAST_SKIP_BITS(re, gb, 31 - log); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + buf >>= log; + + LAST_SKIP_BITS(re, gb, 32 - log); + CLOSE_READER(re, gb); + + sign = -(buf & 1); + buf = ((buf >> 1) ^ sign) - sign; + + return buf; + } +} + +static inline int get_se_golomb_long(struct get_bits_context *gb) +{ + u32 buf = get_ue_golomb_long(gb); + int sign = (buf & 1) - 1; + + return ((buf >> 1) ^ sign) + 1; +} + +static inline int get_interleaved_se_golomb(struct get_bits_context *gb) +{ + u32 buf; + + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + if (buf & 0xAA800000) { + buf >>= 32 - 8; + LAST_SKIP_BITS(re, gb, ff_interleaved_golomb_vlc_len[buf]); + CLOSE_READER(re, gb); + + return ff_interleaved_se_golomb_vlc_code[buf]; + } else { + int log; + LAST_SKIP_BITS(re, gb, 8); + UPDATE_CACHE(re, gb); + buf |= 1 | (GET_CACHE(re, gb) >> 8); + + if ((buf & 0xAAAAAAAA) == 0) + return INVALID_VLC; + + for (log = 31; (buf & 0x80000000) == 0; log--) + buf = (buf << 2) - ((buf << log) >> (log - 1)) + (buf >> 30); + + LAST_SKIP_BITS(re, gb, 63 - 2 * log - 8); + CLOSE_READER(re, gb); + return (signed) (((((buf << log) >> log) - 1) ^ -(buf & 0x1)) + 1) >> 1; + } +} + +static inline int dirac_get_se_golomb(struct get_bits_context *gb) +{ + u32 ret = get_interleaved_ue_golomb(gb); + + if (ret) { + int sign = -get_bits1(gb); + ret = (ret ^ sign) - sign; + } + + return ret; +} + +/** + * read u32 golomb rice code (ffv1). + */ +static inline int get_ur_golomb(struct get_bits_context *gb, + int k, int limit, int esc_len) +{ + u32 buf; + int log; + + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + log = av_log2(buf); + + if (log > 31 - limit) { + buf >>= log - k; + buf += (30U - log) << k; + LAST_SKIP_BITS(re, gb, 32 + k - log); + CLOSE_READER(re, gb); + + return buf; + } else { + LAST_SKIP_BITS(re, gb, limit); + UPDATE_CACHE(re, gb); + + buf = SHOW_UBITS(re, gb, esc_len); + + LAST_SKIP_BITS(re, gb, esc_len); + CLOSE_READER(re, gb); + + return buf + limit - 1; + } +} + +/** + * read u32 golomb rice code (jpegls). + */ +static inline int get_ur_golomb_jpegls(struct get_bits_context *gb, + int k, int limit, int esc_len) +{ + u32 buf; + int log; + + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + log = av_log2(buf); + + if (log - k >= 32 - MIN_CACHE_BITS + (MIN_CACHE_BITS == 32) && + 32 - log < limit) { + buf >>= log - k; + buf += (30U - log) << k; + LAST_SKIP_BITS(re, gb, 32 + k - log); + CLOSE_READER(re, gb); + + return buf; + } else { + int i; + for (i = 0; i + MIN_CACHE_BITS <= limit && SHOW_UBITS(re, gb, MIN_CACHE_BITS) == 0; i += MIN_CACHE_BITS) { + if (gb->size_in_bits <= re_index) { + CLOSE_READER(re, gb); + return -1; + } + LAST_SKIP_BITS(re, gb, MIN_CACHE_BITS); + UPDATE_CACHE(re, gb); + } + for (; i < limit && SHOW_UBITS(re, gb, 1) == 0; i++) { + SKIP_BITS(re, gb, 1); + } + LAST_SKIP_BITS(re, gb, 1); + UPDATE_CACHE(re, gb); + + if (i < limit - 1) { + if (k) { + if (k > MIN_CACHE_BITS - 1) { + buf = SHOW_UBITS(re, gb, 16) << (k-16); + LAST_SKIP_BITS(re, gb, 16); + UPDATE_CACHE(re, gb); + buf |= SHOW_UBITS(re, gb, k-16); + LAST_SKIP_BITS(re, gb, k-16); + } else { + buf = SHOW_UBITS(re, gb, k); + LAST_SKIP_BITS(re, gb, k); + } + } else { + buf = 0; + } + buf += ((u32)i << k); + } else if (i == limit - 1) { + buf = SHOW_UBITS(re, gb, esc_len); + LAST_SKIP_BITS(re, gb, esc_len); + + buf ++; + } else { + buf = -1; + } + CLOSE_READER(re, gb); + return buf; + } +} + +/** + * read signed golomb rice code (ffv1). + */ +static inline int get_sr_golomb(struct get_bits_context *gb, + int k, int limit, int esc_len) +{ + u32 v = get_ur_golomb(gb, k, limit, esc_len); + + return (v >> 1) ^ -(v & 1); +} + +/** + * read signed golomb rice code (flac). + */ +static inline int get_sr_golomb_flac(struct get_bits_context *gb, + int k, int limit, int esc_len) +{ + u32 v = get_ur_golomb_jpegls(gb, k, limit, esc_len); + + return (v >> 1) ^ -(v & 1); +} + +/** + * read u32 golomb rice code (shorten). + */ +static inline u32 get_ur_golomb_shorten(struct get_bits_context *gb, int k) +{ + return get_ur_golomb_jpegls(gb, k, INT_MAX, 0); +} + +/** + * read signed golomb rice code (shorten). + */ +static inline int get_sr_golomb_shorten(struct get_bits_context *gb, int k) +{ + int uvar = get_ur_golomb_jpegls(gb, k + 1, INT_MAX, 0); + + return (uvar >> 1) ^ -(uvar & 1); +} + +/** + * write u32 exp golomb code. 2^16 - 2 at most + */ +static inline void set_ue_golomb(struct put_bits_context *pb, int i) +{ + if (i < 256) + put_bits(pb, ff_ue_golomb_len[i], i + 1); + else { + int e = av_log2(i + 1); + put_bits(pb, 2 * e + 1, i + 1); + } +} + +/** + * write u32 exp golomb code. 2^32-2 at most. + */ +static inline void set_ue_golomb_long(struct put_bits_context *pb, u32 i) +{ + if (i < 256) + put_bits(pb, ff_ue_golomb_len[i], i + 1); + else { + int e = av_log2(i + 1); + put_bits64(pb, 2 * e + 1, i + 1); + } +} + +/** + * write truncated u32 exp golomb code. + */ +static inline void set_te_golomb(struct put_bits_context *pb, int i, int range) +{ + if (range == 2) + put_bits(pb, 1, i ^ 1); + else + set_ue_golomb(pb, i); +} + +/** + * write signed exp golomb code. 16 bits at most. + */ +static inline void set_se_golomb(struct put_bits_context *pb, int i) +{ + i = 2 * i - 1; + + if (i < 0) + i ^= -1; //FIXME check if gcc does the right thing + set_ue_golomb(pb, i); +} + +/** + * write u32 golomb rice code (ffv1). + */ +static inline void set_ur_golomb(struct put_bits_context *pb, int i, int k, int limit, + int esc_len) +{ + int e; + + e = i >> k; + if (e < limit) + put_bits(pb, e + k + 1, (1 << k) + av_mod_uintp2(i, k)); + else + put_bits(pb, limit + esc_len, i - limit + 1); +} + +/** + * write u32 golomb rice code (jpegls). + */ +static inline void set_ur_golomb_jpegls(struct put_bits_context *pb, + int i, int k, int limit, int esc_len) +{ + int e; + + e = (i >> k) + 1; + if (e < limit) { + while (e > 31) { + put_bits(pb, 31, 0); + e -= 31; + } + put_bits(pb, e, 1); + if (k) + put_sbits(pb, k, i); + } else { + while (limit > 31) { + put_bits(pb, 31, 0); + limit -= 31; + } + put_bits(pb, limit, 1); + put_bits(pb, esc_len, i - 1); + } +} + +/** + * write signed golomb rice code (ffv1). + */ +static inline void set_sr_golomb(struct put_bits_context *pb, + int i, int k, int limit, int esc_len) +{ + int v; + + v = -2 * i - 1; + v ^= (v >> 31); + + set_ur_golomb(pb, v, k, limit, esc_len); +} + +/** + * write signed golomb rice code (flac). + */ +static inline void set_sr_golomb_flac(struct put_bits_context *pb, + int i, int k, int limit, int esc_len) +{ + int v; + + v = -2 * i - 1; + v ^= (v >> 31); + + set_ur_golomb_jpegls(pb, v, k, limit, esc_len); +} + +#endif /* AVCODEC_GOLOMB_H */
diff --git a/drivers/amvdec_ports/utils/pixfmt.h b/drivers/amvdec_ports/utils/pixfmt.h new file mode 100644 index 0000000..f13411e --- /dev/null +++ b/drivers/amvdec_ports/utils/pixfmt.h
@@ -0,0 +1,470 @@ +#ifndef AVUTIL_PIXFMT_H +#define AVUTIL_PIXFMT_H + +/** + * Pixel format. + * + * @note + * AV_PIX_FMT_RGB32 is handled in an endian-specific manner. An RGBA + * color is put together as: + * (A << 24) | (R << 16) | (G << 8) | B + * This is stored as BGRA on little-endian CPU architectures and ARGB on + * big-endian CPUs. + * + * @note + * If the resolution is not a multiple of the chroma subsampling factor + * then the chroma plane resolution must be rounded up. + * + * @par + * When the pixel format is palettized RGB32 (AV_PIX_FMT_PAL8), the palettized + * image data is stored in AVFrame.data[0]. The palette is transported in + * AVFrame.data[1], is 1024 bytes long (256 4-byte entries) and is + * formatted the same as in AV_PIX_FMT_RGB32 described above (i.e., it is + * also endian-specific). Note also that the individual RGB32 palette + * components stored in AVFrame.data[1] should be in the range 0..255. + * This is important as many custom PAL8 video codecs that were designed + * to run on the IBM VGA graphics adapter use 6-bit palette components. + * + * @par + * For all the 8 bits per pixel formats, an RGB32 palette is in data[1] like + * for pal8. This palette is filled in automatically by the function + * allocating the picture. + */ +enum AVPixelFormat { + AV_PIX_FMT_NONE = -1, + AV_PIX_FMT_YUV420P, ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples) + AV_PIX_FMT_YUYV422, ///< packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr + AV_PIX_FMT_RGB24, ///< packed RGB 8:8:8, 24bpp, RGBRGB... + AV_PIX_FMT_BGR24, ///< packed RGB 8:8:8, 24bpp, BGRBGR... + AV_PIX_FMT_YUV422P, ///< planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples) + AV_PIX_FMT_YUV444P, ///< planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples) + AV_PIX_FMT_YUV410P, ///< planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples) + AV_PIX_FMT_YUV411P, ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) + AV_PIX_FMT_GRAY8, ///< Y , 8bpp + AV_PIX_FMT_MONOWHITE, ///< Y , 1bpp, 0 is white, 1 is black, in each byte pixels are ordered from the msb to the lsb + AV_PIX_FMT_MONOBLACK, ///< Y , 1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb + AV_PIX_FMT_PAL8, ///< 8 bits with AV_PIX_FMT_RGB32 palette + AV_PIX_FMT_YUVJ420P, ///< planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV420P and setting color_range + AV_PIX_FMT_YUVJ422P, ///< planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV422P and setting color_range + AV_PIX_FMT_YUVJ444P, ///< planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV444P and setting color_range + AV_PIX_FMT_UYVY422, ///< packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1 + AV_PIX_FMT_UYYVYY411, ///< packed YUV 4:1:1, 12bpp, Cb Y0 Y1 Cr Y2 Y3 + AV_PIX_FMT_BGR8, ///< packed RGB 3:3:2, 8bpp, (msb)2B 3G 3R(lsb) + AV_PIX_FMT_BGR4, ///< packed RGB 1:2:1 bitstream, 4bpp, (msb)1B 2G 1R(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits + AV_PIX_FMT_BGR4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1B 2G 1R(lsb) + AV_PIX_FMT_RGB8, ///< packed RGB 3:3:2, 8bpp, (msb)2R 3G 3B(lsb) + AV_PIX_FMT_RGB4, ///< packed RGB 1:2:1 bitstream, 4bpp, (msb)1R 2G 1B(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits + AV_PIX_FMT_RGB4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1R 2G 1B(lsb) + AV_PIX_FMT_NV12, ///< planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V) + AV_PIX_FMT_NV21, ///< as above, but U and V bytes are swapped + + AV_PIX_FMT_ARGB, ///< packed ARGB 8:8:8:8, 32bpp, ARGBARGB... + AV_PIX_FMT_RGBA, ///< packed RGBA 8:8:8:8, 32bpp, RGBARGBA... + AV_PIX_FMT_ABGR, ///< packed ABGR 8:8:8:8, 32bpp, ABGRABGR... + AV_PIX_FMT_BGRA, ///< packed BGRA 8:8:8:8, 32bpp, BGRABGRA... + + AV_PIX_FMT_GRAY16BE, ///< Y , 16bpp, big-endian + AV_PIX_FMT_GRAY16LE, ///< Y , 16bpp, little-endian + AV_PIX_FMT_YUV440P, ///< planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples) + AV_PIX_FMT_YUVJ440P, ///< planar YUV 4:4:0 full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV440P and setting color_range + AV_PIX_FMT_YUVA420P, ///< planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples) + AV_PIX_FMT_RGB48BE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as big-endian + AV_PIX_FMT_RGB48LE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as little-endian + + AV_PIX_FMT_RGB565BE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), big-endian + AV_PIX_FMT_RGB565LE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), little-endian + AV_PIX_FMT_RGB555BE, ///< packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), big-endian , X=unused/undefined + AV_PIX_FMT_RGB555LE, ///< packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), little-endian, X=unused/undefined + + AV_PIX_FMT_BGR565BE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), big-endian + AV_PIX_FMT_BGR565LE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), little-endian + AV_PIX_FMT_BGR555BE, ///< packed BGR 5:5:5, 16bpp, (msb)1X 5B 5G 5R(lsb), big-endian , X=unused/undefined + AV_PIX_FMT_BGR555LE, ///< packed BGR 5:5:5, 16bpp, (msb)1X 5B 5G 5R(lsb), little-endian, X=unused/undefined + +#ifdef FF_API_VAAPI + /** @name Deprecated pixel formats */ + /**@{*/ + AV_PIX_FMT_VAAPI_MOCO, ///< HW acceleration through VA API at motion compensation entry-point, Picture.data[3] contains a vaapi_render_state struct which contains macroblocks as well as various fields extracted from headers + AV_PIX_FMT_VAAPI_IDCT, ///< HW acceleration through VA API at IDCT entry-point, Picture.data[3] contains a vaapi_render_state struct which contains fields extracted from headers + AV_PIX_FMT_VAAPI_VLD, ///< HW decoding through VA API, Picture.data[3] contains a VASurfaceID + /**@}*/ + AV_PIX_FMT_VAAPI = AV_PIX_FMT_VAAPI_VLD, +#else + /** + * Hardware acceleration through VA-API, data[3] contains a + * VASurfaceID. + */ + AV_PIX_FMT_VAAPI, +#endif + + AV_PIX_FMT_YUV420P16LE, ///< planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV420P16BE, ///< planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV422P16LE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV422P16BE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV444P16LE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV444P16BE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_DXVA2_VLD, ///< HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer + + AV_PIX_FMT_RGB444LE, ///< packed RGB 4:4:4, 16bpp, (msb)4X 4R 4G 4B(lsb), little-endian, X=unused/undefined + AV_PIX_FMT_RGB444BE, ///< packed RGB 4:4:4, 16bpp, (msb)4X 4R 4G 4B(lsb), big-endian, X=unused/undefined + AV_PIX_FMT_BGR444LE, ///< packed BGR 4:4:4, 16bpp, (msb)4X 4B 4G 4R(lsb), little-endian, X=unused/undefined + AV_PIX_FMT_BGR444BE, ///< packed BGR 4:4:4, 16bpp, (msb)4X 4B 4G 4R(lsb), big-endian, X=unused/undefined + AV_PIX_FMT_YA8, ///< 8 bits gray, 8 bits alpha + + AV_PIX_FMT_Y400A = AV_PIX_FMT_YA8, ///< alias for AV_PIX_FMT_YA8 + AV_PIX_FMT_GRAY8A= AV_PIX_FMT_YA8, ///< alias for AV_PIX_FMT_YA8 + + AV_PIX_FMT_BGR48BE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as big-endian + AV_PIX_FMT_BGR48LE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as little-endian + + /** + * The following 12 formats have the disadvantage of needing 1 format for each bit depth. + * Notice that each 9/10 bits sample is stored in 16 bits with extra padding. + * If you want to support multiple bit depths, then using AV_PIX_FMT_YUV420P16* with the bpp stored separately is better. + */ + AV_PIX_FMT_YUV420P9BE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P9LE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV420P10BE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P10LE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV422P10BE,///< planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P10LE,///< planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV444P9BE, ///< planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P9LE, ///< planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV444P10BE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P10LE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV422P9BE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P9LE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_GBRP, ///< planar GBR 4:4:4 24bpp + AV_PIX_FMT_GBR24P = AV_PIX_FMT_GBRP, // alias for #AV_PIX_FMT_GBRP + AV_PIX_FMT_GBRP9BE, ///< planar GBR 4:4:4 27bpp, big-endian + AV_PIX_FMT_GBRP9LE, ///< planar GBR 4:4:4 27bpp, little-endian + AV_PIX_FMT_GBRP10BE, ///< planar GBR 4:4:4 30bpp, big-endian + AV_PIX_FMT_GBRP10LE, ///< planar GBR 4:4:4 30bpp, little-endian + AV_PIX_FMT_GBRP16BE, ///< planar GBR 4:4:4 48bpp, big-endian + AV_PIX_FMT_GBRP16LE, ///< planar GBR 4:4:4 48bpp, little-endian + AV_PIX_FMT_YUVA422P, ///< planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples) + AV_PIX_FMT_YUVA444P, ///< planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples) + AV_PIX_FMT_YUVA420P9BE, ///< planar YUV 4:2:0 22.5bpp, (1 Cr & Cb sample per 2x2 Y & A samples), big-endian + AV_PIX_FMT_YUVA420P9LE, ///< planar YUV 4:2:0 22.5bpp, (1 Cr & Cb sample per 2x2 Y & A samples), little-endian + AV_PIX_FMT_YUVA422P9BE, ///< planar YUV 4:2:2 27bpp, (1 Cr & Cb sample per 2x1 Y & A samples), big-endian + AV_PIX_FMT_YUVA422P9LE, ///< planar YUV 4:2:2 27bpp, (1 Cr & Cb sample per 2x1 Y & A samples), little-endian + AV_PIX_FMT_YUVA444P9BE, ///< planar YUV 4:4:4 36bpp, (1 Cr & Cb sample per 1x1 Y & A samples), big-endian + AV_PIX_FMT_YUVA444P9LE, ///< planar YUV 4:4:4 36bpp, (1 Cr & Cb sample per 1x1 Y & A samples), little-endian + AV_PIX_FMT_YUVA420P10BE, ///< planar YUV 4:2:0 25bpp, (1 Cr & Cb sample per 2x2 Y & A samples, big-endian) + AV_PIX_FMT_YUVA420P10LE, ///< planar YUV 4:2:0 25bpp, (1 Cr & Cb sample per 2x2 Y & A samples, little-endian) + AV_PIX_FMT_YUVA422P10BE, ///< planar YUV 4:2:2 30bpp, (1 Cr & Cb sample per 2x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA422P10LE, ///< planar YUV 4:2:2 30bpp, (1 Cr & Cb sample per 2x1 Y & A samples, little-endian) + AV_PIX_FMT_YUVA444P10BE, ///< planar YUV 4:4:4 40bpp, (1 Cr & Cb sample per 1x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA444P10LE, ///< planar YUV 4:4:4 40bpp, (1 Cr & Cb sample per 1x1 Y & A samples, little-endian) + AV_PIX_FMT_YUVA420P16BE, ///< planar YUV 4:2:0 40bpp, (1 Cr & Cb sample per 2x2 Y & A samples, big-endian) + AV_PIX_FMT_YUVA420P16LE, ///< planar YUV 4:2:0 40bpp, (1 Cr & Cb sample per 2x2 Y & A samples, little-endian) + AV_PIX_FMT_YUVA422P16BE, ///< planar YUV 4:2:2 48bpp, (1 Cr & Cb sample per 2x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA422P16LE, ///< planar YUV 4:2:2 48bpp, (1 Cr & Cb sample per 2x1 Y & A samples, little-endian) + AV_PIX_FMT_YUVA444P16BE, ///< planar YUV 4:4:4 64bpp, (1 Cr & Cb sample per 1x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA444P16LE, ///< planar YUV 4:4:4 64bpp, (1 Cr & Cb sample per 1x1 Y & A samples, little-endian) + + AV_PIX_FMT_VDPAU, ///< HW acceleration through VDPAU, Picture.data[3] contains a VdpVideoSurface + + AV_PIX_FMT_XYZ12LE, ///< packed XYZ 4:4:4, 36 bpp, (msb) 12X, 12Y, 12Z (lsb), the 2-byte value for each X/Y/Z is stored as little-endian, the 4 lower bits are set to 0 + AV_PIX_FMT_XYZ12BE, ///< packed XYZ 4:4:4, 36 bpp, (msb) 12X, 12Y, 12Z (lsb), the 2-byte value for each X/Y/Z is stored as big-endian, the 4 lower bits are set to 0 + AV_PIX_FMT_NV16, ///< interleaved chroma YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples) + AV_PIX_FMT_NV20LE, ///< interleaved chroma YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_NV20BE, ///< interleaved chroma YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + + AV_PIX_FMT_RGBA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + AV_PIX_FMT_RGBA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian + AV_PIX_FMT_BGRA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + AV_PIX_FMT_BGRA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian + + AV_PIX_FMT_YVYU422, ///< packed YUV 4:2:2, 16bpp, Y0 Cr Y1 Cb + + AV_PIX_FMT_YA16BE, ///< 16 bits gray, 16 bits alpha (big-endian) + AV_PIX_FMT_YA16LE, ///< 16 bits gray, 16 bits alpha (little-endian) + + AV_PIX_FMT_GBRAP, ///< planar GBRA 4:4:4:4 32bpp + AV_PIX_FMT_GBRAP16BE, ///< planar GBRA 4:4:4:4 64bpp, big-endian + AV_PIX_FMT_GBRAP16LE, ///< planar GBRA 4:4:4:4 64bpp, little-endian + /** + * HW acceleration through QSV, data[3] contains a pointer to the + * mfxFrameSurface1 structure. + */ + AV_PIX_FMT_QSV, + /** + * HW acceleration though MMAL, data[3] contains a pointer to the + * MMAL_BUFFER_HEADER_T structure. + */ + AV_PIX_FMT_MMAL, + + AV_PIX_FMT_D3D11VA_VLD, ///< HW decoding through Direct3D11 via old API, Picture.data[3] contains a ID3D11VideoDecoderOutputView pointer + + /** + * HW acceleration through CUDA. data[i] contain CUdeviceptr pointers + * exactly as for system memory frames. + */ + AV_PIX_FMT_CUDA, + + AV_PIX_FMT_0RGB, ///< packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined + AV_PIX_FMT_RGB0, ///< packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined + AV_PIX_FMT_0BGR, ///< packed BGR 8:8:8, 32bpp, XBGRXBGR... X=unused/undefined + AV_PIX_FMT_BGR0, ///< packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined + + AV_PIX_FMT_YUV420P12BE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P12LE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV420P14BE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P14LE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV422P12BE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P12LE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV422P14BE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P14LE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV444P12BE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P12LE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV444P14BE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P14LE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_GBRP12BE, ///< planar GBR 4:4:4 36bpp, big-endian + AV_PIX_FMT_GBRP12LE, ///< planar GBR 4:4:4 36bpp, little-endian + AV_PIX_FMT_GBRP14BE, ///< planar GBR 4:4:4 42bpp, big-endian + AV_PIX_FMT_GBRP14LE, ///< planar GBR 4:4:4 42bpp, little-endian + AV_PIX_FMT_YUVJ411P, ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV411P and setting color_range + + AV_PIX_FMT_BAYER_BGGR8, ///< bayer, BGBG..(odd line), GRGR..(even line), 8-bit samples */ + AV_PIX_FMT_BAYER_RGGB8, ///< bayer, RGRG..(odd line), GBGB..(even line), 8-bit samples */ + AV_PIX_FMT_BAYER_GBRG8, ///< bayer, GBGB..(odd line), RGRG..(even line), 8-bit samples */ + AV_PIX_FMT_BAYER_GRBG8, ///< bayer, GRGR..(odd line), BGBG..(even line), 8-bit samples */ + AV_PIX_FMT_BAYER_BGGR16LE, ///< bayer, BGBG..(odd line), GRGR..(even line), 16-bit samples, little-endian */ + AV_PIX_FMT_BAYER_BGGR16BE, ///< bayer, BGBG..(odd line), GRGR..(even line), 16-bit samples, big-endian */ + AV_PIX_FMT_BAYER_RGGB16LE, ///< bayer, RGRG..(odd line), GBGB..(even line), 16-bit samples, little-endian */ + AV_PIX_FMT_BAYER_RGGB16BE, ///< bayer, RGRG..(odd line), GBGB..(even line), 16-bit samples, big-endian */ + AV_PIX_FMT_BAYER_GBRG16LE, ///< bayer, GBGB..(odd line), RGRG..(even line), 16-bit samples, little-endian */ + AV_PIX_FMT_BAYER_GBRG16BE, ///< bayer, GBGB..(odd line), RGRG..(even line), 16-bit samples, big-endian */ + AV_PIX_FMT_BAYER_GRBG16LE, ///< bayer, GRGR..(odd line), BGBG..(even line), 16-bit samples, little-endian */ + AV_PIX_FMT_BAYER_GRBG16BE, ///< bayer, GRGR..(odd line), BGBG..(even line), 16-bit samples, big-endian */ + + AV_PIX_FMT_XVMC,///< XVideo Motion Acceleration via common packet passing + + AV_PIX_FMT_YUV440P10LE, ///< planar YUV 4:4:0,20bpp, (1 Cr & Cb sample per 1x2 Y samples), little-endian + AV_PIX_FMT_YUV440P10BE, ///< planar YUV 4:4:0,20bpp, (1 Cr & Cb sample per 1x2 Y samples), big-endian + AV_PIX_FMT_YUV440P12LE, ///< planar YUV 4:4:0,24bpp, (1 Cr & Cb sample per 1x2 Y samples), little-endian + AV_PIX_FMT_YUV440P12BE, ///< planar YUV 4:4:0,24bpp, (1 Cr & Cb sample per 1x2 Y samples), big-endian + AV_PIX_FMT_AYUV64LE, ///< packed AYUV 4:4:4,64bpp (1 Cr & Cb sample per 1x1 Y & A samples), little-endian + AV_PIX_FMT_AYUV64BE, ///< packed AYUV 4:4:4,64bpp (1 Cr & Cb sample per 1x1 Y & A samples), big-endian + + AV_PIX_FMT_VIDEOTOOLBOX, ///< hardware decoding through Videotoolbox + + AV_PIX_FMT_P010LE, ///< like NV12, with 10bpp per component, data in the high bits, zeros in the low bits, little-endian + AV_PIX_FMT_P010BE, ///< like NV12, with 10bpp per component, data in the high bits, zeros in the low bits, big-endian + + AV_PIX_FMT_GBRAP12BE, ///< planar GBR 4:4:4:4 48bpp, big-endian + AV_PIX_FMT_GBRAP12LE, ///< planar GBR 4:4:4:4 48bpp, little-endian + + AV_PIX_FMT_GBRAP10BE, ///< planar GBR 4:4:4:4 40bpp, big-endian + AV_PIX_FMT_GBRAP10LE, ///< planar GBR 4:4:4:4 40bpp, little-endian + + AV_PIX_FMT_MEDIACODEC, ///< hardware decoding through MediaCodec + + AV_PIX_FMT_GRAY12BE, ///< Y , 12bpp, big-endian + AV_PIX_FMT_GRAY12LE, ///< Y , 12bpp, little-endian + AV_PIX_FMT_GRAY10BE, ///< Y , 10bpp, big-endian + AV_PIX_FMT_GRAY10LE, ///< Y , 10bpp, little-endian + + AV_PIX_FMT_P016LE, ///< like NV12, with 16bpp per component, little-endian + AV_PIX_FMT_P016BE, ///< like NV12, with 16bpp per component, big-endian + + /** + * Hardware surfaces for Direct3D11. + * + * This is preferred over the legacy AV_PIX_FMT_D3D11VA_VLD. The new D3D11 + * hwaccel API and filtering support AV_PIX_FMT_D3D11 only. + * + * data[0] contains a ID3D11Texture2D pointer, and data[1] contains the + * texture array index of the frame as intptr_t if the ID3D11Texture2D is + * an array texture (or always 0 if it's a normal texture). + */ + AV_PIX_FMT_D3D11, + + AV_PIX_FMT_GRAY9BE, ///< Y , 9bpp, big-endian + AV_PIX_FMT_GRAY9LE, ///< Y , 9bpp, little-endian + + AV_PIX_FMT_GBRPF32BE, ///< IEEE-754 single precision planar GBR 4:4:4, 96bpp, big-endian + AV_PIX_FMT_GBRPF32LE, ///< IEEE-754 single precision planar GBR 4:4:4, 96bpp, little-endian + AV_PIX_FMT_GBRAPF32BE, ///< IEEE-754 single precision planar GBRA 4:4:4:4, 128bpp, big-endian + AV_PIX_FMT_GBRAPF32LE, ///< IEEE-754 single precision planar GBRA 4:4:4:4, 128bpp, little-endian + + /** + * DRM-managed buffers exposed through PRIME buffer sharing. + * + * data[0] points to an AVDRMFrameDescriptor. + */ + AV_PIX_FMT_DRM_PRIME, + /** + * Hardware surfaces for OpenCL. + * + * data[i] contain 2D image objects (typed in C as cl_mem, used + * in OpenCL as image2d_t) for each plane of the surface. + */ + AV_PIX_FMT_OPENCL, + + AV_PIX_FMT_GRAY14BE, ///< Y , 14bpp, big-endian + AV_PIX_FMT_GRAY14LE, ///< Y , 14bpp, little-endian + + AV_PIX_FMT_GRAYF32BE, ///< IEEE-754 single precision Y, 32bpp, big-endian + AV_PIX_FMT_GRAYF32LE, ///< IEEE-754 single precision Y, 32bpp, little-endian + + AV_PIX_FMT_YUVA422P12BE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), 12b alpha, big-endian + AV_PIX_FMT_YUVA422P12LE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), 12b alpha, little-endian + AV_PIX_FMT_YUVA444P12BE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), 12b alpha, big-endian + AV_PIX_FMT_YUVA444P12LE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), 12b alpha, little-endian + + AV_PIX_FMT_NV24, ///< planar YUV 4:4:4, 24bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V) + AV_PIX_FMT_NV42, ///< as above, but U and V bytes are swapped + + AV_PIX_FMT_NB ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions +}; + +#ifdef AV_HAVE_BIGENDIAN +#define AV_PIX_FMT_NE(be, le) AV_PIX_FMT_##be +#else +#define AV_PIX_FMT_NE(be, le) AV_PIX_FMT_##le +#endif + +#define AV_PIX_FMT_YUV420P10 AV_PIX_FMT_NE(YUV420P10BE, YUV420P10LE) +#define AV_PIX_FMT_YUV422P10 AV_PIX_FMT_NE(YUV422P10BE, YUV422P10LE) +#define AV_PIX_FMT_YUV440P10 AV_PIX_FMT_NE(YUV440P10BE, YUV440P10LE) +#define AV_PIX_FMT_YUV444P10 AV_PIX_FMT_NE(YUV444P10BE, YUV444P10LE) +#define AV_PIX_FMT_YUV420P12 AV_PIX_FMT_NE(YUV420P12BE, YUV420P12LE) +#define AV_PIX_FMT_YUV422P12 AV_PIX_FMT_NE(YUV422P12BE, YUV422P12LE) +#define AV_PIX_FMT_YUV440P12 AV_PIX_FMT_NE(YUV440P12BE, YUV440P12LE) +#define AV_PIX_FMT_YUV444P12 AV_PIX_FMT_NE(YUV444P12BE, YUV444P12LE) + + +#define AV_PIX_FMT_GBRP9 AV_PIX_FMT_NE(GBRP9BE , GBRP9LE) +#define AV_PIX_FMT_GBRP10 AV_PIX_FMT_NE(GBRP10BE, GBRP10LE) +#define AV_PIX_FMT_GBRP12 AV_PIX_FMT_NE(GBRP12BE, GBRP12LE) +#define AV_PIX_FMT_GBRP14 AV_PIX_FMT_NE(GBRP14BE, GBRP14LE) +#define AV_PIX_FMT_GBRP16 AV_PIX_FMT_NE(GBRP16BE, GBRP16LE) +#define AV_PIX_FMT_GBRAP10 AV_PIX_FMT_NE(GBRAP10BE, GBRAP10LE) +#define AV_PIX_FMT_GBRAP12 AV_PIX_FMT_NE(GBRAP12BE, GBRAP12LE) +#define AV_PIX_FMT_GBRAP16 AV_PIX_FMT_NE(GBRAP16BE, GBRAP16LE) + +#define AV_PIX_FMT_GRAY9 AV_PIX_FMT_NE(GRAY9BE, GRAY9LE) +#define AV_PIX_FMT_GRAY10 AV_PIX_FMT_NE(GRAY10BE, GRAY10LE) +#define AV_PIX_FMT_GRAY12 AV_PIX_FMT_NE(GRAY12BE, GRAY12LE) + +#define AV_PIX_FMT_YUV420P9 AV_PIX_FMT_NE(YUV420P9BE , YUV420P9LE) +#define AV_PIX_FMT_YUV422P9 AV_PIX_FMT_NE(YUV422P9BE , YUV422P9LE) +#define AV_PIX_FMT_YUV444P9 AV_PIX_FMT_NE(YUV444P9BE , YUV444P9LE) + +/** + * Chromaticity coordinates of the source primaries. + * These values match the ones defined by ISO/IEC 23001-8_2013 § 7.1. + */ +enum AVColorPrimaries { + AVCOL_PRI_RESERVED0 = 0, + AVCOL_PRI_BT709 = 1, ///< also ITU-R BT1361 / IEC 61966-2-4 / SMPTE RP177 Annex B + AVCOL_PRI_UNSPECIFIED = 2, + AVCOL_PRI_RESERVED = 3, + AVCOL_PRI_BT470M = 4, ///< also FCC Title 47 Code of Federal Regulations 73.682 (a)(20) + + AVCOL_PRI_BT470BG = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM + AVCOL_PRI_SMPTE170M = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC + AVCOL_PRI_SMPTE240M = 7, ///< functionally identical to above + AVCOL_PRI_FILM = 8, ///< colour filters using Illuminant C + AVCOL_PRI_BT2020 = 9, ///< ITU-R BT2020 + AVCOL_PRI_SMPTE428 = 10, ///< SMPTE ST 428-1 (CIE 1931 XYZ) + AVCOL_PRI_SMPTEST428_1 = AVCOL_PRI_SMPTE428, + AVCOL_PRI_SMPTE431 = 11, ///< SMPTE ST 431-2 (2011) / DCI P3 + AVCOL_PRI_SMPTE432 = 12, ///< SMPTE ST 432-1 (2010) / P3 D65 / Display P3 + AVCOL_PRI_JEDEC_P22 = 22, ///< JEDEC P22 phosphors + AVCOL_PRI_NB ///< Not part of ABI +}; + +/** + * Color Transfer Characteristic. + * These values match the ones defined by ISO/IEC 23001-8_2013 § 7.2. + */ +enum AVColorTransferCharacteristic { + AVCOL_TRC_RESERVED0 = 0, + AVCOL_TRC_BT709 = 1, ///< also ITU-R BT1361 + AVCOL_TRC_UNSPECIFIED = 2, + AVCOL_TRC_RESERVED = 3, + AVCOL_TRC_GAMMA22 = 4, ///< also ITU-R BT470M / ITU-R BT1700 625 PAL & SECAM + AVCOL_TRC_GAMMA28 = 5, ///< also ITU-R BT470BG + AVCOL_TRC_SMPTE170M = 6, ///< also ITU-R BT601-6 525 or 625 / ITU-R BT1358 525 or 625 / ITU-R BT1700 NTSC + AVCOL_TRC_SMPTE240M = 7, + AVCOL_TRC_LINEAR = 8, ///< "Linear transfer characteristics" + AVCOL_TRC_LOG = 9, ///< "Logarithmic transfer characteristic (100:1 range)" + AVCOL_TRC_LOG_SQRT = 10, ///< "Logarithmic transfer characteristic (100 * Sqrt(10) : 1 range)" + AVCOL_TRC_IEC61966_2_4 = 11, ///< IEC 61966-2-4 + AVCOL_TRC_BT1361_ECG = 12, ///< ITU-R BT1361 Extended Colour Gamut + AVCOL_TRC_IEC61966_2_1 = 13, ///< IEC 61966-2-1 (sRGB or sYCC) + AVCOL_TRC_BT2020_10 = 14, ///< ITU-R BT2020 for 10-bit system + AVCOL_TRC_BT2020_12 = 15, ///< ITU-R BT2020 for 12-bit system + AVCOL_TRC_SMPTE2084 = 16, ///< SMPTE ST 2084 for 10-, 12-, 14- and 16-bit systems + AVCOL_TRC_SMPTEST2084 = AVCOL_TRC_SMPTE2084, + AVCOL_TRC_SMPTE428 = 17, ///< SMPTE ST 428-1 + AVCOL_TRC_SMPTEST428_1 = AVCOL_TRC_SMPTE428, + AVCOL_TRC_ARIB_STD_B67 = 18, ///< ARIB STD-B67, known as "Hybrid log-gamma" + AVCOL_TRC_NB ///< Not part of ABI +}; + +/** + * YUV colorspace type. + * 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) + AVCOL_SPC_BT709 = 1, ///< also ITU-R BT1361 / IEC 61966-2-4 xvYCC709 / SMPTE RP177 Annex B + AVCOL_SPC_UNSPECIFIED = 2, + AVCOL_SPC_RESERVED = 3, + AVCOL_SPC_FCC = 4, ///< FCC Title 47 Code of Federal Regulations 73.682 (a)(20) + AVCOL_SPC_BT470BG = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM / IEC 61966-2-4 xvYCC601 + AVCOL_SPC_SMPTE170M = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC + AVCOL_SPC_SMPTE240M = 7, ///< functionally identical to above + AVCOL_SPC_YCGCO = 8, ///< Used by Dirac / VC-2 and H.264 FRext, see ITU-T SG16 + AVCOL_SPC_YCOCG = AVCOL_SPC_YCGCO, + AVCOL_SPC_BT2020_NCL = 9, ///< ITU-R BT2020 non-constant luminance system + AVCOL_SPC_BT2020_CL = 10, ///< ITU-R BT2020 constant luminance system + AVCOL_SPC_SMPTE2085 = 11, ///< SMPTE 2085, Y'D'zD'x + AVCOL_SPC_CHROMA_DERIVED_NCL = 12, ///< Chromaticity-derived non-constant luminance system + AVCOL_SPC_CHROMA_DERIVED_CL = 13, ///< Chromaticity-derived constant luminance system + AVCOL_SPC_ICTCP = 14, ///< ITU-R BT.2100-0, ICtCp + AVCOL_SPC_NB ///< Not part of ABI +}; + +/** + * MPEG vs JPEG YUV range. + */ +enum AVColorRange { + AVCOL_RANGE_UNSPECIFIED = 0, + AVCOL_RANGE_MPEG = 1, ///< the normal 219*2^(n-8) "MPEG" YUV ranges + AVCOL_RANGE_JPEG = 2, ///< the normal 2^n-1 "JPEG" YUV ranges + AVCOL_RANGE_NB ///< Not part of ABI +}; + +/** + * Location of chroma samples. + * + * Illustration showing the location of the first (top left) chroma sample of the + * image, the left shows only luma, the right + * shows the location of the chroma sample, the 2 could be imagined to overlay + * each other but are drawn separately due to limitations of ASCII + * + * 1st 2nd 1st 2nd horizontal luma sample positions + * v v v v + * ______ ______ + *1st luma line > |X X ... |3 4 X ... X are luma samples, + * | |1 2 1-6 are possible chroma positions + *2nd luma line > |X X ... |5 6 X ... 0 is undefined/unknown position + */ +enum AVChromaLocation { + AVCHROMA_LOC_UNSPECIFIED = 0, + AVCHROMA_LOC_LEFT = 1, ///< MPEG-2/4 4:2:0, H.264 default for 4:2:0 + AVCHROMA_LOC_CENTER = 2, ///< MPEG-1 4:2:0, JPEG 4:2:0, H.263 4:2:0 + AVCHROMA_LOC_TOPLEFT = 3, ///< ITU-R 601, SMPTE 274M 296M S314M(DV 4:1:1), mpeg2 4:2:2 + AVCHROMA_LOC_TOP = 4, + AVCHROMA_LOC_BOTTOMLEFT = 5, + AVCHROMA_LOC_BOTTOM = 6, + AVCHROMA_LOC_NB ///< Not part of ABI +}; + +#endif /* AVUTIL_PIXFMT_H */ +
diff --git a/drivers/amvdec_ports/utils/put_bits.h b/drivers/amvdec_ports/utils/put_bits.h new file mode 100644 index 0000000..8b2aa15 --- /dev/null +++ b/drivers/amvdec_ports/utils/put_bits.h
@@ -0,0 +1,323 @@ +#ifndef AVCODEC_PUT_BITS_H +#define AVCODEC_PUT_BITS_H + +#include <linux/kernel.h> +#include <linux/types.h> +#include "common.h" + +struct put_bits_context { + u32 bit_buf; + int bit_left; + u8 *buf; + u8 *buf_ptr; + u8 *buf_end; + int size_in_bits; +}; + +/** + * Initialize the struct put_bits_context s. + * + * @param buffer the buffer where to put bits + * @param buffer_size the size in bytes of buffer + */ +static inline void init_put_bits(struct put_bits_context *s, + u8 *buffer, int buffer_size) +{ + if (buffer_size < 0) { + buffer_size = 0; + buffer = NULL; + } + + s->size_in_bits = 8 * buffer_size; + s->buf = buffer; + s->buf_end = s->buf + buffer_size; + s->buf_ptr = s->buf; + s->bit_left = 32; + s->bit_buf = 0; +} + +/** + * Rebase the bit writer onto a reallocated buffer. + * + * @param buffer the buffer where to put bits + * @param buffer_size the size in bytes of buffer, + * must be larger than the previous size + */ +static inline void rebase_put_bits(struct put_bits_context *s, + u8 *buffer, int buffer_size) +{ + s->buf_end = buffer + buffer_size; + s->buf_ptr = buffer + (s->buf_ptr - s->buf); + s->buf = buffer; + s->size_in_bits = 8 * buffer_size; +} + +/** + * @return the total number of bits written to the bitstream. + */ +static inline int put_bits_count(struct put_bits_context *s) +{ + return (s->buf_ptr - s->buf) * 8 + 32 - s->bit_left; +} + +/** + * @return the number of bits available in the bitstream. + */ +static inline int put_bits_left(struct put_bits_context* s) +{ + return (s->buf_end - s->buf_ptr) * 8 - 32 + s->bit_left; +} + +/** + * Pad the end of the output stream with zeros. + */ +static inline void flush_put_bits(struct put_bits_context *s) +{ +#ifndef BITSTREAM_WRITER_LE + if (s->bit_left < 32) + s->bit_buf <<= s->bit_left; +#endif + while (s->bit_left < 32) { +#ifdef BITSTREAM_WRITER_LE + *s->buf_ptr++ = s->bit_buf; + s->bit_buf >>= 8; +#else + *s->buf_ptr++ = s->bit_buf >> 24; + s->bit_buf <<= 8; +#endif + s->bit_left += 8; + } + s->bit_left = 32; + s->bit_buf = 0; +} + +static inline void flush_put_bits_le(struct put_bits_context *s) +{ + while (s->bit_left < 32) { + *s->buf_ptr++ = s->bit_buf; + s->bit_buf >>= 8; + s->bit_left += 8; + } + s->bit_left = 32; + s->bit_buf = 0; +} + +#ifdef BITSTREAM_WRITER_LE +#define avpriv_align_put_bits align_put_bits_unsupported_here +#define avpriv_put_string ff_put_string_unsupported_here +#define avpriv_copy_bits avpriv_copy_bits_unsupported_here +#else +/** + * Pad the bitstream with zeros up to the next byte boundary. + */ +void avpriv_align_put_bits(struct put_bits_context *s); + +/** + * Put the string string in the bitstream. + * + * @param terminate_string 0-terminates the written string if value is 1 + */ +void avpriv_put_string(struct put_bits_context *pb, + const char *string, int terminate_string); + +/** + * Copy the content of src to the bitstream. + * + * @param length the number of bits of src to copy + */ +void avpriv_copy_bits(struct put_bits_context *pb, const u8 *src, int length); +#endif + +/** + * Write up to 31 bits into a bitstream. + * Use put_bits32 to write 32 bits. + */ +static inline void put_bits(struct put_bits_context *s, int n, u32 value) +{ + u32 bit_buf; + int bit_left; + + bit_buf = s->bit_buf; + bit_left = s->bit_left; + + /* XXX: optimize */ +#ifdef BITSTREAM_WRITER_LE + bit_buf |= value << (32 - bit_left); + if (n >= bit_left) { + if (3 < s->buf_end - s->buf_ptr) { + AV_WL32(s->buf_ptr, bit_buf); + s->buf_ptr += 4; + } else { + pr_err("Internal error, put_bits buffer too small\n"); + } + bit_buf = value >> bit_left; + bit_left += 32; + } + bit_left -= n; +#else + if (n < bit_left) { + bit_buf = (bit_buf << n) | value; + bit_left -= n; + } else { + bit_buf <<= bit_left; + bit_buf |= value >> (n - bit_left); + if (3 < s->buf_end - s->buf_ptr) { + AV_WB32(s->buf_ptr, bit_buf); + s->buf_ptr += 4; + } else { + pr_err("Internal error, put_bits buffer too small\n"); + } + bit_left += 32 - n; + bit_buf = value; + } +#endif + s->bit_buf = bit_buf; + s->bit_left = bit_left; +} + +static inline void put_bits_le(struct put_bits_context *s, int n, u32 value) +{ + u32 bit_buf; + int bit_left; + + bit_buf = s->bit_buf; + bit_left = s->bit_left; + + bit_buf |= value << (32 - bit_left); + if (n >= bit_left) { + if (3 < s->buf_end - s->buf_ptr) { + AV_WL32(s->buf_ptr, bit_buf); + s->buf_ptr += 4; + } else { + pr_err("Internal error, put_bits buffer too small\n"); + } + bit_buf = value >> bit_left; + bit_left += 32; + } + bit_left -= n; + + s->bit_buf = bit_buf; + s->bit_left = bit_left; +} + +static inline u32 av_mod_uintp2(u32 a, u32 p) +{ + return a & ((1 << p) - 1); +} + +static inline void put_sbits(struct put_bits_context *pb, int n, int32_t value) +{ + put_bits(pb, n, av_mod_uintp2(value, n)); +} + +/** + * Write exactly 32 bits into a bitstream. + */ +static void put_bits32(struct put_bits_context *s, u32 value) +{ + u32 bit_buf; + int bit_left; + + bit_buf = s->bit_buf; + bit_left = s->bit_left; + +#ifdef BITSTREAM_WRITER_LE + bit_buf |= value << (32 - bit_left); + if (3 < s->buf_end - s->buf_ptr) { + AV_WL32(s->buf_ptr, bit_buf); + s->buf_ptr += 4; + } else { + pr_err("Internal error, put_bits buffer too small\n"); + } + bit_buf = (uint64_t)value >> bit_left; +#else + bit_buf = (uint64_t)bit_buf << bit_left; + bit_buf |= value >> (32 - bit_left); + if (3 < s->buf_end - s->buf_ptr) { + AV_WB32(s->buf_ptr, bit_buf); + s->buf_ptr += 4; + } else { + pr_err("Internal error, put_bits buffer too small\n"); + } + bit_buf = value; +#endif + + s->bit_buf = bit_buf; + s->bit_left = bit_left; +} + +/** + * Write up to 64 bits into a bitstream. + */ +static inline void put_bits64(struct put_bits_context *s, int n, uint64_t value) +{ + if (n < 32) + put_bits(s, n, value); + else if (n == 32) + put_bits32(s, value); + else if (n < 64) { + u32 lo = value & 0xffffffff; + u32 hi = value >> 32; +#ifdef BITSTREAM_WRITER_LE + put_bits32(s, lo); + put_bits(s, n - 32, hi); +#else + put_bits(s, n - 32, hi); + put_bits32(s, lo); +#endif + } else { + u32 lo = value & 0xffffffff; + u32 hi = value >> 32; +#ifdef BITSTREAM_WRITER_LE + put_bits32(s, lo); + put_bits32(s, hi); +#else + put_bits32(s, hi); + put_bits32(s, lo); +#endif + } +} + +/** + * Return the pointer to the byte where the bitstream writer will put + * the next bit. + */ +static inline u8 *put_bits_ptr(struct put_bits_context *s) +{ + return s->buf_ptr; +} + +/** + * Skip the given number of bytes. + * struct put_bits_context must be flushed & aligned to a byte boundary before calling this. + */ +static inline void skip_put_bytes(struct put_bits_context *s, int n) +{ + s->buf_ptr += n; +} + +/** + * Skip the given number of bits. + * Must only be used if the actual values in the bitstream do not matter. + * If n is 0 the behavior is undefined. + */ +static inline void skip_put_bits(struct put_bits_context *s, int n) +{ + s->bit_left -= n; + s->buf_ptr -= 4 * (s->bit_left >> 5); + s->bit_left &= 31; +} + +/** + * Change the end of the buffer. + * + * @param size the new size in bytes of the buffer where to put bits + */ +static inline void set_put_bits_buffer_size(struct put_bits_context *s, int size) +{ + s->buf_end = s->buf + size; + s->size_in_bits = 8*size; +} + +#endif /* AVCODEC_PUT_BITS_H */ +
diff --git a/drivers/amvdec_ports/vdec_drv_base.h b/drivers/amvdec_ports/vdec_drv_base.h new file mode 100644 index 0000000..990d406 --- /dev/null +++ b/drivers/amvdec_ports/vdec_drv_base.h
@@ -0,0 +1,73 @@ +/* +* 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 _VDEC_DRV_BASE_ +#define _VDEC_DRV_BASE_ + +#include "aml_vcodec_drv.h" + +#include "vdec_drv_if.h" + +struct vdec_common_if { + /** + * (*init)() - initialize decode driver + * @ctx : [in] aml v4l2 context + * @h_vdec : [out] driver handle + */ + int (*init)(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec); + + int (*probe)(unsigned long h_vdec, + struct aml_vcodec_mem *bs, void *out); + + /** + * (*decode)() - trigger decode + * @h_vdec : [in] driver handle + * @bs : [in] input bitstream + * @fb : [in] frame buffer to store decoded frame + * @res_chg : [out] resolution change happen + */ + int (*decode)(unsigned long h_vdec, struct aml_vcodec_mem *bs, + bool *res_chg); + + /** + * (*get_param)() - get driver's parameter + * @h_vdec : [in] driver handle + * @type : [in] input parameter type + * @out : [out] buffer to store query result + */ + int (*get_param)(unsigned long h_vdec, + enum vdec_get_param_type type, void *out); + + /** + * (*set_param)() - set driver's parameter + * @h_vdec : [in] driver handle + * @type : [in] input parameter type + * @in : [in] buffer to store query result + */ + int (*set_param)(unsigned long h_vdec, + enum vdec_set_param_type type, void *in); + + /** + * (*deinit)() - deinitialize driver. + * @h_vdec : [in] driver handle to be deinit + */ + void (*deinit)(unsigned long h_vdec); +}; + +#endif
diff --git a/drivers/amvdec_ports/vdec_drv_if.c b/drivers/amvdec_ports/vdec_drv_if.c new file mode 100644 index 0000000..01510c5 --- /dev/null +++ b/drivers/amvdec_ports/vdec_drv_if.c
@@ -0,0 +1,139 @@ +/* +* 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/interrupt.h> +#include <linux/kernel.h> +#include <linux/slab.h> + +#include "vdec_drv_if.h" +#include "aml_vcodec_dec.h" +#include "vdec_drv_base.h" + +const struct vdec_common_if *get_h264_dec_comm_if(void); +const struct vdec_common_if *get_hevc_dec_comm_if(void); +const struct vdec_common_if *get_vp9_dec_comm_if(void); +const struct vdec_common_if *get_mpeg12_dec_comm_if(void); +const struct vdec_common_if *get_mpeg4_dec_comm_if(void); +const struct vdec_common_if *get_mjpeg_dec_comm_if(void); +const struct vdec_common_if *get_av1_dec_comm_if(void); + +int vdec_if_init(struct aml_vcodec_ctx *ctx, unsigned int fourcc) +{ + int ret = 0; + + switch (fourcc) { + case V4L2_PIX_FMT_H264: + ctx->dec_if = get_h264_dec_comm_if(); + break; + case V4L2_PIX_FMT_HEVC: + ctx->dec_if = get_hevc_dec_comm_if(); + break; + case V4L2_PIX_FMT_VP9: + ctx->dec_if = get_vp9_dec_comm_if(); + break; + case V4L2_PIX_FMT_MPEG: + case V4L2_PIX_FMT_MPEG1: + case V4L2_PIX_FMT_MPEG2: + ctx->dec_if = get_mpeg12_dec_comm_if(); + break; + case V4L2_PIX_FMT_MPEG4: + ctx->dec_if = get_mpeg4_dec_comm_if(); + break; + case V4L2_PIX_FMT_MJPEG: + ctx->dec_if = get_mjpeg_dec_comm_if(); + break; + case V4L2_PIX_FMT_AV1: + ctx->dec_if = get_av1_dec_comm_if(); + break; + default: + return -EINVAL; + } + + ret = ctx->dec_if->init(ctx, &ctx->drv_handle); + + return ret; +} + +int vdec_if_probe(struct aml_vcodec_ctx *ctx, + struct aml_vcodec_mem *bs, void *out) +{ + int ret = 0; + + ret = ctx->dec_if->probe(ctx->drv_handle, bs, out); + + return ret; +} + +int vdec_if_decode(struct aml_vcodec_ctx *ctx, + struct aml_vcodec_mem *bs, bool *res_chg) +{ + int ret = 0; + + if (bs) { + if ((bs->addr & 63) != 0) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "bs dma_addr should 64 byte align\n"); + return -EINVAL; + } + } + + if (ctx->drv_handle == 0) + return -EIO; + + aml_vcodec_set_curr_ctx(ctx->dev, ctx); + ret = ctx->dec_if->decode(ctx->drv_handle, bs, res_chg); + aml_vcodec_set_curr_ctx(ctx->dev, NULL); + + return ret; +} + +int vdec_if_get_param(struct aml_vcodec_ctx *ctx, + enum vdec_get_param_type type, void *out) +{ + int ret = 0; + + if (ctx->drv_handle == 0) + return -EIO; + + ret = ctx->dec_if->get_param(ctx->drv_handle, type, out); + + 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) + return; + + ctx->dec_if->deinit(ctx->drv_handle); + ctx->drv_handle = 0; +}
diff --git a/drivers/amvdec_ports/vdec_drv_if.h b/drivers/amvdec_ports/vdec_drv_if.h new file mode 100644 index 0000000..29911f8 --- /dev/null +++ b/drivers/amvdec_ports/vdec_drv_if.h
@@ -0,0 +1,165 @@ +/* +* 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 _VDEC_DRV_IF_H_ +#define _VDEC_DRV_IF_H_ + +#include "aml_vcodec_drv.h" +#include "aml_vcodec_dec.h" +#include "aml_vcodec_util.h" +#include "../stream_input/amports/streambuf.h" + +#define AML_VIDEO_MAGIC CODEC_MODE('A', 'M', 'L', 'V') + +#define V4L_STREAM_TYPE_MATEDATA (0) +#define V4L_STREAM_TYPE_FRAME (1) + +struct stream_info { + u32 stream_width; + u32 stream_height; + u32 stream_field; + u32 stream_dpb; +}; + +struct aml_video_stream { + u32 magic; + u32 type; + union { + struct stream_info s; + u8 buf[64]; + } m; + u32 len; + u8 data[0]; +}; + +/** + * struct vdec_fb_status - decoder frame buffer status + * @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_INIT, + FB_ST_DECODER, + FB_ST_VPP, + FB_ST_GE2D, + FB_ST_DISPLAY, + FB_ST_FREE +}; + +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_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_PIC_INFO, + GET_PARAM_CROP_INFO, + GET_PARAM_DPB_SIZE, + GET_PARAM_CONFIG_INFO, + GET_PARAM_DW_MODE, + GET_PARAM_COMP_BUF_INFO +}; + +/* + * SET_PARAM_PS_INFO : set picture parms, data parsed from ucode. + */ +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_PIC_INFO, + SET_PARAM_CFG_INFO +}; + +/** + * struct vdec_fb_node - decoder frame buffer node + * @list : list to hold this node + * @fb : point to frame buffer (vdec_fb), fb could point to frame buffer and + * working buffer this is for maintain buffers in different state + */ +struct vdec_fb_node { + struct list_head list; + struct vdec_fb *fb; +}; + +/** + * vdec_if_init() - initialize decode driver + * @ctx : [in] v4l2 context + * @fourcc : [in] video format fourcc, V4L2_PIX_FMT_H264/VP8/VP9.. + */ +int vdec_if_init(struct aml_vcodec_ctx *ctx, unsigned int fourcc); + +int vdec_if_probe(struct aml_vcodec_ctx *ctx, + struct aml_vcodec_mem *bs, void *out); + +/** + * vdec_if_deinit() - deinitialize decode driver + * @ctx : [in] v4l2 context + * + */ +void vdec_if_deinit(struct aml_vcodec_ctx *ctx); + +/** + * vdec_if_decode() - trigger decode + * @ctx : [in] v4l2 context + * @bs : [in] input bitstream + * @fb : [in] frame buffer to store decoded frame, when null menas parse + * header only + * @res_chg : [out] resolution change happens if current bs have different + * picture width/height + * Note: To flush the decoder when reaching EOF, set input bitstream as NULL. + * + * Return: 0 on success. -EIO on unrecoverable error. + */ +int vdec_if_decode(struct aml_vcodec_ctx *ctx, + struct aml_vcodec_mem *bs, bool *res_chg); + +/** + * vdec_if_get_param() - get driver's parameter + * @ctx : [in] v4l2 context + * @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_set_param(struct aml_vcodec_ctx *ctx, + enum vdec_set_param_type type, void *in); + +#endif
diff --git a/drivers/common/Makefile b/drivers/common/Makefile new file mode 100644 index 0000000..77ce080 --- /dev/null +++ b/drivers/common/Makefile
@@ -0,0 +1,2 @@ +obj-y += media_clock/ +obj-y += firmware/
diff --git a/drivers/common/chips/chips.c b/drivers/common/chips/chips.c new file mode 100644 index 0000000..158e32c --- /dev/null +++ b/drivers/common/chips/chips.c
@@ -0,0 +1,198 @@ +/* + * drivers/amlogic/media/common/arch/chips/chips.c + * + * Copyright (C) 2016 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/vmalloc.h> +#include <linux/mm.h> + +#include <linux/amlogic/media/utils/vformat.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" +#include <linux/amlogic/media/utils/log.h> +#include <linux/amlogic/media/utils/vdec_reg.h> +#include "decoder_cpu_ver_info.h" + +#define VIDEO_FIRMWARE_FATHER_NAME "video" + +/* + *#define MESON_CPU_MAJOR_ID_M6 0x16 + *#define MESON_CPU_MAJOR_ID_M6TV 0x17 + *#define MESON_CPU_MAJOR_ID_M6TVL 0x18 + *#define MESON_CPU_MAJOR_ID_M8 0x19 + *#define MESON_CPU_MAJOR_ID_MTVD 0x1A + *#define MESON_CPU_MAJOR_ID_M8B 0x1B + *#define MESON_CPU_MAJOR_ID_MG9TV 0x1C + *#define MESON_CPU_MAJOR_ID_M8M2 0x1D + *#define MESON_CPU_MAJOR_ID_GXBB 0x1F + *#define MESON_CPU_MAJOR_ID_GXTVBB 0x20 + *#define MESON_CPU_MAJOR_ID_GXL 0x21 + *#define MESON_CPU_MAJOR_ID_GXM 0x22 + *#define MESON_CPU_MAJOR_ID_TXL 0x23 + */ +struct type_name { + + int type; + + const char *name; +}; +static const struct type_name cpu_type_name[] = { + {AM_MESON_CPU_MAJOR_ID_M6, "m6"}, + {AM_MESON_CPU_MAJOR_ID_M6TV, "m6tv"}, + {AM_MESON_CPU_MAJOR_ID_M6TVL, "m6tvl"}, + {AM_MESON_CPU_MAJOR_ID_M8, "m8"}, + {AM_MESON_CPU_MAJOR_ID_MTVD, "mtvd"}, + {AM_MESON_CPU_MAJOR_ID_M8B, "m8b"}, + {AM_MESON_CPU_MAJOR_ID_MG9TV, "mg9tv"}, + {AM_MESON_CPU_MAJOR_ID_M8M2, "m8"}, + {AM_MESON_CPU_MAJOR_ID_GXBB, "gxbb"}, + {AM_MESON_CPU_MAJOR_ID_GXTVBB, "gxtvbb"}, + {AM_MESON_CPU_MAJOR_ID_GXL, "gxl"}, + {AM_MESON_CPU_MAJOR_ID_GXM, "gxm"}, + {AM_MESON_CPU_MAJOR_ID_TXL, "txl"}, + {AM_MESON_CPU_MAJOR_ID_TXLX, "txlx"}, + {AM_MESON_CPU_MAJOR_ID_GXLX, "gxlx"}, + {AM_MESON_CPU_MAJOR_ID_G12A, "g12a"}, + {AM_MESON_CPU_MAJOR_ID_G12B, "g12b"}, + {AM_MESON_CPU_MAJOR_ID_SM1, "sm1"}, + {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}, +}; + +static const char *get_type_name(const struct type_name *typename, int size, + int type) +{ + + const char *name = "unknown"; + + int i; + + for (i = 0; i < size; i++) { + + if (type == typename[i].type) + + name = typename[i].name; + + } + + return name; +} + +const char *get_cpu_type_name(void) +{ + + return get_type_name(cpu_type_name, + sizeof(cpu_type_name) / sizeof(struct type_name), + get_cpu_major_id()); +} +EXPORT_SYMBOL(get_cpu_type_name); + +/* + *enum vformat_e { + * VFORMAT_MPEG12 = 0, + * VFORMAT_MPEG4, + * VFORMAT_H264, + * VFORMAT_MJPEG, + * VFORMAT_REAL, + * VFORMAT_JPEG, + * VFORMAT_VC1, + * VFORMAT_AVS, + * VFORMAT_YUV, + * VFORMAT_H264MVC, + * VFORMAT_H264_4K2K, + * VFORMAT_HEVC, + * VFORMAT_H264_ENC, + * VFORMAT_JPEG_ENC, + * VFORMAT_VP9, +* VFORMAT_AVS2, + * VFORMAT_MAX + *}; + */ +static const struct type_name vformat_type_name[] = { + {VFORMAT_MPEG12, "mpeg12"}, + {VFORMAT_MPEG4, "mpeg4"}, + {VFORMAT_H264, "h264"}, + {VFORMAT_MJPEG, "mjpeg"}, + {VFORMAT_REAL, "real"}, + {VFORMAT_JPEG, "jpeg"}, + {VFORMAT_VC1, "vc1"}, + {VFORMAT_AVS, "avs"}, + {VFORMAT_YUV, "yuv"}, + {VFORMAT_H264MVC, "h264mvc"}, + {VFORMAT_H264_4K2K, "h264_4k"}, + {VFORMAT_HEVC, "hevc"}, + {VFORMAT_H264_ENC, "h264_enc"}, + {VFORMAT_JPEG_ENC, "jpeg_enc"}, + {VFORMAT_VP9, "vp9"}, + {VFORMAT_AVS2, "avs2"}, + {VFORMAT_AV1, "av1"}, + {VFORMAT_YUV, "yuv"}, + {0, NULL}, +}; + +const char *get_video_format_name(enum vformat_e type) +{ + + return get_type_name(vformat_type_name, + sizeof(vformat_type_name) / sizeof(struct type_name), type); +} +EXPORT_SYMBOL(get_video_format_name); + +static struct chip_vdec_info_s current_chip_info; + +struct chip_vdec_info_s *get_current_vdec_chip(void) +{ + + return ¤t_chip_info; +} +EXPORT_SYMBOL(get_current_vdec_chip); + +bool check_efuse_chip(int vformat) +{ + unsigned int status, i = 0; + int type[] = {15, 14, 11, 2}; /* avs2, vp9, h265, h264 */ + + status = (READ_EFUSE_REG(EFUSE_LIC2) >> 8 & 0xf); + if (!status) + return false; + + do { + if ((status & 1) && (type[i] == vformat)) + return true; + i++; + } while (status >>= 1); + + return false; +} +EXPORT_SYMBOL(check_efuse_chip); +
diff --git a/drivers/common/chips/chips.h b/drivers/common/chips/chips.h new file mode 100644 index 0000000..003e9d2 --- /dev/null +++ b/drivers/common/chips/chips.h
@@ -0,0 +1,40 @@ +/* + * drivers/amlogic/media/common/arch/chips/chips.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 UCODE_MANAGER_HEADER +#define UCODE_MANAGER_HEADER +#include "../media_clock/clk/clk_priv.h" + +struct chip_vdec_info_s { + + int cpu_type; + + struct video_firmware_s *firmware; + + struct chip_vdec_clk_s *clk_mgr[VDEC_MAX]; + + struct clk_set_setting *clk_setting_array; +}; + +const char *get_cpu_type_name(void); +const char *get_video_format_name(enum vformat_e type); + +struct chip_vdec_info_s *get_current_vdec_chip(void); + +bool check_efuse_chip(int vformat); + +#endif
diff --git a/drivers/common/chips/decoder_cpu_ver_info.c b/drivers/common/chips/decoder_cpu_ver_info.c new file mode 100644 index 0000000..af162b8 --- /dev/null +++ b/drivers/common/chips/decoder_cpu_ver_info.c
@@ -0,0 +1,271 @@ +/* +* 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/kernel.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/platform_device.h> +#include <linux/of_device.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" +#define AM_SUCESS 0 +#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]= +{ + AM_MESON_CPU_MAJOR_ID_M6, + AM_MESON_CPU_MAJOR_ID_M6TV, + AM_MESON_CPU_MAJOR_ID_M6TVL, + AM_MESON_CPU_MAJOR_ID_M8, + AM_MESON_CPU_MAJOR_ID_MTVD, + AM_MESON_CPU_MAJOR_ID_M8B, + AM_MESON_CPU_MAJOR_ID_MG9TV, + AM_MESON_CPU_MAJOR_ID_M8M2, + AM_MESON_CPU_MAJOR_ID_UNUSE, + AM_MESON_CPU_MAJOR_ID_GXBB, + AM_MESON_CPU_MAJOR_ID_GXTVBB, + AM_MESON_CPU_MAJOR_ID_GXL, + AM_MESON_CPU_MAJOR_ID_GXM, + AM_MESON_CPU_MAJOR_ID_TXL, + AM_MESON_CPU_MAJOR_ID_TXLX, + AM_MESON_CPU_MAJOR_ID_AXG, + AM_MESON_CPU_MAJOR_ID_GXLX, + AM_MESON_CPU_MAJOR_ID_TXHD, + AM_MESON_CPU_MAJOR_ID_G12A, + AM_MESON_CPU_MAJOR_ID_G12B, + AM_MESON_CPU_MAJOR_ID_GXLX2, + AM_MESON_CPU_MAJOR_ID_SM1, + 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_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[] = { + { + .compatible = "amlogic, cpu-major-id-axg", + .data = &cpu_ver_info[AM_MESON_CPU_MAJOR_ID_AXG - MAJOR_ID_START], + }, + + { + .compatible = "amlogic, cpu-major-id-g12a", + .data = &cpu_ver_info[AM_MESON_CPU_MAJOR_ID_G12A - MAJOR_ID_START], + }, + + { + .compatible = "amlogic, cpu-major-id-gxl", + .data = &cpu_ver_info[AM_MESON_CPU_MAJOR_ID_GXL - MAJOR_ID_START], + }, + + { + .compatible = "amlogic, cpu-major-id-gxm", + .data = &cpu_ver_info[AM_MESON_CPU_MAJOR_ID_GXM - MAJOR_ID_START], + }, + + { + .compatible = "amlogic, cpu-major-id-txl", + .data = &cpu_ver_info[AM_MESON_CPU_MAJOR_ID_TXL - MAJOR_ID_START], + }, + + { + .compatible = "amlogic, cpu-major-id-txlx", + .data = &cpu_ver_info[AM_MESON_CPU_MAJOR_ID_TXLX - MAJOR_ID_START], + }, + + { + .compatible = "amlogic, cpu-major-id-sm1", + .data = &cpu_ver_info[AM_MESON_CPU_MAJOR_ID_SM1 - MAJOR_ID_START], + }, + + { + .compatible = "amlogic, cpu-major-id-tl1", + .data = &cpu_ver_info[AM_MESON_CPU_MAJOR_ID_TL1 - MAJOR_ID_START], + }, + { + .compatible = "amlogic, cpu-major-id-tm2", + .data = &cpu_ver_info[AM_MESON_CPU_MAJOR_ID_TM2 - MAJOR_ID_START], + }, + { + .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 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, +}; + +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) + 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; + } + } + + *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; +} + +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, &sub_id)) { + cpu_ver_id = id_type; + 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) && (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) +{ + if (AM_MESON_CPU_MAJOR_ID_MAX == cpu_ver_id) + initial_cpu_id(); + + return cpu_ver_id; +} +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_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 new file mode 100644 index 0000000..6129244 --- /dev/null +++ b/drivers/common/chips/decoder_cpu_ver_info.h
@@ -0,0 +1,95 @@ +/* +* 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 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 { + AM_MESON_CPU_MAJOR_ID_M6 = 0x16, + AM_MESON_CPU_MAJOR_ID_M6TV = 0x17, + AM_MESON_CPU_MAJOR_ID_M6TVL = 0x18, + AM_MESON_CPU_MAJOR_ID_M8 = 0x19, + AM_MESON_CPU_MAJOR_ID_MTVD = 0x1A, + AM_MESON_CPU_MAJOR_ID_M8B = 0x1B, + AM_MESON_CPU_MAJOR_ID_MG9TV = 0x1C, + AM_MESON_CPU_MAJOR_ID_M8M2 = 0x1D, + AM_MESON_CPU_MAJOR_ID_UNUSE = 0x1E, + AM_MESON_CPU_MAJOR_ID_GXBB = 0x1F, + AM_MESON_CPU_MAJOR_ID_GXTVBB = 0x20, + AM_MESON_CPU_MAJOR_ID_GXL = 0x21, + AM_MESON_CPU_MAJOR_ID_GXM = 0x22, + AM_MESON_CPU_MAJOR_ID_TXL = 0x23, + AM_MESON_CPU_MAJOR_ID_TXLX = 0x24, + AM_MESON_CPU_MAJOR_ID_AXG = 0x25, + AM_MESON_CPU_MAJOR_ID_GXLX = 0x26, + AM_MESON_CPU_MAJOR_ID_TXHD = 0x27, + AM_MESON_CPU_MAJOR_ID_G12A = 0x28, + 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_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_C1 = 0x30, + AM_MESON_CPU_MAJOR_ID_RES_0x31, + AM_MESON_CPU_MAJOR_ID_SC2 = 0x32, + 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/Makefile b/drivers/common/firmware/Makefile new file mode 100644 index 0000000..748039c --- /dev/null +++ b/drivers/common/firmware/Makefile
@@ -0,0 +1,3 @@ +obj-m += firmware.o +firmware-objs += firmware_drv.o +firmware-objs += firmware_type.o
diff --git a/drivers/common/firmware/firmware_cfg.h b/drivers/common/firmware/firmware_cfg.h new file mode 100644 index 0000000..e23ac2a --- /dev/null +++ b/drivers/common/firmware/firmware_cfg.h
@@ -0,0 +1,32 @@ +/* + * drivers/amlogic/media/common/firmware/firmware_cfg.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. + * + */ + +/*all firmwares in one bin.*/ +{VIDEO_MISC, VIDEO_PACKAGE, "video_ucode.bin"}, + +/* Note: if the addition of new package has the same name */ +/* as the firmware in the video_ucode.bin, the firmware */ +/* in the video_ucode.bin will be ignored yet, because the */ +/* video_ucode.bin will always be processed in the end */ +{VIDEO_ENCODE, VIDEO_PACKAGE, "h264_enc.bin"}, + + +/*firmware for a special format, to replace the format in the package.*/ +/*{VIDEO_DECODE, VIDEO_FW_FILE, "h265.bin"},*/ +/*{VIDEO_DECODE, VIDEO_FW_FILE, "h264.bin"},*/ +/*{VIDEO_DECODE, VIDEO_FW_FILE, "h264_multi.bin"},*/ +
diff --git a/drivers/common/firmware/firmware_drv.c b/drivers/common/firmware/firmware_drv.c new file mode 100644 index 0000000..9422198 --- /dev/null +++ b/drivers/common/firmware/firmware_drv.c
@@ -0,0 +1,1056 @@ +/* + * drivers/amlogic/media/common/firmware/firmware.c + * + * Copyright (C) 2016 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/vmalloc.h> +#include <linux/mm.h> +#include <linux/slab.h> + +#include <linux/amlogic/media/utils/vformat.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" +#include "../chips/chips.h" +#include <linux/string.h> +#include <linux/amlogic/media/utils/log.h> +#include <linux/firmware.h> +#include <linux/amlogic/tee.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.3" + +#define CLASS_NAME "firmware_codec" +#define DEV_NAME "firmware_vdec" +#define DIR "video" +#define FRIMWARE_SIZE (64 * 1024) /*64k*/ +#define BUFF_SIZE (1024 * 1024 * 2) + +#define FW_LOAD_FORCE (0x1) +#define FW_LOAD_TRY (0X2) + +/*the first 256 bytes are signature data*/ +#define SEC_OFFSET (256) + +#define TRY_PARSE_MAX (256) + +#define PACK ('P' << 24 | 'A' << 16 | 'C' << 8 | 'K') +#define CODE ('C' << 24 | 'O' << 16 | 'D' << 8 | 'E') + +#ifndef FIRMWARE_MAJOR +#define FIRMWARE_MAJOR AMSTREAM_MAJOR +#endif + +static DEFINE_MUTEX(mutex); + +static struct ucode_file_info_s ucode_info[] = { +#include "firmware_cfg.h" +}; + +static const struct file_operations fw_fops = { + .owner = THIS_MODULE +}; + +struct fw_mgr_s *g_mgr; +struct fw_dev_s *g_dev; +struct package_head_s package_head; + +static u32 debug; +static u32 detail; + +int get_firmware_data(unsigned int format, char *buf) +{ + int data_len, ret = -1; + struct fw_mgr_s *mgr = g_mgr; + struct fw_info_s *info; + + pr_info("[%s], the fw (%s) will be loaded...\n", + tee_enabled() ? "TEE" : "LOCAL", + get_fw_format_name(format)); + + if (tee_enabled()) + return 0; + + mutex_lock(&mutex); + + if (list_empty(&mgr->fw_head)) { + pr_info("the info list is empty.\n"); + goto out; + } + + list_for_each_entry(info, &mgr->fw_head, node) { + if (format != info->format) + continue; + + data_len = info->data->head.data_size; + memcpy(buf, info->data->data, data_len); + ret = data_len; + + break; + } + +out: + mutex_unlock(&mutex); + + return ret; +} +EXPORT_SYMBOL(get_firmware_data); + +int get_data_from_name(const char *name, char *buf) +{ + int data_len, ret = -1; + struct fw_mgr_s *mgr = g_mgr; + struct fw_info_s *info; + char *fw_name = __getname(); + int len; + + if (fw_name == NULL) + return -ENOMEM; + + len = snprintf(fw_name, PATH_MAX, "%s.bin", name); + if (len >= PATH_MAX) { + __putname(fw_name); + return -ENAMETOOLONG; + } + + mutex_lock(&mutex); + + if (list_empty(&mgr->fw_head)) { + pr_info("the info list is empty.\n"); + goto out; + } + + list_for_each_entry(info, &mgr->fw_head, node) { + if (strcmp(fw_name, info->name)) + continue; + + data_len = info->data->head.data_size; + memcpy(buf, info->data->data, data_len); + ret = data_len; + + break; + } +out: + mutex_unlock(&mutex); + + __putname(fw_name); + + return ret; +} +EXPORT_SYMBOL(get_data_from_name); + +static int fw_probe(char *buf) +{ + int magic = 0; + + memcpy(&magic, buf, sizeof(int)); + return magic; +} + +static int request_firmware_from_sys(const char *file_name, + char *buf, int size) +{ + int ret = -1; + const struct firmware *fw; + int magic, offset = 0; + + pr_info("Try to load %s ...\n", file_name); + + ret = request_firmware(&fw, file_name, g_dev->dev); + if (ret < 0) { + pr_info("Error : %d can't load the %s.\n", ret, file_name); + goto err; + } + + if (fw->size > size) { + pr_info("Not enough memory size for ucode.\n"); + ret = -ENOMEM; + goto release; + } + + magic = fw_probe((char *)fw->data); + if (magic != PACK && magic != CODE) { + if (fw->size < SEC_OFFSET) { + pr_info("This is an invalid firmware file.\n"); + goto release; + } + + magic = fw_probe((char *)fw->data + SEC_OFFSET); + if (magic != PACK) { + pr_info("The firmware file is not packet.\n"); + goto release; + } + + offset = SEC_OFFSET; + } + + memcpy(buf, (char *)fw->data + offset, fw->size - offset); + + pr_info("load firmware size : %zd, Name : %s.\n", + fw->size, file_name); + ret = fw->size; +release: + release_firmware(fw); +err: + return ret; +} + +int request_decoder_firmware_on_sys(enum vformat_e format, + const char *file_name, char *buf, int size) +{ + int ret; + + ret = get_data_from_name(file_name, buf); + if (ret < 0) + pr_info("Get firmware fail.\n"); + + if (ret > size) { + pr_info("Not enough memory.\n"); + return -ENOMEM; + } + + return ret; +} +int get_decoder_firmware_data(enum vformat_e format, + const char *file_name, char *buf, int size) +{ + int ret; + + ret = request_decoder_firmware_on_sys(format, file_name, buf, size); + if (ret < 0) + pr_info("get_decoder_firmware_data %s for format %d failed!\n", + file_name, format); + + return ret; +} +EXPORT_SYMBOL(get_decoder_firmware_data); + +static unsigned long fw_mgr_lock(struct fw_mgr_s *mgr) +{ + unsigned long flags; + + spin_lock_irqsave(&mgr->lock, flags); + return flags; +} + +static void fw_mgr_unlock(struct fw_mgr_s *mgr, unsigned long flags) +{ + spin_unlock_irqrestore(&mgr->lock, flags); +} + +static void fw_add_info(struct fw_info_s *info) +{ + unsigned long flags; + struct fw_mgr_s *mgr = g_mgr; + + flags = fw_mgr_lock(mgr); + list_add(&info->node, &mgr->fw_head); + fw_mgr_unlock(mgr, flags); +} + +static void fw_del_info(struct fw_info_s *info) +{ + unsigned long flags; + struct fw_mgr_s *mgr = g_mgr; + + flags = fw_mgr_lock(mgr); + list_del(&info->node); + kfree(info); + fw_mgr_unlock(mgr, flags); +} + +static void fw_info_walk(void) +{ + struct fw_mgr_s *mgr = g_mgr; + struct fw_info_s *info; + + if (list_empty(&mgr->fw_head)) { + pr_info("the info list is empty.\n"); + return; + } + + list_for_each_entry(info, &mgr->fw_head, node) { + if (IS_ERR_OR_NULL(info->data)) + continue; + + pr_info("name : %s.\n", info->name); + pr_info("ver : %s.\n", + info->data->head.version); + pr_info("crc : 0x%x.\n", + info->data->head.checksum); + pr_info("size : %d.\n", + info->data->head.data_size); + pr_info("maker: %s.\n", + info->data->head.maker); + pr_info("from : %s.\n", info->src_from); + pr_info("date : %s.\n", + info->data->head.date); + if (info->data->head.duplicate) + pr_info("NOTE : Dup from %s.\n", + info->data->head.dup_from); + pr_info("\n"); + } +} + +static void fw_files_info_walk(void) +{ + struct fw_mgr_s *mgr = g_mgr; + struct fw_files_s *files; + + if (list_empty(&mgr->files_head)) { + pr_info("the file list is empty.\n"); + return; + } + + list_for_each_entry(files, &mgr->files_head, node) { + pr_info("type : %s.\n", !files->fw_type ? + "VIDEO_DECODE" : files->fw_type == 1 ? + "VIDEO_ENCODE" : "VIDEO_MISC"); + pr_info("from : %s.\n", !files->file_type ? + "VIDEO_PACKAGE" : "VIDEO_FW_FILE"); + pr_info("path : %s.\n", files->path); + pr_info("name : %s.\n\n", files->name); + } +} + +static ssize_t info_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + char *pbuf = buf; + struct fw_mgr_s *mgr = g_mgr; + struct fw_info_s *info; + unsigned int secs = 0; + struct tm tm; + char history_change_id[7] = {0}; + int i; + + mutex_lock(&mutex); + + if (list_empty(&mgr->fw_head)) { + pbuf += sprintf(pbuf, "No firmware.\n"); + goto out; + } + + /* shows version of driver. */ + 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)) + continue; + + if (detail) { + pr_info("%-5s: %s\n", "name", info->name); + pr_info("%-5s: %s\n", "ver", + info->data->head.version); + pr_info("%-5s: 0x%x\n", "sum", + info->data->head.checksum); + pr_info("%-5s: %d\n", "size", + info->data->head.data_size); + pr_info("%-5s: %s\n", "maker", + info->data->head.maker); + pr_info("%-5s: %s\n", "from", + info->src_from); + pr_info("%-5s: %s\n\n", "date", + info->data->head.date); + continue; + } + + secs = info->data->head.time + - sys_tz.tz_minuteswest * 60; + //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, + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_mon + 1, tm.tm_mday, tm.tm_year + 1900, + "cmtid:", info->data->head.commit, + "chgid:", info->data->head.change_id, + "mk:", info->data->head.maker); + } +out: + mutex_unlock(&mutex); + + return pbuf - buf; +} + +static ssize_t info_store(struct class *cls, + struct class_attribute *attr, const char *buf, size_t count) +{ + if (kstrtoint(buf, 0, &detail) < 0) + return -EINVAL; + + return count; +} + +static int fw_info_fill(void) +{ + int ret = 0, i, len; + struct fw_mgr_s *mgr = g_mgr; + struct fw_files_s *files; + int info_size = ARRAY_SIZE(ucode_info); + char *path = __getname(); + const char *name; + + if (path == NULL) + return -ENOMEM; + + for (i = 0; i < info_size; i++) { + name = ucode_info[i].name; + if (IS_ERR_OR_NULL(name)) + break; + + len = snprintf(path, PATH_MAX, "%s/%s", DIR, + ucode_info[i].name); + if (len >= PATH_MAX) + continue; + + files = kzalloc(sizeof(struct fw_files_s), GFP_KERNEL); + if (files == NULL) { + __putname(path); + return -ENOMEM; + } + + files->file_type = ucode_info[i].file_type; + files->fw_type = ucode_info[i].fw_type; + strncpy(files->path, path, sizeof(files->path)); + files->path[sizeof(files->path) - 1] = '\0'; + strncpy(files->name, name, sizeof(files->name)); + files->name[sizeof(files->name) - 1] = '\0'; + + list_add(&files->node, &mgr->files_head); + } + + __putname(path); + + if (debug) + fw_files_info_walk(); + + return ret; +} + +static int fw_data_check_sum(struct firmware_s *fw) +{ + unsigned int crc; + + crc = crc32_le(~0U, fw->data, fw->head.data_size); + + /*pr_info("firmware crc result : 0x%x\n", crc ^ ~0U);*/ + + return fw->head.checksum != (crc ^ ~0U) ? 0 : 1; +} + +static int fw_data_filter(struct firmware_s *fw, + struct fw_info_s *fw_info) +{ + struct fw_mgr_s *mgr = g_mgr; + struct fw_info_s *info, *tmp; + int cpu = fw_get_cpu(fw->head.cpu); + + if (mgr->cur_cpu < cpu) { + kfree(fw_info); + kfree(fw); + return -1; + } + + /* the encode fw need to ignoring filtering rules. */ + if (fw_info->format == FIRMWARE_MAX) + return 0; + + list_for_each_entry_safe(info, tmp, &mgr->fw_head, node) { + if (info->format != fw_info->format) + continue; + + if (IS_ERR_OR_NULL(info->data)) { + fw_del_info(info); + return 0; + } + + /* high priority of VIDEO_FW_FILE */ + if (info->file_type == VIDEO_FW_FILE) { + pr_info("the %s need to priority proc.\n",info->name); + kfree(fw_info); + kfree(fw); + return 1; + } + + /* the cpu ver is lower and needs to be filtered */ + if (cpu < fw_get_cpu(info->data->head.cpu)) { + if (debug) + pr_info("keep the newer fw (%s) and ignore the older fw (%s).\n", + info->name, fw_info->name); + kfree(fw_info); + kfree(fw); + return 1; + } + + /* removes not match fw from info list */ + if (debug) + pr_info("drop the old fw (%s) will be load the newer fw (%s).\n", + info->name, fw_info->name); + kfree(info->data); + fw_del_info(info); + } + + return 0; +} + +static int fw_replace_dup_data(char *buf) +{ + int ret = 0; + struct fw_mgr_s *mgr = g_mgr; + struct package_s *pkg = + (struct package_s *) buf; + struct package_info_s *pinfo = + (struct package_info_s *) pkg->data; + struct fw_info_s *info = NULL; + char *pdata = pkg->data; + int try_cnt = TRY_PARSE_MAX; + + do { + if (!pinfo->head.length) + break; + list_for_each_entry(info, &mgr->fw_head, node) { + struct firmware_s *comp = NULL; + struct firmware_s *data = NULL; + int len = 0; + + comp = (struct firmware_s *)pinfo->data; + if (comp->head.duplicate) + break; + + if (!info->data->head.duplicate || + comp->head.checksum != + info->data->head.checksum) + continue; + + len = pinfo->head.length; + data = kzalloc(len, GFP_KERNEL); + if (data == NULL) { + ret = -ENOMEM; + goto out; + } + + memcpy(data, pinfo->data, len); + + /* update header information. */ + memcpy(data, info->data, sizeof(*data)); + + /* if replaced success need to update real size. */ + data->head.data_size = comp->head.data_size; + + kfree(info->data); + info->data = data; + } + pdata += (pinfo->head.length + sizeof(*pinfo)); + pinfo = (struct package_info_s *)pdata; + } while (try_cnt--); +out: + return ret; +} + +static int fw_check_pack_version(char *buf) +{ + struct package_s *pack = NULL; + int major, minor, major_fw, minor_fw; + int ret; + + pack = (struct package_s *) buf; + ret = sscanf(PACK_VERS, "v%x.%x", &major, &minor); + if (ret != 2) + return -1; + + package_head = pack->head; + major_fw = (pack->head.version >> 16) & 0xff; + minor_fw = pack->head.version & 0xff; + + if (major < major_fw) { + pr_info("the pack ver v%d.%d too higher to unsupport.\n", + major_fw, minor_fw); + return -1; + } + + if (minor < minor_fw) { + pr_info("The fw driver version (v%d.%d) is lower than the pkg version (v%d.%d).\n", + major, minor, major_fw, minor_fw); + pr_info("The driver version is too low that may affect the work please update asap.\n"); + } + + 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.%d\n", major_fw, minor_fw, pack->head.submit_count); + } + + return 0; +} + +static int fw_package_parse(struct fw_files_s *files, + char *buf, int size) +{ + int ret = 0; + struct package_info_s *pack_info; + struct fw_info_s *info; + struct firmware_s *data; + char *pack_data; + int info_len, len; + int try_cnt = TRY_PARSE_MAX; + char *path = __getname(); + + if (path == NULL) + return -ENOMEM; + + pack_data = ((struct package_s *)buf)->data; + pack_info = (struct package_info_s *)pack_data; + info_len = sizeof(struct package_info_s); + + do { + if (!pack_info->head.length) + break; + + len = snprintf(path, PATH_MAX, "%s/%s", DIR, + pack_info->head.name); + if (len >= PATH_MAX) + continue; + + info = kzalloc(sizeof(struct fw_info_s), GFP_KERNEL); + if (info == NULL) { + ret = -ENOMEM; + goto out; + } + + data = kzalloc(FRIMWARE_SIZE, GFP_KERNEL); + if (data == NULL) { + kfree(info); + ret = -ENOMEM; + goto out; + } + + info->file_type = files->file_type; + strncpy(info->src_from, files->name, + sizeof(info->src_from)); + info->src_from[sizeof(info->src_from) - 1] = '\0'; + strncpy(info->name, pack_info->head.name, + sizeof(info->name)); + info->name[sizeof(info->name) - 1] = '\0'; + info->format = get_fw_format(pack_info->head.format); + + len = pack_info->head.length; + memcpy(data, pack_info->data, len); + + pack_data += (pack_info->head.length + info_len); + pack_info = (struct package_info_s *)pack_data; + + if (!data->head.duplicate && + !fw_data_check_sum(data)) { + pr_info("check sum fail !\n"); + kfree(data); + kfree(info); + goto out; + } + + if (fw_data_filter(data, info)) + continue; + + if (debug) + pr_info("adds %s to the fw list.\n", info->name); + + info->data = data; + fw_add_info(info); + } while (try_cnt--); + + /* process the fw of dup attribute. */ + ret = fw_replace_dup_data(buf); + if (ret) + pr_err("replace dup fw failed.\n"); +out: + __putname(path); + + return ret; +} + +static int fw_code_parse(struct fw_files_s *files, + char *buf, int size) +{ + struct fw_info_s *info; + + info = kzalloc(sizeof(struct fw_info_s), GFP_KERNEL); + if (info == NULL) + return -ENOMEM; + + info->data = kzalloc(FRIMWARE_SIZE, GFP_KERNEL); + if (info->data == NULL) { + kfree(info); + return -ENOMEM; + } + + info->file_type = files->file_type; + strncpy(info->src_from, files->name, + sizeof(info->src_from)); + info->src_from[sizeof(info->src_from) - 1] = '\0'; + memcpy(info->data, buf, size); + + if (!fw_data_check_sum(info->data)) { + pr_info("check sum fail !\n"); + kfree(info->data); + kfree(info); + return -1; + } + + if (debug) + pr_info("adds %s to the fw list.\n", info->name); + + fw_add_info(info); + + return 0; +} + +static int get_firmware_from_sys(const char *path, + char *buf, int size) +{ + int len = 0; + + len = request_firmware_from_sys(path, buf, size); + if (len < 0) + pr_info("get data from fsys fail.\n"); + + return len; +} + +static int fw_data_binding(void) +{ + int ret = 0, magic = 0; + struct fw_mgr_s *mgr = g_mgr; + struct fw_files_s *files, *tmp; + char *buf = NULL; + int size; + + if (list_empty(&mgr->files_head)) { + pr_info("the file list is empty.\n"); + return 0; + } + + buf = vmalloc(BUFF_SIZE); + if (IS_ERR_OR_NULL(buf)) + return -ENOMEM; + + memset(buf, 0, BUFF_SIZE); + + list_for_each_entry_safe(files, tmp, &mgr->files_head, node) { + size = get_firmware_from_sys(files->path, buf, BUFF_SIZE); + magic = fw_probe(buf); + + if (files->file_type == VIDEO_PACKAGE && magic == PACK) { + if (!fw_check_pack_version(buf)) + ret = fw_package_parse(files, buf, size); + } else if (files->file_type == VIDEO_FW_FILE && magic == CODE) { + ret = fw_code_parse(files, buf, size); + } else { + list_del(&files->node); + kfree(files); + pr_info("invaild file type.\n"); + } + + memset(buf, 0, BUFF_SIZE); + } + + if (debug) + fw_info_walk(); + + vfree(buf); + + return ret; +} + +static int fw_pre_load(void) +{ + if (fw_info_fill() < 0) { + pr_info("Get path fail.\n"); + return -1; + } + + if (fw_data_binding() < 0) { + pr_info("Set data fail.\n"); + return -1; + } + + return 0; +} + +static int fw_mgr_init(void) +{ + g_mgr = kzalloc(sizeof(struct fw_mgr_s), GFP_KERNEL); + if (IS_ERR_OR_NULL(g_mgr)) + return -ENOMEM; + + g_mgr->cur_cpu = get_cpu_major_id(); + INIT_LIST_HEAD(&g_mgr->files_head); + INIT_LIST_HEAD(&g_mgr->fw_head); + spin_lock_init(&g_mgr->lock); + + return 0; +} + +static void fw_ctx_clean(void) +{ + struct fw_mgr_s *mgr = g_mgr; + struct fw_files_s *files; + struct fw_info_s *info; + unsigned long flags; + + flags = fw_mgr_lock(mgr); + while (!list_empty(&mgr->files_head)) { + files = list_entry(mgr->files_head.next, + struct fw_files_s, node); + list_del(&files->node); + kfree(files); + } + + while (!list_empty(&mgr->fw_head)) { + info = list_entry(mgr->fw_head.next, + struct fw_info_s, node); + list_del(&info->node); + kfree(info->data); + kfree(info); + } + fw_mgr_unlock(mgr, flags); +} + +int video_fw_reload(int mode) +{ + int ret = 0; + struct fw_mgr_s *mgr = g_mgr; + + if (tee_enabled()) + return 0; + + mutex_lock(&mutex); + + if (mode & FW_LOAD_FORCE) { + fw_ctx_clean(); + + ret = fw_pre_load(); + if (ret < 0) + pr_err("The fw reload fail.\n"); + } else if (mode & FW_LOAD_TRY) { + if (!list_empty(&mgr->fw_head)) { + pr_info("The fw has been loaded.\n"); + goto out; + } + + ret = fw_pre_load(); + if (ret < 0) + pr_err("The fw try to reload fail.\n"); + } +out: + mutex_unlock(&mutex); + + return ret; +} +EXPORT_SYMBOL(video_fw_reload); + +static ssize_t reload_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + char *pbuf = buf; + + pbuf += sprintf(pbuf, "The fw reload usage.\n"); + pbuf += sprintf(pbuf, "> set 1 means that the fw is forced to update\n"); + pbuf += sprintf(pbuf, "> set 2 means that the fw is try to reload\n"); + + return pbuf - buf; +} + +static ssize_t reload_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t size) +{ + int ret = -1; + unsigned int val; + + ret = kstrtoint(buf, 0, &val); + if (ret != 0) + return -EINVAL; + + ret = video_fw_reload(val); + if (ret < 0) + pr_err("fw reload fail.\n"); + + return size; +} + +static ssize_t debug_show(struct class *cls, + struct class_attribute *attr, char *buf) +{ + return sprintf(buf, "%x\n", debug); +} + +static ssize_t debug_store(struct class *cls, + struct class_attribute *attr, const char *buf, size_t count) +{ + if (kstrtoint(buf, 0, &debug) < 0) + return -EINVAL; + + 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), + __ATTR(debug, 0664, debug_show, debug_store), + __ATTR_NULL +}; + +static struct class fw_class = { + .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; + + g_dev = kzalloc(sizeof(struct fw_dev_s), GFP_KERNEL); + if (IS_ERR_OR_NULL(g_dev)) + return -ENOMEM; + + g_dev->dev_no = MKDEV(FIRMWARE_MAJOR, 100); + + ret = register_chrdev_region(g_dev->dev_no, 1, DEV_NAME); + if (ret < 0) { + pr_info("Can't get major number %d.\n", FIRMWARE_MAJOR); + goto err; + } + + cdev_init(&g_dev->cdev, &fw_fops); + g_dev->cdev.owner = THIS_MODULE; + + ret = cdev_add(&g_dev->cdev, g_dev->dev_no, 1); + if (ret) { + pr_info("Error %d adding cdev fail.\n", ret); + goto err; + } + + ret = class_register(&fw_class); + if (ret < 0) { + pr_info("Failed in creating class.\n"); + goto err; + } + + g_dev->dev = device_create(&fw_class, NULL, + g_dev->dev_no, NULL, DEV_NAME); + if (IS_ERR_OR_NULL(g_dev->dev)) { + pr_info("Create device failed.\n"); + ret = -ENODEV; + goto err; + } + + pr_info("Registered firmware driver success.\n"); +err: + return ret; +} + +static void fw_driver_exit(void) +{ + cdev_del(&g_dev->cdev); + device_destroy(&fw_class, g_dev->dev_no); + class_unregister(&fw_class); + unregister_chrdev_region(g_dev->dev_no, 1); + kfree(g_dev); + kfree(g_mgr); +} + +static int __init fw_module_init(void) +{ + int ret = -1; + + ret = fw_driver_init(); + if (ret) { + pr_info("Error %d firmware driver init fail.\n", ret); + goto err; + } + + ret = fw_mgr_init(); + if (ret) { + pr_info("Error %d firmware mgr init fail.\n", ret); + goto err; + } + + ret = fw_pre_load(); + if (ret) { + pr_info("Error %d firmware pre load fail.\n", ret); + goto err; + } +err: + return ret; +} + +static void __exit fw_module_exit(void) +{ + fw_ctx_clean(); + fw_driver_exit(); + pr_info("Firmware driver cleaned up.\n"); +} + +module_init(fw_module_init); +module_exit(fw_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Nanxin Qin <nanxin.qin@amlogic.com>");
diff --git a/drivers/common/firmware/firmware_priv.h b/drivers/common/firmware/firmware_priv.h new file mode 100644 index 0000000..d901f9d --- /dev/null +++ b/drivers/common/firmware/firmware_priv.h
@@ -0,0 +1,124 @@ +/* + * drivers/amlogic/media/common/firmware/firmware.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 __VIDEO_FIRMWARE_PRIV_HEAD_ +#define __VIDEO_FIRMWARE_PRIV_HEAD_ +#include <linux/types.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/cdev.h> +#include "firmware_type.h" + +struct fw_mgr_s { + struct list_head fw_head; + struct list_head files_head; + spinlock_t lock; + int cur_cpu; +}; + +struct fw_files_s { + struct list_head node; + int fw_type; + int file_type; + char name[32]; + char path[64]; +}; + +struct ucode_file_info_s { + int fw_type; + int file_type; + const char *name; +}; + +struct fw_info_s { + struct list_head node; + char name[32]; + char src_from[32]; + int file_type; + unsigned int format; + struct firmware_s *data; +}; + +struct fw_head_s { + int magic; + int checksum; + char name[32]; + char cpu[16]; + char format[32]; + char version[32]; + char maker[32]; + char date[32]; + char commit[16]; + int data_size; + unsigned int time; + char change_id[16]; + int duplicate; + char dup_from[16]; + char reserved[92]; +}; + +struct firmware_s { + union { + struct fw_head_s head; + char buf[512]; + }; + char data[0]; +}; + +struct package_head_s { + int magic; + int size; + int checksum; + int total; + int version; + int submit_count; + char change_id[16]; + char commit[16]; + char history_change_id[30]; + char reserved[62]; +}; + +struct package_s { + union { + struct package_head_s head; + char buf[256]; + }; + char data[0]; +}; + +struct info_head_s { + char name[32]; + char format[32]; + char cpu[32]; + int length; +}; + +struct package_info_s { + union { + struct info_head_s head; + char buf[256]; + }; + char data[0]; +}; + +struct fw_dev_s { + struct cdev cdev; + struct device *dev; + dev_t dev_no; +}; + +#endif
diff --git a/drivers/common/firmware/firmware_type.c b/drivers/common/firmware/firmware_type.c new file mode 100644 index 0000000..8d95c12 --- /dev/null +++ b/drivers/common/firmware/firmware_type.c
@@ -0,0 +1,129 @@ +/* +* 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 "firmware_type.h" +#include "../chips/decoder_cpu_ver_info.h" + +static const struct format_name_s format_name[] = { + {VIDEO_DEC_MPEG12, "mpeg12"}, + {VIDEO_DEC_MPEG12_MULTI, "mpeg12_multi"}, + {VIDEO_DEC_MPEG4_3, "mpeg4_3"}, + {VIDEO_DEC_MPEG4_4, "mpeg4_4"}, + {VIDEO_DEC_MPEG4_4_MULTI, "mpeg4_4_multi"}, + {VIDEO_DEC_MPEG4_5, "xvid"}, + {VIDEO_DEC_MPEG4_5_MULTI, "xvid_multi"}, + {VIDEO_DEC_H263, "h263"}, + {VIDEO_DEC_H263_MULTI, "h263_multi"}, + {VIDEO_DEC_MJPEG, "mjpeg"}, + {VIDEO_DEC_MJPEG_MULTI, "mjpeg_multi"}, + {VIDEO_DEC_REAL_V8, "real_v8"}, + {VIDEO_DEC_REAL_V9, "real_v9"}, + {VIDEO_DEC_VC1, "vc1"}, + {VIDEO_DEC_VC1_G12A, "vc1_g12a"}, + {VIDEO_DEC_AVS, "avs"}, + {VIDEO_DEC_AVS_GXM, "avs_gxm"}, + {VIDEO_DEC_AVS_NOCABAC, "avs_no_cabac"}, + {VIDEO_DEC_AVS_MULTI, "avs_multi"}, + {VIDEO_DEC_H264, "h264"}, + {VIDEO_DEC_H264_MVC, "h264_mvc"}, + {VIDEO_DEC_H264_MVC_GXM, "h264_mvc_gxm"}, + {VIDEO_DEC_H264_MULTI, "h264_multi"}, + {VIDEO_DEC_H264_MULTI_MMU, "h264_multi_mmu"}, + {VIDEO_DEC_H264_MULTI_GXM, "h264_multi_gxm"}, + {VIDEO_DEC_HEVC, "hevc"}, + {VIDEO_DEC_HEVC_MMU, "hevc_mmu"}, + {VIDEO_DEC_HEVC_MMU_SWAP, "hevc_mmu_swap"}, + {VIDEO_DEC_HEVC_G12A, "hevc_g12a"}, + {VIDEO_DEC_VP9, "vp9"}, + {VIDEO_DEC_VP9_MMU, "vp9_mmu"}, + {VIDEO_DEC_VP9_G12A, "vp9_g12a"}, + {VIDEO_DEC_AVS2, "avs2"}, + {VIDEO_DEC_AVS2_MMU, "avs2_mmu"}, + {VIDEO_DEC_AV1_MMU, "av1_mmu"}, + {VIDEO_ENC_H264, "h264_enc"}, + {VIDEO_ENC_JPEG, "jpeg_enc"}, + {FIRMWARE_MAX, "unknown"}, +}; + +static const struct cpu_type_s cpu_type[] = { + {AM_MESON_CPU_MAJOR_ID_GXL, "gxl"}, + {AM_MESON_CPU_MAJOR_ID_GXM, "gxm"}, + {AM_MESON_CPU_MAJOR_ID_TXL, "txl"}, + {AM_MESON_CPU_MAJOR_ID_TXLX, "txlx"}, + {AM_MESON_CPU_MAJOR_ID_AXG, "axg"}, + {AM_MESON_CPU_MAJOR_ID_GXLX, "gxlx"}, + {AM_MESON_CPU_MAJOR_ID_TXHD, "txhd"}, + {AM_MESON_CPU_MAJOR_ID_G12A, "g12a"}, + {AM_MESON_CPU_MAJOR_ID_G12B, "g12b"}, + {AM_MESON_CPU_MAJOR_ID_GXLX2, "gxlx2"}, + {AM_MESON_CPU_MAJOR_ID_SM1, "sm1"}, + {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) +{ + const char *name = "unknown"; + int i, size = ARRAY_SIZE(format_name); + + for (i = 0; i < size; i++) { + if (format == format_name[i].format) + name = format_name[i].name; + } + + return name; +} +EXPORT_SYMBOL(get_fw_format_name); + +unsigned int get_fw_format(const char *name) +{ + unsigned int format = FIRMWARE_MAX; + int i, size = ARRAY_SIZE(format_name); + + for (i = 0; i < size; i++) { + if (!strcmp(name, format_name[i].name)) + format = format_name[i].format; + } + + return format; +} +EXPORT_SYMBOL(get_fw_format); + +int fw_get_cpu(const char *name) +{ + int type = 0; + int i, size = ARRAY_SIZE(cpu_type); + + for (i = 0; i < size; i++) { + if (!strcmp(name, cpu_type[i].name)) + type = cpu_type[i].type; + } + + return type; +} +EXPORT_SYMBOL(fw_get_cpu); +
diff --git a/drivers/common/firmware/firmware_type.h b/drivers/common/firmware/firmware_type.h new file mode 100644 index 0000000..4615baf --- /dev/null +++ b/drivers/common/firmware/firmware_type.h
@@ -0,0 +1,99 @@ +/* +* 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 __VIDEO_FIRMWARE_FORMAT_ +#define __VIDEO_FIRMWARE_FORMAT_ + +#include <linux/slab.h> + +/* example: #define VIDEO_DEC_AV1 TAG('A', 'V', '1', '-')*/ +#define TAG(a, b, c, d)\ + ((a << 24) | (b << 16) | (c << 8) | d) + +/* fws define */ +#define VIDEO_DEC_MPEG12 (0) +#define VIDEO_DEC_MPEG4_3 (1) +#define VIDEO_DEC_MPEG4_4 (2) +#define VIDEO_DEC_MPEG4_5 (3) +#define VIDEO_DEC_H263 (4) +#define VIDEO_DEC_MJPEG (5) +#define VIDEO_DEC_MJPEG_MULTI (6) +#define VIDEO_DEC_REAL_V8 (7) +#define VIDEO_DEC_REAL_V9 (8) +#define VIDEO_DEC_VC1 (9) +#define VIDEO_DEC_AVS (10) +#define VIDEO_DEC_H264 (11) +#define VIDEO_DEC_H264_4k2K (12) +#define VIDEO_DEC_H264_4k2K_SINGLE (13) +#define VIDEO_DEC_H264_MVC (14) +#define VIDEO_DEC_H264_MULTI (15) +#define VIDEO_DEC_HEVC (16) +#define VIDEO_DEC_HEVC_MMU (17) +#define VIDEO_DEC_VP9 (18) +#define VIDEO_DEC_VP9_MMU (19) +#define VIDEO_ENC_H264 (20) +#define VIDEO_ENC_JPEG (21) +#define VIDEO_DEC_H264_MULTI_MMU (23) +#define VIDEO_DEC_HEVC_G12A (24) +#define VIDEO_DEC_VP9_G12A (25) +#define VIDEO_DEC_AVS2 (26) +#define VIDEO_DEC_AVS2_MMU (27) +#define VIDEO_DEC_AVS_GXM (28) +#define VIDEO_DEC_AVS_NOCABAC (29) +#define VIDEO_DEC_H264_MULTI_GXM (30) +#define VIDEO_DEC_H264_MVC_GXM (31) +#define VIDEO_DEC_VC1_G12A (32) +#define VIDEO_DEC_MPEG12_MULTI TAG('M', '1', '2', 'M') +#define VIDEO_DEC_MPEG4_4_MULTI TAG('M', '4', '4', 'M') +#define VIDEO_DEC_MPEG4_5_MULTI TAG('M', '4', '5', 'M') +#define VIDEO_DEC_H263_MULTI TAG('2', '6', '3', 'M') +#define VIDEO_DEC_HEVC_MMU_SWAP TAG('2', '6', '5', 'S') +#define VIDEO_DEC_AVS_MULTI TAG('A', 'V', 'S', 'M') +#define VIDEO_DEC_AV1_MMU TAG('A', 'V', '1', 'M') + +/* ... */ +#define FIRMWARE_MAX (UINT_MAX) + +#define VIDEO_PACKAGE (0) +#define VIDEO_FW_FILE (1) + +#define VIDEO_DECODE (0) +#define VIDEO_ENCODE (1) +#define VIDEO_MISC (2) + +#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; + const char *name; +}; + +struct cpu_type_s { + int type; + const char *name; +}; + +const char *get_fw_format_name(unsigned int format); +unsigned int get_fw_format(const char *name); +int fw_get_cpu(const char *name); + +#endif
diff --git a/drivers/common/media_clock/Makefile b/drivers/common/media_clock/Makefile new file mode 100644 index 0000000..975b5e5 --- /dev/null +++ b/drivers/common/media_clock/Makefile
@@ -0,0 +1,6 @@ +obj-m += media_clock.o +media_clock-objs += ../chips/chips.o +media_clock-objs += clk/clkg12.o +media_clock-objs += clk/clk.o +media_clock-objs += switch/amports_gate.o +media_clock-objs += ../chips/decoder_cpu_ver_info.o
diff --git a/drivers/common/media_clock/clk/clk.c b/drivers/common/media_clock/clk/clk.c new file mode 100644 index 0000000..6340c1a --- /dev/null +++ b/drivers/common/media_clock/clk/clk.c
@@ -0,0 +1,473 @@ +/* + * drivers/amlogic/media/common/arch/clk/clk.c + * + * Copyright (C) 2016 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/vmalloc.h> +#include <linux/mm.h> +#include <linux/vmalloc.h> +#include <linux/slab.h> + +#include <linux/amlogic/media/utils/vformat.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" +#include "clk_priv.h" +#include <linux/amlogic/media/utils/log.h> +#include "../../chips/decoder_cpu_ver_info.h" + +#define p_vdec() (get_current_vdec_chip()->clk_mgr[VDEC_1]) +#define p_vdec2() (get_current_vdec_chip()->clk_mgr[VDEC_2]) +#define p_vdec_hcodec() (get_current_vdec_chip()->clk_mgr[VDEC_HCODEC]) +#define p_vdec_hevc() (get_current_vdec_chip()->clk_mgr[VDEC_HEVC]) +#define p_vdec_hevc_back() (get_current_vdec_chip()->clk_mgr[VDEC_HEVCB]) + +static int clock_source_wxhxfps_saved[VDEC_MAX + 1]; + +#define IF_HAVE_RUN(p, fn)\ + do {\ + if (p && p->fn)\ + p->fn();\ + } while (0) +/* + *#define IF_HAVE_RUN_P1_RET(p, fn, p1)\ + * do {\ + * pr_debug("%s-----%d\n", __func__, clk);\ + * if (p && p->fn)\ + * return p->fn(p1);\ + * else\ + * return -1;\ + * } while (0) + * + *#define IF_HAVE_RUN_RET(p, fn)\ + * do {\ + * if (p && p->fn)\ + * return p->fn();\ + * else\ + * return 0;\ + * } while (0) + */ + +int vdec_clock_init(void) +{ + if (p_vdec() && p_vdec()->clock_init) + return p_vdec()->clock_init(); + else + return 0; +} +EXPORT_SYMBOL(vdec_clock_init); + +/* + *clk ==0 : + * to be release. + * released shared clk, + *clk ==1 :default low clk + *clk ==2 :default high clk + */ +int vdec_clock_set(int clk) +{ + pr_debug("%s-----%d\n", __func__, clk); + if (p_vdec() && p_vdec()->clock_set) + return p_vdec()->clock_set(clk); + else + return -1; +} +EXPORT_SYMBOL(vdec_clock_set); + +void vdec_clock_enable(void) +{ + vdec_clock_set(1); +} +EXPORT_SYMBOL(vdec_clock_enable); + +void vdec_clock_hi_enable(void) +{ + vdec_clock_set(2); +} +EXPORT_SYMBOL(vdec_clock_hi_enable); + +void vdec_clock_on(void) +{ + IF_HAVE_RUN(p_vdec(), clock_on); +} +EXPORT_SYMBOL(vdec_clock_on); + +void vdec_clock_off(void) +{ + IF_HAVE_RUN(p_vdec(), clock_off); + clock_source_wxhxfps_saved[VDEC_1] = 0; +} +EXPORT_SYMBOL(vdec_clock_off); + +int vdec2_clock_set(int clk) +{ + pr_debug("%s-----%d\n", __func__, clk); + if (p_vdec2() && p_vdec2()->clock_set) + return p_vdec2()->clock_set(clk); + else + return -1; +} +EXPORT_SYMBOL(vdec2_clock_set); + +void vdec2_clock_enable(void) +{ + vdec2_clock_set(1); +} +EXPORT_SYMBOL(vdec2_clock_enable); + +void vdec2_clock_hi_enable(void) +{ + vdec2_clock_set(2); +} +EXPORT_SYMBOL(vdec2_clock_hi_enable); + +void vdec2_clock_on(void) +{ + IF_HAVE_RUN(p_vdec2(), clock_on); +} +EXPORT_SYMBOL(vdec2_clock_on); + +void vdec2_clock_off(void) +{ + IF_HAVE_RUN(p_vdec2(), clock_off); + clock_source_wxhxfps_saved[VDEC_2] = 0; +} +EXPORT_SYMBOL(vdec2_clock_off); + +int hcodec_clock_set(int clk) +{ + pr_debug("%s-----%d\n", __func__, clk); + if (p_vdec_hcodec() && p_vdec_hcodec()->clock_set) + return p_vdec_hcodec()->clock_set(clk); + else + return -1; +} +EXPORT_SYMBOL(hcodec_clock_set); + +void hcodec_clock_enable(void) +{ + hcodec_clock_set(667); +} +EXPORT_SYMBOL(hcodec_clock_enable); + +void hcodec_clock_hi_enable(void) +{ + hcodec_clock_set(2); +} +EXPORT_SYMBOL(hcodec_clock_hi_enable); + +void hcodec_clock_on(void) +{ + IF_HAVE_RUN(p_vdec_hcodec(), clock_on); +} +EXPORT_SYMBOL(hcodec_clock_on); + +void hcodec_clock_off(void) +{ + IF_HAVE_RUN(p_vdec_hcodec(), clock_off); + clock_source_wxhxfps_saved[VDEC_HCODEC] = 0; +} +EXPORT_SYMBOL(hcodec_clock_off); + +int hevc_back_clock_init(void) +{ + if (p_vdec_hevc_back() && p_vdec_hevc_back()->clock_init) + return p_vdec_hevc_back()->clock_init(); + else + return 0; +} +EXPORT_SYMBOL(hevc_back_clock_init); + +int hevc_back_clock_set(int clk) +{ + pr_debug("%s-----%d\n", __func__, clk); + if (p_vdec_hevc_back() && p_vdec_hevc_back()->clock_set) + return p_vdec_hevc_back()->clock_set(clk); + else + return -1; +} +EXPORT_SYMBOL(hevc_back_clock_set); + +void hevc_back_clock_enable(void) +{ + hevc_back_clock_set(1); +} +EXPORT_SYMBOL(hevc_back_clock_enable); + +void hevc_back_clock_hi_enable(void) +{ + hevc_back_clock_set(2); +} +EXPORT_SYMBOL(hevc_back_clock_hi_enable); + +int hevc_clock_init(void) +{ + if (p_vdec_hevc() && p_vdec_hevc()->clock_init) + return p_vdec_hevc()->clock_init(); + else + return 0; +} +EXPORT_SYMBOL(hevc_clock_init); + +int hevc_clock_set(int clk) +{ + pr_debug("%s-----%d\n", __func__, clk); + if (p_vdec_hevc() && p_vdec_hevc()->clock_set) + return p_vdec_hevc()->clock_set(clk); + else + return -1; +} +EXPORT_SYMBOL(hevc_clock_set); + +void hevc_clock_enable(void) +{ + hevc_clock_set(1); +} +EXPORT_SYMBOL(hevc_clock_enable); + +void hevc_clock_hi_enable(void) +{ + hevc_clock_set(2); +} +EXPORT_SYMBOL(hevc_clock_hi_enable); + +void hevc_back_clock_on(void) +{ + IF_HAVE_RUN(p_vdec_hevc_back(), clock_on); +} +EXPORT_SYMBOL(hevc_back_clock_on); + +void hevc_back_clock_off(void) +{ + IF_HAVE_RUN(p_vdec_hevc_back(), clock_off); + clock_source_wxhxfps_saved[VDEC_HEVCB] = 0; +} +EXPORT_SYMBOL(hevc_back_clock_off); + +void hevc_clock_on(void) +{ + IF_HAVE_RUN(p_vdec_hevc(), clock_on); +} +EXPORT_SYMBOL(hevc_clock_on); + +void hevc_clock_off(void) +{ + IF_HAVE_RUN(p_vdec_hevc(), clock_off); + clock_source_wxhxfps_saved[VDEC_HEVC] = 0; +} +EXPORT_SYMBOL(hevc_clock_off); + +int vdec_source_get(enum vdec_type_e core) +{ + return clock_source_wxhxfps_saved[core]; +} +EXPORT_SYMBOL(vdec_source_get); + +int vdec_clk_get(enum vdec_type_e core) +{ + return get_current_vdec_chip()->clk_mgr[core]->clock_get(core); +} +EXPORT_SYMBOL(vdec_clk_get); + +int get_clk_with_source(int format, int w_x_h_fps) +{ + struct clk_set_setting *p_setting; + int i; + int clk = -2; + + p_setting = get_current_vdec_chip()->clk_setting_array; + if (!p_setting || format < 0 || format > VFORMAT_MAX) { + pr_info("error on get_clk_with_source ,%p,%d\n", + p_setting, format); + return -1; /*no setting found. */ + } + p_setting = &p_setting[format]; + for (i = 0; i < MAX_CLK_SET; i++) { + if (p_setting->set[i].wh_X_fps > w_x_h_fps) { + clk = p_setting->set[i].clk_Mhz; + break; + } + } + return clk; +} +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); + int ret_clk; + + if (clk < 0) { + pr_info("can't get valid clk for source ,%d,%d,%d\n", + width, height, fps); + if (format >= 1920 && width >= 1080 && fps >= 30) + clk = 2; /*default high clk */ + else + clk = 0; /*default clk. */ + } + if (width * height * fps == 0) + clk = 0; + /* + *clk == 0 + *is used for set default clk; + *if used supper clk. + *changed to default min clk. + */ + + if (format == VFORMAT_HEVC || format == VFORMAT_VP9 + || format == VFORMAT_AVS2 + || 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 && + !is_hevc_front_back_clk_combined()) { + ret_clk = hevc_back_clock_set(clk); + clock_source_wxhxfps_saved[VDEC_HEVCB] = width * height * fps; + } + } else if (format == VFORMAT_H264_ENC || format == VFORMAT_JPEG_ENC) { + ret_clk = hcodec_clock_set(clk); + clock_source_wxhxfps_saved[VDEC_HCODEC] = width * height * fps; + } else if (format == VFORMAT_H264_4K2K && + get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_M8) { + ret_clk = vdec2_clock_set(clk); + clock_source_wxhxfps_saved[VDEC_2] = width * height * fps; + ret_clk = vdec_clock_set(clk); + clock_source_wxhxfps_saved[VDEC_1] = width * height * fps; + } else { + ret_clk = vdec_clock_set(clk); + clock_source_wxhxfps_saved[VDEC_1] = width * height * fps; + } + return ret_clk; +} +EXPORT_SYMBOL(vdec_source_changed_for_clk_set); + +static int register_vdec_clk_mgr_per_cpu(int cputype, + enum vdec_type_e vdec_type, struct chip_vdec_clk_s *t_mgr) +{ + + struct chip_vdec_clk_s *mgr; + + if (cputype != get_cpu_major_id() || vdec_type >= VDEC_MAX) { + /* + *pr_info("ignore vdec clk mgr for vdec[%d] cpu=%d\n", + *vdec_type, cputype); + */ + return 0; /* ignore don't needed firmare. */ + } + mgr = kmalloc(sizeof(struct chip_vdec_clk_s), GFP_KERNEL); + if (!mgr) + return -ENOMEM; + *mgr = *t_mgr; + /* + *pr_info("register vdec clk mgr for vdec[%d]\n", vdec_type); + */ + if (mgr->clock_init) { + if (mgr->clock_init()) { + kfree(mgr); + return -ENOMEM; + } + } + get_current_vdec_chip()->clk_mgr[vdec_type] = mgr; + return 0; +} + +int register_vdec_clk_mgr(int cputype[], enum vdec_type_e vdec_type, + struct chip_vdec_clk_s *t_mgr) +{ + int i = 0; + + while (cputype[i] > 0) { + register_vdec_clk_mgr_per_cpu(cputype[i], vdec_type, t_mgr); + i++; + } + return 0; +} +EXPORT_SYMBOL(register_vdec_clk_mgr); + +int unregister_vdec_clk_mgr(enum vdec_type_e vdec_type) +{ + kfree(get_current_vdec_chip()->clk_mgr[vdec_type]); + + return 0; +} +EXPORT_SYMBOL(unregister_vdec_clk_mgr); + +static int register_vdec_clk_setting_per_cpu(int cputype, + struct clk_set_setting *setting, int size) +{ + + struct clk_set_setting *p_setting; + + if (cputype != get_cpu_major_id()) { + /* + *pr_info("ignore clk_set_setting for cpu=%d\n", + *cputype); + */ + return 0; /* ignore don't needed this setting . */ + } + p_setting = kmalloc(size, GFP_KERNEL); + if (!p_setting) + return -ENOMEM; + memcpy(p_setting, setting, size); + + pr_info("register clk_set_setting cpu[%d]\n", cputype); + + get_current_vdec_chip()->clk_setting_array = p_setting; + return 0; +} + +int register_vdec_clk_setting(int cputype[], + struct clk_set_setting *p_seting, int size) +{ + int i = 0; + + while (cputype[i] > 0) { + register_vdec_clk_setting_per_cpu(cputype[i], p_seting, size); + i++; + } + return 0; +} +EXPORT_SYMBOL(register_vdec_clk_setting); + +int unregister_vdec_clk_setting(void) +{ + kfree(get_current_vdec_chip()->clk_setting_array); + + return 0; +} +EXPORT_SYMBOL(unregister_vdec_clk_setting); +
diff --git a/drivers/common/media_clock/clk/clk.h b/drivers/common/media_clock/clk/clk.h new file mode 100644 index 0000000..bbc3bee --- /dev/null +++ b/drivers/common/media_clock/clk/clk.h
@@ -0,0 +1,177 @@ +/* + * drivers/amlogic/media/common/arch/clk/clk.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 VDEC_CHIP_CLK_HEADER +#define VDEC_CHIP_CLK_HEADER +#include <linux/types.h> +#include <linux/init.h> +#include <linux/module.h> +#include "clk_priv.h" +#include <linux/amlogic/media/clk/gp_pll.h> + +#ifndef INCLUDE_FROM_ARCH_CLK_MGR +int vdec_clock_init(void); +int vdec_clock_set(int clk); +int vdec2_clock_set(int clk); + +int hcodec_clock_set(int clk); +int hevc_clock_init(void); +int hevc_clock_set(int clk); + +void vdec_clock_on(void); +void vdec_clock_off(void); +void vdec2_clock_on(void); + +void vdec2_clock_off(void); +void hcodec_clock_on(void); +void hcodec_clock_off(void); +void hevc_clock_on(void); +void hevc_clock_off(void); + +int hevc_back_clock_init(void); +void hevc_back_clock_on(void); +void hevc_back_clock_off(void); +int hevc_back_clock_set(int clk); +void hevc_back_clock_enable(void); +void hevc_back_clock_hi_enable(void); + +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); + +void vdec_clock_enable(void); +void vdec_clock_hi_enable(void); +void hcodec_clock_enable(void); +void hcodec_clock_hi_enable(void); +void hevc_clock_enable(void); +void hevc_clock_hi_enable(void); +void vdec2_clock_enable(void); +void vdec2_clock_hi_enable(void); +void set_clock_gate(struct gate_switch_node *nodes, int num); + +#endif +int register_vdec_clk_mgr(int cputype[], + enum vdec_type_e vdec_type, struct chip_vdec_clk_s *t_mgr); + +int unregister_vdec_clk_mgr(enum vdec_type_e vdec_type); + +int register_vdec_clk_setting(int cputype[], + struct clk_set_setting *p_seting, int size); + +int unregister_vdec_clk_setting(void); + +#ifdef INCLUDE_FROM_ARCH_CLK_MGR +static struct chip_vdec_clk_s vdec_clk_mgr __initdata = { + .clock_init = vdec_clock_init, + .clock_set = vdec_clock_set, + .clock_on = vdec_clock_on, + .clock_off = vdec_clock_off, + .clock_get = vdec_clock_get, +}; + +#ifdef VDEC_HAS_VDEC2 +static struct chip_vdec_clk_s vdec2_clk_mgr __initdata = { + .clock_set = vdec2_clock_set, + .clock_on = vdec2_clock_on, + .clock_off = vdec2_clock_off, + .clock_get = vdec_clock_get, +}; +#endif + +#ifdef VDEC_HAS_HEVC +static struct chip_vdec_clk_s vdec_hevc_clk_mgr __initdata = { + .clock_init = hevc_clock_init, + .clock_set = hevc_clock_set, + .clock_on = hevc_clock_on, + .clock_off = hevc_clock_off, + .clock_get = vdec_clock_get, +}; +static struct chip_vdec_clk_s vdec_hevc_back_clk_mgr __initdata = { + .clock_init = hevc_back_clock_init, + .clock_set = hevc_back_clock_set, + .clock_on = hevc_back_clock_on, + .clock_off = hevc_back_clock_off, + .clock_get = vdec_clock_get, +}; +#endif + +#ifdef VDEC_HAS_VDEC_HCODEC +static struct chip_vdec_clk_s vdec_hcodec_clk_mgr __initdata = { + .clock_set = hcodec_clock_set, + .clock_on = hcodec_clock_on, + .clock_off = hcodec_clock_off, + .clock_get = vdec_clock_get, +}; +#endif + +static int __init vdec_init_clk(void) +{ + int cpus[] = CLK_FOR_CPU; + + register_vdec_clk_mgr(cpus, VDEC_1, &vdec_clk_mgr); +#ifdef VDEC_HAS_VDEC2 + register_vdec_clk_mgr(cpus, VDEC_2, &vdec2_clk_mgr); +#endif +#ifdef VDEC_HAS_HEVC + register_vdec_clk_mgr(cpus, VDEC_HEVC, &vdec_hevc_clk_mgr); + 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 + register_vdec_clk_mgr(cpus, VDEC_HCODEC, &vdec_hcodec_clk_mgr); +#endif + +#ifdef VDEC_HAS_CLK_SETTINGS + register_vdec_clk_setting(cpus, + clks_for_formats, sizeof(clks_for_formats)); +#endif + return 0; +} + +static void __exit vdec_clk_exit(void) +{ + unregister_vdec_clk_mgr(VDEC_1); +#ifdef VDEC_HAS_VDEC2 + unregister_vdec_clk_mgr(VDEC_2); +#endif +#ifdef VDEC_HAS_HEVC + unregister_vdec_clk_mgr(VDEC_HEVC); +#endif +#ifdef VDEC_HAS_VDEC_HCODEC + unregister_vdec_clk_mgr(VDEC_HCODEC); +#endif +#ifdef VDEC_HAS_CLK_SETTINGS + unregister_vdec_clk_setting(); +#endif + pr_info("media clock exit.\n"); +} + +#define ARCH_VDEC_CLK_INIT()\ + module_init(vdec_init_clk) + +#define ARCH_VDEC_CLK_EXIT()\ + module_exit(vdec_clk_exit) + +MODULE_DESCRIPTION("AMLOGIC clk Driver"); +MODULE_LICENSE("GPL"); + +#endif +#endif
diff --git a/drivers/common/media_clock/clk/clk_priv.h b/drivers/common/media_clock/clk/clk_priv.h new file mode 100644 index 0000000..60b7be0 --- /dev/null +++ b/drivers/common/media_clock/clk/clk_priv.h
@@ -0,0 +1,38 @@ +/* + * drivers/amlogic/media/common/arch/clk/clk_priv.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 AMPORTS_CLK_PRIV_HEADER +#define AMPORTS_CLK_PRIV_HEADER + +struct clk_set { + u32 wh_X_fps; /* [x*y*fps */ + u32 clk_Mhz; /*min MHZ */ +}; +#define MAX_CLK_SET 6 +struct clk_set_setting { + struct clk_set set[MAX_CLK_SET]; +}; + +struct chip_vdec_clk_s { + int (*clock_get)(enum vdec_type_e core); + int (*clock_init)(void); + int (*clock_set)(int clk); + void (*clock_on)(void); + void (*clock_off)(void); + void (*clock_prepare_switch)(void); +}; +#endif
diff --git a/drivers/common/media_clock/clk/clkg12.c b/drivers/common/media_clock/clk/clkg12.c new file mode 100644 index 0000000..c49d150 --- /dev/null +++ b/drivers/common/media_clock/clk/clkg12.c
@@ -0,0 +1,1071 @@ +/* + * drivers/amlogic/media/common/arch/clk/clkgx.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. + * + */ +#define DEBUG +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/amlogic/media/clk/gp_pll.h> +#include <linux/amlogic/media/utils/vdec_reg.h> +#include <linux/amlogic/media/utils/amports_config.h> +#include "../../../frame_provider/decoder/utils/vdec.h" +#include <linux/amlogic/media/registers/register.h> +#include "clk_priv.h" +#include <linux/amlogic/media/utils/log.h> + +#include <linux/amlogic/media/registers/register_ops.h> +#include "../switch/amports_gate.h" +#include "../../chips/decoder_cpu_ver_info.h" + +#define MHz (1000000) +#define debug_print pr_info +#define TL1_HEVC_MAX_CLK (800) + +//#define NO_CLKTREE + +/* set gp0 648M vdec use gp0 clk*/ +#define VDEC1_648M() \ + WRITE_HHI_REG_BITS(HHI_VDEC_CLK_CNTL, (6 << 9) | (0), 0, 16) + +#define HEVC_648M() \ + WRITE_HHI_REG_BITS(HHI_VDEC2_CLK_CNTL, (6 << 9) | (0), 16, 16) + +/*set gp0 1296M vdec use gp0 clk div2*/ +#define VDEC1_648M_DIV() \ + WRITE_HHI_REG_BITS(HHI_VDEC_CLK_CNTL, (6 << 9) | (1), 0, 16) + +#define HEVC_648M_DIV() \ + WRITE_HHI_REG_BITS(HHI_VDEC2_CLK_CNTL, (6 << 9) | (1), 16, 16) + +#define VDEC1_WITH_GP_PLL() \ + ((READ_HHI_REG(HHI_VDEC_CLK_CNTL) & 0xe00) == 0xc00) +#define HEVC_WITH_GP_PLL() \ + ((READ_HHI_REG(HHI_VDEC2_CLK_CNTL) & 0xe000000) == 0xc000000) + +#define VDEC1_CLOCK_ON() \ + do { if (is_meson_m8_cpu()) { \ + WRITE_HHI_REG_BITS(HHI_VDEC_CLK_CNTL, 1, 8, 1); \ + WRITE_VREG_BITS(DOS_GCLK_EN0, 0x3ff, 0, 10); \ + } else { \ + WRITE_HHI_REG_BITS(HHI_VDEC_CLK_CNTL, 1, 8, 1); \ + WRITE_HHI_REG_BITS(HHI_VDEC3_CLK_CNTL, 0, 15, 1); \ + WRITE_HHI_REG_BITS(HHI_VDEC3_CLK_CNTL, 0, 8, 1); \ + WRITE_VREG_BITS(DOS_GCLK_EN0, 0x3ff, 0, 10); \ + } \ + } while (0) + +#define VDEC2_CLOCK_ON() do {\ + WRITE_HHI_REG_BITS(HHI_VDEC2_CLK_CNTL, 1, 8, 1); \ + WRITE_VREG(DOS_GCLK_EN1, 0x3ff);\ + } while (0) + +#define HCODEC_CLOCK_ON() do {\ + WRITE_HHI_REG_BITS(HHI_VDEC_CLK_CNTL, 1, 24, 1); \ + WRITE_VREG_BITS(DOS_GCLK_EN0, 0x7fff, 12, 15);\ + } while (0) +#define HEVC_CLOCK_ON() do {\ + WRITE_HHI_REG_BITS(HHI_VDEC2_CLK_CNTL, 1, 24, 1); \ + WRITE_HHI_REG_BITS(HHI_VDEC2_CLK_CNTL, 1, 8, 1); \ + WRITE_HHI_REG_BITS(HHI_VDEC4_CLK_CNTL, 0, 31, 1); \ + WRITE_HHI_REG_BITS(HHI_VDEC4_CLK_CNTL, 0, 15, 1); \ + WRITE_HHI_REG_BITS(HHI_VDEC4_CLK_CNTL, 0, 24, 1); \ + WRITE_VREG(DOS_GCLK_EN3, 0xffffffff);\ + } while (0) +#define VDEC1_SAFE_CLOCK() do {\ + WRITE_HHI_REG_BITS(HHI_VDEC3_CLK_CNTL, \ + READ_HHI_REG(HHI_VDEC_CLK_CNTL) & 0x7f, 0, 7); \ + WRITE_HHI_REG_BITS(HHI_VDEC3_CLK_CNTL, 1, 8, 1); \ + WRITE_HHI_REG_BITS(HHI_VDEC3_CLK_CNTL, 1, 15, 1);\ + } while (0) + +#define VDEC1_CLOCK_OFF() \ + WRITE_HHI_REG_BITS(HHI_VDEC_CLK_CNTL, 0, 8, 1) +#define VDEC2_CLOCK_OFF() \ + WRITE_HHI_REG_BITS(HHI_VDEC2_CLK_CNTL, 0, 8, 1) +#define HCODEC_CLOCK_OFF() \ + WRITE_HHI_REG_BITS(HHI_VDEC_CLK_CNTL, 0, 24, 1) +#define HEVC_SAFE_CLOCK() do { \ + WRITE_HHI_REG_BITS(HHI_VDEC4_CLK_CNTL, \ + (READ_HHI_REG(HHI_VDEC2_CLK_CNTL) >> 16) & 0x7f, 16, 7);\ + WRITE_HHI_REG_BITS(HHI_VDEC4_CLK_CNTL, \ + (READ_HHI_REG(HHI_VDEC2_CLK_CNTL) >> 25) & 0x7f, 25, 7);\ + WRITE_HHI_REG_BITS(HHI_VDEC4_CLK_CNTL, 1, 24, 1); \ + WRITE_HHI_REG_BITS(HHI_VDEC4_CLK_CNTL, 1, 31, 1);\ + WRITE_HHI_REG_BITS(HHI_VDEC4_CLK_CNTL, 1, 15, 1);\ + } while (0) + +#define HEVC_CLOCK_OFF() do {\ + WRITE_HHI_REG_BITS(HHI_VDEC2_CLK_CNTL, 0, 24, 1);\ + WRITE_HHI_REG_BITS(HHI_VDEC2_CLK_CNTL, 0, 8, 1);\ +}while(0) + +static int clock_real_clk[VDEC_MAX + 1]; + +static unsigned int set_frq_enable, vdec_frq, hevc_frq, hevcb_frq; + +#ifdef NO_CLKTREE +static struct gp_pll_user_handle_s *gp_pll_user_vdec, *gp_pll_user_hevc; +static bool is_gp0_div2 = true; + +static int gp_pll_user_cb_vdec(struct gp_pll_user_handle_s *user, + int event) +{ + 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) + clk_set_rate(clk, 1296000000UL); + else + clk_set_rate(clk, 648000000UL); + VDEC1_SAFE_CLOCK(); + VDEC1_CLOCK_OFF(); + if (is_gp0_div2) + VDEC1_648M_DIV(); + else + VDEC1_648M(); + + VDEC1_CLOCK_ON(); + debug_print("gp_pll_user_cb_vdec call set\n"); + } + } + return 0; +} + +static int gp_pll_user_cb_hevc(struct gp_pll_user_handle_s *user, + int event) +{ + debug_print("gp_pll_user_cb_hevc callback\n"); + if (event == GP_PLL_USER_EVENT_GRANT) { + struct clk *clk = clk_get(NULL, "gp0_pll"); + if (!IS_ERR(clk)) { + if (is_gp0_div2) + clk_set_rate(clk, 1296000000UL); + else + clk_set_rate(clk, 648000000UL); +// HEVC_SAFE_CLOCK(); + HEVC_CLOCK_OFF(); + if (is_gp0_div2) + HEVC_648M_DIV(); + else + HEVC_648M(); + HEVC_CLOCK_ON(); + debug_print("gp_pll_user_cb_hevc callback2\n"); + } + } + + return 0; +} + + +#endif + +struct clk_mux_s { + struct gate_switch_node *vdec_mux_node; + struct gate_switch_node *hcodec_mux_node; + struct gate_switch_node *hevc_mux_node; + struct gate_switch_node *hevc_back_mux_node; +}; + +struct clk_mux_s gclk; + +void vdec1_set_clk(int source, int div) +{ + pr_debug("vdec1_set_clk %d, %d\n", source, div); + WRITE_HHI_REG_BITS(HHI_VDEC_CLK_CNTL, (source << 9) | (div - 1), 0, 16); +} +EXPORT_SYMBOL(vdec1_set_clk); + +void hcodec_set_clk(int source, int div) +{ + WRITE_HHI_REG_BITS(HHI_VDEC_CLK_CNTL, + (source << 9) | (div - 1), 16, 16); +} +EXPORT_SYMBOL(hcodec_set_clk); + +void vdec2_set_clk(int source, int div) +{ + WRITE_HHI_REG_BITS(HHI_VDEC2_CLK_CNTL, + (source << 9) | (div - 1), 0, 16); +} +EXPORT_SYMBOL(vdec2_set_clk); + +//extern uint force_hevc_clock_cntl; +uint force_hevc_clock_cntl = 0; +void hevc_set_clk(int source, int div) +{ + if (force_hevc_clock_cntl) { + pr_info("%s, write force clock cntl %x\n", __func__, force_hevc_clock_cntl); + WRITE_HHI_REG(HHI_VDEC2_CLK_CNTL, force_hevc_clock_cntl); + } else { + pr_debug("hevc_set_clk %d, %d\n", source, div); + WRITE_HHI_REG_BITS(HHI_VDEC2_CLK_CNTL, + (source << 9) | (div - 1), 16, 16); + WRITE_HHI_REG_BITS(HHI_VDEC2_CLK_CNTL, (source << 9) | (div - 1), 0, 16); + } +} +EXPORT_SYMBOL(hevc_set_clk); + +void vdec_get_clk_source(int clk, int *source, int *div, int *rclk) +{ +#define source_div4 (0) +#define source_div3 (1) +#define source_div5 (2) +#define source_div7 (3) + if (clk > 500) { + *source = source_div3; + *div = 1; + *rclk = 667; + } else if (clk >= 500) { + *source = source_div4; + *div = 1; + *rclk = 500; + } else if (clk >= 400) { + *source = source_div5; + *div = 1; + *rclk = 400; + } else if (clk >= 333) { + *source = source_div3; + *div = 2; + *rclk = 333; + } else if (clk >= 200) { + *source = source_div5; + *div = 2; + *rclk = 200; + } else if (clk >= 166) { + *source = source_div4; + *div = 3; + *rclk = 166; + } else if (clk >= 133) { + *source = source_div5; + *div = 3; + *rclk = 133; + } else if (clk >= 100) { + *source = source_div5; + *div = 4; + *rclk = 100; + } else if (clk >= 50) { + *source = source_div5; + *div = 8; + *rclk = 50; + } else { + *source = source_div5; + *div = 20; + *rclk = 10; + } +} +EXPORT_SYMBOL(vdec_get_clk_source); + + +/* + *enum vformat_e { + * VFORMAT_MPEG12 = 0, + * VFORMAT_MPEG4, + * VFORMAT_H264, + * VFORMAT_MJPEG, + * VFORMAT_REAL, + * VFORMAT_JPEG, + * VFORMAT_VC1, + * VFORMAT_AVS, + * VFORMAT_YUV, + * VFORMAT_H264MVC, + * VFORMAT_H264_4K2K, + * VFORMAT_HEVC, + * VFORMAT_H264_ENC, + * VFORMAT_JPEG_ENC, + * VFORMAT_VP9, + * VFORMAT_MAX + *}; + *sample: + *{{1280*720*30, 100}, {1920*1080*30, 166}, {1920*1080*60, 333}, + * {4096*2048*30, 600}, {4096*2048*60, 600}, {INT_MAX, 600},} + *mean: + *width * height * fps + *<720p30fps clk=100MHZ + *>=720p30fps & < 1080p30fps clk=166MHZ + *>=1080p 30fps & < 1080p60fps clk=333MHZ + */ +static struct clk_set_setting clks_for_formats[] = { + { /*[VFORMAT_MPEG12] */ + {{1280 * 720 * 30, 100}, {1920 * 1080 * 30, 166}, + {1920 * 1080 * 60, 333}, + {4096 * 2048 * 30, 600}, {4096 * 2048 * 60, + 600}, {INT_MAX, 600}, + } + }, + { /*[VFORMAT_MPEG4] */ + {{1280 * 720 * 30, 100}, {1920 * 1080 * 30, 166}, + {1920 * 1080 * 60, 333}, + {4096 * 2048 * 30, 600}, {4096 * 2048 * 60, + 600}, {INT_MAX, 600}, + } + }, + { /*[VFORMAT_H264] */ + {{1280 * 720 * 30, 100}, {1920 * 1080 * 21, 166}, + {1920 * 1080 * 30, 333}, + {1920 * 1080 * 60, 600}, {4096 * 2048 * 60, + 600}, {INT_MAX, 600}, + } + }, + { /*[VFORMAT_MJPEG] */ + {{1280 * 720 * 30, 200}, {1920 * 1080 * 30, 200}, + {1920 * 1080 * 60, 333}, + {4096 * 2048 * 30, 600}, {4096 * 2048 * 60, + 600}, {INT_MAX, 600}, + } + }, + { /*[VFORMAT_REAL] */ + {{1280 * 720 * 20, 200}, {1920 * 1080 * 30, 500}, + {1920 * 1080 * 60, 500}, + {4096 * 2048 * 30, 600}, {4096 * 2048 * 60, + 600}, {INT_MAX, 600}, + } + }, + { /*[VFORMAT_JPEG] */ + {{1280 * 720 * 30, 100}, {1920 * 1080 * 30, 166}, + {1920 * 1080 * 60, 333}, + {4096 * 2048 * 30, 600}, {4096 * 2048 * 60, + 600}, {INT_MAX, 600}, + } + }, + { /*[VFORMAT_VC1] */ + {{1280 * 720 * 30, 100}, {1920 * 1080 * 30, 166}, + {1920 * 1080 * 60, 333}, + {4096 * 2048 * 30, 600}, {4096 * 2048 * 60, + 600}, {INT_MAX, 600}, + } + }, + { /*[VFORMAT_AVS] */ + {{1280 * 720 * 30, 100}, {1920 * 1080 * 30, 166}, + {1920 * 1080 * 60, 333}, + {4096 * 2048 * 30, 600}, {4096 * 2048 * 60, + 600}, {INT_MAX, 600}, + } + }, + { /*[VFORMAT_YUV] */ + {{1280 * 720 * 30, 100}, {INT_MAX, 100}, + {0, 0}, {0, 0}, {0, 0}, {0, 0}, + } + }, + { /*VFORMAT_H264MVC */ + {{1280 * 720 * 30, 333}, {1920 * 1080 * 30, 333}, + {4096 * 2048 * 60, 600}, + {INT_MAX, 630}, {0, 0}, {0, 0}, + } + }, + { /*VFORMAT_H264_4K2K */ + {{1280 * 720 * 30, 600}, {4096 * 2048 * 60, 630}, + {INT_MAX, 630}, + {0, 0}, {0, 0}, {0, 0}, + } + }, + { /*VFORMAT_HEVC */ + {{1280 * 720 * 30, 100}, {1920 * 1080 * 60, 600}, + {4096 * 2048 * 25, 630}, + {4096 * 2048 * 30, 630}, {4096 * 2048 * 60, + 630}, {INT_MAX, 630}, + } + }, + { /*VFORMAT_H264_ENC */ + {{1280 * 720 * 30, 0}, {INT_MAX, 0}, + {0, 0}, {0, 0}, {0, 0}, {0, 0}, + } + }, + { /*VFORMAT_JPEG_ENC */ + {{1280 * 720 * 30, 0}, {INT_MAX, 0}, + {0, 0}, {0, 0}, {0, 0}, {0, 0}, + } + }, + { /*VFORMAT_VP9 */ + {{1280 * 720 * 30, 100}, {1920 * 1080 * 30, 100}, + {1920 * 1080 * 60, 166}, + {4096 * 2048 * 30, 333}, {4096 * 2048 * 60, + 630}, {INT_MAX, 630}, + } + }, + {/*VFORMAT_AVS2*/ + {{1280*720*30, 100}, {1920*1080*30, 100}, + {1920*1080*60, 166}, {4096*2048*30, 333}, + {4096*2048*60, 630}, {INT_MAX, 630},} + }, + {/*VFORMAT_AV1*/ + {{1280*720*30, 100}, {1920*1080*30, 100}, + {1920*1080*60, 166}, {4096*2048*30, 333}, + {4096*2048*60, 630}, {INT_MAX, 630},} + }, + +}; + +void set_clock_gate(struct gate_switch_node *nodes, int num) +{ + struct gate_switch_node *node = NULL; + char *hevc_mux_str = NULL; + + 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"; + + do { + node = &nodes[num - 1]; + if (IS_ERR_OR_NULL(node) || (IS_ERR_OR_NULL(node->clk))) + pr_info("get mux clk err.\n"); + + if (!strcmp(node->name, "clk_vdec_mux")) + gclk.vdec_mux_node = node; + else if (!strcmp(node->name, "clk_hcodec_mux")) + gclk.hcodec_mux_node = node; + else if (!strcmp(node->name, hevc_mux_str)) + gclk.hevc_mux_node = node; + else if (!strcmp(node->name, "clk_hevcb_mux")) + gclk.hevc_back_mux_node = node; + } while(--num); +} +EXPORT_SYMBOL(set_clock_gate); +#ifdef NO_CLKTREE +int vdec_set_clk(int dec, int source, int div) +{ + + if (dec == VDEC_1) + vdec1_set_clk(source, div); + else if (dec == VDEC_2) + vdec2_set_clk(source, div); + else if (dec == VDEC_HEVC) + hevc_set_clk(source, div); + else if (dec == VDEC_HCODEC) + hcodec_set_clk(source, div); + return 0; +} + +#else +static int vdec_set_clk(int dec, int rate) +{ + struct clk *clk = NULL; + + switch (dec) { + case VDEC_1: + clk = gclk.vdec_mux_node->clk; + WRITE_VREG_BITS(DOS_GCLK_EN0, 0x3ff, 0, 10); + break; + + case VDEC_HCODEC: + clk = gclk.hcodec_mux_node->clk; + WRITE_VREG_BITS(DOS_GCLK_EN0, 0x7fff, 12, 15); + break; + + case VDEC_2: + clk = gclk.vdec_mux_node->clk; + WRITE_VREG(DOS_GCLK_EN1, 0x3ff); + break; + + case VDEC_HEVC: + clk = gclk.hevc_mux_node->clk; + WRITE_VREG(DOS_GCLK_EN3, 0xffffffff); + break; + + case VDEC_HEVCB: + clk = gclk.hevc_back_mux_node->clk; + WRITE_VREG(DOS_GCLK_EN3, 0xffffffff); + break; + + case VDEC_MAX: + break; + + default: + pr_info("invaild vdec type.\n"); + } + + if (IS_ERR_OR_NULL(clk)) { + pr_info("the mux clk err.\n"); + return -1; + } + + clk_set_rate(clk, rate); + + return 0; +} + +static int vdec_clock_init(void) +{ + return 0; +} + +#endif +#ifdef NO_CLKTREE +static int vdec_clock_init(void) +{ + gp_pll_user_vdec = gp_pll_user_register("vdec", 0, + gp_pll_user_cb_vdec); + 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() >= AM_MESON_CPU_MAJOR_ID_GXL) { + pr_info("used fix clk for vdec clk source!\n"); + //update_vdec_clk_config_settings(1); + } + return (gp_pll_user_vdec) ? 0 : -ENOMEM; +} + + + +static void update_clk_with_clk_configs( + int clk, int *source, int *div, int *rclk) +{ + unsigned int config = 0;//get_vdec_clk_config_settings(); + + if (!config) + return; + if (config >= 10) { + int wantclk; + wantclk = config; + vdec_get_clk_source(wantclk, source, div, rclk); + } + return; +} +#define NO_GP0_PLL 0//(get_vdec_clk_config_settings() == 1) +#define ALWAYS_GP0_PLL 0//(get_vdec_clk_config_settings() == 2) + +#define NO_GP0_PLL 0//(get_vdec_clk_config_settings() == 1) +#define ALWAYS_GP0_PLL 0//(get_vdec_clk_config_settings() == 2) + +static int vdec_clock_set(int clk) +{ + int use_gpll = 0; + int source, div, rclk; + int clk_seted = 0; + int gp_pll_wait = 0; + if (clk == 1) + clk = 200; + else if (clk == 2) { + if (clock_real_clk[VDEC_1] != 648) + clk = 500; + else + clk = 648; + } else if (clk == 0) { + /*used for release gp pull. + if used, release it. + if not used gp pll + do nothing. + */ + if (clock_real_clk[VDEC_1] == 667 || + (clock_real_clk[VDEC_1] == 648) || + clock_real_clk[VDEC_1] <= 0) + clk = 200; + else + clk = clock_real_clk[VDEC_1]; + } + vdec_get_clk_source(clk, &source, &div, &rclk); + update_clk_with_clk_configs(clk, &source, &div, &rclk); + + if (clock_real_clk[VDEC_1] == rclk) + return rclk; + if (NO_GP0_PLL) { + use_gpll = 0; + clk_seted = 0; + } else if ((rclk > 500 && clk != 667) || ALWAYS_GP0_PLL) { + if (clock_real_clk[VDEC_1] == 648) + return 648; + use_gpll = 1; + gp_pll_request(gp_pll_user_vdec); + while (!VDEC1_WITH_GP_PLL() && gp_pll_wait++ < 1000000) + udelay(1); + if (VDEC1_WITH_GP_PLL()) { + clk_seted = 1; + rclk = 648; + } else { + use_gpll = 0; + rclk = 667; + /*gp_pull request failed,used default 500Mhz*/ + pr_info("get gp pll failed used fix pull\n"); + } + } + if (!clk_seted) {/*if 648 not set,*/ + VDEC1_SAFE_CLOCK(); + VDEC1_CLOCK_OFF(); + vdec_set_clk(VDEC_1, source, div); + VDEC1_CLOCK_ON(); + } + + if (!use_gpll) + gp_pll_release(gp_pll_user_vdec); + clock_real_clk[VDEC_1] = rclk; + debug_print("vdec_clock_set 2 to %d\n", rclk); + return rclk; +} +static int hevc_clock_init(void) +{ + gp_pll_user_hevc = gp_pll_user_register("hevc", 0, + gp_pll_user_cb_hevc); + + return (gp_pll_user_hevc) ? 0 : -ENOMEM; +} +static int hevc_back_clock_init(void) +{ + return 0; +} + +static int hevc_back_clock_set(int clk) +{ + return 0; +} + +static int hevc_clock_set(int clk) +{ + int use_gpll = 0; + int source, div, rclk; + int gp_pll_wait = 0; + int clk_seted = 0; + + debug_print("hevc_clock_set 1 to clk %d\n", clk); + if (clk == 1) + clk = 200; + else if (clk == 2) { + if (clock_real_clk[VDEC_HEVC] != 648) + clk = 500; + else + clk = 648; + } else if (clk == 0) { + /*used for release gp pull. + if used, release it. + if not used gp pll + do nothing. + */ + if ((clock_real_clk[VDEC_HEVC] == 667) || + (clock_real_clk[VDEC_HEVC] == 648) || + (clock_real_clk[VDEC_HEVC] <= 0)) + clk = 200; + else + clk = clock_real_clk[VDEC_HEVC]; + } + vdec_get_clk_source(clk, &source, &div, &rclk); + update_clk_with_clk_configs(clk, &source, &div, &rclk); + + if (rclk == clock_real_clk[VDEC_HEVC]) + return rclk;/*clk not changed,*/ + if (NO_GP0_PLL) { + use_gpll = 0; + clk_seted = 0; + } else if ((rclk > 500 && clk != 667) || ALWAYS_GP0_PLL) { + if (clock_real_clk[VDEC_HEVC] == 648) + return 648; + use_gpll = 1; + gp_pll_request(gp_pll_user_hevc); + while (!HEVC_WITH_GP_PLL() && gp_pll_wait++ < 1000000) + udelay(1); + if (HEVC_WITH_GP_PLL()) { + clk_seted = 1; + rclk = 648; + } else { + rclk = 667; + /*gp_pull request failed,used default 500Mhz*/ + pr_info("get gp pll failed used fix pull\n"); + } + } + if (!clk_seted) {/*if 648 not set,*/ +// HEVC_SAFE_CLOCK(); + HEVC_CLOCK_OFF(); + vdec_set_clk(VDEC_HEVC, source, div); + HEVC_CLOCK_ON(); + } + if (!use_gpll) + gp_pll_release(gp_pll_user_hevc); + clock_real_clk[VDEC_HEVC] = rclk; + /*debug_print("hevc_clock_set 2 to rclk=%d, configs=%d\n", + rclk, + get_vdec_clk_config_settings());*/ //DEBUG_TMP + return rclk; +} + +static int hcodec_clock_set(int clk) +{ + int source, div, rclk; + HCODEC_CLOCK_OFF(); + vdec_get_clk_source(200, &source, &div, &rclk); + vdec_set_clk(VDEC_HCODEC, source, div); + HCODEC_CLOCK_ON(); + clock_real_clk[VDEC_HCODEC] = rclk; + return rclk; +} + + +#else +static int vdec_clock_set(int clk) +{ + if (clk == 1) + clk = 200; + else if (clk == 2) { + if (clock_real_clk[VDEC_1] != 648) + clk = 500; + else + clk = 648; + } else if (clk == 0) { + if (clock_real_clk[VDEC_1] == 667 || + (clock_real_clk[VDEC_1] == 648) || + clock_real_clk[VDEC_1] <= 0) + clk = 200; + else + clk = clock_real_clk[VDEC_1]; + } + + if ((clk > 500 && clk != 667)) { + if (clock_real_clk[VDEC_1] == 648) + return 648; + clk = 667; + } + + 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_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; + } + + vdec_set_clk(VDEC_1, clk * MHz); + + clock_real_clk[VDEC_1] = clk; + + pr_debug("vdec mux clock is %lu Hz\n", + clk_get_rate(gclk.vdec_mux_node->clk)); + + return clk; +} + +static int hevc_clock_init(void) +{ + return 0; +} + +static int hevc_back_clock_init(void) +{ + return 0; +} + +static int hevc_back_clock_set(int clk) +{ + if (clk == 1) + clk = 200; + else if (clk == 2) { + if (clock_real_clk[VDEC_HEVCB] != 648) + clk = 500; + else + clk = 648; + } else if (clk == 0) { + if (clock_real_clk[VDEC_HEVCB] == 667 || + (clock_real_clk[VDEC_HEVCB] == 648) || + clock_real_clk[VDEC_HEVCB] <= 0) + clk = 200; + else + clk = clock_real_clk[VDEC_HEVCB]; + } + + if ((clk > 500 && clk != 667)) { + if (clock_real_clk[VDEC_HEVCB] == 648) + return 648; + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) + clk = TL1_HEVC_MAX_CLK; + else + clk = 667; + } + + if (set_frq_enable && hevcb_frq) { + pr_info("Set the hevcb frq is %u MHz\n", hevcb_frq); + clk = hevcb_frq; + } + + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_TXLX) && + (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SC2)) { + if ((READ_EFUSE_REG(EFUSE_LIC1) >> 28 & 0x1) && clk > 333) { + pr_info("The hevcb clock limit to 333MHz.\n"); + clk = 333; + } + } + + vdec_set_clk(VDEC_HEVCB, clk * MHz); + + clock_real_clk[VDEC_HEVCB] = clk; + pr_debug("hevc back mux clock is %lu Hz\n", + clk_get_rate(gclk.hevc_back_mux_node->clk)); + + return clk; +} + +static int hevc_clock_set(int clk) +{ + if (clk == 1) + clk = 200; + else if (clk == 2) { + if (clock_real_clk[VDEC_HEVC] != 648) + clk = 500; + else + clk = 648; + } else if (clk == 0) { + if (clock_real_clk[VDEC_HEVC] == 667 || + (clock_real_clk[VDEC_HEVC] == 648) || + clock_real_clk[VDEC_HEVC] <= 0) + clk = 200; + else + clk = clock_real_clk[VDEC_HEVC]; + } + + 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) && + (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) { + pr_info("Set the hevc frq is %u MHz\n", hevc_frq); + clk = hevc_frq; + } + + vdec_set_clk(VDEC_HEVC, clk * MHz); + + clock_real_clk[VDEC_HEVC] = clk; + + pr_debug("hevc mux clock is %lu Hz\n", + clk_get_rate(gclk.hevc_mux_node->clk)); + + return clk; +} + +static int hcodec_clock_set(int clk) +{ + if (clk == 1) + clk = 200; + else if (clk == 2) { + if (clock_real_clk[VDEC_HCODEC] != 648) + clk = 500; + else + clk = 648; + } else if (clk == 0) { + if (clock_real_clk[VDEC_HCODEC] == 667 || + (clock_real_clk[VDEC_HCODEC] == 648) || + clock_real_clk[VDEC_HCODEC] <= 0) + clk = 200; + else + clk = clock_real_clk[VDEC_HCODEC]; + } + + if ((clk > 500 && clk != 667)) { + if (clock_real_clk[VDEC_HCODEC] == 648) + return 648; + clk = 667; + } + + vdec_set_clk(VDEC_HCODEC, clk * MHz); + + clock_real_clk[VDEC_HCODEC] = clk; + + pr_debug("hcodec mux clock is %lu Hz\n", + clk_get_rate(gclk.hcodec_mux_node->clk)); + + return clk; +} +#endif + +static void vdec_clock_on(void) +{ + mutex_lock(&gclk.vdec_mux_node->mutex); + if (!gclk.vdec_mux_node->ref_count) + clk_prepare_enable(gclk.vdec_mux_node->clk); + + gclk.vdec_mux_node->ref_count++; + mutex_unlock(&gclk.vdec_mux_node->mutex); + + pr_debug("the %-15s clock on, ref cnt: %d\n", + gclk.vdec_mux_node->name, + gclk.vdec_mux_node->ref_count); +} + +static void vdec_clock_off(void) +{ + mutex_lock(&gclk.vdec_mux_node->mutex); + gclk.vdec_mux_node->ref_count--; + if (!gclk.vdec_mux_node->ref_count) + clk_disable_unprepare(gclk.vdec_mux_node->clk); + + clock_real_clk[VDEC_1] = 0; + mutex_unlock(&gclk.vdec_mux_node->mutex); + + pr_debug("the %-15s clock off, ref cnt: %d\n", + gclk.vdec_mux_node->name, + gclk.vdec_mux_node->ref_count); +} + +static void hcodec_clock_on(void) +{ + mutex_lock(&gclk.hcodec_mux_node->mutex); + if (!gclk.hcodec_mux_node->ref_count) + clk_prepare_enable(gclk.hcodec_mux_node->clk); + + gclk.hcodec_mux_node->ref_count++; + mutex_unlock(&gclk.hcodec_mux_node->mutex); + + pr_debug("the %-15s clock on, ref cnt: %d\n", + gclk.hcodec_mux_node->name, + gclk.hcodec_mux_node->ref_count); +} + +static void hcodec_clock_off(void) +{ + mutex_lock(&gclk.hcodec_mux_node->mutex); + gclk.hcodec_mux_node->ref_count--; + if (!gclk.hcodec_mux_node->ref_count) + clk_disable_unprepare(gclk.hcodec_mux_node->clk); + + mutex_unlock(&gclk.hcodec_mux_node->mutex); + + pr_debug("the %-15s clock off, ref cnt: %d\n", + gclk.hcodec_mux_node->name, + gclk.hcodec_mux_node->ref_count); +} + +static void hevc_clock_on(void) +{ + mutex_lock(&gclk.hevc_mux_node->mutex); + if (!gclk.hevc_mux_node->ref_count) + clk_prepare_enable(gclk.hevc_mux_node->clk); + + gclk.hevc_mux_node->ref_count++; + WRITE_VREG(DOS_GCLK_EN3, 0xffffffff); + mutex_unlock(&gclk.hevc_mux_node->mutex); + + pr_debug("the %-15s clock on, ref cnt: %d\n", + gclk.hevc_mux_node->name, + gclk.hevc_mux_node->ref_count); +} + +static void hevc_clock_off(void) +{ + mutex_lock(&gclk.hevc_mux_node->mutex); + gclk.hevc_mux_node->ref_count--; + if (!gclk.hevc_mux_node->ref_count) + clk_disable_unprepare(gclk.hevc_mux_node->clk); + + clock_real_clk[VDEC_HEVC] = 0; + mutex_unlock(&gclk.hevc_mux_node->mutex); + + pr_debug("the %-15s clock off, ref cnt: %d\n", + gclk.hevc_mux_node->name, + gclk.hevc_mux_node->ref_count); +} + +static void hevc_back_clock_on(void) +{ + mutex_lock(&gclk.hevc_back_mux_node->mutex); + if (!gclk.hevc_back_mux_node->ref_count) + clk_prepare_enable(gclk.hevc_back_mux_node->clk); + + gclk.hevc_back_mux_node->ref_count++; + WRITE_VREG(DOS_GCLK_EN3, 0xffffffff); + mutex_unlock(&gclk.hevc_back_mux_node->mutex); + + pr_debug("the %-15s clock on, ref cnt: %d\n", + gclk.hevc_back_mux_node->name, + gclk.hevc_back_mux_node->ref_count); +} + +static void hevc_back_clock_off(void) +{ + mutex_lock(&gclk.hevc_back_mux_node->mutex); + gclk.hevc_back_mux_node->ref_count--; + if (!gclk.hevc_back_mux_node->ref_count) + clk_disable_unprepare(gclk.hevc_back_mux_node->clk); + + clock_real_clk[VDEC_HEVC] = 0; + mutex_unlock(&gclk.hevc_back_mux_node->mutex); + + pr_debug("the %-15s clock off, ref cnt: %d\n", + gclk.hevc_back_mux_node->name, + gclk.hevc_back_mux_node->ref_count); +} + +static int vdec_clock_get(enum vdec_type_e core) +{ + if (core >= VDEC_MAX) + return 0; + + return clock_real_clk[core]; +} + +#define INCLUDE_FROM_ARCH_CLK_MGR + +/*#define VDEC_HAS_VDEC2*/ +#define VDEC_HAS_HEVC +#define VDEC_HAS_VDEC_HCODEC +#define VDEC_HAS_CLK_SETTINGS +#define CLK_FOR_CPU {\ + AM_MESON_CPU_MAJOR_ID_GXBB,\ + AM_MESON_CPU_MAJOR_ID_GXTVBB,\ + AM_MESON_CPU_MAJOR_ID_GXL,\ + AM_MESON_CPU_MAJOR_ID_GXM,\ + AM_MESON_CPU_MAJOR_ID_TXL,\ + AM_MESON_CPU_MAJOR_ID_TXLX,\ + AM_MESON_CPU_MAJOR_ID_GXLX,\ + AM_MESON_CPU_MAJOR_ID_G12A,\ + AM_MESON_CPU_MAJOR_ID_G12B,\ + AM_MESON_CPU_MAJOR_ID_SM1,\ + 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" + +module_param(set_frq_enable, uint, 0664); +MODULE_PARM_DESC(set_frq_enable, "\n set frequency enable\n"); + +module_param(vdec_frq, uint, 0664); +MODULE_PARM_DESC(vdec_frq, "\n set vdec frequency\n"); + +module_param(hevc_frq, uint, 0664); +MODULE_PARM_DESC(hevc_frq, "\n set hevc frequency\n"); + +module_param(hevcb_frq, uint, 0664); +MODULE_PARM_DESC(hevcb_frq, "\n set hevcb frequency\n"); + +ARCH_VDEC_CLK_INIT(); +ARCH_VDEC_CLK_EXIT(); + +MODULE_LICENSE("GPL");
diff --git a/drivers/common/media_clock/switch/amports_gate.c b/drivers/common/media_clock/switch/amports_gate.c new file mode 100644 index 0000000..58a0289 --- /dev/null +++ b/drivers/common/media_clock/switch/amports_gate.c
@@ -0,0 +1,204 @@ +/* + * drivers/amlogic/media/common/arch/switch/amports_gate.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. + * + */ +#define DEBUG +#include <linux/compiler.h> +#include <linux/clk-provider.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/clk.h> +#include "amports_gate.h" +#include <linux/amlogic/media/utils/vdec_reg.h> +#include "../../../stream_input/amports/amports_priv.h" +#include "../../../frame_provider/decoder/utils/vdec.h" +#include "../clk/clk.h" + + +#define DEBUG_REF 1 +#define GATE_RESET_OK + +#ifdef GATE_RESET_OK + +struct gate_switch_node gates[] = { + { + .name = "demux", + }, + { + .name = "parser_top", + }, + { + .name = "vdec", + }, + { + .name = "clk_81", + }, + { + .name = "clk_vdec_mux", + }, + { + .name = "clk_hcodec_mux", + }, + { + .name = "clk_hevc_mux", + }, + { + .name = "clk_hevcb_mux", + }, + { + .name = "ahbarb0", + }, + { + .name = "asyncfifo", + }, + { + .name = "clk_hevcf_mux", + }, +}; + +/* + *mesonstream { + * compatible = "amlogic, codec, streambuf"; + * dev_name = "mesonstream"; + * status = "okay"; + * clocks = <&clkc CLKID_DOS_PARSER + * &clkc CLKID_DEMUX + * &clkc CLKID_DOS + * &clkc CLKID_VDEC_MUX + * &clkc CLKID_HCODEC_MUX + * &clkc CLKID_HEVCF_MUX + * &clkc CLKID_HEVC_MUX>; + * clock-names = "parser_top", + * "demux", + * "vdec", + * "clk_vdec_mux", + * "clk_hcodec_mux", + * "clk_hevc_mux", + * "clk_hevcb_mux"; + *}; + */ + +int amports_clock_gate_init(struct device *dev) +{ + int i; + + for (i = 0; i < sizeof(gates) / sizeof(struct gate_switch_node); i++) { + 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 %px\n", + gates[i].name, + gates[i].clk); + } else { + pr_info("get gate %s control ok %px\n", + gates[i].name, + gates[i].clk); + } + gates[i].ref_count = 0; + mutex_init(&gates[i].mutex); + } + + set_clock_gate(gates, ARRAY_SIZE(gates)); + + return 0; +} +EXPORT_SYMBOL(amports_clock_gate_init); + +static int amports_gate_clk(struct gate_switch_node *gate_node, int enable) +{ + mutex_lock(&gate_node->mutex); + if (enable) { + if (gate_node->ref_count == 0) + clk_prepare_enable(gate_node->clk); + + gate_node->ref_count++; + + if (DEBUG_REF) + pr_debug("the %-15s clock on, ref cnt: %d\n", + gate_node->name, gate_node->ref_count); + } else { + gate_node->ref_count--; + if (gate_node->ref_count == 0) + clk_disable_unprepare(gate_node->clk); + + if (DEBUG_REF) + pr_debug("the %-15s clock off, ref cnt: %d\n", + gate_node->name, gate_node->ref_count); + } + mutex_unlock(&gate_node->mutex); + + return 0; +} + +int amports_switch_gate(const char *name, int enable) +{ + int i; + + for (i = 0; i < sizeof(gates) / sizeof(struct gate_switch_node); i++) { + if (!strcmp(name, gates[i].name)) { + + /*pr_info("openclose:%d gate %s control\n", enable, + * gates[i].name); + */ + + if (gates[i].clk) + amports_gate_clk(&gates[i], enable); + } + } + return 0; +} +EXPORT_SYMBOL(amports_switch_gate); + +#else +/* + *can used for debug. + *on chip bringup. + */ +int amports_clock_gate_init(struct device *dev) +{ + static int gate_inited; + + if (gate_inited) + return 0; +/* + *#define HHI_GCLK_MPEG0 0x1050 + *#define HHI_GCLK_MPEG1 0x1051 + *#define HHI_GCLK_MPEG2 0x1052 + *#define HHI_GCLK_OTHER 0x1054 + *#define HHI_GCLK_AO 0x1055 + */ + WRITE_HHI_REG_BITS(HHI_GCLK_MPEG0, 1, 1, 1);/*dos*/ + WRITE_HHI_REG_BITS(HHI_GCLK_MPEG1, 1, 25, 1);/*U_parser_top()*/ + WRITE_HHI_REG_BITS(HHI_GCLK_MPEG1, 0xff, 6, 8);/*aiu()*/ + WRITE_HHI_REG_BITS(HHI_GCLK_MPEG1, 1, 4, 1);/*demux()*/ + WRITE_HHI_REG_BITS(HHI_GCLK_MPEG1, 1, 2, 1);/*audio in()*/ + WRITE_HHI_REG_BITS(HHI_GCLK_MPEG2, 1, 25, 1);/*VPU Interrupt*/ + gate_inited++; + + + + return 0; +} +EXPORT_SYMBOL(amports_clock_gate_init); + + +int amports_switch_gate(const char *name, int enable) +{ + return 0; +} +EXPORT_SYMBOL(amports_switch_gate); + +#endif
diff --git a/drivers/common/media_clock/switch/amports_gate.h b/drivers/common/media_clock/switch/amports_gate.h new file mode 100644 index 0000000..58abc92 --- /dev/null +++ b/drivers/common/media_clock/switch/amports_gate.h
@@ -0,0 +1,32 @@ +/* + * drivers/amlogic/media/common/arch/switch/amports_gate.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 AMPORT_GATE_H +#define AMPORT_GATE_H +#include <linux/device.h> + +struct gate_switch_node { + struct clk *clk; + const char *name; + struct mutex mutex; + int ref_count; +}; + +extern int amports_clock_gate_init(struct device *dev); +extern int amports_switch_gate(const char *name, int enable); + +#endif
diff --git a/drivers/frame_provider/Makefile b/drivers/frame_provider/Makefile new file mode 100644 index 0000000..f30c4f1 --- /dev/null +++ b/drivers/frame_provider/Makefile
@@ -0,0 +1,2 @@ +obj-y += decoder/ +obj-y += decoder_v4l/
diff --git a/drivers/frame_provider/decoder/Makefile b/drivers/frame_provider/decoder/Makefile new file mode 100644 index 0000000..bb0079e --- /dev/null +++ b/drivers/frame_provider/decoder/Makefile
@@ -0,0 +1,13 @@ +obj-y += utils/ +obj-y += mpeg12/ +obj-y += mpeg4/ +obj-y += vc1/ +obj-y += h264/ +obj-y += h264_multi/ +obj-y += h265/ +obj-y += vp9/ +obj-y += mjpeg/ +obj-y += avs/ +obj-y += avs2/ +obj-y += avs_multi/ +obj-y += vav1/
diff --git a/drivers/frame_provider/decoder/avs/Makefile b/drivers/frame_provider/decoder/avs/Makefile new file mode 100644 index 0000000..1d56236 --- /dev/null +++ b/drivers/frame_provider/decoder/avs/Makefile
@@ -0,0 +1,2 @@ +obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_AVS) += amvdec_avs.o +amvdec_avs-objs += avs.o avsp_trans.o
diff --git a/drivers/frame_provider/decoder/avs/avs.c b/drivers/frame_provider/decoder/avs/avs.c new file mode 100644 index 0000000..5869eac --- /dev/null +++ b/drivers/frame_provider/decoder/avs/avs.c
@@ -0,0 +1,1988 @@ +/* + * 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. + * + */ +#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/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 "../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.h" +#include <linux/amlogic/media/codec_mm/configs.h> +#include "../utils/decoder_mmu_box.h" +#include "../utils/decoder_bmmu_box.h" +#include "../utils/firmware.h" +#include "../../../common/chips/decoder_cpu_ver_info.h" +//#include <linux/amlogic/tee.h> +#include <uapi/linux/tee.h> + +#define DRIVER_NAME "amvdec_avs" +#define MODULE_NAME "amvdec_avs" + + +#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 I_PICTURE 0 +#define P_PICTURE 1 +#define B_PICTURE 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 VF_POOL_SIZE 32 +#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 + + +#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_flag; + +/******************************** +firmware_sel + 0: use avsp_trans long cabac ucode; + 1: not use avsp_trans long cabac ucode +********************************/ +static int firmware_sel; +static int disable_longcabac_trans = 1; + +static int support_user_data = 1; + +int avs_get_debug_flag(void) +{ + return debug_flag; +} + +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_event_cb(int type, void *data, void *private_data); +static int vavs_vf_states(struct vframe_states *states, void *); + +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 +#define WORKSPACE_SIZE (4 * SZ_1M) + +#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 + +static u32 vf_buf_num = 8; +static u32 vf_buf_num_used; +static u32 canvas_base = 128; +#ifdef NV21 + int canvas_num = 2; /*NV21*/ +#else + 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; +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; +static u32 buf_size = 32 * 1024 * 1024; +static u32 buf_offset; +static u32 avi_flag; +static u32 vavs_ratio; +static u32 pic_type; +static u32 pts_by_offset = 1; +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 + +static u32 radr, rval; +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; + +static struct vdec_s *vdec = NULL; + +#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 + + +static void *user_data_buffer; +static dma_addr_t user_data_buffer_phys; + +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 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 +}; + +static void set_frame_info(struct vframe_s *vf, unsigned int *duration) +{ + int ar = 0; + + unsigned int pixel_ratio = READ_VREG(AVS_PIC_RATIO); +#ifndef USE_AVS_SEQ_INFO + if (vavs_amstream_dec_info.width > 0 + && vavs_amstream_dec_info.height > 0) { + vf->width = vavs_amstream_dec_info.width; + vf->height = vavs_amstream_dec_info.height; + } else +#endif + { + vf->width = READ_VREG(AVS_PIC_WIDTH); + vf->height = READ_VREG(AVS_PIC_HEIGHT); + frame_width = vf->width; + frame_height = vf->height; + /* pr_info("%s: (%d,%d)\n", __func__,vf->width, vf->height);*/ + } + +#ifndef USE_AVS_SEQ_INFO + if (vavs_amstream_dec_info.rate > 0) + *duration = 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); */ + frame_dur = *duration; + schedule_work(¬ify_work); + } + + if (vavs_ratio == 0) { + /* always stretch to 16:9 */ + vf->ratio_control |= (0x90 << + DISP_RATIO_ASPECT_RATIO_BIT); + } else { + switch (pixel_ratio) { + case 1: + ar = (vf->height * vavs_ratio) / vf->width; + break; + case 2: + ar = (vf->height * 3 * vavs_ratio) / (vf->width * 4); + break; + case 3: + ar = (vf->height * 9 * vavs_ratio) / (vf->width * 16); + break; + case 4: + ar = (vf->height * 100 * vavs_ratio) / (vf->width * + 221); + break; + default: + ar = (vf->height * 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; +} + + +static struct work_struct userdata_push_work; +/* +#define DUMP_LAST_REPORTED_USER_DATA +*/ +static void userdata_push_do_work(struct work_struct *work) +{ + 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(), + 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 *)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 *)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 *)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)user_data_buffer, + USER_DATA_SIZE, user_data_length); +*/ +} + +static void UserDataHandler(void) +{ + unsigned int user_data_flags; + + user_data_flags = READ_VREG(AV_SCRATCH_N); + if (user_data_flags & (1 << 15)) { /* data ready */ + schedule_work(&userdata_push_work); + } +} + + +#ifdef HANDLE_AVS_IRQ +static irqreturn_t vavs_isr(int irq, void *dev_id) +#else +static void vavs_isr(void) +#endif +{ + u32 reg; + struct vframe_s *vf; + 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; + if (debug_flag & 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); + } + } +#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 + + + UserDataHandler(); + + reg = READ_VREG(AVS_BUFFEROUT); + + if (reg) { + if (debug_flag & AVS_DEBUG_PRINT) + pr_info("AVS_BUFFEROUT=%x\n", reg); + if (pts_by_offset) { + offset = READ_VREG(AVS_OFFSET_REG); + if (debug_flag & AVS_DEBUG_PRINT) + pr_info("AVS OFFSET=%x\n", offset); + if (pts_lookup_offset_us64(PTS_TYPE_VIDEO, offset, &pts, + &frame_size, + 0, &pts_us64) == 0) { + pts_valid = 1; +#ifdef DEBUG_PTS + pts_hit++; +#endif + } else { +#ifdef DEBUG_PTS + pts_missed++; +#endif + } + } + + repeat_count = READ_VREG(AVS_REPEAT_COUNT); + if (firmware_sel == 0) + buffer_index = + ((reg & 0x7) + + (((reg >> 8) & 0x3) << 3) - 1) & 0x1f; + else + buffer_index = + ((reg & 0x7) - 1) & 7; + + 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) + pts_i_missed++; + else + pts_i_hit++; + } +#endif + + if ((dec_control & DEC_CONTROL_FLAG_FORCE_2500_1080P_INTERLACE) + && frame_width == 1920 && frame_height == 1080) { + force_interlaced_frame = true; + } + + if (throw_pb_flag && picture_type != I_PICTURE) { + + if (debug_flag & AVS_DEBUG_PRINT) { + pr_info("picture type %d throwed\n", + picture_type); + } + WRITE_VREG(AVS_BUFFERIN, ~(1 << buffer_index)); + } else if (reg & INTERLACE_FLAG || force_interlaced_frame) { /* interlace */ + throw_pb_flag = 0; + + if (debug_flag & AVS_DEBUG_PRINT) { + pr_info("interlace, picture type %d\n", + picture_type); + } + + if (kfifo_get(&newframe_q, &vf) == 0) { + pr_info + ("fatal error, no available buffer slot."); + return IRQ_HANDLED; + } + set_frame_info(vf, &dur); + vf->bufWidth = 1920; + pic_type = 2; + if ((picture_type == I_PICTURE) && pts_valid) { + vf->pts = pts; + vf->pts_us64 = pts_us64; + if ((repeat_count > 1) && avi_flag) { + /* next_pts = pts + + * (vavs_amstream_dec_info.rate * + * repeat_count >> 1)*15/16; + */ + next_pts = + pts + + (dur * repeat_count >> 1) * + 15 / 16; + } else + next_pts = 0; + } else { + vf->pts = next_pts; + if (vf->pts == 0) { + vf->pts_us64 = 0; + } + if ((repeat_count > 1) && avi_flag) { + /* vf->duration = + * vavs_amstream_dec_info.rate * + * repeat_count >> 1; + */ + vf->duration = dur * repeat_count >> 1; + if (next_pts != 0) { + next_pts += + ((vf->duration) - + ((vf->duration) >> 4)); + } + } else { + /* vf->duration = + * vavs_amstream_dec_info.rate >> 1; + */ + vf->duration = dur >> 1; + 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 + vf->canvas0Addr = vf->canvas1Addr = + index2canvas(buffer_index); + vf->type_original = vf->type; + + if (debug_flag & AVS_DEBUG_PRINT) { + pr_info("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; + */ + vfbuf_use[buffer_index]++; + vf->mem_handle = + 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); + ATRACE_COUNTER(MODULE_NAME, vf->pts); + vf_notify_receiver(PROVIDER_NAME, + VFRAME_EVENT_PROVIDER_VFRAME_READY, + NULL); + + if (kfifo_get(&newframe_q, &vf) == 0) { + pr_info("fatal error, no available buffer slot."); + return IRQ_HANDLED; + } + set_frame_info(vf, &dur); + vf->bufWidth = 1920; + if (force_interlaced_frame) + vf->pts = 0; + else + vf->pts = next_pts; + if (vf->pts == 0) { + vf->pts_us64 = 0; + } + if ((repeat_count > 1) && avi_flag) { + /* vf->duration = vavs_amstream_dec_info.rate * + * repeat_count >> 1; + */ + vf->duration = dur * repeat_count >> 1; + if (next_pts != 0) { + next_pts += + ((vf->duration) - + ((vf->duration) >> 4)); + } + } else { + /* vf->duration = vavs_amstream_dec_info.rate + * >> 1; + */ + vf->duration = dur >> 1; + 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 + vf->canvas0Addr = vf->canvas1Addr = + index2canvas(buffer_index); + vf->type_original = vf->type; + vf->pts_us64 = 0; + vfbuf_use[buffer_index]++; + 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, + NULL); + total_frame++; + } else { /* progressive */ + throw_pb_flag = 0; + + if (debug_flag & AVS_DEBUG_PRINT) { + pr_info("progressive picture type %d\n", + picture_type); + } + if (kfifo_get(&newframe_q, &vf) == 0) { + pr_info + ("fatal error, no available buffer slot."); + return IRQ_HANDLED; + } + set_frame_info(vf, &dur); + vf->bufWidth = 1920; + pic_type = 1; + + if ((picture_type == I_PICTURE) && pts_valid) { + vf->pts = pts; + if ((repeat_count > 1) && avi_flag) { + /* next_pts = pts + + * (vavs_amstream_dec_info.rate * + * repeat_count)*15/16; + */ + next_pts = + pts + + (dur * repeat_count) * 15 / 16; + } else + next_pts = 0; + } else { + vf->pts = next_pts; + if (vf->pts == 0) { + vf->pts_us64 = 0; + } + if ((repeat_count > 1) && avi_flag) { + /* vf->duration = + * vavs_amstream_dec_info.rate * + * repeat_count; + */ + vf->duration = dur * repeat_count; + if (next_pts != 0) { + next_pts += + ((vf->duration) - + ((vf->duration) >> 4)); + } + } else { + /* vf->duration = + * vavs_amstream_dec_info.rate; + */ + vf->duration = dur; + 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 + 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; + */ + if (debug_flag & AVS_DEBUG_PRINT) { + pr_info("buffer_index %d, canvas addr %x\n", + buffer_index, vf->canvas0Addr + ); + pr_info("PicType = %d, PTS = 0x%x\n", + picture_type, vf->pts); + } + + vfbuf_use[buffer_index]++; + vf->mem_handle = + 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); + ATRACE_COUNTER(MODULE_NAME, vf->pts); + vf_notify_receiver(PROVIDER_NAME, + VFRAME_EVENT_PROVIDER_VFRAME_READY, + NULL); + total_frame++; + } + + /*count info*/ + gvs->frame_dur = frame_dur; + vdec_count_info(gvs, 0, offset); + + /* pr_info("PicType = %d, PTS = 0x%x\n", + * picture_type, vf->pts); + */ + WRITE_VREG(AVS_BUFFEROUT, 0); + } + WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); + +#ifdef HANDLE_AVS_IRQ + return IRQ_HANDLED; +#else + return; +#endif +} +/* + *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; + + if (recover_flag) + return NULL; + + if (kfifo_peek(&display_q, &vf)) + return vf; + + return NULL; + +} + +static struct vframe_s *vavs_vf_get(void *op_arg) +{ + struct vframe_s *vf; + + if (recover_flag) + return NULL; + + if (kfifo_get(&display_q, &vf)) + return vf; + + return NULL; + +} + +static void vavs_vf_put(struct vframe_s *vf, void *op_arg) +{ + int i; + + if (recover_flag) + return; + + for (i = 0; i < VF_POOL_SIZE; i++) { + if (vf == &cur_vfpool[i]) + break; + } + if (i < VF_POOL_SIZE) + kfifo_put(&recycle_q, (const struct vframe_s *)vf); + +} + +static int vavs_event_cb(int type, void *data, void *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 && vdec) + req->req_result[0] = vdec_secure(vdec); + else + req->req_result[0] = 0xffffffff; + } + + return 0; +} + +int vavs_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus) +{ + if (!(stat & STAT_VDEC_RUN)) + return -1; + + 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 = READ_VREG(AV_SCRATCH_C); + vstatus->status = stat; + vstatus->bit_rate = gvs->bit_rate; + 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; +} + +int vavs_set_isreset(struct vdec_s *vdec, int isreset) +{ + is_reset = isreset; + return 0; +} + +static int vavs_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; +} +/****************************************/ +static int vavs_canvas_init(void) +{ + 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; + u32 endian; + + vf_buf_num_used = vf_buf_num; + 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 = vf_buf_num_used + 2; +#else + need_alloc_buf_num = 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(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) + buf_offset = buf_start - + RV_AI_BUFF_START_ADDR; + else + 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 (vdec->canvas_mode == CANVAS_BLKMODE_LINEAR) + endian = 7; + else + endian = 0; +#ifdef NV21 + config_cav_lut_ex(canvas_base + canvas_num * i + 0, + buf_start, + canvas_width, canvas_height, + CANVAS_ADDR_NOWRAP, + 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_1); +#else + config_cav_lut_ex(canvas_num * i + 0, + buf_start, + canvas_width, canvas_height, + CANVAS_ADDR_NOWRAP, + 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, 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_1); +#endif + if (debug_flag & AVS_DEBUG_PRINT) { + pr_info("canvas config %d, addr %p\n", i, + (void *)buf_start); + } + + } + return 0; +} + +void vavs_recover(void) +{ + vavs_canvas_init(); + + 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); + WRITE_VREG(AV_SCRATCH_H, 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); + WRITE_VREG(AV_SCRATCH_H, 1); // 8 buf flag to ucode + } + + + if (firmware_sel == 0) { + /* fixed canvas index */ + WRITE_VREG(AV_SCRATCH_0, canvas_base); + WRITE_VREG(AV_SCRATCH_1, vf_buf_num_used); + } else { + int ii; + + 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) + ); + } + } + + /* notify ucode the buffer offset */ + WRITE_VREG(AV_SCRATCH_F, buf_offset); + + /* disable PSCALE for hardware sharing */ + WRITE_VREG(PSCALE_CTRL, 0); + + WRITE_VREG(AVS_SOS_COUNT, 0); + 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 1 /* def DEBUG_UCODE */ + WRITE_VREG(AV_SCRATCH_D, 0); +#endif + +#ifdef NV21 + SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17); +#endif + +#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_N, (u32)(user_data_buffer_phys - buf_offset)); + pr_info("support_user_data = %d\n", support_user_data); + if (support_user_data) + WRITE_VREG(AV_SCRATCH_M, 1); + else + WRITE_VREG(AV_SCRATCH_M, 0); + + WRITE_VREG(AV_SCRATCH_5, 0); + +} + +static int vavs_prot_init(void) +{ + int r; +#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 + + /***************** 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); + /*************************************************************/ + + r = vavs_canvas_init(); + WRITE_VREG(AV_SCRATCH_H, 0); +#ifdef NV21 + if (firmware_sel == 0) { + /* fixed canvas index */ + WRITE_VREG(AV_SCRATCH_0, canvas_base); + WRITE_VREG(AV_SCRATCH_1, vf_buf_num_used); + } else { + int ii; + + 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) + ); + } + WRITE_VREG(AV_SCRATCH_H, 1); // 8 buf flag to ucode + } +#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 */ + WRITE_VREG(AV_SCRATCH_F, buf_offset); + + /* disable PSCALE for hardware sharing */ + WRITE_VREG(PSCALE_CTRL, 0); + + WRITE_VREG(AVS_SOS_COUNT, 0); + 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 1 /* def DEBUG_UCODE */ + WRITE_VREG(AV_SCRATCH_D, 0); +#endif + +#ifdef NV21 + SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17); +#endif + +#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_N, (u32)(user_data_buffer_phys - buf_offset)); + pr_info("support_user_data = %d\n", support_user_data); + if (support_user_data) + WRITE_VREG(AV_SCRATCH_M, 1); + else + WRITE_VREG(AV_SCRATCH_M, 0); + + return r; +} + +#ifdef AVSP_LONG_CABAC +static unsigned char es_write_addr[MAX_CODED_FRAME_SIZE] __aligned(64); +#endif +static void vavs_local_init(bool is_reset) +{ + int i; + + is_reset = 0; + vavs_ratio = vavs_amstream_dec_info.ratio; + + avi_flag = (unsigned long) vavs_amstream_dec_info.param; + + frame_width = frame_height = frame_dur = frame_prog = 0; + + throw_pb_flag = 1; + + total_frame = 0; + saved_resolution = 0; + next_pts = 0; + +#ifdef DEBUG_PTS + pts_hit = pts_missed = pts_i_hit = pts_i_missed = 0; +#endif + + if (!is_reset) { + 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; + vfpool[i].bufWidth = 1920; + kfifo_put(&newframe_q, vf); + } + + for (i = 0; i < vf_buf_num; i++) + vfbuf_use[i] = 0; + } + + cur_vfpool = vfpool; + + if (recover_flag == 1) + return; + + 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); + +} + +static int vavs_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; +} + +#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(true); + + pr_info("vavs: vf_ppmgr_reset\n"); +} +#endif + +static void vavs_local_reset(void) +{ + mutex_lock(&vavs_mutex); + //recover_flag = 1; + pr_info("error, local reset\n"); + amvdec_stop(); + msleep(100); + vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_RESET, NULL); + vavs_local_init(true); + vavs_recover(); + + + reset_userdata_fifo(1); + + + amvdec_start(); + 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); +} + +static struct work_struct fatal_error_wd_work; +static struct work_struct notify_work; +static atomic_t error_handler_run = ATOMIC_INIT(0); +static void vavs_fatal_error_handler(struct work_struct *work) +{ + if (debug_flag & 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(true); + vf_reg_provider(&vavs_vf_prov); +#endif + vavs_recover(); + amvdec_start(); + mutex_unlock(&vavs_mutex); + } else { + pr_info("avs fatal_error_handler\n"); + vavs_local_reset(); + } + atomic_set(&error_handler_run, 0); +} + +static void vavs_notify_work(struct work_struct *work) +{ + if (fr_hint_status == VDEC_NEED_HINT) { + vf_notify_receiver(PROVIDER_NAME , + VFRAME_EVENT_PROVIDER_FR_HINT , + (void *)((unsigned long)frame_dur)); + fr_hint_status = VDEC_HINTED; + } + return; +} + +static void avs_set_clk(struct work_struct *work) +{ + int fps = 96000 / frame_dur; + + saved_resolution = frame_width * frame_height * fps; + if (firmware_sel == 0 && + (debug_flag & AVS_DEBUG_USE_FULL_SPEED)) { + vdec_source_changed(VFORMAT_AVS, + 4096, 2048, 60); + } else { + vdec_source_changed(VFORMAT_AVS, + frame_width, frame_height, fps); + } +} + +static void vavs_put_timer_func(struct timer_list *timer) +{ +#ifndef HANDLE_AVS_IRQ + vavs_isr(); +#endif + + if (READ_VREG(AVS_SOS_COUNT)) { + if (!error_recovery_mode) { +#if 0 + if (debug_flag & 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(true); + vf_reg_provider(&vavs_vf_prov); +#endif + vavs_recover(); + amvdec_start(); + mutex_unlock(&vavs_mutex); + } else { + vavs_local_reset(); + } +#else + if (!atomic_read(&error_handler_run)) { + atomic_set(&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(&fatal_error_wd_work); + } +#endif + } + } +#if 0 + if (long_cabac_busy == 0 && + error_watchdog_threshold > 0 && + kfifo_len(&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(&newframe_q), + kfifo_len(&display_q), + kfifo_len(&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 (!kfifo_is_empty(&recycle_q) && (READ_VREG(AVS_BUFFERIN) == 0)) { + struct vframe_s *vf; + + if (kfifo_get(&recycle_q, &vf)) { + if ((vf->index < vf_buf_num) && + (--vfbuf_use[vf->index] == 0)) { + WRITE_VREG(AVS_BUFFERIN, ~(1 << vf->index)); + vf->index = vf_buf_num; + } + kfifo_put(&newframe_q, + (const struct vframe_s *)vf); + } + } + + if (frame_dur > 0 && saved_resolution != + frame_width * frame_height * (96000 / frame_dur)) + schedule_work(&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; +#ifdef PERFORMANCE_DEBUG + pr_info("enter %s buf level (new %d, display %d, recycle %d)\r\n", + __func__, + kfifo_len(&newframe_q), + kfifo_len(&display_q), + kfifo_len(&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(&newframe_q), + kfifo_len(&display_q), + kfifo_len(&recycle_q) + ); +#endif + if (status < 0) { + pr_info("transcoding error, local reset\r\n"); + vavs_local_reset(); + } + +} +#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(void) +{ + int ret, size = -1; + char *buf = vmalloc(0x1000 * 16); + + if (IS_ERR_OR_NULL(buf)) + return -ENOMEM; + + pr_info("vavs_init\n"); + + stat |= STAT_TIMER_INIT; + + amvdec_enable(); + vavs_local_init(false); + + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXM) + size = get_firmware_data(VIDEO_DEC_AVS, buf); + else { + if (firmware_sel == 1) + size = get_firmware_data(VIDEO_DEC_AVS_NOCABAC, buf); +#ifdef AVSP_LONG_CABAC + else { + init_avsp_long_cabac_buf(); + size = get_firmware_data(VIDEO_DEC_AVS, buf); + } +#endif + } + + if (size < 0) { + amvdec_disable(); + pr_err("get firmware fail."); + vfree(buf); + return -1; + } + + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXM) + ret = amvdec_loadmc_ex(VFORMAT_AVS, NULL, buf); + else if (firmware_sel == 1) + ret = amvdec_loadmc_ex(VFORMAT_AVS, "avs_no_cabac", buf); + else + ret = amvdec_loadmc_ex(VFORMAT_AVS, NULL, buf); + + 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); + + stat |= STAT_MC_LOAD; + + /* enable AMRISC side protocol */ + ret = vavs_prot_init(); + if (ret < 0) + return ret; + +#ifdef HANDLE_AVS_IRQ + if (vdec_request_irq(VDEC_IRQ_1, vavs_isr, + "vavs-irq", (void *)vavs_dec_id)) { + amvdec_disable(); + pr_info("vavs irq register error.\n"); + return -ENOENT; + } +#endif + + stat |= STAT_ISR_REG; + +#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER + vf_provider_init(&vavs_vf_prov, PROVIDER_NAME, &vavs_vf_provider, NULL); + vf_reg_provider(&vavs_vf_prov); + vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_START, NULL); +#else + vf_provider_init(&vavs_vf_prov, PROVIDER_NAME, &vavs_vf_provider, NULL); + vf_reg_provider(&vavs_vf_prov); +#endif + + if (vavs_amstream_dec_info.rate != 0) { + if (!is_reset) { + vf_notify_receiver(PROVIDER_NAME, + VFRAME_EVENT_PROVIDER_FR_HINT, + (void *)((unsigned long) + vavs_amstream_dec_info.rate)); + fr_hint_status = VDEC_HINTED; + } + } else + fr_hint_status = VDEC_NEED_HINT; + + stat |= STAT_VF_HOOK; + + timer_setup(&recycle_timer, vavs_put_timer_func, 0); + recycle_timer.expires = jiffies + PUT_INTERVAL; + add_timer(&recycle_timer); + + 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); + amvdec_start(); + + 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; + + if (pdata == NULL) { + pr_info("amvdec_avs memory resource undefined.\n"); + return -EFAULT; + } + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXM || disable_longcabac_trans) + firmware_sel = 1; + + if (firmware_sel == 1) { + vf_buf_num = 8; + canvas_base = 0; + canvas_num = 2; + } else { + + canvas_base = 128; + canvas_num = 2; /*NV21*/ + } + + + if (pdata->sys_info) + vavs_amstream_dec_info = *pdata->sys_info; + + pr_info("%s (%d,%d) %d\n", __func__, vavs_amstream_dec_info.width, + vavs_amstream_dec_info.height, vavs_amstream_dec_info.rate); + + pdata->dec_status = vavs_dec_status; + pdata->set_isreset = vavs_set_isreset; + is_reset = 0; + + pdata->user_data_read = NULL; + pdata->reset_userdata_fifo = NULL; + + vavs_vdec_info_init(); + + + if (NULL == user_data_buffer) { + user_data_buffer = + dma_alloc_coherent(amports_get_dma_device(), + USER_DATA_SIZE, + &user_data_buffer_phys, GFP_KERNEL); + if (!user_data_buffer) { + pr_info("%s: Can not allocate user_data_buffer\n", + __func__); + return -ENOMEM; + } + pr_debug("user_data_buffer = 0x%p, user_data_buffer_phys = 0x%x\n", + user_data_buffer, (u32)user_data_buffer_phys); + } + + INIT_WORK(&set_clk_work, avs_set_clk); + vdec = pdata; + + INIT_WORK(&fatal_error_wd_work, vavs_fatal_error_handler); + atomic_set(&error_handler_run, 0); + + INIT_WORK(&userdata_push_work, userdata_push_do_work); + INIT_WORK(¬ify_work, vavs_notify_work); + + if (vavs_init() < 0) { + pr_info("amvdec_avs init failed.\n"); + kfree(gvs); + gvs = NULL; + pdata->dec_status = NULL; + return -ENODEV; + } + return 0; +} + +static int amvdec_avs_remove(struct platform_device *pdev) +{ + if (stat & STAT_TIMER_ARM) { + del_timer_sync(&recycle_timer); + stat &= ~STAT_TIMER_ARM; + } + cancel_work_sync(&fatal_error_wd_work); + atomic_set(&error_handler_run, 0); + + cancel_work_sync(&userdata_push_work); + + cancel_work_sync(¬ify_work); + if (stat & STAT_VDEC_RUN) { + amvdec_stop(); + stat &= ~STAT_VDEC_RUN; + } + + if (stat & STAT_ISR_REG) { + vdec_free_irq(VDEC_IRQ_1, (void *)vavs_dec_id); + stat &= ~STAT_ISR_REG; + } + +#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 (stat & STAT_VF_HOOK) { + if (fr_hint_status == VDEC_HINTED) + vf_notify_receiver(PROVIDER_NAME, + VFRAME_EVENT_PROVIDER_FR_END_HINT, NULL); + fr_hint_status = VDEC_NO_NEED_HINT; + vf_unreg_provider(&vavs_vf_prov); + stat &= ~STAT_VF_HOOK; + } + + + if (user_data_buffer != NULL) { + dma_free_coherent( + amports_get_dma_device(), + USER_DATA_SIZE, + user_data_buffer, + user_data_buffer_phys); + user_data_buffer = NULL; + user_data_buffer_phys = 0; + } + + + amvdec_disable(); + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_TM2) + vdec_reset_core(NULL); + pic_type = 0; + if (mm_blk_handle) { + decoder_bmmu_box_free(mm_blk_handle); + mm_blk_handle = NULL; + } +#ifdef DEBUG_PTS + pr_debug("pts hit %d, pts missed %d, i hit %d, missed %d\n", pts_hit, + pts_missed, pts_i_hit, pts_i_missed); + pr_debug("total frame %d, avi_flag %d, rate %d\n", total_frame, avi_flag, + vavs_amstream_dec_info.rate); +#endif + kfree(gvs); + gvs = NULL; + vdec = NULL; + + cancel_work_sync(&set_clk_work); + return 0; +} + +/****************************************/ +#ifdef CONFIG_PM +static int avs_suspend(struct device *dev) +{ + amvdec_suspend(to_platform_device(dev), dev->power.power_state); + return 0; +} + +static int avs_resume(struct device *dev) +{ + amvdec_resume(to_platform_device(dev)); + return 0; +} + +static const struct dev_pm_ops avs_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(avs_suspend, avs_resume) +}; +#endif + +static struct platform_driver amvdec_avs_driver = { + .probe = amvdec_avs_probe, + .remove = amvdec_avs_remove, + .driver = { + .name = DRIVER_NAME, +#ifdef CONFIG_PM + .pm = &avs_pm_ops, +#endif + } +}; + +static struct codec_profile_t amvdec_avs_profile = { + .name = "avs", + .profile = "" +}; + +static struct mconfig avs_configs[] = { + MC_PU32("stat", &stat), + MC_PU32("debug_flag", &debug_flag), + MC_PU32("error_recovery_mode", &error_recovery_mode), + MC_PU32("pic_type", &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 avs_node; + + +static int __init amvdec_avs_driver_init_module(void) +{ + pr_debug("amvdec_avs module init\n"); + + if (platform_driver_register(&amvdec_avs_driver)) { + pr_info("failed to register amvdec_avs driver\n"); + return -ENODEV; + } + + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXBB) + amvdec_avs_profile.profile = "avs+"; + + vcodec_profile_register(&amvdec_avs_profile); + INIT_REG_NODE_CONFIGS("media.decoder", &avs_node, + "avs", avs_configs, CONFIG_FOR_RW); + return 0; +} + +static void __exit amvdec_avs_driver_remove_module(void) +{ + pr_debug("amvdec_avs module remove.\n"); + + platform_driver_unregister(&amvdec_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(debug_flag, uint, 0664); +MODULE_PARM_DESC(debug_flag, "\n debug_flag\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(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(support_user_data, uint, 0664); +MODULE_PARM_DESC(support_user_data, "\n support_user_data\n"); + +module_init(amvdec_avs_driver_init_module); +module_exit(amvdec_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/avs/avs.h b/drivers/frame_provider/decoder/avs/avs.h new file mode 100644 index 0000000..8277d20 --- /dev/null +++ b/drivers/frame_provider/decoder/avs/avs.h
@@ -0,0 +1,91 @@ +/* +* 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_UCODE 0x02 +#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/avs/avsp_trans.c b/drivers/frame_provider/decoder/avs/avsp_trans.c new file mode 100644 index 0000000..a92dbb9 --- /dev/null +++ b/drivers/frame_provider/decoder/avs/avsp_trans.c
@@ -0,0 +1,5065 @@ +/* +* 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/errno.h> +#include <linux/interrupt.h> +#include <linux/timer.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.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/dma-mapping.h> +#include <linux/amlogic/media/codec_mm/codec_mm.h> +#include <linux/slab.h> +/* #include <mach/am_regs.h> */ +#include <linux/module.h> +#include <linux/amlogic/media/utils/vdec_reg.h> +#include "../../../stream_input/amports/streambuf_reg.h" +#include "../utils/amvdec.h" +#include <linux/amlogic/media/registers/register.h> +#include "../../../stream_input/amports/amports_priv.h" + +#include "avs.h" +#ifdef AVSP_LONG_CABAC + +#define DECODING_SANITY_CHECK + +#define TRACE 0 +#define LIWR_FIX 0 +#define pow2(a, b) (1<<b) +#define io_printf pr_info + +static unsigned char *local_heap_adr; +static int local_heap_size; +static int local_heap_pos; +static int transcoding_error_flag; + +unsigned char *local_alloc(int num, int size) +{ + unsigned char *ret_buf = NULL; + int alloc_size = num * size; + + if ((local_heap_pos + alloc_size) <= local_heap_size) { + ret_buf = local_heap_adr + local_heap_pos; + local_heap_pos += alloc_size; + } else { + pr_info( + "!!!local_alloc(%d) error, local_heap (size %d) is not enough\r\n", + alloc_size, local_heap_size); + } + return ret_buf; +} + +int local_heap_init(int size) +{ + /*local_heap_adr = &local_heap[0];*/ + local_heap_adr = (unsigned char *)(avsp_heap_adr + + MAX_CODED_FRAME_SIZE); + memset(local_heap_adr, 0, LOCAL_HEAP_SIZE); + + local_heap_size = LOCAL_HEAP_SIZE; + local_heap_pos = 0; + return 0; +} + +void local_heap_uninit(void) +{ + local_heap_adr = NULL; + local_heap_size = 0; + local_heap_pos = 0; +} + +#define CODE2D_ESCAPE_SYMBOL 59 + +const int vlc_golomb_order[3][7][2] = + +{{{2, 9}, {2, 9}, {2, 9}, {2, 9}, {2, 9}, {2, 9}, {2, 9}, }, {{3, 9}, {2, 9}, { + 2, 9}, {2, 9}, {2, 9}, {2, 9}, {2, 9}, }, {{2, 9}, {0, 9}, + {1, 9}, {1, 9}, {0, 9}, {-1, -1}, {-1, -1}, }, }; + +const int MaxRun[3][7] = {{22, 14, 9, 6, 4, 2, 1}, {25, 18, 13, 9, 6, 4, 3}, { + 24, 19, 10, 7, 4, -1, -1} }; + +const int refabslevel[19][26] = {{4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, -1, -1, -1}, {7, 4, 4, 3, 3, 3, 3, 3, 2, + 2, 2, 2, 2, 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + 10, 6, 4, 4, 3, 3, 3, 2, 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1}, {13, 7, 5, 4, 3, 2, 2, -1, -1, + -1 - 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1}, {18, 8, 4, 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {22, 7, 3, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1}, {27, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, + 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2}, {5, 4, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, -1, -1, -1, -1, -1, -1, -1}, {7, 5, 4, 4, 3, 3, 3, 2, 2, + 2, 2, 2, 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {10, 6, 5, 4, 3, 3, 2, 2, 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1}, {13, 7, 5, 4, + 3, 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1}, {17, 8, 4, + 3, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + 22, 6, 3, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1}, {5, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1}, {6, 4, 3, + 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, -1, -1, -1, -1, -1, -1}, {10, 6, 4, 4, 3, 3, + 2, 2, 2, 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {14, 7, 4, 3, 3, 2, + 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1}, {20, 7, 3, 2, + 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1} }; + +static const int incvlc_intra[7] = {0, 1, 2, 4, 7, 10, 3000}; +static const int incvlc_chroma[5] = {0, 1, 2, 4, 3000}; + +const int AVS_2DVLC_INTRA[7][26][27] = {{{0, 22, 38, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1}, {2, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 44, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {6, 50, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {8, 54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {10, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1}, {12, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1}, {14, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1}, {16, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {18, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1}, {20, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1}, {24, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1}, {26, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {28, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1}, {30, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1}, {34, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1}, {36, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {40, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1}, {42, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1}, {46, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1}, {48, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {52, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1}, {56, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1}, }, {{8, 0, 4, 15, 27, 41, + 55, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1}, {-1, 2, 17, 35, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {-1, 6, 25, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, 9, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, 11, 39, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, 13, 45, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, 19, 49, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, 21, 51, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, 23, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, 29, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, 31, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, 37, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, 47, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, 57, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, }, {{8, 0, 2, 6, + 13, 17, 27, 35, 45, 55, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, 4, 11, 21, 33, 49, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, 9, 23, 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, 15, + 29, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, 19, 39, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1}, {-1, 25, 43, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1}, {-1, 31, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, 41, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, 47, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1}, {-1, 57, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1}, }, {{8, 0, 2, 4, 9, 11, 17, 21, 25, 33, 39, 45, 55, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, 6, 13, 19, + 29, 35, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, 15, 27, 41, 57, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, 23, 37, 53, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, 31, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, 43, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, 49, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, }, {{6, 0, 2, 4, 7, 9, 11, 15, 17, + 21, 23, 29, 33, 35, 43, 47, 49, 57, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, 13, 19, 27, 31, 37, 45, 55, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + 25, 41, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, 39, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, 53, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, }, {{0, + 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 23, 25, 27, 31, 33, 37, 41, + 45, 49, 51, 55, -1, -1, -1, -1, -1}, {-1, 21, 29, 35, 43, 47, + 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1}, {-1, 39, 57, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1}, }, {{0, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, + 21, 23, 25, 27, 29, 31, 35, 37, 39, 41, 43, 47, 49, 51, 53, 57}, + {-1, 33, 45, 55, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1} } }; + +const int AVS_2DVLC_CHROMA[5][26][27] = {{{0, 14, 32, 56, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {2, 48, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1}, {6, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {10, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {12, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {16, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {18, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {20, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {22, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {24, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {26, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {28, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {30, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {34, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {36, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {38, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {40, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {42, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {44, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {46, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {50, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {52, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, }, {{0, 1, 5, 15, 29, + 43, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, 3, 21, 45, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1}, {-1, 7, 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, 9, 41, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, 11, 53, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, 19, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, 23, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, 27, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, 31, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, 33, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, 35, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, 39, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, 47, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, 49, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, 55, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, 57, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, }, + {{2, 0, 3, 7, 11, 17, 27, 33, 47, 53, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { + -1, 5, 13, 21, 37, 55, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, 9, 23, 41, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, 15, 31, 57, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + 19, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, 25, 45, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, 29, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + 35, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, 39, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, 49, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, }, {{0, 1, 3, 5, 7, 11, 15, 19, 23, 29, + 35, 43, 47, 53, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1}, {-1, 9, 13, 21, 31, 39, 51, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1}, {-1, 17, 27, + 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {-1, 25, 41, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, { + -1, 33, 55, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, 45, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, { + -1, 49, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, 57, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}, {-1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1}, }, + {{0, 1, 3, 5, 7, 9, 11, 13, 15, 19, 21, 23, 27, 29, 33, 37, 41, + 43, 51, 55, -1, -1, -1, -1, -1, -1, -1}, {-1, + 17, 25, 31, 39, 45, 53, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, 35, 49, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, 47, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + 57, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}, } }; + +const int UE[64][2] = {{1, 1}, {2, 3}, {3, 3}, {4, 5}, {5, 5}, {6, 5}, {7, 5}, { + 8, 7}, {9, 7}, {10, 7}, {11, 7}, {12, 7}, {13, 7}, {14, 7}, {15, + 7}, {16, 9}, {17, 9}, {18, 9}, {19, 9}, {20, 9}, {21, 9}, + {22, 9}, {23, 9}, {24, 9}, {25, 9}, {26, 9}, {27, 9}, {28, 9}, { + 29, 9}, {30, 9}, {31, 9}, {32, 11}, {33, 11}, { + 34, 11}, {35, 11}, {36, 11}, {37, 11}, {38, 11}, + {39, 11}, {40, 11}, {41, 11}, {42, 11}, {43, 11}, {44, 11}, {45, + 11}, {46, 11}, {47, 11}, {48, 11}, {49, 11}, { + 50, 11}, {51, 11}, {52, 11}, {53, 11}, {54, 11}, + {55, 11}, {56, 11}, {57, 11}, {58, 11}, {59, 11}, {60, 11}, {61, + 11}, {62, 11}, {63, 11}, {64, 13} }; + +unsigned int src_start; +unsigned int des_start; + +#ifdef AVSP_LONG_CABAC + +unsigned char *es_buf; +unsigned int es_buf_ptr; +unsigned int es_buf_is_overflow; + +#else +FILE *f_es; +#endif +unsigned int es_ptr; +unsigned int es_res; +unsigned int es_res_ptr; +unsigned int previous_es; + +void init_es(void) +{ + +#ifdef AVSP_LONG_CABAC + es_buf_is_overflow = 0; + + es_buf[0] = 0x00; + es_buf[1] = 0x00; + es_buf[2] = 0x01; + es_buf_ptr = 3; + es_ptr = 3; +#else + f_es = fopen("es.out", "wb"); + if (f_es == NULL) + io_printf(" ERROR : Can not open es.out for write\n"); + putc(0x00, f_es); + putc(0x00, f_es); + putc(0x01, f_es); + + es_ptr = 3; +#endif + es_res = 0; + es_res_ptr = 0; + previous_es = 0xff; + +} + +void push_es(int value, int num) +{ + unsigned char wr_es_data; + int push_num; + int push_value; + +#ifdef DUMP_DEBUG + if (avs_get_debug_flag() & ES_DUMP) + io_printf(" push_es : value : 0x%x, num : %d\n", value, num); +#endif + while (num > 0) { + if (num >= 8) + push_num = 8; + else + push_num = num; + + num = num - push_num; + push_value = (value >> num); + + es_res = (es_res << push_num) | push_value; + es_res_ptr = es_res_ptr + push_num; + +#ifdef DUMP_DEBUG + if (avs_get_debug_flag() & ES_DUMP) + io_printf(" #### es_res : 0x%X, es_res_ptr : %d\n", + es_res, es_res_ptr); +#endif + + while (es_res_ptr >= 8) { + es_res_ptr = es_res_ptr & 7; + wr_es_data = (es_res >> es_res_ptr) & 0xff; + if ((previous_es == 0) & (wr_es_data < 4)) { + io_printf( + " Insert 2'b10 for emu at position : %d\n", + es_ptr); + + es_res_ptr = es_res_ptr + 2; + wr_es_data = 2; + } +#ifdef AVSP_LONG_CABAC +#ifdef DUMP_DEBUG + if (avs_get_debug_flag() & ES_DUMP) + pr_info("es_buf[%d] = 0x%02x\r\n", + es_buf_ptr, wr_es_data); +#endif + if (!es_buf_is_overflow) { + es_buf[es_buf_ptr++] = wr_es_data; + if (es_buf_ptr >= MAX_CODED_FRAME_SIZE) + es_buf_is_overflow = 1; + } +#else + putc(wr_es_data, f_es); +#endif + es_ptr++; + previous_es = ((previous_es << 8) | wr_es_data) + & 0xffff; + } + + } +} + +#ifdef BLOCK_SIZE +#undef BLOCK_SIZE +#endif + +#define MIN_QP 0 +#define MAX_QP 63 + +#define BLOCK_SIZE 4 +#define B8_SIZE 8 +#define MB_BLOCK_SIZE 16 + +#define BLOCK_MULTIPLE (MB_BLOCK_SIZE/(BLOCK_SIZE*2)) + +#define DECODE_COPY_MB 0 +#define DECODE_MB 1 + +#define NO_INTRA_PMODE 5 +#define INTRA_PMODE_4x4 10 +#define NO_INTRA_PMODE_4x4 19 +/* 8x8 intra prediction modes */ +#define VERT_PRED 0 +#define HOR_PRED 1 +#define DC_PRED 2 +#define DOWN_LEFT_PRED 3 +#define DOWN_RIGHT_PRED 4 + +#define VERT_PRED_4x4 0 +#define HOR_PRED_4x4 1 +#define DC_PRED_4x4 2 +#define DOWN_LEFT_PRED_4x4 3 +#define DOWN_RIGHT_PRED_4x4 4 + +#define HOR_DOWN_PRED_4x4 5 +#define VERT_LEFT_PRED_4x4 6 +#define HOR_UP_PRED_4x4 7 +#define VERT_RIGHT_PRED_4x4 8 + +#define DC_PRED_8 0 +#define HOR_PRED_8 1 +#define VERT_PRED_8 2 +#define PLANE_8 3 + +#define LUMA_16DC 0 +#define LUMA_16AC 1 +#define LUMA_8x8 2 +#define LUMA_8x4 3 +#define LUMA_4x8 4 +#define LUMA_4x4 5 +#define CHROMA_DC 6 +#define CHROMA_AC 7 +#define NUM_BLOCK_TYPES 8 + +#define I_PICTURE_START_CODE 0xB3 +#define PB_PICTURE_START_CODE 0xB6 +#define SLICE_START_CODE_MIN 0x00 +#define SLICE_START_CODE_MAX 0xAF +#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 EOS 1 +#define SOP 2 +#define SOS 3 +#define P8x8 8 +#define I8MB 9 +#define I4MB 10 +#define IBLOCK 11 +#define SI4MB 12 +#define MAXMODE 13 + +#define IS_INTRA(MB) ((MB)->mb_type == I8MB || (MB)->mb_type == I4MB) +#define IS_NEWINTRA(MB) ((MB)->mb_type == I4MB) +#define IS_OLDINTRA(MB) ((MB)->mb_type == I8MB) +#define IS_INTER(MB) ((MB)->mb_type != I8MB && (MB)->mb_type != I4MB) +#define IS_INTERMV(MB) ((MB)->mb_type != I8MB && (MB)->mb_type != I4MB\ + && (MB)->mb_type != 0) + +#define IS_DIRECT(MB) ((MB)->mb_type == 0 && (img->type == B_IMG)) +#define IS_COPY(MB) ((MB)->mb_type == 0 && (img->type == P_IMG)) +#define IS_P8x8(MB) ((MB)->mb_type == P8x8) + +#define P_IMG 0 +#define B_IMG 1 +#define I_IMG 2 + +#define FIELD 0 +#define FRAME 1 + +#define SE_CABP 21 +struct decoding_environment_s { + unsigned int dbuffer; + int dbits_to_go; + unsigned char *dcodestrm; + int *dcodestrm_len; +}; + +struct bi_context_type_s { + unsigned char MPS; + unsigned int LG_PMPS; + unsigned char cycno; +}; + + +/********************************************************************** + * C O N T E X T S F O R R M S Y N T A X E L E M E N T S + ********************************************************************** + */ + +#define NUM_MB_TYPE_CTX 11 +#define NUM_B8_TYPE_CTX 9 +#define NUM_MV_RES_CTX 10 +#define NUM_REF_NO_CTX 6 +#define NUM_DELTA_QP_CTX 4 +#define NUM_MB_AFF_CTX 4 + +struct motion_info_contexts_s { + struct bi_context_type_s mb_type_contexts[4][NUM_MB_TYPE_CTX]; + struct bi_context_type_s b8_type_contexts[2][NUM_B8_TYPE_CTX]; + struct bi_context_type_s mv_res_contexts[2][NUM_MV_RES_CTX]; + struct bi_context_type_s ref_no_contexts[2][NUM_REF_NO_CTX]; + struct bi_context_type_s delta_qp_contexts[NUM_DELTA_QP_CTX]; + struct bi_context_type_s mb_aff_contexts[NUM_MB_AFF_CTX]; +#ifdef TEST_WEIGHTING_AEC +struct bi_context_type_s mb_weighting_pred; +#endif +}; + +#define NUM_IPR_CTX 2 +#define NUM_CIPR_CTX 4 +#define NUM_CBP_CTX 4 +#define NUM_BCBP_CTX 4 +#define NUM_MAP_CTX 16 +#define NUM_LAST_CTX 16 + +#define NUM_ONE_CTX 5 +#define NUM_ABS_CTX 5 + +struct texture_info_contexts { + struct bi_context_type_s ipr_contexts[NUM_IPR_CTX]; + struct bi_context_type_s cipr_contexts[NUM_CIPR_CTX]; + struct bi_context_type_s cbp_contexts[3][NUM_CBP_CTX]; + struct bi_context_type_s bcbp_contexts[NUM_BLOCK_TYPES][NUM_BCBP_CTX]; + struct bi_context_type_s one_contexts[NUM_BLOCK_TYPES][NUM_ONE_CTX]; + struct bi_context_type_s abs_contexts[NUM_BLOCK_TYPES][NUM_ABS_CTX]; + struct bi_context_type_s fld_map_contexts[NUM_BLOCK_TYPES][NUM_MAP_CTX]; + struct bi_context_type_s fld_last_contexts + [NUM_BLOCK_TYPES][NUM_LAST_CTX]; + struct bi_context_type_s map_contexts[NUM_BLOCK_TYPES][NUM_MAP_CTX]; + struct bi_context_type_s last_contexts[NUM_BLOCK_TYPES][NUM_LAST_CTX]; +}; +struct img_par; + +struct syntaxelement { + int type; + int value1; + int value2; + int len; + int inf; + unsigned int bitpattern; + int context; + int k; + int golomb_grad; + int golomb_maxlevels; +#if TRACE +#define TRACESTRING_SIZE 100 + char tracestring[TRACESTRING_SIZE]; +#endif + + void (*mapping)(int len, int info, int *value1, int *value2); + + void (*reading)(struct syntaxelement *, struct img_par *, + struct decoding_environment_s *); + +}; + +struct bitstream_s { + + int read_len; + int code_len; + + int frame_bitoffset; + int bitstream_length; + + unsigned char *stream_buffer; +}; + +struct datapartition { + + struct bitstream_s *bitstream; + struct decoding_environment_s de_aec; + + int (*read_syntax_element)(struct syntaxelement *, struct img_par *, + struct datapartition *); +/*!< virtual function; + * actual method depends on chosen data partition and + * entropy coding method + */ +}; + +struct slice_s { + int picture_id; + int qp; + int picture_type; + int start_mb_nr; + int max_part_nr; + int num_mb; + + struct datapartition *part_arr; + struct motion_info_contexts_s *mot_ctx; + struct texture_info_contexts *tex_ctx; + int field_ctx[3][2]; +}; + +struct img_par { + int number; + int current_mb_nr; + int max_mb_nr; + int current_slice_nr; + int tr; + int qp; + int type; + + int typeb; + + int width; + int height; + int width_cr; + int height_cr; + int source_bitdepth; + int mb_y; + int mb_x; + int block_y; + int pix_y; + int pix_x; + int pix_c_y; + int block_x; + int pix_c_x; + + int ***mv; + int mpr[16][16]; + + int m7[16][16]; + int m8[/*2*/4][8][8]; + int cof[4][/*6*/8][4][4]; + int cofu[4]; + int **ipredmode; + int quad[256]; + int cod_counter; + + int ***dfmv; + int ***dbmv; + int **fw_reffrarr; + int **bw_reffrarr; + + int ***mv_frm; + int **fw_reffrarr_frm; + int **bw_reffrarr_frm; + int imgtr_next_p; + int imgtr_last_p; + int tr_frm; + int tr_fld; + int imgtr_last_prev_p; + + int no_forward_reference; + int seq_header_indicate; + int b_discard_flag; + + int ***fw_mv; + int ***bw_mv; + int subblock_x; + int subblock_y; + + int buf_cycle; + + int direct_type; + + int ***mv_top; + int ***mv_bot; + int **fw_reffrarr_top; + int **bw_reffrarr_top; + int **fw_reffrarr_bot; + int **bw_reffrarr_bot; + + int **ipredmode_top; + int **ipredmode_bot; + int ***fw_mv_top; + int ***fw_mv_bot; + int ***bw_mv_top; + int ***bw_mv_bot; + int ***dfmv_top; + int ***dbmv_top; + int ***dfmv_bot; + int ***dbm_bot; + + int toppoc; + int bottompoc; + int framepoc; + unsigned int frame_num; + + unsigned int pic_distance; + int delta_pic_order_cnt_bottom; + + signed int pic_distance_msb; + unsigned int prev_pic_distance_lsb; + signed int curr_pic_distance_msb; + unsigned int this_poc; + + int pic_width_inmbs; + int pic_height_inmbs; + int pic_size_inmbs; + + int block8_x, block8_y; + int structure; + int pn; + int buf_used; + int buf_size; + int picture_structure; + int advanced_pred_mode_disable; + int types; + int current_mb_nr_fld; + + int p_field_enhanced; + int b_field_enhanced; + + int slice_weighting_flag; + int lum_scale[4]; + int lum_shift[4]; + int chroma_scale[4]; + int chroma_shift[4]; + int mb_weighting_flag; + int weighting_prediction; + int mpr_weight[16][16]; + int top_bot; + int bframe_number; + + int auto_crop_right; + int auto_crop_bottom; + + struct slice_s *current_slice; + int is_v_block; + int is_intra_block; + + int new_seq_header_flag; + int new_sequence_flag; + int last_pic_bbv_delay; + + int sequence_end_flag; + int is_top_field; + + int abt_flag; + int qp_shift; + +#ifdef EIGHTH +int eighth_subpixel_flag; +int subpixel_precision; +int unit_length; +int subpixel_mask; + +int max_mvd; +int min_mvd; +#endif + +}; + +struct macroblock { + int qp; + int slice_nr; + int delta_quant; + struct macroblock *mb_available[3][3]; + /*!< pointer to neighboring MBs in a 3x3 window of current MB, + *which is located at [1][1] + * NULL pointer identifies neighboring MBs which are unavailable + */ + + int mb_type; + int mvd[2][BLOCK_MULTIPLE][BLOCK_MULTIPLE][2]; + int cbp, cbp_blk, cbp01; + unsigned long cbp_bits; + + int b8mode[4]; + int b8pdir[4]; + int mb_type_2; + int c_ipred_mode_2; + int dct_mode; + + int c_ipred_mode; + int lf_disable; + int lf_alpha_c0_offset; + int lf_beta_offset; + + int CABT[4]; + int CABP[4]; + int cbp_4x4[4]; + + int skip_flag; + + struct macroblock *mb_available_up; + struct macroblock *mb_available_left; + unsigned int mbaddr_a, mbaddr_b, mbaddr_c, mbaddr_d; + unsigned int mbavail_a, mbavail_b, mbavail_c, mbavail_d; + +}; + +struct macroblock *mb_data; + +struct img_par *img; + +struct bitstream_s *curr_stream; + +struct datapartition *alloc_partition(int n); + +unsigned int vld_mem_start_addr; +unsigned int vld_mem_end_addr; + +int marker_bit; + +int progressive_sequence; +int horizontal_size; +int vertical_size; + +int second_ifield; +int pre_img_type; + +/* slice_header() */ +int slice_vertical_position; +int slice_vertical_position_extension; +int fixed_picture_qp; +int fixed_slice_qp; +int slice_qp; + +/* + ************************************************************************* + * Function:ue_v, reads an u(v) syntax element, the length in bits is stored in + the global UsedBits variable + * Input: + tracestring + the string for the trace file + bitstream + the stream to be read from + * Output: + * Return: the value of the coded syntax element + * Attention: + ************************************************************************* + */ +/*! + * definition of AVS syntaxelements + * order of elements follow dependencies for picture reconstruction + */ +/*! + * \brief Assignment of old TYPE partition elements to new + * elements + * + * old element | new elements + * TYPE_HEADER | SE_HEADER, SE_PTYPE + * TYPE_MBHEADER | SE_MBTYPE, SE_REFFRAME, SE_INTRAPREDMODE + * TYPE_MVD | SE_MVD + * TYPE_CBP | SE_CBP_INTRA, SE_CBP_INTER * SE_DELTA_QUANT_INTER + * SE_DELTA_QUANT_INTRA + * TYPE_COEFF_Y | SE_LUM_DC_INTRA, SE_LUM_AC_INTRA, + SE_LUM_DC_INTER, SE_LUM_AC_INTER + * TYPE_2x2DC | SE_CHR_DC_INTRA, SE_CHR_DC_INTER + * TYPE_COEFF_C | SE_CHR_AC_INTRA, SE_CHR_AC_INTER + * TYPE_EOS | SE_EOS + */ + +#define SE_HEADER 0 +#define SE_PTYPE 1 +#define SE_MBTYPE 2 +#define SE_REFFRAME 3 +#define SE_INTRAPREDMODE 4 +#define SE_MVD 5 +#define SE_CBP_INTRA 6 +#define SE_LUM_DC_INTRA 7 +#define SE_CHR_DC_INTRA 8 +#define SE_LUM_AC_INTRA 9 +#define SE_CHR_AC_INTRA 10 +#define SE_CBP_INTER 11 +#define SE_LUM_DC_INTER 12 +#define SE_CHR_DC_INTER 13 +#define SE_LUM_AC_INTER 14 +#define SE_CHR_AC_INTER 15 +#define SE_DELTA_QUANT_INTER 16 +#define SE_DELTA_QUANT_INTRA 17 +#define SE_BFRAME 18 +#define SE_EOS 19 +#define SE_MAX_ELEMENTS 20 +#define SE_CBP01 21 +int chroma_format; +/* + ************************************************************************* + * Function:Reads bits from the bitstream buffer + * Input: + byte buffer[] + containing VLC-coded data bits + int totbitoffset + bit offset from start of partition + int bytecount + total bytes in bitstream + int numbits + number of bits to read + * Output: + * Return: + * Attention: + ************************************************************************* + */ + +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; +} + +/* + ************************************************************************* + * Function:read FLC codeword from UVLC-partition + * Input: + * Output: + * Return: + * Attention: + ************************************************************************* + */ + +int read_syntaxelement_flc(struct syntaxelement *sym) +{ + int frame_bitoffset = curr_stream->frame_bitoffset; + unsigned char *buf = curr_stream->stream_buffer; + int bitstreamlengthinbytes = curr_stream->bitstream_length; + + if ((get_bits(buf, frame_bitoffset, &(sym->inf), bitstreamlengthinbytes, + sym->len)) < 0) + return -1; + + curr_stream->frame_bitoffset += sym->len; + sym->value1 = sym->inf; + +#if TRACE + tracebits2(sym->tracestring, sym->len, sym->inf); +#endif + + return 1; +} + +/* + ************************************************************************* + * Function:ue_v, reads an u(1) syntax element, the length in bits is stored in + the global UsedBits variable + * Input: + tracestring + the string for the trace file + bitstream + the stream to be read from + * Output: + * Return: the value of the coded syntax element + * Attention: + ************************************************************************* + */ +int u_1(char *tracestring) +{ + return u_v(1, tracestring); +} + +/* + ************************************************************************* + * Function:mapping rule for ue(v) syntax elements + * Input:length and info + * Output:number in the code table + * Return: + * Attention: + ************************************************************************* + */ +void linfo_ue(int len, int info, int *value1, int *dummy) +{ + *value1 = (int)pow2(2, (len / 2)) + info - 1; +} + +int u_v(int leninbits, char *tracestring) +{ + struct syntaxelement symbol, *sym = &symbol; + +#ifdef AVSP_LONG_CABAC +#else + assert(curr_stream->stream_buffer != NULL); +#endif + sym->type = SE_HEADER; + sym->mapping = linfo_ue; + sym->len = leninbits; + read_syntaxelement_flc(sym); + + return sym->inf; +} + +/* + ************************************************************************* + * Function:mapping rule for se(v) syntax elements + * Input:length and info + * Output:signed mvd + * Return: + * Attention: + ************************************************************************* + */ + +void linfo_se(int len, int info, int *value1, int *dummy) +{ + int n; + + n = (int)pow2(2, (len / 2)) + info - 1; + *value1 = (n + 1) / 2; + if ((n & 0x01) == 0) + *value1 = -*value1; + +} + +/* + ************************************************************************* + * Function:length and info + * Input: + * Output:cbp (intra) + * Return: + * Attention: + ************************************************************************* + */ + +void linfo_cbp_intra(int len, int info, int *cbp, int *dummy) +{ +} + +const int NCBP[64][2] = {{4, 0}, {16, 19}, {17, 16}, {19, 15}, {14, 18}, + {9, 11}, {22, 31}, {8, 13}, {11, 17}, {21, 30}, {10, 12}, + {7, 9}, {12, 10}, {6, 7}, {5, 8}, {1, 1}, {35, 4}, {47, 42}, { + 48, 38}, {38, 27}, {46, 39}, {36, 33}, {50, 59}, + {26, 26}, {45, 40}, {52, 58}, {41, 35}, {28, 25}, {37, 29}, {23, + 24}, {31, 28}, {2, 3}, {43, 5}, {51, 51}, {56, + 52}, {39, 37}, {55, 50}, {33, 43}, {62, 63}, { + 27, 44}, {54, 53}, {60, 62}, {40, 48}, {32, 47}, + {42, 34}, {24, 45}, {29, 49}, {3, 6}, {49, 14}, {53, 55}, {57, + 56}, {25, 36}, {58, 54}, {30, 41}, {59, 60}, { + 15, 21}, {61, 57}, {63, 61}, {44, 46}, {18, 22}, + {34, 32}, {13, 20}, {20, 23}, {0, 2} }; + +unsigned int s1, t1, value_s, value_t; +unsigned char dec_bypass, dec_final; + +#define get_byte() { \ + dbuffer = dcodestrm[(*dcodestrm_len)++];\ + dbits_to_go = 7; \ +} + +#define dbuffer (dep->dbuffer) +#define dbits_to_go (dep->dbits_to_go) +#define dcodestrm (dep->dcodestrm) +#define dcodestrm_len (dep->dcodestrm_len) + +#define B_BITS 10 + +#define LG_PMPS_SHIFTNO 2 + +#define HALF (1 << (B_BITS-1)) +#define QUARTER (1 << (B_BITS-2)) + +unsigned int biari_decode_symbol(struct decoding_environment_s *dep, + struct bi_context_type_s *bi_ct) +{ + register unsigned char bit; + register unsigned char s_flag; + register unsigned char is_lps = 0; + register unsigned char cwr; + register unsigned char cycno = bi_ct->cycno; + register unsigned int lg_pmps = bi_ct->LG_PMPS; + register unsigned int t_rlps; + register unsigned int s2, t2; + +#ifdef DUMP_DEBUG + if (avs_get_debug_flag() & AEC_DUMP) + io_printf("LG_PMPS : %03X, MPS : %d, cycno : %d -- %p\n", + bi_ct->LG_PMPS, bi_ct->MPS, bi_ct->cycno, bi_ct); +#endif + + bit = bi_ct->MPS; + + cwr = (cycno <= 1) ? 3 : (cycno == 2) ? 4 : 5; + + if (t1 >= (lg_pmps >> LG_PMPS_SHIFTNO)) { + s2 = s1; + t2 = t1 - (lg_pmps >> LG_PMPS_SHIFTNO); + s_flag = 0; + } else { + s2 = s1 + 1; + t2 = 256 + t1 - (lg_pmps >> LG_PMPS_SHIFTNO); + s_flag = 1; + } + +#ifdef DUMP_DEBUG + if (avs_get_debug_flag() & AEC_DUMP) + io_printf(" s2 : %d, t2 : %03X\n", s2, t2); +#endif + + if (s2 > value_s || (s2 == value_s && value_t >= t2)) { + is_lps = 1; + bit = !bit; + + t_rlps = (s_flag == 0) ? + (lg_pmps >> LG_PMPS_SHIFTNO) : + (t1 + (lg_pmps >> LG_PMPS_SHIFTNO)); + + if (s2 == value_s) + value_t = (value_t - t2); + else { + if (--dbits_to_go < 0) + get_byte(); + + value_t = (value_t << 1) + | ((dbuffer >> dbits_to_go) & 0x01); + value_t = 256 + value_t - t2; + + } + + while (t_rlps < QUARTER) { + t_rlps = t_rlps << 1; + if (--dbits_to_go < 0) + get_byte(); + + value_t = (value_t << 1) + | ((dbuffer >> dbits_to_go) & 0x01); + } + + s1 = 0; + t1 = t_rlps & 0xff; + + value_s = 0; + while (value_t < QUARTER) { + int j; + + if (--dbits_to_go < 0) + get_byte(); + j = (dbuffer >> dbits_to_go) & 0x01; + + value_t = (value_t << 1) | j; + value_s++; + } + value_t = value_t & 0xff; + } else { + + s1 = s2; + t1 = t2; + } + + if (dec_bypass) + return bit; + + if (is_lps) + cycno = (cycno <= 2) ? (cycno + 1) : 3; + else if (cycno == 0) + cycno = 1; + bi_ct->cycno = cycno; + + if (is_lps) { + switch (cwr) { + case 3: + lg_pmps = lg_pmps + 197; + break; + case 4: + lg_pmps = lg_pmps + 95; + break; + default: + lg_pmps = lg_pmps + 46; + } + + if (lg_pmps >= (256 << LG_PMPS_SHIFTNO)) { + lg_pmps = (512 << LG_PMPS_SHIFTNO) - 1 - lg_pmps; + bi_ct->MPS = !(bi_ct->MPS); + } + } else { +#ifdef DUMP_DEBUG + if (avs_get_debug_flag() & AEC_DUMP) + io_printf(" - lg_pmps_MPS : %X (%X - %X - %X)\n", + lg_pmps - (unsigned int)(lg_pmps>>cwr) + - (unsigned int)(lg_pmps>>(cwr+2)), + lg_pmps, + (unsigned int)(lg_pmps>>cwr), + (unsigned int)(lg_pmps>>(cwr+2)) + ); +#endif + lg_pmps = lg_pmps - (unsigned int)(lg_pmps >> cwr) + - (unsigned int)(lg_pmps >> (cwr + 2)); + } + + bi_ct->LG_PMPS = lg_pmps; + + return bit; +} + +unsigned int biari_decode_symbolw(struct decoding_environment_s *dep, + struct bi_context_type_s *bi_ct1, + struct bi_context_type_s *bi_ct2) +{ + register unsigned char bit1, bit2; + register unsigned char pred_mps, bit; + register unsigned int lg_pmps; + register unsigned char cwr1, cycno1 = bi_ct1->cycno; + register unsigned char cwr2, cycno2 = bi_ct2->cycno; + register unsigned int lg_pmps1 = bi_ct1->LG_PMPS; + register unsigned int lg_pmps2 = + bi_ct2->LG_PMPS; + register unsigned int t_rlps; + register unsigned char s_flag, is_lps = 0; + register unsigned int s2, t2; + + + bit1 = bi_ct1->MPS; + bit2 = bi_ct2->MPS; + + cwr1 = (cycno1 <= 1) ? 3 : (cycno1 == 2) ? 4 : 5; + cwr2 = (cycno2 <= 1) ? 3 : (cycno2 == 2) ? 4 : 5; + + if (bit1 == bit2) { + pred_mps = bit1; + lg_pmps = (lg_pmps1 + lg_pmps2) / 2; + } else { + if (lg_pmps1 < lg_pmps2) { + pred_mps = bit1; + lg_pmps = (256 << LG_PMPS_SHIFTNO) - 1 + - ((lg_pmps2 - lg_pmps1) >> 1); + } else { + pred_mps = bit2; + lg_pmps = (256 << LG_PMPS_SHIFTNO) - 1 + - ((lg_pmps1 - lg_pmps2) >> 1); + } + } + +#ifdef DUMP_DEBUG + if (avs_get_debug_flag() & AEC_DUMP) + io_printf(" - Begin - LG_PMPS : %03X, MPS : %d\n", + lg_pmps, pred_mps); +#endif + if (t1 >= (lg_pmps >> LG_PMPS_SHIFTNO)) { + s2 = s1; + t2 = t1 - (lg_pmps >> LG_PMPS_SHIFTNO); + s_flag = 0; + } else { + s2 = s1 + 1; + t2 = 256 + t1 - (lg_pmps >> LG_PMPS_SHIFTNO); + s_flag = 1; + } + + bit = pred_mps; + if (s2 > value_s || (s2 == value_s && value_t >= t2)) { + is_lps = 1; + bit = !bit; + t_rlps = (s_flag == 0) ? + (lg_pmps >> LG_PMPS_SHIFTNO) : + (t1 + (lg_pmps >> LG_PMPS_SHIFTNO)); + + if (s2 == value_s) + value_t = (value_t - t2); + else { + if (--dbits_to_go < 0) + get_byte(); + + value_t = (value_t << 1) + | ((dbuffer >> dbits_to_go) & 0x01); + value_t = 256 + value_t - t2; + } + + while (t_rlps < QUARTER) { + t_rlps = t_rlps << 1; + if (--dbits_to_go < 0) + get_byte(); + + value_t = (value_t << 1) + | ((dbuffer >> dbits_to_go) & 0x01); + } + s1 = 0; + t1 = t_rlps & 0xff; + + value_s = 0; + while (value_t < QUARTER) { + int j; + + if (--dbits_to_go < 0) + get_byte(); + j = (dbuffer >> dbits_to_go) & 0x01; + + value_t = (value_t << 1) | j; + value_s++; + } + value_t = value_t & 0xff; + } else { + s1 = s2; + t1 = t2; + } + + if (bit != bit1) { + cycno1 = (cycno1 <= 2) ? (cycno1 + 1) : 3; + } else { + if (cycno1 == 0) + cycno1 = 1; + } + + if (bit != bit2) { + cycno2 = (cycno2 <= 2) ? (cycno2 + 1) : 3; + } else { + if (cycno2 == 0) + cycno2 = 1; + } + bi_ct1->cycno = cycno1; + bi_ct2->cycno = cycno2; + + { + + if (bit == bit1) { + lg_pmps1 = + lg_pmps1 + - (unsigned int)(lg_pmps1 + >> cwr1) + - (unsigned int)(lg_pmps1 + >> (cwr1 + + 2)); + } else { + switch (cwr1) { + case 3: + lg_pmps1 = lg_pmps1 + 197; + break; + case 4: + lg_pmps1 = lg_pmps1 + 95; + break; + default: + lg_pmps1 = lg_pmps1 + 46; + } + + if (lg_pmps1 >= (256 << LG_PMPS_SHIFTNO)) { + lg_pmps1 = (512 << LG_PMPS_SHIFTNO) - 1 + - lg_pmps1; + bi_ct1->MPS = !(bi_ct1->MPS); + } + } + bi_ct1->LG_PMPS = lg_pmps1; + + if (bit == bit2) { + lg_pmps2 = + lg_pmps2 + - (unsigned int)(lg_pmps2 + >> cwr2) + - (unsigned int)(lg_pmps2 + >> (cwr2 + + 2)); + } else { + switch (cwr2) { + case 3: + lg_pmps2 = lg_pmps2 + 197; + break; + case 4: + lg_pmps2 = lg_pmps2 + 95; + break; + default: + lg_pmps2 = lg_pmps2 + 46; + } + + if (lg_pmps2 >= (256 << LG_PMPS_SHIFTNO)) { + lg_pmps2 = (512 << LG_PMPS_SHIFTNO) - 1 + - lg_pmps2; + bi_ct2->MPS = !(bi_ct2->MPS); + } + } + bi_ct2->LG_PMPS = lg_pmps2; + } + + + return bit; +} + +/*! + ************************************************************************ + * \brief + * biari_decode_symbol_eq_prob(): + * \return + * the decoded symbol + ************************************************************************ + */ +unsigned int biari_decode_symbol_eq_prob(struct decoding_environment_s *dep) +{ + unsigned char bit; + struct bi_context_type_s octx; + struct bi_context_type_s *ctx = &octx; + + ctx->LG_PMPS = (QUARTER << LG_PMPS_SHIFTNO) - 1; + ctx->MPS = 0; + ctx->cycno = 0xfe; + dec_bypass = 1; + bit = biari_decode_symbol(dep, ctx); + dec_bypass = 0; + return bit; +} + +unsigned int biari_decode_final(struct decoding_environment_s *dep) +{ + unsigned char bit; + struct bi_context_type_s octx; + struct bi_context_type_s *ctx = &octx; + + ctx->LG_PMPS = 1 << LG_PMPS_SHIFTNO; + ctx->MPS = 0; + ctx->cycno = 0xff; + dec_final = 1; + bit = biari_decode_symbol(dep, ctx); + dec_final = 0; + return bit; +} + +int i_8(char *tracestring) +{ + int frame_bitoffset = curr_stream->frame_bitoffset; + unsigned char *buf = curr_stream->stream_buffer; + int bitstreamlengthinbytes = curr_stream->bitstream_length; + struct syntaxelement symbol, *sym = &symbol; +#ifdef AVSP_LONG_CABAC +#else + assert(curr_stream->stream_buffer != NULL); +#endif + + sym->len = 8; + sym->type = SE_HEADER; + sym->mapping = linfo_ue; + + if ((get_bits(buf, frame_bitoffset, &(sym->inf), bitstreamlengthinbytes, + sym->len)) < 0) + return -1; + curr_stream->frame_bitoffset += sym->len; + sym->value1 = sym->inf; + if (sym->inf & 0x80) + sym->inf = -(~((int)0xffffff00 | sym->inf) + 1); +#if TRACE + tracebits2(sym->tracestring, sym->len, sym->inf); +#endif + return sym->inf; +} + +/*! + ************************************************************************ + * \brief + * arideco_bits_read + ************************************************************************ + */ +int arideco_bits_read(struct decoding_environment_s *dep) +{ + + return 8 * ((*dcodestrm_len) - 1) + (8 - dbits_to_go); +} + +/*! + ************************************************************************ + * \brief + * arithmetic decoding + ************************************************************************ + */ +int read_syntaxelement_aec(struct syntaxelement *se, struct img_par *img, + struct datapartition *this_data_part) +{ + int curr_len; + struct decoding_environment_s *dep_dp = &(this_data_part->de_aec); + + curr_len = arideco_bits_read(dep_dp); + + se->reading(se, img, dep_dp); + + se->len = (arideco_bits_read(dep_dp) - curr_len); + return se->len; +} + +/*! + ************************************************************************ + * \brief + * This function is used to arithmetically decode the + * run length info of the skip mb + ************************************************************************ + */ +void readrunlenghtfrombuffer_aec(struct syntaxelement *se, struct img_par *img, + struct decoding_environment_s *dep_dp) +{ + struct bi_context_type_s *pctx; + int ctx, symbol; + + pctx = img->current_slice->tex_ctx->one_contexts[0]; + symbol = 0; + ctx = 0; + while (biari_decode_symbol(dep_dp, pctx + ctx) == 0) { + symbol += 1; + ctx++; + if (ctx >= 3) + ctx = 3; + } + se->value1 = symbol; +#if TRACE + fprintf(p_trace, "@%d%s\t\t\t%d\n", + symbol_count++, se->tracestring, se->value1); + fflush(p_trace); +#endif +} + +/*! + ************************************************************************ + * \brief + * This function is used to arithmetically decode a pair of + * intra prediction modes of a given MB. + ************************************************************************ + */ +int mapd_intrap[5] = {0, 2, 3, 4, 1}; +void read_intrapredmode_aec(struct syntaxelement *se, struct img_par *img, + struct decoding_environment_s *dep_dp) +{ + struct bi_context_type_s *pctx; + int ctx, symbol; + + pctx = img->current_slice->tex_ctx->one_contexts[1]; + symbol = 0; + ctx = 0; +#ifdef DUMP_DEBUG + if (avs_get_debug_flag() & AEC_DUMP) + io_printf(" -- read_intrapredmode_aec ctx : %d\n", ctx); +#endif + while (biari_decode_symbol(dep_dp, pctx + ctx) == 0) { + symbol += 1; + ctx++; + if (ctx >= 3) + ctx = 3; +#ifdef DUMP_DEBUG + if (avs_get_debug_flag() & AEC_DUMP) + io_printf(" -- read_intrapredmode_aec ctx : %d\n", ctx); +#endif + if (symbol == 4) + break; + } + se->value1 = mapd_intrap[symbol] - 1; + +#if TRACE + fprintf(p_trace, "@%d %s\t\t\t%d\n", + symbol_count++, se->tracestring, se->value1); + fflush(p_trace); +#endif +} + +/*! + ************************************************************************ + * \brief + * decoding of unary binarization using one or 2 distinct + * models for the first and all remaining bins; no terminating + * "0" for max_symbol + *********************************************************************** + */ +unsigned int unary_bin_max_decode(struct decoding_environment_s *dep_dp, + struct bi_context_type_s *ctx, + int ctx_offset, unsigned int max_symbol) +{ + unsigned int l; + unsigned int symbol; + struct bi_context_type_s *ictx; + + symbol = biari_decode_symbol(dep_dp, ctx); + + if (symbol == 0) + return 0; + + if (max_symbol == 1) + return symbol; + symbol = 0; + ictx = ctx + ctx_offset; + do { + l = biari_decode_symbol(dep_dp, ictx); + symbol++; + } while ((l != 0) && (symbol < max_symbol - 1)); + if ((l != 0) && (symbol == max_symbol - 1)) + symbol++; + return symbol; +} + +/*! + ************************************************************************ + * \brief + * decoding of unary binarization using one or 2 distinct + * models for the first and all remaining bins + *********************************************************************** + */ +unsigned int unary_bin_decode(struct decoding_environment_s *dep_dp, + struct bi_context_type_s *ctx, int ctx_offset) +{ + unsigned int l; + unsigned int symbol; + struct bi_context_type_s *ictx; + + symbol = 1 - biari_decode_symbol(dep_dp, ctx); + + if (symbol == 0) + return 0; + symbol = 0; + ictx = ctx + ctx_offset; + do { + l = 1 - biari_decode_symbol(dep_dp, ictx); + symbol++; + } while (l != 0); + return symbol; +} + +/*! + ************************************************************************ + * \brief + * This function is used to arithmetically decode the chroma + * intra prediction mode of a given MB. + ************************************************************************ + */ +void read_cipredmode_aec(struct syntaxelement *se, + struct img_par *img, + struct decoding_environment_s *dep_dp) +{ + struct texture_info_contexts *ctx = img->current_slice->tex_ctx; + struct macroblock *curr_mb = &mb_data[img->current_mb_nr]; + int act_ctx, a, b; + int act_sym = se->value1; + + if (curr_mb->mb_available_up == NULL) + b = 0; + else { + /*if ( (curr_mb->mb_available_up)->mb_type==IPCM) + * b=0; + * else + */ + b = (((curr_mb->mb_available_up)->c_ipred_mode != 0) ? 1 : 0); + } + + if (curr_mb->mb_available_left == NULL) + a = 0; + else { + /* if ( (curr_mb->mb_available_left)->mb_type==IPCM) + * a=0; + * else + */ + a = (((curr_mb->mb_available_left)->c_ipred_mode != 0) ? 1 : 0); + } + + act_ctx = a + b; + + + act_sym = biari_decode_symbol(dep_dp, ctx->cipr_contexts + act_ctx); + + if (act_sym != 0) + act_sym = unary_bin_max_decode(dep_dp, ctx->cipr_contexts + 3, + 0, 2) + 1; + + se->value1 = act_sym; + +#if TRACE + fprintf(p_trace, "@%d %s\t\t%d\n", + symbol_count++, se->tracestring, se->value1); + fflush(p_trace); +#endif + +} + +int slice_header(char *buf, int startcodepos, int length) +{ + int i; + + int weight_para_num = 0; + int mb_row; + int mb_column; + int mb_index; + int mb_width, mb_height; + + mb_column = 0; + + memcpy(curr_stream->stream_buffer, buf, length); + curr_stream->code_len = curr_stream->bitstream_length = length; + + curr_stream->read_len = + curr_stream->frame_bitoffset = (startcodepos) * 8; + slice_vertical_position = u_v(8, "slice vertical position"); + + push_es(slice_vertical_position, 8); + +#ifdef DUMP_DEBUG + if (avs_get_debug_flag() & SLICE_INFO_DUMP) + io_printf(" * 8-bits slice_vertical_position : %d\n", + slice_vertical_position); +#endif + + if (vertical_size > 2800) { + slice_vertical_position_extension = u_v(3, + "slice vertical position extension"); + push_es(slice_vertical_position_extension, 3); + + } + + if (vertical_size > 2800) + mb_row = (slice_vertical_position_extension << 7) + + slice_vertical_position; + else + mb_row = slice_vertical_position; + + mb_width = (horizontal_size + 15) / 16; + if (!progressive_sequence) + mb_height = 2 * ((vertical_size + 31) / 32); + else + mb_height = (vertical_size + 15) / 16; + + + mb_index = mb_row * mb_width + mb_column; + + if (!img->picture_structure && img->type == I_IMG + && (mb_index >= mb_width * mb_height / 2)) { + second_ifield = 1; + img->type = P_IMG; + pre_img_type = P_IMG; + } + + { + if (!fixed_picture_qp) { + fixed_slice_qp = u_v(1, "fixed_slice_qp"); + push_es(fixed_slice_qp, 1); +#ifdef DUMP_DEBUG + if (avs_get_debug_flag() & SLICE_INFO_DUMP) + io_printf(" * 1-bit fixed_slice_qp : %d\n", + fixed_slice_qp); +#endif + slice_qp = u_v(6, "slice_qp"); + push_es(slice_qp, 6); +#ifdef DUMP_DEBUG + if (avs_get_debug_flag() & SLICE_INFO_DUMP) + io_printf(" * 6-bits slice_qp : %d\n", + slice_qp); +#endif + + img->qp = slice_qp; + } + + if (img->type != I_IMG) { + img->slice_weighting_flag = u_v(1, + "slice weighting flag"); + + if (img->slice_weighting_flag) { + + if (second_ifield && !img->picture_structure) + weight_para_num = 1; + else if (img->type == P_IMG + && img->picture_structure) + weight_para_num = 2; + else if (img->type == P_IMG + && !img->picture_structure) + weight_para_num = 4; + else if (img->type == B_IMG + && img->picture_structure) + weight_para_num = 2; + else if (img->type == B_IMG + && !img->picture_structure) + weight_para_num = 4; + +#ifdef DUMP_DEBUG + if (avs_get_debug_flag() & SLICE_INFO_DUMP) + io_printf(" - weight_para_num : %d\n", + weight_para_num); +#endif + for (i = 0; i < weight_para_num; i++) { + img->lum_scale[i] = u_v(8, + "luma scale"); + + img->lum_shift[i] = i_8("luma shift"); + + marker_bit = u_1("insert bit"); + + + { + img->chroma_scale[i] = u_v(8, + "chroma scale"); + + img->chroma_shift[i] = i_8( + "chroma shift"); + + marker_bit = u_1("insert bit"); + + } + } + img->mb_weighting_flag = u_v(1, + "MB weighting flag"); + + } + } + } + + +#if 1 + return mb_index; +#endif +} + +void no_mem_exit(char *where) +{ + io_printf("%s\r\n", where); +} + +unsigned char bit[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; + +struct inputstream_s { + /*FILE *f;*/ + unsigned char buf[SVA_STREAM_BUF_SIZE]; + unsigned int uclear_bits; + unsigned int upre_3bytes; + int ibyte_position; + int ibuf_bytesnum; + int iclear_bitsnum; + int istuff_bitsnum; + int ibits_count; +}; + +struct inputstream_s IRABS; +struct inputstream_s *p_irabs = &IRABS; + +struct stat_bits { + int curr_frame_bits; + int prev_frame_bits; + int emulate_bits; + int prev_emulate_bits; + int last_unit_bits; + int bitrate; + int total_bitrate[1000]; + int coded_pic_num; + int time_s; +}; + +struct stat_bits *stat_bits_ptr; + +unsigned char *temp_slice_buf; +int start_codeposition; +int first_slice_length; +int first_slice_startpos; + +int bitstream_buf_used; +int startcode_offset; + +int bitstream_read_ptr; + +int demulate_enable; + +int last_dquant; + +int total_mb_count; + +int current_mb_skip; + +int skip_mode_flag; + +int current_mb_intra; + +/* + ************************************************************************* + * Function: Check start code's type + * Input: + * Output: + * Return: + * Author: XZHENG, 20080515 + ************************************************************************* + */ +void check_type(int startcode) +{ + startcode = startcode & 0x000000ff; + switch (startcode) { + case 0xb0: + case 0xb2: + case 0xb5: + demulate_enable = 0; + break; + default: + demulate_enable = 1; + break; + } + +} +/* + ************************************************************************* + * Function: + * Input: + * Output: + * Return: 0 : OK + -1 : arrive at stream end + -2 : meet another start code + * Attention: + ************************************************************************* + */ +int clear_nextbyte(struct inputstream_s *p) +{ + int i, k, j; + unsigned char temp[3]; + + i = p->ibyte_position; + k = p->ibuf_bytesnum - i; + if (k < 3) { + for (j = 0; j < k; j++) + temp[j] = p->buf[i + j]; + + p->ibuf_bytesnum = read_bitstream(p->buf + k, + SVA_STREAM_BUF_SIZE - k); + bitstream_buf_used++; + if (p->ibuf_bytesnum == 0) { + if (k > 0) { + while (k > 0) { + p->upre_3bytes = ((p->upre_3bytes << 8) + | p->buf[i]) + & 0x00ffffff; + if (p->upre_3bytes < 4 + && demulate_enable) { + p->uclear_bits = + (p->uclear_bits + << 6) + | (p->buf[i] + >> 2); + p->iclear_bitsnum += 6; + stat_bits_ptr->emulate_bits + += 2; + } else { + p->uclear_bits = (p->uclear_bits + << 8) + | p->buf[i]; + p->iclear_bitsnum += 8; + } + p->ibyte_position++; + k--; + i++; + } + return 0; + } else { + return -1; + } + } else { + for (j = 0; j < k; j++) + p->buf[j] = temp[j]; + p->ibuf_bytesnum += k; + i = p->ibyte_position = 0; + } + } + if (p->buf[i] == 0 && p->buf[i + 1] == 0 && p->buf[i + 2] == 1) + return -2; + p->upre_3bytes = ((p->upre_3bytes << 8) | p->buf[i]) & 0x00ffffff; + if (p->upre_3bytes < 4 && demulate_enable) { + p->uclear_bits = (p->uclear_bits << 6) | (p->buf[i] >> 2); + p->iclear_bitsnum += 6; + stat_bits_ptr->emulate_bits += 2; + } else { + p->uclear_bits = (p->uclear_bits << 8) | p->buf[i]; + p->iclear_bitsnum += 8; + } + p->ibyte_position++; + return 0; +} + +/* + ************************************************************************* + * Function: + * Input: + * Output: + * Return: 0 : OK + -1 : arrive at stream end + -2 : meet another start code + * Attention: + ************************************************************************* + */ +int read_n_bit(struct inputstream_s *p, int n, int *v) +{ + int r; + unsigned int t; + + while (n > p->iclear_bitsnum) { + r = clear_nextbyte(p); + if (r) { + if (r == -1) { + if (p->ibuf_bytesnum - p->ibyte_position > 0) + break; + } + return r; + } + } + t = p->uclear_bits; + r = 32 - p->iclear_bitsnum; + *v = (t << r) >> (32 - n); + p->iclear_bitsnum -= n; + return 0; +} + +#ifdef AVSP_LONG_CABAC +unsigned char TMP_BUF[2 * SVA_STREAM_BUF_SIZE]; +int tmp_buf_wr_ptr; +int tmp_buf_rd_ptr; +int tmp_buf_count; +#endif +void open_irabs(struct inputstream_s *p) +{ + p->uclear_bits = 0xffffffff; + p->ibyte_position = 0; + p->ibuf_bytesnum = 0; + p->iclear_bitsnum = 0; + p->istuff_bitsnum = 0; + p->ibits_count = 0; + p->upre_3bytes = 0; + + bitstream_buf_used = 0; + bitstream_read_ptr = (src_start - 16) & 0xfffffff0; + +#ifdef AVSP_LONG_CABAC + tmp_buf_count = 0; + tmp_buf_wr_ptr = 0; + tmp_buf_rd_ptr = 0; +#endif + +} + +void move_bitstream(unsigned int move_from_addr, unsigned int move_to_addr, + int move_size) +{ + int move_bytes_left = move_size; + unsigned int move_read_addr; + unsigned int move_write_addr = move_to_addr; + + int move_byte; + unsigned int data32; + + while (move_from_addr > vld_mem_end_addr) { + move_from_addr = move_from_addr + vld_mem_start_addr + - vld_mem_end_addr - 8; + } + move_read_addr = move_from_addr; + while (move_bytes_left > 0) { + move_byte = move_bytes_left; + if (move_byte > 512) + move_byte = 512; + if ((move_read_addr + move_byte) > vld_mem_end_addr) + move_byte = (vld_mem_end_addr + 8) - move_read_addr; + + WRITE_VREG(LMEM_DMA_ADR, move_read_addr); + WRITE_VREG(LMEM_DMA_COUNT, move_byte / 2); + WRITE_VREG(LMEM_DMA_CTRL, 0xc200); + + data32 = 0x8000; + while (data32 & 0x8000) + data32 = READ_VREG(LMEM_DMA_CTRL); + + WRITE_VREG(LMEM_DMA_ADR, move_write_addr); + WRITE_VREG(LMEM_DMA_COUNT, move_byte / 2); + WRITE_VREG(LMEM_DMA_CTRL, 0x8200); + + data32 = 0x8000; + while (data32 & 0x8000) + data32 = READ_VREG(LMEM_DMA_CTRL); + + data32 = 0x0fff; + while (data32 & 0x0fff) + data32 = READ_VREG(WRRSP_LMEM); + +#ifdef DUMP_DEBUG + if (avs_get_debug_flag() & STREAM_INFO_DUMP) + io_printf(" 2 MOVE %d Bytes from 0x%x to 0x%x\n", + move_byte, move_read_addr, move_write_addr); +#endif + + move_read_addr = move_read_addr + move_byte; + if (move_read_addr > vld_mem_end_addr) + move_read_addr = vld_mem_start_addr; + move_write_addr = move_write_addr + move_byte; + move_bytes_left = move_bytes_left - move_byte; + } + +} + +int read_bitstream(unsigned char *buf, int size) +{ + int i; + +#ifdef AVSP_LONG_CABAC + + unsigned int *TMP_BUF_32 = (unsigned int *)bitstream_read_tmp; + + if (tmp_buf_count < size) { + dma_sync_single_for_cpu(amports_get_dma_device(), + bitstream_read_tmp_phy, SVA_STREAM_BUF_SIZE, + DMA_FROM_DEVICE); + + move_bitstream(bitstream_read_ptr, bitstream_read_tmp_phy, + SVA_STREAM_BUF_SIZE); + + for (i = 0; i < SVA_STREAM_BUF_SIZE / 8; i++) { + TMP_BUF[tmp_buf_wr_ptr++] = + (TMP_BUF_32[2 * i + 1] >> 24) & 0xff; + if (tmp_buf_wr_ptr >= (2 * SVA_STREAM_BUF_SIZE)) + tmp_buf_wr_ptr = 0; + TMP_BUF[tmp_buf_wr_ptr++] = + (TMP_BUF_32[2 * i + 1] >> 16) & 0xff; + if (tmp_buf_wr_ptr >= (2 * SVA_STREAM_BUF_SIZE)) + tmp_buf_wr_ptr = 0; + TMP_BUF[tmp_buf_wr_ptr++] = (TMP_BUF_32[2 * i + 1] >> 8) + & 0xff; + if (tmp_buf_wr_ptr >= (2 * SVA_STREAM_BUF_SIZE)) + tmp_buf_wr_ptr = 0; + TMP_BUF[tmp_buf_wr_ptr++] = (TMP_BUF_32[2 * i + 1] >> 0) + & 0xff; + if (tmp_buf_wr_ptr >= (2 * SVA_STREAM_BUF_SIZE)) + tmp_buf_wr_ptr = 0; + TMP_BUF[tmp_buf_wr_ptr++] = + (TMP_BUF_32[2 * i + 0] >> 24) & 0xff; + if (tmp_buf_wr_ptr >= (2 * SVA_STREAM_BUF_SIZE)) + tmp_buf_wr_ptr = 0; + TMP_BUF[tmp_buf_wr_ptr++] = + (TMP_BUF_32[2 * i + 0] >> 16) & 0xff; + if (tmp_buf_wr_ptr >= (2 * SVA_STREAM_BUF_SIZE)) + tmp_buf_wr_ptr = 0; + TMP_BUF[tmp_buf_wr_ptr++] = (TMP_BUF_32[2 * i + 0] >> 8) + & 0xff; + if (tmp_buf_wr_ptr >= (2 * SVA_STREAM_BUF_SIZE)) + tmp_buf_wr_ptr = 0; + TMP_BUF[tmp_buf_wr_ptr++] = (TMP_BUF_32[2 * i + 0] >> 0) + & 0xff; + if (tmp_buf_wr_ptr >= (2 * SVA_STREAM_BUF_SIZE)) + tmp_buf_wr_ptr = 0; + } + tmp_buf_count = tmp_buf_count + SVA_STREAM_BUF_SIZE; + bitstream_read_ptr = bitstream_read_ptr + SVA_STREAM_BUF_SIZE; + } + +#ifdef DUMP_DEBUG + if (avs_get_debug_flag() & STREAM_INFO_DUMP) + io_printf(" Read %d bytes from %d, size left : %d\n", + size, tmp_buf_rd_ptr, tmp_buf_count); +#endif + for (i = 0; i < size; i++) { + buf[i] = TMP_BUF[tmp_buf_rd_ptr++]; + if (tmp_buf_rd_ptr >= (2 * SVA_STREAM_BUF_SIZE)) + tmp_buf_rd_ptr = 0; + } + tmp_buf_count = tmp_buf_count - size; + +#else + for (i = 0; i < size; i++) + buf[i] = tmp_stream[bitstream_read_ptr + i]; + bitstream_read_ptr = bitstream_read_ptr + size; +#endif + + return size; +} + +int next_startcode(struct inputstream_s *p) +{ + int i, m; + unsigned char a = 0, b = 0; + + m = 0; + + while (1) { + if (p->ibyte_position >= p->ibuf_bytesnum - 2) { + m = p->ibuf_bytesnum - p->ibyte_position; + if (m < 0) + return -2; + if (m == 1) + b = p->buf[p->ibyte_position + 1]; + if (m == 2) { + b = p->buf[p->ibyte_position + 1]; + a = p->buf[p->ibyte_position]; + } + p->ibuf_bytesnum = read_bitstream(p->buf, + SVA_STREAM_BUF_SIZE); + p->ibyte_position = 0; + bitstream_buf_used++; + } + + if (p->ibuf_bytesnum + m < 3) + return -1; + + if (m == 1 && b == 0 && p->buf[0] == 0 && p->buf[1] == 1) { + p->ibyte_position = 2; + p->iclear_bitsnum = 0; + p->istuff_bitsnum = 0; + p->ibits_count += 24; + p->upre_3bytes = 1; + return 0; + } + + if (m == 2 && b == 0 && a == 0 && p->buf[0] == 1) { + p->ibyte_position = 1; + p->iclear_bitsnum = 0; + p->istuff_bitsnum = 0; + p->ibits_count += 24; + p->upre_3bytes = 1; + return 0; + } + + if (m == 2 && b == 0 && p->buf[0] == 0 && p->buf[1] == 1) { + p->ibyte_position = 2; + p->iclear_bitsnum = 0; + p->istuff_bitsnum = 0; + p->ibits_count += 24; + p->upre_3bytes = 1; + return 0; + } + + for (i = p->ibyte_position; i < p->ibuf_bytesnum - 2; i++) { + if (p->buf[i] == 0 && p->buf[i + 1] == 0 + && p->buf[i + 2] == 1) { + p->ibyte_position = i + 3; + p->iclear_bitsnum = 0; + p->istuff_bitsnum = 0; + p->ibits_count += 24; + p->upre_3bytes = 1; + return 0; + } + p->ibits_count += 8; + } + p->ibyte_position = i; + } +} + +int get_oneunit(char *buf, int *startcodepos, int *length) +{ + int i, j, k; + + i = next_startcode(p_irabs); + + if (i != 0) { + if (i == -1) + io_printf( + "\narrive at stream end and start code is not found!"); + if (i == -2) + io_printf("\np->ibyte_position error!"); + + } + startcode_offset = + p_irabs->ibyte_position + - 3 + (bitstream_buf_used-1) + * SVA_STREAM_BUF_SIZE; + buf[0] = 0; + buf[1] = 0; + buf[2] = 1; + *startcodepos = 3; + i = read_n_bit(p_irabs, 8, &j); + buf[3] = (char)j; + + check_type(buf[3]); + if (buf[3] == SEQUENCE_END_CODE) { + *length = 4; + return -1; + } + k = 4; + while (1) { + i = read_n_bit(p_irabs, 8, &j); + if (i < 0) + break; + buf[k++] = (char)j; + if (k >= (MAX_CODED_FRAME_SIZE - 1)) + break; + } + if (p_irabs->iclear_bitsnum > 0) { + int shift; + + shift = 8 - p_irabs->iclear_bitsnum; + i = read_n_bit(p_irabs, p_irabs->iclear_bitsnum, &j); + + if (j != 0) + buf[k++] = (char)(j << shift); + stat_bits_ptr->last_unit_bits += shift; + } + *length = k; + return k; +} + +/*unsigned char tmp_buf[MAX_CODED_FRAME_SIZE] __attribute__ ((aligned(64)));*/ +/*unsigned char tmp_buf[MAX_CODED_FRAME_SIZE] __aligned(64);*/ +int header(void) +{ + unsigned char *buf; + int startcodepos, length; + + unsigned char *tmp_buf; + + tmp_buf = (unsigned char *)avsp_heap_adr; + + buf = &tmp_buf[0]; + while (1) { + start_codeposition = get_oneunit(buf, &startcodepos, &length); + + switch (buf[startcodepos]) { + case SEQUENCE_HEADER_CODE: + io_printf( + "# SEQUENCE_HEADER_CODE (0x%02x) found at offset %d (0x%x)\n", + buf[startcodepos], startcode_offset, + startcode_offset); + break; + case EXTENSION_START_CODE: + io_printf( + "# EXTENSION_START_CODE (0x%02x) found at offset %d (0x%x)\n", + buf[startcodepos], startcode_offset, + startcode_offset); + break; + case USER_DATA_START_CODE: + io_printf( + "# USER_DATA_START_CODE (0x%02x) found at offset %d (0x%x)\n", + buf[startcodepos], startcode_offset, + startcode_offset); + break; + case VIDEO_EDIT_CODE: + io_printf( + "# VIDEO_EDIT_CODE (0x%02x) found at offset %d (0x%x)\n", + buf[startcodepos], startcode_offset, + startcode_offset); + break; + case I_PICTURE_START_CODE: + io_printf( + "# I_PICTURE_START_CODE (0x%02x) found at offset %d (0x%x)\n", + buf[startcodepos], startcode_offset, + startcode_offset); + break; + case PB_PICTURE_START_CODE: + io_printf( + "# PB_PICTURE_START_CODE (0x%02x) found at offset %d (0x%x)\n", + buf[startcodepos], startcode_offset, + startcode_offset); + break; + case SEQUENCE_END_CODE: + io_printf( + "# SEQUENCE_END_CODE (0x%02x) found at offset %d (0x%x)\n", + buf[startcodepos], startcode_offset, + startcode_offset); + break; + default: + io_printf( + "# SLICE_START_CODE (0x%02x) found at offset %d (0x%x)\n", + buf[startcodepos], startcode_offset, + startcode_offset); +#if 0 + io_printf("VLD_MEM_VIFIFO_START_PTR %x\r\n", + READ_VREG(VLD_MEM_VIFIFO_START_PTR)); + io_printf("VLD_MEM_VIFIFO_CURR_PTR %x\r\n", + READ_VREG(VLD_MEM_VIFIFO_CURR_PTR)); + io_printf("VLD_MEM_VIFIFO_END_PTR %x\r\n", + READ_VREG(VLD_MEM_VIFIFO_END_PTR)); + io_printf("VLD_MEM_VIFIFO_WP %x\r\n" + READ_VREG(VLD_MEM_VIFIFO_WP)); + io_printf("VLD_MEM_VIFIFO_RP %x\r\n", + READ_VREG(VLD_MEM_VIFIFO_RP)); + io_printf("VLD_MEM_VBUF_RD_PTR %x\r\n" + READ_VREG(VLD_MEM_VBUF_RD_PTR)); + io_printf("VLD_MEM_VIFIFO_BUF_CNTL %x\r\n", + READ_VREG(VLD_MEM_VIFIFO_BUF_CNTL)); + io_printf("PARSER_VIDEO_HOLE %x\r\n", + READ_MPEG_REG(PARSER_VIDEO_HOLE)); +#endif + if ((buf[startcodepos] >= SLICE_START_CODE_MIN + && buf[startcodepos] + <= SLICE_START_CODE_MAX) + && ((!img->seq_header_indicate) + || (img->type == B_IMG + && img->b_discard_flag + == 1 + && !img->no_forward_reference))) { + break; + } else if (buf[startcodepos] >= SLICE_START_CODE_MIN) { + + first_slice_length = length; + first_slice_startpos = startcodepos; + + temp_slice_buf = &tmp_buf[0]; + return SOP; + } else { + io_printf("Can't find start code"); + return -EOS; + } + } + } + +} + +/* + ************************************************************************* + * Function:Allocates a Bitstream + * Input: + * Output:allocated Bitstream point + * Return: + * Attention: + ************************************************************************* + */ +struct bitstream_s *alloc_bitstream(void) +{ + struct bitstream_s *bitstream; + + bitstream = (struct bitstream_s *)local_alloc(1, + sizeof(struct bitstream_s)); + if (bitstream == NULL) { + io_printf( + "AllocBitstream: Memory allocation for Bitstream failed"); + return NULL; + } + bitstream->stream_buffer = (unsigned char *)local_alloc( + MAX_CODED_FRAME_SIZE, + sizeof(unsigned char)); + if (bitstream->stream_buffer == NULL) { + io_printf( + "AllocBitstream: Memory allocation for streamBuffer failed"); + return NULL; + } + + return bitstream; +} + +void biari_init_context_logac(struct bi_context_type_s *ctx) +{ + ctx->LG_PMPS = (QUARTER << LG_PMPS_SHIFTNO) - 1; + ctx->MPS = 0; + ctx->cycno = 0; +} + +#define BIARI_CTX_INIT1_LOG(jj, ctx)\ +{\ + for (j = 0; j < jj; j++)\ + biari_init_context_logac(&(ctx[j]));\ +} + +#define BIARI_CTX_INIT2_LOG(ii, jj, ctx)\ +{\ + for (i = 0; i < ii; i++)\ + for (j = 0; j < jj; j++)\ + biari_init_context_logac(&(ctx[i][j]));\ +} + +#define BIARI_CTX_INIT3_LOG(ii, jj, kk, ctx)\ +{\ + for (i = 0; i < ii; i++)\ + for (j = 0; j < jj; j++)\ + for (k = 0; k < kk; k++)\ + biari_init_context_logac(&(ctx[i][j][k]));\ +} + +#define BIARI_CTX_INIT4_LOG(ii, jj, kk, ll, ctx)\ +{\ + for (i = 0; i < ii; i++)\ + for (j = 0; j < jj; j++)\ + for (k = 0; k < kk; k++)\ + for (l = 0; l < ll; l++)\ + biari_init_context_logac\ + (&(ctx[i][j][k][l]));\ +} + +void init_contexts(struct img_par *img) +{ + struct motion_info_contexts_s *mc = img->current_slice->mot_ctx; + struct texture_info_contexts *tc = img->current_slice->tex_ctx; + int i, j; + +#ifdef DUMP_DEBUG + if (avs_get_debug_flag() & SLICE_INFO_DUMP) + io_printf(" ---- init_contexts ----\n"); +#endif + + BIARI_CTX_INIT2_LOG(3, NUM_MB_TYPE_CTX, mc->mb_type_contexts); + BIARI_CTX_INIT2_LOG(2, NUM_B8_TYPE_CTX, mc->b8_type_contexts); + BIARI_CTX_INIT2_LOG(2, NUM_MV_RES_CTX, mc->mv_res_contexts); + BIARI_CTX_INIT2_LOG(2, NUM_REF_NO_CTX, mc->ref_no_contexts); + BIARI_CTX_INIT1_LOG(NUM_DELTA_QP_CTX, mc->delta_qp_contexts); + BIARI_CTX_INIT1_LOG(NUM_MB_AFF_CTX, mc->mb_aff_contexts); + + BIARI_CTX_INIT1_LOG(NUM_IPR_CTX, tc->ipr_contexts); + BIARI_CTX_INIT1_LOG(NUM_CIPR_CTX, tc->cipr_contexts); + BIARI_CTX_INIT2_LOG(3, NUM_CBP_CTX, tc->cbp_contexts); + BIARI_CTX_INIT2_LOG(NUM_BLOCK_TYPES, NUM_BCBP_CTX, tc->bcbp_contexts); + BIARI_CTX_INIT2_LOG(NUM_BLOCK_TYPES, NUM_ONE_CTX, tc->one_contexts); + BIARI_CTX_INIT2_LOG(NUM_BLOCK_TYPES, NUM_ABS_CTX, tc->abs_contexts); + BIARI_CTX_INIT2_LOG(NUM_BLOCK_TYPES, NUM_MAP_CTX, tc->fld_map_contexts); + BIARI_CTX_INIT2_LOG(NUM_BLOCK_TYPES, NUM_LAST_CTX, + tc->fld_last_contexts); + BIARI_CTX_INIT2_LOG(NUM_BLOCK_TYPES, NUM_MAP_CTX, tc->map_contexts); + BIARI_CTX_INIT2_LOG(NUM_BLOCK_TYPES, NUM_LAST_CTX, tc->last_contexts); +#ifdef TEST_WEIGHTING_AEC + biari_init_context_logac(&mc->mb_weighting_pred); +#endif +} + +/*! + ************************************************************************ + * \brief + * Allocation of contexts models for the motion info + * used for arithmetic decoding + * + ************************************************************************ + */ +struct motion_info_contexts_s *create_contexts_motioninfo(void) +{ + struct motion_info_contexts_s *deco_ctx; + + deco_ctx = (struct motion_info_contexts_s *)local_alloc(1, + sizeof(struct motion_info_contexts_s)); + if (deco_ctx == NULL) + no_mem_exit("create_contexts_motioninfo: deco_ctx"); + + return deco_ctx; +} + +/*! + ************************************************************************ + * \brief + * Allocates of contexts models for the texture info + * used for arithmetic decoding + ************************************************************************ + */ +struct texture_info_contexts *create_contexts_textureinfo(void) +{ + struct texture_info_contexts *deco_ctx; + + deco_ctx = (struct texture_info_contexts *)local_alloc(1, + sizeof(struct texture_info_contexts)); + if (deco_ctx == NULL) + no_mem_exit("create_contexts_textureinfo: deco_ctx"); + + return deco_ctx; +} + +struct datapartition *alloc_partition(int n) +{ + struct datapartition *part_arr, *datapart; + int i; + + part_arr = + (struct datapartition *)local_alloc(n, sizeof(struct datapartition)); + if (part_arr == NULL) { + no_mem_exit( + "alloc_partition: Memory allocation for Data Partition failed"); + return NULL; + } + +#if LIWR_FIX + part_arr[0].bitstream = NULL; +#else + for (i = 0; i < n; i++) { + datapart = &(part_arr[i]); + datapart->bitstream = (struct bitstream_s *)local_alloc(1, + sizeof(struct bitstream_s)); + if (datapart->bitstream == NULL) { + no_mem_exit( + "alloc_partition: Memory allocation for Bitstream failed"); + return NULL; + } + } +#endif + return part_arr; +} + +int malloc_slice(struct img_par *img) +{ + struct slice_s *currslice; + + img->current_slice = + (struct slice_s *)local_alloc(1, sizeof(struct slice_s)); + currslice = img->current_slice; + if (currslice == NULL) { + no_mem_exit( + "Memory allocation for struct slice_s datastruct Failed" + ); + return 0; + } + if (1) { + + currslice->mot_ctx = create_contexts_motioninfo(); + if (currslice->mot_ctx == NULL) + return 0; + + currslice->tex_ctx = create_contexts_textureinfo(); + if (currslice->tex_ctx == NULL) + return 0; + } +#if LIWR_FIX + currslice->max_part_nr = 1; +#else + currslice->max_part_nr = 3; +#endif + currslice->part_arr = alloc_partition(currslice->max_part_nr); + if (currslice->part_arr == NULL) + return 0; + return 1; +} + +void init(struct img_par *img) +{ + int i; + + for (i = 0; i < 256; i++) + img->quad[i] = i * i; +} + +/* + ************************************************************************* + * Function:Allocate 2D memory array -> int array2D[rows][columns] + * Input: + * Output: memory size in bytes + * Return: + * Attention: + ************************************************************************* + */ + +int get_mem2Dint(int ***array2D, int rows, int columns) +{ + int i; + + *array2D = (int **)local_alloc(rows, sizeof(int *)); + if (*array2D == NULL) { + no_mem_exit("get_mem2Dint: array2D"); + return -1; + } + (*array2D)[0] = (int *)local_alloc(rows * columns, sizeof(int)); + if ((*array2D)[0] == NULL) { + no_mem_exit("get_mem2Dint: array2D"); + return -1; + } + + for (i = 1; i < rows; i++) + (*array2D)[i] = (*array2D)[i - 1] + columns; + + return rows * columns * sizeof(int); +} + +int initial_decode(void) +{ + int i, j; + int ret; + int img_height = (vertical_size + img->auto_crop_bottom); + int memory_size = 0; + + ret = malloc_slice(img); + if (ret == 0) + return 0; + + mb_data = (struct macroblock *)local_alloc( + (img->width / MB_BLOCK_SIZE) + * (img_height /*vertical_size*/ + / MB_BLOCK_SIZE), sizeof(struct macroblock)); + if (mb_data == NULL) { + no_mem_exit("init_global_buffers: mb_data"); + return 0; + } + + if (progressive_sequence) { + int size; + size = get_mem2Dint(&(img->ipredmode), + img->width / B8_SIZE * 2 + 4, + vertical_size / B8_SIZE * 2 + 4); + if (size == -1) + return 0; + + memory_size += size; + } else { + int size; + size = get_mem2Dint(&(img->ipredmode), + img->width / B8_SIZE * 2 + 4, + (vertical_size + 32) / (2 * B8_SIZE) * 4 + 4); + if (size == -1) + return 0; + + memory_size += size; + } + + for (i = 0; i < img->width / (B8_SIZE) * 2 + 4; i++) { + for (j = 0; j < img->height / (B8_SIZE) * 2 + 4; j++) + img->ipredmode[i][j] = -1; + } + + init(img); + img->number = 0; + img->type = I_IMG; + img->imgtr_last_p = 0; + img->imgtr_next_p = 0; + + img->new_seq_header_flag = 1; + img->new_sequence_flag = 1; + + return 1; +} + +void aec_new_slice(void) +{ + last_dquant = 0; +} + +/*! + ************************************************************************ + * \brief + * Initializes the DecodingEnvironment for the arithmetic coder + ************************************************************************ + */ + +void arideco_start_decoding(struct decoding_environment_s *dep, + unsigned char *cpixcode, + int firstbyte, int *cpixcode_len, int slice_type) +{ + + dcodestrm = cpixcode; + dcodestrm_len = cpixcode_len; + *dcodestrm_len = firstbyte; + + s1 = 0; + t1 = QUARTER - 1; + value_s = 0; + + value_t = 0; + + { + int i; + + dbits_to_go = 0; + for (i = 0; i < B_BITS - 1; i++) { + if (--dbits_to_go < 0) + get_byte(); + + value_t = (value_t << 1) + | ((dbuffer >> dbits_to_go) & 0x01); + } + } + + while (value_t < QUARTER) { + if (--dbits_to_go < 0) + get_byte(); + + value_t = (value_t << 1) | ((dbuffer >> dbits_to_go) & 0x01); + value_s++; + } + value_t = value_t & 0xff; + + dec_final = dec_bypass = 0; + + + +} + +/* + ************************************************************************* + * Function:Checks the availability of neighboring macroblocks of + the current macroblock for prediction and context determination; + marks the unavailable MBs for intra prediction in the + ipredmode-array by -1. Only neighboring MBs in the causal + past of the current MB are checked. + * Input: + * Output: + * Return: + * Attention: + ************************************************************************* + */ + +void checkavailabilityofneighbors(struct img_par *img) +{ + int i, j; + const int mb_width = img->width / MB_BLOCK_SIZE; + const int mb_nr = img->current_mb_nr; + struct macroblock *curr_mb = &mb_data[mb_nr]; + int check_value; + int remove_prediction; + + curr_mb->mb_available_up = NULL; + curr_mb->mb_available_left = NULL; + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + mb_data[mb_nr].mb_available[i][j] = NULL; + + mb_data[mb_nr].mb_available[1][1] = curr_mb; + + if (img->pix_x >= MB_BLOCK_SIZE) { + remove_prediction = curr_mb->slice_nr + != mb_data[mb_nr - 1].slice_nr; + + if (remove_prediction) + + { + + img->ipredmode[(img->block_x + 1) * 2 - 1][(img->block_y + + 1) * 2] = -1; + img->ipredmode[(img->block_x + 1) * 2 - 1][(img->block_y + + 1) * 2 + 1] = -1; + img->ipredmode[(img->block_x + 1) * 2 - 1][(img->block_y + + 2) * 2] = -1; + img->ipredmode[(img->block_x + 1) * 2 - 1][(img->block_y + + 2) * 2 + 1] = -1; + } + if (!remove_prediction) + curr_mb->mb_available[1][0] = &(mb_data[mb_nr - 1]); + + } + + check_value = (img->pix_y >= MB_BLOCK_SIZE); + if (check_value) { + remove_prediction = curr_mb->slice_nr + != mb_data[mb_nr - mb_width].slice_nr; + + if (remove_prediction) { + img->ipredmode + [(img->block_x + 1) * 2][(img->block_y + 1) + * 2 - 1] = -1; + img->ipredmode[(img->block_x + 1) * 2 + 1][(img->block_y + + 1) * 2 - 1] = -1; + img->ipredmode[(img->block_x + 1) * 2 + 2][(img->block_y + + 1) * 2 - 1] = -1; + img->ipredmode[(img->block_x + 1) * 2 + 3][(img->block_y + + 1) * 2 - 1] = -1; + } + + if (!remove_prediction) { + curr_mb->mb_available[0][1] = + &(mb_data[mb_nr - mb_width]); + } + } + + if (img->pix_y >= MB_BLOCK_SIZE && img->pix_x >= MB_BLOCK_SIZE) { + remove_prediction = curr_mb->slice_nr + != mb_data[mb_nr - mb_width - 1].slice_nr; + + if (remove_prediction) { + img->ipredmode[img->block_x * 2 + 1][img->block_y * 2 + + 1] = -1; + } + if (!remove_prediction) { + curr_mb->mb_available[0][0] = &(mb_data[mb_nr - mb_width + - 1]); + } + } + + if (img->pix_y >= MB_BLOCK_SIZE + && img->pix_x < (img->width - MB_BLOCK_SIZE)) { + if (curr_mb->slice_nr == mb_data[mb_nr - mb_width + 1].slice_nr) + curr_mb->mb_available[0][2] = &(mb_data[mb_nr - mb_width + + 1]); + } + + if (1) { + curr_mb->mbaddr_a = mb_nr - 1; + curr_mb->mbaddr_b = mb_nr - img->pic_width_inmbs; + curr_mb->mbaddr_c = mb_nr - img->pic_width_inmbs + 1; + curr_mb->mbaddr_d = mb_nr - img->pic_width_inmbs - 1; + + curr_mb->mbavail_a = + (curr_mb->mb_available[1][0] != NULL) ? 1 : 0; + curr_mb->mbavail_b = + (curr_mb->mb_available[0][1] != NULL) ? 1 : 0; + curr_mb->mbavail_c = + (curr_mb->mb_available[0][2] != NULL) ? 1 : 0; + curr_mb->mbavail_d = + (curr_mb->mb_available[0][0] != NULL) ? 1 : 0; + + } + +} + +void checkavailabilityofneighborsaec(void) +{ + + int i, j; + const int mb_width = img->width / MB_BLOCK_SIZE; + const int mb_nr = img->current_mb_nr; + struct macroblock *curr_mb = &(mb_data[mb_nr]); + int check_value; + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + mb_data[mb_nr].mb_available[i][j] = NULL; + mb_data[mb_nr].mb_available[1][1] = &(mb_data[mb_nr]); + + if (img->pix_x >= MB_BLOCK_SIZE) { + int remove_prediction = curr_mb->slice_nr + != mb_data[mb_nr - 1].slice_nr; + if (!remove_prediction) + curr_mb->mb_available[1][0] = &(mb_data[mb_nr - 1]); + } + + check_value = (img->pix_y >= MB_BLOCK_SIZE); + if (check_value) { + int remove_prediction = curr_mb->slice_nr + != mb_data[mb_nr - mb_width].slice_nr; + + if (!remove_prediction) { + curr_mb->mb_available[0][1] = + &(mb_data[mb_nr - mb_width]); + } + } + + if (img->pix_y >= MB_BLOCK_SIZE && img->pix_x >= MB_BLOCK_SIZE) { + int remove_prediction = curr_mb->slice_nr + != mb_data[mb_nr - mb_width - 1].slice_nr; + if (!remove_prediction) { + curr_mb->mb_available[0][0] = &(mb_data[mb_nr - mb_width + - 1]); + } + } + + if (img->pix_y >= MB_BLOCK_SIZE + && img->pix_x < (img->width - MB_BLOCK_SIZE)) { + if (curr_mb->slice_nr == mb_data[mb_nr - mb_width + 1].slice_nr) + curr_mb->mb_available[0][2] = &(mb_data[mb_nr - mb_width + + 1]); + } + curr_mb->mb_available_left = curr_mb->mb_available[1][0]; + curr_mb->mb_available_up = curr_mb->mb_available[0][1]; + curr_mb->mbaddr_a = mb_nr - 1; + curr_mb->mbaddr_b = mb_nr - img->pic_width_inmbs; + curr_mb->mbaddr_c = mb_nr - img->pic_width_inmbs + 1; + curr_mb->mbaddr_d = mb_nr - img->pic_width_inmbs - 1; + + curr_mb->mbavail_a = (curr_mb->mb_available[1][0] != NULL) ? 1 : 0; + curr_mb->mbavail_b = (curr_mb->mb_available[0][1] != NULL) ? 1 : 0; + curr_mb->mbavail_c = (curr_mb->mb_available[0][2] != NULL) ? 1 : 0; + curr_mb->mbavail_d = (curr_mb->mb_available[0][0] != NULL) ? 1 : 0; +} + +/* + ************************************************************************* + * Function:initializes the current macroblock + * Input: + * Output: + * Return: + * Attention: + ************************************************************************* + */ + +void start_macroblock(struct img_par *img) +{ + int i, j, k, l; + struct macroblock *curr_mb; + +#ifdef AVSP_LONG_CABAC +#else + +#endif + + curr_mb = &mb_data[img->current_mb_nr]; + + /* Update coordinates of the current macroblock */ + img->mb_x = (img->current_mb_nr) % (img->width / MB_BLOCK_SIZE); + img->mb_y = (img->current_mb_nr) / (img->width / MB_BLOCK_SIZE); + +#ifdef DUMP_DEBUG + if (avs_get_debug_flag() & MB_NUM_DUMP) + io_printf(" #Begin MB : %d, (%x, %x) es_ptr %d\n", + img->current_mb_nr, img->mb_x, img->mb_y, es_ptr); +#endif + + + total_mb_count = total_mb_count + 1; + + /* Define vertical positions */ + img->block_y = img->mb_y * BLOCK_SIZE / 2; /* luma block position */ + img->block8_y = img->mb_y * BLOCK_SIZE / 2; + img->pix_y = img->mb_y * MB_BLOCK_SIZE; /* luma macroblock position */ + if (chroma_format == 2) + img->pix_c_y = img->mb_y * + MB_BLOCK_SIZE; /* chroma macroblock position */ + else + img->pix_c_y = img->mb_y * + MB_BLOCK_SIZE / 2; /* chroma macroblock position */ + + /* Define horizontal positions */ + img->block_x = img->mb_x * BLOCK_SIZE / 2; /* luma block position */ + img->block8_x = img->mb_x * BLOCK_SIZE / 2; + img->pix_x = img->mb_x * MB_BLOCK_SIZE; /* luma pixel position */ + img->pix_c_x = img->mb_x * + MB_BLOCK_SIZE / 2; /* chroma pixel position */ + + checkavailabilityofneighbors(img); + + /*<!*******EDIT START BY lzhang ******************/ + + if (1) + checkavailabilityofneighborsaec(); + /*<!*******EDIT end BY lzhang ******************/ + + curr_mb->qp = img->qp; + curr_mb->mb_type = 0; + curr_mb->delta_quant = 0; + curr_mb->cbp = 0; + curr_mb->cbp_blk = 0; + curr_mb->c_ipred_mode = DC_PRED_8; + curr_mb->c_ipred_mode_2 = DC_PRED_8; + + for (l = 0; l < 2; l++) + for (j = 0; j < BLOCK_MULTIPLE; j++) + for (i = 0; i < BLOCK_MULTIPLE; i++) + for (k = 0; k < 2; k++) + curr_mb->mvd[l][j][i][k] = 0; + + curr_mb->cbp_bits = 0; + + for (j = 0; j < MB_BLOCK_SIZE; j++) + for (i = 0; i < MB_BLOCK_SIZE; i++) + img->m7[i][j] = 0; + + for (j = 0; j < 2 * BLOCK_SIZE; j++) + for (i = 0; i < 2 * BLOCK_SIZE; i++) { + img->m8[0][i][j] = 0; + img->m8[1][i][j] = 0; + img->m8[2][i][j] = 0; + img->m8[3][i][j] = 0; + } + + curr_mb->lf_disable = 1; + + img->weighting_prediction = 0; +} + +/* + ************************************************************************* + * Function:init macroblock I and P frames + * Input: + * Output: + * Return: + * Attention: + ************************************************************************* + */ + +void init_macroblock(struct img_par *img) +{ + int i, j; + + + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + img->ipredmode[img->block_x * 2 + i + 2][img->block_y + * 2 + j + 2] = -1; + } + } + +} + +/* + ************************************************************************* + * Function:Interpret the mb mode for I-Frames + * Input: + * Output: + * Return: + * Attention: + ************************************************************************* + */ + +void interpret_mb_mode_i(struct img_par *img) +{ + int i; + + struct macroblock *curr_mb = &mb_data[img->current_mb_nr]; + int num = 4; + + curr_mb->mb_type = I8MB; + + + current_mb_intra = 1; + + for (i = 0; i < 4; i++) { + curr_mb->b8mode[i] = IBLOCK; + curr_mb->b8pdir[i] = -1; + } + + for (i = num; i < 4; i++) { + curr_mb->b8mode[i] = + curr_mb->mb_type_2 == P8x8 ? + 4 : curr_mb->mb_type_2; + curr_mb->b8pdir[i] = 0; + } +} + +const int pred_4x4[9][9] = {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {1, 1, 1, 1, 1, 1, 1, + 1, 1}, {0, 1, 2, 3, 4, 5, 6, 7, 8}, {0, 0, 0, 3, 3, 3, 3, 3, 3}, + {0, 1, 4, 4, 4, 4, 4, 4, 4}, {0, 1, 5, 5, 5, 5, 5, 5, 5}, {0, 0, + 0, 0, 0, 0, 6, 0, 0}, + {0, 1, 7, 7, 7, 7, 7, 7, 7}, {0, 0, 0, 0, 4, 5, 6, 7, 8} + +}; + +const int pred_4x4to8x8[9] = {0, 1, 2, 3, 4, 1, 0, 1, 0 + +}; + +const int pred_8x8to4x4[5] = {0, 1, 2, 3, 4}; + +void read_ipred_block_modes(struct img_par *img, int b8) +{ + int bi, bj, dec; + struct syntaxelement curr_se; + struct macroblock *curr_mb; + int j2; + int mostprobableintrapredmode; + int upintrapredmode; + int uprightintrapredmode; + int leftintrapredmode; + int leftdownintrapredmode; + int intrachromapredmodeflag; + + struct slice_s *currslice = img->current_slice; + struct datapartition *dp; + + curr_mb = mb_data + img->current_mb_nr; + intrachromapredmodeflag = IS_INTRA(curr_mb); + + curr_se.type = SE_INTRAPREDMODE; +#if TRACE + strncpy(curr_se.tracestring, "Ipred Mode", TRACESTRING_SIZE); +#endif + + if (b8 < 4) { + if (curr_mb->b8mode[b8] == IBLOCK) { + intrachromapredmodeflag = 1; + + if (1) { + dp = &(currslice->part_arr[0]); + curr_se.reading = read_intrapredmode_aec; + dp->read_syntax_element(&curr_se, img, dp); + + if (curr_se.value1 == -1) + push_es(1, 1); + else + push_es(curr_se.value1, 3); + + + } + bi = img->block_x + (b8 & 1); + bj = img->block_y + (b8 / 2); + + upintrapredmode = img->ipredmode[(bi + 1) * 2][(bj) * 2 + + 1]; + uprightintrapredmode = + img->ipredmode[(bi + 1) * 2 + 1][(bj) + * 2 + 1]; + leftintrapredmode = + img->ipredmode[(bi) * 2 + 1][(bj + 1) + * 2]; + leftdownintrapredmode = img->ipredmode[(bi) * 2 + 1][(bj + + 1) * 2 + 1]; + + if ((upintrapredmode < 0) || (leftintrapredmode < 0)) { + mostprobableintrapredmode = DC_PRED; + } else if ((upintrapredmode < NO_INTRA_PMODE) + && (leftintrapredmode < + NO_INTRA_PMODE)) { + mostprobableintrapredmode = + upintrapredmode + < leftintrapredmode ? + upintrapredmode : + leftintrapredmode; + } else if (upintrapredmode < NO_INTRA_PMODE) { + mostprobableintrapredmode = upintrapredmode; + } else if (leftintrapredmode < NO_INTRA_PMODE) { + mostprobableintrapredmode = leftintrapredmode; + } else { + mostprobableintrapredmode = + pred_4x4[leftintrapredmode + - INTRA_PMODE_4x4][upintrapredmode + - INTRA_PMODE_4x4]; + mostprobableintrapredmode = + pred_4x4to8x8[mostprobableintrapredmode]; + } + + + + dec = + (curr_se.value1 == -1) ? + mostprobableintrapredmode : + curr_se.value1 + + (curr_se.value1 + >= mostprobableintrapredmode); + +#ifdef DUMP_DEBUG + if (avs_get_debug_flag() & MB_INFO_DUMP) + io_printf(" - ipredmode[%d] : %d\n", b8, dec); +#endif + + img->ipredmode[(1 + bi) * 2][(1 + bj) * 2] = dec; + img->ipredmode[(1 + bi) * 2 + 1][(1 + bj) * 2] = dec; + img->ipredmode[(1 + bi) * 2][(1 + bj) * 2 + 1] = dec; + img->ipredmode[(1 + bi) * 2 + 1][(1 + bj) * 2 + 1] = + dec; + + j2 = bj; + } + } else if (b8 == 4 && curr_mb->b8mode[b8 - 3] == IBLOCK) { + + curr_se.type = SE_INTRAPREDMODE; +#if TRACE + strncpy(curr_se.tracestring, + "Chroma intra pred mode", TRACESTRING_SIZE); +#endif + + if (1) { + dp = &(currslice->part_arr[0]); + curr_se.reading = read_cipredmode_aec; + dp->read_syntax_element(&curr_se, img, dp); + } else + + { + } + curr_mb->c_ipred_mode = curr_se.value1; + + push_es(UE[curr_se.value1][0], UE[curr_se.value1][1]); + +#ifdef DUMP_DEBUG + if (avs_get_debug_flag() & MB_INFO_DUMP) + io_printf(" * UE c_ipred_mode read : %d\n", + curr_mb->c_ipred_mode); +#endif + + if (curr_se.value1 < DC_PRED_8 || curr_se.value1 > PLANE_8) { +#ifdef DUMP_DEBUG + if (avs_get_debug_flag() & MB_INFO_DUMP) + io_printf("%d\n", img->current_mb_nr); +#endif + pr_info("illegal chroma intra pred mode!\n"); + } + } +} + +/*! + ************************************************************************ + * \brief + * This function is used to arithmetically decode the coded + * block pattern of a given MB. + ************************************************************************ + */ +void readcp_aec(struct syntaxelement *se, struct img_par *img, + struct decoding_environment_s *dep_dp) +{ + struct texture_info_contexts *ctx = img->current_slice->tex_ctx; + struct macroblock *curr_mb = &mb_data[img->current_mb_nr]; + + int mb_x, mb_y; + int a, b; + int curr_cbp_ctx, curr_cbp_idx; + int cbp = 0; + int cbp_bit; + int mask; + + for (mb_y = 0; mb_y < 4; mb_y += 2) { + for (mb_x = 0; mb_x < 4; mb_x += 2) { + if (curr_mb->b8mode[mb_y + (mb_x / 2)] == IBLOCK) + curr_cbp_idx = 0; + else + curr_cbp_idx = 1; + + if (mb_y == 0) { + if (curr_mb->mb_available_up == NULL) + b = 0; + else { + b = ((((curr_mb->mb_available_up)->cbp + & (1 << (2 + mb_x / 2))) + == 0) ? 1 : 0); + } + + } else + b = (((cbp & (1 << (mb_x / 2))) == 0) ? 1 : 0); + + if (mb_x == 0) { + if (curr_mb->mb_available_left == NULL) + a = 0; + else { + a = + ((((curr_mb->mb_available_left)->cbp + & (1 + << (2 + * (mb_y + / 2) + + 1))) + == 0) ? + 1 : 0); + } + } else + a = (((cbp & (1 << mb_y)) == 0) ? 1 : 0); + curr_cbp_ctx = a + 2 * b; + mask = (1 << (mb_y + mb_x / 2)); + cbp_bit = biari_decode_symbol(dep_dp, + ctx->cbp_contexts[0] + curr_cbp_ctx); + + if (cbp_bit) + cbp += mask; + } + } + curr_cbp_ctx = 0; + cbp_bit = biari_decode_symbol(dep_dp, + ctx->cbp_contexts[1] + curr_cbp_ctx); + + if (cbp_bit) { + curr_cbp_ctx = 1; + cbp_bit = biari_decode_symbol(dep_dp, + ctx->cbp_contexts[1] + curr_cbp_ctx); + if (cbp_bit) { + cbp += 48; + + } else { + curr_cbp_ctx = 1; + cbp_bit = biari_decode_symbol(dep_dp, + ctx->cbp_contexts[1] + curr_cbp_ctx); + cbp += (cbp_bit == 1) ? 32 : 16; + + } + } + + se->value1 = cbp; + if (!cbp) + last_dquant = 0; + + + +} + +/*! + ************************************************************************ + * \brief + * This function is used to arithmetically decode the delta qp + * of a given MB. + ************************************************************************ + */ +void readdquant_aec(struct syntaxelement *se, struct img_par *img, + struct decoding_environment_s *dep_dp) +{ + struct motion_info_contexts_s *ctx = img->current_slice->mot_ctx; + + int act_ctx; + int act_sym; + int dquant; + + + act_ctx = ((last_dquant != 0) ? 1 : 0); + + act_sym = 1 + - biari_decode_symbol(dep_dp, + ctx->delta_qp_contexts + act_ctx); + if (act_sym != 0) { + act_ctx = 2; + act_sym = unary_bin_decode(dep_dp, + ctx->delta_qp_contexts + act_ctx, 1); + act_sym++; + } + act_sym &= 0x3f; + push_es(UE[act_sym][0], UE[act_sym][1]); + + dquant = (act_sym + 1) / 2; + if ((act_sym & 0x01) == 0) + dquant = -dquant; + se->value1 = dquant; + + last_dquant = dquant; + +} + +int csyntax; + +#define CHECKDELTAQP {\ + if (img->qp+curr_mb->delta_quant > 63\ + || img->qp+curr_mb->delta_quant < 0) {\ + csyntax = 0;\ + transcoding_error_flag = 1;\ + io_printf("error(0) (%3d|%3d) @ MB%d\n",\ + curr_mb->delta_quant,\ + img->qp+curr_mb->delta_quant,\ + img->picture_structure == 0 \ + ? img->current_mb_nr_fld : img->current_mb_nr);\ + } } + +int dct_level[65]; +int dct_run[65]; +int pair_pos; +int dct_pairs = -1; +const int t_chr[5] = {0, 1, 2, 4, 3000}; + +void readrunlevel_aec_ref(struct syntaxelement *se, struct img_par *img, + struct decoding_environment_s *dep_dp) +{ + int pairs, rank, pos; + int run, level, abslevel, symbol; + int sign; + + if (dct_pairs < 0) { + struct bi_context_type_s (*primary)[NUM_MAP_CTX]; + struct bi_context_type_s *pctx; + struct bi_context_type_s *pCTX2; + int ctx, ctx2, offset; + + if (se->context == LUMA_8x8) { + if (img->picture_structure == 0) { + primary = + img->current_slice->tex_ctx->fld_map_contexts; + } else { + primary = + img->current_slice->tex_ctx->map_contexts; + } + } else { + if (img->picture_structure == 0) { + primary = + img->current_slice->tex_ctx->fld_last_contexts; + } else { + primary = + img->current_slice->tex_ctx->last_contexts; + } + } + + rank = 0; + pos = 0; + for (pairs = 0; pairs < 65; pairs++) { +#ifdef DECODING_SANITY_CHECK + /*max index is NUM_BLOCK_TYPES - 1*/ + pctx = primary[rank & 0x7]; +#else + pctx = primary[rank]; +#endif + if (rank > 0) { +#ifdef DECODING_SANITY_CHECK + /*max index is NUM_BLOCK_TYPES - 1*/ + pCTX2 = primary[(5 + (pos >> 5)) & 0x7]; +#else + pCTX2 = primary[5 + (pos >> 5)]; +#endif + ctx2 = (pos >> 1) & 0x0f; + ctx = 0; + + + if (biari_decode_symbolw(dep_dp, pctx + ctx, + pCTX2 + ctx2)) { + break; + } + } + + ctx = 1; + symbol = 0; + while (biari_decode_symbol(dep_dp, pctx + ctx) == 0) { + symbol += 1; + ctx++; + if (ctx >= 2) + ctx = 2; + } + abslevel = symbol + 1; + + if (biari_decode_symbol_eq_prob(dep_dp)) { + level = -abslevel; + sign = 1; + } else { + level = abslevel; + sign = 0; + } +#if TRACE + tracebits2("level", 1, level); +#endif + + if (abslevel == 1) + offset = 4; + else + offset = 6; + symbol = 0; + ctx = 0; + while (biari_decode_symbol(dep_dp, pctx + ctx + offset) + == 0) { + symbol += 1; + ctx++; + if (ctx >= 1) + ctx = 1; + } + run = symbol; + +#if TRACE + tracebits2("run", 1, run); +#endif + dct_level[pairs] = level; + dct_run[pairs] = run; + if (abslevel > t_chr[rank]) { + if (abslevel <= 2) + rank = abslevel; + else if (abslevel <= 4) + rank = 3; + else + rank = 4; + } + pos += (run + 1); + if (pos >= 64) + pos = 63; + } + dct_pairs = pairs; + pair_pos = dct_pairs; + } + + if (dct_pairs > 0) { + se->value1 = dct_level[pair_pos - 1]; + se->value2 = dct_run[pair_pos - 1]; + pair_pos--; + } else { + + se->value1 = se->value2 = 0; + } + + if ((dct_pairs--) == 0) + pair_pos = 0; +} + +int b8_ctr; +#if 0 +int curr_residual_chroma[4][16][16]; +int curr_residual_luma[16][16]; +#endif + +const int SCAN[2][64][2] = {{{0, 0}, {0, 1}, {0, 2}, {1, 0}, {0, 3}, {0, 4}, {1, + 1}, {1, 2}, {0, 5}, {0, 6}, {1, 3}, {2, 0}, {2, 1}, {0, 7}, {1, + 4}, {2, 2}, {3, 0}, {1, 5}, {1, 6}, {2, 3}, {3, 1}, {3, 2}, {4, + 0}, {1, 7}, {2, 4}, {4, 1}, {2, 5}, {3, 3}, {4, 2}, {2, 6}, {3, + 4}, {4, 3}, {5, 0}, {5, 1}, {2, 7}, {3, 5}, {4, 4}, {5, 2}, {6, + 0}, {5, 3}, {3, 6}, {4, 5}, {6, 1}, {6, 2}, {5, 4}, {3, 7}, {4, + 6}, {6, 3}, {5, 5}, {4, 7}, {6, 4}, {5, 6}, {6, 5}, {5, 7}, {6, + 6}, {7, 0}, {6, 7}, {7, 1}, {7, 2}, {7, 3}, {7, 4}, {7, 5}, {7, + 6}, {7, 7} }, {{0, 0}, {1, 0}, {0, 1}, {0, 2}, {1, 1}, {2, 0}, { + 3, 0}, {2, 1}, {1, 2}, {0, 3}, {0, 4}, {1, 3}, {2, 2}, {3, 1}, { + 4, 0}, {5, 0}, {4, 1}, {3, 2}, {2, 3}, {1, 4}, {0, 5}, {0, 6}, { + 1, 5}, {2, 4}, {3, 3}, {4, 2}, {5, 1}, {6, 0}, {7, 0}, {6, 1}, { + 5, 2}, {4, 3}, {3, 4}, {2, 5}, {1, 6}, {0, 7}, {1, 7}, {2, 6}, { + 3, 5}, {4, 4}, {5, 3}, {6, 2}, {7, 1}, {7, 2}, {6, 3}, {5, 4}, { + 4, 5}, {3, 6}, {2, 7}, {3, 7}, {4, 6}, {5, 5}, {6, 4}, {7, 3}, { + 7, 4}, {6, 5}, {5, 6}, {4, 7}, {5, 7}, {6, 6}, {7, 5}, {7, 6}, { + 6, 7}, {7, 7} } }; + +const int SCAN_4x4[16][2] = {{0, 0}, {1, 0}, {0, 1}, {0, 2}, {1, 1}, {2, 0}, {3, + 0}, {2, 1}, {1, 2}, {0, 3}, {1, 3}, {2, 2}, {3, 1}, {3, 2}, {2, + 3}, {3, 3} }; + +/* + ************************************************************************* + * Function: + * Input: + * Output: + * Return: + * Attention: + ************************************************************************* + */ + +void encode_golomb_word(unsigned int symbol, unsigned int grad0, + unsigned int max_levels, unsigned int *res_bits, + unsigned int *res_len) +{ + unsigned int level, res, numbits; + + res = 1UL << grad0; + level = 1UL; + numbits = 1UL + grad0; + + while (symbol >= res && level < max_levels) { + symbol -= res; + res = res << 1; + level++; + numbits += 2UL; + } + + if (level >= max_levels) { + if (symbol >= res) + symbol = res - 1UL; + } + + *res_bits = res | symbol; + *res_len = numbits; +} + +/* + ************************************************************************* + * Function: + * Input: + * Output: + * Return: + * Attention: + ************************************************************************* + */ + +void encode_multilayer_golomb_word(unsigned int symbol, + const unsigned int *grad, const unsigned int *max_levels, + unsigned int *res_bits, unsigned int *res_len) +{ + unsigned int accbits, acclen, bits, len, tmp; + + accbits = acclen = 0UL; + + while (1) { + encode_golomb_word(symbol, *grad, *max_levels, &bits, &len); + accbits = (accbits << len) | bits; + acclen += len; +#ifdef AVSP_LONG_CABAC +#else + assert(acclen <= 32UL); +#endif + tmp = *max_levels - 1UL; + + if (!((len == (tmp << 1) + (*grad)) + && (bits == (1UL << (tmp + *grad)) - 1UL))) + break; + + tmp = *max_levels; + symbol -= (((1UL << tmp) - 1UL) << (*grad)) - 1UL; + grad++; + max_levels++; + } + *res_bits = accbits; + *res_len = acclen; +} + +/* + ************************************************************************* + * Function: + * Input: + * Output: + * Return: + * Attention: + ************************************************************************* + */ + +int writesyntaxelement_golomb(struct syntaxelement *se, int write_to_stream) +{ + unsigned int bits, len, i; + unsigned int grad[4], max_lev[4]; + + if (!(se->golomb_maxlevels & ~0xFF)) + encode_golomb_word(se->value1, se->golomb_grad, + se->golomb_maxlevels, &bits, &len); + else { + for (i = 0UL; i < 4UL; i++) { + grad[i] = (se->golomb_grad >> (i << 3)) & 0xFFUL; + max_lev[i] = (se->golomb_maxlevels >> (i << 3)) + & 0xFFUL; + } + encode_multilayer_golomb_word(se->value1, grad, max_lev, &bits, + &len); + } + + se->len = len; + se->bitpattern = bits; + + if (write_to_stream) + push_es(bits, len); + return se->len; +} + +/* + ************************************************************************* + * Function:Get coded block pattern and coefficients (run/level) + from the bitstream + * Input: + * Output: + * Return: + * Attention: + ************************************************************************* + */ + +void read_cbpandcoeffsfrom_nal(struct img_par *img) +{ + + int tablenum; + int inumblk; + int inumcoeff; + int symbol2D; + int escape_level_diff; + const int (*AVS_2DVLC_table_intra)[26][27]; + const int (*AVS_2DVLC_table_chroma)[26][27]; + int write_to_stream; + struct syntaxelement currse_enc; + struct syntaxelement *e_currse = &currse_enc; + + int coeff_save[65][2]; + int coeff_ptr; + + int ii, jj; + int mb_nr = img->current_mb_nr; + + int m2, jg2; + struct macroblock *curr_mb = &mb_data[mb_nr]; + + int block8x8; + + int block_x, block_y; + + struct slice_s *currslice = img->current_slice; + int level, run, coef_ctr, len, k, i0, j0, uv, qp; + + int boff_x, boff_y, start_scan; + struct syntaxelement curr_se; + struct datapartition *dp; + + AVS_2DVLC_table_intra = AVS_2DVLC_INTRA; + AVS_2DVLC_table_chroma = AVS_2DVLC_CHROMA; + write_to_stream = 1; + + dct_pairs = -1; + + curr_mb->qp = img->qp; + qp = curr_mb->qp; + + + for (block_y = 0; block_y < 4; block_y += 2) {/* all modes */ + for (block_x = 0; block_x < 4; block_x += 2) { + block8x8 = 2 * (block_y / 2) + block_x / 2; + if (curr_mb->cbp & (1 << block8x8)) { + tablenum = 0; + inumblk = 1; + inumcoeff = 65; + coeff_save[0][0] = 0; + coeff_save[0][1] = 0; + coeff_ptr = 1; + + b8_ctr = block8x8; + + boff_x = (block8x8 % 2) << 3; + boff_y = (block8x8 / 2) << 3; + + img->subblock_x = boff_x >> 2; + img->subblock_y = boff_y >> 2; + + start_scan = 0; + coef_ctr = start_scan - 1; + level = 1; + img->is_v_block = 0; + img->is_intra_block = IS_INTRA(curr_mb); + for (k = start_scan; + (k < 65) && (level != 0); + k++) { + + curr_se.context = LUMA_8x8; + curr_se.type = + (IS_INTRA(curr_mb)) ? + SE_LUM_AC_INTRA : + SE_LUM_AC_INTER; + + dp = &(currslice->part_arr[0]); + curr_se.reading = + readrunlevel_aec_ref; + dp-> + read_syntax_element(&curr_se, + img, dp); + level = curr_se.value1; + run = curr_se.value2; + len = curr_se.len; + + if (level != 0) { + coeff_save[coeff_ptr][0] = + run; + coeff_save[coeff_ptr][1] = + level; + coeff_ptr++; + } + + + + if (level != 0) {/* leave if len = 1 */ + coef_ctr += run + 1; + if ((img->picture_structure + == FRAME)) { + ii = + SCAN[img->picture_structure] + [coef_ctr][0]; + jj = + SCAN[img->picture_structure] + [coef_ctr][1]; + } else { + ii = + SCAN[img->picture_structure] + [coef_ctr][0]; + jj = + SCAN[img->picture_structure] + [coef_ctr][1]; + } + + } + } + + while (coeff_ptr > 0) { + run = + coeff_save[coeff_ptr + - 1][0]; + level = + coeff_save[coeff_ptr + - 1][1]; + + coeff_ptr--; + + symbol2D = CODE2D_ESCAPE_SYMBOL; + if (level > -27 && level < 27 + && run < 26) { + if (tablenum == 0) + + symbol2D = + AVS_2DVLC_table_intra + [tablenum] + [run][abs( + level) + - 1]; + else + + symbol2D = + AVS_2DVLC_table_intra + [tablenum] + [run][abs( + level)]; + if (symbol2D >= 0 + && level + < 0) + symbol2D++; + if (symbol2D < 0) + + symbol2D = + (CODE2D_ESCAPE_SYMBOL + + (run + << 1) + + ((level + > 0) ? + 1 : + 0)); + } + + else { + + symbol2D = + (CODE2D_ESCAPE_SYMBOL + + (run + << 1) + + ((level + > 0) ? + 1 : + 0)); + } + + + + e_currse->type = SE_LUM_AC_INTER; + e_currse->value1 = symbol2D; + e_currse->value2 = 0; + + e_currse->golomb_grad = + vlc_golomb_order + [0][tablenum][0]; + e_currse->golomb_maxlevels = + vlc_golomb_order + [0][tablenum][1]; + + writesyntaxelement_golomb( + e_currse, + write_to_stream); + + if (symbol2D + >= CODE2D_ESCAPE_SYMBOL) { + + e_currse->type = + SE_LUM_AC_INTER; + e_currse->golomb_grad = + 1; + e_currse->golomb_maxlevels = + 11; + escape_level_diff = + abs( + level) + - ((run + > MaxRun[0][tablenum]) ? + 1 : + refabslevel[tablenum][run]); + e_currse->value1 = + escape_level_diff; + + writesyntaxelement_golomb( + e_currse, + write_to_stream); + + } + + if (abs(level) + > incvlc_intra[tablenum]) { + if (abs(level) <= 2) + tablenum = + abs( + level); + else if (abs(level) <= 4) + tablenum = 3; + else if (abs(level) <= 7) + tablenum = 4; + else if (abs(level) + <= 10) + tablenum = 5; + else + tablenum = 6; + } + } + + + } + } + } + + + + m2 = img->mb_x * 2; + jg2 = img->mb_y * 2; + + + uv = -1; + block_y = 4; +#if 0 + qp = QP_SCALE_CR[curr_mb->qp]; +#endif + for (block_x = 0; block_x < 4; block_x += 2) { + + uv++; + + + b8_ctr = (uv + 4); + if ((curr_mb->cbp >> (uv + 4)) & 0x1) { + + tablenum = 0; + inumblk = 1; + inumcoeff = 65; + coeff_save[0][0] = 0; + coeff_save[0][1] = 0; + coeff_ptr = 1; + + coef_ctr = -1; + level = 1; + img->subblock_x = 0; + img->subblock_y = 0; + curr_se.context = CHROMA_AC; + curr_se.type = (IS_INTRA(curr_mb) ? + SE_CHR_AC_INTRA : + SE_CHR_AC_INTER); + dp = &(currslice->part_arr[0]); + curr_se.reading = readrunlevel_aec_ref; + img->is_v_block = uv; + img->is_intra_block = IS_INTRA(curr_mb); + for (k = 0; (k < 65) && (level != 0); k++) { + + dp->read_syntax_element + (&curr_se, img, dp); + level = curr_se.value1; + run = curr_se.value2; + len = curr_se.len; + + if (level != 0) { + coeff_save[coeff_ptr][0] = run; + coeff_save[coeff_ptr][1] = + level; + coeff_ptr++; + } + + + if (level != 0) { + coef_ctr = coef_ctr + run + 1; + if ((img->picture_structure + == FRAME) + /*&& (!curr_mb->mb_field)*/) { + i0 = + SCAN[img->picture_structure] + [coef_ctr][0]; + j0 = + SCAN[img->picture_structure] + [coef_ctr][1]; + } else { + i0 = + SCAN[img->picture_structure] + [coef_ctr][0]; + j0 = + SCAN[img->picture_structure] + [coef_ctr][1]; + } + + } + } + + while (coeff_ptr > 0) { + + run = coeff_save[coeff_ptr - 1][0]; + level = coeff_save[coeff_ptr - 1][1]; + + coeff_ptr--; + + symbol2D = CODE2D_ESCAPE_SYMBOL; + if (level > -27 && level < 27 + && run < 26) { + if (tablenum == 0) + + symbol2D = + AVS_2DVLC_table_chroma + [tablenum][run][abs( + level) + - 1]; + else + symbol2D = + AVS_2DVLC_table_chroma + [tablenum][run][abs( + level)]; + if (symbol2D >= 0 + && level < 0) + symbol2D++; + if (symbol2D < 0) + symbol2D = + (CODE2D_ESCAPE_SYMBOL + + (run + << 1) + + ((level + > 0) ? + 1 : + 0)); + } + + else { + symbol2D = + (CODE2D_ESCAPE_SYMBOL + + (run + << 1) + + ((level + > 0) ? + 1 : + 0)); + } + + e_currse->type = SE_LUM_AC_INTER; + e_currse->value1 = symbol2D; + e_currse->value2 = 0; + e_currse->golomb_grad = + vlc_golomb_order[2] + [tablenum][0]; + e_currse->golomb_maxlevels = + vlc_golomb_order[2] + [tablenum][1]; + + writesyntaxelement_golomb(e_currse, + write_to_stream); + + /* + * if (write_to_stream) + * { + * bitCount[BITS_COEFF_UV_MB]+=e_currse->len; + * e_currse++; + * curr_mb->currSEnr++; + * } + * no_bits+=e_currse->len; + + + * if (icoef == 0) break; + */ + + if (symbol2D >= CODE2D_ESCAPE_SYMBOL) { + + e_currse->type = SE_LUM_AC_INTER; + e_currse->golomb_grad = 0; + e_currse->golomb_maxlevels = 11; + escape_level_diff = + abs(level) + - ((run + > MaxRun[2][tablenum]) ? + 1 : + refabslevel[tablenum + + 14][run]); + e_currse->value1 = + escape_level_diff; + + writesyntaxelement_golomb( + e_currse, + write_to_stream); + + } + + if (abs(level) + > incvlc_chroma[tablenum]) { + if (abs(level) <= 2) + tablenum = abs(level); + else if (abs(level) <= 4) + tablenum = 3; + else + tablenum = 4; + } + } + + } + } +} + +/* + ************************************************************************* + * Function:Get the syntax elements from the NAL + * Input: + * Output: + * Return: + * Attention: + ************************************************************************* + */ + +int read_one_macroblock(struct img_par *img) +{ + int i, j; + + struct syntaxelement curr_se; + struct macroblock *curr_mb = &mb_data[img->current_mb_nr]; + + int cabp_flag; + + int tempcbp; + int fixqp; + + struct slice_s *currslice = img->current_slice; + struct datapartition *dp; + + fixqp = (fixed_picture_qp || fixed_slice_qp); + + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) { + img->m8[0][i][j] = 0; + img->m8[1][i][j] = 0; + img->m8[2][i][j] = 0; + img->m8[3][i][j] = 0; + } + + current_mb_skip = 0; + + curr_mb->qp = img->qp; + curr_se.type = SE_MBTYPE; + curr_se.mapping = linfo_ue; + + curr_mb->mb_type_2 = 0; + + if (img->type == I_IMG) + curr_mb->mb_type = 0; + + interpret_mb_mode_i(img); + + init_macroblock(img); + + if ((IS_INTRA(curr_mb)) && (img->abt_flag)) { + +#if TRACE + strncpy(curr_se.tracestring, "cabp_flag", TRACESTRING_SIZE); +#endif + + curr_se.len = 1; + curr_se.type = SE_CABP; + read_syntaxelement_flc(&curr_se); + cabp_flag = curr_se.value1; + if (cabp_flag == 0) { + curr_mb->CABP[0] = 0; + curr_mb->CABP[1] = 0; + curr_mb->CABP[2] = 0; + curr_mb->CABP[3] = 0; + } else { + for (i = 0; i < 4; i++) { + curr_se.len = 1; + curr_se.type = SE_CABP; + read_syntaxelement_flc(&curr_se); + curr_mb->CABP[i] = curr_se.value1; + } + } + + } else { + curr_mb->CABP[0] = 0; + curr_mb->CABP[1] = 0; + curr_mb->CABP[2] = 0; + curr_mb->CABP[3] = 0; + + } + + if (IS_INTRA(curr_mb)) { + for (i = 0; i < /*5*/(chroma_format + 4); i++) + + read_ipred_block_modes(img, i); + } + + curr_se.type = SE_CBP_INTRA; + curr_se.mapping = linfo_cbp_intra; + +#if TRACE + snprintf(curr_se.tracestring, TRACESTRING_SIZE, "CBP"); +#endif + + if (img->type == I_IMG || IS_INTER(curr_mb)) { + curr_se.golomb_maxlevels = 0; + + if (1) { + dp = &(currslice->part_arr[0]); + curr_se.reading = readcp_aec; + dp->read_syntax_element(&curr_se, img, dp); + } + + + curr_mb->cbp = curr_se.value1; + push_es(UE[NCBP[curr_se.value1][0]][0], + UE[NCBP[curr_se.value1][0]][1]); + + } + +# if 1 + if (curr_mb->cbp != 0) + tempcbp = 1; + else + tempcbp = 0; +#else + + if (chroma_format == 2) { +#if TRACE + snprintf(curr_se.tracestring, TRACESTRING_SIZE, "CBP422"); +#endif + curr_se.mapping = /*linfo_se*/linfo_ue; + curr_se.type = SE_CBP_INTRA; + readsyntaxelement_uvlc(&curr_se, inp); + curr_mb->cbp01 = curr_se.value1; + io_printf(" * UE cbp01 read : 0x%02X\n", curr_mb->cbp01); + } + + if (chroma_format == 2) { + if (curr_mb->cbp != 0 || curr_mb->cbp01 != 0) + tempcbp = 1; + else + tempcbp = 0; + + } else { + if (curr_mb->cbp != 0) + tempcbp = 1; + else + tempcbp = 0; + } + +#endif + + if (IS_INTRA(curr_mb) && (img->abt_flag) && (curr_mb->cbp & (0xF))) { + curr_mb->CABT[0] = curr_mb->CABP[0]; + curr_mb->CABT[1] = curr_mb->CABP[1]; + curr_mb->CABT[2] = curr_mb->CABP[2]; + curr_mb->CABT[3] = curr_mb->CABP[3]; + } else { + + curr_mb->CABT[0] = 0; + curr_mb->CABT[1] = 0; + curr_mb->CABT[2] = 0; + curr_mb->CABT[3] = 0; + + if (!fixqp && (tempcbp)) { + if (IS_INTER(curr_mb)) + curr_se.type = SE_DELTA_QUANT_INTER; + else + curr_se.type = SE_DELTA_QUANT_INTRA; + +#if TRACE + snprintf(curr_se.tracestring, + TRACESTRING_SIZE, "Delta quant "); +#endif + + if (1) { + dp = &(currslice->part_arr[0]); + curr_se.reading = readdquant_aec; + dp->read_syntax_element(&curr_se, img, dp); + } + + curr_mb->delta_quant = curr_se.value1; +#ifdef DUMP_DEBUG + if (avs_get_debug_flag() & MB_INFO_DUMP) { + io_printf(" * SE delta_quant read : %d\n", + curr_mb->delta_quant); + } +#endif + CHECKDELTAQP + + if (transcoding_error_flag) + return -1; + + img->qp = (img->qp - MIN_QP + curr_mb->delta_quant + + (MAX_QP - MIN_QP + 1)) + % (MAX_QP - MIN_QP + 1) + MIN_QP; + } + + if (fixqp) { + curr_mb->delta_quant = 0; + img->qp = (img->qp - MIN_QP + curr_mb->delta_quant + + (MAX_QP - MIN_QP + 1)) + % (MAX_QP - MIN_QP + 1) + MIN_QP; + + } +#ifdef DUMP_DEBUG + if (avs_get_debug_flag() & MB_INFO_DUMP) + io_printf(" - img->qp : %d\n", img->qp); +#endif + } + + read_cbpandcoeffsfrom_nal(img); + return DECODE_MB; +} + +/*! + ************************************************************************ + * \brief + * finding end of a slice in case this is not the end of a frame + * + * Unsure whether the "correction" below actually solves an off-by-one + * problem or whether it introduces one in some cases :-( Anyway, + * with this change the bit stream format works with AEC again. + * StW, 8.7.02 + ************************************************************************ + */ +int aec_startcode_follows(struct img_par *img, int eos_bit) +{ + struct slice_s *currslice = img->current_slice; + struct datapartition *dp; + unsigned int bit; + struct decoding_environment_s *dep_dp; + + dp = &(currslice->part_arr[0]); + dep_dp = &(dp->de_aec); + + if (eos_bit) + bit = biari_decode_final(dep_dp); + else + bit = 0; + + return bit == 1 ? 1 : 0; +} + +#ifdef AVSP_LONG_CABAC +int process_long_cabac(void) +#else +void main(void) +#endif +{ + int data32; + int current_header; + int i; + int tmp; + int ret; + + int byte_startposition; + int aec_mb_stuffing_bit; + struct slice_s *currslice; +#ifdef PERFORMANCE_DEBUG + pr_info("enter %s\r\n", __func__); +#endif + transcoding_error_flag = 0; + ret = 0; + es_buf = es_write_addr_virt; + + if (local_heap_init(MAX_CODED_FRAME_SIZE * 4) < 0) { + ret = -1; + goto End; + } + + img = (struct img_par *)local_alloc(1, sizeof(struct img_par)); + if (img == NULL) { + no_mem_exit("main: img"); + ret = -1; + goto End; + } + stat_bits_ptr = (struct stat_bits *)local_alloc(1, + sizeof(struct stat_bits)); + if (stat_bits_ptr == NULL) { + no_mem_exit("main: stat_bits"); + ret = -1; + goto End; + } + + curr_stream = alloc_bitstream(); + if (curr_stream == NULL) { + io_printf("alloc bitstream failed\n"); + ret = -1; + goto End; + } + + chroma_format = 1; + demulate_enable = 0; + img->seq_header_indicate = 1; + +#ifdef AVSP_LONG_CABAC + data32 = READ_VREG(LONG_CABAC_REQ); + progressive_sequence = (data32 >> 1) & 1; + fixed_picture_qp = (data32 >> 2) & 1; + img->picture_structure = (data32 >> 3) & 1; + img->type = (data32 >> 4) & 3; + skip_mode_flag = (data32 >> 6) & 1; + + src_start = READ_VREG(LONG_CABAC_SRC_ADDR); + des_start = READ_VREG(LONG_CABAC_DES_ADDR); + + data32 = READ_VREG(LONG_CABAC_PIC_SIZE); + horizontal_size = (data32 >> 0) & 0xffff; + vertical_size = (data32 >> 16) & 0xffff; + if (horizontal_size * vertical_size > 1920 * 1080) { + io_printf("pic size check failed: width = %d, height = %d\n", + horizontal_size, vertical_size); + ret = -1; + goto End; + } + + vld_mem_start_addr = READ_VREG(VLD_MEM_VIFIFO_START_PTR); + vld_mem_end_addr = READ_VREG(VLD_MEM_VIFIFO_END_PTR); + +#else + progressive_sequence = 0; + fixed_picture_qp = 0; + img->picture_structure = 0; + img->type = I_IMG; + skip_mode_flag = 1; + horizontal_size = 1920; + vertical_size = 1080; + + src_start = 0; +#endif + + if (horizontal_size % 16 != 0) + img->auto_crop_right = 16 - (horizontal_size % 16); + else + img->auto_crop_right = 0; + + if (!progressive_sequence) { + if (vertical_size % 32 != 0) + img->auto_crop_bottom = 32 - (vertical_size % 32); + else + img->auto_crop_bottom = 0; + } else { + if (vertical_size % 16 != 0) + img->auto_crop_bottom = 16 - (vertical_size % 16); + else + img->auto_crop_bottom = 0; + } + + img->width = (horizontal_size + img->auto_crop_right); + if (img->picture_structure) + img->height = (vertical_size + img->auto_crop_bottom); + else + img->height = (vertical_size + img->auto_crop_bottom) / 2; + img->width_cr = (img->width >> 1); + + img->pic_width_inmbs = img->width / MB_BLOCK_SIZE; + img->pic_height_inmbs = img->height / MB_BLOCK_SIZE; + img->pic_size_inmbs = img->pic_width_inmbs * img->pic_height_inmbs; + + io_printf( + "[LONG CABAC] Start Transcoding from 0x%x to 0x%x Size : %d x %d\r\n", + src_start, des_start, horizontal_size, vertical_size); +#if 0 + io_printf("VLD_MEM_VIFIFO_START_PTR %x\r\n", + READ_VREG(VLD_MEM_VIFIFO_START_PTR)); + io_printf("VLD_MEM_VIFIFO_CURR_PTR %x\r\n", + READ_VREG(VLD_MEM_VIFIFO_CURR_PTR)); + io_printf("VLD_MEM_VIFIFO_END_PTR %x\r\n", + READ_VREG(VLD_MEM_VIFIFO_END_PTR)); + io_printf("VLD_MEM_VIFIFO_WP %x\r\n", + READ_VREG(VLD_MEM_VIFIFO_WP)); + io_printf("VLD_MEM_VIFIFO_RP %x\r\n", + READ_VREG(VLD_MEM_VIFIFO_RP)); + io_printf("VLD_MEM_VBUF_RD_PTR %x\r\n", + READ_VREG(VLD_MEM_VBUF_RD_PTR)); + io_printf("VLD_MEM_VIFIFO_BUF_CNTL %x\r\n", + READ_VREG(VLD_MEM_VIFIFO_BUF_CNTL)); +#endif + io_printf( + "[LONG CABAC] progressive_sequence : %d, fixed_picture_qp : %d, skip_mode_flag : %d\r\n", + progressive_sequence, fixed_picture_qp, skip_mode_flag); + io_printf("[LONG CABAC] picture_structure : %d, picture_type : %d\r\n", + img->picture_structure, img->type); + + open_irabs(p_irabs); + + + if (initial_decode() == 0) { + io_printf("initial_decode failed\n"); + ret = -1; + goto End; + } + + init_es(); + + current_header = header(); + io_printf("[LONG CABAC] header Return : %d\n", current_header); + + tmp = slice_header(temp_slice_buf, first_slice_startpos, + first_slice_length); + + init_contexts(img); + aec_new_slice(); + byte_startposition = (curr_stream->frame_bitoffset) / 8; + + currslice = img->current_slice; + + if (1) { + for (i = 0; i < 1; i++) { + img->current_slice->part_arr[i].read_syntax_element = + read_syntaxelement_aec; + img->current_slice->part_arr[i].bitstream = curr_stream; + } + curr_stream = currslice->part_arr[0].bitstream; + } + if ((curr_stream->frame_bitoffset) % 8 != 0) + byte_startposition++; + + arideco_start_decoding(&img->current_slice->part_arr[0].de_aec, + curr_stream->stream_buffer, (byte_startposition), + &(curr_stream->read_len), img->type); + + img->current_mb_nr = 0; + total_mb_count = 0; + while (img->current_mb_nr < img->pic_size_inmbs) + + { + start_macroblock(img); + if (-1 == read_one_macroblock(img)) { + ret = -1; + pr_info("macroblock trans failed, exit\n"); + goto End; + } + if (img->cod_counter <= 0) + aec_mb_stuffing_bit = aec_startcode_follows(img, 1); + img->current_mb_nr++; + } + + push_es(0xff, 8); + io_printf(" Total ES_LENGTH : %d\n", es_ptr); + +#ifdef AVSP_LONG_CABAC + push_es(0xff, 64); + if (es_buf_is_overflow) { + io_printf("fatal error: es_buf_is_overflow\n"); + ret = -1; + goto End; + } + + if (transcoding_error_flag == 0) { +#if 1 + dma_sync_single_for_device(amports_get_dma_device(), + es_write_addr_phy, + es_ptr, DMA_TO_DEVICE); + + wmb(); /**/ +#endif + } +#else + fclose(f_es); +#endif + +End: +#ifdef AVSP_LONG_CABAC + WRITE_VREG(LONG_CABAC_REQ, 0); +#endif + local_heap_uninit(); +#ifdef PERFORMANCE_DEBUG + pr_info("exit %s\r\n", __func__); +#endif + return ret; +} +#endif
diff --git a/drivers/frame_provider/decoder/avs2/Makefile b/drivers/frame_provider/decoder/avs2/Makefile new file mode 100644 index 0000000..5fe8566 --- /dev/null +++ b/drivers/frame_provider/decoder/avs2/Makefile
@@ -0,0 +1,2 @@ +obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_AVS2) += amvdec_avs2.o +amvdec_avs2-objs += vavs2.o avs2_bufmgr.o
diff --git a/drivers/frame_provider/decoder/avs2/avs2_bufmgr.c b/drivers/frame_provider/decoder/avs2/avs2_bufmgr.c new file mode 100644 index 0000000..de9a3d2 --- /dev/null +++ b/drivers/frame_provider/decoder/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 "../utils/decoder_mmu_box.h" +#include "../utils/decoder_bmmu_box.h" +#include "avs2_global.h" + +#include <linux/amlogic/media/utils/vdec_reg.h> +#include "../utils/vdec.h" +#include "../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/avs2/avs2_global.h b/drivers/frame_provider/decoder/avs2/avs2_global.h new file mode 100644 index 0000000..be35a5e --- /dev/null +++ b/drivers/frame_provider/decoder/avs2/avs2_global.h
@@ -0,0 +1,1690 @@ +/* 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; + /*AVS2_10B_MMU_DW*/ + unsigned long dw_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/avs2/vavs2.c b/drivers/frame_provider/decoder/avs2/vavs2.c new file mode 100644 index 0000000..e21dc55 --- /dev/null +++ b/drivers/frame_provider/decoder/avs2/vavs2.c
@@ -0,0 +1,8623 @@ + /* + * 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 "../utils/decoder_mmu_box.h" +#include "../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 "../utils/vdec.h" +#include "../utils/amvdec.h" + +#include <linux/amlogic/media/video_sink/video.h> +#include <linux/amlogic/media/codec_mm/configs.h> +#include "../utils/config_parser.h" +#include "../utils/firmware.h" +#include "../../../common/chips/decoder_cpu_ver_info.h" +#include "../utils/vdec_feature.h" + +#define I_ONLY_SUPPORT +#define MIX_STREAM_SUPPORT +#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 +*/ +/*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" + +#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]; + +static u32 decode_timeout_val = 200; + +static int start_decode_buf_level = 0x8000; + +static u32 work_buf_size; + +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" +#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 int vavs2_stop(struct AVS2Decoder_s *dec); +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 + +#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*/ + +#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) +//#define DW_HEADER_BUFFER_IDX(n) ((FRAME_BUFFERS * 3) + n+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 +#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; +#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; + u32 vavs2_ratio; + 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; + +#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]; + 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]; + u32 vf_pre_count; + u32 vf_get_count; + u32 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) +{ + 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) +{ + 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; + + 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 + +#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 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); +} +#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 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 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 +#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 = 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 = 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 +#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*/ + }, +#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 +#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*/ + }, +#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 +#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, + }, +#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); + #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 = + 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); + #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 = + 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 + #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 + 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) +{ +#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; + + 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; + + 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); + } + 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; + + 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 && ((dw_mode & 0x20) == 0)) { + 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; + + +#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 + + i = pic->index; + +#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->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; + 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; +} + +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 + 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 + 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) & 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); + 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 +#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);*/ + 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); +#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) { + 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) & 0xf) == 8 || + (get_double_write_mode(dec) & 0xf) == 9) { + data32 |= (0xff<<16); + 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 &= (~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 +#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, + 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 +#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); + + 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 + +#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); + + 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 +} + +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 struct AVS2Decoder_s gAVS2Decoder; + +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 + +#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; +} + +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 ((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 ? + 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); + +#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_ptr = dec->lmem_addr; + +#ifdef AVS2_10B_MMU + 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)); + } +#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; +} + +/******************************************** + * 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 = 0; + unsigned int pixel_ratio = 0;; + + 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); + + pixel_ratio = dec->vavs2_amstream_dec_info.ratio; + + if (dec->vavs2_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 * dec->vavs2_ratio) / vf->width; + break; + case 2: + vf->sar_width = 4; + vf->sar_height = 3; + ar = (vf->height * 3 * dec->vavs2_ratio) / (vf->width * 4); + break; + case 3: + vf->sar_width = 16; + vf->sar_height = 9; + ar = (vf->height * 9 * dec->vavs2_ratio) / (vf->width * 16); + break; + case 4: + vf->sar_width = 221; + vf->sar_height = 100; + ar = (vf->height * 100 * dec->vavs2_ratio) / (vf->width * + 221); + break; + default: + vf->sar_width = 1; + vf->sar_height = 1; + ar = (vf->height * dec->vavs2_ratio) / vf->width; + break; + } + } + + ar = min_t(u32, 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_len(&dec->display_q) > VF_POOL_SIZE) { + avs2_print(dec, AVS2_DBG_BUFMGR, + "kfifo len:%d invaild, peek error\n", + kfifo_len(&dec->display_q)); + return NULL; + } + + 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; + } + 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)); + 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 = 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 && (pic->double_write_mode & 0x20) == 0) + 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 ((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); + dec->last_pts = vf->pts; + + if (vf->pts_us64 != 0) + dec->last_lookup_pts_us64 = vf->pts_us64; + + 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); + } + + 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; +#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; +#endif + } + if (pic->double_write_mode && + ((pic->double_write_mode & 0x20) == 0)) { + 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; + } + 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) + vf->duration = 96000/rate; + else + vf->duration = 0; + } +#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, + 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); + } + 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->pts); + 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); +#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 + } + } + } + } + } + + 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 + + if (ret >= 0) { +#ifdef AVS2_10B_MMU + if (dec->mmu_enable) { + 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 +#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-> + 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 + if (dec->mmu_enable) + 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->vavs2_ratio = dec->vavs2_amstream_dec_info.ratio; + + 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 vavs2_stop(struct AVS2Decoder_s *dec) +{ + + dec->init_flag = 0; + dec->first_sc_checked = 0; + 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; + } + + 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); + + if (dec->m_ins_flag) + cancel_work_sync(&dec->work); + else + amhevc_disable(); + uninit_mmu_buffers(dec); + + 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; + + dec->need_cache_size = buf_size * SZ_1M; + dec->sc_start_time = get_jiffies_64(); +#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( + 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 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 AVS2Decoder_s *dec = &gAVS2Decoder; + int ret; + pr_info("%s\n", __func__); + + 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; + dec->eos = 0; + dec->start_process_time = 0; + dec->timeout_num = 0; + dec->fatal_error = 0; + dec->show_frame_num = 0; + if (pdata == NULL) { + avs2_print(dec, 0, + "\namvdec_avs2 memory resource undefined.\n"); + mutex_unlock(&vavs2_mutex); + return -EFAULT; + } + dec->m_ins_flag = 0; + 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"); + return -1; + } + + ret = decoder_bmmu_box_alloc_buf_phy(dec->bmmu_box, WORK_SPACE_BUF_ID, + work_buf_size, DRIVER_NAME, &pdata->mem_start); + if (ret < 0) { + uninit_mmu_buffers(dec); + mutex_unlock(&vavs2_mutex); + return ret; + } + dec->buf_size = work_buf_size; + + dec->buf_start = pdata->mem_start; + + + if (debug) { + avs2_print(dec, 0, + "===AVS2 decoder mem resource 0x%lx size 0x%x\n", + pdata->mem_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->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;*/ + is_reset = 0; + if (vavs2_init(pdata) < 0) { + pr_info("\namvdec_avs2 init failed.\n"); + avs2_local_uninit(dec); + uninit_mmu_buffers(dec); + pdata->dec_status = NULL; + mutex_unlock(&vavs2_mutex); + return -ENODEV; + } + /*set the max clk for smooth playing...*/ + hevc_source_changed(VFORMAT_AVS2, + 4096, 2048, 60); + mutex_unlock(&vavs2_mutex); + + return 0; +} + +static int amvdec_avs2_remove(struct platform_device *pdev) +{ + struct AVS2Decoder_s *dec = &gAVS2Decoder; + if (debug) + pr_info("amvdec_avs2_remove\n"); + + mutex_lock(&vavs2_mutex); + + vavs2_stop(dec); + + + hevc_source_changed(VFORMAT_AVS2, 0, 0, 0); + + +#ifdef DEBUG_PTS + pr_info("pts missed %ld, pts hit %ld, duration %d\n", + dec->pts_missed, dec->pts_hit, dec->frame_dur); +#endif + + mutex_unlock(&vavs2_mutex); + + return 0; +} + +/****************************************/ + +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, + } +}; + +static struct codec_profile_t amvdec_avs2_profile = { + .name = "avs2", + .profile = "" +}; + +static struct codec_profile_t amvdec_avs2_profile_mult; + +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 + 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", + __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; + + 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 = vzalloc(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-pts", 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 ((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 { + /*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 (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); */ + 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; + + 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 (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"); + 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"); + + if (platform_driver_register(&amvdec_avs2_driver)) { + pr_err("failed to register amvdec_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); + amvdec_avs2_profile_mult = amvdec_avs2_profile; + amvdec_avs2_profile_mult.name = "mavs2"; + vcodec_profile_register(&amvdec_avs2_profile_mult); + + INIT_REG_NODE_CONFIGS("media.decoder", &avs2_node, + "avs2", avs2_configs, CONFIG_FOR_RW); + vcodec_feature_register(VFORMAT_AVS2, 0); + + return 0; +} + +static void __exit amvdec_avs2_driver_remove_module(void) +{ + pr_debug("amvdec_avs2 module remove.\n"); + platform_driver_unregister(&ammvdec_avs2_driver); + platform_driver_unregister(&amvdec_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/avs2/vavs2.h b/drivers/frame_provider/decoder/avs2/vavs2.h new file mode 100644 index 0000000..071bfb3 --- /dev/null +++ b/drivers/frame_provider/decoder/avs2/vavs2.h
@@ -0,0 +1,26 @@ +/* + * drivers/amlogic/amports/vavs2.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 VAVS2_H +#define VAVS2_H + +#define AVS2_10B_MMU +#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); +#endif
diff --git a/drivers/frame_provider/decoder/avs_multi/Makefile b/drivers/frame_provider/decoder/avs_multi/Makefile new file mode 100644 index 0000000..638cec0 --- /dev/null +++ b/drivers/frame_provider/decoder/avs_multi/Makefile
@@ -0,0 +1,2 @@ +obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_AVS_MULTI) += amvdec_mavs.o +amvdec_mavs-objs += avs_multi.o
diff --git a/drivers/frame_provider/decoder/avs_multi/avs_multi.c b/drivers/frame_provider/decoder/avs_multi/avs_multi.c new file mode 100644 index 0000000..7dd20bb --- /dev/null +++ b/drivers/frame_provider/decoder/avs_multi/avs_multi.c
@@ -0,0 +1,5030 @@ +/* + * 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 "../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 "../utils/decoder_mmu_box.h" +#include "../utils/decoder_bmmu_box.h" +#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 +/* +#define DEBUG_WITH_SINGLE_MODE +#define DEBUG_MULTI_WITH_AUTOMODE +#define DEBUG_MULTI_FRAME_INS +*/ + + +#define USE_DYNAMIC_BUF_NUM + +#ifdef DEBUG_WITH_SINGLE_MODE +#define DRIVER_NAME "amvdec_avs" +#else +#define DRIVER_NAME "ammvdec_avs" +#endif + +#define MULTI_DRIVER_NAME "ammvdec_avs" + +#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; + u32 prepare_num; + u32 put_num; + u32 peek_num; + u32 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); + 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; + hw->peek_num++; + if (step == 2) + return NULL; + if (hw->recover_flag) + return NULL; + + if (kfifo_len(&hw->display_q) > VF_POOL_SIZE) { + debug_print(hw, PRINT_FLAG_RUN_FLOW, + "kfifo len:%d invaild, peek error\n", + kfifo_len(&hw->display_q)); + 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) { + 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) { + 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 + CLEAR_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 + CLEAR_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->pts); + 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->pts); + 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->pts); + 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-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); + + 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 + CLEAR_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 = "mavs", + .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"); +#ifdef DEBUG_WITH_SINGLE_MODE + if (platform_driver_register(&amvdec_avs_driver)) { + 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+"; + + 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; +} + + + +static void __exit ammvdec_avs_driver_remove_module(void) +{ + pr_debug("ammvdec_avs module remove.\n"); + + platform_driver_unregister(&ammvdec_avs_driver); +#ifdef DEBUG_WITH_SINGLE_MODE + platform_driver_unregister(&amvdec_avs_driver); +#endif +} + +/****************************************/ +/* +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/avs_multi/avs_multi.h b/drivers/frame_provider/decoder/avs_multi/avs_multi.h new file mode 100644 index 0000000..8922b40 --- /dev/null +++ b/drivers/frame_provider/decoder/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/h264/Makefile b/drivers/frame_provider/decoder/h264/Makefile new file mode 100644 index 0000000..b7c85ee --- /dev/null +++ b/drivers/frame_provider/decoder/h264/Makefile
@@ -0,0 +1,6 @@ +obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_H264) += amvdec_h264.o +amvdec_h264-objs += vh264.o + +obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_H264_MVC) += amvdec_h264mvc.o +amvdec_h264mvc-objs += vh264_mvc.o +
diff --git a/drivers/frame_provider/decoder/h264/vh264.c b/drivers/frame_provider/decoder/h264/vh264.c new file mode 100644 index 0000000..55f0581 --- /dev/null +++ b/drivers/frame_provider/decoder/h264/vh264.c
@@ -0,0 +1,4509 @@ +/* + * drivers/amlogic/media/frame_provider/decoder/h264/vh264.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. + * + */ + +#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/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/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 "../../../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" +#include "vh264.h" +#include "../../../stream_input/amports/streambuf.h" +#include <linux/delay.h> +#include <linux/amlogic/media/video_sink/video.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 "../../../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" +#define HANDLE_H264_IRQ + +#if 0 +/* currently, only iptv supports this function*/ +#define SUPPORT_BAD_MACRO_BLOCK_REDUNDANCY +#endif + +/* #define DEBUG_PTS */ +#if 0 /* MESON_CPU_TYPE <= MESON_CPU_TYPE_MESON6TV */ +#define DROP_B_FRAME_FOR_1080P_50_60FPS +#endif +#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 VDEC_CLOCK_ADJUST_FRAME 30 + +static inline bool close_to(int a, int b, int m) +{ + return (abs(a - b) < m) ? true : false; +} + +static DEFINE_MUTEX(vh264_mutex); +#define DEF_BUF_START_ADDR 0x1000000 +#define V_BUF_ADDR_OFFSET_NEW (0x1ee000) +#define V_BUF_ADDR_OFFSET (0x13e000) + +#define PIC_SINGLE_FRAME 0 +#define PIC_TOP_BOT_TOP 1 +#define PIC_BOT_TOP_BOT 2 +#define PIC_DOUBLE_FRAME 3 +#define PIC_TRIPLE_FRAME 4 +#define PIC_TOP_BOT 5 +#define PIC_BOT_TOP 6 +#define PIC_INVALID 7 + +#define EXTEND_SAR 0xff + +#define VF_POOL_SIZE 64 +#define VF_BUF_NUM 24 +#define WORKSPACE_BUF_NUM 2 +#define PUT_INTERVAL (HZ/100) +#define NO_DISP_WD_COUNT (3 * HZ / PUT_INTERVAL) + +#define SWITCHING_STATE_OFF 0 +#define SWITCHING_STATE_ON_CMD3 1 +#define SWITCHING_STATE_ON_CMD1 2 +#define SWITCHING_STATE_ON_CMD1_PENDING 3 + + +#define DEC_CONTROL_FLAG_FORCE_2997_1080P_INTERLACE 0x0001 +#define DEC_CONTROL_FLAG_FORCE_2500_576P_INTERLACE 0x0002 +#define DEC_CONTROL_FLAG_DISABLE_FAST_POC 0x0004 + +#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 { + unsigned int y_addr; + unsigned int u_addr; + unsigned int v_addr; + + int y_canvas_index; + int u_canvas_index; + int v_canvas_index; + + unsigned int y_canvas_width; + unsigned int u_canvas_width; + unsigned int v_canvas_width; + + unsigned int y_canvas_height; + unsigned int u_canvas_height; + unsigned int v_canvas_height; + + unsigned long phy_addr; + int alloc_count; +}; + +#define spec2canvas(x) \ + (((x)->v_canvas_index << 16) | \ + ((x)->u_canvas_index << 8) | \ + ((x)->y_canvas_index << 0)) + +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_prot_init(void); +static int vh264_local_init(void); +static void vh264_put_timer_func(struct timer_list *timer); +static void stream_switching_done(void); + +static const char vh264_dec_id[] = "vh264-dev"; + +#define PROVIDER_NAME "decoder.h264" + +static const struct vframe_operations_s vh264_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, +}; + +static struct vframe_provider_s vh264_vf_prov; +/*TODO irq*/ +#if 1 +static u32 frame_width, frame_height, frame_dur, frame_prog, frame_packing_type, + last_duration; +static u32 saved_resolution; +static u32 last_mb_width, last_mb_height; +#else +static u32 frame_buffer_size; +static u32 frame_width, frame_height, frame_dur, frame_prog, last_duration; +static u32 last_mb_width, last_mb_height; +static u32 frame_packing_type; +#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); +static DECLARE_KFIFO(delay_display_q, struct vframe_s *, VF_POOL_SIZE); + +static struct vframe_s vfpool[VF_POOL_SIZE]; +static s32 vfbuf_use[VF_BUF_NUM]; +static struct buffer_spec_s buffer_spec[VF_BUF_NUM]; +static struct buffer_spec_s fense_buffer_spec[2]; +/* disp buf + keep buf+ fense buf + workspace */ + +#define MAX_BLK_BUFFERS (VF_BUF_NUM + 2 + WORKSPACE_BUF_NUM) +#define VF_BUFFER_IDX(n) (WORKSPACE_BUF_NUM + n) +#define FENSE_BUFFER_IDX(n) (WORKSPACE_BUF_NUM + VF_BUF_NUM + n) + +#define USER_DATA_RUND_SIZE (USER_DATA_SIZE + 4096) +static struct vframe_s fense_vf[2]; + +static struct timer_list recycle_timer; +static u32 stat; +static s32 buf_offset; +static u32 pts_outside; +static u32 sync_outside; +static u32 dec_control; +static u32 vh264_ratio; +static u32 vh264_rotation; +static u32 use_idr_framerate; +static u32 high_bandwidth; + +static u32 seq_info; +static u32 timing_info_present_flag; +static u32 fixed_frame_rate_flag; +static u32 fixed_frame_rate_check_count; +static u32 aspect_ratio_info; +static u32 num_units_in_tick; +static u32 time_scale; +static u32 h264_ar; +static u32 decoder_debug_flag; +static u32 dpb_size_adj = 6; +static u32 fr_hint_status; + +#ifdef DROP_B_FRAME_FOR_1080P_50_60FPS +static u32 last_interlaced; +#endif +static bool is_4k; +static unsigned char h264_first_pts_ready; +static bool h264_first_valid_pts_ready; +static u32 h264pts1, h264pts2; +static u32 h264_pts_count, duration_from_pts_done, duration_on_correcting; +static u32 vh264_error_count; +static u32 vh264_no_disp_count; +static u32 fatal_error_flag; +static u32 fatal_error_reset; +static u32 max_refer_buf = 1; +static u32 decoder_force_reset; +static unsigned int no_idr_error_count; +static unsigned int no_idr_error_max = 60; +static unsigned int canvas_mode; + +#ifdef SUPPORT_BAD_MACRO_BLOCK_REDUNDANCY +/* 0~128*/ +static u32 bad_block_scale; +#endif +static u32 enable_userdata_debug; + +static unsigned int enable_switch_fense = 1; +#define EN_SWITCH_FENCE() (enable_switch_fense && !is_4k) +static struct vframe_qos_s s_vframe_qos; +static int frame_count; + +#if 0 +static u32 vh264_no_disp_wd_count; +#endif +static u32 vh264_running; +static s32 vh264_stream_switching_state; +static s32 vh264_eos; +static struct vframe_s *p_last_vf; +static s32 iponly_early_mode; +static void *mm_blk_handle; +static int tvp_flag; +static bool is_reset; + +/*TODO irq*/ +#if 1 +static u32 last_pts, last_pts_remainder; +#else +static u32 last_pts; +#endif +static bool check_pts_discontinue; +static u32 wait_buffer_counter; +static u32 video_signal_from_vui; + +static uint error_recovery_mode; +static uint error_recovery_mode_in = 3; +static uint error_recovery_mode_use = 3; + +static uint mb_total = 0, mb_width = 0, mb_height; +static uint saved_idc_level; +#define UCODE_IP_ONLY 2 +#define UCODE_IP_ONLY_PARAM 1 +static uint ucode_type; + +#ifdef DEBUG_PTS +static unsigned long pts_missed, pts_hit; +#endif +static uint debugfirmware; + +static atomic_t vh264_active = ATOMIC_INIT(0); +static int vh264_reset; +static struct work_struct error_wd_work; +static struct work_struct stream_switching_work; +static struct work_struct set_parameter_work; +static struct work_struct notify_work; +static struct work_struct set_clk_work; +static struct work_struct userdata_push_work; + +struct h264_qos_data_node_t { + struct list_head list; + + uint32_t b_offset; + int poc; + /* 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; +}; + +/*qos data records list waiting for match with picture that be display*/ +static struct list_head picture_qos_list; +/*free qos data records list*/ +static struct list_head free_qos_nodes_list; +#define MAX_FREE_QOS_NODES 64 +static struct h264_qos_data_node_t free_nodes[MAX_FREE_QOS_NODES]; +static struct work_struct qos_work; +static struct dec_sysinfo vh264_amstream_dec_info; +static dma_addr_t mc_dma_handle; +static void *mc_cpu_addr; +static u32 first_offset; +static u32 first_pts; +static u32 first_frame_size; +static u64 first_pts64; +static bool first_pts_cached; +static void *sei_data_buffer; +static dma_addr_t sei_data_buffer_phys; +static int clk_adj_frame_count; + +#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_TOTAL_SIZE (20*SZ_1K) +#define MC_SWAP_SIZE (4*SZ_1K) + +#define MODE_ERROR 0 +#define MODE_FULL 1 + +static DEFINE_SPINLOCK(lock); +static DEFINE_SPINLOCK(prepare_lock); +static DEFINE_SPINLOCK(recycle_lock); + +static bool block_display_q; +static int vh264_stop(int mode); +static s32 vh264_init(void); + + +#define DFS_HIGH_THEASHOLD 3 + +static bool pts_discontinue; + +static struct ge2d_context_s *ge2d_videoh264_context; + +static struct vdec_info *gvs; + +static struct vdec_s *vdec_h264; + +static int ge2d_videoh264task_init(void) +{ + if (ge2d_videoh264_context == NULL) + ge2d_videoh264_context = create_ge2d_work_queue(); + + if (ge2d_videoh264_context == NULL) { + pr_info("create_ge2d_work_queue video task failed\n"); + return -1; + } + return 0; +} + +static int ge2d_videoh264task_release(void) +{ + if (ge2d_videoh264_context) { + destroy_ge2d_work_queue(ge2d_videoh264_context); + ge2d_videoh264_context = NULL; + } + return 0; +} + +static int ge2d_canvas_dup(struct canvas_s *srcy, struct canvas_s *srcu, + struct canvas_s *des, int format, u32 srcindex, + u32 desindex) +{ + + struct config_para_ex_s ge2d_config; + /* pr_info("[%s]h264 ADDR srcy[0x%lx] srcu[0x%lx] des[0x%lx]\n", + * __func__, srcy->addr, srcu->addr, des->addr); + */ + memset(&ge2d_config, 0, sizeof(struct config_para_ex_s)); + + ge2d_config.alu_const_color = 0; + ge2d_config.bitmask_en = 0; + ge2d_config.src1_gb_alpha = 0; + + ge2d_config.src_planes[0].addr = srcy->addr; + ge2d_config.src_planes[0].w = srcy->width; + ge2d_config.src_planes[0].h = srcy->height; + + ge2d_config.src_planes[1].addr = srcu->addr; + ge2d_config.src_planes[1].w = srcu->width; + ge2d_config.src_planes[1].h = srcu->height; + + ge2d_config.dst_planes[0].addr = des->addr; + ge2d_config.dst_planes[0].w = des->width; + ge2d_config.dst_planes[0].h = des->height; + + ge2d_config.src_para.canvas_index = srcindex; + ge2d_config.src_para.mem_type = CANVAS_TYPE_INVALID; + ge2d_config.src_para.format = format; + ge2d_config.src_para.fill_color_en = 0; + ge2d_config.src_para.fill_mode = 0; + ge2d_config.src_para.color = 0; + ge2d_config.src_para.top = 0; + ge2d_config.src_para.left = 0; + ge2d_config.src_para.width = srcy->width; + ge2d_config.src_para.height = srcy->height; + + ge2d_config.dst_para.canvas_index = desindex; + ge2d_config.dst_para.mem_type = CANVAS_TYPE_INVALID; + ge2d_config.dst_para.format = format; + ge2d_config.dst_para.fill_color_en = 0; + ge2d_config.dst_para.fill_mode = 0; + ge2d_config.dst_para.color = 0; + ge2d_config.dst_para.top = 0; + ge2d_config.dst_para.left = 0; + ge2d_config.dst_para.width = srcy->width; + ge2d_config.dst_para.height = srcy->height; + + if (ge2d_context_config_ex(ge2d_videoh264_context, &ge2d_config) < 0) { + pr_info("ge2d_context_config_ex failed\n"); + return -1; + } + + stretchblt_noalpha(ge2d_videoh264_context, 0, 0, srcy->width, + srcy->height, 0, 0, srcy->width, srcy->height); + + return 0; +} + +static inline int fifo_level(void) +{ + return VF_POOL_SIZE - kfifo_len(&newframe_q); +} + + +void spec_set_canvas(struct buffer_spec_s *spec, + unsigned int width, unsigned int height) +{ + int endian; + + endian = (canvas_mode == CANVAS_BLKMODE_LINEAR)?7:0; + config_cav_lut_ex(spec->y_canvas_index, + spec->y_addr, + width, height, + CANVAS_ADDR_NOWRAP, canvas_mode, endian, VDEC_1); + + config_cav_lut_ex(spec->u_canvas_index, + spec->u_addr, + width, height / 2, + CANVAS_ADDR_NOWRAP, canvas_mode, endian, VDEC_1); + +} + +static void vh264_notify_work(struct work_struct *work) +{ + pr_info("frame duration changed %d\n", frame_dur); + vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_FR_HINT, + (void *)((unsigned long)frame_dur)); + + return; +} + +static void prepare_display_q(void) +{ + unsigned long flags; + int count; + + spin_lock_irqsave(&prepare_lock, flags); + + if (block_display_q) { + spin_unlock_irqrestore(&prepare_lock, flags); + return; + } + + spin_unlock_irqrestore(&prepare_lock, flags); + + count = (int)VF_POOL_SIZE - + kfifo_len(&delay_display_q) - + kfifo_len(&display_q) - + kfifo_len(&recycle_q) - + kfifo_len(&newframe_q); + + if ((vh264_stream_switching_state != SWITCHING_STATE_OFF) + || !EN_SWITCH_FENCE()) + count = 0; + else + count = (count < 2) ? 0 : 2; + + while (kfifo_len(&delay_display_q) > count) { + struct vframe_s *vf; + + if (kfifo_get(&delay_display_q, &vf)) { + 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); + } + } +} + +static struct vframe_s *vh264_vf_peek(void *op_arg) +{ + struct vframe_s *vf; + + if (kfifo_peek(&display_q, &vf)) + return vf; + + return NULL; +} + +static struct vframe_s *vh264_vf_get(void *op_arg) +{ + struct vframe_s *vf; + + if (kfifo_get(&display_q, &vf)) + return vf; + + return NULL; +} +static bool vf_valid_check(struct vframe_s *vf) { + int i; + for (i = 0; i < VF_POOL_SIZE; i++) { + if (vf == &vfpool[i]) + return true; + } + pr_info(" invalid vf been put, vf = %p\n", vf); + for (i = 0; i < VF_POOL_SIZE; i++) { + pr_info("www valid vf[%d]= %p \n", i, &vfpool[i]); + } + return false; +} + +static void vh264_vf_put(struct vframe_s *vf, void *op_arg) +{ + unsigned long flags; + + spin_lock_irqsave(&recycle_lock, flags); + + if ((vf != &fense_vf[0]) && (vf != &fense_vf[1])) { + if (vf && (vf_valid_check(vf) == true)) + kfifo_put(&recycle_q, (const struct vframe_s *)vf); + } + spin_unlock_irqrestore(&recycle_lock, flags); +} + +static int vh264_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(&vh264_vf_prov); +#endif + spin_lock_irqsave(&lock, flags); + vh264_local_init(); + vh264_prot_init(); + spin_unlock_irqrestore(&lock, flags); +#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER + vf_reg_provider(&vh264_vf_prov); +#endif + amvdec_start(); + } + return 0; +} + +static int vh264_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) + + kfifo_len(&delay_display_q); + states->buf_recycle_num = kfifo_len(&recycle_q); + + spin_unlock_irqrestore(&lock, flags); + + return 0; +} + +#if 0 +static tvin_trans_fmt_t convert_3d_format(u32 type) +{ + const tvin_trans_fmt_t conv_tab[] = { + 0, /* checkerboard */ + 0, /* column alternation */ + TVIN_TFMT_3D_LA, /* row alternation */ + TVIN_TFMT_3D_LRH_OLER, /* side by side */ + TVIN_TFMT_3D_FA /* top bottom */ + }; + + return (type <= 4) ? conv_tab[type] : 0; +} +#endif + + + +#define DUMP_CC_AS_ASCII + +#ifdef DUMP_CC_AS_ASCII +static int vbi_to_ascii(int c) +{ + if (c < 0) + return '?'; + + c &= 0x7F; + + if (c < 0x20 || c >= 0x7F) + return '.'; + + return c; +} + +static void dump_cc_ascii(const uint8_t *buf, unsigned int vpts, int poc) +{ + int cc_flag; + int cc_count; + int i; + int szAscii[32]; + int index = 0; + + cc_flag = buf[1] & 0x40; + if (!cc_flag) { + pr_info("### cc_flag is invalid\n"); + return; + } + cc_count = buf[1] & 0x1f; + + for (i = 0; i < cc_count; ++i) { + unsigned int b0; + unsigned int cc_valid; + unsigned int cc_type; + unsigned char cc_data1; + unsigned char cc_data2; + + b0 = buf[3 + i * 3]; + cc_valid = b0 & 4; + cc_type = b0 & 3; + cc_data1 = buf[4 + i * 3]; + cc_data2 = buf[5 + i * 3]; + + + if (cc_type == 0) { + /* NTSC pair, Line 21 */ + szAscii[index++] = vbi_to_ascii(cc_data1); + szAscii[index++] = vbi_to_ascii(cc_data2); + if ((!cc_valid) || (i >= 3)) + break; + } + } + + if (index > 0 && index <= 8) { + char pr_buf[128]; + int len; + + sprintf(pr_buf, "push vpts:0x%x, poc:%d :", vpts, poc); + len = strlen(pr_buf); + for (i=0;i<index;i++) + sprintf(pr_buf + len + i*2, "%c ", szAscii[i]); + pr_info("%s\n", pr_buf); + } + +} +#endif + +/* +#define DUMP_USER_DATA_HEX +*/ +#ifdef DUMP_USER_DATA_HEX +static void print_data(unsigned char *pdata, int len) +{ + int nLeft; + char buf[128]; + + nLeft = len; + while (nLeft >= 16) { + int i; + + for (i=0;i<16;i++) + sprintf(buf+i*3, "%02x ", pdata[i]); + + pr_info("%s\n", buf); + nLeft -= 16; + pdata += 16; + } + + while (nLeft >= 8) { + int i; + for (i=0;i<nLeft;i++) + sprintf(buf+i*3, "%02x ", pdata[i]); + + pr_info("%s\n", buf); + nLeft -= 8; + pdata += 8; + } +} +#endif + + + +static void aml_swap_data(uint8_t *user_data, int ud_size) +{ + int swap_blocks, i, j, k, m; + unsigned char c_temp; + + /* swap byte order */ + swap_blocks = ud_size / 8; + for (i = 0; i < swap_blocks; i++) { + j = i * 8; + k = j + 7; + for (m = 0; m < 4; m++) { + c_temp = user_data[j]; + user_data[j++] = user_data[k]; + user_data[k--] = c_temp; + } + } +} + + +static void udr_dump_data(unsigned int user_data_wp, + unsigned int user_data_length, + unsigned int pts, + int poc) +{ + unsigned char *pdata; + int user_data_len; + int wp_start; + int nLeft; + unsigned char szBuf[256]; + int nOffset; + + dma_sync_single_for_cpu(amports_get_dma_device(), + sei_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 *)sei_data_buffer; + pdata += wp_start; + nLeft = user_data_len; + + memset(szBuf, 0, 256); + memcpy(szBuf, pdata, user_data_len); + } else { + wp_start = user_data_wp + + USER_DATA_SIZE - user_data_len; + + pdata = (unsigned char *)sei_data_buffer; + pdata += wp_start; + nLeft = USER_DATA_SIZE - wp_start; + + memset(szBuf, 0, 256); + memcpy(szBuf, pdata, nLeft); + nOffset = nLeft; + + pdata = (unsigned char *)sei_data_buffer; + nLeft = user_data_wp; + memcpy(szBuf+nOffset, pdata, nLeft); + } + + aml_swap_data(szBuf, user_data_len); + +#ifdef DUMP_USER_DATA_HEX + print_data(szBuf, user_data_len); +#endif + +#ifdef DUMP_CC_AS_ASCII + dump_cc_ascii(szBuf+7, pts, poc); +#endif +} + + +struct vh264_userdata_recored_t { + struct userdata_meta_info_t meta_info; + u32 rec_start; + u32 rec_len; +}; + +#define USERDATA_FIFO_NUM 256 + +struct vh264_userdata_info_t { + struct vh264_userdata_recored_t records[USERDATA_FIFO_NUM]; + u8 *data_buf; + u8 *data_buf_end; + u32 buf_len; + u32 read_index; + u32 write_index; + u32 last_wp; +}; + +static struct vh264_userdata_info_t *p_userdata_mgr; + +static DEFINE_MUTEX(userdata_mutex); + + +void vh264_crate_userdata_manager(u8 *userdata_buf, int buf_len) +{ + p_userdata_mgr = (struct vh264_userdata_info_t *) + vmalloc(sizeof(struct vh264_userdata_info_t)); + if (p_userdata_mgr) { + memset(p_userdata_mgr, 0, + sizeof(struct vh264_userdata_info_t)); + p_userdata_mgr->data_buf = userdata_buf; + p_userdata_mgr->buf_len = buf_len; + p_userdata_mgr->data_buf_end = userdata_buf + buf_len; + } +} + +void vh264_destroy_userdata_manager(void) +{ + if (p_userdata_mgr) { + vfree(p_userdata_mgr); + p_userdata_mgr = NULL; + } +} + +/* +#define DUMP_USER_DATA +*/ +#ifdef DUMP_USER_DATA + +#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_mem_data(unsigned char *pdata, + int len, + 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, duration = %d, vpts = 0x%x, vpts_valid = %d\n", + rec_id, len, flag, + duration, vpts, vpts_valid); +#endif + pr_info("%d len = %d, flag = %d, vpts = 0x%x\n", + rec_id, len, flag, vpts); + + + 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 dump_data(u8 *pdata, + unsigned int user_data_length, + unsigned int flag, + unsigned int duration, + unsigned int vpts, + unsigned int vpts_valid, + int rec_id) +{ + unsigned char szBuf[256]; + + + memset(szBuf, 0, 256); + memcpy(szBuf, pdata, user_data_length); +/* + aml_swap_data(szBuf, user_data_length); +*/ + + print_mem_data(szBuf, user_data_length, + flag, duration, vpts, + vpts_valid, rec_id); + +#ifdef DEBUG_CC_DUMP_ASCII + dump_cc_ascii(szBuf+7); +#endif +} + +static void push_to_buf(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->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 *)sei_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 *)sei_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 dump_userdata_info( + void *puser_data, + int len, + struct userdata_meta_info_t *pmeta) +{ + u8 *pstart; + + pstart = (u8 *)puser_data; + + + push_to_buf(pstart, len, pmeta); +} + +static void show_user_data_buf(void) +{ + u8 *pbuf; + int len; + unsigned int flag; + unsigned int duration; + unsigned int vpts; + unsigned int vpts_valid; + 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); + + 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); + + dump_data(pbuf, len, flag, duration, vpts, vpts_valid, rec_id); + pbuf += len; + msleep(30); + } +} + +static int vh264_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 vh264_dump_userdata(void) +{ + if (user_data_buf) { + show_user_data_buf(); + kfree(user_data_buf); + user_data_buf = NULL; + } +} + +static void vh264_reset_user_data_buf(void) +{ + total_len = 0; + pbuf_start = user_data_buf; + bskip = 0; + n_userdata_id = 0; +} +#endif + +static void vh264_add_userdata(struct userdata_meta_info_t meta_info, int wp) +{ + struct vh264_userdata_recored_t *p_userdata_rec; + int data_length; + + mutex_lock(&userdata_mutex); + + if (p_userdata_mgr) { + if (wp > p_userdata_mgr->last_wp) + data_length = wp - p_userdata_mgr->last_wp; + else + data_length = wp + p_userdata_mgr->buf_len - + p_userdata_mgr->last_wp; + + if (data_length & 0x7) + data_length = (((data_length + 8) >> 3) << 3); +#if 0 + pr_info("wakeup_push: ri:%d, wi:%d, data_len:%d, last_wp:%d, wp:%d, id = %d\n", + p_userdata_mgr->read_index, + p_userdata_mgr->write_index, + data_length, + p_userdata_mgr->last_wp, + wp, + n_userdata_id); +#endif + p_userdata_rec = p_userdata_mgr->records + + p_userdata_mgr->write_index; + p_userdata_rec->meta_info = meta_info; + p_userdata_rec->rec_start = p_userdata_mgr->last_wp; + p_userdata_rec->rec_len = data_length; + p_userdata_mgr->last_wp = wp; + +#ifdef DUMP_USER_DATA + dump_userdata_info(p_userdata_mgr->data_buf + + p_userdata_rec->rec_start, + data_length, + &meta_info); + n_userdata_id++; +#endif + + p_userdata_mgr->write_index++; + if (p_userdata_mgr->write_index >= USERDATA_FIFO_NUM) + p_userdata_mgr->write_index = 0; + } + mutex_unlock(&userdata_mutex); + + vdec_wakeup_userdata_poll(vdec_h264); +} + +static int vh264_user_data_read(struct vdec_s *vdec, + struct userdata_param_t *puserdata_para) +{ + int rec_ri, rec_wi; + int rec_len; + u8 *rec_data_start; + u8 *pdest_buf; + struct vh264_userdata_recored_t *p_userdata_rec; + u32 data_size; + u32 res; + int copy_ok = 1; + + + pdest_buf = puserdata_para->pbuf_addr; + + + mutex_lock(&userdata_mutex); + + if (!p_userdata_mgr) { + mutex_unlock(&userdata_mutex); + return 0; + } +/* + pr_info("ri = %d, wi = %d\n", + p_userdata_mgr->read_index, + p_userdata_mgr->write_index); +*/ + rec_ri = p_userdata_mgr->read_index; + rec_wi = p_userdata_mgr->write_index; + + if (rec_ri == rec_wi) { + mutex_unlock(&userdata_mutex); + return 0; + } + + p_userdata_rec = p_userdata_mgr->records + rec_ri; + + rec_len = p_userdata_rec->rec_len; + rec_data_start = p_userdata_rec->rec_start + p_userdata_mgr->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 + > p_userdata_mgr->data_buf_end) { + int first_section_len; + + first_section_len = p_userdata_mgr->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 *)p_userdata_mgr->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) { + p_userdata_mgr->read_index++; + if (p_userdata_mgr->read_index >= USERDATA_FIFO_NUM) + p_userdata_mgr->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 + > p_userdata_mgr->data_buf_end) { + int first_section_len; + + first_section_len = p_userdata_mgr->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 *)p_userdata_mgr->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) { + p_userdata_mgr->read_index++; + if (p_userdata_mgr->read_index + >= USERDATA_FIFO_NUM) + p_userdata_mgr->read_index = 0; + } + + } + puserdata_para->meta_info = p_userdata_rec->meta_info; + + if (p_userdata_mgr->read_index <= p_userdata_mgr->write_index) + puserdata_para->meta_info.records_in_que = + p_userdata_mgr->write_index - + p_userdata_mgr->read_index; + else + puserdata_para->meta_info.records_in_que = + p_userdata_mgr->write_index + + USERDATA_FIFO_NUM - + p_userdata_mgr->read_index; + + puserdata_para->version = (0<<24|0<<16|0<<8|1); + + mutex_unlock(&userdata_mutex); + + return 1; +} + +static void vh264_wakeup_userdata_poll(struct vdec_s *vdec) +{ + amstream_wakeup_userdata_poll(vdec); +} + +static void vh264_reset_userdata_fifo(struct vdec_s *vdec, int bInit) +{ + mutex_lock(&userdata_mutex); + + if (p_userdata_mgr) { + pr_info("h264_reset_userdata_fifo: bInit: %d, ri: %d, wi: %d\n", + bInit, p_userdata_mgr->read_index, + p_userdata_mgr->write_index); + p_userdata_mgr->read_index = 0; + p_userdata_mgr->write_index = 0; + + if (bInit) + p_userdata_mgr->last_wp = 0; + } + + mutex_unlock(&userdata_mutex); +} + +static void h264_reset_qos_mgr(void) +{ + int i; + + pr_info("h264_reset_qos_mgr\n"); + + INIT_LIST_HEAD(&free_qos_nodes_list); + INIT_LIST_HEAD(&picture_qos_list); + + for (i = 0; i < MAX_FREE_QOS_NODES; i++) { + free_nodes[i].b_offset = 0xFFFFFFFF; + + list_add_tail(&free_nodes[i].list, + &free_qos_nodes_list); + } +} + + +static void load_qos_data(int pic_number, uint32_t b_offset) +{ + 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 +*/ +#define SUPPORT_NODE + +#ifdef SUPPORT_NODE + struct h264_qos_data_node_t *node; + struct h264_qos_data_node_t *tmp; + int bFoundNode = 0; + + node = NULL; + if (!list_empty(&picture_qos_list)) { + list_for_each_entry_safe(node, tmp, &picture_qos_list, list) { + if (node->b_offset == b_offset) { + bFoundNode = 1; + break; + } + } + } + /* + pr_info("bFoundNode = %d, node:0x%p\n", bFoundNode, node); + */ + if (!bFoundNode) { + if (!list_empty(&free_qos_nodes_list)) { + node = list_entry( + free_qos_nodes_list.next, + struct h264_qos_data_node_t, + list); + /* + pr_info("get a node:0x%p\n", node); + */ + } else { + pr_info("there is no qos data node avaible\n"); + + return; + } + } + + node->b_offset = b_offset; + node->poc = pic_number; + + node->max_mv = 0; + node->avg_mv = 0; + node->min_mv = 0; + + node->max_skip = 0; + node->avg_skip = 0; + node->min_skip = 0; + + node->max_qp = 0; + node->avg_qp = 0; + node->min_qp = 0; +#endif + + + + + + + /* 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)); + +#ifdef SUPPORT_NODE + list_move(&node->list, &picture_qos_list); +#endif + 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 +#ifdef SUPPORT_NODE + node->avg_qp = rdata32/blk88_y_count; +#endif + + /* 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 +#ifdef SUPPORT_NODE + node->avg_skip = rdata32*100/blk88_y_count; +#endif + /* 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)); + +#ifdef SUPPORT_NODE + list_move(&node->list, &picture_qos_list); +#endif + 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 +#ifdef SUPPORT_NODE + node->min_qp = (rdata32>>0)&0xff; +#endif + +#ifdef DEBUG_QOS + pr_info(" [Picture %d Quality] Y QP max : %d\n", + pic_number, (rdata32>>8)&0xff); +#endif +#ifdef SUPPORT_NODE + node->max_qp = (rdata32>>8)&0xff; +#endif + +#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)); +#ifdef SUPPORT_NODE + list_move(&node->list, &picture_qos_list); +#endif + 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 +#ifdef SUPPORT_NODE + node->avg_mv = value; +#endif + + /* 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 +#ifdef SUPPORT_NODE + node->max_mv = mv_hi; +#endif + + 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 +#ifdef SUPPORT_NODE + node->min_mv = mv_lo; +#endif + +#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)); +#ifdef SUPPORT_NODE + list_move(&node->list, &picture_qos_list); +#endif +} + +void search_qos_node(struct vframe_qos_s *picture_qos, uint32_t b_offset) +{ + struct h264_qos_data_node_t *node; + struct h264_qos_data_node_t *tmp; + + if (!list_empty(&picture_qos_list)) { + list_for_each_entry_safe(node, tmp, &picture_qos_list, list) { + if (node->b_offset == b_offset) { + + picture_qos->avg_mv = node->avg_mv; + picture_qos->min_mv = node->min_mv; + picture_qos->max_mv = node->max_mv; + + picture_qos->avg_skip = node->avg_skip; + picture_qos->min_skip = node->min_skip; + picture_qos->max_skip = node->max_skip; + + picture_qos->avg_qp = node->avg_qp; + picture_qos->min_qp = node->min_qp; + picture_qos->max_qp = node->max_qp; + +#if 0 + pr_info("POC:%d, mv: max:%d, avg:%d, min:%d\n" + "qp: max:%d, avg:%d, min:%d\n" + "skip: max:%d, avg:%d, min:%d\n", + node->poc, + picture_qos->max_mv, + picture_qos->avg_mv, + picture_qos->min_mv, + picture_qos->max_qp, + picture_qos->avg_qp, + picture_qos->min_qp, + picture_qos->max_skip, + picture_qos->avg_skip, + picture_qos->min_skip); +#endif + node->b_offset = 0xFFFFFFFF; + list_move(&node->list, &free_qos_nodes_list); + + break; + } + } + } +} + +static void qos_do_work(struct work_struct *work) +{ + uint32_t poc; + uint32_t bOffset; + + + poc = READ_VREG(AV_SCRATCH_M); + bOffset = READ_VREG(AV_SCRATCH_L); +/* + pr_info("poc:%d, bOffset:0x%x\n", poc, bOffset); +*/ + load_qos_data(poc, bOffset); + + + WRITE_VREG(AV_SCRATCH_0, 0); +} + +static void userdata_push_do_work(struct work_struct *work) +{ + unsigned int sei_itu35_flags; + unsigned int sei_itu35_wp; + unsigned int sei_itu35_data_length; + + struct userdata_meta_info_t meta_info; + u32 offset, pts; + u64 pts_us64 = 0; + u32 slice_type; + u32 reg; + u32 poc_number; + u32 picture_struct; + + memset(&meta_info, 0, sizeof(meta_info)); + + meta_info.duration = frame_dur; + + reg = READ_VREG(AV_SCRATCH_M); + poc_number = reg & 0x7FFFFFF; + if ((poc_number >> 16) == 0x7FF) + poc_number = (reg & 0x7FFFFFF) - 0x8000000; + + slice_type = (reg >> 29) & 0x7; + switch (slice_type) { + case SLICE_TYPE_I: + meta_info.flags |= 1<<7; + break; + case SLICE_TYPE_P: + meta_info.flags |= 3<<7; + break; + case SLICE_TYPE_B: + meta_info.flags |= 2<<7; + break; + } + meta_info.poc_number = poc_number; + picture_struct = (reg >> 27) & 0x3; + + meta_info.flags |= (VFORMAT_H264 << 3) | (picture_struct << 12); + + + offset = READ_VREG(AV_SCRATCH_L); + + if (pts_pickout_offset_us64 + (PTS_TYPE_VIDEO, offset, &pts, 0, &pts_us64) != 0) { + pr_info("pts pick outfailed, offset:0x%x\n", offset); + pts = -1; + meta_info.vpts_valid = 0; + } else + meta_info.vpts_valid = 1; + meta_info.vpts = pts; +/* + pr_info("offset:0x%x, vpts:0x%x, slice:%d, poc:%d\n", + offset, pts, slice_type, + poc_number); +*/ + sei_itu35_flags = READ_VREG(AV_SCRATCH_J); + sei_itu35_wp = (sei_itu35_flags >> 16) & 0xffff; + sei_itu35_data_length = sei_itu35_flags & 0x7fff; + + if (enable_userdata_debug) + udr_dump_data(sei_itu35_wp, + sei_itu35_data_length, + pts, poc_number); + + + vh264_add_userdata(meta_info, sei_itu35_wp); + + WRITE_VREG(AV_SCRATCH_J, 0); +} + + +static void set_frame_info(struct vframe_s *vf) +{ + vf->width = frame_width; + vf->height = frame_height; + vf->duration = frame_dur; + vf->ratio_control = + (min(h264_ar, (u32) DISP_RATIO_ASPECT_RATIO_MAX)) << + DISP_RATIO_ASPECT_RATIO_BIT; + vf->orientation = vh264_rotation; + vf->flag = 0; + +#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER_3D_PROCESS + vf->trans_fmt = 0; + if ((vf->trans_fmt == TVIN_TFMT_3D_LRF) || + (vf->trans_fmt == TVIN_TFMT_3D_LA)) { + vf->left_eye.start_x = 0; + vf->left_eye.start_y = 0; + vf->left_eye.width = frame_width / 2; + vf->left_eye.height = frame_height; + + vf->right_eye.start_x = 0; + vf->right_eye.start_y = 0; + vf->right_eye.width = frame_width / 2; + vf->right_eye.height = frame_height; + } else if ((vf->trans_fmt == TVIN_TFMT_3D_LRH_OLER) || + (vf->trans_fmt == TVIN_TFMT_3D_TB)) { + vf->left_eye.start_x = 0; + vf->left_eye.start_y = 0; + vf->left_eye.width = frame_width / 2; + vf->left_eye.height = frame_height; + + vf->right_eye.start_x = 0; + vf->right_eye.start_y = 0; + vf->right_eye.width = frame_width / 2; + vf->right_eye.height = frame_height; + } +#endif + +} + +#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER +static void vh264_ppmgr_reset(void) +{ + vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_RESET, NULL); + + vh264_local_init(); + + pr_info("vh264dec: vf_ppmgr_reset\n"); +} +#endif + +static int get_max_dpb_size(int level_idc, int mb_width, int mb_height) +{ + int size, r; + + switch (level_idc) { + case 10: + r = 1485; + break; + case 11: + r = 3375; + break; + case 12: + case 13: + case 20: + r = 8910; + break; + case 21: + r = 17820; + break; + case 22: + case 30: + r = 30375; + break; + case 31: + r = 67500; + break; + case 32: + r = 76800; + break; + case 40: + case 41: + case 42: + r = 122880; + break; + case 50: + r = 414000; + break; + case 51: + case 52: + r = 691200; + break; + default: + return 0; + } + size = (mb_width * mb_height + + (mb_width * mb_height / 2)) * 256 * 10; + r = (r * 1024 + size-1) / size; + r = min(r, 16); + /*pr_info("max_dpb %d size:%d\n", r, size);*/ + return r; +} +static void vh264_set_params(struct work_struct *work) +{ + int aspect_ratio_info_present_flag, aspect_ratio_idc; + int max_dpb_size, actual_dpb_size, max_reference_size; + int i, mb_mv_byte, ret; + unsigned long addr; + unsigned int post_canvas, buf_size, endian; + unsigned int frame_mbs_only_flag; + unsigned int chroma_format_idc, chroma444, video_signal; + unsigned int crop_infor, crop_bottom, crop_right, level_idc; + if (!atomic_read(&vh264_active)) + return; + mutex_lock(&vh264_mutex); + if (vh264_stream_switching_state == SWITCHING_STATE_ON_CMD1) + vh264_stream_switching_state = SWITCHING_STATE_ON_CMD1_PENDING; + post_canvas = get_post_canvas(); + clk_adj_frame_count = 0; + /* set to max decoder clock rate at the beginning */ + + if (vdec_is_support_4k()) + vdec_source_changed(VFORMAT_H264, 3840, 2160, 60); + else + vdec_source_changed(VFORMAT_H264, 1920, 1080, 29); + + timing_info_present_flag = 0; + mb_width = READ_VREG(AV_SCRATCH_1); + seq_info = READ_VREG(AV_SCRATCH_2); + aspect_ratio_info = READ_VREG(AV_SCRATCH_3); + num_units_in_tick = READ_VREG(AV_SCRATCH_4); + time_scale = READ_VREG(AV_SCRATCH_5); + level_idc = READ_VREG(AV_SCRATCH_A); + if (level_idc > 0) + saved_idc_level = level_idc; + else if (saved_idc_level > 0) + level_idc = saved_idc_level; + video_signal = READ_VREG(AV_SCRATCH_H); + video_signal_from_vui = + ((video_signal & 0xffff) << 8) | + ((video_signal & 0xff0000) >> 16) | + ((video_signal & 0x3f000000)); +/* + * pr_info("video_signal_type_present_flag 0x%x\n", + * (video_signal_from_vui >> 29) & 1); + * pr_info("video_format 0x%x\n", + * (video_signal_from_vui >> 26) & 7); + * pr_info("video_full_range_flag 0x%x\n", + * (video_signal_from_vui >> 25) & 1); + * pr_info("color_description_present_flag 0x%x\n", + * (video_signal_from_vui >> 24) & 1); + * pr_info("color_primaries 0x%x\n", + * (video_signal_from_vui >> 16) & 0xff); + * pr_info("transfer_characteristic 0x%x\n", + * (video_signal_from_vui >> 8) & 0xff); + * pr_info("matrix_coefficient 0x%x\n", + * video_signal_from_vui & 0xff); + */ + + mb_total = (mb_width >> 8) & 0xffff; + max_reference_size = (mb_width >> 24) & 0x7f; + mb_mv_byte = (mb_width & 0x80000000) ? 24 : 96; + if (ucode_type == UCODE_IP_ONLY_PARAM) + mb_mv_byte = 96; + mb_width = mb_width & 0xff; + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXTVBB) { + if (!mb_width && mb_total) + mb_width = 256; + } + if (mb_width) + mb_height = mb_total / mb_width; + last_duration = 0; + /* AV_SCRATCH_2 + * bit 15: frame_mbs_only_flag + * bit 13-14: chroma_format_idc + */ + frame_mbs_only_flag = (seq_info >> 15) & 0x01; + chroma_format_idc = (seq_info >> 13) & 0x03; + chroma444 = (chroma_format_idc == 3) ? 1 : 0; + + /* @AV_SCRATCH_6.31-16 = (left << 8 | right ) << 1 + * @AV_SCRATCH_6.15-0 = (top << 8 | bottom ) << + * (2 - frame_mbs_only_flag) + */ + crop_infor = READ_VREG(AV_SCRATCH_6); + crop_bottom = (crop_infor & 0xff) >> (2 - frame_mbs_only_flag); + crop_right = ((crop_infor >> 16) & 0xff) >> (2 - frame_mbs_only_flag); + + /* if width or height from outside is not equal to mb, then use mb */ + /* add: for seeking stream with other resolution */ + if ((last_mb_width && (last_mb_width != mb_width)) + || (mb_width != ((frame_width + 15) >> 4))) + frame_width = 0; + if ((last_mb_height && (last_mb_height != mb_height)) + || (mb_height != ((frame_height + 15) >> 4))) + frame_height = 0; + last_mb_width = mb_width; + last_mb_height = mb_height; + + if ((frame_width == 0) || (frame_height == 0) || crop_infor) { + frame_width = mb_width << 4; + frame_height = mb_height << 4; + if (frame_mbs_only_flag) { + frame_height = + frame_height - (2 >> chroma444) * + min(crop_bottom, + (unsigned int)((8 << chroma444) - 1)); + frame_width = + frame_width - (2 >> chroma444) * min(crop_right, + (unsigned + int)((8 << chroma444) - 1)); + } else { + frame_height = + frame_height - (4 >> chroma444) * + min(crop_bottom, + (unsigned int)((8 << chroma444) + - 1)); + frame_width = + frame_width - (4 >> chroma444) * min(crop_right, + (unsigned + int)((8 << + chroma444) + - 1)); + } +#if 0 + pr_info + ("frame_mbs_only_flag %d, crop_bottom %d, frame_height %d, ", + frame_mbs_only_flag, crop_bottom, frame_height); + pr_info + ("mb_height %d,crop_right %d, frame_width %d, mb_width %d\n", + mb_height, crop_right, frame_width, mb_width); +#endif + if (frame_height == 1088) + frame_height = 1080; + } + + mb_width = (mb_width + 3) & 0xfffffffc; + mb_height = (mb_height + 3) & 0xfffffffc; + mb_total = mb_width * mb_height; + + /*max_reference_size <= max_dpb_size <= actual_dpb_size*/ + is_4k = (mb_total > 8160) ? true:false; + + + max_dpb_size = get_max_dpb_size(level_idc, mb_width, mb_height); + if (max_dpb_size < max_reference_size) + max_dpb_size = max_reference_size; + if (max_dpb_size > 15 + && get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXTVBB + && (codec_mm_get_total_size() < 80 * SZ_1M)) { + actual_dpb_size + = max_reference_size + dpb_size_adj; + if (actual_dpb_size > VF_BUF_NUM) + actual_dpb_size = VF_BUF_NUM; + } else { + actual_dpb_size = max_dpb_size + dpb_size_adj; + actual_dpb_size = min(actual_dpb_size, VF_BUF_NUM); + } + max_reference_size++; + pr_info("actual_dpb_size %d max_dpb_size %d max_ref %d\n", + actual_dpb_size, max_dpb_size, + max_reference_size); + buf_size = mb_total * mb_mv_byte * max_reference_size; + + ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle, 1, + buf_size, DRIVER_NAME, &addr); + + if (ret < 0) { + fatal_error_flag = + DECODER_FATAL_ERROR_NO_MEM; + vh264_running = 0; + mutex_unlock(&vh264_mutex); + return; + } + + WRITE_VREG(AV_SCRATCH_1, addr); + WRITE_VREG(AV_SCRATCH_3, post_canvas); + WRITE_VREG(AV_SCRATCH_4, addr + buf_size); + + if (!(READ_VREG(AV_SCRATCH_F) & 0x1)) { + for (i = 0; i < actual_dpb_size; i++) { +#ifdef DOUBLE_WRITE + int page_count = + PAGE_ALIGN((mb_total << 8) + (mb_total + << 7) + (mb_total << 6) + + (mb_total << 5)) / PAGE_SIZE; +#else + int 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; + fatal_error_flag = + DECODER_FATAL_ERROR_NO_MEM; + vh264_running = 0; + mutex_unlock(&vh264_mutex); + return; + } + + addr = buffer_spec[i].phy_addr; + buffer_spec[i].alloc_count = page_count; + + if (i <= 21) { + buffer_spec[i].y_addr = addr; + addr += mb_total << 8; + buffer_spec[i].u_addr = addr; + buffer_spec[i].v_addr = addr; + addr += mb_total << 7; + vfbuf_use[i] = 0; + + buffer_spec[i].y_canvas_index = 128 + i * 2; + buffer_spec[i].u_canvas_index = 128 + i * 2 + 1; + buffer_spec[i].v_canvas_index = 128 + i * 2 + 1; + + buffer_spec[i].y_canvas_width = mb_width << 4; + buffer_spec[i].y_canvas_height = mb_height << 4; + buffer_spec[i].u_canvas_width = mb_width << 4; + buffer_spec[i].u_canvas_height = mb_height << 4; + buffer_spec[i].v_canvas_width = mb_width << 4; + buffer_spec[i].v_canvas_height = mb_height << 4; + + endian = (canvas_mode == CANVAS_BLKMODE_LINEAR)?7:0; + config_cav_lut_ex(128 + i * 2, + buffer_spec[i].y_addr, + mb_width << 4, mb_height << 4, + CANVAS_ADDR_NOWRAP, + 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, VDEC_1); + WRITE_VREG(ANC0_CANVAS_ADDR + i, + spec2canvas(&buffer_spec[i])); + } else { + buffer_spec[i].y_canvas_index = + 2 * (i - 21) + 4; + buffer_spec[i].y_addr = addr; + addr += mb_total << 8; + buffer_spec[i].u_canvas_index = + 2 * (i - 21) + 5; + buffer_spec[i].v_canvas_index = + 2 * (i - 21) + 5; + buffer_spec[i].u_addr = addr; + addr += mb_total << 7; + vfbuf_use[i] = 0; + + buffer_spec[i].y_canvas_width = mb_width << 4; + buffer_spec[i].y_canvas_height = mb_height << 4; + buffer_spec[i].u_canvas_width = mb_width << 4; + buffer_spec[i].u_canvas_height = mb_height << 4; + buffer_spec[i].v_canvas_width = mb_width << 4; + buffer_spec[i].v_canvas_height = mb_height << 4; + + spec_set_canvas(&buffer_spec[i] + , mb_width << 4, mb_height << 4); + WRITE_VREG(ANC0_CANVAS_ADDR + i + , spec2canvas(&buffer_spec[i])); + } + } + } else { + fatal_error_flag = + DECODER_FATAL_ERROR_NO_MEM; + vh264_running = 0; + mutex_unlock(&vh264_mutex); + pr_err("never be here!!\n"); + return; + } + + timing_info_present_flag = seq_info & 0x2; + fixed_frame_rate_flag = 0; + aspect_ratio_info_present_flag = seq_info & 0x1; + aspect_ratio_idc = (seq_info >> 16) & 0xff; + + if (timing_info_present_flag) { + fixed_frame_rate_flag = seq_info & 0x40; + + if (((num_units_in_tick * 120) >= time_scale + && ((!sync_outside) || (!frame_dur))) && + num_units_in_tick + && time_scale) { + if (use_idr_framerate || !frame_dur + || !duration_from_pts_done || vh264_running) { + u32 frame_dur_es = + div_u64(96000ULL * 2 * + num_units_in_tick, + time_scale); + + /* 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; + if (fr_hint_status == VDEC_NEED_HINT) { + schedule_work(¬ify_work); + fr_hint_status = VDEC_HINTED; + } + } + } + } + } else + pr_info("H.264: timing_info not present\n"); + + if (aspect_ratio_info_present_flag) { + if (aspect_ratio_idc == EXTEND_SAR) { + h264_ar = + div_u64(256ULL * (aspect_ratio_info >> 16) * + frame_height, + (aspect_ratio_info & 0xffff) * + frame_width); + } else { + /* pr_info("v264dec: aspect_ratio_idc = %d\n", + * aspect_ratio_idc); + */ + + switch (aspect_ratio_idc) { + case 1: + h264_ar = 0x100 * frame_height / frame_width; + break; + case 2: + h264_ar = 0x100 * frame_height * 11 / + (frame_width * 12); + break; + case 3: + h264_ar = 0x100 * frame_height * 11 / + (frame_width * 10); + break; + case 4: + h264_ar = 0x100 * frame_height * 11 / + (frame_width * 16); + break; + case 5: + h264_ar = 0x100 * frame_height * 33 / + (frame_width * 40); + break; + case 6: + h264_ar = 0x100 * frame_height * 11 / + (frame_width * 24); + break; + case 7: + h264_ar = 0x100 * frame_height * 11 / + (frame_width * 20); + break; + case 8: + h264_ar = 0x100 * frame_height * 11 / + (frame_width * 32); + break; + case 9: + h264_ar = 0x100 * frame_height * 33 / + (frame_width * 80); + break; + case 10: + h264_ar = 0x100 * frame_height * 11 / + (frame_width * 18); + break; + case 11: + h264_ar = 0x100 * frame_height * 11 / + (frame_width * 15); + break; + case 12: + h264_ar = 0x100 * frame_height * 33 / + (frame_width * 64); + break; + case 13: + h264_ar = 0x100 * frame_height * 99 / + (frame_width * 160); + break; + case 14: + h264_ar = 0x100 * frame_height * 3 / + (frame_width * 4); + break; + case 15: + h264_ar = 0x100 * frame_height * 2 / + (frame_width * 3); + break; + case 16: + h264_ar = 0x100 * frame_height * 1 / + (frame_width * 2); + break; + default: + if (vh264_ratio >> 16) { + h264_ar = (frame_height * + (vh264_ratio & 0xffff) * + 0x100 + + ((vh264_ratio >> 16) * + frame_width / 2)) / + ((vh264_ratio >> 16) * + frame_width); + } else { + h264_ar = frame_height * 0x100 / + frame_width; + } + break; + } + } + } else { + pr_info("v264dec: aspect_ratio not available from source\n"); + if (vh264_ratio >> 16) { + /* high 16 bit is width, low 16 bit is height */ + h264_ar = + ((vh264_ratio & 0xffff) * frame_height * 0x100 + + (vh264_ratio >> 16) * frame_width / 2) / + ((vh264_ratio >> 16) * frame_width); + } else + h264_ar = frame_height * 0x100 / frame_width; + } + + WRITE_VREG(AV_SCRATCH_0, + (max_reference_size << 24) | (actual_dpb_size << 16) | + (max_dpb_size << 8)); + if (vh264_stream_switching_state != SWITCHING_STATE_OFF) { + vh264_stream_switching_state = SWITCHING_STATE_OFF; + pr_info("Leaving switching mode.\n"); + } + mutex_unlock(&vh264_mutex); +} + +static unsigned int pts_inc_by_duration( + unsigned int *new_pts, unsigned int *new_pts_rem) +{ + unsigned int r, rem; + + r = last_pts + DUR2PTS(frame_dur); + rem = last_pts_remainder + DUR2PTS_REM(frame_dur); + + if (rem >= 96) { + r++; + rem -= 96; + } + + if (new_pts) + *new_pts = r; + if (new_pts_rem) + *new_pts_rem = rem; + + return r; +} +static inline bool vh264_isr_parser(struct vframe_s *vf, + unsigned int pts_valid, unsigned int buffer_index, + unsigned int pts) +{ + unsigned int pts_duration = 0; + + if (h264_first_pts_ready == 0) { + if (pts_valid == 0) { + vfbuf_use[buffer_index]++; + vf->index = buffer_index; + kfifo_put(&recycle_q, + (const struct vframe_s *)vf); + return false; + } + + h264pts1 = pts; + h264_pts_count = 0; + h264_first_pts_ready = 1; + } else { + if (pts < h264pts1) { + if (h264_pts_count > 24) { + pr_info("invalid h264pts1, reset\n"); + h264pts1 = pts; + h264_pts_count = 0; + } + } + if (pts_valid && (pts > h264pts1) && (h264_pts_count > 24) + && (duration_from_pts_done == 0)) { + unsigned int + old_duration = frame_dur; + h264pts2 = pts; + + pts_duration = (h264pts2 - h264pts1) * 16 / + (h264_pts_count * 15); + + if ((pts_duration != frame_dur) + && (!pts_outside)) { + if (use_idr_framerate) { + bool pts_c_24 = close_to(pts_duration, + RATE_24_FPS, + RATE_CORRECTION_THRESHOLD); + bool frm_c_25 = close_to(frame_dur, + RATE_25_FPS, + RATE_CORRECTION_THRESHOLD); + bool pts_c_25 = close_to(pts_duration, + RATE_25_FPS, + RATE_CORRECTION_THRESHOLD); + bool frm_c_24 = close_to(frame_dur, + RATE_24_FPS, + RATE_CORRECTION_THRESHOLD); + if ((pts_c_24 && frm_c_25) + || (pts_c_25 && frm_c_24)) { + pr_info + ("H.264:Correct frame dur "); + pr_info + (" from %d to duration based ", + frame_dur); + pr_info + ("on PTS %d ---\n", + pts_duration); + frame_dur = pts_duration; + duration_from_pts_done = 1; + } else if (((frame_dur < 96000 / 240) + && (pts_duration > 96000 / 240)) + || (!duration_on_correcting && + !frm_c_25 && !frm_c_24)) { + /* fft: if the frame rate is + * not regular, use the + * calculate rate insteadof. + */ + pr_info + ("H.264:Correct frame dur "); + pr_info + (" from %d to duration based ", + frame_dur); + pr_info + ("on PTS %d ---\n", + pts_duration); + frame_dur = pts_duration; + duration_on_correcting = 1; + } + } else { + if (close_to(pts_duration, + frame_dur, 2000)) { + frame_dur = pts_duration; + pr_info + ("used calculate frame rate,"); + pr_info("on duration =%d\n", + frame_dur); + } else { + pr_info + ("don't use calculate frame "); + pr_info + ("rate pts_duration =%d\n", + pts_duration); + } + } + } + + if (duration_from_pts_done == 0) { + if (close_to + (pts_duration, + old_duration, + RATE_CORRECTION_THRESHOLD)) { + pr_info + ("finished correct frame dur"); + pr_info + (" new=%d,old_duration=%d,cnt=%d\n", + pts_duration, + old_duration, + h264_pts_count); + duration_from_pts_done = 1; + } else { /*not the same,redo it. */ + if (!close_to(pts_duration, + old_duration, 1000) && + !close_to(pts_duration, + frame_dur, 1000) && + close_to(pts_duration, + last_duration, 200)) { + /* yangle: frame_dur must + * wrong,recover it. + */ + frame_dur = pts_duration; + } + + pr_info + ("restart correct frame duration "); + pr_info + ("new=%d,old_duration=%d,cnt=%d\n", + pts_duration, + old_duration, + h264_pts_count); + h264pts1 = h264pts2; + h264_pts_count = 0; + duration_from_pts_done = 0; + } + } + last_duration = pts_duration; + } + } + return true; +} + +static inline void h264_update_gvs(void) +{ + u32 ratio_control; + u32 ar; + + if (gvs->frame_height != frame_height) { + gvs->frame_width = frame_width; + gvs->frame_height = frame_height; + } + if (gvs->frame_dur != frame_dur) { + gvs->frame_dur = frame_dur; + if (frame_dur != 0) + gvs->frame_rate = 96000 / frame_dur; + else + gvs->frame_rate = -1; + } + gvs->error_count = READ_VREG(AV_SCRATCH_D); + gvs->status = stat; + if (fatal_error_reset) + gvs->status |= fatal_error_flag; + ar = min_t(u32, + h264_ar, + DISP_RATIO_ASPECT_RATIO_MAX); + ratio_control = + ar << DISP_RATIO_ASPECT_RATIO_BIT; + gvs->ratio_control = ratio_control; +} + +#ifdef HANDLE_H264_IRQ +static irqreturn_t vh264_isr(int irq, void *dev_id) +#else +static void vh264_isr(void) +#endif +{ + unsigned int buffer_index; + struct vframe_s *vf; + unsigned int cpu_cmd; + unsigned int pts, pts_lookup_save, pts_valid_save, pts_valid = 0; + unsigned int pts_us64_valid = 0; + unsigned int framesize; + u64 pts_us64; + bool force_interlaced_frame = false; + unsigned int sei_itu35_flags; + + static const unsigned int idr_num = + FIX_FRAME_RATE_CHECK_IDRFRAME_NUM; + static const unsigned int flg_1080_itl = + DEC_CONTROL_FLAG_FORCE_2997_1080P_INTERLACE; + static const unsigned int flg_576_itl = + DEC_CONTROL_FLAG_FORCE_2500_576P_INTERLACE; + + WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); + + if (0 == (stat & STAT_VDEC_RUN)) { + pr_info("decoder is not running\n"); +#ifdef HANDLE_H264_IRQ + return IRQ_HANDLED; +#else + return; +#endif + } + + cpu_cmd = READ_VREG(AV_SCRATCH_0); + +#ifdef DROP_B_FRAME_FOR_1080P_50_60FPS + if ((frame_dur < 2004) && + (frame_width >= 1400) && + (frame_height >= 1000) && (last_interlaced == 0)) + SET_VREG_MASK(AV_SCRATCH_F, 0x8); +#endif + if ((decoder_force_reset == 1) + || ((error_recovery_mode != 1) + && (no_idr_error_count >= no_idr_error_max) + && (ucode_type != UCODE_IP_ONLY_PARAM))) { + vh264_running = 0; + pr_info("force reset decoder %d!!!\n", no_idr_error_count); + schedule_work(&error_wd_work); + decoder_force_reset = 0; + no_idr_error_count = 0; + } else if ((cpu_cmd & 0xff) == 1) { + if (unlikely + (vh264_running + && (kfifo_len(&newframe_q) != VF_POOL_SIZE))) { + /* a cmd 1 sent during decoding w/o getting a cmd 3. */ + /* should not happen but the original code has such + * case, do the same process + */ + if ((READ_VREG(AV_SCRATCH_1) & 0xff) + == 1) {/*invalid mb_width*/ + vh264_running = 0; + fatal_error_flag = DECODER_FATAL_ERROR_UNKNOWN; + /* this is fatal error, need restart */ + pr_info("cmd 1 fatal error happened\n"); + schedule_work(&error_wd_work); + } else { + vh264_stream_switching_state = SWITCHING_STATE_ON_CMD1; + pr_info("Enter switching mode cmd1.\n"); + schedule_work(&stream_switching_work); + } + return IRQ_HANDLED; + } + pr_info("Enter set parameter cmd1.\n"); + schedule_work(&set_parameter_work); + return IRQ_HANDLED; + } else if ((cpu_cmd & 0xff) == 2) { + int frame_mb_only, pic_struct_present, pic_struct, prog_frame, + poc_sel, idr_flag, eos, error; + int i, status, num_frame, b_offset; + int current_error_count, slice_type; + + vh264_running = 1; + vh264_no_disp_count = 0; + num_frame = (cpu_cmd >> 8) & 0xff; + frame_mb_only = seq_info & 0x8000; + pic_struct_present = seq_info & 0x10; + + current_error_count = READ_VREG(AV_SCRATCH_D); + if (vh264_error_count != current_error_count) { + /* pr_info("decoder error happened, count %d\n", + * current_error_count); + */ + vh264_error_count = current_error_count; + } + + for (i = 0; (i < num_frame) && (!vh264_eos); i++) { + status = READ_VREG(AV_SCRATCH_1 + i); + buffer_index = status & 0x1f; + error = status & 0x200; + slice_type = (READ_VREG(AV_SCRATCH_H) >> (i * 4)) & 0xf; + + if ((error_recovery_mode_use & 2) && error) + check_pts_discontinue = true; + if (ucode_type == UCODE_IP_ONLY_PARAM + && iponly_early_mode) + continue; + if ((p_last_vf != NULL) + && (p_last_vf->index == buffer_index)) + continue; + + if (buffer_index >= VF_BUF_NUM) + continue; + + pic_struct = (status >> 5) & 0x7; + prog_frame = status & 0x100; + poc_sel = status & 0x200; + idr_flag = status & 0x400; + frame_packing_type = (status >> 12) & 0x7; + eos = (status >> 15) & 1; + + if (eos) + vh264_eos = 1; + + b_offset = (status >> 16) & 0xffff; + + if (error) + no_idr_error_count++; + if (idr_flag || + (!error && (slice_type != SLICE_TYPE_I))) + no_idr_error_count = 0; + + if (decoder_debug_flag) { + pr_info + ("slice_type %x idr %x error %x count %d", + slice_type, idr_flag, error, + no_idr_error_count); + pr_info(" prog %x pic_struct %x offset %x\n", + prog_frame, pic_struct, b_offset); + } +#ifdef DROP_B_FRAME_FOR_1080P_50_60FPS + last_interlaced = prog_frame ? 0 : 1; +#endif + if (kfifo_get(&newframe_q, &vf) == 0) { + pr_info + ("fatal error, no available buffer slot."); + return IRQ_HANDLED; + } + + if (clk_adj_frame_count < (VDEC_CLOCK_ADJUST_FRAME + 1)) + clk_adj_frame_count++; + + set_frame_info(vf); + + switch (i) { + case 0: + b_offset |= + (READ_VREG(AV_SCRATCH_A) & 0xffff) + << 16; + break; + case 1: + b_offset |= + READ_VREG(AV_SCRATCH_A) & 0xffff0000; + break; + case 2: + b_offset |= + (READ_VREG(AV_SCRATCH_B) & 0xffff) + << 16; + break; + case 3: + b_offset |= + READ_VREG(AV_SCRATCH_B) & 0xffff0000; + break; + case 4: + b_offset |= + (READ_VREG(AV_SCRATCH_C) & 0xffff) + << 16; + break; + case 5: + b_offset |= + READ_VREG(AV_SCRATCH_C) & 0xffff0000; + break; + default: + break; + } + + if (error) + gvs->drop_frame_count++; + + /* add 64bit pts us ; */ + if (unlikely + ((b_offset == first_offset) + && (first_pts_cached))) { + pts = first_pts; + pts_us64 = first_pts64; + framesize = first_frame_size; + first_pts_cached = false; + pts_valid = 1; + pts_us64_valid = 1; +#ifdef DEBUG_PTS + pts_hit++; +#endif + } else if (pts_lookup_offset_us64 + (PTS_TYPE_VIDEO, b_offset, &pts, + &framesize, 0, &pts_us64) == 0) { + pts_valid = 1; + pts_us64_valid = 1; +#ifdef DEBUG_PTS + pts_hit++; +#endif + } else { + pts_valid = 0; + pts_us64_valid = 0; + framesize = 0; +#ifdef DEBUG_PTS + pts_missed++; +#endif + } + + if (idr_flag) + s_vframe_qos.type = 4; + else if (slice_type == SLICE_TYPE_I) + s_vframe_qos.type = 1; + else if (slice_type == SLICE_TYPE_P) + s_vframe_qos.type = 2; + else if (slice_type == SLICE_TYPE_B || slice_type == 8) + s_vframe_qos.type = 3; + + s_vframe_qos.size = framesize; + + if (pts_valid) + s_vframe_qos.pts = pts; + else + s_vframe_qos.pts = last_pts + DUR2PTS(frame_dur); +#ifndef ENABLE_SEI_ITU_T35 + if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_G12A) { + u32 reg_data; + if (i) { + reg_data = READ_VREG(AV_SCRATCH_N); + s_vframe_qos.max_mv + = (reg_data >> 16) & 0xffff; + s_vframe_qos.avg_mv + = (reg_data >> 8) & 0xff; + s_vframe_qos.min_mv + = reg_data & 0xff; + reg_data = READ_VREG(AV_SCRATCH_L); + s_vframe_qos.max_qp + = (reg_data >> 16) & 0xff; + s_vframe_qos.avg_qp + = (reg_data >> 8) & 0xff; + s_vframe_qos.min_qp + = reg_data & 0xff; + reg_data = READ_VREG(AV_SCRATCH_M); + s_vframe_qos.max_skip + = (reg_data >> 16) & 0xff; + s_vframe_qos.avg_skip + = (reg_data >> 8) & 0xff; + s_vframe_qos.min_skip + = reg_data & 0xff; + } else { + reg_data = READ_VREG(AV_SCRATCH_J); + s_vframe_qos.max_mv + = (reg_data >> 16) & 0xffff; + s_vframe_qos.avg_mv + = (reg_data >> 8) & 0xff; + s_vframe_qos.min_mv + = reg_data & 0xff; + reg_data = READ_VREG(AV_SCRATCH_I); + s_vframe_qos.max_qp + = (reg_data >> 16) & 0xff; + s_vframe_qos.avg_qp + = (reg_data >> 8) & 0xff; + s_vframe_qos.min_qp + = reg_data & 0xff; + reg_data = READ_VREG(AV_SCRATCH_K); + s_vframe_qos.max_skip + = (reg_data >> 16) & 0xff; + s_vframe_qos.avg_skip + = (reg_data >> 8) & 0xff; + s_vframe_qos.min_skip + = reg_data & 0xff; + } + if (decoder_debug_flag&0x2) { + pr_info("max_mv %d avg_mv %d min_mv %d slice_type %d offset %x i = %d\n", + s_vframe_qos.max_mv, + s_vframe_qos.avg_mv, + s_vframe_qos.min_mv, + slice_type, + b_offset, + i); + pr_info("max_qp %d avg_qp %d min_qp %d\n", + s_vframe_qos.max_qp, + s_vframe_qos.avg_qp, + s_vframe_qos.min_qp); + pr_info("max_skip %d avg_skip %d min_skip %d\n", + s_vframe_qos.max_skip, + s_vframe_qos.avg_skip, + s_vframe_qos.min_skip); + } + } else + search_qos_node(&s_vframe_qos, b_offset); +#endif + frame_count++; + + s_vframe_qos.num = frame_count; + //vdec_fill_frame_info(&s_vframe_qos, 1); + + /* on second IDR frame,check the diff between pts + * compute from duration and pts from lookup , + * if large than frame_dur,we think it is uncorrect. + */ + pts_lookup_save = pts; + pts_valid_save = pts_valid; + if (fixed_frame_rate_flag + && (fixed_frame_rate_check_count <= + idr_num)) { + if (idr_flag && pts_valid) { + fixed_frame_rate_check_count++; + /* pr_info("diff:%d\n", + * last_pts - pts_lookup_save); + */ + if ((fixed_frame_rate_check_count == + idr_num) && + (abs(pts - (last_pts + + DUR2PTS(frame_dur))) > + DUR2PTS(frame_dur))) { + fixed_frame_rate_flag = 0; + pr_info("pts sync mode play\n"); + } + + if (fixed_frame_rate_flag + && (fixed_frame_rate_check_count + > idr_num)) { + pr_info + ("fix_frame_rate mode play\n"); + } + } + } + + if (READ_VREG(AV_SCRATCH_F) & 2) { + /* for I only mode, ignore the PTS information + * and only uses frame duration for each I + * frame decoded + */ + if (p_last_vf) + pts_valid = 0; + /* also skip frame duration calculation + * based on PTS + */ + duration_from_pts_done = 1; + /* and add a default duration for 1/30 second + * if there is no valid frame + * duration available + */ + if (frame_dur == 0) + frame_dur = 96000 / 30; + } + + if (sync_outside == 0) { + if (!vh264_isr_parser(vf, + pts_valid, buffer_index, pts)) + continue; + + h264_pts_count++; + } else { + if (!idr_flag) + pts_valid = 0; + } + + if (pts_valid && !pts_discontinue) { + pts_discontinue = + (abs(last_pts - pts) >= + tsync_vpts_discontinuity_margin()); + } + /* if use_idr_framerate or fixed frame rate, only + * use PTS for IDR frames except for pts discontinue + */ + if (timing_info_present_flag && + frame_dur && + (use_idr_framerate || + (fixed_frame_rate_flag != 0)) + && pts_valid && h264_first_valid_pts_ready + && (!pts_discontinue)) { + pts_valid = + (slice_type == SLICE_TYPE_I) ? 1 : 0; + } + + if (!h264_first_valid_pts_ready && pts_valid) { + h264_first_valid_pts_ready = true; + last_pts = pts - DUR2PTS(frame_dur); + last_pts_remainder = 0; + } + /* calculate PTS of next frame and smooth + * PTS for fixed rate source + */ + if (pts_valid) { + if ((fixed_frame_rate_flag) && + (!pts_discontinue) && + (abs(pts_inc_by_duration(NULL, NULL) + - pts) + < DUR2PTS(frame_dur))) { + pts = pts_inc_by_duration(&pts, + &last_pts_remainder); + } else + last_pts_remainder = 0; + + } else { + if (fixed_frame_rate_flag && !pts_discontinue && + (fixed_frame_rate_check_count > idr_num) && + pts_valid_save && (sync_outside == 0) && + (abs(pts_inc_by_duration(NULL, NULL) - pts) + > DUR2PTS(frame_dur))) { + duration_from_pts_done = 0; + pr_info("recalc frame_dur\n"); + } else + pts = pts_inc_by_duration(&pts, + &last_pts_remainder); + pts_valid = 1; + } + + if ((dec_control & + flg_1080_itl) + && (frame_width == 1920) + && (frame_height >= 1080) + && (vf->duration == 3203)) + force_interlaced_frame = true; + else if ((dec_control & + flg_576_itl) + && (frame_width == 720) + && (frame_height == 576) + && (vf->duration == 3840)) + force_interlaced_frame = true; + + /* for frames with PTS, check if there is PTS + * discontinue based on previous frames + * (including error frames), + * force no VPTS discontinue reporting if we saw + *errors earlier but only once. + */ + + /*count info*/ + h264_update_gvs(); + vdec_count_info(gvs, error, b_offset); + vdec_fill_vdec_frame(vdec_h264, &s_vframe_qos, gvs, vf, 0); + + if ((pts_valid) && (check_pts_discontinue) + && (!error)) { + if (pts_discontinue) { + vf->flag = 0; + check_pts_discontinue = false; + } else if ((pts - last_pts) < 90000) { + vf->flag = VFRAME_FLAG_NO_DISCONTINUE; + check_pts_discontinue = false; + } + } + + last_pts = pts; + + if (fixed_frame_rate_flag + && (fixed_frame_rate_check_count <= + idr_num) + && (sync_outside == 0) + && pts_valid_save) + pts = pts_lookup_save; + + if (pic_struct_present) { + if ((pic_struct == PIC_TOP_BOT) + || (pic_struct == PIC_BOT_TOP)) + prog_frame = 0; + } + + if ((!force_interlaced_frame) + && (prog_frame + || (pic_struct_present + && pic_struct + <= PIC_TRIPLE_FRAME))) { + if (pic_struct_present) { + if (pic_struct == PIC_TOP_BOT_TOP + || pic_struct + == PIC_BOT_TOP_BOT) { + vf->duration += + vf->duration >> 1; + } else if (pic_struct == + PIC_DOUBLE_FRAME) + vf->duration += vf->duration; + else if (pic_struct == + PIC_TRIPLE_FRAME) { + vf->duration += + vf->duration << 1; + } + } + + last_pts = + last_pts + DUR2PTS(vf->duration - + frame_dur); + + vf->index = buffer_index; + vf->type = + VIDTYPE_PROGRESSIVE | + VIDTYPE_VIU_FIELD | + VIDTYPE_VIU_NV21; + vf->duration_pulldown = 0; + vf->signal_type = video_signal_from_vui; + vf->index = buffer_index; + vf->pts = (pts_valid) ? pts : 0; + if (pts_us64_valid == 1) + vf->pts_us64 = pts_us64; + else + vf->pts_us64 = div64_u64(((u64)vf->pts)*100, 9); + vf->canvas0Addr = vf->canvas1Addr = + spec2canvas(&buffer_spec[buffer_index]); + vf->type_original = vf->type; + vfbuf_use[buffer_index]++; + vf->mem_handle = + decoder_bmmu_box_get_mem_handle( + mm_blk_handle, + VF_BUFFER_IDX(buffer_index)); + decoder_do_frame_check(NULL, vf); + if ((error_recovery_mode_use & 2) && error) { + kfifo_put(&recycle_q, + (const struct vframe_s *)vf); + } else { + p_last_vf = vf; + pts_discontinue = false; + kfifo_put(&delay_display_q, + (const struct vframe_s *)vf); + } + } else { + if (pic_struct_present + && pic_struct == PIC_TOP_BOT) + vf->type = VIDTYPE_INTERLACE_TOP; + else if (pic_struct_present + && pic_struct == PIC_BOT_TOP) + vf->type = VIDTYPE_INTERLACE_BOTTOM; + else { + vf->type = + poc_sel ? + VIDTYPE_INTERLACE_BOTTOM : + VIDTYPE_INTERLACE_TOP; + } + vf->type |= VIDTYPE_VIU_NV21; + vf->type |= VIDTYPE_INTERLACE_FIRST; + + high_bandwidth |= + ((codec_mm_get_total_size() < 80 * SZ_1M) + & ((READ_VREG(AV_SCRATCH_N) & 0xf) == 3) + & ((frame_width * frame_height) >= 1920*1080)); + if (high_bandwidth) + vf->flag |= VFRAME_FLAG_HIGH_BANDWIDTH; + + vf->duration >>= 1; + vf->duration_pulldown = 0; + vf->signal_type = video_signal_from_vui; + vf->index = buffer_index; + vf->pts = (pts_valid) ? pts : 0; + if (pts_us64_valid == 1) + vf->pts_us64 = pts_us64; + else + vf->pts_us64 = div64_u64(((u64)vf->pts)*100, 9); + vf->canvas0Addr = vf->canvas1Addr = + spec2canvas(&buffer_spec[buffer_index]); + vf->type_original = vf->type; + vfbuf_use[buffer_index]++; + vf->ready_jiffies64 = jiffies_64; + vf->mem_handle = + decoder_bmmu_box_get_mem_handle( + mm_blk_handle, + VF_BUFFER_IDX(buffer_index)); + decoder_do_frame_check(NULL, vf); + if ((error_recovery_mode_use & 2) && error) { + kfifo_put(&recycle_q, + (const struct vframe_s *)vf); + continue; + } else { + pts_discontinue = false; + kfifo_put(&delay_display_q, + (const struct vframe_s *)vf); + } + + if (READ_VREG(AV_SCRATCH_F) & 2) + continue; + + if (kfifo_get(&newframe_q, &vf) == 0) { + pr_info + ("fatal error, no avail buffer slot."); + return IRQ_HANDLED; + } + + set_frame_info(vf); + + if (pic_struct_present + && pic_struct == PIC_TOP_BOT) + vf->type = VIDTYPE_INTERLACE_BOTTOM; + else if (pic_struct_present + && pic_struct == PIC_BOT_TOP) + vf->type = VIDTYPE_INTERLACE_TOP; + else { + vf->type = + poc_sel ? + VIDTYPE_INTERLACE_TOP : + VIDTYPE_INTERLACE_BOTTOM; + } + + vf->type |= VIDTYPE_VIU_NV21; + vf->duration >>= 1; + vf->duration_pulldown = 0; + vf->signal_type = video_signal_from_vui; + vf->index = buffer_index; + vf->pts = 0; + vf->pts_us64 = 0; + vf->canvas0Addr = vf->canvas1Addr = + spec2canvas(&buffer_spec[buffer_index]); + vf->type_original = vf->type; + vfbuf_use[buffer_index]++; + if (high_bandwidth) + vf->flag |= VFRAME_FLAG_HIGH_BANDWIDTH; + + p_last_vf = vf; + vf->ready_jiffies64 = jiffies_64; + vf->mem_handle = + decoder_bmmu_box_get_mem_handle( + mm_blk_handle, + VF_BUFFER_IDX(buffer_index)); + kfifo_put(&delay_display_q, + (const struct vframe_s *)vf); + } + } + + WRITE_VREG(AV_SCRATCH_0, 0); + } else if ((cpu_cmd & 0xff) == 3) { + vh264_running = 1; + vh264_stream_switching_state = SWITCHING_STATE_ON_CMD3; + + pr_info("Enter switching mode cmd3.\n"); + schedule_work(&stream_switching_work); + + } else if ((cpu_cmd & 0xff) == 4) { + vh264_running = 1; + /* reserved for slice group */ + WRITE_VREG(AV_SCRATCH_0, 0); + } else if ((cpu_cmd & 0xff) == 5) { + vh264_running = 1; + /* reserved for slice group */ + WRITE_VREG(AV_SCRATCH_0, 0); + } else if ((cpu_cmd & 0xff) == 6) { + vh264_running = 0; + fatal_error_flag = DECODER_FATAL_ERROR_UNKNOWN; + /* this is fatal error, need restart */ + pr_info("fatal error happend\n"); + amvdec_stop(); + if (!fatal_error_reset) + schedule_work(&error_wd_work); + } else if ((cpu_cmd & 0xff) == 7) { + vh264_running = 0; + frame_width = (READ_VREG(AV_SCRATCH_1) + 1) * 16; + pr_info("Over decoder supported size, width = %d\n", + frame_width); + fatal_error_flag = DECODER_FATAL_ERROR_SIZE_OVERFLOW; + } else if ((cpu_cmd & 0xff) == 8) { + vh264_running = 0; + frame_height = (READ_VREG(AV_SCRATCH_1) + 1) * 16; + pr_info("Over decoder supported size, height = %d\n", + frame_height); + fatal_error_flag = DECODER_FATAL_ERROR_SIZE_OVERFLOW; + } else if ((cpu_cmd & 0xff) == 9) { + first_offset = READ_VREG(AV_SCRATCH_1); + if (pts_lookup_offset_us64 + (PTS_TYPE_VIDEO, first_offset, &first_pts, + &first_frame_size, 0, + &first_pts64) == 0) + first_pts_cached = true; + WRITE_VREG(AV_SCRATCH_0, 0); + } else if ((cpu_cmd & 0xff) == 0xa) { + int b_offset; + unsigned int frame_size; + + b_offset = READ_VREG(AV_SCRATCH_2); + buffer_index = READ_VREG(AV_SCRATCH_1); + /*pr_info("iponly output %d b_offset %x\n", + * buffer_index,b_offset); + */ + if (kfifo_get(&newframe_q, &vf) == 0) { + WRITE_VREG(AV_SCRATCH_0, 0); + pr_info + ("fatal error, no available buffer slot."); + return IRQ_HANDLED; + } + if (pts_lookup_offset_us64 (PTS_TYPE_VIDEO, b_offset, + &pts, &frame_size, + 0, &pts_us64) != 0) + vf->pts_us64 = vf->pts = 0; + else { + vf->pts_us64 = pts_us64; + vf->pts = pts; + } + set_frame_info(vf); + vf->type = VIDTYPE_PROGRESSIVE | + VIDTYPE_VIU_FIELD | + VIDTYPE_VIU_NV21; + vf->duration_pulldown = 0; + vf->signal_type = video_signal_from_vui; + vf->index = buffer_index; + vf->canvas0Addr = vf->canvas1Addr = + spec2canvas(&buffer_spec[buffer_index]); + vf->type_original = vf->type; + vf->mem_handle = decoder_bmmu_box_get_mem_handle( + mm_blk_handle, + VF_BUFFER_IDX(buffer_index)); + vfbuf_use[buffer_index]++; + p_last_vf = vf; + pts_discontinue = false; + iponly_early_mode = 1; + decoder_do_frame_check(NULL, vf); + kfifo_put(&delay_display_q, + (const struct vframe_s *)vf); + WRITE_VREG(AV_SCRATCH_0, 0); + } else if ((cpu_cmd & 0xff) == 0xB) { + schedule_work(&qos_work); + } + + sei_itu35_flags = READ_VREG(AV_SCRATCH_J); + if (sei_itu35_flags & (1 << 15)) { /* data ready */ +#ifdef ENABLE_SEI_ITU_T35 + schedule_work(&userdata_push_work); +#else + /* necessary if enabled itu_t35 in ucode*/ + WRITE_VREG(AV_SCRATCH_J, 0); +#endif + } + +#ifdef HANDLE_H264_IRQ + return IRQ_HANDLED; +#else + return; +#endif +} + +static void vh264_set_clk(struct work_struct *work) +{ + int fps = 96000 / frame_dur; + + if (frame_dur < 10) /*dur is too small ,think it errors fps*/ + fps = 60; + saved_resolution = frame_width * frame_height * fps; + vdec_source_changed(VFORMAT_H264, + frame_width, frame_height, fps); +} + +static void vh264_put_timer_func(struct timer_list *timer) +{ + unsigned int wait_buffer_status; + unsigned int wait_i_pass_frames; + unsigned int reg_val; + + enum receviver_start_e state = RECEIVER_INACTIVE; + + if (vh264_reset) { + pr_info("operation forbidden in timer !\n"); + goto exit; + } + + prepare_display_q(); + + 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; +#ifndef HANDLE_H264_IRQ + vh264_isr(); +#endif + + if (vh264_stream_switching_state != SWITCHING_STATE_OFF) + wait_buffer_counter = 0; + else { + reg_val = READ_VREG(AV_SCRATCH_9); + wait_buffer_status = reg_val & (1 << 31); + wait_i_pass_frames = reg_val & 0xff; + if (wait_buffer_status) { + if (kfifo_is_empty(&display_q) && + kfifo_is_empty(&delay_display_q) && + kfifo_is_empty(&recycle_q) && + (state == RECEIVER_INACTIVE)) { + pr_info("$$$$decoder is waiting for buffer\n"); + if (++wait_buffer_counter > 4) { + amvdec_stop(); + schedule_work(&error_wd_work); + } + } else + wait_buffer_counter = 0; + } else if (wait_i_pass_frames > 1000) { + pr_info("i passed frames > 1000\n"); + amvdec_stop(); + schedule_work(&error_wd_work); + } + } + +#if 0 + if (!wait_buffer_status) { + if (vh264_no_disp_count++ > NO_DISP_WD_COUNT) { + pr_info("$$$decoder did not send frame out\n"); + amvdec_stop(); +#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER + vh264_ppmgr_reset(); +#else + vf_light_unreg_provider(PROVIDER_NAME); + vh264_local_init(); + vf_reg_provider(vh264_vf_prov); +#endif + vh264_prot_init(); + amvdec_start(); + + vh264_no_disp_count = 0; + vh264_no_disp_wd_count++; + } + } +#endif + + while (!kfifo_is_empty(&recycle_q) && + ((READ_VREG(AV_SCRATCH_7) == 0) + || (READ_VREG(AV_SCRATCH_8) == 0)) + && (vh264_stream_switching_state == SWITCHING_STATE_OFF)) { + struct vframe_s *vf; + + if (kfifo_get(&recycle_q, &vf)) { + if (vf->index < VF_BUF_NUM) { + if (--vfbuf_use[vf->index] == 0) { + if (READ_VREG(AV_SCRATCH_7) == 0) { + WRITE_VREG(AV_SCRATCH_7, + vf->index + 1); + } else { + WRITE_VREG(AV_SCRATCH_8, + vf->index + 1); + } + } + + vf->index = VF_BUF_NUM; + kfifo_put(&newframe_q, + (const struct vframe_s *)vf); + } + } + } + + if (vh264_stream_switching_state != SWITCHING_STATE_OFF) { + while (!kfifo_is_empty(&recycle_q)) { + struct vframe_s *vf; + + if (kfifo_get(&recycle_q, &vf)) { + if (vf->index < VF_BUF_NUM) { + vf->index = VF_BUF_NUM; + kfifo_put(&newframe_q, + (const struct vframe_s *)vf); + } + } + } + + WRITE_VREG(AV_SCRATCH_7, 0); + WRITE_VREG(AV_SCRATCH_8, 0); + + if (kfifo_len(&newframe_q) == VF_POOL_SIZE) + stream_switching_done(); + } + + if (ucode_type != UCODE_IP_ONLY_PARAM && + (clk_adj_frame_count > VDEC_CLOCK_ADJUST_FRAME) && + frame_dur > 0 && saved_resolution != + frame_width * frame_height * (96000 / frame_dur)) + schedule_work(&set_clk_work); + +exit: + timer->expires = jiffies + PUT_INTERVAL; + + add_timer(timer); +} + +int vh264_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus) +{ + u32 ratio_control; + u32 ar; + + if (!(stat & STAT_VDEC_RUN)) + return -1; + + 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 = READ_VREG(AV_SCRATCH_D); + vstatus->status = stat; + if (fatal_error_reset) + vstatus->status |= fatal_error_flag; + vstatus->bit_rate = gvs->bit_rate; + 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; + ar = min_t(u32, + h264_ar, + DISP_RATIO_ASPECT_RATIO_MAX); + ratio_control = + ar << DISP_RATIO_ASPECT_RATIO_BIT; + vstatus->ratio_control = ratio_control; + + snprintf(vstatus->vdec_name, sizeof(vstatus->vdec_name), + "%s", DRIVER_NAME); + + return 0; +} + +static int vh264_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_set_trickmode(struct vdec_s *vdec, unsigned long trickmode) +{ + if (trickmode == TRICKMODE_I) { + WRITE_VREG(AV_SCRATCH_F, + (READ_VREG(AV_SCRATCH_F) & 0xfffffffc) | 2); + trickmode_i = 1; + } else if (trickmode == TRICKMODE_NONE) { + WRITE_VREG(AV_SCRATCH_F, READ_VREG(AV_SCRATCH_F) & 0xfffffffc); + trickmode_i = 0; + } + + return 0; +} + +int vh264_set_isreset(struct vdec_s *vdec, int isreset) +{ + is_reset = isreset; + return 0; +} + +static void vh264_prot_init(void) +{ + ulong timeout = jiffies + HZ; + + while (READ_VREG(DCAC_DMA_CTRL) & 0x8000) { + if (time_after(jiffies, timeout)) { + pr_info("%s DCAC_DMA_CTRL time out\n", __func__); + break; + } + } + + timeout = jiffies + HZ; + while (READ_VREG(LMEM_DMA_CTRL) & 0x8000) { + if (time_after(jiffies, timeout)) { + pr_info("%s LMEM_DMA_CTRL time out\n", __func__); + break; + } + } + +#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)); + + /* disable PSCALE for hardware sharing */ + WRITE_VREG(PSCALE_CTRL, 0); + + WRITE_VREG(AV_SCRATCH_0, 0); + WRITE_VREG(AV_SCRATCH_1, buf_offset); + if (!tee_enabled()) + WRITE_VREG(AV_SCRATCH_G, mc_dma_handle); + WRITE_VREG(AV_SCRATCH_7, 0); + WRITE_VREG(AV_SCRATCH_8, 0); + WRITE_VREG(AV_SCRATCH_9, 0); + WRITE_VREG(AV_SCRATCH_N, 0); + +#ifdef SUPPORT_BAD_MACRO_BLOCK_REDUNDANCY + if (bad_block_scale > 128) + bad_block_scale = 128; + WRITE_VREG(AV_SCRATCH_A, bad_block_scale); +#endif + + error_recovery_mode_use = + (error_recovery_mode != + 0) ? error_recovery_mode : error_recovery_mode_in; + WRITE_VREG(AV_SCRATCH_F, + (READ_VREG(AV_SCRATCH_F) & 0xffffffc3) | + (READ_VREG(AV_SCRATCH_F) & 0xffffff43) | + ((error_recovery_mode_use & 0x1) << 4)); + if (dec_control & DEC_CONTROL_FLAG_DISABLE_FAST_POC) + SET_VREG_MASK(AV_SCRATCH_F, 1 << 7); + /* clear mailbox interrupt */ + WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); + + /* enable mailbox interrupt */ + WRITE_VREG(ASSIST_MBOX1_MASK, 1); + + SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17); + if (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(AV_SCRATCH_I, (u32)(sei_data_buffer_phys - buf_offset)); + WRITE_VREG(AV_SCRATCH_J, 0); + /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */ + if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M8) && !is_meson_mtvd_cpu()) { + /* pr_info("vh264 meson8 prot init\n"); */ + WRITE_VREG(MDEC_PIC_DC_THRESH, 0x404038aa); + } + /* #endif */ +} + +static int vh264_local_init(void) +{ + int i, ret; + u32 size; + unsigned long buf_start; + vh264_ratio = vh264_amstream_dec_info.ratio; + /* vh264_ratio = 0x100; */ + + vh264_rotation = (((unsigned long) vh264_amstream_dec_info.param) + >> 16) & 0xffff; + + frame_prog = 0; + frame_width = vh264_amstream_dec_info.width; + frame_height = vh264_amstream_dec_info.height; + frame_dur = vh264_amstream_dec_info.rate; + pts_outside = ((unsigned long) vh264_amstream_dec_info.param) & 0x01; + sync_outside = ((unsigned long) vh264_amstream_dec_info.param & 0x02) + >> 1; + use_idr_framerate = ((unsigned long) vh264_amstream_dec_info.param + & 0x04) >> 2; + max_refer_buf = !(((unsigned long) vh264_amstream_dec_info.param + & 0x10) >> 4); + if (!vh264_reset) { + 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_BLK_BUFFERS, + 4 + PAGE_SHIFT, + CODEC_MM_FLAGS_CMA_CLEAR | + CODEC_MM_FLAGS_FOR_VDECODER | + tvp_flag); + } + pr_info + ("H264 sysinfo: %dx%d duration=%d, pts_outside=%d \n", + frame_width, frame_height, frame_dur, pts_outside); + pr_debug("sync_outside=%d, use_idr_framerate=%d\n", + sync_outside, use_idr_framerate); + + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXTVBB) + size = V_BUF_ADDR_OFFSET_NEW; + else + size = V_BUF_ADDR_OFFSET; + + ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle, 0, + size, DRIVER_NAME, &buf_start); + if (ret < 0) + return ret; + + buf_offset = buf_start - DEF_BUF_START_ADDR; + + if ((unsigned long) vh264_amstream_dec_info.param & 0x08) + ucode_type = UCODE_IP_ONLY_PARAM; + else + ucode_type = 0; + + if ((unsigned long) vh264_amstream_dec_info.param & 0x20) + error_recovery_mode_in = 1; + else + error_recovery_mode_in = 3; + + if (!vh264_running) { + last_mb_width = 0; + last_mb_height = 0; + } + + for (i = 0; i < VF_BUF_NUM; i++) + vfbuf_use[i] = 0; + + INIT_KFIFO(display_q); + INIT_KFIFO(delay_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; + vfpool[i].bufWidth = 1920; + kfifo_put(&newframe_q, vf); + } + +#ifdef DROP_B_FRAME_FOR_1080P_50_60FPS + last_interlaced = 1; +#endif + h264_first_pts_ready = 0; + h264_first_valid_pts_ready = false; + h264pts1 = 0; + h264pts2 = 0; + h264_pts_count = 0; + duration_from_pts_done = 0; + vh264_error_count = READ_VREG(AV_SCRATCH_D); + + p_last_vf = NULL; + check_pts_discontinue = false; + last_pts = 0; + wait_buffer_counter = 0; + vh264_no_disp_count = 0; + fatal_error_flag = 0; + high_bandwidth = 0; + vh264_stream_switching_state = SWITCHING_STATE_OFF; +#ifdef DEBUG_PTS + pts_missed = 0; + pts_hit = 0; +#endif + pts_discontinue = false; + no_idr_error_count = 0; + + vh264_reset_userdata_fifo(vdec_h264, 1); + h264_reset_qos_mgr(); + + if (enable_switch_fense) { + for (i = 0; i < ARRAY_SIZE(fense_buffer_spec); i++) { + struct buffer_spec_s *s = &fense_buffer_spec[i]; + s->alloc_count = 3 * SZ_1M / PAGE_SIZE; + ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle, + FENSE_BUFFER_IDX(i), + 3 * SZ_1M, DRIVER_NAME, &s->phy_addr); + + if (ret < 0) { + fatal_error_flag = + DECODER_FATAL_ERROR_NO_MEM; + vh264_running = 0; + return ret; + } + s->y_canvas_index = 2 * i; + s->u_canvas_index = 2 * i + 1; + s->v_canvas_index = 2 * i + 1; + } + } + return 0; +} + +static s32 vh264_init(void) +{ + int ret = 0; + int trickmode_fffb = 0; + int firmwareloaded = 0; + + /* pr_info("\nvh264_init\n"); */ + timer_setup(&recycle_timer, vh264_put_timer_func, 0); + + stat |= STAT_TIMER_INIT; + + vh264_running = 0;/* init here to reset last_mb_width&last_mb_height */ + vh264_eos = 0; + duration_on_correcting = 0; + first_pts = 0; + first_pts64 = 0; + first_offset = 0; + first_pts_cached = false; + fixed_frame_rate_check_count = 0; + fr_hint_status = VDEC_NO_NEED_HINT; + saved_resolution = 0; + iponly_early_mode = 0; + saved_idc_level = 0; + + frame_count = 0; + memset(&s_vframe_qos, 0, sizeof(s_vframe_qos)); + /*init vdec status*/ + ret = vh264_vdec_info_init(); + if (0 != ret) + return -ret; + + ret = vh264_local_init(); + if (ret < 0) + return ret; + query_video_status(0, &trickmode_fffb); + + amvdec_enable(); + if (!firmwareloaded && tee_enabled()) { + ret = amvdec_loadmc_ex(VFORMAT_H264, NULL, NULL); + if (ret < 0) { + amvdec_disable(); + pr_err("H264: the %s fw loading failed, err: %x\n", + tee_enabled() ? "TEE" : "local", ret); + return ret; + } + } else { + /* -- 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(); + del_timer_sync(&recycle_timer); + pr_err("vh264_init: Can not allocate mc memory.\n"); + return -ENOMEM; + } + + pr_debug("264 ucode swap area: phyaddr %p, cpu vaddr %p\n", + (void *)mc_dma_handle, mc_cpu_addr); + if (debugfirmware) { + int r0, r1, r2, r3, r4, r5; + char firmwarename[32]; + + pr_debug("start load debug %d firmware ...\n", debugfirmware); + + snprintf(firmwarename, 32, "%s%d", "vh264_mc", debugfirmware); + r0 = amvdec_loadmc_ex(VFORMAT_H264, firmwarename, NULL); + +#define DEBUGGET_FW(t, name, buf, size, ret)\ + do {\ + snprintf(firmwarename, 32, "%s%d", name,\ + debugfirmware);\ + ret = get_decoder_firmware_data(t,\ + firmwarename, buf, size);\ + } while (0) + /*memcpy((u8 *) mc_cpu_addr + MC_OFFSET_HEADER, vh264_header_mc, + *MC_SWAP_SIZE); + */ + DEBUGGET_FW(VFORMAT_H264, "vh264_header_mc", + (u8 *) mc_cpu_addr + MC_OFFSET_HEADER, + MC_SWAP_SIZE, r1); + + /*memcpy((u8 *) mc_cpu_addr + MC_OFFSET_DATA, vh264_data_mc, + *MC_SWAP_SIZE); + */ + DEBUGGET_FW(VFORMAT_H264, "vh264_data_mc", + (u8 *) mc_cpu_addr + MC_OFFSET_DATA, MC_SWAP_SIZE, r2); + /*memcpy((u8 *) mc_cpu_addr + MC_OFFSET_MMCO, vh264_mmco_mc, + *MC_SWAP_SIZE); + */ + DEBUGGET_FW(VFORMAT_H264, "vh264_mmco_mc", + (u8 *) mc_cpu_addr + MC_OFFSET_MMCO, MC_SWAP_SIZE, r3); + /*memcpy((u8 *) mc_cpu_addr + MC_OFFSET_LIST, vh264_list_mc, + *MC_SWAP_SIZE); + */ + DEBUGGET_FW(VFORMAT_H264, "vh264_list_mc", + (u8 *) mc_cpu_addr + MC_OFFSET_LIST, MC_SWAP_SIZE, r4); + /*memcpy((u8 *) mc_cpu_addr + MC_OFFSET_SLICE, vh264_slice_mc, + *MC_SWAP_SIZE); + */ + DEBUGGET_FW(VFORMAT_H264, "vh264_slice_mc", + (u8 *) mc_cpu_addr + MC_OFFSET_SLICE, MC_SWAP_SIZE, r5); + + if (r0 < 0 || r1 < 0 || r2 < 0 || r3 < 0 || r4 < 0 || r5 < 0) { + pr_err("264 load debugfirmware err %d,%d,%d,%d,%d,%d\n", + r0, r1, r2, r3, r4, r5); + amvdec_disable(); + if (mc_cpu_addr) { + dma_free_coherent(amports_get_dma_device(), + MC_TOTAL_SIZE, mc_cpu_addr, + mc_dma_handle); + mc_cpu_addr = NULL; + } + return -EBUSY; + } + firmwareloaded = 1; + } else { + int ret = -1; + char *buf = vmalloc(0x1000 * 16); + + if (IS_ERR_OR_NULL(buf)) + return -ENOMEM; + + if (get_firmware_data(VIDEO_DEC_H264, buf) < 0) { + pr_err("get firmware fail."); + vfree(buf); + return -1; + } + + ret = amvdec_loadmc_ex(VFORMAT_H264, NULL, buf); + memcpy((u8 *) mc_cpu_addr + MC_OFFSET_HEADER, + buf + 0x4000, MC_SWAP_SIZE); + memcpy((u8 *) mc_cpu_addr + MC_OFFSET_DATA, + buf + 0x2000, MC_SWAP_SIZE); + memcpy((u8 *) mc_cpu_addr + MC_OFFSET_MMCO, + buf + 0x6000, MC_SWAP_SIZE); + memcpy((u8 *) mc_cpu_addr + MC_OFFSET_LIST, + buf + 0x3000, MC_SWAP_SIZE); + memcpy((u8 *) mc_cpu_addr + MC_OFFSET_SLICE, + buf + 0x5000, MC_SWAP_SIZE); + + vfree(buf); + + if (ret < 0) { + amvdec_disable(); + if (mc_cpu_addr) { + dma_free_coherent(amports_get_dma_device(), + MC_TOTAL_SIZE, mc_cpu_addr, + mc_dma_handle); + mc_cpu_addr = NULL; + } + pr_err("H264: the %s fw loading failed, err: %x\n", + tee_enabled() ? "TEE" : "local", ret); + return -EBUSY; + } + } + } + + stat |= STAT_MC_LOAD; + + /* enable AMRISC side protocol */ + vh264_prot_init(); + +#ifdef HANDLE_H264_IRQ + /*TODO irq */ + + if (vdec_request_irq(VDEC_IRQ_1, vh264_isr, + "vh264-irq", (void *)vh264_dec_id)) { + pr_err("vh264 irq register error.\n"); + amvdec_disable(); + return -ENOENT; + } +#endif + + stat |= STAT_ISR_REG; + +#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER + vf_provider_init(&vh264_vf_prov, PROVIDER_NAME, &vh264_vf_provider_ops, + NULL); + vf_reg_provider(&vh264_vf_prov); + vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_START, NULL); +#else + vf_provider_init(&vh264_vf_prov, PROVIDER_NAME, &vh264_vf_provider_ops, + NULL); + vf_reg_provider(&vh264_vf_prov); +#endif + + if (frame_dur != 0) { + if (!is_reset) { + vf_notify_receiver(PROVIDER_NAME, + VFRAME_EVENT_PROVIDER_FR_HINT, + (void *)((unsigned long)frame_dur)); + fr_hint_status = VDEC_HINTED; + } + } else + fr_hint_status = VDEC_NEED_HINT; + + stat |= STAT_VF_HOOK; + + recycle_timer.expires = jiffies + PUT_INTERVAL; + add_timer(&recycle_timer); + + stat |= STAT_TIMER_ARM; + + vh264_stream_switching_state = SWITCHING_STATE_OFF; + + stat |= STAT_VDEC_RUN; + wmb(); /* Ensure fetchbuf contents visible */ + + /* -- start decoder */ + amvdec_start(); + + init_userdata_fifo(); + + return 0; +} + +static int vh264_stop(int mode) +{ + + + if (stat & STAT_VDEC_RUN) { + amvdec_stop(); + stat &= ~STAT_VDEC_RUN; + } + + if (stat & STAT_ISR_REG) { + WRITE_VREG(ASSIST_MBOX1_MASK, 0); + /*TODO irq */ + + vdec_free_irq(VDEC_IRQ_1, (void *)vh264_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 (mode == MODE_FULL) { + if (fr_hint_status == VDEC_HINTED) + vf_notify_receiver(PROVIDER_NAME, + VFRAME_EVENT_PROVIDER_FR_END_HINT, + NULL); + fr_hint_status = VDEC_NO_NEED_HINT; + } + + vf_unreg_provider(&vh264_vf_prov); + stat &= ~STAT_VF_HOOK; + } + + 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; + } + } + if (sei_data_buffer != NULL) { + dma_free_coherent( + amports_get_dma_device(), + USER_DATA_RUND_SIZE, + sei_data_buffer, + sei_data_buffer_phys); + sei_data_buffer = NULL; + sei_data_buffer_phys = 0; + } + amvdec_disable(); + if (mm_blk_handle) { + decoder_bmmu_box_free(mm_blk_handle); + mm_blk_handle = NULL; + } + memset(&fense_buffer_spec, 0, sizeof(fense_buffer_spec)); + memset(&buffer_spec, 0, sizeof(buffer_spec)); + return 0; +} + +static void wait_vh264_search_done(void) +{ + 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) { + pr_info("%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 error_do_work(struct work_struct *work) +{ + + /* + * we need to lock vh264_stop/vh264_init. + * because we will call amvdec_h264_remove on this step; + * then we may call more than once on + * free_irq/deltimer/..and some other. + */ + if (atomic_read(&vh264_active)) { + amvdec_stop(); + do { + msleep(50); + } while (vh264_stream_switching_state != SWITCHING_STATE_OFF); + wait_vh264_search_done(); + vh264_reset = 1; +#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER + vh264_ppmgr_reset(); +#else + vf_light_unreg_provider(&vh264_vf_prov); + + vh264_local_init(); + + vf_reg_provider(&vh264_vf_prov); +#endif + vh264_prot_init(); + amvdec_start(); + vh264_reset = 0; + } +} + +static void stream_switching_done(void) +{ + int state = vh264_stream_switching_state; + + WRITE_VREG(AV_SCRATCH_7, 0); + WRITE_VREG(AV_SCRATCH_8, 0); + WRITE_VREG(AV_SCRATCH_9, 0); + + if (state == SWITCHING_STATE_ON_CMD1) { + pr_info("Enter set parameter cmd1 switching_state %x.\n", + vh264_stream_switching_state); + schedule_work(&set_parameter_work); + return; + } else if (state == SWITCHING_STATE_ON_CMD1_PENDING) + return; + + vh264_stream_switching_state = SWITCHING_STATE_OFF; + + wmb(); /* Ensure fetchbuf contents visible */ + + if (state == SWITCHING_STATE_ON_CMD3) + WRITE_VREG(AV_SCRATCH_0, 0); + + pr_info("Leaving switching mode.\n"); +} + +/* construt a new frame as a copy of last frame so frame receiver can + * release all buffer resources to decoder. + */ +static void stream_switching_do(struct work_struct *work) +{ + int mb_total_num, mb_width_num, mb_height_num, i = 0; + struct vframe_s *vf = NULL; + u32 y_index, u_index, src_index, des_index, y_desindex, u_desindex; + struct canvas_s csy, csu, cyd; + unsigned long flags; + bool delay = true; + + if (!atomic_read(&vh264_active)) + return; + + if (vh264_stream_switching_state == SWITCHING_STATE_OFF) + return; + + spin_lock_irqsave(&prepare_lock, flags); + + block_display_q = true; + + spin_unlock_irqrestore(&prepare_lock, flags); + + mb_total_num = mb_total; + mb_width_num = mb_width; + mb_height_num = mb_height; + + while (is_4k || kfifo_len(&delay_display_q) > 2) { + if (kfifo_get(&delay_display_q, &vf)) { + 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); + } else + break; + } + + if (!kfifo_get(&delay_display_q, &vf)) { + vf = p_last_vf; + delay = false; + } + + while (vf) { + int buffer_index; + + buffer_index = vf->index & 0xff; + + /* construct a clone of the frame from last frame */ + +#if 0 + + pr_info("src yaddr[0x%x] index[%d] width[%d] heigth[%d]\n", + buffer_spec[buffer_index].y_addr, + buffer_spec[buffer_index].y_canvas_index, + buffer_spec[buffer_index].y_canvas_width, + buffer_spec[buffer_index].y_canvas_height); + + pr_info("src uaddr[0x%x] index[%d] width[%d] heigth[%d]\n", + buffer_spec[buffer_index].u_addr, + buffer_spec[buffer_index].u_canvas_index, + buffer_spec[buffer_index].u_canvas_width, + buffer_spec[buffer_index].u_canvas_height); +#endif + if (EN_SWITCH_FENCE()) { + y_index = buffer_spec[buffer_index].y_canvas_index; + u_index = buffer_spec[buffer_index].u_canvas_index; + + canvas_read(y_index, &csy); + canvas_read(u_index, &csu); + + 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, 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, 0, VDEC_1); + + y_desindex = fense_buffer_spec[i].y_canvas_index; + u_desindex = fense_buffer_spec[i].u_canvas_index; + + canvas_read(y_desindex, &cyd); + + src_index = ((y_index & 0xff) | + ((u_index << 8) & 0x0000ff00)); + des_index = ((y_desindex & 0xff) | + ((u_desindex << 8) & 0x0000ff00)); + + ge2d_canvas_dup(&csy, &csu, &cyd, + GE2D_FORMAT_M24_NV21, + src_index, + des_index); + } + vf->mem_handle = decoder_bmmu_box_get_mem_handle( + mm_blk_handle, + FENSE_BUFFER_IDX(i)); + fense_vf[i] = *vf; + fense_vf[i].index = -1; + + if (EN_SWITCH_FENCE()) + fense_vf[i].canvas0Addr = + spec2canvas(&fense_buffer_spec[i]); + else + fense_vf[i].flag |= VFRAME_FLAG_SWITCHING_FENSE; + + /* send clone to receiver */ + kfifo_put(&display_q, + (const struct vframe_s *)&fense_vf[i]); + ATRACE_COUNTER(MODULE_NAME, fense_vf[i].pts); + /* early recycle frames for last session */ + if (delay) + vh264_vf_put(vf, NULL); + + vf_notify_receiver(PROVIDER_NAME, + VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + + i++; + + if (!kfifo_get(&delay_display_q, &vf)) + break; + } + + block_display_q = false; + + pr_info("Switching fense frame post\n"); +} + +static int amvdec_h264_probe(struct platform_device *pdev) +{ + struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data; + + mutex_lock(&vh264_mutex); + + if (pdata == NULL) { + pr_info("\namvdec_h264 memory resource undefined.\n"); + mutex_unlock(&vh264_mutex); + return -EFAULT; + } + canvas_mode = pdata->canvas_mode; + tvp_flag = vdec_secure(pdata) ? CODEC_MM_FLAGS_TVP : 0; + if (pdata->sys_info) + vh264_amstream_dec_info = *pdata->sys_info; + if (sei_data_buffer == NULL) { + sei_data_buffer = + dma_alloc_coherent(amports_get_dma_device(), + USER_DATA_RUND_SIZE, + &sei_data_buffer_phys, GFP_KERNEL); + if (!sei_data_buffer) { + pr_info("%s: Can not allocate sei_data_buffer\n", + __func__); + mutex_unlock(&vh264_mutex); + return -ENOMEM; + } + /* pr_info("buffer 0x%x, phys 0x%x, remap 0x%x\n", + * sei_data_buffer, sei_data_buffer_phys, + * (u32)sei_data_buffer_remap); + */ + } + pdata->dec_status = vh264_dec_status; + pdata->set_trickmode = vh264_set_trickmode; + pdata->set_isreset = vh264_set_isreset; + + pdata->user_data_read = vh264_user_data_read; + pdata->reset_userdata_fifo = vh264_reset_userdata_fifo; + pdata->wakeup_userdata_poll = vh264_wakeup_userdata_poll; + + is_reset = 0; + clk_adj_frame_count = 0; + if (vh264_init() < 0) { + pr_info("\namvdec_h264 init failed.\n"); + kfree(gvs); + gvs = NULL; + pdata->dec_status = NULL; + mutex_unlock(&vh264_mutex); + return -ENODEV; + } + vdec_h264 = pdata; + vh264_crate_userdata_manager(sei_data_buffer, USER_DATA_SIZE); + vh264_reset_userdata_fifo(vdec_h264, 1); + +#ifdef DUMP_USER_DATA + vh264_init_userdata_dump(); + vh264_reset_user_data_buf(); +#endif + + INIT_WORK(&error_wd_work, error_do_work); + INIT_WORK(&stream_switching_work, stream_switching_do); + INIT_WORK(&set_parameter_work, vh264_set_params); + INIT_WORK(¬ify_work, vh264_notify_work); + INIT_WORK(&set_clk_work, vh264_set_clk); + 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); + vdec_set_vframe_comm(pdata, DRIVER_NAME); + + return 0; +} + +static int amvdec_h264_remove(struct platform_device *pdev) +{ + atomic_set(&vh264_active, 0); + cancel_work_sync(&set_parameter_work); + cancel_work_sync(&error_wd_work); + cancel_work_sync(&stream_switching_work); + cancel_work_sync(¬ify_work); + cancel_work_sync(&userdata_push_work); + cancel_work_sync(&qos_work); + + + vh264_stop(MODE_FULL); + wait_vh264_search_done(); + vdec_source_changed(VFORMAT_H264, 0, 0, 0); +#ifdef DUMP_USER_DATA + vh264_dump_userdata(); +#endif + vh264_destroy_userdata_manager(); + atomic_set(&vh264_active, 0); +#ifdef DEBUG_PTS + pr_info + ("pts missed %ld, pts hit %ld, pts_outside %d, duration %d, ", + pts_missed, pts_hit, pts_outside, frame_dur); + pr_info("sync_outside %d, use_idr_framerate %d\n", + sync_outside, use_idr_framerate); +#endif + kfree(gvs); + gvs = NULL; + cancel_work_sync(&set_clk_work); + mutex_unlock(&vh264_mutex); + return 0; +} + +/****************************************/ + +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, + } +}; + +static struct codec_profile_t amvdec_h264_profile = { + .name = "h264", + .profile = "" +}; + + +static struct mconfig h264_configs[] = { + MC_PU32("stat", &stat), + MC_PU32("error_recovery_mode", &error_recovery_mode), + MC_PU32("sync_outside", &sync_outside), + MC_PU32("dec_control", &dec_control), + MC_PU32("fatal_error_reset", &fatal_error_reset), + MC_PU32("max_refer_buf", &max_refer_buf), + MC_PU32("ucode_type", &ucode_type), + MC_PU32("debugfirmware", &debugfirmware), + MC_PU32("fixed_frame_rate_flag", &fixed_frame_rate_flag), + MC_PU32("decoder_debug_flag", &decoder_debug_flag), + MC_PU32("dpb_size_adj", &dpb_size_adj), + MC_PU32("decoder_force_reset", &decoder_force_reset), + MC_PU32("no_idr_error_max", &no_idr_error_max), + MC_PU32("enable_switch_fense", &enable_switch_fense), +}; +static struct mconfig_node h264_node; + + +static int __init amvdec_h264_driver_init_module(void) +{ + pr_debug("amvdec_h264 module init\n"); + + ge2d_videoh264task_init(); + + if (platform_driver_register(&amvdec_h264_driver)) { + pr_err("failed to register amvdec_h264 driver\n"); + return -ENODEV; + } + if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXTVBB + && (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); + INIT_REG_NODE_CONFIGS("media.decoder", &h264_node, + "h264", h264_configs, CONFIG_FOR_RW); + return 0; +} + +static void __exit amvdec_h264_driver_remove_module(void) +{ + pr_debug("amvdec_h264 module remove.\n"); + + platform_driver_unregister(&amvdec_h264_driver); + + ge2d_videoh264task_release(); +} + +/****************************************/ + +module_param(stat, uint, 0664); +MODULE_PARM_DESC(stat, "\n amvdec_h264 stat\n"); +module_param(error_recovery_mode, uint, 0664); +MODULE_PARM_DESC(error_recovery_mode, "\n amvdec_h264 error_recovery_mode\n"); +module_param(sync_outside, uint, 0664); +MODULE_PARM_DESC(sync_outside, "\n amvdec_h264 sync_outside\n"); +module_param(dec_control, uint, 0664); +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"); +module_param(fatal_error_reset, uint, 0664); +MODULE_PARM_DESC(fatal_error_reset, + "\n amvdec_h264 decoder reset when fatal error happens\n"); +module_param(max_refer_buf, uint, 0664); +MODULE_PARM_DESC(max_refer_buf, + "\n amvdec_h264 dec buffering or not for reference frame\n"); +module_param(ucode_type, uint, 0664); +MODULE_PARM_DESC(ucode_type, + "\n amvdec_h264 dec buffering or not for reference frame\n"); +module_param(debugfirmware, uint, 0664); +MODULE_PARM_DESC(debugfirmware, "\n amvdec_h264 debug load firmware\n"); +module_param(fixed_frame_rate_flag, uint, 0664); +MODULE_PARM_DESC(fixed_frame_rate_flag, + "\n amvdec_h264 fixed_frame_rate_flag\n"); +module_param(decoder_debug_flag, uint, 0664); +MODULE_PARM_DESC(decoder_debug_flag, + "\n amvdec_h264 decoder_debug_flag\n"); + +module_param(dpb_size_adj, uint, 0664); +MODULE_PARM_DESC(dpb_size_adj, + "\n amvdec_h264 dpb_size_adj\n"); + + +module_param(decoder_force_reset, uint, 0664); +MODULE_PARM_DESC(decoder_force_reset, + "\n amvdec_h264 decoder force reset\n"); +module_param(no_idr_error_max, uint, 0664); +MODULE_PARM_DESC(no_idr_error_max, + "\n print no_idr_error_max\n"); +module_param(enable_switch_fense, uint, 0664); +MODULE_PARM_DESC(enable_switch_fense, + "\n enable switch fense\n"); + +#ifdef SUPPORT_BAD_MACRO_BLOCK_REDUNDANCY +module_param(bad_block_scale, uint, 0664); +MODULE_PARM_DESC(bad_block_scale, + "\n print bad_block_scale\n"); +#endif + +module_param(enable_userdata_debug, uint, 0664); +MODULE_PARM_DESC(enable_userdata_debug, + "\n enable_userdata_debug\n"); + + +module_init(amvdec_h264_driver_init_module); +module_exit(amvdec_h264_driver_remove_module); + +MODULE_DESCRIPTION("AMLOGIC H264 Video Decoder Driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Chen Zhang <chen.zhang@amlogic.com>");
diff --git a/drivers/frame_provider/decoder/h264/vh264.h b/drivers/frame_provider/decoder/h264/vh264.h new file mode 100644 index 0000000..6c8e4ad --- /dev/null +++ b/drivers/frame_provider/decoder/h264/vh264.h
@@ -0,0 +1,27 @@ +/* + * drivers/amlogic/media/frame_provider/decoder/h264/vh264.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 VH264_H +#define VH264_H + +extern int query_video_status(int type, int *value); + +/* extern s32 vh264_init(void); */ + +extern s32 vh264_release(void); + +#endif /* VMPEG4_H */
diff --git a/drivers/frame_provider/decoder/h264/vh264_mvc.c b/drivers/frame_provider/decoder/h264/vh264_mvc.c new file mode 100644 index 0000000..4827e38 --- /dev/null +++ b/drivers/frame_provider/decoder/h264/vh264_mvc.c
@@ -0,0 +1,1918 @@ +/* + * drivers/amlogic/amports/vh264mvc.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/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.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/workqueue.h> +#include <linux/dma-mapping.h> +#include <linux/atomic.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" +#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> +#include "../utils/firmware.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 + +#define DRIVER_NAME "amvdec_h264mvc" +#define MODULE_NAME "amvdec_h264mvc" + +#define HANDLE_h264mvc_IRQ + +#define DEBUG_PTS +#define DEBUG_SKIP + +#define PUT_INTERVAL (HZ/100) + +#define STAT_TIMER_INIT 0x01 +#define STAT_MC_LOAD 0x02 +#define STAT_ISR_REG 0x04 +#define STAT_VF_HOOK 0x08 +#define STAT_TIMER_ARM 0x10 +#define STAT_VDEC_RUN 0x20 + +#define DROPPING_THREAD_HOLD 4 +#define DROPPING_FIRST_WAIT 16 +#define DISPLAY_INVALID_POS -65536 + +#define INIT_DROP_FRAME_CNT 8 + +static int vh264mvc_vf_states(struct vframe_states *states, void *); +static struct vframe_s *vh264mvc_vf_peek(void *); +static struct vframe_s *vh264mvc_vf_get(void *); +static void vh264mvc_vf_put(struct vframe_s *, void *); +static int vh264mvc_event_cb(int type, void *data, void *private_data); + +static void vh264mvc_prot_init(void); +static int vh264mvc_local_init(void); +static void vh264mvc_put_timer_func(struct timer_list *timer); + +static const char vh264mvc_dec_id[] = "vh264mvc-dev"; + +#define PROVIDER_NAME "decoder.h264mvc" + +static struct vdec_info *gvs; +static struct work_struct alloc_work; +static struct work_struct set_clk_work; + +static DEFINE_MUTEX(vh264_mvc_mutex); + +static const struct vframe_operations_s vh264mvc_vf_provider = { + .peek = vh264mvc_vf_peek, + .get = vh264mvc_vf_get, + .put = vh264mvc_vf_put, + .event_cb = vh264mvc_event_cb, + .vf_states = vh264mvc_vf_states, +}; + +static struct vframe_provider_s vh264mvc_vf_prov; + +static struct vdec_s *vdec = NULL; +static u32 frame_width, frame_height, frame_dur; +static u32 saved_resolution; +static struct timer_list recycle_timer; +static u32 stat; +static u32 pts_outside; +static u32 sync_outside; +static u32 vh264mvc_ratio; +static u32 h264mvc_ar; +static u32 no_dropping_cnt; +static s32 init_drop_cnt; +spinlock_t mvc_rp_lock; + +#ifdef DEBUG_SKIP +static unsigned long view_total, view_dropped; +#endif + +#ifdef DEBUG_PTS +static unsigned long pts_missed, pts_hit; +#endif + +static atomic_t vh264mvc_active = ATOMIC_INIT(0); +static struct work_struct error_wd_work; + +static struct dec_sysinfo vh264mvc_amstream_dec_info; +static dma_addr_t mc_dma_handle; +static void *mc_cpu_addr; + +static DEFINE_SPINLOCK(lock); + +static int vh264mvc_stop(void); +static s32 vh264mvc_init(void); + +/*************************** + * new + ************************** + */ + +/* 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 CANVAS_START AV_SCRATCH_6 +#define BUFFER_RECYCLE AV_SCRATCH_7 +#define DROP_CONTROL AV_SCRATCH_8 +#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 SIM_RESERV_D AV_SCRATCH_D +#define WORKSPACE_START AV_SCRATCH_E +#define SIM_RESERV_F AV_SCRATCH_F +#define DECODE_ERROR_CNT AV_SCRATCH_G +#define CURRENT_UCODE AV_SCRATCH_H +#define CURRENT_SPS_PPS AV_SCRATCH_I/* bit[15:9]-SPS, bit[8:0]-PPS */ +#define DECODE_SKIP_PICTURE AV_SCRATCH_J +#define UCODE_START_ADDR AV_SCRATCH_K +#define SIM_RESERV_L AV_SCRATCH_L +#define REF_START_VIEW_0 AV_SCRATCH_M +#define REF_START_VIEW_1 AV_SCRATCH_N + +/******************************************** + * Mailbox command + ********************************************/ +#define CMD_FINISHED 0 +#define CMD_ALLOC_VIEW_0 1 +#define CMD_ALLOC_VIEW_1 2 +#define CMD_FRAME_DISPLAY 3 +#define CMD_FATAL_ERROR 4 + +#define CANVAS_INDEX_START 0x78 +/* /AMVDEC_H264MVC_CANVAS_INDEX */ + +#define MC_TOTAL_SIZE (28*SZ_1K) +#define MC_SWAP_SIZE (4*SZ_1K) + +unsigned int DECODE_BUFFER_START = 0x00200000; +unsigned int DECODE_BUFFER_END = 0x05000000; + +/* #define DISPLAY_BUFFER_NUM 4 */ +static unsigned int dynamic_buf_num_margin = 8; + +#define DECODE_BUFFER_NUM_MAX 16 +#define MAX_BMMU_BUFFER_NUM (DECODE_BUFFER_NUM_MAX + dynamic_buf_num_margin) +#define TOTAL_BMMU_BUFF_NUM (MAX_BMMU_BUFFER_NUM * 2 + 3) +#define VF_BUFFER_IDX(n) (2 + n) + +#define DECODER_WORK_SPACE_SIZE 0xa0000 + + +static unsigned int ANC_CANVAS_ADDR; +static unsigned int index; +static unsigned long ref_start_addr[2]; +static unsigned int max_dec_frame_buffering[2]; +static unsigned int total_dec_frame_buffering[2]; + +static unsigned int dpb_size, ref_size; + +static int display_buff_id; +static int display_view_id; +static int display_POC; +static int stream_offset; + +#define video_domain_addr(adr) (adr&0x7fffffff) +static unsigned long work_space_adr; + +struct buffer_spec_s { + unsigned int y_addr; + unsigned int u_addr; + unsigned int v_addr; + + int y_canvas_index; + int u_canvas_index; + int v_canvas_index; + + struct page *alloc_pages; + unsigned long phy_addr; + int alloc_count; +}; +/* +static struct buffer_spec_s buffer_spec0[MAX_BMMU_BUFFER_NUM]; +static struct buffer_spec_s buffer_spec1[MAX_BMMU_BUFFER_NUM]; +*/ +static struct buffer_spec_s *buffer_spec0; +static struct buffer_spec_s *buffer_spec1; +static void *mm_blk_handle; + +/* + * dbg_mode: + * bit 0: 1, print debug information + * bit 4: 1, recycle buffer without displaying; + * bit 5: 1, buffer single frame step , set dbg_cmd to 1 to step + * + */ +static int dbg_mode; +static int dbg_cmd; +static int view_mode = + 3; /* 0, left; 1 ,right ; 2, left<->right 3, right<->left */ +static int drop_rate = 2; +static int drop_thread_hold; +/**/ + +struct mvc_buf_s { + struct list_head list; + struct vframe_s vframe; + int display_POC; + int view0_buff_id; + int view1_buff_id; + int view0_drop; + int view1_drop; + int stream_offset; + unsigned int pts; +} /*mvc_buf_t */; + +#define spec2canvas(x) \ + (((x)->v_canvas_index << 16) | \ + ((x)->u_canvas_index << 8) | \ + ((x)->y_canvas_index << 0)) + +#define to_mvcbuf(vf) \ + container_of(vf, struct mvc_buf_s, vframe) + +static int vf_buf_init_flag; + +static void init_vf_buf(void) +{ + + vf_buf_init_flag = 1; +} + +static void uninit_vf_buf(void) +{ + +} + +/* #define QUEUE_SUPPORT */ + +struct mvc_info_s { + int view0_buf_id; + int view1_buf_id; + int view0_drop; + int view1_drop; + int display_pos; + int used; + int slot; + unsigned int stream_offset; +}; + +#define VF_POOL_SIZE 20 +static struct vframe_s vfpool[VF_POOL_SIZE]; +static struct mvc_info_s vfpool_idx[VF_POOL_SIZE]; +static s32 view0_vfbuf_use[DECODE_BUFFER_NUM_MAX]; +static s32 view1_vfbuf_use[DECODE_BUFFER_NUM_MAX]; + +static s32 fill_ptr, get_ptr, putting_ptr, put_ptr; +static s32 dirty_frame_num; +static s32 enable_recycle; + +static s32 init_drop_frame_id[INIT_DROP_FRAME_CNT]; +#define INCPTR(p) ptr_atomic_wrap_inc(&p) +static inline void ptr_atomic_wrap_inc(u32 *ptr) +{ + u32 i = *ptr; + + i++; + + if (i >= VF_POOL_SIZE) + i = 0; + + *ptr = i; +} + +static void set_frame_info(struct vframe_s *vf) +{ + unsigned int ar = 0; + + vf->width = frame_width; + vf->height = frame_height; + vf->duration = frame_dur; + vf->duration_pulldown = 0; + + if (vh264mvc_ratio == 0) { + /* always stretch to 16:9 */ + vf->ratio_control |= (0x90 << + DISP_RATIO_ASPECT_RATIO_BIT); + vf->sar_height = 1; + vf->sar_width = 1; + } else { + /* h264mvc_ar = ((float)frame_height/frame_width) + *customer_ratio; + */ + switch (h264mvc_ar) { + case 1: + ar = 0x3ff; + vf->sar_height = 1; + vf->sar_width = 1; + break; + case 2: + ar = 0x3ff; + vf->sar_height = 11; + vf->sar_width = 12; + break; + case 3: + ar = 0x3ff; + vf->sar_height = 11; + vf->sar_width = 10; + break; + case 4: + ar = 0x3ff; + vf->sar_height = 11; + vf->sar_width = 16; + break; + case 5: + ar = 0x3ff; + vf->sar_height = 33; + vf->sar_width = 40; + break; + case 6: + ar = 0x3ff; + vf->sar_height = 11; + vf->sar_width = 24; + break; + case 7: + ar = 0x3ff; + vf->sar_height = 11; + vf->sar_width = 20; + break; + case 8: + ar = 0x3ff; + vf->sar_height = 11; + vf->sar_width = 32; + break; + case 9: + ar = 0x3ff; + vf->sar_height = 33; + vf->sar_width = 80; + break; + case 10: + ar = 0x3ff; + vf->sar_height = 11; + vf->sar_width = 18; + break; + case 11: + ar = 0x3ff; + vf->sar_height = 11; + vf->sar_width = 15; + break; + case 12: + ar = 0x3ff; + vf->sar_height = 33; + vf->sar_width = 64; + break; + case 13: + ar = 0x3ff; + vf->sar_height = 99; + vf->sar_width = 160; + break; + case 14: + ar = 0x3ff; + vf->sar_height = 3; + vf->sar_width = 4; + break; + case 15: + ar = 0x3ff; + vf->sar_height = 2; + vf->sar_width = 3; + break; + case 16: + ar = 0x3ff; + vf->sar_height = 1; + vf->sar_width = 2; + break; + default: + ar = 0x3ff; + vf->sar_height = 1; + vf->sar_width = 1; + break; + } + } + ar = min_t(u32, ar, DISP_RATIO_ASPECT_RATIO_MAX); + + vf->ratio_control = (ar << DISP_RATIO_ASPECT_RATIO_BIT); +} + +static int vh264mvc_vf_states(struct vframe_states *states, void *op_arg) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&lock, flags); + states->vf_pool_size = VF_POOL_SIZE; + + i = put_ptr - fill_ptr; + if (i < 0) + i += VF_POOL_SIZE; + states->buf_free_num = i; + + i = putting_ptr - put_ptr; + if (i < 0) + i += VF_POOL_SIZE; + states->buf_recycle_num = i; + + i = fill_ptr - get_ptr; + if (i < 0) + i += VF_POOL_SIZE; + states->buf_avail_num = i; + + spin_unlock_irqrestore(&lock, flags); + return 0; +} + +void send_drop_cmd(void) +{ + int ready_cnt = 0; + int temp_get_ptr = get_ptr; + int temp_fill_ptr = fill_ptr; + + while (temp_get_ptr != temp_fill_ptr) { + if ((vfpool_idx[temp_get_ptr].view0_buf_id >= 0) + && (vfpool_idx[temp_get_ptr].view1_buf_id >= 0) + && (vfpool_idx[temp_get_ptr].view0_drop == 0) + && (vfpool_idx[temp_get_ptr].view1_drop == 0)) + ready_cnt++; + INCPTR(temp_get_ptr); + } + if (dbg_mode & 0x40) { + pr_info("ready_cnt is %d ; no_dropping_cnt is %d\n", ready_cnt, + no_dropping_cnt); + } + if ((no_dropping_cnt >= DROPPING_FIRST_WAIT) + && (ready_cnt < drop_thread_hold)) + WRITE_VREG(DROP_CONTROL, (1 << 31) | (drop_rate)); + else + WRITE_VREG(DROP_CONTROL, 0); +} + +#if 0 +int get_valid_frame(void) +{ + int ready_cnt = 0; + int temp_get_ptr = get_ptr; + int temp_fill_ptr = fill_ptr; + + while (temp_get_ptr != temp_fill_ptr) { + if ((vfpool_idx[temp_get_ptr].view0_buf_id >= 0) + && (vfpool_idx[temp_get_ptr].view1_buf_id >= 0) + && (vfpool_idx[temp_get_ptr].view0_drop == 0) + && (vfpool_idx[temp_get_ptr].view1_drop == 0)) + ready_cnt++; + INCPTR(temp_get_ptr); + } + return ready_cnt; +} +#endif +static struct vframe_s *vh264mvc_vf_peek(void *op_arg) +{ + + if (get_ptr == fill_ptr) + return NULL; + send_drop_cmd(); + return &vfpool[get_ptr]; + +} + +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; + + view0_buf_id = vfpool_idx[get_ptr].view0_buf_id; + view1_buf_id = vfpool_idx[get_ptr].view1_buf_id; + vf = &vfpool[get_ptr]; + + if ((view0_buf_id >= 0) && (view1_buf_id >= 0)) { + if (view_mode == 0 || view_mode == 1) { + vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD; + + 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; + + vf->left_eye.start_x = 0; + vf->left_eye.start_y = 0; + vf->left_eye.width = vf->width; + vf->left_eye.height = vf->height; + vf->right_eye.start_x = 0; + 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; + + if (view_mode == 2) { + buf_spec_0 = &buffer_spec1[view1_buf_id]; + buf_spec_1 = &buffer_spec0[view0_buf_id]; + } else { + 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)) + && ((no_dropping_cnt >= DROPPING_FIRST_WAIT))) + vf->frame_dirty = 1; + else + vf->frame_dirty = 0; + + INCPTR(get_ptr); + + if (frame_width == 0) + frame_width = vh264mvc_amstream_dec_info.width; + if (frame_height == 0) + frame_height = vh264mvc_amstream_dec_info.height; + + vf->width = frame_width; + vf->height = frame_height; + + if ((no_dropping_cnt < DROPPING_FIRST_WAIT) && (vf->frame_dirty == 0)) + no_dropping_cnt++; + return vf; + +} + +static void vh264mvc_vf_put(struct vframe_s *vf, void *op_arg) +{ + + if (vf_buf_init_flag == 0) + return; + if (vf->frame_dirty) { + + vf->frame_dirty = 0; + dirty_frame_num++; + enable_recycle = 0; + if (dbg_mode & PUT_PRINT_ENABLE) { + pr_info("invalid: dirty_frame_num is !!! %d\n", + dirty_frame_num); + } + } else { + INCPTR(putting_ptr); + while (dirty_frame_num > 0) { + INCPTR(putting_ptr); + dirty_frame_num--; + } + enable_recycle = 1; + if (dbg_mode & PUT_PRINT_ENABLE) { + pr_info("valid: dirty_frame_num is @@@ %d\n", + dirty_frame_num); + } + /* send_drop_cmd(); */ + } + +} + +static int vh264mvc_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(&vh264mvc_vf_prov); +#endif + spin_lock_irqsave(&lock, flags); + vh264mvc_local_init(); + vh264mvc_prot_init(); + spin_unlock_irqrestore(&lock, flags); +#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER + vf_reg_provider(&vh264mvc_vf_prov); +#endif + amvdec_start(); + } + return 0; +} + +/**/ +static long init_canvas(int view_index, 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, bmmu_index; + int mb_total, ret = -1; + /* cav_con canvas; */ + mb_total = mb_width * mb_height; + mutex_lock(&vh264_mvc_mutex); + + for (j = 0; j < (dpb_number + 1); j++) { + int page_count; + if (j == 0) { + if (!view_index) + bmmu_index = 1; + else + bmmu_index = dpb_number + 2; + + ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle, + bmmu_index, refbuf_size, DRIVER_NAME, + &ref_start_addr[view_index]); + + if (ret < 0) { + mutex_unlock(&vh264_mvc_mutex); + return ret; + } + + continue; + } + /* canvas buf */ + WRITE_VREG(ANC_CANVAS_ADDR, + index | ((index + 1) << 8) | + ((index + 2) << 16)); + ANC_CANVAS_ADDR++; + + i = j - 1; + if (!view_index) + bmmu_index = VF_BUFFER_IDX(i); + else + bmmu_index = VF_BUFFER_IDX(i) + dpb_number + 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, + bmmu_index, page_count << PAGE_SHIFT, + DRIVER_NAME, &buffer_spec[i].phy_addr); + + if (ret < 0) { + buffer_spec[i].alloc_count = 0; + mutex_unlock(&vh264_mvc_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; + config_cav_lut_ex(index, addr, + mb_width << 4, mb_height << 4, + 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; + 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; + config_cav_lut_ex(index, addr, mb_width << 3, mb_height << 3, + CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32, 0, VDEC_1); + + index++; + } + mutex_unlock(&vh264_mvc_mutex); + 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: + size = 70778880; + break; + default: + break; + } + + size /= pic_size; + size = size + 1; /* For MVC need onr 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; +} + +int check_in_list(int pos, int *slot) +{ + int i; + int ret = 0; + + for (i = 0; i < VF_POOL_SIZE; i++) { + if ((vfpool_idx[i].display_pos == pos) + && (vfpool_idx[i].used == 0)) { + ret = 1; + *slot = vfpool_idx[i].slot; + break; + } + } + return ret; +} + +static void do_alloc_work(struct work_struct *work) +{ + int level_idc, max_reference_frame_num, mb_width, mb_height; + int refbuf_size; + int ret = READ_VREG(MAILBOX_COMMAND); + + switch (ret & 0xff) { + case CMD_ALLOC_VIEW_0: + if (dbg_mode & 0x1) { + pr_info + ("Start H264 display buffer for view 0\n"); + } + + ret = READ_VREG(MAILBOX_DATA_0); + level_idc = (ret >> 24) & 0xff; + max_reference_frame_num = (ret >> 16) & 0xff; + mb_width = (ret >> 8) & 0xff; + mb_height = (ret >> 0) & 0xff; + max_dec_frame_buffering[0] = + get_max_dec_frame_buf_size(level_idc, + max_reference_frame_num, + mb_width, mb_height); + + total_dec_frame_buffering[0] = + max_dec_frame_buffering[0] + dynamic_buf_num_margin; + + 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; + + if (dbg_mode & 0x1) { + pr_info("dpb_size: 0x%x\n", dpb_size); + pr_info("ref_size: 0x%x\n", ref_size); + pr_info("total_dec_frame_buffering[0] : 0x%x\n", + total_dec_frame_buffering[0]); + pr_info("max_reference_frame_num: 0x%x\n", + max_reference_frame_num); + } + refbuf_size + = ref_size * (max_reference_frame_num + 1) * 2; + + if (is_support_vdec_canvas()) + index = 0; + else + index = CANVAS_INDEX_START; + ANC_CANVAS_ADDR = ANC0_CANVAS_ADDR; + + ret = + init_canvas(0, refbuf_size, dpb_size, + total_dec_frame_buffering[0], mb_width, + mb_height, buffer_spec0); + + if (ret < 0) { + pr_info(" Un-expected memory alloc problem\n"); + return; + } + + WRITE_VREG(REF_START_VIEW_0, + video_domain_addr(ref_start_addr[0])); + WRITE_VREG(MAILBOX_DATA_0, + (max_dec_frame_buffering[0] << 8) | + (total_dec_frame_buffering[0] << 0)); + WRITE_VREG(MAILBOX_DATA_1, ref_size); + WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED); + + if (dbg_mode & 0x1) { + pr_info + ("End H264 display buffer for view 0\n"); + } + if (frame_width == 0) { + if (vh264mvc_amstream_dec_info.width) + frame_width = vh264mvc_amstream_dec_info.width; + else + frame_width = mb_width << 4; + } + if (frame_height == 0) { + frame_height = mb_height << 4; + if (frame_height == 1088) + frame_height = 1080; + } + break; + case CMD_ALLOC_VIEW_1: + if (dbg_mode & 0x1) { + pr_info + ("Start H264 display buffer for view 1\n"); + } + + ret = READ_VREG(MAILBOX_DATA_0); + level_idc = (ret >> 24) & 0xff; + max_reference_frame_num = (ret >> 16) & 0xff; + mb_width = (ret >> 8) & 0xff; + mb_height = (ret >> 0) & 0xff; + max_dec_frame_buffering[1] = + get_max_dec_frame_buf_size(level_idc, + max_reference_frame_num, + mb_width, mb_height); + if (max_dec_frame_buffering[1] != max_dec_frame_buffering[0]) { + pr_info + (" Warning: view0/1 max_dec_frame_buffering "); + pr_info("different : 0x%x/0x%x, Use View0\n", + max_dec_frame_buffering[0], + max_dec_frame_buffering[1]); + max_dec_frame_buffering[1] = max_dec_frame_buffering[0]; + } + + total_dec_frame_buffering[1] = + max_dec_frame_buffering[1] + dynamic_buf_num_margin; + + 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; + if (dbg_mode & 0x1) { + pr_info("dpb_size: 0x%x\n", dpb_size); + pr_info("ref_size: 0x%x\n", ref_size); + pr_info("total_dec_frame_buffering[1] : 0x%x\n", + total_dec_frame_buffering[1]); + pr_info("max_reference_frame_num: 0x%x\n", + max_reference_frame_num); + } + + 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]; + + ret = init_canvas(1, refbuf_size, dpb_size, + total_dec_frame_buffering[1], mb_width, + mb_height, buffer_spec1); + + if (ret < 0) { + pr_info(" Un-expected memory alloc problem\n"); + return; + } + + WRITE_VREG(REF_START_VIEW_1, + video_domain_addr(ref_start_addr[1])); + WRITE_VREG(MAILBOX_DATA_0, + (max_dec_frame_buffering[1] << 8) | + (total_dec_frame_buffering[1] << 0)); + WRITE_VREG(MAILBOX_DATA_1, ref_size); + WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED); + + if (dbg_mode & 0x1) { + pr_info + ("End H264 buffer allocation for view 1\n"); + } + if (frame_width == 0) { + if (vh264mvc_amstream_dec_info.width) + frame_width = vh264mvc_amstream_dec_info.width; + else + frame_width = mb_width << 4; + } + if (frame_height == 0) { + frame_height = mb_height << 4; + if (frame_height == 1088) + frame_height = 1080; + } + break; + } + +} + +static void mvc_set_rp(void) { + unsigned long flags; + + spin_lock_irqsave(&mvc_rp_lock, flags); + STBUF_WRITE(&vdec->vbuf, set_rp, + READ_VREG(VLD_MEM_VIFIFO_RP)); + spin_unlock_irqrestore(&mvc_rp_lock, flags); +} + +#ifdef HANDLE_h264mvc_IRQ +static irqreturn_t vh264mvc_isr(int irq, void *dev_id) +#else +static void vh264mvc_isr(void) +#endif +{ + int drop_status; + struct vframe_s *vf; + unsigned int pts, pts_valid = 0; + u64 pts_us64; + u32 frame_size; + int ret = READ_VREG(MAILBOX_COMMAND); + + mvc_set_rp(); + + /* pr_info("vh264mvc_isr, cmd =%x\n", ret); */ + switch (ret & 0xff) { + case CMD_ALLOC_VIEW_0: + case CMD_ALLOC_VIEW_1: + schedule_work(&alloc_work); + break; + case CMD_FRAME_DISPLAY: + ret = READ_VREG(MAILBOX_DATA_0); + display_buff_id = (ret >> 0) & 0x3f; + display_view_id = (ret >> 6) & 0x3; + drop_status = (ret >> 8) & 0x1; + display_POC = READ_VREG(MAILBOX_DATA_1); + stream_offset = READ_VREG(MAILBOX_DATA_2); + /* if (display_view_id == 0) */ + WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED); + +#ifdef DEBUG_SKIP + view_total++; + if (drop_status) + view_dropped++; +#endif + if (dbg_mode & 0x1) { + pr_info + (" H264 display frame ready - View : %x, Buffer : %x\n", + display_view_id, display_buff_id); + pr_info + (" H264 display frame POC -- Buffer : %x, POC : %x\n", + display_buff_id, display_POC); + pr_info("H264 display frame ready\n"); + } + if (dbg_mode & 0x10) { + if ((dbg_mode & 0x20) == 0) { + while (READ_VREG(BUFFER_RECYCLE) != 0) + ; + WRITE_VREG(BUFFER_RECYCLE, + (display_view_id << 8) | + (display_buff_id + 1)); + display_buff_id = -1; + display_view_id = -1; + display_POC = -1; + } + } else { + unsigned char in_list_flag = 0; + + int slot = 0; + + in_list_flag = check_in_list(display_POC, &slot); + + if ((dbg_mode & 0x40) && (drop_status)) { + pr_info + ("drop_status:%dview_id=%d,buff_id=%d,", + drop_status, display_view_id, display_buff_id); + pr_info + ("offset=%d, display_POC = %d,fill_ptr=0x%x\n", + stream_offset, display_POC, fill_ptr); + } + + if ((in_list_flag) && (stream_offset != 0)) { + pr_info + ("error case ,display_POC is %d, slot is %d\n", + display_POC, slot); + in_list_flag = 0; + } + if (!in_list_flag) { + if (display_view_id == 0) { + vfpool_idx[fill_ptr].view0_buf_id = + display_buff_id; + view0_vfbuf_use[display_buff_id]++; + vfpool_idx[fill_ptr].stream_offset = + stream_offset; + vfpool_idx[fill_ptr].view0_drop = + drop_status; + } + if (display_view_id == 1) { + vfpool_idx[fill_ptr].view1_buf_id = + display_buff_id; + vfpool_idx[fill_ptr].view1_drop = + drop_status; + view1_vfbuf_use[display_buff_id]++; + } + vfpool_idx[fill_ptr].slot = fill_ptr; + vfpool_idx[fill_ptr].display_pos = display_POC; + + } else { + if (display_view_id == 0) { + vfpool_idx[slot].view0_buf_id = + display_buff_id; + view0_vfbuf_use[display_buff_id]++; + vfpool_idx[slot].stream_offset = + stream_offset; + vfpool_idx[slot].view0_drop = + drop_status; + + } + if (display_view_id == 1) { + vfpool_idx[slot].view1_buf_id = + display_buff_id; + view1_vfbuf_use[display_buff_id]++; + vfpool_idx[slot].view1_drop = + drop_status; + } + vf = &vfpool[slot]; + + if (display_view_id == 0) { + vf->mem_handle = + decoder_bmmu_box_get_mem_handle( + mm_blk_handle, + VF_BUFFER_IDX(display_buff_id)); + + } else if (display_view_id == 1) { + vf->mem_head_handle = + decoder_bmmu_box_get_mem_handle( + mm_blk_handle, + VF_BUFFER_IDX(display_buff_id)); + + vf->mem_handle = + decoder_bmmu_box_get_mem_handle( + mm_blk_handle, + VF_BUFFER_IDX(display_buff_id) + + total_dec_frame_buffering[0] + + 1); + } + + + + if (vfpool_idx[slot].stream_offset == 0) { + pr_info + ("error case, invalid stream offset\n"); + } + if (pts_lookup_offset_us64 + (PTS_TYPE_VIDEO, + vfpool_idx[slot].stream_offset, &pts, + &frame_size, + 0x10000, &pts_us64) == 0) + pts_valid = 1; + else + pts_valid = 0; + vf->pts = (pts_valid) ? pts : 0; + vf->pts_us64 = (pts_valid) ? pts_us64 : 0; + /* vf->pts = vf->pts_us64 ? vf->pts_us64 + * : vf->pts ; + */ + /* vf->pts = vf->pts_us64; */ + if (dbg_mode & 0x80) + pr_info("vf->pts:%d\n", vf->pts); + vfpool_idx[slot].used = 1; + INCPTR(fill_ptr); + set_frame_info(vf); + + gvs->frame_dur = frame_dur; + vdec_count_info(gvs, 0, + vfpool_idx[slot].stream_offset); + + vf_notify_receiver(PROVIDER_NAME, + VFRAME_EVENT_PROVIDER_VFRAME_READY, + NULL); + + } + } + break; + case CMD_FATAL_ERROR: + pr_info("fatal error !!!\n"); + schedule_work(&error_wd_work); + break; + default: + break; + } +#ifdef HANDLE_h264mvc_IRQ + return IRQ_HANDLED; +#else + return; +#endif +} + +static void vh264_mvc_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_H264MVC, + frame_width, frame_height, fps * 2); + } +} + +static void vh264mvc_put_timer_func(struct timer_list *timer) +{ + int valid_frame = 0; + + mvc_set_rp(); + + if (enable_recycle == 0) { + if (dbg_mode & TIME_TASK_PRINT_ENABLE) { + /* valid_frame = get_valid_frame(); */ + pr_info("dirty_frame_num is %d , valid frame is %d\n", + dirty_frame_num, valid_frame); + + } + /* goto RESTART; */ + } + + while ((putting_ptr != put_ptr) && (READ_VREG(BUFFER_RECYCLE) == 0)) { + int view0_buf_id = vfpool_idx[put_ptr].view0_buf_id; + int view1_buf_id = vfpool_idx[put_ptr].view1_buf_id; + + if ((view0_buf_id >= 0) && + (view0_vfbuf_use[view0_buf_id] == 1)) { + if (dbg_mode & 0x100) { + pr_info + ("round 0: put_ptr is %d ;view0_buf_id is %d\n", + put_ptr, view0_buf_id); + } + WRITE_VREG(BUFFER_RECYCLE, + (0 << 8) | (view0_buf_id + 1)); + view0_vfbuf_use[view0_buf_id] = 0; + vfpool_idx[put_ptr].view0_buf_id = -1; + vfpool_idx[put_ptr].view0_drop = 0; + } else if ((view1_buf_id >= 0) + && (view1_vfbuf_use[view1_buf_id] == 1)) { + if (dbg_mode & 0x100) { + pr_info + ("round 1: put_ptr is %d ;view1_buf_id %d==\n", + put_ptr, view1_buf_id); + } + WRITE_VREG(BUFFER_RECYCLE, + (1 << 8) | (view1_buf_id + 1)); + view1_vfbuf_use[view1_buf_id] = 0; + vfpool_idx[put_ptr].display_pos = DISPLAY_INVALID_POS; + vfpool_idx[put_ptr].view1_buf_id = -1; + vfpool_idx[put_ptr].view1_drop = 0; + vfpool_idx[put_ptr].used = 0; + INCPTR(put_ptr); + } + } + + schedule_work(&set_clk_work); + + /* RESTART: */ + timer->expires = jiffies + PUT_INTERVAL; + + add_timer(timer); +} + +int vh264mvc_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 = READ_VREG(AV_SCRATCH_D); + vstatus->status = stat; + vstatus->bit_rate = gvs->bit_rate; + 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 vh264mvc_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 vh264mvc_set_trickmode(struct vdec_s *vdec, unsigned long trickmode) +{ + if (trickmode == TRICKMODE_I) { + WRITE_VREG(AV_SCRATCH_F, + (READ_VREG(AV_SCRATCH_F) & 0xfffffffc) | 2); + trickmode_i = 1; + } else if (trickmode == TRICKMODE_NONE) { + WRITE_VREG(AV_SCRATCH_F, READ_VREG(AV_SCRATCH_F) & 0xfffffffc); + trickmode_i = 0; + } + + return 0; +} + +static void H264_DECODE_INIT(void) +{ + int i; + + i = READ_VREG(DECODE_SKIP_PICTURE); + +#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 + + /* Wait for some time for RESET */ + READ_VREG(DECODE_SKIP_PICTURE); + READ_VREG(DECODE_SKIP_PICTURE); + + WRITE_VREG(DECODE_SKIP_PICTURE, i); + + /* 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); + /* disable COEF_GT_64 , error_m4_table and voff_rw_err */ + 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 */ + + /* 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)); +#if 0 + WRITE_VREG(POWER_CTL_VLD, + READ_VREG(POWER_CTL_VLD) | (0 << 10) | + (1 << 9) | (1 << 6)); +#else + WRITE_VREG(POWER_CTL_VLD, ((1 << 10) | /* disable cabac_step_2 */ + (1 << 9) | /* viff_drop_flag_en */ + (1 << 6) /* h264_000003_en */ + ) + ); +#endif + WRITE_VREG(M4_CONTROL_REG, (1 << 13)); /* H264_DECODE_INFO - h264_en */ + + 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, + video_domain_addr(work_space_adr)); +#else + /* Start Address of Workspace (UCODE, temp_data...) */ + WRITE_VREG(WORKSPACE_START, + 0x05000000); +#endif + /* 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 vh264mvc_prot_init(void) +{ + while (READ_VREG(DCAC_DMA_CTRL) & 0x8000) + ; + while (READ_VREG(LMEM_DMA_CTRL) & 0x8000) + ; /* reg address is 0x350 */ + /* clear mailbox interrupt */ + WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); + + /* enable mailbox interrupt */ + WRITE_VREG(ASSIST_MBOX1_MASK, 1); + + /* disable PSCALE for hardware sharing */ + WRITE_VREG(PSCALE_CTRL, 0); + + H264_DECODE_INIT(); + +#if 1 /* /MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */ + 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); + +#else + WRITE_RESET_REG(RESET0_REGISTER, 0x80); /* RESET MCPU */ +#endif + + WRITE_VREG(MAILBOX_COMMAND, 0); + 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 +} + +static int vh264mvc_local_init(void) +{ + int i, size, ret; + display_buff_id = -1; + display_view_id = -1; + display_POC = -1; + no_dropping_cnt = 0; + init_drop_cnt = INIT_DROP_FRAME_CNT; + + for (i = 0; i < INIT_DROP_FRAME_CNT; i++) + init_drop_frame_id[i] = 0; + +#ifdef DEBUG_PTS + pts_missed = 0; + pts_hit = 0; +#endif + +#ifdef DEBUG_SKIP + view_total = 0; + view_dropped = 0; +#endif + + /* vh264mvc_ratio = vh264mvc_amstream_dec_info.ratio; */ + vh264mvc_ratio = 0x100; + + /* frame_width = vh264mvc_amstream_dec_info.width; */ + /* frame_height = vh264mvc_amstream_dec_info.height; */ + frame_dur = vh264mvc_amstream_dec_info.rate; + if (frame_dur == 0) + frame_dur = 96000 / 24; + + pts_outside = ((unsigned long) vh264mvc_amstream_dec_info.param) & 0x01; + sync_outside = ((unsigned long) vh264mvc_amstream_dec_info.param & 0x02) + >> 1; + INIT_WORK(&alloc_work, do_alloc_work); + + max_dec_frame_buffering[0] = -1; + 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; + } + + for (i = 0; i < VF_POOL_SIZE; i++) { + vfpool_idx[i].display_pos = -1; + vfpool_idx[i].view0_buf_id = DISPLAY_INVALID_POS; + vfpool_idx[i].view1_buf_id = -1; + vfpool_idx[i].view0_drop = 0; + vfpool_idx[i].view1_drop = 0; + vfpool_idx[i].used = 0; + } + for (i = 0; i < VF_POOL_SIZE; i++) { + memset(&vfpool[i], 0, sizeof(struct vframe_s)); + vfpool[i].index = i; + } + init_vf_buf(); + + 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, + TOTAL_BMMU_BUFF_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 vh264mvc_init(void) +{ + int ret = -1; + char *buf = vmalloc(0x1000 * 16); + + if (buf == NULL) + return -ENOMEM; + + pr_info("\nvh264mvc_init\n"); + timer_setup(&recycle_timer, vh264mvc_put_timer_func, 0); + + stat |= STAT_TIMER_INIT; + + ret = vh264mvc_vdec_info_init(); + if (0 != ret) { + vfree(buf); + return -ret; + } + + ret = vh264mvc_local_init(); + if (ret < 0) { + vfree(buf); + return ret; + } + + amvdec_enable(); + + if (tee_enabled()) { + ret = amvdec_loadmc_ex(VFORMAT_H264MVC, NULL, buf); + if (ret != 0) { + amvdec_disable(); + vfree(buf); + pr_err("H264_MVC: the %s fw loading failed, err: %x\n", + tee_enabled() ? "TEE" : "local", ret); + return -1; + } + } else { + /* -- 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_mvc init: Can not allocate mc memory.\n"); + return -ENOMEM; + } + + WRITE_VREG(UCODE_START_ADDR, mc_dma_handle); + + if (get_firmware_data(VIDEO_DEC_H264_MVC, buf) < 0) { + pr_err("get firmware fail."); + vfree(buf); + return -1; + } + + ret = amvdec_loadmc_ex(VFORMAT_H264MVC, NULL, buf); + + /*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); + + 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; + return -EBUSY; + } + } + vfree(buf); + + stat |= STAT_MC_LOAD; + + /* enable AMRISC side protocol */ + vh264mvc_prot_init(); + +#ifdef HANDLE_h264mvc_IRQ + if (vdec_request_irq(VDEC_IRQ_1, vh264mvc_isr, + "vh264mvc-irq", (void *)vh264mvc_dec_id)) { + pr_info("vh264mvc irq register error.\n"); + amvdec_disable(); + return -ENOENT; + } +#endif + + stat |= STAT_ISR_REG; + + vf_provider_init(&vh264mvc_vf_prov, PROVIDER_NAME, + &vh264mvc_vf_provider, NULL); + vf_reg_provider(&vh264mvc_vf_prov); + vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_START, NULL); + + stat |= STAT_VF_HOOK; + + recycle_timer.expires = jiffies + PUT_INTERVAL; + add_timer(&recycle_timer); + + stat |= STAT_TIMER_ARM; + + amvdec_start(); + + stat |= STAT_VDEC_RUN; + + return 0; +} + +static int vh264mvc_stop(void) +{ + if (stat & STAT_VDEC_RUN) { + amvdec_stop(); + stat &= ~STAT_VDEC_RUN; + } + + if (stat & STAT_ISR_REG) { + WRITE_VREG(ASSIST_MBOX1_MASK, 0); +#ifdef HANDLE_h264mvc_IRQ + vdec_free_irq(VDEC_IRQ_1, (void *)vh264mvc_dec_id); +#endif + stat &= ~STAT_ISR_REG; + } + + if (stat & STAT_TIMER_ARM) { + del_timer_sync(&recycle_timer); + stat &= ~STAT_TIMER_ARM; + } + + if (stat & STAT_VF_HOOK) { + ulong flags; + + spin_lock_irqsave(&lock, flags); + spin_unlock_irqrestore(&lock, flags); + vf_unreg_provider(&vh264mvc_vf_prov); + stat &= ~STAT_VF_HOOK; + } + + 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 (mm_blk_handle) { + decoder_bmmu_box_free(mm_blk_handle); + mm_blk_handle = NULL; + } + uninit_vf_buf(); + return 0; +} + +static void error_do_work(struct work_struct *work) +{ + if (atomic_read(&vh264mvc_active)) { + vh264mvc_stop(); + vh264mvc_init(); + } +} + +static int amvdec_h264mvc_probe(struct platform_device *pdev) +{ + struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data; + int config_val = 0; + + pr_info("amvdec_h264mvc probe start.\n"); + mutex_lock(&vh264_mvc_mutex); + +#if 0 + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + pr_info("\namvdec_h264mvc memory resource undefined.\n"); + return -EFAULT; + } +#endif + + if (pdata == NULL) { + mutex_unlock(&vh264_mvc_mutex); + pr_info("\namvdec_h264mvc memory resource undefined.\n"); + return -EFAULT; + } + + if (pdata->sys_info) + vh264mvc_amstream_dec_info = *pdata->sys_info; + + if (pdata->config_len) { + pr_info("pdata->config: %s\n", pdata->config); + if (get_config_int(pdata->config, "parm_v4l_buffer_margin", + &config_val) == 0) + dynamic_buf_num_margin = config_val; + } + + pdata->dec_status = vh264mvc_dec_status; + /* pdata->set_trickmode = vh264mvc_set_trickmode; */ + + buffer_spec0 = (struct buffer_spec_s *)vzalloc( + sizeof(struct buffer_spec_s) * MAX_BMMU_BUFFER_NUM * 2); + if (NULL == buffer_spec0) + return -ENOMEM; + buffer_spec1 = &buffer_spec0[MAX_BMMU_BUFFER_NUM]; + + if (vh264mvc_init() < 0) { + pr_info("\namvdec_h264mvc init failed.\n"); + kfree(gvs); + gvs = NULL; + vfree(buffer_spec0); + buffer_spec0 = NULL; + mutex_unlock(&vh264_mvc_mutex); + return -ENODEV; + } + + INIT_WORK(&error_wd_work, error_do_work); + INIT_WORK(&set_clk_work, vh264_mvc_set_clk); + spin_lock_init(&mvc_rp_lock); + + vdec = pdata; + + atomic_set(&vh264mvc_active, 1); + + mutex_unlock(&vh264_mvc_mutex); + + pr_info("amvdec_h264mvc probe end.\n"); + + return 0; +} + +static int amvdec_h264mvc_remove(struct platform_device *pdev) +{ + pr_info("amvdec_h264mvc_remove\n"); + cancel_work_sync(&alloc_work); + cancel_work_sync(&error_wd_work); + cancel_work_sync(&set_clk_work); + vh264mvc_stop(); + frame_width = 0; + frame_height = 0; + vdec_source_changed(VFORMAT_H264MVC, 0, 0, 0); + atomic_set(&vh264mvc_active, 0); + +#ifdef DEBUG_PTS + pr_info + ("pts missed %ld, pts hit %ld, pts_outside %d, ", + pts_missed, pts_hit, pts_outside); + pr_info("duration %d, sync_outside %d\n", + frame_dur, sync_outside); +#endif + +#ifdef DEBUG_SKIP + pr_info("view_total = %ld, dropped %ld\n", view_total, view_dropped); +#endif + vfree(buffer_spec0); + buffer_spec0 = NULL; + kfree(gvs); + gvs = NULL; + + return 0; +} + +/****************************************/ + +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, + } +}; + +static struct codec_profile_t amvdec_hmvc_profile = { + .name = "hmvc", + .profile = "" +}; +static struct codec_profile_t amvdec_hmvc_profile_single; + +static struct mconfig h264mvc_configs[] = { + MC_PU32("stat", &stat), + MC_PU32("dbg_mode", &dbg_mode), + MC_PU32("view_mode", &view_mode), + MC_PU32("dbg_cmd", &dbg_cmd), + MC_PU32("drop_rate", &drop_rate), + MC_PU32("drop_thread_hold", &drop_thread_hold), +}; +static struct mconfig_node h264mvc_node; + +static int __init amvdec_h264mvc_driver_init_module(void) +{ + pr_debug("amvdec_h264mvc module init\n"); + + if (platform_driver_register(&amvdec_h264mvc_driver)) { + pr_err("failed to register amvdec_h264mvc driver\n"); + return -ENODEV; + } + + vcodec_profile_register(&amvdec_hmvc_profile); + amvdec_hmvc_profile_single = amvdec_hmvc_profile; + amvdec_hmvc_profile_single.name = "h264mvc"; + vcodec_profile_register(&amvdec_hmvc_profile_single); + INIT_REG_NODE_CONFIGS("media.decoder", &h264mvc_node, + "h264mvc", h264mvc_configs, CONFIG_FOR_RW); + return 0; +} + +static void __exit amvdec_h264mvc_driver_remove_module(void) +{ + pr_debug("amvdec_h264mvc module remove.\n"); + + platform_driver_unregister(&amvdec_h264mvc_driver); +} + +/****************************************/ + +module_param(stat, uint, 0664); +MODULE_PARM_DESC(stat, "\n amvdec_h264mvc stat\n"); + +module_param(dbg_mode, uint, 0664); +MODULE_PARM_DESC(dbg_mode, "\n amvdec_h264mvc dbg mode\n"); + +module_param(dynamic_buf_num_margin, uint, 0664); +MODULE_PARM_DESC(dynamic_buf_num_margin, "\n amvdec_h264mvc dynamic_buf_num_margin\n"); + +module_param(view_mode, uint, 0664); +MODULE_PARM_DESC(view_mode, "\n amvdec_h264mvc view mode\n"); + +module_param(dbg_cmd, uint, 0664); +MODULE_PARM_DESC(dbg_cmd, "\n amvdec_h264mvc cmd mode\n"); + +module_param(drop_rate, uint, 0664); +MODULE_PARM_DESC(drop_rate, "\n amvdec_h264mvc drop rate\n"); + +module_param(drop_thread_hold, uint, 0664); +MODULE_PARM_DESC(drop_thread_hold, "\n amvdec_h264mvc drop thread hold\n"); +module_init(amvdec_h264mvc_driver_init_module); +module_exit(amvdec_h264mvc_driver_remove_module); + +MODULE_DESCRIPTION("AMLOGIC h264mvc Video Decoder Driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Chen Zhang <chen.zhang@amlogic.com>");
diff --git a/drivers/frame_provider/decoder/h264_multi/Makefile b/drivers/frame_provider/decoder/h264_multi/Makefile new file mode 100644 index 0000000..21dfb6a --- /dev/null +++ b/drivers/frame_provider/decoder/h264_multi/Makefile
@@ -0,0 +1,2 @@ +obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_H264_MULTI) += amvdec_mh264.o +amvdec_mh264-objs += vmh264.o h264_dpb.o
diff --git a/drivers/frame_provider/decoder/h264_multi/h264_dpb.c b/drivers/frame_provider/decoder/h264_multi/h264_dpb.c new file mode 100644 index 0000000..52d9611 --- /dev/null +++ b/drivers/frame_provider/decoder/h264_multi/h264_dpb.c
@@ -0,0 +1,6008 @@ +/* +* 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 "../utils/vdec.h" +#include "../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; + } + 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; + 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->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/h264_multi/h264_dpb.h b/drivers/frame_provider/decoder/h264_multi/h264_dpb.h new file mode 100644 index 0000000..8b3e8bb --- /dev/null +++ b/drivers/frame_provider/decoder/h264_multi/h264_dpb.h
@@ -0,0 +1,1005 @@ +/* +* 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; +}; + +/* #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; + 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/h264_multi/vmh264.c b/drivers/frame_provider/decoder/h264_multi/vmh264.c new file mode 100644 index 0000000..5932c91 --- /dev/null +++ b/drivers/frame_provider/decoder/h264_multi/vmh264.c
@@ -0,0 +1,11272 @@ +/* + * 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 "../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 "../utils/vdec.h" +#include "../utils/amvdec.h" +#include "../h264/vh264.h" +#include "../../../stream_input/amports/streambuf.h" +#include <linux/delay.h> +#include <linux/amlogic/media/codec_mm/configs.h> +#include "../utils/decoder_mmu_box.h" +#include "../utils/decoder_bmmu_box.h" +#include "../utils/firmware.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 + +/* +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" +#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 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 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 +/*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 = 0x7fCfb6; /*0x1f14*/ + + +/* + 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; + +#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; +}; + +#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 + + +/* + *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 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); + +#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 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; + u32 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; + 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; + 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; + +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(struct vdec_s *vdec); +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; + struct vdec_s *vdec = hw_to_vdec(hw); + + 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; + } + 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); + 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 { + 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); + } 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 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->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; + } + + 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; + + /* trigger to parse head data. */ + if (!hw->v4l_params_parsed) + return 1; + + if (dpb->mDPB.used_size >= dpb->mDPB.size - 1) + return 0; + + 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) { + 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; + } + + 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->i_only) + 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; + } + + 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 (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 error_proc_policy %x\n", + __func__, buffer_index, + frame->data_flag & ERROR_FLAG, + frame->poc, hw->data_flag & ERROR_FLAG, + 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 && (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)) + 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 { + vf->pts = frame->pts; + vf->pts_us64 = frame->pts64; + vf->timestamp = frame->timestamp; + 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 + + } + 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; + } + } + + 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->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 + + 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) { + 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); + } + 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) { + if (hw->is_used_v4l) { + expires = jiffies + msecs_to_jiffies(2000); + while (INVALID_IDX == (index = v4l_get_free_buf_idx(vdec))) { + if (time_after(jiffies, expires) || + v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx)) + break; + } + + 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] EOS get free buff fail.\n", ctx->id); + return -1; + } + } + } + + vf->type |= VIDTYPE_V4L_EOS; + vf->timestamp = ULONG_MAX; + 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->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); + } + + 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; + int new_size; + char *new_buf; + 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; + } + } + new_size = AUX_DATA_SIZE(pic) + aux_count + heads_size; + new_buf = krealloc(AUX_DATA_BUF(pic), + new_size, + GFP_KERNEL); + if (new_buf) { + unsigned char valid_tag = 0; + unsigned char *h = + new_buf + + AUX_DATA_SIZE(pic); + unsigned char *p = h + 8; + int len = 0; + int padding_len = 0; + AUX_DATA_BUF(pic) = new_buf; + 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) +{ + 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; +} + +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, + hw->seq_info2); + 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 && !(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 (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_len(&hw->display_q) > VF_POOL_SIZE) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "kfifo len:%d invaild, peek error\n", + kfifo_len(&hw->display_q)); + return NULL; + } + + 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; + } + + 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) + 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->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) +{ + 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]; +#ifndef NV21 + vf->canvas0_config[2] = p_canvas_config[2]; +#endif + vf->canvas1_config[0] = p_canvas_config[0]; + vf->canvas1_config[1] = p_canvas_config[1]; +#ifndef NV21 + vf->canvas1_config[2] = p_canvas_config[2]; +#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) +{ + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + int pic_size = mb_width * mb_height * 384; + int size = 0, size_vui; + int level_idc = p_H264_Dpb->mSPS.level_idc; + + 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 */ + + 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; + + 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; + 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; + 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->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 + ) { + 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; + 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->seq_info2 = seq_info2; + dpb_print(DECODE_ID(hw), 0, + "AV_SCRATCH_1 = %x, AV_SCRATCH_2 %x\r\n", + seq_info2, hw->seq_info); + + 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); + 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); + } + 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 || hw->is_used_v4l) + 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->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 (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 ((error_proc_policy & 0x4) && + (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 ((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)))) { + 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 ((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 ((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 ((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) + && (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 (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; + } + } + 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)); + 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 = + 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 ((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__, + 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 (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 (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 (!(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) && !hw->enable_fence) { + 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 (((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 ((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 ((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 (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) { + /*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 ((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 (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 (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)); + + 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 video_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 (hw->is_used_v4l + && (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->dec_again_cnt = 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 (error_proc_policy & 0x80000000) + hw->send_error_frame_flag = 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 + 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; + +#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); + + 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, + 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_size = active_buffer_spec_num; + + 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->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->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; + } + } + } + + return ret; + +} + +static int check_dirty_data(struct vdec_s *vdec) +{ + struct vdec_h264_hw_s *hw = + (struct vdec_h264_hw_s *)(vdec->private); + u32 wp, rp, level; + + rp = STBUF_READ(&vdec->vbuf, get_rp); + wp = STBUF_READ(&vdec->vbuf, get_wp); + + if (wp > rp) + level = wp - rp; + else + level = wp + vdec->input.size - rp ; + + if (level > (vdec->input.size / 2)) + hw->dec_again_cnt++; + + if (hw->dec_again_cnt > dirty_again_threshold) { + dpb_print(DECODE_ID(hw), 0, "h264 data skipped %x\n", level); + hw->dec_again_cnt = 0; + return 1; + } + return 0; +} + +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)); + 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(); + } 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; */ + hw->dec_again_cnt = 0; + if ((hw->dec_result == DEC_RESULT_TIMEOUT) && + !hw->i_only && (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 (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; + } + + if ((vdec_stream_based(vdec)) && + (error_proc_policy & 0x400000) && + check_dirty_data(vdec)) { + hw->dec_result = DEC_RESULT_DONE; + 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; + 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); + notify_v4l_eos(hw_to_vdec(hw)); + 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; + } + } + + 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 (vdec->slave) + vdec_set_next_sched(vdec, vdec->slave); + else if (vdec->master) + vdec_set_next_sched(vdec, vdec->master); + } else if (vdec->slave || vdec->master) + vdec_set_next_sched(vdec, vdec); +#endif + + if (from == 1) { + /* This is a timeout work */ + if (work_pending(&hw->work)) { + /* + * The vh264_work arrives at the last second, + * give it a chance to handle the scenario. + */ + 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) { + if (hw->mmu_enable == 0) + vdec_core_finish_run(vdec, CORE_MASK_VDEC_1); + else + vdec_core_finish_run(vdec, CORE_MASK_VDEC_1 | CORE_MASK_HEVC); + } 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); + + if (ctx->param_sets_from_ucode && + !hw->v4l_params_parsed) + vdec_v4l_write_frame_sync(ctx); + } + + if (hw->vdec_cb) + hw->vdec_cb(hw_to_vdec(hw), hw->vdec_cb_arg); +} + + +static void vh264_work(struct work_struct *work) +{ + struct vdec_h264_hw_s *hw = container_of(work, + struct vdec_h264_hw_s, work); + struct vdec_s *vdec = hw_to_vdec(hw); + + vh264_work_implement(hw, vdec, 0); +} + + +static void vh264_timeout_work(struct work_struct *work) +{ + struct vdec_h264_hw_s *hw = container_of(work, + struct vdec_h264_hw_s, timeout_work); + struct vdec_s *vdec = hw_to_vdec(hw); + + if (work_pending(&hw->work)) + return; + + hw->timeout_processing = 1; + vh264_work_implement(hw, vdec, 1); +} + +static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) +{ + bool ret = 0; + struct vdec_h264_hw_s *hw = + (struct vdec_h264_hw_s *)vdec->private; + int tvp = vdec_secure(hw_to_vdec(hw)) ? + CODEC_MM_FLAGS_TVP : 0; + + if (hw->timeout_processing && + (work_pending(&hw->work) || work_busy(&hw->work) || + work_pending(&hw->timeout_work) || work_busy(&hw->timeout_work))) { + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_DETAIL, + "h264 work pending, not ready for run.\n"); + return 0; + } + hw->timeout_processing = 0; + if (!hw->first_sc_checked && hw->mmu_enable) { + int size = decoder_mmu_box_sc_check(hw->mmu_box, tvp); + hw->first_sc_checked =1; + dpb_print(DECODE_ID(hw), 0, + "vmh264 cached=%d need_size=%d speed= %d ms\n", + size, (hw->need_cache_size >> PAGE_SHIFT), + (int)(get_jiffies_64() - hw->sc_start_time) * 1000/HZ); + } + + 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) + return 0; + } + +#ifndef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + if (vdec->master) + return 0; +#endif + if (hw->eos) + return 0; + + if (hw->stat & DECODER_FATAL_ERROR_NO_MEM) + return 0; + + if (disp_vframe_valve_level && + kfifo_len(&hw->display_q) >= + disp_vframe_valve_level) { + hw->valve_count--; + if (hw->valve_count <= 0) + hw->valve_count = 2; + else + return 0; + } + if (hw->next_again_flag && + (!vdec_frame_based(vdec))) { + u32 parser_wr_ptr = STBUF_READ(&vdec->vbuf, get_wp); + 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); + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_DETAIL, + "%s buf lelvel:%x\n", __func__, r); + return 0; + } + } + + if (h264_debug_flag & 0x20000000) { + /* pr_info("%s, a\n", __func__); */ + ret = 1; + } else + ret = is_buffer_available(vdec); + +#ifdef CONSTRAIN_MAX_BUF_NUM + 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 + ) + ret = 0; + if (run_ready_display_q_num > 0 && + kfifo_len(&hw->display_q) >= + run_ready_display_q_num) + ret = 0; + /*avoid more buffers consumed when + switching resolution*/ + if (run_ready_max_buf_num == 0xff && + 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) { + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + + if (ctx->param_sets_from_ucode) { + if (hw->v4l_params_parsed) { + 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; + } + } else if (!ctx->v4l_codec_dpb_ready) { + if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < + run_ready_min_buf_num) + ret = 0; + } + } + + 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; + else + return ret ? (CORE_MASK_VDEC_1 | CORE_MASK_HEVC) : 0; + } else + return ret ? (CORE_MASK_VDEC_1 | CORE_MASK_HEVC) : 0; +} + +static unsigned char get_data_check_sum + (struct vdec_h264_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_h264_hw_s *hw = + (struct vdec_h264_hw_s *)vdec->private; + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + int size, ret = -1; + if (!hw->vdec_pg_enable_flag) { + hw->vdec_pg_enable_flag = 1; + amvdec_enable(); + 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) + hevc_reset_core(vdec); + hw->vdec_cb_arg = arg; + hw->vdec_cb = callback; + +#ifdef DETECT_WRONG_MULTI_SLICE + hw->cur_picture_slice_count = 0; +#endif + + if (kfifo_len(&hw->display_q) > VF_POOL_SIZE) { + hw->reset_bufmgr_flag = 1; + dpb_print(DECODE_ID(hw), 0, + "kfifo len:%d invaild, need bufmgr reset\n", + kfifo_len(&hw->display_q)); + } + + if (vdec_stream_based(vdec)) { + hw->pre_parser_wr_ptr = + STBUF_READ(&vdec->vbuf, get_wp); + hw->next_again_flag = 0; + } + + if (hw->reset_bufmgr_flag || + ((error_proc_policy & 0x40) && + p_H264_Dpb->buf_alloc_fail)) { + h264_reset_bufmgr(vdec); + //flag must clear after reset for v4l buf_spec_init use + hw->reset_bufmgr_flag = 0; + } + + if (h264_debug_cmd & 0xf000) { + if (((h264_debug_cmd >> 12) & 0xf) + == (DECODE_ID(hw) + 1)) { + h264_reconfig(hw); + h264_debug_cmd &= (~0xf000); + } + } + /* hw->chunk = vdec_prepare_input(vdec); */ +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + if (vdec->slave || vdec->master) + vdec_set_flag(vdec, VDEC_FLAG_SELF_INPUT_CONTEXT); +#endif + size = vdec_prepare_input(vdec, &hw->chunk); + if ((size < 0) || + (input_frame_based(vdec) && hw->chunk == NULL)) { + input_empty[DECODE_ID(hw)]++; + hw->dec_result = DEC_RESULT_AGAIN; + + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_DETAIL, + "vdec_prepare_input: Insufficient data\n"); + + vdec_schedule_work(&hw->work); + return; + } + input_empty[DECODE_ID(hw)] = 0; + + 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), + READ_VREG(VLD_MEM_VIFIFO_RP), + READ_VREG(VLD_MEM_VIFIFO_WP)); +#endif + + if (input_frame_based(vdec) && !vdec_secure(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 (dpb_is_debug(DECODE_ID(hw), + PRINT_FLAG_VDEC_STATUS) + ) { + dpb_print(DECODE_ID(hw), 0, + "%s: size 0x%x sum 0x%x %02x %02x %02x %02x %02x %02x .. %02x %02x %02x %02x\n", + __func__, 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 (dpb_is_debug(DECODE_ID(hw), + PRINT_FRAMEBASE_DATA) + ) { + int jj; + + for (jj = 0; jj < 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); + } else + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s: %x %x %x %x %x size 0x%x\n", + __func__, + 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); + + start_process_time(hw); + if (vdec->mc_loaded) { + /*firmware have load before, + and not changes to another. + ignore reload. + */ + 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; + amvdec_disable(); + hw->vdec_pg_enable_flag = 0; + dpb_print(DECODE_ID(hw), PRINT_FLAG_ERROR, + "MH264 the %s fw loading failed, err: %x\n", + tee_enabled() ? "TEE" : "local", ret); + hw->dec_result = DEC_RESULT_FORCE_EXIT; + vdec_schedule_work(&hw->work); + return; + } + vdec->mc_type = VFORMAT_H264; + hw->reg_g_status = READ_VREG(AV_SCRATCH_G); + if (hw->mmu_enable) { + ret = amhevc_loadmc_ex(VFORMAT_H264, "mh264_mmu", + hw->fw_mmu->data); + if (ret < 0) { + amvdec_enable_flag = false; + amhevc_disable(); + dpb_print(DECODE_ID(hw), PRINT_FLAG_ERROR, + "MH264_MMU the %s fw loading failed, err: %x\n", + tee_enabled() ? "TEE" : "local", ret); + hw->dec_result = DEC_RESULT_FORCE_EXIT; + vdec_schedule_work(&hw->work); + return; + } + 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; + + decode_size = hw->chunk->size + + (hw->chunk->offset & (VDEC_FIFO_ALIGN - 1)); + WRITE_VREG(H264_DECODE_INFO, (1<<13)); + WRITE_VREG(H264_DECODE_SIZE, decode_size); + WRITE_VREG(VIFF_BIT_CNT, decode_size * 8); + if (vdec->mvfrm) + vdec->mvfrm->frame_size = hw->chunk->size; + } else { + if (size <= 0) + size = 0x7fffffff; /*error happen*/ + WRITE_VREG(H264_DECODE_INFO, (1<<13)); + WRITE_VREG(H264_DECODE_SIZE, size); + WRITE_VREG(VIFF_BIT_CNT, size * 8); + hw->start_bit_cnt = size * 8; + } + config_aux_buf(hw); + config_decode_mode(hw); + vdec_enable_input(vdec); + WRITE_VREG(NAL_SEARCH_CTL, 0); + hw->sei_data_len = 0; + if (enable_itu_t35) + WRITE_VREG(NAL_SEARCH_CTL, READ_VREG(NAL_SEARCH_CTL) | 0x1); + if (!hw->init_flag) { + if (hw->mmu_enable) + WRITE_VREG(NAL_SEARCH_CTL, + READ_VREG(NAL_SEARCH_CTL) | 0x2); + else + WRITE_VREG(NAL_SEARCH_CTL, + READ_VREG(NAL_SEARCH_CTL) & (~0x2)); + } + 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() >= AM_MESON_CPU_MAJOR_ID_G12A) { + + if (hw->mmu_enable) + SET_VREG_MASK(VDEC_ASSIST_MMC_CTRL1, 1 << 3); + else + CLEAR_VREG_MASK(VDEC_ASSIST_MMC_CTRL1, 1 << 3); + } + if (vdec->mvfrm) + vdec->mvfrm->hw_decode_start = local_clock(); + amvdec_start(); + if (hw->mmu_enable /*&& !hw->frame_busy && !hw->frame_done*/) { + WRITE_VREG(HEVC_ASSIST_SCRATCH_0, 0x0); + amhevc_start(); + if (hw->config_bufmgr_done) { + hevc_mcr_sao_global_hw_init(hw, + (hw->mb_width << 4), (hw->mb_height << 4)); + hevc_mcr_config_canv2axitbl(hw, 1); + } + } + + /* if (hw->init_flag) { */ + WRITE_VREG(DPB_STATUS_REG, H264_ACTION_SEARCH_HEAD); + /* } */ + + 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) +{ + int i; + ulong flags; + + if (hw->is_used_v4l) { + spin_lock_irqsave(&hw->bufspec_lock, flags); + for (i = 0; i < BUFSPEC_POOL_SIZE; i++) { + hw->buffer_spec[i].used = -1; + hw->buffer_spec[i].cma_alloc_addr = 0; + hw->buffer_spec[i].buf_adr = 0; + } + spin_unlock_irqrestore(&hw->bufspec_lock, flags); + } + + 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); + } +} + +static void reset(struct vdec_s *vdec) +{ + struct vdec_h264_hw_s *hw = + (struct vdec_h264_hw_s *)vdec->private; + + pr_info("vmh264 reset\n"); + + cancel_work_sync(&hw->work); + cancel_work_sync(&hw->notify_work); + if (hw->stat & STAT_VDEC_RUN) { + amvdec_stop(); + if (hw->mmu_enable) + amhevc_stop(); + hw->stat &= ~STAT_VDEC_RUN; + } + + if (hw->stat & STAT_TIMER_ARM) { + del_timer_sync(&hw->check_timer); + hw->stat &= ~STAT_TIMER_ARM; + } + hw->eos = 0; + hw->decode_pic_count = 0; + + reset_process_time(hw); + h264_reset_bufmgr(vdec); + clear_refer_bufs(hw); + + dpb_print(DECODE_ID(hw), 0, "%s\n", __func__); +} + +static void h264_reconfig(struct vdec_h264_hw_s *hw) +{ + int i; + unsigned long flags; + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + struct vdec_s *vdec = hw_to_vdec(hw); + dpb_print(DECODE_ID(hw), 0, + "%s\n", __func__); + /* after calling flush_dpb() and bufmgr_h264_remove_unused_frame(), + all buffers are in display queue (used == 2), + or free (used == 0) + */ + if (dpb_is_debug(DECODE_ID(hw), + PRINT_FLAG_DUMP_BUFSPEC)) + dump_bufspec(hw, "pre h264_reconfig"); + + flush_dpb(p_H264_Dpb); + bufmgr_h264_remove_unused_frame(p_H264_Dpb, 0); + + if (hw->collocate_cma_alloc_addr) { + decoder_bmmu_box_free_idx( + hw->bmmu_box, + BMMU_REF_IDX); + hw->collocate_cma_alloc_addr = 0; + hw->dpb.colocated_mv_addr_start = 0; + hw->dpb.colocated_mv_addr_end = 0; + } + spin_lock_irqsave(&hw->bufspec_lock, flags); + for (i = 0; i < BUFSPEC_POOL_SIZE; i++) { + if (vdec->parallel_dec == 1) { + vdec->free_canvas_ex(hw->buffer_spec[i].y_canvas_index, vdec->id); + vdec->free_canvas_ex(hw->buffer_spec[i].u_canvas_index, vdec->id); + vdec->free_canvas_ex(hw->buffer_spec[i].v_canvas_index, vdec->id); + hw->buffer_spec[i].y_canvas_index = -1; + hw->buffer_spec[i].u_canvas_index = -1; + hw->buffer_spec[i].v_canvas_index = -1; +#ifdef VDEC_DW + if (IS_VDEC_DW(hw)) { + vdec->free_canvas_ex(hw->buffer_spec[i].vdec_dw_y_canvas_index, vdec->id); + vdec->free_canvas_ex(hw->buffer_spec[i].vdec_dw_u_canvas_index, vdec->id); + vdec->free_canvas_ex(hw->buffer_spec[i].vdec_dw_v_canvas_index, vdec->id); + hw->buffer_spec[i].vdec_dw_y_canvas_index = -1; + hw->buffer_spec[i].vdec_dw_u_canvas_index = -1; + hw->buffer_spec[i].vdec_dw_v_canvas_index = -1; +#endif + } + } + /*make sure buffers not put back to bufmgr when + vf_put is called*/ + if (hw->buffer_spec[i].used == 2) + hw->buffer_spec[i].used = 3; + + /* ready to release "free buffers" + */ + if (hw->buffer_spec[i].used == 0) + 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; + hw->config_bufmgr_done = 0; + + if (hw->is_used_v4l) { + mutex_lock(&vmh264_mutex); + dealloc_buf_specs(hw, 1); + mutex_unlock(&vmh264_mutex); + } + + if (dpb_is_debug(DECODE_ID(hw), + PRINT_FLAG_DUMP_BUFSPEC)) + dump_bufspec(hw, "after h264_reconfig"); +} + +#ifdef ERROR_HANDLE_TEST +static void h264_clear_dpb(struct vdec_h264_hw_s *hw) +{ + int i; + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, + "%s\n", __func__); + remove_dpb_pictures(p_H264_Dpb); + for (i = 0; i < BUFSPEC_POOL_SIZE; i++) { + /*make sure buffers not put back to bufmgr when + vf_put is called*/ + if (hw->buffer_spec[i].used == 2) + hw->buffer_spec[i].used = 5; + } + +} +#endif + +static void h264_reset_bufmgr(struct vdec_s *vdec) +{ + ulong timeout; + struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; +#if 0 + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + int actual_dpb_size, max_reference_size; + int reorder_pic_num; + unsigned int colocated_buf_size; + unsigned int colocated_mv_addr_start; + unsigned int colocated_mv_addr_end; + dpb_print(DECODE_ID(hw), 0, + "%s\n", __func__); + + for (i = 0; i < VF_POOL_SIZE; i++) + hw->vfpool[hw->cur_pool][i].index = -1; /* VF_BUF_NUM; */ + + actual_dpb_size = p_H264_Dpb->mDPB.size; + max_reference_size = p_H264_Dpb->max_reference_size; + reorder_pic_num = p_H264_Dpb->reorder_pic_num; + + colocated_buf_size = p_H264_Dpb->colocated_buf_size; + colocated_mv_addr_start = p_H264_Dpb->colocated_mv_addr_start; + colocated_mv_addr_end = p_H264_Dpb->colocated_mv_addr_end; + + hw->cur_pool++; + if (hw->cur_pool >= VF_POOL_NUM) + hw->cur_pool = 0; + + 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); + } + + for (i = 0; i < BUFSPEC_POOL_SIZE; i++) + hw->buffer_spec[i].used = 0; + + dpb_init_global(&hw->dpb, + DECODE_ID(hw), 0, 0); + p_H264_Dpb->mDPB.size = actual_dpb_size; + p_H264_Dpb->max_reference_size = max_reference_size; + p_H264_Dpb->reorder_pic_num = reorder_pic_num; + + p_H264_Dpb->colocated_buf_size = colocated_buf_size; + p_H264_Dpb->colocated_mv_addr_start = colocated_mv_addr_start; + p_H264_Dpb->colocated_mv_addr_end = colocated_mv_addr_end; + + p_H264_Dpb->fast_output_enable = fast_output_enable; + hw->has_i_frame = 0; +#else + dpb_print(DECODE_ID(hw), 0, + "%s frame count %d to skip %d\n\n", + __func__, hw->decode_pic_count+1, + hw->skip_frame_count); + + flush_dpb(&hw->dpb); + + 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); + + vh264_local_init(hw, true); + /*hw->decode_pic_count = 0; + hw->seq_info2 = 0;*/ + + if (vh264_set_params(hw, + hw->cfg_param1, + hw->cfg_param2, + hw->cfg_param3, + hw->cfg_param4, true) < 0) + hw->stat |= DECODER_FATAL_ERROR_SIZE_OVERFLOW; + else + hw->stat &= (~DECODER_FATAL_ERROR_SIZE_OVERFLOW); + + /*drop 3 frames after reset bufmgr if bit0 is set 1 */ + if (first_i_policy & 0x01) + hw->first_i_policy = (3 << 8) | first_i_policy; + + p_H264_Dpb->first_insert_frame = FirstInsertFrm_RESET; + + if (hw->stat & DECODER_FATAL_ERROR_SIZE_OVERFLOW) + hw->init_flag = 0; + else + hw->init_flag = 1; + + hw->reset_bufmgr_count++; +#endif +} + +int ammvdec_h264_mmu_init(struct vdec_h264_hw_s *hw) +{ + int ret = -1; + int tvp_flag = vdec_secure(hw_to_vdec(hw)) ? + CODEC_MM_FLAGS_TVP : 0; + int buf_size = 64; + + pr_debug("ammvdec_h264_mmu_init tvp = 0x%x mmu_enable %d\n", + tvp_flag, hw->mmu_enable); + hw->need_cache_size = buf_size * SZ_1M; + hw->sc_start_time = get_jiffies_64(); + if (hw->mmu_enable && !hw->mmu_box) { + hw->mmu_box = decoder_mmu_box_alloc_box(DRIVER_NAME, + hw->id, + MMU_MAX_BUFFERS, + hw->need_cache_size, + tvp_flag); + if (!hw->mmu_box) { + pr_err("h264 4k alloc mmu box failed!!\n"); + return -1; + } + ret = 0; + } + if (!hw->bmmu_box) { + hw->bmmu_box = decoder_bmmu_box_alloc_box( + DRIVER_NAME, + hw->id, + BMMU_MAX_BUFFERS, + 4 + PAGE_SHIFT, + CODEC_MM_FLAGS_CMA_CLEAR | + CODEC_MM_FLAGS_FOR_VDECODER | + tvp_flag); + if (hw->bmmu_box) + ret = 0; + } + return ret; +} +int ammvdec_h264_mmu_release(struct vdec_h264_hw_s *hw) +{ + if (hw->mmu_box) { + decoder_mmu_box_free(hw->mmu_box); + hw->mmu_box = NULL; + } + if (hw->bmmu_box) { + decoder_bmmu_box_free(hw->bmmu_box); + hw->bmmu_box = NULL; + } + return 0; +} + +static int ammvdec_h264_probe(struct platform_device *pdev) +{ + struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data; + 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; + } + + hw = (struct vdec_h264_hw_s *)h264_alloc_hw_stru(&pdev->dev, + sizeof(struct vdec_h264_hw_s), GFP_KERNEL); + if (hw == NULL) { + pr_info("\nammvdec_h264 device data allocation failed\n"); + return -ENOMEM; + } + hw->id = pdev->id; + hw->platform_dev = pdev; + + snprintf(hw->trace.vdec_name, sizeof(hw->trace.vdec_name), + "h264-%d", hw->id); + 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; + + platform_set_drvdata(pdev, pdata); + + hw->mmu_enable = 0; + hw->first_head_check_flag = 0; + + if (pdata->sys_info) + hw->vh264_amstream_dec_info = *pdata->sys_info; + + if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5) + force_enable_mmu = 1; + + if (force_enable_mmu && pdata->sys_info && + (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_TXLX) && + (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_GXLX) && + (pdata->sys_info->height * pdata->sys_info->width + > 1920 * 1088)) + hw->mmu_enable = 1; + + if (hw->mmu_enable && + (pdata->frame_base_video_path == FRAME_BASE_PATH_IONVIDEO)) { + hw->mmu_enable = 0; + pr_info("ionvideo needs disable mmu, path= %d \n", + pdata->frame_base_video_path); + } + + if (ammvdec_h264_mmu_init(hw)) { + h264_free_hw_stru(&pdev->dev, (void *)hw); + pr_info("\nammvdec_h264 mmu alloc failed!\n"); + return -ENOMEM; + } + + 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) + hw->double_write_mode = config_val; + else + hw->double_write_mode = double_write_mode; + + if (get_config_int(pdata->config, + "parm_v4l_codec_enable", + &config_val) == 0) + hw->is_used_v4l = config_val; + + if (get_config_int(pdata->config, + "parm_v4l_buffer_margin", + &config_val) == 0) + hw->reorder_dpb_size_margin = config_val; + + if (get_config_int(pdata->config, + "parm_v4l_canvas_mem_mode", + &config_val) == 0) + hw->canvas_mode = config_val; + if (get_config_int(pdata->config, + "parm_v4l_low_latency_mode", + &config_val) == 0) + hw->low_latency_mode = config_val ? 0x8:0; + if (get_config_int(pdata->config, "sidebind_type", + &config_val) == 0) + hw->sidebind_type = config_val; + + if (get_config_int(pdata->config, "sidebind_channel_id", + &config_val) == 0) + hw->sidebind_channel_id = config_val; + + if (get_config_int(pdata->config, + "parm_enable_fence", + &config_val) == 0) + hw->enable_fence = config_val; + + if (get_config_int(pdata->config, + "parm_fence_usage", + &config_val) == 0) + hw->fence_usage = config_val; + + if (get_config_int(pdata->config, + "negative_dv", + &config_val) == 0) { + 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; + + if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5) + hw->double_write_mode = 3; + + if (force_config_fence) { + hw->enable_fence = true; + hw->fence_usage = (force_config_fence >> 4) & 0xf; + if (force_config_fence & 0x2) + hw->enable_fence = false; + dpb_print(DECODE_ID(hw), 0, + "enable fence: %d, fence usage: %d\n", + hw->enable_fence, hw->fence_usage); + } + + if (!hw->is_used_v4l) { + hw->reorder_dpb_size_margin = reorder_dpb_size_margin; + hw->canvas_mode = mem_map_mode; + + if ((h264_debug_flag & IGNORE_PARAM_FROM_CONFIG) == 0) + hw->canvas_mode = pdata->canvas_mode; + } + + if (hw->mmu_enable) { + hw->canvas_mode = CANVAS_BLKMODE_LINEAR; + hw->double_write_mode &= 0xffff; + } + + if (pdata->parallel_dec == 1) { + int i; + for (i = 0; i < BUFSPEC_POOL_SIZE; i++) { + hw->buffer_spec[i].y_canvas_index = -1; + hw->buffer_spec[i].u_canvas_index = -1; + hw->buffer_spec[i].v_canvas_index = -1; +#ifdef VDEC_DW + if (IS_VDEC_DW(hw)) { + hw->buffer_spec[i].vdec_dw_y_canvas_index = -1; + hw->buffer_spec[i].vdec_dw_u_canvas_index = -1; + hw->buffer_spec[i].vdec_dw_v_canvas_index = -1; + } +#endif + } + } + + dpb_print(DECODE_ID(hw), 0, + "%s mmu_enable %d double_write_mode 0x%x\n", + __func__, hw->mmu_enable, hw->double_write_mode); + + pdata->private = hw; + pdata->dec_status = dec_status; + pdata->set_trickmode = vmh264_set_trickmode; + pdata->run_ready = run_ready; + pdata->run = run; + pdata->reset = reset; + pdata->irq_handler = vh264_isr; + pdata->threaded_irq_handler = vh264_isr_thread_fn; + pdata->dump_state = vmh264_dump_state; + +#ifdef MH264_USERDATA_ENABLE + pdata->wakeup_userdata_poll = vmh264_wakeup_userdata_poll; + pdata->user_data_read = vmh264_user_data_read; + pdata->reset_userdata_fifo = vmh264_reset_userdata_fifo; +#else + pdata->wakeup_userdata_poll = NULL; + pdata->user_data_read = NULL; + pdata->reset_userdata_fifo = NULL; +#endif + if (pdata->use_vfm_path) { + snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE, + VFM_DEC_PROVIDER_NAME); + hw->frameinfo_enable = 1; + } +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + else if (vdec_dual(pdata)) { + 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); + + if (!hw->is_used_v4l) + vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name, + &vf_provider_ops, pdata); + + platform_set_drvdata(pdev, pdata); + + buf_spec_init(hw, false); + + hw->platform_dev = pdev; + +#ifdef DUMP_USERDATA_RECORD + vmh264_init_userdata_dump(); + vmh264_reset_user_data_buf(); +#endif + if (decoder_bmmu_box_alloc_buf_phy(hw->bmmu_box, BMMU_DPB_IDX, + V_BUF_ADDR_OFFSET, DRIVER_NAME, &hw->cma_alloc_addr) < 0) { + h264_free_hw_stru(&pdev->dev, (void *)hw); + pdata->dec_status = NULL; + return -ENOMEM; + } + + hw->buf_offset = hw->cma_alloc_addr - DEF_BUF_START_ADDR + + DCAC_READ_MARGIN; + if (hw->mmu_enable) { + u32 extif_size = EXTIF_BUF_SIZE; + 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) { + h264_free_hw_stru(&pdev->dev, (void *)hw); + pdata->dec_status = NULL; + return -ENOMEM; + } + } + if (!vdec_secure(pdata)) { +#if 1 + /*init internal buf*/ + tmpbuf = (char *)codec_mm_phys_to_virt(hw->cma_alloc_addr); + if (tmpbuf) { + memset(tmpbuf, 0, V_BUF_ADDR_OFFSET); + codec_mm_dma_flush(tmpbuf, + V_BUF_ADDR_OFFSET, + DMA_TO_DEVICE); + } else { + tmpbuf = codec_mm_vmap(hw->cma_alloc_addr, + V_BUF_ADDR_OFFSET); + if (tmpbuf) { + memset(tmpbuf, 0, V_BUF_ADDR_OFFSET); + codec_mm_dma_flush(tmpbuf, + V_BUF_ADDR_OFFSET, + DMA_TO_DEVICE); + codec_mm_unmap_phyaddr(tmpbuf); + } + } +#else + /*init sps/pps internal buf 64k*/ + tmpbuf = (char *)codec_mm_phys_to_virt(hw->cma_alloc_addr + + (mem_sps_base - DEF_BUF_START_ADDR)); + memset(tmpbuf, 0, 0x10000); + dma_sync_single_for_device(amports_get_dma_device(), + hw->cma_alloc_addr + + (mem_sps_base - DEF_BUF_START_ADDR), + 0x10000, DMA_TO_DEVICE); +#endif + } + /**/ + +#if 0 + if (NULL == hw->sei_data_buffer) { + hw->sei_data_buffer = + dma_alloc_coherent(amports_get_dma_device(), + USER_DATA_SIZE, + &hw->sei_data_buffer_phys, GFP_KERNEL); + if (!hw->sei_data_buffer) { + pr_info("%s: Can not allocate sei_data_buffer\n", + __func__); + ammvdec_h264_mmu_release(hw); + h264_free_hw_stru(&pdev->dev, (void *)hw); + return -ENOMEM; + } + /* pr_info("buffer 0x%x, phys 0x%x, remap 0x%x\n", + sei_data_buffer, sei_data_buffer_phys, + (u32)sei_data_buffer_remap); */ + } +#endif + 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); + + vdec_source_changed(VFORMAT_H264, 3840, 2160, 60); + + if (hw->mmu_enable) + hevc_source_changed(VFORMAT_HEVC, 3840, 2160, 60); + + if (vh264_init(hw) < 0) { + pr_info("\nammvdec_h264 init failed.\n"); + ammvdec_h264_mmu_release(hw); + h264_free_hw_stru(&pdev->dev, (void *)hw); + pdata->dec_status = NULL; + return -ENODEV; + } +#ifdef MH264_USERDATA_ENABLE + vmh264_crate_userdata_manager(hw, + hw->sei_user_data_buffer, + USER_DATA_SIZE); +#endif + +#ifdef AUX_DATA_CRC + vdec_aux_data_check_init(pdata); +#endif + + vdec_set_prepare_level(pdata, start_decode_buf_level); + if (pdata->parallel_dec == 1) { + if (hw->mmu_enable == 0) + vdec_core_request(pdata, CORE_MASK_VDEC_1); + else { + vdec_core_request(pdata, CORE_MASK_VDEC_1 | CORE_MASK_HEVC + | CORE_MASK_COMBINE); + } + } else + vdec_core_request(pdata, CORE_MASK_VDEC_1 | CORE_MASK_HEVC + | CORE_MASK_COMBINE); + + atomic_set(&hw->vh264_active, 1); + vdec_set_vframe_comm(pdata, DRIVER_NAME); + 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); + } + + return 0; +} + +static void vdec_fence_release(struct vdec_h264_hw_s *hw, + struct vdec_sync *sync) +{ + ulong expires; + + /* clear display pool. */ + clear_refer_bufs(hw); + + /* notify signal to wake up all fences. */ + vdec_timeline_increase(sync, VF_POOL_SIZE); + + expires = jiffies + msecs_to_jiffies(2000); + while (!check_objs_all_signaled(sync)) { + if (time_after(jiffies, expires)) { + pr_err("wait fence signaled timeout.\n"); + break; + } + } + + pr_info("fence start release\n"); + + /* decreases refcnt of timeline. */ + vdec_timeline_put(sync); +} + +static int ammvdec_h264_remove(struct platform_device *pdev) +{ + struct vdec_h264_hw_s *hw = + (struct vdec_h264_hw_s *) + (((struct vdec_s *)(platform_get_drvdata(pdev)))->private); + int i; + + struct vdec_s *vdec = hw_to_vdec(hw); + + if (vdec->next_status == VDEC_STATUS_DISCONNECTED + && (vdec->status == VDEC_STATUS_ACTIVE)) { + dpb_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 */ + } + + for (i = 0; i < BUFSPEC_POOL_SIZE; i++) + release_aux_data(hw, i); + + atomic_set(&hw->vh264_active, 0); + + if (hw->stat & STAT_TIMER_ARM) { + del_timer_sync(&hw->check_timer); + hw->stat &= ~STAT_TIMER_ARM; + } + + vh264_stop(hw); +#ifdef MH264_USERDATA_ENABLE +#ifdef DUMP_USERDATA_RECORD + vmh264_dump_userdata(); +#endif + vmh264_destroy_userdata_manager(hw); +#endif + /* vdec_source_changed(VFORMAT_H264, 0, 0, 0); */ + +#ifdef AUX_DATA_CRC + vdec_aux_data_check_exit(vdec); +#endif + + atomic_set(&hw->vh264_active, 0); + if (vdec->parallel_dec == 1) { + if (hw->mmu_enable == 0) + vdec_core_release(vdec, CORE_MASK_VDEC_1); + else + vdec_core_release(vdec, CORE_MASK_VDEC_1 | CORE_MASK_HEVC | + CORE_MASK_COMBINE); + } 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 < BUFSPEC_POOL_SIZE; i++) { + vdec->free_canvas_ex(hw->buffer_spec[i].y_canvas_index, vdec->id); + vdec->free_canvas_ex(hw->buffer_spec[i].u_canvas_index, vdec->id); + vdec->free_canvas_ex(hw->buffer_spec[i].v_canvas_index, vdec->id); + if (IS_VDEC_DW(hw)) { + vdec->free_canvas_ex(hw->buffer_spec[i].vdec_dw_y_canvas_index, vdec->id); + vdec->free_canvas_ex(hw->buffer_spec[i].vdec_dw_u_canvas_index, vdec->id); + vdec->free_canvas_ex(hw->buffer_spec[i].vdec_dw_v_canvas_index, vdec->id); + } + } + } + + if (hw->enable_fence) + vdec_fence_release(hw, vdec->sync); + + ammvdec_h264_mmu_release(hw); + h264_free_hw_stru(&pdev->dev, (void *)hw); + clk_adj_frame_count = 0; + + return 0; +} + +/****************************************/ + +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, + } +}; + +static struct codec_profile_t ammvdec_h264_profile = { + .name = "mh264", + .profile = "" +}; + +static struct mconfig hm264_configs[] = { + MC_PU32("h264_debug_flag", &h264_debug_flag), + MC_PI32("start_decode_buf_level", &start_decode_buf_level), + MC_PU32("fixed_frame_rate_mode", &fixed_frame_rate_mode), + MC_PU32("decode_timeout_val", &decode_timeout_val), + MC_PU32("reorder_dpb_size_margin", &reorder_dpb_size_margin), + MC_PU32("reference_buf_margin", &reference_buf_margin), + MC_PU32("radr", &radr), + MC_PU32("rval", &rval), + MC_PU32("h264_debug_mask", &h264_debug_mask), + MC_PU32("h264_debug_cmd", &h264_debug_cmd), + MC_PI32("force_rate_streambase", &force_rate_streambase), + MC_PI32("dec_control", &dec_control), + MC_PI32("force_rate_framebase", &force_rate_framebase), + MC_PI32("force_disp_bufspec_num", &force_disp_bufspec_num), + MC_PU32("prefix_aux_buf_size", &prefix_aux_buf_size), + MC_PU32("suffix_aux_buf_size", &suffix_aux_buf_size), +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + MC_PU32("reorder_dpb_size_margin_dv", &reorder_dpb_size_margin_dv), + MC_PU32("dv_toggle_prov_name", &dv_toggle_prov_name), + MC_PU32("dolby_meta_with_el", &dolby_meta_with_el), +#endif + MC_PU32("i_only_flag", &i_only_flag), + MC_PU32("force_rate_streambase", &force_rate_streambase), +}; +static struct mconfig_node hm264_node; + + +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"); + return -ENODEV; + } + + 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, v4l"; + } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXTVBB) { + 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; +} + +static void __exit ammvdec_h264_driver_remove_module(void) +{ + pr_info("ammvdec_h264 module remove.\n"); + + platform_driver_unregister(&ammvdec_h264_driver); +} + +/****************************************/ +module_param(h264_debug_flag, uint, 0664); +MODULE_PARM_DESC(h264_debug_flag, "\n ammvdec_h264 h264_debug_flag\n"); + +module_param(start_decode_buf_level, int, 0664); +MODULE_PARM_DESC(start_decode_buf_level, + "\n ammvdec_h264 start_decode_buf_level\n"); + +module_param(pre_decode_buf_level, int, 0664); +MODULE_PARM_DESC(pre_decode_buf_level, "\n ammvdec_h264 pre_decode_buf_level\n"); + +module_param(fixed_frame_rate_mode, uint, 0664); +MODULE_PARM_DESC(fixed_frame_rate_mode, "\namvdec_h264 fixed_frame_rate_mode\n"); + +module_param(decode_timeout_val, uint, 0664); +MODULE_PARM_DESC(decode_timeout_val, "\n amvdec_h264 decode_timeout_val\n"); + +module_param(errordata_timeout_val, uint, 0664); +MODULE_PARM_DESC(errordata_timeout_val, "\n amvdec_h264 errordata_timeout_val\n"); + +module_param(get_data_timeout_val, uint, 0664); +MODULE_PARM_DESC(get_data_timeout_val, "\n amvdec_h264 get_data_timeout_val\n"); + +module_param(frame_max_data_packet, uint, 0664); +MODULE_PARM_DESC(frame_max_data_packet, "\n amvdec_h264 frame_max_data_packet\n"); + +module_param(reorder_dpb_size_margin, uint, 0664); +MODULE_PARM_DESC(reorder_dpb_size_margin, "\n ammvdec_h264 reorder_dpb_size_margin\n"); + +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION +module_param(reorder_dpb_size_margin_dv, uint, 0664); +MODULE_PARM_DESC(reorder_dpb_size_margin_dv, + "\n ammvdec_h264 reorder_dpb_size_margin_dv\n"); +#endif + +module_param(reference_buf_margin, uint, 0664); +MODULE_PARM_DESC(reference_buf_margin, "\n ammvdec_h264 reference_buf_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(radr, uint, 0664); +MODULE_PARM_DESC(radr, "\nradr\n"); + +module_param(rval, uint, 0664); +MODULE_PARM_DESC(rval, "\nrval\n"); + +module_param(h264_debug_mask, uint, 0664); +MODULE_PARM_DESC(h264_debug_mask, "\n amvdec_h264 h264_debug_mask\n"); + +module_param(h264_debug_cmd, uint, 0664); +MODULE_PARM_DESC(h264_debug_cmd, "\n amvdec_h264 h264_debug_cmd\n"); + +module_param(force_rate_streambase, int, 0664); +MODULE_PARM_DESC(force_rate_streambase, "\n amvdec_h264 force_rate_streambase\n"); + +module_param(dec_control, int, 0664); +MODULE_PARM_DESC(dec_control, "\n amvdec_h264 dec_control\n"); + +module_param(force_rate_framebase, int, 0664); +MODULE_PARM_DESC(force_rate_framebase, "\n amvdec_h264 force_rate_framebase\n"); + +module_param(force_disp_bufspec_num, int, 0664); +MODULE_PARM_DESC(force_disp_bufspec_num, "\n amvdec_h264 force_disp_bufspec_num\n"); + +module_param(V_BUF_ADDR_OFFSET, int, 0664); +MODULE_PARM_DESC(V_BUF_ADDR_OFFSET, "\n amvdec_h264 V_BUF_ADDR_OFFSET\n"); + +module_param(prefix_aux_buf_size, uint, 0664); +MODULE_PARM_DESC(prefix_aux_buf_size, "\n prefix_aux_buf_size\n"); + +module_param(suffix_aux_buf_size, uint, 0664); +MODULE_PARM_DESC(suffix_aux_buf_size, "\n suffix_aux_buf_size\n"); + +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION +module_param(dv_toggle_prov_name, uint, 0664); +MODULE_PARM_DESC(dv_toggle_prov_name, "\n dv_toggle_prov_name\n"); + +module_param(dolby_meta_with_el, uint, 0664); +MODULE_PARM_DESC(dolby_meta_with_el, "\n dolby_meta_with_el\n"); + +#endif + +module_param(fast_output_enable, uint, 0664); +MODULE_PARM_DESC(fast_output_enable, "\n amvdec_h264 fast_output_enable\n"); + +module_param(error_proc_policy, uint, 0664); +MODULE_PARM_DESC(error_proc_policy, "\n amvdec_h264 error_proc_policy\n"); + +module_param(error_skip_count, uint, 0664); +MODULE_PARM_DESC(error_skip_count, "\n amvdec_h264 error_skip_count\n"); + +module_param(force_sliding_margin, uint, 0664); +MODULE_PARM_DESC(force_sliding_margin, "\n amvdec_h264 force_sliding_margin\n"); + +module_param(i_only_flag, uint, 0664); +MODULE_PARM_DESC(i_only_flag, "\n amvdec_h264 i_only_flag\n"); + +module_param(first_i_policy, uint, 0664); +MODULE_PARM_DESC(first_i_policy, "\n amvdec_h264 first_i_policy\n"); + +module_param(frmbase_cont_bitlevel, uint, 0664); +MODULE_PARM_DESC(frmbase_cont_bitlevel, + "\n amvdec_h264 frmbase_cont_bitlevel\n"); + +module_param(frmbase_cont_bitlevel2, uint, 0664); +MODULE_PARM_DESC(frmbase_cont_bitlevel2, + "\n amvdec_h264 frmbase_cont_bitlevel\n"); + +module_param(udebug_flag, uint, 0664); +MODULE_PARM_DESC(udebug_flag, "\n amvdec_mh264 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(max_alloc_buf_count, uint, 0664); +MODULE_PARM_DESC(max_alloc_buf_count, "\n amvdec_h264 max_alloc_buf_count\n"); + +module_param(enable_itu_t35, uint, 0664); +MODULE_PARM_DESC(enable_itu_t35, "\n amvdec_h264 enable_itu_t35\n"); + +module_param(endian, uint, 0664); +MODULE_PARM_DESC(endian, "\nrval\n"); + +module_param(mmu_enable, uint, 0664); +MODULE_PARM_DESC(mmu_enable, "\n mmu_enable\n"); + +module_param(force_enable_mmu, uint, 0664); +MODULE_PARM_DESC(force_enable_mmu, "\n force_enable_mmu\n"); + +module_param(again_threshold, uint, 0664); +MODULE_PARM_DESC(again_threshold, "\n again_threshold\n"); + +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"); +*/ +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(not_run_ready, uint, + &max_decode_instance_num, 0664); + +module_param_array(input_empty, uint, + &max_decode_instance_num, 0664); + +module_param_array(max_get_frame_interval, uint, + &max_decode_instance_num, 0664); + +module_param_array(step, uint, &max_decode_instance_num, 0664); + +module_param_array(ref_frame_mark_flag, uint, &max_decode_instance_num, 0664); + +module_param(disp_vframe_valve_level, uint, 0664); +MODULE_PARM_DESC(disp_vframe_valve_level, "\n disp_vframe_valve_level\n"); + +module_param(double_write_mode, uint, 0664); +MODULE_PARM_DESC(double_write_mode, "\n double_write_mode\n"); + +module_param(mem_map_mode, uint, 0664); +MODULE_PARM_DESC(mem_map_mode, "\n mem_map_mode\n"); + +module_param(without_display_mode, uint, 0664); +MODULE_PARM_DESC(without_display_mode, "\n without_display_mode\n"); + +module_param(check_slice_num, uint, 0664); +MODULE_PARM_DESC(check_slice_num, "\n check_slice_num\n"); + +module_param(mb_count_threshold, uint, 0664); +MODULE_PARM_DESC(mb_count_threshold, "\n mb_count_threshold\n"); + +module_param(loop_playback_poc_threshold, int, 0664); +MODULE_PARM_DESC(loop_playback_poc_threshold, "\n loop_playback_poc_threshold\n"); + +module_param(poc_threshold, int, 0664); +MODULE_PARM_DESC(poc_threshold, "\n poc_threshold\n"); + +module_param(force_config_fence, uint, 0664); +MODULE_PARM_DESC(force_config_fence, "\n force enable fence\n"); + +module_param(dirty_again_threshold, uint, 0664); +MODULE_PARM_DESC(dirty_again_threshold, "\n amvdec_h264 dirty_again_threshold\n"); + +module_init(ammvdec_h264_driver_init_module); +module_exit(ammvdec_h264_driver_remove_module); + +MODULE_DESCRIPTION("AMLOGIC H264 Video Decoder Driver"); +MODULE_LICENSE("GPL");
diff --git a/drivers/frame_provider/decoder/h265/Makefile b/drivers/frame_provider/decoder/h265/Makefile new file mode 100644 index 0000000..86b8b88 --- /dev/null +++ b/drivers/frame_provider/decoder/h265/Makefile
@@ -0,0 +1,2 @@ +obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_H265) += amvdec_h265.o +amvdec_h265-objs += vh265.o
diff --git a/drivers/frame_provider/decoder/h265/vh265.c b/drivers/frame_provider/decoder/h265/vh265.c new file mode 100644 index 0000000..d5945ce --- /dev/null +++ b/drivers/frame_provider/decoder/h265/vh265.c
@@ -0,0 +1,16227 @@ +/* + * drivers/amlogic/amports/vh265.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/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/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.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/mm.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" +#include "../utils/decoder_bmmu_box.h" +#include "../utils/config_parser.h" +#include "../utils/firmware.h" +#include "../../../common/chips/decoder_cpu_ver_info.h" +#include "../utils/vdec_v4l2_buffer_ops.h" +#include <media/v4l2-mem2mem.h> + +/* +to enable DV of frame mode +#define DOLBY_META_SUPPORT in ucode +*/ + +#define HEVC_8K_LFTOFFSET_FIX +#define SUPPORT_LONG_TERM_RPS + +//#define CO_MV_COMPRESS + +#define CONSTRAIN_MAX_BUF_NUM + +#define SWAP_HEVC_UCODE +#define DETREFILL_ENABLE + +#define AGAIN_HAS_THRESHOLD +/*#define TEST_NO_BUF*/ +#define HEVC_PIC_STRUCT_SUPPORT +#define MULTI_INSTANCE_SUPPORT +#define USE_UNINIT_SEMA + + /* .buf_size = 0x100000*16, + //4k2k , 0x100000 per buffer */ + /* 4096x2304 , 0x120000 per buffer */ +#define MPRED_8K_MV_BUF_SIZE (0x120000*4) +#define MPRED_4K_MV_BUF_SIZE (0x120000) +#define MPRED_MV_BUF_SIZE (0x3fc00) + +#define MMU_COMPRESS_HEADER_SIZE_1080P 0x10000 +#define MMU_COMPRESS_HEADER_SIZE_4K 0x48000 +#define MMU_COMPRESS_HEADER_SIZE_8K 0x120000 +#define DB_NUM 20 + +#define MAX_FRAME_4K_NUM 0x1200 +#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 + +#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 +#define SWAP_HEVC_OFFSET (3 * 0x1000) + +#define MEM_NAME "codec_265" +/* #include <mach/am_regs.h> */ +#include <linux/amlogic/media/utils/vdec_reg.h> + +#include "../utils/vdec.h" +#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 +#define STAT_KTHREAD 0x40 +#endif + +#ifdef MULTI_INSTANCE_SUPPORT +#define MAX_DECODE_INSTANCE_NUM 9 +#define MULTI_DRIVER_NAME "ammvdec_h265" +#endif +#define DRIVER_NAME "amvdec_h265" +#define DRIVER_HEADER_NAME "amvdec_h265_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) + +#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)) + +#define SEI_UserDataITU_T_T35 4 +#define INVALID_IDX -1 /* Invalid buffer index.*/ + +static struct semaphore h265_sema; + +struct hevc_state_s; +static int hevc_print(struct hevc_state_s *hevc, + int debug_flag, const char *fmt, ...); +static int hevc_print_cont(struct hevc_state_s *hevc, + int debug_flag, const char *fmt, ...); +static int vh265_vf_states(struct vframe_states *states, void *); +static struct vframe_s *vh265_vf_peek(void *); +static struct vframe_s *vh265_vf_get(void *); +static void vh265_vf_put(struct vframe_s *, void *); +static int vh265_event_cb(int type, void *data, void *private_data); + +static int vh265_stop(struct hevc_state_s *hevc); +#ifdef MULTI_INSTANCE_SUPPORT +static int vmh265_stop(struct hevc_state_s *hevc); +static s32 vh265_init(struct vdec_s *vdec); +static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask); +static void reset_process_time(struct hevc_state_s *hevc); +static void start_process_time(struct hevc_state_s *hevc); +static void restart_process_time(struct hevc_state_s *hevc); +static void timeout_process(struct hevc_state_s *hevc); +#else +static s32 vh265_init(struct hevc_state_s *hevc); +#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(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" +#define MULTI_INSTANCE_PROVIDER_NAME "vdec.h265" + +static const struct vframe_operations_s vh265_vf_provider = { + .peek = vh265_vf_peek, + .get = vh265_vf_get, + .put = vh265_vf_put, + .event_cb = vh265_event_cb, + .vf_states = vh265_vf_states, +}; + +static struct vframe_provider_s vh265_vf_prov; + +static u32 bit_depth_luma; +static u32 bit_depth_chroma; +static u32 video_signal_type; +static int start_decode_buf_level = 0x8000; +static unsigned int decode_timeout_val = 200; + +static u32 run_ready_min_buf_num = 2; +static u32 disable_ip_mode; +static u32 print_lcu_error = 1; +/*data_resend_policy: + bit 0, stream base resend data when decoding buf empty +*/ +static u32 data_resend_policy = 1; +static int poc_num_margin = 1000; +static int poc_error_limit = 30; + +static u32 dirty_again_threshold = 100; +static u32 dirty_buffersize_threshold = 0x800000; + + +#define VIDEO_SIGNAL_TYPE_AVAILABLE_MASK 0x20000000 +/* +static const char * const video_format_names[] = { + "component", "PAL", "NTSC", "SECAM", + "MAC", "unspecified", "unspecified", "unspecified" +}; + +static const char * const color_primaries_names[] = { + "unknown", "bt709", "undef", "unknown", + "bt470m", "bt470bg", "smpte170m", "smpte240m", + "film", "bt2020" +}; + +static const char * const transfer_characteristics_names[] = { + "unknown", "bt709", "undef", "unknown", + "bt470m", "bt470bg", "smpte170m", "smpte240m", + "linear", "log100", "log316", "iec61966-2-4", + "bt1361e", "iec61966-2-1", "bt2020-10", "bt2020-12", + "smpte-st-2084", "smpte-st-428" +}; + +static const char * const matrix_coeffs_names[] = { + "GBR", "bt709", "undef", "unknown", + "fcc", "bt470bg", "smpte170m", "smpte240m", + "YCgCo", "bt2020nc", "bt2020c" +}; +*/ +#ifdef SUPPORT_10BIT +#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 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: + * 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; + * 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; + * 0x300, if > 720p, use mode 4, else use mode 1; + * 0x1000,if > 1080p,use mode 3, else if > 960*540, use mode 4, else use mode 1; + */ +static u32 double_write_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 workaround_enable; +static u32 force_w_h; +#endif +static u32 force_fps; +static u32 pts_unstable; +#define H265_DEBUG_BUFMGR 0x01 +#define H265_DEBUG_BUFMGR_MORE 0x02 +#define H265_DEBUG_DETAIL 0x04 +#define H265_DEBUG_REG 0x08 +#define H265_DEBUG_MAN_SEARCH_NAL 0x10 +#define H265_DEBUG_MAN_SKIP_NAL 0x20 +#define H265_DEBUG_DISPLAY_CUR_FRAME 0x40 +#define H265_DEBUG_FORCE_CLK 0x80 +#define H265_DEBUG_SEND_PARAM_WITH_REG 0x100 +#define H265_DEBUG_NO_DISPLAY 0x200 +#define H265_DEBUG_DISCARD_NAL 0x400 +#define H265_DEBUG_OUT_PTS 0x800 +#define H265_DEBUG_DUMP_PIC_LIST 0x1000 +#define H265_DEBUG_PRINT_SEI 0x2000 +#define H265_DEBUG_PIC_STRUCT 0x4000 +#define H265_DEBUG_HAS_AUX_IN_SLICE 0x8000 +#define H265_DEBUG_DIS_LOC_ERROR_PROC 0x10000 +#define H265_DEBUG_DIS_SYS_ERROR_PROC 0x20000 +#define H265_NO_CHANG_DEBUG_FLAG_IN_CODE 0x40000 +#define H265_DEBUG_TRIG_SLICE_SEGMENT_PROC 0x80000 +#define H265_DEBUG_HW_RESET 0x100000 +#define H265_CFG_CANVAS_IN_DECODE 0x200000 +#define H265_DEBUG_DV 0x400000 +#define H265_DEBUG_NO_EOS_SEARCH_DONE 0x800000 +#define H265_DEBUG_NOT_USE_LAST_DISPBUF 0x1000000 +#define H265_DEBUG_IGNORE_CONFORMANCE_WINDOW 0x2000000 +#define H265_DEBUG_WAIT_DECODE_DONE_WHEN_STOP 0x4000000 +#ifdef MULTI_INSTANCE_SUPPORT +#define PRINT_FLAG_ERROR 0x0 +#define IGNORE_PARAM_FROM_CONFIG 0x08000000 +#define PRINT_FRAMEBASE_DATA 0x10000000 +#define PRINT_FLAG_VDEC_STATUS 0x20000000 +#define PRINT_FLAG_VDEC_DETAIL 0x40000000 +#define PRINT_FLAG_V4L_DETAIL 0x80000000 +#endif + +#define BUF_POOL_SIZE 32 +#define MAX_BUF_NUM 24 +#define MAX_REF_PIC_NUM 24 +#define MAX_REF_ACTIVE 16 + +#ifdef MV_USE_FIXED_BUF +#define BMMU_MAX_BUFFERS (BUF_POOL_SIZE + 1) +#define VF_BUFFER_IDX(n) (n) +#define BMMU_WORKSPACE_ID (BUF_POOL_SIZE) +#else +#define BMMU_MAX_BUFFERS (BUF_POOL_SIZE + 1 + MAX_REF_PIC_NUM) +#define VF_BUFFER_IDX(n) (n) +#define BMMU_WORKSPACE_ID (BUF_POOL_SIZE) +#define MV_BUFFER_IDX(n) (BUF_POOL_SIZE + 1 + n) +#endif + +#define HEVC_MV_INFO 0x310d +#define HEVC_QP_INFO 0x3137 +#define HEVC_SKIP_INFO 0x3136 + +const u32 h265_version = 201602101; +static u32 debug_mask = 0xffffffff; +static u32 log_mask; +static u32 debug; +static u32 radr; +static u32 rval; +static u32 dbg_cmd; +static u32 dump_nal; +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 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 decode_pic_begin; +static uint slice_parse_begin; +static u32 step; +static bool is_reset; + +#ifdef CONSTRAIN_MAX_BUF_NUM +static u32 run_ready_max_vf_only_num; +static u32 run_ready_display_q_num; + /*0: not check + 0xff: work_pic_num + */ +static u32 run_ready_max_buf_num = 0xff; +#endif + +static u32 dynamic_buf_num_margin = 7; +static u32 buf_alloc_width; +static u32 buf_alloc_height; + +static u32 max_buf_num = 16; +static u32 buf_alloc_size; +/*static u32 re_config_pic_flag;*/ +/* + *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 h265) 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[1:0]PB_skip_mode: 0, start decoding at begin; + *1, start decoding after first I; + *2, only decode and display none error picture; + *3, start decoding and display after IDR,etc + *bit[31:16] PB_skip_count_after_decoding (decoding but not display), + *only for mode 0 and 1. + */ +static u32 nal_skip_policy = 2; + +/* + *bit 0, 1: only display I picture; + *bit 1, 1: only decode I picture; + */ +static u32 i_only_flag; +static u32 skip_nal_count = 500; +/* +bit 0, fast output first I picture +*/ +static u32 fast_output_enable = 1; + +static u32 frmbase_cont_bitlevel = 0x60; + +/* +use_cma: 1, use both reserver memory and cma for buffers +2, only use cma for buffers +*/ +static u32 use_cma = 2; + +#define AUX_BUF_ALIGN(adr) ((adr + 0xf) & (~0xf)) +/* +static u32 prefix_aux_buf_size = (16 * 1024); +static u32 suffix_aux_buf_size; +*/ +static u32 prefix_aux_buf_size = (12 * 1024); +static u32 suffix_aux_buf_size = (12 * 1024); + +static u32 max_decoding_time; +/* + *error handling + */ +/*error_handle_policy: + *bit 0: 0, auto skip error_skip_nal_count nals before error recovery; + *1, skip error_skip_nal_count nals before error recovery; + *bit 1 (valid only when bit0 == 1): + *1, wait vps/sps/pps after error recovery; + *bit 2 (valid only when bit0 == 0): + *0, auto search after error recovery (hevc_recover() called); + *1, manual search after error recovery + *(change to auto search after get IDR: WRITE_VREG(NAL_SEARCH_CTL, 0x2)) + * + *bit 4: 0, set error_mark after reset/recover + * 1, do not set error_mark after reset/recover + * + *bit 5: 0, check total lcu for every picture + * 1, do not check total lcu + * + *bit 6: 0, do not check head error + * 1, check head error + * + *bit 7: 0, allow to print over decode + * 1, NOT allow to print over decode + * + *bit 8: 0, use interlace policy + * 1, NOT use interlace policy + *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 + */ + +static u32 error_handle_policy; +static u32 error_skip_nal_count = 6; +static u32 error_handle_threshold = 30; +static u32 error_handle_nal_skip_threshold = 10; +static u32 error_handle_system_threshold = 30; +static u32 interlace_enable = 1; +static u32 fr_hint_status; + + /* + *parser_sei_enable: + * bit 0, sei; + * bit 1, sei_suffix (fill aux buf) + * bit 2, fill sei to aux buf (when bit 0 is 1) + * bit 8, debug flag + */ +static u32 parser_sei_enable; +static u32 parser_dolby_vision_enable = 1; +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION +static u32 dolby_meta_with_el; +static u32 dolby_el_flush_th = 2; +#endif +/* this is only for h265 mmu enable */ + +static u32 mmu_enable = 1; +static u32 mmu_enable_force; +static u32 work_buf_size; +static unsigned int force_disp_pic_index; +static unsigned int disp_vframe_valve_level; +static int pre_decode_buf_level = 0x1000; +static unsigned int pic_list_debug; +#ifdef HEVC_8K_LFTOFFSET_FIX + /* performance_profile: bit 0, multi slice in ucode + */ +static unsigned int performance_profile = 1; +#endif +#ifdef MULTI_INSTANCE_SUPPORT +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 max_get_frame_interval[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]; +static unsigned int ref_frame_mark_flag[MAX_DECODE_INSTANCE_NUM] = +{1, 1, 1, 1, 1, 1, 1, 1, 1}; + +#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC +static unsigned char get_idx(struct hevc_state_s *hevc); +#endif + +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION +static u32 dv_toggle_prov_name; + +static u32 dv_debug; + +static u32 force_bypass_dvenl; +#endif +#endif + +/* + *[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; + +/* + *The parameter sps_max_dec_pic_buffering_minus1_0+1 + *in SPS is the minimum DPB size required for stream + *(note: this parameter does not include the frame + *currently being decoded) +1 (decoding the current + *frame) +1 (decoding the current frame will only + *update refrence frame information, such as reference + *relation, when the next frame is decoded) + */ +static u32 detect_stuck_buffer_margin = 3; + + +#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC +#define get_dbg_flag(hevc) ((debug_mask & (1 << hevc->index)) ? debug : 0) +#define get_dbg_flag2(hevc) ((debug_mask & (1 << get_idx(hevc))) ? debug : 0) +#define is_log_enable(hevc) ((log_mask & (1 << hevc->index)) ? 1 : 0) +#else +#define get_dbg_flag(hevc) debug +#define get_dbg_flag2(hevc) debug +#define is_log_enable(hevc) (log_mask ? 1 : 0) +#define get_valid_double_write_mode(hevc) double_write_mode +#define get_buf_alloc_width(hevc) buf_alloc_width +#define get_buf_alloc_height(hevc) buf_alloc_height +#define get_dynamic_buf_num_margin(hevc) dynamic_buf_num_margin +#endif +#define get_buffer_mode(hevc) buffer_mode + + +static DEFINE_SPINLOCK(lock); +struct task_struct *h265_task = NULL; +#undef DEBUG_REG +#ifdef DEBUG_REG +void WRITE_VREG_DBG(unsigned adr, unsigned val) +{ + if (debug & H265_DEBUG_REG) + pr_info("%s(%x, %x)\n", __func__, adr, val); + WRITE_VREG(adr, val); +} + +#undef WRITE_VREG +#define WRITE_VREG WRITE_VREG_DBG +#endif +extern u32 trickmode_i; + +static DEFINE_MUTEX(vh265_mutex); + +static DEFINE_MUTEX(vh265_log_mutex); + +//static struct vdec_info *gvs; + +static u32 without_display_mode; + +static u32 mv_buf_dynamic_alloc; + +/************************************************** + * + *h265 buffer management include + * + *************************************************** + */ +enum NalUnitType { + NAL_UNIT_CODED_SLICE_TRAIL_N = 0, /* 0 */ + NAL_UNIT_CODED_SLICE_TRAIL_R, /* 1 */ + + NAL_UNIT_CODED_SLICE_TSA_N, /* 2 */ + /* Current name in the spec: TSA_R */ + NAL_UNIT_CODED_SLICE_TLA, /* 3 */ + + NAL_UNIT_CODED_SLICE_STSA_N, /* 4 */ + NAL_UNIT_CODED_SLICE_STSA_R, /* 5 */ + + NAL_UNIT_CODED_SLICE_RADL_N, /* 6 */ + /* Current name in the spec: RADL_R */ + NAL_UNIT_CODED_SLICE_DLP, /* 7 */ + + NAL_UNIT_CODED_SLICE_RASL_N, /* 8 */ + /* Current name in the spec: RASL_R */ + NAL_UNIT_CODED_SLICE_TFD, /* 9 */ + + NAL_UNIT_RESERVED_10, + NAL_UNIT_RESERVED_11, + NAL_UNIT_RESERVED_12, + NAL_UNIT_RESERVED_13, + NAL_UNIT_RESERVED_14, + NAL_UNIT_RESERVED_15, + + /* Current name in the spec: BLA_W_LP */ + NAL_UNIT_CODED_SLICE_BLA, /* 16 */ + /* Current name in the spec: BLA_W_DLP */ + NAL_UNIT_CODED_SLICE_BLANT, /* 17 */ + NAL_UNIT_CODED_SLICE_BLA_N_LP, /* 18 */ + /* Current name in the spec: IDR_W_DLP */ + NAL_UNIT_CODED_SLICE_IDR, /* 19 */ + NAL_UNIT_CODED_SLICE_IDR_N_LP, /* 20 */ + NAL_UNIT_CODED_SLICE_CRA, /* 21 */ + NAL_UNIT_RESERVED_22, + NAL_UNIT_RESERVED_23, + + NAL_UNIT_RESERVED_24, + NAL_UNIT_RESERVED_25, + NAL_UNIT_RESERVED_26, + NAL_UNIT_RESERVED_27, + NAL_UNIT_RESERVED_28, + NAL_UNIT_RESERVED_29, + NAL_UNIT_RESERVED_30, + NAL_UNIT_RESERVED_31, + + NAL_UNIT_VPS, /* 32 */ + NAL_UNIT_SPS, /* 33 */ + NAL_UNIT_PPS, /* 34 */ + NAL_UNIT_ACCESS_UNIT_DELIMITER, /* 35 */ + NAL_UNIT_EOS, /* 36 */ + NAL_UNIT_EOB, /* 37 */ + NAL_UNIT_FILLER_DATA, /* 38 */ + NAL_UNIT_SEI, /* 39 Prefix SEI */ + NAL_UNIT_SEI_SUFFIX, /* 40 Suffix SEI */ + NAL_UNIT_RESERVED_41, + NAL_UNIT_RESERVED_42, + NAL_UNIT_RESERVED_43, + NAL_UNIT_RESERVED_44, + NAL_UNIT_RESERVED_45, + NAL_UNIT_RESERVED_46, + NAL_UNIT_RESERVED_47, + NAL_UNIT_UNSPECIFIED_48, + NAL_UNIT_UNSPECIFIED_49, + NAL_UNIT_UNSPECIFIED_50, + NAL_UNIT_UNSPECIFIED_51, + NAL_UNIT_UNSPECIFIED_52, + NAL_UNIT_UNSPECIFIED_53, + NAL_UNIT_UNSPECIFIED_54, + NAL_UNIT_UNSPECIFIED_55, + NAL_UNIT_UNSPECIFIED_56, + NAL_UNIT_UNSPECIFIED_57, + NAL_UNIT_UNSPECIFIED_58, + NAL_UNIT_UNSPECIFIED_59, + NAL_UNIT_UNSPECIFIED_60, + NAL_UNIT_UNSPECIFIED_61, + NAL_UNIT_UNSPECIFIED_62, + NAL_UNIT_UNSPECIFIED_63, + NAL_UNIT_INVALID, +}; + +/* --------------------------------------------------- */ +/* Amrisc Software Interrupt */ +/* --------------------------------------------------- */ +#define AMRISC_STREAM_EMPTY_REQ 0x01 +#define AMRISC_PARSER_REQ 0x02 +#define AMRISC_MAIN_REQ 0x04 + +/* --------------------------------------------------- */ +/* HEVC_DEC_STATUS define */ +/* --------------------------------------------------- */ +#define HEVC_DEC_IDLE 0x0 +#define HEVC_NAL_UNIT_VPS 0x1 +#define HEVC_NAL_UNIT_SPS 0x2 +#define HEVC_NAL_UNIT_PPS 0x3 +#define HEVC_NAL_UNIT_CODED_SLICE_SEGMENT 0x4 +#define HEVC_CODED_SLICE_SEGMENT_DAT 0x5 +#define HEVC_SLICE_DECODING 0x6 +#define HEVC_NAL_UNIT_SEI 0x7 +#define HEVC_SLICE_SEGMENT_DONE 0x8 +#define HEVC_NAL_SEARCH_DONE 0x9 +#define HEVC_DECPIC_DATA_DONE 0xa +#define HEVC_DECPIC_DATA_ERROR 0xb +#define HEVC_SEI_DAT 0xc +#define HEVC_SEI_DAT_DONE 0xd +#define HEVC_NAL_DECODE_DONE 0xe +#define HEVC_OVER_DECODE 0xf + +#define HEVC_DATA_REQUEST 0x12 + +#define HEVC_DECODE_BUFEMPTY 0x20 +#define HEVC_DECODE_TIMEOUT 0x21 +#define HEVC_SEARCH_BUFEMPTY 0x22 +#define HEVC_DECODE_OVER_SIZE 0x23 +#define HEVC_DECODE_BUFEMPTY2 0x24 +#define HEVC_FIND_NEXT_PIC_NAL 0x50 +#define HEVC_FIND_NEXT_DVEL_NAL 0x51 + +#define HEVC_DUMP_LMEM 0x30 + +#define HEVC_4k2k_60HZ_NOT_SUPPORT 0x80 +#define HEVC_DISCARD_NAL 0xf0 +#define HEVC_ACTION_DEC_CONT 0xfd +#define HEVC_ACTION_ERROR 0xfe +#define HEVC_ACTION_DONE 0xff + +/* --------------------------------------------------- */ +/* 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 + +/************************************************** + * + *h265 buffer management + * + *************************************************** + */ +/* #define BUFFER_MGR_ONLY */ +/* #define CONFIG_HEVC_CLK_FORCED_ON */ +/* #define ENABLE_SWAP_TEST */ +#define MCRCC_ENABLE +#define INVALID_POC 0x80000000 + +#define HEVC_DEC_STATUS_REG HEVC_ASSIST_SCRATCH_0 +#define HEVC_RPM_BUFFER HEVC_ASSIST_SCRATCH_1 +#define HEVC_SHORT_TERM_RPS HEVC_ASSIST_SCRATCH_2 +#define HEVC_VPS_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 +#define HEVC_STREAM_SWAP_BUFFER HEVC_ASSIST_SCRATCH_7 +#define HEVC_STREAM_SWAP_BUFFER2 HEVC_ASSIST_SCRATCH_8 +#define HEVC_sao_mem_unit HEVC_ASSIST_SCRATCH_9 +#define HEVC_SAO_ABV HEVC_ASSIST_SCRATCH_A +#define HEVC_sao_vb_size HEVC_ASSIST_SCRATCH_B +#define HEVC_SAO_VB HEVC_ASSIST_SCRATCH_C +#define HEVC_SCALELUT HEVC_ASSIST_SCRATCH_D +#define HEVC_WAIT_FLAG HEVC_ASSIST_SCRATCH_E +#define RPM_CMD_REG HEVC_ASSIST_SCRATCH_F +#define LMEM_DUMP_ADR HEVC_ASSIST_SCRATCH_F +#ifdef ENABLE_SWAP_TEST +#define HEVC_STREAM_SWAP_TEST HEVC_ASSIST_SCRATCH_L +#endif + +/*#define HEVC_DECODE_PIC_BEGIN_REG HEVC_ASSIST_SCRATCH_M*/ +/*#define HEVC_DECODE_PIC_NUM_REG HEVC_ASSIST_SCRATCH_N*/ +#define HEVC_DECODE_SIZE HEVC_ASSIST_SCRATCH_N + /*do not define ENABLE_SWAP_TEST*/ +#define HEVC_AUX_ADR HEVC_ASSIST_SCRATCH_L +#define HEVC_AUX_DATA_SIZE HEVC_ASSIST_SCRATCH_M + +#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/fetch SEI in ucode; + * 1, parse/fetch SEI in ucode + *bit [18]: for NAL_SEI_SUFFIX when bit0 is 0: + * 0, do not fetch NAL_SEI_SUFFIX to aux buf; + * 1, fetch NAL_SEL_SUFFIX data to aux buf + *bit [19]: + * 0, parse NAL_SEI in ucode + * 1, fetch NAL_SEI to aux buf + *bit [20]: for DOLBY_VISION_META + * 0, do not fetch DOLBY_VISION_META to aux buf + * 1, fetch DOLBY_VISION_META to aux buf + */ +#define NAL_SEARCH_CTL HEVC_ASSIST_SCRATCH_I + /*read only*/ +#define CUR_NAL_UNIT_TYPE HEVC_ASSIST_SCRATCH_J + /* + [15 : 8] rps_set_id + [7 : 0] start_decoding_flag + */ +#define HEVC_DECODE_INFO HEVC_ASSIST_SCRATCH_1 + /*set before start decoder*/ +#define HEVC_DECODE_MODE HEVC_ASSIST_SCRATCH_J +#define HEVC_DECODE_MODE2 HEVC_ASSIST_SCRATCH_H +#define DECODE_STOP_POS HEVC_ASSIST_SCRATCH_K + +#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 + +#define MAX_INT 0x7FFFFFFF + +#define RPM_BEGIN 0x100 +#define modification_list_cur 0x148 +#define RPM_END 0x180 +#ifdef SUPPORT_LONG_TERM_RPS +/* + */ +#define RPS_END 0x8000 +#define RPS_LT_BIT 14 +#define RPS_USED_BIT 13 +#define RPS_SIGN_BIT 12 +#else +#define RPS_END 0x8000 +#define RPS_USED_BIT 14 +#define RPS_SIGN_BIT 13 +#endif +/* MISC_FLAG0 */ +#define PCM_LOOP_FILTER_DISABLED_FLAG_BIT 0 +#define PCM_ENABLE_FLAG_BIT 1 +#define LOOP_FILER_ACROSS_TILES_ENABLED_FLAG_BIT 2 +#define PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT 3 +#define DEBLOCKING_FILTER_OVERRIDE_ENABLED_FLAG_BIT 4 +#define PPS_DEBLOCKING_FILTER_DISABLED_FLAG_BIT 5 +#define DEBLOCKING_FILTER_OVERRIDE_FLAG_BIT 6 +#define SLICE_DEBLOCKING_FILTER_DISABLED_FLAG_BIT 7 +#define SLICE_SAO_LUMA_FLAG_BIT 8 +#define SLICE_SAO_CHROMA_FLAG_BIT 9 +#define SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT 10 + +union param_u { + struct { + unsigned short data[RPM_END - RPM_BEGIN]; + } l; + struct { + /* from ucode lmem, do not change this struct */ + unsigned short CUR_RPS[0x10]; + unsigned short num_ref_idx_l0_active; + unsigned short num_ref_idx_l1_active; + unsigned short slice_type; + unsigned short slice_temporal_mvp_enable_flag; + unsigned short dependent_slice_segment_flag; + unsigned short slice_segment_address; + unsigned short num_title_rows_minus1; + unsigned short pic_width_in_luma_samples; + unsigned short pic_height_in_luma_samples; + unsigned short log2_min_coding_block_size_minus3; + unsigned short log2_diff_max_min_coding_block_size; + unsigned short log2_max_pic_order_cnt_lsb_minus4; + unsigned short POClsb; + unsigned short collocated_from_l0_flag; + unsigned short collocated_ref_idx; + unsigned short log2_parallel_merge_level; + unsigned short five_minus_max_num_merge_cand; + unsigned short sps_num_reorder_pics_0; + unsigned short modification_flag; + unsigned short tiles_enabled_flag; + unsigned short num_tile_columns_minus1; + unsigned short num_tile_rows_minus1; + unsigned short tile_width[12]; + unsigned short tile_height[8]; + unsigned short misc_flag0; + unsigned short pps_beta_offset_div2; + unsigned short pps_tc_offset_div2; + unsigned short slice_beta_offset_div2; + unsigned short slice_tc_offset_div2; + unsigned short pps_cb_qp_offset; + unsigned short pps_cr_qp_offset; + unsigned short first_slice_segment_in_pic_flag; + unsigned short m_temporalId; + unsigned short m_nalUnitType; + + unsigned short vui_num_units_in_tick_hi; + unsigned short vui_num_units_in_tick_lo; + unsigned short vui_time_scale_hi; + unsigned short vui_time_scale_lo; + unsigned short bit_depth; + unsigned short profile_etc; + unsigned short sei_frame_field_info; + unsigned short video_signal_type; + unsigned short modification_list[0x20]; + unsigned short conformance_window_flag; + unsigned short conf_win_left_offset; + unsigned short conf_win_right_offset; + unsigned short conf_win_top_offset; + unsigned short conf_win_bottom_offset; + unsigned short chroma_format_idc; + unsigned short color_description; + unsigned short aspect_ratio_idc; + unsigned short sar_width; + unsigned short sar_height; + unsigned short sps_max_dec_pic_buffering_minus1_0; + } p; +}; + +#define RPM_BUF_SIZE (0x80*2) +/* non mmu mode lmem size : 0x400, mmu mode : 0x500*/ +#define LMEM_BUF_SIZE (0x500 * 2) + +struct buff_s { + u32 buf_start; + u32 buf_size; + u32 buf_end; +}; + +struct BuffInfo_s { + u32 max_width; + u32 max_height; + unsigned int start_adr; + unsigned int 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 vps; + 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; + 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; +#endif + struct buff_s rpm; + struct buff_s lmem; +}; + +//#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*/ +#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 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 + */ + .buf_size = 0x1e00, + }, + .sao_abv = { + .buf_size = 0, //0x30000, + }, + .sao_vb = { + .buf_size = 0, //0x30000, + }, + .short_term_rps = {/*checked*/ + /* SHORT_TERM_RPS - Max 64 set, 16 entry every set, + * total 64x16x2 = 2048 bytes (0x800) + */ + .buf_size = 0x800, + }, + .vps = {/*checked*/ + /* VPS STORE AREA - Max 16 VPS, each has 0x80 bytes, + * total 0x0800 bytes + */ + .buf_size = 0x800, + }, + .sps = {/*checked*/ + /* SPS STORE AREA - Max 16 SPS, each has 0x80 bytes, + * total 0x0800 bytes + */ + .buf_size = 0x800, + }, + .pps = {/*checked*/ + /* 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, //0x2800, + }, + .swap_buf = {/*checked*/ + /* 256cyclex64bit = 2K bytes 0x800 + * (only 144 cycles valid) + */ + .buf_size = 0x800, + }, + .swap_buf2 = {/*checked*/ + .buf_size = 0x800, + }, + .scalelut = {/*checked*/ + /* support up to 32 SCALELUT 1024x32 = + * 32Kbytes (0x8000) + */ + .buf_size = 0x8000, + }, + .dblk_para = {.buf_size = 0x14500, }, // dblk parameter + .dblk_data = {.buf_size = 0x62800, }, // dblk data for left/top + .dblk_data2 = {.buf_size = 0x22800, }, // dblk data for adapter + .mmu_vbh = {/*checked*/ + .buf_size = VBH_BUF_SIZE_1080P, /*2*16*2304/4, 4K*/ + }, +#if 0 + .cm_header = {/*checked*//* 0x44000 = ((1088*2*1024*4)/32/4)*(32/8)*/ + .buf_size = MMU_COMPRESS_HEADER_SIZE_1080P * + (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, + }, +#ifdef MV_USE_FIXED_BUF + .mpred_mv = {/*checked*//* 1080p, 0x40000 per buffer */ + .buf_size = MPRED_MV_BUF_SIZE * MAX_REF_PIC_NUM, + }, +#endif + .rpm = {/*checked*/ + .buf_size = RPM_BUF_SIZE, + }, + .lmem = {/*checked*/ + .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 = 0x4000, + }, + .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 = 0, //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 = {.buf_size = 0x19100, }, // dblk parameter + .dblk_data = {.buf_size = 0x88800, }, // dblk data for left/top + .dblk_data2 = {.buf_size = 0x48800, }, // dblk data for adapter + .mmu_vbh = { + .buf_size = VBH_BUF_SIZE_4K, /*2*16*2304/4, 4K*/ + }, +#if 0 + .cm_header = {/*0x44000 = ((1088*2*1024*4)/32/4)*(32/8)*/ + .buf_size = MMU_COMPRESS_HEADER_SIZE_4K * + (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, + }, +#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 = 0, //0x30000*2, + }, + .sao_vb = { + .buf_size = 0, //0x30000*2, + }, + .short_term_rps = { + // SHORT_TERM_RPS - Max 64 set, 16 entry every set, total 64x16x2 = 2048 bytes (0x800) + .buf_size = 0x800, + },