adt3-S media_modules source code [1/1]
internal tot CL:
h265: Revert fix special long ref issue [1/1]
SWPL-49771
Problem:
some file playback unsmooth.
Solution:
Revert commit 915cf6061ec37e7f937b6c73d7db10ec1b8db335
Verify:
A311D-W400
Change-Id(I38171dd2c8b5bbc1aafe07185d9c9dfaf6bb88ce)
Signed-off-by: Peng Yixin <yixin.peng@amlogic.com>
Signed-off-by: Liang Ji <liang.ji@amlogic.com>
Change-Id: Id514584bd7ee4de8bda95c75d9e25adf635b8ccc
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..6640ff9
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,44 @@
+
+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_VDEC_AV1=m \
+ CONFIG_AMLOGIC_MEDIA_VENC_H264=m \
+ CONFIG_AMLOGIC_MEDIA_VENC_JPEG=m \
+ CONFIG_AMLOGIC_MEDIA_VENC_H265=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
+
+
+modules:
+ $(MAKE) -C $(KERNEL_SRC) M=$(M)/drivers modules "EXTRA_CFLAGS+=-I$(INCLUDE) -Wno-error $(CONFIGS_BUILD) $(EXTRA_INCLUDE)" $(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..362d4c7
--- /dev/null
+++ b/Media.mk
@@ -0,0 +1,117 @@
+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_AVS_MULTI=m \
+ CONFIG_AMLOGIC_MEDIA_VDEC_AVS2=m \
+ CONFIG_AMLOGIC_MEDIA_VDEC_AV1=m \
+ CONFIG_AMLOGIC_MEDIA_VENC_H264=m \
+ CONFIG_AMLOGIC_MEDIA_VENC_JPEG=m \
+ CONFIG_AMLOGIC_MEDIA_VENC_H265=m
+
+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=$$(cd ./$(TARGET_HOST_TOOL_PATH); pwd):$$PATH \
+ $(MAKE) -C $(KDIR) M=$(MEDIA_MODULES) ARCH=$(KERNEL_ARCH) \
+ CROSS_COMPILE=$(PREFIX_CROSS_COMPILE) $(CONFIGS) \
+ EXTRA_CFLAGS+=-I$(INCLUDE) modules;
+ sh $(TOP)/device/amlogic/common/copy_modules.sh $(MEDIA_MODULES) $(MODS_OUT)
+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
+
+ifeq ($(KERNEL_A32_SUPPORT), true)
+TOOLS := /opt/gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
+else
+TOOLS := /opt/gcc-linaro-5.3-2016.02-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
+endif
+
+
+modules:
+ CCACHE_NODIRECT="true" PATH=$$(cd ./$(TARGET_HOST_TOOL_PATH); pwd):$$PATH \
+ $(MAKE) -C $(KDIR) M=$(MEDIA_DRIVERS) ARCH=$(KERNEL_ARCH) \
+ CROSS_COMPILE=$(TOOLS) $(CONFIGS) \
+ EXTRA_CFLAGS+=-I$(INCLUDE) -j64
+
+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=$$(cd ./$(TARGET_HOST_TOOL_PATH); pwd):$$PATH \
+ $(MAKE) -C $(KDIR) M=$(MEDIA_DRIVERS) ARCH=$(KERNEL_ARCH) clean
+
+endif
diff --git a/drivers/Makefile b/drivers/Makefile
new file mode 100644
index 0000000..3e487db
--- /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 += fake_video_out/
+obj-y += framerate_adapter/
+obj-y += media_sync/
diff --git a/drivers/amvdec_ports/Makefile b/drivers/amvdec_ports/Makefile
new file mode 100644
index 0000000..6395adf
--- /dev/null
+++ b/drivers/amvdec_ports/Makefile
@@ -0,0 +1,24 @@
+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_vfm.o
+amvdec_ports-objs += vdec_drv_if.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_vcodec_adapt.c b/drivers/amvdec_ports/aml_vcodec_adapt.c
new file mode 100644
index 0000000..95ee48a
--- /dev/null
+++ b/drivers/amvdec_ports/aml_vcodec_adapt.c
@@ -0,0 +1,718 @@
+/*
+* 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 void aml_recycle_dma_buffers(struct aml_vcodec_ctx *ctx, u32 handle);
+static int def_4k_vstreambuf_sizeM =
+ (DEFAULT_VIDEO_BUFFER_SIZE_4K >> 20);
+static int def_vstreambuf_sizeM =
+ (DEFAULT_VIDEO_BUFFER_SIZE >> 20);
+
+static int slow_input = 0;
+
+static int use_bufferlevelx10000 = 10000;
+static unsigned int amstream_buf_num = BUF_MAX_NUM;
+
+static struct stream_buf_s bufs[BUF_MAX_NUM] = {
+ {
+ .reg_base = VLD_MEM_VIFIFO_REG_BASE,
+ .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 int reset_canuse_buferlevel(int levelx10000)
+{
+ int i;
+ struct stream_buf_s *p = NULL;
+
+ if (levelx10000 >= 0 && levelx10000 <= 10000)
+ use_bufferlevelx10000 = levelx10000;
+ else
+ use_bufferlevelx10000 = 10000;
+ for (i = 0; i < amstream_buf_num; i++) {
+ p = &bufs[i];
+ p->canusebuf_size = ((p->buf_size / 1024) *
+ use_bufferlevelx10000 / 10000) * 1024;
+ p->canusebuf_size += 1023;
+ p->canusebuf_size &= ~1023;
+
+ if (p->canusebuf_size > p->buf_size)
+ p->canusebuf_size = p->buf_size;
+ }
+
+ return 0;
+}
+
+static void change_vbufsize(struct vdec_s *vdec,
+ struct stream_buf_s *pvbuf)
+{
+ if (pvbuf->buf_start != 0) {
+ v4l_dbg(0, V4L_DEBUG_CODEC_ERROR, "streambuf is alloced before\n");
+ return;
+ }
+
+ if (vdec->port->is_4k) {
+ pvbuf->buf_size = def_4k_vstreambuf_sizeM * SZ_1M;
+
+ if (vdec->port_flag & PORT_FLAG_DRM)
+ pvbuf->buf_size = DEFAULT_VIDEO_BUFFER_SIZE_4K_TVP;
+
+ if ((pvbuf->buf_size > 30 * SZ_1M)
+ && (codec_mm_get_total_size() < 220 * SZ_1M)) {
+ /*if less than 250M, used 20M for 4K & 265*/
+ pvbuf->buf_size = pvbuf->buf_size >> 1;
+ }
+ } else if (pvbuf->buf_size > def_vstreambuf_sizeM * SZ_1M) {
+ if (vdec->port_flag & PORT_FLAG_DRM)
+ pvbuf->buf_size = DEFAULT_VIDEO_BUFFER_SIZE_TVP;
+ } else {
+ pvbuf->buf_size = def_vstreambuf_sizeM * SZ_1M;
+ if (vdec->port_flag & PORT_FLAG_DRM)
+ pvbuf->buf_size = DEFAULT_VIDEO_BUFFER_SIZE_TVP;
+ }
+
+ reset_canuse_buferlevel(10000);
+}
+
+static void user_buffer_init(void)
+{
+ struct stream_buf_s *pubuf = &bufs[BUF_TYPE_USERDATA];
+
+ 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 stream_buf_s *pbuf, int release_num)
+{
+ struct aml_vdec_adapt *ada_ctx
+ = container_of(port, struct aml_vdec_adapt, port);
+ struct vdec_s *vdec = ada_ctx->vdec;
+
+ struct vdec_s *slave = NULL;
+
+ switch (release_num) {
+ default:
+ case 0:
+ case 4: {
+ if ((port->type & PORT_TYPE_FRAME) == 0)
+ esparser_release(pbuf);
+ }
+
+ case 3: {
+ if (vdec->slave)
+ slave = vdec->slave;
+ vdec_release(vdec);
+
+ if (slave)
+ vdec_release(slave);
+ vdec = NULL;
+ }
+
+ case 2: {
+ if ((port->type & PORT_TYPE_FRAME) == 0)
+ stbuf_release(pbuf);
+ }
+
+ case 1:
+ ;
+ }
+}
+
+static int video_component_init(struct stream_port_s *port,
+ 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) {
+ ret = vdec_init(vdec, port->is_4k);
+ if (ret < 0) {
+ v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_ERROR, "failed\n");
+ video_component_release(port, pbuf, 2);
+ return ret;
+ }
+
+ return 0;
+ }
+
+ change_vbufsize(vdec, pbuf);
+
+ if (has_hevc_vdec()) {
+ if (port->type & PORT_TYPE_MPTS) {
+ if (pbuf->type == BUF_TYPE_HEVC)
+ vdec_poweroff(VDEC_1);
+ else
+ vdec_poweroff(VDEC_HEVC);
+ }
+ }
+
+ ret = stbuf_init(pbuf, vdec);
+ if (ret < 0) {
+ v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_ERROR, "stbuf_init failed\n");
+ return ret;
+ }
+
+ /* todo: set path based on port flag */
+ ret = vdec_init(vdec, port->is_4k);
+ if (ret < 0) {
+ v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_ERROR, "vdec_init failed\n");
+ video_component_release(port, pbuf, 2);
+ return ret;
+ }
+
+ if (vdec_dual(vdec)) {
+ ret = vdec_init(vdec->slave, port->is_4k);
+ if (ret < 0) {
+ v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_ERROR, "vdec_init failed\n");
+ video_component_release(port, pbuf, 2);
+ return ret;
+ }
+ }
+
+ if (port->type & PORT_TYPE_ES) {
+ ret = esparser_init(pbuf, vdec);
+ if (ret < 0) {
+ video_component_release(port, pbuf, 3);
+ v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_ERROR, "esparser_init() failed\n");
+ return ret;
+ }
+ }
+
+ pbuf->flag |= BUF_FLAG_IN_USE;
+
+ vdec_connect(vdec);
+
+ return 0;
+}
+
+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, pvbuf, 0);
+
+ 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;
+ vdec->vf_receiver_name = ada_ctx->recv_name;
+
+ /* 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;
+ ada_ctx->vfm_path = vdec->frame_base_video_path;
+
+ 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;
+
+ 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);
+ }
+
+}
+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 > 600) ? true : false;
+}
+
+int vdec_vframe_write(struct aml_vdec_adapt *ada_ctx,
+ const char *buf, unsigned int count, u64 timestamp)
+{
+ int ret = -1;
+ struct vdec_s *vdec = ada_ctx->vdec;
+
+ /* set timestamp */
+ vdec_set_timestamp(vdec, timestamp);
+
+ 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("/data/es.data", buf, count);
+ dump_output_frame--;
+ }
+
+ 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->q_data[AML_Q_DATA_SRC].resolution_changed)
+ vdec_set_eos(vdec, false);
+ if (*mode == V4L_RESET_MODE_NORMAL &&
+ vdec->input.have_frame_num == 0) {
+ v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_PRINFO,
+ "no input reset mode: %d\n", *mode);
+ *mode = V4L_RESET_MODE_LIGHT;
+ }
+ if (ada_ctx->ctx->param_sets_from_ucode &&
+ *mode == V4L_RESET_MODE_NORMAL &&
+ ada_ctx->ctx->q_data[AML_Q_DATA_SRC].resolution_changed == true) {
+ v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_PRINFO,
+ "resolution_changed reset mode: %d\n", *mode);
+ *mode = V4L_RESET_MODE_LIGHT;
+ }
+ v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_PRINFO,
+ "reset mode: %d\n", *mode);
+
+ 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;
+}
+
+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);
+}
diff --git a/drivers/amvdec_ports/aml_vcodec_adapt.h b/drivers/amvdec_ports/aml_vcodec_adapt.h
new file mode 100644
index 0000000..b86cbff
--- /dev/null
+++ b/drivers/amvdec_ports/aml_vcodec_adapt.h
@@ -0,0 +1,77 @@
+/*
+* 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 {
+ enum vformat_e format;
+ void *vsi;
+ int32_t failure;
+ uint32_t inst_addr;
+ unsigned int signaled;
+ struct aml_vcodec_ctx *ctx;
+ struct platform_device *dev;
+ wait_queue_head_t wq;
+ struct file *filp;
+ struct vdec_s *vdec;
+ struct stream_port_s port;
+ struct dec_sysinfo dec_prop;
+ struct v4l2_config_parm config;
+ int video_type;
+ char *recv_name;
+ int vfm_path;
+};
+
+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);
+
+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);
+
+#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..afebb7a
--- /dev/null
+++ b/drivers/amvdec_ports/aml_vcodec_dec.c
@@ -0,0 +1,2715 @@
+/*
+* 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 "aml_vcodec_drv.h"
+#include "aml_vcodec_dec.h"
+//#include "aml_vcodec_intr.h"
+#include "aml_vcodec_util.h"
+#include "vdec_drv_if.h"
+#include <linux/delay.h>
+#include <linux/atomic.h>
+#include <linux/crc32.h>
+#include "aml_vcodec_adapt.h"
+#include <linux/spinlock.h>
+
+#include "aml_vcodec_vfm.h"
+#include "../frame_provider/decoder/utils/decoder_bmmu_box.h"
+#include "../frame_provider/decoder/utils/decoder_mmu_box.h"
+
+#define KERNEL_ATRACE_TAG KERNEL_ATRACE_TAG_V4L2
+#include <trace/events/meson_atrace.h>
+
+#define OUT_FMT_IDX 0 //default h264
+#define CAP_FMT_IDX 8 //capture nv21
+
+#define 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 WORK_ITEMS_MAX (32)
+
+//#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[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_H264,
+ .type = AML_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_HEVC,
+ .type = AML_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_VP9,
+ .type = AML_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_MPEG1,
+ .type = AML_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_MPEG2,
+ .type = AML_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_MPEG4,
+ .type = AML_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_MJPEG,
+ .type = AML_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_AV1,
+ .type = AML_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .type = AML_FMT_FRAME,
+ .num_planes = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV21M,
+ .type = AML_FMT_FRAME,
+ .num_planes = 2,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .type = AML_FMT_FRAME,
+ .num_planes = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .type = AML_FMT_FRAME,
+ .num_planes = 2,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .type = AML_FMT_FRAME,
+ .num_planes = 1,
+ },
+};
+
+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_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},
+ },
+};
+
+#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(aml_vdec_framesizes)
+#define NUM_FORMATS ARRAY_SIZE(aml_video_formats)
+
+extern bool multiplanar;
+extern bool dump_capture_frame;
+
+extern int dmabuf_fd_install_data(int fd, void* data, u32 size);
+extern bool is_v4l2_buf_file(struct file *file);
+
+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 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};
+
+ if (ctx->receive_cmd_stop &&
+ changes != V4L2_EVENT_SRC_CH_RESOLUTION &&
+ changes != V4L2_EVENT_SEND_EOS) {
+ ctx->state = AML_STATE_ABORT;
+ ATRACE_COUNTER("v4l2_state", ctx->state);
+ changes = V4L2_EVENT_REQUEST_EXIT;
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE,
+ "vcodec state (AML_STATE_ABORT)\n");
+ }
+
+ switch (changes) {
+ case V4L2_EVENT_SRC_CH_RESOLUTION:
+ case V4L2_EVENT_SRC_CH_HDRINFO:
+ 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);
+}
+
+static void aml_vdec_pic_info_update(struct aml_vcodec_ctx *ctx)
+{
+ unsigned int dpbsize = 0;
+ int ret;
+
+ 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);
+
+ ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize);
+ if (dpbsize == 0)
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR,
+ "Incorrect dpb size, ret=%d\n", ret);
+
+ /* update picture information */
+ ctx->dpb_size = dpbsize;
+ ctx->picinfo = ctx->last_decoded_picinfo;
+}
+
+static bool aml_check_inst_quit(struct aml_vcodec_dev *dev,
+ struct aml_vcodec_ctx * inst, u32 id)
+{
+ struct aml_vcodec_ctx *ctx = NULL;
+ bool ret = true;
+
+ if (dev == NULL)
+ return false;
+
+ mutex_lock(&dev->dev_mutex);
+
+ if (list_empty(&dev->ctx_list)) {
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR,
+ "v4l inst list is empty.\n");
+ ret = true;
+ goto out;
+ }
+
+ list_for_each_entry(ctx, &dev->ctx_list, list) {
+ if ((ctx == inst) && (ctx->id == id)) {
+ ret = ctx->receive_cmd_stop ? true : false;
+ goto out;
+ }
+ }
+out:
+ mutex_unlock(&dev->dev_mutex);
+
+ return ret;
+}
+
+void vdec_frame_buffer_release(void *data)
+{
+ struct file_private_data *priv_data =
+ (struct file_private_data *) data;
+ struct aml_vcodec_dev *dev = (struct aml_vcodec_dev *)
+ priv_data->vb_handle;
+ struct aml_vcodec_ctx *inst = (struct aml_vcodec_ctx *)
+ priv_data->v4l_dec_ctx;
+ u32 id = priv_data->v4l_inst_id;
+
+ if (aml_check_inst_quit(dev, inst, id)) {
+ struct vframe_s *vf = &priv_data->vf;
+
+ v4l_dbg(0, V4L_DEBUG_CODEC_BUFMGR,
+ "[%d]: vf idx: %d, bmmu idx: %d, bmmu_box: %lx\n",
+ id, vf->index, vf->mm_box.bmmu_idx,
+ (ulong) vf->mm_box.bmmu_box);
+
+ v4l_dbg(0, V4L_DEBUG_CODEC_BUFMGR,
+ "[%d]: vf idx: %d, mmu_idx: %d, mmu_box: %lx\n",
+ id, vf->index, vf->mm_box.mmu_idx,
+ (ulong) vf->mm_box.mmu_box);
+
+ if (decoder_bmmu_box_valide_check(vf->mm_box.bmmu_box)) {
+ decoder_bmmu_box_free_idx(vf->mm_box.bmmu_box,
+ vf->mm_box.bmmu_idx);
+ decoder_bmmu_try_to_release_box(vf->mm_box.bmmu_box);
+ }
+
+ if (decoder_mmu_box_valide_check(vf->mm_box.mmu_box)) {
+ decoder_mmu_box_free_idx(vf->mm_box.mmu_box,
+ vf->mm_box.mmu_idx);
+ decoder_mmu_try_to_release_box(vf->mm_box.mmu_box);
+ }
+
+ }
+
+ memset(data, 0, sizeof(struct file_private_data));
+ kfree(data);
+}
+
+int get_fb_from_queue(struct aml_vcodec_ctx *ctx, struct vdec_v4l2_buffer **out_fb)
+{
+ ulong flags;
+ struct vb2_buffer *dst_buf = NULL;
+ struct vdec_v4l2_buffer *pfb;
+ struct aml_video_dec_buf *dst_buf_info, *info;
+ struct vb2_v4l2_buffer *dst_vb2_v4l2;
+
+ flags = aml_vcodec_ctx_lock(ctx);
+
+ if (ctx->state == AML_STATE_ABORT) {
+ aml_vcodec_ctx_unlock(ctx, flags);
+ return -1;
+ }
+
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ if (!dst_buf) {
+ aml_vcodec_ctx_unlock(ctx, flags);
+ return -1;
+ }
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR,
+ "vbuf idx: %d, state: %d, ready: %d\n",
+ dst_buf->index, dst_buf->state,
+ v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx));
+
+ dst_vb2_v4l2 = container_of(dst_buf, struct vb2_v4l2_buffer, vb2_buf);
+ dst_buf_info = container_of(dst_vb2_v4l2, struct aml_video_dec_buf, vb);
+
+ pfb = &dst_buf_info->frame_buffer;
+ pfb->buf_idx = dst_buf->index;
+ pfb->num_planes = dst_buf->num_planes;
+ pfb->status = FB_ST_NORMAL;
+ if (dst_buf->num_planes == 1) {
+ pfb->m.mem[0].dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+ pfb->m.mem[0].addr = dma_to_phys(v4l_get_dev_from_codec_mm(), pfb->m.mem[0].dma_addr);
+ pfb->m.mem[0].size = ctx->picinfo.y_len_sz + ctx->picinfo.c_len_sz;
+ pfb->m.mem[0].offset = ctx->picinfo.y_len_sz;
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR,
+ "idx: %u, 1 plane, y:(0x%lx, %d)\n", dst_buf->index,
+ pfb->m.mem[0].addr, pfb->m.mem[0].size);
+ } else if (dst_buf->num_planes == 2) {
+ pfb->m.mem[0].dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+ pfb->m.mem[0].addr = dma_to_phys(v4l_get_dev_from_codec_mm(), pfb->m.mem[0].dma_addr);
+ pfb->m.mem[0].size = ctx->picinfo.y_len_sz;
+ pfb->m.mem[0].offset = 0;
+
+ pfb->m.mem[1].dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 1);
+ pfb->m.mem[1].addr = dma_to_phys(v4l_get_dev_from_codec_mm(), pfb->m.mem[1].dma_addr);
+ pfb->m.mem[1].size = ctx->picinfo.c_len_sz;
+ pfb->m.mem[1].offset = ctx->picinfo.c_len_sz >> 1;
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR,
+ "idx: %u, 2 planes, y:(0x%lx, %d), c:(0x%lx, %d)\n", dst_buf->index,
+ pfb->m.mem[0].addr, pfb->m.mem[0].size,
+ pfb->m.mem[1].addr, pfb->m.mem[1].size);
+ } else {
+ pfb->m.mem[0].dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+ pfb->m.mem[0].addr = dma_to_phys(v4l_get_dev_from_codec_mm(), pfb->m.mem[0].dma_addr);
+ pfb->m.mem[0].size = ctx->picinfo.y_len_sz;
+ pfb->m.mem[0].offset = 0;
+
+ pfb->m.mem[1].dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 1);
+ pfb->m.mem[1].addr = dma_to_phys(v4l_get_dev_from_codec_mm(), pfb->m.mem[2].dma_addr);
+ pfb->m.mem[1].size = ctx->picinfo.c_len_sz >> 1;
+ pfb->m.mem[1].offset = 0;
+
+ pfb->m.mem[2].dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 2);
+ pfb->m.mem[2].addr = dma_to_phys(v4l_get_dev_from_codec_mm(), pfb->m.mem[3].dma_addr);
+ pfb->m.mem[2].size = ctx->picinfo.c_len_sz >> 1;
+ pfb->m.mem[2].offset = 0;
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR,
+ "idx: %u, 3 planes, y:(0x%lx, %d), u:(0x%lx, %d), v:(0x%lx, %d)\n",
+ dst_buf->index,
+ pfb->m.mem[0].addr, pfb->m.mem[0].size,
+ pfb->m.mem[1].addr, pfb->m.mem[1].size,
+ pfb->m.mem[2].addr, pfb->m.mem[2].size);
+ }
+
+ dst_buf_info->used = true;
+ ctx->buf_used_count++;
+
+ *out_fb = pfb;
+
+ info = container_of(pfb, struct aml_video_dec_buf, frame_buffer);
+
+ ctx->cap_pool.dec++;
+ ctx->cap_pool.seq[ctx->cap_pool.out++] =
+ (V4L_CAP_BUFF_IN_DEC << 16 | dst_buf->index);
+ v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+
+ aml_vcodec_ctx_unlock(ctx, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(get_fb_from_queue);
+
+int put_fb_to_queue(struct aml_vcodec_ctx *ctx, struct vdec_v4l2_buffer *in_fb)
+{
+ struct aml_video_dec_buf *dstbuf;
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, "%s\n", __func__);
+
+ if (in_fb == NULL) {
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "No free frame buffer\n");
+ return -1;
+ }
+
+ dstbuf = container_of(in_fb, struct aml_video_dec_buf, frame_buffer);
+
+ mutex_lock(&ctx->lock);
+
+ if (!dstbuf->used)
+ goto out;
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO,
+ "status=%x queue id=%d to rdy_queue\n",
+ in_fb->status, dstbuf->vb.vb2_buf.index);
+
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, &dstbuf->vb);
+
+ dstbuf->used = false;
+out:
+ mutex_unlock(&ctx->lock);
+
+ return 0;
+
+}
+EXPORT_SYMBOL(put_fb_to_queue);
+
+void trans_vframe_to_user(struct aml_vcodec_ctx *ctx, struct vdec_v4l2_buffer *fb)
+{
+ struct aml_video_dec_buf *dstbuf = NULL;
+ struct vb2_buffer *vb2_buf = NULL;
+ struct vframe_s *vf = (struct vframe_s *)fb->vf_handle;
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_OUTPUT,
+ "FROM (%s %s) vf: %lx, ts: %llu, idx: %d, "
+ "Y:(%lx, %u) C/U:(%lx, %u) V:(%lx, %u)\n",
+ vf_get_provider(ctx->ada_ctx->recv_name)->name,
+ ctx->ada_ctx->vfm_path != FRAME_BASE_PATH_V4L_VIDEO ? "OSD" : "VIDEO",
+ (ulong) vf, vf->timestamp, vf->index,
+ fb->m.mem[0].addr, fb->m.mem[0].size,
+ fb->m.mem[1].addr, fb->m.mem[1].size,
+ fb->m.mem[2].addr, fb->m.mem[2].size);
+
+ dstbuf = container_of(fb, struct aml_video_dec_buf, frame_buffer);
+ vb2_buf = &dstbuf->vb.vb2_buf;
+
+ if (dstbuf->frame_buffer.num_planes == 1) {
+ vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 0, fb->m.mem[0].bytes_used);
+ } else if (dstbuf->frame_buffer.num_planes == 2) {
+ vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 0, fb->m.mem[0].bytes_used);
+ vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 1, fb->m.mem[1].bytes_used);
+ }
+ dstbuf->vb.vb2_buf.timestamp = vf->timestamp;
+ dstbuf->ready_to_display = true;
+
+ if (dump_capture_frame) {
+ struct file *fp;
+ fp = filp_open("/data/dec_dump.raw",
+ O_CREAT | O_RDWR | O_LARGEFILE | O_APPEND, 0600);
+ if (!IS_ERR(fp)) {
+ struct vb2_buffer *vb = &dstbuf->vb.vb2_buf;
+ kernel_write(fp,vb2_plane_vaddr(vb, 0),vb->planes[0].bytesused, 0);
+ if (dstbuf->frame_buffer.num_planes == 2)
+ kernel_write(fp,vb2_plane_vaddr(vb, 1),
+ vb->planes[1].bytesused, 0);
+ pr_info("dump idx: %d %dx%d\n", dump_capture_frame, vf->width, vf->height);
+ dump_capture_frame = false;
+ filp_close(fp, NULL);
+ }
+ }
+
+ if (vf->flag & VFRAME_FLAG_EMPTY_FRAME_V4L) {
+ dstbuf->vb.flags = V4L2_BUF_FLAG_LAST;
+ if (dstbuf->frame_buffer.num_planes == 1) {
+ vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 0, 0);
+ } else if (dstbuf->frame_buffer.num_planes == 2) {
+ vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 0, 0);
+ vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 1, 0);
+ }
+ ctx->has_receive_eos = true;
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR,
+ "recevie a empty frame. idx: %d, state: %d\n",
+ dstbuf->vb.vb2_buf.index,
+ dstbuf->vb.vb2_buf.state);
+ ATRACE_COUNTER("v4l2_eos", 0);
+ }
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO,
+ "receive vbuf idx: %d, state: %d\n",
+ dstbuf->vb.vb2_buf.index,
+ dstbuf->vb.vb2_buf.state);
+
+ if (vf->flag & VFRAME_FLAG_EMPTY_FRAME_V4L) {
+ if (ctx->q_data[AML_Q_DATA_SRC].resolution_changed) {
+ /* make the run to stanby until new buffs to enque. */
+ ctx->v4l_codec_dpb_ready = false;
+ ctx->reset_flag = V4L_RESET_MODE_LIGHT;
+
+ /*
+ * 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. */
+ vf->flag |= VFRAME_FLAG_VIDEO_LINEAR;
+ ATRACE_COUNTER("v4l2_from", vf->index_disp);
+ dstbuf->privdata.vf = *vf;
+ dstbuf->privdata.vf.omx_index =
+ dstbuf->vb.vb2_buf.index;
+
+ v4l2_m2m_buf_done(&dstbuf->vb, VB2_BUF_STATE_DONE);
+ }
+
+ mutex_lock(&ctx->state_lock);
+ if (ctx->state == AML_STATE_FLUSHING &&
+ ctx->has_receive_eos) {
+ ctx->state = AML_STATE_FLUSHED;
+ ATRACE_COUNTER("v4l2_state", ctx->state);
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE,
+ "vcodec state (AML_STATE_FLUSHED)\n");
+ }
+ mutex_unlock(&ctx->state_lock);
+
+ ctx->decoded_frame_cnt++;
+}
+
+static int get_display_buffer(struct aml_vcodec_ctx *ctx, struct vdec_v4l2_buffer **out)
+{
+ int ret = -1;
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, "%s\n", __func__);
+
+ ret = vdec_if_get_param(ctx, GET_PARAM_DISP_FRAME_BUFFER, out);
+ if (ret) {
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR,
+ "Cannot get param : GET_PARAM_DISP_FRAME_BUFFER\n");
+ return -1;
+ }
+
+ if (!*out) {
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR,
+ "No display frame buffer\n");
+ return -1;
+ }
+
+ return ret;
+}
+
+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, ready: %d, used: %d, dpb is ready: %s\n",
+ ctx->dpb_size, v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx),
+ ctx->cap_pool.out, ctx->v4l_codec_dpb_ready ? "yes" : "no");
+ }
+}
+
+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("v4l2_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("v4l2_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_dpb_ready(struct aml_vcodec_ctx *ctx)
+{
+ ulong expires;
+
+ expires = jiffies + msecs_to_jiffies(1000);
+ while (!ctx->v4l_codec_dpb_ready) {
+ u32 ready_num = 0;
+
+ if (time_after(jiffies, expires)) {
+ 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->dpb_size)
+ ctx->v4l_codec_dpb_ready = true;
+ }
+}
+
+void aml_recycle_dma_buffers(struct aml_vcodec_ctx *ctx, u32 handle)
+{
+ struct vb2_v4l2_buffer *vb;
+ struct aml_video_dec_buf *buf;
+ struct vb2_queue *q;
+ int index = handle & 0xf;
+
+ if (ctx->is_out_stream_off) {
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_INPUT,
+ "ignore buff idx: %d streamoff\n", index);
+ return;
+ }
+ q = v4l2_m2m_get_vq(ctx->m2m_ctx,
+ V4L2_BUF_TYPE_VIDEO_OUTPUT);
+
+ vb = to_vb2_v4l2_buffer(q->bufs[index]);
+ buf = container_of(vb, struct aml_video_dec_buf, vb);
+ v4l2_m2m_buf_done(vb, buf->error ? VB2_BUF_STATE_ERROR :
+ VB2_BUF_STATE_DONE);
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_INPUT,
+ "recycle buff idx: %d, vbuf: %lx\n", index,
+ (ulong)vb2_dma_contig_plane_dma_addr(q->bufs[index], 0));
+}
+
+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 vb2_buffer *src_buf;
+ struct aml_vcodec_mem buf;
+ bool res_chg = false;
+ int ret;
+ struct aml_video_dec_buf *src_buf_info;
+ struct vb2_v4l2_buffer *src_vb2_v4l2;
+
+ if (ctx->state < AML_STATE_INIT ||
+ ctx->state > AML_STATE_FLUSHED) {
+ 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;
+ }
+
+ src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+ if (src_buf == NULL) {
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR,
+ "src_buf empty.\n");
+ goto out;
+ }
+
+ /*this case for google, but some frames are droped on ffmpeg, so disabled temp.*/
+ if (0 && !is_enough_work_items(ctx))
+ goto out;
+
+ src_vb2_v4l2 = container_of(src_buf, struct vb2_v4l2_buffer, vb2_buf);
+ src_buf_info = container_of(src_vb2_v4l2, struct aml_video_dec_buf, vb);
+
+ if (src_buf_info->lastframe) {
+ /*the empty data use to flushed the decoder.*/
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR,
+ "Got empty flush input buffer.\n");
+
+ /*
+ * when inputs a small amount of src buff, then soon to
+ * switch state FLUSHING, must to wait the DBP to be ready.
+ */
+ if (!ctx->v4l_codec_dpb_ready) {
+ v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
+ goto out;
+ }
+
+ mutex_lock(&ctx->state_lock);
+ if (ctx->state == AML_STATE_ACTIVE) {
+ ctx->state = AML_STATE_FLUSHING;// prepare flushing
+ ATRACE_COUNTER("v4l2_state", ctx->state);
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE,
+ "vcodec state (AML_STATE_FLUSHING-LASTFRM)\n");
+ }
+ mutex_unlock(&ctx->state_lock);
+
+ src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+ v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
+
+ /* sets eos data for vdec input. */
+ aml_vdec_flush_decoder(ctx);
+
+ goto out;
+ }
+
+ buf.index = src_buf->index;
+ buf.vaddr = vb2_plane_vaddr(src_buf, 0);
+ buf.addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+ buf.size = src_buf->planes[0].bytesused;
+ buf.model = src_buf->memory;
+ buf.timestamp = src_buf->timestamp;
+
+ if (!buf.vaddr && !buf.addr) {
+ v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR,
+ "id=%d src_addr is NULL.\n", src_buf->index);
+ goto out;
+ }
+
+ src_buf_info->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);*/
+
+ ret = vdec_if_decode(ctx, &buf, &res_chg);
+ if (ret > 0) {
+ /*
+ * we only return src buffer with VB2_BUF_STATE_DONE
+ * when decode success without resolution change.
+ */
+ v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+ if (!(ctx->is_drm_mode && buf.model == VB2_MEMORY_DMABUF))
+ v4l2_m2m_buf_done(&src_buf_info->vb, VB2_BUF_STATE_DONE);
+ } else if (ret && ret != -EAGAIN) {
+ src_buf_info->error = (ret == -EIO ? true : false);
+ v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+
+ if (!(ctx->is_drm_mode && buf.model == VB2_MEMORY_DMABUF))
+ v4l2_m2m_buf_done(&src_buf_info->vb, VB2_BUF_STATE_ERROR);
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR,
+ "error processing src data. %d.\n", ret);
+ } else if (res_chg) {
+ /* wait the DPB state to be ready. */
+ aml_wait_dpb_ready(ctx);
+
+ src_buf_info->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("v4l2_state", ctx->state);
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE,
+ "vcodec state (AML_STATE_FLUSHING-RESCHG)\n");
+ }
+ mutex_unlock(&ctx->state_lock);
+
+ ctx->q_data[AML_Q_DATA_SRC].resolution_changed = true;
+ 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 {
+ /* decoder is lack of resource, retry after short delay */
+ usleep_range(50000, 55000);
+ }
+
+ 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("v4l2_state", ctx->state);
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE,
+ "vcodec state (AML_STATE_ABORT).\n");
+ goto out;
+ }
+
+ if (ctx->state == AML_STATE_RESET) {
+ ctx->state = AML_STATE_PROBE;
+ ATRACE_COUNTER("v4l2_state", ctx->state);
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE,
+ "vcodec state (AML_STATE_PROBE)\n");
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR,
+ "dpb: %d, ready: %d, used: %d\n", ctx->dpb_size,
+ v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx),
+ ctx->buf_used_count);
+
+ /* vdec has ready to decode subsequence data of new resolution. */
+ ctx->q_data[AML_Q_DATA_SRC].resolution_changed = false;
+ v4l2_m2m_job_resume(ctx->dev->m2m_dev_dec, ctx->m2m_ctx);
+ }
+
+out:
+ complete(&ctx->comp);
+ return;
+}
+
+void wait_vcodec_ending(struct aml_vcodec_ctx *ctx)
+{
+ struct aml_vcodec_dev *dev = ctx->dev;
+
+ /* disable queue output item to worker. */
+ ctx->output_thread_ready = false;
+
+ /* flush output buffer worker. */
+ flush_workqueue(dev->decode_workqueue);
+
+ /* 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 try_to_capture(struct aml_vcodec_ctx *ctx)
+{
+ int ret = 0;
+ struct vdec_v4l2_buffer *fb = NULL;
+
+ ret = get_display_buffer(ctx, &fb);
+ if (ret) {
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR,
+ "the que have no disp buf,ret: %d\n", ret);
+ return;
+ }
+
+ trans_vframe_to_user(ctx, fb);
+}
+EXPORT_SYMBOL_GPL(try_to_capture);
+
+static int vdec_thread(void *data)
+{
+ struct sched_param param =
+ {.sched_priority = MAX_RT_PRIO / 2};
+ struct aml_vdec_thread *thread =
+ (struct aml_vdec_thread *) data;
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *) thread->priv;
+
+ sched_setscheduler(current, SCHED_FIFO, ¶m);
+
+ for (;;) {
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO,
+ "%s, state: %d\n", __func__, ctx->state);
+
+ if (down_interruptible(&thread->sem))
+ break;
+
+ if (thread->stop)
+ break;
+
+ /* handle event. */
+ thread->func(ctx);
+ }
+
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ }
+
+ return 0;
+}
+
+void aml_thread_notify(struct aml_vcodec_ctx *ctx,
+ enum aml_thread_type type)
+{
+ struct aml_vdec_thread *thread = NULL;
+
+ mutex_lock(&ctx->lock);
+ list_for_each_entry(thread, &ctx->vdec_thread_list, node) {
+ if (thread->task == NULL)
+ continue;
+
+ if (thread->type == type)
+ up(&thread->sem);
+ }
+ mutex_unlock(&ctx->lock);
+}
+EXPORT_SYMBOL_GPL(aml_thread_notify);
+
+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_thread, thread, "aml-%s", thread_name);
+ if (IS_ERR(thread->task)) {
+ ret = PTR_ERR(thread->task);
+ thread->task = NULL;
+ goto err;
+ }
+ sched_setscheduler_nocheck(thread->task, SCHED_FIFO, ¶m);
+
+ 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;
+
+ while (!list_empty(&ctx->vdec_thread_list)) {
+ thread = list_entry(ctx->vdec_thread_list.next,
+ struct aml_vdec_thread, node);
+ mutex_lock(&ctx->lock);
+ list_del(&thread->node);
+ mutex_unlock(&ctx->lock);
+
+ 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->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:
+ ATRACE_COUNTER("v4l2_stop", 0);
+ if (ctx->state != AML_STATE_ACTIVE) {
+ if (ctx->state >= AML_STATE_IDLE &&
+ ctx->state < AML_STATE_PROBE) {
+ ctx->state = AML_STATE_ABORT;
+ ATRACE_COUNTER("v4l2_state", ctx->state);
+ aml_vdec_dispatch_event(ctx, V4L2_EVENT_REQUEST_EXIT);
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE,
+ "vcodec state (AML_STATE_ABORT)\n");
+ return 0;
+ }
+ }
+
+ src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
+ V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+ if (!vb2_is_streaming(src_vq)) {
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR,
+ "Output 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;
+ break;
+
+ case V4L2_DEC_CMD_START:
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, "CMD V4L2_DEC_CMD_START\n");
+ dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
+ multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
+ V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ vb2_clear_last_buffer_dequeued(dst_vq);//pay attention
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+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)) {
+ if (ctx->is_stream_off) {
+ mutex_lock(&ctx->state_lock);
+ if ((ctx->state == AML_STATE_ACTIVE ||
+ ctx->state == AML_STATE_FLUSHING ||
+ ctx->state == AML_STATE_FLUSHED) ||
+ (ctx->reset_flag == V4L_RESET_MODE_LIGHT)) {
+ ctx->state = AML_STATE_RESET;
+ ATRACE_COUNTER("v4l2_state", ctx->state);
+ ctx->v4l_codec_dpb_ready = false;
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE,
+ "vcodec state (AML_STATE_RESET)\n");
+ aml_vdec_reset(ctx);
+ }
+ mutex_unlock(&ctx->state_lock);
+
+ ctx->is_stream_off = false;
+ ctx->v4l_resolution_change = 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;
+
+ q = v4l2_m2m_get_vq(fh->m2m_ctx, i);
+ if (!V4L2_TYPE_IS_OUTPUT(q->type))
+ ctx->is_stream_off = true;
+ else
+ ctx->is_out_stream_off = true;
+
+ 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)
+ vb2_queue_release(q);
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT,
+ "%s, type: %d, count: %d\n",
+ __func__, q->type, rb->count);
+
+ if (!V4L2_TYPE_IS_OUTPUT(rb->type)) {
+ /* driver needs match v4l buffer number with dpb_size */
+ if (rb->count > ctx->dpb_size) {
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT,
+ "reqbufs (st:%d) %d -> %d\n",
+ ctx->state, rb->count, ctx->dpb_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;
+
+ flags = aml_vcodec_ctx_lock(ctx);
+ ctx->state = AML_STATE_ABORT;
+ ATRACE_COUNTER("v4l2_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->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];
+ 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->state = AML_STATE_IDLE;
+ ATRACE_COUNTER("v4l2_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 (ret == -EAGAIN)
+ ATRACE_COUNTER("v4l2_qbuf_eagain", 0);
+ else
+ ATRACE_COUNTER("v4l2_qbuf_ok", 0);
+ }
+ 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 (V4L2_TYPE_IS_OUTPUT(buf->type)) {
+ if (ret == -EAGAIN)
+ ATRACE_COUNTER("v4l2_dqin_eagain", 0);
+ else
+ ATRACE_COUNTER("v4l2_dqin_ok", 0);
+ } else {
+ if (ret == -EAGAIN)
+ ATRACE_COUNTER("v4l2_dqout_eagain", 0);
+ }
+
+ if (!ret && !V4L2_TYPE_IS_OUTPUT(buf->type)) {
+ struct vb2_queue *vq;
+ struct vb2_v4l2_buffer *vb2_v4l2 = NULL;
+ struct aml_video_dec_buf *aml_buf = NULL;
+
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, buf->type);
+ vb2_v4l2 = to_vb2_v4l2_buffer(vq->bufs[buf->index]);
+ aml_buf = container_of(vb2_v4l2, struct aml_video_dec_buf, vb);
+ aml_buf->privdata.vb_handle = (ulong) ctx->dev;
+ aml_buf->privdata.v4l_dec_ctx = (ulong) ctx;
+ aml_buf->privdata.v4l_inst_id = ctx->id;
+
+ file = fget(vb2_v4l2->private);
+ if (is_v4l2_buf_file(file)) {
+ dmabuf_fd_install_data(vb2_v4l2->private,
+ (void*)&aml_buf->privdata,
+ sizeof(struct file_private_data));
+ ATRACE_COUNTER("v4l2_dqout_ok", aml_buf->privdata.vf.index_disp);
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, "disp: %d, vf: %lx\n",
+ aml_buf->privdata.vf.index_disp,
+ (ulong) v4l_get_vf_handle(vb2_v4l2->private));
+ }
+ fput(file);
+ }
+
+ 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);
+
+ 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));
+
+ 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)
+{
+ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+ int i;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ pix_fmt_mp->num_planes = 1;
+ pix_fmt_mp->plane_fmt[0].bytesperline = 0;
+ if (pix_fmt_mp->pixelformat != V4L2_PIX_FMT_MPEG2 &&
+ pix_fmt_mp->pixelformat != V4L2_PIX_FMT_H264)
+ pix_fmt_mp->field = V4L2_FIELD_NONE;
+ else if (pix_fmt_mp->field != V4L2_FIELD_NONE)
+ pr_info("%s, field: %u, fmt: %u\n",
+ __func__, pix_fmt_mp->field,
+ pix_fmt_mp->pixelformat);
+ } else if (!V4L2_TYPE_IS_OUTPUT(f->type)) {
+ int tmp_w, tmp_h;
+
+ pix_fmt_mp->field = V4L2_FIELD_NONE;
+ pix_fmt_mp->height = clamp(pix_fmt_mp->height,
+ AML_VDEC_MIN_H,
+ AML_VDEC_MAX_H);
+ pix_fmt_mp->width = clamp(pix_fmt_mp->width,
+ AML_VDEC_MIN_W,
+ AML_VDEC_MAX_W);
+
+ /*
+ * Find next closer width align 64, heign align 64, size align
+ * 64 rectangle
+ * Note: This only get default value, the real HW needed value
+ * only available when ctx in AML_STATE_PROBE state
+ */
+ tmp_w = pix_fmt_mp->width;
+ tmp_h = pix_fmt_mp->height;
+ v4l_bound_align_image(&pix_fmt_mp->width,
+ AML_VDEC_MIN_W,
+ AML_VDEC_MAX_W, 6,
+ &pix_fmt_mp->height,
+ AML_VDEC_MIN_H,
+ AML_VDEC_MAX_H, 6, 9);
+
+ if (pix_fmt_mp->width < tmp_w &&
+ (pix_fmt_mp->width + 64) <= AML_VDEC_MAX_W)
+ pix_fmt_mp->width += 64;
+ if (pix_fmt_mp->height < tmp_h &&
+ (pix_fmt_mp->height + 64) <= AML_VDEC_MAX_H)
+ pix_fmt_mp->height += 64;
+
+ pix_fmt_mp->num_planes = fmt->num_planes;
+ pix_fmt_mp->plane_fmt[0].sizeimage =
+ pix_fmt_mp->width * pix_fmt_mp->height;
+ pix_fmt_mp->plane_fmt[0].bytesperline = pix_fmt_mp->width;
+
+ if (pix_fmt_mp->num_planes == 2) {
+ pix_fmt_mp->plane_fmt[1].sizeimage =
+ (pix_fmt_mp->width * pix_fmt_mp->height) / 2;
+ pix_fmt_mp->plane_fmt[1].bytesperline =
+ pix_fmt_mp->width;
+ }
+ }
+
+ for (i = 0; i < pix_fmt_mp->num_planes; i++)
+ memset(&(pix_fmt_mp->plane_fmt[i].reserved[0]), 0x0,
+ sizeof(pix_fmt_mp->plane_fmt[0].reserved));
+
+ pix_fmt_mp->flags = 0;
+ memset(&pix_fmt_mp->reserved, 0x0, sizeof(pix_fmt_mp->reserved));
+ return 0;
+}
+
+static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct aml_video_fmt *fmt = NULL;
+ struct aml_vcodec_ctx *ctx = fh_to_ctx(priv);
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT,
+ "%s, type: %u, planes: %u, fmt: %u\n",
+ __func__, f->type, f->fmt.pix_mp.num_planes,
+ f->fmt.pix_mp.pixelformat);
+
+ fmt = aml_vdec_find_format(f);
+ if (!fmt)
+ return -EINVAL;
+
+ return vidioc_try_fmt(f, fmt);
+}
+
+static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+ struct aml_video_fmt *fmt = NULL;
+ struct aml_vcodec_ctx *ctx = fh_to_ctx(priv);
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT,
+ "%s, type: %u, planes: %u, fmt: %u\n",
+ __func__, f->type, f->fmt.pix_mp.num_planes,
+ f->fmt.pix_mp.pixelformat);
+
+ fmt = aml_vdec_find_format(f);
+ if (!fmt)
+ return -EINVAL;
+
+ if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) {
+ v4l_dbg(0, V4L_DEBUG_CODEC_ERROR,
+ "sizeimage of output format must be given\n");
+ return -EINVAL;
+ }
+
+ return vidioc_try_fmt(f, fmt);
+}
+
+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;
+
+ if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE))
+ return -EINVAL;
+
+ q_data = &ctx->q_data[AML_Q_DATA_DST];
+
+ switch (s->target) {
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ case V4L2_SEL_TGT_COMPOSE:
+ if (vdec_if_get_param(ctx, GET_PARAM_CROP_INFO, &(s->r))) {
+ /* set to default value if header info not ready yet*/
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = q_data->visible_width;
+ s->r.height = q_data->visible_height;
+ }
+ break;
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = ctx->picinfo.coded_width;
+ s->r.height = ctx->picinfo.coded_height;
+ 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);
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s, type: %d\n",
+ __func__, s->type);
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ switch (s->target) {
+ case V4L2_SEL_TGT_COMPOSE:
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = ctx->picinfo.visible_width;
+ s->r.height = ctx->picinfo.visible_height;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void copy_v4l2_format_dimention(struct v4l2_pix_format_mplane *pix_mp,
+ struct aml_q_data *q_data, u32 type)
+{
+ if (!pix_mp || !q_data)
+ return;
+
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ pix_mp->width = q_data->visible_width;
+ pix_mp->height = q_data->visible_height;
+ } else {
+ /*
+ * Width and height are set to the dimensions
+ * of the movie, the buffer is bigger and
+ * further processing stages should crop to this
+ * rectangle.
+ */
+ pix_mp->width = q_data->coded_width;
+ pix_mp->height = q_data->coded_height;
+ }
+
+ /*
+ * Set pixelformat to the format in which mt vcodec
+ * outputs the decoded frame
+ */
+ pix_mp->num_planes = q_data->fmt->num_planes;
+ pix_mp->pixelformat = q_data->fmt->fourcc;
+ pix_mp->plane_fmt[0].bytesperline = q_data->bytesperline[0];
+ pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage[0];
+ if (type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ pix_mp->plane_fmt[1].bytesperline = q_data->bytesperline[1];
+ pix_mp->plane_fmt[1].sizeimage = q_data->sizeimage[1];
+ }
+}
+
+static int vidioc_vdec_s_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct aml_vcodec_ctx *ctx = fh_to_ctx(priv);
+ struct v4l2_pix_format_mplane *pix_mp;
+ struct aml_q_data *q_data;
+ int ret = 0;
+ struct aml_video_fmt *fmt;
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT,
+ "%s, type: %u, planes: %u, fmt: %u\n",
+ __func__, f->type, f->fmt.pix_mp.num_planes,
+ f->fmt.pix_mp.pixelformat);
+
+ q_data = aml_vdec_get_q_data(ctx, f->type);
+ if (!q_data)
+ return -EINVAL;
+
+ pix_mp = &f->fmt.pix_mp;
+ if ((f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) &&
+ vb2_is_busy(&ctx->m2m_ctx->out_q_ctx.q)) {
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR,
+ "out_q_ctx buffers already requested\n");
+ }
+
+ 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");
+ }
+
+ fmt = aml_vdec_find_format(f);
+ if (fmt == NULL) {
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ f->fmt.pix.pixelformat =
+ aml_video_formats[OUT_FMT_IDX].fourcc;
+ fmt = aml_vdec_find_format(f);
+ } else if (!V4L2_TYPE_IS_OUTPUT(f->type)) {
+ f->fmt.pix.pixelformat =
+ aml_video_formats[CAP_FMT_IDX].fourcc;
+ fmt = aml_vdec_find_format(f);
+ }
+ }
+
+ q_data->fmt = fmt;
+ vidioc_try_fmt(f, q_data->fmt);
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ if (ctx->is_drm_mode)
+ pix_mp->plane_fmt[0].sizeimage = 1;
+ q_data->sizeimage[0] = pix_mp->plane_fmt[0].sizeimage;
+ q_data->coded_width = pix_mp->width;
+ q_data->coded_height = pix_mp->height;
+
+ 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->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("v4l2_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 = pix_mp->pixelformat;
+ if (ctx->state >= AML_STATE_PROBE)
+ copy_v4l2_format_dimention(pix_mp, q_data, f->type);
+ }
+
+ 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, j = 0;
+
+ for (i = 0; i < NUM_FORMATS; i++) {
+ if (output_queue && (aml_video_formats[i].type != AML_FMT_DEC))
+ continue;
+ if (!output_queue && (aml_video_formats[i].type != AML_FMT_FRAME))
+ continue;
+
+ if (j == f->index) {
+ fmt = &aml_video_formats[i];
+ 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 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;
+ }
+
+ 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");
+ }
+
+ 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)) {
+ /* Until STREAMOFF is called on the CAPTURE queue
+ * (acknowledging the event), the driver operates as if
+ * the resolution hasn't changed yet.
+ * So we just return picinfo yet, and update picinfo in
+ * stop_streaming hook function
+ */
+ /* it is used for alloc the decode buffer size. */
+ q_data->sizeimage[0] = ctx->picinfo.y_len_sz;
+ q_data->sizeimage[1] = ctx->picinfo.c_len_sz;
+
+ /* it is used for alloc the EGL image buffer size. */
+ q_data->coded_width = ctx->picinfo.coded_width;
+ q_data->coded_height = ctx->picinfo.coded_height;
+
+ q_data->bytesperline[0] = ctx->picinfo.coded_width;
+ q_data->bytesperline[1] = ctx->picinfo.coded_width;
+
+ copy_v4l2_format_dimention(pix_mp, q_data, f->type);
+ } 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, q_data, f->type);
+ } else {
+ copy_v4l2_format_dimention(pix_mp, q_data, f->type);
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO,
+ "type=%d state=%d Format information could not be read, not ready yet!\n",
+ f->type, ctx->state);
+ return -EINVAL;
+ }
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT,
+ "%s, type: %u, planes: %u, fmt: %u\n",
+ __func__, f->type, f->fmt.pix_mp.num_planes,
+ f->fmt.pix_mp.pixelformat);
+
+ 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;
+ alloc_devs[i] = v4l_get_dev_from_codec_mm();//alloc mm from the codec mm
+ }
+ } else {
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ *nplanes = 2;
+ else
+ *nplanes = 1;
+
+ for (i = 0; i < *nplanes; i++) {
+ sizes[i] = q_data->sizeimage[i];
+ if (V4L2_TYPE_IS_OUTPUT(vq->type) && ctx->output_dma_mode)
+ sizes[i] = 0;
+ //alloc_devs[i] = &ctx->dev->plat_dev->dev;
+ alloc_devs[i] = v4l_get_dev_from_codec_mm();//alloc mm from the codec mm
+ }
+ }
+
+ 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;
+ 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]);
+ }
+ }
+
+ return 0;
+}
+
+static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb)
+{
+ struct aml_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vb2_v4l2 = NULL;
+ struct aml_video_dec_buf *buf = NULL;
+ struct aml_vcodec_mem src_mem;
+ unsigned int dpb = 0;
+
+ vb2_v4l2 = to_vb2_v4l2_buffer(vb);
+ buf = container_of(vb2_v4l2, struct aml_video_dec_buf, vb);
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT,
+ "%s, vb: %lx, type: %d, idx: %d, state: %d, used: %d, ts: %llu\n",
+ __func__, (ulong) vb, vb->vb2_queue->type,
+ vb->index, vb->state, buf->used, vb->timestamp);
+ /*
+ * check if this buffer is ready to be used after decode
+ */
+ if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
+ if (vb->index >= ctx->dpb_size) {
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR,
+ "enque capture buf idx %d/%d is invalid.\n",
+ vb->index, ctx->dpb_size);
+ return;
+ }
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO,
+ "y_addr: %lx, vf_h: %lx, state: %d",
+ buf->frame_buffer.m.mem[0].addr,
+ buf->frame_buffer.vf_handle,
+ buf->frame_buffer.status);
+
+ if (!buf->que_in_m2m) {
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR,
+ "enque capture buf idx %d, vf: %lx\n",
+ vb->index, (ulong) v4l_get_vf_handle(vb2_v4l2->private));
+
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2);
+ buf->que_in_m2m = true;
+ buf->queued_in_vb2 = true;
+ buf->queued_in_v4l2 = true;
+ buf->ready_to_display = false;
+ ctx->cap_pool.seq[ctx->cap_pool.in++] =
+ (V4L_CAP_BUFF_IN_M2M << 16 | vb->index);
+
+ /* check dpb ready */
+ aml_check_dpb_ready(ctx);
+ } else if (buf->frame_buffer.status == FB_ST_DISPLAY) {
+ buf->queued_in_vb2 = false;
+ buf->queued_in_v4l2 = true;
+ buf->ready_to_display = false;
+
+ /* recycle vf */
+ video_vf_put(ctx->ada_ctx->recv_name,
+ &buf->frame_buffer, ctx->id);
+ }
+ return;
+ }
+
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb));
+
+ if (ctx->state != AML_STATE_INIT) {
+ return;
+ }
+
+ 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");
+ v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+ return;
+ }
+
+ src_mem.index = vb->index;
+ src_mem.vaddr = vb2_plane_vaddr(vb, 0);
+ src_mem.addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+ src_mem.size = vb->planes[0].bytesused;
+ src_mem.model = vb->memory;
+ src_mem.timestamp = vb->timestamp;
+
+ if (vdec_if_probe(ctx, &src_mem, NULL)) {
+ v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+
+ if (!(ctx->is_drm_mode && src_mem.model == VB2_MEMORY_DMABUF))
+ v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_DONE);
+ return;
+ }
+
+ /*
+ * If on model dmabuf must remove the buffer
+ * because this data has been consumed by hw.
+ */
+ if (ctx->is_drm_mode && src_mem.model == VB2_MEMORY_DMABUF) {
+ v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+ } else if (ctx->param_sets_from_ucode) {
+ v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+ v4l2_m2m_buf_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 (vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpb)) {
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR,
+ "GET_PARAM_DPB_SIZE err\n");
+ return;
+ }
+
+ if (!dpb)
+ return;
+
+ ctx->dpb_size = dpb;
+ ctx->last_decoded_picinfo = ctx->picinfo;
+ aml_vdec_dispatch_event(ctx, V4L2_EVENT_SRC_CH_RESOLUTION);
+
+ mutex_lock(&ctx->state_lock);
+ if (ctx->state == AML_STATE_INIT) {
+ ctx->state = AML_STATE_PROBE;
+ ATRACE_COUNTER("v4l2_state", ctx->state);
+ 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;
+ bool buf_error;
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT,
+ "%s, type: %d, idx: %d\n",
+ __func__, vb->vb2_queue->type, vb->index);
+
+ vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
+ buf = container_of(vb2_v4l2, struct aml_video_dec_buf, vb);
+
+ if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
+ buf->queued_in_v4l2 = false;
+ buf->queued_in_vb2 = false;
+ }
+ buf_error = buf->error;
+
+ if (buf_error) {
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR,
+ "Unrecoverable error on buffer.\n");
+ ctx->state = AML_STATE_ABORT;
+ ATRACE_COUNTER("v4l2_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);
+ unsigned int size, phy_addr = 0;
+ char *owner = __getname();
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s, type: %d, idx: %d\n",
+ __func__, vb->vb2_queue->type, vb->index);
+
+ if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
+ buf->used = false;
+ buf->ready_to_display = false;
+ buf->queued_in_v4l2 = false;
+ buf->frame_buffer.status = FB_ST_NORMAL;
+ } else {
+ buf->lastframe = false;
+ }
+
+ /* codec_mm buffers count */
+ if (V4L2_TYPE_IS_OUTPUT(vb->type)) {
+ if (vb->memory == VB2_MEMORY_MMAP) {
+ size = vb->planes[0].length;
+ phy_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+ snprintf(owner, PATH_MAX, "%s-%d", "v4l-input", ctx->id);
+ strncpy(buf->mem_onwer, owner, sizeof(buf->mem_onwer));
+ buf->mem_onwer[sizeof(buf->mem_onwer) - 1] = '\0';
+
+ buf->mem[0] = v4l_reqbufs_from_codec_mm(buf->mem_onwer,
+ phy_addr, size, vb->index);
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR,
+ "IN alloc, addr: %x, size: %u, idx: %u\n",
+ phy_addr, size, vb->index);
+ }
+ } else {
+ snprintf(owner, PATH_MAX, "%s-%d", "v4l-output", ctx->id);
+ strncpy(buf->mem_onwer, owner, sizeof(buf->mem_onwer));
+ buf->mem_onwer[sizeof(buf->mem_onwer) - 1] = '\0';
+
+ if ((vb->memory == VB2_MEMORY_MMAP) && (vb->num_planes == 1)) {
+ size = vb->planes[0].length;
+ phy_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+ buf->mem[0] = v4l_reqbufs_from_codec_mm(buf->mem_onwer,
+ phy_addr, size, vb->index);
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR,
+ "OUT Y alloc, addr: %x, size: %u, idx: %u\n",
+ phy_addr, size, vb->index);
+ } else if ((vb->memory == VB2_MEMORY_MMAP) && (vb->num_planes == 2)) {
+ size = vb->planes[0].length;
+ phy_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+ buf->mem[0] = v4l_reqbufs_from_codec_mm(buf->mem_onwer,
+ phy_addr, size, vb->index);
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR,
+ "OUT Y alloc, addr: %x, size: %u, idx: %u\n",
+ phy_addr, size, vb->index);
+
+ size = vb->planes[1].length;
+ phy_addr = vb2_dma_contig_plane_dma_addr(vb, 1);
+ buf->mem[1] = v4l_reqbufs_from_codec_mm(buf->mem_onwer,
+ phy_addr, size, vb->index);
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR,
+ "OUT C alloc, addr: %x, size: %u, idx: %u\n",
+ phy_addr, size, vb->index);
+ }
+ }
+
+ __putname(owner);
+
+ return 0;
+}
+
+static void codec_mm_bufs_cnt_clean(struct vb2_queue *q)
+{
+ struct aml_vcodec_ctx *ctx = vb2_get_drv_priv(q);
+ struct vb2_v4l2_buffer *vb2_v4l2 = NULL;
+ struct aml_video_dec_buf *buf = NULL;
+ int i;
+
+ for (i = 0; i < q->num_buffers; ++i) {
+ vb2_v4l2 = to_vb2_v4l2_buffer(q->bufs[i]);
+ buf = container_of(vb2_v4l2, struct aml_video_dec_buf, vb);
+ if (IS_ERR_OR_NULL(buf->mem[0]))
+ return;
+
+ if (V4L2_TYPE_IS_OUTPUT(q->bufs[i]->type)) {
+ v4l_freebufs_back_to_codec_mm(buf->mem_onwer, buf->mem[0]);
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR,
+ "IN clean, addr: %lx, size: %u, idx: %u\n",
+ buf->mem[0]->phy_addr, buf->mem[0]->buffer_size, i);
+ buf->mem[0] = NULL;
+ continue;
+ }
+
+ if (q->memory == VB2_MEMORY_MMAP) {
+ v4l_freebufs_back_to_codec_mm(buf->mem_onwer, buf->mem[0]);
+ v4l_freebufs_back_to_codec_mm(buf->mem_onwer, buf->mem[1]);
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR,
+ "OUT Y clean, addr: %lx, size: %u, idx: %u\n",
+ buf->mem[0]->phy_addr, buf->mem[0]->buffer_size, i);
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR,
+ "OUT C clean, addr: %lx, size: %u, idx: %u\n",
+ buf->mem[1]->phy_addr, buf->mem[1]->buffer_size, i);
+ buf->mem[0] = NULL;
+ buf->mem[1] = NULL;
+ }
+ }
+}
+
+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;
+
+ 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);
+
+ codec_mm_bufs_cnt_clean(q);
+
+ if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+ while ((vb2_v4l2 = v4l2_m2m_src_buf_remove(ctx->m2m_ctx)))
+ v4l2_m2m_buf_done(vb2_v4l2, VB2_BUF_STATE_ERROR);
+
+ for (i = 0; i < q->num_buffers; ++i) {
+ vb2_v4l2 = to_vb2_v4l2_buffer(q->bufs[i]);
+ if (vb2_v4l2->vb2_buf.state == VB2_BUF_STATE_ACTIVE)
+ v4l2_m2m_buf_done(vb2_v4l2, VB2_BUF_STATE_ERROR);
+ }
+ } else {
+ /* clean output cache and decoder status . */
+ if (ctx->state > AML_STATE_INIT)
+ aml_vdec_reset(ctx);
+
+ while ((vb2_v4l2 = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx)))
+ v4l2_m2m_buf_done(vb2_v4l2, VB2_BUF_STATE_ERROR);
+
+ for (i = 0; i < q->num_buffers; ++i) {
+ vb2_v4l2 = to_vb2_v4l2_buffer(q->bufs[i]);
+ buf = container_of(vb2_v4l2, struct aml_video_dec_buf, vb);
+ buf->frame_buffer.status = FB_ST_NORMAL;
+ buf->que_in_m2m = false;
+ buf->vb.flags = 0;
+ ctx->cap_pool.seq[i] = 0;
+
+ if (vb2_v4l2->vb2_buf.state == VB2_BUF_STATE_ACTIVE)
+ v4l2_m2m_buf_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);*/
+ }
+
+ 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);
+}
+
+void vdec_device_vf_run(struct aml_vcodec_ctx *ctx)
+{
+ if (ctx->state < AML_STATE_INIT ||
+ ctx->state > AML_STATE_FLUSHED)
+ return;
+
+ aml_thread_notify(ctx, AML_THREAD_CAPTURE);
+}
+
+static int m2mops_vdec_job_ready(void *m2m_priv)
+{
+ struct aml_vcodec_ctx *ctx = m2m_priv;
+
+ 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->dpb_size;
+ } else {
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR,
+ "Seqinfo not ready.\n");
+ ctrl->val = 0;
+ ret = -EINVAL;
+ }
+ break;
+ case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:
+ ctrl->val = 4;
+ break;
+ 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);
+ }
+
+ 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,
+};
+
+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);
+ ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+ if (ctx->ctrl_hdl.error) {
+ ret = ctx->ctrl_hdl.error;
+ goto err;
+ }
+
+ ctrl = v4l2_ctrl_new_std(&ctx->ctrl_hdl,
+ &aml_vcodec_dec_ctrl_ops,
+ V4L2_CID_MIN_BUFFERS_FOR_OUTPUT,
+ 0, 32, 1, 8);
+ ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+ if (ctx->ctrl_hdl.error) {
+ ret = ctx->ctrl_hdl.error;
+ goto err;
+ }
+
+ ctrl = v4l2_ctrl_new_custom(&ctx->ctrl_hdl, &ctrl_st_mode, NULL);
+ if (ctx->ctrl_hdl.error) {
+ 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);
+
+ if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ if (vdec_if_get_param(ctx, GET_PARAM_CONFIG_INFO,
+ &ctx->config.parm.dec)) {
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR,
+ "GET_PARAM_CONFIG_INFO err\n");
+ return -1;
+ }
+ memcpy(a->parm.raw_data, ctx->config.parm.data,
+ sizeof(a->parm.raw_data));
+ }
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s\n", __func__);
+
+ 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);
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s\n", __func__);
+
+ if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ 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)
+ 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;
+ }
+
+ return 0;
+}
+
+static void m2mops_vdec_lock(void *m2m_priv)
+{
+ struct aml_vcodec_ctx *ctx = m2m_priv;
+
+ mutex_lock(&ctx->dev->dev_mutex);
+}
+
+static void m2mops_vdec_unlock(void *m2m_priv)
+{
+ struct aml_vcodec_ctx *ctx = m2m_priv;
+
+ mutex_unlock(&ctx->dev->dev_mutex);
+}
+
+const struct v4l2_m2m_ops aml_vdec_m2m_ops = {
+ .device_run = m2mops_vdec_device_run,
+ .job_ready = m2mops_vdec_job_ready,
+ .job_abort = m2mops_vdec_job_abort,
+ .lock = m2mops_vdec_lock,
+ .unlock = m2mops_vdec_unlock,
+};
+
+static const struct vb2_ops aml_vdec_vb2_ops = {
+ .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_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_mplane,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap_mplane,
+ .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out_mplane,
+ .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out_mplane,
+
+ .vidioc_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,
+
+ .vidioc_enum_fmt_vid_cap_mplane = vidioc_vdec_enum_fmt_vid_cap_mplane,
+ .vidioc_enum_fmt_vid_cap = vidioc_vdec_enum_fmt_vid_cap_mplane,
+ .vidioc_enum_fmt_vid_out_mplane = vidioc_vdec_enum_fmt_vid_out_mplane,
+ .vidioc_enum_fmt_vid_out = vidioc_vdec_enum_fmt_vid_out_mplane,
+ .vidioc_enum_framesizes = vidioc_enum_framesizes,
+
+ .vidioc_querycap = vidioc_vdec_querycap,
+ .vidioc_subscribe_event = vidioc_vdec_subscribe_evt,
+ .vidioc_unsubscribe_event = vidioc_vdec_event_unsubscribe,
+ .vidioc_g_selection = vidioc_vdec_g_selection,
+ .vidioc_s_selection = vidioc_vdec_s_selection,
+
+ .vidioc_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;
+ src_vq->drv_priv = ctx;
+ src_vq->buf_struct_size = sizeof(struct aml_video_dec_buf);
+ src_vq->ops = &aml_vdec_vb2_ops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->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;
+ 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..3653ff0
--- /dev/null
+++ b/drivers/amvdec_ports/aml_vcodec_dec.h
@@ -0,0 +1,126 @@
+/*
+* 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 <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"
+
+#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
+
+/**
+ * struct vdec_fb - decoder frame buffer
+ * @mem_type : gather or scatter memory.
+ * @num_planes : used number of the plane
+ * @mem[4] : array mem for used planes,
+ * mem[0]: Y, mem[1]: C/U, mem[2]: V
+ * @vf_fd : the file handle of video frame
+ * @vf_handle : video frame handle
+ * @status : frame buffer status (vdec_fb_status)
+ */
+
+struct vdec_v4l2_buffer {
+ int mem_type;
+ int num_planes;
+ union {
+ struct aml_vcodec_mem mem[4];
+ u32 vf_fd;
+ } m;
+ ulong vf_handle;
+ u32 status;
+ u32 buf_idx;
+};
+
+
+/**
+ * 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
+ * @ready_to_display: Capture buffer not display yet
+ * @queued_in_vb2: Capture buffer is queue in vb2
+ * @queued_in_v4l2: Capture buffer is in v4l2 driver, but not in vb2
+ * queue yet
+ * @lastframe: Intput buffer is last buffer - EOS
+ * @error: An unrecoverable error occurs on this buffer.
+ * @frame_buffer: Decode status, and buffer information of Capture buffer
+ *
+ * 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 ready_to_display;
+ bool que_in_m2m;
+ bool queued_in_vb2;
+ bool queued_in_v4l2;
+ bool lastframe;
+ bool error;
+};
+
+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 vdec_device_vf_run(struct aml_vcodec_ctx *ctx);
+void try_to_capture(struct aml_vcodec_ctx *ctx);
+void aml_thread_notify(struct aml_vcodec_ctx *ctx,
+ enum aml_thread_type type);
+int aml_thread_start(struct aml_vcodec_ctx *ctx, aml_thread_func func,
+ enum aml_thread_type type, const char *thread_name);
+void aml_thread_stop(struct aml_vcodec_ctx *ctx);
+void wait_vcodec_ending(struct aml_vcodec_ctx *ctx);
+void vdec_frame_buffer_release(void *data);
+void aml_vdec_dispatch_event(struct aml_vcodec_ctx *ctx, u32 changes);
+void* v4l_get_vf_handle(int fd);
+
+#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..1ed0b97
--- /dev/null
+++ b/drivers/amvdec_ports/aml_vcodec_dec_drv.c
@@ -0,0 +1,635 @@
+/*
+* 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 "aml_vcodec_drv.h"
+#include "aml_vcodec_dec.h"
+#include "aml_vcodec_util.h"
+#include "aml_vcodec_vfm.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;
+
+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;
+ aml_buf = kzalloc(sizeof(*aml_buf), GFP_KERNEL);
+ if (!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);
+ dev->filp = file;
+ ctx->dev = dev;
+ init_waitqueue_head(&ctx->queue);
+ mutex_init(&ctx->state_lock);
+ mutex_init(&ctx->lock);
+ spin_lock_init(&ctx->slock);
+ init_completion(&ctx->comp);
+
+ 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;
+ aml_vcodec_dec_set_default_params(ctx);
+
+ ret = aml_thread_start(ctx, try_to_capture, 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 ret;
+
+ /* 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);
+ 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);
+
+ /*
+ * Call v4l2_m2m_ctx_release before aml_vcodec_dec_release. First, it
+ * makes sure the worker thread is not running after vdec_if_deinit.
+ * Second, the decoder will be flushed and all the buffers will be
+ * returned in stop_streaming.
+ */
+ aml_thread_stop(ctx);
+ wait_vcodec_ending(ctx);
+ v4l2_m2m_ctx_release(ctx->m2m_ctx);
+ aml_vcodec_dec_release(ctx);
+
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
+
+ list_del_init(&ctx->list);
+ kfree(ctx->empty_flush_buf);
+ kfree(ctx);
+ 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);
+ v4l_dbg(0, V4L_DEBUG_CODEC_ERROR,
+ "the buf file checked fail!\n");
+ 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 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;
+
+ 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) {
+ v4l_dbg(0, V4L_DEBUG_CODEC_ERROR,
+ "v4l2_device_register err=%d\n", ret);
+ goto err_res;
+ }
+
+ init_waitqueue_head(&dev->queue);
+
+ vfd_dec = video_device_alloc();
+ if (!vfd_dec) {
+ v4l_dbg(0, V4L_DEBUG_CODEC_ERROR,
+ "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)) {
+ v4l_dbg(0, V4L_DEBUG_CODEC_ERROR,
+ "Failed to init mem2mem dec device\n");
+ ret = PTR_ERR((__force void *)dev->m2m_dev_dec);
+ goto err_dec_mem_init;
+ }
+
+ dev->decode_workqueue =
+ alloc_ordered_workqueue(AML_VCODEC_DEC_NAME,
+ WQ_MEM_RECLAIM | WQ_FREEZABLE);
+ if (!dev->decode_workqueue) {
+ v4l_dbg(0, V4L_DEBUG_CODEC_ERROR,
+ "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) {
+ v4l_dbg(0, V4L_DEBUG_CODEC_ERROR,
+ "Failed to register video device\n");
+ goto err_dec_reg;
+ }
+
+ v4l_dbg(0, V4L_DEBUG_CODEC_PRINFO,
+ "decoder registered as /dev/video%d\n", vfd_dec->num);
+
+ return 0;
+
+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 const struct of_device_id aml_vcodec_match[] = {
+ {.compatible = "amlogic, vcodec-dec",},
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, aml_vcodec_match);
+
+static int aml_vcodec_dec_remove(struct platform_device *pdev)
+{
+ struct aml_vcodec_dev *dev = platform_get_drvdata(pdev);
+
+ flush_workqueue(dev->decode_workqueue);
+ destroy_workqueue(dev->decode_workqueue);
+
+ 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);
+
+ return 0;
+}
+
+/*static void aml_vcodec_dev_release(struct device *dev)
+{
+}*/
+
+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 struct platform_device aml_vcodec_dec_device = {
+ .name = AML_VCODEC_DEC_NAME,
+ .dev.release = aml_vcodec_dev_release,
+};*/
+
+module_platform_driver(aml_vcodec_dec_driver);
+
+/*
+static int __init amvdec_ports_init(void)
+{
+ int ret;
+
+ ret = platform_device_register(&aml_vcodec_dec_device);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&aml_vcodec_dec_driver);
+ if (ret)
+ platform_device_unregister(&aml_vcodec_dec_device);
+
+ return ret;
+}
+
+static void __exit amvdec_ports_exit(void)
+{
+ platform_driver_unregister(&aml_vcodec_dec_driver);
+ platform_device_unregister(&aml_vcodec_dec_device);
+}
+
+module_init(amvdec_ports_init);
+module_exit(amvdec_ports_exit);
+*/
+
+u32 debug_mode;
+EXPORT_SYMBOL(debug_mode);
+module_param(debug_mode, uint, 0644);
+
+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);
+
+bool dump_capture_frame;
+EXPORT_SYMBOL(dump_capture_frame);
+module_param(dump_capture_frame, bool, 0644);
+
+int dump_output_frame;
+EXPORT_SYMBOL(dump_output_frame);
+module_param(dump_output_frame, int, 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);
+
+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..2e9e576
--- /dev/null
+++ b/drivers/amvdec_ports/aml_vcodec_drv.h
@@ -0,0 +1,567 @@
+/*
+* 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/platform_device.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <linux/amlogic/media/vfm/vframe.h>
+#include "aml_vcodec_util.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)
+
+/* 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)
+
+/**
+ * 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_RESET - decoder has be reset after flush.
+ * @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_RESET,
+ 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;
+};
+
+/**
+ * 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 {
+ unsigned int visible_width;
+ unsigned int visible_height;
+ unsigned int coded_width;
+ unsigned int coded_height;
+ enum v4l2_field field;
+ unsigned int bytesperline[AML_VCODEC_MAX_PLANES];
+ unsigned int 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 {
+ unsigned int bitrate;
+ unsigned int num_b_frame;
+ unsigned int rc_frame;
+ unsigned int rc_mb;
+ unsigned int seq_hdr_mode;
+ unsigned int intra_period;
+ unsigned int gop_size;
+ unsigned int framerate_num;
+ unsigned int framerate_denom;
+ unsigned int h264_max_qp;
+ unsigned int h264_profile;
+ unsigned int h264_level;
+ unsigned int force_intra;
+};
+
+/**
+ * struct aml_vcodec_pm - Power management data structure
+ */
+struct aml_vcodec_pm {
+ struct clk *vdec_bus_clk_src;
+ struct clk *vencpll;
+
+ struct clk *vcodecpll;
+ struct clk *univpll_d2;
+ struct clk *clk_cci400_sel;
+ struct clk *vdecpll;
+ struct clk *vdec_sel;
+ struct clk *vencpll_d2;
+ struct clk *venc_sel;
+ struct clk *univpll1_d2;
+ struct clk *venc_lt_sel;
+ struct device *larbvdec;
+ struct device *larbvenc;
+ struct device *larbvenclt;
+ struct device *dev;
+ struct aml_vcodec_dev *amldev;
+};
+
+/**
+ * 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.
+ * @field: frame/field information.
+ */
+struct vdec_pic_info {
+ unsigned int visible_width;
+ unsigned int visible_height;
+ unsigned int coded_width;
+ unsigned int coded_height;
+ unsigned int y_bs_sz;
+ unsigned int c_bs_sz;
+ unsigned int y_len_sz;
+ unsigned int c_len_sz;
+ int profile_idc;
+ int ref_frame_count;
+ enum v4l2_field field;
+};
+
+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;
+};
+
+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 reorder_frames;
+ u32 field;
+};
+
+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;
+};
+
+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 aml_vcodec_ctx - Context (instance) private data.
+ *
+ * @id: index of the context that this structure describes.
+ * @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.
+ * @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.
+ * @empty_flush_buf: a fake size-0 capture buffer that indicates flush.
+ * @list: link to ctx_list of aml_vcodec_dev.
+ * @q_data: store information of input and output queue of the context.
+ * @queue: waitqueue that can be used to wait for this context to finish.
+ * @lock: protect the vdec thread.
+ * @state_lock: protect the codec status.
+ * @state: state of the context.
+ * @decode_work: decoder work be used to output buffer.
+ * @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
+ * @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.
+ */
+struct aml_vcodec_ctx {
+ int id;
+ enum aml_instance_type type;
+ struct aml_vcodec_dev *dev;
+ struct v4l2_m2m_ctx *m2m_ctx;
+ struct aml_vdec_adapt *ada_ctx;
+ const struct vdec_common_if *dec_if;
+ ulong drv_handle;
+ struct v4l2_fh fh;
+ struct v4l2_ctrl_handler ctrl_hdl;
+ spinlock_t slock;
+ struct aml_video_dec_buf *empty_flush_buf;
+ struct list_head list;
+
+ struct aml_q_data q_data[2];
+ wait_queue_head_t queue;
+ struct mutex lock, state_lock;
+ 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;
+ 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;
+
+ 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;
+};
+
+/**
+ * struct aml_vcodec_dev - driver data
+ * @v4l2_dev: V4L2 device to register video devices for.
+ * @vfd_dec: Video device for decoder
+ * @vfd_enc: Video device for encoder.
+ *
+ * @m2m_dev_dec: m2m device for decoder
+ * @m2m_dev_enc: m2m device for encoder.
+ * @plat_dev: platform device
+ * @vpu_plat_dev: aml vpu platform device
+ * @alloc_ctx: VB2 allocator context
+ * (for allocations without kernel mapping).
+ * @ctx_list: list of struct aml_vcodec_ctx
+ * @irqlock: protect data access by irq handler and work thread
+ * @curr_ctx: The context that is waiting for codec hardware
+ *
+ * @reg_base: Mapped address of AML Vcodec registers.
+ *
+ * @id_counter: used to identify current opened instance
+ *
+ * @encode_workqueue: encode work queue
+ *
+ * @int_cond: used to identify interrupt condition happen
+ * @int_type: used to identify what kind of interrupt condition happen
+ * @dev_mutex: video_device lock
+ * @queue: waitqueue for waiting for completion of device commands
+ *
+ * @dec_irq: decoder irq resource
+ * @enc_irq: h264 encoder irq resource
+ * @enc_lt_irq: vp8 encoder irq resource
+ *
+ * @dec_mutex: decoder hardware lock
+ * @enc_mutex: encoder hardware lock.
+ *
+ * @pm: power management control
+ * @dec_capability: used to identify decode capability, ex: 4k
+ * @enc_capability: used to identify encode capability
+ */
+struct aml_vcodec_dev {
+ struct v4l2_device v4l2_dev;
+ struct video_device *vfd_dec;
+ struct video_device *vfd_enc;
+ struct file *filp;
+
+ struct v4l2_m2m_dev *m2m_dev_dec;
+ struct v4l2_m2m_dev *m2m_dev_enc;
+ struct platform_device *plat_dev;
+ struct platform_device *vpu_plat_dev;//??
+ struct vb2_alloc_ctx *alloc_ctx;//??
+ struct list_head ctx_list;
+ spinlock_t irqlock;
+ struct aml_vcodec_ctx *curr_ctx;
+ void __iomem *reg_base[NUM_MAX_VCODEC_REG_BASE];
+
+ unsigned long id_counter;
+
+ struct workqueue_struct *decode_workqueue;
+ struct workqueue_struct *encode_workqueue;
+ int int_cond;
+ int int_type;
+ struct mutex dev_mutex;
+ wait_queue_head_t queue;
+
+ int dec_irq;
+ int enc_irq;
+ int enc_lt_irq;
+
+ struct mutex dec_mutex;
+ struct mutex enc_mutex;
+
+ struct aml_vcodec_pm pm;
+ unsigned int dec_capability;
+ unsigned int enc_capability;
+};
+
+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);
+}
+
+#endif /* _AML_VCODEC_DRV_H_ */
diff --git a/drivers/amvdec_ports/aml_vcodec_util.c b/drivers/amvdec_ports/aml_vcodec_util.c
new file mode 100644
index 0000000..509a42a
--- /dev/null
+++ b/drivers/amvdec_ports/aml_vcodec_util.c
@@ -0,0 +1,112 @@
+/*
+* 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 __iomem *aml_vcodec_get_reg_addr(struct aml_vcodec_ctx *data,
+ unsigned int reg_idx)
+{
+ struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)data;
+
+ if (!data || reg_idx >= NUM_MAX_VCODEC_REG_BASE) {
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR,
+ "Invalid arguments, reg_idx=%d\n", reg_idx);
+ return NULL;
+ }
+ return ctx->dev->reg_base[reg_idx];
+}
+EXPORT_SYMBOL(aml_vcodec_get_reg_addr);
+
+int aml_vcodec_mem_alloc(struct aml_vcodec_ctx *data,
+ struct aml_vcodec_mem *mem)
+{
+ unsigned long size = mem->size;
+ struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)data;
+ struct device *dev = &ctx->dev->plat_dev->dev;
+
+ mem->vaddr = dma_alloc_coherent(dev, size, &mem->dma_addr, GFP_KERNEL);
+ //mem->vaddr = codec_mm_dma_alloc_coherent(dev_name(dev), size,
+ // &mem->dma_addr, GFP_KERNEL, 0);
+ if (!mem->vaddr) {
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR,
+ "%s dma_alloc size=%ld failed!\n", dev_name(dev),
+ size);
+ return -ENOMEM;
+ }
+
+ memset(mem->vaddr, 0, size);
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "va: %p\n", mem->vaddr);
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "dma: 0x%lx\n", (ulong) mem->dma_addr);
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "size: 0x%lx\n", size);
+
+ return 0;
+}
+EXPORT_SYMBOL(aml_vcodec_mem_alloc);
+
+void aml_vcodec_mem_free(struct aml_vcodec_ctx *data,
+ struct aml_vcodec_mem *mem)
+{
+ unsigned long size = mem->size;
+ struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)data;
+ struct device *dev = &ctx->dev->plat_dev->dev;
+
+ if (!mem->vaddr) {
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR,
+ "%s dma_free size=%ld failed!\n", dev_name(dev),
+ size);
+ return;
+ }
+
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "va: %p\n", mem->vaddr);
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "dma: 0x%lx\n", (ulong) mem->dma_addr);
+ v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "size: 0x%lx\n", size);
+
+ dma_free_coherent(dev, size, mem->vaddr, mem->dma_addr);
+ mem->vaddr = NULL;
+ mem->dma_addr = 0;
+ mem->size = 0;
+}
+EXPORT_SYMBOL(aml_vcodec_mem_free);
+
+void aml_vcodec_set_curr_ctx(struct aml_vcodec_dev *dev,
+ struct aml_vcodec_ctx *ctx)
+{
+ 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..312ee40
--- /dev/null
+++ b/drivers/amvdec_ports/aml_vcodec_util.h
@@ -0,0 +1,105 @@
+/*
+* 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;
+ dma_addr_t dma_addr;
+ u32 model;
+};
+
+struct aml_vcodec_ctx;
+struct aml_vcodec_dev;
+
+extern u32 debug_mode;
+
+#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_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 __iomem *aml_vcodec_get_reg_addr(struct aml_vcodec_ctx *data,
+ unsigned int reg_idx);
+int aml_vcodec_mem_alloc(struct aml_vcodec_ctx *data,
+ struct aml_vcodec_mem *mem);
+void aml_vcodec_mem_free(struct aml_vcodec_ctx *data,
+ struct aml_vcodec_mem *mem);
+void aml_vcodec_set_curr_ctx(struct aml_vcodec_dev *dev,
+ struct aml_vcodec_ctx *ctx);
+struct aml_vcodec_ctx *aml_vcodec_get_curr_ctx(struct aml_vcodec_dev *dev);
+
+#endif /* _AML_VCODEC_UTIL_H_ */
diff --git a/drivers/amvdec_ports/aml_vcodec_vfm.c b/drivers/amvdec_ports/aml_vcodec_vfm.c
new file mode 100644
index 0000000..62896ea
--- /dev/null
+++ b/drivers/amvdec_ports/aml_vcodec_vfm.c
@@ -0,0 +1,245 @@
+/*
+* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc.,
+* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* Description:
+*/
+#include "aml_vcodec_vfm.h"
+#include "aml_vcodec_vfq.h"
+#include "aml_vcodec_util.h"
+#include "aml_vcodec_adapt.h"
+#include <media/v4l2-mem2mem.h>
+
+#define KERNEL_ATRACE_TAG KERNEL_ATRACE_TAG_VIDEO_COMPOSER
+#include <trace/events/meson_atrace.h>
+
+#define RECEIVER_NAME "v4l2-video"
+#define PROVIDER_NAME "v4l2-video"
+
+static struct vframe_s *vdec_vf_peek(void *op_arg)
+{
+ struct vcodec_vfm_s *vfm = (struct vcodec_vfm_s *)op_arg;
+
+ return vfq_peek(&vfm->vf_que);
+}
+
+static struct vframe_s *vdec_vf_get(void *op_arg)
+{
+ struct vcodec_vfm_s *vfm = (struct vcodec_vfm_s *)op_arg;
+
+ return vfq_pop(&vfm->vf_que);
+}
+
+static void vdec_vf_put(struct vframe_s *vf, void *op_arg)
+{
+ struct vcodec_vfm_s *vfm = (struct vcodec_vfm_s *)op_arg;
+
+ /* If the video frame from amvide that means */
+ /* the data has been processed and finished, */
+ /* then push back to VDA. thus we don't put the */
+ /* buffer to the decoder directly.*/
+
+ //vf_put(vf, vfm->recv_name);
+ //vf_notify_provider(vfm->recv_name, VFRAME_EVENT_RECEIVER_PUT, NULL);
+
+ if (vfq_level(&vfm->vf_que_recycle) > POOL_SIZE - 1) {
+ v4l_dbg(vfm->ctx, V4L_DEBUG_CODEC_ERROR, "vfq full.\n");
+ return;
+ }
+
+ atomic_set(&vf->use_cnt, 1);
+
+ vfq_push(&vfm->vf_que_recycle, vf);
+
+ /* schedule capture work. */
+ vdec_device_vf_run(vfm->ctx);
+}
+
+static int vdec_event_cb(int type, void *data, void *private_data)
+{
+
+ if (type & VFRAME_EVENT_RECEIVER_PUT) {
+ } else if (type & VFRAME_EVENT_RECEIVER_GET) {
+ } else if (type & VFRAME_EVENT_RECEIVER_FRAME_WAIT) {
+ }
+ return 0;
+}
+
+static int vdec_vf_states(struct vframe_states *states, void *op_arg)
+{
+ struct vcodec_vfm_s *vfm = (struct vcodec_vfm_s *)op_arg;
+
+ states->vf_pool_size = POOL_SIZE;
+ states->buf_recycle_num = 0;
+ states->buf_free_num = POOL_SIZE - vfq_level(&vfm->vf_que);
+ states->buf_avail_num = vfq_level(&vfm->vf_que);
+
+ return 0;
+}
+
+void video_vf_put(char *receiver, struct vdec_v4l2_buffer *fb, int id)
+{
+ struct vframe_provider_s *vfp = vf_get_provider(receiver);
+ struct vframe_s *vf = (struct vframe_s *)fb->vf_handle;
+
+ ATRACE_COUNTER("v4l2_to", vf->index_disp);
+
+ v4l_dbg(0, V4L_DEBUG_CODEC_OUTPUT,
+ "[%d]: TO (%s) vf: %p, idx: %d, "
+ "Y:(%lx, %u) C/U:(%lx, %u) V:(%lx, %u)\n",
+ id, vfp->name, vf, vf->index,
+ fb->m.mem[0].addr, fb->m.mem[0].size,
+ fb->m.mem[1].addr, fb->m.mem[1].size,
+ fb->m.mem[2].addr, fb->m.mem[2].size);
+
+ if (vfp && vf && atomic_dec_and_test(&vf->use_cnt))
+ vf_put(vf, receiver);
+}
+
+static const struct vframe_operations_s vf_provider = {
+ .peek = vdec_vf_peek,
+ .get = vdec_vf_get,
+ .put = vdec_vf_put,
+ .event_cb = vdec_event_cb,
+ .vf_states = vdec_vf_states,
+};
+
+static int video_receiver_event_fun(int type, void *data, void *private_data)
+{
+ int ret = 0;
+ struct vframe_states states;
+ struct vcodec_vfm_s *vfm = (struct vcodec_vfm_s *)private_data;
+
+ switch (type) {
+ case VFRAME_EVENT_PROVIDER_UNREG: {
+ if (vf_get_receiver(vfm->prov_name)) {
+ v4l_dbg(vfm->ctx, V4L_DEBUG_CODEC_EXINFO,
+ "unreg %s provider.\n",
+ vfm->prov_name);
+ vf_unreg_provider(&vfm->vf_prov);
+ }
+
+ break;
+ }
+
+ case VFRAME_EVENT_PROVIDER_START: {
+ if (vf_get_receiver(vfm->prov_name)) {
+ v4l_dbg(vfm->ctx, V4L_DEBUG_CODEC_EXINFO,
+ "reg %s provider.\n",
+ vfm->prov_name);
+ vf_provider_init(&vfm->vf_prov, vfm->prov_name,
+ &vf_provider, vfm);
+ vf_reg_provider(&vfm->vf_prov);
+ vf_notify_receiver(vfm->prov_name,
+ VFRAME_EVENT_PROVIDER_START, NULL);
+ }
+
+ vfq_init(&vfm->vf_que, POOL_SIZE + 1, &vfm->pool[0]);
+ vfq_init(&vfm->vf_que_recycle, POOL_SIZE + 1, &vfm->pool_recycle[0]);
+
+ break;
+ }
+
+ case VFRAME_EVENT_PROVIDER_QUREY_STATE: {
+ vdec_vf_states(&states, vfm);
+ if (states.buf_avail_num > 0)
+ ret = RECEIVER_ACTIVE;
+ break;
+ }
+
+ case VFRAME_EVENT_PROVIDER_VFRAME_READY: {
+ if (vfq_level(&vfm->vf_que) > POOL_SIZE - 1)
+ ret = -1;
+
+ if (!vf_peek(vfm->recv_name))
+ ret = -1;
+
+ vfm->vf = vf_get(vfm->recv_name);
+ if (!vfm->vf)
+ ret = -1;
+
+ if (ret < 0) {
+ v4l_dbg(vfm->ctx, V4L_DEBUG_CODEC_ERROR, "receiver vf err.\n");
+ break;
+ }
+
+ vfq_push(&vfm->vf_que, vfm->vf);
+
+ if (vfm->ada_ctx->vfm_path == FRAME_BASE_PATH_V4L_VIDEO) {
+ vf_notify_receiver(vfm->prov_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
+ break;
+ }
+
+ /* schedule capture work. */
+ vdec_device_vf_run(vfm->ctx);
+
+ break;
+ }
+
+ default:
+ v4l_dbg(vfm->ctx, V4L_DEBUG_CODEC_EXINFO,
+ "the vf event is %d", type);
+ }
+
+ return ret;
+}
+
+static const struct vframe_receiver_op_s vf_receiver = {
+ .event_cb = video_receiver_event_fun
+};
+
+struct vframe_s *peek_video_frame(struct vcodec_vfm_s *vfm)
+{
+ if (vfm->ada_ctx->vfm_path == FRAME_BASE_PATH_V4L_VIDEO)
+ return vfq_peek(&vfm->vf_que_recycle);
+ else
+ return vfq_peek(&vfm->vf_que);
+}
+
+struct vframe_s *get_video_frame(struct vcodec_vfm_s *vfm)
+{
+ if (vfm->ada_ctx->vfm_path == FRAME_BASE_PATH_V4L_VIDEO)
+ return vfq_pop(&vfm->vf_que_recycle);
+ else
+ return vfq_pop(&vfm->vf_que);
+}
+
+int vcodec_vfm_init(struct vcodec_vfm_s *vfm)
+{
+ int ret;
+
+ snprintf(vfm->recv_name, VF_NAME_SIZE, "%s-%d",
+ RECEIVER_NAME, vfm->ctx->id);
+ snprintf(vfm->prov_name, VF_NAME_SIZE, "%s-%d",
+ PROVIDER_NAME, vfm->ctx->id);
+
+ vfm->ada_ctx->recv_name = vfm->recv_name;
+
+ vf_receiver_init(&vfm->vf_recv, vfm->recv_name, &vf_receiver, vfm);
+ ret = vf_reg_receiver(&vfm->vf_recv);
+
+ vfm->vfm_initialized = ret ? false : true;
+
+ return ret;
+}
+
+void vcodec_vfm_release(struct vcodec_vfm_s *vfm)
+{
+ if (vfm->vfm_initialized)
+ vf_unreg_receiver(&vfm->vf_recv);
+}
+
diff --git a/drivers/amvdec_ports/aml_vcodec_vfm.h b/drivers/amvdec_ports/aml_vcodec_vfm.h
new file mode 100644
index 0000000..141e9a7
--- /dev/null
+++ b/drivers/amvdec_ports/aml_vcodec_vfm.h
@@ -0,0 +1,60 @@
+/*
+* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc.,
+* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* Description:
+*/
+#ifndef __AML_VCODEC_VFM_H_
+#define __AML_VCODEC_VFM_H_
+
+#include "aml_vcodec_vfq.h"
+#include "aml_vcodec_drv.h"
+#include "aml_vcodec_dec.h"
+#include <linux/amlogic/media/vfm/vframe_provider.h>
+#include <linux/amlogic/media/vfm/vframe_receiver.h>
+
+#define VF_NAME_SIZE (32)
+#define POOL_SIZE (32)
+
+struct vcodec_vfm_s {
+ struct aml_vcodec_ctx *ctx;
+ struct aml_vdec_adapt *ada_ctx;
+ struct vfq_s vf_que;
+ struct vfq_s vf_que_recycle;
+ struct vframe_s *vf;
+ struct vframe_s *pool[POOL_SIZE + 1];
+ struct vframe_s *pool_recycle[POOL_SIZE + 1];
+ char recv_name[VF_NAME_SIZE];
+ char prov_name[VF_NAME_SIZE];
+ struct vframe_provider_s vf_prov;
+ struct vframe_receiver_s vf_recv;
+ bool vfm_initialized;
+};
+
+int vcodec_vfm_init(struct vcodec_vfm_s *vfm);
+
+void vcodec_vfm_release(struct vcodec_vfm_s *vfm);
+
+struct vframe_s *peek_video_frame(struct vcodec_vfm_s *vfm);
+
+struct vframe_s *get_video_frame(struct vcodec_vfm_s *vfm);
+
+int get_fb_from_queue(struct aml_vcodec_ctx *ctx, struct vdec_v4l2_buffer **out_fb);
+int put_fb_to_queue(struct aml_vcodec_ctx *ctx, struct vdec_v4l2_buffer *in_fb);
+
+void video_vf_put(char *receiver, struct vdec_v4l2_buffer *fb, int id);
+
+#endif /* __AML_VCODEC_VFM_H_ */
diff --git a/drivers/amvdec_ports/aml_vcodec_vfq.h b/drivers/amvdec_ports/aml_vcodec_vfq.h
new file mode 100644
index 0000000..e19c53c
--- /dev/null
+++ b/drivers/amvdec_ports/aml_vcodec_vfq.h
@@ -0,0 +1,112 @@
+/*
+* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc.,
+* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* Description:
+*/
+#ifndef __AML_VCODEC_VFQ_H_
+#define __AML_VCODEC_VFQ_H_
+
+#include <linux/types.h>
+#include <asm/barrier.h>
+
+struct vfq_s {
+ int rp;
+ int wp;
+ int size;
+ int pre_rp;
+ int pre_wp;
+ struct vframe_s **pool;
+};
+
+static inline void vfq_lookup_start(struct vfq_s *q)
+{
+ q->pre_rp = q->rp;
+ q->pre_wp = q->wp;
+}
+static inline void vfq_lookup_end(struct vfq_s *q)
+{
+ q->rp = q->pre_rp;
+ q->wp = q->pre_wp;
+}
+
+static inline void vfq_init(struct vfq_s *q, u32 size, struct vframe_s **pool)
+{
+ q->rp = q->wp = 0;
+ q->size = size;
+ q->pool = pool;
+}
+
+static inline bool vfq_empty(struct vfq_s *q)
+{
+ return q->rp == q->wp;
+}
+
+static inline void vfq_push(struct vfq_s *q, struct vframe_s *vf)
+{
+ int wp = q->wp;
+
+ /*ToDo*/
+ smp_mb();
+
+ q->pool[wp] = vf;
+
+ /*ToDo*/
+ smp_wmb();
+
+ q->wp = (wp == (q->size - 1)) ? 0 : (wp + 1);
+}
+
+static inline struct vframe_s *vfq_pop(struct vfq_s *q)
+{
+ struct vframe_s *vf;
+ int rp;
+
+ if (vfq_empty(q))
+ return NULL;
+
+ rp = q->rp;
+
+ /*ToDo*/
+ smp_rmb();
+
+ vf = q->pool[rp];
+
+ /*ToDo*/
+ smp_mb();
+
+ q->rp = (rp == (q->size - 1)) ? 0 : (rp + 1);
+
+ return vf;
+}
+
+static inline struct vframe_s *vfq_peek(struct vfq_s *q)
+{
+ return (vfq_empty(q)) ? NULL : q->pool[q->rp];
+}
+
+static inline int vfq_level(struct vfq_s *q)
+{
+ int level = q->wp - q->rp;
+
+ if (level < 0)
+ level += q->size;
+
+ return level;
+}
+
+#endif /* __AML_VCODEC_VFQ_H_ */
+
diff --git a/drivers/amvdec_ports/decoder/aml_h264_parser.c b/drivers/amvdec_ports/decoder/aml_h264_parser.c
new file mode 100644
index 0000000..c9da299
--- /dev/null
+++ b/drivers/amvdec_ports/decoder/aml_h264_parser.c
@@ -0,0 +1,732 @@
+/*
+* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc.,
+* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* Description:
+*/
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#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..4ea76b9
--- /dev/null
+++ b/drivers/amvdec_ports/decoder/aml_hevc_parser.c
@@ -0,0 +1,1301 @@
+/*
+* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc.,
+* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* Description:
+*/
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#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..0c81cb5
--- /dev/null
+++ b/drivers/amvdec_ports/decoder/aml_hevc_parser.h
@@ -0,0 +1,563 @@
+/*
+ * 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..fd56755
--- /dev/null
+++ b/drivers/amvdec_ports/decoder/aml_mjpeg_parser.c
@@ -0,0 +1,416 @@
+/*
+* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc.,
+* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* Description:
+*/
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#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..bbc9282
--- /dev/null
+++ b/drivers/amvdec_ports/decoder/aml_mjpeg_parser.h
@@ -0,0 +1,186 @@
+/*
+ * drivers/amvdec_ports/decoder/aml_mjpeg_parser.h
+ *
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+#ifndef AML_MJPEG_PARSER_H
+#define AML_MJPEG_PARSER_H
+
+#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..2720446
--- /dev/null
+++ b/drivers/amvdec_ports/decoder/aml_mpeg12_parser.c
@@ -0,0 +1,217 @@
+/*
+* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc.,
+* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* Description:
+*/
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#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..8abbc78
--- /dev/null
+++ b/drivers/amvdec_ports/decoder/aml_mpeg12_parser.h
@@ -0,0 +1,98 @@
+/*
+ * drivers/amvdec_ports/decoder/aml_mpeg12_parser.h
+ *
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+#ifndef AML_MPEG12_PARSER_H
+#define AML_MPEG12_PARSER_H
+
+#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..f680b12
--- /dev/null
+++ b/drivers/amvdec_ports/decoder/aml_mpeg4_parser.c
@@ -0,0 +1,1250 @@
+/*
+* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc.,
+* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* Description:
+*/
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#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..3e5bf62
--- /dev/null
+++ b/drivers/amvdec_ports/decoder/aml_mpeg4_parser.h
@@ -0,0 +1,275 @@
+/*
+ * drivers/amvdec_ports/decoder/aml_mpeg4_parser.h
+ *
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+#ifndef AVCODEC_MPEG4VIDEO_H
+#define AVCODEC_MPEG4VIDEO_H
+
+#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..b027b8a
--- /dev/null
+++ b/drivers/amvdec_ports/decoder/aml_vp9_parser.c
@@ -0,0 +1,318 @@
+/*
+* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc.,
+* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* Description:
+*/
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#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..e8693d4
--- /dev/null
+++ b/drivers/amvdec_ports/decoder/vdec_av1_if.c
@@ -0,0 +1,1329 @@
+/*
+* 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_vcodec_vfm.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 vcodec_vfm_s vfm;
+ struct aml_dec_params parms;
+ struct completion comp;
+};
+
+/*!\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 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:11;");
+ pbuf += sprintf(pbuf, "av1_double_write_mode:3;");
+ pbuf += sprintf(pbuf, "av1_buf_width:1920;");
+ pbuf += sprintf(pbuf, "av1_buf_height:1088;");
+ pbuf += sprintf(pbuf, "av1_max_pic_w:8192;");
+ pbuf += sprintf(pbuf, "av1_max_pic_h:4608;");
+ pbuf += sprintf(pbuf, "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;
+
+ 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:%d;",
+ ctx->config.parm.dec.cfg.init_width);
+ pbuf += sprintf(pbuf, "av1_buf_height:%d;",
+ ctx->config.parm.dec.cfg.init_height);
+ pbuf += sprintf(pbuf, "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);
+ 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);
+ }
+
+ if ((ctx->config.parm.dec.parms_status &
+ V4L2_CONFIG_PARM_DECODE_HDRINFO) &&
+ inst->parms.hdr.color_parms.present_flag) {
+ u8 *pbuf = ctx->config.buf + ctx->config.length;
+
+ pbuf += sprintf(pbuf, "HDRStaticInfo:%d;", 1);
+ 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;
+ }
+
+ 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.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;
+
+ /* init vfm */
+ inst->vfm.ctx = ctx;
+ inst->vfm.ada_ctx = &inst->vdec;
+ ret = vcodec_vfm_init(&inst->vfm);
+ if (ret) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "init vfm failed.\n");
+ goto err;
+ }
+
+ /* probe info from the stream */
+ inst->vsi = kzalloc(sizeof(struct vdec_av1_vsi), GFP_KERNEL);
+ if (!inst->vsi) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /* alloc the header buffer to be used cache sps or spp etc.*/
+ inst->vsi->header_buf = kzalloc(HEADER_BUFFER_SIZE, GFP_KERNEL);
+ if (!inst->vsi->header_buf) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ init_completion(&inst->comp);
+
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO,
+ "av1 Instance >> %lx\n", (ulong) inst);
+
+ ctx->ada_ctx = &inst->vdec;
+ *h_vdec = (unsigned long)inst;
+
+ /* 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;
+ }
+
+ //dump_init();
+
+ return 0;
+err:
+ if (inst)
+ vcodec_vfm_release(&inst->vfm);
+ if (inst && inst->vsi && inst->vsi->header_buf)
+ kfree(inst->vsi->header_buf);
+ 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->dec.dpb_sz ? 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->dec.dpb_sz ? 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)
+{
+ ulong flags;
+ struct vdec_av1_inst *inst = (struct vdec_av1_inst *)h_vdec;
+ struct aml_vcodec_ctx *ctx = inst->ctx;
+
+ video_decoder_release(&inst->vdec);
+
+ vcodec_vfm_release(&inst->vfm);
+
+ //dump_deinit();
+
+ spin_lock_irqsave(&ctx->slock, flags);
+ if (inst->vsi && inst->vsi->header_buf)
+ kfree(inst->vsi->header_buf);
+
+ if (inst->vsi)
+ kfree(inst->vsi);
+
+ kfree(inst);
+
+ ctx->drv_handle = 0;
+ spin_unlock_irqrestore(&ctx->slock, flags);
+}
+
+static int vdec_av1_get_fb(struct vdec_av1_inst *inst, struct vdec_v4l2_buffer **out)
+{
+ return get_fb_from_queue(inst->ctx, out);
+}
+
+static void vdec_av1_get_vf(struct vdec_av1_inst *inst, struct vdec_v4l2_buffer **out)
+{
+ struct vframe_s *vf = NULL;
+ struct vdec_v4l2_buffer *fb = NULL;
+
+ vf = peek_video_frame(&inst->vfm);
+ if (!vf) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "there is no vframe.\n");
+ *out = NULL;
+ return;
+ }
+
+ vf = get_video_frame(&inst->vfm);
+ if (!vf) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "the vframe is avalid.\n");
+ *out = NULL;
+ return;
+ }
+
+ atomic_set(&vf->use_cnt, 1);
+
+ fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle;
+ fb->vf_handle = (unsigned long)vf;
+ fb->status = FB_ST_DISPLAY;
+
+ *out = fb;
+}
+
+// Returns 1 when OBU type is valid, and 0 otherwise.
+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 (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)
+{
+ int bit_buffer_byte_length;
+
+ if (!rb || !header)
+ return -1;
+
+ bit_buffer_byte_length = rb->bit_buffer_end - rb->bit_buffer;
+
+ 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);
+ else
+ ret = -1;
+
+ vfree(data);
+ } else {
+ ret = vdec_vframe_write(vdec, buf, size, ts);
+ }
+
+ 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;
+ u32 size;
+ int ret = -1;
+
+ if (bs == NULL)
+ return -1;
+
+ buf = (u8 *) bs->vaddr;
+ size = bs->size;
+
+ if (vdec_input_full(vdec)) {
+ ATRACE_COUNTER("vdec_input_full", 0);
+ return -EAGAIN;
+ }
+
+ 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);
+ } 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);
+ }
+ ATRACE_COUNTER("v4l2_decode_write", ret);
+
+ 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)
+ 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_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(0, V4L_DEBUG_CODEC_ERROR,
+ "the av1 inst of dec is invalid.\n");
+ return -1;
+ }
+
+ switch (type) {
+ case GET_PARAM_DISP_FRAME_BUFFER:
+ vdec_av1_get_vf(inst, out);
+ break;
+
+ case GET_PARAM_FREE_FRAME_BUFFER:
+ ret = vdec_av1_get_fb(inst, out);
+ break;
+
+ case GET_PARAM_PIC_INFO:
+ get_pic_info(inst, out);
+ break;
+
+ 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;
+
+ 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 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;
+
+ /* 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;
+
+ /* calc DPB size */
+ dec->dpb_sz = ps->dpb_size;
+
+ 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, crop(%d x %d), coded(%d x %d) dpb: %d\n",
+ ps->visible_width, ps->visible_height,
+ ps->coded_width, ps->coded_height,
+ ps->dpb_size);
+}
+
+static void set_param_hdr_info(struct vdec_av1_inst *inst,
+ struct aml_vdec_hdr_infos *hdr)
+{
+ if ((inst->parms.parms_status &
+ V4L2_CONFIG_PARM_DECODE_HDRINFO)) {
+ 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,
+ "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 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(0, 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_HDR_INFO:
+ set_param_hdr_info(inst, in);
+ break;
+
+ case SET_PARAM_POST_EVENT:
+ set_param_post_event(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..d13fc34
--- /dev/null
+++ b/drivers/amvdec_ports/decoder/vdec_h264_if.c
@@ -0,0 +1,1126 @@
+/*
+* 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_vcodec_vfm.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 vcodec_vfm_s vfm;
+ 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);
+ 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;
+ bool dec_init = false;
+
+ inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+ if (!inst)
+ return -ENOMEM;
+
+ inst->vdec.video_type = VFORMAT_H264;
+ inst->vdec.dev = ctx->dev->vpu_plat_dev;
+ inst->vdec.filp = ctx->dev->filp;
+ inst->vdec.ctx = ctx;
+ inst->ctx = ctx;
+
+ vdec_parser_parms(inst);
+
+ /* set play mode.*/
+ if (ctx->is_drm_mode)
+ inst->vdec.port.flag |= PORT_FLAG_DRM;
+
+ /* init vfm */
+ inst->vfm.ctx = ctx;
+ inst->vfm.ada_ctx = &inst->vdec;
+ ret = vcodec_vfm_init(&inst->vfm);
+ if (ret) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "init vfm failed.\n");
+ goto err;
+ }
+
+ ret = video_decoder_init(&inst->vdec);
+ if (ret) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "vdec_h264 init err=%d\n", ret);
+ goto err;
+ }
+ dec_init = true;
+
+ /* probe info from the stream */
+ inst->vsi = kzalloc(sizeof(struct vdec_h264_vsi), GFP_KERNEL);
+ if (!inst->vsi) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /* alloc the header buffer to be used cache sps or spp etc.*/
+ inst->vsi->header_buf = kzalloc(HEADER_BUFFER_SIZE, GFP_KERNEL);
+ if (!inst->vsi->header_buf) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ init_completion(&inst->comp);
+
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO,
+ "H264 Instance >> %lx", (ulong) inst);
+
+ ctx->ada_ctx = &inst->vdec;
+ *h_vdec = (unsigned long)inst;
+
+ //dump_init();
+
+ return 0;
+err:
+ if (dec_init)
+ video_decoder_release(&inst->vdec);
+ if (inst)
+ vcodec_vfm_release(&inst->vfm);
+ if (inst && inst->vsi && inst->vsi->header_buf)
+ kfree(inst->vsi->header_buf);
+ 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 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;
+ pic->ref_frame_count= sps->ref_frame_count;
+ /* 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.reorder_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);
+ 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->dec.dpb_sz ? 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->dec.dpb_sz ? 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)
+{
+ ulong flags;
+ struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec;
+ struct aml_vcodec_ctx *ctx = inst->ctx;
+
+ video_decoder_release(&inst->vdec);
+
+ vcodec_vfm_release(&inst->vfm);
+
+ //dump_deinit();
+
+ spin_lock_irqsave(&ctx->slock, flags);
+ if (inst->vsi && inst->vsi->header_buf)
+ kfree(inst->vsi->header_buf);
+
+ if (inst->vsi)
+ kfree(inst->vsi);
+
+ kfree(inst);
+
+ ctx->drv_handle = 0;
+ spin_unlock_irqrestore(&ctx->slock, flags);
+}
+
+static int vdec_h264_get_fb(struct vdec_h264_inst *inst, struct vdec_v4l2_buffer **out)
+{
+ return get_fb_from_queue(inst->ctx, out);
+}
+
+static void vdec_h264_get_vf(struct vdec_h264_inst *inst, struct vdec_v4l2_buffer **out)
+{
+ struct vframe_s *vf = NULL;
+ struct vdec_v4l2_buffer *fb = NULL;
+
+ vf = peek_video_frame(&inst->vfm);
+ if (!vf) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "there is no vframe.\n");
+ *out = NULL;
+ return;
+ }
+
+ vf = get_video_frame(&inst->vfm);
+ if (!vf) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "the vframe is avalid.\n");
+ *out = NULL;
+ return;
+ }
+
+ atomic_set(&vf->use_cnt, 1);
+
+ fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle;
+ if (fb) {
+ fb->vf_handle = (unsigned long)vf;
+ fb->status = FB_ST_DISPLAY;
+ }
+
+ *out = fb;
+
+ //pr_info("%s, %d\n", __func__, fb->base_y.bytes_used);
+ //dump_write(fb->base_y.vaddr, fb->base_y.bytes_used);
+ //dump_write(fb->base_c.vaddr, fb->base_c.bytes_used);
+
+ /* convert yuv format. */
+ //swap_uv(fb->base_c.vaddr, fb->base_c.size);
+}
+
+static int vdec_write_nalu(struct vdec_h264_inst *inst,
+ 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);
+ } 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);
+
+ 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) ||
+ (inst->vsi->pic.ref_frame_count !=
+ inst->vsi->cur_pic.ref_frame_count))) {
+ 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;
+ u32 size;
+ int ret = -1;
+
+ if (bs == NULL)
+ return -1;
+
+ buf = (u8 *) bs->vaddr;
+ size = bs->size;
+
+ 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);
+ } 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(0, V4L_DEBUG_CODEC_ERROR,
+ "the h264 inst of dec is invalid.\n");
+ return -1;
+ }
+
+ switch (type) {
+ case GET_PARAM_DISP_FRAME_BUFFER:
+ vdec_h264_get_vf(inst, out);
+ break;
+
+ case GET_PARAM_FREE_FRAME_BUFFER:
+ ret = vdec_h264_get_fb(inst, out);
+ break;
+
+ case GET_PARAM_PIC_INFO:
+ get_pic_info(inst, out);
+ break;
+
+ 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;
+ 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->ref_frame_count = ps->ref_frames;
+ pic->field = ps->field;
+ 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) dpb: %d, scan: %s\n",
+ ps->visible_width, ps->visible_height,
+ ps->coded_width, ps->coded_height,
+ dec->dpb_sz,
+ ps->field == V4L2_FIELD_NONE ? "P" : "I");
+}
+
+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_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(0, 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;
+ 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..2a41276
--- /dev/null
+++ b/drivers/amvdec_ports/decoder/vdec_hevc_if.c
@@ -0,0 +1,881 @@
+/*
+* 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_vcodec_vfm.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 vcodec_vfm_s vfm;
+ struct aml_dec_params parms;
+ struct completion comp;
+};
+
+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:16;");
+ 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);
+ 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_hevc_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec)
+{
+ struct vdec_hevc_inst *inst = NULL;
+ int ret = -1;
+ bool dec_init = false;
+
+ inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+ if (!inst)
+ return -ENOMEM;
+
+ inst->vdec.video_type = VFORMAT_HEVC;
+ inst->vdec.dev = ctx->dev->vpu_plat_dev;
+ inst->vdec.filp = ctx->dev->filp;
+ inst->vdec.ctx = ctx;
+ inst->ctx = ctx;
+
+ 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;
+
+ /* init vfm */
+ inst->vfm.ctx = ctx;
+ inst->vfm.ada_ctx = &inst->vdec;
+ ret = vcodec_vfm_init(&inst->vfm);
+ if (ret) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "init vfm failed.\n");
+ goto err;
+ }
+
+ ret = video_decoder_init(&inst->vdec);
+ if (ret) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "vdec_hevc init err=%d\n", ret);
+ goto err;
+ }
+ dec_init = true;
+
+ /* probe info from the stream */
+ inst->vsi = kzalloc(sizeof(struct vdec_hevc_vsi), GFP_KERNEL);
+ if (!inst->vsi) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /* alloc the header buffer to be used cache sps or spp etc.*/
+ inst->vsi->header_buf = kzalloc(HEADER_BUFFER_SIZE, GFP_KERNEL);
+ if (!inst->vsi->header_buf) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ init_completion(&inst->comp);
+
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO,
+ "hevc Instance >> %lx\n", (ulong) inst);
+
+ ctx->ada_ctx = &inst->vdec;
+ *h_vdec = (unsigned long)inst;
+
+ //dump_init();
+
+ return 0;
+err:
+ if (dec_init)
+ video_decoder_release(&inst->vdec);
+ if (inst)
+ vcodec_vfm_release(&inst->vfm);
+ if (inst && inst->vsi && inst->vsi->header_buf)
+ kfree(inst->vsi->header_buf);
+ 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->parms.cfg.init_width;
+ int h = inst->parms.cfg.init_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);
+ 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->dec.dpb_sz ? 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->dec.dpb_sz ? 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)
+{
+ ulong flags;
+ struct vdec_hevc_inst *inst = (struct vdec_hevc_inst *)h_vdec;
+ struct aml_vcodec_ctx *ctx = inst->ctx;
+
+ video_decoder_release(&inst->vdec);
+
+ vcodec_vfm_release(&inst->vfm);
+
+ //dump_deinit();
+
+ spin_lock_irqsave(&ctx->slock, flags);
+ if (inst->vsi && inst->vsi->header_buf)
+ kfree(inst->vsi->header_buf);
+
+ if (inst->vsi)
+ kfree(inst->vsi);
+
+ kfree(inst);
+
+ ctx->drv_handle = 0;
+ spin_unlock_irqrestore(&ctx->slock, flags);
+}
+
+static int vdec_hevc_get_fb(struct vdec_hevc_inst *inst, struct vdec_v4l2_buffer **out)
+{
+ return get_fb_from_queue(inst->ctx, out);
+}
+
+static void vdec_hevc_get_vf(struct vdec_hevc_inst *inst, struct vdec_v4l2_buffer **out)
+{
+ struct vframe_s *vf = NULL;
+ struct vdec_v4l2_buffer *fb = NULL;
+
+ vf = peek_video_frame(&inst->vfm);
+ if (!vf) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "there is no vframe.\n");
+ *out = NULL;
+ return;
+ }
+
+ vf = get_video_frame(&inst->vfm);
+ if (!vf) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "the vframe is avalid.\n");
+ *out = NULL;
+ return;
+ }
+
+ atomic_set(&vf->use_cnt, 1);
+
+ fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle;
+ fb->vf_handle = (unsigned long)vf;
+ fb->status = FB_ST_DISPLAY;
+
+ *out = fb;
+
+ //pr_info("%s, %d\n", __func__, fb->base_y.bytes_used);
+ //dump_write(fb->base_y.vaddr, fb->base_y.bytes_used);
+ //dump_write(fb->base_c.vaddr, fb->base_c.bytes_used);
+
+ /* convert yuv format. */
+ //swap_uv(fb->base_c.vaddr, fb->base_c.size);
+}
+
+static int vdec_write_nalu(struct vdec_hevc_inst *inst,
+ u8 *buf, u32 size, u64 ts)
+{
+ int ret = 0;
+ struct aml_vdec_adapt *vdec = &inst->vdec;
+
+ ret = vdec_vframe_write(vdec, buf, size, ts);
+
+ 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;
+ u32 size;
+ int ret = -1;
+
+ if (bs == NULL)
+ return -1;
+
+ buf = (u8 *) bs->vaddr;
+ size = bs->size;
+
+ 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);
+ } 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 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(0, V4L_DEBUG_CODEC_ERROR,
+ "the hevc inst of dec is invalid.\n");
+ return -1;
+ }
+
+ switch (type) {
+ case GET_PARAM_DISP_FRAME_BUFFER:
+ vdec_hevc_get_vf(inst, out);
+ break;
+
+ case GET_PARAM_FREE_FRAME_BUFFER:
+ ret = vdec_hevc_get_fb(inst, out);
+ break;
+
+ case GET_PARAM_PIC_INFO:
+ get_pic_info(inst, out);
+ break;
+
+ 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;
+ 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;
+
+ /* 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;
+
+ 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, crop(%d x %d), coded(%d x %d) dpb: %d, scan: %s\n",
+ pic->visible_width, pic->visible_height,
+ pic->coded_width, pic->coded_height,
+ dec->dpb_sz,
+ pic->field == V4L2_FIELD_NONE ? "P" : "I");
+}
+
+static void set_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 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(0, 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_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;
+ 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..f9816cc
--- /dev/null
+++ b/drivers/amvdec_ports/decoder/vdec_mjpeg_if.c
@@ -0,0 +1,668 @@
+/*
+* 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_vcodec_vfm.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 vcodec_vfm_s vfm;
+ 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;");
+
+ 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);
+ 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;
+ bool dec_init = false;
+
+ inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+ if (!inst)
+ return -ENOMEM;
+
+ inst->vdec.video_type = VFORMAT_MJPEG;
+ inst->vdec.dev = ctx->dev->vpu_plat_dev;
+ inst->vdec.filp = ctx->dev->filp;
+ inst->vdec.config = ctx->config;
+ inst->vdec.ctx = ctx;
+ 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;
+
+ /* init vfm */
+ inst->vfm.ctx = ctx;
+ inst->vfm.ada_ctx = &inst->vdec;
+ ret = vcodec_vfm_init(&inst->vfm);
+ if (ret) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "init vfm failed.\n");
+ goto err;
+ }
+
+ ret = video_decoder_init(&inst->vdec);
+ if (ret) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "vdec_mjpeg init err=%d\n", ret);
+ goto err;
+ }
+ dec_init = true;
+
+ /* probe info from the stream */
+ inst->vsi = kzalloc(sizeof(struct vdec_mjpeg_vsi), GFP_KERNEL);
+ if (!inst->vsi) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /* alloc the header buffer to be used cache sps or spp etc.*/
+ inst->vsi->header_buf = kzalloc(HEADER_BUFFER_SIZE, GFP_KERNEL);
+ if (!inst->vsi->header_buf) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO,
+ "mjpeg Instance >> %lx\n", (ulong) inst);
+
+ init_completion(&inst->comp);
+ ctx->ada_ctx = &inst->vdec;
+ *h_vdec = (unsigned long)inst;
+
+ //dump_init();
+
+ return 0;
+
+err:
+ if (dec_init)
+ video_decoder_release(&inst->vdec);
+ if (inst)
+ vcodec_vfm_release(&inst->vfm);
+ if (inst && inst->vsi && inst->vsi->header_buf)
+ kfree(inst->vsi->header_buf);
+ 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), 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_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);
+ 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->dec.dpb_sz ? 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->dec.dpb_sz ? 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);
+
+ vcodec_vfm_release(&inst->vfm);
+
+ //dump_deinit();
+
+ if (inst->vsi && inst->vsi->header_buf)
+ kfree(inst->vsi->header_buf);
+
+ if (inst->vsi)
+ kfree(inst->vsi);
+
+ kfree(inst);
+}
+
+static int vdec_mjpeg_get_fb(struct vdec_mjpeg_inst *inst, struct vdec_v4l2_buffer **out)
+{
+ return get_fb_from_queue(inst->ctx, out);
+}
+
+static void vdec_mjpeg_get_vf(struct vdec_mjpeg_inst *inst, struct vdec_v4l2_buffer **out)
+{
+ struct vframe_s *vf = NULL;
+ struct vdec_v4l2_buffer *fb = NULL;
+
+ vf = peek_video_frame(&inst->vfm);
+ if (!vf) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "there is no vframe.\n");
+ *out = NULL;
+ return;
+ }
+
+ vf = get_video_frame(&inst->vfm);
+ if (!vf) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "the vframe is avalid.\n");
+ *out = NULL;
+ return;
+ }
+
+ atomic_set(&vf->use_cnt, 1);
+
+ fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle;
+ fb->vf_handle = (unsigned long)vf;
+ fb->status = FB_ST_DISPLAY;
+
+ *out = fb;
+
+ //pr_info("%s, %d\n", __func__, fb->base_y.bytes_used);
+ //dump_write(fb->base_y.va, fb->base_y.bytes_used);
+ //dump_write(fb->base_c.va, fb->base_c.bytes_used);
+
+ /* convert yuv format. */
+ //swap_uv(fb->base_c.va, fb->base_c.size);
+}
+
+static int vdec_write_nalu(struct vdec_mjpeg_inst *inst,
+ u8 *buf, u32 size, u64 ts)
+{
+ int ret = 0;
+ struct aml_vdec_adapt *vdec = &inst->vdec;
+
+ ret = vdec_vframe_write(vdec, buf, size, ts);
+
+ 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);
+ } 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(0, V4L_DEBUG_CODEC_ERROR,
+ "the mjpeg inst of dec is invalid.\n");
+ return -1;
+ }
+
+ switch (type) {
+ case GET_PARAM_DISP_FRAME_BUFFER:
+ vdec_mjpeg_get_vf(inst, out);
+ break;
+
+ case GET_PARAM_FREE_FRAME_BUFFER:
+ ret = vdec_mjpeg_get_fb(inst, out);
+ break;
+
+ case GET_PARAM_PIC_INFO:
+ get_pic_info(inst, out);
+ break;
+
+ case GET_PARAM_DPB_SIZE:
+ get_dpb_size(inst, out);
+ break;
+
+ case GET_PARAM_CROP_INFO:
+ get_crop_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_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;
+
+ dec->dpb_sz = ps->dpb_size;
+
+ 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, crop(%d x %d), coded(%d x %d) dpb: %d\n",
+ ps->visible_width, ps->visible_height,
+ ps->coded_width, ps->coded_height,
+ dec->dpb_sz);
+}
+
+static void set_param_write_sync(struct vdec_mjpeg_inst *inst)
+{
+ complete(&inst->comp);
+}
+
+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(0, 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;
+
+ 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..9a38e71
--- /dev/null
+++ b/drivers/amvdec_ports/decoder/vdec_mpeg12_if.c
@@ -0,0 +1,656 @@
+/*
+* 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_vcodec_vfm.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 vcodec_vfm_s vfm;
+ 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);
+ 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;
+ bool dec_init = false;
+
+ inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+ if (!inst)
+ return -ENOMEM;
+
+ inst->vdec.video_type = VFORMAT_MPEG12;
+ inst->vdec.dev = ctx->dev->vpu_plat_dev;
+ inst->vdec.filp = ctx->dev->filp;
+ inst->vdec.config = ctx->config;
+ inst->vdec.ctx = ctx;
+ 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;
+
+ /* init vfm */
+ inst->vfm.ctx = ctx;
+ inst->vfm.ada_ctx = &inst->vdec;
+ ret = vcodec_vfm_init(&inst->vfm);
+ if (ret) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "init vfm failed.\n");
+ goto err;
+ }
+
+ ret = video_decoder_init(&inst->vdec);
+ if (ret) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "vdec_mpeg12 init err=%d\n", ret);
+ goto err;
+ }
+ dec_init = true;
+
+ /* probe info from the stream */
+ inst->vsi = kzalloc(sizeof(struct vdec_mpeg12_vsi), GFP_KERNEL);
+ if (!inst->vsi) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /* alloc the header buffer to be used cache sps or spp etc.*/
+ inst->vsi->header_buf = kzalloc(HEADER_BUFFER_SIZE, GFP_KERNEL);
+ if (!inst->vsi->header_buf) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO,
+ "mpeg12 Instance >> %lx\n", (ulong) inst);
+ init_completion(&inst->comp);
+ ctx->ada_ctx = &inst->vdec;
+ *h_vdec = (unsigned long)inst;
+
+ //dump_init();
+
+ return 0;
+
+err:
+ if (dec_init)
+ video_decoder_release(&inst->vdec);
+ if (inst)
+ vcodec_vfm_release(&inst->vfm);
+ if (inst && inst->vsi && inst->vsi->header_buf)
+ kfree(inst->vsi->header_buf);
+ 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);
+ 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->dec.dpb_sz ? 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->dec.dpb_sz ? 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);
+
+ vcodec_vfm_release(&inst->vfm);
+
+ //dump_deinit();
+
+ if (inst->vsi && inst->vsi->header_buf)
+ kfree(inst->vsi->header_buf);
+
+ if (inst->vsi)
+ kfree(inst->vsi);
+
+ kfree(inst);
+}
+
+static int vdec_mpeg12_get_fb(struct vdec_mpeg12_inst *inst, struct vdec_v4l2_buffer **out)
+{
+ return get_fb_from_queue(inst->ctx, out);
+}
+
+static void vdec_mpeg12_get_vf(struct vdec_mpeg12_inst *inst, struct vdec_v4l2_buffer **out)
+{
+ struct vframe_s *vf = NULL;
+ struct vdec_v4l2_buffer *fb = NULL;
+
+ vf = peek_video_frame(&inst->vfm);
+ if (!vf) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "there is no vframe.\n");
+ *out = NULL;
+ return;
+ }
+
+ vf = get_video_frame(&inst->vfm);
+ if (!vf) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "the vframe is avalid.\n");
+ *out = NULL;
+ return;
+ }
+
+ atomic_set(&vf->use_cnt, 1);
+
+ fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle;
+ fb->vf_handle = (unsigned long)vf;
+ fb->status = FB_ST_DISPLAY;
+
+ *out = fb;
+
+ //pr_info("%s, %d\n", __func__, fb->base_y.bytes_used);
+ //dump_write(fb->base_y.va, fb->base_y.bytes_used);
+ //dump_write(fb->base_c.va, fb->base_c.bytes_used);
+
+ /* convert yuv format. */
+ //swap_uv(fb->base_c.va, fb->base_c.size);
+}
+
+static int vdec_write_nalu(struct vdec_mpeg12_inst *inst,
+ u8 *buf, u32 size, u64 ts)
+{
+ int ret = 0;
+ struct aml_vdec_adapt *vdec = &inst->vdec;
+
+ ret = vdec_vframe_write(vdec, buf, size, ts);
+
+ 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);
+ } 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_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(0, V4L_DEBUG_CODEC_ERROR,
+ "the mpeg12 inst of dec is invalid.\n");
+ return -1;
+ }
+
+ switch (type) {
+ case GET_PARAM_DISP_FRAME_BUFFER:
+ vdec_mpeg12_get_vf(inst, out);
+ break;
+
+ case GET_PARAM_FREE_FRAME_BUFFER:
+ ret = vdec_mpeg12_get_fb(inst, out);
+ break;
+
+ case GET_PARAM_PIC_INFO:
+ get_pic_info(inst, out);
+ break;
+
+ case GET_PARAM_DPB_SIZE:
+ get_dpb_size(inst, out);
+ break;
+
+ case GET_PARAM_CROP_INFO:
+ get_crop_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_mpeg12_inst *inst)
+{
+ complete(&inst->comp);
+}
+
+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;
+
+ 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, crop(%d x %d), coded(%d x %d) dpb: %d scan: %s\n",
+ ps->visible_width, ps->visible_height,
+ ps->coded_width, ps->coded_height,
+ dec->dpb_sz,
+ pic->field == V4L2_FIELD_NONE ? "P" : "I");
+}
+
+static 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(0, 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_PS_INFO:
+ set_param_ps_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..c47bafc
--- /dev/null
+++ b/drivers/amvdec_ports/decoder/vdec_mpeg4_if.c
@@ -0,0 +1,667 @@
+/*
+* 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_vcodec_vfm.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 vcodec_vfm_s vfm;
+ 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);
+ 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;
+ bool dec_init = false;
+
+ inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+ if (!inst)
+ return -ENOMEM;
+
+ inst->vdec.video_type = VFORMAT_MPEG4;
+ inst->vdec.format = VIDEO_DEC_FORMAT_MPEG4_5;
+ inst->vdec.dev = ctx->dev->vpu_plat_dev;
+ inst->vdec.filp = ctx->dev->filp;
+ inst->vdec.config = ctx->config;
+ inst->vdec.ctx = ctx;
+ 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;
+
+ /* init vfm */
+ inst->vfm.ctx = ctx;
+ inst->vfm.ada_ctx = &inst->vdec;
+ ret = vcodec_vfm_init(&inst->vfm);
+ if (ret) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "init vfm failed.\n");
+ goto err;
+ }
+ dec_init = true;
+
+ ret = video_decoder_init(&inst->vdec);
+ if (ret) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "vdec_mpeg4 init err=%d\n", ret);
+ goto err;
+ }
+
+ /* probe info from the stream */
+ inst->vsi = kzalloc(sizeof(struct vdec_mpeg4_vsi), GFP_KERNEL);
+ if (!inst->vsi) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /* alloc the header buffer to be used cache sps or spp etc.*/
+ inst->vsi->header_buf = kzalloc(HEADER_BUFFER_SIZE, GFP_KERNEL);
+ if (!inst->vsi->header_buf) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO,
+ "mpeg4 Instance >> %lx\n", (ulong) inst);
+
+ init_completion(&inst->comp);
+ ctx->ada_ctx = &inst->vdec;
+ *h_vdec = (unsigned long)inst;
+
+ //dump_init();
+
+ return 0;
+
+err:
+ if (dec_init)
+ video_decoder_release(&inst->vdec);
+ if (inst)
+ vcodec_vfm_release(&inst->vfm);
+ if (inst && inst->vsi && inst->vsi->header_buf)
+ kfree(inst->vsi->header_buf);
+ 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);
+ 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->dec.dpb_sz ? 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->dec.dpb_sz ? 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);
+
+ vcodec_vfm_release(&inst->vfm);
+
+ //dump_deinit();
+
+ if (inst->vsi && inst->vsi->header_buf)
+ kfree(inst->vsi->header_buf);
+
+ if (inst->vsi)
+ kfree(inst->vsi);
+
+ kfree(inst);
+}
+
+static int vdec_mpeg4_get_fb(struct vdec_mpeg4_inst *inst, struct vdec_v4l2_buffer **out)
+{
+ return get_fb_from_queue(inst->ctx, out);
+}
+
+static void vdec_mpeg4_get_vf(struct vdec_mpeg4_inst *inst, struct vdec_v4l2_buffer **out)
+{
+ struct vframe_s *vf = NULL;
+ struct vdec_v4l2_buffer *fb = NULL;
+
+ vf = peek_video_frame(&inst->vfm);
+ if (!vf) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "there is no vframe.\n");
+ *out = NULL;
+ return;
+ }
+
+ vf = get_video_frame(&inst->vfm);
+ if (!vf) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "the vframe is avalid.\n");
+ *out = NULL;
+ return;
+ }
+
+ atomic_set(&vf->use_cnt, 1);
+
+ fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle;
+ fb->vf_handle = (unsigned long)vf;
+ fb->status = FB_ST_DISPLAY;
+
+ *out = fb;
+
+ //pr_info("%s, %d\n", __func__, fb->base_y.bytes_used);
+ //dump_write(fb->base_y.va, fb->base_y.bytes_used);
+ //dump_write(fb->base_c.va, fb->base_c.bytes_used);
+
+ /* convert yuv format. */
+ //swap_uv(fb->base_c.va, fb->base_c.size);
+}
+
+static int vdec_write_nalu(struct vdec_mpeg4_inst *inst,
+ u8 *buf, u32 size, u64 ts)
+{
+ int ret = 0;
+ struct aml_vdec_adapt *vdec = &inst->vdec;
+
+ ret = vdec_vframe_write(vdec, buf, size, ts);
+
+ 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);
+ } 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(0, V4L_DEBUG_CODEC_ERROR,
+ "the mpeg4 inst of dec is invalid.\n");
+ return -1;
+ }
+
+ switch (type) {
+ case GET_PARAM_DISP_FRAME_BUFFER:
+ vdec_mpeg4_get_vf(inst, out);
+ break;
+
+ case GET_PARAM_FREE_FRAME_BUFFER:
+ ret = vdec_mpeg4_get_fb(inst, out);
+ break;
+
+ case GET_PARAM_PIC_INFO:
+ get_pic_info(inst, out);
+ break;
+
+ case GET_PARAM_DPB_SIZE:
+ get_dpb_size(inst, out);
+ break;
+
+ case GET_PARAM_CROP_INFO:
+ get_crop_info(inst, out);
+ 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;
+
+ 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, crop(%d x %d), coded(%d x %d) dpb: %d, scan:%s\n",
+ ps->visible_width, ps->visible_height,
+ ps->coded_width, ps->coded_height,
+ dec->dpb_sz,
+ pic->field == V4L2_FIELD_NONE ? "P" : "I");
+}
+
+static void set_param_write_sync(struct vdec_mpeg4_inst *inst)
+{
+ complete(&inst->comp);
+}
+
+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(0, 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;
+
+ 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..6704350
--- /dev/null
+++ b/drivers/amvdec_ports/decoder/vdec_vp9_if.c
@@ -0,0 +1,1085 @@
+/*
+* 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_vcodec_vfm.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 vcodec_vfm_s vfm;
+ struct aml_dec_params parms;
+ struct completion comp;
+};
+
+static int vdec_write_nalu(struct vdec_vp9_inst *inst,
+ u8 *buf, u32 size, u64 ts);
+
+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:16;");
+ 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;
+
+ 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);
+ 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);
+ }
+
+ 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, "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;
+ }
+
+ 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.video_type = VFORMAT_VP9;
+ inst->vdec.dev = ctx->dev->vpu_plat_dev;
+ inst->vdec.filp = ctx->dev->filp;
+ inst->vdec.ctx = ctx;
+ inst->ctx = ctx;
+
+ 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;
+
+ /* init vfm */
+ inst->vfm.ctx = ctx;
+ inst->vfm.ada_ctx = &inst->vdec;
+ ret = vcodec_vfm_init(&inst->vfm);
+ if (ret) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "init vfm failed.\n");
+ goto err;
+ }
+
+ /* probe info from the stream */
+ inst->vsi = kzalloc(sizeof(struct vdec_vp9_vsi), GFP_KERNEL);
+ if (!inst->vsi) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /* alloc the header buffer to be used cache sps or spp etc.*/
+ inst->vsi->header_buf = kzalloc(HEADER_BUFFER_SIZE, GFP_KERNEL);
+ 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;
+ }
+
+ //dump_init();
+
+ return 0;
+err:
+ if (inst)
+ vcodec_vfm_release(&inst->vfm);
+ if (inst && inst->vsi && inst->vsi->header_buf)
+ kfree(inst->vsi->header_buf);
+ 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->parms.cfg.init_width;
+ int h = inst->parms.cfg.init_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)
+{
+ int ret = 0;
+
+ ret = vdec_write_nalu(inst, buf, size, timestamp);
+ 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->dec.dpb_sz ? 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->dec.dpb_sz ? 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);
+ } 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_vp9_deinit(unsigned long h_vdec)
+{
+ ulong flags;
+ struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec;
+ struct aml_vcodec_ctx *ctx = inst->ctx;
+
+ video_decoder_release(&inst->vdec);
+
+ vcodec_vfm_release(&inst->vfm);
+
+ //dump_deinit();
+
+ spin_lock_irqsave(&ctx->slock, flags);
+ if (inst->vsi && inst->vsi->header_buf)
+ kfree(inst->vsi->header_buf);
+
+ if (inst->vsi)
+ kfree(inst->vsi);
+
+ kfree(inst);
+
+ ctx->drv_handle = 0;
+ spin_unlock_irqrestore(&ctx->slock, flags);
+
+ need_trigger = false;
+ dump_cnt = 0;
+}
+
+static int vdec_vp9_get_fb(struct vdec_vp9_inst *inst, struct vdec_v4l2_buffer **out)
+{
+ return get_fb_from_queue(inst->ctx, out);
+}
+
+static void vdec_vp9_get_vf(struct vdec_vp9_inst *inst, struct vdec_v4l2_buffer **out)
+{
+ struct vframe_s *vf = NULL;
+ struct vdec_v4l2_buffer *fb = NULL;
+
+ vf = peek_video_frame(&inst->vfm);
+ if (!vf) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "there is no vframe.\n");
+ *out = NULL;
+ return;
+ }
+
+ vf = get_video_frame(&inst->vfm);
+ if (!vf) {
+ v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR,
+ "the vframe is avalid.\n");
+ *out = NULL;
+ return;
+ }
+
+ atomic_set(&vf->use_cnt, 1);
+
+ fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle;
+ fb->vf_handle = (unsigned long)vf;
+ fb->status = FB_ST_DISPLAY;
+
+ *out = fb;
+
+ //pr_info("%s, %d\n", __func__, fb->base_y.bytes_used);
+ //dump_write(fb->base_y.vaddr, fb->base_y.bytes_used);
+ //dump_write(fb->base_c.vaddr, fb->base_c.bytes_used);
+
+ /* convert yuv format. */
+ //swap_uv(fb->base_c.vaddr, fb->base_c.size);
+}
+
+static void add_prefix_data(struct vp9_superframe_split *s,
+ u8 **out, u32 *out_size)
+{
+ 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);
+ 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)
+{
+ 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);
+ vfree(data);
+ } else {
+ ret = vdec_vframe_write(vdec, buf, size, ts);
+ }
+
+ 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;
+ u32 size;
+ int ret = -1;
+
+ if (bs == NULL)
+ return -1;
+
+ buf = (u8 *) bs->vaddr;
+ size = bs->size;
+
+ if (vdec_input_full(vdec)) {
+ ATRACE_COUNTER("vdec_input_full", 0);
+ return -EAGAIN;
+ }
+
+ 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);
+ } 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);
+ }
+ ATRACE_COUNTER("v4l2_decode_write", ret);
+
+ 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 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(0, V4L_DEBUG_CODEC_ERROR,
+ "the vp9 inst of dec is invalid.\n");
+ return -1;
+ }
+
+ switch (type) {
+ case GET_PARAM_DISP_FRAME_BUFFER:
+ vdec_vp9_get_vf(inst, out);
+ break;
+
+ case GET_PARAM_FREE_FRAME_BUFFER:
+ ret = vdec_vp9_get_fb(inst, out);
+ break;
+
+ case GET_PARAM_PIC_INFO:
+ get_pic_info(inst, out);
+ break;
+
+ 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;
+ 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;
+
+ /* 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;
+
+ /* calc DPB size */
+ dec->dpb_sz = ps->dpb_size;
+
+ 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, crop(%d x %d), coded(%d x %d) dpb: %d\n",
+ ps->visible_width, ps->visible_height,
+ ps->coded_width, ps->coded_height,
+ ps->dpb_size);
+}
+
+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 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(0, 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_HDR_INFO:
+ set_param_hdr_info(inst, in);
+ break;
+
+ case SET_PARAM_POST_EVENT:
+ set_param_post_event(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..1d621da
--- /dev/null
+++ b/drivers/amvdec_ports/utils/common.c
@@ -0,0 +1,242 @@
+/*
+* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc.,
+* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* Description:
+*/
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#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);
+}
+
diff --git a/drivers/amvdec_ports/utils/common.h b/drivers/amvdec_ports/utils/common.h
new file mode 100644
index 0000000..dd4c51f
--- /dev/null
+++ b/drivers/amvdec_ports/utils/common.h
@@ -0,0 +1,172 @@
+/*
+* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc.,
+* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* Description:
+*/
+#ifndef UTILS_COMMON_H
+#define UTILS_COMMON_H
+
+#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);
+
+#endif
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..ed9f053
--- /dev/null
+++ b/drivers/amvdec_ports/vdec_drv_if.c
@@ -0,0 +1,126 @@
+/*
+* 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;
+}
+
+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..a04d832
--- /dev/null
+++ b/drivers/amvdec_ports/vdec_drv_if.h
@@ -0,0 +1,144 @@
+/*
+* 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_NORMAL : initial state
+ * @FB_ST_DISPLAY : frmae buffer is ready to be displayed
+ * @FB_ST_FREE : frame buffer is not used by decoder any more
+ */
+enum vdec_fb_status {
+ FB_ST_NORMAL,
+ FB_ST_DISPLAY,
+ FB_ST_FREE
+};
+
+/* For GET_PARAM_DISP_FRAME_BUFFER and GET_PARAM_FREE_FRAME_BUFFER,
+ * the caller does not own the returned buffer. The buffer will not be
+ * released before vdec_if_deinit.
+ * GET_PARAM_DISP_FRAME_BUFFER : get next displayable frame buffer,
+ * struct vdec_fb**
+ * GET_PARAM_FREE_FRAME_BUFFER : get non-referenced framebuffer, vdec_fb**
+ * GET_PARAM_PIC_INFO : get picture info, struct vdec_pic_info*
+ * GET_PARAM_CROP_INFO : get crop info, struct v4l2_crop*
+ * GET_PARAM_DPB_SIZE : get dpb size, unsigned int*
+ */
+enum vdec_get_param_type {
+ GET_PARAM_DISP_FRAME_BUFFER,
+ GET_PARAM_FREE_FRAME_BUFFER,
+ GET_PARAM_PIC_INFO,
+ GET_PARAM_CROP_INFO,
+ GET_PARAM_DPB_SIZE,
+ GET_PARAM_CONFIG_INFO
+};
+
+/*
+ * 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_HDR_INFO,
+ SET_PARAM_POST_EVENT
+};
+
+/**
+ * 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);
+
+#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..d692ca8
--- /dev/null
+++ b/drivers/common/chips/chips.c
@@ -0,0 +1,190 @@
+/*
+ * 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/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"},
+ {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..d74728c
--- /dev/null
+++ b/drivers/common/chips/decoder_cpu_ver_info.c
@@ -0,0 +1,176 @@
+/*
+* 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/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 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_RES_0x2c,
+ AM_MESON_CPU_MAJOR_ID_RES_0x2d,
+ AM_MESON_CPU_MAJOR_ID_TL1,
+ AM_MESON_CPU_MAJOR_ID_TM2,
+ AM_MESON_CPU_MAJOR_ID_RES_0x30,
+ AM_MESON_CPU_MAJOR_ID_RES_0x31,
+ AM_MESON_CPU_MAJOR_ID_SC2,
+};
+
+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],
+ },
+ {},
+};
+
+static bool get_cpu_id_from_dtb(enum AM_MESON_CPU_MAJOR_ID *pidType)
+{
+ struct device_node *pNode = NULL;
+ struct platform_device* pDev = NULL;
+ const struct of_device_id *pMatch = NULL;
+
+ 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) {
+ pr_err("No find of_match_device\n");
+ return -EINVAL;
+ }
+
+ *pidType = *(enum AM_MESON_CPU_MAJOR_ID *)pMatch->data;
+
+ return AM_SUCESS;
+}
+
+static void initial_cpu_id(void)
+{
+ enum AM_MESON_CPU_MAJOR_ID id_type = AM_MESON_CPU_MAJOR_ID_MAX;
+
+ if (AM_SUCESS == get_cpu_id_from_dtb(&id_type))
+ cpu_ver_id = id_type;
+ else
+ cpu_ver_id = (enum AM_MESON_CPU_MAJOR_ID)get_cpu_type();
+
+ if (AM_MESON_CPU_MAJOR_ID_G12B == cpu_ver_id)
+ if (is_meson_rev_b())
+ cpu_ver_id = AM_MESON_CPU_MAJOR_ID_TL1;
+}
+
+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);
+
+bool is_cpu_tm2_revb(void)
+{
+ return ((get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_TM2) &&
+ (is_meson_rev_b()));
+}
+EXPORT_SYMBOL(is_cpu_tm2_revb);
+
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..673b001
--- /dev/null
+++ b/drivers/common/chips/decoder_cpu_ver_info.h
@@ -0,0 +1,61 @@
+/*
+* 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
+
+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_RES_0x2c,
+ AM_MESON_CPU_MAJOR_ID_RES_0x2d,
+ AM_MESON_CPU_MAJOR_ID_TL1 = 0x2e,
+ AM_MESON_CPU_MAJOR_ID_TM2 = 0x2f,
+ AM_MESON_CPU_MAJOR_ID_RES_0x30,
+ AM_MESON_CPU_MAJOR_ID_RES_0x31,
+ AM_MESON_CPU_MAJOR_ID_SC2 = 0x32,
+ AM_MESON_CPU_MAJOR_ID_RES_0x33,
+ AM_MESON_CPU_MAJOR_ID_T5,
+ AM_MESON_CPU_MAJOR_ID_MAX,
+};
+
+enum AM_MESON_CPU_MAJOR_ID get_cpu_major_id(void);
+bool is_cpu_tm2_revb(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..85a81e6
--- /dev/null
+++ b/drivers/common/firmware/firmware_drv.c
@@ -0,0 +1,1015 @@
+/*
+ * 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/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>
+#include <linux/cdev.h>
+#include <linux/crc32.h>
+#include "../chips/decoder_cpu_ver_info.h"
+
+/* major.minor */
+#define PACK_VERS "v0.2"
+
+#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;
+
+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;
+
+ mutex_lock(&mutex);
+
+ if (list_empty(&mgr->fw_head)) {
+ pbuf += sprintf(pbuf, "No firmware.\n");
+ goto out;
+ }
+
+ /* shows version of driver. */
+ pr_info("The driver version is %s\n", PACK_VERS);
+
+ 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);
+
+ 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;
+
+ 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\n", major_fw, minor_fw);
+ }
+
+ 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;
+}
+
+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,
+};
+
+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..410745b
--- /dev/null
+++ b/drivers/common/firmware/firmware_priv.h
@@ -0,0 +1,120 @@
+/*
+ * 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;
+ char reserved[128];
+};
+
+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..c232020
--- /dev/null
+++ b/drivers/common/firmware/firmware_type.c
@@ -0,0 +1,122 @@
+/*
+* 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"},
+};
+
+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..e997057
--- /dev/null
+++ b/drivers/common/firmware/firmware_type.h
@@ -0,0 +1,98 @@
+/*
+* 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)
+
+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..972bcc1
--- /dev/null
+++ b/drivers/common/media_clock/clk/clk.c
@@ -0,0 +1,457 @@
+/*
+ * 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/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(1);
+}
+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);
+
+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) {
+ 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 = vzalloc(sizeof(struct chip_vdec_clk_s));
+ 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()) {
+ vfree(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)
+{
+ vfree(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 = vzalloc(size);
+ 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)
+{
+ vfree(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..82eec1d
--- /dev/null
+++ b/drivers/common/media_clock/clk/clk.h
@@ -0,0 +1,175 @@
+/*
+ * 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);
+
+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() >= 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..be2401c
--- /dev/null
+++ b/drivers/common/media_clock/clk/clkg12.c
@@ -0,0 +1,1063 @@
+/*
+ * 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)
+
+#define CHECK_RET(_ret) if (ret) {debug_print(\
+ "%s:%d:function call failed with result: %d\n",\
+ __FUNCTION__, __LINE__, _ret);}
+
+
+static int clock_real_clk[VDEC_MAX + 1];
+
+static unsigned int set_frq_enable, vdec_frq, hevc_frq, hevcb_frq;
+
+#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)
+{
+ int ret;
+
+ debug_print("gp_pll_user_cb_vdec call\n");
+ if (event == GP_PLL_USER_EVENT_GRANT) {
+ struct clk *clk = clk_get(NULL, "gp0_pll");
+ if (!IS_ERR(clk)) {
+ if (is_gp0_div2) {
+ ret = clk_set_rate(clk, 1296000000UL);
+ CHECK_RET(ret);
+ } else {
+ ret = clk_set_rate(clk, 648000000UL);
+ CHECK_RET(ret);
+ }
+ 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)
+ 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;
+ int ret;
+
+ 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;
+ }
+
+ ret = clk_set_rate(clk, rate);
+ CHECK_RET(ret);
+
+ 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() >= MESON_CPU_MAJOR_ID_GXL)
+ is_gp0_div2 = false;
+ else
+ is_gp0_div2 = true;
+
+ if (get_cpu_major_id() >= 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)
+ clk = 800;
+
+ 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)
+ clk = TL1_HEVC_MAX_CLK;
+ else
+ clk = 667;
+ }
+
+ 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,\
+ 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..9d5f7b4
--- /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 %p\n",
+ gates[i].name,
+ gates[i].clk);
+ } else {
+ pr_info("get gate %s control ok %p\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/fake_video_out/Makefile b/drivers/fake_video_out/Makefile
new file mode 100644
index 0000000..1dd937c
--- /dev/null
+++ b/drivers/fake_video_out/Makefile
@@ -0,0 +1 @@
+obj-m += fake_video.o
diff --git a/drivers/fake_video_out/fake_video.c b/drivers/fake_video_out/fake_video.c
new file mode 100644
index 0000000..e0e9b16
--- /dev/null
+++ b/drivers/fake_video_out/fake_video.c
@@ -0,0 +1,309 @@
+/*
+* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc.,
+* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* Description:
+*/
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/ctype.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma-contiguous.h>
+#include <linux/sched.h>
+#include <linux/amlogic/media/vfm/vframe.h>
+#include <linux/amlogic/media/vfm/vframe_provider.h>
+#include <linux/amlogic/media/vfm/vframe_receiver.h>
+#include <linux/amlogic/major.h>
+#include "../frame_provider/decoder/utils/vdec.h"
+#include <linux/delay.h>
+#include <linux/kthread.h>
+
+#define RECEIVER_NAME "fake-amvideo"
+#define DEVICE_NAME "fake-amvideo"
+
+#define TUNNEL_MODE (0)
+#define NON_TUNNEL_MODE (1)
+
+static u32 display_mode = TUNNEL_MODE;
+module_param(display_mode, uint, 0664);
+MODULE_PARM_DESC(display_mode, "\n display_mode\n");
+
+static struct device *amvideo_dev = NULL;
+struct timer_list timer;
+struct task_struct *task;
+bool thread_stop = false;
+atomic_t frame_count;
+
+static struct vframe_receiver_s fake_video_vf_recv;
+static int video_receiver_event_fun(int type, void *data, void *);
+static const struct vframe_receiver_op_s fake_video_vf_receiver = {
+ .event_cb = video_receiver_event_fun
+};
+
+static struct vframe_s *video_vf_peek(void)
+{
+ return vf_peek(RECEIVER_NAME);
+}
+
+static struct vframe_s *video_vf_get(void)
+{
+ struct vframe_s *vf = NULL;
+
+ vf = vf_get(RECEIVER_NAME);
+
+ if (vf) {
+ atomic_set(&vf->use_cnt, 1);
+ /*pr_err("Get vframe w: %d, h: %d, fence: %lx, idx: %d\n",
+ vf->width, vf->height, (ulong)vf->fence, vf->index & 0xff);*/
+ }
+
+ return vf;
+}
+
+static void video_vf_put(struct vframe_s *vf)
+{
+ struct vframe_provider_s *vfp = vf_get_provider(RECEIVER_NAME);
+
+ if (vfp && vf && atomic_dec_and_test(&vf->use_cnt)) {
+ vf_put(vf, RECEIVER_NAME);
+ }
+}
+
+static int video_receiver_event_fun(int type, void *data, void *private_data)
+{
+ switch (type) {
+ case VFRAME_EVENT_PROVIDER_UNREG: {
+ atomic_set(&frame_count, 0);
+ pr_info("VFRAME_EVENT_PROVIDER_UNREG\n");
+ break;
+ }
+ case VFRAME_EVENT_PROVIDER_START: {
+ pr_info("VFRAME_EVENT_PROVIDER_START\n");
+ break;
+ }
+ case VFRAME_EVENT_PROVIDER_QUREY_STATE: {
+ break;
+ }
+ case VFRAME_EVENT_PROVIDER_VFRAME_READY: {
+ pr_info("VFRAME_EVENT_PROVIDER_VFRAME_READY\n");
+ atomic_inc(&frame_count);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void display_timer_func(unsigned long arg)
+{
+ struct vframe_s *vf = NULL;
+
+ if (display_mode != TUNNEL_MODE)
+ goto out;
+
+ vf = video_vf_peek();
+ if (!vf) {
+ goto out;
+ }
+
+ if (vf->fence) {
+ if (vdec_fence_status_get(vf->fence) == 1) {
+ pr_info("[VDEC-FENCE]: Display, idx: %d\n",
+ vf->index & 0xff);
+ vf = video_vf_get();
+ video_vf_put(vf);
+ } else {
+ pr_err("[VDEC-FENCE]: Display invalid, fence status err.\n");
+ }
+ }
+
+out:
+ mod_timer(&timer, jiffies + msecs_to_jiffies(16));
+}
+
+static int display_thread(void *data)
+{
+ struct vframe_s *vf = NULL;
+
+ for (;;) {
+ if (thread_stop)
+ break;
+
+ if ((atomic_read(&frame_count) == 0) ||
+ display_mode != NON_TUNNEL_MODE)
+ continue;
+
+ if (video_vf_peek()) {
+ vf = video_vf_get();
+ if (!vf) {
+ pr_err("receiver vf err.\n");
+ break;
+ }
+
+ atomic_dec(&frame_count);
+
+ if (vf->fence) {
+ u64 timestamp = local_clock();
+ /* fence waiting until frame ready. */
+ vdec_fence_wait(vf->fence, msecs_to_jiffies(2000));
+
+ if (vdec_fence_status_get(vf->fence) == 1) {
+ pr_info("[VDEC-FENCE]: Display, idx: %d, dec cost: %lld\n",
+ vf->index & 0xff, local_clock() - timestamp);
+ } else {
+ pr_err("[VDEC-FENCE]: Display invalid, fence status err.\n");
+ }
+ }
+
+ video_vf_put(vf);
+ }
+ msleep(16);
+ }
+ return 0;
+}
+
+static int amvideo_open(struct inode *inode, struct file *file)
+{
+ file->private_data = NULL;
+ return 0;
+}
+
+static int amvideo_release(struct inode *inode, struct file *file)
+{
+ file->private_data = NULL;
+ return 0;
+}
+
+static long amvideo_ioctl(struct file *file, unsigned int cmd, ulong arg)
+{
+ file->private_data = NULL;
+ return 0;
+}
+
+#ifdef CONFIG_COMPAT
+static long amvideo_compat_ioctl(struct file *file, unsigned int cmd, ulong arg)
+{
+ file->private_data = NULL;
+ return 0;
+}
+#endif
+
+static const struct file_operations amvideo_fops = {
+ .owner = THIS_MODULE,
+ .open = amvideo_open,
+ .release = amvideo_release,
+ .unlocked_ioctl = amvideo_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = amvideo_compat_ioctl,
+#endif
+ //.poll = amvideo_poll,
+};
+
+static struct class amvideo_class = {
+ .name = "fake_video",
+};
+
+#define FAKEVIDEO_MAJOR (23 + (AML_BASE))
+
+static int __init fake_video_init(void)
+{
+ int ret = 0;
+
+ ret = class_register(&amvideo_class);
+ if (ret) {
+ pr_err("create video class fail.\n");
+ return 0;
+ }
+
+
+ /* create video device */
+ ret = register_chrdev(FAKEVIDEO_MAJOR, DEVICE_NAME, &amvideo_fops);
+ if (ret < 0) {
+ pr_err("Can't register major for amvideo device\n");
+ goto err1;
+ }
+
+ amvideo_dev = device_create(&amvideo_class, NULL,
+ MKDEV(FAKEVIDEO_MAJOR, 0), NULL, DEVICE_NAME);
+ if (IS_ERR(amvideo_dev)) {
+ pr_err("Can't create amvideo device\n");
+ goto err;
+ }
+
+ vf_receiver_init(&fake_video_vf_recv, RECEIVER_NAME,
+ &fake_video_vf_receiver, NULL);
+ vf_reg_receiver(&fake_video_vf_recv);
+
+ atomic_set(&frame_count, 0);
+
+ init_timer(&timer);
+ //timer.data = 0;
+ timer.function = display_timer_func;
+ timer.expires = jiffies + HZ;
+ add_timer(&timer);
+
+ thread_stop = false;
+ task = kthread_run(display_thread, NULL, "aml-%s", "fake-video-thread");
+ if (IS_ERR(task)) {
+ ret = PTR_ERR(task);
+ pr_err("Failed to creat display thread, ret: %d.\n", ret);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ unregister_chrdev(FAKEVIDEO_MAJOR, DEVICE_NAME);
+err1:
+ class_unregister(&amvideo_class);
+
+ return ret;
+}
+
+static void __exit fake_video_exit(void)
+{
+ thread_stop = true;
+ kthread_stop(task);
+
+ del_timer_sync(&timer);
+
+ vf_unreg_receiver(&fake_video_vf_recv);
+
+ device_destroy(&amvideo_class, MKDEV(FAKEVIDEO_MAJOR, 0));
+ unregister_chrdev(FAKEVIDEO_MAJOR, DEVICE_NAME);
+ class_unregister(&amvideo_class);
+
+}
+
+
+module_init(fake_video_init);
+module_exit(fake_video_exit);
+
+
+MODULE_DESCRIPTION("AMLOGIC fake video output driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nanxin Qin <nanxin.qin@amlogic.com>");
+
diff --git a/drivers/frame_provider/Makefile b/drivers/frame_provider/Makefile
new file mode 100644
index 0000000..371e088
--- /dev/null
+++ b/drivers/frame_provider/Makefile
@@ -0,0 +1 @@
+obj-y += decoder/
diff --git a/drivers/frame_provider/decoder/Makefile b/drivers/frame_provider/decoder/Makefile
new file mode 100644
index 0000000..349d381
--- /dev/null
+++ b/drivers/frame_provider/decoder/Makefile
@@ -0,0 +1,14 @@
+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 += real/
+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..6314f9d
--- /dev/null
+++ b/drivers/frame_provider/decoder/avs/avs.c
@@ -0,0 +1,1993 @@
+/*
+ * 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>
+
+
+#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
+ canvas_config_ex(canvas_base + canvas_num * i + 0,
+ buf_start,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP,
+ vdec->canvas_mode, endian);
+ canvas_config_ex(canvas_base + canvas_num * i + 1,
+ buf_start +
+ decbuf_y_size, canvas_width,
+ canvas_height / 2,
+ CANVAS_ADDR_NOWRAP,
+ vdec->canvas_mode, endian);
+#else
+ canvas_config_ex(canvas_num * i + 0,
+ buf_start,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP,
+ vdec->canvas_mode, endian);
+ canvas_config_ex(canvas_num * i + 1,
+ buf_start +
+ decbuf_y_size, canvas_width / 2,
+ canvas_height / 2,
+ CANVAS_ADDR_NOWRAP,
+ vdec->canvas_mode, endian);
+ canvas_config_ex(canvas_num * i + 2,
+ buf_start +
+ decbuf_y_size + decbuf_uv_size,
+ canvas_width / 2, canvas_height / 2,
+ CANVAS_ADDR_NOWRAP,
+ vdec->canvas_mode, endian);
+#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(unsigned long arg)
+{
+ struct timer_list *timer = (struct timer_list *)arg;
+
+#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");
+ init_timer(&recycle_timer);
+
+ 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;
+
+ recycle_timer.data = (ulong)(&recycle_timer);
+ recycle_timer.function = vavs_put_timer_func;
+ 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..3da87e4
--- /dev/null
+++ b/drivers/frame_provider/decoder/avs2/avs2_bufmgr.c
@@ -0,0 +1,2203 @@
+/*
+* 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 "../../../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..3e7fcb8
--- /dev/null
+++ b/drivers/frame_provider/decoder/avs2/avs2_global.h
@@ -0,0 +1,1684 @@
+/* The copyright in this software is being made available under the BSD
+ * License, included below. This software may be subject to other third party
+ * and contributor rights, including patent rights, and no such rights are
+ * granted under this license.
+ *
+ * Copyright (c) 2002-2016, Audio Video coding Standard Workgroup of China
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Audio Video coding Standard Workgroup of China
+ * nor the names of its contributors maybe
+ * used to endorse or promote products
+ * derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+
+
+/*
+ * File name: global.h
+ * Function: global definitions for for AVS decoder.
+ *
+ */
+
+#ifndef _GLOBAL_H_
+#define _GLOBAL_H_
+
+/* #include <stdio.h> //!< for FILE */
+/* #include <stdlib.h> */
+
+#define AML
+#define SANITY_CHECK
+#undef NO_DISPLAY
+
+/* #include "define.h" */
+#define RD "19.2"
+#define VERSION "19.2"
+
+#define RESERVED_PROFILE_ID 0x24
+#define BASELINE_PICTURE_PROFILE 18
+#define BASELINE_PROFILE 32 /* 0x20 */
+#define BASELINE10_PROFILE 34 /* 0x22 */
+
+
+#define SCENE_PROFILE 48 /* 0x21 */
+#define SCENE10_PROFILE 50 /* 0x23 */
+
+#define TRACE 0 /* !< 0:Trace off 1:Trace on */
+
+
+/* Type definitions and file operation for Windows/Linux
+ * All file operations for windows are replaced with native (FILE *) operations
+ * Falei LUO (falei.luo@vipl.ict.ac.cn)
+ * */
+
+#define _FILE_OFFSET_BITS 64 /* for 64 bit fseeko */
+#define fseek fseeko
+
+#define int16 int16_t
+#define int64 int64_t
+
+/* ////////////////// bug fix ///////////////////////////// */
+#define ALFSliceFix 1
+#define WRITENBIT_FIX 1
+#define FIX_PROFILE_LEVEL_DPB_RPS_1 1
+#define FIX_PROFILE_LEVEL_DPB_RPS_2 1
+#define FIX_RPS_PICTURE_REMOVE 1 /* flluo@pku.edu.cn */
+#define Mv_Clip 1 /* yuquanhe@hisilicon.com */
+#define REMOVE_UNUSED 1 /* yuquanhe@hisilicon.com */
+#define SAO_Height_Fix 1 /* yuquanhe@hisilicon.com */
+#define B_BACKGROUND_Fix 1 /* yuquanhe@hisilicon.com */
+#define Check_Bitstream 1 /* yuquanhe@hisilicon.com */
+#define Wq_param_Clip 1 /* yuquanhe@hisilicon.com */
+ /* luofalei flluo@pku.edu.cn , wlq15@mails.tsinghua.edu.cn ,
+ Longfei.Wang@mediatek.com */
+#define RD1501_FIX_BG 1
+ /* yuquanhe@hisilicon.com ; he-yuan.lin@mstarsemi.com */
+#define Mv_Rang 1
+ /* Longfei.Wang@mediatek.com ;fred.chiu@mediatek.com
+ jie1222.chen@samsung.com */
+#define RD160_FIX_BG 1
+ /* Y_K_Tu@novatek.com.tw, he-yuan.lin@mstarsemi.com,
+ victor.huang@montage-tech.com M4041 */
+#define RD1601_FIX_BG 1
+#define SEQ_CHANGE_CHECKER 1 /* he-yuan.lin@mstarsemi.com */
+#define M4140_END_OF_SLICE_CHECKER 1 /* he-yuan.lin@mstarsemi.com */
+ /* wlq15@mails.tsinghua.edu.cn */
+#define Mv_check_bug 1
+#define SAO_ASSERTION_FIX 1 /* fred.chiu@mediatek.com */
+#define FIELD_HORI_MV_NO_SCALE_FIX 1 /* fred.chiu@mediatek.com */
+#define RD170_FIX_BG 1
+#define FIX_CHROMA_FIELD_MV_BK_DIST 1
+#define FIX_LUMA_FIELD_MV_BK_DIST 1
+#define FIX_CHROMA_FIELD_MV_CLIP 1
+#if 1
+#define FIX_FLUSH_DPB_BY_LF 1 /* fred.chiu@mediatek.com */
+#define FIX_SEQ_END_FLUSH_DPB_BY_LF 1 /* fred.chiu@mediatek.com */
+#else
+#define FIX_FLUSH_DPB_BY_LF 0 /* fred.chiu@mediatek.com */
+#define FIX_SEQ_END_FLUSH_DPB_BY_LF 0 /* fred.chiu@mediatek.com */
+#endif
+#define RD191_FIX_BUG 1 /* yuquanhe@hsilicon.com */
+#define SYM_MV_SCALE_FIX 1/* peisong.chen@broadcom.com */
+#define BUG_10BIT_REFINEQP 0 /* wangzhenyu */
+
+
+
+#if RD191_FIX_BUG
+#endif
+
+/************************
+ * AVS2 macros start
+ **************************/
+
+#define INTERLACE_CODING 1
+#if INTERLACE_CODING /* M3531: MV scaling compensation */
+/* Luma component */
+#define HALF_PIXEL_COMPENSATION 1 /* common functions definition */
+#define HALF_PIXEL_COMPENSATION_PMV 1 /* spacial MV prediction */
+#define HALF_PIXEL_COMPENSATION_DIRECT 1 /* B direct mode */
+ /* MV derivation method 1, weighted P_skip mode */
+#define HALF_PIXEL_COMPENSATION_M1 1
+ /* M1 related with mv-scaling function */
+#define HALF_PIXEL_COMPENSATION_M1_FUCTION 1
+#define HALF_PIXEL_COMPENSATION_MVD 1 /* MV scaling from FW->BW */
+/* Chroma components */
+ /* chroma MV is scaled with luma MV for 4:2:0 format */
+#define HALF_PIXEL_CHROMA 1
+ /* half pixel compensation for p skip/direct */
+#define HALF_PIXEL_PSKIP 1
+#define INTERLACE_CODING_FIX 1 /* HLS fix */
+#define OUTPUT_INTERLACE_MERGED_PIC 1
+
+#endif
+/*
+ *******************************
+AVS2 10bit/12bit profile
+ ********************************
+ */
+
+#define DBFIX_10bit 1
+
+#define BUG_10bit 1
+
+/*
+ ***************************************
+AVS2 HIGH LEVEL SYNTAX
+ ***************************************
+ */
+#define AVS2_HDR_HLS 1
+ /* AVS2 HDR technology //yuquanhe@hisilicon.com */
+#define AVS2_HDR_Tec 1
+#if AVS2_HDR_Tec
+#define HDR_CHROMA_DELTA_QP 1 /* M3905 */
+#define HDR_ADPTIVE_UV_DELTA 1
+#endif
+/*
+ *************************************
+AVS2 S2
+ *************************************
+ */
+#define AVS2_S2_FASTMODEDECISION 1
+#define RD1510_FIX_BG 1 /* 20160714, flluo@pku.edu.cn */
+
+
+/* ////////////////// prediction techniques ///////////////////////////// */
+#define LAM_2Level_TU 0.8
+
+
+#define DIRECTION 4
+#define DS_FORWARD 4
+#define DS_BACKWARD 2
+#define DS_SYM 3
+#define DS_BID 1
+
+#define MH_PSKIP_NUM 4
+#define NUM_OFFSET 0
+#define BID_P_FST 1
+#define BID_P_SND 2
+#define FW_P_FST 3
+#define FW_P_SND 4
+#define WPM_NUM 3
+ /* M3330 changes it to 2, the original value is 3 */
+#define MAX_MVP_CAND_NUM 2
+
+#define DMH_MODE_NUM 5 /* Number of DMH mode */
+#define TH_ME 0 /* Threshold of ME */
+
+#define MV_SCALE 1
+
+/* ///// reference picture management // */
+#define FIX_MAX_REF 1 /* Falei LUO, flluo@pku.edu.cn */
+#if FIX_MAX_REF
+ /* maximum number of reference frame for each frame */
+#define MAXREF 7
+#define MAXGOP 32
+#endif
+
+/* #define REF_MAXBUFFER 7 */
+/* more bufferes for displaying and background */
+/* #define REF_MAXBUFFER 15 */
+#if 1
+#define REF_MAXBUFFER 23
+#define REF_BUFFER 16
+#else
+#if RD170_FIX_BG
+#define REF_MAXBUFFER 16
+#else
+#define REF_MAXBUFFER 7
+#endif
+#endif
+
+#ifdef TO_PORTING
+ /* block-composed background reference, fangdong@mail.ustc.edu.cn */
+#define BCBR 1
+#else
+#define BCBR 0
+#endif
+/* one more buffer for background when background_picture_output_flag is 0*/
+#define AVS2_MAX_BUFFER_NUM (REF_MAXBUFFER + 1)
+
+/* /////////////////Adaptive Loop Filter////////////////////////// */
+#define NUM_ALF_COEFF_CTX 1
+#define NUM_ALF_LCU_CTX 4
+
+#define LAMBDA_SCALE_LUMA (1.0)
+#define LAMBDA_SCALE_CHROMA (1.0)
+
+
+
+/* ////////////////// entropy coding ///////////////////////////// */
+ /* M3090: Make sure rs1 will not overflow for 8-bit unsign char */
+#define NUN_VALUE_BOUND 254
+#define Encoder_BYPASS_Final 1 /* M3484 */
+#define Decoder_Bypass_Annex 0 /* M3484 */
+#define Decoder_Final_Annex 0 /* M3540 */
+
+
+/* ////////////////// coefficient coding ///// */
+ /* M3035 size of an coefficient group, 4x4 */
+#define CG_SIZE 16
+
+#define SWAP(x, y) {\
+ (y) = (y) ^ (x);\
+ (x) = (y) ^ (x);\
+ (y) = (x) ^ (y);\
+}
+
+/* ////////////////// encoder optimization /////// */
+#define TH 2
+
+#define M3624MDLOG /* reserved */
+
+#define TDRDO 1 /* M3528 */
+/* #define FIX_TDRDO_BG 1 // flluo@pku.edu.cn, 20160318// */
+#define RATECONTROL 1 /* M3580 M3627 M3689 */
+#define AQPO 1 /* M3623 */
+#define AQPOM3694 0
+#define AQPOM4063 1
+#define AQPOM3762 1
+#define BGQPO 1 /* M4061 */
+#if BGQPO
+#define LONGREFERENCE 32
+#endif
+
+/* #define REPORT */
+/* ////////////////// Quantization /////////////////////////////////////// */
+ /* Adaptive frequency weighting quantization */
+#define FREQUENCY_WEIGHTING_QUANTIZATION 1
+#if FREQUENCY_WEIGHTING_QUANTIZATION
+#define CHROMA_DELTA_QP 1
+#define AWQ_WEIGHTING 1
+#define AWQ_LARGE_BLOCK_ENABLE 1
+#define COUNT_BIT_OVERHEAD 0
+#define AWQ_LARGE_BLOCK_EXT_MAPPING 1
+#endif
+
+#define QuantClip 1
+#define QuantMatrixClipFix 1 /* 20160418, fllu@pku.edu.cn */
+
+#define WQ_MATRIX_FCD 1
+#if !WQ_MATRIX_FCD
+#define WQ_FLATBASE_INBIT 7
+#else
+#define WQ_FLATBASE_INBIT 6
+#endif
+
+
+#define REFINED_QP 1
+
+
+/* ////////////////// delta QP ///// */
+ /* M3122: the minimum dQP unit is Macro block */
+#define MB_DQP 1
+ /* M3122: 1 represents left prediction
+ and 0 represents previous prediction */
+#define LEFT_PREDICTION 1
+
+
+/* //////////////////////SAO///////// */
+#define NUM_BO_OFFSET 32
+#define MAX_NUM_SAO_CLASSES 32
+#define NUM_SAO_BO_CLASSES_LOG2 5
+#define NUM_SAO_BO_CLASSES_IN_BIT 5
+#define MAX_DOUBLE (1.7e + 308)
+#define NUM_SAO_EO_TYPES_LOG2 2
+#define NUM_SAO_BO_CLASSES (1<<NUM_SAO_BO_CLASSES_LOG2)
+#define SAO_RATE_THR 0.75
+#define SAO_RATE_CHROMA_THR 1
+#define SAO_SHIFT_PIX_NUM 4
+
+#define SAO_PARA_CROSS_SLICE 1
+#define SAO_MULSLICE_FTR_FIX 1
+
+/* /////////////////// Transform ///////////////////// */
+#define SEC_TR_SIZE 4
+ /* apply secT to greater than or equal to 8x8 block, */
+#define SEC_TR_MIN_BITSIZE 3
+
+#define BUGFIXED_COMBINED_ST_BD 1
+
+/* /////////////////// Scalable ///////////////////// */
+#define M3480_TEMPORAL_SCALABLE 1
+#define TEMPORAL_MAXLEVEL 8
+#define TEMPORAL_MAXLEVEL_BIT 3
+
+
+
+
+/*
+ *************************************
+ * AVS2 macros end
+ *
+ *************************************
+ */
+
+#define CHROMA 1
+#define LUMA_8x8 2
+#define NUM_BLOCK_TYPES 8
+
+#if (!defined clamp)
+ /* !< clamp a to the range of [b;c] */
+#define clamp(a, b, c) ((a) < (b) ? (b) : ((a) > (c) ? (c) : (a)))
+#endif
+
+ /* POC200301 moved from defines.h */
+#define LOG2_MAX_FRAME_NUM_MINUS4 4
+ /* !< bytes for one frame */
+#define MAX_CODED_FRAME_SIZE 15000000
+
+/* ----------------------- */
+/* FLAGS and DEFINES for new chroma intra prediction, Dzung Hoang */
+/* Threshold values to zero out quantized transform coefficients. */
+/* Recommend that _CHROMA_COEFF_COST_ be low to improve chroma quality */
+#define _LUMA_COEFF_COST_ 4 /* !< threshold for luma coeffs */
+ /* !< Number of pixels padded around the reference frame (>=4) */
+#define IMG_PAD_SIZE 64
+
+#define OUTSTRING_SIZE 255
+
+ /* !< abs macro, faster than procedure */
+#define absm(A) ((A) < (0) ? (-(A)) : (A))
+ /* !< used for start value for some variables */
+#define MAX_VALUE 999999
+
+#define Clip1(a) ((a) > 255 ? 255:((a) < 0 ? 0 : (a)))
+#define Clip3(min, max, val) (((val) < (min)) ?\
+ (min) : (((val) > (max)) ? (max) : (val)))
+
+/* --------------------------------------------- */
+
+/* block size of block transformed by AVS */
+#define PSKIPDIRECT 0
+#define P2NX2N 1
+#define P2NXN 2
+#define PNX2N 3
+#define PHOR_UP 4
+#define PHOR_DOWN 5
+#define PVER_LEFT 6
+#define PVER_RIGHT 7
+#define PNXN 8
+#define I8MB 9
+#define I16MB 10
+#define IBLOCK 11
+#define InNxNMB 12
+#define INxnNMB 13
+#define MAXMODE 14 /* add yuqh 20130824 */
+#define LAMBDA_ACCURACY_BITS 16
+#define LAMBDA_FACTOR(lambda) ((int)((double)(1 << LAMBDA_ACCURACY_BITS)\
+ * lambda + 0.5))
+#define WEIGHTED_COST(factor, bits) (((factor) * (bits))\
+ >> LAMBDA_ACCURACY_BITS)
+#define MV_COST(f, s, cx, cy, px, py) (WEIGHTED_COST(f, mvbits[((cx) << (s))\
+ - px] + mvbits[((cy) << (s)) - py]))
+#define REF_COST(f, ref) (WEIGHTED_COST(f, refbits[(ref)]))
+
+#define BWD_IDX(ref) (((ref) < 2) ? 1 - (ref) : (ref))
+#define REF_COST_FWD(f, ref) (WEIGHTED_COST(f,\
+ ((img->num_ref_pic_active_fwd_minus1 == 0) ?\
+ 0 : refbits[(ref)])))
+#define REF_COST_BWD(f, ef) (WEIGHTED_COST(f,\
+ ((img->num_ref_pic_active_bwd_minus1 == 0) ?\
+ 0 : BWD_IDX(refbits[ref]))))
+
+#define IS_INTRA(MB) ((MB)->cuType == I8MB ||\
+ (MB)->cuType == I16MB ||\
+ (MB)->cuType == InNxNMB || (MB)->cuType == INxnNMB)
+#define IS_INTER(MB) ((MB)->cuType != I8MB &&\
+ (MB)->cuType != I16MB && (MB)->cuType != InNxNMB\
+ && (MB)->cuType != INxnNMB)
+#define IS_INTERMV(MB) ((MB)->cuType != I8MB &&\
+ (MB)->cuType != I16MB && (MB)->cuType != InNxNMB &&\
+ (MB)->cuType != INxnNMB && (MB)->cuType != 0)
+
+
+#define IS_DIRECT(MB) ((MB)->cuType == PSKIPDIRECT && (img->type == B_IMG))
+#define IS_P_SKIP(MB) ((MB)->cuType == PSKIPDIRECT &&\
+ (((img->type == F_IMG)) || ((img->type == P_IMG))))
+#define IS_P8x8(MB) ((MB)->cuType == PNXN)
+
+/* Quantization parameter range */
+#define MIN_QP 0
+#define MAX_QP 63
+#define SHIFT_QP 11
+
+/* Picture types */
+#define INTRA_IMG 0 /* !< I frame */
+#define INTER_IMG 1 /* !< P frame */
+#define B_IMG 2 /* !< B frame */
+#define I_IMG 0 /* !< I frame */
+#define P_IMG 1 /* !< P frame */
+#define F_IMG 4 /* !< F frame */
+
+#define BACKGROUND_IMG 3
+
+#define BP_IMG 5
+
+
+/* Direct Mode types */
+#define MIN_CU_SIZE 8
+#define MIN_BLOCK_SIZE 4
+#define MIN_CU_SIZE_IN_BIT 3
+#define MIN_BLOCK_SIZE_IN_BIT 2
+#define BLOCK_MULTIPLE (MIN_CU_SIZE/(MIN_BLOCK_SIZE))
+#define MAX_CU_SIZE 64
+#define MAX_CU_SIZE_IN_BIT 6
+#define B4X4_IN_BIT 2
+#define B8X8_IN_BIT 3
+#define B16X16_IN_BIT 4
+#define B32X32_IN_BIT 5
+#define B64X64_IN_BIT 6
+ /* !< # luma intra prediction modes */
+#define NUM_INTRA_PMODE 33
+ /* number of luma modes for full RD search */
+#define NUM_MODE_FULL_RD 9
+ /* !< #chroma intra prediction modes */
+#define NUM_INTRA_PMODE_CHROMA 5
+
+/* luma intra prediction modes */
+
+#define DC_PRED 0
+#define PLANE_PRED 1
+#define BI_PRED 2
+#define VERT_PRED 12
+#define HOR_PRED 24
+
+
+/* chroma intra prediction modes */
+#define DM_PRED_C 0
+#define DC_PRED_C 1
+#define HOR_PRED_C 2
+#define VERT_PRED_C 3
+#define BI_PRED_C 4
+
+#define EOS 1 /* !< End Of Sequence */
+ /* !< Start Of Picture */
+#define SOP 2
+
+#define DECODING_OK 0
+#define SEARCH_SYNC 1
+#define DECODE_MB 1
+
+#ifndef max
+ /* !< Macro returning max value */
+#define max(a, b) ((a) > (b) ? (a) : (b))
+ /* !< Macro returning min value */
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+
+#define XY_MIN_PMV 1
+#if XY_MIN_PMV
+#define MVPRED_xy_MIN 0
+#else
+#define MVPRED_MEDIAN 0
+#endif
+#define MVPRED_L 1
+#define MVPRED_U 2
+#define MVPRED_UR 3
+
+#define DUAL 4
+#define FORWARD 0
+#define BACKWARD 1
+#define SYM 2
+#define BID 3
+#define INTRA -1
+
+#define BUF_CYCLE 5
+
+#define ROI_M3264 1 /* ROI Information Encoding */
+
+#define PicExtensionData 1
+
+
+#define REF_OUTPUT 1 /* M3337 */
+
+
+/* MV scaling 14 bit */
+#define MULTI 16384
+#define HALF_MULTI 8192
+#define OFFSET 14
+/* end of MV scaling */
+ /* store the middle pixel's mv in a motion information unit */
+#define MV_DECIMATION_FACTOR 4
+
+/* BUGFIX_AVAILABILITY_INTRA */
+#define NEIGHBOR_INTRA_LEFT 0
+#define NEIGHBOR_INTRA_UP 1
+#define NEIGHBOR_INTRA_UP_RIGHT 2
+#define NEIGHBOR_INTRA_UP_LEFT 3
+#define NEIGHBOR_INTRA_LEFT_DOWN 4
+/* end of BUGFIX_AVAILABILITY_INTRA */
+
+/* end #include "define.h" */
+
+/*#include "commonStructures.h"*/
+
+/*typedef uint16_t byte;*/ /* !< byte type definition */
+#define byte uint16_t
+#define pel_t byte
+
+enum BitCountType_e {
+ BITS_HEADER,
+ BITS_TOTAL_MB,
+ BITS_MB_MODE,
+ BITS_INTER_MB,
+ BITS_CBP_MB,
+ BITS_CBP01_MB,
+ BITS_COEFF_Y_MB,
+ BITS_COEFF_UV_MB,
+ BITS_DELTA_QUANT_MB,
+ BITS_SAO_MB,
+ MAX_BITCOUNTER_MB
+};
+
+
+enum SAOEOClasses {
+/* EO Groups, the assignments depended on
+how you implement the edgeType calculation */
+ SAO_CLASS_EO_FULL_VALLEY = 0,
+ SAO_CLASS_EO_HALF_VALLEY = 1,
+ SAO_CLASS_EO_PLAIN = 2,
+ SAO_CLASS_EO_HALF_PEAK = 3,
+ SAO_CLASS_EO_FULL_PEAK = 4,
+ SAO_CLASS_BO = 5,
+ NUM_SAO_EO_CLASSES = SAO_CLASS_BO,
+ NUM_SAO_OFFSET
+};
+
+struct SAOstatdata {
+ int32_t diff[MAX_NUM_SAO_CLASSES];
+ int32_t count[MAX_NUM_SAO_CLASSES];
+};
+
+struct CopyRight_s {
+ int32_t extension_id;
+ int32_t copyright_flag;
+ int32_t copyright_id;
+ int32_t original_or_copy;
+ int32_t reserved;
+ int32_t copyright_number;
+};
+
+struct CameraParamters_s {
+ int32_t reserved;
+ int32_t camera_id;
+ int32_t height_of_image_device;
+ int32_t focal_length;
+ int32_t f_number;
+ int32_t vertical_angle_of_view;
+ int32_t camera_position_x;
+ int32_t camera_position_y;
+ int32_t camera_position_z;
+ int32_t camera_direction_x;
+ int32_t camera_direction_y;
+ int32_t camera_direction_z;
+ int32_t image_plane_vertical_x;
+ int32_t image_plane_vertical_y;
+ int32_t image_plane_vertical_z;
+};
+
+/* ! SNRParameters */
+struct SNRParameters_s {
+ double snr_y; /* !< current Y SNR */
+ double snr_u; /* !< current U SNR */
+ double snr_v; /* !< current V SNR */
+ double snr_y1; /* !< SNR Y(dB) first frame */
+ double snr_u1; /* !< SNR U(dB) first frame */
+ double snr_v1; /* !< SNR V(dB) first frame */
+ double snr_ya; /* !< Average SNR Y(dB) remaining frames */
+ double snr_ua; /* !< Average SNR U(dB) remaining frames */
+ double snr_va; /* !< Average SNR V(dB) remaining frames */
+#if INTERLACE_CODING
+ double i_snr_ya; /* !< current Y SNR */
+ double i_snr_ua; /* !< current U SNR */
+ double i_snr_va; /* !< current V SNR */
+#endif
+};
+
+/* signal to noise ratio parameters */
+
+/* ! codingUnit */
+struct codingUnit {
+ uint32_t ui_MbBitSize;
+ int32_t uiBitSize; /* size of MB */
+ /* !< number of current syntax element */
+ int32_t currSEnr;
+ int32_t slice_nr;
+ int32_t delta_quant; /* !< for rate control */
+ int32_t delta_qp;
+ int32_t qp;
+ int32_t bitcounter[MAX_BITCOUNTER_MB];
+ struct codingUnit
+ *mb_available[3][3]; /*!< pointer to neighboring MBs
+ in a 3x3 window of current MB, which is located at [1][1] \n
+ NULL pointer identifies neighboring MBs which are unavailable */
+ /* some storage of codingUnit syntax elements for global access */
+ int32_t cuType;
+ int32_t weighted_skipmode;
+
+ int32_t md_directskip_mode;
+
+ int32_t trans_size;
+ int
+ /* !< indices correspond to [forw,backw][block_y][block_x][x,y, dmh] */
+ mvd[2][BLOCK_MULTIPLE][BLOCK_MULTIPLE][3];
+
+ int32_t intra_pred_modes[BLOCK_MULTIPLE * BLOCK_MULTIPLE];
+ int32_t real_intra_pred_modes[BLOCK_MULTIPLE * BLOCK_MULTIPLE];
+ int32_t l_ipred_mode;
+ int32_t cbp, cbp_blk;
+ uint32_t cbp_bits;
+
+ int32_t b8mode[4];
+ int32_t b8pdir[4];
+ /* !< chroma intra prediction mode */
+ int32_t c_ipred_mode;
+
+ /* !< pointer to neighboring MB (AEC) */
+ struct codingUnit *mb_available_up;
+ /* !< pointer to neighboring MB (AEC) */
+ struct codingUnit *mb_available_left;
+ int32_t mbAddrA, mbAddrB, mbAddrC, mbAddrD;
+ /* !<added by mz, 2008.04 */
+ int32_t slice_set_index;
+ /* added by mz, 2008.04 */
+ int32_t slice_header_flag;
+ int32_t sliceqp; /* added by mz, 2008.04 */
+#if MB_DQP
+ int32_t previouse_qp;
+ int32_t left_cu_qp;
+#endif
+ int32_t block_available_up;
+ int32_t block_available_left;
+
+};
+
+
+/* image parameters */
+struct syntaxelement;
+struct slice;
+struct alfdatapart;
+struct SAOBlkParam_s {
+ int32_t modeIdc; /* NEW, MERGE, OFF */
+ /* NEW: EO_0, EO_90, EO_135, EO_45, BO. MERGE: left, above */
+ int32_t typeIdc;
+ int32_t startBand; /* BO: starting band index */
+ int32_t startBand2;
+ int32_t deltaband;
+ int32_t offset[MAX_NUM_SAO_CLASSES];
+};
+struct ALFParam_s {
+ int32_t alf_flag;
+ int32_t num_coeff;
+ int32_t filters_per_group;
+ int32_t componentID;
+ int32_t filterPattern[16]; /* *filterPattern; */
+ int32_t coeffmulti[16][9]; /* **coeffmulti; */
+};
+
+enum ALFComponentID {
+ ALF_Y = 0,
+ ALF_Cb,
+ ALF_Cr,
+ NUM_ALF_COMPONENT
+};
+struct ALF_APS_s {
+ int32_t usedflag;
+ int32_t cur_number;
+ int32_t max_number;
+ struct ALFParam_s alf_par[NUM_ALF_COMPONENT];
+};
+
+
+/* ------------------------------------------------------
+ * frame data
+ */
+struct avs2_frame_s {
+ int32_t imgcoi_ref;
+ byte * *referenceFrame[3];
+ int32_t **refbuf;
+ int32_t ***mvbuf;
+#if 0
+ double saorate[NUM_SAO_COMPONENTS];
+#endif
+ byte ***ref;
+
+ int32_t imgtr_fwRefDistance;
+ int32_t refered_by_others;
+ int32_t is_output;
+ int32_t to_prepare_disp;
+#if M3480_TEMPORAL_SCALABLE
+ /* temporal level setted in configure file */
+ int32_t temporal_id;
+#endif
+ byte **oneForthRefY;
+#if FIX_MAX_REF
+ int32_t ref_poc[MAXREF];
+#else
+ int32_t ref_poc[4];
+#endif
+#ifdef AML
+ int32_t index;
+ int32_t mmu_alloc_flag;
+ int32_t lcu_size_log2;
+ /*uint32_t header_adr;*/
+ uint32_t mc_y_adr;
+ uint32_t mc_u_v_adr;
+ uint32_t mc_canvas_y;
+ uint32_t mc_canvas_u_v;
+ uint32_t mpred_mv_wr_start_addr;
+ uint8_t bg_flag;
+ /**/
+ unsigned long header_adr;
+ int buf_size;
+ int lcu_total;
+ int comp_body_size;
+ uint32_t dw_y_adr;
+ uint32_t dw_u_v_adr;
+ int y_canvas_index;
+ int uv_canvas_index;
+ struct canvas_config_s canvas_config[2];
+ int double_write_mode;
+ int bit_depth;
+ unsigned long cma_alloc_addr;
+ int BUF_index;
+ int pic_w;
+ int pic_h;
+ int stream_offset;
+ u32 pts;
+ u64 pts64;
+ /**/
+ int vf_ref;
+ int decode_idx;
+ int slice_type;
+ int32_t imgtr_fwRefDistance_bak;
+ int32_t error_mark;
+ int32_t decoded_lcu;
+#endif
+#ifndef MV_USE_FIXED_BUF
+ int mv_buf_index;
+#endif
+
+ /* picture qos infomation*/
+ int max_qp;
+ int avg_qp;
+ int min_qp;
+ int max_skip;
+ int avg_skip;
+ int min_skip;
+ int max_mv;
+ int min_mv;
+ int avg_mv;
+
+ u32 hw_decode_time;
+ u32 frame_size; // For frame base mode
+};
+
+
+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..3bad1eb
--- /dev/null
+++ b/drivers/frame_provider/decoder/avs2/vavs2.c
@@ -0,0 +1,8025 @@
+ /*
+ * 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 "../../../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 <linux/amlogic/tee.h>
+
+
+#define I_ONLY_SUPPORT
+#define MIX_STREAM_SUPPORT
+#define G12A_BRINGUP_DEBUG
+#define CONSTRAIN_MAX_BUF_NUM
+
+#include "vavs2.h"
+#define HEVC_SHIFT_LENGTH_PROTECT 0x313a
+#define HEVC_MPRED_CTRL9 0x325b
+#define HEVC_DBLK_CFGD 0x350d
+
+
+#define HEVC_CM_HEADER_START_ADDR 0x3628
+#define HEVC_DBLK_CFGB 0x350b
+#define HEVCD_MPP_ANC2AXI_TBL_DATA 0x3464
+#define HEVC_SAO_MMU_VH1_ADDR 0x363b
+#define HEVC_SAO_MMU_VH0_ADDR 0x363a
+
+
+/*
+ * AVS2_DEC_STATUS define
+*/
+/*internal*/
+#define AVS2_DEC_IDLE 0
+#define AVS2_SEQUENCE 1
+#define AVS2_I_PICTURE 2
+#define AVS2_PB_PICTURE 3
+#define AVS2_DISCARD_STARTCODE 4
+#define AVS2_DISCARD_NAL 4
+
+#define AVS2_SLICE_DECODING 6
+
+#define SWAP_IN_CMD 0x10
+#define SWAP_OUT_CMD 0x11
+#define SWAP_OUTIN_CMD 0x12
+#define SWAP_DONE 0x13
+#define SWAP_POST_INIT 0x14
+
+/*head*/
+#define AVS2_HEAD_SEQ_READY 0x21
+#define AVS2_HEAD_PIC_I_READY 0x22
+#define AVS2_HEAD_PIC_PB_READY 0x23
+#define AVS2_HEAD_SEQ_END_READY 0x24
+#define AVS2_STARTCODE_SEARCH_DONE 0x25
+
+/*pic done*/
+#define HEVC_DECPIC_DATA_DONE 0x30
+#define HEVC_DECPIC_DATA_ERROR 0x31
+#define HEVC_NAL_DECODE_DONE 0x32
+#define AVS2_DECODE_BUFEMPTY 0x33
+#define AVS2_DECODE_TIMEOUT 0x34
+#define AVS2_DECODE_OVER_SIZE 0x35
+#define AVS2_EOS 0x36
+
+/*cmd*/
+#define AVS2_10B_DISCARD_NAL 0xf0
+#define AVS2_SEARCH_NEW_PIC 0xf1
+#define AVS2_ACTION_ERROR 0xfe
+#define HEVC_ACTION_ERROR 0xfe
+#define AVS2_ACTION_DONE 0xff
+/*AVS2_DEC_STATUS end*/
+
+
+#define VF_POOL_SIZE 32
+
+#undef pr_info
+#define pr_info printk
+
+#define DECODE_MODE_SINGLE (0 | (0x80 << 24))
+#define DECODE_MODE_MULTI_STREAMBASE (1 | (0x80 << 24))
+#define DECODE_MODE_MULTI_FRAMEBASE (2 | (0x80 << 24))
+
+
+#define VP9_TRIGGER_FRAME_DONE 0x100
+#define VP9_TRIGGER_FRAME_ENABLE 0x200
+
+/*#define MV_MEM_UNIT 0x240*/
+#define MV_MEM_UNIT 0x200
+/*---------------------------------------------------
+ Include "parser_cmd.h"
+---------------------------------------------------*/
+#define PARSER_CMD_SKIP_CFG_0 0x0000090b
+
+#define PARSER_CMD_SKIP_CFG_1 0x1b14140f
+
+#define PARSER_CMD_SKIP_CFG_2 0x001b1910
+
+
+#define PARSER_CMD_NUMBER 37
+
+static unsigned short parser_cmd[PARSER_CMD_NUMBER] = {
+0x0401,
+0x8401,
+0x0800,
+0x0402,
+0x9002,
+0x1423,
+0x8CC3,
+0x1423,
+0x8804,
+0x9825,
+0x0800,
+0x04FE,
+0x8406,
+0x8411,
+0x1800,
+0x8408,
+0x8409,
+0x8C2A,
+0x9C2B,
+0x1C00,
+0x840F,
+0x8407,
+0x8000,
+0x8408,
+0x2000,
+0xA800,
+0x8410,
+0x04DE,
+0x840C,
+0x840D,
+0xAC00,
+0xA000,
+0x08C0,
+0x08E0,
+0xA40E,
+0xFC00,
+0x7C00
+};
+
+static int32_t g_WqMDefault4x4[16] = {
+ 64, 64, 64, 68,
+ 64, 64, 68, 72,
+ 64, 68, 76, 80,
+ 72, 76, 84, 96
+};
+
+
+static int32_t g_WqMDefault8x8[64] = {
+ 64, 64, 64, 64, 68, 68, 72, 76,
+ 64, 64, 64, 68, 72, 76, 84, 92,
+ 64, 64, 68, 72, 76, 80, 88, 100,
+ 64, 68, 72, 80, 84, 92, 100, 112,
+ 68, 72, 80, 84, 92, 104, 112, 128,
+ 76, 80, 84, 92, 104, 116, 132, 152,
+ 96, 100, 104, 116, 124, 140, 164, 188,
+ 104, 108, 116, 128, 152, 172, 192, 216
+};
+/*#define HEVC_PIC_STRUCT_SUPPORT*/
+/* to remove, fix build error */
+
+/*#define CODEC_MM_FLAGS_FOR_VDECODER 0*/
+
+#define MULTI_INSTANCE_SUPPORT
+/* #define ERROR_HANDLE_DEBUG */
+
+#ifndef STAT_KTHREAD
+#define STAT_KTHREAD 0x40
+#endif
+
+#ifdef MULTI_INSTANCE_SUPPORT
+#define MAX_DECODE_INSTANCE_NUM 12
+#define MULTI_DRIVER_NAME "ammvdec_avs2"
+
+#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 unsigned int max_decode_instance_num
+ = MAX_DECODE_INSTANCE_NUM;
+static unsigned int decode_frame_count[MAX_DECODE_INSTANCE_NUM];
+static unsigned int display_frame_count[MAX_DECODE_INSTANCE_NUM];
+static unsigned int max_process_time[MAX_DECODE_INSTANCE_NUM];
+static unsigned int run_count[MAX_DECODE_INSTANCE_NUM];
+static unsigned int input_empty[MAX_DECODE_INSTANCE_NUM];
+static unsigned int not_run_ready[MAX_DECODE_INSTANCE_NUM];
+
+#ifdef G12A_BRINGUP_DEBUG
+static u32 decode_timeout_val = 200;
+#else
+static u32 decode_timeout_val = 200;
+#endif
+static int start_decode_buf_level = 0x8000;
+#ifdef AVS2_10B_MMU
+static u32 work_buf_size; /* = 24 * 1024 * 1024*/;
+#else
+static u32 work_buf_size = 32 * 1024 * 1024;
+#endif
+
+static u32 mv_buf_margin;
+static int pre_decode_buf_level = 0x1000;
+static u32 again_threshold;
+
+
+/* DOUBLE_WRITE_MODE is enabled only when NV21 8 bit output is needed */
+/* double_write_mode:
+ * 0, no double write;
+ * 1, 1:1 ratio;
+ * 2, (1/4):(1/4) ratio;
+ * 3, (1/4):(1/4) ratio, with both compressed frame included
+ * 4, (1/2):(1/2) ratio;
+ * 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(unsigned long arg);
+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
+
+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
+
+
+
+typedef unsigned int u32;
+typedef unsigned short u16;
+
+#define AVS2_DBG_BUFMGR 0x01
+#define AVS2_DBG_BUFMGR_MORE 0x02
+#define AVS2_DBG_BUFMGR_DETAIL 0x04
+#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_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 DEBUG_REG
+#ifdef DEBUG_REG
+static void WRITE_VREG_DBG2(unsigned adr, unsigned val)
+{
+ if (debug & AVS2_DBG_REG)
+ pr_info("%s(%x, %x)\n", __func__, adr, val);
+ if (adr != 0)
+ WRITE_VREG(adr, val);
+}
+
+#undef WRITE_VREG
+#define WRITE_VREG WRITE_VREG_DBG2
+#endif
+
+
+//#ifdef AVS2_10B_MMU
+//#define MMU_COMPRESS_HEADER_SIZE 0x48000
+//#define MMU_COMPRESS_8K_HEADER_SIZE 0x48000*4
+//#endif
+#define MMU_COMPRESS_HEADER_SIZE_1080P 0x10000
+#define MMU_COMPRESS_HEADER_SIZE_4K 0x48000
+#define MMU_COMPRESS_HEADER_SIZE_8K 0x120000
+
+#define INVALID_IDX -1 /* Invalid buffer index.*/
+
+
+#define FRAME_BUFFERS (AVS2_MAX_BUFFER_NUM)
+#define HEADER_FRAME_BUFFERS (FRAME_BUFFERS)
+#define MAX_BUF_NUM (FRAME_BUFFERS)
+
+#define FRAME_CONTEXTS_LOG2 2
+#define FRAME_CONTEXTS (1 << FRAME_CONTEXTS_LOG2)
+/*buffer + header buffer + workspace*/
+#undef MV_USE_FIXED_BUF
+#ifdef MV_USE_FIXED_BUF
+#define MAX_BMMU_BUFFER_NUM ((FRAME_BUFFERS + HEADER_FRAME_BUFFERS + 1)+1)
+#define VF_BUFFER_IDX(n) (n)
+#define HEADER_BUFFER_IDX(n) (FRAME_BUFFERS + n+1)
+#define WORK_SPACE_BUF_ID (FRAME_BUFFERS + HEADER_FRAME_BUFFERS+1)
+#else
+#define MAX_BMMU_BUFFER_NUM (((FRAME_BUFFERS*2)+HEADER_FRAME_BUFFERS+1)+1)
+#define VF_BUFFER_IDX(n) (n)
+#define HEADER_BUFFER_IDX(n) (FRAME_BUFFERS + n+1)
+#define MV_BUFFER_IDX(n) ((FRAME_BUFFERS * 2) + n+1)
+#define WORK_SPACE_BUF_ID ((FRAME_BUFFERS * 2) + HEADER_FRAME_BUFFERS+1)
+#endif
+
+#define CO_MV_BUF_SIZE_1080P 0x3fc00
+#define CO_MV_BUF_SIZE_4K 0x120000
+#define CO_MV_BUF_SIZE_8K 0x480000
+/*
+static void set_canvas(struct AVS2Decoder_s *dec,
+ struct avs2_frame_s *pic);
+int avs2_prepare_display_buf(struct AVS2Decoder_s *dec,
+ int pos);
+*/
+
+
+struct buff_s {
+ u32 buf_start;
+ u32 buf_size;
+ u32 buf_end;
+};
+
+struct BuffInfo_s {
+ u32 max_width;
+ u32 max_height;
+ u32 start_adr;
+ u32 end_adr;
+ struct buff_s ipp;
+ struct buff_s sao_abv;
+ struct buff_s sao_vb;
+ struct buff_s short_term_rps;
+ struct buff_s rcs;
+ struct buff_s sps;
+ struct buff_s pps;
+ struct buff_s sao_up;
+ struct buff_s swap_buf;
+ struct buff_s swap_buf2;
+ struct buff_s scalelut;
+ struct buff_s dblk_para;
+ struct buff_s dblk_data;
+ struct buff_s dblk_data2;
+#ifdef AVS2_10B_MMU
+ struct buff_s mmu_vbh;
+ struct buff_s cm_header;
+#endif
+ struct buff_s mpred_above;
+#ifdef MV_USE_FIXED_BUF
+ struct buff_s mpred_mv;
+#endif
+ struct buff_s rpm;
+ struct buff_s lmem;
+};
+
+#define DEC_RESULT_NONE 0
+#define DEC_RESULT_DONE 1
+#define DEC_RESULT_AGAIN 2
+#define DEC_RESULT_CONFIG_PARAM 3
+#define DEC_RESULT_ERROR 4
+#define DEC_INIT_PICLIST 5
+#define DEC_UNINIT_PICLIST 6
+#define DEC_RESULT_GET_DATA 7
+#define DEC_RESULT_GET_DATA_RETRY 8
+#define DEC_RESULT_EOS 9
+#define DEC_RESULT_FORCE_EXIT 10
+
+static void avs2_work(struct work_struct *work);
+struct loop_filter_info_n;
+struct loopfilter;
+struct segmentation;
+
+struct AVS2Decoder_s {
+ int pic_list_init_flag;
+ unsigned char index;
+ spinlock_t buffer_lock;
+ struct device *cma_dev;
+ struct platform_device *platform_dev;
+ void (*vdec_cb)(struct vdec_s *, void *);
+ void *vdec_cb_arg;
+ struct vframe_chunk_s *chunk;
+ int dec_result;
+ struct work_struct work;
+ u32 start_shift_bytes;
+
+ struct BuffInfo_s work_space_buf_store;
+ unsigned long buf_start;
+ u32 buf_size;
+ u32 cma_alloc_count;
+ unsigned long cma_alloc_addr;
+ uint8_t eos;
+ unsigned long int start_process_time;
+ unsigned last_lcu_idx;
+ int decode_timeout_count;
+ unsigned timeout_num;
+
+ int double_write_mode;
+
+ unsigned char m_ins_flag;
+ char *provider_name;
+ int frame_count;
+ u32 stat;
+ struct timer_list timer;
+ u32 frame_dur;
+ u32 frame_ar;
+ 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;
+
+#if 1
+ /*AVS2_10B_MMU*/
+ void *frame_mmu_map_addr;
+ dma_addr_t frame_mmu_map_phy_addr;
+#endif
+ unsigned int use_cma_flag;
+
+ struct BUF_s m_BUF[MAX_BUF_NUM];
+ struct MVBUF_s m_mv_BUF[MAX_BUF_NUM];
+ u32 used_buf_num;
+ DECLARE_KFIFO(newframe_q, struct vframe_s *, VF_POOL_SIZE);
+ DECLARE_KFIFO(display_q, struct vframe_s *, VF_POOL_SIZE);
+ DECLARE_KFIFO(pending_q, struct vframe_s *, VF_POOL_SIZE);
+ struct vframe_s vfpool[VF_POOL_SIZE];
+ 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;
+ char vdec_name[32];
+ char pts_name[32];
+ char new_q_name[32];
+ char disp_q_name[32];
+};
+
+static int compute_losless_comp_body_size(
+ struct AVS2Decoder_s *dec, int width, int height,
+ uint8_t is_bit_depth_10);
+
+static int avs2_print(struct AVS2Decoder_s *dec,
+ int flag, const char *fmt, ...)
+{
+#define HEVC_PRINT_BUF 256
+ unsigned char buf[HEVC_PRINT_BUF];
+ int len = 0;
+ if (dec == NULL ||
+ (flag == 0) ||
+ (debug & flag)) {
+ va_list args;
+ va_start(args, fmt);
+ if (dec)
+ len = sprintf(buf, "[%d]", dec->index);
+ vsnprintf(buf + len, HEVC_PRINT_BUF - len, fmt, args);
+ pr_info("%s", buf);
+ va_end(args);
+ }
+ return 0;
+}
+
+static int avs2_print_cont(struct AVS2Decoder_s *dec,
+ int flag, const char *fmt, ...)
+{
+ unsigned char buf[HEVC_PRINT_BUF];
+ int len = 0;
+ if (dec == NULL ||
+ (flag == 0) ||
+ (debug & flag)) {
+ va_list args;
+ va_start(args, fmt);
+ vsnprintf(buf + len, HEVC_PRINT_BUF - len, fmt, args);
+ pr_info("%s", buf);
+ va_end(args);
+ }
+ return 0;
+}
+
+#define PROB_SIZE (496 * 2 * 4)
+#define PROB_BUF_SIZE (0x5000)
+#define COUNT_BUF_SIZE (0x300 * 4 * 4)
+/*compute_losless_comp_body_size(4096, 2304, 1) = 18874368(0x1200000)*/
+#define MAX_FRAME_4K_NUM 0x1200
+#define MAX_FRAME_8K_NUM 0x4800
+#define MAX_SIZE_4K (4096 * 2304)
+#define IS_8K_SIZE(w, h) (((w) * (h)) > MAX_SIZE_4K)
+#define IS_4K_SIZE(w, h) (((w) * (h)) > (1920*1088))
+
+static int get_frame_mmu_map_size(struct AVS2Decoder_s *dec)
+{
+ if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
+ (IS_8K_SIZE(dec->init_pic_w, dec->init_pic_h)))
+ return (MAX_FRAME_8K_NUM * 4);
+ return (MAX_FRAME_4K_NUM * 4);
+}
+
+static int get_compress_header_size(struct AVS2Decoder_s *dec)
+{
+ if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
+ (IS_8K_SIZE(dec->init_pic_w, dec->init_pic_h)))
+ return MMU_COMPRESS_HEADER_SIZE_8K;
+ else if (IS_4K_SIZE(dec->init_pic_w, dec->init_pic_h))
+ return MMU_COMPRESS_HEADER_SIZE_4K;
+ return MMU_COMPRESS_HEADER_SIZE_1080P;
+}
+
+static void reset_process_time(struct AVS2Decoder_s *dec)
+{
+ if (dec->start_process_time) {
+ unsigned process_time =
+ 1000 * (jiffies - dec->start_process_time) / HZ;
+ dec->start_process_time = 0;
+ if (process_time > max_process_time[dec->index])
+ max_process_time[dec->index] = process_time;
+ }
+}
+
+static void start_process_time(struct AVS2Decoder_s *dec)
+{
+ dec->start_process_time = jiffies;
+ dec->decode_timeout_count = 0;
+ dec->last_lcu_idx = 0;
+}
+
+static void update_decoded_pic(struct AVS2Decoder_s *dec);
+
+static void timeout_process(struct AVS2Decoder_s *dec)
+{
+ struct avs2_decoder *avs2_dec = &dec->avs2_dec;
+ struct avs2_frame_s *cur_pic = avs2_dec->hc.cur_pic;
+ dec->timeout_num++;
+ amhevc_stop();
+ avs2_print(dec,
+ 0, "%s decoder timeout\n", __func__);
+ if (cur_pic)
+ cur_pic->error_mark = 1;
+ dec->dec_result = DEC_RESULT_DONE;
+ update_decoded_pic(dec);
+ reset_process_time(dec);
+ vdec_schedule_work(&dec->work);
+}
+
+static u32 get_valid_double_write_mode(struct AVS2Decoder_s *dec)
+{
+ return (dec->m_ins_flag &&
+ ((double_write_mode & 0x80000000) == 0)) ?
+ dec->double_write_mode :
+ (double_write_mode & 0x7fffffff);
+}
+
+static int get_double_write_mode(struct AVS2Decoder_s *dec)
+{
+ u32 valid_dw_mode = get_valid_double_write_mode(dec);
+ int w = dec->avs2_dec.img.width;
+ int h = dec->avs2_dec.img.height;
+ u32 dw = 0x1; /*1:1*/
+ switch (valid_dw_mode) {
+ case 0x100:
+ if (w > 1920 && h > 1088)
+ dw = 0x4; /*1:2*/
+ break;
+ case 0x200:
+ if (w > 1920 && h > 1088)
+ dw = 0x2; /*1:4*/
+ break;
+ case 0x300:
+ if (w > 1280 && h > 720)
+ dw = 0x4; /*1:2*/
+ break;
+ default:
+ dw = valid_dw_mode;
+ break;
+ }
+ return dw;
+}
+
+/* for double write buf alloc */
+static int get_double_write_mode_init(struct AVS2Decoder_s *dec)
+{
+ u32 valid_dw_mode = get_valid_double_write_mode(dec);
+ u32 dw;
+ int w = dec->init_pic_w;
+ int h = dec->init_pic_h;
+
+ dw = 0x1; /*1:1*/
+ switch (valid_dw_mode) {
+ case 0x100:
+ if (w > 1920 && h > 1088)
+ dw = 0x4; /*1:2*/
+ break;
+ case 0x200:
+ if (w > 1920 && h > 1088)
+ dw = 0x2; /*1:4*/
+ break;
+ case 0x300:
+ if (w > 1280 && h > 720)
+ dw = 0x4; /*1:2*/
+ break;
+ default:
+ dw = valid_dw_mode;
+ break;
+ }
+ return dw;
+}
+
+static int get_double_write_ratio(struct AVS2Decoder_s *dec,
+ int dw_mode)
+{
+ int ratio = 1;
+ if ((dw_mode == 2) ||
+ (dw_mode == 3))
+ ratio = 4;
+ else if (dw_mode == 4)
+ ratio = 2;
+ return ratio;
+}
+
+//#define MAX_4K_NUM 0x1200
+#ifdef AVS2_10B_MMU
+int avs2_alloc_mmu(
+ struct AVS2Decoder_s *dec,
+ int cur_buf_idx,
+ int pic_width,
+ int pic_height,
+ unsigned short bit_depth,
+ unsigned int *mmu_index_adr)
+{
+ int bit_depth_10 = (bit_depth == AVS2_BITS_10);
+ int picture_size;
+ int cur_mmu_4k_number, max_frame_num;
+#ifdef DYNAMIC_ALLOC_HEAD
+ unsigned long buf_addr;
+ struct avs2_frame_s *pic = dec->avs2_dec.hc.cur_pic;
+ if (pic->header_adr == 0) {
+ if (decoder_bmmu_box_alloc_buf_phy
+ (dec->bmmu_box,
+ HEADER_BUFFER_IDX(cur_buf_idx),
+ get_compress_header_size(dec),
+ DRIVER_HEADER_NAME,
+ &buf_addr) < 0){
+ avs2_print(dec, 0,
+ "%s malloc compress header failed %d\n",
+ DRIVER_HEADER_NAME, cur_buf_idx);
+ dec->fatal_error |= DECODER_FATAL_ERROR_NO_MEM;
+ return -1;
+ } else
+ pic->header_adr = buf_addr;
+ }
+#endif
+
+ picture_size = compute_losless_comp_body_size(
+ dec, pic_width, pic_height,
+ bit_depth_10);
+ cur_mmu_4k_number = ((picture_size + (1 << 12) - 1) >> 12);
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1)
+ max_frame_num = MAX_FRAME_8K_NUM;
+ else
+ max_frame_num = MAX_FRAME_4K_NUM;
+ if (cur_mmu_4k_number > max_frame_num) {
+ pr_err("over max !! cur_mmu_4k_number 0x%x width %d height %d\n",
+ cur_mmu_4k_number, pic_width, pic_height);
+ return -1;
+ }
+ return decoder_mmu_box_alloc_idx(
+ dec->mmu_box,
+ cur_buf_idx,
+ cur_mmu_4k_number,
+ mmu_index_adr);
+}
+#endif
+
+#if 0
+/*ndef MV_USE_FIXED_BUF*/
+static void dealloc_mv_bufs(struct AVS2Decoder_s *dec)
+{
+ int i;
+ for (i = 0; i < FRAME_BUFFERS; i++) {
+ if (dec->m_mv_BUF[i].start_adr) {
+ if (debug)
+ pr_info(
+ "dealloc mv buf(%d) adr %ld size 0x%x used_flag %d\n",
+ i, dec->m_mv_BUF[i].start_adr,
+ dec->m_mv_BUF[i].size,
+ dec->m_mv_BUF[i].used_flag);
+ decoder_bmmu_box_free_idx(
+ dec->bmmu_box,
+ MV_BUFFER_IDX(i));
+ dec->m_mv_BUF[i].start_adr = 0;
+ dec->m_mv_BUF[i].size = 0;
+ dec->m_mv_BUF[i].used_flag = 0;
+ }
+ }
+}
+
+static int alloc_mv_buf(struct AVS2Decoder_s *dec,
+ int i, int size)
+{
+ int ret = 0;
+ if (decoder_bmmu_box_alloc_buf_phy
+ (dec->bmmu_box,
+ MV_BUFFER_IDX(i), size,
+ DRIVER_NAME,
+ &dec->m_mv_BUF[i].start_adr) < 0) {
+ dec->m_mv_BUF[i].start_adr = 0;
+ ret = -1;
+ } else {
+ dec->m_mv_BUF[i].size = size;
+ dec->m_mv_BUF[i].used_flag = 0;
+ ret = 0;
+ if (debug) {
+ pr_info(
+ "MV Buffer %d: start_adr %p size %x\n",
+ i,
+ (void *)dec->m_mv_BUF[i].start_adr,
+ dec->m_mv_BUF[i].size);
+ }
+ }
+ return ret;
+}
+
+static int init_mv_buf_list(struct AVS2Decoder_s *dec)
+{
+ int i;
+ int ret = 0;
+ int count = FRAME_BUFFERS;
+ int pic_width = dec->init_pic_w;
+ int pic_height = dec->init_pic_h;
+ int lcu_size = 64; /*fixed 64*/
+ int pic_width_64 = (pic_width + 63) & (~0x3f);
+ int pic_height_32 = (pic_height + 31) & (~0x1f);
+ int pic_width_lcu = (pic_width_64 % lcu_size) ?
+ pic_width_64 / lcu_size + 1
+ : pic_width_64 / lcu_size;
+ int pic_height_lcu = (pic_height_32 % lcu_size) ?
+ pic_height_32 / lcu_size + 1
+ : pic_height_32 / lcu_size;
+ int lcu_total = pic_width_lcu * pic_height_lcu;
+ int size = ((lcu_total * MV_MEM_UNIT) + 0xffff) &
+ (~0xffff);
+ if (mv_buf_margin > 0)
+ count = dec->avs2_dec.ref_maxbuffer + mv_buf_margin;
+ for (i = 0; i < count; i++) {
+ if (alloc_mv_buf(dec, i, size) < 0) {
+ ret = -1;
+ break;
+ }
+ }
+ return ret;
+}
+#if 0
+
+static int get_mv_buf(struct AVS2Decoder_s *dec,
+ struct avs2_frame_s *pic)
+{
+ int i;
+ int ret = -1;
+ for (i = 0; i < FRAME_BUFFERS; i++) {
+ if (dec->m_mv_BUF[i].start_adr &&
+ dec->m_mv_BUF[i].used_flag == 0) {
+ dec->m_mv_BUF[i].used_flag = 1;
+ ret = i;
+ break;
+ }
+ }
+
+ if (ret >= 0) {
+ pic->mv_buf_index = ret;
+ pic->mpred_mv_wr_start_addr =
+ (dec->m_mv_BUF[ret].start_adr + 0xffff) &
+ (~0xffff);
+ if (debug & AVS2_DBG_BUFMGR_MORE)
+ pr_info(
+ "%s => %d (%d) size 0x%x\n",
+ __func__, ret,
+ pic->mpred_mv_wr_start_addr,
+ dec->m_mv_BUF[ret].size);
+ } else {
+ pr_info(
+ "%s: Error, mv buf is not enough\n",
+ __func__);
+ }
+ return ret;
+}
+
+static void put_mv_buf(struct AVS2Decoder_s *dec,
+ struct avs2_frame_s *pic)
+{
+ int i = pic->mv_buf_index;
+ if (i >= FRAME_BUFFERS) {
+ if (debug & AVS2_DBG_BUFMGR_MORE)
+ pr_info(
+ "%s: index %d beyond range\n",
+ __func__, i);
+ return;
+ }
+ if (debug & AVS2_DBG_BUFMGR_MORE)
+ pr_info(
+ "%s(%d): used_flag(%d)\n",
+ __func__, i,
+ dec->m_mv_BUF[i].used_flag);
+
+ pic->mv_buf_index = -1;
+ if (dec->m_mv_BUF[i].start_adr &&
+ dec->m_mv_BUF[i].used_flag)
+ dec->m_mv_BUF[i].used_flag = 0;
+}
+
+static void put_un_used_mv_bufs(struct AVS2Decoder_s *dec)
+{
+ struct VP9_Common_s *const cm = &dec->common;
+ struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs;
+ int i;
+ for (i = 0; i < dec->used_buf_num; ++i) {
+ if ((frame_bufs[i].ref_count == 0) &&
+ (frame_bufs[i].buf.index != -1) &&
+ (frame_bufs[i].buf.mv_buf_index >= 0)
+ )
+ put_mv_buf(dec, &frame_bufs[i].buf);
+ }
+}
+#endif
+
+#endif
+
+static int get_free_buf_count(struct AVS2Decoder_s *dec)
+{
+ struct avs2_decoder *avs2_dec = &dec->avs2_dec;
+ int i;
+ int count = 0;
+ for (i = 0; i < avs2_dec->ref_maxbuffer; i++) {
+ if ((avs2_dec->fref[i]->imgcoi_ref < -256
+#if 0
+ || abs(avs2_dec->fref[i]->
+ imgtr_fwRefDistance - img->tr) >= 128
+#endif
+ ) && avs2_dec->fref[i]->is_output == -1
+ && avs2_dec->fref[i]->bg_flag == 0
+#ifndef NO_DISPLAY
+ && avs2_dec->fref[i]->vf_ref == 0
+ && avs2_dec->fref[i]->to_prepare_disp == 0
+#endif
+ ) {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+#ifdef CONSTRAIN_MAX_BUF_NUM
+static int get_vf_ref_only_buf_count(struct AVS2Decoder_s *dec)
+{
+ struct avs2_decoder *avs2_dec = &dec->avs2_dec;
+ int i;
+ int count = 0;
+ for (i = 0; i < avs2_dec->ref_maxbuffer; i++) {
+ if ((avs2_dec->fref[i]->imgcoi_ref < -256
+#if 0
+ || abs(avs2_dec->fref[i]->
+ imgtr_fwRefDistance - img->tr) >= 128
+#endif
+ ) && avs2_dec->fref[i]->is_output == -1
+ && avs2_dec->fref[i]->bg_flag == 0
+#ifndef NO_DISPLAY
+ && avs2_dec->fref[i]->vf_ref > 0
+ && avs2_dec->fref[i]->to_prepare_disp == 0
+#endif
+ ) {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+static int get_used_buf_count(struct AVS2Decoder_s *dec)
+{
+ struct avs2_decoder *avs2_dec = &dec->avs2_dec;
+ int i;
+ int count = 0;
+ for (i = 0; i < avs2_dec->ref_maxbuffer; i++) {
+ if ((avs2_dec->fref[i]->imgcoi_ref >= -256
+#if 0
+ || abs(avs2_dec->fref[i]->
+ imgtr_fwRefDistance - img->tr) >= 128
+#endif
+ ) || avs2_dec->fref[i]->is_output != -1
+ || avs2_dec->fref[i]->bg_flag != 0
+#ifndef NO_DISPLAY
+ || avs2_dec->fref[i]->vf_ref != 0
+ || avs2_dec->fref[i]->to_prepare_disp != 0
+#endif
+ ) {
+ count++;
+ }
+ }
+
+ return count;
+}
+#endif
+
+int avs2_bufmgr_init(struct AVS2Decoder_s *dec, struct BuffInfo_s *buf_spec_i,
+ struct buff_s *mc_buf_i) {
+
+ dec->frame_count = 0;
+#ifdef AVS2_10B_MMU
+ dec->used_4k_num = -1;
+ dec->cur_fb_idx_mmu = INVALID_IDX;
+#endif
+
+
+ /* private init */
+ dec->work_space_buf = buf_spec_i;
+#ifndef AVS2_10B_MMU
+ dec->mc_buf = mc_buf_i;
+#endif
+ dec->rpm_addr = NULL;
+ dec->lmem_addr = NULL;
+
+ dec->use_cma_flag = 0;
+ dec->decode_idx = 0;
+ dec->slice_idx = 0;
+ /*int m_uiMaxCUWidth = 1<<7;*/
+ /*int m_uiMaxCUHeight = 1<<7;*/
+ dec->wait_buf = 0;
+ dec->error_flag = 0;
+ dec->skip_PB_before_I = 0;
+
+ dec->pts_mode = PTS_NORMAL;
+ dec->last_pts = 0;
+ dec->last_lookup_pts = 0;
+ dec->last_pts_us64 = 0;
+ dec->last_lookup_pts_us64 = 0;
+ dec->shift_byte_count = 0;
+ dec->shift_byte_count_lo = 0;
+ dec->shift_byte_count_hi = 0;
+ dec->pts_mode_switching_count = 0;
+ dec->pts_mode_recovery_count = 0;
+
+ dec->buf_num = 0;
+
+ dec->bufmgr_error_count = 0;
+ return 0;
+}
+
+
+
+#define HEVC_CM_BODY_START_ADDR 0x3626
+#define HEVC_CM_BODY_LENGTH 0x3627
+#define HEVC_CM_HEADER_LENGTH 0x3629
+#define HEVC_CM_HEADER_OFFSET 0x362b
+
+#define LOSLESS_COMPRESS_MODE
+
+/*#define DECOMP_HEADR_SURGENT*/
+
+static u32 mem_map_mode; /* 0:linear 1:32x32 2:64x32 ; m8baby test1902 */
+static u32 enable_mem_saving = 1;
+static u32 force_w_h;
+
+static u32 force_fps;
+
+
+const u32 avs2_version = 201602101;
+static u32 debug;
+static u32 radr;
+static u32 rval;
+static u32 pop_shorts;
+static u32 dbg_cmd;
+static u32 dbg_skip_decode_index;
+static u32 endian = 0xff0;
+#ifdef ERROR_HANDLE_DEBUG
+static u32 dbg_nal_skip_flag;
+ /* bit[0], skip vps; bit[1], skip sps; bit[2], skip pps */
+static u32 dbg_nal_skip_count;
+#endif
+/*for debug*/
+static u32 decode_pic_begin;
+static uint slice_parse_begin;
+static u32 step;
+#ifdef MIX_STREAM_SUPPORT
+static u32 buf_alloc_width = 4096;
+static u32 buf_alloc_height = 2304;
+
+static u32 dynamic_buf_num_margin;
+#else
+static u32 buf_alloc_width;
+static u32 buf_alloc_height;
+static u32 dynamic_buf_num_margin = 7;
+#endif
+#ifdef CONSTRAIN_MAX_BUF_NUM
+static u32 run_ready_max_vf_only_num;
+static u32 run_ready_display_q_num;
+ /*0: not check
+ 0xff: avs2_dec.ref_maxbuffer
+ */
+static u32 run_ready_max_buf_num = 0xff;
+#endif
+static u32 buf_alloc_depth = 10;
+static u32 buf_alloc_size;
+/*
+bit[0]: 0,
+ bit[1]: 0, always release cma buffer when stop
+ bit[1]: 1, never release cma buffer when stop
+bit[0]: 1, when stop, release cma buffer if blackout is 1;
+do not release cma buffer is blackout is not 1
+
+bit[2]: 0, when start decoding, check current displayed buffer
+ (only for buffer decoded by vp9) if blackout is 0
+ 1, do not check current displayed buffer
+
+bit[3]: 1, if blackout is not 1, do not release current
+ displayed cma buffer always.
+*/
+/* set to 1 for fast play;
+ set to 8 for other case of "keep last frame"
+*/
+static u32 buffer_mode = 1;
+/* buffer_mode_dbg: debug only*/
+static u32 buffer_mode_dbg = 0xffff0000;
+/**/
+
+/*
+bit 0, 1: only display I picture;
+bit 1, 1: only decode I picture;
+*/
+static u32 i_only_flag;
+
+
+static u32 max_decoding_time;
+/*
+error handling
+*/
+/*error_handle_policy:
+bit 0: search seq again if buffer mgr error occur
+ (buffer mgr error count need big than
+ re_search_seq_threshold)
+bit 1: 1, display from I picture;
+ 0, display from any correct pic
+*/
+
+static u32 error_handle_policy = 1;
+/*
+re_search_seq_threshold:
+ bit 7~0: buffer mgr error research seq count
+ bit 15~8: frame count threshold
+*/
+static u32 re_search_seq_threshold = 0x800; /*0x8;*/
+/*static u32 parser_sei_enable = 1;*/
+
+static u32 max_buf_num = (REF_BUFFER + 1);
+
+static u32 run_ready_min_buf_num = 2;
+
+static DEFINE_MUTEX(vavs2_mutex);
+
+#define HEVC_DEC_STATUS_REG HEVC_ASSIST_SCRATCH_0
+#define HEVC_RPM_BUFFER HEVC_ASSIST_SCRATCH_1
+#define AVS2_ALF_SWAP_BUFFER HEVC_ASSIST_SCRATCH_2
+#define HEVC_RCS_BUFFER HEVC_ASSIST_SCRATCH_3
+#define HEVC_SPS_BUFFER HEVC_ASSIST_SCRATCH_4
+#define HEVC_PPS_BUFFER HEVC_ASSIST_SCRATCH_5
+//#define HEVC_SAO_UP HEVC_ASSIST_SCRATCH_6
+#ifdef AVS2_10B_MMU
+#define AVS2_MMU_MAP_BUFFER HEVC_ASSIST_SCRATCH_7
+#else
+#define HEVC_STREAM_SWAP_BUFFER HEVC_ASSIST_SCRATCH_7
+#endif
+#define HEVC_STREAM_SWAP_BUFFER2 HEVC_ASSIST_SCRATCH_8
+/*
+#define VP9_PROB_SWAP_BUFFER HEVC_ASSIST_SCRATCH_9
+#define VP9_COUNT_SWAP_BUFFER HEVC_ASSIST_SCRATCH_A
+#define VP9_SEG_MAP_BUFFER HEVC_ASSIST_SCRATCH_B
+*/
+//#define HEVC_SCALELUT HEVC_ASSIST_SCRATCH_D
+#define 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)
+
+#define WORK_BUF_SPEC_NUM 3
+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 = 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
+ .mpred_above = {
+ .buf_size = 0x1e00, /* 2 * size of hevc*/
+ },
+#ifdef MV_USE_FIXED_BUF
+ .mpred_mv = {/* 1080p, 0x40000 per buffer */
+ .buf_size = CO_MV_BUF_SIZE_1080P * FRAME_BUFFERS,
+ },
+#endif
+ .rpm = {
+ .buf_size = RPM_BUF_SIZE,
+ },
+ .lmem = {
+ .buf_size = 0x400 * 2,
+ }
+ },
+ {
+ .max_width = 4096,
+ .max_height = 2304,
+ .ipp = {
+ /* IPP work space calculation :
+ 4096 * (Y+CbCr+Flags) = 12k, round to 16k */
+ .buf_size = 0x4000,
+ },
+ .sao_abv = {
+ .buf_size = 0,
+ },
+ .sao_vb = {
+ .buf_size = 0,
+ },
+ .short_term_rps = {
+ /* SHORT_TERM_RPS - Max 64 set, 16 entry every set,
+ total 64x16x2 = 2048 bytes (0x800) */
+ .buf_size = 0x800,
+ },
+ .rcs = {
+ /* RCS STORE AREA - Max 16 RCS, each has 32 bytes,
+ total 0x0400 bytes */
+ .buf_size = 0x400,
+ },
+ .sps = {
+ /* SPS STORE AREA - Max 16 SPS, each has 0x80 bytes,
+ total 0x0800 bytes */
+ .buf_size = 0x800,
+ },
+ .pps = {
+ /* PPS STORE AREA - Max 64 PPS, each has 0x80 bytes,
+ total 0x2000 bytes */
+ .buf_size = 0x2000,
+ },
+ .sao_up = {
+ /* SAO UP STORE AREA - Max 640(10240/16) LCU,
+ each has 16 bytes total 0x2800 bytes */
+ .buf_size = 0,
+ },
+ .swap_buf = {
+ /* 256cyclex64bit = 2K bytes 0x800
+ (only 144 cycles valid) */
+ .buf_size = 0x800,
+ },
+ .swap_buf2 = {
+ .buf_size = 0x800,
+ },
+ .scalelut = {
+ /* support up to 32 SCALELUT 1024x32 = 32Kbytes
+ (0x8000) */
+ .buf_size = 0,
+ },
+ .dblk_para = {
+ /* DBLK -> Max 256(4096/16) LCU,
+ each para 1024bytes(total:0x40000),
+ data 1024bytes(total:0x40000)*/
+ .buf_size = 0x8100, //0x8080,
+ },
+ .dblk_data = {
+ /*DBLK -> Max 256(4096/16) LCU,
+ each para 1024bytes(total:0x40000),
+ data 1024bytes(total:0x40000)*/
+ .buf_size = 0x88800,
+ },
+ .dblk_data2 = {
+ .buf_size = 0x88800,
+ },
+#ifdef AVS2_10B_MMU
+ .mmu_vbh = {
+ .buf_size = VBH_BUF_SIZE_4K,/*2*16*(more than 2304)/4, 4K*/
+ },
+#if 0
+ .cm_header = {
+ /*add one for keeper.*/
+ .buf_size = MMU_COMPRESS_HEADER_SIZE *
+ (FRAME_BUFFERS + 1),
+ /* 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) */
+ },
+#endif
+#endif
+ .mpred_above = {
+ .buf_size = 0x4000, /* 2 * size of hevc*/
+ },
+#ifdef MV_USE_FIXED_BUF
+ .mpred_mv = {
+ /* .buf_size = 0x100000*16,
+ //4k2k , 0x100000 per buffer */
+ /* 4096x2304 , 0x120000 per buffer */
+ .buf_size = CO_MV_BUF_SIZE_4K * FRAME_BUFFERS,
+ },
+#endif
+ .rpm = {
+ .buf_size = RPM_BUF_SIZE,
+ },
+ .lmem = {
+ .buf_size = 0x400 * 2,
+ }
+ },
+ {
+ .max_width = 4096 * 2,
+ .max_height = 2304 * 2,
+ .ipp = {
+ /*IPP work space calculation : 4096 * (Y+CbCr+Flags) = 12k,
+ round to 16k*/
+ .buf_size = 0x4000 * 2,
+ },
+ .sao_abv = {
+ .buf_size = 0,
+ },
+ .sao_vb = {
+ .buf_size = 0,
+ },
+ .short_term_rps = {
+ /*SHORT_TERM_RPS - Max 64 set, 16 entry every set,
+ total 64x16x2 = 2048 bytes (0x800)*/
+ .buf_size = 0x800,
+ },
+ .rcs = {
+ /*RCS STORE AREA - Max 16 RCS, each has 32 bytes,
+ total 0x0400 bytes*/
+ .buf_size = 0x400,
+ },
+ .sps = {
+ /*SPS STORE AREA - Max 16 SPS, each has 0x80 bytes,
+ total 0x0800 bytes*/
+ .buf_size = 0x800,
+ },
+ .pps = {
+ /*PPS STORE AREA - Max 64 PPS, each has 0x80 bytes, total
+ 0x2000 bytes*/
+ .buf_size = 0x2000,
+ },
+ .sao_up = {
+ /*SAO UP STORE AREA - Max 640(10240/16) LCU, each has 16 bytes i
+ total 0x2800 bytes*/
+ .buf_size = 0,
+ },
+ .swap_buf = {
+ /*256cyclex64bit = 2K bytes 0x800 (only 144 cycles valid)*/
+ .buf_size = 0x800,
+ },
+ .swap_buf2 = {
+ .buf_size = 0x800,
+ },
+ .scalelut = {
+ /*support up to 32 SCALELUT 1024x32 = 32Kbytes (0x8000)*/
+ .buf_size = 0,
+ },
+ .dblk_para = {
+ .buf_size = 0x10100, //0x10080,
+ },
+ .dblk_data = {
+ .buf_size = 0x110800,
+ },
+ .dblk_data2 = {
+ .buf_size = 0x110800,
+ },
+#ifdef AVS2_10B_MMU
+ .mmu_vbh = {
+ .buf_size = VBH_BUF_SIZE_8K, /*2*16*2304/4, 4K*/
+ },
+#if 0
+ .cm_header = {
+ /*0x44000 = ((1088*2*1024*4)/32/4)*(32/8)*/
+ .buf_size = MMU_COMPRESS_8K_HEADER_SIZE * 17,
+ },
+#endif
+#endif
+ .mpred_above = {
+ .buf_size = 0x8000,
+ },
+#ifdef MV_USE_FIXED_BUF
+ .mpred_mv = {
+ /*4k2k , 0x100000 per buffer*/
+ .buf_size = CO_MV_BUF_SIZE_8K * FRAME_BUFFERS,
+ },
+#endif
+ .rpm = {
+ .buf_size = RPM_BUF_SIZE,
+ },
+ .lmem = {
+ .buf_size = 0x400 * 2,
+ }
+ }
+};
+
+#define IS_8K_SIZE(w, h) (((w) * (h)) > MAX_SIZE_4K)
+#define IS_4K_SIZE(w, h) (((w) * (h)) > (1920*1088))
+#ifndef MV_USE_FIXED_BUF
+static uint32_t get_mv_buf_size(struct AVS2Decoder_s *dec, int width, int height) {
+ struct avs2_decoder *avs2_dec = &dec->avs2_dec;
+ uint32_t size;
+ if (mv_buf_dynamic_alloc == 1) {
+ int mv_mem_unit =
+ avs2_dec->lcu_size_log2 == 6 ? 0x200 : avs2_dec->lcu_size_log2 ==
+ 5 ? 0x80 : 0x20;
+ int extended_pic_width = (width + avs2_dec->lcu_size -1)
+ & (~(avs2_dec->lcu_size - 1));
+ int extended_pic_height = (height + avs2_dec->lcu_size -1)
+ & (~(avs2_dec->lcu_size - 1));
+ int lcu_x_num = extended_pic_width / avs2_dec->lcu_size;
+ int lcu_y_num = extended_pic_height / avs2_dec->lcu_size;
+ int new_size = lcu_x_num * lcu_y_num * mv_mem_unit;
+ size = (new_size + 0xffff) & (~0xffff);
+
+ } else {
+ if (IS_8K_SIZE(width, height))
+ size = CO_MV_BUF_SIZE_8K;
+ else if (IS_4K_SIZE(width, height))
+ size = CO_MV_BUF_SIZE_4K;
+ else
+ size = CO_MV_BUF_SIZE_1080P;
+ }
+ return size;
+}
+#endif
+
+/*Losless compression body buffer size 4K per 64x32 (jt)*/
+static int compute_losless_comp_body_size(struct AVS2Decoder_s *dec,
+ int width, int height,
+ uint8_t is_bit_depth_10)
+{
+ int width_x64;
+ int height_x32;
+ int bsize;
+ width_x64 = width + 63;
+ width_x64 >>= 6;
+ height_x32 = height + 31;
+ height_x32 >>= 5;
+#ifdef AVS2_10B_MMU
+ bsize = (is_bit_depth_10 ? 4096 : 3200)
+ * width_x64 * height_x32;
+#else
+ bsize = (is_bit_depth_10 ? 4096 : 3072)
+ * width_x64 * height_x32;
+#endif
+ avs2_print(dec, AVS2_DBG_BUFMGR_MORE,
+ "%s(%d,%d,%d)=>%d\n",
+ __func__, width, height,
+ is_bit_depth_10, bsize);
+
+ return bsize;
+}
+
+/* Losless compression header buffer size 32bytes per 128x64 (jt)*/
+static int compute_losless_comp_header_size(struct AVS2Decoder_s *dec,
+ int width, int height)
+{
+ int width_x128;
+ int height_x64;
+ int hsize;
+ width_x128 = width + 127;
+ width_x128 >>= 7;
+ height_x64 = height + 63;
+ height_x64 >>= 6;
+
+ hsize = 32 * width_x128 * height_x64;
+ avs2_print(dec, AVS2_DBG_BUFMGR_MORE,
+ "%s(%d,%d)=>%d\n",
+ __func__, width, height,
+ hsize);
+
+ return hsize;
+}
+
+static void init_buff_spec(struct AVS2Decoder_s *dec,
+ struct BuffInfo_s *buf_spec)
+{
+ void *mem_start_virt;
+ buf_spec->ipp.buf_start = buf_spec->start_adr;
+ buf_spec->sao_abv.buf_start =
+ buf_spec->ipp.buf_start + buf_spec->ipp.buf_size;
+
+ buf_spec->sao_vb.buf_start =
+ buf_spec->sao_abv.buf_start + buf_spec->sao_abv.buf_size;
+ buf_spec->short_term_rps.buf_start =
+ buf_spec->sao_vb.buf_start + buf_spec->sao_vb.buf_size;
+ buf_spec->rcs.buf_start =
+ buf_spec->short_term_rps.buf_start +
+ buf_spec->short_term_rps.buf_size;
+ buf_spec->sps.buf_start =
+ buf_spec->rcs.buf_start + buf_spec->rcs.buf_size;
+ buf_spec->pps.buf_start =
+ buf_spec->sps.buf_start + buf_spec->sps.buf_size;
+ buf_spec->sao_up.buf_start =
+ buf_spec->pps.buf_start + buf_spec->pps.buf_size;
+ buf_spec->swap_buf.buf_start =
+ buf_spec->sao_up.buf_start + buf_spec->sao_up.buf_size;
+ buf_spec->swap_buf2.buf_start =
+ buf_spec->swap_buf.buf_start + buf_spec->swap_buf.buf_size;
+ buf_spec->scalelut.buf_start =
+ buf_spec->swap_buf2.buf_start + buf_spec->swap_buf2.buf_size;
+ buf_spec->dblk_para.buf_start =
+ buf_spec->scalelut.buf_start + buf_spec->scalelut.buf_size;
+ buf_spec->dblk_data.buf_start =
+ buf_spec->dblk_para.buf_start + buf_spec->dblk_para.buf_size;
+ buf_spec->dblk_data2.buf_start =
+ buf_spec->dblk_data.buf_start + buf_spec->dblk_data.buf_size;
+#ifdef AVS2_10B_MMU
+ buf_spec->mmu_vbh.buf_start =
+ buf_spec->dblk_data2.buf_start + buf_spec->dblk_data2.buf_size;
+ buf_spec->mpred_above.buf_start =
+ buf_spec->mmu_vbh.buf_start + buf_spec->mmu_vbh.buf_size;
+#else
+ buf_spec->mpred_above.buf_start =
+ buf_spec->dblk_data2.buf_start + buf_spec->dblk_data2.buf_size;
+#endif
+#ifdef MV_USE_FIXED_BUF
+ buf_spec->mpred_mv.buf_start =
+ buf_spec->mpred_above.buf_start +
+ buf_spec->mpred_above.buf_size;
+
+ buf_spec->rpm.buf_start =
+ buf_spec->mpred_mv.buf_start +
+ buf_spec->mpred_mv.buf_size;
+#else
+ buf_spec->rpm.buf_start =
+ buf_spec->mpred_above.buf_start +
+ buf_spec->mpred_above.buf_size;
+
+#endif
+ buf_spec->lmem.buf_start =
+ buf_spec->rpm.buf_start +
+ buf_spec->rpm.buf_size;
+ buf_spec->end_adr =
+ buf_spec->lmem.buf_start +
+ buf_spec->lmem.buf_size;
+
+ if (dec) {
+ mem_start_virt =
+ codec_mm_phys_to_virt(buf_spec->dblk_para.buf_start);
+ if (mem_start_virt) {
+ memset(mem_start_virt, 0, buf_spec->dblk_para.buf_size);
+ codec_mm_dma_flush(mem_start_virt,
+ buf_spec->dblk_para.buf_size,
+ DMA_TO_DEVICE);
+ } else {
+ /*not virt for tvp playing,
+ may need clear on ucode.*/
+ pr_err("mem_start_virt failed\n");
+ }
+ if (debug) {
+ pr_info("%s workspace (%x %x) size = %x\n", __func__,
+ buf_spec->start_adr, buf_spec->end_adr,
+ buf_spec->end_adr - buf_spec->start_adr);
+ }
+ if (debug) {
+ pr_info("ipp.buf_start :%x\n",
+ buf_spec->ipp.buf_start);
+ pr_info("sao_abv.buf_start :%x\n",
+ buf_spec->sao_abv.buf_start);
+ pr_info("sao_vb.buf_start :%x\n",
+ buf_spec->sao_vb.buf_start);
+ pr_info("short_term_rps.buf_start :%x\n",
+ buf_spec->short_term_rps.buf_start);
+ pr_info("rcs.buf_start :%x\n",
+ buf_spec->rcs.buf_start);
+ pr_info("sps.buf_start :%x\n",
+ buf_spec->sps.buf_start);
+ pr_info("pps.buf_start :%x\n",
+ buf_spec->pps.buf_start);
+ pr_info("sao_up.buf_start :%x\n",
+ buf_spec->sao_up.buf_start);
+ pr_info("swap_buf.buf_start :%x\n",
+ buf_spec->swap_buf.buf_start);
+ pr_info("swap_buf2.buf_start :%x\n",
+ buf_spec->swap_buf2.buf_start);
+ pr_info("scalelut.buf_start :%x\n",
+ buf_spec->scalelut.buf_start);
+ pr_info("dblk_para.buf_start :%x\n",
+ buf_spec->dblk_para.buf_start);
+ pr_info("dblk_data.buf_start :%x\n",
+ buf_spec->dblk_data.buf_start);
+ pr_info("dblk_data2.buf_start :%x\n",
+ buf_spec->dblk_data2.buf_start);
+ #ifdef AVS2_10B_MMU
+ pr_info("mmu_vbh.buf_start :%x\n",
+ buf_spec->mmu_vbh.buf_start);
+ #endif
+ pr_info("mpred_above.buf_start :%x\n",
+ buf_spec->mpred_above.buf_start);
+#ifdef MV_USE_FIXED_BUF
+ pr_info("mpred_mv.buf_start :%x\n",
+ buf_spec->mpred_mv.buf_start);
+#endif
+ if ((debug & AVS2_DBG_SEND_PARAM_WITH_REG) == 0) {
+ pr_info("rpm.buf_start :%x\n",
+ buf_spec->rpm.buf_start);
+ }
+ }
+ }
+
+}
+
+static void uninit_mmu_buffers(struct AVS2Decoder_s *dec)
+{
+#if 0
+/*ndef MV_USE_FIXED_BUF*/
+ dealloc_mv_bufs(dec);
+#endif
+ decoder_mmu_box_free(dec->mmu_box);
+ dec->mmu_box = NULL;
+
+ if (dec->bmmu_box)
+ decoder_bmmu_box_free(dec->bmmu_box);
+ dec->bmmu_box = NULL;
+}
+
+#ifndef AVS2_10B_MMU
+static void init_buf_list(struct AVS2Decoder_s *dec)
+{
+ int i;
+ int buf_size;
+ int mc_buffer_end = dec->mc_buf->buf_start + dec->mc_buf->buf_size;
+ dec->used_buf_num = max_buf_num;
+
+ if (dec->used_buf_num > MAX_BUF_NUM)
+ dec->used_buf_num = MAX_BUF_NUM;
+ if (buf_alloc_size > 0) {
+ buf_size = buf_alloc_size;
+ avs2_print(dec, AVS2_DBG_BUFMGR,
+ "[Buffer Management] init_buf_list:\n");
+ } else {
+ int pic_width = dec->init_pic_w;
+ int pic_height = dec->init_pic_h;
+
+ /*SUPPORT_10BIT*/
+ int losless_comp_header_size = compute_losless_comp_header_size
+ (dec, pic_width, pic_height);
+ int losless_comp_body_size = compute_losless_comp_body_size
+ (dec, pic_width, pic_height, buf_alloc_depth == 10);
+ int mc_buffer_size = losless_comp_header_size
+ + losless_comp_body_size;
+ int mc_buffer_size_h = (mc_buffer_size + 0xffff)>>16;
+
+ int dw_mode = get_double_write_mode_init(dec);
+
+ if (dw_mode) {
+ int pic_width_dw = pic_width /
+ get_double_write_ratio(dec, dw_mode);
+ int pic_height_dw = pic_height /
+ get_double_write_ratio(dec, dw_mode);
+ int lcu_size = 64; /*fixed 64*/
+ int pic_width_64 = (pic_width_dw + 63) & (~0x3f);
+ int pic_height_32 = (pic_height_dw + 31) & (~0x1f);
+ int pic_width_lcu =
+ (pic_width_64 % lcu_size) ? pic_width_64 / lcu_size
+ + 1 : pic_width_64 / lcu_size;
+ int pic_height_lcu =
+ (pic_height_32 % lcu_size) ? pic_height_32 / lcu_size
+ + 1 : pic_height_32 / lcu_size;
+ int lcu_total = pic_width_lcu * pic_height_lcu;
+ int mc_buffer_size_u_v = lcu_total * lcu_size * lcu_size / 2;
+ int mc_buffer_size_u_v_h = (mc_buffer_size_u_v + 0xffff) >> 16;
+ /*64k alignment*/
+ buf_size = ((mc_buffer_size_u_v_h << 16) * 3);
+ } else
+ buf_size = 0;
+
+ if (mc_buffer_size & 0xffff) { /*64k alignment*/
+ mc_buffer_size_h += 1;
+ }
+ if ((dw_mode & 0x10) == 0)
+ buf_size += (mc_buffer_size_h << 16);
+ avs2_print(dec, AVS2_DBG_BUFMGR,
+ "init_buf_list num %d (width %d height %d):\n",
+ dec->used_buf_num, pic_width, pic_height);
+ }
+
+ for (i = 0; i < dec->used_buf_num; i++) {
+ if (((i + 1) * buf_size) > dec->mc_buf->buf_size)
+ dec->use_cma_flag = 1;
+#ifndef AVS2_10B_MMU
+ dec->m_BUF[i].alloc_flag = 0;
+ dec->m_BUF[i].index = i;
+
+ dec->use_cma_flag = 1;
+ if (dec->use_cma_flag) {
+ dec->m_BUF[i].cma_page_count =
+ PAGE_ALIGN(buf_size) / PAGE_SIZE;
+ if (decoder_bmmu_box_alloc_buf_phy(dec->bmmu_box,
+ VF_BUFFER_IDX(i), buf_size, DRIVER_NAME,
+ &dec->m_BUF[i].alloc_addr) < 0) {
+ dec->m_BUF[i].cma_page_count = 0;
+ if (i <= 5) {
+ dec->fatal_error |=
+ DECODER_FATAL_ERROR_NO_MEM;
+ }
+ break;
+ }
+ dec->m_BUF[i].start_adr = dec->m_BUF[i].alloc_addr;
+ } else {
+ dec->m_BUF[i].cma_page_count = 0;
+ dec->m_BUF[i].alloc_addr = 0;
+ dec->m_BUF[i].start_adr =
+ dec->mc_buf->buf_start + i * buf_size;
+ }
+ dec->m_BUF[i].size = buf_size;
+ dec->m_BUF[i].free_start_adr = dec->m_BUF[i].start_adr;
+
+ if (((dec->m_BUF[i].start_adr + buf_size) > mc_buffer_end)
+ && (dec->m_BUF[i].alloc_addr == 0)) {
+ if (debug) {
+ avs2_print(dec, 0,
+ "Max mc buffer or mpred_mv buffer is used\n");
+ }
+ break;
+ }
+
+ avs2_print(dec, AVS2_DBG_BUFMGR,
+ "Buffer %d: start_adr %p size %x\n", i,
+ (void *)dec->m_BUF[i].start_adr,
+ dec->m_BUF[i].size);
+#endif
+ }
+ dec->buf_num = i;
+}
+#endif
+
+static int config_pic(struct AVS2Decoder_s *dec,
+ struct avs2_frame_s *pic, int32_t lcu_size_log2)
+{
+ int ret = -1;
+ int i;
+ int pic_width = dec->init_pic_w;
+ int pic_height = dec->init_pic_h;
+ /*struct avs2_decoder *avs2_dec = &dec->avs2_dec;
+ int32_t lcu_size_log2 = avs2_dec->lcu_size_log2;*/
+ int32_t lcu_size = 1 << lcu_size_log2;
+ int pic_width_64 = (pic_width + 63) & (~0x3f);
+ int pic_height_32 = (pic_height + 31) & (~0x1f);
+ int pic_width_lcu = (pic_width_64 % lcu_size) ?
+ pic_width_64 / lcu_size + 1
+ : pic_width_64 / lcu_size;
+ int pic_height_lcu = (pic_height_32 % lcu_size) ?
+ pic_height_32 / lcu_size + 1
+ : pic_height_32 / lcu_size;
+ int lcu_total = pic_width_lcu * pic_height_lcu;
+#if 0
+ int32_t MV_MEM_UNIT =
+ (lcu_size_log2 == 6) ? 0x200 :
+ ((lcu_size_log2 == 5) ? 0x80 : 0x20);
+#endif
+#ifdef MV_USE_FIXED_BUF
+ u32 mpred_mv_end = dec->work_space_buf->mpred_mv.buf_start +
+ dec->work_space_buf->mpred_mv.buf_size;
+#endif
+ u32 y_adr = 0;
+ int buf_size = 0;
+
+ int losless_comp_header_size =
+ compute_losless_comp_header_size(
+ dec, pic_width, pic_height);
+ int losless_comp_body_size = compute_losless_comp_body_size(
+ dec, pic_width,
+ pic_height, buf_alloc_depth == 10);
+ int mc_buffer_size = losless_comp_header_size + losless_comp_body_size;
+ int mc_buffer_size_h = (mc_buffer_size + 0xffff) >> 16;
+ int mc_buffer_size_u_v = 0;
+ int mc_buffer_size_u_v_h = 0;
+ int dw_mode = get_double_write_mode_init(dec);
+
+ if (dw_mode) {
+ int pic_width_dw = pic_width /
+ get_double_write_ratio(dec, dw_mode);
+ int pic_height_dw = pic_height /
+ get_double_write_ratio(dec, dw_mode);
+ int pic_width_64_dw = (pic_width_dw + 63) & (~0x3f);
+ int pic_height_32_dw = (pic_height_dw + 31) & (~0x1f);
+ int pic_width_lcu_dw = (pic_width_64_dw % lcu_size) ?
+ pic_width_64_dw / lcu_size + 1
+ : pic_width_64_dw / lcu_size;
+ int pic_height_lcu_dw = (pic_height_32_dw % lcu_size) ?
+ pic_height_32_dw / lcu_size + 1
+ : pic_height_32_dw / lcu_size;
+ int lcu_total_dw = pic_width_lcu_dw * pic_height_lcu_dw;
+
+ mc_buffer_size_u_v = lcu_total_dw * lcu_size * lcu_size / 2;
+ mc_buffer_size_u_v_h = (mc_buffer_size_u_v + 0xffff) >> 16;
+ /*64k alignment*/
+ buf_size = ((mc_buffer_size_u_v_h << 16) * 3);
+ buf_size = ((buf_size + 0xffff) >> 16) << 16;
+ }
+ if (mc_buffer_size & 0xffff) /*64k alignment*/
+ mc_buffer_size_h += 1;
+#ifndef AVS2_10B_MMU
+ if ((dw_mode & 0x10) == 0)
+ buf_size += (mc_buffer_size_h << 16);
+#endif
+
+#ifdef AVS2_10B_MMU
+#ifndef DYNAMIC_ALLOC_HEAD
+ pic->header_adr = decoder_bmmu_box_get_phy_addr(
+ dec->bmmu_box, HEADER_BUFFER_IDX(pic->index));
+
+ avs2_print(dec, AVS2_DBG_BUFMGR_MORE,
+ "buf_size %d, MMU header_adr %d: %ld\n",
+ buf_size, pic->index, pic->header_adr);
+#endif
+#endif
+
+ i = pic->index;
+#ifdef MV_USE_FIXED_BUF
+#ifdef G12A_BRINGUP_DEBUG
+ if (1) {
+#else
+ if ((dec->work_space_buf->mpred_mv.buf_start +
+ (((i + 1) * lcu_total) * MV_MEM_UNIT))
+ <= mpred_mv_end
+ ) {
+#endif
+#endif
+#ifndef AVS2_10B_MMU
+ if (debug) {
+ pr_err("start %x .size=%d\n",
+ dec->mc_buf_spec.buf_start + i * buf_size,
+ buf_size);
+ }
+#endif
+#ifndef AVS2_10B_MMU
+ for (i = 0; i < dec->buf_num; i++) {
+ y_adr = ((dec->m_BUF[i].free_start_adr
+ + 0xffff) >> 16) << 16;
+ /*64k alignment*/
+ if ((y_adr+buf_size) <= (dec->m_BUF[i].start_adr+
+ dec->m_BUF[i].size)) {
+ dec->m_BUF[i].free_start_adr =
+ y_adr + buf_size;
+ break;
+ }
+ }
+ if (i < dec->buf_num)
+#else
+ /*if ((dec->mc_buf->buf_start + (i + 1) * buf_size) <
+ dec->mc_buf->buf_end)
+ y_adr = dec->mc_buf->buf_start + i * buf_size;
+ else {*/
+ if (buf_size > 0 && pic->cma_alloc_addr == 0) {
+ ret = decoder_bmmu_box_alloc_buf_phy(dec->bmmu_box,
+ VF_BUFFER_IDX(i),
+ buf_size, DRIVER_NAME,
+ &pic->cma_alloc_addr);
+ if (ret < 0) {
+ avs2_print(dec, 0,
+ "decoder_bmmu_box_alloc_buf_phy idx %d size %d fail\n",
+ VF_BUFFER_IDX(i),
+ buf_size
+ );
+ return ret;
+ }
+
+ if (pic->cma_alloc_addr)
+ y_adr = pic->cma_alloc_addr;
+ else {
+ avs2_print(dec, 0,
+ "decoder_bmmu_box_alloc_buf_phy idx %d size %d return null\n",
+ VF_BUFFER_IDX(i),
+ buf_size
+ );
+ return -1;
+ }
+ }
+#endif
+ {
+ /*ensure get_pic_by_POC()
+ not get the buffer not decoded*/
+ pic->BUF_index = i;
+ pic->lcu_total = lcu_total;
+
+ pic->comp_body_size = losless_comp_body_size;
+ pic->buf_size = buf_size;
+#ifndef AVS2_10B_MMU
+ pic->mc_y_adr = y_adr;
+#endif
+ pic->mc_canvas_y = pic->index;
+ pic->mc_canvas_u_v = pic->index;
+#ifndef AVS2_10B_MMU
+ if (dw_mode & 0x10) {
+ pic->mc_u_v_adr = y_adr +
+ ((mc_buffer_size_u_v_h << 16) << 1);
+
+ pic->mc_canvas_y =
+ (pic->index << 1);
+ pic->mc_canvas_u_v =
+ (pic->index << 1) + 1;
+
+ pic->dw_y_adr = y_adr;
+ pic->dw_u_v_adr = pic->mc_u_v_adr;
+ } else
+#endif
+ if (dw_mode) {
+ pic->dw_y_adr = y_adr
+#ifndef AVS2_10B_MMU
+ + (mc_buffer_size_h << 16)
+#endif
+ ;
+ pic->dw_u_v_adr = pic->dw_y_adr +
+ ((mc_buffer_size_u_v_h << 16) << 1);
+#ifdef AVS2_10B_MMU
+ pic->mc_y_adr = pic->dw_y_adr;
+ pic->mc_u_v_adr = pic->dw_u_v_adr;
+#endif
+ }
+#ifdef MV_USE_FIXED_BUF
+#ifdef G12A_BRINGUP_DEBUG
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) {
+ pic->mpred_mv_wr_start_addr =
+ dec->work_space_buf->mpred_mv.buf_start +
+ (pic->index * 0x120000 * 4);
+ } else {
+ pic->mpred_mv_wr_start_addr =
+ dec->work_space_buf->mpred_mv.buf_start +
+ (pic->index * 0x120000);
+ }
+#else
+ pic->mpred_mv_wr_start_addr =
+ dec->work_space_buf->mpred_mv.buf_start +
+ ((pic->index * lcu_total)
+ * MV_MEM_UNIT);
+#endif
+#endif
+ if (debug) {
+ avs2_print(dec, AVS2_DBG_BUFMGR,
+ "%s index %d BUF_index %d mc_y_adr %x ",
+ __func__, pic->index,
+ pic->BUF_index,
+ pic->mc_y_adr);
+ avs2_print_cont(dec, AVS2_DBG_BUFMGR,
+ "comp_body_size %x comp_buf_size %x ",
+ pic->comp_body_size,
+ pic->buf_size);
+ avs2_print_cont(dec, AVS2_DBG_BUFMGR,
+ "mpred_mv_wr_start_adr %d\n",
+ pic->mpred_mv_wr_start_addr);
+ avs2_print_cont(dec, AVS2_DBG_BUFMGR,
+ "dw_y_adr %d, pic->dw_u_v_adr =%d\n",
+ pic->dw_y_adr,
+ pic->dw_u_v_adr);
+ }
+ ret = 0;
+ }
+#ifdef MV_USE_FIXED_BUF
+ } else {
+ avs2_print(dec, 0,
+ "mv buffer alloc fail %x > %x\n",
+ dec->work_space_buf->mpred_mv.buf_start +
+ (((i + 1) * lcu_total) * MV_MEM_UNIT),
+ mpred_mv_end);
+ }
+#endif
+ return ret;
+}
+
+static void init_pic_list(struct AVS2Decoder_s *dec,
+ int32_t lcu_size_log2)
+{
+ int i;
+ struct avs2_decoder *avs2_dec = &dec->avs2_dec;
+ struct avs2_frame_s *pic;
+#ifdef AVS2_10B_MMU
+ unsigned long buf_addr1;
+ /*alloc AVS2 compress header first*/
+ if (decoder_bmmu_box_alloc_buf_phy
+ (dec->bmmu_box,
+ HEADER_BUFFER_IDX(-1), get_compress_header_size(dec),
+ DRIVER_HEADER_NAME,
+ &buf_addr1) < 0){
+ avs2_print(dec, 0,
+ "%s malloc compress header failed %d\n",
+ DRIVER_HEADER_NAME, -1);
+ dec->fatal_error |= DECODER_FATAL_ERROR_NO_MEM;
+ return;
+ }
+#ifndef DYNAMIC_ALLOC_HEAD
+ for (i = 0; i < dec->used_buf_num; i++) {
+ unsigned long buf_addr;
+ if (decoder_bmmu_box_alloc_buf_phy
+ (dec->bmmu_box,
+ HEADER_BUFFER_IDX(i), get_compress_header_size(dec),
+ DRIVER_HEADER_NAME,
+ &buf_addr) < 0){
+ avs2_print(dec, 0,
+ "%s malloc compress header failed %d\n",
+ DRIVER_HEADER_NAME, i);
+ dec->fatal_error |= DECODER_FATAL_ERROR_NO_MEM;
+ return;
+ }
+ }
+#endif
+#endif
+ dec->frame_height = avs2_dec->img.height;
+ dec->frame_width = avs2_dec->img.width;
+
+ for (i = 0; i < dec->used_buf_num; i++) {
+ if (i == (dec->used_buf_num - 1))
+ pic = avs2_dec->m_bg;
+ else
+ pic = avs2_dec->fref[i];
+ pic->index = i;
+ pic->BUF_index = -1;
+ pic->mv_buf_index = -1;
+ if (config_pic(dec, pic, lcu_size_log2) < 0) {
+ if (debug)
+ avs2_print(dec, 0,
+ "Config_pic %d fail\n",
+ pic->index);
+ pic->index = -1;
+ break;
+ }
+ pic->pic_w = avs2_dec->img.width;
+ pic->pic_h = avs2_dec->img.height;
+ }
+ for (; i < dec->used_buf_num; i++) {
+ if (i == (dec->used_buf_num - 1))
+ pic = avs2_dec->m_bg;
+ else
+ pic = avs2_dec->fref[i];
+ pic->index = -1;
+ pic->BUF_index = -1;
+ pic->mv_buf_index = -1;
+ }
+ avs2_print(dec, AVS2_DBG_BUFMGR,
+ "%s ok, used_buf_num = %d\n",
+ __func__, dec->used_buf_num);
+ dec->pic_list_init_flag = 1;
+}
+
+
+static void init_pic_list_hw(struct AVS2Decoder_s *dec)
+{
+ int i;
+ struct avs2_decoder *avs2_dec = &dec->avs2_dec;
+ struct avs2_frame_s *pic;
+ /*WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0x0);*/
+#if 0
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR,
+ (0x1 << 1) | (0x1 << 2));
+
+#ifdef DUAL_CORE_64
+ WRITE_VREG(HEVC2_HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR,
+ (0x1 << 1) | (0x1 << 2));
+#endif
+#endif
+ for (i = 0; i < dec->used_buf_num; i++) {
+ if (i == (dec->used_buf_num - 1))
+ pic = avs2_dec->m_bg;
+ else
+ pic = avs2_dec->fref[i];
+ if (pic->index < 0)
+ break;
+#ifdef AVS2_10B_MMU
+ /*WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
+ pic->header_adr
+ | (pic->mc_canvas_y << 8)|0x1);*/
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR,
+ (0x1 << 1) | (pic->index << 8));
+
+#ifdef DUAL_CORE_64
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXLX2)
+ WRITE_VREG(HEVC2_MPP_ANC2AXI_TBL_CONF_ADDR,
+ (0x1 << 1) | (pic->index << 8));
+ else
+ WRITE_VREG(HEVC2_HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR,
+ (0x1 << 1) | (pic->index << 8));
+#endif
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA, pic->header_adr >> 5);
+#else
+ /*WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
+ pic->mc_y_adr
+ | (pic->mc_canvas_y << 8) | 0x1);*/
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA, pic->mc_y_adr >> 5);
+#endif
+#ifndef LOSLESS_COMPRESS_MODE
+ /*WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
+ pic->mc_u_v_adr
+ | (pic->mc_canvas_u_v << 8)| 0x1);*/
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA, pic->mc_u_v_adr >> 5);
+#endif
+#ifdef DUAL_CORE_64
+#ifdef AVS2_10B_MMU
+ WRITE_VREG(HEVC2_HEVCD_MPP_ANC2AXI_TBL_DATA,
+ pic->header_adr >> 5);
+#else
+ WRITE_VREG(HEVC2_HEVCD_MPP_ANC2AXI_TBL_DATA,
+ pic->mc_y_adr >> 5);
+#endif
+#ifndef LOSLESS_COMPRESS_MODE
+ WRITE_VREG(HEVC2_HEVCD_MPP_ANC2AXI_TBL_DATA,
+ pic->mc_u_v_adr >> 5);
+#endif
+/*DUAL_CORE_64*/
+#endif
+ }
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0x1);
+#ifdef DUAL_CORE_64
+ WRITE_VREG(HEVC2_HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR,
+ 0x1);
+#endif
+ /*Zero out canvas registers in IPP -- avoid simulation X*/
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
+ (0 << 8) | (0 << 1) | 1);
+ for (i = 0; i < 32; i++) {
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0);
+#ifdef DUAL_CORE_64
+ WRITE_VREG(HEVC2_HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0);
+#endif
+ }
+}
+
+
+static void dump_pic_list(struct AVS2Decoder_s *dec)
+{
+ int ii;
+ struct avs2_decoder *avs2_dec = &dec->avs2_dec;
+ for (ii = 0; ii < avs2_dec->ref_maxbuffer; ii++) {
+ avs2_print(dec, 0,
+ "fref[%d]: index %d decode_id %d mvbuf %d imgcoi_ref %d imgtr_fwRefDistance %d refered %d, pre %d is_out %d, bg %d, vf_ref %d error %d lcu %d ref_pos(%d,%d,%d,%d,%d,%d,%d)\n",
+ ii, avs2_dec->fref[ii]->index,
+ avs2_dec->fref[ii]->decode_idx,
+ avs2_dec->fref[ii]->mv_buf_index,
+ avs2_dec->fref[ii]->imgcoi_ref,
+ avs2_dec->fref[ii]->imgtr_fwRefDistance,
+ avs2_dec->fref[ii]->refered_by_others,
+ avs2_dec->fref[ii]->to_prepare_disp,
+ avs2_dec->fref[ii]->is_output,
+ avs2_dec->fref[ii]->bg_flag,
+ avs2_dec->fref[ii]->vf_ref,
+ avs2_dec->fref[ii]->error_mark,
+ avs2_dec->fref[ii]->decoded_lcu,
+ avs2_dec->fref[ii]->ref_poc[0],
+ avs2_dec->fref[ii]->ref_poc[1],
+ avs2_dec->fref[ii]->ref_poc[2],
+ avs2_dec->fref[ii]->ref_poc[3],
+ avs2_dec->fref[ii]->ref_poc[4],
+ avs2_dec->fref[ii]->ref_poc[5],
+ avs2_dec->fref[ii]->ref_poc[6]
+ );
+ }
+ return;
+}
+
+static int config_mc_buffer(struct AVS2Decoder_s *dec)
+{
+ int32_t i;
+ struct avs2_decoder *avs2_dec = &dec->avs2_dec;
+ struct avs2_frame_s *pic;
+ struct avs2_frame_s *cur_pic = avs2_dec->hc.cur_pic;
+
+ /*if (avs2_dec->img.type == I_IMG)
+ return 0;
+ */
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "Entered config_mc_buffer....\n");
+ if (avs2_dec->f_bg != NULL) {
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "config_mc_buffer for background (canvas_y %d, canvas_u_v %d)\n",
+ avs2_dec->f_bg->mc_canvas_y, avs2_dec->f_bg->mc_canvas_u_v);
+ /*WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
+ (7 << 8) | (0<<1) | 1); L0:BG */
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
+ (15 << 8) | (0<<1) | 1); /* L0:BG*/
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR,
+ (avs2_dec->f_bg->mc_canvas_u_v << 16) |
+ (avs2_dec->f_bg->mc_canvas_u_v << 8) |
+ avs2_dec->f_bg->mc_canvas_y);
+ /*WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
+ (23 << 8) | (0<<1) | 1); L1:BG*/
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
+ (31 << 8) | (0<<1) | 1); /* L1:BG*/
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR,
+ (avs2_dec->f_bg->mc_canvas_u_v << 16) |
+ (avs2_dec->f_bg->mc_canvas_u_v << 8) |
+ avs2_dec->f_bg->mc_canvas_y);
+ }
+
+ if (avs2_dec->img.type == I_IMG)
+ return 0;
+
+ if (avs2_dec->img.type == P_IMG) {
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "config_mc_buffer for P_IMG, img type %d\n",
+ avs2_dec->img.type);
+ /*refer to prepare_RefInfo()*/
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
+ (0 << 8) | (0<<1) | 1);
+ for (i = 0; i < avs2_dec->img.num_of_references; i++) {
+ pic = avs2_dec->fref[i];
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR,
+ (pic->mc_canvas_u_v << 16) |
+ (pic->mc_canvas_u_v << 8) |
+ pic->mc_canvas_y);
+
+ if (pic->error_mark)
+ cur_pic->error_mark = 1;
+
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "refid %x mc_canvas_u_v %x mc_canvas_y %x error_mark %x\n",
+ i, pic->mc_canvas_u_v, pic->mc_canvas_y,
+ pic->error_mark);
+ }
+ } else if (avs2_dec->img.type == F_IMG) {
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "config_mc_buffer for F_IMG, img type %d\n",
+ avs2_dec->img.type);
+ /*refer to prepare_RefInfo()*/
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
+ (0 << 8) | (0<<1) | 1);
+ for (i = 0; i < avs2_dec->img.num_of_references; i++) {
+ pic = avs2_dec->fref[i];
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR,
+ (pic->mc_canvas_u_v << 16) |
+ (pic->mc_canvas_u_v << 8) |
+ pic->mc_canvas_y);
+
+ if (pic->error_mark)
+ cur_pic->error_mark = 1;
+
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "refid %x mc_canvas_u_v %x mc_canvas_y %x error_mark %x\n",
+ i, pic->mc_canvas_u_v, pic->mc_canvas_y,
+ pic->error_mark);
+ }
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
+ (16 << 8) | (0<<1) | 1);
+ for (i = 0; i < avs2_dec->img.num_of_references; i++) {
+ pic = avs2_dec->fref[i];
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR,
+ (pic->mc_canvas_u_v << 16) |
+ (pic->mc_canvas_u_v << 8) |
+ pic->mc_canvas_y);
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "refid %x mc_canvas_u_v %x mc_canvas_y %x\n",
+ i, pic->mc_canvas_u_v, pic->mc_canvas_y);
+ }
+ } else {
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "config_mc_buffer for B_IMG\n");
+ /*refer to prepare_RefInfo()*/
+ pic = avs2_dec->fref[1];
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
+ (0 << 8) | (0<<1) | 1);
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR,
+ (pic->mc_canvas_u_v << 16) |
+ (pic->mc_canvas_u_v << 8) |
+ pic->mc_canvas_y);
+
+ if (pic->error_mark)
+ cur_pic->error_mark = 1;
+
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "refid %x mc_canvas_u_v %x mc_canvas_y %x error_mark %x\n",
+ 1, pic->mc_canvas_u_v, pic->mc_canvas_y,
+ pic->error_mark);
+
+ pic = avs2_dec->fref[0];
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
+ (16 << 8) | (0<<1) | 1);
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR,
+ (pic->mc_canvas_u_v<<16) |
+ (pic->mc_canvas_u_v<<8) |
+ pic->mc_canvas_y);
+
+ if (pic->error_mark)
+ cur_pic->error_mark = 1;
+
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "refid %x mc_canvas_u_v %x mc_canvas_y %x error_mark %x\n",
+ 0, pic->mc_canvas_u_v, pic->mc_canvas_y,
+ pic->error_mark);
+ }
+ return 0;
+}
+#if 0
+static void mcrcc_get_hitrate(void)
+{
+ u32 tmp;
+ u32 raw_mcr_cnt;
+ u32 hit_mcr_cnt;
+ u32 byp_mcr_cnt_nchoutwin;
+ u32 byp_mcr_cnt_nchcanv;
+ int hitrate;
+
+ if (debug & AVS2_DBG_CACHE)
+ pr_info("[cache_util.c] Entered mcrcc_get_hitrate...\n");
+ WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x0<<1));
+ raw_mcr_cnt = READ_VREG(HEVCD_MCRCC_PERFMON_DATA);
+ WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x1<<1));
+ hit_mcr_cnt = READ_VREG(HEVCD_MCRCC_PERFMON_DATA);
+ WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x2<<1));
+ byp_mcr_cnt_nchoutwin = READ_VREG(HEVCD_MCRCC_PERFMON_DATA);
+ WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x3<<1));
+ byp_mcr_cnt_nchcanv = READ_VREG(HEVCD_MCRCC_PERFMON_DATA);
+
+ if (debug & AVS2_DBG_CACHE) {
+ pr_info("raw_mcr_cnt_total: %d\n",raw_mcr_cnt);
+ pr_info("hit_mcr_cnt_total: %d\n",hit_mcr_cnt);
+ pr_info("byp_mcr_cnt_nchoutwin_total: %d\n",byp_mcr_cnt_nchoutwin);
+ pr_info("byp_mcr_cnt_nchcanv_total: %d\n",byp_mcr_cnt_nchcanv);
+ }
+ WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x4<<1));
+ tmp = READ_VREG(HEVCD_MCRCC_PERFMON_DATA);
+ if (debug & AVS2_DBG_CACHE)
+ pr_info("miss_mcr_0_cnt_total: %d\n", tmp);
+
+ WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x5<<1));
+ tmp = READ_VREG(HEVCD_MCRCC_PERFMON_DATA);
+ if (debug & AVS2_DBG_CACHE)
+ pr_info("miss_mcr_1_cnt_total: %d\n", tmp);
+
+ WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x6<<1));
+ tmp = READ_VREG(HEVCD_MCRCC_PERFMON_DATA);
+ if (debug & AVS2_DBG_CACHE)
+ pr_info("hit_mcr_0_cnt_total: %d\n",tmp);
+
+ WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x7<<1));
+ tmp= READ_VREG(HEVCD_MCRCC_PERFMON_DATA);
+ if (debug & AVS2_DBG_CACHE)
+ pr_info("hit_mcr_1_cnt_total: %d\n",tmp);
+
+ if (raw_mcr_cnt != 0) {
+ hitrate = (hit_mcr_cnt / raw_mcr_cnt) * 100;
+ if (debug & AVS2_DBG_CACHE)
+ pr_info("MCRCC_HIT_RATE : %d\n", hitrate);
+ hitrate = ((byp_mcr_cnt_nchoutwin + byp_mcr_cnt_nchcanv)
+ /raw_mcr_cnt) * 100;
+ if (debug & AVS2_DBG_CACHE)
+ pr_info("MCRCC_BYP_RATE : %d\n", hitrate);
+ } else if (debug & AVS2_DBG_CACHE) {
+ pr_info("MCRCC_HIT_RATE : na\n");
+ pr_info("MCRCC_BYP_RATE : na\n");
+ }
+ return;
+}
+
+
+static void decomp_get_hitrate(void)
+{
+ u32 raw_mcr_cnt;
+ u32 hit_mcr_cnt;
+ int hitrate;
+
+ if (debug & AVS2_DBG_CACHE)
+ pr_info("[cache_util.c] Entered decomp_get_hitrate...\n");
+ WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x0<<1));
+ raw_mcr_cnt = READ_VREG(HEVCD_MPP_DECOMP_PERFMON_DATA);
+ WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x1<<1));
+ hit_mcr_cnt = READ_VREG(HEVCD_MPP_DECOMP_PERFMON_DATA);
+
+ if (debug & AVS2_DBG_CACHE) {
+ pr_info("hcache_raw_cnt_total: %d\n",raw_mcr_cnt);
+ pr_info("hcache_hit_cnt_total: %d\n",hit_mcr_cnt);
+ }
+ if (raw_mcr_cnt != 0) {
+ hitrate = (hit_mcr_cnt / raw_mcr_cnt) * 100;
+ if (debug & AVS2_DBG_CACHE)
+ pr_info("DECOMP_HCACHE_HIT_RATE : %d\n", hitrate);
+ } else {
+ if (debug & AVS2_DBG_CACHE)
+ pr_info("DECOMP_HCACHE_HIT_RATE : na\n");
+ }
+ WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x2<<1));
+ raw_mcr_cnt = READ_VREG(HEVCD_MPP_DECOMP_PERFMON_DATA);
+ WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x3<<1));
+ hit_mcr_cnt = READ_VREG(HEVCD_MPP_DECOMP_PERFMON_DATA);
+
+ if (debug & AVS2_DBG_CACHE) {
+ pr_info("dcache_raw_cnt_total: %d\n", raw_mcr_cnt);
+ pr_info("dcache_hit_cnt_total: %d\n", hit_mcr_cnt);
+ }
+ if (raw_mcr_cnt != 0) {
+ hitrate = (hit_mcr_cnt / raw_mcr_cnt) * 100;
+ if (debug & AVS2_DBG_CACHE)
+ pr_info("DECOMP_DCACHE_HIT_RATE : %d\n", hitrate);
+ } else if (debug & AVS2_DBG_CACHE) {
+ pr_info("DECOMP_DCACHE_HIT_RATE : na\n");
+ }
+return;
+}
+
+static void decomp_get_comprate(void)
+{
+ u32 raw_ucomp_cnt;
+ u32 fast_comp_cnt;
+ u32 slow_comp_cnt;
+ int comprate;
+
+ if (debug & AVS2_DBG_CACHE)
+ pr_info("[cache_util.c] Entered decomp_get_comprate...\n");
+ WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x4<<1));
+ fast_comp_cnt = READ_VREG(HEVCD_MPP_DECOMP_PERFMON_DATA);
+ WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x5<<1));
+ slow_comp_cnt = READ_VREG(HEVCD_MPP_DECOMP_PERFMON_DATA);
+ WRITE_VREG(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x6<<1));
+ raw_ucomp_cnt = READ_VREG(HEVCD_MPP_DECOMP_PERFMON_DATA);
+ if (debug & AVS2_DBG_CACHE) {
+ pr_info("decomp_fast_comp_total: %d\n", fast_comp_cnt);
+ pr_info("decomp_slow_comp_total: %d\n", slow_comp_cnt);
+ pr_info("decomp_raw_uncomp_total: %d\n", raw_ucomp_cnt);
+ }
+
+ if (raw_ucomp_cnt != 0) {
+ comprate = ((fast_comp_cnt + slow_comp_cnt)
+ / raw_ucomp_cnt) * 100;
+ if (debug & AVS2_DBG_CACHE)
+ pr_info("DECOMP_COMP_RATIO : %d\n", comprate);
+ } else if (debug & AVS2_DBG_CACHE) {
+ pr_info("DECOMP_COMP_RATIO : na\n");
+ }
+ return;
+}
+#endif
+
+static void config_mcrcc_axi_hw(struct AVS2Decoder_s *dec)
+{
+ uint32_t rdata32;
+ uint32_t rdata32_2;
+ struct avs2_decoder *avs2_dec = &dec->avs2_dec;
+
+ WRITE_VREG(HEVCD_MCRCC_CTL1, 0x2); /* reset mcrcc*/
+
+ if (avs2_dec->img.type == I_IMG) { /* I-PIC*/
+ /* remove reset -- disables clock */
+ WRITE_VREG(HEVCD_MCRCC_CTL1, 0x0);
+ return;
+ }
+/*
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) {
+ mcrcc_get_hitrate();
+ decomp_get_hitrate();
+ decomp_get_comprate();
+ }
+*/
+ if ((avs2_dec->img.type == B_IMG) ||
+ (avs2_dec->img.type == F_IMG)) { /*B-PIC or F_PIC*/
+ /*Programme canvas0 */
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
+ (0 << 8) | (0 << 1) | 0);
+ rdata32 = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
+ rdata32 = rdata32 & 0xffff;
+ rdata32 = rdata32 | (rdata32 << 16);
+ WRITE_VREG(HEVCD_MCRCC_CTL2, rdata32);
+
+ /*Programme canvas1 */
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
+ (16 << 8) | (1 << 1) | 0);
+ rdata32_2 = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
+ rdata32_2 = rdata32_2 & 0xffff;
+ rdata32_2 = rdata32_2 | (rdata32_2 << 16);
+ if (rdata32 == rdata32_2) {
+ rdata32_2 =
+ READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
+ rdata32_2 = rdata32_2 & 0xffff;
+ rdata32_2 = rdata32_2 | (rdata32_2 << 16);
+ }
+ WRITE_VREG(HEVCD_MCRCC_CTL3, rdata32_2);
+ } else { /* P-PIC */
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
+ (0 << 8) | (1 << 1) | 0);
+ rdata32 = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
+ rdata32 = rdata32 & 0xffff;
+ rdata32 = rdata32 | (rdata32 << 16);
+ WRITE_VREG(HEVCD_MCRCC_CTL2, rdata32);
+
+ /*Programme canvas1*/
+ rdata32 =
+ READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
+ rdata32 = rdata32 & 0xffff;
+ rdata32 = rdata32 | (rdata32 << 16);
+ WRITE_VREG(HEVCD_MCRCC_CTL3, rdata32);
+ }
+ /*enable mcrcc progressive-mode */
+ WRITE_VREG(HEVCD_MCRCC_CTL1, 0xff0);
+ return;
+}
+
+static void config_mpred_hw(struct AVS2Decoder_s *dec)
+{
+ uint32_t data32;
+ struct avs2_decoder *avs2_dec = &dec->avs2_dec;
+ struct avs2_frame_s *cur_pic = avs2_dec->hc.cur_pic;
+ struct avs2_frame_s *col_pic = avs2_dec->fref[0];
+ int32_t mpred_mv_rd_start_addr;
+ int32_t mpred_curr_lcu_x;
+ int32_t mpred_curr_lcu_y;
+ int32_t mpred_mv_rd_end_addr;
+ int32_t above_en;
+ int32_t mv_wr_en;
+ int32_t mv_rd_en;
+ int32_t col_isIntra;
+ int mv_mem_unit;
+ if (avs2_dec->img.type != I_IMG) {
+ above_en = 1;
+ mv_wr_en = 1;
+ mv_rd_en = 1;
+ col_isIntra = 0;
+ } else {
+ above_en = 1;
+ mv_wr_en = 1;
+ mv_rd_en = 0;
+ col_isIntra = 0;
+ }
+
+ mpred_mv_rd_start_addr =
+ col_pic->mpred_mv_wr_start_addr;
+ data32 = READ_VREG(HEVC_MPRED_CURR_LCU);
+ mpred_curr_lcu_x = data32 & 0xffff;
+ mpred_curr_lcu_y = (data32 >> 16) & 0xffff;
+
+ mv_mem_unit = avs2_dec->lcu_size_log2 == 6 ?
+ 0x200 : (avs2_dec->lcu_size_log2 == 5 ?
+ 0x80 : 0x20);
+
+ mpred_mv_rd_end_addr =
+ mpred_mv_rd_start_addr +
+ ((avs2_dec->lcu_x_num *
+ avs2_dec->lcu_y_num) * mv_mem_unit);
+
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "cur pic index %d col pic index %d\n",
+ cur_pic->index, col_pic->index);
+
+
+ WRITE_VREG(HEVC_MPRED_MV_WR_START_ADDR,
+ cur_pic->mpred_mv_wr_start_addr);
+ WRITE_VREG(HEVC_MPRED_MV_RD_START_ADDR,
+ col_pic->mpred_mv_wr_start_addr);
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "[MPRED CO_MV] write 0x%x read 0x%x\n",
+ cur_pic->mpred_mv_wr_start_addr,
+ col_pic->mpred_mv_wr_start_addr);
+
+ data32 =
+ ((avs2_dec->bk_img_is_top_field) << 13) |
+ ((avs2_dec->hd.background_picture_enable & 1) << 12) |
+ ((avs2_dec->hd.curr_RPS.num_of_ref & 7) << 8) |
+ ((avs2_dec->hd.b_pmvr_enabled & 1) << 6) |
+ ((avs2_dec->img.is_top_field & 1) << 5) |
+ ((avs2_dec->img.is_field_sequence & 1) << 4) |
+ ((avs2_dec->img.typeb & 7) << 1) |
+ (avs2_dec->hd.background_reference_enable & 0x1);
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "HEVC_MPRED_CTRL9 <= 0x%x(num of ref %d)\n",
+ data32, avs2_dec->hd.curr_RPS.num_of_ref);
+ WRITE_VREG(HEVC_MPRED_CTRL9, data32);
+
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "%s: dis %d %d %d %d %d %d %d fref0_ref_poc %d %d %d %d %d %d %d\n",
+ __func__,
+ avs2_dec->fref[0]->imgtr_fwRefDistance,
+ avs2_dec->fref[1]->imgtr_fwRefDistance,
+ avs2_dec->fref[2]->imgtr_fwRefDistance,
+ avs2_dec->fref[3]->imgtr_fwRefDistance,
+ avs2_dec->fref[4]->imgtr_fwRefDistance,
+ avs2_dec->fref[5]->imgtr_fwRefDistance,
+ avs2_dec->fref[6]->imgtr_fwRefDistance,
+ avs2_dec->fref[0]->ref_poc[0],
+ avs2_dec->fref[0]->ref_poc[1],
+ avs2_dec->fref[0]->ref_poc[2],
+ avs2_dec->fref[0]->ref_poc[3],
+ avs2_dec->fref[0]->ref_poc[4],
+ avs2_dec->fref[0]->ref_poc[5],
+ avs2_dec->fref[0]->ref_poc[6]
+ );
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "pic_distance %d, imgtr_next_P %d\n",
+ avs2_dec->img.pic_distance, avs2_dec->img.imgtr_next_P);
+
+
+ WRITE_VREG(HEVC_MPRED_CUR_POC, avs2_dec->img.pic_distance);
+ WRITE_VREG(HEVC_MPRED_COL_POC, avs2_dec->img.imgtr_next_P);
+
+ /*below MPRED Ref_POC_xx_Lx registers
+ must follow Ref_POC_xx_L0 ->
+ Ref_POC_xx_L1 in pair write order!!!*/
+ WRITE_VREG(HEVC_MPRED_L0_REF00_POC,
+ avs2_dec->fref[0]->imgtr_fwRefDistance);
+ WRITE_VREG(HEVC_MPRED_L1_REF00_POC,
+ avs2_dec->fref[0]->ref_poc[0]);
+
+ WRITE_VREG(HEVC_MPRED_L0_REF01_POC,
+ avs2_dec->fref[1]->imgtr_fwRefDistance);
+ WRITE_VREG(HEVC_MPRED_L1_REF01_POC,
+ avs2_dec->fref[0]->ref_poc[1]);
+
+ WRITE_VREG(HEVC_MPRED_L0_REF02_POC,
+ avs2_dec->fref[2]->imgtr_fwRefDistance);
+ WRITE_VREG(HEVC_MPRED_L1_REF02_POC,
+ avs2_dec->fref[0]->ref_poc[2]);
+
+ WRITE_VREG(HEVC_MPRED_L0_REF03_POC,
+ avs2_dec->fref[3]->imgtr_fwRefDistance);
+ WRITE_VREG(HEVC_MPRED_L1_REF03_POC,
+ avs2_dec->fref[0]->ref_poc[3]);
+
+ WRITE_VREG(HEVC_MPRED_L0_REF04_POC,
+ avs2_dec->fref[4]->imgtr_fwRefDistance);
+ WRITE_VREG(HEVC_MPRED_L1_REF04_POC,
+ avs2_dec->fref[0]->ref_poc[4]);
+
+ WRITE_VREG(HEVC_MPRED_L0_REF05_POC,
+ avs2_dec->fref[5]->imgtr_fwRefDistance);
+ WRITE_VREG(HEVC_MPRED_L1_REF05_POC,
+ avs2_dec->fref[0]->ref_poc[5]);
+
+ WRITE_VREG(HEVC_MPRED_L0_REF06_POC,
+ avs2_dec->fref[6]->imgtr_fwRefDistance);
+ WRITE_VREG(HEVC_MPRED_L1_REF06_POC,
+ avs2_dec->fref[0]->ref_poc[6]);
+
+
+ WRITE_VREG(HEVC_MPRED_MV_RD_END_ADDR,
+ mpred_mv_rd_end_addr);
+}
+
+static void config_dblk_hw(struct AVS2Decoder_s *dec)
+{
+ /*
+ * Picture level de-block parameter configuration here
+ */
+ struct avs2_decoder *avs2_dec = &dec->avs2_dec;
+ union param_u *rpm_param = &avs2_dec->param;
+ uint32_t data32;
+
+ data32 = READ_VREG(HEVC_DBLK_CFG1);
+ data32 = (((data32 >> 20) & 0xfff) << 20) |
+ (((avs2_dec->input.sample_bit_depth == 10)
+ ? 0xa : 0x0) << 16) | /*[16 +: 4]: {luma_bd[1:0],
+ chroma_bd[1:0]}*/
+ (((data32 >> 2) & 0x3fff) << 2) |
+ (((rpm_param->p.lcu_size == 6)
+ ? 0 : (rpm_param->p.lcu_size == 5)
+ ? 1 : 2) << 0);/*[ 0 +: 2]: lcu_size*/
+ WRITE_VREG(HEVC_DBLK_CFG1, data32);
+
+ data32 = (avs2_dec->img.height << 16) |
+ avs2_dec->img.width;
+ WRITE_VREG(HEVC_DBLK_CFG2, data32);
+ /*
+ [27 +: 1]: cross_slice_loopfilter_enable_flag
+ [26 +: 1]: loop_filter_disable
+ [25 +: 1]: useNSQT
+ [22 +: 3]: imgtype
+ [17 +: 5]: alpha_c_offset (-8~8)
+ [12 +: 5]: beta_offset (-8~8)
+ [ 6 +: 6]: chroma_quant_param_delta_u (-16~16)
+ [ 0 +: 6]: chroma_quant_param_delta_v (-16~16)
+ */
+ data32 = ((avs2_dec->input.crossSliceLoopFilter
+ & 0x1) << 27) |
+ ((rpm_param->p.loop_filter_disable & 0x1) << 26) |
+ ((avs2_dec->input.useNSQT & 0x1) << 25) |
+ ((avs2_dec->img.type & 0x7) << 22) |
+ ((rpm_param->p.alpha_c_offset & 0x1f) << 17) |
+ ((rpm_param->p.beta_offset & 0x1f) << 12) |
+ ((rpm_param->p.chroma_quant_param_delta_cb & 0x3f) << 6) |
+ ((rpm_param->p.chroma_quant_param_delta_cr & 0x3f) << 0);
+
+ WRITE_VREG(HEVC_DBLK_CFG9, data32);
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "[c] cfgDBLK: crossslice(%d),lfdisable(%d),bitDepth(%d),lcuSize(%d),NSQT(%d)\n",
+ avs2_dec->input.crossSliceLoopFilter,
+ rpm_param->p.loop_filter_disable,
+ avs2_dec->input.sample_bit_depth,
+ avs2_dec->lcu_size,
+ avs2_dec->input.useNSQT);
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "[c] cfgDBLK: alphaCOffset(%d),betaOffset(%d),quantDeltaCb(%d),quantDeltaCr(%d)\n",
+ rpm_param->p.alpha_c_offset,
+ rpm_param->p.beta_offset,
+ rpm_param->p.chroma_quant_param_delta_cb,
+ rpm_param->p.chroma_quant_param_delta_cr);
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "[c] cfgDBLK: .done.\n");
+}
+
+static void config_sao_hw(struct AVS2Decoder_s *dec)
+{
+ uint32_t data32;
+ struct avs2_decoder *avs2_dec = &dec->avs2_dec;
+ struct avs2_frame_s *cur_pic = avs2_dec->hc.cur_pic;
+
+ int lcu_size = 64;
+ int mc_buffer_size_u_v =
+ cur_pic->lcu_total * lcu_size*lcu_size/2;
+ int mc_buffer_size_u_v_h =
+ (mc_buffer_size_u_v + 0xffff) >> 16;/*64k alignment*/
+
+ data32 = READ_VREG(HEVC_SAO_CTRL0);
+ data32 &= (~0xf);
+ data32 |= avs2_dec->lcu_size_log2;
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "%s, lcu_size_log2 = %d, config HEVC_SAO_CTRL0 0x%x\n",
+ __func__,
+ avs2_dec->lcu_size_log2,
+ data32);
+
+ WRITE_VREG(HEVC_SAO_CTRL0, data32);
+
+#ifndef AVS2_10B_MMU
+ if ((get_double_write_mode(dec) & 0x10) == 0)
+ WRITE_VREG(HEVC_CM_BODY_START_ADDR, cur_pic->mc_y_adr);
+#endif
+ if (get_double_write_mode(dec)) {
+ WRITE_VREG(HEVC_SAO_Y_START_ADDR, cur_pic->dw_y_adr);
+ WRITE_VREG(HEVC_SAO_C_START_ADDR, cur_pic->dw_u_v_adr);
+ WRITE_VREG(HEVC_SAO_Y_WPTR, cur_pic->dw_y_adr);
+ WRITE_VREG(HEVC_SAO_C_WPTR, cur_pic->dw_u_v_adr);
+ } else {
+ WRITE_VREG(HEVC_SAO_Y_START_ADDR, 0xffffffff);
+ WRITE_VREG(HEVC_SAO_C_START_ADDR, 0xffffffff);
+ }
+#ifdef AVS2_10B_MMU
+ WRITE_VREG(HEVC_CM_HEADER_START_ADDR, cur_pic->header_adr);
+#endif
+ data32 = (mc_buffer_size_u_v_h << 16) << 1;
+ /*pr_info("data32=%x,mc_buffer_size_u_v_h=%x,lcu_total=%x\n",
+ data32, mc_buffer_size_u_v_h, cur_pic->lcu_total);*/
+ WRITE_VREG(HEVC_SAO_Y_LENGTH, data32);
+
+ data32 = (mc_buffer_size_u_v_h << 16);
+ WRITE_VREG(HEVC_SAO_C_LENGTH, data32);
+
+#ifdef AVS2_10B_NV21
+#ifdef DOS_PROJECT
+ data32 = READ_VREG(HEVC_SAO_CTRL1);
+ data32 &= (~0x3000);
+ /*[13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32*/
+ data32 |= (MEM_MAP_MODE << 12);
+ data32 &= (~0x3);
+ data32 |= 0x1; /* [1]:dw_disable [0]:cm_disable*/
+ 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);
+
+ 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*/
+ WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32);
+#endif
+#else
+ data32 = READ_VREG(HEVC_SAO_CTRL1);
+ data32 &= (~0x3000);
+ data32 |= (MEM_MAP_MODE <<
+ 12); /* [13:12] axi_aformat, 0-Linear,
+ 1-32x32, 2-64x32 */
+ data32 &= (~0xff0);
+ /* data32 |= 0x670; // Big-Endian per 64-bit */
+ data32 |= endian; /* Big-Endian per 64-bit */
+ 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*/
+
+ 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 {
+ data32 = READ_VREG(HEVC_SAO_CTRL5);
+ data32 &= (~(0xff << 16));
+ if (get_double_write_mode(dec) == 2 ||
+ get_double_write_mode(dec) == 3)
+ data32 |= (0xff<<16);
+ else if (get_double_write_mode(dec) == 4)
+ data32 |= (0x33<<16);
+ WRITE_VREG(HEVC_SAO_CTRL5, data32);
+ }
+
+ data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG);
+ data32 &= (~0x30);
+ /* [5:4] -- address_format 00:linear 01:32x32 10:64x32 */
+ data32 |= (mem_map_mode <<
+ 4);
+ data32 &= (~0xF);
+ data32 |= 0xf; /* valid only when double write only */
+ /*data32 |= 0x8;*/ /* Big-Endian per 64-bit */
+ WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32);
+#endif
+}
+
+static void reconstructCoefficients(struct AVS2Decoder_s *dec,
+ struct ALFParam_s *alfParam)
+{
+ int32_t g, sum, i, coeffPred;
+ for (g = 0; g < alfParam->filters_per_group; g++) {
+ sum = 0;
+ for (i = 0; i < alfParam->num_coeff - 1; i++) {
+ sum += (2 * alfParam->coeffmulti[g][i]);
+ dec->m_filterCoeffSym[g][i] =
+ alfParam->coeffmulti[g][i];
+ /*pr_info("[t] dec->m_filterCoeffSym[%d][%d]=0x%x\n",
+ g, i, dec->m_filterCoeffSym[g][i]);*/
+ }
+ coeffPred = (1 << ALF_NUM_BIT_SHIFT) - sum;
+ dec->m_filterCoeffSym[g][alfParam->num_coeff - 1]
+ = coeffPred +
+ alfParam->coeffmulti[g][alfParam->num_coeff - 1];
+ /*pr_info("[t] dec->m_filterCoeffSym[%d][%d]=0x%x\n",
+ g, (alfParam->num_coeff - 1),
+ dec->m_filterCoeffSym[g][alfParam->num_coeff - 1]);*/
+ }
+}
+
+static void reconstructCoefInfo(struct AVS2Decoder_s *dec,
+ int32_t compIdx, struct ALFParam_s *alfParam)
+{
+ int32_t i;
+ if (compIdx == ALF_Y) {
+ if (alfParam->filters_per_group > 1) {
+ for (i = 1; i < NO_VAR_BINS; ++i) {
+ if (alfParam->filterPattern[i])
+ dec->m_varIndTab[i] =
+ dec->m_varIndTab[i - 1] + 1;
+ else
+ dec->m_varIndTab[i] =
+ dec->m_varIndTab[i - 1];
+ }
+ }
+ }
+ reconstructCoefficients(dec, alfParam);
+}
+
+static void config_alf_hw(struct AVS2Decoder_s *dec)
+{
+ /*
+ * Picture level ALF parameter configuration here
+ */
+ uint32_t data32;
+ int32_t i, j;
+ int32_t m_filters_per_group;
+ struct avs2_decoder *avs2_dec = &dec->avs2_dec;
+ struct ALFParam_s *m_alfPictureParam_y =
+ &avs2_dec->m_alfPictureParam[0];
+ struct ALFParam_s *m_alfPictureParam_cb =
+ &avs2_dec->m_alfPictureParam[1];
+ struct ALFParam_s *m_alfPictureParam_cr =
+ &avs2_dec->m_alfPictureParam[2];
+
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "[t]alfy,cidx(%d),flag(%d),filters_per_group(%d),filterPattern[0]=0x%x,[15]=0x%x\n",
+ m_alfPictureParam_y->componentID,
+ m_alfPictureParam_y->alf_flag,
+ m_alfPictureParam_y->filters_per_group,
+ m_alfPictureParam_y->filterPattern[0],
+ m_alfPictureParam_y->filterPattern[15]);
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "[t]alfy,num_coeff(%d),coeffmulti[0][0]=0x%x,[0][1]=0x%x,[1][0]=0x%x,[1][1]=0x%x\n",
+ m_alfPictureParam_y->num_coeff,
+ m_alfPictureParam_y->coeffmulti[0][0],
+ m_alfPictureParam_y->coeffmulti[0][1],
+ m_alfPictureParam_y->coeffmulti[1][0],
+ m_alfPictureParam_y->coeffmulti[1][1]);
+
+ /*Cr*/
+ for (i = 0; i < 16; i++)
+ dec->m_varIndTab[i] = 0;
+ for (j = 0; j < 16; j++)
+ for (i = 0; i < 9; i++)
+ dec->m_filterCoeffSym[j][i] = 0;
+ reconstructCoefInfo(dec, 2, m_alfPictureParam_cr);
+ data32 =
+ ((dec->m_filterCoeffSym[0][4] & 0xf) << 28) |
+ ((dec->m_filterCoeffSym[0][3] & 0x7f) << 21) |
+ ((dec->m_filterCoeffSym[0][2] & 0x7f) << 14) |
+ ((dec->m_filterCoeffSym[0][1] & 0x7f) << 7) |
+ ((dec->m_filterCoeffSym[0][0] & 0x7f) << 0);
+ WRITE_VREG(HEVC_DBLK_CFGD, data32);
+ data32 =
+ ((dec->m_filterCoeffSym[0][8] & 0x7f) << 24) |
+ ((dec->m_filterCoeffSym[0][7] & 0x7f) << 17) |
+ ((dec->m_filterCoeffSym[0][6] & 0x7f) << 10) |
+ ((dec->m_filterCoeffSym[0][5] & 0x7f) << 3) |
+ (((dec->m_filterCoeffSym[0][4] >> 4) & 0x7) << 0);
+ WRITE_VREG(HEVC_DBLK_CFGD, data32);
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "[c] pic_alf_on_cr(%d), alf_cr_coef(%d %d %d %d %d %d %d %d %d)\n",
+ m_alfPictureParam_cr->alf_flag,
+ dec->m_filterCoeffSym[0][0],
+ dec->m_filterCoeffSym[0][1],
+ dec->m_filterCoeffSym[0][2],
+ dec->m_filterCoeffSym[0][3],
+ dec->m_filterCoeffSym[0][4],
+ dec->m_filterCoeffSym[0][5],
+ dec->m_filterCoeffSym[0][6],
+ dec->m_filterCoeffSym[0][7],
+ dec->m_filterCoeffSym[0][8]);
+
+ /* Cb*/
+ for (j = 0; j < 16; j++)
+ for (i = 0; i < 9; i++)
+ dec->m_filterCoeffSym[j][i] = 0;
+ reconstructCoefInfo(dec, 1, m_alfPictureParam_cb);
+ data32 =
+ ((dec->m_filterCoeffSym[0][4] & 0xf) << 28) |
+ ((dec->m_filterCoeffSym[0][3] & 0x7f) << 21) |
+ ((dec->m_filterCoeffSym[0][2] & 0x7f) << 14) |
+ ((dec->m_filterCoeffSym[0][1] & 0x7f) << 7) |
+ ((dec->m_filterCoeffSym[0][0] & 0x7f) << 0);
+ WRITE_VREG(HEVC_DBLK_CFGD, data32);
+ data32 =
+ ((dec->m_filterCoeffSym[0][8] & 0x7f) << 24) |
+ ((dec->m_filterCoeffSym[0][7] & 0x7f) << 17) |
+ ((dec->m_filterCoeffSym[0][6] & 0x7f) << 10) |
+ ((dec->m_filterCoeffSym[0][5] & 0x7f) << 3) |
+ (((dec->m_filterCoeffSym[0][4] >> 4) & 0x7) << 0);
+ WRITE_VREG(HEVC_DBLK_CFGD, data32);
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "[c] pic_alf_on_cb(%d), alf_cb_coef(%d %d %d %d %d %d %d %d %d)\n",
+ m_alfPictureParam_cb->alf_flag,
+ dec->m_filterCoeffSym[0][0],
+ dec->m_filterCoeffSym[0][1],
+ dec->m_filterCoeffSym[0][2],
+ dec->m_filterCoeffSym[0][3],
+ dec->m_filterCoeffSym[0][4],
+ dec->m_filterCoeffSym[0][5],
+ dec->m_filterCoeffSym[0][6],
+ dec->m_filterCoeffSym[0][7],
+ dec->m_filterCoeffSym[0][8]);
+
+ /* Y*/
+ for (j = 0; j < 16; j++)
+ for (i = 0; i < 9; i++)
+ dec->m_filterCoeffSym[j][i] = 0;
+ reconstructCoefInfo(dec, 0, m_alfPictureParam_y);
+ data32 =
+ ((dec->m_varIndTab[7] & 0xf) << 28) |
+ ((dec->m_varIndTab[6] & 0xf) << 24) |
+ ((dec->m_varIndTab[5] & 0xf) << 20) |
+ ((dec->m_varIndTab[4] & 0xf) << 16) |
+ ((dec->m_varIndTab[3] & 0xf) << 12) |
+ ((dec->m_varIndTab[2] & 0xf) << 8) |
+ ((dec->m_varIndTab[1] & 0xf) << 4) |
+ ((dec->m_varIndTab[0] & 0xf) << 0);
+ WRITE_VREG(HEVC_DBLK_CFGD, data32);
+ data32 = ((dec->m_varIndTab[15] & 0xf) << 28) |
+ ((dec->m_varIndTab[14] & 0xf) << 24) |
+ ((dec->m_varIndTab[13] & 0xf) << 20) |
+ ((dec->m_varIndTab[12] & 0xf) << 16) |
+ ((dec->m_varIndTab[11] & 0xf) << 12) |
+ ((dec->m_varIndTab[10] & 0xf) << 8) |
+ ((dec->m_varIndTab[9] & 0xf) << 4) |
+ ((dec->m_varIndTab[8] & 0xf) << 0);
+ WRITE_VREG(HEVC_DBLK_CFGD, data32);
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "[c] pic_alf_on_y(%d), alf_y_tab(%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d)\n",
+ m_alfPictureParam_y->alf_flag,
+ dec->m_varIndTab[0],
+ dec->m_varIndTab[1],
+ dec->m_varIndTab[2],
+ dec->m_varIndTab[3],
+ dec->m_varIndTab[4],
+ dec->m_varIndTab[5],
+ dec->m_varIndTab[6],
+ dec->m_varIndTab[7],
+ dec->m_varIndTab[8],
+ dec->m_varIndTab[9],
+ dec->m_varIndTab[10],
+ dec->m_varIndTab[11],
+ dec->m_varIndTab[12],
+ dec->m_varIndTab[13],
+ dec->m_varIndTab[14],
+ dec->m_varIndTab[15]);
+
+ m_filters_per_group =
+ (m_alfPictureParam_y->alf_flag == 0) ?
+ 1 : m_alfPictureParam_y->filters_per_group;
+ for (i = 0; i < m_filters_per_group; i++) {
+ data32 =
+ ((dec->m_filterCoeffSym[i][4] & 0xf) << 28) |
+ ((dec->m_filterCoeffSym[i][3] & 0x7f) << 21) |
+ ((dec->m_filterCoeffSym[i][2] & 0x7f) << 14) |
+ ((dec->m_filterCoeffSym[i][1] & 0x7f) << 7) |
+ ((dec->m_filterCoeffSym[i][0] & 0x7f) << 0);
+ WRITE_VREG(HEVC_DBLK_CFGD, data32);
+ data32 =
+ /*[31] last indication*/
+ ((i == m_filters_per_group-1) << 31) |
+ ((dec->m_filterCoeffSym[i][8] & 0x7f) << 24) |
+ ((dec->m_filterCoeffSym[i][7] & 0x7f) << 17) |
+ ((dec->m_filterCoeffSym[i][6] & 0x7f) << 10) |
+ ((dec->m_filterCoeffSym[i][5] & 0x7f) << 3) |
+ (((dec->m_filterCoeffSym[i][4] >> 4) & 0x7) << 0);
+ WRITE_VREG(HEVC_DBLK_CFGD, data32);
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "[c] alf_y_coef[%d](%d %d %d %d %d %d %d %d %d)\n",
+ i, dec->m_filterCoeffSym[i][0],
+ dec->m_filterCoeffSym[i][1],
+ dec->m_filterCoeffSym[i][2],
+ dec->m_filterCoeffSym[i][3],
+ dec->m_filterCoeffSym[i][4],
+ dec->m_filterCoeffSym[i][5],
+ dec->m_filterCoeffSym[i][6],
+ dec->m_filterCoeffSym[i][7],
+ dec->m_filterCoeffSym[i][8]);
+ }
+ avs2_print(dec, AVS2_DBG_BUFMGR_DETAIL,
+ "[c] cfgALF .done.\n");
+}
+
+static void config_other_hw(struct AVS2Decoder_s *dec)
+{
+ uint32_t data32;
+ struct avs2_decoder *avs2_dec = &dec->avs2_dec;
+ struct avs2_frame_s *cur_pic = avs2_dec->hc.cur_pic;
+ int bit_depth = cur_pic->bit_depth;
+ int losless_comp_header_size =
+ compute_losless_comp_header_size(
+ dec, cur_pic->pic_w,
+ cur_pic->pic_h);
+ int losless_comp_body_size =
+ compute_losless_comp_body_size(
+ dec, cur_pic->pic_w,
+ cur_pic->pic_h, (bit_depth == AVS2_BITS_10));
+ cur_pic->comp_body_size = losless_comp_body_size;
+
+#ifdef LOSLESS_COMPRESS_MODE
+ data32 = READ_VREG(HEVC_SAO_CTRL5);
+ if (bit_depth == AVS2_BITS_10)
+ data32 &= ~(1 << 9);
+ else
+ data32 |= (1 << 9);
+
+ WRITE_VREG(HEVC_SAO_CTRL5, data32);
+
+#ifdef AVS2_10B_MMU
+ /*bit[4] : paged_mem_mode*/
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0x1 << 4));
+#else
+ /*bit[3] smem mdoe*/
+ if (bit_depth == AVS2_BITS_10)
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0 << 3));
+ else
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (1 << 3));
+#endif
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL2, (losless_comp_body_size >> 5));
+ /*WRITE_VREG(HEVCD_MPP_DECOMP_CTL3,(0xff<<20) | (0xff<<10) | 0xff);*/
+ WRITE_VREG(HEVC_CM_BODY_LENGTH, losless_comp_body_size);
+ WRITE_VREG(HEVC_CM_HEADER_OFFSET, losless_comp_body_size);
+ WRITE_VREG(HEVC_CM_HEADER_LENGTH, losless_comp_header_size);
+#else
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31);
+#endif
+}
+
+static void avs2_config_work_space_hw(struct AVS2Decoder_s *dec)
+{
+ struct BuffInfo_s *buf_spec = dec->work_space_buf;
+#ifdef LOSLESS_COMPRESS_MODE
+ int losless_comp_header_size =
+ compute_losless_comp_header_size(
+ dec, dec->init_pic_w,
+ dec->init_pic_h);
+ int losless_comp_body_size =
+ compute_losless_comp_body_size(dec,
+ dec->init_pic_w,
+ dec->init_pic_h, buf_alloc_depth == 10);
+#endif
+#ifdef AVS2_10B_MMU
+ unsigned int data32;
+#endif
+ if (debug && dec->init_flag == 0)
+ avs2_print(dec, 0,
+ "%s %x %x %x %x %x %x %x %x %x %x %x %x %x\n",
+ __func__,
+ buf_spec->ipp.buf_start,
+ buf_spec->start_adr,
+ buf_spec->short_term_rps.buf_start,
+ buf_spec->rcs.buf_start,
+ buf_spec->sps.buf_start,
+ buf_spec->pps.buf_start,
+ buf_spec->sao_up.buf_start,
+ buf_spec->swap_buf.buf_start,
+ buf_spec->swap_buf2.buf_start,
+ buf_spec->scalelut.buf_start,
+ buf_spec->dblk_para.buf_start,
+ buf_spec->dblk_data.buf_start,
+ buf_spec->dblk_data2.buf_start);
+ WRITE_VREG(HEVCD_IPP_LINEBUFF_BASE, buf_spec->ipp.buf_start);
+ if ((debug & AVS2_DBG_SEND_PARAM_WITH_REG) == 0)
+ WRITE_VREG(HEVC_RPM_BUFFER, (u32)dec->rpm_phy_addr);
+ WRITE_VREG(AVS2_ALF_SWAP_BUFFER, buf_spec->short_term_rps.buf_start);
+ WRITE_VREG(HEVC_RCS_BUFFER, buf_spec->rcs.buf_start);
+ WRITE_VREG(HEVC_SPS_BUFFER, buf_spec->sps.buf_start);
+ WRITE_VREG(HEVC_PPS_BUFFER, buf_spec->pps.buf_start);
+ //WRITE_VREG(HEVC_SAO_UP, buf_spec->sao_up.buf_start);
+#ifdef AVS2_10B_MMU
+ WRITE_VREG(AVS2_MMU_MAP_BUFFER, dec->frame_mmu_map_phy_addr);
+#else
+ WRITE_VREG(HEVC_STREAM_SWAP_BUFFER, buf_spec->swap_buf.buf_start);
+#endif
+ WRITE_VREG(HEVC_STREAM_SWAP_BUFFER2, buf_spec->swap_buf2.buf_start);
+ //WRITE_VREG(HEVC_SCALELUT, buf_spec->scalelut.buf_start);
+
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) {
+ if (buf_spec->max_width <= 4096 && buf_spec->max_height <= 2304)
+ WRITE_VREG(HEVC_DBLK_CFG3, 0x404010); //default value
+ else
+ WRITE_VREG(HEVC_DBLK_CFG3, 0x808020); // make left storage 2 x 4k]
+ avs2_print(dec, AVS2_DBG_BUFMGR,
+ "HEVC_DBLK_CFG3 = %x\n", READ_VREG(HEVC_DBLK_CFG3));
+ }
+
+ /* cfg_p_addr */
+ WRITE_VREG(HEVC_DBLK_CFG4, buf_spec->dblk_para.buf_start);
+ /* cfg_d_addr */
+ WRITE_VREG(HEVC_DBLK_CFG5, buf_spec->dblk_data.buf_start);
+
+ WRITE_VREG(HEVC_DBLK_CFGE, buf_spec->dblk_data2.buf_start);
+
+#ifdef LOSLESS_COMPRESS_MODE
+ data32 = READ_VREG(HEVC_SAO_CTRL5);
+#if 1
+ data32 &= ~(1<<9);
+#else
+ if (params->p.bit_depth != 0x00)
+ data32 &= ~(1<<9);
+ else
+ data32 |= (1<<9);
+#endif
+ WRITE_VREG(HEVC_SAO_CTRL5, data32);
+#ifdef AVS2_10B_MMU
+ /*bit[4] : paged_mem_mode*/
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0x1 << 4));
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL2, 0);
+#else
+ /* bit[3] smem mode*/
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0<<3));
+
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL2, (losless_comp_body_size >> 5));
+#endif
+ /*WRITE_VREG(HEVCD_MPP_DECOMP_CTL2,(losless_comp_body_size >> 5));*/
+ /*WRITE_VREG(HEVCD_MPP_DECOMP_CTL3,(0xff<<20) | (0xff<<10) | 0xff);*/
+/*8-bit mode */
+ WRITE_VREG(HEVC_CM_BODY_LENGTH, losless_comp_body_size);
+ WRITE_VREG(HEVC_CM_HEADER_OFFSET, losless_comp_body_size);
+ WRITE_VREG(HEVC_CM_HEADER_LENGTH, losless_comp_header_size);
+#else
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31);
+#endif
+
+#ifdef AVS2_10B_MMU
+ WRITE_VREG(HEVC_SAO_MMU_VH0_ADDR, buf_spec->mmu_vbh.buf_start);
+ WRITE_VREG(HEVC_SAO_MMU_VH1_ADDR, buf_spec->mmu_vbh.buf_start
+ + VBH_BUF_SIZE(buf_spec));
+ /*data32 = READ_VREG(HEVC_SAO_CTRL9);*/
+ /*data32 |= 0x1;*/
+ /*WRITE_VREG(HEVC_SAO_CTRL9, data32);*/
+
+ /* use HEVC_CM_HEADER_START_ADDR */
+ data32 = READ_VREG(HEVC_SAO_CTRL5);
+ data32 |= (1<<10);
+#if 1
+ if (debug & AVS2_DBG_FORCE_UNCOMPRESS)
+ data32 |= 0x80;
+#endif
+ WRITE_VREG(HEVC_SAO_CTRL5, data32);
+
+#endif
+
+ WRITE_VREG(LMEM_DUMP_ADR, (u32)dec->lmem_phy_addr);
+#if 1
+/*MULTI_INSTANCE_SUPPORT*/
+ /*new added in simulation???*/
+ WRITE_VREG(HEVC_MPRED_ABV_START_ADDR, buf_spec->mpred_above.buf_start);
+#endif
+}
+
+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*/
+
+ 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->lmem_addr) {
+ if (dec->lmem_phy_addr)
+ dma_free_coherent(amports_get_dma_device(),
+ LMEM_BUF_SIZE, dec->lmem_addr,
+ dec->lmem_phy_addr);
+ dec->lmem_addr = NULL;
+ }
+
+#ifdef AVS2_10B_MMU
+ if (dec->frame_mmu_map_addr) {
+ if (dec->frame_mmu_map_phy_addr)
+ dma_free_coherent(amports_get_dma_device(),
+ get_frame_mmu_map_size(dec), dec->frame_mmu_map_addr,
+ dec->frame_mmu_map_phy_addr);
+ dec->frame_mmu_map_addr = NULL;
+ }
+#endif
+ if (dec->gvs)
+ vfree(dec->gvs);
+ dec->gvs = NULL;
+}
+
+static int avs2_local_init(struct AVS2Decoder_s *dec)
+{
+ int ret = -1;
+ /*int losless_comp_header_size, losless_comp_body_size;*/
+
+ struct BuffInfo_s *cur_buf_info = NULL;
+
+ cur_buf_info = &dec->work_space_buf_store;
+ if (force_bufspec) {
+ memcpy(cur_buf_info, &amvavs2_workbuff_spec[force_bufspec & 0xf],
+ sizeof(struct BuffInfo_s));
+ pr_info("force buffer spec %d\n", force_bufspec & 0xf);
+ } else if (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));
+
+ cur_buf_info->start_adr = dec->buf_start;
+#ifndef AVS2_10B_MMU
+ dec->mc_buf_spec.buf_end = dec->buf_start + dec->buf_size;
+#endif
+
+ init_buff_spec(dec, cur_buf_info);
+
+ init_avs2_decoder(&dec->avs2_dec);
+
+#ifdef AVS2_10B_MMU
+ avs2_bufmgr_init(dec, cur_buf_info, NULL);
+#else
+ dec->mc_buf_spec.buf_start = (cur_buf_info->end_adr + 0xffff)
+ & (~0xffff);
+ dec->mc_buf_spec.buf_size = (dec->mc_buf_spec.buf_end
+ - dec->mc_buf_spec.buf_start);
+ if (debug) {
+ pr_err("dec->mc_buf_spec.buf_start %x-%x\n",
+ dec->mc_buf_spec.buf_start,
+ dec->mc_buf_spec.buf_start +
+ dec->mc_buf_spec.buf_size);
+ }
+ avs2_bufmgr_init(dec, cur_buf_info, &dec->mc_buf_spec);
+#endif
+
+ if (!vdec_is_support_4k()
+ && (buf_alloc_width > 1920 && buf_alloc_height > 1088)) {
+ buf_alloc_width = 1920;
+ buf_alloc_height = 1088;
+ } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) {
+ buf_alloc_width = 8192;
+ buf_alloc_height = 4608;
+ }
+ dec->init_pic_w = buf_alloc_width ? buf_alloc_width :
+ (dec->vavs2_amstream_dec_info.width ?
+ dec->vavs2_amstream_dec_info.width :
+ dec->work_space_buf->max_width);
+ dec->init_pic_h = buf_alloc_height ? buf_alloc_height :
+ (dec->vavs2_amstream_dec_info.height ?
+ dec->vavs2_amstream_dec_info.height :
+ dec->work_space_buf->max_height);
+#if 0
+/*ndef MV_USE_FIXED_BUF*/
+ if (init_mv_buf_list(dec) < 0) {
+ pr_err("%s: init_mv_buf_list fail\n", __func__);
+ return -1;
+ }
+#endif
+
+#ifndef AVS2_10B_MMU
+ init_buf_list(dec);
+#else
+ dec->used_buf_num = max_buf_num + dec->dynamic_buf_margin;
+ if (dec->used_buf_num > MAX_BUF_NUM)
+ dec->used_buf_num = MAX_BUF_NUM;
+ if (dec->used_buf_num > FRAME_BUFFERS)
+ dec->used_buf_num = FRAME_BUFFERS;
+#endif
+ dec->avs2_dec.ref_maxbuffer = dec->used_buf_num - 1;
+ /*init_pic_list(dec);*/
+
+ pts_unstable = ((unsigned long)(dec->vavs2_amstream_dec_info.param)
+ & 0x40) >> 6;
+
+ if ((debug & AVS2_DBG_SEND_PARAM_WITH_REG) == 0) {
+ dec->rpm_addr = dma_alloc_coherent(amports_get_dma_device(),
+ RPM_BUF_SIZE,
+ &dec->rpm_phy_addr, GFP_KERNEL);
+ if (dec->rpm_addr == NULL) {
+ pr_err("%s: failed to alloc rpm buffer\n", __func__);
+ return -1;
+ }
+ avs2_print(dec, AVS2_DBG_BUFMGR,
+ "rpm_phy_addr %x\n", (u32) dec->rpm_phy_addr);
+ dec->rpm_ptr = dec->rpm_addr;
+ }
+
+ 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
+ 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
+
+ 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(dec,
+ pic->double_write_mode);
+ canvas_h = pic->pic_h /
+ get_double_write_ratio(dec,
+ pic->double_write_mode);
+
+ if (mem_map_mode == 0)
+ canvas_w = ALIGN(canvas_w, 32);
+ else
+ canvas_w = ALIGN(canvas_w, 64);
+ 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;
+ }
+
+ canvas_config_ex(pic->y_canvas_index,
+ pic->dw_y_adr, canvas_w, canvas_h,
+ CANVAS_ADDR_NOWRAP, blkmode, 0x7);
+ canvas_config_ex(pic->uv_canvas_index,
+ pic->dw_u_v_adr, canvas_w, canvas_h,
+ CANVAS_ADDR_NOWRAP, blkmode, 0x7);
+#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;
+ }
+
+ canvas_config_ex(pic->y_canvas_index,
+ pic->mc_y_adr, canvas_w, canvas_h,
+ CANVAS_ADDR_NOWRAP, blkmode, 0x7);
+ canvas_config_ex(pic->uv_canvas_index,
+ pic->mc_u_v_adr, canvas_w, canvas_h,
+ CANVAS_ADDR_NOWRAP, blkmode, 0x7);
+ #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;
+ vf->signal_type = dec->video_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_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;
+ }
+
+ return 0;
+}
+
+static struct avs2_frame_s *get_disp_pic(struct AVS2Decoder_s *dec)
+{
+ struct avs2_decoder *avs2_dec = &dec->avs2_dec;
+ struct avs2_frame_s *pic = NULL;
+ int32_t j;
+ int32_t pre_disp_count_min = 0x7fffffff;
+ for (j = 0; j < avs2_dec->ref_maxbuffer; j++) {
+ if (avs2_dec->fref[j]->to_prepare_disp &&
+ avs2_dec->fref[j]->to_prepare_disp <
+ pre_disp_count_min) {
+ pre_disp_count_min =
+ avs2_dec->fref[j]->to_prepare_disp;
+ pic = avs2_dec->fref[j];
+ }
+ }
+ if (pic)
+ pic->to_prepare_disp = 0;
+
+ return pic;
+
+}
+
+
+
+static void fill_frame_info(struct AVS2Decoder_s *dec,
+ struct avs2_frame_s *pic, unsigned int framesize, unsigned int pts)
+{
+ struct vframe_qos_s *vframe_qos = &dec->vframe_qos;
+
+ if (pic->slice_type == I_IMG)
+ vframe_qos->type = 1;
+ else if (pic->slice_type == P_IMG)
+ vframe_qos->type = 2;
+ else if (pic->slice_type == B_IMG)
+ vframe_qos->type = 3;
+/*
+#define SHOW_QOS_INFO
+*/
+ if (input_frame_based(hw_to_vdec(dec)))
+ vframe_qos->size = pic->frame_size;
+ else
+ vframe_qos->size = framesize;
+ vframe_qos->pts = pts;
+#ifdef SHOW_QOS_INFO
+ avs2_print(dec, 0, "slice:%d\n", pic->slice_type);
+#endif
+
+
+ vframe_qos->max_mv = pic->max_mv;
+ vframe_qos->avg_mv = pic->avg_mv;
+ vframe_qos->min_mv = pic->min_mv;
+#ifdef SHOW_QOS_INFO
+ avs2_print(dec, 0, "mv: max:%d, avg:%d, min:%d\n",
+ vframe_qos->max_mv,
+ vframe_qos->avg_mv,
+ vframe_qos->min_mv);
+#endif
+
+ vframe_qos->max_qp = pic->max_qp;
+ vframe_qos->avg_qp = pic->avg_qp;
+ vframe_qos->min_qp = pic->min_qp;
+#ifdef SHOW_QOS_INFO
+ avs2_print(dec, 0, "qp: max:%d, avg:%d, min:%d\n",
+ vframe_qos->max_qp,
+ vframe_qos->avg_qp,
+ vframe_qos->min_qp);
+#endif
+
+ vframe_qos->max_skip = pic->max_skip;
+ vframe_qos->avg_skip = pic->avg_skip;
+ vframe_qos->min_skip = pic->min_skip;
+#ifdef SHOW_QOS_INFO
+ avs2_print(dec, 0, "skip: max:%d, avg:%d, min:%d\n",
+ vframe_qos->max_skip,
+ vframe_qos->avg_skip,
+ vframe_qos->min_skip);
+#endif
+
+ vframe_qos->num++;
+
+}
+
+static void set_vframe(struct AVS2Decoder_s *dec,
+ struct vframe_s *vf, struct avs2_frame_s *pic, u8 dummy)
+{
+ unsigned long flags;
+ int stream_offset;
+ unsigned int frame_size = 0;
+ int pts_discontinue;
+ struct vdec_s *vdec = hw_to_vdec(dec);
+ stream_offset = pic->stream_offset;
+ avs2_print(dec, AVS2_DBG_BUFMGR,
+ "%s index = %d pos = %d\r\n",
+ __func__, pic->index,
+ pic->imgtr_fwRefDistance);
+
+ if (pic->double_write_mode)
+ set_canvas(dec, pic);
+
+ display_frame_count[dec->index]++;
+
+ if (!dummy) {
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (vdec_frame_based(vdec)) {
+ vf->pts = pic->pts;
+ vf->pts_us64 = pic->pts64;
+ } else {
+#endif
+ if ((vdec->vbuf.no_parser == 0) || (vdec->vbuf.use_ptsserv)) {
+ /* if (pts_lookup_offset(PTS_TYPE_VIDEO,
+ stream_offset, &vf->pts, 0) != 0) { */
+ if (pts_lookup_offset_us64
+ (PTS_TYPE_VIDEO, stream_offset,
+ &vf->pts, &frame_size, 0,
+ &vf->pts_us64) != 0) {
+#ifdef DEBUG_PTS
+ dec->pts_missed++;
+#endif
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+ }
+ }
+ }
+#ifdef DEBUG_PTS
+ else
+ dec->pts_hit++;
+#endif
+ if (pts_unstable)
+ dec->pts_mode = PTS_NONE_REF_USE_DURATION;
+
+ fill_frame_info(dec, pic, frame_size, vf->pts);
+
+ if ((dec->pts_mode == PTS_NORMAL) && (vf->pts != 0)
+ && dec->get_frame_dur) {
+ int pts_diff = (int)vf->pts - dec->last_lookup_pts;
+
+ if (pts_diff < 0) {
+ dec->pts_mode_switching_count++;
+ dec->pts_mode_recovery_count = 0;
+
+ if (dec->pts_mode_switching_count >=
+ PTS_MODE_SWITCHING_THRESHOLD) {
+ dec->pts_mode =
+ PTS_NONE_REF_USE_DURATION;
+ pr_info
+ ("HEVC: switch to n_d mode.\n");
+ }
+
+ } else {
+ int p = PTS_MODE_SWITCHING_RECOVERY_THREASHOLD;
+ dec->pts_mode_recovery_count++;
+ if (dec->pts_mode_recovery_count > p) {
+ dec->pts_mode_switching_count = 0;
+ dec->pts_mode_recovery_count = 0;
+ }
+ }
+ }
+
+ pts_discontinue =
+ (abs(dec->last_pts - vf->pts) >=
+ tsync_vpts_discontinuity_margin());
+
+ if (vf->pts != 0)
+ dec->last_lookup_pts = vf->pts;
+#if 1
+ if ((dec->pts_mode == PTS_NONE_REF_USE_DURATION)
+ && ((pic->slice_type != I_IMG) || (!pts_discontinue &&
+ !first_pts_checkin_complete(PTS_TYPE_AUDIO))))
+ vf->pts = dec->last_pts + DUR2PTS(dec->frame_dur);
+#endif
+ dec->last_pts = vf->pts;
+
+ if (vf->pts_us64 != 0)
+ dec->last_lookup_pts_us64 = vf->pts_us64;
+
+#if 1
+ if ((dec->pts_mode == PTS_NONE_REF_USE_DURATION)
+ && ((pic->slice_type != I_IMG) || (!pts_discontinue &&
+ !first_pts_checkin_complete(PTS_TYPE_AUDIO)))) {
+ vf->pts_us64 =
+ dec->last_pts_us64 +
+ (DUR2PTS(dec->frame_dur) * 100 / 9);
+ }
+#endif
+ dec->last_pts_us64 = vf->pts_us64;
+ avs2_print(dec, AVS2_DBG_OUT_PTS,
+ "avs2 dec out pts: vf->pts=%d, vf->pts_us64 = %lld\n",
+ vf->pts, vf->pts_us64);
+ }
+
+ vf->index = 0xff00 | pic->index;
+
+ if (pic->double_write_mode & 0x10) {
+ /* double write only */
+ vf->compBodyAddr = 0;
+ vf->compHeadAddr = 0;
+ } else {
+#ifdef AVS2_10B_MMU
+ vf->compBodyAddr = 0;
+ vf->compHeadAddr = pic->header_adr;
+#else
+ vf->compBodyAddr = pic->mc_y_adr; /*body adr*/
+ vf->compHeadAddr = pic->mc_y_adr +
+ pic->comp_body_size;
+ /*head adr*/
+#endif
+ }
+ if (pic->double_write_mode) {
+ vf->type = VIDTYPE_PROGRESSIVE |
+ VIDTYPE_VIU_FIELD;
+ vf->type |= VIDTYPE_VIU_NV21;
+ if (pic->double_write_mode == 3) {
+ vf->type |= VIDTYPE_COMPRESS;
+#ifdef AVS2_10B_MMU
+ vf->type |= VIDTYPE_SCATTER;
+#endif
+ }
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (dec->m_ins_flag) {
+ vf->canvas0Addr = vf->canvas1Addr = -1;
+ vf->plane_num = 2;
+ vf->canvas0_config[0] =
+ pic->canvas_config[0];
+ vf->canvas0_config[1] =
+ pic->canvas_config[1];
+
+ vf->canvas1_config[0] =
+ pic->canvas_config[0];
+ vf->canvas1_config[1] =
+ pic->canvas_config[1];
+
+ } else
+#endif
+ vf->canvas0Addr = vf->canvas1Addr =
+ spec2canvas(pic);
+ } else {
+ vf->canvas0Addr = vf->canvas1Addr = 0;
+ vf->type = VIDTYPE_COMPRESS | VIDTYPE_VIU_FIELD;
+#ifdef AVS2_10B_MMU
+ vf->type |= VIDTYPE_SCATTER;
+#endif
+ }
+
+ switch (pic->bit_depth) {
+ case AVS2_BITS_8:
+ vf->bitdepth = BITDEPTH_Y8 |
+ BITDEPTH_U8 | BITDEPTH_V8;
+ break;
+ case AVS2_BITS_10:
+ case AVS2_BITS_12:
+ vf->bitdepth = BITDEPTH_Y10 |
+ BITDEPTH_U10 | BITDEPTH_V10;
+ break;
+ default:
+ vf->bitdepth = BITDEPTH_Y10 |
+ BITDEPTH_U10 | BITDEPTH_V10;
+ break;
+ }
+ if ((vf->type & VIDTYPE_COMPRESS) == 0)
+ vf->bitdepth =
+ BITDEPTH_Y8 | BITDEPTH_U8 | BITDEPTH_V8;
+ if (pic->bit_depth == AVS2_BITS_8)
+ vf->bitdepth |= BITDEPTH_SAVING_MODE;
+
+ set_frame_info(dec, vf);
+ /* if((vf->width!=pic->width)|
+ (vf->height!=pic->height)) */
+ /* pr_info("aaa: %d/%d, %d/%d\n",
+ vf->width,vf->height, pic->width,
+ pic->height); */
+ vf->width = pic->pic_w /
+ get_double_write_ratio(dec,
+ pic->double_write_mode);
+ vf->height = pic->pic_h /
+ get_double_write_ratio(dec,
+ pic->double_write_mode);
+ if (force_w_h != 0) {
+ vf->width = (force_w_h >> 16) & 0xffff;
+ vf->height = force_w_h & 0xffff;
+ }
+ vf->compWidth = pic->pic_w;
+ vf->compHeight = pic->pic_h;
+ if (force_fps & 0x100) {
+ u32 rate = force_fps & 0xff;
+ if (rate)
+ vf->duration = 96000/rate;
+ else
+ vf->duration = 0;
+ }
+#ifdef AVS2_10B_MMU
+ if (vf->type & VIDTYPE_SCATTER) {
+ vf->mem_handle = decoder_mmu_box_get_mem_handle(
+ dec->mmu_box,
+ pic->index);
+ vf->mem_head_handle = decoder_bmmu_box_get_mem_handle(
+ dec->bmmu_box,
+ HEADER_BUFFER_IDX(pic->index));
+ } else {
+ vf->mem_handle = decoder_bmmu_box_get_mem_handle(
+ dec->bmmu_box,
+ VF_BUFFER_IDX(pic->index));
+ vf->mem_head_handle = decoder_bmmu_box_get_mem_handle(
+ dec->bmmu_box,
+ HEADER_BUFFER_IDX(pic->index));
+ }
+#else
+ vf->mem_handle = decoder_bmmu_box_get_mem_handle(
+ dec->bmmu_box,
+ VF_BUFFER_IDX(pic->index));
+#endif
+ if (!vdec->vbuf.use_ptsserv && vdec_stream_based(vdec)) {
+ vf->pts_us64 = stream_offset;
+ vf->pts = 0;
+ }
+ if (!dummy) {
+ lock_buffer(dec, flags);
+ pic->vf_ref = 1;
+ unlock_buffer(dec, flags);
+ }
+ 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");
+ 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",
+ 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 = get_double_write_mode(dec);
+ 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,
+ "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) {
+ 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++) {
+ if (dec->avs2_dec.fref[ii]->
+ bg_flag == 0 &&
+ dec->avs2_dec.fref[ii]->
+ is_output == -1 &&
+ dec->avs2_dec.fref[ii]->
+ mmu_alloc_flag &&
+ dec->avs2_dec.fref[ii]->
+ vf_ref == 0) {
+ struct avs2_frame_s *pic =
+ dec->avs2_dec.fref[ii];
+ if (dec->avs2_dec.fref[ii]->
+ refered_by_others == 0) {
+#ifdef AVS2_10B_MMU
+ dec->avs2_dec.fref[ii]->
+ mmu_alloc_flag = 0;
+ /*release_buffer_4k(
+ dec->avs2_dec.fref[ii]->index);*/
+ decoder_mmu_box_free_idx(dec->mmu_box,
+ dec->avs2_dec.fref[ii]->index);
+#ifdef DYNAMIC_ALLOC_HEAD
+ decoder_bmmu_box_free_idx(
+ dec->bmmu_box,
+ HEADER_BUFFER_IDX(pic->index));
+ pic->header_adr = 0;
+#endif
+#endif
+#ifndef MV_USE_FIXED_BUF
+ decoder_bmmu_box_free_idx(
+ dec->bmmu_box,
+ MV_BUFFER_IDX(pic->index));
+ pic->mpred_mv_wr_start_addr = 0;
+#endif
+ }
+ decoder_bmmu_box_free_idx(
+ dec->bmmu_box,
+ VF_BUFFER_IDX(pic->index));
+ dec->cma_alloc_addr = 0;
+ }
+ }
+ }
+ }
+
+ if ((dec_status == AVS2_HEAD_PIC_I_READY)
+ || (dec_status == AVS2_HEAD_PIC_PB_READY)) {
+ PRINT_LINE();
+
+ if (debug & AVS2_DBG_SEND_PARAM_WITH_REG) {
+ get_rpm_param(
+ &dec->avs2_dec.param);
+ } else {
+
+ for (i = 0; i < (RPM_END - RPM_BEGIN); i += 4) {
+ int ii;
+ for (ii = 0; ii < 4; ii++)
+ dec->avs2_dec.param.l.data[i + ii] =
+ dec->rpm_ptr[i + 3 - ii];
+ }
+ }
+#ifdef SANITY_CHECK
+ if (dec->avs2_dec.param.p.num_of_ref_cur >
+ dec->avs2_dec.ref_maxbuffer) {
+ pr_info("Warning: Wrong num_of_ref_cur %d, force to %d\n",
+ dec->avs2_dec.param.p.num_of_ref_cur,
+ dec->avs2_dec.ref_maxbuffer);
+ dec->avs2_dec.param.p.num_of_ref_cur =
+ dec->avs2_dec.ref_maxbuffer;
+ }
+#endif
+ PRINT_LINE();
+
+ debug_buffer_mgr_more(dec);
+ get_frame_rate(&dec->avs2_dec.param, dec);
+
+#if 0 // 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, 0,
+ "video_signal_type present:\n");
+ avs2_print(dec, 0,
+ " %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, 0,
+ "color_description present:\n");
+ avs2_print(dec, 0,
+ "color_primarie = %d\n",
+ v & 0xff);
+ avs2_print(dec, 0,
+ "transfer_characteristic = %d\n",
+ (c >> 8) & 0xff);
+ avs2_print(dec, 0,
+ " matrix_coefficient = %d\n",
+ c & 0xff);
+
+ transfer = (c >> 8) & 0xFF;
+ if (transfer >= 15)
+ avs2_print(dec, 0,
+ "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, 0,
+ "unsupport matrix_coefficient\n");
+ else if (maxtrix == 9)
+ maxtrix = 10;
+ else if (maxtrix == 8)
+ maxtrix = 9;
+
+ convert_c = (transfer << 8) | (maxtrix);
+
+ avs2_print(dec, 0,
+ " 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++;
+
+ PRINT_LINE();
+#ifdef I_ONLY_SUPPORT
+ if ((start_code == PB_PICTURE_START_CODE) &&
+ (dec->i_only & 0x2))
+ ret = -2;
+#endif
+#ifdef AVS2_10B_MMU
+ if (ret >= 0) {
+ ret = avs2_alloc_mmu(dec,
+ dec->avs2_dec.hc.cur_pic->index,
+ dec->avs2_dec.img.width,
+ dec->avs2_dec.img.height,
+ dec->avs2_dec.input.sample_bit_depth,
+ dec->frame_mmu_map_addr);
+ if (ret >= 0) {
+ dec->cur_fb_idx_mmu =
+ dec->avs2_dec.hc.cur_pic->index;
+ dec->avs2_dec.hc.cur_pic->mmu_alloc_flag = 1;
+ } else
+ pr_err("can't alloc need mmu1,idx %d ret =%d\n",
+ dec->avs2_dec.hc.cur_pic->index,
+ ret);
+ }
+#endif
+
+#ifndef MV_USE_FIXED_BUF
+ if (ret >= 0 &&
+ dec->avs2_dec.hc.cur_pic->
+ mpred_mv_wr_start_addr == 0) {
+ unsigned long buf_addr;
+ unsigned mv_buf_size = get_mv_buf_size(
+ dec,
+ dec->avs2_dec.hc.cur_pic->pic_w,
+ dec->avs2_dec.hc.cur_pic->pic_h);
+ int i = dec->avs2_dec.hc.cur_pic->index;
+ /*if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1)
+ mv_buf_size = 0x120000 * 4;*/
+ if (decoder_bmmu_box_alloc_buf_phy
+ (dec->bmmu_box,
+ MV_BUFFER_IDX(i),
+ mv_buf_size,
+ DRIVER_NAME,
+ &buf_addr) < 0)
+ ret = -1;
+ else
+ dec->avs2_dec.hc.cur_pic->
+ mpred_mv_wr_start_addr
+ = buf_addr;
+ }
+#endif
+ if (ret < 0) {
+ avs2_print(dec, AVS2_DBG_BUFMGR,
+ "avs2_bufmgr_process=> %d, AVS2_10B_DISCARD_NAL\r\n",
+ ret);
+ WRITE_VREG(HEVC_DEC_STATUS_REG, AVS2_10B_DISCARD_NAL);
+ #ifdef AVS2_10B_MMU
+ avs2_recycle_mmu_buf(dec);
+ #endif
+ if (dec->m_ins_flag) {
+ dec->dec_result = DEC_RESULT_DONE;
+ amhevc_stop();
+ vdec_schedule_work(&dec->work);
+ }
+
+ goto irq_handled_exit;
+ } else {
+ PRINT_LINE();
+ dec->avs2_dec.hc.cur_pic->stream_offset =
+ READ_VREG(HEVC_SHIFT_BYTE_COUNT);
+ /*
+ struct PIC_BUFFER_CONFIG_s *cur_pic
+ = &cm->cur_frame->buf;
+ cur_pic->decode_idx = dec->frame_count;
+ */
+ if (!dec->m_ins_flag) {
+ dec->frame_count++;
+ decode_frame_count[dec->index]
+ = dec->frame_count;
+ }
+ /*MULTI_INSTANCE_SUPPORT*/
+ if (dec->chunk) {
+ dec->avs2_dec.hc.cur_pic->pts =
+ dec->chunk->pts;
+ dec->avs2_dec.hc.cur_pic->pts64 =
+ dec->chunk->pts64;
+ }
+ /**/
+ dec->avs2_dec.hc.cur_pic->bit_depth
+ = dec->avs2_dec.input.sample_bit_depth;
+ dec->avs2_dec.hc.cur_pic->double_write_mode
+ = get_double_write_mode(dec);
+decode_slice:
+ PRINT_LINE();
+
+ config_mc_buffer(dec);
+ config_mcrcc_axi_hw(dec);
+ config_mpred_hw(dec);
+ config_dblk_hw(dec);
+ config_sao_hw(dec);
+ config_alf_hw(dec);
+ config_other_hw(dec);
+
+ avs2_print(dec, AVS2_DBG_BUFMGR_MORE,
+ "=>fref0 imgtr_fwRefDistance %d, fref1 imgtr_fwRefDistance %d, dis2/dis3/dis4 %d %d %d img->tr %d\n",
+ dec->avs2_dec.fref[0]->imgtr_fwRefDistance,
+ dec->avs2_dec.fref[1]->imgtr_fwRefDistance,
+ dec->avs2_dec.fref[2]->imgtr_fwRefDistance,
+ dec->avs2_dec.fref[3]->imgtr_fwRefDistance,
+ dec->avs2_dec.fref[4]->imgtr_fwRefDistance,
+ dec->avs2_dec.img.tr);
+
+ if ((debug_again & 0x2) &&
+ dec->process_state ==
+ PROC_STATE_INIT) {
+ dec->process_state = PROC_STATE_DECODING;
+ dec_again_process(dec);
+ goto irq_handled_exit;
+ }
+
+ dec->process_state = PROC_STATE_DECODING;
+
+ WRITE_VREG(HEVC_DEC_STATUS_REG, AVS2_ACTION_DONE);
+
+ }
+
+ if (dec->m_ins_flag)
+ start_process_time(dec);
+ }
+irq_handled_exit:
+ PRINT_LINE();
+ dec->process_busy = 0;
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t vavs2_isr(int irq, void *data)
+{
+ int i;
+ unsigned int dec_status;
+ struct AVS2Decoder_s *dec = (struct AVS2Decoder_s *)data;
+ uint debug_tag;
+
+ WRITE_VREG(HEVC_ASSIST_MBOX0_CLR_REG, 1);
+
+ dec_status = READ_VREG(HEVC_DEC_STATUS_REG);
+
+ if (!dec)
+ return IRQ_HANDLED;
+ if (dec->init_flag == 0)
+ return IRQ_HANDLED;
+ if (dec->process_busy)/*on process.*/
+ return IRQ_HANDLED;
+ dec->dec_status = dec_status;
+ dec->process_busy = 1;
+ if (debug & AVS2_DBG_IRQ_EVENT)
+ avs2_print(dec, 0,
+ "avs2 isr dec status = 0x%x, lcu 0x%x shiftbyte 0x%x (%x %x lev %x, wr %x, rd %x)\n",
+ dec_status, READ_VREG(HEVC_PARSER_LCU_START),
+ READ_VREG(HEVC_SHIFT_BYTE_COUNT),
+ READ_VREG(HEVC_STREAM_START_ADDR),
+ READ_VREG(HEVC_STREAM_END_ADDR),
+ READ_VREG(HEVC_STREAM_LEVEL),
+ READ_VREG(HEVC_STREAM_WR_PTR),
+ READ_VREG(HEVC_STREAM_RD_PTR)
+ );
+
+ debug_tag = READ_HREG(DEBUG_REG1);
+ if (debug_tag & 0x10000) {
+ dma_sync_single_for_cpu(
+ amports_get_dma_device(),
+ dec->lmem_phy_addr,
+ LMEM_BUF_SIZE,
+ DMA_FROM_DEVICE);
+
+ pr_info("LMEM<tag %x>:\n", READ_HREG(DEBUG_REG1));
+ for (i = 0; i < 0x400; i += 4) {
+ int ii;
+ if ((i & 0xf) == 0)
+ pr_info("%03x: ", i);
+ for (ii = 0; ii < 4; ii++) {
+ pr_info("%04x ",
+ dec->lmem_ptr[i + 3 - ii]);
+ }
+ if (((i + ii) & 0xf) == 0)
+ pr_info("\n");
+ }
+
+ if (((udebug_pause_pos & 0xffff)
+ == (debug_tag & 0xffff)) &&
+ (udebug_pause_decode_idx == 0 ||
+ udebug_pause_decode_idx == dec->decode_idx) &&
+ (udebug_pause_val == 0 ||
+ udebug_pause_val == READ_HREG(DEBUG_REG2))) {
+ udebug_pause_pos &= 0xffff;
+ dec->ucode_pause_pos = udebug_pause_pos;
+ } else if (debug_tag & 0x20000)
+ dec->ucode_pause_pos = 0xffffffff;
+ if (dec->ucode_pause_pos)
+ reset_process_time(dec);
+ else
+ WRITE_HREG(DEBUG_REG1, 0);
+ } else if (debug_tag != 0) {
+ pr_info(
+ "dbg%x: %x lcu %x\n", READ_HREG(DEBUG_REG1),
+ READ_HREG(DEBUG_REG2),
+ READ_VREG(HEVC_PARSER_LCU_START));
+ if (((udebug_pause_pos & 0xffff)
+ == (debug_tag & 0xffff)) &&
+ (udebug_pause_decode_idx == 0 ||
+ udebug_pause_decode_idx == dec->decode_idx) &&
+ (udebug_pause_val == 0 ||
+ udebug_pause_val == READ_HREG(DEBUG_REG2))) {
+ udebug_pause_pos &= 0xffff;
+ dec->ucode_pause_pos = udebug_pause_pos;
+ }
+ if (dec->ucode_pause_pos)
+ reset_process_time(dec);
+ else
+ WRITE_HREG(DEBUG_REG1, 0);
+ dec->process_busy = 0;
+ return IRQ_HANDLED;
+ }
+
+ if (!dec->m_ins_flag) {
+ if (dec->error_flag == 1) {
+ dec->error_flag = 2;
+ dec->process_busy = 0;
+ return IRQ_HANDLED;
+ } else if (dec->error_flag == 3) {
+ dec->process_busy = 0;
+ return IRQ_HANDLED;
+ }
+
+ if ((dec->pic_list_init_flag) &&
+ get_free_buf_count(dec) <= 0) {
+ /*
+ if (dec->wait_buf == 0)
+ pr_info("set wait_buf to 1\r\n");
+ */
+ dec->wait_buf = 1;
+ dec->process_busy = 0;
+ if (debug & AVS2_DBG_IRQ_EVENT)
+ avs2_print(dec, 0, "wait_buf\n");
+ return IRQ_HANDLED;
+ } else if (force_disp_pic_index) {
+ dec->process_busy = 0;
+ return IRQ_HANDLED;
+ }
+ }
+ return IRQ_WAKE_THREAD;
+}
+
+static void vavs2_put_timer_func(unsigned long arg)
+{
+ struct AVS2Decoder_s *dec = (struct AVS2Decoder_s *)arg;
+ struct timer_list *timer = &dec->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);
+
+}
+
+#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;
+ init_timer(&dec->timer);
+
+ 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.data = (ulong) dec;
+ dec->timer.function = vavs2_put_timer_func;
+ dec->timer.expires = jiffies + PUT_INTERVAL;
+
+ /*add_timer(&dec->timer);
+
+ dec->stat |= STAT_TIMER_ARM;
+ 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.data = (ulong)dec;
+ dec->timer.function = vavs2_put_timer_func;
+ dec->timer.expires = jiffies + PUT_INTERVAL;
+
+
+ add_timer(&dec->timer);
+
+ dec->stat |= STAT_TIMER_ARM;
+
+ /* 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;
+
+#ifdef AVS2_10B_MMU
+ dec->need_cache_size = buf_size * SZ_1M;
+ dec->sc_start_time = get_jiffies_64();
+ dec->mmu_box = decoder_mmu_box_alloc_box(DRIVER_NAME,
+ dec->index, FRAME_BUFFERS,
+ dec->need_cache_size,
+ tvp_flag
+ );
+ if (!dec->mmu_box) {
+ pr_err("avs2 alloc mmu box failed!!\n");
+ return -1;
+ }
+#endif
+ dec->bmmu_box = decoder_bmmu_box_alloc_box(
+ DRIVER_NAME,
+ dec->index,
+ MAX_BMMU_BUFFER_NUM,
+ 4 + PAGE_SHIFT,
+ CODEC_MM_FLAGS_CMA_CLEAR |
+ CODEC_MM_FLAGS_FOR_VDECODER |
+ tvp_flag);
+ if (!dec->bmmu_box) {
+ pr_err("avs2 alloc bmmu box failed!!\n");
+ return -1;
+ }
+ return 0;
+}
+
+static 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__);
+ mutex_lock(&vavs2_mutex);
+
+ memcpy(&BUF[0], &dec->m_BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM);
+ memset(dec, 0, sizeof(struct AVS2Decoder_s));
+ memcpy(&dec->m_BUF[0], &BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM);
+
+ dec->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);
+
+ 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;
+
+ 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;
+}
+
+/****************************************/
+#ifdef CONFIG_PM
+static int avs2_suspend(struct device *dev)
+{
+ amhevc_suspend(to_platform_device(dev), dev->power.power_state);
+ return 0;
+}
+
+static int avs2_resume(struct device *dev)
+{
+ amhevc_resume(to_platform_device(dev));
+ return 0;
+}
+
+static const struct dev_pm_ops avs2_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(avs2_suspend, avs2_resume)
+};
+#endif
+
+static struct platform_driver amvdec_avs2_driver = {
+ .probe = amvdec_avs2_probe,
+ .remove = amvdec_avs2_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &avs2_pm_ops,
+#endif
+ }
+};
+
+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
+ 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%lx 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;
+ 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 (pdata == NULL) {
+ pr_info("\nammvdec_avs2 memory resource undefined.\n");
+ return -EFAULT;
+ }
+ /*dec = (struct AVS2Decoder_s *)devm_kzalloc(&pdev->dev,
+ sizeof(struct AVS2Decoder_s), GFP_KERNEL);*/
+ memset(&vf_dp, 0, sizeof(struct vframe_master_display_colour_s));
+ dec = vmalloc(sizeof(struct AVS2Decoder_s));
+ memset(dec, 0, sizeof(struct AVS2Decoder_s));
+ if (dec == NULL) {
+ pr_info("\nammvdec_avs2 device data allocation failed\n");
+ return -ENOMEM;
+ }
+ if (pdata->parallel_dec == 1) {
+ int i;
+ for (i = 0; i < AVS2_MAX_BUFFER_NUM; i++) {
+ dec->avs2_dec.frm_pool[i].y_canvas_index = -1;
+ dec->avs2_dec.frm_pool[i].uv_canvas_index = -1;
+ }
+ }
+ pdata->private = dec;
+ pdata->dec_status = vavs2_dec_status;
+#ifdef I_ONLY_SUPPORT
+ pdata->set_trickmode = vavs2_set_trickmode;
+#endif
+ pdata->run_ready = run_ready;
+ pdata->run = run;
+ pdata->reset = reset;
+ pdata->irq_handler = avs2_irq_cb;
+ pdata->threaded_irq_handler = avs2_threaded_irq_cb;
+ pdata->dump_state = avs2_dump_state;
+
+ memcpy(&BUF[0], &dec->m_BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM);
+ memset(dec, 0, sizeof(struct AVS2Decoder_s));
+ memcpy(&dec->m_BUF[0], &BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM);
+
+ dec->index = pdev->id;
+ dec->m_ins_flag = 1;
+
+ 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 1
+ if ((debug & IGNORE_PARAM_FROM_CONFIG) == 0 &&
+ pdata->config_len) {
+ /*use ptr config for doubel_write_mode, etc*/
+ avs2_print(dec, 0, "pdata->config=%s\n", pdata->config);
+ if (get_config_int(pdata->config, "avs2_double_write_mode",
+ &config_val) == 0)
+ dec->double_write_mode = config_val;
+ else
+ dec->double_write_mode = double_write_mode;
+
+ if (get_config_int(pdata->config, "parm_v4l_buffer_margin",
+ &config_val) == 0)
+ dec->dynamic_buf_margin = config_val;
+ else
+ dec->dynamic_buf_margin = 0;
+
+ if (get_config_int(pdata->config, "sidebind_type",
+ &config_val) == 0)
+ dec->sidebind_type = config_val;
+
+ if (get_config_int(pdata->config, "sidebind_channel_id",
+ &config_val) == 0)
+ dec->sidebind_channel_id = config_val;
+
+ if (get_config_int(pdata->config, "HDRStaticInfo",
+ &vf_dp.present_flag) == 0
+ && vf_dp.present_flag == 1) {
+ get_config_int(pdata->config, "mG.x",
+ &vf_dp.primaries[0][0]);
+ get_config_int(pdata->config, "mG.y",
+ &vf_dp.primaries[0][1]);
+ get_config_int(pdata->config, "mB.x",
+ &vf_dp.primaries[1][0]);
+ get_config_int(pdata->config, "mB.y",
+ &vf_dp.primaries[1][1]);
+ get_config_int(pdata->config, "mR.x",
+ &vf_dp.primaries[2][0]);
+ get_config_int(pdata->config, "mR.y",
+ &vf_dp.primaries[2][1]);
+ get_config_int(pdata->config, "mW.x",
+ &vf_dp.white_point[0]);
+ get_config_int(pdata->config, "mW.y",
+ &vf_dp.white_point[1]);
+ get_config_int(pdata->config, "mMaxDL",
+ &vf_dp.luminance[0]);
+ get_config_int(pdata->config, "mMinDL",
+ &vf_dp.luminance[1]);
+ vf_dp.content_light_level.present_flag = 1;
+ get_config_int(pdata->config, "mMaxCLL",
+ &content_light_level.max_content);
+ get_config_int(pdata->config, "mMaxFALL",
+ &content_light_level.max_pic_average);
+ vf_dp.content_light_level = content_light_level;
+ dec->video_signal_type = (1 << 29)
+ | (5 << 26) /* unspecified */
+ | (0 << 25) /* limit */
+ | (1 << 24) /* color available */
+ | (9 << 16) /* 2020 */
+ | (16 << 8) /* 2084 */
+ | (9 << 0); /* 2020 */
+ }
+ dec->vf_dp = vf_dp;
+ } else
+#endif
+ {
+ /*dec->vavs2_amstream_dec_info.width = 0;
+ dec->vavs2_amstream_dec_info.height = 0;
+ dec->vavs2_amstream_dec_info.rate = 30;*/
+ dec->double_write_mode = double_write_mode;
+ dec->dynamic_buf_margin = dynamic_buf_num_margin;
+ }
+ video_signal_type = dec->video_signal_type;
+
+#if 0
+ dec->buf_start = pdata->mem_start;
+ dec->buf_size = pdata->mem_end - pdata->mem_start + 1;
+#else
+ if (amvdec_avs2_mmu_init(dec) < 0) {
+ pr_err("avs2 alloc bmmu box failed!!\n");
+ /* devm_kfree(&pdev->dev, (void *)dec); */
+ vfree((void *)dec);
+ return -1;
+ }
+ dec->cma_alloc_count = PAGE_ALIGN(work_buf_size) / PAGE_SIZE;
+ ret = decoder_bmmu_box_alloc_buf_phy(dec->bmmu_box, WORK_SPACE_BUF_ID,
+ dec->cma_alloc_count * PAGE_SIZE, DRIVER_NAME,
+ &dec->cma_alloc_addr);
+ if (ret < 0) {
+ uninit_mmu_buffers(dec);
+ /* devm_kfree(&pdev->dev, (void *)dec); */
+ vfree((void *)dec);
+ return ret;
+ }
+ dec->buf_start = dec->cma_alloc_addr;
+ dec->buf_size = work_buf_size;
+#endif
+ dec->init_flag = 0;
+ dec->first_sc_checked = 0;
+ dec->fatal_error = 0;
+ dec->show_frame_num = 0;
+
+ if (debug) {
+ pr_info("===AVS2 decoder mem resource 0x%lx size 0x%x\n",
+ dec->buf_start,
+ dec->buf_size);
+ }
+
+ if (pdata->sys_info) {
+ dec->vavs2_amstream_dec_info = *pdata->sys_info;
+ dec->frame_width = dec->vavs2_amstream_dec_info.width;
+ dec->frame_height = dec->vavs2_amstream_dec_info.height;
+ } else {
+ dec->vavs2_amstream_dec_info.width = 0;
+ dec->vavs2_amstream_dec_info.height = 0;
+ dec->vavs2_amstream_dec_info.rate = 30;
+ }
+
+ dec->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;
+ 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);
+ }
+ }
+
+
+#ifdef DEBUG_PTS
+ pr_info("pts missed %ld, pts hit %ld, duration %d\n",
+ dec->pts_missed, dec->pts_hit, dec->frame_dur);
+#endif
+ /* 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,
+ .driver = {
+ .name = MULTI_DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &avs2_pm_ops,
+#endif
+ }
+};
+#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 (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];
+
+ 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_SM1) {
+ amvdec_avs2_profile.profile =
+ "8k, 10bit, dwrite, compressed";
+ } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) {
+ if (vdec_is_support_4k())
+ amvdec_avs2_profile.profile =
+ "4k, 10bit, dwrite, compressed";
+ else
+ amvdec_avs2_profile.profile =
+ "10bit, dwrite, compressed";
+ } else {
+ amvdec_avs2_profile.name = "avs2_unsupport";
+ }
+
+ 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);
+
+ 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..6b51f61
--- /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 MV_USE_FIXED_BUF
+
+void adapt_coef_probs(int pic_count, int prev_kf, int cur_kf, int pre_fc,
+unsigned int *prev_prob, unsigned int *cur_prob, unsigned int *count);
+#endif
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..dcb15e1
--- /dev/null
+++ b/drivers/frame_provider/decoder/avs_multi/avs_multi.c
@@ -0,0 +1,5016 @@
+/*
+ * drivers/amlogic/amports/vavs.c
+ *
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/semaphore.h>
+#include <linux/timer.h>
+#include <linux/kfifo.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/amlogic/media/utils/amstream.h>
+#include <linux/amlogic/media/frame_sync/ptsserv.h>
+#include <linux/amlogic/media/canvas/canvas.h>
+#include <linux/amlogic/media/vfm/vframe_provider.h>
+#include <linux/amlogic/media/vfm/vframe_receiver.h>
+#include <linux/amlogic/media/vfm/vframe.h>
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "../../../stream_input/amports/streambuf_reg.h"
+#include "../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>
+
+#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(unsigned long arg);
+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_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
+ canvas_config(canvas_base + canvas_num * i + 0,
+ buf_start,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+ canvas_config(canvas_base + canvas_num * i + 1,
+ buf_start +
+ decbuf_y_size, canvas_width,
+ canvas_height / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+#else
+ canvas_config(canvas_num * i + 0,
+ buf_start,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+ canvas_config(canvas_num * i + 1,
+ buf_start +
+ decbuf_y_size, canvas_width / 2,
+ canvas_height / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+ canvas_config(canvas_num * i + 2,
+ buf_start +
+ decbuf_y_size + decbuf_uv_size,
+ canvas_width / 2, canvas_height / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+#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
+
+#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++) {
+ canvas_config_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);
+
+ canvas_config_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);
+ }
+ } 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
+
+#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(unsigned long arg)
+{
+ struct vdec_avs_hw_s *hw = (struct vdec_avs_hw_s *)arg;
+ 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) {
+ 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;
+
+ 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;
+}
+
+/****************************************/
+#ifdef DEBUG_WITH_SINGLE_MODE
+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(unsigned long arg)
+{
+ struct vdec_avs_hw_s *hw = (struct vdec_avs_hw_s *)arg;
+ 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++) {
+ canvas_config_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);
+
+ canvas_config_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);
+ }
+ }
+}
+
+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
+ 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;
+ }
+#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);
+ 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..03a1dba
--- /dev/null
+++ b/drivers/frame_provider/decoder/h264/vh264.c
@@ -0,0 +1,4543 @@
+/*
+ * 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 <linux/amlogic/media/ge2d/ge2d.h>
+#include "../utils/decoder_mmu_box.h"
+#include "../utils/decoder_bmmu_box.h"
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include <linux/amlogic/media/codec_mm/configs.h>
+#include "../utils/firmware.h"
+#include <linux/amlogic/tee.h>
+#include "../../../common/chips/decoder_cpu_ver_info.h"
+#include <linux/uaccess.h>
+
+
+
+#define DRIVER_NAME "amvdec_h264"
+#define MODULE_NAME "amvdec_h264"
+#define MEM_NAME "codec_264"
+#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(unsigned long arg);
+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;
+
+/* if not define, must clear AV_SCRATCH_J in isr when
+ * ITU_T35 code enabled in ucode, otherwise may fatal
+ * error repeatly.
+ */
+//#define ENABLE_SEI_ITU_T35
+
+
+
+static unsigned int enable_switch_fense = 1;
+#define EN_SWITCH_FENCE() (enable_switch_fense && !is_4k)
+static struct vframe_qos_s s_vframe_qos;
+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;
+ canvas_config_ex(spec->y_canvas_index,
+ spec->y_addr,
+ width, height,
+ CANVAS_ADDR_NOWRAP, canvas_mode, endian);
+
+ canvas_config_ex(spec->u_canvas_index,
+ spec->u_addr,
+ width, height / 2,
+ CANVAS_ADDR_NOWRAP, canvas_mode, endian);
+
+}
+
+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;
+ canvas_config_ex(128 + i * 2,
+ buffer_spec[i].y_addr,
+ mb_width << 4, mb_height << 4,
+ CANVAS_ADDR_NOWRAP,
+ canvas_mode, endian);
+ canvas_config_ex(128 + i * 2 + 1,
+ buffer_spec[i].u_addr,
+ mb_width << 4, mb_height << 3,
+ CANVAS_ADDR_NOWRAP,
+ canvas_mode, endian);
+ 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(unsigned long arg)
+{
+ struct timer_list *timer = (struct timer_list *)arg;
+ 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"); */
+ init_timer(&recycle_timer);
+
+ 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.data = (ulong) &recycle_timer;
+ recycle_timer.function = vh264_put_timer_func;
+ recycle_timer.expires = jiffies + PUT_INTERVAL;
+
+ add_timer(&recycle_timer);
+
+ stat |= STAT_TIMER_ARM;
+
+ 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);
+
+ canvas_config(fense_buffer_spec[i].y_canvas_index,
+ fense_buffer_spec[i].phy_addr,
+ mb_width_num << 4, mb_height_num << 4,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config(fense_buffer_spec[i].u_canvas_index,
+ fense_buffer_spec[i].phy_addr +
+ (mb_total_num << 8),
+ mb_width_num << 4, mb_height_num << 3,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+
+ 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;
+}
+
+/****************************************/
+#ifdef CONFIG_PM
+static int h264_suspend(struct device *dev)
+{
+ amvdec_suspend(to_platform_device(dev), dev->power.power_state);
+ return 0;
+}
+
+static int h264_resume(struct device *dev)
+{
+ amvdec_resume(to_platform_device(dev));
+ return 0;
+}
+
+static const struct dev_pm_ops h264_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(h264_suspend, h264_resume)
+};
+#endif
+
+static struct platform_driver amvdec_h264_driver = {
+ .probe = amvdec_h264_probe,
+ .remove = amvdec_h264_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &h264_pm_ops,
+#endif
+ }
+};
+
+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)) {
+ 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_4k2k.c b/drivers/frame_provider/decoder/h264/vh264_4k2k.c
new file mode 100644
index 0000000..44465ad
--- /dev/null
+++ b/drivers/frame_provider/decoder/h264/vh264_4k2k.c
@@ -0,0 +1,1808 @@
+/*
+ * drivers/amlogic/amports/vh264_4k2k.c
+ *
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/kfifo.h>
+#include <linux/platform_device.h>
+#include <linux/amlogic/media/utils/amstream.h>
+#include <linux/amlogic/media/utils/vformat.h>
+#include <linux/amlogic/media/frame_sync/ptsserv.h>
+#include <linux/amlogic/media/canvas/canvas.h>
+#include <linux/amlogic/media/vfm/vframe.h>
+#include <linux/amlogic/media/vfm/vframe_provider.h>
+#include <linux/amlogic/media/vfm/vframe_receiver.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma-contiguous.h>
+#include <linux/delay.h>
+
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include <linux/amlogic/media/video_sink/video_keeper.h>
+#include "../utils/firmware.h"
+#include <linux/amlogic/tee.h>
+#include "../../../common/chips/decoder_cpu_ver_info.h"
+
+
+
+#define MEM_NAME "codec_264_4k"
+
+/* #include <mach/am_regs.h> */
+#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
+
+#include <linux/amlogic/media/vpu/vpu.h>
+#endif
+
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "../../../stream_input/amports/amports_priv.h"
+#include "../utils/vdec.h"
+#include "../utils/amvdec.h"
+#include "../utils/decoder_mmu_box.h"
+#include "../utils/decoder_bmmu_box.h"
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include <linux/amlogic/media/codec_mm/configs.h>
+
+
+
+#if 0 /* MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6TVD */
+#define DOUBLE_WRITE
+#endif
+
+#define DRIVER_NAME "amvdec_h264_4k2k"
+#define MODULE_NAME "amvdec_h264_4k2k"
+
+#define PUT_INTERVAL (HZ/100)
+#define ERROR_RESET_COUNT 500
+#define DECODE_BUFFER_NUM_MAX 32
+#define DISPLAY_BUFFER_NUM 6
+#define MAX_BMMU_BUFFER_NUM (DECODE_BUFFER_NUM_MAX + DISPLAY_BUFFER_NUM)
+#define VF_BUFFER_IDX(n) (2 + n)
+#define DECODER_WORK_SPACE_SIZE 0x800000
+
+#if 1 /* MESON_CPU_TYPE == MESON_CPU_TYPE_MESONG9TV */
+#define H264_4K2K_SINGLE_CORE 1
+#else
+#define H264_4K2K_SINGLE_CORE IS_MESON_M8M2_CPU
+#endif
+
+#define SLICE_TYPE_I 2
+
+static int vh264_4k2k_vf_states(struct vframe_states *states, void *);
+static struct vframe_s *vh264_4k2k_vf_peek(void *);
+static struct vframe_s *vh264_4k2k_vf_get(void *);
+static void vh264_4k2k_vf_put(struct vframe_s *, void *);
+static int vh264_4k2k_event_cb(int type, void *data, void *private_data);
+
+static void vh264_4k2k_prot_init(void);
+static int vh264_4k2k_local_init(void);
+static void vh264_4k2k_put_timer_func(unsigned long arg);
+
+static const char vh264_4k2k_dec_id[] = "vh264_4k2k-dev";
+static const char vh264_4k2k_dec_id2[] = "vh264_4k2k-vdec2-dev";
+
+#define PROVIDER_NAME "decoder.h264_4k2k"
+
+static const struct vframe_operations_s vh264_4k2k_vf_provider = {
+ .peek = vh264_4k2k_vf_peek,
+ .get = vh264_4k2k_vf_get,
+ .put = vh264_4k2k_vf_put,
+ .event_cb = vh264_4k2k_event_cb,
+ .vf_states = vh264_4k2k_vf_states,
+};
+static void *mm_blk_handle;
+static struct vframe_provider_s vh264_4k2k_vf_prov;
+
+static u32 mb_width_old, mb_height_old;
+static u32 frame_width, frame_height, frame_dur, frame_ar;
+static u32 saved_resolution;
+static struct timer_list recycle_timer;
+static u32 stat;
+static u32 error_watchdog_count;
+static uint error_recovery_mode;
+static u32 sync_outside;
+static u32 vh264_4k2k_rotation;
+static u32 first_i_received;
+static struct vframe_s *p_last_vf;
+static struct work_struct set_clk_work;
+
+#ifdef DEBUG_PTS
+static unsigned long pts_missed, pts_hit;
+#endif
+
+static struct dec_sysinfo vh264_4k2k_amstream_dec_info;
+static dma_addr_t mc_dma_handle;
+static void *mc_cpu_addr;
+
+#define AMVDEC_H264_4K2K_CANVAS_INDEX 0x80
+#define AMVDEC_H264_4K2K_CANVAS_MAX 0xc6
+static DEFINE_SPINLOCK(lock);
+static int fatal_error;
+
+static atomic_t vh264_4k2k_active = ATOMIC_INIT(0);
+
+static DEFINE_MUTEX(vh264_4k2k_mutex);
+
+static void (*probe_callback)(void);
+static void (*remove_callback)(void);
+static struct device *cma_dev;
+
+/* bit[3:0] command : */
+/* 0 - command finished */
+/* (DATA0 - {level_idc_mmco, max_reference_frame_num, width, height} */
+/* 1 - alloc view_0 display_buffer and reference_data_area */
+/* 2 - alloc view_1 display_buffer and reference_data_area */
+#define MAILBOX_COMMAND AV_SCRATCH_0
+#define MAILBOX_DATA_0 AV_SCRATCH_1
+#define MAILBOX_DATA_1 AV_SCRATCH_2
+#define MAILBOX_DATA_2 AV_SCRATCH_3
+#define MAILBOX_DATA_3 AV_SCRATCH_4
+#define MAILBOX_DATA_4 AV_SCRATCH_5
+#define CANVAS_START AV_SCRATCH_6
+#define BUFFER_RECYCLE AV_SCRATCH_7
+#define PICTURE_COUNT AV_SCRATCH_9
+#define DECODE_STATUS AV_SCRATCH_A
+#define SPS_STATUS AV_SCRATCH_B
+#define PPS_STATUS AV_SCRATCH_C
+#define MS_ID AV_SCRATCH_D
+#define WORKSPACE_START AV_SCRATCH_E
+#define DECODED_PIC_NUM AV_SCRATCH_F
+#define DECODE_ERROR_CNT AV_SCRATCH_G
+#define CURRENT_UCODE AV_SCRATCH_H
+/* bit[15:9]-SPS, bit[8:0]-PPS */
+#define CURRENT_SPS_PPS AV_SCRATCH_I
+#define DECODE_SKIP_PICTURE AV_SCRATCH_J
+#define DECODE_MODE AV_SCRATCH_K
+#define RESERVED_REG_L AV_SCRATCH_L
+#define REF_START_VIEW_0 AV_SCRATCH_M
+#define REF_START_VIEW_1 AV_SCRATCH_N
+
+#define VDEC2_MAILBOX_COMMAND VDEC2_AV_SCRATCH_0
+#define VDEC2_MAILBOX_DATA_0 VDEC2_AV_SCRATCH_1
+#define VDEC2_MAILBOX_DATA_1 VDEC2_AV_SCRATCH_2
+#define VDEC2_MAILBOX_DATA_2 VDEC2_AV_SCRATCH_3
+#define VDEC2_MAILBOX_DATA_3 VDEC2_AV_SCRATCH_4
+#define VDEC2_MAILBOX_DATA_4 VDEC2_AV_SCRATCH_5
+#define VDEC2_CANVAS_START VDEC2_AV_SCRATCH_6
+#define VDEC2_BUFFER_RECYCLE VDEC2_AV_SCRATCH_7
+#define VDEC2_PICTURE_COUNT VDEC2_AV_SCRATCH_9
+#define VDEC2_DECODE_STATUS VDEC2_AV_SCRATCH_A
+#define VDEC2_SPS_STATUS VDEC2_AV_SCRATCH_B
+#define VDEC2_PPS_STATUS VDEC2_AV_SCRATCH_C
+#define VDEC2_MS_ID VDEC2_AV_SCRATCH_D
+#define VDEC2_WORKSPACE_START VDEC2_AV_SCRATCH_E
+#define VDEC2_DECODED_PIC_NUM VDEC2_AV_SCRATCH_F
+#define VDEC2_DECODE_ERROR_CNT VDEC2_AV_SCRATCH_G
+#define VDEC2_CURRENT_UCODE VDEC2_AV_SCRATCH_H
+/* bit[15:9]-SPS, bit[8:0]-PPS */
+#define VDEC2_CURRENT_SPS_PPS VDEC2_AV_SCRATCH_I
+#define VDEC2_DECODE_SKIP_PICTURE VDEC2_AV_SCRATCH_J
+#define VDEC2_RESERVED_REG_K VDEC2_AV_SCRATCH_K
+#define VDEC2_RESERVED_REG_L VDEC2_AV_SCRATCH_L
+#define VDEC2_REF_START_VIEW_0 VDEC2_AV_SCRATCH_M
+#define VDEC2_REF_START_VIEW_1 VDEC2_AV_SCRATCH_N
+
+/********************************************
+ * DECODE_STATUS Define
+ *******************************************
+ */
+#define DECODE_IDLE 0
+#define DECODE_START_HEADER 1
+#define DECODE_HEADER 2
+#define DECODE_START_MMCO 3
+#define DECODE_MMCO 4
+#define DECODE_START_SLICE 5
+#define DECODE_SLICE 6
+#define DECODE_WAIT_BUFFER 7
+
+/********************************************
+ * Dual Core Communication
+ ********************************************
+ */
+#define FATAL_ERROR DOS_SCRATCH16
+#define PRE_MASTER_UPDATE_TIMES DOS_SCRATCH20
+/* bit[31] - REQUEST */
+/* bit[30:0] - MASTER_UPDATE_TIMES */
+#define SLAVE_WAIT_DPB_UPDATE DOS_SCRATCH21
+/* [15:8] - current_ref, [7:0] current_dpb (0x80 means no buffer found) */
+#define SLAVE_REF_DPB DOS_SCRATCH22
+#define SAVE_MVC_ENTENSION_0 DOS_SCRATCH23
+#define SAVE_I_POC DOS_SCRATCH24
+/* bit[31:30] - core_status 0-idle, 1-mmco, 2-decoding, 3-finished */
+/* bit[29:0] - core_pic_count */
+#define CORE_STATUS_M DOS_SCRATCH25
+#define CORE_STATUS_S DOS_SCRATCH26
+#define SAVE_ref_status_view_0 DOS_SCRATCH27
+#define SAVE_ref_status_view_1 DOS_SCRATCH28
+#define ALLOC_INFO_0 DOS_SCRATCH29
+#define ALLOC_INFO_1 DOS_SCRATCH30
+
+/********************************************
+ * Mailbox command
+ ********************************************/
+#define CMD_FINISHED 0
+#define CMD_ALLOC_VIEW 1
+#define CMD_FRAME_DISPLAY 3
+#define CMD_DEBUG 10
+
+#define MC_TOTAL_SIZE (28*SZ_1K)
+#define MC_SWAP_SIZE (4*SZ_1K)
+
+static unsigned long work_space_adr, ref_start_addr;
+static unsigned long reserved_buffer;
+
+
+#define video_domain_addr(adr) (adr&0x7fffffff)
+
+
+struct buffer_spec_s {
+ unsigned int y_addr;
+ unsigned int uv_addr;
+#ifdef DOUBLE_WRITE
+ unsigned int y_dw_addr;
+ unsigned int uv_dw_addr;
+#endif
+
+ int y_canvas_index;
+ int uv_canvas_index;
+#ifdef DOUBLE_WRITE
+ int y_dw_canvas_index;
+ int uv_dw_canvas_index;
+#endif
+
+ struct page *alloc_pages;
+ unsigned long phy_addr;
+ int alloc_count;
+};
+
+static struct buffer_spec_s buffer_spec[MAX_BMMU_BUFFER_NUM];
+
+#ifdef DOUBLE_WRITE
+#define spec2canvas(x) \
+ (((x)->uv_dw_canvas_index << 16) | \
+ ((x)->uv_dw_canvas_index << 8) | \
+ ((x)->y_dw_canvas_index << 0))
+#else
+#define spec2canvas(x) \
+ (((x)->uv_canvas_index << 16) | \
+ ((x)->uv_canvas_index << 8) | \
+ ((x)->y_canvas_index << 0))
+#endif
+
+#define VF_POOL_SIZE 32
+
+static DECLARE_KFIFO(newframe_q, struct vframe_s *, VF_POOL_SIZE);
+static DECLARE_KFIFO(display_q, struct vframe_s *, VF_POOL_SIZE);
+static DECLARE_KFIFO(recycle_q, struct vframe_s *, VF_POOL_SIZE);
+
+static s32 vfbuf_use[DECODE_BUFFER_NUM_MAX];
+static struct vframe_s vfpool[VF_POOL_SIZE];
+
+static struct work_struct alloc_work;
+static struct vdec_info *gvs;
+
+static void set_frame_info(struct vframe_s *vf)
+{
+ unsigned int ar;
+
+#ifdef DOUBLE_WRITE
+ vf->width = frame_width / 2;
+ vf->height = frame_height / 2;
+#else
+ vf->width = frame_width;
+ vf->height = frame_height;
+#endif
+ vf->duration = frame_dur;
+ vf->duration_pulldown = 0;
+ vf->flag = 0;
+
+ ar = min_t(u32, frame_ar, DISP_RATIO_ASPECT_RATIO_MAX);
+ vf->ratio_control = (ar << DISP_RATIO_ASPECT_RATIO_BIT);
+ vf->orientation = vh264_4k2k_rotation;
+
+}
+
+static int vh264_4k2k_vf_states(struct vframe_states *states, void *op_arg)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ states->vf_pool_size = VF_POOL_SIZE;
+ states->buf_free_num = kfifo_len(&newframe_q);
+ states->buf_avail_num = kfifo_len(&display_q);
+ states->buf_recycle_num = kfifo_len(&recycle_q);
+
+ spin_unlock_irqrestore(&lock, flags);
+ return 0;
+}
+
+static struct vframe_s *vh264_4k2k_vf_peek(void *op_arg)
+{
+ struct vframe_s *vf;
+
+ if (kfifo_peek(&display_q, &vf))
+ return vf;
+
+ return NULL;
+}
+
+static struct vframe_s *vh264_4k2k_vf_get(void *op_arg)
+{
+ struct vframe_s *vf;
+
+ if (kfifo_get(&display_q, &vf))
+ return vf;
+
+ return NULL;
+}
+
+static void vh264_4k2k_vf_put(struct vframe_s *vf, void *op_arg)
+{
+ kfifo_put(&recycle_q, (const struct vframe_s *)vf);
+}
+
+static int vh264_4k2k_event_cb(int type, void *data, void *private_data)
+{
+ if (type & VFRAME_EVENT_RECEIVER_RESET) {
+ unsigned long flags;
+
+ amvdec_stop();
+
+ if (!H264_4K2K_SINGLE_CORE)
+ amvdec2_stop();
+#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vf_light_unreg_provider(&vh264_4k2k_vf_prov);
+#endif
+ spin_lock_irqsave(&lock, flags);
+ vh264_4k2k_local_init();
+ vh264_4k2k_prot_init();
+ spin_unlock_irqrestore(&lock, flags);
+#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vf_reg_provider(&vh264_4k2k_vf_prov);
+#endif
+ amvdec_start();
+
+ if (!H264_4K2K_SINGLE_CORE)
+ amvdec2_start();
+ }
+
+ return 0;
+}
+
+static int init_canvas(int refbuf_size, long dpb_size, int dpb_number,
+ int mb_width, int mb_height,
+ struct buffer_spec_s *buffer_spec)
+{
+ unsigned long addr;
+ int i, j, ret = -1;
+ int mb_total;
+ int canvas_addr = ANC0_CANVAS_ADDR;
+ int vdec2_canvas_addr = VDEC2_ANC0_CANVAS_ADDR;
+ int index = AMVDEC_H264_4K2K_CANVAS_INDEX;
+
+ mb_total = mb_width * mb_height;
+ mutex_lock(&vh264_4k2k_mutex);
+
+ for (j = 0; j < (dpb_number + 1); j++) {
+ int page_count;
+ if (j == 0) {
+ ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle, 1,
+ refbuf_size, DRIVER_NAME, &ref_start_addr);
+ if (ret < 0) {
+ mutex_unlock(&vh264_4k2k_mutex);
+ return ret;
+ }
+ continue;
+ }
+
+ WRITE_VREG(canvas_addr++, index | ((index + 1) << 8) |
+ ((index + 1) << 16));
+ if (!H264_4K2K_SINGLE_CORE) {
+ WRITE_VREG(vdec2_canvas_addr++,
+ index | ((index + 1) << 8) |
+ ((index + 1) << 16));
+ }
+
+ i = j - 1;
+#ifdef DOUBLE_WRITE
+ page_count =
+ PAGE_ALIGN((mb_total << 8) + (mb_total << 7) +
+ (mb_total << 6) + (mb_total << 5)) / PAGE_SIZE;
+#else
+ page_count =
+ PAGE_ALIGN((mb_total << 8) + (mb_total << 7)) / PAGE_SIZE;
+#endif
+
+ ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle,
+ VF_BUFFER_IDX(i), page_count << PAGE_SHIFT,
+ DRIVER_NAME, &buffer_spec[i].phy_addr);
+
+ if (ret < 0) {
+ buffer_spec[i].alloc_count = 0;
+ mutex_unlock(&vh264_4k2k_mutex);
+ return ret;
+ }
+ addr = buffer_spec[i].phy_addr;
+ buffer_spec[i].alloc_count = page_count;
+ buffer_spec[i].y_addr = addr;
+ buffer_spec[i].y_canvas_index = index;
+ canvas_config(index,
+ addr,
+ mb_width << 4,
+ mb_height << 4,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+
+ addr += mb_total << 8;
+ index++;
+
+ buffer_spec[i].uv_addr = addr;
+ buffer_spec[i].uv_canvas_index = index;
+ canvas_config(index,
+ addr,
+ mb_width << 4,
+ mb_height << 3,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+
+ addr += mb_total << 7;
+ index++;
+
+#ifdef DOUBLE_WRITE
+ buffer_spec[i].y_dw_addr = addr;
+ buffer_spec[i].y_dw_canvas_index = index;
+ canvas_config(index,
+ addr,
+ mb_width << 3,
+ mb_height << 3,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+
+ addr += mb_total << 6;
+ index++;
+
+ buffer_spec[i].uv_dw_addr = addr;
+ buffer_spec[i].uv_dw_canvas_index = index;
+ canvas_config(index,
+ addr,
+ mb_width << 3,
+ mb_height << 2,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+
+ index++;
+#endif
+ }
+
+ mutex_unlock(&vh264_4k2k_mutex);
+
+ pr_info
+ ("H264 4k2k decoder canvas allocation successful, ");
+
+ return 0;
+}
+
+static int get_max_dec_frame_buf_size(int level_idc,
+ int max_reference_frame_num, int mb_width,
+ int mb_height)
+{
+ int pic_size = mb_width * mb_height * 384;
+
+ int size = 0;
+
+ switch (level_idc) {
+ case 9:
+ size = 152064;
+ break;
+ case 10:
+ size = 152064;
+ break;
+ case 11:
+ size = 345600;
+ break;
+ case 12:
+ size = 912384;
+ break;
+ case 13:
+ size = 912384;
+ break;
+ case 20:
+ size = 912384;
+ break;
+ case 21:
+ size = 1824768;
+ break;
+ case 22:
+ size = 3110400;
+ break;
+ case 30:
+ size = 3110400;
+ break;
+ case 31:
+ size = 6912000;
+ break;
+ case 32:
+ size = 7864320;
+ break;
+ case 40:
+ size = 12582912;
+ break;
+ case 41:
+ size = 12582912;
+ break;
+ case 42:
+ size = 13369344;
+ break;
+ case 50:
+ size = 42393600;
+ break;
+ case 51:
+ case 52:
+ default:
+ size = 70778880;
+ break;
+ }
+
+ size /= pic_size;
+ size = size + 1; /* need one more buffer */
+
+ if (max_reference_frame_num > size)
+ size = max_reference_frame_num;
+
+ if (size > DECODE_BUFFER_NUM_MAX)
+ size = DECODE_BUFFER_NUM_MAX;
+
+ return size;
+}
+
+static void do_alloc_work(struct work_struct *work)
+{
+ int level_idc, max_reference_frame_num, mb_width, mb_height,
+ frame_mbs_only_flag;
+ int dpb_size, ref_size, refbuf_size;
+ int max_dec_frame_buffering,
+ total_dec_frame_buffering;
+ unsigned int chroma444;
+ unsigned int crop_infor, crop_bottom, crop_right;
+ int ret = READ_VREG(MAILBOX_COMMAND);
+
+
+ ret = READ_VREG(MAILBOX_DATA_0);
+ /* MAILBOX_DATA_1 :
+ * bit15 : frame_mbs_only_flag
+ * bit 0-7 : chroma_format_idc
+ * MAILBOX_DATA_2:
+ * bit31-16: (left << 8 | right ) << 1
+ * bit15-0 : (top << 8 | bottom ) << (2 - frame_mbs_only_flag)
+ */
+ frame_mbs_only_flag = READ_VREG(MAILBOX_DATA_1);
+ crop_infor = READ_VREG(MAILBOX_DATA_2);
+ level_idc = (ret >> 24) & 0xff;
+ max_reference_frame_num = (ret >> 16) & 0xff;
+ mb_width = (ret >> 8) & 0xff;
+ if (mb_width == 0)
+ mb_width = 256;
+ mb_height = (ret >> 0) & 0xff;
+ max_dec_frame_buffering =
+ get_max_dec_frame_buf_size(level_idc, max_reference_frame_num,
+ mb_width, mb_height);
+ total_dec_frame_buffering =
+ max_dec_frame_buffering + DISPLAY_BUFFER_NUM;
+
+ chroma444 = ((frame_mbs_only_flag&0xffff) == 3) ? 1 : 0;
+ frame_mbs_only_flag = (frame_mbs_only_flag >> 16) & 0x01;
+ crop_bottom = (crop_infor & 0xff) >> (2 - frame_mbs_only_flag);
+ crop_right = ((crop_infor >> 16) & 0xff) >> 1;
+ pr_info("crop_right = 0x%x crop_bottom = 0x%x chroma_format_idc = 0x%x\n",
+ crop_right, crop_bottom, chroma444);
+
+ if ((frame_width == 0) || (frame_height == 0) || crop_infor ||
+ mb_width != mb_width_old ||
+ mb_height != mb_height_old) {
+ frame_width = mb_width << 4;
+ frame_height = mb_height << 4;
+ mb_width_old = mb_width;
+ mb_height_old = mb_height;
+ if (frame_mbs_only_flag) {
+ frame_height -= (2 >> chroma444) *
+ min(crop_bottom,
+ (unsigned int)((8 << chroma444) - 1));
+ frame_width -= (2 >> chroma444) *
+ min(crop_right,
+ (unsigned int)((8 << chroma444) - 1));
+ } else {
+ frame_height -= (4 >> chroma444) *
+ min(crop_bottom,
+ (unsigned int)((8 << chroma444) - 1));
+ frame_width -= (4 >> chroma444) *
+ min(crop_right,
+ (unsigned int)((8 << chroma444) - 1));
+ }
+ pr_info("frame_mbs_only_flag %d, crop_bottom %d frame_height %d, mb_height %d crop_right %d, frame_width %d, mb_width %d\n",
+ frame_mbs_only_flag, crop_bottom, frame_height,
+ mb_height, crop_right, frame_width, mb_height);
+ }
+
+ mb_width = (mb_width + 3) & 0xfffffffc;
+ mb_height = (mb_height + 3) & 0xfffffffc;
+
+ dpb_size = mb_width * mb_height * 384;
+ ref_size = mb_width * mb_height * 96;
+ refbuf_size = ref_size * (max_reference_frame_num + 1) * 2;
+
+
+ pr_info("mb_width=%d, mb_height=%d\n",
+ mb_width, mb_height);
+
+ ret = init_canvas(refbuf_size, dpb_size,
+ total_dec_frame_buffering, mb_width, mb_height,
+ buffer_spec);
+
+ if (ret == -1) {
+ pr_info(" Un-expected memory alloc problem\n");
+ return;
+ }
+
+ if (frame_width == 0)
+ frame_width = mb_width << 4;
+ if (frame_height == 0)
+ frame_height = mb_height << 4;
+
+ WRITE_VREG(REF_START_VIEW_0, video_domain_addr(ref_start_addr));
+ if (!H264_4K2K_SINGLE_CORE) {
+ WRITE_VREG(VDEC2_REF_START_VIEW_0,
+ video_domain_addr(ref_start_addr));
+ }
+
+ WRITE_VREG(MAILBOX_DATA_0,
+ (max_dec_frame_buffering << 8) |
+ (total_dec_frame_buffering << 0));
+ WRITE_VREG(MAILBOX_DATA_1, ref_size);
+ WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED);
+
+ /* ///////////// FAKE FIRST PIC */
+
+}
+
+static irqreturn_t vh264_4k2k_isr(int irq, void *dev_id)
+{
+ int drop_status, display_buff_id, display_POC, slice_type, error;
+ unsigned int stream_offset;
+ struct vframe_s *vf = NULL;
+ int ret = READ_VREG(MAILBOX_COMMAND);
+ u32 frame_size;
+
+ switch (ret & 0xff) {
+ case CMD_ALLOC_VIEW:
+ schedule_work(&alloc_work);
+ break;
+
+ case CMD_FRAME_DISPLAY:
+ ret >>= 8;
+ display_buff_id = (ret >> 0) & 0x3f;
+ drop_status = (ret >> 8) & 0x1;
+ slice_type = (ret >> 9) & 0x7;
+ error = (ret >> 12) & 0x1;
+ display_POC = READ_VREG(MAILBOX_DATA_0);
+ stream_offset = READ_VREG(MAILBOX_DATA_1);
+
+ smp_rmb();/* rmb smp */
+
+ WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED);
+
+ if (kfifo_get(&newframe_q, &vf) == 0) {
+ pr_info("fatal error, no available buffer slot.");
+ return IRQ_HANDLED;
+ }
+
+ if (vf) {
+ vfbuf_use[display_buff_id]++;
+
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+
+ if ((!sync_outside)
+ || (sync_outside &&
+ (slice_type == SLICE_TYPE_I))) {
+ ret = pts_lookup_offset_us64(PTS_TYPE_VIDEO,
+ stream_offset,
+ &vf->pts,
+ &frame_size,
+ 0,
+ &vf->pts_us64);
+ if (ret != 0)
+ pr_debug(" vpts lookup failed\n");
+ }
+#ifdef H264_4K2K_SINGLE_CORE
+ if (READ_VREG(DECODE_MODE) & 1) {
+ /* for I only mode, ignore the PTS information
+ * and only uses 10fps for each
+ * I frame decoded
+ */
+ if (p_last_vf) {
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+ }
+ frame_dur = 96000 / 10;
+ }
+#endif
+ vf->signal_type = 0;
+ vf->index = display_buff_id;
+ vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD;
+ vf->type |= VIDTYPE_VIU_NV21;
+ vf->canvas0Addr = vf->canvas1Addr =
+ spec2canvas(&buffer_spec[display_buff_id]);
+ set_frame_info(vf);
+
+ if (error)
+ gvs->drop_frame_count++;
+
+ gvs->frame_dur = frame_dur;
+ vdec_count_info(gvs, error, stream_offset);
+
+ if (((error_recovery_mode & 2) && error)
+ || (!first_i_received
+ && (slice_type != SLICE_TYPE_I))) {
+ kfifo_put(&recycle_q,
+ (const struct vframe_s *)vf);
+ } else {
+ p_last_vf = vf;
+ first_i_received = 1;
+ vf->mem_handle =
+ decoder_bmmu_box_get_mem_handle(
+ mm_blk_handle,
+ VF_BUFFER_IDX(display_buff_id));
+ kfifo_put(&display_q,
+ (const struct vframe_s *)vf);
+ ATRACE_COUNTER(MODULE_NAME, vf->pts);
+
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY,
+ NULL);
+ }
+ }
+ break;
+
+ case CMD_DEBUG:
+ pr_info("M: core_status 0x%08x 0x%08x; ",
+ READ_VREG(CORE_STATUS_M), READ_VREG(CORE_STATUS_S));
+ switch (READ_VREG(MAILBOX_DATA_0)) {
+ case 1:
+ pr_info("H264_BUFFER_INFO_INDEX = 0x%x\n",
+ READ_VREG(MAILBOX_DATA_1));
+ WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED);
+ break;
+ case 2:
+ pr_info("H264_BUFFER_INFO_DATA = 0x%x\n",
+ READ_VREG(MAILBOX_DATA_1));
+ WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED);
+ break;
+ case 3:
+ pr_info("REC_CANVAS_ADDR = 0x%x\n",
+ READ_VREG(MAILBOX_DATA_1));
+ WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED);
+ break;
+ case 4:
+ pr_info("after DPB_MMCO\n");
+ WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED);
+ break;
+ case 5:
+ pr_info("MBY = 0x%x, S_MBXY = 0x%x\n",
+ READ_VREG(MAILBOX_DATA_1),
+ READ_VREG(0x2c07));
+ WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED);
+ break;
+ case 6:
+ pr_info("after FIFO_OUT_FRAME\n");
+ WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED);
+ break;
+ case 7:
+ pr_info("after RELEASE_EXCEED_REF_BUFF\n");
+ WRITE_VREG(MAILBOX_COMMAND, CMD_FINISHED);
+ break;
+ case 0x5a:
+ pr_info("\n");
+ break;
+ default:
+ pr_info("\n");
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return IRQ_HANDLED;
+}
+
+#if 1 /*MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8*/
+static irqreturn_t vh264_4k2k_vdec2_isr(int irq, void *dev_id)
+{
+ int ret = READ_VREG(VDEC2_MAILBOX_COMMAND);
+
+ switch (ret & 0xff) {
+ case CMD_DEBUG:
+ pr_info("S: core_status 0x%08x 0x%08x; ",
+ READ_VREG(CORE_STATUS_M), READ_VREG(CORE_STATUS_S));
+ switch (READ_VREG(VDEC2_MAILBOX_DATA_0)) {
+ case 1:
+ pr_info("H264_BUFFER_INFO_INDEX = 0x%x\n",
+ READ_VREG(VDEC2_MAILBOX_DATA_1));
+ WRITE_VREG(VDEC2_MAILBOX_COMMAND, CMD_FINISHED);
+ break;
+ case 2:
+ pr_info("H264_BUFFER_INFO_DATA = 0x%x\n",
+ READ_VREG(VDEC2_MAILBOX_DATA_1));
+ WRITE_VREG(VDEC2_MAILBOX_COMMAND, CMD_FINISHED);
+ break;
+ case 3:
+ pr_info("REC_CANVAS_ADDR = 0x%x\n",
+ READ_VREG(VDEC2_MAILBOX_DATA_1));
+ WRITE_VREG(VDEC2_MAILBOX_COMMAND, CMD_FINISHED);
+ break;
+ case 4:
+ pr_info("after DPB_MMCO\n");
+ WRITE_VREG(VDEC2_MAILBOX_COMMAND, CMD_FINISHED);
+ break;
+ case 5:
+ pr_info("MBY = 0x%x, M/S_MBXY = 0x%x-0x%x\n",
+ READ_VREG(VDEC2_MAILBOX_DATA_1),
+ READ_VREG(0xc07), READ_VREG(0x2c07));
+ WRITE_VREG(VDEC2_MAILBOX_COMMAND, CMD_FINISHED);
+ break;
+ case 6:
+ pr_info("after FIFO_OUT_FRAME\n");
+ WRITE_VREG(VDEC2_MAILBOX_COMMAND, CMD_FINISHED);
+ break;
+ case 7:
+ pr_info("after RELEASE_EXCEED_REF_BUFF\n");
+ WRITE_VREG(VDEC2_MAILBOX_COMMAND, CMD_FINISHED);
+ break;
+ case 0x5a:
+ pr_info("\n");
+ break;
+ default:
+ pr_info("\n");
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return IRQ_HANDLED;
+}
+#endif
+
+static void vh264_4k2k_set_clk(struct work_struct *work)
+{
+ if (first_i_received &&/*do switch after first i frame ready.*/
+ frame_dur > 0 && saved_resolution !=
+ frame_width * frame_height * (96000 / frame_dur)) {
+ int fps = 96000 / frame_dur;
+
+ pr_info("H264 4k2k resolution changed!!\n");
+ if (vdec_source_changed(VFORMAT_H264_4K2K,
+ frame_width, frame_height, fps) > 0)/*changed clk ok*/
+ saved_resolution = frame_width * frame_height * fps;
+ }
+}
+
+static void vh264_4k2k_put_timer_func(unsigned long arg)
+{
+ struct timer_list *timer = (struct timer_list *)arg;
+ enum receviver_start_e state = RECEIVER_INACTIVE;
+
+ if (vf_get_receiver(PROVIDER_NAME)) {
+ state = vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_QUREY_STATE, NULL);
+ if ((state == RECEIVER_STATE_NULL)
+ || (state == RECEIVER_STATE_NONE))
+ state = RECEIVER_INACTIVE;
+ } else
+ state = RECEIVER_INACTIVE;
+
+ /* error watchdog */
+ if (((READ_VREG(VLD_MEM_VIFIFO_CONTROL) & 0x100) == 0) &&/* dec has in*/
+ (state == RECEIVER_INACTIVE) && /* rec has no buf to recycle */
+ (kfifo_is_empty(&display_q)) && /* no buf in display queue */
+ (kfifo_is_empty(&recycle_q)) && /* no buf to recycle */
+ (READ_VREG(MS_ID) & 0x100)
+#ifdef CONFIG_H264_2K4K_SINGLE_CORE
+ && (READ_VREG(VDEC2_MS_ID) & 0x100)
+
+/* with both decoder
+ * have started decoding
+ */
+#endif
+ && first_i_received) {
+ if (++error_watchdog_count == ERROR_RESET_COUNT) {
+ /* and it lasts for a while */
+ pr_info("H264 4k2k decoder fatal error watchdog.\n");
+ fatal_error = DECODER_FATAL_ERROR_UNKNOWN;
+ }
+ } else
+ error_watchdog_count = 0;
+
+ if (READ_VREG(FATAL_ERROR) != 0) {
+ pr_info("H264 4k2k decoder ucode fatal error.\n");
+ fatal_error = DECODER_FATAL_ERROR_UNKNOWN;
+ WRITE_VREG(FATAL_ERROR, 0);
+ }
+
+ while (!kfifo_is_empty(&recycle_q) &&
+ (READ_VREG(BUFFER_RECYCLE) == 0)) {
+ struct vframe_s *vf;
+
+ if (kfifo_get(&recycle_q, &vf)) {
+ if ((vf->index < DECODE_BUFFER_NUM_MAX)
+ && (--vfbuf_use[vf->index] == 0)) {
+ WRITE_VREG(BUFFER_RECYCLE, vf->index + 1);
+ vf->index = DECODE_BUFFER_NUM_MAX;
+ }
+
+ kfifo_put(&newframe_q, (const struct vframe_s *)vf);
+ }
+ }
+
+ schedule_work(&set_clk_work);
+
+ timer->expires = jiffies + PUT_INTERVAL;
+
+ add_timer(timer);
+}
+
+int vh264_4k2k_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus)
+{
+ vstatus->frame_width = frame_width;
+ vstatus->frame_height = frame_height;
+ if (frame_dur != 0)
+ vstatus->frame_rate = 96000 / frame_dur;
+ else
+ vstatus->frame_rate = -1;
+ vstatus->error_count = 0;
+ vstatus->status = stat | fatal_error;
+ vstatus->frame_dur = frame_dur;
+ vstatus->frame_data = gvs->frame_data;
+ vstatus->total_data = gvs->total_data;
+ vstatus->frame_count = gvs->frame_count;
+ vstatus->error_frame_count = gvs->error_frame_count;
+ vstatus->drop_frame_count = gvs->drop_frame_count;
+ vstatus->total_data = gvs->total_data;
+ vstatus->samp_cnt = gvs->samp_cnt;
+ vstatus->offset = gvs->offset;
+ snprintf(vstatus->vdec_name, sizeof(vstatus->vdec_name),
+ "%s", DRIVER_NAME);
+
+ return 0;
+}
+
+static int vh264_4k2k_vdec_info_init(void)
+{
+ gvs = kzalloc(sizeof(struct vdec_info), GFP_KERNEL);
+ if (NULL == gvs) {
+ pr_info("the struct of vdec status malloc failed.\n");
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+int vh264_4k2k_set_trickmode(struct vdec_s *vdec, unsigned long trickmode)
+{
+ if (trickmode == TRICKMODE_I) {
+ WRITE_VREG(DECODE_MODE, 1);
+ trickmode_i = 1;
+ } else if (trickmode == TRICKMODE_NONE) {
+ WRITE_VREG(DECODE_MODE, 0);
+ trickmode_i = 0;
+ }
+
+ return 0;
+}
+
+static void H264_DECODE_INIT(void)
+{
+ int i;
+
+ WRITE_VREG(GCLK_EN, 0x3ff);
+
+ WRITE_VREG(DOS_SW_RESET0, (1 << 7) | (1 << 6) | (1 << 4));
+ WRITE_VREG(DOS_SW_RESET0, 0);
+
+ READ_VREG(DOS_SW_RESET0);
+ READ_VREG(DOS_SW_RESET0);
+ READ_VREG(DOS_SW_RESET0);
+
+ WRITE_VREG(DOS_SW_RESET0, (1 << 7) | (1 << 6) | (1 << 4));
+ WRITE_VREG(DOS_SW_RESET0, 0);
+
+ WRITE_VREG(DOS_SW_RESET0, (1 << 9) | (1 << 8));
+ WRITE_VREG(DOS_SW_RESET0, 0);
+
+ READ_VREG(DOS_SW_RESET0);
+ READ_VREG(DOS_SW_RESET0);
+ READ_VREG(DOS_SW_RESET0);
+
+ /* fill_weight_pred */
+ WRITE_VREG(MC_MPORT_CTRL, 0x0300);
+ for (i = 0; i < 192; i++)
+ WRITE_VREG(MC_MPORT_DAT, 0x100);
+ WRITE_VREG(MC_MPORT_CTRL, 0);
+
+ WRITE_VREG(MB_WIDTH, 0xff); /* invalid mb_width */
+
+ /* set slice start to 0x000000 or 0x000001 for check more_rbsp_data */
+ WRITE_VREG(SLICE_START_BYTE_01, 0x00000000);
+ WRITE_VREG(SLICE_START_BYTE_23, 0x01010000);
+ /* set to mpeg2 to enable mismatch logic */
+ WRITE_VREG(MPEG1_2_REG, 1);
+ WRITE_VREG(VLD_ERROR_MASK,
+ 0x1011);
+
+ /* Config MCPU Amrisc interrupt */
+ WRITE_VREG(ASSIST_AMR1_INT0, 0x1); /* viu_vsync_int */
+ WRITE_VREG(ASSIST_AMR1_INT1, 0x5); /* mbox_isr */
+ WRITE_VREG(ASSIST_AMR1_INT2, 0x8); /* vld_isr */
+ /* WRITE_VREG(ASSIST_AMR1_INT3, 0x15); // vififo_empty */
+ WRITE_VREG(ASSIST_AMR1_INT4, 0xd); /* rv_ai_mb_finished_int */
+ WRITE_VREG(ASSIST_AMR1_INT7, 0x14); /* dcac_dma_done */
+ WRITE_VREG(ASSIST_AMR1_INT8, 0x15); /* vififo_empty */
+
+ /* Config MCPU Amrisc interrupt */
+ WRITE_VREG(ASSIST_AMR1_INT5, 0x9); /* MCPU interrupt */
+ WRITE_VREG(ASSIST_AMR1_INT6, 0x17); /* CCPU interrupt */
+
+ WRITE_VREG(CPC_P, 0xc00); /* CCPU Code will start from 0xc00 */
+ WRITE_VREG(CINT_VEC_BASE, (0xc20 >> 5));
+ WRITE_VREG(POWER_CTL_VLD, (1 << 10) | /* disable cabac_step_2 */
+ (1 << 9) | /* viff_drop_flag_en */
+ (1 << 6)); /* h264_000003_en */
+ WRITE_VREG(M4_CONTROL_REG, (1 << 13)); /* H264_DECODE_INFO - h264_en */
+
+ WRITE_VREG(CANVAS_START, AMVDEC_H264_4K2K_CANVAS_INDEX);
+ /* Start Address of Workspace (UCODE, temp_data...) */
+ WRITE_VREG(WORKSPACE_START,
+ video_domain_addr(work_space_adr));
+ /* Clear all sequence parameter set available */
+ WRITE_VREG(SPS_STATUS, 0);
+ /* Clear all picture parameter set available */
+ WRITE_VREG(PPS_STATUS, 0);
+ /* Set current microcode to NULL */
+ WRITE_VREG(CURRENT_UCODE, 0xff);
+ /* Set current SPS/PPS to NULL */
+ WRITE_VREG(CURRENT_SPS_PPS, 0xffff);
+ /* Set decode status to DECODE_START_HEADER */
+ WRITE_VREG(DECODE_STATUS, 1);
+}
+
+static void H264_DECODE2_INIT(void)
+{
+ int i;
+
+ WRITE_VREG(VDEC2_GCLK_EN, 0x3ff);
+
+ WRITE_VREG(DOS_SW_RESET2, (1 << 7) | (1 << 6) | (1 << 4));
+ WRITE_VREG(DOS_SW_RESET2, 0);
+
+ READ_VREG(DOS_SW_RESET2);
+ READ_VREG(DOS_SW_RESET2);
+ READ_VREG(DOS_SW_RESET2);
+
+ WRITE_VREG(DOS_SW_RESET2, (1 << 7) | (1 << 6) | (1 << 4));
+ WRITE_VREG(DOS_SW_RESET2, 0);
+
+ WRITE_VREG(DOS_SW_RESET2, (1 << 9) | (1 << 8));
+ WRITE_VREG(DOS_SW_RESET2, 0);
+
+ READ_VREG(DOS_SW_RESET2);
+ READ_VREG(DOS_SW_RESET2);
+ READ_VREG(DOS_SW_RESET2);
+
+ /* fill_weight_pred */
+ WRITE_VREG(VDEC2_MC_MPORT_CTRL, 0x0300);
+ for (i = 0; i < 192; i++)
+ WRITE_VREG(VDEC2_MC_MPORT_DAT, 0x100);
+ WRITE_VREG(VDEC2_MC_MPORT_CTRL, 0);
+
+ WRITE_VREG(VDEC2_MB_WIDTH, 0xff); /* invalid mb_width */
+
+ /* set slice start to 0x000000 or 0x000001 for check more_rbsp_data */
+ WRITE_VREG(VDEC2_SLICE_START_BYTE_01, 0x00000000);
+ WRITE_VREG(VDEC2_SLICE_START_BYTE_23, 0x01010000);
+ /* set to mpeg2 to enable mismatch logic */
+ WRITE_VREG(VDEC2_MPEG1_2_REG, 1);
+ /* disable COEF_GT_64 , error_m4_table and voff_rw_err */
+ WRITE_VREG(VDEC2_VLD_ERROR_MASK,
+ 0x1011);
+
+ /* Config MCPU Amrisc interrupt */
+ WRITE_VREG(VDEC2_ASSIST_AMR1_INT0, 0x1);/* viu_vsync_int */
+ WRITE_VREG(VDEC2_ASSIST_AMR1_INT1, 0x5);/* mbox_isr */
+ WRITE_VREG(VDEC2_ASSIST_AMR1_INT2, 0x8);/* vld_isr */
+ /* WRITE_VREG(VDEC2_ASSIST_AMR1_INT3, 0x15); // vififo_empty */
+ WRITE_VREG(VDEC2_ASSIST_AMR1_INT4, 0xd);/* rv_ai_mb_finished_int */
+ WRITE_VREG(VDEC2_ASSIST_AMR1_INT7, 0x14);/* dcac_dma_done */
+ WRITE_VREG(VDEC2_ASSIST_AMR1_INT8, 0x15);/* vififo_empty */
+
+ /* Config MCPU Amrisc interrupt */
+ WRITE_VREG(VDEC2_ASSIST_AMR1_INT5, 0x9);/* MCPU interrupt */
+ WRITE_VREG(VDEC2_ASSIST_AMR1_INT6, 0x17);/* CCPU interrupt */
+
+ WRITE_VREG(VDEC2_CPC_P, 0xc00); /* CCPU Code will start from 0xc00 */
+ WRITE_VREG(VDEC2_CINT_VEC_BASE, (0xc20 >> 5));
+ WRITE_VREG(VDEC2_POWER_CTL_VLD, (1 << 10) |/* disable cabac_step_2 */
+ (1 << 9) | /* viff_drop_flag_en */
+ (1 << 6)); /* h264_000003_en */
+ /* H264_DECODE_INFO - h264_en */
+ WRITE_VREG(VDEC2_M4_CONTROL_REG, (1 << 13));
+
+ WRITE_VREG(VDEC2_CANVAS_START, AMVDEC_H264_4K2K_CANVAS_INDEX);
+ /* Start Address of Workspace (UCODE, temp_data...) */
+ WRITE_VREG(VDEC2_WORKSPACE_START,
+ video_domain_addr(work_space_adr));
+ /* Clear all sequence parameter set available */
+ WRITE_VREG(VDEC2_SPS_STATUS, 0);
+ /* Clear all picture parameter set available */
+ WRITE_VREG(VDEC2_PPS_STATUS, 0);
+ /* Set current microcode to NULL */
+ WRITE_VREG(VDEC2_CURRENT_UCODE, 0xff);
+ /* Set current SPS/PPS to NULL */
+ WRITE_VREG(VDEC2_CURRENT_SPS_PPS, 0xffff);
+ /* Set decode status to DECODE_START_HEADER */
+ WRITE_VREG(VDEC2_DECODE_STATUS, 1);
+}
+
+static void vh264_4k2k_prot_init(void)
+{
+ /* clear mailbox interrupt */
+#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
+ if (!H264_4K2K_SINGLE_CORE)
+ WRITE_VREG(VDEC2_ASSIST_MBOX0_CLR_REG, 1);
+#endif
+ WRITE_VREG(VDEC_ASSIST_MBOX1_CLR_REG, 1);
+
+ /* enable mailbox interrupt */
+#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
+ if (!H264_4K2K_SINGLE_CORE)
+ WRITE_VREG(VDEC2_ASSIST_MBOX0_MASK, 1);
+#endif
+ WRITE_VREG(VDEC_ASSIST_MBOX1_MASK, 1);
+
+ /* disable PSCALE for hardware sharing */
+ WRITE_VREG(PSCALE_CTRL, 0);
+
+ H264_DECODE_INIT();
+ if (!H264_4K2K_SINGLE_CORE)
+ H264_DECODE2_INIT();
+
+ WRITE_VREG(DOS_SW_RESET0, (1 << 11));
+ WRITE_VREG(DOS_SW_RESET0, 0);
+
+ READ_VREG(DOS_SW_RESET0);
+ READ_VREG(DOS_SW_RESET0);
+ READ_VREG(DOS_SW_RESET0);
+
+ if (!H264_4K2K_SINGLE_CORE) {
+ WRITE_VREG(DOS_SW_RESET2, (1 << 11));
+ WRITE_VREG(DOS_SW_RESET2, 0);
+
+ READ_VREG(DOS_SW_RESET2);
+ READ_VREG(DOS_SW_RESET2);
+ READ_VREG(DOS_SW_RESET2);
+ }
+
+ WRITE_VREG(MAILBOX_COMMAND, 0);
+ WRITE_VREG(BUFFER_RECYCLE, 0);
+
+ if (!H264_4K2K_SINGLE_CORE) {
+ WRITE_VREG(VDEC2_MAILBOX_COMMAND, 0);
+ WRITE_VREG(VDEC2_BUFFER_RECYCLE, 0);
+ }
+
+ CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17);
+ if (!H264_4K2K_SINGLE_CORE)
+ CLEAR_VREG_MASK(VDEC2_MDEC_PIC_DC_CTRL, 1 << 17);
+
+ /* set VDEC Master/ID 0 */
+ WRITE_VREG(MS_ID, (1 << 7) | (0 << 0));
+ if (!H264_4K2K_SINGLE_CORE) {
+ /* set VDEC2 Slave/ID 0 */
+ WRITE_VREG(VDEC2_MS_ID, (0 << 7) | (1 << 0));
+ }
+ WRITE_VREG(DECODE_SKIP_PICTURE, 0);
+ if (!H264_4K2K_SINGLE_CORE)
+ WRITE_VREG(VDEC2_DECODE_SKIP_PICTURE, 0);
+
+ WRITE_VREG(PRE_MASTER_UPDATE_TIMES, 0);
+ WRITE_VREG(SLAVE_WAIT_DPB_UPDATE, 0);
+ WRITE_VREG(SLAVE_REF_DPB, 0);
+ WRITE_VREG(SAVE_MVC_ENTENSION_0, 0);
+ WRITE_VREG(SAVE_I_POC, 0);
+ WRITE_VREG(CORE_STATUS_M, 0);
+ WRITE_VREG(CORE_STATUS_S, 0);
+ WRITE_VREG(SAVE_ref_status_view_0, 0);
+ WRITE_VREG(SAVE_ref_status_view_1, 0);
+ WRITE_VREG(ALLOC_INFO_0, 0);
+ WRITE_VREG(ALLOC_INFO_1, 0);
+ WRITE_VREG(FATAL_ERROR, 0);
+
+ SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17);
+ if (!H264_4K2K_SINGLE_CORE)
+ SET_VREG_MASK(VDEC2_MDEC_PIC_DC_CTRL, 1 << 17);
+
+ WRITE_VREG(MDEC_PIC_DC_THRESH, 0x404038aa);
+ if (!H264_4K2K_SINGLE_CORE) {
+ WRITE_VREG(VDEC2_MDEC_PIC_DC_THRESH, 0x404038aa);
+ }
+#ifdef DOUBLE_WRITE
+ WRITE_VREG(MDEC_DOUBLEW_CFG0, (0 << 31) | /* half y address */
+ (1 << 30) | /* 0:No Merge 1:Automatic Merge */
+ (0 << 28) |
+
+/* Field Picture, 0x:no skip
+ * 10:top only
+ * 11:bottom only
+ */
+ (0 << 27) | /* Source from, 1:MCW 0:DBLK */
+ (0 << 24) | /* Endian Control for Chroma */
+ (0 << 18) | /* DMA ID */
+ (0 << 12) | /* DMA Burst Number */
+ (0 << 11) | /* DMA Urgent */
+ (0 << 10) | /* 1:Round 0:Truncation */
+ (1 << 9) |
+
+/* Size by vertical, 0:original size
+ * 1: 1/2 shrunken size
+ */
+ (1 << 8) |
+
+/* Size by horizontal, 0:original size
+ * 1: 1/2 shrunken size
+ */
+ (0 << 6) |
+
+/* Pixel sel by vertical, 0x:1/2
+ * 10:up
+ * 11:down
+ */
+ (0 << 4) |
+
+/* Pixel sel by horizontal, 0x:1/2
+ * 10:left
+ * 11:right
+ */
+ (0 << 1) | /* Endian Control for Luma */
+ (1 << 0)); /* Double Write Enable */
+ if (!H264_4K2K_SINGLE_CORE) {
+ WRITE_VREG(VDEC2_MDEC_DOUBLEW_CFG0,
+ (0 << 31) | /* half y address */
+ (1 << 30) |
+
+/* 0:No Merge
+ * 1:Automatic Merge
+ */
+ (0 << 28) |
+
+/* Field Picture, 0x:no skip
+ * 10:top only
+ * 11:bottom only
+ */
+ (0 << 27) | /* Source from, 1:MCW 0:DBLK */
+ (0 << 24) | /* Endian Control for Chroma */
+ (0 << 18) | /* DMA ID */
+ (0 << 12) | /* DMA Burst Number */
+ (0 << 11) | /* DMA Urgent */
+ (0 << 10) | /* 1:Round 0:Truncation */
+ (1 << 9) |
+
+/* Size by vertical,
+ * 0:original size
+ * 1: 1/2 shrunken size
+ */
+ (1 << 8) |
+
+/* Size by horizontal,
+ * 0:original size
+ * 1: 1/2 shrunken size
+ */
+ (0 << 6) |
+
+/* Pixel sel by vertical,
+ * 0x:1/2
+ * 10:up
+ * 11:down
+ */
+ (0 << 4) |
+
+/* Pixel sel by horizontal,
+ * 0x:1/2
+ * 10:left
+ * 11:right
+ */
+ (0 << 1) | /* Endian Control for Luma */
+ (1 << 0)); /* Double Write Enable */
+ }
+#endif
+}
+
+static int vh264_4k2k_local_init(void)
+{
+ int i, size, ret;
+
+#ifdef DEBUG_PTS
+ pts_missed = 0;
+ pts_hit = 0;
+#endif
+ mb_width_old = 0;
+ mb_height_old = 0;
+ saved_resolution = 0;
+ vh264_4k2k_rotation =
+ (((unsigned long) vh264_4k2k_amstream_dec_info.param) >> 16)
+ & 0xffff;
+ frame_width = vh264_4k2k_amstream_dec_info.width;
+ frame_height = vh264_4k2k_amstream_dec_info.height;
+ frame_dur =
+ (vh264_4k2k_amstream_dec_info.rate ==
+ 0) ? 3600 : vh264_4k2k_amstream_dec_info.rate;
+ if (frame_width && frame_height)
+ frame_ar = frame_height * 0x100 / frame_width;
+ sync_outside = ((unsigned long) vh264_4k2k_amstream_dec_info.param
+ & 0x02) >> 1;
+ error_watchdog_count = 0;
+
+ pr_info("H264_4K2K: decinfo: %dx%d rate=%d\n",
+ frame_width, frame_height,
+ frame_dur);
+
+ if (frame_dur == 0)
+ frame_dur = 96000 / 24;
+
+ INIT_KFIFO(display_q);
+ INIT_KFIFO(recycle_q);
+ INIT_KFIFO(newframe_q);
+
+ for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++)
+ vfbuf_use[i] = 0;
+
+ for (i = 0; i < VF_POOL_SIZE; i++) {
+ const struct vframe_s *vf = &vfpool[i];
+
+ vfpool[i].index = DECODE_BUFFER_NUM_MAX;
+ kfifo_put(&newframe_q, vf);
+ }
+
+ reserved_buffer = 0;
+ p_last_vf = NULL;
+ first_i_received = 0;
+ INIT_WORK(&alloc_work, do_alloc_work);
+
+ if (mm_blk_handle) {
+ decoder_bmmu_box_free(mm_blk_handle);
+ mm_blk_handle = NULL;
+ }
+
+ mm_blk_handle = decoder_bmmu_box_alloc_box(
+ DRIVER_NAME,
+ 0,
+ MAX_BMMU_BUFFER_NUM,
+ 4 + PAGE_SHIFT,
+ CODEC_MM_FLAGS_CMA_CLEAR |
+ CODEC_MM_FLAGS_FOR_VDECODER);
+
+ size = DECODER_WORK_SPACE_SIZE;
+ ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle, 0,
+ size, DRIVER_NAME, &work_space_adr);
+ return ret;
+}
+
+static s32 vh264_4k2k_init(void)
+{
+ int ret = -1, size = -1;
+ char *buf = vmalloc(0x1000 * 16);
+
+ if (buf == NULL)
+ return -ENOMEM;
+
+ pr_info("\nvh264_4k2k_init\n");
+
+ init_timer(&recycle_timer);
+
+ stat |= STAT_TIMER_INIT;
+
+ ret = vh264_4k2k_local_init();
+ if (ret < 0) {
+ vfree(buf);
+ return ret;
+ }
+ amvdec_enable();
+
+ /* -- ucode loading (amrisc and swap code) */
+ mc_cpu_addr = dma_alloc_coherent(amports_get_dma_device(),
+ MC_TOTAL_SIZE, &mc_dma_handle, GFP_KERNEL);
+ if (!mc_cpu_addr) {
+ amvdec_disable();
+ vfree(buf);
+ pr_err("vh264_4k2k init: Can not allocate mc memory.\n");
+ return -ENOMEM;
+ }
+
+ WRITE_VREG(AV_SCRATCH_L, mc_dma_handle);
+ if (!H264_4K2K_SINGLE_CORE)
+ WRITE_VREG(VDEC2_AV_SCRATCH_L, mc_dma_handle);
+
+ if (H264_4K2K_SINGLE_CORE)
+ size = get_firmware_data(VIDEO_DEC_H264_4k2K_SINGLE, buf);
+ else
+ size = get_firmware_data(VIDEO_DEC_H264_4k2K, buf);
+
+ if (size < 0) {
+ pr_err("get firmware fail.");
+ vfree(buf);
+ return -1;
+ }
+
+ if (H264_4K2K_SINGLE_CORE)
+ ret = amvdec_loadmc_ex(VFORMAT_H264_4K2K, "single_core", buf);
+ else
+ ret = amvdec_loadmc_ex(VFORMAT_H264_4K2K, NULL, buf);
+
+ if (ret < 0) {
+ amvdec_disable();
+ dma_free_coherent(amports_get_dma_device(),
+ MC_TOTAL_SIZE, mc_cpu_addr, mc_dma_handle);
+ mc_cpu_addr = NULL;
+ pr_err("H264_4K2K: the %s fw loading failed, err: %x\n",
+ tee_enabled() ? "TEE" : "local", ret);
+ return -EBUSY;
+ }
+
+ if (!H264_4K2K_SINGLE_CORE) {
+ amvdec2_enable();
+
+ if (amvdec2_loadmc_ex(VFORMAT_H264_4K2K, NULL, buf) < 0) {
+ amvdec_disable();
+ amvdec2_disable();
+ dma_free_coherent(amports_get_dma_device(),
+ MC_TOTAL_SIZE, mc_cpu_addr, mc_dma_handle);
+ mc_cpu_addr = NULL;
+ return -EBUSY;
+ }
+ }
+
+ /*header*/
+ memcpy((u8 *) mc_cpu_addr, buf + 0x1000, 0x1000);
+
+ /*mmco*/
+ memcpy((u8 *) mc_cpu_addr + 0x1000, buf + 0x2000, 0x2000);
+
+ /*slice*/
+ memcpy((u8 *) mc_cpu_addr + 0x3000, buf + 0x4000, 0x3000);
+
+ stat |= STAT_MC_LOAD;
+
+ /* enable AMRISC side protocol */
+ vh264_4k2k_prot_init();
+
+ if (vdec_request_irq(VDEC_IRQ_1, vh264_4k2k_isr,
+ "vh264_4k2k-irq", (void *)vh264_4k2k_dec_id)) {
+ pr_info("vh264_4k2k irq register error.\n");
+ amvdec_disable();
+ if (!H264_4K2K_SINGLE_CORE)
+ amvdec2_disable();
+
+ return -ENOENT;
+ }
+#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
+ if (!H264_4K2K_SINGLE_CORE) {
+ if (vdec_request_irq(VDEC_IRQ_0, vh264_4k2k_vdec2_isr,
+ "vh264_4k2k-vdec2-irq",
+ (void *)vh264_4k2k_dec_id2)) {
+ pr_info("vh264_4k2k irq register error.\n");
+ vdec_free_irq(VDEC_IRQ_1, (void *)vh264_4k2k_dec_id);
+ amvdec_disable();
+ amvdec2_disable();
+ return -ENOENT;
+ }
+ }
+#endif
+
+ stat |= STAT_ISR_REG;
+
+ vf_provider_init(&vh264_4k2k_vf_prov, PROVIDER_NAME,
+ &vh264_4k2k_vf_provider, NULL);
+ vf_reg_provider(&vh264_4k2k_vf_prov);
+ vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_START, NULL);
+
+ vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)((unsigned long)
+ vh264_4k2k_amstream_dec_info.rate));
+
+ stat |= STAT_VF_HOOK;
+
+ recycle_timer.data = (ulong) (&recycle_timer);
+ recycle_timer.function = vh264_4k2k_put_timer_func;
+ recycle_timer.expires = jiffies + PUT_INTERVAL;
+
+ add_timer(&recycle_timer);
+
+ stat |= STAT_TIMER_ARM;
+
+ amvdec_start();
+ if (!H264_4K2K_SINGLE_CORE)
+ amvdec2_start();
+
+ stat |= STAT_VDEC_RUN;
+
+ ret = vh264_4k2k_vdec_info_init();
+ if (0 != ret)
+ return -ret;
+
+ return 0;
+}
+
+static int vh264_4k2k_stop(void)
+{
+
+ if (stat & STAT_VDEC_RUN) {
+ amvdec_stop();
+ if (!H264_4K2K_SINGLE_CORE)
+ amvdec2_stop();
+ stat &= ~STAT_VDEC_RUN;
+ }
+
+ if (stat & STAT_ISR_REG) {
+ WRITE_VREG(VDEC_ASSIST_MBOX1_MASK, 0);
+ if (!H264_4K2K_SINGLE_CORE)
+ WRITE_VREG(VDEC2_ASSIST_MBOX0_MASK, 0);
+
+ vdec_free_irq(VDEC_IRQ_1, (void *)vh264_4k2k_dec_id);
+#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
+ if (!H264_4K2K_SINGLE_CORE)
+ vdec_free_irq(VDEC_IRQ_0, (void *)vh264_4k2k_dec_id2);
+#endif
+ stat &= ~STAT_ISR_REG;
+ }
+
+ if (stat & STAT_TIMER_ARM) {
+ del_timer_sync(&recycle_timer);
+ stat &= ~STAT_TIMER_ARM;
+ }
+
+ if (stat & STAT_VF_HOOK) {
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_FR_END_HINT, NULL);
+
+ vf_unreg_provider(&vh264_4k2k_vf_prov);
+ stat &= ~STAT_VF_HOOK;
+ }
+#ifdef DOUBLE_WRITE
+ WRITE_VREG(MDEC_DOUBLEW_CFG0, 0);
+ if (!H264_4K2K_SINGLE_CORE)
+ WRITE_VREG(VDEC2_MDEC_DOUBLEW_CFG0, 0);
+#endif
+
+ if (stat & STAT_MC_LOAD) {
+ if (mc_cpu_addr != NULL) {
+ dma_free_coherent(amports_get_dma_device(),
+ MC_TOTAL_SIZE, mc_cpu_addr, mc_dma_handle);
+ mc_cpu_addr = NULL;
+ }
+
+ stat &= ~STAT_MC_LOAD;
+ }
+
+ amvdec_disable();
+ if (!H264_4K2K_SINGLE_CORE)
+ amvdec2_disable();
+#ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA
+ msleep(100);
+#endif
+ if (mm_blk_handle) {
+ decoder_bmmu_box_free(mm_blk_handle);
+ mm_blk_handle = NULL;
+ }
+
+ return 0;
+}
+
+void vh264_4k_free_cmabuf(void)
+{
+ int i;
+
+ if (atomic_read(&vh264_4k2k_active))
+ return;
+ mutex_lock(&vh264_4k2k_mutex);
+ for (i = 0; i < ARRAY_SIZE(buffer_spec); i++) {
+ if (buffer_spec[i].phy_addr) {
+ codec_mm_free_for_dma(MEM_NAME,
+ buffer_spec[i].phy_addr);
+ buffer_spec[i].phy_addr = 0;
+ buffer_spec[i].alloc_pages = NULL;
+ buffer_spec[i].alloc_count = 0;
+ pr_info("force free CMA buffer %d\n", i);
+ }
+ }
+ mutex_unlock(&vh264_4k2k_mutex);
+}
+
+static int amvdec_h264_4k2k_probe(struct platform_device *pdev)
+{
+ struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
+
+ pr_info("amvdec_h264_4k2k probe start.\n");
+
+ mutex_lock(&vh264_4k2k_mutex);
+
+ fatal_error = 0;
+
+ if (pdata == NULL) {
+ pr_info("\namvdec_h264_4k2k memory resource undefined.\n");
+ mutex_unlock(&vh264_4k2k_mutex);
+ return -EFAULT;
+ }
+
+ if (pdata->sys_info)
+ vh264_4k2k_amstream_dec_info = *pdata->sys_info;
+ cma_dev = pdata->cma_dev;
+
+ pr_info(" sysinfo: %dx%d, rate = %d, param = 0x%lx\n",
+ vh264_4k2k_amstream_dec_info.width,
+ vh264_4k2k_amstream_dec_info.height,
+ vh264_4k2k_amstream_dec_info.rate,
+ (unsigned long) vh264_4k2k_amstream_dec_info.param);
+
+ if (!H264_4K2K_SINGLE_CORE) {
+ if (vdec_on(VDEC_2)) { /* ++++ */
+ vdec_poweroff(VDEC_2); /* ++++ */
+ mdelay(10);
+ }
+ vdec_poweron(VDEC_2);
+ }
+
+
+ if (!H264_4K2K_SINGLE_CORE)
+ vdec2_power_mode(1);
+
+ pdata->dec_status = vh264_4k2k_dec_status;
+ if (H264_4K2K_SINGLE_CORE)
+ pdata->set_trickmode = vh264_4k2k_set_trickmode;
+
+ if (vh264_4k2k_init() < 0) {
+ pr_info("\namvdec_h264_4k2k init failed.\n");
+ mutex_unlock(&vh264_4k2k_mutex);
+ kfree(gvs);
+ gvs = NULL;
+
+ return -ENODEV;
+ }
+#if 1/*MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8*/
+ request_vpu_clk_vmod(360000000, VPU_VIU_VD1);
+#endif
+
+ if (probe_callback)
+ probe_callback();
+ /*set the max clk for smooth playing...*/
+ vdec_source_changed(VFORMAT_H264_4K2K,
+ 4096, 2048, 30);
+ INIT_WORK(&set_clk_work, vh264_4k2k_set_clk);
+
+ atomic_set(&vh264_4k2k_active, 1);
+ mutex_unlock(&vh264_4k2k_mutex);
+
+ return 0;
+}
+
+static int amvdec_h264_4k2k_remove(struct platform_device *pdev)
+{
+ cancel_work_sync(&alloc_work);
+ cancel_work_sync(&set_clk_work);
+ mutex_lock(&vh264_4k2k_mutex);
+ atomic_set(&vh264_4k2k_active, 0);
+
+ vh264_4k2k_stop();
+
+ vdec_source_changed(VFORMAT_H264_4K2K, 0, 0, 0);
+
+ if (!H264_4K2K_SINGLE_CORE) {
+ vdec_poweroff(VDEC_2);
+ }
+#ifdef DEBUG_PTS
+ pr_info("pts missed %ld, pts hit %ld, duration %d\n",
+ pts_missed, pts_hit, frame_dur);
+#endif
+
+ if (remove_callback)
+ remove_callback();
+
+ mutex_unlock(&vh264_4k2k_mutex);
+
+ kfree(gvs);
+ gvs = NULL;
+
+ pr_info("amvdec_h264_4k2k_remove\n");
+ return 0;
+}
+
+void vh264_4k2k_register_module_callback(void (*enter_func)(void),
+ void (*remove_func)(void))
+{
+ probe_callback = enter_func;
+ remove_callback = remove_func;
+}
+EXPORT_SYMBOL(vh264_4k2k_register_module_callback);
+
+/****************************************/
+
+static struct platform_driver amvdec_h264_4k2k_driver = {
+ .probe = amvdec_h264_4k2k_probe,
+ .remove = amvdec_h264_4k2k_remove,
+#ifdef CONFIG_PM
+ .suspend = amvdec_suspend,
+ .resume = amvdec_resume,
+#endif
+ .driver = {
+ .name = DRIVER_NAME,
+ }
+};
+
+static struct codec_profile_t amvdec_h264_4k2k_profile = {
+ .name = "h264_4k2k",
+ .profile = ""
+};
+static struct mconfig h264_4k2k_configs[] = {
+ MC_PU32("stat", &stat),
+ MC_PU32("error_recovery_mode", &error_recovery_mode),
+};
+static struct mconfig_node h264_4k2k_node;
+
+static int __init amvdec_h264_4k2k_driver_init_module(void)
+{
+ pr_debug("amvdec_h264_4k2k module init\n");
+
+ if (platform_driver_register(&amvdec_h264_4k2k_driver)) {
+ pr_err("failed to register amvdec_h264_4k2k driver\n");
+ return -ENODEV;
+ }
+ if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_GXTVBB)
+ vcodec_profile_register(&amvdec_h264_4k2k_profile);
+ INIT_REG_NODE_CONFIGS("media.decoder", &h264_4k2k_node,
+ "h264_4k2k", h264_4k2k_configs, CONFIG_FOR_RW);
+ return 0;
+}
+
+static void __exit amvdec_h264_4k2k_driver_remove_module(void)
+{
+ pr_debug("amvdec_h264_4k2k module remove.\n");
+
+ platform_driver_unregister(&amvdec_h264_4k2k_driver);
+}
+
+/****************************************/
+
+module_param(stat, uint, 0664);
+MODULE_PARM_DESC(stat, "\n amvdec_h264_4k2k stat\n");
+
+module_param(error_recovery_mode, uint, 0664);
+MODULE_PARM_DESC(error_recovery_mode, "\n amvdec_h264 error_recovery_mode\n");
+
+module_init(amvdec_h264_4k2k_driver_init_module);
+module_exit(amvdec_h264_4k2k_driver_remove_module);
+
+MODULE_DESCRIPTION("AMLOGIC h264_4k2k Video Decoder Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tim Yao <tim.yao@amlogic.com>");
diff --git a/drivers/frame_provider/decoder/h264/vh264_mvc.c b/drivers/frame_provider/decoder/h264/vh264_mvc.c
new file mode 100644
index 0000000..0efd1a0
--- /dev/null
+++ b/drivers/frame_provider/decoder/h264/vh264_mvc.c
@@ -0,0 +1,1888 @@
+/*
+ * 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/amlogic/tee.h>
+
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "../../../stream_input/amports/amports_priv.h"
+#include "../utils/vdec.h"
+#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 <linux/amlogic/tee.h>
+#include "../utils/config_parser.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(unsigned long arg);
+
+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;
+
+ 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;
+ vf->canvas0Addr = vf->canvas1Addr =
+ (view_mode ==
+ 0) ? spec2canvas(&buffer_spec0[view0_buf_id]) :
+ spec2canvas(&buffer_spec1[view1_buf_id]);
+ } 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) {
+ vf->canvas0Addr =
+ spec2canvas(&buffer_spec1[
+ view1_buf_id]);
+ vf->canvas1Addr =
+ spec2canvas(&buffer_spec0[
+ view0_buf_id]);
+ } else {
+ vf->canvas0Addr =
+ spec2canvas(&buffer_spec0[
+ view0_buf_id]);
+ vf->canvas1Addr =
+ spec2canvas(&buffer_spec1[
+ view1_buf_id]);
+ }
+ }
+ }
+ 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;
+ canvas_config(index, addr,
+ mb_width << 4, mb_height << 4,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+
+ addr += mb_total << 8;
+ index++;
+ buffer_spec[i].u_addr = addr;
+ buffer_spec[i].u_canvas_index = index;
+ canvas_config(index, addr, mb_width << 3, mb_height << 3,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+
+ addr += mb_total << 6;
+ index++;
+ buffer_spec[i].v_addr = addr;
+ buffer_spec[i].v_canvas_index = index;
+ canvas_config(index, addr, mb_width << 3, mb_height << 3,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+
+ 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;
+
+ 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);
+ }
+
+ 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(unsigned long arg)
+{
+ struct timer_list *timer = (struct timer_list *)arg;
+
+ 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 */
+
+ 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);
+#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");
+ init_timer(&recycle_timer);
+
+ 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.data = (ulong) (&recycle_timer);
+ recycle_timer.function = vh264mvc_put_timer_func;
+ recycle_timer.expires = jiffies + PUT_INTERVAL;
+
+ add_timer(&recycle_timer);
+
+ stat |= STAT_TIMER_ARM;
+
+ 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;
+}
+
+/****************************************/
+#ifdef CONFIG_PM
+static int h264mvc_suspend(struct device *dev)
+{
+ amvdec_suspend(to_platform_device(dev), dev->power.power_state);
+ return 0;
+}
+
+static int h264mvc_resume(struct device *dev)
+{
+ amvdec_resume(to_platform_device(dev));
+ return 0;
+}
+
+static const struct dev_pm_ops h264mvc_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(h264mvc_suspend, h264mvc_resume)
+};
+#endif
+
+static struct platform_driver amvdec_h264mvc_driver = {
+ .probe = amvdec_h264mvc_probe,
+ .remove = amvdec_h264mvc_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &h264mvc_pm_ops,
+#endif
+ }
+};
+
+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..b583a82
--- /dev/null
+++ b/drivers/frame_provider/decoder/h264_multi/h264_dpb.c
@@ -0,0 +1,6004 @@
+/*
+* 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[512];
+ int len = 0;
+ va_list args;
+
+ va_start(args, fmt);
+ len = sprintf(buf, "%d: ", index);
+ vsnprintf(buf + len, 512-len, fmt, args);
+ pr_debug("%s", buf);
+ va_end(args);
+ }
+ 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[512];
+ int len = 0;
+ va_list args;
+ va_start(args, fmt);
+ vsnprintf(buf + len, 512-len, fmt, args);
+ pr_info("%s", buf);
+ va_end(args);
+ }
+ 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);
+
+ 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 == FALSE) {
+ /* 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 == FALSE) {
+ /* 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 == FALSE)
+ 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;
+
+}
+
+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--;
+}
+
+static 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]->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) {
+#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 i;
+ struct h264_dpb_stru *p_H264_Dpb =
+ container_of(p_Dpb, struct h264_dpb_stru, mDPB);
+ if ((h264_debug_flag & PRINT_FLAG_DUMP_DPB) == 0 &&
+ force == 0)
+ return;
+ for (i = 0; i < p_Dpb->used_size; i++) {
+ dpb_print(p_H264_Dpb->decoder_index,
+ 0,
+ "(");
+ dpb_print_cont(p_H264_Dpb->decoder_index,
+ 0,
+ "fn=%d is_used %d ",
+ p_Dpb->fs[i]->frame_num,
+ p_Dpb->fs[i]->is_used);
+ if (p_Dpb->fs[i]->is_used & 1) {
+ if (p_Dpb->fs[i]->top_field)
+ dpb_print_cont(p_H264_Dpb->decoder_index,
+ 0,
+ "T: poc=%d pic_num=%d ",
+ p_Dpb->fs[i]->top_field->poc,
+ p_Dpb->fs[i]->top_field->pic_num);
+ else
+ dpb_print_cont(p_H264_Dpb->decoder_index,
+ 0,
+ "T: poc=%d ",
+ p_Dpb->fs[i]->frame->top_poc);
+ }
+ if (p_Dpb->fs[i]->is_used & 2) {
+ if (p_Dpb->fs[i]->bottom_field)
+ dpb_print_cont(p_H264_Dpb->decoder_index,
+ 0,
+ "B: poc=%d pic_num=%d ",
+ p_Dpb->fs[i]->bottom_field->poc,
+ p_Dpb->fs[i]->bottom_field->pic_num);
+ else
+ dpb_print_cont(p_H264_Dpb->decoder_index,
+ 0,
+ "B: poc=%d ",
+ p_Dpb->fs[i]->frame->bottom_poc);
+ }
+ if (p_Dpb->fs[i]->is_used == 3) {
+ if (p_Dpb->fs[i]->frame != NULL)
+ dpb_print_cont(p_H264_Dpb->decoder_index,
+ 0,
+ "F: poc=%d pic_num=%d ",
+ p_Dpb->fs[i]->frame->poc,
+ p_Dpb->fs[i]->frame->pic_num);
+ else
+ dpb_print_cont(p_H264_Dpb->decoder_index,
+ 0, "fs[%d] frame is null ", i);
+ }
+ dpb_print_cont(p_H264_Dpb->decoder_index,
+ 0,
+ "G: poc=%d) ", p_Dpb->fs[i]->poc);
+ if (p_Dpb->fs[i]->is_reference)
+ dpb_print_cont(p_H264_Dpb->decoder_index,
+ 0,
+ "ref (%d) ", p_Dpb->fs[i]->is_reference);
+ if (p_Dpb->fs[i]->is_long_term)
+ dpb_print_cont(p_H264_Dpb->decoder_index,
+ 0,
+ "lt_ref (%d) ", p_Dpb->fs[i]->is_reference);
+ if (p_Dpb->fs[i]->is_output)
+ dpb_print_cont(p_H264_Dpb->decoder_index,
+ 0,
+ "out(displayed) ");
+ if (p_Dpb->fs[i]->pre_output)
+ dpb_print_cont(p_H264_Dpb->decoder_index,
+ 0,
+ "pre_output(in dispq or displaying) ");
+ if (p_Dpb->fs[i]->is_used == 3) {
+ if (p_Dpb->fs[i]->frame != NULL && p_Dpb->fs[i]->frame->non_existing)
+ dpb_print_cont(p_H264_Dpb->decoder_index,
+ 0,
+ "non_existing ");
+ else
+ dpb_print_cont(p_H264_Dpb->decoder_index,
+ 0, "fs[%d] frame is null ", i);
+ }
+ dpb_print_cont(p_H264_Dpb->decoder_index,
+ 0,
+ "dpb_frame_count %d ",
+ p_Dpb->fs[i]->dpb_frame_count);
+
+#if (MVC_EXTENSION_ENABLE)
+ if (p_Dpb->fs[i]->is_reference)
+ dpb_print_cont(p_H264_Dpb->decoder_index,
+ 0,
+ "view_id (%d) ", p_Dpb->fs[i]->view_id);
+#endif
+ if (p_Dpb->fs[i]->data_flag) {
+ dpb_print_cont(p_H264_Dpb->decoder_index,
+ 0,
+ "data_flag(0x%x)",
+ p_Dpb->fs[i]->data_flag);
+ }
+ dpb_print_cont(p_H264_Dpb->decoder_index,
+ 0,
+ " bufspec %d\n",
+ p_Dpb->fs[i]->buf_spec_num);
+ }
+}
+
+/*!
+ ************************************************************************
+ * \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;
+ }
+ }
+ }
+ }
+}
+
+static void unmark_for_long_term_reference(struct FrameStore *fs)
+{
+ if (fs->is_used & 1) {
+ if (fs->top_field) {
+ fs->top_field->used_for_reference = 0;
+ fs->top_field->is_long_term = 0;
+ }
+ }
+ if (fs->is_used & 2) {
+ if (fs->bottom_field) {
+ fs->bottom_field->used_for_reference = 0;
+ fs->bottom_field->is_long_term = 0;
+ }
+ }
+ if (fs->is_used == 3) {
+ if (fs->top_field && fs->bottom_field) {
+ fs->top_field->used_for_reference = 0;
+ fs->top_field->is_long_term = 0;
+ fs->bottom_field->used_for_reference = 0;
+ fs->bottom_field->is_long_term = 0;
+ }
+ fs->frame->used_for_reference = 0;
+ fs->frame->is_long_term = 0;
+ }
+
+ fs->is_reference = 0;
+ fs->is_long_term = 0;
+}
+
+/*!
+ ************************************************************************
+ * \brief
+ * 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) ||
+ ((p_Dpb->size - frame_outside_count) == p_H264_Dpb->dec_dpb_size)) {
+ 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 %px (%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 = FALSE;
+
+ 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) {
+ dpb_print(p_H264_Dpb->decoder_index,
+ PRINT_FLAG_DPB_DETAIL, "p_H264_Dpb->decoder_index is null\n");
+ return -1;
+ } else {
+ 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_SKIPDONE)
+ 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..8f90961
--- /dev/null
+++ b/drivers/frame_provider/decoder/h264_multi/h264_dpb.h
@@ -0,0 +1,1001 @@
+/*
+* 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_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 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;
+};
+
+
+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);
+
+#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..368f9f7
--- /dev/null
+++ b/drivers/frame_provider/decoder/h264_multi/vmh264.c
@@ -0,0 +1,10864 @@
+/*
+ * 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 <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/amlogic/tee.h>
+#include <linux/uaccess.h>
+#include "../utils/config_parser.h"
+#include "../../../common/chips/decoder_cpu_ver_info.h"
+#include "../utils/vdec_v4l2_buffer_ops.h"
+#include <linux/crc32.h>
+#include <media/v4l2-mem2mem.h>
+
+#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 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 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.
+*/
+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
+#define DEC_RESULT_DISCARD_DATA 10
+
+
+/*
+ *static const char *dec_result_str[] = {
+ * "DEC_RESULT_NONE ",
+ * "DEC_RESULT_DONE ",
+ * "DEC_RESULT_AGAIN ",
+ * "DEC_RESULT_CONFIG_PARAM",
+ * "DEC_RESULT_GET_DATA ",
+ * "DEC_RESULT_GET_DA_RETRY",
+ * "DEC_RESULT_ERROR ",
+ *};
+ */
+
+#define UCODE_IP_ONLY 2
+#define UCODE_IP_ONLY_PARAM 1
+
+#define MC_OFFSET_HEADER 0x0000
+#define MC_OFFSET_DATA 0x1000
+#define MC_OFFSET_MMCO 0x2000
+#define MC_OFFSET_LIST 0x3000
+#define MC_OFFSET_SLICE 0x4000
+#define MC_OFFSET_MAIN 0x5000
+
+#define MC_TOTAL_SIZE ((20+16)*SZ_1K)
+#define MC_SWAP_SIZE (4*SZ_1K)
+#define MODE_ERROR 0
+#define MODE_FULL 1
+
+#define DFS_HIGH_THEASHOLD 3
+
+#define INIT_FLAG_REG AV_SCRATCH_2
+#define HEAD_PADING_REG AV_SCRATCH_3
+#define UCODE_WATCHDOG_REG AV_SCRATCH_7
+#define LMEM_DUMP_ADR AV_SCRATCH_L
+#define DEBUG_REG1 AV_SCRATCH_M
+#define DEBUG_REG2 AV_SCRATCH_N
+#define FRAME_COUNTER_REG AV_SCRATCH_I
+#define RPM_CMD_REG AV_SCRATCH_A
+#define H264_DECODE_SIZE AV_SCRATCH_E
+#define H264_DECODE_MODE AV_SCRATCH_4
+#define H264_DECODE_SEQINFO AV_SCRATCH_5
+#define H264_AUX_ADR AV_SCRATCH_C
+#define H264_AUX_DATA_SIZE AV_SCRATCH_H
+
+#define H264_DECODE_INFO M4_CONTROL_REG /* 0xc29 */
+#define DPB_STATUS_REG AV_SCRATCH_J
+#define ERROR_STATUS_REG AV_SCRATCH_9
+ /*
+ NAL_SEARCH_CTL: bit 0, enable itu_t35
+ NAL_SEARCH_CTL: bit 1, enable mmu
+ NAL_SEARCH_CTL: bit 2, detect frame_mbs_only_flag whether switch resolution
+ */
+#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 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;
+ u32 vf_get_count;
+ u32 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;
+ 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;
+ char vdec_name[32];
+ char pts_name[32];
+ char new_q_name[32];
+ char disp_q_name[32];
+ int dec_again_cnt;
+};
+
+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)
+
+static int is_oversize(int w, int h)
+{
+ int max = MAX_SIZE_4K;
+
+ 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_double_write_ratio(struct vdec_h264_hw_s *hw)
+{
+ int ratio = 1;
+ int dw_mode = hw->double_write_mode;
+ if ((dw_mode == 2) ||
+ (dw_mode == 3))
+ ratio = 4;
+ else if (dw_mode == 4)
+ ratio = 2;
+ return ratio;
+}
+
+
+static int get_dw_size(struct vdec_h264_hw_s *hw, u32 *pdw_buffer_size_u_v_h)
+{
+ int pic_width, pic_height;
+ 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);
+ int pic_height_dw = pic_height /
+ get_double_write_ratio(hw);
+
+ int pic_width_lcu_dw = (pic_width_dw % lcu_size) ?
+ pic_width_dw / lcu_size + 1 :
+ pic_width_dw / lcu_size;
+ int pic_height_lcu_dw = (pic_height_dw % lcu_size) ?
+ pic_height_dw / lcu_size + 1 :
+ pic_height_dw / lcu_size;
+ int lcu_total_dw = pic_width_lcu_dw * pic_height_lcu_dw;
+
+
+ dw_buffer_size_u_v = lcu_total_dw * lcu_size * lcu_size / 2;
+ dw_buffer_size_u_v_h = (dw_buffer_size_u_v + 0xffff) >> 16;
+ /*64k alignment*/
+ dw_buf_size = ((dw_buffer_size_u_v_h << 16) * 3);
+ *pdw_buffer_size_u_v_h = dw_buffer_size_u_v_h;
+ } else {
+ *pdw_buffer_size_u_v_h = 0;
+ dw_buf_size = 0;
+ }
+
+ return dw_buf_size;
+}
+
+
+static void hevc_mcr_config_canv2axitbl(struct vdec_h264_hw_s *hw, int restore)
+{
+ int i, size;
+ u32 canvas_addr;
+ unsigned long maddr;
+ int num_buff = hw->dpb.mDPB.size;
+ int dw_size = 0;
+ u32 dw_buffer_size_u_v_h;
+ u32 blkmode = hw->canvas_mode;
+ int dw_mode = hw->double_write_mode;
+
+ canvas_addr = ANC0_CANVAS_ADDR;
+ for (i = 0; i < num_buff; i++)
+ WRITE_VREG((canvas_addr + i), i | (i << 8) | (i << 16));
+
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, (0x1 << 1) | (0x1 << 2));
+ size = hw->losless_comp_body_size + hw->losless_comp_header_size;
+
+
+ dw_size = get_dw_size(hw, &dw_buffer_size_u_v_h);
+ size += dw_size;
+ if (size > 0)
+ size += 0x10000;
+
+ dpb_print(DECODE_ID(hw), PRINT_FLAG_MMU_DETAIL,
+ "dw_buffer_size_u_v_h = %d, dw_size = 0x%x, size = 0x%x\n",
+ dw_buffer_size_u_v_h, dw_size, size);
+
+ dpb_print(DECODE_ID(hw), PRINT_FLAG_MMU_DETAIL,
+ "body_size = %d, header_size = %d, body_size_sao = %d\n",
+ hw->losless_comp_body_size,
+ hw->losless_comp_header_size,
+ hw->losless_comp_body_size_sao);
+
+ for (i = 0; i < num_buff; i++) {
+ if (!restore) {
+ if (decoder_bmmu_box_alloc_buf_phy(hw->bmmu_box,
+ HEADER_BUFFER_IDX(i), size,
+ DRIVER_HEADER_NAME, &maddr) < 0) {
+ dpb_print(DECODE_ID(hw), 0,
+ "%s malloc compress header failed %d\n",
+ DRIVER_HEADER_NAME, i);
+ return;
+ }
+ } else
+ maddr = hw->buffer_spec[i].alloc_header_addr;
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA, maddr >> 5);
+ hw->buffer_spec[i].alloc_header_addr = maddr;
+ dpb_print(DECODE_ID(hw), PRINT_FLAG_MMU_DETAIL,
+ "%s : canvas: %d axiaddr:%x size 0x%x\n",
+ __func__, i, (u32)maddr, size);
+
+ if (dw_mode) {
+ u32 addr;
+ int canvas_w;
+ int canvas_h;
+
+ canvas_w = hw->frame_width /
+ get_double_write_ratio(hw);
+ canvas_h = hw->frame_height /
+ get_double_write_ratio(hw);
+
+ 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;
+ 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() >= 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() >= 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() < 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() < 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;
+ }
+ }
+ if (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);
+#endif
+ if (hw->buffer_spec[i].cma_alloc_addr)
+ return 0;
+
+ if (decoder_bmmu_box_alloc_buf_phy(hw->bmmu_box, i,
+ PAGE_ALIGN(buf_size), DRIVER_NAME,
+ &hw->buffer_spec[i].cma_alloc_addr) < 0) {
+ hw->buffer_spec[i].cma_alloc_addr = 0;
+ if (hw->no_mem_count++ > 3) {
+ hw->stat |= DECODER_FATAL_ERROR_NO_MEM;
+ hw->reset_bufmgr_flag = 1;
+ }
+ dpb_print(DECODE_ID(hw), 0,
+ "%s, fail to alloc buf for bufspec%d, try later\n",
+ __func__, i
+ );
+ return -1;
+ } else {
+ hw->no_mem_count = 0;
+ hw->stat &= ~DECODER_FATAL_ERROR_NO_MEM;
+ }
+ if (!vdec_secure(vdec)) {
+ /*init internal buf*/
+ char *tmpbuf = (char *)codec_mm_phys_to_virt(hw->buffer_spec[i].cma_alloc_addr);
+ if (tmpbuf) {
+ memset(tmpbuf, 0, PAGE_ALIGN(buf_size));
+ codec_mm_dma_flush(tmpbuf,
+ PAGE_ALIGN(buf_size),
+ DMA_TO_DEVICE);
+ } else {
+ tmpbuf = codec_mm_vmap(hw->buffer_spec[i].cma_alloc_addr, PAGE_ALIGN(buf_size));
+ if (tmpbuf) {
+ memset(tmpbuf, 0, PAGE_ALIGN(buf_size));
+ codec_mm_dma_flush(tmpbuf,
+ PAGE_ALIGN(buf_size),
+ DMA_TO_DEVICE);
+ codec_mm_unmap_phyaddr(tmpbuf);
+ }
+ }
+ }
+ hw->buffer_spec[i].buf_adr =
+ hw->buffer_spec[i].cma_alloc_addr;
+ addr = hw->buffer_spec[i].buf_adr;
+
+
+ hw->buffer_spec[i].y_addr = addr;
+ addr += hw->mb_total << 8;
+ hw->buffer_spec[i].u_addr = addr;
+ hw->buffer_spec[i].v_addr = addr;
+ addr += hw->mb_total << 7;
+
+ hw->buffer_spec[i].canvas_config[0].phy_addr =
+ hw->buffer_spec[i].y_addr;
+ hw->buffer_spec[i].canvas_config[0].width =
+ hw->mb_width << 4;
+ hw->buffer_spec[i].canvas_config[0].height =
+ hw->mb_height << 4;
+ hw->buffer_spec[i].canvas_config[0].block_mode =
+ hw->canvas_mode;
+
+ hw->buffer_spec[i].canvas_config[1].phy_addr =
+ hw->buffer_spec[i].u_addr;
+ hw->buffer_spec[i].canvas_config[1].width =
+ hw->mb_width << 4;
+ hw->buffer_spec[i].canvas_config[1].height =
+ hw->mb_height << 3;
+ hw->buffer_spec[i].canvas_config[1].block_mode =
+ hw->canvas_mode;
+ dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS,
+ "%s, alloc buf for bufspec%d\n",
+ __func__, i
+ );
+#ifdef VDEC_DW
+
+ if (!IS_VDEC_DW(hw))
+ return 0;
+ else if (IS_VDEC_DW(hw) == 1) {
+ addr = hw->buffer_spec[i].cma_alloc_addr + orig_buf_size;
+ hw->buffer_spec[i].vdec_dw_y_addr = addr;
+ addr += hw->mb_total << 7;
+ hw->buffer_spec[i].vdec_dw_u_addr = addr;
+ hw->buffer_spec[i].vdec_dw_v_addr = addr;
+ addr += hw->mb_total << 6;
+
+ hw->buffer_spec[i].vdec_dw_canvas_config[0].phy_addr =
+ hw->buffer_spec[i].vdec_dw_y_addr;
+ hw->buffer_spec[i].vdec_dw_canvas_config[0].width =
+ hw->mb_width << 3;
+ hw->buffer_spec[i].vdec_dw_canvas_config[0].height =
+ hw->mb_height << 4;
+ hw->buffer_spec[i].vdec_dw_canvas_config[0].block_mode =
+ CANVAS_BLKMODE_32X32;
+
+ hw->buffer_spec[i].vdec_dw_canvas_config[1].phy_addr =
+ hw->buffer_spec[i].vdec_dw_u_addr;
+ hw->buffer_spec[i].vdec_dw_canvas_config[1].width =
+ hw->mb_width << 3;
+ hw->buffer_spec[i].vdec_dw_canvas_config[1].height =
+ hw->mb_height << 3;
+ hw->buffer_spec[i].vdec_dw_canvas_config[1].block_mode =
+ CANVAS_BLKMODE_32X32;
+ }else {
+ addr = hw->buffer_spec[i].cma_alloc_addr + orig_buf_size;
+ hw->buffer_spec[i].vdec_dw_y_addr = addr;
+ addr += hw->mb_total << 6;
+ hw->buffer_spec[i].vdec_dw_u_addr = addr;
+ hw->buffer_spec[i].vdec_dw_v_addr = addr;
+ addr += hw->mb_total << 5;
+
+ hw->buffer_spec[i].vdec_dw_canvas_config[0].phy_addr =
+ hw->buffer_spec[i].vdec_dw_y_addr;
+ hw->buffer_spec[i].vdec_dw_canvas_config[0].width =
+ hw->mb_width << 3;
+ hw->buffer_spec[i].vdec_dw_canvas_config[0].height =
+ hw->mb_height << 3;
+ hw->buffer_spec[i].vdec_dw_canvas_config[0].block_mode =
+ CANVAS_BLKMODE_32X32;
+
+ hw->buffer_spec[i].vdec_dw_canvas_config[1].phy_addr =
+ hw->buffer_spec[i].vdec_dw_u_addr;
+ hw->buffer_spec[i].vdec_dw_canvas_config[1].width =
+ hw->mb_width << 3;
+ hw->buffer_spec[i].vdec_dw_canvas_config[1].height =
+ hw->mb_height << 2;
+ hw->buffer_spec[i].vdec_dw_canvas_config[1].block_mode =
+ CANVAS_BLKMODE_32X32;
+ }
+ dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS,
+ "%s, vdec_dw: alloc buf for bufspec%d\n",
+ __func__, i
+ );
+#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 = vdec_v4l_get_buffer(hw->v4l2_ctx, &fb);
+ 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%lx, 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;
+ }
+
+ 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;
+
+ canvas_config_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);
+
+ 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*/
+ );
+ }
+
+ canvas_config_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);
+
+ 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 if (IS_VDEC_DW(hw) == 1) {
+ canvas_config_ex(hw->buffer_spec[i].
+ vdec_dw_y_canvas_index,
+ hw->buffer_spec[i].vdec_dw_y_addr,
+ hw->mb_width << 3,
+ hw->mb_height << 4,
+ CANVAS_ADDR_NOWRAP,
+ blkmode,
+ endian);
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) {
+ WRITE_VREG(VDEC_ASSIST_CANVAS_BLK32,
+ (1 << 11) |
+ (blkmode << 10) |
+ (1 << 8) |
+ (hw->buffer_spec[i].vdec_dw_y_canvas_index << 0));
+ }
+ canvas_config_ex(hw->buffer_spec[i].
+ vdec_dw_u_canvas_index,
+ hw->buffer_spec[i].vdec_dw_u_addr,
+ hw->mb_width << 3,
+ hw->mb_height << 3,
+ CANVAS_ADDR_NOWRAP,
+ blkmode,
+ endian);
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) {
+ WRITE_VREG(VDEC_ASSIST_CANVAS_BLK32,
+ (1 << 11) |
+ (blkmode << 10) |
+ (1 << 8) |
+ (hw->buffer_spec[i].vdec_dw_u_canvas_index << 0));
+ }
+ } else {
+ canvas_config_ex(hw->buffer_spec[i].
+ vdec_dw_y_canvas_index,
+ hw->buffer_spec[i].vdec_dw_y_addr,
+ hw->mb_width << 3,
+ hw->mb_height << 3,
+ CANVAS_ADDR_NOWRAP,
+ blkmode,
+ endian);
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) {
+ WRITE_VREG(VDEC_ASSIST_CANVAS_BLK32,
+ (1 << 11) |
+ (blkmode << 10) |
+ (1 << 8) |
+ (hw->buffer_spec[i].vdec_dw_y_canvas_index << 0));
+ }
+
+ canvas_config_ex(hw->buffer_spec[i].
+ vdec_dw_u_canvas_index,
+ hw->buffer_spec[i].vdec_dw_u_addr,
+ hw->mb_width << 3,
+ hw->mb_height << 2,
+ CANVAS_ADDR_NOWRAP,
+ blkmode,
+ endian);
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) {
+ WRITE_VREG(VDEC_ASSIST_CANVAS_BLK32,
+ (1 << 11) |
+ (blkmode << 10) |
+ (1 << 8) |
+ (hw->buffer_spec[i].vdec_dw_u_canvas_index << 0));
+ }
+ }
+#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);
+ canvas_h = hw->frame_height /
+ get_double_write_ratio(hw);
+
+ if (hw->canvas_mode == 0)
+ canvas_w = ALIGN(canvas_w, 32);
+ else
+ canvas_w = ALIGN(canvas_w, 64);
+ canvas_h = ALIGN(canvas_h, 32);
+
+ canvas_config_ex(hw->buffer_spec[i].
+ y_canvas_index,
+ hw->buffer_spec[i].dw_y_adr,
+ canvas_w,
+ canvas_h,
+ CANVAS_ADDR_NOWRAP,
+ blkmode,
+ 7);
+
+ canvas_config_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);
+}
+
+
+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, 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:
+ pr_err("v4l buffer state err %d.\n", state);
+ 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\n", __func__);
+ 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);
+ }
+
+ 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 * v4l = 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;
+
+ 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 (v4l->cap_pool.dec < hw->dpb.mDPB.size &&
+ v4l2_m2m_num_dst_bufs_ready(v4l->m2m_ctx)
+ >= run_ready_min_buf_num)
+ 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 ((dec_control & DEC_CONTROL_FLAG_FORCE_2997_1080P_INTERLACE)
+ && hw->bitstream_restriction_flag
+ && (hw->frame_width == 1920)
+ && (hw->frame_height >= 1080) /* For being compatible with a fake progressive stream which is interlaced actually*/
+ && (hw->frame_dur == 3203 || (hw->frame_dur == 3840 && p_H264_Dpb->mSPS.profile_idc == 100 &&
+ p_H264_Dpb->mSPS.level_idc == 40))) {
+ bForceInterlace = 1;
+ } else if ((dec_control & DEC_CONTROL_FLAG_FORCE_2500_576P_INTERLACE)
+ && (hw->frame_width == 720)
+ && (hw->frame_height == 576)
+ && (hw->frame_dur == 3840)) {
+ bForceInterlace = 1;
+ }
+ if ((frame->frame) && (hw->is_used_v4l) && (bForceInterlace == 0)) {
+ bForceInterlace = (frame->frame->mb_aff_frame_flag)?1:0;
+ }
+ return bForceInterlace;
+}
+
+static void fill_frame_info(struct vdec_h264_hw_s *hw, struct FrameStore *frame)
+{
+ struct vframe_qos_s *vframe_qos = &hw->vframe_qos;
+
+ if (frame->slice_type == I_SLICE)
+ vframe_qos->type = 1;
+ else if (frame->slice_type == P_SLICE)
+ vframe_qos->type = 2;
+ else if (frame->slice_type == B_SLICE)
+ vframe_qos->type = 3;
+
+ if (input_frame_based(hw_to_vdec(hw)))
+ vframe_qos->size = frame->frame_size2;
+ else
+ vframe_qos->size = frame->frame_size;
+ vframe_qos->pts = frame->pts64;
+
+ vframe_qos->max_mv = frame->max_mv;
+ vframe_qos->avg_mv = frame->avg_mv;
+ vframe_qos->min_mv = frame->min_mv;
+/*
+ pr_info("mv: max:%d, avg:%d, min:%d\n",
+ vframe_qos->max_mv,
+ vframe_qos->avg_mv,
+ vframe_qos->min_mv);
+*/
+
+ vframe_qos->max_qp = frame->max_qp;
+ vframe_qos->avg_qp = frame->avg_qp;
+ vframe_qos->min_qp = frame->min_qp;
+/*
+ pr_info("qp: max:%d, avg:%d, min:%d\n",
+ vframe_qos->max_qp,
+ vframe_qos->avg_qp,
+ vframe_qos->min_qp);
+*/
+
+ vframe_qos->max_skip = frame->max_skip;
+ vframe_qos->avg_skip = frame->avg_skip;
+ vframe_qos->min_skip = frame->min_skip;
+/*
+ pr_info("skip: max:%d, avg:%d, min:%d\n",
+ vframe_qos->max_skip,
+ vframe_qos->avg_skip,
+ vframe_qos->min_skip);
+*/
+ vframe_qos->num++;
+}
+
+static int is_iframe(struct FrameStore *frame) {
+
+ if (frame->frame && frame->frame->slice_type == I_SLICE) {
+ return 1;
+ }
+ return 0;
+}
+
+static int post_prepare_process(struct vdec_s *vdec, struct FrameStore *frame)
+{
+ struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private;
+ int buffer_index = frame->buf_spec_num;
+
+ if (buffer_index < 0 || buffer_index >= BUFSPEC_POOL_SIZE) {
+ dpb_print(DECODE_ID(hw), 0,
+ "%s, buffer_index 0x%x is beyond range\n",
+ __func__, buffer_index);
+ return -1;
+ }
+
+ if (force_disp_bufspec_num & 0x100) {
+ /*recycle directly*/
+ if (hw->buffer_spec[frame->buf_spec_num].used != 3 &&
+ hw->buffer_spec[frame->buf_spec_num].used != 5)
+ set_frame_output_flag(&hw->dpb, frame->index);
+
+ /*make pre_output not set*/
+ return -1;
+ }
+ if (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 ((frame->data_flag & NODISP_FLAG) ||
+ (frame->data_flag & NULL_FLAG) ||
+ ((!hw->send_error_frame_flag) &&
+ (frame->data_flag & ERROR_FLAG)) ||
+ ((hw->i_only & 0x1) &&
+ (!(frame->data_flag & I_FLAG)))) {
+ set_frame_output_flag(&hw->dpb, frame->index);
+ frame->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;
+ 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->is_used_v4l)
+ vf_count = 1;
+ if (!hw->enable_fence)
+ hw->buffer_spec[buffer_index].vf_ref = 0;
+ fill_frame_info(hw, frame);
+
+ 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;
+ }
+
+ 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 (IS_VDEC_DW(hw))
+ vf->canvas0Addr = vf->canvas1Addr =
+ vdec_dw_spec2canvas(&hw->buffer_spec[buffer_index]);
+#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);
+ vf->height = hw->frame_height /
+ get_double_write_ratio(hw);
+ }
+
+ 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;
+ }
+ }
+
+ if (i == 0) {
+ struct vdec_s *pvdec;
+ struct vdec_info vs;
+
+ pvdec = hw_to_vdec(hw);
+ memset(&vs, 0, sizeof(struct vdec_info));
+ pvdec->dec_status(pvdec, &vs);
+ decoder_do_frame_check(pvdec, vf);
+ vdec_fill_vdec_frame(pvdec, &hw->vframe_qos, &vs, vf, frame->hw_decode_time);
+
+ dpb_print(DECODE_ID(hw), PRINT_FLAG_DPB_DETAIL,
+ "[%s:%d] i_decoded_frame = %d p_decoded_frame = %d b_decoded_frame = %d\n",
+ __func__, __LINE__,vs.i_decoded_frames,vs.p_decoded_frames,vs.b_decoded_frames);
+ }
+
+ /*vf->ratio_control |= (0x3FF << DISP_RATIO_ASPECT_RATIO_BIT);*/
+ vf->sar_width = hw->width_aspect_ratio;
+ vf->sar_height = hw->height_aspect_ratio;
+ 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;
+ }
+ }
+ vdec_vframe_ready(hw_to_vdec(hw), vf);
+ kfifo_put(&hw->display_q, (const struct vframe_s *)vf);
+ ATRACE_COUNTER(hw->pts_name, vf->pts);
+ ATRACE_COUNTER(hw->disp_q_name, kfifo_len(&hw->display_q));
+ ATRACE_COUNTER(hw->new_q_name, kfifo_len(&hw->newframe_q));
+ hw->vf_pre_count++;
+ vdec->vdec_fps_detec(vdec->id);
+#ifdef AUX_DATA_CRC
+ decoder_do_aux_data_check(vdec, hw->buffer_spec[buffer_index].aux_data_buf,
+ hw->buffer_spec[buffer_index].aux_data_size);
+#endif
+ if (hw->is_used_v4l)
+ update_vframe_src_fmt(vf,
+ hw->buffer_spec[buffer_index].aux_data_buf,
+ hw->buffer_spec[buffer_index].aux_data_size,
+ false, vdec->vf_provider_name, NULL);
+
+ if (without_display_mode == 0) {
+ vf_notify_receiver(vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
+ } 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;
+ }
+
+ 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) {
+ 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);
+ return 0;
+ }
+
+ if (post_prepare_process(vdec, frame))
+ return -1;
+
+ if (!frame->show_frame)
+ return 0;
+
+ 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) {
+ if (vdec_v4l_get_buffer(hw->v4l2_ctx, &fb) < 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;
+
+ vdec_vframe_ready(vdec, vf);
+ kfifo_put(&hw->display_q, (const struct vframe_s *)vf);
+ ATRACE_COUNTER(hw->pts_name, vf->pts);
+ vf_notify_receiver(vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
+
+ 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_DEC_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_DEC_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");
+ }
+ }
+}
+
+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 (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
+ 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)));
+#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;
+ 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;
+#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;
+ }
+#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_adr_offset) >> 3) |
+ (l10_structure << 30) |
+ (cur_colocate_ref_type << 29);
+ WRITE_VREG(H264_CO_MB_RD_ADDR, val);
+ dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL,
+ "co idx %d, WRITE_VREG(H264_CO_MB_RD_ADDR) = %x, addr %x L1(0) pic_structure %d mbaff %d\n",
+ colocate_pic->colocated_buf_index,
+ val, colocate_rd_adr + colocate_adr_offset,
+ 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_adr_offset)>>3) |
+ (l10_structure << 30) | (cur_colocate_ref_type << 29);
+ WRITE_VREG(H264_CO_MB_RD_ADDR, val);
+ dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL,
+ "WRITE_VREG(H264_CO_MB_RD_ADDR) = %x, L1(0) pic_structure %d mbaff %d\n",
+ val, colocate_pic->structure,
+ colocate_pic->mb_aff_frame_flag);
+#endif
+ }
+ return ret;
+}
+
+static int vh264_vf_states(struct vframe_states *states, void *op_arg)
+{
+ unsigned long flags;
+ struct vdec_s *vdec = op_arg;
+ struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private;
+
+ spin_lock_irqsave(&hw->lock, flags);
+
+ states->vf_pool_size = VF_POOL_SIZE;
+ states->buf_free_num = kfifo_len(&hw->newframe_q);
+ states->buf_avail_num = kfifo_len(&hw->display_q);
+
+ spin_unlock_irqrestore(&hw->lock, flags);
+
+ return 0;
+}
+
+static struct vframe_s *vh264_vf_peek(void *op_arg)
+{
+ struct vframe_s *vf[2] = {0, 0};
+ struct vdec_s *vdec = op_arg;
+ struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private;
+
+ if (!hw)
+ return NULL;
+
+ if (force_disp_bufspec_num & 0x100) {
+ if (force_disp_bufspec_num & 0x200)
+ return NULL;
+ return &hw->vframe_dummy;
+ }
+
+ if (kfifo_out_peek(&hw->display_q, (void *)&vf, 2)) {
+ if (vf[1]) {
+ vf[0]->next_vf_pts_valid = true;
+ vf[0]->next_vf_pts = vf[1]->pts;
+ } else
+ vf[0]->next_vf_pts_valid = false;
+ return vf[0];
+ }
+
+ return NULL;
+}
+
+static struct vframe_s *vh264_vf_get(void *op_arg)
+{
+ struct vframe_s *vf;
+ struct vdec_s *vdec = op_arg;
+ struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private;
+ struct aml_vcodec_ctx * v4l2_ctx;
+ ulong nv_order = VIDTYPE_VIU_NV21;
+
+ if (!hw)
+ return NULL;
+
+ v4l2_ctx = hw->v4l2_ctx;
+
+ /* swap uv */
+ if (hw->is_used_v4l) {
+ if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12) ||
+ (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);
+ vf->height = hw->frame_height /
+ get_double_write_ratio(hw);
+ }
+ } 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->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\n",
+ __func__, BUFSPEC_INDEX(vf->index), vf,
+ p_H264_Dpb->mFrameStore[frame_index].poc,
+ vf->duration, vf->pts, frame_interval);
+ }
+ }
+ 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 = hw->vf_get_count;
+ 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;
+ }
+
+ 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__);
+
+ }
+
+ hw->vf_put_count++;
+ if (vf_valid_check(vf, hw) == true) {
+ kfifo_put(&hw->newframe_q, (const struct vframe_s *)vf);
+ ATRACE_COUNTER(hw->new_q_name, kfifo_len(&hw->newframe_q));
+ }
+
+#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 = 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;
+
+ 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)) {
+ vf->width = (hw->frame_width /2);
+ if (IS_VDEC_DW(hw) == 2)
+ vf->height = (hw->frame_height /2);
+ 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 += 1; /* need one more buffer */
+
+ return 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;
+
+#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)\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;
+
+ if (seq_info2 != 0 &&
+ hw->seq_info2 != seq_info2 &&
+ hw->seq_info2 != 0
+ ) /*picture size changed*/
+ h264_reconfig(hw);
+
+ 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 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) {
+ 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)))) {
+ bufmgr_h264_remove_unused_frame(p_H264_Dpb, 0);
+
+ for (i = 0; i < p_Dpb->used_size; i++) {
+ if (p_Dpb->fs[i]->pre_output)
+ frame_outside_count++;
+ }
+
+ 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);
+ }
+ }
+ }
+ } 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;
+ else 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)
+ 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) {
+ 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;
+}
+
+#ifdef VDEC_FCC_SUPPORT
+static void fcc_discard_mode_process(struct vdec_s *vdec)
+{
+ struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)(vdec->private);
+ struct h264_dpb_stru *p_H264_Dpb = &hw->dpb;
+
+ if (vdec->fcc_status == AGAIN_STATUS) {
+ vdec->stream_offset = (p_H264_Dpb->dpb_param.l.data[OFFSET_DELIMITER_LO] |
+ p_H264_Dpb->dpb_param.l.data[OFFSET_DELIMITER_HI] << 16);
+ dpb_print(DECODE_ID(hw), PRINT_FLAG_FCC_STATUS,
+ "[%d][FCC]: Notify stream_offset: %d\n",
+ vdec->id, vdec->stream_offset);
+ vdec_wakeup_fcc_poll(vdec);
+ amvdec_stop();
+ vdec->mc_loaded = 0;
+ hw->init_flag = 0;
+ vdec->fcc_status = WAIT_MSG_STATUS;
+ hw->dec_result = DEC_RESULT_AGAIN;
+ vdec_schedule_work(&hw->work);
+ } else if (vdec->fcc_status == DISCARD_STATUS) {
+ dpb_print(DECODE_ID(hw), PRINT_FLAG_FCC_STATUS,
+ "[%d][FCC]: Discard current gop and to find next gop!\n",
+ vdec->id);
+ amvdec_stop();
+ vdec->mc_loaded = 0;
+ hw->init_flag = 0;
+ vdec->fcc_status = AGAIN_STATUS;
+ hw->dec_result = DEC_RESULT_DISCARD_DATA;
+ vdec_schedule_work(&hw->work);
+ }
+}
+
+static int vh264_fcc_process(struct vdec_s *vdec)
+{
+ struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)(vdec->private);
+
+ if (input_stream_based(vdec)) {
+ switch (vdec->fcc_mode) {
+ case FCC_DISCARD_MODE:
+ fcc_discard_mode_process(vdec);
+ return 1;
+ case FCC_DEC_MODE:
+ dpb_print(DECODE_ID(hw), PRINT_FLAG_FCC_STATUS,
+ "[%d][FCC]: Current is Dec mode.\n", vdec->id);
+ break;
+ case FCC_BUTT:
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+static irqreturn_t vh264_isr_thread_fn(struct vdec_s *vdec, int irq)
+{
+ int i;
+ 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_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");
+ }
+ }
+ }
+
+ 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(DECODE_ID(hw), 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
+
+#ifdef VDEC_FCC_SUPPORT
+ if (vh264_fcc_process(vdec) > 0)
+ return IRQ_HANDLED;
+#endif
+
+ WRITE_VREG(DPB_STATUS_REG, H264_ACTION_CONFIG_DONE);
+ reset_process_time(hw);
+ hw->reg_iqidct_control = READ_VREG(IQIDCT_CONTROL);
+ 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
+ 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;
+ reset_process_time(hw);
+
+#ifdef DETECT_WRONG_MULTI_SLICE
+ hw->cur_picture_slice_count++;
+ if (hw->multi_slice_pic_flag == 1 &&
+ hw->cur_picture_slice_count == 1 &&
+ (error_proc_policy & 0x10000)) {
+ hw->first_pre_frame_num = p_H264_Dpb->mVideo.pre_frame_num;
+ }
+ if (hw->multi_slice_pic_flag == 1 &&
+ hw->cur_picture_slice_count > 1 &&
+ (error_proc_policy & 0x10000)) {
+ 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);
+
+ first_mb_in_slice = p[FIRST_MB_IN_SLICE + 3];
+ mby_mbx = READ_VREG(MBY_MBX);
+ decode_mb_count = ((mby_mbx & 0xff) * mb_width +
+ (((mby_mbx >> 8) & 0xff) + 1));
+
+ 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);
+ 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;
+ 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");
+ }
+ }
+ }
+#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;
+ 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) {
+ 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) {
+ 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;
+ }
+ }
+
+ cfg_ret = config_decode_buf(hw,
+ p_H264_Dpb->mVideo.dec_picture);
+ 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;
+ }
+ }
+
+ 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);
+ 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
+
+ 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_DPB_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__);
+ 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)
+ 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",
+ __func__, p_H264_Dpb->last_dpb_status);
+ hw->reset_bufmgr_flag = 1;
+ }
+ }
+ } else if (dec_dpb_status == H264_DECODE_BUFEMPTY)
+ hw->decode_dataempty_num++;
+ if (!hw->frmbase_cont_flag)
+ hw->data_flag |= ERROR_FLAG;
+
+ vdec_schedule_work(&hw->work);
+ } else {
+ /* WRITE_VREG(DPB_STATUS_REG, H264_ACTION_INIT); */
+#ifdef DETECT_WRONG_MULTI_SLICE
+ if (hw->multi_slice_pic_flag == 1 &&
+ hw->cur_picture_slice_count > 1 &&
+ (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);
+ }
+ }
+ 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);
+
+ 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;
+ }
+ 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\n", __func__);
+ 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 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->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 (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(unsigned long arg)
+{
+ struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)arg;
+ 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)) {
+ 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;
+
+ /* 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 (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 */
+ init_timer(&hw->check_timer);
+
+ hw->check_timer.data = (unsigned long)hw;
+ hw->check_timer.function = check_timer_func;
+ hw->check_timer.expires = jiffies + CHECK_INTERVAL;
+
+ /* 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 = vzalloc(SEI_DATA_SIZE);
+ if (hw->sei_data_buf == NULL) {
+ pr_err("%s: failed to alloc sei itu data buffer\n",
+ __func__);
+ return -1;
+ }
+ hw->sei_itu_data_buf = vzalloc(SEI_ITU_DATA_SIZE);
+ 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;
+ vfree(hw->sei_data_buf);
+ hw->sei_data_buf = NULL;
+
+ return -1;
+ }
+
+ if (NULL == hw->sei_user_data_buffer) {
+ hw->sei_user_data_buffer = vzalloc(USER_DATA_SIZE);
+ 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;
+ vfree(hw->sei_data_buf);
+ hw->sei_data_buf = NULL;
+ vfree(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);
+#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) {
+ vfree(hw->sei_data_buf);
+ hw->sei_data_buf = NULL;
+ }
+ if (hw->sei_itu_data_buf != NULL) {
+ vfree(hw->sei_itu_data_buf);
+ hw->sei_itu_data_buf = NULL;
+ }
+ if (hw->sei_user_data_buffer != NULL) {
+ vfree(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 (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 = vzalloc(MAX_USER_DATA_SIZE);
+ if (user_data_buf)
+ return 1;
+ else
+ return 0;
+}
+
+static void vmh264_dump_userdata(void)
+{
+ if (user_data_buf) {
+ show_user_data_buf();
+ vfree(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)\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;
+ }
+
+ 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
+ */
+ 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->reorder_frames = dec_dpb_size + 1; /* +1 for two frames in one packet */
+ ps->dpb_size = active_buffer_spec_num;
+ ps->field = frame_mbs_only_flag ? V4L2_FIELD_NONE : V4L2_FIELD_INTERLACED;
+
+ return 0;
+}
+
+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;
+
+ if (ctx->param_sets_from_ucode &&
+ hw->res_ch_flag == 0) {
+ if (param1 != 0 &&
+ hw->seq_info2 != param1 &&
+ hw->seq_info2 != 0) /*picture size changed*/ {
+ struct aml_vdec_ps_infos ps;
+ dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL,
+ "h264 res_change\n");
+ if (vmh264_get_ps_info(hw, param1,
+ param2, param3, param4, &ps) < 0) {
+ dpb_print(DECODE_ID(hw), 0,
+ "set parameters error\n");
+ }
+ hw->v4l_params_parsed = false;
+ vdec_v4l_set_ps_infos(ctx, &ps);
+ vdec_v4l_res_ch_event(ctx);
+ hw->res_ch_flag = 1;
+ ctx->v4l_resolution_change = 1;
+ amvdec_stop();
+ if (hw->mmu_enable)
+ amhevc_stop();
+ hw->eos = 1;
+ flush_dpb(p_H264_Dpb);
+ //del_timer_sync(&hw->check_timer);
+ if (hw->is_used_v4l)
+ 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
+ */
+ 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 ? ((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();
+ if (!vdec_is_support_4k()) {
+ if (clk_adj_frame_count < VDEC_CLOCK_ADJUST_FRAME) {
+ clk_adj_frame_count++;
+ if (clk_adj_frame_count == VDEC_CLOCK_ADJUST_FRAME) {
+ if (hw->frame_height <= 144)
+ vdec_source_changed(VFORMAT_H264, 1920, 1080, 29);
+ else
+ vdec_source_changed(VFORMAT_H264, 3840, 2160, 60);
+ }
+ }
+ }
+ dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS,
+ "%s dec_result %d %x %x %x\n",
+ __func__,
+ 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->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->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;
+ }
+ } else if (hw->dec_result == DEC_RESULT_DISCARD_DATA) {
+ mutex_lock(&hw->chunks_mutex);
+ vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk);
+ hw->chunk = NULL;
+ mutex_unlock(&hw->chunks_mutex);
+ }
+ 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
+ wait_vmh264_search_done(hw);
+ /* 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;
+ }
+ }
+
+ /* 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);
+
+}
+
+#ifdef VDEC_FCC_SUPPORT
+static void vmh264_wakeup_fcc_poll(struct vdec_s *vdec)
+{
+ amstream_wakeup_fcc_poll(vdec);
+}
+#endif
+
+static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask)
+{
+ bool ret = 0;
+ 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;
+#ifdef VDEC_FCC_SUPPORT
+ int get_msg = 1;
+#endif
+
+ 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 (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;
+ }
+#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->v4l_codec_dpb_ready &&
+ v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) <
+ run_ready_min_buf_num)
+ ret = 0;
+ else if (ctx->v4l_codec_dpb_ready &&
+ !is_buffer_available(vdec))
+ ret = 0;
+ } 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;
+ }
+
+ }
+
+#ifdef VDEC_FCC_SUPPORT
+ get_msg = vdec_has_get_fcc_new_msg(vdec);
+ ret &= get_msg;
+#endif
+
+ if (ret)
+ not_run_ready[DECODE_ID(hw)] = 0;
+ else
+ not_run_ready[DECODE_ID(hw)]++;
+
+ if (vdec->parallel_dec == 1) {
+ if (hw->mmu_enable == 0)
+ return ret ? (CORE_MASK_VDEC_1) : 0;
+ 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();
+ }
+ 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);
+ 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;
+#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 {
+
+ 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;
+ }
+ vmh264_reset_udr_mgr(hw);
+
+ if (vh264_hw_ctx_restore(hw) < 0) {
+ vdec_schedule_work(&hw->work);
+ return;
+ }
+ 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));
+ if (udebug_flag)
+ WRITE_VREG(AV_SCRATCH_K, udebug_flag);
+ mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL);
+
+ if (get_cpu_major_id() >= 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;
+}
+
+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;
+ }
+ 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);
+
+ /* Only the caller from inside decoder we call flush_dbp */
+ if (!hw->reset_bufmgr_flag)
+ flush_dpb(&hw->dpb);
+
+ 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->vdec_name, sizeof(hw->vdec_name),
+ "h264-%d", hw->id);
+ snprintf(hw->pts_name, sizeof(hw->pts_name),
+ "%s-pts", hw->vdec_name);
+ snprintf(hw->new_q_name, sizeof(hw->new_q_name),
+ "%s-newframe_q", hw->vdec_name);
+ snprintf(hw->disp_q_name, sizeof(hw->disp_q_name),
+ "%s-dispframe_q", hw->vdec_name);
+
+ /* 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) {
+ /*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");
+ }
+ } 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->enable_fence)
+ pdata->sync.usage = hw->fence_usage;
+
+ if (!hw->is_used_v4l) {
+ hw->reorder_dpb_size_margin = reorder_dpb_size_margin;
+ hw->canvas_mode = mem_map_mode;
+
+ 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
+
+#ifdef VDEC_FCC_SUPPORT
+ pdata->wakeup_fcc_poll = vmh264_wakeup_fcc_poll;
+#endif
+
+ if (pdata->use_vfm_path) {
+ snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE,
+ VFM_DEC_PROVIDER_NAME);
+ hw->frameinfo_enable = 1;
+ }
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ else if (vdec_dual(pdata)) {
+ if (dv_toggle_prov_name) /*debug purpose*/
+ snprintf(pdata->vf_provider_name,
+ VDEC_PROVIDER_NAME_SIZE,
+ (pdata->master) ? VFM_DEC_DVBL_PROVIDER_NAME :
+ VFM_DEC_DVEL_PROVIDER_NAME);
+ else
+ snprintf(pdata->vf_provider_name,
+ VDEC_PROVIDER_NAME_SIZE,
+ (pdata->master) ? VFM_DEC_DVEL_PROVIDER_NAME :
+ VFM_DEC_DVBL_PROVIDER_NAME);
+ }
+#endif
+ else
+ snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE,
+ PROVIDER_NAME ".%02x", pdev->id & 0xff);
+
+ vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name,
+ &vf_provider_ops, pdata);
+
+ 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() >= 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);
+
+ if (vdec_is_support_4k() ||
+ (clk_adj_frame_count > (VDEC_CLOCK_ADJUST_FRAME - 1)))
+ vdec_source_changed(VFORMAT_H264, 3840, 2160, 60);
+ else if (pdata->sys_info->height * pdata->sys_info->width < 1280 * 720)
+ {
+ vdec_source_changed(VFORMAT_H264, 1280, 720, 29);
+ } else if (pdata->sys_info->height * pdata->sys_info->width < 1920 * 1080)
+ {
+ vdec_source_changed(VFORMAT_H264, 1920, 1080, 29);
+ } else
+ {
+ vdec_source_changed(VFORMAT_H264, 3840, 2160, 60);
+ }
+ 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;
+
+ if (hw->enable_fence) {
+ /* 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;
+ int i;
+
+ /* 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;
+ }
+ }
+
+ for (i = 0; i < VF_POOL_SIZE; i++) {
+ struct vframe_s *vf = &hw->vfpool[hw->cur_pool][i];
+
+ if (vf->fence) {
+ vdec_fence_put(vf->fence);
+ vf->fence = NULL;
+ }
+ }
+
+ /* 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;
+}
+
+/****************************************/
+#ifdef CONFIG_PM
+static int mh264_suspend(struct device *dev)
+{
+ amvdec_suspend(to_platform_device(dev), dev->power.power_state);
+ return 0;
+}
+
+static int mh264_resume(struct device *dev)
+{
+ amvdec_resume(to_platform_device(dev));
+ return 0;
+}
+
+static const struct dev_pm_ops mh264_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mh264_suspend, mh264_resume)
+};
+#endif
+
+static struct platform_driver ammvdec_h264_driver = {
+ .probe = ammvdec_h264_probe,
+ .remove = ammvdec_h264_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &mh264_pm_ops,
+#endif
+ }
+};
+
+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";
+ } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXTVBB) {
+ ammvdec_h264_profile.profile = "4k, frame_dv, fence";
+ }
+ }
+
+ vcodec_profile_register(&ammvdec_h264_profile);
+ INIT_REG_NODE_CONFIGS("media.decoder", &hm264_node,
+ "mh264", hm264_configs, CONFIG_FOR_RW);
+ 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(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..2224f37
--- /dev/null
+++ b/drivers/frame_provider/decoder/h265/vh265.c
@@ -0,0 +1,15200 @@
+/*
+ * 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/amlogic/tee.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 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 (0x1200*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_SAO_MMU_VH1_ADDR 0x363b
+#define HEVC_SAO_MMU_VH0_ADDR 0x363a
+
+#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>
+
+#define SEND_LMEM_WITH_RPM
+#define SUPPORT_10BIT
+/* #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 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(unsigned long arg);
+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 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
+ * 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;
+static u32 endian = 0xff0;
+#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;
+ 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)
+
+#define WORK_BUF_SPEC_NUM 3
+static struct BuffInfo_s amvh265_workbuff_spec[WORK_BUF_SPEC_NUM] = {
+ {
+ /* 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
+ .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
+ .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,
+ },
+ .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*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, //0x8000*2,
+ },
+ .dblk_para = {.buf_size = 0x32100, }, // dblk parameter
+ .dblk_data = {.buf_size = 0x110800, }, // dblk data for left/top
+ .dblk_data2 = {.buf_size = 0x90800, }, // dblk data for adapter
+ .mmu_vbh = {
+ .buf_size = VBH_BUF_SIZE_8K, //2*16*2304/4, 4K
+ },
+#if 0
+ .cm_header = {
+ .buf_size = MMU_COMPRESS_HEADER_SIZE_8K *
+ MAX_REF_PIC_NUM, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8)
+ },
+#endif
+ .mpred_above = {
+ .buf_size = 0x8000,
+ },
+#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,
+ },
+ }
+};
+
+static void init_buff_spec(struct hevc_state_s *hevc,
+ struct BuffInfo_s *buf_spec)
+{
+ buf_spec->ipp.buf_start = buf_spec->start_adr;
+ buf_spec->sao_abv.buf_start =
+ buf_spec->ipp.buf_start + buf_spec->ipp.buf_size;
+
+ buf_spec->sao_vb.buf_start =
+ buf_spec->sao_abv.buf_start + buf_spec->sao_abv.buf_size;
+ buf_spec->short_term_rps.buf_start =
+ buf_spec->sao_vb.buf_start + buf_spec->sao_vb.buf_size;
+ buf_spec->vps.buf_start =
+ buf_spec->short_term_rps.buf_start +
+ buf_spec->short_term_rps.buf_size;
+ buf_spec->sps.buf_start =
+ buf_spec->vps.buf_start + buf_spec->vps.buf_size;
+ buf_spec->pps.buf_start =
+ buf_spec->sps.buf_start + buf_spec->sps.buf_size;
+ buf_spec->sao_up.buf_start =
+ buf_spec->pps.buf_start + buf_spec->pps.buf_size;
+ buf_spec->swap_buf.buf_start =
+ buf_spec->sao_up.buf_start + buf_spec->sao_up.buf_size;
+ buf_spec->swap_buf2.buf_start =
+ buf_spec->swap_buf.buf_start + buf_spec->swap_buf.buf_size;
+ buf_spec->scalelut.buf_start =
+ buf_spec->swap_buf2.buf_start + buf_spec->swap_buf2.buf_size;
+ buf_spec->dblk_para.buf_start =
+ buf_spec->scalelut.buf_start + buf_spec->scalelut.buf_size;
+ buf_spec->dblk_data.buf_start =
+ buf_spec->dblk_para.buf_start + buf_spec->dblk_para.buf_size;
+ buf_spec->dblk_data2.buf_start =
+ buf_spec->dblk_data.buf_start + buf_spec->dblk_data.buf_size;
+ buf_spec->mmu_vbh.buf_start =
+ buf_spec->dblk_data2.buf_start + buf_spec->dblk_data2.buf_size;
+ buf_spec->mpred_above.buf_start =
+ buf_spec->mmu_vbh.buf_start + buf_spec->mmu_vbh.buf_size;
+#ifdef MV_USE_FIXED_BUF
+ buf_spec->mpred_mv.buf_start =
+ buf_spec->mpred_above.buf_start +
+ buf_spec->mpred_above.buf_size;
+
+ buf_spec->rpm.buf_start =
+ buf_spec->mpred_mv.buf_start +
+ buf_spec->mpred_mv.buf_size;
+#else
+ buf_spec->rpm.buf_start =
+ buf_spec->mpred_above.buf_start +
+ buf_spec->mpred_above.buf_size;
+#endif
+ buf_spec->lmem.buf_start =
+ buf_spec->rpm.buf_start +
+ buf_spec->rpm.buf_size;
+ buf_spec->end_adr =
+ buf_spec->lmem.buf_start +
+ buf_spec->lmem.buf_size;
+
+ if (hevc && get_dbg_flag2(hevc)) {
+ hevc_print(hevc, 0,
+ "%s workspace (%x %x) size = %x\n", __func__,
+ buf_spec->start_adr, buf_spec->end_adr,
+ buf_spec->end_adr - buf_spec->start_adr);
+
+ hevc_print(hevc, 0,
+ "ipp.buf_start :%x\n",
+ buf_spec->ipp.buf_start);
+ hevc_print(hevc, 0,
+ "sao_abv.buf_start :%x\n",
+ buf_spec->sao_abv.buf_start);
+ hevc_print(hevc, 0,
+ "sao_vb.buf_start :%x\n",
+ buf_spec->sao_vb.buf_start);
+ hevc_print(hevc, 0,
+ "short_term_rps.buf_start :%x\n",
+ buf_spec->short_term_rps.buf_start);
+ hevc_print(hevc, 0,
+ "vps.buf_start :%x\n",
+ buf_spec->vps.buf_start);
+ hevc_print(hevc, 0,
+ "sps.buf_start :%x\n",
+ buf_spec->sps.buf_start);
+ hevc_print(hevc, 0,
+ "pps.buf_start :%x\n",
+ buf_spec->pps.buf_start);
+ hevc_print(hevc, 0,
+ "sao_up.buf_start :%x\n",
+ buf_spec->sao_up.buf_start);
+ hevc_print(hevc, 0,
+ "swap_buf.buf_start :%x\n",
+ buf_spec->swap_buf.buf_start);
+ hevc_print(hevc, 0,
+ "swap_buf2.buf_start :%x\n",
+ buf_spec->swap_buf2.buf_start);
+ hevc_print(hevc, 0,
+ "scalelut.buf_start :%x\n",
+ buf_spec->scalelut.buf_start);
+ hevc_print(hevc, 0,
+ "dblk_para.buf_start :%x\n",
+ buf_spec->dblk_para.buf_start);
+ hevc_print(hevc, 0,
+ "dblk_data.buf_start :%x\n",
+ buf_spec->dblk_data.buf_start);
+ hevc_print(hevc, 0,
+ "dblk_data2.buf_start :%x\n",
+ buf_spec->dblk_data2.buf_start);
+ hevc_print(hevc, 0,
+ "mpred_above.buf_start :%x\n",
+ buf_spec->mpred_above.buf_start);
+#ifdef MV_USE_FIXED_BUF
+ hevc_print(hevc, 0,
+ "mpred_mv.buf_start :%x\n",
+ buf_spec->mpred_mv.buf_start);
+#endif
+ if ((get_dbg_flag2(hevc)
+ &
+ H265_DEBUG_SEND_PARAM_WITH_REG)
+ == 0) {
+ hevc_print(hevc, 0,
+ "rpm.buf_start :%x\n",
+ buf_spec->rpm.buf_start);
+ }
+ }
+
+}
+
+enum SliceType {
+ B_SLICE,
+ P_SLICE,
+ I_SLICE
+};
+
+/*USE_BUF_BLOCK*/
+struct BUF_s {
+ ulong start_adr;
+ u32 size;
+ u32 luma_size;
+ ulong header_addr;
+ u32 header_size;
+ int used_flag;
+ ulong v4l_ref_buf_addr;
+ ulong chroma_addr;
+ u32 chroma_size;
+} /*BUF_t */;
+
+/* level 6, 6.1 maximum slice number is 800; other is 200 */
+#define MAX_SLICE_NUM 800
+struct PIC_s {
+ int index;
+ int scatter_alloc;
+ int BUF_index;
+ int mv_buf_index;
+ int POC;
+ int decode_idx;
+ int slice_type;
+ int RefNum_L0;
+ int RefNum_L1;
+ int num_reorder_pic;
+ int stream_offset;
+ unsigned char referenced;
+ unsigned char output_mark;
+ unsigned char recon_mark;
+ unsigned char output_ready;
+ unsigned char error_mark;
+ //dis_mark = 0:discard mark,dis_mark = 1:no discard mark
+ unsigned char dis_mark;
+ /**/ int slice_idx;
+ int m_aiRefPOCList0[MAX_SLICE_NUM][16];
+ int m_aiRefPOCList1[MAX_SLICE_NUM][16];
+#ifdef SUPPORT_LONG_TERM_RPS
+ unsigned char long_term_ref;
+ unsigned char m_aiRefLTflgList0[MAX_SLICE_NUM][16];
+ unsigned char m_aiRefLTflgList1[MAX_SLICE_NUM][16];
+#endif
+ /*buffer */
+ unsigned int header_adr;
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ unsigned char dv_enhance_exist;
+#endif
+ char *aux_data_buf;
+ int aux_data_size;
+ unsigned long cma_alloc_addr;
+ struct page *alloc_pages;
+ unsigned int mpred_mv_wr_start_addr;
+ int mv_size;
+ unsigned int mc_y_adr;
+ unsigned int mc_u_v_adr;
+#ifdef SUPPORT_10BIT
+ /*unsigned int comp_body_size;*/
+ unsigned int dw_y_adr;
+ unsigned int dw_u_v_adr;
+#endif
+ int mc_canvas_y;
+ int mc_canvas_u_v;
+ int width;
+ int height;
+
+ int y_canvas_index;
+ int uv_canvas_index;
+#ifdef MULTI_INSTANCE_SUPPORT
+ struct canvas_config_s canvas_config[2];
+#endif
+#ifdef SUPPORT_10BIT
+ int mem_saving_mode;
+ u32 bit_depth_luma;
+ u32 bit_depth_chroma;
+#endif
+#ifdef LOSLESS_COMPRESS_MODE
+ unsigned int losless_comp_body_size;
+#endif
+ unsigned char pic_struct;
+ int vf_ref;
+
+ u32 pts;
+ u64 pts64;
+ u64 timestamp;
+
+ u32 aspect_ratio_idc;
+ u32 sar_width;
+ u32 sar_height;
+ u32 double_write_mode;
+ u32 video_signal_type;
+ 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;
+
+ /* 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
+ bool vframe_bound;
+ bool ip_mode;
+ u32 hdr10p_data_size;
+ char *hdr10p_data_buf;
+ struct fence *fence;
+ bool show_frame;
+} /*PIC_t */;
+
+#define MAX_TILE_COL_NUM 10
+#define MAX_TILE_ROW_NUM 20
+struct tile_s {
+ int width;
+ int height;
+ int start_cu_x;
+ int start_cu_y;
+
+ unsigned int sao_vb_start_addr;
+ unsigned int sao_abv_start_addr;
+};
+
+#define SEI_MASTER_DISPLAY_COLOR_MASK 0x00000001
+#define SEI_CONTENT_LIGHT_LEVEL_MASK 0x00000002
+#define SEI_HDR10PLUS_MASK 0x00000004
+
+#define VF_POOL_SIZE 32
+
+#ifdef MULTI_INSTANCE_SUPPORT
+#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
+#define DEC_RESULT_FREE_CANVAS 11
+#define DEC_RESULT_DISCARD_DATA 12
+
+
+static void vh265_work(struct work_struct *work);
+static void vh265_timeout_work(struct work_struct *work);
+static void vh265_notify_work(struct work_struct *work);
+
+#endif
+
+struct debug_log_s {
+ struct list_head list;
+ uint8_t data; /*will alloc more size*/
+};
+
+struct hevc_state_s {
+#ifdef MULTI_INSTANCE_SUPPORT
+ struct platform_device *platform_dev;
+ void (*vdec_cb)(struct vdec_s *, void *);
+ void *vdec_cb_arg;
+ struct vframe_chunk_s *chunk;
+ int dec_result;
+ u32 timeout_processing;
+ struct work_struct work;
+ struct work_struct timeout_work;
+ struct work_struct notify_work;
+ struct work_struct set_clk_work;
+ /* timeout handle */
+ unsigned long int start_process_time;
+ unsigned int last_lcu_idx;
+ unsigned int decode_timeout_count;
+ unsigned int timeout_num;
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ unsigned char switch_dvlayer_flag;
+ unsigned char no_switch_dvlayer_count;
+ unsigned char bypass_dvenl_enable;
+ unsigned char bypass_dvenl;
+#endif
+ unsigned char start_parser_type;
+ /*start_decoding_flag:
+ vps/pps/sps/idr info from ucode*/
+ unsigned char start_decoding_flag;
+ unsigned char rps_set_id;
+ unsigned char eos;
+ int pic_decoded_lcu_idx;
+ u8 over_decode;
+ u8 empty_flag;
+#endif
+ struct vframe_s vframe_dummy;
+ char *provider_name;
+ int index;
+ struct device *cma_dev;
+ unsigned char m_ins_flag;
+ unsigned char dolby_enhance_flag;
+ unsigned long buf_start;
+ u32 buf_size;
+ u32 mv_buf_size;
+
+ struct BuffInfo_s work_space_buf_store;
+ struct BuffInfo_s *work_space_buf;
+
+ u8 aux_data_dirty;
+ u32 prefix_aux_size;
+ u32 suffix_aux_size;
+ void *aux_addr;
+ void *rpm_addr;
+ void *lmem_addr;
+ dma_addr_t aux_phy_addr;
+ dma_addr_t rpm_phy_addr;
+ dma_addr_t lmem_phy_addr;
+
+ unsigned int pic_list_init_flag;
+ unsigned int use_cma_flag;
+
+ unsigned short *rpm_ptr;
+ unsigned short *lmem_ptr;
+ unsigned short *debug_ptr;
+ int debug_ptr_size;
+ int pic_w;
+ int pic_h;
+ int lcu_x_num;
+ int lcu_y_num;
+ int lcu_total;
+ int lcu_size;
+ int lcu_size_log2;
+ int lcu_x_num_pre;
+ int lcu_y_num_pre;
+ int first_pic_after_recover;
+
+ int num_tile_col;
+ int num_tile_row;
+ int tile_enabled;
+ int tile_x;
+ int tile_y;
+ int tile_y_x;
+ int tile_start_lcu_x;
+ int tile_start_lcu_y;
+ int tile_width_lcu;
+ int tile_height_lcu;
+
+ int slice_type;
+ unsigned int slice_addr;
+ unsigned int slice_segment_addr;
+
+ unsigned char interlace_flag;
+ unsigned char curr_pic_struct;
+ unsigned char frame_field_info_present_flag;
+
+ unsigned short sps_num_reorder_pics_0;
+ unsigned short misc_flag0;
+ int m_temporalId;
+ int m_nalUnitType;
+ int TMVPFlag;
+ int isNextSliceSegment;
+ int LDCFlag;
+ int m_pocRandomAccess;
+ int plevel;
+ int MaxNumMergeCand;
+
+ int new_pic;
+ int new_tile;
+ int curr_POC;
+ int iPrevPOC;
+#ifdef MULTI_INSTANCE_SUPPORT
+ int decoded_poc;
+ struct PIC_s *decoding_pic;
+#endif
+ int iPrevTid0POC;
+ int list_no;
+ int RefNum_L0;
+ int RefNum_L1;
+ int ColFromL0Flag;
+ int LongTerm_Curr;
+ int LongTerm_Col;
+ int Col_POC;
+ int LongTerm_Ref;
+#ifdef MULTI_INSTANCE_SUPPORT
+ int m_pocRandomAccess_bak;
+ int curr_POC_bak;
+ int iPrevPOC_bak;
+ int iPrevTid0POC_bak;
+ unsigned char start_parser_type_bak;
+ unsigned char start_decoding_flag_bak;
+ unsigned char rps_set_id_bak;
+ int pic_decoded_lcu_idx_bak;
+ int decode_idx_bak;
+#endif
+ struct PIC_s *cur_pic;
+ struct PIC_s *col_pic;
+ int skip_flag;
+ int decode_idx;
+ int slice_idx;
+ unsigned char have_vps;
+ unsigned char have_sps;
+ unsigned char have_pps;
+ unsigned char have_valid_start_slice;
+ unsigned char wait_buf;
+ unsigned char error_flag;
+ unsigned int error_skip_nal_count;
+ long used_4k_num;
+
+ unsigned char
+ ignore_bufmgr_error; /* bit 0, for decoding;
+ bit 1, for displaying
+ bit 1 must be set if bit 0 is 1*/
+ int PB_skip_mode;
+ int PB_skip_count_after_decoding;
+#ifdef SUPPORT_10BIT
+ int mem_saving_mode;
+#endif
+#ifdef LOSLESS_COMPRESS_MODE
+ unsigned int losless_comp_body_size;
+#endif
+ int pts_mode;
+ int last_lookup_pts;
+ int last_pts;
+ u64 last_lookup_pts_us64;
+ u64 last_pts_us64;
+ u32 shift_byte_count_lo;
+ u32 shift_byte_count_hi;
+ int pts_mode_switching_count;
+ int pts_mode_recovery_count;
+
+ int pic_num;
+
+ /**/
+ union param_u param;
+
+ struct tile_s m_tile[MAX_TILE_ROW_NUM][MAX_TILE_COL_NUM];
+
+ struct timer_list timer;
+ struct BUF_s m_BUF[BUF_POOL_SIZE];
+ struct BUF_s m_mv_BUF[MAX_REF_PIC_NUM];
+ struct PIC_s *m_PIC[MAX_REF_PIC_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 stat;
+ u32 frame_width;
+ u32 frame_height;
+ u32 frame_dur;
+ u32 frame_ar;
+ u32 bit_depth_luma;
+ u32 bit_depth_chroma;
+ u32 video_signal_type;
+ u32 video_signal_type_debug;
+ u32 saved_resolution;
+ bool get_frame_dur;
+ u32 error_watchdog_count;
+ u32 error_skip_nal_wt_cnt;
+ u32 error_system_watchdog_count;
+
+#ifdef DEBUG_PTS
+ unsigned long pts_missed;
+ unsigned long pts_hit;
+#endif
+ struct dec_sysinfo vh265_amstream_dec_info;
+ unsigned char init_flag;
+ unsigned char first_sc_checked;
+ unsigned char uninit_list;
+ u32 start_decoding_time;
+
+ int show_frame_num;
+#ifdef USE_UNINIT_SEMA
+ struct semaphore h265_uninit_done_sema;
+#endif
+ int fatal_error;
+
+
+ u32 sei_present_flag;
+ void *frame_mmu_map_addr;
+ dma_addr_t frame_mmu_map_phy_addr;
+ unsigned int mmu_mc_buf_start;
+ unsigned int mmu_mc_buf_end;
+ unsigned int mmu_mc_start_4k_adr;
+ void *mmu_box;
+ void *bmmu_box;
+ int mmu_enable;
+
+ unsigned int dec_status;
+
+ /* data for SEI_MASTER_DISPLAY_COLOR */
+ unsigned int primaries[3][2];
+ unsigned int white_point[2];
+ unsigned int luminance[2];
+ /* data for SEI_CONTENT_LIGHT_LEVEL */
+ unsigned int content_light_level[2];
+
+ struct PIC_s *pre_top_pic;
+ struct PIC_s *pre_bot_pic;
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ int double_write_mode;
+ int dynamic_buf_num_margin;
+ int start_action;
+ int save_buffer_mode;
+#endif
+ u32 i_only;
+ struct list_head log_list;
+ u32 ucode_pause_pos;
+ u32 start_shift_bytes;
+
+ u32 vf_pre_count;
+ u32 vf_get_count;
+ u32 vf_put_count;
+#ifdef SWAP_HEVC_UCODE
+ dma_addr_t mc_dma_handle;
+ void *mc_cpu_addr;
+ int swap_size;
+ ulong swap_addr;
+#endif
+#ifdef DETREFILL_ENABLE
+ dma_addr_t detbuf_adr;
+ u16 *detbuf_adr_virt;
+ u8 delrefill_check;
+#endif
+ u8 head_error_flag;
+ int valve_count;
+ struct firmware_s *fw;
+ int max_pic_w;
+ int max_pic_h;
+#ifdef AGAIN_HAS_THRESHOLD
+ u8 next_again_flag;
+ u32 pre_parser_wr_ptr;
+#endif
+ u32 ratio_control;
+ u32 first_pic_flag;
+ u32 decode_size;
+ struct mutex chunks_mutex;
+ int need_cache_size;
+ u64 sc_start_time;
+ u32 skip_nal_count;
+ bool is_swap;
+ bool is_4k;
+ int frameinfo_enable;
+ struct vframe_qos_s vframe_qos;
+ bool is_used_v4l;
+ void *v4l2_ctx;
+ bool v4l_params_parsed;
+ u32 mem_map_mode;
+ u32 performance_profile;
+ struct vdec_info *gvs;
+ u32 res_ch_flag;
+ bool ip_mode;
+ u32 kpi_first_i_comming;
+ u32 kpi_first_i_decoded;
+ int sidebind_type;
+ int sidebind_channel_id;
+ u32 pre_parser_video_rp;
+ u32 pre_parser_video_wp;
+ bool dv_duallayer;
+ u32 poc_error_count;
+ u32 timeout_flag;
+ ulong timeout;
+ bool discard_dv_data;
+ bool enable_fence;
+ int fence_usage;
+ int low_latency_flag;
+ u32 dirty_shift_flag;
+ char vdec_name[32];
+ char set_canvas0_addr[32];
+ char get_canvas0_addr[32];
+ char put_canvas0_addr[32];
+ char vf_put_name[32];
+ char vf_get_name[32];
+ char new_q_name[32];
+ char disp_q_name[32];
+ char pts_name[32];
+ int dec_again_cnt;
+} /*hevc_stru_t */;
+
+#ifdef AGAIN_HAS_THRESHOLD
+static u32 again_threshold;
+#endif
+#ifdef SEND_LMEM_WITH_RPM
+#define get_lmem_params(hevc, ladr) \
+ hevc->lmem_ptr[ladr - (ladr & 0x3) + 3 - (ladr & 0x3)]
+
+
+static int get_frame_mmu_map_size(void)
+{
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1)
+ return (MAX_FRAME_8K_NUM * 4);
+
+ return (MAX_FRAME_4K_NUM * 4);
+}
+
+static int is_oversize(int w, int h)
+{
+ int max = (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1)?
+ MAX_SIZE_8K : MAX_SIZE_4K;
+
+ if (w < 0 || h < 0)
+ return true;
+
+ if (h != 0 && (w > max / h))
+ return true;
+
+ return false;
+}
+
+int is_oversize_ex(int w, int h)
+{
+ int max = (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) ?
+ MAX_SIZE_8K : MAX_SIZE_4K;
+
+ if (w == 0 || h == 0)
+ return true;
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) {
+ if (w > 8192 || h > 4608)
+ return true;
+ } else {
+ if (w > 4096 || h > 2304)
+ return true;
+ }
+
+ if (w < 0 || h < 0)
+ return true;
+
+ if (h != 0 && (w > max / h))
+ return true;
+
+ return false;
+}
+
+
+void check_head_error(struct hevc_state_s *hevc)
+{
+#define pcm_enabled_flag 0x040
+#define pcm_sample_bit_depth_luma 0x041
+#define pcm_sample_bit_depth_chroma 0x042
+ hevc->head_error_flag = 0;
+ if ((error_handle_policy & 0x40) == 0)
+ return;
+ if (get_lmem_params(hevc, pcm_enabled_flag)) {
+ uint16_t pcm_depth_luma = get_lmem_params(
+ hevc, pcm_sample_bit_depth_luma);
+ uint16_t pcm_sample_chroma = get_lmem_params(
+ hevc, pcm_sample_bit_depth_chroma);
+ if (pcm_depth_luma >
+ hevc->bit_depth_luma ||
+ pcm_sample_chroma >
+ hevc->bit_depth_chroma) {
+ hevc_print(hevc, 0,
+ "error, pcm bit depth %d, %d is greater than normal bit depth %d, %d\n",
+ pcm_depth_luma,
+ pcm_sample_chroma,
+ hevc->bit_depth_luma,
+ hevc->bit_depth_chroma);
+ hevc->head_error_flag = 1;
+ }
+ }
+}
+#endif
+
+#ifdef SUPPORT_10BIT
+/* Losless compression body buffer size 4K per 64x32 (jt) */
+static int compute_losless_comp_body_size(struct hevc_state_s *hevc,
+ int width, int height, int mem_saving_mode)
+{
+ int width_x64;
+ int height_x32;
+ int bsize;
+
+ width_x64 = width + 63;
+ width_x64 >>= 6;
+
+ height_x32 = height + 31;
+ height_x32 >>= 5;
+ if (mem_saving_mode == 1 && hevc->mmu_enable)
+ bsize = 3200 * width_x64 * height_x32;
+ else if (mem_saving_mode == 1)
+ bsize = 3072 * width_x64 * height_x32;
+ else
+ bsize = 4096 * width_x64 * height_x32;
+
+ return bsize;
+}
+
+/* Losless compression header buffer size 32bytes per 128x64 (jt) */
+static int compute_losless_comp_header_size(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;
+
+ return hsize;
+}
+#endif
+
+static int add_log(struct hevc_state_s *hevc,
+ const char *fmt, ...)
+{
+#define HEVC_LOG_BUF 196
+ struct debug_log_s *log_item;
+ unsigned char buf[HEVC_LOG_BUF];
+ int len = 0;
+ va_list args;
+ mutex_lock(&vh265_log_mutex);
+ va_start(args, fmt);
+ len = sprintf(buf, "<%ld> <%05d> ",
+ jiffies, hevc->decode_idx);
+ len += vsnprintf(buf + len,
+ HEVC_LOG_BUF - len, fmt, args);
+ va_end(args);
+ log_item = kmalloc(
+ sizeof(struct debug_log_s) + len,
+ GFP_KERNEL);
+ if (log_item) {
+ INIT_LIST_HEAD(&log_item->list);
+ strcpy(&log_item->data, buf);
+ list_add_tail(&log_item->list,
+ &hevc->log_list);
+ }
+ mutex_unlock(&vh265_log_mutex);
+ return 0;
+}
+
+static void dump_log(struct hevc_state_s *hevc)
+{
+ int i = 0;
+ struct debug_log_s *log_item, *tmp;
+ mutex_lock(&vh265_log_mutex);
+ list_for_each_entry_safe(log_item, tmp, &hevc->log_list, list) {
+ hevc_print(hevc, 0,
+ "[LOG%04d]%s\n",
+ i++,
+ &log_item->data);
+ list_del(&log_item->list);
+ kfree(log_item);
+ }
+ mutex_unlock(&vh265_log_mutex);
+}
+
+static unsigned char is_skip_decoding(struct hevc_state_s *hevc,
+ struct PIC_s *pic)
+{
+ if (pic->error_mark
+ && ((hevc->ignore_bufmgr_error & 0x1) == 0))
+ return 1;
+ return 0;
+}
+
+static int get_pic_poc(struct hevc_state_s *hevc,
+ unsigned int idx)
+{
+ if (idx != 0xff
+ && idx < MAX_REF_PIC_NUM
+ && hevc->m_PIC[idx])
+ return hevc->m_PIC[idx]->POC;
+ return INVALID_POC;
+}
+
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+static int get_valid_double_write_mode(struct hevc_state_s *hevc)
+{
+ return (hevc->m_ins_flag &&
+ ((double_write_mode & 0x80000000) == 0)) ?
+ hevc->double_write_mode :
+ (double_write_mode & 0x7fffffff);
+}
+
+static int get_dynamic_buf_num_margin(struct hevc_state_s *hevc)
+{
+ return (hevc->m_ins_flag &&
+ ((dynamic_buf_num_margin & 0x80000000) == 0)) ?
+ hevc->dynamic_buf_num_margin :
+ (dynamic_buf_num_margin & 0x7fffffff);
+}
+#endif
+
+static int get_double_write_mode(struct hevc_state_s *hevc)
+{
+ u32 valid_dw_mode = get_valid_double_write_mode(hevc);
+ int w = hevc->pic_w;
+ int h = hevc->pic_h;
+ u32 dw = 0x1; /*1:1*/
+ switch (valid_dw_mode) {
+ case 0x100:
+ if (w > 1920 && h > 1088)
+ dw = 0x4; /*1:2*/
+ break;
+ case 0x200:
+ if (w > 1920 && h > 1088)
+ dw = 0x2; /*1:4*/
+ break;
+ case 0x300:
+ if (w > 1280 && h > 720)
+ dw = 0x4; /*1:2*/
+ break;
+ default:
+ dw = valid_dw_mode;
+ break;
+ }
+ return dw;
+}
+
+static int v4l_parser_get_double_write_mode(struct hevc_state_s *hevc, int w, int h)
+{
+ u32 valid_dw_mode = get_valid_double_write_mode(hevc);
+ u32 dw = 0x1; /*1:1*/
+ 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;
+ case 0x1000:
+ if (w * h > 1920 * 1080)
+ dw = 3;
+ else if (w * h > 960 * 540)
+ dw = 5;
+ else
+ dw = 1;
+ break;
+ default:
+ dw = valid_dw_mode;
+ break;
+ }
+ return dw;
+}
+
+
+static int get_double_write_ratio(struct hevc_state_s *hevc,
+ int dw_mode)
+{
+ int ratio = 1;
+ if ((dw_mode == 2) ||
+ (dw_mode == 3))
+ ratio = 4;
+ else if ((dw_mode == 4) ||
+ (dw_mode == 5))
+ ratio = 2;
+ return ratio;
+}
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+static unsigned char get_idx(struct hevc_state_s *hevc)
+{
+ return hevc->index;
+}
+#endif
+
+#undef pr_info
+#define pr_info printk
+static int hevc_print(struct hevc_state_s *hevc,
+ int flag, const char *fmt, ...)
+{
+#define HEVC_PRINT_BUF 256
+ unsigned char buf[HEVC_PRINT_BUF];
+ int len = 0;
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ if (hevc == NULL ||
+ (flag == 0) ||
+ ((debug_mask &
+ (1 << hevc->index))
+ && (debug & flag))) {
+#endif
+ va_list args;
+
+ va_start(args, fmt);
+ if (hevc)
+ len = sprintf(buf, "[%d]", hevc->index);
+ vsnprintf(buf + len, HEVC_PRINT_BUF - len, fmt, args);
+ pr_debug("%s", buf);
+ va_end(args);
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ }
+#endif
+ return 0;
+}
+
+static int hevc_print_cont(struct hevc_state_s *hevc,
+ int flag, const char *fmt, ...)
+{
+ unsigned char buf[HEVC_PRINT_BUF];
+ int len = 0;
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ if (hevc == NULL ||
+ (flag == 0) ||
+ ((debug_mask &
+ (1 << hevc->index))
+ && (debug & flag))) {
+#endif
+ va_list args;
+
+ va_start(args, fmt);
+ vsnprintf(buf + len, HEVC_PRINT_BUF - len, fmt, args);
+ pr_info("%s", buf);
+ va_end(args);
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ }
+#endif
+ return 0;
+}
+
+static void put_mv_buf(struct hevc_state_s *hevc,
+ struct PIC_s *pic);
+
+static void update_vf_memhandle(struct hevc_state_s *hevc,
+ struct vframe_s *vf, struct PIC_s *pic);
+
+static void set_canvas(struct hevc_state_s *hevc, struct PIC_s *pic);
+
+static void release_aux_data(struct hevc_state_s *hevc,
+ struct PIC_s *pic);
+static void release_pic_mmu_buf(struct hevc_state_s *hevc, struct PIC_s *pic);
+
+#ifdef MULTI_INSTANCE_SUPPORT
+static void backup_decode_state(struct hevc_state_s *hevc)
+{
+ hevc->m_pocRandomAccess_bak = hevc->m_pocRandomAccess;
+ hevc->curr_POC_bak = hevc->curr_POC;
+ hevc->iPrevPOC_bak = hevc->iPrevPOC;
+ hevc->iPrevTid0POC_bak = hevc->iPrevTid0POC;
+ hevc->start_parser_type_bak = hevc->start_parser_type;
+ hevc->start_decoding_flag_bak = hevc->start_decoding_flag;
+ hevc->rps_set_id_bak = hevc->rps_set_id;
+ hevc->pic_decoded_lcu_idx_bak = hevc->pic_decoded_lcu_idx;
+ hevc->decode_idx_bak = hevc->decode_idx;
+
+}
+
+static void restore_decode_state(struct hevc_state_s *hevc)
+{
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+ if (!vdec_has_more_input(vdec)) {
+ hevc->pic_decoded_lcu_idx =
+ READ_VREG(HEVC_PARSER_LCU_START)
+ & 0xffffff;
+ return;
+ }
+ hevc_print(hevc, PRINT_FLAG_VDEC_STATUS,
+ "%s: discard pic index 0x%x\n",
+ __func__, hevc->decoding_pic ?
+ hevc->decoding_pic->index : 0xff);
+ if (hevc->decoding_pic) {
+ hevc->decoding_pic->error_mark = 0;
+ hevc->decoding_pic->output_ready = 0;
+ hevc->decoding_pic->show_frame = false;
+ hevc->decoding_pic->output_mark = 0;
+ hevc->decoding_pic->referenced = 0;
+ hevc->decoding_pic->POC = INVALID_POC;
+ put_mv_buf(hevc, hevc->decoding_pic);
+ release_aux_data(hevc, hevc->decoding_pic);
+ hevc->decoding_pic = NULL;
+ }
+ if (vdec_stream_based(vdec) &&
+ (hevc->decode_idx - hevc->decode_idx_bak > 1)) {
+ int i;
+ hevc_print(hevc, 0, "decode_idx %d, decode_idx_bak %d\n",
+ hevc->decode_idx, hevc->decode_idx_bak);
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ struct PIC_s *pic;
+ pic = hevc->m_PIC[i];
+ if (pic == NULL ||
+ (pic->index == -1) ||
+ (pic->BUF_index == -1) ||
+ (pic->POC == INVALID_POC))
+ continue;
+ if ((pic->decode_idx >= hevc->decode_idx_bak) &&
+ pic->decode_idx != (hevc->decode_idx - 1)) {
+ hevc_print(hevc, 0, "release error buffer\n");
+ pic->error_mark = 0;
+ pic->output_ready = 0;
+ pic->show_frame = false;
+ pic->output_mark = 0;
+ pic->referenced = 0;
+ pic->POC = INVALID_POC;
+ put_mv_buf(hevc, pic);
+ release_aux_data(hevc, pic);
+ }
+ }
+ }
+ hevc->decode_idx = hevc->decode_idx_bak;
+ hevc->m_pocRandomAccess = hevc->m_pocRandomAccess_bak;
+ hevc->curr_POC = hevc->curr_POC_bak;
+ hevc->iPrevPOC = hevc->iPrevPOC_bak;
+ hevc->iPrevTid0POC = hevc->iPrevTid0POC_bak;
+ hevc->start_parser_type = hevc->start_parser_type_bak;
+ hevc->start_decoding_flag = hevc->start_decoding_flag_bak;
+ hevc->rps_set_id = hevc->rps_set_id_bak;
+ hevc->pic_decoded_lcu_idx = hevc->pic_decoded_lcu_idx_bak;
+
+ if (hevc->pic_list_init_flag == 1)
+ hevc->pic_list_init_flag = 0;
+ /*if (hevc->decode_idx == 0)
+ hevc->start_decoding_flag = 0;*/
+
+ hevc->slice_idx = 0;
+ hevc->used_4k_num = -1;
+}
+#endif
+
+static void hevc_init_stru(struct hevc_state_s *hevc,
+ struct BuffInfo_s *buf_spec_i)
+{
+ int i;
+ INIT_LIST_HEAD(&hevc->log_list);
+ hevc->work_space_buf = buf_spec_i;
+ hevc->prefix_aux_size = 0;
+ hevc->suffix_aux_size = 0;
+ hevc->aux_addr = NULL;
+ hevc->rpm_addr = NULL;
+ hevc->lmem_addr = NULL;
+
+ hevc->curr_POC = INVALID_POC;
+
+ hevc->pic_list_init_flag = 0;
+ hevc->use_cma_flag = 0;
+ hevc->decode_idx = 0;
+ hevc->slice_idx = 0;
+ hevc->new_pic = 0;
+ hevc->new_tile = 0;
+ hevc->iPrevPOC = 0;
+ hevc->list_no = 0;
+ /* int m_uiMaxCUWidth = 1<<7; */
+ /* int m_uiMaxCUHeight = 1<<7; */
+ hevc->m_pocRandomAccess = MAX_INT;
+ hevc->tile_enabled = 0;
+ hevc->tile_x = 0;
+ hevc->tile_y = 0;
+ hevc->iPrevTid0POC = 0;
+ hevc->slice_addr = 0;
+ hevc->slice_segment_addr = 0;
+ hevc->skip_flag = 0;
+ hevc->misc_flag0 = 0;
+
+ hevc->cur_pic = NULL;
+ hevc->col_pic = NULL;
+ hevc->wait_buf = 0;
+ hevc->error_flag = 0;
+ hevc->head_error_flag = 0;
+ hevc->error_skip_nal_count = 0;
+ hevc->have_vps = 0;
+ hevc->have_sps = 0;
+ hevc->have_pps = 0;
+ hevc->have_valid_start_slice = 0;
+
+ hevc->pts_mode = PTS_NORMAL;
+ hevc->last_pts = 0;
+ hevc->last_lookup_pts = 0;
+ hevc->last_pts_us64 = 0;
+ hevc->last_lookup_pts_us64 = 0;
+ hevc->pts_mode_switching_count = 0;
+ hevc->pts_mode_recovery_count = 0;
+
+ hevc->PB_skip_mode = nal_skip_policy & 0x3;
+ hevc->PB_skip_count_after_decoding = (nal_skip_policy >> 16) & 0xffff;
+ if (hevc->PB_skip_mode == 0)
+ hevc->ignore_bufmgr_error = 0x1;
+ else
+ hevc->ignore_bufmgr_error = 0x0;
+
+ if (hevc->is_used_v4l) {
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ if (hevc->m_PIC[i] != NULL) {
+ memset(hevc->m_PIC[i], 0 ,sizeof(struct PIC_s));
+ hevc->m_PIC[i]->index = i;
+ }
+ }
+ }
+
+ hevc->pic_num = 0;
+ hevc->lcu_x_num_pre = 0;
+ hevc->lcu_y_num_pre = 0;
+ hevc->first_pic_after_recover = 0;
+
+ hevc->pre_top_pic = NULL;
+ hevc->pre_bot_pic = NULL;
+
+ hevc->sei_present_flag = 0;
+ hevc->valve_count = 0;
+ hevc->first_pic_flag = 0;
+#ifdef MULTI_INSTANCE_SUPPORT
+ hevc->decoded_poc = INVALID_POC;
+ hevc->start_process_time = 0;
+ hevc->last_lcu_idx = 0;
+ hevc->decode_timeout_count = 0;
+ hevc->timeout_num = 0;
+ hevc->eos = 0;
+ hevc->pic_decoded_lcu_idx = -1;
+ hevc->over_decode = 0;
+ hevc->used_4k_num = -1;
+ hevc->start_decoding_flag = 0;
+ hevc->rps_set_id = 0;
+ backup_decode_state(hevc);
+#endif
+#ifdef DETREFILL_ENABLE
+ hevc->detbuf_adr = 0;
+ hevc->detbuf_adr_virt = NULL;
+#endif
+}
+
+static int post_picture_early(struct vdec_s *vdec, int index);
+static int prepare_display_buf(struct vdec_s *vdec, struct PIC_s *pic);
+static int H265_alloc_mmu(struct hevc_state_s *hevc,
+ struct PIC_s *new_pic, unsigned short bit_depth,
+ unsigned int *mmu_index_adr);
+
+#ifdef DETREFILL_ENABLE
+#define DETREFILL_BUF_SIZE (4 * 0x4000)
+#define HEVC_SAO_DBG_MODE0 0x361e
+#define HEVC_SAO_DBG_MODE1 0x361f
+#define HEVC_SAO_CTRL10 0x362e
+#define HEVC_SAO_CTRL11 0x362f
+static int init_detrefill_buf(struct hevc_state_s *hevc)
+{
+ if (hevc->detbuf_adr_virt)
+ return 0;
+
+ hevc->detbuf_adr_virt =
+ (void *)dma_alloc_coherent(amports_get_dma_device(),
+ DETREFILL_BUF_SIZE, &hevc->detbuf_adr,
+ GFP_KERNEL);
+
+ if (hevc->detbuf_adr_virt == NULL) {
+ pr_err("%s: failed to alloc ETREFILL_BUF\n", __func__);
+ return -1;
+ }
+ return 0;
+}
+
+static void uninit_detrefill_buf(struct hevc_state_s *hevc)
+{
+ if (hevc->detbuf_adr_virt) {
+ dma_free_coherent(amports_get_dma_device(),
+ DETREFILL_BUF_SIZE, hevc->detbuf_adr_virt,
+ hevc->detbuf_adr);
+
+ hevc->detbuf_adr_virt = NULL;
+ hevc->detbuf_adr = 0;
+ }
+}
+
+/*
+ * convert uncompressed frame buffer data from/to ddr
+ */
+static void convUnc8x4blk(uint16_t* blk8x4Luma,
+ uint16_t* blk8x4Cb, uint16_t* blk8x4Cr, uint16_t* cmBodyBuf, int32_t direction)
+{
+ if (direction == 0) {
+ blk8x4Luma[3 + 0 * 8] = ((cmBodyBuf[0] >> 0)) & 0x3ff;
+ blk8x4Luma[3 + 1 * 8] = ((cmBodyBuf[1] << 6)
+ | (cmBodyBuf[0] >> 10)) & 0x3ff;
+ blk8x4Luma[3 + 2 * 8] = ((cmBodyBuf[1] >> 4)) & 0x3ff;
+ blk8x4Luma[3 + 3 * 8] = ((cmBodyBuf[2] << 2)
+ | (cmBodyBuf[1] >> 14)) & 0x3ff;
+ blk8x4Luma[7 + 0 * 8] = ((cmBodyBuf[3] << 8)
+ | (cmBodyBuf[2] >> 8)) & 0x3ff;
+ blk8x4Luma[7 + 1 * 8] = ((cmBodyBuf[3] >> 2)) & 0x3ff;
+ blk8x4Luma[7 + 2 * 8] = ((cmBodyBuf[4] << 4)
+ | (cmBodyBuf[3] >> 12)) & 0x3ff;
+ blk8x4Luma[7 + 3 * 8] = ((cmBodyBuf[4] >> 6)) & 0x3ff;
+ blk8x4Cb [0 + 0 * 4] = ((cmBodyBuf[5] >> 0)) & 0x3ff;
+ blk8x4Cr [0 + 0 * 4] = ((cmBodyBuf[6] << 6)
+ | (cmBodyBuf[5] >> 10)) & 0x3ff;
+ blk8x4Cb [0 + 1 * 4] = ((cmBodyBuf[6] >> 4)) & 0x3ff;
+ blk8x4Cr [0 + 1 * 4] = ((cmBodyBuf[7] << 2)
+ | (cmBodyBuf[6] >> 14)) & 0x3ff;
+
+ blk8x4Luma[0 + 0 * 8] = ((cmBodyBuf[0 + 8] >> 0)) & 0x3ff;
+ blk8x4Luma[1 + 0 * 8] = ((cmBodyBuf[1 + 8] << 6) |
+ (cmBodyBuf[0 + 8] >> 10)) & 0x3ff;
+ blk8x4Luma[2 + 0 * 8] = ((cmBodyBuf[1 + 8] >> 4)) & 0x3ff;
+ blk8x4Luma[0 + 1 * 8] = ((cmBodyBuf[2 + 8] << 2) |
+ (cmBodyBuf[1 + 8] >> 14)) & 0x3ff;
+ blk8x4Luma[1 + 1 * 8] = ((cmBodyBuf[3 + 8] << 8) |
+ (cmBodyBuf[2 + 8] >> 8)) & 0x3ff;
+ blk8x4Luma[2 + 1 * 8] = ((cmBodyBuf[3 + 8] >> 2)) & 0x3ff;
+ blk8x4Luma[0 + 2 * 8] = ((cmBodyBuf[4 + 8] << 4) |
+ (cmBodyBuf[3 + 8] >> 12)) & 0x3ff;
+ blk8x4Luma[1 + 2 * 8] = ((cmBodyBuf[4 + 8] >> 6)) & 0x3ff;
+ blk8x4Luma[2 + 2 * 8] = ((cmBodyBuf[5 + 8] >> 0)) & 0x3ff;
+ blk8x4Luma[0 + 3 * 8] = ((cmBodyBuf[6 + 8] << 6) |
+ (cmBodyBuf[5 + 8] >> 10)) & 0x3ff;
+ blk8x4Luma[1 + 3 * 8] = ((cmBodyBuf[6 + 8] >> 4)) & 0x3ff;
+ blk8x4Luma[2 + 3 * 8] = ((cmBodyBuf[7 + 8] << 2) |
+ (cmBodyBuf[6 + 8] >> 14)) & 0x3ff;
+
+ blk8x4Luma[4 + 0 * 8] = ((cmBodyBuf[0 + 16] >> 0)) & 0x3ff;
+ blk8x4Luma[5 + 0 * 8] = ((cmBodyBuf[1 + 16] << 6) |
+ (cmBodyBuf[0 + 16] >> 10)) & 0x3ff;
+ blk8x4Luma[6 + 0 * 8] = ((cmBodyBuf[1 + 16] >> 4)) & 0x3ff;
+ blk8x4Luma[4 + 1 * 8] = ((cmBodyBuf[2 + 16] << 2) |
+ (cmBodyBuf[1 + 16] >> 14)) & 0x3ff;
+ blk8x4Luma[5 + 1 * 8] = ((cmBodyBuf[3 + 16] << 8) |
+ (cmBodyBuf[2 + 16] >> 8)) & 0x3ff;
+ blk8x4Luma[6 + 1 * 8] = ((cmBodyBuf[3 + 16] >> 2)) & 0x3ff;
+ blk8x4Luma[4 + 2 * 8] = ((cmBodyBuf[4 + 16] << 4) |
+ (cmBodyBuf[3 + 16] >> 12)) & 0x3ff;
+ blk8x4Luma[5 + 2 * 8] = ((cmBodyBuf[4 + 16] >> 6)) & 0x3ff;
+ blk8x4Luma[6 + 2 * 8] = ((cmBodyBuf[5 + 16] >> 0)) & 0x3ff;
+ blk8x4Luma[4 + 3 * 8] = ((cmBodyBuf[6 + 16] << 6) |
+ (cmBodyBuf[5 + 16] >> 10)) & 0x3ff;
+ blk8x4Luma[5 + 3 * 8] = ((cmBodyBuf[6 + 16] >> 4)) & 0x3ff;
+ blk8x4Luma[6 + 3 * 8] = ((cmBodyBuf[7 + 16] << 2) |
+ (cmBodyBuf[6 + 16] >> 14)) & 0x3ff;
+
+ blk8x4Cb[1 + 0 * 4] = ((cmBodyBuf[0 + 24] >> 0)) & 0x3ff;
+ blk8x4Cr[1 + 0 * 4] = ((cmBodyBuf[1 + 24] << 6) |
+ (cmBodyBuf[0 + 24] >> 10)) & 0x3ff;
+ blk8x4Cb[2 + 0 * 4] = ((cmBodyBuf[1 + 24] >> 4)) & 0x3ff;
+ blk8x4Cr[2 + 0 * 4] = ((cmBodyBuf[2 + 24] << 2) |
+ (cmBodyBuf[1 + 24] >> 14)) & 0x3ff;
+ blk8x4Cb[3 + 0 * 4] = ((cmBodyBuf[3 + 24] << 8) |
+ (cmBodyBuf[2 + 24] >> 8)) & 0x3ff;
+ blk8x4Cr[3 + 0 * 4] = ((cmBodyBuf[3 + 24] >> 2)) & 0x3ff;
+ blk8x4Cb[1 + 1 * 4] = ((cmBodyBuf[4 + 24] << 4) |
+ (cmBodyBuf[3 + 24] >> 12)) & 0x3ff;
+ blk8x4Cr[1 + 1 * 4] = ((cmBodyBuf[4 + 24] >> 6)) & 0x3ff;
+ blk8x4Cb[2 + 1 * 4] = ((cmBodyBuf[5 + 24] >> 0)) & 0x3ff;
+ blk8x4Cr[2 + 1 * 4] = ((cmBodyBuf[6 + 24] << 6) |
+ (cmBodyBuf[5 + 24] >> 10)) & 0x3ff;
+ blk8x4Cb[3 + 1 * 4] = ((cmBodyBuf[6 + 24] >> 4)) & 0x3ff;
+ blk8x4Cr[3 + 1 * 4] = ((cmBodyBuf[7 + 24] << 2) |
+ (cmBodyBuf[6 + 24] >> 14)) & 0x3ff;
+ } else {
+ cmBodyBuf[0 + 8 * 0] = (blk8x4Luma[3 + 1 * 8] << 10) |
+ blk8x4Luma[3 + 0 * 8];
+ cmBodyBuf[1 + 8 * 0] = (blk8x4Luma[3 + 3 * 8] << 14) |
+ (blk8x4Luma[3 + 2 * 8] << 4) | (blk8x4Luma[3 + 1 * 8] >> 6);
+ cmBodyBuf[2 + 8 * 0] = (blk8x4Luma[7 + 0 * 8] << 8) |
+ (blk8x4Luma[3 + 3 * 8] >> 2);
+ cmBodyBuf[3 + 8 * 0] = (blk8x4Luma[7 + 2 * 8] << 12) |
+ (blk8x4Luma[7 + 1 * 8] << 2) | (blk8x4Luma[7 + 0 * 8] >>8);
+ cmBodyBuf[4 + 8 * 0] = (blk8x4Luma[7 + 3 * 8] << 6) |
+ (blk8x4Luma[7 + 2 * 8] >>4);
+ cmBodyBuf[5 + 8 * 0] = (blk8x4Cr[0 + 0 * 4] << 10) |
+ blk8x4Cb[0 + 0 * 4];
+ cmBodyBuf[6 + 8 * 0] = (blk8x4Cr[0 + 1 * 4] << 14) |
+ (blk8x4Cb[0 + 1 * 4] << 4) | (blk8x4Cr[0 + 0 * 4] >> 6);
+ cmBodyBuf[7 + 8 * 0] = (0<< 8) | (blk8x4Cr[0 + 1 * 4] >> 2);
+
+ cmBodyBuf[0 + 8 * 1] = (blk8x4Luma[1 + 0 * 8] << 10) |
+ blk8x4Luma[0 + 0 * 8];
+ cmBodyBuf[1 + 8 * 1] = (blk8x4Luma[0 + 1 * 8] << 14) |
+ (blk8x4Luma[2 + 0 * 8] << 4) | (blk8x4Luma[1 + 0 * 8] >> 6);
+ cmBodyBuf[2 + 8 * 1] = (blk8x4Luma[1 + 1 * 8] << 8) |
+ (blk8x4Luma[0 + 1 * 8] >> 2);
+ cmBodyBuf[3 + 8 * 1] = (blk8x4Luma[0 + 2 * 8] << 12) |
+ (blk8x4Luma[2 + 1 * 8] << 2) | (blk8x4Luma[1 + 1 * 8] >>8);
+ cmBodyBuf[4 + 8 * 1] = (blk8x4Luma[1 + 2 * 8] << 6) |
+ (blk8x4Luma[0 + 2 * 8] >>4);
+ cmBodyBuf[5 + 8 * 1] = (blk8x4Luma[0 + 3 * 8] << 10) |
+ blk8x4Luma[2 + 2 * 8];
+ cmBodyBuf[6 + 8 * 1] = (blk8x4Luma[2 + 3 * 8] << 14) |
+ (blk8x4Luma[1 + 3 * 8] << 4) | (blk8x4Luma[0 + 3 * 8] >> 6);
+ cmBodyBuf[7 + 8 * 1] = (0<< 8) | (blk8x4Luma[2 + 3 * 8] >> 2);
+
+ cmBodyBuf[0 + 8 * 2] = (blk8x4Luma[5 + 0 * 8] << 10) |
+ blk8x4Luma[4 + 0 * 8];
+ cmBodyBuf[1 + 8 * 2] = (blk8x4Luma[4 + 1 * 8] << 14) |
+ (blk8x4Luma[6 + 0 * 8] << 4) | (blk8x4Luma[5 + 0 * 8] >> 6);
+ cmBodyBuf[2 + 8 * 2] = (blk8x4Luma[5 + 1 * 8] << 8) |
+ (blk8x4Luma[4 + 1 * 8] >> 2);
+ cmBodyBuf[3 + 8 * 2] = (blk8x4Luma[4 + 2 * 8] << 12) |
+ (blk8x4Luma[6 + 1 * 8] << 2) | (blk8x4Luma[5 + 1 * 8] >>8);
+ cmBodyBuf[4 + 8 * 2] = (blk8x4Luma[5 + 2 * 8] << 6) |
+ (blk8x4Luma[4 + 2 * 8] >>4);
+ cmBodyBuf[5 + 8 * 2] = (blk8x4Luma[4 + 3 * 8] << 10) |
+ blk8x4Luma[6 + 2 * 8];
+ cmBodyBuf[6 + 8 * 2] = (blk8x4Luma[6 + 3 * 8] << 14) |
+ (blk8x4Luma[5 + 3 * 8] << 4) | (blk8x4Luma[4 + 3 * 8] >> 6);
+ cmBodyBuf[7 + 8 * 2] = (0<< 8) | (blk8x4Luma[6 + 3 * 8] >> 2);
+
+ cmBodyBuf[0 + 8 * 3] = (blk8x4Cr[1 + 0 * 4] << 10) |
+ blk8x4Cb[1 + 0 * 4];
+ cmBodyBuf[1 + 8 * 3] = (blk8x4Cr[2 + 0 * 4] << 14) |
+ (blk8x4Cb[2 + 0 * 4] << 4) | (blk8x4Cr[1 + 0 * 4] >> 6);
+ cmBodyBuf[2 + 8 * 3] = (blk8x4Cb[3 + 0 * 4] << 8) |
+ (blk8x4Cr[2 + 0 * 4] >> 2);
+ cmBodyBuf[3 + 8 * 3] = (blk8x4Cb[1 + 1 * 4] << 12) |
+ (blk8x4Cr[3 + 0 * 4] << 2) | (blk8x4Cb[3 + 0 * 4] >>8);
+ cmBodyBuf[4 + 8 * 3] = (blk8x4Cr[1 + 1 * 4] << 6) |
+ (blk8x4Cb[1 + 1 * 4] >>4);
+ cmBodyBuf[5 + 8 * 3] = (blk8x4Cr[2 + 1 * 4] << 10) |
+ blk8x4Cb[2 + 1 * 4];
+ cmBodyBuf[6 + 8 * 3] = (blk8x4Cr[3 + 1 * 4] << 14) |
+ (blk8x4Cb[3 + 1 * 4] << 4) | (blk8x4Cr[2 + 1 * 4] >> 6);
+ cmBodyBuf[7 + 8 * 3] = (0 << 8) | (blk8x4Cr[3 + 1 * 4] >> 2);
+ }
+}
+
+static void corrRefillWithAmrisc (
+ struct hevc_state_s *hevc,
+ uint32_t cmHeaderBaseAddr,
+ uint32_t picWidth,
+ uint32_t ctuPosition)
+{
+ int32_t i;
+ uint16_t ctux = (ctuPosition>>16) & 0xffff;
+ uint16_t ctuy = (ctuPosition>> 0) & 0xffff;
+ int32_t aboveCtuAvailable = (ctuy) ? 1 : 0;
+
+ uint16_t cmBodyBuf[32 * 18];
+
+ uint32_t pic_width_x64_pre = picWidth + 0x3f;
+ uint32_t pic_width_x64 = pic_width_x64_pre >> 6;
+ uint32_t stride64x64 = pic_width_x64 * 128;
+ uint32_t addr_offset64x64_abv = stride64x64 *
+ (aboveCtuAvailable ? ctuy - 1 : ctuy) + 128 * ctux;
+ uint32_t addr_offset64x64_cur = stride64x64*ctuy + 128 * ctux;
+ uint32_t cmHeaderAddrAbv = cmHeaderBaseAddr + addr_offset64x64_abv;
+ uint32_t cmHeaderAddrCur = cmHeaderBaseAddr + addr_offset64x64_cur;
+ unsigned int tmpData32;
+
+ uint16_t blkBuf0Y[32];
+ uint16_t blkBuf0Cb[8];
+ uint16_t blkBuf0Cr[8];
+ uint16_t blkBuf1Y[32];
+ uint16_t blkBuf1Cb[8];
+ uint16_t blkBuf1Cr[8];
+ int32_t blkBufCnt = 0;
+
+ int32_t blkIdx;
+
+ WRITE_VREG(HEVC_SAO_CTRL10, cmHeaderAddrAbv);
+ WRITE_VREG(HEVC_SAO_CTRL11, cmHeaderAddrCur);
+ WRITE_VREG(HEVC_SAO_DBG_MODE0, hevc->detbuf_adr);
+ WRITE_VREG(HEVC_SAO_DBG_MODE1, 2);
+
+ for (i = 0; i < 32 * 18; i++)
+ cmBodyBuf[i] = 0;
+
+ hevc_print(hevc, H265_DEBUG_BUFMGR_MORE,
+ "%s, %d\n", __func__, __LINE__);
+ do {
+ tmpData32 = READ_VREG(HEVC_SAO_DBG_MODE1);
+ } while (tmpData32);
+ hevc_print(hevc, H265_DEBUG_BUFMGR_MORE,
+ "%s, %d\n", __func__, __LINE__);
+
+ hevc_print(hevc, H265_DEBUG_DETAIL,
+ "cmBodyBuf from detbuf:\n");
+ for (i = 0; i < 32 * 18; i++) {
+ cmBodyBuf[i] = hevc->detbuf_adr_virt[i];
+ if (get_dbg_flag(hevc) &
+ H265_DEBUG_DETAIL) {
+ if ((i & 0xf) == 0)
+ hevc_print_cont(hevc, 0, "\n");
+ hevc_print_cont(hevc, 0, "%02x ", cmBodyBuf[i]);
+ }
+ }
+ hevc_print_cont(hevc, H265_DEBUG_DETAIL, "\n");
+
+ for (i = 0; i < 32; i++)
+ blkBuf0Y[i] = 0;
+ for (i = 0; i < 8; i++)
+ blkBuf0Cb[i] = 0;
+ for (i = 0; i < 8; i++)
+ blkBuf0Cr[i] = 0;
+ for (i = 0; i < 32; i++)
+ blkBuf1Y[i] = 0;
+ for (i = 0; i < 8; i++)
+ blkBuf1Cb[i] = 0;
+ for (i = 0; i < 8; i++)
+ blkBuf1Cr[i] = 0;
+
+ for (blkIdx = 0; blkIdx < 18; blkIdx++) {
+ int32_t inAboveCtu = (blkIdx<2) ? 1 : 0;
+ int32_t restoreEnable = (blkIdx>0) ? 1 : 0;
+ uint16_t* blkY = (blkBufCnt==0) ? blkBuf0Y : blkBuf1Y ;
+ uint16_t* blkCb = (blkBufCnt==0) ? blkBuf0Cb : blkBuf1Cb;
+ uint16_t* blkCr = (blkBufCnt==0) ? blkBuf0Cr : blkBuf1Cr;
+ uint16_t* cmBodyBufNow = cmBodyBuf + (blkIdx * 32);
+
+ if (!aboveCtuAvailable && inAboveCtu)
+ continue;
+
+ /* detRefillBuf --> 8x4block*/
+ convUnc8x4blk(blkY, blkCb, blkCr, cmBodyBufNow, 0);
+
+ if (restoreEnable) {
+ blkY[3 + 0 * 8] = blkY[2 + 0 * 8] + 2;
+ blkY[4 + 0 * 8] = blkY[1 + 0 * 8] + 3;
+ blkY[5 + 0 * 8] = blkY[0 + 0 * 8] + 1;
+ blkY[6 + 0 * 8] = blkY[0 + 0 * 8] + 2;
+ blkY[7 + 0 * 8] = blkY[1 + 0 * 8] + 2;
+ blkY[3 + 1 * 8] = blkY[2 + 1 * 8] + 1;
+ blkY[4 + 1 * 8] = blkY[1 + 1 * 8] + 2;
+ blkY[5 + 1 * 8] = blkY[0 + 1 * 8] + 2;
+ blkY[6 + 1 * 8] = blkY[0 + 1 * 8] + 2;
+ blkY[7 + 1 * 8] = blkY[1 + 1 * 8] + 3;
+ blkY[3 + 2 * 8] = blkY[2 + 2 * 8] + 3;
+ blkY[4 + 2 * 8] = blkY[1 + 2 * 8] + 1;
+ blkY[5 + 2 * 8] = blkY[0 + 2 * 8] + 3;
+ blkY[6 + 2 * 8] = blkY[0 + 2 * 8] + 3;
+ blkY[7 + 2 * 8] = blkY[1 + 2 * 8] + 3;
+ blkY[3 + 3 * 8] = blkY[2 + 3 * 8] + 0;
+ blkY[4 + 3 * 8] = blkY[1 + 3 * 8] + 0;
+ blkY[5 + 3 * 8] = blkY[0 + 3 * 8] + 1;
+ blkY[6 + 3 * 8] = blkY[0 + 3 * 8] + 2;
+ blkY[7 + 3 * 8] = blkY[1 + 3 * 8] + 1;
+ blkCb[1 + 0 * 4] = blkCb[0 + 0 * 4];
+ blkCb[2 + 0 * 4] = blkCb[0 + 0 * 4];
+ blkCb[3 + 0 * 4] = blkCb[0 + 0 * 4];
+ blkCb[1 + 1 * 4] = blkCb[0 + 1 * 4];
+ blkCb[2 + 1 * 4] = blkCb[0 + 1 * 4];
+ blkCb[3 + 1 * 4] = blkCb[0 + 1 * 4];
+ blkCr[1 + 0 * 4] = blkCr[0 + 0 * 4];
+ blkCr[2 + 0 * 4] = blkCr[0 + 0 * 4];
+ blkCr[3 + 0 * 4] = blkCr[0 + 0 * 4];
+ blkCr[1 + 1 * 4] = blkCr[0 + 1 * 4];
+ blkCr[2 + 1 * 4] = blkCr[0 + 1 * 4];
+ blkCr[3 + 1 * 4] = blkCr[0 + 1 * 4];
+
+ /*Store data back to DDR*/
+ convUnc8x4blk(blkY, blkCb, blkCr, cmBodyBufNow, 1);
+ }
+
+ blkBufCnt = (blkBufCnt==1) ? 0 : blkBufCnt + 1;
+ }
+
+ hevc_print(hevc, H265_DEBUG_DETAIL,
+ "cmBodyBuf to detbuf:\n");
+ for (i = 0; i < 32 * 18; i++) {
+ hevc->detbuf_adr_virt[i] = cmBodyBuf[i];
+ if (get_dbg_flag(hevc) &
+ H265_DEBUG_DETAIL) {
+ if ((i & 0xf) == 0)
+ hevc_print_cont(hevc, 0, "\n");
+ hevc_print_cont(hevc, 0, "%02x ", cmBodyBuf[i]);
+ }
+ }
+ hevc_print_cont(hevc, H265_DEBUG_DETAIL, "\n");
+
+ WRITE_VREG(HEVC_SAO_DBG_MODE1, 3);
+ hevc_print(hevc, H265_DEBUG_BUFMGR_MORE,
+ "%s, %d\n", __func__, __LINE__);
+ do {
+ tmpData32 = READ_VREG(HEVC_SAO_DBG_MODE1);
+ } while (tmpData32);
+ hevc_print(hevc, H265_DEBUG_BUFMGR_MORE,
+ "%s, %d\n", __func__, __LINE__);
+}
+
+static void delrefill(struct hevc_state_s *hevc)
+{
+ /*
+ * corrRefill
+ */
+ /*HEVC_SAO_DBG_MODE0: picGlobalVariable
+ [31:30]error number
+ [29:20]error2([9:7]tilex[6:0]ctuy)
+ [19:10]error1 [9:0]error0*/
+ uint32_t detResult = READ_VREG(HEVC_ASSIST_SCRATCH_3);
+ uint32_t errorIdx;
+ uint32_t errorNum = (detResult>>30);
+
+ if (detResult) {
+ hevc_print(hevc, H265_DEBUG_BUFMGR,
+ "[corrRefillWithAmrisc] detResult=%08x\n", detResult);
+ for (errorIdx = 0; errorIdx < errorNum; errorIdx++) {
+ uint32_t errorPos = errorIdx * 10;
+ uint32_t errorResult = (detResult >> errorPos) & 0x3ff;
+ uint32_t tilex = (errorResult >> 7) - 1;
+ uint16_t ctux = hevc->m_tile[0][tilex].start_cu_x
+ + hevc->m_tile[0][tilex].width - 1;
+ uint16_t ctuy = (uint16_t)(errorResult & 0x7f);
+ uint32_t ctuPosition = (ctux<< 16) + ctuy;
+ hevc_print(hevc, H265_DEBUG_BUFMGR,
+ "Idx:%d tilex:%d ctu(%d(0x%x), %d(0x%x))\n",
+ errorIdx,tilex,ctux,ctux, ctuy,ctuy);
+ corrRefillWithAmrisc(
+ hevc,
+ (uint32_t)hevc->cur_pic->header_adr,
+ hevc->pic_w,
+ ctuPosition);
+ }
+
+ WRITE_VREG(HEVC_ASSIST_SCRATCH_3, 0); /*clear status*/
+ WRITE_VREG(HEVC_SAO_DBG_MODE0, 0);
+ WRITE_VREG(HEVC_SAO_DBG_MODE1, 1);
+ }
+}
+#endif
+
+static void get_rpm_param(union param_u *params)
+{
+ int i;
+ unsigned int data32;
+
+ for (i = 0; i < 128; i++) {
+ do {
+ data32 = READ_VREG(RPM_CMD_REG);
+ /* hevc_print(hevc, 0, "%x\n", data32); */
+ } while ((data32 & 0x10000) == 0);
+ params->l.data[i] = data32 & 0xffff;
+ /* hevc_print(hevc, 0, "%x\n", data32); */
+ WRITE_VREG(RPM_CMD_REG, 0);
+ }
+}
+
+static int get_free_buf_idx(struct hevc_state_s *hevc)
+{
+ int index = INVALID_IDX;
+ struct PIC_s *pic;
+ int i;
+
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL ||
+ pic->index == -1 ||
+ pic->BUF_index == -1)
+ continue;
+
+ if (pic->output_mark == 0 &&
+ pic->referenced == 0 &&
+ pic->output_ready == 0 &&
+ pic->cma_alloc_addr) {
+ pic->output_ready = 1;
+ index = i;
+ break;
+ }
+ }
+
+ return index;
+}
+
+static struct PIC_s *get_pic_by_POC(struct hevc_state_s *hevc, int POC)
+{
+ int i;
+ struct PIC_s *pic;
+ struct PIC_s *ret_pic = NULL;
+ if (POC == INVALID_POC)
+ return NULL;
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL || pic->index == -1 ||
+ pic->BUF_index == -1)
+ continue;
+ if (pic->POC == POC) {
+ if (ret_pic == NULL)
+ ret_pic = pic;
+ else {
+ if (pic->decode_idx > ret_pic->decode_idx)
+ ret_pic = pic;
+ }
+ }
+ }
+ return ret_pic;
+}
+
+static struct PIC_s *get_ref_pic_by_POC(struct hevc_state_s *hevc, int POC)
+{
+ int i;
+ struct PIC_s *pic;
+ struct PIC_s *ret_pic = NULL;
+
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL || pic->index == -1 ||
+ pic->BUF_index == -1)
+ continue;
+ /*Add width and height of ref picture detection,
+ resolved incorrectly referenced frame.*/
+ if ((pic->POC == POC) && (pic->referenced) &&
+ (hevc->pic_w == pic->width) &&
+ (hevc->pic_h == pic->height)) {
+ if (ret_pic == NULL)
+ ret_pic = pic;
+ else {
+ if (pic->decode_idx > ret_pic->decode_idx)
+ ret_pic = pic;
+ }
+ }
+ }
+
+ return ret_pic;
+}
+
+static unsigned int log2i(unsigned int val)
+{
+ unsigned int ret = -1;
+
+ while (val != 0) {
+ val >>= 1;
+ ret++;
+ }
+ return ret;
+}
+
+static int init_buf_spec(struct hevc_state_s *hevc);
+
+static bool v4l_is_there_vframe_bound(struct hevc_state_s *hevc)
+{
+ int i;
+
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ struct PIC_s *pic = hevc->m_PIC[i];
+
+ if (pic && pic->vframe_bound)
+ return true;
+ }
+
+ return false;
+}
+
+static void v4l_mmu_buffer_release(struct hevc_state_s *hevc)
+{
+ int i;
+
+ /* release workspace */
+ if (hevc->bmmu_box)
+ decoder_bmmu_box_free_idx(hevc->bmmu_box,
+ BMMU_WORKSPACE_ID);
+ /*
+ * it's only when vframe get back to driver, right now we can be sure
+ * that vframe and fd are related. if the playback exits, the capture
+ * requires the upper app to release when the fd is closed, and others
+ * buffers drivers are released by driver.
+ */
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ struct PIC_s *pic = hevc->m_PIC[i];
+
+ if (pic && !pic->vframe_bound) {
+ if (hevc->bmmu_box)
+ decoder_bmmu_box_free_idx(hevc->bmmu_box,
+ VF_BUFFER_IDX(i));
+ if (hevc->mmu_box)
+ decoder_mmu_box_free_idx(hevc->mmu_box, i);
+
+ hevc_print(hevc, PRINT_FLAG_V4L_DETAIL,
+ "%s free buffer[%d], bmmu_box: %p, mmu_box: %p\n",
+ __func__, i, hevc->bmmu_box, hevc->mmu_box);
+ }
+ }
+}
+
+static void uninit_mmu_buffers(struct hevc_state_s *hevc)
+{
+ if (hevc->is_used_v4l &&
+ v4l_is_there_vframe_bound(hevc)) {
+ if (get_double_write_mode(hevc) != 0x10) {
+ v4l_mmu_buffer_release(hevc);
+ return;
+ }
+ }
+
+ if (hevc->mmu_box)
+ decoder_mmu_box_free(hevc->mmu_box);
+ hevc->mmu_box = NULL;
+
+ if (hevc->bmmu_box)
+ decoder_bmmu_box_free(hevc->bmmu_box);
+ hevc->bmmu_box = NULL;
+}
+
+static int init_mmu_box(struct hevc_state_s *hevc)
+{
+ int tvp_flag = vdec_secure(hw_to_vdec(hevc)) ?
+ CODEC_MM_FLAGS_TVP : 0;
+ int buf_size = 64;
+
+ if ((hevc->max_pic_w * hevc->max_pic_h) > 0 &&
+ (hevc->max_pic_w * hevc->max_pic_h) <= 1920*1088) {
+ buf_size = 24;
+ }
+
+ if (get_dbg_flag(hevc)) {
+ hevc_print(hevc, 0, "%s max_w %d max_h %d\n",
+ __func__, hevc->max_pic_w, hevc->max_pic_h);
+ }
+
+ hevc->need_cache_size = buf_size * SZ_1M;
+ hevc->sc_start_time = get_jiffies_64();
+ if (hevc->mmu_enable
+ && ((get_double_write_mode(hevc) & 0x10) == 0)) {
+ hevc->mmu_box = decoder_mmu_box_alloc_box(DRIVER_NAME,
+ hevc->index,
+ MAX_REF_PIC_NUM,
+ buf_size * SZ_1M,
+ tvp_flag
+ );
+ if (!hevc->mmu_box) {
+ hevc_print(hevc, 0, "h265 alloc mmu box failed!!\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int init_mmu_buffers(struct hevc_state_s *hevc)
+{
+ int tvp_flag = vdec_secure(hw_to_vdec(hevc)) ?
+ CODEC_MM_FLAGS_TVP : 0;
+ int buf_size = 64;
+
+ if ((hevc->max_pic_w * hevc->max_pic_h) > 0 &&
+ (hevc->max_pic_w * hevc->max_pic_h) <= 1920*1088) {
+ buf_size = 24;
+ }
+
+ if (get_dbg_flag(hevc)) {
+ hevc_print(hevc, 0, "%s max_w %d max_h %d\n",
+ __func__, hevc->max_pic_w, hevc->max_pic_h);
+ }
+
+ hevc->need_cache_size = buf_size * SZ_1M;
+ hevc->sc_start_time = get_jiffies_64();
+ if (hevc->mmu_enable
+ && ((get_double_write_mode(hevc) & 0x10) == 0)) {
+ hevc->mmu_box = decoder_mmu_box_alloc_box(DRIVER_NAME,
+ hevc->index,
+ MAX_REF_PIC_NUM,
+ buf_size * SZ_1M,
+ tvp_flag
+ );
+ if (!hevc->mmu_box) {
+ pr_err("h265 alloc mmu box failed!!\n");
+ return -1;
+ }
+ }
+
+ hevc->bmmu_box = decoder_bmmu_box_alloc_box(DRIVER_NAME,
+ hevc->index,
+ BMMU_MAX_BUFFERS,
+ 4 + PAGE_SHIFT,
+ CODEC_MM_FLAGS_CMA_CLEAR |
+ CODEC_MM_FLAGS_FOR_VDECODER |
+ tvp_flag);
+ if (!hevc->bmmu_box) {
+ if (hevc->mmu_box)
+ decoder_mmu_box_free(hevc->mmu_box);
+ hevc->mmu_box = NULL;
+ pr_err("h265 alloc mmu box failed!!\n");
+ return -1;
+ }
+ return 0;
+}
+
+struct buf_stru_s
+{
+ int lcu_total;
+ int mc_buffer_size_h;
+ int mc_buffer_size_u_v_h;
+};
+
+#ifndef MV_USE_FIXED_BUF
+static void dealloc_mv_bufs(struct hevc_state_s *hevc)
+{
+ int i;
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ if (hevc->m_mv_BUF[i].start_adr) {
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ hevc_print(hevc, 0,
+ "dealloc mv buf(%d) adr 0x%lx size 0x%x used_flag %d\n",
+ i, hevc->m_mv_BUF[i].start_adr,
+ hevc->m_mv_BUF[i].size,
+ hevc->m_mv_BUF[i].used_flag);
+ decoder_bmmu_box_free_idx(
+ hevc->bmmu_box,
+ MV_BUFFER_IDX(i));
+ hevc->m_mv_BUF[i].start_adr = 0;
+ hevc->m_mv_BUF[i].size = 0;
+ hevc->m_mv_BUF[i].used_flag = 0;
+ }
+ }
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ if (hevc->m_PIC[i] != NULL)
+ hevc->m_PIC[i]->mv_buf_index = -1;
+ }
+}
+
+static int alloc_mv_buf(struct hevc_state_s *hevc, int i)
+{
+ int ret = 0;
+ /*get_cma_alloc_ref();*/ /*DEBUG_TMP*/
+ if (decoder_bmmu_box_alloc_buf_phy
+ (hevc->bmmu_box,
+ MV_BUFFER_IDX(i), hevc->mv_buf_size,
+ DRIVER_NAME,
+ &hevc->m_mv_BUF[i].start_adr) < 0) {
+ hevc->m_mv_BUF[i].start_adr = 0;
+ ret = -1;
+ } else {
+ hevc->m_mv_BUF[i].size = hevc->mv_buf_size;
+ hevc->m_mv_BUF[i].used_flag = 0;
+ ret = 0;
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "MV Buffer %d: start_adr %p size %x\n",
+ i,
+ (void *)hevc->m_mv_BUF[i].start_adr,
+ hevc->m_mv_BUF[i].size);
+ }
+ if (!vdec_secure(hw_to_vdec(hevc)) && (hevc->m_mv_BUF[i].start_adr)) {
+ void *mem_start_virt;
+ mem_start_virt =
+ codec_mm_phys_to_virt(hevc->m_mv_BUF[i].start_adr);
+ if (mem_start_virt) {
+ memset(mem_start_virt, 0, hevc->m_mv_BUF[i].size);
+ codec_mm_dma_flush(mem_start_virt,
+ hevc->m_mv_BUF[i].size, DMA_TO_DEVICE);
+ } else {
+ mem_start_virt = codec_mm_vmap(
+ hevc->m_mv_BUF[i].start_adr,
+ hevc->m_mv_BUF[i].size);
+ if (mem_start_virt) {
+ memset(mem_start_virt, 0, hevc->m_mv_BUF[i].size);
+ codec_mm_dma_flush(mem_start_virt,
+ hevc->m_mv_BUF[i].size,
+ DMA_TO_DEVICE);
+ codec_mm_unmap_phyaddr(mem_start_virt);
+ } else {
+ /*not virt for tvp playing,
+ may need clear on ucode.*/
+ pr_err("ref %s mem_start_virt failed\n", __func__);
+ }
+ }
+ }
+ }
+ /*put_cma_alloc_ref();*/ /*DEBUG_TMP*/
+ return ret;
+}
+#endif
+
+static int get_mv_buf(struct hevc_state_s *hevc, struct PIC_s *pic)
+{
+#ifdef MV_USE_FIXED_BUF
+ if (pic && pic->index >= 0) {
+ int mv_size;
+ if (IS_8K_SIZE(pic->width, pic->height))
+ mv_size = MPRED_8K_MV_BUF_SIZE;
+ else if (IS_4K_SIZE(pic->width, pic->height))
+ mv_size = MPRED_4K_MV_BUF_SIZE; /*0x120000*/
+ else
+ mv_size = MPRED_MV_BUF_SIZE;
+
+ pic->mpred_mv_wr_start_addr =
+ hevc->work_space_buf->mpred_mv.buf_start
+ + (pic->index * mv_size);
+ pic->mv_size = mv_size;
+ }
+ return 0;
+#else
+ int i;
+ int ret = -1;
+ int new_size;
+ if (mv_buf_dynamic_alloc) {
+ int MV_MEM_UNIT =
+ hevc->lcu_size_log2 == 6 ? 0x200 : hevc->lcu_size_log2 ==
+ 5 ? 0x80 : 0x20;
+ int extended_pic_width = (pic->width + hevc->lcu_size -1)
+ & (~(hevc->lcu_size - 1));
+ int extended_pic_height = (pic->height + hevc->lcu_size -1)
+ & (~(hevc->lcu_size - 1));
+ int lcu_x_num = extended_pic_width / hevc->lcu_size;
+ int lcu_y_num = extended_pic_height / hevc->lcu_size;
+ new_size = lcu_x_num * lcu_y_num * MV_MEM_UNIT;
+ hevc->mv_buf_size = (new_size + 0xffff) & (~0xffff);
+ } else {
+ if (IS_8K_SIZE(pic->width, pic->height))
+ new_size = MPRED_8K_MV_BUF_SIZE;
+ else if (IS_4K_SIZE(pic->width, pic->height))
+ new_size = MPRED_4K_MV_BUF_SIZE; /*0x120000*/
+ else
+ new_size = MPRED_MV_BUF_SIZE;
+
+ if (new_size != hevc->mv_buf_size) {
+ dealloc_mv_bufs(hevc);
+ hevc->mv_buf_size = new_size;
+ }
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ if (hevc->m_mv_BUF[i].start_adr &&
+ hevc->m_mv_BUF[i].used_flag == 0) {
+ hevc->m_mv_BUF[i].used_flag = 1;
+ ret = i;
+ break;
+ }
+ }
+ }
+ if (ret < 0) {
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ if (hevc->m_mv_BUF[i].start_adr == 0) {
+ if (alloc_mv_buf(hevc, i) >= 0) {
+ hevc->m_mv_BUF[i].used_flag = 1;
+ ret = i;
+ }
+ break;
+ }
+ }
+ }
+
+ if (ret >= 0) {
+ pic->mv_buf_index = ret;
+ pic->mv_size = hevc->m_mv_BUF[ret].size;
+ pic->mpred_mv_wr_start_addr =
+ (hevc->m_mv_BUF[ret].start_adr + 0xffff) &
+ (~0xffff);
+ hevc_print(hevc, H265_DEBUG_BUFMGR_MORE,
+ "%s => %d (0x%x) size 0x%x\n",
+ __func__, ret,
+ pic->mpred_mv_wr_start_addr,
+ pic->mv_size);
+
+ } else {
+ hevc_print(hevc, 0,
+ "%s: Error, mv buf is not enough\n",
+ __func__);
+ }
+ return ret;
+
+#endif
+}
+
+static void put_mv_buf(struct hevc_state_s *hevc,
+ struct PIC_s *pic)
+{
+#ifndef MV_USE_FIXED_BUF
+ int i = pic->mv_buf_index;
+ if (i < 0 || i >= MAX_REF_PIC_NUM) {
+ hevc_print(hevc, H265_DEBUG_BUFMGR_MORE,
+ "%s: index %d beyond range\n",
+ __func__, i);
+ return;
+ }
+ if (mv_buf_dynamic_alloc) {
+ hevc_print(hevc, H265_DEBUG_BUFMGR_MORE,
+ "%s(%d)\n",
+ __func__, i);
+
+ decoder_bmmu_box_free_idx(
+ hevc->bmmu_box,
+ MV_BUFFER_IDX(i));
+ hevc->m_mv_BUF[i].start_adr = 0;
+ hevc->m_mv_BUF[i].size = 0;
+ hevc->m_mv_BUF[i].used_flag = 0;
+ pic->mv_buf_index = -1;
+ return;
+ }
+
+ hevc_print(hevc, H265_DEBUG_BUFMGR_MORE,
+ "%s(%d): used_flag(%d)\n",
+ __func__, i,
+ hevc->m_mv_BUF[i].used_flag);
+
+ if (hevc->m_mv_BUF[i].start_adr &&
+ hevc->m_mv_BUF[i].used_flag)
+ hevc->m_mv_BUF[i].used_flag = 0;
+ pic->mv_buf_index = -1;
+#endif
+}
+
+static int cal_current_buf_size(struct hevc_state_s *hevc,
+ struct buf_stru_s *buf_stru)
+{
+
+ int buf_size;
+ int pic_width = hevc->pic_w;
+ int pic_height = hevc->pic_h;
+ int lcu_size = hevc->lcu_size;
+ int pic_width_lcu = (pic_width % lcu_size) ? pic_width / lcu_size +
+ 1 : pic_width / lcu_size;
+ int pic_height_lcu = (pic_height % lcu_size) ? pic_height / lcu_size +
+ 1 : pic_height / lcu_size;
+ /*SUPPORT_10BIT*/
+ int losless_comp_header_size = compute_losless_comp_header_size
+ (pic_width, pic_height);
+ /*always alloc buf for 10bit*/
+ int losless_comp_body_size = compute_losless_comp_body_size
+ (hevc, pic_width, pic_height, 0);
+ 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_h = 0;
+
+ int dw_mode = get_double_write_mode(hevc);
+
+ if (hevc->mmu_enable) {
+ if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
+ (IS_8K_SIZE(hevc->pic_w, hevc->pic_h)))
+ buf_size = ((MMU_COMPRESS_HEADER_SIZE_8K + 0xffff) >> 16)
+ << 16;
+ else
+ buf_size = ((MMU_COMPRESS_HEADER_SIZE_4K + 0xffff) >> 16)
+ << 16;
+ } else
+ buf_size = 0;
+
+ if (dw_mode) {
+ int pic_width_dw = pic_width /
+ get_double_write_ratio(hevc, dw_mode);
+ int pic_height_dw = pic_height /
+ get_double_write_ratio(hevc, dw_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;
+
+ int 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);
+ }
+
+ if ((!hevc->mmu_enable) &&
+ ((dw_mode & 0x10) == 0)) {
+ /* use compress mode without mmu,
+ need buf for compress decoding*/
+ buf_size += (mc_buffer_size_h << 16);
+ }
+
+ /*in case start adr is not 64k alignment*/
+ if (buf_size > 0)
+ buf_size += 0x10000;
+
+ if (buf_stru) {
+ buf_stru->lcu_total = pic_width_lcu * pic_height_lcu;
+ buf_stru->mc_buffer_size_h = mc_buffer_size_h;
+ buf_stru->mc_buffer_size_u_v_h = mc_buffer_size_u_v_h;
+ }
+
+ hevc_print(hevc, PRINT_FLAG_V4L_DETAIL,"pic width: %d, pic height: %d, headr: %d, body: %d, size h: %d, size uvh: %d, buf size: %x\n",
+ pic_width, pic_height, losless_comp_header_size,
+ losless_comp_body_size, mc_buffer_size_h,
+ mc_buffer_size_u_v_h, buf_size);
+
+ return buf_size;
+}
+
+static int v4l_alloc_buf(struct hevc_state_s *hevc, struct PIC_s *pic)
+{
+ int ret = -1;
+ int i = pic->index;
+ struct vdec_v4l2_buffer *fb = NULL;
+
+ if (hevc->fatal_error & DECODER_FATAL_ERROR_NO_MEM)
+ return ret;
+
+ ret = vdec_v4l_get_buffer(hevc->v4l2_ctx, &fb);
+ if (ret < 0) {
+ hevc_print(hevc, 0, "[%d] H265 get buffer fail.\n",
+ ((struct aml_vcodec_ctx *)(hevc->v4l2_ctx))->id);
+ return ret;
+ }
+
+ if (hevc->mmu_enable) {
+ if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
+ (IS_8K_SIZE(hevc->pic_w, hevc->pic_h)))
+ hevc->m_BUF[i].header_size =
+ ALIGN(MMU_COMPRESS_HEADER_SIZE_8K, 0x10000);
+ else
+ hevc->m_BUF[i].header_size =
+ ALIGN(MMU_COMPRESS_HEADER_SIZE_4K, 0x10000);
+
+ ret = decoder_bmmu_box_alloc_buf_phy(hevc->bmmu_box,
+ VF_BUFFER_IDX(i), hevc->m_BUF[i].header_size,
+ DRIVER_NAME, &hevc->m_BUF[i].header_addr);
+ if (ret < 0) {
+ hevc_print(hevc, PRINT_FLAG_ERROR,
+ "%s[%d], header size: %d, no mem fatal err\n",
+ __func__, i, hevc->m_BUF[i].header_size);
+ return ret;
+ }
+ }
+
+ hevc->m_BUF[i].used_flag = 0;
+ hevc->m_BUF[i].v4l_ref_buf_addr = (ulong)fb;
+ pic->cma_alloc_addr = hevc->m_BUF[i].v4l_ref_buf_addr;
+ if (fb->num_planes == 1) {
+ hevc->m_BUF[i].start_adr = fb->m.mem[0].addr;
+ hevc->m_BUF[i].luma_size = fb->m.mem[0].offset;
+ hevc->m_BUF[i].size = fb->m.mem[0].size;
+ fb->m.mem[0].bytes_used = fb->m.mem[0].size;
+ pic->dw_y_adr = hevc->m_BUF[i].start_adr;
+ pic->dw_u_v_adr = pic->dw_y_adr + hevc->m_BUF[i].luma_size;
+ } else if (fb->num_planes == 2) {
+ hevc->m_BUF[i].start_adr = fb->m.mem[0].addr;
+ hevc->m_BUF[i].luma_size = fb->m.mem[0].size;
+ hevc->m_BUF[i].chroma_addr = fb->m.mem[1].addr;
+ hevc->m_BUF[i].chroma_size = fb->m.mem[1].size;
+ hevc->m_BUF[i].size = fb->m.mem[0].size + fb->m.mem[1].size;
+ fb->m.mem[0].bytes_used = fb->m.mem[0].size;
+ fb->m.mem[1].bytes_used = fb->m.mem[1].size;
+ pic->dw_y_adr = hevc->m_BUF[i].start_adr;
+ pic->dw_u_v_adr = hevc->m_BUF[i].chroma_addr;
+ }
+
+ return ret;
+}
+
+static int alloc_buf(struct hevc_state_s *hevc)
+{
+ int i;
+ int ret = -1;
+ int buf_size = cal_current_buf_size(hevc, NULL);
+
+ if (hevc->fatal_error & DECODER_FATAL_ERROR_NO_MEM)
+ return ret;
+
+ for (i = 0; i < BUF_POOL_SIZE; i++) {
+ if (hevc->m_BUF[i].start_adr == 0)
+ break;
+ }
+ if (i < BUF_POOL_SIZE) {
+ if (buf_size > 0) {
+ ret = decoder_bmmu_box_alloc_buf_phy
+ (hevc->bmmu_box,
+ VF_BUFFER_IDX(i), buf_size,
+ DRIVER_NAME,
+ &hevc->m_BUF[i].start_adr);
+ if (ret < 0) {
+ hevc->m_BUF[i].start_adr = 0;
+ if (i <= 8) {
+ hevc->fatal_error |=
+ DECODER_FATAL_ERROR_NO_MEM;
+ hevc_print(hevc, PRINT_FLAG_ERROR,
+ "%s[%d], size: %d, no mem fatal err\n",
+ __func__, i, buf_size);
+ }
+ }
+
+ if (ret >= 0) {
+ hevc->m_BUF[i].size = buf_size;
+ hevc->m_BUF[i].used_flag = 0;
+ ret = 0;
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "Buffer %d: start_adr %p size %x\n",
+ i,
+ (void *)hevc->m_BUF[i].start_adr,
+ hevc->m_BUF[i].size);
+ }
+ /*flush the buffer make sure no cache dirty*/
+ if (!vdec_secure(hw_to_vdec(hevc)) && (hevc->m_BUF[i].start_adr)) {
+ void *mem_start_virt;
+ mem_start_virt =
+ codec_mm_phys_to_virt(hevc->m_BUF[i].start_adr);
+ if (mem_start_virt) {
+ memset(mem_start_virt, 0, hevc->m_BUF[i].size);
+ codec_mm_dma_flush(mem_start_virt,
+ hevc->m_BUF[i].size, DMA_TO_DEVICE);
+ } else {
+ codec_mm_memset(hevc->m_BUF[i].start_adr,
+ 0, hevc->m_BUF[i].size);
+ }
+ }
+ }
+ /*put_cma_alloc_ref();*/ /*DEBUG_TMP*/
+ } else
+ ret = 0;
+ }
+
+ if (ret >= 0) {
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "alloc buf(%d) for %d/%d size 0x%x) => %lx\n",
+ i, hevc->pic_w, hevc->pic_h,
+ buf_size,
+ hevc->m_BUF[i].start_adr);
+ }
+ } else {
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "alloc buf(%d) for %d/%d size 0x%x) => Fail!!!\n",
+ i, hevc->pic_w, hevc->pic_h,
+ buf_size);
+ }
+ }
+ return ret;
+}
+
+static void set_buf_unused(struct hevc_state_s *hevc, int i)
+{
+ if (i >= 0 && i < BUF_POOL_SIZE)
+ hevc->m_BUF[i].used_flag = 0;
+}
+
+static void dealloc_unused_buf(struct hevc_state_s *hevc)
+{
+ int i;
+ for (i = 0; i < BUF_POOL_SIZE; i++) {
+ if (hevc->m_BUF[i].start_adr &&
+ hevc->m_BUF[i].used_flag == 0) {
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "dealloc buf(%d) adr 0x%lx size 0x%x\n",
+ i, hevc->m_BUF[i].start_adr,
+ hevc->m_BUF[i].size);
+ }
+ if (!hevc->is_used_v4l)
+ decoder_bmmu_box_free_idx(
+ hevc->bmmu_box,
+ VF_BUFFER_IDX(i));
+ hevc->m_BUF[i].start_adr = 0;
+ hevc->m_BUF[i].size = 0;
+ }
+ }
+}
+
+static void dealloc_pic_buf(struct hevc_state_s *hevc,
+ struct PIC_s *pic)
+{
+ int i = pic->BUF_index;
+ pic->BUF_index = -1;
+ if (i >= 0 &&
+ i < BUF_POOL_SIZE &&
+ hevc->m_BUF[i].start_adr) {
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "dealloc buf(%d) adr 0x%lx size 0x%x\n",
+ i, hevc->m_BUF[i].start_adr,
+ hevc->m_BUF[i].size);
+ }
+
+ if (!hevc->is_used_v4l)
+ decoder_bmmu_box_free_idx(
+ hevc->bmmu_box,
+ VF_BUFFER_IDX(i));
+ hevc->m_BUF[i].used_flag = 0;
+ hevc->m_BUF[i].start_adr = 0;
+ hevc->m_BUF[i].size = 0;
+ }
+}
+
+static int get_work_pic_num(struct hevc_state_s *hevc)
+{
+ int used_buf_num = 0;
+ int sps_pic_buf_diff = 0;
+
+ if (get_dynamic_buf_num_margin(hevc) > 0) {
+ if ((!hevc->sps_num_reorder_pics_0) &&
+ (hevc->param.p.sps_max_dec_pic_buffering_minus1_0)) {
+ /* the range of sps_num_reorder_pics_0 is in
+ [0, sps_max_dec_pic_buffering_minus1_0] */
+ used_buf_num = get_dynamic_buf_num_margin(hevc) +
+ hevc->param.p.sps_max_dec_pic_buffering_minus1_0;
+ } else
+ used_buf_num = hevc->sps_num_reorder_pics_0
+ + get_dynamic_buf_num_margin(hevc);
+
+ sps_pic_buf_diff = hevc->param.p.sps_max_dec_pic_buffering_minus1_0
+ - hevc->sps_num_reorder_pics_0;
+#ifdef MULTI_INSTANCE_SUPPORT
+ /*
+ need one more for multi instance, as
+ apply_ref_pic_set() has no chanch to run to
+ to clear referenced flag in some case
+ */
+ if (hevc->m_ins_flag)
+ used_buf_num++;
+#endif
+ } else
+ used_buf_num = max_buf_num;
+
+ if (hevc->save_buffer_mode)
+ hevc_print(hevc, 0,
+ "save buf _mode : dynamic_buf_num_margin %d ----> %d \n",
+ dynamic_buf_num_margin, hevc->dynamic_buf_num_margin);
+
+ if (sps_pic_buf_diff >= 3)
+ used_buf_num += sps_pic_buf_diff;
+
+ if (hevc->is_used_v4l) {
+ /* for eos add more buffer to flush.*/
+ used_buf_num++;
+ }
+
+ if (used_buf_num > MAX_BUF_NUM)
+ used_buf_num = MAX_BUF_NUM;
+ return used_buf_num;
+}
+
+static int v4l_parser_work_pic_num(struct hevc_state_s *hevc)
+{
+ int used_buf_num = 0;
+ int sps_pic_buf_diff = 0;
+ pr_debug("margin = %d, sps_max_dec_pic_buffering_minus1_0 = %d, sps_num_reorder_pics_0 = %d\n",
+ get_dynamic_buf_num_margin(hevc),
+ hevc->param.p.sps_max_dec_pic_buffering_minus1_0,
+ hevc->param.p.sps_num_reorder_pics_0);
+ if (get_dynamic_buf_num_margin(hevc) > 0) {
+ if ((!hevc->param.p.sps_num_reorder_pics_0) &&
+ (hevc->param.p.sps_max_dec_pic_buffering_minus1_0)) {
+ /* the range of sps_num_reorder_pics_0 is in
+ [0, sps_max_dec_pic_buffering_minus1_0] */
+ used_buf_num = get_dynamic_buf_num_margin(hevc) +
+ hevc->param.p.sps_max_dec_pic_buffering_minus1_0;
+ } else
+ used_buf_num = hevc->param.p.sps_num_reorder_pics_0
+ + get_dynamic_buf_num_margin(hevc);
+
+ sps_pic_buf_diff = hevc->param.p.sps_max_dec_pic_buffering_minus1_0
+ - hevc->param.p.sps_num_reorder_pics_0;
+#ifdef MULTI_INSTANCE_SUPPORT
+ /*
+ need one more for multi instance, as
+ apply_ref_pic_set() has no chanch to run to
+ to clear referenced flag in some case
+ */
+ if (hevc->m_ins_flag)
+ used_buf_num++;
+#endif
+ } else
+ used_buf_num = max_buf_num;
+
+ if (hevc->save_buffer_mode)
+ hevc_print(hevc, 0,
+ "save buf _mode : dynamic_buf_num_margin %d ----> %d \n",
+ dynamic_buf_num_margin, hevc->dynamic_buf_num_margin);
+
+ if (sps_pic_buf_diff >= 4)
+ {
+ used_buf_num += 1;
+ }
+
+ /* for eos add more buffer to flush.*/
+ used_buf_num++;
+
+ if (used_buf_num > MAX_BUF_NUM)
+ used_buf_num = MAX_BUF_NUM;
+ return used_buf_num;
+}
+
+
+static int get_alloc_pic_count(struct hevc_state_s *hevc)
+{
+ int alloc_pic_count = 0;
+ int i;
+ struct PIC_s *pic;
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic && pic->index >= 0)
+ alloc_pic_count++;
+ }
+ return alloc_pic_count;
+}
+
+static int v4l_config_pic(struct hevc_state_s *hevc, struct PIC_s *pic)
+{
+ int i = pic->index;
+ int dw_mode = get_double_write_mode(hevc);
+
+ if (hevc->mmu_enable)
+ pic->header_adr = hevc->m_BUF[i].header_addr;
+
+ pic->BUF_index = i;
+ pic->POC = INVALID_POC;
+ pic->mc_canvas_y = pic->index;
+ pic->mc_canvas_u_v = pic->index;
+
+ if (dw_mode & 0x10) {
+ pic->mc_canvas_y = (pic->index << 1);
+ pic->mc_canvas_u_v = (pic->index << 1) + 1;
+ pic->mc_y_adr = pic->dw_y_adr;
+ pic->mc_u_v_adr = pic->dw_u_v_adr;
+ }
+
+ return 0;
+}
+
+static int config_pic(struct hevc_state_s *hevc, struct PIC_s *pic)
+{
+ int ret = -1;
+ int i;
+ /*int lcu_size_log2 = hevc->lcu_size_log2;
+ int MV_MEM_UNIT=lcu_size_log2==
+ 6 ? 0x100 : lcu_size_log2==5 ? 0x40 : 0x10;*/
+ /*int MV_MEM_UNIT = lcu_size_log2 == 6 ? 0x200 : lcu_size_log2 ==
+ 5 ? 0x80 : 0x20;
+ int mpred_mv_end = hevc->work_space_buf->mpred_mv.buf_start +
+ hevc->work_space_buf->mpred_mv.buf_size;*/
+ unsigned int y_adr = 0;
+ struct buf_stru_s buf_stru;
+ int buf_size = cal_current_buf_size(hevc, &buf_stru);
+ int dw_mode = get_double_write_mode(hevc);
+
+ for (i = 0; i < BUF_POOL_SIZE; i++) {
+ if (hevc->m_BUF[i].start_adr != 0 &&
+ hevc->m_BUF[i].used_flag == 0 &&
+ buf_size <= hevc->m_BUF[i].size) {
+ hevc->m_BUF[i].used_flag = 1;
+ break;
+ }
+ }
+
+ if (i >= BUF_POOL_SIZE)
+ return -1;
+
+ if (hevc->mmu_enable) {
+ pic->header_adr = hevc->m_BUF[i].start_adr;
+ if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
+ (IS_8K_SIZE(hevc->pic_w, hevc->pic_h)))
+ y_adr = hevc->m_BUF[i].start_adr +
+ MMU_COMPRESS_HEADER_SIZE_8K;
+ else
+ y_adr = hevc->m_BUF[i].start_adr +
+ MMU_COMPRESS_HEADER_SIZE_4K;
+ } else
+ y_adr = hevc->m_BUF[i].start_adr;
+
+ y_adr = ((y_adr + 0xffff) >> 16) << 16; /*64k alignment*/
+
+ pic->POC = INVALID_POC;
+ /*ensure get_pic_by_POC()
+ not get the buffer not decoded*/
+ pic->BUF_index = i;
+
+ if ((!hevc->mmu_enable) &&
+ ((dw_mode & 0x10) == 0)
+ ) {
+ pic->mc_y_adr = y_adr;
+ y_adr += (buf_stru.mc_buffer_size_h << 16);
+ }
+ pic->mc_canvas_y = pic->index;
+ pic->mc_canvas_u_v = pic->index;
+ if (dw_mode & 0x10) {
+ pic->mc_y_adr = y_adr;
+ pic->mc_u_v_adr = y_adr +
+ ((buf_stru.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 = pic->mc_y_adr;
+ pic->dw_u_v_adr = pic->mc_u_v_adr;
+ } else if (dw_mode) {
+ pic->dw_y_adr = y_adr;
+ pic->dw_u_v_adr = pic->dw_y_adr +
+ ((buf_stru.mc_buffer_size_u_v_h << 16) << 1);
+ }
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "%s index %d BUF_index %d mc_y_adr %x\n",
+ __func__, pic->index,
+ pic->BUF_index, pic->mc_y_adr);
+ if (hevc->mmu_enable &&
+ dw_mode)
+ hevc_print(hevc, 0,
+ "mmu double write adr %ld\n",
+ pic->cma_alloc_addr);
+ }
+ ret = 0;
+
+ return ret;
+}
+
+static void init_pic_list(struct hevc_state_s *hevc)
+{
+ int i;
+ int init_buf_num = get_work_pic_num(hevc);
+ int dw_mode = get_double_write_mode(hevc);
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+ /*alloc decoder buf will be delay if work on v4l. */
+ if (!hevc->is_used_v4l) {
+ for (i = 0; i < init_buf_num; i++) {
+ if (alloc_buf(hevc) < 0) {
+ if (i <= 8) {
+ /*if alloced (i+1)>=9
+ don't send errors.*/
+ hevc->fatal_error |=
+ DECODER_FATAL_ERROR_NO_MEM;
+ }
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < init_buf_num; i++) {
+ struct PIC_s *pic = hevc->m_PIC[i];
+
+ if (!pic) {
+ pic = vmalloc(sizeof(struct PIC_s));
+ if (pic == NULL) {
+ hevc_print(hevc, 0,
+ "%s: alloc pic %d fail!!!\n",
+ __func__, i);
+ break;
+ }
+ hevc->m_PIC[i] = pic;
+ }
+ memset(pic, 0, sizeof(struct PIC_s));
+
+ pic->index = i;
+ pic->BUF_index = -1;
+ pic->mv_buf_index = -1;
+ if (vdec->parallel_dec == 1) {
+ pic->y_canvas_index = -1;
+ pic->uv_canvas_index = -1;
+ }
+
+ pic->width = hevc->pic_w;
+ pic->height = hevc->pic_h;
+ pic->double_write_mode = dw_mode;
+
+ /*config canvas will be delay if work on v4l. */
+ if (!hevc->is_used_v4l) {
+ if (config_pic(hevc, pic) < 0) {
+ if (get_dbg_flag(hevc))
+ hevc_print(hevc, 0,
+ "Config_pic %d fail\n", pic->index);
+ pic->index = -1;
+ i++;
+ break;
+ }
+
+ if (pic->double_write_mode)
+ set_canvas(hevc, pic);
+ }
+ }
+}
+
+static void uninit_pic_list(struct hevc_state_s *hevc)
+{
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+ int i;
+#ifndef MV_USE_FIXED_BUF
+ dealloc_mv_bufs(hevc);
+#endif
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ struct PIC_s *pic = hevc->m_PIC[i];
+
+ if (pic) {
+ if (vdec->parallel_dec == 1) {
+ vdec->free_canvas_ex(pic->y_canvas_index, vdec->id);
+ vdec->free_canvas_ex(pic->uv_canvas_index, vdec->id);
+ }
+ release_aux_data(hevc, pic);
+ vfree(pic);
+ hevc->m_PIC[i] = NULL;
+ }
+ }
+}
+
+#ifdef LOSLESS_COMPRESS_MODE
+static void init_decode_head_hw(struct hevc_state_s *hevc)
+{
+
+ struct BuffInfo_s *buf_spec = hevc->work_space_buf;
+ unsigned int data32;
+
+ int losless_comp_header_size =
+ compute_losless_comp_header_size(hevc->pic_w,
+ hevc->pic_h);
+ int losless_comp_body_size = compute_losless_comp_body_size(hevc,
+ hevc->pic_w, hevc->pic_h, hevc->mem_saving_mode);
+
+ hevc->losless_comp_body_size = losless_comp_body_size;
+
+
+ if (hevc->mmu_enable) {
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0x1 << 4));
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL2, 0x0);
+ } else {
+ if (hevc->mem_saving_mode == 1)
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1,
+ (1 << 3) | ((workaround_enable & 2) ? 1 : 0));
+ else
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1,
+ ((workaround_enable & 2) ? 1 : 0));
+ 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);
+
+ if (hevc->mmu_enable) {
+ 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);
+ WRITE_VREG(HEVC_SAO_CTRL5, data32);
+ }
+
+ if (!hevc->m_ins_flag)
+ hevc_print(hevc, 0,
+ "%s: (%d, %d) body_size 0x%x header_size 0x%x\n",
+ __func__, hevc->pic_w, hevc->pic_h,
+ losless_comp_body_size, losless_comp_header_size);
+
+}
+#endif
+#define HEVCD_MPP_ANC2AXI_TBL_DATA 0x3464
+
+static void init_pic_list_hw(struct hevc_state_s *hevc)
+{
+ int i;
+ int cur_pic_num = MAX_REF_PIC_NUM;
+ int dw_mode = get_double_write_mode(hevc);
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL)
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR,
+ (0x1 << 1) | (0x1 << 2));
+ else
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0x0);
+
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ if (hevc->m_PIC[i] == NULL ||
+ hevc->m_PIC[i]->index == -1) {
+ cur_pic_num = i;
+ break;
+ }
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) {
+ if (hevc->mmu_enable && ((dw_mode & 0x10) == 0))
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA,
+ hevc->m_PIC[i]->header_adr>>5);
+ else
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA,
+ hevc->m_PIC[i]->mc_y_adr >> 5);
+ } else
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
+ hevc->m_PIC[i]->mc_y_adr |
+ (hevc->m_PIC[i]->mc_canvas_y << 8) | 0x1);
+ if (dw_mode & 0x10) {
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) {
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA,
+ hevc->m_PIC[i]->mc_u_v_adr >> 5);
+ }
+ else
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
+ hevc->m_PIC[i]->mc_u_v_adr |
+ (hevc->m_PIC[i]->mc_canvas_u_v << 8)
+ | 0x1);
+ }
+ }
+ if (cur_pic_num == 0)
+ return;
+
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0x1);
+
+ /* 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 LOSLESS_COMPRESS_MODE
+ if ((dw_mode & 0x10) == 0)
+ init_decode_head_hw(hevc);
+#endif
+
+}
+
+
+static void dump_pic_list(struct hevc_state_s *hevc)
+{
+ int i;
+ struct PIC_s *pic;
+
+ hevc_print(hevc, 0,
+ "pic_list_init_flag is %d\r\n", hevc->pic_list_init_flag);
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL || pic->index == -1)
+ continue;
+ hevc_print_cont(hevc, 0,
+ "index %d buf_idx %d mv_idx %d decode_idx:%d, POC:%d, referenced:%d (LT %d), ",
+ pic->index, pic->BUF_index,
+#ifndef MV_USE_FIXED_BUF
+ pic->mv_buf_index,
+#else
+ -1,
+#endif
+ pic->decode_idx, pic->POC, pic->referenced
+#ifdef SUPPORT_LONG_TERM_RPS
+ , pic->long_term_ref
+#else
+ , 0
+#endif
+ );
+ hevc_print_cont(hevc, 0,
+ "num_reorder_pic:%d, output_mark:%d, error_mark:%d w/h %d,%d",
+ pic->num_reorder_pic, pic->output_mark, pic->error_mark,
+ pic->width, pic->height);
+ hevc_print_cont(hevc, 0,
+ "output_ready:%d, mv_wr_start %x vf_ref %d\n",
+ pic->output_ready, pic->mpred_mv_wr_start_addr,
+ pic->vf_ref);
+ }
+}
+
+static void clear_referenced_flag(struct hevc_state_s *hevc)
+{
+ int i;
+ struct PIC_s *pic;
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL || pic->index == -1)
+ continue;
+ if (pic->referenced) {
+ pic->referenced = 0;
+ put_mv_buf(hevc, pic);
+ }
+ }
+}
+
+static void clear_poc_flag(struct hevc_state_s *hevc)
+{
+ int i;
+ struct PIC_s *pic;
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL || pic->index == -1)
+ continue;
+ pic->POC = INVALID_POC;
+ }
+}
+
+static struct PIC_s *output_pic(struct hevc_state_s *hevc,
+ unsigned char flush_flag)
+{
+ int num_pic_not_yet_display = 0;
+ int i, fisrt_pic_flag = 0;
+ struct PIC_s *pic;
+ struct PIC_s *pic_display = NULL;
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+
+ if (hevc->i_only & 0x4) {
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL ||
+ (pic->index == -1) ||
+ (pic->BUF_index == -1) ||
+ (pic->POC == INVALID_POC))
+ continue;
+ if (pic->output_mark) {
+ if (pic_display) {
+ if (pic->decode_idx <
+ pic_display->decode_idx)
+ pic_display = pic;
+
+ } else
+ pic_display = pic;
+
+ }
+ }
+ if (pic_display) {
+ pic_display->output_mark = 0;
+ pic_display->recon_mark = 0;
+ pic_display->output_ready = 1;
+ pic_display->referenced = 0;
+ put_mv_buf(hevc, pic_display);
+ }
+ } else {
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL ||
+ (pic->index == -1) ||
+ (pic->BUF_index == -1) ||
+ (pic->POC == INVALID_POC))
+ continue;
+ if (pic->output_mark)
+ num_pic_not_yet_display++;
+ if (pic->slice_type == 2 &&
+ hevc->vf_pre_count == 0 &&
+ fast_output_enable & 0x1) {
+ /*fast output for first I picture*/
+ pic->num_reorder_pic = 0;
+ if (vdec->master || vdec->slave)
+ pic_display = pic;
+ fisrt_pic_flag = 1;
+ hevc_print(hevc, 0, "VH265: output first frame\n");
+ }
+ }
+
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL ||
+ (pic->index == -1) ||
+ (pic->BUF_index == -1) ||
+ (pic->POC == INVALID_POC))
+ continue;
+ if (pic->output_mark) {
+ if (pic_display) {
+ if (pic->POC < pic_display->POC)
+ pic_display = pic;
+ else if ((pic->POC == pic_display->POC)
+ && (pic->decode_idx <
+ pic_display->
+ decode_idx))
+ pic_display
+ = pic;
+
+ } else
+ pic_display = pic;
+
+ }
+ }
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ /* dv wait cur_pic all data get,
+ some data may get after picture output */
+ if ((vdec->master || vdec->slave)
+ && (pic_display == hevc->cur_pic) &&
+ (!flush_flag) &&
+ (hevc->bypass_dvenl && !dolby_meta_with_el)
+ && (!fisrt_pic_flag))
+ pic_display = NULL;
+#endif
+
+ if (pic_display) {
+ if ((num_pic_not_yet_display >
+ pic_display->num_reorder_pic)
+ || flush_flag) {
+ pic_display->output_mark = 0;
+ pic_display->recon_mark = 0;
+ pic_display->output_ready = 1;
+ } else if (num_pic_not_yet_display >=
+ (MAX_REF_PIC_NUM - 1)) {
+ pic_display->output_mark = 0;
+ pic_display->recon_mark = 0;
+ pic_display->output_ready = 1;
+ hevc_print(hevc, 0,
+ "Warning, num_reorder_pic %d is byeond buf num\n",
+ pic_display->num_reorder_pic);
+ } else
+ pic_display = NULL;
+ }
+ }
+
+ if (pic_display && hevc->sps_num_reorder_pics_0 &&
+ (hevc->vf_pre_count == 1) && (hevc->first_pic_flag == 1)) {
+ pic_display = NULL;
+ hevc->first_pic_flag = 2;
+ }
+ return pic_display;
+}
+
+static int config_mc_buffer(struct hevc_state_s *hevc, struct PIC_s *cur_pic)
+{
+ int i;
+ struct PIC_s *pic;
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ hevc_print(hevc, 0,
+ "config_mc_buffer entered .....\n");
+ if (cur_pic->slice_type != 2) { /* P and B pic */
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
+ (0 << 8) | (0 << 1) | 1);
+ for (i = 0; i < cur_pic->RefNum_L0; i++) {
+ pic =
+ get_ref_pic_by_POC(hevc,
+ cur_pic->
+ m_aiRefPOCList0[cur_pic->
+ slice_idx][i]);
+ if (pic) {
+ if ((pic->width != hevc->pic_w) ||
+ (pic->height != hevc->pic_h)) {
+ hevc_print(hevc, 0,
+ "%s: Wrong reference pic (poc %d) width/height %d/%d\n",
+ __func__, pic->POC,
+ pic->width, pic->height);
+ cur_pic->error_mark = 1;
+ }
+ if (pic->error_mark && (ref_frame_mark_flag[hevc->index]))
+ cur_pic->error_mark = 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 (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print_cont(hevc, 0,
+ "refid %x mc_canvas_u_v %x",
+ i, pic->mc_canvas_u_v);
+ hevc_print_cont(hevc, 0,
+ " mc_canvas_y %x\n",
+ pic->mc_canvas_y);
+ }
+ } else
+ cur_pic->error_mark = 1;
+
+ if (pic == NULL || pic->error_mark) {
+ hevc_print(hevc, 0,
+ "Error %s, %dth poc (%d) %s",
+ __func__, i,
+ cur_pic->m_aiRefPOCList0[cur_pic->
+ slice_idx][i],
+ pic ? "has error" :
+ "not in list0");
+ }
+ }
+ }
+ if (cur_pic->slice_type == 0) { /* B pic */
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ hevc_print(hevc, 0,
+ "config_mc_buffer RefNum_L1\n");
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
+ (16 << 8) | (0 << 1) | 1);
+
+ for (i = 0; i < cur_pic->RefNum_L1; i++) {
+ pic =
+ get_ref_pic_by_POC(hevc,
+ cur_pic->
+ m_aiRefPOCList1[cur_pic->
+ slice_idx][i]);
+ if (pic) {
+ if ((pic->width != hevc->pic_w) ||
+ (pic->height != hevc->pic_h)) {
+ hevc_print(hevc, 0,
+ "%s: Wrong reference pic (poc %d) width/height %d/%d\n",
+ __func__, pic->POC,
+ pic->width, pic->height);
+ cur_pic->error_mark = 1;
+ }
+
+ if (pic->error_mark && (ref_frame_mark_flag[hevc->index]))
+ cur_pic->error_mark = 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 (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print_cont(hevc, 0,
+ "refid %x mc_canvas_u_v %x",
+ i, pic->mc_canvas_u_v);
+ hevc_print_cont(hevc, 0,
+ " mc_canvas_y %x\n",
+ pic->mc_canvas_y);
+ }
+ } else
+ cur_pic->error_mark = 1;
+
+ if (pic == NULL || pic->error_mark) {
+ hevc_print(hevc, 0,
+ "Error %s, %dth poc (%d) %s",
+ __func__, i,
+ cur_pic->m_aiRefPOCList1[cur_pic->
+ slice_idx][i],
+ pic ? "has error" :
+ "not in list1");
+ }
+ }
+ }
+ return 0;
+}
+
+#ifdef SUPPORT_LONG_TERM_RPS
+static unsigned char is_ref_long_term(struct hevc_state_s *hevc, int poc)
+{
+ int ii;
+ struct PIC_s *pic;
+ for (ii = 0; ii < MAX_REF_PIC_NUM; ii++) {
+ pic = hevc->m_PIC[ii];
+ if (pic == NULL ||
+ pic->index == -1 ||
+ pic->BUF_index == -1
+ )
+ continue;
+
+ if (pic->referenced && pic->POC == poc
+ && pic->long_term_ref)
+ return 1;
+ }
+ return 0;
+}
+
+#endif
+
+static void apply_ref_pic_set(struct hevc_state_s *hevc, int cur_poc,
+ union param_u *params)
+{
+ int ii, i;
+ int poc_tmp;
+ struct PIC_s *pic;
+ unsigned char is_referenced;
+ /* hevc_print(hevc, 0,
+ "%s cur_poc %d\n", __func__, cur_poc); */
+ if (pic_list_debug & 0x2) {
+ pr_err("cur poc %d\n", cur_poc);
+ }
+ for (ii = 0; ii < MAX_REF_PIC_NUM; ii++) {
+ pic = hevc->m_PIC[ii];
+ if (pic == NULL ||
+ pic->index == -1 ||
+ pic->BUF_index == -1
+ )
+ continue;
+
+#ifdef SUPPORT_LONG_TERM_RPS
+ pic->long_term_ref = 0;
+#endif
+ if ((pic->referenced == 0 || pic->POC == cur_poc))
+ continue;
+ is_referenced = 0;
+
+ for (i = 0; i < 16; i++) {
+ int delt;
+#ifdef SUPPORT_LONG_TERM_RPS
+ if (params->p.CUR_RPS[i] == RPS_END)
+ break;
+#else
+ if (params->p.CUR_RPS[i] & 0x8000)
+ break;
+#endif
+ delt =
+ params->p.CUR_RPS[i] &
+ ((1 << (RPS_USED_BIT - 1)) - 1);
+ if (params->p.CUR_RPS[i] & (1 << (RPS_USED_BIT - 1))) {
+ poc_tmp =
+ cur_poc - ((1 << (RPS_USED_BIT - 1)) -
+ delt);
+ } else
+ poc_tmp = cur_poc + delt;
+ if (poc_tmp == pic->POC) {
+#ifdef SUPPORT_LONG_TERM_RPS
+ if (params->p.CUR_RPS[i] & (1 << (RPS_LT_BIT)))
+ pic->long_term_ref = 1;
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR_MORE)
+ hevc_print(hevc, 0, "%d: CUR_RPS 0x%x, LT %d\n",
+ i, params->p.CUR_RPS[i],
+ pic->long_term_ref);
+#endif
+ is_referenced = 1;
+ break;
+ }
+ }
+ if (is_referenced == 0) {
+ pic->referenced = 0;
+ put_mv_buf(hevc, pic);
+ /* hevc_print(hevc, 0,
+ "set poc %d reference to 0\n", pic->POC); */
+ if (pic_list_debug & 0x2) {
+ pr_err("set poc %d reference to 0\n", pic->POC);
+ }
+ }
+ }
+
+}
+
+static void set_ref_pic_list(struct hevc_state_s *hevc, union param_u *params)
+{
+ struct PIC_s *pic = hevc->cur_pic;
+ int i, rIdx;
+ int num_neg = 0;
+ int num_pos = 0;
+ int total_num;
+ int num_ref_idx_l0_active =
+ (params->p.num_ref_idx_l0_active >
+ MAX_REF_ACTIVE) ? MAX_REF_ACTIVE :
+ params->p.num_ref_idx_l0_active;
+ int num_ref_idx_l1_active =
+ (params->p.num_ref_idx_l1_active >
+ MAX_REF_ACTIVE) ? MAX_REF_ACTIVE :
+ params->p.num_ref_idx_l1_active;
+
+ int RefPicSetStCurr0[16];
+ int RefPicSetStCurr1[16];
+#ifdef SUPPORT_LONG_TERM_RPS
+ int num_lt = 0;
+ int RefPicSetLtCurr[16];
+#endif
+
+ for (i = 0; i < 16; i++) {
+ RefPicSetStCurr0[i] = 0;
+ RefPicSetStCurr1[i] = 0;
+ pic->m_aiRefPOCList0[pic->slice_idx][i] = 0;
+ pic->m_aiRefPOCList1[pic->slice_idx][i] = 0;
+ }
+ for (i = 0; i < 16; i++) {
+#ifdef SUPPORT_LONG_TERM_RPS
+ if (params->p.CUR_RPS[i] == RPS_END)
+ break;
+#else
+ if (params->p.CUR_RPS[i] & 0x8000)
+ break;
+#endif
+ if ((params->p.CUR_RPS[i] >> RPS_USED_BIT) & 1) {
+ int delt =
+ params->p.CUR_RPS[i] &
+ ((1 << (RPS_USED_BIT - 1)) - 1);
+
+ if ((params->p.CUR_RPS[i] >> (RPS_USED_BIT - 1)) & 1) {
+#ifdef SUPPORT_LONG_TERM_RPS
+ if ((params->p.CUR_RPS[i] >> RPS_LT_BIT) & 1) {
+ RefPicSetLtCurr[num_lt] =
+ pic->POC - ((1 << (RPS_USED_BIT - 1)) -
+ delt);
+ num_lt++;
+ continue;
+ }
+#endif
+
+ RefPicSetStCurr0[num_neg] =
+ pic->POC - ((1 << (RPS_USED_BIT - 1)) -
+ delt);
+ /* hevc_print(hevc, 0,
+ * "RefPicSetStCurr0 %x %x %x\n",
+ * RefPicSetStCurr0[num_neg], pic->POC,
+ * (0x800-(params[i]&0x7ff)));
+ */
+ num_neg++;
+ } else {
+#ifdef SUPPORT_LONG_TERM_RPS
+ if ((params->p.CUR_RPS[i] >> RPS_LT_BIT) & 1) {
+ RefPicSetLtCurr[num_lt] = pic->POC + delt;
+ num_lt++;
+ continue;
+ }
+#endif
+ RefPicSetStCurr1[num_pos] = pic->POC + delt;
+ /* hevc_print(hevc, 0,
+ * "RefPicSetStCurr1 %d\n",
+ * RefPicSetStCurr1[num_pos]);
+ */
+ num_pos++;
+ }
+ }
+ }
+#ifdef SUPPORT_LONG_TERM_RPS
+ total_num = num_neg + num_pos + num_lt;
+#else
+ total_num = num_neg + num_pos;
+#endif
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "%s: curpoc %d slice_type %d, total %d ",
+ __func__, pic->POC, params->p.slice_type, total_num);
+#ifdef SUPPORT_LONG_TERM_RPS
+ hevc_print_cont(hevc, 0,
+ "num_neg %d num_lt %d num_list0 %d num_list1 %d\n",
+ num_neg, num_lt, num_ref_idx_l0_active, num_ref_idx_l1_active);
+#else
+ hevc_print_cont(hevc, 0,
+ "num_neg %d num_list0 %d num_list1 %d\n",
+ num_neg, num_ref_idx_l0_active, num_ref_idx_l1_active);
+#endif
+
+ }
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "HEVC Stream buf start ");
+ hevc_print_cont(hevc, 0,
+ "%x end %x wr %x rd %x lev %x ctl %x intctl %x\n",
+ READ_VREG(HEVC_STREAM_START_ADDR),
+ READ_VREG(HEVC_STREAM_END_ADDR),
+ READ_VREG(HEVC_STREAM_WR_PTR),
+ READ_VREG(HEVC_STREAM_RD_PTR),
+ READ_VREG(HEVC_STREAM_LEVEL),
+ READ_VREG(HEVC_STREAM_FIFO_CTL),
+ READ_VREG(HEVC_PARSER_INT_CONTROL));
+ }
+
+ if (total_num > 0) {
+ if (params->p.modification_flag & 0x1) {
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ hevc_print(hevc, 0, "ref0 POC (modification):");
+ for (rIdx = 0; rIdx < num_ref_idx_l0_active; rIdx++) {
+ int cIdx = params->p.modification_list[rIdx];
+
+ pic->m_aiRefPOCList0[pic->slice_idx][rIdx] =
+#ifdef SUPPORT_LONG_TERM_RPS
+ cIdx >= (num_neg + num_pos) ?
+ RefPicSetLtCurr[cIdx - num_neg - num_pos] :
+#endif
+ (cIdx >=
+ num_neg ? RefPicSetStCurr1[cIdx -
+ num_neg] :
+ RefPicSetStCurr0[cIdx]);
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print_cont(hevc, 0, "%d ",
+ pic->m_aiRefPOCList0[pic->
+ slice_idx]
+ [rIdx]);
+ }
+ }
+ } else {
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ hevc_print(hevc, 0, "ref0 POC:");
+ for (rIdx = 0; rIdx < num_ref_idx_l0_active; rIdx++) {
+ int cIdx = rIdx % total_num;
+
+ pic->m_aiRefPOCList0[pic->slice_idx][rIdx] =
+#ifdef SUPPORT_LONG_TERM_RPS
+ cIdx >= (num_neg + num_pos) ?
+ RefPicSetLtCurr[cIdx - num_neg - num_pos] :
+#endif
+ (cIdx >=
+ num_neg ? RefPicSetStCurr1[cIdx -
+ num_neg] :
+ RefPicSetStCurr0[cIdx]);
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print_cont(hevc, 0, "%d ",
+ pic->m_aiRefPOCList0[pic->
+ slice_idx]
+ [rIdx]);
+ }
+ }
+ }
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ hevc_print_cont(hevc, 0, "\n");
+ if (params->p.slice_type == B_SLICE) {
+ if (params->p.modification_flag & 0x2) {
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ hevc_print(hevc, 0,
+ "ref1 POC (modification):");
+ for (rIdx = 0; rIdx < num_ref_idx_l1_active;
+ rIdx++) {
+ int cIdx;
+
+ if (params->p.modification_flag & 0x1) {
+ cIdx =
+ params->p.
+ modification_list
+ [num_ref_idx_l0_active +
+ rIdx];
+ } else {
+ cIdx =
+ params->p.
+ modification_list[rIdx];
+ }
+ pic->m_aiRefPOCList1[pic->
+ slice_idx][rIdx] =
+#ifdef SUPPORT_LONG_TERM_RPS
+ cIdx >= (num_neg + num_pos) ?
+ RefPicSetLtCurr[cIdx - num_neg - num_pos] :
+#endif
+ (cIdx >=
+ num_pos ?
+ RefPicSetStCurr0[cIdx - num_pos]
+ : RefPicSetStCurr1[cIdx]);
+ if (get_dbg_flag(hevc) &
+ H265_DEBUG_BUFMGR) {
+ hevc_print_cont(hevc, 0, "%d ",
+ pic->
+ m_aiRefPOCList1[pic->
+ slice_idx]
+ [rIdx]);
+ }
+ }
+ } else {
+ if (get_dbg_flag(hevc) &
+ H265_DEBUG_BUFMGR)
+ hevc_print(hevc, 0, "ref1 POC:");
+ for (rIdx = 0; rIdx < num_ref_idx_l1_active;
+ rIdx++) {
+ int cIdx = rIdx % total_num;
+
+ pic->m_aiRefPOCList1[pic->
+ slice_idx][rIdx] =
+#ifdef SUPPORT_LONG_TERM_RPS
+ cIdx >= (num_neg + num_pos) ?
+ RefPicSetLtCurr[cIdx - num_neg - num_pos] :
+#endif
+ (cIdx >=
+ num_pos ?
+ RefPicSetStCurr0[cIdx -
+ num_pos]
+ : RefPicSetStCurr1[cIdx]);
+ if (get_dbg_flag(hevc) &
+ H265_DEBUG_BUFMGR) {
+ hevc_print_cont(hevc, 0, "%d ",
+ pic->
+ m_aiRefPOCList1[pic->
+ slice_idx]
+ [rIdx]);
+ }
+ }
+ }
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ hevc_print_cont(hevc, 0, "\n");
+ }
+ }
+ /*set m_PIC */
+ pic->slice_type = (params->p.slice_type == I_SLICE) ? 2 :
+ (params->p.slice_type == P_SLICE) ? 1 :
+ (params->p.slice_type == B_SLICE) ? 0 : 3;
+ pic->RefNum_L0 = num_ref_idx_l0_active;
+ pic->RefNum_L1 = num_ref_idx_l1_active;
+}
+
+static void update_tile_info(struct hevc_state_s *hevc, int pic_width_cu,
+ int pic_height_cu, int sao_mem_unit,
+ union param_u *params)
+{
+ int i, j;
+ int start_cu_x, start_cu_y;
+ int sao_vb_size = (sao_mem_unit + (2 << 4)) * pic_height_cu;
+ int sao_abv_size = sao_mem_unit * pic_width_cu;
+#ifdef DETREFILL_ENABLE
+ if (hevc->is_swap && get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_GXM) {
+ int tmpRefillLcuSize = 1 <<
+ (params->p.log2_min_coding_block_size_minus3 +
+ 3 + params->p.log2_diff_max_min_coding_block_size);
+ hevc_print(hevc, H265_DEBUG_BUFMGR_MORE,
+ "%x, %x, %x, %x\n",
+ params->p.slice_segment_address,
+ params->p.bit_depth,
+ params->p.tiles_enabled_flag,
+ tmpRefillLcuSize);
+ if (params->p.slice_segment_address == 0 &&
+ params->p.bit_depth != 0 &&
+ (params->p.tiles_enabled_flag & 1) &&
+ tmpRefillLcuSize == 64)
+ hevc->delrefill_check = 1;
+ else
+ hevc->delrefill_check = 0;
+ }
+#endif
+
+ hevc->tile_enabled = params->p.tiles_enabled_flag & 1;
+ if (params->p.tiles_enabled_flag & 1) {
+ hevc->num_tile_col = params->p.num_tile_columns_minus1 + 1;
+ hevc->num_tile_row = params->p.num_tile_rows_minus1 + 1;
+
+ if (hevc->num_tile_row > MAX_TILE_ROW_NUM
+ || hevc->num_tile_row <= 0) {
+ hevc->num_tile_row = 1;
+ hevc_print(hevc, 0,
+ "%s: num_tile_rows_minus1 (%d) error!!\n",
+ __func__, params->p.num_tile_rows_minus1);
+ }
+ if (hevc->num_tile_col > MAX_TILE_COL_NUM
+ || hevc->num_tile_col <= 0) {
+ hevc->num_tile_col = 1;
+ hevc_print(hevc, 0,
+ "%s: num_tile_columns_minus1 (%d) error!!\n",
+ __func__, params->p.num_tile_columns_minus1);
+ }
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "%s pic_w_cu %d pic_h_cu %d tile_enabled ",
+ __func__, pic_width_cu, pic_height_cu);
+ hevc_print_cont(hevc, 0,
+ "num_tile_col %d num_tile_row %d:\n",
+ hevc->num_tile_col, hevc->num_tile_row);
+ }
+
+ if (params->p.tiles_enabled_flag & 2) { /* uniform flag */
+ int w = pic_width_cu / hevc->num_tile_col;
+ int h = pic_height_cu / hevc->num_tile_row;
+
+ start_cu_y = 0;
+ for (i = 0; i < hevc->num_tile_row; i++) {
+ start_cu_x = 0;
+ for (j = 0; j < hevc->num_tile_col; j++) {
+ if (j == (hevc->num_tile_col - 1)) {
+ hevc->m_tile[i][j].width =
+ pic_width_cu -
+ start_cu_x;
+ } else
+ hevc->m_tile[i][j].width = w;
+ if (i == (hevc->num_tile_row - 1)) {
+ hevc->m_tile[i][j].height =
+ pic_height_cu -
+ start_cu_y;
+ } else
+ hevc->m_tile[i][j].height = h;
+ hevc->m_tile[i][j].start_cu_x
+ = start_cu_x;
+ hevc->m_tile[i][j].start_cu_y
+ = start_cu_y;
+ hevc->m_tile[i][j].sao_vb_start_addr =
+ hevc->work_space_buf->sao_vb.
+ buf_start + j * sao_vb_size;
+ hevc->m_tile[i][j].sao_abv_start_addr =
+ hevc->work_space_buf->sao_abv.
+ buf_start + i * sao_abv_size;
+ if (get_dbg_flag(hevc) &
+ H265_DEBUG_BUFMGR) {
+ hevc_print_cont(hevc, 0,
+ "{y=%d, x=%d w %d h %d ",
+ i, j, hevc->m_tile[i][j].width,
+ hevc->m_tile[i][j].height);
+ hevc_print_cont(hevc, 0,
+ "start_x %d start_y %d ",
+ hevc->m_tile[i][j].start_cu_x,
+ hevc->m_tile[i][j].start_cu_y);
+ hevc_print_cont(hevc, 0,
+ "sao_vb_start 0x%x ",
+ hevc->m_tile[i][j].
+ sao_vb_start_addr);
+ hevc_print_cont(hevc, 0,
+ "sao_abv_start 0x%x}\n",
+ hevc->m_tile[i][j].
+ sao_abv_start_addr);
+ }
+ start_cu_x += hevc->m_tile[i][j].width;
+
+ }
+ start_cu_y += hevc->m_tile[i][0].height;
+ }
+ } else {
+ start_cu_y = 0;
+ for (i = 0; i < hevc->num_tile_row; i++) {
+ start_cu_x = 0;
+ for (j = 0; j < hevc->num_tile_col; j++) {
+ if (j == (hevc->num_tile_col - 1)) {
+ hevc->m_tile[i][j].width =
+ pic_width_cu -
+ start_cu_x;
+ } else {
+ hevc->m_tile[i][j].width =
+ params->p.tile_width[j];
+ }
+ if (i == (hevc->num_tile_row - 1)) {
+ hevc->m_tile[i][j].height =
+ pic_height_cu -
+ start_cu_y;
+ } else {
+ hevc->m_tile[i][j].height =
+ params->
+ p.tile_height[i];
+ }
+ hevc->m_tile[i][j].start_cu_x
+ = start_cu_x;
+ hevc->m_tile[i][j].start_cu_y
+ = start_cu_y;
+ hevc->m_tile[i][j].sao_vb_start_addr =
+ hevc->work_space_buf->sao_vb.
+ buf_start + j * sao_vb_size;
+ hevc->m_tile[i][j].sao_abv_start_addr =
+ hevc->work_space_buf->sao_abv.
+ buf_start + i * sao_abv_size;
+ if (get_dbg_flag(hevc) &
+ H265_DEBUG_BUFMGR) {
+ hevc_print_cont(hevc, 0,
+ "{y=%d, x=%d w %d h %d ",
+ i, j, hevc->m_tile[i][j].width,
+ hevc->m_tile[i][j].height);
+ hevc_print_cont(hevc, 0,
+ "start_x %d start_y %d ",
+ hevc->m_tile[i][j].start_cu_x,
+ hevc->m_tile[i][j].start_cu_y);
+ hevc_print_cont(hevc, 0,
+ "sao_vb_start 0x%x ",
+ hevc->m_tile[i][j].
+ sao_vb_start_addr);
+ hevc_print_cont(hevc, 0,
+ "sao_abv_start 0x%x}\n",
+ hevc->m_tile[i][j].
+ sao_abv_start_addr);
+
+ }
+ start_cu_x += hevc->m_tile[i][j].width;
+ }
+ start_cu_y += hevc->m_tile[i][0].height;
+ }
+ }
+ } else {
+ hevc->num_tile_col = 1;
+ hevc->num_tile_row = 1;
+ hevc->m_tile[0][0].width = pic_width_cu;
+ hevc->m_tile[0][0].height = pic_height_cu;
+ hevc->m_tile[0][0].start_cu_x = 0;
+ hevc->m_tile[0][0].start_cu_y = 0;
+ hevc->m_tile[0][0].sao_vb_start_addr =
+ hevc->work_space_buf->sao_vb.buf_start;
+ hevc->m_tile[0][0].sao_abv_start_addr =
+ hevc->work_space_buf->sao_abv.buf_start;
+ }
+}
+
+static int get_tile_index(struct hevc_state_s *hevc, int cu_adr,
+ int pic_width_lcu)
+{
+ int cu_x;
+ int cu_y;
+ int tile_x = 0;
+ int tile_y = 0;
+ int i;
+
+ if (pic_width_lcu == 0) {
+ if (get_dbg_flag(hevc)) {
+ hevc_print(hevc, 0,
+ "%s Error, pic_width_lcu is 0, pic_w %d, pic_h %d\n",
+ __func__, hevc->pic_w, hevc->pic_h);
+ }
+ return -1;
+ }
+ cu_x = cu_adr % pic_width_lcu;
+ cu_y = cu_adr / pic_width_lcu;
+ if (hevc->tile_enabled) {
+ for (i = 0; i < hevc->num_tile_col; i++) {
+ if (cu_x >= hevc->m_tile[0][i].start_cu_x)
+ tile_x = i;
+ else
+ break;
+ }
+ for (i = 0; i < hevc->num_tile_row; i++) {
+ if (cu_y >= hevc->m_tile[i][0].start_cu_y)
+ tile_y = i;
+ else
+ break;
+ }
+ }
+ return (tile_x) | (tile_y << 8);
+}
+
+static void print_scratch_error(int error_num)
+{
+#if 0
+ if (get_dbg_flag(hevc)) {
+ hevc_print(hevc, 0,
+ " ERROR : HEVC_ASSIST_SCRATCH_TEST Error : %d\n",
+ error_num);
+ }
+#endif
+}
+
+static void hevc_config_work_space_hw(struct hevc_state_s *hevc)
+{
+ struct BuffInfo_s *buf_spec = hevc->work_space_buf;
+
+ if (get_dbg_flag(hevc))
+ hevc_print(hevc, H265_DEBUG_BUFMGR_MORE,
+ "%s %x %x %x %x %x %x %x %x %x %x %x %x %x\n",
+ __func__,
+ buf_spec->ipp.buf_start,
+ buf_spec->start_adr,
+ buf_spec->short_term_rps.buf_start,
+ buf_spec->vps.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 ((get_dbg_flag(hevc) & H265_DEBUG_SEND_PARAM_WITH_REG) == 0)
+ WRITE_VREG(HEVC_RPM_BUFFER, (u32)hevc->rpm_phy_addr);
+ WRITE_VREG(HEVC_SHORT_TERM_RPS, buf_spec->short_term_rps.buf_start);
+ WRITE_VREG(HEVC_VPS_BUFFER, buf_spec->vps.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);
+ if (hevc->mmu_enable) {
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) {
+ WRITE_VREG(HEVC_ASSIST_MMU_MAP_ADDR, hevc->frame_mmu_map_phy_addr);
+ hevc_print(hevc, H265_DEBUG_BUFMGR_MORE,
+ "write HEVC_ASSIST_MMU_MAP_ADDR\n");
+ } else
+ WRITE_VREG(H265_MMU_MAP_BUFFER, hevc->frame_mmu_map_phy_addr);
+ } /*else
+ WRITE_VREG(HEVC_STREAM_SWAP_BUFFER,
+ buf_spec->swap_buf.buf_start);
+ WRITE_VREG(HEVC_STREAM_SWAP_BUFFER2, buf_spec->swap_buf2.buf_start);*/
+ WRITE_VREG(HEVC_SCALELUT, buf_spec->scalelut.buf_start);
+#ifdef HEVC_8K_LFTOFFSET_FIX
+ 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, 0x4010);
+ else
+ WRITE_VREG(HEVC_DBLK_CFG3, 0x8020);
+ //WRITE_VREG(HEVC_DBLK_CFG3, 0x808020); /*offset should x2 if 8k*/
+ hevc_print(hevc, H265_DEBUG_BUFMGR_MORE,
+ "write HEVC_DBLK_CFG3 to %x\n", READ_VREG(HEVC_DBLK_CFG3));
+ }
+#endif
+ /* 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);
+
+ WRITE_VREG(LMEM_DUMP_ADR, (u32)hevc->lmem_phy_addr);
+}
+
+static void parser_cmd_write(void)
+{
+ u32 i;
+ const 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
+ };
+ for (i = 0; i < PARSER_CMD_NUMBER; i++)
+ WRITE_VREG(HEVC_PARSER_CMD_WRITE, parser_cmd[i]);
+}
+
+static void hevc_init_decoder_hw(struct hevc_state_s *hevc,
+ int decode_pic_begin, int decode_pic_num)
+{
+ unsigned int data32;
+ int i;
+#if 0
+ if (get_cpu_major_id() >= MESON_CPU_MAJOR_ID_G12A) {
+ /* Set MCR fetch priorities*/
+ data32 = 0x1 | (0x1 << 2) | (0x1 <<3) |
+ (24 << 4) | (32 << 11) | (24 << 18) | (32 << 25);
+ WRITE_VREG(HEVCD_MPP_DECOMP_AXIURG_CTL, data32);
+ }
+#endif
+#if 1
+ /* m8baby test1902 */
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ hevc_print(hevc, 0,
+ "%s\n", __func__);
+ data32 = READ_VREG(HEVC_PARSER_VERSION);
+ if (data32 != 0x00010001) {
+ print_scratch_error(25);
+ return;
+ }
+ WRITE_VREG(HEVC_PARSER_VERSION, 0x5a5a55aa);
+ data32 = READ_VREG(HEVC_PARSER_VERSION);
+ if (data32 != 0x5a5a55aa) {
+ print_scratch_error(26);
+ return;
+ }
+#if 0
+ /* test Parser Reset */
+ /* reset iqit to start mem init again */
+ WRITE_VREG(DOS_SW_RESET3, (1 << 14) |
+ (1 << 3) /* reset_whole parser */
+ );
+ WRITE_VREG(DOS_SW_RESET3, 0); /* clear reset_whole parser */
+ data32 = READ_VREG(HEVC_PARSER_VERSION);
+ if (data32 != 0x00010001)
+ hevc_print(hevc, 0,
+ "Test Parser Fatal Error\n");
+#endif
+ /* reset iqit to start mem init again */
+ WRITE_VREG(DOS_SW_RESET3, (1 << 14)
+ );
+ CLEAR_VREG_MASK(HEVC_CABAC_CONTROL, 1);
+ CLEAR_VREG_MASK(HEVC_PARSER_CORE_CONTROL, 1);
+
+#endif
+ if (!hevc->m_ins_flag) {
+ data32 = READ_VREG(HEVC_STREAM_CONTROL);
+ data32 = data32 | (1 << 0); /* stream_fetch_enable */
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
+ data32 |= (0xf << 25); /*arwlen_axi_max*/
+ WRITE_VREG(HEVC_STREAM_CONTROL, data32);
+ }
+ data32 = READ_VREG(HEVC_SHIFT_STARTCODE);
+ if (data32 != 0x00000100) {
+ print_scratch_error(29);
+ return;
+ }
+ data32 = READ_VREG(HEVC_SHIFT_EMULATECODE);
+ if (data32 != 0x00000300) {
+ print_scratch_error(30);
+ return;
+ }
+ WRITE_VREG(HEVC_SHIFT_STARTCODE, 0x12345678);
+ WRITE_VREG(HEVC_SHIFT_EMULATECODE, 0x9abcdef0);
+ data32 = READ_VREG(HEVC_SHIFT_STARTCODE);
+ if (data32 != 0x12345678) {
+ print_scratch_error(31);
+ return;
+ }
+ data32 = READ_VREG(HEVC_SHIFT_EMULATECODE);
+ if (data32 != 0x9abcdef0) {
+ print_scratch_error(32);
+ return;
+ }
+ WRITE_VREG(HEVC_SHIFT_STARTCODE, 0x00000100);
+ WRITE_VREG(HEVC_SHIFT_EMULATECODE, 0x00000300);
+
+ data32 = READ_VREG(HEVC_PARSER_INT_CONTROL);
+ data32 &= 0x03ffffff;
+ data32 = data32 | (3 << 29) | (2 << 26) | (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 | (1 << 1) | /* emulation_check_on */
+ (1 << 0) /* startcode_check_on */
+ ;
+ WRITE_VREG(HEVC_SHIFT_STATUS, data32);
+
+ WRITE_VREG(HEVC_SHIFT_CONTROL, (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_CABAC_CONTROL, (1 << 0) /* cabac_enable */
+ );
+ /* hevc_parser_core_clk_en */
+ WRITE_VREG(HEVC_PARSER_CORE_CONTROL, (1 << 0)
+ );
+
+ WRITE_VREG(HEVC_DEC_STATUS_REG, 0);
+
+ /* Initial IQIT_SCALELUT memory -- just to avoid X in simulation */
+ WRITE_VREG(HEVC_IQIT_SCALELUT_WR_ADDR, 0); /* cfg_p_addr */
+ for (i = 0; i < 1024; i++)
+ WRITE_VREG(HEVC_IQIT_SCALELUT_DATA, 0);
+
+#ifdef ENABLE_SWAP_TEST
+ WRITE_VREG(HEVC_STREAM_SWAP_TEST, 100);
+#endif
+
+ /*WRITE_VREG(HEVC_DECODE_PIC_BEGIN_REG, 0);*/
+ /*WRITE_VREG(HEVC_DECODE_PIC_NUM_REG, 0xffffffff);*/
+ 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));
+
+ parser_cmd_write();
+
+ 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 << 8) | // sao_sw_pred_enable */
+ (1 << 5) | /* parser_sao_if_en */
+ (1 << 2) | /* parser_mpred_if_en */
+ (1 << 0) /* parser_scaler_if_en */
+ );
+
+ /* Changed to Start MPRED in microcode */
+ /*
+ * hevc_print(hevc, 0, "[test.c] Start MPRED\n");
+ * WRITE_VREG(HEVC_MPRED_INT_STATUS,
+ * (1<<31)
+ * );
+ */
+
+ 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 (get_double_write_mode(hevc) & 0x10)
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1,
+ 0x1 << 31 /*/Enable NV21 reference read mode for MC*/
+ );
+
+}
+
+static void decoder_hw_reset(void)
+{
+ int i;
+ unsigned int data32;
+
+ /* reset iqit to start mem init again */
+ WRITE_VREG(DOS_SW_RESET3, (1 << 14)
+ );
+ CLEAR_VREG_MASK(HEVC_CABAC_CONTROL, 1);
+ CLEAR_VREG_MASK(HEVC_PARSER_CORE_CONTROL, 1);
+
+ data32 = READ_VREG(HEVC_STREAM_CONTROL);
+ data32 = data32 | (1 << 0) /* stream_fetch_enable */
+ ;
+ WRITE_VREG(HEVC_STREAM_CONTROL, data32);
+
+ data32 = READ_VREG(HEVC_SHIFT_STARTCODE);
+ if (data32 != 0x00000100) {
+ print_scratch_error(29);
+ return;
+ }
+ data32 = READ_VREG(HEVC_SHIFT_EMULATECODE);
+ if (data32 != 0x00000300) {
+ print_scratch_error(30);
+ return;
+ }
+ WRITE_VREG(HEVC_SHIFT_STARTCODE, 0x12345678);
+ WRITE_VREG(HEVC_SHIFT_EMULATECODE, 0x9abcdef0);
+ data32 = READ_VREG(HEVC_SHIFT_STARTCODE);
+ if (data32 != 0x12345678) {
+ print_scratch_error(31);
+ return;
+ }
+ data32 = READ_VREG(HEVC_SHIFT_EMULATECODE);
+ if (data32 != 0x9abcdef0) {
+ print_scratch_error(32);
+ return;
+ }
+ WRITE_VREG(HEVC_SHIFT_STARTCODE, 0x00000100);
+ WRITE_VREG(HEVC_SHIFT_EMULATECODE, 0x00000300);
+
+ data32 = READ_VREG(HEVC_PARSER_INT_CONTROL);
+ data32 &= 0x03ffffff;
+ data32 = data32 | (3 << 29) | (2 << 26) | (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 | (1 << 1) | /* emulation_check_on */
+ (1 << 0) /* startcode_check_on */
+ ;
+ WRITE_VREG(HEVC_SHIFT_STATUS, data32);
+
+ WRITE_VREG(HEVC_SHIFT_CONTROL, (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_CABAC_CONTROL, (1 << 0) /* cabac_enable */
+ );
+ /* hevc_parser_core_clk_en */
+ WRITE_VREG(HEVC_PARSER_CORE_CONTROL, (1 << 0)
+ );
+
+ /* Initial IQIT_SCALELUT memory -- just to avoid X in simulation */
+ WRITE_VREG(HEVC_IQIT_SCALELUT_WR_ADDR, 0); /* cfg_p_addr */
+ for (i = 0; i < 1024; i++)
+ WRITE_VREG(HEVC_IQIT_SCALELUT_DATA, 0);
+
+ /* Send parser_cmd */
+ WRITE_VREG(HEVC_PARSER_CMD_WRITE, (1 << 16) | (0 << 0));
+
+ parser_cmd_write();
+
+ 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 << 8) | // sao_sw_pred_enable */
+ (1 << 5) | /* parser_sao_if_en */
+ (1 << 2) | /* parser_mpred_if_en */
+ (1 << 0) /* parser_scaler_if_en */
+ );
+
+ 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 */
+ );
+
+}
+
+#ifdef CONFIG_HEVC_CLK_FORCED_ON
+static void config_hevc_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 | (0x3 << 5) | (0x3 << 2) | (0x3 << 0));
+
+ /* 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
+
+#ifdef MCRCC_ENABLE
+static void config_mcrcc_axi_hw(struct hevc_state_s *hevc, int slice_type)
+{
+ unsigned int rdata32;
+ unsigned int rdata32_2;
+ int l0_cnt = 0;
+ int l1_cnt = 0x7fff;
+
+ if (get_double_write_mode(hevc) & 0x10) {
+ l0_cnt = hevc->cur_pic->RefNum_L0;
+ l1_cnt = hevc->cur_pic->RefNum_L1;
+ }
+
+ WRITE_VREG(HEVCD_MCRCC_CTL1, 0x2); /* reset mcrcc */
+
+ if (slice_type == 2) { /* I-PIC */
+ /* remove reset -- disables clock */
+ WRITE_VREG(HEVCD_MCRCC_CTL1, 0x0);
+ return;
+ }
+
+ if (slice_type == 0) { /* B-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 && l1_cnt > 1) {
+ 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);
+
+ if (l0_cnt == 1) {
+ WRITE_VREG(HEVCD_MCRCC_CTL3, rdata32);
+ } else {
+ /* 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);
+}
+#endif
+
+static void config_title_hw(struct hevc_state_s *hevc, int sao_vb_size,
+ int sao_mem_unit)
+{
+ WRITE_VREG(HEVC_sao_mem_unit, sao_mem_unit);
+ WRITE_VREG(HEVC_SAO_ABV, hevc->work_space_buf->sao_abv.buf_start);
+ WRITE_VREG(HEVC_sao_vb_size, sao_vb_size);
+ WRITE_VREG(HEVC_SAO_VB, hevc->work_space_buf->sao_vb.buf_start);
+}
+
+static u32 init_aux_size;
+static int aux_data_is_avaible(struct hevc_state_s *hevc)
+{
+ u32 reg_val;
+
+ reg_val = READ_VREG(HEVC_AUX_DATA_SIZE);
+ if (reg_val != 0 && reg_val != init_aux_size)
+ return 1;
+ else
+ return 0;
+}
+
+static void config_aux_buf(struct hevc_state_s *hevc)
+{
+ WRITE_VREG(HEVC_AUX_ADR, hevc->aux_phy_addr);
+ init_aux_size = ((hevc->prefix_aux_size >> 4) << 16) |
+ (hevc->suffix_aux_size >> 4);
+ WRITE_VREG(HEVC_AUX_DATA_SIZE, init_aux_size);
+}
+
+static void config_mpred_hw(struct hevc_state_s *hevc)
+{
+ int i;
+ unsigned int data32;
+ struct PIC_s *cur_pic = hevc->cur_pic;
+ struct PIC_s *col_pic = hevc->col_pic;
+ int AMVP_MAX_NUM_CANDS_MEM = 3;
+ int AMVP_MAX_NUM_CANDS = 2;
+ int NUM_CHROMA_MODE = 5;
+ int DM_CHROMA_IDX = 36;
+ int above_ptr_ctrl = 0;
+ int buffer_linear = 1;
+ int cu_size_log2 = 3;
+
+ int mpred_mv_rd_start_addr;
+ int mpred_curr_lcu_x;
+ int mpred_curr_lcu_y;
+ int mpred_above_buf_start;
+ int mpred_mv_rd_ptr;
+ int mpred_mv_rd_ptr_p1;
+ int mpred_mv_rd_end_addr;
+ int MV_MEM_UNIT;
+ int mpred_mv_wr_ptr;
+ int *ref_poc_L0, *ref_poc_L1;
+
+ int above_en;
+ int mv_wr_en;
+ int mv_rd_en;
+ int col_isIntra;
+
+ if (hevc->slice_type != 2) {
+ 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 =
+ hevc->lcu_size_log2 == 6 ? 0x200 : hevc->lcu_size_log2 ==
+ 5 ? 0x80 : 0x20;
+ mpred_mv_rd_ptr =
+ mpred_mv_rd_start_addr + (hevc->slice_addr * MV_MEM_UNIT);
+
+ mpred_mv_rd_ptr_p1 = mpred_mv_rd_ptr + MV_MEM_UNIT;
+ mpred_mv_rd_end_addr =
+ mpred_mv_rd_start_addr +
+ col_pic->mv_size;
+ //((hevc->lcu_x_num * hevc->lcu_y_num) * MV_MEM_UNIT);
+
+ mpred_above_buf_start = hevc->work_space_buf->mpred_above.buf_start;
+
+ mpred_mv_wr_ptr =
+ cur_pic->mpred_mv_wr_start_addr +
+ (hevc->slice_addr * MV_MEM_UNIT);
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "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, mpred_mv_rd_start_addr);
+
+ data32 = ((hevc->lcu_x_num - hevc->tile_width_lcu) * MV_MEM_UNIT);
+ WRITE_VREG(HEVC_MPRED_MV_WR_ROW_JUMP, data32);
+ WRITE_VREG(HEVC_MPRED_MV_RD_ROW_JUMP, data32);
+
+ data32 = READ_VREG(HEVC_MPRED_CTRL0);
+ data32 = ((hevc->slice_type & 3) |
+ (hevc->new_pic & 1) << 2 |
+ (hevc->new_tile & 1) << 3 |
+ (hevc->isNextSliceSegment & 1)<< 4 |
+ (hevc->TMVPFlag & 1)<< 5 |
+ (hevc->LDCFlag & 1) << 6 |
+ (hevc->ColFromL0Flag & 1)<< 7 |
+ (above_ptr_ctrl & 1)<< 8 |
+ (above_en & 1) << 9 |
+ (mv_wr_en & 1) << 10 |
+ (mv_rd_en & 1)<< 11 |
+ (col_isIntra & 1)<< 12 |
+ (buffer_linear & 1)<< 13 |
+ (hevc->LongTerm_Curr & 1) << 14 |
+ (hevc->LongTerm_Col & 1) << 15 |
+ (hevc->lcu_size_log2 & 0xf) << 16 |
+ (cu_size_log2 & 0xf) << 20 | (hevc->plevel & 0x7) << 24);
+ data32 &= ~(1<< 28);
+ WRITE_VREG(HEVC_MPRED_CTRL0, data32);
+
+ data32 = READ_VREG(HEVC_MPRED_CTRL1);
+ data32 = (
+#if 0
+ /* no set in m8baby test1902 */
+ /* Don't override clk_forced_on , */
+ (data32 & (0x1 << 24)) |
+#endif
+ hevc->MaxNumMergeCand |
+ AMVP_MAX_NUM_CANDS << 4 |
+ AMVP_MAX_NUM_CANDS_MEM << 8 |
+ NUM_CHROMA_MODE << 12 | DM_CHROMA_IDX << 16);
+ WRITE_VREG(HEVC_MPRED_CTRL1, data32);
+
+ data32 = (hevc->pic_w | hevc->pic_h << 16);
+ WRITE_VREG(HEVC_MPRED_PIC_SIZE, data32);
+
+ data32 = ((hevc->lcu_x_num - 1) | (hevc->lcu_y_num - 1) << 16);
+ WRITE_VREG(HEVC_MPRED_PIC_SIZE_LCU, data32);
+
+ data32 = (hevc->tile_start_lcu_x | hevc->tile_start_lcu_y << 16);
+ WRITE_VREG(HEVC_MPRED_TILE_START, data32);
+
+ data32 = (hevc->tile_width_lcu | hevc->tile_height_lcu << 16);
+ WRITE_VREG(HEVC_MPRED_TILE_SIZE_LCU, data32);
+
+ data32 = (hevc->RefNum_L0 | hevc->RefNum_L1 << 8 | 0
+ /* col_RefNum_L0<<16| */
+ /* col_RefNum_L1<<24 */
+ );
+ WRITE_VREG(HEVC_MPRED_REF_NUM, data32);
+
+#ifdef SUPPORT_LONG_TERM_RPS
+ data32 = 0;
+ for (i = 0; i < hevc->RefNum_L0; i++) {
+ if (is_ref_long_term(hevc,
+ cur_pic->m_aiRefPOCList0
+ [cur_pic->slice_idx][i]))
+ data32 = data32 | (1 << i);
+ }
+ for (i = 0; i < hevc->RefNum_L1; i++) {
+ if (is_ref_long_term(hevc,
+ cur_pic->m_aiRefPOCList1
+ [cur_pic->slice_idx][i]))
+ data32 = data32 | (1 << (i + 16));
+ }
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "LongTerm_Ref 0x%x\n", data32);
+ }
+#else
+ data32 = hevc->LongTerm_Ref;
+#endif
+ WRITE_VREG(HEVC_MPRED_LT_REF, data32);
+
+ data32 = 0;
+ for (i = 0; i < hevc->RefNum_L0; i++)
+ data32 = data32 | (1 << i);
+ WRITE_VREG(HEVC_MPRED_REF_EN_L0, data32);
+
+ data32 = 0;
+ for (i = 0; i < hevc->RefNum_L1; i++)
+ data32 = data32 | (1 << i);
+ WRITE_VREG(HEVC_MPRED_REF_EN_L1, data32);
+
+ WRITE_VREG(HEVC_MPRED_CUR_POC, hevc->curr_POC);
+ WRITE_VREG(HEVC_MPRED_COL_POC, hevc->Col_POC);
+
+ /* below MPRED Ref_POC_xx_Lx registers must follow Ref_POC_xx_L0 ->
+ * Ref_POC_xx_L1 in pair write order!!!
+ */
+ ref_poc_L0 = &(cur_pic->m_aiRefPOCList0[cur_pic->slice_idx][0]);
+ ref_poc_L1 = &(cur_pic->m_aiRefPOCList1[cur_pic->slice_idx][0]);
+
+ WRITE_VREG(HEVC_MPRED_L0_REF00_POC, ref_poc_L0[0]);
+ WRITE_VREG(HEVC_MPRED_L1_REF00_POC, ref_poc_L1[0]);
+
+ WRITE_VREG(HEVC_MPRED_L0_REF01_POC, ref_poc_L0[1]);
+ WRITE_VREG(HEVC_MPRED_L1_REF01_POC, ref_poc_L1[1]);
+
+ WRITE_VREG(HEVC_MPRED_L0_REF02_POC, ref_poc_L0[2]);
+ WRITE_VREG(HEVC_MPRED_L1_REF02_POC, ref_poc_L1[2]);
+
+ WRITE_VREG(HEVC_MPRED_L0_REF03_POC, ref_poc_L0[3]);
+ WRITE_VREG(HEVC_MPRED_L1_REF03_POC, ref_poc_L1[3]);
+
+ WRITE_VREG(HEVC_MPRED_L0_REF04_POC, ref_poc_L0[4]);
+ WRITE_VREG(HEVC_MPRED_L1_REF04_POC, ref_poc_L1[4]);
+
+ WRITE_VREG(HEVC_MPRED_L0_REF05_POC, ref_poc_L0[5]);
+ WRITE_VREG(HEVC_MPRED_L1_REF05_POC, ref_poc_L1[5]);
+
+ WRITE_VREG(HEVC_MPRED_L0_REF06_POC, ref_poc_L0[6]);
+ WRITE_VREG(HEVC_MPRED_L1_REF06_POC, ref_poc_L1[6]);
+
+ WRITE_VREG(HEVC_MPRED_L0_REF07_POC, ref_poc_L0[7]);
+ WRITE_VREG(HEVC_MPRED_L1_REF07_POC, ref_poc_L1[7]);
+
+ WRITE_VREG(HEVC_MPRED_L0_REF08_POC, ref_poc_L0[8]);
+ WRITE_VREG(HEVC_MPRED_L1_REF08_POC, ref_poc_L1[8]);
+
+ WRITE_VREG(HEVC_MPRED_L0_REF09_POC, ref_poc_L0[9]);
+ WRITE_VREG(HEVC_MPRED_L1_REF09_POC, ref_poc_L1[9]);
+
+ WRITE_VREG(HEVC_MPRED_L0_REF10_POC, ref_poc_L0[10]);
+ WRITE_VREG(HEVC_MPRED_L1_REF10_POC, ref_poc_L1[10]);
+
+ WRITE_VREG(HEVC_MPRED_L0_REF11_POC, ref_poc_L0[11]);
+ WRITE_VREG(HEVC_MPRED_L1_REF11_POC, ref_poc_L1[11]);
+
+ WRITE_VREG(HEVC_MPRED_L0_REF12_POC, ref_poc_L0[12]);
+ WRITE_VREG(HEVC_MPRED_L1_REF12_POC, ref_poc_L1[12]);
+
+ WRITE_VREG(HEVC_MPRED_L0_REF13_POC, ref_poc_L0[13]);
+ WRITE_VREG(HEVC_MPRED_L1_REF13_POC, ref_poc_L1[13]);
+
+ WRITE_VREG(HEVC_MPRED_L0_REF14_POC, ref_poc_L0[14]);
+ WRITE_VREG(HEVC_MPRED_L1_REF14_POC, ref_poc_L1[14]);
+
+ WRITE_VREG(HEVC_MPRED_L0_REF15_POC, ref_poc_L0[15]);
+ WRITE_VREG(HEVC_MPRED_L1_REF15_POC, ref_poc_L1[15]);
+
+ if (hevc->new_pic) {
+ WRITE_VREG(HEVC_MPRED_ABV_START_ADDR, mpred_above_buf_start);
+ WRITE_VREG(HEVC_MPRED_MV_WPTR, mpred_mv_wr_ptr);
+ /* WRITE_VREG(HEVC_MPRED_MV_RPTR,mpred_mv_rd_ptr); */
+ WRITE_VREG(HEVC_MPRED_MV_RPTR, mpred_mv_rd_start_addr);
+ } else if (!hevc->isNextSliceSegment) {
+ /* WRITE_VREG(HEVC_MPRED_MV_RPTR,mpred_mv_rd_ptr_p1); */
+ WRITE_VREG(HEVC_MPRED_MV_RPTR, mpred_mv_rd_ptr);
+ }
+
+ WRITE_VREG(HEVC_MPRED_MV_RD_END_ADDR, mpred_mv_rd_end_addr);
+}
+
+static void config_sao_hw(struct hevc_state_s *hevc, union param_u *params)
+{
+ unsigned int data32, data32_2;
+ int misc_flag0 = hevc->misc_flag0;
+ int slice_deblocking_filter_disabled_flag = 0;
+
+ int mc_buffer_size_u_v =
+ hevc->lcu_total * hevc->lcu_size * hevc->lcu_size / 2;
+ int mc_buffer_size_u_v_h = (mc_buffer_size_u_v + 0xffff) >> 16;
+ struct PIC_s *cur_pic = hevc->cur_pic;
+ struct aml_vcodec_ctx * v4l2_ctx = hevc->v4l2_ctx;
+
+ data32 = READ_VREG(HEVC_SAO_CTRL0);
+ data32 &= (~0xf);
+ data32 |= hevc->lcu_size_log2;
+ WRITE_VREG(HEVC_SAO_CTRL0, data32);
+
+ data32 = (hevc->pic_w | hevc->pic_h << 16);
+ WRITE_VREG(HEVC_SAO_PIC_SIZE, data32);
+
+ data32 = ((hevc->lcu_x_num - 1) | (hevc->lcu_y_num - 1) << 16);
+ WRITE_VREG(HEVC_SAO_PIC_SIZE_LCU, data32);
+
+ if (hevc->new_pic)
+ WRITE_VREG(HEVC_SAO_Y_START_ADDR, 0xffffffff);
+#ifdef LOSLESS_COMPRESS_MODE
+/*SUPPORT_10BIT*/
+ if ((get_double_write_mode(hevc) & 0x10) == 0) {
+ data32 = READ_VREG(HEVC_SAO_CTRL5);
+ data32 &= (~(0xff << 16));
+
+ if (get_double_write_mode(hevc) == 2 ||
+ get_double_write_mode(hevc) == 3)
+ data32 |= (0xff<<16);
+ else if (get_double_write_mode(hevc) == 4 ||
+ get_double_write_mode(hevc) == 5)
+ data32 |= (0x33<<16);
+
+ if (hevc->mem_saving_mode == 1)
+ data32 |= (1 << 9);
+ else
+ data32 &= ~(1 << 9);
+ if (workaround_enable & 1)
+ data32 |= (1 << 7);
+ WRITE_VREG(HEVC_SAO_CTRL5, data32);
+ }
+ data32 = cur_pic->mc_y_adr;
+ if (get_double_write_mode(hevc))
+ WRITE_VREG(HEVC_SAO_Y_START_ADDR, cur_pic->dw_y_adr);
+
+ if ((get_double_write_mode(hevc) & 0x10) == 0)
+ WRITE_VREG(HEVC_CM_BODY_START_ADDR, data32);
+
+ if (hevc->mmu_enable)
+ WRITE_VREG(HEVC_CM_HEADER_START_ADDR, cur_pic->header_adr);
+#else
+ data32 = cur_pic->mc_y_adr;
+ WRITE_VREG(HEVC_SAO_Y_START_ADDR, data32);
+#endif
+ data32 = (mc_buffer_size_u_v_h << 16) << 1;
+ WRITE_VREG(HEVC_SAO_Y_LENGTH, data32);
+
+#ifdef LOSLESS_COMPRESS_MODE
+/*SUPPORT_10BIT*/
+ if (get_double_write_mode(hevc))
+ WRITE_VREG(HEVC_SAO_C_START_ADDR, cur_pic->dw_u_v_adr);
+#else
+ data32 = cur_pic->mc_u_v_adr;
+ WRITE_VREG(HEVC_SAO_C_START_ADDR, data32);
+#endif
+ data32 = (mc_buffer_size_u_v_h << 16);
+ WRITE_VREG(HEVC_SAO_C_LENGTH, data32);
+
+#ifdef LOSLESS_COMPRESS_MODE
+/*SUPPORT_10BIT*/
+ if (get_double_write_mode(hevc)) {
+ WRITE_VREG(HEVC_SAO_Y_WPTR, cur_pic->dw_y_adr);
+ WRITE_VREG(HEVC_SAO_C_WPTR, cur_pic->dw_u_v_adr);
+ }
+#else
+ /* multi tile to do... */
+ data32 = cur_pic->mc_y_adr;
+ WRITE_VREG(HEVC_SAO_Y_WPTR, data32);
+
+ data32 = cur_pic->mc_u_v_adr;
+ WRITE_VREG(HEVC_SAO_C_WPTR, data32);
+#endif
+ /* DBLK CONFIG HERE */
+ if (hevc->new_pic) {
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) {
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1)
+ data32 = (0xff << 8) | (0x0 << 0);
+ else
+ data32 = (0x57 << 8) | /* 1st/2nd write both enable*/
+ (0x0 << 0); /* h265 video format*/
+
+ if (hevc->pic_w >= 1280)
+ data32 |= (0x1 << 4); /*dblk pipeline mode=1 for performance*/
+ data32 &= (~0x300); /*[8]:first write enable (compress) [9]:double write enable (uncompress)*/
+ if (get_double_write_mode(hevc) == 0)
+ data32 |= (0x1 << 8); /*enable first write*/
+ else if (get_double_write_mode(hevc) == 0x10)
+ data32 |= (0x1 << 9); /*double write only*/
+ else
+ data32 |= ((0x1 << 8) |(0x1 << 9));
+
+ WRITE_VREG(HEVC_DBLK_CFGB, data32);
+ hevc_print(hevc, H265_DEBUG_BUFMGR_MORE,
+ "[DBLK DEBUG] HEVC1 CFGB : 0x%x\n", data32);
+ }
+ data32 = (hevc->pic_w | hevc->pic_h << 16);
+ WRITE_VREG(HEVC_DBLK_CFG2, data32);
+
+ if ((misc_flag0 >> PCM_ENABLE_FLAG_BIT) & 0x1) {
+ data32 =
+ ((misc_flag0 >>
+ PCM_LOOP_FILTER_DISABLED_FLAG_BIT) &
+ 0x1) << 3;
+ } else
+ data32 = 0;
+ data32 |=
+ (((params->p.pps_cb_qp_offset & 0x1f) << 4) |
+ ((params->p.pps_cr_qp_offset
+ & 0x1f) <<
+ 9));
+ data32 |=
+ (hevc->lcu_size ==
+ 64) ? 0 : ((hevc->lcu_size == 32) ? 1 : 2);
+
+ WRITE_VREG(HEVC_DBLK_CFG1, data32);
+
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) {
+ /*if (debug & 0x80) {*/
+ data32 = 1 << 28; /* Debug only: sts1 chooses dblk_main*/
+ WRITE_VREG(HEVC_DBLK_STS1 + 4, data32); /* 0x3510 */
+ hevc_print(hevc, H265_DEBUG_BUFMGR_MORE,
+ "[DBLK DEBUG] HEVC1 STS1 : 0x%x\n",
+ data32);
+ /*}*/
+ }
+ }
+#if 0
+ data32 = READ_VREG(HEVC_SAO_CTRL1);
+ data32 &= (~0x3000);
+ data32 |= (hevc->mem_map_mode <<
+ 12);
+
+/* [13:12] axi_aformat,
+ * 0-Linear, 1-32x32, 2-64x32
+ */
+ WRITE_VREG(HEVC_SAO_CTRL1, data32);
+
+ data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG);
+ data32 &= (~0x30);
+ data32 |= (hevc->mem_map_mode <<
+ 4);
+
+/* [5:4] -- address_format
+ * 00:linear 01:32x32 10:64x32
+ */
+ WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32);
+#else
+ /* m8baby test1902 */
+ data32 = READ_VREG(HEVC_SAO_CTRL1);
+ data32 &= (~0x3000);
+ data32 |= (hevc->mem_map_mode <<
+ 12);
+
+/* [13:12] axi_aformat, 0-Linear,
+ * 1-32x32, 2-64x32
+ */
+ data32 &= (~0xff0);
+ /* data32 |= 0x670; // Big-Endian per 64-bit */
+ data32 |= endian; /* Big-Endian per 64-bit */
+ data32 &= (~0x3); /*[1]:dw_disable [0]:cm_disable*/
+ if (get_double_write_mode(hevc) == 0)
+ data32 |= 0x2; /*disable double write*/
+ else if (get_double_write_mode(hevc) & 0x10)
+ data32 |= 0x1; /*disable cm*/
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) {
+ unsigned int data;
+ data = (0x57 << 8) | /* 1st/2nd write both enable*/
+ (0x0 << 0); /* h265 video format*/
+ if (hevc->pic_w >= 1280)
+ data |= (0x1 << 4); /*dblk pipeline mode=1 for performance*/
+ data &= (~0x300); /*[8]:first write enable (compress) [9]:double write enable (uncompress)*/
+ if (get_double_write_mode(hevc) == 0)
+ data |= (0x1 << 8); /*enable first write*/
+ else if (get_double_write_mode(hevc) & 0x10)
+ data |= (0x1 << 9); /*double write only*/
+ else
+ data |= ((0x1 << 8) |(0x1 << 9));
+ WRITE_VREG(HEVC_DBLK_CFGB, data);
+ hevc_print(hevc, H265_DEBUG_BUFMGR_MORE,
+ "[DBLK DEBUG] HEVC1 CFGB : 0x%x\n", data);
+ }
+
+ /* swap uv */
+ if (hevc->is_used_v4l) {
+ if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV21) ||
+ (v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV21M))
+ data32 &= ~(1 << 8); /* NV21 */
+ else
+ data32 |= (1 << 8); /* NV12 */
+ }
+
+ /*
+ * [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(hevc) & 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);
+ }
+
+ data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG);
+ data32 &= (~0x30);
+ /* [5:4] -- address_format 00:linear 01:32x32 10:64x32 */
+ data32 |= (hevc->mem_map_mode <<
+ 4);
+ data32 &= (~0xF);
+ data32 |= 0xf; /* valid only when double write only */
+ /*data32 |= 0x8;*/ /* Big-Endian per 64-bit */
+
+ /* swap uv */
+ if (hevc->is_used_v4l) {
+ if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV21) ||
+ (v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV21M))
+ data32 |= (1 << 12); /* NV21 */
+ else
+ data32 &= ~(1 << 12); /* NV12 */
+ }
+
+ /*
+ * [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
+ */
+ WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32);
+#endif
+ data32 = 0;
+ data32_2 = READ_VREG(HEVC_SAO_CTRL0);
+ data32_2 &= (~0x300);
+ /* slice_deblocking_filter_disabled_flag = 0;
+ * ucode has handle it , so read it from ucode directly
+ */
+ if (hevc->tile_enabled) {
+ data32 |=
+ ((misc_flag0 >>
+ LOOP_FILER_ACROSS_TILES_ENABLED_FLAG_BIT) &
+ 0x1) << 0;
+ data32_2 |=
+ ((misc_flag0 >>
+ LOOP_FILER_ACROSS_TILES_ENABLED_FLAG_BIT) &
+ 0x1) << 8;
+ }
+ slice_deblocking_filter_disabled_flag = (misc_flag0 >>
+ SLICE_DEBLOCKING_FILTER_DISABLED_FLAG_BIT) &
+ 0x1; /* ucode has handle it,so read it from ucode directly */
+ if ((misc_flag0 & (1 << DEBLOCKING_FILTER_OVERRIDE_ENABLED_FLAG_BIT))
+ && (misc_flag0 & (1 << DEBLOCKING_FILTER_OVERRIDE_FLAG_BIT))) {
+ /* slice_deblocking_filter_disabled_flag =
+ * (misc_flag0>>SLICE_DEBLOCKING_FILTER_DISABLED_FLAG_BIT)&0x1;
+ * //ucode has handle it , so read it from ucode directly
+ */
+ data32 |= slice_deblocking_filter_disabled_flag << 2;
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ hevc_print_cont(hevc, 0,
+ "(1,%x)", data32);
+ if (!slice_deblocking_filter_disabled_flag) {
+ data32 |= (params->p.slice_beta_offset_div2 & 0xf) << 3;
+ data32 |= (params->p.slice_tc_offset_div2 & 0xf) << 7;
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ hevc_print_cont(hevc, 0,
+ "(2,%x)", data32);
+ }
+ } else {
+ data32 |=
+ ((misc_flag0 >>
+ PPS_DEBLOCKING_FILTER_DISABLED_FLAG_BIT) &
+ 0x1) << 2;
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ hevc_print_cont(hevc, 0,
+ "(3,%x)", data32);
+ if (((misc_flag0 >> PPS_DEBLOCKING_FILTER_DISABLED_FLAG_BIT) &
+ 0x1) == 0) {
+ data32 |= (params->p.pps_beta_offset_div2 & 0xf) << 3;
+ data32 |= (params->p.pps_tc_offset_div2 & 0xf) << 7;
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ hevc_print_cont(hevc, 0,
+ "(4,%x)", data32);
+ }
+ }
+ if ((misc_flag0 & (1 << PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT))
+ && ((misc_flag0 & (1 << SLICE_SAO_LUMA_FLAG_BIT))
+ || (misc_flag0 & (1 << SLICE_SAO_CHROMA_FLAG_BIT))
+ || (!slice_deblocking_filter_disabled_flag))) {
+ data32 |=
+ ((misc_flag0 >>
+ SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT)
+ & 0x1) << 1;
+ data32_2 |=
+ ((misc_flag0 >>
+ SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT)
+ & 0x1) << 9;
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ hevc_print_cont(hevc, 0,
+ "(5,%x)\n", data32);
+ } else {
+ data32 |=
+ ((misc_flag0 >>
+ PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT)
+ & 0x1) << 1;
+ data32_2 |=
+ ((misc_flag0 >>
+ PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT)
+ & 0x1) << 9;
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ hevc_print_cont(hevc, 0,
+ "(6,%x)\n", data32);
+ }
+ WRITE_VREG(HEVC_DBLK_CFG9, data32);
+ WRITE_VREG(HEVC_SAO_CTRL0, data32_2);
+}
+
+#ifdef TEST_NO_BUF
+static unsigned char test_flag = 1;
+#endif
+
+static void pic_list_process(struct hevc_state_s *hevc)
+{
+ int work_pic_num = get_work_pic_num(hevc);
+ int alloc_pic_count = 0;
+ int i;
+ struct PIC_s *pic;
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL || pic->index == -1)
+ continue;
+ alloc_pic_count++;
+ if (pic->output_mark == 0 && pic->referenced == 0
+ && pic->output_ready == 0
+ && (pic->width != hevc->pic_w ||
+ pic->height != hevc->pic_h)
+ ) {
+ set_buf_unused(hevc, pic->BUF_index);
+ pic->BUF_index = -1;
+ if (alloc_pic_count > work_pic_num) {
+ pic->width = 0;
+ pic->height = 0;
+ release_pic_mmu_buf(hevc, pic);
+ pic->index = -1;
+ } else {
+ pic->width = hevc->pic_w;
+ pic->height = hevc->pic_h;
+ }
+ }
+ }
+ if (alloc_pic_count < work_pic_num) {
+ int new_count = alloc_pic_count;
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic && pic->index == -1) {
+ pic->index = i;
+ pic->BUF_index = -1;
+ pic->width = hevc->pic_w;
+ pic->height = hevc->pic_h;
+ new_count++;
+ if (new_count >=
+ work_pic_num)
+ break;
+ }
+ }
+
+ }
+ dealloc_unused_buf(hevc);
+ if (get_alloc_pic_count(hevc)
+ != alloc_pic_count) {
+ hevc_print_cont(hevc, 0,
+ "%s: work_pic_num is %d, Change alloc_pic_count from %d to %d\n",
+ __func__,
+ work_pic_num,
+ alloc_pic_count,
+ get_alloc_pic_count(hevc));
+ }
+}
+
+static struct PIC_s *get_new_pic(struct hevc_state_s *hevc,
+ union param_u *rpm_param)
+{
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+ struct PIC_s *new_pic = NULL;
+ struct PIC_s *pic;
+ int i;
+ int ret;
+
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL || pic->index == -1)
+ continue;
+
+ if (pic->output_mark == 0 && pic->referenced == 0
+ && pic->output_ready == 0
+ && pic->width == hevc->pic_w
+ && pic->height == hevc->pic_h
+ && pic->vf_ref == 0
+ ) {
+ if (new_pic) {
+ if (new_pic->POC != INVALID_POC) {
+ if (pic->POC == INVALID_POC ||
+ pic->POC < new_pic->POC)
+ new_pic = pic;
+ }
+ } else
+ new_pic = pic;
+ }
+ }
+
+ if (new_pic == NULL)
+ return NULL;
+
+ if (new_pic->BUF_index < 0) {
+ if (alloc_buf(hevc) < 0)
+ return NULL;
+ else {
+ if (config_pic(hevc, new_pic) < 0) {
+ dealloc_pic_buf(hevc, new_pic);
+ return NULL;
+ }
+ }
+ new_pic->width = hevc->pic_w;
+ new_pic->height = hevc->pic_h;
+ set_canvas(hevc, new_pic);
+
+ init_pic_list_hw(hevc);
+ }
+
+ if (new_pic) {
+ new_pic->double_write_mode =
+ get_double_write_mode(hevc);
+ if (new_pic->double_write_mode)
+ set_canvas(hevc, new_pic);
+
+#ifdef TEST_NO_BUF
+ if (test_flag) {
+ test_flag = 0;
+ return NULL;
+ } else
+ test_flag = 1;
+#endif
+ if (get_mv_buf(hevc, new_pic) < 0)
+ return NULL;
+
+ if (hevc->mmu_enable) {
+ ret = H265_alloc_mmu(hevc, new_pic,
+ rpm_param->p.bit_depth,
+ hevc->frame_mmu_map_addr);
+ if (ret != 0) {
+ put_mv_buf(hevc, new_pic);
+ hevc_print(hevc, 0,
+ "can't alloc need mmu1,idx %d ret =%d\n",
+ new_pic->decode_idx,
+ ret);
+ return NULL;
+ }
+ }
+ new_pic->referenced = 1;
+ new_pic->decode_idx = hevc->decode_idx;
+ new_pic->slice_idx = 0;
+ new_pic->referenced = 1;
+ new_pic->output_mark = 0;
+ new_pic->recon_mark = 0;
+ new_pic->error_mark = 0;
+ new_pic->dis_mark = 0;
+ /* new_pic->output_ready = 0; */
+ new_pic->num_reorder_pic = rpm_param->p.sps_num_reorder_pics_0;
+ new_pic->ip_mode = (!new_pic->num_reorder_pic &&
+ !(vdec->slave || vdec->master) &&
+ !disable_ip_mode) ? true : false;
+ new_pic->losless_comp_body_size = hevc->losless_comp_body_size;
+ new_pic->POC = hevc->curr_POC;
+ new_pic->pic_struct = hevc->curr_pic_struct;
+ if (new_pic->aux_data_buf)
+ release_aux_data(hevc, new_pic);
+ new_pic->mem_saving_mode =
+ hevc->mem_saving_mode;
+ new_pic->bit_depth_luma =
+ hevc->bit_depth_luma;
+ new_pic->bit_depth_chroma =
+ hevc->bit_depth_chroma;
+ new_pic->video_signal_type =
+ hevc->video_signal_type;
+
+ new_pic->conformance_window_flag =
+ hevc->param.p.conformance_window_flag;
+ new_pic->conf_win_left_offset =
+ hevc->param.p.conf_win_left_offset;
+ new_pic->conf_win_right_offset =
+ hevc->param.p.conf_win_right_offset;
+ new_pic->conf_win_top_offset =
+ hevc->param.p.conf_win_top_offset;
+ new_pic->conf_win_bottom_offset =
+ hevc->param.p.conf_win_bottom_offset;
+ new_pic->chroma_format_idc =
+ hevc->param.p.chroma_format_idc;
+
+ hevc_print(hevc, H265_DEBUG_BUFMGR_MORE,
+ "%s: index %d, buf_idx %d, decode_idx %d, POC %d\n",
+ __func__, new_pic->index,
+ new_pic->BUF_index, new_pic->decode_idx,
+ new_pic->POC);
+
+ }
+ if (pic_list_debug & 0x1) {
+ dump_pic_list(hevc);
+ pr_err("\n*******************************************\n");
+ }
+
+ return new_pic;
+}
+
+static struct PIC_s *v4l_get_new_pic(struct hevc_state_s *hevc,
+ union param_u *rpm_param)
+{
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+ int ret;
+ struct aml_vcodec_ctx * v4l = hevc->v4l2_ctx;
+ struct v4l_buff_pool *pool = &v4l->cap_pool;
+ struct PIC_s *new_pic = NULL;
+ struct PIC_s *pic = NULL;
+ int i;
+
+ for (i = 0; i < pool->in; ++i) {
+ u32 state = (pool->seq[i] >> 16);
+ u32 index = (pool->seq[i] & 0xffff);
+
+ switch (state) {
+ case V4L_CAP_BUFF_IN_DEC:
+ pic = hevc->m_PIC[i];
+ if (pic && (pic->index != -1) &&
+ (pic->output_mark == 0) &&
+ (pic->referenced == 0) &&
+ (pic->output_ready == 0) &&
+ (pic->width == hevc->pic_w) &&
+ (pic->height == hevc->pic_h) &&
+ (pic->vf_ref == 0) &&
+ pic->cma_alloc_addr) {
+ new_pic = pic;
+ }
+ break;
+ case V4L_CAP_BUFF_IN_M2M:
+ pic = hevc->m_PIC[index];
+ pic->width = hevc->pic_w;
+ pic->height = hevc->pic_h;
+ if ((pic->index != -1) &&
+ !v4l_alloc_buf(hevc, pic)) {
+ v4l_config_pic(hevc, pic);
+ init_pic_list_hw(hevc);
+ new_pic = pic;
+ }
+ break;
+ default:
+ pr_err("v4l buffer state err %d.\n", state);
+ break;
+ }
+
+ if (new_pic)
+ break;
+ }
+
+ if (new_pic == NULL)
+ return NULL;
+
+ new_pic->double_write_mode = get_double_write_mode(hevc);
+ if (new_pic->double_write_mode)
+ set_canvas(hevc, new_pic);
+
+ if (get_mv_buf(hevc, new_pic) < 0)
+ return NULL;
+
+ if (hevc->mmu_enable) {
+ ret = H265_alloc_mmu(hevc, new_pic,
+ rpm_param->p.bit_depth,
+ hevc->frame_mmu_map_addr);
+ if (ret != 0) {
+ put_mv_buf(hevc, new_pic);
+ hevc_print(hevc, 0,
+ "can't alloc need mmu1,idx %d ret =%d\n",
+ new_pic->decode_idx, ret);
+ return NULL;
+ }
+ }
+
+ new_pic->referenced = 1;
+ new_pic->decode_idx = hevc->decode_idx;
+ new_pic->slice_idx = 0;
+ new_pic->referenced = 1;
+ new_pic->output_mark = 0;
+ new_pic->recon_mark = 0;
+ new_pic->error_mark = 0;
+ new_pic->dis_mark = 0;
+ /* new_pic->output_ready = 0; */
+ new_pic->num_reorder_pic = rpm_param->p.sps_num_reorder_pics_0;
+ new_pic->ip_mode = (!new_pic->num_reorder_pic &&
+ !(vdec->slave || vdec->master) &&
+ !disable_ip_mode &&
+ hevc->low_latency_flag) ? true : false;
+ new_pic->losless_comp_body_size = hevc->losless_comp_body_size;
+ new_pic->POC = hevc->curr_POC;
+ new_pic->pic_struct = hevc->curr_pic_struct;
+
+ if (new_pic->aux_data_buf)
+ release_aux_data(hevc, new_pic);
+ new_pic->mem_saving_mode =
+ hevc->mem_saving_mode;
+ new_pic->bit_depth_luma =
+ hevc->bit_depth_luma;
+ new_pic->bit_depth_chroma =
+ hevc->bit_depth_chroma;
+ new_pic->video_signal_type =
+ hevc->video_signal_type;
+
+ new_pic->conformance_window_flag =
+ hevc->param.p.conformance_window_flag;
+ new_pic->conf_win_left_offset =
+ hevc->param.p.conf_win_left_offset;
+ new_pic->conf_win_right_offset =
+ hevc->param.p.conf_win_right_offset;
+ new_pic->conf_win_top_offset =
+ hevc->param.p.conf_win_top_offset;
+ new_pic->conf_win_bottom_offset =
+ hevc->param.p.conf_win_bottom_offset;
+ new_pic->chroma_format_idc =
+ hevc->param.p.chroma_format_idc;
+
+ hevc_print(hevc, H265_DEBUG_BUFMGR_MORE,
+ "%s: index %d, buf_idx %d, decode_idx %d, POC %d\n",
+ __func__, new_pic->index,
+ new_pic->BUF_index, new_pic->decode_idx,
+ new_pic->POC);
+
+ return new_pic;
+}
+
+static int get_display_pic_num(struct hevc_state_s *hevc)
+{
+ int i;
+ struct PIC_s *pic;
+ int num = 0;
+
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL ||
+ pic->index == -1)
+ continue;
+
+ if (pic->output_ready == 1)
+ num++;
+ }
+ return num;
+}
+
+static void flush_output(struct hevc_state_s *hevc, struct PIC_s *pic)
+{
+ struct PIC_s *pic_display;
+
+ if (pic) {
+ /*PB skip control */
+ if (pic->error_mark == 0 && hevc->PB_skip_mode == 1) {
+ /* start decoding after first I */
+ hevc->ignore_bufmgr_error |= 0x1;
+ }
+ if (hevc->ignore_bufmgr_error & 1) {
+ if (hevc->PB_skip_count_after_decoding > 0)
+ hevc->PB_skip_count_after_decoding--;
+ else {
+ /* start displaying */
+ hevc->ignore_bufmgr_error |= 0x2;
+ }
+ }
+ if (pic->POC != INVALID_POC && !pic->ip_mode)
+ pic->output_mark = 1;
+ pic->recon_mark = 1;
+ }
+ do {
+ pic_display = output_pic(hevc, 1);
+
+ if (pic_display) {
+ pic_display->referenced = 0;
+ put_mv_buf(hevc, pic_display);
+ if ((pic_display->error_mark
+ && ((hevc->ignore_bufmgr_error & 0x2) == 0))
+ || (get_dbg_flag(hevc) &
+ H265_DEBUG_DISPLAY_CUR_FRAME)
+ || (get_dbg_flag(hevc) &
+ H265_DEBUG_NO_DISPLAY)) {
+ pic_display->output_ready = 0;
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "[BM] Display: POC %d, ",
+ pic_display->POC);
+ hevc_print_cont(hevc, 0,
+ "decoding index %d ==> ",
+ pic_display->decode_idx);
+ hevc_print_cont(hevc, 0,
+ "Debug mode or error, recycle it\n");
+ }
+ /*
+ * Here the pic/frame error_mark is 1,
+ * and it won't be displayed, so increase
+ * the drop count
+ */
+ hevc->gvs->drop_frame_count++;
+ if (pic_display->slice_type == I_SLICE) {
+ hevc->gvs->i_lost_frames++;
+ } else if (pic_display->slice_type == P_SLICE) {
+ hevc->gvs->p_lost_frames++;
+ } else if (pic_display->slice_type == B_SLICE) {
+ hevc->gvs->b_lost_frames++;
+ }
+ /* error frame count also need increase */
+ hevc->gvs->error_frame_count++;
+ if (pic_display->slice_type == I_SLICE) {
+ hevc->gvs->i_concealed_frames++;
+ } else if (pic_display->slice_type == P_SLICE) {
+ hevc->gvs->p_concealed_frames++;
+ } else if (pic_display->slice_type == B_SLICE) {
+ hevc->gvs->b_concealed_frames++;
+ }
+ } else {
+ if (hevc->i_only & 0x1
+ && pic_display->slice_type != 2) {
+ pic_display->output_ready = 0;
+ } else {
+ prepare_display_buf(hw_to_vdec(hevc), pic_display);
+ if (get_dbg_flag(hevc)
+ & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "[BM] flush Display: POC %d, ",
+ pic_display->POC);
+ hevc_print_cont(hevc, 0,
+ "decoding index %d\n",
+ pic_display->decode_idx);
+ }
+ }
+ }
+ }
+ } while (pic_display);
+ clear_referenced_flag(hevc);
+}
+
+/*
+* dv_meta_flag: 1, dolby meta only; 2, not include dolby meta
+*/
+static void set_aux_data(struct hevc_state_s *hevc,
+ struct PIC_s *pic, unsigned char suffix_flag,
+ unsigned char dv_meta_flag)
+{
+ int i;
+ unsigned short *aux_adr;
+ unsigned int size_reg_val =
+ READ_VREG(HEVC_AUX_DATA_SIZE);
+ unsigned int aux_count = 0;
+ int aux_size = 0;
+ if (pic == NULL || 0 == aux_data_is_avaible(hevc))
+ return;
+
+ if (hevc->aux_data_dirty ||
+ hevc->m_ins_flag == 0) {
+
+ hevc->aux_data_dirty = 0;
+ }
+
+ if (suffix_flag) {
+ aux_adr = (unsigned short *)
+ (hevc->aux_addr +
+ hevc->prefix_aux_size);
+ aux_count =
+ ((size_reg_val & 0xffff) << 4)
+ >> 1;
+ aux_size =
+ hevc->suffix_aux_size;
+ } else {
+ aux_adr =
+ (unsigned short *)hevc->aux_addr;
+ aux_count =
+ ((size_reg_val >> 16) << 4)
+ >> 1;
+ aux_size =
+ hevc->prefix_aux_size;
+ }
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR_MORE) {
+ hevc_print(hevc, 0,
+ "%s:pic 0x%p old size %d count %d,suf %d dv_flag %d\r\n",
+ __func__, pic, pic->aux_data_size,
+ aux_count, suffix_flag, dv_meta_flag);
+ }
+
+ if (aux_count > aux_size) {
+ hevc_print(hevc, 0,
+ "%s:aux_count(%d) is over size\n", __func__, aux_count);
+ aux_count = 0;
+ }
+ 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 = pic->aux_data_size + aux_count + heads_size;
+ new_buf = vzalloc(new_size);
+ if (new_buf) {
+ unsigned char valid_tag = 0;
+ unsigned char *h =
+ new_buf +
+ pic->aux_data_size;
+ unsigned char *p = h + 8;
+ int len = 0;
+ int padding_len = 0;
+
+ if (pic->aux_data_buf) {
+ memcpy(new_buf, pic->aux_data_buf, pic->aux_data_size);
+ vfree(pic->aux_data_buf);
+ }
+ pic->aux_data_buf = 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) {
+ pic->aux_data_size +=
+ (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) {
+ pic->aux_data_size += (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 (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR_MORE) {
+ hevc_print(hevc, 0,
+ "aux: (size %d) suffix_flag %d\n",
+ pic->aux_data_size, suffix_flag);
+ for (i = 0; i < pic->aux_data_size; i++) {
+ hevc_print_cont(hevc, 0,
+ "%02x ", pic->aux_data_buf[i]);
+ if (((i + 1) & 0xf) == 0)
+ hevc_print_cont(hevc, 0, "\n");
+ }
+ hevc_print_cont(hevc, 0, "\n");
+ }
+
+ } else {
+ hevc_print(hevc, 0, "new buf alloc failed\n");
+ if (pic->aux_data_buf)
+ vfree(pic->aux_data_buf);
+ pic->aux_data_buf = NULL;
+ pic->aux_data_size = 0;
+ }
+ }
+
+}
+
+static void release_aux_data(struct hevc_state_s *hevc,
+ struct PIC_s *pic)
+{
+ if (pic->aux_data_buf) {
+ vfree(pic->aux_data_buf);
+ if ((run_count[hevc->index] & 63) == 0)
+ vm_unmap_aliases();
+ }
+ pic->aux_data_buf = NULL;
+ pic->aux_data_size = 0;
+}
+
+static inline void hevc_pre_pic(struct hevc_state_s *hevc,
+ struct PIC_s *pic)
+{
+
+ /* prev pic */
+ /*if (hevc->curr_POC != 0) {*/
+ int decoded_poc = hevc->iPrevPOC;
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (hevc->m_ins_flag) {
+ decoded_poc = hevc->decoded_poc;
+ hevc->decoded_poc = INVALID_POC;
+ }
+#endif
+ if (hevc->m_nalUnitType != NAL_UNIT_CODED_SLICE_IDR
+ && hevc->m_nalUnitType !=
+ NAL_UNIT_CODED_SLICE_IDR_N_LP) {
+ struct PIC_s *pic_display;
+
+ pic = get_pic_by_POC(hevc, decoded_poc);
+ if (pic && (pic->POC != INVALID_POC)) {
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+
+ /*PB skip control */
+ if (pic->error_mark == 0
+ && hevc->PB_skip_mode == 1) {
+ /* start decoding after
+ * first I
+ */
+ hevc->ignore_bufmgr_error |= 0x1;
+ }
+ if (hevc->ignore_bufmgr_error & 1) {
+ if (hevc->PB_skip_count_after_decoding > 0) {
+ hevc->PB_skip_count_after_decoding--;
+ } else {
+ /* start displaying */
+ hevc->ignore_bufmgr_error |= 0x2;
+ }
+ }
+ if (hevc->mmu_enable
+ && ((hevc->double_write_mode & 0x10) == 0)) {
+ if (!hevc->m_ins_flag) {
+ hevc->used_4k_num =
+ READ_VREG(HEVC_SAO_MMU_STATUS) >> 16;
+
+ if ((!is_skip_decoding(hevc, pic)) &&
+ (hevc->used_4k_num >= 0) &&
+ (hevc->cur_pic->scatter_alloc
+ == 1)) {
+ hevc_print(hevc,
+ H265_DEBUG_BUFMGR_MORE,
+ "%s pic index %d scatter_alloc %d page_start %ld\n",
+ "decoder_mmu_box_free_idx_tail",
+ hevc->cur_pic->index,
+ hevc->cur_pic->scatter_alloc,
+ hevc->used_4k_num);
+ hevc_mmu_dma_check(hw_to_vdec(hevc));
+ decoder_mmu_box_free_idx_tail(
+ hevc->mmu_box,
+ hevc->cur_pic->index,
+ hevc->used_4k_num);
+ hevc->cur_pic->scatter_alloc
+ = 2;
+ }
+ hevc->used_4k_num = -1;
+ }
+ }
+ if (!pic->ip_mode)
+ pic->output_mark = 1;
+ pic->recon_mark = 1;
+ pic->dis_mark = 1;
+ if (vdec->mvfrm) {
+ pic->frame_size = vdec->mvfrm->frame_size;
+ pic->hw_decode_time = (u32)vdec->mvfrm->hw_decode_time;
+ }
+ }
+ do {
+ pic_display = output_pic(hevc, 0);
+
+ if (pic_display) {
+ if ((pic_display->error_mark &&
+ ((hevc->ignore_bufmgr_error &
+ 0x2) == 0))
+ || (get_dbg_flag(hevc) &
+ H265_DEBUG_DISPLAY_CUR_FRAME)
+ || (get_dbg_flag(hevc) &
+ H265_DEBUG_NO_DISPLAY)) {
+ pic_display->output_ready = 0;
+ if (get_dbg_flag(hevc) &
+ H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "[BM] Display: POC %d, ",
+ pic_display->POC);
+ hevc_print_cont(hevc, 0,
+ "decoding index %d ==> ",
+ pic_display->
+ decode_idx);
+ hevc_print_cont(hevc, 0,
+ "Debug or err,recycle it\n");
+ }
+ /*
+ * Here the pic/frame error_mark is 1,
+ * and it won't be displayed, so increase
+ * the drop count
+ */
+ hevc->gvs->drop_frame_count++;
+ if (pic_display->slice_type == I_SLICE) {
+ hevc->gvs->i_lost_frames++;
+ }else if (pic_display->slice_type == P_SLICE) {
+ hevc->gvs->p_lost_frames++;
+ } else if (pic_display->slice_type == B_SLICE) {
+ hevc->gvs->b_lost_frames++;
+ }
+ /* error frame count also need increase */
+ hevc->gvs->error_frame_count++;
+ if (pic_display->slice_type == I_SLICE) {
+ hevc->gvs->i_concealed_frames++;
+ } else if (pic_display->slice_type == P_SLICE) {
+ hevc->gvs->p_concealed_frames++;
+ } else if (pic_display->slice_type == B_SLICE) {
+ hevc->gvs->b_concealed_frames++;
+ }
+ } else {
+ if (hevc->i_only & 0x1
+ && pic_display->
+ slice_type != 2) {
+ pic_display->output_ready = 0;
+ } else {
+ prepare_display_buf
+ (hw_to_vdec(hevc),
+ pic_display);
+ if (get_dbg_flag(hevc) &
+ H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "[BM] Display: POC %d, ",
+ pic_display->POC);
+ hevc_print_cont(hevc, 0,
+ "decoding index %d\n",
+ pic_display->
+ decode_idx);
+ }
+ }
+ }
+ }
+ } while (pic_display);
+ } else {
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "[BM] current pic is IDR, ");
+ hevc_print(hevc, 0,
+ "clear referenced flag of all buffers\n");
+ }
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ dump_pic_list(hevc);
+ if (hevc->vf_pre_count == 1 &&
+ hevc->first_pic_flag == 1) {
+ hevc->first_pic_flag = 2;
+ pic = NULL;
+ }
+ else
+ pic = get_pic_by_POC(hevc, decoded_poc);
+
+ flush_output(hevc, pic);
+ }
+
+}
+
+static void check_pic_decoded_error_pre(struct hevc_state_s *hevc,
+ int decoded_lcu)
+{
+ int current_lcu_idx = decoded_lcu;
+ if (decoded_lcu < 0)
+ return;
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "cur lcu idx = %d, (total %d)\n",
+ current_lcu_idx, hevc->lcu_total);
+ }
+ if ((error_handle_policy & 0x20) == 0 && hevc->cur_pic != NULL) {
+ if (hevc->first_pic_after_recover) {
+ if (current_lcu_idx !=
+ ((hevc->lcu_x_num_pre*hevc->lcu_y_num_pre) - 1))
+ hevc->cur_pic->error_mark = 1;
+ } else {
+ if (hevc->lcu_x_num_pre != 0
+ && hevc->lcu_y_num_pre != 0
+ && current_lcu_idx != 0
+ && current_lcu_idx <
+ ((hevc->lcu_x_num_pre*hevc->lcu_y_num_pre) - 1))
+ hevc->cur_pic->error_mark = 1;
+ }
+ if (hevc->cur_pic->error_mark) {
+ if (print_lcu_error)
+ hevc_print(hevc, 0,
+ "cur lcu idx = %d, (total %d), set error_mark\n",
+ current_lcu_idx,
+ hevc->lcu_x_num_pre*hevc->lcu_y_num_pre);
+ if (is_log_enable(hevc))
+ add_log(hevc,
+ "cur lcu idx = %d, (total %d), set error_mark",
+ current_lcu_idx,
+ hevc->lcu_x_num_pre *
+ hevc->lcu_y_num_pre);
+
+ }
+
+ }
+ if (hevc->cur_pic && hevc->head_error_flag) {
+ hevc->cur_pic->error_mark = 1;
+ hevc_print(hevc, 0,
+ "head has error, set error_mark\n");
+ }
+
+ if ((error_handle_policy & 0x80) == 0) {
+ if (hevc->over_decode && hevc->cur_pic) {
+ hevc_print(hevc, 0,
+ "over decode, set error_mark\n");
+ hevc->cur_pic->error_mark = 1;
+ }
+ }
+
+ hevc->lcu_x_num_pre = hevc->lcu_x_num;
+ hevc->lcu_y_num_pre = hevc->lcu_y_num;
+}
+
+static void check_pic_decoded_error(struct hevc_state_s *hevc,
+ int decoded_lcu)
+{
+ int current_lcu_idx = decoded_lcu;
+ if (decoded_lcu < 0)
+ return;
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "cur lcu idx = %d, (total %d)\n",
+ current_lcu_idx, hevc->lcu_total);
+ }
+ if ((error_handle_policy & 0x20) == 0 && hevc->cur_pic != NULL) {
+ if (hevc->lcu_x_num != 0
+ && hevc->lcu_y_num != 0
+ && current_lcu_idx != 0
+ && current_lcu_idx <
+ ((hevc->lcu_x_num*hevc->lcu_y_num) - 1))
+ hevc->cur_pic->error_mark = 1;
+
+ if (hevc->cur_pic->error_mark) {
+ if (print_lcu_error)
+ hevc_print(hevc, 0,
+ "cur lcu idx = %d, (total %d), set error_mark\n",
+ current_lcu_idx,
+ hevc->lcu_x_num*hevc->lcu_y_num);
+ if (((hevc->i_only & 0x4) == 0) && hevc->cur_pic->POC && ( hevc->cur_pic->slice_type == 0)
+ && ((hevc->cur_pic->POC + MAX_BUF_NUM) < hevc->iPrevPOC)) {
+ hevc_print(hevc, 0,
+ "Flush.. num_reorder_pic %d pic->POC %d hevc->iPrevPOC %d\n",
+ hevc->sps_num_reorder_pics_0,hevc->cur_pic->POC ,hevc->iPrevPOC);
+ flush_output(hevc, get_pic_by_POC(hevc, hevc->cur_pic->POC ));
+ }
+ if (is_log_enable(hevc))
+ add_log(hevc,
+ "cur lcu idx = %d, (total %d), set error_mark",
+ current_lcu_idx,
+ hevc->lcu_x_num *
+ hevc->lcu_y_num);
+
+ }
+
+ }
+ if (hevc->cur_pic && hevc->head_error_flag) {
+ hevc->cur_pic->error_mark = 1;
+ hevc_print(hevc, 0,
+ "head has error, set error_mark\n");
+ }
+
+ if ((error_handle_policy & 0x80) == 0) {
+ if (hevc->over_decode && hevc->cur_pic) {
+ hevc_print(hevc, 0,
+ "over decode, set error_mark\n");
+ hevc->cur_pic->error_mark = 1;
+ }
+ }
+}
+
+/* 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 hevc_state_s *hevc)
+{
+ struct PIC_s *picture = hevc->cur_pic;
+
+/*
+#define DEBUG_QOS
+*/
+
+ if (!hevc->cur_pic)
+ return;
+
+ 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_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];
+#ifdef DEBUG_QOS
+ hevc_print(hevc, 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
+ hevc_print(hevc, 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
+ hevc_print(hevc, 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 = 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;
+
+
+
+#ifdef DEBUG_QOS
+ hevc_print(hevc, 0, "slice_type:%d, poc:%d\n",
+ picture->slice_type,
+ picture->POC);
+#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
+ hevc_print(hevc, 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
+ hevc_print(hevc, 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
+ hevc_print(hevc, 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
+ hevc_print(hevc, 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
+ hevc_print(hevc, 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
+ hevc_print(hevc, 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
+ hevc_print(hevc, 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
+ hevc_print(hevc, 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
+ hevc_print(hevc, 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
+ hevc_print(hevc, 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
+ hevc_print(hevc, 0, "[Picture %d Quality] Y QP min : %d\n",
+ pic_number, (rdata32>>0)&0xff);
+#endif
+ picture->min_qp = (rdata32>>0)&0xff;
+
+#ifdef DEBUG_QOS
+ hevc_print(hevc, 0, "[Picture %d Quality] Y QP max : %d\n",
+ pic_number, (rdata32>>8)&0xff);
+#endif
+ picture->max_qp = (rdata32>>8)&0xff;
+
+#ifdef DEBUG_QOS
+ hevc_print(hevc, 0, "[Picture %d Quality] C QP min : %d\n",
+ pic_number, (rdata32>>16)&0xff);
+ hevc_print(hevc, 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
+ hevc_print(hevc, 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
+ hevc_print(hevc, 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
+ hevc_print(hevc, 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
+ hevc_print(hevc, 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
+ hevc_print(hevc, 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
+ hevc_print(hevc, 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
+ hevc_print(hevc, 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
+ hevc_print(hevc, 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;
+ hevc_print(hevc, 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;
+
+ hevc_print(hevc, 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;
+
+ hevc_print(hevc, 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;
+
+ hevc_print(hevc, 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;
+
+ hevc_print(hevc, 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;
+
+ hevc_print(hevc, 0, "[Picture %d Quality] MVY_L1 MIN : %d\n",
+ pic_number, mv_lo);
+#endif
+
+ rdata32 = READ_VREG(HEVC_PIC_QUALITY_CTRL);
+#ifdef DEBUG_QOS
+ hevc_print(hevc, 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 int hevc_slice_segment_header_process(struct hevc_state_s *hevc,
+ union param_u *rpm_param,
+ int decode_pic_begin)
+{
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+ int i;
+ int lcu_x_num_div;
+ int lcu_y_num_div;
+ int Col_ref;
+ int dbg_skip_flag = 0;
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(hevc->v4l2_ctx);
+
+ if (hevc->is_used_v4l && ctx->param_sets_from_ucode)
+ hevc->res_ch_flag = 0;
+
+ if (hevc->wait_buf == 0) {
+ hevc->sps_num_reorder_pics_0 =
+ rpm_param->p.sps_num_reorder_pics_0;
+ hevc->ip_mode = (!hevc->sps_num_reorder_pics_0 &&
+ !(vdec->slave || vdec->master) &&
+ !disable_ip_mode) ? true : false;
+ hevc->m_temporalId = rpm_param->p.m_temporalId;
+ hevc->m_nalUnitType = rpm_param->p.m_nalUnitType;
+ hevc->interlace_flag =
+ (rpm_param->p.profile_etc >> 2) & 0x1;
+ hevc->curr_pic_struct =
+ (rpm_param->p.sei_frame_field_info >> 3) & 0xf;
+ if (parser_sei_enable & 0x4) {
+ hevc->frame_field_info_present_flag =
+ (rpm_param->p.sei_frame_field_info >> 8) & 0x1;
+ }
+
+ /* if (interlace_enable == 0 || hevc->m_ins_flag) */
+ if (interlace_enable == 0)
+ hevc->interlace_flag = 0;
+ if (interlace_enable & 0x100)
+ hevc->interlace_flag = interlace_enable & 0x1;
+ if (hevc->interlace_flag == 0)
+ hevc->curr_pic_struct = 0;
+ /* if(hevc->m_nalUnitType == NAL_UNIT_EOS){ */
+ /*
+ *hevc->m_pocRandomAccess = MAX_INT;
+ * //add to fix RAP_B_Bossen_1
+ */
+ /* } */
+ hevc->misc_flag0 = rpm_param->p.misc_flag0;
+ if (rpm_param->p.first_slice_segment_in_pic_flag == 0) {
+ hevc->slice_segment_addr =
+ rpm_param->p.slice_segment_address;
+ if (!rpm_param->p.dependent_slice_segment_flag)
+ hevc->slice_addr = hevc->slice_segment_addr;
+ } else {
+ hevc->slice_segment_addr = 0;
+ hevc->slice_addr = 0;
+ }
+
+ hevc->iPrevPOC = hevc->curr_POC;
+ hevc->slice_type = (rpm_param->p.slice_type == I_SLICE) ? 2 :
+ (rpm_param->p.slice_type == P_SLICE) ? 1 :
+ (rpm_param->p.slice_type == B_SLICE) ? 0 : 3;
+ /* hevc->curr_predFlag_L0=(hevc->slice_type==2) ? 0:1; */
+ /* hevc->curr_predFlag_L1=(hevc->slice_type==0) ? 1:0; */
+ hevc->TMVPFlag = rpm_param->p.slice_temporal_mvp_enable_flag;
+ hevc->isNextSliceSegment =
+ rpm_param->p.dependent_slice_segment_flag ? 1 : 0;
+ if (is_oversize_ex(rpm_param->p.pic_width_in_luma_samples,
+ rpm_param->p.pic_height_in_luma_samples)) {
+ hevc_print(hevc, 0, "over size : %u x %u.\n",
+ rpm_param->p.pic_width_in_luma_samples, rpm_param->p.pic_height_in_luma_samples);
+ if ((!hevc->m_ins_flag) &&
+ ((debug &
+ H265_NO_CHANG_DEBUG_FLAG_IN_CODE) == 0))
+ debug |= (H265_DEBUG_DIS_LOC_ERROR_PROC |
+ H265_DEBUG_DIS_SYS_ERROR_PROC);
+ return 3;
+ }
+
+ if (hevc->pic_w != rpm_param->p.pic_width_in_luma_samples
+ || hevc->pic_h !=
+ rpm_param->p.pic_height_in_luma_samples) {
+ hevc_print(hevc, 0,
+ "Pic Width/Height Change (%d,%d)=>(%d,%d), interlace %d\n",
+ hevc->pic_w, hevc->pic_h,
+ rpm_param->p.pic_width_in_luma_samples,
+ rpm_param->p.pic_height_in_luma_samples,
+ hevc->interlace_flag);
+ hevc->pic_w = rpm_param->p.pic_width_in_luma_samples;
+ hevc->pic_h = rpm_param->p.pic_height_in_luma_samples;
+ hevc->frame_width = hevc->pic_w;
+ hevc->frame_height = hevc->pic_h;
+#ifdef LOSLESS_COMPRESS_MODE
+ if (/*re_config_pic_flag == 0 &&*/
+ (get_double_write_mode(hevc) & 0x10) == 0)
+ init_decode_head_hw(hevc);
+#endif
+ }
+
+ if (hevc->bit_depth_chroma > 10 ||
+ hevc->bit_depth_luma > 10) {
+ hevc_print(hevc, 0, "unsupport bitdepth : %u,%u\n",
+ hevc->bit_depth_chroma,
+ hevc->bit_depth_luma);
+ if (!hevc->m_ins_flag)
+ debug |= (H265_DEBUG_DIS_LOC_ERROR_PROC |
+ H265_DEBUG_DIS_SYS_ERROR_PROC);
+ hevc->fatal_error |= DECODER_FATAL_ERROR_SIZE_OVERFLOW;
+ return 4;
+ }
+
+ /* it will cause divide 0 error */
+ if (hevc->pic_w == 0 || hevc->pic_h == 0) {
+ if (get_dbg_flag(hevc)) {
+ hevc_print(hevc, 0,
+ "Fatal Error, pic_w = %d, pic_h = %d\n",
+ hevc->pic_w, hevc->pic_h);
+ }
+ return 3;
+ }
+ pic_list_process(hevc);
+
+ hevc->lcu_size =
+ 1 << (rpm_param->p.log2_min_coding_block_size_minus3 +
+ 3 + rpm_param->
+ p.log2_diff_max_min_coding_block_size);
+ if (hevc->lcu_size == 0) {
+ hevc_print(hevc, 0,
+ "Error, lcu_size = 0 (%d,%d)\n",
+ rpm_param->p.
+ log2_min_coding_block_size_minus3,
+ rpm_param->p.
+ log2_diff_max_min_coding_block_size);
+ return 3;
+ }
+ hevc->lcu_size_log2 = log2i(hevc->lcu_size);
+ lcu_x_num_div = (hevc->pic_w / hevc->lcu_size);
+ lcu_y_num_div = (hevc->pic_h / hevc->lcu_size);
+ hevc->lcu_x_num =
+ ((hevc->pic_w % hevc->lcu_size) ==
+ 0) ? lcu_x_num_div : lcu_x_num_div + 1;
+ hevc->lcu_y_num =
+ ((hevc->pic_h % hevc->lcu_size) ==
+ 0) ? lcu_y_num_div : lcu_y_num_div + 1;
+ hevc->lcu_total = hevc->lcu_x_num * hevc->lcu_y_num;
+
+ if (hevc->m_nalUnitType == NAL_UNIT_CODED_SLICE_IDR
+ || hevc->m_nalUnitType ==
+ NAL_UNIT_CODED_SLICE_IDR_N_LP) {
+ hevc->curr_POC = 0;
+ if ((hevc->m_temporalId - 1) == 0)
+ hevc->iPrevTid0POC = hevc->curr_POC;
+ } else {
+ int iMaxPOClsb =
+ 1 << (rpm_param->p.
+ log2_max_pic_order_cnt_lsb_minus4 + 4);
+ int iPrevPOClsb;
+ int iPrevPOCmsb;
+ int iPOCmsb;
+ int iPOClsb = rpm_param->p.POClsb;
+
+ if (iMaxPOClsb == 0) {
+ hevc_print(hevc, 0,
+ "error iMaxPOClsb is 0\n");
+ return 3;
+ }
+
+ iPrevPOClsb = hevc->iPrevTid0POC % iMaxPOClsb;
+ iPrevPOCmsb = hevc->iPrevTid0POC - iPrevPOClsb;
+
+ if ((iPOClsb < iPrevPOClsb)
+ && ((iPrevPOClsb - iPOClsb) >=
+ (iMaxPOClsb / 2)))
+ iPOCmsb = iPrevPOCmsb + iMaxPOClsb;
+ else if ((iPOClsb > iPrevPOClsb)
+ && ((iPOClsb - iPrevPOClsb) >
+ (iMaxPOClsb / 2)))
+ iPOCmsb = iPrevPOCmsb - iMaxPOClsb;
+ else
+ iPOCmsb = iPrevPOCmsb;
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "iPrePOC%d iMaxPOClsb%d iPOCmsb%d iPOClsb%d\n",
+ hevc->iPrevTid0POC, iMaxPOClsb, iPOCmsb,
+ iPOClsb);
+ }
+ if (hevc->m_nalUnitType == NAL_UNIT_CODED_SLICE_BLA
+ || hevc->m_nalUnitType ==
+ NAL_UNIT_CODED_SLICE_BLANT
+ || hevc->m_nalUnitType ==
+ NAL_UNIT_CODED_SLICE_BLA_N_LP) {
+ /* For BLA picture types, POCmsb is set to 0. */
+ iPOCmsb = 0;
+ }
+ hevc->curr_POC = (iPOCmsb + iPOClsb);
+ if ((hevc->m_temporalId - 1) == 0)
+ hevc->iPrevTid0POC = hevc->curr_POC;
+ else {
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "m_temporalID is %d\n",
+ hevc->m_temporalId);
+ }
+ }
+ }
+ hevc->RefNum_L0 =
+ (rpm_param->p.num_ref_idx_l0_active >
+ MAX_REF_ACTIVE) ? MAX_REF_ACTIVE : rpm_param->p.
+ num_ref_idx_l0_active;
+ hevc->RefNum_L1 =
+ (rpm_param->p.num_ref_idx_l1_active >
+ MAX_REF_ACTIVE) ? MAX_REF_ACTIVE : rpm_param->p.
+ num_ref_idx_l1_active;
+
+ /* if(curr_POC==0x10) dump_lmem(); */
+
+ /* skip RASL pictures after CRA/BLA pictures */
+ if (hevc->m_pocRandomAccess == MAX_INT) {/* first picture */
+ if (hevc->m_nalUnitType == NAL_UNIT_CODED_SLICE_CRA ||
+ hevc->m_nalUnitType == NAL_UNIT_CODED_SLICE_BLA
+ || hevc->m_nalUnitType ==
+ NAL_UNIT_CODED_SLICE_BLANT
+ || hevc->m_nalUnitType ==
+ NAL_UNIT_CODED_SLICE_BLA_N_LP)
+ hevc->m_pocRandomAccess = hevc->curr_POC;
+ else
+ hevc->m_pocRandomAccess = -MAX_INT;
+ } else if (hevc->m_nalUnitType == NAL_UNIT_CODED_SLICE_BLA
+ || hevc->m_nalUnitType ==
+ NAL_UNIT_CODED_SLICE_BLANT
+ || hevc->m_nalUnitType ==
+ NAL_UNIT_CODED_SLICE_BLA_N_LP)
+ hevc->m_pocRandomAccess = hevc->curr_POC;
+ else if ((hevc->curr_POC < hevc->m_pocRandomAccess) &&
+ (nal_skip_policy >= 3) &&
+ (hevc->m_nalUnitType ==
+ NAL_UNIT_CODED_SLICE_RASL_N ||
+ hevc->m_nalUnitType ==
+ NAL_UNIT_CODED_SLICE_TFD)) { /* skip */
+ if (get_dbg_flag(hevc)) {
+ hevc_print(hevc, 0,
+ "RASL picture with POC %d < %d ",
+ hevc->curr_POC, hevc->m_pocRandomAccess);
+ hevc_print(hevc, 0,
+ "RandomAccess point POC), skip it\n");
+ }
+ return 1;
+ }
+
+ WRITE_VREG(HEVC_WAIT_FLAG, READ_VREG(HEVC_WAIT_FLAG) | 0x2);
+ hevc->skip_flag = 0;
+ /**/
+ /* if((iPrevPOC != curr_POC)){ */
+ if (rpm_param->p.slice_segment_address == 0) {
+ struct PIC_s *pic;
+
+ hevc->new_pic = 1;
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (!hevc->m_ins_flag)
+#endif
+ check_pic_decoded_error_pre(hevc,
+ READ_VREG(HEVC_PARSER_LCU_START)
+ & 0xffffff);
+ /**/ if (use_cma == 0) {
+ if (hevc->pic_list_init_flag == 0) {
+ init_pic_list(hevc);
+ init_pic_list_hw(hevc);
+ init_buf_spec(hevc);
+ hevc->pic_list_init_flag = 3;
+ }
+ }
+ if (!hevc->m_ins_flag) {
+ if (hevc->cur_pic)
+ get_picture_qos_info(hevc);
+ }
+ hevc->first_pic_after_recover = 0;
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR_MORE)
+ dump_pic_list(hevc);
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ if (vdec->master) {
+ struct hevc_state_s *hevc_ba =
+ (struct hevc_state_s *)
+ vdec->master->private;
+ if (hevc_ba->cur_pic != NULL) {
+ hevc_ba->cur_pic->dv_enhance_exist = 1;
+ hevc_print(hevc, H265_DEBUG_DV,
+ "To decode el (poc %d) => set bl (poc %d) dv_enhance_exist flag\n",
+ hevc->curr_POC, hevc_ba->cur_pic->POC);
+ }
+ }
+ if (vdec->master == NULL &&
+ vdec->slave == NULL)
+ set_aux_data(hevc,
+ hevc->cur_pic, 1, 0); /*suffix*/
+ if (hevc->bypass_dvenl && !dolby_meta_with_el)
+ set_aux_data(hevc,
+ hevc->cur_pic, 0, 1); /*dv meta only*/
+#else
+ set_aux_data(hevc, hevc->cur_pic, 1, 0);
+#endif
+
+ /* prev pic */
+ hevc_pre_pic(hevc, pic);
+ /*
+ *update referenced of old pictures
+ *(cur_pic->referenced is 1 and not updated)
+ */
+ apply_ref_pic_set(hevc, hevc->curr_POC,
+ rpm_param);
+
+ /*if (hevc->mmu_enable)
+ recycle_mmu_bufs(hevc);*/
+
+
+ /* new pic */
+ hevc->cur_pic = hevc->is_used_v4l ?
+ v4l_get_new_pic(hevc, rpm_param) :
+ get_new_pic(hevc, rpm_param);
+ if (hevc->cur_pic == NULL) {
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ dump_pic_list(hevc);
+ hevc->wait_buf = 1;
+ return -1;
+ }
+#ifdef MULTI_INSTANCE_SUPPORT
+ hevc->decoding_pic = hevc->cur_pic;
+ if (!hevc->m_ins_flag)
+ hevc->over_decode = 0;
+#endif
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ hevc->cur_pic->dv_enhance_exist = 0;
+ if (vdec->slave)
+ hevc_print(hevc, H265_DEBUG_DV,
+ "Clear bl (poc %d) dv_enhance_exist flag\n",
+ hevc->curr_POC);
+ if (vdec->master == NULL &&
+ vdec->slave == NULL)
+ set_aux_data(hevc,
+ hevc->cur_pic, 0, 0); /*prefix*/
+
+ if (hevc->bypass_dvenl && !dolby_meta_with_el)
+ set_aux_data(hevc,
+ hevc->cur_pic, 0, 2); /*pre sei only*/
+#else
+ set_aux_data(hevc, hevc->cur_pic, 0, 0);
+#endif
+ if (get_dbg_flag(hevc) & H265_DEBUG_DISPLAY_CUR_FRAME) {
+ hevc->cur_pic->output_ready = 1;
+ hevc->cur_pic->stream_offset =
+ READ_VREG(HEVC_SHIFT_BYTE_COUNT);
+ prepare_display_buf(vdec, hevc->cur_pic);
+ hevc->wait_buf = 2;
+ return -1;
+ }
+ } else {
+ if (get_dbg_flag(hevc) & H265_DEBUG_HAS_AUX_IN_SLICE) {
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ if (vdec->master == NULL &&
+ vdec->slave == NULL) {
+ set_aux_data(hevc, hevc->cur_pic, 1, 0);
+ set_aux_data(hevc, hevc->cur_pic, 0, 0);
+ }
+#else
+ set_aux_data(hevc, hevc->cur_pic, 1, 0);
+ set_aux_data(hevc, hevc->cur_pic, 0, 0);
+#endif
+ }
+ if (hevc->pic_list_init_flag != 3
+ || hevc->cur_pic == NULL) {
+ /* make it dec from the first slice segment */
+ return 3;
+ }
+ hevc->cur_pic->slice_idx++;
+ hevc->new_pic = 0;
+ }
+ } else {
+ if (hevc->wait_buf == 1) {
+ pic_list_process(hevc);
+ hevc->cur_pic = hevc->is_used_v4l ?
+ v4l_get_new_pic(hevc, rpm_param) :
+ get_new_pic(hevc, rpm_param);
+ if (hevc->cur_pic == NULL)
+ return -1;
+
+ if (!hevc->m_ins_flag)
+ hevc->over_decode = 0;
+
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ hevc->cur_pic->dv_enhance_exist = 0;
+ if (vdec->master == NULL &&
+ vdec->slave == NULL)
+ set_aux_data(hevc, hevc->cur_pic, 0, 0);
+#else
+ set_aux_data(hevc, hevc->cur_pic, 0, 0);
+#endif
+ hevc->wait_buf = 0;
+ } else if (hevc->wait_buf ==
+ 2) {
+ if (get_display_pic_num(hevc) >
+ 1)
+ return -1;
+ hevc->wait_buf = 0;
+ }
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR_MORE)
+ dump_pic_list(hevc);
+ }
+
+ if (hevc->new_pic) {
+#if 1
+ /*SUPPORT_10BIT*/
+ int sao_mem_unit =
+ (hevc->lcu_size == 16 ? 9 :
+ hevc->lcu_size ==
+ 32 ? 14 : 24) << 4;
+#else
+ int sao_mem_unit = ((hevc->lcu_size / 8) * 2 + 4) << 4;
+#endif
+ int pic_height_cu =
+ (hevc->pic_h + hevc->lcu_size - 1) / hevc->lcu_size;
+ int pic_width_cu =
+ (hevc->pic_w + hevc->lcu_size - 1) / hevc->lcu_size;
+ int sao_vb_size = (sao_mem_unit + (2 << 4)) * pic_height_cu;
+
+ /* int sao_abv_size = sao_mem_unit*pic_width_cu; */
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "==>%s dec idx %d, struct %d interlace %d pic idx %d\n",
+ __func__,
+ hevc->decode_idx,
+ hevc->curr_pic_struct,
+ hevc->interlace_flag,
+ hevc->cur_pic->index);
+ }
+ if (dbg_skip_decode_index != 0 &&
+ hevc->decode_idx == dbg_skip_decode_index)
+ dbg_skip_flag = 1;
+
+ hevc->decode_idx++;
+ update_tile_info(hevc, pic_width_cu, pic_height_cu,
+ sao_mem_unit, rpm_param);
+
+ config_title_hw(hevc, sao_vb_size, sao_mem_unit);
+ }
+
+ if (hevc->iPrevPOC != hevc->curr_POC) {
+ hevc->new_tile = 1;
+ hevc->tile_x = 0;
+ hevc->tile_y = 0;
+ hevc->tile_y_x = 0;
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "new_tile (new_pic) tile_x=%d, tile_y=%d\n",
+ hevc->tile_x, hevc->tile_y);
+ }
+ } else if (hevc->tile_enabled) {
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "slice_segment_address is %d\n",
+ rpm_param->p.slice_segment_address);
+ }
+ hevc->tile_y_x =
+ get_tile_index(hevc, rpm_param->p.slice_segment_address,
+ (hevc->pic_w +
+ hevc->lcu_size -
+ 1) / hevc->lcu_size);
+ if ((hevc->tile_y_x != (hevc->tile_x | (hevc->tile_y << 8)))
+ && (hevc->tile_y_x != -1)) {
+ hevc->new_tile = 1;
+ hevc->tile_x = hevc->tile_y_x & 0xff;
+ hevc->tile_y = (hevc->tile_y_x >> 8) & 0xff;
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "new_tile seg adr %d tile_x=%d, tile_y=%d\n",
+ rpm_param->p.slice_segment_address,
+ hevc->tile_x, hevc->tile_y);
+ }
+ } else
+ hevc->new_tile = 0;
+ } else
+ hevc->new_tile = 0;
+
+ if ((hevc->tile_x > (MAX_TILE_COL_NUM - 1))
+ || (hevc->tile_y > (MAX_TILE_ROW_NUM - 1)))
+ hevc->new_tile = 0;
+
+ if (hevc->new_tile) {
+ hevc->tile_start_lcu_x =
+ hevc->m_tile[hevc->tile_y][hevc->tile_x].start_cu_x;
+ hevc->tile_start_lcu_y =
+ hevc->m_tile[hevc->tile_y][hevc->tile_x].start_cu_y;
+ hevc->tile_width_lcu =
+ hevc->m_tile[hevc->tile_y][hevc->tile_x].width;
+ hevc->tile_height_lcu =
+ hevc->m_tile[hevc->tile_y][hevc->tile_x].height;
+ }
+
+ set_ref_pic_list(hevc, rpm_param);
+
+ Col_ref = rpm_param->p.collocated_ref_idx;
+
+ hevc->LDCFlag = 0;
+ if (rpm_param->p.slice_type != I_SLICE) {
+ hevc->LDCFlag = 1;
+ for (i = 0; (i < hevc->RefNum_L0) && hevc->LDCFlag; i++) {
+ if (hevc->cur_pic->
+ m_aiRefPOCList0[hevc->cur_pic->slice_idx][i] >
+ hevc->curr_POC)
+ hevc->LDCFlag = 0;
+ }
+ if (rpm_param->p.slice_type == B_SLICE) {
+ for (i = 0; (i < hevc->RefNum_L1)
+ && hevc->LDCFlag; i++) {
+ if (hevc->cur_pic->
+ m_aiRefPOCList1[hevc->cur_pic->
+ slice_idx][i] >
+ hevc->curr_POC)
+ hevc->LDCFlag = 0;
+ }
+ }
+ }
+
+ hevc->ColFromL0Flag = rpm_param->p.collocated_from_l0_flag;
+
+ hevc->plevel =
+ rpm_param->p.log2_parallel_merge_level;
+ hevc->MaxNumMergeCand = 5 - rpm_param->p.five_minus_max_num_merge_cand;
+
+ hevc->LongTerm_Curr = 0; /* to do ... */
+ hevc->LongTerm_Col = 0; /* to do ... */
+
+ hevc->list_no = 0;
+ if (rpm_param->p.slice_type == B_SLICE)
+ hevc->list_no = 1 - hevc->ColFromL0Flag;
+ if (hevc->list_no == 0) {
+ if (Col_ref < hevc->RefNum_L0) {
+ hevc->Col_POC =
+ hevc->cur_pic->m_aiRefPOCList0[hevc->cur_pic->
+ slice_idx][Col_ref];
+ } else
+ hevc->Col_POC = INVALID_POC;
+ } else {
+ if (Col_ref < hevc->RefNum_L1) {
+ hevc->Col_POC =
+ hevc->cur_pic->m_aiRefPOCList1[hevc->cur_pic->
+ slice_idx][Col_ref];
+ } else
+ hevc->Col_POC = INVALID_POC;
+ }
+
+ hevc->LongTerm_Ref = 0; /* to do ... */
+
+ if (hevc->slice_type != 2) {
+ /* if(hevc->i_only==1){ */
+ /* return 0xf; */
+ /* } */
+
+ if (hevc->Col_POC != INVALID_POC) {
+ hevc->col_pic = get_ref_pic_by_POC(hevc, hevc->Col_POC);
+ if (hevc->col_pic == NULL) {
+ hevc->cur_pic->error_mark = 1;
+ if (get_dbg_flag(hevc)) {
+ hevc_print(hevc, 0,
+ "WRONG,fail to get the pic Col_POC\n");
+ }
+ if (is_log_enable(hevc))
+ add_log(hevc,
+ "WRONG,fail to get the pic Col_POC");
+ } else if (hevc->col_pic->error_mark || hevc->col_pic->dis_mark == 0) {
+ hevc->col_pic->error_mark = 1;
+ hevc->cur_pic->error_mark = 1;
+ if (get_dbg_flag(hevc)) {
+ hevc_print(hevc, 0,
+ "WRONG, Col_POC error_mark is 1\n");
+ }
+ if (is_log_enable(hevc))
+ add_log(hevc,
+ "WRONG, Col_POC error_mark is 1");
+ } else {
+ if ((hevc->col_pic->width
+ != hevc->pic_w) ||
+ (hevc->col_pic->height
+ != hevc->pic_h)) {
+ hevc_print(hevc, 0,
+ "Wrong reference pic (poc %d) width/height %d/%d\n",
+ hevc->col_pic->POC,
+ hevc->col_pic->width,
+ hevc->col_pic->height);
+ hevc->cur_pic->error_mark = 1;
+ }
+
+ }
+
+ if (hevc->cur_pic->error_mark
+ && ((hevc->ignore_bufmgr_error & 0x1) == 0)) {
+ /*count info*/
+ vdec_count_info(hevc->gvs, hevc->cur_pic->error_mark,
+ hevc->cur_pic->stream_offset);
+ if (hevc->cur_pic->slice_type == I_SLICE) {
+ hevc->gvs->i_decoded_frames++;
+ } else if (hevc->cur_pic->slice_type == P_SLICE) {
+ hevc->gvs->p_decoded_frames++;
+ } else if (hevc->cur_pic->slice_type == B_SLICE) {
+ hevc->gvs->b_decoded_frames++;
+ }
+ if (hevc->cur_pic->error_mark) {
+ if (hevc->cur_pic->slice_type == I_SLICE) {
+ hevc->gvs->i_concealed_frames++;
+ } else if (hevc->cur_pic->slice_type == P_SLICE) {
+ hevc->gvs->p_concealed_frames++;
+ } else if (hevc->cur_pic->slice_type == B_SLICE) {
+ hevc->gvs->b_concealed_frames++;
+ }
+ }
+ if (hevc->PB_skip_mode == 2) {
+ hevc->gvs->drop_frame_count++;
+ if (rpm_param->p.slice_type == I_SLICE) {
+ hevc->gvs->i_lost_frames++;
+ } else if (rpm_param->p.slice_type == P_SLICE) {
+ hevc->gvs->p_lost_frames++;
+ } else if (rpm_param->p.slice_type == B_SLICE) {
+ hevc->gvs->b_lost_frames++;
+ }
+ }
+ }
+
+ if (is_skip_decoding(hevc,
+ hevc->cur_pic)) {
+ return 2;
+ }
+ } else
+ hevc->col_pic = hevc->cur_pic;
+ } /* */
+ if (hevc->col_pic == NULL)
+ hevc->col_pic = hevc->cur_pic;
+#ifdef BUFFER_MGR_ONLY
+ return 0xf;
+#else
+ if ((decode_pic_begin > 0 && hevc->decode_idx <= decode_pic_begin)
+ || (dbg_skip_flag))
+ return 0xf;
+#endif
+
+ config_mc_buffer(hevc, hevc->cur_pic);
+
+ if (is_skip_decoding(hevc,
+ hevc->cur_pic)) {
+ if (get_dbg_flag(hevc))
+ hevc_print(hevc, 0,
+ "Discard this picture index %d\n",
+ hevc->cur_pic->index);
+ /*count info*/
+ vdec_count_info(hevc->gvs, hevc->cur_pic->error_mark,
+ hevc->cur_pic->stream_offset);
+ if (hevc->cur_pic->slice_type == I_SLICE) {
+ hevc->gvs->i_decoded_frames++;
+ } else if (hevc->cur_pic->slice_type == P_SLICE) {
+ hevc->gvs->p_decoded_frames++;
+ } else if (hevc->cur_pic->slice_type == B_SLICE) {
+ hevc->gvs->b_decoded_frames++;
+ }
+ if (hevc->cur_pic->error_mark) {
+ if (hevc->cur_pic->slice_type == I_SLICE) {
+ hevc->gvs->i_concealed_frames++;
+ } else if (hevc->cur_pic->slice_type == P_SLICE) {
+ hevc->gvs->p_concealed_frames++;
+ } else if (hevc->cur_pic->slice_type == B_SLICE) {
+ hevc->gvs->b_concealed_frames++;
+ }
+ }
+ if (hevc->PB_skip_mode == 2) {
+ hevc->gvs->drop_frame_count++;
+ if (rpm_param->p.slice_type == I_SLICE) {
+ hevc->gvs->i_lost_frames++;
+ } else if (rpm_param->p.slice_type == P_SLICE) {
+ hevc->gvs->p_lost_frames++;
+ } else if (rpm_param->p.slice_type == B_SLICE) {
+ hevc->gvs->b_lost_frames++;
+ }
+ }
+ return 2;
+ }
+#ifdef MCRCC_ENABLE
+ config_mcrcc_axi_hw(hevc, hevc->cur_pic->slice_type);
+#endif
+ if (!hevc->tile_width_lcu || !hevc->tile_height_lcu)
+ return -1;
+ config_mpred_hw(hevc);
+
+ config_sao_hw(hevc, rpm_param);
+
+ if ((hevc->slice_type != 2) && (hevc->i_only & 0x2))
+ return 0xf;
+
+ if (post_picture_early(vdec, hevc->cur_pic->index))
+ return -1;
+
+ return 0;
+}
+
+
+
+static int H265_alloc_mmu(struct hevc_state_s *hevc, struct PIC_s *new_pic,
+ unsigned short bit_depth, unsigned int *mmu_index_adr) {
+ int cur_buf_idx = new_pic->index;
+ int bit_depth_10 = (bit_depth != 0x00);
+ int picture_size;
+ int cur_mmu_4k_number;
+ int ret, max_frame_num;
+ picture_size = compute_losless_comp_body_size(hevc, new_pic->width,
+ new_pic->height, !bit_depth_10);
+ cur_mmu_4k_number = ((picture_size+(1<<12)-1) >> 12);
+ if (get_double_write_mode(hevc) == 0x10)
+ return 0;
+ /*hevc_print(hevc, 0,
+ "alloc_mmu cur_idx : %d picture_size : %d mmu_4k_number : %d\r\n",
+ cur_buf_idx, picture_size, cur_mmu_4k_number);*/
+
+ 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) {
+ hevc_print(hevc, 0, "over max !! 0x%x width %d height %d\n",
+ cur_mmu_4k_number,
+ new_pic->width,
+ new_pic->height);
+ return -1;
+ }
+ ret = decoder_mmu_box_alloc_idx(
+ hevc->mmu_box,
+ cur_buf_idx,
+ cur_mmu_4k_number,
+ mmu_index_adr);
+
+ new_pic->scatter_alloc = 1;
+
+ hevc_print(hevc, H265_DEBUG_BUFMGR_MORE,
+ "%s pic index %d page count(%d) ret =%d\n",
+ __func__, cur_buf_idx,
+ cur_mmu_4k_number, ret);
+ return ret;
+}
+
+
+static void release_pic_mmu_buf(struct hevc_state_s *hevc,
+ struct PIC_s *pic)
+{
+ hevc_print(hevc, H265_DEBUG_BUFMGR_MORE,
+ "%s pic index %d scatter_alloc %d\n",
+ __func__, pic->index,
+ pic->scatter_alloc);
+
+ if (hevc->mmu_enable
+ && ((hevc->double_write_mode & 0x10) == 0)
+ && pic->scatter_alloc)
+ decoder_mmu_box_free_idx(hevc->mmu_box, pic->index);
+ pic->scatter_alloc = 0;
+}
+
+/*
+ *************************************************
+ *
+ *h265 buffer management end
+ *
+ **************************************************
+ */
+static struct hevc_state_s *gHevc;
+
+static void hevc_local_uninit(struct hevc_state_s *hevc)
+{
+ hevc->rpm_ptr = NULL;
+ hevc->lmem_ptr = NULL;
+
+#ifdef SWAP_HEVC_UCODE
+ if (hevc->is_swap && get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_GXM) {
+ if (hevc->mc_cpu_addr != NULL) {
+ dma_free_coherent(amports_get_dma_device(),
+ hevc->swap_size, hevc->mc_cpu_addr,
+ hevc->mc_dma_handle);
+ hevc->mc_cpu_addr = NULL;
+ }
+
+ }
+#endif
+#ifdef DETREFILL_ENABLE
+ if (hevc->is_swap && get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_GXM)
+ uninit_detrefill_buf(hevc);
+#endif
+ if (hevc->aux_addr) {
+ dma_free_coherent(amports_get_dma_device(),
+ hevc->prefix_aux_size + hevc->suffix_aux_size, hevc->aux_addr,
+ hevc->aux_phy_addr);
+ hevc->aux_addr = NULL;
+ }
+ if (hevc->rpm_addr) {
+ dma_free_coherent(amports_get_dma_device(),
+ RPM_BUF_SIZE, hevc->rpm_addr,
+ hevc->rpm_phy_addr);
+ hevc->rpm_addr = NULL;
+ }
+ if (hevc->lmem_addr) {
+ dma_free_coherent(amports_get_dma_device(),
+ RPM_BUF_SIZE, hevc->lmem_addr,
+ hevc->lmem_phy_addr);
+ hevc->lmem_addr = NULL;
+ }
+
+ if (hevc->mmu_enable && hevc->frame_mmu_map_addr) {
+ if (hevc->frame_mmu_map_phy_addr)
+ dma_free_coherent(amports_get_dma_device(),
+ get_frame_mmu_map_size(), hevc->frame_mmu_map_addr,
+ hevc->frame_mmu_map_phy_addr);
+
+ hevc->frame_mmu_map_addr = NULL;
+ }
+
+ //pr_err("[%s line %d] hevc->gvs=0x%p operation\n",__func__, __LINE__, hevc->gvs);
+}
+
+static int hevc_local_init(struct hevc_state_s *hevc)
+{
+ int ret = -1;
+ struct BuffInfo_s *cur_buf_info = NULL;
+
+ memset(&hevc->param, 0, sizeof(union param_u));
+
+ cur_buf_info = &hevc->work_space_buf_store;
+ if (force_bufspec) {
+ memcpy(cur_buf_info, &amvh265_workbuff_spec[force_bufspec & 0xf],
+ sizeof(struct BuffInfo_s));
+ pr_info("force buffer spec %d\n", force_bufspec & 0xf);
+ } else if (vdec_is_support_4k()) {
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1)
+ memcpy(cur_buf_info, &amvh265_workbuff_spec[2], /* 4k */
+ sizeof(struct BuffInfo_s));
+ else
+ memcpy(cur_buf_info, &amvh265_workbuff_spec[1], /* 4k */
+ sizeof(struct BuffInfo_s));
+ } else
+ memcpy(cur_buf_info, &amvh265_workbuff_spec[0], /* 1080p */
+ sizeof(struct BuffInfo_s));
+
+ cur_buf_info->start_adr = hevc->buf_start;
+ init_buff_spec(hevc, cur_buf_info);
+
+ hevc_init_stru(hevc, cur_buf_info);
+
+ hevc->bit_depth_luma = 8;
+ hevc->bit_depth_chroma = 8;
+ hevc->video_signal_type = 0;
+ hevc->video_signal_type_debug = 0;
+ bit_depth_luma = hevc->bit_depth_luma;
+ bit_depth_chroma = hevc->bit_depth_chroma;
+ video_signal_type = hevc->video_signal_type;
+
+ if ((get_dbg_flag(hevc) & H265_DEBUG_SEND_PARAM_WITH_REG) == 0) {
+ hevc->rpm_addr = dma_alloc_coherent(amports_get_dma_device(),
+ RPM_BUF_SIZE, &hevc->rpm_phy_addr, GFP_KERNEL);
+ if (hevc->rpm_addr == NULL) {
+ pr_err("%s: failed to alloc rpm buffer\n", __func__);
+ return -1;
+ }
+ hevc->rpm_ptr = hevc->rpm_addr;
+ }
+
+ if (prefix_aux_buf_size > 0 ||
+ suffix_aux_buf_size > 0) {
+ u32 aux_buf_size;
+
+ hevc->prefix_aux_size = AUX_BUF_ALIGN(prefix_aux_buf_size);
+ hevc->suffix_aux_size = AUX_BUF_ALIGN(suffix_aux_buf_size);
+ aux_buf_size = hevc->prefix_aux_size + hevc->suffix_aux_size;
+ hevc->aux_addr =dma_alloc_coherent(amports_get_dma_device(),
+ aux_buf_size, &hevc->aux_phy_addr, GFP_KERNEL);
+ if (hevc->aux_addr == NULL) {
+ pr_err("%s: failed to alloc rpm buffer\n", __func__);
+ return -1;
+ }
+ }
+
+ hevc->lmem_addr = dma_alloc_coherent(amports_get_dma_device(),
+ LMEM_BUF_SIZE, &hevc->lmem_phy_addr, GFP_KERNEL);
+ if (hevc->lmem_addr == NULL) {
+ pr_err("%s: failed to alloc lmem buffer\n", __func__);
+ return -1;
+ }
+ hevc->lmem_ptr = hevc->lmem_addr;
+
+ if (hevc->mmu_enable) {
+ hevc->frame_mmu_map_addr =
+ dma_alloc_coherent(amports_get_dma_device(),
+ get_frame_mmu_map_size(),
+ &hevc->frame_mmu_map_phy_addr, GFP_KERNEL);
+ if (hevc->frame_mmu_map_addr == NULL) {
+ pr_err("%s: failed to alloc count_buffer\n", __func__);
+ return -1;
+ }
+ memset(hevc->frame_mmu_map_addr, 0, get_frame_mmu_map_size());
+ }
+ 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 hevc_state_s *hevc, struct PIC_s *pic)
+{
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+ int canvas_w = ALIGN(pic->width, 64)/4;
+ int canvas_h = ALIGN(pic->height, 32)/4;
+ int blkmode = hevc->mem_map_mode;
+
+ /*CANVAS_BLKMODE_64X32*/
+#ifdef SUPPORT_10BIT
+ if (pic->double_write_mode) {
+ canvas_w = pic->width /
+ get_double_write_ratio(hevc, pic->double_write_mode);
+ canvas_h = pic->height /
+ get_double_write_ratio(hevc, pic->double_write_mode);
+
+ if (hevc->mem_map_mode == 0)
+ canvas_w = ALIGN(canvas_w, 32);
+ else
+ 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;
+ }
+
+ canvas_config_ex(pic->y_canvas_index,
+ pic->dw_y_adr, canvas_w, canvas_h,
+ CANVAS_ADDR_NOWRAP, blkmode, hevc->is_used_v4l ? 0 : 7);
+ canvas_config_ex(pic->uv_canvas_index, pic->dw_u_v_adr,
+ canvas_w, canvas_h,
+ CANVAS_ADDR_NOWRAP, blkmode, hevc->is_used_v4l ? 0 : 7);
+#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 = hevc->is_used_v4l ? 0 : 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 = hevc->is_used_v4l ? 0 : 7;
+
+ ATRACE_COUNTER(hevc->set_canvas0_addr, pic->canvas_config[0].phy_addr);
+ hevc_print(hevc, H265_DEBUG_PIC_STRUCT,"%s(canvas0 addr:0x%x)\n",
+ __func__, pic->canvas_config[0].phy_addr);
+#else
+ ATRACE_COUNTER(hevc->set_canvas0_addr, spec2canvas(pic));
+ hevc_print(hevc, H265_DEBUG_PIC_STRUCT,"%s(canvas0 addr:0x%x)\n",
+ __func__, spec2canvas(pic));
+#endif
+ } else {
+ if (!hevc->mmu_enable) {
+ /* to change after 10bit VPU is ready ... */
+ if (vdec->parallel_dec == 1) {
+ if (pic->y_canvas_index == -1)
+ pic->y_canvas_index = vdec->get_canvas_ex(CORE_MASK_HEVC, vdec->id);
+ pic->uv_canvas_index = pic->y_canvas_index;
+ } else {
+ pic->y_canvas_index = 128 + pic->index;
+ pic->uv_canvas_index = 128 + pic->index;
+ }
+
+ canvas_config_ex(pic->y_canvas_index,
+ pic->mc_y_adr, canvas_w, canvas_h,
+ CANVAS_ADDR_NOWRAP, blkmode, hevc->is_used_v4l ? 0 : 7);
+ canvas_config_ex(pic->uv_canvas_index, pic->mc_u_v_adr,
+ canvas_w, canvas_h,
+ CANVAS_ADDR_NOWRAP, blkmode, hevc->is_used_v4l ? 0 : 7);
+ }
+ ATRACE_COUNTER(hevc->set_canvas0_addr, spec2canvas(pic));
+ hevc_print(hevc, H265_DEBUG_PIC_STRUCT,"%s(canvas0 addr:0x%x)\n",
+ __func__, spec2canvas(pic));
+ }
+#else
+ 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;
+ }
+
+
+ canvas_config_ex(pic->y_canvas_index, pic->mc_y_adr, canvas_w, canvas_h,
+ CANVAS_ADDR_NOWRAP, blkmode, hevc->is_used_v4l ? 0 : 7);
+ canvas_config_ex(pic->uv_canvas_index, pic->mc_u_v_adr,
+ canvas_w, canvas_h,
+ CANVAS_ADDR_NOWRAP, blkmode, hevc->is_used_v4l ? 0 : 7);
+
+ ATRACE_COUNTER(hevc->set_canvas0_addr, spec2canvas(pic));
+ hevc_print(hevc, H265_DEBUG_PIC_STRUCT,"%s(canvas0 addr:0x%x)\n",
+ __func__, spec2canvas(pic));
+#endif
+}
+
+static int init_buf_spec(struct hevc_state_s *hevc)
+{
+ int pic_width = hevc->pic_w;
+ int pic_height = hevc->pic_h;
+
+ /* hevc_print(hevc, 0,
+ *"%s1: %d %d\n", __func__, hevc->pic_w, hevc->pic_h);
+ */
+ hevc_print(hevc, 0,
+ "%s2 %d %d\n", __func__, pic_width, pic_height);
+ /* pic_width = hevc->pic_w; */
+ /* pic_height = hevc->pic_h; */
+
+ if (hevc->frame_width == 0 || hevc->frame_height == 0) {
+ hevc->frame_width = pic_width;
+ hevc->frame_height = pic_height;
+
+ }
+
+ return 0;
+}
+
+static int parse_sei(struct hevc_state_s *hevc,
+ struct PIC_s *pic, char *sei_buf, uint32_t size)
+{
+ char *p = sei_buf;
+ char *p_sei;
+ uint16_t header;
+ uint8_t nal_unit_type;
+ uint8_t payload_type, payload_size;
+ int i, j;
+
+ if (size < 2)
+ return 0;
+ header = *p++;
+ header <<= 8;
+ header += *p++;
+ nal_unit_type = header >> 9;
+ if ((nal_unit_type != NAL_UNIT_SEI)
+ && (nal_unit_type != NAL_UNIT_SEI_SUFFIX))
+ return 0;
+ while (p+2 <= sei_buf+size) {
+ payload_type = *p++;
+ payload_size = *p++;
+ if (p+payload_size <= sei_buf+size) {
+ switch (payload_type) {
+ case SEI_PicTiming:
+ if ((parser_sei_enable & 0x4) &&
+ hevc->frame_field_info_present_flag) {
+ p_sei = p;
+ hevc->curr_pic_struct = (*p_sei >> 4)&0x0f;
+ pic->pic_struct = hevc->curr_pic_struct;
+ if (get_dbg_flag(hevc) &
+ H265_DEBUG_PIC_STRUCT) {
+ hevc_print(hevc, 0,
+ "parse result pic_struct = %d\n",
+ hevc->curr_pic_struct);
+ }
+ }
+ break;
+ case SEI_UserDataITU_T_T35:
+ p_sei = p;
+ if (p_sei[0] == 0xB5
+ && p_sei[1] == 0x00
+ && p_sei[2] == 0x3C
+ && p_sei[3] == 0x00
+ && p_sei[4] == 0x01
+ && p_sei[5] == 0x04) {
+ char *new_buf;
+ hevc->sei_present_flag |= SEI_HDR10PLUS_MASK;
+ new_buf = vzalloc(payload_size);
+ if (new_buf) {
+ memcpy(new_buf, p_sei, payload_size);
+ pic->hdr10p_data_buf = new_buf;
+ pic->hdr10p_data_size = payload_size;
+ } else {
+ hevc_print(hevc, 0,
+ "%s:hdr10p data vzalloc size(%d) fail\n",
+ __func__, payload_size);
+ pic->hdr10p_data_buf = NULL;
+ pic->hdr10p_data_size = 0;
+ }
+ }
+
+ break;
+ case SEI_MasteringDisplayColorVolume:
+ /*hevc_print(hevc, 0,
+ "sei type: primary display color volume %d, size %d\n",
+ payload_type,
+ payload_size);*/
+ /* master_display_colour */
+ p_sei = p;
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 2; j++) {
+ hevc->primaries[i][j]
+ = (*p_sei<<8)
+ | *(p_sei+1);
+ p_sei += 2;
+ }
+ }
+ for (i = 0; i < 2; i++) {
+ hevc->white_point[i]
+ = (*p_sei<<8)
+ | *(p_sei+1);
+ p_sei += 2;
+ }
+ for (i = 0; i < 2; i++) {
+ hevc->luminance[i]
+ = (*p_sei<<24)
+ | (*(p_sei+1)<<16)
+ | (*(p_sei+2)<<8)
+ | *(p_sei+3);
+ p_sei += 4;
+ }
+ hevc->sei_present_flag |=
+ SEI_MASTER_DISPLAY_COLOR_MASK;
+ /*for (i = 0; i < 3; i++)
+ for (j = 0; j < 2; j++)
+ hevc_print(hevc, 0,
+ "\tprimaries[%1d][%1d] = %04x\n",
+ i, j,
+ hevc->primaries[i][j]);
+ hevc_print(hevc, 0,
+ "\twhite_point = (%04x, %04x)\n",
+ hevc->white_point[0],
+ hevc->white_point[1]);
+ hevc_print(hevc, 0,
+ "\tmax,min luminance = %08x, %08x\n",
+ hevc->luminance[0],
+ hevc->luminance[1]);*/
+ break;
+ case SEI_ContentLightLevel:
+ if (get_dbg_flag(hevc) & H265_DEBUG_PRINT_SEI)
+ hevc_print(hevc, 0,
+ "sei type: max content light level %d, size %d\n",
+ payload_type, payload_size);
+ /* content_light_level */
+ p_sei = p;
+ hevc->content_light_level[0]
+ = (*p_sei<<8) | *(p_sei+1);
+ p_sei += 2;
+ hevc->content_light_level[1]
+ = (*p_sei<<8) | *(p_sei+1);
+ p_sei += 2;
+ hevc->sei_present_flag |=
+ SEI_CONTENT_LIGHT_LEVEL_MASK;
+ if (get_dbg_flag(hevc) & H265_DEBUG_PRINT_SEI)
+ hevc_print(hevc, 0,
+ "\tmax cll = %04x, max_pa_cll = %04x\n",
+ hevc->content_light_level[0],
+ hevc->content_light_level[1]);
+ break;
+ default:
+ break;
+ }
+ }
+ p += payload_size;
+ }
+ return 0;
+}
+
+/*
+static unsigned calc_ar(unsigned idc, unsigned sar_w, unsigned sar_h,
+ unsigned w, unsigned h)
+{
+ unsigned ar;
+
+ if (idc == 255) {
+ ar = div_u64(256ULL * sar_h * h,
+ sar_w * w);
+ } else {
+ switch (idc) {
+ case 1:
+ ar = 0x100 * h / w;
+ break;
+ case 2:
+ ar = 0x100 * h * 11 / (w * 12);
+ break;
+ case 3:
+ ar = 0x100 * h * 11 / (w * 10);
+ break;
+ case 4:
+ ar = 0x100 * h * 11 / (w * 16);
+ break;
+ case 5:
+ ar = 0x100 * h * 33 / (w * 40);
+ break;
+ case 6:
+ ar = 0x100 * h * 11 / (w * 24);
+ break;
+ case 7:
+ ar = 0x100 * h * 11 / (w * 20);
+ break;
+ case 8:
+ ar = 0x100 * h * 11 / (w * 32);
+ break;
+ case 9:
+ ar = 0x100 * h * 33 / (w * 80);
+ break;
+ case 10:
+ ar = 0x100 * h * 11 / (w * 18);
+ break;
+ case 11:
+ ar = 0x100 * h * 11 / (w * 15);
+ break;
+ case 12:
+ ar = 0x100 * h * 33 / (w * 64);
+ break;
+ case 13:
+ ar = 0x100 * h * 99 / (w * 160);
+ break;
+ case 14:
+ ar = 0x100 * h * 3 / (w * 4);
+ break;
+ case 15:
+ ar = 0x100 * h * 2 / (w * 3);
+ break;
+ case 16:
+ ar = 0x100 * h * 1 / (w * 2);
+ break;
+ default:
+ ar = h * 0x100 / w;
+ break;
+ }
+ }
+
+ return ar;
+}
+*/
+static void set_frame_info(struct hevc_state_s *hevc, struct vframe_s *vf,
+ struct PIC_s *pic)
+{
+ unsigned int ar;
+ int i, j;
+ char *p;
+ unsigned size = 0;
+ unsigned type = 0;
+ struct vframe_master_display_colour_s *vf_dp
+ = &vf->prop.master_display_colour;
+
+ vf->width = pic->width /
+ get_double_write_ratio(hevc, pic->double_write_mode);
+ vf->height = pic->height /
+ get_double_write_ratio(hevc, pic->double_write_mode);
+
+ vf->duration = hevc->frame_dur;
+ vf->duration_pulldown = 0;
+ vf->flag = 0;
+
+ ar = min_t(u32, hevc->frame_ar, DISP_RATIO_ASPECT_RATIO_MAX);
+ vf->ratio_control = (ar << DISP_RATIO_ASPECT_RATIO_BIT);
+
+/*
+ if (((pic->aspect_ratio_idc == 255) &&
+ pic->sar_width &&
+ pic->sar_height) ||
+ ((pic->aspect_ratio_idc != 255) &&
+ (pic->width))) {
+ ar = min_t(u32,
+ calc_ar(pic->aspect_ratio_idc,
+ pic->sar_width,
+ pic->sar_height,
+ pic->width,
+ pic->height),
+ DISP_RATIO_ASPECT_RATIO_MAX);
+ vf->ratio_control = (ar << DISP_RATIO_ASPECT_RATIO_BIT);
+ vf->ratio_control <<= hevc->interlace_flag;
+ }
+*/
+ hevc->ratio_control = vf->ratio_control;
+ if (pic->aux_data_buf
+ && pic->aux_data_size) {
+ /* parser sei */
+ p = pic->aux_data_buf;
+ while (p < pic->aux_data_buf
+ + pic->aux_data_size - 8) {
+ size = *p++;
+ size = (size << 8) | *p++;
+ size = (size << 8) | *p++;
+ size = (size << 8) | *p++;
+ type = *p++;
+ type = (type << 8) | *p++;
+ type = (type << 8) | *p++;
+ type = (type << 8) | *p++;
+ if (type == 0x02000000) {
+ /* hevc_print(hevc, 0,
+ "sei(%d)\n", size); */
+ parse_sei(hevc, pic, p, size);
+ }
+ p += size;
+ }
+ }
+ if (hevc->video_signal_type & VIDEO_SIGNAL_TYPE_AVAILABLE_MASK) {
+ vf->signal_type = pic->video_signal_type;
+ if (hevc->sei_present_flag & SEI_HDR10PLUS_MASK) {
+ u32 data;
+ data = vf->signal_type;
+ data = data & 0xFFFF00FF;
+ data = data | (0x30<<8);
+ vf->signal_type = data;
+ }
+ }
+ else
+ vf->signal_type = 0;
+ hevc->video_signal_type_debug = vf->signal_type;
+
+ /* master_display_colour */
+ if (hevc->sei_present_flag & SEI_MASTER_DISPLAY_COLOR_MASK) {
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 2; j++)
+ vf_dp->primaries[i][j] = hevc->primaries[i][j];
+ for (i = 0; i < 2; i++) {
+ vf_dp->white_point[i] = hevc->white_point[i];
+ vf_dp->luminance[i]
+ = hevc->luminance[i];
+ }
+ vf_dp->present_flag = 1;
+ } else
+ vf_dp->present_flag = 0;
+
+ /* content_light_level */
+ if (hevc->sei_present_flag & SEI_CONTENT_LIGHT_LEVEL_MASK) {
+ vf_dp->content_light_level.max_content
+ = hevc->content_light_level[0];
+ vf_dp->content_light_level.max_pic_average
+ = hevc->content_light_level[1];
+ vf_dp->content_light_level.present_flag = 1;
+ } else
+ vf_dp->content_light_level.present_flag = 0;
+
+ if (hevc->is_used_v4l &&
+ ((hevc->sei_present_flag & SEI_HDR10PLUS_MASK) ||
+ (vf_dp->present_flag) ||
+ (vf_dp->content_light_level.present_flag))) {
+ struct aml_vdec_hdr_infos hdr;
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(hevc->v4l2_ctx);
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.signal_type = vf->signal_type;
+ hdr.color_parms = *vf_dp;
+ vdec_v4l_set_hdr_infos(ctx, &hdr);
+ }
+
+ if ((hevc->sei_present_flag & SEI_HDR10PLUS_MASK) && (pic->hdr10p_data_buf != NULL)
+ && (pic->hdr10p_data_size != 0)) {
+ char *new_buf;
+ new_buf = vzalloc(pic->hdr10p_data_size);
+
+ if (new_buf) {
+ memcpy(new_buf, pic->hdr10p_data_buf, pic->hdr10p_data_size);
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR_MORE) {
+ hevc_print(hevc, 0,
+ "hdr10p data: (size %d)\n",
+ pic->hdr10p_data_size);
+ for (i = 0; i < pic->hdr10p_data_size; i++) {
+ hevc_print_cont(hevc, 0,
+ "%02x ", pic->hdr10p_data_buf[i]);
+ if (((i + 1) & 0xf) == 0)
+ hevc_print_cont(hevc, 0, "\n");
+ }
+ hevc_print_cont(hevc, 0, "\n");
+ }
+
+ vf->hdr10p_data_size = pic->hdr10p_data_size;
+ vf->hdr10p_data_buf = new_buf;
+ } else {
+ hevc_print(hevc, 0,
+ "%s:hdr10p data vzalloc size(%d) fail\n",
+ __func__, pic->hdr10p_data_size);
+ vf->hdr10p_data_buf = NULL;
+ vf->hdr10p_data_size = 0;
+ }
+
+ vfree(pic->hdr10p_data_buf);
+ pic->hdr10p_data_buf = NULL;
+ pic->hdr10p_data_size = 0;
+ }
+
+ vf->sidebind_type = hevc->sidebind_type;
+ vf->sidebind_channel_id = hevc->sidebind_channel_id;
+}
+
+static int vh265_vf_states(struct vframe_states *states, void *op_arg)
+{
+ unsigned long flags;
+#ifdef MULTI_INSTANCE_SUPPORT
+ struct vdec_s *vdec = op_arg;
+ struct hevc_state_s *hevc = (struct hevc_state_s *)vdec->private;
+#else
+ struct hevc_state_s *hevc = (struct hevc_state_s *)op_arg;
+#endif
+
+ spin_lock_irqsave(&lock, flags);
+
+ states->vf_pool_size = VF_POOL_SIZE;
+ states->buf_free_num = kfifo_len(&hevc->newframe_q);
+ states->buf_avail_num = kfifo_len(&hevc->display_q);
+
+ if (step == 2)
+ states->buf_avail_num = 0;
+ spin_unlock_irqrestore(&lock, flags);
+ return 0;
+}
+
+static struct vframe_s *vh265_vf_peek(void *op_arg)
+{
+ struct vframe_s *vf[2] = {0, 0};
+#ifdef MULTI_INSTANCE_SUPPORT
+ struct vdec_s *vdec = op_arg;
+ struct hevc_state_s *hevc = (struct hevc_state_s *)vdec->private;
+#else
+ struct hevc_state_s *hevc = (struct hevc_state_s *)op_arg;
+#endif
+
+ if (step == 2)
+ return NULL;
+
+ if (force_disp_pic_index & 0x100) {
+ if (force_disp_pic_index & 0x200)
+ return NULL;
+ return &hevc->vframe_dummy;
+ }
+
+
+ if (kfifo_out_peek(&hevc->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 *vh265_vf_get(void *op_arg)
+{
+ struct vframe_s *vf;
+#ifdef MULTI_INSTANCE_SUPPORT
+ struct vdec_s *vdec = op_arg;
+ struct hevc_state_s *hevc = (struct hevc_state_s *)vdec->private;
+#else
+ struct hevc_state_s *hevc = (struct hevc_state_s *)op_arg;
+#endif
+
+ if (step == 2)
+ return NULL;
+ else if (step == 1)
+ step = 2;
+#if 0
+ if (force_disp_pic_index & 0x100) {
+ int buffer_index = force_disp_pic_index & 0xff;
+ struct PIC_s *pic = NULL;
+ if (buffer_index >= 0
+ && buffer_index < MAX_REF_PIC_NUM)
+ pic = hevc->m_PIC[buffer_index];
+ if (pic == NULL)
+ return NULL;
+ if (force_disp_pic_index & 0x200)
+ return NULL;
+
+ vf = &hevc->vframe_dummy;
+ if (get_double_write_mode(hevc)) {
+ vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD |
+ VIDTYPE_VIU_NV21;
+ if (hevc->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 {
+ vf->canvas0Addr = vf->canvas1Addr
+ = spec2canvas(pic);
+ }
+ } else {
+ vf->canvas0Addr = vf->canvas1Addr = 0;
+ vf->type = VIDTYPE_COMPRESS | VIDTYPE_VIU_FIELD;
+ if (hevc->mmu_enable)
+ vf->type |= VIDTYPE_SCATTER;
+ }
+ vf->compWidth = pic->width;
+ vf->compHeight = pic->height;
+ update_vf_memhandle(hevc, vf, pic);
+ switch (hevc->bit_depth_luma) {
+ case 9:
+ vf->bitdepth = BITDEPTH_Y9 | BITDEPTH_U9 | BITDEPTH_V9;
+ break;
+ case 10:
+ vf->bitdepth = BITDEPTH_Y10 | BITDEPTH_U10
+ | BITDEPTH_V10;
+ break;
+ default:
+ vf->bitdepth = BITDEPTH_Y8 | BITDEPTH_U8 | BITDEPTH_V8;
+ break;
+ }
+ if ((vf->type & VIDTYPE_COMPRESS) == 0)
+ vf->bitdepth =
+ BITDEPTH_Y8 | BITDEPTH_U8 | BITDEPTH_V8;
+ if (hevc->mem_saving_mode == 1)
+ vf->bitdepth |= BITDEPTH_SAVING_MODE;
+ vf->duration_pulldown = 0;
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+ set_frame_info(hevc, vf);
+
+ vf->width = pic->width /
+ get_double_write_ratio(hevc, pic->double_write_mode);
+ vf->height = pic->height /
+ get_double_write_ratio(hevc, pic->double_write_mode);
+
+ force_disp_pic_index |= 0x200;
+ return vf;
+ }
+#endif
+
+ if (kfifo_get(&hevc->display_q, &vf)) {
+ struct vframe_s *next_vf = NULL;
+
+ ATRACE_COUNTER(hevc->vf_get_name, (long)vf);
+ ATRACE_COUNTER(hevc->disp_q_name, kfifo_len(&hevc->display_q));
+#ifdef MULTI_INSTANCE_SUPPORT
+ ATRACE_COUNTER(hevc->set_canvas0_addr, vf->canvas0_config[0].phy_addr);
+#else
+ ATRACE_COUNTER(hevc->get_canvas0_addr, vf->canvas0Addr);
+#endif
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT) {
+ hevc_print(hevc, 0,
+ "%s(vf 0x%p type %d index 0x%x poc %d/%d) pts(%d,%ld) dur %d\n",
+ __func__, vf, vf->type, vf->index,
+ get_pic_poc(hevc, vf->index & 0xff),
+ get_pic_poc(hevc, (vf->index >> 8) & 0xff),
+ vf->pts, vf->pts_us64,
+ vf->duration);
+#ifdef MULTI_INSTANCE_SUPPORT
+ hevc_print(hevc, 0, "get canvas0 addr:0x%x\n", vf->canvas0_config[0].phy_addr);
+#else
+ hevc_print(hevc, 0, "get canvas0 addr:0x%x\n", vf->canvas0Addr);
+#endif
+ }
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ if (get_dbg_flag(hevc) & H265_DEBUG_DV) {
+ struct PIC_s *pic = hevc->m_PIC[vf->index & 0xff];
+ hevc_print(hevc, 0, "pic 0x%p aux size %d:\n",
+ pic, pic->aux_data_size);
+ if (pic->aux_data_buf && pic->aux_data_size > 0) {
+ int i;
+ for (i = 0; i < pic->aux_data_size; i++) {
+ hevc_print_cont(hevc, 0,
+ "%02x ", pic->aux_data_buf[i]);
+ if (((i + 1) & 0xf) == 0)
+ hevc_print_cont(hevc, 0, "\n");
+ }
+ hevc_print_cont(hevc, 0, "\n");
+ }
+ }
+#endif
+ hevc->show_frame_num++;
+ vf->index_disp = hevc->vf_get_count;
+ hevc->vf_get_count++;
+
+ if (kfifo_peek(&hevc->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 hevc_state_s *hevc) {
+ int i;
+ for (i = 0; i < VF_POOL_SIZE; i++) {
+ if (vf == &hevc->vfpool[i] || vf == &hevc->vframe_dummy)
+ return true;
+ }
+ hevc_print(hevc, 0," h265 invalid vf been put, vf = %p\n", vf);
+ for (i = 0; i < VF_POOL_SIZE; i++) {
+ hevc_print(hevc, PRINT_FLAG_VDEC_STATUS,"valid vf[%d]= %p \n", i, &hevc->vfpool[i]);
+ }
+ return false;
+}
+
+static void vh265_vf_put(struct vframe_s *vf, void *op_arg)
+{
+ unsigned long flags;
+#ifdef MULTI_INSTANCE_SUPPORT
+ struct vdec_s *vdec = op_arg;
+ struct hevc_state_s *hevc = (struct hevc_state_s *)vdec->private;
+#else
+ struct hevc_state_s *hevc = (struct hevc_state_s *)op_arg;
+#endif
+ unsigned char index_top;
+ unsigned char index_bot;
+
+ if (vf && (vf_valid_check(vf, hevc) == false))
+ return;
+ if (vf == (&hevc->vframe_dummy))
+ return;
+ if (!vf)
+ return;
+
+ ATRACE_COUNTER(hevc->vf_put_name, (long)vf);
+#ifdef MULTI_INSTANCE_SUPPORT
+ ATRACE_COUNTER(hevc->put_canvas0_addr, vf->canvas0_config[0].phy_addr);
+#else
+ ATRACE_COUNTER(hevc->put_canvas0_addr, vf->canvas0Addr);
+#endif
+
+ index_top = vf->index & 0xff;
+ index_bot = (vf->index >> 8) & 0xff;
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT)
+ hevc_print(hevc, 0,
+ "%s(vf 0x%p type %d index 0x%x put canvas0 addr:0x%x)\n",
+ __func__, vf, vf->type, vf->index
+#ifdef MULTI_INSTANCE_SUPPORT
+ , vf->canvas0_config[0].phy_addr
+#else
+ , vf->canvas0Addr
+#endif
+ );
+
+ hevc->vf_put_count++;
+ spin_lock_irqsave(&lock, flags);
+ kfifo_put(&hevc->newframe_q, (const struct vframe_s *)vf);
+ ATRACE_COUNTER(hevc->new_q_name, kfifo_len(&hevc->newframe_q));
+ if (hevc->enable_fence && vf->fence) {
+ vdec_fence_put(vf->fence);
+ vf->fence = NULL;
+ }
+
+ if (vf->hdr10p_data_buf) {
+ vfree(vf->hdr10p_data_buf);
+ vf->hdr10p_data_buf = NULL;
+ vf->hdr10p_data_size = 0;
+ }
+
+ if (index_top != 0xff
+ && index_top < MAX_REF_PIC_NUM
+ && hevc->m_PIC[index_top]) {
+ if (hevc->is_used_v4l)
+ hevc->m_PIC[index_top]->vframe_bound = true;
+ if (hevc->m_PIC[index_top]->vf_ref > 0) {
+ hevc->m_PIC[index_top]->vf_ref--;
+
+ if (hevc->m_PIC[index_top]->vf_ref == 0) {
+ hevc->m_PIC[index_top]->output_ready = 0;
+ hevc->m_PIC[index_top]->show_frame = false;
+
+ if (hevc->wait_buf != 0)
+ WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG,
+ 0x1);
+ }
+ }
+ }
+
+ if (index_bot != 0xff
+ && index_bot < MAX_REF_PIC_NUM
+ && hevc->m_PIC[index_bot]) {
+ if (hevc->is_used_v4l)
+ hevc->m_PIC[index_bot]->vframe_bound = true;
+ if (hevc->m_PIC[index_bot]->vf_ref > 0) {
+ hevc->m_PIC[index_bot]->vf_ref--;
+
+ if (hevc->m_PIC[index_bot]->vf_ref == 0) {
+ hevc->m_PIC[index_bot]->output_ready = 0;
+ hevc->m_PIC[index_bot]->show_frame = false;
+
+ if (hevc->wait_buf != 0)
+ WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG,
+ 0x1);
+ }
+ }
+ }
+ spin_unlock_irqrestore(&lock, flags);
+}
+
+static int vh265_event_cb(int type, void *data, void *op_arg)
+{
+ unsigned long flags;
+#ifdef MULTI_INSTANCE_SUPPORT
+ struct vdec_s *vdec = op_arg;
+ struct hevc_state_s *hevc = (struct hevc_state_s *)vdec->private;
+#else
+ struct hevc_state_s *hevc = (struct hevc_state_s *)op_arg;
+#endif
+ if (type & VFRAME_EVENT_RECEIVER_RESET) {
+#if 0
+ amhevc_stop();
+#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vf_light_unreg_provider(&vh265_vf_prov);
+#endif
+ spin_lock_irqsave(&hevc->lock, flags);
+ vh265_local_init();
+ vh265_prot_init();
+ spin_unlock_irqrestore(&hevc->lock, flags);
+#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vf_reg_provider(&vh265_vf_prov);
+#endif
+ amhevc_start();
+#endif
+ } else if (type & VFRAME_EVENT_RECEIVER_GET_AUX_DATA) {
+ struct provider_aux_req_s *req =
+ (struct provider_aux_req_s *)data;
+ unsigned char index;
+
+ if (!req->vf) {
+ req->aux_size = hevc->vf_put_count;
+ return 0;
+ }
+ spin_lock_irqsave(&lock, flags);
+ index = req->vf->index & 0xff;
+ req->aux_buf = NULL;
+ req->aux_size = 0;
+ if (req->bot_flag)
+ index = (req->vf->index >> 8) & 0xff;
+ if (index != 0xff
+ && index < MAX_REF_PIC_NUM
+ && hevc->m_PIC[index]) {
+ req->aux_buf = hevc->m_PIC[index]->aux_data_buf;
+ req->aux_size = hevc->m_PIC[index]->aux_data_size;
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ if (hevc->bypass_dvenl && !dolby_meta_with_el)
+ req->dv_enhance_exist = false;
+ else
+ req->dv_enhance_exist =
+ hevc->m_PIC[index]->dv_enhance_exist;
+ if (vdec_frame_based(vdec) && (hevc->dv_duallayer == true))
+ req->dv_enhance_exist = 1;
+ hevc_print(hevc, H265_DEBUG_DV,
+ "query dv_enhance_exist for (pic 0x%p, vf 0x%p, poc %d index %d) flag => %d, aux sizd 0x%x\n",
+ hevc->m_PIC[index],
+ req->vf,
+ hevc->m_PIC[index]->POC, index,
+ req->dv_enhance_exist, req->aux_size);
+#else
+ req->dv_enhance_exist = 0;
+#endif
+ }
+ spin_unlock_irqrestore(&lock, flags);
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT)
+ hevc_print(hevc, 0,
+ "%s(type 0x%x vf index 0x%x)=>size 0x%x\n",
+ __func__, type, index, req->aux_size);
+ }
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ else if (type & VFRAME_EVENT_RECEIVER_DOLBY_BYPASS_EL) {
+ if ((force_bypass_dvenl & 0x80000000) == 0) {
+ hevc_print(hevc, 0,
+ "%s: VFRAME_EVENT_RECEIVER_DOLBY_BYPASS_EL\n",
+ __func__);
+ hevc->bypass_dvenl_enable = 1;
+ }
+ }
+#endif
+ 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;
+}
+
+#ifdef HEVC_PIC_STRUCT_SUPPORT
+static int process_pending_vframe(struct hevc_state_s *hevc,
+ struct PIC_s *pair_pic, unsigned char pair_frame_top_flag)
+{
+ struct vframe_s *vf;
+
+ if (!pair_pic)
+ return -1;
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT)
+ hevc_print(hevc, 0,
+ "%s: pair_pic index 0x%x %s\n",
+ __func__, pair_pic->index,
+ pair_frame_top_flag ?
+ "top" : "bot");
+
+ if (kfifo_len(&hevc->pending_q) > 1) {
+ unsigned long flags;
+ /* do not pending more than 1 frame */
+ if (kfifo_get(&hevc->pending_q, &vf) == 0) {
+ hevc_print(hevc, 0,
+ "fatal error, no available buffer slot.");
+ return -1;
+ }
+ if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT)
+ hevc_print(hevc, 0,
+ "%s warning(1), vf=>display_q: (index 0x%x)\n",
+ __func__, vf->index);
+ if ((pair_pic->double_write_mode == 3) &&
+ (!(IS_8K_SIZE(vf->width, vf->height)))) {
+ vf->type |= VIDTYPE_COMPRESS;
+ if (hevc->mmu_enable)
+ vf->type |= VIDTYPE_SCATTER;
+ }
+ hevc->vf_pre_count++;
+ spin_lock_irqsave(&lock, flags);
+ kfifo_put(&hevc->newframe_q, (const struct vframe_s *)vf);
+ vf->index &= 0xff;
+ if (vf->index >= MAX_REF_PIC_NUM) {
+ spin_unlock_irqrestore(&lock, flags);
+ return -1;
+ }
+ hevc->m_PIC[vf->index]->vf_ref = 0;
+ hevc->m_PIC[vf->index]->output_ready = 0;
+ if (hevc->wait_buf != 0)
+ WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG,
+ 0x1);
+ spin_unlock_irqrestore(&lock, flags);
+
+ ATRACE_COUNTER(hevc->pts_name, vf->pts);
+ }
+
+ if (kfifo_peek(&hevc->pending_q, &vf)) {
+ if (pair_pic->vf_ref <= 0) {
+ /*
+ *if pair_pic is recycled (pair_pic->vf_ref <= 0),
+ *do not use it
+ */
+ if (kfifo_get(&hevc->pending_q, &vf) == 0) {
+ hevc_print(hevc, 0,
+ "fatal error, no available buffer slot.");
+ return -1;
+ }
+ if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT)
+ hevc_print(hevc, 0,
+ "%s warning(2), vf=>display_q: (index 0x%x)\n",
+ __func__, vf->index);
+ if (vf) {
+ if ((pair_pic->double_write_mode == 3) &&
+ (!(IS_8K_SIZE(vf->width, vf->height)))) {
+ vf->type |= VIDTYPE_COMPRESS;
+ if (hevc->mmu_enable)
+ vf->type |= VIDTYPE_SCATTER;
+ }
+ hevc->vf_pre_count++;
+ vdec_vframe_ready(hw_to_vdec(hevc), vf);
+ kfifo_put(&hevc->display_q,
+ (const struct vframe_s *)vf);
+ ATRACE_COUNTER(hevc->pts_name, vf->pts);
+ }
+ } else if ((!pair_frame_top_flag) &&
+ (((vf->index >> 8) & 0xff) == 0xff)) {
+ if (kfifo_get(&hevc->pending_q, &vf) == 0) {
+ hevc_print(hevc, 0,
+ "fatal error, no available buffer slot.");
+ return -1;
+ }
+ if (vf) {
+ if ((pair_pic->double_write_mode == 3) &&
+ (!(IS_8K_SIZE(vf->width, vf->height)))) {
+ vf->type |= VIDTYPE_COMPRESS;
+ if (hevc->mmu_enable)
+ vf->type |= VIDTYPE_SCATTER;
+ }
+ vf->index &= 0xff;
+ vf->index |= (pair_pic->index << 8);
+ pair_pic->vf_ref++;
+ vdec_vframe_ready(hw_to_vdec(hevc), vf);
+ kfifo_put(&hevc->display_q,
+ (const struct vframe_s *)vf);
+ ATRACE_COUNTER(hevc->pts_name, vf->pts);
+ hevc->vf_pre_count++;
+ if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT)
+ hevc_print(hevc, 0,
+ "%s vf => display_q: (index 0x%x)\n",
+ __func__, vf->index);
+ }
+ } else if (pair_frame_top_flag &&
+ ((vf->index & 0xff) == 0xff)) {
+ if (kfifo_get(&hevc->pending_q, &vf) == 0) {
+ hevc_print(hevc, 0,
+ "fatal error, no available buffer slot.");
+ return -1;
+ }
+ if (vf) {
+ if ((pair_pic->double_write_mode == 3) &&
+ (!(IS_8K_SIZE(vf->width, vf->height)))) {
+ vf->type |= VIDTYPE_COMPRESS;
+ if (hevc->mmu_enable)
+ vf->type |= VIDTYPE_SCATTER;
+ }
+ vf->index &= 0xff00;
+ vf->index |= pair_pic->index;
+ pair_pic->vf_ref++;
+ vdec_vframe_ready(hw_to_vdec(hevc), vf);
+ kfifo_put(&hevc->display_q,
+ (const struct vframe_s *)vf);
+ ATRACE_COUNTER(hevc->pts_name, vf->pts);
+ hevc->vf_pre_count++;
+ if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT)
+ hevc_print(hevc, 0,
+ "%s vf => display_q: (index 0x%x)\n",
+ __func__, vf->index);
+ }
+ }
+ }
+ return 0;
+}
+#endif
+static void update_vf_memhandle(struct hevc_state_s *hevc,
+ struct vframe_s *vf, struct PIC_s *pic)
+{
+ if (pic->index < 0) {
+ vf->mem_handle = NULL;
+ vf->mem_head_handle = NULL;
+ } else if (vf->type & VIDTYPE_SCATTER) {
+ vf->mem_handle =
+ decoder_mmu_box_get_mem_handle(
+ hevc->mmu_box, pic->index);
+ vf->mem_head_handle =
+ decoder_bmmu_box_get_mem_handle(
+ hevc->bmmu_box, VF_BUFFER_IDX(pic->BUF_index));
+ } else {
+ vf->mem_handle =
+ decoder_bmmu_box_get_mem_handle(
+ hevc->bmmu_box, VF_BUFFER_IDX(pic->BUF_index));
+ vf->mem_head_handle = NULL;
+ /*vf->mem_head_handle =
+ decoder_bmmu_box_get_mem_handle(
+ hevc->bmmu_box, VF_BUFFER_IDX(BUF_index));*/
+ }
+ return;
+}
+
+static void fill_frame_info(struct hevc_state_s *hevc,
+ struct PIC_s *pic, unsigned int framesize, unsigned int pts)
+{
+ struct vframe_qos_s *vframe_qos = &hevc->vframe_qos;
+ if (hevc->m_nalUnitType == NAL_UNIT_CODED_SLICE_IDR)
+ vframe_qos->type = 4;
+ else if (pic->slice_type == I_SLICE)
+ vframe_qos->type = 1;
+ else if (pic->slice_type == P_SLICE)
+ vframe_qos->type = 2;
+ else if (pic->slice_type == B_SLICE)
+ vframe_qos->type = 3;
+/*
+#define SHOW_QOS_INFO
+*/
+ if (input_frame_based(hw_to_vdec(hevc)))
+ vframe_qos->size = pic->frame_size;
+ else
+ vframe_qos->size = framesize;
+ vframe_qos->pts = pts;
+#ifdef SHOW_QOS_INFO
+ hevc_print(hevc, 0, "slice:%d, poc:%d\n", pic->slice_type, pic->POC);
+#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
+ hevc_print(hevc, 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
+ hevc_print(hevc, 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
+ hevc_print(hevc, 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 inline void hevc_update_gvs(struct hevc_state_s *hevc)
+{
+ if (hevc->gvs->frame_height != hevc->frame_height) {
+ hevc->gvs->frame_width = hevc->frame_width;
+ hevc->gvs->frame_height = hevc->frame_height;
+ }
+ if (hevc->gvs->frame_dur != hevc->frame_dur) {
+ hevc->gvs->frame_dur = hevc->frame_dur;
+ if (hevc->frame_dur != 0)
+ hevc->gvs->frame_rate = ((96000 * 10 / hevc->frame_dur) % 10) < 5 ?
+ 96000 / hevc->frame_dur : (96000 / hevc->frame_dur +1);
+ else
+ hevc->gvs->frame_rate = -1;
+ }
+ hevc->gvs->error_count = hevc->gvs->error_frame_count;
+ hevc->gvs->status = hevc->stat | hevc->fatal_error;
+ if (hevc->gvs->ratio_control != hevc->ratio_control)
+ hevc->gvs->ratio_control = hevc->ratio_control;
+}
+
+static void put_vf_to_display_q(struct hevc_state_s *hevc, struct vframe_s *vf)
+{
+ hevc->vf_pre_count++;
+ decoder_do_frame_check(hw_to_vdec(hevc), vf);
+ vdec_vframe_ready(hw_to_vdec(hevc), vf);
+ kfifo_put(&hevc->display_q, (const struct vframe_s *)vf);
+ ATRACE_COUNTER(hevc->pts_name, vf->pts);
+}
+
+static int post_prepare_process(struct vdec_s *vdec, struct PIC_s *frame)
+{
+ struct hevc_state_s *hevc = (struct hevc_state_s *)vdec->private;
+
+ if (force_disp_pic_index & 0x100) {
+ /*recycle directly*/
+ frame->output_ready = 0;
+ frame->show_frame = false;
+ hevc_print(hevc, 0, "discard show frame.\n");
+ return -1;
+ }
+
+ frame->show_frame = true;
+
+ return 0;
+}
+
+static int post_video_frame(struct vdec_s *vdec, struct PIC_s *pic)
+{
+ struct hevc_state_s *hevc = (struct hevc_state_s *)vdec->private;
+ struct vframe_s *vf = NULL;
+ int stream_offset = pic->stream_offset;
+ unsigned short slice_type = pic->slice_type;
+ ulong nv_order = VIDTYPE_VIU_NV21;
+ u32 frame_size = 0;
+ struct vdec_info tmp4x;
+ struct aml_vcodec_ctx * v4l2_ctx = hevc->v4l2_ctx;
+
+ /* swap uv */
+ if (hevc->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 (kfifo_get(&hevc->newframe_q, &vf) == 0) {
+ hevc_print(hevc, 0,
+ "fatal error, no available buffer slot.");
+ return -1;
+ }
+
+ if (vf) {
+ /*hevc_print(hevc, PRINT_FLAG_VDEC_STATUS,
+ "%s: pic index 0x%x\n",
+ __func__, pic->index);*/
+
+ if (hevc->is_used_v4l) {
+ vf->v4l_mem_handle
+ = hevc->m_BUF[pic->BUF_index].v4l_ref_buf_addr;
+ if (hevc->mmu_enable) {
+ vf->mm_box.bmmu_box = hevc->bmmu_box;
+ vf->mm_box.bmmu_idx = VF_BUFFER_IDX(pic->BUF_index);
+ vf->mm_box.mmu_box = hevc->mmu_box;
+ vf->mm_box.mmu_idx = pic->index;
+ }
+ }
+
+ if (hevc->enable_fence) {
+ /* fill fence information. */
+ if (hevc->fence_usage == FENCE_USE_FOR_DRIVER)
+ vf->fence = pic->fence;
+ }
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (vdec_frame_based(vdec)) {
+ vf->pts = pic->pts;
+ vf->pts_us64 = pic->pts64;
+ vf->timestamp = pic->timestamp;
+ }
+ /* if (pts_lookup_offset(PTS_TYPE_VIDEO,
+ stream_offset, &vf->pts, 0) != 0) { */
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ else if (vdec->master == NULL) {
+#else
+ else {
+#endif
+#endif
+ hevc_print(hevc, H265_DEBUG_OUT_PTS,
+ "call pts_lookup_offset_us64(0x%x)\n",
+ stream_offset);
+ if ((vdec->vbuf.no_parser == 0) || (vdec->vbuf.use_ptsserv)) {
+ if (pts_lookup_offset_us64
+ (PTS_TYPE_VIDEO, stream_offset, &vf->pts,
+ &frame_size, 0, &vf->pts_us64) != 0) {
+#ifdef DEBUG_PTS
+ hevc->pts_missed++;
+#endif
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+ } else {
+#ifdef DEBUG_PTS
+ hevc->pts_hit++;
+#endif
+ }
+ }
+
+#ifdef MULTI_INSTANCE_SUPPORT
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ } else {
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+ }
+#else
+ }
+#endif
+#endif
+ if (pts_unstable && (hevc->frame_dur > 0))
+ hevc->pts_mode = PTS_NONE_REF_USE_DURATION;
+
+ fill_frame_info(hevc, pic, frame_size, vf->pts);
+
+ if (vf->pts != 0)
+ hevc->last_lookup_pts = vf->pts;
+
+ if ((hevc->pts_mode == PTS_NONE_REF_USE_DURATION)
+ && (slice_type != 2))
+ vf->pts = hevc->last_pts + DUR2PTS(hevc->frame_dur);
+ hevc->last_pts = vf->pts;
+
+ if (vf->pts_us64 != 0)
+ hevc->last_lookup_pts_us64 = vf->pts_us64;
+
+ if ((hevc->pts_mode == PTS_NONE_REF_USE_DURATION)
+ && (slice_type != 2)) {
+ vf->pts_us64 =
+ hevc->last_pts_us64 +
+ (DUR2PTS(hevc->frame_dur) * 100 / 9);
+ }
+ hevc->last_pts_us64 = vf->pts_us64;
+ if ((get_dbg_flag(hevc) & H265_DEBUG_OUT_PTS) != 0) {
+ hevc_print(hevc, 0,
+ "H265 dec out pts: vf->pts=%d, vf->pts_us64 = %lld\n",
+ vf->pts, vf->pts_us64);
+ }
+
+ /*
+ *vf->index:
+ *(1) vf->type is VIDTYPE_PROGRESSIVE
+ * and vf->canvas0Addr != vf->canvas1Addr,
+ * vf->index[7:0] is the index of top pic
+ * vf->index[15:8] is the index of bot pic
+ *(2) other cases,
+ * only vf->index[7:0] is used
+ * vf->index[15:8] == 0xff
+ */
+ vf->index = 0xff00 | pic->index;
+#if 1
+/*SUPPORT_10BIT*/
+ if (pic->double_write_mode & 0x10) {
+ /* double write only */
+ vf->compBodyAddr = 0;
+ vf->compHeadAddr = 0;
+ } else {
+
+ if (hevc->mmu_enable) {
+ vf->compBodyAddr = 0;
+ vf->compHeadAddr = pic->header_adr;
+ } else {
+ vf->compBodyAddr = pic->mc_y_adr; /*body adr*/
+ vf->compHeadAddr = pic->mc_y_adr +
+ pic->losless_comp_body_size;
+ vf->mem_head_handle = NULL;
+ }
+
+ /*head adr*/
+ vf->canvas0Addr = vf->canvas1Addr = 0;
+ }
+ if (pic->double_write_mode) {
+ vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD;
+ vf->type |= nv_order;
+
+ if (((pic->double_write_mode == 3) || (pic->double_write_mode == 5)) &&
+ (!(IS_8K_SIZE(pic->width, pic->height)))) {
+ vf->type |= VIDTYPE_COMPRESS;
+ if (hevc->mmu_enable)
+ vf->type |= VIDTYPE_SCATTER;
+ }
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (hevc->m_ins_flag &&
+ (get_dbg_flag(hevc)
+ & H265_CFG_CANVAS_IN_DECODE) == 0) {
+ 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;
+ if (hevc->mmu_enable)
+ vf->type |= VIDTYPE_SCATTER;
+ }
+ vf->compWidth = pic->width;
+ vf->compHeight = pic->height;
+ update_vf_memhandle(hevc, vf, pic);
+ switch (pic->bit_depth_luma) {
+ case 9:
+ vf->bitdepth = BITDEPTH_Y9;
+ break;
+ case 10:
+ vf->bitdepth = BITDEPTH_Y10;
+ break;
+ default:
+ vf->bitdepth = BITDEPTH_Y8;
+ break;
+ }
+ switch (pic->bit_depth_chroma) {
+ case 9:
+ vf->bitdepth |= (BITDEPTH_U9 | BITDEPTH_V9);
+ break;
+ case 10:
+ vf->bitdepth |= (BITDEPTH_U10 | BITDEPTH_V10);
+ break;
+ default:
+ vf->bitdepth |= (BITDEPTH_U8 | BITDEPTH_V8);
+ break;
+ }
+ if ((vf->type & VIDTYPE_COMPRESS) == 0)
+ vf->bitdepth =
+ BITDEPTH_Y8 | BITDEPTH_U8 | BITDEPTH_V8;
+ if (pic->mem_saving_mode == 1)
+ vf->bitdepth |= BITDEPTH_SAVING_MODE;
+#else
+ vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD;
+ vf->type |= nv_order;
+ vf->canvas0Addr = vf->canvas1Addr = spec2canvas(pic);
+#endif
+ set_frame_info(hevc, vf, pic);
+ if (hevc->discard_dv_data) {
+ vf->discard_dv_data = true;
+ }
+
+ /* if((vf->width!=pic->width)||(vf->height!=pic->height)) */
+ /* hevc_print(hevc, 0,
+ "aaa: %d/%d, %d/%d\n",
+ vf->width,vf->height, pic->width, pic->height); */
+ vf->width = pic->width;
+ vf->height = pic->height;
+
+ if (force_w_h != 0) {
+ vf->width = (force_w_h >> 16) & 0xffff;
+ vf->height = force_w_h & 0xffff;
+ }
+ if (force_fps & 0x100) {
+ u32 rate = force_fps & 0xff;
+
+ if (rate)
+ vf->duration = 96000/rate;
+ else
+ vf->duration = 0;
+ }
+ if (force_fps & 0x200) {
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+ }
+ if (!vdec->vbuf.use_ptsserv && vdec_stream_based(vdec)) {
+ vf->pts_us64 = stream_offset;
+ vf->pts = 0;
+ }
+ /*
+ * !!! to do ...
+ * need move below code to get_new_pic(),
+ * hevc->xxx can only be used by current decoded pic
+ */
+ if (pic->conformance_window_flag &&
+ (get_dbg_flag(hevc) &
+ H265_DEBUG_IGNORE_CONFORMANCE_WINDOW) == 0) {
+ unsigned int SubWidthC, SubHeightC;
+
+ switch (pic->chroma_format_idc) {
+ case 1:
+ SubWidthC = 2;
+ SubHeightC = 2;
+ break;
+ case 2:
+ SubWidthC = 2;
+ SubHeightC = 1;
+ break;
+ default:
+ SubWidthC = 1;
+ SubHeightC = 1;
+ break;
+ }
+ vf->width -= SubWidthC *
+ (pic->conf_win_left_offset +
+ pic->conf_win_right_offset);
+ vf->height -= SubHeightC *
+ (pic->conf_win_top_offset +
+ pic->conf_win_bottom_offset);
+
+ vf->compWidth -= SubWidthC *
+ (pic->conf_win_left_offset +
+ pic->conf_win_right_offset);
+ vf->compHeight -= SubHeightC *
+ (pic->conf_win_top_offset +
+ pic->conf_win_bottom_offset);
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ hevc_print(hevc, 0,
+ "conformance_window %d, %d, %d, %d, %d => cropped width %d, height %d com_w %d com_h %d\n",
+ pic->chroma_format_idc,
+ pic->conf_win_left_offset,
+ pic->conf_win_right_offset,
+ pic->conf_win_top_offset,
+ pic->conf_win_bottom_offset,
+ vf->width, vf->height, vf->compWidth, vf->compHeight);
+ }
+ if (hevc->cur_pic != NULL) {
+ vf->sar_width = hevc->cur_pic->sar_width;
+ vf->sar_height = hevc->cur_pic->sar_height;
+ }
+ vf->width = vf->width /
+ get_double_write_ratio(hevc, pic->double_write_mode);
+ vf->height = vf->height /
+ get_double_write_ratio(hevc, pic->double_write_mode);
+#ifdef HEVC_PIC_STRUCT_SUPPORT
+ if (pic->pic_struct == 3 || pic->pic_struct == 4) {
+ struct vframe_s *vf2;
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT)
+ hevc_print(hevc, 0,
+ "pic_struct = %d index 0x%x\n",
+ pic->pic_struct,
+ pic->index);
+
+ if (kfifo_get(&hevc->newframe_q, &vf2) == 0) {
+ hevc_print(hevc, 0,
+ "fatal error, no available buffer slot.");
+ return -1;
+ }
+ pic->vf_ref = 2;
+ vf->duration = vf->duration>>1;
+ memcpy(vf2, vf, sizeof(struct vframe_s));
+
+ if (pic->pic_struct == 3) {
+ vf->type = VIDTYPE_INTERLACE_TOP
+ | nv_order;
+ vf2->type = VIDTYPE_INTERLACE_BOTTOM
+ | nv_order;
+ } else {
+ vf->type = VIDTYPE_INTERLACE_BOTTOM
+ | nv_order;
+ vf2->type = VIDTYPE_INTERLACE_TOP
+ | nv_order;
+ }
+ put_vf_to_display_q(hevc, vf);
+ hevc->vf_pre_count++;
+ vdec_vframe_ready(hw_to_vdec(hevc), vf2);
+ kfifo_put(&hevc->display_q,
+ (const struct vframe_s *)vf2);
+ ATRACE_COUNTER(hevc->pts_name, vf2->pts);
+ } else if (pic->pic_struct == 5
+ || pic->pic_struct == 6) {
+ struct vframe_s *vf2, *vf3;
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT)
+ hevc_print(hevc, 0,
+ "pic_struct = %d index 0x%x\n",
+ pic->pic_struct,
+ pic->index);
+
+ if (kfifo_get(&hevc->newframe_q, &vf2) == 0) {
+ hevc_print(hevc, 0,
+ "fatal error, no available buffer slot.");
+ return -1;
+ }
+ if (kfifo_get(&hevc->newframe_q, &vf3) == 0) {
+ hevc_print(hevc, 0,
+ "fatal error, no available buffer slot.");
+ return -1;
+ }
+ pic->vf_ref = 3;
+ vf->duration = vf->duration/3;
+ memcpy(vf2, vf, sizeof(struct vframe_s));
+ memcpy(vf3, vf, sizeof(struct vframe_s));
+
+ if (pic->pic_struct == 5) {
+ vf->type = VIDTYPE_INTERLACE_TOP
+ | nv_order;
+ vf2->type = VIDTYPE_INTERLACE_BOTTOM
+ | nv_order;
+ vf3->type = VIDTYPE_INTERLACE_TOP
+ | nv_order;
+ } else {
+ vf->type = VIDTYPE_INTERLACE_BOTTOM
+ | nv_order;
+ vf2->type = VIDTYPE_INTERLACE_TOP
+ | nv_order;
+ vf3->type = VIDTYPE_INTERLACE_BOTTOM
+ | nv_order;
+ }
+ put_vf_to_display_q(hevc, vf);
+ hevc->vf_pre_count++;
+ vdec_vframe_ready(hw_to_vdec(hevc), vf2);
+ kfifo_put(&hevc->display_q,
+ (const struct vframe_s *)vf2);
+ ATRACE_COUNTER(hevc->pts_name, vf2->pts);
+ hevc->vf_pre_count++;
+ vdec_vframe_ready(hw_to_vdec(hevc), vf3);
+ kfifo_put(&hevc->display_q,
+ (const struct vframe_s *)vf3);
+ ATRACE_COUNTER(hevc->pts_name, vf3->pts);
+
+ } else if (pic->pic_struct == 9
+ || pic->pic_struct == 10) {
+ if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT)
+ hevc_print(hevc, 0,
+ "pic_struct = %d index 0x%x\n",
+ pic->pic_struct,
+ pic->index);
+
+ pic->vf_ref = 1;
+ /* process previous pending vf*/
+ process_pending_vframe(hevc,
+ pic, (pic->pic_struct == 9));
+
+ decoder_do_frame_check(vdec, vf);
+ vdec_vframe_ready(vdec, vf);
+ /* process current vf */
+ kfifo_put(&hevc->pending_q,
+ (const struct vframe_s *)vf);
+ vf->height <<= 1;
+ if (pic->pic_struct == 9) {
+ vf->type = VIDTYPE_INTERLACE_TOP
+ | nv_order | VIDTYPE_VIU_FIELD;
+ process_pending_vframe(hevc,
+ hevc->pre_bot_pic, 0);
+ } else {
+ vf->type = VIDTYPE_INTERLACE_BOTTOM |
+ nv_order | VIDTYPE_VIU_FIELD;
+ vf->index = (pic->index << 8) | 0xff;
+ process_pending_vframe(hevc,
+ hevc->pre_top_pic, 1);
+ }
+
+ if (hevc->vf_pre_count == 0)
+ hevc->vf_pre_count++;
+
+ /**/
+ if (pic->pic_struct == 9)
+ hevc->pre_top_pic = pic;
+ else
+ hevc->pre_bot_pic = pic;
+
+ } else if (pic->pic_struct == 11
+ || pic->pic_struct == 12) {
+ if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT)
+ hevc_print(hevc, 0,
+ "pic_struct = %d index 0x%x\n",
+ pic->pic_struct,
+ pic->index);
+ pic->vf_ref = 1;
+ /* process previous pending vf*/
+ process_pending_vframe(hevc, pic,
+ (pic->pic_struct == 11));
+
+ /* put current into pending q */
+ vf->height <<= 1;
+ if (pic->pic_struct == 11)
+ vf->type = VIDTYPE_INTERLACE_TOP |
+ nv_order | VIDTYPE_VIU_FIELD;
+ else {
+ vf->type = VIDTYPE_INTERLACE_BOTTOM |
+ nv_order | VIDTYPE_VIU_FIELD;
+ vf->index = (pic->index << 8) | 0xff;
+ }
+ decoder_do_frame_check(vdec, vf);
+ vdec_vframe_ready(vdec, vf);
+ kfifo_put(&hevc->pending_q,
+ (const struct vframe_s *)vf);
+ if (hevc->vf_pre_count == 0)
+ hevc->vf_pre_count++;
+
+ /**/
+ if (pic->pic_struct == 11)
+ hevc->pre_top_pic = pic;
+ else
+ hevc->pre_bot_pic = pic;
+
+ } else {
+ pic->vf_ref = 1;
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT)
+ hevc_print(hevc, 0,
+ "pic_struct = %d index 0x%x\n",
+ pic->pic_struct,
+ pic->index);
+
+ switch (pic->pic_struct) {
+ case 7:
+ vf->duration <<= 1;
+ break;
+ case 8:
+ vf->duration = vf->duration * 3;
+ break;
+ case 1:
+ vf->height <<= 1;
+ vf->type = VIDTYPE_INTERLACE_TOP |
+ nv_order | VIDTYPE_VIU_FIELD;
+ process_pending_vframe(hevc, pic, 1);
+ hevc->pre_top_pic = pic;
+ break;
+ case 2:
+ vf->height <<= 1;
+ vf->type = VIDTYPE_INTERLACE_BOTTOM
+ | nv_order
+ | VIDTYPE_VIU_FIELD;
+ process_pending_vframe(hevc, pic, 0);
+ hevc->pre_bot_pic = pic;
+ break;
+ }
+ put_vf_to_display_q(hevc, vf);
+ }
+#else
+ vf->type_original = vf->type;
+ pic->vf_ref = 1;
+ put_vf_to_display_q(hevc, vf);
+#endif
+ ATRACE_COUNTER(hevc->new_q_name, kfifo_len(&hevc->newframe_q));
+ ATRACE_COUNTER(hevc->disp_q_name, kfifo_len(&hevc->display_q));
+ /*count info*/
+ vdec_count_info(hevc->gvs, 0, stream_offset);
+ if (hevc->cur_pic != NULL) {
+ if (hevc->cur_pic->slice_type == I_SLICE) {
+ hevc->gvs->i_decoded_frames++;
+ } else if (hevc->cur_pic->slice_type == P_SLICE) {
+ hevc->gvs->p_decoded_frames++;
+ } else if (hevc->cur_pic->slice_type == B_SLICE) {
+ hevc->gvs->b_decoded_frames++;
+ }
+ }
+ hevc_update_gvs(hevc);
+ memcpy(&tmp4x, hevc->gvs, sizeof(struct vdec_info));
+ tmp4x.bit_depth_luma = hevc->bit_depth_luma;
+ tmp4x.bit_depth_chroma = hevc->bit_depth_chroma;
+ tmp4x.double_write_mode = get_double_write_mode(hevc);
+ vdec_fill_vdec_frame(vdec, &hevc->vframe_qos, &tmp4x, vf, pic->hw_decode_time);
+ vdec->vdec_fps_detec(vdec->id);
+ hevc_print(hevc, H265_DEBUG_BUFMGR,
+ "%s(type %d index 0x%x poc %d/%d) pts(%d,%lld) dur %d\n",
+ __func__, vf->type, vf->index,
+ get_pic_poc(hevc, vf->index & 0xff),
+ get_pic_poc(hevc, (vf->index >> 8) & 0xff),
+ vf->pts, vf->pts_us64,
+ vf->duration);
+#ifdef AUX_DATA_CRC
+ if ((vf->index & 0xff) <= MAX_REF_PIC_NUM)
+ decoder_do_aux_data_check(vdec, hevc->m_PIC[vf->index & 0xff]->aux_data_buf,
+ hevc->m_PIC[vf->index & 0xff]->aux_data_size);
+#endif
+ if (hevc->is_used_v4l)
+ update_vframe_src_fmt(vf,
+ hevc->m_PIC[vf->index & 0xff]->aux_data_buf,
+ hevc->m_PIC[vf->index & 0xff]->aux_data_size,
+ false, hevc->provider_name, NULL);
+
+ /*if (pic->vf_ref == hevc->vf_pre_count) {*/
+ if (hevc->kpi_first_i_decoded == 0) {
+ hevc->kpi_first_i_decoded = 1;
+ pr_debug("[vdec_kpi][%s] First I frame decoded.\n",
+ __func__);
+ }
+
+ if (without_display_mode == 0) {
+ vf_notify_receiver(hevc->provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
+ }
+ else
+ vh265_vf_put(vh265_vf_get(vdec), vdec);
+ }
+
+ return 0;
+}
+
+static int post_picture_early(struct vdec_s *vdec, int index)
+{
+ struct hevc_state_s *hevc = (struct hevc_state_s *)vdec->private;
+ struct PIC_s *pic = hevc->m_PIC[index];
+
+ if (!hevc->enable_fence)
+ return 0;
+
+ /* create fence for each buffers. */
+ if (vdec_timeline_create_fence(&vdec->sync))
+ return -1;
+
+ pic->fence = vdec->sync.fence;
+ pic->stream_offset = READ_VREG(HEVC_SHIFT_BYTE_COUNT);
+
+ if (hevc->chunk) {
+ pic->pts = hevc->chunk->pts;
+ pic->pts64 = hevc->chunk->pts64;
+ pic->timestamp = hevc->chunk->timestamp;
+ }
+
+ post_video_frame(vdec, pic);
+
+ display_frame_count[hevc->index]++;
+
+ return 0;
+}
+
+static int prepare_display_buf(struct vdec_s *vdec, struct PIC_s *frame)
+{
+ struct hevc_state_s *hevc =
+ (struct hevc_state_s *)vdec->private;
+
+ if (hevc->enable_fence) {
+ post_prepare_process(vdec, frame);
+
+ if (!frame->show_frame)
+ pr_info("do not display.\n");
+
+ hevc->m_PIC[frame->index]->vf_ref = 1;
+
+ /* notify signal to wake up wq of fence. */
+ vdec_timeline_increase(&vdec->sync, 1);
+ return 0;
+ }
+
+ if (post_prepare_process(vdec, frame))
+ return -1;
+
+ if (!frame->show_frame)
+ return 0;
+
+ if (post_video_frame(vdec, frame))
+ return -1;
+
+ display_frame_count[hevc->index]++;
+ return 0;
+}
+
+static int notify_v4l_eos(struct vdec_s *vdec)
+{
+ struct hevc_state_s *hw = (struct hevc_state_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 = get_free_buf_idx(hw))) {
+ if (time_after(jiffies, expires) ||
+ v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx))
+ break;
+ }
+
+ if (index == INVALID_IDX) {
+ if (vdec_v4l_get_buffer(hw->v4l2_ctx, &fb) < 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->m_BUF[index].v4l_ref_buf_addr;
+ vdec_vframe_ready(vdec, vf);
+ kfifo_put(&hw->display_q, (const struct vframe_s *)vf);
+ vf_notify_receiver(vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
+
+ pr_info("[%d] H265 EOS notify.\n", (hw->is_used_v4l)?ctx->id:vdec->id);
+ }
+
+ return 0;
+}
+
+static void process_nal_sei(struct hevc_state_s *hevc,
+ int payload_type, int payload_size)
+{
+ unsigned short data;
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_PRINT_SEI)
+ hevc_print(hevc, 0,
+ "\tsei message: payload_type = 0x%02x, payload_size = 0x%02x\n",
+ payload_type, payload_size);
+
+ if (payload_type == 137) {
+ int i, j;
+ /* MASTERING_DISPLAY_COLOUR_VOLUME */
+ if (payload_size >= 24) {
+ if (get_dbg_flag(hevc) & H265_DEBUG_PRINT_SEI)
+ hevc_print(hevc, 0,
+ "\tsei MASTERING_DISPLAY_COLOUR_VOLUME available\n");
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 2; j++) {
+ data =
+ (READ_HREG(HEVC_SHIFTED_DATA) >> 16);
+ hevc->primaries[i][j] = data;
+ WRITE_HREG(HEVC_SHIFT_COMMAND,
+ (1<<7)|16);
+ if (get_dbg_flag(hevc) &
+ H265_DEBUG_PRINT_SEI)
+ hevc_print(hevc, 0,
+ "\t\tprimaries[%1d][%1d] = %04x\n",
+ i, j, hevc->primaries[i][j]);
+ }
+ }
+ for (i = 0; i < 2; i++) {
+ data = (READ_HREG(HEVC_SHIFTED_DATA) >> 16);
+ hevc->white_point[i] = data;
+ WRITE_HREG(HEVC_SHIFT_COMMAND, (1<<7)|16);
+ if (get_dbg_flag(hevc) & H265_DEBUG_PRINT_SEI)
+ hevc_print(hevc, 0,
+ "\t\twhite_point[%1d] = %04x\n",
+ i, hevc->white_point[i]);
+ }
+ for (i = 0; i < 2; i++) {
+ data = (READ_HREG(HEVC_SHIFTED_DATA) >> 16);
+ hevc->luminance[i] = data << 16;
+ WRITE_HREG(HEVC_SHIFT_COMMAND,
+ (1<<7)|16);
+ data =
+ (READ_HREG(HEVC_SHIFTED_DATA) >> 16);
+ hevc->luminance[i] |= data;
+ WRITE_HREG(HEVC_SHIFT_COMMAND,
+ (1<<7)|16);
+ if (get_dbg_flag(hevc) &
+ H265_DEBUG_PRINT_SEI)
+ hevc_print(hevc, 0,
+ "\t\tluminance[%1d] = %08x\n",
+ i, hevc->luminance[i]);
+ }
+ hevc->sei_present_flag |= SEI_MASTER_DISPLAY_COLOR_MASK;
+ }
+ payload_size -= 24;
+ while (payload_size > 0) {
+ data = (READ_HREG(HEVC_SHIFTED_DATA) >> 24);
+ payload_size--;
+ WRITE_HREG(HEVC_SHIFT_COMMAND, (1<<7)|8);
+ hevc_print(hevc, 0, "\t\tskip byte %02x\n", data);
+ }
+ }
+}
+
+static int hevc_recover(struct hevc_state_s *hevc)
+{
+ int ret = -1;
+ u32 rem;
+ u64 shift_byte_count64;
+ unsigned int hevc_shift_byte_count;
+ unsigned int hevc_stream_start_addr;
+ unsigned int hevc_stream_end_addr;
+ unsigned int hevc_stream_rd_ptr;
+ unsigned int hevc_stream_wr_ptr;
+ unsigned int hevc_stream_control;
+ unsigned int hevc_stream_fifo_ctl;
+ unsigned int hevc_stream_buf_size;
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+
+ mutex_lock(&vh265_mutex);
+#if 0
+ for (i = 0; i < (hevc->debug_ptr_size / 2); i += 4) {
+ int ii;
+
+ for (ii = 0; ii < 4; ii++)
+ hevc_print(hevc, 0,
+ "%04x ", hevc->debug_ptr[i + 3 - ii]);
+ if (((i + ii) & 0xf) == 0)
+ hevc_print(hevc, 0, "\n");
+ }
+#endif
+#define ES_VID_MAN_RD_PTR (1<<0)
+ if (!hevc->init_flag) {
+ hevc_print(hevc, 0, "h265 has stopped, recover return!\n");
+ mutex_unlock(&vh265_mutex);
+ return ret;
+ }
+ amhevc_stop();
+ msleep(20);
+ ret = 0;
+ /* reset */
+ if (vdec_stream_based(vdec)) {
+ STBUF_WRITE(&vdec->vbuf, set_rp,
+ READ_VREG(HEVC_STREAM_RD_PTR));
+
+ if (!vdec->vbuf.no_parser)
+ SET_PARSER_REG_MASK(PARSER_ES_CONTROL,
+ ES_VID_MAN_RD_PTR);
+ }
+
+ hevc_stream_start_addr = READ_VREG(HEVC_STREAM_START_ADDR);
+ hevc_stream_end_addr = READ_VREG(HEVC_STREAM_END_ADDR);
+ hevc_stream_rd_ptr = READ_VREG(HEVC_STREAM_RD_PTR);
+ hevc_stream_wr_ptr = READ_VREG(HEVC_STREAM_WR_PTR);
+ hevc_stream_control = READ_VREG(HEVC_STREAM_CONTROL);
+ hevc_stream_fifo_ctl = READ_VREG(HEVC_STREAM_FIFO_CTL);
+ hevc_stream_buf_size = hevc_stream_end_addr - hevc_stream_start_addr;
+
+ /* HEVC streaming buffer will reset and restart
+ * from current hevc_stream_rd_ptr position
+ */
+ /* calculate HEVC_SHIFT_BYTE_COUNT value with the new position. */
+ hevc_shift_byte_count = READ_VREG(HEVC_SHIFT_BYTE_COUNT);
+ if ((hevc->shift_byte_count_lo & (1 << 31))
+ && ((hevc_shift_byte_count & (1 << 31)) == 0))
+ hevc->shift_byte_count_hi++;
+
+ hevc->shift_byte_count_lo = hevc_shift_byte_count;
+ shift_byte_count64 = ((u64)(hevc->shift_byte_count_hi) << 32) |
+ hevc->shift_byte_count_lo;
+ div_u64_rem(shift_byte_count64, hevc_stream_buf_size, &rem);
+ shift_byte_count64 -= rem;
+ shift_byte_count64 += hevc_stream_rd_ptr - hevc_stream_start_addr;
+
+ if (rem > (hevc_stream_rd_ptr - hevc_stream_start_addr))
+ shift_byte_count64 += hevc_stream_buf_size;
+
+ hevc->shift_byte_count_lo = (u32)shift_byte_count64;
+ hevc->shift_byte_count_hi = (u32)(shift_byte_count64 >> 32);
+
+ WRITE_VREG(DOS_SW_RESET3,
+ /* (1<<2)| */
+ (1 << 3) | (1 << 4) | (1 << 8) |
+ (1 << 11) | (1 << 12) | (1 << 14)
+ | (1 << 15) | (1 << 17) | (1 << 18) | (1 << 19));
+ WRITE_VREG(DOS_SW_RESET3, 0);
+
+ WRITE_VREG(HEVC_STREAM_START_ADDR, hevc_stream_start_addr);
+ WRITE_VREG(HEVC_STREAM_END_ADDR, hevc_stream_end_addr);
+ WRITE_VREG(HEVC_STREAM_RD_PTR, hevc_stream_rd_ptr);
+ WRITE_VREG(HEVC_STREAM_WR_PTR, hevc_stream_wr_ptr);
+ WRITE_VREG(HEVC_STREAM_CONTROL, hevc_stream_control);
+ WRITE_VREG(HEVC_SHIFT_BYTE_COUNT, hevc->shift_byte_count_lo);
+ WRITE_VREG(HEVC_STREAM_FIFO_CTL, hevc_stream_fifo_ctl);
+
+ hevc_config_work_space_hw(hevc);
+ decoder_hw_reset();
+
+ hevc->have_vps = 0;
+ hevc->have_sps = 0;
+ hevc->have_pps = 0;
+
+ hevc->have_valid_start_slice = 0;
+
+ if (get_double_write_mode(hevc) & 0x10)
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1,
+ 0x1 << 31 /*/Enable NV21 reference read mode for MC*/
+ );
+
+ WRITE_VREG(HEVC_WAIT_FLAG, 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);
+
+ CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL, ES_VID_MAN_RD_PTR);
+
+ WRITE_VREG(DEBUG_REG1, 0x0);
+
+ if ((error_handle_policy & 1) == 0) {
+ if ((error_handle_policy & 4) == 0) {
+ /* ucode auto mode, and do not check vps/sps/pps/idr */
+ WRITE_VREG(NAL_SEARCH_CTL,
+ 0xc);
+ } else {
+ WRITE_VREG(NAL_SEARCH_CTL, 0x1);/* manual parser NAL */
+ }
+ } else {
+ WRITE_VREG(NAL_SEARCH_CTL, 0x1);/* manual parser NAL */
+ }
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_NO_EOS_SEARCH_DONE)
+ WRITE_VREG(NAL_SEARCH_CTL, READ_VREG(NAL_SEARCH_CTL) | 0x10000);
+ WRITE_VREG(NAL_SEARCH_CTL,
+ READ_VREG(NAL_SEARCH_CTL)
+ | ((parser_sei_enable & 0x7) << 17));
+/*#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION*/
+ WRITE_VREG(NAL_SEARCH_CTL,
+ READ_VREG(NAL_SEARCH_CTL) |
+ ((parser_dolby_vision_enable & 0x1) << 20));
+/*#endif*/
+ config_decode_mode(hevc);
+ WRITE_VREG(DECODE_STOP_POS, udebug_flag);
+
+ /* if (amhevc_loadmc(vh265_mc) < 0) { */
+ /* amhevc_disable(); */
+ /* return -EBUSY; */
+ /* } */
+#if 0
+ for (i = 0; i < (hevc->debug_ptr_size / 2); i += 4) {
+ int ii;
+
+ for (ii = 0; ii < 4; ii++) {
+ /* hevc->debug_ptr[i+3-ii]=ttt++; */
+ hevc_print(hevc, 0,
+ "%04x ", hevc->debug_ptr[i + 3 - ii]);
+ }
+ if (((i + ii) & 0xf) == 0)
+ hevc_print(hevc, 0, "\n");
+ }
+#endif
+ init_pic_list_hw(hevc);
+
+ hevc_print(hevc, 0, "%s HEVC_SHIFT_BYTE_COUNT=0x%x\n", __func__,
+ READ_VREG(HEVC_SHIFT_BYTE_COUNT));
+
+#ifdef SWAP_HEVC_UCODE
+ if (!tee_enabled() && hevc->is_swap &&
+ get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_GXM) {
+ WRITE_VREG(HEVC_STREAM_SWAP_BUFFER2, hevc->mc_dma_handle);
+ /*pr_info("write swap buffer %x\n", (u32)(hevc->mc_dma_handle));*/
+ }
+#endif
+ amhevc_start();
+
+ /* skip, search next start code */
+ WRITE_VREG(HEVC_WAIT_FLAG, READ_VREG(HEVC_WAIT_FLAG) & (~0x2));
+ hevc->skip_flag = 1;
+#ifdef ERROR_HANDLE_DEBUG
+ if (dbg_nal_skip_count & 0x20000) {
+ dbg_nal_skip_count &= ~0x20000;
+ mutex_unlock(&vh265_mutex);
+ return ret;
+ }
+#endif
+ WRITE_VREG(HEVC_DEC_STATUS_REG, HEVC_ACTION_DONE);
+ /* Interrupt Amrisc to excute */
+ WRITE_VREG(HEVC_MCPU_INTR_REQ, AMRISC_MAIN_REQ);
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (!hevc->m_ins_flag)
+#endif
+ hevc->first_pic_after_recover = 1;
+ mutex_unlock(&vh265_mutex);
+ return ret;
+}
+
+static void dump_aux_buf(struct hevc_state_s *hevc)
+{
+ int i;
+ unsigned short *aux_adr =
+ (unsigned short *)
+ hevc->aux_addr;
+ unsigned int aux_size =
+ (READ_VREG(HEVC_AUX_DATA_SIZE)
+ >> 16) << 4;
+
+ if (hevc->prefix_aux_size > 0) {
+ hevc_print(hevc, 0,
+ "prefix aux: (size %d)\n",
+ aux_size);
+ if (aux_size > hevc->prefix_aux_size) {
+ hevc_print(hevc, 0,
+ "%s:aux_size(%d) is over size\n", __func__, aux_size);
+ return ;
+ }
+ for (i = 0; i <
+ (aux_size >> 1); i++) {
+ hevc_print_cont(hevc, 0,
+ "%04x ",
+ *(aux_adr + i));
+ if (((i + 1) & 0xf)
+ == 0)
+ hevc_print_cont(hevc,
+ 0, "\n");
+ }
+ }
+ if (hevc->suffix_aux_size > 0) {
+ aux_adr = (unsigned short *)
+ (hevc->aux_addr +
+ hevc->prefix_aux_size);
+ aux_size =
+ (READ_VREG(HEVC_AUX_DATA_SIZE) & 0xffff)
+ << 4;
+ hevc_print(hevc, 0,
+ "suffix aux: (size %d)\n",
+ aux_size);
+ if (aux_size > hevc->suffix_aux_size) {
+ hevc_print(hevc, 0,
+ "%s:aux_size(%d) is over size\n", __func__, aux_size);
+ return ;
+ }
+ for (i = 0; i <
+ (aux_size >> 1); i++) {
+ hevc_print_cont(hevc, 0,
+ "%04x ", *(aux_adr + i));
+ if (((i + 1) & 0xf) == 0)
+ hevc_print_cont(hevc, 0, "\n");
+ }
+ }
+}
+
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+static void dolby_get_meta(struct hevc_state_s *hevc)
+{
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+
+ if (get_dbg_flag(hevc) &
+ H265_DEBUG_BUFMGR_MORE)
+ dump_aux_buf(hevc);
+ if (vdec->dolby_meta_with_el || vdec->slave) {
+ set_aux_data(hevc,
+ hevc->cur_pic, 0, 0);
+ } else if (vdec->master) {
+ struct hevc_state_s *hevc_ba =
+ (struct hevc_state_s *)
+ vdec->master->private;
+ /*do not use hevc_ba*/
+ set_aux_data(hevc,
+ hevc_ba->cur_pic,
+ 0, 1);
+ set_aux_data(hevc,
+ hevc->cur_pic, 0, 2);
+ } else if (vdec_frame_based(vdec)) {
+ set_aux_data(hevc,
+ hevc->cur_pic, 1, 0);
+ }
+}
+#endif
+
+static void read_decode_info(struct hevc_state_s *hevc)
+{
+ uint32_t decode_info =
+ READ_HREG(HEVC_DECODE_INFO);
+ hevc->start_decoding_flag |=
+ (decode_info & 0xff);
+ hevc->rps_set_id = (decode_info >> 8) & 0xff;
+}
+
+static int vh265_get_ps_info(struct hevc_state_s *hevc, int width, int height, struct aml_vdec_ps_infos *ps)
+{
+ int dw_mode = v4l_parser_get_double_write_mode(hevc, width, height);
+
+ ps->visible_width = width / get_double_write_ratio(hevc, dw_mode);
+ ps->visible_height = height / get_double_write_ratio(hevc, dw_mode);
+ ps->coded_width = ALIGN(width, 32) / get_double_write_ratio(hevc, dw_mode);
+ ps->coded_height = ALIGN(height, 32) / get_double_write_ratio(hevc, dw_mode);
+ ps->dpb_size = v4l_parser_work_pic_num(hevc);
+ ps->field = hevc->interlace_flag ? V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int v4l_res_change(struct hevc_state_s *hevc, union param_u *rpm_param)
+{
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(hevc->v4l2_ctx);
+ int ret = 0;
+
+ if (ctx->param_sets_from_ucode &&
+ hevc->res_ch_flag == 0) {
+ struct aml_vdec_ps_infos ps;
+ int width = rpm_param->p.pic_width_in_luma_samples;
+ int height = rpm_param->p.pic_height_in_luma_samples;
+ if ((hevc->pic_w != 0 &&
+ hevc->pic_h != 0) &&
+ (hevc->pic_w != width ||
+ hevc->pic_h != height)) {
+ hevc_print(hevc, 0,
+ "v4l_res_change Pic Width/Height Change (%d,%d)=>(%d,%d), interlace %d\n",
+ hevc->pic_w, hevc->pic_h,
+ width,
+ height,
+ hevc->interlace_flag);
+
+ vh265_get_ps_info(hevc, width, height, &ps);
+ vdec_v4l_set_ps_infos(ctx, &ps);
+ vdec_v4l_res_ch_event(ctx);
+ hevc->v4l_params_parsed = false;
+ hevc->res_ch_flag = 1;
+ ctx->v4l_resolution_change = 1;
+ hevc->eos = 1;
+ flush_output(hevc, NULL);
+ //del_timer_sync(&hevc->timer);
+ notify_v4l_eos(hw_to_vdec(hevc));
+
+ ret = 1;
+ }
+ }
+
+ return ret;
+}
+
+static int hevc_skip_nal(struct hevc_state_s *hevc)
+{
+ if ((hevc->pic_h == 96) && (hevc->pic_w == 160) &&
+ (get_double_write_mode(hevc) == 0x10)) {
+ if (get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_TXLX) {
+ if (hevc->skip_nal_count < skip_nal_count)
+ return 1;
+ } else {
+ if (hevc->skip_nal_count < 1)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#ifdef VDEC_FCC_SUPPORT
+static void fcc_discard_mode_process(struct vdec_s *vdec, struct hevc_state_s *hevc)
+{
+ if (vdec->fcc_status == AGAIN_STATUS &&
+ hevc->param.p.slice_type == I_SLICE) {
+ vdec->stream_offset = READ_VREG(HEVC_SHIFT_BYTE_COUNT);
+ hevc_print(hevc, PRINT_FLAG_VDEC_DETAIL,
+ "[%d][FCC]: Notify stream_offset: %u\n",
+ vdec->id, vdec->stream_offset);
+
+ vdec_wakeup_fcc_poll(vdec);
+ amhevc_stop();
+ vdec->fcc_status = WAIT_MSG_STATUS;
+ hevc->dec_result = DEC_RESULT_AGAIN;
+ vdec_schedule_work(&hevc->work);
+ } else if (vdec->fcc_status == DISCARD_STATUS ||
+ hevc->param.p.slice_type != I_SLICE) {
+ hevc_print(hevc, PRINT_FLAG_VDEC_DETAIL,
+ "[%d][FCC]: Discard current gop and to find next gop!\n",
+ vdec->id);
+
+ amhevc_stop();
+ vdec->fcc_status = AGAIN_STATUS;
+ hevc->dec_result = DEC_RESULT_DISCARD_DATA;
+ vdec_schedule_work(&hevc->work);
+ }
+}
+
+static int vh265_fcc_process(struct vdec_s *vdec, struct hevc_state_s *hevc)
+{
+ if (input_stream_based(vdec)) {
+ switch (vdec->fcc_mode) {
+ case FCC_DISCARD_MODE:
+ fcc_discard_mode_process(vdec, hevc);
+ return 1;
+ case FCC_DEC_MODE:
+ hevc_print(hevc, PRINT_FLAG_VDEC_DETAIL,
+ "[%d][FCC]: Current is Dec mode.\n", vdec->id);
+ break;
+ case FCC_BUTT:
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+static void aspect_ratio_set(struct hevc_state_s *hevc)
+{
+ int aspect_ratio_idc = hevc->param.p.aspect_ratio_idc;
+
+ switch (aspect_ratio_idc) {
+ case 1:
+ hevc->frame_ar = 0x3ff;
+ hevc->cur_pic->sar_height = 1;
+ hevc->cur_pic->sar_width = 1;
+ break;
+ case 2:
+ hevc->frame_ar = 0x3ff;
+ hevc->cur_pic->sar_height = 11;
+ hevc->cur_pic->sar_width = 12;
+ break;
+ case 3:
+ hevc->frame_ar = 0x3ff;
+ hevc->cur_pic->sar_height = 11;
+ hevc->cur_pic->sar_width = 10;
+ break;
+ case 4:
+ hevc->frame_ar = 0x3ff;
+ hevc->cur_pic->sar_height = 11;
+ hevc->cur_pic->sar_width = 16;
+ break;
+ case 5:
+ hevc->frame_ar = 0x3ff;
+ hevc->cur_pic->sar_height = 33;
+ hevc->cur_pic->sar_width = 40;
+ break;
+ case 6:
+ hevc->frame_ar = 0x3ff;
+ hevc->cur_pic->sar_height = 11;
+ hevc->cur_pic->sar_width = 24;
+ break;
+ case 7:
+ hevc->frame_ar = 0x3ff;
+ hevc->cur_pic->sar_height = 11;
+ hevc->cur_pic->sar_width = 20;
+ break;
+ case 8:
+ hevc->frame_ar = 0x3ff;
+ hevc->cur_pic->sar_height = 11;
+ hevc->cur_pic->sar_width = 32;
+ break;
+ case 9:
+ hevc->frame_ar = 0x3ff;
+ hevc->cur_pic->sar_height = 33;
+ hevc->cur_pic->sar_width = 80;
+ break;
+ case 10:
+ hevc->frame_ar = 0x3ff;
+ hevc->cur_pic->sar_height = 11;
+ hevc->cur_pic->sar_width = 18;
+ break;
+ case 11:
+ hevc->frame_ar = 0x3ff;
+ hevc->cur_pic->sar_height = 11;
+ hevc->cur_pic->sar_width = 15;
+ break;
+ case 12:
+ hevc->frame_ar = 0x3ff;
+ hevc->cur_pic->sar_height = 33;
+ hevc->cur_pic->sar_width = 64;
+ break;
+ case 13:
+ hevc->frame_ar = 0x3ff;
+ hevc->cur_pic->sar_height = 99;
+ hevc->cur_pic->sar_width = 160;
+ break;
+ case 14:
+ hevc->frame_ar = 0x3ff;
+ hevc->cur_pic->sar_height = 3;
+ hevc->cur_pic->sar_width = 4;
+ break;
+ case 15:
+ hevc->frame_ar = 0x3ff;
+ hevc->cur_pic->sar_height = 2;
+ hevc->cur_pic->sar_width = 3;
+ break;
+ case 16:
+ hevc->frame_ar = 0x3ff;
+ hevc->cur_pic->sar_height = 1;
+ hevc->cur_pic->sar_width = 2;
+ break;
+ default:
+
+ hevc->frame_ar = 0x3ff;
+ hevc->cur_pic->sar_height = 1;
+ hevc->cur_pic->sar_width = 1;
+ break;
+ }
+
+}
+static irqreturn_t vh265_isr_thread_fn(int irq, void *data)
+{
+ struct hevc_state_s *hevc = (struct hevc_state_s *) data;
+ unsigned int dec_status = hevc->dec_status;
+ int i, ret;
+
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+
+ if (hevc->eos)
+ return IRQ_HANDLED;
+ if (
+#ifdef MULTI_INSTANCE_SUPPORT
+ (!hevc->m_ins_flag) &&
+#endif
+ hevc->error_flag == 1) {
+ if ((error_handle_policy & 0x10) == 0) {
+ if (hevc->cur_pic) {
+ int current_lcu_idx =
+ READ_VREG(HEVC_PARSER_LCU_START)
+ & 0xffffff;
+ if (current_lcu_idx <
+ ((hevc->lcu_x_num*hevc->lcu_y_num)-1))
+ hevc->cur_pic->error_mark = 1;
+
+ }
+ }
+ if ((error_handle_policy & 1) == 0) {
+ hevc->error_skip_nal_count = 1;
+ /* manual search nal, skip error_skip_nal_count
+ * of nal and trigger the HEVC_NAL_SEARCH_DONE irq
+ */
+ WRITE_VREG(NAL_SEARCH_CTL,
+ (error_skip_nal_count << 4) | 0x1);
+ } else {
+ hevc->error_skip_nal_count = error_skip_nal_count;
+ WRITE_VREG(NAL_SEARCH_CTL, 0x1);/* manual parser NAL */
+ }
+ if ((get_dbg_flag(hevc) & H265_DEBUG_NO_EOS_SEARCH_DONE)
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ || vdec->master
+ || vdec->slave
+#endif
+ ) {
+ WRITE_VREG(NAL_SEARCH_CTL,
+ READ_VREG(NAL_SEARCH_CTL) | 0x10000);
+ }
+ WRITE_VREG(NAL_SEARCH_CTL,
+ READ_VREG(NAL_SEARCH_CTL)
+ | ((parser_sei_enable & 0x7) << 17));
+/*#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION*/
+ WRITE_VREG(NAL_SEARCH_CTL,
+ READ_VREG(NAL_SEARCH_CTL) |
+ ((parser_dolby_vision_enable & 0x1) << 20));
+/*#endif*/
+ config_decode_mode(hevc);
+ /* search new nal */
+ WRITE_VREG(HEVC_DEC_STATUS_REG, HEVC_ACTION_DONE);
+ /* Interrupt Amrisc to excute */
+ WRITE_VREG(HEVC_MCPU_INTR_REQ, AMRISC_MAIN_REQ);
+
+ /* hevc_print(hevc, 0,
+ *"%s: error handle\n", __func__);
+ */
+ hevc->error_flag = 2;
+ return IRQ_HANDLED;
+ } else if (
+#ifdef MULTI_INSTANCE_SUPPORT
+ (!hevc->m_ins_flag) &&
+#endif
+ hevc->error_flag == 3) {
+ hevc_print(hevc, 0, "error_flag=3, hevc_recover\n");
+ hevc_recover(hevc);
+ hevc->error_flag = 0;
+
+ if ((error_handle_policy & 0x10) == 0) {
+ if (hevc->cur_pic) {
+ int current_lcu_idx =
+ READ_VREG(HEVC_PARSER_LCU_START)
+ & 0xffffff;
+ if (current_lcu_idx <
+ ((hevc->lcu_x_num*hevc->lcu_y_num)-1))
+ hevc->cur_pic->error_mark = 1;
+
+ }
+ }
+ if ((error_handle_policy & 1) == 0) {
+ /* need skip some data when
+ * error_flag of 3 is triggered,
+ */
+ /* to avoid hevc_recover() being called
+ * for many times at the same bitstream position
+ */
+ hevc->error_skip_nal_count = 1;
+ /* manual search nal, skip error_skip_nal_count
+ * of nal and trigger the HEVC_NAL_SEARCH_DONE irq
+ */
+ WRITE_VREG(NAL_SEARCH_CTL,
+ (error_skip_nal_count << 4) | 0x1);
+ }
+
+ if ((error_handle_policy & 0x2) == 0) {
+ hevc->have_vps = 1;
+ hevc->have_sps = 1;
+ hevc->have_pps = 1;
+ }
+ return IRQ_HANDLED;
+ }
+ if (!hevc->m_ins_flag) {
+ i = READ_VREG(HEVC_SHIFT_BYTE_COUNT);
+ if ((hevc->shift_byte_count_lo & (1 << 31))
+ && ((i & (1 << 31)) == 0))
+ hevc->shift_byte_count_hi++;
+ hevc->shift_byte_count_lo = i;
+ }
+#ifdef MULTI_INSTANCE_SUPPORT
+ mutex_lock(&hevc->chunks_mutex);
+ if ((dec_status == HEVC_DECPIC_DATA_DONE ||
+ dec_status == HEVC_FIND_NEXT_PIC_NAL ||
+ dec_status == HEVC_FIND_NEXT_DVEL_NAL)
+ && (hevc->chunk)) {
+ hevc->cur_pic->pts = hevc->chunk->pts;
+ hevc->cur_pic->pts64 = hevc->chunk->pts64;
+ hevc->cur_pic->timestamp = hevc->chunk->timestamp;
+ }
+ mutex_unlock(&hevc->chunks_mutex);
+
+ if (dec_status == HEVC_DECODE_BUFEMPTY ||
+ dec_status == HEVC_DECODE_BUFEMPTY2) {
+ if (hevc->m_ins_flag) {
+ read_decode_info(hevc);
+ if (vdec_frame_based(hw_to_vdec(hevc))) {
+ hevc->empty_flag = 1;
+ /*suffix sei or dv meta*/
+ set_aux_data(hevc, hevc->cur_pic, 1, 0);
+ goto pic_done;
+ } else {
+ if (
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ vdec->master ||
+ vdec->slave ||
+#endif
+ (data_resend_policy & 0x1)) {
+ hevc->dec_result = DEC_RESULT_AGAIN;
+ amhevc_stop();
+ restore_decode_state(hevc);
+ } else
+ hevc->dec_result = DEC_RESULT_GET_DATA;
+ }
+ reset_process_time(hevc);
+ vdec_schedule_work(&hevc->work);
+ }
+ return IRQ_HANDLED;
+ } else if ((dec_status == HEVC_SEARCH_BUFEMPTY) ||
+ (dec_status == HEVC_NAL_DECODE_DONE)
+ ) {
+ if (hevc->m_ins_flag) {
+ read_decode_info(hevc);
+ if (vdec_frame_based(hw_to_vdec(hevc))) {
+ /*hevc->dec_result = DEC_RESULT_GET_DATA;*/
+ hevc->empty_flag = 1;
+ /*suffix sei or dv meta*/
+ set_aux_data(hevc, hevc->cur_pic, 1, 0);
+ goto pic_done;
+ } else {
+ hevc->dec_result = DEC_RESULT_AGAIN;
+ amhevc_stop();
+ restore_decode_state(hevc);
+ }
+
+ reset_process_time(hevc);
+ vdec_schedule_work(&hevc->work);
+ }
+
+ return IRQ_HANDLED;
+ } else if (dec_status == HEVC_DECPIC_DATA_DONE) {
+ if (hevc->m_ins_flag) {
+ struct PIC_s *pic;
+ struct PIC_s *pic_display;
+ int decoded_poc;
+
+ if (vdec->mvfrm)
+ vdec->mvfrm->hw_decode_time =
+ local_clock() - vdec->mvfrm->hw_decode_start;
+#ifdef DETREFILL_ENABLE
+ if (hevc->is_swap &&
+ get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_GXM) {
+ if (hevc->detbuf_adr_virt && hevc->delrefill_check
+ && READ_VREG(HEVC_SAO_DBG_MODE0))
+ hevc->delrefill_check = 2;
+ }
+#endif
+ hevc->empty_flag = 0;
+pic_done:
+ if (input_frame_based(hw_to_vdec(hevc)) &&
+ frmbase_cont_bitlevel != 0 &&
+ (hevc->decode_size > READ_VREG(HEVC_SHIFT_BYTE_COUNT)) &&
+ (hevc->decode_size - (READ_VREG(HEVC_SHIFT_BYTE_COUNT))
+ > frmbase_cont_bitlevel)) {
+ /*handle the case: multi pictures in one packet*/
+ hevc_print(hevc, PRINT_FLAG_VDEC_STATUS,
+ "%s has more data index= %d, size=0x%x shiftcnt=0x%x)\n",
+ __func__,
+ hevc->decode_idx, hevc->decode_size,
+ READ_VREG(HEVC_SHIFT_BYTE_COUNT));
+ WRITE_VREG(HEVC_DEC_STATUS_REG, HEVC_ACTION_DONE);
+ start_process_time(hevc);
+ return IRQ_HANDLED;
+ }
+
+ read_decode_info(hevc);
+ get_picture_qos_info(hevc);
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ hevc->start_parser_type = 0;
+ hevc->switch_dvlayer_flag = 0;
+#endif
+ hevc->decoded_poc = hevc->curr_POC;
+ hevc->decoding_pic = NULL;
+ hevc->dec_result = DEC_RESULT_DONE;
+#ifdef DETREFILL_ENABLE
+ if (hevc->is_swap &&
+ get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_GXM)
+ if (hevc->delrefill_check != 2)
+#endif
+
+ amhevc_stop();
+
+ reset_process_time(hevc);
+
+ if ((!input_stream_based(vdec) &&
+ hevc->vf_pre_count == 0) || hevc->ip_mode) {
+ decoded_poc = hevc->curr_POC;
+ pic = get_pic_by_POC(hevc, decoded_poc);
+ if (pic && (pic->POC != INVALID_POC)) {
+ /*PB skip control */
+ if (pic->error_mark == 0
+ && hevc->PB_skip_mode == 1) {
+ /* start decoding after
+ * first I
+ */
+ hevc->ignore_bufmgr_error |= 0x1;
+ }
+ if (hevc->ignore_bufmgr_error & 1) {
+ if (hevc->PB_skip_count_after_decoding > 0) {
+ hevc->PB_skip_count_after_decoding--;
+ } else {
+ /* start displaying */
+ hevc->ignore_bufmgr_error |= 0x2;
+ }
+ }
+ if (hevc->mmu_enable
+ && ((hevc->double_write_mode & 0x10) == 0)) {
+ if (!hevc->m_ins_flag) {
+ hevc->used_4k_num =
+ READ_VREG(HEVC_SAO_MMU_STATUS) >> 16;
+
+ if ((!is_skip_decoding(hevc, pic)) &&
+ (hevc->used_4k_num >= 0) &&
+ (hevc->cur_pic->scatter_alloc
+ == 1)) {
+ hevc_print(hevc,
+ H265_DEBUG_BUFMGR_MORE,
+ "%s pic index %d scatter_alloc %d page_start %ld\n",
+ "decoder_mmu_box_free_idx_tail",
+ hevc->cur_pic->index,
+ hevc->cur_pic->scatter_alloc,
+ hevc->used_4k_num);
+ decoder_mmu_box_free_idx_tail(
+ hevc->mmu_box,
+ hevc->cur_pic->index,
+ hevc->used_4k_num);
+ hevc->cur_pic->scatter_alloc
+ = 2;
+ }
+ hevc->used_4k_num = -1;
+ }
+ }
+
+ pic->output_mark = 1;
+ pic->recon_mark = 1;
+ if (vdec->mvfrm) {
+ pic->frame_size =
+ vdec->mvfrm->frame_size;
+ pic->hw_decode_time =
+ (u32)vdec->mvfrm->hw_decode_time;
+ }
+ }
+ /*Detects the first frame whether has an over decode error*/
+ if ((!vdec_dual(vdec)) &&
+ hevc->empty_flag == 0) {
+ hevc->over_decode =
+ (READ_VREG(HEVC_SHIFT_STATUS) >> 15) & 0x1;
+ if (hevc->over_decode)
+ hevc_print(hevc, 0,
+ "!!!Over decode %d\n", __LINE__);
+ }
+ check_pic_decoded_error(hevc,
+ READ_VREG(HEVC_PARSER_LCU_START) & 0xffffff);
+ if (hevc->cur_pic != NULL &&
+ (READ_VREG(HEVC_PARSER_LCU_START) & 0xffffff) == 0
+ && (hevc->lcu_x_num * hevc->lcu_y_num != 1))
+ hevc->cur_pic->error_mark = 1;
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+force_output:
+#endif
+ pic_display = output_pic(hevc, 1);
+ if (pic_display) {
+ if ((pic_display->error_mark &&
+ ((hevc->ignore_bufmgr_error &
+ 0x2) == 0))
+ || (get_dbg_flag(hevc) &
+ H265_DEBUG_DISPLAY_CUR_FRAME)
+ || (get_dbg_flag(hevc) &
+ H265_DEBUG_NO_DISPLAY)) {
+ pic_display->output_ready = 0;
+ if (get_dbg_flag(hevc) &
+ H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "[BM] Display: POC %d, ",
+ pic_display->POC);
+ hevc_print_cont(hevc, 0,
+ "decoding index %d ==> ",
+ pic_display->
+ decode_idx);
+ hevc_print_cont(hevc, 0,
+ "Debug or err,recycle it\n");
+ }
+ } else {
+ if ((pic_display->
+ slice_type != 2) && !pic_display->ip_mode) {
+ pic_display->output_ready = 0;
+ } else {
+ prepare_display_buf
+ (hw_to_vdec(hevc),
+ pic_display);
+ hevc->first_pic_flag = 1;
+ }
+ }
+ }
+ }
+
+ vdec_schedule_work(&hevc->work);
+ }
+
+ return IRQ_HANDLED;
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ } else if (dec_status == HEVC_FIND_NEXT_PIC_NAL ||
+ dec_status == HEVC_FIND_NEXT_DVEL_NAL) {
+ if (hevc->m_ins_flag) {
+ unsigned char next_parser_type =
+ READ_HREG(CUR_NAL_UNIT_TYPE) & 0xff;
+ read_decode_info(hevc);
+
+ if (vdec->slave &&
+ dec_status == HEVC_FIND_NEXT_DVEL_NAL) {
+ /*cur is base, found enhance*/
+ struct hevc_state_s *hevc_el =
+ (struct hevc_state_s *)
+ vdec->slave->private;
+ hevc->switch_dvlayer_flag = 1;
+ hevc->no_switch_dvlayer_count = 0;
+ hevc_el->start_parser_type =
+ next_parser_type;
+ hevc_print(hevc, H265_DEBUG_DV,
+ "switch (poc %d) to el\n",
+ hevc->cur_pic ?
+ hevc->cur_pic->POC :
+ INVALID_POC);
+ } else if (vdec->master &&
+ dec_status == HEVC_FIND_NEXT_PIC_NAL) {
+ /*cur is enhance, found base*/
+ struct hevc_state_s *hevc_ba =
+ (struct hevc_state_s *)
+ vdec->master->private;
+ hevc->switch_dvlayer_flag = 1;
+ hevc->no_switch_dvlayer_count = 0;
+ hevc_ba->start_parser_type =
+ next_parser_type;
+ hevc_print(hevc, H265_DEBUG_DV,
+ "switch (poc %d) to bl\n",
+ hevc->cur_pic ?
+ hevc->cur_pic->POC :
+ INVALID_POC);
+ } else {
+ hevc->switch_dvlayer_flag = 0;
+ hevc->start_parser_type =
+ next_parser_type;
+ hevc->no_switch_dvlayer_count++;
+ hevc_print(hevc, H265_DEBUG_DV,
+ "%s: no_switch_dvlayer_count = %d\n",
+ vdec->master ? "el" : "bl",
+ hevc->no_switch_dvlayer_count);
+ if (vdec->slave &&
+ dolby_el_flush_th != 0 &&
+ hevc->no_switch_dvlayer_count >
+ dolby_el_flush_th) {
+ struct hevc_state_s *hevc_el =
+ (struct hevc_state_s *)
+ vdec->slave->private;
+ struct PIC_s *el_pic;
+ check_pic_decoded_error(hevc_el,
+ hevc_el->pic_decoded_lcu_idx);
+ el_pic = get_pic_by_POC(hevc_el,
+ hevc_el->curr_POC);
+ hevc_el->curr_POC = INVALID_POC;
+ hevc_el->m_pocRandomAccess = MAX_INT;
+ flush_output(hevc_el, el_pic);
+ hevc_el->decoded_poc = INVALID_POC; /*
+ already call flush_output*/
+ hevc_el->decoding_pic = NULL;
+ hevc->no_switch_dvlayer_count = 0;
+ if (get_dbg_flag(hevc) & H265_DEBUG_DV)
+ hevc_print(hevc, 0,
+ "no el anymore, flush_output el\n");
+ }
+ }
+ hevc->decoded_poc = hevc->curr_POC;
+ hevc->decoding_pic = NULL;
+ hevc->dec_result = DEC_RESULT_DONE;
+ amhevc_stop();
+ reset_process_time(hevc);
+ if (aux_data_is_avaible(hevc))
+ dolby_get_meta(hevc);
+ if(hevc->cur_pic && hevc->cur_pic->slice_type == 2 &&
+ hevc->vf_pre_count == 0) {
+ hevc_print(hevc, 0,
+ "first slice_type %x no_switch_dvlayer_count %x\n",
+ hevc->cur_pic->slice_type,
+ hevc->no_switch_dvlayer_count);
+ goto force_output;
+ }
+ vdec_schedule_work(&hevc->work);
+ }
+
+ return IRQ_HANDLED;
+#endif
+ }
+
+#endif
+
+ if (dec_status == HEVC_SEI_DAT) {
+ if (!hevc->m_ins_flag) {
+ int payload_type =
+ READ_HREG(CUR_NAL_UNIT_TYPE) & 0xffff;
+ int payload_size =
+ (READ_HREG(CUR_NAL_UNIT_TYPE) >> 16) & 0xffff;
+ process_nal_sei(hevc,
+ payload_type, payload_size);
+ }
+ WRITE_VREG(HEVC_DEC_STATUS_REG, HEVC_SEI_DAT_DONE);
+ } else if (dec_status == HEVC_NAL_SEARCH_DONE) {
+ int naltype = READ_HREG(CUR_NAL_UNIT_TYPE);
+ int parse_type = HEVC_DISCARD_NAL;
+
+ hevc->error_watchdog_count = 0;
+ hevc->error_skip_nal_wt_cnt = 0;
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (hevc->m_ins_flag)
+ reset_process_time(hevc);
+#endif
+ if (slice_parse_begin > 0 &&
+ get_dbg_flag(hevc) & H265_DEBUG_DISCARD_NAL) {
+ hevc_print(hevc, 0,
+ "nal type %d, discard %d\n", naltype,
+ slice_parse_begin);
+ if (naltype <= NAL_UNIT_CODED_SLICE_CRA)
+ slice_parse_begin--;
+ }
+ if (naltype == NAL_UNIT_EOS) {
+ struct PIC_s *pic;
+ bool eos_in_head = false;
+
+ hevc_print(hevc, 0, "get NAL_UNIT_EOS, flush output\n");
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ if ((vdec_dual(vdec)) && aux_data_is_avaible(hevc)) {
+ if (hevc->decoding_pic)
+ dolby_get_meta(hevc);
+ }
+#endif
+ /*Detects frame whether has an over decode error*/
+ if ((!vdec_dual(vdec)) &&
+ hevc->empty_flag == 0 && input_stream_based(vdec)) {
+ hevc->over_decode =
+ (READ_VREG(HEVC_SHIFT_STATUS) >> 15) & 0x1;
+ if (hevc->over_decode)
+ hevc_print(hevc, 0,
+ "!!!Over decode %d\n", __LINE__);
+ }
+ check_pic_decoded_error(hevc,
+ hevc->pic_decoded_lcu_idx);
+ pic = get_pic_by_POC(hevc, hevc->curr_POC);
+ hevc->curr_POC = INVALID_POC;
+ /* add to fix RAP_B_Bossen_1 */
+ hevc->m_pocRandomAccess = MAX_INT;
+ flush_output(hevc, pic);
+ clear_poc_flag(hevc);
+ if (input_frame_based(vdec)) {
+ u32 shiftbyte = READ_VREG(HEVC_SHIFT_BYTE_COUNT);
+ if (shiftbyte < 0x8 && (hevc->decode_size - shiftbyte) > 0x100) {
+ hevc_print(hevc, 0," shiftbytes 0x%x decode_size 0x%x\n", shiftbyte, hevc->decode_size);
+ eos_in_head = true;
+ }
+ }
+ WRITE_VREG(HEVC_DEC_STATUS_REG, HEVC_DISCARD_NAL);
+ /* Interrupt Amrisc to excute */
+ WRITE_VREG(HEVC_MCPU_INTR_REQ, AMRISC_MAIN_REQ);
+
+ /* eos is in the head of the chunk and followed by sps/pps/IDR
+ * so need to go on decoding
+ */
+ if (eos_in_head)
+ return IRQ_HANDLED;
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (hevc->m_ins_flag) {
+ hevc->decoded_poc = INVALID_POC; /*
+ already call flush_output*/
+ hevc->decoding_pic = NULL;
+ hevc->dec_result = DEC_RESULT_DONE;
+ amhevc_stop();
+
+ vdec_schedule_work(&hevc->work);
+ }
+#endif
+ return IRQ_HANDLED;
+ }
+
+ if (
+#ifdef MULTI_INSTANCE_SUPPORT
+ (!hevc->m_ins_flag) &&
+#endif
+ hevc->error_skip_nal_count > 0) {
+ hevc_print(hevc, 0,
+ "nal type %d, discard %d\n", naltype,
+ hevc->error_skip_nal_count);
+ hevc->error_skip_nal_count--;
+ if (hevc->error_skip_nal_count == 0) {
+ hevc_recover(hevc);
+ hevc->error_flag = 0;
+ if ((error_handle_policy & 0x2) == 0) {
+ hevc->have_vps = 1;
+ hevc->have_sps = 1;
+ hevc->have_pps = 1;
+ }
+ return IRQ_HANDLED;
+ }
+ } else if (naltype == NAL_UNIT_VPS) {
+ parse_type = HEVC_NAL_UNIT_VPS;
+ hevc->have_vps = 1;
+#ifdef ERROR_HANDLE_DEBUG
+ if (dbg_nal_skip_flag & 1)
+ parse_type = HEVC_DISCARD_NAL;
+#endif
+ } else if (hevc->have_vps) {
+ if (naltype == NAL_UNIT_SPS) {
+ parse_type = HEVC_NAL_UNIT_SPS;
+ hevc->have_sps = 1;
+#ifdef ERROR_HANDLE_DEBUG
+ if (dbg_nal_skip_flag & 2)
+ parse_type = HEVC_DISCARD_NAL;
+#endif
+ } else if (naltype == NAL_UNIT_PPS) {
+ parse_type = HEVC_NAL_UNIT_PPS;
+ hevc->have_pps = 1;
+#ifdef ERROR_HANDLE_DEBUG
+ if (dbg_nal_skip_flag & 4)
+ parse_type = HEVC_DISCARD_NAL;
+#endif
+ } else if (hevc->have_sps && hevc->have_pps) {
+ int seg = HEVC_NAL_UNIT_CODED_SLICE_SEGMENT;
+
+ if ((naltype == NAL_UNIT_CODED_SLICE_IDR) ||
+ (naltype ==
+ NAL_UNIT_CODED_SLICE_IDR_N_LP)
+ || (naltype ==
+ NAL_UNIT_CODED_SLICE_CRA)
+ || (naltype ==
+ NAL_UNIT_CODED_SLICE_BLA)
+ || (naltype ==
+ NAL_UNIT_CODED_SLICE_BLANT)
+ || (naltype ==
+ NAL_UNIT_CODED_SLICE_BLA_N_LP)
+ ) {
+ if (slice_parse_begin > 0) {
+ hevc_print(hevc, 0,
+ "discard %d, for debugging\n",
+ slice_parse_begin);
+ slice_parse_begin--;
+ } else {
+ parse_type = seg;
+ }
+ hevc->have_valid_start_slice = 1;
+ } else if (naltype <=
+ NAL_UNIT_CODED_SLICE_CRA
+ && (hevc->have_valid_start_slice
+ || (hevc->PB_skip_mode != 3))) {
+ if (slice_parse_begin > 0) {
+ hevc_print(hevc, 0,
+ "discard %d, dd\n",
+ slice_parse_begin);
+ slice_parse_begin--;
+ } else
+ parse_type = seg;
+
+ }
+ }
+ }
+ if (hevc->have_vps && hevc->have_sps && hevc->have_pps
+ && hevc->have_valid_start_slice &&
+ hevc->error_flag == 0) {
+ if ((get_dbg_flag(hevc) &
+ H265_DEBUG_MAN_SEARCH_NAL) == 0
+ /* && (!hevc->m_ins_flag)*/) {
+ /* auot parser NAL; do not check
+ *vps/sps/pps/idr
+ */
+ WRITE_VREG(NAL_SEARCH_CTL, 0x2);
+ }
+
+ if ((get_dbg_flag(hevc) &
+ H265_DEBUG_NO_EOS_SEARCH_DONE)
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ || vdec->master
+ || vdec->slave
+#endif
+ ) {
+ WRITE_VREG(NAL_SEARCH_CTL,
+ READ_VREG(NAL_SEARCH_CTL) |
+ 0x10000);
+ }
+ WRITE_VREG(NAL_SEARCH_CTL,
+ READ_VREG(NAL_SEARCH_CTL)
+ | ((parser_sei_enable & 0x7) << 17));
+/*#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION*/
+ WRITE_VREG(NAL_SEARCH_CTL,
+ READ_VREG(NAL_SEARCH_CTL) |
+ ((parser_dolby_vision_enable & 0x1) << 20));
+/*#endif*/
+ config_decode_mode(hevc);
+ }
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "naltype = %d parse_type %d\n %d %d %d %d\n",
+ naltype, parse_type, hevc->have_vps,
+ hevc->have_sps, hevc->have_pps,
+ hevc->have_valid_start_slice);
+ }
+
+ WRITE_VREG(HEVC_DEC_STATUS_REG, parse_type);
+ /* Interrupt Amrisc to excute */
+ WRITE_VREG(HEVC_MCPU_INTR_REQ, AMRISC_MAIN_REQ);
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (hevc->m_ins_flag)
+ start_process_time(hevc);
+#endif
+ } else if (dec_status == HEVC_SLICE_SEGMENT_DONE) {
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (hevc->m_ins_flag) {
+ reset_process_time(hevc);
+ read_decode_info(hevc);
+
+ }
+#endif
+ if (hevc->start_decoding_time > 0) {
+ u32 process_time = 1000*
+ (jiffies - hevc->start_decoding_time)/HZ;
+ if (process_time > max_decoding_time)
+ max_decoding_time = process_time;
+ }
+
+ hevc->error_watchdog_count = 0;
+ if (hevc->pic_list_init_flag == 2) {
+ hevc->pic_list_init_flag = 3;
+ hevc_print(hevc, 0, "set pic_list_init_flag to 3\n");
+ if (hevc->kpi_first_i_comming == 0) {
+ hevc->kpi_first_i_comming = 1;
+ pr_debug("[vdec_kpi][%s] First I frame coming.\n",
+ __func__);
+ }
+ } else if (hevc->wait_buf == 0) {
+ u32 vui_time_scale;
+ u32 vui_num_units_in_tick;
+ unsigned char reconfig_flag = 0;
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_SEND_PARAM_WITH_REG)
+ get_rpm_param(&hevc->param);
+ else {
+
+ for (i = 0; i < (RPM_END - RPM_BEGIN); i += 4) {
+ int ii;
+
+ for (ii = 0; ii < 4; ii++) {
+ hevc->param.l.data[i + ii] =
+ hevc->rpm_ptr[i + 3
+ - ii];
+ }
+ }
+#ifdef SEND_LMEM_WITH_RPM
+ check_head_error(hevc);
+#endif
+ }
+#ifdef VDEC_FCC_SUPPORT
+ if (vh265_fcc_process(vdec, hevc) > 0)
+ return IRQ_HANDLED;
+#endif
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR_MORE) {
+ hevc_print(hevc, 0,
+ "rpm_param: (%d)\n", hevc->slice_idx);
+ hevc->slice_idx++;
+ for (i = 0; i < (RPM_END - RPM_BEGIN); i++) {
+ hevc_print_cont(hevc, 0,
+ "%04x ", hevc->param.l.data[i]);
+ if (((i + 1) & 0xf) == 0)
+ hevc_print_cont(hevc, 0, "\n");
+ }
+
+ hevc_print(hevc, 0,
+ "vui_timing_info: %x, %x, %x, %x\n",
+ hevc->param.p.vui_num_units_in_tick_hi,
+ hevc->param.p.vui_num_units_in_tick_lo,
+ hevc->param.p.vui_time_scale_hi,
+ hevc->param.p.vui_time_scale_lo);
+ }
+
+ if (hevc->is_used_v4l) {
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(hevc->v4l2_ctx);
+ if (!v4l_res_change(hevc, &hevc->param)) {
+ if (ctx->param_sets_from_ucode && !hevc->v4l_params_parsed) {
+ struct aml_vdec_ps_infos ps;
+ int width = hevc->param.p.pic_width_in_luma_samples;
+ int height = hevc->param.p.pic_height_in_luma_samples;
+
+ pr_debug("set ucode parse\n");
+ vh265_get_ps_info(hevc, width, height, &ps);
+ /*notice the v4l2 codec.*/
+ vdec_v4l_set_ps_infos(ctx, &ps);
+ hevc->v4l_params_parsed = true;
+ hevc->dec_result = DEC_RESULT_AGAIN;
+ amhevc_stop();
+ restore_decode_state(hevc);
+ reset_process_time(hevc);
+ vdec_schedule_work(&hevc->work);
+ return IRQ_HANDLED;
+ }
+ }else {
+ pr_debug("resolution change\n");
+ hevc->dec_result = DEC_RESULT_AGAIN;
+ amhevc_stop();
+ restore_decode_state(hevc);
+ reset_process_time(hevc);
+ vdec_schedule_work(&hevc->work);
+ return IRQ_HANDLED;
+
+ }
+ }
+
+ if (
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ vdec->master == NULL &&
+ vdec->slave == NULL &&
+#endif
+ aux_data_is_avaible(hevc)
+ ) {
+
+ if (get_dbg_flag(hevc) &
+ H265_DEBUG_BUFMGR_MORE)
+ dump_aux_buf(hevc);
+ }
+
+ vui_time_scale =
+ (u32)(hevc->param.p.vui_time_scale_hi << 16) |
+ hevc->param.p.vui_time_scale_lo;
+ vui_num_units_in_tick =
+ (u32)(hevc->param.
+ p.vui_num_units_in_tick_hi << 16) |
+ hevc->param.
+ p.vui_num_units_in_tick_lo;
+ if (hevc->bit_depth_luma !=
+ ((hevc->param.p.bit_depth & 0xf) + 8)) {
+ reconfig_flag = 1;
+ hevc_print(hevc, 0, "Bit depth luma = %d\n",
+ (hevc->param.p.bit_depth & 0xf) + 8);
+ }
+ if (hevc->bit_depth_chroma !=
+ (((hevc->param.p.bit_depth >> 4) & 0xf) + 8)) {
+ reconfig_flag = 1;
+ hevc_print(hevc, 0, "Bit depth chroma = %d\n",
+ ((hevc->param.p.bit_depth >> 4) &
+ 0xf) + 8);
+ }
+ hevc->bit_depth_luma =
+ (hevc->param.p.bit_depth & 0xf) + 8;
+ hevc->bit_depth_chroma =
+ ((hevc->param.p.bit_depth >> 4) & 0xf) + 8;
+ bit_depth_luma = hevc->bit_depth_luma;
+ bit_depth_chroma = hevc->bit_depth_chroma;
+#ifdef SUPPORT_10BIT
+ if (hevc->bit_depth_luma == 8 &&
+ hevc->bit_depth_chroma == 8 &&
+ enable_mem_saving)
+ hevc->mem_saving_mode = 1;
+ else
+ hevc->mem_saving_mode = 0;
+#endif
+ if (reconfig_flag &&
+ (get_double_write_mode(hevc) & 0x10) == 0)
+ init_decode_head_hw(hevc);
+
+ if ((vui_time_scale != 0)
+ && (vui_num_units_in_tick != 0)) {
+ hevc->frame_dur =
+ div_u64(96000ULL *
+ vui_num_units_in_tick,
+ vui_time_scale);
+ if (hevc->get_frame_dur != true)
+ vdec_schedule_work(
+ &hevc->notify_work);
+
+ hevc->get_frame_dur = true;
+ //hevc->gvs->frame_dur = hevc->frame_dur;
+ }
+
+ if (hevc->video_signal_type !=
+ ((hevc->param.p.video_signal_type << 16)
+ | hevc->param.p.color_description)) {
+ u32 v = hevc->param.p.video_signal_type;
+ u32 c = hevc->param.p.color_description;
+#if 0
+ if (v & 0x2000) {
+ hevc_print(hevc, 0,
+ "video_signal_type present:\n");
+ hevc_print(hevc, 0, " %s %s\n",
+ video_format_names[(v >> 10) & 7],
+ ((v >> 9) & 1) ?
+ "full_range" : "limited");
+ if (v & 0x100) {
+ hevc_print(hevc, 0,
+ " color_description present:\n");
+ hevc_print(hevc, 0,
+ " color_primarie = %s\n",
+ color_primaries_names
+ [v & 0xff]);
+ hevc_print(hevc, 0,
+ " transfer_characteristic = %s\n",
+ transfer_characteristics_names
+ [(c >> 8) & 0xff]);
+ hevc_print(hevc, 0,
+ " matrix_coefficient = %s\n",
+ matrix_coeffs_names[c & 0xff]);
+ }
+ }
+#endif
+ hevc->video_signal_type = (v << 16) | c;
+ video_signal_type = hevc->video_signal_type;
+ }
+
+ if (use_cma &&
+ (hevc->param.p.slice_segment_address == 0)
+ && (hevc->pic_list_init_flag == 0)) {
+ int log = hevc->param.p.log2_min_coding_block_size_minus3;
+ int log_s = hevc->param.p.log2_diff_max_min_coding_block_size;
+
+ hevc->pic_w = hevc->param.p.pic_width_in_luma_samples;
+ hevc->pic_h = hevc->param.p.pic_height_in_luma_samples;
+ hevc->lcu_size = 1 << (log + 3 + log_s);
+ hevc->lcu_size_log2 = log2i(hevc->lcu_size);
+ if (performance_profile &&( (!is_oversize(hevc->pic_w, hevc->pic_h)) && IS_8K_SIZE(hevc->pic_w,hevc->pic_h)))
+ hevc->performance_profile = 1;
+ else
+ hevc->performance_profile = 0;
+ hevc_print(hevc, 0, "hevc->performance_profile %d\n", hevc->performance_profile);
+ if (hevc->pic_w == 0 || hevc->pic_h == 0
+ || hevc->lcu_size == 0
+ || is_oversize(hevc->pic_w, hevc->pic_h)
+ || hevc_skip_nal(hevc)) {
+ /* skip search next start code */
+ WRITE_VREG(HEVC_WAIT_FLAG, READ_VREG(HEVC_WAIT_FLAG)
+ & (~0x2));
+ if ((hevc->pic_h == 96) && (hevc->pic_w == 160))
+ hevc->skip_nal_count++;
+ hevc->skip_flag = 1;
+ WRITE_VREG(HEVC_DEC_STATUS_REG, HEVC_ACTION_DONE);
+ /* Interrupt Amrisc to excute */
+ WRITE_VREG(HEVC_MCPU_INTR_REQ, AMRISC_MAIN_REQ);
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (hevc->m_ins_flag)
+ start_process_time(hevc);
+#endif
+ } else {
+ hevc->sps_num_reorder_pics_0 =
+ hevc->param.p.sps_num_reorder_pics_0;
+ hevc->ip_mode = (!hevc->sps_num_reorder_pics_0 &&
+ !(vdec->slave || vdec->master) &&
+ !disable_ip_mode &&
+ hevc->low_latency_flag) ? true : false;
+ hevc->pic_list_init_flag = 1;
+ if ((!IS_4K_SIZE(hevc->pic_w, hevc->pic_h)) &&
+ ((hevc->param.p.profile_etc & 0xc) == 0x4)
+ && (interlace_enable != 0)) {
+ hevc->double_write_mode = 1;
+ hevc->interlace_flag = 1;
+ hevc->frame_ar = (hevc->pic_h * 0x100 / hevc->pic_w) * 2;
+ hevc_print(hevc, 0,
+ "interlace (%d, %d), profile_etc %x, ar 0x%x, dw %d\n",
+ hevc->pic_w, hevc->pic_h, hevc->param.p.profile_etc, hevc->frame_ar,
+ get_double_write_mode(hevc));
+ /* When dw changed from 0x10 to 1, the mmu_box is NULL */
+ if (!hevc->mmu_box && init_mmu_box(hevc) != 0) {
+ hevc->dec_result = DEC_RESULT_FORCE_EXIT;
+ hevc->fatal_error |=
+ DECODER_FATAL_ERROR_NO_MEM;
+ vdec_schedule_work(&hevc->work);
+ hevc_print(hevc,
+ 0, "can not alloc mmu box, force exit\n");
+ return IRQ_HANDLED;
+ }
+ }
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (hevc->m_ins_flag) {
+ vdec_schedule_work(&hevc->work);
+ } else
+#endif
+ up(&h265_sema);
+ hevc_print(hevc, 0, "set pic_list_init_flag 1\n");
+ }
+ return IRQ_HANDLED;
+ }
+
+}
+ ret =
+ hevc_slice_segment_header_process(hevc,
+ &hevc->param, decode_pic_begin);
+ if (ret < 0) {
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (hevc->m_ins_flag) {
+ hevc->wait_buf = 0;
+ hevc->dec_result = DEC_RESULT_AGAIN;
+ amhevc_stop();
+ restore_decode_state(hevc);
+ reset_process_time(hevc);
+ vdec_schedule_work(&hevc->work);
+ return IRQ_HANDLED;
+ }
+#else
+ ;
+#endif
+ } else if (ret == 0) {
+ if ((hevc->new_pic) && (hevc->cur_pic)) {
+ hevc->cur_pic->stream_offset =
+ READ_VREG(HEVC_SHIFT_BYTE_COUNT);
+ hevc_print(hevc, H265_DEBUG_OUT_PTS,
+ "read stream_offset = 0x%x\n",
+ hevc->cur_pic->stream_offset);
+
+ hevc->cur_pic->aspect_ratio_idc =
+ hevc->param.p.aspect_ratio_idc;
+ hevc->cur_pic->sar_width =
+ hevc->param.p.sar_width;
+ hevc->cur_pic->sar_height =
+ hevc->param.p.sar_height;
+ }
+
+ aspect_ratio_set(hevc);
+ WRITE_VREG(HEVC_DEC_STATUS_REG,
+ HEVC_CODED_SLICE_SEGMENT_DAT);
+ /* Interrupt Amrisc to excute */
+ WRITE_VREG(HEVC_MCPU_INTR_REQ, AMRISC_MAIN_REQ);
+
+ hevc->start_decoding_time = jiffies;
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (hevc->m_ins_flag)
+ start_process_time(hevc);
+#endif
+#if 1
+ /*to do..., copy aux data to hevc->cur_pic*/
+#endif
+#ifdef MULTI_INSTANCE_SUPPORT
+ } else if (hevc->m_ins_flag) {
+ hevc_print(hevc, PRINT_FLAG_VDEC_STATUS,
+ "%s, bufmgr ret %d skip, DEC_RESULT_DONE\n",
+ __func__, ret);
+ hevc->decoded_poc = INVALID_POC;
+ hevc->decoding_pic = NULL;
+ hevc->dec_result = DEC_RESULT_DONE;
+ amhevc_stop();
+ reset_process_time(hevc);
+ vdec_schedule_work(&hevc->work);
+#endif
+ } else {
+ /* skip, search next start code */
+ hevc->gvs->drop_frame_count++;
+ if (hevc->cur_pic->slice_type == I_SLICE) {
+ hevc->gvs->i_lost_frames++;
+ } else if (hevc->cur_pic->slice_type == P_SLICE) {
+ hevc->gvs->i_lost_frames++;
+ } else if (hevc->cur_pic->slice_type == B_SLICE) {
+ hevc->gvs->i_lost_frames++;
+ }
+ WRITE_VREG(HEVC_WAIT_FLAG, READ_VREG(HEVC_WAIT_FLAG) & (~0x2));
+ hevc->skip_flag = 1;
+ WRITE_VREG(HEVC_DEC_STATUS_REG, HEVC_ACTION_DONE);
+ /* Interrupt Amrisc to excute */
+ WRITE_VREG(HEVC_MCPU_INTR_REQ, AMRISC_MAIN_REQ);
+ }
+
+ } else if (dec_status == HEVC_DECODE_OVER_SIZE) {
+ hevc_print(hevc, 0 , "hevc decode oversize !!\n");
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (!hevc->m_ins_flag)
+ debug |= (H265_DEBUG_DIS_LOC_ERROR_PROC |
+ H265_DEBUG_DIS_SYS_ERROR_PROC);
+#endif
+ hevc->fatal_error |= DECODER_FATAL_ERROR_SIZE_OVERFLOW;
+ }
+ return IRQ_HANDLED;
+}
+
+static void wait_hevc_search_done(struct hevc_state_s *hevc)
+{
+ int count = 0;
+ WRITE_VREG(HEVC_SHIFT_STATUS, 0);
+ while (READ_VREG(HEVC_STREAM_CONTROL) & 0x2) {
+ msleep(20);
+ count++;
+ if (count > 100) {
+ hevc_print(hevc, 0, "%s timeout\n", __func__);
+ break;
+ }
+ }
+}
+static irqreturn_t vh265_isr(int irq, void *data)
+{
+ int i, temp;
+ unsigned int dec_status;
+ struct hevc_state_s *hevc = (struct hevc_state_s *)data;
+ u32 debug_tag;
+ dec_status = READ_VREG(HEVC_DEC_STATUS_REG);
+
+ if (hevc->init_flag == 0)
+ return IRQ_HANDLED;
+ hevc->dec_status = dec_status;
+ if (is_log_enable(hevc))
+ add_log(hevc,
+ "isr: status = 0x%x dec info 0x%x lcu 0x%x shiftbyte 0x%x shiftstatus 0x%x",
+ dec_status, READ_HREG(HEVC_DECODE_INFO),
+ READ_VREG(HEVC_MPRED_CURR_LCU),
+ READ_VREG(HEVC_SHIFT_BYTE_COUNT),
+ READ_VREG(HEVC_SHIFT_STATUS));
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ hevc_print(hevc, 0,
+ "265 isr dec status = 0x%x dec info 0x%x shiftbyte 0x%x shiftstatus 0x%x\n",
+ dec_status, READ_HREG(HEVC_DECODE_INFO),
+ READ_VREG(HEVC_SHIFT_BYTE_COUNT),
+ READ_VREG(HEVC_SHIFT_STATUS));
+
+ debug_tag = READ_HREG(DEBUG_REG1);
+ if (debug_tag & 0x10000) {
+ hevc_print(hevc, 0,
+ "LMEM<tag %x>:\n", READ_HREG(DEBUG_REG1));
+
+ if (hevc->mmu_enable)
+ temp = 0x500;
+ else
+ temp = 0x400;
+ for (i = 0; i < temp; i += 4) {
+ int ii;
+ if ((i & 0xf) == 0)
+ hevc_print_cont(hevc, 0, "%03x: ", i);
+ for (ii = 0; ii < 4; ii++) {
+ hevc_print_cont(hevc, 0, "%04x ",
+ hevc->lmem_ptr[i + 3 - ii]);
+ }
+ if (((i + ii) & 0xf) == 0)
+ hevc_print_cont(hevc, 0, "\n");
+ }
+
+ if (((udebug_pause_pos & 0xffff)
+ == (debug_tag & 0xffff)) &&
+ (udebug_pause_decode_idx == 0 ||
+ udebug_pause_decode_idx == hevc->decode_idx) &&
+ (udebug_pause_val == 0 ||
+ udebug_pause_val == READ_HREG(DEBUG_REG2))) {
+ udebug_pause_pos &= 0xffff;
+ hevc->ucode_pause_pos = udebug_pause_pos;
+ }
+ else if (debug_tag & 0x20000)
+ hevc->ucode_pause_pos = 0xffffffff;
+ if (hevc->ucode_pause_pos)
+ reset_process_time(hevc);
+ else
+ WRITE_HREG(DEBUG_REG1, 0);
+ } else if (debug_tag != 0) {
+ hevc_print(hevc, 0,
+ "dbg%x: %x l/w/r %x %x %x\n", READ_HREG(DEBUG_REG1),
+ READ_HREG(DEBUG_REG2),
+ READ_VREG(HEVC_STREAM_LEVEL),
+ READ_VREG(HEVC_STREAM_WR_PTR),
+ READ_VREG(HEVC_STREAM_RD_PTR));
+ if (((udebug_pause_pos & 0xffff)
+ == (debug_tag & 0xffff)) &&
+ (udebug_pause_decode_idx == 0 ||
+ udebug_pause_decode_idx == hevc->decode_idx) &&
+ (udebug_pause_val == 0 ||
+ udebug_pause_val == READ_HREG(DEBUG_REG2))) {
+ udebug_pause_pos &= 0xffff;
+ hevc->ucode_pause_pos = udebug_pause_pos;
+ }
+ if (hevc->ucode_pause_pos)
+ reset_process_time(hevc);
+ else
+ WRITE_HREG(DEBUG_REG1, 0);
+ return IRQ_HANDLED;
+ }
+
+
+ if (hevc->pic_list_init_flag == 1)
+ return IRQ_HANDLED;
+
+ if (!hevc->m_ins_flag) {
+ if (dec_status == HEVC_OVER_DECODE) {
+ hevc->over_decode = 1;
+ hevc_print(hevc, 0,
+ "isr: over decode\n"),
+ WRITE_VREG(HEVC_DEC_STATUS_REG, 0);
+ return IRQ_HANDLED;
+ }
+ }
+
+ return IRQ_WAKE_THREAD;
+
+}
+
+static void vh265_set_clk(struct work_struct *work)
+{
+ struct hevc_state_s *hevc = container_of(work,
+ struct hevc_state_s, set_clk_work);
+
+ int fps = 96000 / hevc->frame_dur;
+
+ if (hevc_source_changed(VFORMAT_HEVC,
+ hevc->frame_width, hevc->frame_height, fps) > 0)
+ hevc->saved_resolution = hevc->frame_width *
+ hevc->frame_height * fps;
+}
+
+static void vh265_check_timer_func(unsigned long arg)
+{
+ struct hevc_state_s *hevc = (struct hevc_state_s *)arg;
+ struct timer_list *timer = &hevc->timer;
+ unsigned char empty_flag;
+ unsigned int buf_level;
+
+ enum receviver_start_e state = RECEIVER_INACTIVE;
+
+ if (hevc->init_flag == 0) {
+ if (hevc->stat & STAT_TIMER_ARM) {
+ mod_timer(&hevc->timer, jiffies + PUT_INTERVAL);
+ }
+ return;
+ }
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (hevc->m_ins_flag &&
+ (get_dbg_flag(hevc) &
+ H265_DEBUG_WAIT_DECODE_DONE_WHEN_STOP) == 0 &&
+ hw_to_vdec(hevc)->next_status ==
+ VDEC_STATUS_DISCONNECTED &&
+ !hevc->is_used_v4l) {
+ hevc->dec_result = DEC_RESULT_FORCE_EXIT;
+ vdec_schedule_work(&hevc->work);
+ hevc_print(hevc,
+ 0, "vdec requested to be disconnected\n");
+ return;
+ }
+
+ if (hevc->m_ins_flag) {
+ if (((get_dbg_flag(hevc) &
+ H265_DEBUG_DIS_LOC_ERROR_PROC) == 0) &&
+ (decode_timeout_val > 0) &&
+ (hevc->start_process_time > 0) &&
+ ((1000 * (jiffies - hevc->start_process_time) / HZ)
+ > decode_timeout_val)
+ ) {
+ u32 dec_status = READ_VREG(HEVC_DEC_STATUS_REG);
+ int current_lcu_idx =
+ READ_VREG(HEVC_PARSER_LCU_START)&0xffffff;
+ if (dec_status == HEVC_CODED_SLICE_SEGMENT_DAT) {
+ if (hevc->last_lcu_idx == current_lcu_idx) {
+ if (hevc->decode_timeout_count > 0)
+ hevc->decode_timeout_count--;
+ if (hevc->decode_timeout_count == 0)
+ timeout_process(hevc);
+ } else
+ restart_process_time(hevc);
+ hevc->last_lcu_idx = current_lcu_idx;
+ } else {
+ hevc->pic_decoded_lcu_idx = current_lcu_idx;
+ timeout_process(hevc);
+ }
+ }
+ } else {
+#endif
+ if (hevc->m_ins_flag == 0 &&
+ vf_get_receiver(hevc->provider_name)) {
+ state =
+ vf_notify_receiver(hevc->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 (hevc->m_ins_flag == 0 &&
+ (empty_flag == 0)
+ && (hevc->pic_list_init_flag == 0
+ || hevc->pic_list_init_flag
+ == 3)) {
+ /* decoder has input */
+ if ((get_dbg_flag(hevc) &
+ H265_DEBUG_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(&hevc->display_q) &&
+ buf_level > 0x200)
+ ) {
+ if (hevc->error_flag == 0) {
+ hevc->error_watchdog_count++;
+ if (hevc->error_watchdog_count ==
+ error_handle_threshold) {
+ hevc_print(hevc, 0,
+ "H265 dec err local reset.\n");
+ hevc->error_flag = 1;
+ hevc->error_watchdog_count = 0;
+ hevc->error_skip_nal_wt_cnt = 0;
+ hevc->
+ error_system_watchdog_count++;
+ WRITE_VREG
+ (HEVC_ASSIST_MBOX0_IRQ_REG,
+ 0x1);
+ }
+ } else if (hevc->error_flag == 2) {
+ int th =
+ error_handle_nal_skip_threshold;
+ hevc->error_skip_nal_wt_cnt++;
+ if (hevc->error_skip_nal_wt_cnt
+ == th) {
+ hevc->error_flag = 3;
+ hevc->error_watchdog_count = 0;
+ hevc->
+ error_skip_nal_wt_cnt = 0;
+ WRITE_VREG
+ (HEVC_ASSIST_MBOX0_IRQ_REG,
+ 0x1);
+ }
+ }
+ }
+ }
+
+ if ((get_dbg_flag(hevc)
+ & H265_DEBUG_DIS_SYS_ERROR_PROC) == 0)
+ /* receiver has no buffer to recycle */
+ if ((state == RECEIVER_INACTIVE) &&
+ (kfifo_is_empty(&hevc->display_q))
+ ) { /* no buffer to recycle */
+ if ((get_dbg_flag(hevc) &
+ H265_DEBUG_DIS_LOC_ERROR_PROC) !=
+ 0)
+ hevc->error_system_watchdog_count++;
+ if (hevc->error_system_watchdog_count ==
+ error_handle_system_threshold) {
+ /* and it lasts for a while */
+ hevc_print(hevc, 0,
+ "H265 dec fatal error watchdog.\n");
+ hevc->
+ error_system_watchdog_count = 0;
+ hevc->fatal_error |= DECODER_FATAL_ERROR_UNKNOWN;
+ }
+ }
+ } else {
+ hevc->error_watchdog_count = 0;
+ hevc->error_system_watchdog_count = 0;
+ }
+#ifdef MULTI_INSTANCE_SUPPORT
+ }
+#endif
+ if ((hevc->ucode_pause_pos != 0) &&
+ (hevc->ucode_pause_pos != 0xffffffff) &&
+ udebug_pause_pos != hevc->ucode_pause_pos) {
+ hevc->ucode_pause_pos = 0;
+ WRITE_HREG(DEBUG_REG1, 0);
+ }
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_DUMP_PIC_LIST) {
+ dump_pic_list(hevc);
+ debug &= ~H265_DEBUG_DUMP_PIC_LIST;
+ }
+ if (get_dbg_flag(hevc) & H265_DEBUG_TRIG_SLICE_SEGMENT_PROC) {
+ WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG, 0x1);
+ debug &= ~H265_DEBUG_TRIG_SLICE_SEGMENT_PROC;
+ }
+#ifdef TEST_NO_BUF
+ if (hevc->wait_buf)
+ WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG, 0x1);
+#endif
+ if (get_dbg_flag(hevc) & H265_DEBUG_HW_RESET) {
+ hevc->error_skip_nal_count = error_skip_nal_count;
+ WRITE_VREG(HEVC_DEC_STATUS_REG, HEVC_ACTION_DONE);
+
+ debug &= ~H265_DEBUG_HW_RESET;
+ }
+
+#ifdef ERROR_HANDLE_DEBUG
+ if ((dbg_nal_skip_count > 0) && ((dbg_nal_skip_count & 0x10000) != 0)) {
+ hevc->error_skip_nal_count = dbg_nal_skip_count & 0xffff;
+ dbg_nal_skip_count &= ~0x10000;
+ WRITE_VREG(HEVC_DEC_STATUS_REG, HEVC_ACTION_DONE);
+ }
+#endif
+
+ if (radr != 0) {
+#ifdef SUPPORT_LONG_TERM_RPS
+ if ((radr >> 24) != 0) {
+ int count = radr >> 24;
+ int adr = radr & 0xffffff;
+ int i;
+ for (i = 0; i < count; i++)
+ pr_info("READ_VREG(%x)=%x\n", adr+i, READ_VREG(adr+i));
+ } else
+#endif
+ 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 (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(hevc) == 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;
+ }
+ hevc_print(hevc, 0,
+ "current displayed buffer address %x\r\n",
+ disp_laddr);
+ }
+ dbg_cmd = 0;
+ }
+ /*don't changed at start.*/
+ if (hevc->m_ins_flag == 0 &&
+ hevc->get_frame_dur && hevc->show_frame_num > 60 &&
+ hevc->frame_dur > 0 && hevc->saved_resolution !=
+ hevc->frame_width * hevc->frame_height *
+ (96000 / hevc->frame_dur))
+ vdec_schedule_work(&hevc->set_clk_work);
+
+ mod_timer(timer, jiffies + PUT_INTERVAL);
+}
+
+static int h265_task_handle(void *data)
+{
+ int ret = 0;
+ struct hevc_state_s *hevc = (struct hevc_state_s *)data;
+
+ set_user_nice(current, -10);
+ while (1) {
+ if (use_cma == 0) {
+ hevc_print(hevc, 0,
+ "ERROR: use_cma can not be changed dynamically\n");
+ }
+ ret = down_interruptible(&h265_sema);
+ if ((hevc->init_flag != 0) && (hevc->pic_list_init_flag == 1)) {
+ init_pic_list(hevc);
+ init_pic_list_hw(hevc);
+ init_buf_spec(hevc);
+ hevc->pic_list_init_flag = 2;
+ hevc_print(hevc, 0, "set pic_list_init_flag to 2\n");
+
+ WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG, 0x1);
+
+ }
+
+ if (hevc->uninit_list) {
+ /*USE_BUF_BLOCK*/
+ uninit_pic_list(hevc);
+ hevc_print(hevc, 0, "uninit list\n");
+ hevc->uninit_list = 0;
+#ifdef USE_UNINIT_SEMA
+ if (use_cma) {
+ up(&hevc->h265_uninit_done_sema);
+ while (!kthread_should_stop())
+ msleep(1);
+ break;
+ }
+#endif
+ }
+ }
+
+ return 0;
+}
+
+void vh265_free_cmabuf(void)
+{
+ struct hevc_state_s *hevc = gHevc;
+
+ mutex_lock(&vh265_mutex);
+
+ if (hevc->init_flag) {
+ mutex_unlock(&vh265_mutex);
+ return;
+ }
+
+ mutex_unlock(&vh265_mutex);
+}
+
+#ifdef MULTI_INSTANCE_SUPPORT
+int vh265_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus)
+#else
+int vh265_dec_status(struct vdec_info *vstatus)
+#endif
+{
+#ifdef MULTI_INSTANCE_SUPPORT
+ struct hevc_state_s *hevc =
+ (struct hevc_state_s *)vdec->private;
+#else
+ struct hevc_state_s *hevc = gHevc;
+#endif
+ if (!hevc)
+ return -1;
+
+ vstatus->frame_width = hevc->pic_w;
+ /* for hevc interlace for disp height x2 */
+ vstatus->frame_height =
+ (hevc->pic_h << hevc->interlace_flag);
+ if (hevc->frame_dur != 0)
+ vstatus->frame_rate = ((96000 * 10 / hevc->frame_dur) % 10) < 5 ?
+ 96000 / hevc->frame_dur : (96000 / hevc->frame_dur +1);
+ else
+ vstatus->frame_rate = -1;
+
+ vstatus->status = hevc->stat | hevc->fatal_error;
+ vstatus->frame_dur = hevc->frame_dur;
+ if (hevc->gvs) {
+ vstatus->error_count = hevc->gvs->error_frame_count;
+ vstatus->bit_rate = hevc->gvs->bit_rate;
+ vstatus->frame_data = hevc->gvs->frame_data;
+ vstatus->total_data = hevc->gvs->total_data;
+ vstatus->frame_count = hevc->gvs->frame_count;
+ vstatus->error_frame_count = hevc->gvs->error_frame_count;
+ vstatus->drop_frame_count = hevc->gvs->drop_frame_count;
+ vstatus->i_decoded_frames = hevc->gvs->i_decoded_frames;
+ vstatus->i_lost_frames = hevc->gvs->i_lost_frames;
+ vstatus->i_concealed_frames = hevc->gvs->i_concealed_frames;
+ vstatus->p_decoded_frames = hevc->gvs->p_decoded_frames;
+ vstatus->p_lost_frames = hevc->gvs->p_lost_frames;
+ vstatus->p_concealed_frames = hevc->gvs->p_concealed_frames;
+ vstatus->b_decoded_frames = hevc->gvs->b_decoded_frames;
+ vstatus->b_lost_frames = hevc->gvs->b_lost_frames;
+ vstatus->b_concealed_frames = hevc->gvs->b_concealed_frames;
+ vstatus->samp_cnt = hevc->gvs->samp_cnt;
+ vstatus->offset = hevc->gvs->offset;
+ }
+
+ snprintf(vstatus->vdec_name, sizeof(vstatus->vdec_name),
+ "%s", DRIVER_NAME);
+ vstatus->ratio_control = hevc->ratio_control;
+ return 0;
+}
+
+int vh265_set_isreset(struct vdec_s *vdec, int isreset)
+{
+ is_reset = isreset;
+ return 0;
+}
+
+static int vh265_vdec_info_init(struct hevc_state_s *hevc)
+{
+ hevc->gvs = kzalloc(sizeof(struct vdec_info), GFP_KERNEL);
+ //pr_err("[%s line %d] hevc->gvs=0x%p operation\n",__func__, __LINE__, hevc->gvs);
+ if (NULL == hevc->gvs) {
+ pr_info("the struct of vdec status malloc failed.\n");
+ return -ENOMEM;
+ }
+ vdec_set_vframe_comm(hw_to_vdec(hevc), DRIVER_NAME);
+ return 0;
+}
+
+#if 0
+static void H265_DECODE_INIT(void)
+{
+ /* enable hevc clocks */
+ WRITE_VREG(DOS_GCLK_EN3, 0xffffffff);
+ /* *************************************************************** */
+ /* Power ON HEVC */
+ /* *************************************************************** */
+ /* Powerup HEVC */
+ WRITE_VREG(P_AO_RTI_GEN_PWR_SLEEP0,
+ READ_VREG(P_AO_RTI_GEN_PWR_SLEEP0) & (~(0x3 << 6)));
+ WRITE_VREG(DOS_MEM_PD_HEVC, 0x0);
+ WRITE_VREG(DOS_SW_RESET3, READ_VREG(DOS_SW_RESET3) | (0x3ffff << 2));
+ WRITE_VREG(DOS_SW_RESET3, READ_VREG(DOS_SW_RESET3) & (~(0x3ffff << 2)));
+ /* remove isolations */
+ WRITE_VREG(AO_RTI_GEN_PWR_ISO0,
+ READ_VREG(AO_RTI_GEN_PWR_ISO0) & (~(0x3 << 10)));
+
+}
+#endif
+
+int vh265_set_trickmode(struct vdec_s *vdec, unsigned long trickmode)
+{
+ struct hevc_state_s *hevc = (struct hevc_state_s *)vdec->private;
+ hevc_print(hevc, 0, "[%s %d] trickmode:%lu\n", __func__, __LINE__, trickmode);
+
+ if (trickmode == TRICKMODE_I) {
+ trickmode_i = 1;
+ i_only_flag = 0x1;
+ } else if (trickmode == TRICKMODE_NONE) {
+ trickmode_i = 0;
+ i_only_flag = 0x0;
+ } else if (trickmode == 0x02) {
+ trickmode_i = 0;
+ i_only_flag = 0x02;
+ } else if (trickmode == 0x03) {
+ trickmode_i = 1;
+ i_only_flag = 0x03;
+ } else if (trickmode == 0x07) {
+ trickmode_i = 1;
+ i_only_flag = 0x07;
+ }
+ //hevc_print(hevc, 0, "i_only_flag: %d trickmode_i:%d\n", i_only_flag, trickmode_i);
+
+ return 0;
+}
+
+static void config_decode_mode(struct hevc_state_s *hevc)
+{
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+#endif
+ unsigned decode_mode;
+#ifdef HEVC_8K_LFTOFFSET_FIX
+ if (hevc->performance_profile)
+ WRITE_VREG(NAL_SEARCH_CTL,
+ READ_VREG(NAL_SEARCH_CTL) | (1 << 21));
+#endif
+ if (!hevc->m_ins_flag)
+ decode_mode = DECODE_MODE_SINGLE;
+ else if (vdec_frame_based(hw_to_vdec(hevc)))
+ decode_mode =
+ DECODE_MODE_MULTI_FRAMEBASE;
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ else if (vdec->slave) {
+ if (force_bypass_dvenl & 0x80000000)
+ hevc->bypass_dvenl = force_bypass_dvenl & 0x1;
+ else
+ hevc->bypass_dvenl = hevc->bypass_dvenl_enable;
+ if (dolby_meta_with_el && hevc->bypass_dvenl) {
+ hevc->bypass_dvenl = 0;
+ hevc_print(hevc, 0,
+ "NOT support bypass_dvenl when meta_with_el\n");
+ }
+ if (hevc->bypass_dvenl)
+ decode_mode =
+ (hevc->start_parser_type << 8)
+ | DECODE_MODE_MULTI_STREAMBASE;
+ else
+ decode_mode =
+ (hevc->start_parser_type << 8)
+ | DECODE_MODE_MULTI_DVBAL;
+ } else if (vdec->master)
+ decode_mode =
+ (hevc->start_parser_type << 8)
+ | DECODE_MODE_MULTI_DVENL;
+#endif
+ else
+ decode_mode =
+ DECODE_MODE_MULTI_STREAMBASE;
+
+ if (hevc->m_ins_flag)
+ decode_mode |=
+ (hevc->start_decoding_flag << 16);
+ /* set MBX0 interrupt flag */
+ decode_mode |= (0x80 << 24);
+ WRITE_VREG(HEVC_DECODE_MODE, decode_mode);
+ WRITE_VREG(HEVC_DECODE_MODE2,
+ hevc->rps_set_id);
+}
+
+static void vh265_prot_init(struct hevc_state_s *hevc)
+{
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+#endif
+ /* H265_DECODE_INIT(); */
+
+ hevc_config_work_space_hw(hevc);
+
+ hevc_init_decoder_hw(hevc, 0, 0xffffffff);
+
+ WRITE_VREG(HEVC_WAIT_FLAG, 1);
+
+ /* WRITE_VREG(P_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 | (dump_nal << 8));
+
+ if ((get_dbg_flag(hevc) &
+ (H265_DEBUG_MAN_SKIP_NAL |
+ H265_DEBUG_MAN_SEARCH_NAL))
+ /*||hevc->m_ins_flag*/
+ ) {
+ WRITE_VREG(NAL_SEARCH_CTL, 0x1); /* manual parser NAL */
+ } else {
+ /* check vps/sps/pps/i-slice in ucode */
+ unsigned ctl_val = 0x8;
+
+ if (hevc->PB_skip_mode == 0)
+ ctl_val = 0x4; /* check vps/sps/pps only in ucode */
+ else if (hevc->PB_skip_mode == 3)
+ ctl_val = 0x0; /* check vps/sps/pps/idr in ucode */
+ /*if (((error_handle_policy & 0x200) == 0) &&
+ input_stream_based(vdec))
+ ctl_val = 0x1;*/
+ WRITE_VREG(NAL_SEARCH_CTL, ctl_val);
+ }
+ if ((get_dbg_flag(hevc) & H265_DEBUG_NO_EOS_SEARCH_DONE)
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ || vdec->master
+ || vdec->slave
+#endif
+ )
+ WRITE_VREG(NAL_SEARCH_CTL, READ_VREG(NAL_SEARCH_CTL) | 0x10000);
+
+ WRITE_VREG(NAL_SEARCH_CTL,
+ READ_VREG(NAL_SEARCH_CTL)
+ | ((parser_sei_enable & 0x7) << 17));
+/*#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION*/
+ WRITE_VREG(NAL_SEARCH_CTL,
+ READ_VREG(NAL_SEARCH_CTL) |
+ ((parser_dolby_vision_enable & 0x1) << 20));
+/*#endif*/
+ WRITE_VREG(DECODE_STOP_POS, udebug_flag);
+
+ config_decode_mode(hevc);
+ config_aux_buf(hevc);
+#ifdef SWAP_HEVC_UCODE
+ if (!tee_enabled() && hevc->is_swap &&
+ get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_GXM) {
+ WRITE_VREG(HEVC_STREAM_SWAP_BUFFER2, hevc->mc_dma_handle);
+ /*pr_info("write swap buffer %x\n", (u32)(hevc->mc_dma_handle));*/
+ }
+#endif
+#ifdef DETREFILL_ENABLE
+ if (hevc->is_swap &&
+ get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_GXM) {
+ WRITE_VREG(HEVC_SAO_DBG_MODE0, 0);
+ WRITE_VREG(HEVC_SAO_DBG_MODE1, 0);
+ }
+#endif
+}
+
+static int vh265_local_init(struct hevc_state_s *hevc)
+{
+ int i;
+ int ret = -1;
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+
+#ifdef DEBUG_PTS
+ hevc->pts_missed = 0;
+ hevc->pts_hit = 0;
+#endif
+ hevc->saved_resolution = 0;
+ hevc->get_frame_dur = false;
+ hevc->frame_width = hevc->vh265_amstream_dec_info.width;
+ hevc->frame_height = hevc->vh265_amstream_dec_info.height;
+ hevc->dec_again_cnt = 0;
+
+ if (is_oversize(hevc->frame_width, hevc->frame_height)) {
+ pr_info("over size : %u x %u.\n",
+ hevc->frame_width, hevc->frame_height);
+ hevc->fatal_error |= DECODER_FATAL_ERROR_SIZE_OVERFLOW;
+ return ret;
+ }
+
+ if (hevc->max_pic_w && hevc->max_pic_h) {
+ hevc->is_4k = !(hevc->max_pic_w && hevc->max_pic_h) ||
+ ((hevc->max_pic_w * hevc->max_pic_h) >
+ 1920 * 1088) ? true : false;
+ } else {
+ hevc->is_4k = !(hevc->frame_width && hevc->frame_height) ||
+ ((hevc->frame_width * hevc->frame_height) >
+ 1920 * 1088) ? true : false;
+ }
+
+ hevc->frame_dur =
+ (hevc->vh265_amstream_dec_info.rate ==
+ 0) ? 3600 : hevc->vh265_amstream_dec_info.rate;
+ //hevc->gvs->frame_dur = hevc->frame_dur;
+ if (hevc->frame_width && hevc->frame_height)
+ hevc->frame_ar = hevc->frame_height * 0x100 / hevc->frame_width;
+
+ if (i_only_flag)
+ hevc->i_only = i_only_flag & 0xff;
+ else if ((unsigned long) hevc->vh265_amstream_dec_info.param
+ & 0x08)
+ hevc->i_only = 0x7;
+ else
+ hevc->i_only = 0x0;
+ hevc->error_watchdog_count = 0;
+ hevc->sei_present_flag = 0;
+ if (vdec->sys_info)
+ pts_unstable = ((unsigned long)vdec->sys_info->param
+ & 0x40) >> 6;
+ hevc_print(hevc, 0,
+ "h265:pts_unstable=%d\n", pts_unstable);
+/*
+ *TODO:FOR VERSION
+ */
+ hevc_print(hevc, 0,
+ "h265: ver (%d,%d) decinfo: %dx%d rate=%d\n", h265_version,
+ 0, hevc->frame_width, hevc->frame_height, hevc->frame_dur);
+
+ if (hevc->frame_dur == 0)
+ hevc->frame_dur = 96000 / 24;
+
+ INIT_KFIFO(hevc->display_q);
+ INIT_KFIFO(hevc->newframe_q);
+ INIT_KFIFO(hevc->pending_q);
+
+ for (i = 0; i < VF_POOL_SIZE; i++) {
+ const struct vframe_s *vf = &hevc->vfpool[i];
+
+ hevc->vfpool[i].index = -1;
+ kfifo_put(&hevc->newframe_q, vf);
+ }
+
+
+ ret = hevc_local_init(hevc);
+
+ return ret;
+}
+#ifdef MULTI_INSTANCE_SUPPORT
+static s32 vh265_init(struct vdec_s *vdec)
+{
+ struct hevc_state_s *hevc = (struct hevc_state_s *)vdec->private;
+#else
+static s32 vh265_init(struct hevc_state_s *hevc)
+{
+
+#endif
+ int ret, size = -1;
+ int fw_size = 0x1000 * 16;
+ struct firmware_s *fw = NULL;
+
+ init_timer(&hevc->timer);
+
+ hevc->stat |= STAT_TIMER_INIT;
+
+ if (hevc->m_ins_flag) {
+#ifdef USE_UNINIT_SEMA
+ sema_init(&hevc->h265_uninit_done_sema, 0);
+#endif
+ INIT_WORK(&hevc->work, vh265_work);
+ INIT_WORK(&hevc->timeout_work, vh265_timeout_work);
+ }
+
+ if (vh265_local_init(hevc) < 0)
+ return -EBUSY;
+
+ mutex_init(&hevc->chunks_mutex);
+ INIT_WORK(&hevc->notify_work, vh265_notify_work);
+ INIT_WORK(&hevc->set_clk_work, vh265_set_clk);
+
+ fw = vmalloc(sizeof(struct firmware_s) + fw_size);
+ if (IS_ERR_OR_NULL(fw))
+ return -ENOMEM;
+
+ if (hevc->mmu_enable)
+ if (get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_GXM)
+ size = get_firmware_data(VIDEO_DEC_HEVC_MMU, fw->data);
+ else {
+ if (!hevc->is_4k) {
+ /* if an older version of the fw was loaded, */
+ /* needs try to load noswap fw because the */
+ /* old fw package dose not contain the swap fw.*/
+ size = get_firmware_data(
+ VIDEO_DEC_HEVC_MMU_SWAP, fw->data);
+ if (size < 0)
+ size = get_firmware_data(
+ VIDEO_DEC_HEVC_MMU, fw->data);
+ else if (size)
+ hevc->is_swap = true;
+ } else
+ size = get_firmware_data(VIDEO_DEC_HEVC_MMU,
+ fw->data);
+ }
+ else
+ size = get_firmware_data(VIDEO_DEC_HEVC, fw->data);
+
+ if (size < 0) {
+ pr_err("get firmware fail.\n");
+ vfree(fw);
+ return -1;
+ }
+
+ fw->len = size;
+
+#ifdef SWAP_HEVC_UCODE
+ if (!tee_enabled() && hevc->is_swap &&
+ get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_GXM) {
+ if (hevc->mmu_enable) {
+ hevc->swap_size = (4 * (4 * SZ_1K)); /*max 4 swap code, each 0x400*/
+ hevc->mc_cpu_addr =
+ dma_alloc_coherent(amports_get_dma_device(),
+ hevc->swap_size,
+ &hevc->mc_dma_handle, GFP_KERNEL);
+ if (!hevc->mc_cpu_addr) {
+ amhevc_disable();
+ pr_info("vh265 mmu swap ucode loaded fail.\n");
+ return -ENOMEM;
+ }
+
+ memcpy((u8 *) hevc->mc_cpu_addr, fw->data + SWAP_HEVC_OFFSET,
+ hevc->swap_size);
+
+ hevc_print(hevc, 0,
+ "vh265 mmu ucode swap loaded %llx\n",
+ hevc->mc_dma_handle);
+ }
+ }
+#endif
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (hevc->m_ins_flag) {
+ hevc->timer.data = (ulong) hevc;
+ hevc->timer.function = vh265_check_timer_func;
+ hevc->timer.expires = jiffies + PUT_INTERVAL;
+
+ hevc->fw = fw;
+ hevc->init_flag = 1;
+
+ return 0;
+ }
+#endif
+ amhevc_enable();
+
+ if (hevc->mmu_enable)
+ if (get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_GXM)
+ ret = amhevc_loadmc_ex(VFORMAT_HEVC, "h265_mmu", fw->data);
+ else {
+ if (!hevc->is_4k) {
+ /* if an older version of the fw was loaded, */
+ /* needs try to load noswap fw because the */
+ /* old fw package dose not contain the swap fw. */
+ ret = amhevc_loadmc_ex(VFORMAT_HEVC,
+ "hevc_mmu_swap", fw->data);
+ if (ret < 0)
+ ret = amhevc_loadmc_ex(VFORMAT_HEVC,
+ "h265_mmu", fw->data);
+ else
+ hevc->is_swap = true;
+ } else
+ ret = amhevc_loadmc_ex(VFORMAT_HEVC,
+ "h265_mmu", fw->data);
+ }
+ else
+ ret = amhevc_loadmc_ex(VFORMAT_HEVC, NULL, fw->data);
+
+ if (ret < 0) {
+ amhevc_disable();
+ vfree(fw);
+ pr_err("H265: the %s fw loading failed, err: %x\n",
+ tee_enabled() ? "TEE" : "local", ret);
+ return -EBUSY;
+ }
+
+ vfree(fw);
+
+ hevc->stat |= STAT_MC_LOAD;
+
+#ifdef DETREFILL_ENABLE
+ if (hevc->is_swap &&
+ get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_GXM)
+ init_detrefill_buf(hevc);
+#endif
+ /* enable AMRISC side protocol */
+ vh265_prot_init(hevc);
+
+ if (vdec_request_threaded_irq(VDEC_IRQ_0, vh265_isr,
+ vh265_isr_thread_fn,
+ IRQF_ONESHOT,/*run thread on this irq disabled*/
+ "vh265-irq", (void *)hevc)) {
+ hevc_print(hevc, 0, "vh265 irq register error.\n");
+ amhevc_disable();
+ return -ENOENT;
+ }
+
+ hevc->stat |= STAT_ISR_REG;
+ hevc->provider_name = PROVIDER_NAME;
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ vf_provider_init(&vh265_vf_prov, hevc->provider_name,
+ &vh265_vf_provider, vdec);
+ vf_reg_provider(&vh265_vf_prov);
+ vf_notify_receiver(hevc->provider_name, VFRAME_EVENT_PROVIDER_START,
+ NULL);
+ if (hevc->frame_dur != 0) {
+ if (!is_reset) {
+ vf_notify_receiver(hevc->provider_name,
+ VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)
+ ((unsigned long)hevc->frame_dur));
+ fr_hint_status = VDEC_HINTED;
+ }
+ } else
+ fr_hint_status = VDEC_NEED_HINT;
+#else
+ vf_provider_init(&vh265_vf_prov, PROVIDER_NAME, &vh265_vf_provider,
+ hevc);
+ vf_reg_provider(&vh265_vf_prov);
+ vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_START, NULL);
+ if (hevc->frame_dur != 0) {
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)
+ ((unsigned long)hevc->frame_dur));
+ fr_hint_status = VDEC_HINTED;
+ } else
+ fr_hint_status = VDEC_NEED_HINT;
+#endif
+ hevc->stat |= STAT_VF_HOOK;
+
+ hevc->timer.data = (ulong) hevc;
+ hevc->timer.function = vh265_check_timer_func;
+ hevc->timer.expires = jiffies + PUT_INTERVAL;
+
+ add_timer(&hevc->timer);
+
+ hevc->stat |= STAT_TIMER_ARM;
+
+ if (use_cma) {
+#ifdef USE_UNINIT_SEMA
+ sema_init(&hevc->h265_uninit_done_sema, 0);
+#endif
+ if (h265_task == NULL) {
+ sema_init(&h265_sema, 1);
+ h265_task =
+ kthread_run(h265_task_handle, hevc,
+ "kthread_h265");
+ }
+ }
+ /* hevc->stat |= STAT_KTHREAD; */
+#if 0
+ if (get_dbg_flag(hevc) & H265_DEBUG_FORCE_CLK) {
+ hevc_print(hevc, 0, "%s force clk\n", __func__);
+ WRITE_VREG(HEVC_IQIT_CLK_RST_CTRL,
+ READ_VREG(HEVC_IQIT_CLK_RST_CTRL) |
+ ((1 << 2) | (1 << 1)));
+ WRITE_VREG(HEVC_DBLK_CFG0,
+ READ_VREG(HEVC_DBLK_CFG0) | ((1 << 2) |
+ (1 << 1) | 0x3fff0000));/* 2,29:16 */
+ WRITE_VREG(HEVC_SAO_CTRL1, READ_VREG(HEVC_SAO_CTRL1) |
+ (1 << 2)); /* 2 */
+ WRITE_VREG(HEVC_MPRED_CTRL1, READ_VREG(HEVC_MPRED_CTRL1) |
+ (1 << 24)); /* 24 */
+ WRITE_VREG(HEVC_STREAM_CONTROL,
+ READ_VREG(HEVC_STREAM_CONTROL) |
+ (1 << 15)); /* 15 */
+ WRITE_VREG(HEVC_CABAC_CONTROL, READ_VREG(HEVC_CABAC_CONTROL) |
+ (1 << 13)); /* 13 */
+ WRITE_VREG(HEVC_PARSER_CORE_CONTROL,
+ READ_VREG(HEVC_PARSER_CORE_CONTROL) |
+ (1 << 15)); /* 15 */
+ WRITE_VREG(HEVC_PARSER_INT_CONTROL,
+ READ_VREG(HEVC_PARSER_INT_CONTROL) |
+ (1 << 15)); /* 15 */
+ WRITE_VREG(HEVC_PARSER_IF_CONTROL,
+ READ_VREG(HEVC_PARSER_IF_CONTROL) | ((1 << 6) |
+ (1 << 3) | (1 << 1))); /* 6, 3, 1 */
+ WRITE_VREG(HEVCD_IPP_DYNCLKGATE_CONFIG, 0xffffffff); /* 31:0 */
+ WRITE_VREG(HEVCD_MCRCC_CTL1, READ_VREG(HEVCD_MCRCC_CTL1) |
+ (1 << 3)); /* 3 */
+ }
+#endif
+#ifdef SWAP_HEVC_UCODE
+ if (!tee_enabled() && hevc->is_swap &&
+ get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_GXM) {
+ WRITE_VREG(HEVC_STREAM_SWAP_BUFFER2, hevc->mc_dma_handle);
+ /*pr_info("write swap buffer %x\n", (u32)(hevc->mc_dma_handle));*/
+ }
+#endif
+
+#ifndef MULTI_INSTANCE_SUPPORT
+ set_vdec_func(&vh265_dec_status);
+#endif
+ amhevc_start();
+
+ WRITE_VREG(HEVC_SHIFT_BYTE_COUNT, 0);
+
+ hevc->stat |= STAT_VDEC_RUN;
+ hevc->init_flag = 1;
+ error_handle_threshold = 30;
+ /* pr_info("%d, vh265_init, RP=0x%x\n",
+ * __LINE__, READ_VREG(HEVC_STREAM_RD_PTR));
+ */
+
+ return 0;
+}
+
+static int check_dirty_data(struct vdec_s *vdec)
+{
+ struct hevc_state_s *hevc =
+ (struct hevc_state_s *)(vdec->private);
+ struct vdec_input_s *input = &vdec->input;
+ u32 wp, rp, level;
+ u32 rp_set;
+
+ rp = STBUF_READ(&vdec->vbuf, get_rp);
+ wp = hevc->pre_parser_wr_ptr;
+
+ if (wp > rp)
+ level = wp - rp;
+ else
+ level = wp + vdec->input.size - rp;
+
+ if (level > 0x100000) {
+ u32 skip_size = ((level >> 1) >> 19) << 19;
+ if (!vdec->input.swap_valid) {
+ hevc_print(hevc , 0, "h265 start data discard level 0x%x, buffer level 0x%x, RP 0x%x, WP 0x%x\n",
+ ((level >> 1) >> 19) << 19, level, rp, wp);
+ if (wp >= rp) {
+ rp_set = rp + skip_size;
+ }
+ else if ((rp + skip_size) < (input->start + input->size)) {
+ rp_set = rp + skip_size;
+ } else {
+ rp_set = rp + skip_size - input->size;
+ }
+ STBUF_WRITE(&vdec->vbuf, set_rp, rp_set);
+ vdec->discard_start_data_flag = 1;
+ vdec->input.stream_cookie += skip_size;
+ hevc->dirty_shift_flag = 1;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static int check_data_size(struct vdec_s *vdec)
+{
+ struct hevc_state_s *hw =
+ (struct hevc_state_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) {
+ hevc_print(hw, 0, "h265 data skipped %x\n", level);
+ hw->dec_again_cnt = 0;
+ return 1;
+ }
+ return 0;
+}
+
+static int vh265_stop(struct hevc_state_s *hevc)
+{
+ if (get_dbg_flag(hevc) &
+ H265_DEBUG_WAIT_DECODE_DONE_WHEN_STOP) {
+ int wait_timeout_count = 0;
+
+ while (READ_VREG(HEVC_DEC_STATUS_REG) ==
+ HEVC_CODED_SLICE_SEGMENT_DAT &&
+ wait_timeout_count < 10){
+ wait_timeout_count++;
+ msleep(20);
+ }
+ }
+ if (hevc->stat & STAT_VDEC_RUN) {
+ amhevc_stop();
+ hevc->stat &= ~STAT_VDEC_RUN;
+ }
+
+ if (hevc->stat & STAT_ISR_REG) {
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (!hevc->m_ins_flag)
+#endif
+ WRITE_VREG(HEVC_ASSIST_MBOX0_MASK, 0);
+ vdec_free_irq(VDEC_IRQ_0, (void *)hevc);
+ hevc->stat &= ~STAT_ISR_REG;
+ }
+
+ hevc->stat &= ~STAT_TIMER_INIT;
+ if (hevc->stat & STAT_TIMER_ARM) {
+ del_timer_sync(&hevc->timer);
+ hevc->stat &= ~STAT_TIMER_ARM;
+ }
+
+ if (hevc->stat & STAT_VF_HOOK) {
+ if (fr_hint_status == VDEC_HINTED) {
+ vf_notify_receiver(hevc->provider_name,
+ VFRAME_EVENT_PROVIDER_FR_END_HINT,
+ NULL);
+ }
+ fr_hint_status = VDEC_NO_NEED_HINT;
+ vf_unreg_provider(&vh265_vf_prov);
+ hevc->stat &= ~STAT_VF_HOOK;
+ }
+
+ hevc_local_uninit(hevc);
+
+ if (use_cma) {
+ hevc->uninit_list = 1;
+ up(&h265_sema);
+#ifdef USE_UNINIT_SEMA
+ down(&hevc->h265_uninit_done_sema);
+ if (!IS_ERR(h265_task)) {
+ kthread_stop(h265_task);
+ h265_task = NULL;
+ }
+#else
+ while (hevc->uninit_list) /* wait uninit complete */
+ msleep(20);
+#endif
+
+ }
+ hevc->init_flag = 0;
+ hevc->first_sc_checked = 0;
+ cancel_work_sync(&hevc->notify_work);
+ cancel_work_sync(&hevc->set_clk_work);
+ uninit_mmu_buffers(hevc);
+ amhevc_disable();
+
+ //pr_err("[%s line %d] hevc->gvs=0x%p operation\n",__func__, __LINE__, hevc->gvs);
+ if (hevc->gvs)
+ kfree(hevc->gvs);
+ hevc->gvs = NULL;
+
+ return 0;
+}
+
+#ifdef MULTI_INSTANCE_SUPPORT
+static void reset_process_time(struct hevc_state_s *hevc)
+{
+ if (hevc->start_process_time) {
+ unsigned int process_time =
+ 1000 * (jiffies - hevc->start_process_time) / HZ;
+ hevc->start_process_time = 0;
+ if (process_time > max_process_time[hevc->index])
+ max_process_time[hevc->index] = process_time;
+ }
+}
+
+static void start_process_time(struct hevc_state_s *hevc)
+{
+ hevc->start_process_time = jiffies;
+ hevc->decode_timeout_count = 2;
+ hevc->last_lcu_idx = 0;
+}
+
+static void restart_process_time(struct hevc_state_s *hevc)
+{
+ hevc->start_process_time = jiffies;
+ hevc->decode_timeout_count = 2;
+}
+
+static void timeout_process(struct hevc_state_s *hevc)
+{
+ /*
+ * In this very timeout point,the vh265_work arrives,
+ * or in some cases the system become slow, then come
+ * this second timeout. In both cases we return.
+ */
+ if (work_pending(&hevc->work) ||
+ work_busy(&hevc->work) ||
+ work_busy(&hevc->timeout_work) ||
+ work_pending(&hevc->timeout_work)) {
+ pr_err("%s h265[%d] work pending, do nothing.\n",__func__, hevc->index);
+ return;
+ }
+
+ hevc->timeout_num++;
+ amhevc_stop();
+ read_decode_info(hevc);
+
+ hevc_print(hevc,
+ 0, "%s decoder timeout\n", __func__);
+ check_pic_decoded_error(hevc,
+ hevc->pic_decoded_lcu_idx);
+ /*The current decoded frame is marked
+ error when the decode timeout*/
+ if (hevc->cur_pic != NULL)
+ hevc->cur_pic->error_mark = 1;
+ hevc->decoded_poc = hevc->curr_POC;
+ hevc->decoding_pic = NULL;
+ hevc->dec_result = DEC_RESULT_DONE;
+ reset_process_time(hevc);
+
+ if (work_pending(&hevc->work))
+ return;
+ vdec_schedule_work(&hevc->timeout_work);
+}
+
+#ifdef CONSTRAIN_MAX_BUF_NUM
+static int get_vf_ref_only_buf_count(struct hevc_state_s *hevc)
+{
+ struct PIC_s *pic;
+ int i;
+ int count = 0;
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL || pic->index == -1)
+ continue;
+ if (pic->output_mark == 0 && pic->referenced == 0
+ && pic->output_ready == 1)
+ count++;
+ }
+
+ return count;
+}
+
+static int get_used_buf_count(struct hevc_state_s *hevc)
+{
+ struct PIC_s *pic;
+ int i;
+ int count = 0;
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL || pic->index == -1)
+ continue;
+ if (pic->output_mark != 0 || pic->referenced != 0
+ || pic->output_ready != 0)
+ count++;
+ }
+
+ return count;
+}
+#endif
+
+
+static unsigned char is_new_pic_available(struct hevc_state_s *hevc)
+{
+ struct PIC_s *new_pic = NULL;
+ struct PIC_s *pic;
+ /* recycle un-used pic */
+ int i;
+ int ref_pic = 0;
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+ unsigned long flags;
+ /*return 1 if pic_list is not initialized yet*/
+ if (hevc->pic_list_init_flag != 3)
+ return 1;
+ spin_lock_irqsave(&lock, flags);
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL || pic->index == -1)
+ continue;
+ if (pic->referenced == 1)
+ ref_pic++;
+ if (pic->output_mark == 0 && pic->referenced == 0
+ && pic->output_ready == 0
+ && pic->vf_ref == 0
+ ) {
+ if (new_pic) {
+ if (pic->POC < new_pic->POC)
+ new_pic = pic;
+ } else
+ new_pic = pic;
+ }
+ }
+ if (new_pic == NULL) {
+ enum receviver_start_e state = RECEIVER_INACTIVE;
+ if (vf_get_receiver(vdec->vf_provider_name)) {
+ state =
+ vf_notify_receiver(vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_QUREY_STATE,
+ NULL);
+ if ((state == RECEIVER_STATE_NULL)
+ || (state == RECEIVER_STATE_NONE))
+ state = RECEIVER_INACTIVE;
+ }
+ if (state == RECEIVER_INACTIVE) {
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ int poc = INVALID_POC;
+ pic = hevc->m_PIC[i];
+ if (pic == NULL || pic->index == -1)
+ continue;
+ if ((pic->referenced == 0) &&
+ (pic->error_mark == 1) &&
+ (pic->output_mark == 1)) {
+ if (pic->POC < poc) {
+ new_pic = pic;
+ poc = pic->POC;
+ }
+ }
+ }
+ if (new_pic) {
+ new_pic->referenced = 0;
+ new_pic->output_mark = 0;
+ put_mv_buf(hevc, new_pic);
+ hevc_print(hevc, 0, "force release error pic %d recieve_state %d \n", new_pic->POC, state);
+ } else {
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL || pic->index == -1)
+ continue;
+ if ((pic->referenced == 1) && (pic->error_mark == 1)) {
+ spin_unlock_irqrestore(&lock, flags);
+ flush_output(hevc, pic);
+ hevc_print(hevc, 0, "DPB error, neeed fornce flush recieve_state %d \n", state);
+ return 0;
+ }
+ }
+ }
+ }
+ }
+ if (new_pic == NULL) {
+ int decode_count = 0;
+
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL || pic->index == -1)
+ continue;
+ if (pic->output_ready == 0)
+ decode_count++;
+ }
+ if (decode_count >=
+ hevc->param.p.sps_max_dec_pic_buffering_minus1_0 + detect_stuck_buffer_margin) {
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR_MORE)
+ dump_pic_list(hevc);
+ if (!(error_handle_policy & 0x400)) {
+ spin_unlock_irqrestore(&lock, flags);
+ flush_output(hevc, NULL);
+ hevc_print(hevc, H265_DEBUG_BUFMGR_MORE, "flush dpb, ref_error_count %d, sps_max_dec_pic_buffering_minus1_0 %d\n",
+ decode_count, hevc->param.p.sps_max_dec_pic_buffering_minus1_0);
+ return 0;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&lock, flags);
+ return (new_pic != NULL) ? 1 : 0;
+}
+
+static void check_buffer_status(struct hevc_state_s *hevc)
+{
+ int i;
+ struct PIC_s *new_pic = NULL;
+ struct PIC_s *pic;
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+
+ enum receviver_start_e state = RECEIVER_INACTIVE;
+ if (vf_get_receiver(vdec->vf_provider_name)) {
+ state =
+ vf_notify_receiver(vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_QUREY_STATE,
+ NULL);
+ if ((state == RECEIVER_STATE_NULL)
+ || (state == RECEIVER_STATE_NONE))
+ state = RECEIVER_INACTIVE;
+ }
+ if (hevc->timeout_flag == false)
+ hevc->timeout = jiffies + HZ / 2;
+
+ if (state == RECEIVER_INACTIVE)
+ hevc->timeout_flag = true;
+ else
+ hevc->timeout_flag = false;
+
+ if (state == RECEIVER_INACTIVE && hevc->timeout_flag &&
+ time_after(jiffies, hevc->timeout)) {
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ int poc = INVALID_POC;
+ pic = hevc->m_PIC[i];
+ if (pic == NULL || pic->index == -1)
+ continue;
+ if ((pic->referenced == 0) &&
+ (pic->error_mark == 1) &&
+ (pic->output_mark == 1)) {
+ if (pic->POC < poc) {
+ new_pic = pic;
+ poc = pic->POC;
+ }
+ }
+ }
+ if (new_pic) {
+ new_pic->referenced = 0;
+ new_pic->output_mark = 0;
+ put_mv_buf(hevc, new_pic);
+ hevc_print(hevc, 0, "check_buffer_status force release error pic %d recieve_state %d \n", new_pic->POC, state);
+ } else {
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL || pic->index == -1)
+ continue;
+ if ((pic->referenced == 1) && (pic->error_mark == 1)) {
+ flush_output(hevc, pic);
+ hevc_print(hevc, 0, "check_buffer_status DPB error, neeed fornce flush recieve_state %d \n", state);
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+static int vmh265_stop(struct hevc_state_s *hevc)
+{
+ if (hevc->stat & STAT_TIMER_ARM) {
+ del_timer_sync(&hevc->timer);
+ hevc->stat &= ~STAT_TIMER_ARM;
+ }
+ if (hevc->stat & STAT_VDEC_RUN) {
+ amhevc_stop();
+ hevc->stat &= ~STAT_VDEC_RUN;
+ }
+ if (hevc->stat & STAT_ISR_REG) {
+ vdec_free_irq(VDEC_IRQ_0, (void *)hevc);
+ hevc->stat &= ~STAT_ISR_REG;
+ }
+
+ if (hevc->stat & STAT_VF_HOOK) {
+ if (fr_hint_status == VDEC_HINTED)
+ vf_notify_receiver(hevc->provider_name,
+ VFRAME_EVENT_PROVIDER_FR_END_HINT,
+ NULL);
+ fr_hint_status = VDEC_NO_NEED_HINT;
+ vf_unreg_provider(&vh265_vf_prov);
+ hevc->stat &= ~STAT_VF_HOOK;
+ }
+
+ hevc_local_uninit(hevc);
+
+ if (hevc->gvs)
+ kfree(hevc->gvs);
+ hevc->gvs = NULL;
+
+ if (use_cma) {
+ hevc->uninit_list = 1;
+ reset_process_time(hevc);
+ hevc->dec_result = DEC_RESULT_FREE_CANVAS;
+ vdec_schedule_work(&hevc->work);
+ flush_work(&hevc->work);
+#ifdef USE_UNINIT_SEMA
+ if (hevc->init_flag) {
+ down(&hevc->h265_uninit_done_sema);
+ }
+#else
+ while (hevc->uninit_list) /* wait uninit complete */
+ msleep(20);
+#endif
+ }
+ hevc->init_flag = 0;
+ hevc->first_sc_checked = 0;
+ cancel_work_sync(&hevc->notify_work);
+ cancel_work_sync(&hevc->set_clk_work);
+ cancel_work_sync(&hevc->timeout_work);
+ cancel_work_sync(&hevc->work);
+ uninit_mmu_buffers(hevc);
+
+ vfree(hevc->fw);
+ hevc->fw = NULL;
+
+ dump_log(hevc);
+ return 0;
+}
+
+static unsigned char get_data_check_sum
+ (struct hevc_state_s *hevc, int size)
+{
+ int jj;
+ int sum = 0;
+ u8 *data = NULL;
+
+ if (!hevc->chunk->block->is_mapped)
+ data = codec_mm_vmap(hevc->chunk->block->start +
+ hevc->chunk->offset, size);
+ else
+ data = ((u8 *)hevc->chunk->block->start_virt) +
+ hevc->chunk->offset;
+
+ for (jj = 0; jj < size; jj++)
+ sum += data[jj];
+
+ if (!hevc->chunk->block->is_mapped)
+ codec_mm_unmap_phyaddr(data);
+ return sum;
+}
+
+static void vh265_notify_work(struct work_struct *work)
+{
+ struct hevc_state_s *hevc =
+ container_of(work,
+ struct hevc_state_s,
+ notify_work);
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (vdec->fr_hint_state == VDEC_NEED_HINT) {
+ vf_notify_receiver(hevc->provider_name,
+ VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)
+ ((unsigned long)hevc->frame_dur));
+ vdec->fr_hint_state = VDEC_HINTED;
+ } else if (fr_hint_status == VDEC_NEED_HINT) {
+ vf_notify_receiver(hevc->provider_name,
+ VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)
+ ((unsigned long)hevc->frame_dur));
+ fr_hint_status = VDEC_HINTED;
+ }
+#else
+ if (fr_hint_status == VDEC_NEED_HINT)
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)
+ ((unsigned long)hevc->frame_dur));
+ fr_hint_status = VDEC_HINTED;
+ }
+#endif
+
+ return;
+}
+
+static void vh265_work_implement(struct hevc_state_s *hevc,
+ struct vdec_s *vdec,int from)
+{
+ if (hevc->dec_result == DEC_RESULT_FREE_CANVAS) {
+ /*USE_BUF_BLOCK*/
+ uninit_pic_list(hevc);
+ hevc->uninit_list = 0;
+#ifdef USE_UNINIT_SEMA
+ up(&hevc->h265_uninit_done_sema);
+#endif
+ return;
+ }
+
+ /* finished decoding one frame or error,
+ * notify vdec core to switch context
+ */
+ if (hevc->pic_list_init_flag == 1
+ && (hevc->dec_result != DEC_RESULT_FORCE_EXIT)) {
+ hevc->pic_list_init_flag = 2;
+ init_pic_list(hevc);
+ init_pic_list_hw(hevc);
+ init_buf_spec(hevc);
+ hevc_print(hevc, 0,
+ "set pic_list_init_flag to 2\n");
+
+ WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG, 0x1);
+ return;
+ }
+
+ hevc_print(hevc, PRINT_FLAG_VDEC_DETAIL,
+ "%s dec_result %d %x %x %x\n",
+ __func__,
+ hevc->dec_result,
+ READ_VREG(HEVC_STREAM_LEVEL),
+ READ_VREG(HEVC_STREAM_WR_PTR),
+ READ_VREG(HEVC_STREAM_RD_PTR));
+
+ if (((hevc->dec_result == DEC_RESULT_GET_DATA) ||
+ (hevc->dec_result == DEC_RESULT_GET_DATA_RETRY))
+ && (hw_to_vdec(hevc)->next_status !=
+ VDEC_STATUS_DISCONNECTED)) {
+ if (!vdec_has_more_input(vdec)) {
+ hevc->dec_result = DEC_RESULT_EOS;
+ vdec_schedule_work(&hevc->work);
+ return;
+ }
+ if (!input_frame_based(vdec)) {
+ int r = vdec_sync_input(vdec);
+ if (r >= 0x200) {
+ WRITE_VREG(HEVC_DECODE_SIZE,
+ READ_VREG(HEVC_DECODE_SIZE) + r);
+
+ hevc_print(hevc, PRINT_FLAG_VDEC_STATUS,
+ "%s DEC_RESULT_GET_DATA %x %x %x mpc %x size 0x%x\n",
+ __func__,
+ READ_VREG(HEVC_STREAM_LEVEL),
+ READ_VREG(HEVC_STREAM_WR_PTR),
+ READ_VREG(HEVC_STREAM_RD_PTR),
+ READ_VREG(HEVC_MPC_E), r);
+
+ start_process_time(hevc);
+ if (READ_VREG(HEVC_DEC_STATUS_REG)
+ == HEVC_DECODE_BUFEMPTY2)
+ WRITE_VREG(HEVC_DEC_STATUS_REG,
+ HEVC_ACTION_DONE);
+ else
+ WRITE_VREG(HEVC_DEC_STATUS_REG,
+ HEVC_ACTION_DEC_CONT);
+ } else {
+ hevc->dec_result = DEC_RESULT_GET_DATA_RETRY;
+ vdec_schedule_work(&hevc->work);
+ }
+ return;
+ }
+
+ /*below for frame_base*/
+ if (hevc->dec_result == DEC_RESULT_GET_DATA) {
+ hevc_print(hevc, PRINT_FLAG_VDEC_STATUS,
+ "%s DEC_RESULT_GET_DATA %x %x %x mpc %x\n",
+ __func__,
+ READ_VREG(HEVC_STREAM_LEVEL),
+ READ_VREG(HEVC_STREAM_WR_PTR),
+ READ_VREG(HEVC_STREAM_RD_PTR),
+ READ_VREG(HEVC_MPC_E));
+ mutex_lock(&hevc->chunks_mutex);
+ vdec_vframe_dirty(vdec, hevc->chunk);
+ hevc->chunk = NULL;
+ mutex_unlock(&hevc->chunks_mutex);
+ vdec_clean_input(vdec);
+ }
+
+ /*if (is_new_pic_available(hevc)) {*/
+ if (run_ready(vdec, VDEC_HEVC)) {
+ int r;
+ int decode_size;
+
+ r = vdec_prepare_input(vdec, &hevc->chunk);
+ if (r < 0) {
+ hevc->dec_result = DEC_RESULT_GET_DATA_RETRY;
+
+ hevc_print(hevc,
+ PRINT_FLAG_VDEC_DETAIL,
+ "amvdec_vh265: Insufficient data\n");
+
+ vdec_schedule_work(&hevc->work);
+ return;
+ }
+ hevc->dec_result = DEC_RESULT_NONE;
+ hevc_print(hevc, PRINT_FLAG_VDEC_STATUS,
+ "%s: chunk size 0x%x sum 0x%x mpc %x\n",
+ __func__, r,
+ (get_dbg_flag(hevc) & PRINT_FLAG_VDEC_STATUS) ?
+ get_data_check_sum(hevc, r) : 0,
+ READ_VREG(HEVC_MPC_E));
+
+ if (get_dbg_flag(hevc) & PRINT_FRAMEBASE_DATA) {
+ int jj;
+ u8 *data = NULL;
+
+ if (!hevc->chunk->block->is_mapped)
+ data = codec_mm_vmap(
+ hevc->chunk->block->start +
+ hevc->chunk->offset, r);
+ else
+ data = ((u8 *)
+ hevc->chunk->block->start_virt)
+ + hevc->chunk->offset;
+
+ for (jj = 0; jj < r; jj++) {
+ if ((jj & 0xf) == 0)
+ hevc_print(hevc,
+ PRINT_FRAMEBASE_DATA,
+ "%06x:", jj);
+ hevc_print_cont(hevc,
+ PRINT_FRAMEBASE_DATA,
+ "%02x ", data[jj]);
+ if (((jj + 1) & 0xf) == 0)
+ hevc_print_cont(hevc,
+ PRINT_FRAMEBASE_DATA,
+ "\n");
+ }
+
+ if (!hevc->chunk->block->is_mapped)
+ codec_mm_unmap_phyaddr(data);
+ }
+
+ decode_size = hevc->chunk->size +
+ (hevc->chunk->offset & (VDEC_FIFO_ALIGN - 1));
+ WRITE_VREG(HEVC_DECODE_SIZE,
+ READ_VREG(HEVC_DECODE_SIZE) + decode_size);
+
+ vdec_enable_input(vdec);
+
+ hevc_print(hevc, PRINT_FLAG_VDEC_STATUS,
+ "%s: mpc %x\n",
+ __func__, READ_VREG(HEVC_MPC_E));
+
+ start_process_time(hevc);
+ WRITE_VREG(HEVC_DEC_STATUS_REG, HEVC_ACTION_DONE);
+ } else{
+ hevc->dec_result = DEC_RESULT_GET_DATA_RETRY;
+
+ /*hevc_print(hevc, PRINT_FLAG_VDEC_DETAIL,
+ * "amvdec_vh265: Insufficient data\n");
+ */
+
+ vdec_schedule_work(&hevc->work);
+ }
+ return;
+ } else if (hevc->dec_result == DEC_RESULT_DONE) {
+ /* if (!hevc->ctx_valid)
+ hevc->ctx_valid = 1; */
+ int i;
+ hevc->dec_again_cnt = 0;
+ decode_frame_count[hevc->index]++;
+#ifdef DETREFILL_ENABLE
+ if (hevc->is_swap &&
+ get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_GXM) {
+ if (hevc->delrefill_check == 2) {
+ delrefill(hevc);
+ amhevc_stop();
+ }
+ }
+#endif
+
+ if (hevc->mmu_enable && ((hevc->double_write_mode & 0x10) == 0)) {
+ hevc->used_4k_num =
+ READ_VREG(HEVC_SAO_MMU_STATUS) >> 16;
+ if (hevc->used_4k_num >= 0 &&
+ hevc->cur_pic &&
+ hevc->cur_pic->scatter_alloc
+ == 1) {
+ hevc_print(hevc, H265_DEBUG_BUFMGR_MORE,
+ "%s pic index %d scatter_alloc %d page_start %ld\n",
+ "decoder_mmu_box_free_idx_tail",
+ hevc->cur_pic->index,
+ hevc->cur_pic->scatter_alloc,
+ hevc->used_4k_num);
+ if (hevc->m_ins_flag)
+ hevc_mmu_dma_check(hw_to_vdec(hevc));
+ decoder_mmu_box_free_idx_tail(
+ hevc->mmu_box,
+ hevc->cur_pic->index,
+ hevc->used_4k_num);
+ hevc->cur_pic->scatter_alloc = 2;
+ }
+ }
+ hevc->pic_decoded_lcu_idx =
+ READ_VREG(HEVC_PARSER_LCU_START)
+ & 0xffffff;
+
+ if ((!vdec_dual(vdec)) &&
+ hevc->empty_flag == 0) {
+ hevc->over_decode =
+ (READ_VREG(HEVC_SHIFT_STATUS) >> 15) & 0x1;
+ if (hevc->over_decode)
+ hevc_print(hevc, 0,
+ "!!!Over decode\n");
+ }
+
+ if (is_log_enable(hevc))
+ add_log(hevc,
+ "%s dec_result %d lcu %d used_mmu %ld shiftbyte 0x%x decbytes 0x%x",
+ __func__,
+ hevc->dec_result,
+ hevc->pic_decoded_lcu_idx,
+ hevc->used_4k_num,
+ READ_VREG(HEVC_SHIFT_BYTE_COUNT),
+ READ_VREG(HEVC_SHIFT_BYTE_COUNT) -
+ hevc->start_shift_bytes
+ );
+
+ hevc_print(hevc, PRINT_FLAG_VDEC_STATUS,
+ "%s dec_result %d (%x %x %x) lcu %d used_mmu %ld shiftbyte 0x%x decbytes 0x%x\n",
+ __func__,
+ hevc->dec_result,
+ READ_VREG(HEVC_STREAM_LEVEL),
+ READ_VREG(HEVC_STREAM_WR_PTR),
+ READ_VREG(HEVC_STREAM_RD_PTR),
+ hevc->pic_decoded_lcu_idx,
+ hevc->used_4k_num,
+ READ_VREG(HEVC_SHIFT_BYTE_COUNT),
+ READ_VREG(HEVC_SHIFT_BYTE_COUNT) -
+ hevc->start_shift_bytes
+ );
+
+ hevc->used_4k_num = -1;
+
+ check_pic_decoded_error(hevc,
+ hevc->pic_decoded_lcu_idx);
+ if ((error_handle_policy & 0x100) == 0 && hevc->cur_pic) {
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ struct PIC_s *pic;
+ pic = hevc->m_PIC[i];
+ if (!pic || pic->index == -1)
+ continue;
+ if ((hevc->cur_pic->POC + poc_num_margin < pic->POC) && (pic->referenced == 0) &&
+ (pic->output_mark == 1) && (pic->output_ready == 0)) {
+ hevc->poc_error_count++;
+ break;
+ }
+ }
+ if (i == MAX_REF_PIC_NUM)
+ hevc->poc_error_count = 0;
+ if (hevc->poc_error_count >= poc_error_limit) {
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ struct PIC_s *pic;
+ pic = hevc->m_PIC[i];
+ if (!pic || pic->index == -1)
+ continue;
+ if ((hevc->cur_pic->POC + poc_num_margin < pic->POC) && (pic->referenced == 0) &&
+ (pic->output_mark == 1) && (pic->output_ready == 0)) {
+ pic->output_mark = 0;
+ hevc_print(hevc, 0, "DPB poc error, remove error frame\n");
+ }
+ }
+ }
+ }
+
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+#if 1
+ if (vdec->slave) {
+ if (dv_debug & 0x1)
+ vdec_set_flag(vdec->slave,
+ VDEC_FLAG_SELF_INPUT_CONTEXT);
+ else
+ vdec_set_flag(vdec->slave,
+ VDEC_FLAG_OTHER_INPUT_CONTEXT);
+ }
+#else
+ if (vdec->slave) {
+ if (no_interleaved_el_slice)
+ vdec_set_flag(vdec->slave,
+ VDEC_FLAG_INPUT_KEEP_CONTEXT);
+ /* this will move real HW pointer for input */
+ else
+ vdec_set_flag(vdec->slave, 0);
+ /* this will not move real HW pointer
+ *and SL layer decoding
+ *will start from same stream position
+ *as current BL decoder
+ */
+ }
+#endif
+#endif
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ hevc->shift_byte_count_lo
+ = READ_VREG(HEVC_SHIFT_BYTE_COUNT);
+ if (vdec->slave) {
+ /*cur is base, found enhance*/
+ struct hevc_state_s *hevc_el =
+ (struct hevc_state_s *)
+ vdec->slave->private;
+ if (hevc_el)
+ hevc_el->shift_byte_count_lo =
+ hevc->shift_byte_count_lo;
+ } else if (vdec->master) {
+ /*cur is enhance, found base*/
+ struct hevc_state_s *hevc_ba =
+ (struct hevc_state_s *)
+ vdec->master->private;
+ if (hevc_ba)
+ hevc_ba->shift_byte_count_lo =
+ hevc->shift_byte_count_lo;
+ }
+#endif
+ mutex_lock(&hevc->chunks_mutex);
+ vdec_vframe_dirty(hw_to_vdec(hevc), hevc->chunk);
+ hevc->chunk = NULL;
+ mutex_unlock(&hevc->chunks_mutex);
+ } else if (hevc->dec_result == DEC_RESULT_AGAIN) {
+ /*
+ stream base: stream buf empty or timeout
+ frame base: vdec_prepare_input fail
+ */
+
+ if (!vdec_has_more_input(vdec)) {
+ hevc->dec_result = DEC_RESULT_EOS;
+ vdec_schedule_work(&hevc->work);
+ return;
+ }
+#ifdef AGAIN_HAS_THRESHOLD
+ hevc->next_again_flag = 1;
+#endif
+ if (input_stream_based(vdec)) {
+ if (!(error_handle_policy & 0x400) && check_data_size(vdec)) {
+ hevc->dec_result = DEC_RESULT_DONE;
+ vdec_schedule_work(&hevc->work);
+ return;
+ } else if ((((error_handle_policy & 0x200) == 0) &&
+ (hevc->pic_list_init_flag == 0))) {
+ check_dirty_data(vdec);
+ }
+ }
+ } else if (hevc->dec_result == DEC_RESULT_EOS) {
+ struct PIC_s *pic;
+ hevc->eos = 1;
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ if ((vdec_dual(vdec)) && aux_data_is_avaible(hevc))
+ if (hevc->decoding_pic)
+ dolby_get_meta(hevc);
+#endif
+ check_pic_decoded_error(hevc,
+ hevc->pic_decoded_lcu_idx);
+ pic = get_pic_by_POC(hevc, hevc->curr_POC);
+ hevc_print(hevc, PRINT_FLAG_VDEC_STATUS,
+ "%s: end of stream, last dec poc %d => 0x%pf\n",
+ __func__, hevc->curr_POC, pic);
+ flush_output(hevc, pic);
+ /* dummy vf with eos flag to backend */
+ notify_v4l_eos(hw_to_vdec(hevc));
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ hevc->shift_byte_count_lo
+ = READ_VREG(HEVC_SHIFT_BYTE_COUNT);
+ if (vdec->slave) {
+ /*cur is base, found enhance*/
+ struct hevc_state_s *hevc_el =
+ (struct hevc_state_s *)
+ vdec->slave->private;
+ if (hevc_el)
+ hevc_el->shift_byte_count_lo =
+ hevc->shift_byte_count_lo;
+ } else if (vdec->master) {
+ /*cur is enhance, found base*/
+ struct hevc_state_s *hevc_ba =
+ (struct hevc_state_s *)
+ vdec->master->private;
+ if (hevc_ba)
+ hevc_ba->shift_byte_count_lo =
+ hevc->shift_byte_count_lo;
+ }
+#endif
+ mutex_lock(&hevc->chunks_mutex);
+ vdec_vframe_dirty(hw_to_vdec(hevc), hevc->chunk);
+ hevc->chunk = NULL;
+ mutex_unlock(&hevc->chunks_mutex);
+ } else if (hevc->dec_result == DEC_RESULT_FORCE_EXIT) {
+ hevc_print(hevc, PRINT_FLAG_VDEC_STATUS,
+ "%s: force exit\n",
+ __func__);
+ if (hevc->stat & STAT_VDEC_RUN) {
+ amhevc_stop();
+ hevc->stat &= ~STAT_VDEC_RUN;
+ }
+ if (hevc->stat & STAT_ISR_REG) {
+ WRITE_VREG(HEVC_ASSIST_MBOX0_MASK, 0);
+ vdec_free_irq(VDEC_IRQ_0, (void *)hevc);
+ hevc->stat &= ~STAT_ISR_REG;
+ }
+ hevc_print(hevc, 0, "%s: force exit end\n",
+ __func__);
+ } else if (hevc->dec_result == DEC_RESULT_DISCARD_DATA) {
+ mutex_lock(&hevc->chunks_mutex);
+ vdec_vframe_dirty(hw_to_vdec(hevc), hevc->chunk);
+ hevc->chunk = NULL;
+ mutex_unlock(&hevc->chunks_mutex);
+ }
+
+ if (hevc->stat & STAT_VDEC_RUN) {
+ amhevc_stop();
+ hevc->stat &= ~STAT_VDEC_RUN;
+ }
+
+ if (hevc->stat & STAT_TIMER_ARM) {
+ del_timer_sync(&hevc->timer);
+ hevc->stat &= ~STAT_TIMER_ARM;
+ }
+
+ wait_hevc_search_done(hevc);
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ if (hevc->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(&hevc->work)) {
+ /*
+ * The vh265_work arrives at the last second,
+ * give it a chance to handle the scenario.
+ */
+ return;
+ //cancel_work_sync(&hevc->work);//reserved for future considraion
+ }
+ }
+
+ /* 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 (hevc->is_used_v4l) {
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(hevc->v4l2_ctx);
+
+ if (ctx->param_sets_from_ucode &&
+ !hevc->v4l_params_parsed)
+ vdec_v4l_write_frame_sync(ctx);
+ }
+
+ if (hevc->vdec_cb)
+ hevc->vdec_cb(hw_to_vdec(hevc), hevc->vdec_cb_arg);
+}
+
+static void vh265_work(struct work_struct *work)
+{
+ struct hevc_state_s *hevc = container_of(work,
+ struct hevc_state_s, work);
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+
+ vh265_work_implement(hevc, vdec, 0);
+}
+
+static void vh265_timeout_work(struct work_struct *work)
+{
+ struct hevc_state_s *hevc = container_of(work,
+ struct hevc_state_s, timeout_work);
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+
+ if (work_pending(&hevc->work))
+ return;
+ hevc->timeout_processing = 1;
+ vh265_work_implement(hevc, vdec, 1);
+}
+
+#ifdef VDEC_FCC_SUPPORT
+static void vh265_wakeup_fcc_poll(struct vdec_s *vdec)
+{
+ amstream_wakeup_fcc_poll(vdec);
+}
+#endif
+
+static int vh265_hw_ctx_restore(struct hevc_state_s *hevc)
+{
+ /* new to do ... */
+ vh265_prot_init(hevc);
+ return 0;
+}
+static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask)
+{
+ struct hevc_state_s *hevc =
+ (struct hevc_state_s *)vdec->private;
+ int tvp = vdec_secure(hw_to_vdec(hevc)) ?
+ CODEC_MM_FLAGS_TVP : 0;
+ bool ret = 0;
+#ifdef VDEC_FCC_SUPPORT
+ int get_msg = 1;
+#endif
+ if (step == 0x12)
+ return 0;
+ else if (step == 0x11)
+ step = 0x12;
+
+ if (hevc->fatal_error & DECODER_FATAL_ERROR_NO_MEM)
+ return 0;
+
+ if (hevc->eos)
+ return 0;
+ if (hevc->timeout_processing &&
+ (work_pending(&hevc->work) ||
+ work_busy(&hevc->work) ||
+ work_busy(&hevc->timeout_work) ||
+ work_pending(&hevc->timeout_work))) {
+ hevc_print(hevc, PRINT_FLAG_VDEC_STATUS,
+ "h265 work pending,not ready for run.\n");
+ return 0;
+ }
+ hevc->timeout_processing = 0;
+ if (!hevc->first_sc_checked && hevc->mmu_enable) {
+ int size = decoder_mmu_box_sc_check(hevc->mmu_box, tvp);
+ hevc->first_sc_checked =1;
+ hevc_print(hevc, 0,
+ "vh265 cached=%d need_size=%d speed= %d ms\n",
+ size, (hevc->need_cache_size >> PAGE_SHIFT),
+ (int)(get_jiffies_64() - hevc->sc_start_time) * 1000/HZ);
+ }
+ if (vdec_stream_based(vdec) && (hevc->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;
+ }
+
+#ifdef AGAIN_HAS_THRESHOLD
+ if (hevc->next_again_flag &&
+ (!vdec_frame_based(vdec))) {
+ u32 parser_wr_ptr =
+ STBUF_READ(&vdec->vbuf, get_wp);
+ if (parser_wr_ptr >= hevc->pre_parser_wr_ptr &&
+ (parser_wr_ptr - hevc->pre_parser_wr_ptr) <
+ again_threshold) {
+ int r = vdec_sync_input(vdec);
+ hevc_print(hevc,
+ PRINT_FLAG_VDEC_DETAIL, "%s buf lelvel:%x\n", __func__, r);
+ return 0;
+ }
+ }
+#endif
+
+ if (disp_vframe_valve_level &&
+ kfifo_len(&hevc->display_q) >=
+ disp_vframe_valve_level) {
+ hevc->valve_count--;
+ if (hevc->valve_count <= 0)
+ hevc->valve_count = 2;
+ else
+ return 0;
+ }
+
+ ret = is_new_pic_available(hevc);
+ if (!ret) {
+ hevc_print(hevc,
+ PRINT_FLAG_VDEC_DETAIL, "%s=>%d\r\n",
+ __func__, ret);
+ }
+
+#ifdef CONSTRAIN_MAX_BUF_NUM
+ if (hevc->pic_list_init_flag == 3) {
+ if (run_ready_max_vf_only_num > 0 &&
+ get_vf_ref_only_buf_count(hevc) >=
+ run_ready_max_vf_only_num
+ )
+ ret = 0;
+ if (run_ready_display_q_num > 0 &&
+ kfifo_len(&hevc->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(hevc) >=
+ get_work_pic_num(hevc)) {
+ check_buffer_status(hevc);
+ ret = 0;
+ }
+ else if (run_ready_max_buf_num &&
+ get_used_buf_count(hevc) >=
+ run_ready_max_buf_num)
+ ret = 0;
+ }
+#endif
+
+ if (hevc->is_used_v4l) {
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(hevc->v4l2_ctx);
+
+ if (ctx->param_sets_from_ucode) {
+ if (hevc->v4l_params_parsed) {
+ if (!ctx->v4l_codec_dpb_ready &&
+ v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) <
+ run_ready_min_buf_num)
+ ret = 0;
+ } 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;
+ }
+ }
+
+#ifdef VDEC_FCC_SUPPORT
+ get_msg = vdec_has_get_fcc_new_msg(vdec);
+ ret &= get_msg;
+#endif
+ if (ret)
+ not_run_ready[hevc->index] = 0;
+ else
+ not_run_ready[hevc->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 hevc_state_s *hevc =
+ (struct hevc_state_s *)vdec->private;
+ int r, loadr = 0;
+ unsigned char check_sum = 0;
+
+ run_count[hevc->index]++;
+ hevc->vdec_cb_arg = arg;
+ hevc->vdec_cb = callback;
+ hevc->aux_data_dirty = 1;
+ hevc_reset_core(vdec);
+
+#ifdef AGAIN_HAS_THRESHOLD
+ if (vdec_stream_based(vdec)) {
+ hevc->pre_parser_wr_ptr =
+ STBUF_READ(&vdec->vbuf, get_wp);
+ hevc->next_again_flag = 0;
+ }
+#endif
+ r = vdec_prepare_input(vdec, &hevc->chunk);
+ if (r < 0) {
+ input_empty[hevc->index]++;
+ hevc->dec_result = DEC_RESULT_AGAIN;
+ hevc_print(hevc, PRINT_FLAG_VDEC_DETAIL,
+ "ammvdec_vh265: Insufficient data\n");
+
+ vdec_schedule_work(&hevc->work);
+ return;
+ }
+ input_empty[hevc->index] = 0;
+ hevc->dec_result = DEC_RESULT_NONE;
+ if (vdec_frame_based(vdec) &&
+ ((get_dbg_flag(hevc) & PRINT_FLAG_VDEC_STATUS)
+ || is_log_enable(hevc)) &&
+ !vdec_secure(vdec))
+ check_sum = get_data_check_sum(hevc, r);
+
+ if (is_log_enable(hevc))
+ add_log(hevc,
+ "%s: size 0x%x sum 0x%x shiftbyte 0x%x",
+ __func__, r,
+ check_sum,
+ READ_VREG(HEVC_SHIFT_BYTE_COUNT)
+ );
+ if ((hevc->dirty_shift_flag == 1) && !(vdec->input.swap_valid)) {
+ WRITE_VREG(HEVC_SHIFT_BYTE_COUNT, vdec->input.stream_cookie);
+ }
+ hevc->start_shift_bytes = READ_VREG(HEVC_SHIFT_BYTE_COUNT);
+
+ hevc_print(hevc, PRINT_FLAG_VDEC_STATUS,
+ "%s: size 0x%x sum 0x%x (%x %x %x %x %x) byte count %x\n",
+ __func__, r,
+ check_sum,
+ READ_VREG(HEVC_STREAM_LEVEL),
+ READ_VREG(HEVC_STREAM_WR_PTR),
+ READ_VREG(HEVC_STREAM_RD_PTR),
+ STBUF_READ(&vdec->vbuf, get_rp),
+ STBUF_READ(&vdec->vbuf, get_wp),
+ hevc->start_shift_bytes
+ );
+ if ((get_dbg_flag(hevc) & PRINT_FRAMEBASE_DATA) &&
+ input_frame_based(vdec) &&
+ !vdec_secure(vdec)) {
+ int jj;
+ u8 *data = NULL;
+
+ if (!hevc->chunk->block->is_mapped)
+ data = codec_mm_vmap(hevc->chunk->block->start +
+ hevc->chunk->offset, r);
+ else
+ data = ((u8 *)hevc->chunk->block->start_virt)
+ + hevc->chunk->offset;
+
+ for (jj = 0; jj < r; jj++) {
+ if ((jj & 0xf) == 0)
+ hevc_print(hevc, PRINT_FRAMEBASE_DATA,
+ "%06x:", jj);
+ hevc_print_cont(hevc, PRINT_FRAMEBASE_DATA,
+ "%02x ", data[jj]);
+ if (((jj + 1) & 0xf) == 0)
+ hevc_print_cont(hevc, PRINT_FRAMEBASE_DATA,
+ "\n");
+ }
+
+ if (!hevc->chunk->block->is_mapped)
+ codec_mm_unmap_phyaddr(data);
+ }
+ if (vdec->mc_loaded) {
+ /*firmware have load before,
+ and not changes to another.
+ ignore reload.
+ */
+ if (tee_enabled() && hevc->is_swap &&
+ get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_GXM)
+ WRITE_VREG(HEVC_STREAM_SWAP_BUFFER2, hevc->swap_addr);
+ } else {
+ if (hevc->mmu_enable)
+ if (get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_GXM)
+ loadr = amhevc_vdec_loadmc_ex(VFORMAT_HEVC, vdec,
+ "h265_mmu", hevc->fw->data);
+ else {
+ if (!hevc->is_4k) {
+ /* if an older version of the fw was loaded, */
+ /* needs try to load noswap fw because the */
+ /* old fw package dose not contain the swap fw.*/
+ loadr = amhevc_vdec_loadmc_ex(
+ VFORMAT_HEVC, vdec,
+ "hevc_mmu_swap",
+ hevc->fw->data);
+ if (loadr < 0)
+ loadr = amhevc_vdec_loadmc_ex(
+ VFORMAT_HEVC, vdec,
+ "h265_mmu",
+ hevc->fw->data);
+ else
+ hevc->is_swap = true;
+ } else
+ loadr = amhevc_vdec_loadmc_ex(
+ VFORMAT_HEVC, vdec,
+ "h265_mmu", hevc->fw->data);
+ }
+ else
+ loadr = amhevc_vdec_loadmc_ex(VFORMAT_HEVC, vdec,
+ NULL, hevc->fw->data);
+ if (loadr < 0) {
+ amhevc_disable();
+ hevc_print(hevc, 0, "H265: the %s fw loading failed, err: %x\n",
+ tee_enabled() ? "TEE" : "local", loadr);
+ hevc->dec_result = DEC_RESULT_FORCE_EXIT;
+ vdec_schedule_work(&hevc->work);
+ return;
+ }
+
+ if (tee_enabled() && hevc->is_swap &&
+ get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_GXM)
+ hevc->swap_addr = READ_VREG(HEVC_STREAM_SWAP_BUFFER2);
+#ifdef DETREFILL_ENABLE
+ if (hevc->is_swap &&
+ get_cpu_major_id() <= AM_MESON_CPU_MAJOR_ID_GXM)
+ init_detrefill_buf(hevc);
+#endif
+ vdec->mc_loaded = 1;
+ vdec->mc_type = VFORMAT_HEVC;
+ }
+ if (vh265_hw_ctx_restore(hevc) < 0) {
+ vdec_schedule_work(&hevc->work);
+ return;
+ }
+ vdec_enable_input(vdec);
+
+ WRITE_VREG(HEVC_DEC_STATUS_REG, HEVC_ACTION_DONE);
+
+ if (vdec_frame_based(vdec)) {
+ WRITE_VREG(HEVC_SHIFT_BYTE_COUNT, 0);
+ r = hevc->chunk->size +
+ (hevc->chunk->offset & (VDEC_FIFO_ALIGN - 1));
+ hevc->decode_size = r;
+ if (vdec->mvfrm)
+ vdec->mvfrm->frame_size = hevc->chunk->size;
+ }
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ else {
+ if (vdec->master || vdec->slave)
+ WRITE_VREG(HEVC_SHIFT_BYTE_COUNT,
+ hevc->shift_byte_count_lo);
+ }
+#endif
+ WRITE_VREG(HEVC_DECODE_SIZE, r);
+ /*WRITE_VREG(HEVC_DECODE_COUNT, hevc->decode_idx);*/
+ hevc->init_flag = 1;
+
+ if (hevc->pic_list_init_flag == 3)
+ init_pic_list_hw(hevc);
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR_MORE)
+ dump_pic_list(hevc);
+ backup_decode_state(hevc);
+ start_process_time(hevc);
+ mod_timer(&hevc->timer, jiffies);
+ hevc->stat |= STAT_TIMER_ARM;
+ hevc->stat |= STAT_ISR_REG;
+ if (vdec->mvfrm)
+ vdec->mvfrm->hw_decode_start = local_clock();
+ amhevc_start();
+ hevc->stat |= STAT_VDEC_RUN;
+}
+
+static void aml_free_canvas(struct vdec_s *vdec)
+{
+ int i;
+ struct hevc_state_s *hevc =
+ (struct hevc_state_s *)vdec->private;
+
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ struct PIC_s *pic = hevc->m_PIC[i];
+
+ if (pic) {
+ if (vdec->parallel_dec == 1) {
+ vdec->free_canvas_ex(pic->y_canvas_index, vdec->id);
+ vdec->free_canvas_ex(pic->uv_canvas_index, vdec->id);
+ }
+ }
+ }
+}
+
+static void reset(struct vdec_s *vdec)
+{
+ struct hevc_state_s *hevc =
+ (struct hevc_state_s *)vdec->private;
+ int i;
+
+ cancel_work_sync(&hevc->work);
+ cancel_work_sync(&hevc->notify_work);
+ if (hevc->stat & STAT_VDEC_RUN) {
+ amhevc_stop();
+ hevc->stat &= ~STAT_VDEC_RUN;
+ }
+
+ if (hevc->stat & STAT_TIMER_ARM) {
+ del_timer_sync(&hevc->timer);
+ hevc->stat &= ~STAT_TIMER_ARM;
+ }
+ hevc->dec_result = DEC_RESULT_NONE;
+ reset_process_time(hevc);
+ hevc->pic_list_init_flag = 0;
+ dealloc_mv_bufs(hevc);
+ aml_free_canvas(vdec);
+ hevc_local_uninit(hevc);
+ if (vh265_local_init(hevc) < 0)
+ pr_debug(" %s local init fail\n", __func__);
+ for (i = 0; i < BUF_POOL_SIZE; i++) {
+ hevc->m_BUF[i].start_adr = 0;
+ }
+
+ hevc_print(hevc, PRINT_FLAG_VDEC_DETAIL, "%s\r\n", __func__);
+}
+
+static irqreturn_t vh265_irq_cb(struct vdec_s *vdec, int irq)
+{
+ struct hevc_state_s *hevc =
+ (struct hevc_state_s *)vdec->private;
+
+ return vh265_isr(0, hevc);
+}
+
+static irqreturn_t vh265_threaded_irq_cb(struct vdec_s *vdec, int irq)
+{
+ struct hevc_state_s *hevc =
+ (struct hevc_state_s *)vdec->private;
+
+ return vh265_isr_thread_fn(0, hevc);
+}
+#endif
+
+static int amvdec_h265_probe(struct platform_device *pdev)
+{
+#ifdef MULTI_INSTANCE_SUPPORT
+ struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
+#else
+ struct vdec_dev_reg_s *pdata =
+ (struct vdec_dev_reg_s *)pdev->dev.platform_data;
+#endif
+ char *tmpbuf;
+ int ret;
+ struct hevc_state_s *hevc;
+
+ hevc = vmalloc(sizeof(struct hevc_state_s));
+ if (hevc == NULL) {
+ hevc_print(hevc, 0, "%s vmalloc hevc failed\r\n", __func__);
+ return -ENOMEM;
+ }
+ gHevc = hevc;
+ if ((debug & H265_NO_CHANG_DEBUG_FLAG_IN_CODE) == 0)
+ debug &= (~(H265_DEBUG_DIS_LOC_ERROR_PROC |
+ H265_DEBUG_DIS_SYS_ERROR_PROC));
+ memset(hevc, 0, sizeof(struct hevc_state_s));
+ if (get_dbg_flag(hevc))
+ hevc_print(hevc, 0, "%s\r\n", __func__);
+ mutex_lock(&vh265_mutex);
+
+ if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXTVBB) &&
+ (parser_sei_enable & 0x100) == 0)
+ parser_sei_enable = 7; /*old 1*/
+ hevc->m_ins_flag = 0;
+ hevc->init_flag = 0;
+ hevc->first_sc_checked = 0;
+ hevc->uninit_list = 0;
+ hevc->fatal_error = 0;
+ hevc->show_frame_num = 0;
+ hevc->frameinfo_enable = 1;
+#ifdef MULTI_INSTANCE_SUPPORT
+ hevc->platform_dev = pdev;
+ platform_set_drvdata(pdev, pdata);
+#endif
+
+ if (pdata == NULL) {
+ hevc_print(hevc, 0,
+ "\namvdec_h265 memory resource undefined.\n");
+ vfree(hevc);
+ mutex_unlock(&vh265_mutex);
+ return -EFAULT;
+ }
+ if (mmu_enable_force == 0) {
+ if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_GXL
+ || double_write_mode == 0x10)
+ hevc->mmu_enable = 0;
+ else
+ hevc->mmu_enable = 1;
+ }
+ if (init_mmu_buffers(hevc)) {
+ hevc_print(hevc, 0,
+ "\n 265 mmu init failed!\n");
+ vfree(hevc);
+ mutex_unlock(&vh265_mutex);
+ return -EFAULT;
+ }
+
+ ret = decoder_bmmu_box_alloc_buf_phy(hevc->bmmu_box, BMMU_WORKSPACE_ID,
+ work_buf_size, DRIVER_NAME, &hevc->buf_start);
+ if (ret < 0) {
+ uninit_mmu_buffers(hevc);
+ vfree(hevc);
+ mutex_unlock(&vh265_mutex);
+ return ret;
+ }
+ hevc->buf_size = work_buf_size;
+
+
+ if (!vdec_secure(pdata)) {
+ tmpbuf = (char *)codec_mm_phys_to_virt(hevc->buf_start);
+ if (tmpbuf) {
+ memset(tmpbuf, 0, work_buf_size);
+ dma_sync_single_for_device(amports_get_dma_device(),
+ hevc->buf_start,
+ work_buf_size, DMA_TO_DEVICE);
+ } else {
+ tmpbuf = codec_mm_vmap(hevc->buf_start,
+ work_buf_size);
+ if (tmpbuf) {
+ memset(tmpbuf, 0, work_buf_size);
+ dma_sync_single_for_device(
+ amports_get_dma_device(),
+ hevc->buf_start,
+ work_buf_size,
+ DMA_TO_DEVICE);
+ codec_mm_unmap_phyaddr(tmpbuf);
+ }
+ }
+ }
+
+ if (get_dbg_flag(hevc)) {
+ hevc_print(hevc, 0,
+ "===H.265 decoder mem resource 0x%lx size 0x%x\n",
+ hevc->buf_start, hevc->buf_size);
+ }
+
+ if (pdata->sys_info)
+ hevc->vh265_amstream_dec_info = *pdata->sys_info;
+ else {
+ hevc->vh265_amstream_dec_info.width = 0;
+ hevc->vh265_amstream_dec_info.height = 0;
+ hevc->vh265_amstream_dec_info.rate = 30;
+ }
+#ifndef MULTI_INSTANCE_SUPPORT
+ if (pdata->flag & DEC_FLAG_HEVC_WORKAROUND) {
+ workaround_enable |= 3;
+ hevc_print(hevc, 0,
+ "amvdec_h265 HEVC_WORKAROUND flag set.\n");
+ } else
+ workaround_enable &= ~3;
+#endif
+ hevc->cma_dev = pdata->cma_dev;
+ vh265_vdec_info_init(hevc);
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ pdata->private = hevc;
+ pdata->dec_status = vh265_dec_status;
+ pdata->set_trickmode = vh265_set_trickmode;
+ pdata->set_isreset = vh265_set_isreset;
+ is_reset = 0;
+ if (vh265_init(pdata) < 0) {
+#else
+ if (vh265_init(hevc) < 0) {
+#endif
+ hevc_print(hevc, 0,
+ "\namvdec_h265 init failed.\n");
+ hevc_local_uninit(hevc);
+ if (hevc->gvs)
+ kfree(hevc->gvs);
+ hevc->gvs = NULL;
+ uninit_mmu_buffers(hevc);
+ vfree(hevc);
+ pdata->dec_status = NULL;
+ mutex_unlock(&vh265_mutex);
+ return -ENODEV;
+ }
+ /*set the max clk for smooth playing...*/
+ hevc_source_changed(VFORMAT_HEVC,
+ 3840, 2160, 60);
+ mutex_unlock(&vh265_mutex);
+
+ return 0;
+}
+
+static int amvdec_h265_remove(struct platform_device *pdev)
+{
+ struct hevc_state_s *hevc = gHevc;
+
+ if (get_dbg_flag(hevc))
+ hevc_print(hevc, 0, "%s\r\n", __func__);
+
+ mutex_lock(&vh265_mutex);
+
+ vh265_stop(hevc);
+
+ hevc_source_changed(VFORMAT_HEVC, 0, 0, 0);
+
+
+#ifdef DEBUG_PTS
+ hevc_print(hevc, 0,
+ "pts missed %ld, pts hit %ld, duration %d\n",
+ hevc->pts_missed, hevc->pts_hit, hevc->frame_dur);
+#endif
+
+ vfree(hevc);
+ hevc = NULL;
+ gHevc = NULL;
+
+ mutex_unlock(&vh265_mutex);
+
+ return 0;
+}
+/****************************************/
+#ifdef CONFIG_PM
+static int h265_suspend(struct device *dev)
+{
+ amhevc_suspend(to_platform_device(dev), dev->power.power_state);
+ return 0;
+}
+
+static int h265_resume(struct device *dev)
+{
+ amhevc_resume(to_platform_device(dev));
+ return 0;
+}
+
+static const struct dev_pm_ops h265_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(h265_suspend, h265_resume)
+};
+#endif
+
+static struct platform_driver amvdec_h265_driver = {
+ .probe = amvdec_h265_probe,
+ .remove = amvdec_h265_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &h265_pm_ops,
+#endif
+ }
+};
+
+#ifdef MULTI_INSTANCE_SUPPORT
+static void vh265_dump_state(struct vdec_s *vdec)
+{
+ int i;
+ struct hevc_state_s *hevc =
+ (struct hevc_state_s *)vdec->private;
+ hevc_print(hevc, 0,
+ "====== %s\n", __func__);
+
+ hevc_print(hevc, 0,
+ "width/height (%d/%d), reorder_pic_num %d ip_mode %d buf count(bufspec size) %d, video_signal_type 0x%x, is_swap %d i_only 0x%x\n",
+ hevc->frame_width,
+ hevc->frame_height,
+ hevc->sps_num_reorder_pics_0,
+ hevc->ip_mode,
+ get_work_pic_num(hevc),
+ hevc->video_signal_type_debug,
+ hevc->is_swap,
+ hevc->i_only
+ );
+
+ hevc_print(hevc, 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),
+ hevc->eos,
+ hevc->dec_result,
+ decode_frame_count[hevc->index],
+ display_frame_count[hevc->index],
+ run_count[hevc->index],
+ not_run_ready[hevc->index],
+ input_empty[hevc->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);
+ hevc_print(hevc, 0,
+ "\nreceiver(%s) state %d\n",
+ vdec->vf_provider_name,
+ state);
+ }
+
+ hevc_print(hevc, 0,
+ "%s, newq(%d/%d), dispq(%d/%d), vf prepare/get/put (%d/%d/%d), pic_list_init_flag(%d), is_new_pic_available(%d)\n",
+ __func__,
+ kfifo_len(&hevc->newframe_q),
+ VF_POOL_SIZE,
+ kfifo_len(&hevc->display_q),
+ VF_POOL_SIZE,
+ hevc->vf_pre_count,
+ hevc->vf_get_count,
+ hevc->vf_put_count,
+ hevc->pic_list_init_flag,
+ is_new_pic_available(hevc)
+ );
+
+ dump_pic_list(hevc);
+
+ for (i = 0; i < BUF_POOL_SIZE; i++) {
+ hevc_print(hevc, 0,
+ "Buf(%d) start_adr 0x%lx size 0x%x used %d\n",
+ i,
+ hevc->m_BUF[i].start_adr,
+ hevc->m_BUF[i].size,
+ hevc->m_BUF[i].used_flag);
+ }
+
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ hevc_print(hevc, 0,
+ "mv_Buf(%d) start_adr 0x%lx size 0x%x used %d\n",
+ i,
+ hevc->m_mv_BUF[i].start_adr,
+ hevc->m_mv_BUF[i].size,
+ hevc->m_mv_BUF[i].used_flag);
+ }
+
+ hevc_print(hevc, 0,
+ "HEVC_DEC_STATUS_REG=0x%x\n",
+ READ_VREG(HEVC_DEC_STATUS_REG));
+ hevc_print(hevc, 0,
+ "HEVC_MPC_E=0x%x\n",
+ READ_VREG(HEVC_MPC_E));
+ hevc_print(hevc, 0,
+ "HEVC_DECODE_MODE=0x%x\n",
+ READ_VREG(HEVC_DECODE_MODE));
+ hevc_print(hevc, 0,
+ "HEVC_DECODE_MODE2=0x%x\n",
+ READ_VREG(HEVC_DECODE_MODE2));
+ hevc_print(hevc, 0,
+ "NAL_SEARCH_CTL=0x%x\n",
+ READ_VREG(NAL_SEARCH_CTL));
+ hevc_print(hevc, 0,
+ "HEVC_PARSER_LCU_START=0x%x\n",
+ READ_VREG(HEVC_PARSER_LCU_START));
+ hevc_print(hevc, 0,
+ "HEVC_DECODE_SIZE=0x%x\n",
+ READ_VREG(HEVC_DECODE_SIZE));
+ hevc_print(hevc, 0,
+ "HEVC_SHIFT_BYTE_COUNT=0x%x\n",
+ READ_VREG(HEVC_SHIFT_BYTE_COUNT));
+ hevc_print(hevc, 0,
+ "HEVC_STREAM_START_ADDR=0x%x\n",
+ READ_VREG(HEVC_STREAM_START_ADDR));
+ hevc_print(hevc, 0,
+ "HEVC_STREAM_END_ADDR=0x%x\n",
+ READ_VREG(HEVC_STREAM_END_ADDR));
+ hevc_print(hevc, 0,
+ "HEVC_STREAM_LEVEL=0x%x\n",
+ READ_VREG(HEVC_STREAM_LEVEL));
+ hevc_print(hevc, 0,
+ "HEVC_STREAM_WR_PTR=0x%x\n",
+ READ_VREG(HEVC_STREAM_WR_PTR));
+ hevc_print(hevc, 0,
+ "HEVC_STREAM_RD_PTR=0x%x\n",
+ READ_VREG(HEVC_STREAM_RD_PTR));
+ hevc_print(hevc, 0,
+ "PARSER_VIDEO_RP=0x%x\n",
+ STBUF_READ(&vdec->vbuf, get_rp));
+ hevc_print(hevc, 0,
+ "PARSER_VIDEO_WP=0x%x\n",
+ STBUF_READ(&vdec->vbuf, get_wp));
+
+ if (input_frame_based(vdec) &&
+ (get_dbg_flag(hevc) & PRINT_FRAMEBASE_DATA)
+ ) {
+ int jj;
+ if (hevc->chunk && hevc->chunk->block &&
+ hevc->chunk->size > 0) {
+ u8 *data = NULL;
+ if (!hevc->chunk->block->is_mapped)
+ data = codec_mm_vmap(hevc->chunk->block->start +
+ hevc->chunk->offset, hevc->chunk->size);
+ else
+ data = ((u8 *)hevc->chunk->block->start_virt)
+ + hevc->chunk->offset;
+ hevc_print(hevc, 0,
+ "frame data size 0x%x\n",
+ hevc->chunk->size);
+ for (jj = 0; jj < hevc->chunk->size; jj++) {
+ if ((jj & 0xf) == 0)
+ hevc_print(hevc,
+ PRINT_FRAMEBASE_DATA,
+ "%06x:", jj);
+ hevc_print_cont(hevc,
+ PRINT_FRAMEBASE_DATA,
+ "%02x ", data[jj]);
+ if (((jj + 1) & 0xf) == 0)
+ hevc_print_cont(hevc,
+ PRINT_FRAMEBASE_DATA,
+ "\n");
+ }
+
+ if (!hevc->chunk->block->is_mapped)
+ codec_mm_unmap_phyaddr(data);
+ }
+ }
+
+}
+
+
+static int ammvdec_h265_probe(struct platform_device *pdev)
+{
+
+ struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
+ struct hevc_state_s *hevc = NULL;
+ int ret;
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ int config_val;
+#endif
+ //pr_err("[%s pid=%d tgid=%d] \n",__func__, current->pid, current->tgid);
+ if (pdata == NULL) {
+ pr_info("\nammvdec_h265 memory resource undefined.\n");
+ return -EFAULT;
+ }
+
+ /* hevc = (struct hevc_state_s *)devm_kzalloc(&pdev->dev,
+ sizeof(struct hevc_state_s), GFP_KERNEL); */
+ hevc = vmalloc(sizeof(struct hevc_state_s));
+ if (hevc == NULL) {
+ pr_info("\nammvdec_h265 device data allocation failed\n");
+ return -ENOMEM;
+ }
+ memset(hevc, 0, sizeof(struct hevc_state_s));
+
+ /* the ctx from v4l2 driver. */
+ hevc->v4l2_ctx = pdata->private;
+
+ pdata->private = hevc;
+ pdata->dec_status = vh265_dec_status;
+ pdata->set_trickmode = vh265_set_trickmode;
+ pdata->run_ready = run_ready;
+ pdata->run = run;
+ pdata->reset = reset;
+ pdata->irq_handler = vh265_irq_cb;
+ pdata->threaded_irq_handler = vh265_threaded_irq_cb;
+ pdata->dump_state = vh265_dump_state;
+#ifdef VDEC_FCC_SUPPORT
+ pdata->wakeup_fcc_poll = vh265_wakeup_fcc_poll;
+#endif
+ hevc->index = pdev->id;
+ hevc->m_ins_flag = 1;
+
+ snprintf(hevc->vdec_name, sizeof(hevc->vdec_name),
+ "h265-%d", hevc->index);
+ snprintf(hevc->pts_name, sizeof(hevc->pts_name),
+ "%s-pts", hevc->vdec_name);
+ snprintf(hevc->vf_get_name, sizeof(hevc->vf_get_name),
+ "%s-vf_get", hevc->vdec_name);
+ snprintf(hevc->vf_put_name, sizeof(hevc->vf_put_name),
+ "%s-vf_put", hevc->vdec_name);
+ snprintf(hevc->set_canvas0_addr, sizeof(hevc->set_canvas0_addr),
+ "%s-set_canvas0_addr", hevc->vdec_name);
+ snprintf(hevc->get_canvas0_addr, sizeof(hevc->get_canvas0_addr),
+ "%s-get_canvas0_addr", hevc->vdec_name);
+ snprintf(hevc->put_canvas0_addr, sizeof(hevc->put_canvas0_addr),
+ "%s-put_canvas0_addr", hevc->vdec_name);
+ snprintf(hevc->new_q_name, sizeof(hevc->new_q_name),
+ "%s-newframe_q", hevc->vdec_name);
+ snprintf(hevc->disp_q_name, sizeof(hevc->disp_q_name),
+ "%s-dispframe_q", hevc->vdec_name);
+
+ if (pdata->use_vfm_path) {
+ snprintf(pdata->vf_provider_name,
+ VDEC_PROVIDER_NAME_SIZE,
+ VFM_DEC_PROVIDER_NAME);
+ hevc->frameinfo_enable = 1;
+ }
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ else if (vdec_dual(pdata)) {
+ struct hevc_state_s *hevc_pair = NULL;
+
+ if (dv_toggle_prov_name) /*debug purpose*/
+ snprintf(pdata->vf_provider_name,
+ VDEC_PROVIDER_NAME_SIZE,
+ (pdata->master) ? VFM_DEC_DVBL_PROVIDER_NAME :
+ VFM_DEC_DVEL_PROVIDER_NAME);
+ else
+ snprintf(pdata->vf_provider_name,
+ VDEC_PROVIDER_NAME_SIZE,
+ (pdata->master) ? VFM_DEC_DVEL_PROVIDER_NAME :
+ VFM_DEC_DVBL_PROVIDER_NAME);
+ hevc->dolby_enhance_flag = pdata->master ? 1 : 0;
+ if (pdata->master)
+ hevc_pair = (struct hevc_state_s *)
+ pdata->master->private;
+ else if (pdata->slave)
+ hevc_pair = (struct hevc_state_s *)
+ pdata->slave->private;
+ if (hevc_pair)
+ hevc->shift_byte_count_lo =
+ hevc_pair->shift_byte_count_lo;
+ }
+#endif
+ else
+ snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE,
+ MULTI_INSTANCE_PROVIDER_NAME ".%02x", pdev->id & 0xff);
+
+ vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name,
+ &vh265_vf_provider, pdata);
+
+ hevc->provider_name = pdata->vf_provider_name;
+ platform_set_drvdata(pdev, pdata);
+
+ hevc->platform_dev = pdev;
+
+ if (((get_dbg_flag(hevc) & IGNORE_PARAM_FROM_CONFIG) == 0) &&
+ pdata->config && pdata->config_len) {
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ /*use ptr config for doubel_write_mode, etc*/
+ hevc_print(hevc, 0, "pdata->config=%s\n", pdata->config);
+
+ if (get_config_int(pdata->config, "hevc_double_write_mode",
+ &config_val) == 0)
+ hevc->double_write_mode = config_val;
+ else
+ hevc->double_write_mode = double_write_mode;
+
+ if (get_config_int(pdata->config, "save_buffer_mode",
+ &config_val) == 0)
+ hevc->save_buffer_mode = config_val;
+ else
+ hevc->save_buffer_mode = 0;
+
+ /*use ptr config for max_pic_w, etc*/
+ if (get_config_int(pdata->config, "hevc_buf_width",
+ &config_val) == 0) {
+ hevc->max_pic_w = config_val;
+ }
+ if (get_config_int(pdata->config, "hevc_buf_height",
+ &config_val) == 0) {
+ hevc->max_pic_h = config_val;
+ }
+ if (get_config_int(pdata->config, "sidebind_type",
+ &config_val) == 0)
+ hevc->sidebind_type = config_val;
+
+ if (get_config_int(pdata->config, "sidebind_channel_id",
+ &config_val) == 0)
+ hevc->sidebind_channel_id = config_val;
+
+ if (get_config_int(pdata->config,
+ "parm_v4l_codec_enable",
+ &config_val) == 0)
+ hevc->is_used_v4l = config_val;
+
+ if (get_config_int(pdata->config,
+ "parm_v4l_buffer_margin",
+ &config_val) == 0)
+ hevc->dynamic_buf_num_margin = config_val;
+
+ if (get_config_int(pdata->config,
+ "parm_v4l_canvas_mem_mode",
+ &config_val) == 0)
+ hevc->mem_map_mode = config_val;
+
+ if (get_config_int(pdata->config, "dv_duallayer",
+ &config_val) == 0)
+ hevc->dv_duallayer = config_val;
+ else
+ hevc->dv_duallayer = false;
+
+ if (get_config_int(pdata->config, "negative_dv",
+ &config_val) == 0) {
+ hevc->discard_dv_data = config_val;
+ hevc_print(hevc, 0, "discard dv data\n");
+ }
+
+ if (get_config_int(pdata->config,
+ "parm_enable_fence",
+ &config_val) == 0)
+ hevc->enable_fence = config_val;
+
+ if (get_config_int(pdata->config,
+ "parm_fence_usage",
+ &config_val) == 0)
+ hevc->fence_usage = config_val;
+
+ if (get_config_int(pdata->config,
+ "parm_v4l_low_latency_mode",
+ &config_val) == 0)
+ hevc->low_latency_flag = config_val;
+
+#endif
+ } else {
+ if (pdata->sys_info)
+ hevc->vh265_amstream_dec_info = *pdata->sys_info;
+ else {
+ hevc->vh265_amstream_dec_info.width = 0;
+ hevc->vh265_amstream_dec_info.height = 0;
+ hevc->vh265_amstream_dec_info.rate = 30;
+ }
+ hevc->double_write_mode = double_write_mode;
+ }
+ /* get valid double write from configure or node */
+ //hevc->double_write_mode = get_double_write_mode(hevc);
+
+ if (force_config_fence) {
+ hevc->enable_fence = true;
+ hevc->fence_usage = (force_config_fence >> 4) & 0xf;
+ if (force_config_fence & 0x2)
+ hevc->enable_fence = false;
+ hevc_print(hevc, 0,
+ "enable fence: %d, fence usage: %d\n",
+ hevc->enable_fence, hevc->fence_usage);
+ }
+
+ if (hevc->enable_fence)
+ pdata->sync.usage = hevc->fence_usage;
+
+ if ((get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T5) &&
+ (hevc->double_write_mode == 3))
+ hevc->double_write_mode = 0x1000;
+
+ if (!hevc->is_used_v4l) {
+ /* get valid double write from configure or node */
+ //hevc->double_write_mode = get_double_write_mode(hevc);
+ if (hevc->save_buffer_mode && dynamic_buf_num_margin > 2)
+ hevc->dynamic_buf_num_margin = dynamic_buf_num_margin -2;
+ else
+ hevc->dynamic_buf_num_margin = dynamic_buf_num_margin;
+ hevc->mem_map_mode = mem_map_mode;
+ }
+
+ if (mmu_enable_force == 0) {
+ if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_GXL)
+ hevc->mmu_enable = 0;
+ else
+ hevc->mmu_enable = 1;
+ }
+
+ if (init_mmu_buffers(hevc) < 0) {
+ hevc_print(hevc, 0,
+ "\n 265 mmu init failed!\n");
+ mutex_unlock(&vh265_mutex);
+ /* devm_kfree(&pdev->dev, (void *)hevc);*/
+ if (hevc)
+ vfree((void *)hevc);
+ pdata->dec_status = NULL;
+ return -EFAULT;
+ }
+#if 0
+ hevc->buf_start = pdata->mem_start;
+ hevc->buf_size = pdata->mem_end - pdata->mem_start + 1;
+#else
+
+ ret = decoder_bmmu_box_alloc_buf_phy(hevc->bmmu_box,
+ BMMU_WORKSPACE_ID, work_buf_size,
+ DRIVER_NAME, &hevc->buf_start);
+ if (ret < 0) {
+ uninit_mmu_buffers(hevc);
+ /* devm_kfree(&pdev->dev, (void *)hevc); */
+ if (hevc)
+ vfree((void *)hevc);
+ pdata->dec_status = NULL;
+ mutex_unlock(&vh265_mutex);
+ return ret;
+ }
+ hevc->buf_size = work_buf_size;
+#endif
+ if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXTVBB) &&
+ (parser_sei_enable & 0x100) == 0)
+ parser_sei_enable = 7;
+ hevc->init_flag = 0;
+ hevc->first_sc_checked = 0;
+ hevc->uninit_list = 0;
+ hevc->fatal_error = 0;
+ hevc->show_frame_num = 0;
+
+ /*
+ *hevc->mc_buf_spec.buf_end = pdata->mem_end + 1;
+ *for (i = 0; i < WORK_BUF_SPEC_NUM; i++)
+ * amvh265_workbuff_spec[i].start_adr = pdata->mem_start;
+ */
+ if (get_dbg_flag(hevc)) {
+ hevc_print(hevc, 0,
+ "===H.265 decoder mem resource 0x%lx size 0x%x\n",
+ hevc->buf_start, hevc->buf_size);
+ }
+
+ hevc_print(hevc, 0,
+ "dynamic_buf_num_margin=%d\n",
+ hevc->dynamic_buf_num_margin);
+ hevc_print(hevc, 0,
+ "double_write_mode=%d\n",
+ hevc->double_write_mode);
+
+ hevc->cma_dev = pdata->cma_dev;
+ vh265_vdec_info_init(hevc);
+
+ if (vh265_init(pdata) < 0) {
+ hevc_print(hevc, 0,
+ "\namvdec_h265 init failed.\n");
+ hevc_local_uninit(hevc);
+ if (hevc->gvs)
+ kfree(hevc->gvs);
+ hevc->gvs = NULL;
+ uninit_mmu_buffers(hevc);
+ /* devm_kfree(&pdev->dev, (void *)hevc); */
+ if (hevc)
+ vfree((void *)hevc);
+ pdata->dec_status = NULL;
+ return -ENODEV;
+ }
+
+#ifdef AUX_DATA_CRC
+ vdec_aux_data_check_init(pdata);
+#endif
+
+ vdec_set_prepare_level(pdata, start_decode_buf_level);
+
+ /*set the max clk for smooth playing...*/
+ hevc_source_changed(VFORMAT_HEVC,
+ 3840, 2160, 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);
+
+ if (hevc->enable_fence) {
+ /* creat timeline. */
+ vdec_timeline_create(&pdata->sync, DRIVER_NAME);
+ }
+
+ return 0;
+}
+
+static void vdec_fence_release(struct hevc_state_s *hw,
+ struct vdec_sync *sync)
+{
+ ulong expires;
+ int i;
+
+ /* 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;
+ }
+ }
+
+ for (i = 0; i < VF_POOL_SIZE; i++) {
+ struct vframe_s *vf = &hw->vfpool[i];
+
+ if (vf->fence) {
+ vdec_fence_put(vf->fence);
+ vf->fence = NULL;
+ }
+ }
+
+ /* decreases refcnt of timeline. */
+ vdec_timeline_put(sync);
+}
+
+static int ammvdec_h265_remove(struct platform_device *pdev)
+{
+ struct hevc_state_s *hevc =
+ (struct hevc_state_s *)
+ (((struct vdec_s *)(platform_get_drvdata(pdev)))->private);
+ struct vdec_s *vdec;
+
+ if (hevc == NULL)
+ return 0;
+ vdec = hw_to_vdec(hevc);
+
+#ifdef AUX_DATA_CRC
+ vdec_aux_data_check_exit(vdec);
+#endif
+
+ //pr_err("%s [pid=%d,tgid=%d]\n", __func__, current->pid, current->tgid);
+ if (get_dbg_flag(hevc))
+ hevc_print(hevc, 0, "%s\r\n", __func__);
+
+ vmh265_stop(hevc);
+
+ /* vdec_source_changed(VFORMAT_H264, 0, 0, 0); */
+ if (vdec->parallel_dec == 1)
+ vdec_core_release(hw_to_vdec(hevc), CORE_MASK_HEVC);
+ else
+ vdec_core_release(hw_to_vdec(hevc), CORE_MASK_HEVC);
+
+ vdec_set_status(hw_to_vdec(hevc), VDEC_STATUS_DISCONNECTED);
+
+ if (hevc->enable_fence)
+ vdec_fence_release(hevc, &vdec->sync);
+
+ vfree((void *)hevc);
+
+ return 0;
+}
+
+static struct platform_driver ammvdec_h265_driver = {
+ .probe = ammvdec_h265_probe,
+ .remove = ammvdec_h265_remove,
+ .driver = {
+ .name = MULTI_DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &h265_pm_ops,
+#endif
+ }
+};
+#endif
+
+static struct codec_profile_t amvdec_h265_profile = {
+ .name = "hevc",
+ .profile = ""
+};
+
+static struct codec_profile_t amvdec_h265_profile_single,
+ amvdec_h265_profile_mult;
+
+static struct mconfig h265_configs[] = {
+ MC_PU32("use_cma", &use_cma),
+ MC_PU32("bit_depth_luma", &bit_depth_luma),
+ MC_PU32("bit_depth_chroma", &bit_depth_chroma),
+ MC_PU32("video_signal_type", &video_signal_type),
+#ifdef ERROR_HANDLE_DEBUG
+ MC_PU32("dbg_nal_skip_flag", &dbg_nal_skip_flag),
+ MC_PU32("dbg_nal_skip_count", &dbg_nal_skip_count),
+#endif
+ MC_PU32("radr", &radr),
+ MC_PU32("rval", &rval),
+ 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("nal_skip_policy", &nal_skip_policy),
+ MC_PU32("i_only_flag", &i_only_flag),
+ MC_PU32("error_handle_policy", &error_handle_policy),
+ MC_PU32("error_handle_threshold", &error_handle_threshold),
+ MC_PU32("error_handle_nal_skip_threshold",
+ &error_handle_nal_skip_threshold),
+ MC_PU32("error_handle_system_threshold",
+ &error_handle_system_threshold),
+ MC_PU32("error_skip_nal_count", &error_skip_nal_count),
+ MC_PU32("debug", &debug),
+ MC_PU32("debug_mask", &debug_mask),
+ MC_PU32("buffer_mode", &buffer_mode),
+ MC_PU32("double_write_mode", &double_write_mode),
+ MC_PU32("buf_alloc_width", &buf_alloc_width),
+ MC_PU32("buf_alloc_height", &buf_alloc_height),
+ MC_PU32("dynamic_buf_num_margin", &dynamic_buf_num_margin),
+ MC_PU32("max_buf_num", &max_buf_num),
+ MC_PU32("buf_alloc_size", &buf_alloc_size),
+ MC_PU32("buffer_mode_dbg", &buffer_mode_dbg),
+ MC_PU32("mem_map_mode", &mem_map_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("prefix_aux_buf_size", &prefix_aux_buf_size),
+ MC_PU32("suffix_aux_buf_size", &suffix_aux_buf_size),
+ MC_PU32("interlace_enable", &interlace_enable),
+ MC_PU32("pts_unstable", &pts_unstable),
+ MC_PU32("parser_sei_enable", &parser_sei_enable),
+ MC_PU32("start_decode_buf_level", &start_decode_buf_level),
+ MC_PU32("decode_timeout_val", &decode_timeout_val),
+ MC_PU32("parser_dolby_vision_enable", &parser_dolby_vision_enable),
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ MC_PU32("dv_toggle_prov_name", &dv_toggle_prov_name),
+ MC_PU32("dv_debug", &dv_debug),
+#endif
+};
+static struct mconfig_node decoder_265_node;
+
+static int __init amvdec_h265_driver_init_module(void)
+{
+ struct BuffInfo_s *p_buf_info;
+
+ if (vdec_is_support_4k()) {
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1)
+ p_buf_info = &amvh265_workbuff_spec[2];
+ else
+ p_buf_info = &amvh265_workbuff_spec[1];
+ } else
+ p_buf_info = &amvh265_workbuff_spec[0];
+
+ init_buff_spec(NULL, p_buf_info);
+ work_buf_size =
+ (p_buf_info->end_adr - p_buf_info->start_adr
+ + 0xffff) & (~0xffff);
+
+ pr_debug("amvdec_h265 module init\n");
+ error_handle_policy = 0;
+
+#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;
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (platform_driver_register(&ammvdec_h265_driver))
+ pr_err("failed to register ammvdec_h265 driver\n");
+
+#endif
+ if (platform_driver_register(&amvdec_h265_driver)) {
+ pr_err("failed to register amvdec_h265 driver\n");
+ return -ENODEV;
+ }
+#if 1/*MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8*/
+ if (!has_hevc_vdec()) {
+ /* not support hevc */
+ amvdec_h265_profile.name = "hevc_unsupport";
+ }
+ if (vdec_is_support_4k()) {
+ if (is_meson_m8m2_cpu()) {
+ /* m8m2 support 4k */
+ amvdec_h265_profile.profile = "4k";
+ } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) {
+ amvdec_h265_profile.profile =
+ "8k, 8bit, 10bit, dwrite, compressed, frame_dv, fence";
+ }else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXBB) {
+ amvdec_h265_profile.profile =
+ "4k, 8bit, 10bit, dwrite, compressed, frame_dv, fence";
+ } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_MG9TV)
+ amvdec_h265_profile.profile = "4k";
+ }
+#endif
+ if (codec_mm_get_total_size() < 80 * SZ_1M) {
+ pr_info("amvdec_h265 default mmu enabled.\n");
+ mmu_enable = 1;
+ }
+
+ vcodec_profile_register(&amvdec_h265_profile);
+ amvdec_h265_profile_single = amvdec_h265_profile;
+ amvdec_h265_profile_single.name = "h265";
+ vcodec_profile_register(&amvdec_h265_profile_single);
+ amvdec_h265_profile_mult = amvdec_h265_profile;
+ amvdec_h265_profile_mult.name = "mh265";
+ vcodec_profile_register(&amvdec_h265_profile_mult);
+ INIT_REG_NODE_CONFIGS("media.decoder", &decoder_265_node,
+ "h265", h265_configs, CONFIG_FOR_RW);
+ return 0;
+}
+
+static void __exit amvdec_h265_driver_remove_module(void)
+{
+ pr_debug("amvdec_h265 module remove.\n");
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ platform_driver_unregister(&ammvdec_h265_driver);
+#endif
+ platform_driver_unregister(&amvdec_h265_driver);
+}
+
+/****************************************/
+/*
+ *module_param(stat, uint, 0664);
+ *MODULE_PARM_DESC(stat, "\n amvdec_h265 stat\n");
+ */
+module_param(use_cma, uint, 0664);
+MODULE_PARM_DESC(use_cma, "\n amvdec_h265 use_cma\n");
+
+module_param(bit_depth_luma, uint, 0664);
+MODULE_PARM_DESC(bit_depth_luma, "\n amvdec_h265 bit_depth_luma\n");
+
+module_param(bit_depth_chroma, uint, 0664);
+MODULE_PARM_DESC(bit_depth_chroma, "\n amvdec_h265 bit_depth_chroma\n");
+
+module_param(video_signal_type, uint, 0664);
+MODULE_PARM_DESC(video_signal_type, "\n amvdec_h265 video_signal_type\n");
+
+#ifdef ERROR_HANDLE_DEBUG
+module_param(dbg_nal_skip_flag, uint, 0664);
+MODULE_PARM_DESC(dbg_nal_skip_flag, "\n amvdec_h265 dbg_nal_skip_flag\n");
+
+module_param(dbg_nal_skip_count, uint, 0664);
+MODULE_PARM_DESC(dbg_nal_skip_count, "\n amvdec_h265 dbg_nal_skip_count\n");
+#endif
+
+module_param(radr, uint, 0664);
+MODULE_PARM_DESC(radr, "\n radr\n");
+
+module_param(rval, uint, 0664);
+MODULE_PARM_DESC(rval, "\n rval\n");
+
+module_param(dbg_cmd, uint, 0664);
+MODULE_PARM_DESC(dbg_cmd, "\n dbg_cmd\n");
+
+module_param(dump_nal, uint, 0664);
+MODULE_PARM_DESC(dump_nal, "\n dump_nal\n");
+
+module_param(dbg_skip_decode_index, uint, 0664);
+MODULE_PARM_DESC(dbg_skip_decode_index, "\n dbg_skip_decode_index\n");
+
+module_param(endian, uint, 0664);
+MODULE_PARM_DESC(endian, "\n rval\n");
+
+module_param(step, uint, 0664);
+MODULE_PARM_DESC(step, "\n amvdec_h265 step\n");
+
+module_param(decode_pic_begin, uint, 0664);
+MODULE_PARM_DESC(decode_pic_begin, "\n amvdec_h265 decode_pic_begin\n");
+
+module_param(slice_parse_begin, uint, 0664);
+MODULE_PARM_DESC(slice_parse_begin, "\n amvdec_h265 slice_parse_begin\n");
+
+module_param(nal_skip_policy, uint, 0664);
+MODULE_PARM_DESC(nal_skip_policy, "\n amvdec_h265 nal_skip_policy\n");
+
+module_param(i_only_flag, uint, 0664);
+MODULE_PARM_DESC(i_only_flag, "\n amvdec_h265 i_only_flag\n");
+
+module_param(fast_output_enable, uint, 0664);
+MODULE_PARM_DESC(fast_output_enable, "\n amvdec_h265 fast_output_enable\n");
+
+module_param(error_handle_policy, uint, 0664);
+MODULE_PARM_DESC(error_handle_policy, "\n amvdec_h265 error_handle_policy\n");
+
+module_param(error_handle_threshold, uint, 0664);
+MODULE_PARM_DESC(error_handle_threshold,
+ "\n amvdec_h265 error_handle_threshold\n");
+
+module_param(error_handle_nal_skip_threshold, uint, 0664);
+MODULE_PARM_DESC(error_handle_nal_skip_threshold,
+ "\n amvdec_h265 error_handle_nal_skip_threshold\n");
+
+module_param(error_handle_system_threshold, uint, 0664);
+MODULE_PARM_DESC(error_handle_system_threshold,
+ "\n amvdec_h265 error_handle_system_threshold\n");
+
+module_param(error_skip_nal_count, uint, 0664);
+MODULE_PARM_DESC(error_skip_nal_count,
+ "\n amvdec_h265 error_skip_nal_count\n");
+
+module_param(skip_nal_count, uint, 0664);
+MODULE_PARM_DESC(skip_nal_count, "\n skip_nal_count\n");
+
+module_param(debug, uint, 0664);
+MODULE_PARM_DESC(debug, "\n amvdec_h265 debug\n");
+
+module_param(debug_mask, uint, 0664);
+MODULE_PARM_DESC(debug_mask, "\n amvdec_h265 debug mask\n");
+
+module_param(log_mask, uint, 0664);
+MODULE_PARM_DESC(log_mask, "\n amvdec_h265 log_mask\n");
+
+module_param(buffer_mode, uint, 0664);
+MODULE_PARM_DESC(buffer_mode, "\n buffer_mode\n");
+
+module_param(double_write_mode, uint, 0664);
+MODULE_PARM_DESC(double_write_mode, "\n double_write_mode\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(dynamic_buf_num_margin, uint, 0664);
+MODULE_PARM_DESC(dynamic_buf_num_margin, "\n dynamic_buf_num_margin\n");
+
+module_param(max_buf_num, uint, 0664);
+MODULE_PARM_DESC(max_buf_num, "\n max_buf_num\n");
+
+module_param(buf_alloc_size, uint, 0664);
+MODULE_PARM_DESC(buf_alloc_size, "\n buf_alloc_size\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
+
+#if 0
+module_param(re_config_pic_flag, uint, 0664);
+MODULE_PARM_DESC(re_config_pic_flag, "\n re_config_pic_flag\n");
+#endif
+
+module_param(buffer_mode_dbg, uint, 0664);
+MODULE_PARM_DESC(buffer_mode_dbg, "\n buffer_mode_dbg\n");
+
+module_param(mem_map_mode, uint, 0664);
+MODULE_PARM_DESC(mem_map_mode, "\n mem_map_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(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");
+
+module_param(interlace_enable, uint, 0664);
+MODULE_PARM_DESC(interlace_enable, "\n interlace_enable\n");
+module_param(pts_unstable, uint, 0664);
+MODULE_PARM_DESC(pts_unstable, "\n amvdec_h265 pts_unstable\n");
+module_param(parser_sei_enable, uint, 0664);
+MODULE_PARM_DESC(parser_sei_enable, "\n parser_sei_enable\n");
+
+module_param(parser_dolby_vision_enable, uint, 0664);
+MODULE_PARM_DESC(parser_dolby_vision_enable,
+ "\n parser_dolby_vision_enable\n");
+
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+module_param(dolby_meta_with_el, uint, 0664);
+MODULE_PARM_DESC(dolby_meta_with_el,
+ "\n dolby_meta_with_el\n");
+
+module_param(dolby_el_flush_th, uint, 0664);
+MODULE_PARM_DESC(dolby_el_flush_th,
+ "\n dolby_el_flush_th\n");
+#endif
+module_param(mmu_enable, uint, 0664);
+MODULE_PARM_DESC(mmu_enable, "\n mmu_enable\n");
+
+module_param(mmu_enable_force, uint, 0664);
+MODULE_PARM_DESC(mmu_enable_force, "\n mmu_enable_force\n");
+
+#ifdef MULTI_INSTANCE_SUPPORT
+module_param(start_decode_buf_level, int, 0664);
+MODULE_PARM_DESC(start_decode_buf_level,
+ "\n h265 start_decode_buf_level\n");
+
+module_param(decode_timeout_val, uint, 0664);
+MODULE_PARM_DESC(decode_timeout_val,
+ "\n h265 decode_timeout_val\n");
+
+module_param(print_lcu_error, uint, 0664);
+MODULE_PARM_DESC(print_lcu_error,
+ "\n h265 print_lcu_error\n");
+
+module_param(data_resend_policy, uint, 0664);
+MODULE_PARM_DESC(data_resend_policy,
+ "\n h265 data_resend_policy\n");
+
+module_param(poc_num_margin, int, 0664);
+MODULE_PARM_DESC(poc_num_margin,
+ "\n h265 poc_num_margin\n");
+
+module_param(poc_error_limit, int, 0664);
+MODULE_PARM_DESC(poc_error_limit,
+ "\n h265 poc_error_limit\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(max_get_frame_interval,
+ 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_array(ref_frame_mark_flag, uint,
+ &max_decode_instance_num, 0664);
+
+#endif
+#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(dv_debug, uint, 0664);
+MODULE_PARM_DESC(dv_debug, "\n dv_debug\n");
+
+module_param(force_bypass_dvenl, uint, 0664);
+MODULE_PARM_DESC(force_bypass_dvenl, "\n force_bypass_dvenl\n");
+#endif
+
+#ifdef AGAIN_HAS_THRESHOLD
+module_param(again_threshold, uint, 0664);
+MODULE_PARM_DESC(again_threshold, "\n again_threshold\n");
+#endif
+
+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(frmbase_cont_bitlevel, uint, 0664);
+MODULE_PARM_DESC(frmbase_cont_bitlevel, "\n frmbase_cont_bitlevel\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(pre_decode_buf_level, int, 0664);
+MODULE_PARM_DESC(pre_decode_buf_level, "\n ammvdec_h264 pre_decode_buf_level\n");
+
+module_param(udebug_pause_decode_idx, uint, 0664);
+MODULE_PARM_DESC(udebug_pause_decode_idx, "\n udebug_pause_decode_idx\n");
+
+module_param(disp_vframe_valve_level, uint, 0664);
+MODULE_PARM_DESC(disp_vframe_valve_level, "\n disp_vframe_valve_level\n");
+
+module_param(pic_list_debug, uint, 0664);
+MODULE_PARM_DESC(pic_list_debug, "\n pic_list_debug\n");
+
+module_param(without_display_mode, uint, 0664);
+MODULE_PARM_DESC(without_display_mode, "\n amvdec_h265 without_display_mode\n");
+
+#ifdef HEVC_8K_LFTOFFSET_FIX
+module_param(performance_profile, uint, 0664);
+MODULE_PARM_DESC(performance_profile, "\n amvdec_h265 performance_profile\n");
+#endif
+module_param(disable_ip_mode, uint, 0664);
+MODULE_PARM_DESC(disable_ip_mode, "\n amvdec_h265 disable ip_mode\n");
+
+module_param(dirty_again_threshold, uint, 0664);
+MODULE_PARM_DESC(dirty_again_threshold, "\n dirty_again_threshold\n");
+
+module_param(dirty_buffersize_threshold, uint, 0664);
+MODULE_PARM_DESC(dirty_buffersize_threshold, "\n dirty_buffersize_threshold\n");
+
+module_param(force_config_fence, uint, 0664);
+MODULE_PARM_DESC(force_config_fence, "\n force enable fence\n");
+
+module_param(mv_buf_dynamic_alloc, uint, 0664);
+MODULE_PARM_DESC(mv_buf_dynamic_alloc, "\n mv_buf_dynamic_alloc\n");
+
+module_param(detect_stuck_buffer_margin, uint, 0664);
+MODULE_PARM_DESC(detect_stuck_buffer_margin, "\n detect_stuck_buffer_margin\n");
+
+module_init(amvdec_h265_driver_init_module);
+module_exit(amvdec_h265_driver_remove_module);
+
+MODULE_DESCRIPTION("AMLOGIC h265 Video Decoder Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tim Yao <tim.yao@amlogic.com>");
diff --git a/drivers/frame_provider/decoder/h265/vh265.h b/drivers/frame_provider/decoder/h265/vh265.h
new file mode 100644
index 0000000..11de11a
--- /dev/null
+++ b/drivers/frame_provider/decoder/h265/vh265.h
@@ -0,0 +1,27 @@
+/*
+ * drivers/amlogic/amports/vh265.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 VH265_H
+#define VH265_H
+
+extern u32 get_blackout_policy(void);
+
+extern s32 vh265_init(void);
+
+extern s32 vh265_release(void);
+
+#endif /* VMPEG4_H */
diff --git a/drivers/frame_provider/decoder/mjpeg/Makefile b/drivers/frame_provider/decoder/mjpeg/Makefile
new file mode 100644
index 0000000..ab91854
--- /dev/null
+++ b/drivers/frame_provider/decoder/mjpeg/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_MJPEG) += amvdec_mjpeg.o
+amvdec_mjpeg-objs += vmjpeg.o
+
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_MJPEG_MULTI) += amvdec_mmjpeg.o
+amvdec_mmjpeg-objs += vmjpeg_multi.o
diff --git a/drivers/frame_provider/decoder/mjpeg/vmjpeg.c b/drivers/frame_provider/decoder/mjpeg/vmjpeg.c
new file mode 100644
index 0000000..6b87d4a
--- /dev/null
+++ b/drivers/frame_provider/decoder/mjpeg/vmjpeg.c
@@ -0,0 +1,984 @@
+/*
+ * drivers/amlogic/amports/vmjpeg.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/kfifo.h>
+#include <linux/platform_device.h>
+#include <linux/amlogic/media/frame_sync/ptsserv.h>
+#include <linux/amlogic/media/utils/amstream.h>
+#include <linux/amlogic/media/canvas/canvas.h>
+#include <linux/amlogic/media/vfm/vframe.h>
+#include <linux/amlogic/media/vfm/vframe_provider.h>
+#include <linux/amlogic/media/vfm/vframe_receiver.h>
+
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "../../../stream_input/amports/amports_priv.h"
+#include <linux/amlogic/media/registers/register.h>
+#include "../utils/decoder_mmu_box.h"
+#include "../utils/decoder_bmmu_box.h"
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include <linux/amlogic/media/codec_mm/configs.h>
+#include <linux/amlogic/tee.h>
+
+
+
+#ifdef CONFIG_AM_VDEC_MJPEG_LOG
+#define AMLOG
+#define LOG_LEVEL_VAR amlog_level_vmjpeg
+#define LOG_MASK_VAR amlog_mask_vmjpeg
+#define LOG_LEVEL_ERROR 0
+#define LOG_LEVEL_INFO 1
+#define LOG_LEVEL_DESC "0:ERROR, 1:INFO"
+#endif
+#include <linux/amlogic/media/utils/amlog.h>
+MODULE_AMLOG(LOG_LEVEL_ERROR, 0, LOG_LEVEL_DESC, LOG_DEFAULT_MASK_DESC);
+
+#include "../utils/amvdec.h"
+#include "../utils/firmware.h"
+
+#define DRIVER_NAME "amvdec_mjpeg"
+#define MODULE_NAME "amvdec_mjpeg"
+
+/* protocol register usage
+ * AV_SCRATCH_0 - AV_SCRATCH_1 : initial display buffer fifo
+ * AV_SCRATCH_2 - AV_SCRATCH_3 : decoder settings
+ * AV_SCRATCH_4 - AV_SCRATCH_7 : display buffer spec
+ * AV_SCRATCH_8 - AV_SCRATCH_9 : amrisc/host display buffer management
+ * AV_SCRATCH_a : time stamp
+ */
+
+#define MREG_DECODE_PARAM AV_SCRATCH_2 /* bit 0-3: pico_addr_mode */
+/* bit 15-4: reference height */
+#define MREG_TO_AMRISC AV_SCRATCH_8
+#define MREG_FROM_AMRISC AV_SCRATCH_9
+#define MREG_FRAME_OFFSET AV_SCRATCH_A
+
+#define PICINFO_BUF_IDX_MASK 0x0007
+#define PICINFO_AVI1 0x0080
+#define PICINFO_INTERLACE 0x0020
+#define PICINFO_INTERLACE_AVI1_BOT 0x0010
+#define PICINFO_INTERLACE_FIRST 0x0010
+
+#define VF_POOL_SIZE 16
+#define DECODE_BUFFER_NUM_MAX 4
+#define MAX_BMMU_BUFFER_NUM DECODE_BUFFER_NUM_MAX
+#define PUT_INTERVAL (HZ/100)
+
+#if 1/*MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6*/
+/* #define NV21 */
+#endif
+static DEFINE_MUTEX(vmjpeg_mutex);
+
+static struct dec_sysinfo vmjpeg_amstream_dec_info;
+
+static struct vframe_s *vmjpeg_vf_peek(void *);
+static struct vframe_s *vmjpeg_vf_get(void *);
+static void vmjpeg_vf_put(struct vframe_s *, void *);
+static int vmjpeg_vf_states(struct vframe_states *states, void *);
+static int vmjpeg_event_cb(int type, void *data, void *private_data);
+
+static int vmjpeg_prot_init(void);
+static void vmjpeg_local_init(void);
+
+static const char vmjpeg_dec_id[] = "vmjpeg-dev";
+static struct vdec_info *gvs;
+static struct work_struct set_clk_work;
+
+#define PROVIDER_NAME "decoder.mjpeg"
+static const struct vframe_operations_s vmjpeg_vf_provider = {
+ .peek = vmjpeg_vf_peek,
+ .get = vmjpeg_vf_get,
+ .put = vmjpeg_vf_put,
+ .event_cb = vmjpeg_event_cb,
+ .vf_states = vmjpeg_vf_states,
+};
+static void *mm_blk_handle;
+static struct vframe_provider_s vmjpeg_vf_prov;
+
+static DECLARE_KFIFO(newframe_q, struct vframe_s *, VF_POOL_SIZE);
+static DECLARE_KFIFO(display_q, struct vframe_s *, VF_POOL_SIZE);
+static DECLARE_KFIFO(recycle_q, struct vframe_s *, VF_POOL_SIZE);
+
+static struct vframe_s vfpool[VF_POOL_SIZE];
+static s32 vfbuf_use[DECODE_BUFFER_NUM_MAX];
+
+static u32 frame_width, frame_height, frame_dur;
+static u32 saved_resolution;
+static struct timer_list recycle_timer;
+static u32 stat;
+static u32 buf_size = 32 * 1024 * 1024;
+static DEFINE_SPINLOCK(lock);
+static bool is_reset;
+
+static inline u32 index2canvas0(u32 index)
+{
+ const u32 canvas_tab[4] = {
+#ifdef NV21
+ 0x010100, 0x030302, 0x050504, 0x070706
+#else
+ 0x020100, 0x050403, 0x080706, 0x0b0a09
+#endif
+ };
+
+ return canvas_tab[index];
+}
+
+static inline u32 index2canvas1(u32 index)
+{
+ const u32 canvas_tab[4] = {
+#ifdef NV21
+ 0x0d0d0c, 0x0f0f0e, 0x171716, 0x191918
+#else
+ 0x0e0d0c, 0x181716, 0x222120, 0x252423
+#endif
+ };
+
+ return canvas_tab[index];
+}
+
+static void set_frame_info(struct vframe_s *vf)
+{
+ vf->width = frame_width;
+ vf->height = frame_height;
+ vf->duration = frame_dur;
+ vf->ratio_control = 0;
+ vf->duration_pulldown = 0;
+ vf->flag = 0;
+}
+
+static irqreturn_t vmjpeg_isr(int irq, void *dev_id)
+{
+ u32 reg, offset, pts, pts_valid = 0;
+ struct vframe_s *vf = NULL;
+ u64 pts_us64;
+ u32 frame_size;
+
+ WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
+
+ reg = READ_VREG(MREG_FROM_AMRISC);
+
+ if (reg & PICINFO_BUF_IDX_MASK) {
+ offset = READ_VREG(MREG_FRAME_OFFSET);
+
+ if (pts_lookup_offset_us64
+ (PTS_TYPE_VIDEO, offset, &pts,
+ &frame_size, 0, &pts_us64) == 0)
+ pts_valid = 1;
+
+ if ((reg & PICINFO_INTERLACE) == 0) {
+ u32 index = ((reg & PICINFO_BUF_IDX_MASK) - 1) & 3;
+
+ if (index >= DECODE_BUFFER_NUM_MAX) {
+ pr_err("fatal error, invalid buffer index.");
+ return IRQ_HANDLED;
+ }
+
+ if (kfifo_get(&newframe_q, &vf) == 0) {
+ pr_info(
+ "fatal error, no available buffer slot.");
+ return IRQ_HANDLED;
+ }
+
+ set_frame_info(vf);
+ vf->signal_type = 0;
+ vf->index = index;
+#ifdef NV21
+ vf->type =
+ VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD |
+ VIDTYPE_VIU_NV21;
+#else
+ vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD;
+#endif
+ vf->canvas0Addr = vf->canvas1Addr =
+ index2canvas0(index);
+ vf->pts = (pts_valid) ? pts : 0;
+ vf->pts_us64 = (pts_valid) ? pts_us64 : 0;
+ vf->orientation = 0;
+ vf->type_original = vf->type;
+ vfbuf_use[index]++;
+ vf->mem_handle =
+ decoder_bmmu_box_get_mem_handle(
+ mm_blk_handle,
+ index);
+
+ gvs->frame_dur = frame_dur;
+ vdec_count_info(gvs, 0, offset);
+
+ 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 {
+ u32 index = ((reg & PICINFO_BUF_IDX_MASK) - 1) & 3;
+
+ if (index >= DECODE_BUFFER_NUM_MAX) {
+ pr_info("fatal error, invalid buffer index.");
+ return IRQ_HANDLED;
+ }
+
+ if (kfifo_get(&newframe_q, &vf) == 0) {
+ pr_info
+ ("fatal error, no available buffer slot.");
+ return IRQ_HANDLED;
+ }
+
+ set_frame_info(vf);
+ vf->signal_type = 0;
+ vf->index = index;
+#if 0
+ if (reg & PICINFO_AVI1) {
+ /* AVI1 format */
+ if (reg & PICINFO_INTERLACE_AVI1_BOT) {
+ vf->type =
+ VIDTYPE_INTERLACE_BOTTOM |
+ VIDTYPE_INTERLACE_FIRST;
+ } else
+ vf->type = VIDTYPE_INTERLACE_TOP;
+ } else {
+ if (reg & PICINFO_INTERLACE_FIRST) {
+ vf->type =
+ VIDTYPE_INTERLACE_TOP |
+ VIDTYPE_INTERLACE_FIRST;
+ } else
+ vf->type = VIDTYPE_INTERLACE_BOTTOM;
+ }
+
+ vf->type |= VIDTYPE_VIU_FIELD;
+#ifdef NV21
+ vf->type |= VIDTYPE_VIU_NV21;
+#endif
+ vf->duration >>= 1;
+ vf->canvas0Addr = vf->canvas1Addr =
+ index2canvas0(index);
+ vf->orientation = 0;
+ if ((vf->type & VIDTYPE_INTERLACE_FIRST) &&
+ (pts_valid))
+ vf->pts = pts;
+ else
+ vf->pts = 0;
+
+ vfbuf_use[index]++;
+
+ kfifo_put(&display_q, (const struct vframe_s *)vf);
+ ATRACE_COUNTER(MODULE_NAME, vf->pts);
+#else
+ /* send whole frame by weaving top & bottom field */
+#ifdef NV21
+ vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_NV21;
+#else
+ vf->type = VIDTYPE_PROGRESSIVE;
+#endif
+ vf->canvas0Addr = index2canvas0(index);
+ vf->canvas1Addr = index2canvas1(index);
+ vf->orientation = 0;
+ if (pts_valid) {
+ vf->pts = pts;
+ vf->pts_us64 = pts_us64;
+ } else {
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+ }
+ vf->type_original = vf->type;
+ vfbuf_use[index]++;
+ vf->mem_handle =
+ decoder_bmmu_box_get_mem_handle(
+ mm_blk_handle,
+ index);
+
+ gvs->frame_dur = frame_dur;
+ vdec_count_info(gvs, 0, offset);
+
+ 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);
+#endif
+ }
+
+ WRITE_VREG(MREG_FROM_AMRISC, 0);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static struct vframe_s *vmjpeg_vf_peek(void *op_arg)
+{
+ struct vframe_s *vf;
+
+ if (kfifo_peek(&display_q, &vf))
+ return vf;
+
+ return NULL;
+}
+
+static struct vframe_s *vmjpeg_vf_get(void *op_arg)
+{
+ struct vframe_s *vf;
+
+ if (kfifo_get(&display_q, &vf))
+ return vf;
+
+ return NULL;
+}
+
+static void vmjpeg_vf_put(struct vframe_s *vf, void *op_arg)
+{
+ kfifo_put(&recycle_q, (const struct vframe_s *)vf);
+}
+
+static int vmjpeg_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(&vmjpeg_vf_prov);
+#endif
+ spin_lock_irqsave(&lock, flags);
+ vmjpeg_local_init();
+ vmjpeg_prot_init();
+ spin_unlock_irqrestore(&lock, flags);
+#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vf_reg_provider(&vmjpeg_vf_prov);
+#endif
+ amvdec_start();
+ }
+ return 0;
+}
+
+static int vmjpeg_vf_states(struct vframe_states *states, void *op_arg)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ states->vf_pool_size = VF_POOL_SIZE;
+ states->buf_free_num = kfifo_len(&newframe_q);
+ states->buf_avail_num = kfifo_len(&display_q);
+ states->buf_recycle_num = kfifo_len(&recycle_q);
+
+ spin_unlock_irqrestore(&lock, flags);
+
+ return 0;
+}
+static void mjpeg_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_MJPEG,
+ frame_width, frame_height, fps);
+ }
+}
+
+static void vmjpeg_put_timer_func(unsigned long arg)
+{
+ struct timer_list *timer = (struct timer_list *)arg;
+
+ while (!kfifo_is_empty(&recycle_q) &&
+ (READ_VREG(MREG_TO_AMRISC) == 0)) {
+ struct vframe_s *vf;
+
+ if (kfifo_get(&recycle_q, &vf)) {
+ if ((vf->index < DECODE_BUFFER_NUM_MAX)
+ && (--vfbuf_use[vf->index] == 0)) {
+ WRITE_VREG(MREG_TO_AMRISC, vf->index + 1);
+ vf->index = DECODE_BUFFER_NUM_MAX;
+ }
+
+ kfifo_put(&newframe_q, (const struct vframe_s *)vf);
+ }
+ }
+
+ schedule_work(&set_clk_work);
+
+ timer->expires = jiffies + PUT_INTERVAL;
+
+ add_timer(timer);
+}
+
+int vmjpeg_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 (0 != frame_dur)
+ vstatus->frame_rate = 96000 / frame_dur;
+ else
+ vstatus->frame_rate = 96000;
+ vstatus->error_count = 0;
+ 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 vmjpeg_set_isreset(struct vdec_s *vdec, int isreset)
+{
+ is_reset = isreset;
+ return 0;
+}
+
+/****************************************/
+static int vmjpeg_canvas_init(void)
+{
+ int i, ret;
+ u32 canvas_width, canvas_height;
+ u32 decbuf_size, decbuf_y_size, decbuf_uv_size;
+ unsigned long buf_start;
+
+ 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;
+ }
+
+ for (i = 0; i < MAX_BMMU_BUFFER_NUM; i++) {
+
+ ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle, i,
+ decbuf_size, DRIVER_NAME, &buf_start);
+ if (ret < 0)
+ return ret;
+#ifdef NV21
+ canvas_config(index2canvas0(i) & 0xff,
+ buf_start,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config((index2canvas0(i) >> 8) & 0xff,
+ buf_start +
+ decbuf_y_size, canvas_width,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config(index2canvas1(i) & 0xff,
+ buf_start +
+ decbuf_size / 2, canvas_width,
+ canvas_height, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config((index2canvas1(i) >> 8) & 0xff,
+ buf_start +
+ decbuf_y_size + decbuf_uv_size / 2,
+ canvas_width, canvas_height / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+#else
+ canvas_config(index2canvas0(i) & 0xff,
+ buf_start,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config((index2canvas0(i) >> 8) & 0xff,
+ buf_start +
+ decbuf_y_size, canvas_width / 2,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config((index2canvas0(i) >> 16) & 0xff,
+ buf_start +
+ decbuf_y_size + decbuf_uv_size,
+ canvas_width / 2, canvas_height / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config(index2canvas1(i) & 0xff,
+ buf_start +
+ decbuf_size / 2, canvas_width,
+ canvas_height, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config((index2canvas1(i) >> 8) & 0xff,
+ buf_start +
+ decbuf_y_size + decbuf_uv_size / 2,
+ canvas_width / 2, canvas_height / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config((index2canvas1(i) >> 16) & 0xff,
+ buf_start +
+ decbuf_y_size + decbuf_uv_size +
+ decbuf_uv_size / 2, canvas_width / 2,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+#endif
+
+ }
+ return 0;
+}
+
+static void init_scaler(void)
+{
+ /* 4 point triangle */
+ const unsigned int filt_coef[] = {
+ 0x20402000, 0x20402000, 0x1f3f2101, 0x1f3f2101,
+ 0x1e3e2202, 0x1e3e2202, 0x1d3d2303, 0x1d3d2303,
+ 0x1c3c2404, 0x1c3c2404, 0x1b3b2505, 0x1b3b2505,
+ 0x1a3a2606, 0x1a3a2606, 0x19392707, 0x19392707,
+ 0x18382808, 0x18382808, 0x17372909, 0x17372909,
+ 0x16362a0a, 0x16362a0a, 0x15352b0b, 0x15352b0b,
+ 0x14342c0c, 0x14342c0c, 0x13332d0d, 0x13332d0d,
+ 0x12322e0e, 0x12322e0e, 0x11312f0f, 0x11312f0f,
+ 0x10303010
+ };
+ int i;
+
+ /* pscale enable, PSCALE cbus bmem enable */
+ WRITE_VREG(PSCALE_CTRL, 0xc000);
+
+ /* write filter coefs */
+ WRITE_VREG(PSCALE_BMEM_ADDR, 0);
+ for (i = 0; i < 33; i++) {
+ WRITE_VREG(PSCALE_BMEM_DAT, 0);
+ WRITE_VREG(PSCALE_BMEM_DAT, filt_coef[i]);
+ }
+
+ /* Y horizontal initial info */
+ WRITE_VREG(PSCALE_BMEM_ADDR, 37 * 2);
+ /* [35]: buf repeat pix0,
+ * [34:29] => buf receive num,
+ * [28:16] => buf blk x,
+ * [15:0] => buf phase
+ */
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x0008);
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x60000000);
+
+ /* C horizontal initial info */
+ WRITE_VREG(PSCALE_BMEM_ADDR, 41 * 2);
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x0008);
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x60000000);
+
+ /* Y vertical initial info */
+ WRITE_VREG(PSCALE_BMEM_ADDR, 39 * 2);
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x0008);
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x60000000);
+
+ /* C vertical initial info */
+ WRITE_VREG(PSCALE_BMEM_ADDR, 43 * 2);
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x0008);
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x60000000);
+
+ /* Y horizontal phase step */
+ WRITE_VREG(PSCALE_BMEM_ADDR, 36 * 2 + 1);
+ /* [19:0] => Y horizontal phase step */
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x10000);
+ /* C horizontal phase step */
+ WRITE_VREG(PSCALE_BMEM_ADDR, 40 * 2 + 1);
+ /* [19:0] => C horizontal phase step */
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x10000);
+
+ /* Y vertical phase step */
+ WRITE_VREG(PSCALE_BMEM_ADDR, 38 * 2 + 1);
+ /* [19:0] => Y vertical phase step */
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x10000);
+ /* C vertical phase step */
+ WRITE_VREG(PSCALE_BMEM_ADDR, 42 * 2 + 1);
+ /* [19:0] => C horizontal phase step */
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x10000);
+
+ /* reset pscaler */
+#if 1/*MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6*/
+ WRITE_VREG(DOS_SW_RESET0, (1 << 10));
+ WRITE_VREG(DOS_SW_RESET0, 0);
+#else
+ WRITE_RESET_REG(RESET2_REGISTER, RESET_PSCALE);
+#endif
+ READ_RESET_REG(RESET2_REGISTER);
+ READ_RESET_REG(RESET2_REGISTER);
+ READ_RESET_REG(RESET2_REGISTER);
+
+ WRITE_VREG(PSCALE_RST, 0x7);
+ WRITE_VREG(PSCALE_RST, 0x0);
+}
+
+static int vmjpeg_prot_init(void)
+{
+ int r;
+#if 1/*MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6*/
+ WRITE_VREG(DOS_SW_RESET0, (1 << 7) | (1 << 6));
+ WRITE_VREG(DOS_SW_RESET0, 0);
+#else
+ WRITE_RESET_REG(RESET0_REGISTER, RESET_IQIDCT | RESET_MC);
+#endif
+
+ r = vmjpeg_canvas_init();
+
+ WRITE_VREG(AV_SCRATCH_0, 12);
+ WRITE_VREG(AV_SCRATCH_1, 0x031a);
+#ifdef NV21
+ WRITE_VREG(AV_SCRATCH_4, 0x010100);
+ WRITE_VREG(AV_SCRATCH_5, 0x030302);
+ WRITE_VREG(AV_SCRATCH_6, 0x050504);
+ WRITE_VREG(AV_SCRATCH_7, 0x070706);
+#else
+ WRITE_VREG(AV_SCRATCH_4, 0x020100);
+ WRITE_VREG(AV_SCRATCH_5, 0x050403);
+ WRITE_VREG(AV_SCRATCH_6, 0x080706);
+ WRITE_VREG(AV_SCRATCH_7, 0x0b0a09);
+#endif
+ init_scaler();
+
+ /* clear buffer IN/OUT registers */
+ WRITE_VREG(MREG_TO_AMRISC, 0);
+ WRITE_VREG(MREG_FROM_AMRISC, 0);
+
+ WRITE_VREG(MCPU_INTR_MSK, 0xffff);
+ WRITE_VREG(MREG_DECODE_PARAM, (frame_height << 4) | 0x8000);
+
+ /* clear mailbox interrupt */
+ WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
+ /* enable mailbox interrupt */
+ WRITE_VREG(ASSIST_MBOX1_MASK, 1);
+ /* set interrupt mapping for vld */
+ WRITE_VREG(ASSIST_AMR1_INT8, 8);
+#if 1/*MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6*/
+#ifdef NV21
+ SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17);
+#else
+ CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17);
+#endif
+#endif
+ return r;
+}
+
+static int vmjpeg_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 void vmjpeg_local_init(void)
+{
+ int i;
+
+ frame_width = vmjpeg_amstream_dec_info.width;
+ frame_height = vmjpeg_amstream_dec_info.height;
+ frame_dur = vmjpeg_amstream_dec_info.rate;
+ saved_resolution = 0;
+ amlog_level(LOG_LEVEL_INFO, "mjpegdec: w(%d), h(%d), dur(%d)\n",
+ frame_width, frame_height, frame_dur);
+
+ for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++)
+ vfbuf_use[i] = 0;
+
+ INIT_KFIFO(display_q);
+ INIT_KFIFO(recycle_q);
+ INIT_KFIFO(newframe_q);
+
+ for (i = 0; i < VF_POOL_SIZE; i++) {
+ const struct vframe_s *vf = &vfpool[i];
+
+ vfpool[i].index = DECODE_BUFFER_NUM_MAX;
+ kfifo_put(&newframe_q, vf);
+ }
+ if (mm_blk_handle) {
+ decoder_bmmu_box_free(mm_blk_handle);
+ mm_blk_handle = NULL;
+ }
+
+ mm_blk_handle = decoder_bmmu_box_alloc_box(
+ DRIVER_NAME,
+ 0,
+ MAX_BMMU_BUFFER_NUM,
+ 4 + PAGE_SHIFT,
+ CODEC_MM_FLAGS_CMA_CLEAR |
+ CODEC_MM_FLAGS_FOR_VDECODER);
+}
+
+static s32 vmjpeg_init(void)
+{
+ int ret = -1, size = -1;
+ char *buf = vmalloc(0x1000 * 16);
+
+ if (IS_ERR_OR_NULL(buf))
+ return -ENOMEM;
+
+ init_timer(&recycle_timer);
+
+ stat |= STAT_TIMER_INIT;
+
+ amvdec_enable();
+
+ vmjpeg_local_init();
+
+ size = get_firmware_data(VIDEO_DEC_MJPEG, buf);
+ if (size < 0) {
+ amvdec_disable();
+ pr_err("get firmware fail.");
+ vfree(buf);
+ return -1;
+ }
+
+ ret = amvdec_loadmc_ex(VFORMAT_MJPEG, NULL, buf);
+ if (ret < 0) {
+ amvdec_disable();
+ vfree(buf);
+ pr_err("MJPEG: 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 = vmjpeg_prot_init();
+ if (ret < 0)
+ return ret;
+
+ ret = vdec_request_irq(VDEC_IRQ_1, vmjpeg_isr,
+ "vmjpeg-irq", (void *)vmjpeg_dec_id);
+
+ if (ret) {
+ amvdec_disable();
+
+ amlog_level(LOG_LEVEL_ERROR, "vmjpeg irq register error.\n");
+ return -ENOENT;
+ }
+
+ stat |= STAT_ISR_REG;
+
+#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vf_provider_init(&vmjpeg_vf_prov, PROVIDER_NAME, &vmjpeg_vf_provider,
+ NULL);
+ vf_reg_provider(&vmjpeg_vf_prov);
+ vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_START, NULL);
+#else
+ vf_provider_init(&vmjpeg_vf_prov, PROVIDER_NAME, &vmjpeg_vf_provider,
+ NULL);
+ vf_reg_provider(&vmjpeg_vf_prov);
+#endif
+
+ if (!is_reset)
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)
+ ((unsigned long)vmjpeg_amstream_dec_info.rate));
+
+ stat |= STAT_VF_HOOK;
+
+ recycle_timer.data = (ulong)&recycle_timer;
+ recycle_timer.function = vmjpeg_put_timer_func;
+ recycle_timer.expires = jiffies + PUT_INTERVAL;
+
+ add_timer(&recycle_timer);
+
+ stat |= STAT_TIMER_ARM;
+
+ amvdec_start();
+
+ stat |= STAT_VDEC_RUN;
+
+ return 0;
+}
+
+static int amvdec_mjpeg_probe(struct platform_device *pdev)
+{
+ struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
+
+ mutex_lock(&vmjpeg_mutex);
+
+ amlog_level(LOG_LEVEL_INFO, "amvdec_mjpeg probe start.\n");
+
+ INIT_WORK(&set_clk_work, mjpeg_set_clk);
+
+ if (pdata == NULL) {
+ amlog_level(LOG_LEVEL_ERROR,
+ "amvdec_mjpeg memory resource undefined.\n");
+ mutex_unlock(&vmjpeg_mutex);
+
+ return -EFAULT;
+ }
+
+ if (pdata->sys_info)
+ vmjpeg_amstream_dec_info = *pdata->sys_info;
+
+ pdata->dec_status = vmjpeg_dec_status;
+ pdata->set_isreset = vmjpeg_set_isreset;
+ is_reset = 0;
+ vmjpeg_vdec_info_init();
+
+ if (vmjpeg_init() < 0) {
+ amlog_level(LOG_LEVEL_ERROR, "amvdec_mjpeg init failed.\n");
+ mutex_unlock(&vmjpeg_mutex);
+ kfree(gvs);
+ gvs = NULL;
+ pdata->dec_status = NULL;
+ return -ENODEV;
+ }
+
+ mutex_unlock(&vmjpeg_mutex);
+
+ amlog_level(LOG_LEVEL_INFO, "amvdec_mjpeg probe end.\n");
+
+ return 0;
+}
+
+static int amvdec_mjpeg_remove(struct platform_device *pdev)
+{
+ mutex_lock(&vmjpeg_mutex);
+
+ cancel_work_sync(&set_clk_work);
+
+ if (stat & STAT_VDEC_RUN) {
+ amvdec_stop();
+ stat &= ~STAT_VDEC_RUN;
+ }
+
+ if (stat & STAT_ISR_REG) {
+ vdec_free_irq(VDEC_IRQ_1, (void *)vmjpeg_dec_id);
+ stat &= ~STAT_ISR_REG;
+ }
+
+ if (stat & STAT_TIMER_ARM) {
+ del_timer_sync(&recycle_timer);
+ stat &= ~STAT_TIMER_ARM;
+ }
+
+ if (stat & STAT_VF_HOOK) {
+ if (!is_reset)
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_FR_END_HINT,
+ NULL);
+
+ vf_unreg_provider(&vmjpeg_vf_prov);
+ stat &= ~STAT_VF_HOOK;
+ }
+
+ amvdec_disable();
+
+ mutex_unlock(&vmjpeg_mutex);
+
+ kfree(gvs);
+ gvs = NULL;
+
+ if (mm_blk_handle) {
+ decoder_bmmu_box_free(mm_blk_handle);
+ mm_blk_handle = NULL;
+ }
+
+ amlog_level(LOG_LEVEL_INFO, "amvdec_mjpeg remove.\n");
+
+ return 0;
+}
+
+/****************************************/
+#ifdef CONFIG_PM
+static int mjpeg_suspend(struct device *dev)
+{
+ amvdec_suspend(to_platform_device(dev), dev->power.power_state);
+ return 0;
+}
+
+static int mjpeg_resume(struct device *dev)
+{
+ amvdec_resume(to_platform_device(dev));
+ return 0;
+}
+
+static const struct dev_pm_ops mjpeg_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mjpeg_suspend, mjpeg_resume)
+};
+#endif
+
+static struct platform_driver amvdec_mjpeg_driver = {
+ .probe = amvdec_mjpeg_probe,
+ .remove = amvdec_mjpeg_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &mjpeg_pm_ops,
+#endif
+ }
+};
+
+static struct codec_profile_t amvdec_mjpeg_profile = {
+ .name = "mjpeg",
+ .profile = ""
+};
+static struct mconfig mjpeg_configs[] = {
+ MC_PU32("stat", &stat),
+};
+static struct mconfig_node mjpeg_node;
+
+static int __init amvdec_mjpeg_driver_init_module(void)
+{
+ amlog_level(LOG_LEVEL_INFO, "amvdec_mjpeg module init\n");
+
+ if (platform_driver_register(&amvdec_mjpeg_driver)) {
+ amlog_level(LOG_LEVEL_ERROR,
+ "failed to register amvdec_mjpeg driver\n");
+ return -ENODEV;
+ }
+ vcodec_profile_register(&amvdec_mjpeg_profile);
+ INIT_REG_NODE_CONFIGS("media.decoder", &mjpeg_node,
+ "mjpeg", mjpeg_configs, CONFIG_FOR_RW);
+ return 0;
+}
+
+static void __exit amvdec_mjpeg_driver_remove_module(void)
+{
+ amlog_level(LOG_LEVEL_INFO, "amvdec_mjpeg module remove.\n");
+
+ platform_driver_unregister(&amvdec_mjpeg_driver);
+}
+
+/****************************************/
+
+module_param(stat, uint, 0664);
+MODULE_PARM_DESC(stat, "\n amvdec_mjpeg stat\n");
+
+module_init(amvdec_mjpeg_driver_init_module);
+module_exit(amvdec_mjpeg_driver_remove_module);
+
+MODULE_DESCRIPTION("AMLOGIC MJMPEG Video Decoder Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tim Yao <timyao@amlogic.com>");
diff --git a/drivers/frame_provider/decoder/mjpeg/vmjpeg_multi.c b/drivers/frame_provider/decoder/mjpeg/vmjpeg_multi.c
new file mode 100644
index 0000000..8fe1dbb
--- /dev/null
+++ b/drivers/frame_provider/decoder/mjpeg/vmjpeg_multi.c
@@ -0,0 +1,1859 @@
+/*
+ * drivers/amlogic/amports/vmjpeg.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/kfifo.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/amlogic/media/frame_sync/ptsserv.h>
+#include <linux/amlogic/media/utils/amstream.h>
+#include <linux/amlogic/media/canvas/canvas.h>
+#include <linux/amlogic/media/vfm/vframe.h>
+#include <linux/amlogic/media/vfm/vframe_provider.h>
+#include <linux/amlogic/media/vfm/vframe_receiver.h>
+#include <linux/amlogic/tee.h>
+
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include <linux/amlogic/media/registers/register.h>
+#include "../../../stream_input/amports/amports_priv.h"
+#include "../../../common/chips/decoder_cpu_ver_info.h"
+
+#include "../utils/vdec_input.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/vdec_v4l2_buffer_ops.h"
+#include "../utils/config_parser.h"
+#include <media/v4l2-mem2mem.h>
+
+#define MEM_NAME "codec_mmjpeg"
+
+#define DRIVER_NAME "ammvdec_mjpeg"
+#define CHECK_INTERVAL (HZ/100)
+
+/* protocol register usage
+ * AV_SCRATCH_4 : decode buffer spec
+ * AV_SCRATCH_5 : decode buffer index
+ */
+
+#define MREG_DECODE_PARAM AV_SCRATCH_2 /* bit 0-3: pico_addr_mode */
+/* bit 15-4: reference height */
+#define MREG_TO_AMRISC AV_SCRATCH_8
+#define MREG_FROM_AMRISC AV_SCRATCH_9
+#define MREG_FRAME_OFFSET AV_SCRATCH_A
+#define DEC_STATUS_REG AV_SCRATCH_F
+#define MREG_PIC_WIDTH AV_SCRATCH_B
+#define MREG_PIC_HEIGHT AV_SCRATCH_C
+#define DECODE_STOP_POS AV_SCRATCH_K
+
+#define PICINFO_BUF_IDX_MASK 0x0007
+#define PICINFO_AVI1 0x0080
+#define PICINFO_INTERLACE 0x0020
+#define PICINFO_INTERLACE_AVI1_BOT 0x0010
+#define PICINFO_INTERLACE_FIRST 0x0010
+
+#define VF_POOL_SIZE 64
+#define DECODE_BUFFER_NUM_MAX 16
+#define DECODE_BUFFER_NUM_DEF 4
+#define MAX_BMMU_BUFFER_NUM DECODE_BUFFER_NUM_MAX
+
+#define DEFAULT_MEM_SIZE (32*SZ_1M)
+static int debug_enable;
+static u32 udebug_flag;
+#define DECODE_ID(hw) (hw_to_vdec(hw)->id)
+
+static unsigned int radr;
+static unsigned int rval;
+#define VMJPEG_DEV_NUM 9
+static unsigned int max_decode_instance_num = VMJPEG_DEV_NUM;
+static unsigned int max_process_time[VMJPEG_DEV_NUM];
+static unsigned int decode_timeout_val = 200;
+static struct vframe_s *vmjpeg_vf_peek(void *);
+static struct vframe_s *vmjpeg_vf_get(void *);
+static void vmjpeg_vf_put(struct vframe_s *, void *);
+static int vmjpeg_vf_states(struct vframe_states *states, void *);
+static int vmjpeg_event_cb(int type, void *data, void *private_data);
+static void vmjpeg_work(struct work_struct *work);
+static int pre_decode_buf_level = 0x800;
+static int start_decode_buf_level = 0x2000;
+static u32 without_display_mode;
+static u32 dynamic_buf_num_margin;
+static u32 run_ready_min_buf_num = 2;
+#undef pr_info
+#define pr_info printk
+unsigned int mmjpeg_debug_mask = 0xff;
+#define PRINT_FLAG_ERROR 0x0
+#define PRINT_FLAG_RUN_FLOW 0X0001
+#define PRINT_FLAG_TIMEINFO 0x0002
+#define PRINT_FLAG_UCODE_DETAIL 0x0004
+#define PRINT_FLAG_VLD_DETAIL 0x0008
+#define PRINT_FLAG_DEC_DETAIL 0x0010
+#define PRINT_FLAG_BUFFER_DETAIL 0x0020
+#define PRINT_FLAG_RESTORE 0x0040
+#define PRINT_FRAME_NUM 0x0080
+#define PRINT_FLAG_FORCE_DONE 0x0100
+#define PRINT_FRAMEBASE_DATA 0x0400
+#define PRINT_FLAG_TIMEOUT_STATUS 0x1000
+#define PRINT_FLAG_V4L_DETAIL 0x8000
+#define IGNORE_PARAM_FROM_CONFIG 0x8000000
+
+int mmjpeg_debug_print(int index, int debug_flag, const char *fmt, ...)
+{
+ if (((debug_enable & debug_flag) &&
+ ((1 << index) & mmjpeg_debug_mask))
+ || (debug_flag == PRINT_FLAG_ERROR)) {
+ unsigned char buf[512];
+ int len = 0;
+ va_list args;
+ va_start(args, fmt);
+ len = sprintf(buf, "%d: ", index);
+ vsnprintf(buf + len, 512-len, fmt, args);
+ pr_info("%s", buf);
+ va_end(args);
+ }
+ return 0;
+}
+
+static const char vmjpeg_dec_id[] = "vmmjpeg-dev";
+
+#define PROVIDER_NAME "vdec.mjpeg"
+static const struct vframe_operations_s vf_provider_ops = {
+ .peek = vmjpeg_vf_peek,
+ .get = vmjpeg_vf_get,
+ .put = vmjpeg_vf_put,
+ .event_cb = vmjpeg_event_cb,
+ .vf_states = vmjpeg_vf_states,
+};
+
+#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_DECODE_TIMEOUT 0x21
+
+
+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 canvas_config_s canvas_config[3];
+ unsigned long cma_alloc_addr;
+ int cma_alloc_count;
+ unsigned int buf_adr;
+ ulong v4l_ref_buf_addr;
+};
+
+#define spec2canvas(x) \
+ (((x)->v_canvas_index << 16) | \
+ ((x)->u_canvas_index << 8) | \
+ ((x)->y_canvas_index << 0))
+
+struct vdec_mjpeg_hw_s {
+ spinlock_t lock;
+ struct mutex vmjpeg_mutex;
+
+ 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);
+
+ struct vframe_s vfpool[VF_POOL_SIZE];
+ struct buffer_spec_s buffer_spec[DECODE_BUFFER_NUM_MAX];
+ s32 vfbuf_use[DECODE_BUFFER_NUM_MAX];
+
+ u32 frame_width;
+ u32 frame_height;
+ u32 frame_dur;
+ u32 saved_resolution;
+ u8 init_flag;
+ u32 stat;
+ u32 dec_result;
+ unsigned long buf_start;
+ u32 buf_size;
+ void *mm_blk_handle;
+ struct dec_sysinfo vmjpeg_amstream_dec_info;
+
+ struct vframe_chunk_s *chunk;
+ struct work_struct work;
+ void (*vdec_cb)(struct vdec_s *, void *);
+ void *vdec_cb_arg;
+ struct firmware_s *fw;
+ struct timer_list check_timer;
+ u32 decode_timeout_count;
+ unsigned long int start_process_time;
+ u32 last_vld_level;
+ u8 eos;
+ u32 frame_num;
+ u32 put_num;
+ u32 run_count;
+ u32 not_run_ready;
+ u32 buffer_not_ready;
+ u32 input_empty;
+ u32 peek_num;
+ u32 get_num;
+ bool is_used_v4l;
+ void *v4l2_ctx;
+ bool v4l_params_parsed;
+ int buf_num;
+ int dynamic_buf_num_margin;
+ int sidebind_type;
+ int sidebind_channel_id;
+ u32 res_ch_flag;
+ u32 canvas_mode;
+ u32 canvas_endian;
+ 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_mjpeg_hw_s *hw);
+static int notify_v4l_eos(struct vdec_s *vdec);
+
+static void set_frame_info(struct vdec_mjpeg_hw_s *hw, struct vframe_s *vf)
+{
+ u32 temp;
+ temp = READ_VREG(MREG_PIC_WIDTH);
+ if (temp > 1920)
+ vf->width = hw->frame_width = 1920;
+ else if (temp > 0)
+ vf->width = hw->frame_width = temp;
+ temp = READ_VREG(MREG_PIC_HEIGHT);
+ if (temp > 1088)
+ vf->height = hw->frame_height = 1088;
+ else if (temp > 0)
+ vf->height = hw->frame_height = temp;
+ vf->duration = hw->frame_dur;
+ vf->ratio_control = DISP_RATIO_ASPECT_RATIO_MAX << DISP_RATIO_ASPECT_RATIO_BIT;
+ vf->sar_width = 1;
+ vf->sar_height = 1;
+ vf->duration_pulldown = 0;
+ vf->flag = 0;
+
+ vf->canvas0Addr = vf->canvas1Addr = -1;
+ vf->plane_num = 3;
+
+ vf->canvas0_config[0] = hw->buffer_spec[vf->index].canvas_config[0];
+ vf->canvas0_config[1] = hw->buffer_spec[vf->index].canvas_config[1];
+ vf->canvas0_config[2] = hw->buffer_spec[vf->index].canvas_config[2];
+
+ vf->canvas1_config[0] = hw->buffer_spec[vf->index].canvas_config[0];
+ vf->canvas1_config[1] = hw->buffer_spec[vf->index].canvas_config[1];
+ vf->canvas1_config[2] = hw->buffer_spec[vf->index].canvas_config[2];
+
+ vf->sidebind_type = hw->sidebind_type;
+ vf->sidebind_channel_id = hw->sidebind_channel_id;
+}
+
+static irqreturn_t vmjpeg_isr(struct vdec_s *vdec, int irq)
+{
+ struct vdec_mjpeg_hw_s *hw =
+ (struct vdec_mjpeg_hw_s *)(vdec->private);
+
+ if (!hw)
+ return IRQ_HANDLED;
+
+ if (hw->eos)
+ return IRQ_HANDLED;
+
+ WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
+
+ return IRQ_WAKE_THREAD;
+}
+
+static int vmjpeg_get_ps_info(struct vdec_mjpeg_hw_s *hw, int width, int height, struct aml_vdec_ps_infos *ps)
+{
+ ps->visible_width = width;
+ ps->visible_height = height;
+ ps->coded_width = ALIGN(width, 64);
+ ps->coded_height = ALIGN(height, 64);
+ ps->dpb_size = hw->buf_num;
+
+ return 0;
+}
+
+static int v4l_res_change(struct vdec_mjpeg_hw_s *hw, int width, int height)
+{
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(hw->v4l2_ctx);
+ int ret = 0;
+
+ if (ctx->param_sets_from_ucode &&
+ hw->res_ch_flag == 0) {
+ struct aml_vdec_ps_infos ps;
+
+ if ((hw->frame_width != 0 &&
+ hw->frame_height != 0) &&
+ (hw->frame_width != width ||
+ hw->frame_height != height)) {
+ mmjpeg_debug_print(DECODE_ID(hw), 0,
+ "v4l_res_change Pic Width/Height Change (%d,%d)=>(%d,%d)\n",
+ hw->frame_width, hw->frame_height,
+ width,
+ height);
+ vmjpeg_get_ps_info(hw, width, height, &ps);
+ vdec_v4l_set_ps_infos(ctx, &ps);
+ vdec_v4l_res_ch_event(ctx);
+ hw->v4l_params_parsed = false;
+ hw->res_ch_flag = 1;
+ ctx->v4l_resolution_change = 1;
+ hw->eos = 1;
+ notify_v4l_eos(hw_to_vdec(hw));
+
+ ret = 1;
+ }
+ }
+
+ return ret;
+}
+
+static irqreturn_t vmjpeg_isr_thread_fn(struct vdec_s *vdec, int irq)
+{
+ struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)(vdec->private);
+ u32 reg;
+ struct vframe_s *vf = NULL;
+ u32 index, offset = 0, pts;
+ u64 pts_us64;
+ u32 frame_size;
+
+ if (READ_VREG(AV_SCRATCH_D) != 0 &&
+ (debug_enable & PRINT_FLAG_UCODE_DETAIL)) {
+ pr_info("dbg%x: %x\n", READ_VREG(AV_SCRATCH_D),
+ READ_VREG(AV_SCRATCH_E));
+ WRITE_VREG(AV_SCRATCH_D, 0);
+ return IRQ_HANDLED;
+ }
+
+ if (READ_VREG(DEC_STATUS_REG) == 1) {
+ if (hw->is_used_v4l) {
+ int frame_width = READ_VREG(MREG_PIC_WIDTH);
+ int frame_height = READ_VREG(MREG_PIC_HEIGHT);
+
+ if (!v4l_res_change(hw, frame_width, frame_height)) {
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(hw->v4l2_ctx);
+ if (ctx->param_sets_from_ucode && !hw->v4l_params_parsed) {
+ struct aml_vdec_ps_infos ps;
+
+ vmjpeg_get_ps_info(hw, frame_width, frame_height, &ps);
+ hw->v4l_params_parsed = true;
+ vdec_v4l_set_ps_infos(ctx, &ps);
+ reset_process_time(hw);
+ hw->dec_result = DEC_RESULT_AGAIN;
+ vdec_schedule_work(&hw->work);
+ } else {
+ WRITE_VREG(DEC_STATUS_REG, 0);
+ }
+ } else {
+ reset_process_time(hw);
+ hw->dec_result = DEC_RESULT_AGAIN;
+ vdec_schedule_work(&hw->work);
+ }
+ } else
+ WRITE_VREG(DEC_STATUS_REG, 0);
+ return IRQ_HANDLED;
+ }
+ reset_process_time(hw);
+
+ reg = READ_VREG(MREG_FROM_AMRISC);
+ index = READ_VREG(AV_SCRATCH_5) & 0xffffff;
+
+ if (index >= hw->buf_num) {
+ pr_err("fatal error, invalid buffer index.");
+ return IRQ_HANDLED;
+ }
+
+ if (kfifo_get(&hw->newframe_q, &vf) == 0) {
+ pr_info(
+ "fatal error, no available buffer slot.");
+ return IRQ_HANDLED;
+ }
+
+ if (hw->is_used_v4l) {
+ vf->v4l_mem_handle
+ = hw->buffer_spec[index].v4l_ref_buf_addr;
+ mmjpeg_debug_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL,
+ "[%d] %s(), v4l mem handle: 0x%lx\n",
+ ((struct aml_vcodec_ctx *)(hw->v4l2_ctx))->id,
+ __func__, vf->v4l_mem_handle);
+ }
+
+ vf->index = index;
+ set_frame_info(hw, vf);
+
+ vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD;
+ /* vf->pts = (pts_valid) ? pts : 0; */
+ /* vf->pts_us64 = (pts_valid) ? pts_us64 : 0; */
+
+ if (hw->chunk) {
+ vf->pts = hw->chunk->pts;
+ vf->pts_us64 = hw->chunk->pts64;
+ vf->timestamp = hw->chunk->timestamp;
+ } else {
+ offset = READ_VREG(MREG_FRAME_OFFSET);
+ if ((vdec->vbuf.no_parser == 0) || (vdec->vbuf.use_ptsserv)) {
+ if (pts_lookup_offset_us64
+ (PTS_TYPE_VIDEO, offset, &pts,
+ &frame_size, 3000,
+ &pts_us64) == 0) {
+ vf->pts = pts;
+ vf->pts_us64 = pts_us64;
+ } else {
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+ }
+ }
+ if (!vdec->vbuf.use_ptsserv && vdec_stream_based(vdec)) {
+ vf->pts_us64 = offset;
+ vf->pts = 0;
+ }
+ }
+ vf->orientation = 0;
+ hw->vfbuf_use[index]++;
+
+ vf->mem_handle =
+ decoder_bmmu_box_get_mem_handle(
+ hw->mm_blk_handle, index);
+ decoder_do_frame_check(vdec, 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));
+ hw->frame_num++;
+ mmjpeg_debug_print(DECODE_ID(hw), PRINT_FRAME_NUM,
+ "%s:frame num:%d,pts=%d,pts64=%lld. dur=%d\n",
+ __func__, hw->frame_num,
+ vf->pts, vf->pts_us64, vf->duration);
+ vdec->vdec_fps_detec(vdec->id);
+ if (without_display_mode == 0) {
+ vf_notify_receiver(vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY,
+ NULL);
+ } else
+ vmjpeg_vf_put(vmjpeg_vf_get(vdec), vdec);
+
+ hw->dec_result = DEC_RESULT_DONE;
+
+ vdec_schedule_work(&hw->work);
+
+ return IRQ_HANDLED;
+}
+
+static int valid_vf_check(struct vframe_s *vf, struct vdec_mjpeg_hw_s *hw)
+{
+ int i;
+
+ if (!vf || (vf->index == -1))
+ return 0;
+
+ for (i = 0; i < VF_POOL_SIZE; i++) {
+ if (vf == &hw->vfpool[i])
+ return 1;
+ }
+
+ return 0;
+}
+
+static struct vframe_s *vmjpeg_vf_peek(void *op_arg)
+{
+ struct vframe_s *vf;
+ struct vdec_s *vdec = op_arg;
+ struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)vdec->private;
+
+ if (!hw)
+ return NULL;
+ hw->peek_num++;
+ if (kfifo_peek(&hw->display_q, &vf))
+ return vf;
+
+ return NULL;
+}
+
+static struct vframe_s *vmjpeg_vf_get(void *op_arg)
+{
+ struct vframe_s *vf;
+ struct vdec_s *vdec = op_arg;
+ struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)vdec->private;
+
+ if (!hw)
+ return NULL;
+ hw->get_num++;
+ if (kfifo_get(&hw->display_q, &vf)) {
+ ATRACE_COUNTER(hw->disp_q_name, kfifo_len(&hw->display_q));
+ return vf;
+ }
+ return NULL;
+}
+
+static void vmjpeg_vf_put(struct vframe_s *vf, void *op_arg)
+{
+ struct vdec_s *vdec = op_arg;
+ struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)vdec->private;
+
+ if (!valid_vf_check(vf, hw)) {
+ mmjpeg_debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR,
+ "invalid vf: %lx\n", (ulong)vf);
+ return ;
+ }
+
+ mmjpeg_debug_print(DECODE_ID(hw), PRINT_FRAME_NUM,
+ "%s:put_num:%d\n", __func__, hw->put_num);
+ hw->vfbuf_use[vf->index]--;
+ kfifo_put(&hw->newframe_q, (const struct vframe_s *)vf);
+ ATRACE_COUNTER(hw->new_q_name, kfifo_len(&hw->newframe_q));
+ hw->put_num++;
+}
+
+static int vmjpeg_event_cb(int type, void *data, void *op_arg)
+{
+ struct vdec_s *vdec = op_arg;
+
+ 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 int vmjpeg_vf_states(struct vframe_states *states, void *op_arg)
+{
+ unsigned long flags;
+ struct vdec_s *vdec = op_arg;
+ struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_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);
+ states->buf_recycle_num = 0;
+
+ spin_unlock_irqrestore(&hw->lock, flags);
+
+ return 0;
+}
+
+static int vmjpeg_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus)
+{
+ struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)vdec->private;
+
+ if (!hw)
+ return -1;
+
+ vstatus->frame_width = hw->frame_width;
+ vstatus->frame_height = hw->frame_height;
+ if (0 != hw->frame_dur)
+ vstatus->frame_rate = 96000 / hw->frame_dur;
+ else
+ vstatus->frame_rate = 96000;
+ vstatus->error_count = 0;
+ vstatus->status = hw->stat;
+
+ return 0;
+}
+
+/****************************************/
+static void vmjpeg_canvas_init(struct vdec_mjpeg_hw_s *hw)
+{
+ int i, ret;
+ u32 canvas_width, canvas_height;
+ u32 decbuf_size, decbuf_y_size, decbuf_uv_size;
+ unsigned long buf_start, addr;
+ u32 endian;
+ struct vdec_s *vdec = hw_to_vdec(hw);
+
+ endian = (vdec->canvas_mode ==
+ CANVAS_BLKMODE_LINEAR) ? 7 : 0;
+ canvas_width = 1920;
+ canvas_height = 1088;
+ decbuf_y_size = 0x200000;
+ decbuf_uv_size = 0x80000;
+ decbuf_size = 0x300000;
+
+ for (i = 0; i < hw->buf_num; i++) {
+ int canvas;
+
+ if (hw->is_used_v4l) {
+ continue;
+ } else {
+ ret = decoder_bmmu_box_alloc_buf_phy(hw->mm_blk_handle, i,
+ decbuf_size, DRIVER_NAME, &buf_start);
+ if (ret < 0) {
+ pr_err("CMA alloc failed! size 0x%d idx %d\n",
+ decbuf_size, i);
+ return;
+ }
+ }
+
+ hw->buffer_spec[i].buf_adr = buf_start;
+ addr = hw->buffer_spec[i].buf_adr;
+
+ hw->buffer_spec[i].y_addr = addr;
+ addr += decbuf_y_size;
+ hw->buffer_spec[i].u_addr = addr;
+ addr += decbuf_uv_size;
+ hw->buffer_spec[i].v_addr = addr;
+
+ 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);
+ if (hw->buffer_spec[i].v_canvas_index == -1)
+ hw->buffer_spec[i].v_canvas_index = vdec->get_canvas_ex(CORE_MASK_VDEC_1, vdec->id);
+ } else {
+ canvas = vdec->get_canvas(i, 3);
+ 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);
+ }
+
+ canvas_config_ex(hw->buffer_spec[i].y_canvas_index,
+ hw->buffer_spec[i].y_addr,
+ canvas_width,
+ canvas_height,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR, endian);
+ hw->buffer_spec[i].canvas_config[0].phy_addr =
+ hw->buffer_spec[i].y_addr;
+ hw->buffer_spec[i].canvas_config[0].width =
+ canvas_width;
+ hw->buffer_spec[i].canvas_config[0].height =
+ canvas_height;
+ hw->buffer_spec[i].canvas_config[0].block_mode =
+ CANVAS_BLKMODE_LINEAR;
+ hw->buffer_spec[i].canvas_config[0].endian =
+ endian;
+
+ canvas_config_ex(hw->buffer_spec[i].u_canvas_index,
+ hw->buffer_spec[i].u_addr,
+ canvas_width / 2,
+ canvas_height / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR, endian);
+ hw->buffer_spec[i].canvas_config[1].phy_addr =
+ hw->buffer_spec[i].u_addr;
+ hw->buffer_spec[i].canvas_config[1].width =
+ canvas_width / 2;
+ hw->buffer_spec[i].canvas_config[1].height =
+ canvas_height / 2;
+ hw->buffer_spec[i].canvas_config[1].block_mode =
+ CANVAS_BLKMODE_LINEAR;
+ hw->buffer_spec[i].canvas_config[1].endian =
+ endian;
+
+ canvas_config_ex(hw->buffer_spec[i].v_canvas_index,
+ hw->buffer_spec[i].v_addr,
+ canvas_width / 2,
+ canvas_height / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR, endian);
+ hw->buffer_spec[i].canvas_config[2].phy_addr =
+ hw->buffer_spec[i].v_addr;
+ hw->buffer_spec[i].canvas_config[2].width =
+ canvas_width / 2;
+ hw->buffer_spec[i].canvas_config[2].height =
+ canvas_height / 2;
+ hw->buffer_spec[i].canvas_config[2].block_mode =
+ CANVAS_BLKMODE_LINEAR;
+ hw->buffer_spec[i].canvas_config[2].endian =
+ endian;
+ }
+}
+
+static void init_scaler(void)
+{
+ /* 4 point triangle */
+ const unsigned int filt_coef[] = {
+ 0x20402000, 0x20402000, 0x1f3f2101, 0x1f3f2101,
+ 0x1e3e2202, 0x1e3e2202, 0x1d3d2303, 0x1d3d2303,
+ 0x1c3c2404, 0x1c3c2404, 0x1b3b2505, 0x1b3b2505,
+ 0x1a3a2606, 0x1a3a2606, 0x19392707, 0x19392707,
+ 0x18382808, 0x18382808, 0x17372909, 0x17372909,
+ 0x16362a0a, 0x16362a0a, 0x15352b0b, 0x15352b0b,
+ 0x14342c0c, 0x14342c0c, 0x13332d0d, 0x13332d0d,
+ 0x12322e0e, 0x12322e0e, 0x11312f0f, 0x11312f0f,
+ 0x10303010
+ };
+ int i;
+
+ /* pscale enable, PSCALE cbus bmem enable */
+ WRITE_VREG(PSCALE_CTRL, 0xc000);
+
+ /* write filter coefs */
+ WRITE_VREG(PSCALE_BMEM_ADDR, 0);
+ for (i = 0; i < 33; i++) {
+ WRITE_VREG(PSCALE_BMEM_DAT, 0);
+ WRITE_VREG(PSCALE_BMEM_DAT, filt_coef[i]);
+ }
+
+ /* Y horizontal initial info */
+ WRITE_VREG(PSCALE_BMEM_ADDR, 37 * 2);
+ /* [35]: buf repeat pix0,
+ * [34:29] => buf receive num,
+ * [28:16] => buf blk x,
+ * [15:0] => buf phase
+ */
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x0008);
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x60000000);
+
+ /* C horizontal initial info */
+ WRITE_VREG(PSCALE_BMEM_ADDR, 41 * 2);
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x0008);
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x60000000);
+
+ /* Y vertical initial info */
+ WRITE_VREG(PSCALE_BMEM_ADDR, 39 * 2);
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x0008);
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x60000000);
+
+ /* C vertical initial info */
+ WRITE_VREG(PSCALE_BMEM_ADDR, 43 * 2);
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x0008);
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x60000000);
+
+ /* Y horizontal phase step */
+ WRITE_VREG(PSCALE_BMEM_ADDR, 36 * 2 + 1);
+ /* [19:0] => Y horizontal phase step */
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x10000);
+ /* C horizontal phase step */
+ WRITE_VREG(PSCALE_BMEM_ADDR, 40 * 2 + 1);
+ /* [19:0] => C horizontal phase step */
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x10000);
+
+ /* Y vertical phase step */
+ WRITE_VREG(PSCALE_BMEM_ADDR, 38 * 2 + 1);
+ /* [19:0] => Y vertical phase step */
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x10000);
+ /* C vertical phase step */
+ WRITE_VREG(PSCALE_BMEM_ADDR, 42 * 2 + 1);
+ /* [19:0] => C horizontal phase step */
+ WRITE_VREG(PSCALE_BMEM_DAT, 0x10000);
+
+ /* reset pscaler */
+#if 1/*MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6*/
+ WRITE_VREG(DOS_SW_RESET0, (1 << 10));
+ WRITE_VREG(DOS_SW_RESET0, 0);
+#else
+ WRITE_RESET_REG(RESET2_REGISTER, RESET_PSCALE);
+#endif
+ if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SC2) {
+ READ_RESET_REG(RESET2_REGISTER);
+ READ_RESET_REG(RESET2_REGISTER);
+ READ_RESET_REG(RESET2_REGISTER);
+ }
+ WRITE_VREG(PSCALE_RST, 0x7);
+ WRITE_VREG(PSCALE_RST, 0x0);
+}
+
+static void vmjpeg_dump_state(struct vdec_s *vdec)
+{
+ struct vdec_mjpeg_hw_s *hw =
+ (struct vdec_mjpeg_hw_s *)(vdec->private);
+ mmjpeg_debug_print(DECODE_ID(hw), 0,
+ "====== %s\n", __func__);
+ mmjpeg_debug_print(DECODE_ID(hw), 0,
+ "width/height (%d/%d) buf_num %d\n",
+ hw->frame_width,
+ hw->frame_height,
+ hw->buf_num
+ );
+ mmjpeg_debug_print(DECODE_ID(hw), 0,
+ "is_framebase(%d), eos %d, state 0x%x, dec_result 0x%x dec_frm %d put_frm %d run %d not_run_ready %d input_empty %d\n",
+ input_frame_based(vdec),
+ hw->eos,
+ hw->stat,
+ hw->dec_result,
+ hw->frame_num,
+ hw->put_num,
+ 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);
+ mmjpeg_debug_print(DECODE_ID(hw), 0,
+ "\nreceiver(%s) state %d\n",
+ vdec->vf_provider_name,
+ state);
+ }
+ mmjpeg_debug_print(DECODE_ID(hw), 0,
+ "%s, newq(%d/%d), dispq(%d/%d) vf peek/get/put (%d/%d/%d)\n",
+ __func__,
+ kfifo_len(&hw->newframe_q),
+ VF_POOL_SIZE,
+ kfifo_len(&hw->display_q),
+ VF_POOL_SIZE,
+ hw->peek_num,
+ hw->get_num,
+ hw->put_num
+ );
+ mmjpeg_debug_print(DECODE_ID(hw), 0,
+ "VIFF_BIT_CNT=0x%x\n",
+ READ_VREG(VIFF_BIT_CNT));
+ mmjpeg_debug_print(DECODE_ID(hw), 0,
+ "VLD_MEM_VIFIFO_LEVEL=0x%x\n",
+ READ_VREG(VLD_MEM_VIFIFO_LEVEL));
+ mmjpeg_debug_print(DECODE_ID(hw), 0,
+ "VLD_MEM_VIFIFO_WP=0x%x\n",
+ READ_VREG(VLD_MEM_VIFIFO_WP));
+ mmjpeg_debug_print(DECODE_ID(hw), 0,
+ "VLD_MEM_VIFIFO_RP=0x%x\n",
+ READ_VREG(VLD_MEM_VIFIFO_RP));
+ mmjpeg_debug_print(DECODE_ID(hw), 0,
+ "PARSER_VIDEO_RP=0x%x\n",
+ STBUF_READ(&vdec->vbuf, get_rp));
+ mmjpeg_debug_print(DECODE_ID(hw), 0,
+ "PARSER_VIDEO_WP=0x%x\n",
+ STBUF_READ(&vdec->vbuf, get_wp));
+ if (input_frame_based(vdec) &&
+ debug_enable & 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;
+
+ mmjpeg_debug_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)
+ mmjpeg_debug_print(DECODE_ID(hw),
+ PRINT_FRAMEBASE_DATA,
+ "%06x:", jj);
+ mmjpeg_debug_print(DECODE_ID(hw),
+ PRINT_FRAMEBASE_DATA,
+ "%02x ", data[jj]);
+ if (((jj + 1) & 0xf) == 0)
+ mmjpeg_debug_print(DECODE_ID(hw),
+ PRINT_FRAMEBASE_DATA,
+ "\n");
+ }
+
+ if (!hw->chunk->block->is_mapped)
+ codec_mm_unmap_phyaddr(data);
+ }
+ }
+}
+static void reset_process_time(struct vdec_mjpeg_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_mjpeg_hw_s *hw)
+{
+ hw->decode_timeout_count = 2;
+ hw->start_process_time = jiffies;
+}
+
+static void timeout_process(struct vdec_mjpeg_hw_s *hw)
+{
+ amvdec_stop();
+ mmjpeg_debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR,
+ "%s decoder timeout\n", __func__);
+ hw->dec_result = DEC_RESULT_DONE;
+ reset_process_time(hw);
+ vdec_schedule_work(&hw->work);
+}
+
+static void check_timer_func(unsigned long arg)
+{
+ struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)arg;
+ struct vdec_s *vdec = hw_to_vdec(hw);
+ int timeout_val = decode_timeout_val;
+
+ mmjpeg_debug_print(DECODE_ID(hw), PRINT_FLAG_VLD_DETAIL,
+ "%s: status:nstatus=%d:%d\n",
+ __func__, vdec->status, vdec->next_status);
+ mmjpeg_debug_print(DECODE_ID(hw), PRINT_FLAG_VLD_DETAIL,
+ "%s: %d,buftl=%x:%x:%x:%x\n",
+ __func__, __LINE__,
+ READ_VREG(VLD_MEM_VIFIFO_BUF_CNTL),
+ STBUF_READ(&vdec->vbuf, get_wp),
+ READ_VREG(VLD_MEM_VIFIFO_LEVEL),
+ READ_VREG(VLD_MEM_VIFIFO_WP));
+
+ 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 (((debug_enable & PRINT_FLAG_TIMEOUT_STATUS) == 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(DEC_STATUS_REG) == DEC_DECODE_TIMEOUT) {
+ pr_info("ucode DEC_DECODE_TIMEOUT\n");
+ if (hw->decode_timeout_count > 0)
+ hw->decode_timeout_count--;
+ if (hw->decode_timeout_count == 0)
+ timeout_process(hw);
+ WRITE_VREG(DEC_STATUS_REG, 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 vmjpeg_v4l_alloc_buff_config_canvas(struct vdec_mjpeg_hw_s *hw, int i)
+{
+ int ret;
+ u32 canvas;
+ ulong decbuf_start = 0, decbuf_u_start = 0, decbuf_v_start = 0;
+ int decbuf_y_size = 0, decbuf_u_size = 0, decbuf_v_size = 0;
+ u32 canvas_width = 0, canvas_height = 0;
+ struct vdec_s *vdec = hw_to_vdec(hw);
+ struct vdec_v4l2_buffer *fb = NULL;
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(hw->v4l2_ctx);
+
+ if (hw->buffer_spec[i].v4l_ref_buf_addr)
+ return 0;
+
+ ret = vdec_v4l_get_buffer(hw->v4l2_ctx, &fb);
+ if (ret < 0) {
+ mmjpeg_debug_print(DECODE_ID(hw), 0,
+ "[%d] get fb fail.\n",
+ ((struct aml_vcodec_ctx *)
+ (hw->v4l2_ctx))->id);
+ return ret;
+ }
+
+ if (!hw->frame_width || !hw->frame_height) {
+ struct vdec_pic_info pic;
+ vdec_v4l_get_pic_info(ctx, &pic);
+ hw->frame_width = pic.visible_width;
+ hw->frame_height = pic.visible_height;
+ mmjpeg_debug_print(DECODE_ID(hw), 0,
+ "[%d] set %d x %d from IF layer\n", ctx->id,
+ hw->frame_width, hw->frame_height);
+ }
+
+ hw->buffer_spec[i].v4l_ref_buf_addr = (ulong)fb;
+ if (fb->num_planes == 1) {
+ decbuf_start = fb->m.mem[0].addr;
+ decbuf_y_size = fb->m.mem[0].offset;
+ decbuf_u_start = decbuf_start + decbuf_y_size;
+ decbuf_u_size = decbuf_y_size / 4;
+ decbuf_v_start = decbuf_u_start + decbuf_u_size;
+ decbuf_v_size = decbuf_u_size;
+ canvas_width = ALIGN(hw->frame_width, 64);
+ canvas_height = ALIGN(hw->frame_height, 64);
+ fb->m.mem[0].bytes_used = fb->m.mem[0].size;
+ } else if (fb->num_planes == 2) {
+ decbuf_start = fb->m.mem[0].addr;
+ decbuf_y_size = fb->m.mem[0].size;
+ decbuf_u_start = fb->m.mem[1].addr;
+ decbuf_u_size = fb->m.mem[1].size;
+ decbuf_v_start = decbuf_u_start + decbuf_u_size;
+ decbuf_v_size = decbuf_u_size;
+ canvas_width = ALIGN(hw->frame_width, 64);
+ canvas_height = ALIGN(hw->frame_height, 64);
+ fb->m.mem[0].bytes_used = fb->m.mem[0].size;
+ fb->m.mem[1].bytes_used = fb->m.mem[1].size;
+ } else if (fb->num_planes == 3) {
+ decbuf_start = fb->m.mem[0].addr;
+ decbuf_y_size = fb->m.mem[0].size;
+ decbuf_u_start = fb->m.mem[1].addr;
+ decbuf_u_size = fb->m.mem[1].size;
+ decbuf_v_start = fb->m.mem[2].addr;
+ decbuf_v_size = fb->m.mem[2].size;
+ canvas_width = ALIGN(hw->frame_width, 64);
+ canvas_height = ALIGN(hw->frame_height, 64);
+ fb->m.mem[0].bytes_used = fb->m.mem[0].size;
+ fb->m.mem[1].bytes_used = fb->m.mem[1].size;
+ fb->m.mem[2].bytes_used = fb->m.mem[2].size;
+ }
+
+ mmjpeg_debug_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL,
+ "[%d] v4l ref buf addr: 0x%px\n", ctx->id, fb);
+
+ 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);
+ if (hw->buffer_spec[i].v_canvas_index == -1)
+ hw->buffer_spec[i].v_canvas_index =
+ vdec->get_canvas_ex(CORE_MASK_VDEC_1, vdec->id);
+ } else {
+ canvas = vdec->get_canvas(i, 3);
+ 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);
+ }
+
+ hw->buffer_spec[i].canvas_config[0].phy_addr =
+ decbuf_start;
+ hw->buffer_spec[i].canvas_config[0].width =
+ canvas_width;
+ hw->buffer_spec[i].canvas_config[0].height =
+ canvas_height;
+ hw->buffer_spec[i].canvas_config[0].block_mode =
+ hw->canvas_mode;
+ hw->buffer_spec[i].canvas_config[0].endian =
+ hw->canvas_endian;
+
+ canvas_config_config(hw->buffer_spec[i].y_canvas_index,
+ &hw->buffer_spec[i].canvas_config[0]);
+
+ hw->buffer_spec[i].canvas_config[1].phy_addr =
+ decbuf_u_start;
+ hw->buffer_spec[i].canvas_config[1].width =
+ canvas_width / 2;
+ hw->buffer_spec[i].canvas_config[1].height =
+ canvas_height / 2;
+ hw->buffer_spec[i].canvas_config[1].block_mode =
+ hw->canvas_mode;
+ hw->buffer_spec[i].canvas_config[1].endian =
+ hw->canvas_endian;
+
+ canvas_config_config(hw->buffer_spec[i].u_canvas_index,
+ &hw->buffer_spec[i].canvas_config[1]);
+
+ hw->buffer_spec[i].canvas_config[2].phy_addr =
+ decbuf_v_start;
+ hw->buffer_spec[i].canvas_config[2].width =
+ canvas_width / 2;
+ hw->buffer_spec[i].canvas_config[2].height =
+ canvas_height / 2;
+ hw->buffer_spec[i].canvas_config[2].block_mode =
+ hw->canvas_mode;
+ hw->buffer_spec[i].canvas_config[2].endian =
+ hw->canvas_endian;
+
+ canvas_config_config(hw->buffer_spec[i].v_canvas_index,
+ &hw->buffer_spec[i].canvas_config[2]);
+
+ /* mjpeg decoder canvas need to be revert to match display. */
+ hw->buffer_spec[i].canvas_config[0].endian = hw->canvas_endian ? 0 : 7;
+ hw->buffer_spec[i].canvas_config[1].endian = hw->canvas_endian ? 0 : 7;
+ hw->buffer_spec[i].canvas_config[2].endian = hw->canvas_endian ? 0 : 7;
+
+ return 0;
+}
+
+static int vmjpeg_get_buf_num(struct vdec_mjpeg_hw_s *hw)
+{
+ int buf_num = DECODE_BUFFER_NUM_DEF;
+
+ buf_num += hw->dynamic_buf_num_margin;
+
+ if (buf_num > DECODE_BUFFER_NUM_MAX)
+ buf_num = DECODE_BUFFER_NUM_MAX;
+
+ return buf_num;
+}
+
+static bool is_enough_free_buffer(struct vdec_mjpeg_hw_s *hw)
+{
+ int i;
+
+ for (i = 0; i < hw->buf_num; i++) {
+ if (hw->vfbuf_use[i] == 0)
+ break;
+ }
+
+ return i == hw->buf_num ? false : true;
+}
+
+static int find_free_buffer(struct vdec_mjpeg_hw_s *hw)
+{
+ int i;
+
+ for (i = 0; i < hw->buf_num; i++) {
+ if (hw->vfbuf_use[i] == 0)
+ break;
+ }
+
+ if (i == hw->buf_num)
+ return -1;
+
+ 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) {
+ /*run to parser csd data*/
+ i = 0;
+ } else {
+ if (vmjpeg_v4l_alloc_buff_config_canvas(hw, i))
+ return -1;
+ }
+ }
+
+ return i;
+}
+
+static int vmjpeg_hw_ctx_restore(struct vdec_mjpeg_hw_s *hw)
+{
+ struct buffer_spec_s *buff_spec;
+ int index, i;
+
+ index = find_free_buffer(hw);
+ if (index < 0)
+ return -1;
+
+ WRITE_VREG(DOS_SW_RESET0, (1 << 7) | (1 << 6));
+ WRITE_VREG(DOS_SW_RESET0, 0);
+
+ if (!hw->init_flag) {
+ vmjpeg_canvas_init(hw);
+ } else {
+ if (!hw->is_used_v4l) {
+ for (i = 0; i < hw->buf_num; i++) {
+ buff_spec = &hw->buffer_spec[i];
+ canvas_config_config(buff_spec->y_canvas_index,
+ &buff_spec->canvas_config[0]);
+ canvas_config_config(buff_spec->u_canvas_index,
+ &buff_spec->canvas_config[1]);
+ canvas_config_config(buff_spec->v_canvas_index,
+ &buff_spec->canvas_config[2]);
+ }
+ }
+ }
+
+ /* find next decode buffer index */
+ WRITE_VREG(AV_SCRATCH_4, spec2canvas(&hw->buffer_spec[index]));
+ WRITE_VREG(AV_SCRATCH_5, index | 1 << 24);
+ init_scaler();
+
+ /* clear buffer IN/OUT registers */
+ WRITE_VREG(MREG_TO_AMRISC, 0);
+ WRITE_VREG(MREG_FROM_AMRISC, 0);
+
+ WRITE_VREG(MCPU_INTR_MSK, 0xffff);
+ WRITE_VREG(MREG_DECODE_PARAM, (hw->frame_height << 4) | 0x8000);
+
+ /* clear mailbox interrupt */
+ WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
+ /* enable mailbox interrupt */
+ WRITE_VREG(ASSIST_MBOX1_MASK, 1);
+ /* set interrupt mapping for vld */
+ WRITE_VREG(ASSIST_AMR1_INT8, 8);
+#if 1/*MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6*/
+ CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17);
+#endif
+ return 0;
+}
+
+static s32 vmjpeg_init(struct vdec_s *vdec)
+{
+ int i;
+ int size = -1, fw_size = 0x1000 * 16;
+ struct firmware_s *fw = NULL;
+ struct vdec_mjpeg_hw_s *hw =
+ (struct vdec_mjpeg_hw_s *)vdec->private;
+
+ fw = vmalloc(sizeof(struct firmware_s) + fw_size);
+ if (IS_ERR_OR_NULL(fw))
+ return -ENOMEM;
+
+ size = get_firmware_data(VIDEO_DEC_MJPEG_MULTI, fw->data);
+ if (size < 0) {
+ pr_err("get firmware fail.");
+ vfree(fw);
+ return -1;
+ }
+
+ fw->len = size;
+ hw->fw = fw;
+
+ if (hw->is_used_v4l) {
+ hw->frame_width = 0;
+ hw->frame_height = 0;
+ } else {
+ hw->frame_width = hw->vmjpeg_amstream_dec_info.width;
+ hw->frame_height = hw->vmjpeg_amstream_dec_info.height;
+ }
+ hw->frame_dur = ((hw->vmjpeg_amstream_dec_info.rate) ?
+ hw->vmjpeg_amstream_dec_info.rate : 3840);
+ hw->saved_resolution = 0;
+ hw->eos = 0;
+ hw->init_flag = 0;
+ hw->frame_num = 0;
+ hw->put_num = 0;
+ hw->run_count = 0;
+ hw->not_run_ready = 0;
+ hw->input_empty = 0;
+ hw->peek_num = 0;
+ hw->get_num = 0;
+ for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++)
+ hw->vfbuf_use[i] = 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[i];
+
+ hw->vfpool[i].index = -1;
+ kfifo_put(&hw->newframe_q, vf);
+ }
+
+ if (hw->mm_blk_handle) {
+ 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);
+
+ init_timer(&hw->check_timer);
+
+ hw->check_timer.data = (unsigned long)hw;
+ hw->check_timer.function = check_timer_func;
+ hw->check_timer.expires = jiffies + CHECK_INTERVAL;
+ /*add_timer(&hw->check_timer);*/
+ hw->stat |= STAT_TIMER_ARM;
+ hw->stat |= STAT_ISR_REG;
+
+ WRITE_VREG(DECODE_STOP_POS, udebug_flag);
+ INIT_WORK(&hw->work, vmjpeg_work);
+ pr_info("w:h=%d:%d\n", hw->frame_width, hw->frame_height);
+ return 0;
+}
+
+static unsigned long run_ready(struct vdec_s *vdec,
+ unsigned long mask)
+{
+ struct vdec_mjpeg_hw_s *hw =
+ (struct vdec_mjpeg_hw_s *)vdec->private;
+ hw->not_run_ready++;
+ if (hw->eos)
+ return 0;
+ 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;
+ }
+
+ 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->v4l_codec_dpb_ready &&
+ v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) <
+ run_ready_min_buf_num)
+ return 0;
+ } else {
+ if (ctx->v4l_resolution_change)
+ return 0;
+ }
+ } else if (!ctx->v4l_codec_dpb_ready) {
+ if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) <
+ run_ready_min_buf_num)
+ return 0;
+ }
+ }
+
+ if (!is_enough_free_buffer(hw)) {
+ hw->buffer_not_ready++;
+ return 0;
+ }
+
+ hw->not_run_ready = 0;
+ hw->buffer_not_ready = 0;
+ if (vdec->parallel_dec == 1)
+ return CORE_MASK_VDEC_1;
+ else
+ return CORE_MASK_VDEC_1 | CORE_MASK_HEVC;
+}
+
+static void run(struct vdec_s *vdec, unsigned long mask,
+ void (*callback)(struct vdec_s *, void *), void *arg)
+{
+ struct vdec_mjpeg_hw_s *hw =
+ (struct vdec_mjpeg_hw_s *)vdec->private;
+ int i, ret;
+
+ hw->vdec_cb_arg = arg;
+ hw->vdec_cb = callback;
+
+ hw->run_count++;
+ vdec_reset_core(vdec);
+ for (i = 0; i < hw->buf_num; i++) {
+ if (hw->vfbuf_use[i] == 0)
+ break;
+ }
+
+ if (i == hw->buf_num) {
+ hw->dec_result = DEC_RESULT_AGAIN;
+ vdec_schedule_work(&hw->work);
+ return;
+ }
+
+ ret = vdec_prepare_input(vdec, &hw->chunk);
+ if (ret <= 0) {
+ hw->input_empty++;
+ mmjpeg_debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW,
+ "%s: %d,r=%d,buftl=%x:%x:%x\n",
+ __func__, __LINE__, ret,
+ READ_VREG(VLD_MEM_VIFIFO_BUF_CNTL),
+ STBUF_READ(&vdec->vbuf, get_rp),
+ READ_VREG(VLD_MEM_VIFIFO_WP));
+
+ hw->dec_result = DEC_RESULT_AGAIN;
+ vdec_schedule_work(&hw->work);
+ return;
+ }
+ hw->input_empty = 0;
+ hw->dec_result = DEC_RESULT_NONE;
+ if (vdec->mc_loaded) {
+ /*firmware have load before,
+ and not changes to another.
+ ignore reload.
+ */
+ } else {
+ ret = amvdec_vdec_loadmc_ex(VFORMAT_MJPEG, "mmjpeg", vdec, hw->fw->data);
+ if (ret < 0) {
+ pr_err("[%d] MMJPEG: the %s fw loading failed, err: %x\n",
+ vdec->id, 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_MJPEG;
+ }
+/* if (amvdec_vdec_loadmc_buf_ex(vdec, hw->fw->data, hw->fw->len) < 0) {
+ pr_err("%s: Error amvdec_loadmc fail\n", __func__);
+ return;
+ }*/
+
+ if (vmjpeg_hw_ctx_restore(hw) < 0) {
+ hw->dec_result = DEC_RESULT_ERROR;
+ mmjpeg_debug_print(DECODE_ID(hw), 0,
+ "amvdec_mmjpeg: error HW context restore\n");
+ vdec_schedule_work(&hw->work);
+ return;
+ }
+#if 0
+ vdec_enable_input(vdec);
+ mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL);
+#endif
+ hw->stat |= STAT_MC_LOAD;
+ start_process_time(hw);
+ hw->last_vld_level = 0;
+ mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL);
+ amvdec_start();
+ vdec_enable_input(vdec);
+ hw->stat |= STAT_VDEC_RUN;
+ hw->init_flag = 1;
+
+ mmjpeg_debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW,
+ "%s (0x%x 0x%x 0x%x) vldcrl 0x%x bitcnt 0x%x powerctl 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ __func__,
+ READ_VREG(VLD_MEM_VIFIFO_LEVEL),
+ READ_VREG(VLD_MEM_VIFIFO_WP),
+ READ_VREG(VLD_MEM_VIFIFO_RP),
+ READ_VREG(VLD_DECODE_CONTROL),
+ READ_VREG(VIFF_BIT_CNT),
+ READ_VREG(POWER_CTL_VLD),
+ READ_VREG(VLD_MEM_VIFIFO_START_PTR),
+ READ_VREG(VLD_MEM_VIFIFO_CURR_PTR),
+ READ_VREG(VLD_MEM_VIFIFO_CONTROL),
+ READ_VREG(VLD_MEM_VIFIFO_BUF_CNTL),
+ READ_VREG(VLD_MEM_VIFIFO_END_PTR));
+}
+static void wait_vmjpeg_search_done(struct vdec_mjpeg_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 > 1000) {
+ mmjpeg_debug_print(DECODE_ID(hw), 0,
+ "%s, 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 int notify_v4l_eos(struct vdec_s *vdec)
+{
+ struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)vdec->private;
+ struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx);
+ struct vframe_s *vf = NULL;
+ struct vdec_v4l2_buffer *fb = NULL;
+ int index = -1;
+
+ if (hw->eos) {
+ if (kfifo_get(&hw->newframe_q, &vf) == 0 || vf == NULL) {
+ mmjpeg_debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR,
+ "%s fatal error, no available buffer slot.\n",
+ __func__);
+ return -1;
+ }
+
+ if (hw->is_used_v4l) {
+ index = find_free_buffer(hw);
+ if ((index == -1) && vdec_v4l_get_buffer(hw->v4l2_ctx, &fb)) {
+ pr_err("[%d] get fb fail.\n", ctx->id);
+ return -1;
+ }
+ }
+
+ vf->type |= VIDTYPE_V4L_EOS;
+ vf->timestamp = ULONG_MAX;
+ vf->v4l_mem_handle = (index == -1) ? (ulong)fb :
+ hw->buffer_spec[index].v4l_ref_buf_addr;
+ vf->flag = VFRAME_FLAG_EMPTY_FRAME_V4L;
+
+ vdec_vframe_ready(vdec, vf);
+ kfifo_put(&hw->display_q, (const struct vframe_s *)vf);
+ vf_notify_receiver(vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
+
+ pr_info("[%d] mpeg12 EOS notify.\n", (hw->is_used_v4l)?ctx->id:vdec->id);
+ }
+
+ return 0;
+}
+
+static void vmjpeg_work(struct work_struct *work)
+{
+ struct vdec_mjpeg_hw_s *hw = container_of(work,
+ struct vdec_mjpeg_hw_s, work);
+ struct vdec_s *vdec = hw_to_vdec(hw);
+
+ mmjpeg_debug_print(DECODE_ID(hw), PRINT_FLAG_BUFFER_DETAIL,
+ "%s: result=%d,len=%d:%d\n",
+ __func__, hw->dec_result,
+ kfifo_len(&hw->newframe_q),
+ kfifo_len(&hw->display_q));
+ if (hw->dec_result == DEC_RESULT_DONE) {
+ vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk);
+ hw->chunk = NULL;
+ } 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(hw_to_vdec(hw))) {
+ hw->dec_result = DEC_RESULT_EOS;
+ vdec_schedule_work(&hw->work);
+ /*pr_info("%s: return\n",
+ __func__);*/
+ return;
+ }
+ } else if (hw->dec_result == DEC_RESULT_FORCE_EXIT) {
+ pr_info("%s: force exit\n", __func__);
+ if (hw->stat & STAT_ISR_REG) {
+ amvdec_stop();
+ vdec_free_irq(VDEC_IRQ_1, (void *)hw);
+ hw->stat &= ~STAT_ISR_REG;
+ }
+ } else if (hw->dec_result == DEC_RESULT_EOS) {
+ pr_info("%s: end of stream\n", __func__);
+ if (hw->stat & STAT_VDEC_RUN) {
+ amvdec_stop();
+ hw->stat &= ~STAT_VDEC_RUN;
+ }
+ hw->eos = 1;
+ notify_v4l_eos(vdec);
+
+ vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk);
+ hw->chunk = NULL;
+ vdec_clean_input(hw_to_vdec(hw));
+ }
+ if (hw->stat & STAT_VDEC_RUN) {
+ amvdec_stop();
+ hw->stat &= ~STAT_VDEC_RUN;
+ }
+ /*disable mbox interrupt */
+ WRITE_VREG(ASSIST_MBOX1_MASK, 0);
+ wait_vmjpeg_search_done(hw);
+
+ 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);
+ }
+
+ /* mark itself has all HW resource released and input released */
+ 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);
+ }
+ del_timer_sync(&hw->check_timer);
+ hw->stat &= ~STAT_TIMER_ARM;
+
+ if (hw->vdec_cb)
+ hw->vdec_cb(hw_to_vdec(hw), hw->vdec_cb_arg);
+}
+
+static int vmjpeg_stop(struct vdec_mjpeg_hw_s *hw)
+{
+ pr_info("%s ...count = %d\n", __func__, hw->frame_num);
+
+ if (hw->stat & STAT_VDEC_RUN) {
+ amvdec_stop();
+ pr_info("%s amvdec_stop\n", __func__);
+ 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);
+ hw->init_flag = 0;
+
+ if (hw->mm_blk_handle) {
+ decoder_bmmu_box_free(hw->mm_blk_handle);
+ hw->mm_blk_handle = NULL;
+ }
+
+ if (hw->fw) {
+ vfree(hw->fw);
+ hw->fw = NULL;
+ }
+
+ return 0;
+}
+
+static int ammvdec_mjpeg_probe(struct platform_device *pdev)
+{
+ struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
+ struct vdec_mjpeg_hw_s *hw = NULL;
+ int config_val = 0;
+
+ if (pdata == NULL) {
+ pr_info("ammvdec_mjpeg memory resource undefined.\n");
+ return -EFAULT;
+ }
+
+ hw = vzalloc(sizeof(struct vdec_mjpeg_hw_s));
+ if (hw == NULL) {
+ pr_info("\nammvdec_mjpeg device data allocation failed\n");
+ return -ENOMEM;
+ }
+
+ /* the ctx from v4l2 driver. */
+ hw->v4l2_ctx = pdata->private;
+
+ pdata->private = hw;
+ pdata->dec_status = vmjpeg_dec_status;
+
+ pdata->run = run;
+ pdata->run_ready = run_ready;
+ pdata->irq_handler = vmjpeg_isr;
+ pdata->threaded_irq_handler = vmjpeg_isr_thread_fn;
+ pdata->dump_state = vmjpeg_dump_state;
+
+ snprintf(hw->vdec_name, sizeof(hw->vdec_name),
+ "vmjpeg-%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);
+
+ if (pdata->parallel_dec == 1) {
+ int i;
+ for (i = 0; i < DECODE_BUFFER_NUM_MAX; 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;
+ }
+ }
+
+ if (pdata->use_vfm_path)
+ snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE,
+ VFM_DEC_PROVIDER_NAME);
+ else
+ snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE,
+ PROVIDER_NAME ".%02x", pdev->id & 0xff);
+
+ platform_set_drvdata(pdev, pdata);
+ hw->platform_dev = pdev;
+
+ if (((debug_enable & IGNORE_PARAM_FROM_CONFIG) == 0) && pdata->config_len) {
+ mmjpeg_debug_print(DECODE_ID(hw), 0, "pdata->config: %s\n", pdata->config);
+ if (get_config_int(pdata->config, "parm_v4l_buffer_margin",
+ &config_val) == 0)
+ hw->dynamic_buf_num_margin = config_val;
+ else
+ hw->dynamic_buf_num_margin = dynamic_buf_num_margin;
+
+ 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_canvas_mem_endian",
+ &config_val) == 0)
+ hw->canvas_endian = config_val;
+
+ 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_v4l_codec_enable",
+ &config_val) == 0)
+ hw->is_used_v4l = config_val;
+ } else {
+ hw->dynamic_buf_num_margin = dynamic_buf_num_margin;
+ }
+
+ hw->buf_num = vmjpeg_get_buf_num(hw);
+
+ vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name,
+ &vf_provider_ops, pdata);
+
+ platform_set_drvdata(pdev, pdata);
+
+ hw->platform_dev = pdev;
+
+ vdec_source_changed(VFORMAT_MJPEG,
+ 1920, 1080, 60);
+ if (vmjpeg_init(pdata) < 0) {
+ pr_info("ammvdec_mjpeg init failed.\n");
+ if (hw) {
+ vfree(hw);
+ hw = NULL;
+ }
+ pdata->dec_status = NULL;
+ return -ENODEV;
+ }
+ 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);
+ }
+
+ return 0;
+}
+
+static int ammvdec_mjpeg_remove(struct platform_device *pdev)
+{
+ struct vdec_mjpeg_hw_s *hw =
+ (struct vdec_mjpeg_hw_s *)
+ (((struct vdec_s *)(platform_get_drvdata(pdev)))->private);
+ struct vdec_s *vdec;
+ int i;
+
+ if (!hw)
+ return -1;
+ vdec = hw_to_vdec(hw);
+
+ vmjpeg_stop(hw);
+
+ 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(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);
+ }
+ }
+ vfree(hw);
+
+ pr_info("%s\n", __func__);
+ return 0;
+}
+
+/****************************************/
+#ifdef CONFIG_PM
+static int mmjpeg_suspend(struct device *dev)
+{
+ amvdec_suspend(to_platform_device(dev), dev->power.power_state);
+ return 0;
+}
+
+static int mmjpeg_resume(struct device *dev)
+{
+ amvdec_resume(to_platform_device(dev));
+ return 0;
+}
+
+static const struct dev_pm_ops mmjpeg_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mmjpeg_suspend, mmjpeg_resume)
+};
+#endif
+
+static struct platform_driver ammvdec_mjpeg_driver = {
+ .probe = ammvdec_mjpeg_probe,
+ .remove = ammvdec_mjpeg_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &mmjpeg_pm_ops,
+#endif
+ }
+};
+
+static struct codec_profile_t ammvdec_mjpeg_profile = {
+ .name = "mmjpeg",
+ .profile = ""
+};
+
+static int __init ammvdec_mjpeg_driver_init_module(void)
+{
+ if (platform_driver_register(&ammvdec_mjpeg_driver)) {
+ pr_err("failed to register ammvdec_mjpeg driver\n");
+ return -ENODEV;
+ }
+ vcodec_profile_register(&ammvdec_mjpeg_profile);
+ return 0;
+}
+
+static void __exit ammvdec_mjpeg_driver_remove_module(void)
+{
+ platform_driver_unregister(&ammvdec_mjpeg_driver);
+}
+
+/****************************************/
+module_param(debug_enable, uint, 0664);
+MODULE_PARM_DESC(debug_enable, "\n debug enable\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(udebug_flag, uint, 0664);
+MODULE_PARM_DESC(udebug_flag, "\n amvdec_mmpeg12 udebug_flag\n");
+
+module_param(dynamic_buf_num_margin, uint, 0664);
+MODULE_PARM_DESC(dynamic_buf_num_margin, "\n dynamic_buf_num_margin\n");
+
+module_param(decode_timeout_val, uint, 0664);
+MODULE_PARM_DESC(decode_timeout_val, "\n ammvdec_mjpeg decode_timeout_val\n");
+
+module_param_array(max_process_time, uint, &max_decode_instance_num, 0664);
+
+module_param(radr, uint, 0664);
+MODULE_PARM_DESC(radr, "\nradr\n");
+
+module_param(start_decode_buf_level, uint, 0664);
+MODULE_PARM_DESC(start_decode_buf_level, "\nstart_decode_buf_level\n");
+
+module_param(rval, uint, 0664);
+MODULE_PARM_DESC(rval, "\nrval\n");
+
+module_param(without_display_mode, uint, 0664);
+MODULE_PARM_DESC(without_display_mode, "\n without_display_mode\n");
+
+module_init(ammvdec_mjpeg_driver_init_module);
+module_exit(ammvdec_mjpeg_driver_remove_module);
+
+MODULE_DESCRIPTION("AMLOGIC MJMPEG Video Decoder Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tim Yao <timyao@amlogic.com>");
diff --git a/drivers/frame_provider/decoder/mpeg12/Makefile b/drivers/frame_provider/decoder/mpeg12/Makefile
new file mode 100644
index 0000000..34f78c4
--- /dev/null
+++ b/drivers/frame_provider/decoder/mpeg12/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_MPEG12) += amvdec_mpeg12.o
+amvdec_mpeg12-objs += vmpeg12.o
+
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_MPEG2_MULTI) += amvdec_mmpeg12.o
+amvdec_mmpeg12-objs += vmpeg12_multi.o
diff --git a/drivers/frame_provider/decoder/mpeg12/vmpeg12.c b/drivers/frame_provider/decoder/mpeg12/vmpeg12.c
new file mode 100644
index 0000000..29757a0
--- /dev/null
+++ b/drivers/frame_provider/decoder/mpeg12/vmpeg12.c
@@ -0,0 +1,2241 @@
+/*
+ * drivers/amlogic/amports/vmpeg12.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/kfifo.h>
+#include <linux/platform_device.h>
+#include <linux/amlogic/media/frame_sync/ptsserv.h>
+#include <linux/amlogic/media/utils/amstream.h>
+#include <linux/amlogic/media/canvas/canvas.h>
+#include <linux/module.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/cpu_version.h>
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "vmpeg12.h"
+#include <linux/amlogic/media/registers/register.h>
+#include "../../../stream_input/amports/amports_priv.h"
+#include "../utils/decoder_mmu_box.h"
+#include "../utils/decoder_bmmu_box.h"
+#include <linux/uaccess.h>
+#include <linux/amlogic/media/codec_mm/configs.h>
+#include <linux/amlogic/tee.h>
+
+
+
+#ifdef CONFIG_AM_VDEC_MPEG12_LOG
+#define AMLOG
+#define LOG_LEVEL_VAR amlog_level_vmpeg
+#define LOG_MASK_VAR amlog_mask_vmpeg
+#define LOG_LEVEL_ERROR 0
+#define LOG_LEVEL_INFO 1
+#define LOG_LEVEL_DESC "0:ERROR, 1:INFO"
+#endif
+#include <linux/amlogic/media/utils/amlog.h>
+MODULE_AMLOG(LOG_LEVEL_ERROR, 0, LOG_LEVEL_DESC, LOG_DEFAULT_MASK_DESC);
+
+#include "../utils/amvdec.h"
+#include "../utils/vdec.h"
+#include "../utils/firmware.h"
+#include "../../../common/chips/decoder_cpu_ver_info.h"
+
+#define DRIVER_NAME "amvdec_mpeg12"
+#define MODULE_NAME "amvdec_mpeg12"
+
+/* protocol registers */
+#define MREG_SEQ_INFO AV_SCRATCH_4
+#define MREG_PIC_INFO AV_SCRATCH_5
+#define MREG_PIC_WIDTH AV_SCRATCH_6
+#define MREG_PIC_HEIGHT AV_SCRATCH_7
+#define MREG_BUFFERIN AV_SCRATCH_8
+#define MREG_BUFFEROUT AV_SCRATCH_9
+
+#define MREG_CMD AV_SCRATCH_A
+#define MREG_CO_MV_START AV_SCRATCH_B
+#define MREG_ERROR_COUNT AV_SCRATCH_C
+#define MREG_FRAME_OFFSET AV_SCRATCH_D
+#define MREG_WAIT_BUFFER AV_SCRATCH_E
+#define MREG_FATAL_ERROR AV_SCRATCH_F
+#define MREG_FORCE_I_RDY AV_SCRATCH_G
+
+#define PICINFO_ERROR 0x80000000
+#define PICINFO_TYPE_MASK 0x00030000
+#define PICINFO_TYPE_I 0x00000000
+#define PICINFO_TYPE_P 0x00010000
+#define PICINFO_TYPE_B 0x00020000
+
+#define PICINFO_PROG 0x8000
+#define PICINFO_RPT_FIRST 0x4000
+#define PICINFO_TOP_FIRST 0x2000
+#define PICINFO_FRAME 0x1000
+
+#define SEQINFO_EXT_AVAILABLE 0x80000000
+#define SEQINFO_PROG 0x00010000
+#define CCBUF_SIZE (5*1024)
+
+#define VF_POOL_SIZE 32
+#define DECODE_BUFFER_NUM_MAX 8
+#define PUT_INTERVAL (HZ/100)
+#define WORKSPACE_SIZE (2*SZ_64K)
+#define MAX_BMMU_BUFFER_NUM (DECODE_BUFFER_NUM_MAX + 1)
+
+
+#define INCPTR(p) ptr_atomic_wrap_inc(&p)
+
+#define DEC_CONTROL_FLAG_FORCE_2500_720_576_INTERLACE 0x0002
+#define DEC_CONTROL_FLAG_FORCE_3000_704_480_INTERLACE 0x0004
+#define DEC_CONTROL_FLAG_FORCE_2500_704_576_INTERLACE 0x0008
+#define DEC_CONTROL_FLAG_FORCE_2500_544_576_INTERLACE 0x0010
+#define DEC_CONTROL_FLAG_FORCE_2500_480_576_INTERLACE 0x0020
+#define DEC_CONTROL_INTERNAL_MASK 0x0fff
+#define DEC_CONTROL_FLAG_FORCE_SEQ_INTERLACE 0x1000
+
+#define INTERLACE_SEQ_ALWAYS
+
+#if 1/* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+#define NV21
+#endif
+
+
+enum {
+ FRAME_REPEAT_TOP,
+ FRAME_REPEAT_BOT,
+ FRAME_REPEAT_NONE
+};
+
+static struct vframe_s *vmpeg_vf_peek(void *);
+static struct vframe_s *vmpeg_vf_get(void *);
+static void vmpeg_vf_put(struct vframe_s *, void *);
+static int vmpeg_vf_states(struct vframe_states *states, void *);
+static int vmpeg_event_cb(int type, void *data, void *private_data);
+
+static int vmpeg12_prot_init(void);
+static void vmpeg12_local_init(void);
+
+static const char vmpeg12_dec_id[] = "vmpeg12-dev";
+#define PROVIDER_NAME "decoder.mpeg12"
+static const struct vframe_operations_s vmpeg_vf_provider = {
+ .peek = vmpeg_vf_peek,
+ .get = vmpeg_vf_get,
+ .put = vmpeg_vf_put,
+ .event_cb = vmpeg_event_cb,
+ .vf_states = vmpeg_vf_states,
+};
+static void *mm_blk_handle;
+static struct vframe_provider_s vmpeg_vf_prov;
+static int tvp_flag;
+
+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 const u32 frame_rate_tab[16] = {
+ 96000 / 30, 96000000 / 23976, 96000 / 24, 96000 / 25,
+ 9600000 / 2997, 96000 / 30, 96000 / 50, 9600000 / 5994,
+ 96000 / 60,
+ /* > 8 reserved, use 24 */
+ 96000 / 24, 96000 / 24, 96000 / 24, 96000 / 24,
+ 96000 / 24, 96000 / 24, 96000 / 24
+};
+
+static struct vframe_s vfpool[VF_POOL_SIZE];
+static struct vframe_s vfpool2[VF_POOL_SIZE];
+static int cur_pool_idx;
+static s32 vfbuf_use[DECODE_BUFFER_NUM_MAX];
+static u32 dec_control;
+static u32 frame_width, frame_height, frame_dur, frame_prog;
+static u32 saved_resolution;
+static struct timer_list recycle_timer;
+static u32 stat;
+static u32 buf_size = 32 * 1024 * 1024;
+static u32 ccbuf_phyAddress;
+static void *ccbuf_phyAddress_virt;
+static int ccbuf_phyAddress_is_remaped_nocache;
+static u32 lastpts;
+static u32 fr_hint_status;
+static u32 last_offset;
+static u32 ratio_control;
+
+
+static DEFINE_SPINLOCK(lock);
+
+static u32 frame_rpt_state;
+
+static struct dec_sysinfo vmpeg12_amstream_dec_info;
+static struct vdec_info *gvs;
+static struct vdec_s *vdec;
+
+/* for error handling */
+static s32 frame_force_skip_flag;
+static s32 error_frame_skip_level;
+static s32 wait_buffer_counter;
+static u32 first_i_frame_ready;
+static u32 force_first_i_ready;
+
+static struct work_struct userdata_push_work;
+static struct work_struct notify_work;
+static struct work_struct reset_work;
+static struct work_struct set_clk_work;
+static bool is_reset;
+
+static DEFINE_MUTEX(userdata_mutex);
+
+static void vmpeg12_create_userdata_manager(u8 *userdata_buf, int buf_len);
+
+struct mpeg12_userdata_recored_t {
+ struct userdata_meta_info_t meta_info;
+ u32 rec_start;
+ u32 rec_len;
+};
+
+#define USERDATA_FIFO_NUM 256
+
+struct mpeg12_userdata_info_t {
+ struct mpeg12_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 mpeg12_userdata_info_t *p_userdata_mgr;
+
+
+static inline int pool_index(struct vframe_s *vf)
+{
+ if ((vf >= &vfpool[0]) && (vf <= &vfpool[VF_POOL_SIZE - 1]))
+ return 0;
+ else if ((vf >= &vfpool2[0]) && (vf <= &vfpool2[VF_POOL_SIZE - 1]))
+ return 1;
+ else
+ return -1;
+}
+
+static inline u32 index2canvas(u32 index)
+{
+ const u32 canvas_tab[8] = {
+#ifdef NV21
+ 0x010100, 0x030302, 0x050504, 0x070706,
+ 0x090908, 0x0b0b0a, 0x0d0d0c, 0x0f0f0e
+#else
+ 0x020100, 0x050403, 0x080706, 0x0b0a09,
+ 0x0e0d0c, 0x11100f, 0x141312, 0x171615
+#endif
+ };
+
+ return canvas_tab[index];
+}
+
+static void set_frame_info(struct vframe_s *vf)
+{
+ unsigned int ar_bits;
+ u32 temp;
+
+#ifdef CONFIG_AM_VDEC_MPEG12_LOG
+ bool first = (frame_width == 0) && (frame_height == 0);
+#endif
+ temp = READ_VREG(MREG_PIC_WIDTH);
+ if (temp > 1920)
+ vf->width = frame_width = 1920;
+ else
+ vf->width = frame_width = temp;
+
+ temp = READ_VREG(MREG_PIC_HEIGHT);
+ if (temp > 1088)
+ vf->height = frame_height = 1088;
+ else
+ vf->height = frame_height = temp;
+
+ vf->flag = 0;
+
+ if (frame_dur > 0)
+ vf->duration = frame_dur;
+ else {
+ int index = (READ_VREG(MREG_SEQ_INFO) >> 4) & 0xf;
+ vf->duration = frame_dur = frame_rate_tab[index];
+ schedule_work(¬ify_work);
+ }
+
+ gvs->frame_dur = vf->duration;
+
+ ar_bits = READ_VREG(MREG_SEQ_INFO) & 0xf;
+
+ if (ar_bits == 0x2)
+ vf->ratio_control = 0xc0 << DISP_RATIO_ASPECT_RATIO_BIT;
+
+ else if (ar_bits == 0x3)
+ vf->ratio_control = 0x90 << DISP_RATIO_ASPECT_RATIO_BIT;
+
+ else if (ar_bits == 0x4)
+ vf->ratio_control = 0x74 << DISP_RATIO_ASPECT_RATIO_BIT;
+
+ else
+ vf->ratio_control = 0;
+
+ ratio_control = vf->ratio_control;
+
+ amlog_level_if(first, LOG_LEVEL_INFO,
+ "mpeg2dec: w(%d), h(%d), dur(%d), dur-ES(%d)\n",
+ frame_width, frame_height, frame_dur,
+ frame_rate_tab[(READ_VREG(MREG_SEQ_INFO) >> 4) & 0xf]);
+}
+
+static bool error_skip(u32 info, struct vframe_s *vf)
+{
+ if (error_frame_skip_level) {
+ /* skip error frame */
+ if ((info & PICINFO_ERROR) || (frame_force_skip_flag)) {
+ if ((info & PICINFO_ERROR) == 0) {
+ if ((info & PICINFO_TYPE_MASK) ==
+ PICINFO_TYPE_I)
+ frame_force_skip_flag = 0;
+ } else {
+ if (error_frame_skip_level >= 2)
+ frame_force_skip_flag = 1;
+ }
+ if ((info & PICINFO_ERROR) || (frame_force_skip_flag))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+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;
+ }
+ }
+}
+
+/*
+#define DUMP_USER_DATA
+*/
+#ifdef DUMP_USER_DATA
+static int last_wp;
+#define DUMP_USER_DATA_HEX
+
+
+#ifdef DUMP_USER_DATA_HEX
+static void print_data(unsigned char *pdata,
+ int len,
+ unsigned int flag,
+ unsigned int duration,
+ unsigned int vpts,
+ unsigned int vpts_valid,
+ int rec_id,
+ u32 reference)
+{
+ int nLeft;
+
+ nLeft = len;
+
+ pr_info("%d len:%d, flag:0x%x, dur:%d, vpts:0x%x, valid:%d, refer:%d\n",
+ rec_id, len, flag,
+ duration, vpts, vpts_valid,
+ reference);
+ 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;
+ }
+}
+#endif
+
+
+#define DEBUG_CC_DUMP_ASCII
+
+#ifdef DEBUG_CC_DUMP_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, 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;
+ }
+ }
+ switch (index) {
+ case 8:
+ pr_info("push poc:%d : %c %c %c %c %c %c %c %c\n",
+ poc,
+ szAscii[0], szAscii[1], szAscii[2], szAscii[3],
+ szAscii[4], szAscii[5], szAscii[6], szAscii[7]);
+ break;
+ case 7:
+ pr_info("push poc:%d : %c %c %c %c %c %c %c\n",
+ poc,
+ szAscii[0], szAscii[1], szAscii[2], szAscii[3],
+ szAscii[4], szAscii[5], szAscii[6]);
+ break;
+ case 6:
+ pr_info("push poc:%d : %c %c %c %c %c %c\n", poc,
+ szAscii[0], szAscii[1], szAscii[2], szAscii[3],
+ szAscii[4], szAscii[5]);
+ break;
+ case 5:
+ pr_info("push poc:%d : %c %c %c %c %c\n", poc,
+ szAscii[0], szAscii[1], szAscii[2], szAscii[3],
+ szAscii[4]);
+ break;
+ case 4:
+ pr_info("push poc:%d : %c %c %c %c\n", poc,
+ szAscii[0], szAscii[1], szAscii[2], szAscii[3]);
+ break;
+ case 3:
+ pr_info("push poc:%d : %c %c %c\n", poc,
+ szAscii[0], szAscii[1], szAscii[2]);
+ break;
+ case 2:
+ pr_info("push poc:%d : %c %c\n", poc,
+ szAscii[0], szAscii[1]);
+ break;
+ case 1:
+ pr_info("push poc:%d : %c\n", poc, szAscii[0]);
+ break;
+ default:
+ pr_info("push poc:%d and no CC data: index = %d\n",
+ poc, index);
+ break;
+ }
+}
+#endif
+
+
+static int is_atsc(u8 *pdata)
+{
+ if ((pdata[0] == 0x47) &&
+ (pdata[1] == 0x41) &&
+ (pdata[2] == 0x39) &&
+ (pdata[3] == 0x34))
+ return 1;
+ else
+ return 0;
+}
+/*
+#define DUMP_HEAD_INFO_DATA
+*/
+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,
+ u32 reference)
+{
+ unsigned char szBuf[256];
+
+
+ memset(szBuf, 0, 256);
+ memcpy(szBuf, pdata, user_data_length);
+
+ aml_swap_data(szBuf, user_data_length);
+#ifdef DUMP_USER_DATA_HEX
+ print_data(szBuf,
+ user_data_length,
+ flag,
+ duration,
+ vpts,
+ vpts_valid,
+ rec_id,
+ reference);
+#endif
+
+#ifdef DEBUG_CC_DUMP_ASCII
+#ifdef DUMP_HEAD_INFO_DATA
+ if (is_atsc(szBuf+8))
+ dump_cc_ascii(szBuf+8+4, reference);
+#else
+ if (is_atsc(szBuf))
+ dump_cc_ascii(szBuf+4, reference);
+#endif
+#endif
+}
+
+
+
+
+#define MAX_USER_DATA_SIZE 1572864
+static void *user_data_buf;
+static unsigned char *pbuf_start;
+static int total_len;
+static int bskip;
+static int n_userdata_id;
+
+static void reset_user_data_buf(void)
+{
+ total_len = 0;
+ pbuf_start = user_data_buf;
+ bskip = 0;
+ n_userdata_id = 0;
+}
+
+static void push_to_buf(u8 *pdata, int len, struct userdata_meta_info_t *pmeta,
+ u32 reference)
+{
+ 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++;
+
+ *pLen = reference;
+ pbuf_start += sizeof(u32);
+ info_cnt++;
+ pLen++;
+
+
+
+ pbuf_end = (u8 *)ccbuf_phyAddress_virt + CCBUF_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 *)ccbuf_phyAddress_virt;
+ 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,
+ u32 reference)
+{
+ u8 *pstart;
+
+ pstart = (u8 *)puser_data;
+
+#ifdef DUMP_HEAD_INFO_DATA
+ push_to_buf(pstart, len, pmeta, reference);
+#else
+ push_to_buf(pstart+8, len - 8, pmeta, reference);
+#endif
+}
+
+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;
+ u32 reference;
+
+ 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);
+
+ reference = *pLen;
+ pLen++;
+ pbuf += sizeof(u32);
+
+
+ dump_data(pbuf, len, flag, duration,
+ vpts, vpts_valid, rec_id, reference);
+ pbuf += len;
+ msleep(30);
+ }
+}
+#endif
+
+static void vmpeg12_add_userdata(struct userdata_meta_info_t meta_info,
+ int wp,
+ u32 reference);
+/*
+#define PRINT_HEAD_INFO
+*/
+static void userdata_push_do_work(struct work_struct *work)
+{
+ u32 reg;
+ u32 offset, pts;
+ u64 pts_us64 = 0;
+ u8 *pdata;
+ u8 head_info[8];
+ struct userdata_meta_info_t meta_info;
+ u32 wp;
+ u32 index;
+ u32 picture_struct;
+ u32 reference;
+ u32 picture_type;
+ u32 temp;
+#ifdef PRINT_HEAD_INFO
+ u8 *ptype_str;
+#endif
+ memset(&meta_info, 0, sizeof(meta_info));
+
+ meta_info.duration = frame_dur;
+
+ reg = READ_VREG(AV_SCRATCH_M);
+ meta_info.flags = ((reg >> 30) << 1);
+ meta_info.flags |= (VFORMAT_MPEG12 << 3);
+ /* check top_field_first flag */
+ if ((reg >> 28) & 0x1) {
+ meta_info.flags |= (1 << 10);
+ meta_info.flags |= (((reg >> 29) & 0x1) << 11);
+ }
+
+ offset = READ_VREG(AV_SCRATCH_N);
+ if (offset != last_offset) {
+ meta_info.flags |= 1;
+ last_offset = offset;
+ }
+
+ if (pts_pickout_offset_us64
+ (PTS_TYPE_VIDEO, offset, &pts, 0, &pts_us64) != 0) {
+ pr_info("pick out pts failed by offset = 0x%x\n", offset);
+ pts = -1;
+ meta_info.vpts_valid = 0;
+ } else
+ meta_info.vpts_valid = 1;
+ meta_info.vpts = pts;
+
+ if (!ccbuf_phyAddress_is_remaped_nocache &&
+ ccbuf_phyAddress &&
+ ccbuf_phyAddress_virt) {
+ codec_mm_dma_flush(
+ ccbuf_phyAddress_virt,
+ CCBUF_SIZE,
+ DMA_FROM_DEVICE);
+ }
+
+ mutex_lock(&userdata_mutex);
+ if (p_userdata_mgr && ccbuf_phyAddress_virt) {
+ int new_wp;
+
+ new_wp = reg & 0xffff;
+ if (new_wp < p_userdata_mgr->last_wp)
+ pdata = (u8 *)ccbuf_phyAddress_virt;
+ else
+ pdata = (u8 *)ccbuf_phyAddress_virt +
+ p_userdata_mgr->last_wp;
+ memcpy(head_info, pdata, 8);
+ } else
+ memset(head_info, 0, 8);
+ mutex_unlock(&userdata_mutex);
+ aml_swap_data(head_info, 8);
+
+ wp = (head_info[0] << 8 | head_info[1]);
+ index = (head_info[2] << 8 | head_info[3]);
+
+ picture_struct = (head_info[6] << 8 | head_info[7]);
+ temp = (head_info[4] << 8 | head_info[5]);
+ reference = temp & 0x3FF;
+ picture_type = (temp >> 10) & 0x7;
+
+#if 0
+ pr_info("index = %d, wp = %d, ref = %d, type = %d, struct = 0x%x, vpts:0x%x\n",
+ index, wp, reference,
+ picture_type, picture_struct, meta_info.vpts);
+#endif
+ switch (picture_type) {
+ case 1:
+ /* pr_info("I type, pos:%d\n",
+ (meta_info.flags>>1)&0x3); */
+ meta_info.flags |= (1<<7);
+#ifdef PRINT_HEAD_INFO
+ ptype_str = " I";
+#endif
+ break;
+ case 2:
+ /* pr_info("P type, pos:%d\n",
+ (meta_info.flags>>1)&0x3); */
+ meta_info.flags |= (2<<7);
+#ifdef PRINT_HEAD_INFO
+ ptype_str = " P";
+#endif
+ break;
+ case 3:
+ /* pr_info("B type, pos:%d\n",
+ (meta_info.flags>>1)&0x3); */
+ meta_info.flags |= (3<<7);
+#ifdef PRINT_HEAD_INFO
+ ptype_str = " B";
+#endif
+ break;
+ case 4:
+ /* pr_info("D type, pos:%d\n",
+ (meta_info.flags>>1)&0x3); */
+ meta_info.flags |= (4<<7);
+#ifdef PRINT_HEAD_INFO
+ ptype_str = " D";
+#endif
+ break;
+ default:
+ /* pr_info("Unknown type:0x%x, pos:%d\n",
+ pheader->picture_coding_type,
+ (meta_info.flags>>1)&0x3); */
+#ifdef PRINT_HEAD_INFO
+ ptype_str = " U";
+#endif
+ break;
+ }
+#ifdef PRINT_HEAD_INFO
+ pr_info("ref:%d, type:%s, ext:%d, offset:0x%x, first:%d, id:%d\n",
+ reference, ptype_str,
+ (reg >> 30), offset,
+ (reg >> 28)&0x3,
+ n_userdata_id);
+#endif
+ vmpeg12_add_userdata(meta_info, reg & 0xffff, reference);
+
+ WRITE_VREG(AV_SCRATCH_M, 0);
+}
+
+static void vmpeg12_notify_work(struct work_struct *work)
+{
+ pr_info("frame duration changed %d\n", frame_dur);
+ 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 irqreturn_t vmpeg12_isr(int irq, void *dev_id)
+{
+ u32 reg, info, seqinfo, offset, pts, pts_valid = 0;
+ struct vframe_s *vf;
+ u64 pts_us64 = 0;
+ u32 frame_size;
+
+ WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
+
+ reg = READ_VREG(MREG_BUFFEROUT);
+
+ if (reg) {
+ info = READ_VREG(MREG_PIC_INFO);
+ offset = READ_VREG(MREG_FRAME_OFFSET);
+ seqinfo = READ_VREG(MREG_SEQ_INFO);
+
+ if ((first_i_frame_ready == 0) &&
+ ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_I) &&
+ ((info & PICINFO_ERROR) == 0))
+ first_i_frame_ready = 1;
+
+ if ((pts_lookup_offset_us64
+ (PTS_TYPE_VIDEO, offset, &pts,
+ &frame_size, 0, &pts_us64) == 0)
+ && (((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_I)
+ || ((info & PICINFO_TYPE_MASK) ==
+ PICINFO_TYPE_P)))
+ pts_valid = 1;
+
+ if (pts_valid && lastpts == pts)
+ pts_valid = 0;
+ if (pts_valid)
+ lastpts = pts;
+ /*if (frame_prog == 0) */
+ {
+ frame_prog = info & PICINFO_PROG;
+ if ((seqinfo & SEQINFO_EXT_AVAILABLE)
+ && (!(seqinfo & SEQINFO_PROG)))
+ frame_prog = 0;
+ }
+
+ if ((dec_control &
+ DEC_CONTROL_FLAG_FORCE_2500_720_576_INTERLACE)
+ && (frame_width == 720 || frame_width == 480)
+ && (frame_height == 576)
+ && (frame_dur == 3840))
+ frame_prog = 0;
+ else if ((dec_control &
+ DEC_CONTROL_FLAG_FORCE_3000_704_480_INTERLACE)
+ && (frame_width == 704) && (frame_height == 480)
+ && (frame_dur == 3200))
+ frame_prog = 0;
+ else if ((dec_control &
+ DEC_CONTROL_FLAG_FORCE_2500_704_576_INTERLACE)
+ && (frame_width == 704) && (frame_height == 576)
+ && (frame_dur == 3840))
+ frame_prog = 0;
+ else if ((dec_control &
+ DEC_CONTROL_FLAG_FORCE_2500_544_576_INTERLACE)
+ && (frame_width == 544) && (frame_height == 576)
+ && (frame_dur == 3840))
+ frame_prog = 0;
+ else if ((dec_control &
+ DEC_CONTROL_FLAG_FORCE_2500_480_576_INTERLACE)
+ && (frame_width == 480) && (frame_height == 576)
+ && (frame_dur == 3840))
+ frame_prog = 0;
+ else if (dec_control & DEC_CONTROL_FLAG_FORCE_SEQ_INTERLACE)
+ frame_prog = 0;
+ if (frame_prog & PICINFO_PROG) {
+ u32 index = ((reg & 0xf) - 1) & 7;
+
+ seqinfo = READ_VREG(MREG_SEQ_INFO);
+
+ if (kfifo_get(&newframe_q, &vf) == 0) {
+ pr_info
+ ("fatal error, no available buffer slot.");
+ return IRQ_HANDLED;
+ }
+
+ set_frame_info(vf);
+ /*pr_info("video signal type:0x%x\n",
+ READ_VREG(AV_SCRATCH_H));*/
+ vf->signal_type = READ_VREG(AV_SCRATCH_H);
+ vf->index = index;
+#ifdef NV21
+ vf->type =
+ VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD |
+ VIDTYPE_VIU_NV21;
+#else
+ vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD;
+#endif
+ if ((seqinfo & SEQINFO_EXT_AVAILABLE)
+ && (seqinfo & SEQINFO_PROG)) {
+ if (info & PICINFO_RPT_FIRST) {
+ if (info & PICINFO_TOP_FIRST) {
+ vf->duration =
+ vf->duration * 3;
+ /* repeat three times */
+ } else {
+ vf->duration =
+ vf->duration * 2;
+ /* repeat two times */
+ }
+ }
+ vf->duration_pulldown = 0;
+ /* no pull down */
+
+ } else {
+ vf->duration_pulldown =
+ (info & PICINFO_RPT_FIRST) ?
+ vf->duration >> 1 : 0;
+ }
+
+ /*count info*/
+ vdec_count_info(gvs, info & PICINFO_ERROR, offset);
+
+ vf->duration += vf->duration_pulldown;
+ vf->canvas0Addr = vf->canvas1Addr =
+ index2canvas(index);
+ vf->orientation = 0;
+ vf->pts = (pts_valid) ? pts : 0;
+ vf->pts_us64 = (pts_valid) ? pts_us64 : 0;
+ vf->type_original = vf->type;
+
+ vfbuf_use[index] = 1;
+
+ if ((error_skip(info, vf)) ||
+ ((first_i_frame_ready == 0)
+ && ((PICINFO_TYPE_MASK & info) !=
+ PICINFO_TYPE_I))) {
+ gvs->drop_frame_count++;
+ kfifo_put(&recycle_q,
+ (const struct vframe_s *)vf);
+ } else {
+ vf->mem_handle =
+ decoder_bmmu_box_get_mem_handle(
+ mm_blk_handle,
+ 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);
+ }
+
+ } else {
+ u32 index = ((reg & 0xf) - 1) & 7;
+ int first_field_type = (info & PICINFO_TOP_FIRST) ?
+ VIDTYPE_INTERLACE_TOP :
+ VIDTYPE_INTERLACE_BOTTOM;
+
+#ifdef INTERLACE_SEQ_ALWAYS
+ /* once an interlaced sequence exist,
+ *always force interlaced type
+ */
+ /* to make DI easy. */
+ dec_control |= DEC_CONTROL_FLAG_FORCE_SEQ_INTERLACE;
+#endif
+#if 0
+ if (info & PICINFO_FRAME) {
+ frame_rpt_state =
+ (info & PICINFO_TOP_FIRST) ?
+ FRAME_REPEAT_TOP : FRAME_REPEAT_BOT;
+ } else {
+ if (frame_rpt_state == FRAME_REPEAT_TOP) {
+ first_field_type =
+ VIDTYPE_INTERLACE_TOP;
+ } else if (frame_rpt_state ==
+ FRAME_REPEAT_BOT) {
+ first_field_type =
+ VIDTYPE_INTERLACE_BOTTOM;
+ }
+ frame_rpt_state = FRAME_REPEAT_NONE;
+ }
+#else
+ frame_rpt_state = FRAME_REPEAT_NONE;
+#endif
+ if (kfifo_get(&newframe_q, &vf) == 0) {
+ pr_info
+ ("fatal error, no available buffer slot.");
+ return IRQ_HANDLED;
+ }
+ if (info & PICINFO_RPT_FIRST)
+ vfbuf_use[index] = 3;
+ else
+ vfbuf_use[index] = 2;
+
+ set_frame_info(vf);
+ vf->signal_type = 0;
+ vf->index = index;
+ vf->type =
+ (first_field_type == VIDTYPE_INTERLACE_TOP) ?
+ VIDTYPE_INTERLACE_TOP :
+ VIDTYPE_INTERLACE_BOTTOM;
+#ifdef NV21
+ vf->type |= VIDTYPE_VIU_NV21;
+#endif
+ if (info & PICINFO_RPT_FIRST)
+ vf->duration /= 3;
+ else
+ vf->duration >>= 1;
+ vf->duration_pulldown = (info & PICINFO_RPT_FIRST) ?
+ vf->duration >> 1 : 0;
+ vf->duration += vf->duration_pulldown;
+ vf->orientation = 0;
+ vf->canvas0Addr = vf->canvas1Addr =
+ index2canvas(index);
+ vf->pts = (pts_valid) ? pts : 0;
+ vf->pts_us64 = (pts_valid) ? pts_us64 : 0;
+ vf->type_original = vf->type;
+
+ if ((error_skip(info, vf)) ||
+ ((first_i_frame_ready == 0)
+ && ((PICINFO_TYPE_MASK & info) !=
+ PICINFO_TYPE_I))) {
+ gvs->drop_frame_count++;
+ kfifo_put(&recycle_q,
+ (const struct vframe_s *)vf);
+ } else {
+ vf->mem_handle =
+ decoder_bmmu_box_get_mem_handle(
+ mm_blk_handle,
+ 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);
+ }
+
+ if (kfifo_get(&newframe_q, &vf) == 0) {
+ pr_info
+ ("fatal error, no available buffer slot.");
+ return IRQ_HANDLED;
+ }
+
+ set_frame_info(vf);
+ vf->signal_type = 0;
+ vf->index = index;
+ vf->type = (first_field_type ==
+ VIDTYPE_INTERLACE_TOP) ?
+ VIDTYPE_INTERLACE_BOTTOM :
+ VIDTYPE_INTERLACE_TOP;
+#ifdef NV21
+ vf->type |= VIDTYPE_VIU_NV21;
+#endif
+ if (info & PICINFO_RPT_FIRST)
+ vf->duration /= 3;
+ else
+ vf->duration >>= 1;
+ vf->duration_pulldown = (info & PICINFO_RPT_FIRST) ?
+ vf->duration >> 1 : 0;
+ vf->duration += vf->duration_pulldown;
+ vf->orientation = 0;
+ vf->canvas0Addr = vf->canvas1Addr =
+ index2canvas(index);
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+ vf->type_original = vf->type;
+
+ /*count info*/
+ vdec_count_info(gvs, info & PICINFO_ERROR, offset);
+
+ if ((error_skip(info, vf)) ||
+ ((first_i_frame_ready == 0)
+ && ((PICINFO_TYPE_MASK & info) !=
+ PICINFO_TYPE_I))) {
+ gvs->drop_frame_count++;
+ kfifo_put(&recycle_q,
+ (const struct vframe_s *)vf);
+ } else {
+ vf->mem_handle =
+ decoder_bmmu_box_get_mem_handle(
+ mm_blk_handle,
+ 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);
+ }
+
+ if (info & PICINFO_RPT_FIRST) {
+ if (kfifo_get(&newframe_q, &vf) == 0) {
+ pr_info("error, no available buffer slot.");
+ return IRQ_HANDLED;
+ }
+
+ set_frame_info(vf);
+
+ vf->index = index;
+ vf->type = (first_field_type ==
+ VIDTYPE_INTERLACE_TOP) ?
+ VIDTYPE_INTERLACE_TOP :
+ VIDTYPE_INTERLACE_BOTTOM;
+#ifdef NV21
+ vf->type |= VIDTYPE_VIU_NV21;
+#endif
+ vf->duration /= 3;
+ vf->duration_pulldown =
+ (info & PICINFO_RPT_FIRST) ?
+ vf->duration >> 1 : 0;
+ vf->duration += vf->duration_pulldown;
+ vf->orientation = 0;
+ vf->canvas0Addr = vf->canvas1Addr =
+ index2canvas(index);
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+ if ((error_skip(info, vf)) ||
+ ((first_i_frame_ready == 0)
+ && ((PICINFO_TYPE_MASK & info)
+ != PICINFO_TYPE_I))) {
+ kfifo_put(&recycle_q,
+ (const struct vframe_s *)vf);
+ } else {
+ 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);
+ }
+ }
+ }
+ WRITE_VREG(MREG_BUFFEROUT, 0);
+ }
+
+ reg = READ_VREG(AV_SCRATCH_M);
+ if (reg & (1<<16))
+ schedule_work(&userdata_push_work);
+
+ return IRQ_HANDLED;
+}
+
+static struct vframe_s *vmpeg_vf_peek(void *op_arg)
+{
+ struct vframe_s *vf;
+
+ if (kfifo_peek(&display_q, &vf))
+ return vf;
+
+ return NULL;
+}
+
+static struct vframe_s *vmpeg_vf_get(void *op_arg)
+{
+ struct vframe_s *vf;
+
+ if (kfifo_get(&display_q, &vf))
+ return vf;
+
+ return NULL;
+}
+
+static void vmpeg_vf_put(struct vframe_s *vf, void *op_arg)
+{
+ if (pool_index(vf) == cur_pool_idx)
+ kfifo_put(&recycle_q, (const struct vframe_s *)vf);
+}
+
+static int vmpeg_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(&vmpeg_vf_prov);
+#endif
+ spin_lock_irqsave(&lock, flags);
+ vmpeg12_local_init();
+ vmpeg12_prot_init();
+ spin_unlock_irqrestore(&lock, flags);
+#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vf_reg_provider(&vmpeg_vf_prov);
+#endif
+ amvdec_start();
+ }
+ return 0;
+}
+
+static int vmpeg_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 vmpeg12_ppmgr_reset(void)
+{
+ vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_RESET, NULL);
+
+ vmpeg12_local_init();
+
+ pr_info("vmpeg12dec: vf_ppmgr_reset\n");
+}
+#endif
+
+static void vmpeg12_reset_userdata_fifo(struct vdec_s *vdec, int bInit);
+static void vmpeg12_wakeup_userdata_poll(struct vdec_s *vdec);
+
+static void reset_do_work(struct work_struct *work)
+{
+ amvdec_stop();
+
+#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vmpeg12_ppmgr_reset();
+#else
+ vf_light_unreg_provider(&vmpeg_vf_prov);
+ vmpeg12_local_init();
+ vf_reg_provider(&vmpeg_vf_prov);
+#endif
+ vmpeg12_prot_init();
+ vmpeg12_create_userdata_manager(ccbuf_phyAddress_virt, CCBUF_SIZE);
+ vmpeg12_reset_userdata_fifo(vdec, 1);
+#ifdef DUMP_USER_DATA
+ last_wp = 0;
+#endif
+
+ amvdec_start();
+}
+
+static void vmpeg12_set_clk(struct work_struct *work)
+{
+ {
+ int fps = 96000 / frame_dur;
+
+ saved_resolution = frame_width * frame_height * fps;
+ vdec_source_changed(VFORMAT_MPEG12,
+ frame_width, frame_height, fps);
+ }
+}
+
+
+static void vmpeg_put_timer_func(unsigned long arg)
+{
+ struct timer_list *timer = (struct timer_list *)arg;
+ int fatal_reset = 0;
+
+ enum receviver_start_e state = RECEIVER_INACTIVE;
+
+ if (vf_get_receiver(PROVIDER_NAME)) {
+ state = vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_QUREY_STATE, NULL);
+ if ((state == RECEIVER_STATE_NULL)
+ || (state == RECEIVER_STATE_NONE)) {
+ /* receiver has no event_cb or
+ *receiver's event_cb does not process this event
+ */
+ state = RECEIVER_INACTIVE;
+ }
+ } else
+ state = RECEIVER_INACTIVE;
+
+ if (READ_VREG(MREG_FATAL_ERROR) == 1)
+ fatal_reset = 1;
+
+ if ((READ_VREG(MREG_WAIT_BUFFER) != 0) &&
+ (kfifo_is_empty(&recycle_q)) &&
+ (kfifo_is_empty(&display_q)) && (state == RECEIVER_INACTIVE)) {
+ if (++wait_buffer_counter > 4)
+ fatal_reset = 1;
+
+ } else
+ wait_buffer_counter = 0;
+
+ if (fatal_reset && (kfifo_is_empty(&display_q))) {
+ pr_info("$$$$decoder is waiting for buffer or fatal reset.\n");
+ schedule_work(&reset_work);
+ }
+
+ while (!kfifo_is_empty(&recycle_q) && (READ_VREG(MREG_BUFFERIN) == 0)) {
+ struct vframe_s *vf;
+
+ if (kfifo_get(&recycle_q, &vf)) {
+ if ((vf->index < DECODE_BUFFER_NUM_MAX) &&
+ (--vfbuf_use[vf->index] == 0)) {
+ WRITE_VREG(MREG_BUFFERIN, vf->index + 1);
+ vf->index = DECODE_BUFFER_NUM_MAX;
+ }
+
+ if (pool_index(vf) == cur_pool_idx) {
+ 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);
+}
+
+int vmpeg12_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;
+ vstatus->ratio_control = ratio_control;
+ snprintf(vstatus->vdec_name, sizeof(vstatus->vdec_name),
+ "%s", DRIVER_NAME);
+
+ return 0;
+}
+
+int vmpeg12_set_isreset(struct vdec_s *vdec, int isreset)
+{
+ is_reset = isreset;
+ return 0;
+}
+
+
+
+
+static void vmpeg12_create_userdata_manager(u8 *userdata_buf, int buf_len)
+{
+ mutex_lock(&userdata_mutex);
+
+ p_userdata_mgr = (struct mpeg12_userdata_info_t *)
+ vmalloc(sizeof(struct mpeg12_userdata_info_t));
+ if (p_userdata_mgr) {
+ memset(p_userdata_mgr, 0,
+ sizeof(struct mpeg12_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;
+ }
+ mutex_unlock(&userdata_mutex);
+}
+
+static void vmpeg12_destroy_userdata_manager(void)
+{
+ mutex_lock(&userdata_mutex);
+
+ if (p_userdata_mgr) {
+ vfree(p_userdata_mgr);
+ p_userdata_mgr = NULL;
+ }
+ mutex_unlock(&userdata_mutex);
+}
+
+static void vmpeg12_add_userdata(struct userdata_meta_info_t meta_info,
+ int wp,
+ u32 reference)
+{
+ struct mpeg12_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 {
+ p_userdata_mgr->last_wp = 0;
+ data_length = wp - p_userdata_mgr->last_wp;
+ }
+
+ if (data_length & 0x7)
+ data_length = (((data_length + 8) >> 3) << 3);
+/*
+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);
+*/
+ 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,
+ reference);
+ 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);
+}
+
+
+static int vmpeg12_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 mpeg12_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 vmpeg12_reset_userdata_fifo(struct vdec_s *vdec, int bInit)
+{
+ mutex_lock(&userdata_mutex);
+
+ if (p_userdata_mgr) {
+ pr_info("vmpeg12_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 vmpeg12_wakeup_userdata_poll(struct vdec_s *vdec)
+{
+ amstream_wakeup_userdata_poll(vdec);
+}
+
+static int vmpeg12_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 vmpeg12_canvas_init(void)
+{
+ int i, ret;
+ u32 canvas_width, canvas_height;
+ u32 decbuf_size, decbuf_y_size, decbuf_uv_size;
+ static unsigned long buf_start;
+
+ 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;
+ }
+
+
+ for (i = 0; i < MAX_BMMU_BUFFER_NUM; i++) {
+
+ if (i == (MAX_BMMU_BUFFER_NUM - 1)) /* workspace mem */
+ decbuf_size = WORKSPACE_SIZE;
+
+ ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle, i,
+ decbuf_size, DRIVER_NAME, &buf_start);
+ if (ret < 0)
+ return ret;
+
+ if (i == (MAX_BMMU_BUFFER_NUM - 1)) {
+
+ WRITE_VREG(MREG_CO_MV_START, (buf_start + CCBUF_SIZE));
+ if (!ccbuf_phyAddress) {
+ ccbuf_phyAddress
+ = (u32)buf_start;
+
+ ccbuf_phyAddress_virt
+ = codec_mm_phys_to_virt(
+ ccbuf_phyAddress);
+ if ((!ccbuf_phyAddress_virt) && (!tvp_flag)) {
+ ccbuf_phyAddress_virt
+ = codec_mm_vmap(
+ ccbuf_phyAddress,
+ CCBUF_SIZE);
+ ccbuf_phyAddress_is_remaped_nocache = 1;
+ }
+ }
+
+ } else {
+#ifdef NV21
+ canvas_config(2 * i + 0,
+ buf_start,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+ canvas_config(2 * i + 1,
+ buf_start +
+ decbuf_y_size, canvas_width,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+#else
+ canvas_config(3 * i + 0,
+ buf_start,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+ canvas_config(3 * i + 1,
+ buf_start +
+ decbuf_y_size, canvas_width / 2,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+ canvas_config(3 * i + 2,
+ buf_start +
+ decbuf_y_size + decbuf_uv_size,
+ canvas_width / 2, canvas_height / 2,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+#endif
+ }
+ }
+
+ return 0;
+}
+
+static int vmpeg12_prot_init(void)
+{
+ int ret;
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M6) {
+ int save_reg = READ_VREG(POWER_CTL_VLD);
+
+ WRITE_VREG(DOS_SW_RESET0, (1 << 7) | (1 << 6) | (1 << 4));
+ WRITE_VREG(DOS_SW_RESET0, 0);
+
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M8) {
+
+ 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);
+
+ WRITE_VREG(MDEC_SW_RESET, (1 << 7));
+ WRITE_VREG(MDEC_SW_RESET, 0);
+ }
+
+ WRITE_VREG(POWER_CTL_VLD, save_reg);
+
+ } else
+ WRITE_RESET_REG(RESET0_REGISTER, RESET_IQIDCT | RESET_MC);
+
+ ret = vmpeg12_canvas_init();
+
+#ifdef NV21
+ WRITE_VREG(AV_SCRATCH_0, 0x010100);
+ WRITE_VREG(AV_SCRATCH_1, 0x030302);
+ WRITE_VREG(AV_SCRATCH_2, 0x050504);
+ WRITE_VREG(AV_SCRATCH_3, 0x070706);
+ WRITE_VREG(AV_SCRATCH_4, 0x090908);
+ WRITE_VREG(AV_SCRATCH_5, 0x0b0b0a);
+ WRITE_VREG(AV_SCRATCH_6, 0x0d0d0c);
+ WRITE_VREG(AV_SCRATCH_7, 0x0f0f0e);
+#else
+ WRITE_VREG(AV_SCRATCH_0, 0x020100);
+ WRITE_VREG(AV_SCRATCH_1, 0x050403);
+ WRITE_VREG(AV_SCRATCH_2, 0x080706);
+ WRITE_VREG(AV_SCRATCH_3, 0x0b0a09);
+ WRITE_VREG(AV_SCRATCH_4, 0x0e0d0c);
+ WRITE_VREG(AV_SCRATCH_5, 0x11100f);
+ WRITE_VREG(AV_SCRATCH_6, 0x141312);
+ WRITE_VREG(AV_SCRATCH_7, 0x171615);
+#endif
+
+ /* set to mpeg1 default */
+ WRITE_VREG(MPEG1_2_REG, 0);
+ /* disable PSCALE for hardware sharing */
+ WRITE_VREG(PSCALE_CTRL, 0);
+ /* for Mpeg1 default value */
+ WRITE_VREG(PIC_HEAD_INFO, 0x380);
+ /* disable mpeg4 */
+ WRITE_VREG(M4_CONTROL_REG, 0);
+ /* clear mailbox interrupt */
+ WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
+ /* clear buffer IN/OUT registers */
+ WRITE_VREG(MREG_BUFFERIN, 0);
+ WRITE_VREG(MREG_BUFFEROUT, 0);
+ /* set reference width and height */
+ if ((frame_width != 0) && (frame_height != 0))
+ WRITE_VREG(MREG_CMD, (frame_width << 16) | frame_height);
+ else
+ WRITE_VREG(MREG_CMD, 0);
+ WRITE_VREG(MREG_FORCE_I_RDY, (force_first_i_ready & 0x01));
+ /* clear error count */
+ WRITE_VREG(MREG_ERROR_COUNT, 0);
+ WRITE_VREG(MREG_FATAL_ERROR, 0);
+ /* clear wait buffer status */
+ WRITE_VREG(MREG_WAIT_BUFFER, 0);
+#ifdef NV21
+ SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17);
+#endif
+ return ret;
+}
+
+static void vmpeg12_local_init(void)
+{
+ int i;
+
+ INIT_KFIFO(display_q);
+ INIT_KFIFO(recycle_q);
+ INIT_KFIFO(newframe_q);
+
+ cur_pool_idx ^= 1;
+
+ for (i = 0; i < VF_POOL_SIZE; i++) {
+ const struct vframe_s *vf;
+
+ if (cur_pool_idx == 0) {
+ vf = &vfpool[i];
+ vfpool[i].index = DECODE_BUFFER_NUM_MAX;
+ } else {
+ vf = &vfpool2[i];
+ vfpool2[i].index = DECODE_BUFFER_NUM_MAX;
+ }
+ kfifo_put(&newframe_q, (const struct vframe_s *)vf);
+ }
+
+ for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++)
+ vfbuf_use[i] = 0;
+ if (mm_blk_handle) {
+ mutex_lock(&userdata_mutex);
+ if (p_userdata_mgr) {
+ vfree(p_userdata_mgr);
+ p_userdata_mgr = NULL;
+ }
+ if (ccbuf_phyAddress_is_remaped_nocache)
+ codec_mm_unmap_phyaddr(ccbuf_phyAddress_virt);
+ ccbuf_phyAddress_virt = NULL;
+ ccbuf_phyAddress = 0;
+ ccbuf_phyAddress_is_remaped_nocache = 0;
+ decoder_bmmu_box_free(mm_blk_handle);
+ mm_blk_handle = NULL;
+ mutex_unlock(&userdata_mutex);
+ }
+
+ 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 |
+ tvp_flag);
+
+
+ frame_width = frame_height = frame_dur = frame_prog = 0;
+ frame_force_skip_flag = 0;
+ wait_buffer_counter = 0;
+ first_i_frame_ready = force_first_i_ready;
+ saved_resolution = 0;
+ dec_control &= DEC_CONTROL_INTERNAL_MASK;
+}
+
+static s32 vmpeg12_init(void)
+{
+ int ret = -1, size = -1;
+ char *buf = vmalloc(0x1000 * 16);
+
+ if (IS_ERR_OR_NULL(buf))
+ return -ENOMEM;
+
+ init_timer(&recycle_timer);
+
+ stat |= STAT_TIMER_INIT;
+
+ vmpeg12_local_init();
+
+ amvdec_enable();
+
+ size = get_firmware_data(VIDEO_DEC_MPEG12, buf);
+ if (size < 0) {
+ pr_err("get firmware fail.");
+ vfree(buf);
+ return -1;
+ }
+
+ ret = amvdec_loadmc_ex(VFORMAT_MPEG12, "mpeg12", buf);
+ if (ret < 0) {
+ amvdec_disable();
+ vfree(buf);
+ pr_err("MPEG12: 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 */
+ vmpeg12_prot_init();
+
+ ret = vdec_request_irq(VDEC_IRQ_1, vmpeg12_isr,
+ "vmpeg12-irq", (void *)vmpeg12_dec_id);
+
+ if (ret) {
+ amvdec_disable();
+ amlog_level(LOG_LEVEL_ERROR, "vmpeg12 irq register error.\n");
+ return -ENOENT;
+ }
+
+ stat |= STAT_ISR_REG;
+#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vf_provider_init(&vmpeg_vf_prov, PROVIDER_NAME, &vmpeg_vf_provider,
+ NULL);
+ vf_reg_provider(&vmpeg_vf_prov);
+ vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_START, NULL);
+#else
+ vf_provider_init(&vmpeg_vf_prov, PROVIDER_NAME, &vmpeg_vf_provider,
+ NULL);
+ vf_reg_provider(&vmpeg_vf_prov);
+#endif
+ if (vmpeg12_amstream_dec_info.rate != 0) {
+ if (!is_reset) {
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)
+ ((unsigned long)
+ vmpeg12_amstream_dec_info.rate));
+ fr_hint_status = VDEC_HINTED;
+ }
+ } else
+ fr_hint_status = VDEC_NEED_HINT;
+
+ stat |= STAT_VF_HOOK;
+
+ recycle_timer.data = (ulong)&recycle_timer;
+ recycle_timer.function = vmpeg_put_timer_func;
+ recycle_timer.expires = jiffies + PUT_INTERVAL;
+
+ add_timer(&recycle_timer);
+
+ stat |= STAT_TIMER_ARM;
+
+ amvdec_start();
+
+ stat |= STAT_VDEC_RUN;
+
+ return 0;
+}
+
+#ifdef DUMP_USER_DATA
+static int amvdec_mpeg12_init_userdata_dump(void)
+{
+ user_data_buf = kmalloc(MAX_USER_DATA_SIZE, GFP_KERNEL);
+ if (user_data_buf)
+ return 1;
+ else
+ return 0;
+}
+#endif
+
+static int amvdec_mpeg12_probe(struct platform_device *pdev)
+{
+ struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
+
+ amlog_level(LOG_LEVEL_INFO, "amvdec_mpeg12 probe start.\n");
+
+ if (pdata == NULL) {
+ amlog_level(LOG_LEVEL_ERROR,
+ "amvdec_mpeg12 platform data undefined.\n");
+ return -EFAULT;
+ }
+
+ tvp_flag = vdec_secure(pdata) ? CODEC_MM_FLAGS_TVP : 0;
+ if (pdata->sys_info)
+ vmpeg12_amstream_dec_info = *pdata->sys_info;
+
+ pdata->dec_status = vmpeg12_dec_status;
+ pdata->set_isreset = vmpeg12_set_isreset;
+
+ pdata->user_data_read = vmpeg12_user_data_read;
+ pdata->reset_userdata_fifo = vmpeg12_reset_userdata_fifo;
+ pdata->wakeup_userdata_poll = vmpeg12_wakeup_userdata_poll;
+ is_reset = 0;
+
+ vmpeg12_vdec_info_init();
+
+ INIT_WORK(&set_clk_work, vmpeg12_set_clk);
+ if (vmpeg12_init() < 0) {
+ amlog_level(LOG_LEVEL_ERROR, "amvdec_mpeg12 init failed.\n");
+ kfree(gvs);
+ gvs = NULL;
+ pdata->dec_status = NULL;
+ return -ENODEV;
+ }
+ vdec = pdata;
+#ifdef DUMP_USER_DATA
+ amvdec_mpeg12_init_userdata_dump();
+#endif
+ vmpeg12_create_userdata_manager(ccbuf_phyAddress_virt, CCBUF_SIZE);
+
+ INIT_WORK(&userdata_push_work, userdata_push_do_work);
+ INIT_WORK(¬ify_work, vmpeg12_notify_work);
+ INIT_WORK(&reset_work, reset_do_work);
+
+
+ last_offset = 0xFFFFFFFF;
+#ifdef DUMP_USER_DATA
+ last_wp = 0;
+ reset_user_data_buf();
+#endif
+
+ amlog_level(LOG_LEVEL_INFO, "amvdec_mpeg12 probe end.\n");
+
+ return 0;
+}
+
+static int amvdec_mpeg12_remove(struct platform_device *pdev)
+{
+ cancel_work_sync(&userdata_push_work);
+ cancel_work_sync(¬ify_work);
+ cancel_work_sync(&reset_work);
+
+ if (stat & STAT_VDEC_RUN) {
+ amvdec_stop();
+ stat &= ~STAT_VDEC_RUN;
+ }
+
+ if (stat & STAT_ISR_REG) {
+ vdec_free_irq(VDEC_IRQ_1, (void *)vmpeg12_dec_id);
+ stat &= ~STAT_ISR_REG;
+ }
+
+ if (stat & STAT_TIMER_ARM) {
+ del_timer_sync(&recycle_timer);
+ stat &= ~STAT_TIMER_ARM;
+ }
+
+ cancel_work_sync(&set_clk_work);
+ 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(&vmpeg_vf_prov);
+ stat &= ~STAT_VF_HOOK;
+ }
+
+ amvdec_disable();
+ if (ccbuf_phyAddress_is_remaped_nocache)
+ codec_mm_unmap_phyaddr(ccbuf_phyAddress_virt);
+
+ ccbuf_phyAddress_virt = NULL;
+ ccbuf_phyAddress = 0;
+ ccbuf_phyAddress_is_remaped_nocache = 0;
+ vmpeg12_destroy_userdata_manager();
+
+ if (mm_blk_handle) {
+ decoder_bmmu_box_free(mm_blk_handle);
+ mm_blk_handle = NULL;
+ }
+ amlog_level(LOG_LEVEL_INFO, "amvdec_mpeg12 remove.\n");
+
+ kfree(gvs);
+ gvs = NULL;
+ vdec = NULL;
+
+#ifdef DUMP_USER_DATA
+ if (user_data_buf) {
+ show_user_data_buf();
+ kfree(user_data_buf);
+ user_data_buf = NULL;
+ }
+#endif
+
+ return 0;
+}
+
+/****************************************/
+#ifdef CONFIG_PM
+static int mpeg12_suspend(struct device *dev)
+{
+ amvdec_suspend(to_platform_device(dev), dev->power.power_state);
+ return 0;
+}
+
+static int mpeg12_resume(struct device *dev)
+{
+ amvdec_resume(to_platform_device(dev));
+ return 0;
+}
+
+static const struct dev_pm_ops mpeg12_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mpeg12_suspend, mpeg12_resume)
+};
+#endif
+
+static struct platform_driver amvdec_mpeg12_driver = {
+ .probe = amvdec_mpeg12_probe,
+ .remove = amvdec_mpeg12_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &mpeg12_pm_ops,
+#endif
+ }
+};
+
+static struct codec_profile_t amvdec_mpeg12_profile = {
+ .name = "mpeg12",
+ .profile = ""
+};
+
+
+static struct mconfig mpeg12_configs[] = {
+ MC_PU32("stat", &stat),
+ MC_PU32("dec_control", &dec_control),
+ MC_PU32("error_frame_skip_level", &error_frame_skip_level),
+};
+static struct mconfig_node mpeg12_node;
+
+
+static int __init amvdec_mpeg12_driver_init_module(void)
+{
+ amlog_level(LOG_LEVEL_INFO, "amvdec_mpeg12 module init\n");
+
+ if (platform_driver_register(&amvdec_mpeg12_driver)) {
+ amlog_level(LOG_LEVEL_ERROR,
+ "failed to register amvdec_mpeg12 driver\n");
+ return -ENODEV;
+ }
+ vcodec_profile_register(&amvdec_mpeg12_profile);
+ INIT_REG_NODE_CONFIGS("media.decoder", &mpeg12_node,
+ "mpeg12", mpeg12_configs, CONFIG_FOR_RW);
+ return 0;
+}
+
+static void __exit amvdec_mpeg12_driver_remove_module(void)
+{
+ amlog_level(LOG_LEVEL_INFO, "amvdec_mpeg12 module remove.\n");
+
+ platform_driver_unregister(&amvdec_mpeg12_driver);
+}
+
+/****************************************/
+module_param(dec_control, uint, 0664);
+MODULE_PARM_DESC(dec_control, "\n amvmpeg12 decoder control\n");
+module_param(error_frame_skip_level, uint, 0664);
+MODULE_PARM_DESC(error_frame_skip_level,
+ "\n amvdec_mpeg12 error_frame_skip_level\n");
+module_param(force_first_i_ready, uint, 0664);
+MODULE_PARM_DESC(force_first_i_ready, "\n amvmpeg12 force_first_i_ready\n");
+
+module_init(amvdec_mpeg12_driver_init_module);
+module_exit(amvdec_mpeg12_driver_remove_module);
+
+MODULE_DESCRIPTION("AMLOGIC MPEG1/2 Video Decoder Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tim Yao <timyao@amlogic.com>");
diff --git a/drivers/frame_provider/decoder/mpeg12/vmpeg12.h b/drivers/frame_provider/decoder/mpeg12/vmpeg12.h
new file mode 100644
index 0000000..e26a414
--- /dev/null
+++ b/drivers/frame_provider/decoder/mpeg12/vmpeg12.h
@@ -0,0 +1,26 @@
+/*
+ * drivers/amlogic/amports/vmpeg12.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 VMPEG12_H
+#define VMPEG12_H
+
+/* /#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+/* TODO: move to register headers */
+#define VPP_VD1_POSTBLEND (1 << 10)
+/* /#endif */
+
+#endif /* VMPEG12_H */
diff --git a/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c b/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c
new file mode 100644
index 0000000..f2e274a
--- /dev/null
+++ b/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c
@@ -0,0 +1,3941 @@
+/*
+ * drivers/amlogic/amports/vmpeg12.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/kfifo.h>
+#include <linux/platform_device.h>
+#include <linux/random.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include <linux/amlogic/media/frame_sync/ptsserv.h>
+#include <linux/amlogic/media/utils/amstream.h>
+#include <linux/amlogic/media/canvas/canvas.h>
+#include <linux/amlogic/media/vfm/vframe.h>
+#include <linux/amlogic/media/vfm/vframe_provider.h>
+#include <linux/amlogic/media/vfm/vframe_receiver.h>
+#include <linux/amlogic/tee.h>
+
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include <linux/amlogic/media/registers/register.h>
+#include "../../../stream_input/amports/amports_priv.h"
+
+#include "../utils/vdec_input.h"
+#include "../utils/vdec.h"
+#include "../utils/amvdec.h"
+#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/config_parser.h"
+#include "../utils/firmware.h"
+#include "../utils/vdec_v4l2_buffer_ops.h"
+#include "../utils/config_parser.h"
+#include <media/v4l2-mem2mem.h>
+
+
+
+#define MEM_NAME "codec_mmpeg12"
+#define CHECK_INTERVAL (HZ/100)
+
+#define DRIVER_NAME "ammvdec_mpeg12"
+#define MREG_REF0 AV_SCRATCH_2
+#define MREG_REF1 AV_SCRATCH_3
+/* protocol registers */
+#define MREG_SEQ_INFO AV_SCRATCH_4
+#define MREG_PIC_INFO AV_SCRATCH_5
+#define MREG_PIC_WIDTH AV_SCRATCH_6
+#define MREG_PIC_HEIGHT AV_SCRATCH_7
+#define MREG_INPUT AV_SCRATCH_8 /*input_type*/
+#define MREG_BUFFEROUT AV_SCRATCH_9 /*FROM_AMRISC_REG*/
+
+#define MREG_CMD AV_SCRATCH_A
+#define MREG_CO_MV_START AV_SCRATCH_B
+#define MREG_ERROR_COUNT AV_SCRATCH_C
+#define MREG_FRAME_OFFSET AV_SCRATCH_D
+#define MREG_WAIT_BUFFER AV_SCRATCH_E
+#define MREG_FATAL_ERROR AV_SCRATCH_F
+
+#define MREG_CC_ADDR AV_SCRATCH_0
+#define AUX_BUF_ALIGN(adr) ((adr + 0xf) & (~0xf))
+
+#define GET_SLICE_TYPE(type) ("IPB##"[((type&PICINFO_TYPE_MASK)>>16)&0x3])
+#define PICINFO_ERROR 0x80000000
+#define PICINFO_TYPE_MASK 0x00030000
+#define PICINFO_TYPE_I 0x00000000
+#define PICINFO_TYPE_P 0x00010000
+#define PICINFO_TYPE_B 0x00020000
+#define PICINFO_PROG 0x8000
+#define PICINFO_RPT_FIRST 0x4000
+#define PICINFO_TOP_FIRST 0x2000
+#define PICINFO_FRAME 0x1000
+
+#define TOP_FIELD 0x1000
+#define BOTTOM_FIELD 0x2000
+#define FRAME_PICTURE 0x3000
+#define FRAME_PICTURE_MASK 0x3000
+
+#define SEQINFO_EXT_AVAILABLE 0x80000000
+#define SEQINFO_PROG 0x00010000
+#define CCBUF_SIZE (5*1024)
+
+#define VF_POOL_SIZE 64
+#define DECODE_BUFFER_NUM_MAX 16
+#define DECODE_BUFFER_NUM_DEF 8
+#define MAX_BMMU_BUFFER_NUM (DECODE_BUFFER_NUM_MAX + 1)
+
+#define PUT_INTERVAL (HZ/100)
+#define WORKSPACE_SIZE (4*SZ_64K) /*swap&ccbuf&matirx&MV*/
+#define CTX_LMEM_SWAP_OFFSET 0
+#define CTX_CCBUF_OFFSET 0x800
+#define CTX_QUANT_MATRIX_OFFSET (CTX_CCBUF_OFFSET + 5*1024)
+#define CTX_CO_MV_OFFSET (CTX_QUANT_MATRIX_OFFSET + 1*1024)
+#define CTX_DECBUF_OFFSET (CTX_CO_MV_OFFSET + 0x11000)
+
+#define DEFAULT_MEM_SIZE (32*SZ_1M)
+static u32 buf_size = 32 * 1024 * 1024;
+static int pre_decode_buf_level = 0x800;
+static int start_decode_buf_level = 0x4000;
+static u32 dec_control;
+static u32 error_frame_skip_level = 1;
+static u32 udebug_flag;
+static unsigned int radr;
+static unsigned int rval;
+
+static u32 without_display_mode;
+static u32 dynamic_buf_num_margin = 2;
+
+#define VMPEG12_DEV_NUM 9
+static unsigned int max_decode_instance_num = VMPEG12_DEV_NUM;
+static unsigned int max_process_time[VMPEG12_DEV_NUM];
+static unsigned int decode_timeout_val = 200;
+#define INCPTR(p) ptr_atomic_wrap_inc(&p)
+
+#define DEC_CONTROL_FLAG_FORCE_2500_720_576_INTERLACE 0x0002
+#define DEC_CONTROL_FLAG_FORCE_3000_704_480_INTERLACE 0x0004
+#define DEC_CONTROL_FLAG_FORCE_2500_704_576_INTERLACE 0x0008
+#define DEC_CONTROL_FLAG_FORCE_2500_544_576_INTERLACE 0x0010
+#define DEC_CONTROL_FLAG_FORCE_2500_480_576_INTERLACE 0x0020
+#define DEC_CONTROL_INTERNAL_MASK 0x0fff
+#define DEC_CONTROL_FLAG_FORCE_SEQ_INTERLACE 0x1000
+
+#define INTERLACE_SEQ_ALWAYS
+
+#if 1/* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+#define NV21
+#endif
+
+#define AGAIN_HAS_THRESHOLD
+
+#ifdef AGAIN_HAS_THRESHOLD
+static u32 again_threshold;
+#endif
+
+/*
+#define DUMP_USER_DATA
+*/
+
+enum {
+ FRAME_REPEAT_TOP,
+ FRAME_REPEAT_BOT,
+ FRAME_REPEAT_NONE
+};
+
+/*Send by AV_SCRATCH_9*/
+#define MPEG12_PIC_DONE 1
+#define MPEG12_DATA_EMPTY 2
+#define MPEG12_SEQ_END 3
+#define MPEG12_DATA_REQUEST 4
+
+/*Send by AV_SCRATCH_G*/
+#define MPEG12_V4L2_INFO_NOTIFY 1
+/*Send by AV_SCRATCH_J*/
+#define MPEG12_USERDATA_DONE 0x8000
+
+#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_DISCARD_DATA 8
+
+#define DEC_DECODE_TIMEOUT 0x21
+#define DECODE_ID(hw) (hw_to_vdec(hw)->id)
+#define DECODE_STOP_POS AV_SCRATCH_K
+
+struct mmpeg2_userdata_record_t {
+ struct userdata_meta_info_t meta_info;
+ u32 rec_start;
+ u32 rec_len;
+};
+
+#define USERDATA_FIFO_NUM 256
+#define MAX_FREE_USERDATA_NODES 5
+
+struct mmpeg2_userdata_info_t {
+ struct mmpeg2_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;
+};
+#define MAX_UD_RECORDS 5
+
+struct pic_info_t {
+ u32 buffer_info;
+ u32 index;
+ u32 offset;
+ u32 width;
+ u32 height;
+ u32 pts;
+ u64 pts64;
+ bool pts_valid;
+ ulong v4l_ref_buf_addr;
+ u32 hw_decode_time;
+ u32 frame_size; // For frame base mode
+};
+
+struct vdec_mpeg12_hw_s {
+ spinlock_t lock;
+ 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);
+ struct vframe_s vfpool[VF_POOL_SIZE];
+ s32 vfbuf_use[DECODE_BUFFER_NUM_MAX];
+ s32 ref_use[DECODE_BUFFER_NUM_MAX];
+ u32 frame_width;
+ u32 frame_height;
+ u32 frame_dur;
+ u32 frame_prog;
+ 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 vmpeg12_ratio;
+ u64 vmpeg12_ratio64;
+ u32 pixel_ratio;
+ u32 reg_pic_width;
+ u32 reg_pic_height;
+ u32 reg_mpeg1_2_reg;
+ u32 reg_pic_head_info;
+ u32 reg_f_code_reg;
+ u32 reg_slice_ver_pos_pic_type;
+ u32 reg_vcop_ctrl_reg;
+ u32 reg_mb_info;
+ u32 reg_signal_type;
+ u32 dec_num;
+ u32 disp_num;
+ struct timer_list check_timer;
+ u32 decode_timeout_count;
+ unsigned long int start_process_time;
+ u32 last_vld_level;
+ u32 eos;
+
+ struct pic_info_t pics[DECODE_BUFFER_NUM_MAX];
+ u32 canvas_spec[DECODE_BUFFER_NUM_MAX];
+ u64 lastpts64;
+ u32 last_chunk_pts;
+ struct canvas_config_s canvas_config[DECODE_BUFFER_NUM_MAX][2];
+ struct dec_sysinfo vmpeg12_amstream_dec_info;
+
+ s32 refs[2];
+ int dec_result;
+ u32 timeout_processing;
+ struct work_struct work;
+ struct work_struct timeout_work;
+ struct work_struct notify_work;
+ void (*vdec_cb)(struct vdec_s *, void *);
+ void *vdec_cb_arg;
+ dma_addr_t ccbuf_phyAddress;
+ void *ccbuf_phyAddress_virt;
+ u32 cc_buf_size;
+ unsigned long ccbuf_phyAddress_is_remaped_nocache;
+ u32 frame_rpt_state;
+/* for error handling */
+ s32 frame_force_skip_flag;
+ s32 error_frame_skip_level;
+ s32 wait_buffer_counter;
+ u32 first_i_frame_ready;
+ u32 run_count;
+ u32 not_run_ready;
+ u32 input_empty;
+ u32 put_num;
+ u32 peek_num;
+ u32 get_num;
+ u32 drop_frame_count;
+ u32 buffer_not_ready;
+ u32 ratio_control;
+ int frameinfo_enable;
+ struct firmware_s *fw;
+ u32 canvas_mode;
+#ifdef AGAIN_HAS_THRESHOLD
+ u32 pre_parser_wr_ptr;
+ u8 next_again_flag;
+#endif
+ struct work_struct userdata_push_work;
+ struct mutex userdata_mutex;
+ struct mmpeg2_userdata_info_t userdata_info;
+ struct mmpeg2_userdata_record_t ud_record[MAX_UD_RECORDS];
+ int cur_ud_idx;
+ u8 *user_data_buffer;
+ int wait_for_udr_send;
+ u32 ucode_cc_last_wp;
+ u32 notify_ucode_cc_last_wp;
+ u32 notify_data_cc_last_wp;
+ u32 userdata_wp_ctx;
+#ifdef DUMP_USER_DATA
+#define MAX_USER_DATA_SIZE 1572864
+ void *user_data_dump_buf;
+ unsigned char *pdump_buf_cur_start;
+ int total_len;
+ int bskip;
+ int n_userdata_id;
+ u32 reference[MAX_UD_RECORDS];
+#endif
+ int tvp_flag;
+ bool is_used_v4l;
+ void *v4l2_ctx;
+ bool v4l_params_parsed;
+ u32 buf_num;
+ u32 dynamic_buf_num_margin;
+ struct vdec_info gvs;
+ struct vframe_qos_s vframe_qos;
+ u32 res_ch_flag;
+ u32 i_only;
+ u32 kpi_first_i_comming;
+ u32 kpi_first_i_decoded;
+ int sidebind_type;
+ int sidebind_channel_id;
+ u32 profile_idc;
+ u32 level_idc;
+ int dec_again_cnt;
+ int vdec_pg_enable_flag;
+ char vdec_name[32];
+ char pts_name[32];
+ char new_q_name[32];
+ char disp_q_name[32];
+ u32 last_frame_offset;
+};
+
+static void vmpeg12_local_init(struct vdec_mpeg12_hw_s *hw);
+static int vmpeg12_hw_ctx_restore(struct vdec_mpeg12_hw_s *hw);
+static void reset_process_time(struct vdec_mpeg12_hw_s *hw);
+static void vmpeg12_canvas_init(struct vdec_mpeg12_hw_s *hw);
+static void flush_output(struct vdec_mpeg12_hw_s *hw);
+static struct vframe_s *vmpeg_vf_peek(void *);
+static struct vframe_s *vmpeg_vf_get(void *);
+static void vmpeg_vf_put(struct vframe_s *, void *);
+static int vmpeg_vf_states(struct vframe_states *states, void *);
+static int vmpeg_event_cb(int type, void *data, void *private_data);
+static int notify_v4l_eos(struct vdec_s *vdec);
+static void start_process_time_set(struct vdec_mpeg12_hw_s *hw);
+static int check_dirty_data(struct vdec_s *vdec);
+
+static int debug_enable;
+/*static struct work_struct userdata_push_work;*/
+#undef pr_info
+#define pr_info printk
+unsigned int mpeg12_debug_mask = 0xff;
+/*static int counter_max = 5;*/
+
+static u32 run_ready_min_buf_num = 2;
+static int dirty_again_threshold = 100;
+static int error_proc_policy = 0x1;
+
+#define PRINT_FLAG_ERROR 0x0
+#define PRINT_FLAG_RUN_FLOW 0X0001
+#define PRINT_FLAG_TIMEINFO 0x0002
+#define PRINT_FLAG_UCODE_DETAIL 0x0004
+#define PRINT_FLAG_VLD_DETAIL 0x0008
+#define PRINT_FLAG_DEC_DETAIL 0x0010
+#define PRINT_FLAG_BUFFER_DETAIL 0x0020
+#define PRINT_FLAG_RESTORE 0x0040
+#define PRINT_FRAME_NUM 0x0080
+#define PRINT_FLAG_FORCE_DONE 0x0100
+#define PRINT_FLAG_COUNTER 0X0200
+#define PRINT_FRAMEBASE_DATA 0x0400
+#define PRINT_FLAG_VDEC_STATUS 0x0800
+#define PRINT_FLAG_PARA_DATA 0x1000
+#define PRINT_FLAG_USERDATA_DETAIL 0x2000
+#define PRINT_FLAG_TIMEOUT_STATUS 0x4000
+#define PRINT_FLAG_V4L_DETAIL 0x8000
+#define PRINT_FLAG_FCC_STATUS 0x10000
+#define IGNORE_PARAM_FROM_CONFIG 0x8000000
+
+
+
+
+int debug_print(int index, int debug_flag, const char *fmt, ...)
+{
+ if (((debug_enable & debug_flag) &&
+ ((1 << index) & mpeg12_debug_mask))
+ || (debug_flag == PRINT_FLAG_ERROR)) {
+ unsigned char buf[512];
+ int len = 0;
+ va_list args;
+ va_start(args, fmt);
+ len = sprintf(buf, "%d: ", index);
+ vsnprintf(buf + len, 512-len, fmt, args);
+ pr_info("%s", buf);
+ va_end(args);
+ }
+ return 0;
+}
+
+
+/*static bool is_reset;*/
+#define PROVIDER_NAME "vdec.mpeg12"
+static const struct vframe_operations_s vf_provider_ops = {
+ .peek = vmpeg_vf_peek,
+ .get = vmpeg_vf_get,
+ .put = vmpeg_vf_put,
+ .event_cb = vmpeg_event_cb,
+ .vf_states = vmpeg_vf_states,
+};
+
+
+static const u32 frame_rate_tab[16] = {
+ 96000 / 30, 96000000 / 23976, 96000 / 24, 96000 / 25,
+ 9600000 / 2997, 96000 / 30, 96000 / 50, 9600000 / 5994,
+ 96000 / 60,
+ /* > 8 reserved, use 24 */
+ 96000 / 24, 96000 / 24, 96000 / 24, 96000 / 24,
+ 96000 / 24, 96000 / 24, 96000 / 24
+};
+
+static int vmpeg12_v4l_alloc_buff_config_canvas(struct vdec_mpeg12_hw_s *hw, int i)
+{
+ int ret;
+ u32 canvas;
+ ulong decbuf_start = 0, decbuf_uv_start = 0;
+ int decbuf_y_size = 0, decbuf_uv_size = 0;
+ u32 canvas_width = 0, canvas_height = 0;
+ struct vdec_s *vdec = hw_to_vdec(hw);
+ struct vdec_v4l2_buffer *fb = NULL;
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(hw->v4l2_ctx);
+
+ if (hw->pics[i].v4l_ref_buf_addr)
+ return 0;
+
+ ret = vdec_v4l_get_buffer(hw->v4l2_ctx, &fb);
+ if (ret < 0) {
+ debug_print(DECODE_ID(hw), 0,
+ "[%d] get fb fail %d/%d.\n",
+ ctx->id, i, hw->buf_num);
+ return ret;
+ }
+
+ if (!hw->frame_width || !hw->frame_height) {
+ struct vdec_pic_info pic;
+ vdec_v4l_get_pic_info(ctx, &pic);
+ hw->frame_width = pic.visible_width;
+ hw->frame_height = pic.visible_height;
+ debug_print(DECODE_ID(hw), 0,
+ "[%d] set %d x %d from IF layer\n", ctx->id,
+ hw->frame_width, hw->frame_height);
+ }
+
+ hw->pics[i].v4l_ref_buf_addr = (ulong)fb;
+ if (fb->num_planes == 1) {
+ decbuf_start = fb->m.mem[0].addr;
+ decbuf_y_size = fb->m.mem[0].offset;
+ decbuf_uv_start = decbuf_start + decbuf_y_size;
+ decbuf_uv_size = decbuf_y_size / 2;
+ canvas_width = ALIGN(hw->frame_width, 64);
+ canvas_height = ALIGN(hw->frame_height, 32);
+ fb->m.mem[0].bytes_used = fb->m.mem[0].size;
+ } else if (fb->num_planes == 2) {
+ decbuf_start = fb->m.mem[0].addr;
+ decbuf_y_size = fb->m.mem[0].size;
+ decbuf_uv_start = fb->m.mem[1].addr;
+ decbuf_uv_size = fb->m.mem[1].size;
+ canvas_width = ALIGN(hw->frame_width, 64);
+ canvas_height = ALIGN(hw->frame_height, 32);
+ fb->m.mem[0].bytes_used = decbuf_y_size;
+ fb->m.mem[1].bytes_used = decbuf_uv_size;
+ }
+
+ debug_print(DECODE_ID(hw), 0, "[%d] %s(), v4l ref buf addr: 0x%px\n",
+ ctx->id, __func__, fb);
+
+ if (vdec->parallel_dec == 1) {
+ u32 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 = decbuf_start;
+ hw->canvas_config[i][0].width = canvas_width;
+ hw->canvas_config[i][0].height = canvas_height;
+ hw->canvas_config[i][0].block_mode = hw->canvas_mode;
+ hw->canvas_config[i][0].endian =
+ (hw->canvas_mode == CANVAS_BLKMODE_LINEAR) ? 7 : 0;
+ canvas_config_config(canvas_y(canvas), &hw->canvas_config[i][0]);
+
+ hw->canvas_config[i][1].phy_addr = decbuf_uv_start;
+ hw->canvas_config[i][1].width = canvas_width;
+ hw->canvas_config[i][1].height = canvas_height / 2;
+ hw->canvas_config[i][1].block_mode = hw->canvas_mode;
+ hw->canvas_config[i][1].endian =
+ (hw->canvas_mode == CANVAS_BLKMODE_LINEAR) ? 7 : 0;
+ canvas_config_config(canvas_u(canvas), &hw->canvas_config[i][1]);
+
+ debug_print(DECODE_ID(hw), PRINT_FLAG_BUFFER_DETAIL,
+ "[%d] %s(), canvas: 0x%x mode: %d y: %lx uv: %lx w: %d h: %d\n",
+ ctx->id, __func__, canvas, hw->canvas_mode,
+ decbuf_start, decbuf_uv_start,
+ canvas_width, canvas_height);
+
+ return 0;
+}
+
+static unsigned int vmpeg12_get_buf_num(struct vdec_mpeg12_hw_s *hw)
+{
+ unsigned int buf_num = DECODE_BUFFER_NUM_DEF;
+
+ buf_num += hw->dynamic_buf_num_margin;
+
+ if (buf_num > DECODE_BUFFER_NUM_MAX)
+ buf_num = DECODE_BUFFER_NUM_MAX;
+
+ return buf_num;
+}
+
+static bool is_enough_free_buffer(struct vdec_mpeg12_hw_s *hw)
+{
+ int i;
+
+ for (i = 0; i < hw->buf_num; i++) {
+ if ((hw->vfbuf_use[i] == 0) && (hw->ref_use[i] == 0))
+ break;
+ }
+
+ return (i == hw->buf_num) ? false : true;
+}
+
+static int find_free_buffer(struct vdec_mpeg12_hw_s *hw)
+{
+ int i;
+
+ for (i = 0; i < hw->buf_num; i++) {
+ if ((hw->vfbuf_use[i] == 0) &&
+ (hw->ref_use[i] == 0))
+ break;
+ }
+
+ if (i == hw->buf_num)
+ return -1;
+
+ 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) {
+ /*run to parser csd data*/
+ i = 0;
+ } else {
+ if (vmpeg12_v4l_alloc_buff_config_canvas(hw, i))
+ return -1;
+ }
+ }
+ return i;
+}
+
+static u32 spec_to_index(struct vdec_mpeg12_hw_s *hw, u32 spec)
+{
+ u32 i;
+
+ for (i = 0; i < hw->buf_num; i++) {
+ if (hw->canvas_spec[i] == spec)
+ return i;
+ }
+
+ return hw->buf_num;
+}
+
+/* +[SE][BUG-145343][huanghang] fixed:mpeg2 frame qos info notify */
+static void fill_frame_info(struct vdec_mpeg12_hw_s *hw, u32 slice_type,
+ int frame_size, u32 pts)
+{
+ unsigned char a[3];
+ unsigned char i, j, t;
+ unsigned long data;
+ struct vframe_qos_s *vframe_qos = &hw->vframe_qos;
+
+ vframe_qos->type = ((slice_type & PICINFO_TYPE_MASK) ==
+ PICINFO_TYPE_I) ? 1 :
+ ((slice_type &
+ PICINFO_TYPE_MASK) ==
+ PICINFO_TYPE_P) ? 2 : 3;
+ vframe_qos->size = frame_size;
+ vframe_qos->pts = pts;
+
+ get_random_bytes(&data, sizeof(unsigned long));
+ if (vframe_qos->type == 1)
+ 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;
+ }
+ }
+ }
+ vframe_qos->max_mv = a[2];
+ vframe_qos->avg_mv = a[1];
+ vframe_qos->min_mv = a[0];
+
+ 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;
+ }
+ }
+ }
+ vframe_qos->max_qp = a[2];
+ vframe_qos->avg_qp = a[1];
+ vframe_qos->min_qp = a[0];
+
+ 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;
+ }
+ }
+ }
+ vframe_qos->max_skip = a[2];
+ vframe_qos->avg_skip = a[1];
+ vframe_qos->min_skip = a[0];
+
+ vframe_qos->num++;
+
+ return;
+}
+
+static void set_frame_info(struct vdec_mpeg12_hw_s *hw, struct vframe_s *vf)
+{
+ int ar = 0;
+ u32 buffer_index = vf->index;
+ unsigned int num = 0;
+ unsigned int den = 0;
+
+ vf->width = hw->pics[buffer_index].width;
+ vf->height = hw->pics[buffer_index].height;
+
+ if (hw->vmpeg12_ratio64 != 0) {
+ num = hw->vmpeg12_ratio64>>32;
+ den = hw->vmpeg12_ratio64 & 0xffffffff;
+ } else {
+ num = hw->vmpeg12_ratio>>16;
+ den = hw->vmpeg12_ratio & 0xffff;
+
+ }
+
+ if (hw->frame_dur > 0)
+ vf->duration = hw->frame_dur;
+ else {
+ vf->duration = hw->frame_dur =
+ frame_rate_tab[(READ_VREG(MREG_SEQ_INFO) >> 4) & 0xf];
+ vdec_schedule_work(&hw->notify_work);
+ }
+/*
+ ar_bits = READ_VREG(MREG_SEQ_INFO) & 0xf;
+
+ if (ar_bits == 0x2)
+ vf->ratio_control = 0xc0 << DISP_RATIO_ASPECT_RATIO_BIT;
+
+ else if (ar_bits == 0x3)
+ vf->ratio_control = 0x90 << DISP_RATIO_ASPECT_RATIO_BIT;
+
+ else if (ar_bits == 0x4)
+ vf->ratio_control = 0x74 << DISP_RATIO_ASPECT_RATIO_BIT;
+ else
+ vf->ratio_control = 0;
+*/
+
+ hw->pixel_ratio = READ_VREG(MREG_SEQ_INFO) & 0xf;;
+
+ if (hw->vmpeg12_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 (hw->pixel_ratio) {
+ case 1:
+ vf->sar_width = 1;
+ vf->sar_height = 1;
+ ar = (vf->height * hw->vmpeg12_ratio) / vf->width;
+ break;
+ case 2:
+ vf->sar_width = 4;
+ vf->sar_height = 3;
+ ar = (vf->height * 3 * hw->vmpeg12_ratio) / (vf->width * 4);
+ break;
+ case 3:
+ vf->sar_width = 16;
+ vf->sar_height = 9;
+ ar = (vf->height * 9 * hw->vmpeg12_ratio) / (vf->width * 16);
+ break;
+ case 4:
+ vf->sar_width = 221;
+ vf->sar_height = 100;
+ ar = (vf->height * 100 * hw->vmpeg12_ratio) / (vf->width *
+ 221);
+ break;
+ default:
+ vf->sar_width = 1;
+ vf->sar_height = 1;
+ ar = (vf->height * hw->vmpeg12_ratio) / vf->width;
+ break;
+ }
+ }
+ ar = min(ar, DISP_RATIO_ASPECT_RATIO_MAX);
+ vf->ratio_control = (ar << DISP_RATIO_ASPECT_RATIO_BIT);
+
+ hw->ratio_control = vf->ratio_control;
+
+ 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];
+
+ vf->sidebind_type = hw->sidebind_type;
+ vf->sidebind_channel_id = hw->sidebind_channel_id;
+
+ debug_print(DECODE_ID(hw), PRINT_FLAG_PARA_DATA,
+ "mpeg2dec: w(%d), h(%d), dur(%d), dur-ES(%d)\n",
+ hw->frame_width, hw->frame_height, hw->frame_dur,
+ frame_rate_tab[(READ_VREG(MREG_SEQ_INFO) >> 4) & 0xf]);
+}
+
+static bool error_skip(struct vdec_mpeg12_hw_s *hw,
+ u32 info, struct vframe_s *vf)
+{
+ if (hw->error_frame_skip_level) {
+ /* skip error frame */
+ if ((info & PICINFO_ERROR) || (hw->frame_force_skip_flag)) {
+ if ((info & PICINFO_ERROR) == 0) {
+ if ((info & PICINFO_TYPE_MASK) ==
+ PICINFO_TYPE_I)
+ hw->frame_force_skip_flag = 0;
+ } else {
+ if (hw->error_frame_skip_level >= 2)
+ hw->frame_force_skip_flag = 1;
+ }
+ if ((info & PICINFO_ERROR)
+ || (hw->frame_force_skip_flag))
+ return true;
+ }
+ }
+ return false;
+}
+
+static inline void vmpeg12_save_hw_context(struct vdec_mpeg12_hw_s *hw, u32 reg)
+{
+ if (reg == 3) {
+ hw->ctx_valid = 0;
+ //pr_info("%s, hw->userdata_wp_ctx %d\n", __func__, hw->userdata_wp_ctx);
+ } else {
+ hw->seqinfo = READ_VREG(MREG_SEQ_INFO);
+ hw->reg_pic_width = READ_VREG(MREG_PIC_WIDTH);
+ hw->reg_pic_height = READ_VREG(MREG_PIC_HEIGHT);
+ hw->reg_mpeg1_2_reg = READ_VREG(MPEG1_2_REG);
+ hw->reg_pic_head_info = READ_VREG(PIC_HEAD_INFO);
+ hw->reg_f_code_reg = READ_VREG(F_CODE_REG);
+ hw->reg_slice_ver_pos_pic_type = READ_VREG(SLICE_VER_POS_PIC_TYPE);
+ hw->reg_vcop_ctrl_reg = READ_VREG(VCOP_CTRL_REG);
+ hw->reg_mb_info = READ_VREG(MB_INFO);
+ hw->reg_signal_type = READ_VREG(AV_SCRATCH_H);
+ debug_print(DECODE_ID(hw), PRINT_FLAG_PARA_DATA,
+ "signal_type = %x", hw->reg_signal_type);
+ hw->ctx_valid = 1;
+ }
+}
+
+static void vmmpeg2_reset_udr_mgr(struct vdec_mpeg12_hw_s *hw)
+{
+ hw->wait_for_udr_send = 0;
+ hw->cur_ud_idx = 0;
+ memset(&hw->ud_record, 0, sizeof(hw->ud_record));
+}
+
+static void vmmpeg2_crate_userdata_manager(
+ struct vdec_mpeg12_hw_s *hw,
+ u8 *userdata_buf,
+ int buf_len)
+{
+ if (hw) {
+ mutex_init(&hw->userdata_mutex);
+
+ memset(&hw->userdata_info, 0,
+ sizeof(struct mmpeg2_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;
+ hw->userdata_wp_ctx = 0;
+
+ vmmpeg2_reset_udr_mgr(hw);
+ }
+}
+
+static void vmmpeg2_destroy_userdata_manager(struct vdec_mpeg12_hw_s *hw)
+{
+ if (hw)
+ memset(&hw->userdata_info,
+ 0,
+ sizeof(struct mmpeg2_userdata_info_t));
+}
+
+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;
+ }
+ }
+}
+
+#ifdef DUMP_USER_DATA
+static void push_to_buf(struct vdec_mpeg12_hw_s *hw,
+ u8 *pdata,
+ int len,
+ struct userdata_meta_info_t *pmeta,
+ u32 reference)
+{
+ u32 *pLen;
+ int info_cnt;
+ u8 *pbuf_end;
+
+ if (!hw->user_data_dump_buf)
+ return;
+
+ if (hw->bskip) {
+ pr_info("over size, skip\n");
+ return;
+ }
+ info_cnt = 0;
+ pLen = (u32 *)hw->pdump_buf_cur_start;
+
+ *pLen = len;
+ hw->pdump_buf_cur_start += sizeof(u32);
+ info_cnt++;
+ pLen++;
+
+ *pLen = pmeta->duration;
+ hw->pdump_buf_cur_start += sizeof(u32);
+ info_cnt++;
+ pLen++;
+
+ *pLen = pmeta->flags;
+ hw->pdump_buf_cur_start += sizeof(u32);
+ info_cnt++;
+ pLen++;
+
+ *pLen = pmeta->vpts;
+ hw->pdump_buf_cur_start += sizeof(u32);
+ info_cnt++;
+ pLen++;
+
+ *pLen = pmeta->vpts_valid;
+ hw->pdump_buf_cur_start += sizeof(u32);
+ info_cnt++;
+ pLen++;
+
+
+ *pLen = hw->n_userdata_id;
+ hw->pdump_buf_cur_start += sizeof(u32);
+ info_cnt++;
+ pLen++;
+
+ *pLen = reference;
+ hw->pdump_buf_cur_start += sizeof(u32);
+ info_cnt++;
+ pLen++;
+
+ pbuf_end = hw->userdata_info.data_buf_end;
+ if (pdata + len > pbuf_end) {
+ int first_section_len;
+
+ first_section_len = pbuf_end - pdata;
+ memcpy(hw->pdump_buf_cur_start, pdata, first_section_len);
+ pdata = (u8 *)hw->userdata_info.data_buf;
+ hw->pdump_buf_cur_start += first_section_len;
+ memcpy(hw->pdump_buf_cur_start, pdata, len - first_section_len);
+ hw->pdump_buf_cur_start += len - first_section_len;
+ } else {
+ memcpy(hw->pdump_buf_cur_start, pdata, len);
+ hw->pdump_buf_cur_start += len;
+ }
+
+ hw->total_len += len + info_cnt * sizeof(u32);
+ if (hw->total_len >= MAX_USER_DATA_SIZE-4096)
+ hw->bskip = 1;
+}
+
+static void dump_userdata_info(struct vdec_mpeg12_hw_s *hw,
+ void *puser_data,
+ int len,
+ struct userdata_meta_info_t *pmeta,
+ u32 reference)
+{
+ u8 *pstart;
+
+ pstart = (u8 *)puser_data;
+
+#ifdef DUMP_HEAD_INFO_DATA
+ push_to_buf(hw, pstart, len, pmeta, reference);
+#else
+ push_to_buf(hw, pstart+8, len - 8, pmeta, reference);
+#endif
+}
+
+
+static void print_data(unsigned char *pdata,
+ int len,
+ unsigned int flag,
+ unsigned int duration,
+ unsigned int vpts,
+ unsigned int vpts_valid,
+ int rec_id,
+ u32 reference)
+{
+ int nLeft;
+
+ nLeft = len;
+
+ pr_info("%d len:%d, flag:0x%x, dur:%d, vpts:0x%x, valid:%d, refer:%d\n",
+ rec_id, len, flag,
+ duration, vpts, vpts_valid,
+ reference);
+ 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,
+ u32 reference)
+{
+ unsigned char szBuf[256];
+
+
+ memset(szBuf, 0, 256);
+ memcpy(szBuf, pdata, user_data_length);
+
+ aml_swap_data(szBuf, user_data_length);
+
+ print_data(szBuf,
+ user_data_length,
+ flag,
+ duration,
+ vpts,
+ vpts_valid,
+ rec_id,
+ reference);
+}
+
+
+static void show_user_data_buf(struct vdec_mpeg12_hw_s *hw)
+{
+ u8 *pbuf;
+ int len;
+ unsigned int flag;
+ unsigned int duration;
+ unsigned int vpts;
+ unsigned int vpts_valid;
+ int rec_id;
+ u32 reference;
+
+ pr_info("show user data buf\n");
+ pbuf = hw->user_data_dump_buf;
+
+ while (pbuf < hw->pdump_buf_cur_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);
+
+ reference = *pLen;
+ pLen++;
+ pbuf += sizeof(u32);
+
+
+ dump_data(pbuf, len, flag, duration,
+ vpts, vpts_valid, rec_id, reference);
+ pbuf += len;
+ msleep(30);
+ }
+}
+
+static int amvdec_mmpeg12_init_userdata_dump(struct vdec_mpeg12_hw_s *hw)
+{
+ hw->user_data_dump_buf = kmalloc(MAX_USER_DATA_SIZE, GFP_KERNEL);
+ if (hw->user_data_dump_buf)
+ return 1;
+ else
+ return 0;
+}
+
+static void amvdec_mmpeg12_uninit_userdata_dump(struct vdec_mpeg12_hw_s *hw)
+{
+ if (hw->user_data_dump_buf) {
+ show_user_data_buf(hw);
+ kfree(hw->user_data_dump_buf);
+ hw->user_data_dump_buf = NULL;
+ }
+}
+
+static void reset_user_data_buf(struct vdec_mpeg12_hw_s *hw)
+{
+ hw->total_len = 0;
+ hw->pdump_buf_cur_start = hw->user_data_dump_buf;
+ hw->bskip = 0;
+ hw->n_userdata_id = 0;
+}
+#endif
+
+static void user_data_ready_notify(struct vdec_mpeg12_hw_s *hw,
+ u32 pts, u32 pts_valid)
+{
+ struct mmpeg2_userdata_record_t *p_userdata_rec;
+ int i;
+
+ if (hw->wait_for_udr_send) {
+ for (i = 0; i < hw->cur_ud_idx; i++) {
+ mutex_lock(&hw->userdata_mutex);
+
+
+ p_userdata_rec = hw->userdata_info.records
+ + hw->userdata_info.write_index;
+
+ hw->ud_record[i].meta_info.vpts_valid = pts_valid;
+ hw->ud_record[i].meta_info.vpts = pts;
+
+ *p_userdata_rec = hw->ud_record[i];
+#ifdef DUMP_USER_DATA
+ dump_userdata_info(hw,
+ hw->userdata_info.data_buf + p_userdata_rec->rec_start,
+ p_userdata_rec->rec_len,
+ &p_userdata_rec->meta_info,
+ hw->reference[i]);
+ hw->n_userdata_id++;
+#endif
+/*
+ pr_info("notify: rec_start:%d, rec_len:%d, wi:%d, reference:%d\n",
+ p_userdata_rec->rec_start,
+ p_userdata_rec->rec_len,
+ hw->userdata_info.write_index,
+ hw->reference[i]);
+*/
+ 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);
+
+
+ vdec_wakeup_userdata_poll(hw_to_vdec(hw));
+ }
+ hw->wait_for_udr_send = 0;
+ hw->cur_ud_idx = 0;
+ }
+ hw->notify_ucode_cc_last_wp = hw->ucode_cc_last_wp;
+ hw->notify_data_cc_last_wp = hw->userdata_info.last_wp;
+}
+
+static int vmmpeg2_user_data_read(struct vdec_s *vdec,
+ struct userdata_param_t *puserdata_para)
+{
+ struct vdec_mpeg12_hw_s *hw = NULL;
+ int rec_ri, rec_wi;
+ int rec_len;
+ u8 *rec_data_start;
+ u8 *pdest_buf;
+ struct mmpeg2_userdata_record_t *p_userdata_rec;
+ u32 data_size;
+ u32 res;
+ int copy_ok = 1;
+
+ hw = (struct vdec_mpeg12_hw_s *)vdec->private;
+
+ pdest_buf = puserdata_para->pbuf_addr;
+
+ mutex_lock(&hw->userdata_mutex);
+
+/*
+ pr_info("ri = %d, wi = %d\n",
+ hw->userdata_info.read_index,
+ hw->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("ri:%d, wi:%d, rec_len:%d, rec_start:%d, buf_len:%d\n",
+ rec_ri, rec_wi,
+ 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 vmmpeg2_reset_userdata_fifo(struct vdec_s *vdec, int bInit)
+{
+ struct vdec_mpeg12_hw_s *hw = NULL;
+
+ hw = (struct vdec_mpeg12_hw_s *)vdec->private;
+
+ if (hw) {
+ mutex_lock(&hw->userdata_mutex);
+ pr_info("mpeg2_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 vmmpeg2_wakeup_userdata_poll(struct vdec_s *vdec)
+{
+ amstream_wakeup_userdata_poll(vdec);
+}
+
+/*
+#define PRINT_HEAD_INFO
+*/
+static void userdata_push_do_work(struct work_struct *work)
+{
+ u32 reg;
+ u8 *pdata;
+ u8 *psrc_data;
+ u8 head_info[8];
+ struct userdata_meta_info_t meta_info;
+ u32 wp;
+ u32 index;
+ u32 picture_struct;
+ u32 reference;
+ u32 picture_type;
+ u32 temp;
+ u32 data_length;
+ u32 data_start;
+ int i;
+ u32 offset;
+ u32 cur_wp;
+#ifdef PRINT_HEAD_INFO
+ u8 *ptype_str;
+#endif
+ struct mmpeg2_userdata_record_t *pcur_ud_rec;
+
+ struct vdec_mpeg12_hw_s *hw = container_of(work,
+ struct vdec_mpeg12_hw_s, userdata_push_work);
+
+ memset(&meta_info, 0, sizeof(meta_info));
+
+ meta_info.duration = hw->frame_dur;
+
+
+ reg = READ_VREG(AV_SCRATCH_J);
+ hw->userdata_wp_ctx = reg & (~(1<<16));
+ meta_info.flags = ((reg >> 30) << 1);
+ meta_info.flags |= (VFORMAT_MPEG12 << 3);
+ /* check top_field_first flag */
+ if ((reg >> 28) & 0x1) {
+ meta_info.flags |= (1 << 10);
+ meta_info.flags |= (((reg >> 29) & 0x1) << 11);
+ }
+
+ cur_wp = reg & 0x7fff;
+ if (cur_wp == hw->ucode_cc_last_wp || (cur_wp >= AUX_BUF_ALIGN(CCBUF_SIZE))) {
+ debug_print(DECODE_ID(hw), 0,
+ "Null or Over size user data package: wp = %d\n", cur_wp);
+ WRITE_VREG(AV_SCRATCH_J, 0);
+ return;
+ }
+
+ if (hw->cur_ud_idx >= MAX_UD_RECORDS) {
+ debug_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL,
+ "UD Records over: %d, skip it\n", MAX_UD_RECORDS);
+ WRITE_VREG(AV_SCRATCH_J, 0);
+ hw->cur_ud_idx = 0;
+ return;
+ }
+
+ if (cur_wp < hw->ucode_cc_last_wp)
+ hw->ucode_cc_last_wp = 0;
+
+ offset = READ_VREG(AV_SCRATCH_I);
+
+ mutex_lock(&hw->userdata_mutex);
+ if (hw->ccbuf_phyAddress_virt) {
+ pdata = (u8 *)hw->ccbuf_phyAddress_virt + hw->ucode_cc_last_wp;
+ memcpy(head_info, pdata, 8);
+ } else
+ memset(head_info, 0, 8);
+ mutex_unlock(&hw->userdata_mutex);
+ aml_swap_data(head_info, 8);
+
+ wp = (head_info[0] << 8 | head_info[1]);
+ index = (head_info[2] << 8 | head_info[3]);
+
+ picture_struct = (head_info[6] << 8 | head_info[7]);
+ temp = (head_info[4] << 8 | head_info[5]);
+ reference = temp & 0x3FF;
+ picture_type = (temp >> 10) & 0x7;
+
+ if (debug_enable & PRINT_FLAG_USERDATA_DETAIL)
+ pr_info("index:%d, wp:%d, ref:%d, type:%d, struct:0x%x, u_last_wp:0x%x\n",
+ index, wp, reference,
+ picture_type, picture_struct,
+ hw->ucode_cc_last_wp);
+
+ switch (picture_type) {
+ case 1:
+ /* pr_info("I type, pos:%d\n",
+ (meta_info.flags>>1)&0x3); */
+ meta_info.flags |= (1<<7);
+#ifdef PRINT_HEAD_INFO
+ ptype_str = " I";
+#endif
+ break;
+ case 2:
+ /* pr_info("P type, pos:%d\n",
+ (meta_info.flags>>1)&0x3); */
+ meta_info.flags |= (2<<7);
+#ifdef PRINT_HEAD_INFO
+ ptype_str = " P";
+#endif
+ break;
+ case 3:
+ /* pr_info("B type, pos:%d\n",
+ (meta_info.flags>>1)&0x3); */
+ meta_info.flags |= (3<<7);
+#ifdef PRINT_HEAD_INFO
+ ptype_str = " B";
+#endif
+ break;
+ case 4:
+ /* pr_info("D type, pos:%d\n",
+ (meta_info.flags>>1)&0x3); */
+ meta_info.flags |= (4<<7);
+#ifdef PRINT_HEAD_INFO
+ ptype_str = " D";
+#endif
+ break;
+ default:
+ /* pr_info("Unknown type:0x%x, pos:%d\n",
+ pheader->picture_coding_type,
+ (meta_info.flags>>1)&0x3); */
+#ifdef PRINT_HEAD_INFO
+ ptype_str = " U";
+#endif
+ break;
+ }
+#ifdef PRINT_HEAD_INFO
+ pr_info("ref:%d, type:%s, ext:%d, first:%d, data_length:%d\n",
+ reference, ptype_str,
+ (reg >> 30),
+ (reg >> 28)&0x3,
+ reg & 0xffff);
+#endif
+ data_length = cur_wp - hw->ucode_cc_last_wp;
+ data_start = reg & 0xffff;
+ psrc_data = (u8 *)hw->ccbuf_phyAddress_virt + hw->ucode_cc_last_wp;
+
+ pdata = hw->userdata_info.data_buf + hw->userdata_info.last_wp;
+ for (i = 0; i < data_length && hw->ccbuf_phyAddress_virt != NULL && psrc_data; i++) {
+ *pdata++ = *psrc_data++;
+ if (pdata >= hw->userdata_info.data_buf_end)
+ pdata = hw->userdata_info.data_buf;
+ }
+ pcur_ud_rec = hw->ud_record + hw->cur_ud_idx;
+
+ pcur_ud_rec->meta_info = meta_info;
+ pcur_ud_rec->rec_start = hw->userdata_info.last_wp;
+ pcur_ud_rec->rec_len = data_length;
+
+ hw->userdata_info.last_wp += data_length;
+ if (hw->userdata_info.last_wp >= USER_DATA_SIZE)
+ hw->userdata_info.last_wp %= USER_DATA_SIZE;
+
+ hw->wait_for_udr_send = 1;
+
+ hw->ucode_cc_last_wp = cur_wp;
+
+ if (debug_enable & PRINT_FLAG_USERDATA_DETAIL)
+ pr_info("cur_wp:%d, rec_start:%d, rec_len:%d\n",
+ cur_wp,
+ pcur_ud_rec->rec_start,
+ pcur_ud_rec->rec_len);
+
+#ifdef DUMP_USER_DATA
+ hw->reference[hw->cur_ud_idx] = reference;
+#endif
+
+ hw->cur_ud_idx++;
+ WRITE_VREG(AV_SCRATCH_J, 0);
+
+}
+
+
+void userdata_pushed_drop(struct vdec_mpeg12_hw_s *hw)
+{
+ hw->userdata_info.last_wp = hw->notify_data_cc_last_wp;
+ hw->ucode_cc_last_wp = hw->notify_ucode_cc_last_wp;
+ hw->cur_ud_idx = 0;
+ hw->wait_for_udr_send = 0;
+
+}
+
+
+static inline void hw_update_gvs(struct vdec_mpeg12_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;
+ }
+ if (hw->gvs.ratio_control != hw->ratio_control)
+ hw->gvs.ratio_control = hw->ratio_control;
+
+ hw->gvs.status = hw->stat;
+ hw->gvs.error_count = hw->gvs.error_frame_count;
+ hw->gvs.drop_frame_count = hw->drop_frame_count;
+
+}
+
+static int prepare_display_buf(struct vdec_mpeg12_hw_s *hw,
+ struct pic_info_t *pic)
+{
+ u32 field_num = 0, i;
+ u32 first_field_type = 0, type = 0;
+ struct vframe_s *vf = NULL;
+ u32 index = pic->index;
+ u32 info = pic->buffer_info;
+ struct vdec_s *vdec = hw_to_vdec(hw);
+ struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx;
+ ulong nv_order = VIDTYPE_VIU_NV21;
+ bool pb_skip = false;
+
+#ifdef NV21
+ type = nv_order;
+#endif
+ /* swap uv */
+ if (hw->is_used_v4l) {
+ if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12) ||
+ (v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12M))
+ nv_order = VIDTYPE_VIU_NV12;
+ }
+
+ if (hw->i_only) {
+ pb_skip = 1;
+ }
+
+ user_data_ready_notify(hw, pic->pts, pic->pts_valid);
+
+ if (hw->frame_prog & PICINFO_PROG) {
+ field_num = 1;
+ type |= VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD | nv_order;
+ } else {
+#ifdef INTERLACE_SEQ_ALWAYS
+ /* once an interlace seq, force interlace, to make di easy. */
+ hw->dec_control |= DEC_CONTROL_FLAG_FORCE_SEQ_INTERLACE;
+#endif
+ hw->frame_rpt_state = FRAME_REPEAT_NONE;
+
+ first_field_type = (info & PICINFO_TOP_FIRST) ?
+ VIDTYPE_INTERLACE_TOP : VIDTYPE_INTERLACE_BOTTOM;
+ field_num = (info & PICINFO_RPT_FIRST) ? 3 : 2;
+ }
+
+ for (i = 0; i < field_num; i++) {
+ if (kfifo_get(&hw->newframe_q, &vf) == 0) {
+ debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR,
+ "fatal error, no available buffer slot.");
+ hw->dec_result = DEC_RESULT_ERROR;
+ vdec_schedule_work(&hw->work);
+ return -1;
+ }
+
+ if (hw->is_used_v4l) {
+ vf->v4l_mem_handle
+ = hw->pics[index].v4l_ref_buf_addr;
+ debug_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL,
+ "[%d] %s(), v4l mem handle: 0x%lx\n",
+ ((struct aml_vcodec_ctx *)(hw->v4l2_ctx))->id,
+ __func__, vf->v4l_mem_handle);
+ }
+
+ hw->vfbuf_use[index]++;
+ vf->index = index;
+ set_frame_info(hw, vf);
+ if (field_num > 1) {
+ vf->duration = vf->duration / field_num;
+ vf->duration_pulldown = (field_num == 3) ?
+ (vf->duration >> 1):0;
+ if (i > 0)
+ type = nv_order;
+ if (i == 1) /* second field*/
+ type |= (first_field_type == VIDTYPE_INTERLACE_TOP) ?
+ VIDTYPE_INTERLACE_BOTTOM : VIDTYPE_INTERLACE_TOP;
+ else
+ type |= (first_field_type == VIDTYPE_INTERLACE_TOP) ?
+ VIDTYPE_INTERLACE_TOP : VIDTYPE_INTERLACE_BOTTOM;
+ } else {
+ if ((hw->seqinfo & SEQINFO_EXT_AVAILABLE) &&
+ (hw->seqinfo & SEQINFO_PROG)) {
+ if (info & PICINFO_RPT_FIRST) {
+ if (info & PICINFO_TOP_FIRST)
+ vf->duration *= 3;
+ else
+ vf->duration *= 2;
+ }
+ vf->duration_pulldown = 0;
+ } else {
+ vf->duration_pulldown =
+ (info & PICINFO_RPT_FIRST) ?
+ vf->duration >> 1 : 0;
+ }
+ }
+ vf->duration += vf->duration_pulldown;
+ vf->type = type;
+ vf->signal_type = hw->reg_signal_type;
+ vf->orientation = 0;
+ if (i > 0) {
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+ } else {
+ vf->pts = (pic->pts_valid) ? pic->pts : 0;
+ vf->pts_us64 = (pic->pts_valid) ? pic->pts64 : 0;
+ }
+ vf->type_original = vf->type;
+
+ if ((error_skip(hw, pic->buffer_info, vf)) ||
+ (((hw->first_i_frame_ready == 0) || pb_skip) &&
+ ((PICINFO_TYPE_MASK & pic->buffer_info) !=
+ PICINFO_TYPE_I))) {
+ unsigned long flags;
+ hw->drop_frame_count++;
+ if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_I) {
+ hw->gvs.i_lost_frames++;
+ } else if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_P) {
+ hw->gvs.p_lost_frames++;
+ } else if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_B) {
+ hw->gvs.b_lost_frames++;
+ }
+ /* Though we drop it, it is still an error frame, count it.
+ * Becase we've counted the error frame in vdec_count_info
+ * function, avoid count it twice.
+ */
+ if (!(info & PICINFO_ERROR)) {
+ hw->gvs.error_frame_count++;
+ if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_I) {
+ hw->gvs.i_concealed_frames++;
+ } else if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_P) {
+ hw->gvs.p_concealed_frames++;
+ } else if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_B) {
+ hw->gvs.b_concealed_frames++;
+ }
+ }
+ hw->vfbuf_use[index]--;
+ spin_lock_irqsave(&hw->lock, flags);
+ kfifo_put(&hw->newframe_q,
+ (const struct vframe_s *)vf);
+ spin_unlock_irqrestore(&hw->lock, flags);
+ } else {
+ debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEINFO,
+ "%s, vf: %lx, num[%d]: %d(%c), dur: %d, type: %x, pts: %d(%lld)\n",
+ __func__, (ulong)vf, i, hw->disp_num, GET_SLICE_TYPE(info),
+ vf->duration, vf->type, vf->pts, vf->pts_us64);
+ hw->disp_num++;
+ if (i == 0) {
+ decoder_do_frame_check(vdec, vf);
+ hw_update_gvs(hw);
+ vdec_fill_vdec_frame(vdec, &hw->vframe_qos,
+ &hw->gvs, vf, pic->hw_decode_time);
+ }
+ vdec->vdec_fps_detec(vdec->id);
+ vf->mem_handle =
+ decoder_bmmu_box_get_mem_handle(
+ hw->mm_blk_handle, index);
+ 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) | pic->offset;
+ vf->pts = 0;
+ } else {
+ vf->pts_us64 = (u64)-1;
+ vf->pts = 0;
+ }
+ }
+ 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));
+ /* if (hw->disp_num == 1) { */
+ if (hw->kpi_first_i_decoded == 0) {
+ hw->kpi_first_i_decoded = 1;
+ debug_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL,
+ "[vdec_kpi][%s] First I frame decoded.\n",
+ __func__);
+ }
+ if (without_display_mode == 0) {
+ vf_notify_receiver(vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY,
+ NULL);
+ } else
+ vmpeg_vf_put(vmpeg_vf_get(vdec), vdec);
+
+
+ }
+ }
+ return 0;
+}
+
+static void force_interlace_check(struct vdec_mpeg12_hw_s *hw)
+{
+ if ((hw->dec_control &
+ DEC_CONTROL_FLAG_FORCE_2500_720_576_INTERLACE) &&
+ (hw->frame_width == 720) &&
+ (hw->frame_height == 576) &&
+ (hw->frame_dur == 3840)) {
+ hw->frame_prog = 0;
+ } else if ((hw->dec_control
+ & DEC_CONTROL_FLAG_FORCE_3000_704_480_INTERLACE) &&
+ (hw->frame_width == 704) &&
+ (hw->frame_height == 480) &&
+ (hw->frame_dur == 3200)) {
+ hw->frame_prog = 0;
+ } else if ((hw->dec_control
+ & DEC_CONTROL_FLAG_FORCE_2500_704_576_INTERLACE) &&
+ (hw->frame_width == 704) &&
+ (hw->frame_height == 576) &&
+ (hw->frame_dur == 3840)) {
+ hw->frame_prog = 0;
+ } else if ((hw->dec_control
+ & DEC_CONTROL_FLAG_FORCE_2500_544_576_INTERLACE) &&
+ (hw->frame_width == 544) &&
+ (hw->frame_height == 576) &&
+ (hw->frame_dur == 3840)) {
+ hw->frame_prog = 0;
+ } else if ((hw->dec_control
+ & DEC_CONTROL_FLAG_FORCE_2500_480_576_INTERLACE) &&
+ (hw->frame_width == 480) &&
+ (hw->frame_height == 576) &&
+ (hw->frame_dur == 3840)) {
+ hw->frame_prog = 0;
+ } else if (hw->dec_control
+ & DEC_CONTROL_FLAG_FORCE_SEQ_INTERLACE) {
+ hw->frame_prog = 0;
+ }
+
+}
+
+static int update_reference(struct vdec_mpeg12_hw_s *hw,
+ int index)
+{
+ hw->ref_use[index]++;
+ if (hw->refs[1] == -1) {
+ hw->refs[1] = index;
+ /*
+ * first pic need output to show
+ * usecnt do not decrease.
+ */
+ } else if (hw->refs[0] == -1) {
+ hw->refs[0] = hw->refs[1];
+ hw->refs[1] = index;
+ /* second pic do not output */
+ index = hw->buf_num;
+ } else {
+ hw->ref_use[hw->refs[0]]--; //old ref0 ununsed
+ hw->refs[0] = hw->refs[1];
+ hw->refs[1] = index;
+ index = hw->refs[0];
+ }
+ return index;
+}
+
+static bool is_ref_error(struct vdec_mpeg12_hw_s *hw)
+{
+ if ((hw->pics[hw->refs[0]].buffer_info & PICINFO_ERROR) ||
+ (hw->pics[hw->refs[1]].buffer_info & PICINFO_ERROR))
+ return 1;
+ return 0;
+}
+
+static int vmpeg2_get_ps_info(struct vdec_mpeg12_hw_s *hw, int width, int height,
+ bool frame_prog, struct aml_vdec_ps_infos *ps)
+{
+ ps->visible_width = width;
+ ps->visible_height = height;
+ ps->coded_width = ALIGN(width, 64);
+ ps->coded_height = ALIGN(height, 32);
+ ps->dpb_size = hw->buf_num;
+ ps->field = frame_prog ? V4L2_FIELD_NONE : V4L2_FIELD_INTERLACED;
+
+ return 0;
+}
+
+static int v4l_res_change(struct vdec_mpeg12_hw_s *hw, int width, int height, bool frame_prog)
+{
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(hw->v4l2_ctx);
+ int ret = 0;
+
+ if (ctx->param_sets_from_ucode &&
+ hw->res_ch_flag == 0) {
+ struct aml_vdec_ps_infos ps;
+
+ if ((hw->frame_width != 0 &&
+ hw->frame_height != 0) &&
+ (hw->frame_width != width ||
+ hw->frame_height != height)) {
+ debug_print(DECODE_ID(hw), 0,
+ "v4l_res_change Pic Width/Height Change (%d,%d)=>(%d,%d)\n",
+ hw->frame_width, hw->frame_height,
+ width,
+ height);
+ vmpeg2_get_ps_info(hw, width, height, frame_prog, &ps);
+ vdec_v4l_set_ps_infos(ctx, &ps);
+ vdec_v4l_res_ch_event(ctx);
+ hw->v4l_params_parsed = false;
+ hw->res_ch_flag = 1;
+ ctx->v4l_resolution_change = 1;
+ hw->eos = 1;
+ flush_output(hw);
+ notify_v4l_eos(hw_to_vdec(hw));
+
+ ret = 1;
+ }
+ }
+
+ return ret;
+}
+
+#ifdef VDEC_FCC_SUPPORT
+static void fcc_discard_mode_process(struct vdec_s *vdec)
+{
+ struct vdec_mpeg12_hw_s *hw =
+ (struct vdec_mpeg12_hw_s *)(vdec->private);
+ int wrap_count;
+ u32 rp;
+ u32 first_ptr;
+
+ if (vdec->fcc_status == AGAIN_STATUS) {
+ wrap_count = READ_VREG(VLD_MEM_VIFIFO_WRAP_COUNT);
+ rp = READ_VREG(VLD_MEM_VIFIFO_RP);
+ first_ptr = vdec->vbuf.ext_buf_addr;
+
+ vdec->stream_offset = rp + vdec->input.size * wrap_count - first_ptr;
+ debug_print(DECODE_ID(hw), PRINT_FLAG_FCC_STATUS,
+ "[%d][FCC]: Notify stream_offset: %d\n",
+ vdec->id, vdec->stream_offset);
+
+ debug_print(DECODE_ID(hw), PRINT_FLAG_FCC_STATUS,
+ "[%d][FCC]: rp : 0x%x size: 0x%x wrap_count:%d first_ptr: 0x%x\n",
+ vdec->id, rp, vdec->input.size, wrap_count, first_ptr);
+ vdec_wakeup_fcc_poll(vdec);
+ vdec->fcc_status = WAIT_MSG_STATUS;
+ hw->dec_result = DEC_RESULT_AGAIN;
+ vdec_schedule_work(&hw->work);
+ } else if (vdec->fcc_status == DISCARD_STATUS) {
+ debug_print(DECODE_ID(hw), PRINT_FLAG_FCC_STATUS,
+ "[%d][FCC]: Discard current gop and to find next gop!\n",
+ vdec->id);
+ vdec->fcc_status = AGAIN_STATUS;
+ hw->dec_result = DEC_RESULT_DISCARD_DATA;
+ vdec_schedule_work(&hw->work);
+ }
+}
+
+static int vmpeg2_fcc_process(struct vdec_s *vdec)
+{
+ struct vdec_mpeg12_hw_s *hw =
+ (struct vdec_mpeg12_hw_s *)(vdec->private);
+
+ if (input_stream_based(vdec)) {
+ switch (vdec->fcc_mode) {
+ case FCC_DISCARD_MODE:
+ fcc_discard_mode_process(vdec);
+ return 1;
+ case FCC_DEC_MODE:
+ debug_print(DECODE_ID(hw), PRINT_FLAG_FCC_STATUS,
+ "[%d][FCC]: Current is Dec mode.\n", vdec->id);
+ break;
+ case FCC_BUTT:
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+static irqreturn_t vmpeg12_isr_thread_fn(struct vdec_s *vdec, int irq)
+{
+ u32 reg, index, info, seqinfo, offset, pts, frame_size=0, tmp;
+ u64 pts_us64 = 0;
+ struct pic_info_t *new_pic, *disp_pic;
+ struct vdec_mpeg12_hw_s *hw =
+ (struct vdec_mpeg12_hw_s *)(vdec->private);
+
+ if (READ_VREG(AV_SCRATCH_M) != 0 &&
+ (debug_enable & PRINT_FLAG_UCODE_DETAIL)) {
+
+ debug_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL,
+ "dbg %x: %x, level %x, wp %x, rp %x, cnt %x\n",
+ READ_VREG(AV_SCRATCH_M), READ_VREG(AV_SCRATCH_N),
+ READ_VREG(VLD_MEM_VIFIFO_LEVEL),
+ READ_VREG(VLD_MEM_VIFIFO_WP),
+ READ_VREG(VLD_MEM_VIFIFO_RP),
+ READ_VREG(VIFF_BIT_CNT));
+ WRITE_VREG(AV_SCRATCH_M, 0);
+ return IRQ_HANDLED;
+ }
+
+ reg = READ_VREG(AV_SCRATCH_G);
+ if (reg == 1) {
+ if (hw->kpi_first_i_comming == 0) {
+ hw->kpi_first_i_comming = 1;
+ debug_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL,
+ "[vdec_kpi][%s] First I frame coming.\n",
+ __func__);
+ }
+
+#ifdef VDEC_FCC_SUPPORT
+ if (vmpeg2_fcc_process(vdec) > 0) {
+ WRITE_VREG(AV_SCRATCH_G, 0);
+ return IRQ_HANDLED;
+ }
+#endif
+ if (hw->is_used_v4l) {
+ int frame_width = READ_VREG(MREG_PIC_WIDTH);
+ int frame_height = READ_VREG(MREG_PIC_HEIGHT);
+ int info = READ_VREG(MREG_SEQ_INFO);
+ bool frame_prog = info & 0x10000;
+
+ if (!v4l_res_change(hw, frame_width, frame_height, frame_prog)) {
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(hw->v4l2_ctx);
+ if (ctx->param_sets_from_ucode && !hw->v4l_params_parsed) {
+ struct aml_vdec_ps_infos ps;
+
+ vmpeg2_get_ps_info(hw, frame_width, frame_height, frame_prog, &ps);
+ hw->v4l_params_parsed = true;
+ vdec_v4l_set_ps_infos(ctx, &ps);
+ userdata_pushed_drop(hw);
+ reset_process_time(hw);
+ hw->dec_result = DEC_RESULT_AGAIN;
+ vdec_schedule_work(&hw->work);
+ } else {
+ WRITE_VREG(AV_SCRATCH_G, 0);
+ }
+ } else {
+ userdata_pushed_drop(hw);
+ reset_process_time(hw);
+ hw->dec_result = DEC_RESULT_AGAIN;
+ vdec_schedule_work(&hw->work);
+ }
+ } else
+ WRITE_VREG(AV_SCRATCH_G, 0);
+ return IRQ_HANDLED;
+ }
+
+ reg = READ_VREG(AV_SCRATCH_J);
+ if (reg & (1 << 16)) {
+ vdec_schedule_work(&hw->userdata_push_work);
+ return IRQ_HANDLED;
+ }
+
+ reg = READ_VREG(MREG_BUFFEROUT);
+ if (reg == MPEG12_DATA_REQUEST) {
+ debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW,
+ "%s: data request, bcnt=%x\n",
+ __func__, READ_VREG(VIFF_BIT_CNT));
+ if (vdec_frame_based(vdec)) {
+ reset_process_time(hw);
+ hw->dec_result = DEC_RESULT_GET_DATA;
+ vdec_schedule_work(&hw->work);
+ }
+ } else if (reg == MPEG12_DATA_EMPTY) {
+ /*timeout when decoding next frame*/
+ debug_print(DECODE_ID(hw), PRINT_FLAG_VLD_DETAIL,
+ "%s: Insufficient data, lvl=%x ctrl=%x bcnt=%x\n",
+ __func__,
+ READ_VREG(VLD_MEM_VIFIFO_LEVEL),
+ READ_VREG(VLD_MEM_VIFIFO_CONTROL),
+ READ_VREG(VIFF_BIT_CNT));
+ if (vdec_frame_based(vdec)) {
+ userdata_pushed_drop(hw);
+ hw->dec_result = DEC_RESULT_DONE;
+ vdec_schedule_work(&hw->work);
+ } else {
+ hw->dec_result = DEC_RESULT_AGAIN;
+ vdec_schedule_work(&hw->work);
+ userdata_pushed_drop(hw);
+ reset_process_time(hw);
+ }
+ return IRQ_HANDLED;
+ } else { /* MPEG12_PIC_DONE, MPEG12_SEQ_END */
+ reset_process_time(hw);
+
+ info = READ_VREG(MREG_PIC_INFO);
+ offset = READ_VREG(MREG_FRAME_OFFSET);
+ index = spec_to_index(hw, READ_VREG(REC_CANVAS_ADDR));
+ seqinfo = READ_VREG(MREG_SEQ_INFO);
+
+ if (((seqinfo >> 8) & 0xff) &&
+ ((seqinfo >> 12 & 0x7) != hw->profile_idc ||
+ (seqinfo >> 8 & 0xf) != hw->level_idc)) {
+ hw->profile_idc = seqinfo >> 12 & 0x7;
+ hw->level_idc = seqinfo >> 8 & 0xf;
+ vdec_set_profile_level(vdec, hw->profile_idc, hw->level_idc);
+ debug_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL,
+ "profile_idc: %d level_idc: %d\n",
+ hw->profile_idc, hw->level_idc);
+ }
+
+ if ((info & PICINFO_PROG) == 0 &&
+ (info & FRAME_PICTURE_MASK) != FRAME_PICTURE) {
+ hw->first_i_frame_ready = 1; /* for field struct case*/
+ }
+ if (index >= hw->buf_num) {
+ debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR,
+ "mmpeg12: invalid buf index: %d\n", index);
+ hw->dec_result = DEC_RESULT_ERROR;
+ vdec_schedule_work(&hw->work);
+ return IRQ_HANDLED;
+ }
+ hw->dec_num++;
+ hw->dec_result = DEC_RESULT_DONE;
+ new_pic = &hw->pics[index];
+ if (vdec->mvfrm) {
+ new_pic->frame_size = vdec->mvfrm->frame_size;
+ new_pic->hw_decode_time =
+ local_clock() - vdec->mvfrm->hw_decode_start;
+ }
+ tmp = READ_VREG(MREG_PIC_WIDTH);
+ if ((tmp > 1920) || (tmp == 0)) {
+ new_pic->width = 1920;
+ hw->frame_width = 1920;
+ } else {
+ new_pic->width = tmp;
+ hw->frame_width = tmp;
+ }
+
+ tmp = READ_VREG(MREG_PIC_HEIGHT);
+ if ((tmp > 1088) || (tmp == 0)) {
+ new_pic->height = 1088;
+ hw->frame_height = 1088;
+ } else {
+ new_pic->height = tmp;
+ hw->frame_height = tmp;
+ }
+
+ new_pic->buffer_info = info;
+ new_pic->offset = offset;
+ new_pic->index = index;
+ if (((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_I) ||
+ ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_P)) {
+ if (hw->chunk) {
+ new_pic->pts_valid = hw->chunk->pts_valid;
+ new_pic->pts = hw->chunk->pts;
+ new_pic->pts64 = hw->chunk->pts64;
+ if (hw->last_chunk_pts == hw->chunk->pts) {
+ new_pic->pts_valid = 0;
+ debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEINFO,
+ "pts invalid\n");
+ }
+ } else {
+ 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) {
+ new_pic->pts_valid = true;
+ new_pic->pts = pts;
+ new_pic->pts64 = pts_us64;
+ } else
+ new_pic->pts_valid = false;
+ }
+ }
+ } else {
+ if (hw->chunk)
+ hw->last_chunk_pts = hw->chunk->pts;
+ new_pic->pts_valid = false;
+ }
+
+ debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW,
+ "mmpeg12: new_pic=%d, ind=%d, info=%x, seq=%x, offset=%d\n",
+ hw->dec_num, index, info, seqinfo, offset);
+
+ hw->frame_prog = info & PICINFO_PROG;
+ if ((seqinfo & SEQINFO_EXT_AVAILABLE) &&
+ ((seqinfo & SEQINFO_PROG) == 0))
+ hw->frame_prog = 0;
+ force_interlace_check(hw);
+
+ if (is_ref_error(hw)) {
+ if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_B)
+ new_pic->buffer_info |= PICINFO_ERROR;
+ }
+
+ if (((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_I) ||
+ ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_P)) {
+ index = update_reference(hw, index);
+ } else {
+ /* drop b frame before reference pic ready */
+ if (hw->refs[0] == -1)
+ index = hw->buf_num;
+ }
+ vmpeg12_save_hw_context(hw, reg);
+
+ if (index >= hw->buf_num) {
+ if (hw->dec_num != 2) {
+ debug_print(DECODE_ID(hw), 0,
+ "mmpeg12: drop pic num %d, type %c, index %d, offset %x\n",
+ hw->dec_num, GET_SLICE_TYPE(info), index, offset);
+ hw->dec_result = DEC_RESULT_ERROR;
+ }
+ vdec_schedule_work(&hw->work);
+ return IRQ_HANDLED;
+ }
+
+ disp_pic = &hw->pics[index];
+ info = hw->pics[index].buffer_info;
+ if (disp_pic->pts_valid && hw->lastpts64 == disp_pic->pts64)
+ disp_pic->pts_valid = false;
+ if (disp_pic->pts_valid)
+ hw->lastpts64 = disp_pic->pts64;
+
+ if (input_frame_based(hw_to_vdec(hw)))
+ frame_size = new_pic->frame_size;
+
+ fill_frame_info(hw, info, frame_size, new_pic->pts);
+
+ if ((hw->first_i_frame_ready == 0) &&
+ ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_I) &&
+ ((info & PICINFO_ERROR) == 0)) {
+ hw->first_i_frame_ready = 1;
+ }
+
+ debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW,
+ "mmpeg12: disp_pic=%d(%c), ind=%d, offst=%x, pts=(%d,%lld)(%d)\n",
+ hw->disp_num, GET_SLICE_TYPE(info), index, disp_pic->offset,
+ disp_pic->pts, disp_pic->pts64, disp_pic->pts_valid);
+
+ prepare_display_buf(hw, disp_pic);
+ vdec_schedule_work(&hw->work);
+ }
+
+ return IRQ_HANDLED;
+}
+static irqreturn_t vmpeg12_isr(struct vdec_s *vdec, int irq)
+{
+ u32 info, offset;
+ struct vdec_mpeg12_hw_s *hw =
+ (struct vdec_mpeg12_hw_s *)(vdec->private);
+ if (hw->eos)
+ return IRQ_HANDLED;
+ info = READ_VREG(MREG_PIC_INFO);
+ offset = READ_VREG(MREG_FRAME_OFFSET);
+ if (offset != hw->last_frame_offset) {
+ vdec_count_info(&hw->gvs, info & PICINFO_ERROR, offset);
+ if (info & PICINFO_ERROR) {
+ if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_I) {
+ hw->gvs.i_concealed_frames++;
+ } else if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_P) {
+ hw->gvs.p_concealed_frames++;
+ } else if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_B) {
+ hw->gvs.b_concealed_frames++;
+ }
+ }
+ if (offset) {
+ if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_I) {
+ hw->gvs.i_decoded_frames++;
+ } else if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_P) {
+ hw->gvs.p_decoded_frames++;
+ } else if ((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_B) {
+ hw->gvs.b_decoded_frames++;
+ }
+ }
+ hw->last_frame_offset = offset;
+ }
+
+ WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
+
+ return IRQ_WAKE_THREAD;
+}
+
+static void vmpeg12_notify_work(struct work_struct *work)
+{
+ struct vdec_mpeg12_hw_s *hw = container_of(work,
+ struct vdec_mpeg12_hw_s, notify_work);
+ struct vdec_s *vdec = hw_to_vdec(hw);
+
+ 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;
+ }
+}
+
+static void wait_vmmpeg12_search_done(struct vdec_mpeg12_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 > 1000) {
+ debug_print(DECODE_ID(hw), 0,
+ "%s, 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 flush_output(struct vdec_mpeg12_hw_s *hw)
+{
+ int index = hw->refs[1];
+
+ /* video only one frame need not flush. */
+ if (hw->dec_num < 2)
+ return;
+
+ if ((hw->refs[0] >= 0) &&
+ (hw->refs[0] < hw->buf_num))
+ hw->ref_use[hw->refs[0]] = 0;
+
+ if (index >= 0 && index < hw->buf_num) {
+ hw->ref_use[index] = 0;
+ prepare_display_buf(hw, &hw->pics[index]);
+ }
+}
+
+static int notify_v4l_eos(struct vdec_s *vdec)
+{
+ struct vdec_mpeg12_hw_s *hw = (struct vdec_mpeg12_hw_s *)vdec->private;
+ struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx);
+ struct vframe_s *vf = NULL;
+ struct vdec_v4l2_buffer *fb = NULL;
+ int index = -1;
+
+ if (hw->eos) {
+ if (kfifo_get(&hw->newframe_q, &vf) == 0 || vf == NULL) {
+ debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR,
+ "%s fatal error, no available buffer slot.\n",
+ __func__);
+ return -1;
+ }
+ if (hw->is_used_v4l) {
+ index = find_free_buffer(hw);
+ if ((index == -1) &&
+ vdec_v4l_get_buffer(hw->v4l2_ctx, &fb)) {
+ pr_err("[%d] get fb fail.\n", ctx->id);
+ return -1;
+ }
+ }
+
+ vf->type |= VIDTYPE_V4L_EOS;
+ vf->timestamp = ULONG_MAX;
+ vf->v4l_mem_handle = (index == -1) ? (ulong)fb :
+ hw->pics[index].v4l_ref_buf_addr;
+ vf->flag = VFRAME_FLAG_EMPTY_FRAME_V4L;
+
+ vdec_vframe_ready(vdec, vf);
+ kfifo_put(&hw->display_q, (const struct vframe_s *)vf);
+ ATRACE_COUNTER(hw->pts_name, vf->pts);
+ vf_notify_receiver(vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
+
+ pr_info("[%d] mpeg12 EOS notify.\n", (hw->is_used_v4l)?ctx->id:vdec->id);
+ }
+
+ return 0;
+}
+
+static void vmpeg12_work_implement(struct vdec_mpeg12_hw_s *hw,
+ struct vdec_s *vdec, int from)
+{
+ int r;
+
+ if (hw->dec_result != DEC_RESULT_DONE)
+ debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW,
+ "%s, result=%d, status=%d\n", __func__,
+ hw->dec_result, vdec->next_status);
+ if (hw->dec_result == DEC_RESULT_DONE) {
+ if (vdec->input.swap_valid)
+ hw->dec_again_cnt = 0;
+ vdec_vframe_dirty(vdec, hw->chunk);
+ hw->chunk = NULL;
+ } else if (hw->dec_result == DEC_RESULT_AGAIN &&
+ (vdec->next_status != VDEC_STATUS_DISCONNECTED)) {
+ /*
+ stream base: stream buf empty or timeout
+ frame base: vdec_prepare_input fail
+ */
+ if (!vdec_has_more_input(vdec)) {
+ hw->dec_result = DEC_RESULT_EOS;
+ vdec_schedule_work(&hw->work);
+ return;
+ }
+ if ((vdec_stream_based(vdec)) &&
+ (error_proc_policy & 0x1) &&
+ check_dirty_data(vdec)) {
+ hw->dec_result = DEC_RESULT_DONE;
+ vdec_schedule_work(&hw->work);
+ return;
+ }
+#ifdef AGAIN_HAS_THRESHOLD
+ hw->next_again_flag = 1;
+#endif
+ //hw->dec_again_cnt++;
+ } else if (hw->dec_result == DEC_RESULT_GET_DATA &&
+ vdec->next_status != VDEC_STATUS_DISCONNECTED) {
+ if (!vdec_has_more_input(vdec)) {
+ hw->dec_result = DEC_RESULT_EOS;
+ vdec_schedule_work(&hw->work);
+ return;
+ }
+ debug_print(DECODE_ID(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(vdec, hw->chunk);
+ hw->chunk = NULL;
+ vdec_clean_input(vdec);
+
+ r = vdec_prepare_input(vdec, &hw->chunk);
+ if (r < 0) {
+ hw->input_empty++;
+ reset_process_time(hw);
+ hw->dec_result = DEC_RESULT_GET_DATA;
+ debug_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL,
+ "%s: Insufficient data, get data retry\n", __func__);
+ vdec_schedule_work(&hw->work);
+ return;
+ }
+ hw->input_empty = 0;
+ if (vdec_frame_based(vdec) && (hw->chunk != NULL)) {
+ r = hw->chunk->size +
+ (hw->chunk->offset & (VDEC_FIFO_ALIGN - 1));
+ WRITE_VREG(VIFF_BIT_CNT, r * 8);
+ if (vdec->mvfrm)
+ vdec->mvfrm->frame_size += hw->chunk->size;
+ }
+ debug_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS,
+ "%s: %x %x %x size %d, bitcnt %d\n",
+ __func__,
+ READ_VREG(VLD_MEM_VIFIFO_LEVEL),
+ READ_VREG(VLD_MEM_VIFIFO_WP),
+ READ_VREG(VLD_MEM_VIFIFO_RP),
+ r, READ_VREG(VIFF_BIT_CNT));
+ vdec_enable_input(vdec);
+ hw->dec_result = DEC_RESULT_NONE;
+ hw->last_vld_level = 0;
+ start_process_time_set(hw);
+ hw->init_flag = 1;
+ mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL);
+ WRITE_VREG(MREG_BUFFEROUT, 0);
+ return;
+ } else if (hw->dec_result == DEC_RESULT_FORCE_EXIT) {
+ debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR,
+ "%s: force exit\n", __func__);
+ if (hw->stat & STAT_ISR_REG) {
+ amvdec_stop();
+ vdec_free_irq(VDEC_IRQ_1, (void *)hw);
+ hw->stat &= ~STAT_ISR_REG;
+ }
+ } else if (hw->dec_result == DEC_RESULT_EOS) {
+ if (hw->stat & STAT_VDEC_RUN) {
+ amvdec_stop();
+ hw->stat &= ~STAT_VDEC_RUN;
+ }
+ hw->eos = 1;
+ vdec_vframe_dirty(vdec, hw->chunk);
+ hw->chunk = NULL;
+ vdec_clean_input(vdec);
+ flush_output(hw);
+ notify_v4l_eos(vdec);
+
+ debug_print(DECODE_ID(hw), 0,
+ "%s: end of stream, num %d(%d)\n",
+ __func__, hw->disp_num, hw->dec_num);
+ } else if (hw->dec_result == DEC_RESULT_DISCARD_DATA) {
+ hw->dec_again_cnt = 0;
+ vdec_vframe_dirty(vdec, hw->chunk);
+ hw->chunk = NULL;
+ }
+ if (hw->stat & STAT_VDEC_RUN) {
+ amvdec_stop();
+ hw->stat &= ~STAT_VDEC_RUN;
+ }
+ /*disable mbox interrupt */
+ WRITE_VREG(ASSIST_MBOX1_MASK, 0);
+ del_timer_sync(&hw->check_timer);
+ hw->stat &= ~STAT_TIMER_ARM;
+ wait_vmmpeg12_search_done(hw);
+
+ if (from == 1) {
+ /*This is a timeout work*/
+ if (work_pending(&hw->work)) {
+ pr_err("timeout work return befor finishing.");
+ /*
+ * The vmpeg12_work arrives at the last second,
+ * give it a chance to handle the scenario.
+ */
+ return;
+ }
+ }
+
+ if (vdec->parallel_dec == 1)
+ vdec_core_finish_run(vdec, CORE_MASK_VDEC_1);
+ else
+ vdec_core_finish_run(vdec, CORE_MASK_VDEC_1 | CORE_MASK_HEVC);
+
+ 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(vdec, hw->vdec_cb_arg);
+}
+
+static void vmpeg12_work(struct work_struct *work)
+{
+ struct vdec_mpeg12_hw_s *hw =
+ container_of(work, struct vdec_mpeg12_hw_s, work);
+ struct vdec_s *vdec = hw_to_vdec(hw);
+
+ vmpeg12_work_implement(hw, vdec, 0);
+}
+static void vmpeg12_timeout_work(struct work_struct *work)
+{
+ struct vdec_mpeg12_hw_s *hw =
+ container_of(work, struct vdec_mpeg12_hw_s, timeout_work);
+ struct vdec_s *vdec = hw_to_vdec(hw);
+
+ if (work_pending(&hw->work)) {
+ pr_err("timeout work return befor executing.");
+ return;
+ }
+
+ hw->timeout_processing = 1;
+ vmpeg12_work_implement(hw, vdec, 1);
+}
+
+static struct vframe_s *vmpeg_vf_peek(void *op_arg)
+{
+ struct vframe_s *vf;
+ struct vdec_s *vdec = op_arg;
+ struct vdec_mpeg12_hw_s *hw =
+ (struct vdec_mpeg12_hw_s *)vdec->private;
+ hw->peek_num++;
+ if (kfifo_peek(&hw->display_q, &vf))
+ return vf;
+
+ return NULL;
+}
+
+static struct vframe_s *vmpeg_vf_get(void *op_arg)
+{
+ struct vframe_s *vf;
+ struct vdec_s *vdec = op_arg;
+ struct vdec_mpeg12_hw_s *hw =
+ (struct vdec_mpeg12_hw_s *)vdec->private;
+
+ hw->get_num++;
+ if (kfifo_get(&hw->display_q, &vf)) {
+ ATRACE_COUNTER(hw->disp_q_name, kfifo_len(&hw->display_q));
+ return vf;
+ }
+ return NULL;
+}
+
+static int mpeg12_valid_vf_check(struct vframe_s *vf, struct vdec_mpeg12_hw_s *hw)
+{
+ int i;
+
+ if (vf == NULL)
+ return 0;
+
+ for (i = 0; i < VF_POOL_SIZE; i++) {
+ if (vf == &hw->vfpool[i])
+ return 1;
+ }
+ return 0;
+}
+
+static void vmpeg_vf_put(struct vframe_s *vf, void *op_arg)
+{
+ struct vdec_s *vdec = op_arg;
+ struct vdec_mpeg12_hw_s *hw =
+ (struct vdec_mpeg12_hw_s *)vdec->private;
+ unsigned long flags;
+
+ if (!mpeg12_valid_vf_check(vf, hw)) {
+ debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR,
+ "invalid vf: %lx\n", (ulong)vf);
+ return ;
+ }
+ spin_lock_irqsave(&hw->lock, flags);
+ hw->vfbuf_use[vf->index]--;
+ if (hw->vfbuf_use[vf->index] < 0) {
+ debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR,
+ "warn: vf %lx, index %d putback repetitive, set use to 0\n", (ulong)vf, vf->index);
+ hw->vfbuf_use[vf->index] = 0;
+ }
+ hw->put_num++;
+ debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW,
+ "%s: vf: %lx, index: %d, use: %d\n", __func__, (ulong)vf,
+ vf->index, hw->vfbuf_use[vf->index]);
+ kfifo_put(&hw->newframe_q,
+ (const struct vframe_s *)vf);
+ ATRACE_COUNTER(hw->new_q_name, kfifo_len(&hw->newframe_q));
+ spin_unlock_irqrestore(&hw->lock, flags);
+}
+
+
+static int vmpeg_event_cb(int type, void *data, void *op_arg)
+{
+ struct vdec_s *vdec = op_arg;
+
+ 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 int vmpeg_vf_states(struct vframe_states *states, void *op_arg)
+{
+ unsigned long flags;
+ struct vdec_s *vdec = op_arg;
+ struct vdec_mpeg12_hw_s *hw =
+ (struct vdec_mpeg12_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);
+ states->buf_recycle_num = 0;
+
+ spin_unlock_irqrestore(&hw->lock, flags);
+ return 0;
+}
+
+static u32 get_ratio_control(struct vdec_mpeg12_hw_s *hw)
+{
+ u32 ar_bits;
+
+ u32 ratio_control;
+
+ ar_bits = hw->pixel_ratio;
+
+ if (ar_bits == 0x2)
+ ratio_control = 0xc0 << DISP_RATIO_ASPECT_RATIO_BIT;
+
+ else if (ar_bits == 0x3)
+ ratio_control = 0x90 << DISP_RATIO_ASPECT_RATIO_BIT;
+
+ else if (ar_bits == 0x4)
+ ratio_control = 0x74 << DISP_RATIO_ASPECT_RATIO_BIT;
+ else
+ ratio_control = 0;
+
+ return ratio_control;
+}
+
+static int vmmpeg12_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus)
+{
+ struct vdec_mpeg12_hw_s *hw =
+ (struct vdec_mpeg12_hw_s *)vdec->private;
+
+ 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->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;
+ vstatus->ratio_control = get_ratio_control(hw);
+
+ snprintf(vstatus->vdec_name, sizeof(vstatus->vdec_name),
+ "%s", DRIVER_NAME);
+
+ return 0;
+}
+
+
+
+/****************************************/
+static void vmpeg12_canvas_init(struct vdec_mpeg12_hw_s *hw)
+{
+ int i, ret;
+ u32 canvas_width, canvas_height;
+ u32 decbuf_size, decbuf_y_size, decbuf_uv_size;
+ unsigned long decbuf_start;
+ /*u32 disp_addr = 0xffffffff;*/
+ struct vdec_s *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;
+ }
+
+ for (i = 0; i < hw->buf_num + 1; i++) {
+ unsigned canvas;
+
+ if (i == hw->buf_num) /* SWAP&CCBUF&MATIRX&MV */
+ decbuf_size = WORKSPACE_SIZE;
+
+ if (hw->is_used_v4l && !(i == hw->buf_num)) {
+ continue;
+ } else {
+ ret = decoder_bmmu_box_alloc_buf_phy(hw->mm_blk_handle, i,
+ decbuf_size, DRIVER_NAME, &decbuf_start);
+ if (ret < 0) {
+ pr_err("mmu alloc failed! size 0x%d idx %d\n",
+ decbuf_size, i);
+ return;
+ }
+ }
+
+ if (i == hw->buf_num) {
+ hw->cc_buf_size = AUX_BUF_ALIGN(CCBUF_SIZE);
+ hw->ccbuf_phyAddress_virt = dma_alloc_coherent(amports_get_dma_device(),
+ hw->cc_buf_size, &hw->ccbuf_phyAddress,
+ GFP_KERNEL);
+ if (hw->ccbuf_phyAddress_virt == NULL) {
+ pr_err("%s: failed to alloc cc buffer\n", __func__);
+ return;
+ }
+ hw->buf_start = decbuf_start;
+ WRITE_VREG(MREG_CO_MV_START, hw->buf_start);
+ WRITE_VREG(MREG_CC_ADDR, hw->ccbuf_phyAddress);
+ } else {
+ 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 =
+ decbuf_start;
+ hw->canvas_config[i][0].width =
+ canvas_width;
+ hw->canvas_config[i][0].height =
+ canvas_height;
+ hw->canvas_config[i][0].block_mode =
+ hw->canvas_mode;
+ hw->canvas_config[i][0].endian =
+ (hw->canvas_mode == CANVAS_BLKMODE_LINEAR)?7:0;
+
+ canvas_config_config(canvas_y(canvas),
+ &hw->canvas_config[i][0]);
+
+ hw->canvas_config[i][1].phy_addr =
+ decbuf_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 = hw->canvas_mode;
+ hw->canvas_config[i][1].endian =
+ (hw->canvas_mode == CANVAS_BLKMODE_LINEAR)?7:0;
+
+ canvas_config_config(canvas_u(canvas),
+ &hw->canvas_config[i][1]);
+ }
+ }
+ return;
+}
+
+static void vmpeg2_dump_state(struct vdec_s *vdec)
+{
+ struct vdec_mpeg12_hw_s *hw =
+ (struct vdec_mpeg12_hw_s *)(vdec->private);
+ u32 i;
+ debug_print(DECODE_ID(hw), 0,
+ "====== %s\n", __func__);
+ debug_print(DECODE_ID(hw), 0,
+ "width/height (%d/%d),i_first %d, buf_num %d\n",
+ hw->frame_width,
+ hw->frame_height,
+ hw->first_i_frame_ready,
+ hw->buf_num
+ );
+ debug_print(DECODE_ID(hw), 0,
+ "is_framebase(%d), eos %d, state 0x%x, dec_result 0x%x dec_frm %d put_frm %d run %d not_run_ready %d,input_empty %d\n",
+ vdec_frame_based(vdec),
+ hw->eos,
+ hw->stat,
+ hw->dec_result,
+ hw->dec_num,
+ hw->put_num,
+ hw->run_count,
+ hw->not_run_ready,
+ hw->input_empty
+ );
+
+ for (i = 0; i < hw->buf_num; i++) {
+ debug_print(DECODE_ID(hw), 0,
+ "index %d, used %d, ref %d\n", i,
+ hw->vfbuf_use[i], hw->ref_use[i]);
+ }
+
+ 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(DECODE_ID(hw), 0,
+ "\nreceiver(%s) state %d\n",
+ vdec->vf_provider_name,
+ state);
+ }
+ debug_print(DECODE_ID(hw), 0,
+ "%s, newq(%d/%d), dispq(%d/%d) vf pre/get/put (%d/%d/%d),drop=%d, buffer_not_ready %d\n",
+ __func__,
+ kfifo_len(&hw->newframe_q),
+ VF_POOL_SIZE,
+ kfifo_len(&hw->display_q),
+ VF_POOL_SIZE,
+ hw->disp_num,
+ hw->get_num,
+ hw->put_num,
+ hw->drop_frame_count,
+ hw->buffer_not_ready
+ );
+ debug_print(DECODE_ID(hw), 0,
+ "VIFF_BIT_CNT=0x%x\n",
+ READ_VREG(VIFF_BIT_CNT));
+ debug_print(DECODE_ID(hw), 0,
+ "VLD_MEM_VIFIFO_LEVEL=0x%x\n",
+ READ_VREG(VLD_MEM_VIFIFO_LEVEL));
+ debug_print(DECODE_ID(hw), 0,
+ "VLD_MEM_VIFIFO_WP=0x%x\n",
+ READ_VREG(VLD_MEM_VIFIFO_WP));
+ debug_print(DECODE_ID(hw), 0,
+ "VLD_MEM_VIFIFO_RP=0x%x\n",
+ READ_VREG(VLD_MEM_VIFIFO_RP));
+ debug_print(DECODE_ID(hw), 0,
+ "PARSER_VIDEO_RP=0x%x\n",
+ STBUF_READ(&vdec->vbuf, get_rp));
+ debug_print(DECODE_ID(hw), 0,
+ "PARSER_VIDEO_WP=0x%x\n",
+ STBUF_READ(&vdec->vbuf, get_wp));
+
+ if (vdec_frame_based(vdec) &&
+ debug_enable & 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(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)
+ debug_print(DECODE_ID(hw),
+ PRINT_FRAMEBASE_DATA,
+ "%06x:", jj);
+ debug_print(DECODE_ID(hw),
+ PRINT_FRAMEBASE_DATA,
+ "%02x ", data[jj]);
+ if (((jj + 1) & 0xf) == 0)
+ debug_print(DECODE_ID(hw),
+ PRINT_FRAMEBASE_DATA, "\n");
+ }
+
+ if (!hw->chunk->block->is_mapped)
+ codec_mm_unmap_phyaddr(data);
+ }
+ }
+}
+
+static void reset_process_time(struct vdec_mpeg12_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_set(struct vdec_mpeg12_hw_s *hw)
+{
+ if ((hw->refs[1] != -1) && (hw->refs[0] == -1))
+ hw->decode_timeout_count = 1;
+ else
+ hw->decode_timeout_count = 10;
+ hw->start_process_time = jiffies;
+}
+
+static void timeout_process(struct vdec_mpeg12_hw_s *hw)
+{
+ struct vdec_s *vdec = hw_to_vdec(hw);
+
+ if (work_pending(&hw->work) ||
+ work_busy(&hw->work) ||
+ work_busy(&hw->timeout_work) ||
+ work_pending(&hw->timeout_work)) {
+ pr_err("%s mpeg12[%d] timeout_process return befor do anything.\n",__func__, vdec->id);
+ return;
+ }
+ reset_process_time(hw);
+ amvdec_stop();
+ debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR,
+ "%s decoder timeout, status=%d, level=%d\n",
+ __func__, vdec->status, READ_VREG(VLD_MEM_VIFIFO_LEVEL));
+ hw->dec_result = DEC_RESULT_DONE;
+ if ((hw->refs[1] != -1) && (hw->refs[0] != -1))
+ hw->first_i_frame_ready = 0;
+
+ /*
+ * In this very timeout point,the vmpeg12_work arrives,
+ * let it to handle the scenario.
+ */
+ if (work_pending(&hw->work)) {
+ pr_err("%s mpeg12[%d] return befor schedule.", __func__, vdec->id);
+ return;
+ }
+ vdec_schedule_work(&hw->timeout_work);
+}
+
+static void check_timer_func(unsigned long arg)
+{
+ struct vdec_mpeg12_hw_s *hw = (struct vdec_mpeg12_hw_s *)arg;
+ struct vdec_s *vdec = hw_to_vdec(hw);
+ unsigned int timeout_val = decode_timeout_val;
+
+ 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 (((debug_enable & PRINT_FLAG_TIMEOUT_STATUS) == 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 (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 vmpeg12_hw_ctx_restore(struct vdec_mpeg12_hw_s *hw)
+{
+ int index = -1;
+ u32 i;
+ struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx;
+
+ index = find_free_buffer(hw);
+ if (index < 0 || index >= hw->buf_num)
+ return -1;
+ if (!hw->init_flag)
+ vmpeg12_canvas_init(hw);
+ else {
+ WRITE_VREG(MREG_CO_MV_START, hw->buf_start);
+ WRITE_VREG(MREG_CC_ADDR, hw->ccbuf_phyAddress);
+ if (!hw->is_used_v4l) {
+ for (i = 0; i < hw->buf_num; i++) {
+ canvas_config_config(canvas_y(hw->canvas_spec[i]),
+ &hw->canvas_config[i][0]);
+ canvas_config_config(canvas_u(hw->canvas_spec[i]),
+ &hw->canvas_config[i][1]);
+ }
+ }
+ }
+
+ /* prepare REF0 & REF1
+ points to the past two IP buffers
+ prepare REC_CANVAS_ADDR and ANC2_CANVAS_ADDR
+ points to the output buffer*/
+ WRITE_VREG(MREG_REF0,
+ (hw->refs[0] == -1) ? 0xffffffff :
+ hw->canvas_spec[hw->refs[0]]);
+ WRITE_VREG(MREG_REF1,
+ (hw->refs[1] == -1) ? 0xffffffff :
+ hw->canvas_spec[hw->refs[1]]);
+ WRITE_VREG(REC_CANVAS_ADDR, hw->canvas_spec[index]);
+ WRITE_VREG(ANC2_CANVAS_ADDR, hw->canvas_spec[index]);
+
+ debug_print(DECODE_ID(hw), PRINT_FLAG_RESTORE,
+ "%s,ref0=0x%x, ref1=0x%x,rec=0x%x, ctx_valid=%d,index=%d\n",
+ __func__,
+ READ_VREG(MREG_REF0),
+ READ_VREG(MREG_REF1),
+ READ_VREG(REC_CANVAS_ADDR),
+ hw->ctx_valid, index);
+ /* set to mpeg1 default */
+ WRITE_VREG(MPEG1_2_REG,
+ (hw->ctx_valid) ? hw->reg_mpeg1_2_reg : 0);
+ /* disable PSCALE for hardware sharing */
+ WRITE_VREG(PSCALE_CTRL, 0);
+ /* for Mpeg1 default value */
+ WRITE_VREG(PIC_HEAD_INFO,
+ (hw->ctx_valid) ? hw->reg_pic_head_info : 0x380);
+ /* disable mpeg4 */
+ WRITE_VREG(M4_CONTROL_REG, 0);
+ /* clear mailbox interrupt */
+ WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
+ /* clear buffer IN/OUT registers */
+ WRITE_VREG(MREG_BUFFEROUT, 0);
+ /* enable mailbox interrupt */
+ WRITE_VREG(ASSIST_MBOX1_MASK, 1);
+ /* set reference width and height */
+ if ((hw->frame_width != 0) && (hw->frame_height != 0))
+ WRITE_VREG(MREG_CMD,
+ (hw->frame_width << 16) | hw->frame_height);
+ else
+ WRITE_VREG(MREG_CMD, 0);
+
+ debug_print(DECODE_ID(hw), PRINT_FLAG_RESTORE,
+ "0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
+ hw->frame_width, hw->frame_height, hw->seqinfo,
+ hw->reg_f_code_reg, hw->reg_slice_ver_pos_pic_type,
+ hw->reg_mb_info);
+
+ WRITE_VREG(MREG_PIC_WIDTH, hw->reg_pic_width);
+ WRITE_VREG(MREG_PIC_HEIGHT, hw->reg_pic_height);
+ WRITE_VREG(MREG_SEQ_INFO, hw->seqinfo);
+ WRITE_VREG(F_CODE_REG, hw->reg_f_code_reg);
+ WRITE_VREG(SLICE_VER_POS_PIC_TYPE,
+ hw->reg_slice_ver_pos_pic_type);
+ WRITE_VREG(MB_INFO, hw->reg_mb_info);
+ WRITE_VREG(VCOP_CTRL_REG, hw->reg_vcop_ctrl_reg);
+ WRITE_VREG(AV_SCRATCH_H, hw->reg_signal_type);
+
+ if (READ_VREG(MREG_ERROR_COUNT) != 0 ||
+ READ_VREG(MREG_FATAL_ERROR) == 1)
+ debug_print(DECODE_ID(hw), PRINT_FLAG_RESTORE,
+ "err_cnt:%d fa_err:%d\n",
+ READ_VREG(MREG_ERROR_COUNT),
+ READ_VREG(MREG_FATAL_ERROR));
+
+ /* clear error count */
+ WRITE_VREG(MREG_ERROR_COUNT, 0);
+ /*Use MREG_FATAL_ERROR bit1, the ucode determine
+ whether to report the interruption of width and
+ height information,in order to be compatible
+ with the old version of ucode.
+ 1: Report the width and height information
+ 0: No Report
+ bit0:
+ 1: Use cma cc buffer for new driver
+ 0: use codec mm cc buffer for old driver
+ */
+ WRITE_VREG(MREG_FATAL_ERROR, 3);
+ /* clear wait buffer status */
+ WRITE_VREG(MREG_WAIT_BUFFER, 0);
+#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);
+
+ if (!hw->ctx_valid)
+ WRITE_VREG(AV_SCRATCH_J, hw->userdata_wp_ctx);
+
+ if (hw->chunk) {
+ /*frame based input*/
+ WRITE_VREG(MREG_INPUT,
+ (hw->chunk->offset & 7) | (1<<7) | (hw->ctx_valid<<6));
+ } else {
+ /*stream based input*/
+ WRITE_VREG(MREG_INPUT, (hw->ctx_valid<<6));
+ }
+ return 0;
+}
+
+static void vmpeg12_local_init(struct vdec_mpeg12_hw_s *hw)
+{
+ int i;
+ INIT_KFIFO(hw->display_q);
+ INIT_KFIFO(hw->newframe_q);
+
+ hw->vmpeg12_ratio = hw->vmpeg12_amstream_dec_info.ratio;
+
+ hw->vmpeg12_ratio64 = hw->vmpeg12_amstream_dec_info.ratio64;
+
+ for (i = 0; i < VF_POOL_SIZE; i++) {
+ const struct vframe_s *vf;
+ vf = &hw->vfpool[i];
+ hw->vfpool[i].index = DECODE_BUFFER_NUM_MAX;
+ kfifo_put(&hw->newframe_q, (const struct vframe_s *)vf);
+ }
+
+ for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) {
+ hw->vfbuf_use[i] = 0;
+ hw->ref_use[i] = 0;
+ }
+
+
+ if (hw->mm_blk_handle) {
+ 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 |
+ hw->tvp_flag);
+ hw->eos = 0;
+ hw->frame_width = hw->frame_height = 0;
+ hw->frame_dur = hw->frame_prog = 0;
+ hw->frame_force_skip_flag = 0;
+ hw->wait_buffer_counter = 0;
+ hw->first_i_frame_ready = 0;
+ hw->dec_control &= DEC_CONTROL_INTERNAL_MASK;
+ hw->refs[0] = -1;
+ hw->refs[1] = -1;
+ hw->disp_num = 0;
+ hw->dec_num = 0;
+ hw->put_num = 0;
+ hw->run_count = 0;
+ hw->not_run_ready = 0;
+ hw->input_empty = 0;
+ hw->peek_num = 0;
+ hw->get_num = 0;
+ hw->drop_frame_count = 0;
+ hw->buffer_not_ready = 0;
+ hw->start_process_time = 0;
+ hw->init_flag = 0;
+ hw->dec_again_cnt = 0;
+ hw->error_frame_skip_level = error_frame_skip_level;
+
+ if (dec_control)
+ hw->dec_control = dec_control;
+}
+
+static s32 vmpeg12_init(struct vdec_mpeg12_hw_s *hw)
+{
+ int size;
+ u32 fw_size = 16*0x1000;
+ struct firmware_s *fw;
+
+ vmpeg12_local_init(hw);
+
+ fw = vmalloc(sizeof(struct firmware_s) + fw_size);
+ if (IS_ERR_OR_NULL(fw))
+ return -ENOMEM;
+
+ pr_debug("get firmware ...\n");
+ size = get_firmware_data(VIDEO_DEC_MPEG12_MULTI, fw->data);
+ if (size < 0) {
+ pr_err("get firmware fail.\n");
+ vfree(fw);
+ return -1;
+ }
+
+ fw->len = size;
+ hw->fw = fw;
+
+ INIT_WORK(&hw->userdata_push_work, userdata_push_do_work);
+ INIT_WORK(&hw->work, vmpeg12_work);
+ INIT_WORK(&hw->timeout_work, vmpeg12_timeout_work);
+ INIT_WORK(&hw->notify_work, vmpeg12_notify_work);
+
+ if (NULL == hw->user_data_buffer) {
+ hw->user_data_buffer = kmalloc(USER_DATA_SIZE,
+ GFP_KERNEL);
+ if (!hw->user_data_buffer) {
+ pr_info("%s: Can not allocate user_data_buffer\n",
+ __func__);
+ return -1;
+ }
+ }
+
+ vmmpeg2_crate_userdata_manager(hw,
+ hw->user_data_buffer,
+ USER_DATA_SIZE);
+
+ //amvdec_enable();
+ init_timer(&hw->check_timer);
+ hw->check_timer.data = (unsigned long)hw;
+ hw->check_timer.function = check_timer_func;
+ hw->check_timer.expires = jiffies + CHECK_INTERVAL;
+
+ hw->stat |= STAT_TIMER_ARM;
+ hw->stat |= STAT_ISR_REG;
+
+ hw->buf_start = 0;
+ WRITE_VREG(DECODE_STOP_POS, udebug_flag);
+
+ return 0;
+}
+
+#ifdef VDEC_FCC_SUPPORT
+static void vmmpeg2_wakeup_fcc_poll(struct vdec_s *vdec)
+{
+ amstream_wakeup_fcc_poll(vdec);
+}
+#endif
+
+static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask)
+{
+ struct vdec_mpeg12_hw_s *hw =
+ (struct vdec_mpeg12_hw_s *)vdec->private;
+ if (hw->eos)
+ return 0;
+ if (hw->timeout_processing &&
+ (work_pending(&hw->work) || work_busy(&hw->work) ||
+ work_pending(&hw->timeout_work) || work_busy(&hw->timeout_work))) {
+ debug_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS,
+ "mpeg12 work pending,not ready for run.\n");
+ return 0;
+ }
+ 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;
+ }
+ }
+
+#ifdef AGAIN_HAS_THRESHOLD
+ 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);
+ debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW,
+ "%s buf level%x\n",
+ __func__, r);
+ return 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->v4l_codec_dpb_ready &&
+ v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) <
+ run_ready_min_buf_num)
+ if (!ctx->v4l_codec_dpb_ready)
+ return 0;
+ } else {
+ if (ctx->v4l_resolution_change)
+ return 0;
+ }
+ } else if (!ctx->v4l_codec_dpb_ready) {
+ if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) <
+ run_ready_min_buf_num)
+ return 0;
+ }
+ }
+
+ if (!is_enough_free_buffer(hw)) {
+ hw->buffer_not_ready++;
+ return 0;
+ }
+
+#ifdef VDEC_FCC_SUPPORT
+ if (!vdec_has_get_fcc_new_msg(vdec)) {
+ hw->buffer_not_ready++;
+ return 0;
+ }
+#endif
+
+ hw->not_run_ready = 0;
+ hw->buffer_not_ready = 0;
+ if (vdec->parallel_dec == 1)
+ return (unsigned long)(CORE_MASK_VDEC_1);
+ else
+ return (unsigned long)(CORE_MASK_VDEC_1 | CORE_MASK_HEVC);
+}
+
+static unsigned char get_data_check_sum
+ (struct vdec_mpeg12_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 int check_dirty_data(struct vdec_s *vdec)
+{
+ struct vdec_mpeg12_hw_s *hw =
+ (struct vdec_mpeg12_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) {
+ debug_print(DECODE_ID(hw), 0, "mpeg12 data skipped %x\n", level);
+ hw->dec_again_cnt = 0;
+ return 1;
+ }
+ return 0;
+}
+
+
+static void run(struct vdec_s *vdec, unsigned long mask,
+void (*callback)(struct vdec_s *, void *),
+ void *arg)
+{
+ struct vdec_mpeg12_hw_s *hw =
+ (struct vdec_mpeg12_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]*/
+ WRITE_VREG(DOS_SW_RESET0, 0xfffffff0);
+ WRITE_VREG(DOS_SW_RESET0, 0);
+ WRITE_VREG(POWER_CTL_VLD, save_reg);
+ hw->run_count++;
+ vdec_reset_core(vdec);
+ hw->vdec_cb_arg = arg;
+ hw->vdec_cb = callback;
+
+#ifdef AGAIN_HAS_THRESHOLD
+ if (vdec_stream_based(vdec)) {
+ hw->pre_parser_wr_ptr =
+ STBUF_READ(&vdec->vbuf, get_wp);
+ hw->next_again_flag = 0;
+ }
+#endif
+
+ size = vdec_prepare_input(vdec, &hw->chunk);
+ if (size < 0) {
+ hw->input_empty++;
+ hw->dec_result = DEC_RESULT_AGAIN;
+
+ debug_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL,
+ "vdec_prepare_input: Insufficient data\n");
+ vdec_schedule_work(&hw->work);
+ return;
+ }
+
+ hw->input_empty = 0;
+ if ((vdec_frame_based(vdec)) &&
+ (hw->chunk != NULL)) {
+ size = hw->chunk->size +
+ (hw->chunk->offset & (VDEC_FIFO_ALIGN - 1));
+ WRITE_VREG(VIFF_BIT_CNT, size * 8);
+ if (vdec->mvfrm)
+ vdec->mvfrm->frame_size = hw->chunk->size;
+ }
+ if (vdec_frame_based(vdec) && !vdec_secure(vdec)) {
+ /* HW needs padding (NAL start) for frame ending */
+ char* tail = (char *)hw->chunk->block->start_virt;
+
+ tail += hw->chunk->offset + hw->chunk->size;
+ tail[0] = 0;
+ tail[1] = 0;
+ tail[2] = 1;
+ tail[3] = 0;
+ codec_mm_dma_flush(tail, 4, DMA_TO_DEVICE);
+ }
+
+ if (vdec_frame_based(vdec) && debug_enable && !vdec_secure(vdec)) {
+ u8 *data = NULL;
+ if (hw->chunk)
+ debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW,
+ "run: chunk offset 0x%x, size %d\n",
+ hw->chunk->offset, hw->chunk->size);
+
+ if (!hw->chunk->block->is_mapped)
+ data = codec_mm_vmap(hw->chunk->block->start +
+ hw->chunk->offset, size);
+ else
+ data = ((u8 *)hw->chunk->block->start_virt) +
+ hw->chunk->offset;
+
+ if (debug_enable & PRINT_FLAG_VDEC_STATUS
+ ) {
+ debug_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 (debug_enable & PRINT_FRAMEBASE_DATA
+ ) {
+ int jj;
+ debug_print(DECODE_ID(hw), PRINT_FRAMEBASE_DATA,
+ "frame data:\n");
+ for (jj = 0; jj < size; jj++) {
+ if ((jj & 0xf) == 0)
+ pr_info("%06x:", jj);
+ pr_info("%02x ", data[jj]);
+ if (((jj + 1) & 0xf) == 0)
+ pr_info("\n");
+ }
+ pr_info("\n");
+ }
+
+ if (!hw->chunk->block->is_mapped)
+ codec_mm_unmap_phyaddr(data);
+ } else {
+ debug_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS,
+ "%s: %x %x %x %x %x size 0x%x, bitcnt %d\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, READ_VREG(VIFF_BIT_CNT));
+ }
+
+ if (vdec->mc_loaded) {
+ /*firmware have load before,
+ and not changes to another.
+ ignore reload.
+ */
+ } else {
+ ret = amvdec_vdec_loadmc_buf_ex(VFORMAT_MPEG12, "mmpeg12", 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_MPEG12;
+ }
+
+ if (vmpeg12_hw_ctx_restore(hw) < 0) {
+ hw->dec_result = DEC_RESULT_ERROR;
+ debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR,
+ "ammvdec_mpeg12: error HW context restore\n");
+ vdec_schedule_work(&hw->work);
+ return;
+ }
+ /*wmb();*/
+ hw->dec_result = DEC_RESULT_NONE;
+ hw->stat |= STAT_MC_LOAD;
+ vdec_enable_input(vdec);
+ hw->last_vld_level = 0;
+ start_process_time_set(hw);
+ if (vdec->mvfrm)
+ vdec->mvfrm->hw_decode_start = local_clock();
+ amvdec_start();
+ hw->stat |= STAT_VDEC_RUN;
+ hw->init_flag = 1;
+
+ mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL);
+}
+
+static void reset(struct vdec_s *vdec)
+{
+ pr_info("ammvdec_mpeg12: reset.\n");
+}
+
+static int vmpeg12_set_trickmode(struct vdec_s *vdec, unsigned long trickmode)
+{
+ struct vdec_mpeg12_hw_s *hw =
+ (struct vdec_mpeg12_hw_s *)vdec->private;
+ if (!hw)
+ return 0;
+
+ if (trickmode == TRICKMODE_I) {
+ hw->i_only = 0x3;
+ //trickmode_i = 1;
+ } else if (trickmode == TRICKMODE_NONE) {
+ hw->i_only = 0x0;
+ //trickmode_i = 0;
+ }
+ return 0;
+}
+
+static int ammvdec_mpeg12_probe(struct platform_device *pdev)
+{
+ struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
+ struct vdec_mpeg12_hw_s *hw = NULL;
+ int config_val = 0;
+
+ pr_info("ammvdec_mpeg12 probe start.\n");
+
+ if (pdata == NULL) {
+ pr_info("ammvdec_mpeg12 platform data undefined.\n");
+ return -EFAULT;
+ }
+
+ hw = vzalloc(sizeof(struct vdec_mpeg12_hw_s));
+ if (hw == NULL) {
+ pr_info("\nammvdec_mpeg12 decoder driver alloc failed\n");
+ return -ENOMEM;
+ }
+
+ /* the ctx from v4l2 driver. */
+ hw->v4l2_ctx = pdata->private;
+
+ pdata->private = hw;
+ pdata->dec_status = vmmpeg12_dec_status;
+ pdata->set_trickmode = vmpeg12_set_trickmode;
+ pdata->run_ready = run_ready;
+ pdata->run = run;
+ pdata->reset = reset;
+ pdata->irq_handler = vmpeg12_isr;
+ pdata->threaded_irq_handler = vmpeg12_isr_thread_fn;
+ pdata->dump_state = vmpeg2_dump_state;
+
+ pdata->user_data_read = vmmpeg2_user_data_read;
+ pdata->reset_userdata_fifo = vmmpeg2_reset_userdata_fifo;
+ pdata->wakeup_userdata_poll = vmmpeg2_wakeup_userdata_poll;
+
+#ifdef VDEC_FCC_SUPPORT
+ pdata->wakeup_fcc_poll = vmmpeg2_wakeup_fcc_poll;
+#endif
+ snprintf(hw->vdec_name, sizeof(hw->vdec_name),
+ "mpeg12-%d", pdev->id);
+ snprintf(hw->pts_name, sizeof(hw->pts_name),
+ "%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);
+
+ 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,
+ 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,
+ &vf_provider_ops, pdata);
+
+ if (pdata->parallel_dec == 1) {
+ int i;
+ for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++)
+ hw->canvas_spec[i] = 0xffffff;
+ }
+ platform_set_drvdata(pdev, pdata);
+
+ hw->dynamic_buf_num_margin = dynamic_buf_num_margin;
+ hw->canvas_mode = pdata->canvas_mode;
+ if (pdata->config_len) {
+ 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_canvas_mem_mode",
+ &config_val) == 0)
+ hw->canvas_mode = config_val;
+
+ if ((debug_enable & IGNORE_PARAM_FROM_CONFIG) == 0 &&
+ get_config_int(pdata->config,
+ "parm_v4l_buffer_margin",
+ &config_val) == 0)
+ hw->dynamic_buf_num_margin= config_val;
+ 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;
+ }
+
+ hw->buf_num = vmpeg12_get_buf_num(hw);
+ hw->platform_dev = pdev;
+
+ hw->tvp_flag = vdec_secure(pdata) ? CODEC_MM_FLAGS_TVP : 0;
+ if (pdata->sys_info)
+ hw->vmpeg12_amstream_dec_info = *pdata->sys_info;
+
+ debug_print(DECODE_ID(hw), 0,
+ "%s, sysinfo: %dx%d, tvp_flag = 0x%x\n",
+ __func__,
+ hw->vmpeg12_amstream_dec_info.width,
+ hw->vmpeg12_amstream_dec_info.height,
+ hw->tvp_flag);
+
+ if (vmpeg12_init(hw) < 0) {
+ pr_info("ammvdec_mpeg12 init failed.\n");
+ if (hw) {
+ vfree(hw);
+ hw = NULL;
+ }
+ pdata->dec_status = NULL;
+ return -ENODEV;
+ }
+ 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);
+ }
+ hw->last_frame_offset = 0xFFFFFFFF;
+#ifdef DUMP_USER_DATA
+ amvdec_mmpeg12_init_userdata_dump(hw);
+ reset_user_data_buf(hw);
+#endif
+
+ /*INIT_WORK(&userdata_push_work, userdata_push_do_work);*/
+ return 0;
+}
+
+static int ammvdec_mpeg12_remove(struct platform_device *pdev)
+
+{
+ struct vdec_mpeg12_hw_s *hw =
+ (struct vdec_mpeg12_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->userdata_push_work);
+ cancel_work_sync(&hw->notify_work);
+ cancel_work_sync(&hw->work);
+ cancel_work_sync(&hw->timeout_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);
+ }
+ }
+
+ if (hw->ccbuf_phyAddress_virt) {
+ dma_free_coherent(amports_get_dma_device(),hw->cc_buf_size,
+ hw->ccbuf_phyAddress_virt, hw->ccbuf_phyAddress);
+ hw->ccbuf_phyAddress_virt = NULL;
+ hw->ccbuf_phyAddress = 0;
+ }
+
+ if (hw->user_data_buffer != NULL) {
+ kfree(hw->user_data_buffer);
+ hw->user_data_buffer = NULL;
+ }
+ vmmpeg2_destroy_userdata_manager(hw);
+
+#ifdef DUMP_USER_DATA
+ amvdec_mmpeg12_uninit_userdata_dump(hw);
+#endif
+
+ if (hw->fw) {
+ vfree(hw->fw);
+ hw->fw = NULL;
+ }
+
+ vfree(hw);
+
+ pr_info("ammvdec_mpeg12 removed.\n");
+
+ return 0;
+}
+
+/****************************************/
+#ifdef CONFIG_PM
+static int mmpeg12_suspend(struct device *dev)
+{
+ amvdec_suspend(to_platform_device(dev), dev->power.power_state);
+ return 0;
+}
+
+static int mmpeg12_resume(struct device *dev)
+{
+ amvdec_resume(to_platform_device(dev));
+ return 0;
+}
+
+static const struct dev_pm_ops mmpeg12_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mmpeg12_suspend, mmpeg12_resume)
+};
+#endif
+
+static struct platform_driver ammvdec_mpeg12_driver = {
+ .probe = ammvdec_mpeg12_probe,
+ .remove = ammvdec_mpeg12_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &mmpeg12_pm_ops,
+#endif
+ }
+};
+
+static struct codec_profile_t ammvdec_mpeg12_profile = {
+ .name = "mmpeg12",
+ .profile = ""
+};
+
+static struct mconfig mmpeg12_configs[] = {
+ MC_PU32("radr", &radr),
+ MC_PU32("rval", &rval),
+ MC_PU32("dec_control", &dec_control),
+ MC_PU32("error_frame_skip_level", &error_frame_skip_level),
+ MC_PU32("decode_timeout_val", &decode_timeout_val),
+ MC_PU32("start_decode_buf_level", &start_decode_buf_level),
+ MC_PU32("pre_decode_buf_level", &pre_decode_buf_level),
+ MC_PU32("debug_enable", &debug_enable),
+ MC_PU32("udebug_flag", &udebug_flag),
+ MC_PU32("without_display_mode", &without_display_mode),
+ MC_PU32("dynamic_buf_num_margin", &dynamic_buf_num_margin),
+#ifdef AGAIN_HAS_THRESHOLD
+ MC_PU32("again_threshold", &again_threshold),
+#endif
+};
+static struct mconfig_node mmpeg12_node;
+
+static int __init ammvdec_mpeg12_driver_init_module(void)
+{
+ pr_info("ammvdec_mpeg12 module init\n");
+
+ if (platform_driver_register(&ammvdec_mpeg12_driver)) {
+ pr_info("failed to register ammvdec_mpeg12 driver\n");
+ return -ENODEV;
+ }
+ vcodec_profile_register(&ammvdec_mpeg12_profile);
+ INIT_REG_NODE_CONFIGS("media.decoder", &mmpeg12_node,
+ "mmpeg12", mmpeg12_configs, CONFIG_FOR_RW);
+ return 0;
+}
+
+static void __exit ammvdec_mpeg12_driver_remove_module(void)
+{
+ pr_info("ammvdec_mpeg12 module exit.\n");
+ platform_driver_unregister(&ammvdec_mpeg12_driver);
+}
+
+/****************************************/
+module_param(dec_control, uint, 0664);
+MODULE_PARM_DESC(dec_control, "\n ammvdec_mpeg12 decoder control\n");
+module_param(error_frame_skip_level, uint, 0664);
+MODULE_PARM_DESC(error_frame_skip_level,
+ "\n ammvdec_mpeg12 error_frame_skip_level\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(debug_enable, uint, 0664);
+MODULE_PARM_DESC(debug_enable,
+ "\n ammvdec_mpeg12 debug enable\n");
+module_param(pre_decode_buf_level, int, 0664);
+MODULE_PARM_DESC(pre_decode_buf_level,
+ "\n ammvdec_mpeg12 pre_decode_buf_level\n");
+
+module_param(start_decode_buf_level, int, 0664);
+MODULE_PARM_DESC(start_decode_buf_level,
+ "\n ammvdec_mpeg12 start_decode_buf_level\n");
+
+module_param(decode_timeout_val, uint, 0664);
+MODULE_PARM_DESC(decode_timeout_val, "\n ammvdec_mpeg12 decode_timeout_val\n");
+
+module_param(dynamic_buf_num_margin, uint, 0664);
+MODULE_PARM_DESC(dynamic_buf_num_margin, "\n ammvdec_mpeg12 dynamic_buf_num_margin\n");
+
+module_param_array(max_process_time, uint, &max_decode_instance_num, 0664);
+
+module_param(udebug_flag, uint, 0664);
+MODULE_PARM_DESC(udebug_flag, "\n ammvdec_mpeg12 udebug_flag\n");
+
+module_param(dirty_again_threshold, int, 0664);
+MODULE_PARM_DESC(dirty_again_threshold, "\n ammvdec_mpeg12 dirty_again_threshold\n");
+
+
+#ifdef AGAIN_HAS_THRESHOLD
+module_param(again_threshold, uint, 0664);
+MODULE_PARM_DESC(again_threshold, "\n again_threshold\n");
+#endif
+
+module_param(without_display_mode, uint, 0664);
+MODULE_PARM_DESC(without_display_mode, "\n ammvdec_mpeg12 without_display_mode\n");
+
+module_param(error_proc_policy, uint, 0664);
+MODULE_PARM_DESC(error_proc_policy, "\n ammvdec_mpeg12 error_proc_policy\n");
+
+module_init(ammvdec_mpeg12_driver_init_module);
+module_exit(ammvdec_mpeg12_driver_remove_module);
+
+MODULE_DESCRIPTION("AMLOGIC MULTI MPEG1/2 Video Decoder Driver");
+MODULE_LICENSE("GPL");
+
+
diff --git a/drivers/frame_provider/decoder/mpeg4/Makefile b/drivers/frame_provider/decoder/mpeg4/Makefile
new file mode 100644
index 0000000..917cc85
--- /dev/null
+++ b/drivers/frame_provider/decoder/mpeg4/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_MPEG4) += amvdec_mpeg4.o
+amvdec_mpeg4-objs += vmpeg4.o
+
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_MPEG4_MULTI) += amvdec_mmpeg4.o
+amvdec_mmpeg4-objs += vmpeg4_multi.o
diff --git a/drivers/frame_provider/decoder/mpeg4/vmpeg4.c b/drivers/frame_provider/decoder/mpeg4/vmpeg4.c
new file mode 100644
index 0000000..b13ca9c
--- /dev/null
+++ b/drivers/frame_provider/decoder/mpeg4/vmpeg4.c
@@ -0,0 +1,1325 @@
+/*
+ * drivers/amlogic/amports/vmpeg4.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/dma-mapping.h>
+#include <linux/amlogic/media/utils/amstream.h>
+#include <linux/amlogic/media/frame_sync/ptsserv.h>
+
+#include <linux/amlogic/media/vfm/vframe.h>
+#include <linux/amlogic/media/vfm/vframe_provider.h>
+#include <linux/amlogic/media/vfm/vframe_receiver.h>
+#include <linux/amlogic/media/canvas/canvas.h>
+
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "vmpeg4.h"
+#include <linux/amlogic/media/registers/register.h>
+#include "../../../stream_input/amports/amports_priv.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 <linux/amlogic/tee.h>
+#include "../../../common/chips/decoder_cpu_ver_info.h"
+
+
+/* #define CONFIG_AM_VDEC_MPEG4_LOG */
+#ifdef CONFIG_AM_VDEC_MPEG4_LOG
+#define AMLOG
+#define LOG_LEVEL_VAR amlog_level_vmpeg4
+#define LOG_MASK_VAR amlog_mask_vmpeg4
+#define LOG_LEVEL_ERROR 0
+#define LOG_LEVEL_INFO 1
+#define LOG_LEVEL_DESC "0:ERROR, 1:INFO"
+#define LOG_MASK_PTS 0x01
+#define LOG_MASK_DESC "0x01:DEBUG_PTS"
+#endif
+
+#include <linux/amlogic/media/utils/amlog.h>
+
+MODULE_AMLOG(LOG_LEVEL_ERROR, 0, LOG_LEVEL_DESC, LOG_DEFAULT_MASK_DESC);
+
+#include "../utils/amvdec.h"
+#include "../utils/vdec.h"
+#include "../utils/firmware.h"
+
+#define DRIVER_NAME "amvdec_mpeg4"
+#define MODULE_NAME "amvdec_mpeg4"
+
+#define DEBUG_PTS
+
+/* /#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+#define NV21
+/* /#endif */
+
+#define I_PICTURE 0
+#define P_PICTURE 1
+#define B_PICTURE 2
+
+#define ORI_BUFFER_START_ADDR 0x01000000
+
+#define INTERLACE_FLAG 0x80
+#define TOP_FIELD_FIRST_FLAG 0x40
+
+/* protocol registers */
+#define MP4_PIC_RATIO AV_SCRATCH_5
+#define MP4_RATE AV_SCRATCH_3
+#define MP4_ERR_COUNT AV_SCRATCH_6
+#define MP4_PIC_WH AV_SCRATCH_7
+#define MREG_BUFFERIN AV_SCRATCH_8
+#define MREG_BUFFEROUT AV_SCRATCH_9
+#define MP4_NOT_CODED_CNT AV_SCRATCH_A
+#define MP4_VOP_TIME_INC AV_SCRATCH_B
+#define MP4_OFFSET_REG AV_SCRATCH_C
+#define MP4_SYS_RATE AV_SCRATCH_E
+#define MEM_OFFSET_REG AV_SCRATCH_F
+
+#define PARC_FORBIDDEN 0
+#define PARC_SQUARE 1
+#define PARC_CIF 2
+#define PARC_10_11 3
+#define PARC_16_11 4
+#define PARC_40_33 5
+#define PARC_RESERVED 6
+/* values between 6 and 14 are reserved */
+#define PARC_EXTENDED 15
+
+#define VF_POOL_SIZE 32
+#define DECODE_BUFFER_NUM_MAX 8
+#define PUT_INTERVAL (HZ/100)
+#define WORKSPACE_SIZE (1 * SZ_1M)
+#define MAX_BMMU_BUFFER_NUM (DECODE_BUFFER_NUM_MAX + 1)
+#define DCAC_BUFF_START_IP 0x02b00000
+
+
+#define RATE_DETECT_COUNT 5
+#define DURATION_UNIT 96000
+#define PTS_UNIT 90000
+
+#define DUR2PTS(x) ((x) - ((x) >> 4))
+
+#define MAX_MPEG4_SUPPORT_SIZE (1920*1088)
+
+static struct vframe_s *vmpeg_vf_peek(void *);
+static struct vframe_s *vmpeg_vf_get(void *);
+static void vmpeg_vf_put(struct vframe_s *, void *);
+static int vmpeg_vf_states(struct vframe_states *states, void *);
+static int vmpeg_event_cb(int type, void *data, void *private_data);
+
+static int vmpeg4_prot_init(void);
+static void vmpeg4_local_init(void);
+
+static const char vmpeg4_dec_id[] = "vmpeg4-dev";
+
+#define PROVIDER_NAME "decoder.mpeg4"
+
+struct vdec_s *vdec = NULL;
+
+/*
+ *int query_video_status(int type, int *value);
+ */
+static const struct vframe_operations_s vmpeg_vf_provider = {
+ .peek = vmpeg_vf_peek,
+ .get = vmpeg_vf_get,
+ .put = vmpeg_vf_put,
+ .event_cb = vmpeg_event_cb,
+ .vf_states = vmpeg_vf_states,
+};
+static void *mm_blk_handle;
+static struct vframe_provider_s vmpeg_vf_prov;
+
+static DECLARE_KFIFO(newframe_q, struct vframe_s *, VF_POOL_SIZE);
+static DECLARE_KFIFO(display_q, struct vframe_s *, VF_POOL_SIZE);
+static DECLARE_KFIFO(recycle_q, struct vframe_s *, VF_POOL_SIZE);
+
+static struct vframe_s vfpool[VF_POOL_SIZE];
+static s32 vfbuf_use[DECODE_BUFFER_NUM_MAX];
+static u32 frame_width, frame_height, frame_dur, frame_prog;
+static u32 saved_resolution;
+static struct timer_list recycle_timer;
+static u32 stat;
+static u32 buf_size = 32 * 1024 * 1024;
+static u32 buf_offset;
+static u32 vmpeg4_ratio;
+static u64 vmpeg4_ratio64;
+static u32 rate_detect;
+static u32 vmpeg4_rotation;
+static u32 fr_hint_status;
+
+static u32 total_frame;
+static u32 last_vop_time_inc, last_duration;
+static u32 last_anch_pts, vop_time_inc_since_last_anch,
+ frame_num_since_last_anch;
+static u64 last_anch_pts_us64;
+static struct vdec_info *gvs;
+
+#ifdef CONFIG_AM_VDEC_MPEG4_LOG
+u32 pts_hit, pts_missed, pts_i_hit, pts_i_missed;
+#endif
+
+static struct work_struct reset_work;
+static struct work_struct notify_work;
+static struct work_struct set_clk_work;
+static bool is_reset;
+static bool first_i_frame_ready;
+
+static DEFINE_SPINLOCK(lock);
+
+static struct dec_sysinfo vmpeg4_amstream_dec_info;
+
+static unsigned char aspect_ratio_table[16] = {
+ PARC_FORBIDDEN,
+ PARC_SQUARE,
+ PARC_CIF,
+ PARC_10_11,
+ PARC_16_11,
+ PARC_40_33,
+ PARC_RESERVED, PARC_RESERVED, PARC_RESERVED, PARC_RESERVED,
+ PARC_RESERVED, PARC_RESERVED, PARC_RESERVED, PARC_RESERVED,
+ PARC_RESERVED, PARC_EXTENDED
+};
+
+static inline u32 index2canvas(u32 index)
+{
+ const u32 canvas_tab[8] = {
+#ifdef NV21
+ 0x010100, 0x030302, 0x050504, 0x070706,
+ 0x090908, 0x0b0b0a, 0x0d0d0c, 0x0f0f0e
+#else
+ 0x020100, 0x050403, 0x080706, 0x0b0a09,
+ 0x0e0d0c, 0x11100f, 0x141312, 0x171615
+#endif
+ };
+
+ return canvas_tab[index];
+}
+
+static void set_aspect_ratio(struct vframe_s *vf, unsigned int pixel_ratio)
+{
+ int ar = 0;
+ unsigned int num = 0;
+ unsigned int den = 0;
+
+ if (vmpeg4_ratio64 != 0) {
+ num = vmpeg4_ratio64 >> 32;
+ den = vmpeg4_ratio64 & 0xffffffff;
+ } else {
+ num = vmpeg4_ratio >> 16;
+ den = vmpeg4_ratio & 0xffff;
+
+ }
+ if ((num == 0) || (den == 0)) {
+ num = 1;
+ den = 1;
+ }
+
+ if (vmpeg4_ratio == 0) {
+ vf->ratio_control |= (0x90 << DISP_RATIO_ASPECT_RATIO_BIT);
+ /* always stretch to 16:9 */
+ } else if (pixel_ratio > 0x0f) {
+ num = (pixel_ratio >> 8) *
+ vmpeg4_amstream_dec_info.width * num;
+ ar = div_u64((pixel_ratio & 0xff) *
+ vmpeg4_amstream_dec_info.height * den * 0x100ULL +
+ (num >> 1), num);
+ } else {
+ switch (aspect_ratio_table[pixel_ratio]) {
+ case 0:
+ num = vmpeg4_amstream_dec_info.width * num;
+ ar = (vmpeg4_amstream_dec_info.height * den * 0x100 +
+ (num >> 1)) / num;
+ break;
+ case 1:
+ num = vf->width * num;
+ ar = (vf->height * den * 0x100 + (num >> 1)) / num;
+ break;
+ case 2:
+ num = (vf->width * 12) * num;
+ ar = (vf->height * den * 0x100 * 11 +
+ ((num) >> 1)) / num;
+ break;
+ case 3:
+ num = (vf->width * 10) * num;
+ ar = (vf->height * den * 0x100 * 11 + (num >> 1)) /
+ num;
+ break;
+ case 4:
+ num = (vf->width * 16) * num;
+ ar = (vf->height * den * 0x100 * 11 + (num >> 1)) /
+ num;
+ break;
+ case 5:
+ num = (vf->width * 40) * num;
+ ar = (vf->height * den * 0x100 * 33 + (num >> 1)) /
+ num;
+ break;
+ default:
+ num = vf->width * num;
+ ar = (vf->height * den * 0x100 + (num >> 1)) / num;
+ break;
+ }
+ }
+
+ ar = min(ar, DISP_RATIO_ASPECT_RATIO_MAX);
+
+ vf->ratio_control = (ar << DISP_RATIO_ASPECT_RATIO_BIT);
+}
+
+static irqreturn_t vmpeg4_isr(int irq, void *dev_id)
+{
+ u32 reg;
+ struct vframe_s *vf = NULL;
+ u32 picture_type;
+ u32 buffer_index;
+ u32 pts, pts_valid = 0, offset = 0;
+ u64 pts_us64 = 0;
+ u32 rate, vop_time_inc, repeat_cnt, duration = 3200;
+ u32 frame_size;
+
+ reg = READ_VREG(MREG_BUFFEROUT);
+
+ if (reg) {
+ buffer_index = reg & 0x7;
+ picture_type = (reg >> 3) & 7;
+ rate = READ_VREG(MP4_RATE);
+ repeat_cnt = READ_VREG(MP4_NOT_CODED_CNT);
+ vop_time_inc = READ_VREG(MP4_VOP_TIME_INC);
+
+ if (buffer_index >= DECODE_BUFFER_NUM_MAX) {
+ pr_err("fatal error, invalid buffer index.");
+ return IRQ_HANDLED;
+ }
+
+ if (vmpeg4_amstream_dec_info.width == 0) {
+ vmpeg4_amstream_dec_info.width =
+ READ_VREG(MP4_PIC_WH) >> 16;
+ }
+#if 0
+ else {
+ pr_info("info width = %d, ucode width = %d\n",
+ vmpeg4_amstream_dec_info.width,
+ READ_VREG(MP4_PIC_WH) >> 16);
+ }
+#endif
+
+ if (vmpeg4_amstream_dec_info.height == 0) {
+ vmpeg4_amstream_dec_info.height =
+ READ_VREG(MP4_PIC_WH) & 0xffff;
+ }
+#if 0
+ else {
+ pr_info("info height = %d, ucode height = %d\n",
+ vmpeg4_amstream_dec_info.height,
+ READ_VREG(MP4_PIC_WH) & 0xffff);
+ }
+#endif
+ if (vmpeg4_amstream_dec_info.rate == 0
+ || vmpeg4_amstream_dec_info.rate > 96000) {
+ /* if ((rate >> 16) != 0) { */
+ if ((rate & 0xffff) != 0 && (rate >> 16) != 0) {
+ vmpeg4_amstream_dec_info.rate =
+ (rate >> 16) * DURATION_UNIT /
+ (rate & 0xffff);
+ duration = vmpeg4_amstream_dec_info.rate;
+ if (fr_hint_status == VDEC_NEED_HINT) {
+ schedule_work(¬ify_work);
+ fr_hint_status = VDEC_HINTED;
+ }
+ } else if (rate_detect < RATE_DETECT_COUNT) {
+ if (vop_time_inc < last_vop_time_inc) {
+ duration =
+ vop_time_inc + rate -
+ last_vop_time_inc;
+ } else {
+ duration =
+ vop_time_inc - last_vop_time_inc;
+ }
+
+ if (duration == last_duration) {
+ rate_detect++;
+ if (rate_detect >= RATE_DETECT_COUNT) {
+ vmpeg4_amstream_dec_info.rate =
+ duration * DURATION_UNIT /
+ rate;
+ duration =
+ vmpeg4_amstream_dec_info.rate;
+ }
+ } else
+ rate_detect = 0;
+
+ last_duration = duration;
+ }
+ } else {
+ duration = vmpeg4_amstream_dec_info.rate;
+#if 0
+ pr_info("info rate = %d, ucode rate = 0x%x:0x%x\n",
+ vmpeg4_amstream_dec_info.rate,
+ READ_VREG(MP4_RATE), vop_time_inc);
+#endif
+ }
+
+ if ((picture_type == I_PICTURE) ||
+ (picture_type == P_PICTURE)) {
+ offset = READ_VREG(MP4_OFFSET_REG);
+ /*2500-->3000,because some mpeg4
+ *video may checkout failed;
+ *may have av sync problem.can changed small later.
+ *263 may need small?
+ */
+ if (pts_lookup_offset_us64
+ (PTS_TYPE_VIDEO, offset, &pts,
+ &frame_size, 3000,
+ &pts_us64) == 0) {
+ pts_valid = 1;
+ last_anch_pts = pts;
+ last_anch_pts_us64 = pts_us64;
+#ifdef CONFIG_AM_VDEC_MPEG4_LOG
+ pts_hit++;
+#endif
+ } else {
+#ifdef CONFIG_AM_VDEC_MPEG4_LOG
+ pts_missed++;
+#endif
+ }
+#ifdef CONFIG_AM_VDEC_MPEG4_LOG
+ amlog_mask(LOG_MASK_PTS,
+ "I offset 0x%x, pts_valid %d pts=0x%x\n",
+ offset, pts_valid, pts);
+#endif
+ }
+
+ if (pts_valid) {
+ last_anch_pts = pts;
+ last_anch_pts_us64 = pts_us64;
+ frame_num_since_last_anch = 0;
+ vop_time_inc_since_last_anch = 0;
+ } else {
+ pts = last_anch_pts;
+ pts_us64 = last_anch_pts_us64;
+
+ if ((rate != 0) && ((rate >> 16) == 0)
+ && vmpeg4_amstream_dec_info.rate == 0) {
+ /* variable PTS rate */
+ /*bug on variable pts calc,
+ *do as dixed vop first if we
+ *have rate setting before.
+ */
+ if (vop_time_inc > last_vop_time_inc) {
+ vop_time_inc_since_last_anch +=
+ vop_time_inc - last_vop_time_inc;
+ } else {
+ vop_time_inc_since_last_anch +=
+ vop_time_inc + rate -
+ last_vop_time_inc;
+ }
+
+ pts += vop_time_inc_since_last_anch *
+ PTS_UNIT / rate;
+ pts_us64 += (u64)(vop_time_inc_since_last_anch *
+ PTS_UNIT / rate) * 100 / 9;
+
+ if (vop_time_inc_since_last_anch > (1 << 14)) {
+ /* avoid overflow */
+ last_anch_pts = pts;
+ last_anch_pts_us64 = pts_us64;
+ vop_time_inc_since_last_anch = 0;
+ }
+ } else {
+ /* fixed VOP rate */
+ frame_num_since_last_anch++;
+ pts += DUR2PTS(frame_num_since_last_anch *
+ vmpeg4_amstream_dec_info.rate);
+ pts_us64 += DUR2PTS(frame_num_since_last_anch *
+ vmpeg4_amstream_dec_info.rate) *
+ 100 / 9;
+
+ if (frame_num_since_last_anch > (1 << 15)) {
+ /* avoid overflow */
+ last_anch_pts = pts;
+ last_anch_pts_us64 = pts_us64;
+ frame_num_since_last_anch = 0;
+ }
+ }
+ }
+
+ if ( (first_i_frame_ready == 0) &&
+ (picture_type == I_PICTURE)) {
+ first_i_frame_ready = 1;
+ }
+
+ if (reg & INTERLACE_FLAG) { /* interlace */
+ if (kfifo_get(&newframe_q, &vf) == 0) {
+ printk
+ ("fatal error, no available buffer slot.");
+ return IRQ_HANDLED;
+ }
+ vf->signal_type = 0;
+ vf->index = buffer_index;
+ vf->width = vmpeg4_amstream_dec_info.width;
+ vf->height = vmpeg4_amstream_dec_info.height;
+ vf->bufWidth = 1920;
+ vf->flag = 0;
+ vf->orientation = vmpeg4_rotation;
+ vf->pts = pts;
+ vf->pts_us64 = pts_us64;
+ vf->duration = duration >> 1;
+ vf->duration_pulldown = 0;
+ 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;
+
+ set_aspect_ratio(vf, READ_VREG(MP4_PIC_RATIO));
+
+ vfbuf_use[buffer_index]++;
+
+ if (first_i_frame_ready == 0) {
+ kfifo_put(&recycle_q, (const struct vframe_s *)vf);
+ } else {
+ vf->mem_handle =
+ decoder_bmmu_box_get_mem_handle(
+ 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);
+
+ }
+
+ if (kfifo_get(&newframe_q, &vf) == 0) {
+ printk(
+ "fatal error, no available buffer slot.");
+ return IRQ_HANDLED;
+ }
+ vf->signal_type = 0;
+ vf->index = buffer_index;
+ vf->width = vmpeg4_amstream_dec_info.width;
+ vf->height = vmpeg4_amstream_dec_info.height;
+ vf->bufWidth = 1920;
+ vf->flag = 0;
+ vf->orientation = vmpeg4_rotation;
+
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+ vf->duration = duration >> 1;
+
+ vf->duration_pulldown = 0;
+ 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;
+
+ set_aspect_ratio(vf, READ_VREG(MP4_PIC_RATIO));
+
+ amlog_mask(LOG_MASK_PTS,
+ "[%s:%d] [inte] dur=0x%x rate=%d picture_type=%d\n",
+ __func__, __LINE__, vf->duration,
+ vmpeg4_amstream_dec_info.rate, picture_type);
+
+ vfbuf_use[buffer_index]++;
+
+ if (first_i_frame_ready == 0) {
+ kfifo_put(&recycle_q, (const struct vframe_s *)vf);
+ } else {
+ vf->mem_handle =
+ decoder_bmmu_box_get_mem_handle(
+ mm_blk_handle,
+ buffer_index);
+
+ kfifo_put(&display_q, (const struct vframe_s *)vf);
+ ATRACE_COUNTER(MODULE_NAME, vf->pts);
+
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY,
+ NULL);
+ }
+
+
+ } else { /* progressive */
+ if (kfifo_get(&newframe_q, &vf) == 0) {
+ printk
+ ("fatal error, no available buffer slot.");
+ return IRQ_HANDLED;
+ }
+ vf->signal_type = 0;
+ vf->index = buffer_index;
+ vf->width = vmpeg4_amstream_dec_info.width;
+ vf->height = vmpeg4_amstream_dec_info.height;
+ vf->bufWidth = 1920;
+ vf->flag = 0;
+ vf->orientation = vmpeg4_rotation;
+ vf->pts = pts;
+ vf->pts_us64 = pts_us64;
+ vf->duration = duration;
+ vf->duration_pulldown = repeat_cnt * duration;
+#ifdef NV21
+ vf->type =
+ VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD |
+ VIDTYPE_VIU_NV21;
+#else
+ vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD;
+#endif
+ vf->canvas0Addr = vf->canvas1Addr =
+ index2canvas(buffer_index);
+ vf->type_original = vf->type;
+
+ set_aspect_ratio(vf, READ_VREG(MP4_PIC_RATIO));
+
+ amlog_mask(LOG_MASK_PTS,
+ "[%s:%d] [prog] dur=0x%x rate=%d picture_type=%d\n",
+ __func__, __LINE__, vf->duration,
+ vmpeg4_amstream_dec_info.rate, picture_type);
+
+
+ vfbuf_use[buffer_index]++;
+
+ if (first_i_frame_ready == 0) {
+ kfifo_put(&recycle_q, (const struct vframe_s *)vf);
+ } else {
+ vf->mem_handle =
+ 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 += repeat_cnt + 1;
+
+ WRITE_VREG(MREG_BUFFEROUT, 0);
+
+ last_vop_time_inc = vop_time_inc;
+
+ /*count info*/
+ gvs->frame_dur = duration;
+ vdec_count_info(gvs, 0, offset);
+ }
+
+ WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
+
+ return IRQ_HANDLED;
+}
+
+static struct vframe_s *vmpeg_vf_peek(void *op_arg)
+{
+ struct vframe_s *vf;
+
+ if (kfifo_peek(&display_q, &vf))
+ return vf;
+
+ return NULL;
+}
+
+static struct vframe_s *vmpeg_vf_get(void *op_arg)
+{
+ struct vframe_s *vf;
+
+ if (kfifo_get(&display_q, &vf))
+ return vf;
+
+ return NULL;
+}
+
+static void vmpeg_vf_put(struct vframe_s *vf, void *op_arg)
+{
+ kfifo_put(&recycle_q, (const struct vframe_s *)vf);
+}
+
+static int vmpeg_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(&vmpeg_vf_prov);
+#endif
+ spin_lock_irqsave(&lock, flags);
+ vmpeg4_local_init();
+ vmpeg4_prot_init();
+ spin_unlock_irqrestore(&lock, flags);
+#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vf_reg_provider(&vmpeg_vf_prov);
+#endif
+ amvdec_start();
+ }
+
+ 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;
+}
+
+static int vmpeg_vf_states(struct vframe_states *states, void *op_arg)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ states->vf_pool_size = VF_POOL_SIZE;
+ states->buf_free_num = kfifo_len(&newframe_q);
+ states->buf_avail_num = kfifo_len(&display_q);
+ states->buf_recycle_num = kfifo_len(&recycle_q);
+
+ spin_unlock_irqrestore(&lock, flags);
+
+ return 0;
+}
+
+static void vmpeg4_notify_work(struct work_struct *work)
+{
+ pr_info("frame duration changed %d\n", vmpeg4_amstream_dec_info.rate);
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)
+ ((unsigned long)
+ vmpeg4_amstream_dec_info.rate));
+ return;
+}
+
+static void reset_do_work(struct work_struct *work)
+{
+ unsigned long flags;
+
+ amvdec_stop();
+#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vf_light_unreg_provider(&vmpeg_vf_prov);
+#endif
+ spin_lock_irqsave(&lock, flags);
+ vmpeg4_local_init();
+ vmpeg4_prot_init();
+ spin_unlock_irqrestore(&lock, flags);
+#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vf_reg_provider(&vmpeg_vf_prov);
+#endif
+ amvdec_start();
+}
+
+static void vmpeg4_set_clk(struct work_struct *work)
+{
+ int fps = 96000 / frame_dur;
+
+ saved_resolution = frame_width * frame_height * fps;
+ vdec_source_changed(VFORMAT_MPEG4,
+ frame_width, frame_height, fps);
+}
+
+static void vmpeg_put_timer_func(unsigned long arg)
+{
+ struct timer_list *timer = (struct timer_list *)arg;
+
+ while (!kfifo_is_empty(&recycle_q) && (READ_VREG(MREG_BUFFERIN) == 0)) {
+ struct vframe_s *vf;
+
+ if (kfifo_get(&recycle_q, &vf)) {
+ if ((vf->index < DECODE_BUFFER_NUM_MAX)
+ && (--vfbuf_use[vf->index] == 0)) {
+ WRITE_VREG(MREG_BUFFERIN, ~(1 << vf->index));
+ vf->index = DECODE_BUFFER_NUM_MAX;
+ }
+ 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);
+
+ if (READ_VREG(AV_SCRATCH_L)) {
+ pr_info("mpeg4 fatal error happened,need reset !!\n");
+ schedule_work(&reset_work);
+ }
+
+
+ timer->expires = jiffies + PUT_INTERVAL;
+
+ add_timer(timer);
+}
+
+int vmpeg4_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus)
+{
+ if (!(stat & STAT_VDEC_RUN))
+ return -1;
+
+ vstatus->frame_width = vmpeg4_amstream_dec_info.width;
+ vstatus->frame_height = vmpeg4_amstream_dec_info.height;
+ if (0 != vmpeg4_amstream_dec_info.rate)
+ vstatus->frame_rate =
+ DURATION_UNIT / vmpeg4_amstream_dec_info.rate;
+ else
+ vstatus->frame_rate = -1;
+ vstatus->error_count = READ_VREG(MP4_ERR_COUNT);
+ 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 vmpeg4_set_isreset(struct vdec_s *vdec, int isreset)
+{
+ is_reset = isreset;
+ return 0;
+}
+
+static int vmpeg4_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 vmpeg4_canvas_init(void)
+{
+ int i, ret;
+ u32 canvas_width, canvas_height;
+ unsigned long buf_start;
+ u32 alloc_size, decbuf_size, decbuf_y_size, decbuf_uv_size;
+
+ if (buf_size <= 0x00400000) {
+ /* SD only */
+ canvas_width = 768;
+ canvas_height = 576;
+ decbuf_y_size = 0x80000;
+ decbuf_uv_size = 0x20000;
+ decbuf_size = 0x100000;
+ } else {
+ int w = vmpeg4_amstream_dec_info.width;
+ int h = vmpeg4_amstream_dec_info.height;
+ int align_w, align_h;
+ int max, min;
+
+ align_w = ALIGN(w, 64);
+ align_h = ALIGN(h, 64);
+ if (align_w > align_h) {
+ max = align_w;
+ min = align_h;
+ } else {
+ max = align_h;
+ min = align_w;
+ }
+ /* HD & SD */
+ if ((max > 1920 || min > 1088) &&
+ ALIGN(align_w * align_h * 3/2, SZ_64K) * 9 <=
+ buf_size) {
+ canvas_width = align_w;
+ canvas_height = align_h;
+ decbuf_y_size = ALIGN(align_w * align_h, SZ_64K);
+ decbuf_uv_size = ALIGN(align_w * align_h/4, SZ_64K);
+ decbuf_size = ALIGN(align_w * align_h * 3/2, SZ_64K);
+ } else { /*1080p*/
+ if (h > w) {
+ canvas_width = 1088;
+ canvas_height = 1920;
+ } else {
+ canvas_width = 1920;
+ canvas_height = 1088;
+ }
+ decbuf_y_size = 0x200000;
+ decbuf_uv_size = 0x80000;
+ decbuf_size = 0x300000;
+ }
+ }
+
+ for (i = 0; i < MAX_BMMU_BUFFER_NUM; i++) {
+ /* workspace mem */
+ if (i == (MAX_BMMU_BUFFER_NUM - 1))
+ alloc_size = WORKSPACE_SIZE;
+ else
+ alloc_size = decbuf_size;
+
+ ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle, i,
+ alloc_size, DRIVER_NAME, &buf_start);
+ if (ret < 0)
+ return ret;
+ if (i == (MAX_BMMU_BUFFER_NUM - 1)) {
+ buf_offset = buf_start - DCAC_BUFF_START_IP;
+ continue;
+ }
+
+
+#ifdef NV21
+ canvas_config(2 * i + 0,
+ buf_start,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+ canvas_config(2 * i + 1,
+ buf_start +
+ decbuf_y_size, canvas_width,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+#else
+ canvas_config(3 * i + 0,
+ buf_start,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+ canvas_config(3 * i + 1,
+ buf_start +
+ decbuf_y_size, canvas_width / 2,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+ canvas_config(3 * i + 2,
+ buf_start +
+ decbuf_y_size + decbuf_uv_size,
+ canvas_width / 2, canvas_height / 2,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+#endif
+
+ }
+ return 0;
+}
+
+static int vmpeg4_prot_init(void)
+{
+ int r;
+#if 1 /* /MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+ WRITE_VREG(DOS_SW_RESET0, (1 << 7) | (1 << 6));
+ WRITE_VREG(DOS_SW_RESET0, 0);
+#else
+ WRITE_RESET_REG(RESET0_REGISTER, RESET_IQIDCT | RESET_MC);
+#endif
+
+ r = vmpeg4_canvas_init();
+
+ /* index v << 16 | u << 8 | y */
+#ifdef NV21
+ WRITE_VREG(AV_SCRATCH_0, 0x010100);
+ WRITE_VREG(AV_SCRATCH_1, 0x030302);
+ WRITE_VREG(AV_SCRATCH_2, 0x050504);
+ WRITE_VREG(AV_SCRATCH_3, 0x070706);
+ WRITE_VREG(AV_SCRATCH_G, 0x090908);
+ WRITE_VREG(AV_SCRATCH_H, 0x0b0b0a);
+ WRITE_VREG(AV_SCRATCH_I, 0x0d0d0c);
+ WRITE_VREG(AV_SCRATCH_J, 0x0f0f0e);
+#else
+ WRITE_VREG(AV_SCRATCH_0, 0x020100);
+ WRITE_VREG(AV_SCRATCH_1, 0x050403);
+ WRITE_VREG(AV_SCRATCH_2, 0x080706);
+ WRITE_VREG(AV_SCRATCH_3, 0x0b0a09);
+ WRITE_VREG(AV_SCRATCH_G, 0x0e0d0c);
+ WRITE_VREG(AV_SCRATCH_H, 0x11100f);
+ WRITE_VREG(AV_SCRATCH_I, 0x141312);
+ WRITE_VREG(AV_SCRATCH_J, 0x171615);
+#endif
+ WRITE_VREG(AV_SCRATCH_L, 0);/*clearfatal error flag*/
+
+ /* notify ucode the buffer offset */
+ WRITE_VREG(AV_SCRATCH_F, buf_offset);
+
+ /* disable PSCALE for hardware sharing */
+ WRITE_VREG(PSCALE_CTRL, 0);
+
+ /* clear repeat count */
+ WRITE_VREG(MP4_NOT_CODED_CNT, 0);
+
+ WRITE_VREG(MREG_BUFFERIN, 0);
+ WRITE_VREG(MREG_BUFFEROUT, 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
+
+#if 1/* /MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
+ pr_debug("mpeg4 meson8 prot init\n");
+ WRITE_VREG(MDEC_PIC_DC_THRESH, 0x404038aa);
+#endif
+
+ WRITE_VREG(MP4_PIC_WH, (vmpeg4_amstream_dec_info.
+ width << 16) | vmpeg4_amstream_dec_info.height);
+ WRITE_VREG(MP4_SYS_RATE, vmpeg4_amstream_dec_info.rate);
+ return r;
+}
+
+static void vmpeg4_local_init(void)
+{
+ int i;
+
+ vmpeg4_ratio = vmpeg4_amstream_dec_info.ratio;
+
+ vmpeg4_ratio64 = vmpeg4_amstream_dec_info.ratio64;
+
+ vmpeg4_rotation =
+ (((unsigned long) vmpeg4_amstream_dec_info.param)
+ >> 16) & 0xffff;
+
+ frame_width = frame_height = frame_dur = frame_prog = 0;
+
+ total_frame = 0;
+ saved_resolution = 0;
+ last_anch_pts = 0;
+
+ last_anch_pts_us64 = 0;
+
+ last_vop_time_inc = last_duration = 0;
+
+ vop_time_inc_since_last_anch = 0;
+
+ frame_num_since_last_anch = 0;
+
+ first_i_frame_ready = 0;
+#ifdef CONFIG_AM_VDEC_MPEG4_LOG
+ pts_hit = pts_missed = pts_i_hit = pts_i_missed = 0;
+#endif
+
+ for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++)
+ vfbuf_use[i] = 0;
+
+ INIT_KFIFO(display_q);
+ INIT_KFIFO(recycle_q);
+ INIT_KFIFO(newframe_q);
+
+ for (i = 0; i < VF_POOL_SIZE; i++) {
+ const struct vframe_s *vf = &vfpool[i];
+
+ vfpool[i].index = DECODE_BUFFER_NUM_MAX;
+ kfifo_put(&newframe_q, (const struct vframe_s *)vf);
+ }
+ if (mm_blk_handle) {
+ decoder_bmmu_box_free(mm_blk_handle);
+ mm_blk_handle = NULL;
+ }
+
+ mm_blk_handle = decoder_bmmu_box_alloc_box(
+ DRIVER_NAME,
+ 0,
+ MAX_BMMU_BUFFER_NUM,
+ 4 + PAGE_SHIFT,
+ CODEC_MM_FLAGS_CMA_CLEAR |
+ CODEC_MM_FLAGS_FOR_VDECODER);
+}
+
+static s32 vmpeg4_init(void)
+{
+ int trickmode_fffb = 0;
+ int size = -1, ret = -1;
+ char fw_name[32] = {0};
+ char *buf = vmalloc(0x1000 * 16);
+
+ if (IS_ERR_OR_NULL(buf))
+ return -ENOMEM;
+ amlog_level(LOG_LEVEL_INFO, "vmpeg4_init\n");
+
+ if (vmpeg4_amstream_dec_info.format ==
+ VIDEO_DEC_FORMAT_MPEG4_5) {
+ size = get_firmware_data(VIDEO_DEC_MPEG4_5, buf);
+ strncpy(fw_name, "vmpeg4_mc_5", sizeof(fw_name));
+
+ amlog_level(LOG_LEVEL_INFO, "load VIDEO_DEC_FORMAT_MPEG4_5\n");
+ } else if (vmpeg4_amstream_dec_info.format == VIDEO_DEC_FORMAT_H263) {
+ size = get_firmware_data(VIDEO_DEC_H263, buf);
+ strncpy(fw_name, "h263_mc", sizeof(fw_name));
+
+ pr_info("load VIDEO_DEC_FORMAT_H263\n");
+ } else
+ pr_err("unsupport mpeg4 sub format %d\n",
+ vmpeg4_amstream_dec_info.format);
+
+ if (size < 0) {
+ pr_err("get firmware fail.");
+ vfree(buf);
+ return -1;
+ }
+
+ ret = amvdec_loadmc_ex(VFORMAT_MPEG4, fw_name, buf);
+ if (ret < 0) {
+ amvdec_disable();
+ vfree(buf);
+ pr_err("%s: the %s fw loading failed, err: %x\n",
+ fw_name, tee_enabled() ? "TEE" : "local", ret);
+ return -EBUSY;
+ }
+
+ vfree(buf);
+ stat |= STAT_MC_LOAD;
+ query_video_status(0, &trickmode_fffb);
+
+ init_timer(&recycle_timer);
+ stat |= STAT_TIMER_INIT;
+
+ if (vdec_request_irq(VDEC_IRQ_1, vmpeg4_isr,
+ "vmpeg4-irq", (void *)vmpeg4_dec_id)) {
+ amlog_level(LOG_LEVEL_ERROR, "vmpeg4 irq register error.\n");
+ return -ENOENT;
+ }
+ stat |= STAT_ISR_REG;
+ vmpeg4_local_init();
+ /* enable AMRISC side protocol */
+ ret = vmpeg4_prot_init();
+ if (ret < 0) {
+ if (mm_blk_handle) {
+ decoder_bmmu_box_free(mm_blk_handle);
+ mm_blk_handle = NULL;
+ }
+ return ret;
+ }
+ amvdec_enable();
+ fr_hint_status = VDEC_NO_NEED_HINT;
+#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vf_provider_init(&vmpeg_vf_prov, PROVIDER_NAME, &vmpeg_vf_provider,
+ NULL);
+ vf_reg_provider(&vmpeg_vf_prov);
+ vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_START, NULL);
+#else
+ vf_provider_init(&vmpeg_vf_prov, PROVIDER_NAME, &vmpeg_vf_provider,
+ NULL);
+ vf_reg_provider(&vmpeg_vf_prov);
+#endif
+ if (vmpeg4_amstream_dec_info.rate != 0) {
+ if (!is_reset) {
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)
+ ((unsigned long)
+ vmpeg4_amstream_dec_info.rate));
+ fr_hint_status = VDEC_HINTED;
+ }
+ } else
+ fr_hint_status = VDEC_NEED_HINT;
+
+ stat |= STAT_VF_HOOK;
+
+ recycle_timer.data = (ulong)&recycle_timer;
+ recycle_timer.function = vmpeg_put_timer_func;
+ recycle_timer.expires = jiffies + PUT_INTERVAL;
+
+ add_timer(&recycle_timer);
+
+ stat |= STAT_TIMER_ARM;
+
+ amvdec_start();
+
+ stat |= STAT_VDEC_RUN;
+
+ return 0;
+}
+
+static int amvdec_mpeg4_probe(struct platform_device *pdev)
+{
+ struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
+
+ if (pdata == NULL) {
+ amlog_level(LOG_LEVEL_ERROR,
+ "amvdec_mpeg4 memory resource undefined.\n");
+ return -EFAULT;
+ }
+
+ if (pdata->sys_info) {
+ vmpeg4_amstream_dec_info = *pdata->sys_info;
+ if ((vmpeg4_amstream_dec_info.height != 0) &&
+ (vmpeg4_amstream_dec_info.width >
+ (MAX_MPEG4_SUPPORT_SIZE/vmpeg4_amstream_dec_info.height))) {
+ pr_info("amvdec_mpeg4: oversize, unsupport: %d*%d\n",
+ vmpeg4_amstream_dec_info.width,
+ vmpeg4_amstream_dec_info.height);
+ return -EFAULT;
+ }
+ }
+ pdata->dec_status = vmpeg4_dec_status;
+ pdata->set_isreset = vmpeg4_set_isreset;
+ is_reset = 0;
+ vdec = pdata;
+
+ INIT_WORK(&reset_work, reset_do_work);
+ INIT_WORK(¬ify_work, vmpeg4_notify_work);
+ INIT_WORK(&set_clk_work, vmpeg4_set_clk);
+
+ vmpeg4_vdec_info_init();
+
+ if (vmpeg4_init() < 0) {
+ amlog_level(LOG_LEVEL_ERROR, "amvdec_mpeg4 init failed.\n");
+ kfree(gvs);
+ gvs = NULL;
+ pdata->dec_status = NULL;
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int amvdec_mpeg4_remove(struct platform_device *pdev)
+{
+ if (stat & STAT_VDEC_RUN) {
+ amvdec_stop();
+ stat &= ~STAT_VDEC_RUN;
+ }
+
+ if (stat & STAT_ISR_REG) {
+ vdec_free_irq(VDEC_IRQ_1, (void *)vmpeg4_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 (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(&vmpeg_vf_prov);
+ stat &= ~STAT_VF_HOOK;
+ }
+
+ cancel_work_sync(&reset_work);
+ cancel_work_sync(¬ify_work);
+ cancel_work_sync(&set_clk_work);
+
+ amvdec_disable();
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_TM2)
+ vdec_reset_core(NULL);
+ if (mm_blk_handle) {
+ decoder_bmmu_box_free(mm_blk_handle);
+ mm_blk_handle = NULL;
+ }
+
+ amlog_mask(LOG_MASK_PTS,
+ "pts hit %d, pts missed %d, i hit %d, missed %d\n", pts_hit,
+ pts_missed, pts_i_hit, pts_i_missed);
+ amlog_mask(LOG_MASK_PTS, "total frame %d, rate %d\n", total_frame,
+ vmpeg4_amstream_dec_info.rate);
+ kfree(gvs);
+ gvs = NULL;
+ vdec = NULL;
+
+ return 0;
+}
+
+/****************************************/
+#ifdef CONFIG_PM
+static int mpeg4_suspend(struct device *dev)
+{
+ amvdec_suspend(to_platform_device(dev), dev->power.power_state);
+ return 0;
+}
+
+static int mpeg4_resume(struct device *dev)
+{
+ amvdec_resume(to_platform_device(dev));
+ return 0;
+}
+
+static const struct dev_pm_ops mpeg4_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mpeg4_suspend, mpeg4_resume)
+};
+#endif
+
+static struct platform_driver amvdec_mpeg4_driver = {
+ .probe = amvdec_mpeg4_probe,
+ .remove = amvdec_mpeg4_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &mpeg4_pm_ops,
+#endif
+ }
+};
+
+static struct codec_profile_t amvdec_mpeg4_profile = {
+ .name = "mpeg4",
+ .profile = ""
+};
+static struct mconfig mpeg4_configs[] = {
+ MC_PU32("stat", &stat),
+};
+static struct mconfig_node mpeg4_node;
+
+static int __init amvdec_mpeg4_driver_init_module(void)
+{
+ amlog_level(LOG_LEVEL_INFO, "amvdec_mpeg4 module init\n");
+
+ if (platform_driver_register(&amvdec_mpeg4_driver)) {
+ amlog_level(LOG_LEVEL_ERROR,
+ "failed to register amvdec_mpeg4 driver\n");
+ return -ENODEV;
+ }
+ vcodec_profile_register(&amvdec_mpeg4_profile);
+ INIT_REG_NODE_CONFIGS("media.decoder", &mpeg4_node,
+ "mpeg4", mpeg4_configs, CONFIG_FOR_R);
+ return 0;
+}
+
+static void __exit amvdec_mpeg4_driver_remove_module(void)
+{
+ amlog_level(LOG_LEVEL_INFO, "amvdec_mpeg4 module remove.\n");
+
+ platform_driver_unregister(&amvdec_mpeg4_driver);
+}
+
+/****************************************/
+module_init(amvdec_mpeg4_driver_init_module);
+module_exit(amvdec_mpeg4_driver_remove_module);
+
+MODULE_DESCRIPTION("AMLOGIC MPEG4 Video Decoder Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tim Yao <timyao@amlogic.com>");
diff --git a/drivers/frame_provider/decoder/mpeg4/vmpeg4.h b/drivers/frame_provider/decoder/mpeg4/vmpeg4.h
new file mode 100644
index 0000000..7914e6a
--- /dev/null
+++ b/drivers/frame_provider/decoder/mpeg4/vmpeg4.h
@@ -0,0 +1,26 @@
+/*
+ * drivers/amlogic/amports/vmpeg4.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 VMPEG4_H
+#define VMPEG4_H
+
+/* /#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+/* TODO: move to register headers */
+#define VPP_VD1_POSTBLEND (1 << 10)
+/* /#endif */
+
+#endif /* VMPEG4_H */
diff --git a/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c b/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c
new file mode 100644
index 0000000..71b07bf
--- /dev/null
+++ b/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c
@@ -0,0 +1,2885 @@
+/*
+ * drivers/amlogic/amports/vmpeg4.c
+ *
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/kfifo.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/amlogic/media/utils/amstream.h>
+#include <linux/amlogic/media/frame_sync/ptsserv.h>
+
+#include <linux/amlogic/media/vfm/vframe.h>
+#include <linux/amlogic/media/vfm/vframe_provider.h>
+#include <linux/amlogic/media/vfm/vframe_receiver.h>
+#include <linux/amlogic/media/canvas/canvas.h>
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include <linux/amlogic/tee.h>
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include <linux/amlogic/media/registers/register.h>
+#include "../../../stream_input/amports/amports_priv.h"
+
+#include "../utils/amvdec.h"
+#include "../utils/vdec_input.h"
+#include "../utils/vdec.h"
+#include "../utils/firmware.h"
+#include "../utils/decoder_mmu_box.h"
+#include "../utils/decoder_bmmu_box.h"
+#include <linux/amlogic/media/codec_mm/configs.h>
+#include "../utils/firmware.h"
+#include "../utils/vdec_v4l2_buffer_ops.h"
+#include "../utils/config_parser.h"
+#include "../../../common/chips/decoder_cpu_ver_info.h"
+#include <media/v4l2-mem2mem.h>
+
+#define DRIVER_NAME "ammvdec_mpeg4"
+
+#define MEM_NAME "codec_mmpeg4"
+
+#define DEBUG_PTS
+
+#define NV21
+#define I_PICTURE 0
+#define P_PICTURE 1
+#define B_PICTURE 2
+#define GET_PIC_TYPE(type) ("IPB####"[type&0x3])
+
+#define ORI_BUFFER_START_ADDR 0x01000000
+#define DEFAULT_MEM_SIZE (32*SZ_1M)
+
+#define INTERLACE_FLAG 0x80
+#define TOP_FIELD_FIRST_FLAG 0x40
+
+/* protocol registers */
+#define MREG_REF0 AV_SCRATCH_1
+#define MREG_REF1 AV_SCRATCH_2
+#define MP4_PIC_RATIO AV_SCRATCH_5
+#define MP4_RATE AV_SCRATCH_3
+#define MP4_ERR_COUNT AV_SCRATCH_6
+#define MP4_PIC_WH AV_SCRATCH_7
+#define MREG_INPUT AV_SCRATCH_8
+#define MREG_BUFFEROUT AV_SCRATCH_9
+#define MP4_NOT_CODED_CNT AV_SCRATCH_A
+#define MP4_VOP_TIME_INC AV_SCRATCH_B
+#define MP4_OFFSET_REG AV_SCRATCH_C
+#define MP4_VOS_INFO AV_SCRATCH_D
+#define MP4_SYS_RATE AV_SCRATCH_E
+#define MEM_OFFSET_REG AV_SCRATCH_F
+#define MP4_PIC_INFO AV_SCRATCH_H
+
+#define PARC_FORBIDDEN 0
+#define PARC_SQUARE 1
+#define PARC_CIF 2
+#define PARC_10_11 3
+#define PARC_16_11 4
+#define PARC_40_33 5
+#define PARC_RESERVED 6
+/* values between 6 and 14 are reserved */
+#define PARC_EXTENDED 15
+
+#define VF_POOL_SIZE 64
+#define DECODE_BUFFER_NUM_MAX 16
+#define DECODE_BUFFER_NUM_DEF 8
+#define PUT_INTERVAL (HZ/100)
+#define MAX_BMMU_BUFFER_NUM (DECODE_BUFFER_NUM_MAX + 1)
+#define WORKSPACE_SIZE (12*SZ_64K)
+static u32 buf_size = 32 * 1024 * 1024;
+
+#define CTX_LMEM_SWAP_OFFSET 0
+#define CTX_QUANT_MATRIX_OFFSET 0x800
+/* dcac buffer must align at 4k boundary */
+#define CTX_DCAC_BUF_OFFSET 0x1000
+#define CTX_DECBUF_OFFSET (0x0c0000 + 0x1000)
+
+#define RATE_DETECT_COUNT 5
+#define DURATION_UNIT 96000
+#define PTS_UNIT 90000
+#define CHECK_INTERVAL (HZ/100)
+
+#define DUR2PTS(x) ((x) - ((x) >> 4))
+
+/* 96000/(60fps* 2field) = 800, 96000/10fps = 9600 */
+#define MPEG4_VALID_DUR(x) ((x < 9600) && (x > 799))
+
+#define MAX_MPEG4_SUPPORT_SIZE (1920*1088)
+
+#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_UNFINISH 6
+
+#define DEC_DECODE_TIMEOUT 0x21
+#define DECODE_ID(hw) (hw_to_vdec(hw)->id)
+#define DECODE_STOP_POS AV_SCRATCH_K
+static u32 udebug_flag;
+
+static struct vframe_s *vmpeg_vf_peek(void *);
+static struct vframe_s *vmpeg_vf_get(void *);
+static void vmpeg_vf_put(struct vframe_s *, void *);
+static int vmpeg_vf_states(struct vframe_states *states, void *);
+static int vmpeg_event_cb(int type, void *data, void *private_data);
+static int notify_v4l_eos(struct vdec_s *vdec);
+
+static int pre_decode_buf_level = 0x800;
+static int start_decode_buf_level = 0x4000;
+static int debug_enable;
+static unsigned int radr;
+static unsigned int rval;
+/* 0x40bit = 8byte */
+static unsigned int frmbase_cont_bitlevel = 0x40;
+static unsigned int dynamic_buf_num_margin;
+
+#define VMPEG4_DEV_NUM 9
+static unsigned int max_decode_instance_num = VMPEG4_DEV_NUM;
+static unsigned int max_process_time[VMPEG4_DEV_NUM];
+static unsigned int decode_timeout_val = 200;
+
+static u32 without_display_mode;
+
+#undef pr_info
+#define pr_info printk
+unsigned int mpeg4_debug_mask = 0xff;
+static u32 run_ready_min_buf_num = 2;
+
+
+#define PRINT_FLAG_ERROR 0x0
+#define PRINT_FLAG_RUN_FLOW 0X0001
+#define PRINT_FLAG_TIMEINFO 0x0002
+#define PRINT_FLAG_UCODE_DETAIL 0x0004
+#define PRINT_FLAG_VLD_DETAIL 0x0008
+#define PRINT_FLAG_DEC_DETAIL 0x0010
+#define PRINT_FLAG_BUFFER_DETAIL 0x0020
+#define PRINT_FLAG_RESTORE 0x0040
+#define PRINT_FRAME_NUM 0x0080
+#define PRINT_FLAG_FORCE_DONE 0x0100
+#define PRINT_FLAG_COUNTER 0X0200
+#define PRINT_FRAMEBASE_DATA 0x0400
+#define PRINT_FLAG_VDEC_STATUS 0x0800
+#define PRINT_FLAG_TIMEOUT_STATUS 0x1000
+#define PRINT_FLAG_V4L_DETAIL 0x8000
+#define IGNORE_PARAM_FROM_CONFIG 0x8000000
+
+int mmpeg4_debug_print(int index, int debug_flag, const char *fmt, ...)
+{
+ if (((debug_enable & debug_flag) &&
+ ((1 << index) & mpeg4_debug_mask))
+ || (debug_flag == PRINT_FLAG_ERROR)) {
+ unsigned char buf[512];
+ int len = 0;
+ va_list args;
+ va_start(args, fmt);
+ len = sprintf(buf, "%d: ", index);
+ vsnprintf(buf + len, 512-len, fmt, args);
+ pr_info("%s", buf);
+ va_end(args);
+ }
+ return 0;
+}
+
+struct pic_info_t {
+ int index;
+ u32 pic_type;
+ u32 pic_info;
+ u32 pts;
+ u64 pts64;
+ bool pts_valid;
+ u32 duration;
+ u32 repeat_cnt;
+ ulong v4l_ref_buf_addr;
+ u32 hw_decode_time;
+ u32 frame_size; // For frame base mode;
+ u32 offset;
+};
+
+struct vdec_mpeg4_hw_s {
+ spinlock_t lock;
+ struct platform_device *platform_dev;
+ /* struct device *cma_dev; */
+
+ DECLARE_KFIFO(newframe_q, struct vframe_s *, VF_POOL_SIZE);
+ DECLARE_KFIFO(display_q, struct vframe_s *, VF_POOL_SIZE);
+ struct vframe_s vfpool[VF_POOL_SIZE];
+
+ s32 vfbuf_use[DECODE_BUFFER_NUM_MAX];
+ u32 frame_width;
+ u32 frame_height;
+ u32 frame_dur;
+ u32 frame_prog;
+
+ u32 ctx_valid;
+ u32 reg_vcop_ctrl_reg;
+ u32 reg_pic_head_info;
+ u32 reg_mpeg1_2_reg;
+ u32 reg_slice_qp;
+ u32 reg_mp4_pic_wh;
+ u32 reg_mp4_rate;
+ u32 reg_mb_info;
+ u32 reg_dc_ac_ctrl;
+ u32 reg_iqidct_control;
+ u32 reg_resync_marker_length;
+ u32 reg_rv_ai_mb_count;
+ struct timer_list check_timer;
+ u32 decode_timeout_count;
+ u32 timeout_cnt;
+ unsigned long int start_process_time;
+
+ u32 last_vld_level;
+ u8 init_flag;
+ u32 eos;
+ void *mm_blk_handle;
+
+ struct vframe_chunk_s *chunk;
+ u32 chunk_offset;
+ u32 chunk_size;
+ u32 chunk_frame_count;
+ u32 stat;
+ unsigned long buf_start;
+ u32 buf_size;
+ /*
+ unsigned long cma_alloc_addr;
+ int cma_alloc_count;
+ */
+ u32 vmpeg4_ratio;
+ u64 vmpeg4_ratio64;
+ u32 rate_detect;
+ u32 vmpeg4_rotation;
+ u32 total_frame;
+ u32 last_vop_time_inc;
+ u32 last_duration;
+ u32 last_anch_pts;
+ u32 vop_time_inc_since_last_anch;
+ u32 frame_num_since_last_anch;
+ u64 last_anch_pts_us64;
+
+ u32 last_pts;
+ u64 last_pts64;
+ u32 pts_hit;
+ u32 pts_missed;
+ u32 pts_i_hit;
+ u32 pts_i_missed;
+ struct pic_info_t pic[DECODE_BUFFER_NUM_MAX];
+ u32 canvas_spec[DECODE_BUFFER_NUM_MAX];
+#ifdef NV21
+ struct canvas_config_s canvas_config[DECODE_BUFFER_NUM_MAX][2];
+#else
+ struct canvas_config_s canvas_config[DECODE_BUFFER_NUM_MAX][3];
+#endif
+ struct dec_sysinfo vmpeg4_amstream_dec_info;
+
+ s32 refs[2];
+ int dec_result;
+ struct work_struct work;
+
+ void (*vdec_cb)(struct vdec_s *, void *);
+ void *vdec_cb_arg;
+ u32 frame_num;
+ u32 put_num;
+ u32 sys_mp4_rate;
+ u32 run_count;
+ u32 not_run_ready;
+ u32 buffer_not_ready;
+ u32 input_empty;
+ u32 peek_num;
+ u32 get_num;
+ u32 first_i_frame_ready;
+ u32 drop_frame_count;
+ u32 unstable_pts;
+ u32 last_dec_pts;
+
+ struct firmware_s *fw;
+ u32 blkmode;
+ wait_queue_head_t wait_q;
+ bool is_used_v4l;
+ void *v4l2_ctx;
+ bool v4l_params_parsed;
+ u32 buf_num;
+ u32 dynamic_buf_num_margin;
+ u32 i_only;
+ int sidebind_type;
+ int sidebind_channel_id;
+ u32 res_ch_flag;
+ unsigned int i_decoded_frames;
+ unsigned int i_lost_frames;
+ unsigned int i_concealed_frames;
+ unsigned int p_decoded_frames;
+ unsigned int p_lost_frames;
+ unsigned int p_concealed_frames;
+ unsigned int b_decoded_frames;
+ unsigned int b_lost_frames;
+ unsigned int b_concealed_frames;
+ u32 profile_idc;
+ u32 level_idc;
+ int vdec_pg_enable_flag;
+ char vdec_name[32];
+ char pts_name[32];
+ char new_q_name[32];
+ char disp_q_name[32];
+};
+static void vmpeg4_local_init(struct vdec_mpeg4_hw_s *hw);
+static int vmpeg4_hw_ctx_restore(struct vdec_mpeg4_hw_s *hw);
+static unsigned char
+ get_data_check_sum(struct vdec_mpeg4_hw_s *hw, int size);
+static void flush_output(struct vdec_mpeg4_hw_s * hw);
+
+#define PROVIDER_NAME "vdec.mpeg4"
+
+/*
+ *int query_video_status(int type, int *value);
+ */
+static const struct vframe_operations_s vf_provider_ops = {
+ .peek = vmpeg_vf_peek,
+ .get = vmpeg_vf_get,
+ .put = vmpeg_vf_put,
+ .event_cb = vmpeg_event_cb,
+ .vf_states = vmpeg_vf_states,
+};
+
+static unsigned char aspect_ratio_table[16] = {
+ PARC_FORBIDDEN,
+ PARC_SQUARE,
+ PARC_CIF,
+ PARC_10_11,
+ PARC_16_11,
+ PARC_40_33,
+ PARC_RESERVED, PARC_RESERVED, PARC_RESERVED, PARC_RESERVED,
+ PARC_RESERVED, PARC_RESERVED, PARC_RESERVED, PARC_RESERVED,
+ PARC_RESERVED, PARC_EXTENDED
+};
+
+static void reset_process_time(struct vdec_mpeg4_hw_s *hw);
+
+
+static int vmpeg4_get_buf_num(struct vdec_mpeg4_hw_s *hw)
+{
+ int buf_num = DECODE_BUFFER_NUM_DEF;
+
+ buf_num += hw->dynamic_buf_num_margin;
+ if (buf_num > DECODE_BUFFER_NUM_MAX)
+ buf_num = DECODE_BUFFER_NUM_MAX;
+
+ return buf_num;
+}
+
+static int vmpeg4_v4l_alloc_buff_config_canvas(struct vdec_mpeg4_hw_s *hw, int i)
+{
+ int ret;
+ u32 canvas;
+ ulong decbuf_start = 0, decbuf_uv_start = 0;
+ int decbuf_y_size = 0, decbuf_uv_size = 0;
+ u32 canvas_width = 0, canvas_height = 0;
+ struct vdec_s *vdec = hw_to_vdec(hw);
+ struct vdec_v4l2_buffer *fb = NULL;
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(hw->v4l2_ctx);
+
+ if (hw->pic[i].v4l_ref_buf_addr)
+ return 0;
+
+ ret = vdec_v4l_get_buffer(hw->v4l2_ctx, &fb);
+ if (ret < 0) {
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "[%d] get fb fail.\n",
+ ((struct aml_vcodec_ctx *)
+ (hw->v4l2_ctx))->id);
+ return ret;
+ }
+
+ if (!hw->frame_width || !hw->frame_height) {
+ struct vdec_pic_info pic;
+ vdec_v4l_get_pic_info(ctx, &pic);
+ hw->frame_width = pic.visible_width;
+ hw->frame_height = pic.visible_height;
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "[%d] set %d x %d from IF layer\n", ctx->id,
+ hw->frame_width, hw->frame_height);
+ }
+
+ hw->pic[i].v4l_ref_buf_addr = (ulong)fb;
+ if (fb->num_planes == 1) {
+ decbuf_start = fb->m.mem[0].addr;
+ decbuf_y_size = fb->m.mem[0].offset;
+ decbuf_uv_start = decbuf_start + decbuf_y_size;
+ decbuf_uv_size = decbuf_y_size / 2;
+ canvas_width = ALIGN(hw->frame_width, 64);
+ canvas_height = ALIGN(hw->frame_height, 64);
+ fb->m.mem[0].bytes_used = fb->m.mem[0].size;
+ } else if (fb->num_planes == 2) {
+ decbuf_start = fb->m.mem[0].addr;
+ decbuf_y_size = fb->m.mem[0].size;
+ decbuf_uv_start = fb->m.mem[1].addr;
+ decbuf_uv_size = fb->m.mem[1].size;
+ canvas_width = ALIGN(hw->frame_width, 64);
+ canvas_height = ALIGN(hw->frame_height, 64);
+ fb->m.mem[0].bytes_used = decbuf_y_size;
+ fb->m.mem[1].bytes_used = decbuf_uv_size;
+ }
+
+ mmpeg4_debug_print(DECODE_ID(hw), 0, "[%d] %s(), v4l ref buf addr: 0x%px\n",
+ ctx->id, __func__, fb);
+
+ if (vdec->parallel_dec == 1) {
+ u32 tmp;
+ 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;
+ }
+ 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;
+ }
+ canvas = hw->canvas_spec[i];
+ } else {
+ canvas = vdec->get_canvas(i, 2);
+ hw->canvas_spec[i] = canvas;
+ }
+
+ hw->canvas_config[i][0].phy_addr = decbuf_start;
+ hw->canvas_config[i][0].width = canvas_width;
+ hw->canvas_config[i][0].height = canvas_height;
+ hw->canvas_config[i][0].block_mode = hw->blkmode;
+ if (hw->blkmode == CANVAS_BLKMODE_LINEAR)
+ hw->canvas_config[i][0].endian = 7;
+ else
+ hw->canvas_config[i][0].endian = 0;
+ canvas_config_config(canvas_y(canvas),
+ &hw->canvas_config[i][0]);
+
+ hw->canvas_config[i][1].phy_addr =
+ decbuf_uv_start;
+ hw->canvas_config[i][1].width = canvas_width;
+ hw->canvas_config[i][1].height = (canvas_height >> 1);
+ hw->canvas_config[i][1].block_mode = hw->blkmode;
+ if (hw->blkmode == CANVAS_BLKMODE_LINEAR)
+ hw->canvas_config[i][1].endian = 7;
+ else
+ hw->canvas_config[i][1].endian = 0;
+ canvas_config_config(canvas_u(canvas),
+ &hw->canvas_config[i][1]);
+
+ return 0;
+}
+
+static bool is_enough_free_buffer(struct vdec_mpeg4_hw_s *hw)
+{
+ int i;
+
+ for (i = 0; i < hw->buf_num; i++) {
+ if (hw->vfbuf_use[i] == 0)
+ break;
+ }
+
+ return i == hw->buf_num ? false : true;
+}
+
+static int find_free_buffer(struct vdec_mpeg4_hw_s *hw)
+{
+ int i;
+
+ for (i = 0; i < hw->buf_num; i++) {
+ if (hw->vfbuf_use[i] == 0)
+ break;
+ }
+
+ if (i == hw->buf_num)
+ return -1;
+
+ 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) {
+ /*run to parser csd data*/
+ i = 0;
+ } else {
+ if (vmpeg4_v4l_alloc_buff_config_canvas(hw, i))
+ return -1;
+ }
+ }
+
+
+ return i;
+}
+
+static int spec_to_index(struct vdec_mpeg4_hw_s *hw, u32 spec)
+{
+ int i;
+
+ for (i = 0; i < hw->buf_num; i++) {
+ if (hw->canvas_spec[i] == spec)
+ return i;
+ }
+
+ return -1;
+}
+
+static void set_frame_info(struct vdec_mpeg4_hw_s *hw, struct vframe_s *vf,
+ int buffer_index)
+{
+ int ar = 0;
+ unsigned int num = 0;
+ unsigned int den = 0;
+ unsigned int pixel_ratio = READ_VREG(MP4_PIC_RATIO);
+
+ if (hw->vmpeg4_ratio64 != 0) {
+ num = hw->vmpeg4_ratio64>>32;
+ den = hw->vmpeg4_ratio64 & 0xffffffff;
+ } else {
+ num = hw->vmpeg4_ratio>>16;
+ den = hw->vmpeg4_ratio & 0xffff;
+
+ }
+ if ((num == 0) || (den == 0)) {
+ num = 1;
+ den = 1;
+ }
+
+ if (hw->vmpeg4_ratio == 0) {
+ vf->ratio_control |= (0x90 << DISP_RATIO_ASPECT_RATIO_BIT);
+ vf->sar_width = 1;
+ vf->sar_height = 1;
+ /* always stretch to 16:9 */
+ } else if (pixel_ratio > 0x0f) {
+ num = (pixel_ratio >> 8) *
+ hw->frame_width * num;
+ ar = div_u64((pixel_ratio & 0xff) *
+ hw->frame_height * den * 0x100ULL +
+ (num >> 1), num);
+ } else {
+ switch (aspect_ratio_table[pixel_ratio]) {
+ case 0:
+ vf->sar_width = 1;
+ vf->sar_height = 1;
+ num = hw->frame_width * num;
+ ar = (hw->frame_height * den *
+ 0x100 + (num >> 1)) / num;
+ break;
+ case 1:
+ vf->sar_width = 1;
+ vf->sar_height = 1;
+ num = vf->width * num;
+ ar = (vf->height * den * 0x100 + (num >> 1)) / num;
+ break;
+ case 2:
+ vf->sar_width = 12;
+ vf->sar_height = 11;
+ num = (vf->width * 12) * num;
+ ar = (vf->height * den * 0x100 * 11 +
+ ((num) >> 1)) / num;
+ break;
+ case 3:
+ vf->sar_width = 10;
+ vf->sar_height = 11;
+ num = (vf->width * 10) * num;
+ ar = (vf->height * den * 0x100 * 11 + (num >> 1)) /
+ num;
+ break;
+ case 4:
+ vf->sar_width = 16;
+ vf->sar_height = 11;
+ num = (vf->width * 16) * num;
+ ar = (vf->height * den * 0x100 * 11 + (num >> 1)) /
+ num;
+ break;
+ case 5:
+ vf->sar_width = 40;
+ vf->sar_height = 33;
+ num = (vf->width * 40) * num;
+ ar = (vf->height * den * 0x100 * 33 + (num >> 1)) /
+ num;
+ break;
+ default:
+ vf->sar_width = 1;
+ vf->sar_height = 1;
+ num = vf->width * num;
+ ar = (vf->height * den * 0x100 + (num >> 1)) / num;
+ break;
+ }
+ }
+
+ vf->sidebind_type = hw->sidebind_type;
+ vf->sidebind_channel_id = hw->sidebind_channel_id;
+
+ ar = min(ar, DISP_RATIO_ASPECT_RATIO_MAX);
+
+ vf->signal_type = 0;
+ vf->type_original = vf->type;
+ vf->ratio_control = (ar << DISP_RATIO_ASPECT_RATIO_BIT);
+ vf->canvas0Addr = vf->canvas1Addr = -1;
+#ifdef NV21
+ vf->plane_num = 2;
+#else
+ vf->plane_num = 3;
+#endif
+ vf->canvas0_config[0] = hw->canvas_config[buffer_index][0];
+ vf->canvas0_config[1] = hw->canvas_config[buffer_index][1];
+#ifndef NV21
+ vf->canvas0_config[2] = hw->canvas_config[buffer_index][2];
+#endif
+ vf->canvas1_config[0] = hw->canvas_config[buffer_index][0];
+ vf->canvas1_config[1] = hw->canvas_config[buffer_index][1];
+#ifndef NV21
+ vf->canvas1_config[2] = hw->canvas_config[buffer_index][2];
+#endif
+}
+
+static inline void vmpeg4_save_hw_context(struct vdec_mpeg4_hw_s *hw)
+{
+ hw->reg_mpeg1_2_reg = READ_VREG(MPEG1_2_REG);
+ hw->reg_vcop_ctrl_reg = READ_VREG(VCOP_CTRL_REG);
+ hw->reg_pic_head_info = READ_VREG(PIC_HEAD_INFO);
+ hw->reg_slice_qp = READ_VREG(SLICE_QP);
+ hw->reg_mp4_pic_wh = READ_VREG(MP4_PIC_WH);
+ hw->reg_mp4_rate = READ_VREG(MP4_RATE);
+ hw->reg_mb_info = READ_VREG(MB_INFO);
+ hw->reg_dc_ac_ctrl = READ_VREG(DC_AC_CTRL);
+ hw->reg_iqidct_control = READ_VREG(IQIDCT_CONTROL);
+ hw->reg_resync_marker_length = READ_VREG(RESYNC_MARKER_LENGTH);
+ hw->reg_rv_ai_mb_count = READ_VREG(RV_AI_MB_COUNT);
+}
+
+static int update_ref(struct vdec_mpeg4_hw_s *hw, int index)
+{
+ hw->vfbuf_use[index]++;
+
+ if (hw->refs[1] == -1) {
+ hw->refs[1] = index;
+ index = -1;
+ } else if (hw->refs[0] == -1) {
+ hw->refs[0] = hw->refs[1];
+ hw->refs[1] = index;
+ index = hw->refs[0];
+ } else {
+ hw->vfbuf_use[hw->refs[0]]--;
+ hw->refs[0] = hw->refs[1];
+ hw->refs[1] = index;
+ index = hw->refs[0];
+ }
+
+ return index;
+}
+
+static int prepare_display_buf(struct vdec_mpeg4_hw_s * hw,
+ struct pic_info_t *pic)
+{
+ struct vframe_s *vf = NULL;
+ struct vdec_s *vdec = hw_to_vdec(hw);
+ struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx;
+ ulong nv_order = VIDTYPE_VIU_NV21;
+ int index = pic->index;
+ bool pb_skip = false;
+ unsigned long flags;
+
+ /* 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 (hw->i_only)
+ pb_skip = 1;
+
+ if (pic->pic_info & INTERLACE_FLAG) {
+ if (kfifo_get(&hw->newframe_q, &vf) == 0) {
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "fatal error, no available buffer slot.");
+ return -1;
+ }
+
+ if (hw->is_used_v4l) {
+ vf->v4l_mem_handle
+ = hw->pic[index].v4l_ref_buf_addr;
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL,
+ "[%d] %s(), v4l mem handle: 0x%lx\n",
+ ((struct aml_vcodec_ctx *)(hw->v4l2_ctx))->id,
+ __func__, vf->v4l_mem_handle);
+ }
+
+ vf->index = pic->index;
+ vf->width = hw->frame_width;
+ vf->height = hw->frame_height;
+ vf->bufWidth = 1920;
+ vf->flag = 0;
+ vf->orientation = hw->vmpeg4_rotation;
+ vf->pts = pic->pts;
+ vf->pts_us64 = pic->pts64;
+ vf->duration = pic->duration >> 1;
+ vf->duration_pulldown = 0;
+ vf->type = (pic->pic_info & TOP_FIELD_FIRST_FLAG) ?
+ VIDTYPE_INTERLACE_TOP : VIDTYPE_INTERLACE_BOTTOM;
+#ifdef NV21
+ vf->type |= nv_order;
+#endif
+ set_frame_info(hw, vf, pic->index);
+
+ hw->vfbuf_use[pic->index]++;
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEINFO,
+ "field0: pts %d, pts64 %lld, w %d, h %d, dur %d\n",
+ vf->pts, vf->pts_us64, vf->width, vf->height, vf->duration);
+
+ if (vdec_stream_based(vdec) && (!vdec->vbuf.use_ptsserv)) {
+ vf->pts_us64 =
+ (((u64)vf->duration << 32) &
+ 0xffffffff00000000) | pic->offset;
+ vf->pts = 0;
+ }
+ if (((hw->first_i_frame_ready == 0) || pb_skip)
+ && (pic->pic_type != I_PICTURE)) {
+ hw->drop_frame_count++;
+ if (pic->pic_type == I_PICTURE) {
+ hw->i_lost_frames++;
+ } else if (pic->pic_type == P_PICTURE) {
+ hw->p_lost_frames++;
+ } else if (pic->pic_type == B_PICTURE) {
+ hw->b_lost_frames++;
+ }
+ hw->vfbuf_use[index]--;
+ spin_lock_irqsave(&hw->lock, flags);
+ kfifo_put(&hw->newframe_q,
+ (const struct vframe_s *)vf);
+ spin_unlock_irqrestore(&hw->lock, flags);
+ return 0;
+ } else {
+ vf->mem_handle =
+ decoder_bmmu_box_get_mem_handle(
+ hw->mm_blk_handle, index);
+ kfifo_put(&hw->display_q, (const struct vframe_s *)vf);
+ ATRACE_COUNTER(hw->pts_name, vf->pts);
+ hw->frame_num++;
+ if (pic->pic_type == I_PICTURE) {
+ hw->i_decoded_frames++;
+ } else if (pic->pic_type == P_PICTURE) {
+ hw->p_decoded_frames++;
+ } else if (pic->pic_type == B_PICTURE) {
+ hw->b_decoded_frames++;
+ }
+ if (without_display_mode == 0) {
+ vf_notify_receiver(vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
+ } else
+ vmpeg_vf_put(vmpeg_vf_get(vdec), vdec);
+ }
+ if (kfifo_get(&hw->newframe_q, &vf) == 0) {
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "error, no available buf.\n");
+ hw->dec_result = DEC_RESULT_ERROR;
+ return -1;
+ }
+
+ if (hw->is_used_v4l) {
+ vf->v4l_mem_handle
+ = hw->pic[index].v4l_ref_buf_addr;
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL,
+ "[%d] %s(), v4l mem handle: 0x%lx\n",
+ ((struct aml_vcodec_ctx *)(hw->v4l2_ctx))->id,
+ __func__, vf->v4l_mem_handle);
+ }
+
+
+ vf->index = pic->index;
+ vf->width = hw->frame_width;
+ vf->height = hw->frame_height;
+ vf->bufWidth = 1920;
+ vf->flag = 0;
+ vf->orientation = hw->vmpeg4_rotation;
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+ vf->duration = pic->duration >> 1;
+ vf->duration_pulldown = 0;
+ vf->type = (pic->pic_info & TOP_FIELD_FIRST_FLAG) ?
+ VIDTYPE_INTERLACE_BOTTOM : VIDTYPE_INTERLACE_TOP;
+#ifdef NV21
+ vf->type |= nv_order;
+#endif
+ set_frame_info(hw, vf, pic->index);
+
+ hw->vfbuf_use[pic->index]++;
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEINFO,
+ "filed1: pts %d, pts64 %lld, w %d, h %d, dur: %d\n",
+ vf->pts, vf->pts_us64, vf->width, vf->height, vf->duration);
+
+ if (vdec_stream_based(vdec) && (!vdec->vbuf.use_ptsserv)) {
+ vf->pts_us64 = (u64)-1;
+ vf->pts = 0;
+ }
+
+ if (((hw->first_i_frame_ready == 0) || pb_skip)
+ && (pic->pic_type != I_PICTURE)) {
+ hw->drop_frame_count++;
+ if (pic->pic_type == I_PICTURE) {
+ hw->i_lost_frames++;
+ } else if (pic->pic_type == P_PICTURE) {
+ hw->p_lost_frames++;
+ } else if (pic->pic_type == B_PICTURE) {
+ hw->b_lost_frames++;
+ }
+ hw->vfbuf_use[index]--;
+ spin_lock_irqsave(&hw->lock, flags);
+ kfifo_put(&hw->newframe_q,
+ (const struct vframe_s *)vf);
+ spin_unlock_irqrestore(&hw->lock, flags);
+ } else {
+ vf->mem_handle =
+ decoder_bmmu_box_get_mem_handle(
+ hw->mm_blk_handle, index);
+ decoder_do_frame_check(vdec, vf);
+ vdec_vframe_ready(vdec, vf);
+ kfifo_put(&hw->display_q,
+ (const struct vframe_s *)vf);
+ ATRACE_COUNTER(hw->pts_name, vf->pts);
+ vdec->vdec_fps_detec(vdec->id);
+ hw->frame_num++;
+ if (pic->pic_type == I_PICTURE) {
+ hw->i_decoded_frames++;
+ } else if (pic->pic_type == P_PICTURE) {
+ hw->p_decoded_frames++;
+ } else if (pic->pic_type == B_PICTURE) {
+ hw->b_decoded_frames++;
+ }
+ if (without_display_mode == 0) {
+ vf_notify_receiver(vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
+ } else
+ vmpeg_vf_put(vmpeg_vf_get(vdec), vdec);
+ }
+ } else {
+ /* progressive */
+ if (kfifo_get(&hw->newframe_q, &vf) == 0) {
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "error, no available buf\n");
+ hw->dec_result = DEC_RESULT_ERROR;
+ return -1;
+ }
+ if (hw->is_used_v4l) {
+ vf->v4l_mem_handle
+ = hw->pic[index].v4l_ref_buf_addr;
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL,
+ "[%d] %s(), v4l mem handle: 0x%lx\n",
+ ((struct aml_vcodec_ctx *)(hw->v4l2_ctx))->id,
+ __func__, vf->v4l_mem_handle);
+ }
+
+ vf->index = index;
+ vf->width = hw->frame_width;
+ vf->height = hw->frame_height;
+ vf->bufWidth = 1920;
+ vf->flag = 0;
+ vf->orientation = hw->vmpeg4_rotation;
+ vf->pts = pic->pts;
+ vf->pts_us64 = pic->pts64;
+ vf->duration = pic->duration;
+ vf->duration_pulldown = pic->repeat_cnt *
+ pic->duration;
+#ifdef NV21
+ vf->type = VIDTYPE_PROGRESSIVE |
+ VIDTYPE_VIU_FIELD | nv_order;
+#else
+ vf->type = VIDTYPE_PROGRESSIVE |
+ VIDTYPE_VIU_FIELD;
+#endif
+ set_frame_info(hw, vf, index);
+
+ hw->vfbuf_use[index]++;
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEINFO,
+ "prog: pts %d, pts64 %lld, w %d, h %d, dur %d\n",
+ vf->pts, vf->pts_us64, vf->width, vf->height, vf->duration);
+
+ if (vdec_stream_based(vdec) && (!vdec->vbuf.use_ptsserv)) {
+ vf->pts_us64 =
+ (((u64)vf->duration << 32) &
+ 0xffffffff00000000) | pic->offset;
+ vf->pts = 0;
+ }
+
+ if (((hw->first_i_frame_ready == 0) || pb_skip)
+ && (pic->pic_type != I_PICTURE)) {
+ hw->drop_frame_count++;
+ if (pic->pic_type == I_PICTURE) {
+ hw->i_lost_frames++;
+ } else if (pic->pic_type == P_PICTURE) {
+ hw->p_lost_frames++;
+ } else if (pic->pic_type == B_PICTURE) {
+ hw->b_lost_frames++;
+ }
+ hw->vfbuf_use[index]--;
+ spin_lock_irqsave(&hw->lock, flags);
+ kfifo_put(&hw->newframe_q,
+ (const struct vframe_s *)vf);
+ spin_unlock_irqrestore(&hw->lock, flags);
+ } else {
+ struct vdec_info vinfo;
+
+ vf->mem_handle =
+ decoder_bmmu_box_get_mem_handle(
+ hw->mm_blk_handle, index);
+ decoder_do_frame_check(vdec, 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));
+ vdec->vdec_fps_detec(vdec->id);
+ hw->frame_num++;
+ if (pic->pic_type == I_PICTURE) {
+ hw->i_decoded_frames++;
+ } else if (pic->pic_type == P_PICTURE) {
+ hw->p_decoded_frames++;
+ } else if (pic->pic_type == B_PICTURE) {
+ hw->b_decoded_frames++;
+ }
+ vdec->dec_status(vdec, &vinfo);
+ vdec_fill_vdec_frame(vdec, NULL,
+ &vinfo, vf, pic->hw_decode_time);
+ if (without_display_mode == 0) {
+ vf_notify_receiver(vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
+ } else
+ vmpeg_vf_put(vmpeg_vf_get(vdec), vdec);
+ }
+
+ }
+ return 0;
+}
+
+static void vmpeg4_prepare_input(struct vdec_mpeg4_hw_s *hw)
+{
+ struct vdec_s *vdec = hw_to_vdec(hw);
+ struct vdec_input_s *input = &vdec->input;
+ struct vframe_block_list_s *block = NULL;
+ struct vframe_chunk_s *chunk = hw->chunk;
+ int dummy;
+
+ if (chunk == NULL)
+ return;
+
+ /* full reset to HW input */
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 0);
+
+ /* reset VLD fifo for all vdec */
+ WRITE_VREG(DOS_SW_RESET0, (1<<5) | (1<<4) | (1<<3));
+ WRITE_VREG(DOS_SW_RESET0, 0);
+ if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SC2)
+ dummy = READ_RESET_REG(RESET0_REGISTER);
+ WRITE_VREG(POWER_CTL_VLD, 1 << 4);
+
+ /*
+ *setup HW decoder input buffer (VLD context)
+ * based on input->type and input->target
+ */
+ if (input_frame_based(input)) {
+ block = chunk->block;
+
+ WRITE_VREG(VLD_MEM_VIFIFO_START_PTR, block->start);
+ WRITE_VREG(VLD_MEM_VIFIFO_END_PTR, block->start +
+ block->size - 8);
+ WRITE_VREG(VLD_MEM_VIFIFO_CURR_PTR,
+ round_down(block->start + hw->chunk_offset,
+ VDEC_FIFO_ALIGN));
+
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 1);
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 0);
+
+ /* set to manual mode */
+ WRITE_VREG(VLD_MEM_VIFIFO_BUF_CNTL, 2);
+ WRITE_VREG(VLD_MEM_VIFIFO_RP,
+ round_down(block->start + hw->chunk_offset,
+ VDEC_FIFO_ALIGN));
+ dummy = hw->chunk_offset + hw->chunk_size +
+ VLD_PADDING_SIZE;
+ if (dummy >= block->size)
+ dummy -= block->size;
+ WRITE_VREG(VLD_MEM_VIFIFO_WP,
+ round_down(block->start + dummy,
+ VDEC_FIFO_ALIGN));
+
+ WRITE_VREG(VLD_MEM_VIFIFO_BUF_CNTL, 3);
+ WRITE_VREG(VLD_MEM_VIFIFO_BUF_CNTL, 2);
+
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL,
+ (0x11 << 16) | (1<<10) | (7<<3));
+
+ }
+}
+
+static int vmpeg4_get_ps_info(struct vdec_mpeg4_hw_s *hw, int width, int height, int interlace, struct aml_vdec_ps_infos *ps)
+{
+ ps->visible_width = width;
+ ps->visible_height = height;
+ ps->coded_width = ALIGN(width, 64);
+ ps->coded_height = ALIGN(height, 64);
+ ps->dpb_size = hw->buf_num;
+ ps->field = interlace ? V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int v4l_res_change(struct vdec_mpeg4_hw_s *hw, int width, int height, int interlace)
+{
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(hw->v4l2_ctx);
+ int ret = 0;
+
+ if (ctx->param_sets_from_ucode &&
+ hw->res_ch_flag == 0) {
+ struct aml_vdec_ps_infos ps;
+
+ if ((hw->frame_width != 0 &&
+ hw->frame_height != 0) &&
+ (hw->frame_width != width ||
+ hw->frame_height != height)) {
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "v4l_res_change Pic Width/Height Change (%d,%d)=>(%d,%d)\n",
+ hw->frame_width, hw->frame_height,
+ width,
+ height);
+ vmpeg4_get_ps_info(hw, width, height, interlace, &ps);
+ vdec_v4l_set_ps_infos(ctx, &ps);
+ vdec_v4l_res_ch_event(ctx);
+ hw->v4l_params_parsed = false;
+ hw->res_ch_flag = 1;
+ ctx->v4l_resolution_change = 1;
+ hw->eos = 1;
+ flush_output(hw);
+ notify_v4l_eos(hw_to_vdec(hw));
+
+ ret = 1;
+ }
+ }
+
+ return ret;
+}
+
+
+static irqreturn_t vmpeg4_isr_thread_fn(struct vdec_s *vdec, int irq)
+{
+ u32 reg;
+ u32 picture_type;
+ int index;
+ u32 pts, offset = 0;
+ u64 pts_us64 = 0;
+ u32 frame_size, dec_w, dec_h;
+ u32 time_increment_resolution, fixed_vop_rate, vop_time_inc, vos_info;
+ u32 repeat_cnt, duration = 3200;
+ struct pic_info_t *dec_pic, *disp_pic;
+ struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)(vdec->private);
+
+ if (hw->eos)
+ return IRQ_HANDLED;
+
+ if (READ_VREG(MP4_PIC_INFO) == 1) {
+ if (hw->is_used_v4l) {
+ int frame_width = READ_VREG(MP4_PIC_WH)>> 16;
+ int frame_height = READ_VREG(MP4_PIC_WH) & 0xffff;
+ int interlace = (READ_VREG(MP4_PIC_RATIO) & 0x80000000) >> 31;
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_BUFFER_DETAIL,
+ "interlace = %d\n", interlace);
+ if (!v4l_res_change(hw, frame_width, frame_height, interlace)) {
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(hw->v4l2_ctx);
+ if (ctx->param_sets_from_ucode && !hw->v4l_params_parsed) {
+ struct aml_vdec_ps_infos ps;
+
+ vmpeg4_get_ps_info(hw, frame_width, frame_height, interlace, &ps);
+ hw->v4l_params_parsed = true;
+ vdec_v4l_set_ps_infos(ctx, &ps);
+ reset_process_time(hw);
+ hw->dec_result = DEC_RESULT_AGAIN;
+ vdec_schedule_work(&hw->work);
+ } else {
+ WRITE_VREG(MP4_PIC_INFO, 0);
+ }
+ } else {
+ reset_process_time(hw);
+ hw->dec_result = DEC_RESULT_AGAIN;
+ vdec_schedule_work(&hw->work);
+ }
+ } else
+ WRITE_VREG(MP4_PIC_INFO, 0);
+ return IRQ_HANDLED;
+ }
+
+ WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
+ if (READ_VREG(AV_SCRATCH_M) != 0 &&
+ (debug_enable & PRINT_FLAG_UCODE_DETAIL)) {
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_UCODE_DETAIL,
+ "dbg %x: %x, level %x, wp %x, rp %x, cnt %x\n",
+ READ_VREG(AV_SCRATCH_M), READ_VREG(AV_SCRATCH_N),
+ READ_VREG(VLD_MEM_VIFIFO_LEVEL),
+ READ_VREG(VLD_MEM_VIFIFO_WP),
+ READ_VREG(VLD_MEM_VIFIFO_RP),
+ READ_VREG(VIFF_BIT_CNT));
+ WRITE_VREG(AV_SCRATCH_M, 0);
+ return IRQ_HANDLED;
+ }
+ reg = READ_VREG(MREG_BUFFEROUT);
+
+ time_increment_resolution = READ_VREG(MP4_RATE);
+ fixed_vop_rate = time_increment_resolution >> 16;
+ time_increment_resolution &= 0xffff;
+ if (time_increment_resolution > 0 &&
+ fixed_vop_rate == 0)
+ hw->sys_mp4_rate = time_increment_resolution;
+
+ if (hw->vmpeg4_amstream_dec_info.rate == 0) {
+ if ((fixed_vop_rate != 0) &&
+ (time_increment_resolution != 0)) {
+ hw->vmpeg4_amstream_dec_info.rate = fixed_vop_rate *
+ DURATION_UNIT / time_increment_resolution;
+ } else if (time_increment_resolution == 0
+ && hw->sys_mp4_rate > 0)
+ time_increment_resolution = hw->sys_mp4_rate;
+ }
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL,
+ "time_inc_res = %d, fixed_vop_rate = %d, rate = %d\n",
+ time_increment_resolution, fixed_vop_rate,
+ hw->vmpeg4_amstream_dec_info.rate);
+
+ if (reg == 2) {
+ /* timeout when decoding next frame */
+
+ /* for frame based case, insufficient result may happen
+ * at the beginning when only VOL head is available save
+ * HW context also, such as for the QTable from VCOP register
+ */
+ mmpeg4_debug_print(DECODE_ID(hw),
+ PRINT_FLAG_VLD_DETAIL,
+ "%s, level = %x, vfifo_ctrl = %x, bitcnt = %d\n",
+ __func__,
+ READ_VREG(VLD_MEM_VIFIFO_LEVEL),
+ READ_VREG(VLD_MEM_VIFIFO_CONTROL),
+ READ_VREG(VIFF_BIT_CNT));
+
+ if (vdec_frame_based(vdec)) {
+ vmpeg4_save_hw_context(hw);
+ hw->dec_result = DEC_RESULT_DONE;
+ vdec_schedule_work(&hw->work);
+ } else {
+ reset_process_time(hw);
+ hw->dec_result = DEC_RESULT_AGAIN;
+ vdec_schedule_work(&hw->work);
+ }
+ return IRQ_HANDLED;
+ } else {
+ reset_process_time(hw);
+ picture_type = (reg >> 3) & 7;
+ repeat_cnt = READ_VREG(MP4_NOT_CODED_CNT);
+ vop_time_inc = READ_VREG(MP4_VOP_TIME_INC);
+ vos_info = READ_VREG(MP4_VOS_INFO);
+ if ((vos_info & 0xff) &&
+ (((vos_info >> 4) & 0xf) != hw->profile_idc ||
+ (vos_info & 0xf) != hw->level_idc)) {
+ hw->profile_idc = vos_info >> 4 & 0xf;
+ hw->level_idc = vos_info & 0xf;
+ vdec_set_profile_level(vdec, hw->profile_idc, hw->level_idc);
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL,
+ "profile_idc: %d level_idc: %d\n",
+ hw->profile_idc, hw->level_idc);
+ }
+
+ index = spec_to_index(hw, READ_VREG(REC_CANVAS_ADDR));
+ if (index < 0) {
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "invalid buffer index %d. rec = %x\n",
+ index, READ_VREG(REC_CANVAS_ADDR));
+ hw->dec_result = DEC_RESULT_ERROR;
+ vdec_schedule_work(&hw->work);
+ return IRQ_HANDLED;
+ }
+ hw->dec_result = DEC_RESULT_DONE;
+ dec_pic = &hw->pic[index];
+ if (vdec->mvfrm) {
+ dec_pic->frame_size = vdec->mvfrm->frame_size;
+ dec_pic->hw_decode_time =
+ local_clock() - vdec->mvfrm->hw_decode_start;
+ }
+ dec_pic->pts_valid = false;
+ dec_pic->pts = 0;
+ dec_pic->pts64 = 0;
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_BUFFER_DETAIL,
+ "new pic: index=%d, used=%d, repeat=%d, time_inc=%d\n",
+ index, hw->vfbuf_use[index], repeat_cnt, vop_time_inc);
+
+ dec_w = READ_VREG(MP4_PIC_WH)>> 16;
+ dec_h = READ_VREG(MP4_PIC_WH) & 0xffff;
+ if (dec_w != 0)
+ hw->frame_width = dec_w;
+ if (dec_h != 0)
+ hw->frame_height = dec_h;
+
+ if (hw->vmpeg4_amstream_dec_info.rate == 0) {
+ if (vop_time_inc < hw->last_vop_time_inc) {
+ duration = vop_time_inc +
+ time_increment_resolution -
+ hw->last_vop_time_inc;
+ } else {
+ duration = vop_time_inc -
+ hw->last_vop_time_inc;
+ }
+
+ if (duration == hw->last_duration) {
+ hw->rate_detect++;
+ if ((hw->rate_detect >= RATE_DETECT_COUNT) &&
+ (time_increment_resolution != 0)) {
+ hw->vmpeg4_amstream_dec_info.rate =
+ duration * DURATION_UNIT /
+ time_increment_resolution;
+ duration =
+ hw->vmpeg4_amstream_dec_info.rate;
+ }
+ } else {
+ hw->rate_detect = 0;
+ hw->last_duration = duration;
+ }
+ if (MPEG4_VALID_DUR(duration)) {
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEINFO,
+ "warn: duration %x, set 0\n", duration);
+ duration = 0;
+ }
+ } else {
+ duration = hw->vmpeg4_amstream_dec_info.rate;
+#if 0
+ pr_info("info rate = %d, ucode rate = 0x%x:0x%x\n",
+ hw->vmpeg4_amstream_dec_info.rate,
+ READ_VREG(MP4_RATE), vop_time_inc);
+#endif
+ }
+
+ /* frame mode with unstable pts */
+ if (hw->unstable_pts && hw->chunk) {
+ dec_pic->pts_valid = hw->chunk->pts_valid;
+ dec_pic->pts = hw->chunk->pts;
+ dec_pic->pts64 = hw->chunk->pts64;
+ if ((B_PICTURE == picture_type) ||
+ (hw->last_dec_pts == dec_pic->pts))
+ dec_pic->pts_valid = 0;
+
+ hw->last_dec_pts = dec_pic->pts;
+ } else if ((I_PICTURE == picture_type) ||
+ (P_PICTURE == picture_type)) {
+ offset = READ_VREG(MP4_OFFSET_REG);
+ if (hw->chunk) {
+ dec_pic->pts_valid = hw->chunk->pts_valid;
+ dec_pic->pts = hw->chunk->pts;
+ dec_pic->pts64 = hw->chunk->pts64;
+ } else {
+ dec_pic->offset = offset;
+ if ((vdec->vbuf.no_parser == 0) || (vdec->vbuf.use_ptsserv)) {
+ if (pts_lookup_offset_us64(PTS_TYPE_VIDEO, offset,
+ &pts, &frame_size, 3000, &pts_us64) == 0) {
+ dec_pic->pts_valid = true;
+ dec_pic->pts = pts;
+ dec_pic->pts64 = pts_us64;
+ hw->pts_hit++;
+ } else {
+ dec_pic->pts_valid = false;
+ hw->pts_missed++;
+ }
+ }
+ }
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEINFO,
+ "%c, offset=0x%x, pts=0x%x(%d), index=%d, used=%d\n",
+ GET_PIC_TYPE(picture_type), offset, dec_pic->pts,
+ dec_pic->pts_valid, index, hw->vfbuf_use[index]);
+ }
+
+ dec_pic->index = index;
+ dec_pic->pic_info = reg;
+ dec_pic->pic_type = picture_type;
+ dec_pic->duration = duration;
+ hw->vfbuf_use[index] = 0;
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW,
+ "mmpeg4: pic_num: %d, index %d, type %c, pts %x\n",
+ hw->frame_num, index,
+ GET_PIC_TYPE(picture_type),
+ dec_pic->pts);
+
+ /* buffer management */
+ if ((picture_type == I_PICTURE) ||
+ (picture_type == P_PICTURE)) {
+ index = update_ref(hw, index);
+ } else {
+ /* drop B frame or disp immediately.
+ * depend on if there are two ref frames
+ */
+ if (hw->refs[1] == -1)
+ index = -1;
+ }
+ vmpeg4_save_hw_context(hw);
+ if (index < 0) {
+ vdec_schedule_work(&hw->work);
+ return IRQ_HANDLED;
+ }
+ disp_pic = &hw->pic[index];
+ if ((hw->first_i_frame_ready == 0) &&
+ (I_PICTURE == disp_pic->pic_type))
+ hw->first_i_frame_ready = 1;
+
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW,
+ "disp: index=%d, pts=%x(%d), used=%d, picout=%c(dec=%c)\n",
+ index, disp_pic->pts, disp_pic->pts_valid,
+ hw->vfbuf_use[index],
+ GET_PIC_TYPE(disp_pic->pic_type),
+ GET_PIC_TYPE(picture_type));
+
+ if (disp_pic->pts_valid) {
+ hw->last_anch_pts = disp_pic->pts;
+ hw->last_anch_pts_us64 = disp_pic->pts64;
+ hw->frame_num_since_last_anch = 0;
+ hw->vop_time_inc_since_last_anch = 0;
+ } else if (vdec_stream_based(vdec)) {
+ disp_pic->pts = hw->last_anch_pts;
+ disp_pic->pts64 = hw->last_anch_pts_us64;
+
+ if ((time_increment_resolution != 0) &&
+ (fixed_vop_rate == 0) &&
+ (hw->vmpeg4_amstream_dec_info.rate == 0)) {
+ /* variable PTS rate */
+ /*bug on variable pts calc,
+ *do as dixed vop first if we
+ *have rate setting before.
+ */
+ if (vop_time_inc > hw->last_vop_time_inc) {
+ duration = vop_time_inc -
+ hw->last_vop_time_inc;
+ } else {
+ duration = vop_time_inc +
+ time_increment_resolution -
+ hw->last_vop_time_inc;
+ }
+
+ hw->vop_time_inc_since_last_anch += duration;
+
+ disp_pic->pts += hw->vop_time_inc_since_last_anch *
+ PTS_UNIT / time_increment_resolution;
+ disp_pic->pts64 += (hw->vop_time_inc_since_last_anch *
+ PTS_UNIT / time_increment_resolution) *
+ 100 / 9;
+
+ if (hw->vop_time_inc_since_last_anch >
+ (1 << 14)) {
+ /* avoid overflow */
+ hw->last_anch_pts = disp_pic->pts;
+ hw->last_anch_pts_us64 = disp_pic->pts64;
+ hw->vop_time_inc_since_last_anch = 0;
+ }
+ } else {
+ /* fixed VOP rate */
+ hw->frame_num_since_last_anch++;
+ disp_pic->pts += DUR2PTS(hw->frame_num_since_last_anch *
+ hw->vmpeg4_amstream_dec_info.rate);
+ disp_pic->pts64 += DUR2PTS(
+ hw->frame_num_since_last_anch *
+ hw->vmpeg4_amstream_dec_info.rate) * 100 / 9;
+
+ if (hw->frame_num_since_last_anch > (1 << 15)) {
+ /* avoid overflow */
+ hw->last_anch_pts = disp_pic->pts;
+ hw->last_anch_pts_us64 = disp_pic->pts64;
+ hw->frame_num_since_last_anch = 0;
+ }
+ }
+ } else if (hw->unstable_pts && hw->chunk &&
+ MPEG4_VALID_DUR(duration)) {
+ /* invalid pts calc */
+ hw->frame_num_since_last_anch = hw->chunk_frame_count;
+ disp_pic->pts = hw->last_anch_pts +
+ DUR2PTS(hw->frame_num_since_last_anch *
+ duration);
+ disp_pic->pts64 = hw->last_anch_pts_us64 +
+ DUR2PTS(hw->frame_num_since_last_anch *
+ duration) * 100 / 9;
+
+ if (hw->frame_num_since_last_anch > (1 << 15)) {
+ /* avoid overflow */
+ hw->last_anch_pts = disp_pic->pts;
+ hw->last_anch_pts_us64 = disp_pic->pts64;
+ hw->frame_num_since_last_anch = 0;
+ } else
+ disp_pic->pts_valid = 1;
+ }
+
+ if (vdec_frame_based(vdec) &&
+ (hw->unstable_pts) &&
+ MPEG4_VALID_DUR(duration)) {
+
+ u32 threshold = DUR2PTS(duration) >> 3;
+
+ if (disp_pic->pts <= (hw->last_pts + threshold)) {
+ disp_pic->pts = hw->last_pts + DUR2PTS(duration);
+ disp_pic->pts64 = hw->last_pts64 +
+ (DUR2PTS(duration)*100/9);
+ }
+ if (!disp_pic->pts_valid) {
+ disp_pic->pts = 0;
+ disp_pic->pts64 = 0;
+ }
+ }
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_TIMEINFO,
+ "disp: pic_type %c, pts %d(%lld), diff %d, cnt %d\n",
+ GET_PIC_TYPE(disp_pic->pic_type),
+ disp_pic->pts,
+ disp_pic->pts64,
+ disp_pic->pts - hw->last_pts,
+ hw->chunk_frame_count);
+ hw->last_pts = disp_pic->pts;
+ hw->last_pts64 = disp_pic->pts64;
+ hw->frame_dur = duration;
+ disp_pic->duration = duration;
+ disp_pic->repeat_cnt = repeat_cnt;
+
+ prepare_display_buf(hw, disp_pic);
+
+ hw->total_frame += repeat_cnt + 1;
+ hw->last_vop_time_inc = vop_time_inc;
+
+ if (vdec_frame_based(vdec) &&
+ (frmbase_cont_bitlevel != 0) &&
+ (hw->first_i_frame_ready)) {
+ u32 consume_byte, res_byte, bitcnt;
+
+ bitcnt = READ_VREG(VIFF_BIT_CNT);
+ res_byte = bitcnt >> 3;
+
+ if (hw->chunk_size > res_byte) {
+ if (bitcnt > frmbase_cont_bitlevel) {
+ consume_byte = hw->chunk_size - res_byte;
+
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW,
+ "%s, size %d, consume %d, res %d\n", __func__,
+ hw->chunk_size, consume_byte, res_byte);
+
+ if (consume_byte > VDEC_FIFO_ALIGN) {
+ consume_byte -= VDEC_FIFO_ALIGN;
+ res_byte += VDEC_FIFO_ALIGN;
+ }
+ hw->chunk_offset += consume_byte;
+ hw->chunk_size = res_byte;
+ hw->dec_result = DEC_RESULT_UNFINISH;
+ hw->chunk_frame_count++;
+ hw->unstable_pts = 1;
+ } else {
+ hw->chunk_size = 0;
+ hw->chunk_offset = 0;
+ }
+ } else {
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR,
+ "error: bitbyte %d hw->chunk_size %d\n", res_byte, hw->chunk_size);
+ hw->chunk_size = 0;
+ hw->chunk_offset = 0;
+ }
+ }
+ vdec_schedule_work(&hw->work);
+ }
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FRAME_NUM,
+ "%s: frame num:%d\n", __func__, hw->frame_num);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t vmpeg4_isr(struct vdec_s *vdec, int irq)
+{
+ struct vdec_mpeg4_hw_s *hw =
+ (struct vdec_mpeg4_hw_s *)(vdec->private);
+
+ if (hw->eos)
+ return IRQ_HANDLED;
+
+ return IRQ_WAKE_THREAD;
+}
+
+static void flush_output(struct vdec_mpeg4_hw_s * hw)
+{
+ struct pic_info_t *pic;
+
+ if (hw->vfbuf_use[hw->refs[1]] > 0) {
+ pic = &hw->pic[hw->refs[1]];
+ prepare_display_buf(hw, pic);
+ }
+}
+
+static int notify_v4l_eos(struct vdec_s *vdec)
+{
+ struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)vdec->private;
+ struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx);
+ struct vframe_s *vf = NULL;
+ struct vdec_v4l2_buffer *fb = NULL;
+ int index = -1;
+
+ if (hw->eos) {
+ if (kfifo_get(&hw->newframe_q, &vf) == 0 || vf == NULL) {
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR,
+ "%s fatal error, no available buffer slot.\n",
+ __func__);
+ return -1;
+ }
+
+ if (hw->is_used_v4l) {
+ index = find_free_buffer(hw);
+ if ((index == -1) &&
+ vdec_v4l_get_buffer(hw->v4l2_ctx, &fb)) {
+ pr_err("[%d] get fb fail.\n", ctx->id);
+ return -1;
+ }
+ }
+
+ vf->type |= VIDTYPE_V4L_EOS;
+ vf->timestamp = ULONG_MAX;
+ vf->v4l_mem_handle = (index == -1) ? (ulong)fb :
+ hw->pic[index].v4l_ref_buf_addr;;
+ vf->flag = VFRAME_FLAG_EMPTY_FRAME_V4L;
+
+ vdec_vframe_ready(vdec, vf);
+ kfifo_put(&hw->display_q, (const struct vframe_s *)vf);
+ ATRACE_COUNTER(hw->pts_name, vf->pts);
+ vf_notify_receiver(vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
+
+ pr_info("[%d] mpeg4 EOS notify.\n", (hw->is_used_v4l)?ctx->id:vdec->id);
+ }
+
+ return 0;
+}
+
+static void vmpeg4_work(struct work_struct *work)
+{
+ struct vdec_mpeg4_hw_s *hw =
+ container_of(work, struct vdec_mpeg4_hw_s, work);
+ struct vdec_s *vdec = hw_to_vdec(hw);
+
+ /* finished decoding one frame or error,
+ * notify vdec core to switch context
+ */
+ if (hw->dec_result != DEC_RESULT_DONE)
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW,
+ "vmpeg4_work: result=%d,status=%d\n",
+ hw->dec_result, hw_to_vdec(hw)->next_status);
+
+ if (hw->dec_result == DEC_RESULT_UNFINISH) {
+ if (!hw->ctx_valid)
+ hw->ctx_valid = 1;
+
+ } else if ((hw->dec_result == DEC_RESULT_DONE) ||
+ ((input_frame_based(&vdec->input)) && hw->chunk)) {
+ if (!hw->ctx_valid)
+ hw->ctx_valid = 1;
+
+ vdec_vframe_dirty(vdec, hw->chunk);
+ hw->chunk = NULL;
+ } else if (hw->dec_result == DEC_RESULT_AGAIN
+ && (vdec->next_status != VDEC_STATUS_DISCONNECTED)) {
+ /*
+ stream base: stream buf empty or timeout
+ frame base: vdec_prepare_input fail
+ */
+ if (!vdec_has_more_input(vdec)) {
+ hw->dec_result = DEC_RESULT_EOS;
+ vdec_schedule_work(&hw->work);
+ return;
+ }
+ } else if (hw->dec_result == DEC_RESULT_FORCE_EXIT) {
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR,
+ "%s: force exit\n", __func__);
+ if (hw->stat & STAT_ISR_REG) {
+ amvdec_stop();
+ vdec_free_irq(VDEC_IRQ_1, (void *)hw);
+ hw->stat &= ~STAT_ISR_REG;
+ }
+ } else if (hw->dec_result == DEC_RESULT_EOS) {
+ hw->eos = 1;
+ if (hw->stat & STAT_VDEC_RUN) {
+ amvdec_stop();
+ hw->stat &= ~STAT_VDEC_RUN;
+ }
+ vdec_vframe_dirty(vdec, hw->chunk);
+ hw->chunk = NULL;
+ vdec_clean_input(vdec);
+ flush_output(hw);
+ notify_v4l_eos(vdec);
+
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "%s: eos flushed, frame_num %d\n",
+ __func__, hw->frame_num);
+ }
+
+ if (hw->stat & STAT_VDEC_RUN) {
+ amvdec_stop();
+ hw->stat &= ~STAT_VDEC_RUN;
+ }
+ /*disable mbox interrupt */
+ WRITE_VREG(ASSIST_MBOX1_MASK, 0);
+ del_timer_sync(&hw->check_timer);
+ hw->stat &= ~STAT_TIMER_ARM;
+
+ 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);
+ }
+
+ /* mark itself has all HW resource released and input released */
+ if (vdec->parallel_dec == 1)
+ vdec_core_finish_run(vdec, CORE_MASK_VDEC_1);
+ else
+ vdec_core_finish_run(vdec, CORE_MASK_VDEC_1 | CORE_MASK_HEVC);
+
+ wake_up_interruptible(&hw->wait_q);
+ if (hw->vdec_cb)
+ hw->vdec_cb(vdec, hw->vdec_cb_arg);
+}
+
+static struct vframe_s *vmpeg_vf_peek(void *op_arg)
+{
+ struct vframe_s *vf;
+ struct vdec_s *vdec = op_arg;
+ struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)vdec->private;
+
+ if (!hw)
+ return NULL;
+ hw->peek_num++;
+ if (kfifo_peek(&hw->display_q, &vf))
+ return vf;
+
+ return NULL;
+}
+
+static struct vframe_s *vmpeg_vf_get(void *op_arg)
+{
+ struct vframe_s *vf;
+ struct vdec_s *vdec = op_arg;
+ struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)vdec->private;
+ hw->get_num++;
+ if (kfifo_get(&hw->display_q, &vf)) {
+ ATRACE_COUNTER(hw->disp_q_name, kfifo_len(&hw->display_q));
+ return vf;
+ }
+ return NULL;
+}
+
+static void vmpeg_vf_put(struct vframe_s *vf, void *op_arg)
+{
+ struct vdec_s *vdec = op_arg;
+ struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)vdec->private;
+ unsigned long flags;
+
+ if (!vf)
+ return;
+
+ hw->vfbuf_use[vf->index]--;
+ hw->put_num++;
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FRAME_NUM,
+ "%s: put num:%d\n",__func__, hw->put_num);
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_BUFFER_DETAIL,
+ "index=%d, used=%d\n", vf->index, hw->vfbuf_use[vf->index]);
+ spin_lock_irqsave(&hw->lock, flags);
+ kfifo_put(&hw->newframe_q, (const struct vframe_s *)vf);
+ spin_unlock_irqrestore(&hw->lock, flags);
+ ATRACE_COUNTER(hw->new_q_name, kfifo_len(&hw->newframe_q));
+}
+
+static int vmpeg_event_cb(int type, void *data, void *op_arg)
+{
+ struct vdec_s *vdec = op_arg;
+
+ 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 int vmpeg_vf_states(struct vframe_states *states, void *op_arg)
+{
+ unsigned long flags;
+ struct vdec_s *vdec = op_arg;
+ struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_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);
+ states->buf_recycle_num = 0;
+
+ spin_unlock_irqrestore(&hw->lock, flags);
+
+ return 0;
+}
+
+
+static int dec_status(struct vdec_s *vdec, struct vdec_info *vstatus)
+{
+ struct vdec_mpeg4_hw_s *hw =
+ (struct vdec_mpeg4_hw_s *)vdec->private;
+
+ if (!hw)
+ return -1;
+
+ vstatus->frame_width = hw->frame_width;
+ vstatus->frame_height = hw->frame_height;
+ if (0 != hw->vmpeg4_amstream_dec_info.rate)
+ vstatus->frame_rate = ((DURATION_UNIT * 10 / hw->vmpeg4_amstream_dec_info.rate) % 10) < 5 ?
+ DURATION_UNIT / hw->vmpeg4_amstream_dec_info.rate : (DURATION_UNIT / hw->vmpeg4_amstream_dec_info.rate +1);
+ else
+ vstatus->frame_rate = -1;
+ vstatus->error_count = READ_VREG(MP4_ERR_COUNT);
+ vstatus->status = hw->stat;
+ vstatus->frame_dur = hw->frame_dur;
+ vstatus->error_frame_count = READ_VREG(MP4_ERR_COUNT);
+ vstatus->drop_frame_count = hw->drop_frame_count;
+ vstatus->frame_count =hw->frame_num;
+ vstatus->i_decoded_frames = hw->i_decoded_frames;
+ vstatus->i_lost_frames = hw->i_lost_frames;
+ vstatus->i_concealed_frames = hw->i_concealed_frames;
+ vstatus->p_decoded_frames = hw->p_decoded_frames;
+ vstatus->p_lost_frames = hw->p_lost_frames;
+ vstatus->p_concealed_frames = hw->p_concealed_frames;
+ vstatus->b_decoded_frames = hw->b_decoded_frames;
+ vstatus->b_lost_frames = hw->b_lost_frames;
+ vstatus->b_concealed_frames = hw->b_concealed_frames;
+ snprintf(vstatus->vdec_name, sizeof(vstatus->vdec_name),
+ "%s", DRIVER_NAME);
+
+ return 0;
+}
+
+/****************************************/
+static int vmpeg4_canvas_init(struct vdec_mpeg4_hw_s *hw)
+{
+ int i, ret;
+ u32 canvas_width, canvas_height;
+ u32 decbuf_size, decbuf_y_size;
+ struct vdec_s *vdec = hw_to_vdec(hw);
+ unsigned long decbuf_start;
+
+ if (buf_size <= 0x00400000) {
+ /* SD only */
+ canvas_width = 768;
+ canvas_height = 576;
+ decbuf_y_size = 0x80000;
+ decbuf_size = 0x100000;
+ } else {
+ int w = 1920;
+ int h = 1088;
+ int align_w, align_h;
+ int max, min;
+
+ align_w = ALIGN(w, 64);
+ align_h = ALIGN(h, 64);
+ if (align_w > align_h) {
+ max = align_w;
+ min = align_h;
+ } else {
+ max = align_h;
+ min = align_w;
+ }
+ /* HD & SD */
+ if ((max > 1920 || min > 1088) &&
+ ALIGN(align_w * align_h * 3/2, SZ_64K) * 9 <=
+ buf_size) {
+ canvas_width = align_w;
+ canvas_height = align_h;
+ decbuf_y_size =
+ ALIGN(align_w * align_h, SZ_64K);
+ decbuf_size =
+ ALIGN(align_w * align_h * 3/2, SZ_64K);
+ } else { /*1080p*/
+ canvas_width = 1920;
+ canvas_height = 1088;
+ if (hw->vmpeg4_amstream_dec_info.width < hw->vmpeg4_amstream_dec_info.height ) {
+ canvas_width = 1088;
+ canvas_height = 1920;
+ }
+ decbuf_y_size = 0x200000;
+ decbuf_size = 0x300000;
+ }
+ }
+
+ for (i = 0; i < hw->buf_num + 1; i++) {
+
+ unsigned canvas;
+
+ if (i == hw->buf_num)
+ decbuf_size = WORKSPACE_SIZE;
+
+ if (hw->is_used_v4l && !(i == hw->buf_num)) {
+ continue;
+ } else {
+ ret = decoder_bmmu_box_alloc_buf_phy(hw->mm_blk_handle, i,
+ decbuf_size, DRIVER_NAME, &decbuf_start);
+ if (ret < 0) {
+ pr_err("mmu alloc failed! size %d idx %d\n",
+ decbuf_size, i);
+ return ret;
+ }
+ }
+
+ if (i == hw->buf_num) {
+ hw->buf_start = decbuf_start;
+ } else {
+ if (vdec->parallel_dec == 1) {
+ unsigned tmp;
+ 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;
+ }
+ 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;
+ }
+ canvas = hw->canvas_spec[i];
+ } else {
+ canvas = vdec->get_canvas(i, 2);
+ hw->canvas_spec[i] = canvas;
+ }
+
+ hw->canvas_config[i][0].phy_addr = decbuf_start;
+ hw->canvas_config[i][0].width = canvas_width;
+ hw->canvas_config[i][0].height = canvas_height;
+ hw->canvas_config[i][0].block_mode = hw->blkmode;
+ if (hw->blkmode == CANVAS_BLKMODE_LINEAR)
+ hw->canvas_config[i][0].endian = 7;
+ else
+ hw->canvas_config[i][0].endian = 0;
+ canvas_config_config(canvas_y(canvas),
+ &hw->canvas_config[i][0]);
+
+ hw->canvas_config[i][1].phy_addr =
+ decbuf_start + decbuf_y_size;
+ hw->canvas_config[i][1].width = canvas_width;
+ hw->canvas_config[i][1].height = (canvas_height >> 1);
+ hw->canvas_config[i][1].block_mode = hw->blkmode;
+ if (hw->blkmode == CANVAS_BLKMODE_LINEAR)
+ hw->canvas_config[i][1].endian = 7;
+ else
+ hw->canvas_config[i][1].endian = 0;
+ canvas_config_config(canvas_u(canvas),
+ &hw->canvas_config[i][1]);
+ }
+ }
+
+ return 0;
+}
+
+static void vmpeg4_dump_state(struct vdec_s *vdec)
+{
+ struct vdec_mpeg4_hw_s *hw =
+ (struct vdec_mpeg4_hw_s *)(vdec->private);
+ u32 i;
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "====== %s\n", __func__);
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "width/height (%d/%d), i_fram:%d, buffer_not_ready %d, buf_num %d\n",
+ hw->frame_width,
+ hw->frame_height,
+ hw->first_i_frame_ready,
+ hw->buffer_not_ready,
+ hw->buf_num
+ );
+ for (i = 0; i < hw->buf_num; i++) {
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "index %d, used %d\n", i, hw->vfbuf_use[i]);
+ }
+
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "is_framebase(%d), eos %d, state 0x%x, dec_result 0x%x dec_frm %d\n",
+ vdec_frame_based(vdec),
+ hw->eos,
+ hw->stat,
+ hw->dec_result,
+ hw->frame_num
+ );
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "is_framebase(%d), put_frm %d run %d not_run_ready %d input_empty %d,drop %d\n",
+ vdec_frame_based(vdec),
+ hw->put_num,
+ hw->run_count,
+ hw->not_run_ready,
+ hw->input_empty,
+ hw->drop_frame_count
+ );
+
+ 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);
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "\nreceiver(%s) state %d\n",
+ vdec->vf_provider_name,
+ state);
+ }
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "%s, newq(%d/%d), dispq(%d/%d) vf peek/get/put (%d/%d/%d)\n",
+ __func__,
+ kfifo_len(&hw->newframe_q), VF_POOL_SIZE,
+ kfifo_len(&hw->display_q), VF_POOL_SIZE,
+ hw->peek_num, hw->get_num, hw->put_num
+ );
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "VIFF_BIT_CNT=0x%x\n",
+ READ_VREG(VIFF_BIT_CNT));
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "VLD_MEM_VIFIFO_LEVEL=0x%x\n",
+ READ_VREG(VLD_MEM_VIFIFO_LEVEL));
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "VLD_MEM_VIFIFO_WP=0x%x\n",
+ READ_VREG(VLD_MEM_VIFIFO_WP));
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "VLD_MEM_VIFIFO_RP=0x%x\n",
+ READ_VREG(VLD_MEM_VIFIFO_RP));
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "PARSER_VIDEO_RP=0x%x\n",
+ STBUF_READ(&vdec->vbuf, get_rp));
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "PARSER_VIDEO_WP=0x%x\n",
+ STBUF_READ(&vdec->vbuf, get_wp));
+
+ if (vdec_frame_based(vdec) &&
+ debug_enable & 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;
+
+ mmpeg4_debug_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)
+ mmpeg4_debug_print(DECODE_ID(hw),
+ PRINT_FRAMEBASE_DATA,
+ "%06x:", jj);
+ mmpeg4_debug_print(DECODE_ID(hw),
+ PRINT_FRAMEBASE_DATA,
+ "%02x ", data[jj]);
+ if (((jj + 1) & 0xf) == 0)
+ mmpeg4_debug_print(DECODE_ID(hw),
+ PRINT_FRAMEBASE_DATA,
+ "\n");
+ }
+
+ if (!hw->chunk->block->is_mapped)
+ codec_mm_unmap_phyaddr(data);
+ }
+ }
+}
+
+static void reset_process_time(struct vdec_mpeg4_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_mpeg4_hw_s *hw)
+{
+ hw->decode_timeout_count = 2;
+ hw->start_process_time = jiffies;
+}
+
+static void timeout_process(struct vdec_mpeg4_hw_s *hw)
+{
+ if (hw->stat & STAT_VDEC_RUN) {
+ amvdec_stop();
+ hw->stat &= ~STAT_VDEC_RUN;
+ }
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "%s decoder timeout %d\n", __func__, hw->timeout_cnt);
+ if (vdec_frame_based((hw_to_vdec(hw)))) {
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "%s frame_num %d, chunk size 0x%x, chksum 0x%x\n",
+ __func__,
+ hw->frame_num,
+ hw->chunk->size,
+ get_data_check_sum(hw, hw->chunk->size));
+ }
+ hw->timeout_cnt++;
+ /* timeout: data droped, frame_num inaccurate*/
+ hw->frame_num++;
+ reset_process_time(hw);
+ hw->first_i_frame_ready = 0;
+ hw->dec_result = DEC_RESULT_DONE;
+ vdec_schedule_work(&hw->work);
+}
+
+
+static void check_timer_func(unsigned long arg)
+{
+ struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)arg;
+ struct vdec_s *vdec = hw_to_vdec(hw);
+ unsigned int timeout_val = decode_timeout_val;
+
+ 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 (((debug_enable & PRINT_FLAG_TIMEOUT_STATUS) == 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 (vdec->next_status == VDEC_STATUS_DISCONNECTED) {
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR,
+ "vdec requested to be disconnected\n");
+ hw->dec_result = DEC_RESULT_FORCE_EXIT;
+ vdec_schedule_work(&hw->work);
+ return;
+ }
+
+ mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL);
+}
+
+static int vmpeg4_hw_ctx_restore(struct vdec_mpeg4_hw_s *hw)
+{
+ int index, i;
+ void *workspace_buf = NULL;
+
+ index = find_free_buffer(hw);
+ if (index < 0)
+ return -1;
+
+ if (!hw->init_flag) {
+ if (vmpeg4_canvas_init(hw) < 0)
+ return -1;
+ } else {
+ if (!hw->is_used_v4l) {
+ for (i = 0; i < hw->buf_num; i++) {
+ canvas_config_config(canvas_y(hw->canvas_spec[i]),
+ &hw->canvas_config[i][0]);
+ canvas_config_config(canvas_u(hw->canvas_spec[i]),
+ &hw->canvas_config[i][1]);
+ }
+ }
+ }
+ /* prepare REF0 & REF1
+ * points to the past two IP buffers
+ * prepare REC_CANVAS_ADDR and ANC2_CANVAS_ADDR
+ * points to the output buffer
+ */
+ if (hw->refs[0] == -1) {
+ WRITE_VREG(MREG_REF0, (hw->refs[1] == -1) ? 0xffffffff :
+ hw->canvas_spec[hw->refs[1]]);
+ } else {
+ WRITE_VREG(MREG_REF0, (hw->refs[0] == -1) ? 0xffffffff :
+ hw->canvas_spec[hw->refs[0]]);
+ }
+ WRITE_VREG(MREG_REF1, (hw->refs[1] == -1) ? 0xffffffff :
+ hw->canvas_spec[hw->refs[1]]);
+
+ WRITE_VREG(REC_CANVAS_ADDR, hw->canvas_spec[index]);
+ WRITE_VREG(ANC2_CANVAS_ADDR, hw->canvas_spec[index]);
+
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_RESTORE,
+ "restore ref0=0x%x, ref1=0x%x, rec=0x%x, ctx_valid=%d,index=%d\n",
+ READ_VREG(MREG_REF0),
+ READ_VREG(MREG_REF1),
+ READ_VREG(REC_CANVAS_ADDR),
+ hw->ctx_valid, index);
+
+ /* notify ucode the buffer start address */
+ workspace_buf = codec_mm_vmap(hw->buf_start, WORKSPACE_SIZE);
+ if (workspace_buf) {
+ /* clear to fix decoder timeout at first time */
+ if (!hw->init_flag)
+ memset(workspace_buf, 0, WORKSPACE_SIZE);
+ codec_mm_dma_flush(workspace_buf,
+ WORKSPACE_SIZE, DMA_TO_DEVICE);
+ codec_mm_unmap_phyaddr(workspace_buf);
+ }
+ WRITE_VREG(MEM_OFFSET_REG, hw->buf_start);
+
+ /* disable PSCALE for hardware sharing */
+ WRITE_VREG(PSCALE_CTRL, 0);
+
+ WRITE_VREG(MREG_BUFFEROUT, 0x10000);
+
+ /* clear mailbox interrupt */
+ WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
+
+ /* enable mailbox interrupt */
+ WRITE_VREG(ASSIST_MBOX1_MASK, 1);
+
+ /* clear repeat count */
+ WRITE_VREG(MP4_NOT_CODED_CNT, 0);
+
+#ifdef NV21
+ SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17);
+#endif
+
+#if 1/* /MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
+ WRITE_VREG(MDEC_PIC_DC_THRESH, 0x404038aa);
+#endif
+
+ WRITE_VREG(MP4_PIC_WH, (hw->ctx_valid) ?
+ hw->reg_mp4_pic_wh :
+ ((hw->frame_width << 16) | hw->frame_height));
+ WRITE_VREG(MP4_SYS_RATE, hw->vmpeg4_amstream_dec_info.rate);
+
+ if (hw->ctx_valid) {
+ WRITE_VREG(DC_AC_CTRL, hw->reg_dc_ac_ctrl);
+ WRITE_VREG(IQIDCT_CONTROL, hw->reg_iqidct_control);
+ WRITE_VREG(RESYNC_MARKER_LENGTH, hw->reg_resync_marker_length);
+ WRITE_VREG(RV_AI_MB_COUNT, hw->reg_rv_ai_mb_count);
+ }
+ WRITE_VREG(MPEG1_2_REG, (hw->ctx_valid) ? hw->reg_mpeg1_2_reg : 1);
+ WRITE_VREG(VCOP_CTRL_REG, hw->reg_vcop_ctrl_reg);
+ WRITE_VREG(PIC_HEAD_INFO, hw->reg_pic_head_info);
+ WRITE_VREG(SLICE_QP, hw->reg_slice_qp);
+ WRITE_VREG(MB_INFO, hw->reg_mb_info);
+
+ if (vdec_frame_based(hw_to_vdec(hw)) && hw->chunk) {
+ /* frame based input */
+ WRITE_VREG(MREG_INPUT, (hw->chunk->offset & 7) | (1<<7) |
+ (hw->ctx_valid<<6));
+ } else {
+ /* stream based input */
+ WRITE_VREG(MREG_INPUT, (hw->ctx_valid<<6));
+ }
+
+ return 0;
+}
+
+static void vmpeg4_local_init(struct vdec_mpeg4_hw_s *hw)
+{
+ int i;
+
+ hw->vmpeg4_ratio = hw->vmpeg4_amstream_dec_info.ratio;
+
+ hw->vmpeg4_ratio64 = hw->vmpeg4_amstream_dec_info.ratio64;
+
+ hw->vmpeg4_rotation =
+ (((unsigned long)hw->vmpeg4_amstream_dec_info.param) >> 16) & 0xffff;
+ hw->sys_mp4_rate = hw->vmpeg4_amstream_dec_info.rate;
+ if (hw->is_used_v4l) {
+ hw->frame_width = 0;
+ hw->frame_height = 0;
+ } else {
+ hw->frame_width = hw->vmpeg4_amstream_dec_info.width;
+ hw->frame_height = hw->vmpeg4_amstream_dec_info.height;
+ }
+
+ hw->frame_dur = 0;
+ hw->frame_prog = 0;
+ hw->unstable_pts =
+ (((unsigned long) hw->vmpeg4_amstream_dec_info.param & 0x40) >> 6);
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "param = 0x%px unstable_pts = %d\n",
+ hw->vmpeg4_amstream_dec_info.param,
+ hw->unstable_pts);
+ hw->last_dec_pts = -1;
+
+ hw->total_frame = 0;
+
+ hw->last_anch_pts = 0;
+
+ hw->last_anch_pts_us64 = 0;
+
+ hw->last_vop_time_inc = hw->last_duration = 0;
+
+ hw->vop_time_inc_since_last_anch = 0;
+ hw->last_pts = 0;
+ hw->last_pts64 = 0;
+ hw->frame_num_since_last_anch = 0;
+ hw->frame_num = 0;
+ hw->put_num = 0;
+ hw->run_count = 0;
+ hw->not_run_ready = 0;
+ hw->input_empty = 0;
+ hw->peek_num = 0;
+ hw->get_num = 0;
+
+ hw->pts_hit = hw->pts_missed = hw->pts_i_hit = hw->pts_i_missed = 0;
+ hw->refs[0] = -1;
+ hw->refs[1] = -1;
+ hw->first_i_frame_ready = 0;
+ hw->drop_frame_count = 0;
+ hw->buffer_not_ready = 0;
+ hw->init_flag = 0;
+ hw->dec_result = DEC_RESULT_NONE;
+ hw->timeout_cnt = 0;
+
+ for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++)
+ hw->vfbuf_use[i] = 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[i];
+
+ hw->vfpool[i].index = DECODE_BUFFER_NUM_MAX;
+ kfifo_put(&hw->newframe_q, (const struct vframe_s *)vf);
+ }
+ if (hw->mm_blk_handle) {
+ 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);
+ INIT_WORK(&hw->work, vmpeg4_work);
+
+ init_waitqueue_head(&hw->wait_q);
+}
+
+static s32 vmmpeg4_init(struct vdec_mpeg4_hw_s *hw)
+{
+ int trickmode_fffb = 0;
+ int size = -1, fw_size = 0x1000 * 16;
+ struct firmware_s *fw = NULL;
+
+ fw = vmalloc(sizeof(struct firmware_s) + fw_size);
+ if (IS_ERR_OR_NULL(fw))
+ return -ENOMEM;
+
+ if (hw->vmpeg4_amstream_dec_info.format ==
+ VIDEO_DEC_FORMAT_MPEG4_5) {
+ size = get_firmware_data(VIDEO_DEC_MPEG4_5_MULTI, fw->data);
+ strncpy(fw->name, "mmpeg4_mc_5", sizeof(fw->name));
+ } else if (hw->vmpeg4_amstream_dec_info.format ==
+ VIDEO_DEC_FORMAT_H263) {
+ size = get_firmware_data(VIDEO_DEC_H263_MULTI, fw->data);
+ strncpy(fw->name, "mh263_mc", sizeof(fw->name));
+ } else
+ pr_err("unsupport mpeg4 sub format %d\n",
+ hw->vmpeg4_amstream_dec_info.format);
+ pr_info("mmpeg4 get fw %s, size %x\n", fw->name, size);
+ if (size < 0) {
+ pr_err("get firmware failed.");
+ vfree(fw);
+ return -1;
+ }
+
+ fw->len = size;
+ hw->fw = fw;
+
+ query_video_status(0, &trickmode_fffb);
+
+ pr_info("%s\n", __func__);
+
+ //amvdec_enable();
+
+ init_timer(&hw->check_timer);
+ hw->check_timer.data = (unsigned long)hw;
+ hw->check_timer.function = check_timer_func;
+ hw->check_timer.expires = jiffies + CHECK_INTERVAL;
+ hw->stat |= STAT_TIMER_ARM;
+ hw->eos = 0;
+ WRITE_VREG(DECODE_STOP_POS, udebug_flag);
+
+ vmpeg4_local_init(hw);
+ wmb();
+
+ return 0;
+}
+
+static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask)
+{
+ struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)vdec->private;
+
+ if (hw->eos)
+ return 0;
+ if (vdec_stream_based(vdec) && (hw->init_flag == 0)
+ && 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->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->v4l_codec_dpb_ready &&
+ v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) <
+ run_ready_min_buf_num)
+ return 0;
+ } else {
+ if (ctx->v4l_resolution_change)
+ return 0;
+ }
+ } else if (!ctx->v4l_codec_dpb_ready) {
+ if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) <
+ run_ready_min_buf_num)
+ return 0;
+ }
+ }
+
+ if (!is_enough_free_buffer(hw)) {
+ hw->buffer_not_ready++;
+ return 0;
+ }
+
+ hw->not_run_ready = 0;
+ hw->buffer_not_ready = 0;
+ if (vdec->parallel_dec == 1)
+ return (unsigned long)(CORE_MASK_VDEC_1);
+ else
+ return (unsigned long)(CORE_MASK_VDEC_1 | CORE_MASK_HEVC);
+}
+
+static unsigned char get_data_check_sum
+ (struct vdec_mpeg4_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_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)vdec->private;
+ int size = 0, ret = 0;
+ if (!hw->vdec_pg_enable_flag) {
+ hw->vdec_pg_enable_flag = 1;
+ amvdec_enable();
+ }
+ hw->run_count++;
+ hw->vdec_cb_arg = arg;
+ hw->vdec_cb = callback;
+ vdec_reset_core(vdec);
+
+ if ((vdec_frame_based(vdec)) &&
+ (hw->dec_result == DEC_RESULT_UNFINISH)) {
+ vmpeg4_prepare_input(hw);
+ size = hw->chunk_size;
+ } else {
+ size = vdec_prepare_input(vdec, &hw->chunk);
+ if (size < 4) { /*less than start code size 00 00 01 xx*/
+ hw->input_empty++;
+ hw->dec_result = DEC_RESULT_AGAIN;
+ vdec_schedule_work(&hw->work);
+ return;
+ }
+ if ((vdec_frame_based(vdec)) &&
+ (hw->chunk != NULL)) {
+ hw->chunk_offset = hw->chunk->offset;
+ hw->chunk_size = hw->chunk->size;
+ hw->chunk_frame_count = 0;
+ }
+ }
+ if (vdec_frame_based(vdec) && !vdec_secure(vdec)) {
+ /* HW needs padding (NAL start) for frame ending */
+ char* tail = (char *)hw->chunk->block->start_virt;
+
+ tail += hw->chunk->offset + hw->chunk->size;
+ tail[0] = 0;
+ tail[1] = 0;
+ tail[2] = 1;
+ tail[3] = 0xb6;
+ codec_mm_dma_flush(tail, 4, DMA_TO_DEVICE);
+ }
+ if (vdec_frame_based(vdec) &&
+ (debug_enable & 0xc00)) {
+ 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;
+
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS,
+ "%s: size 0x%x sum 0x%x %02x %02x %02x %02x %02x %02x .. %02x %02x %02x %02x\n",
+ __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 (debug_enable & PRINT_FRAMEBASE_DATA) {
+ int jj;
+
+ for (jj = 0; jj < size; jj++) {
+ if ((jj & 0xf) == 0)
+ mmpeg4_debug_print(DECODE_ID(hw),
+ PRINT_FRAMEBASE_DATA,
+ "%06x:", jj);
+ mmpeg4_debug_print(DECODE_ID(hw),
+ PRINT_FRAMEBASE_DATA,
+ "%02x ", data[jj]);
+ if (((jj + 1) & 0xf) == 0)
+ mmpeg4_debug_print(DECODE_ID(hw),
+ PRINT_FRAMEBASE_DATA,
+ "\n");
+ }
+ }
+
+ if (!hw->chunk->block->is_mapped)
+ codec_mm_unmap_phyaddr(data);
+ }
+
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW,
+ "%s, size=%d, %x %x %x %x %x\n",
+ __func__, size,
+ 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));
+
+ hw->dec_result = DEC_RESULT_NONE;
+ if (vdec->mc_loaded) {
+ /*firmware have load before,
+ and not changes to another.
+ ignore reload.
+ */
+ } else {
+ ret = amvdec_vdec_loadmc_buf_ex(VFORMAT_MPEG4,hw->fw->name, 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_MPEG4;
+ }
+ if (vmpeg4_hw_ctx_restore(hw) < 0) {
+ hw->dec_result = DEC_RESULT_ERROR;
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "amvdec_mpeg4: error HW context restore\n");
+ vdec_schedule_work(&hw->work);
+ return;
+ }
+ if (vdec_frame_based(vdec)) {
+ size = hw->chunk_size +
+ (hw->chunk_offset & (VDEC_FIFO_ALIGN - 1));
+ WRITE_VREG(VIFF_BIT_CNT, size * 8);
+ if (vdec->mvfrm)
+ vdec->mvfrm->frame_size = hw->chunk->size;
+ }
+ hw->input_empty = 0;
+ hw->last_vld_level = 0;
+ start_process_time(hw);
+ vdec_enable_input(vdec);
+ /* wmb before ISR is handled */
+ wmb();
+
+ if (vdec->mvfrm)
+ vdec->mvfrm->hw_decode_start = local_clock();
+ amvdec_start();
+ hw->stat |= STAT_VDEC_RUN;
+ hw->init_flag = 1;
+ mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL);
+}
+
+static int vmpeg4_stop(struct vdec_mpeg4_hw_s *hw)
+{
+ cancel_work_sync(&hw->work);
+
+ if (hw->mm_blk_handle) {
+ decoder_bmmu_box_free(hw->mm_blk_handle);
+ hw->mm_blk_handle = NULL;
+ }
+
+ if (hw->stat & STAT_TIMER_ARM) {
+ del_timer_sync(&hw->check_timer);
+ hw->stat &= ~STAT_TIMER_ARM;
+ }
+
+ if (hw->fw) {
+ vfree(hw->fw);
+ hw->fw = NULL;
+ }
+ return 0;
+}
+static void reset(struct vdec_s *vdec)
+{
+ struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)vdec->private;
+
+ pr_info("amvdec_mmpeg4: reset.\n");
+
+ vmpeg4_local_init(hw);
+
+ hw->ctx_valid = 0;
+}
+
+static int vmpeg4_set_trickmode(struct vdec_s *vdec, unsigned long trickmode)
+{
+ struct vdec_mpeg4_hw_s *hw =
+ (struct vdec_mpeg4_hw_s *)vdec->private;
+ if (!hw)
+ return 0;
+
+ if (trickmode == TRICKMODE_I) {
+ hw->i_only = 0x3;
+ trickmode_i = 1;
+ } else if (trickmode == TRICKMODE_NONE) {
+ hw->i_only = 0x0;
+ trickmode_i = 0;
+ }
+ return 0;
+}
+
+static int ammvdec_mpeg4_probe(struct platform_device *pdev)
+{
+ struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
+ struct vdec_mpeg4_hw_s *hw = NULL;
+ int config_val = 0;
+
+ if (pdata == NULL) {
+ pr_err("%s memory resource undefined.\n", __func__);
+ return -EFAULT;
+ }
+
+ hw = vmalloc(sizeof(struct vdec_mpeg4_hw_s));
+ if (hw == NULL) {
+ pr_err("\namvdec_mpeg4 decoder driver alloc failed\n");
+ return -ENOMEM;
+ }
+ memset(hw, 0, sizeof(struct vdec_mpeg4_hw_s));
+
+ /* the ctx from v4l2 driver. */
+ hw->v4l2_ctx = pdata->private;
+
+ pdata->private = hw;
+ pdata->dec_status = dec_status;
+ /* pdata->set_trickmode = set_trickmode; */
+ pdata->set_trickmode = vmpeg4_set_trickmode;
+ pdata->run_ready = run_ready;
+ pdata->run = run;
+ pdata->reset = reset;
+ pdata->irq_handler = vmpeg4_isr;
+ pdata->threaded_irq_handler = vmpeg4_isr_thread_fn;
+ pdata->dump_state = vmpeg4_dump_state;
+
+ snprintf(hw->vdec_name, sizeof(hw->vdec_name),
+ "mpeg4-%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);
+
+ if (pdata->use_vfm_path)
+ snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE,
+ VFM_DEC_PROVIDER_NAME);
+ else
+ snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE,
+ PROVIDER_NAME ".%02x", pdev->id & 0xff);
+
+ platform_set_drvdata(pdev, pdata);
+ hw->platform_dev = pdev;
+
+ if (pdata->parallel_dec == 1) {
+ int i;
+ for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++)
+ hw->canvas_spec[i] = 0xffffff;
+ }
+
+ vf_provider_init(&pdata->vframe_provider,
+ pdata->vf_provider_name, &vf_provider_ops, pdata);
+
+ hw->blkmode = pdata->canvas_mode;
+
+ if (pdata->sys_info) {
+ hw->vmpeg4_amstream_dec_info = *pdata->sys_info;
+ if ((hw->vmpeg4_amstream_dec_info.height != 0) &&
+ (hw->vmpeg4_amstream_dec_info.width >
+ (MAX_MPEG4_SUPPORT_SIZE/hw->vmpeg4_amstream_dec_info.height))) {
+ pr_info("ammvdec_mpeg4: oversize, unsupport: %d*%d\n",
+ hw->vmpeg4_amstream_dec_info.width,
+ hw->vmpeg4_amstream_dec_info.height);
+ pdata->dec_status = NULL;
+ vfree((void *)hw);
+ hw = NULL;
+ return -EFAULT;
+ }
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "sysinfo: %d x %d, rate: %d\n",
+ hw->vmpeg4_amstream_dec_info.width,
+ hw->vmpeg4_amstream_dec_info.height,
+ hw->vmpeg4_amstream_dec_info.rate);
+ }
+
+ if (((debug_enable & IGNORE_PARAM_FROM_CONFIG) == 0) && pdata->config_len) {
+ mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW,
+ "pdata->config: %s\n", pdata->config);
+ if (get_config_int(pdata->config, "parm_v4l_buffer_margin",
+ &config_val) == 0)
+ hw->dynamic_buf_num_margin = config_val;
+ else
+ hw->dynamic_buf_num_margin = dynamic_buf_num_margin;
+
+ 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_v4l_codec_enable",
+ &config_val) == 0)
+ hw->is_used_v4l = config_val;
+
+ if (get_config_int(pdata->config,
+ "parm_v4l_canvas_mem_mode",
+ &config_val) == 0)
+ hw->blkmode = config_val;
+ } else
+ hw->dynamic_buf_num_margin = dynamic_buf_num_margin;
+
+ hw->buf_num = vmpeg4_get_buf_num(hw);
+
+ if (vmmpeg4_init(hw) < 0) {
+ pr_err("%s init failed.\n", __func__);
+
+ if (hw) {
+ vfree((void *)hw);
+ hw = NULL;
+ }
+ pdata->dec_status = NULL;
+ return -ENODEV;
+ }
+ 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);
+ }
+
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "%s end.\n", __func__);
+ return 0;
+}
+
+static int ammvdec_mpeg4_remove(struct platform_device *pdev)
+{
+ struct vdec_mpeg4_hw_s *hw =
+ (struct vdec_mpeg4_hw_s *)
+ (((struct vdec_s *)(platform_get_drvdata(pdev)))->private);
+ struct vdec_s *vdec = hw_to_vdec(hw);
+ int i;
+
+ if (vdec->next_status == VDEC_STATUS_DISCONNECTED
+ && (vdec->status == VDEC_STATUS_ACTIVE)) {
+ mmpeg4_debug_print(DECODE_ID(hw), 0,
+ "%s force exit %d\n", __func__, __LINE__);
+ hw->dec_result = DEC_RESULT_FORCE_EXIT;
+ vdec_schedule_work(&hw->work);
+ wait_event_interruptible_timeout(hw->wait_q,
+ (vdec->status == VDEC_STATUS_CONNECTED),
+ msecs_to_jiffies(1000)); /* wait for work done */
+ }
+
+ vmpeg4_stop(hw);
+
+ 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);
+ }
+ }
+
+ mmpeg4_debug_print(DECODE_ID(hw), 0, "%s\n", __func__);
+ vfree((void *)hw);
+ hw = NULL;
+
+ return 0;
+}
+
+/****************************************/
+#ifdef CONFIG_PM
+static int mmpeg4_suspend(struct device *dev)
+{
+ amvdec_suspend(to_platform_device(dev), dev->power.power_state);
+ return 0;
+}
+
+static int mmpeg4_resume(struct device *dev)
+{
+ amvdec_resume(to_platform_device(dev));
+ return 0;
+}
+
+static const struct dev_pm_ops mmpeg4_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mmpeg4_suspend, mmpeg4_resume)
+};
+#endif
+
+static struct platform_driver ammvdec_mpeg4_driver = {
+ .probe = ammvdec_mpeg4_probe,
+ .remove = ammvdec_mpeg4_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &mmpeg4_pm_ops,
+#endif
+ }
+};
+
+static struct codec_profile_t amvdec_mpeg4_profile = {
+ .name = "mmpeg4",
+ .profile = ""
+};
+
+static int __init ammvdec_mpeg4_driver_init_module(void)
+{
+ pr_info("%s \n", __func__);
+
+ if (platform_driver_register(&ammvdec_mpeg4_driver)) {
+ pr_err("failed to register ammvdec_mpeg4 driver\n");
+ return -ENODEV;
+ }
+ vcodec_profile_register(&amvdec_mpeg4_profile);
+ return 0;
+}
+
+static void __exit ammvdec_mpeg4_driver_remove_module(void)
+{
+ pr_info("ammvdec_mpeg4 module remove.\n");
+
+ platform_driver_unregister(&ammvdec_mpeg4_driver);
+}
+
+/****************************************/
+module_param(debug_enable, uint, 0664);
+MODULE_PARM_DESC(debug_enable,
+ "\n ammvdec_mpeg4 debug enable\n");
+
+module_param(frmbase_cont_bitlevel, uint, 0664);
+MODULE_PARM_DESC(frmbase_cont_bitlevel, "\nfrmbase_cont_bitlevel\n");
+
+module_param(dynamic_buf_num_margin, uint, 0664);
+MODULE_PARM_DESC(dynamic_buf_num_margin, "\n dynamic_buf_num_margin\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(decode_timeout_val, uint, 0664);
+MODULE_PARM_DESC(decode_timeout_val, "\n ammvdec_mpeg4 decode_timeout_val\n");
+
+module_param_array(max_process_time, uint, &max_decode_instance_num, 0664);
+
+module_param(pre_decode_buf_level, int, 0664);
+MODULE_PARM_DESC(pre_decode_buf_level,
+ "\n ammvdec_mpeg4 pre_decode_buf_level\n");
+
+module_param(start_decode_buf_level, int, 0664);
+MODULE_PARM_DESC(start_decode_buf_level,
+ "\n ammvdec_mpeg4 start_decode_buf_level\n");
+
+module_param(udebug_flag, uint, 0664);
+MODULE_PARM_DESC(udebug_flag, "\n ammvdec_mpeg4 udebug_flag\n");
+
+module_param(without_display_mode, uint, 0664);
+MODULE_PARM_DESC(without_display_mode, "\n ammvdec_mpeg4 without_display_mode\n");
+
+module_init(ammvdec_mpeg4_driver_init_module);
+module_exit(ammvdec_mpeg4_driver_remove_module);
+
+MODULE_DESCRIPTION("AMLOGIC MPEG4 Video Decoder Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tim Yao <timyao@amlogic.com>");
+
diff --git a/drivers/frame_provider/decoder/real/Makefile b/drivers/frame_provider/decoder/real/Makefile
new file mode 100644
index 0000000..ab03ef2
--- /dev/null
+++ b/drivers/frame_provider/decoder/real/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_REAL) += amvdec_real.o
+amvdec_real-objs += vreal.o
diff --git a/drivers/frame_provider/decoder/real/vreal.c b/drivers/frame_provider/decoder/real/vreal.c
new file mode 100644
index 0000000..f6474b6
--- /dev/null
+++ b/drivers/frame_provider/decoder/real/vreal.c
@@ -0,0 +1,1069 @@
+/*
+ * drivers/amlogic/amports/vreal.c
+ *
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/fs.h>
+#include <linux/kfifo.h>
+#include <linux/platform_device.h>
+
+#include <linux/amlogic/media/canvas/canvas.h>
+
+#include <linux/dma-mapping.h>
+#include <linux/amlogic/media/utils/amstream.h>
+#include <linux/amlogic/media/utils/vformat.h>
+#include <linux/amlogic/media/frame_sync/ptsserv.h>
+#include <linux/amlogic/media/vfm/vframe.h>
+#include <linux/amlogic/media/vfm/vframe_provider.h>
+#include <linux/amlogic/media/vfm/vframe_receiver.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include "../../../stream_input/amports/amports_priv.h"
+#include "../utils/vdec.h"
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "../utils/amvdec.h"
+
+#include "../../../stream_input/amports/streambuf.h"
+#include "../../../stream_input/amports/streambuf_reg.h"
+#include "../../../stream_input/parser/rmparser.h"
+
+#include "vreal.h"
+#include <linux/amlogic/media/registers/register.h>
+#include "../utils/decoder_mmu_box.h"
+#include "../utils/decoder_bmmu_box.h"
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include <linux/amlogic/media/codec_mm/configs.h>
+#include "../utils/firmware.h"
+#include <linux/amlogic/tee.h>
+
+
+
+#define DRIVER_NAME "amvdec_real"
+#define MODULE_NAME "amvdec_real"
+
+#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+#define NV21
+#endif
+
+#define RM_DEF_BUFFER_ADDR 0x01000000
+/* protocol registers */
+#define STATUS_AMRISC AV_SCRATCH_4
+
+#define RV_PIC_INFO AV_SCRATCH_5
+#define VPTS_TR AV_SCRATCH_6
+#define VDTS AV_SCRATCH_7
+#define FROM_AMRISC AV_SCRATCH_8
+#define TO_AMRISC AV_SCRATCH_9
+#define SKIP_B_AMRISC AV_SCRATCH_A
+#define INT_REASON AV_SCRATCH_B
+#define WAIT_BUFFER AV_SCRATCH_E
+
+#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+#define MDEC_WIDTH AV_SCRATCH_I
+#define MDEC_HEIGHT AV_SCRATCH_J
+#else
+#define MDEC_WIDTH HARM_ASB_MB2
+#define MDEC_HEIGHT HASB_ARM_MB0
+#endif
+
+#define PARC_FORBIDDEN 0
+#define PARC_SQUARE 1
+#define PARC_CIF 2
+#define PARC_10_11 3
+#define PARC_16_11 4
+#define PARC_40_33 5
+#define PARC_RESERVED 6
+/* values between 6 and 14 are reserved */
+#define PARC_EXTENDED 15
+
+#define VF_POOL_SIZE 16
+#define VF_BUF_NUM 4
+#define PUT_INTERVAL (HZ/100)
+#define WORKSPACE_SIZE (1 * SZ_1M)
+#define MAX_BMMU_BUFFER_NUM (VF_BUF_NUM + 1)
+#define RV_AI_BUFF_START_IP 0x01f00000
+
+static struct vframe_s *vreal_vf_peek(void *);
+static struct vframe_s *vreal_vf_get(void *);
+static void vreal_vf_put(struct vframe_s *, void *);
+static int vreal_vf_states(struct vframe_states *states, void *);
+static int vreal_event_cb(int type, void *data, void *private_data);
+
+static int vreal_prot_init(void);
+static void vreal_local_init(void);
+
+static const char vreal_dec_id[] = "vreal-dev";
+
+#define PROVIDER_NAME "decoder.real"
+
+/*
+ *int query_video_status(int type, int *value);
+ */
+static const struct vframe_operations_s vreal_vf_provider = {
+ .peek = vreal_vf_peek,
+ .get = vreal_vf_get,
+ .put = vreal_vf_put,
+ .event_cb = vreal_event_cb,
+ .vf_states = vreal_vf_states,
+};
+
+static struct vframe_provider_s vreal_vf_prov;
+static void *mm_blk_handle;
+
+static DECLARE_KFIFO(newframe_q, struct vframe_s *, VF_POOL_SIZE);
+static DECLARE_KFIFO(display_q, struct vframe_s *, VF_POOL_SIZE);
+static DECLARE_KFIFO(recycle_q, struct vframe_s *, VF_POOL_SIZE);
+
+static struct vframe_s vfpool[VF_POOL_SIZE];
+static s32 vfbuf_use[VF_BUF_NUM];
+
+static u32 frame_width, frame_height, frame_dur, frame_prog;
+static u32 saved_resolution;
+static struct timer_list recycle_timer;
+static u32 stat;
+static u32 buf_size = 32 * 1024 * 1024;
+static u32 buf_offset;
+static u32 vreal_ratio;
+u32 vreal_format;
+static u32 wait_key_frame;
+static u32 last_tr;
+static u32 frame_count;
+static u32 current_vdts;
+static u32 hold;
+static u32 decoder_state;
+static u32 real_err_count;
+
+static u32 fatal_flag;
+static s32 wait_buffer_counter;
+static struct work_struct set_clk_work;
+static bool is_reset;
+
+static DEFINE_SPINLOCK(lock);
+
+static unsigned short pic_sz_tbl[12] ____cacheline_aligned;
+static dma_addr_t pic_sz_tbl_map;
+static const unsigned char RPR_size[9] = { 0, 1, 1, 2, 2, 3, 3, 3, 3 };
+
+static struct dec_sysinfo vreal_amstream_dec_info;
+
+static unsigned char aspect_ratio_table[16] = {
+ PARC_FORBIDDEN,
+ PARC_SQUARE,
+ PARC_CIF,
+ PARC_10_11,
+ PARC_16_11,
+ PARC_40_33,
+ PARC_RESERVED, PARC_RESERVED, PARC_RESERVED, PARC_RESERVED,
+ PARC_RESERVED, PARC_RESERVED, PARC_RESERVED, PARC_RESERVED,
+ PARC_RESERVED, PARC_EXTENDED
+};
+
+static inline u32 index2canvas(u32 index)
+{
+ const u32 canvas_tab[4] = {
+#ifdef NV21
+ 0x010100, 0x030302, 0x050504, 0x070706
+#else
+ 0x020100, 0x050403, 0x080706, 0x0b0a09
+#endif
+ };
+
+ return canvas_tab[index];
+}
+
+static void set_aspect_ratio(struct vframe_s *vf, unsigned int pixel_ratio)
+{
+ int ar = 0;
+
+ if (vreal_ratio == 0) {
+ vf->ratio_control |= (0x90 <<
+ DISP_RATIO_ASPECT_RATIO_BIT);
+ /* always stretch to 16:9 */
+ } else {
+ switch (aspect_ratio_table[pixel_ratio]) {
+ case 0:
+ ar = vreal_amstream_dec_info.height * vreal_ratio /
+ vreal_amstream_dec_info.width;
+ break;
+ case 1:
+ case 0xff:
+ ar = vreal_ratio * vf->height / vf->width;
+ break;
+ case 2:
+ ar = (vreal_ratio * vf->height * 12) / (vf->width * 11);
+ break;
+ case 3:
+ ar = (vreal_ratio * vf->height * 11) / (vf->width * 10);
+ break;
+ case 4:
+ ar = (vreal_ratio * vf->height * 11) / (vf->width * 16);
+ break;
+ case 5:
+ ar = (vreal_ratio * vf->height * 33) / (vf->width * 40);
+ break;
+ default:
+ ar = vreal_ratio * vf->height / vf->width;
+ break;
+ }
+ }
+
+ ar = min(ar, DISP_RATIO_ASPECT_RATIO_MAX);
+
+ vf->ratio_control |= (ar << DISP_RATIO_ASPECT_RATIO_BIT);
+}
+
+static irqreturn_t vreal_isr(int irq, void *dev_id)
+{
+ u32 from;
+ struct vframe_s *vf = NULL;
+ u32 buffer_index;
+ unsigned int status;
+ unsigned int vdts;
+ unsigned int info;
+ unsigned int tr;
+ unsigned int pictype;
+ u32 r = READ_VREG(INT_REASON);
+
+ if (decoder_state == 0)
+ return IRQ_HANDLED;
+
+ status = READ_VREG(STATUS_AMRISC);
+ if (status & (PARSER_ERROR_WRONG_PACKAGE_SIZE |
+ PARSER_ERROR_WRONG_HEAD_VER |
+ DECODER_ERROR_VLC_DECODE_TBL)) {
+ /* decoder or parser error */
+ real_err_count++;
+ /* pr_info("real decoder or parser
+ *error, status 0x%x\n", status);
+ */
+ }
+
+ if (r == 2) {
+ pr_info("first vpts = 0x%x\n", READ_VREG(VDTS));
+ pts_checkin_offset(PTS_TYPE_AUDIO, 0, READ_VREG(VDTS) * 90);
+ WRITE_VREG(AV_SCRATCH_B, 0);
+ WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
+ return IRQ_HANDLED;
+ } else if (r == 3) {
+ pr_info("first apts = 0x%x\n", READ_VREG(VDTS));
+ pts_checkin_offset(PTS_TYPE_VIDEO, 0, READ_VREG(VDTS) * 90);
+ WRITE_VREG(AV_SCRATCH_B, 0);
+ WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
+ return IRQ_HANDLED;
+ }
+
+ from = READ_VREG(FROM_AMRISC);
+ if ((hold == 0) && from) {
+ tr = READ_VREG(VPTS_TR);
+ pictype = (tr >> 13) & 3;
+ tr = (tr & 0x1fff) * 96;
+
+ if (kfifo_get(&newframe_q, &vf) == 0) {
+ pr_info("fatal error, no available buffer slot.");
+ return IRQ_HANDLED;
+ }
+
+ vdts = READ_VREG(VDTS);
+ if (last_tr == -1) /* ignore tr for first time */
+ vf->duration = frame_dur;
+ else {
+ if (tr > last_tr)
+ vf->duration = tr - last_tr;
+ else
+ vf->duration = (96 << 13) + tr - last_tr;
+
+ if (vf->duration > 10 * frame_dur) {
+ /* not a reasonable duration,
+ *should not happen
+ */
+ vf->duration = frame_dur;
+ }
+#if 0
+ else {
+ if (check_frame_duration == 0) {
+ frame_dur = vf->duration;
+ check_frame_duration = 1;
+ }
+ }
+#endif
+ }
+
+ last_tr = tr;
+ buffer_index = from & 0x03;
+
+ if (pictype == 0) { /* I */
+ current_vdts = vdts * 90 + 1;
+ vf->pts = current_vdts;
+ if (wait_key_frame)
+ wait_key_frame = 0;
+ } else {
+ if (wait_key_frame) {
+ while (READ_VREG(TO_AMRISC))
+ ;
+ WRITE_VREG(TO_AMRISC, ~(1 << buffer_index));
+ WRITE_VREG(FROM_AMRISC, 0);
+ return IRQ_HANDLED;
+ } else {
+ current_vdts +=
+ vf->duration - (vf->duration >> 4);
+ vf->pts = current_vdts;
+ }
+ }
+
+ /* pr_info("pts %d, picture type %d\n", vf->pts, pictype); */
+
+ info = READ_VREG(RV_PIC_INFO);
+ vf->signal_type = 0;
+ vf->index = buffer_index;
+ vf->width = info >> 16;
+ vf->height = (info >> 4) & 0xfff;
+ vf->bufWidth = 1920;
+ vf->flag = 0;
+ vf->ratio_control = 0;
+ set_aspect_ratio(vf, info & 0x0f);
+ vf->duration_pulldown = 0;
+#ifdef NV21
+ vf->type = VIDTYPE_PROGRESSIVE |
+ VIDTYPE_VIU_FIELD | VIDTYPE_VIU_NV21;
+#else
+ vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD;
+#endif
+ vf->canvas0Addr = vf->canvas1Addr = index2canvas(buffer_index);
+ vf->orientation = 0;
+ vf->type_original = vf->type;
+
+ vfbuf_use[buffer_index] = 1;
+ vf->mem_handle =
+ decoder_bmmu_box_get_mem_handle(
+ mm_blk_handle,
+ buffer_index);
+
+ kfifo_put(&display_q, (const struct vframe_s *)vf);
+ ATRACE_COUNTER(MODULE_NAME, vf->pts);
+
+ frame_count++;
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
+ WRITE_VREG(FROM_AMRISC, 0);
+ }
+
+ WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
+
+ return IRQ_HANDLED;
+}
+
+static struct vframe_s *vreal_vf_peek(void *op_arg)
+{
+ struct vframe_s *vf;
+
+ if (kfifo_peek(&display_q, &vf))
+ return vf;
+
+ return NULL;
+}
+
+static struct vframe_s *vreal_vf_get(void *op_arg)
+{
+ struct vframe_s *vf;
+
+ if (kfifo_get(&display_q, &vf))
+ return vf;
+
+ return NULL;
+}
+
+static void vreal_vf_put(struct vframe_s *vf, void *op_arg)
+{
+ kfifo_put(&recycle_q, (const struct vframe_s *)vf);
+}
+
+static int vreal_event_cb(int type, void *data, void *private_data)
+{
+ if (type & VFRAME_EVENT_RECEIVER_RESET) {
+ unsigned long flags;
+
+ amvdec_stop();
+#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vf_light_unreg_provider(&vreal_vf_prov);
+#endif
+ spin_lock_irqsave(&lock, flags);
+ vreal_local_init();
+ vreal_prot_init();
+ spin_unlock_irqrestore(&lock, flags);
+#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vf_reg_provider(&vreal_vf_prov);
+#endif
+ amvdec_start();
+ }
+ return 0;
+}
+
+static int vreal_vf_states(struct vframe_states *states, void *op_arg)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ states->vf_pool_size = VF_POOL_SIZE;
+ states->buf_free_num = kfifo_len(&newframe_q);
+ states->buf_avail_num = kfifo_len(&display_q);
+ states->buf_recycle_num = kfifo_len(&recycle_q);
+
+ spin_unlock_irqrestore(&lock, flags);
+
+ return 0;
+}
+#if 0
+#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+static void vreal_ppmgr_reset(void)
+{
+ vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_RESET, NULL);
+
+ vreal_local_init();
+
+ pr_info("vrealdec: vf_ppmgr_reset\n");
+}
+#endif
+#endif
+
+static void vreal_set_clk(struct work_struct *work)
+{
+ if (frame_dur > 0 &&
+ saved_resolution !=
+ frame_width * frame_height * (96000 / frame_dur)) {
+ int fps = 96000 / frame_dur;
+
+ saved_resolution = frame_width * frame_height * fps;
+ vdec_source_changed(VFORMAT_REAL,
+ frame_width, frame_height, fps);
+ }
+}
+
+static void vreal_put_timer_func(unsigned long arg)
+{
+ struct timer_list *timer = (struct timer_list *)arg;
+ /* unsigned int status; */
+
+#if 0
+ enum receviver_start_e state = RECEIVER_INACTIVE;
+
+ if (vf_get_receiver(PROVIDER_NAME)) {
+ state =
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_QUREY_STATE, NULL);
+ if ((state == RECEIVER_STATE_NULL)
+ || (state == RECEIVER_STATE_NONE)) {
+ /* receiver has no event_cb
+ *or receiver's event_cb does not process this event
+ */
+ state = RECEIVER_INACTIVE;
+ }
+ } else
+ state = RECEIVER_INACTIVE;
+
+ if ((READ_VREG(WAIT_BUFFER) != 0) &&
+ kfifo_is_empty(&display_q) &&
+ kfifo_is_empty(&recycle_q) && (state == RECEIVER_INACTIVE)) {
+ pr_info("$$$$$$decoder is waiting for buffer\n");
+ if (++wait_buffer_counter > 2) {
+ amvdec_stop();
+
+#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vreal_ppmgr_reset();
+#else
+ vf_light_unreg_provider(&vreal_vf_prov);
+ vreal_local_init();
+ vf_reg_provider(&vreal_vf_prov);
+#endif
+ vreal_prot_init();
+ amvdec_start();
+ }
+ }
+#endif
+
+ while (!kfifo_is_empty(&recycle_q) && (READ_VREG(TO_AMRISC) == 0)) {
+ struct vframe_s *vf;
+
+ if (kfifo_get(&recycle_q, &vf)) {
+ if ((vf->index < VF_BUF_NUM)
+ && (--vfbuf_use[vf->index] == 0)) {
+ WRITE_VREG(TO_AMRISC, ~(1 << vf->index));
+ vf->index = VF_BUF_NUM;
+ }
+
+ kfifo_put(&newframe_q, (const struct vframe_s *)vf);
+ }
+ }
+
+ schedule_work(&set_clk_work);
+
+ timer->expires = jiffies + PUT_INTERVAL;
+
+ add_timer(timer);
+}
+
+int vreal_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus)
+{
+ if (!(stat & STAT_VDEC_RUN))
+ return -1;
+
+ vstatus->frame_width = vreal_amstream_dec_info.width;
+ vstatus->frame_height = vreal_amstream_dec_info.height;
+ if (0 != vreal_amstream_dec_info.rate)
+ vstatus->frame_rate = 96000 / vreal_amstream_dec_info.rate;
+ else
+ vstatus->frame_rate = 96000;
+ vstatus->error_count = real_err_count;
+ vstatus->status =
+ ((READ_VREG(STATUS_AMRISC) << 16) | fatal_flag) | stat;
+ /* pr_info("vreal_dec_status 0x%x\n", vstatus->status); */
+ return 0;
+}
+
+int vreal_set_isreset(struct vdec_s *vdec, int isreset)
+{
+ is_reset = isreset;
+ return 0;
+}
+
+/****************************************/
+static int vreal_canvas_init(void)
+{
+ int i, ret;
+ unsigned long buf_start;
+ u32 canvas_width, canvas_height;
+ u32 alloc_size, decbuf_size, decbuf_y_size, decbuf_uv_size;
+
+ if (buf_size <= 0x00400000) {
+ /* SD only */
+ canvas_width = 768;
+ canvas_height = 576;
+ decbuf_y_size = 0x80000;
+ decbuf_uv_size = 0x20000;
+ decbuf_size = 0x100000;
+ } else {
+ /* HD & SD */
+ #if 1
+ int w = vreal_amstream_dec_info.width;
+ int h = vreal_amstream_dec_info.height;
+ int align_w, align_h;
+ int max, min;
+
+ align_w = ALIGN(w, 64);
+ align_h = ALIGN(h, 64);
+ if (align_w > align_h) {
+ max = align_w;
+ min = align_h;
+ } else {
+ canvas_width = 1920;
+ canvas_height = 1088;
+ max = align_h;
+ min = align_w;
+ }
+ /* HD & SD */
+ if ((max > 1920 || min > 1088) &&
+ ALIGN(align_w * align_h * 3/2, SZ_64K) * 9 <=
+ buf_size) {
+ canvas_width = align_w;
+ canvas_height = align_h;
+ decbuf_y_size = ALIGN(align_w * align_h, SZ_64K);
+ decbuf_uv_size = ALIGN(align_w * align_h/4, SZ_64K);
+ decbuf_size = ALIGN(align_w * align_h * 3/2, SZ_64K);
+ } else { /*1080p*/
+ if (h > w) {
+ canvas_width = 1088;
+ canvas_height = 1920;
+ } else {
+ canvas_width = 1920;
+ canvas_height = 1088;
+ }
+ decbuf_y_size = 0x200000;
+ decbuf_uv_size = 0x80000;
+ decbuf_size = 0x300000;
+ }
+ #endif
+ }
+
+ for (i = 0; i < MAX_BMMU_BUFFER_NUM; i++) {
+ /* workspace mem */
+ if (i == (MAX_BMMU_BUFFER_NUM - 1))
+ alloc_size = WORKSPACE_SIZE;
+ else
+ alloc_size = decbuf_size;
+
+ ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle, i,
+ alloc_size, DRIVER_NAME, &buf_start);
+ if (ret < 0)
+ return ret;
+
+ if (i == (MAX_BMMU_BUFFER_NUM - 1)) {
+ buf_offset = buf_start - RV_AI_BUFF_START_IP;
+ continue;
+ }
+
+#ifdef NV21
+ canvas_config(2 * i + 0,
+ buf_start,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+ canvas_config(2 * i + 1,
+ buf_start +
+ decbuf_y_size, canvas_width,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+#else
+ canvas_config(3 * i + 0,
+ buf_start,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+ canvas_config(3 * i + 1,
+ buf_start +
+ decbuf_y_size, canvas_width / 2,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+ canvas_config(3 * i + 2,
+ buf_start +
+ decbuf_y_size + decbuf_uv_size,
+ canvas_width / 2, canvas_height / 2,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+#endif
+ }
+
+ return 0;
+}
+
+static int vreal_prot_init(void)
+{
+ int r;
+#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+ WRITE_VREG(DOS_SW_RESET0, (1 << 7) | (1 << 6));
+ WRITE_VREG(DOS_SW_RESET0, 0);
+#else
+ WRITE_RESET_REG(RESET0_REGISTER, RESET_IQIDCT | RESET_MC);
+#endif
+
+
+
+ r = vreal_canvas_init();
+
+ /* index v << 16 | u << 8 | y */
+#ifdef NV21
+ WRITE_VREG(AV_SCRATCH_0, 0x010100);
+ WRITE_VREG(AV_SCRATCH_1, 0x030302);
+ WRITE_VREG(AV_SCRATCH_2, 0x050504);
+ WRITE_VREG(AV_SCRATCH_3, 0x070706);
+#else
+ WRITE_VREG(AV_SCRATCH_0, 0x020100);
+ WRITE_VREG(AV_SCRATCH_1, 0x050403);
+ WRITE_VREG(AV_SCRATCH_2, 0x080706);
+ WRITE_VREG(AV_SCRATCH_3, 0x0b0a09);
+#endif
+
+ /* notify ucode the buffer offset */
+ WRITE_VREG(AV_SCRATCH_F, buf_offset);
+
+#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+ WRITE_VREG(DOS_SW_RESET0, (1 << 9) | (1 << 8));
+ WRITE_VREG(DOS_SW_RESET0, 0);
+#else
+ WRITE_RESET_REG(RESET2_REGISTER, RESET_PIC_DC | RESET_DBLK);
+#endif
+
+ /* disable PSCALE for hardware sharing */
+ WRITE_VREG(PSCALE_CTRL, 0);
+
+ WRITE_VREG(FROM_AMRISC, 0);
+ WRITE_VREG(TO_AMRISC, 0);
+ WRITE_VREG(STATUS_AMRISC, 0);
+
+ WRITE_VREG(RV_PIC_INFO, 0);
+ WRITE_VREG(VPTS_TR, 0);
+ WRITE_VREG(VDTS, 0);
+ WRITE_VREG(SKIP_B_AMRISC, 0);
+
+ WRITE_VREG(MDEC_WIDTH, (frame_width + 15) & 0xfff0);
+ WRITE_VREG(MDEC_HEIGHT, (frame_height + 15) & 0xfff0);
+
+ /* clear mailbox interrupt */
+ WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
+
+ /* enable mailbox interrupt */
+ WRITE_VREG(ASSIST_MBOX1_MASK, 1);
+
+ /* clear wait buffer status */
+ WRITE_VREG(WAIT_BUFFER, 0);
+
+#ifdef NV21
+ SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17);
+#endif
+ return r;
+}
+
+static void vreal_local_init(void)
+{
+ int i;
+
+ /* vreal_ratio = vreal_amstream_dec_info.ratio; */
+ vreal_ratio = 0x100;
+
+ frame_prog = 0;
+
+ frame_width = vreal_amstream_dec_info.width;
+ frame_height = vreal_amstream_dec_info.height;
+ frame_dur = vreal_amstream_dec_info.rate;
+
+ for (i = 0; i < VF_BUF_NUM; i++)
+ vfbuf_use[i] = 0;
+
+ INIT_KFIFO(display_q);
+ INIT_KFIFO(recycle_q);
+ INIT_KFIFO(newframe_q);
+
+ for (i = 0; i < VF_POOL_SIZE; i++) {
+ const struct vframe_s *vf = &vfpool[i];
+ vfpool[i].index = VF_BUF_NUM;
+ kfifo_put(&newframe_q, vf);
+ }
+
+ if (mm_blk_handle) {
+ decoder_bmmu_box_free(mm_blk_handle);
+ mm_blk_handle = NULL;
+ }
+
+ mm_blk_handle = decoder_bmmu_box_alloc_box(
+ DRIVER_NAME,
+ 0,
+ MAX_BMMU_BUFFER_NUM,
+ 4 + PAGE_SHIFT,
+ CODEC_MM_FLAGS_CMA_CLEAR |
+ CODEC_MM_FLAGS_FOR_VDECODER);
+
+ decoder_state = 1;
+ hold = 0;
+ last_tr = -1;
+ wait_key_frame = 1;
+ frame_count = 0;
+ current_vdts = 0;
+ real_err_count = 0;
+
+ pic_sz_tbl_map = 0;
+ saved_resolution = 0;
+ fatal_flag = 0;
+ wait_buffer_counter = 0;
+}
+
+static void load_block_data(void *dest, unsigned int count)
+{
+ unsigned short *pdest = (unsigned short *)dest;
+ unsigned short src_tbl[12];
+ unsigned int i;
+
+ src_tbl[0] = RPR_size[vreal_amstream_dec_info.extra + 1];
+ memcpy((void *)&src_tbl[1], vreal_amstream_dec_info.param,
+ 2 << src_tbl[0]);
+
+#if 0
+ for (i = 0; i < 12; i++)
+ pr_info("src_tbl[%d]: 0x%x\n", i, src_tbl[i]);
+#endif
+
+ for (i = 0; i < count / 4; i++) {
+ pdest[i * 4] = src_tbl[i * 4 + 3];
+ pdest[i * 4 + 1] = src_tbl[i * 4 + 2];
+ pdest[i * 4 + 2] = src_tbl[i * 4 + 1];
+ pdest[i * 4 + 3] = src_tbl[i * 4];
+ }
+
+ pic_sz_tbl_map = dma_map_single(amports_get_dma_device(), &pic_sz_tbl,
+ sizeof(pic_sz_tbl), DMA_TO_DEVICE);
+
+}
+
+s32 vreal_init(struct vdec_s *vdec)
+{
+ int ret = -1, size = -1;
+ char fw_name[32] = {0};
+ char *buf = vmalloc(0x1000 * 16);
+
+ if (IS_ERR_OR_NULL(buf))
+ return -ENOMEM;
+
+ pr_info("vreal_init\n");
+
+ init_timer(&recycle_timer);
+
+ stat |= STAT_TIMER_INIT;
+
+ amvdec_enable();
+
+ vreal_local_init();
+
+ ret = rmparser_init(vdec);
+ if (ret) {
+ amvdec_disable();
+ vfree(buf);
+ pr_info("rm parser init failed\n");
+ return ret;
+ }
+
+ if (vreal_amstream_dec_info.format == VIDEO_DEC_FORMAT_REAL_8) {
+ if (vreal_amstream_dec_info.param == NULL) {
+ rmparser_release();
+ amvdec_disable();
+ vfree(buf);
+ return -1;
+ }
+ load_block_data((void *)pic_sz_tbl, 12);
+
+ /* TODO: need to load the table into lmem */
+ WRITE_VREG(LMEM_DMA_ADR, (unsigned int)pic_sz_tbl_map);
+ WRITE_VREG(LMEM_DMA_COUNT, 10);
+ WRITE_VREG(LMEM_DMA_CTRL, 0xc178 | (3 << 11));
+ while (READ_VREG(LMEM_DMA_CTRL) & 0x8000)
+ ;
+ size = get_firmware_data(VIDEO_DEC_REAL_V8, buf);
+ strncpy(fw_name, "vreal_mc_8", sizeof(fw_name));
+
+ pr_info("load VIDEO_DEC_FORMAT_REAL_8\n");
+ } else if (vreal_amstream_dec_info.format == VIDEO_DEC_FORMAT_REAL_9) {
+ size = get_firmware_data(VIDEO_DEC_REAL_V9, buf);
+ strncpy(fw_name, "vreal_mc_9", sizeof(fw_name));
+
+ pr_info("load VIDEO_DEC_FORMAT_REAL_9\n");
+ } else
+ pr_info("unsurpported real format\n");
+
+ if (size < 0) {
+ rmparser_release();
+ amvdec_disable();
+ pr_err("get firmware fail.");
+ vfree(buf);
+ return -1;
+ }
+
+ ret = amvdec_loadmc_ex(VFORMAT_REAL, fw_name, buf);
+ if (ret < 0) {
+ rmparser_release();
+ amvdec_disable();
+ vfree(buf);
+ pr_err("%s: the %s fw loading failed, err: %x\n",
+ fw_name, tee_enabled() ? "TEE" : "local", ret);
+ return -EBUSY;
+ }
+
+ vfree(buf);
+
+ stat |= STAT_MC_LOAD;
+
+ /* enable AMRISC side protocol */
+ ret = vreal_prot_init();
+ if (ret < 0) {
+ rmparser_release();
+ amvdec_disable();
+ return ret;
+ }
+ if (vdec_request_irq(VDEC_IRQ_1, vreal_isr,
+ "vreal-irq", (void *)vreal_dec_id)) {
+ rmparser_release();
+ amvdec_disable();
+
+ pr_info("vreal irq register error.\n");
+ return -ENOENT;
+ }
+
+ stat |= STAT_ISR_REG;
+#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vf_provider_init(&vreal_vf_prov, PROVIDER_NAME, &vreal_vf_provider,
+ NULL);
+ vf_reg_provider(&vreal_vf_prov);
+ vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_START, NULL);
+#else
+ vf_provider_init(&vreal_vf_prov, PROVIDER_NAME, &vreal_vf_provider,
+ NULL);
+ vf_reg_provider(&vreal_vf_prov);
+#endif
+
+ if (!is_reset)
+ vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)((unsigned long)vreal_amstream_dec_info.rate));
+
+ stat |= STAT_VF_HOOK;
+
+ recycle_timer.data = (ulong)&recycle_timer;
+ recycle_timer.function = vreal_put_timer_func;
+ recycle_timer.expires = jiffies + PUT_INTERVAL;
+
+ add_timer(&recycle_timer);
+
+ stat |= STAT_TIMER_ARM;
+
+ amvdec_start();
+
+ stat |= STAT_VDEC_RUN;
+
+ pr_info("vreal init finished\n");
+
+ return 0;
+}
+
+void vreal_set_fatal_flag(int flag)
+{
+ if (flag)
+ fatal_flag = PARSER_FATAL_ERROR;
+}
+
+static int amvdec_real_probe(struct platform_device *pdev)
+{
+ struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
+
+ if (pdata == NULL) {
+ pr_info("amvdec_real memory resource undefined.\n");
+ return -EFAULT;
+ }
+ if (pdata->sys_info)
+ vreal_amstream_dec_info = *pdata->sys_info;
+
+ pdata->dec_status = vreal_dec_status;
+ pdata->set_isreset = vreal_set_isreset;
+ is_reset = 0;
+
+ INIT_WORK(&set_clk_work, vreal_set_clk);
+ if (vreal_init(pdata) < 0) {
+ pr_info("amvdec_real init failed.\n");
+ pdata->dec_status = NULL;
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int amvdec_real_remove(struct platform_device *pdev)
+{
+ cancel_work_sync(&set_clk_work);
+ if (stat & STAT_VDEC_RUN) {
+ amvdec_stop();
+ stat &= ~STAT_VDEC_RUN;
+ }
+
+ if (stat & STAT_ISR_REG) {
+ vdec_free_irq(VDEC_IRQ_1, (void *)vreal_dec_id);
+ stat &= ~STAT_ISR_REG;
+ }
+
+ if (stat & STAT_TIMER_ARM) {
+ del_timer_sync(&recycle_timer);
+ stat &= ~STAT_TIMER_ARM;
+ }
+
+ if (stat & STAT_VF_HOOK) {
+ if (!is_reset)
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_FR_END_HINT, NULL);
+
+ vf_unreg_provider(&vreal_vf_prov);
+ stat &= ~STAT_VF_HOOK;
+ }
+
+ if (pic_sz_tbl_map != 0) {
+ dma_unmap_single(NULL, pic_sz_tbl_map, sizeof(pic_sz_tbl),
+ DMA_TO_DEVICE);
+ }
+
+ rmparser_release();
+
+ vdec_source_changed(VFORMAT_REAL, 0, 0, 0);
+
+ amvdec_disable();
+
+ if (mm_blk_handle) {
+ decoder_bmmu_box_free(mm_blk_handle);
+ mm_blk_handle = NULL;
+ }
+ pr_info("frame duration %d, frames %d\n", frame_dur, frame_count);
+ return 0;
+}
+
+/****************************************/
+#ifdef CONFIG_PM
+static int real_suspend(struct device *dev)
+{
+ amvdec_suspend(to_platform_device(dev), dev->power.power_state);
+ return 0;
+}
+
+static int real_resume(struct device *dev)
+{
+ amvdec_resume(to_platform_device(dev));
+ return 0;
+}
+
+static const struct dev_pm_ops real_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(real_suspend, real_resume)
+};
+#endif
+
+static struct platform_driver amvdec_real_driver = {
+ .probe = amvdec_real_probe,
+ .remove = amvdec_real_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &real_pm_ops,
+#endif
+ }
+};
+
+static struct codec_profile_t amvdec_real_profile = {
+ .name = "real",
+ .profile = "rmvb,1080p+"
+};
+static struct mconfig real_configs[] = {
+ MC_PU32("stat", &stat),
+};
+static struct mconfig_node real_node;
+
+static int __init amvdec_real_driver_init_module(void)
+{
+ pr_debug("amvdec_real module init\n");
+
+ if (platform_driver_register(&amvdec_real_driver)) {
+ pr_err("failed to register amvdec_real driver\n");
+ return -ENODEV;
+ }
+ vcodec_profile_register(&amvdec_real_profile);
+ INIT_REG_NODE_CONFIGS("media.decoder", &real_node,
+ "real", real_configs, CONFIG_FOR_R);
+ return 0;
+}
+
+static void __exit amvdec_real_driver_remove_module(void)
+{
+ pr_debug("amvdec_real module remove.\n");
+
+ platform_driver_unregister(&amvdec_real_driver);
+}
+
+/****************************************/
+
+module_init(amvdec_real_driver_init_module);
+module_exit(amvdec_real_driver_remove_module);
+
+MODULE_DESCRIPTION("AMLOGIC REAL Video Decoder Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/frame_provider/decoder/real/vreal.h b/drivers/frame_provider/decoder/real/vreal.h
new file mode 100644
index 0000000..734cc6f
--- /dev/null
+++ b/drivers/frame_provider/decoder/real/vreal.h
@@ -0,0 +1,26 @@
+/*
+ * drivers/amlogic/amports/vreal.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 VREAL_H
+#define VREAL_H
+
+#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+/* TODO: move to register headers */
+#define VPP_VD1_POSTBLEND (1 << 10)
+#endif
+
+#endif /* VREAL_H */
diff --git a/drivers/frame_provider/decoder/utils/Makefile b/drivers/frame_provider/decoder/utils/Makefile
new file mode 100644
index 0000000..1e7552b
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/Makefile
@@ -0,0 +1,10 @@
+obj-m += decoder_common.o
+decoder_common-objs += utils.o vdec.o vdec_input.o amvdec.o
+decoder_common-objs += decoder_mmu_box.o decoder_bmmu_box.o
+decoder_common-objs += config_parser.o secprot.o vdec_profile.o
+decoder_common-objs += amstream_profile.o
+decoder_common-objs += frame_check.o amlogic_fbc_hook.o
+decoder_common-objs += vdec_v4l2_buffer_ops.o
+decoder_common-objs += vdec_sync.o
+decoder_common-objs += vdec_power_ctrl.o
+
diff --git a/drivers/frame_provider/decoder/utils/amlogic_fbc_hook.c b/drivers/frame_provider/decoder/utils/amlogic_fbc_hook.c
new file mode 100644
index 0000000..b6179fb
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/amlogic_fbc_hook.c
@@ -0,0 +1,104 @@
+/*
+ * drivers/amlogic/media/frame_provider/decoder/utils/amlogic_fbc_hook.c
+ *
+ * Copyright (C) 2016 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+#include "amlogic_fbc_hook.h"
+static AMLOGIC_FBC_vframe_decoder_fun_t g_decoder_fun;
+static AMLOGIC_FBC_vframe_encoder_fun_t g_encoder_fun;
+
+
+int AMLOGIC_FBC_vframe_decoder(
+ void *dstyuv[4],
+ struct vframe_s *vf,
+ int out_format,
+ int flags)
+
+{
+ if (g_decoder_fun) {
+ return g_decoder_fun(dstyuv,
+ vf,
+ out_format,
+ flags);
+ }
+ printk("no AMLOGIC_FBC_vframe_decoder ERRR!!\n");
+ return -1;
+}
+EXPORT_SYMBOL(AMLOGIC_FBC_vframe_decoder);
+
+int AMLOGIC_FBC_vframe_encoder(
+ void *srcyuv[4],
+ void *dst_header,
+ void *dst_body,
+ int in_format,
+ int flags)
+
+{
+ if (g_encoder_fun) {
+ return g_encoder_fun(
+ srcyuv,
+ dst_header,
+ dst_body,
+ in_format,
+ flags);
+ }
+ printk("no AMLOGIC_FBC_vframe_encoder ERRR!!\n");
+ return -1;
+}
+EXPORT_SYMBOL(AMLOGIC_FBC_vframe_encoder);
+
+int register_amlogic_afbc_dec_fun(AMLOGIC_FBC_vframe_decoder_fun_t fn)
+{
+ if (g_decoder_fun) {
+ pr_err("error!!,AMLOGIC_FBC dec have register\n");
+ return -1;
+ }
+ printk("register_amlogic_afbc_dec_fun\n");
+ g_decoder_fun = fn;
+ return 0;
+}
+EXPORT_SYMBOL(register_amlogic_afbc_dec_fun);
+
+int register_amlogic_afbc_enc_fun(AMLOGIC_FBC_vframe_encoder_fun_t fn)
+{
+ if (g_encoder_fun) {
+ pr_err("error!!,AMLOGIC_FBC enc have register\n");
+ return -1;
+ }
+ g_encoder_fun = fn;
+ return 0;
+}
+EXPORT_SYMBOL(register_amlogic_afbc_enc_fun);
+
+int unregister_amlogic_afbc_dec_fun(void)
+{
+ g_decoder_fun = NULL;
+ pr_err("unregister_amlogic_afbc_dec_fun\n");
+ return 0;
+}
+EXPORT_SYMBOL(unregister_amlogic_afbc_dec_fun);
+
+int unregister_amlogic_afbc_enc_fun(void)
+{
+ g_encoder_fun = NULL;
+ pr_err("unregister_amlogic_afbc_dec_fun\n");
+ return 0;
+}
+EXPORT_SYMBOL(unregister_amlogic_afbc_enc_fun);
+
+
diff --git a/drivers/frame_provider/decoder/utils/amlogic_fbc_hook.h b/drivers/frame_provider/decoder/utils/amlogic_fbc_hook.h
new file mode 100644
index 0000000..7eec4b7
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/amlogic_fbc_hook.h
@@ -0,0 +1,55 @@
+/*
+ * drivers/amlogic/media/frame_provider/decoder/utils/amlogic_fbc_hook.h
+ *
+ * Copyright (C) 2016 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef AMLGIC_FBC_HEADER___
+#define AMLGIC_FBC_HEADER___
+#include <linux/amlogic/media/vfm/vframe.h>
+/*
+unsigned short *planes[4],
+ unsigned char *buf,
+ unsigned *v2_head_buf // v2_head_buf_size=(((frame_info->mbw + 1)>>1)*2) * (((frame_info->mbh + 15)>>4)*16)
+);
+*/
+
+int AMLOGIC_FBC_vframe_decoder(
+ void *dstyuv[4],
+ struct vframe_s *vf,
+ int out_format,
+ int flags);
+int AMLOGIC_FBC_vframe_encoder(
+ void *srcyuv[4],
+ void *dst_header,
+ void *dst_body,
+ int in_format,
+ int flags);
+
+typedef int (*AMLOGIC_FBC_vframe_decoder_fun_t)(
+ void **,
+ struct vframe_s *,
+ int,
+ int);
+typedef int (*AMLOGIC_FBC_vframe_encoder_fun_t)(
+ void **,
+ void *,
+ void *,
+ int,
+ int);
+int register_amlogic_afbc_dec_fun(AMLOGIC_FBC_vframe_decoder_fun_t fn);
+int register_amlogic_afbc_enc_fun(AMLOGIC_FBC_vframe_encoder_fun_t fn);
+int unregister_amlogic_afbc_dec_fun(void);
+int unregister_amlogic_afbc_enc_fun(void);
+#endif
\ No newline at end of file
diff --git a/drivers/frame_provider/decoder/utils/amstream_profile.c b/drivers/frame_provider/decoder/utils/amstream_profile.c
new file mode 100644
index 0000000..c8033ce
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/amstream_profile.c
@@ -0,0 +1,70 @@
+/*
+ * drivers/amlogic/media/stream_input/amports/amstream_profile.c
+ *
+ * Copyright (C) 2016 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/amlogic/media/utils/amstream.h>
+
+static const struct codec_profile_t *vcodec_profile[SUPPORT_VDEC_NUM] = { 0 };
+
+static int vcodec_profile_idx;
+
+ssize_t vcodec_profile_read(char *buf)
+{
+ char *pbuf = buf;
+ int i = 0;
+
+ for (i = 0; i < vcodec_profile_idx; i++) {
+ pbuf += snprintf(pbuf, PAGE_SIZE - (pbuf - buf), "%s:%s;\n", vcodec_profile[i]->name,
+ vcodec_profile[i]->profile);
+ }
+
+ return pbuf - buf;
+}
+EXPORT_SYMBOL(vcodec_profile_read);
+
+int vcodec_profile_register(const struct codec_profile_t *vdec_profile)
+{
+ if (vcodec_profile_idx < SUPPORT_VDEC_NUM) {
+ vcodec_profile[vcodec_profile_idx] = vdec_profile;
+ vcodec_profile_idx++;
+ pr_debug("regist %s codec profile\n", vdec_profile->name);
+
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(vcodec_profile_register);
+
+bool is_support_profile(char *name)
+{
+ int ret = 0;
+ int i, size = ARRAY_SIZE(vcodec_profile);
+
+ for (i = 0; i < size; i++) {
+ if (!vcodec_profile[i])
+ break;
+ if (!strcmp(name, vcodec_profile[i]->name))
+ return true;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(is_support_profile);
+
+
diff --git a/drivers/frame_provider/decoder/utils/amvdec.c b/drivers/frame_provider/decoder/utils/amvdec.c
new file mode 100644
index 0000000..af36ef1
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/amvdec.c
@@ -0,0 +1,1169 @@
+/*
+ * drivers/amlogic/media/frame_provider/decoder/utils/amvdec.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/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/amlogic/media/utils/vformat.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+#include "vdec.h"
+
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+
+#ifdef CONFIG_WAKELOCK
+#include <linux/wakelock.h>
+#endif
+#include "../../../stream_input/amports/amports_priv.h"
+
+/* #include <mach/am_regs.h> */
+/* #include <mach/power_gate.h> */
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "amvdec.h"
+#include <linux/amlogic/media/utils/amports_config.h>
+#include "firmware.h"
+#include <linux/amlogic/tee.h>
+#include "../../../common/chips/decoder_cpu_ver_info.h"
+
+#define MC_SIZE (4096 * 16)
+
+#ifdef CONFIG_WAKELOCK
+static struct wake_lock amvdec_lock;
+struct timer_list amvdevtimer;
+#define WAKE_CHECK_INTERVAL (100*HZ/100)
+#endif
+#define AMVDEC_USE_STATIC_MEMORY
+static void *mc_addr;
+static dma_addr_t mc_addr_map;
+
+#ifdef CONFIG_WAKELOCK
+static int video_running;
+static int video_stated_changed = 1;
+#endif
+
+static void amvdec_pg_enable(bool enable)
+{
+ ulong timeout;
+
+ if (enable) {
+ AMVDEC_CLK_GATE_ON(MDEC_CLK_PIC_DC);
+ AMVDEC_CLK_GATE_ON(MDEC_CLK_DBLK);
+ AMVDEC_CLK_GATE_ON(MC_CLK);
+ AMVDEC_CLK_GATE_ON(IQIDCT_CLK);
+ /* AMVDEC_CLK_GATE_ON(VLD_CLK); */
+ AMVDEC_CLK_GATE_ON(AMRISC);
+ /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6TVD */
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M8)
+ WRITE_VREG(GCLK_EN, 0x3ff);
+ /* #endif */
+ CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 31);
+ } else {
+
+ AMVDEC_CLK_GATE_OFF(AMRISC);
+ timeout = jiffies + HZ / 100;
+
+ while (READ_VREG(MDEC_PIC_DC_STATUS) != 0) {
+ if (time_after(jiffies, timeout)) {
+ WRITE_VREG_BITS(MDEC_PIC_DC_CTRL, 1, 0, 1);
+ WRITE_VREG_BITS(MDEC_PIC_DC_CTRL, 0, 0, 1);
+ READ_VREG(MDEC_PIC_DC_STATUS);
+ READ_VREG(MDEC_PIC_DC_STATUS);
+ READ_VREG(MDEC_PIC_DC_STATUS);
+ break;
+ }
+ }
+
+ AMVDEC_CLK_GATE_OFF(MDEC_CLK_PIC_DC);
+ timeout = jiffies + HZ / 100;
+
+ while (READ_VREG(DBLK_STATUS) & 1) {
+ if (time_after(jiffies, timeout)) {
+ WRITE_VREG(DBLK_CTRL, 3);
+ WRITE_VREG(DBLK_CTRL, 0);
+ READ_VREG(DBLK_STATUS);
+ READ_VREG(DBLK_STATUS);
+ READ_VREG(DBLK_STATUS);
+ break;
+ }
+ }
+ AMVDEC_CLK_GATE_OFF(MDEC_CLK_DBLK);
+ timeout = jiffies + HZ / 100;
+
+ while (READ_VREG(MC_STATUS0) & 1) {
+ if (time_after(jiffies, timeout)) {
+ SET_VREG_MASK(MC_CTRL1, 0x9);
+ CLEAR_VREG_MASK(MC_CTRL1, 0x9);
+ READ_VREG(MC_STATUS0);
+ READ_VREG(MC_STATUS0);
+ READ_VREG(MC_STATUS0);
+ break;
+ }
+ }
+ AMVDEC_CLK_GATE_OFF(MC_CLK);
+ timeout = jiffies + HZ / 100;
+ while (READ_VREG(DCAC_DMA_CTRL) & 0x8000) {
+ if (time_after(jiffies, timeout))
+ break;
+ }
+ AMVDEC_CLK_GATE_OFF(IQIDCT_CLK);
+ /* AMVDEC_CLK_GATE_OFF(VLD_CLK); */
+ }
+}
+
+static void amvdec2_pg_enable(bool enable)
+{
+ if (has_vdec2()) {
+ ulong timeout;
+
+ if (!vdec_on(VDEC_2))
+ return;
+ if (enable) {
+ /* WRITE_VREG(VDEC2_GCLK_EN, 0x3ff); */
+ } else {
+ timeout = jiffies + HZ / 10;
+
+ while (READ_VREG(VDEC2_MDEC_PIC_DC_STATUS) != 0) {
+ if (time_after(jiffies, timeout)) {
+ WRITE_VREG_BITS(VDEC2_MDEC_PIC_DC_CTRL,
+ 1, 0, 1);
+ WRITE_VREG_BITS(VDEC2_MDEC_PIC_DC_CTRL,
+ 0, 0, 1);
+ READ_VREG(VDEC2_MDEC_PIC_DC_STATUS);
+ READ_VREG(VDEC2_MDEC_PIC_DC_STATUS);
+ READ_VREG(VDEC2_MDEC_PIC_DC_STATUS);
+ break;
+ }
+ }
+
+ timeout = jiffies + HZ / 10;
+
+ while (READ_VREG(VDEC2_DBLK_STATUS) & 1) {
+ if (time_after(jiffies, timeout)) {
+ WRITE_VREG(VDEC2_DBLK_CTRL, 3);
+ WRITE_VREG(VDEC2_DBLK_CTRL, 0);
+ READ_VREG(VDEC2_DBLK_STATUS);
+ READ_VREG(VDEC2_DBLK_STATUS);
+ READ_VREG(VDEC2_DBLK_STATUS);
+ break;
+ }
+ }
+
+ timeout = jiffies + HZ / 10;
+
+ while (READ_VREG(VDEC2_DCAC_DMA_CTRL) & 0x8000) {
+ if (time_after(jiffies, timeout))
+ break;
+ }
+ }
+ }
+}
+
+static void amhevc_pg_enable(bool enable)
+{
+ if (has_hevc_vdec()) {
+ ulong timeout;
+
+ if (!vdec_on(VDEC_HEVC))
+ return;
+ if (enable) {
+ /* WRITE_VREG(VDEC2_GCLK_EN, 0x3ff); */
+ } else {
+ timeout = jiffies + HZ / 10;
+
+ while (READ_VREG(HEVC_MDEC_PIC_DC_STATUS) != 0) {
+ if (time_after(jiffies, timeout)) {
+ WRITE_VREG_BITS(HEVC_MDEC_PIC_DC_CTRL,
+ 1, 0, 1);
+ WRITE_VREG_BITS(HEVC_MDEC_PIC_DC_CTRL,
+ 0, 0, 1);
+ READ_VREG(HEVC_MDEC_PIC_DC_STATUS);
+ READ_VREG(HEVC_MDEC_PIC_DC_STATUS);
+ READ_VREG(HEVC_MDEC_PIC_DC_STATUS);
+ break;
+ }
+ }
+
+ timeout = jiffies + HZ / 10;
+
+ while (READ_VREG(HEVC_DBLK_STATUS) & 1) {
+ if (time_after(jiffies, timeout)) {
+ WRITE_VREG(HEVC_DBLK_CTRL, 3);
+ WRITE_VREG(HEVC_DBLK_CTRL, 0);
+ READ_VREG(HEVC_DBLK_STATUS);
+ READ_VREG(HEVC_DBLK_STATUS);
+ READ_VREG(HEVC_DBLK_STATUS);
+ break;
+ }
+ }
+
+ timeout = jiffies + HZ / 10;
+
+ while (READ_VREG(HEVC_DCAC_DMA_CTRL) & 0x8000) {
+ if (time_after(jiffies, timeout))
+ break;
+ }
+ }
+ }
+}
+
+#ifdef CONFIG_WAKELOCK
+int amvdec_wake_lock(void)
+{
+ wake_lock(&amvdec_lock);
+ return 0;
+}
+
+int amvdec_wake_unlock(void)
+{
+ wake_unlock(&amvdec_lock);
+ return 0;
+}
+#else
+#define amvdec_wake_lock()
+#define amvdec_wake_unlock()
+#endif
+
+static s32 am_vdec_loadmc_ex(struct vdec_s *vdec,
+ const char *name, char *def, s32(*load)(const u32 *))
+{
+ int err;
+
+ if (!vdec->mc_loaded) {
+ if (!def) {
+ err = get_decoder_firmware_data(vdec->format,
+ name, (u8 *)(vdec->mc),
+ (4096 * 4 * 4));
+ if (err <= 0)
+ return -1;
+ } else
+ memcpy((char *)vdec->mc, def, sizeof(vdec->mc));
+
+ vdec->mc_loaded = true;
+ }
+
+ err = (*load)(vdec->mc);
+ if (err < 0) {
+ pr_err("loading firmware %s to vdec ram failed!\n", name);
+ return err;
+ }
+
+ return err;
+}
+
+static s32 am_vdec_loadmc_buf_ex(struct vdec_s *vdec,
+ char *buf, int size, s32(*load)(const u32 *))
+{
+ int err;
+
+ if (!vdec->mc_loaded) {
+ memcpy((u8 *)(vdec->mc), buf, size);
+ vdec->mc_loaded = true;
+ }
+
+ err = (*load)(vdec->mc);
+ if (err < 0) {
+ pr_err("loading firmware to vdec ram failed!\n");
+ return err;
+ }
+
+ return err;
+}
+
+static s32 am_loadmc_ex(enum vformat_e type,
+ const char *name, char *def, s32(*load)(const u32 *))
+{
+ char *mc_addr = vmalloc(4096 * 16);
+ char *pmc_addr = def;
+ int err;
+
+ if (!def && mc_addr) {
+ int loaded;
+
+ loaded = get_decoder_firmware_data(type,
+ name, mc_addr, (4096 * 16));
+ if (loaded > 0)
+ pmc_addr = mc_addr;
+ }
+ if (!pmc_addr) {
+ vfree(mc_addr);
+ return -1;
+ }
+ err = (*load)((u32 *) pmc_addr);
+ if (err < 0) {
+ pr_err("loading firmware %s to vdec ram failed!\n", name);
+ vfree(mc_addr);
+ return err;
+ }
+ vfree(mc_addr);
+
+ return err;
+}
+
+static s32 amvdec_loadmc(const u32 *p)
+{
+ ulong timeout;
+ s32 ret = 0;
+
+#ifdef AMVDEC_USE_STATIC_MEMORY
+ if (mc_addr == NULL) {
+#else
+ {
+#endif
+ mc_addr = kmalloc(MC_SIZE, GFP_KERNEL);
+ }
+
+ if (!mc_addr)
+ return -ENOMEM;
+
+ memcpy(mc_addr, p, MC_SIZE);
+
+ mc_addr_map = dma_map_single(get_vdec_device(),
+ mc_addr, MC_SIZE, DMA_TO_DEVICE);
+
+ WRITE_VREG(MPSR, 0);
+ WRITE_VREG(CPSR, 0);
+
+ /* Read CBUS register for timing */
+ timeout = READ_VREG(MPSR);
+ timeout = READ_VREG(MPSR);
+
+ timeout = jiffies + HZ;
+
+ WRITE_VREG(IMEM_DMA_ADR, mc_addr_map);
+ WRITE_VREG(IMEM_DMA_COUNT, 0x1000);
+ WRITE_VREG(IMEM_DMA_CTRL, (0x8000 | (7 << 16)));
+
+ while (READ_VREG(IMEM_DMA_CTRL) & 0x8000) {
+ if (time_before(jiffies, timeout))
+ schedule();
+ else {
+ pr_err("vdec load mc error\n");
+ ret = -EBUSY;
+ break;
+ }
+ }
+
+ dma_unmap_single(get_vdec_device(),
+ mc_addr_map, MC_SIZE, DMA_TO_DEVICE);
+
+#ifndef AMVDEC_USE_STATIC_MEMORY
+ kfree(mc_addr);
+ mc_addr = NULL;
+#endif
+
+ return ret;
+}
+
+s32 optee_load_fw(enum vformat_e type, const char *fw_name)
+{
+ s32 ret = -1;
+ unsigned int format = FIRMWARE_MAX;
+ unsigned int vdec = OPTEE_VDEC_LEGENCY;
+ char *name = __getname();
+ bool is_swap = false;
+
+ sprintf(name, "%s", fw_name ? fw_name : "null");
+
+ switch ((u32)type) {
+ case VFORMAT_VC1:
+ format = VIDEO_DEC_VC1;
+ break;
+
+ case VFORMAT_AVS:
+ if (!strcmp(name, "avs_no_cabac"))
+ format = VIDEO_DEC_AVS_NOCABAC;
+ else if (!strcmp(name, "avs_multi"))
+ format = VIDEO_DEC_AVS_MULTI;
+ else
+ format = VIDEO_DEC_AVS;
+ break;
+
+ case VFORMAT_MPEG12:
+ if (!strcmp(name, "mpeg12"))
+ format = VIDEO_DEC_MPEG12;
+ else if (!strcmp(name, "mmpeg12"))
+ format = VIDEO_DEC_MPEG12_MULTI;
+ break;
+
+ case VFORMAT_MJPEG:
+ if (!strcmp(name, "mmjpeg"))
+ format = VIDEO_DEC_MJPEG_MULTI;
+ else
+ format = VIDEO_DEC_MJPEG;
+ break;
+
+ case VFORMAT_VP9:
+ if (!strcmp(name, "vp9_mc"))
+ format = VIDEO_DEC_VP9;
+ else
+ format = VIDEO_DEC_VP9_MMU;
+ break;
+
+ case VFORMAT_AVS2:
+ format = VIDEO_DEC_AVS2_MMU;
+ vdec = OPTEE_VDEC_HEVC;
+ break;
+
+ case VFORMAT_AV1:
+ format = VIDEO_DEC_AV1_MMU;
+ vdec = OPTEE_VDEC_HEVC;
+ break;
+
+ case VFORMAT_HEVC:
+ if (!strcmp(name, "h265_mmu"))
+ format = VIDEO_DEC_HEVC_MMU;
+ else if (!strcmp(name, "hevc_mmu_swap")) {
+ format = VIDEO_DEC_HEVC_MMU_SWAP;
+ vdec = OPTEE_VDEC_HEVC;
+ is_swap = true;
+ } else
+ format = VIDEO_DEC_HEVC;
+ break;
+
+ case VFORMAT_REAL:
+ if (!strcmp(name, "vreal_mc_8"))
+ format = VIDEO_DEC_REAL_V8;
+ else if (!strcmp(name, "vreal_mc_9"))
+ format = VIDEO_DEC_REAL_V9;
+ break;
+
+ case VFORMAT_MPEG4:
+ if (!strcmp(name, "mmpeg4_mc_5"))
+ format = VIDEO_DEC_MPEG4_5_MULTI;
+ else if ((!strcmp(name, "mh263_mc")))
+ format = VIDEO_DEC_H263_MULTI;
+ else if (!strcmp(name, "vmpeg4_mc_5"))
+ format = VIDEO_DEC_MPEG4_5;
+ else if (!strcmp(name, "h263_mc"))
+ format = VIDEO_DEC_H263;
+ /*not support now*/
+ else if (!strcmp(name, "vmpeg4_mc_311"))
+ format = VIDEO_DEC_MPEG4_3;
+ else if (!strcmp(name, "vmpeg4_mc_4"))
+ format = VIDEO_DEC_MPEG4_4;
+ break;
+
+ case VFORMAT_H264_4K2K:
+ if (!strcmp(name, "single_core"))
+ format = VIDEO_DEC_H264_4k2K_SINGLE;
+ else
+ format = VIDEO_DEC_H264_4k2K;
+ break;
+
+ case VFORMAT_H264MVC:
+ format = VIDEO_DEC_H264_MVC;
+ break;
+
+ case VFORMAT_H264:
+ if (!strcmp(name, "mh264"))
+ format = VIDEO_DEC_H264_MULTI;
+ else if (!strcmp(name, "mh264_mmu")) {
+ format = VIDEO_DEC_H264_MULTI_MMU;
+ vdec = OPTEE_VDEC_HEVC;
+ } else
+ format = VIDEO_DEC_H264;
+ break;
+
+ default:
+ pr_info("Unknow vdec format!\n");
+ break;
+ }
+
+ if (format < FIRMWARE_MAX) {
+ if (is_swap)
+ ret = tee_load_video_fw_swap(format, vdec, is_swap);
+ else
+ ret = tee_load_video_fw(format, vdec);
+ }
+
+ __putname(name);
+
+ return ret;
+}
+EXPORT_SYMBOL(optee_load_fw);
+
+s32 amvdec_loadmc_ex(enum vformat_e type, const char *name, char *def)
+{
+ if (tee_enabled())
+ return optee_load_fw(type, name);
+ else
+ return am_loadmc_ex(type, name, def, &amvdec_loadmc);
+}
+EXPORT_SYMBOL(amvdec_loadmc_ex);
+
+s32 amvdec_vdec_loadmc_ex(enum vformat_e type, const char *name,
+ struct vdec_s *vdec, char *def)
+{
+ if (tee_enabled())
+ return optee_load_fw(type, name);
+ else
+ return am_vdec_loadmc_ex(vdec, name, def, &amvdec_loadmc);
+}
+EXPORT_SYMBOL(amvdec_vdec_loadmc_ex);
+
+s32 amvdec_vdec_loadmc_buf_ex(enum vformat_e type, const char *name,
+ struct vdec_s *vdec, char *buf, int size)
+{
+ if (tee_enabled())
+ return optee_load_fw(type, name);
+ else
+ return am_vdec_loadmc_buf_ex(vdec, buf, size, &amvdec_loadmc);
+}
+EXPORT_SYMBOL(amvdec_vdec_loadmc_buf_ex);
+
+static s32 amvdec2_loadmc(const u32 *p)
+{
+ if (has_vdec2()) {
+ ulong timeout;
+ s32 ret = 0;
+
+#ifdef AMVDEC_USE_STATIC_MEMORY
+ if (mc_addr == NULL) {
+#else
+ {
+#endif
+ mc_addr = kmalloc(MC_SIZE, GFP_KERNEL);
+ }
+
+ if (!mc_addr)
+ return -ENOMEM;
+
+ memcpy(mc_addr, p, MC_SIZE);
+
+ mc_addr_map = dma_map_single(get_vdec_device(),
+ mc_addr, MC_SIZE, DMA_TO_DEVICE);
+
+ WRITE_VREG(VDEC2_MPSR, 0);
+ WRITE_VREG(VDEC2_CPSR, 0);
+
+ /* Read CBUS register for timing */
+ timeout = READ_VREG(VDEC2_MPSR);
+ timeout = READ_VREG(VDEC2_MPSR);
+
+ timeout = jiffies + HZ;
+
+ WRITE_VREG(VDEC2_IMEM_DMA_ADR, mc_addr_map);
+ WRITE_VREG(VDEC2_IMEM_DMA_COUNT, 0x1000);
+ WRITE_VREG(VDEC2_IMEM_DMA_CTRL, (0x8000 | (7 << 16)));
+
+ while (READ_VREG(VDEC2_IMEM_DMA_CTRL) & 0x8000) {
+ if (time_before(jiffies, timeout))
+ schedule();
+ else {
+ pr_err("vdec2 load mc error\n");
+ ret = -EBUSY;
+ break;
+ }
+ }
+
+ dma_unmap_single(get_vdec_device(),
+ mc_addr_map, MC_SIZE, DMA_TO_DEVICE);
+
+#ifndef AMVDEC_USE_STATIC_MEMORY
+ kfree(mc_addr);
+ mc_addr = NULL;
+#endif
+
+ return ret;
+ } else
+ return 0;
+}
+
+s32 amvdec2_loadmc_ex(enum vformat_e type, const char *name, char *def)
+{
+ if (has_vdec2())
+ return am_loadmc_ex(type, name, def, &amvdec2_loadmc);
+ else
+ return 0;
+}
+EXPORT_SYMBOL(amvdec2_loadmc_ex);
+
+s32 amhcodec_loadmc(const u32 *p)
+{
+#ifdef AMVDEC_USE_STATIC_MEMORY
+ if (mc_addr == NULL) {
+#else
+ {
+#endif
+ mc_addr = kmalloc(MC_SIZE, GFP_KERNEL);
+ }
+
+ if (!mc_addr)
+ return -ENOMEM;
+
+ memcpy(mc_addr, p, MC_SIZE);
+
+ mc_addr_map = dma_map_single(get_vdec_device(),
+ mc_addr, MC_SIZE, DMA_TO_DEVICE);
+
+ WRITE_VREG(HCODEC_IMEM_DMA_ADR, mc_addr_map);
+ WRITE_VREG(HCODEC_IMEM_DMA_COUNT, 0x100);
+ WRITE_VREG(HCODEC_IMEM_DMA_CTRL, (0x8000 | (7 << 16)));
+
+ while (READ_VREG(HCODEC_IMEM_DMA_CTRL) & 0x8000)
+ udelay(1000);
+
+ dma_unmap_single(get_vdec_device(),
+ mc_addr_map, MC_SIZE, DMA_TO_DEVICE);
+
+#ifndef AMVDEC_USE_STATIC_MEMORY
+ kfree(mc_addr);
+#endif
+
+ return 0;
+}
+EXPORT_SYMBOL(amhcodec_loadmc);
+
+s32 amhcodec_loadmc_ex(enum vformat_e type, const char *name, char *def)
+{
+ return am_loadmc_ex(type, name, def, &amhcodec_loadmc);
+}
+EXPORT_SYMBOL(amhcodec_loadmc_ex);
+
+static s32 amhevc_loadmc(const u32 *p)
+{
+ ulong timeout;
+ s32 ret = 0;
+
+ if (has_hevc_vdec()) {
+#ifdef AMVDEC_USE_STATIC_MEMORY
+ if (mc_addr == NULL) {
+#else
+ {
+#endif
+ mc_addr = kmalloc(MC_SIZE, GFP_KERNEL);
+ }
+
+ if (!mc_addr)
+ return -ENOMEM;
+
+ memcpy(mc_addr, p, MC_SIZE);
+
+ mc_addr_map =
+ dma_map_single(get_vdec_device(),
+ mc_addr, MC_SIZE, DMA_TO_DEVICE);
+
+ WRITE_VREG(HEVC_MPSR, 0);
+ WRITE_VREG(HEVC_CPSR, 0);
+
+ /* Read CBUS register for timing */
+ timeout = READ_VREG(HEVC_MPSR);
+ timeout = READ_VREG(HEVC_MPSR);
+
+ timeout = jiffies + HZ;
+
+ WRITE_VREG(HEVC_IMEM_DMA_ADR, mc_addr_map);
+ WRITE_VREG(HEVC_IMEM_DMA_COUNT, 0x1000);
+ WRITE_VREG(HEVC_IMEM_DMA_CTRL, (0x8000 | (7 << 16)));
+
+ while (READ_VREG(HEVC_IMEM_DMA_CTRL) & 0x8000) {
+ if (time_before(jiffies, timeout))
+ schedule();
+ else {
+ pr_err("vdec2 load mc error\n");
+ ret = -EBUSY;
+ break;
+ }
+ }
+
+ dma_unmap_single(get_vdec_device(),
+ mc_addr_map, MC_SIZE, DMA_TO_DEVICE);
+
+#ifndef AMVDEC_USE_STATIC_MEMORY
+ kfree(mc_addr);
+ mc_addr = NULL;
+#endif
+ }
+
+ return ret;
+}
+
+s32 amhevc_loadmc_ex(enum vformat_e type, const char *name, char *def)
+{
+ if (has_hevc_vdec())
+ if (tee_enabled())
+ return optee_load_fw(type, name);
+ else
+ return am_loadmc_ex(type, name, def, &amhevc_loadmc);
+ else
+ return -1;
+}
+EXPORT_SYMBOL(amhevc_loadmc_ex);
+
+s32 amhevc_vdec_loadmc_ex(enum vformat_e type, struct vdec_s *vdec,
+ const char *name, char *def)
+{
+ if (has_hevc_vdec())
+ if (tee_enabled())
+ return optee_load_fw(type, name);
+ else
+ return am_vdec_loadmc_ex(vdec, name, def, &amhevc_loadmc);
+ else
+ return -1;
+}
+EXPORT_SYMBOL(amhevc_vdec_loadmc_ex);
+
+void amvdec_start(void)
+{
+#ifdef CONFIG_WAKELOCK
+ amvdec_wake_lock();
+#endif
+
+ /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M6) {
+ READ_VREG(DOS_SW_RESET0);
+ READ_VREG(DOS_SW_RESET0);
+ READ_VREG(DOS_SW_RESET0);
+
+ WRITE_VREG(DOS_SW_RESET0, (1 << 12) | (1 << 11));
+ WRITE_VREG(DOS_SW_RESET0, 0);
+
+ READ_VREG(DOS_SW_RESET0);
+ READ_VREG(DOS_SW_RESET0);
+ READ_VREG(DOS_SW_RESET0);
+ } else {
+ /* #else */
+ /* additional cbus dummy register reading for timing control */
+ READ_RESET_REG(RESET0_REGISTER);
+ READ_RESET_REG(RESET0_REGISTER);
+ READ_RESET_REG(RESET0_REGISTER);
+ READ_RESET_REG(RESET0_REGISTER);
+
+ WRITE_RESET_REG(RESET0_REGISTER, RESET_VCPU | RESET_CCPU);
+
+ READ_RESET_REG(RESET0_REGISTER);
+ READ_RESET_REG(RESET0_REGISTER);
+ READ_RESET_REG(RESET0_REGISTER);
+ }
+ /* #endif */
+
+ WRITE_VREG(MPSR, 0x0001);
+}
+EXPORT_SYMBOL(amvdec_start);
+
+void amvdec2_start(void)
+{
+ if (has_vdec2()) {
+#ifdef CONFIG_WAKELOCK
+ amvdec_wake_lock();
+#endif
+
+ READ_VREG(DOS_SW_RESET2);
+ READ_VREG(DOS_SW_RESET2);
+ READ_VREG(DOS_SW_RESET2);
+
+ WRITE_VREG(DOS_SW_RESET2, (1 << 12) | (1 << 11));
+ WRITE_VREG(DOS_SW_RESET2, 0);
+
+ READ_VREG(DOS_SW_RESET2);
+ READ_VREG(DOS_SW_RESET2);
+ READ_VREG(DOS_SW_RESET2);
+
+ WRITE_VREG(VDEC2_MPSR, 0x0001);
+ }
+}
+EXPORT_SYMBOL(amvdec2_start);
+
+void amhcodec_start(void)
+{
+ WRITE_VREG(HCODEC_MPSR, 0x0001);
+}
+EXPORT_SYMBOL(amhcodec_start);
+
+void amhevc_start(void)
+{
+
+ if (has_hevc_vdec()) {
+#ifdef CONFIG_WAKELOCK
+ amvdec_wake_lock();
+#endif
+
+ READ_VREG(DOS_SW_RESET3);
+ READ_VREG(DOS_SW_RESET3);
+ READ_VREG(DOS_SW_RESET3);
+
+ WRITE_VREG(DOS_SW_RESET3, (1 << 12) | (1 << 11));
+ WRITE_VREG(DOS_SW_RESET3, 0);
+
+ READ_VREG(DOS_SW_RESET3);
+ READ_VREG(DOS_SW_RESET3);
+ READ_VREG(DOS_SW_RESET3);
+
+ WRITE_VREG(HEVC_MPSR, 0x0001);
+ }
+}
+EXPORT_SYMBOL(amhevc_start);
+
+void amvdec_stop(void)
+{
+ ulong timeout = jiffies + HZ/10;
+
+ WRITE_VREG(MPSR, 0);
+ WRITE_VREG(CPSR, 0);
+
+ while (READ_VREG(IMEM_DMA_CTRL) & 0x8000) {
+ if (time_after(jiffies, timeout))
+ break;
+ }
+
+ timeout = jiffies + HZ/10;
+ while (READ_VREG(LMEM_DMA_CTRL) & 0x8000) {
+ if (time_after(jiffies, timeout))
+ break;
+ }
+
+ /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M6) {
+ READ_VREG(DOS_SW_RESET0);
+ READ_VREG(DOS_SW_RESET0);
+ READ_VREG(DOS_SW_RESET0);
+
+ WRITE_VREG(DOS_SW_RESET0, (1 << 12) | (1 << 11));
+ WRITE_VREG(DOS_SW_RESET0, 0);
+
+ READ_VREG(DOS_SW_RESET0);
+ READ_VREG(DOS_SW_RESET0);
+ READ_VREG(DOS_SW_RESET0);
+ } else {
+ /* #else */
+ WRITE_RESET_REG(RESET0_REGISTER, RESET_VCPU | RESET_CCPU);
+
+ /* additional cbus dummy register reading for timing control */
+ READ_RESET_REG(RESET0_REGISTER);
+ READ_RESET_REG(RESET0_REGISTER);
+ READ_RESET_REG(RESET0_REGISTER);
+ READ_RESET_REG(RESET0_REGISTER);
+ }
+ /* #endif */
+
+#ifdef CONFIG_WAKELOCK
+ amvdec_wake_unlock();
+#endif
+}
+EXPORT_SYMBOL(amvdec_stop);
+
+void amvdec2_stop(void)
+{
+ if (has_vdec2()) {
+ ulong timeout = jiffies + HZ/10;
+
+ WRITE_VREG(VDEC2_MPSR, 0);
+ WRITE_VREG(VDEC2_CPSR, 0);
+
+ while (READ_VREG(VDEC2_IMEM_DMA_CTRL) & 0x8000) {
+ if (time_after(jiffies, timeout))
+ break;
+ }
+
+ READ_VREG(DOS_SW_RESET2);
+ READ_VREG(DOS_SW_RESET2);
+ READ_VREG(DOS_SW_RESET2);
+
+#ifdef CONFIG_WAKELOCK
+ amvdec_wake_unlock();
+#endif
+ }
+}
+EXPORT_SYMBOL(amvdec2_stop);
+
+void amhcodec_stop(void)
+{
+ WRITE_VREG(HCODEC_MPSR, 0);
+}
+EXPORT_SYMBOL(amhcodec_stop);
+
+void amhevc_stop(void)
+{
+ if (has_hevc_vdec()) {
+ ulong timeout = jiffies + HZ/10;
+
+ WRITE_VREG(HEVC_MPSR, 0);
+ WRITE_VREG(HEVC_CPSR, 0);
+
+ while (READ_VREG(HEVC_IMEM_DMA_CTRL) & 0x8000) {
+ if (time_after(jiffies, timeout))
+ break;
+ }
+
+ timeout = jiffies + HZ/10;
+ while (READ_VREG(HEVC_LMEM_DMA_CTRL) & 0x8000) {
+ if (time_after(jiffies, timeout))
+ break;
+ }
+
+ READ_VREG(DOS_SW_RESET3);
+ READ_VREG(DOS_SW_RESET3);
+ READ_VREG(DOS_SW_RESET3);
+
+#ifdef CONFIG_WAKELOCK
+ amvdec_wake_unlock();
+#endif
+ }
+}
+EXPORT_SYMBOL(amhevc_stop);
+
+void amvdec_enable(void)
+{
+ amvdec_pg_enable(true);
+}
+EXPORT_SYMBOL(amvdec_enable);
+
+void amvdec_disable(void)
+{
+ amvdec_pg_enable(false);
+}
+EXPORT_SYMBOL(amvdec_disable);
+
+void amvdec2_enable(void)
+{
+ if (has_vdec2())
+ amvdec2_pg_enable(true);
+}
+EXPORT_SYMBOL(amvdec2_enable);
+
+void amvdec2_disable(void)
+{
+ if (has_vdec2())
+ amvdec2_pg_enable(false);
+}
+EXPORT_SYMBOL(amvdec2_disable);
+
+void amhevc_enable(void)
+{
+ if (has_hevc_vdec())
+ amhevc_pg_enable(true);
+}
+EXPORT_SYMBOL(amhevc_enable);
+
+void amhevc_disable(void)
+{
+ if (has_hevc_vdec())
+ amhevc_pg_enable(false);
+}
+EXPORT_SYMBOL(amhevc_disable);
+
+#ifdef CONFIG_PM
+int amvdec_suspend(struct platform_device *dev, pm_message_t event)
+{
+ amvdec_pg_enable(false);
+
+ /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6TVD */
+ if (has_vdec2())
+ amvdec2_pg_enable(false);
+ /* #endif */
+
+ if (has_hevc_vdec())
+ amhevc_pg_enable(false);
+ /*vdec_set_suspend_clk(1, 0);*//*DEBUG_TMP*/
+ return 0;
+}
+EXPORT_SYMBOL(amvdec_suspend);
+
+int amvdec_resume(struct platform_device *dev)
+{
+ amvdec_pg_enable(true);
+
+ /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6TVD */
+ if (has_vdec2())
+ amvdec2_pg_enable(true);
+ /* #endif */
+
+ /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
+ if (has_hevc_vdec())
+ amhevc_pg_enable(true);
+ /* #endif */
+ /*vdec_set_suspend_clk(0, 0);*//*DEBUG_TMP*/
+ return 0;
+}
+EXPORT_SYMBOL(amvdec_resume);
+
+int amhevc_suspend(struct platform_device *dev, pm_message_t event)
+{
+ if (has_hevc_vdec()) {
+ amhevc_pg_enable(false);
+ /*vdec_set_suspend_clk(1, 1);*//*DEBUG_TMP*/
+ }
+ return 0;
+}
+EXPORT_SYMBOL(amhevc_suspend);
+
+int amhevc_resume(struct platform_device *dev)
+{
+ if (has_hevc_vdec()) {
+ amhevc_pg_enable(true);
+ /*vdec_set_suspend_clk(0, 1);*//*DEBUG_TMP*/
+ }
+ return 0;
+}
+EXPORT_SYMBOL(amhevc_resume);
+
+
+#endif
+
+#ifdef CONFIG_WAKELOCK
+
+static int vdec_is_paused(void)
+{
+ static unsigned long old_wp = -1, old_rp = -1, old_level = -1;
+ unsigned long wp, rp, level;
+ static int paused_time;
+
+ /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
+ if (has_hevc_vdec()) {
+ if ((vdec_on(VDEC_HEVC))
+ && (READ_VREG(HEVC_STREAM_CONTROL) & 1)) {
+ wp = READ_VREG(HEVC_STREAM_WR_PTR);
+ rp = READ_VREG(HEVC_STREAM_RD_PTR);
+ level = READ_VREG(HEVC_STREAM_LEVEL);
+ } else {
+ wp = READ_VREG(VLD_MEM_VIFIFO_WP);
+ rp = READ_VREG(VLD_MEM_VIFIFO_RP);
+ level = READ_VREG(VLD_MEM_VIFIFO_LEVEL);
+ }
+ } else
+ /* #endif */
+ {
+ wp = READ_VREG(VLD_MEM_VIFIFO_WP);
+ rp = READ_VREG(VLD_MEM_VIFIFO_RP);
+ level = READ_VREG(VLD_MEM_VIFIFO_LEVEL);
+ }
+ /*have data,but output buffer is full */
+ if ((rp == old_rp && level > 1024) ||
+ (rp == old_rp && wp == old_wp && level == old_level)) {
+ /*no write && not read */
+ paused_time++;
+ } else {
+ paused_time = 0;
+ }
+ old_wp = wp; old_rp = rp; old_level = level;
+ if (paused_time > 10)
+ return 1;
+ return 0;
+}
+
+int amvdev_pause(void)
+{
+ video_running = 0;
+ video_stated_changed = 1;
+ return 0;
+}
+EXPORT_SYMBOL(amvdev_pause);
+
+int amvdev_resume(void)
+{
+ video_running = 1;
+ video_stated_changed = 1;
+ return 0;
+}
+EXPORT_SYMBOL(amvdev_resume);
+
+static void vdec_paused_check_timer(unsigned long arg)
+{
+ if (video_stated_changed) {
+ if (!video_running) {
+ if (vdec_is_paused()) {
+ pr_info("vdec paused and release wakelock now\n");
+ amvdec_wake_unlock();
+ video_stated_changed = 0;
+ }
+ } else {
+ amvdec_wake_lock();
+ video_stated_changed = 0;
+ }
+ }
+ mod_timer(&amvdevtimer, jiffies + WAKE_CHECK_INTERVAL);
+}
+#else
+int amvdev_pause(void)
+{
+ return 0;
+}
+
+int amvdev_resume(void)
+{
+ return 0;
+}
+#endif
+
+int amvdec_init(void)
+{
+#ifdef CONFIG_WAKELOCK
+ /*
+ *wake_lock_init(&amvdec_lock, WAKE_LOCK_IDLE, "amvdec_lock");
+ *tmp mark for compile, no "WAKE_LOCK_IDLE" definition in kernel 3.8
+ */
+ wake_lock_init(&amvdec_lock, /*WAKE_LOCK_IDLE */ WAKE_LOCK_SUSPEND,
+ "amvdec_lock");
+
+ init_timer(&amvdevtimer);
+
+ amvdevtimer.data = (ulong) &amvdevtimer;
+ amvdevtimer.function = vdec_paused_check_timer;
+#endif
+ return 0;
+}
+EXPORT_SYMBOL(amvdec_init);
+
+void amvdec_exit(void)
+{
+#ifdef CONFIG_WAKELOCK
+ del_timer_sync(&amvdevtimer);
+#endif
+}
+EXPORT_SYMBOL(amvdec_exit);
+
+#if 0
+int __init amvdec_init(void)
+{
+#ifdef CONFIG_WAKELOCK
+ /*
+ *wake_lock_init(&amvdec_lock, WAKE_LOCK_IDLE, "amvdec_lock");
+ *tmp mark for compile, no "WAKE_LOCK_IDLE" definition in kernel 3.8
+ */
+ wake_lock_init(&amvdec_lock, /*WAKE_LOCK_IDLE */ WAKE_LOCK_SUSPEND,
+ "amvdec_lock");
+
+ init_timer(&amvdevtimer);
+
+ amvdevtimer.data = (ulong) &amvdevtimer;
+ amvdevtimer.function = vdec_paused_check_timer;
+#endif
+ return 0;
+}
+
+static void __exit amvdec_exit(void)
+{
+#ifdef CONFIG_WAKELOCK
+ del_timer_sync(&amvdevtimer);
+#endif
+}
+
+module_init(amvdec_init);
+module_exit(amvdec_exit);
+
+
+MODULE_DESCRIPTION("Amlogic Video Decoder Utility Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tim Yao <timyao@amlogic.com>");
+#endif
diff --git a/drivers/frame_provider/decoder/utils/amvdec.h b/drivers/frame_provider/decoder/utils/amvdec.h
new file mode 100644
index 0000000..a3deecd
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/amvdec.h
@@ -0,0 +1,91 @@
+/*
+ * drivers/amlogic/media/frame_provider/decoder/utils/amvdec.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 AMVDEC_H
+#define AMVDEC_H
+#include <linux/amlogic/media/utils/amports_config.h>
+#include <linux/amlogic/media/utils/vformat.h>
+#include "vdec.h"
+
+#define UCODE_ALIGN 8
+#define UCODE_ALIGN_MASK 7UL
+
+struct amvdec_dec_reg_s {
+ unsigned long mem_start;
+ unsigned long mem_end;
+ struct device *cma_dev;
+ struct dec_sysinfo *dec_sysinfo;
+}; /*amvdec_dec_reg_t */
+
+struct vdec_s;
+
+extern void amvdec_start(void);
+extern void amvdec_stop(void);
+extern void amvdec_enable(void);
+extern void amvdec_disable(void);
+s32 amvdec_loadmc_ex(enum vformat_e type, const char *name, char *def);
+s32 amvdec_vdec_loadmc_ex(enum vformat_e type, const char *name,
+ struct vdec_s *vdec, char *def);
+
+extern void amvdec2_start(void);
+extern void amvdec2_stop(void);
+extern void amvdec2_enable(void);
+extern void amvdec2_disable(void);
+s32 amvdec2_loadmc_ex(enum vformat_e type, const char *name, char *def);
+
+extern void amhevc_start(void);
+extern void amhevc_stop(void);
+extern void amhevc_enable(void);
+extern void amhevc_disable(void);
+s32 amhevc_loadmc_ex(enum vformat_e type, const char *name, char *def);
+s32 amhevc_vdec_loadmc_ex(enum vformat_e type, struct vdec_s *vdec,
+ const char *name, char *def);
+s32 amvdec_vdec_loadmc_buf_ex(enum vformat_e type, const char *name,
+ struct vdec_s *vdec, char *buf, int size);
+
+extern void amhcodec_start(void);
+extern void amhcodec_stop(void);
+s32 amhcodec_loadmc(const u32 *p);
+s32 amhcodec_loadmc_ex(enum vformat_e type, const char *name, char *def);
+
+extern int amvdev_pause(void);
+extern int amvdev_resume(void);
+
+#ifdef CONFIG_PM
+extern int amvdec_suspend(struct platform_device *dev, pm_message_t event);
+extern int amvdec_resume(struct platform_device *dec);
+extern int amhevc_suspend(struct platform_device *dev, pm_message_t event);
+extern int amhevc_resume(struct platform_device *dec);
+
+#endif
+
+int amvdec_init(void);
+void amvdec_exit(void);
+
+#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+#define AMVDEC_CLK_GATE_ON(a)
+#define AMVDEC_CLK_GATE_OFF(a)
+#else
+#define AMVDEC_CLK_GATE_ON(a) CLK_GATE_ON(a)
+#define AMVDEC_CLK_GATE_OFF(a) CLK_GATE_OFF(a)
+#endif
+
+/* TODO: move to register headers */
+#define RESET_VCPU (1<<7)
+#define RESET_CCPU (1<<8)
+
+#endif /* AMVDEC_H */
diff --git a/drivers/frame_provider/decoder/utils/config_parser.c b/drivers/frame_provider/decoder/utils/config_parser.c
new file mode 100644
index 0000000..9a65620
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/config_parser.c
@@ -0,0 +1,64 @@
+/*
+ * drivers/amlogic/amports/config_parser.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 "config_parser.h"
+/*
+ *sample config:
+ *configs: width:1920;height:1080;
+ *need:width
+ *ok: return 0;
+ **val = value;
+ */
+int get_config_int(const char *configs, const char *need, int *val)
+{
+ const char *str;
+ int ret;
+ int lval = 0;
+ *val = 0;
+
+ if (!configs || !need)
+ return -1;
+ str = strstr(configs, need);
+ if (str != NULL) {
+ if (str > configs && str[-1] != ';') {
+ /*
+ * if not the first config val.
+ * make sure before is ';'
+ * to recognize:
+ * ;crop_width:100
+ * ;width:100
+ */
+ return -2;
+ }
+ str += strlen(need);
+ if (str[0] != ':' || str[1] == '\0')
+ return -3;
+ ret = sscanf(str, ":%d", &lval);
+ if (ret == 1) {
+ *val = lval;
+ return 0;
+ }
+ }
+
+ return -4;
+}
+EXPORT_SYMBOL(get_config_int);
+
diff --git a/drivers/frame_provider/decoder/utils/config_parser.h b/drivers/frame_provider/decoder/utils/config_parser.h
new file mode 100644
index 0000000..9746caf
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/config_parser.h
@@ -0,0 +1,21 @@
+/*
+ * drivers/amlogic/amports/config_parser.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.
+ *
+ */
+#ifndef CONFIG_PARSER_HHH_
+#define CONFIG_PARSER_HHH_
+int get_config_int(const char *configs, const char *need, int *val);
+
+#endif/*CONFIG_PARSER_HHH_*/
diff --git a/drivers/frame_provider/decoder/utils/decoder_bmmu_box.c b/drivers/frame_provider/decoder/utils/decoder_bmmu_box.c
new file mode 100644
index 0000000..461621b
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/decoder_bmmu_box.c
@@ -0,0 +1,607 @@
+/*
+ * drivers/amlogic/amports/decoder/decoder_bmmu_box.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/slab.h>
+#include <linux/amlogic/media/codec_mm/codec_mm_scatter.h>
+#include <linux/platform_device.h>
+
+#include <linux/amlogic/media/video_sink/video_keeper.h>
+#include "decoder_bmmu_box.h"
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include <linux/amlogic/media/codec_mm/codec_mm_keeper.h>
+
+struct decoder_bmmu_box {
+ int max_mm_num;
+ const char *name;
+ int channel_id;
+ struct mutex mutex;
+ struct list_head list;
+ int total_size;
+ int box_ref_cnt;
+ int change_size_on_need_smaller;
+ int align2n; /*can overwite on idx alloc */
+ int mem_flags; /*can overwite on idx alloc */
+ struct codec_mm_s *mm_list[1];
+};
+
+struct decoder_bmmu_box_mgr {
+ int num;
+ struct mutex mutex;
+ struct list_head box_list;
+};
+static struct decoder_bmmu_box_mgr global_blk_mgr;
+static struct decoder_bmmu_box_mgr *get_decoder_bmmu_box_mgr(void)
+{
+ return &global_blk_mgr;
+}
+
+static int decoder_bmmu_box_mgr_add_box(struct decoder_bmmu_box *box)
+{
+ struct decoder_bmmu_box_mgr *mgr = get_decoder_bmmu_box_mgr();
+
+ mutex_lock(&mgr->mutex);
+ list_add_tail(&box->list, &mgr->box_list);
+ mutex_unlock(&mgr->mutex);
+ return 0;
+}
+
+static int decoder_bmmu_box_mgr_del_box(struct decoder_bmmu_box *box)
+{
+ struct decoder_bmmu_box_mgr *mgr = get_decoder_bmmu_box_mgr();
+
+ mutex_lock(&mgr->mutex);
+ list_del(&box->list);
+ mutex_unlock(&mgr->mutex);
+ return 0;
+}
+
+bool decoder_bmmu_box_valide_check(void *box)
+{
+ struct decoder_bmmu_box_mgr *mgr = get_decoder_bmmu_box_mgr();
+ struct decoder_bmmu_box *bmmu_box = NULL;
+ bool is_valide = false;
+
+ mutex_lock(&mgr->mutex);
+ list_for_each_entry(bmmu_box, &mgr->box_list, list) {
+ if (bmmu_box && bmmu_box == box) {
+ is_valide = true;
+ break;
+ }
+ }
+ mutex_unlock(&mgr->mutex);
+
+ return is_valide;
+}
+EXPORT_SYMBOL(decoder_bmmu_box_valide_check);
+
+void *decoder_bmmu_box_alloc_box(const char *name,
+ int channel_id, int max_num,
+ int aligned, int mem_flags)
+/*min_size_M:wait alloc this size*/
+{
+ struct decoder_bmmu_box *box;
+ int size;
+ int tvp_flags;
+ tvp_flags = (mem_flags & CODEC_MM_FLAGS_TVP) ?
+ CODEC_MM_FLAGS_TVP : 0;
+
+ pr_debug("decoder_bmmu_box_alloc_box, tvp_flags = %x\n", tvp_flags);
+
+ size = sizeof(struct decoder_bmmu_box) + sizeof(struct codec_mm_s *) *
+ max_num;
+ box = kmalloc(size, GFP_KERNEL);
+ if (!box) {
+ pr_err("can't alloc decoder buffers box!!!\n");
+ return NULL;
+ }
+ memset(box, 0, size);
+ box->max_mm_num = max_num;
+ box->name = name;
+ box->channel_id = channel_id;
+ box->align2n = aligned;
+ box->mem_flags = mem_flags | tvp_flags;
+ mutex_init(&box->mutex);
+ INIT_LIST_HEAD(&box->list);
+ decoder_bmmu_box_mgr_add_box(box);
+ return (void *)box;
+}
+EXPORT_SYMBOL(decoder_bmmu_box_alloc_box);
+
+int decoder_bmmu_box_alloc_idx(void *handle, int idx, int size, int aligned_2n,
+ int mem_flags)
+/*align& flags if -1 user box default.*/
+{
+ struct decoder_bmmu_box *box = handle;
+ struct codec_mm_s *mm;
+ int align = aligned_2n;
+ int memflags = mem_flags;
+
+ if (!box || idx < 0 || idx >= box->max_mm_num) {
+ pr_err("can't alloc mmu box(%p),idx:%d\n",
+ box, idx);
+ return -1;
+ }
+ if (align == -1)
+ align = box->align2n;
+ if (memflags == -1)
+ memflags = box->mem_flags;
+
+ mutex_lock(&box->mutex);
+ mm = box->mm_list[idx];
+ if (mm) {
+ int invalid = 0;
+ int keeped = 0;
+
+ keeped = is_codec_mm_keeped(mm);
+ if (!keeped) {
+ if (mm->page_count * PAGE_SIZE < size) {
+ /*size is small. */
+ invalid = 1;
+ } else if (box->change_size_on_need_smaller &&
+ (mm->buffer_size > (size << 1))) {
+ /*size is too large. */
+ invalid = 2;
+ } else if (mm->phy_addr & ((1 << align) - 1)) {
+ /*addr is not align */
+ invalid = 4;
+ }
+ if (invalid) {
+ box->total_size -= mm->buffer_size;
+ codec_mm_release(mm, box->name);
+ box->mm_list[idx] = NULL;
+ mm = NULL;
+ }
+ } else {
+ box->total_size -= mm->buffer_size;
+ codec_mm_release(mm, box->name);
+ box->mm_list[idx] = NULL;
+ mm = NULL;
+ }
+ }
+ if (!mm) {
+ mm = codec_mm_alloc(box->name, size, align, memflags);
+ if (mm) {
+ box->mm_list[idx] = mm;
+ box->total_size += mm->buffer_size;
+ mm->ins_id = box->channel_id;
+ mm->ins_buffer_id = idx;
+ box->box_ref_cnt++;
+ }
+ }
+ mutex_unlock(&box->mutex);
+ return mm ? 0 : -ENOMEM;
+}
+
+int decoder_bmmu_box_free_idx(void *handle, int idx)
+{
+ struct decoder_bmmu_box *box = handle;
+ struct codec_mm_s *mm;
+
+ if (!box || idx < 0 || idx >= box->max_mm_num) {
+ pr_err("can't free idx of box(%p),idx:%d in (%d-%d)\n",
+ box, idx, 0,
+ box ? (box->max_mm_num - 1) : 0);
+ return -1;
+ }
+ mutex_lock(&box->mutex);
+ mm = box->mm_list[idx];
+ if (mm) {
+ box->total_size -= mm->buffer_size;
+ codec_mm_release(mm, box->name);
+ box->mm_list[idx] = NULL;
+ mm = NULL;
+ box->box_ref_cnt--;
+ }
+ mutex_unlock(&box->mutex);
+ return 0;
+}
+EXPORT_SYMBOL(decoder_bmmu_box_free_idx);
+
+int decoder_bmmu_box_free(void *handle)
+{
+ struct decoder_bmmu_box *box = handle;
+ struct codec_mm_s *mm;
+ int i;
+
+ if (!box) {
+ pr_err("can't free box of NULL box!\n");
+ return -1;
+ }
+ mutex_lock(&box->mutex);
+ for (i = 0; i < box->max_mm_num; i++) {
+ mm = box->mm_list[i];
+ if (mm) {
+ codec_mm_release(mm, box->name);
+ box->mm_list[i] = NULL;
+ }
+ }
+ mutex_unlock(&box->mutex);
+ decoder_bmmu_box_mgr_del_box(box);
+ kfree(box);
+ return 0;
+}
+EXPORT_SYMBOL(decoder_bmmu_box_free);
+
+void decoder_bmmu_try_to_release_box(void *handle)
+{
+ struct decoder_bmmu_box *box = handle;
+ bool is_keep = false;
+ int i;
+
+ if (!box || box->box_ref_cnt)
+ return;
+
+ mutex_lock(&box->mutex);
+ for (i = 0; i < box->max_mm_num; i++) {
+ if (box->mm_list[i]) {
+ is_keep = true;
+ break;
+ }
+ }
+ mutex_unlock(&box->mutex);
+
+ if (!is_keep) {
+ decoder_bmmu_box_mgr_del_box(box);
+ kfree(box);
+ }
+}
+EXPORT_SYMBOL(decoder_bmmu_try_to_release_box);
+
+void *decoder_bmmu_box_get_mem_handle(void *box_handle, int idx)
+{
+ struct decoder_bmmu_box *box = box_handle;
+
+ if (!box || idx < 0 || idx >= box->max_mm_num)
+ return NULL;
+ return box->mm_list[idx];
+}
+EXPORT_SYMBOL(decoder_bmmu_box_get_mem_handle);
+
+int decoder_bmmu_box_get_mem_size(void *box_handle, int idx)
+{
+ struct decoder_bmmu_box *box = box_handle;
+ int size = 0;
+
+ if (!box || idx < 0 || idx >= box->max_mm_num)
+ return 0;
+ mutex_lock(&box->mutex);
+ if (box->mm_list[idx] != NULL)
+ size = box->mm_list[idx]->buffer_size;
+ mutex_unlock(&box->mutex);
+ return size;
+}
+
+
+unsigned long decoder_bmmu_box_get_phy_addr(void *box_handle, int idx)
+{
+ struct decoder_bmmu_box *box = box_handle;
+ struct codec_mm_s *mm;
+
+ if (!box || idx < 0 || idx >= box->max_mm_num)
+ return 0;
+ mm = box->mm_list[idx];
+ if (!mm)
+ return 0;
+ return mm->phy_addr;
+}
+EXPORT_SYMBOL(decoder_bmmu_box_get_phy_addr);
+
+void *decoder_bmmu_box_get_virt_addr(void *box_handle, int idx)
+{
+ struct decoder_bmmu_box *box = box_handle;
+ struct codec_mm_s *mm;
+
+ if (!box || idx < 0 || idx >= box->max_mm_num)
+ return NULL;
+ mm = box->mm_list[idx];
+ if (!mm)
+ return 0;
+ return codec_mm_phys_to_virt(mm->phy_addr);
+}
+
+/*flags: &0x1 for wait,*/
+int decoder_bmmu_box_check_and_wait_size(int size, int flags)
+{
+ if ((flags & BMMU_ALLOC_FLAGS_CAN_CLEAR_KEEPER) &&
+ codec_mm_get_free_size() < size) {
+ pr_err("CMA force free keep,for size = %d\n", size);
+ /*need free others?
+ */
+ try_free_keep_video(1);
+ }
+
+ return codec_mm_enough_for_size(size,
+ flags & BMMU_ALLOC_FLAGS_WAIT);
+}
+
+int decoder_bmmu_box_alloc_idx_wait(
+ void *handle, int idx,
+ int size, int aligned_2n,
+ int mem_flags,
+ int wait_flags)
+{
+ int have_space;
+ int ret = -1;
+ int keeped = 0;
+
+ if (decoder_bmmu_box_get_mem_size(handle, idx) >= size) {
+ struct decoder_bmmu_box *box = handle;
+ struct codec_mm_s *mm;
+ mutex_lock(&box->mutex);
+ mm = box->mm_list[idx];
+ keeped = is_codec_mm_keeped(mm);
+ mutex_unlock(&box->mutex);
+
+ if (!keeped)
+ return 0;/*have alloced memery before.*/
+ }
+ have_space = decoder_bmmu_box_check_and_wait_size(
+ size,
+ wait_flags);
+ if (have_space) {
+ ret = decoder_bmmu_box_alloc_idx(handle,
+ idx, size, aligned_2n, mem_flags);
+ if (ret == -ENOMEM) {
+ pr_info("bmmu alloc idx fail, try free keep video.\n");
+ try_free_keep_video(1);
+ }
+ } else {
+ try_free_keep_video(1);
+ ret = -ENOMEM;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(decoder_bmmu_box_alloc_idx_wait);
+
+int decoder_bmmu_box_alloc_buf_phy(
+ void *handle, int idx,
+ int size, unsigned char *driver_name,
+ unsigned long *buf_phy_addr)
+{
+ if (!decoder_bmmu_box_check_and_wait_size(
+ size,
+ 1)) {
+ pr_info("%s not enough buf for buf_idx = %d\n",
+ driver_name, idx);
+ return -ENOMEM;
+ }
+ if (!decoder_bmmu_box_alloc_idx_wait(
+ handle,
+ idx,
+ size,
+ -1,
+ -1,
+ BMMU_ALLOC_FLAGS_WAITCLEAR
+ )) {
+ *buf_phy_addr =
+ decoder_bmmu_box_get_phy_addr(
+ handle,
+ idx);
+ /*
+ *pr_info("%s malloc buf_idx = %d addr = %ld size = %d\n",
+ * driver_name, idx, *buf_phy_addr, size);
+ */
+ } else {
+ pr_info("%s malloc failed %d\n", driver_name, idx);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(decoder_bmmu_box_alloc_buf_phy);
+
+static int decoder_bmmu_box_dump(struct decoder_bmmu_box *box, void *buf,
+ int size)
+{
+ char *pbuf = buf;
+ char sbuf[512];
+ int tsize = 0;
+ int s;
+ int i;
+ if (!buf) {
+ pbuf = sbuf;
+ size = 512;
+ }
+#define BUFPRINT(args...) \
+ do {\
+ s = snprintf(pbuf, size - tsize, args);\
+ tsize += s;\
+ pbuf += s; \
+ } while (0)
+
+ for (i = 0; i < box->max_mm_num; i++) {
+ struct codec_mm_s *mm = box->mm_list[i];
+ if (buf && (size - tsize) < 256) {
+ BUFPRINT("\n\t**NOT END**\n");
+ break;
+ }
+ if (mm) {
+ BUFPRINT("code mem[%d]:%p, addr=%p, size=%d,from=%d\n",
+ i,
+ (void *)mm,
+ (void *)mm->phy_addr,
+ mm->buffer_size,
+ mm->from_flags);
+ if (!buf) {
+ pr_info("%s", sbuf);
+ pbuf = sbuf;
+ }
+ }
+ }
+#undef BUFPRINT
+
+ return tsize;
+}
+
+static int decoder_bmmu_box_dump_all(void *buf, int size)
+{
+ struct decoder_bmmu_box_mgr *mgr = get_decoder_bmmu_box_mgr();
+ char *pbuf = buf;
+ char sbuf[512];
+ int tsize = 0;
+ int s;
+ int i;
+ struct list_head *head, *list;
+ if (!buf) {
+ pbuf = sbuf;
+ size = 512;
+ }
+#define BUFPRINT(args...) \
+ do {\
+ s = snprintf(pbuf, size - tsize, args);\
+ tsize += s;\
+ pbuf += s; \
+ } while (0)
+
+ mutex_lock(&mgr->mutex);
+ head = &mgr->box_list;
+ list = head->next;
+ i = 0;
+ while (list != head) {
+ struct decoder_bmmu_box *box;
+
+ box = list_entry(list, struct decoder_bmmu_box, list);
+ BUFPRINT("box[%d]: %s, %splayer_id:%d, max_num:%d, size:%d\n",
+ i, box->name,
+ (box->mem_flags & CODEC_MM_FLAGS_TVP) ?
+ "TVP mode " : "",
+ box->channel_id,
+ box->max_mm_num,
+ box->total_size);
+ if (buf) {
+ s = decoder_bmmu_box_dump(box, pbuf, size - tsize);
+ if (s > 0) {
+ tsize += s;
+ pbuf += s;
+ }
+ } else {
+ pr_info("%s", sbuf);
+ pbuf = sbuf;
+ tsize += decoder_bmmu_box_dump(box, NULL, 0);
+ }
+ list = list->next;
+ i++;
+ }
+ mutex_unlock(&mgr->mutex);
+
+#undef BUFPRINT
+ if (!buf)
+ pr_info("%s", sbuf);
+ return tsize;
+}
+
+static ssize_t box_dump_show(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ ssize_t ret = 0;
+
+ ret = decoder_bmmu_box_dump_all(buf, PAGE_SIZE);
+ return ret;
+}
+
+static ssize_t box_debug_show(struct class *class,
+ struct class_attribute *attr,
+ char *buf)
+{
+ ssize_t size = 0;
+ size += sprintf(buf, "box debug help:\n");
+ size += sprintf(buf + size, "echo n > debug\n");
+ size += sprintf(buf + size, "n==0: clear all debugs)\n");
+ size += sprintf(buf + size,
+ "n=1: dump all box\n");
+
+ return size;
+}
+
+
+static ssize_t box_debug_store(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned val;
+ ssize_t ret;
+ val = -1;
+ ret = sscanf(buf, "%d", &val);
+ if (ret != 1)
+ return -EINVAL;
+ switch (val) {
+ case 1:
+ decoder_bmmu_box_dump_all(NULL , 0);
+ break;
+ default:
+ pr_err("unknow cmd! %d\n", val);
+ }
+ return size;
+
+}
+
+
+
+static struct class_attribute decoder_bmmu_box_class_attrs[] = {
+ __ATTR_RO(box_dump),
+ __ATTR(debug, S_IRUGO | S_IWUSR | S_IWGRP,
+ box_debug_show, box_debug_store),
+ __ATTR_NULL
+};
+
+static struct class decoder_bmmu_box_class = {
+ .name = "decoder_bmmu_box",
+ .class_attrs = decoder_bmmu_box_class_attrs,
+ };
+
+int decoder_bmmu_box_init(void)
+{
+ int r;
+
+ memset(&global_blk_mgr, 0, sizeof(global_blk_mgr));
+ INIT_LIST_HEAD(&global_blk_mgr.box_list);
+ mutex_init(&global_blk_mgr.mutex);
+ r = class_register(&decoder_bmmu_box_class);
+ return r;
+}
+EXPORT_SYMBOL(decoder_bmmu_box_init);
+
+void decoder_bmmu_box_exit(void)
+{
+ class_unregister(&decoder_bmmu_box_class);
+ pr_info("dec bmmu box exit.\n");
+}
+
+#if 0
+static int __init decoder_bmmu_box_init(void)
+{
+ int r;
+
+ memset(&global_blk_mgr, 0, sizeof(global_blk_mgr));
+ INIT_LIST_HEAD(&global_blk_mgr.box_list);
+ mutex_init(&global_blk_mgr.mutex);
+ r = class_register(&decoder_bmmu_box_class);
+ return r;
+}
+
+module_init(decoder_bmmu_box_init);
+#endif
diff --git a/drivers/frame_provider/decoder/utils/decoder_bmmu_box.h b/drivers/frame_provider/decoder/utils/decoder_bmmu_box.h
new file mode 100644
index 0000000..778cb8e
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/decoder_bmmu_box.h
@@ -0,0 +1,70 @@
+/*
+ * drivers/amlogic/amports/decoder/decoder_bmmu_box.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 DECODER_BLOCK_BUFFER_BOX
+#define DECODER_BLOCK_BUFFER_BOX
+
+void *decoder_bmmu_box_alloc_box(const char *name,
+ int channel_id,
+ int max_num,
+ int aligned,
+ int mem_flags);
+
+int decoder_bmmu_box_alloc_idx(
+ void *handle, int idx, int size,
+ int aligned_2n, int mem_flags);
+
+int decoder_bmmu_box_free_idx(void *handle, int idx);
+int decoder_bmmu_box_free(void *handle);
+void *decoder_bmmu_box_get_mem_handle(
+ void *box_handle, int idx);
+
+unsigned long decoder_bmmu_box_get_phy_addr(
+ void *box_handle, int idx);
+
+void *decoder_bmmu_box_get_virt_addr(
+ void *box_handle, int idx);
+
+/*flags: &0x1 for wait,*/
+int decoder_bmmu_box_check_and_wait_size(
+ int size, int flags);
+
+int decoder_bmmu_box_alloc_buf_phy(
+ void *handle, int idx,
+ int size, unsigned char *driver_name,
+ unsigned long *buf_phy_addr);
+
+#define BMMU_ALLOC_FLAGS_WAIT (1 << 0)
+#define BMMU_ALLOC_FLAGS_CAN_CLEAR_KEEPER (1 << 1)
+#define BMMU_ALLOC_FLAGS_WAITCLEAR \
+ (BMMU_ALLOC_FLAGS_WAIT |\
+ BMMU_ALLOC_FLAGS_CAN_CLEAR_KEEPER)
+
+int decoder_bmmu_box_alloc_idx_wait(
+ void *handle, int idx,
+ int size, int aligned_2n,
+ int mem_flags,
+ int wait_flags);
+
+bool decoder_bmmu_box_valide_check(void *box);
+void decoder_bmmu_try_to_release_box(void *handle);
+
+int decoder_bmmu_box_init(void);
+void decoder_bmmu_box_exit(void);
+
+#endif
+
diff --git a/drivers/frame_provider/decoder/utils/decoder_mmu_box.c b/drivers/frame_provider/decoder/utils/decoder_mmu_box.c
new file mode 100644
index 0000000..75862ec
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/decoder_mmu_box.c
@@ -0,0 +1,459 @@
+/*
+ * drivers/amlogic/media/frame_provider/decoder/utils/decoder_mmu_box.c
+ *
+ * Copyright (C) 2016 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/semaphore.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/kfifo.h>
+#include <linux/kthread.h>
+#include <linux/slab.h>
+#include <linux/amlogic/media/codec_mm/codec_mm_scatter.h>
+#include <linux/platform_device.h>
+
+struct decoder_mmu_box {
+ int max_sc_num;
+ const char *name;
+ int channel_id;
+ int tvp_mode;
+ int box_ref_cnt;
+ struct mutex mutex;
+ struct list_head list;
+ struct codec_mm_scatter *sc_list[1];
+};
+#define MAX_KEEP_FRAME 4
+#define START_KEEP_ID 0x9
+#define MAX_KEEP_ID (INT_MAX - 1)
+struct decoder_mmu_box_mgr {
+ int num;
+ struct mutex mutex;
+ struct codec_mm_scatter *keep_sc[MAX_KEEP_FRAME];
+ int keep_id[MAX_KEEP_FRAME];
+ int next_id;/*id for keep & free.*/
+ struct list_head box_list;
+};
+static struct decoder_mmu_box_mgr global_mgr;
+static struct decoder_mmu_box_mgr *get_decoder_mmu_box_mgr(void)
+{
+ return &global_mgr;
+}
+
+static int decoder_mmu_box_mgr_add_box(struct decoder_mmu_box *box)
+{
+ struct decoder_mmu_box_mgr *mgr = get_decoder_mmu_box_mgr();
+
+ mutex_lock(&mgr->mutex);
+ list_add_tail(&box->list, &mgr->box_list);
+ mutex_unlock(&mgr->mutex);
+ return 0;
+}
+
+static int decoder_mmu_box_mgr_del_box(struct decoder_mmu_box *box)
+{
+ struct decoder_mmu_box_mgr *mgr = get_decoder_mmu_box_mgr();
+
+ mutex_lock(&mgr->mutex);
+ list_del(&box->list);
+ mutex_unlock(&mgr->mutex);
+ return 0;
+}
+
+bool decoder_mmu_box_valide_check(void *box)
+{
+ struct decoder_mmu_box_mgr *mgr = get_decoder_mmu_box_mgr();
+ struct decoder_mmu_box *mmu_box = NULL;
+ bool is_valide = false;
+
+ mutex_lock(&mgr->mutex);
+ list_for_each_entry(mmu_box, &mgr->box_list, list) {
+ if (mmu_box && mmu_box == box) {
+ is_valide = true;
+ break;
+ }
+ }
+ mutex_unlock(&mgr->mutex);
+
+ return is_valide;
+}
+EXPORT_SYMBOL(decoder_mmu_box_valide_check);
+
+void decoder_mmu_try_to_release_box(void *handle)
+{
+ struct decoder_mmu_box *box = handle;
+ bool is_keep = false;
+ int i;
+
+ if (!box || box->box_ref_cnt)
+ return;
+
+ mutex_lock(&box->mutex);
+ for (i = 0; i < box->max_sc_num; i++) {
+ if (box->sc_list[i]) {
+ is_keep = true;
+ break;
+ }
+ }
+ mutex_unlock(&box->mutex);
+
+ if (!is_keep) {
+ decoder_mmu_box_mgr_del_box(box);
+ codec_mm_scatter_mgt_delay_free_swith(0, 0, 0, box->tvp_mode);
+ kfree(box);
+ }
+}
+EXPORT_SYMBOL(decoder_mmu_try_to_release_box);
+
+int decoder_mmu_box_sc_check(void *handle, int is_tvp)
+{
+ struct decoder_mmu_box *box = handle;
+ if (!box) {
+ pr_err("mmu box NULL !!!\n");
+ return 0;
+ }
+ return codec_mm_scatter_size(is_tvp);
+}
+EXPORT_SYMBOL(decoder_mmu_box_sc_check);
+
+
+void *decoder_mmu_box_alloc_box(const char *name,
+ int channel_id,
+ int max_num,
+ int min_size_M,
+ int mem_flags)
+/*min_size_M:wait alloc this size*/
+{
+ struct decoder_mmu_box *box;
+ int size;
+
+ pr_debug("decoder_mmu_box_alloc_box, mem_flags = 0x%x\n", mem_flags);
+
+ size = sizeof(struct decoder_mmu_box) +
+ sizeof(struct codec_mm_scatter *) *
+ max_num;
+ box = kmalloc(size, GFP_KERNEL);
+ if (!box) {
+ pr_err("can't alloc decoder buffers box!!!\n");
+ return NULL;
+ }
+ memset(box, 0, size);
+ box->max_sc_num = max_num;
+ box->name = name;
+ box->channel_id = channel_id;
+ box->tvp_mode = mem_flags;
+
+ mutex_init(&box->mutex);
+ INIT_LIST_HEAD(&box->list);
+ decoder_mmu_box_mgr_add_box(box);
+ codec_mm_scatter_mgt_delay_free_swith(1, 2000,
+ min_size_M, box->tvp_mode);
+ return (void *)box;
+}
+EXPORT_SYMBOL(decoder_mmu_box_alloc_box);
+
+int decoder_mmu_box_alloc_idx(
+ void *handle, int idx, int num_pages,
+ unsigned int *mmu_index_adr)
+{
+ struct decoder_mmu_box *box = handle;
+ struct codec_mm_scatter *sc;
+ int ret;
+ int i;
+
+ if (!box || idx < 0 || idx >= box->max_sc_num) {
+ pr_err("can't alloc mmu box(%p),idx:%d\n",
+ box, idx);
+ return -1;
+ }
+ mutex_lock(&box->mutex);
+ sc = box->sc_list[idx];
+ if (sc) {
+ if (sc->page_max_cnt >= num_pages)
+ ret = codec_mm_scatter_alloc_want_pages(sc,
+ num_pages);
+ else {
+ box->box_ref_cnt--;
+ codec_mm_scatter_dec_owner_user(sc, 0);
+ box->sc_list[idx] = NULL;
+ sc = NULL;
+ }
+
+ }
+ if (!sc) {
+ sc = codec_mm_scatter_alloc(num_pages + 64, num_pages,
+ box->tvp_mode);
+ if (!sc) {
+ mutex_unlock(&box->mutex);
+ pr_err("alloc mmu failed, need pages=%d\n",
+ num_pages);
+ return -1;
+ }
+ box->sc_list[idx] = sc;
+ box->box_ref_cnt++;
+ }
+
+ for (i = 0; i < num_pages; i++)
+ mmu_index_adr[i] = PAGE_INDEX(sc->pages_list[i]);
+
+ mutex_unlock(&box->mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(decoder_mmu_box_alloc_idx);
+
+int decoder_mmu_box_free_idx_tail(
+ void *handle, int idx,
+ int start_release_index)
+{
+ struct decoder_mmu_box *box = handle;
+ struct codec_mm_scatter *sc;
+
+ if (!box || idx < 0 || idx >= box->max_sc_num) {
+ pr_err("can't free tail mmu box(%p),idx:%d in (%d-%d)\n",
+ box, idx, 0,
+ box ? (box->max_sc_num - 1) : 0);
+ return -1;
+ }
+ mutex_lock(&box->mutex);
+ sc = box->sc_list[idx];
+ if (sc && start_release_index < sc->page_cnt)
+ codec_mm_scatter_free_tail_pages_fast(sc,
+ start_release_index);
+ mutex_unlock(&box->mutex);
+ return 0;
+}
+EXPORT_SYMBOL(decoder_mmu_box_free_idx_tail);
+
+int decoder_mmu_box_free_idx(void *handle, int idx)
+{
+ struct decoder_mmu_box *box = handle;
+ struct codec_mm_scatter *sc;
+
+ if (!box || idx < 0 || idx >= box->max_sc_num) {
+ pr_err("can't free idx of box(%p),idx:%d in (%d-%d)\n",
+ box, idx, 0,
+ box ? (box->max_sc_num - 1) : 0);
+ return -1;
+ }
+ mutex_lock(&box->mutex);
+ sc = box->sc_list[idx];
+ if (sc && sc->page_cnt > 0) {
+ codec_mm_scatter_dec_owner_user(sc, 0);
+ box->sc_list[idx] = NULL;
+ box->box_ref_cnt--;
+ }
+ mutex_unlock(&box->mutex);
+
+ if (sc && box->box_ref_cnt == 0)
+ codec_mm_scatter_mgt_delay_free_swith(0, 0, 0, box->tvp_mode);
+
+ return 0;
+}
+EXPORT_SYMBOL(decoder_mmu_box_free_idx);
+
+int decoder_mmu_box_free(void *handle)
+{
+ struct decoder_mmu_box *box = handle;
+ struct codec_mm_scatter *sc;
+ int i;
+
+ if (!box) {
+ pr_err("can't free box of NULL box!\n");
+ return -1;
+ }
+ mutex_lock(&box->mutex);
+ for (i = 0; i < box->max_sc_num; i++) {
+ sc = box->sc_list[i];
+ if (sc) {
+ codec_mm_scatter_dec_owner_user(sc, 0);
+ box->sc_list[i] = NULL;
+ }
+ }
+ mutex_unlock(&box->mutex);
+ decoder_mmu_box_mgr_del_box(box);
+ codec_mm_scatter_mgt_delay_free_swith(0, 0, 0, box->tvp_mode);
+ kfree(box);
+ return 0;
+}
+EXPORT_SYMBOL(decoder_mmu_box_free);
+
+void *decoder_mmu_box_get_mem_handle(void *box_handle, int idx)
+{
+ struct decoder_mmu_box *box = box_handle;
+
+ if (!box || idx < 0 || idx >= box->max_sc_num)
+ return NULL;
+ return box->sc_list[idx];
+}
+EXPORT_SYMBOL(decoder_mmu_box_get_mem_handle);
+
+static int decoder_mmu_box_dump(struct decoder_mmu_box *box,
+ void *buf, int size)
+{
+ char *pbuf = buf;
+ char sbuf[512];
+ int tsize = 0;
+ int s;
+ int i;
+
+ if (!buf) {
+ pbuf = sbuf;
+ size = 512;
+ }
+ #define BUFPRINT(args...) \
+ do {\
+ s = snprintf(pbuf, size - tsize, args);\
+ tsize += s;\
+ pbuf += s; \
+ } while (0)
+
+ for (i = 0; i < box->max_sc_num; i++) {
+ struct codec_mm_scatter *sc = box->sc_list[i];
+
+ if (sc) {
+ BUFPRINT("sc mem[%d]:%p, size=%d\n",
+ i, sc,
+ sc->page_cnt << PAGE_SHIFT);
+ }
+ }
+#undef BUFPRINT
+ if (!buf)
+ pr_info("%s", sbuf);
+
+ return tsize;
+}
+
+static int decoder_mmu_box_dump_all(void *buf, int size)
+{
+ struct decoder_mmu_box_mgr *mgr = get_decoder_mmu_box_mgr();
+ char *pbuf = buf;
+ char sbuf[512];
+ int tsize = 0;
+ int s;
+ int i;
+ struct list_head *head, *list;
+
+ if (!pbuf) {
+ pbuf = sbuf;
+ size = 512;
+ }
+
+ #define BUFPRINT(args...) \
+ do {\
+ s = snprintf(pbuf, size - tsize, args);\
+ tsize += s;\
+ pbuf += s; \
+ } while (0)
+
+ mutex_lock(&mgr->mutex);
+ head = &mgr->box_list;
+ list = head->next;
+ i = 0;
+ while (list != head) {
+ struct decoder_mmu_box *box;
+ box = list_entry(list, struct decoder_mmu_box,
+ list);
+ BUFPRINT("box[%d]: %s, %splayer_id:%d, max_num:%d\n",
+ i,
+ box->name,
+ box->tvp_mode ? "TVP mode " : "",
+ box->channel_id,
+ box->max_sc_num);
+ if (buf) {
+ s += decoder_mmu_box_dump(box, pbuf, size - tsize);
+ if (s > 0) {
+ tsize += s;
+ pbuf += s;
+ }
+ } else {
+ pr_info("%s", sbuf);
+ pbuf = sbuf;
+ tsize += decoder_mmu_box_dump(box, NULL, 0);
+ }
+ list = list->next;
+ i++;
+ }
+ mutex_unlock(&mgr->mutex);
+
+
+#undef BUFPRINT
+ if (!buf)
+ pr_info("%s", sbuf);
+ return tsize;
+}
+
+
+
+static ssize_t
+box_dump_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+
+ ret = decoder_mmu_box_dump_all(buf, PAGE_SIZE);
+ return ret;
+}
+
+
+
+static struct class_attribute decoder_mmu_box_class_attrs[] = {
+ __ATTR_RO(box_dump),
+ __ATTR_NULL
+};
+
+static struct class decoder_mmu_box_class = {
+ .name = "decoder_mmu_box",
+ .class_attrs = decoder_mmu_box_class_attrs,
+};
+
+int decoder_mmu_box_init(void)
+{
+ int r;
+
+ memset(&global_mgr, 0, sizeof(global_mgr));
+ INIT_LIST_HEAD(&global_mgr.box_list);
+ mutex_init(&global_mgr.mutex);
+ global_mgr.next_id = START_KEEP_ID;
+ r = class_register(&decoder_mmu_box_class);
+ return r;
+}
+EXPORT_SYMBOL(decoder_mmu_box_init);
+
+void decoder_mmu_box_exit(void)
+{
+ class_unregister(&decoder_mmu_box_class);
+ pr_info("dec mmu box exit.\n");
+}
+
+#if 0
+static int __init decoder_mmu_box_init(void)
+{
+ int r;
+
+ memset(&global_mgr, 0, sizeof(global_mgr));
+ INIT_LIST_HEAD(&global_mgr.box_list);
+ mutex_init(&global_mgr.mutex);
+ global_mgr.next_id = START_KEEP_ID;
+ r = class_register(&decoder_mmu_box_class);
+ return r;
+}
+
+module_init(decoder_mmu_box_init);
+#endif
diff --git a/drivers/frame_provider/decoder/utils/decoder_mmu_box.h b/drivers/frame_provider/decoder/utils/decoder_mmu_box.h
new file mode 100644
index 0000000..029f91a
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/decoder_mmu_box.h
@@ -0,0 +1,50 @@
+/*
+ * drivers/amlogic/media/frame_provider/decoder/utils/decoder_mmu_box.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 DECODER_BUFFER_BOX
+#define DECODER_BUFFER_BOX
+
+void *decoder_mmu_box_alloc_box(const char *name,
+ int channel_id,
+ int max_num,
+ int min_size_M,
+ int mem_flags);
+
+int decoder_mmu_box_sc_check(void *handle, int is_tvp);
+
+int decoder_mmu_box_alloc_idx(
+ void *handle, int idx, int num_pages,
+ unsigned int *mmu_index_adr);
+
+int decoder_mmu_box_free_idx_tail(void *handle, int idx,
+ int start_release_index);
+
+int decoder_mmu_box_free_idx(void *handle, int idx);
+
+int decoder_mmu_box_free(void *handle);
+
+int decoder_mmu_box_move_keep_idx(void *box_handle,
+ int keep_idx);
+int decoder_mmu_box_free_keep(int keep_id);
+int decoder_mmu_box_free_all_keep(void);
+void *decoder_mmu_box_get_mem_handle(void *box_handle, int idx);
+bool decoder_mmu_box_valide_check(void *box);
+void decoder_mmu_try_to_release_box(void *handle);
+int decoder_mmu_box_init(void);
+void decoder_mmu_box_exit(void);
+
+#endif
diff --git a/drivers/frame_provider/decoder/utils/firmware.h b/drivers/frame_provider/decoder/utils/firmware.h
new file mode 100644
index 0000000..c799fd0
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/firmware.h
@@ -0,0 +1,41 @@
+/*
+* 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_HEADER_
+#define __VIDEO_FIRMWARE_HEADER_
+
+#include "../../../common/firmware/firmware_type.h"
+#include <linux/amlogic/media/utils/vformat.h>
+
+#define FW_LOAD_FORCE (0x1)
+#define FW_LOAD_TRY (0X2)
+
+struct firmware_s {
+ char name[32];
+ unsigned int len;
+ char data[0];
+};
+
+extern int get_decoder_firmware_data(enum vformat_e type,
+ const char *file_name, char *buf, int size);
+extern int get_data_from_name(const char *name, char *buf);
+extern int get_firmware_data(unsigned int foramt, char *buf);
+extern int video_fw_reload(int mode);
+
+#endif
diff --git a/drivers/frame_provider/decoder/utils/frame_check.c b/drivers/frame_provider/decoder/utils/frame_check.c
new file mode 100644
index 0000000..4cd80c0
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/frame_check.c
@@ -0,0 +1,1761 @@
+/*
+ * drivers/amlogic/media/frame_provider/decoder/utils/frame_check.c
+ *
+ * Copyright (C) 2016 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kfifo.h>
+#include <linux/interrupt.h>
+#include <linux/semaphore.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/kfifo.h>
+#include <linux/kthread.h>
+#include <linux/platform_device.h>
+#include <linux/amlogic/media/canvas/canvas.h>
+#include <linux/amlogic/media/canvas/canvas_mgr.h>
+#include <linux/amlogic/media/vfm/vframe.h>
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma-contiguous.h>
+#include <asm-generic/checksum.h>
+#include <linux/amlogic/media/codec_mm/configs.h>
+#include <linux/crc32.h>
+#include <linux/fs.h>
+#include "vdec.h"
+#include "frame_check.h"
+#include "amlogic_fbc_hook.h"
+#include <linux/highmem.h>
+#include <linux/page-flags.h>
+#include "../../../common/chips/decoder_cpu_ver_info.h"
+#include <asm/cacheflush.h>
+
+#define FC_ERROR 0x0
+
+#define FC_YUV_DEBUG 0x01
+#define FC_CRC_DEBUG 0x02
+#define FC_TST_DEBUG 0x80
+#define FC_ERR_CRC_BLOCK_MODE 0x10
+#define FC_CHECK_CRC_LOOP_MODE 0x20
+#define AD_CHECK_CRC_LOOP_MODE 0x40
+
+#define YUV_MASK 0x01
+#define CRC_MASK 0x02
+#define AUX_MASK 0x04
+
+
+#define MAX_YUV_SIZE (4096 * 2304)
+#define YUV_DEF_SIZE (MAX_YUV_SIZE * 3 / 2)
+#define YUV_DEF_NUM 1
+
+#define MAX_SIZE_AFBC_PLANES (4096 * 2048)
+
+#define VMAP_STRIDE_SIZE (1024*1024)
+
+static unsigned int fc_debug;
+static unsigned int size_yuv_buf = (YUV_DEF_SIZE * YUV_DEF_NUM);
+
+#define dbg_print(mask, ...) do { \
+ if ((fc_debug & mask) || \
+ (mask == FC_ERROR)) \
+ printk("[FRMAE_CHECK] "__VA_ARGS__);\
+ } while(0)
+
+
+#define CRC_PATH "/data/tmp/"
+#define YUV_PATH "/data/tmp/"
+static char comp_crc[128] = "name";
+static char aux_comp_crc[128] = "aux";
+
+static struct vdec_s *single_mode_vdec = NULL;
+
+static unsigned int yuv_enable, check_enable;
+static unsigned int aux_enable;
+static unsigned int yuv_start[MAX_INSTANCE_MUN];
+static unsigned int yuv_num[MAX_INSTANCE_MUN];
+
+#define CHECKSUM_PATH "/data/local/tmp/"
+static char checksum_info[128] = "checksum info";
+static char checksum_filename[128] = "checksum";
+static unsigned int checksum_enable;
+static unsigned int checksum_start_count;
+
+static const char * const format_name[] = {
+ "MPEG12",
+ "MPEG4",
+ "H264",
+ "MJPEG",
+ "REAL",
+ "JPEG",
+ "VC1",
+ "AVS",
+ "YUV",
+ "H264MVC",
+ "H264_4K2K",
+ "HEVC",
+ "H264_ENC",
+ "JPEG_ENC",
+ "VP9",
+ "AVS2",
+ "AV1",
+};
+
+static const char *get_format_name(int format)
+{
+ if (format < 17 && format >= 0)
+ return format_name[format];
+ else
+ return "Unknow";
+}
+
+
+static inline void set_enable(struct pic_check_mgr_t *p, int mask)
+{
+ p->enable |= mask;
+}
+
+static inline void set_disable(struct pic_check_mgr_t *p, int mask)
+{
+ p->enable &= (~mask);
+}
+
+static inline void aux_set_enable(struct aux_data_check_mgr_t *p, int mask)
+{
+ p->enable |= mask;
+}
+
+static inline void aux_set_disable(struct aux_data_check_mgr_t *p, int mask)
+{
+ p->enable &= (~mask);
+}
+
+
+static inline void check_schedule(struct pic_check_mgr_t *mgr)
+{
+ if (atomic_read(&mgr->work_inited))
+ vdec_schedule_work(&mgr->frame_check_work);
+}
+
+static inline void aux_data_check_schedule(struct aux_data_check_mgr_t *mgr)
+{
+ if (atomic_read(&mgr->work_inited))
+ vdec_schedule_work(&mgr->aux_data_check_work);
+}
+
+static bool is_oversize(int w, int h)
+{
+ if (w <= 0 || h <= 0)
+ return true;
+
+ if (h != 0 && (w > (MAX_YUV_SIZE / h)))
+ return true;
+
+ return false;
+}
+
+
+static int get_frame_size(struct pic_check_mgr_t *pic,
+ struct vframe_s *vf)
+{
+ if (is_oversize(vf->width, vf->height)) {
+ dbg_print(FC_ERROR, "vf size err: w=%d, h=%d\n",
+ vf->width, vf->height);
+ return -1;
+ }
+ pic->height = vf->height;
+ pic->width = vf->width;
+ pic->size_y = vf->width * vf->height;
+ pic->size_uv = pic->size_y >> (1 + pic->mjpeg_flag);
+ pic->size_pic = pic->size_y + (pic->size_y >> 1);
+
+ if ((!(vf->type & VIDTYPE_VIU_NV21)) && (!pic->mjpeg_flag))
+ return 0;
+
+ if ((vf->canvas0Addr == vf->canvas1Addr) &&
+ (vf->canvas0Addr != 0) &&
+ (vf->canvas0Addr != -1)) {
+ pic->canvas_w =
+ canvas_get_width(canvasY(vf->canvas0Addr));
+ pic->canvas_h =
+ canvas_get_height(canvasY(vf->canvas0Addr));
+ } else {
+ pic->canvas_w = vf->canvas0_config[0].width;
+ pic->canvas_h = vf->canvas0_config[0].height;
+ }
+
+ if ((pic->canvas_h < 1) || (pic->canvas_w < 1)) {
+ dbg_print(FC_ERROR, "(canvas,pic) w(%d,%d), h(%d,%d)\n",
+ pic->canvas_w, vf->width, pic->canvas_h, vf->height);
+ return -1;
+ }
+/*
+ int blkmod;
+ blkmod = canvas_get_blkmode(canvasY(vf->canvas0Addr));
+ if (blkmod != CANVAS_BLKMODE_LINEAR) {
+ dbg_print(0, "WARN: canvas blkmod %x\n", blkmod);
+ }
+*/
+ return 0;
+}
+
+static int canvas_get_virt_addr(struct pic_check_mgr_t *pic,
+ struct vframe_s *vf)
+{
+ unsigned long phy_y_addr, phy_uv_addr;
+ void *vaddr_y, *vaddr_uv;
+
+ if ((vf->canvas0Addr == vf->canvas1Addr) &&
+ (vf->canvas0Addr != 0) &&
+ (vf->canvas0Addr != -1)) {
+ phy_y_addr = canvas_get_addr(canvasY(vf->canvas0Addr));
+ phy_uv_addr = canvas_get_addr(canvasU(vf->canvas0Addr));
+ } else {
+ phy_y_addr = vf->canvas0_config[0].phy_addr;
+ phy_uv_addr = vf->canvas0_config[1].phy_addr;
+ }
+ vaddr_y = codec_mm_phys_to_virt(phy_y_addr);
+ vaddr_uv = codec_mm_phys_to_virt(phy_uv_addr);
+
+ if (((!vaddr_y) || (!vaddr_uv)) && ((!phy_y_addr) || (!phy_uv_addr))) {
+ dbg_print(FC_ERROR, "%s, y_addr %p(0x%lx), uv_addr %p(0x%lx)\n",
+ __func__, vaddr_y, phy_y_addr, vaddr_uv, phy_uv_addr);
+ return -1;
+ }
+ pic->y_vaddr = vaddr_y;
+ pic->uv_vaddr = vaddr_uv;
+ pic->y_phyaddr = phy_y_addr;
+ pic->uv_phyaddr = phy_uv_addr;
+
+ if (pic->mjpeg_flag) {
+ if ((vf->canvas0Addr == vf->canvas1Addr) &&
+ (vf->canvas0Addr != 0) &&
+ (vf->canvas0Addr != -1)) {
+ pic->extra_v_phyaddr = canvas_get_addr(canvasV(vf->canvas0Addr));
+ } else {
+ pic->extra_v_phyaddr = vf->canvas0_config[2].phy_addr;
+ }
+ pic->extra_v_vaddr = codec_mm_phys_to_virt(phy_uv_addr);
+
+ if (!pic->extra_v_vaddr && !pic->extra_v_phyaddr)
+ return -1;
+ }
+
+ return 0;
+}
+
+static int str_strip(char *str)
+{
+ char *s = str;
+ int i = 0;
+
+ while (s[i]) {
+ if (s[i] == '\n')
+ s[i] = 0;
+ else if (s[i] == ' ')
+ s[i] = '_';
+ i++;
+ }
+
+ return i;
+}
+
+static char *fget_crc_str(char *buf,
+ unsigned int size, struct pic_check_t *fc)
+{
+ unsigned int c = 0, sz, ret, index, crc1, crc2;
+ mm_segment_t old_fs;
+ char *cs;
+
+ if (!fc->compare_fp)
+ return NULL;
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ do {
+ cs = buf;
+ sz = size;
+ while (--sz && (c = vfs_read(fc->compare_fp,
+ cs, 1, &fc->compare_pos) != 0)) {
+ if (*cs++ == '\n')
+ break;
+ }
+ *cs = '\0';
+ if ((c == 0) && (cs == buf)) {
+ set_fs(old_fs);
+ return NULL;
+ }
+ ret = sscanf(buf, "%08u: %8x %8x", &index, &crc1, &crc2);
+ dbg_print(FC_CRC_DEBUG, "%s, index = %d, cmp = %d\n",
+ __func__, index, fc->cmp_crc_cnt);
+ }while(ret != 3 || index != fc->cmp_crc_cnt);
+
+ set_fs(old_fs);
+ fc->cmp_crc_cnt++;
+
+ return buf;
+}
+
+static char *fget_aux_data_crc_str(char *buf,
+ unsigned int size, struct aux_data_check_t *fc)
+{
+ unsigned int c = 0, sz, ret, index, crc;
+ mm_segment_t old_fs;
+ char *cs;
+
+ if (!fc->compare_fp)
+ return NULL;
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ do {
+ cs = buf;
+ sz = size;
+ while (--sz && (c = vfs_read(fc->compare_fp,
+ cs, 1, &fc->compare_pos) != 0)) {
+ if (*cs++ == '\n')
+ break;
+ }
+ *cs = '\0';
+ if ((c == 0) && (cs == buf)) {
+ set_fs(old_fs);
+ return NULL;
+ }
+ ret = sscanf(buf, "%08u: %8x", &index, &crc);
+ dbg_print(FC_CRC_DEBUG, "%s, index = %d, cmp = %d\n",
+ __func__, index, fc->cmp_crc_cnt);
+ }while(ret != 2 || index != fc->cmp_crc_cnt);
+
+ set_fs(old_fs);
+ fc->cmp_crc_cnt++;
+
+ return buf;
+}
+
+
+static struct file* file_open(int mode, const char *str, ...)
+{
+ char file[256] = {0};
+ struct file* fp = NULL;
+ va_list args;
+
+ va_start(args, str);
+ vsnprintf(file, sizeof(file), str, args);
+
+ fp = filp_open(file, mode, (mode&O_CREAT)?0666:0);
+ if (IS_ERR(fp)) {
+ fp = NULL;
+ dbg_print(FC_ERROR, "open %s failed\n", file);
+ va_end(args);
+ return fp;
+ }
+ dbg_print(FC_ERROR, "open %s success\n", file);
+ va_end(args);
+
+ return fp;
+}
+
+static int write_yuv_work(struct pic_check_mgr_t *mgr)
+{
+ mm_segment_t old_fs;
+ unsigned int i, wr_size, pic_num;
+ struct pic_dump_t *dump = &mgr->pic_dump;
+
+ if (dump->dump_cnt > 0) {
+ if (!dump->yuv_fp) {
+ dump->yuv_fp = file_open(O_CREAT | O_WRONLY | O_TRUNC,
+ "%s%s-%d-%d.yuv", YUV_PATH, comp_crc, mgr->id, mgr->file_cnt);
+ dump->yuv_pos = 0;
+ }
+
+ if ((mgr->enable & YUV_MASK) &&
+ (dump->yuv_fp != NULL) &&
+ (dump->dump_cnt >= dump->num)) {
+
+ i = 0;
+ pic_num = dump->dump_cnt;
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ while (pic_num > 0) {
+ wr_size = vfs_write(dump->yuv_fp,
+ (dump->buf_addr + i * mgr->size_pic),
+ mgr->size_pic, &dump->yuv_pos);
+ if (mgr->size_pic != wr_size) {
+ dbg_print(FC_ERROR, "buf failed to write yuv file\n");
+ break;
+ }
+ pic_num--;
+ i++;
+ }
+ set_fs(old_fs);
+ vfs_fsync(dump->yuv_fp, 0);
+
+ filp_close(dump->yuv_fp, current->files);
+ dump->yuv_pos = 0;
+ dump->yuv_fp = NULL;
+ set_disable(mgr, YUV_MASK);
+ dbg_print(FC_YUV_DEBUG,
+ "closed yuv file, dump yuv exit\n");
+ dump->num = 0;
+ dump->dump_cnt = 0;
+ if (dump->buf_addr != NULL)
+ vfree(dump->buf_addr);
+ dump->buf_addr = NULL;
+ dump->buf_size = 0;
+ }
+ }
+
+ return 0;
+}
+
+static int write_crc_work(struct pic_check_mgr_t *mgr)
+{
+ unsigned int wr_size;
+ char *crc_buf, crc_tmp[64*30];
+ mm_segment_t old_fs;
+ struct pic_check_t *check = &mgr->pic_check;
+
+ if (mgr->enable & CRC_MASK) {
+ wr_size = 0;
+ while (kfifo_get(&check->wr_chk_q, &crc_buf) != 0) {
+ wr_size += sprintf(&crc_tmp[wr_size], "%s", crc_buf);
+ if (check->compare_fp != NULL) {
+ if (!fget_crc_str(crc_buf, SIZE_CRC, check)) {
+ dbg_print(0, "%s, can't get more compare crc\n", __func__);
+ filp_close(check->compare_fp, current->files);
+ check->compare_fp = NULL;
+ }
+ }
+ kfifo_put(&check->new_chk_q, crc_buf);
+ }
+ if (check->check_fp && (wr_size != 0)) {
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ if (wr_size != vfs_write(check->check_fp,
+ crc_tmp, wr_size, &check->check_pos)) {
+ dbg_print(FC_ERROR, "failed to check_dump_filp\n");
+ }
+ set_fs(old_fs);
+ }
+ }
+ return 0;
+}
+
+
+static int write_aux_data_crc_work(struct aux_data_check_mgr_t *mgr)
+{
+ unsigned int wr_size;
+ char *crc_buf, crc_tmp[64*30];
+ mm_segment_t old_fs;
+ struct aux_data_check_t *check = &mgr->aux_data_check;
+
+ if (mgr->enable & AUX_MASK) {
+ wr_size = 0;
+ while (kfifo_get(&check->wr_chk_q, &crc_buf) != 0) {
+ wr_size += sprintf(&crc_tmp[wr_size], "%s", crc_buf);
+ if (check->compare_fp != NULL) {
+ if (!fget_aux_data_crc_str(crc_buf, SIZE_CRC, check)) {
+ dbg_print(0, "%s, can't get more compare crc\n", __func__);
+ filp_close(check->compare_fp, current->files);
+ check->compare_fp = NULL;
+ }
+ }
+ kfifo_put(&check->new_chk_q, crc_buf);
+ }
+ if (check->check_fp && (wr_size != 0)) {
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ if (wr_size != vfs_write(check->check_fp,
+ crc_tmp, wr_size, &check->check_pos)) {
+ dbg_print(FC_ERROR, "failed to check_dump_filp\n");
+ }
+ set_fs(old_fs);
+ }
+ }
+ return 0;
+}
+
+
+
+static void do_check_work(struct work_struct *work)
+{
+ struct pic_check_mgr_t *mgr = container_of(work,
+ struct pic_check_mgr_t, frame_check_work);
+
+ write_yuv_work(mgr);
+
+ write_crc_work(mgr);
+}
+
+static void do_aux_data_check_work(struct work_struct *work)
+{
+ struct aux_data_check_mgr_t *mgr = container_of(work,
+ struct aux_data_check_mgr_t, aux_data_check_work);
+
+ write_aux_data_crc_work(mgr);
+}
+
+
+static int memcpy_phy_to_virt(char *to_virt,
+ ulong phy_from, unsigned int size)
+{
+ void *vaddr = NULL;
+ unsigned int tmp_size = 0;
+
+ if (single_mode_vdec != NULL) {
+ unsigned int offset = phy_from & (~PAGE_MASK);
+ while (size > 0) {
+ /* flush dcache in isr. */
+ flush_dcache_page(phys_to_page(phy_from));
+
+ if (offset + size >= PAGE_SIZE) {
+ vaddr = kmap_atomic(phys_to_page(phy_from));
+ tmp_size = (PAGE_SIZE - offset);
+ phy_from += tmp_size; //for next loop;
+ size -= tmp_size;
+ vaddr += offset;
+ } else {
+ vaddr = kmap_atomic(phys_to_page(phy_from));
+ vaddr += offset;
+ tmp_size = size;
+ size = 0;
+ }
+ if (vaddr == NULL) {
+ dbg_print(FC_CRC_DEBUG, "%s: kmap_atomic failed phy: 0x%x\n",
+ __func__, (unsigned int)phy_from);
+ return -1;
+ }
+
+ memcpy(to_virt, vaddr, tmp_size);
+ to_virt += tmp_size;
+
+ kunmap_atomic(vaddr - offset);
+ offset = 0;
+ }
+ } else {
+ while (size > 0) {
+ if (size >= VMAP_STRIDE_SIZE) {
+ vaddr = codec_mm_vmap(phy_from, VMAP_STRIDE_SIZE);
+ tmp_size = VMAP_STRIDE_SIZE;
+ phy_from += VMAP_STRIDE_SIZE;
+ size -= VMAP_STRIDE_SIZE;
+ } else {
+ vaddr = codec_mm_vmap(phy_from, size);
+ tmp_size = size;
+ size = 0;
+ }
+ if (vaddr == NULL) {
+ dbg_print(FC_YUV_DEBUG, "%s: codec_mm_vmap failed phy: 0x%x\n",
+ __func__, (unsigned int)phy_from);
+ return -1;
+ }
+ codec_mm_dma_flush(vaddr,
+ tmp_size, DMA_FROM_DEVICE);
+ memcpy(to_virt, vaddr, tmp_size);
+ to_virt += tmp_size;
+
+ codec_mm_unmap_phyaddr(vaddr);
+ }
+ }
+ return 0;
+}
+
+
+static int do_yuv_unit_cp(void **addr, ulong phy, void *virt,
+ int h, int w, int stride)
+{
+ int ret = 0, i;
+ void *tmp = *addr;
+
+ if ((phy != 0) && (virt == NULL)) {
+ for (i = 0; i < h; i++) {
+ ret |= memcpy_phy_to_virt(tmp, phy, w);
+ phy += stride;
+ tmp += w;
+ }
+ } else {
+ for (i = 0; i < h; i++) {
+ memcpy(tmp, virt, w);
+ virt += stride;
+ tmp += w;
+ }
+ }
+ *addr = tmp;
+
+ return ret;
+}
+
+static int do_yuv_dump(struct pic_check_mgr_t *mgr, struct vframe_s *vf)
+{
+ int ret = 0;
+ void *tmp_addr;
+ struct pic_dump_t *dump = &mgr->pic_dump;
+
+ if (dump->start > 0) {
+ dump->start--;
+ return 0;
+ }
+
+ if (dump->dump_cnt >= dump->num) {
+ mgr->enable &= (~YUV_MASK);
+ dump->num = 0;
+ dump->dump_cnt = 0;
+ return 0;
+ }
+
+ if (single_mode_vdec != NULL) {
+ if (mgr->size_pic >
+ (dump->buf_size - dump->dump_cnt * mgr->size_pic)) {
+ if (dump->buf_size) {
+ dbg_print(FC_ERROR,
+ "not enough buf for single mode, force dump less\n");
+ dump->num = dump->dump_cnt;
+ check_schedule(mgr);
+ } else
+ set_disable(mgr, YUV_MASK);
+ return -1;
+ }
+ tmp_addr = dump->buf_addr +
+ mgr->size_pic * dump->dump_cnt;
+ } else {
+ if (mgr->size_pic > dump->buf_size) {
+ dbg_print(FC_ERROR,
+ "not enough size, pic/buf size: 0x%x/0x%x\n",
+ mgr->size_pic, dump->buf_size);
+ return -1;
+ }
+ tmp_addr = dump->buf_addr;
+ }
+
+ if (vf->width == mgr->canvas_w) {
+ if ((mgr->uv_vaddr == NULL) || (mgr->y_vaddr == NULL)) {
+ ret |= memcpy_phy_to_virt(tmp_addr, mgr->y_phyaddr, mgr->size_y);
+ ret |= memcpy_phy_to_virt(tmp_addr + mgr->size_y,
+ mgr->uv_phyaddr, mgr->size_uv);
+ if (mgr->mjpeg_flag) /*mjpeg yuv420 u v is separate */
+ ret |= memcpy_phy_to_virt(tmp_addr + mgr->size_y + mgr->size_uv,
+ mgr->extra_v_phyaddr, mgr->size_uv);
+ } else {
+ memcpy(tmp_addr, mgr->y_vaddr, mgr->size_y);
+ memcpy(tmp_addr + mgr->size_y, mgr->uv_vaddr, mgr->size_uv);
+ if (mgr->mjpeg_flag) /*mjpeg u v is separate */
+ memcpy(tmp_addr + mgr->size_y + mgr->size_uv,
+ mgr->extra_v_vaddr, mgr->size_uv);
+ }
+ } else {
+ u32 uv_stride, uv_cpsize;
+ ret |= do_yuv_unit_cp(&tmp_addr, mgr->y_phyaddr, mgr->y_vaddr,
+ vf->height, vf->width, mgr->canvas_w);
+
+ uv_stride = (mgr->mjpeg_flag) ? (mgr->canvas_w >> 1) : mgr->canvas_w;
+ uv_cpsize = (mgr->mjpeg_flag) ? (vf->width >> 1) : vf->width;
+ ret |= do_yuv_unit_cp(&tmp_addr, mgr->uv_phyaddr, mgr->uv_vaddr,
+ vf->height >> 1, uv_cpsize, uv_stride);
+
+ if (mgr->mjpeg_flag) {
+ ret |= do_yuv_unit_cp(&tmp_addr, mgr->extra_v_phyaddr, mgr->extra_v_vaddr,
+ vf->height >> 1, uv_cpsize, uv_stride);
+ }
+ }
+
+ dump->dump_cnt++;
+ dbg_print(0, "----->dump %dst, size %x (%d x %d), dec total %d\n",
+ dump->dump_cnt, mgr->size_pic, vf->width, vf->height, mgr->frame_cnt);
+
+ if (single_mode_vdec != NULL) {
+ /* single mode need schedule work to write*/
+ if (dump->dump_cnt >= dump->num)
+ check_schedule(mgr);
+ } else {
+ int wr_size;
+ mm_segment_t old_fs;
+
+ /* dump for dec pic not in isr */
+ if (dump->yuv_fp == NULL) {
+ dump->yuv_fp = file_open(O_CREAT | O_WRONLY | O_TRUNC,
+ "%s%s-%d-%d.yuv", YUV_PATH, comp_crc, mgr->id, mgr->file_cnt);
+ if (dump->yuv_fp == NULL)
+ return -1;
+ mgr->file_cnt++;
+ }
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ wr_size = vfs_write(dump->yuv_fp, dump->buf_addr,
+ mgr->size_pic, &dump->yuv_pos);
+ if (mgr->size_pic != wr_size) {
+ dbg_print(FC_ERROR, "buf failed to write yuv file\n");
+ }
+ set_fs(old_fs);
+ vfs_fsync(dump->yuv_fp, 0);
+ }
+
+ return 0;
+}
+
+static int crc_store(struct pic_check_mgr_t *mgr, struct vframe_s *vf,
+ int crc_y, int crc_uv)
+{
+ int ret = 0;
+ char *crc_addr = NULL;
+ int comp_frame = 0, comp_crc_y, comp_crc_uv;
+ struct pic_check_t *check = &mgr->pic_check;
+
+ mgr->yuvsum += crc_uv;
+ mgr->yuvsum += crc_y;
+
+ if (kfifo_get(&check->new_chk_q, &crc_addr) == 0) {
+ dbg_print(0, "%08d: %08x %08x\n",
+ mgr->frame_cnt, crc_y, crc_uv);
+ if (check->check_fp) {
+ dbg_print(0, "crc32 dropped\n");
+ } else {
+ dbg_print(0, "no opened file to write crc32\n");
+ }
+ return -1;
+ }
+ if (check->cmp_crc_cnt > mgr->frame_cnt) {
+ sscanf(crc_addr, "%08u: %8x %8x",
+ &comp_frame, &comp_crc_y, &comp_crc_uv);
+
+ dbg_print(0, "%08d: %08x %08x <--> %08d: %08x %08x\n",
+ mgr->frame_cnt, crc_y, crc_uv,
+ comp_frame, comp_crc_y, comp_crc_uv);
+
+ if (comp_frame == mgr->frame_cnt) {
+ if ((comp_crc_y != crc_y) || (crc_uv != comp_crc_uv)) {
+ mgr->pic_dump.start = 0;
+ if (fc_debug || mgr->pic_dump.num < 3)
+ mgr->pic_dump.num++;
+ dbg_print(0, "\n\nError: %08d: %08x %08x != %08x %08x\n\n",
+ mgr->frame_cnt, crc_y, crc_uv, comp_crc_y, comp_crc_uv);
+ if (!(vf->type & VIDTYPE_SCATTER))
+ do_yuv_dump(mgr, vf);
+ if (fc_debug & FC_ERR_CRC_BLOCK_MODE)
+ mgr->err_crc_block = 1;
+ mgr->usr_cmp_result = -1;
+ }
+ } else {
+ mgr->usr_cmp_result = -1;
+ dbg_print(0, "frame num error: frame_cnt(%d) frame_comp(%d)\n",
+ mgr->frame_cnt, comp_frame);
+ }
+ } else {
+ dbg_print(0, "%08d: %08x %08x\n", mgr->frame_cnt, crc_y, crc_uv);
+ }
+
+ if ((check->check_fp) && (crc_addr != NULL)) {
+ ret = snprintf(crc_addr, SIZE_CRC,
+ "%08d: %08x %08x\n", mgr->frame_cnt, crc_y, crc_uv);
+
+ kfifo_put(&check->wr_chk_q, crc_addr);
+ if ((mgr->frame_cnt & 0xf) == 0)
+ check_schedule(mgr);
+ }
+ return ret;
+}
+
+static int aux_data_crc_store(struct aux_data_check_mgr_t *mgr,int crc)
+{
+ int ret = 0;
+ char *crc_addr = NULL;
+ int comp_frame = 0, comp_crc;
+ struct aux_data_check_t *check = &mgr->aux_data_check;
+
+ if (kfifo_get(&check->new_chk_q, &crc_addr) == 0) {
+ dbg_print(0, "%08d: %08x\n",
+ mgr->frame_cnt, crc);
+ if (check->check_fp) {
+ dbg_print(0, "crc32 dropped\n");
+ } else {
+ dbg_print(0, "no opened file to write crc32\n");
+ }
+ return -1;
+ }
+ if (check->cmp_crc_cnt > mgr->frame_cnt) {
+ sscanf(crc_addr, "%08u: %8x",
+ &comp_frame, &comp_crc);
+
+ dbg_print(0, "%08d: %08x <--> %08d: %08x\n",
+ mgr->frame_cnt, crc,
+ comp_frame, comp_crc);
+ if (comp_frame == mgr->frame_cnt) {
+ if (comp_crc != crc) {
+ dbg_print(0, "\n\nError: %08d: %08x != %08x \n\n",
+ mgr->frame_cnt, crc, comp_crc);
+ }
+ } else {
+ dbg_print(0, "frame num error: frame_cnt(%d) frame_comp(%d)\n",
+ mgr->frame_cnt, comp_frame);
+ }
+ } else {
+ dbg_print(0, "%08d: %08x\n", mgr->frame_cnt, crc);
+ }
+
+ if ((check->check_fp) && (crc_addr != NULL)) {
+ ret = snprintf(crc_addr, SIZE_CRC,
+ "%08d: %08x\n", mgr->frame_cnt, crc);
+
+ kfifo_put(&check->wr_chk_q, crc_addr);
+ if ((mgr->frame_cnt & 0xf) == 0)
+ aux_data_check_schedule(mgr);
+ }
+ return ret;
+}
+
+
+
+static int crc32_vmap_le(unsigned int *crc32,
+ ulong phyaddr, unsigned int size)
+{
+ void *vaddr = NULL;
+ unsigned int crc = *crc32;
+ unsigned int tmp_size = 0;
+
+ /*single mode cannot use codec_mm_vmap*/
+ if (single_mode_vdec != NULL) {
+ unsigned int offset = phyaddr & (~PAGE_MASK);
+ while (size > 0) {
+ /*flush dcache in isr.*/
+ flush_dcache_page(phys_to_page(phyaddr));
+
+ if (offset + size >= PAGE_SIZE) {
+ vaddr = kmap_atomic(phys_to_page(phyaddr));
+ tmp_size = (PAGE_SIZE - offset);
+ phyaddr += tmp_size;
+ size -= tmp_size;
+ vaddr += offset;
+ } else {
+ vaddr = kmap_atomic(phys_to_page(phyaddr));
+ tmp_size = size;
+ vaddr += offset;
+ size = 0;
+ }
+ if (vaddr == NULL) {
+ dbg_print(FC_CRC_DEBUG, "%s: kmap_atomic failed phy: 0x%x\n",
+ __func__, (unsigned int)phyaddr);
+ return -1;
+ }
+
+ crc = crc32_le(crc, vaddr, tmp_size);
+
+ kunmap_atomic(vaddr - offset);
+ offset = 0;
+ }
+ } else {
+ while (size > 0) {
+ if (size >= VMAP_STRIDE_SIZE) {
+ vaddr = codec_mm_vmap(phyaddr, VMAP_STRIDE_SIZE);
+ tmp_size = VMAP_STRIDE_SIZE;
+ phyaddr += VMAP_STRIDE_SIZE;
+ size -= VMAP_STRIDE_SIZE;
+ } else {
+ vaddr = codec_mm_vmap(phyaddr, size);
+ tmp_size = size;
+ size = 0;
+ }
+ if (vaddr == NULL) {
+ dbg_print(FC_CRC_DEBUG, "%s: codec_mm_vmap failed phy: 0x%x\n",
+ __func__, (unsigned int)phyaddr);
+ return -1;
+ }
+ codec_mm_dma_flush(vaddr,
+ tmp_size, DMA_FROM_DEVICE);
+
+ crc = crc32_le(crc, vaddr, tmp_size);
+
+ codec_mm_unmap_phyaddr(vaddr);
+ }
+ }
+ *crc32 = crc;
+
+ return 0;
+}
+
+static int do_check_nv21(struct pic_check_mgr_t *mgr, struct vframe_s *vf)
+{
+ int i;
+ unsigned int crc_y = 0, crc_uv = 0;
+ void *p_yaddr, *p_uvaddr;
+ ulong y_phyaddr, uv_phyaddr;
+ int ret = 0;
+
+ p_yaddr = mgr->y_vaddr;
+ p_uvaddr = mgr->uv_vaddr;
+ y_phyaddr = mgr->y_phyaddr;
+ uv_phyaddr = mgr->uv_phyaddr;
+ if ((p_yaddr == NULL) || (p_uvaddr == NULL))
+ {
+ if (vf->width == mgr->canvas_w) {
+ ret = crc32_vmap_le(&crc_y, y_phyaddr, mgr->size_y);
+ ret |= crc32_vmap_le(&crc_uv, uv_phyaddr, mgr->size_uv);
+ } else {
+ for (i = 0; i < vf->height; i++) {
+ ret |= crc32_vmap_le(&crc_y, y_phyaddr, vf->width);
+ y_phyaddr += mgr->canvas_w;
+ }
+ for (i = 0; i < vf->height/2; i++) {
+ ret |= crc32_vmap_le(&crc_uv, uv_phyaddr, vf->width);
+ uv_phyaddr += mgr->canvas_w;
+ }
+ }
+ if (ret < 0) {
+ dbg_print(0, "calc crc failed, may codec_mm_vmap failed\n");
+ return ret;
+ }
+ } else {
+ if (mgr->frame_cnt == 0) {
+ unsigned int *p = mgr->y_vaddr;
+ dbg_print(0, "YUV0000: %08x-%08x-%08x-%08x\n",
+ p[0], p[1], p[2], p[3]);
+ }
+ if (vf->width == mgr->canvas_w) {
+ crc_y = crc32_le(crc_y, p_yaddr, mgr->size_y);
+ crc_uv = crc32_le(crc_uv, p_uvaddr, mgr->size_uv);
+ } else {
+ for (i = 0; i < vf->height; i++) {
+ crc_y = crc32_le(crc_y, p_yaddr, vf->width);
+ p_yaddr += mgr->canvas_w;
+ }
+ for (i = 0; i < vf->height/2; i++) {
+ crc_uv = crc32_le(crc_uv, p_uvaddr, vf->width);
+ p_uvaddr += mgr->canvas_w;
+ }
+ }
+ }
+
+ crc_store(mgr, vf, crc_y, crc_uv);
+
+ return 0;
+}
+
+static int do_check_yuv16(struct pic_check_mgr_t *mgr,
+ struct vframe_s *vf, char *ybuf, char *uvbuf,
+ char *ubuf, char *vbuf)
+{
+ unsigned int crc1, crc2, crc3, crc4;
+ int w, h;
+
+ w = vf->width;
+ h = vf->height;
+ crc1 = 0;
+ crc2 = 0;
+ crc3 = 0;
+ crc4 = 0;
+
+ crc1 = crc32_le(0, ybuf, w * h *2);
+ crc2 = crc32_le(0, ubuf, w * h/2);
+ crc3 = crc32_le(0, vbuf, w * h/2);
+ crc4 = crc32_le(0, uvbuf, w * h*2/2);
+ /*
+ printk("%08d: %08x %08x %08x %08x\n",
+ mgr->frame_cnt, crc1, crc4, crc2, crc3);
+ */
+ mgr->size_y = w * h * 2;
+ mgr->size_uv = w * h;
+ mgr->size_pic = mgr->size_y + mgr->size_uv;
+ mgr->y_vaddr = ybuf;
+ mgr->uv_vaddr = uvbuf;
+ mgr->canvas_w = w;
+ mgr->canvas_h = h;
+ crc_store(mgr, vf, crc1, crc4);
+
+ return 0;
+}
+
+static int do_check_aux_data_crc(struct aux_data_check_mgr_t *mgr,
+ char *aux_buf, int size)
+{
+ unsigned int crc = 0;
+
+ crc = crc32_le(0, aux_buf, size);
+
+ //pr_info("%s:crc = %08x\n",crc);
+ aux_data_crc_store(mgr,crc);
+
+ return 0;
+}
+
+
+static int fbc_check_prepare(struct pic_check_t *check,
+ int resize, int y_size)
+{
+ int i = 0;
+
+ if (y_size > MAX_SIZE_AFBC_PLANES)
+ return -1;
+
+ if (((!check->fbc_planes[0]) ||
+ (!check->fbc_planes[1]) ||
+ (!check->fbc_planes[2]) ||
+ (!check->fbc_planes[3])) &&
+ (!resize))
+ return -1;
+
+ if (resize) {
+ dbg_print(0, "size changed to 0x%x(y_size)\n", y_size);
+ for (i = 0; i < ARRAY_SIZE(check->fbc_planes); i++) {
+ if (check->fbc_planes[i]) {
+ vfree(check->fbc_planes[i]);
+ check->fbc_planes[i] = NULL;
+ }
+ }
+ }
+ for (i = 0; i < ARRAY_SIZE(check->fbc_planes); i++) {
+ if (!check->fbc_planes[i])
+ check->fbc_planes[i] =
+ vmalloc(y_size * sizeof(short));
+ }
+ if ((!check->fbc_planes[0]) ||
+ (!check->fbc_planes[1]) ||
+ (!check->fbc_planes[2]) ||
+ (!check->fbc_planes[3])) {
+ dbg_print(0, "vmalloc staicplanes failed %lx %lx %lx %lx\n",
+ (ulong)check->fbc_planes[0],
+ (ulong)check->fbc_planes[1],
+ (ulong)check->fbc_planes[2],
+ (ulong)check->fbc_planes[3]);
+ for (i = 0; i < ARRAY_SIZE(check->fbc_planes); i++) {
+ if (check->fbc_planes[i]) {
+ vfree(check->fbc_planes[i]);
+ check->fbc_planes[i] = NULL;
+ }
+ }
+ return -1;
+ } else
+ dbg_print(FC_CRC_DEBUG, "vmalloc staicplanes sucessed\n");
+
+ return 0;
+}
+
+int load_user_cmp_crc(struct pic_check_mgr_t *mgr)
+{
+ int i;
+ struct pic_check_t *chk;
+ void *qaddr;
+
+ if (mgr == NULL ||
+ (mgr->cmp_pool == NULL)||
+ (mgr->usr_cmp_num == 0))
+ return 0;
+
+ chk = &mgr->pic_check;
+
+ if (chk->cmp_crc_cnt > 0) {
+ pr_info("cmp crc32 data is ready\n");
+ return -1;
+ }
+
+ if (chk->check_addr == NULL) {
+ pr_info("no cmp crc buf\n"); /* vmalloc again or return */
+ return -1;
+ }
+
+ if (mgr->usr_cmp_num >= USER_CMP_POOL_MAX_SIZE)
+ mgr->usr_cmp_num = USER_CMP_POOL_MAX_SIZE - 1;
+
+ for (i = 0; i < mgr->usr_cmp_num; i++) {
+ qaddr = chk->check_addr + i * SIZE_CRC;
+ dbg_print(FC_CRC_DEBUG, "%s, %8d: %08x %08x\n", __func__,
+ mgr->cmp_pool[i].pic_num,
+ mgr->cmp_pool[i].y_crc,
+ mgr->cmp_pool[i].uv_crc);
+ sprintf(qaddr, "%8d: %08x %08x\n",
+ mgr->cmp_pool[i].pic_num,
+ mgr->cmp_pool[i].y_crc,
+ mgr->cmp_pool[i].uv_crc);
+
+ kfifo_put(&chk->new_chk_q, qaddr);
+ chk->cmp_crc_cnt++;
+ }
+
+ mgr->usr_cmp_result = 0;
+
+ vfree(mgr->cmp_pool);
+ mgr->cmp_pool = NULL;
+
+ return 0;
+}
+
+
+int decoder_do_frame_check(struct vdec_s *vdec, struct vframe_s *vf)
+{
+ int resize = 0;
+ void *planes[4];
+ struct pic_check_t *check = NULL;
+ struct pic_check_mgr_t *mgr = NULL;
+ int ret = 0;
+
+ if (vdec == NULL) {
+ if (single_mode_vdec == NULL)
+ return 0;
+ mgr = &single_mode_vdec->vfc;
+ } else {
+ mgr = &vdec->vfc;
+ single_mode_vdec = NULL;
+ }
+
+ if ((mgr == NULL) || (vf == NULL) ||
+ (mgr->enable == 0))
+ return 0;
+
+ mgr->mjpeg_flag = ((vdec) &&
+ (vdec->format == VFORMAT_MJPEG)) ? 1 : 0;
+
+ if (get_frame_size(mgr, vf) < 0)
+ return -1;
+
+ if (mgr->last_size_pic != mgr->size_pic) {
+ resize = 1;
+ dbg_print(0, "size changed, %x-->%x [%d x %d]\n",
+ mgr->last_size_pic, mgr->size_pic,
+ vf->width, vf->height);
+ /* for slt, if no compare crc file, use the
+ * cmp crc from amstream ioctl write */
+ load_user_cmp_crc(mgr);
+ } else
+ resize = 0;
+ mgr->last_size_pic = mgr->size_pic;
+
+ if ((vf->type & VIDTYPE_VIU_NV21) || (mgr->mjpeg_flag)) {
+ int flush_size;
+
+ if (canvas_get_virt_addr(mgr, vf) < 0)
+ return -2;
+
+ /* flush */
+ flush_size = mgr->mjpeg_flag ?
+ ((mgr->canvas_w * mgr->canvas_h) >> 2) :
+ ((mgr->canvas_w * mgr->canvas_h) >> 1);
+ if (mgr->y_vaddr)
+ codec_mm_dma_flush(mgr->y_vaddr,
+ mgr->canvas_w * mgr->canvas_h, DMA_FROM_DEVICE);
+ if (mgr->uv_vaddr)
+ codec_mm_dma_flush(mgr->uv_vaddr,
+ flush_size, DMA_FROM_DEVICE);
+ if ((mgr->mjpeg_flag) && (mgr->extra_v_vaddr))
+ codec_mm_dma_flush(mgr->extra_v_vaddr,
+ flush_size, DMA_FROM_DEVICE);
+
+ if (mgr->enable & CRC_MASK)
+ ret = do_check_nv21(mgr, vf);
+
+ if (mgr->enable & YUV_MASK)
+ do_yuv_dump(mgr, vf);
+
+ } else if (vf->type & VIDTYPE_SCATTER) {
+ check = &mgr->pic_check;
+
+ if (mgr->pic_dump.buf_addr != NULL) {
+ dbg_print(0, "scatter free yuv buf\n");
+ vfree(mgr->pic_dump.buf_addr);
+ mgr->pic_dump.buf_addr = NULL;
+ }
+ if (fbc_check_prepare(check,
+ resize, mgr->size_y) < 0)
+ return -3;
+ planes[0] = check->fbc_planes[0];
+ planes[1] = check->fbc_planes[1];
+ planes[2] = check->fbc_planes[2];
+ planes[3] = check->fbc_planes[3];
+ ret = AMLOGIC_FBC_vframe_decoder(planes, vf, 0, 0);
+ if (ret < 0) {
+ dbg_print(0, "amlogic_fbc_lib.ko error %d\n", ret);
+ } else {
+ do_check_yuv16(mgr, vf,
+ (void *)planes[0], (void *)planes[3],//uv
+ (void *)planes[1], (void *)planes[2]);
+ }
+ }
+ mgr->frame_cnt++;
+
+ if (mgr->usr_cmp_num > 0) {
+ mgr->usr_cmp_num -= 1;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(decoder_do_frame_check);
+
+int decoder_do_aux_data_check(struct vdec_s *vdec, char *aux_buffer, int size)
+{
+ struct aux_data_check_mgr_t *mgr = NULL;
+ int ret = 0;
+
+ if (vdec == NULL) {
+ return 0;
+ } else {
+ mgr = &vdec->adc;
+ }
+
+ if ((mgr == NULL) || (mgr->enable == 0))
+ return 0;
+
+ if (mgr->enable & AUX_MASK)
+ ret = do_check_aux_data_crc(mgr,aux_buffer,size);
+
+ mgr->frame_cnt++;
+
+ return ret;
+}
+EXPORT_SYMBOL(decoder_do_aux_data_check);
+
+static int dump_buf_alloc(struct pic_dump_t *dump)
+{
+ if ((dump->buf_addr != NULL) &&
+ (dump->buf_size != 0))
+ return 0;
+
+ dump->buf_addr =
+ (char *)vmalloc(size_yuv_buf);
+ if (!dump->buf_addr) {
+ dump->buf_size = 0;
+ dbg_print(0, "vmalloc yuv buf failed\n");
+ return -ENOMEM;
+ }
+ dump->buf_size = size_yuv_buf;
+
+ dbg_print(0, "%s: buf for yuv is alloced\n", __func__);
+
+ return 0;
+}
+
+int dump_yuv_trig(struct pic_check_mgr_t *mgr,
+ int id, int start, int num)
+{
+ struct pic_dump_t *dump = &mgr->pic_dump;
+
+ if (!dump->num) {
+ mgr->id = id;
+ dump->start = start;
+ dump->num = num;
+ dump->end = start + num;
+ dump->dump_cnt = 0;
+ dump->yuv_fp = NULL;
+ if (!atomic_read(&mgr->work_inited)) {
+ INIT_WORK(&mgr->frame_check_work, do_check_work);
+ atomic_set(&mgr->work_inited, 1);
+ }
+ dump_buf_alloc(dump);
+ str_strip(comp_crc);
+ set_enable(mgr, YUV_MASK);
+ } else {
+ dbg_print(FC_ERROR, "yuv dump now, trig later\n");
+ return -EBUSY;
+ }
+ dbg_print(0, "dump yuv trigger, from %d to %d frame\n",
+ dump->start, dump->end);
+ return 0;
+}
+
+int frame_check_init(struct pic_check_mgr_t *mgr, int id)
+{
+ int i;
+ struct pic_dump_t *dump = &mgr->pic_dump;
+ struct pic_check_t *check = &mgr->pic_check;
+
+ mgr->frame_cnt = 0;
+ mgr->size_pic = 0;
+ mgr->last_size_pic = 0;
+ mgr->id = id;
+ mgr->yuvsum = 0;
+ mgr->height = 0;
+ mgr->width = 0;
+
+ dump->num = 0;
+ dump->dump_cnt = 0;
+ dump->yuv_fp = NULL;
+ check->check_pos = 0;
+ check->compare_pos = 0;
+
+ if (!atomic_read(&mgr->work_inited)) {
+ INIT_WORK(&mgr->frame_check_work, do_check_work);
+ atomic_set(&mgr->work_inited, 1);
+ }
+ /* for dump error yuv prepare. */
+ dump_buf_alloc(dump);
+
+ /* try to open compare crc32 file */
+ str_strip(comp_crc);
+ check->compare_fp = file_open(O_RDONLY,
+ "%s%s", CRC_PATH, comp_crc);
+
+ /* create crc32 log file */
+ check->check_fp = file_open(O_CREAT| O_WRONLY | O_TRUNC,
+ "%s%s-%d-%d.crc", CRC_PATH, comp_crc, id, mgr->file_cnt);
+
+ INIT_KFIFO(check->new_chk_q);
+ INIT_KFIFO(check->wr_chk_q);
+ check->check_addr = vmalloc(SIZE_CRC * SIZE_CHECK_Q);
+ if (check->check_addr == NULL) {
+ dbg_print(FC_ERROR, "vmalloc qbuf fail\n");
+ } else {
+ void *qaddr = NULL, *rdret = NULL;
+ check->cmp_crc_cnt = 0;
+ for (i = 0; i < SIZE_CHECK_Q; i++) {
+ qaddr = check->check_addr + i * SIZE_CRC;
+ rdret = fget_crc_str(qaddr,
+ SIZE_CRC, check);
+ if (rdret == NULL) {
+ if (i < 3)
+ dbg_print(0, "can't get compare crc string\n");
+ if (check->compare_fp) {
+ filp_close(check->compare_fp, current->files);
+ check->compare_fp = NULL;
+ }
+ }
+
+ kfifo_put(&check->new_chk_q, qaddr);
+ }
+ }
+ set_enable(mgr, CRC_MASK);
+ dbg_print(0, "%s end\n", __func__);
+
+ return 0;
+}
+
+
+int aux_data_check_init(struct aux_data_check_mgr_t *mgr, int id)
+{
+ int i;
+ struct aux_data_check_t *check = &mgr->aux_data_check;
+
+ mgr->frame_cnt = 0;
+ mgr->id = id;
+
+ check->check_pos = 0;
+ check->compare_pos = 0;
+
+ if (!atomic_read(&mgr->work_inited)) {
+ INIT_WORK(&mgr->aux_data_check_work, do_aux_data_check_work);
+ atomic_set(&mgr->work_inited, 1);
+ }
+
+ /* try to open compare meta crc32 file */
+ str_strip(aux_comp_crc);
+ check->compare_fp = file_open(O_RDONLY,
+ "%s%s", CRC_PATH, aux_comp_crc);
+
+ /* create meta crc log file */
+ check->check_fp = file_open(O_CREAT| O_WRONLY | O_TRUNC,
+ "%s%s-%d-%d.crc", CRC_PATH, aux_comp_crc, id, mgr->file_cnt);
+
+ INIT_KFIFO(check->new_chk_q);
+ INIT_KFIFO(check->wr_chk_q);
+ check->check_addr = vmalloc(SIZE_CRC * SIZE_CHECK_Q);
+ if (check->check_addr == NULL) {
+ dbg_print(FC_ERROR, "vmalloc qbuf fail\n");
+ } else {
+ void *qaddr = NULL, *rdret = NULL;
+ check->cmp_crc_cnt = 0;
+ for (i = 0; i < SIZE_CHECK_Q; i++) {
+ qaddr = check->check_addr + i * SIZE_CRC;
+ rdret = fget_aux_data_crc_str(qaddr,
+ SIZE_CRC, check);
+ if (rdret == NULL) {
+ if (i < 3)
+ dbg_print(0, "can't get compare crc string\n");
+ if (check->compare_fp) {
+ filp_close(check->compare_fp, current->files);
+ check->compare_fp = NULL;
+ }
+ }
+
+ kfifo_put(&check->new_chk_q, qaddr);
+ }
+ }
+ aux_set_enable(mgr, AUX_MASK);
+ dbg_print(0, "%s end\n", __func__);
+
+ return 0;
+}
+
+
+void frame_check_exit(struct pic_check_mgr_t *mgr)
+{
+ int i;
+ struct pic_dump_t *dump = &mgr->pic_dump;
+ struct pic_check_t *check = &mgr->pic_check;
+
+ if (mgr->enable != 0) {
+ if (dump->dump_cnt != 0) {
+ dbg_print(0, "%s, cnt = %d, num = %d\n",
+ __func__, dump->dump_cnt, dump->num);
+ set_enable(mgr, YUV_MASK);
+ }
+ if (atomic_read(&mgr->work_inited)) {
+ cancel_work_sync(&mgr->frame_check_work);
+ atomic_set(&mgr->work_inited, 0);
+ }
+ if (single_mode_vdec != NULL)
+ write_yuv_work(mgr);
+ write_crc_work(mgr);
+
+ for (i = 0; i < ARRAY_SIZE(check->fbc_planes); i++) {
+ if (check->fbc_planes[i]) {
+ vfree(check->fbc_planes[i]);
+ check->fbc_planes[i] = NULL;
+ }
+ }
+ if (check->check_addr) {
+ vfree(check->check_addr);
+ check->check_addr = NULL;
+ }
+
+ if (mgr->cmp_pool) {
+ vfree(mgr->cmp_pool);
+ mgr->cmp_pool = NULL;
+ }
+
+ if (check->check_fp) {
+ filp_close(check->check_fp, current->files);
+ check->check_fp = NULL;
+ }
+ if (check->compare_fp) {
+ filp_close(check->compare_fp, current->files);
+ check->compare_fp = NULL;
+ }
+ if (dump->yuv_fp) {
+ filp_close(dump->yuv_fp, current->files);
+ dump->yuv_fp = NULL;
+ }
+ if (dump->buf_addr) {
+ vfree(dump->buf_addr);
+ dump->buf_addr = NULL;
+ }
+ mgr->file_cnt++;
+ set_disable(mgr, YUV_MASK | CRC_MASK);
+ dbg_print(0, "%s end\n", __func__);
+ }
+}
+
+void aux_data_check_exit(struct aux_data_check_mgr_t *mgr)
+{
+ //struct pic_dump_t *dump = &mgr->pic_dump;
+ struct aux_data_check_t *check = &mgr->aux_data_check;
+
+ if (mgr->enable != 0) {
+ if (atomic_read(&mgr->work_inited)) {
+ cancel_work_sync(&mgr->aux_data_check_work);
+ atomic_set(&mgr->work_inited, 0);
+ }
+
+ write_aux_data_crc_work(mgr);
+
+ if (check->check_addr) {
+ vfree(check->check_addr);
+ check->check_addr = NULL;
+ }
+
+ if (check->check_fp) {
+ filp_close(check->check_fp, current->files);
+ check->check_fp = NULL;
+ }
+ if (check->compare_fp) {
+ filp_close(check->compare_fp, current->files);
+ check->compare_fp = NULL;
+ }
+
+ mgr->file_cnt++;
+ aux_set_disable(mgr, AUX_MASK);
+ dbg_print(0, "%s end\n", __func__);
+ }
+}
+
+
+
+int vdec_frame_check_init(struct vdec_s *vdec)
+{
+ int ret = 0, id = 0;
+
+ if (vdec == NULL)
+ return 0;
+
+ if ((vdec->is_reset) &&
+ (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_GXL))
+ return 0;
+
+ vdec->vfc.err_crc_block = 0;
+ single_mode_vdec = (vdec_single(vdec))? vdec : NULL;
+
+ if (!check_enable && !yuv_enable)
+ return 0;
+
+ vdec->canvas_mode = CANVAS_BLKMODE_LINEAR;
+ id = vdec->id;
+
+ if (check_enable & (0x01 << id)) {
+ frame_check_init(&vdec->vfc, id);
+ /*repeat check one video crc32, not clear enable*/
+ if ((fc_debug & FC_CHECK_CRC_LOOP_MODE) == 0)
+ check_enable &= ~(0x01 << id);
+ }
+
+ if (yuv_enable & (0x01 << id)) {
+ ret = dump_yuv_trig(&vdec->vfc,
+ id, yuv_start[id], yuv_num[id]);
+ if (ret < 0)
+ pr_info("dump yuv init failed\n");
+ else {
+ pr_info("dump yuv init ok, total %d\n",
+ yuv_num[id]);
+ vdec->canvas_mode = CANVAS_BLKMODE_LINEAR;
+ }
+ yuv_num[id] = 0;
+ yuv_start[id] = 0;
+ yuv_enable &= ~(0x01 << id);
+ }
+
+ return ret;
+}
+
+int print_decoder_info(struct vdec_s *vdec)
+{
+ if (vdec->vfc.enable & CRC_MASK) {
+ const char *format_name;
+
+ format_name = get_format_name(vdec->format);
+ if (format_name == NULL)
+ return -1;
+
+ dbg_print(0, "Decoder-Summary:Type:%10s,framesize:%04dx%04d;out-nums:%08d,yuvsum:%08x\n",
+ format_name, vdec->vfc.width, vdec->vfc.height,
+ vdec->vfc.frame_cnt, vdec->vfc.yuvsum);
+ sprintf(checksum_info, "Type:%10s,framesize:%04dx%04d,out-nums:%08d,yuvsum:%08x",
+ format_name, vdec->vfc.width, vdec->vfc.height,
+ vdec->vfc.frame_cnt, vdec->vfc.yuvsum);
+ if (checksum_enable) {
+ struct file *checksum_fp;
+ static loff_t checksum_pos;
+ mm_segment_t old_fs;
+ char checksum_buf[128]="\n";
+ static int num;
+ static char file_name[128];
+
+ if (strcmp(checksum_filename,file_name) != 0) {
+ num = 0;
+ checksum_pos = 0;
+ strcpy(file_name,checksum_filename);
+ }
+ if (checksum_start_count == 1) {
+ num = 0;
+ checksum_start_count = 0;
+ }
+
+ str_strip(checksum_filename);
+ checksum_fp = file_open(O_CREAT| O_WRONLY | O_APPEND,
+ "%s%s.txt", CHECKSUM_PATH,checksum_filename);
+ if (checksum_fp == NULL) {
+ return -1;
+ }
+ sprintf(checksum_buf, "%08d (Type:%10s, framesize:%04dx%04d, out-nums:%08d, yuvsum:%08x)\n",
+ num,format_name, vdec->vfc.width, vdec->vfc.height,
+ vdec->vfc.frame_cnt, vdec->vfc.yuvsum);
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ vfs_write(checksum_fp, checksum_buf,
+ strlen(checksum_buf), &checksum_pos);
+
+ set_fs(old_fs);
+
+ filp_close(checksum_fp, current->files);
+ checksum_fp = NULL;
+ num++;
+ }
+ }
+
+ return 0;
+}
+
+int vdec_aux_data_check_init(struct vdec_s *vdec)
+{
+ int ret = 0, id = 0;
+
+ if (vdec == NULL)
+ return 0;
+
+ if ((vdec->is_reset) &&
+ (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_GXL))
+ return 0;
+
+ if (!aux_enable)
+ return 0;
+
+ id = vdec->id;
+
+ if (aux_enable & (0x01 << id)) {
+ aux_data_check_init(&vdec->adc, id);
+ /*repeat check one video meta crc32, not clear enable*/
+ if ((fc_debug & AD_CHECK_CRC_LOOP_MODE) == 0)
+ aux_enable &= ~(0x01 << id);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(vdec_aux_data_check_init);
+
+
+void vdec_aux_data_check_exit(struct vdec_s *vdec)
+{
+ if (vdec == NULL)
+ return;
+ aux_data_check_exit(&vdec->adc);
+}
+EXPORT_SYMBOL(vdec_aux_data_check_exit);
+
+
+void vdec_frame_check_exit(struct vdec_s *vdec)
+{
+ if (vdec == NULL)
+ return;
+ print_decoder_info(vdec);
+ frame_check_exit(&vdec->vfc);
+
+ single_mode_vdec = NULL;
+}
+
+ssize_t dump_yuv_store(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct vdec_s *vdec = NULL;
+ unsigned int id = 0, num = 0, start = 0;
+ int ret = -1;
+
+ ret = sscanf(buf, "%d %d %d", &id, &start, &num);
+ if (ret < 0) {
+ pr_info("%s, parse failed\n", buf);
+ return size;
+ }
+ if ((num == 0) || (num > YUV_MAX_DUMP_NUM)) {
+ pr_info("requred yuv num %d, max %d\n",
+ num, YUV_MAX_DUMP_NUM);
+ return size;
+ }
+ vdec = vdec_get_vdec_by_id(id);
+ if (vdec == NULL) {
+ yuv_start[id] = start;
+ yuv_num[id] = num;
+ yuv_enable |= (1 << id);
+ pr_info("no connected vdec.%d now, set dump ok\n", id);
+ return size;
+ }
+
+ ret = dump_yuv_trig(&vdec->vfc, id, start, num);
+ if (ret < 0)
+ pr_info("trigger dump yuv failed\n");
+ else
+ pr_info("trigger dump yuv init ok, total %d frames\n", num);
+
+ return size;
+}
+
+ssize_t dump_yuv_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ int i;
+ char *pbuf = buf;
+
+ for (i = 0; i < MAX_INSTANCE_MUN; i++) {
+ pbuf += pr_info("vdec.%d, start: %d, total: %d frames\n",
+ i, yuv_start[i], yuv_num[i]);
+ }
+ pbuf += sprintf(pbuf,
+ "\nUsage: echo [id] [start] [num] > dump_yuv\n\n");
+ return pbuf - buf;
+}
+
+
+ssize_t frame_check_store(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret = -1;
+ int on_off, id;
+
+ ret = sscanf(buf, "%d %d", &id, &on_off);
+ if (ret < 0) {
+ pr_info("%s, parse failed\n", buf);
+ return size;
+ }
+ if (id >= MAX_INSTANCE_MUN) {
+ pr_info("%d out of max vdec id\n", id);
+ return size;
+ }
+ if (on_off)
+ check_enable |= (1 << id);
+ else
+ check_enable &= ~(1 << id);
+
+ return size;
+}
+
+ssize_t frame_check_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ int i;
+ char *pbuf = buf;
+
+ for (i = 0; i < MAX_INSTANCE_MUN; i++) {
+ pbuf += sprintf(pbuf,
+ "vdec.%d\tcrc: %s\n", i,
+ (check_enable & (0x01 << i))?"enabled":"--");
+ }
+ pbuf += sprintf(pbuf,
+ "\nUsage:\techo [id] [1:on/0:off] > frame_check\n\n");
+
+ if (fc_debug & FC_ERR_CRC_BLOCK_MODE) {
+ /* cat frame_check to next frame when block */
+ struct vdec_s *vdec = NULL;
+ vdec = vdec_get_vdec_by_id(__ffs(check_enable));
+ if (vdec)
+ vdec->vfc.err_crc_block = 0;
+ }
+
+ return pbuf - buf;
+}
+
+
+module_param_string(comp_crc, comp_crc, 128, 0664);
+MODULE_PARM_DESC(comp_crc, "\n crc_filename\n");
+
+module_param_string(aux_comp_crc, aux_comp_crc, 128, 0664);
+MODULE_PARM_DESC(aux_comp_crc, "\n aux crc_filename\n");
+
+
+module_param(fc_debug, uint, 0664);
+MODULE_PARM_DESC(fc_debug, "\n frame check debug\n");
+
+module_param(aux_enable, uint, 0664);
+MODULE_PARM_DESC(aux_enable, "\n aux data check debug\n");
+
+module_param(size_yuv_buf, uint, 0664);
+MODULE_PARM_DESC(size_yuv_buf, "\n size_yuv_buf\n");
+
+module_param_string(checksum_info, checksum_info, 128, 0664);
+MODULE_PARM_DESC(checksum_info, "\n checksum_info\n");
+
+module_param_string(checksum_filename, checksum_filename, 128, 0664);
+MODULE_PARM_DESC(checksum_filename, "\n checksum_filename\n");
+
+module_param(checksum_start_count, uint, 0664);
+MODULE_PARM_DESC(checksum_start_count, "\n checksum_start_count\n");
+
+module_param(checksum_enable, uint, 0664);
+MODULE_PARM_DESC(checksum_enable, "\n checksum_enable\n");
diff --git a/drivers/frame_provider/decoder/utils/frame_check.h b/drivers/frame_provider/decoder/utils/frame_check.h
new file mode 100644
index 0000000..e983377
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/frame_check.h
@@ -0,0 +1,162 @@
+/*
+ * drivers/amlogic/media/frame_provider/decoder/utils/frame_check.h
+ *
+ * Copyright (C) 2016 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+*/
+
+#ifndef __FRAME_CHECK_H__
+#define __FRAME_CHECK_H__
+
+
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/amlogic/media/vfm/vframe.h>
+#include <linux/kfifo.h>
+
+#define FRAME_CHECK
+#define AUX_DATA_CRC
+
+
+#define YUV_MAX_DUMP_NUM 60
+
+#define SIZE_CRC 64
+#define SIZE_CHECK_Q 128
+
+#define USER_CMP_POOL_MAX_SIZE (SIZE_CHECK_Q)
+
+struct pic_dump_t{
+ struct file *yuv_fp;
+ loff_t yuv_pos;
+ unsigned int start;
+ unsigned int num;
+ unsigned int end;
+ unsigned int dump_cnt;
+
+ unsigned int buf_size;
+ char *buf_addr;
+};
+
+struct pic_check_t{
+ struct file *check_fp;
+ loff_t check_pos;
+
+ struct file *compare_fp;
+ loff_t compare_pos;
+ unsigned int cmp_crc_cnt;
+ void *fbc_planes[4];
+ void *check_addr;
+ DECLARE_KFIFO(new_chk_q, char *, SIZE_CHECK_Q);
+ DECLARE_KFIFO(wr_chk_q, char *, SIZE_CHECK_Q);
+};
+
+struct aux_data_check_t{
+ struct file *check_fp;
+ loff_t check_pos;
+
+ struct file *compare_fp;
+ loff_t compare_pos;
+ unsigned int cmp_crc_cnt;
+ void *check_addr;
+
+ DECLARE_KFIFO(new_chk_q, char *, SIZE_CHECK_Q);
+ DECLARE_KFIFO(wr_chk_q, char *, SIZE_CHECK_Q);
+};
+
+
+struct pic_check_mgr_t{
+ int id;
+ int enable;
+ unsigned int frame_cnt;
+ /* pic info */
+ unsigned int canvas_w;
+ unsigned int canvas_h;
+ unsigned int size_y; //real size
+ unsigned int size_uv;
+ unsigned int size_pic;
+ unsigned int last_size_pic;
+ void *y_vaddr;
+ void *uv_vaddr;
+ ulong y_phyaddr;
+ ulong uv_phyaddr;
+ int err_crc_block;
+
+ int file_cnt;
+ atomic_t work_inited;
+ struct work_struct frame_check_work;
+
+ struct pic_check_t pic_check;
+ struct pic_dump_t pic_dump;
+
+ struct usr_crc_info_t *cmp_pool;
+ int usr_cmp_num;
+ int usr_cmp_result;
+ /* for mjpeg u different addr with v */
+ bool mjpeg_flag;
+ void *extra_v_vaddr;
+ ulong extra_v_phyaddr;
+ int yuvsum;
+ u32 width;
+ u32 height;
+};
+
+struct aux_data_check_mgr_t{
+ int id;
+ int enable;
+ unsigned int frame_cnt;
+ /* pic info */
+ int aux_size;
+ char *aux_addr;
+
+ int file_cnt;
+ atomic_t work_inited;
+ struct work_struct aux_data_check_work;
+
+ struct aux_data_check_t aux_data_check;
+};
+
+
+int dump_yuv_trig(struct pic_check_mgr_t *mgr,
+ int id, int start, int num);
+
+int decoder_do_frame_check(struct vdec_s *vdec, struct vframe_s *vf);
+
+int decoder_do_aux_data_check(struct vdec_s *vdec, char *aux_buffer, int size);
+
+int frame_check_init(struct pic_check_mgr_t *mgr, int id);
+
+void frame_check_exit(struct pic_check_mgr_t *mgr);
+
+ssize_t frame_check_show(struct class *class,
+ struct class_attribute *attr, char *buf);
+
+ssize_t frame_check_store(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size);
+
+ssize_t dump_yuv_show(struct class *class,
+ struct class_attribute *attr, char *buf);
+
+ssize_t dump_yuv_store(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size);
+
+void vdec_frame_check_exit(struct vdec_s *vdec);
+int vdec_frame_check_init(struct vdec_s *vdec);
+
+void vdec_aux_data_check_exit(struct vdec_s *vdec);
+int vdec_aux_data_check_init(struct vdec_s *vdec);
+
+
+#endif /* __FRAME_CHECK_H__ */
+
diff --git a/drivers/frame_provider/decoder/utils/secprot.c b/drivers/frame_provider/decoder/utils/secprot.c
new file mode 100644
index 0000000..a1e7fa7
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/secprot.c
@@ -0,0 +1,75 @@
+/*
+ * drivers/amlogic/amports/arch/secprot.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+*/
+
+#include <linux/kernel.h>
+#include <asm/compiler.h>
+#include "secprot.h"
+#ifndef CONFIG_ARM64
+#include <asm/opcodes-sec.h>
+#endif
+
+#ifdef CONFIG_ARM64
+
+int tee_config_device_secure(int dev_id, int secure)
+{
+ int ret = 0;
+ register unsigned x0 asm("x0");
+ register unsigned x1 asm("x1");
+ register unsigned x2 asm("x2");
+
+ x0 = OPTEE_SMC_CONFIG_DEVICE_SECURE;
+ x1 = dev_id;
+ x2 = secure;
+
+ asm volatile(
+ __asmeq("%0", "x0")
+ __asmeq("%1", "x0")
+ __asmeq("%2", "x1")
+ __asmeq("%3", "x2")
+ "smc #0\n"
+ : "=r"(x0)
+ : "r"(x0), "r"(x1), "r"(x2));
+ ret = x0;
+
+ return ret;
+}
+#else
+int tee_config_device_secure(int dev_id, int secure)
+{
+ int ret = 0;
+ register unsigned int r0 asm("r0");
+ register unsigned int r1 asm("r1");
+ register unsigned int r2 asm("r2");
+
+ r0 = OPTEE_SMC_CONFIG_DEVICE_SECURE;
+ r1 = dev_id;
+ r2 = secure;
+
+ asm volatile(
+ __asmeq("%0", "r0")
+ __asmeq("%1", "r0")
+ __asmeq("%2", "r1")
+ __asmeq("%3", "r2")
+ __SMC(0)
+ : "=r"(r0)
+ : "r"(r0), "r"(r1), "r"(r2));
+ ret = r0;
+
+ return ret;
+}
+#endif
+
diff --git a/drivers/frame_provider/decoder/utils/secprot.h b/drivers/frame_provider/decoder/utils/secprot.h
new file mode 100644
index 0000000..28ee477
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/secprot.h
@@ -0,0 +1,39 @@
+/*
+ * drivers/amlogic/amports/arch/secprot.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+*/
+
+#ifndef __SECPROT_H_
+#define __SECPROT_H_
+
+#define DMC_DEV_TYPE_NON_SECURE 0
+#define DMC_DEV_TYPE_SECURE 1
+
+#define DMC_DEV_ID_GPU 1
+#define DMC_DEV_ID_HEVC 4
+#define DMC_DEV_ID_PARSER 7
+#define DMC_DEV_ID_VPU 8
+#define DMC_DEV_ID_VDEC 13
+#define DMC_DEV_ID_HCODEC 14
+#define DMC_DEV_ID_GE2D 15
+
+#define OPTEE_SMC_CONFIG_DEVICE_SECURE 0xb200000e
+
+/*#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t"*/
+
+extern int tee_config_device_secure(int dev_id, int secure);
+
+#endif /* __SECPROT_H_ */
+
diff --git a/drivers/frame_provider/decoder/utils/utils.c b/drivers/frame_provider/decoder/utils/utils.c
new file mode 100644
index 0000000..44b1626
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/utils.c
@@ -0,0 +1,73 @@
+/*
+ * drivers/amlogic/media/frame_provider/decoder/utils/utils.c
+ *
+ * Copyright (C) 2016 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/semaphore.h>
+#include <linux/sched/rt.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "vdec.h"
+#include "vdec_input.h"
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "amvdec.h"
+#include "decoder_mmu_box.h"
+#include "decoder_bmmu_box.h"
+#include "vdec_profile.h"
+
+static int __init decoder_common_init(void)
+{
+ /*vdec init.*/
+ vdec_module_init();
+
+ /*amvdec init.*/
+ amvdec_init();
+
+ /*mmu box init.*/
+ decoder_mmu_box_init();/*exit?*/
+ decoder_bmmu_box_init();
+
+ vdec_profile_init_debugfs();
+
+ return 0;
+}
+
+static void __exit decoder_common_exit(void)
+{
+ /*vdec exit.*/
+ vdec_module_exit();
+
+ /*amvdec exit.*/
+ amvdec_exit();
+
+ decoder_mmu_box_exit();
+ decoder_bmmu_box_exit();
+
+ vdec_profile_exit_debugfs();
+}
+
+module_init(decoder_common_init);
+module_exit(decoder_common_exit);
+MODULE_DESCRIPTION("AMLOGIC decoder_common driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/frame_provider/decoder/utils/vdec.c b/drivers/frame_provider/decoder/utils/vdec.c
new file mode 100644
index 0000000..69ec60c
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/vdec.c
@@ -0,0 +1,6067 @@
+/*
+ * drivers/amlogic/media/frame_provider/decoder/utils/vdec.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/spinlock.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/semaphore.h>
+#include <linux/sched/rt.h>
+#include <linux/interrupt.h>
+#include <linux/amlogic/media/utils/vformat.h>
+#include <linux/amlogic/iomap.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/video_sink/ionvideo_ext.h>
+#ifdef CONFIG_AMLOGIC_V4L_VIDEO3
+#include <linux/amlogic/media/video_sink/v4lvideo_ext.h>
+#endif
+#include <linux/amlogic/media/vfm/vfm_ext.h>
+/*for VDEC_DEBUG_SUPPORT*/
+#include <linux/time.h>
+
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "../../../stream_input/amports/streambuf.h"
+#include "vdec.h"
+#include "vdec_trace.h"
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+#include "vdec_profile.h"
+#endif
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/libfdt_env.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/dma-contiguous.h>
+#include <linux/cma.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/utils/amports_config.h>
+#include "../utils/amvdec.h"
+#include "vdec_input.h"
+
+#include "../../../common/media_clock/clk/clk.h"
+#include <linux/reset.h>
+#include <linux/amlogic/cpu_version.h>
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include <linux/amlogic/media/video_sink/video_keeper.h>
+#include <linux/amlogic/media/codec_mm/configs.h>
+#include <linux/amlogic/media/frame_sync/ptsserv.h>
+#include "secprot.h"
+#include "../../../common/chips/decoder_cpu_ver_info.h"
+#include "frame_check.h"
+
+#ifdef CONFIG_AMLOGIC_POWER
+#include <linux/amlogic/power_ctrl.h>
+#endif
+
+#include <dt-bindings/power/sc2-pd.h>
+#include <linux/amlogic/pwr_ctrl.h>
+#include <linux/of_device.h>
+#include "vdec_power_ctrl.h"
+
+static DEFINE_MUTEX(vdec_mutex);
+
+#define MC_SIZE (4096 * 4)
+#define CMA_ALLOC_SIZE SZ_64M
+#define MEM_NAME "vdec_prealloc"
+static int inited_vcodec_num;
+#define jiffies_ms div64_u64(get_jiffies_64() * 1000, HZ)
+static int poweron_clock_level;
+static int debug_vdetect = 0;
+static int keep_vdec_mem;
+static unsigned int debug_trace_num = 16 * 20;
+static int step_mode;
+static unsigned int clk_config;
+#ifdef VDEC_FCC_SUPPORT
+static int fcc_debug;
+static void vdec_fcc_jump_back(struct vdec_s *vdec);
+#endif
+/*
+ * 0x1 : sched_priority to MAX_RT_PRIO -1.
+ * 0x2 : always reload firmware.
+ * 0x4 : vdec canvas debug enable
+ * 0x100: enable vdec fence.
+ */
+#define VDEC_DBG_SCHED_PRIO (0x1)
+#define VDEC_DBG_ALWAYS_LOAD_FW (0x2)
+#define VDEC_DBG_CANVAS_STATUS (0x4)
+#define VDEC_DBG_ENABLE_FENCE (0x100)
+
+#define FRAME_BASE_PATH_DI_V4LVIDEO_0 (29)
+#define FRAME_BASE_PATH_DI_V4LVIDEO_1 (30)
+#define FRAME_BASE_PATH_DI_V4LVIDEO_2 (31)
+
+u32 debug = VDEC_DBG_ALWAYS_LOAD_FW;
+EXPORT_SYMBOL(debug);
+
+int hevc_max_reset_count;
+EXPORT_SYMBOL(hevc_max_reset_count);
+
+int no_powerdown;
+EXPORT_SYMBOL(no_powerdown);
+
+static int parallel_decode = 1;
+static int fps_detection;
+static int fps_clear;
+
+
+static int force_nosecure_even_drm;
+static int disable_switch_single_to_mult;
+
+static DEFINE_SPINLOCK(vdec_spin_lock);
+
+#define HEVC_TEST_LIMIT 100
+#define GXBB_REV_A_MINOR 0xA
+
+#define PRINT_FRAME_INFO 1
+#define DISABLE_FRAME_INFO 2
+
+#define RESET7_REGISTER_LEVEL 0x1127
+#define P_RESETCTRL_RESET5_LEVEL 0x15
+
+static int frameinfo_flag = 0;
+static int v4lvideo_add_di = 1;
+static int max_di_instance = 2;
+static int max_supported_di_instance = 4;
+
+//static int path_debug = 0;
+
+static int enable_mvdec_info = 1;
+
+int decode_underflow = 0;
+
+static int enable_stream_mode_multi_dec;
+
+#define CANVAS_MAX_SIZE (AMVDEC_CANVAS_MAX1 - AMVDEC_CANVAS_START_INDEX + 1 + AMVDEC_CANVAS_MAX2 + 1)
+
+extern void vframe_rate_uevent(int duration);
+
+struct am_reg {
+ char *name;
+ int offset;
+};
+
+struct vdec_isr_context_s {
+ int index;
+ int irq;
+ irq_handler_t dev_isr;
+ irq_handler_t dev_threaded_isr;
+ void *dev_id;
+ struct vdec_s *vdec;
+};
+
+struct decode_fps_s {
+ u32 frame_count;
+ u64 start_timestamp;
+ u64 last_timestamp;
+ u32 fps;
+};
+
+struct vdec_core_s {
+ struct list_head connected_vdec_list;
+ spinlock_t lock;
+ spinlock_t canvas_lock;
+ spinlock_t fps_lock;
+ spinlock_t input_lock;
+ struct ida ida;
+ atomic_t vdec_nr;
+ struct vdec_s *vfm_vdec;
+ struct vdec_s *active_vdec;
+ struct vdec_s *active_hevc;
+ struct vdec_s *hint_fr_vdec;
+ struct platform_device *vdec_core_platform_device;
+ struct device *cma_dev;
+ struct semaphore sem;
+ struct task_struct *thread;
+ struct workqueue_struct *vdec_core_wq;
+
+ unsigned long sched_mask;
+ struct vdec_isr_context_s isr_context[VDEC_IRQ_MAX];
+ int power_ref_count[VDEC_MAX];
+ struct vdec_s *last_vdec;
+ int parallel_dec;
+ unsigned long power_ref_mask;
+ int vdec_combine_flag;
+ struct decode_fps_s decode_fps[MAX_INSTANCE_MUN];
+ unsigned long buff_flag;
+ unsigned long stream_buff_flag;
+ struct power_manager_s *pm;
+ u32 vdec_resouce_status;
+};
+
+struct canvas_status_s {
+ int type;
+ int canvas_used_flag;
+ int id;
+};
+
+
+static struct vdec_core_s *vdec_core;
+
+static const char * const vdec_status_string[] = {
+ "VDEC_STATUS_UNINITIALIZED",
+ "VDEC_STATUS_DISCONNECTED",
+ "VDEC_STATUS_CONNECTED",
+ "VDEC_STATUS_ACTIVE"
+};
+/*
+bit [28] enable print
+bit [23:16] etc
+bit [15:12]
+ none 0 and not 0x1: force single
+ none 0 and 0x1: force multi
+bit [8]
+ 1: force dual
+bit [3]
+ 1: use mavs for single mode
+bit [2]
+ 1: force vfm path for frame mode
+bit [1]
+ 1: force esparser auto mode
+bit [0]
+ 1: disable audo manual mode ??
+*/
+
+static int debugflags;
+
+static char vfm_path[VDEC_MAP_NAME_SIZE] = {"disable"};
+static const char vfm_path_node[][VDEC_MAP_NAME_SIZE] =
+{
+ "video_render.0",
+ "video_render.1",
+ "amvideo",
+ "videopip",
+ "deinterlace",
+ "dimulti.1",
+ "amlvideo",
+ "aml_video.1",
+ "amlvideo2.0",
+ "amlvideo2.1",
+ "ppmgr",
+ "ionvideo",
+ "ionvideo.1",
+ "ionvideo.2",
+ "ionvideo.3",
+ "ionvideo.4",
+ "ionvideo.5",
+ "ionvideo.6",
+ "ionvideo.7",
+ "ionvideo.8",
+ "videosync.0",
+ "v4lvideo.0",
+ "v4lvideo.1",
+ "v4lvideo.2",
+ "v4lvideo.3",
+ "v4lvideo.4",
+ "v4lvideo.5",
+ "v4lvideo.6",
+ "v4lvideo.7",
+ "v4lvideo.8",
+ "fake-amvideo",
+ "disable",
+ "reserved",
+};
+
+static struct canvas_status_s canvas_stat[AMVDEC_CANVAS_MAX1 - AMVDEC_CANVAS_START_INDEX + 1 + AMVDEC_CANVAS_MAX2 + 1];
+
+
+int vdec_get_debug_flags(void)
+{
+ return debugflags;
+}
+EXPORT_SYMBOL(vdec_get_debug_flags);
+
+void VDEC_PRINT_FUN_LINENO(const char *fun, int line)
+{
+ if (debugflags & 0x10000000)
+ pr_info("%s, %d\n", fun, line);
+}
+EXPORT_SYMBOL(VDEC_PRINT_FUN_LINENO);
+
+bool is_support_no_parser(void)
+{
+ if ((enable_stream_mode_multi_dec) ||
+ (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2))
+ return true;
+ return false;
+}
+EXPORT_SYMBOL(is_support_no_parser);
+
+unsigned char is_mult_inc(unsigned int type)
+{
+ unsigned char ret = 0;
+ if (vdec_get_debug_flags() & 0xf000)
+ ret = (vdec_get_debug_flags() & 0x1000)
+ ? 1 : 0;
+ else if (type & PORT_TYPE_DECODER_SCHED)
+ ret = 1;
+ return ret;
+}
+EXPORT_SYMBOL(is_mult_inc);
+
+static const bool cores_with_input[VDEC_MAX] = {
+ true, /* VDEC_1 */
+ false, /* VDEC_HCODEC */
+ false, /* VDEC_2 */
+ true, /* VDEC_HEVC / VDEC_HEVC_FRONT */
+ false, /* VDEC_HEVC_BACK */
+};
+
+static const int cores_int[VDEC_MAX] = {
+ VDEC_IRQ_1,
+ VDEC_IRQ_2,
+ VDEC_IRQ_0,
+ VDEC_IRQ_0,
+ VDEC_IRQ_HEVC_BACK
+};
+
+unsigned long vdec_canvas_lock(struct vdec_core_s *core)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&core->canvas_lock, flags);
+
+ return flags;
+}
+
+void vdec_canvas_unlock(struct vdec_core_s *core, unsigned long flags)
+{
+ spin_unlock_irqrestore(&core->canvas_lock, flags);
+}
+
+unsigned long vdec_fps_lock(struct vdec_core_s *core)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&core->fps_lock, flags);
+
+ return flags;
+}
+
+void vdec_fps_unlock(struct vdec_core_s *core, unsigned long flags)
+{
+ spin_unlock_irqrestore(&core->fps_lock, flags);
+}
+
+unsigned long vdec_core_lock(struct vdec_core_s *core)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&core->lock, flags);
+
+ return flags;
+}
+
+void vdec_core_unlock(struct vdec_core_s *core, unsigned long flags)
+{
+ spin_unlock_irqrestore(&core->lock, flags);
+}
+
+unsigned long vdec_inputbuff_lock(struct vdec_core_s *core)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&core->input_lock, flags);
+
+ return flags;
+}
+
+void vdec_inputbuff_unlock(struct vdec_core_s *core, unsigned long flags)
+{
+ spin_unlock_irqrestore(&core->input_lock, flags);
+}
+
+
+static bool vdec_is_input_frame_empty(struct vdec_s *vdec) {
+ struct vdec_core_s *core = vdec_core;
+ bool ret;
+ unsigned long flags;
+
+ flags = vdec_inputbuff_lock(core);
+ ret = !(vdec->core_mask & core->buff_flag);
+ vdec_inputbuff_unlock(core, flags);
+
+ return ret;
+}
+
+static void vdec_up(struct vdec_s *vdec)
+{
+ struct vdec_core_s *core = vdec_core;
+
+ if (debug & 8)
+ pr_info("vdec_up, id:%d\n", vdec->id);
+ up(&core->sem);
+}
+
+
+static u64 vdec_get_us_time_system(void)
+{
+ struct timeval tv;
+
+ do_gettimeofday(&tv);
+
+ return div64_u64(timeval_to_ns(&tv), 1000);
+}
+
+static void vdec_fps_clear(int id)
+{
+ if (id >= MAX_INSTANCE_MUN)
+ return;
+
+ vdec_core->decode_fps[id].frame_count = 0;
+ vdec_core->decode_fps[id].start_timestamp = 0;
+ vdec_core->decode_fps[id].last_timestamp = 0;
+ vdec_core->decode_fps[id].fps = 0;
+}
+
+static void vdec_fps_clearall(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_INSTANCE_MUN; i++) {
+ vdec_core->decode_fps[i].frame_count = 0;
+ vdec_core->decode_fps[i].start_timestamp = 0;
+ vdec_core->decode_fps[i].last_timestamp = 0;
+ vdec_core->decode_fps[i].fps = 0;
+ }
+}
+
+static void vdec_fps_detec(int id)
+{
+ unsigned long flags;
+
+ if (fps_detection == 0)
+ return;
+
+ if (id >= MAX_INSTANCE_MUN)
+ return;
+
+ flags = vdec_fps_lock(vdec_core);
+
+ if (fps_clear == 1) {
+ vdec_fps_clearall();
+ fps_clear = 0;
+ }
+
+ vdec_core->decode_fps[id].frame_count++;
+ if (vdec_core->decode_fps[id].frame_count == 1) {
+ vdec_core->decode_fps[id].start_timestamp =
+ vdec_get_us_time_system();
+ vdec_core->decode_fps[id].last_timestamp =
+ vdec_core->decode_fps[id].start_timestamp;
+ } else {
+ vdec_core->decode_fps[id].last_timestamp =
+ vdec_get_us_time_system();
+ vdec_core->decode_fps[id].fps =
+ (u32)div_u64(((u64)(vdec_core->decode_fps[id].frame_count) *
+ 10000000000),
+ (vdec_core->decode_fps[id].last_timestamp -
+ vdec_core->decode_fps[id].start_timestamp));
+ }
+ vdec_fps_unlock(vdec_core, flags);
+}
+
+
+
+static int get_canvas(unsigned int index, unsigned int base)
+{
+ int start;
+ int canvas_index = index * base;
+ int ret;
+
+ if ((base > 4) || (base == 0))
+ return -1;
+
+ if ((AMVDEC_CANVAS_START_INDEX + canvas_index + base - 1)
+ <= AMVDEC_CANVAS_MAX1) {
+ start = AMVDEC_CANVAS_START_INDEX + base * index;
+ } else {
+ canvas_index -= (AMVDEC_CANVAS_MAX1 -
+ AMVDEC_CANVAS_START_INDEX + 1) / base * base;
+ if (canvas_index <= AMVDEC_CANVAS_MAX2)
+ start = canvas_index / base;
+ else
+ return -1;
+ }
+
+ if (base == 1) {
+ ret = start;
+ } else if (base == 2) {
+ ret = ((start + 1) << 16) | ((start + 1) << 8) | start;
+ } else if (base == 3) {
+ ret = ((start + 2) << 16) | ((start + 1) << 8) | start;
+ } else if (base == 4) {
+ ret = (((start + 3) << 24) | (start + 2) << 16) |
+ ((start + 1) << 8) | start;
+ }
+
+ return ret;
+}
+
+static int get_canvas_ex(int type, int id)
+{
+ int i;
+ unsigned long flags;
+
+ flags = vdec_canvas_lock(vdec_core);
+
+ for (i = 0; i < CANVAS_MAX_SIZE; i++) {
+ if ((canvas_stat[i].type == type) &&
+ (canvas_stat[i].id & (1 << id)) == 0) {
+ canvas_stat[i].canvas_used_flag++;
+ canvas_stat[i].id |= (1 << id);
+ if (debug & 4)
+ pr_debug("get used canvas %d\n", i);
+ vdec_canvas_unlock(vdec_core, flags);
+ if (i < AMVDEC_CANVAS_MAX2 + 1)
+ return i;
+ else
+ return (i + AMVDEC_CANVAS_START_INDEX - AMVDEC_CANVAS_MAX2 - 1);
+ }
+ }
+
+ for (i = 0; i < CANVAS_MAX_SIZE; i++) {
+ if (canvas_stat[i].type == 0) {
+ canvas_stat[i].type = type;
+ canvas_stat[i].canvas_used_flag = 1;
+ canvas_stat[i].id = (1 << id);
+ if (debug & 4) {
+ pr_debug("get canvas %d\n", i);
+ pr_debug("canvas_used_flag %d\n",
+ canvas_stat[i].canvas_used_flag);
+ pr_debug("canvas_stat[i].id %d\n",
+ canvas_stat[i].id);
+ }
+ vdec_canvas_unlock(vdec_core, flags);
+ if (i < AMVDEC_CANVAS_MAX2 + 1)
+ return i;
+ else
+ return (i + AMVDEC_CANVAS_START_INDEX - AMVDEC_CANVAS_MAX2 - 1);
+ }
+ }
+ vdec_canvas_unlock(vdec_core, flags);
+
+ pr_info("cannot get canvas\n");
+
+ return -1;
+}
+
+static void free_canvas_ex(int index, int id)
+{
+ unsigned long flags;
+ int offset;
+
+ flags = vdec_canvas_lock(vdec_core);
+ if (index >= 0 &&
+ index < AMVDEC_CANVAS_MAX2 + 1)
+ offset = index;
+ else if ((index >= AMVDEC_CANVAS_START_INDEX) &&
+ (index <= AMVDEC_CANVAS_MAX1))
+ offset = index + AMVDEC_CANVAS_MAX2 + 1 - AMVDEC_CANVAS_START_INDEX;
+ else {
+ vdec_canvas_unlock(vdec_core, flags);
+ return;
+ }
+
+ if ((canvas_stat[offset].canvas_used_flag > 0) &&
+ (canvas_stat[offset].id & (1 << id))) {
+ canvas_stat[offset].canvas_used_flag--;
+ canvas_stat[offset].id &= ~(1 << id);
+ if (canvas_stat[offset].canvas_used_flag == 0) {
+ canvas_stat[offset].type = 0;
+ canvas_stat[offset].id = 0;
+ }
+ if (debug & 4) {
+ pr_debug("free index %d used_flag %d, type = %d, id = %d\n",
+ offset,
+ canvas_stat[offset].canvas_used_flag,
+ canvas_stat[offset].type,
+ canvas_stat[offset].id);
+ }
+ }
+ vdec_canvas_unlock(vdec_core, flags);
+
+ return;
+
+}
+
+static void vdec_dmc_pipeline_reset(void)
+{
+ /*
+ * bit15: vdec_piple
+ * bit14: hevc_dmc_piple
+ * bit13: hevcf_dmc_pipl
+ * bit12: wave420_dmc_pipl
+ * bit11: hcodec_dmc_pipl
+ */
+
+ WRITE_RESET_REG(RESET7_REGISTER,
+ (1 << 15) | (1 << 14) | (1 << 13) |
+ (1 << 12) | (1 << 11));
+}
+
+static void vdec_stop_armrisc(int hw)
+{
+ ulong timeout = jiffies + HZ;
+
+ if (hw == VDEC_INPUT_TARGET_VLD) {
+ WRITE_VREG(MPSR, 0);
+ WRITE_VREG(CPSR, 0);
+
+ while (READ_VREG(IMEM_DMA_CTRL) & 0x8000) {
+ if (time_after(jiffies, timeout))
+ break;
+ }
+
+ timeout = jiffies + HZ;
+ while (READ_VREG(LMEM_DMA_CTRL) & 0x8000) {
+ if (time_after(jiffies, timeout))
+ break;
+ }
+ } else if (hw == VDEC_INPUT_TARGET_HEVC) {
+ WRITE_VREG(HEVC_MPSR, 0);
+ WRITE_VREG(HEVC_CPSR, 0);
+
+ while (READ_VREG(HEVC_IMEM_DMA_CTRL) & 0x8000) {
+ if (time_after(jiffies, timeout))
+ break;
+ }
+
+ timeout = jiffies + HZ/10;
+ while (READ_VREG(HEVC_LMEM_DMA_CTRL) & 0x8000) {
+ if (time_after(jiffies, timeout))
+ break;
+ }
+ }
+}
+
+static void vdec_disable_DMC(struct vdec_s *vdec)
+{
+ /*close first,then wait pedding end,timing suggestion from vlsi*/
+ struct vdec_input_s *input = &vdec->input;
+ unsigned long flags;
+ unsigned int mask = 0;
+
+ if (input->target == VDEC_INPUT_TARGET_VLD) {
+ mask = (1 << 13);
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
+ mask = (1 << 21);
+ } else if (input->target == VDEC_INPUT_TARGET_HEVC) {
+ mask = (1 << 4); /*hevc*/
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
+ mask |= (1 << 8); /*hevcb */
+ }
+
+ /* need to stop armrisc. */
+ if (!IS_ERR_OR_NULL(vdec->dev))
+ vdec_stop_armrisc(input->target);
+
+ spin_lock_irqsave(&vdec_spin_lock, flags);
+ codec_dmcbus_write(DMC_REQ_CTRL,
+ codec_dmcbus_read(DMC_REQ_CTRL) & ~mask);
+ spin_unlock_irqrestore(&vdec_spin_lock, flags);
+
+ if (is_cpu_tm2_revb() ||
+ (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2)) {
+ while (!(codec_dmcbus_read(TM2_REVB_DMC_CHAN_STS)
+ & mask))
+ ;
+ } else {
+ while (!(codec_dmcbus_read(DMC_CHAN_STS)
+ & mask))
+ ;
+ }
+
+ pr_debug("%s input->target= 0x%x\n", __func__, input->target);
+}
+
+static void vdec_enable_DMC(struct vdec_s *vdec)
+{
+ struct vdec_input_s *input = &vdec->input;
+ unsigned long flags;
+ unsigned int mask = 0;
+
+ if (input->target == VDEC_INPUT_TARGET_VLD) {
+ mask = (1 << 13);
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
+ mask = (1 << 21);
+ } else if (input->target == VDEC_INPUT_TARGET_HEVC) {
+ mask = (1 << 4); /*hevc*/
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
+ mask |= (1 << 8); /*hevcb */
+ }
+
+ /*must to be reset the dmc pipeline if it's g12b.*/
+ if (get_cpu_type() == AM_MESON_CPU_MAJOR_ID_G12B)
+ vdec_dmc_pipeline_reset();
+
+ spin_lock_irqsave(&vdec_spin_lock, flags);
+ codec_dmcbus_write(DMC_REQ_CTRL,
+ codec_dmcbus_read(DMC_REQ_CTRL) | mask);
+ spin_unlock_irqrestore(&vdec_spin_lock, flags);
+ pr_debug("%s input->target= 0x%x\n", __func__, input->target);
+}
+
+
+
+static int vdec_get_hw_type(int value)
+{
+ int type;
+ switch (value) {
+ case VFORMAT_HEVC:
+ case VFORMAT_VP9:
+ case VFORMAT_AVS2:
+ case VFORMAT_AV1:
+ type = CORE_MASK_HEVC;
+ break;
+
+ case VFORMAT_MPEG12:
+ case VFORMAT_MPEG4:
+ case VFORMAT_H264:
+ case VFORMAT_MJPEG:
+ case VFORMAT_REAL:
+ case VFORMAT_JPEG:
+ case VFORMAT_VC1:
+ case VFORMAT_AVS:
+ case VFORMAT_YUV:
+ case VFORMAT_H264MVC:
+ case VFORMAT_H264_4K2K:
+ case VFORMAT_H264_ENC:
+ case VFORMAT_JPEG_ENC:
+ type = CORE_MASK_VDEC_1;
+ break;
+
+ default:
+ type = -1;
+ }
+
+ return type;
+}
+
+
+static void vdec_save_active_hw(struct vdec_s *vdec)
+{
+ int type;
+
+ type = vdec_get_hw_type(vdec->port->vformat);
+
+ if (type == CORE_MASK_HEVC) {
+ vdec_core->active_hevc = vdec;
+ } else if (type == CORE_MASK_VDEC_1) {
+ vdec_core->active_vdec = vdec;
+ } else {
+ pr_info("save_active_fw wrong\n");
+ }
+}
+
+static void vdec_update_buff_status(void)
+{
+ struct vdec_core_s *core = vdec_core;
+ unsigned long flags;
+ struct vdec_s *vdec;
+
+ flags = vdec_inputbuff_lock(core);
+ core->buff_flag = 0;
+ core->stream_buff_flag = 0;
+ list_for_each_entry(vdec, &core->connected_vdec_list, list) {
+ struct vdec_input_s *input = &vdec->input;
+ if (input_frame_based(input)) {
+ if (input->have_frame_num || input->eos)
+ core->buff_flag |= vdec->core_mask;
+ } else if (input_stream_based(input)) {
+ core->stream_buff_flag |= vdec->core_mask;
+ }
+ /* slave el pre_decode_level wp update */
+ if ((is_support_no_parser()) && (vdec->slave)) {
+ STBUF_WRITE(&vdec->slave->vbuf, set_wp,
+ STBUF_READ(&vdec->vbuf, get_wp));
+ }
+ }
+ vdec_inputbuff_unlock(core, flags);
+}
+
+#if 0
+void vdec_update_streambuff_status(void)
+{
+ struct vdec_core_s *core = vdec_core;
+ struct vdec_s *vdec;
+
+ /* check streaming prepare level threshold if not EOS */
+ list_for_each_entry(vdec, &core->connected_vdec_list, list) {
+ struct vdec_input_s *input = &vdec->input;
+ if (input && input_stream_based(input) && !input->eos &&
+ (vdec->need_more_data & VDEC_NEED_MORE_DATA)) {
+ u32 rp, wp, level;
+
+ rp = STBUF_READ(&vdec->vbuf, get_rp);
+ wp = STBUF_READ(&vdec->vbuf, get_wp);
+ if (wp < rp)
+ level = input->size + wp - rp;
+ else
+ level = wp - rp;
+ if ((level < input->prepare_level) &&
+ (pts_get_rec_num(PTS_TYPE_VIDEO,
+ vdec->input.total_rd_count) < 2)) {
+ break;
+ } else if (level > input->prepare_level) {
+ vdec->need_more_data &= ~VDEC_NEED_MORE_DATA;
+ if (debug & 8)
+ pr_info("vdec_flush_streambuff_status up\n");
+ vdec_up(vdec);
+ }
+ break;
+ }
+ }
+}
+EXPORT_SYMBOL(vdec_update_streambuff_status);
+#endif
+
+int vdec_status(struct vdec_s *vdec, struct vdec_info *vstatus)
+{
+ if (vdec && vdec->dec_status &&
+ ((vdec->status == VDEC_STATUS_CONNECTED ||
+ vdec->status == VDEC_STATUS_ACTIVE)))
+ return vdec->dec_status(vdec, vstatus);
+
+ return 0;
+}
+EXPORT_SYMBOL(vdec_status);
+
+int vdec_set_trickmode(struct vdec_s *vdec, unsigned long trickmode)
+{
+ int r;
+ if (vdec->set_trickmode) {
+ r = vdec->set_trickmode(vdec, trickmode);
+
+ if ((r == 0) && (vdec->slave) && (vdec->slave->set_trickmode))
+ r = vdec->slave->set_trickmode(vdec->slave,
+ trickmode);
+ return r;
+ }
+ return -1;
+}
+EXPORT_SYMBOL(vdec_set_trickmode);
+
+int vdec_set_isreset(struct vdec_s *vdec, int isreset)
+{
+ vdec->is_reset = isreset;
+ pr_info("is_reset=%d\n", isreset);
+ if (vdec->set_isreset)
+ return vdec->set_isreset(vdec, isreset);
+ return 0;
+}
+EXPORT_SYMBOL(vdec_set_isreset);
+
+int vdec_set_dv_metawithel(struct vdec_s *vdec, int isdvmetawithel)
+{
+ vdec->dolby_meta_with_el = isdvmetawithel;
+ pr_info("isdvmetawithel=%d\n", isdvmetawithel);
+ return 0;
+}
+EXPORT_SYMBOL(vdec_set_dv_metawithel);
+
+void vdec_set_no_powerdown(int flag)
+{
+ no_powerdown = flag;
+ pr_info("no_powerdown=%d\n", no_powerdown);
+ return;
+}
+EXPORT_SYMBOL(vdec_set_no_powerdown);
+
+void vdec_count_info(struct vdec_info *vs, unsigned int err,
+ unsigned int offset)
+{
+ if (err)
+ vs->error_frame_count++;
+ if (offset) {
+ if (0 == vs->frame_count) {
+ vs->offset = 0;
+ vs->samp_cnt = 0;
+ }
+ vs->frame_data = offset > vs->total_data ?
+ offset - vs->total_data : vs->total_data - offset;
+ vs->total_data = offset;
+ if (vs->samp_cnt < 96000 * 2) { /* 2s */
+ if (0 == vs->samp_cnt)
+ vs->offset = offset;
+ vs->samp_cnt += vs->frame_dur;
+ } else {
+ vs->bit_rate = (offset - vs->offset) / 2;
+ /*pr_info("bitrate : %u\n",vs->bit_rate);*/
+ vs->samp_cnt = 0;
+ }
+ vs->frame_count++;
+ }
+ /*pr_info("size : %u, offset : %u, dur : %u, cnt : %u\n",
+ vs->offset,offset,vs->frame_dur,vs->samp_cnt);*/
+ return;
+}
+EXPORT_SYMBOL(vdec_count_info);
+int vdec_is_support_4k(void)
+{
+ return !is_meson_gxl_package_805X();
+}
+EXPORT_SYMBOL(vdec_is_support_4k);
+
+/*
+ * clk_config:
+ *0:default
+ *1:no gp0_pll;
+ *2:always used gp0_pll;
+ *>=10:fixed n M clk;
+ *== 100 , 100M clks;
+ */
+unsigned int get_vdec_clk_config_settings(void)
+{
+ return clk_config;
+}
+void update_vdec_clk_config_settings(unsigned int config)
+{
+ clk_config = config;
+}
+EXPORT_SYMBOL(update_vdec_clk_config_settings);
+
+struct device *get_codec_cma_device(void)
+{
+ return vdec_core->cma_dev;
+}
+
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+static const char * const vdec_device_name[] = {
+ "amvdec_mpeg12", "ammvdec_mpeg12",
+ "amvdec_mpeg4", "ammvdec_mpeg4",
+ "amvdec_h264", "ammvdec_h264",
+ "amvdec_mjpeg", "ammvdec_mjpeg",
+ "amvdec_real", "ammvdec_real",
+ "amjpegdec", "ammjpegdec",
+ "amvdec_vc1", "ammvdec_vc1",
+ "amvdec_avs", "ammvdec_avs",
+ "amvdec_yuv", "ammvdec_yuv",
+ "amvdec_h264mvc", "ammvdec_h264mvc",
+ "amvdec_h264_4k2k", "ammvdec_h264_4k2k",
+ "amvdec_h265", "ammvdec_h265",
+ "amvenc_avc", "amvenc_avc",
+ "jpegenc", "jpegenc",
+ "amvdec_vp9", "ammvdec_vp9",
+ "amvdec_avs2", "ammvdec_avs2",
+ "amvdec_av1", "ammvdec_av1",
+};
+
+
+#else
+
+static const char * const vdec_device_name[] = {
+ "amvdec_mpeg12",
+ "amvdec_mpeg4",
+ "amvdec_h264",
+ "amvdec_mjpeg",
+ "amvdec_real",
+ "amjpegdec",
+ "amvdec_vc1",
+ "amvdec_avs",
+ "amvdec_yuv",
+ "amvdec_h264mvc",
+ "amvdec_h264_4k2k",
+ "amvdec_h265",
+ "amvenc_avc",
+ "jpegenc",
+ "amvdec_vp9",
+ "amvdec_avs2",
+ "amvdec_av1"
+};
+
+#endif
+
+/*
+ * Only support time sliced decoding for frame based input,
+ * so legacy decoder can exist with time sliced decoder.
+ */
+static const char *get_dev_name(bool use_legacy_vdec, int format)
+{
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ if (use_legacy_vdec && (debugflags & 0x8) == 0)
+ return vdec_device_name[format * 2];
+ else
+ return vdec_device_name[format * 2 + 1];
+#else
+ return vdec_device_name[format];
+#endif
+}
+
+#ifdef VDEC_DEBUG_SUPPORT
+static u64 get_current_clk(void)
+{
+ /*struct timespec xtime = current_kernel_time();
+ u64 usec = xtime.tv_sec * 1000000;
+ usec += xtime.tv_nsec / 1000;
+ */
+ u64 usec = sched_clock();
+ return usec;
+}
+
+static void inc_profi_count(unsigned long mask, u32 *count)
+{
+ enum vdec_type_e type;
+
+ for (type = VDEC_1; type < VDEC_MAX; type++) {
+ if (mask & (1 << type))
+ count[type]++;
+ }
+}
+
+static void update_profi_clk_run(struct vdec_s *vdec,
+ unsigned long mask, u64 clk)
+{
+ enum vdec_type_e type;
+
+ for (type = VDEC_1; type < VDEC_MAX; type++) {
+ if (mask & (1 << type)) {
+ vdec->start_run_clk[type] = clk;
+ if (vdec->profile_start_clk[type] == 0)
+ vdec->profile_start_clk[type] = clk;
+ vdec->total_clk[type] = clk
+ - vdec->profile_start_clk[type];
+ /*pr_info("set start_run_clk %ld\n",
+ vdec->start_run_clk);*/
+
+ }
+ }
+}
+
+static void update_profi_clk_stop(struct vdec_s *vdec,
+ unsigned long mask, u64 clk)
+{
+ enum vdec_type_e type;
+
+ for (type = VDEC_1; type < VDEC_MAX; type++) {
+ if (mask & (1 << type)) {
+ if (vdec->start_run_clk[type] == 0)
+ pr_info("error, start_run_clk[%d] not set\n", type);
+
+ /*pr_info("update run_clk type %d, %ld, %ld, %ld\n",
+ type,
+ clk,
+ vdec->start_run_clk[type],
+ vdec->run_clk[type]);*/
+ vdec->run_clk[type] +=
+ (clk - vdec->start_run_clk[type]);
+ }
+ }
+}
+
+#endif
+
+int vdec_set_decinfo(struct vdec_s *vdec, struct dec_sysinfo *p)
+{
+ if (copy_from_user((void *)&vdec->sys_info_store, (void *)p,
+ sizeof(struct dec_sysinfo)))
+ return -EFAULT;
+
+ /* force switch to mult instance if supports this profile. */
+ if ((vdec->type == VDEC_TYPE_SINGLE) &&
+ !disable_switch_single_to_mult) {
+ const char *str = NULL;
+ char fmt[16] = {0};
+
+ str = strchr(get_dev_name(false, vdec->format), '_');
+ if (!str)
+ return -1;
+
+ sprintf(fmt, "m%s", ++str);
+ if (is_support_profile(fmt) &&
+ vdec->sys_info->format != VIDEO_DEC_FORMAT_H263 &&
+ vdec->format != VFORMAT_AV1)
+ vdec->type = VDEC_TYPE_STREAM_PARSER;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(vdec_set_decinfo);
+
+/* construct vdec strcture */
+struct vdec_s *vdec_create(struct stream_port_s *port,
+ struct vdec_s *master)
+{
+ struct vdec_s *vdec;
+ int type = VDEC_TYPE_SINGLE;
+ int id;
+
+ if (is_mult_inc(port->type))
+ type = (port->type & PORT_TYPE_FRAME) ?
+ VDEC_TYPE_FRAME_BLOCK :
+ VDEC_TYPE_STREAM_PARSER;
+
+ id = ida_simple_get(&vdec_core->ida,
+ 0, MAX_INSTANCE_MUN, GFP_KERNEL);
+ if (id < 0) {
+ pr_info("vdec_create request id failed!ret =%d\n", id);
+ return NULL;
+ }
+ vdec = vzalloc(sizeof(struct vdec_s));
+
+ /* TBD */
+ if (vdec) {
+ vdec->magic = 0x43454456;
+ vdec->id = -1;
+ vdec->type = type;
+ vdec->port = port;
+ vdec->sys_info = &vdec->sys_info_store;
+
+ INIT_LIST_HEAD(&vdec->list);
+
+ atomic_inc(&vdec_core->vdec_nr);
+#ifdef CONFIG_AMLOGIC_V4L_VIDEO3
+ v4lvideo_dec_count_increase();
+#endif
+ vdec->id = id;
+ vdec_input_init(&vdec->input, vdec);
+ vdec->input.vdec_is_input_frame_empty = vdec_is_input_frame_empty;
+ vdec->input.vdec_up = vdec_up;
+ if (master) {
+ vdec->master = master;
+ master->slave = vdec;
+ master->sched = 1;
+ }
+ if (enable_mvdec_info) {
+ vdec->mvfrm = (struct vdec_frames_s *)
+ vzalloc(sizeof(struct vdec_frames_s));
+ if (!vdec->mvfrm)
+ pr_err("vzalloc: vdec_frames_s failed\n");
+ }
+ }
+
+ pr_debug("vdec_create instance %p, total %d, PM: %s\n", vdec,
+ atomic_read(&vdec_core->vdec_nr),
+ get_pm_name(vdec_core->pm->pm_type));
+
+ //trace_vdec_create(vdec); /*DEBUG_TMP*/
+
+ return vdec;
+}
+EXPORT_SYMBOL(vdec_create);
+
+int vdec_set_format(struct vdec_s *vdec, int format)
+{
+ vdec->format = format;
+ vdec->port_flag |= PORT_FLAG_VFORMAT;
+
+ if (vdec->slave) {
+ vdec->slave->format = format;
+ vdec->slave->port_flag |= PORT_FLAG_VFORMAT;
+ }
+ //trace_vdec_set_format(vdec, format);/*DEBUG_TMP*/
+
+ return 0;
+}
+EXPORT_SYMBOL(vdec_set_format);
+
+int vdec_set_pts(struct vdec_s *vdec, u32 pts)
+{
+ vdec->pts = pts;
+ vdec->pts64 = div64_u64((u64)pts * 100, 9);
+ vdec->pts_valid = true;
+ //trace_vdec_set_pts(vdec, (u64)pts);/*DEBUG_TMP*/
+ return 0;
+}
+EXPORT_SYMBOL(vdec_set_pts);
+
+void vdec_set_timestamp(struct vdec_s *vdec, u64 timestamp)
+{
+ vdec->timestamp = timestamp;
+ vdec->timestamp_valid = true;
+}
+EXPORT_SYMBOL(vdec_set_timestamp);
+
+int vdec_set_pts64(struct vdec_s *vdec, u64 pts64)
+{
+ vdec->pts64 = pts64;
+ vdec->pts = (u32)div64_u64(pts64 * 9, 100);
+ vdec->pts_valid = true;
+
+ //trace_vdec_set_pts64(vdec, pts64);/*DEBUG_TMP*/
+ return 0;
+}
+EXPORT_SYMBOL(vdec_set_pts64);
+
+int vdec_get_status(struct vdec_s *vdec)
+{
+ return vdec->status;
+}
+EXPORT_SYMBOL(vdec_get_status);
+
+int vdec_get_frame_num(struct vdec_s *vdec)
+{
+ return vdec->input.have_frame_num;
+}
+EXPORT_SYMBOL(vdec_get_frame_num);
+
+void vdec_set_status(struct vdec_s *vdec, int status)
+{
+ //trace_vdec_set_status(vdec, status);/*DEBUG_TMP*/
+ vdec->status = status;
+}
+EXPORT_SYMBOL(vdec_set_status);
+
+void vdec_set_next_status(struct vdec_s *vdec, int status)
+{
+ //trace_vdec_set_next_status(vdec, status);/*DEBUG_TMP*/
+ vdec->next_status = status;
+}
+EXPORT_SYMBOL(vdec_set_next_status);
+
+int vdec_set_video_path(struct vdec_s *vdec, int video_path)
+{
+ vdec->frame_base_video_path = video_path;
+ return 0;
+}
+EXPORT_SYMBOL(vdec_set_video_path);
+
+int vdec_set_receive_id(struct vdec_s *vdec, int receive_id)
+{
+ vdec->vf_receiver_inst = receive_id;
+ return 0;
+}
+EXPORT_SYMBOL(vdec_set_receive_id);
+
+/* add frame data to input chain */
+int vdec_write_vframe(struct vdec_s *vdec, const char *buf, size_t count)
+{
+ return vdec_input_add_frame(&vdec->input, buf, count);
+}
+EXPORT_SYMBOL(vdec_write_vframe);
+
+int vdec_write_vframe_with_dma(struct vdec_s *vdec,
+ ulong addr, size_t count, u32 handle, chunk_free free, void* priv)
+{
+ return vdec_input_add_frame_with_dma(&vdec->input,
+ addr, count, handle, free, priv);
+}
+EXPORT_SYMBOL(vdec_write_vframe_with_dma);
+
+/* add a work queue thread for vdec*/
+void vdec_schedule_work(struct work_struct *work)
+{
+ if (vdec_core->vdec_core_wq)
+ queue_work(vdec_core->vdec_core_wq, work);
+ else
+ schedule_work(work);
+}
+EXPORT_SYMBOL(vdec_schedule_work);
+
+static struct vdec_s *vdec_get_associate(struct vdec_s *vdec)
+{
+ if (vdec->master)
+ return vdec->master;
+ else if (vdec->slave)
+ return vdec->slave;
+ return NULL;
+}
+
+static void vdec_sync_input_read(struct vdec_s *vdec)
+{
+ if (!vdec_stream_based(vdec))
+ return;
+
+ if (vdec_dual(vdec)) {
+ u32 me, other;
+ if (vdec->input.target == VDEC_INPUT_TARGET_VLD) {
+ me = READ_VREG(VLD_MEM_VIFIFO_WRAP_COUNT);
+ other =
+ vdec_get_associate(vdec)->input.stream_cookie;
+ if (me > other)
+ return;
+ else if (me == other) {
+ me = READ_VREG(VLD_MEM_VIFIFO_RP);
+ other =
+ vdec_get_associate(vdec)->input.swap_rp;
+ if (me > other) {
+ STBUF_WRITE(&vdec->vbuf, set_rp,
+ vdec_get_associate(vdec)->input.swap_rp);
+ return;
+ }
+ }
+
+ STBUF_WRITE(&vdec->vbuf, set_rp,
+ READ_VREG(VLD_MEM_VIFIFO_RP));
+ } else if (vdec->input.target == VDEC_INPUT_TARGET_HEVC) {
+ me = READ_VREG(HEVC_SHIFT_BYTE_COUNT);
+ if (((me & 0x80000000) == 0) &&
+ (vdec->input.streaming_rp & 0x80000000))
+ me += 1ULL << 32;
+ other = vdec_get_associate(vdec)->input.streaming_rp;
+ if (me > other) {
+ STBUF_WRITE(&vdec->vbuf, set_rp,
+ vdec_get_associate(vdec)->input.swap_rp);
+ return;
+ }
+
+ STBUF_WRITE(&vdec->vbuf, set_rp,
+ READ_VREG(HEVC_STREAM_RD_PTR));
+ }
+ } else if (vdec->input.target == VDEC_INPUT_TARGET_VLD) {
+ STBUF_WRITE(&vdec->vbuf, set_rp,
+ READ_VREG(VLD_MEM_VIFIFO_RP));
+ } else if (vdec->input.target == VDEC_INPUT_TARGET_HEVC) {
+ STBUF_WRITE(&vdec->vbuf, set_rp,
+ READ_VREG(HEVC_STREAM_RD_PTR));
+ }
+}
+
+static void vdec_sync_input_write(struct vdec_s *vdec)
+{
+ if (!vdec_stream_based(vdec))
+ return;
+
+ if (vdec->input.target == VDEC_INPUT_TARGET_VLD) {
+ if (is_support_no_parser()) {
+ if (!vdec->master) {
+ WRITE_VREG(VLD_MEM_VIFIFO_WP,
+ STBUF_READ(&vdec->vbuf, get_wp));
+ } else {
+ STBUF_WRITE(&vdec->vbuf, set_wp,
+ STBUF_READ(&vdec->master->vbuf, get_wp));
+ }
+ } else {
+ WRITE_VREG(VLD_MEM_VIFIFO_WP,
+ STBUF_READ(&vdec->vbuf, get_wp));
+ }
+ } else if (vdec->input.target == VDEC_INPUT_TARGET_HEVC) {
+ if (is_support_no_parser()) {
+ if (!vdec->master) {
+ WRITE_VREG(HEVC_STREAM_WR_PTR,
+ STBUF_READ(&vdec->vbuf, get_wp));
+ } else {
+ STBUF_WRITE(&vdec->vbuf, set_wp,
+ STBUF_READ(&vdec->master->vbuf, get_wp));
+ }
+ } else {
+ WRITE_VREG(HEVC_STREAM_WR_PTR,
+ STBUF_READ(&vdec->vbuf, get_wp));
+ }
+ }
+}
+
+void vdec_stream_skip_data(struct vdec_s *vdec, int skip_size)
+{
+ u32 rp_set;
+ struct vdec_input_s *input = &vdec->input;
+ u32 rp = 0, wp = 0, 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 <= skip_size) {
+ pr_err("skip size is error, buffer level = 0x%x, skip size = 0x%x\n", level, skip_size);
+ return;
+ }
+
+ if (wp >= rp) {
+ rp_set = rp + skip_size;
+ }
+ else if ((rp + skip_size) < (input->start + input->size)) {
+ rp_set = rp + skip_size;
+ } else {
+ rp_set = rp + skip_size - input->size;
+ input->stream_cookie++;
+ }
+
+ if (vdec->format == VFORMAT_H264)
+ SET_VREG_MASK(POWER_CTL_VLD,
+ (1 << 9));
+
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 0);
+
+ /* restore read side */
+ WRITE_VREG(VLD_MEM_SWAP_ADDR,
+ input->swap_page_phys);
+ WRITE_VREG(VLD_MEM_SWAP_CTL, 1);
+
+ while (READ_VREG(VLD_MEM_SWAP_CTL) & (1<<7))
+ ;
+ WRITE_VREG(VLD_MEM_SWAP_CTL, 0);
+
+ WRITE_VREG(VLD_MEM_VIFIFO_CURR_PTR,
+ rp_set);
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 1);
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 0);
+ STBUF_WRITE(&vdec->vbuf, set_rp,
+ rp_set);
+ WRITE_VREG(VLD_MEM_SWAP_ADDR,
+ input->swap_page_phys);
+ WRITE_VREG(VLD_MEM_SWAP_CTL, 3);
+ while (READ_VREG(VLD_MEM_SWAP_CTL) & (1<<7))
+ ;
+ WRITE_VREG(VLD_MEM_SWAP_CTL, 0);
+}
+EXPORT_SYMBOL(vdec_stream_skip_data);
+
+/*
+ *get next frame from input chain
+ */
+/*
+ *THE VLD_FIFO is 512 bytes and Video buffer level
+ * empty interrupt is set to 0x80 bytes threshold
+ */
+#define VLD_PADDING_SIZE 1024
+#define HEVC_PADDING_SIZE (1024*16)
+int vdec_prepare_input(struct vdec_s *vdec, struct vframe_chunk_s **p)
+{
+ struct vdec_input_s *input = &vdec->input;
+ struct vframe_chunk_s *chunk = NULL;
+ struct vframe_block_list_s *block = NULL;
+ int dummy;
+
+ /* full reset to HW input */
+ if (input->target == VDEC_INPUT_TARGET_VLD) {
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 0);
+
+ /* reset VLD fifo for all vdec */
+ WRITE_VREG(DOS_SW_RESET0, (1<<5) | (1<<4) | (1<<3));
+ WRITE_VREG(DOS_SW_RESET0, 0);
+ if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SC2)
+ dummy = READ_RESET_REG(RESET0_REGISTER);
+ WRITE_VREG(POWER_CTL_VLD, 1 << 4);
+ } else if (input->target == VDEC_INPUT_TARGET_HEVC) {
+#if 0
+ /*move to driver*/
+ if (input_frame_based(input))
+ WRITE_VREG(HEVC_STREAM_CONTROL, 0);
+
+ /*
+ * 2: assist
+ * 3: parser
+ * 4: parser_state
+ * 8: dblk
+ * 11:mcpu
+ * 12:ccpu
+ * 13:ddr
+ * 14:iqit
+ * 15:ipp
+ * 17:qdct
+ * 18:mpred
+ * 19:sao
+ * 24:hevc_afifo
+ */
+ WRITE_VREG(DOS_SW_RESET3,
+ (1<<3)|(1<<4)|(1<<8)|(1<<11)|(1<<12)|(1<<14)|(1<<15)|
+ (1<<17)|(1<<18)|(1<<19));
+ WRITE_VREG(DOS_SW_RESET3, 0);
+#endif
+ }
+
+ /*
+ *setup HW decoder input buffer (VLD context)
+ * based on input->type and input->target
+ */
+ if (input_frame_based(input)) {
+ chunk = vdec_input_next_chunk(&vdec->input);
+
+ if (chunk == NULL) {
+ *p = NULL;
+ return -1;
+ }
+
+ block = chunk->block;
+
+ if (input->target == VDEC_INPUT_TARGET_VLD) {
+ WRITE_VREG(VLD_MEM_VIFIFO_START_PTR, block->start);
+ WRITE_VREG(VLD_MEM_VIFIFO_END_PTR, block->start +
+ block->size - 8);
+ WRITE_VREG(VLD_MEM_VIFIFO_CURR_PTR,
+ round_down(block->start + chunk->offset,
+ VDEC_FIFO_ALIGN));
+
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 1);
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 0);
+
+ /* set to manual mode */
+ WRITE_VREG(VLD_MEM_VIFIFO_BUF_CNTL, 2);
+ WRITE_VREG(VLD_MEM_VIFIFO_RP,
+ round_down(block->start + chunk->offset,
+ VDEC_FIFO_ALIGN));
+ dummy = chunk->offset + chunk->size +
+ VLD_PADDING_SIZE;
+ if (dummy >= block->size)
+ dummy -= block->size;
+ WRITE_VREG(VLD_MEM_VIFIFO_WP,
+ round_down(block->start + dummy,
+ VDEC_FIFO_ALIGN));
+
+ WRITE_VREG(VLD_MEM_VIFIFO_BUF_CNTL, 3);
+ WRITE_VREG(VLD_MEM_VIFIFO_BUF_CNTL, 2);
+
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL,
+ (0x11 << 16) | (1<<10) | (7<<3));
+
+ } else if (input->target == VDEC_INPUT_TARGET_HEVC) {
+ WRITE_VREG(HEVC_STREAM_START_ADDR, block->start);
+ WRITE_VREG(HEVC_STREAM_END_ADDR, block->start +
+ block->size);
+ WRITE_VREG(HEVC_STREAM_RD_PTR, block->start +
+ chunk->offset);
+ dummy = chunk->offset + chunk->size +
+ HEVC_PADDING_SIZE;
+ if (dummy >= block->size)
+ dummy -= block->size;
+ WRITE_VREG(HEVC_STREAM_WR_PTR,
+ round_down(block->start + dummy,
+ VDEC_FIFO_ALIGN));
+
+ /* set endian */
+ SET_VREG_MASK(HEVC_STREAM_CONTROL, 7 << 4);
+ }
+
+ *p = chunk;
+ return chunk->size;
+
+ } else {
+ /* stream based */
+ u32 rp = 0, wp = 0, fifo_len = 0, first_set_rp = 0;
+ int size;
+ bool swap_valid = input->swap_valid;
+ unsigned long swap_page_phys = input->swap_page_phys;
+
+ if (vdec_dual(vdec) &&
+ ((vdec->flag & VDEC_FLAG_SELF_INPUT_CONTEXT) == 0)) {
+ /* keep using previous input context */
+ struct vdec_s *master = (vdec->slave) ?
+ vdec : vdec->master;
+ if (master->input.last_swap_slave) {
+ swap_valid = master->slave->input.swap_valid;
+ swap_page_phys =
+ master->slave->input.swap_page_phys;
+ } else {
+ swap_valid = master->input.swap_valid;
+ swap_page_phys = master->input.swap_page_phys;
+ }
+ }
+
+ if (swap_valid) {
+ if (input->target == VDEC_INPUT_TARGET_VLD) {
+ if (vdec->format == VFORMAT_H264)
+ SET_VREG_MASK(POWER_CTL_VLD,
+ (1 << 9));
+
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 0);
+
+ /* restore read side */
+ WRITE_VREG(VLD_MEM_SWAP_ADDR,
+ swap_page_phys);
+ WRITE_VREG(VLD_MEM_SWAP_CTL, 1);
+
+ while (READ_VREG(VLD_MEM_SWAP_CTL) & (1<<7))
+ ;
+ WRITE_VREG(VLD_MEM_SWAP_CTL, 0);
+#ifdef VDEC_FCC_SUPPORT
+ vdec_fcc_jump_back(vdec);
+#endif
+
+ /* restore wrap count */
+ WRITE_VREG(VLD_MEM_VIFIFO_WRAP_COUNT,
+ input->stream_cookie);
+
+ rp = READ_VREG(VLD_MEM_VIFIFO_RP);
+ fifo_len = READ_VREG(VLD_MEM_VIFIFO_LEVEL);
+
+ /* enable */
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL,
+ (0x11 << 16) | (1<<10));
+
+ if (vdec->vbuf.no_parser)
+ SET_VREG_MASK(VLD_MEM_VIFIFO_CONTROL,
+ 7 << 3);
+
+ /* sync with front end */
+ vdec_sync_input_read(vdec);
+ vdec_sync_input_write(vdec);
+
+ wp = READ_VREG(VLD_MEM_VIFIFO_WP);
+ } else if (input->target == VDEC_INPUT_TARGET_HEVC) {
+ SET_VREG_MASK(HEVC_STREAM_CONTROL, 1);
+
+ /* restore read side */
+ WRITE_VREG(HEVC_STREAM_SWAP_ADDR,
+ swap_page_phys);
+ WRITE_VREG(HEVC_STREAM_SWAP_CTRL, 1);
+
+ while (READ_VREG(HEVC_STREAM_SWAP_CTRL)
+ & (1<<7))
+ ;
+ WRITE_VREG(HEVC_STREAM_SWAP_CTRL, 0);
+#ifdef VDEC_FCC_SUPPORT
+ vdec_fcc_jump_back(vdec);
+#endif
+ /* restore stream offset */
+ WRITE_VREG(HEVC_SHIFT_BYTE_COUNT,
+ input->stream_cookie);
+
+ rp = READ_VREG(HEVC_STREAM_RD_PTR);
+ fifo_len = (READ_VREG(HEVC_STREAM_FIFO_CTL)
+ >> 16) & 0x7f;
+
+
+ /* enable */
+
+ /* sync with front end */
+ vdec_sync_input_read(vdec);
+ vdec_sync_input_write(vdec);
+
+ wp = READ_VREG(HEVC_STREAM_WR_PTR);
+
+ if (vdec->vbuf.no_parser)
+ SET_VREG_MASK(HEVC_STREAM_CONTROL,
+ 7 << 4);
+ /*pr_info("vdec: restore context\r\n");*/
+ }
+
+ } else {
+ if (vdec->vbuf.ext_buf_addr)
+ first_set_rp = STBUF_READ(&vdec->vbuf, get_rp);
+ else {
+ if (vdec->discard_start_data_flag)
+ first_set_rp = STBUF_READ(&vdec->vbuf, get_rp);
+ else
+ first_set_rp = input->start;
+ }
+
+ if (input->target == VDEC_INPUT_TARGET_VLD) {
+ WRITE_VREG(VLD_MEM_VIFIFO_START_PTR,
+ input->start);
+ WRITE_VREG(VLD_MEM_VIFIFO_END_PTR,
+ input->start + input->size - 8);
+ WRITE_VREG(VLD_MEM_VIFIFO_CURR_PTR,
+ first_set_rp);
+
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 1);
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 0);
+
+ /* set to manual mode */
+ WRITE_VREG(VLD_MEM_VIFIFO_BUF_CNTL, 2);
+ WRITE_VREG(VLD_MEM_VIFIFO_RP, first_set_rp);
+ WRITE_VREG(VLD_MEM_VIFIFO_WP,
+ STBUF_READ(&vdec->vbuf, get_wp));
+ rp = READ_VREG(VLD_MEM_VIFIFO_RP);
+
+ /* enable */
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL,
+ (0x11 << 16) | (1<<10));
+ if (vdec->vbuf.no_parser)
+ SET_VREG_MASK(VLD_MEM_VIFIFO_CONTROL,
+ 7 << 3);
+
+ wp = READ_VREG(VLD_MEM_VIFIFO_WP);
+
+ } else if (input->target == VDEC_INPUT_TARGET_HEVC) {
+ WRITE_VREG(HEVC_STREAM_START_ADDR,
+ input->start);
+ WRITE_VREG(HEVC_STREAM_END_ADDR,
+ input->start + input->size);
+ WRITE_VREG(HEVC_STREAM_RD_PTR,
+ first_set_rp);
+ WRITE_VREG(HEVC_STREAM_WR_PTR,
+ STBUF_READ(&vdec->vbuf, get_wp));
+ rp = READ_VREG(HEVC_STREAM_RD_PTR);
+ wp = READ_VREG(HEVC_STREAM_WR_PTR);
+ fifo_len = (READ_VREG(HEVC_STREAM_FIFO_CTL)
+ >> 16) & 0x7f;
+ if (vdec->vbuf.no_parser)
+ SET_VREG_MASK(HEVC_STREAM_CONTROL,
+ 7 << 4);
+ /* enable */
+ }
+ }
+ *p = NULL;
+ if (wp >= rp)
+ size = wp - rp + fifo_len;
+ else
+ size = wp + input->size - rp + fifo_len;
+ if (size < 0) {
+ pr_info("%s error: input->size %x wp %x rp %x fifo_len %x => size %x\r\n",
+ __func__, input->size, wp, rp, fifo_len, size);
+ size = 0;
+ }
+ return size;
+ }
+}
+EXPORT_SYMBOL(vdec_prepare_input);
+
+void vdec_enable_input(struct vdec_s *vdec)
+{
+ struct vdec_input_s *input = &vdec->input;
+
+ if (vdec->status != VDEC_STATUS_ACTIVE)
+ return;
+
+ if (input->target == VDEC_INPUT_TARGET_VLD)
+ SET_VREG_MASK(VLD_MEM_VIFIFO_CONTROL, (1<<2) | (1<<1));
+ else if (input->target == VDEC_INPUT_TARGET_HEVC) {
+ SET_VREG_MASK(HEVC_STREAM_CONTROL, 1);
+ if (vdec_stream_based(vdec)) {
+ if (vdec->vbuf.no_parser)
+ /*set endian for non-parser mode. */
+ SET_VREG_MASK(HEVC_STREAM_CONTROL, 7 << 4);
+ else
+ CLEAR_VREG_MASK(HEVC_STREAM_CONTROL, 7 << 4);
+ } else
+ SET_VREG_MASK(HEVC_STREAM_CONTROL, 7 << 4);
+
+ SET_VREG_MASK(HEVC_STREAM_FIFO_CTL, (1<<29));
+ }
+}
+EXPORT_SYMBOL(vdec_enable_input);
+
+int vdec_set_input_buffer(struct vdec_s *vdec, u32 start, u32 size)
+{
+ int r = vdec_input_set_buffer(&vdec->input, start, size);
+
+ if (r)
+ return r;
+
+ if (vdec->slave)
+ r = vdec_input_set_buffer(&vdec->slave->input, start, size);
+
+ return r;
+}
+EXPORT_SYMBOL(vdec_set_input_buffer);
+
+/*
+ * vdec_eos returns the possibility that there are
+ * more input can be used by decoder through vdec_prepare_input
+ * Note: this function should be called prior to vdec_vframe_dirty
+ * by decoder driver to determine if EOS happens for stream based
+ * decoding when there is no sufficient data for a frame
+ */
+bool vdec_has_more_input(struct vdec_s *vdec)
+{
+ struct vdec_input_s *input = &vdec->input;
+
+ if (!input->eos)
+ return true;
+
+ if (input_frame_based(input))
+ return vdec_input_next_input_chunk(input) != NULL;
+ else {
+ if (input->target == VDEC_INPUT_TARGET_VLD)
+ return READ_VREG(VLD_MEM_VIFIFO_WP) !=
+ STBUF_READ(&vdec->vbuf, get_wp);
+ else {
+ return (READ_VREG(HEVC_STREAM_WR_PTR) & ~0x3) !=
+ (STBUF_READ(&vdec->vbuf, get_wp) & ~0x3);
+ }
+ }
+}
+EXPORT_SYMBOL(vdec_has_more_input);
+
+void vdec_set_prepare_level(struct vdec_s *vdec, int level)
+{
+ vdec->input.prepare_level = level;
+}
+EXPORT_SYMBOL(vdec_set_prepare_level);
+
+void vdec_set_flag(struct vdec_s *vdec, u32 flag)
+{
+ vdec->flag = flag;
+}
+EXPORT_SYMBOL(vdec_set_flag);
+
+void vdec_set_eos(struct vdec_s *vdec, bool eos)
+{
+ struct vdec_core_s *core = vdec_core;
+
+ vdec->input.eos = eos;
+
+ if (vdec->slave)
+ vdec->slave->input.eos = eos;
+ up(&core->sem);
+}
+EXPORT_SYMBOL(vdec_set_eos);
+
+#ifdef VDEC_DEBUG_SUPPORT
+void vdec_set_step_mode(void)
+{
+ step_mode = 0x1ff;
+}
+EXPORT_SYMBOL(vdec_set_step_mode);
+#endif
+
+void vdec_set_next_sched(struct vdec_s *vdec, struct vdec_s *next_vdec)
+{
+ if (vdec && next_vdec) {
+ vdec->sched = 0;
+ next_vdec->sched = 1;
+ }
+}
+EXPORT_SYMBOL(vdec_set_next_sched);
+
+/*
+ * Swap Context: S0 S1 S2 S3 S4
+ * Sample sequence: M S M M S
+ * Master Context: S0 S0 S2 S3 S3
+ * Slave context: NA S1 S1 S2 S4
+ * ^
+ * ^
+ * ^
+ * the tricky part
+ * If there are back to back decoding of master or slave
+ * then the context of the counter part should be updated
+ * with current decoder. In this example, S1 should be
+ * updated to S2.
+ * This is done by swap the swap_page and related info
+ * between two layers.
+ */
+static void vdec_borrow_input_context(struct vdec_s *vdec)
+{
+ struct page *swap_page;
+ unsigned long swap_page_phys;
+ struct vdec_input_s *me;
+ struct vdec_input_s *other;
+
+ if (!vdec_dual(vdec))
+ return;
+
+ me = &vdec->input;
+ other = &vdec_get_associate(vdec)->input;
+
+ /* swap the swap_context, borrow counter part's
+ * swap context storage and update all related info.
+ * After vdec_vframe_dirty, vdec_save_input_context
+ * will be called to update current vdec's
+ * swap context
+ */
+ swap_page = other->swap_page;
+ other->swap_page = me->swap_page;
+ me->swap_page = swap_page;
+
+ swap_page_phys = other->swap_page_phys;
+ other->swap_page_phys = me->swap_page_phys;
+ me->swap_page_phys = swap_page_phys;
+
+ other->swap_rp = me->swap_rp;
+ other->streaming_rp = me->streaming_rp;
+ other->stream_cookie = me->stream_cookie;
+ other->swap_valid = me->swap_valid;
+}
+
+void vdec_vframe_dirty(struct vdec_s *vdec, struct vframe_chunk_s *chunk)
+{
+ if (chunk)
+ chunk->flag |= VFRAME_CHUNK_FLAG_CONSUMED;
+
+ if (vdec_stream_based(vdec)) {
+ vdec->input.swap_needed = true;
+
+ if (vdec_dual(vdec)) {
+ vdec_get_associate(vdec)->input.dirty_count = 0;
+ vdec->input.dirty_count++;
+ if (vdec->input.dirty_count > 1) {
+ vdec->input.dirty_count = 1;
+ vdec_borrow_input_context(vdec);
+ }
+ }
+
+ /* for stream based mode, we update read and write pointer
+ * also in case decoder wants to keep working on decoding
+ * for more frames while input front end has more data
+ */
+ vdec_sync_input_read(vdec);
+ vdec_sync_input_write(vdec);
+
+ vdec->need_more_data |= VDEC_NEED_MORE_DATA_DIRTY;
+ vdec->need_more_data &= ~VDEC_NEED_MORE_DATA;
+ }
+}
+EXPORT_SYMBOL(vdec_vframe_dirty);
+
+bool vdec_need_more_data(struct vdec_s *vdec)
+{
+ if (vdec_stream_based(vdec))
+ return vdec->need_more_data & VDEC_NEED_MORE_DATA;
+
+ return false;
+}
+EXPORT_SYMBOL(vdec_need_more_data);
+
+
+void hevc_wait_ddr(void)
+{
+ unsigned long flags;
+ unsigned int mask = 0;
+
+ mask = 1 << 4; /* hevc */
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
+ mask |= (1 << 8); /* hevcb */
+
+ spin_lock_irqsave(&vdec_spin_lock, flags);
+ codec_dmcbus_write(DMC_REQ_CTRL,
+ codec_dmcbus_read(DMC_REQ_CTRL) & ~mask);
+ spin_unlock_irqrestore(&vdec_spin_lock, flags);
+
+ if (is_cpu_tm2_revb() ||
+ (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2)) {
+ while (!(codec_dmcbus_read(TM2_REVB_DMC_CHAN_STS)
+ & mask))
+ ;
+ } else {
+ while (!(codec_dmcbus_read(DMC_CHAN_STS)
+ & mask))
+ ;
+ }
+}
+
+void vdec_save_input_context(struct vdec_s *vdec)
+{
+ struct vdec_input_s *input = &vdec->input;
+
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ vdec_profile(vdec, VDEC_PROFILE_EVENT_SAVE_INPUT);
+#endif
+
+ if (input->target == VDEC_INPUT_TARGET_VLD)
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 1<<15);
+
+ if (input_stream_based(input) && (input->swap_needed)) {
+ if (input->target == VDEC_INPUT_TARGET_VLD) {
+ WRITE_VREG(VLD_MEM_SWAP_ADDR,
+ input->swap_page_phys);
+ WRITE_VREG(VLD_MEM_SWAP_CTL, 3);
+ while (READ_VREG(VLD_MEM_SWAP_CTL) & (1<<7))
+ ;
+ WRITE_VREG(VLD_MEM_SWAP_CTL, 0);
+ vdec->input.stream_cookie =
+ READ_VREG(VLD_MEM_VIFIFO_WRAP_COUNT);
+ vdec->input.swap_rp =
+ READ_VREG(VLD_MEM_VIFIFO_RP);
+ vdec->input.total_rd_count =
+ (u64)vdec->input.stream_cookie *
+ vdec->input.size + vdec->input.swap_rp -
+ READ_VREG(VLD_MEM_VIFIFO_BYTES_AVAIL);
+ } else if (input->target == VDEC_INPUT_TARGET_HEVC) {
+ WRITE_VREG(HEVC_STREAM_SWAP_ADDR,
+ input->swap_page_phys);
+ WRITE_VREG(HEVC_STREAM_SWAP_CTRL, 3);
+
+ while (READ_VREG(HEVC_STREAM_SWAP_CTRL) & (1<<7))
+ ;
+ WRITE_VREG(HEVC_STREAM_SWAP_CTRL, 0);
+
+ vdec->input.stream_cookie =
+ READ_VREG(HEVC_SHIFT_BYTE_COUNT);
+ vdec->input.swap_rp =
+ READ_VREG(HEVC_STREAM_RD_PTR);
+ if (((vdec->input.stream_cookie & 0x80000000) == 0) &&
+ (vdec->input.streaming_rp & 0x80000000))
+ vdec->input.streaming_rp += 1ULL << 32;
+ vdec->input.streaming_rp &= 0xffffffffULL << 32;
+ vdec->input.streaming_rp |= vdec->input.stream_cookie;
+ vdec->input.total_rd_count = vdec->input.streaming_rp;
+ hevc_wait_ddr();
+ }
+
+ input->swap_valid = true;
+ input->swap_needed = false;
+ /*pr_info("vdec: save context\r\n");*/
+
+ vdec_sync_input_read(vdec);
+
+ if (vdec_dual(vdec)) {
+ struct vdec_s *master = (vdec->slave) ?
+ vdec : vdec->master;
+ master->input.last_swap_slave = (master->slave == vdec);
+ /* pr_info("master->input.last_swap_slave = %d\n",
+ master->input.last_swap_slave); */
+ }
+ }
+}
+EXPORT_SYMBOL(vdec_save_input_context);
+
+void vdec_clean_input(struct vdec_s *vdec)
+{
+ struct vdec_input_s *input = &vdec->input;
+
+ while (!list_empty(&input->vframe_chunk_list)) {
+ struct vframe_chunk_s *chunk =
+ vdec_input_next_chunk(input);
+ if (chunk && (chunk->flag & VFRAME_CHUNK_FLAG_CONSUMED))
+ vdec_input_release_chunk(input, chunk);
+ else
+ break;
+ }
+ vdec_save_input_context(vdec);
+}
+EXPORT_SYMBOL(vdec_clean_input);
+
+
+static int vdec_input_read_restore(struct vdec_s *vdec)
+{
+ struct vdec_input_s *input = &vdec->input;
+
+ if (!vdec_stream_based(vdec))
+ return 0;
+
+ if (!input->swap_valid) {
+ if (input->target == VDEC_INPUT_TARGET_VLD) {
+ WRITE_VREG(VLD_MEM_VIFIFO_START_PTR,
+ input->start);
+ WRITE_VREG(VLD_MEM_VIFIFO_END_PTR,
+ input->start + input->size - 8);
+ WRITE_VREG(VLD_MEM_VIFIFO_CURR_PTR,
+ input->start);
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 1);
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 0);
+
+ /* set to manual mode */
+ WRITE_VREG(VLD_MEM_VIFIFO_BUF_CNTL, 2);
+ WRITE_VREG(VLD_MEM_VIFIFO_RP, input->start);
+ } else if (input->target == VDEC_INPUT_TARGET_HEVC) {
+ WRITE_VREG(HEVC_STREAM_START_ADDR,
+ input->start);
+ WRITE_VREG(HEVC_STREAM_END_ADDR,
+ input->start + input->size);
+ WRITE_VREG(HEVC_STREAM_RD_PTR,
+ input->start);
+ }
+ return 0;
+ }
+ if (input->target == VDEC_INPUT_TARGET_VLD) {
+ /* restore read side */
+ WRITE_VREG(VLD_MEM_SWAP_ADDR,
+ input->swap_page_phys);
+
+ /*swap active*/
+ WRITE_VREG(VLD_MEM_SWAP_CTL, 1);
+
+ /*wait swap busy*/
+ while (READ_VREG(VLD_MEM_SWAP_CTL) & (1<<7))
+ ;
+
+ WRITE_VREG(VLD_MEM_SWAP_CTL, 0);
+ } else if (input->target == VDEC_INPUT_TARGET_HEVC) {
+ /* restore read side */
+ WRITE_VREG(HEVC_STREAM_SWAP_ADDR,
+ input->swap_page_phys);
+ WRITE_VREG(HEVC_STREAM_SWAP_CTRL, 1);
+
+ while (READ_VREG(HEVC_STREAM_SWAP_CTRL)
+ & (1<<7))
+ ;
+ WRITE_VREG(HEVC_STREAM_SWAP_CTRL, 0);
+ }
+
+ return 0;
+}
+
+
+int vdec_sync_input(struct vdec_s *vdec)
+{
+ struct vdec_input_s *input = &vdec->input;
+ u32 rp = 0, wp = 0, fifo_len = 0;
+ int size;
+
+ vdec_input_read_restore(vdec);
+ vdec_sync_input_read(vdec);
+ vdec_sync_input_write(vdec);
+ if (input->target == VDEC_INPUT_TARGET_VLD) {
+ rp = READ_VREG(VLD_MEM_VIFIFO_RP);
+ wp = READ_VREG(VLD_MEM_VIFIFO_WP);
+
+ } else if (input->target == VDEC_INPUT_TARGET_HEVC) {
+ rp = READ_VREG(HEVC_STREAM_RD_PTR);
+ wp = READ_VREG(HEVC_STREAM_WR_PTR);
+ fifo_len = (READ_VREG(HEVC_STREAM_FIFO_CTL)
+ >> 16) & 0x7f;
+ }
+ if (wp >= rp)
+ size = wp - rp + fifo_len;
+ else
+ size = wp + input->size - rp + fifo_len;
+ if (size < 0) {
+ pr_info("%s error: input->size %x wp %x rp %x fifo_len %x => size %x\r\n",
+ __func__, input->size, wp, rp, fifo_len, size);
+ size = 0;
+ }
+ return size;
+
+}
+EXPORT_SYMBOL(vdec_sync_input);
+
+const char *vdec_status_str(struct vdec_s *vdec)
+{
+ if (vdec->status < 0)
+ return "INVALID";
+ return vdec->status < ARRAY_SIZE(vdec_status_string) ?
+ vdec_status_string[vdec->status] : "INVALID";
+}
+
+const char *vdec_type_str(struct vdec_s *vdec)
+{
+ switch (vdec->type) {
+ case VDEC_TYPE_SINGLE:
+ return "VDEC_TYPE_SINGLE";
+ case VDEC_TYPE_STREAM_PARSER:
+ return "VDEC_TYPE_STREAM_PARSER";
+ case VDEC_TYPE_FRAME_BLOCK:
+ return "VDEC_TYPE_FRAME_BLOCK";
+ case VDEC_TYPE_FRAME_CIRCULAR:
+ return "VDEC_TYPE_FRAME_CIRCULAR";
+ default:
+ return "VDEC_TYPE_INVALID";
+ }
+}
+
+const char *vdec_device_name_str(struct vdec_s *vdec)
+{
+ return vdec_device_name[vdec->format * 2 + 1];
+}
+EXPORT_SYMBOL(vdec_device_name_str);
+
+void walk_vdec_core_list(char *s)
+{
+ struct vdec_s *vdec;
+ struct vdec_core_s *core = vdec_core;
+ unsigned long flags;
+
+ pr_info("%s --->\n", s);
+
+ flags = vdec_core_lock(vdec_core);
+
+ if (list_empty(&core->connected_vdec_list)) {
+ pr_info("connected vdec list empty\n");
+ } else {
+ list_for_each_entry(vdec, &core->connected_vdec_list, list) {
+ pr_info("\tvdec (%p), status = %s\n", vdec,
+ vdec_status_str(vdec));
+ }
+ }
+
+ vdec_core_unlock(vdec_core, flags);
+}
+EXPORT_SYMBOL(walk_vdec_core_list);
+
+/* insert vdec to vdec_core for scheduling,
+ * for dual running decoders, connect/disconnect always runs in pairs
+ */
+int vdec_connect(struct vdec_s *vdec)
+{
+ unsigned long flags;
+
+ //trace_vdec_connect(vdec);/*DEBUG_TMP*/
+
+ if (vdec->status != VDEC_STATUS_DISCONNECTED)
+ return 0;
+
+ vdec_set_status(vdec, VDEC_STATUS_CONNECTED);
+ vdec_set_next_status(vdec, VDEC_STATUS_CONNECTED);
+
+ init_completion(&vdec->inactive_done);
+
+ if (vdec->slave) {
+ vdec_set_status(vdec->slave, VDEC_STATUS_CONNECTED);
+ vdec_set_next_status(vdec->slave, VDEC_STATUS_CONNECTED);
+
+ init_completion(&vdec->slave->inactive_done);
+ }
+
+ flags = vdec_core_lock(vdec_core);
+
+ list_add_tail(&vdec->list, &vdec_core->connected_vdec_list);
+
+ if (vdec->slave) {
+ list_add_tail(&vdec->slave->list,
+ &vdec_core->connected_vdec_list);
+ }
+
+ vdec_core_unlock(vdec_core, flags);
+
+ up(&vdec_core->sem);
+
+ return 0;
+}
+EXPORT_SYMBOL(vdec_connect);
+
+/* remove vdec from vdec_core scheduling */
+int vdec_disconnect(struct vdec_s *vdec)
+{
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ vdec_profile(vdec, VDEC_PROFILE_EVENT_DISCONNECT);
+#endif
+ //trace_vdec_disconnect(vdec);/*DEBUG_TMP*/
+
+ if ((vdec->status != VDEC_STATUS_CONNECTED) &&
+ (vdec->status != VDEC_STATUS_ACTIVE)) {
+ return 0;
+ }
+ mutex_lock(&vdec_mutex);
+ /*
+ *when a vdec is under the management of scheduler
+ * the status change will only be from vdec_core_thread
+ */
+ vdec_set_next_status(vdec, VDEC_STATUS_DISCONNECTED);
+
+ if (vdec->slave)
+ vdec_set_next_status(vdec->slave, VDEC_STATUS_DISCONNECTED);
+ else if (vdec->master)
+ vdec_set_next_status(vdec->master, VDEC_STATUS_DISCONNECTED);
+ mutex_unlock(&vdec_mutex);
+ up(&vdec_core->sem);
+
+ if(!wait_for_completion_timeout(&vdec->inactive_done,
+ msecs_to_jiffies(2000)))
+ goto discon_timeout;
+
+ if (vdec->slave) {
+ if(!wait_for_completion_timeout(&vdec->slave->inactive_done,
+ msecs_to_jiffies(2000)))
+ goto discon_timeout;
+ } else if (vdec->master) {
+ if(!wait_for_completion_timeout(&vdec->master->inactive_done,
+ msecs_to_jiffies(2000)))
+ goto discon_timeout;
+ }
+
+ return 0;
+discon_timeout:
+ pr_err("%s timeout!!! status: 0x%x force it to 2\n", __func__, vdec->status);
+ vdec_set_status(vdec, VDEC_STATUS_CONNECTED);
+ return 0;
+}
+EXPORT_SYMBOL(vdec_disconnect);
+
+/* release vdec structure */
+int vdec_destroy(struct vdec_s *vdec)
+{
+ //trace_vdec_destroy(vdec);/*DEBUG_TMP*/
+
+ vdec_input_release(&vdec->input);
+
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ vdec_profile_flush(vdec);
+#endif
+ ida_simple_remove(&vdec_core->ida, vdec->id);
+ if (vdec->mvfrm)
+ vfree(vdec->mvfrm);
+ vfree(vdec);
+
+#ifdef CONFIG_AMLOGIC_V4L_VIDEO3
+ v4lvideo_dec_count_decrease();
+#endif
+ atomic_dec(&vdec_core->vdec_nr);
+
+ return 0;
+}
+EXPORT_SYMBOL(vdec_destroy);
+
+static bool is_tunnel_pipeline(u32 pl)
+{
+ return ((pl & BIT(FRAME_BASE_PATH_DTV_TUNNEL_MODE)) ||
+ (pl & BIT(FRAME_BASE_PATH_AMLVIDEO_AMVIDEO))) ?
+ true : false;
+}
+
+static bool is_nontunnel_pipeline(u32 pl)
+{
+ return (pl & BIT(FRAME_BASE_PATH_DI_V4LVIDEO)) ? true : false;
+}
+
+static bool is_v4lvideo_already_used(u32 pre, int vf_receiver_inst)
+{
+ if (vf_receiver_inst == 0) {
+ if (pre & BIT(FRAME_BASE_PATH_DI_V4LVIDEO_0)) {
+ return true;
+ }
+ } else if (vf_receiver_inst == 1) {
+ if (pre & BIT(FRAME_BASE_PATH_DI_V4LVIDEO_1)) {
+ return true;
+ }
+ } else if (vf_receiver_inst == 2) {
+ if (pre & BIT(FRAME_BASE_PATH_DI_V4LVIDEO_2)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool is_res_locked(u32 pre, u32 cur, int vf_receiver_inst)
+{
+ if (is_tunnel_pipeline(pre)) {
+ if (is_tunnel_pipeline(cur)) {
+ return true;
+ }
+ } else if (is_nontunnel_pipeline(cur)) {
+ if (is_v4lvideo_already_used(pre,vf_receiver_inst)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+int vdec_resource_checking(struct vdec_s *vdec)
+{
+ /*
+ * If it is the single instance that the pipeline of DTV used,
+ * then have to check that the resources which is belong tunnel
+ * pipeline these are being released.
+ */
+ ulong expires = jiffies + msecs_to_jiffies(2000);
+ while (is_res_locked(vdec_core->vdec_resouce_status,
+ BIT(vdec->frame_base_video_path),
+ vdec->vf_receiver_inst)) {
+ if (time_after(jiffies, expires)) {
+ pr_err("wait vdec resource timeout.\n");
+ return -EBUSY;
+ }
+ schedule();
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(vdec_resource_checking);
+
+/*
+ *register vdec_device
+ * create output, vfm or create ionvideo output
+ */
+s32 vdec_init(struct vdec_s *vdec, int is_4k)
+{
+ int r = 0;
+ struct vdec_s *p = vdec;
+ const char *dev_name;
+ int id = PLATFORM_DEVID_AUTO;/*if have used my self*/
+ int max_di_count = max_di_instance;
+
+ if (vdec_stream_based(vdec))
+ max_di_count = max_supported_di_instance;
+
+ if (is_res_locked(vdec_core->vdec_resouce_status,
+ BIT(vdec->frame_base_video_path),
+ vdec->vf_receiver_inst))
+ return -EBUSY;
+ //pr_err("%s [pid=%d,tgid=%d]\n", __func__, current->pid, current->tgid);
+ dev_name = get_dev_name(vdec_single(vdec), vdec->format);
+
+ if (dev_name == NULL)
+ return -ENODEV;
+
+ pr_info("vdec_init, dev_name:%s, vdec_type=%s id = %d\n",
+ dev_name, vdec_type_str(vdec), vdec->id);
+
+ snprintf(vdec->name, sizeof(vdec->name),
+ "vdec-%d", vdec->id);
+ snprintf(vdec->dec_spend_time, sizeof(vdec->dec_spend_time),
+ "%s-dec_spend_time", vdec->name);
+ snprintf(vdec->dec_spend_time_ave, sizeof(vdec->dec_spend_time_ave),
+ "%s-dec_spend_time_ave", vdec->name);
+
+ /*
+ *todo: VFM patch control should be configurable,
+ * for now all stream based input uses default VFM path.
+ */
+ if (!is_support_no_parser()) {
+ if (vdec_stream_based(vdec) && !vdec_dual(vdec)) {
+ if (vdec_core->vfm_vdec == NULL) {
+ pr_debug("vdec_init set vfm decoder %p\n", vdec);
+ vdec_core->vfm_vdec = vdec;
+ } else {
+ pr_info("vdec_init vfm path busy.\n");
+ return -EBUSY;
+ }
+ }
+ }
+
+ mutex_lock(&vdec_mutex);
+ inited_vcodec_num++;
+ mutex_unlock(&vdec_mutex);
+
+ vdec_input_set_type(&vdec->input, vdec->type,
+ (vdec->format == VFORMAT_HEVC ||
+ vdec->format == VFORMAT_AVS2 ||
+ vdec->format == VFORMAT_VP9 ||
+ vdec->format == VFORMAT_AV1
+ ) ?
+ VDEC_INPUT_TARGET_HEVC :
+ VDEC_INPUT_TARGET_VLD);
+ if (vdec_single(vdec) || (vdec_get_debug_flags() & 0x2))
+ vdec_enable_DMC(vdec);
+ p->cma_dev = vdec_core->cma_dev;
+ p->get_canvas = get_canvas;
+ p->get_canvas_ex = get_canvas_ex;
+ p->free_canvas_ex = free_canvas_ex;
+ p->vdec_fps_detec = vdec_fps_detec;
+ /* todo */
+ if (!vdec_dual(vdec)) {
+ p->use_vfm_path =
+ (is_support_no_parser()) ?
+ vdec_single(vdec) :
+ vdec_stream_based(vdec);
+ }
+
+ if (debugflags & 0x4)
+ p->use_vfm_path = 1;
+ /* vdec_dev_reg.flag = 0; */
+ if (vdec->id >= 0)
+ id = vdec->id;
+ p->parallel_dec = parallel_decode;
+ vdec_core->parallel_dec = parallel_decode;
+ vdec->canvas_mode = CANVAS_BLKMODE_32X32;
+#ifdef FRAME_CHECK
+ vdec_frame_check_init(vdec);
+#endif
+ /* stream buffer init. */
+ if (vdec->vbuf.ops && !vdec->master) {
+ r = vdec->vbuf.ops->init(&vdec->vbuf, vdec);
+ if (r) {
+ pr_err("%s stream buffer init err (%d)\n", dev_name, r);
+
+ mutex_lock(&vdec_mutex);
+ inited_vcodec_num--;
+ mutex_unlock(&vdec_mutex);
+
+ goto error;
+ }
+
+ if (vdec->slave) {
+ memcpy(&vdec->slave->vbuf, &vdec->vbuf,
+ sizeof(vdec->vbuf));
+ }
+ }
+
+ p->dev = platform_device_register_data(
+ &vdec_core->vdec_core_platform_device->dev,
+ dev_name,
+ id,
+ &p, sizeof(struct vdec_s *));
+
+ if (IS_ERR(p->dev)) {
+ r = PTR_ERR(p->dev);
+ pr_err("vdec: Decoder device %s register failed (%d)\n",
+ dev_name, r);
+
+ mutex_lock(&vdec_mutex);
+ inited_vcodec_num--;
+ mutex_unlock(&vdec_mutex);
+
+ goto error;
+ } else if (!p->dev->dev.driver) {
+ pr_info("vdec: Decoder device %s driver probe failed.\n",
+ dev_name);
+ r = -ENODEV;
+
+ goto error;
+ }
+
+ if ((p->type == VDEC_TYPE_FRAME_BLOCK) && (p->run == NULL)) {
+ r = -ENODEV;
+ pr_err("vdec: Decoder device not handled (%s)\n", dev_name);
+
+ mutex_lock(&vdec_mutex);
+ inited_vcodec_num--;
+ mutex_unlock(&vdec_mutex);
+
+ goto error;
+ }
+
+ if (p->use_vfm_path) {
+ vdec->vf_receiver_inst = -1;
+ vdec->vfm_map_id[0] = 0;
+ } else if (!vdec_dual(vdec)) {
+ /* create IONVIDEO instance and connect decoder's
+ * vf_provider interface to it
+ */
+ if (!is_support_no_parser()) {
+ if (p->type != VDEC_TYPE_FRAME_BLOCK) {
+ r = -ENODEV;
+ pr_err("vdec: Incorrect decoder type\n");
+
+ mutex_lock(&vdec_mutex);
+ inited_vcodec_num--;
+ mutex_unlock(&vdec_mutex);
+
+ goto error;
+ }
+ }
+
+ if (strncmp("disable", vfm_path, strlen("disable"))) {
+ snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE,
+ "%s %s", vdec->vf_provider_name, vfm_path);
+ snprintf(vdec->vfm_map_id, VDEC_MAP_NAME_SIZE,
+ "vdec-map-%d", vdec->id);
+ } else if (p->frame_base_video_path == FRAME_BASE_PATH_IONVIDEO) {
+#if 1
+ r = ionvideo_assign_map(&vdec->vf_receiver_name,
+ &vdec->vf_receiver_inst);
+#else
+ /*
+ * temporarily just use decoder instance ID as iondriver ID
+ * to solve OMX iondriver instance number check time sequence
+ * only the limitation is we can NOT mix different video
+ * decoders since same ID will be used for different decoder
+ * formats.
+ */
+ vdec->vf_receiver_inst = p->dev->id;
+ r = ionvideo_assign_map(&vdec->vf_receiver_name,
+ &vdec->vf_receiver_inst);
+#endif
+ if (r < 0) {
+ pr_err("IonVideo frame receiver allocation failed.\n");
+
+ mutex_lock(&vdec_mutex);
+ inited_vcodec_num--;
+ mutex_unlock(&vdec_mutex);
+
+ goto error;
+ }
+
+ snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE,
+ "%s %s", vdec->vf_provider_name,
+ vdec->vf_receiver_name);
+ snprintf(vdec->vfm_map_id, VDEC_MAP_NAME_SIZE,
+ "vdec-map-%d", vdec->id);
+ } else if (p->frame_base_video_path ==
+ FRAME_BASE_PATH_AMLVIDEO_AMVIDEO) {
+ if (vdec_secure(vdec)) {
+ snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE,
+ "%s %s", vdec->vf_provider_name,
+ "amlvideo amvideo");
+ } else {
+ if (debug_vdetect)
+ snprintf(vdec->vfm_map_chain,
+ VDEC_MAP_NAME_SIZE,
+ "%s vdetect.0 %s",
+ vdec->vf_provider_name,
+ "amlvideo ppmgr deinterlace amvideo");
+ else
+ snprintf(vdec->vfm_map_chain,
+ VDEC_MAP_NAME_SIZE, "%s %s",
+ vdec->vf_provider_name,
+ "amlvideo ppmgr deinterlace amvideo");
+ }
+ snprintf(vdec->vfm_map_id, VDEC_MAP_NAME_SIZE,
+ "vdec-map-%d", vdec->id);
+ } else if (p->frame_base_video_path ==
+ FRAME_BASE_PATH_AMLVIDEO1_AMVIDEO2) {
+ snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE,
+ "%s %s", vdec->vf_provider_name,
+ "aml_video.1 videosync.0 videopip");
+ snprintf(vdec->vfm_map_id, VDEC_MAP_NAME_SIZE,
+ "vdec-map-%d", vdec->id);
+ } else if (p->frame_base_video_path == FRAME_BASE_PATH_V4L_OSD) {
+ snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE,
+ "%s %s", vdec->vf_provider_name,
+ vdec->vf_receiver_name);
+ snprintf(vdec->vfm_map_id, VDEC_MAP_NAME_SIZE,
+ "vdec-map-%d", vdec->id);
+ } else if (p->frame_base_video_path == FRAME_BASE_PATH_TUNNEL_MODE) {
+ snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE,
+ "%s %s", vdec->vf_provider_name,
+ "amvideo");
+ snprintf(vdec->vfm_map_id, VDEC_MAP_NAME_SIZE,
+ "vdec-map-%d", vdec->id);
+ } else if (p->frame_base_video_path == FRAME_BASE_PATH_PIP_TUNNEL_MODE) {
+ snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE,
+ "%s %s", vdec->vf_provider_name,
+ "videosync.0 videopip");
+ snprintf(vdec->vfm_map_id, VDEC_MAP_NAME_SIZE,
+ "vdec-map-%d", vdec->id);
+ } else if (p->frame_base_video_path == FRAME_BASE_PATH_V4L_VIDEO) {
+ snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE,
+ "%s %s %s", vdec->vf_provider_name,
+ vdec->vf_receiver_name, "amvideo");
+ snprintf(vdec->vfm_map_id, VDEC_MAP_NAME_SIZE,
+ "vdec-map-%d", vdec->id);
+ } else if (p->frame_base_video_path ==
+ FRAME_BASE_PATH_DI_V4LVIDEO) {
+#ifdef CONFIG_AMLOGIC_V4L_VIDEO3
+ r = v4lvideo_assign_map(&vdec->vf_receiver_name,
+ &vdec->vf_receiver_inst);
+#else
+ r = -1;
+#endif
+ if (r < 0) {
+ pr_err("V4lVideo frame receiver allocation failed.\n");
+ mutex_lock(&vdec_mutex);
+ inited_vcodec_num--;
+ mutex_unlock(&vdec_mutex);
+ goto error;
+ }
+ if (!v4lvideo_add_di)
+ snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE,
+ "%s %s", vdec->vf_provider_name,
+ vdec->vf_receiver_name);
+ else {
+ if ((vdec->vf_receiver_inst == 0)
+ && (max_di_count > 0))
+ if (max_di_count == 1)
+ snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE,
+ "%s %s %s", vdec->vf_provider_name,
+ "deinterlace",
+ vdec->vf_receiver_name);
+ else
+ snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE,
+ "%s %s %s", vdec->vf_provider_name,
+ "dimulti.1",
+ vdec->vf_receiver_name);
+ else if ((vdec->vf_receiver_inst <
+ max_di_count) &&
+ (vdec->vf_receiver_inst == 1))
+ snprintf(vdec->vfm_map_chain,
+ VDEC_MAP_NAME_SIZE,
+ "%s %s %s",
+ vdec->vf_provider_name,
+ "deinterlace",
+ vdec->vf_receiver_name);
+ else if (vdec->vf_receiver_inst <
+ max_di_count)
+ snprintf(vdec->vfm_map_chain,
+ VDEC_MAP_NAME_SIZE,
+ "%s %s%d %s",
+ vdec->vf_provider_name,
+ "dimulti.",
+ vdec->vf_receiver_inst,
+ vdec->vf_receiver_name);
+ else
+ snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE,
+ "%s %s", vdec->vf_provider_name,
+ vdec->vf_receiver_name);
+ }
+ snprintf(vdec->vfm_map_id, VDEC_MAP_NAME_SIZE,
+ "vdec-map-%d", vdec->id);
+ } else if (p->frame_base_video_path ==
+ FRAME_BASE_PATH_V4LVIDEO) {
+#ifdef CONFIG_AMLOGIC_V4L_VIDEO3
+ r = v4lvideo_assign_map(&vdec->vf_receiver_name,
+ &vdec->vf_receiver_inst);
+#else
+ r = -1;
+#endif
+ if (r < 0) {
+ pr_err("V4lVideo frame receiver allocation failed.\n");
+ mutex_lock(&vdec_mutex);
+ inited_vcodec_num--;
+ mutex_unlock(&vdec_mutex);
+ goto error;
+ }
+ snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE,
+ "%s %s", vdec->vf_provider_name,
+ vdec->vf_receiver_name);
+ snprintf(vdec->vfm_map_id, VDEC_MAP_NAME_SIZE,
+ "vdec-map-%d", vdec->id);
+ } else if (p->frame_base_video_path ==
+ FRAME_BASE_PATH_DTV_TUNNEL_MODE) {
+ snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE,
+ "%s deinterlace %s", vdec->vf_provider_name,
+ "amvideo");
+ snprintf(vdec->vfm_map_id, VDEC_MAP_NAME_SIZE,
+ "vdec-map-%d", vdec->id);
+ } else if (p->frame_base_video_path ==
+ FRAME_BASE_PATH_AMLVIDEO_FENCE) {
+ snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE,
+ "%s %s", vdec->vf_provider_name,
+ "amlvideo amvideo");
+ snprintf(vdec->vfm_map_id, VDEC_MAP_NAME_SIZE,
+ "vdec-map-%d", vdec->id);
+ }
+
+ if (vfm_map_add(vdec->vfm_map_id,
+ vdec->vfm_map_chain) < 0) {
+ r = -ENOMEM;
+ pr_err("Decoder pipeline map creation failed %s.\n",
+ vdec->vfm_map_id);
+ vdec->vfm_map_id[0] = 0;
+
+ mutex_lock(&vdec_mutex);
+ inited_vcodec_num--;
+ mutex_unlock(&vdec_mutex);
+
+ goto error;
+ }
+
+ pr_debug("vfm map %s created\n", vdec->vfm_map_id);
+
+ /*
+ *assume IONVIDEO driver already have a few vframe_receiver
+ * registered.
+ * 1. Call iondriver function to allocate a IONVIDEO path and
+ * provide receiver's name and receiver op.
+ * 2. Get decoder driver's provider name from driver instance
+ * 3. vfm_map_add(name, "<decoder provider name>
+ * <iondriver receiver name>"), e.g.
+ * vfm_map_add("vdec_ion_map_0", "mpeg4_0 iondriver_1");
+ * 4. vf_reg_provider and vf_reg_receiver
+ * Note: the decoder provider's op uses vdec as op_arg
+ * the iondriver receiver's op uses iondev device as
+ * op_arg
+ */
+
+ }
+
+ if (!vdec_single(vdec)) {
+ vf_reg_provider(&p->vframe_provider);
+
+ vf_notify_receiver(p->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_START,
+ vdec);
+
+ if (vdec_core->hint_fr_vdec == NULL)
+ vdec_core->hint_fr_vdec = vdec;
+
+ if (vdec_core->hint_fr_vdec == vdec) {
+ if (p->sys_info->rate != 0) {
+ if (!vdec->is_reset) {
+ vf_notify_receiver(p->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)
+ ((unsigned long)
+ p->sys_info->rate));
+ vdec->fr_hint_state = VDEC_HINTED;
+ }
+ } else {
+ vdec->fr_hint_state = VDEC_NEED_HINT;
+ }
+ }
+ }
+
+ p->dolby_meta_with_el = 0;
+ pr_debug("vdec_init, vf_provider_name = %s, b %d\n",
+ p->vf_provider_name, is_cpu_tm2_revb());
+
+ mutex_lock(&vdec_mutex);
+ vdec_core->vdec_resouce_status |= BIT(p->frame_base_video_path);
+ if (p->frame_base_video_path == FRAME_BASE_PATH_DI_V4LVIDEO) {
+ if (p->vf_receiver_inst == 0) {
+ vdec_core->vdec_resouce_status |= BIT(FRAME_BASE_PATH_DI_V4LVIDEO_0);
+ } else if (p->vf_receiver_inst == 1) {
+ vdec_core->vdec_resouce_status |= BIT(FRAME_BASE_PATH_DI_V4LVIDEO_1);
+ } else if (p->vf_receiver_inst == 2) {
+ vdec_core->vdec_resouce_status |= BIT(FRAME_BASE_PATH_DI_V4LVIDEO_2);
+ }
+ }
+ mutex_unlock(&vdec_mutex);
+
+ vdec_input_prepare_bufs(/*prepared buffer for fast playing.*/
+ &vdec->input,
+ vdec->sys_info->width,
+ vdec->sys_info->height);
+ /* vdec is now ready to be active */
+ vdec_set_status(vdec, VDEC_STATUS_DISCONNECTED);
+
+#ifdef VDEC_FCC_SUPPORT
+ init_waitqueue_head(&vdec->jump_back_wq);
+ mutex_init(&vdec->jump_back_mutex);
+ vdec->fcc_mode = FCC_BUTT;
+ vdec->fcc_status = STATUS_BUTT;
+#endif
+ return 0;
+
+error:
+ return r;
+}
+EXPORT_SYMBOL(vdec_init);
+
+/*
+ *Remove the vdec after timeout happens both in vdec_disconnect
+ *and platform_device_unregister. Then after, we can release the vdec.
+ */
+static void vdec_connect_list_force_clear(struct vdec_core_s *core, struct vdec_s *v_ref)
+{
+ struct vdec_s *vdec, *tmp;
+ unsigned long flags;
+
+ flags = vdec_core_lock(core);
+
+ list_for_each_entry_safe(vdec, tmp,
+ &core->connected_vdec_list, list) {
+ if ((vdec->status == VDEC_STATUS_DISCONNECTED) &&
+ (vdec == v_ref)) {
+ pr_err("%s, vdec = %p, active vdec = %p\n",
+ __func__, vdec, core->active_vdec);
+ if (v_ref->active_mask)
+ core->sched_mask &= ~v_ref->active_mask;
+ if (core->active_vdec == v_ref)
+ core->active_vdec = NULL;
+ if (core->active_hevc == v_ref)
+ core->active_hevc = NULL;
+ if (core->last_vdec == v_ref)
+ core->last_vdec = NULL;
+ list_del(&vdec->list);
+ }
+ }
+
+ vdec_core_unlock(core, flags);
+}
+
+/* vdec_create/init/release/destroy are applied to both dual running decoders
+ */
+void vdec_release(struct vdec_s *vdec)
+{
+ u32 wcount = 0;
+
+ //trace_vdec_release(vdec);/*DEBUG_TMP*/
+#ifdef VDEC_DEBUG_SUPPORT
+ if (step_mode) {
+ pr_info("VDEC_DEBUG: in step_mode, wait release\n");
+ while (step_mode)
+ udelay(10);
+ pr_info("VDEC_DEBUG: step_mode is clear\n");
+ }
+#endif
+ /* When release, userspace systemctl need this duration 0 event */
+ vframe_rate_uevent(0);
+ vdec_disconnect(vdec);
+
+ if (vdec->vframe_provider.name) {
+ if (!vdec_single(vdec)) {
+ if (vdec_core->hint_fr_vdec == vdec
+ && vdec->fr_hint_state == VDEC_HINTED)
+ vf_notify_receiver(
+ vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_FR_END_HINT,
+ NULL);
+ vdec->fr_hint_state = VDEC_NO_NEED_HINT;
+ }
+ vf_unreg_provider(&vdec->vframe_provider);
+ }
+
+ if (vdec_core->vfm_vdec == vdec)
+ vdec_core->vfm_vdec = NULL;
+
+ if (vdec_core->hint_fr_vdec == vdec)
+ vdec_core->hint_fr_vdec = NULL;
+
+ if (vdec->vf_receiver_inst >= 0) {
+ if (vdec->vfm_map_id[0]) {
+ vfm_map_remove(vdec->vfm_map_id);
+ vdec->vfm_map_id[0] = 0;
+ }
+ }
+
+ while (vdec->irq_cnt > vdec->irq_thread_cnt) {
+ if ((wcount & 0x1f) == 0)
+ pr_debug("%s vdec[%lx]: %lld > %lld, loop %u times\n",__func__, (unsigned long)vdec,
+ vdec->irq_cnt,vdec->irq_thread_cnt, wcount);
+ /*
+ * Wait at most 2000 ms.
+ * In suspend scenario, the system may disable thread_fn,
+ * thus can NOT always waiting the thread_fn happen
+ */
+ if (++wcount > 1000)
+ break;
+ usleep_range(1000, 2000);
+ }
+
+#ifdef FRAME_CHECK
+ vdec_frame_check_exit(vdec);
+#endif
+ vdec_fps_clear(vdec->id);
+ if (atomic_read(&vdec_core->vdec_nr) == 1)
+ vdec_disable_DMC(vdec);
+ platform_device_unregister(vdec->dev);
+ /*Check if the vdec still in connected list, if yes, delete it*/
+ vdec_connect_list_force_clear(vdec_core, vdec);
+
+ if (vdec->vbuf.ops && !vdec->master)
+ vdec->vbuf.ops->release(&vdec->vbuf);
+
+ pr_debug("vdec_release instance %p, total %d id = %d\n", vdec,
+ atomic_read(&vdec_core->vdec_nr), vdec->id);
+
+ mutex_lock(&vdec_mutex);
+ if (vdec->frame_base_video_path == FRAME_BASE_PATH_DI_V4LVIDEO) {
+ if (vdec->vf_receiver_inst == 0) {
+ vdec_core->vdec_resouce_status &= ~BIT(FRAME_BASE_PATH_DI_V4LVIDEO_0);
+ } else if (vdec->vf_receiver_inst == 1) {
+ vdec_core->vdec_resouce_status &= ~BIT(FRAME_BASE_PATH_DI_V4LVIDEO_1);
+ } else if (vdec->vf_receiver_inst == 2) {
+ vdec_core->vdec_resouce_status &= ~BIT(FRAME_BASE_PATH_DI_V4LVIDEO_2);
+ }
+ }
+ vdec_core->vdec_resouce_status &= ~BIT(vdec->frame_base_video_path);
+ mutex_unlock(&vdec_mutex);
+
+ vdec_destroy(vdec);
+
+ mutex_lock(&vdec_mutex);
+ inited_vcodec_num--;
+ mutex_unlock(&vdec_mutex);
+}
+EXPORT_SYMBOL(vdec_release);
+
+/* For dual running decoders, vdec_reset is only called with master vdec.
+ */
+int vdec_reset(struct vdec_s *vdec)
+{
+ //trace_vdec_reset(vdec); /*DEBUG_TMP*/
+
+ vdec_disconnect(vdec);
+
+ if (vdec->vframe_provider.name)
+ vf_unreg_provider(&vdec->vframe_provider);
+
+ if ((vdec->slave) && (vdec->slave->vframe_provider.name))
+ vf_unreg_provider(&vdec->slave->vframe_provider);
+
+ if (vdec->reset) {
+ vdec->reset(vdec);
+ if (vdec->slave)
+ vdec->slave->reset(vdec->slave);
+ }
+ vdec->mc_loaded = 0;/*clear for reload firmware*/
+ vdec_input_release(&vdec->input);
+
+ vdec_input_init(&vdec->input, vdec);
+
+ vdec_input_prepare_bufs(&vdec->input, vdec->sys_info->width,
+ vdec->sys_info->height);
+
+ vf_reg_provider(&vdec->vframe_provider);
+ vf_notify_receiver(vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_START, vdec);
+
+ if (vdec->slave) {
+ vf_reg_provider(&vdec->slave->vframe_provider);
+ vf_notify_receiver(vdec->slave->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_START, vdec->slave);
+ vdec->slave->mc_loaded = 0;/*clear for reload firmware*/
+ }
+
+ vdec_connect(vdec);
+
+ return 0;
+}
+EXPORT_SYMBOL(vdec_reset);
+
+int vdec_v4l2_reset(struct vdec_s *vdec, int flag)
+{
+ //trace_vdec_reset(vdec); /*DEBUG_TMP*/
+ pr_debug("vdec_v4l2_reset %d\n", flag);
+ vdec_disconnect(vdec);
+ if (flag != 2) {
+ if (vdec->vframe_provider.name)
+ vf_unreg_provider(&vdec->vframe_provider);
+
+ if ((vdec->slave) && (vdec->slave->vframe_provider.name))
+ vf_unreg_provider(&vdec->slave->vframe_provider);
+
+ if (vdec->reset) {
+ vdec->reset(vdec);
+ if (vdec->slave)
+ vdec->slave->reset(vdec->slave);
+ }
+ vdec->mc_loaded = 0;/*clear for reload firmware*/
+
+ vdec_input_release(&vdec->input);
+
+ vdec_input_init(&vdec->input, vdec);
+
+ vdec_input_prepare_bufs(&vdec->input, vdec->sys_info->width,
+ vdec->sys_info->height);
+
+ vf_reg_provider(&vdec->vframe_provider);
+ vf_notify_receiver(vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_START, vdec);
+
+ if (vdec->slave) {
+ vf_reg_provider(&vdec->slave->vframe_provider);
+ vf_notify_receiver(vdec->slave->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_START, vdec->slave);
+ vdec->slave->mc_loaded = 0;/*clear for reload firmware*/
+ }
+ } else {
+ if (vdec->reset) {
+ vdec->reset(vdec);
+ if (vdec->slave)
+ vdec->slave->reset(vdec->slave);
+ }
+ }
+
+ vdec_connect(vdec);
+
+ vdec_frame_check_init(vdec);
+
+ return 0;
+}
+EXPORT_SYMBOL(vdec_v4l2_reset);
+
+
+void vdec_free_cmabuf(void)
+{
+ mutex_lock(&vdec_mutex);
+
+ /*if (inited_vcodec_num > 0) {
+ mutex_unlock(&vdec_mutex);
+ return;
+ }*/
+ mutex_unlock(&vdec_mutex);
+}
+
+void vdec_core_request(struct vdec_s *vdec, unsigned long mask)
+{
+ vdec->core_mask |= mask;
+
+ if (vdec->slave)
+ vdec->slave->core_mask |= mask;
+ if (vdec_core->parallel_dec == 1) {
+ if (mask & CORE_MASK_COMBINE)
+ vdec_core->vdec_combine_flag++;
+ }
+
+}
+EXPORT_SYMBOL(vdec_core_request);
+
+int vdec_core_release(struct vdec_s *vdec, unsigned long mask)
+{
+ vdec->core_mask &= ~mask;
+
+ if (vdec->slave)
+ vdec->slave->core_mask &= ~mask;
+ if (vdec_core->parallel_dec == 1) {
+ if (mask & CORE_MASK_COMBINE)
+ vdec_core->vdec_combine_flag--;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(vdec_core_release);
+
+bool vdec_core_with_input(unsigned long mask)
+{
+ enum vdec_type_e type;
+
+ for (type = VDEC_1; type < VDEC_MAX; type++) {
+ if ((mask & (1 << type)) && cores_with_input[type])
+ return true;
+ }
+
+ return false;
+}
+
+void vdec_core_finish_run(struct vdec_s *vdec, unsigned long mask)
+{
+ unsigned long i;
+ unsigned long t = mask;
+ mutex_lock(&vdec_mutex);
+ while (t) {
+ i = __ffs(t);
+ clear_bit(i, &vdec->active_mask);
+ t &= ~(1 << i);
+ }
+
+ if (vdec->active_mask == 0)
+ vdec_set_status(vdec, VDEC_STATUS_CONNECTED);
+
+ mutex_unlock(&vdec_mutex);
+}
+EXPORT_SYMBOL(vdec_core_finish_run);
+/*
+ * find what core resources are available for vdec
+ */
+static unsigned long vdec_schedule_mask(struct vdec_s *vdec,
+ unsigned long active_mask)
+{
+ unsigned long mask = vdec->core_mask &
+ ~CORE_MASK_COMBINE;
+
+ if (vdec->core_mask & CORE_MASK_COMBINE) {
+ /* combined cores must be granted together */
+ if ((mask & ~active_mask) == mask)
+ return mask;
+ else
+ return 0;
+ } else
+ return mask & ~vdec->sched_mask & ~active_mask;
+}
+
+/*
+ *Decoder callback
+ * Each decoder instance uses this callback to notify status change, e.g. when
+ * decoder finished using HW resource.
+ * a sample callback from decoder's driver is following:
+ *
+ * if (hw->vdec_cb) {
+ * vdec_set_next_status(vdec, VDEC_STATUS_CONNECTED);
+ * hw->vdec_cb(vdec, hw->vdec_cb_arg);
+ * }
+ */
+static void vdec_callback(struct vdec_s *vdec, void *data)
+{
+ struct vdec_core_s *core = (struct vdec_core_s *)data;
+
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ vdec_profile(vdec, VDEC_PROFILE_EVENT_CB);
+#endif
+
+ up(&core->sem);
+}
+
+static irqreturn_t vdec_isr(int irq, void *dev_id)
+{
+ struct vdec_isr_context_s *c =
+ (struct vdec_isr_context_s *)dev_id;
+ struct vdec_s *vdec = vdec_core->last_vdec;
+ irqreturn_t ret = IRQ_HANDLED;
+
+ if (vdec_core->parallel_dec == 1) {
+ if (irq == vdec_core->isr_context[VDEC_IRQ_0].irq)
+ vdec = vdec_core->active_hevc;
+ else if (irq == vdec_core->isr_context[VDEC_IRQ_1].irq)
+ vdec = vdec_core->active_vdec;
+ else
+ vdec = NULL;
+ }
+
+ if (c->dev_isr) {
+ ret = c->dev_isr(irq, c->dev_id);
+ goto isr_done;
+ }
+
+ if ((c != &vdec_core->isr_context[VDEC_IRQ_0]) &&
+ (c != &vdec_core->isr_context[VDEC_IRQ_1]) &&
+ (c != &vdec_core->isr_context[VDEC_IRQ_HEVC_BACK])) {
+#if 0
+ pr_warn("vdec interrupt w/o a valid receiver\n");
+#endif
+ goto isr_done;
+ }
+
+ if (!vdec) {
+#if 0
+ pr_warn("vdec interrupt w/o an active instance running. core = %p\n",
+ core);
+#endif
+ goto isr_done;
+ }
+
+ if (!vdec->irq_handler) {
+#if 0
+ pr_warn("vdec instance has no irq handle.\n");
+#endif
+ goto isr_done;
+ }
+
+ ret = vdec->irq_handler(vdec, c->index);
+isr_done:
+ if (vdec && ret == IRQ_WAKE_THREAD)
+ vdec->irq_cnt++;
+
+ return ret;
+}
+
+static irqreturn_t vdec_thread_isr(int irq, void *dev_id)
+{
+ struct vdec_isr_context_s *c =
+ (struct vdec_isr_context_s *)dev_id;
+ struct vdec_s *vdec = vdec_core->last_vdec;
+ irqreturn_t ret = IRQ_HANDLED;
+
+ if (vdec_core->parallel_dec == 1) {
+ if (irq == vdec_core->isr_context[VDEC_IRQ_0].irq)
+ vdec = vdec_core->active_hevc;
+ else if (irq == vdec_core->isr_context[VDEC_IRQ_1].irq)
+ vdec = vdec_core->active_vdec;
+ else
+ vdec = NULL;
+ }
+
+ if (c->dev_threaded_isr) {
+ ret = c->dev_threaded_isr(irq, c->dev_id);
+ goto thread_isr_done;
+ }
+ if (!vdec)
+ goto thread_isr_done;
+
+ if (!vdec->threaded_irq_handler)
+ goto thread_isr_done;
+ ret = vdec->threaded_irq_handler(vdec, c->index);
+thread_isr_done:
+ if (vdec)
+ vdec->irq_thread_cnt++;
+ return ret;
+}
+
+unsigned long vdec_ready_to_run(struct vdec_s *vdec, unsigned long mask)
+{
+ unsigned long ready_mask;
+ struct vdec_input_s *input = &vdec->input;
+
+ /* Wait the matching irq_thread finished */
+ if (vdec->irq_cnt > vdec->irq_thread_cnt)
+ return false;
+
+ if ((vdec->status != VDEC_STATUS_CONNECTED) &&
+ (vdec->status != VDEC_STATUS_ACTIVE))
+ return false;
+
+ if (!vdec->run_ready)
+ return false;
+
+ /* when crc32 error, block at error frame */
+ if (vdec->vfc.err_crc_block)
+ return false;
+
+ if ((vdec->slave || vdec->master) &&
+ (vdec->sched == 0))
+ return false;
+#ifdef VDEC_DEBUG_SUPPORT
+ inc_profi_count(mask, vdec->check_count);
+#endif
+ if (vdec_core_with_input(mask)) {
+
+ /* check frame based input underrun */
+ if (input && !input->eos && input_frame_based(input)
+ && (!vdec_input_next_chunk(input))) {
+#ifdef VDEC_DEBUG_SUPPORT
+ inc_profi_count(mask, vdec->input_underrun_count);
+#endif
+ return false;
+ }
+ /* check streaming prepare level threshold if not EOS */
+ if (input && input_stream_based(input) && !input->eos) {
+ u32 rp, wp, level;
+
+ rp = STBUF_READ(&vdec->vbuf, get_rp);
+ wp = STBUF_READ(&vdec->vbuf, get_wp);
+ if (wp < rp)
+ level = input->size + wp - rp;
+ else
+ level = wp - rp;
+
+ if ((level < input->prepare_level) &&
+ (pts_get_rec_num(PTS_TYPE_VIDEO,
+ vdec->input.total_rd_count) < 2)) {
+ vdec->need_more_data |= VDEC_NEED_MORE_DATA;
+#ifdef VDEC_DEBUG_SUPPORT
+ inc_profi_count(mask, vdec->input_underrun_count);
+ if (step_mode & 0x200) {
+ if ((step_mode & 0xff) == vdec->id) {
+ step_mode |= 0xff;
+ return mask;
+ }
+ }
+#endif
+ return false;
+ } else if (level > input->prepare_level)
+ vdec->need_more_data &= ~VDEC_NEED_MORE_DATA;
+ }
+ }
+
+ if (step_mode) {
+ if ((step_mode & 0xff) != vdec->id)
+ return 0;
+ step_mode |= 0xff; /*VDEC_DEBUG_SUPPORT*/
+ }
+
+ /*step_mode &= ~0xff; not work for id of 0, removed*/
+
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ vdec_profile(vdec, VDEC_PROFILE_EVENT_CHK_RUN_READY);
+#endif
+
+ ready_mask = vdec->run_ready(vdec, mask) & mask;
+#ifdef VDEC_DEBUG_SUPPORT
+ if (ready_mask != mask)
+ inc_profi_count(ready_mask ^ mask, vdec->not_run_ready_count);
+#endif
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ if (ready_mask)
+ vdec_profile(vdec, VDEC_PROFILE_EVENT_RUN_READY);
+#endif
+
+ return ready_mask;
+}
+
+/* bridge on/off vdec's interrupt processing to vdec core */
+static void vdec_route_interrupt(struct vdec_s *vdec, unsigned long mask,
+ bool enable)
+{
+ enum vdec_type_e type;
+
+ for (type = VDEC_1; type < VDEC_MAX; type++) {
+ if (mask & (1 << type)) {
+ struct vdec_isr_context_s *c =
+ &vdec_core->isr_context[cores_int[type]];
+ if (enable)
+ c->vdec = vdec;
+ else if (c->vdec == vdec)
+ c->vdec = NULL;
+ }
+ }
+}
+
+/*
+ * Set up secure protection for each decoder instance running.
+ * Note: The operation from REE side only resets memory access
+ * to a default policy and even a non_secure type will still be
+ * changed to secure type automatically when secure source is
+ * detected inside TEE.
+ * Perform need_more_data checking and set flag is decoder
+ * is not consuming data.
+ */
+void vdec_prepare_run(struct vdec_s *vdec, unsigned long mask)
+{
+ struct vdec_input_s *input = &vdec->input;
+ int secure = (vdec_secure(vdec)) ? DMC_DEV_TYPE_SECURE :
+ DMC_DEV_TYPE_NON_SECURE;
+
+ vdec_route_interrupt(vdec, mask, true);
+
+ if (!vdec_core_with_input(mask))
+ return;
+
+ if (vdec_stream_based(vdec) && !vdec_secure(vdec))
+ {
+ tee_config_device_secure(DMC_DEV_ID_PARSER, 0);
+ }
+ if (input->target == VDEC_INPUT_TARGET_VLD)
+ tee_config_device_secure(DMC_DEV_ID_VDEC, secure);
+ else if (input->target == VDEC_INPUT_TARGET_HEVC)
+ tee_config_device_secure(DMC_DEV_ID_HEVC, secure);
+
+ if (vdec_stream_based(vdec) &&
+ ((vdec->need_more_data & VDEC_NEED_MORE_DATA_RUN) &&
+ (vdec->need_more_data & VDEC_NEED_MORE_DATA_DIRTY) == 0)) {
+ vdec->need_more_data |= VDEC_NEED_MORE_DATA;
+ }
+
+ vdec->need_more_data |= VDEC_NEED_MORE_DATA_RUN;
+ vdec->need_more_data &= ~VDEC_NEED_MORE_DATA_DIRTY;
+}
+
+
+/* struct vdec_core_shread manages all decoder instance in active list. When
+ * a vdec is added into the active list, it can onlt be in two status:
+ * VDEC_STATUS_CONNECTED(the decoder does not own HW resource and ready to run)
+ * VDEC_STATUS_ACTIVE(the decoder owns HW resources and is running).
+ * Removing a decoder from active list is only performed within core thread.
+ * Adding a decoder into active list is performed from user thread.
+ */
+static int vdec_core_thread(void *data)
+{
+ struct vdec_core_s *core = (struct vdec_core_s *)data;
+ struct sched_param param = {.sched_priority = MAX_RT_PRIO/2};
+ unsigned long flags;
+ int i;
+
+ sched_setscheduler(current, SCHED_FIFO, ¶m);
+
+ allow_signal(SIGTERM);
+
+ while (down_interruptible(&core->sem) == 0) {
+ struct vdec_s *vdec, *tmp, *worker;
+ unsigned long sched_mask = 0;
+ LIST_HEAD(disconnecting_list);
+
+ if (kthread_should_stop())
+ break;
+ mutex_lock(&vdec_mutex);
+
+ if (core->parallel_dec == 1) {
+ for (i = VDEC_1; i < VDEC_MAX; i++) {
+ core->power_ref_mask =
+ core->power_ref_count[i] > 0 ?
+ (core->power_ref_mask | (1 << i)) :
+ (core->power_ref_mask & ~(1 << i));
+ }
+ }
+ /* clean up previous active vdec's input */
+ list_for_each_entry(vdec, &core->connected_vdec_list, list) {
+ unsigned long mask = vdec->sched_mask &
+ (vdec->active_mask ^ vdec->sched_mask);
+
+ vdec_route_interrupt(vdec, mask, false);
+
+#ifdef VDEC_DEBUG_SUPPORT
+ update_profi_clk_stop(vdec, mask, get_current_clk());
+#endif
+ /*
+ * If decoder released some core resources (mask), then
+ * check if these core resources are associated
+ * with any input side and do input clean up accordingly
+ */
+ if (vdec_core_with_input(mask)) {
+ struct vdec_input_s *input = &vdec->input;
+ while (!list_empty(
+ &input->vframe_chunk_list)) {
+ struct vframe_chunk_s *chunk =
+ vdec_input_next_chunk(input);
+ if (chunk && (chunk->flag &
+ VFRAME_CHUNK_FLAG_CONSUMED))
+ vdec_input_release_chunk(input,
+ chunk);
+ else
+ break;
+ }
+
+ vdec_save_input_context(vdec);
+ }
+
+ vdec->sched_mask &= ~mask;
+ core->sched_mask &= ~mask;
+ }
+ vdec_update_buff_status();
+ /*
+ *todo:
+ * this is the case when the decoder is in active mode and
+ * the system side wants to stop it. Currently we rely on
+ * the decoder instance to go back to VDEC_STATUS_CONNECTED
+ * from VDEC_STATUS_ACTIVE by its own. However, if for some
+ * reason the decoder can not exist by itself (dead decoding
+ * or whatever), then we may have to add another vdec API
+ * to kill the vdec and release its HW resource and make it
+ * become inactive again.
+ * if ((core->active_vdec) &&
+ * (core->active_vdec->status == VDEC_STATUS_DISCONNECTED)) {
+ * }
+ */
+
+ /* check disconnected decoders */
+ flags = vdec_core_lock(vdec_core);
+ list_for_each_entry_safe(vdec, tmp,
+ &core->connected_vdec_list, list) {
+ if ((vdec->status == VDEC_STATUS_CONNECTED) &&
+ (vdec->next_status == VDEC_STATUS_DISCONNECTED)) {
+ if (core->parallel_dec == 1) {
+ if (vdec_core->active_hevc == vdec)
+ vdec_core->active_hevc = NULL;
+ if (vdec_core->active_vdec == vdec)
+ vdec_core->active_vdec = NULL;
+ }
+ if (core->last_vdec == vdec)
+ core->last_vdec = NULL;
+ list_move(&vdec->list, &disconnecting_list);
+ }
+ }
+ vdec_core_unlock(vdec_core, flags);
+ mutex_unlock(&vdec_mutex);
+ /* elect next vdec to be scheduled */
+ vdec = core->last_vdec;
+ if (vdec) {
+ vdec = list_entry(vdec->list.next, struct vdec_s, list);
+ list_for_each_entry_from(vdec,
+ &core->connected_vdec_list, list) {
+ sched_mask = vdec_schedule_mask(vdec,
+ core->sched_mask);
+ if (!sched_mask)
+ continue;
+ sched_mask = vdec_ready_to_run(vdec,
+ sched_mask);
+ if (sched_mask)
+ break;
+ }
+
+ if (&vdec->list == &core->connected_vdec_list)
+ vdec = NULL;
+ }
+
+ if (!vdec) {
+ /* search from beginning */
+ list_for_each_entry(vdec,
+ &core->connected_vdec_list, list) {
+ sched_mask = vdec_schedule_mask(vdec,
+ core->sched_mask);
+ if (vdec == core->last_vdec) {
+ if (!sched_mask) {
+ vdec = NULL;
+ break;
+ }
+
+ sched_mask = vdec_ready_to_run(vdec,
+ sched_mask);
+
+ if (!sched_mask) {
+ vdec = NULL;
+ break;
+ }
+ break;
+ }
+
+ if (!sched_mask)
+ continue;
+
+ sched_mask = vdec_ready_to_run(vdec,
+ sched_mask);
+ if (sched_mask)
+ break;
+ }
+
+ if (&vdec->list == &core->connected_vdec_list)
+ vdec = NULL;
+ }
+
+ worker = vdec;
+
+ if (vdec) {
+ unsigned long mask = sched_mask;
+ unsigned long i;
+
+ /* setting active_mask should be atomic.
+ * it can be modified by decoder driver callbacks.
+ */
+ while (sched_mask) {
+ i = __ffs(sched_mask);
+ set_bit(i, &vdec->active_mask);
+ sched_mask &= ~(1 << i);
+ }
+
+ /* vdec's sched_mask is only set from core thread */
+ vdec->sched_mask |= mask;
+ if (core->last_vdec) {
+ if ((core->last_vdec != vdec) &&
+ (core->last_vdec->mc_type != vdec->mc_type))
+ vdec->mc_loaded = 0;/*clear for reload firmware*/
+ } else
+ vdec->mc_loaded = 0;
+ core->last_vdec = vdec;
+ if (debug & 2)
+ vdec->mc_loaded = 0;/*alway reload firmware*/
+ vdec_set_status(vdec, VDEC_STATUS_ACTIVE);
+
+ core->sched_mask |= mask;
+ if (core->parallel_dec == 1)
+ vdec_save_active_hw(vdec);
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ vdec_profile(vdec, VDEC_PROFILE_EVENT_RUN);
+#endif
+ vdec_prepare_run(vdec, mask);
+#ifdef VDEC_DEBUG_SUPPORT
+ inc_profi_count(mask, vdec->run_count);
+ update_profi_clk_run(vdec, mask, get_current_clk());
+#endif
+
+ vdec->run(vdec, mask, vdec_callback, core);
+
+
+ /* we have some cores scheduled, keep working until
+ * all vdecs are checked with no cores to schedule
+ */
+ if (core->parallel_dec == 1) {
+ if (vdec_core->vdec_combine_flag == 0)
+ up(&core->sem);
+ } else
+ up(&core->sem);
+ }
+
+ /* remove disconnected decoder from active list */
+ list_for_each_entry_safe(vdec, tmp, &disconnecting_list, list) {
+ list_del(&vdec->list);
+ vdec_set_status(vdec, VDEC_STATUS_DISCONNECTED);
+ /*core->last_vdec = NULL;*/
+ complete(&vdec->inactive_done);
+ }
+
+ /* if there is no new work scheduled and nothing
+ * is running, sleep 20ms
+ */
+ if (core->parallel_dec == 1) {
+ if (vdec_core->vdec_combine_flag == 0) {
+ if ((!worker) &&
+ ((core->sched_mask != core->power_ref_mask)) &&
+ (atomic_read(&vdec_core->vdec_nr) > 0) &&
+ ((core->buff_flag | core->stream_buff_flag) &
+ (core->sched_mask ^ core->power_ref_mask))) {
+ usleep_range(1000, 2000);
+ up(&core->sem);
+ }
+ } else {
+ if ((!worker) && (!core->sched_mask) &&
+ (atomic_read(&vdec_core->vdec_nr) > 0) &&
+ (core->buff_flag | core->stream_buff_flag)) {
+ usleep_range(1000, 2000);
+ up(&core->sem);
+ }
+ }
+ } else if ((!worker) && (!core->sched_mask) && (atomic_read(&vdec_core->vdec_nr) > 0)) {
+ usleep_range(1000, 2000);
+ up(&core->sem);
+ }
+
+ }
+
+ return 0;
+}
+
+#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
+void vdec_power_reset(void)
+{
+ /* enable vdec1 isolation */
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) | 0xc0);
+ /* power off vdec1 memories */
+ WRITE_VREG(DOS_MEM_PD_VDEC, 0xffffffffUL);
+ /* vdec1 power off */
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | 0xc);
+
+ if (has_vdec2()) {
+ /* enable vdec2 isolation */
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) | 0x300);
+ /* power off vdec2 memories */
+ WRITE_VREG(DOS_MEM_PD_VDEC2, 0xffffffffUL);
+ /* vdec2 power off */
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | 0x30);
+ }
+
+ if (has_hdec()) {
+ /* enable hcodec isolation */
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) | 0x30);
+ /* power off hcodec memories */
+ WRITE_VREG(DOS_MEM_PD_HCODEC, 0xffffffffUL);
+ /* hcodec power off */
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | 3);
+ }
+
+ if (has_hevc_vdec()) {
+ /* enable hevc isolation */
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) | 0xc00);
+ /* power off hevc memories */
+ WRITE_VREG(DOS_MEM_PD_HEVC, 0xffffffffUL);
+ /* hevc power off */
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | 0xc0);
+ }
+}
+EXPORT_SYMBOL(vdec_power_reset);
+
+void vdec_poweron(enum vdec_type_e core)
+{
+ if (core >= VDEC_MAX)
+ return;
+
+ mutex_lock(&vdec_mutex);
+
+ vdec_core->power_ref_count[core]++;
+ if (vdec_core->power_ref_count[core] > 1) {
+ mutex_unlock(&vdec_mutex);
+ return;
+ }
+
+ if (vdec_on(core)) {
+ mutex_unlock(&vdec_mutex);
+ return;
+ }
+
+ vdec_core->pm->power_on(vdec_core->cma_dev, core);
+
+ mutex_unlock(&vdec_mutex);
+}
+EXPORT_SYMBOL(vdec_poweron);
+
+void vdec_poweroff(enum vdec_type_e core)
+{
+ if (core >= VDEC_MAX)
+ return;
+
+ mutex_lock(&vdec_mutex);
+
+ vdec_core->power_ref_count[core]--;
+ if (vdec_core->power_ref_count[core] > 0) {
+ mutex_unlock(&vdec_mutex);
+ return;
+ }
+
+ vdec_core->pm->power_off(vdec_core->cma_dev, core);
+
+ mutex_unlock(&vdec_mutex);
+}
+EXPORT_SYMBOL(vdec_poweroff);
+
+bool vdec_on(enum vdec_type_e core)
+{
+ return vdec_core->pm->power_state(vdec_core->cma_dev, core);
+}
+EXPORT_SYMBOL(vdec_on);
+
+#elif 0 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6TVD */
+void vdec_poweron(enum vdec_type_e core)
+{
+ ulong flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ if (core == VDEC_1) {
+ /* vdec1 soft reset */
+ WRITE_VREG(DOS_SW_RESET0, 0xfffffffc);
+ WRITE_VREG(DOS_SW_RESET0, 0);
+ /* enable vdec1 clock */
+ vdec_clock_enable();
+ /* reset DOS top registers */
+ WRITE_VREG(DOS_VDEC_MCRCC_STALL_CTRL, 0);
+ } else if (core == VDEC_2) {
+ /* vdec2 soft reset */
+ WRITE_VREG(DOS_SW_RESET2, 0xffffffff);
+ WRITE_VREG(DOS_SW_RESET2, 0);
+ /* enable vdec2 clock */
+ vdec2_clock_enable();
+ /* reset DOS top registers */
+ WRITE_VREG(DOS_VDEC2_MCRCC_STALL_CTRL, 0);
+ } else if (core == VDEC_HCODEC) {
+ /* hcodec soft reset */
+ WRITE_VREG(DOS_SW_RESET1, 0xffffffff);
+ WRITE_VREG(DOS_SW_RESET1, 0);
+ /* enable hcodec clock */
+ hcodec_clock_enable();
+ }
+
+ spin_unlock_irqrestore(&lock, flags);
+}
+
+void vdec_poweroff(enum vdec_type_e core)
+{
+ ulong flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ if (core == VDEC_1) {
+ /* disable vdec1 clock */
+ vdec_clock_off();
+ } else if (core == VDEC_2) {
+ /* disable vdec2 clock */
+ vdec2_clock_off();
+ } else if (core == VDEC_HCODEC) {
+ /* disable hcodec clock */
+ hcodec_clock_off();
+ }
+
+ spin_unlock_irqrestore(&lock, flags);
+}
+
+bool vdec_on(enum vdec_type_e core)
+{
+ bool ret = false;
+
+ if (core == VDEC_1) {
+ if (READ_HHI_REG(HHI_VDEC_CLK_CNTL) & 0x100)
+ ret = true;
+ } else if (core == VDEC_2) {
+ if (READ_HHI_REG(HHI_VDEC2_CLK_CNTL) & 0x100)
+ ret = true;
+ } else if (core == VDEC_HCODEC) {
+ if (READ_HHI_REG(HHI_VDEC_CLK_CNTL) & 0x1000000)
+ ret = true;
+ }
+
+ return ret;
+}
+#endif
+
+int vdec_source_changed(int format, int width, int height, int fps)
+{
+ /* todo: add level routines for clock adjustment per chips */
+ int ret = -1;
+ static int on_setting;
+
+ if (on_setting > 0)
+ return ret;/*on changing clk,ignore this change*/
+
+ if (vdec_source_get(VDEC_1) == width * height * fps)
+ return ret;
+
+
+ on_setting = 1;
+ ret = vdec_source_changed_for_clk_set(format, width, height, fps);
+ pr_debug("vdec1 video changed to %d x %d %d fps clk->%dMHZ\n",
+ width, height, fps, vdec_clk_get(VDEC_1));
+ on_setting = 0;
+ return ret;
+
+}
+EXPORT_SYMBOL(vdec_source_changed);
+
+void vdec_reset_core(struct vdec_s *vdec)
+{
+ unsigned long flags;
+ unsigned int mask = 0;
+
+ mask = 1 << 13; /*bit13: DOS VDEC interface*/
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
+ mask = 1 << 21; /*bit21: DOS VDEC interface*/
+
+ spin_lock_irqsave(&vdec_spin_lock, flags);
+ codec_dmcbus_write(DMC_REQ_CTRL,
+ codec_dmcbus_read(DMC_REQ_CTRL) & ~mask);
+ spin_unlock_irqrestore(&vdec_spin_lock, flags);
+
+ if (is_cpu_tm2_revb() ||
+ (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2)) {
+ while (!(codec_dmcbus_read(TM2_REVB_DMC_CHAN_STS)
+ & mask))
+ ;
+ } else {
+ while (!(codec_dmcbus_read(DMC_CHAN_STS)
+ & mask))
+ ;
+ }
+ /*
+ * 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
+ */
+ WRITE_VREG(DOS_SW_RESET0, (1<<3)|(1<<4)|(1<<5)|(1<<7)|(1<<8)|(1<<9));
+ WRITE_VREG(DOS_SW_RESET0, 0);
+
+ spin_lock_irqsave(&vdec_spin_lock, flags);
+ codec_dmcbus_write(DMC_REQ_CTRL,
+ codec_dmcbus_read(DMC_REQ_CTRL) | mask);
+ spin_unlock_irqrestore(&vdec_spin_lock, flags);
+}
+EXPORT_SYMBOL(vdec_reset_core);
+
+void hevc_mmu_dma_check(struct vdec_s *vdec)
+{
+ ulong timeout;
+ u32 data;
+ if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_G12A)
+ return;
+ timeout = jiffies + HZ/100;
+ while (1) {
+ data = READ_VREG(HEVC_CM_CORE_STATUS);
+ if ((data & 0x1) == 0)
+ break;
+ if (time_after(jiffies, timeout)) {
+ if (debug & 0x10)
+ pr_info(" %s sao mmu dma idle\n", __func__);
+ break;
+ }
+ }
+ /*disable sao mmu dma */
+ CLEAR_VREG_MASK(HEVC_SAO_MMU_DMA_CTRL, 1 << 0);
+ timeout = jiffies + HZ/100;
+ while (1) {
+ data = READ_VREG(HEVC_SAO_MMU_DMA_STATUS);
+ if ((data & 0x1))
+ break;
+ if (time_after(jiffies, timeout)) {
+ if (debug & 0x10)
+ pr_err("%s sao mmu dma timeout, num_buf_used = 0x%x\n",
+ __func__, (READ_VREG(HEVC_SAO_MMU_STATUS) >> 16));
+ break;
+ }
+ }
+}
+EXPORT_SYMBOL(hevc_mmu_dma_check);
+
+void hevc_reset_core(struct vdec_s *vdec)
+{
+ unsigned long flags;
+ unsigned int mask = 0;
+ int cpu_type;
+
+ mask = 1 << 4; /*bit4: hevc*/
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
+ mask |= 1 << 8; /*bit8: hevcb*/
+
+ WRITE_VREG(HEVC_STREAM_CONTROL, 0);
+ spin_lock_irqsave(&vdec_spin_lock, flags);
+ codec_dmcbus_write(DMC_REQ_CTRL,
+ codec_dmcbus_read(DMC_REQ_CTRL) & ~mask);
+ spin_unlock_irqrestore(&vdec_spin_lock, flags);
+
+ if (is_cpu_tm2_revb() ||
+ (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2)) {
+ while (!(codec_dmcbus_read(TM2_REVB_DMC_CHAN_STS)
+ & mask))
+ ;
+ } else {
+ while (!(codec_dmcbus_read(DMC_CHAN_STS)
+ & mask))
+ ;
+ }
+
+ if (vdec == NULL || input_frame_based(vdec))
+ WRITE_VREG(HEVC_STREAM_CONTROL, 0);
+
+
+ WRITE_VREG(HEVC_SAO_MMU_RESET_CTRL,
+ READ_VREG(HEVC_SAO_MMU_RESET_CTRL) | 1);
+
+ /*
+ * 2: assist
+ * 3: parser
+ * 4: parser_state
+ * 8: dblk
+ * 10:wrrsp lmem
+ * 11:mcpu
+ * 12:ccpu
+ * 13:ddr
+ * 14:iqit
+ * 15:ipp
+ * 17:qdct
+ * 18:mpred
+ * 19:sao
+ * 24:hevc_afifo
+ * 26:rst_mmu_n
+ */
+ if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2) &&
+ (vdec->format == VFORMAT_AVS2)) {
+ WRITE_VREG(DOS_SW_RESET3,
+ (1<<3)|(1<<4)|(1<<8)|(1<<11)|
+ (1<<12)|(1<<14)|(1<<15)|
+ (1<<17)|(1<<18)|(1<<19));
+ } else {
+ WRITE_VREG(DOS_SW_RESET3,
+ (1<<3)|(1<<4)|(1<<8)|(1<<10)|(1<<11)|
+ (1<<12)|(1<<13)|(1<<14)|(1<<15)|
+ (1<<17)|(1<<18)|(1<<19)|(1<<24)|(1<<26));
+ }
+
+ WRITE_VREG(DOS_SW_RESET3, 0);
+ while (READ_VREG(HEVC_WRRSP_LMEM) & 0xfff)
+ ;
+ WRITE_VREG(HEVC_SAO_MMU_RESET_CTRL,
+ READ_VREG(HEVC_SAO_MMU_RESET_CTRL) & (~1));
+ cpu_type = get_cpu_major_id();
+ if (cpu_type == AM_MESON_CPU_MAJOR_ID_TL1 &&
+ is_meson_rev_b())
+ cpu_type = AM_MESON_CPU_MAJOR_ID_G12B;
+ switch (cpu_type) {
+ case AM_MESON_CPU_MAJOR_ID_G12B:
+ WRITE_RESET_REG((RESET7_REGISTER_LEVEL),
+ READ_RESET_REG(RESET7_REGISTER_LEVEL) & (~((1<<13)|(1<<14))));
+ WRITE_RESET_REG((RESET7_REGISTER_LEVEL),
+ READ_RESET_REG((RESET7_REGISTER_LEVEL)) | ((1<<13)|(1<<14)));
+ break;
+ case AM_MESON_CPU_MAJOR_ID_G12A:
+ case AM_MESON_CPU_MAJOR_ID_SM1:
+ case AM_MESON_CPU_MAJOR_ID_TL1:
+ case AM_MESON_CPU_MAJOR_ID_TM2:
+ WRITE_RESET_REG((RESET7_REGISTER_LEVEL),
+ READ_RESET_REG(RESET7_REGISTER_LEVEL) & (~((1<<13))));
+ WRITE_RESET_REG((RESET7_REGISTER_LEVEL),
+ READ_RESET_REG((RESET7_REGISTER_LEVEL)) | ((1<<13)));
+ break;
+ case AM_MESON_CPU_MAJOR_ID_SC2:
+ WRITE_RESET_REG(P_RESETCTRL_RESET5_LEVEL,
+ READ_RESET_REG(P_RESETCTRL_RESET5_LEVEL) & (~((1<<1)|(1<<12)|(1<<13))));
+ WRITE_RESET_REG(P_RESETCTRL_RESET5_LEVEL,
+ READ_RESET_REG(P_RESETCTRL_RESET5_LEVEL) | ((1<<1)|(1<<12)|(1<<13)));
+ break;
+ default:
+ break;
+ }
+
+
+ spin_lock_irqsave(&vdec_spin_lock, flags);
+ codec_dmcbus_write(DMC_REQ_CTRL,
+ codec_dmcbus_read(DMC_REQ_CTRL) | mask);
+ spin_unlock_irqrestore(&vdec_spin_lock, flags);
+
+}
+EXPORT_SYMBOL(hevc_reset_core);
+
+int vdec2_source_changed(int format, int width, int height, int fps)
+{
+ int ret = -1;
+ static int on_setting;
+
+ if (has_vdec2()) {
+ /* todo: add level routines for clock adjustment per chips */
+ if (on_setting != 0)
+ return ret;/*on changing clk,ignore this change*/
+
+ if (vdec_source_get(VDEC_2) == width * height * fps)
+ return ret;
+
+ on_setting = 1;
+ ret = vdec_source_changed_for_clk_set(format,
+ width, height, fps);
+ pr_debug("vdec2 video changed to %d x %d %d fps clk->%dMHZ\n",
+ width, height, fps, vdec_clk_get(VDEC_2));
+ on_setting = 0;
+ return ret;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(vdec2_source_changed);
+
+int hevc_source_changed(int format, int width, int height, int fps)
+{
+ /* todo: add level routines for clock adjustment per chips */
+ int ret = -1;
+ static int on_setting;
+
+ if (on_setting != 0)
+ return ret;/*on changing clk,ignore this change*/
+
+ if (vdec_source_get(VDEC_HEVC) == width * height * fps)
+ return ret;
+
+ on_setting = 1;
+ ret = vdec_source_changed_for_clk_set(format, width, height, fps);
+ pr_debug("hevc video changed to %d x %d %d fps clk->%dMHZ\n",
+ width, height, fps, vdec_clk_get(VDEC_HEVC));
+ on_setting = 0;
+
+ return ret;
+}
+EXPORT_SYMBOL(hevc_source_changed);
+
+static struct am_reg am_risc[] = {
+ {"MSP", 0x300},
+ {"MPSR", 0x301},
+ {"MCPU_INT_BASE", 0x302},
+ {"MCPU_INTR_GRP", 0x303},
+ {"MCPU_INTR_MSK", 0x304},
+ {"MCPU_INTR_REQ", 0x305},
+ {"MPC-P", 0x306},
+ {"MPC-D", 0x307},
+ {"MPC_E", 0x308},
+ {"MPC_W", 0x309},
+ {"CSP", 0x320},
+ {"CPSR", 0x321},
+ {"CCPU_INT_BASE", 0x322},
+ {"CCPU_INTR_GRP", 0x323},
+ {"CCPU_INTR_MSK", 0x324},
+ {"CCPU_INTR_REQ", 0x325},
+ {"CPC-P", 0x326},
+ {"CPC-D", 0x327},
+ {"CPC_E", 0x328},
+ {"CPC_W", 0x329},
+ {"AV_SCRATCH_0", 0x09c0},
+ {"AV_SCRATCH_1", 0x09c1},
+ {"AV_SCRATCH_2", 0x09c2},
+ {"AV_SCRATCH_3", 0x09c3},
+ {"AV_SCRATCH_4", 0x09c4},
+ {"AV_SCRATCH_5", 0x09c5},
+ {"AV_SCRATCH_6", 0x09c6},
+ {"AV_SCRATCH_7", 0x09c7},
+ {"AV_SCRATCH_8", 0x09c8},
+ {"AV_SCRATCH_9", 0x09c9},
+ {"AV_SCRATCH_A", 0x09ca},
+ {"AV_SCRATCH_B", 0x09cb},
+ {"AV_SCRATCH_C", 0x09cc},
+ {"AV_SCRATCH_D", 0x09cd},
+ {"AV_SCRATCH_E", 0x09ce},
+ {"AV_SCRATCH_F", 0x09cf},
+ {"AV_SCRATCH_G", 0x09d0},
+ {"AV_SCRATCH_H", 0x09d1},
+ {"AV_SCRATCH_I", 0x09d2},
+ {"AV_SCRATCH_J", 0x09d3},
+ {"AV_SCRATCH_K", 0x09d4},
+ {"AV_SCRATCH_L", 0x09d5},
+ {"AV_SCRATCH_M", 0x09d6},
+ {"AV_SCRATCH_N", 0x09d7},
+};
+
+static ssize_t amrisc_regs_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ char *pbuf = buf;
+ struct am_reg *regs = am_risc;
+ int rsize = sizeof(am_risc) / sizeof(struct am_reg);
+ int i;
+ unsigned int val;
+ ssize_t ret;
+
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M8) {
+ mutex_lock(&vdec_mutex);
+ if (!vdec_on(VDEC_1)) {
+ mutex_unlock(&vdec_mutex);
+ pbuf += sprintf(pbuf, "amrisc is power off\n");
+ ret = pbuf - buf;
+ return ret;
+ }
+ } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M6) {
+ /*TODO:M6 define */
+ /*
+ * switch_mod_gate_by_type(MOD_VDEC, 1);
+ */
+ amports_switch_gate("vdec", 1);
+ }
+ pbuf += sprintf(pbuf, "amrisc registers show:\n");
+ for (i = 0; i < rsize; i++) {
+ val = READ_VREG(regs[i].offset);
+ pbuf += sprintf(pbuf, "%s(%#x)\t:%#x(%d)\n",
+ regs[i].name, regs[i].offset, val, val);
+ }
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M8)
+ mutex_unlock(&vdec_mutex);
+ else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M6) {
+ /*TODO:M6 define */
+ /*
+ * switch_mod_gate_by_type(MOD_VDEC, 0);
+ */
+ amports_switch_gate("vdec", 0);
+ }
+ ret = pbuf - buf;
+ return ret;
+}
+
+static ssize_t dump_trace_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ int i;
+ char *pbuf = buf;
+ ssize_t ret;
+ u16 *trace_buf = vzalloc(debug_trace_num * 2);
+
+ if (!trace_buf) {
+ pbuf += sprintf(pbuf, "No Memory bug\n");
+ ret = pbuf - buf;
+ return ret;
+ }
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M8) {
+ mutex_lock(&vdec_mutex);
+ if (!vdec_on(VDEC_1)) {
+ mutex_unlock(&vdec_mutex);
+ vfree(trace_buf);
+ pbuf += sprintf(pbuf, "amrisc is power off\n");
+ ret = pbuf - buf;
+ return ret;
+ }
+ } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M6) {
+ /*TODO:M6 define */
+ /*
+ * switch_mod_gate_by_type(MOD_VDEC, 1);
+ */
+ amports_switch_gate("vdec", 1);
+ }
+ pr_info("dump trace steps:%d start\n", debug_trace_num);
+ i = 0;
+ while (i <= debug_trace_num - 16) {
+ trace_buf[i] = READ_VREG(MPC_E);
+ trace_buf[i + 1] = READ_VREG(MPC_E);
+ trace_buf[i + 2] = READ_VREG(MPC_E);
+ trace_buf[i + 3] = READ_VREG(MPC_E);
+ trace_buf[i + 4] = READ_VREG(MPC_E);
+ trace_buf[i + 5] = READ_VREG(MPC_E);
+ trace_buf[i + 6] = READ_VREG(MPC_E);
+ trace_buf[i + 7] = READ_VREG(MPC_E);
+ trace_buf[i + 8] = READ_VREG(MPC_E);
+ trace_buf[i + 9] = READ_VREG(MPC_E);
+ trace_buf[i + 10] = READ_VREG(MPC_E);
+ trace_buf[i + 11] = READ_VREG(MPC_E);
+ trace_buf[i + 12] = READ_VREG(MPC_E);
+ trace_buf[i + 13] = READ_VREG(MPC_E);
+ trace_buf[i + 14] = READ_VREG(MPC_E);
+ trace_buf[i + 15] = READ_VREG(MPC_E);
+ i += 16;
+ };
+ pr_info("dump trace steps:%d finished\n", debug_trace_num);
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M8)
+ mutex_unlock(&vdec_mutex);
+ else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M6) {
+ /*TODO:M6 define */
+ /*
+ * switch_mod_gate_by_type(MOD_VDEC, 0);
+ */
+ amports_switch_gate("vdec", 0);
+ }
+ for (i = 0; i < debug_trace_num; i++) {
+ if (i % 4 == 0) {
+ if (i % 16 == 0)
+ pbuf += sprintf(pbuf, "\n");
+ else if (i % 8 == 0)
+ pbuf += sprintf(pbuf, " ");
+ else /* 4 */
+ pbuf += sprintf(pbuf, " ");
+ }
+ pbuf += sprintf(pbuf, "%04x:", trace_buf[i]);
+ }
+ while (i < debug_trace_num)
+ ;
+ vfree(trace_buf);
+ pbuf += sprintf(pbuf, "\n");
+ ret = pbuf - buf;
+ return ret;
+}
+
+static ssize_t clock_level_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ char *pbuf = buf;
+ size_t ret;
+
+ pbuf += sprintf(pbuf, "%dMHZ\n", vdec_clk_get(VDEC_1));
+
+ if (has_vdec2())
+ pbuf += sprintf(pbuf, "%dMHZ\n", vdec_clk_get(VDEC_2));
+
+ if (has_hevc_vdec())
+ pbuf += sprintf(pbuf, "%dMHZ\n", vdec_clk_get(VDEC_HEVC));
+
+ ret = pbuf - buf;
+ return ret;
+}
+
+static ssize_t enable_mvdec_info_show(struct class *cla,
+ struct class_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", enable_mvdec_info);
+}
+
+static ssize_t enable_mvdec_info_store(struct class *cla,
+ struct class_attribute *attr,
+ const char *buf, size_t count)
+{
+ int r;
+ int val;
+
+ r = kstrtoint(buf, 0, &val);
+ if (r < 0)
+ return -EINVAL;
+ enable_mvdec_info = val;
+
+ return count;
+}
+
+static ssize_t store_poweron_clock_level(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned int val;
+ ssize_t ret;
+
+ /*ret = sscanf(buf, "%d", &val);*/
+ ret = kstrtoint(buf, 0, &val);
+
+ if (ret != 0)
+ return -EINVAL;
+ poweron_clock_level = val;
+ return size;
+}
+
+static ssize_t show_poweron_clock_level(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", poweron_clock_level);
+}
+
+/*
+ *if keep_vdec_mem == 1
+ *always don't release
+ *vdec 64 memory for fast play.
+ */
+static ssize_t store_keep_vdec_mem(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned int val;
+ ssize_t ret;
+
+ /*ret = sscanf(buf, "%d", &val);*/
+ ret = kstrtoint(buf, 0, &val);
+ if (ret != 0)
+ return -EINVAL;
+ keep_vdec_mem = val;
+ return size;
+}
+
+static ssize_t show_keep_vdec_mem(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", keep_vdec_mem);
+}
+
+
+#ifdef VDEC_DEBUG_SUPPORT
+static ssize_t store_debug(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct vdec_s *vdec;
+ struct vdec_core_s *core = vdec_core;
+ unsigned long flags;
+
+ unsigned id;
+ unsigned val;
+ ssize_t ret;
+ char cbuf[32];
+
+ cbuf[0] = 0;
+ ret = sscanf(buf, "%s %x %x", cbuf, &id, &val);
+ /*pr_info(
+ "%s(%s)=>ret %ld: %s, %x, %x\n",
+ __func__, buf, ret, cbuf, id, val);*/
+ if (strcmp(cbuf, "schedule") == 0) {
+ pr_info("VDEC_DEBUG: force schedule\n");
+ up(&core->sem);
+ } else if (strcmp(cbuf, "power_off") == 0) {
+ pr_info("VDEC_DEBUG: power off core %d\n", id);
+ vdec_poweroff(id);
+ } else if (strcmp(cbuf, "power_on") == 0) {
+ pr_info("VDEC_DEBUG: power_on core %d\n", id);
+ vdec_poweron(id);
+ } else if (strcmp(cbuf, "wr") == 0) {
+ pr_info("VDEC_DEBUG: WRITE_VREG(0x%x, 0x%x)\n",
+ id, val);
+ WRITE_VREG(id, val);
+ } else if (strcmp(cbuf, "rd") == 0) {
+ pr_info("VDEC_DEBUG: READ_VREG(0x%x) = 0x%x\n",
+ id, READ_VREG(id));
+ } else if (strcmp(cbuf, "read_hevc_clk_reg") == 0) {
+ pr_info(
+ "VDEC_DEBUG: HHI_VDEC4_CLK_CNTL = 0x%x, HHI_VDEC2_CLK_CNTL = 0x%x\n",
+ READ_HHI_REG(HHI_VDEC4_CLK_CNTL),
+ READ_HHI_REG(HHI_VDEC2_CLK_CNTL));
+ }
+
+ flags = vdec_core_lock(vdec_core);
+
+ list_for_each_entry(vdec,
+ &core->connected_vdec_list, list) {
+ pr_info("vdec: status %d, id %d\n", vdec->status, vdec->id);
+ if (((vdec->status == VDEC_STATUS_CONNECTED
+ || vdec->status == VDEC_STATUS_ACTIVE)) &&
+ (vdec->id == id)) {
+ /*to add*/
+ break;
+ }
+ }
+ vdec_core_unlock(vdec_core, flags);
+ return size;
+}
+
+static ssize_t show_debug(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ char *pbuf = buf;
+ struct vdec_s *vdec;
+ struct vdec_core_s *core = vdec_core;
+ unsigned long flags = vdec_core_lock(vdec_core);
+ u64 tmp;
+
+ pbuf += sprintf(pbuf,
+ "============== help:\n");
+ pbuf += sprintf(pbuf,
+ "'echo xxx > debug' usuage:\n");
+ pbuf += sprintf(pbuf,
+ "schedule - trigger schedule thread to run\n");
+ pbuf += sprintf(pbuf,
+ "power_off core_num - call vdec_poweroff(core_num)\n");
+ pbuf += sprintf(pbuf,
+ "power_on core_num - call vdec_poweron(core_num)\n");
+ pbuf += sprintf(pbuf,
+ "wr adr val - call WRITE_VREG(adr, val)\n");
+ pbuf += sprintf(pbuf,
+ "rd adr - call READ_VREG(adr)\n");
+ pbuf += sprintf(pbuf,
+ "read_hevc_clk_reg - read HHI register for hevc clk\n");
+ pbuf += sprintf(pbuf,
+ "===================\n");
+
+ pbuf += sprintf(pbuf,
+ "name(core)\tschedule_count\trun_count\tinput_underrun\tdecbuf_not_ready\trun_time\n");
+ list_for_each_entry(vdec,
+ &core->connected_vdec_list, list) {
+ enum vdec_type_e type;
+ if ((vdec->status == VDEC_STATUS_CONNECTED
+ || vdec->status == VDEC_STATUS_ACTIVE)) {
+ for (type = VDEC_1; type < VDEC_MAX; type++) {
+ if (vdec->core_mask & (1 << type)) {
+ pbuf += sprintf(pbuf, "%s(%d):",
+ vdec->vf_provider_name, type);
+ pbuf += sprintf(pbuf, "\t%d",
+ vdec->check_count[type]);
+ pbuf += sprintf(pbuf, "\t%d",
+ vdec->run_count[type]);
+ pbuf += sprintf(pbuf, "\t%d",
+ vdec->input_underrun_count[type]);
+ pbuf += sprintf(pbuf, "\t%d",
+ vdec->not_run_ready_count[type]);
+ tmp = vdec->run_clk[type] * 100;
+ do_div(tmp, vdec->total_clk[type]);
+ pbuf += sprintf(pbuf,
+ "\t%d%%\n",
+ vdec->total_clk[type] == 0 ? 0 :
+ (u32)tmp);
+ }
+ }
+ }
+ }
+
+ vdec_core_unlock(vdec_core, flags);
+ return pbuf - buf;
+
+}
+#endif
+
+int show_stream_buffer_status(char *buf,
+ int (*callback) (struct stream_buf_s *, char *))
+{
+ char *pbuf = buf;
+ struct vdec_s *vdec;
+ struct vdec_core_s *core = vdec_core;
+ u64 flags = vdec_core_lock(vdec_core);
+
+ list_for_each_entry(vdec,
+ &core->connected_vdec_list, list) {
+ if ((vdec->status == VDEC_STATUS_CONNECTED
+ || vdec->status == VDEC_STATUS_ACTIVE)) {
+ if (vdec_frame_based(vdec))
+ continue;
+ pbuf += callback(&vdec->vbuf, pbuf);
+ }
+ }
+ vdec_core_unlock(vdec_core, flags);
+
+ return pbuf - buf;
+}
+EXPORT_SYMBOL(show_stream_buffer_status);
+
+static ssize_t store_vdec_vfm_path(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t count)
+{
+ char *buf_dup, *ps, *token;
+ char str[VDEC_MAP_NAME_SIZE] = "\0";
+ bool found = false;
+ int i;
+
+ if (strlen(buf) >= VDEC_MAP_NAME_SIZE) {
+ pr_info("parameter is overflow\n");
+ return -1;
+ }
+
+ buf_dup = kstrdup(buf, GFP_KERNEL);
+ ps = buf_dup;
+ while (1) {
+ token = strsep(&ps, "\n ");
+ if (token == NULL)
+ break;
+ if (*token == '\0')
+ continue;
+
+ for (i = 0; strcmp("reserved", vfm_path_node[i]) != 0; i++) {
+ if (!strncmp (vfm_path_node[i], token, strlen(vfm_path_node[i]))) {
+ break;
+ }
+ }
+
+ if (strcmp("reserved", vfm_path_node[i]) == 0 ||
+ strncmp("help", buf, strlen("help")) == 0) {
+ if (strncmp("help", buf, strlen("help")) != 0) {
+ pr_info("warnning! Input parameter is invalid. set failed!\n");
+ }
+ pr_info("\nusage for example: \n");
+ pr_info("echo help > /sys/class/vdec/vfm_path \n");
+ pr_info("echo disable > /sys/class/vdec/vfm_path \n");
+ pr_info("echo amlvideo ppmgr amvideo > /sys/class/vdec/vfm_path \n");
+ found = false;
+
+ break;
+ } else {
+ strcat(str, vfm_path_node[i]);
+ strcat(str, " ");
+ found = true;
+ }
+ }
+
+ if (found == true) {
+ memset(vfm_path, 0, sizeof(vfm_path));
+ strncpy(vfm_path, str, strlen(str));
+ vfm_path[VDEC_MAP_NAME_SIZE - 1] = '\0';
+ pr_info("cfg path success: decoder %s\n", vfm_path);
+ }
+ kfree(buf_dup);
+
+ return count;
+}
+
+static ssize_t show_vdec_vfm_path(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ int len = 0;
+ int i;
+ len += sprintf(buf + len, "cfg vfm path: decoder %s\n", vfm_path);
+ len += sprintf(buf + len, "\nvfm path node list: \n");
+ for (i = 0; strcmp("reserved", vfm_path_node[i]) != 0; i++) {
+ len += sprintf(buf + len, "\t%s \n", vfm_path_node[i]);
+ }
+
+ return len;
+}
+
+/*irq num as same as .dts*/
+/*
+ * interrupts = <0 3 1
+ * 0 23 1
+ * 0 32 1
+ * 0 43 1
+ * 0 44 1
+ * 0 45 1>;
+ * interrupt-names = "vsync",
+ * "demux",
+ * "parser",
+ * "mailbox_0",
+ * "mailbox_1",
+ * "mailbox_2";
+ */
+s32 vdec_request_threaded_irq(enum vdec_irq_num num,
+ irq_handler_t handler,
+ irq_handler_t thread_fn,
+ unsigned long irqflags,
+ const char *devname, void *dev)
+{
+ s32 res_irq;
+ s32 ret = 0;
+
+ if (num >= VDEC_IRQ_MAX) {
+ pr_err("[%s] request irq error, irq num too big!", __func__);
+ return -EINVAL;
+ }
+
+ if (vdec_core->isr_context[num].irq < 0) {
+ res_irq = platform_get_irq(
+ vdec_core->vdec_core_platform_device, num);
+ if (res_irq < 0) {
+ pr_err("[%s] get irq error!", __func__);
+ return -EINVAL;
+ }
+
+ vdec_core->isr_context[num].irq = res_irq;
+ vdec_core->isr_context[num].dev_isr = handler;
+ vdec_core->isr_context[num].dev_threaded_isr = thread_fn;
+ vdec_core->isr_context[num].dev_id = dev;
+
+ ret = request_threaded_irq(res_irq,
+ vdec_isr,
+ vdec_thread_isr,
+ (thread_fn) ? IRQF_ONESHOT : irqflags,
+ devname,
+ &vdec_core->isr_context[num]);
+
+ if (ret) {
+ vdec_core->isr_context[num].irq = -1;
+ vdec_core->isr_context[num].dev_isr = NULL;
+ vdec_core->isr_context[num].dev_threaded_isr = NULL;
+ vdec_core->isr_context[num].dev_id = NULL;
+
+ pr_err("vdec irq register error for %s.\n", devname);
+ return -EIO;
+ }
+ } else {
+ vdec_core->isr_context[num].dev_isr = handler;
+ vdec_core->isr_context[num].dev_threaded_isr = thread_fn;
+ vdec_core->isr_context[num].dev_id = dev;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(vdec_request_threaded_irq);
+
+s32 vdec_request_irq(enum vdec_irq_num num, irq_handler_t handler,
+ const char *devname, void *dev)
+{
+ pr_debug("vdec_request_irq %p, %s\n", handler, devname);
+
+ return vdec_request_threaded_irq(num,
+ handler,
+ NULL,/*no thread_fn*/
+ IRQF_SHARED,
+ devname,
+ dev);
+}
+EXPORT_SYMBOL(vdec_request_irq);
+
+void vdec_free_irq(enum vdec_irq_num num, void *dev)
+{
+ if (num >= VDEC_IRQ_MAX) {
+ pr_err("[%s] request irq error, irq num too big!", __func__);
+ return;
+ }
+ /*
+ *assume amrisc is stopped already and there is no mailbox interrupt
+ * when we reset pointers here.
+ */
+ vdec_core->isr_context[num].dev_isr = NULL;
+ vdec_core->isr_context[num].dev_threaded_isr = NULL;
+ vdec_core->isr_context[num].dev_id = NULL;
+ synchronize_irq(vdec_core->isr_context[num].irq);
+}
+EXPORT_SYMBOL(vdec_free_irq);
+
+struct vdec_s *vdec_get_default_vdec_for_userdata(void)
+{
+ struct vdec_s *vdec;
+ struct vdec_s *ret_vdec;
+ struct vdec_core_s *core = vdec_core;
+ unsigned long flags;
+ int id;
+
+ flags = vdec_core_lock(vdec_core);
+
+ id = 0x10000000;
+ ret_vdec = NULL;
+ if (!list_empty(&core->connected_vdec_list)) {
+ list_for_each_entry(vdec, &core->connected_vdec_list, list) {
+ if (vdec->id < id) {
+ id = vdec->id;
+ ret_vdec = vdec;
+ }
+ }
+ }
+
+ vdec_core_unlock(vdec_core, flags);
+
+ return ret_vdec;
+}
+EXPORT_SYMBOL(vdec_get_default_vdec_for_userdata);
+
+struct vdec_s *vdec_get_vdec_by_video_id(int video_id)
+{
+ struct vdec_s *vdec;
+ struct vdec_s *ret_vdec;
+ struct vdec_core_s *core = vdec_core;
+ unsigned long flags;
+
+ flags = vdec_core_lock(vdec_core);
+
+ ret_vdec = NULL;
+ if (!list_empty(&core->connected_vdec_list)) {
+ list_for_each_entry(vdec, &core->connected_vdec_list, list) {
+ if (vdec->video_id == video_id) {
+ ret_vdec = vdec;
+ break;
+ }
+ }
+ }
+
+ vdec_core_unlock(vdec_core, flags);
+
+ return ret_vdec;
+}
+EXPORT_SYMBOL(vdec_get_vdec_by_video_id);
+
+struct vdec_s *vdec_get_vdec_by_id(int vdec_id)
+{
+ struct vdec_s *vdec;
+ struct vdec_s *ret_vdec;
+ struct vdec_core_s *core = vdec_core;
+ unsigned long flags;
+
+ flags = vdec_core_lock(vdec_core);
+
+ ret_vdec = NULL;
+ if (!list_empty(&core->connected_vdec_list)) {
+ list_for_each_entry(vdec, &core->connected_vdec_list, list) {
+ if (vdec->id == vdec_id) {
+ ret_vdec = vdec;
+ break;
+ }
+ }
+ }
+
+ vdec_core_unlock(vdec_core, flags);
+
+ return ret_vdec;
+}
+EXPORT_SYMBOL(vdec_get_vdec_by_id);
+
+
+int vdec_read_user_data(struct vdec_s *vdec,
+ struct userdata_param_t *p_userdata_param)
+{
+ int ret = 0;
+
+ if (!vdec)
+ vdec = vdec_get_default_vdec_for_userdata();
+
+ if (vdec) {
+ if (vdec->user_data_read)
+ ret = vdec->user_data_read(vdec, p_userdata_param);
+ }
+ return ret;
+}
+EXPORT_SYMBOL(vdec_read_user_data);
+
+int vdec_wakeup_userdata_poll(struct vdec_s *vdec)
+{
+ if (vdec) {
+ if (vdec->wakeup_userdata_poll)
+ vdec->wakeup_userdata_poll(vdec);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(vdec_wakeup_userdata_poll);
+
+void vdec_reset_userdata_fifo(struct vdec_s *vdec, int bInit)
+{
+ if (!vdec)
+ vdec = vdec_get_default_vdec_for_userdata();
+
+ if (vdec) {
+ if (vdec->reset_userdata_fifo)
+ vdec->reset_userdata_fifo(vdec, bInit);
+ }
+}
+EXPORT_SYMBOL(vdec_reset_userdata_fifo);
+
+void vdec_set_profile_level(struct vdec_s *vdec, u32 profile_idc, u32 level_idc)
+{
+ if (vdec) {
+ vdec->profile_idc = profile_idc;
+ vdec->level_idc = level_idc;
+ }
+}
+EXPORT_SYMBOL(vdec_set_profile_level);
+
+#ifdef VDEC_FCC_SUPPORT
+int vdec_wakeup_fcc_poll(struct vdec_s *vdec)
+{
+ if (vdec) {
+ if (vdec->wakeup_fcc_poll)
+ vdec->wakeup_fcc_poll(vdec);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(vdec_wakeup_fcc_poll);
+
+int vdec_has_get_fcc_new_msg(struct vdec_s *vdec)
+{
+ int ret = 1;
+
+ if (vdec == NULL) {
+ pr_info("Error, invalid vdec instance!\n");
+ return 0;
+ }
+
+ if (input_stream_based(vdec)) {
+ if (vdec->fcc_mode == FCC_DISCARD_MODE &&
+ vdec->fcc_status == STATUS_BUTT) {
+ ret = 1;
+ vdec->fcc_status = AGAIN_STATUS;
+ } else if (vdec->fcc_mode == FCC_DEC_MODE &&
+ vdec->fcc_status != SWITCH_DONE_STATUS) {
+ ret = 1;
+
+ if (wait_event_interruptible_timeout(vdec->jump_back_wq, vdec->jump_back_done | vdec->jump_back_error,
+ HZ / 2) <= 0) {
+ pr_info("[%d][FCC]: Error! Wait jump back wp timeout 500ms!\n",
+ vdec->id);
+ vdec->fcc_status = SWITCH_DONE_STATUS;
+ } else {
+ if (fcc_debug_enable())
+ pr_info("[%d][FCC]: jump_back_done = %d\n",
+ vdec->id, vdec->jump_back_done);
+ if (vdec->jump_back_done) {
+ vdec->fcc_status = JUMP_BACK_STATUS;
+ vdec->jump_back_done = 0;
+ } else {
+ vdec->fcc_status = SWITCH_DONE_STATUS;
+ vdec->jump_back_error = 0;
+ }
+ }
+
+ if (fcc_debug_enable())
+ pr_info("[%d][FCC]: It is DEC mode now! fcc_status: %d\n",
+ vdec->id, vdec->fcc_status);
+ } else if (vdec->fcc_mode == FCC_DISCARD_MODE &&
+ !vdec->fcc_new_msg) {
+ if (vdec->fcc_status == WAIT_MSG_STATUS) {
+ if (fcc_debug_enable())
+ pr_info("[%d][FCC]: Wait msg!\n", vdec->id);
+ ret = 0;
+ } else {
+ if (fcc_debug_enable())
+ pr_info("[%d][FCC]: Continue to find header!\n", vdec->id);
+ ret = 1;
+ }
+ } else if (vdec->fcc_new_msg) {
+ if (fcc_debug_enable())
+ pr_info("[%d][FCC]: Got discard msg!\n", vdec->id);
+ ret = 1;
+ vdec->fcc_new_msg = 0;
+ if (vdec->fcc_mode == FCC_DISCARD_MODE) {
+ vdec->fcc_status = DISCARD_STATUS;
+ }
+ }
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(vdec_has_get_fcc_new_msg);
+void vdec_set_dmc_urgent(struct vdec_s *vdec, int urgentType)
+{
+#ifndef DMC_AXI4_G12_CHAN_CTRL
+#define DMC_AXI4_G12_CHAN_CTRL (0x90 << 2)
+#endif
+#define DMC_URGENT_TYPE_NORMAL 1
+#define DMC_URGENT_TYPE_URGENT 2
+#define DMC_URGENT_TYPE_SUPERURGENT 4
+
+ if (vdec) {
+ if (urgentType == DMC_URGENT_TYPE_NORMAL ||
+ urgentType == DMC_URGENT_TYPE_URGENT ||
+ urgentType == DMC_URGENT_TYPE_SUPERURGENT) {
+ int type;
+ unsigned int val;
+
+ type = vdec_get_hw_type(vdec->port->vformat);
+ if (type == CORE_MASK_HEVC) {
+ if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_G12A) {
+ val = READ_DMCREG(DMC_AXI4_CHAN_CTRL);
+ val &= (~(0x7 << 16));
+ val |= ((urgentType & 0x7) << 16);
+ WRITE_DMCREG(DMC_AXI4_CHAN_CTRL, val);
+ } else {
+ val = READ_DMCREG(DMC_AXI4_G12_CHAN_CTRL);
+ val &= (~(0x7 << 16));
+ val |= ((urgentType & 0x7) << 16);
+ WRITE_DMCREG(DMC_AXI4_G12_CHAN_CTRL, val);
+ }
+ }
+ }
+ }
+
+}
+EXPORT_SYMBOL(vdec_set_dmc_urgent);
+
+int fcc_debug_enable(void)
+{
+ return fcc_debug;
+}
+EXPORT_SYMBOL(fcc_debug_enable);
+
+static void vdec_fcc_jump_back(struct vdec_s *vdec)
+{
+ u32 cur_rp, set_rp;
+ struct vdec_input_s *input = &vdec->input;
+
+ if (fcc_debug_enable())
+ pr_info("[%d][FCC]: fcc_mode = %d fcc_status = %d\n",
+ vdec->id, vdec->fcc_mode, vdec->fcc_status);
+
+ if (input->target == VDEC_INPUT_TARGET_VLD) {
+ if (vdec->fcc_mode == FCC_DEC_MODE &&
+ vdec->fcc_status == JUMP_BACK_STATUS) {
+ set_rp = vdec->jump_back_rp;
+ cur_rp =READ_VREG(VLD_MEM_VIFIFO_RP);
+ input->stream_cookie = READ_VREG(VLD_MEM_VIFIFO_WRAP_COUNT);
+ if (cur_rp < set_rp) {
+ if (fcc_debug_enable())
+ pr_info("[%d][FCC]: Packet is wrapped! VLD_MEM_VIFIFO_WRAP_COUNT = %d\n",
+ vdec->id, input->stream_cookie);
+ input->stream_cookie = (input->stream_cookie - 1) < 0 ?
+ 0 : input->stream_cookie - 1;
+ }
+
+ WRITE_VREG(VLD_MEM_VIFIFO_CURR_PTR, set_rp);
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 1);
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 0);
+
+ WRITE_VREG(VLD_MEM_SWAP_ADDR,
+ input->swap_page_phys);
+ WRITE_VREG(VLD_MEM_SWAP_CTL, 3);
+ while (READ_VREG(VLD_MEM_SWAP_CTL) & (1<<7))
+ ;
+ WRITE_VREG(VLD_MEM_SWAP_CTL, 0);
+ vdec->fcc_status = SWITCH_DONE_STATUS;
+ if (fcc_debug_enable()) {
+ pr_info("[%d][FCC]:Current VLD_MEM_VIFIFO_WRAP_COUNT = %d cur_rp = %x set_rp = %x\n",
+ vdec->id, input->stream_cookie, cur_rp, set_rp);
+ }
+ }
+ } else if (input->target == VDEC_INPUT_TARGET_HEVC) {
+ if (vdec->fcc_mode == FCC_DEC_MODE &&
+ vdec->fcc_status == JUMP_BACK_STATUS) {
+ set_rp = vdec->jump_back_rp;
+ cur_rp = READ_VREG(HEVC_STREAM_RD_PTR);
+ if (cur_rp < set_rp) {
+ input->stream_cookie = input->stream_cookie + set_rp - cur_rp - vdec->input.size;
+ } else {
+ input->stream_cookie = input->stream_cookie - cur_rp + set_rp;
+ }
+
+ WRITE_VREG(HEVC_STREAM_RD_PTR, set_rp);
+ vdec->fcc_status = SWITCH_DONE_STATUS;
+
+ WRITE_VREG(HEVC_STREAM_SWAP_ADDR,
+ input->swap_page_phys);
+ WRITE_VREG(HEVC_STREAM_SWAP_CTRL, 3);
+
+ while (READ_VREG(HEVC_STREAM_SWAP_CTRL)
+ & (1<<7))
+ ;
+ WRITE_VREG(HEVC_STREAM_SWAP_CTRL, 0);
+ }
+ }
+
+ return;
+}
+#endif
+
+static int dump_mode;
+static ssize_t dump_risc_mem_store(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)/*set*/
+{
+ unsigned int val;
+ ssize_t ret;
+ char dump_mode_str[4] = "PRL";
+
+ /*ret = sscanf(buf, "%d", &val);*/
+ ret = kstrtoint(buf, 0, &val);
+
+ if (ret != 0)
+ return -EINVAL;
+ dump_mode = val & 0x3;
+ pr_info("set dump mode to %d,%c_mem\n",
+ dump_mode, dump_mode_str[dump_mode]);
+ return size;
+}
+static u32 read_amrisc_reg(int reg)
+{
+ WRITE_VREG(0x31b, reg);
+ return READ_VREG(0x31c);
+}
+
+static void dump_pmem(void)
+{
+ int i;
+
+ WRITE_VREG(0x301, 0x8000);
+ WRITE_VREG(0x31d, 0);
+ pr_info("start dump amrisc pmem of risc\n");
+ for (i = 0; i < 0xfff; i++) {
+ /*same as .o format*/
+ pr_info("%08x // 0x%04x:\n", read_amrisc_reg(i), i);
+ }
+}
+
+static void dump_lmem(void)
+{
+ int i;
+
+ WRITE_VREG(0x301, 0x8000);
+ WRITE_VREG(0x31d, 2);
+ pr_info("start dump amrisc lmem\n");
+ for (i = 0; i < 0x3ff; i++) {
+ /*same as */
+ pr_info("[%04x] = 0x%08x:\n", i, read_amrisc_reg(i));
+ }
+}
+
+static ssize_t dump_risc_mem_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ char *pbuf = buf;
+ int ret;
+
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M8) {
+ mutex_lock(&vdec_mutex);
+ if (!vdec_on(VDEC_1)) {
+ mutex_unlock(&vdec_mutex);
+ pbuf += sprintf(pbuf, "amrisc is power off\n");
+ ret = pbuf - buf;
+ return ret;
+ }
+ } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M6) {
+ /*TODO:M6 define */
+ /*
+ * switch_mod_gate_by_type(MOD_VDEC, 1);
+ */
+ amports_switch_gate("vdec", 1);
+ }
+ /*start do**/
+ switch (dump_mode) {
+ case 0:
+ dump_pmem();
+ break;
+ case 2:
+ dump_lmem();
+ break;
+ default:
+ break;
+ }
+
+ /*done*/
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M8)
+ mutex_unlock(&vdec_mutex);
+ else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M6) {
+ /*TODO:M6 define */
+ /*
+ * switch_mod_gate_by_type(MOD_VDEC, 0);
+ */
+ amports_switch_gate("vdec", 0);
+ }
+ return sprintf(buf, "done\n");
+}
+
+static ssize_t core_show(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ struct vdec_core_s *core = vdec_core;
+ char *pbuf = buf;
+ unsigned long flags = vdec_core_lock(vdec_core);
+
+ if (list_empty(&core->connected_vdec_list))
+ pbuf += sprintf(pbuf, "connected vdec list empty\n");
+ else {
+ struct vdec_s *vdec;
+
+ pbuf += sprintf(pbuf,
+ " Core: last_sched %p, sched_mask %lx\n",
+ core->last_vdec,
+ core->sched_mask);
+
+ list_for_each_entry(vdec, &core->connected_vdec_list, list) {
+ pbuf += sprintf(pbuf,
+ "\tvdec.%d (%p (%s)), status = %s,\ttype = %s, \tactive_mask = %lx\n",
+ vdec->id,
+ vdec,
+ vdec_device_name[vdec->format * 2],
+ vdec_status_str(vdec),
+ vdec_type_str(vdec),
+ vdec->active_mask);
+ }
+ }
+
+ vdec_core_unlock(vdec_core, flags);
+ return pbuf - buf;
+}
+
+static ssize_t vdec_status_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ char *pbuf = buf;
+ struct vdec_s *vdec;
+ struct vdec_info vs;
+ unsigned char vdec_num = 0;
+ struct vdec_core_s *core = vdec_core;
+ unsigned long flags = vdec_core_lock(vdec_core);
+
+ if (list_empty(&core->connected_vdec_list)) {
+ pbuf += sprintf(pbuf, "No vdec.\n");
+ goto out;
+ }
+
+ list_for_each_entry(vdec, &core->connected_vdec_list, list) {
+ if ((vdec->status == VDEC_STATUS_CONNECTED
+ || vdec->status == VDEC_STATUS_ACTIVE)) {
+ memset(&vs, 0, sizeof(vs));
+ if (vdec_status(vdec, &vs)) {
+ pbuf += sprintf(pbuf, "err.\n");
+ goto out;
+ }
+ pbuf += sprintf(pbuf,
+ "vdec channel %u statistics:\n",
+ vdec_num);
+ pbuf += sprintf(pbuf,
+ "%13s : %s\n", "device name",
+ vs.vdec_name);
+ pbuf += sprintf(pbuf,
+ "%13s : %u\n", "frame width",
+ vs.frame_width);
+ pbuf += sprintf(pbuf,
+ "%13s : %u\n", "frame height",
+ vs.frame_height);
+ pbuf += sprintf(pbuf,
+ "%13s : %u %s\n", "frame rate",
+ vs.frame_rate, "fps");
+ pbuf += sprintf(pbuf,
+ "%13s : %u %s\n", "bit rate",
+ vs.bit_rate / 1024 * 8, "kbps");
+ pbuf += sprintf(pbuf,
+ "%13s : %u\n", "status",
+ vs.status);
+ pbuf += sprintf(pbuf,
+ "%13s : %u\n", "frame dur",
+ vs.frame_dur);
+ pbuf += sprintf(pbuf,
+ "%13s : %u %s\n", "frame data",
+ vs.frame_data / 1024, "KB");
+ pbuf += sprintf(pbuf,
+ "%13s : %u\n", "frame count",
+ vs.frame_count);
+ pbuf += sprintf(pbuf,
+ "%13s : %u\n", "drop count",
+ vs.drop_frame_count);
+ pbuf += sprintf(pbuf,
+ "%13s : %u\n", "fra err count",
+ vs.error_frame_count);
+ pbuf += sprintf(pbuf,
+ "%13s : %u\n", "hw err count",
+ vs.error_count);
+ pbuf += sprintf(pbuf,
+ "%13s : %llu %s\n", "total data",
+ vs.total_data / 1024, "KB");
+ pbuf += sprintf(pbuf,
+ "%13s : %x\n\n", "ratio_control",
+ vs.ratio_control);
+
+ vdec_num++;
+ }
+ }
+out:
+ vdec_core_unlock(vdec_core, flags);
+ return pbuf - buf;
+}
+
+static ssize_t dump_vdec_blocks_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ struct vdec_core_s *core = vdec_core;
+ char *pbuf = buf;
+ unsigned long flags = vdec_core_lock(vdec_core);
+
+ if (list_empty(&core->connected_vdec_list))
+ pbuf += sprintf(pbuf, "connected vdec list empty\n");
+ else {
+ struct vdec_s *vdec;
+ list_for_each_entry(vdec, &core->connected_vdec_list, list) {
+ pbuf += vdec_input_dump_blocks(&vdec->input,
+ pbuf, PAGE_SIZE - (pbuf - buf));
+ }
+ }
+ vdec_core_unlock(vdec_core, flags);
+
+ return pbuf - buf;
+}
+static ssize_t dump_vdec_chunks_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ struct vdec_core_s *core = vdec_core;
+ char *pbuf = buf;
+ unsigned long flags = vdec_core_lock(vdec_core);
+
+ if (list_empty(&core->connected_vdec_list))
+ pbuf += sprintf(pbuf, "connected vdec list empty\n");
+ else {
+ struct vdec_s *vdec;
+ list_for_each_entry(vdec, &core->connected_vdec_list, list) {
+ pbuf += vdec_input_dump_chunks(vdec->id, &vdec->input,
+ pbuf, PAGE_SIZE - (pbuf - buf));
+ }
+ }
+ vdec_core_unlock(vdec_core, flags);
+
+ return pbuf - buf;
+}
+
+static ssize_t dump_decoder_state_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ char *pbuf = buf;
+ struct vdec_s *vdec;
+ struct vdec_core_s *core = vdec_core;
+ unsigned long flags = vdec_core_lock(vdec_core);
+
+ if (list_empty(&core->connected_vdec_list)) {
+ pbuf += sprintf(pbuf, "No vdec.\n");
+ } else {
+ list_for_each_entry(vdec,
+ &core->connected_vdec_list, list) {
+ if ((vdec->status == VDEC_STATUS_CONNECTED
+ || vdec->status == VDEC_STATUS_ACTIVE)
+ && vdec->dump_state)
+ vdec->dump_state(vdec);
+ }
+ }
+ vdec_core_unlock(vdec_core, flags);
+
+ return pbuf - buf;
+}
+
+static ssize_t dump_fps_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ char *pbuf = buf;
+ struct vdec_core_s *core = vdec_core;
+ int i;
+
+ unsigned long flags = vdec_fps_lock(vdec_core);
+ for (i = 0; i < MAX_INSTANCE_MUN; i++)
+ pbuf += sprintf(pbuf, "%d ", core->decode_fps[i].fps);
+
+ pbuf += sprintf(pbuf, "\n");
+ vdec_fps_unlock(vdec_core, flags);
+
+ return pbuf - buf;
+}
+
+static char * parser_h264_profile(char *pbuf, struct vdec_s *vdec)
+{
+ switch (vdec->profile_idc) {
+ case 66:
+ pbuf += sprintf(pbuf, "%d: Baseline Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ case 77:
+ pbuf += sprintf(pbuf, "%d: Main Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ case 88:
+ pbuf += sprintf(pbuf, "%d: Extended Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ case 100:
+ pbuf += sprintf(pbuf, "%d: High Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ case 110:
+ pbuf += sprintf(pbuf, "%d: High 10 Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ default:
+ pbuf += sprintf(pbuf, "%d: Not Support Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ }
+
+ return pbuf;
+}
+
+static char * parser_mpeg2_profile(char *pbuf, struct vdec_s *vdec)
+{
+ switch (vdec->profile_idc) {
+ case 5:
+ pbuf += sprintf(pbuf, "%d: Simple Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ case 4:
+ pbuf += sprintf(pbuf, "%d: Main Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ case 3:
+ pbuf += sprintf(pbuf, "%d: SNR Scalable Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ case 2:
+ pbuf += sprintf(pbuf, "%d: Airspace Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ case 1:
+ pbuf += sprintf(pbuf, "%d: High Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ default:
+ pbuf += sprintf(pbuf, "%d: Not Support Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ }
+ return pbuf;
+}
+
+static char * parser_mpeg4_profile(char *pbuf, struct vdec_s *vdec)
+{
+ switch (vdec->profile_idc) {
+ case 0:
+ pbuf += sprintf(pbuf, "%d: Simple Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ case 1:
+ pbuf += sprintf(pbuf, "%d: Simple Scalable Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ case 2:
+ pbuf += sprintf(pbuf, "%d: Core Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ case 3:
+ pbuf += sprintf(pbuf, "%d: Main Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ case 4:
+ pbuf += sprintf(pbuf, "%d: N-bit Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ case 5:
+ pbuf += sprintf(pbuf, "%d: Scalable Texture Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ case 6:
+ if (vdec->profile_idc == 1 || vdec->profile_idc == 2)
+ pbuf += sprintf(pbuf, "%d: Simple Face Animation Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ else
+ pbuf += sprintf(pbuf, "%d: Simple FBA Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ case 7:
+ pbuf += sprintf(pbuf, "%d: Basic Animated Texture Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ case 8:
+ pbuf += sprintf(pbuf, "%d: Hybrid Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ case 9:
+ pbuf += sprintf(pbuf, "%d: Advanced Real Time Simple Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ case 10:
+ pbuf += sprintf(pbuf, "%d: Core Scalable Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ case 11:
+ pbuf += sprintf(pbuf, "%d: Advanced Coding Efficiency Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ case 12:
+ pbuf += sprintf(pbuf, "%d: Advanced Core Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ case 13:
+ pbuf += sprintf(pbuf, "%d: Advanced Scalable Texture Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ case 14:
+ case 15:
+ pbuf += sprintf(pbuf, "%d: Advanced Simple Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ default:
+ pbuf += sprintf(pbuf, "%d: Not Support Profile(%u)\n",
+ vdec->id, vdec->profile_idc);
+ break;
+ }
+
+ return pbuf;
+}
+
+static ssize_t profile_idc_show(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ struct vdec_core_s *core = vdec_core;
+ char *pbuf = buf;
+ unsigned long flags = vdec_core_lock(vdec_core);
+
+ if (list_empty(&core->connected_vdec_list))
+ pbuf += sprintf(pbuf, "connected vdec list empty\n");
+ else {
+ struct vdec_s *vdec;
+ list_for_each_entry(vdec, &core->connected_vdec_list, list) {
+ if (vdec->format == 0) {
+ pbuf = parser_mpeg2_profile(pbuf, vdec);
+ } else if (vdec->format == 1) {
+ pbuf = parser_mpeg4_profile(pbuf, vdec);
+ } else if (vdec->format == 2) {
+ pbuf = parser_h264_profile(pbuf, vdec);
+ } else {
+ pbuf += sprintf(pbuf,
+ "%d: Not Support\n", vdec->id);
+ }
+ }
+ }
+
+ vdec_core_unlock(vdec_core, flags);
+ return pbuf - buf;
+}
+
+static char * parser_h264_level(char *pbuf, struct vdec_s *vdec)
+{
+
+ pbuf += sprintf(pbuf, "%d: Level %d.%d(%u)\n",
+ vdec->id, vdec->level_idc/10, vdec->level_idc%10, vdec->level_idc);
+
+ return pbuf;
+}
+
+static char * parser_mpeg2_level(char *pbuf, struct vdec_s *vdec)
+{
+ switch (vdec->level_idc) {
+ case 10:
+ pbuf += sprintf(pbuf, "%d: Low Level(%u)\n",
+ vdec->id, vdec->level_idc);
+ break;
+ case 8:
+ pbuf += sprintf(pbuf, "%d: Main Level(%u)\n",
+ vdec->id, vdec->level_idc);
+ break;
+ case 6:
+ pbuf += sprintf(pbuf, "%d: High 1440 Level(%u)\n",
+ vdec->id, vdec->level_idc);
+ break;
+ case 4:
+ pbuf += sprintf(pbuf, "%d: High Level(%u)\n",
+ vdec->id, vdec->level_idc);
+ break;
+ default:
+ pbuf += sprintf(pbuf, "%d: Not Support Level(%u)\n",
+ vdec->id, vdec->level_idc);
+ break;
+ }
+
+ return pbuf;
+}
+
+static char * parser_mpeg4_level(char *pbuf, struct vdec_s *vdec)
+{
+ switch (vdec->level_idc) {
+ case 1:
+ pbuf += sprintf(pbuf, "%d: Level 1(%u)\n",
+ vdec->id, vdec->level_idc);
+ break;
+ case 2:
+ pbuf += sprintf(pbuf, "%d: Level 2(%u)\n",
+ vdec->id, vdec->level_idc);
+ break;
+ case 3:
+ pbuf += sprintf(pbuf, "%d: Level 3(%u)\n",
+ vdec->id, vdec->level_idc);
+ break;
+ case 4:
+ pbuf += sprintf(pbuf, "%d: Level 4(%u)\n",
+ vdec->id, vdec->level_idc);
+ break;
+ case 5:
+ pbuf += sprintf(pbuf, "%d: Level 5(%u)\n",
+ vdec->id, vdec->level_idc);
+ break;
+ default:
+ pbuf += sprintf(pbuf, "%d: Not Support Level(%u)\n",
+ vdec->id, vdec->level_idc);
+ break;
+ }
+
+ return pbuf;
+}
+
+static ssize_t level_idc_show(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ struct vdec_core_s *core = vdec_core;
+ char *pbuf = buf;
+ unsigned long flags = vdec_core_lock(vdec_core);
+
+ if (list_empty(&core->connected_vdec_list))
+ pbuf += sprintf(pbuf, "connected vdec list empty\n");
+ else {
+ struct vdec_s *vdec;
+ list_for_each_entry(vdec, &core->connected_vdec_list, list) {
+ if (vdec->format == 0) {
+ pbuf = parser_mpeg2_level(pbuf, vdec);
+ } else if (vdec->format == 1) {
+ pbuf = parser_mpeg4_level(pbuf, vdec);
+ } else if (vdec->format == 2) {
+ pbuf = parser_h264_level(pbuf, vdec);
+ } else {
+ pbuf += sprintf(pbuf,
+ "%d: Not Support\n", vdec->id);
+ }
+ }
+ }
+
+ vdec_core_unlock(vdec_core, flags);
+ return pbuf - buf;
+}
+
+#ifdef VDEC_FCC_SUPPORT
+static ssize_t store_fcc_debug(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned int val;
+ ssize_t ret;
+
+ ret = kstrtoint(buf, 0, &val);
+ if (ret != 0)
+ return -EINVAL;
+ fcc_debug = val;
+ return size;
+}
+
+static ssize_t show_fcc_debug(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", fcc_debug);
+}
+#endif
+
+static struct class_attribute vdec_class_attrs[] = {
+ __ATTR_RO(amrisc_regs),
+ __ATTR_RO(dump_trace),
+ __ATTR_RO(clock_level),
+ __ATTR(enable_mvdec_info, S_IRUGO | S_IWUSR | S_IWGRP,
+ enable_mvdec_info_show, enable_mvdec_info_store),
+ __ATTR(poweron_clock_level, S_IRUGO | S_IWUSR | S_IWGRP,
+ show_poweron_clock_level, store_poweron_clock_level),
+ __ATTR(dump_risc_mem, S_IRUGO | S_IWUSR | S_IWGRP,
+ dump_risc_mem_show, dump_risc_mem_store),
+ __ATTR(keep_vdec_mem, S_IRUGO | S_IWUSR | S_IWGRP,
+ show_keep_vdec_mem, store_keep_vdec_mem),
+ __ATTR_RO(core),
+ __ATTR_RO(vdec_status),
+ __ATTR_RO(dump_vdec_blocks),
+ __ATTR_RO(dump_vdec_chunks),
+ __ATTR_RO(dump_decoder_state),
+#ifdef VDEC_DEBUG_SUPPORT
+ __ATTR(debug, S_IRUGO | S_IWUSR | S_IWGRP,
+ show_debug, store_debug),
+#endif
+#ifdef FRAME_CHECK
+ __ATTR(dump_yuv, S_IRUGO | S_IWUSR | S_IWGRP,
+ dump_yuv_show, dump_yuv_store),
+ __ATTR(frame_check, S_IRUGO | S_IWUSR | S_IWGRP,
+ frame_check_show, frame_check_store),
+#endif
+ __ATTR_RO(dump_fps),
+ __ATTR_RO(profile_idc),
+ __ATTR_RO(level_idc),
+ __ATTR(vfm_path, S_IRUGO | S_IWUSR | S_IWGRP,
+ show_vdec_vfm_path, store_vdec_vfm_path),
+#ifdef VDEC_FCC_SUPPORT
+ __ATTR(fcc_debug, S_IRUGO | S_IWUSR | S_IWGRP,
+ show_fcc_debug, store_fcc_debug),
+#endif
+ __ATTR_NULL
+};
+
+static struct class vdec_class = {
+ .name = "vdec",
+ .class_attrs = vdec_class_attrs,
+ };
+
+struct device *get_vdec_device(void)
+{
+ return &vdec_core->vdec_core_platform_device->dev;
+}
+EXPORT_SYMBOL(get_vdec_device);
+
+static int vdec_probe(struct platform_device *pdev)
+{
+ s32 i, r;
+
+ vdec_core = (struct vdec_core_s *)devm_kzalloc(&pdev->dev,
+ sizeof(struct vdec_core_s), GFP_KERNEL);
+ if (vdec_core == NULL) {
+ pr_err("vdec core allocation failed.\n");
+ return -ENOMEM;
+ }
+
+ atomic_set(&vdec_core->vdec_nr, 0);
+ sema_init(&vdec_core->sem, 1);
+
+ r = class_register(&vdec_class);
+ if (r) {
+ pr_info("vdec class create fail.\n");
+ return r;
+ }
+
+ vdec_core->vdec_core_platform_device = pdev;
+
+ platform_set_drvdata(pdev, vdec_core);
+
+ for (i = 0; i < VDEC_IRQ_MAX; i++) {
+ vdec_core->isr_context[i].index = i;
+ vdec_core->isr_context[i].irq = -1;
+ }
+
+ r = vdec_request_threaded_irq(VDEC_IRQ_0, NULL, NULL,
+ IRQF_ONESHOT, "vdec-0", NULL);
+ if (r < 0) {
+ pr_err("vdec interrupt request failed\n");
+ return r;
+ }
+
+ r = vdec_request_threaded_irq(VDEC_IRQ_1, NULL, NULL,
+ IRQF_ONESHOT, "vdec-1", NULL);
+ if (r < 0) {
+ pr_err("vdec interrupt request failed\n");
+ return r;
+ }
+#if 0
+ if (get_cpu_major_id() >= MESON_CPU_MAJOR_ID_G12A) {
+ r = vdec_request_threaded_irq(VDEC_IRQ_HEVC_BACK, NULL, NULL,
+ IRQF_ONESHOT, "vdec-hevc_back", NULL);
+ if (r < 0) {
+ pr_err("vdec interrupt request failed\n");
+ return r;
+ }
+ }
+#endif
+ r = of_reserved_mem_device_init(&pdev->dev);
+ if (r == 0)
+ pr_info("vdec_probe done\n");
+
+ vdec_core->cma_dev = &pdev->dev;
+
+ if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_M8) {
+ /* default to 250MHz */
+ vdec_clock_hi_enable();
+ }
+
+ if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_GXBB) {
+ /* set vdec dmc request to urgent */
+ WRITE_DMCREG(DMC_AM5_CHAN_CTRL, 0x3f203cf);
+ }
+ INIT_LIST_HEAD(&vdec_core->connected_vdec_list);
+ spin_lock_init(&vdec_core->lock);
+ spin_lock_init(&vdec_core->canvas_lock);
+ spin_lock_init(&vdec_core->fps_lock);
+ spin_lock_init(&vdec_core->input_lock);
+ ida_init(&vdec_core->ida);
+ vdec_core->thread = kthread_run(vdec_core_thread, vdec_core,
+ "vdec-core");
+
+ vdec_core->vdec_core_wq = alloc_ordered_workqueue("%s",__WQ_LEGACY |
+ WQ_MEM_RECLAIM |WQ_HIGHPRI/*high priority*/, "vdec-work");
+ /*work queue priority lower than vdec-core.*/
+
+ /* power manager init. */
+ vdec_core->pm = (struct power_manager_s *)
+ of_device_get_match_data(&pdev->dev);
+ if (vdec_core->pm->init) {
+ r = vdec_core->pm->init(&pdev->dev);
+ if (r) {
+ pr_err("vdec power manager init failed\n");
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+static int vdec_remove(struct platform_device *pdev)
+{
+ int i;
+
+ for (i = 0; i < VDEC_IRQ_MAX; i++) {
+ if (vdec_core->isr_context[i].irq >= 0) {
+ free_irq(vdec_core->isr_context[i].irq,
+ &vdec_core->isr_context[i]);
+ vdec_core->isr_context[i].irq = -1;
+ vdec_core->isr_context[i].dev_isr = NULL;
+ vdec_core->isr_context[i].dev_threaded_isr = NULL;
+ vdec_core->isr_context[i].dev_id = NULL;
+ }
+ }
+
+ kthread_stop(vdec_core->thread);
+
+ destroy_workqueue(vdec_core->vdec_core_wq);
+
+ if (vdec_core->pm->release)
+ vdec_core->pm->release(&pdev->dev);
+
+ class_unregister(&vdec_class);
+
+ return 0;
+}
+
+static struct mconfig vdec_configs[] = {
+ MC_PU32("debug_trace_num", &debug_trace_num),
+ MC_PI32("hevc_max_reset_count", &hevc_max_reset_count),
+ MC_PU32("clk_config", &clk_config),
+ MC_PI32("step_mode", &step_mode),
+ MC_PI32("poweron_clock_level", &poweron_clock_level),
+};
+static struct mconfig_node vdec_node;
+
+extern const struct of_device_id amlogic_vdec_matches[];
+
+static struct platform_driver vdec_driver = {
+ .probe = vdec_probe,
+ .remove = vdec_remove,
+ .driver = {
+ .name = "vdec",
+ .of_match_table = amlogic_vdec_matches,
+ }
+};
+
+static struct codec_profile_t amvdec_common_profile = {
+ .name = "vdec_common",
+ .profile = "vdec"
+};
+
+static struct codec_profile_t amvdec_input_profile = {
+ .name = "vdec_input",
+ .profile = "drm_framemode"
+};
+
+int vdec_module_init(void)
+{
+ if (platform_driver_register(&vdec_driver)) {
+ pr_info("failed to register vdec module\n");
+ return -ENODEV;
+ }
+ INIT_REG_NODE_CONFIGS("media.decoder", &vdec_node,
+ "vdec", vdec_configs, CONFIG_FOR_RW);
+ vcodec_profile_register(&amvdec_common_profile);
+
+ vcodec_profile_register(&amvdec_input_profile);
+ return 0;
+}
+EXPORT_SYMBOL(vdec_module_init);
+
+void vdec_module_exit(void)
+{
+ platform_driver_unregister(&vdec_driver);
+}
+EXPORT_SYMBOL(vdec_module_exit);
+
+#if 0
+static int __init vdec_module_init(void)
+{
+ if (platform_driver_register(&vdec_driver)) {
+ pr_info("failed to register vdec module\n");
+ return -ENODEV;
+ }
+ INIT_REG_NODE_CONFIGS("media.decoder", &vdec_node,
+ "vdec", vdec_configs, CONFIG_FOR_RW);
+ return 0;
+}
+
+static void __exit vdec_module_exit(void)
+{
+ platform_driver_unregister(&vdec_driver);
+}
+#endif
+
+static int vdec_mem_device_init(struct reserved_mem *rmem, struct device *dev)
+{
+ vdec_core->cma_dev = dev;
+
+ return 0;
+}
+
+static const struct reserved_mem_ops rmem_vdec_ops = {
+ .device_init = vdec_mem_device_init,
+};
+
+static int __init vdec_mem_setup(struct reserved_mem *rmem)
+{
+ rmem->ops = &rmem_vdec_ops;
+ pr_info("vdec: reserved mem setup\n");
+
+ return 0;
+}
+
+
+void vdec_set_vframe_comm(struct vdec_s *vdec, char *n)
+{
+ struct vdec_frames_s *mvfrm = vdec->mvfrm;
+
+ if (!mvfrm)
+ return;
+
+ mvfrm->comm.vdec_id = vdec->id;
+
+ snprintf(mvfrm->comm.vdec_name, sizeof(mvfrm->comm.vdec_name)-1,
+ "%s", n);
+ mvfrm->comm.vdec_type = vdec->type;
+}
+EXPORT_SYMBOL(vdec_set_vframe_comm);
+
+u32 diff_pts(u32 a, u32 b)
+{
+ if (!a || !b)
+ return 0;
+ else
+ return abs(a - b);
+}
+
+/*
+ * We only use the first 5 frames to calc duration.
+ * The fifo[0]~fifo[4] means the frame 0 to frame 4.
+ * we start to calculate the duration from frame 1.
+ * And the caller guarantees that slot > 0.
+ */
+static void cal_dur_from_pts(struct vdec_s *vdec, u32 slot)
+{
+#define DURATION_THRESHOD 10
+ static u32 must_send = 0, ready = 0;
+ u32 old = 0, cur, diff;
+ struct vframe_counter_s *fifo = vdec->mvfrm->fifo_buf;
+
+ if (vdec->mvfrm->wr == 1) {
+ ready = 0;
+ must_send = 0;
+ }
+
+ if (must_send == 2)
+ return ;
+
+ if (ready)
+ ++must_send;
+
+ if ((vdec->format != VFORMAT_H264 && vdec->format != VFORMAT_HEVC) ||
+ !fifo[slot].pts) {
+ if (fifo[slot].frame_dur != ready) {
+ if (must_send)
+ ready = (ready + fifo[slot].frame_dur) / 2;
+ else
+ ready = fifo[slot].frame_dur;
+ pr_debug("%s inner driver dur%u \n",__func__, ready);
+ }
+ goto end_handle;
+ }
+
+ if (slot == 1) {
+ cur = diff_pts(fifo[1].pts, fifo[0].pts);
+ } else {
+ old = diff_pts(fifo[slot - 1].pts, fifo[slot - 2].pts);
+ cur = diff_pts(fifo[slot].pts, fifo[slot - 1].pts);
+ }
+
+ diff = abs(cur - old);
+ if (diff > DURATION_THRESHOD) {
+ u32 dur, cur2;
+
+ cur2 = (cur << 4) / 15;
+ diff = abs(cur2 - fifo[slot].frame_dur);
+ if (fifo[slot].frame_dur == 3600)
+ dur = cur2;
+ else if (diff < DURATION_THRESHOD || diff > fifo[slot].frame_dur)
+ dur = fifo[slot].frame_dur;
+ else
+ dur = cur2;
+
+ if (ready == dur)
+ goto end_handle;
+
+ if (must_send)
+ ready = (ready + dur) / 2;
+ else
+ ready = dur;
+ pr_debug("%s vstatus %u dur%u -> %u, revised %u\n",__func__,fifo[slot].frame_dur, cur,cur2, dur);
+ if (diff > 10 && slot >= 2)
+ pr_debug("wr=%u,slot=%u pts %u, %u, %u\n",vdec->mvfrm->wr,slot,
+ fifo[slot].pts, fifo[slot-1].pts,fifo[slot-2].pts);
+ }
+
+end_handle:
+ if (must_send) {
+ ++must_send;
+ vframe_rate_uevent(ready);
+ }
+}
+
+void vdec_fill_vdec_frame(struct vdec_s *vdec, struct vframe_qos_s *vframe_qos,
+ struct vdec_info *vinfo,struct vframe_s *vf,
+ u32 hw_dec_time)
+{
+#define MINIMUM_FRAMES 5
+ u32 i;
+ struct vframe_counter_s *fifo_buf;
+ struct vdec_frames_s *mvfrm = vdec->mvfrm;
+
+ if (!mvfrm)
+ return;
+ fifo_buf = mvfrm->fifo_buf;
+
+ /* assume fps==60,mv->wr max value can support system running 828 days,
+ this is enough for us */
+ i = mvfrm->wr & (NUM_FRAME_VDEC-1); //find the slot num in fifo_buf
+ mvfrm->fifo_buf[i].decode_time_cost = hw_dec_time;
+ if (vframe_qos)
+ memcpy(&fifo_buf[i].qos, vframe_qos, sizeof(struct vframe_qos_s));
+ if (vinfo) {
+ memcpy(&fifo_buf[i].frame_width, &vinfo->frame_width,
+ ((char*)&vinfo->reserved[0] - (char*)&vinfo->frame_width));
+ /*copy for ipb report*/
+ memcpy(&fifo_buf[i].i_decoded_frames, &vinfo->i_decoded_frames,
+ ((char*)&vinfo->endipb_line[0] - (char*)&vinfo->i_decoded_frames));
+ fifo_buf[i].av_resynch_counter = timestamp_avsync_counter_get();
+ }
+ if (vf) {
+ fifo_buf[i].vf_type = vf->type;
+ fifo_buf[i].signal_type = vf->signal_type;
+ fifo_buf[i].pts = vf->pts;
+ fifo_buf[i].pts_us64 = vf->pts_us64;
+
+ /* Calculate the duration from pts */
+ if (mvfrm->wr < MINIMUM_FRAMES && mvfrm->wr > 0)
+ cal_dur_from_pts(vdec, i);
+ }
+ mvfrm->wr++;
+}
+EXPORT_SYMBOL(vdec_fill_vdec_frame);
+
+void vdec_vframe_ready(struct vdec_s *vdec, struct vframe_s *vf) {
+ if (vdec_secure(vdec)) {
+ vf->flag |= VFRAME_FLAG_VIDEO_SECURE;
+ } else {
+ vf->flag &= ~VFRAME_FLAG_VIDEO_SECURE;
+ }
+}
+EXPORT_SYMBOL(vdec_vframe_ready);
+
+/* In this function,if we use copy_to_user, we may encounter sleep,
+which may block the vdec_fill_vdec_frame,this is not acceptable.
+So, we should use a tmp buffer(passed by caller) to get the content */
+u32 vdec_get_frame_vdec(struct vdec_s *vdec, struct vframe_counter_s *tmpbuf)
+{
+ u32 toread = 0;
+ u32 slot_rd;
+ struct vframe_counter_s *fifo_buf = NULL;
+ struct vdec_frames_s *mvfrm = NULL;
+
+ /*
+ switch (version) {
+ case version_1:
+ f1();
+ case version_2:
+ f2();
+ default:
+ break;
+ }
+ */
+
+ if (!vdec)
+ return 0;
+ mvfrm = vdec->mvfrm;
+ if (!mvfrm)
+ return 0;
+
+ fifo_buf = &mvfrm->fifo_buf[0];
+
+ toread = mvfrm->wr - mvfrm->rd;
+ if (toread) {
+ if (toread >= NUM_FRAME_VDEC - QOS_FRAME_NUM) {
+ /* round the fifo_buf length happens, give QOS_FRAME_NUM for buffer */
+ mvfrm->rd = mvfrm->wr - (NUM_FRAME_VDEC - QOS_FRAME_NUM);
+ }
+
+ if (toread >= QOS_FRAME_NUM) {
+ toread = QOS_FRAME_NUM; //by default, we use this num
+ }
+
+ slot_rd = mvfrm->rd &( NUM_FRAME_VDEC-1); //In this case it equals to x%y
+ if (slot_rd + toread <= NUM_FRAME_VDEC) {
+ memcpy(tmpbuf, &fifo_buf[slot_rd], toread*sizeof(struct vframe_counter_s));
+ } else {
+ u32 exeed;
+ exeed = slot_rd + toread - NUM_FRAME_VDEC;
+ memcpy(tmpbuf, &fifo_buf[slot_rd], (NUM_FRAME_VDEC - slot_rd)*sizeof(struct vframe_counter_s));
+ memcpy(&tmpbuf[NUM_FRAME_VDEC-slot_rd], &fifo_buf[0], exeed*sizeof(struct vframe_counter_s));
+ }
+
+ mvfrm->rd += toread;
+ }
+ return toread;
+}
+EXPORT_SYMBOL(vdec_get_frame_vdec);
+
+void vdec_set_vld_wp(struct vdec_s *vdec, u32 wp)
+{
+ if (vdec_single(vdec)) {
+ WRITE_VREG(VLD_MEM_VIFIFO_WP, wp);
+ }
+}
+EXPORT_SYMBOL(vdec_set_vld_wp);
+
+void vdec_config_vld_reg(struct vdec_s *vdec, u32 addr, u32 size)
+{
+ if (vdec_single(vdec)) {
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 0);
+ /* reset VLD before setting all pointers */
+ WRITE_VREG(VLD_MEM_VIFIFO_WRAP_COUNT, 0);
+ /*TODO: only > m6*/
+ WRITE_VREG(DOS_SW_RESET0, (1 << 4));
+ WRITE_VREG(DOS_SW_RESET0, 0);
+
+
+ WRITE_VREG(POWER_CTL_VLD, 1 << 4);
+
+ WRITE_VREG(VLD_MEM_VIFIFO_START_PTR,
+ addr);
+ WRITE_VREG(VLD_MEM_VIFIFO_END_PTR,
+ addr + size - 8);
+ WRITE_VREG(VLD_MEM_VIFIFO_CURR_PTR,
+ addr);
+
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 1);
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 0);
+
+ /* set to manual mode */
+ WRITE_VREG(VLD_MEM_VIFIFO_BUF_CNTL, 2);
+ WRITE_VREG(VLD_MEM_VIFIFO_WP, addr);
+
+ WRITE_VREG(VLD_MEM_VIFIFO_BUF_CNTL, 3);
+ WRITE_VREG(VLD_MEM_VIFIFO_BUF_CNTL, 2);
+
+ /* enable */
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL,
+ (0x11 << 16) | (1<<10) | (1 << 1) | (1 << 2));
+ SET_VREG_MASK(VLD_MEM_VIFIFO_CONTROL,
+ 7 << 3);
+ }
+}
+EXPORT_SYMBOL(vdec_config_vld_reg);
+
+RESERVEDMEM_OF_DECLARE(vdec, "amlogic, vdec-memory", vdec_mem_setup);
+/*
+uint force_hevc_clock_cntl;
+EXPORT_SYMBOL(force_hevc_clock_cntl);
+
+module_param(force_hevc_clock_cntl, uint, 0664);
+*/
+module_param(debug, uint, 0664);
+module_param(debug_trace_num, uint, 0664);
+module_param(hevc_max_reset_count, int, 0664);
+module_param(clk_config, uint, 0664);
+module_param(step_mode, int, 0664);
+module_param(debugflags, int, 0664);
+module_param(parallel_decode, int, 0664);
+module_param(fps_detection, int, 0664);
+module_param(fps_clear, int, 0664);
+module_param(force_nosecure_even_drm, int, 0664);
+module_param(disable_switch_single_to_mult, int, 0664);
+
+module_param(frameinfo_flag, int, 0664);
+MODULE_PARM_DESC(frameinfo_flag,
+ "\n frameinfo_flag\n");
+module_param(v4lvideo_add_di, int, 0664);
+MODULE_PARM_DESC(v4lvideo_add_di,
+ "\n v4lvideo_add_di\n");
+
+module_param(max_di_instance, int, 0664);
+MODULE_PARM_DESC(max_di_instance,
+ "\n max_di_instance\n");
+
+module_param(max_supported_di_instance, int, 0664);
+MODULE_PARM_DESC(max_supported_di_instance,
+ "\n max_supported_di_instance\n");
+
+module_param(debug_vdetect, int, 0664);
+MODULE_PARM_DESC(debug_vdetect, "\n debug_vdetect\n");
+
+#ifdef VDEC_FCC_SUPPORT
+module_param(fcc_debug, int, 0664);
+MODULE_PARM_DESC(fcc_debug, "\n fcc_debug\n");
+#endif
+
+module_param(enable_stream_mode_multi_dec, int, 0664);
+EXPORT_SYMBOL(enable_stream_mode_multi_dec);
+MODULE_PARM_DESC(enable_stream_mode_multi_dec,
+ "\n enable multi-decoding on stream mode. \n");
+/*
+*module_init(vdec_module_init);
+*module_exit(vdec_module_exit);
+*/
+#define CREATE_TRACE_POINTS
+#include "vdec_trace.h"
+MODULE_DESCRIPTION("AMLOGIC vdec driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tim Yao <timyao@amlogic.com>");
diff --git a/drivers/frame_provider/decoder/utils/vdec.h b/drivers/frame_provider/decoder/utils/vdec.h
new file mode 100644
index 0000000..302bfad
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/vdec.h
@@ -0,0 +1,539 @@
+/*
+ * drivers/amlogic/media/frame_provider/decoder/utils/vdec.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_H
+#define VDEC_H
+#include <linux/amlogic/media/utils/amports_config.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/completion.h>
+#include <linux/irqreturn.h>
+
+#include <linux/amlogic/media/utils/amstream.h>
+#include <linux/amlogic/media/vfm/vframe.h>
+#include <linux/amlogic/media/vfm/vframe_provider.h>
+#include <linux/amlogic/media/vfm/vframe_receiver.h>
+#define KERNEL_ATRACE_TAG KERNEL_ATRACE_TAG_VDEC
+#include <trace/events/meson_atrace.h>
+/*#define CONFIG_AM_VDEC_DV*/
+#include "../../../stream_input/amports/streambuf.h"
+#include "../../../stream_input/amports/stream_buffer_base.h"
+
+#include "vdec_input.h"
+#include "frame_check.h"
+#include "vdec_sync.h"
+
+s32 vdec_dev_register(void);
+s32 vdec_dev_unregister(void);
+
+int vdec_source_changed(int format, int width, int height, int fps);
+int vdec2_source_changed(int format, int width, int height, int fps);
+int hevc_source_changed(int format, int width, int height, int fps);
+struct device *get_vdec_device(void);
+int vdec_module_init(void);
+void vdec_module_exit(void);
+
+#define MAX_INSTANCE_MUN 9
+
+#define VDEC_DEBUG_SUPPORT
+
+#define DEC_FLAG_HEVC_WORKAROUND 0x01
+
+#define VDEC_FIFO_ALIGN 8
+
+#define VDEC_FCC_SUPPORT
+
+enum vdec_type_e {
+ VDEC_1 = 0,
+ VDEC_HCODEC,
+ VDEC_2,
+ VDEC_HEVC,
+ VDEC_HEVCB,
+ VDEC_MAX
+};
+
+#define CORE_MASK_VDEC_1 (1 << VDEC_1)
+#define CORE_MASK_HCODEC (1 << VDEC_HCODEC)
+#define CORE_MASK_VDEC_2 (1 << VDEC_2)
+#define CORE_MASK_HEVC (1 << VDEC_HEVC)
+#define CORE_MASK_HEVC_FRONT (1 << VDEC_HEVC)
+#define CORE_MASK_HEVC_BACK (1 << VDEC_HEVCB)
+#define CORE_MASK_COMBINE (1UL << 31)
+
+extern void vdec2_power_mode(int level);
+extern void vdec_poweron(enum vdec_type_e core);
+extern void vdec_poweroff(enum vdec_type_e core);
+extern bool vdec_on(enum vdec_type_e core);
+extern void vdec_power_reset(void);
+extern void vdec_set_dmc_urgent(struct vdec_s *vdec, int urgentType);
+
+
+
+/*irq num as same as .dts*/
+
+/*
+ * interrupts = <0 3 1
+ * 0 23 1
+ * 0 32 1
+ * 0 43 1
+ * 0 44 1
+ * 0 45 1>;
+ * interrupt-names = "vsync",
+ * "demux",
+ * "parser",
+ * "mailbox_0",
+ * "mailbox_1",
+ * "mailbox_2";
+ */
+enum vdec_irq_num {
+ VSYNC_IRQ = 0,
+ DEMUX_IRQ,
+ PARSER_IRQ,
+ VDEC_IRQ_0,
+ VDEC_IRQ_1,
+ VDEC_IRQ_2,
+ VDEC_IRQ_HEVC_BACK,
+ VDEC_IRQ_MAX,
+};
+
+enum vdec_fr_hint_state {
+ VDEC_NO_NEED_HINT = 0,
+ VDEC_NEED_HINT,
+ VDEC_HINTED,
+};
+
+#ifdef VDEC_FCC_SUPPORT
+typedef enum {
+ DISCARD_STATUS = 1,
+ AGAIN_STATUS,
+ WAIT_MSG_STATUS,
+ SWITCHING_STATUS,
+ JUMP_BACK_STATUS,
+ SWITCH_DONE_STATUS,
+ STATUS_BUTT
+} FCC_STATUS;
+#endif
+
+extern s32 vdec_request_threaded_irq(enum vdec_irq_num num,
+ irq_handler_t handler,
+ irq_handler_t thread_fn,
+ unsigned long irqflags,
+ const char *devname, void *dev);
+extern s32 vdec_request_irq(enum vdec_irq_num num, irq_handler_t handler,
+ const char *devname, void *dev);
+extern void vdec_free_irq(enum vdec_irq_num num, void *dev);
+
+extern void dma_contiguous_early_fixup(phys_addr_t base, unsigned long size);
+unsigned int get_vdec_clk_config_settings(void);
+void update_vdec_clk_config_settings(unsigned int config);
+//unsigned int get_mmu_mode(void);//DEBUG_TMP
+//extern void vdec_fill_frame_info(struct vframe_qos_s *vframe_qos, int debug);
+extern void vdec_fill_vdec_frame(struct vdec_s *vdec,
+ struct vframe_qos_s *vframe_qos,
+ struct vdec_info *vinfo,
+ struct vframe_s *vf, u32 hw_dec_time);
+
+extern void vdec_vframe_ready(struct vdec_s *vdec, struct vframe_s *vf);
+extern void vdec_set_vframe_comm(struct vdec_s *vdec, char *n);
+
+
+struct vdec_s;
+enum vformat_t;
+
+/* stream based with single instance decoder driver */
+#define VDEC_TYPE_SINGLE 0
+
+/* stream based with multi-instance decoder with HW resouce sharing */
+#define VDEC_TYPE_STREAM_PARSER 1
+
+/* frame based with multi-instance decoder, input block list based */
+#define VDEC_TYPE_FRAME_BLOCK 2
+
+/* frame based with multi-instance decoder, single circular input block */
+#define VDEC_TYPE_FRAME_CIRCULAR 3
+
+/* decoder status: uninitialized */
+#define VDEC_STATUS_UNINITIALIZED 0
+
+/* decoder status: before the decoder can start consuming data */
+#define VDEC_STATUS_DISCONNECTED 1
+
+/* decoder status: decoder should become disconnected once it's not active */
+#define VDEC_STATUS_CONNECTED 2
+
+/* decoder status: decoder owns HW resource and is running */
+#define VDEC_STATUS_ACTIVE 3
+
+#define VDEC_PROVIDER_NAME_SIZE 16
+#define VDEC_RECEIVER_NAME_SIZE 16
+#define VDEC_MAP_NAME_SIZE 90
+
+#define VDEC_FLAG_OTHER_INPUT_CONTEXT 0x0
+#define VDEC_FLAG_SELF_INPUT_CONTEXT 0x01
+
+#define VDEC_NEED_MORE_DATA_RUN 0x01
+#define VDEC_NEED_MORE_DATA_DIRTY 0x02
+#define VDEC_NEED_MORE_DATA 0x04
+
+struct vdec_s {
+ u32 magic;
+ struct list_head list;
+ unsigned long core_mask;
+ unsigned long active_mask;
+ unsigned long sched_mask;
+ int id;
+
+ struct vdec_s *master;
+ struct vdec_s *slave;
+ struct stream_port_s *port;
+ struct stream_buf_s vbuf;
+ int status;
+ int next_status;
+ int type;
+ int port_flag;
+ int format;
+ u32 pts;
+ u64 pts64;
+ bool pts_valid;
+ u64 timestamp;
+ bool timestamp_valid;
+ int flag;
+ int sched;
+ int need_more_data;
+ u32 canvas_mode;
+
+ struct completion inactive_done;
+
+ /* config (temp) */
+ unsigned long mem_start;
+ unsigned long mem_end;
+
+ void *mm_blk_handle;
+
+ struct device *cma_dev;
+ struct platform_device *dev;
+ struct dec_sysinfo sys_info_store;
+ struct dec_sysinfo *sys_info;
+
+ /* input */
+ struct vdec_input_s input;
+
+ /*frame check*/
+ struct pic_check_mgr_t vfc;
+
+ /* mc cache */
+ u32 mc[4096 * 4];
+ bool mc_loaded;
+ u32 mc_type;
+ /* frame provider/receiver interface */
+ char vf_provider_name[VDEC_PROVIDER_NAME_SIZE];
+ struct vframe_provider_s vframe_provider;
+ char *vf_receiver_name;
+ char vfm_map_id[VDEC_MAP_NAME_SIZE];
+ char vfm_map_chain[VDEC_MAP_NAME_SIZE];
+ int vf_receiver_inst;
+ enum FRAME_BASE_VIDEO_PATH frame_base_video_path;
+ enum vdec_fr_hint_state fr_hint_state;
+ bool use_vfm_path;
+ char config[PAGE_SIZE];
+ int config_len;
+ bool is_reset;
+ bool dolby_meta_with_el;
+
+ /* canvas */
+ int (*get_canvas)(unsigned int index, unsigned int base);
+ int (*get_canvas_ex)(int type, int id);
+ void (*free_canvas_ex)(int index, int id);
+
+ int (*dec_status)(struct vdec_s *vdec, struct vdec_info *vstatus);
+ int (*set_trickmode)(struct vdec_s *vdec, unsigned long trickmode);
+ int (*set_isreset)(struct vdec_s *vdec, int isreset);
+ void (*vdec_fps_detec)(int id);
+
+ unsigned long (*run_ready)(struct vdec_s *vdec, unsigned long mask);
+ void (*run)(struct vdec_s *vdec, unsigned long mask,
+ void (*callback)(struct vdec_s *, void *), void *);
+ void (*reset)(struct vdec_s *vdec);
+ void (*dump_state)(struct vdec_s *vdec);
+ irqreturn_t (*irq_handler)(struct vdec_s *vdec, int irq);
+ irqreturn_t (*threaded_irq_handler)(struct vdec_s *vdec, int irq);
+
+ int (*user_data_read)(struct vdec_s *vdec,
+ struct userdata_param_t *puserdata_para);
+ void (*reset_userdata_fifo)(struct vdec_s *vdec, int bInit);
+ void (*wakeup_userdata_poll)(struct vdec_s *vdec);
+#ifdef VDEC_FCC_SUPPORT
+ void (*wakeup_fcc_poll)(struct vdec_s *vdec);
+#endif
+ /* private */
+ void *private; /* decoder per instance specific data */
+#ifdef VDEC_DEBUG_SUPPORT
+ u64 profile_start_clk[VDEC_MAX];
+ u64 total_clk[VDEC_MAX];
+ u32 check_count[VDEC_MAX];
+ u32 not_run_ready_count[VDEC_MAX];
+ u32 input_underrun_count[VDEC_MAX];
+ u32 run_count[VDEC_MAX];
+ u64 run_clk[VDEC_MAX];
+ u64 start_run_clk[VDEC_MAX];
+#endif
+ u64 irq_thread_cnt;
+ u64 irq_cnt;
+ int parallel_dec;
+ struct vdec_frames_s *mvfrm;
+ struct vdec_sync sync;
+
+ /*aux data check*/
+ struct aux_data_check_mgr_t adc;
+
+ u32 hdr10p_data_size;
+ char hdr10p_data_buf[PAGE_SIZE];
+ bool hdr10p_data_valid;
+ u32 profile_idc;
+ u32 level_idc;
+#ifdef VDEC_FCC_SUPPORT
+ enum fcc_mode_e fcc_mode;
+ u32 stream_offset;
+ int fcc_new_msg;
+ FCC_STATUS fcc_status;
+ wait_queue_head_t jump_back_wq;
+ struct mutex jump_back_mutex;
+ u32 jump_back_done;
+ u32 jump_back_error;
+ u32 jump_back_rp;
+#endif
+ u32 video_id;
+ char name[32];
+ char dec_spend_time[32];
+ char dec_spend_time_ave[32];
+ u32 discard_start_data_flag;
+};
+
+/* common decoder vframe provider name to use default vfm path */
+#define VFM_DEC_PROVIDER_NAME "decoder"
+#define VFM_DEC_DVBL_PROVIDER_NAME "dvbldec"
+#define VFM_DEC_DVEL_PROVIDER_NAME "dveldec"
+
+#define hw_to_vdec(hw) ((struct vdec_s *) \
+ (platform_get_drvdata(hw->platform_dev)))
+
+#define canvas_y(canvas) ((canvas) & 0xff)
+#define canvas_u(canvas) (((canvas) >> 8) & 0xff)
+#define canvas_v(canvas) (((canvas) >> 16) & 0xff)
+#define canvas_y2(canvas) (((canvas) >> 16) & 0xff)
+#define canvas_u2(canvas) (((canvas) >> 24) & 0xff)
+
+#define vdec_frame_based(vdec) \
+ (((vdec)->type == VDEC_TYPE_FRAME_BLOCK) || \
+ ((vdec)->type == VDEC_TYPE_FRAME_CIRCULAR))
+#define vdec_stream_based(vdec) \
+ (((vdec)->type == VDEC_TYPE_STREAM_PARSER) || \
+ ((vdec)->type == VDEC_TYPE_SINGLE))
+#define vdec_single(vdec) \
+ ((vdec)->type == VDEC_TYPE_SINGLE)
+#define vdec_dual(vdec) \
+ (((vdec)->port->type & PORT_TYPE_DUALDEC) ||\
+ (vdec_get_debug_flags() & 0x100))
+#define vdec_secure(vdec) \
+ (((vdec)->port_flag & PORT_FLAG_DRM))
+
+/* construct vdec strcture */
+extern struct vdec_s *vdec_create(struct stream_port_s *port,
+ struct vdec_s *master);
+
+/* set video format */
+extern int vdec_set_format(struct vdec_s *vdec, int format);
+
+/* set PTS */
+extern int vdec_set_pts(struct vdec_s *vdec, u32 pts);
+
+extern int vdec_set_pts64(struct vdec_s *vdec, u64 pts64);
+
+/* set vfm map when use frame base decoder */
+extern int vdec_set_video_path(struct vdec_s *vdec, int video_path);
+
+/* set receive id when receive is ionvideo or amlvideo */
+extern int vdec_set_receive_id(struct vdec_s *vdec, int receive_id);
+
+/* add frame data to input chain */
+extern int vdec_write_vframe(struct vdec_s *vdec, const char *buf,
+ size_t count);
+
+extern int vdec_write_vframe_with_dma(struct vdec_s *vdec,
+ ulong addr, size_t count, u32 handle, chunk_free free, void* priv);
+
+/* mark the vframe_chunk as consumed */
+extern void vdec_vframe_dirty(struct vdec_s *vdec,
+ struct vframe_chunk_s *chunk);
+
+/* prepare decoder input */
+extern int vdec_prepare_input(struct vdec_s *vdec, struct vframe_chunk_s **p);
+
+/* clean decoder input */
+extern void vdec_clean_input(struct vdec_s *vdec);
+
+/* sync decoder input */
+extern int vdec_sync_input(struct vdec_s *vdec);
+
+/* enable decoder input */
+extern void vdec_enable_input(struct vdec_s *vdec);
+
+/* set decoder input prepare level */
+extern void vdec_set_prepare_level(struct vdec_s *vdec, int level);
+
+/* set vdec input */
+extern int vdec_set_input_buffer(struct vdec_s *vdec, u32 start, u32 size);
+
+/* check if decoder can get more input */
+extern bool vdec_has_more_input(struct vdec_s *vdec);
+
+/* allocate input chain
+ * register vdec_device
+ * create output, vfm or create ionvideo output
+ * insert vdec to vdec_manager for scheduling
+ */
+extern int vdec_connect(struct vdec_s *vdec);
+
+/* remove vdec from vdec_manager scheduling
+ * release input chain
+ * disconnect video output from ionvideo
+ */
+extern int vdec_disconnect(struct vdec_s *vdec);
+
+/* release vdec structure */
+extern int vdec_destroy(struct vdec_s *vdec);
+
+/* reset vdec */
+extern int vdec_reset(struct vdec_s *vdec);
+
+extern int vdec_v4l2_reset(struct vdec_s *vdec, int flag);
+
+extern void vdec_set_status(struct vdec_s *vdec, int status);
+
+extern void vdec_set_next_status(struct vdec_s *vdec, int status);
+
+extern int vdec_set_decinfo(struct vdec_s *vdec, struct dec_sysinfo *p);
+
+extern int vdec_init(struct vdec_s *vdec, int is_4k);
+
+extern void vdec_release(struct vdec_s *vdec);
+
+extern int vdec_status(struct vdec_s *vdec, struct vdec_info *vstatus);
+
+extern int vdec_set_trickmode(struct vdec_s *vdec, unsigned long trickmode);
+
+extern int vdec_set_isreset(struct vdec_s *vdec, int isreset);
+
+extern int vdec_set_dv_metawithel(struct vdec_s *vdec, int isdvmetawithel);
+
+extern void vdec_set_no_powerdown(int flag);
+
+extern int vdec_is_support_4k(void);
+extern void vdec_set_flag(struct vdec_s *vdec, u32 flag);
+
+extern void vdec_set_eos(struct vdec_s *vdec, bool eos);
+
+extern void vdec_set_next_sched(struct vdec_s *vdec, struct vdec_s *next_vdec);
+
+extern const char *vdec_status_str(struct vdec_s *vdec);
+
+extern const char *vdec_type_str(struct vdec_s *vdec);
+
+extern const char *vdec_device_name_str(struct vdec_s *vdec);
+
+extern void vdec_schedule_work(struct work_struct *work);
+
+extern void vdec_count_info(struct vdec_info *vs, unsigned int err,
+ unsigned int offset);
+
+extern bool vdec_need_more_data(struct vdec_s *vdec);
+
+extern void vdec_reset_core(struct vdec_s *vdec);
+
+extern void hevc_reset_core(struct vdec_s *vdec);
+
+extern void vdec_set_suspend_clk(int mode, int hevc);
+
+extern unsigned long vdec_ready_to_run(struct vdec_s *vdec, unsigned long mask);
+
+extern void vdec_prepare_run(struct vdec_s *vdec, unsigned long mask);
+
+extern void vdec_core_request(struct vdec_s *vdec, unsigned long mask);
+
+extern int vdec_core_release(struct vdec_s *vdec, unsigned long mask);
+
+extern bool vdec_core_with_input(unsigned long mask);
+
+extern void vdec_core_finish_run(struct vdec_s *vdec, unsigned long mask);
+
+#ifdef VDEC_DEBUG_SUPPORT
+extern void vdec_set_step_mode(void);
+#endif
+extern void hevc_mmu_dma_check(struct vdec_s *vdec);
+int vdec_read_user_data(struct vdec_s *vdec,
+ struct userdata_param_t *p_userdata_param);
+
+int vdec_wakeup_userdata_poll(struct vdec_s *vdec);
+
+void vdec_reset_userdata_fifo(struct vdec_s *vdec, int bInit);
+
+struct vdec_s *vdec_get_vdec_by_video_id(int video_id);
+struct vdec_s *vdec_get_vdec_by_id(int vdec_id);
+
+
+#ifdef VDEC_FCC_SUPPORT
+int vdec_wakeup_fcc_poll(struct vdec_s *vdec);
+int vdec_has_get_fcc_new_msg(struct vdec_s *vdec);
+int fcc_debug_enable(void);
+#endif
+
+#ifdef VDEC_DEBUG_SUPPORT
+extern void vdec_set_step_mode(void);
+#endif
+int vdec_get_debug_flags(void);
+
+void VDEC_PRINT_FUN_LINENO(const char *fun, int line);
+
+
+unsigned char is_mult_inc(unsigned int);
+
+int vdec_get_status(struct vdec_s *vdec);
+
+void vdec_set_timestamp(struct vdec_s *vdec, u64 timestamp);
+
+extern u32 vdec_get_frame_vdec(struct vdec_s *vdec, struct vframe_counter_s *tmpbuf);
+
+int vdec_get_frame_num(struct vdec_s *vdec);
+
+int show_stream_buffer_status(char *buf,
+ int (*callback) (struct stream_buf_s *, char *));
+
+bool is_support_no_parser(void);
+
+extern u32 timestamp_avsync_counter_get(void);
+
+int vdec_resource_checking(struct vdec_s *vdec);
+
+
+void vdec_set_profile_level(struct vdec_s *vdec, u32 profile_idc, u32 level_idc);
+
+extern void vdec_stream_skip_data(struct vdec_s *vdec, int skip_size);
+void vdec_set_vld_wp(struct vdec_s *vdec, u32 wp);
+void vdec_config_vld_reg(struct vdec_s *vdec, u32 addr, u32 size);
+
+#endif /* VDEC_H */
diff --git a/drivers/frame_provider/decoder/utils/vdec_input.c b/drivers/frame_provider/decoder/utils/vdec_input.c
new file mode 100644
index 0000000..5deb374
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/vdec_input.c
@@ -0,0 +1,1216 @@
+/*
+ * drivers/amlogic/media/frame_provider/decoder/utils/vdec_input.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/uaccess.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+
+#include "../../../stream_input/amports/amports_priv.h"
+#include "vdec.h"
+#include "vdec_input.h"
+
+#include <asm/cacheflush.h>
+#include <linux/crc32.h>
+
+
+#define VFRAME_BLOCK_SIZE (512 * SZ_1K)/*512 for 1080p default init.*/
+#define VFRAME_BLOCK_SIZE_4K (2 * SZ_1M) /*2M for 4K default.*/
+#define VFRAME_BLOCK_SIZE_MAX (4 * SZ_1M)
+
+#define VFRAME_BLOCK_PAGEALIGN 4
+#define VFRAME_BLOCK_MIN_LEVEL (2 * SZ_1M)
+#define VFRAME_BLOCK_MAX_LEVEL (8 * SZ_1M)
+#define VFRAME_BLOCK_MAX_TOTAL_SIZE (16 * SZ_1M)
+
+/*
+2s for OMX
+*/
+#define MAX_FRAME_DURATION_S 2
+
+
+#define VFRAME_BLOCK_HOLE (SZ_64K)
+
+#define MIN_FRAME_PADDING_SIZE ((u32)(L1_CACHE_BYTES))
+
+#define EXTRA_PADDING_SIZE (16 * SZ_1K) /*HEVC_PADDING_SIZE*/
+
+#define MEM_NAME "VFRAME_INPUT"
+
+//static int vdec_input_get_duration_u64(struct vdec_input_s *input);
+static struct vframe_block_list_s *
+ vdec_input_alloc_new_block(struct vdec_input_s *input,
+ ulong phy_addr,
+ int size,
+ chunk_free free,
+ void* priv);
+
+static int aml_copy_from_user(void *to, const void *from, ulong n)
+{
+ int ret =0;
+
+ if (likely(access_ok(VERIFY_READ, from, n)))
+ ret = copy_from_user(to, from, n);
+ else
+ memcpy(to, from, n);
+
+ return ret;
+}
+
+static int copy_from_user_to_phyaddr(void *virts, const char __user *buf,
+ u32 size, ulong phys, u32 pading, bool is_mapped)
+{
+ u32 i, span = SZ_1M;
+ u32 count = size / PAGE_ALIGN(span);
+ u32 remain = size % PAGE_ALIGN(span);
+ ulong addr = phys;
+ u8 *p = virts;
+
+ if (is_mapped) {
+ if (aml_copy_from_user(p, buf, size))
+ return -EFAULT;
+
+ if (pading)
+ memset(p + size, 0, pading);
+
+ codec_mm_dma_flush(p, size + pading, DMA_TO_DEVICE);
+
+ return 0;
+ }
+
+ for (i = 0; i < count; i++) {
+ addr = phys + i * span;
+ p = codec_mm_vmap(addr, span);
+ if (!p)
+ return -1;
+
+ if (aml_copy_from_user(p, buf + i * span, span)) {
+ codec_mm_unmap_phyaddr(p);
+ return -EFAULT;
+ }
+
+ codec_mm_dma_flush(p, span, DMA_TO_DEVICE);
+ codec_mm_unmap_phyaddr(p);
+ }
+
+ if (!remain)
+ return 0;
+
+ span = size - remain;
+ addr = phys + span;
+ p = codec_mm_vmap(addr, remain + pading);
+ if (!p)
+ return -1;
+
+ if (aml_copy_from_user(p, buf + span, remain)) {
+ codec_mm_unmap_phyaddr(p);
+ return -EFAULT;
+ }
+
+ if (pading)
+ memset(p + remain, 0, pading);
+
+ codec_mm_dma_flush(p, remain + pading, DMA_TO_DEVICE);
+ codec_mm_unmap_phyaddr(p);
+
+ return 0;
+}
+
+static int vframe_chunk_fill(struct vdec_input_s *input,
+ struct vframe_chunk_s *chunk, const char *buf,
+ size_t count, struct vframe_block_list_s *block)
+{
+ u8 *p = (u8 *)block->start_virt + block->wp;
+ if (block->type == VDEC_TYPE_FRAME_BLOCK) {
+ copy_from_user_to_phyaddr(p, buf, count,
+ block->start + block->wp,
+ chunk->pading_size,
+ block->is_mapped);
+ } else if (block->type == VDEC_TYPE_FRAME_CIRCULAR) {
+ size_t len = min((size_t)(block->size - block->wp), count);
+ u32 wp;
+
+ copy_from_user_to_phyaddr(p, buf, len,
+ block->start + block->wp, 0,
+ block->is_mapped);
+ p += len;
+
+ if (count > len) {
+ copy_from_user_to_phyaddr(p, buf + len,
+ count - len,
+ block->start, 0,
+ block->is_mapped);
+
+ p += count - len;
+ }
+
+ wp = block->wp + count;
+ if (wp >= block->size)
+ wp -= block->size;
+
+ len = min(block->size - wp, chunk->pading_size);
+
+ if (!block->is_mapped) {
+ p = codec_mm_vmap(block->start + wp, len);
+ memset(p, 0, len);
+ codec_mm_dma_flush(p, len, DMA_TO_DEVICE);
+ codec_mm_unmap_phyaddr(p);
+ } else {
+ memset(p, 0, len);
+ codec_mm_dma_flush(p, len, DMA_TO_DEVICE);
+ }
+
+ if (chunk->pading_size > len) {
+ p = (u8 *)block->start_virt;
+
+ if (!block->is_mapped) {
+ p = codec_mm_vmap(block->start,
+ chunk->pading_size - len);
+ memset(p, 0, chunk->pading_size - len);
+ codec_mm_dma_flush(p,
+ chunk->pading_size - len,
+ DMA_TO_DEVICE);
+ codec_mm_unmap_phyaddr(p);
+ } else {
+ memset(p, 0, chunk->pading_size - len);
+ codec_mm_dma_flush(p,
+ chunk->pading_size - len,
+ DMA_TO_DEVICE);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static inline u32 vframe_block_space(struct vframe_block_list_s *block)
+{
+ if (block->type == VDEC_TYPE_FRAME_BLOCK) {
+ return block->size - block->wp;
+ } else {
+ return (block->rp >= block->wp) ?
+ (block->rp - block->wp) :
+ (block->rp - block->wp + block->size);
+ }
+}
+
+static void vframe_block_add_chunk(struct vframe_block_list_s *block,
+ struct vframe_chunk_s *chunk)
+{
+ block->wp += chunk->size + chunk->pading_size;
+ if (block->wp >= block->size)
+ block->wp -= block->size;
+ block->data_size += chunk->size;
+ block->chunk_count++;
+ chunk->block = block;
+ block->input->wr_block = block;
+ chunk->sequence = block->input->sequence;
+ block->input->sequence++;
+}
+
+static bool is_coherent_buff = 1;
+
+static void vframe_block_free_block(struct vframe_block_list_s *block)
+{
+ if (is_coherent_buff) {
+ if (block->mem_handle) {
+ codec_mm_dma_free_coherent(block->mem_handle);
+ }
+ } else {
+ if (block->addr) {
+ codec_mm_free_for_dma(MEM_NAME, block->addr);
+ }
+ }
+ /*
+ *pr_err("free block %d, size=%d\n", block->id, block->size);
+ */
+ kfree(block);
+}
+
+static int vframe_block_init_alloc_storage(struct vdec_input_s *input,
+ struct vframe_block_list_s *block,
+ ulong phy_addr,
+ int size,
+ chunk_free free,
+ void *priv)
+{
+ int alloc_size = input->default_block_size;
+ block->magic = 0x4b434c42;
+ block->input = input;
+ block->type = input->type;
+
+ /*
+ * todo: for different type use different size
+ */
+ if (phy_addr) {
+ block->is_out_buf = 1;
+ block->start_virt = NULL;
+ block->start = phy_addr;
+ block->size = size;
+ block->free = free;
+ block->priv = priv;
+ } else {
+ alloc_size = PAGE_ALIGN(alloc_size);
+ if (is_coherent_buff) {
+ block->start_virt = codec_mm_dma_alloc_coherent(&block->mem_handle, &block->addr, alloc_size, MEM_NAME);
+ } else {
+ block->addr = codec_mm_alloc_for_dma_ex(
+ MEM_NAME,
+ alloc_size/PAGE_SIZE,
+ VFRAME_BLOCK_PAGEALIGN,
+ CODEC_MM_FLAGS_DMA_CPU | CODEC_MM_FLAGS_FOR_VDECODER,
+ input->id,
+ block->id);
+ }
+
+ if (!block->addr) {
+ pr_err("Input block allocation failed\n");
+ return -ENOMEM;
+ }
+
+ if (!is_coherent_buff)
+ block->start_virt = (void *)codec_mm_phys_to_virt(block->addr);
+ if (block->start_virt)
+ block->is_mapped = true;
+ block->start = block->addr;
+ block->size = alloc_size;
+ block->is_out_buf = 0;
+ block->free = NULL;
+ }
+
+ return 0;
+}
+
+void vdec_input_init(struct vdec_input_s *input, struct vdec_s *vdec)
+{
+ INIT_LIST_HEAD(&input->vframe_block_list);
+ INIT_LIST_HEAD(&input->vframe_block_free_list);
+ INIT_LIST_HEAD(&input->vframe_chunk_list);
+ spin_lock_init(&input->lock);
+ input->id = vdec->id;
+ input->block_nums = 0;
+ input->vdec = vdec;
+ input->block_id_seq = 0;
+ input->size = 0;
+ input->default_block_size = VFRAME_BLOCK_SIZE;
+ snprintf(input->vdec_input_name, sizeof(input->vdec_input_name),
+ "vdec-input-%d", vdec->id);
+}
+int vdec_input_prepare_bufs(struct vdec_input_s *input,
+ int frame_width, int frame_height)
+{
+ struct vframe_block_list_s *block;
+ int i;
+ unsigned long flags;
+
+ if (vdec_secure(input->vdec))
+ return 0;
+ if (input->size > 0)
+ return 0;
+ if (frame_width * frame_height >= 1920 * 1088) {
+ /*have add data before. ignore prepare buffers.*/
+ input->default_block_size = VFRAME_BLOCK_SIZE_4K;
+ }
+ /*prepared 3 buffers for smooth start.*/
+ for (i = 0; i < 3; i++) {
+ block = vdec_input_alloc_new_block(input, 0, 0, NULL, NULL);
+ if (!block)
+ break;
+ flags = vdec_input_lock(input);
+ list_move_tail(&block->list,
+ &input->vframe_block_free_list);
+ input->wr_block = NULL;
+ vdec_input_unlock(input, flags);
+ }
+ return 0;
+}
+
+static int vdec_input_dump_block_locked(
+ struct vframe_block_list_s *block,
+ char *buf, int size)
+{
+ char *pbuf = buf;
+ char sbuf[512];
+ int tsize = 0;
+ int s;
+ if (!pbuf) {
+ pbuf = sbuf;
+ size = 512;
+ }
+ #define BUFPRINT(args...) \
+ do {\
+ s = snprintf(pbuf, size - tsize, args);\
+ tsize += s;\
+ pbuf += s; \
+ } while (0)
+
+ BUFPRINT("\tblock:[%d:%p]-addr=%p,vstart=%p,type=%d\n",
+ block->id,
+ block,
+ (void *)block->addr,
+ (void *)block->start_virt,
+ block->type);
+ BUFPRINT("\t-blocksize=%d,data=%d,wp=%d,rp=%d,chunk_count=%d\n",
+ block->size,
+ block->data_size,
+ block->wp,
+ block->rp,
+ block->chunk_count);
+ /*
+ BUFPRINT("\tlist=%p,next=%p,prev=%p\n",
+ &block->list,
+ block->list.next,
+ block->list.prev);
+ */
+ #undef BUFPRINT
+ if (!buf)
+ pr_info("%s", sbuf);
+ return tsize;
+}
+
+int vdec_input_dump_blocks(struct vdec_input_s *input,
+ char *bufs, int size)
+{
+ struct list_head *p, *tmp;
+ unsigned long flags;
+ char *lbuf = bufs;
+ char sbuf[256];
+ int s = 0;
+
+ if (size <= 0)
+ return 0;
+ if (!bufs)
+ lbuf = sbuf;
+ s += snprintf(lbuf + s, size - s,
+ "blocks:vdec-%d id:%d,bufsize=%d,dsize=%d,frames:%d,dur:%dms\n",
+ input->id,
+ input->block_nums,
+ input->size,
+ input->data_size,
+ input->have_frame_num,
+ vdec_input_get_duration_u64(input)/1000);
+ if (bufs)
+ lbuf += s;
+ else {
+ pr_info("%s", sbuf);
+ lbuf = NULL;
+ }
+
+ flags = vdec_input_lock(input);
+ /* dump input blocks */
+ list_for_each_safe(p, tmp, &input->vframe_block_list) {
+ struct vframe_block_list_s *block = list_entry(
+ p, struct vframe_block_list_s, list);
+ if (bufs != NULL) {
+ lbuf = bufs + s;
+ if (size - s < 128)
+ break;
+ }
+ s += vdec_input_dump_block_locked(block, lbuf, size - s);
+ }
+ list_for_each_safe(p, tmp, &input->vframe_block_free_list) {
+ struct vframe_block_list_s *block = list_entry(
+ p, struct vframe_block_list_s, list);
+ if (bufs != NULL) {
+ lbuf = bufs + s;
+ if (size - s < 128)
+ break;
+ }
+ s += vdec_input_dump_block_locked(block, lbuf, size - s);
+ }
+ vdec_input_unlock(input, flags);
+ return s;
+}
+
+static int vdec_input_dump_chunk_locked(
+ int id,
+ struct vframe_chunk_s *chunk,
+ char *buf, int size)
+{
+ char *pbuf = buf;
+ char sbuf[512];
+ int tsize = 0;
+ int s;
+ if (!pbuf) {
+ pbuf = sbuf;
+ size = 512;
+ }
+ #define BUFPRINT(args...) \
+ do {\
+ s = snprintf(pbuf, size - tsize, args);\
+ tsize += s;\
+ pbuf += s; \
+ } while (0)
+
+ BUFPRINT(
+ "\t[%d][%lld:%p]-off=%d,size:%d,p:%d,\tpts64=%lld,addr=%p\n",
+ id,
+ chunk->sequence,
+ chunk->block,
+ chunk->offset,
+ chunk->size,
+ chunk->pading_size,
+ chunk->pts64,
+ (void *)(chunk->block->addr + chunk->offset));
+ /*
+ BUFPRINT("\tlist=%p,next=%p,prev=%p\n",
+ &chunk->list,
+ chunk->list.next,
+ chunk->list.prev);
+ */
+ #undef BUFPRINT
+ if (!buf)
+ pr_info("%s", sbuf);
+ return tsize;
+}
+
+int vdec_input_dump_chunks(int id, struct vdec_input_s *input,
+ char *bufs, int size)
+{
+
+ struct list_head *p, *tmp;
+ unsigned long flags;
+ char *lbuf = bufs;
+ char sbuf[256];
+ int s = 0;
+ int i = 0;
+
+ if (size <= 0)
+ return 0;
+ if (!bufs)
+ lbuf = sbuf;
+ s = snprintf(lbuf + s, size - s,
+ "[%d]blocks:vdec-%d id:%d,bufsize=%d,dsize=%d,frames:%d,maxframe:%d\n",
+ id,
+ input->id,
+ input->block_nums,
+ input->size,
+ input->data_size,
+ input->have_frame_num,
+ input->frame_max_size);
+ if (bufs)
+ lbuf += s;
+ if (!bufs) {
+ pr_info("%s", sbuf);
+ lbuf = NULL;
+ }
+ flags = vdec_input_lock(input);
+ /*dump chunks list infos.*/
+ list_for_each_safe(p, tmp, &input->vframe_chunk_list) {
+ struct vframe_chunk_s *chunk = list_entry(
+ p, struct vframe_chunk_s, list);
+ if (bufs != NULL)
+ lbuf = bufs + s;
+ s += vdec_input_dump_chunk_locked(id, chunk, lbuf, size - s);
+ i++;
+ if (i >= 10)
+ break;
+ }
+ vdec_input_unlock(input, flags);
+ return s;
+}
+
+
+
+int vdec_input_set_buffer(struct vdec_input_s *input, u32 start, u32 size)
+{
+ if (input_frame_based(input))
+ return -EINVAL;
+
+ input->start = start;
+ input->size = size;
+ input->swap_rp = start;
+
+ if (vdec_secure(input->vdec))
+ input->swap_page_phys = codec_mm_alloc_for_dma("SWAP",
+ 1, 0, CODEC_MM_FLAGS_TVP);
+ else {
+ input->swap_page = codec_mm_dma_alloc_coherent(&input->mem_handle,
+ (ulong *)&input->swap_page_phys,
+ PAGE_SIZE, MEM_NAME);
+ if (input->swap_page == NULL)
+ return -ENOMEM;
+ }
+
+ if (input->swap_page_phys == 0)
+ return -ENOMEM;
+ return 0;
+}
+EXPORT_SYMBOL(vdec_input_set_buffer);
+
+void vdec_input_set_type(struct vdec_input_s *input, int type, int target)
+{
+ input->type = type;
+ input->target = target;
+ if (type == VDEC_TYPE_FRAME_CIRCULAR) {
+ /*alway used max block.*/
+ input->default_block_size = VFRAME_BLOCK_SIZE_MAX;
+ }
+}
+EXPORT_SYMBOL(vdec_input_set_type);
+
+int vdec_input_get_status(struct vdec_input_s *input,
+ struct vdec_input_status_s *status)
+{
+ unsigned long flags;
+
+ if (input->vdec == NULL)
+ return -EINVAL;
+
+ flags = vdec_input_lock(input);
+
+ if (list_empty(&input->vframe_block_list)) {
+ status->size = VFRAME_BLOCK_SIZE;
+ status->data_len = 0;
+ status->free_len = VFRAME_BLOCK_SIZE;
+ status->read_pointer = 0;
+ } else {
+ int r = VFRAME_BLOCK_MAX_LEVEL - vdec_input_level(input)
+ - VFRAME_BLOCK_HOLE;
+ status->size = input->size;
+ status->data_len = vdec_input_level(input);
+ status->free_len = (r > 0) ? r : 0;
+ status->read_pointer = input->total_rd_count;
+ }
+
+ vdec_input_unlock(input, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(vdec_input_get_status);
+
+static void vdec_input_add_block(struct vdec_input_s *input,
+ struct vframe_block_list_s *block)
+{
+ unsigned long flags;
+
+ flags = vdec_input_lock(input);
+ block->wp = 0;
+ block->id = input->block_id_seq++;
+ list_add_tail(&block->list, &input->vframe_block_list);
+ input->size += block->size;
+ input->block_nums++;
+ input->wr_block = block;
+ vdec_input_unlock(input, flags);
+}
+
+static inline void vdec_input_del_block_locked(struct vdec_input_s *input,
+ struct vframe_block_list_s *block)
+{
+ list_del(&block->list);
+ input->size -= block->size;
+ input->block_nums--;
+}
+
+int vdec_input_level(struct vdec_input_s *input)
+{
+ return input->total_wr_count - input->total_rd_count;
+}
+EXPORT_SYMBOL(vdec_input_level);
+
+static struct vframe_block_list_s *
+ vdec_input_alloc_new_block(struct vdec_input_s *input,
+ ulong phy_addr,
+ int size,
+ chunk_free free,
+ void* priv)
+{
+ struct vframe_block_list_s *block;
+ block = kzalloc(sizeof(struct vframe_block_list_s),
+ GFP_KERNEL);
+ if (block == NULL) {
+ input->no_mem_err_cnt++;
+ pr_err("vframe_block structure allocation failed\n");
+ return NULL;
+ }
+
+ if (vframe_block_init_alloc_storage(input,
+ block, phy_addr, size, free, priv) != 0) {
+ kfree(block);
+ pr_err("vframe_block storage allocation failed\n");
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&block->list);
+
+ vdec_input_add_block(input, block);
+
+ /*
+ *pr_info("vdec-%d:new block id=%d, total_blocks:%d, size=%d\n",
+ * input->id,
+ * block->id,
+ * input->block_nums,
+ * block->size);
+ */
+ if (0 && input->size > VFRAME_BLOCK_MAX_LEVEL * 2) {
+ /*
+ used
+ */
+ pr_info(
+ "input[%d] reach max: size:%d, blocks:%d",
+ input->id,
+ input->size,
+ input->block_nums);
+ pr_info("level:%d, wr:%lld,rd:%lld\n",
+ vdec_input_level(input),
+ input->total_wr_count,
+ input->total_rd_count);
+ vdec_input_dump_blocks(input, NULL, 0);
+ }
+ return block;
+}
+int vdec_input_get_duration_u64(struct vdec_input_s *input)
+{
+ int duration = (input->last_inpts_u64 - input->last_comsumed_pts_u64);
+ if (input->last_in_nopts_cnt > 0 &&
+ input->last_comsumed_pts_u64 > 0 &&
+ input->last_duration > 0) {
+ duration += (input->last_in_nopts_cnt -
+ input->last_comsumed_no_pts_cnt) *
+ input->last_duration;
+ }
+ if (duration > 1000 * 1000000)/*> 1000S,I think jumped.*/
+ duration = 0;
+ if (duration <= 0 && input->last_duration > 0) {
+ /*..*/
+ duration = input->last_duration * input->have_frame_num;
+ }
+ if (duration < 0)
+ duration = 0;
+ return duration;
+}
+EXPORT_SYMBOL(vdec_input_get_duration_u64);
+
+/*
+ ret >= 13: have enough buffer, blocked add more buffers
+*/
+static int vdec_input_have_blocks_enough(struct vdec_input_s *input)
+{
+ int ret = 0;
+ if (vdec_input_level(input) > VFRAME_BLOCK_MIN_LEVEL)
+ ret += 1;
+ if (vdec_input_level(input) >= VFRAME_BLOCK_MAX_LEVEL)
+ ret += 2;
+ if (vdec_input_get_duration_u64(input) > MAX_FRAME_DURATION_S)
+ ret += 4;
+ if (input->have_frame_num > 30)
+ ret += 8;
+ else
+ ret -= 8;/*not enough frames.*/
+ if (input->size >= VFRAME_BLOCK_MAX_TOTAL_SIZE)
+ ret += 100;/*always bloced add more buffers.*/
+
+ return ret;
+}
+static int vdec_input_get_free_block(
+ struct vdec_input_s *input,
+ int size,/*frame size + pading*/
+ struct vframe_block_list_s **block_ret)
+{
+ struct vframe_block_list_s *to_freeblock = NULL;
+ struct vframe_block_list_s *block = NULL;
+ unsigned long flags;
+ flags = vdec_input_lock(input);
+ /*get from free list.*/
+ if (!list_empty(&input->vframe_block_free_list)) {
+ block = list_entry(input->vframe_block_free_list.next,
+ struct vframe_block_list_s, list);
+ if (block->size < (size)) {
+ vdec_input_del_block_locked(input, block);
+ to_freeblock = block;
+ block = NULL;
+ } else {
+ list_move_tail(&block->list,
+ &input->vframe_block_list);
+ input->wr_block = block;/*swith to new block*/
+ }
+ }
+ vdec_input_unlock(input, flags);
+ if (to_freeblock) {
+ /*free the small block.*/
+ vframe_block_free_block(to_freeblock);
+ }
+ if (block) {
+ *block_ret = block;
+ return 0;
+ }
+
+ if (vdec_input_have_blocks_enough(input) > 13) {
+ /*buf fulled */
+ return -EAGAIN;
+ }
+ if (input->no_mem_err_cnt > 3) {
+ /*alloced failed more times.
+ */
+ return -EAGAIN;
+ }
+ if (input->default_block_size <=
+ size * 2) {
+ int def_size = input->default_block_size;
+ do {
+ def_size *= 2;
+ } while ((def_size <= 2 * size) &&
+ (def_size <= VFRAME_BLOCK_SIZE_MAX));
+ if (def_size < size)
+ def_size = ALIGN(size + 64, (1 << 17));
+ /*128k aligned,same as codec_mm*/
+ input->default_block_size = def_size;
+ }
+ block = vdec_input_alloc_new_block(input, 0, 0, NULL, NULL);
+ if (!block) {
+ input->no_mem_err_cnt++;
+ return -EAGAIN;
+ }
+ input->no_mem_err_cnt = 0;
+ *block_ret = block;
+ return 0;
+}
+
+int vdec_input_add_chunk(struct vdec_input_s *input, const char *buf,
+ size_t count, u32 handle, chunk_free free, void* priv)
+{
+ unsigned long flags;
+ struct vframe_chunk_s *chunk;
+ struct vdec_s *vdec = input->vdec;
+ struct vframe_block_list_s *block;
+ int need_pading_size = MIN_FRAME_PADDING_SIZE;
+
+ if (vdec_secure(vdec)) {
+ block = vdec_input_alloc_new_block(input, (ulong)buf,
+ PAGE_ALIGN(count + HEVC_PADDING_SIZE + 1),
+ free, priv); /*Add padding large than HEVC_PADDING_SIZE */
+ if (!block)
+ return -ENOMEM;
+ block->handle = handle;
+ } else {
+#if 0
+ if (add_count == 0) {
+ add_count++;
+ memcpy(sps, buf, 30);
+ return 30;
+ } else if (add_count == 1) {
+ add_count++;
+ memcpy(pps, buf, 8);
+ return 8;
+ }
+ add_count++;
+#endif
+
+#if 0
+ pr_info("vdec_input_add_frame add %p, count=%d\n", buf, (int)count);
+
+ if (count >= 8) {
+ pr_info("%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ buf[0], buf[1], buf[2], buf[3],
+ buf[4], buf[5], buf[6], buf[7]);
+ }
+ if (count >= 16) {
+ pr_info("%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ buf[8], buf[9], buf[10], buf[11],
+ buf[12], buf[13], buf[14], buf[15]);
+ }
+ if (count >= 24) {
+ pr_info("%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ buf[16], buf[17], buf[18], buf[19],
+ buf[20], buf[21], buf[22], buf[23]);
+ }
+ if (count >= 32) {
+ pr_info("%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ buf[24], buf[25], buf[26], buf[27],
+ buf[28], buf[29], buf[30], buf[31]);
+ }
+#endif
+ if (input_stream_based(input))
+ return -EINVAL;
+
+ if (count < PAGE_SIZE) {
+ need_pading_size = PAGE_ALIGN(count + need_pading_size) -
+ count;
+ } else {
+ /*to 64 bytes aligned;*/
+ if (count & 0x3f)
+ need_pading_size += 64 - (count & 0x3f);
+ }
+ block = input->wr_block;
+ if (block &&
+ (vframe_block_space(block) > (count + need_pading_size))) {
+ /*this block have enough buffers.
+ do nothings.
+ */
+ } else if (block && (block->type == VDEC_TYPE_FRAME_CIRCULAR)) {
+ /*in circular module.
+ only one block,.*/
+ return -EAGAIN;
+ } else if (block != NULL) {
+ /*have block but not enough space.
+ recycle the no enough blocks.*/
+ flags = vdec_input_lock(input);
+ if (input->wr_block == block &&
+ block->chunk_count == 0) {
+ block->rp = 0;
+ block->wp = 0;
+ /*block no data move to freelist*/
+ list_move_tail(&block->list,
+ &input->vframe_block_free_list);
+ input->wr_block = NULL;
+ }
+ vdec_input_unlock(input, flags);
+ block = NULL;
+ }
+ if (!block) {/*try new block.*/
+ int ret = vdec_input_get_free_block(input,
+ count + need_pading_size + EXTRA_PADDING_SIZE,
+ &block);
+ if (ret < 0)/*no enough block now.*/
+ return ret;
+ }
+ }
+
+ chunk = kzalloc(sizeof(struct vframe_chunk_s), GFP_KERNEL);
+
+ if (!chunk) {
+ pr_err("vframe_chunk structure allocation failed\n");
+ return -ENOMEM;
+ }
+
+ if ((vdec->hdr10p_data_valid == true) &&
+ (vdec->hdr10p_data_size != 0)) {
+ char *new_buf;
+ new_buf = vzalloc(vdec->hdr10p_data_size);
+ if (new_buf) {
+ memcpy(new_buf, vdec->hdr10p_data_buf, vdec->hdr10p_data_size);
+ chunk->hdr10p_data_buf = new_buf;
+ chunk->hdr10p_data_size = vdec->hdr10p_data_size;
+ } else {
+ pr_err("%s:hdr10p data vzalloc size(%d) failed\n",
+ __func__, vdec->hdr10p_data_size);
+ chunk->hdr10p_data_buf = NULL;
+ chunk->hdr10p_data_size = 0;
+ }
+ } else {
+ chunk->hdr10p_data_buf = NULL;
+ chunk->hdr10p_data_size = 0;
+ }
+ vdec->hdr10p_data_valid = false;
+
+ chunk->magic = 0x4b554843;
+ if (vdec->pts_valid) {
+ chunk->pts = vdec->pts;
+ chunk->pts64 = vdec->pts64;
+ }
+
+ if (vdec->timestamp_valid)
+ chunk->timestamp = vdec->timestamp;
+
+ if (vdec->pts_valid &&
+ input->last_inpts_u64 > 0 &&
+ input->last_in_nopts_cnt == 0) {
+ int d = (int)(chunk->pts64 - input->last_inpts_u64);
+ if (d > 0 && (d < input->last_duration))
+ input->last_duration = d;
+ /* alwasy: used the smallest duration;
+ if 60fps->30 fps.
+ maybe have warning value.
+ */
+ }
+ chunk->pts_valid = vdec->pts_valid;
+ vdec->pts_valid = false;
+ INIT_LIST_HEAD(&chunk->list);
+
+ if (vdec_secure(vdec)) {
+ chunk->offset = 0;
+ chunk->size = count;
+ chunk->pading_size = PAGE_ALIGN(chunk->size + need_pading_size) -
+ chunk->size;
+ } else {
+ chunk->offset = block->wp;
+ chunk->size = count;
+ chunk->pading_size = need_pading_size;
+ if (vframe_chunk_fill(input, chunk, buf, count, block)) {
+ pr_err("vframe_chunk_fill failed\n");
+ kfree(chunk);
+ return -EFAULT;
+ }
+
+ }
+
+
+ flags = vdec_input_lock(input);
+
+ vframe_block_add_chunk(block, chunk);
+
+ list_add_tail(&chunk->list, &input->vframe_chunk_list);
+ input->data_size += chunk->size;
+ input->have_frame_num++;
+
+ if (input->have_frame_num == 1)
+ input->vdec_up(vdec);
+ ATRACE_COUNTER(input->vdec_input_name, input->have_frame_num);
+ if (chunk->pts_valid) {
+ input->last_inpts_u64 = chunk->pts64;
+ input->last_in_nopts_cnt = 0;
+ } else {
+ /*nopts*/
+ input->last_in_nopts_cnt++;
+ }
+ if (chunk->size > input->frame_max_size)
+ input->frame_max_size = chunk->size;
+ input->total_wr_count += count;
+ vdec_input_unlock(input, flags);
+#if 0
+ if (add_count == 2)
+ input->total_wr_count += 38;
+#endif
+
+ return count;
+}
+
+int vdec_input_add_frame(struct vdec_input_s *input, const char *buf,
+ size_t count)
+{
+ int ret = 0;
+ struct drm_info drm;
+ struct vdec_s *vdec = input->vdec;
+ unsigned long phy_buf;
+
+ if (vdec_secure(vdec)) {
+ while (count > 0) {
+ if (count < sizeof(struct drm_info))
+ return -EIO;
+ if (copy_from_user((void*)&drm, buf + ret, sizeof(struct drm_info)))
+ return -EAGAIN;
+ if (!(drm.drm_flag & TYPE_DRMINFO_V2))
+ return -EIO; /*must drm info v2 version*/
+ phy_buf = (unsigned long) drm.drm_phy;
+ vdec_input_add_chunk(input, (char *)phy_buf,
+ (size_t)drm.drm_pktsize, drm.handle, NULL, NULL);
+ count -= sizeof(struct drm_info);
+ ret += sizeof(struct drm_info);
+
+ /* the drm frame data might include head infos and raw */
+ /* data thus the next drm unit still need a valid pts.*/
+ if (count >= sizeof(struct drm_info))
+ vdec->pts_valid = true;
+ }
+ } else {
+ ret = vdec_input_add_chunk(input, buf, count, 0, NULL, NULL);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(vdec_input_add_frame);
+
+int vdec_input_add_frame_with_dma(struct vdec_input_s *input, ulong addr,
+ size_t count, u32 handle, chunk_free free, void* priv)
+{
+ struct vdec_s *vdec = input->vdec;
+
+ return vdec_secure(vdec) ?
+ vdec_input_add_chunk(input,
+ (char *)addr, count, handle, free, priv) : -1;
+}
+EXPORT_SYMBOL(vdec_input_add_frame_with_dma);
+
+struct vframe_chunk_s *vdec_input_next_chunk(struct vdec_input_s *input)
+{
+ struct vframe_chunk_s *chunk = NULL;
+ unsigned long flags;
+ flags = vdec_input_lock(input);
+ if (!list_empty(&input->vframe_chunk_list)) {
+ chunk = list_first_entry(&input->vframe_chunk_list,
+ struct vframe_chunk_s, list);
+ }
+ vdec_input_unlock(input, flags);
+ return chunk;
+}
+EXPORT_SYMBOL(vdec_input_next_chunk);
+
+struct vframe_chunk_s *vdec_input_next_input_chunk(
+ struct vdec_input_s *input)
+{
+ struct vframe_chunk_s *chunk = NULL;
+ struct list_head *p;
+ unsigned long flags;
+ flags = vdec_input_lock(input);
+
+ list_for_each(p, &input->vframe_chunk_list) {
+ struct vframe_chunk_s *c = list_entry(
+ p, struct vframe_chunk_s, list);
+ if ((c->flag & VFRAME_CHUNK_FLAG_CONSUMED) == 0) {
+ chunk = c;
+ break;
+ }
+ }
+ vdec_input_unlock(input, flags);
+ return chunk;
+}
+EXPORT_SYMBOL(vdec_input_next_input_chunk);
+
+void vdec_input_release_chunk(struct vdec_input_s *input,
+ struct vframe_chunk_s *chunk)
+{
+ struct vframe_chunk_s *p;
+ u32 chunk_valid = 0;
+ unsigned long flags;
+ struct vframe_block_list_s *block = chunk->block;
+ struct vframe_block_list_s *tofreeblock = NULL;
+ flags = vdec_input_lock(input);
+
+ list_for_each_entry(p, &input->vframe_chunk_list, list) {
+ if (p == chunk) {
+ chunk_valid = 1;
+ break;
+ }
+ }
+ /* 2 threads go here, the other done the deletion,so return*/
+ if (chunk_valid == 0) {
+ vdec_input_unlock(input, flags);
+ pr_err("%s chunk is deleted,so return.\n", __func__);
+ return;
+ }
+
+ list_del(&chunk->list);
+ input->have_frame_num--;
+ ATRACE_COUNTER(input->vdec_input_name, input->have_frame_num);
+ if (chunk->pts_valid) {
+ input->last_comsumed_no_pts_cnt = 0;
+ input->last_comsumed_pts_u64 = chunk->pts64;
+ } else
+ input->last_comsumed_no_pts_cnt++;
+ block->rp += chunk->size;
+ if (block->rp >= block->size)
+ block->rp -= block->size;
+ block->data_size -= chunk->size;
+ block->chunk_count--;
+ input->data_size -= chunk->size;
+ input->total_rd_count += chunk->size;
+ if (block->is_out_buf) {
+ list_move_tail(&block->list,
+ &input->vframe_block_free_list);
+ if (block->free) {
+ vdec_input_del_block_locked(input, block);
+ block->free(block->priv, block->handle);
+ kfree(block);
+ }
+ } else if (block->chunk_count == 0 &&
+ input->wr_block != block ) {/*don't free used block*/
+ if (block->size < input->default_block_size) {
+ vdec_input_del_block_locked(input, block);
+ tofreeblock = block;
+ } else {
+ block->rp = 0;
+ block->wp = 0;
+ list_move_tail(&block->list,
+ &input->vframe_block_free_list);
+ }
+ }
+
+ vdec_input_unlock(input, flags);
+ if (tofreeblock)
+ vframe_block_free_block(tofreeblock);
+ kfree(chunk);
+}
+EXPORT_SYMBOL(vdec_input_release_chunk);
+
+unsigned long vdec_input_lock(struct vdec_input_s *input)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&input->lock, flags);
+
+ return flags;
+}
+EXPORT_SYMBOL(vdec_input_lock);
+
+void vdec_input_unlock(struct vdec_input_s *input, unsigned long flags)
+{
+ spin_unlock_irqrestore(&input->lock, flags);
+}
+EXPORT_SYMBOL(vdec_input_unlock);
+
+void vdec_input_release(struct vdec_input_s *input)
+{
+ struct list_head *p, *tmp;
+
+ /* release chunk data */
+ list_for_each_safe(p, tmp, &input->vframe_chunk_list) {
+ struct vframe_chunk_s *chunk = list_entry(
+ p, struct vframe_chunk_s, list);
+ vdec_input_release_chunk(input, chunk);
+ }
+ list_for_each_safe(p, tmp, &input->vframe_block_list) {
+ /*should never here.*/
+ list_move_tail(p, &input->vframe_block_free_list);
+ }
+ /* release input blocks */
+ list_for_each_safe(p, tmp, &input->vframe_block_free_list) {
+ struct vframe_block_list_s *block = list_entry(
+ p, struct vframe_block_list_s, list);
+ vdec_input_del_block_locked(input, block);
+ vframe_block_free_block(block);
+ }
+
+ /* release swap pages */
+ if (vdec_secure(input->vdec)) {
+ if (input->swap_page_phys)
+ codec_mm_free_for_dma("SWAP", input->swap_page_phys);
+ } else {
+ if (input->swap_page)
+ codec_mm_dma_free_coherent(input->mem_handle);
+ }
+ input->swap_page = NULL;
+ input->swap_page_phys = 0;
+ input->swap_valid = false;
+}
+EXPORT_SYMBOL(vdec_input_release);
+
+u32 vdec_input_get_freed_handle(struct vdec_s *vdec)
+{
+ struct vframe_block_list_s *block;
+ struct vdec_input_s *input = &vdec->input;
+ unsigned long flags;
+ u32 handle = 0;
+
+ if (!vdec)
+ return 0;
+
+ if (!vdec_secure(vdec))
+ return 0;
+
+ flags = vdec_input_lock(input);
+ do {
+ block = list_first_entry_or_null(&input->vframe_block_free_list,
+ struct vframe_block_list_s, list);
+ if (!block) {
+ break;
+ }
+
+ handle = block->handle;
+ vdec_input_del_block_locked(input, block);
+ if (block->free)
+ block->free(block->priv, handle);
+ kfree(block);
+
+ } while(!handle);
+
+ vdec_input_unlock(input, flags);
+ return handle;
+}
+EXPORT_SYMBOL(vdec_input_get_freed_handle);
+
+
diff --git a/drivers/frame_provider/decoder/utils/vdec_input.h b/drivers/frame_provider/decoder/utils/vdec_input.h
new file mode 100644
index 0000000..9783db7
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/vdec_input.h
@@ -0,0 +1,191 @@
+/*
+ * drivers/amlogic/media/frame_provider/decoder/utils/vdec_input.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_INPUT_H
+#define VDEC_INPUT_H
+
+struct vdec_s;
+struct vdec_input_s;
+
+typedef void (*chunk_free)(void *priv, u32 handle);
+
+struct vframe_block_list_s {
+ u32 magic;
+ int id;
+ struct list_head list;
+ ulong start;
+ void *start_virt;
+ ulong addr;
+ bool is_mapped;
+ int type;
+ u32 size;
+ u32 wp;
+ u32 rp;
+ int data_size;
+ int chunk_count;
+ int is_out_buf;
+ u32 handle;
+ ulong mem_handle;
+ /* free callback */
+ chunk_free free;
+ void* priv;
+
+ struct vdec_input_s *input;
+};
+
+#define VFRAME_CHUNK_FLAG_CONSUMED 0x0001
+
+struct vframe_chunk_s {
+ u32 magic;
+ struct list_head list;
+ int flag;
+ u32 offset;
+ u32 size;
+ u32 pts;
+ u32 pading_size;
+ u64 pts64;
+ bool pts_valid;
+ u64 timestamp;
+ bool timestamp_valid;
+ u64 sequence;
+ struct vframe_block_list_s *block;
+ u32 hdr10p_data_size;
+ char *hdr10p_data_buf;
+};
+
+#define VDEC_INPUT_TARGET_VLD 0
+#define VDEC_INPUT_TARGET_HEVC 1
+#define VLD_PADDING_SIZE 1024
+#define HEVC_PADDING_SIZE (1024*16)
+
+struct vdec_input_s {
+ struct list_head vframe_block_list;
+ struct list_head vframe_chunk_list;
+ struct list_head vframe_block_free_list;
+ struct vframe_block_list_s *wr_block;
+ int have_free_blocks;
+ int no_mem_err_cnt;/*when alloc no mem cnt++*/
+ int block_nums;
+ int block_id_seq;
+ int id;
+ spinlock_t lock;
+ int type;
+ int target;
+ struct vdec_s *vdec;
+ bool swap_valid;
+ bool swap_needed;
+ bool eos;
+ ulong mem_handle;
+ void *swap_page;
+ dma_addr_t swap_page_phys;
+ u64 total_wr_count;
+ u64 total_rd_count;
+ u64 streaming_rp;
+ u32 swap_rp;
+ bool last_swap_slave;
+ int dirty_count;
+ u64 sequence;
+ unsigned start;
+ unsigned size;
+ int default_block_size;
+ int data_size;
+ int frame_max_size;
+ int prepare_level;
+/*for check frame delay.*/
+ u64 last_inpts_u64;
+ u64 last_comsumed_pts_u64;
+ int last_in_nopts_cnt;
+ int last_comsumed_no_pts_cnt;
+ int last_duration;
+/*for check frame delay.*/
+ int have_frame_num;
+ int stream_cookie; /* wrap count for vld_mem and
+ HEVC_SHIFT_BYTE_COUNT for hevc */
+ char vdec_input_name[32];
+ bool (*vdec_is_input_frame_empty)(struct vdec_s *);
+ void (*vdec_up)(struct vdec_s *);
+};
+
+struct vdec_input_status_s {
+ int size;
+ int data_len;
+ int free_len;
+ int read_pointer;
+};
+
+#define input_frame_based(input) \
+ (((input)->type == VDEC_TYPE_FRAME_BLOCK) || \
+ ((input)->type == VDEC_TYPE_FRAME_CIRCULAR))
+#define input_stream_based(input) \
+ (((input)->type == VDEC_TYPE_STREAM_PARSER) || \
+ ((input)->type == VDEC_TYPE_SINGLE))
+
+/* Initialize vdec_input structure */
+extern void vdec_input_init(struct vdec_input_s *input, struct vdec_s *vdec);
+extern int vdec_input_prepare_bufs(struct vdec_input_s *input,
+ int frame_width, int frame_height);
+
+/* Get available input data size */
+extern int vdec_input_level(struct vdec_input_s *input);
+
+/* Set input type and target */
+extern void vdec_input_set_type(struct vdec_input_s *input, int type,
+ int target);
+
+/* Set stream buffer information for stream based input */
+extern int vdec_input_set_buffer(struct vdec_input_s *input, u32 start,
+ u32 size);
+
+/* Add enqueue video data into decoder's input */
+extern int vdec_input_add_frame(struct vdec_input_s *input, const char *buf,
+ size_t count);
+
+extern int vdec_input_add_frame_with_dma(struct vdec_input_s *input, ulong addr,
+ size_t count, u32 handle, chunk_free free, void* priv);
+
+/* Peek next frame data from decoder's input */
+extern struct vframe_chunk_s *vdec_input_next_chunk(
+ struct vdec_input_s *input);
+
+/* Peek next frame data from decoder's input, not marked as consumed */
+extern struct vframe_chunk_s *vdec_input_next_input_chunk(
+ struct vdec_input_s *input);
+
+/* Consume next frame data from decoder's input */
+extern void vdec_input_release_chunk(struct vdec_input_s *input,
+ struct vframe_chunk_s *chunk);
+
+/* Get decoder input buffer status */
+extern int vdec_input_get_status(struct vdec_input_s *input,
+ struct vdec_input_status_s *status);
+
+extern unsigned long vdec_input_lock(struct vdec_input_s *input);
+
+extern void vdec_input_unlock(struct vdec_input_s *input, unsigned long lock);
+
+/* release all resource for decoder's input */
+extern void vdec_input_release(struct vdec_input_s *input);
+/* return block handle and free block */
+extern u32 vdec_input_get_freed_handle(struct vdec_s *vdec);
+int vdec_input_dump_chunks(int id, struct vdec_input_s *input,
+ char *bufs, int size);
+int vdec_input_dump_blocks(struct vdec_input_s *input,
+ char *bufs, int size);
+
+int vdec_input_get_duration_u64(struct vdec_input_s *input);
+
+#endif /* VDEC_INPUT_H */
diff --git a/drivers/frame_provider/decoder/utils/vdec_power_ctrl.c b/drivers/frame_provider/decoder/utils/vdec_power_ctrl.c
new file mode 100644
index 0000000..9057a80
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/vdec_power_ctrl.c
@@ -0,0 +1,794 @@
+/*
+ * drivers/amlogic/media/frame_provider/decoder/utils/vdec_power_ctrl.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 "vdec_power_ctrl.h"
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include <linux/amlogic/power_ctrl.h>
+#include <dt-bindings/power/sc2-pd.h>
+#include <linux/amlogic/pwr_ctrl.h>
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include "../../../common/media_clock/switch/amports_gate.h"
+#include "../../../common/chips/decoder_cpu_ver_info.h"
+#include "../../../common/media_clock/clk/clk.h"
+
+#define HEVC_TEST_LIMIT (100)
+#define GXBB_REV_A_MINOR (0xa)
+
+extern int no_powerdown;
+extern int hevc_max_reset_count;
+
+struct pm_name_s {
+ int type;
+ const char *name;
+};
+
+static const struct pm_name_s pm_name[] = {
+ {PM_POWER_CTRL_RW_REG, "legacy"},
+ {PM_POWER_CTRL_API, "power-ctrl-api"},
+ {PM_POWER_DOMAIN, "power-domain"},
+ {PM_POWER_DOMAIN_SEC_API, "pd-sec-api"},
+ {PM_POWER_DOMAIN_NONSEC_API, "pd-non-sec-api"},
+};
+
+const char *get_pm_name(int type)
+{
+ const char *name = "unknown";
+ int i, size = ARRAY_SIZE(pm_name);
+
+ for (i = 0; i < size; i++) {
+ if (type == pm_name[i].type)
+ name = pm_name[i].name;
+ }
+
+ return name;
+}
+EXPORT_SYMBOL(get_pm_name);
+
+static struct pm_pd_s pm_domain_data[] = {
+ { .name = "pwrc-vdec", },
+ { .name = "pwrc-hcodec",},
+ { .name = "pwrc-vdec-2", },
+ { .name = "pwrc-hevc", },
+ { .name = "pwrc-hevc-b", },
+ { .name = "pwrc-wave", },
+};
+
+static void pm_vdec_power_switch(struct pm_pd_s *pd, int id, bool on)
+{
+ struct device *dev = pd[id].dev;
+
+ if (on)
+ pm_runtime_get_sync(dev);
+ else
+ pm_runtime_put_sync(dev);
+
+ pr_debug("the %-15s power %s\n",
+ pd[id].name, on ? "on" : "off");
+}
+
+static int pm_vdec_power_domain_init(struct device *dev)
+{
+ int i, err;
+ const struct power_manager_s *pm = of_device_get_match_data(dev);
+ struct pm_pd_s *pd = pm->pd_data;
+
+ for (i = 0; i < ARRAY_SIZE(pm_domain_data); i++) {
+ pd[i].dev = dev_pm_domain_attach_by_name(dev, pd[i].name);
+ if (IS_ERR_OR_NULL(pd[i].dev)) {
+ err = PTR_ERR(pd[i].dev);
+ dev_err(dev, "Get %s failed, pm-domain: %d\n",
+ pd[i].name, err);
+ continue;
+ }
+
+ pd[i].link = device_link_add(dev, pd[i].dev,
+ DL_FLAG_PM_RUNTIME |
+ DL_FLAG_STATELESS);
+ if (IS_ERR_OR_NULL(pd[i].link)) {
+ dev_err(dev, "Adding %s device link failed!\n",
+ pd[i].name);
+ return -ENODEV;
+ }
+
+ pr_debug("power domain: name: %s, dev: %px, link: %px\n",
+ pd[i].name, pd[i].dev, pd[i].link);
+ }
+
+ return 0;
+}
+
+static void pm_vdec_power_domain_relese(struct device *dev)
+{
+ int i;
+ const struct power_manager_s *pm = of_device_get_match_data(dev);
+ struct pm_pd_s *pd = pm->pd_data;
+
+ for (i = 0; i < ARRAY_SIZE(pm_domain_data); i++) {
+ if (!IS_ERR_OR_NULL(pd[i].link))
+ device_link_del(pd[i].link);
+
+ if (!IS_ERR_OR_NULL(pd[i].dev))
+ dev_pm_domain_detach(pd[i].dev, true);
+ }
+}
+
+static void pm_vdec_clock_on(int id)
+{
+ if (id == VDEC_1) {
+ amports_switch_gate("clk_vdec_mux", 1);
+ vdec_clock_hi_enable();
+ } else if (id == VDEC_HCODEC) {
+ hcodec_clock_enable();
+ } else if (id == VDEC_HEVC) {
+ /* enable hevc clock */
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2)
+ amports_switch_gate("clk_hevcf_mux", 1);
+ else
+ amports_switch_gate("clk_hevc_mux", 1);
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
+ amports_switch_gate("clk_hevcb_mux", 1);
+ hevc_clock_hi_enable();
+ hevc_back_clock_hi_enable();
+ }
+}
+
+static void pm_vdec_clock_off(int id)
+{
+ if (id == VDEC_1) {
+ vdec_clock_off();
+ } else if (id == VDEC_HCODEC) {
+ hcodec_clock_off();
+ } else if (id == VDEC_HEVC) {
+ /* disable hevc clock */
+ hevc_clock_off();
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
+ hevc_back_clock_off();
+ }
+}
+
+static void pm_vdec_power_domain_power_on(struct device *dev, int id)
+{
+ const struct power_manager_s *pm = of_device_get_match_data(dev);
+
+ pm_vdec_clock_on(id);
+ pm_vdec_power_switch(pm->pd_data, id, true);
+}
+
+static void pm_vdec_power_domain_power_off(struct device *dev, int id)
+{
+ const struct power_manager_s *pm = of_device_get_match_data(dev);
+
+ pm_vdec_clock_off(id);
+ pm_vdec_power_switch(pm->pd_data, id, false);
+}
+
+static bool pm_vdec_power_domain_power_state(struct device *dev, int id)
+{
+ const struct power_manager_s *pm = of_device_get_match_data(dev);
+
+ return pm_runtime_active(pm->pd_data[id].dev);
+}
+
+static bool test_hevc(u32 decomp_addr, u32 us_delay)
+{
+ int i;
+
+ /* SW_RESET IPP */
+ WRITE_VREG(HEVCD_IPP_TOP_CNTL, 1);
+ WRITE_VREG(HEVCD_IPP_TOP_CNTL, 0);
+
+ /* initialize all canvas table */
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0);
+ for (i = 0; i < 32; i++)
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
+ 0x1 | (i << 8) | decomp_addr);
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1);
+ 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);
+
+ /* Initialize mcrcc */
+ WRITE_VREG(HEVCD_MCRCC_CTL1, 0x2);
+ WRITE_VREG(HEVCD_MCRCC_CTL2, 0x0);
+ WRITE_VREG(HEVCD_MCRCC_CTL3, 0x0);
+ WRITE_VREG(HEVCD_MCRCC_CTL1, 0xff0);
+
+ /* Decomp initialize */
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x0);
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL2, 0x0);
+
+ /* Frame level initialization */
+ WRITE_VREG(HEVCD_IPP_TOP_FRMCONFIG, 0x100 | (0x100 << 16));
+ WRITE_VREG(HEVCD_IPP_TOP_TILECONFIG3, 0x0);
+ WRITE_VREG(HEVCD_IPP_TOP_LCUCONFIG, 0x1 << 5);
+ WRITE_VREG(HEVCD_IPP_BITDEPTH_CONFIG, 0x2 | (0x2 << 2));
+
+ WRITE_VREG(HEVCD_IPP_CONFIG, 0x0);
+ WRITE_VREG(HEVCD_IPP_LINEBUFF_BASE, 0x0);
+
+ /* Enable SWIMP mode */
+ WRITE_VREG(HEVCD_IPP_SWMPREDIF_CONFIG, 0x1);
+
+ /* Enable frame */
+ WRITE_VREG(HEVCD_IPP_TOP_CNTL, 0x2);
+ WRITE_VREG(HEVCD_IPP_TOP_FRMCTL, 0x1);
+
+ /* Send SW-command CTB info */
+ WRITE_VREG(HEVCD_IPP_SWMPREDIF_CTBINFO, 0x1 << 31);
+
+ /* Send PU_command */
+ WRITE_VREG(HEVCD_IPP_SWMPREDIF_PUINFO0, (0x4 << 9) | (0x4 << 16));
+ WRITE_VREG(HEVCD_IPP_SWMPREDIF_PUINFO1, 0x1 << 3);
+ WRITE_VREG(HEVCD_IPP_SWMPREDIF_PUINFO2, 0x0);
+ WRITE_VREG(HEVCD_IPP_SWMPREDIF_PUINFO3, 0x0);
+
+ udelay(us_delay);
+
+ WRITE_VREG(HEVCD_IPP_DBG_SEL, 0x2 << 4);
+
+ return (READ_VREG(HEVCD_IPP_DBG_DATA) & 3) == 1;
+}
+
+static bool hevc_workaround_needed(void)
+{
+ return (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_GXBB) &&
+ (get_meson_cpu_version(MESON_CPU_VERSION_LVL_MINOR)
+ == GXBB_REV_A_MINOR);
+}
+
+static void pm_vdec_legacy_power_off(struct device *dev, int id);
+
+static void pm_vdec_legacy_power_on(struct device *dev, int id)
+{
+ void *decomp_addr = NULL;
+ ulong decomp_dma_addr;
+ ulong mem_handle;
+ u32 decomp_addr_aligned = 0;
+ int hevc_loop = 0;
+ int sleep_val, iso_val;
+ bool is_power_ctrl_ver2 = false;
+
+ is_power_ctrl_ver2 =
+ ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
+ (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1)) ? true : false;
+
+ if (hevc_workaround_needed() &&
+ (id == VDEC_HEVC)) {
+ decomp_addr = codec_mm_dma_alloc_coherent(&mem_handle,
+ &decomp_dma_addr, SZ_64K + SZ_4K, "vdec_prealloc");
+ if (decomp_addr) {
+ decomp_addr_aligned = ALIGN(decomp_dma_addr, SZ_64K);
+ memset((u8 *)decomp_addr +
+ (decomp_addr_aligned - decomp_dma_addr),
+ 0xff, SZ_4K);
+ } else
+ pr_err("vdec: alloc HEVC gxbb decomp buffer failed.\n");
+ }
+
+ if (id == VDEC_1) {
+ sleep_val = is_power_ctrl_ver2 ? 0x2 : 0xc;
+ iso_val = is_power_ctrl_ver2 ? 0x2 : 0xc0;
+
+ /* vdec1 power on */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_sleep_mask(true, sleep_val, 0)) {
+ pr_err("vdec-1 power on ctrl sleep fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val);
+#endif
+ /* wait 10uS */
+ udelay(10);
+ /* vdec1 soft reset */
+ WRITE_VREG(DOS_SW_RESET0, 0xfffffffc);
+ WRITE_VREG(DOS_SW_RESET0, 0);
+ /* enable vdec1 clock */
+ /*
+ *add power on vdec clock level setting,only for m8 chip,
+ * m8baby and m8m2 can dynamic adjust vdec clock,
+ * power on with default clock level
+ */
+ amports_switch_gate("clk_vdec_mux", 1);
+ vdec_clock_hi_enable();
+ /* power up vdec memories */
+ WRITE_VREG(DOS_MEM_PD_VDEC, 0);
+
+ /* remove vdec1 isolation */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_iso_mask(true, iso_val, 0)) {
+ pr_err("vdec-1 power on ctrl iso fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val);
+#endif
+ /* reset DOS top registers */
+ WRITE_VREG(DOS_VDEC_MCRCC_STALL_CTRL, 0);
+ } else if (id == VDEC_2) {
+ if (has_vdec2()) {
+ /* vdec2 power on */
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) &
+ ~0x30);
+ /* wait 10uS */
+ udelay(10);
+ /* vdec2 soft reset */
+ WRITE_VREG(DOS_SW_RESET2, 0xffffffff);
+ WRITE_VREG(DOS_SW_RESET2, 0);
+ /* enable vdec1 clock */
+ vdec2_clock_hi_enable();
+ /* power up vdec memories */
+ WRITE_VREG(DOS_MEM_PD_VDEC2, 0);
+ /* remove vdec2 isolation */
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) &
+ ~0x300);
+ /* reset DOS top registers */
+ WRITE_VREG(DOS_VDEC2_MCRCC_STALL_CTRL, 0);
+ }
+ } else if (id == VDEC_HCODEC) {
+ if (has_hdec()) {
+ sleep_val = is_power_ctrl_ver2 ? 0x1 : 0x3;
+ iso_val = is_power_ctrl_ver2 ? 0x1 : 0x30;
+
+ /* hcodec power on */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_sleep_mask(true, sleep_val, 0)) {
+ pr_err("hcodec power on ctrl sleep fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val);
+#endif
+ /* wait 10uS */
+ udelay(10);
+ /* hcodec soft reset */
+ WRITE_VREG(DOS_SW_RESET1, 0xffffffff);
+ WRITE_VREG(DOS_SW_RESET1, 0);
+ /* enable hcodec clock */
+ hcodec_clock_enable();
+ /* power up hcodec memories */
+ WRITE_VREG(DOS_MEM_PD_HCODEC, 0);
+ /* remove hcodec isolation */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_iso_mask(true, iso_val, 0)) {
+ pr_err("hcodec power on ctrl iso fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val);
+#endif
+ }
+ } else if (id == VDEC_HEVC) {
+ if (has_hevc_vdec()) {
+ bool hevc_fixed = false;
+
+ sleep_val = is_power_ctrl_ver2 ? 0x4 : 0xc0;
+ iso_val = is_power_ctrl_ver2 ? 0x4 : 0xc00;
+
+ while (!hevc_fixed) {
+ /* hevc power on */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_sleep_mask(true, sleep_val, 0)) {
+ pr_err("hevc power on ctrl sleep fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val);
+#endif
+ /* wait 10uS */
+ udelay(10);
+ /* hevc soft reset */
+ WRITE_VREG(DOS_SW_RESET3, 0xffffffff);
+ WRITE_VREG(DOS_SW_RESET3, 0);
+ /* enable hevc clock */
+ amports_switch_gate("clk_hevc_mux", 1);
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
+ amports_switch_gate("clk_hevcb_mux", 1);
+ hevc_clock_hi_enable();
+ hevc_back_clock_hi_enable();
+ /* power up hevc memories */
+ WRITE_VREG(DOS_MEM_PD_HEVC, 0);
+ /* remove hevc isolation */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_iso_mask(true, iso_val, 0)) {
+ pr_err("hevc power on ctrl iso fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val);
+#endif
+ if (!hevc_workaround_needed())
+ break;
+
+ if (decomp_addr)
+ hevc_fixed = test_hevc(
+ decomp_addr_aligned, 20);
+
+ if (!hevc_fixed) {
+ hevc_loop++;
+ if (hevc_loop >= HEVC_TEST_LIMIT) {
+ pr_warn("hevc power sequence over limit\n");
+ pr_warn("=====================================================\n");
+ pr_warn(" This chip is identified to have HW failure.\n");
+ pr_warn(" Please contact sqa-platform to replace the platform.\n");
+ pr_warn("=====================================================\n");
+
+ panic("Force panic for chip detection !!!\n");
+
+ break;
+ }
+
+ pm_vdec_legacy_power_off(NULL, VDEC_HEVC);
+
+ mdelay(10);
+ }
+ }
+
+ if (hevc_loop > hevc_max_reset_count)
+ hevc_max_reset_count = hevc_loop;
+
+ WRITE_VREG(DOS_SW_RESET3, 0xffffffff);
+ udelay(10);
+ WRITE_VREG(DOS_SW_RESET3, 0);
+ }
+ }
+
+ if (decomp_addr)
+ codec_mm_dma_free_coherent(mem_handle);
+}
+
+static void pm_vdec_legacy_power_off(struct device *dev, int id)
+{
+ int sleep_val, iso_val;
+ bool is_power_ctrl_ver2 = false;
+
+ is_power_ctrl_ver2 =
+ ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
+ (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1)) ? true : false;
+
+ if (id == VDEC_1) {
+ sleep_val = is_power_ctrl_ver2 ? 0x2 : 0xc;
+ iso_val = is_power_ctrl_ver2 ? 0x2 : 0xc0;
+
+ /* enable vdec1 isolation */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_iso_mask(false, iso_val, 0)) {
+ pr_err("vdec-1 power off ctrl iso fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val);
+#endif
+ /* power off vdec1 memories */
+ WRITE_VREG(DOS_MEM_PD_VDEC, 0xffffffffUL);
+ /* disable vdec1 clock */
+ vdec_clock_off();
+ /* vdec1 power off */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_sleep_mask(false, sleep_val, 0)) {
+ pr_err("vdec-1 power off ctrl sleep fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val);
+#endif
+ } else if (id == VDEC_2) {
+ if (has_vdec2()) {
+ /* enable vdec2 isolation */
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) |
+ 0x300);
+ /* power off vdec2 memories */
+ WRITE_VREG(DOS_MEM_PD_VDEC2, 0xffffffffUL);
+ /* disable vdec2 clock */
+ vdec2_clock_off();
+ /* vdec2 power off */
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) |
+ 0x30);
+ }
+ } else if (id == VDEC_HCODEC) {
+ if (has_hdec()) {
+ sleep_val = is_power_ctrl_ver2 ? 0x1 : 0x3;
+ iso_val = is_power_ctrl_ver2 ? 0x1 : 0x30;
+
+ /* enable hcodec isolation */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_iso_mask(false, iso_val, 0)) {
+ pr_err("hcodec power off ctrl iso fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val);
+#endif
+ /* power off hcodec memories */
+ WRITE_VREG(DOS_MEM_PD_HCODEC, 0xffffffffUL);
+ /* disable hcodec clock */
+ hcodec_clock_off();
+ /* hcodec power off */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_sleep_mask(false, sleep_val, 0)) {
+ pr_err("hcodec power off ctrl sleep fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val);
+#endif
+ }
+ } else if (id == VDEC_HEVC) {
+ if (has_hevc_vdec()) {
+ sleep_val = is_power_ctrl_ver2 ? 0x4 : 0xc0;
+ iso_val = is_power_ctrl_ver2 ? 0x4 : 0xc00;
+
+ if (no_powerdown == 0) {
+ /* enable hevc isolation */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_iso_mask(false, iso_val, 0)) {
+ pr_err("hevc power off ctrl iso fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val);
+#endif
+ /* power off hevc memories */
+ WRITE_VREG(DOS_MEM_PD_HEVC, 0xffffffffUL);
+
+ /* disable hevc clock */
+ hevc_clock_off();
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
+ hevc_back_clock_off();
+
+ /* hevc power off */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_sleep_mask(false, sleep_val, 0)) {
+ pr_err("hevc power off ctrl sleep fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val);
+#endif
+ } else {
+ pr_info("!!!!!!!!not power down\n");
+ hevc_reset_core(NULL);
+ no_powerdown = 0;
+ }
+ }
+ }
+}
+
+static bool pm_vdec_legacy_power_state(struct device *dev, int id)
+{
+ bool ret = false;
+
+ if (id == VDEC_1) {
+ if (((READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) &
+ (((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
+ (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1))
+ ? 0x2 : 0xc)) == 0) &&
+ (READ_HHI_REG(HHI_VDEC_CLK_CNTL) & 0x100))
+ ret = true;
+ } else if (id == VDEC_2) {
+ if (has_vdec2()) {
+ if (((READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & 0x30) == 0) &&
+ (READ_HHI_REG(HHI_VDEC2_CLK_CNTL) & 0x100))
+ ret = true;
+ }
+ } else if (id == VDEC_HCODEC) {
+ if (has_hdec()) {
+ if (((READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) &
+ (((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
+ (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1))
+ ? 0x1 : 0x3)) == 0) &&
+ (READ_HHI_REG(HHI_VDEC_CLK_CNTL) & 0x1000000))
+ ret = true;
+ }
+ } else if (id == VDEC_HEVC) {
+ if (has_hevc_vdec()) {
+ if (((READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) &
+ (((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
+ (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1))
+ ? 0x4 : 0xc0)) == 0) &&
+ (READ_HHI_REG(HHI_VDEC2_CLK_CNTL) & 0x1000000))
+ ret = true;
+ }
+ }
+
+ return ret;
+}
+
+static void pm_vdec_pd_sec_api_power_on(struct device *dev, int id)
+{
+ int pd_id = (id == VDEC_1) ? PDID_DOS_VDEC :
+ (id == VDEC_HEVC) ? PDID_DOS_HEVC :
+ PDID_DOS_HCODEC;
+
+ pm_vdec_clock_on(id);
+ pwr_ctrl_psci_smc(pd_id, PWR_ON);
+
+}
+
+static void pm_vdec_pd_sec_api_power_off(struct device *dev, int id)
+{
+ int pd_id = (id == VDEC_1) ? PDID_DOS_VDEC :
+ (id == VDEC_HEVC) ? PDID_DOS_HEVC :
+ PDID_DOS_HCODEC;
+
+ pm_vdec_clock_off(id);
+ pwr_ctrl_psci_smc(pd_id, PWR_OFF);
+}
+
+static bool pm_vdec_pd_sec_api_power_state(struct device *dev, int id)
+{
+ int pd_id = (id == VDEC_1) ? PDID_DOS_VDEC :
+ (id == VDEC_HEVC) ? PDID_DOS_HEVC :
+ PDID_DOS_HCODEC;
+
+ return !pwr_ctrl_status_psci_smc(pd_id);
+}
+
+static void pm_vdec_pd_nosec_api_power_on(struct device *dev, int id)
+{
+#if 0
+ int pd_id = (id == VDEC_1) ? PM_DOS_VDEC :
+ (id == VDEC_HEVC) ? PM_DOS_HEVC :
+ PM_DOS_HCODEC;
+
+ pm_vdec_clock_on(id);
+ power_domain_switch(pd_id, PWR_ON);
+#endif
+}
+
+static void pm_vdec_pd_nosec_api_power_off(struct device *dev, int id)
+{
+#if 0
+ int pd_id = (id == VDEC_1) ? PM_DOS_VDEC :
+ (id == VDEC_HEVC) ? PM_DOS_HEVC :
+ PM_DOS_HCODEC;
+
+ pm_vdec_clock_off(id);
+ power_domain_switch(pd_id, PWR_OFF);
+#endif
+}
+
+static bool pm_vdec_pd_nosec_api_power_state(struct device *dev, int id)
+{
+ return pm_vdec_legacy_power_state(dev, id);
+}
+
+static const struct power_manager_s pm_rw_reg_data = {
+ .pm_type = PM_POWER_CTRL_RW_REG,
+ .power_on = pm_vdec_legacy_power_on,
+ .power_off = pm_vdec_legacy_power_off,
+ .power_state = pm_vdec_legacy_power_state,
+};
+
+static const struct power_manager_s pm_ctrl_api_data = {
+ .pm_type = PM_POWER_CTRL_API,
+ .power_on = pm_vdec_legacy_power_on,
+ .power_off = pm_vdec_legacy_power_off,
+ .power_state = pm_vdec_legacy_power_state,
+};
+
+static const struct power_manager_s pm_pd_data = {
+ .pm_type = PM_POWER_DOMAIN,
+ .pd_data = pm_domain_data,
+ .init = pm_vdec_power_domain_init,
+ .release = pm_vdec_power_domain_relese,
+ .power_on = pm_vdec_power_domain_power_on,
+ .power_off = pm_vdec_power_domain_power_off,
+ .power_state = pm_vdec_power_domain_power_state,
+};
+
+static const struct power_manager_s pm_pd_sec_api_data = {
+ .pm_type = PM_POWER_DOMAIN_SEC_API,
+ .power_on = pm_vdec_pd_sec_api_power_on,
+ .power_off = pm_vdec_pd_sec_api_power_off,
+ .power_state = pm_vdec_pd_sec_api_power_state,
+};
+
+static const struct power_manager_s pm_pd_nosec_api_data = {
+ .pm_type = PM_POWER_DOMAIN_NONSEC_API,
+ .power_on = pm_vdec_pd_nosec_api_power_on,
+ .power_off = pm_vdec_pd_nosec_api_power_off,
+ .power_state = pm_vdec_pd_nosec_api_power_state,
+};
+
+const struct of_device_id amlogic_vdec_matches[] = {
+ { .compatible = "amlogic, vdec", .data = &pm_rw_reg_data },
+ { .compatible = "amlogic, vdec-pm-api", .data = &pm_ctrl_api_data },
+ { .compatible = "amlogic, vdec-pm-pd", .data = &pm_pd_data },
+ { .compatible = "amlogic, vdec-pm-pd-sec-api", .data = &pm_pd_sec_api_data },
+ { .compatible = "amlogic, vdec-pm-pd-nsec-api", .data = &pm_pd_nosec_api_data },
+ {},
+};
+EXPORT_SYMBOL(amlogic_vdec_matches);
+
diff --git a/drivers/frame_provider/decoder/utils/vdec_power_ctrl.h b/drivers/frame_provider/decoder/utils/vdec_power_ctrl.h
new file mode 100644
index 0000000..e7ab77e
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/vdec_power_ctrl.h
@@ -0,0 +1,107 @@
+/*
+ * drivers/amlogic/media/frame_provider/decoder/utils/vdec_power_ctrl.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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+#include "vdec.h"
+
+/* Directly controlled by reading and writing registers. */
+#define PM_POWER_CTRL_RW_REG (0)
+
+/* Use power_ctrl_xxx family of interface controls. */
+#define PM_POWER_CTRL_API (1)
+
+/*
+ * Power Domain interface control, currently supported
+ * in versions 4.19 and above.
+ */
+#define PM_POWER_DOMAIN (2)
+
+/*
+ * Controlled by the secure API provided by power domain,
+ * version 4.9 supports currently supported platforms (SC2).
+ */
+#define PM_POWER_DOMAIN_SEC_API (3)
+
+/*
+ * Use non-secure API control through power domain, version 4.9 support,
+ * currently supported platforms (SM1, TM2, TM2-revB).
+ */
+#define PM_POWER_DOMAIN_NONSEC_API (4)
+
+enum pm_pd_e {
+ PD_VDEC,
+ PD_HCODEC,
+ PD_VDEC2,
+ PD_HEVC,
+ PD_HEVCB,
+ PD_WAVE,
+ PD_MAX
+};
+
+struct pm_pd_s {
+ u8 *name;
+ struct device *dev;
+ struct device_link *link;
+};
+
+struct power_manager_s {
+ int pm_type;
+ struct pm_pd_s *pd_data;
+ int (*init) (struct device *dev);
+ void (*release) (struct device *dev);
+ void (*power_on) (struct device *dev, int id);
+ void (*power_off) (struct device *dev, int id);
+ bool (*power_state) (struct device *dev, int id);
+};
+
+const char *get_pm_name(int type);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
+#define DL_FLAG_STATELESS BIT(0)
+#define DL_FLAG_AUTOREMOVE_CONSUMER BIT(1)
+#define DL_FLAG_PM_RUNTIME BIT(2)
+#define DL_FLAG_RPM_ACTIVE BIT(3)
+#define DL_FLAG_AUTOREMOVE_SUPPLIER BIT(4)
+
+struct device_link {
+ u32 flags;
+ /* ... */
+};
+
+static inline struct device *dev_pm_domain_attach_by_name(struct device *dev,
+ const char *name)
+ { return NULL; }
+static inline struct device_link *device_link_add(struct device *consumer,
+ struct device *supplier, u32 flags)
+ { return NULL; }
+static inline void device_link_del(struct device_link *link) { return; }
+static inline void device_link_remove(void *consumer, struct device *supplier) { return; }
+#endif
+
diff --git a/drivers/frame_provider/decoder/utils/vdec_profile.c b/drivers/frame_provider/decoder/utils/vdec_profile.c
new file mode 100644
index 0000000..94f8b8f
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/vdec_profile.c
@@ -0,0 +1,480 @@
+/*
+ * drivers/amlogic/amports/vdec_profile.c
+ *
+ * Copyright (C) 2016 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+*/
+
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/debugfs.h>
+#include <linux/moduleparam.h>
+
+
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include <trace/events/meson_atrace.h>
+#include "vdec_profile.h"
+#include "vdec.h"
+
+
+#define ISA_TIMERE 0x2662
+#define ISA_TIMERE_HI 0x2663
+
+#define PROFILE_REC_SIZE 40
+
+static DEFINE_MUTEX(vdec_profile_mutex);
+static int rec_wp;
+static bool rec_wrapped;
+static uint dec_time_stat_flag;
+static uint dec_time_stat_reset;
+
+
+struct dentry *root, *event;
+
+#define MAX_INSTANCE_MUN 9
+
+struct vdec_profile_time_stat_s {
+ int time_6ms_less_cnt;
+ int time_6_9ms_cnt;
+ int time_9_12ms_cnt;
+ int time_12_15ms_cnt;
+ int time_15_18ms_cnt;
+ int time_18_21ms_cnt;
+ int time_21ms_up_cnt;
+ u64 time_max_us;
+ u64 time_total_us;
+};
+
+struct vdec_profile_statistics_s {
+ bool status;
+ u64 run_lasttimestamp;
+ int run_cnt;
+ u64 cb_lasttimestamp;
+ int cb_cnt;
+ u64 decode_first_us;
+ struct vdec_profile_time_stat_s run2cb_time_stat;
+ struct vdec_profile_time_stat_s decode_time_stat;
+};
+
+static struct vdec_profile_statistics_s statistics_s[MAX_INSTANCE_MUN];
+
+
+struct vdec_profile_rec_s {
+ struct vdec_s *vdec;
+ u64 timestamp;
+ int event;
+ int para1;
+ int para2;
+};
+
+static struct vdec_profile_rec_s recs[PROFILE_REC_SIZE];
+static const char *event_name[VDEC_PROFILE_MAX_EVENT] = {
+ "run",
+ "cb",
+ "save_input",
+ "check run ready",
+ "run ready",
+ "disconnect",
+ "dec_work",
+ "info"
+};
+
+#if 0 /* get time from hardware. */
+static u64 get_us_time_hw(void)
+{
+ u32 lo, hi1, hi2;
+ int offset = 0;
+
+ /* txlx, g12a isa register base is 0x3c00 */
+ if (get_cpu_major_id() >= MESON_CPU_MAJOR_ID_TXLX)
+ offset = 0x1600;
+
+ do {
+ hi1 = READ_MPEG_REG(ISA_TIMERE_HI + offset);
+ lo = READ_MPEG_REG(ISA_TIMERE + offset);
+ hi2 = READ_MPEG_REG(ISA_TIMERE_HI + offset);
+ } while (hi1 != hi2);
+
+ return (((u64)hi1) << 32) | lo;
+}
+#endif
+
+static u64 get_us_time_system(void)
+{
+ struct timeval tv;
+
+ do_gettimeofday(&tv);
+
+ return div64_u64(timeval_to_ns(&tv), 1000);
+}
+
+static void vdec_profile_update_alloc_time(
+ struct vdec_profile_time_stat_s *time_stat, u64 startus, u64 endus)
+{
+ u64 spend_time_us = endus - startus;
+
+ if (spend_time_us > 0 && spend_time_us < 100000000) {
+ if (spend_time_us < 6000)
+ time_stat->time_6ms_less_cnt++;
+ else if (spend_time_us < 9000)
+ time_stat->time_6_9ms_cnt++;
+ else if (spend_time_us < 12000)
+ time_stat->time_9_12ms_cnt++;
+ else if (spend_time_us < 15000)
+ time_stat->time_12_15ms_cnt++;
+ else if (spend_time_us < 18000)
+ time_stat->time_15_18ms_cnt++;
+ else if (spend_time_us < 21000)
+ time_stat->time_18_21ms_cnt++;
+ else
+ time_stat->time_21ms_up_cnt++;
+ }
+
+ if (spend_time_us > time_stat->time_max_us)
+ time_stat->time_max_us = spend_time_us;
+
+ time_stat->time_total_us += spend_time_us;
+}
+
+
+static void vdec_profile_statistics(struct vdec_s *vdec, int event)
+{
+ struct vdec_profile_statistics_s *time_stat = NULL;
+ u64 timestamp;
+ int i;
+
+ if (vdec->id >= MAX_INSTANCE_MUN)
+ return;
+
+ if (event != VDEC_PROFILE_EVENT_RUN &&
+ event != VDEC_PROFILE_EVENT_CB)
+ return;
+
+ mutex_lock(&vdec_profile_mutex);
+
+ if (dec_time_stat_reset == 1) {
+ if (event != VDEC_PROFILE_EVENT_RUN) {
+ mutex_unlock(&vdec_profile_mutex);
+ return;
+ }
+ for (i = 0; i < MAX_INSTANCE_MUN; i++)
+ memset(&statistics_s[i], 0,
+ sizeof(struct vdec_profile_statistics_s));
+ dec_time_stat_reset = 0;
+ }
+
+ time_stat = &statistics_s[vdec->id];
+ timestamp = get_us_time_system();
+
+ if (time_stat->status == false) {
+ time_stat->decode_first_us = timestamp;
+ time_stat->status = true;
+ }
+
+ if (event == VDEC_PROFILE_EVENT_RUN) {
+ time_stat->run_lasttimestamp = timestamp;
+ time_stat->run_cnt++;
+ } else if (event == VDEC_PROFILE_EVENT_CB) {
+ /*run2cb statistics*/
+ vdec_profile_update_alloc_time(&time_stat->run2cb_time_stat, time_stat->run_lasttimestamp, timestamp);
+
+ /*decode statistics*/
+ if (time_stat->cb_cnt == 0)
+ vdec_profile_update_alloc_time(&time_stat->decode_time_stat, time_stat->decode_first_us, timestamp);
+ else
+ vdec_profile_update_alloc_time(&time_stat->decode_time_stat, time_stat->cb_lasttimestamp, timestamp);
+
+ time_stat->cb_lasttimestamp = timestamp;
+ time_stat->cb_cnt++;
+ ATRACE_COUNTER(vdec->dec_spend_time, timestamp - time_stat->run_lasttimestamp);
+ ATRACE_COUNTER(vdec->dec_spend_time_ave, div_u64(time_stat->run2cb_time_stat.time_total_us, time_stat->cb_cnt));
+ }
+
+ mutex_unlock(&vdec_profile_mutex);
+}
+
+
+void vdec_profile_more(struct vdec_s *vdec, int event, int para1, int para2)
+{
+ mutex_lock(&vdec_profile_mutex);
+
+ recs[rec_wp].vdec = vdec;
+ recs[rec_wp].timestamp = get_us_time_system();
+ recs[rec_wp].event = event;
+ recs[rec_wp].para1 = para1;
+ recs[rec_wp].para2 = para2;
+
+ rec_wp++;
+ if (rec_wp == PROFILE_REC_SIZE) {
+ rec_wrapped = true;
+ rec_wp = 0;
+ }
+
+ mutex_unlock(&vdec_profile_mutex);
+}
+EXPORT_SYMBOL(vdec_profile_more);
+
+void vdec_profile(struct vdec_s *vdec, int event)
+{
+ ATRACE_COUNTER(vdec->vfm_map_id, event);
+ vdec_profile_more(vdec, event, 0 , 0);
+ if (dec_time_stat_flag == 1)
+ vdec_profile_statistics(vdec, event);
+}
+EXPORT_SYMBOL(vdec_profile);
+
+void vdec_profile_flush(struct vdec_s *vdec)
+{
+ int i;
+
+ if (vdec->id >= MAX_INSTANCE_MUN)
+ return;
+
+ mutex_lock(&vdec_profile_mutex);
+
+ for (i = 0; i < PROFILE_REC_SIZE; i++) {
+ if (recs[i].vdec == vdec)
+ recs[i].vdec = NULL;
+ }
+
+ memset(&statistics_s[vdec->id], 0, sizeof(struct vdec_profile_statistics_s));
+
+ mutex_unlock(&vdec_profile_mutex);
+}
+
+static const char *event_str(int event)
+{
+ if (event < VDEC_PROFILE_MAX_EVENT)
+ return event_name[event];
+
+ return "INVALID";
+}
+
+static int vdec_profile_dbg_show(struct seq_file *m, void *v)
+{
+ int i, end;
+ u64 base_timestamp;
+
+ mutex_lock(&vdec_profile_mutex);
+
+ if (rec_wrapped) {
+ i = rec_wp;
+ end = rec_wp;
+ } else {
+ i = 0;
+ end = rec_wp;
+ }
+
+ base_timestamp = recs[i].timestamp;
+ while (1) {
+ if ((!rec_wrapped) && (i == end))
+ break;
+
+ if (recs[i].vdec) {
+ seq_printf(m, "[%s:%d] \t%016llu us : %s (%d,%d)\n",
+ vdec_device_name_str(recs[i].vdec),
+ recs[i].vdec->id,
+ recs[i].timestamp - base_timestamp,
+ event_str(recs[i].event),
+ recs[i].para1,
+ recs[i].para2
+ );
+ } else {
+ seq_printf(m, "[%s:%d] \t%016llu us : %s (%d,%d)\n",
+ "N/A",
+ 0,
+ recs[i].timestamp - base_timestamp,
+ event_str(recs[i].event),
+ recs[i].para1,
+ recs[i].para2
+ );
+ }
+ if (++i == PROFILE_REC_SIZE)
+ i = 0;
+
+ if (rec_wrapped && (i == end))
+ break;
+ }
+
+ mutex_unlock(&vdec_profile_mutex);
+
+ return 0;
+}
+
+static int time_stat_profile_dbg_show(struct seq_file *m, void *v)
+{
+ int i;
+
+ mutex_lock(&vdec_profile_mutex);
+
+ for (i = 0; i < MAX_INSTANCE_MUN; i++)
+ {
+ if (statistics_s[i].status == false)
+ continue;
+
+ seq_printf(m, "[%d]run_cnt:%d, cb_cnt:%d\n\
+ \t\t\ttime_total_us:%llu\n\
+ \t\t\trun2cb time:\n\
+ \t\t\ttime_max_us:%llu\n\
+ \t\t\t[%d]run2cb ave_us:%llu\n\
+ \t\t\ttime_6ms_less_cnt:%d\n\
+ \t\t\ttime_6_9ms_cnt:%d\n\
+ \t\t\ttime_9_12ms_cnt:%d\n\
+ \t\t\ttime_12_15ms_cnt:%d\n\
+ \t\t\ttime_15_18ms_cnt:%d\n\
+ \t\t\ttime_18_21ms_cnt:%d\n\
+ \t\t\ttime_21ms_up_cnt:%d\n\
+ \t\t\tdecode time:\n\
+ \t\t\ttime_total_us:%llu\n\
+ \t\t\ttime_max_us:%llu\n\
+ \t\t\t[%d]cb2cb ave_us:%llu\n\
+ \t\t\ttime_6ms_less_cnt:%d\n\
+ \t\t\ttime_6_9ms_cnt:%d\n\
+ \t\t\ttime_9_12ms_cnt:%d\n\
+ \t\t\ttime_12_15ms_cnt:%d\n\
+ \t\t\ttime_15_18ms_cnt:%d\n\
+ \t\t\ttime_18_21ms_cnt:%d\n\
+ \t\t\ttime_21ms_up_cnt:%d\n",
+ i,
+ statistics_s[i].run_cnt,
+ statistics_s[i].cb_cnt,
+ statistics_s[i].run2cb_time_stat.time_total_us,
+ statistics_s[i].run2cb_time_stat.time_max_us,
+ i,
+ div_u64(statistics_s[i].run2cb_time_stat.time_total_us , statistics_s[i].cb_cnt),
+ statistics_s[i].run2cb_time_stat.time_6ms_less_cnt,
+ statistics_s[i].run2cb_time_stat.time_6_9ms_cnt,
+ statistics_s[i].run2cb_time_stat.time_9_12ms_cnt,
+ statistics_s[i].run2cb_time_stat.time_12_15ms_cnt,
+ statistics_s[i].run2cb_time_stat.time_15_18ms_cnt,
+ statistics_s[i].run2cb_time_stat.time_18_21ms_cnt,
+ statistics_s[i].run2cb_time_stat.time_21ms_up_cnt,
+ statistics_s[i].decode_time_stat.time_total_us,
+ statistics_s[i].decode_time_stat.time_max_us,
+ i,
+ div_u64(statistics_s[i].decode_time_stat.time_total_us , statistics_s[i].cb_cnt),
+ statistics_s[i].decode_time_stat.time_6ms_less_cnt,
+ statistics_s[i].decode_time_stat.time_6_9ms_cnt,
+ statistics_s[i].decode_time_stat.time_9_12ms_cnt,
+ statistics_s[i].decode_time_stat.time_12_15ms_cnt,
+ statistics_s[i].decode_time_stat.time_15_18ms_cnt,
+ statistics_s[i].decode_time_stat.time_18_21ms_cnt,
+ statistics_s[i].decode_time_stat.time_21ms_up_cnt);
+ }
+
+ mutex_unlock(&vdec_profile_mutex);
+
+ return 0;
+}
+
+
+static int vdec_profile_dbg_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, vdec_profile_dbg_show, NULL);
+}
+
+static int time_stat_profile_dbg_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, time_stat_profile_dbg_show, NULL);
+}
+
+
+static const struct file_operations event_dbg_fops = {
+ .open = vdec_profile_dbg_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations time_stat_dbg_fops = {
+ .open = time_stat_profile_dbg_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+
+#if 0 /*DEBUG_TMP*/
+static int __init vdec_profile_init_debugfs(void)
+{
+ struct dentry *root, *event;
+
+ root = debugfs_create_dir("vdec_profile", NULL);
+ if (IS_ERR(root) || !root)
+ goto err;
+
+ event = debugfs_create_file("event", 0400, root, NULL,
+ &event_dbg_fops);
+ if (!event)
+ goto err_1;
+
+ mutex_init(&vdec_profile_mutex);
+
+ return 0;
+
+err_1:
+ debugfs_remove(root);
+err:
+ pr_err("Can not create debugfs for vdec_profile\n");
+ return 0;
+}
+
+#endif
+
+int vdec_profile_init_debugfs(void)
+{
+ struct dentry *root, *event, *time_stat;
+
+ root = debugfs_create_dir("vdec_profile", NULL);
+ if (IS_ERR(root) || !root)
+ goto err;
+
+ event = debugfs_create_file("event", 0400, root, NULL,
+ &event_dbg_fops);
+ if (!event)
+ goto err_1;
+
+ time_stat = debugfs_create_file("time_stat", 0400, root, NULL,
+ &time_stat_dbg_fops);
+ if (!time_stat)
+ goto err_2;
+
+ mutex_init(&vdec_profile_mutex);
+
+ return 0;
+
+err_2:
+ debugfs_remove(event);
+err_1:
+ debugfs_remove(root);
+err:
+ pr_err("Can not create debugfs for vdec_profile\n");
+ return 0;
+}
+EXPORT_SYMBOL(vdec_profile_init_debugfs);
+
+void vdec_profile_exit_debugfs(void)
+{
+ debugfs_remove(event);
+ debugfs_remove(root);
+}
+EXPORT_SYMBOL(vdec_profile_exit_debugfs);
+
+module_param(dec_time_stat_flag, uint, 0664);
+
+module_param(dec_time_stat_reset, uint, 0664);
+
+
+/*module_init(vdec_profile_init_debugfs);*/
+
diff --git a/drivers/frame_provider/decoder/utils/vdec_profile.h b/drivers/frame_provider/decoder/utils/vdec_profile.h
new file mode 100644
index 0000000..34f3bee
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/vdec_profile.h
@@ -0,0 +1,40 @@
+/*
+ * drivers/amlogic/amports/vdec_profile.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_PROFILE_H
+#define VDEC_PROFILE_H
+
+struct vdec_s;
+
+#define VDEC_PROFILE_EVENT_RUN 0
+#define VDEC_PROFILE_EVENT_CB 1
+#define VDEC_PROFILE_EVENT_SAVE_INPUT 2
+#define VDEC_PROFILE_EVENT_CHK_RUN_READY 3
+#define VDEC_PROFILE_EVENT_RUN_READY 4
+#define VDEC_PROFILE_EVENT_DISCONNECT 5
+#define VDEC_PROFILE_EVENT_DEC_WORK 6
+#define VDEC_PROFILE_EVENT_INFO 7
+#define VDEC_PROFILE_MAX_EVENT 8
+
+extern void vdec_profile(struct vdec_s *vdec, int event);
+extern void vdec_profile_more(struct vdec_s *vdec, int event, int para1, int para2);
+extern void vdec_profile_flush(struct vdec_s *vdec);
+
+int vdec_profile_init_debugfs(void);
+void vdec_profile_exit_debugfs(void);
+
+#endif /* VDEC_PROFILE_H */
diff --git a/drivers/frame_provider/decoder/utils/vdec_sync.c b/drivers/frame_provider/decoder/utils/vdec_sync.c
new file mode 100644
index 0000000..314a4f0
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/vdec_sync.c
@@ -0,0 +1,427 @@
+/*
+* 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/file.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/sync_file.h>
+#include "vdec_sync.h"
+
+#define VDEC_DBG_ENABLE_FENCE (0x100)
+
+extern u32 debug;
+
+static const struct fence_ops timeline_fence_ops;
+static inline struct sync_pt *fence_to_sync_pt(struct fence *fence)
+{
+ if (fence->ops != &timeline_fence_ops)
+ return NULL;
+ return container_of(fence, struct sync_pt, fence);
+}
+
+/**
+ * sync_timeline_create() - creates a sync object
+ * @name: sync_timeline name
+ *
+ * Creates a new sync_timeline. Returns the sync_timeline object or NULL in
+ * case of error.
+ */
+static struct sync_timeline *sync_timeline_create(const char *name)
+{
+ struct sync_timeline *obj;
+
+ obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+ if (!obj)
+ return NULL;
+
+ kref_init(&obj->kref);
+ obj->context = fence_context_alloc(1);
+ obj->timestamp = local_clock();
+ strlcpy(obj->name, name, sizeof(obj->name));
+ INIT_LIST_HEAD(&obj->active_list_head);
+ INIT_LIST_HEAD(&obj->pt_list);
+ spin_lock_init(&obj->lock);
+
+ return obj;
+}
+
+static void sync_timeline_free(struct kref *kref)
+{
+ struct sync_timeline *obj =
+ container_of(kref, struct sync_timeline, kref);
+
+ pr_info("[VDEC-FENCE] free timeline: %lx\n", (ulong) obj);
+ kfree(obj);
+}
+
+static void sync_timeline_get(struct sync_timeline *obj)
+{
+ kref_get(&obj->kref);
+}
+
+static void sync_timeline_put(struct sync_timeline *obj)
+{
+ kref_put(&obj->kref, sync_timeline_free);
+}
+
+static const char *timeline_fence_get_driver_name(struct fence *fence)
+{
+ struct sync_timeline *parent = fence_parent(fence);
+
+ return parent->name;
+}
+
+static const char *timeline_fence_get_timeline_name(struct fence *fence)
+{
+ struct sync_timeline *parent = fence_parent(fence);
+
+ return parent->name;
+}
+
+static void timeline_fence_release(struct fence *fence)
+{
+ struct sync_pt *pt = fence_to_sync_pt(fence);
+ struct sync_timeline *parent = fence_parent(fence);
+ unsigned long flags;
+
+ /*pr_info("[VDEC-FENCE] release fence: %lx\n", (ulong) fence);*/
+
+ spin_lock_irqsave(fence->lock, flags);
+ list_del(&pt->link);
+ if (!list_empty(&pt->active_list))
+ list_del(&pt->active_list);
+ spin_unlock_irqrestore(fence->lock, flags);
+ sync_timeline_put(parent);
+ fence_free(fence);
+}
+
+static bool timeline_fence_signaled(struct fence *fence)
+{
+ struct sync_timeline *parent = fence_parent(fence);
+ struct sync_pt *pt = get_sync_pt(fence);
+
+ if (__fence_is_later(fence->seqno, parent->value))
+ return false;
+
+ if (pt->timestamp > parent->timestamp)
+ return false;
+
+ return true;
+}
+
+static bool timeline_fence_enable_signaling(struct fence *fence)
+{
+ struct sync_pt *pt = container_of(fence, struct sync_pt, fence);
+ struct sync_timeline *parent = fence_parent(fence);
+
+ if (timeline_fence_signaled(fence))
+ return false;
+
+ list_add_tail(&pt->active_list, &parent->active_list_head);
+ return true;
+}
+
+static void timeline_fence_disable_signaling(struct fence *fence)
+{
+ struct sync_pt *pt = container_of(fence, struct sync_pt, fence);
+
+ list_del_init(&pt->active_list);
+}
+
+static void timeline_fence_value_str(struct fence *fence,
+ char *str, int size)
+{
+ snprintf(str, size, "%d", fence->seqno);
+}
+
+static void timeline_fence_timeline_value_str(struct fence *fence,
+ char *str, int size)
+{
+ struct sync_timeline *parent = fence_parent(fence);
+
+ snprintf(str, size, "%d", parent->value);
+}
+
+static const struct fence_ops timeline_fence_ops = {
+ .get_driver_name = timeline_fence_get_driver_name,
+ .get_timeline_name = timeline_fence_get_timeline_name,
+ .enable_signaling = timeline_fence_enable_signaling,
+ .disable_signaling = timeline_fence_disable_signaling,
+ .signaled = timeline_fence_signaled,
+ .wait = fence_default_wait,
+ .release = timeline_fence_release,
+ .fence_value_str = timeline_fence_value_str,
+ .timeline_value_str = timeline_fence_timeline_value_str,
+};
+
+/**
+ * sync_timeline_signal() - signal a status change on a sync_timeline
+ * @obj: sync_timeline to signal
+ * @inc: num to increment on timeline->value
+ *
+ * A sync implementation should call this any time one of it's fences
+ * has signaled or has an error condition.
+ */
+static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc)
+{
+ struct sync_pt *pt, *next;
+ unsigned long flags;
+
+ spin_lock_irqsave(&obj->lock, flags);
+ obj->value += inc;
+ list_for_each_entry_safe(pt, next, &obj->active_list_head,
+ active_list) {
+ if (fence_is_signaled(&pt->fence))
+ list_del_init(&pt->active_list);
+ }
+ spin_unlock_irqrestore(&obj->lock, flags);
+}
+
+/**
+ * sync_pt_create() - creates a sync pt
+ * @parent: fence's parent sync_timeline
+ * @inc: value of the fence
+ *
+ * Creates a new sync_pt as a child of @parent. @size bytes will be
+ * allocated allowing for implementation specific data to be kept after
+ * the generic sync_timeline struct. Returns the sync_pt object or
+ * NULL in case of error.
+ */
+static struct sync_pt *sync_pt_create(struct sync_timeline *obj,
+ unsigned int value)
+{
+ struct sync_pt *pt;
+ unsigned long flags;
+
+ pt = kzalloc(sizeof(*pt), GFP_KERNEL);
+ if (!pt)
+ return NULL;
+ spin_lock_irqsave(&obj->lock, flags);
+ sync_timeline_get(obj);
+ fence_init(&pt->fence, &timeline_fence_ops, &obj->lock,
+ obj->context, value);
+ list_add_tail(&pt->link, &obj->pt_list);
+ INIT_LIST_HEAD(&pt->active_list);
+ spin_unlock_irqrestore(&obj->lock, flags);
+
+ return pt;
+}
+
+static void sync_pt_free(struct sync_timeline *obj,
+ struct sync_pt *pt)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&obj->lock, flags);
+ list_del(&pt->link);
+ sync_timeline_put(obj);
+ spin_unlock_irqrestore(&obj->lock, flags);
+ kfree(pt);
+ pt = NULL;
+}
+
+static int timeline_create_fence(struct vdec_sync *sync, int usage,
+ struct fence **fence, int *fd, u32 value)
+{
+ int ret;
+ struct sync_pt *pt;
+ struct sync_file *sync_file;
+ struct sync_timeline *obj = sync->timeline;
+
+ if (obj == NULL)
+ return -EPERM;
+
+ pt = sync_pt_create(obj, value);
+ if (!pt) {
+ return -ENOMEM;
+ }
+
+ if (usage == FENCE_USE_FOR_APP) {
+ *fd = get_unused_fd_flags(O_CLOEXEC);
+ if (*fd < 0) {
+ ret = -EBADF;
+ goto err;
+ }
+
+ sync_file = sync_file_create(&pt->fence);
+ if (!sync_file) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ fd_install(*fd, sync_file->file);
+
+ /* decreases refcnt. */
+ fence_put(&pt->fence);
+ }
+
+ *fence = &pt->fence;
+
+ pt->timestamp = local_clock();
+
+ if (debug & VDEC_DBG_ENABLE_FENCE)
+ pr_info("[VDEC-FENCE]: create fence: %lx, fd: %d, ref: %d, usage: %d\n",
+ (ulong) &pt->fence, *fd, atomic_read(&pt->fence.refcount.refcount), usage);
+ return 0;
+err:
+ put_unused_fd(*fd);
+ if (pt)
+ sync_pt_free(obj, pt);
+
+ return ret;
+}
+
+struct fence *vdec_fence_get(int fd)
+{
+ return sync_file_get_fence(fd);
+}
+EXPORT_SYMBOL(vdec_fence_get);
+
+void vdec_fence_put(struct fence *fence)
+{
+ if (debug & VDEC_DBG_ENABLE_FENCE)
+ pr_info("[VDEC-FENCE]: the fence (%px) cost time: %lld ns\n",
+ fence, local_clock() - get_sync_pt(fence)->timestamp);
+ fence_put(fence);
+}
+EXPORT_SYMBOL(vdec_fence_put);
+
+int vdec_fence_wait(struct fence *fence, long timeout)
+{
+ if (debug & VDEC_DBG_ENABLE_FENCE)
+ pr_info("[VDEC-FENCE]: wait fence %lx.\n", (ulong) fence);
+
+ return fence_wait_timeout(fence, false, timeout);
+}
+EXPORT_SYMBOL(vdec_fence_wait);
+
+void vdec_timeline_create(struct vdec_sync *sync, u8 *name)
+{
+ snprintf(sync->name, sizeof(sync->name), "%s", name);
+
+ sync->timeline = (void *)sync_timeline_create(sync->name);
+ if (sync->timeline)
+ pr_info("[VDEC-FENCE]: create timeline %lx, name: %s\n",
+ (ulong) sync->timeline, sync->name);
+ else
+ pr_err("[VDEC-FENCE]: create timeline faild.\n");
+}
+EXPORT_SYMBOL(vdec_timeline_create);
+
+int vdec_timeline_create_fence(struct vdec_sync *sync)
+{
+ struct sync_timeline *obj = sync->timeline;
+ struct sync_pt *pt = NULL;
+ ulong flags;
+ u32 value = 0;
+
+ if (obj == NULL)
+ return -EPERM;
+
+ spin_lock_irqsave(&obj->lock, flags);
+
+ pt = list_last_entry(&obj->pt_list, struct sync_pt, link);
+ value = obj->value + 1;
+
+ if (!list_empty(&obj->pt_list)) {
+ pt = list_last_entry(&obj->pt_list, struct sync_pt, link);
+ if (value == pt->fence.seqno) {
+ value++;
+ }
+ }
+ spin_unlock_irqrestore(&obj->lock, flags);
+
+ return timeline_create_fence(sync,
+ sync->usage,
+ &sync->fence,
+ &sync->fd,
+ value);
+}
+EXPORT_SYMBOL(vdec_timeline_create_fence);
+
+void vdec_timeline_increase(struct vdec_sync *sync, u32 value)
+{
+ struct sync_timeline *obj = sync->timeline;
+
+ if (obj == NULL)
+ return;
+
+ obj->timestamp = local_clock();
+
+ if (debug & VDEC_DBG_ENABLE_FENCE)
+ pr_info("[VDEC-FENCE]: update timeline %d.\n",
+ obj->value + value);
+
+ sync_timeline_signal(obj, value);
+}
+EXPORT_SYMBOL(vdec_timeline_increase);
+
+void vdec_timeline_put(struct vdec_sync *sync)
+{
+ struct sync_timeline *obj = sync->timeline;
+
+ sync_timeline_put(obj);
+}
+EXPORT_SYMBOL(vdec_timeline_put);
+
+void vdec_fence_status_set(struct fence *fence, int status)
+{
+ fence->error = status;
+}
+EXPORT_SYMBOL(vdec_fence_status_set);
+
+int vdec_fence_status_get(struct fence *fence)
+{
+ return fence_get_status(fence);
+}
+EXPORT_SYMBOL(vdec_fence_status_get);
+
+bool check_objs_all_signaled(struct vdec_sync *sync)
+{
+ struct sync_timeline *obj = sync->timeline;
+ bool ret = false;
+ ulong flags;
+
+ spin_lock_irqsave(&obj->lock, flags);
+ ret = list_empty(&obj->active_list_head);
+ spin_unlock_irqrestore(&obj->lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(check_objs_all_signaled);
+
+int vdec_clean_all_fence(struct vdec_sync *sync)
+{
+ struct sync_timeline *obj = sync->timeline;
+ struct sync_pt *pt, *next;
+
+ spin_lock_irq(&obj->lock);
+
+ list_for_each_entry_safe(pt, next, &obj->pt_list, link) {
+ fence_set_error(&pt->fence, -ENOENT);
+ fence_signal_locked(&pt->fence);
+ }
+
+ spin_unlock_irq(&obj->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(vdec_clean_all_fence);
+
diff --git a/drivers/frame_provider/decoder/utils/vdec_sync.h b/drivers/frame_provider/decoder/utils/vdec_sync.h
new file mode 100644
index 0000000..0622341
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/vdec_sync.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:
+*/
+#include <linux/list.h>
+#include <linux/rbtree.h>
+#include <linux/spinlock.h>
+#include <linux/fence.h>
+#include <linux/sync_file.h>
+#include <uapi/linux/sync_file.h>
+
+#define FENCE_USE_FOR_DRIVER (0)
+#define FENCE_USE_FOR_APP (1)
+
+struct sync_timeline {
+ struct kref kref;
+ char name[32];
+
+ /* protected by lock */
+ u64 context;
+ u32 value;
+
+ struct list_head active_list_head;
+ struct list_head pt_list;
+ spinlock_t lock;
+
+ u64 timestamp;
+};
+
+struct sync_pt {
+ struct fence fence;
+ struct list_head link;
+ struct list_head active_list;
+ u64 timestamp;
+};
+
+struct vdec_sync {
+ u8 name[32];
+ void *timeline;
+ int usage;
+ int fd;
+ struct fence *fence;
+};
+
+static inline struct sync_timeline *fence_parent(struct fence *fence)
+{
+ return container_of(fence->lock, struct sync_timeline, lock);
+}
+
+static inline struct sync_pt *get_sync_pt(struct fence *fence)
+{
+ return container_of(fence, struct sync_pt, fence);
+}
+
+struct fence *vdec_fence_get(int fd);
+
+void vdec_fence_put(struct fence *fence);
+
+int vdec_fence_wait(struct fence *fence, long timeout);
+
+void vdec_timeline_create(struct vdec_sync *sync, u8 *name);
+
+int vdec_timeline_create_fence(struct vdec_sync *sync);
+
+void vdec_timeline_increase(struct vdec_sync *sync, u32 value);
+
+void vdec_timeline_put(struct vdec_sync *sync);
+
+int vdec_fence_status_get(struct fence *fence);
+
+void vdec_fence_status_set(struct fence *fence, int status);
+
+bool check_objs_all_signaled(struct vdec_sync *sync);
+
+int vdec_clean_all_fence(struct vdec_sync *sync);
+
diff --git a/drivers/frame_provider/decoder/utils/vdec_trace.h b/drivers/frame_provider/decoder/utils/vdec_trace.h
new file mode 100644
index 0000000..e09518e
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/vdec_trace.h
@@ -0,0 +1,149 @@
+/*
+ * drivers/amlogic/amports/vdec_trace.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.
+ *
+*/
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM vdec
+
+#if !defined(_VDEC_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _VDEC_TRACE_H
+
+#include <linux/tracepoint.h>
+
+struct vdec_s;
+
+/* single lifecycle events */
+DECLARE_EVENT_CLASS(vdec_event_class,
+ TP_PROTO(struct vdec_s *vdec),
+ TP_ARGS(vdec),
+ TP_STRUCT__entry(
+ __field(struct vdec_s *, vdec)
+ ),
+ TP_fast_assign(
+ __entry->vdec = vdec;
+ ),
+ TP_printk("[%p]", __entry->vdec)
+);
+
+#define DEFINE_VDEC_EVENT(name) \
+DEFINE_EVENT(vdec_event_class, name, \
+ TP_PROTO(struct vdec_s *vdec), \
+ TP_ARGS(vdec))
+
+DEFINE_VDEC_EVENT(vdec_create);
+DEFINE_VDEC_EVENT(vdec_connect);
+DEFINE_VDEC_EVENT(vdec_disconnect);
+DEFINE_VDEC_EVENT(vdec_destroy);
+DEFINE_VDEC_EVENT(vdec_reset);
+DEFINE_VDEC_EVENT(vdec_release);
+
+/* set format event */
+#define format_name(format) \
+ __print_symbolic(format, \
+ {0, "MPEG"}, \
+ {1, "MPEG4"}, \
+ {2, "H264"}, \
+ {3, "MJPEG"}, \
+ {4, "REAL"}, \
+ {5, "JPEG"}, \
+ {6, "VC1"}, \
+ {7, "AVS"}, \
+ {8, "YUV"}, \
+ {9, "H264MVC"}, \
+ {10, "H264_4K2K"}, \
+ {11, "H265"}, \
+ {12, "ENC_AVC"}, \
+ {13, "ENC_JPEG"}, \
+ {14, "VP9"})
+
+TRACE_EVENT(vdec_set_format,
+ TP_PROTO(struct vdec_s *vdec, int format),
+ TP_ARGS(vdec, format),
+ TP_STRUCT__entry(
+ __field(struct vdec_s *, vdec)
+ __field(int, format)
+ ),
+ TP_fast_assign(
+ __entry->vdec = vdec;
+ __entry->format = format;
+ ),
+ TP_printk("[%p]:%s", __entry->vdec,
+ format_name(__entry->format))
+);
+
+/* status events */
+#define status_name(status) \
+ __print_symbolic(status, \
+ {0, "UNINITIALIZED"}, \
+ {1, "DISCONNECTED"}, \
+ {2, "CONNECTED"}, \
+ {3, "ACTIVE"})
+
+DECLARE_EVENT_CLASS(vdec_status_class,
+ TP_PROTO(struct vdec_s *vdec, int state),
+ TP_ARGS(vdec, state),
+ TP_STRUCT__entry(
+ __field(struct vdec_s *, vdec)
+ __field(int, state)
+ ),
+ TP_fast_assign(
+ __entry->vdec = vdec;
+ __entry->state = state;
+ ),
+ TP_printk("[%p]:%s", __entry->vdec, status_name(__entry->state))
+);
+
+#define DEFINE_STATUS_EVENT(name) \
+DEFINE_EVENT(vdec_status_class, name, \
+ TP_PROTO(struct vdec_s *vdec, int status), \
+ TP_ARGS(vdec, status))
+
+DEFINE_STATUS_EVENT(vdec_set_status);
+DEFINE_STATUS_EVENT(vdec_set_next_status);
+
+/* set pts events */
+DECLARE_EVENT_CLASS(vdec_pts_class,
+ TP_PROTO(struct vdec_s *vdec, u64 pts),
+ TP_ARGS(vdec, pts),
+ TP_STRUCT__entry(
+ __field(struct vdec_s *, vdec)
+ __field(u64, pts)
+ ),
+ TP_fast_assign(
+ __entry->vdec = vdec;
+ __entry->pts = pts;
+ ),
+ TP_printk("[%p]%llu", __entry->vdec, __entry->pts)
+);
+
+#define DEFINE_PTS_EVENT(name) \
+DEFINE_EVENT(vdec_pts_class, name, \
+ TP_PROTO(struct vdec_s *vdec, u64 pts), \
+ TP_ARGS(vdec, pts))
+
+DEFINE_PTS_EVENT(vdec_set_pts);
+DEFINE_PTS_EVENT(vdec_set_pts64);
+
+#endif /* _VDEC_TRACE_H */
+
+/*
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE vdec_trace
+#include <trace/define_trace.h>
+*/
+/**/ //DEBUG_TMP
diff --git a/drivers/frame_provider/decoder/utils/vdec_v4l2_buffer_ops.c b/drivers/frame_provider/decoder/utils/vdec_v4l2_buffer_ops.c
new file mode 100644
index 0000000..e892127
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/vdec_v4l2_buffer_ops.c
@@ -0,0 +1,187 @@
+/*
+* 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 "vdec_v4l2_buffer_ops.h"
+#include <media/v4l2-mem2mem.h>
+#include <linux/printk.h>
+
+int vdec_v4l_get_buffer(struct aml_vcodec_ctx *ctx,
+ struct vdec_v4l2_buffer **out)
+{
+ int ret = -1;
+
+ if (ctx->drv_handle == 0)
+ return -EIO;
+
+ ret = ctx->dec_if->get_param(ctx->drv_handle,
+ GET_PARAM_FREE_FRAME_BUFFER, out);
+
+ return ret;
+}
+EXPORT_SYMBOL(vdec_v4l_get_buffer);
+
+int vdec_v4l_get_pic_info(struct aml_vcodec_ctx *ctx,
+ struct vdec_pic_info *pic)
+{
+ int ret = 0;
+
+ if (ctx->drv_handle == 0)
+ return -EIO;
+
+ ret = ctx->dec_if->get_param(ctx->drv_handle,
+ GET_PARAM_PIC_INFO, pic);
+
+ return ret;
+}
+EXPORT_SYMBOL(vdec_v4l_get_pic_info);
+
+int vdec_v4l_set_ps_infos(struct aml_vcodec_ctx *ctx,
+ struct aml_vdec_ps_infos *ps)
+{
+ int ret = 0;
+
+ if (ctx->drv_handle == 0)
+ return -EIO;
+
+ ret = ctx->dec_if->set_param(ctx->drv_handle,
+ SET_PARAM_PS_INFO, ps);
+
+ return ret;
+}
+EXPORT_SYMBOL(vdec_v4l_set_ps_infos);
+
+int vdec_v4l_set_hdr_infos(struct aml_vcodec_ctx *ctx,
+ struct aml_vdec_hdr_infos *hdr)
+{
+ int ret = 0;
+
+ if (ctx->drv_handle == 0)
+ return -EIO;
+
+ ret = ctx->dec_if->set_param(ctx->drv_handle,
+ SET_PARAM_HDR_INFO, hdr);
+
+ return ret;
+}
+EXPORT_SYMBOL(vdec_v4l_set_hdr_infos);
+
+static void aml_wait_dpb_ready(struct aml_vcodec_ctx *ctx)
+{
+ ulong expires;
+
+ expires = jiffies + msecs_to_jiffies(1000);
+ while (!ctx->v4l_codec_dpb_ready) {
+ u32 ready_num = 0;
+
+ if (time_after(jiffies, expires)) {
+ pr_err("the DPB state has not ready.\n");
+ break;
+ }
+
+ ready_num = v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx);
+ if ((ready_num + ctx->buf_used_count) >= ctx->dpb_size)
+ ctx->v4l_codec_dpb_ready = true;
+ }
+}
+
+void aml_vdec_pic_info_update(struct aml_vcodec_ctx *ctx)
+{
+ unsigned int dpbsize = 0;
+ int ret;
+
+ if (ctx->dec_if->get_param(ctx->drv_handle, GET_PARAM_PIC_INFO, &ctx->last_decoded_picinfo)) {
+ pr_err("Cannot get param : GET_PARAM_PICTURE_INFO ERR\n");
+ return;
+ }
+
+ if (ctx->last_decoded_picinfo.visible_width == 0 ||
+ ctx->last_decoded_picinfo.visible_height == 0 ||
+ ctx->last_decoded_picinfo.coded_width == 0 ||
+ ctx->last_decoded_picinfo.coded_height == 0) {
+ pr_err("Cannot get correct pic info\n");
+ return;
+ }
+
+ ret = ctx->dec_if->get_param(ctx->drv_handle, GET_PARAM_DPB_SIZE, &dpbsize);
+ if (dpbsize == 0)
+ pr_err("Incorrect dpb size, ret=%d\n", ret);
+
+ /* update picture information */
+ ctx->dpb_size = dpbsize;
+ ctx->picinfo = ctx->last_decoded_picinfo;
+}
+
+int vdec_v4l_post_evet(struct aml_vcodec_ctx *ctx, u32 event)
+{
+ int ret = 0;
+
+ if (ctx->drv_handle == 0)
+ return -EIO;
+ if (event == 1)
+ ctx->reset_flag = 2;
+ ret = ctx->dec_if->set_param(ctx->drv_handle,
+ SET_PARAM_POST_EVENT, &event);
+
+ return ret;
+}
+EXPORT_SYMBOL(vdec_v4l_post_evet);
+
+int vdec_v4l_res_ch_event(struct aml_vcodec_ctx *ctx)
+{
+ int ret = 0;
+ struct aml_vcodec_dev *dev = ctx->dev;
+
+ if (ctx->drv_handle == 0)
+ return -EIO;
+
+ /* wait the DPB state to be ready. */
+ aml_wait_dpb_ready(ctx);
+
+ aml_vdec_pic_info_update(ctx);
+
+ mutex_lock(&ctx->state_lock);
+
+ ctx->state = AML_STATE_FLUSHING;/*prepare flushing*/
+
+ pr_info("[%d]: vcodec state (AML_STATE_FLUSHING-RESCHG)\n", ctx->id);
+
+ mutex_unlock(&ctx->state_lock);
+
+ ctx->q_data[AML_Q_DATA_SRC].resolution_changed = true;
+ v4l2_m2m_job_pause(dev->m2m_dev_dec, ctx->m2m_ctx);
+
+ return ret;
+}
+EXPORT_SYMBOL(vdec_v4l_res_ch_event);
+
+
+int vdec_v4l_write_frame_sync(struct aml_vcodec_ctx *ctx)
+{
+ int ret = 0;
+
+ if (ctx->drv_handle == 0)
+ return -EIO;
+
+ ret = ctx->dec_if->set_param(ctx->drv_handle,
+ SET_PARAM_WRITE_FRAME_SYNC, NULL);
+
+ return ret;
+}
+EXPORT_SYMBOL(vdec_v4l_write_frame_sync);
+
diff --git a/drivers/frame_provider/decoder/utils/vdec_v4l2_buffer_ops.h b/drivers/frame_provider/decoder/utils/vdec_v4l2_buffer_ops.h
new file mode 100644
index 0000000..1494f10
--- /dev/null
+++ b/drivers/frame_provider/decoder/utils/vdec_v4l2_buffer_ops.h
@@ -0,0 +1,52 @@
+/*
+* 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_VDEC_V4L2_BUFFER_H_
+#define _AML_VDEC_V4L2_BUFFER_H_
+
+#include "../../../amvdec_ports/vdec_drv_base.h"
+#include "../../../amvdec_ports/aml_vcodec_adapt.h"
+
+int vdec_v4l_get_buffer(
+ struct aml_vcodec_ctx *ctx,
+ struct vdec_v4l2_buffer **out);
+
+int vdec_v4l_get_pic_info(
+ struct aml_vcodec_ctx *ctx,
+ struct vdec_pic_info *pic);
+
+int vdec_v4l_set_ps_infos(
+ struct aml_vcodec_ctx *ctx,
+ struct aml_vdec_ps_infos *ps);
+
+int vdec_v4l_set_hdr_infos(
+ struct aml_vcodec_ctx *ctx,
+ struct aml_vdec_hdr_infos *hdr);
+
+int vdec_v4l_write_frame_sync(
+ struct aml_vcodec_ctx *ctx);
+
+int vdec_v4l_post_evet(
+ struct aml_vcodec_ctx *ctx,
+ u32 event);
+
+int vdec_v4l_res_ch_event(
+ struct aml_vcodec_ctx *ctx);
+
+#endif
diff --git a/drivers/frame_provider/decoder/vav1/Makefile b/drivers/frame_provider/decoder/vav1/Makefile
new file mode 100644
index 0000000..64a4973
--- /dev/null
+++ b/drivers/frame_provider/decoder/vav1/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_AV1) += amvdec_av1.o
+amvdec_av1-objs += vav1.o av1_bufmgr.o
diff --git a/drivers/frame_provider/decoder/vav1/aom_av1_define.h b/drivers/frame_provider/decoder/vav1/aom_av1_define.h
new file mode 100644
index 0000000..69e63f1
--- /dev/null
+++ b/drivers/frame_provider/decoder/vav1/aom_av1_define.h
@@ -0,0 +1,190 @@
+/*
+* 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:
+*/
+enum NalUnitType
+{
+ NAL_UNIT_CODED_SLICE_TRAIL_N = 0, // 0
+ NAL_UNIT_CODED_SLICE_TRAIL_R, // 1
+
+ NAL_UNIT_CODED_SLICE_TSA_N, // 2
+ NAL_UNIT_CODED_SLICE_TLA, // 3 // Current name in the spec: TSA_R
+
+ NAL_UNIT_CODED_SLICE_STSA_N, // 4
+ NAL_UNIT_CODED_SLICE_STSA_R, // 5
+
+ NAL_UNIT_CODED_SLICE_RADL_N, // 6
+ NAL_UNIT_CODED_SLICE_DLP, // 7 // Current name in the spec: RADL_R
+
+ NAL_UNIT_CODED_SLICE_RASL_N, // 8
+ NAL_UNIT_CODED_SLICE_TFD, // 9 // Current name in the spec: RASL_R
+
+ NAL_UNIT_RESERVED_10,
+ NAL_UNIT_RESERVED_11,
+ NAL_UNIT_RESERVED_12,
+ NAL_UNIT_RESERVED_13,
+ NAL_UNIT_RESERVED_14,
+ NAL_UNIT_RESERVED_15,
+
+ NAL_UNIT_CODED_SLICE_BLA, // 16 // Current name in the spec: BLA_W_LP
+ NAL_UNIT_CODED_SLICE_BLANT, // 17 // Current name in the spec: BLA_W_DLP
+ NAL_UNIT_CODED_SLICE_BLA_N_LP, // 18
+ NAL_UNIT_CODED_SLICE_IDR, // 19 // Current name in the spec: IDR_W_DLP
+ 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,
+};
+
+int forbidden_zero_bit;
+int m_nalUnitType;
+int m_reservedZero6Bits;
+int m_temporalId;
+
+//---------------------------------------------------
+// Amrisc Software Interrupt
+//---------------------------------------------------
+#define AMRISC_STREAM_EMPTY_REQ 0x01
+#define AMRISC_PARSER_REQ 0x02
+#define AMRISC_MAIN_REQ 0x04
+
+//---------------------------------------------------
+// AOM_AV1_DEC_STATUS (HEVC_DEC_STATUS) define
+//---------------------------------------------------
+ /*command*/
+#define AOM_AV1_DEC_IDLE 0
+#define AOM_AV1_DEC_FRAME_HEADER 1
+#define AOM_AV1_DEC_TILE_END 2
+#define AOM_AV1_DEC_TG_END 3
+#define AOM_AV1_DEC_LCU_END 4
+#define AOM_AV1_DECODE_SLICE 5
+#define AOM_AV1_SEARCH_HEAD 6
+#define AOM_AV1_DUMP_LMEM 7
+#define AOM_AV1_FGS_PARAM_CONT 8
+#define AOM_AV1_FGS_PARAM_CONT 8
+#define AOM_AV1_PIC_END_CONT 9
+ /*status*/
+#define AOM_AV1_DEC_PIC_END 0xe0
+ /*AOM_AV1_FGS_PARA:
+ Bit[11] - 0 Read, 1 - Write
+ Bit[10:8] - film_grain_params_ref_idx, For Write request
+ */
+#define AOM_AV1_FGS_PARAM 0xe1
+#define AOM_AV1_DEC_PIC_END_PRE 0xe2
+#define AOM_AV1_HEAD_PARSER_DONE 0xf0
+#define AOM_AV1_HEAD_SEARCH_DONE 0xf1
+#define AOM_AV1_SEQ_HEAD_PARSER_DONE 0xf2
+#define AOM_AV1_FRAME_HEAD_PARSER_DONE 0xf3
+#define AOM_AV1_FRAME_PARSER_DONE 0xf4
+#define AOM_AV1_REDUNDANT_FRAME_HEAD_PARSER_DONE 0xf5
+#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
+
+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
+};
diff --git a/drivers/frame_provider/decoder/vav1/av1_bufmgr.c b/drivers/frame_provider/decoder/vav1/av1_bufmgr.c
new file mode 100644
index 0000000..41a522f
--- /dev/null
+++ b/drivers/frame_provider/decoder/vav1/av1_bufmgr.c
@@ -0,0 +1,3389 @@
+/*
+* 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 CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#else
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/amlogic/media/canvas/canvas.h>
+
+#undef pr_info
+#define pr_info printk
+
+#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
+ */
+ }
+}
+
+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 */
+}
+
+#endif
+
+#include "av1_global.h"
+int aom_realloc_frame_buffer(AV1_COMMON *cm, PIC_BUFFER_CONFIG *pic,
+ int width, int height, unsigned int order_hint);
+void dump_params(AV1Decoder *pbi, union param_u *params);
+
+#define assert(a)
+#define IMPLIES(a)
+
+int new_compressed_data_count = 0;
+
+static int valid_ref_frame_size(int ref_width, int ref_height,
+ int this_width, int this_height) {
+ return 2 * this_width >= ref_width && 2 * this_height >= ref_height &&
+ this_width <= 16 * ref_width && this_height <= 16 * ref_height;
+}
+
+#ifdef SUPPORT_SCALE_FACTOR
+// Note: Expect val to be in q4 precision
+static inline int scaled_x(int val, const struct scale_factors *sf) {
+ const int off =
+ (sf->x_scale_fp - (1 << REF_SCALE_SHIFT)) * (1 << (SUBPEL_BITS - 1));
+ const int64_t tval = (int64_t)val * sf->x_scale_fp + off;
+ return (int)ROUND_POWER_OF_TWO_SIGNED_64(tval,
+ REF_SCALE_SHIFT - SCALE_EXTRA_BITS);
+}
+
+// Note: Expect val to be in q4 precision
+static inline int scaled_y(int val, const struct scale_factors *sf) {
+ const int off =
+ (sf->y_scale_fp - (1 << REF_SCALE_SHIFT)) * (1 << (SUBPEL_BITS - 1));
+ const int64_t tval = (int64_t)val * sf->y_scale_fp + off;
+ return (int)ROUND_POWER_OF_TWO_SIGNED_64(tval,
+ REF_SCALE_SHIFT - SCALE_EXTRA_BITS);
+}
+
+// Note: Expect val to be in q4 precision
+static int unscaled_value(int val, const struct scale_factors *sf) {
+ (void)sf;
+ return val << SCALE_EXTRA_BITS;
+}
+
+static int get_fixed_point_scale_factor(int other_size, int this_size) {
+ // Calculate scaling factor once for each reference frame
+ // and use fixed point scaling factors in decoding and encoding routines.
+ // Hardware implementations can calculate scale factor in device driver
+ // and use multiplication and shifting on hardware instead of division.
+ return ((other_size << REF_SCALE_SHIFT) + this_size / 2) / this_size;
+}
+
+// Given the fixed point scale, calculate coarse point scale.
+static int fixed_point_scale_to_coarse_point_scale(int scale_fp) {
+ return ROUND_POWER_OF_TWO(scale_fp, REF_SCALE_SHIFT - SCALE_SUBPEL_BITS);
+}
+
+
+void av1_setup_scale_factors_for_frame(struct scale_factors *sf, int other_w,
+ int other_h, int this_w, int this_h) {
+ if (!valid_ref_frame_size(other_w, other_h, this_w, this_h)) {
+ sf->x_scale_fp = REF_INVALID_SCALE;
+ sf->y_scale_fp = REF_INVALID_SCALE;
+ return;
+ }
+
+ sf->x_scale_fp = get_fixed_point_scale_factor(other_w, this_w);
+ sf->y_scale_fp = get_fixed_point_scale_factor(other_h, this_h);
+
+ sf->x_step_q4 = fixed_point_scale_to_coarse_point_scale(sf->x_scale_fp);
+ sf->y_step_q4 = fixed_point_scale_to_coarse_point_scale(sf->y_scale_fp);
+
+ if (av1_is_scaled(sf)) {
+ sf->scale_value_x = scaled_x;
+ sf->scale_value_y = scaled_y;
+ } else {
+ sf->scale_value_x = unscaled_value;
+ sf->scale_value_y = unscaled_value;
+ }
+#ifdef ORI_CODE
+ // AV1 convolve functions
+ // Special case convolve functions should produce the same result as
+ // av1_convolve_2d.
+ // subpel_x_qn == 0 && subpel_y_qn == 0
+ sf->convolve[0][0][0] = av1_convolve_2d_copy_sr;
+ // subpel_x_qn == 0
+ sf->convolve[0][1][0] = av1_convolve_y_sr;
+ // subpel_y_qn == 0
+ sf->convolve[1][0][0] = av1_convolve_x_sr;
+ // subpel_x_qn != 0 && subpel_y_qn != 0
+ sf->convolve[1][1][0] = av1_convolve_2d_sr;
+ // subpel_x_qn == 0 && subpel_y_qn == 0
+ sf->convolve[0][0][1] = av1_dist_wtd_convolve_2d_copy;
+ // subpel_x_qn == 0
+ sf->convolve[0][1][1] = av1_dist_wtd_convolve_y;
+ // subpel_y_qn == 0
+ sf->convolve[1][0][1] = av1_dist_wtd_convolve_x;
+ // subpel_x_qn != 0 && subpel_y_qn != 0
+ sf->convolve[1][1][1] = av1_dist_wtd_convolve_2d;
+ // AV1 High BD convolve functions
+ // Special case convolve functions should produce the same result as
+ // av1_highbd_convolve_2d.
+ // subpel_x_qn == 0 && subpel_y_qn == 0
+ sf->highbd_convolve[0][0][0] = av1_highbd_convolve_2d_copy_sr;
+ // subpel_x_qn == 0
+ sf->highbd_convolve[0][1][0] = av1_highbd_convolve_y_sr;
+ // subpel_y_qn == 0
+ sf->highbd_convolve[1][0][0] = av1_highbd_convolve_x_sr;
+ // subpel_x_qn != 0 && subpel_y_qn != 0
+ sf->highbd_convolve[1][1][0] = av1_highbd_convolve_2d_sr;
+ // subpel_x_qn == 0 && subpel_y_qn == 0
+ sf->highbd_convolve[0][0][1] = av1_highbd_dist_wtd_convolve_2d_copy;
+ // subpel_x_qn == 0
+ sf->highbd_convolve[0][1][1] = av1_highbd_dist_wtd_convolve_y;
+ // subpel_y_qn == 0
+ sf->highbd_convolve[1][0][1] = av1_highbd_dist_wtd_convolve_x;
+ // subpel_x_qn != 0 && subpel_y_qn != 0
+ sf->highbd_convolve[1][1][1] = av1_highbd_dist_wtd_convolve_2d;
+#endif
+}
+#endif
+
+static RefCntBuffer *assign_cur_frame_new_fb(AV1_COMMON *const cm) {
+ // Release the previously-used frame-buffer
+ int new_fb_idx;
+ if (cm->cur_frame != NULL) {
+ --cm->cur_frame->ref_count;
+ cm->cur_frame = NULL;
+ }
+
+ // Assign a new framebuffer
+ new_fb_idx = get_free_frame_buffer(cm);
+ if (new_fb_idx == INVALID_IDX) return NULL;
+
+ cm->cur_frame = &cm->buffer_pool->frame_bufs[new_fb_idx];
+ cm->cur_frame->buf.buf_8bit_valid = 0;
+#ifdef AML
+ cm->cur_frame->buf.index = new_fb_idx;
+#endif
+#ifdef ORI_CODE
+ av1_zero(cm->cur_frame->interp_filter_selected);
+#endif
+ return cm->cur_frame;
+}
+
+// Modify 'lhs_ptr' to reference the buffer at 'rhs_ptr', and update the ref
+// counts accordingly.
+static void assign_frame_buffer_p(RefCntBuffer **lhs_ptr,
+ RefCntBuffer *rhs_ptr) {
+ RefCntBuffer *const old_ptr = *lhs_ptr;
+ if (old_ptr != NULL) {
+ assert(old_ptr->ref_count > 0);
+ // One less reference to the buffer at 'old_ptr', so decrease ref count.
+ --old_ptr->ref_count;
+ }
+
+ *lhs_ptr = rhs_ptr;
+ // One more reference to the buffer at 'rhs_ptr', so increase ref count.
+ ++rhs_ptr->ref_count;
+}
+
+AV1Decoder *av1_decoder_create(BufferPool *const pool, AV1_COMMON *cm) {
+ int i;
+
+#ifndef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ AV1Decoder *pbi = (AV1Decoder *)malloc(sizeof(*pbi));
+#else
+ AV1Decoder *pbi = (AV1Decoder *)vmalloc(sizeof(AV1Decoder));
+#endif
+ if (!pbi) return NULL;
+ memset(pbi, 0, sizeof(*pbi));
+
+ // The jmp_buf is valid only for the duration of the function that calls
+ // setjmp(). Therefore, this function must reset the 'setjmp' field to 0
+ // before it returns.
+
+ pbi->common = cm;
+ cm->error.setjmp = 1;
+
+#ifdef ORI_CODE
+ memset(cm->fc, 0, sizeof(*cm->fc));
+ memset(cm->default_frame_context, 0, sizeof(*cm->default_frame_context));
+#endif
+ pbi->need_resync = 1;
+
+ // Initialize the references to not point to any frame buffers.
+ for (i = 0; i < REF_FRAMES; i++) {
+ cm->ref_frame_map[i] = NULL;
+ cm->next_ref_frame_map[i] = NULL;
+#ifdef AML
+ cm->next_used_ref_frame_map[i] = NULL;
+#endif
+ }
+
+ cm->current_frame.frame_number = 0;
+ pbi->decoding_first_frame = 1;
+ pbi->common->buffer_pool = pool;
+
+ cm->seq_params.bit_depth = AOM_BITS_8;
+
+#ifdef ORI_CODE
+ cm->alloc_mi = dec_alloc_mi;
+ cm->free_mi = dec_free_mi;
+ cm->setup_mi = dec_setup_mi;
+
+ av1_loop_filter_init(cm);
+
+ av1_qm_init(cm);
+ av1_loop_restoration_precal();
+#if CONFIG_ACCOUNTING
+ pbi->acct_enabled = 1;
+ aom_accounting_init(&pbi->accounting);
+#endif
+#endif
+ cm->error.setjmp = 0;
+
+#ifdef ORI_CODE
+ aom_get_worker_interface()->init(&pbi->lf_worker);
+ pbi->lf_worker.thread_name = "aom lf worker";
+#endif
+
+ return pbi;
+}
+
+static void reset_frame_buffers(AV1Decoder *const pbi);
+
+void av1_bufmgr_ctx_reset(AV1Decoder *pbi, BufferPool *const pool, AV1_COMMON *cm)
+{
+ if (!pbi || !pool || !cm)
+ return;
+
+ reset_frame_buffers(pbi);
+ memset(pbi, 0, sizeof(*pbi));
+ memset(cm, 0, sizeof(*cm));
+
+ cm->current_frame.frame_number = 0;
+ cm->seq_params.bit_depth = AOM_BITS_8;
+ cm->error.setjmp = 0;
+
+ pbi->bufmgr_proc_count = 0;
+ pbi->need_resync = 1;
+ pbi->decoding_first_frame = 1;
+ pbi->num_output_frames = 0;
+ pbi->common = cm;
+ pbi->common->buffer_pool = pool;
+}
+
+int release_fb_cb(void *cb_priv, aom_codec_frame_buffer_t *fb) {
+#if 0
+ InternalFrameBuffer *const int_fb = (InternalFrameBuffer *)fb->priv;
+ (void)cb_priv;
+ if (int_fb) int_fb->in_use = 0;
+#endif
+ return 0;
+}
+
+static void decrease_ref_count(AV1Decoder *pbi, RefCntBuffer *const buf,
+ BufferPool *const pool) {
+ if (buf != NULL) {
+ --buf->ref_count;
+ // Reference counts should never become negative. If this assertion fails,
+ // there is a bug in our reference count management.
+ assert(buf->ref_count >= 0);
+ // A worker may only get a free framebuffer index when calling get_free_fb.
+ // But the raw frame buffer is not set up until we finish decoding header.
+ // So if any error happens during decoding header, frame_bufs[idx] will not
+ // have a valid raw frame buffer.
+ if (buf->ref_count == 0
+#ifdef ORI_CODE
+ && buf->raw_frame_buffer.data
+#endif
+ ) {
+#ifdef AML
+ av1_release_buf(pbi, buf);
+#endif
+ release_fb_cb(pool->cb_priv, &buf->raw_frame_buffer);
+ buf->raw_frame_buffer.data = NULL;
+ buf->raw_frame_buffer.size = 0;
+ buf->raw_frame_buffer.priv = NULL;
+ }
+ }
+}
+
+static void swap_frame_buffers(AV1Decoder *pbi, int frame_decoded) {
+ int ref_index = 0, mask;
+ AV1_COMMON *const cm = pbi->common;
+ BufferPool *const pool = cm->buffer_pool;
+ unsigned long flags;
+
+ if (frame_decoded) {
+ int check_on_show_existing_frame;
+ lock_buffer_pool(pool, flags);
+
+ // In ext-tile decoding, the camera frame header is only decoded once. So,
+ // we don't release the references here.
+ if (!pbi->camera_frame_header_ready) {
+ // If we are not holding reference buffers in cm->next_ref_frame_map,
+ // assert that the following two for loops are no-ops.
+ assert(IMPLIES(!pbi->hold_ref_buf,
+ cm->current_frame.refresh_frame_flags == 0));
+ assert(IMPLIES(!pbi->hold_ref_buf,
+ cm->show_existing_frame && !pbi->reset_decoder_state));
+
+ // The following two for loops need to release the reference stored in
+ // cm->ref_frame_map[ref_index] before transferring the reference stored
+ // in cm->next_ref_frame_map[ref_index] to cm->ref_frame_map[ref_index].
+ for (mask = cm->current_frame.refresh_frame_flags; mask; mask >>= 1) {
+ decrease_ref_count(pbi, cm->ref_frame_map[ref_index], pool);
+ cm->ref_frame_map[ref_index] = cm->next_ref_frame_map[ref_index];
+ cm->next_ref_frame_map[ref_index] = NULL;
+ ++ref_index;
+ }
+
+ check_on_show_existing_frame =
+ !cm->show_existing_frame || pbi->reset_decoder_state;
+ for (; ref_index < REF_FRAMES && check_on_show_existing_frame;
+ ++ref_index) {
+ decrease_ref_count(pbi, cm->ref_frame_map[ref_index], pool);
+ cm->ref_frame_map[ref_index] = cm->next_ref_frame_map[ref_index];
+ cm->next_ref_frame_map[ref_index] = NULL;
+ }
+ }
+
+ if (cm->show_existing_frame || cm->show_frame) {
+ if (pbi->output_all_layers) {
+ // Append this frame to the output queue
+ if (pbi->num_output_frames >= MAX_NUM_SPATIAL_LAYERS) {
+ // We can't store the new frame anywhere, so drop it and return an
+ // error
+ cm->cur_frame->buf.corrupted = 1;
+ decrease_ref_count(pbi, cm->cur_frame, pool);
+ cm->error.error_code = AOM_CODEC_UNSUP_BITSTREAM;
+ } else {
+ pbi->output_frames[pbi->num_output_frames] = cm->cur_frame;
+ pbi->num_output_frames++;
+ }
+ } else {
+ // Replace any existing output frame
+ assert(pbi->num_output_frames == 0 || pbi->num_output_frames == 1);
+ if (pbi->num_output_frames > 0) {
+ decrease_ref_count(pbi, pbi->output_frames[0], pool);
+ }
+ if (cm->cur_frame) {
+ pbi->output_frames[0] = cm->cur_frame;
+ pbi->num_output_frames = 1;
+ }
+ }
+ } else {
+ decrease_ref_count(pbi, cm->cur_frame, pool);
+ }
+
+ unlock_buffer_pool(pool, flags);
+ } else {
+ // The code here assumes we are not holding reference buffers in
+ // cm->next_ref_frame_map. If this assertion fails, we are leaking the
+ // frame buffer references in cm->next_ref_frame_map.
+ assert(IMPLIES(!pbi->camera_frame_header_ready, !pbi->hold_ref_buf));
+ // Nothing was decoded, so just drop this frame buffer
+ lock_buffer_pool(pool, flags);
+ decrease_ref_count(pbi, cm->cur_frame, pool);
+ unlock_buffer_pool(pool, flags);
+ }
+ cm->cur_frame = NULL;
+
+ if (!pbi->camera_frame_header_ready) {
+ pbi->hold_ref_buf = 0;
+
+ // Invalidate these references until the next frame starts.
+ for (ref_index = 0; ref_index < INTER_REFS_PER_FRAME; ref_index++) {
+ cm->remapped_ref_idx[ref_index] = INVALID_IDX;
+ }
+ }
+}
+
+void aom_internal_error(struct aom_internal_error_info *info,
+ aom_codec_err_t error, const char *fmt, ...) {
+ va_list ap;
+
+ info->error_code = error;
+ info->has_detail = 0;
+
+ if (fmt) {
+ size_t sz = sizeof(info->detail);
+
+ info->has_detail = 1;
+ va_start(ap, fmt);
+ vsnprintf(info->detail, sz - 1, fmt, ap);
+ va_end(ap);
+ info->detail[sz - 1] = '\0';
+ }
+#ifdef ORI_CODE
+ if (info->setjmp) longjmp(info->jmp, info->error_code);
+#endif
+}
+
+#ifdef ORI_CODE
+void av1_zero_unused_internal_frame_buffers(InternalFrameBufferList *list) {
+ int i;
+
+ assert(list != NULL);
+
+ for (i = 0; i < list->num_internal_frame_buffers; ++i) {
+ if (list->int_fb[i].data && !list->int_fb[i].in_use)
+ memset(list->int_fb[i].data, 0, list->int_fb[i].size);
+ }
+}
+#endif
+
+// Release the references to the frame buffers in cm->ref_frame_map and reset
+// all elements of cm->ref_frame_map to NULL.
+static void reset_ref_frame_map(AV1Decoder *const pbi) {
+ AV1_COMMON *const cm = pbi->common;
+ BufferPool *const pool = cm->buffer_pool;
+ int i;
+
+ for (i = 0; i < REF_FRAMES; i++) {
+ decrease_ref_count(pbi, cm->ref_frame_map[i], pool);
+ cm->ref_frame_map[i] = NULL;
+#ifdef AML
+ cm->next_used_ref_frame_map[i] = NULL;
+#endif
+ }
+}
+
+// Generate next_ref_frame_map.
+static void generate_next_ref_frame_map(AV1Decoder *const pbi) {
+ AV1_COMMON *const cm = pbi->common;
+ BufferPool *const pool = cm->buffer_pool;
+ unsigned long flags;
+ int ref_index = 0;
+ int mask;
+
+ lock_buffer_pool(pool, flags);
+ // cm->next_ref_frame_map holds references to frame buffers. After storing a
+ // frame buffer index in cm->next_ref_frame_map, we need to increase the
+ // frame buffer's ref_count.
+ for (mask = cm->current_frame.refresh_frame_flags; mask; mask >>= 1) {
+ if (mask & 1) {
+ cm->next_ref_frame_map[ref_index] = cm->cur_frame;
+ } else {
+ cm->next_ref_frame_map[ref_index] = cm->ref_frame_map[ref_index];
+ }
+ if (cm->next_ref_frame_map[ref_index] != NULL)
+ ++cm->next_ref_frame_map[ref_index]->ref_count;
+ ++ref_index;
+ }
+
+ for (; ref_index < REF_FRAMES; ++ref_index) {
+ cm->next_ref_frame_map[ref_index] = cm->ref_frame_map[ref_index];
+ if (cm->next_ref_frame_map[ref_index] != NULL)
+ ++cm->next_ref_frame_map[ref_index]->ref_count;
+ }
+ unlock_buffer_pool(pool, flags);
+ pbi->hold_ref_buf = 1;
+}
+
+// If the refresh_frame_flags bitmask is set, update reference frame id values
+// and mark frames as valid for reference.
+static void update_ref_frame_id(AV1_COMMON *const cm, int frame_id) {
+ int i;
+ int refresh_frame_flags = cm->current_frame.refresh_frame_flags;
+ assert(cm->seq_params.frame_id_numbers_present_flag);
+ for (i = 0; i < REF_FRAMES; i++) {
+ if ((refresh_frame_flags >> i) & 1) {
+ cm->ref_frame_id[i] = frame_id;
+ cm->valid_for_referencing[i] = 1;
+ }
+ }
+}
+
+static void show_existing_frame_reset(AV1Decoder *const pbi,
+ int existing_frame_idx) {
+ AV1_COMMON *const cm = pbi->common;
+ int i;
+ assert(cm->show_existing_frame);
+
+ cm->current_frame.frame_type = KEY_FRAME;
+
+ cm->current_frame.refresh_frame_flags = (1 << REF_FRAMES) - 1;
+
+ for (i = 0; i < INTER_REFS_PER_FRAME; ++i) {
+ cm->remapped_ref_idx[i] = INVALID_IDX;
+ }
+
+ if (pbi->need_resync) {
+ reset_ref_frame_map(pbi);
+ pbi->need_resync = 0;
+ }
+
+ // Note that the displayed frame must be valid for referencing in order to
+ // have been selected.
+ if (cm->seq_params.frame_id_numbers_present_flag) {
+ cm->current_frame_id = cm->ref_frame_id[existing_frame_idx];
+ update_ref_frame_id(cm, cm->current_frame_id);
+ }
+
+ cm->refresh_frame_context = REFRESH_FRAME_CONTEXT_DISABLED;
+
+ generate_next_ref_frame_map(pbi);
+
+#ifdef ORI_CODE
+ // Reload the adapted CDFs from when we originally coded this keyframe
+ *cm->fc = cm->next_ref_frame_map[existing_frame_idx]->frame_context;
+#endif
+}
+
+static void reset_frame_buffers(AV1Decoder *const pbi) {
+ AV1_COMMON *const cm = pbi->common;
+ RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
+ int i;
+ unsigned long flags;
+
+ // We have not stored any references to frame buffers in
+ // cm->next_ref_frame_map, so we can directly reset it to all NULL.
+ for (i = 0; i < REF_FRAMES; ++i) {
+ cm->next_ref_frame_map[i] = NULL;
+ }
+
+ lock_buffer_pool(cm->buffer_pool, flags);
+ reset_ref_frame_map(pbi);
+ assert(cm->cur_frame->ref_count == 1);
+ for (i = 0; i < FRAME_BUFFERS; ++i) {
+ // Reset all unreferenced frame buffers. We can also reset cm->cur_frame
+ // because we are the sole owner of cm->cur_frame.
+ if (frame_bufs[i].ref_count > 0 && &frame_bufs[i] != cm->cur_frame) {
+ continue;
+ }
+ frame_bufs[i].order_hint = 0;
+ av1_zero(frame_bufs[i].ref_order_hints);
+ }
+#ifdef ORI_CODE
+ av1_zero_unused_internal_frame_buffers(&cm->buffer_pool->int_frame_buffers);
+#endif
+ unlock_buffer_pool(cm->buffer_pool, flags);
+}
+
+static int frame_is_intra_only(const AV1_COMMON *const cm) {
+ return cm->current_frame.frame_type == KEY_FRAME ||
+ cm->current_frame.frame_type == INTRA_ONLY_FRAME;
+}
+
+static int frame_is_sframe(const AV1_COMMON *cm) {
+ return cm->current_frame.frame_type == S_FRAME;
+}
+
+// These functions take a reference frame label between LAST_FRAME and
+// EXTREF_FRAME inclusive. Note that this is different to the indexing
+// previously used by the frame_refs[] array.
+static int get_ref_frame_map_idx(const AV1_COMMON *const cm,
+ const MV_REFERENCE_FRAME ref_frame) {
+ return (ref_frame >= LAST_FRAME && ref_frame <= EXTREF_FRAME)
+ ? cm->remapped_ref_idx[ref_frame - LAST_FRAME]
+ : INVALID_IDX;
+}
+
+static RefCntBuffer *get_ref_frame_buf(
+ const AV1_COMMON *const cm, const MV_REFERENCE_FRAME ref_frame) {
+ const int map_idx = get_ref_frame_map_idx(cm, ref_frame);
+ return (map_idx != INVALID_IDX) ? cm->ref_frame_map[map_idx] : NULL;
+}
+#ifdef SUPPORT_SCALE_FACTOR
+static struct scale_factors *get_ref_scale_factors(
+ AV1_COMMON *const cm, const MV_REFERENCE_FRAME ref_frame) {
+ const int map_idx = get_ref_frame_map_idx(cm, ref_frame);
+ return (map_idx != INVALID_IDX) ? &cm->ref_scale_factors[map_idx] : NULL;
+}
+#endif
+static RefCntBuffer *get_primary_ref_frame_buf(
+ const AV1_COMMON *const cm) {
+ int map_idx;
+ if (cm->primary_ref_frame == PRIMARY_REF_NONE) return NULL;
+ map_idx = get_ref_frame_map_idx(cm, cm->primary_ref_frame + 1);
+ return (map_idx != INVALID_IDX) ? cm->ref_frame_map[map_idx] : NULL;
+}
+
+static int get_relative_dist(const OrderHintInfo *oh, int a, int b) {
+ int bits;
+ int m;
+ int diff;
+ if (!oh->enable_order_hint) return 0;
+
+ bits = oh->order_hint_bits_minus_1 + 1;
+
+ assert(bits >= 1);
+ assert(a >= 0 && a < (1 << bits));
+ assert(b >= 0 && b < (1 << bits));
+
+ diff = a - b;
+ m = 1 << (bits - 1);
+ diff = (diff & (m - 1)) - (diff & m);
+ return diff;
+}
+
+
+void av1_read_frame_size(union param_u *params, int num_bits_width,
+ int num_bits_height, int *width, int *height, int* dec_width) {
+ *width = params->p.frame_width;
+ *height = params->p.frame_height;//aom_rb_read_literal(rb, num_bits_height) + 1;
+#ifdef AML
+ *dec_width = params->p.dec_frame_width;
+#endif
+}
+
+static REFERENCE_MODE read_frame_reference_mode(
+ const AV1_COMMON *cm, union param_u *params) {
+ if (frame_is_intra_only(cm)) {
+ return SINGLE_REFERENCE;
+ } else {
+ return params->p.reference_mode ? REFERENCE_MODE_SELECT : SINGLE_REFERENCE;
+ }
+}
+
+static inline int calc_mi_size(int len) {
+ // len is in mi units. Align to a multiple of SBs.
+ return ALIGN_POWER_OF_TWO(len, MAX_MIB_SIZE_LOG2);
+}
+
+void av1_set_mb_mi(AV1_COMMON *cm, int width, int height) {
+ // Ensure that the decoded width and height are both multiples of
+ // 8 luma pixels (note: this may only be a multiple of 4 chroma pixels if
+ // subsampling is used).
+ // This simplifies the implementation of various experiments,
+ // eg. cdef, which operates on units of 8x8 luma pixels.
+ const int aligned_width = ALIGN_POWER_OF_TWO(width, 3);
+ const int aligned_height = ALIGN_POWER_OF_TWO(height, 3);
+ av1_print2(AV1_DEBUG_BUFMGR_DETAIL, " [PICTURE] av1_set_mb_mi (%d X %d)\n", width, height);
+
+ cm->mi_cols = aligned_width >> MI_SIZE_LOG2;
+ cm->mi_rows = aligned_height >> MI_SIZE_LOG2;
+ cm->mi_stride = calc_mi_size(cm->mi_cols);
+
+ cm->mb_cols = (cm->mi_cols + 2) >> 2;
+ cm->mb_rows = (cm->mi_rows + 2) >> 2;
+ cm->MBs = cm->mb_rows * cm->mb_cols;
+
+#if CONFIG_LPF_MASK
+ alloc_loop_filter_mask(cm);
+#endif
+}
+
+int av1_alloc_context_buffers(AV1_COMMON *cm, int width, int height) {
+#ifdef ORI_CODE
+ int new_mi_size;
+#endif
+ av1_set_mb_mi(cm, width, height);
+#ifdef ORI_CODE
+ new_mi_size = cm->mi_stride * calc_mi_size(cm->mi_rows);
+ if (cm->mi_alloc_size < new_mi_size) {
+ cm->free_mi(cm);
+ if (cm->alloc_mi(cm, new_mi_size)) goto fail;
+ }
+#endif
+ return 0;
+
+#ifdef ORI_CODE
+fail:
+ // clear the mi_* values to force a realloc on resync
+ av1_set_mb_mi(cm, 0, 0);
+
+ av1_free_context_buffers(cm);
+#endif
+ return 1;
+}
+
+#ifndef USE_SCALED_WIDTH_FROM_UCODE
+static void calculate_scaled_size_helper(int *dim, int denom) {
+ if (denom != SCALE_NUMERATOR) {
+ // We need to ensure the constraint in "Appendix A" of the spec:
+ // * FrameWidth is greater than or equal to 16
+ // * FrameHeight is greater than or equal to 16
+ // For this, we clamp the downscaled dimension to at least 16. One
+ // exception: if original dimension itself was < 16, then we keep the
+ // downscaled dimension to be same as the original, to ensure that resizing
+ // is valid.
+ const int min_dim = AOMMIN(16, *dim);
+ // Use this version if we need *dim to be even
+ // *width = (*width * SCALE_NUMERATOR + denom) / (2 * denom);
+ // *width <<= 1;
+ *dim = (*dim * SCALE_NUMERATOR + denom / 2) / (denom);
+ *dim = AOMMAX(*dim, min_dim);
+ }
+}
+#ifdef ORI_CODE
+void av1_calculate_scaled_size(int *width, int *height, int resize_denom) {
+ calculate_scaled_size_helper(width, resize_denom);
+ calculate_scaled_size_helper(height, resize_denom);
+}
+#endif
+void av1_calculate_scaled_superres_size(int *width, int *height,
+ int superres_denom) {
+ (void)height;
+ calculate_scaled_size_helper(width, superres_denom);
+}
+#endif
+
+static void setup_superres(AV1_COMMON *const cm, union param_u *params,
+ int *width, int *height) {
+#ifdef USE_SCALED_WIDTH_FROM_UCODE
+ cm->superres_upscaled_width = params->p.frame_width_scaled;
+ cm->superres_upscaled_height = params->p.frame_height;
+
+
+ *width = params->p.dec_frame_width;
+ *height = params->p.frame_height;
+ av1_print2(AV1_DEBUG_BUFMGR_DETAIL, " [PICTURE] set decoding size to (%d X %d) scaled size to (%d X %d)\n",
+ *width, *height,
+ cm->superres_upscaled_width,
+ cm->superres_upscaled_height);
+#else
+ cm->superres_upscaled_width = *width;
+ cm->superres_upscaled_height = *height;
+
+ const SequenceHeader *const seq_params = &cm->seq_params;
+ if (!seq_params->enable_superres) return;
+
+ //if (aom_rb_read_bit(-1, defmark, rb)) {
+ if (params->p.superres_scale_denominator != SCALE_NUMERATOR) {
+#ifdef ORI_CODE
+ cm->superres_scale_denominator =
+ (uint8_t)aom_rb_read_literal(-1, defmark, rb, SUPERRES_SCALE_BITS);
+ cm->superres_scale_denominator += SUPERRES_SCALE_DENOMINATOR_MIN;
+#else
+ cm->superres_scale_denominator = params->p.superres_scale_denominator;
+#endif
+ // Don't edit cm->width or cm->height directly, or the buffers won't get
+ // resized correctly
+ av1_calculate_scaled_superres_size(width, height,
+ cm->superres_scale_denominator);
+ } else {
+ // 1:1 scaling - ie. no scaling, scale not provided
+ cm->superres_scale_denominator = SCALE_NUMERATOR;
+ }
+/*!USE_SCALED_WIDTH_FROM_UCODE*/
+#endif
+}
+
+static void resize_context_buffers(AV1_COMMON *cm, int width, int height) {
+#if CONFIG_SIZE_LIMIT
+ if (width > DECODE_WIDTH_LIMIT || height > DECODE_HEIGHT_LIMIT)
+ aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "Dimensions of %dx%d beyond allowed size of %dx%d.",
+ width, height, DECODE_WIDTH_LIMIT, DECODE_HEIGHT_LIMIT);
+#endif
+ if (cm->width != width || cm->height != height) {
+ const int new_mi_rows =
+ ALIGN_POWER_OF_TWO(height, MI_SIZE_LOG2) >> MI_SIZE_LOG2;
+ const int new_mi_cols =
+ ALIGN_POWER_OF_TWO(width, MI_SIZE_LOG2) >> MI_SIZE_LOG2;
+
+ // Allocations in av1_alloc_context_buffers() depend on individual
+ // dimensions as well as the overall size.
+ if (new_mi_cols > cm->mi_cols || new_mi_rows > cm->mi_rows) {
+ if (av1_alloc_context_buffers(cm, width, height)) {
+ // The cm->mi_* values have been cleared and any existing context
+ // buffers have been freed. Clear cm->width and cm->height to be
+ // consistent and to force a realloc next time.
+ cm->width = 0;
+ cm->height = 0;
+ aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
+ "Failed to allocate context buffers");
+ }
+ } else {
+ av1_set_mb_mi(cm, width, height);
+ }
+#ifdef ORI_CODE
+ av1_init_context_buffers(cm);
+#endif
+ cm->width = width;
+ cm->height = height;
+ }
+
+#ifdef ORI_CODE
+ ensure_mv_buffer(cm->cur_frame, cm);
+#endif
+ cm->cur_frame->width = cm->width;
+ cm->cur_frame->height = cm->height;
+}
+
+static void setup_buffer_pool(AV1_COMMON *cm) {
+ BufferPool *const pool = cm->buffer_pool;
+ const SequenceHeader *const seq_params = &cm->seq_params;
+ unsigned long flags;
+
+ lock_buffer_pool(pool, flags);
+ if (aom_realloc_frame_buffer(cm, &cm->cur_frame->buf,
+ cm->width, cm->height, cm->cur_frame->order_hint)) {
+ unlock_buffer_pool(pool, flags);
+ aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
+ "Failed to allocate frame buffer");
+ }
+ unlock_buffer_pool(pool, flags);
+
+ cm->cur_frame->buf.bit_depth = (unsigned int)seq_params->bit_depth;
+ cm->cur_frame->buf.color_primaries = seq_params->color_primaries;
+ cm->cur_frame->buf.transfer_characteristics =
+ seq_params->transfer_characteristics;
+ cm->cur_frame->buf.matrix_coefficients = seq_params->matrix_coefficients;
+ cm->cur_frame->buf.monochrome = seq_params->monochrome;
+ cm->cur_frame->buf.chroma_sample_position =
+ seq_params->chroma_sample_position;
+ cm->cur_frame->buf.color_range = seq_params->color_range;
+ cm->cur_frame->buf.render_width = cm->render_width;
+ cm->cur_frame->buf.render_height = cm->render_height;
+}
+
+static void setup_frame_size(AV1_COMMON *cm, int frame_size_override_flag, union param_u *params) {
+ const SequenceHeader *const seq_params = &cm->seq_params;
+ int width, height, dec_width;
+
+ if (frame_size_override_flag) {
+ int num_bits_width = seq_params->num_bits_width;
+ int num_bits_height = seq_params->num_bits_height;
+ av1_read_frame_size(params, num_bits_width, num_bits_height, &width, &height, &dec_width);
+#ifdef AML
+ cm->dec_width = dec_width;
+#endif
+ if (width > seq_params->max_frame_width ||
+ height > seq_params->max_frame_height) {
+ aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "Frame dimensions are larger than the maximum values");
+ }
+ } else {
+ width = seq_params->max_frame_width;
+ height = seq_params->max_frame_height;
+#ifdef AML
+ cm->dec_width = dec_width = params->p.dec_frame_width;
+#endif
+ }
+ setup_superres(cm, params, &width, &height);
+ resize_context_buffers(cm, width, height);
+#ifdef ORI_CODE
+ setup_render_size(cm, params);
+#endif
+ setup_buffer_pool(cm);
+}
+
+static int valid_ref_frame_img_fmt(aom_bit_depth_t ref_bit_depth,
+ int ref_xss, int ref_yss,
+ aom_bit_depth_t this_bit_depth,
+ int this_xss, int this_yss) {
+ return ref_bit_depth == this_bit_depth && ref_xss == this_xss &&
+ ref_yss == this_yss;
+}
+
+static void setup_frame_size_with_refs(AV1_COMMON *cm, union param_u *params) {
+ int width, height, dec_width;
+ int found = 0;
+ int has_valid_ref_frame = 0;
+ int i;
+ SequenceHeader *seq_params;
+ for (i = LAST_FRAME; i <= ALTREF_FRAME; ++i) {
+ /*if (aom_rb_read_bit(rb)) {*/
+ if (params->p.valid_ref_frame_bits & (1<<i)) {
+ const RefCntBuffer *const ref_buf = get_ref_frame_buf(cm, i);
+ // This will never be NULL in a normal stream, as streams are required to
+ // have a shown keyframe before any inter frames, which would refresh all
+ // the reference buffers. However, it might be null if we're starting in
+ // the middle of a stream, and static analysis will error if we don't do
+ // a null check here.
+ if (ref_buf == NULL) {
+ aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "Invalid condition: invalid reference buffer");
+ } else {
+ const PIC_BUFFER_CONFIG *const buf = &ref_buf->buf;
+ width = buf->y_crop_width;
+ height = buf->y_crop_height;
+ cm->render_width = buf->render_width;
+ cm->render_height = buf->render_height;
+ setup_superres(cm, params, &width, &height);
+ resize_context_buffers(cm, width, height);
+ found = 1;
+ break;
+ }
+ }
+ }
+
+ seq_params = &cm->seq_params;
+ if (!found) {
+ int num_bits_width = seq_params->num_bits_width;
+ int num_bits_height = seq_params->num_bits_height;
+
+ av1_read_frame_size(params, num_bits_width, num_bits_height, &width, &height, &dec_width);
+#ifdef AML
+ cm->dec_width = dec_width;
+#endif
+ setup_superres(cm, params, &width, &height);
+ resize_context_buffers(cm, width, height);
+#ifdef ORI_CODE
+ setup_render_size(cm, rb);
+#endif
+ }
+
+ if (width <= 0 || height <= 0)
+ aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "Invalid frame size");
+
+ // Check to make sure at least one of frames that this frame references
+ // has valid dimensions.
+ for (i = LAST_FRAME; i <= ALTREF_FRAME; ++i) {
+ const RefCntBuffer *const ref_frame = get_ref_frame_buf(cm, i);
+ if (ref_frame != NULL) {
+ has_valid_ref_frame |=
+ valid_ref_frame_size(ref_frame->buf.y_crop_width,
+ ref_frame->buf.y_crop_height, width, height);
+ }
+ }
+ if (!has_valid_ref_frame)
+ aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "Referenced frame has invalid size");
+ for (i = LAST_FRAME; i <= ALTREF_FRAME; ++i) {
+ const RefCntBuffer *const ref_frame = get_ref_frame_buf(cm, i);
+ if (ref_frame != NULL) {
+ if (!valid_ref_frame_img_fmt(
+ ref_frame->buf.bit_depth, ref_frame->buf.subsampling_x,
+ ref_frame->buf.subsampling_y, seq_params->bit_depth,
+ seq_params->subsampling_x, seq_params->subsampling_y))
+ aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "Referenced frame has incompatible color format");
+ }
+ }
+ setup_buffer_pool(cm);
+}
+
+typedef struct {
+ int map_idx; // frame map index
+ RefCntBuffer *buf; // frame buffer
+ int sort_idx; // index based on the offset to be used for sorting
+} REF_FRAME_INFO;
+
+// Compares the sort_idx fields. If they are equal, then compares the map_idx
+// fields to break the tie. This ensures a stable sort.
+static int compare_ref_frame_info(const void *arg_a, const void *arg_b) {
+ const REF_FRAME_INFO *info_a = (REF_FRAME_INFO *)arg_a;
+ const REF_FRAME_INFO *info_b = (REF_FRAME_INFO *)arg_b;
+
+ const int sort_idx_diff = info_a->sort_idx - info_b->sort_idx;
+ if (sort_idx_diff != 0) return sort_idx_diff;
+ return info_a->map_idx - info_b->map_idx;
+}
+
+
+/*
+for av1_setup_motion_field()
+*/
+static int motion_field_projection(AV1_COMMON *cm,
+ MV_REFERENCE_FRAME start_frame, int dir) {
+#ifdef ORI_CODE
+ TPL_MV_REF *tpl_mvs_base = cm->tpl_mvs;
+ int ref_offset[REF_FRAMES] = { 0 };
+#endif
+ MV_REFERENCE_FRAME rf;
+ const RefCntBuffer *const start_frame_buf =
+ get_ref_frame_buf(cm, start_frame);
+ int start_frame_order_hint;
+ unsigned int const *ref_order_hints;
+ int cur_order_hint;
+ int start_to_current_frame_offset;
+
+#ifdef AML
+ int i;
+ //av1_print2(AV1_DEBUG_BUFMGR_DETAIL, "$$$$$$$$$$$%s:cm->mv_ref_id_index = %d, start_frame=%d\n", __func__, cm->mv_ref_id_index, start_frame);
+ cm->mv_ref_id[cm->mv_ref_id_index] = start_frame;
+ for (i = 0; i < REF_FRAMES; i++) {
+ cm->mv_ref_offset[cm->mv_ref_id_index][i]=0;
+ }
+ cm->mv_cal_tpl_mvs[cm->mv_ref_id_index]=0;
+ cm->mv_ref_id_index++;
+#endif
+ if (start_frame_buf == NULL) return 0;
+
+ if (start_frame_buf->frame_type == KEY_FRAME ||
+ start_frame_buf->frame_type == INTRA_ONLY_FRAME)
+ return 0;
+
+ if (start_frame_buf->mi_rows != cm->mi_rows ||
+ start_frame_buf->mi_cols != cm->mi_cols)
+ return 0;
+
+ start_frame_order_hint = start_frame_buf->order_hint;
+ ref_order_hints =
+ &start_frame_buf->ref_order_hints[0];
+ cur_order_hint = cm->cur_frame->order_hint;
+ start_to_current_frame_offset = get_relative_dist(
+ &cm->seq_params.order_hint_info, start_frame_order_hint, cur_order_hint);
+
+ for (rf = LAST_FRAME; rf <= INTER_REFS_PER_FRAME; ++rf) {
+ cm->mv_ref_offset[cm->mv_ref_id_index-1][rf] = get_relative_dist(&cm->seq_params.order_hint_info,
+ start_frame_order_hint,
+ ref_order_hints[rf - LAST_FRAME]);
+ }
+#ifdef AML
+ cm->mv_cal_tpl_mvs[cm->mv_ref_id_index-1]=1;
+#endif
+ if (dir == 2) start_to_current_frame_offset = -start_to_current_frame_offset;
+#ifdef ORI_CODE
+ MV_REF *mv_ref_base = start_frame_buf->mvs;
+ const int mvs_rows = (cm->mi_rows + 1) >> 1;
+ const int mvs_cols = (cm->mi_cols + 1) >> 1;
+
+ for (int blk_row = 0; blk_row < mvs_rows; ++blk_row) {
+ for (int blk_col = 0; blk_col < mvs_cols; ++blk_col) {
+ MV_REF *mv_ref = &mv_ref_base[blk_row * mvs_cols + blk_col];
+ MV fwd_mv = mv_ref->mv.as_mv;
+
+ if (mv_ref->ref_frame > INTRA_FRAME) {
+ int_mv this_mv;
+ int mi_r, mi_c;
+ const int ref_frame_offset = ref_offset[mv_ref->ref_frame];
+
+ int pos_valid =
+ abs(ref_frame_offset) <= MAX_FRAME_DISTANCE &&
+ ref_frame_offset > 0 &&
+ abs(start_to_current_frame_offset) <= MAX_FRAME_DISTANCE;
+
+ if (pos_valid) {
+ get_mv_projection(&this_mv.as_mv, fwd_mv,
+ start_to_current_frame_offset, ref_frame_offset);
+ pos_valid = get_block_position(cm, &mi_r, &mi_c, blk_row, blk_col,
+ this_mv.as_mv, dir >> 1);
+ }
+
+ if (pos_valid) {
+ const int mi_offset = mi_r * (cm->mi_stride >> 1) + mi_c;
+
+ tpl_mvs_base[mi_offset].mfmv0.as_mv.row = fwd_mv.row;
+ tpl_mvs_base[mi_offset].mfmv0.as_mv.col = fwd_mv.col;
+ tpl_mvs_base[mi_offset].ref_frame_offset = ref_frame_offset;
+ }
+ }
+ }
+ }
+#endif
+ return 1;
+}
+
+#ifdef AML
+static int setup_motion_field_debug_count = 0;
+#endif
+void av1_setup_motion_field(AV1_COMMON *cm) {
+ const OrderHintInfo *const order_hint_info = &cm->seq_params.order_hint_info;
+ int ref_frame;
+ int size;
+ int cur_order_hint;
+ const RefCntBuffer *ref_buf[INTER_REFS_PER_FRAME];
+ int ref_order_hint[INTER_REFS_PER_FRAME];
+ int ref_stamp;
+ memset(cm->ref_frame_side, 0, sizeof(cm->ref_frame_side));
+ if (!order_hint_info->enable_order_hint) return;
+#ifdef ORI_CODE
+ TPL_MV_REF *tpl_mvs_base = cm->tpl_mvs;
+#endif
+ size = ((cm->mi_rows + MAX_MIB_SIZE) >> 1) * (cm->mi_stride >> 1);
+#ifdef ORI_CODE
+ for (int idx = 0; idx < size; ++idx) {
+ tpl_mvs_base[idx].mfmv0.as_int = INVALID_MV;
+ tpl_mvs_base[idx].ref_frame_offset = 0;
+ }
+#endif
+ cur_order_hint = cm->cur_frame->order_hint;
+
+ for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ref_frame++) {
+ const int ref_idx = ref_frame - LAST_FRAME;
+ const RefCntBuffer *const buf = get_ref_frame_buf(cm, ref_frame);
+ int order_hint = 0;
+
+ if (buf != NULL) order_hint = buf->order_hint;
+
+ ref_buf[ref_idx] = buf;
+ ref_order_hint[ref_idx] = order_hint;
+
+ if (get_relative_dist(order_hint_info, order_hint, cur_order_hint) > 0)
+ cm->ref_frame_side[ref_frame] = 1;
+ else if (order_hint == cur_order_hint)
+ cm->ref_frame_side[ref_frame] = -1;
+ }
+ ref_stamp = MFMV_STACK_SIZE - 1;
+#ifdef AML
+ cm->mv_ref_id_index = 0;
+ av1_print2(AV1_DEBUG_BUFMGR_DETAIL, "%s(%d) mi_cols %d mi_rows %d\n",
+ __func__, setup_motion_field_debug_count++,
+ cm->mi_cols,
+ cm->mi_rows
+ );
+#endif
+ if (ref_buf[LAST_FRAME - LAST_FRAME] != NULL) {
+ const int alt_of_lst_order_hint =
+ ref_buf[LAST_FRAME - LAST_FRAME]
+ ->ref_order_hints[ALTREF_FRAME - LAST_FRAME];
+
+ const int is_lst_overlay =
+ (alt_of_lst_order_hint == ref_order_hint[GOLDEN_FRAME - LAST_FRAME]);
+ if (!is_lst_overlay) motion_field_projection(cm, LAST_FRAME, 2);
+ --ref_stamp;
+ }
+
+ if (get_relative_dist(order_hint_info,
+ ref_order_hint[BWDREF_FRAME - LAST_FRAME],
+ cur_order_hint) > 0) {
+ if (motion_field_projection(cm, BWDREF_FRAME, 0)) --ref_stamp;
+ }
+
+ if (get_relative_dist(order_hint_info,
+ ref_order_hint[ALTREF2_FRAME - LAST_FRAME],
+ cur_order_hint) > 0) {
+ if (motion_field_projection(cm, ALTREF2_FRAME, 0)) --ref_stamp;
+ }
+
+ if (get_relative_dist(order_hint_info,
+ ref_order_hint[ALTREF_FRAME - LAST_FRAME],
+ cur_order_hint) > 0 &&
+ ref_stamp >= 0)
+ if (motion_field_projection(cm, ALTREF_FRAME, 0)) --ref_stamp;
+
+ if (ref_stamp >= 0) motion_field_projection(cm, LAST2_FRAME, 2);
+}
+
+
+static void set_ref_frame_info(int *remapped_ref_idx, int frame_idx,
+ REF_FRAME_INFO *ref_info) {
+ assert(frame_idx >= 0 && frame_idx < INTER_REFS_PER_FRAME);
+
+ remapped_ref_idx[frame_idx] = ref_info->map_idx;
+ av1_print2(AV1_DEBUG_BUFMGR_DETAIL, "+++++++++++++%s:remapped_ref_idx[%d]=0x%x\n", __func__, frame_idx, ref_info->map_idx);
+}
+
+
+void av1_set_frame_refs(AV1_COMMON *const cm, int *remapped_ref_idx,
+ int lst_map_idx, int gld_map_idx) {
+ int lst_frame_sort_idx = -1;
+ int gld_frame_sort_idx = -1;
+ int i;
+ //assert(cm->seq_params.order_hint_info.enable_order_hint);
+ //assert(cm->seq_params.order_hint_info.order_hint_bits_minus_1 >= 0);
+ const int cur_order_hint = (int)cm->current_frame.order_hint;
+ const int cur_frame_sort_idx =
+ 1 << cm->seq_params.order_hint_info.order_hint_bits_minus_1;
+
+ REF_FRAME_INFO ref_frame_info[REF_FRAMES];
+ int ref_flag_list[INTER_REFS_PER_FRAME] = { 0, 0, 0, 0, 0, 0, 0 };
+ int bwd_start_idx;
+ int bwd_end_idx;
+ int fwd_start_idx, fwd_end_idx;
+ int ref_idx;
+ static const MV_REFERENCE_FRAME ref_frame_list[INTER_REFS_PER_FRAME - 2] = {
+ LAST2_FRAME, LAST3_FRAME, BWDREF_FRAME, ALTREF2_FRAME, ALTREF_FRAME
+ };
+
+ for (i = 0; i < REF_FRAMES; ++i) {
+ const int map_idx = i;
+ RefCntBuffer *buf;
+ int offset;
+
+ ref_frame_info[i].map_idx = map_idx;
+ ref_frame_info[i].sort_idx = -1;
+
+ buf = cm->ref_frame_map[map_idx];
+ ref_frame_info[i].buf = buf;
+
+ if (buf == NULL) continue;
+ // If this assertion fails, there is a reference leak.
+ assert(buf->ref_count > 0);
+
+ offset = (int)buf->order_hint;
+ ref_frame_info[i].sort_idx =
+ (offset == -1) ? -1
+ : cur_frame_sort_idx +
+ get_relative_dist(&cm->seq_params.order_hint_info,
+ offset, cur_order_hint);
+ assert(ref_frame_info[i].sort_idx >= -1);
+
+ if (map_idx == lst_map_idx) lst_frame_sort_idx = ref_frame_info[i].sort_idx;
+ if (map_idx == gld_map_idx) gld_frame_sort_idx = ref_frame_info[i].sort_idx;
+ }
+
+ // Confirm both LAST_FRAME and GOLDEN_FRAME are valid forward reference
+ // frames.
+ if (lst_frame_sort_idx == -1 || lst_frame_sort_idx >= cur_frame_sort_idx) {
+ aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "Inter frame requests a look-ahead frame as LAST");
+ }
+ if (gld_frame_sort_idx == -1 || gld_frame_sort_idx >= cur_frame_sort_idx) {
+ aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "Inter frame requests a look-ahead frame as GOLDEN");
+ }
+
+ // Sort ref frames based on their frame_offset values.
+ qsort(ref_frame_info, REF_FRAMES, sizeof(REF_FRAME_INFO),
+ compare_ref_frame_info);
+
+ // Identify forward and backward reference frames.
+ // Forward reference: offset < order_hint
+ // Backward reference: offset >= order_hint
+ fwd_start_idx = 0;
+ fwd_end_idx = REF_FRAMES - 1;
+
+ for (i = 0; i < REF_FRAMES; i++) {
+ if (ref_frame_info[i].sort_idx == -1) {
+ fwd_start_idx++;
+ continue;
+ }
+
+ if (ref_frame_info[i].sort_idx >= cur_frame_sort_idx) {
+ fwd_end_idx = i - 1;
+ break;
+ }
+ }
+
+ bwd_start_idx = fwd_end_idx + 1;
+ bwd_end_idx = REF_FRAMES - 1;
+
+ // === Backward Reference Frames ===
+
+ // == ALTREF_FRAME ==
+ if (bwd_start_idx <= bwd_end_idx) {
+ set_ref_frame_info(remapped_ref_idx, ALTREF_FRAME - LAST_FRAME,
+ &ref_frame_info[bwd_end_idx]);
+ ref_flag_list[ALTREF_FRAME - LAST_FRAME] = 1;
+ bwd_end_idx--;
+ }
+
+ // == BWDREF_FRAME ==
+ if (bwd_start_idx <= bwd_end_idx) {
+ set_ref_frame_info(remapped_ref_idx, BWDREF_FRAME - LAST_FRAME,
+ &ref_frame_info[bwd_start_idx]);
+ ref_flag_list[BWDREF_FRAME - LAST_FRAME] = 1;
+ bwd_start_idx++;
+ }
+
+ // == ALTREF2_FRAME ==
+ if (bwd_start_idx <= bwd_end_idx) {
+ set_ref_frame_info(remapped_ref_idx, ALTREF2_FRAME - LAST_FRAME,
+ &ref_frame_info[bwd_start_idx]);
+ ref_flag_list[ALTREF2_FRAME - LAST_FRAME] = 1;
+ }
+
+ // === Forward Reference Frames ===
+
+ for (i = fwd_start_idx; i <= fwd_end_idx; ++i) {
+ // == LAST_FRAME ==
+ if (ref_frame_info[i].map_idx == lst_map_idx) {
+ set_ref_frame_info(remapped_ref_idx, LAST_FRAME - LAST_FRAME,
+ &ref_frame_info[i]);
+ ref_flag_list[LAST_FRAME - LAST_FRAME] = 1;
+ }
+
+ // == GOLDEN_FRAME ==
+ if (ref_frame_info[i].map_idx == gld_map_idx) {
+ set_ref_frame_info(remapped_ref_idx, GOLDEN_FRAME - LAST_FRAME,
+ &ref_frame_info[i]);
+ ref_flag_list[GOLDEN_FRAME - LAST_FRAME] = 1;
+ }
+ }
+
+ assert(ref_flag_list[LAST_FRAME - LAST_FRAME] == 1 &&
+ ref_flag_list[GOLDEN_FRAME - LAST_FRAME] == 1);
+
+ // == LAST2_FRAME ==
+ // == LAST3_FRAME ==
+ // == BWDREF_FRAME ==
+ // == ALTREF2_FRAME ==
+ // == ALTREF_FRAME ==
+
+ // Set up the reference frames in the anti-chronological order.
+ for (ref_idx = 0; ref_idx < (INTER_REFS_PER_FRAME - 2); ref_idx++) {
+ const MV_REFERENCE_FRAME ref_frame = ref_frame_list[ref_idx];
+
+ if (ref_flag_list[ref_frame - LAST_FRAME] == 1) continue;
+
+ while (fwd_start_idx <= fwd_end_idx &&
+ (ref_frame_info[fwd_end_idx].map_idx == lst_map_idx ||
+ ref_frame_info[fwd_end_idx].map_idx == gld_map_idx)) {
+ fwd_end_idx--;
+ }
+ if (fwd_start_idx > fwd_end_idx) break;
+
+ set_ref_frame_info(remapped_ref_idx, ref_frame - LAST_FRAME,
+ &ref_frame_info[fwd_end_idx]);
+ ref_flag_list[ref_frame - LAST_FRAME] = 1;
+
+ fwd_end_idx--;
+ }
+
+ // Assign all the remaining frame(s), if any, to the earliest reference frame.
+ for (; ref_idx < (INTER_REFS_PER_FRAME - 2); ref_idx++) {
+ const MV_REFERENCE_FRAME ref_frame = ref_frame_list[ref_idx];
+ if (ref_flag_list[ref_frame - LAST_FRAME] == 1) continue;
+ set_ref_frame_info(remapped_ref_idx, ref_frame - LAST_FRAME,
+ &ref_frame_info[fwd_start_idx]);
+ ref_flag_list[ref_frame - LAST_FRAME] = 1;
+ }
+
+ for (i = 0; i < INTER_REFS_PER_FRAME; i++) {
+ assert(ref_flag_list[i] == 1);
+ }
+}
+
+void av1_setup_frame_buf_refs(AV1_COMMON *cm) {
+ MV_REFERENCE_FRAME ref_frame;
+ cm->cur_frame->order_hint = cm->current_frame.order_hint;
+
+ for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
+ const RefCntBuffer *const buf = get_ref_frame_buf(cm, ref_frame);
+ if (buf != NULL)
+ cm->cur_frame->ref_order_hints[ref_frame - LAST_FRAME] = buf->order_hint;
+ }
+}
+
+void av1_setup_frame_sign_bias(AV1_COMMON *cm) {
+ MV_REFERENCE_FRAME ref_frame;
+ for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
+ const RefCntBuffer *const buf = get_ref_frame_buf(cm, ref_frame);
+ if (cm->seq_params.order_hint_info.enable_order_hint && buf != NULL) {
+ const int ref_order_hint = buf->order_hint;
+ cm->ref_frame_sign_bias[ref_frame] =
+ (get_relative_dist(&cm->seq_params.order_hint_info, ref_order_hint,
+ (int)cm->current_frame.order_hint) <= 0)
+ ? 0
+ : 1;
+ } else {
+ cm->ref_frame_sign_bias[ref_frame] = 0;
+ }
+ }
+}
+
+
+void av1_setup_skip_mode_allowed(AV1_COMMON *cm)
+{
+ const OrderHintInfo *const order_hint_info = &cm->seq_params.order_hint_info;
+ SkipModeInfo *const skip_mode_info = &cm->current_frame.skip_mode_info;
+ int i;
+ int cur_order_hint;
+ int ref_order_hints[2] = { -1, INT_MAX };
+ int ref_idx[2] = { INVALID_IDX, INVALID_IDX };
+
+ skip_mode_info->skip_mode_allowed = 0;
+ skip_mode_info->ref_frame_idx_0 = INVALID_IDX;
+ skip_mode_info->ref_frame_idx_1 = INVALID_IDX;
+ av1_print2(AV1_DEBUG_BUFMGR_DETAIL, "av1_setup_skip_mode_allowed %d %d %d\n", order_hint_info->enable_order_hint,
+ frame_is_intra_only(cm),
+ cm->current_frame.reference_mode);
+ if (!order_hint_info->enable_order_hint || frame_is_intra_only(cm) ||
+ cm->current_frame.reference_mode == SINGLE_REFERENCE)
+ return;
+
+ cur_order_hint = cm->current_frame.order_hint;
+
+ // Identify the nearest forward and backward references.
+ for (i = 0; i < INTER_REFS_PER_FRAME; ++i) {
+ const RefCntBuffer *const buf = get_ref_frame_buf(cm, LAST_FRAME + i);
+ int ref_order_hint;
+ if (buf == NULL) continue;
+
+ ref_order_hint = buf->order_hint;
+ if (get_relative_dist(order_hint_info, ref_order_hint, cur_order_hint) < 0) {
+ // Forward reference
+ if (ref_order_hints[0] == -1 ||
+ get_relative_dist(order_hint_info, ref_order_hint,
+ ref_order_hints[0]) > 0) {
+ ref_order_hints[0] = ref_order_hint;
+ ref_idx[0] = i;
+ }
+ } else if (get_relative_dist(order_hint_info, ref_order_hint,
+ cur_order_hint) > 0) {
+ // Backward reference
+ if (ref_order_hints[1] == INT_MAX ||
+ get_relative_dist(order_hint_info, ref_order_hint,
+ ref_order_hints[1]) < 0) {
+ ref_order_hints[1] = ref_order_hint;
+ ref_idx[1] = i;
+ }
+ }
+ }
+
+ if (ref_idx[0] != INVALID_IDX && ref_idx[1] != INVALID_IDX) {
+ // == Bi-directional prediction ==
+ skip_mode_info->skip_mode_allowed = 1;
+ skip_mode_info->ref_frame_idx_0 = AOMMIN(ref_idx[0], ref_idx[1]);
+ skip_mode_info->ref_frame_idx_1 = AOMMAX(ref_idx[0], ref_idx[1]);
+ } else if (ref_idx[0] != INVALID_IDX && ref_idx[1] == INVALID_IDX) {
+ // == Forward prediction only ==
+ // Identify the second nearest forward reference.
+ ref_order_hints[1] = -1;
+ for (i = 0; i < INTER_REFS_PER_FRAME; ++i) {
+ const RefCntBuffer *const buf = get_ref_frame_buf(cm, LAST_FRAME + i);
+ int ref_order_hint;
+ if (buf == NULL) continue;
+
+ ref_order_hint = buf->order_hint;
+ if ((ref_order_hints[0] != -1 &&
+ get_relative_dist(order_hint_info, ref_order_hint, ref_order_hints[0]) < 0) &&
+ (ref_order_hints[1] == -1 ||
+ get_relative_dist(order_hint_info, ref_order_hint, ref_order_hints[1]) > 0)) {
+ // Second closest forward reference
+ ref_order_hints[1] = ref_order_hint;
+ ref_idx[1] = i;
+ }
+ }
+ if (ref_order_hints[1] != -1) {
+ skip_mode_info->skip_mode_allowed = 1;
+ skip_mode_info->ref_frame_idx_0 = AOMMIN(ref_idx[0], ref_idx[1]);
+ skip_mode_info->ref_frame_idx_1 = AOMMAX(ref_idx[0], ref_idx[1]);
+ }
+ }
+ av1_print2(AV1_DEBUG_BUFMGR_DETAIL,
+ "skip_mode_info: skip_mode_allowed 0x%x 0x%x 0x%x\n",
+ cm->current_frame.skip_mode_info.skip_mode_allowed,
+ cm->current_frame.skip_mode_info.ref_frame_idx_0,
+ cm->current_frame.skip_mode_info.ref_frame_idx_1);
+}
+
+static inline int frame_might_allow_ref_frame_mvs(const AV1_COMMON *cm) {
+ return !cm->error_resilient_mode &&
+ cm->seq_params.order_hint_info.enable_ref_frame_mvs &&
+ cm->seq_params.order_hint_info.enable_order_hint &&
+ !frame_is_intra_only(cm);
+}
+
+#ifdef ORI_CODE
+/*
+* segmentation
+*/
+static const int seg_feature_data_signed[SEG_LVL_MAX] = {
+ 1, 1, 1, 1, 1, 0, 0, 0
+};
+
+static const int seg_feature_data_max[SEG_LVL_MAX] = { MAXQ,
+ MAX_LOOP_FILTER,
+ MAX_LOOP_FILTER,
+ MAX_LOOP_FILTER,
+ MAX_LOOP_FILTER,
+ 7,
+ 0,
+ 0 };
+
+
+static inline void segfeatures_copy(struct segmentation *dst,
+ const struct segmentation *src) {
+ int i, j;
+ for (i = 0; i < MAX_SEGMENTS; i++) {
+ dst->feature_mask[i] = src->feature_mask[i];
+ for (j = 0; j < SEG_LVL_MAX; j++) {
+ dst->feature_data[i][j] = src->feature_data[i][j];
+ }
+ }
+ dst->segid_preskip = src->segid_preskip;
+ dst->last_active_segid = src->last_active_segid;
+}
+
+static void av1_clearall_segfeatures(struct segmentation *seg) {
+ av1_zero(seg->feature_data);
+ av1_zero(seg->feature_mask);
+}
+
+static void av1_enable_segfeature(struct segmentation *seg, int segment_id,
+ int feature_id) {
+ seg->feature_mask[segment_id] |= 1 << feature_id;
+}
+
+void av1_calculate_segdata(struct segmentation *seg) {
+ seg->segid_preskip = 0;
+ seg->last_active_segid = 0;
+ for (int i = 0; i < MAX_SEGMENTS; i++) {
+ for (int j = 0; j < SEG_LVL_MAX; j++) {
+ if (seg->feature_mask[i] & (1 << j)) {
+ seg->segid_preskip |= (j >= SEG_LVL_REF_FRAME);
+ seg->last_active_segid = i;
+ }
+ }
+ }
+}
+
+static int av1_seg_feature_data_max(int feature_id) {
+ return seg_feature_data_max[feature_id];
+}
+
+static int av1_is_segfeature_signed(int feature_id) {
+ return seg_feature_data_signed[feature_id];
+}
+
+static void av1_set_segdata(struct segmentation *seg, int segment_id,
+ int feature_id, int seg_data) {
+ if (seg_data < 0) {
+ assert(seg_feature_data_signed[feature_id]);
+ assert(-seg_data <= seg_feature_data_max[feature_id]);
+ } else {
+ assert(seg_data <= seg_feature_data_max[feature_id]);
+ }
+
+ seg->feature_data[segment_id][feature_id] = seg_data;
+}
+
+static inline int clamp(int value, int low, int high) {
+ return value < low ? low : (value > high ? high : value);
+}
+
+static void setup_segmentation(AV1_COMMON *const cm,
+ union param_u *params) {
+ struct segmentation *const seg = &cm->seg;
+
+ seg->update_map = 0;
+ seg->update_data = 0;
+ seg->temporal_update = 0;
+
+ seg->enabled = params->p.seg_enabled; //aom_rb_read_bit(-1, defmark, rb);
+ if (!seg->enabled) {
+ if (cm->cur_frame->seg_map)
+ memset(cm->cur_frame->seg_map, 0, (cm->mi_rows * cm->mi_cols));
+
+ memset(seg, 0, sizeof(*seg));
+ segfeatures_copy(&cm->cur_frame->seg, seg);
+ return;
+ }
+ if (cm->seg.enabled && cm->prev_frame &&
+ (cm->mi_rows == cm->prev_frame->mi_rows) &&
+ (cm->mi_cols == cm->prev_frame->mi_cols)) {
+ cm->last_frame_seg_map = cm->prev_frame->seg_map;
+ } else {
+ cm->last_frame_seg_map = NULL;
+ }
+ // Read update flags
+ if (cm->primary_ref_frame == PRIMARY_REF_NONE) {
+ // These frames can't use previous frames, so must signal map + features
+ seg->update_map = 1;
+ seg->temporal_update = 0;
+ seg->update_data = 1;
+ } else {
+ seg->update_map = params->p.seg_update_map; // aom_rb_read_bit(-1, defmark, rb);
+ if (seg->update_map) {
+ seg->temporal_update = params->p.seg_temporal_update; //aom_rb_read_bit(-1, defmark, rb);
+ } else {
+ seg->temporal_update = 0;
+ }
+ seg->update_data = params->p.seg_update_data; //aom_rb_read_bit(-1, defmark, rb);
+ }
+
+ // Segmentation data update
+ if (seg->update_data) {
+ av1_clearall_segfeatures(seg);
+
+ for (int i = 0; i < MAX_SEGMENTS; i++) {
+ for (int j = 0; j < SEG_LVL_MAX; j++) {
+ int data = 0;
+ const int feature_enabled = params->p.seg_feature_enabled ;//aom_rb_read_bit(-1, defmark, rb);
+ if (feature_enabled) {
+ av1_enable_segfeature(seg, i, j);
+
+ const int data_max = av1_seg_feature_data_max(j);
+ const int data_min = -data_max;
+ /*
+ const int ubits = get_unsigned_bits(data_max);
+
+ if (av1_is_segfeature_signed(j)) {
+ data = aom_rb_read_inv_signed_literal(-1, defmark, rb, ubits);
+ } else {
+ data = aom_rb_read_literal(-1, defmark, rb, ubits);
+ }*/
+ data = params->p.seg_data;
+ data = clamp(data, data_min, data_max);
+ }
+ av1_set_segdata(seg, i, j, data);
+ }
+ }
+ av1_calculate_segdata(seg);
+ } else if (cm->prev_frame) {
+ segfeatures_copy(seg, &cm->prev_frame->seg);
+ }
+ segfeatures_copy(&cm->cur_frame->seg, seg);
+}
+#endif
+
+/**/
+
+
+int av1_decode_frame_headers_and_setup(AV1Decoder *pbi, int trailing_bits_present, union param_u *params)
+{
+ AV1_COMMON *const cm = pbi->common;
+ /*
+ read_uncompressed_header()
+ */
+ const SequenceHeader *const seq_params = &cm->seq_params;
+ CurrentFrame *const current_frame = &cm->current_frame;
+ //MACROBLOCKD *const xd = &pbi->mb;
+ BufferPool *const pool = cm->buffer_pool;
+ RefCntBuffer *const frame_bufs = pool->frame_bufs;
+ int i;
+ int frame_size_override_flag;
+ unsigned long flags;
+
+ if (!pbi->sequence_header_ready) {
+ aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "No sequence header");
+ }
+ cm->last_frame_type = current_frame->frame_type;
+
+ if (seq_params->reduced_still_picture_hdr) {
+ cm->show_existing_frame = 0;
+ cm->show_frame = 1;
+ current_frame->frame_type = KEY_FRAME;
+ if (pbi->sequence_header_changed) {
+ // This is the start of a new coded video sequence.
+ pbi->sequence_header_changed = 0;
+ pbi->decoding_first_frame = 1;
+ reset_frame_buffers(pbi);
+ }
+ cm->error_resilient_mode = 1;
+ } else {
+ cm->show_existing_frame = params->p.show_existing_frame;
+ pbi->reset_decoder_state = 0;
+ if (cm->show_existing_frame) {
+ int existing_frame_idx;
+ RefCntBuffer *frame_to_show;
+ if (pbi->sequence_header_changed) {
+ aom_internal_error(
+ &cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "New sequence header starts with a show_existing_frame.");
+ }
+ // Show an existing frame directly.
+ existing_frame_idx = params->p.existing_frame_idx; //aom_rb_read_literal(rb, 3);
+ frame_to_show = cm->ref_frame_map[existing_frame_idx];
+ if (frame_to_show == NULL) {
+ aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM,
+ "Buffer does not contain a decoded frame");
+ return 0;
+ }
+ if (seq_params->decoder_model_info_present_flag &&
+ cm->timing_info.equal_picture_interval == 0) {
+ cm->frame_presentation_time = params->p.frame_presentation_time;
+ //read_temporal_point_info(cm);
+ }
+ if (seq_params->frame_id_numbers_present_flag) {
+ //int frame_id_length = seq_params->frame_id_length;
+ int display_frame_id = params->p.display_frame_id; //aom_rb_read_literal(rb, frame_id_length);
+ /* Compare display_frame_id with ref_frame_id and check valid for
+ * referencing */
+ if (display_frame_id != cm->ref_frame_id[existing_frame_idx] ||
+ cm->valid_for_referencing[existing_frame_idx] == 0)
+ aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "Reference buffer frame ID mismatch");
+ }
+ lock_buffer_pool(pool, flags);
+ assert(frame_to_show->ref_count > 0);
+ // cm->cur_frame should be the buffer referenced by the return value
+ // of the get_free_fb() call in av1_receive_compressed_data(), and
+ // generate_next_ref_frame_map() has not been called, so ref_count
+ // should still be 1.
+ assert(cm->cur_frame->ref_count == 1);
+ // assign_frame_buffer_p() decrements ref_count directly rather than
+ // call decrease_ref_count(). If cm->cur_frame->raw_frame_buffer has
+ // already been allocated, it will not be released by
+ // assign_frame_buffer_p()!
+ assert(!cm->cur_frame->raw_frame_buffer.data);
+ assign_frame_buffer_p(&cm->cur_frame, frame_to_show);
+ pbi->reset_decoder_state = frame_to_show->frame_type == KEY_FRAME;
+ unlock_buffer_pool(pool, flags);
+
+#ifdef ORI_CODE
+ cm->lf.filter_level[0] = 0;
+ cm->lf.filter_level[1] = 0;
+#endif
+ cm->show_frame = 1;
+
+ // Section 6.8.2: It is a requirement of bitstream conformance that when
+ // show_existing_frame is used to show a previous frame, that the value
+ // of showable_frame for the previous frame was equal to 1.
+ if (!frame_to_show->showable_frame) {
+ aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM,
+ "Buffer does not contain a showable frame");
+ }
+ // Section 6.8.2: It is a requirement of bitstream conformance that when
+ // show_existing_frame is used to show a previous frame with
+ // RefFrameType[ frame_to_show_map_idx ] equal to KEY_FRAME, that the
+ // frame is output via the show_existing_frame mechanism at most once.
+ if (pbi->reset_decoder_state) frame_to_show->showable_frame = 0;
+
+#ifdef ORI_CODE
+ cm->film_grain_params = frame_to_show->film_grain_params;
+#endif
+ if (pbi->reset_decoder_state) {
+ show_existing_frame_reset(pbi, existing_frame_idx);
+ } else {
+ current_frame->refresh_frame_flags = 0;
+ }
+
+ return 0;
+ }
+
+ current_frame->frame_type = (FRAME_TYPE)params->p.frame_type; //aom_rb_read_literal(rb, 2);
+ if (pbi->sequence_header_changed) {
+ if (current_frame->frame_type == KEY_FRAME) {
+ // This is the start of a new coded video sequence.
+ pbi->sequence_header_changed = 0;
+ pbi->decoding_first_frame = 1;
+ reset_frame_buffers(pbi);
+ } else {
+ aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "Sequence header has changed without a keyframe.");
+ }
+ }
+ cm->show_frame = params->p.show_frame; //aom_rb_read_bit(rb);
+ if (seq_params->still_picture &&
+ (current_frame->frame_type != KEY_FRAME || !cm->show_frame)) {
+ aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "Still pictures must be coded as shown keyframes");
+ }
+ cm->showable_frame = current_frame->frame_type != KEY_FRAME;
+ if (cm->show_frame) {
+ if (seq_params->decoder_model_info_present_flag &&
+ cm->timing_info.equal_picture_interval == 0)
+ cm->frame_presentation_time = params->p.frame_presentation_time;
+ //read_temporal_point_info(cm);
+ } else {
+ // See if this frame can be used as show_existing_frame in future
+ cm->showable_frame = params->p.showable_frame;//aom_rb_read_bit(rb);
+ }
+ cm->cur_frame->showable_frame = cm->showable_frame;
+ cm->error_resilient_mode =
+ frame_is_sframe(cm) ||
+ (current_frame->frame_type == KEY_FRAME && cm->show_frame)
+ ? 1
+ : params->p.error_resilient_mode; //aom_rb_read_bit(rb);
+ }
+
+#ifdef ORI_CODE
+ cm->disable_cdf_update = aom_rb_read_bit(rb);
+ if (seq_params->force_screen_content_tools == 2) {
+ cm->allow_screen_content_tools = aom_rb_read_bit(rb);
+ } else {
+ cm->allow_screen_content_tools = seq_params->force_screen_content_tools;
+ }
+
+ if (cm->allow_screen_content_tools) {
+ if (seq_params->force_integer_mv == 2) {
+ cm->cur_frame_force_integer_mv = aom_rb_read_bit(rb);
+ } else {
+ cm->cur_frame_force_integer_mv = seq_params->force_integer_mv;
+ }
+ } else {
+ cm->cur_frame_force_integer_mv = 0;
+ }
+#endif
+
+ frame_size_override_flag = 0;
+ cm->allow_intrabc = 0;
+ cm->primary_ref_frame = PRIMARY_REF_NONE;
+
+ if (!seq_params->reduced_still_picture_hdr) {
+ if (seq_params->frame_id_numbers_present_flag) {
+ int frame_id_length = seq_params->frame_id_length;
+ int diff_len = seq_params->delta_frame_id_length;
+ int prev_frame_id = 0;
+ int have_prev_frame_id =
+ !pbi->decoding_first_frame &&
+ !(current_frame->frame_type == KEY_FRAME && cm->show_frame);
+ if (have_prev_frame_id) {
+ prev_frame_id = cm->current_frame_id;
+ }
+ cm->current_frame_id = params->p.current_frame_id; //aom_rb_read_literal(rb, frame_id_length);
+
+ if (have_prev_frame_id) {
+ int diff_frame_id;
+ if (cm->current_frame_id > prev_frame_id) {
+ diff_frame_id = cm->current_frame_id - prev_frame_id;
+ } else {
+ diff_frame_id =
+ (1 << frame_id_length) + cm->current_frame_id - prev_frame_id;
+ }
+ /* Check current_frame_id for conformance */
+ if (prev_frame_id == cm->current_frame_id ||
+ diff_frame_id >= (1 << (frame_id_length - 1))) {
+ aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "Invalid value of current_frame_id");
+ }
+ }
+ /* Check if some frames need to be marked as not valid for referencing */
+ for (i = 0; i < REF_FRAMES; i++) {
+ if (current_frame->frame_type == KEY_FRAME && cm->show_frame) {
+ cm->valid_for_referencing[i] = 0;
+ } else if (cm->current_frame_id - (1 << diff_len) > 0) {
+ if (cm->ref_frame_id[i] > cm->current_frame_id ||
+ cm->ref_frame_id[i] < cm->current_frame_id - (1 << diff_len))
+ cm->valid_for_referencing[i] = 0;
+ } else {
+ if (cm->ref_frame_id[i] > cm->current_frame_id &&
+ cm->ref_frame_id[i] < (1 << frame_id_length) +
+ cm->current_frame_id - (1 << diff_len))
+ cm->valid_for_referencing[i] = 0;
+ }
+ }
+ }
+
+ frame_size_override_flag = frame_is_sframe(cm) ? 1 : params->p.frame_size_override_flag; //aom_rb_read_bit(rb);
+
+ current_frame->order_hint = params->p.order_hint; /*aom_rb_read_literal(
+ rb, seq_params->order_hint_info.order_hint_bits_minus_1 + 1);*/
+ current_frame->frame_number = current_frame->order_hint;
+
+ if (!cm->error_resilient_mode && !frame_is_intra_only(cm)) {
+ cm->primary_ref_frame = params->p.primary_ref_frame;//aom_rb_read_literal(rb, PRIMARY_REF_BITS);
+ }
+ }
+
+ if (seq_params->decoder_model_info_present_flag) {
+ cm->buffer_removal_time_present = params->p.buffer_removal_time_present; //aom_rb_read_bit(rb);
+ if (cm->buffer_removal_time_present) {
+ int op_num;
+ for (op_num = 0;
+ op_num < seq_params->operating_points_cnt_minus_1 + 1; op_num++) {
+ if (cm->op_params[op_num].decoder_model_param_present_flag) {
+ if ((((seq_params->operating_point_idc[op_num] >>
+ cm->temporal_layer_id) &
+ 0x1) &&
+ ((seq_params->operating_point_idc[op_num] >>
+ (cm->spatial_layer_id + 8)) &
+ 0x1)) ||
+ seq_params->operating_point_idc[op_num] == 0) {
+ cm->op_frame_timing[op_num].buffer_removal_time =
+ params->p.op_frame_timing[op_num];
+ /*aom_rb_read_unsigned_literal(
+ rb, cm->buffer_model.buffer_removal_time_length);*/
+ } else {
+ cm->op_frame_timing[op_num].buffer_removal_time = 0;
+ }
+ } else {
+ cm->op_frame_timing[op_num].buffer_removal_time = 0;
+ }
+ }
+ }
+ }
+ if (current_frame->frame_type == KEY_FRAME) {
+ if (!cm->show_frame) { // unshown keyframe (forward keyframe)
+ current_frame->refresh_frame_flags = params->p.refresh_frame_flags; //aom_rb_read_literal(rb, REF_FRAMES);
+ } else { // shown keyframe
+ current_frame->refresh_frame_flags = (1 << REF_FRAMES) - 1;
+ }
+
+ for (i = 0; i < INTER_REFS_PER_FRAME; ++i) {
+ cm->remapped_ref_idx[i] = INVALID_IDX;
+ }
+ if (pbi->need_resync) {
+ reset_ref_frame_map(pbi);
+ pbi->need_resync = 0;
+ }
+ } else {
+ if (current_frame->frame_type == INTRA_ONLY_FRAME) {
+ current_frame->refresh_frame_flags = params->p.refresh_frame_flags; //aom_rb_read_literal(rb, REF_FRAMES);
+ if (current_frame->refresh_frame_flags == 0xFF) {
+ aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM,
+ "Intra only frames cannot have refresh flags 0xFF");
+ }
+ if (pbi->need_resync) {
+ reset_ref_frame_map(pbi);
+ pbi->need_resync = 0;
+ }
+ } else if (pbi->need_resync != 1) { /* Skip if need resync */
+ current_frame->refresh_frame_flags =
+ frame_is_sframe(cm) ? 0xFF : params->p.refresh_frame_flags; //aom_rb_read_literal(rb, REF_FRAMES);
+ }
+ }
+
+ if (!frame_is_intra_only(cm) || current_frame->refresh_frame_flags != 0xFF) {
+ // Read all ref frame order hints if error_resilient_mode == 1
+ if (cm->error_resilient_mode &&
+ seq_params->order_hint_info.enable_order_hint) {
+ int ref_idx;
+ for (ref_idx = 0; ref_idx < REF_FRAMES; ref_idx++) {
+ // Read order hint from bit stream
+ unsigned int order_hint = params->p.ref_order_hint[ref_idx];/*aom_rb_read_literal(
+ rb, seq_params->order_hint_info.order_hint_bits_minus_1 + 1);*/
+ // Get buffer
+ RefCntBuffer *buf = cm->ref_frame_map[ref_idx];
+ int buf_idx;
+ if (buf == NULL || order_hint != buf->order_hint) {
+ if (buf != NULL) {
+ lock_buffer_pool(pool, flags);
+ decrease_ref_count(pbi, buf, pool);
+ unlock_buffer_pool(pool, flags);
+ }
+ // If no corresponding buffer exists, allocate a new buffer with all
+ // pixels set to neutral grey.
+ buf_idx = get_free_frame_buffer(cm);
+ if (buf_idx == INVALID_IDX) {
+ aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
+ "Unable to find free frame buffer");
+ }
+ buf = &frame_bufs[buf_idx];
+ lock_buffer_pool(pool, flags);
+ if (aom_realloc_frame_buffer(cm, &buf->buf, seq_params->max_frame_width,
+ seq_params->max_frame_height, buf->order_hint)) {
+ decrease_ref_count(pbi, buf, pool);
+ unlock_buffer_pool(pool, flags);
+ aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
+ "Failed to allocate frame buffer");
+ }
+ unlock_buffer_pool(pool, flags);
+#ifdef ORI_CODE
+ set_planes_to_neutral_grey(seq_params, &buf->buf, 0);
+#endif
+ cm->ref_frame_map[ref_idx] = buf;
+ buf->order_hint = order_hint;
+ }
+ }
+ }
+ }
+
+ if (current_frame->frame_type == KEY_FRAME) {
+ setup_frame_size(cm, frame_size_override_flag, params);
+#ifdef ORI_CODE
+ if (cm->allow_screen_content_tools && !av1_superres_scaled(cm))
+ cm->allow_intrabc = aom_rb_read_bit(rb);
+#endif
+ cm->allow_ref_frame_mvs = 0;
+ cm->prev_frame = NULL;
+ } else {
+ cm->allow_ref_frame_mvs = 0;
+
+ if (current_frame->frame_type == INTRA_ONLY_FRAME) {
+#ifdef ORI_CODE
+ cm->cur_frame->film_grain_params_present =
+ seq_params->film_grain_params_present;
+#endif
+ setup_frame_size(cm, frame_size_override_flag, params);
+#ifdef ORI_CODE
+ if (cm->allow_screen_content_tools && !av1_superres_scaled(cm))
+ cm->allow_intrabc = aom_rb_read_bit(rb);
+#endif
+ } else if (pbi->need_resync != 1) { /* Skip if need resync */
+ int frame_refs_short_signaling = 0;
+ // Frame refs short signaling is off when error resilient mode is on.
+ if (seq_params->order_hint_info.enable_order_hint)
+ frame_refs_short_signaling = params->p.frame_refs_short_signaling;//aom_rb_read_bit(rb);
+
+ if (frame_refs_short_signaling) {
+ // == LAST_FRAME ==
+ const int lst_ref = params->p.lst_ref; //aom_rb_read_literal(rb, REF_FRAMES_LOG2);
+ const RefCntBuffer *const lst_buf = cm->ref_frame_map[lst_ref];
+
+ // == GOLDEN_FRAME ==
+ const int gld_ref = params->p.gld_ref; //aom_rb_read_literal(rb, REF_FRAMES_LOG2);
+ const RefCntBuffer *const gld_buf = cm->ref_frame_map[gld_ref];
+
+ // Most of the time, streams start with a keyframe. In that case,
+ // ref_frame_map will have been filled in at that point and will not
+ // contain any NULLs. However, streams are explicitly allowed to start
+ // with an intra-only frame, so long as they don't then signal a
+ // reference to a slot that hasn't been set yet. That's what we are
+ // checking here.
+ if (lst_buf == NULL)
+ aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "Inter frame requests nonexistent reference");
+ if (gld_buf == NULL)
+ aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "Inter frame requests nonexistent reference");
+
+ av1_set_frame_refs(cm, cm->remapped_ref_idx, lst_ref, gld_ref);
+ }
+
+ for (i = 0; i < INTER_REFS_PER_FRAME; ++i) {
+ int ref = 0;
+ if (!frame_refs_short_signaling) {
+ ref = params->p.remapped_ref_idx[i];//aom_rb_read_literal(rb, REF_FRAMES_LOG2);
+
+ // Most of the time, streams start with a keyframe. In that case,
+ // ref_frame_map will have been filled in at that point and will not
+ // contain any NULLs. However, streams are explicitly allowed to start
+ // with an intra-only frame, so long as they don't then signal a
+ // reference to a slot that hasn't been set yet. That's what we are
+ // checking here.
+ if (cm->ref_frame_map[ref] == NULL)
+ aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "Inter frame requests nonexistent reference");
+ cm->remapped_ref_idx[i] = ref;
+ } else {
+ ref = cm->remapped_ref_idx[i];
+ }
+
+ cm->ref_frame_sign_bias[LAST_FRAME + i] = 0;
+
+ if (seq_params->frame_id_numbers_present_flag) {
+ int frame_id_length = seq_params->frame_id_length;
+ //int diff_len = seq_params->delta_frame_id_length;
+ int delta_frame_id_minus_1 = params->p.delta_frame_id_minus_1[i];//aom_rb_read_literal(rb, diff_len);
+ int ref_frame_id =
+ ((cm->current_frame_id - (delta_frame_id_minus_1 + 1) +
+ (1 << frame_id_length)) %
+ (1 << frame_id_length));
+ // Compare values derived from delta_frame_id_minus_1 and
+ // refresh_frame_flags. Also, check valid for referencing
+ if (ref_frame_id != cm->ref_frame_id[ref] ||
+ cm->valid_for_referencing[ref] == 0)
+ aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "Reference buffer frame ID mismatch");
+ }
+ }
+
+ if (!cm->error_resilient_mode && frame_size_override_flag) {
+ setup_frame_size_with_refs(cm, params);
+ } else {
+ setup_frame_size(cm, frame_size_override_flag, params);
+ }
+#ifdef ORI_CODE
+ if (cm->cur_frame_force_integer_mv) {
+ cm->allow_high_precision_mv = 0;
+ } else {
+ cm->allow_high_precision_mv = aom_rb_read_bit(rb);
+ }
+ cm->interp_filter = read_frame_interp_filter(rb);
+ cm->switchable_motion_mode = aom_rb_read_bit(rb);
+#endif
+ }
+
+ cm->prev_frame = get_primary_ref_frame_buf(cm);
+ if (cm->primary_ref_frame != PRIMARY_REF_NONE &&
+ get_primary_ref_frame_buf(cm) == NULL) {
+ aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "Reference frame containing this frame's initial "
+ "frame context is unavailable.");
+ }
+#if 0
+ av1_print2(AV1_DEBUG_BUFMGR_DETAIL, "%d,%d,%d,%d\n",cm->error_resilient_mode,
+ cm->seq_params.order_hint_info.enable_ref_frame_mvs,
+ cm->seq_params.order_hint_info.enable_order_hint,frame_is_intra_only(cm));
+
+ printf("frame_might_allow_ref_frame_mvs()=>%d, current_frame->frame_type=%d, pbi->need_resync=%d, params->p.allow_ref_frame_mvs=%d\n",
+ frame_might_allow_ref_frame_mvs(cm), current_frame->frame_type, pbi->need_resync,
+ params->p.allow_ref_frame_mvs);
+#endif
+ if (!(current_frame->frame_type == INTRA_ONLY_FRAME) &&
+ pbi->need_resync != 1) {
+ if (frame_might_allow_ref_frame_mvs(cm))
+ cm->allow_ref_frame_mvs = params->p.allow_ref_frame_mvs; //aom_rb_read_bit(-1, "<allow_ref_frame_mvs>", rb);
+ else
+ cm->allow_ref_frame_mvs = 0;
+
+#ifdef SUPPORT_SCALE_FACTOR
+ for (i = LAST_FRAME; i <= ALTREF_FRAME; ++i) {
+ const RefCntBuffer *const ref_buf = get_ref_frame_buf(cm, i);
+ struct scale_factors *const ref_scale_factors =
+ get_ref_scale_factors(cm, i);
+ if (ref_buf != NULL) {
+#ifdef AML
+ av1_setup_scale_factors_for_frame(
+ ref_scale_factors, ref_buf->buf.y_crop_width,
+ ref_buf->buf.y_crop_height, cm->dec_width, cm->height);
+#else
+ av1_setup_scale_factors_for_frame(
+ ref_scale_factors, ref_buf->buf.y_crop_width,
+ ref_buf->buf.y_crop_height, cm->width, cm->height);
+#endif
+ }
+ if (ref_scale_factors) {
+ if ((!av1_is_valid_scale(ref_scale_factors)))
+ aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM,
+ "Reference frame has invalid dimensions");
+ }
+ }
+#endif
+ }
+ }
+
+ av1_setup_frame_buf_refs(cm);
+
+ av1_setup_frame_sign_bias(cm);
+
+ cm->cur_frame->frame_type = current_frame->frame_type;
+
+ if (seq_params->frame_id_numbers_present_flag) {
+ update_ref_frame_id(cm, cm->current_frame_id);
+ }
+#ifdef ORI_CODE
+ const int might_bwd_adapt =
+ !(seq_params->reduced_still_picture_hdr) && !(cm->disable_cdf_update);
+ if (might_bwd_adapt) {
+ cm->refresh_frame_context = aom_rb_read_bit(rb)
+ ? REFRESH_FRAME_CONTEXT_DISABLED
+ : REFRESH_FRAME_CONTEXT_BACKWARD;
+ } else {
+ cm->refresh_frame_context = REFRESH_FRAME_CONTEXT_DISABLED;
+ }
+#endif
+
+ cm->cur_frame->buf.bit_depth = seq_params->bit_depth;
+ cm->cur_frame->buf.color_primaries = seq_params->color_primaries;
+ cm->cur_frame->buf.transfer_characteristics =
+ seq_params->transfer_characteristics;
+ cm->cur_frame->buf.matrix_coefficients = seq_params->matrix_coefficients;
+ cm->cur_frame->buf.monochrome = seq_params->monochrome;
+ cm->cur_frame->buf.chroma_sample_position =
+ seq_params->chroma_sample_position;
+ cm->cur_frame->buf.color_range = seq_params->color_range;
+ cm->cur_frame->buf.render_width = cm->render_width;
+ cm->cur_frame->buf.render_height = cm->render_height;
+
+ if (pbi->need_resync) {
+ aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "Keyframe / intra-only frame required to reset decoder"
+ " state");
+ }
+
+ generate_next_ref_frame_map(pbi);
+
+#ifdef ORI_CODE
+ if (cm->allow_intrabc) {
+ // Set parameters corresponding to no filtering.
+ struct loopfilter *lf = &cm->lf;
+ lf->filter_level[0] = 0;
+ lf->filter_level[1] = 0;
+ cm->cdef_info.cdef_bits = 0;
+ cm->cdef_info.cdef_strengths[0] = 0;
+ cm->cdef_info.nb_cdef_strengths = 1;
+ cm->cdef_info.cdef_uv_strengths[0] = 0;
+ cm->rst_info[0].frame_restoration_type = RESTORE_NONE;
+ cm->rst_info[1].frame_restoration_type = RESTORE_NONE;
+ cm->rst_info[2].frame_restoration_type = RESTORE_NONE;
+ }
+
+ read_tile_info(pbi, rb);
+ if (!av1_is_min_tile_width_satisfied(cm)) {
+ aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "Minimum tile width requirement not satisfied");
+ }
+
+ setup_quantization(cm, rb);
+ xd->bd = (int)seq_params->bit_depth;
+
+ if (cm->num_allocated_above_context_planes < av1_num_planes(cm) ||
+ cm->num_allocated_above_context_mi_col < cm->mi_cols ||
+ cm->num_allocated_above_contexts < cm->tile_rows) {
+ av1_free_above_context_buffers(cm, cm->num_allocated_above_contexts);
+ if (av1_alloc_above_context_buffers(cm, cm->tile_rows))
+ aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
+ "Failed to allocate context buffers");
+ }
+
+ if (cm->primary_ref_frame == PRIMARY_REF_NONE) {
+ av1_setup_past_independence(cm);
+ }
+
+ setup_segmentation(cm, params);
+
+ cm->delta_q_info.delta_q_res = 1;
+ cm->delta_q_info.delta_lf_res = 1;
+ cm->delta_q_info.delta_lf_present_flag = 0;
+ cm->delta_q_info.delta_lf_multi = 0;
+ cm->delta_q_info.delta_q_present_flag =
+ cm->base_qindex > 0 ? aom_rb_read_bit(-1, defmark, rb) : 0;
+ if (cm->delta_q_info.delta_q_present_flag) {
+ xd->current_qindex = cm->base_qindex;
+ cm->delta_q_info.delta_q_res = 1 << aom_rb_read_literal(-1, defmark, rb, 2);
+ if (!cm->allow_intrabc)
+ cm->delta_q_info.delta_lf_present_flag = aom_rb_read_bit(-1, defmark, rb);
+ if (cm->delta_q_info.delta_lf_present_flag) {
+ cm->delta_q_info.delta_lf_res = 1 << aom_rb_read_literal(-1, defmark, rb, 2);
+ cm->delta_q_info.delta_lf_multi = aom_rb_read_bit(-1, defmark, rb);
+ av1_reset_loop_filter_delta(xd, av1_num_planes(cm));
+ }
+ }
+
+ xd->cur_frame_force_integer_mv = cm->cur_frame_force_integer_mv;
+
+ for (int i = 0; i < MAX_SEGMENTS; ++i) {
+ const int qindex = av1_get_qindex(&cm->seg, i, cm->base_qindex);
+ xd->lossless[i] = qindex == 0 && cm->y_dc_delta_q == 0 &&
+ cm->u_dc_delta_q == 0 && cm->u_ac_delta_q == 0 &&
+ cm->v_dc_delta_q == 0 && cm->v_ac_delta_q == 0;
+ xd->qindex[i] = qindex;
+ }
+ cm->coded_lossless = is_coded_lossless(cm, xd);
+ cm->all_lossless = cm->coded_lossless && !av1_superres_scaled(cm);
+ setup_segmentation_dequant(cm, xd);
+ if (cm->coded_lossless) {
+ cm->lf.filter_level[0] = 0;
+ cm->lf.filter_level[1] = 0;
+ }
+ if (cm->coded_lossless || !seq_params->enable_cdef) {
+ cm->cdef_info.cdef_bits = 0;
+ cm->cdef_info.cdef_strengths[0] = 0;
+ cm->cdef_info.cdef_uv_strengths[0] = 0;
+ }
+ if (cm->all_lossless || !seq_params->enable_restoration) {
+ cm->rst_info[0].frame_restoration_type = RESTORE_NONE;
+ cm->rst_info[1].frame_restoration_type = RESTORE_NONE;
+ cm->rst_info[2].frame_restoration_type = RESTORE_NONE;
+ }
+ setup_loopfilter(cm, rb);
+
+ if (!cm->coded_lossless && seq_params->enable_cdef) {
+ setup_cdef(cm, rb);
+ }
+ if (!cm->all_lossless && seq_params->enable_restoration) {
+ decode_restoration_mode(cm, rb);
+ }
+
+ cm->tx_mode = read_tx_mode(cm, rb);
+#endif
+
+ current_frame->reference_mode = read_frame_reference_mode(cm, params);
+
+#ifdef ORI_CODE
+ if (current_frame->reference_mode != SINGLE_REFERENCE)
+ setup_compound_reference_mode(cm);
+
+
+#endif
+
+ av1_setup_skip_mode_allowed(cm);
+
+ /*
+ the point that ucode send send_bufmgr_info
+ and wait bufmgr code to return is_skip_mode_allowed
+ */
+
+ /*
+ read_uncompressed_header() end
+ */
+
+ av1_setup_motion_field(cm);
+#ifdef AML
+ cm->cur_frame->mi_cols = cm->mi_cols;
+ cm->cur_frame->mi_rows = cm->mi_rows;
+ cm->cur_frame->dec_width = cm->dec_width;
+
+ /*
+ superres_post_decode(AV1Decoder *pbi) =>
+ av1_superres_upscale(cm, pool); =>
+ aom_realloc_frame_buffer(
+ frame_to_show, cm->superres_upscaled_width,
+ cm->superres_upscaled_height, seq_params->subsampling_x,
+ seq_params->subsampling_y, seq_params->use_highbitdepth,
+ AOM_BORDER_IN_PIXELS, cm->byte_alignment, fb, cb, cb_priv)
+ */
+ aom_realloc_frame_buffer(cm, &cm->cur_frame->buf,
+ cm->superres_upscaled_width, cm->superres_upscaled_height,
+ cm->cur_frame->order_hint);
+#endif
+ return 0;
+}
+
+static int are_seq_headers_consistent(const SequenceHeader *seq_params_old,
+ const SequenceHeader *seq_params_new) {
+ return !memcmp(seq_params_old, seq_params_new, sizeof(SequenceHeader));
+}
+
+aom_codec_err_t aom_get_num_layers_from_operating_point_idc(
+ int operating_point_idc, unsigned int *number_spatial_layers,
+ unsigned int *number_temporal_layers) {
+ // derive number of spatial/temporal layers from operating_point_idc
+
+ if (!number_spatial_layers || !number_temporal_layers)
+ return AOM_CODEC_INVALID_PARAM;
+
+ if (operating_point_idc == 0) {
+ *number_temporal_layers = 1;
+ *number_spatial_layers = 1;
+ } else {
+ int j;
+ *number_spatial_layers = 0;
+ *number_temporal_layers = 0;
+ for (j = 0; j < MAX_NUM_SPATIAL_LAYERS; j++) {
+ *number_spatial_layers +=
+ (operating_point_idc >> (j + MAX_NUM_TEMPORAL_LAYERS)) & 0x1;
+ }
+ for (j = 0; j < MAX_NUM_TEMPORAL_LAYERS; j++) {
+ *number_temporal_layers += (operating_point_idc >> j) & 0x1;
+ }
+ }
+
+ return AOM_CODEC_OK;
+}
+
+void av1_read_sequence_header(AV1_COMMON *cm, union param_u *params,
+ SequenceHeader *seq_params) {
+#ifdef ORI_CODE
+ const int num_bits_width = aom_rb_read_literal(-1, "<num_bits_width>", rb, 4) + 1;
+ const int num_bits_height = aom_rb_read_literal(-1, "<num_bits_height>", rb, 4) + 1;
+ const int max_frame_width = aom_rb_read_literal(-1, "<max_frame_width>", rb, num_bits_width) + 1;
+ const int max_frame_height = aom_rb_read_literal(-1, "<max_frame_height>", rb, num_bits_height) + 1;
+
+ seq_params->num_bits_width = num_bits_width;
+ seq_params->num_bits_height = num_bits_height;
+#endif
+ seq_params->max_frame_width = params->p.max_frame_width; //max_frame_width;
+ seq_params->max_frame_height = params->p.max_frame_height; //max_frame_height;
+
+ if (seq_params->reduced_still_picture_hdr) {
+ seq_params->frame_id_numbers_present_flag = 0;
+ } else {
+ seq_params->frame_id_numbers_present_flag = params->p.frame_id_numbers_present_flag; //aom_rb_read_bit(-1, "<frame_id_numbers_present_flag>", rb);
+ }
+ if (seq_params->frame_id_numbers_present_flag) {
+ // We must always have delta_frame_id_length < frame_id_length,
+ // in order for a frame to be referenced with a unique delta.
+ // Avoid wasting bits by using a coding that enforces this restriction.
+#ifdef ORI_CODE
+ seq_params->delta_frame_id_length = aom_rb_read_literal(-1, "<delta_frame_id_length>", rb, 4) + 2;
+ seq_params->frame_id_length = params->p.frame_id_length + aom_rb_read_literal(-1, "<frame_id_length>", rb, 3) + seq_params->delta_frame_id_length + 1;
+#else
+ seq_params->delta_frame_id_length = params->p.delta_frame_id_length;
+ seq_params->frame_id_length = params->p.frame_id_length + seq_params->delta_frame_id_length + 1;
+#endif
+ if (seq_params->frame_id_length > 16)
+ aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "Invalid frame_id_length");
+ }
+#ifdef ORI_CODE
+ setup_sb_size(seq_params, rb);
+ seq_params->enable_filter_intra = aom_rb_read_bit(-1, "<enable_filter_intra>", rb);
+ seq_params->enable_intra_edge_filter = aom_rb_read_bit(-1, "<enable_intra_edge_filter>", rb);
+#endif
+
+ if (seq_params->reduced_still_picture_hdr) {
+ seq_params->enable_interintra_compound = 0;
+ seq_params->enable_masked_compound = 0;
+ seq_params->enable_warped_motion = 0;
+ seq_params->enable_dual_filter = 0;
+ seq_params->order_hint_info.enable_order_hint = 0;
+ seq_params->order_hint_info.enable_dist_wtd_comp = 0;
+ seq_params->order_hint_info.enable_ref_frame_mvs = 0;
+ seq_params->force_screen_content_tools = 2; // SELECT_SCREEN_CONTENT_TOOLS
+ seq_params->force_integer_mv = 2; // SELECT_INTEGER_MV
+ seq_params->order_hint_info.order_hint_bits_minus_1 = -1;
+ } else {
+#ifdef ORI_CODE
+ seq_params->enable_interintra_compound = aom_rb_read_bit(-1, "<enable_interintra_compound>", rb);
+ seq_params->enable_masked_compound = aom_rb_read_bit(-1, "<enable_masked_compound>", rb);
+ seq_params->enable_warped_motion = aom_rb_read_bit(-1, "<enable_warped_motion>", rb);
+ seq_params->enable_dual_filter = aom_rb_read_bit(-1, "<enable_dual_filter>", rb);
+#endif
+ seq_params->order_hint_info.enable_order_hint = params->p.enable_order_hint; //aom_rb_read_bit(-1, "<order_hint_info.enable_order_hint>", rb);
+ seq_params->order_hint_info.enable_dist_wtd_comp =
+ seq_params->order_hint_info.enable_order_hint ? params->p.enable_dist_wtd_comp : 0; //aom_rb_read_bit(-1, "<order_hint_info.enable_dist_wtd_comp>", rb) : 0;
+ seq_params->order_hint_info.enable_ref_frame_mvs =
+ seq_params->order_hint_info.enable_order_hint ? params->p.enable_ref_frame_mvs : 0; //aom_rb_read_bit(-1, "<order_hint_info.enable_ref_frame_mvs>", rb) : 0;
+
+#ifdef ORI_CODE
+ if (aom_rb_read_bit(-1, defmark, rb)) {
+ seq_params->force_screen_content_tools =
+ 2; // SELECT_SCREEN_CONTENT_TOOLS
+ } else {
+ seq_params->force_screen_content_tools = aom_rb_read_bit(-1, defmark, rb);
+ }
+
+ if (seq_params->force_screen_content_tools > 0) {
+ if (aom_rb_read_bit(-1, defmark, rb)) {
+ seq_params->force_integer_mv = 2; // SELECT_INTEGER_MV
+ } else {
+ seq_params->force_integer_mv = aom_rb_read_bit(-1, defmark, rb);
+ }
+ } else {
+ seq_params->force_integer_mv = 2; // SELECT_INTEGER_MV
+ }
+#endif
+ seq_params->order_hint_info.order_hint_bits_minus_1 =
+ seq_params->order_hint_info.enable_order_hint
+ ? params->p.order_hint_bits_minus_1 /*aom_rb_read_literal(-1, "<order_hint_info.order_hint_bits_minus_1>", rb, 3)*/
+ : -1;
+ }
+ seq_params->enable_superres = params->p.enable_superres; //aom_rb_read_bit(-1, defmark, rb);
+
+#ifdef ORI_CODE
+ seq_params->enable_cdef = aom_rb_read_bit(-1, defmark, rb);
+ seq_params->enable_restoration = aom_rb_read_bit(-1, defmark, rb);
+#endif
+}
+
+#ifdef ORI_CODE
+void av1_read_op_parameters_info(AV1_COMMON *const cm,
+ struct aom_read_bit_buffer *rb, int op_num) {
+ // The cm->op_params array has MAX_NUM_OPERATING_POINTS + 1 elements.
+ if (op_num > MAX_NUM_OPERATING_POINTS) {
+ aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM,
+ "AV1 does not support %d decoder model operating points",
+ op_num + 1);
+ }
+
+ cm->op_params[op_num].decoder_buffer_delay = aom_rb_read_unsigned_literal(-1, defmark,
+ rb, cm->buffer_model.encoder_decoder_buffer_delay_length);
+
+ cm->op_params[op_num].encoder_buffer_delay = aom_rb_read_unsigned_literal(-1, defmark,
+ rb, cm->buffer_model.encoder_decoder_buffer_delay_length);
+
+ cm->op_params[op_num].low_delay_mode_flag = aom_rb_read_bit(-1, defmark, rb);
+}
+#endif
+
+static int is_valid_seq_level_idx(AV1_LEVEL seq_level_idx) {
+ return seq_level_idx < SEQ_LEVELS || seq_level_idx == SEQ_LEVEL_MAX;
+}
+
+static uint32_t read_sequence_header_obu(AV1Decoder *pbi,
+ union param_u *params) {
+ AV1_COMMON *const cm = pbi->common;
+ int i;
+ int operating_point;
+ // Verify rb has been configured to report errors.
+ //assert(rb->error_handler);
+
+ // Use a local variable to store the information as we decode. At the end,
+ // if no errors have occurred, cm->seq_params is updated.
+ SequenceHeader sh = cm->seq_params;
+ SequenceHeader *const seq_params = &sh;
+
+ seq_params->profile = params->p.profile; //av1_read_profile(rb);
+ if (seq_params->profile > CONFIG_MAX_DECODE_PROFILE) {
+ cm->error.error_code = AOM_CODEC_UNSUP_BITSTREAM;
+ return 0;
+ }
+
+ // Still picture or not
+ seq_params->still_picture = params->p.still_picture; //aom_rb_read_bit(-1, "<still_picture>", rb);
+ seq_params->reduced_still_picture_hdr = params->p.reduced_still_picture_hdr; //aom_rb_read_bit(-1, "<reduced_still_picture_hdr>", rb);
+ // Video must have reduced_still_picture_hdr = 0
+ if (!seq_params->still_picture && seq_params->reduced_still_picture_hdr) {
+ cm->error.error_code = AOM_CODEC_UNSUP_BITSTREAM;
+ return 0;
+ }
+
+ if (seq_params->reduced_still_picture_hdr) {
+ cm->timing_info_present = 0;
+ seq_params->decoder_model_info_present_flag = 0;
+ seq_params->display_model_info_present_flag = 0;
+ seq_params->operating_points_cnt_minus_1 = 0;
+ seq_params->operating_point_idc[0] = 0;
+ //if (!read_bitstream_level(0, "<seq_level_idx>", &seq_params->seq_level_idx[0], rb)) {
+ if (!is_valid_seq_level_idx(params->p.seq_level_idx[0])) {
+ cm->error.error_code = AOM_CODEC_UNSUP_BITSTREAM;
+ return 0;
+ }
+ seq_params->tier[0] = 0;
+ cm->op_params[0].decoder_model_param_present_flag = 0;
+ cm->op_params[0].display_model_param_present_flag = 0;
+ } else {
+ cm->timing_info_present = params->p.timing_info_present; //aom_rb_read_bit(-1, "<timing_info_present>", rb); // timing_info_present_flag
+ if (cm->timing_info_present) {
+#ifdef ORI_CODE
+ av1_read_timing_info_header(cm, rb);
+#endif
+ seq_params->decoder_model_info_present_flag = params->p.decoder_model_info_present_flag; //aom_rb_read_bit(-1, "<decoder_model_info_present_flag>", rb);
+#ifdef ORI_CODE
+ if (seq_params->decoder_model_info_present_flag)
+ av1_read_decoder_model_info(cm, rb);
+#endif
+ } else {
+ seq_params->decoder_model_info_present_flag = 0;
+ }
+#ifdef ORI_CODE
+ seq_params->display_model_info_present_flag = aom_rb_read_bit(-1, "<display_model_info_present_flag>", rb);
+#endif
+ seq_params->operating_points_cnt_minus_1 = params->p.operating_points_cnt_minus_1;
+ //aom_rb_read_literal(-1, "<operating_points_cnt_minus_1>", rb, OP_POINTS_CNT_MINUS_1_BITS);
+ for (i = 0; i < seq_params->operating_points_cnt_minus_1 + 1; i++) {
+ seq_params->operating_point_idc[i] = params->p.operating_point_idc[i];
+ //aom_rb_read_literal(i, "<operating_point_idc>", rb, OP_POINTS_IDC_BITS);
+ //if (!read_bitstream_level(i, "<seq_level_idx>", &seq_params->seq_level_idx[i], rb)) {
+ if (!is_valid_seq_level_idx(params->p.seq_level_idx[i])) {
+ cm->error.error_code = AOM_CODEC_UNSUP_BITSTREAM;
+ return 0;
+ }
+ // This is the seq_level_idx[i] > 7 check in the spec. seq_level_idx 7
+ // is equivalent to level 3.3.
+#ifdef ORI_CODE
+ if (seq_params->seq_level_idx[i] >= SEQ_LEVEL_4_0)
+ seq_params->tier[i] = aom_rb_read_bit(i, "<tier>", rb);
+ else
+ seq_params->tier[i] = 0;
+#endif
+ if (seq_params->decoder_model_info_present_flag) {
+ cm->op_params[i].decoder_model_param_present_flag = params->p.decoder_model_param_present_flag[i]; //aom_rb_read_bit(-1, defmark, rb);
+#ifdef ORI_CODE
+ if (cm->op_params[i].decoder_model_param_present_flag)
+ av1_read_op_parameters_info(cm, rb, i);
+#endif
+ } else {
+ cm->op_params[i].decoder_model_param_present_flag = 0;
+ }
+#ifdef ORI_CODE
+ if (cm->timing_info_present &&
+ (cm->timing_info.equal_picture_interval ||
+ cm->op_params[i].decoder_model_param_present_flag)) {
+ cm->op_params[i].bitrate = av1_max_level_bitrate(
+ seq_params->profile, seq_params->seq_level_idx[i],
+ seq_params->tier[i]);
+ // Level with seq_level_idx = 31 returns a high "dummy" bitrate to pass
+ // the check
+ if (cm->op_params[i].bitrate == 0)
+ aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM,
+ "AV1 does not support this combination of "
+ "profile, level, and tier.");
+ // Buffer size in bits/s is bitrate in bits/s * 1 s
+ cm->op_params[i].buffer_size = cm->op_params[i].bitrate;
+ }
+#endif
+ if (cm->timing_info_present && cm->timing_info.equal_picture_interval &&
+ !cm->op_params[i].decoder_model_param_present_flag) {
+ // When the decoder_model_parameters are not sent for this op, set
+ // the default ones that can be used with the resource availability mode
+ cm->op_params[i].decoder_buffer_delay = 70000;
+ cm->op_params[i].encoder_buffer_delay = 20000;
+ cm->op_params[i].low_delay_mode_flag = 0;
+ }
+
+#ifdef ORI_CODE
+ if (seq_params->display_model_info_present_flag) {
+ cm->op_params[i].display_model_param_present_flag = aom_rb_read_bit(-1, defmark, rb);
+ if (cm->op_params[i].display_model_param_present_flag) {
+ cm->op_params[i].initial_display_delay =
+ aom_rb_read_literal(-1, defmark, rb, 4) + 1;
+ if (cm->op_params[i].initial_display_delay > 10)
+ aom_internal_error(
+ &cm->error, AOM_CODEC_UNSUP_BITSTREAM,
+ "AV1 does not support more than 10 decoded frames delay");
+ } else {
+ cm->op_params[i].initial_display_delay = 10;
+ }
+ } else {
+ cm->op_params[i].display_model_param_present_flag = 0;
+ cm->op_params[i].initial_display_delay = 10;
+ }
+#endif
+ }
+ }
+ // This decoder supports all levels. Choose operating point provided by
+ // external means
+ operating_point = pbi->operating_point;
+ if (operating_point < 0 ||
+ operating_point > seq_params->operating_points_cnt_minus_1)
+ operating_point = 0;
+ pbi->current_operating_point =
+ seq_params->operating_point_idc[operating_point];
+ if (aom_get_num_layers_from_operating_point_idc(
+ pbi->current_operating_point, &cm->number_spatial_layers,
+ &cm->number_temporal_layers) != AOM_CODEC_OK) {
+ cm->error.error_code = AOM_CODEC_ERROR;
+ return 0;
+ }
+
+ av1_read_sequence_header(cm, params, seq_params);
+#ifdef ORI_CODE
+ av1_read_color_config(rb, pbi->allow_lowbitdepth, seq_params, &cm->error);
+ if (!(seq_params->subsampling_x == 0 && seq_params->subsampling_y == 0) &&
+ !(seq_params->subsampling_x == 1 && seq_params->subsampling_y == 1) &&
+ !(seq_params->subsampling_x == 1 && seq_params->subsampling_y == 0)) {
+ aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM,
+ "Only 4:4:4, 4:2:2 and 4:2:0 are currently supported, "
+ "%d %d subsampling is not supported.\n",
+ seq_params->subsampling_x, seq_params->subsampling_y);
+ }
+ seq_params->film_grain_params_present = aom_rb_read_bit(-1, "<film_grain_params_present>", rb);
+
+ if (av1_check_trailing_bits(pbi, rb) != 0) {
+ // cm->error.error_code is already set.
+ return 0;
+ }
+#endif
+
+ // If a sequence header has been decoded before, we check if the new
+ // one is consistent with the old one.
+ if (pbi->sequence_header_ready) {
+ if (!are_seq_headers_consistent(&cm->seq_params, seq_params))
+ pbi->sequence_header_changed = 1;
+ }
+
+ cm->seq_params = *seq_params;
+ pbi->sequence_header_ready = 1;
+ return 0;
+
+}
+
+int aom_decode_frame_from_obus(AV1Decoder *pbi, union param_u *params, int obu_type)
+{
+ AV1_COMMON *const cm = pbi->common;
+ ObuHeader obu_header;
+ int frame_decoding_finished = 0;
+ uint32_t frame_header_size = 0;
+
+ //struct aom_read_bit_buffer rb;
+ size_t payload_size = 0;
+ size_t decoded_payload_size = 0;
+ size_t obu_payload_offset = 0;
+ //size_t bytes_read = 0;
+
+ memset(&obu_header, 0, sizeof(obu_header));
+#ifdef ORI_CODE
+ pbi->seen_frame_header = 0;
+#else
+ /* set in the test.c*/
+#endif
+
+ obu_header.type = obu_type;
+ pbi->cur_obu_type = obu_header.type;
+ if (av1_is_debug(AOM_DEBUG_PRINT_LIST_INFO))
+ dump_params(pbi, params);
+ switch (obu_header.type) {
+ case OBU_SEQUENCE_HEADER:
+ decoded_payload_size = read_sequence_header_obu(pbi, params);
+ if (cm->error.error_code != AOM_CODEC_OK) return -1;
+ break;
+
+ case OBU_FRAME_HEADER:
+ case OBU_REDUNDANT_FRAME_HEADER:
+ case OBU_FRAME:
+ if (obu_header.type == OBU_REDUNDANT_FRAME_HEADER) {
+ if (!pbi->seen_frame_header) {
+ cm->error.error_code = AOM_CODEC_CORRUPT_FRAME;
+ return -1;
+ }
+ } else {
+ // OBU_FRAME_HEADER or OBU_FRAME.
+ if (pbi->seen_frame_header) {
+ cm->error.error_code = AOM_CODEC_CORRUPT_FRAME;
+ return -1;
+ }
+ }
+ // Only decode first frame header received
+ if (!pbi->seen_frame_header ||
+ (cm->large_scale_tile && !pbi->camera_frame_header_ready)) {
+ frame_header_size = av1_decode_frame_headers_and_setup(
+ pbi, /*&rb, data, p_data_end,*/obu_header.type != OBU_FRAME, params);
+ pbi->seen_frame_header = 1;
+ if (!pbi->ext_tile_debug && cm->large_scale_tile)
+ pbi->camera_frame_header_ready = 1;
+ } else {
+ // TODO(wtc): Verify that the frame_header_obu is identical to the
+ // original frame_header_obu. For now just skip frame_header_size
+ // bytes in the bit buffer.
+ }
+
+ decoded_payload_size = frame_header_size;
+ pbi->frame_header_size = frame_header_size;
+
+ if (cm->show_existing_frame) {
+ if (obu_header.type == OBU_FRAME) {
+ cm->error.error_code = AOM_CODEC_UNSUP_BITSTREAM;
+ return -1;
+ }
+ frame_decoding_finished = 1;
+ pbi->seen_frame_header = 0;
+ break;
+ }
+
+ // In large scale tile coding, decode the common camera frame header
+ // before any tile list OBU.
+ if (!pbi->ext_tile_debug && pbi->camera_frame_header_ready) {
+ frame_decoding_finished = 1;
+ // Skip the rest of the frame data.
+ decoded_payload_size = payload_size;
+ // Update data_end.
+#ifdef ORI_CODE
+ *p_data_end = data_end;
+#endif
+ break;
+ }
+#if 0 //def AML
+ frame_decoding_finished = 1;
+#endif
+ if (obu_header.type != OBU_FRAME) break;
+ obu_payload_offset = frame_header_size;
+ // Byte align the reader before reading the tile group.
+ // byte_alignment() has set cm->error.error_code if it returns -1.
+#ifdef ORI_CODE
+ if (byte_alignment(cm, &rb)) return -1;
+ AOM_FALLTHROUGH_INTENDED; // fall through to read tile group.
+#endif
+ default:
+ break;
+ }
+ return frame_decoding_finished;
+}
+
+int get_buffer_index(AV1Decoder *pbi, RefCntBuffer *buffer)
+{
+ AV1_COMMON *const cm = pbi->common;
+ int i = -1;
+
+ if (buffer) {
+ for (i = 0; i < FRAME_BUFFERS; i++) {
+ RefCntBuffer *buf =
+ &cm->buffer_pool->frame_bufs[i];
+ if (buf == buffer) {
+ break;
+ }
+ }
+ }
+
+ return i;
+}
+
+void dump_buffer(RefCntBuffer *buf)
+{
+ int i;
+ pr_info("ref_count %d, vf_ref %d, order_hint %d, w/h(%d,%d) showable_frame %d frame_type %d canvas(%d,%d) w/h(%d,%d) mi_c/r(%d,%d) header 0x%x ref_deltas(",
+ buf->ref_count, buf->buf.vf_ref, buf->order_hint, buf->width, buf->height, buf->showable_frame, buf->frame_type,
+ buf->buf.mc_canvas_y, buf->buf.mc_canvas_u_v,
+ buf->buf.y_crop_width, buf->buf.y_crop_height,
+ buf->mi_cols, buf->mi_rows,
+ buf->buf.header_adr);
+ for (i = 0; i < REF_FRAMES; i++)
+ pr_info("%d,", buf->ref_deltas[i]);
+ pr_info("), ref_order_hints(");
+
+ for (i = 0; i < INTER_REFS_PER_FRAME; i++)
+ pr_info("%d ", buf->ref_order_hints[i]);
+ pr_info(")");
+}
+
+void dump_ref_buffer_info(AV1Decoder *pbi, int i)
+{
+ AV1_COMMON *const cm = pbi->common;
+ pr_info("remapped_ref_idx %d, ref_frame_sign_bias %d, ref_frame_id %d, valid_for_referencing %d ref_frame_side %d ref_frame_map idx %d, next_ref_frame_map idx %d",
+ cm->remapped_ref_idx[i],
+ cm->ref_frame_sign_bias[i],
+ cm->ref_frame_id[i],
+ cm->valid_for_referencing[i],
+ cm->ref_frame_side[i],
+ get_buffer_index(pbi, cm->ref_frame_map[i]),
+ get_buffer_index(pbi, cm->next_ref_frame_map[i]));
+}
+
+void dump_mv_refs(AV1Decoder *pbi)
+{
+ int i, j;
+ AV1_COMMON *const cm = pbi->common;
+ for (i = 0; i < cm->mv_ref_id_index; i++) {
+ pr_info("%d: ref_id %d cal_tpl_mvs %d mv_ref_offset: ",
+ i, cm->mv_ref_id[i], cm->mv_cal_tpl_mvs[i]);
+ for (j = 0; j < REF_FRAMES; j++)
+ pr_info("%d ", cm->mv_ref_offset[i][j]);
+ pr_info("\n");
+ }
+}
+
+void dump_ref_spec_bufs(AV1Decoder *pbi)
+{
+ int i;
+ AV1_COMMON *const cm = pbi->common;
+ for (i = 0; i < INTER_REFS_PER_FRAME; ++i) {
+ PIC_BUFFER_CONFIG *pic_config = av1_get_ref_frame_spec_buf(cm, LAST_FRAME + i);
+ if (pic_config == NULL) continue;
+ pr_info("%d: index %d order_hint %d header 0x%x dw_header 0x%x canvas(%d,%d) mv_wr_start 0x%x lcu_total %d\n",
+ i, pic_config->index,
+ pic_config->order_hint,
+ pic_config->header_adr,
+#ifdef AOM_AV1_MMU_DW
+ pic_config->header_dw_adr,
+#else
+ 0,
+#endif
+ pic_config->mc_canvas_y,
+ pic_config->mc_canvas_u_v,
+ pic_config->mpred_mv_wr_start_addr,
+ pic_config->lcu_total
+ );
+ }
+}
+
+#ifdef SUPPORT_SCALE_FACTOR
+void dump_scale_factors(AV1Decoder *pbi)
+{
+ int i;
+ AV1_COMMON *const cm = pbi->common;
+ for (i = LAST_FRAME; i <= ALTREF_FRAME; ++i) {
+ struct scale_factors *const sf =
+ get_ref_scale_factors(cm, i);
+ if (sf)
+ pr_info("%d: is_scaled %d x_scale_fp %d, y_scale_fp %d\n",
+ i, av1_is_scaled(sf),
+ sf->x_scale_fp, sf->y_scale_fp);
+ else
+ pr_info("%d: sf null\n", i);
+ }
+}
+
+#endif
+
+void dump_buffer_status(AV1Decoder *pbi)
+{
+ int i;
+ AV1_COMMON *const cm = pbi->common;
+ BufferPool *const pool = cm->buffer_pool;
+ unsigned long flags;
+
+ lock_buffer_pool(pool, flags);
+
+ pr_info("%s: pbi %p cm %p cur_frame %p\n", __func__, pbi, cm, cm->cur_frame);
+
+ pr_info("Buffer Pool:\n");
+ for (i = 0; i < FRAME_BUFFERS; i++) {
+ RefCntBuffer *buf =
+ &cm->buffer_pool->frame_bufs[i];
+ pr_info("%d: ", i);
+ if (buf)
+ dump_buffer(buf);
+ pr_info("\n");
+ }
+
+ if (cm->prev_frame) {
+ pr_info("prev_frame (%d): ",
+ get_buffer_index(pbi, cm->prev_frame));
+ dump_buffer(cm->prev_frame);
+ pr_info("\n");
+ }
+ if (cm->cur_frame) {
+ pr_info("cur_frame (%d): ",
+ get_buffer_index(pbi, cm->cur_frame));
+ dump_buffer(cm->cur_frame);
+ pr_info("\n");
+ }
+ pr_info("REF_FRAMES Info(ref buf is ref_frame_map[remapped_ref_idx[i-1]], i=1~7):\n");
+ for (i = 0; i < REF_FRAMES; i++) {
+ pr_info("%d: ", i);
+ dump_ref_buffer_info(pbi, i);
+ pr_info("\n");
+ }
+ pr_info("Ref Spec Buffers:\n");
+ dump_ref_spec_bufs(pbi);
+
+ pr_info("MV refs:\n");
+ dump_mv_refs(pbi);
+
+#ifdef SUPPORT_SCALE_FACTOR
+ pr_info("Scale factors:\n");
+ dump_scale_factors(pbi);
+#endif
+ unlock_buffer_pool(pool, flags);
+}
+
+
+struct param_dump_item_s {
+ unsigned int size;
+ char* name;
+ unsigned int adr_off;
+} param_dump_items[] = {
+ {1, "profile", (unsigned long)&(((union param_u *)0)->p.profile )},
+ {1, "still_picture", (unsigned long)&(((union param_u *)0)->p.still_picture )},
+ {1, "reduced_still_picture_hdr", (unsigned long)&(((union param_u *)0)->p.reduced_still_picture_hdr )},
+ {1, "decoder_model_info_present_flag", (unsigned long)&(((union param_u *)0)->p.decoder_model_info_present_flag)},
+ {1, "max_frame_width", (unsigned long)&(((union param_u *)0)->p.max_frame_width )},
+ {1, "max_frame_height", (unsigned long)&(((union param_u *)0)->p.max_frame_height )},
+ {1, "frame_id_numbers_present_flag", (unsigned long)&(((union param_u *)0)->p.frame_id_numbers_present_flag )},
+ {1, "delta_frame_id_length", (unsigned long)&(((union param_u *)0)->p.delta_frame_id_length )},
+ {1, "frame_id_length", (unsigned long)&(((union param_u *)0)->p.frame_id_length )},
+ {1, "order_hint_bits_minus_1", (unsigned long)&(((union param_u *)0)->p.order_hint_bits_minus_1 )},
+ {1, "enable_order_hint", (unsigned long)&(((union param_u *)0)->p.enable_order_hint )},
+ {1, "enable_dist_wtd_comp", (unsigned long)&(((union param_u *)0)->p.enable_dist_wtd_comp )},
+ {1, "enable_ref_frame_mvs", (unsigned long)&(((union param_u *)0)->p.enable_ref_frame_mvs )},
+ {1, "enable_superres", (unsigned long)&(((union param_u *)0)->p.enable_superres )},
+ {1, "superres_scale_denominator", (unsigned long)&(((union param_u *)0)->p.superres_scale_denominator )},
+ {1, "show_existing_frame", (unsigned long)&(((union param_u *)0)->p.show_existing_frame )},
+ {1, "frame_type", (unsigned long)&(((union param_u *)0)->p.frame_type )},
+ {1, "show_frame", (unsigned long)&(((union param_u *)0)->p.show_frame )},
+ {1, "e.r.r.o.r_resilient_mode", (unsigned long)&(((union param_u *)0)->p.error_resilient_mode )},
+ {1, "refresh_frame_flags", (unsigned long)&(((union param_u *)0)->p.refresh_frame_flags )},
+ {1, "showable_frame", (unsigned long)&(((union param_u *)0)->p.showable_frame )},
+ {1, "current_frame_id", (unsigned long)&(((union param_u *)0)->p.current_frame_id )},
+ {1, "frame_size_override_flag", (unsigned long)&(((union param_u *)0)->p.frame_size_override_flag )},
+ {1, "order_hint", (unsigned long)&(((union param_u *)0)->p.order_hint )},
+ {1, "primary_ref_frame", (unsigned long)&(((union param_u *)0)->p.primary_ref_frame )},
+ {1, "frame_refs_short_signaling", (unsigned long)&(((union param_u *)0)->p.frame_refs_short_signaling )},
+ {1, "frame_width", (unsigned long)&(((union param_u *)0)->p.frame_width )},
+ {1, "dec_frame_width", (unsigned long)&(((union param_u *)0)->p.dec_frame_width )},
+ {1, "frame_width_scaled", (unsigned long)&(((union param_u *)0)->p.frame_width_scaled )},
+ {1, "frame_height", (unsigned long)&(((union param_u *)0)->p.frame_height )},
+ {1, "reference_mode", (unsigned long)&(((union param_u *)0)->p.reference_mode )},
+ {1, "update_parameters", (unsigned long)&(((union param_u *)0)->p.update_parameters )},
+ {1, "film_grain_params_ref_idx", (unsigned long)&(((union param_u *)0)->p.film_grain_params_ref_idx )},
+ {1, "allow_ref_frame_mvs", (unsigned long)&(((union param_u *)0)->p.allow_ref_frame_mvs )},
+ {1, "lst_ref", (unsigned long)&(((union param_u *)0)->p.lst_ref )},
+ {1, "gld_ref", (unsigned long)&(((union param_u *)0)->p.gld_ref )},
+ {INTER_REFS_PER_FRAME, "remapped_ref_idx", (unsigned long)&(((union param_u *)0)->p.remapped_ref_idx[0] )},
+ {INTER_REFS_PER_FRAME, "delta_frame_id_minus_1", (unsigned long)&(((union param_u *)0)->p.delta_frame_id_minus_1[0] )},
+ {REF_FRAMES, "ref_order_hint", (unsigned long)&(((union param_u *)0)->p.ref_order_hint[0] )},
+};
+
+void dump_params(AV1Decoder *pbi, union param_u *params)
+{
+ int i, j;
+ unsigned char *start_adr = (unsigned char*)params;
+
+ pr_info("============ params:\n");
+ for (i = 0; i < sizeof(param_dump_items) / sizeof(param_dump_items[0]); i++) {
+ for (j = 0; j < param_dump_items[i].size; j++) {
+ if (param_dump_items[i].size > 1)
+ pr_info("%s(%d): 0x%x\n",
+ param_dump_items[i].name, j,
+ *((unsigned short*)(start_adr + param_dump_items[i].adr_off + j * 2)));
+ else
+ pr_info("%s: 0x%x\n", param_dump_items[i].name,
+ *((unsigned short*)(start_adr + param_dump_items[i].adr_off + j * 2)));
+ }
+ }
+}
+
+/*static void raw_write_image(AV1Decoder *pbi, PIC_BUFFER_CONFIG *sd)
+{
+ printf("$$$$$$$ output image\n");
+}*/
+
+/*
+ return 0, need decoding data
+ 1, decoding done
+ -1, decoding error
+
+*/
+int av1_bufmgr_process(AV1Decoder *pbi, union param_u *params,
+ unsigned char new_compressed_data, int obu_type)
+{
+ AV1_COMMON *const cm = pbi->common;
+ int j;
+ // Release any pending output frames from the previous decoder_decode call.
+ // We need to do this even if the decoder is being flushed or the input
+ // arguments are invalid.
+ BufferPool *const pool = cm->buffer_pool;
+ int frame_decoded;
+ av1_print2(AV1_DEBUG_BUFMGR_DETAIL, "%s: pbi %p cm %p cur_frame %p\n", __func__, pbi, cm, cm->cur_frame);
+ av1_print2(AV1_DEBUG_BUFMGR_DETAIL, "%s: new_compressed_data= %d\n", __func__, new_compressed_data);
+ for (j = 0; j < pbi->num_output_frames; j++) {
+ decrease_ref_count(pbi, pbi->output_frames[j], pool);
+ }
+ pbi->num_output_frames = 0;
+ //
+ if (new_compressed_data) {
+ if (assign_cur_frame_new_fb(cm) == NULL) {
+ cm->error.error_code = AOM_CODEC_MEM_ERROR;
+ return -1;
+ }
+ pbi->seen_frame_header = 0;
+ av1_print2(AV1_DEBUG_BUFMGR_DETAIL, "New_compressed_data (%d)\n", new_compressed_data_count++);
+
+ }
+
+ frame_decoded =
+ aom_decode_frame_from_obus(pbi, params, obu_type);
+
+ if (pbi->cur_obu_type == OBU_FRAME_HEADER ||
+ pbi->cur_obu_type == OBU_REDUNDANT_FRAME_HEADER ||
+ pbi->cur_obu_type == OBU_FRAME) {
+ if (av1_is_debug(AOM_DEBUG_PRINT_LIST_INFO)) {
+ pr_info("after bufmgr (frame_decoded %d seen_frame_header %d): ",
+ frame_decoded, pbi->seen_frame_header);
+ dump_buffer_status(pbi);
+ }
+ }
+ av1_print2(AV1_DEBUG_BUFMGR_DETAIL, "%s: pbi %p cm %p cur_frame %p\n", __func__, pbi, cm, cm->cur_frame);
+
+ return frame_decoded;
+
+}
+
+int av1_get_raw_frame(AV1Decoder *pbi, size_t index, PIC_BUFFER_CONFIG **sd) {
+ if (index >= pbi->num_output_frames) return -1;
+ *sd = &pbi->output_frames[index]->buf;
+ //*grain_params = &pbi->output_frames[index]->film_grain_params;
+ //aom_clear_system_state();
+ return 0;
+}
+
+int av1_bufmgr_postproc(AV1Decoder *pbi, unsigned char frame_decoded)
+{
+ PIC_BUFFER_CONFIG *sd = NULL;
+ int index;
+#if 0
+ if (frame_decoded) {
+ printf("before swap_frame_buffers: ");
+ dump_buffer_status(pbi);
+ }
+#endif
+ swap_frame_buffers(pbi, frame_decoded);
+ if (frame_decoded) {
+ if (av1_is_debug(AOM_DEBUG_PRINT_LIST_INFO)) {
+ pr_info("after swap_frame_buffers: ");
+ dump_buffer_status(pbi);
+ }
+ }
+ if (frame_decoded) {
+ pbi->decoding_first_frame = 0;
+ }
+
+
+ for (index = 0;;index++) {
+ if (av1_get_raw_frame(pbi, index, &sd) < 0)
+ break;
+ if (sd)
+ av1_raw_write_image(pbi, sd);
+ }
+ return 0;
+}
+
+int aom_realloc_frame_buffer(AV1_COMMON *cm, PIC_BUFFER_CONFIG *pic,
+ int width, int height, unsigned int order_hint)
+{
+ av1_print2(AV1_DEBUG_BUFMGR_DETAIL, "%s, index 0x%x, width 0x%x, height 0x%x order_hint 0x%x\n",
+ __func__, pic->index, width, height, order_hint);
+ pic->y_crop_width = width;
+ pic->y_crop_height = height;
+ pic->order_hint = order_hint;
+ return 0;
+}
+
+
+unsigned char av1_frame_is_inter(const AV1_COMMON *const cm) {
+ unsigned char is_inter = cm->cur_frame && (cm->cur_frame->frame_type != KEY_FRAME)
+ && (cm->current_frame.frame_type != INTRA_ONLY_FRAME);
+ return is_inter;
+}
+
+PIC_BUFFER_CONFIG *av1_get_ref_frame_spec_buf(
+ const AV1_COMMON *const cm, const MV_REFERENCE_FRAME ref_frame) {
+ RefCntBuffer *buf = get_ref_frame_buf(cm, ref_frame);
+ if (buf) {
+ buf->buf.order_hint = buf->order_hint;
+ return &(buf->buf);
+ }
+ return NULL;
+}
+
+struct scale_factors *av1_get_ref_scale_factors(
+ AV1_COMMON *const cm, const MV_REFERENCE_FRAME ref_frame)
+{
+ return get_ref_scale_factors(cm, ref_frame);
+}
+
+void av1_set_next_ref_frame_map(AV1Decoder *pbi) {
+ int ref_index = 0;
+ int mask;
+ AV1_COMMON *const cm = pbi->common;
+ int check_on_show_existing_frame;
+ av1_print2(AV1_DEBUG_BUFMGR_DETAIL, "%s, %d, mask 0x%x, show_existing_frame %d, reset_decoder_state %d\n",
+ __func__, pbi->camera_frame_header_ready,
+ cm->current_frame.refresh_frame_flags,
+ cm->show_existing_frame,
+ pbi->reset_decoder_state
+ );
+ if (!pbi->camera_frame_header_ready) {
+ for (mask = cm->current_frame.refresh_frame_flags; mask; mask >>= 1) {
+ cm->next_used_ref_frame_map[ref_index] = cm->next_ref_frame_map[ref_index];
+ ++ref_index;
+ }
+
+ check_on_show_existing_frame =
+ !cm->show_existing_frame || pbi->reset_decoder_state;
+ for (; ref_index < REF_FRAMES && check_on_show_existing_frame;
+ ++ref_index) {
+ cm->next_used_ref_frame_map[ref_index] = cm->next_ref_frame_map[ref_index];
+ }
+ }
+}
+
+unsigned int av1_get_next_used_ref_info(
+ const AV1_COMMON *const cm, int i) {
+ /*
+ i = 0~1 orde_hint map
+ i = 2~10 size map[i-2]
+ */
+ unsigned int info = 0;
+ int j;
+ if (i < 2) {
+ /*next_used_ref_frame_map has 8 items*/
+ for (j = 0; j < 4; j++) {
+ RefCntBuffer *buf =
+ cm->next_used_ref_frame_map[(i * 4) + j];
+ if (buf)
+ info |= ((buf->buf.order_hint & 0xff)
+ << (j * 8));
+ }
+ } else if (i < 10) {
+ RefCntBuffer *buf =
+ cm->next_used_ref_frame_map[i-2];
+ if (buf)
+ info = (buf->buf.y_crop_width << 16) | (buf->buf.y_crop_height & 0xffff);
+ } else {
+ for (j = 0; j < 4; j++) {
+ RefCntBuffer *buf =
+ cm->next_used_ref_frame_map[((i - 10) * 4) + j];
+ if (buf)
+ info |= ((buf->buf.index & 0xff)
+ << (j * 8));
+ }
+ }
+ return info;
+}
+
+RefCntBuffer *av1_get_primary_ref_frame_buf(
+ const AV1_COMMON *const cm)
+{
+ return get_primary_ref_frame_buf(cm);
+}
diff --git a/drivers/frame_provider/decoder/vav1/av1_global.h b/drivers/frame_provider/decoder/vav1/av1_global.h
new file mode 100644
index 0000000..75af688
--- /dev/null
+++ b/drivers/frame_provider/decoder/vav1/av1_global.h
@@ -0,0 +1,2335 @@
+/*
+* 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 AV1_GLOBAL_H_
+#define AV1_GLOBAL_H_
+#define AOM_AV1_MMU_DW
+#ifndef HAVE_NEON
+#define HAVE_NEON 0
+#endif
+#ifndef CONFIG_ACCOUNTING
+#define CONFIG_ACCOUNTING 0
+#endif
+#ifndef CONFIG_INSPECTION
+#define CONFIG_INSPECTION 0
+#endif
+#ifndef CONFIG_LPF_MASK
+#define CONFIG_LPF_MASK 0
+#endif
+#ifndef CONFIG_SIZE_LIMIT
+#define CONFIG_SIZE_LIMIT 0
+#endif
+
+#define SUPPORT_SCALE_FACTOR
+#define USE_SCALED_WIDTH_FROM_UCODE
+#define AML
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+#define AML_DEVICE
+#endif
+#ifdef BUFMGR_FOR_SIM
+#define printf io_printf
+#endif
+
+#ifndef INT_MAX
+#define INT_MAX 0x7FFFFFFF
+#endif
+#define AOMMIN(x, y) (((x) < (y)) ? (x) : (y))
+#define AOMMAX(x, y) (((x) > (y)) ? (x) : (y))
+
+//typedef char int8_t;
+//#ifndef BUFMGR_FOR_SIM
+typedef unsigned char uint8_t;
+//#endif
+typedef unsigned int uint32_t;
+//typedef int int32_t;
+//typedef long long int64_t;
+
+#ifdef AML
+#define AOM_AV1_MMU
+#define FILM_GRAIN_REG_SIZE 39
+typedef struct buff_s
+{
+ uint32_t buf_start;
+ uint32_t buf_size;
+ uint32_t buf_end;
+} buff_t;
+
+typedef struct BuffInfo_s
+{
+ uint32_t max_width;
+ uint32_t max_height;
+ uint32_t start_adr;
+ uint32_t end_adr;
+ buff_t ipp;
+ buff_t sao_abv;
+ buff_t sao_vb;
+ buff_t short_term_rps;
+ buff_t vps;
+ buff_t seg_map;
+ buff_t daala_top;
+ buff_t sao_up;
+ buff_t swap_buf;
+ buff_t cdf_buf;
+ buff_t gmc_buf;
+ buff_t scalelut;
+ buff_t dblk_para;
+ buff_t dblk_data;
+ buff_t cdef_data;
+ buff_t ups_data;
+#ifdef AOM_AV1_MMU
+ buff_t mmu_vbh;
+ buff_t cm_header;
+#endif
+#ifdef AOM_AV1_MMU_DW
+ buff_t mmu_vbh_dw;
+ buff_t cm_header_dw;
+#endif
+ buff_t fgs_table;
+ buff_t mpred_above;
+ buff_t mpred_mv;
+ buff_t rpm;
+ buff_t lmem;
+} BuffInfo_t;
+#endif
+
+#define va_start(v,l) __builtin_va_start(v,l)
+#define va_end(v) __builtin_va_end(v)
+#define va_arg(v,l) __builtin_va_arg(v,l)
+/*
+mem.h
+*/
+#if (defined(__GNUC__) && __GNUC__) || defined(__SUNPRO_C)
+#define DECLARE_ALIGNED(n, typ, val) typ val __attribute__((aligned(n)))
+#elif defined(_MSC_VER)
+#define DECLARE_ALIGNED(n, typ, val) __declspec(align(n)) typ val
+#else
+#warning No alignment directives known for this compiler.
+#define DECLARE_ALIGNED(n, typ, val) typ val
+#endif
+
+/* Indicates that the usage of the specified variable has been audited to assure
+ * that it's safe to use uninitialized. Silences 'may be used uninitialized'
+ * warnings on gcc.
+ */
+#if defined(__GNUC__) && __GNUC__
+#define UNINITIALIZED_IS_SAFE(x) x = x
+#else
+#define UNINITIALIZED_IS_SAFE(x) x
+#endif
+
+#if HAVE_NEON && defined(_MSC_VER)
+#define __builtin_prefetch(x)
+#endif
+
+/* Shift down with rounding for use when n >= 0, value >= 0 */
+#define ROUND_POWER_OF_TWO(value, n) (((value) + (((1 << (n)) >> 1))) >> (n))
+
+/* Shift down with rounding for signed integers, for use when n >= 0 */
+#define ROUND_POWER_OF_TWO_SIGNED(value, n) \
+ (((value) < 0) ? -ROUND_POWER_OF_TWO(-(value), (n)) \
+ : ROUND_POWER_OF_TWO((value), (n)))
+
+/* Shift down with rounding for use when n >= 0, value >= 0 for (64 bit) */
+#define ROUND_POWER_OF_TWO_64(value, n) \
+ (((value) + ((((int64_t)1 << (n)) >> 1))) >> (n))
+/* Shift down with rounding for signed integers, for use when n >= 0 (64 bit) */
+#define ROUND_POWER_OF_TWO_SIGNED_64(value, n) \
+ (((value) < 0) ? -ROUND_POWER_OF_TWO_64(-(value), (n)) \
+ : ROUND_POWER_OF_TWO_64((value), (n)))
+
+/* shift right or left depending on sign of n */
+#define RIGHT_SIGNED_SHIFT(value, n) \
+ ((n) < 0 ? ((value) << (-(n))) : ((value) >> (n)))
+
+#define ALIGN_POWER_OF_TWO(value, n) \
+ (((value) + ((1 << (n)) - 1)) & ~((1 << (n)) - 1))
+
+#define DIVIDE_AND_ROUND(x, y) (((x) + ((y) >> 1)) / (y))
+
+#define CONVERT_TO_SHORTPTR(x) ((uint16_t *)(((uintptr_t)(x)) << 1))
+#define CONVERT_TO_BYTEPTR(x) ((uint8_t *)(((uintptr_t)(x)) >> 1))
+
+#ifdef AML
+#define TYPEDEF typedef
+#define UENUM1BYTE(enumvar) enumvar
+#define SENUM1BYTE(enumvar) enumvar
+#define UENUM2BYTE(enumvar) enumvar
+#define SENUM2BYTE(enumvar) enumvar
+#define UENUM4BYTE(enumvar) enumvar
+#define SENUM4BYTE(enumvar) enumvar
+
+#else
+#define TYPEDEF
+/*!\brief force enum to be unsigned 1 byte*/
+#define UENUM1BYTE(enumvar) \
+ ; \
+ typedef uint8_t enumvar
+
+/*!\brief force enum to be signed 1 byte*/
+#define SENUM1BYTE(enumvar) \
+ ; \
+ typedef int8_t enumvar
+
+/*!\brief force enum to be unsigned 2 byte*/
+#define UENUM2BYTE(enumvar) \
+ ; \
+ typedef uint16_t enumvar
+
+/*!\brief force enum to be signed 2 byte*/
+#define SENUM2BYTE(enumvar) \
+ ; \
+ typedef int16_t enumvar
+
+/*!\brief force enum to be unsigned 4 byte*/
+#define UENUM4BYTE(enumvar) \
+ ; \
+ typedef uint32_t enumvar
+
+/*!\brief force enum to be unsigned 4 byte*/
+#define SENUM4BYTE(enumvar) \
+ ; \
+ typedef int32_t enumvar
+#endif
+
+
+/*
+#include "enums.h"
+*/
+#undef MAX_SB_SIZE
+
+// Max superblock size
+#define MAX_SB_SIZE_LOG2 7
+#define MAX_SB_SIZE (1 << MAX_SB_SIZE_LOG2)
+#define MAX_SB_SQUARE (MAX_SB_SIZE * MAX_SB_SIZE)
+
+// Min superblock size
+#define MIN_SB_SIZE_LOG2 6
+
+// Pixels per Mode Info (MI) unit
+#define MI_SIZE_LOG2 2
+#define MI_SIZE (1 << MI_SIZE_LOG2)
+
+// MI-units per max superblock (MI Block - MIB)
+#define MAX_MIB_SIZE_LOG2 (MAX_SB_SIZE_LOG2 - MI_SIZE_LOG2)
+#define MAX_MIB_SIZE (1 << MAX_MIB_SIZE_LOG2)
+
+// MI-units per min superblock
+#define MIN_MIB_SIZE_LOG2 (MIN_SB_SIZE_LOG2 - MI_SIZE_LOG2)
+
+// Mask to extract MI offset within max MIB
+#define MAX_MIB_MASK (MAX_MIB_SIZE - 1)
+
+// Maximum number of tile rows and tile columns
+#define MAX_TILE_ROWS 64
+#define MAX_TILE_COLS 64
+
+#define MAX_VARTX_DEPTH 2
+
+#define MI_SIZE_64X64 (64 >> MI_SIZE_LOG2)
+#define MI_SIZE_128X128 (128 >> MI_SIZE_LOG2)
+
+#define MAX_PALETTE_SQUARE (64 * 64)
+// Maximum number of colors in a palette.
+#define PALETTE_MAX_SIZE 8
+// Minimum number of colors in a palette.
+#define PALETTE_MIN_SIZE 2
+
+#define FRAME_OFFSET_BITS 5
+#define MAX_FRAME_DISTANCE ((1 << FRAME_OFFSET_BITS) - 1)
+
+// 4 frame filter levels: y plane vertical, y plane horizontal,
+// u plane, and v plane
+#define FRAME_LF_COUNT 4
+#define DEFAULT_DELTA_LF_MULTI 0
+#define MAX_MODE_LF_DELTAS 2
+
+#define DIST_PRECISION_BITS 4
+#define DIST_PRECISION (1 << DIST_PRECISION_BITS) // 16
+
+#define PROFILE_BITS 3
+// The following three profiles are currently defined.
+// Profile 0. 8-bit and 10-bit 4:2:0 and 4:0:0 only.
+// Profile 1. 8-bit and 10-bit 4:4:4
+// Profile 2. 8-bit and 10-bit 4:2:2
+// 12-bit 4:0:0, 4:2:2 and 4:4:4
+// Since we have three bits for the profiles, it can be extended later.
+TYPEDEF enum {
+ PROFILE_0,
+ PROFILE_1,
+ PROFILE_2,
+ MAX_PROFILES,
+} SENUM1BYTE(BITSTREAM_PROFILE);
+
+#define OP_POINTS_CNT_MINUS_1_BITS 5
+#define OP_POINTS_IDC_BITS 12
+
+// Note: Some enums use the attribute 'packed' to use smallest possible integer
+// type, so that we can save memory when they are used in structs/arrays.
+
+typedef enum ATTRIBUTE_PACKED {
+ BLOCK_4X4,
+ BLOCK_4X8,
+ BLOCK_8X4,
+ BLOCK_8X8,
+ BLOCK_8X16,
+ BLOCK_16X8,
+ BLOCK_16X16,
+ BLOCK_16X32,
+ BLOCK_32X16,
+ BLOCK_32X32,
+ BLOCK_32X64,
+ BLOCK_64X32,
+ BLOCK_64X64,
+ BLOCK_64X128,
+ BLOCK_128X64,
+ BLOCK_128X128,
+ BLOCK_4X16,
+ BLOCK_16X4,
+ BLOCK_8X32,
+ BLOCK_32X8,
+ BLOCK_16X64,
+ BLOCK_64X16,
+ BLOCK_SIZES_ALL,
+ BLOCK_SIZES = BLOCK_4X16,
+ BLOCK_INVALID = 255,
+ BLOCK_LARGEST = (BLOCK_SIZES - 1)
+} BLOCK_SIZE2;
+
+// 4X4, 8X8, 16X16, 32X32, 64X64, 128X128
+#define SQR_BLOCK_SIZES 6
+
+TYPEDEF enum {
+ PARTITION_NONE,
+ PARTITION_HORZ,
+ PARTITION_VERT,
+ PARTITION_SPLIT,
+ PARTITION_HORZ_A, // HORZ split and the top partition is split again
+ PARTITION_HORZ_B, // HORZ split and the bottom partition is split again
+ PARTITION_VERT_A, // VERT split and the left partition is split again
+ PARTITION_VERT_B, // VERT split and the right partition is split again
+ PARTITION_HORZ_4, // 4:1 horizontal partition
+ PARTITION_VERT_4, // 4:1 vertical partition
+ EXT_PARTITION_TYPES,
+ PARTITION_TYPES = PARTITION_SPLIT + 1,
+ PARTITION_INVALID = 255
+} UENUM1BYTE(PARTITION_TYPE);
+
+typedef char PARTITION_CONTEXT;
+#define PARTITION_PLOFFSET 4 // number of probability models per block size
+#define PARTITION_BLOCK_SIZES 5
+#define PARTITION_CONTEXTS (PARTITION_BLOCK_SIZES * PARTITION_PLOFFSET)
+
+// block transform size
+TYPEDEF enum {
+ TX_4X4, // 4x4 transform
+ TX_8X8, // 8x8 transform
+ TX_16X16, // 16x16 transform
+ TX_32X32, // 32x32 transform
+ TX_64X64, // 64x64 transform
+ TX_4X8, // 4x8 transform
+ TX_8X4, // 8x4 transform
+ TX_8X16, // 8x16 transform
+ TX_16X8, // 16x8 transform
+ TX_16X32, // 16x32 transform
+ TX_32X16, // 32x16 transform
+ TX_32X64, // 32x64 transform
+ TX_64X32, // 64x32 transform
+ TX_4X16, // 4x16 transform
+ TX_16X4, // 16x4 transform
+ TX_8X32, // 8x32 transform
+ TX_32X8, // 32x8 transform
+ TX_16X64, // 16x64 transform
+ TX_64X16, // 64x16 transform
+ TX_SIZES_ALL, // Includes rectangular transforms
+ TX_SIZES = TX_4X8, // Does NOT include rectangular transforms
+ TX_SIZES_LARGEST = TX_64X64,
+ TX_INVALID = 255 // Invalid transform size
+} UENUM1BYTE(TX_SIZE);
+
+#define TX_SIZE_LUMA_MIN (TX_4X4)
+/* We don't need to code a transform size unless the allowed size is at least
+ one more than the minimum. */
+#define TX_SIZE_CTX_MIN (TX_SIZE_LUMA_MIN + 1)
+
+// Maximum tx_size categories
+#define MAX_TX_CATS (TX_SIZES - TX_SIZE_CTX_MIN)
+#define MAX_TX_DEPTH 2
+
+#define MAX_TX_SIZE_LOG2 (6)
+#define MAX_TX_SIZE (1 << MAX_TX_SIZE_LOG2)
+#define MIN_TX_SIZE_LOG2 2
+#define MIN_TX_SIZE (1 << MIN_TX_SIZE_LOG2)
+#define MAX_TX_SQUARE (MAX_TX_SIZE * MAX_TX_SIZE)
+
+// Pad 4 extra columns to remove horizontal availability check.
+#define TX_PAD_HOR_LOG2 2
+#define TX_PAD_HOR 4
+// Pad 6 extra rows (2 on top and 4 on bottom) to remove vertical availability
+// check.
+#define TX_PAD_TOP 0
+#define TX_PAD_BOTTOM 4
+#define TX_PAD_VER (TX_PAD_TOP + TX_PAD_BOTTOM)
+// Pad 16 extra bytes to avoid reading overflow in SIMD optimization.
+#define TX_PAD_END 16
+#define TX_PAD_2D ((32 + TX_PAD_HOR) * (32 + TX_PAD_VER) + TX_PAD_END)
+
+// Number of maxium size transform blocks in the maximum size superblock
+#define MAX_TX_BLOCKS_IN_MAX_SB_LOG2 ((MAX_SB_SIZE_LOG2 - MAX_TX_SIZE_LOG2) * 2)
+#define MAX_TX_BLOCKS_IN_MAX_SB (1 << MAX_TX_BLOCKS_IN_MAX_SB_LOG2)
+
+// frame transform mode
+TYPEDEF enum {
+ ONLY_4X4, // use only 4x4 transform
+ TX_MODE_LARGEST, // transform size is the largest possible for pu size
+ TX_MODE_SELECT, // transform specified for each block
+ TX_MODES,
+} UENUM1BYTE(TX_MODE);
+
+// 1D tx types
+TYPEDEF enum {
+ DCT_1D,
+ ADST_1D,
+ FLIPADST_1D,
+ IDTX_1D,
+ TX_TYPES_1D,
+} UENUM1BYTE(TX_TYPE_1D);
+
+TYPEDEF enum {
+ DCT_DCT, // DCT in both horizontal and vertical
+ ADST_DCT, // ADST in vertical, DCT in horizontal
+ DCT_ADST, // DCT in vertical, ADST in horizontal
+ ADST_ADST, // ADST in both directions
+ FLIPADST_DCT, // FLIPADST in vertical, DCT in horizontal
+ DCT_FLIPADST, // DCT in vertical, FLIPADST in horizontal
+ FLIPADST_FLIPADST, // FLIPADST in both directions
+ ADST_FLIPADST, // ADST in vertical, FLIPADST in horizontal
+ FLIPADST_ADST, // FLIPADST in vertical, ADST in horizontal
+ IDTX, // Identity in both directions
+ V_DCT, // DCT in vertical, identity in horizontal
+ H_DCT, // Identity in vertical, DCT in horizontal
+ V_ADST, // ADST in vertical, identity in horizontal
+ H_ADST, // Identity in vertical, ADST in horizontal
+ V_FLIPADST, // FLIPADST in vertical, identity in horizontal
+ H_FLIPADST, // Identity in vertical, FLIPADST in horizontal
+ TX_TYPES,
+} UENUM1BYTE(TX_TYPE);
+
+TYPEDEF enum {
+ REG_REG,
+ REG_SMOOTH,
+ REG_SHARP,
+ SMOOTH_REG,
+ SMOOTH_SMOOTH,
+ SMOOTH_SHARP,
+ SHARP_REG,
+ SHARP_SMOOTH,
+ SHARP_SHARP,
+} UENUM1BYTE(DUAL_FILTER_TYPE);
+
+TYPEDEF enum {
+ // DCT only
+ EXT_TX_SET_DCTONLY,
+ // DCT + Identity only
+ EXT_TX_SET_DCT_IDTX,
+ // Discrete Trig transforms w/o flip (4) + Identity (1)
+ EXT_TX_SET_DTT4_IDTX,
+ // Discrete Trig transforms w/o flip (4) + Identity (1) + 1D Hor/vert DCT (2)
+ EXT_TX_SET_DTT4_IDTX_1DDCT,
+ // Discrete Trig transforms w/ flip (9) + Identity (1) + 1D Hor/Ver DCT (2)
+ EXT_TX_SET_DTT9_IDTX_1DDCT,
+ // Discrete Trig transforms w/ flip (9) + Identity (1) + 1D Hor/Ver (6)
+ EXT_TX_SET_ALL16,
+ EXT_TX_SET_TYPES
+} UENUM1BYTE(TxSetType);
+
+#define IS_2D_TRANSFORM(tx_type) (tx_type < IDTX)
+
+#define EXT_TX_SIZES 4 // number of sizes that use extended transforms
+#define EXT_TX_SETS_INTER 4 // Sets of transform selections for INTER
+#define EXT_TX_SETS_INTRA 3 // Sets of transform selections for INTRA
+
+TYPEDEF enum {
+ AOM_LAST_FLAG = 1 << 0,
+ AOM_LAST2_FLAG = 1 << 1,
+ AOM_LAST3_FLAG = 1 << 2,
+ AOM_GOLD_FLAG = 1 << 3,
+ AOM_BWD_FLAG = 1 << 4,
+ AOM_ALT2_FLAG = 1 << 5,
+ AOM_ALT_FLAG = 1 << 6,
+ AOM_REFFRAME_ALL = (1 << 7) - 1
+} UENUM1BYTE(AOM_REFFRAME);
+
+TYPEDEF enum {
+ UNIDIR_COMP_REFERENCE,
+ BIDIR_COMP_REFERENCE,
+ COMP_REFERENCE_TYPES,
+} UENUM1BYTE(COMP_REFERENCE_TYPE);
+
+/*enum { PLANE_TYPE_Y, PLANE_TYPE_UV, PLANE_TYPES } UENUM1BYTE(PLANE_TYPE);*/
+
+#define CFL_ALPHABET_SIZE_LOG2 4
+#define CFL_ALPHABET_SIZE (1 << CFL_ALPHABET_SIZE_LOG2)
+#define CFL_MAGS_SIZE ((2 << CFL_ALPHABET_SIZE_LOG2) + 1)
+#define CFL_IDX_U(idx) (idx >> CFL_ALPHABET_SIZE_LOG2)
+#define CFL_IDX_V(idx) (idx & (CFL_ALPHABET_SIZE - 1))
+
+/*enum { CFL_PRED_U, CFL_PRED_V, CFL_PRED_PLANES } UENUM1BYTE(CFL_PRED_TYPE);*/
+
+TYPEDEF enum {
+ CFL_SIGN_ZERO,
+ CFL_SIGN_NEG,
+ CFL_SIGN_POS,
+ CFL_SIGNS
+} UENUM1BYTE(CFL_SIGN_TYPE);
+
+TYPEDEF enum {
+ CFL_DISALLOWED,
+ CFL_ALLOWED,
+ CFL_ALLOWED_TYPES
+} UENUM1BYTE(CFL_ALLOWED_TYPE);
+
+// CFL_SIGN_ZERO,CFL_SIGN_ZERO is invalid
+#define CFL_JOINT_SIGNS (CFL_SIGNS * CFL_SIGNS - 1)
+// CFL_SIGN_U is equivalent to (js + 1) / 3 for js in 0 to 8
+#define CFL_SIGN_U(js) (((js + 1) * 11) >> 5)
+// CFL_SIGN_V is equivalent to (js + 1) % 3 for js in 0 to 8
+#define CFL_SIGN_V(js) ((js + 1) - CFL_SIGNS * CFL_SIGN_U(js))
+
+// There is no context when the alpha for a given plane is zero.
+// So there are 2 fewer contexts than joint signs.
+#define CFL_ALPHA_CONTEXTS (CFL_JOINT_SIGNS + 1 - CFL_SIGNS)
+#define CFL_CONTEXT_U(js) (js + 1 - CFL_SIGNS)
+// Also, the contexts are symmetric under swapping the planes.
+#define CFL_CONTEXT_V(js) \
+ (CFL_SIGN_V(js) * CFL_SIGNS + CFL_SIGN_U(js) - CFL_SIGNS)
+
+TYPEDEF enum {
+ PALETTE_MAP,
+ COLOR_MAP_TYPES,
+} UENUM1BYTE(COLOR_MAP_TYPE);
+
+TYPEDEF enum {
+ TWO_COLORS,
+ THREE_COLORS,
+ FOUR_COLORS,
+ FIVE_COLORS,
+ SIX_COLORS,
+ SEVEN_COLORS,
+ EIGHT_COLORS,
+ PALETTE_SIZES
+} UENUM1BYTE(PALETTE_SIZE);
+
+TYPEDEF enum {
+ PALETTE_COLOR_ONE,
+ PALETTE_COLOR_TWO,
+ PALETTE_COLOR_THREE,
+ PALETTE_COLOR_FOUR,
+ PALETTE_COLOR_FIVE,
+ PALETTE_COLOR_SIX,
+ PALETTE_COLOR_SEVEN,
+ PALETTE_COLOR_EIGHT,
+ PALETTE_COLORS
+} UENUM1BYTE(PALETTE_COLOR);
+
+// Note: All directional predictors must be between V_PRED and D67_PRED (both
+// inclusive).
+TYPEDEF enum {
+ DC_PRED, // Average of above and left pixels
+ V_PRED, // Vertical
+ H_PRED, // Horizontal
+ D45_PRED, // Directional 45 degree
+ D135_PRED, // Directional 135 degree
+ D113_PRED, // Directional 113 degree
+ D157_PRED, // Directional 157 degree
+ D203_PRED, // Directional 203 degree
+ D67_PRED, // Directional 67 degree
+ SMOOTH_PRED, // Combination of horizontal and vertical interpolation
+ SMOOTH_V_PRED, // Vertical interpolation
+ SMOOTH_H_PRED, // Horizontal interpolation
+ PAETH_PRED, // Predict from the direction of smallest gradient
+ NEARESTMV,
+ NEARMV,
+ GLOBALMV,
+ NEWMV,
+ // Compound ref compound modes
+ NEAREST_NEARESTMV,
+ NEAR_NEARMV,
+ NEAREST_NEWMV,
+ NEW_NEARESTMV,
+ NEAR_NEWMV,
+ NEW_NEARMV,
+ GLOBAL_GLOBALMV,
+ NEW_NEWMV,
+ MB_MODE_COUNT,
+ INTRA_MODE_START = DC_PRED,
+ INTRA_MODE_END = NEARESTMV,
+ INTRA_MODE_NUM = INTRA_MODE_END - INTRA_MODE_START,
+ SINGLE_INTER_MODE_START = NEARESTMV,
+ SINGLE_INTER_MODE_END = NEAREST_NEARESTMV,
+ SINGLE_INTER_MODE_NUM = SINGLE_INTER_MODE_END - SINGLE_INTER_MODE_START,
+ COMP_INTER_MODE_START = NEAREST_NEARESTMV,
+ COMP_INTER_MODE_END = MB_MODE_COUNT,
+ COMP_INTER_MODE_NUM = COMP_INTER_MODE_END - COMP_INTER_MODE_START,
+ INTER_MODE_START = NEARESTMV,
+ INTER_MODE_END = MB_MODE_COUNT,
+ INTRA_MODES = PAETH_PRED + 1, // PAETH_PRED has to be the last intra mode.
+ INTRA_INVALID = MB_MODE_COUNT // For uv_mode in inter blocks
+} UENUM1BYTE(PREDICTION_MODE);
+
+// TODO(ltrudeau) Do we really want to pack this?
+// TODO(ltrudeau) Do we match with PREDICTION_MODE?
+TYPEDEF enum {
+ UV_DC_PRED, // Average of above and left pixels
+ UV_V_PRED, // Vertical
+ UV_H_PRED, // Horizontal
+ UV_D45_PRED, // Directional 45 degree
+ UV_D135_PRED, // Directional 135 degree
+ UV_D113_PRED, // Directional 113 degree
+ UV_D157_PRED, // Directional 157 degree
+ UV_D203_PRED, // Directional 203 degree
+ UV_D67_PRED, // Directional 67 degree
+ UV_SMOOTH_PRED, // Combination of horizontal and vertical interpolation
+ UV_SMOOTH_V_PRED, // Vertical interpolation
+ UV_SMOOTH_H_PRED, // Horizontal interpolation
+ UV_PAETH_PRED, // Predict from the direction of smallest gradient
+ UV_CFL_PRED, // Chroma-from-Luma
+ UV_INTRA_MODES,
+ UV_MODE_INVALID, // For uv_mode in inter blocks
+} UENUM1BYTE(UV_PREDICTION_MODE);
+
+TYPEDEF enum {
+ SIMPLE_TRANSLATION,
+ OBMC_CAUSAL, // 2-sided OBMC
+ WARPED_CAUSAL, // 2-sided WARPED
+ MOTION_MODES
+} UENUM1BYTE(MOTION_MODE);
+
+TYPEDEF enum {
+ II_DC_PRED,
+ II_V_PRED,
+ II_H_PRED,
+ II_SMOOTH_PRED,
+ INTERINTRA_MODES
+} UENUM1BYTE(INTERINTRA_MODE);
+
+TYPEDEF enum {
+ COMPOUND_AVERAGE,
+ COMPOUND_DISTWTD,
+ COMPOUND_WEDGE,
+ COMPOUND_DIFFWTD,
+ COMPOUND_TYPES,
+ MASKED_COMPOUND_TYPES = 2,
+} UENUM1BYTE(COMPOUND_TYPE);
+
+TYPEDEF enum {
+ FILTER_DC_PRED,
+ FILTER_V_PRED,
+ FILTER_H_PRED,
+ FILTER_D157_PRED,
+ FILTER_PAETH_PRED,
+ FILTER_INTRA_MODES,
+} UENUM1BYTE(FILTER_INTRA_MODE);
+
+TYPEDEF enum {
+ SEQ_LEVEL_2_0,
+ SEQ_LEVEL_2_1,
+ SEQ_LEVEL_2_2,
+ SEQ_LEVEL_2_3,
+ SEQ_LEVEL_3_0,
+ SEQ_LEVEL_3_1,
+ SEQ_LEVEL_3_2,
+ SEQ_LEVEL_3_3,
+ SEQ_LEVEL_4_0,
+ SEQ_LEVEL_4_1,
+ SEQ_LEVEL_4_2,
+ SEQ_LEVEL_4_3,
+ SEQ_LEVEL_5_0,
+ SEQ_LEVEL_5_1,
+ SEQ_LEVEL_5_2,
+ SEQ_LEVEL_5_3,
+ SEQ_LEVEL_6_0,
+ SEQ_LEVEL_6_1,
+ SEQ_LEVEL_6_2,
+ SEQ_LEVEL_6_3,
+ SEQ_LEVEL_7_0,
+ SEQ_LEVEL_7_1,
+ SEQ_LEVEL_7_2,
+ SEQ_LEVEL_7_3,
+ SEQ_LEVELS,
+ SEQ_LEVEL_MAX = 31
+} UENUM1BYTE(AV1_LEVEL);
+
+#define LEVEL_BITS 5
+
+#define DIRECTIONAL_MODES 8
+#define MAX_ANGLE_DELTA 3
+#define ANGLE_STEP 3
+
+#define INTER_MODES (1 + NEWMV - NEARESTMV)
+
+#define INTER_COMPOUND_MODES (1 + NEW_NEWMV - NEAREST_NEARESTMV)
+
+#define SKIP_CONTEXTS 3
+#define SKIP_MODE_CONTEXTS 3
+
+#define COMP_INDEX_CONTEXTS 6
+#define COMP_GROUP_IDX_CONTEXTS 6
+
+#define NMV_CONTEXTS 3
+
+#define NEWMV_MODE_CONTEXTS 6
+#define GLOBALMV_MODE_CONTEXTS 2
+#define REFMV_MODE_CONTEXTS 6
+#define DRL_MODE_CONTEXTS 3
+
+#define GLOBALMV_OFFSET 3
+#define REFMV_OFFSET 4
+
+#define NEWMV_CTX_MASK ((1 << GLOBALMV_OFFSET) - 1)
+#define GLOBALMV_CTX_MASK ((1 << (REFMV_OFFSET - GLOBALMV_OFFSET)) - 1)
+#define REFMV_CTX_MASK ((1 << (8 - REFMV_OFFSET)) - 1)
+
+#define COMP_NEWMV_CTXS 5
+#define INTER_MODE_CONTEXTS 8
+
+#define DELTA_Q_SMALL 3
+#define DELTA_Q_PROBS (DELTA_Q_SMALL)
+#define DEFAULT_DELTA_Q_RES_PERCEPTUAL 4
+#define DEFAULT_DELTA_Q_RES_OBJECTIVE 4
+
+#define DELTA_LF_SMALL 3
+#define DELTA_LF_PROBS (DELTA_LF_SMALL)
+#define DEFAULT_DELTA_LF_RES 2
+
+/* Segment Feature Masks */
+#define MAX_MV_REF_CANDIDATES 2
+
+#define MAX_REF_MV_STACK_SIZE 8
+#define REF_CAT_LEVEL 640
+
+#define INTRA_INTER_CONTEXTS 4
+#define COMP_INTER_CONTEXTS 5
+#define REF_CONTEXTS 3
+
+#define COMP_REF_TYPE_CONTEXTS 5
+#define UNI_COMP_REF_CONTEXTS 3
+
+#define TXFM_PARTITION_CONTEXTS ((TX_SIZES - TX_8X8) * 6 - 3)
+#ifdef ORI_CODE
+typedef uint8_t TXFM_CONTEXT;
+#endif
+// An enum for single reference types (and some derived values).
+enum {
+ NONE_FRAME = -1,
+ INTRA_FRAME,
+ LAST_FRAME,
+ LAST2_FRAME,
+ LAST3_FRAME,
+ GOLDEN_FRAME,
+ BWDREF_FRAME,
+ ALTREF2_FRAME,
+ ALTREF_FRAME,
+ REF_FRAMES,
+
+ // Extra/scratch reference frame. It may be:
+ // - used to update the ALTREF2_FRAME ref (see lshift_bwd_ref_frames()), or
+ // - updated from ALTREF2_FRAME ref (see rshift_bwd_ref_frames()).
+ EXTREF_FRAME = REF_FRAMES,
+
+ // Number of inter (non-intra) reference types.
+ INTER_REFS_PER_FRAME = ALTREF_FRAME - LAST_FRAME + 1,
+
+ // Number of forward (aka past) reference types.
+ FWD_REFS = GOLDEN_FRAME - LAST_FRAME + 1,
+
+ // Number of backward (aka future) reference types.
+ BWD_REFS = ALTREF_FRAME - BWDREF_FRAME + 1,
+
+ SINGLE_REFS = FWD_REFS + BWD_REFS,
+};
+
+#define REF_FRAMES_LOG2 3
+
+// REF_FRAMES for the cm->ref_frame_map array, 1 scratch frame for the new
+// frame in cm->cur_frame, INTER_REFS_PER_FRAME for scaled references on the
+// encoder in the cpi->scaled_ref_buf array.
+#define FRAME_BUFFERS (REF_FRAMES + 1 + INTER_REFS_PER_FRAME)
+
+#define FWD_RF_OFFSET(ref) (ref - LAST_FRAME)
+#define BWD_RF_OFFSET(ref) (ref - BWDREF_FRAME)
+
+TYPEDEF enum {
+ LAST_LAST2_FRAMES, // { LAST_FRAME, LAST2_FRAME }
+ LAST_LAST3_FRAMES, // { LAST_FRAME, LAST3_FRAME }
+ LAST_GOLDEN_FRAMES, // { LAST_FRAME, GOLDEN_FRAME }
+ BWDREF_ALTREF_FRAMES, // { BWDREF_FRAME, ALTREF_FRAME }
+ LAST2_LAST3_FRAMES, // { LAST2_FRAME, LAST3_FRAME }
+ LAST2_GOLDEN_FRAMES, // { LAST2_FRAME, GOLDEN_FRAME }
+ LAST3_GOLDEN_FRAMES, // { LAST3_FRAME, GOLDEN_FRAME }
+ BWDREF_ALTREF2_FRAMES, // { BWDREF_FRAME, ALTREF2_FRAME }
+ ALTREF2_ALTREF_FRAMES, // { ALTREF2_FRAME, ALTREF_FRAME }
+ TOTAL_UNIDIR_COMP_REFS,
+ // NOTE: UNIDIR_COMP_REFS is the number of uni-directional reference pairs
+ // that are explicitly signaled.
+ UNIDIR_COMP_REFS = BWDREF_ALTREF_FRAMES + 1,
+} UENUM1BYTE(UNIDIR_COMP_REF);
+
+#define TOTAL_COMP_REFS (FWD_REFS * BWD_REFS + TOTAL_UNIDIR_COMP_REFS)
+
+#define COMP_REFS (FWD_REFS * BWD_REFS + UNIDIR_COMP_REFS)
+
+// NOTE: A limited number of unidirectional reference pairs can be signalled for
+// compound prediction. The use of skip mode, on the other hand, makes it
+// possible to have a reference pair not listed for explicit signaling.
+#define MODE_CTX_REF_FRAMES (REF_FRAMES + TOTAL_COMP_REFS)
+
+// Note: It includes single and compound references. So, it can take values from
+// NONE_FRAME to (MODE_CTX_REF_FRAMES - 1). Hence, it is not defined as an enum.
+typedef int8_t MV_REFERENCE_FRAME;
+
+TYPEDEF enum {
+ RESTORE_NONE,
+ RESTORE_WIENER,
+ RESTORE_SGRPROJ,
+ RESTORE_SWITCHABLE,
+ RESTORE_SWITCHABLE_TYPES = RESTORE_SWITCHABLE,
+ RESTORE_TYPES = 4,
+} UENUM1BYTE(RestorationType);
+
+// Picture prediction structures (0-12 are predefined) in scalability metadata.
+TYPEDEF enum {
+ SCALABILITY_L1T2 = 0,
+ SCALABILITY_L1T3 = 1,
+ SCALABILITY_L2T1 = 2,
+ SCALABILITY_L2T2 = 3,
+ SCALABILITY_L2T3 = 4,
+ SCALABILITY_S2T1 = 5,
+ SCALABILITY_S2T2 = 6,
+ SCALABILITY_S2T3 = 7,
+ SCALABILITY_L2T1h = 8,
+ SCALABILITY_L2T2h = 9,
+ SCALABILITY_L2T3h = 10,
+ SCALABILITY_S2T1h = 11,
+ SCALABILITY_S2T2h = 12,
+ SCALABILITY_S2T3h = 13,
+ SCALABILITY_SS = 14
+} UENUM1BYTE(SCALABILITY_STRUCTURES);
+
+#define SUPERRES_SCALE_BITS 3
+#define SUPERRES_SCALE_DENOMINATOR_MIN (SCALE_NUMERATOR + 1)
+
+// In large_scale_tile coding, external references are used.
+#define MAX_EXTERNAL_REFERENCES 128
+#define MAX_TILES 512
+
+
+#define CONFIG_MULTITHREAD 0
+#define CONFIG_ENTROPY_STATS 0
+
+#define CONFIG_MAX_DECODE_PROFILE 2
+
+/*
+from:
+seg_common.h
+*/
+#ifdef ORI_CODE
+
+#define MAX_SEGMENTS 8
+#define SEG_TREE_PROBS (MAX_SEGMENTS - 1)
+
+#define SEG_TEMPORAL_PRED_CTXS 3
+#define SPATIAL_PREDICTION_PROBS 3
+
+enum {
+ SEG_LVL_ALT_Q, // Use alternate Quantizer ....
+ SEG_LVL_ALT_LF_Y_V, // Use alternate loop filter value on y plane vertical
+ SEG_LVL_ALT_LF_Y_H, // Use alternate loop filter value on y plane horizontal
+ SEG_LVL_ALT_LF_U, // Use alternate loop filter value on u plane
+ SEG_LVL_ALT_LF_V, // Use alternate loop filter value on v plane
+ SEG_LVL_REF_FRAME, // Optional Segment reference frame
+ SEG_LVL_SKIP, // Optional Segment (0,0) + skip mode
+ SEG_LVL_GLOBALMV,
+ SEG_LVL_MAX
+} UENUM1BYTE(SEG_LVL_FEATURES);
+
+struct segmentation {
+ uint8_t enabled;
+ uint8_t update_map;
+ uint8_t update_data;
+ uint8_t temporal_update;
+
+ int16_t feature_data[MAX_SEGMENTS][SEG_LVL_MAX];
+ unsigned int feature_mask[MAX_SEGMENTS];
+ int last_active_segid; // The highest numbered segment id that has some
+ // enabled feature.
+ uint8_t segid_preskip; // Whether the segment id will be read before the
+ // skip syntax element.
+ // 1: the segment id will be read first.
+ // 0: the skip syntax element will be read first.
+};
+
+/*
+from av1_loopfilter.h
+*/
+#define MAX_LOOP_FILTER 63
+
+
+/* from
+quant_common.h:
+*/
+#define MAXQ 255
+
+#endif
+
+/*
+from:
+aom/av1/common/common.h
+*/
+#define av1_zero(dest) memset(&(dest), 0, sizeof(dest))
+#define av1_zero_array(dest, n) memset(dest, 0, n * sizeof(*(dest)))
+/*
+from:
+aom/av1/common/alloccommon.h
+*/
+#define INVALID_IDX -1 // Invalid buffer index.
+
+/*
+from:
+aom/av1/common/timing.h
+*/
+typedef struct aom_timing {
+ uint32_t num_units_in_display_tick;
+ uint32_t time_scale;
+ int equal_picture_interval;
+ uint32_t num_ticks_per_picture;
+} aom_timing_info_t;
+
+typedef struct aom_dec_model_info {
+ uint32_t num_units_in_decoding_tick;
+ int encoder_decoder_buffer_delay_length;
+ int buffer_removal_time_length;
+ int frame_presentation_time_length;
+} aom_dec_model_info_t;
+
+typedef struct aom_dec_model_op_parameters {
+ int decoder_model_param_present_flag;
+ int64_t bitrate;
+ int64_t buffer_size;
+ uint32_t decoder_buffer_delay;
+ uint32_t encoder_buffer_delay;
+ int low_delay_mode_flag;
+ int display_model_param_present_flag;
+ int initial_display_delay;
+} aom_dec_model_op_parameters_t;
+
+typedef struct aom_op_timing_info_t {
+ uint32_t buffer_removal_time;
+} aom_op_timing_info_t;
+/*
+from:
+aom/aom_codec.h
+*/
+/*!\brief OBU types. */
+typedef enum {
+ 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,
+} OBU_TYPE;
+
+typedef enum aom_bit_depth {
+ AOM_BITS_8 = 8, /**< 8 bits */
+ AOM_BITS_10 = 10, /**< 10 bits */
+ AOM_BITS_12 = 12, /**< 12 bits */
+} aom_bit_depth_t;
+
+/*!\brief Algorithm return codes */
+typedef enum {
+ /*!\brief Operation completed without error */
+ AOM_CODEC_OK,
+
+ /*!\brief Unspecified error */
+ AOM_CODEC_ERROR,
+
+ /*!\brief Memory operation failed */
+ AOM_CODEC_MEM_ERROR,
+
+ /*!\brief ABI version mismatch */
+ AOM_CODEC_ABI_MISMATCH,
+
+ /*!\brief Algorithm does not have required capability */
+ AOM_CODEC_INCAPABLE,
+
+ /*!\brief The given bitstream is not supported.
+ *
+ * The bitstream was unable to be parsed at the highest level. The decoder
+ * is unable to proceed. This error \ref SHOULD be treated as fatal to the
+ * stream. */
+ AOM_CODEC_UNSUP_BITSTREAM,
+
+ /*!\brief Encoded bitstream uses an unsupported feature
+ *
+ * The decoder does not implement a feature required by the encoder. This
+ * return code should only be used for features that prevent future
+ * pictures from being properly decoded. This error \ref MAY be treated as
+ * fatal to the stream or \ref MAY be treated as fatal to the current GOP.
+ */
+ AOM_CODEC_UNSUP_FEATURE,
+
+ /*!\brief The coded data for this stream is corrupt or incomplete
+ *
+ * There was a problem decoding the current frame. This return code
+ * should only be used for failures that prevent future pictures from
+ * being properly decoded. This error \ref MAY be treated as fatal to the
+ * stream or \ref MAY be treated as fatal to the current GOP. If decoding
+ * is continued for the current GOP, artifacts may be present.
+ */
+ AOM_CODEC_CORRUPT_FRAME,
+
+ /*!\brief An application-supplied parameter is not valid.
+ *
+ */
+ AOM_CODEC_INVALID_PARAM,
+
+ /*!\brief An iterator reached the end of list.
+ *
+ */
+ AOM_CODEC_LIST_END
+
+} aom_codec_err_t;
+
+typedef struct cfg_options {
+ /*!\brief Reflects if ext_partition should be enabled
+ *
+ * If this value is non-zero it enabled the feature
+ */
+ unsigned int ext_partition;
+} cfg_options_t;
+
+/*
+from:
+aom/av1/common/obu_util.h
+*/
+typedef struct {
+ size_t size; // Size (1 or 2 bytes) of the OBU header (including the
+ // optional OBU extension header) in the bitstream.
+ 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;
+} ObuHeader;
+
+
+/*
+from:
+aom/internal/aom_codec_internal.h
+*/
+
+struct aom_internal_error_info {
+ aom_codec_err_t error_code;
+ int has_detail;
+ char detail[80];
+ int setjmp; // Boolean: whether 'jmp' is valid.
+#ifdef ORI_CODE
+ jmp_buf jmp;
+#endif
+};
+
+/*
+from:
+aom/aom_frame_buffer.h
+*/
+typedef struct aom_codec_frame_buffer {
+ uint8_t *data; /**< Pointer to the data buffer */
+ size_t size; /**< Size of data in bytes */
+ void *priv; /**< Frame's private data */
+} aom_codec_frame_buffer_t;
+
+/*
+from:
+aom/aom_image.h
+*/
+#define AOM_IMAGE_ABI_VERSION (5) /**<\hideinitializer*/
+
+#define AOM_IMG_FMT_PLANAR 0x100 /**< Image is a planar format. */
+#define AOM_IMG_FMT_UV_FLIP 0x200 /**< V plane precedes U in memory. */
+/** 0x400 used to signal alpha channel, skipping for backwards compatibility. */
+#define AOM_IMG_FMT_HIGHBITDEPTH 0x800 /**< Image uses 16bit framebuffer. */
+
+/*!\brief List of supported image formats */
+typedef enum aom_img_fmt {
+ AOM_IMG_FMT_NONE,
+ AOM_IMG_FMT_YV12 =
+ AOM_IMG_FMT_PLANAR | AOM_IMG_FMT_UV_FLIP | 1, /**< planar YVU */
+ AOM_IMG_FMT_I420 = AOM_IMG_FMT_PLANAR | 2,
+ AOM_IMG_FMT_AOMYV12 = AOM_IMG_FMT_PLANAR | AOM_IMG_FMT_UV_FLIP |
+ 3, /** < planar 4:2:0 format with aom color space */
+ AOM_IMG_FMT_AOMI420 = AOM_IMG_FMT_PLANAR | 4,
+ AOM_IMG_FMT_I422 = AOM_IMG_FMT_PLANAR | 5,
+ AOM_IMG_FMT_I444 = AOM_IMG_FMT_PLANAR | 6,
+ AOM_IMG_FMT_I42016 = AOM_IMG_FMT_I420 | AOM_IMG_FMT_HIGHBITDEPTH,
+ AOM_IMG_FMT_YV1216 = AOM_IMG_FMT_YV12 | AOM_IMG_FMT_HIGHBITDEPTH,
+ AOM_IMG_FMT_I42216 = AOM_IMG_FMT_I422 | AOM_IMG_FMT_HIGHBITDEPTH,
+ AOM_IMG_FMT_I44416 = AOM_IMG_FMT_I444 | AOM_IMG_FMT_HIGHBITDEPTH,
+} aom_img_fmt_t; /**< alias for enum aom_img_fmt */
+
+/*!\brief List of supported color primaries */
+typedef enum aom_color_primaries {
+ AOM_CICP_CP_RESERVED_0 = 0, /**< For future use */
+ AOM_CICP_CP_BT_709 = 1, /**< BT.709 */
+ AOM_CICP_CP_UNSPECIFIED = 2, /**< Unspecified */
+ AOM_CICP_CP_RESERVED_3 = 3, /**< For future use */
+ AOM_CICP_CP_BT_470_M = 4, /**< BT.470 System M (historical) */
+ AOM_CICP_CP_BT_470_B_G = 5, /**< BT.470 System B, G (historical) */
+ AOM_CICP_CP_BT_601 = 6, /**< BT.601 */
+ AOM_CICP_CP_SMPTE_240 = 7, /**< SMPTE 240 */
+ AOM_CICP_CP_GENERIC_FILM =
+ 8, /**< Generic film (color filters using illuminant C) */
+ AOM_CICP_CP_BT_2020 = 9, /**< BT.2020, BT.2100 */
+ AOM_CICP_CP_XYZ = 10, /**< SMPTE 428 (CIE 1921 XYZ) */
+ AOM_CICP_CP_SMPTE_431 = 11, /**< SMPTE RP 431-2 */
+ AOM_CICP_CP_SMPTE_432 = 12, /**< SMPTE EG 432-1 */
+ AOM_CICP_CP_RESERVED_13 = 13, /**< For future use (values 13 - 21) */
+ AOM_CICP_CP_EBU_3213 = 22, /**< EBU Tech. 3213-E */
+ AOM_CICP_CP_RESERVED_23 = 23 /**< For future use (values 23 - 255) */
+} aom_color_primaries_t; /**< alias for enum aom_color_primaries */
+
+/*!\brief List of supported transfer functions */
+typedef enum aom_transfer_characteristics {
+ AOM_CICP_TC_RESERVED_0 = 0, /**< For future use */
+ AOM_CICP_TC_BT_709 = 1, /**< BT.709 */
+ AOM_CICP_TC_UNSPECIFIED = 2, /**< Unspecified */
+ AOM_CICP_TC_RESERVED_3 = 3, /**< For future use */
+ AOM_CICP_TC_BT_470_M = 4, /**< BT.470 System M (historical) */
+ AOM_CICP_TC_BT_470_B_G = 5, /**< BT.470 System B, G (historical) */
+ AOM_CICP_TC_BT_601 = 6, /**< BT.601 */
+ AOM_CICP_TC_SMPTE_240 = 7, /**< SMPTE 240 M */
+ AOM_CICP_TC_LINEAR = 8, /**< Linear */
+ AOM_CICP_TC_LOG_100 = 9, /**< Logarithmic (100 : 1 range) */
+ AOM_CICP_TC_LOG_100_SQRT10 =
+ 10, /**< Logarithmic (100 * Sqrt(10) : 1 range) */
+ AOM_CICP_TC_IEC_61966 = 11, /**< IEC 61966-2-4 */
+ AOM_CICP_TC_BT_1361 = 12, /**< BT.1361 */
+ AOM_CICP_TC_SRGB = 13, /**< sRGB or sYCC*/
+ AOM_CICP_TC_BT_2020_10_BIT = 14, /**< BT.2020 10-bit systems */
+ AOM_CICP_TC_BT_2020_12_BIT = 15, /**< BT.2020 12-bit systems */
+ AOM_CICP_TC_SMPTE_2084 = 16, /**< SMPTE ST 2084, ITU BT.2100 PQ */
+ AOM_CICP_TC_SMPTE_428 = 17, /**< SMPTE ST 428 */
+ AOM_CICP_TC_HLG = 18, /**< BT.2100 HLG, ARIB STD-B67 */
+ AOM_CICP_TC_RESERVED_19 = 19 /**< For future use (values 19-255) */
+} aom_transfer_characteristics_t; /**< alias for enum aom_transfer_function */
+
+/*!\brief List of supported matrix coefficients */
+typedef enum aom_matrix_coefficients {
+ AOM_CICP_MC_IDENTITY = 0, /**< Identity matrix */
+ AOM_CICP_MC_BT_709 = 1, /**< BT.709 */
+ AOM_CICP_MC_UNSPECIFIED = 2, /**< Unspecified */
+ AOM_CICP_MC_RESERVED_3 = 3, /**< For future use */
+ AOM_CICP_MC_FCC = 4, /**< US FCC 73.628 */
+ AOM_CICP_MC_BT_470_B_G = 5, /**< BT.470 System B, G (historical) */
+ AOM_CICP_MC_BT_601 = 6, /**< BT.601 */
+ AOM_CICP_MC_SMPTE_240 = 7, /**< SMPTE 240 M */
+ AOM_CICP_MC_SMPTE_YCGCO = 8, /**< YCgCo */
+ AOM_CICP_MC_BT_2020_NCL =
+ 9, /**< BT.2020 non-constant luminance, BT.2100 YCbCr */
+ AOM_CICP_MC_BT_2020_CL = 10, /**< BT.2020 constant luminance */
+ AOM_CICP_MC_SMPTE_2085 = 11, /**< SMPTE ST 2085 YDzDx */
+ AOM_CICP_MC_CHROMAT_NCL =
+ 12, /**< Chromaticity-derived non-constant luminance */
+ AOM_CICP_MC_CHROMAT_CL = 13, /**< Chromaticity-derived constant luminance */
+ AOM_CICP_MC_ICTCP = 14, /**< BT.2100 ICtCp */
+ AOM_CICP_MC_RESERVED_15 = 15 /**< For future use (values 15-255) */
+} aom_matrix_coefficients_t;
+
+/*!\brief List of supported color range */
+typedef enum aom_color_range {
+ AOM_CR_STUDIO_RANGE = 0, /**< Y [16..235], UV [16..240] */
+ AOM_CR_FULL_RANGE = 1 /**< YUV/RGB [0..255] */
+} aom_color_range_t; /**< alias for enum aom_color_range */
+
+/*!\brief List of chroma sample positions */
+typedef enum aom_chroma_sample_position {
+ AOM_CSP_UNKNOWN = 0, /**< Unknown */
+ AOM_CSP_VERTICAL = 1, /**< Horizontally co-located with luma(0, 0)*/
+ /**< sample, between two vertical samples */
+ AOM_CSP_COLOCATED = 2, /**< Co-located with luma(0, 0) sample */
+ AOM_CSP_RESERVED = 3 /**< Reserved value */
+} aom_chroma_sample_position_t; /**< alias for enum aom_transfer_function */
+
+/*
+from:
+aom/aom_scale/yv12config.h
+*/
+typedef struct PIC_BUFFER_CONFIG_s {
+ union {
+ struct {
+ int y_width;
+ int uv_width;
+ };
+ int widths[2];
+ };
+ union {
+ struct {
+ int y_height;
+ int uv_height;
+ };
+ int heights[2];
+ };
+ union {
+ struct {
+ int y_crop_width;
+ int uv_crop_width;
+ };
+ int crop_widths[2];
+ };
+ union {
+ struct {
+ int y_crop_height;
+ int uv_crop_height;
+ };
+ int crop_heights[2];
+ };
+ union {
+ struct {
+ int y_stride;
+ int uv_stride;
+ };
+ int strides[2];
+ };
+ union {
+ struct {
+ uint8_t *y_buffer;
+ uint8_t *u_buffer;
+ uint8_t *v_buffer;
+ };
+ uint8_t *buffers[3];
+ };
+
+ // Indicate whether y_buffer, u_buffer, and v_buffer points to the internally
+ // allocated memory or external buffers.
+ int use_external_reference_buffers;
+ // This is needed to store y_buffer, u_buffer, and v_buffer when set reference
+ // uses an external refernece, and restore those buffer pointers after the
+ // external reference frame is no longer used.
+ uint8_t *store_buf_adr[3];
+
+ // If the frame is stored in a 16-bit buffer, this stores an 8-bit version
+ // for use in global motion detection. It is allocated on-demand.
+ uint8_t *y_buffer_8bit;
+ int buf_8bit_valid;
+
+ uint8_t *buffer_alloc;
+ size_t buffer_alloc_sz;
+ int border;
+ size_t frame_size;
+ int subsampling_x;
+ int subsampling_y;
+ unsigned int bit_depth;
+ aom_color_primaries_t color_primaries;
+ aom_transfer_characteristics_t transfer_characteristics;
+ aom_matrix_coefficients_t matrix_coefficients;
+ uint8_t monochrome;
+ aom_chroma_sample_position_t chroma_sample_position;
+ aom_color_range_t color_range;
+ int render_width;
+ int render_height;
+
+ int corrupted;
+ int flags;
+
+#ifdef AML
+ int32_t index;
+ int32_t decode_idx;
+ int32_t slice_type;
+ int32_t RefNum_L0;
+ int32_t RefNum_L1;
+ int32_t num_reorder_pic;
+ int32_t stream_offset;
+ uint8_t referenced;
+ uint8_t output_mark;
+ uint8_t recon_mark;
+ uint8_t output_ready;
+ uint8_t error_mark;
+ /**/
+ int32_t slice_idx;
+ /*buffer*/
+ uint32_t fgs_table_adr;
+#ifdef AOM_AV1_MMU
+ uint32_t header_adr;
+#endif
+#ifdef AOM_AV1_MMU_DW
+ uint32_t header_dw_adr;
+#endif
+ uint32_t mpred_mv_wr_start_addr;
+ uint32_t mc_y_adr;
+ uint32_t mc_u_v_adr;
+ int32_t mc_canvas_y;
+ int32_t mc_canvas_u_v;
+
+ int32_t lcu_total;
+ /**/
+ unsigned int order_hint;
+#endif
+#ifdef AML_DEVICE
+ int mv_buf_index;
+ unsigned long cma_alloc_addr;
+ int BUF_index;
+ int buf_size;
+ int comp_body_size;
+ unsigned int dw_y_adr;
+ unsigned int dw_u_v_adr;
+ int double_write_mode;
+ int y_canvas_index;
+ int uv_canvas_index;
+ int vf_ref;
+ struct canvas_config_s canvas_config[2];
+ char *aux_data_buf;
+ int aux_data_size;
+ u32 pts;
+ u64 pts64;
+ /* 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;
+#endif
+ bool vframe_bound;
+ u64 timestamp;
+} PIC_BUFFER_CONFIG;
+
+/*
+from:
+common/blockd.h
+*/
+TYPEDEF enum {
+ KEY_FRAME = 0,
+ INTER_FRAME = 1,
+ INTRA_ONLY_FRAME = 2, // replaces intra-only
+ S_FRAME = 3,
+ FRAME_TYPES,
+} UENUM1BYTE(FRAME_TYPE);
+
+/*from:
+mv.h
+*/
+#ifdef ORI_CODE
+typedef struct mv32 {
+ int32_t row;
+ int32_t col;
+} MV32;
+#endif
+/*from:
+ aom_filter.h
+*/
+#define SUBPEL_BITS 4
+#define SUBPEL_MASK ((1 << SUBPEL_BITS) - 1)
+#define SUBPEL_SHIFTS (1 << SUBPEL_BITS)
+#define SUBPEL_TAPS 8
+
+#define SCALE_SUBPEL_BITS 10
+#define SCALE_SUBPEL_SHIFTS (1 << SCALE_SUBPEL_BITS)
+#define SCALE_SUBPEL_MASK (SCALE_SUBPEL_SHIFTS - 1)
+#define SCALE_EXTRA_BITS (SCALE_SUBPEL_BITS - SUBPEL_BITS)
+#define SCALE_EXTRA_OFF ((1 << SCALE_EXTRA_BITS) / 2)
+
+#define RS_SUBPEL_BITS 6
+#define RS_SUBPEL_MASK ((1 << RS_SUBPEL_BITS) - 1)
+#define RS_SCALE_SUBPEL_BITS 14
+#define RS_SCALE_SUBPEL_MASK ((1 << RS_SCALE_SUBPEL_BITS) - 1)
+#define RS_SCALE_EXTRA_BITS (RS_SCALE_SUBPEL_BITS - RS_SUBPEL_BITS)
+#define RS_SCALE_EXTRA_OFF (1 << (RS_SCALE_EXTRA_BITS - 1))
+
+/*from:
+scale.h
+*/
+#define SCALE_NUMERATOR 8
+
+#define REF_SCALE_SHIFT 14
+#define REF_NO_SCALE (1 << REF_SCALE_SHIFT)
+#define REF_INVALID_SCALE -1
+
+struct scale_factors {
+ int x_scale_fp; // horizontal fixed point scale factor
+ int y_scale_fp; // vertical fixed point scale factor
+ int x_step_q4;
+ int y_step_q4;
+
+ int (*scale_value_x)(int val, const struct scale_factors *sf);
+ int (*scale_value_y)(int val, const struct scale_factors *sf);
+#ifdef ORI_CODE
+ // convolve_fn_ptr[subpel_x != 0][subpel_y != 0][is_compound]
+ aom_convolve_fn_t convolve[2][2][2];
+ aom_highbd_convolve_fn_t highbd_convolve[2][2][2];
+#endif
+};
+
+#ifdef ORI_CODE
+MV32 av1_scale_mv(const MV *mv, int x, int y, const struct scale_factors *sf);
+#endif
+void av1_setup_scale_factors_for_frame(struct scale_factors *sf, int other_w,
+ int other_h, int this_w, int this_h);
+
+static inline int av1_is_valid_scale(const struct scale_factors *sf) {
+#ifdef ORI_CODE
+ assert(sf != NULL);
+#endif
+ return sf->x_scale_fp != REF_INVALID_SCALE &&
+ sf->y_scale_fp != REF_INVALID_SCALE;
+}
+
+static inline int av1_is_scaled(const struct scale_factors *sf) {
+#ifdef ORI_CODE
+ assert(sf != NULL);
+#endif
+ return av1_is_valid_scale(sf) &&
+ (sf->x_scale_fp != REF_NO_SCALE || sf->y_scale_fp != REF_NO_SCALE);
+}
+
+
+/*
+from:
+common/onyxc_int.h
+*/
+
+#define CDEF_MAX_STRENGTHS 16
+
+/* Constant values while waiting for the sequence header */
+#define FRAME_ID_LENGTH 15
+#define DELTA_FRAME_ID_LENGTH 14
+
+#define FRAME_CONTEXTS (FRAME_BUFFERS + 1)
+// Extra frame context which is always kept at default values
+#define FRAME_CONTEXT_DEFAULTS (FRAME_CONTEXTS - 1)
+#define PRIMARY_REF_BITS 3
+#define PRIMARY_REF_NONE 7
+
+#define NUM_PING_PONG_BUFFERS 2
+
+#define MAX_NUM_TEMPORAL_LAYERS 8
+#define MAX_NUM_SPATIAL_LAYERS 4
+/* clang-format off */
+// clang-format seems to think this is a pointer dereference and not a
+// multiplication.
+#define MAX_NUM_OPERATING_POINTS \
+ MAX_NUM_TEMPORAL_LAYERS * MAX_NUM_SPATIAL_LAYERS
+/* clang-format on*/
+
+// TODO(jingning): Turning this on to set up transform coefficient
+// processing timer.
+#define TXCOEFF_TIMER 0
+#define TXCOEFF_COST_TIMER 0
+
+TYPEDEF enum {
+ SINGLE_REFERENCE = 0,
+ COMPOUND_REFERENCE = 1,
+ REFERENCE_MODE_SELECT = 2,
+ REFERENCE_MODES = 3,
+} UENUM1BYTE(REFERENCE_MODE);
+
+TYPEDEF enum {
+ /**
+ * Frame context updates are disabled
+ */
+ REFRESH_FRAME_CONTEXT_DISABLED,
+ /**
+ * Update frame context to values resulting from backward probability
+ * updates based on entropy/counts in the decoded frame
+ */
+ REFRESH_FRAME_CONTEXT_BACKWARD,
+} UENUM1BYTE(REFRESH_FRAME_CONTEXT_MODE);
+
+#define MFMV_STACK_SIZE 3
+
+#ifdef AML
+#define MV_REF_SIZE 8
+#endif
+
+#ifdef ORI_CODE
+typedef struct {
+ int_mv mfmv0;
+ uint8_t ref_frame_offset;
+} TPL_MV_REF;
+typedef struct {
+ int_mv mv;
+ MV_REFERENCE_FRAME ref_frame;
+} MV_REF;
+#endif
+
+typedef struct RefCntBuffer_s {
+ // For a RefCntBuffer, the following are reference-holding variables:
+ // - cm->ref_frame_map[]
+ // - cm->cur_frame
+ // - cm->scaled_ref_buf[] (encoder only)
+ // - cm->next_ref_frame_map[] (decoder only)
+ // - pbi->output_frame_index[] (decoder only)
+ // With that definition, 'ref_count' is the number of reference-holding
+ // variables that are currently referencing this buffer.
+ // For example:
+ // - suppose this buffer is at index 'k' in the buffer pool, and
+ // - Total 'n' of the variables / array elements above have value 'k' (that
+ // is, they are pointing to buffer at index 'k').
+ // Then, pool->frame_bufs[k].ref_count = n.
+ int ref_count;
+
+ unsigned int order_hint;
+ unsigned int ref_order_hints[INTER_REFS_PER_FRAME];
+
+ int intra_only;
+ int segmentation_enabled;
+ unsigned int segment_feature[8];
+#ifdef AML
+ int segmentation_update_map;
+ int prev_segmentation_enabled;
+ int seg_mi_rows;
+ int seg_mi_cols;
+
+ unsigned int seg_lf_info_y[8];
+ unsigned int seg_lf_info_c[8];
+ int8_t ref_deltas[REF_FRAMES];
+ int8_t mode_deltas[MAX_MODE_LF_DELTAS];
+#endif
+ //MV_REF *mvs;
+ uint8_t *seg_map;
+#ifdef ORI_CODE
+ struct segmentation seg;
+#endif
+
+ int mi_rows;
+ int mi_cols;
+ // Width and height give the size of the buffer (before any upscaling, unlike
+ // the sizes that can be derived from the buf structure)
+ int width;
+ int height;
+#ifdef ORI_CODE
+ WarpedMotionParams global_motion[REF_FRAMES];
+#endif
+ int showable_frame; // frame can be used as show existing frame in future
+ uint8_t film_grain_params_present;
+#ifdef ORI_CODE
+ aom_film_grain_t film_grain_params;
+#endif
+#ifdef AML
+ int dec_width;
+ uint8_t film_grain_reg_valid;
+ uint32_t film_grain_reg[FILM_GRAIN_REG_SIZE];
+#endif
+ aom_codec_frame_buffer_t raw_frame_buffer;
+ PIC_BUFFER_CONFIG buf;
+#ifdef ORI_CODE
+ hash_table hash_table;
+#endif
+ FRAME_TYPE frame_type;
+
+ // This is only used in the encoder but needs to be indexed per ref frame
+ // so it's extremely convenient to keep it here.
+#ifdef ORI_CODE
+ int interp_filter_selected[SWITCHABLE];
+#endif
+ // Inter frame reference frame delta for loop filter
+#ifndef AML
+ int8_t ref_deltas[REF_FRAMES];
+#endif
+#ifdef ORI_CODE
+ // 0 = ZERO_MV, MV
+ int8_t mode_deltas[MAX_MODE_LF_DELTAS];
+
+ FRAME_CONTEXT frame_context;
+#endif
+} RefCntBuffer;
+
+typedef struct BufferPool_s {
+// Protect BufferPool from being accessed by several FrameWorkers at
+// the same time during frame parallel decode.
+// TODO(hkuang): Try to use atomic variable instead of locking the whole pool.
+// TODO(wtc): Remove this. See
+// https://chromium-review.googlesource.com/c/webm/libvpx/+/560630.
+#if CONFIG_MULTITHREAD
+ pthread_mutex_t pool_mutex;
+#endif
+
+ // Private data associated with the frame buffer callbacks.
+ void *cb_priv;
+#ifdef ORI_CODE
+ aom_get_frame_buffer_cb_fn_t get_fb_cb;
+ aom_release_frame_buffer_cb_fn_t release_fb_cb;
+#endif
+ RefCntBuffer frame_bufs[FRAME_BUFFERS];
+
+#ifdef ORI_CODE
+ // Frame buffers allocated internally by the codec.
+ InternalFrameBufferList int_frame_buffers;
+#endif
+#ifdef AML_DEVICE
+ spinlock_t lock;
+#endif
+} BufferPool;
+
+typedef struct {
+ int cdef_pri_damping;
+ int cdef_sec_damping;
+ int nb_cdef_strengths;
+ int cdef_strengths[CDEF_MAX_STRENGTHS];
+ int cdef_uv_strengths[CDEF_MAX_STRENGTHS];
+ int cdef_bits;
+} CdefInfo;
+
+typedef struct {
+ int delta_q_present_flag;
+ // Resolution of delta quant
+ int delta_q_res;
+ int delta_lf_present_flag;
+ // Resolution of delta lf level
+ int delta_lf_res;
+ // This is a flag for number of deltas of loop filter level
+ // 0: use 1 delta, for y_vertical, y_horizontal, u, and v
+ // 1: use separate deltas for each filter level
+ int delta_lf_multi;
+} DeltaQInfo;
+
+typedef struct {
+ int enable_order_hint; // 0 - disable order hint, and related tools
+ int order_hint_bits_minus_1; // dist_wtd_comp, ref_frame_mvs,
+ // frame_sign_bias
+ // if 0, enable_dist_wtd_comp and
+ // enable_ref_frame_mvs must be set as 0.
+ int enable_dist_wtd_comp; // 0 - disable dist-wtd compound modes
+ // 1 - enable it
+ int enable_ref_frame_mvs; // 0 - disable ref frame mvs
+ // 1 - enable it
+} OrderHintInfo;
+
+// Sequence header structure.
+// Note: All syntax elements of sequence_header_obu that need to be
+// bit-identical across multiple sequence headers must be part of this struct,
+// so that consistency is checked by are_seq_headers_consistent() function.
+typedef struct SequenceHeader {
+ int num_bits_width;
+ int num_bits_height;
+ int max_frame_width;
+ int max_frame_height;
+ uint8_t frame_id_numbers_present_flag;
+ int frame_id_length;
+ int delta_frame_id_length;
+ BLOCK_SIZE2 sb_size; // Size of the superblock used for this frame
+ int mib_size; // Size of the superblock in units of MI blocks
+ int mib_size_log2; // Log 2 of above.
+
+ OrderHintInfo order_hint_info;
+
+ uint8_t force_screen_content_tools; // 0 - force off
+ // 1 - force on
+ // 2 - adaptive
+ uint8_t still_picture; // Video is a single frame still picture
+ uint8_t reduced_still_picture_hdr; // Use reduced header for still picture
+ uint8_t force_integer_mv; // 0 - Don't force. MV can use subpel
+ // 1 - force to integer
+ // 2 - adaptive
+ uint8_t enable_filter_intra; // enables/disables filterintra
+ uint8_t enable_intra_edge_filter; // enables/disables edge upsampling
+ uint8_t enable_interintra_compound; // enables/disables interintra_compound
+ uint8_t enable_masked_compound; // enables/disables masked compound
+ uint8_t enable_dual_filter; // 0 - disable dual interpolation filter
+ // 1 - enable vert/horz filter selection
+ uint8_t enable_warped_motion; // 0 - disable warp for the sequence
+ // 1 - enable warp for the sequence
+ uint8_t enable_superres; // 0 - Disable superres for the sequence
+ // and no frame level superres flag
+ // 1 - Enable superres for the sequence
+ // enable per-frame superres flag
+ uint8_t enable_cdef; // To turn on/off CDEF
+ uint8_t enable_restoration; // To turn on/off loop restoration
+ BITSTREAM_PROFILE profile;
+
+ // Operating point info.
+ int operating_points_cnt_minus_1;
+ int operating_point_idc[MAX_NUM_OPERATING_POINTS];
+ uint8_t display_model_info_present_flag;
+ uint8_t decoder_model_info_present_flag;
+ AV1_LEVEL seq_level_idx[MAX_NUM_OPERATING_POINTS];
+ uint8_t tier[MAX_NUM_OPERATING_POINTS]; // seq_tier in the spec. One bit: 0
+ // or 1.
+
+ // Color config.
+ aom_bit_depth_t bit_depth; // AOM_BITS_8 in profile 0 or 1,
+ // AOM_BITS_10 or AOM_BITS_12 in profile 2 or 3.
+ uint8_t use_highbitdepth; // If true, we need to use 16bit frame buffers.
+ uint8_t monochrome; // Monochorme video
+ aom_color_primaries_t color_primaries;
+ aom_transfer_characteristics_t transfer_characteristics;
+ aom_matrix_coefficients_t matrix_coefficients;
+ int color_range;
+ int subsampling_x; // Chroma subsampling for x
+ int subsampling_y; // Chroma subsampling for y
+ aom_chroma_sample_position_t chroma_sample_position;
+ uint8_t separate_uv_delta_q;
+ uint8_t film_gry_dequant_QTXain_params_present;
+} SequenceHeader;
+
+typedef struct {
+ int skip_mode_allowed;
+ int skip_mode_flag;
+ int ref_frame_idx_0;
+ int ref_frame_idx_1;
+} SkipModeInfo;
+
+typedef struct {
+ FRAME_TYPE frame_type;
+ REFERENCE_MODE reference_mode;
+
+ unsigned int order_hint;
+ unsigned int frame_number;
+ SkipModeInfo skip_mode_info;
+ int refresh_frame_flags; // Which ref frames are overwritten by this frame
+ int frame_refs_short_signaling;
+} CurrentFrame;
+
+typedef struct AV1_Common_s {
+ CurrentFrame current_frame;
+ struct aom_internal_error_info error;
+ int width;
+ int height;
+ int render_width;
+ int render_height;
+ int timing_info_present;
+ aom_timing_info_t timing_info;
+ int buffer_removal_time_present;
+ aom_dec_model_info_t buffer_model;
+ aom_dec_model_op_parameters_t op_params[MAX_NUM_OPERATING_POINTS + 1];
+ aom_op_timing_info_t op_frame_timing[MAX_NUM_OPERATING_POINTS + 1];
+ uint32_t frame_presentation_time;
+
+ int context_update_tile_id;
+#ifdef SUPPORT_SCALE_FACTOR
+ // Scale of the current frame with respect to itself.
+ struct scale_factors sf_identity;
+#endif
+ RefCntBuffer *prev_frame;
+
+ // TODO(hkuang): Combine this with cur_buf in macroblockd.
+ RefCntBuffer *cur_frame;
+
+ // For encoder, we have a two-level mapping from reference frame type to the
+ // corresponding buffer in the buffer pool:
+ // * 'remapped_ref_idx[i - 1]' maps reference type 'i' (range: LAST_FRAME ...
+ // EXTREF_FRAME) to a remapped index 'j' (in range: 0 ... REF_FRAMES - 1)
+ // * Later, 'cm->ref_frame_map[j]' maps the remapped index 'j' to a pointer to
+ // the reference counted buffer structure RefCntBuffer, taken from the buffer
+ // pool cm->buffer_pool->frame_bufs.
+ //
+ // LAST_FRAME, ..., EXTREF_FRAME
+ // | |
+ // v v
+ // remapped_ref_idx[LAST_FRAME - 1], ..., remapped_ref_idx[EXTREF_FRAME - 1]
+ // | |
+ // v v
+ // ref_frame_map[], ..., ref_frame_map[]
+ //
+ // Note: INTRA_FRAME always refers to the current frame, so there's no need to
+ // have a remapped index for the same.
+ int remapped_ref_idx[REF_FRAMES];
+
+#ifdef SUPPORT_SCALE_FACTOR
+ struct scale_factors ref_scale_factors[REF_FRAMES];
+#endif
+ // For decoder, ref_frame_map[i] maps reference type 'i' to a pointer to
+ // the buffer in the buffer pool 'cm->buffer_pool.frame_bufs'.
+ // For encoder, ref_frame_map[j] (where j = remapped_ref_idx[i]) maps
+ // remapped reference index 'j' (that is, original reference type 'i') to
+ // a pointer to the buffer in the buffer pool 'cm->buffer_pool.frame_bufs'.
+ RefCntBuffer *ref_frame_map[REF_FRAMES];
+
+ // Prepare ref_frame_map for the next frame.
+ // Only used in frame parallel decode.
+ RefCntBuffer *next_ref_frame_map[REF_FRAMES];
+#ifdef AML
+ RefCntBuffer *next_used_ref_frame_map[REF_FRAMES];
+#endif
+ FRAME_TYPE last_frame_type; /* last frame's frame type for motion search.*/
+
+ int show_frame;
+ int showable_frame; // frame can be used as show existing frame in future
+ int show_existing_frame;
+
+ uint8_t disable_cdf_update;
+ int allow_high_precision_mv;
+ uint8_t cur_frame_force_integer_mv; // 0 the default in AOM, 1 only integer
+
+ uint8_t allow_screen_content_tools;
+ int allow_intrabc;
+ int allow_warped_motion;
+
+ // MBs, mb_rows/cols is in 16-pixel units; mi_rows/cols is in
+ // MB_MODE_INFO (8-pixel) units.
+ int MBs;
+ int mb_rows, mi_rows;
+ int mb_cols, mi_cols;
+ int mi_stride;
+
+ /* profile settings */
+ TX_MODE tx_mode;
+
+#if CONFIG_ENTROPY_STATS
+ int coef_cdf_category;
+#endif
+
+ int base_qindex;
+ int y_dc_delta_q;
+ int u_dc_delta_q;
+ int v_dc_delta_q;
+ int u_ac_delta_q;
+ int v_ac_delta_q;
+
+#ifdef ORI_CODE
+ // The dequantizers below are true dequantizers used only in the
+ // dequantization process. They have the same coefficient
+ // shift/scale as TX.
+ int16_t y_dequant_QTX[MAX_SEGMENTS][2];
+ int16_t u_dequant_QTX[MAX_SEGMENTS][2];
+ int16_t v_dequant_QTX[MAX_SEGMENTS][2];
+
+ // Global quant matrix tables
+ const qm_val_t *giqmatrix[NUM_QM_LEVELS][3][TX_SIZES_ALL];
+ const qm_val_t *gqmatrix[NUM_QM_LEVELS][3][TX_SIZES_ALL];
+
+ // Local quant matrix tables for each frame
+ const qm_val_t *y_iqmatrix[MAX_SEGMENTS][TX_SIZES_ALL];
+ const qm_val_t *u_iqmatrix[MAX_SEGMENTS][TX_SIZES_ALL];
+ const qm_val_t *v_iqmatrix[MAX_SEGMENTS][TX_SIZES_ALL];
+#endif
+ // Encoder
+ int using_qmatrix;
+ int qm_y;
+ int qm_u;
+ int qm_v;
+ int min_qmlevel;
+ int max_qmlevel;
+ int use_quant_b_adapt;
+
+ /* We allocate a MB_MODE_INFO struct for each macroblock, together with
+ an extra row on top and column on the left to simplify prediction. */
+ int mi_alloc_size;
+
+#ifdef ORI_CODE
+ MB_MODE_INFO *mip; /* Base of allocated array */
+ MB_MODE_INFO *mi; /* Corresponds to upper left visible macroblock */
+
+ // TODO(agrange): Move prev_mi into encoder structure.
+ // prev_mip and prev_mi will only be allocated in encoder.
+ MB_MODE_INFO *prev_mip; /* MB_MODE_INFO array 'mip' from last decoded frame */
+ MB_MODE_INFO *prev_mi; /* 'mi' from last frame (points into prev_mip) */
+
+ // Separate mi functions between encoder and decoder.
+ int (*alloc_mi)(struct AV1Common *cm, int mi_size);
+ void (*free_mi)(struct AV1Common *cm);
+ void (*setup_mi)(struct AV1Common *cm);
+
+ // Grid of pointers to 8x8 MB_MODE_INFO structs. Any 8x8 not in the visible
+ // area will be NULL.
+ MB_MODE_INFO **mi_grid_base;
+ MB_MODE_INFO **mi_grid_visible;
+ MB_MODE_INFO **prev_mi_grid_base;
+ MB_MODE_INFO **prev_mi_grid_visible;
+#endif
+ // Whether to use previous frames' motion vectors for prediction.
+ int allow_ref_frame_mvs;
+
+ uint8_t *last_frame_seg_map;
+
+#ifdef ORI_CODE
+ InterpFilter interp_filter;
+#endif
+ int switchable_motion_mode;
+#ifdef ORI_CODE
+ loop_filter_info_n lf_info;
+#endif
+ // The denominator of the superres scale; the numerator is fixed.
+ uint8_t superres_scale_denominator;
+ int superres_upscaled_width;
+ int superres_upscaled_height;
+
+#ifdef ORI_CODE
+ RestorationInfo rst_info[MAX_MB_PLANE];
+#endif
+ // Pointer to a scratch buffer used by self-guided restoration
+ int32_t *rst_tmpbuf;
+#ifdef ORI_CODE
+ RestorationLineBuffers *rlbs;
+#endif
+ // Output of loop restoration
+ PIC_BUFFER_CONFIG rst_frame;
+
+ // Flag signaling how frame contexts should be updated at the end of
+ // a frame decode
+ REFRESH_FRAME_CONTEXT_MODE refresh_frame_context;
+
+ int ref_frame_sign_bias[REF_FRAMES]; /* Two state 0, 1 */
+
+#ifdef ORI_CODE
+ struct loopfilter lf;
+ struct segmentation seg;
+#endif
+
+ int coded_lossless; // frame is fully lossless at the coded resolution.
+ int all_lossless; // frame is fully lossless at the upscaled resolution.
+
+ int reduced_tx_set_used;
+
+#ifdef ORI_CODE
+ // Context probabilities for reference frame prediction
+ MV_REFERENCE_FRAME comp_fwd_ref[FWD_REFS];
+ MV_REFERENCE_FRAME comp_bwd_ref[BWD_REFS];
+
+ FRAME_CONTEXT *fc; /* this frame entropy */
+ FRAME_CONTEXT *default_frame_context;
+#endif
+ int primary_ref_frame;
+
+ int error_resilient_mode;
+
+ int tile_cols, tile_rows;
+
+ int max_tile_width_sb;
+ int min_log2_tile_cols;
+ int max_log2_tile_cols;
+ int max_log2_tile_rows;
+ int min_log2_tile_rows;
+ int min_log2_tiles;
+ int max_tile_height_sb;
+ int uniform_tile_spacing_flag;
+ int log2_tile_cols; // only valid for uniform tiles
+ int log2_tile_rows; // only valid for uniform tiles
+ int tile_col_start_sb[MAX_TILE_COLS + 1]; // valid for 0 <= i <= tile_cols
+ int tile_row_start_sb[MAX_TILE_ROWS + 1]; // valid for 0 <= i <= tile_rows
+ int tile_width, tile_height; // In MI units
+ int min_inner_tile_width; // min width of non-rightmost tile
+
+ unsigned int large_scale_tile;
+ unsigned int single_tile_decoding;
+
+ int byte_alignment;
+ int skip_loop_filter;
+ int skip_film_grain;
+
+ // External BufferPool passed from outside.
+ BufferPool *buffer_pool;
+
+#ifdef ORI_CODE
+ PARTITION_CONTEXT **above_seg_context;
+ ENTROPY_CONTEXT **above_context[MAX_MB_PLANE];
+ TXFM_CONTEXT **above_txfm_context;
+ WarpedMotionParams global_motion[REF_FRAMES];
+ aom_film_grain_t film_grain_params;
+
+ CdefInfo cdef_info;
+ DeltaQInfo delta_q_info; // Delta Q and Delta LF parameters
+#endif
+ int num_tg;
+ SequenceHeader seq_params;
+ int current_frame_id;
+ int ref_frame_id[REF_FRAMES];
+ int valid_for_referencing[REF_FRAMES];
+#ifdef ORI_CODE
+ TPL_MV_REF *tpl_mvs;
+#endif
+ int tpl_mvs_mem_size;
+ // TODO(jingning): This can be combined with sign_bias later.
+ int8_t ref_frame_side[REF_FRAMES];
+
+ int is_annexb;
+
+ int temporal_layer_id;
+ int spatial_layer_id;
+ unsigned int number_temporal_layers;
+ unsigned int number_spatial_layers;
+ int num_allocated_above_context_mi_col;
+ int num_allocated_above_contexts;
+ int num_allocated_above_context_planes;
+
+#if TXCOEFF_TIMER
+ int64_t cum_txcoeff_timer;
+ int64_t txcoeff_timer;
+ int txb_count;
+#endif
+
+#if TXCOEFF_COST_TIMER
+ int64_t cum_txcoeff_cost_timer;
+ int64_t txcoeff_cost_timer;
+ int64_t txcoeff_cost_count;
+#endif
+ const cfg_options_t *options;
+ int is_decoding;
+#ifdef AML
+ int mv_ref_offset[MV_REF_SIZE][REF_FRAMES];
+ int mv_ref_id[MV_REF_SIZE];
+ unsigned char mv_cal_tpl_mvs[MV_REF_SIZE];
+ int mv_ref_id_index;
+ int prev_fb_idx;
+ int new_fb_idx;
+ int32_t dec_width;
+#endif
+#ifdef AML_DEVICE
+ int cur_fb_idx_mmu;
+#ifdef AOM_AV1_MMU_DW
+ int cur_fb_idx_mmu_dw;
+#endif
+ int current_video_frame;
+ int use_prev_frame_mvs;
+ int frame_type;
+ int intra_only;
+ struct RefCntBuffer_s frame_refs[INTER_REFS_PER_FRAME];
+
+#endif
+} AV1_COMMON;
+
+
+/*
+from:
+ decoder/decoder.h
+*/
+
+typedef struct EXTERNAL_REFERENCES {
+ PIC_BUFFER_CONFIG refs[MAX_EXTERNAL_REFERENCES];
+ int num;
+} EXTERNAL_REFERENCES;
+
+typedef struct AV1Decoder {
+ //DECLARE_ALIGNED(32, MACROBLOCKD, mb);
+
+ //DECLARE_ALIGNED(32, AV1_COMMON, common);
+ AV1_COMMON *common;
+
+#ifdef ORI_CODE
+ AVxWorker lf_worker;
+ AV1LfSync lf_row_sync;
+ AV1LrSync lr_row_sync;
+ AV1LrStruct lr_ctxt;
+ AVxWorker *tile_workers;
+ int num_workers;
+ DecWorkerData *thread_data;
+ ThreadData td;
+ TileDataDec *tile_data;
+ int allocated_tiles;
+ TileBufferDec tile_buffers[MAX_TILE_ROWS][MAX_TILE_COLS];
+ AV1DecTileMT tile_mt_info;
+#endif
+
+ // Each time the decoder is called, we expect to receive a full temporal unit.
+ // This can contain up to one shown frame per spatial layer in the current
+ // operating point (note that some layers may be entirely omitted).
+ // If the 'output_all_layers' option is true, we save all of these shown
+ // frames so that they can be returned to the application. If the
+ // 'output_all_layers' option is false, then we only output one image per
+ // temporal unit.
+ //
+ // Note: The saved buffers are released at the start of the next time the
+ // application calls aom_codec_decode().
+ int output_all_layers;
+ RefCntBuffer *output_frames[MAX_NUM_SPATIAL_LAYERS];
+ size_t num_output_frames; // How many frames are queued up so far?
+
+ // In order to properly support random-access decoding, we need
+ // to behave slightly differently for the very first frame we decode.
+ // So we track whether this is the first frame or not.
+ int decoding_first_frame;
+
+ int allow_lowbitdepth;
+ int max_threads;
+ int inv_tile_order;
+ int need_resync; // wait for key/intra-only frame.
+ int hold_ref_buf; // Boolean: whether we are holding reference buffers in
+ // common.next_ref_frame_map.
+ int reset_decoder_state;
+
+ int tile_size_bytes;
+ int tile_col_size_bytes;
+ int dec_tile_row, dec_tile_col; // always -1 for non-VR tile encoding
+#if CONFIG_ACCOUNTING
+ int acct_enabled;
+ Accounting accounting;
+#endif
+ int tg_size; // Number of tiles in the current tilegroup
+ int tg_start; // First tile in the current tilegroup
+ int tg_size_bit_offset;
+ int sequence_header_ready;
+ int sequence_header_changed;
+#if CONFIG_INSPECTION
+ aom_inspect_cb inspect_cb;
+ void *inspect_ctx;
+#endif
+ int operating_point;
+ int current_operating_point;
+ int seen_frame_header;
+
+ // State if the camera frame header is already decoded while
+ // large_scale_tile = 1.
+ int camera_frame_header_ready;
+ size_t frame_header_size;
+#ifdef ORI_CODE
+ DataBuffer obu_size_hdr;
+#endif
+ int output_frame_width_in_tiles_minus_1;
+ int output_frame_height_in_tiles_minus_1;
+ int tile_count_minus_1;
+ uint32_t coded_tile_data_size;
+ unsigned int ext_tile_debug; // for ext-tile software debug & testing
+ unsigned int row_mt;
+ EXTERNAL_REFERENCES ext_refs;
+ PIC_BUFFER_CONFIG tile_list_outbuf;
+
+#ifdef ORI_CODE
+ CB_BUFFER *cb_buffer_base;
+#endif
+ int cb_buffer_alloc_size;
+
+ int allocated_row_mt_sync_rows;
+
+#if CONFIG_MULTITHREAD
+ pthread_mutex_t *row_mt_mutex_;
+ pthread_cond_t *row_mt_cond_;
+#endif
+
+#ifdef ORI_CODE
+ AV1DecRowMTInfo frame_row_mt_info;
+#endif
+
+#ifdef AML
+ unsigned char pred_inter_read_enable;
+ int cur_obu_type;
+ int decode_idx;
+ int bufmgr_proc_count;
+ int obu_frame_frame_head_come_after_tile;
+ uint32_t frame_width;
+ uint32_t frame_height;
+ BuffInfo_t* work_space_buf;
+ buff_t* mc_buf;
+ //unsigned short *rpm_ptr;
+ void *private_data;
+ u32 pre_stream_offset;
+#endif
+} AV1Decoder;
+
+#define RPM_BEGIN 0x200
+#define RPM_END 0x280
+
+typedef union param_u {
+ struct {
+ unsigned short data[RPM_END - RPM_BEGIN];
+ } l;
+ struct {
+ /*sequence head*/
+ unsigned short profile;
+ unsigned short still_picture;
+ unsigned short reduced_still_picture_hdr;
+ unsigned short decoder_model_info_present_flag;
+ unsigned short max_frame_width;
+ unsigned short max_frame_height;
+ unsigned short frame_id_numbers_present_flag;
+ unsigned short delta_frame_id_length;
+ unsigned short frame_id_length;
+ unsigned short order_hint_bits_minus_1;
+ unsigned short enable_order_hint;
+ unsigned short enable_dist_wtd_comp;
+ unsigned short enable_ref_frame_mvs;
+
+ /*frame head*/
+ unsigned short show_existing_frame;
+ unsigned short frame_type;
+ unsigned short show_frame;
+ unsigned short error_resilient_mode;
+ unsigned short refresh_frame_flags;
+ unsigned short showable_frame;
+ unsigned short current_frame_id;
+ unsigned short frame_size_override_flag;
+ unsigned short order_hint;
+ unsigned short primary_ref_frame;
+ unsigned short frame_refs_short_signaling;
+ unsigned short frame_width;
+ unsigned short dec_frame_width;
+ unsigned short frame_width_scaled;
+ unsigned short frame_height;
+ unsigned short reference_mode;
+ unsigned short allow_ref_frame_mvs;
+ unsigned short superres_scale_denominator;
+ unsigned short lst_ref;
+ unsigned short gld_ref;
+ unsigned short existing_frame_idx;
+
+ unsigned short remapped_ref_idx[INTER_REFS_PER_FRAME];
+ unsigned short delta_frame_id_minus_1[INTER_REFS_PER_FRAME];
+ unsigned short ref_order_hint[REF_FRAMES];
+ /*other not in reference*/
+ unsigned short bit_depth;
+ unsigned short seq_flags;
+ unsigned short update_parameters;
+ unsigned short film_grain_params_ref_idx;
+
+ /*loop_filter & segmentation*/
+ unsigned short loop_filter_sharpness_level;
+ unsigned short loop_filter_mode_ref_delta_enabled;
+ unsigned short loop_filter_ref_deltas_0;
+ unsigned short loop_filter_ref_deltas_1;
+ unsigned short loop_filter_ref_deltas_2;
+ unsigned short loop_filter_ref_deltas_3;
+ unsigned short loop_filter_ref_deltas_4;
+ unsigned short loop_filter_ref_deltas_5;
+ unsigned short loop_filter_ref_deltas_6;
+ unsigned short loop_filter_ref_deltas_7;
+ unsigned short loop_filter_mode_deltas_0;
+ unsigned short loop_filter_mode_deltas_1;
+ unsigned short loop_filter_level_0;
+ unsigned short loop_filter_level_1;
+ unsigned short loop_filter_level_u;
+ unsigned short loop_filter_level_v;
+
+ unsigned short segmentation_enabled;
+ /*
+ SEG_LVL_ALT_LF_Y_V feature_enable: seg_lf_info_y[bit7]
+ SEG_LVL_ALT_LF_Y_V data: seg_lf_info_y[bit0~6]
+ SEG_LVL_ALT_LF_Y_H feature enable: seg_lf_info_y[bit15]
+ SEG_LVL_ALT_LF_Y_H data: seg_lf_info_y[bit8~14]
+ */
+ unsigned short seg_lf_info_y[8];
+ /*
+ SEG_LVL_ALT_LF_U feature_enable: seg_lf_info_y[bit7]
+ SEG_LVL_ALT_LF_U data: seg_lf_info_y[bit0~6]
+ SEG_LVL_ALT_LF_V feature enable: seg_lf_info_y[bit15]
+ SEG_LVL_ALT_LF_V data: seg_lf_info_y[bit8~14]
+ */
+ unsigned short seg_lf_info_c[8];
+ unsigned short video_signal_type;
+ unsigned short color_description;
+
+ /*ucode end*/
+ /*other*/
+ unsigned short enable_superres;
+
+ /*seqence not use*/
+ unsigned short operating_points_cnt_minus_1;
+ unsigned short operating_point_idc[MAX_NUM_OPERATING_POINTS];
+ unsigned short seq_level_idx[MAX_NUM_OPERATING_POINTS];
+ unsigned short decoder_model_param_present_flag[MAX_NUM_OPERATING_POINTS];
+ unsigned short timing_info_present;
+ /*frame head not use*/
+ unsigned short display_frame_id;
+ unsigned short frame_presentation_time;
+ unsigned short buffer_removal_time_present;
+ unsigned short op_frame_timing[MAX_NUM_OPERATING_POINTS + 1];
+ unsigned short valid_ref_frame_bits;
+
+ } p;
+}param_t;
+
+PIC_BUFFER_CONFIG *av1_get_ref_frame_spec_buf(
+ const AV1_COMMON *const cm, const MV_REFERENCE_FRAME ref_frame);
+
+int av1_bufmgr_process(AV1Decoder *pbi, union param_u *params,
+ unsigned char new_compressed_data, int obu_type);
+
+struct scale_factors *av1_get_ref_scale_factors(
+ AV1_COMMON *const cm, const MV_REFERENCE_FRAME ref_frame);
+
+void av1_set_next_ref_frame_map(AV1Decoder *pbi);
+
+unsigned int av1_get_next_used_ref_info(
+ const AV1_COMMON *const cm, int i);
+
+void av1_release_buf(AV1Decoder *pbi, RefCntBuffer *const buf);
+
+int av1_bufmgr_postproc(AV1Decoder *pbi, unsigned char frame_decoded);
+
+AV1Decoder *av1_decoder_create(BufferPool *const pool, AV1_COMMON *cm);
+
+unsigned char av1_frame_is_inter(const AV1_COMMON *const cm);
+
+RefCntBuffer *av1_get_primary_ref_frame_buf(
+ const AV1_COMMON *const cm);
+
+void av1_raw_write_image(AV1Decoder *pbi, PIC_BUFFER_CONFIG *sd);
+
+int get_free_frame_buffer(struct AV1_Common_s *cm);
+
+void av1_bufmgr_ctx_reset(AV1Decoder *pbi, BufferPool *const pool, AV1_COMMON *cm);
+
+#if 1
+#define lock_buffer_pool(pool, flags) \
+ spin_lock_irqsave(&pool->lock, flags)
+
+#define unlock_buffer_pool(pool, flags) \
+ spin_unlock_irqrestore(&pool->lock, flags)
+#else
+#define lock_buffer_pool(pool, flags) flags=1;
+
+#define unlock_buffer_pool(pool, flags) flags=0;
+
+#endif
+
+#define AV1_DEBUG_BUFMGR 0x01
+#define AV1_DEBUG_BUFMGR_MORE 0x02
+#define AV1_DEBUG_BUFMGR_DETAIL 0x04
+#define AV1_DEBUG_OUT_PTS 0x10
+#define AOM_DEBUG_HW_MORE 0x20
+#define AOM_DEBUG_VFRAME 0x40
+#define AOM_DEBUG_PRINT_LIST_INFO 0x80
+#define AOM_AV1_DEBUG_SEND_PARAM_WITH_REG 0x100
+#define AV1_DEBUG_IGNORE_VF_REF 0x200
+#define AV1_DEBUG_DBG_LF_PRINT 0x400
+#define AV1_DEBUG_REG 0x800
+#define AOM_DEBUG_BUFMGR_ONLY 0x1000
+#define AOM_DEBUG_AUX_DATA 0x2000
+#define AV1_DEBUG_QOS_INFO 0x4000
+#define AOM_DEBUG_DW_DISP_MAIN 0x8000
+#define AV1_DEBUG_DIS_LOC_ERROR_PROC 0x10000
+#define AOM_DEBUG_DIS_RECYCLE_MMU_TAIL 0x20000
+#define AV1_DEBUG_DUMP_PIC_LIST 0x40000
+#define AV1_DEBUG_TRIG_SLICE_SEGMENT_PROC 0x80000
+#define AOM_DEBUG_USE_FIXED_MV_BUF_SIZE 0x100000
+#define AV1_DEBUG_LOAD_UCODE_FROM_FILE 0x200000
+#define AV1_DEBUG_FORCE_SEND_AGAIN 0x400000
+#define AV1_DEBUG_DUMP_DATA 0x800000
+#define AV1_DEBUG_CACHE 0x1000000
+#define AV1_DEBUG_CACHE_HIT_RATE 0x2000000
+#define IGNORE_PARAM_FROM_CONFIG 0x8000000
+#if 1
+/*def MULTI_INSTANCE_SUPPORT*/
+#define PRINT_FLAG_ERROR 0x0
+#define PRINT_FLAG_V4L_DETAIL 0x10000000
+#define PRINT_FLAG_VDEC_STATUS 0x20000000
+#define PRINT_FLAG_VDEC_DETAIL 0x40000000
+#define PRINT_FLAG_VDEC_DATA 0x80000000
+#endif
+
+int av1_print2(int flag, const char *fmt, ...);
+
+unsigned char av1_is_debug(int flag);
+
+#endif
+
diff --git a/drivers/frame_provider/decoder/vav1/vav1.c b/drivers/frame_provider/decoder/vav1/vav1.c
new file mode 100644
index 0000000..d67d76c
--- /dev/null
+++ b/drivers/frame_provider/decoder/vav1/vav1.c
@@ -0,0 +1,11363 @@
+ /*
+ * drivers/amlogic/amports/vav1.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/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 "../../../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 <linux/crc32.h>
+
+#define MEM_NAME "codec_av1"
+/* #include <mach/am_regs.h> */
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "../utils/vdec.h"
+#include "../utils/amvdec.h"
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+#include "../utils/vdec_profile.h"
+#endif
+
+#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 "../../../amvdec_ports/vdec_drv_base.h"
+
+//#define DEBUG_UCODE_LOG
+#define DEBUG_CMD
+#define DEBUG_CRC_ERROR
+
+#define SUPPORT_V4L2
+//#define DEBUG_USE_VP9_DEVICE_NAME
+//#define BUFMGR_ONLY_OLD_CHIP
+
+#ifdef SUPPORT_V4L2
+#include "../utils/vdec_v4l2_buffer_ops.h"
+#include <media/v4l2-mem2mem.h>
+#endif
+#include "../../../amvdec_ports/utils/common.h"
+
+#define AML
+#include "aom_av1_define.h"
+#include "av1_global.h"
+
+#define DUMP_FILMGRAIN
+#define MIX_STREAM_SUPPORT
+//#define MV_USE_FIXED_BUF
+//#define USE_SPEC_BUF_FOR_MMU_HEAD
+
+#define AOM_AV1_DBLK_INIT
+#define AOM_AV1_UPSCALE_INIT
+
+#define USE_DEC_PIC_END
+
+
+#include "vav1.h"
+
+#define FGS_TABLE_SIZE (512 * 128 / 8)
+
+#define AV1_GMC_PARAM_BUFF_ADDR 0x316d
+#define HEVCD_MPP_DECOMP_AXIURG_CTL 0x34c7
+#define HEVC_FGS_IDX 0x3660
+#define HEVC_FGS_DATA 0x3661
+#define HEVC_FGS_CTRL 0x3662
+#define AV1_SKIP_MODE_INFO 0x316c
+#define AV1_QUANT_WR 0x3146
+#define AV1_SEG_W_ADDR 0x3165
+#define AV1_SEG_R_ADDR 0x3166
+#define AV1_REF_SEG_INFO 0x3171
+#define HEVC_ASSIST_PIC_SIZE_FB_READ 0x300d
+#define PARSER_REF_SCALE_ENBL 0x316b
+#define HEVC_MPRED_MV_RPTR_1 0x3263
+#define HEVC_MPRED_MV_RPTR_2 0x3264
+#define HEVC_SAO_CTRL9 0x362d
+#define HEVC_FGS_TABLE_START 0x3666
+#define HEVC_FGS_TABLE_LENGTH 0x3667
+#define HEVC_DBLK_CDEF0 0x3515
+#define HEVC_DBLK_CDEF1 0x3516
+#define HEVC_DBLK_UPS1 0x351c
+#define HEVC_DBLK_UPS2 0x351d
+#define HEVC_DBLK_UPS3 0x351e
+#define HEVC_DBLK_UPS4 0x351f
+#define HEVC_DBLK_UPS5 0x3520
+#define AV1_UPSCALE_X0_QN 0x316e
+#define AV1_UPSCALE_STEP_QN 0x316f
+#define HEVC_DBLK_DBLK0 0x3523
+#define HEVC_DBLK_DBLK1 0x3524
+#define HEVC_DBLK_DBLK2 0x3525
+
+#define HW_MASK_FRONT 0x1
+#define HW_MASK_BACK 0x2
+
+#define AV1D_MPP_REFINFO_TBL_ACCCONFIG 0x3442
+#define AV1D_MPP_REFINFO_DATA 0x3443
+#define AV1D_MPP_REF_SCALE_ENBL 0x3441
+#define HEVC_MPRED_CTRL4 0x324c
+#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_MV_INFO 0x310d
+#define HEVC_QP_INFO 0x3137
+#define HEVC_SKIP_INFO 0x3136
+
+#define HEVC_CM_BODY_LENGTH2 0x3663
+#define HEVC_CM_HEADER_OFFSET2 0x3664
+#define HEVC_CM_HEADER_LENGTH2 0x3665
+
+#define HEVC_CM_HEADER_START_ADDR2 0x364a
+#define HEVC_SAO_MMU_DMA_CTRL2 0x364c
+#define HEVC_SAO_MMU_VH0_ADDR2 0x364d
+#define HEVC_SAO_MMU_VH1_ADDR2 0x364e
+#define HEVC_SAO_MMU_STATUS2 0x3650
+#define HEVC_DW_VH0_ADDDR 0x365e
+#define HEVC_DW_VH1_ADDDR 0x365f
+
+#ifdef BUFMGR_ONLY_OLD_CHIP
+#undef AV1_SKIP_MODE_INFO
+#define AV1_SKIP_MODE_INFO HEVC_ASSIST_SCRATCH_B
+#endif
+
+
+#define AOM_AV1_DEC_IDLE 0
+#define AOM_AV1_DEC_FRAME_HEADER 1
+#define AOM_AV1_DEC_TILE_END 2
+#define AOM_AV1_DEC_TG_END 3
+#define AOM_AV1_DEC_LCU_END 4
+#define AOM_AV1_DECODE_SLICE 5
+#define AOM_AV1_SEARCH_HEAD 6
+#define AOM_AV1_DUMP_LMEM 7
+#define AOM_AV1_FGS_PARAM_CONT 8
+#define AOM_AV1_DISCARD_NAL 0x10
+
+/*status*/
+#define AOM_AV1_DEC_PIC_END 0xe0
+/*AOM_AV1_FGS_PARA:
+Bit[11] - 0 Read, 1 - Write
+Bit[10:8] - film_grain_params_ref_idx, For Write request
+*/
+#define AOM_AV1_FGS_PARAM 0xe1
+#define AOM_AV1_DEC_PIC_END_PRE 0xe2
+#define AOM_AV1_HEAD_PARSER_DONE 0xf0
+#define AOM_AV1_HEAD_SEARCH_DONE 0xf1
+#define AOM_AV1_SEQ_HEAD_PARSER_DONE 0xf2
+#define AOM_AV1_FRAME_HEAD_PARSER_DONE 0xf3
+#define AOM_AV1_FRAME_PARSER_DONE 0xf4
+#define AOM_AV1_REDUNDANT_FRAME_HEAD_PARSER_DONE 0xf5
+#define HEVC_ACTION_DONE 0xff
+
+#define AOM_DECODE_BUFEMPTY 0x20
+#define AOM_DECODE_TIMEOUT 0x21
+#define AOM_SEARCH_BUFEMPTY 0x22
+#define AOM_DECODE_OVER_SIZE 0x23
+#define AOM_EOS 0x24
+#define AOM_NAL_DECODE_DONE 0x25
+
+
+#define VF_POOL_SIZE 32
+
+#undef pr_info
+#define pr_info printk
+
+#define DECODE_MODE_SINGLE ((0x80 << 24) | 0)
+#define DECODE_MODE_MULTI_STREAMBASE ((0x80 << 24) | 1)
+#define DECODE_MODE_MULTI_FRAMEBASE ((0x80 << 24) | 2)
+#define DECODE_MODE_SINGLE_LOW_LATENCY ((0x80 << 24) | 3)
+#define DECODE_MODE_MULTI_FRAMEBASE_NOHEAD ((0x80 << 24) | 4)
+
+#define AV1_TRIGGER_FRAME_DONE 0x100
+#define AV1_TRIGGER_FRAME_ENABLE 0x200
+
+#define MV_MEM_UNIT 0x240
+/*---------------------------------------------------
+ * 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
+
+/*#define HEVC_PIC_STRUCT_SUPPORT*/
+/* to remove, fix build error */
+
+/*#define CODEC_MM_FLAGS_FOR_VDECODER 0*/
+
+#define MULTI_INSTANCE_SUPPORT
+#define SUPPORT_10BIT
+/* #define ERROR_HANDLE_DEBUG */
+
+#ifndef STAT_KTHREAD
+#define STAT_KTHREAD 0x40
+#endif
+
+#ifdef MULTI_INSTANCE_SUPPORT
+#define MAX_DECODE_INSTANCE_NUM 9
+
+#ifdef DEBUG_USE_VP9_DEVICE_NAME
+#define MULTI_DRIVER_NAME "ammvdec_vp9"
+#else
+#define MULTI_DRIVER_NAME "ammvdec_av1"
+#endif
+
+#define AUX_BUF_ALIGN(adr) ((adr + 0xf) & (~0xf))
+#ifdef DEBUG_UCODE_LOG
+static u32 prefix_aux_buf_size;
+static u32 suffix_aux_buf_size;
+#else
+static u32 prefix_aux_buf_size = (16 * 1024);
+static u32 suffix_aux_buf_size;
+#endif
+#if (defined DEBUG_UCODE_LOG) || (defined DEBUG_CMD)
+//#define UCODE_LOG_BUF_SIZE (16 * 1024)
+#define UCODE_LOG_BUF_SIZE (1024 * 1024)
+#endif
+static unsigned int max_decode_instance_num
+ = MAX_DECODE_INSTANCE_NUM;
+static unsigned int decode_frame_count[MAX_DECODE_INSTANCE_NUM];
+static unsigned int display_frame_count[MAX_DECODE_INSTANCE_NUM];
+static unsigned int max_process_time[MAX_DECODE_INSTANCE_NUM];
+static unsigned int run_count[MAX_DECODE_INSTANCE_NUM];
+static unsigned int input_empty[MAX_DECODE_INSTANCE_NUM];
+static unsigned int not_run_ready[MAX_DECODE_INSTANCE_NUM];
+#ifdef AOM_AV1_MMU_DW
+static unsigned int dw_mmu_enable[MAX_DECODE_INSTANCE_NUM];
+#endif
+/* disable timeout for av1 mosaic JIRA SWPL-23326 */
+static u32 decode_timeout_val = 0;
+static int start_decode_buf_level = 0x8000;
+//static u32 work_buf_size;
+static u32 force_pts_unstable;
+static u32 mv_buf_margin = REF_FRAMES;
+static u32 mv_buf_dynamic_alloc;
+static u32 force_max_one_mv_buffer_size;
+
+/* 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
+ * 0x10, double write only
+ * 0x20, mmu double write
+ * 0x100, if > 1080p,use mode 4,else use mode 1;
+ * 0x200, if > 1080p,use mode 2,else use mode 1;
+ * 0x300, if > 720p, use mode 4, else use mode 1;
+ */
+static u32 double_write_mode;
+
+#ifdef DEBUG_USE_VP9_DEVICE_NAME
+#define DRIVER_NAME "amvdec_vp9"
+#define DRIVER_HEADER_NAME "amvdec_vp9_header"
+#else
+#define DRIVER_NAME "amvdec_av1"
+#define DRIVER_HEADER_NAME "amvdec_av1_header"
+#endif
+
+#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 PTS2DUR(x) ((x)*96/90)
+
+
+struct AV1HW_s;
+static int vav1_vf_states(struct vframe_states *states, void *);
+static struct vframe_s *vav1_vf_peek(void *);
+static struct vframe_s *vav1_vf_get(void *);
+static void vav1_vf_put(struct vframe_s *, void *);
+static int vav1_event_cb(int type, void *data, void *private_data);
+
+static int vav1_stop(struct AV1HW_s *hw);
+#ifdef MULTI_INSTANCE_SUPPORT
+static s32 vav1_init(struct vdec_s *vdec);
+#else
+static s32 vav1_init(struct AV1HW_s *hw);
+#endif
+static void vav1_prot_init(struct AV1HW_s *hw, u32 mask);
+static int vav1_local_init(struct AV1HW_s *hw);
+static void vav1_put_timer_func(unsigned long arg);
+static void dump_data(struct AV1HW_s *hw, int size);
+static unsigned int get_data_check_sum
+ (struct AV1HW_s *hw, int size);
+static void dump_pic_list(struct AV1HW_s *hw);
+static int vav1_mmu_map_alloc(struct AV1HW_s *hw);
+static void vav1_mmu_map_free(struct AV1HW_s *hw);
+static int av1_alloc_mmu(
+ struct AV1HW_s *hw,
+ int cur_buf_idx,
+ int pic_width,
+ int pic_height,
+ unsigned short bit_depth,
+ unsigned int *mmu_index_adr);
+
+#ifdef DEBUG_USE_VP9_DEVICE_NAME
+static const char vav1_dec_id[] = "vvp9-dev";
+
+#define PROVIDER_NAME "decoder.vp9"
+#define MULTI_INSTANCE_PROVIDER_NAME "vdec.vp9"
+#else
+static const char vav1_dec_id[] = "vav1-dev";
+
+#define PROVIDER_NAME "decoder.av1"
+#define MULTI_INSTANCE_PROVIDER_NAME "vdec.av1"
+#endif
+#define DV_PROVIDER_NAME "dvbldec"
+
+static const struct vframe_operations_s vav1_vf_provider = {
+ .peek = vav1_vf_peek,
+ .get = vav1_vf_get,
+ .put = vav1_vf_put,
+ .event_cb = vav1_event_cb,
+ .vf_states = vav1_vf_states,
+};
+
+static struct vframe_provider_s vav1_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 on_no_keyframe_skiped;
+static u32 without_display_mode;
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+static u32 force_dv_enable;
+#endif
+
+#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 HEVC_ASSIST_MMU_MAP_ADDR 0x3009
+
+
+/*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;
+ ulong v4l_ref_buf_addr;
+ ulong header_addr;
+ u32 header_size;
+ u32 luma_size;
+ ulong chroma_addr;
+ u32 chroma_size;
+} /*BUF_t */;
+
+struct MVBUF_s {
+ unsigned long start_adr;
+ unsigned int size;
+ int used_flag;
+} /*MVBUF_t */;
+
+/*#define TEST_WR_PTR_INC*/
+/*#define WR_PTR_INC_NUM 128*/
+#define WR_PTR_INC_NUM 1
+
+//#define SIMULATION
+#define DOS_PROJECT
+#undef MEMORY_MAP_IN_REAL_CHIP
+
+/*#undef DOS_PROJECT*/
+/*#define MEMORY_MAP_IN_REAL_CHIP*/
+
+/*#define CONFIG_HEVC_CLK_FORCED_ON*/
+/*#define ENABLE_SWAP_TEST*/
+#ifndef BUFMGR_ONLY_OLD_CHIP
+#define MCRCC_ENABLE
+#endif
+
+#ifdef AV1_10B_NV21
+#else
+#define LOSLESS_COMPRESS_MODE
+#endif
+
+typedef unsigned int u32;
+typedef unsigned short u16;
+
+
+static u32 get_picture_qos;
+
+static u32 debug;
+
+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;
+
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+static u32 dv_toggle_prov_name;
+#endif
+
+static u32 run_ready_min_buf_num = 2;
+#ifdef DEBUG_CRC_ERROR
+/*
+ bit[4] fill zero in header before starting
+ bit[5] dump mmu header always
+
+ bit[6] dump mv buffer always
+
+ bit[8] delay after decoding
+ bit[31~16] delayed mseconds
+*/
+static u32 crc_debug_flag;
+#endif
+#ifdef DEBUG_CMD
+static u32 header_dump_size = 0x10000;
+static u32 debug_cmd_wait_count;
+static u32 debug_cmd_wait_type;
+#endif
+#
+#define DEBUG_REG
+#ifdef DEBUG_REG
+void AV1_WRITE_VREG_DBG2(unsigned int adr, unsigned int val, int line)
+{
+ if (debug & AV1_DEBUG_REG)
+ pr_info("%d:%s(%x, %x)\n", line, __func__, adr, val);
+ if (adr != 0)
+ WRITE_VREG(adr, val);
+}
+
+#undef WRITE_VREG
+#define WRITE_VREG(a,v) AV1_WRITE_VREG_DBG2(a,v,__LINE__)
+#endif
+
+#define FRAME_CNT_WINDOW_SIZE 59
+#define RATE_CORRECTION_THRESHOLD 5
+/**************************************************
+
+AV1 buffer management start
+
+***************************************************/
+#define MMU_COMPRESS_HEADER_SIZE_1080P 0x10000
+#define MMU_COMPRESS_HEADER_SIZE_4K 0x48000
+#define MMU_COMPRESS_HEADER_SIZE_8K 0x120000
+
+//#define MMU_COMPRESS_HEADER_SIZE 0x48000
+//#define MAX_ONE_MV_BUFFER_SIZE 0x260000
+//#define MAX_ONE_MV_BUFFER_SIZE 0x130000
+
+#define MAX_ONE_MV_BUFFER_SIZE_1080P 0x20400
+#define MAX_ONE_MV_BUFFER_SIZE_4K 0x91400
+#define MAX_ONE_MV_BUFFER_SIZE_8K 0x244800
+/*to support tm2revb and sc2*/
+#define MAX_ONE_MV_BUFFER_SIZE_1080P_TM2REVB 0x26400
+#define MAX_ONE_MV_BUFFER_SIZE_4K_TM2REVB 0xac400
+#define MAX_ONE_MV_BUFFER_SIZE_8K_TM2REVB 0x2b0800
+
+static int vav1_mmu_compress_header_size(struct AV1HW_s *hw);
+
+//#define MMU_COMPRESS_HEADER_SIZE 0x48000
+//#define MMU_COMPRESS_HEADER_SIZE_DW MMU_COMPRESS_HEADER_SIZE
+//#define MMU_COMPRESS_8K_HEADER_SIZE (0x48000*4)
+#define MAX_SIZE_8K (8192 * 4608)
+#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))
+
+#define INVALID_IDX -1 /* Invalid buffer index.*/
+
+
+/*4 scratch frames for the new frames to support a maximum of 4 cores decoding
+ *in parallel, 3 for scaled references on the encoder.
+ *TODO(hkuang): Add ondemand frame buffers instead of hardcoding the number
+ * // of framebuffers.
+ *TODO(jkoleszar): These 3 extra references could probably come from the
+ *normal reference pool.
+ */
+//#define FRAME_BUFFERS (REF_FRAMES + 16)
+//#define REF_FRAMES_4K (6)
+#define REF_FRAMES_4K REF_FRAMES
+
+#ifdef USE_SPEC_BUF_FOR_MMU_HEAD
+#define HEADER_FRAME_BUFFERS (0)
+#elif (defined AOM_AV1_MMU_DW)
+#define HEADER_FRAME_BUFFERS (2 * FRAME_BUFFERS)
+#else
+#define HEADER_FRAME_BUFFERS (FRAME_BUFFERS)
+#endif
+#define MAX_BUF_NUM (FRAME_BUFFERS)
+#define MV_BUFFER_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)
+#define VF_BUFFER_IDX(n) (n)
+#define HEADER_BUFFER_IDX(n) (FRAME_BUFFERS + n)
+#define WORK_SPACE_BUF_ID (FRAME_BUFFERS + HEADER_FRAME_BUFFERS)
+#else
+#define MAX_BMMU_BUFFER_NUM \
+ (FRAME_BUFFERS + HEADER_FRAME_BUFFERS + MV_BUFFER_NUM + 1)
+#define VF_BUFFER_IDX(n) (n)
+#define HEADER_BUFFER_IDX(n) (FRAME_BUFFERS + n)
+#define MV_BUFFER_IDX(n) (FRAME_BUFFERS + HEADER_FRAME_BUFFERS + n)
+#define WORK_SPACE_BUF_ID \
+ (FRAME_BUFFERS + HEADER_FRAME_BUFFERS + MV_BUFFER_NUM)
+#endif
+#ifdef AOM_AV1_MMU_DW
+#define DW_HEADER_BUFFER_IDX(n) (HEADER_BUFFER_IDX(HEADER_FRAME_BUFFERS/2) + n)
+#endif
+
+
+static void set_canvas(struct AV1HW_s *hw,
+ struct PIC_BUFFER_CONFIG_s *pic_config);
+
+static void fill_frame_info(struct AV1HW_s *hw,
+ struct PIC_BUFFER_CONFIG_s *frame,
+ unsigned int framesize,
+ unsigned int pts);
+
+
+static int compute_losless_comp_body_size(int width, int height,
+ uint8_t is_bit_depth_10);
+
+
+
+#ifdef MULTI_INSTANCE_SUPPORT
+#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
+
+#define DEC_S1_RESULT_NONE 0
+#define DEC_S1_RESULT_DONE 1
+#define DEC_S1_RESULT_FORCE_EXIT 2
+#define DEC_S1_RESULT_TEST_TRIGGER_DONE 0xf0
+
+#ifdef FB_DECODING_TEST_SCHEDULE
+#define TEST_SET_NONE 0
+#define TEST_SET_PIC_DONE 1
+#define TEST_SET_S2_DONE 2
+#endif
+
+static void av1_work(struct work_struct *work);
+#endif
+
+#ifdef DUMP_FILMGRAIN
+u32 fg_dump_index = 0xff;
+#endif
+
+#ifdef AOM_AV1_DBLK_INIT
+struct loop_filter_info_n_s;
+struct loopfilter;
+struct segmentation_lf;
+#endif
+struct AV1HW_s {
+ AV1Decoder *pbi;
+ union param_u aom_param;
+ unsigned char frame_decoded;
+ unsigned char one_compressed_data_done;
+ unsigned char new_compressed_data;
+#if 1
+/*def CHECK_OBU_REDUNDANT_FRAME_HEADER*/
+ int obu_frame_frame_head_come_after_tile;
+#endif
+ unsigned char index;
+
+ 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;
+ struct work_struct set_clk_work;
+ u32 start_shift_bytes;
+ u32 data_size;
+
+ 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 save_buffer_mode;
+
+ int double_write_mode;
+
+ long used_4k_num;
+
+ unsigned char m_ins_flag;
+ char *provider_name;
+ union param_u param;
+ int frame_count;
+ int pic_count;
+ u32 stat;
+ struct timer_list timer;
+ u32 frame_dur;
+ u32 frame_ar;
+ int fatal_error;
+ uint8_t init_flag;
+ uint8_t config_next_ref_info_flag;
+ uint8_t first_sc_checked;
+ uint8_t process_busy;
+#define PROC_STATE_INIT 0
+#define PROC_STATE_DECODESLICE 1
+#define PROC_STATE_SENDAGAIN 2
+ uint8_t process_state;
+ u32 ucode_pause_pos;
+
+ int show_frame_num;
+ struct buff_s mc_buf_spec;
+ struct dec_sysinfo vav1_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 DUMP_FILMGRAIN
+ dma_addr_t fg_phy_addr;
+ unsigned char *fg_ptr;
+ void *fg_addr;
+#endif
+ u32 fgs_valid;
+
+ u8 aux_data_dirty;
+ u32 prefix_aux_size;
+ u32 suffix_aux_size;
+ void *aux_addr;
+ dma_addr_t aux_phy_addr;
+ char *dv_data_buf;
+ int dv_data_size;
+#if (defined DEBUG_UCODE_LOG) || (defined DEBUG_CMD)
+ void *ucode_log_addr;
+ dma_addr_t ucode_log_phy_addr;
+#endif
+
+ void *prob_buffer_addr;
+ void *count_buffer_addr;
+ dma_addr_t prob_buffer_phy_addr;
+ dma_addr_t count_buffer_phy_addr;
+
+ void *frame_mmu_map_addr;
+ dma_addr_t frame_mmu_map_phy_addr;
+#ifdef AOM_AV1_MMU_DW
+ 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[MV_BUFFER_NUM];
+ u32 used_buf_num;
+ u32 mv_buf_margin;
+ 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;
+ int pic_num;
+ int lcu_size_log2;
+ unsigned int losless_comp_body_size;
+
+ u32 video_signal_type;
+
+ u32 pts_unstable;
+ bool av1_first_pts_ready;
+ bool dur_recalc_flag;
+ u8 first_pts_index;
+ u32 frame_mode_pts_save[FRAME_BUFFERS];
+ u64 frame_mode_pts64_save[FRAME_BUFFERS];
+ u64 frame_mode_timestamp_save[FRAME_BUFFERS];
+ u64 timestamp_duration;
+
+ int last_pts;
+ u64 last_pts_us64;
+ u64 last_timestamp;
+ u64 shift_byte_count;
+
+ u32 shift_byte_count_lo;
+ u32 shift_byte_count_hi;
+ int pts_mode_switching_count;
+ int pts_mode_recovery_count;
+ bool get_frame_dur;
+
+ u32 saved_resolution;
+ /**/
+ struct AV1_Common_s common;
+ struct RefCntBuffer_s *cur_buf;
+ int refresh_frame_flags;
+ uint8_t need_resync;
+ uint8_t hold_ref_buf;
+ uint8_t ready_for_new_data;
+ struct BufferPool_s av1_buffer_pool;
+
+ struct BuffInfo_s *work_space_buf;
+
+ struct buff_s *mc_buf;
+
+ unsigned int frame_width;
+ unsigned int frame_height;
+
+ unsigned short *rpm_ptr;
+ int init_pic_w;
+ int init_pic_h;
+ int lcu_total;
+
+ int current_lcu_size;
+
+ int slice_type;
+
+ int skip_flag;
+ int decode_idx;
+ int result_done_count;
+ uint8_t has_keyframe;
+ uint8_t has_sequence;
+ uint8_t wait_buf;
+ uint8_t error_flag;
+
+ /* bit 0, for decoding; bit 1, for displaying */
+ uint8_t ignore_bufmgr_error;
+ int PB_skip_mode;
+ int PB_skip_count_after_decoding;
+ /*hw*/
+
+ /**/
+ struct vdec_info *gvs;
+
+ u32 pre_stream_offset;
+
+ unsigned int dec_status;
+ u32 last_put_idx;
+ int new_frame_displayed;
+ void *mmu_box;
+ void *bmmu_box;
+ int mmu_enable;
+#ifdef AOM_AV1_MMU_DW
+ void *mmu_box_dw;
+ int dw_mmu_enable;
+#endif
+ struct vframe_master_display_colour_s vf_dp;
+ struct firmware_s *fw;
+ int max_pic_w;
+ int max_pic_h;
+ int buffer_spec_index;
+ int32_t max_one_mv_buffer_size;
+
+ int need_cache_size;
+ u64 sc_start_time;
+ bool postproc_done;
+ int low_latency_flag;
+ bool no_head;
+ bool pic_list_init_done;
+ bool pic_list_init_done2;
+ bool is_used_v4l;
+ void *v4l2_ctx;
+ bool v4l_params_parsed;
+ int frameinfo_enable;
+ struct vframe_qos_s vframe_qos;
+
+#ifdef AOM_AV1_DBLK_INIT
+ /*
+ * malloc may not work in real chip, please allocate memory for the following structures
+ */
+ struct loop_filter_info_n_s *lfi;
+ struct loopfilter *lf;
+ struct segmentation_lf *seg_4lf;
+#endif
+ u32 mem_map_mode;
+ u32 dynamic_buf_num_margin;
+ struct vframe_s vframe_dummy;
+ u32 res_ch_flag;
+ int buffer_wrap[FRAME_BUFFERS];
+ int sidebind_type;
+ int sidebind_channel_id;
+ char vdec_name[32];
+ char pts_name[32];
+ char new_q_name[32];
+ char disp_q_name[32];
+};
+static void av1_dump_state(struct vdec_s *vdec);
+
+int av1_print(struct AV1HW_s *hw,
+ int flag, const char *fmt, ...)
+{
+#define HEVC_PRINT_BUF 256
+ unsigned char buf[HEVC_PRINT_BUF];
+ int len = 0;
+
+ if (hw == NULL ||
+ (flag == 0) ||
+ (debug & flag)) {
+ va_list args;
+
+ va_start(args, fmt);
+ if (hw)
+ len = sprintf(buf, "[%d]", hw->index);
+ vsnprintf(buf + len, HEVC_PRINT_BUF - len, fmt, args);
+ pr_info("%s", buf);
+ va_end(args);
+ }
+ return 0;
+}
+
+unsigned char av1_is_debug(int flag)
+{
+ if ((flag == 0) || (debug & flag))
+ return 1;
+
+ return 0;
+}
+
+int av1_print2(int flag, const char *fmt, ...)
+{
+ unsigned char buf[HEVC_PRINT_BUF];
+ int len = 0;
+
+ if ((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;
+
+}
+
+static int is_oversize(int w, int h)
+{
+ int max = (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1)?
+ MAX_SIZE_8K : MAX_SIZE_4K;
+
+ if (w <= 0 || h <= 0)
+ return true;
+
+ if (h != 0 && (w > max / h))
+ return true;
+
+ return false;
+}
+
+static int v4l_alloc_and_config_pic(struct AV1HW_s *hw,
+ struct PIC_BUFFER_CONFIG_s *pic);
+
+static inline bool close_to(int a, int b, int m)
+{
+ return (abs(a - b) < m) ? true : false;
+}
+
+#ifdef MULTI_INSTANCE_SUPPORT
+static int av1_print_cont(struct AV1HW_s *hw,
+ int flag, const char *fmt, ...)
+{
+ unsigned char buf[HEVC_PRINT_BUF];
+ int len = 0;
+
+ if (hw == 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;
+}
+
+static void trigger_schedule(struct AV1HW_s *hw)
+{
+ 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 reset_process_time(struct AV1HW_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[hw->index])
+ max_process_time[hw->index] = process_time;
+ }
+}
+
+static void start_process_time(struct AV1HW_s *hw)
+{
+ hw->start_process_time = jiffies;
+ hw->decode_timeout_count = 0;
+ hw->last_lcu_idx = 0;
+}
+
+static void timeout_process(struct AV1HW_s *hw)
+{
+ reset_process_time(hw);
+ if (hw->process_busy) {
+ av1_print(hw,
+ 0, "%s decoder timeout but process_busy\n", __func__);
+ if (debug)
+ av1_print(hw, 0, "debug disable timeout notify\n");
+ return;
+ }
+ hw->timeout_num++;
+ amhevc_stop();
+ av1_print(hw,
+ 0, "%s decoder timeout\n", __func__);
+
+ hw->dec_result = DEC_RESULT_DONE;
+ vdec_schedule_work(&hw->work);
+}
+
+static u32 get_valid_double_write_mode(struct AV1HW_s *hw)
+{
+ u32 dw = ((double_write_mode & 0x80000000) == 0) ?
+ hw->double_write_mode :
+ (double_write_mode & 0x7fffffff);
+ if ((dw & 0x20) &&
+ ((dw & 0xf) == 2 || (dw & 0xf) == 3)) {
+ pr_info("MMU doueble write 1:4 not supported !!!\n");
+ dw = 0;
+ }
+ return dw;
+}
+
+static int v4l_parser_get_double_write_mode(struct AV1HW_s *hw)
+{
+ u32 valid_dw_mode = get_valid_double_write_mode(hw);
+ u32 dw;
+ int w, h;
+
+ /* mask for supporting double write value bigger than 0x100 */
+ if (valid_dw_mode & 0xffffff00) {
+ w = hw->frame_width;
+ h = hw->frame_height;
+
+ dw = 0x1; /*1:1*/
+ switch (valid_dw_mode) {
+ case 0x100:
+ if (w > 1920 && h > 1088)
+ dw = 0x4; /*1:2*/
+ break;
+ case 0x200:
+ if (w > 1920 && h > 1088)
+ dw = 0x2; /*1:4*/
+ break;
+ case 0x300:
+ if (w > 1280 && h > 720)
+ dw = 0x4; /*1:2*/
+ break;
+ default:
+ break;
+ }
+ return dw;
+ }
+
+ return valid_dw_mode;
+}
+
+static int get_double_write_mode(struct AV1HW_s *hw)
+{
+ u32 valid_dw_mode = get_valid_double_write_mode(hw);
+ u32 dw;
+ int w, h;
+ struct AV1_Common_s *cm = &hw->common;
+ struct PIC_BUFFER_CONFIG_s *cur_pic_config;
+
+ if (!cm->cur_frame)
+ return 1;/*no valid frame,*/
+ cur_pic_config = &cm->cur_frame->buf;
+ w = cur_pic_config->y_crop_width;
+ h = cur_pic_config->y_crop_height;
+
+ dw = 0x1; /*1:1*/
+ switch (valid_dw_mode) {
+ case 0x100:
+ if (w > 1920 && h > 1088)
+ dw = 0x4; /*1:2*/
+ break;
+ case 0x200:
+ if (w > 1920 && h > 1088)
+ dw = 0x2; /*1:4*/
+ break;
+ case 0x300:
+ if (w > 1280 && h > 720)
+ dw = 0x4; /*1:2*/
+ break;
+ default:
+ dw = valid_dw_mode;
+ break;
+ }
+ return dw;
+}
+
+/* for double write buf alloc */
+static int get_double_write_mode_init(struct AV1HW_s *hw)
+{
+ u32 valid_dw_mode = get_valid_double_write_mode(hw);
+ u32 dw;
+ int w = hw->init_pic_w;
+ int h = hw->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;
+}
+#endif
+
+static int get_double_write_ratio(struct AV1HW_s *hw,
+ int dw_mode)
+{
+ int ratio = 1;
+ int dw_mode_ratio = dw_mode & 0xf;
+ if ((dw_mode_ratio == 2) ||
+ (dw_mode_ratio == 3))
+ ratio = 4;
+ else if (dw_mode_ratio == 4)
+ ratio = 2;
+ return ratio;
+}
+
+/* return page number */
+static int av1_mmu_page_num(struct AV1HW_s *hw,
+ int w, int h, int save_mode)
+{
+ int picture_size;
+ int cur_mmu_4k_number, max_frame_num;
+
+ picture_size = compute_losless_comp_body_size(w, h, save_mode);
+ cur_mmu_4k_number = ((picture_size + (PAGE_SIZE - 1)) >> PAGE_SHIFT);
+
+ 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, w, h);
+ return -1;
+ }
+
+ return cur_mmu_4k_number;
+}
+
+//#define MAX_4K_NUM 0x1200
+int av1_alloc_mmu(
+ struct AV1HW_s *hw,
+ int cur_buf_idx,
+ int pic_width,
+ int pic_height,
+ unsigned short bit_depth,
+ unsigned int *mmu_index_adr)
+{
+ int ret = 0;
+ int bit_depth_10 = (bit_depth == AOM_BITS_10);
+ int cur_mmu_4k_number;
+
+ if (!hw->mmu_box) {
+ pr_err("error no mmu box!\n");
+ return -1;
+ }
+
+ if (hw->double_write_mode & 0x10)
+ return 0;
+
+ if (bit_depth >= AOM_BITS_12) {
+ hw->fatal_error = DECODER_FATAL_ERROR_SIZE_OVERFLOW;
+ pr_err("fatal_error, un support bit depth 12!\n\n");
+ return -1;
+ }
+
+ cur_mmu_4k_number = av1_mmu_page_num(hw,
+ pic_width,
+ pic_height,
+ bit_depth_10);
+ if (cur_mmu_4k_number < 0)
+ return -1;
+
+ ret = decoder_mmu_box_alloc_idx(
+ hw->mmu_box,
+ hw->buffer_wrap[cur_buf_idx],
+ cur_mmu_4k_number,
+ mmu_index_adr);
+
+ return ret;
+}
+
+#ifdef AOM_AV1_MMU_DW
+static int compute_losless_comp_body_size_dw(int width, int height,
+ uint8_t is_bit_depth_10);
+
+int av1_alloc_mmu_dw(
+ struct AV1HW_s *hw,
+ int cur_buf_idx,
+ int pic_width,
+ int pic_height,
+ unsigned short bit_depth,
+ unsigned int *mmu_index_adr)
+{
+ int ret = 0;
+ int bit_depth_10 = (bit_depth == AOM_BITS_10);
+ int picture_size;
+ int cur_mmu_4k_number, max_frame_num;
+ if (!hw->mmu_box_dw) {
+ pr_err("error no mmu box!\n");
+ return -1;
+ }
+ if (hw->double_write_mode & 0x10)
+ return 0;
+ if (bit_depth >= AOM_BITS_12) {
+ hw->fatal_error = DECODER_FATAL_ERROR_SIZE_OVERFLOW;
+ pr_err("fatal_error, un support bit depth 12!\n\n");
+ return -1;
+ }
+ picture_size = compute_losless_comp_body_size_dw(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;
+ }
+ ret = decoder_mmu_box_alloc_idx(
+ hw->mmu_box_dw,
+ hw->buffer_wrap[cur_buf_idx],
+ cur_mmu_4k_number,
+ mmu_index_adr);
+ return ret;
+}
+#endif
+
+#ifndef MV_USE_FIXED_BUF
+static void dealloc_mv_bufs(struct AV1HW_s *hw)
+{
+ int i;
+ for (i = 0; i < MV_BUFFER_NUM; i++) {
+ if (hw->m_mv_BUF[i].start_adr) {
+ if (debug)
+ pr_info(
+ "dealloc mv buf(%d) adr %ld size 0x%x used_flag %d\n",
+ i, hw->m_mv_BUF[i].start_adr,
+ hw->m_mv_BUF[i].size,
+ hw->m_mv_BUF[i].used_flag);
+ decoder_bmmu_box_free_idx(
+ hw->bmmu_box,
+ MV_BUFFER_IDX(i));
+ hw->m_mv_BUF[i].start_adr = 0;
+ hw->m_mv_BUF[i].size = 0;
+ hw->m_mv_BUF[i].used_flag = 0;
+ }
+ }
+}
+
+static int alloc_mv_buf(struct AV1HW_s *hw,
+ int i, int size)
+{
+ int ret = 0;
+ if (decoder_bmmu_box_alloc_buf_phy
+ (hw->bmmu_box,
+ MV_BUFFER_IDX(i), size,
+ DRIVER_NAME,
+ &hw->m_mv_BUF[i].start_adr) < 0) {
+ hw->m_mv_BUF[i].start_adr = 0;
+ ret = -1;
+ } else {
+ hw->m_mv_BUF[i].size = size;
+ hw->m_mv_BUF[i].used_flag = 0;
+ ret = 0;
+ if (debug) {
+ pr_info(
+ "MV Buffer %d: start_adr %p size %x\n",
+ i,
+ (void *)hw->m_mv_BUF[i].start_adr,
+ hw->m_mv_BUF[i].size);
+ }
+ }
+ return ret;
+}
+
+static int cal_mv_buf_size(struct AV1HW_s *hw, int pic_width, int pic_height)
+{
+ unsigned lcu_size = hw->current_lcu_size;
+ int extended_pic_width = (pic_width + lcu_size -1)
+ & (~(lcu_size - 1));
+ int extended_pic_height = (pic_height + lcu_size -1)
+ & (~(lcu_size - 1));
+
+ int lcu_x_num = extended_pic_width / lcu_size;
+ int lcu_y_num = extended_pic_height / lcu_size;
+ int size_a, size_b, size;
+
+ if (get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_SC2)
+ /*tm2revb and sc2*/
+ size_a = lcu_x_num * lcu_y_num * 16 *
+ ((lcu_size == 64) ? 16 : 64);
+ else
+ size_a = lcu_x_num * lcu_y_num * 16 *
+ ((lcu_size == 64) ? 19 : 76);
+
+ size_b = lcu_x_num * ((lcu_y_num >> 3) +
+ (lcu_y_num & 0x7)) * 16;
+ size = ((size_a + size_b) + 0xffff) & (~0xffff);
+
+ if (debug & AOM_DEBUG_USE_FIXED_MV_BUF_SIZE)
+ size = hw->max_one_mv_buffer_size;
+ if (force_max_one_mv_buffer_size)
+ size = force_max_one_mv_buffer_size;
+ return size;
+}
+
+static int init_mv_buf_list(struct AV1HW_s *hw)
+{
+ int i;
+ int ret = 0;
+ int count = MV_BUFFER_NUM;
+ int pic_width = hw->init_pic_w;
+ int pic_height = hw->init_pic_h;
+ int size = cal_mv_buf_size(hw, pic_width, pic_height);
+
+ if (mv_buf_dynamic_alloc)
+ return 0;
+#if 0
+ if (mv_buf_margin > 0)
+ count = REF_FRAMES + mv_buf_margin;
+ if (hw->init_pic_w > 2048 && hw->init_pic_h > 1088)
+ count = REF_FRAMES_4K + mv_buf_margin;
+#else
+ if (debug)
+ pr_info("%s, calculated mv size 0x%x\n",
+ __func__, size);
+
+ if ((hw->is_used_v4l) && !IS_8K_SIZE(pic_width, pic_height)) {
+ if (vdec_is_support_4k())
+ size = 0xb0000;
+ else
+ size = 0x30000;
+ }
+
+ if (hw->init_pic_w > 4096 && hw->init_pic_h > 2048)
+ count = REF_FRAMES_4K + hw->mv_buf_margin;
+ else if (hw->init_pic_w > 2048 && hw->init_pic_h > 1088)
+ count = REF_FRAMES_4K + hw->mv_buf_margin;
+ else
+ count = REF_FRAMES + hw->mv_buf_margin;
+
+#endif
+ if (debug) {
+ pr_info("%s w:%d, h:%d, count: %d, size 0x%x\n",
+ __func__, hw->init_pic_w, hw->init_pic_h,
+ count, size);
+ }
+
+ for (i = 0;
+ i < count && i < MV_BUFFER_NUM; i++) {
+ if (alloc_mv_buf(hw, i, size) < 0) {
+ ret = -1;
+ break;
+ }
+ }
+ return ret;
+}
+
+static int get_mv_buf(struct AV1HW_s *hw,
+ struct PIC_BUFFER_CONFIG_s *pic_config)
+{
+ int i;
+ int ret = -1;
+ if (mv_buf_dynamic_alloc) {
+ int size = cal_mv_buf_size(hw,
+ pic_config->y_crop_width, pic_config->y_crop_height);
+ for (i = 0; i < MV_BUFFER_NUM; i++) {
+ if (hw->m_mv_BUF[i].start_adr == 0) {
+ ret = i;
+ break;
+ }
+ }
+ if (i == MV_BUFFER_NUM) {
+ pr_info(
+ "%s: Error, mv buf MV_BUFFER_NUM is not enough\n",
+ __func__);
+ return ret;
+ }
+
+ if (alloc_mv_buf(hw, ret, size) >= 0) {
+ pic_config->mv_buf_index = ret;
+ pic_config->mpred_mv_wr_start_addr =
+ (hw->m_mv_BUF[ret].start_adr + 0xffff) &
+ (~0xffff);
+ } else {
+ pr_info(
+ "%s: Error, mv buf alloc fail\n",
+ __func__);
+ }
+ return ret;
+ }
+
+ for (i = 0; i < MV_BUFFER_NUM; i++) {
+ if (hw->m_mv_BUF[i].start_adr &&
+ hw->m_mv_BUF[i].used_flag == 0) {
+ hw->m_mv_BUF[i].used_flag = 1;
+ ret = i;
+ break;
+ }
+ }
+
+ if (ret >= 0) {
+ pic_config->mv_buf_index = ret;
+ pic_config->mpred_mv_wr_start_addr =
+ (hw->m_mv_BUF[ret].start_adr + 0xffff) &
+ (~0xffff);
+ if (debug & AV1_DEBUG_BUFMGR_MORE)
+ pr_info(
+ "%s => %d (%d) size 0x%x\n",
+ __func__, ret,
+ pic_config->mpred_mv_wr_start_addr,
+ hw->m_mv_BUF[ret].size);
+ } else {
+ pr_info(
+ "%s: Error, mv buf is not enough\n",
+ __func__);
+ }
+ return ret;
+}
+static void put_mv_buf(struct AV1HW_s *hw,
+ int *mv_buf_index)
+{
+ int i = *mv_buf_index;
+ if (i >= MV_BUFFER_NUM) {
+ if (debug & AV1_DEBUG_BUFMGR_MORE)
+ pr_info(
+ "%s: index %d beyond range\n",
+ __func__, i);
+ return;
+ }
+ if (mv_buf_dynamic_alloc) {
+ if (hw->m_mv_BUF[i].start_adr) {
+ if (debug)
+ pr_info(
+ "dealloc mv buf(%d) adr %ld size 0x%x used_flag %d\n",
+ i, hw->m_mv_BUF[i].start_adr,
+ hw->m_mv_BUF[i].size,
+ hw->m_mv_BUF[i].used_flag);
+ decoder_bmmu_box_free_idx(
+ hw->bmmu_box,
+ MV_BUFFER_IDX(i));
+ hw->m_mv_BUF[i].start_adr = 0;
+ hw->m_mv_BUF[i].size = 0;
+ hw->m_mv_BUF[i].used_flag = 0;
+ }
+ *mv_buf_index = -1;
+ return;
+ }
+
+ if (debug & AV1_DEBUG_BUFMGR_MORE)
+ pr_info(
+ "%s(%d): used_flag(%d)\n",
+ __func__, i,
+ hw->m_mv_BUF[i].used_flag);
+
+ *mv_buf_index = -1;
+ if (hw->m_mv_BUF[i].start_adr &&
+ hw->m_mv_BUF[i].used_flag)
+ hw->m_mv_BUF[i].used_flag = 0;
+}
+static void put_un_used_mv_bufs(struct AV1HW_s *hw)
+{
+ struct AV1_Common_s *const cm = &hw->common;
+ struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs;
+ int i;
+ for (i = 0; i < hw->used_buf_num; ++i) {
+ if ((frame_bufs[i].ref_count == 0) &&
+ (frame_bufs[i].buf.index != -1) &&
+ (frame_bufs[i].buf.mv_buf_index >= 0)
+ )
+ put_mv_buf(hw, &frame_bufs[i].buf.mv_buf_index);
+ }
+}
+#endif
+
+static void init_pic_list_hw(struct AV1HW_s *pbi);
+
+static int get_free_fb_idx(AV1_COMMON *cm)
+{
+ int i;
+ RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
+
+ for (i = 0; i < FRAME_BUFFERS; ++i) {
+ if (frame_bufs[i].ref_count == 0
+ && frame_bufs[i].buf.vf_ref == 0)
+ break;
+ }
+
+ return i;
+}
+
+static int v4l_get_free_fb(struct AV1HW_s *hw)
+{
+ struct AV1_Common_s *const cm = &hw->common;
+ struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs;
+ struct aml_vcodec_ctx * v4l = hw->v4l2_ctx;
+ struct v4l_buff_pool *pool = &v4l->cap_pool;
+ struct PIC_BUFFER_CONFIG_s *pic = NULL;
+ struct PIC_BUFFER_CONFIG_s *free_pic = NULL;
+ ulong flags;
+ int idx, i;
+
+ lock_buffer_pool(cm->buffer_pool, flags);
+
+ for (i = 0; i < pool->in; ++i) {
+ u32 state = (pool->seq[i] >> 16);
+ u32 index = (pool->seq[i] & 0xffff);
+
+ switch (state) {
+ case V4L_CAP_BUFF_IN_DEC:
+ pic = &frame_bufs[i].buf;
+ if ((frame_bufs[i].ref_count == 0) &&
+ (pic->vf_ref == 0) &&
+ (pic->index != -1) &&
+ pic->cma_alloc_addr) {
+ free_pic = pic;
+ }
+ break;
+ case V4L_CAP_BUFF_IN_M2M:
+ idx = get_free_fb_idx(cm);
+ pic = &frame_bufs[idx].buf;
+ pic->y_crop_width = hw->frame_width;
+ pic->y_crop_height = hw->frame_height;
+ hw->buffer_wrap[idx] = index;
+ if (!v4l_alloc_and_config_pic(hw, pic)) {
+ set_canvas(hw, pic);
+ init_pic_list_hw(hw);
+ free_pic = pic;
+ }
+ break;
+ default:
+ pr_err("v4l buffer state err %d.\n", state);
+ break;
+ }
+
+ if (free_pic) {
+ if (frame_bufs[i].buf.use_external_reference_buffers) {
+ // If this frame buffer's y_buffer, u_buffer, and v_buffer point to the
+ // external reference buffers. Restore the buffer pointers to point to the
+ // internally allocated memory.
+ PIC_BUFFER_CONFIG *ybf = &frame_bufs[i].buf;
+
+ ybf->y_buffer = ybf->store_buf_adr[0];
+ ybf->u_buffer = ybf->store_buf_adr[1];
+ ybf->v_buffer = ybf->store_buf_adr[2];
+ ybf->use_external_reference_buffers = 0;
+ }
+
+ frame_bufs[i].ref_count = 1;
+ break;
+ }
+ }
+
+ unlock_buffer_pool(cm->buffer_pool, flags);
+
+ return free_pic ? free_pic->index : INVALID_IDX;
+}
+
+static int get_free_fb(AV1_COMMON *cm) {
+ RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
+ unsigned long flags;
+ int i;
+
+ lock_buffer_pool(cm->buffer_pool, flags);
+ for (i = 0; i < FRAME_BUFFERS; ++i) {
+ if (frame_bufs[i].ref_count == 0
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ && frame_bufs[i].buf.vf_ref == 0
+#endif
+ )
+ break;
+ }
+
+ if (i != FRAME_BUFFERS) {
+ if (frame_bufs[i].buf.use_external_reference_buffers) {
+ // If this frame buffer's y_buffer, u_buffer, and v_buffer point to the
+ // external reference buffers. Restore the buffer pointers to point to the
+ // internally allocated memory.
+ PIC_BUFFER_CONFIG *ybf = &frame_bufs[i].buf;
+ ybf->y_buffer = ybf->store_buf_adr[0];
+ ybf->u_buffer = ybf->store_buf_adr[1];
+ ybf->v_buffer = ybf->store_buf_adr[2];
+ ybf->use_external_reference_buffers = 0;
+ }
+
+ frame_bufs[i].ref_count = 1;
+ } else {
+ // We should never run out of free buffers. If this assertion fails, there
+ // is a reference leak.
+ //assert(0 && "Ran out of free frame buffers. Likely a reference leak.");
+ // Reset i to be INVALID_IDX to indicate no free buffer found.
+ i = INVALID_IDX;
+ }
+
+ unlock_buffer_pool(cm->buffer_pool, flags);
+ return i;
+}
+
+int get_free_frame_buffer(struct AV1_Common_s *cm)
+{
+ struct AV1HW_s *hw = container_of(cm, struct AV1HW_s, common);
+
+ return hw->is_used_v4l ? v4l_get_free_fb(hw) : get_free_fb(cm);
+}
+
+static int get_free_buf_count(struct AV1HW_s *hw)
+{
+ struct AV1_Common_s *const cm = &hw->common;
+ struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs;
+ int i;
+ int free_buf_count = 0;
+ for (i = 0; i < hw->used_buf_num; ++i)
+ if ((frame_bufs[i].ref_count == 0) &&
+ (frame_bufs[i].buf.vf_ref == 0) &&
+ (frame_bufs[i].buf.index != -1)
+ )
+ free_buf_count++;
+ return free_buf_count;
+}
+
+int aom_bufmgr_init(struct AV1HW_s *hw, struct BuffInfo_s *buf_spec_i,
+ struct buff_s *mc_buf_i) {
+ struct AV1_Common_s *cm = &hw->common;
+ if (debug)
+ pr_info("%s %d %p\n", __func__, __LINE__, hw->pbi);
+ hw->frame_count = 0;
+ hw->pic_count = 0;
+ hw->pre_stream_offset = 0;
+ spin_lock_init(&cm->buffer_pool->lock);
+ cm->prev_fb_idx = INVALID_IDX;
+ cm->new_fb_idx = INVALID_IDX;
+ hw->used_4k_num = -1;
+ cm->cur_fb_idx_mmu = INVALID_IDX;
+ pr_debug
+ ("After aom_bufmgr_init, prev_fb_idx : %d, new_fb_idx : %d\r\n",
+ cm->prev_fb_idx, cm->new_fb_idx);
+ hw->need_resync = 1;
+
+ cm->current_video_frame = 0;
+ hw->ready_for_new_data = 1;
+
+ /* private init */
+ hw->work_space_buf = buf_spec_i;
+ if (!hw->mmu_enable)
+ hw->mc_buf = mc_buf_i;
+
+ hw->rpm_addr = NULL;
+ hw->lmem_addr = NULL;
+#ifdef DUMP_FILMGRAIN
+ hw->fg_addr = NULL;
+#endif
+ hw->use_cma_flag = 0;
+ hw->decode_idx = 0;
+ hw->result_done_count = 0;
+ /*int m_uiMaxCUWidth = 1<<7;*/
+ /*int m_uiMaxCUHeight = 1<<7;*/
+ hw->has_keyframe = 0;
+ hw->has_sequence = 0;
+ hw->skip_flag = 0;
+ hw->wait_buf = 0;
+ hw->error_flag = 0;
+
+ hw->last_pts = 0;
+ hw->last_pts_us64 = 0;
+ hw->last_timestamp = 0;
+ hw->shift_byte_count = 0;
+ hw->shift_byte_count_lo = 0;
+ hw->shift_byte_count_hi = 0;
+ hw->pts_mode_switching_count = 0;
+ hw->pts_mode_recovery_count = 0;
+
+ hw->buf_num = 0;
+ hw->pic_num = 0;
+
+ return 0;
+}
+
+/*
+struct AV1HW_s av1_decoder;
+union param_u av1_param;
+*/
+/**************************************************
+ *
+ *AV1 buffer management end
+ *
+ ***************************************************
+ */
+
+
+#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*/
+#ifdef AV1_10B_NV21
+static u32 mem_map_mode = 2 /* 0:linear 1:32x32 2:64x32*/
+#else
+static u32 mem_map_mode; /* 0:linear 1:32x32 2:64x32 ; m8baby test1902 */
+#endif
+static u32 enable_mem_saving = 1;
+static u32 force_w_h;
+
+static u32 force_fps;
+
+
+const u32 av1_version = 201602101;
+static u32 debug;
+static u32 radr;
+static u32 rval;
+static u32 pop_shorts;
+static u32 dbg_cmd;
+static u32 dbg_skip_decode_index;
+static u32 endian = 0xff0;
+static u32 multi_frames_in_one_pack = 1;
+#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 av1_max_pic_w = 4096;
+static u32 av1_max_pic_h = 2304;
+
+static u32 dynamic_buf_num_margin = 3;
+#else
+static u32 buf_alloc_width;
+static u32 buf_alloc_height;
+static u32 dynamic_buf_num_margin = 7;
+#endif
+static u32 buf_alloc_depth = 10;
+static u32 buf_alloc_size;
+/*
+ *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 AV1) 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 low_latency_flag;
+
+static u32 no_head;
+
+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 (av1_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
+ *
+ */
+
+static u32 error_handle_policy;
+/*static u32 parser_sei_enable = 1;*/
+#define MAX_BUF_NUM_NORMAL 16
+/*less bufs num 12 caused frame drop, nts failed*/
+#define MAX_BUF_NUM_LESS 14
+static u32 max_buf_num = MAX_BUF_NUM_NORMAL;
+#define MAX_BUF_NUM_SAVE_BUF 8
+
+static DEFINE_MUTEX(vav1_mutex);
+#ifndef MULTI_INSTANCE_SUPPORT
+static struct device *cma_dev;
+#endif
+#define HEVC_DEC_STATUS_REG HEVC_ASSIST_SCRATCH_0
+#define HEVC_FG_STATUS HEVC_ASSIST_SCRATCH_B
+#define HEVC_RPM_BUFFER HEVC_ASSIST_SCRATCH_1
+#define AOM_AV1_ADAPT_PROB_REG HEVC_ASSIST_SCRATCH_3
+#define AOM_AV1_MMU_MAP_BUFFER HEVC_ASSIST_SCRATCH_4 // changed to use HEVC_ASSIST_MMU_MAP_ADDR
+#define AOM_AV1_DAALA_TOP_BUFFER HEVC_ASSIST_SCRATCH_5
+//#define HEVC_SAO_UP HEVC_ASSIST_SCRATCH_6
+//#define HEVC_STREAM_SWAP_BUFFER HEVC_ASSIST_SCRATCH_7
+#define AOM_AV1_CDF_BUFFER_W HEVC_ASSIST_SCRATCH_8
+#define AOM_AV1_CDF_BUFFER_R HEVC_ASSIST_SCRATCH_9
+#define AOM_AV1_COUNT_SWAP_BUFFER HEVC_ASSIST_SCRATCH_A
+#define AOM_AV1_SEG_MAP_BUFFER_W AV1_SEG_W_ADDR // HEVC_ASSIST_SCRATCH_B
+#define AOM_AV1_SEG_MAP_BUFFER_R AV1_SEG_R_ADDR // HEVC_ASSIST_SCRATCH_C
+//#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 HEVC_STREAM_SWAP_TEST HEVC_ASSIST_SCRATCH_L
+
+#ifdef MULTI_INSTANCE_SUPPORT
+#define HEVC_DECODE_COUNT HEVC_ASSIST_SCRATCH_M
+#define HEVC_DECODE_SIZE HEVC_ASSIST_SCRATCH_N
+#else
+#define HEVC_DECODE_PIC_BEGIN_REG HEVC_ASSIST_SCRATCH_M
+#define HEVC_DECODE_PIC_NUM_REG HEVC_ASSIST_SCRATCH_N
+#endif
+#define AOM_AV1_SEGMENT_FEATURE AV1_QUANT_WR
+
+#define DEBUG_REG1 HEVC_ASSIST_SCRATCH_G
+#define DEBUG_REG2 HEVC_ASSIST_SCRATCH_H
+
+#define LMEM_DUMP_ADR HEVC_ASSIST_SCRATCH_I
+#define CUR_NAL_UNIT_TYPE HEVC_ASSIST_SCRATCH_J
+#define DECODE_STOP_POS HEVC_ASSIST_SCRATCH_K
+
+#define PIC_END_LCU_COUNT HEVC_ASSIST_SCRATCH_2
+
+#define HEVC_AUX_ADR HEVC_ASSIST_SCRATCH_L
+#define HEVC_AUX_DATA_SIZE HEVC_ASSIST_SCRATCH_7
+#if (defined DEBUG_UCODE_LOG) || (defined DEBUG_CMD)
+#define HEVC_DBG_LOG_ADR HEVC_ASSIST_SCRATCH_C
+#ifdef DEBUG_CMD
+#define HEVC_D_ADR HEVC_ASSIST_SCRATCH_4
+#endif
+#endif
+/*
+ *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
+ /*[31:24] chip feature
+ 31: 0, use MBOX1; 1, use MBOX0
+ [24:16] debug
+ 0x1, bufmgr only
+ */
+#define DECODE_MODE HEVC_ASSIST_SCRATCH_J
+#define DECODE_STOP_POS HEVC_ASSIST_SCRATCH_K
+
+#define RPM_BUF_SIZE ((RPM_END - RPM_BEGIN) * 2)
+#define LMEM_BUF_SIZE (0x600 * 2)
+
+/*
+#ifdef MAP_8K
+static u32 seg_map_size = 0xd8000;
+#else
+static u32 seg_map_size = 0x36000;
+#endif
+*/
+//static u32 seg_map_size = 0x36000;
+
+//#define VBH_BUF_COUNT 4
+//#define VBH_BUF_SIZE_1080P ((((2 * 16 * 1088) + 0xffff) & (~0xffff)) * VBH_BUF_COUNT)
+//#define VBH_BUF_SIZE_4K ((((2 * 16 * 2304) + 0xffff) & (~0xffff))) * VBH_BUF_COUNT)
+//#define VBH_BUF_SIZE_8K ((((2 * 16 * 4608) + 0xffff) & (~0xffff))) * VBH_BUF_COUNT)
+
+ /*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)
+
+#define WORK_BUF_SPEC_NUM 3
+
+static struct BuffInfo_s aom_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 = 0x1E00,
+ },
+ .sao_abv = {
+ .buf_size = 0x0, //0x30000,
+ },
+ .sao_vb = {
+ .buf_size = 0x0, //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,
+ },
+ .seg_map = {
+ // SEGMENT MAP AREA - 1920x1088/4/4 * 3 bits = 0xBF40 Bytes * 16 = 0xBF400
+ .buf_size = 0xBF400,
+ },
+ .daala_top = {
+ // DAALA TOP STORE AREA - 224 Bytes (use 256 Bytes for LPDDR4) per 128. Total 4096/128*256 = 0x2000
+ .buf_size = 0xf00,
+ },
+ .sao_up = {
+ // SAO UP STORE AREA - Max 640(10240/16) LCU, each has 16 bytes total 0x2800 bytes
+ .buf_size = 0x0, //0x2800,
+ },
+ .swap_buf = {
+ // 256cyclex64bit = 2K bytes 0x800 (only 144 cycles valid)
+ .buf_size = 0x800,
+ },
+ .cdf_buf = {
+ // for context store/load 1024x256 x16 = 512K bytes 16*0x8000
+ .buf_size = 0x80000,
+ },
+ .gmc_buf = {
+ // for gmc_parameter store/load 128 x 16 = 2K bytes 0x800
+ .buf_size = 0x800,
+ },
+ .scalelut = {
+ // support up to 32 SCALELUT 1024x32 = 32Kbytes (0x8000)
+ .buf_size = 0x0, //0x8000,
+ },
+ .dblk_para = {
+ // DBLK -> Max 256(4096/16) LCU, each para 1024bytes(total:0x40000), data 1024bytes(total:0x40000)
+ .buf_size = 0xd00, /*0xc40*/
+ },
+ .dblk_data = {
+ .buf_size = 0x49000,
+ },
+ .cdef_data = {
+ .buf_size = 0x22400,
+ },
+ .ups_data = {
+ .buf_size = 0x36000,
+ },
+ .fgs_table = {
+ .buf_size = FGS_TABLE_SIZE * FRAME_BUFFERS, // 512x128bits
+ },
+#ifdef AOM_AV1_MMU
+ .mmu_vbh = {
+ .buf_size = VBH_BUF_SIZE_1080P, //2*16*(more than 2304)/4, 4K
+ },
+ .cm_header = {
+ #ifdef USE_SPEC_BUF_FOR_MMU_HEAD
+ .buf_size = MMU_COMPRESS_HEADER_SIZE_1080P * FRAME_BUFFERS, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8)
+ #else
+ .buf_size = 0,
+ #endif
+ },
+#endif
+#ifdef AOM_AV1_MMU_DW
+ .mmu_vbh_dw = {
+ .buf_size = DW_VBH_BUF_SIZE_1080P, //2*16*(more than 2304)/4, 4K
+ },
+ .cm_header_dw = {
+ #ifdef USE_SPEC_BUF_FOR_MMU_HEAD
+ .buf_size = MMU_COMPRESS_HEADER_SIZE_1080P*FRAME_BUFFERS, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8)
+ #else
+ .buf_size = 0,
+ #endif
+ },
+#endif
+ .mpred_above = {
+ .buf_size = 0x2800, /*round from 0x2760*/ /* 2 * size of hw*/
+ },
+#ifdef MV_USE_FIXED_BUF
+ .mpred_mv = {
+ .buf_size = MAX_ONE_MV_BUFFER_SIZE_1080P_TM2REVB * FRAME_BUFFERS,/*round from 203A0*/ //1080p, 0x40000 per buffer
+ },
+#endif
+ .rpm = {
+ .buf_size = 0x80*2,
+ },
+ .lmem = {
+ .buf_size = 0x400 * 2,
+ }
+ },
+ {
+#ifdef VPU_FILMGRAIN_DUMP
+ .max_width = 640,
+ .max_height = 480,
+#else
+ .max_width = 4096,
+ .max_height = 2304,
+#endif
+ .ipp = {
+ // IPP work space calculation : 4096 * (Y+CbCr+Flags) = 12k, round to 16k
+ .buf_size = 0x4000,
+ },
+ .sao_abv = {
+ .buf_size = 0x0, //0x30000,
+ },
+ .sao_vb = {
+ .buf_size = 0x0, //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,
+ },
+ .seg_map = {
+ // SEGMENT MAP AREA - 4096x2304/4/4 * 3 bits = 0x36000 Bytes * 16 = 0x360000
+ .buf_size = 0x360000,
+ },
+ .daala_top = {
+ // DAALA TOP STORE AREA - 224 Bytes (use 256 Bytes for LPDDR4) per 128. Total 4096/128*256 = 0x2000
+ .buf_size = 0x2000,
+ },
+ .sao_up = {
+ // SAO UP STORE AREA - Max 640(10240/16) LCU, each has 16 bytes total 0x2800 bytes
+ .buf_size = 0x0, //0x2800,
+ },
+ .swap_buf = {
+ // 256cyclex64bit = 2K bytes 0x800 (only 144 cycles valid)
+ .buf_size = 0x800,
+ },
+ .cdf_buf = {
+ // for context store/load 1024x256 x16 = 512K bytes 16*0x8000
+ .buf_size = 0x80000,
+ },
+ .gmc_buf = {
+ // for gmc_parameter store/load 128 x 16 = 2K bytes 0x800
+ .buf_size = 0x800,
+ },
+ .scalelut = {
+ // support up to 32 SCALELUT 1024x32 = 32Kbytes (0x8000)
+ .buf_size = 0x0, //0x8000,
+ },
+ .dblk_para = {
+ // DBLK -> Max 256(4096/16) LCU, each para 1024bytes(total:0x40000), data 1024bytes(total:0x40000)
+ .buf_size = 0x1a00, /*0x1980*/
+ },
+ .dblk_data = {
+ .buf_size = 0x52800,
+ },
+ .cdef_data = {
+ .buf_size = 0x24a00,
+ },
+ .ups_data = {
+ .buf_size = 0x6f000,
+ },
+ .fgs_table = {
+ .buf_size = FGS_TABLE_SIZE * FRAME_BUFFERS, // 512x128bits
+ },
+#ifdef AOM_AV1_MMU
+ .mmu_vbh = {
+ .buf_size = VBH_BUF_SIZE_4K, //2*16*(more than 2304)/4, 4K
+ },
+ .cm_header = {
+ #ifdef USE_SPEC_BUF_FOR_MMU_HEAD
+ .buf_size = MMU_COMPRESS_HEADER_SIZE_4K*FRAME_BUFFERS, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8)
+ #else
+ .buf_size = 0,
+ #endif
+ },
+#endif
+#ifdef AOM_AV1_MMU_DW
+ .mmu_vbh_dw = {
+ .buf_size = DW_VBH_BUF_SIZE_4K, //2*16*(more than 2304)/4, 4K
+ },
+ .cm_header_dw = {
+ #ifdef USE_SPEC_BUF_FOR_MMU_HEAD
+ .buf_size = MMU_COMPRESS_HEADER_SIZE_4K*FRAME_BUFFERS, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8)
+ #else
+ .buf_size = 0,
+ #endif
+ },
+#endif
+ .mpred_above = {
+ .buf_size = 0x5400, /* 2 * size of hw*/
+ },
+#ifdef MV_USE_FIXED_BUF
+ .mpred_mv = {
+ /* .buf_size = 0x100000*16,
+ //4k2k , 0x100000 per buffer */
+ /* 4096x2304 , 0x120000 per buffer */
+ .buf_size = MAX_ONE_MV_BUFFER_SIZE_4K_TM2REVB * FRAME_BUFFERS,
+ },
+#endif
+ .rpm = {
+ .buf_size = 0x80*2,
+ },
+ .lmem = {
+ .buf_size = 0x400 * 2,
+ }
+
+ },
+ {
+ .max_width = 8192,
+ .max_height = 4608,
+ .ipp = {
+ // IPP work space calculation : 4096 * (Y+CbCr+Flags) = 12k, round to 16k
+ .buf_size = 0x4000,
+ },
+ .sao_abv = {
+ .buf_size = 0x0, //0x30000,
+ },
+ .sao_vb = {
+ .buf_size = 0x0, //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,
+ },
+ .seg_map = {
+ // SEGMENT MAP AREA - 4096x2304/4/4 * 3 bits = 0x36000 Bytes * 16 = 0x360000
+ .buf_size = 0xd80000,
+ },
+ .daala_top = {
+ // DAALA TOP STORE AREA - 224 Bytes (use 256 Bytes for LPDDR4) per 128. Total 4096/128*256 = 0x2000
+ .buf_size = 0x2000,
+ },
+ .sao_up = {
+ // SAO UP STORE AREA - Max 640(10240/16) LCU, each has 16 bytes total 0x2800 bytes
+ .buf_size = 0x0, //0x2800,
+ },
+ .swap_buf = {
+ // 256cyclex64bit = 2K bytes 0x800 (only 144 cycles valid)
+ .buf_size = 0x800,
+ },
+ .cdf_buf = {
+ // for context store/load 1024x256 x16 = 512K bytes 16*0x8000
+ .buf_size = 0x80000,
+ },
+ .gmc_buf = {
+ // for gmc_parameter store/load 128 x 16 = 2K bytes 0x800
+ .buf_size = 0x800,
+ },
+ .scalelut = {
+ // support up to 32 SCALELUT 1024x32 = 32Kbytes (0x8000)
+ .buf_size = 0x0, //0x8000,
+ },
+ .dblk_para = {
+ // DBLK -> Max 256(4096/16) LCU, each para 1024bytes(total:0x40000), data 1024bytes(total:0x40000)
+ .buf_size = 0x3300, /*0x32a0*/
+ },
+ .dblk_data = {
+ .buf_size = 0xa4800,
+ },
+ .cdef_data = {
+ .buf_size = 0x29200,
+ },
+ .ups_data = {
+ .buf_size = 0xdb000,
+ },
+ .fgs_table = {
+ .buf_size = FGS_TABLE_SIZE * FRAME_BUFFERS, // 512x128bits
+ },
+#ifdef AOM_AV1_MMU
+ .mmu_vbh = {
+ .buf_size = VBH_BUF_SIZE_8K, //2*16*(more than 2304)/4, 4K
+ },
+ .cm_header = {
+ #ifdef USE_SPEC_BUF_FOR_MMU_HEAD
+ .buf_size = MMU_COMPRESS_HEADER_SIZE_8K*FRAME_BUFFERS, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8)
+#else
+ .buf_size = 0,
+#endif
+ },
+#endif
+#ifdef AOM_AV1_MMU_DW
+ .mmu_vbh_dw = {
+ .buf_size = DW_VBH_BUF_SIZE_8K, //2*16*(more than 2304)/4, 4K
+ },
+ .cm_header_dw = {
+ #ifdef USE_SPEC_BUF_FOR_MMU_HEAD
+ .buf_size = MMU_COMPRESS_HEADER_SIZE_8K*FRAME_BUFFERS, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8)
+ #else
+ .buf_size = 0,
+ #endif
+ },
+#endif
+ .mpred_above = {
+ .buf_size = 0xA800, /* 2 * size of hw*/
+ },
+#ifdef MV_USE_FIXED_BUF
+ .mpred_mv = {
+ /* .buf_size = 0x100000*16,
+ //4k2k , 0x100000 per buffer */
+ /* 4096x2304 , 0x120000 per buffer */
+ .buf_size = MAX_ONE_MV_BUFFER_SIZE_8K_TM2REVB * FRAME_BUFFERS,
+ },
+#endif
+ .rpm = {
+ .buf_size = 0x80*2,
+ },
+ .lmem = {
+ .buf_size = 0x400 * 2,
+ }
+
+ }
+};
+
+
+/*
+* AUX DATA Process
+*/
+static u32 init_aux_size;
+static int aux_data_is_avaible(struct AV1HW_s *hw)
+{
+ u32 reg_val;
+
+ reg_val = READ_VREG(HEVC_AUX_DATA_SIZE);
+ if (reg_val != 0 && reg_val != init_aux_size)
+ return 1;
+ else
+ return 0;
+}
+
+static void config_aux_buf(struct AV1HW_s *hw)
+{
+ WRITE_VREG(HEVC_AUX_ADR, hw->aux_phy_addr);
+ init_aux_size = ((hw->prefix_aux_size >> 4) << 16) |
+ (hw->suffix_aux_size >> 4);
+ WRITE_VREG(HEVC_AUX_DATA_SIZE, init_aux_size);
+}
+
+/*
+* dv_meta_flag: 1, dolby meta (T35) only; 2, not include dolby meta (T35)
+*/
+static void set_aux_data(struct AV1HW_s *hw,
+ char **aux_data_buf, int *aux_data_size,
+ unsigned char suffix_flag,
+ unsigned char dv_meta_flag)
+{
+ int i;
+ unsigned short *aux_adr;
+ unsigned int size_reg_val =
+ READ_VREG(HEVC_AUX_DATA_SIZE);
+ unsigned int aux_count = 0;
+ int aux_size = 0;
+ if (0 == aux_data_is_avaible(hw))
+ return;
+
+ if (hw->aux_data_dirty ||
+ hw->m_ins_flag == 0) {
+
+ hw->aux_data_dirty = 0;
+ }
+
+ if (suffix_flag) {
+ aux_adr = (unsigned short *)
+ (hw->aux_addr +
+ hw->prefix_aux_size);
+ aux_count =
+ ((size_reg_val & 0xffff) << 4)
+ >> 1;
+ aux_size =
+ hw->suffix_aux_size;
+ } else {
+ aux_adr =
+ (unsigned short *)hw->aux_addr;
+ aux_count =
+ ((size_reg_val >> 16) << 4)
+ >> 1;
+ aux_size =
+ hw->prefix_aux_size;
+ }
+ if (debug & AV1_DEBUG_BUFMGR_MORE) {
+ av1_print(hw, 0,
+ "%s:old size %d count %d,suf %d dv_flag %d\r\n",
+ __func__, *aux_data_size,
+ 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 == 0x14)
+ heads_size += 8;
+ else if (dv_meta_flag == 2 && tag != 0x14)
+ heads_size += 8;
+ }
+ }
+ new_size = *aux_data_size + aux_count + heads_size;
+ new_buf = vmalloc(new_size);
+ if (new_buf) {
+ unsigned char valid_tag = 0;
+ unsigned char *h =
+ new_buf +
+ *aux_data_size;
+ unsigned char *p = h + 8;
+ int len = 0;
+ int padding_len = 0;
+ if (*aux_data_buf) {
+ memcpy(new_buf, *aux_data_buf, *aux_data_size);
+ vfree(*aux_data_buf);
+ }
+ *aux_data_buf = 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 == 0x14)
+ valid_tag = 1;
+ else if (dv_meta_flag == 2
+ && tag != 0x14)
+ valid_tag = 1;
+ else
+ valid_tag = 0;
+ if (valid_tag && len > 0) {
+ *aux_data_size +=
+ (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 += (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 (debug & AV1_DEBUG_BUFMGR_MORE) {
+ av1_print(hw, 0,
+ "aux: (size %d) suffix_flag %d\n",
+ *aux_data_size, suffix_flag);
+ for (i = 0; i < *aux_data_size; i++) {
+ av1_print_cont(hw, 0,
+ "%02x ", (*aux_data_buf)[i]);
+ if (((i + 1) & 0xf) == 0)
+ av1_print_cont(hw, 0, "\n");
+ }
+ av1_print_cont(hw, 0, "\n");
+ }
+
+ } else {
+ av1_print(hw, 0, "new buf alloc failed\n");
+ if (*aux_data_buf)
+ vfree(*aux_data_buf);
+ *aux_data_buf = NULL;
+ *aux_data_size = 0;
+ }
+ }
+
+}
+
+static void set_dv_data(struct AV1HW_s *hw)
+{
+ set_aux_data(hw, &hw->dv_data_buf,
+ &hw->dv_data_size, 0, 1);
+
+}
+
+static void set_pic_aux_data(struct AV1HW_s *hw,
+ struct PIC_BUFFER_CONFIG_s *pic, unsigned char suffix_flag,
+ unsigned char dv_meta_flag)
+{
+ if (pic == NULL)
+ return;
+ set_aux_data(hw, &pic->aux_data_buf,
+ &pic->aux_data_size, suffix_flag, dv_meta_flag);
+}
+
+static void copy_dv_data(struct AV1HW_s *hw,
+ struct PIC_BUFFER_CONFIG_s *pic)
+{
+ char *new_buf;
+ int new_size;
+ new_size = pic->aux_data_size + hw->dv_data_size;
+ new_buf = vmalloc(new_size);
+ if (new_buf) {
+ if (debug & AV1_DEBUG_BUFMGR_MORE) {
+ av1_print(hw, 0,
+ "%s: (size %d) pic index %d\n",
+ __func__,
+ hw->dv_data_size, pic->index);
+ }
+ if (pic->aux_data_buf) {
+ memcpy(new_buf, pic->aux_data_buf, pic->aux_data_size);
+ vfree(pic->aux_data_buf);
+ }
+ memcpy(new_buf + pic->aux_data_size, hw->dv_data_buf, hw->dv_data_size);
+ pic->aux_data_size += hw->dv_data_size;
+ pic->aux_data_buf = new_buf;
+ vfree(hw->dv_data_buf);
+ hw->dv_data_buf = NULL;
+ hw->dv_data_size = 0;
+ }
+
+}
+
+static void release_aux_data(struct AV1HW_s *hw,
+ struct PIC_BUFFER_CONFIG_s *pic)
+{
+ if (pic->aux_data_buf)
+ vfree(pic->aux_data_buf);
+ pic->aux_data_buf = NULL;
+ pic->aux_data_size = 0;
+}
+
+static void dump_aux_buf(struct AV1HW_s *hw)
+{
+ int i;
+ unsigned short *aux_adr =
+ (unsigned short *)
+ hw->aux_addr;
+ unsigned int aux_size =
+ (READ_VREG(HEVC_AUX_DATA_SIZE)
+ >> 16) << 4;
+
+ if (hw->prefix_aux_size > 0) {
+ av1_print(hw, 0,
+ "prefix aux: (size %d)\n",
+ aux_size);
+ for (i = 0; i <
+ (aux_size >> 1); i++) {
+ av1_print_cont(hw, 0,
+ "%04x ",
+ *(aux_adr + i));
+ if (((i + 1) & 0xf)
+ == 0)
+ av1_print_cont(hw,
+ 0, "\n");
+ }
+ }
+ if (hw->suffix_aux_size > 0) {
+ aux_adr = (unsigned short *)
+ (hw->aux_addr +
+ hw->prefix_aux_size);
+ aux_size =
+ (READ_VREG(HEVC_AUX_DATA_SIZE) & 0xffff)
+ << 4;
+ av1_print(hw, 0,
+ "suffix aux: (size %d)\n",
+ aux_size);
+ for (i = 0; i <
+ (aux_size >> 1); i++) {
+ av1_print_cont(hw, 0,
+ "%04x ", *(aux_adr + i));
+ if (((i + 1) & 0xf) == 0)
+ av1_print_cont(hw, 0, "\n");
+ }
+ }
+}
+
+/*
+*
+*/
+
+/*Losless compression body buffer size 4K per 64x32 (jt)*/
+static int compute_losless_comp_body_size(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;
+ bsize = (is_bit_depth_10?4096:3200)*width_x64*height_x32;
+ if (debug & AV1_DEBUG_BUFMGR_MORE)
+ pr_info("%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(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;
+ if (debug & AV1_DEBUG_BUFMGR_MORE)
+ pr_info("%s(%d,%d)=>%d\n",
+ __func__, width, height,
+ hsize);
+
+ return hsize;
+}
+
+#ifdef AOM_AV1_MMU_DW
+static int compute_losless_comp_body_size_dw(int width, int height,
+ uint8_t is_bit_depth_10)
+{
+
+ return compute_losless_comp_body_size(width, height, is_bit_depth_10);
+}
+
+/* Losless compression header buffer size 32bytes per 128x64 (jt)*/
+static int compute_losless_comp_header_size_dw(int width, int height)
+{
+ return compute_losless_comp_header_size(width, height);
+}
+#endif
+
+static void init_buff_spec(struct AV1HW_s *hw,
+ struct BuffInfo_s *buf_spec)
+{
+ void *mem_start_virt;
+
+ buf_spec->ipp.buf_start =
+ buf_spec->start_adr;
+ buf_spec->sao_abv.buf_start =
+ buf_spec->ipp.buf_start + buf_spec->ipp.buf_size;
+
+ buf_spec->sao_vb.buf_start =
+ buf_spec->sao_abv.buf_start + buf_spec->sao_abv.buf_size;
+ buf_spec->short_term_rps.buf_start =
+ buf_spec->sao_vb.buf_start + buf_spec->sao_vb.buf_size;
+ buf_spec->vps.buf_start =
+ buf_spec->short_term_rps.buf_start + buf_spec->short_term_rps.buf_size;
+ buf_spec->seg_map.buf_start =
+ buf_spec->vps.buf_start + buf_spec->vps.buf_size;
+ buf_spec->daala_top.buf_start =
+ buf_spec->seg_map.buf_start + buf_spec->seg_map.buf_size;
+ buf_spec->sao_up.buf_start =
+ buf_spec->daala_top.buf_start + buf_spec->daala_top.buf_size;
+ buf_spec->swap_buf.buf_start =
+ buf_spec->sao_up.buf_start + buf_spec->sao_up.buf_size;
+ buf_spec->cdf_buf.buf_start =
+ buf_spec->swap_buf.buf_start + buf_spec->swap_buf.buf_size;
+ buf_spec->gmc_buf.buf_start =
+ buf_spec->cdf_buf.buf_start + buf_spec->cdf_buf.buf_size;
+ buf_spec->scalelut.buf_start =
+ buf_spec->gmc_buf.buf_start + buf_spec->gmc_buf.buf_size;
+ buf_spec->dblk_para.buf_start =
+ buf_spec->scalelut.buf_start + buf_spec->scalelut.buf_size;
+ buf_spec->dblk_data.buf_start =
+ buf_spec->dblk_para.buf_start + buf_spec->dblk_para.buf_size;
+ buf_spec->cdef_data.buf_start =
+ buf_spec->dblk_data.buf_start + buf_spec->dblk_data.buf_size;
+ buf_spec->ups_data.buf_start =
+ buf_spec->cdef_data.buf_start + buf_spec->cdef_data.buf_size;
+ buf_spec->fgs_table.buf_start =
+ buf_spec->ups_data.buf_start + buf_spec->ups_data.buf_size;
+#ifdef AOM_AV1_MMU
+ buf_spec->mmu_vbh.buf_start =
+ buf_spec->fgs_table.buf_start + buf_spec->fgs_table.buf_size;
+ buf_spec->cm_header.buf_start =
+ buf_spec->mmu_vbh.buf_start + buf_spec->mmu_vbh.buf_size;
+#ifdef AOM_AV1_MMU_DW
+ buf_spec->mmu_vbh_dw.buf_start =
+ buf_spec->cm_header.buf_start + buf_spec->cm_header.buf_size;
+ buf_spec->cm_header_dw.buf_start =
+ buf_spec->mmu_vbh_dw.buf_start + buf_spec->mmu_vbh_dw.buf_size;
+ buf_spec->mpred_above.buf_start =
+ buf_spec->cm_header_dw.buf_start + buf_spec->cm_header_dw.buf_size;
+#else
+ buf_spec->mpred_above.buf_start =
+ buf_spec->cm_header.buf_start + buf_spec->cm_header.buf_size;
+#endif
+#else
+ buf_spec->mpred_above.buf_start =
+ buf_spec->fgs_table.buf_start + buf_spec->fgs_table.buf_size;
+#endif
+
+#ifdef MV_USE_FIXED_BUF
+ buf_spec->mpred_mv.buf_start =
+ buf_spec->mpred_above.buf_start +
+ buf_spec->mpred_above.buf_size;
+
+ buf_spec->rpm.buf_start =
+ buf_spec->mpred_mv.buf_start +
+ buf_spec->mpred_mv.buf_size;
+#else
+ buf_spec->rpm.buf_start =
+ buf_spec->mpred_above.buf_start +
+ buf_spec->mpred_above.buf_size;
+
+#endif
+ buf_spec->lmem.buf_start =
+ buf_spec->rpm.buf_start +
+ buf_spec->rpm.buf_size;
+ buf_spec->end_adr =
+ buf_spec->lmem.buf_start +
+ buf_spec->lmem.buf_size;
+
+ if (!hw)
+ return;
+
+ if (!vdec_secure(hw_to_vdec(hw))) {
+ 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 {
+ mem_start_virt = codec_mm_vmap(
+ buf_spec->dblk_para.buf_start,
+ buf_spec->dblk_para.buf_size);
+ 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);
+ codec_mm_unmap_phyaddr(mem_start_virt);
+ } 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("vps.buf_start :%x\n",
+ buf_spec->vps.buf_start);
+ pr_info("seg_map.buf_start :%x\n",
+ buf_spec->seg_map.buf_start);
+ pr_info("daala_top.buf_start :%x\n",
+ buf_spec->daala_top.buf_start);
+ pr_info("swap_buf.buf_start :%x\n",
+ buf_spec->swap_buf.buf_start);
+ pr_info("cdf_buf.buf_start :%x\n",
+ buf_spec->cdf_buf.buf_start);
+ pr_info("gmc_buf.buf_start :%x\n",
+ buf_spec->gmc_buf.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("cdef_data.buf_start :%x\n",
+ buf_spec->cdef_data.buf_start);
+ pr_info("ups_data.buf_start :%x\n",
+ buf_spec->ups_data.buf_start);
+
+#ifdef AOM_AV1_MMU
+ pr_info("mmu_vbh.buf_start :%x\n",
+ buf_spec->mmu_vbh.buf_start);
+#endif
+ pr_info("mpred_above.buf_start :%x\n",
+ buf_spec->mpred_above.buf_start);
+#ifdef MV_USE_FIXED_BUF
+ pr_info("mpred_mv.buf_start :%x\n",
+ buf_spec->mpred_mv.buf_start);
+#endif
+ if ((debug & AOM_AV1_DEBUG_SEND_PARAM_WITH_REG) == 0) {
+ pr_info("rpm.buf_start :%x\n",
+ buf_spec->rpm.buf_start);
+ }
+ }
+}
+
+static bool v4l_is_there_vframe_bound(struct AV1HW_s *hw)
+{
+ int i;
+ struct AV1_Common_s *const cm = &hw->common;
+ struct RefCntBuffer_s *frame_bufs = cm->buffer_pool->frame_bufs;
+
+ for (i = 0; i < hw->used_buf_num; ++i) {
+ if (frame_bufs[i].buf.vframe_bound)
+ return true;
+ }
+
+ return false;
+}
+
+static void v4l_mmu_buffer_release(struct AV1HW_s *hw)
+{
+ struct AV1_Common_s *const cm = &hw->common;
+ struct RefCntBuffer_s *frame_bufs = cm->buffer_pool->frame_bufs;
+ int i;
+
+ /* release workspace */
+ if (hw->bmmu_box)
+ decoder_bmmu_box_free_idx(hw->bmmu_box,
+ WORK_SPACE_BUF_ID);
+ /*
+ * it's only when vframe get back to driver, right now we can be sure
+ * that vframe and fd are related. if the playback exits, the capture
+ * requires the upper app to release when the fd is closed, and others
+ * buffers drivers are released by driver.
+ */
+ for (i = 0; i < hw->used_buf_num; ++i) {
+ if (!frame_bufs[i].buf.vframe_bound) {
+ if (hw->bmmu_box)
+ decoder_bmmu_box_free_idx(hw->bmmu_box,
+ HEADER_BUFFER_IDX(hw->buffer_wrap[i]));
+ if (hw->mmu_box)
+ decoder_mmu_box_free_idx(hw->mmu_box, hw->buffer_wrap[i]);
+
+ av1_print(hw, PRINT_FLAG_V4L_DETAIL,
+ "%s free buffer[%d], bmmu_box: %p, mmu_box: %p\n",
+ __func__, i, hw->bmmu_box, hw->mmu_box);
+ }
+ }
+}
+
+static void uninit_mmu_buffers(struct AV1HW_s *hw)
+{
+#ifndef MV_USE_FIXED_BUF
+ dealloc_mv_bufs(hw);
+#endif
+ if (hw->is_used_v4l &&
+ v4l_is_there_vframe_bound(hw)) {
+ if (get_double_write_mode(hw) != 0x10) {
+ v4l_mmu_buffer_release(hw);
+ return;
+ }
+ }
+
+ if (hw->mmu_box)
+ decoder_mmu_box_free(hw->mmu_box);
+ hw->mmu_box = NULL;
+
+#ifdef AOM_AV1_MMU_DW
+ if (hw->mmu_box_dw)
+ decoder_mmu_box_free(hw->mmu_box_dw);
+ hw->mmu_box_dw = NULL;
+#endif
+ if (hw->bmmu_box)
+ decoder_bmmu_box_free(hw->bmmu_box);
+ hw->bmmu_box = NULL;
+}
+
+static int calc_luc_quantity(int lcu_size, u32 w, u32 h)
+{
+ int pic_width_64 = (w + 63) & (~0x3f);
+ int pic_height_32 = (h + 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;
+
+ return pic_width_lcu * pic_height_lcu;
+}
+
+static int v4l_alloc_and_config_pic(struct AV1HW_s *hw,
+ struct PIC_BUFFER_CONFIG_s *pic)
+{
+ int ret = -1;
+ int i = pic->index;
+ int dw_mode = get_double_write_mode_init(hw);
+ int lcu_total = calc_luc_quantity(hw->current_lcu_size,
+ hw->frame_width, hw->frame_height);
+#ifdef MV_USE_FIXED_BUF
+ u32 mpred_mv_end = hw->work_space_buf->mpred_mv.buf_start +
+ hw->work_space_buf->mpred_mv.buf_size;
+//#ifdef USE_DYNAMIC_MV_BUFFER
+// int32_t MV_MEM_UNIT = (lcu_size == 128) ? (19*4*16) : (19*16);
+// int32_t mv_buffer_size = (lcu_total*MV_MEM_UNIT);
+//#else
+ int32_t mv_buffer_size = hw->max_one_mv_buffer_size;
+//#endif
+#endif
+ struct vdec_v4l2_buffer *fb = NULL;
+
+ if (i < 0)
+ return ret;
+
+ ret = vdec_v4l_get_buffer(hw->v4l2_ctx, &fb);
+ if (ret < 0) {
+ av1_print(hw, 0, "[%d] AV1 get buffer fail.\n",
+ ((struct aml_vcodec_ctx *) (hw->v4l2_ctx))->id);
+ return ret;
+ }
+
+ if (hw->mmu_enable) {
+ hw->m_BUF[i].header_addr = decoder_bmmu_box_get_phy_addr(
+ hw->bmmu_box, HEADER_BUFFER_IDX(hw->buffer_wrap[i]));
+ if (debug & AV1_DEBUG_BUFMGR_MORE) {
+ pr_info("MMU header_adr %d: %ld\n",
+ i, hw->m_BUF[i].header_addr);
+ }
+ }
+
+#ifdef MV_USE_FIXED_BUF
+ if ((hw->work_space_buf->mpred_mv.buf_start +
+ ((i + 1) * mv_buffer_size))
+ <= mpred_mv_end) {
+#endif
+ hw->m_BUF[i].v4l_ref_buf_addr = (ulong)fb;
+ pic->cma_alloc_addr = fb->m.mem[0].addr;
+ if (fb->num_planes == 1) {
+ hw->m_BUF[i].start_adr = fb->m.mem[0].addr;
+ hw->m_BUF[i].luma_size = fb->m.mem[0].offset;
+ hw->m_BUF[i].size = fb->m.mem[0].size;
+ fb->m.mem[0].bytes_used = fb->m.mem[0].size;
+ pic->dw_y_adr = hw->m_BUF[i].start_adr;
+ pic->dw_u_v_adr = pic->dw_y_adr + hw->m_BUF[i].luma_size;
+ } else if (fb->num_planes == 2) {
+ hw->m_BUF[i].start_adr = fb->m.mem[0].addr;
+ hw->m_BUF[i].size = fb->m.mem[0].size;
+ hw->m_BUF[i].chroma_addr = fb->m.mem[1].addr;
+ hw->m_BUF[i].chroma_size = fb->m.mem[1].size;
+ fb->m.mem[0].bytes_used = fb->m.mem[0].size;
+ fb->m.mem[1].bytes_used = fb->m.mem[1].size;
+ pic->dw_y_adr = hw->m_BUF[i].start_adr;
+ pic->dw_u_v_adr = hw->m_BUF[i].chroma_addr;
+ }
+
+ /* config frame buffer */
+ if (hw->mmu_enable)
+ pic->header_adr = hw->m_BUF[i].header_addr;
+
+ pic->BUF_index = i;
+ pic->lcu_total = lcu_total;
+ pic->mc_canvas_y = pic->index;
+ pic->mc_canvas_u_v = pic->index;
+
+ if (dw_mode & 0x10) {
+ pic->mc_canvas_y = (pic->index << 1);
+ pic->mc_canvas_u_v = (pic->index << 1) + 1;
+ }
+
+#ifdef MV_USE_FIXED_BUF
+ pic->mpred_mv_wr_start_addr =
+ hw->work_space_buf->mpred_mv.buf_start +
+ (pic->index * mv_buffer_size);
+#endif
+
+#ifdef DUMP_FILMGRAIN
+ if (pic->index == fg_dump_index) {
+ pic->fgs_table_adr = hw->fg_phy_addr;
+ pr_info("set buffer %d film grain table 0x%x\n",
+ pic->index, pic->fgs_table_adr);
+ } else
+#endif
+ pic->fgs_table_adr =
+ hw->work_space_buf->fgs_table.buf_start +
+ (pic->index * FGS_TABLE_SIZE);
+
+ if (debug) {
+
+ pr_info("%s index %d BUF_index %d ",
+ __func__, pic->index,
+ pic->BUF_index);
+ pr_info("comp_body_size %x comp_buf_size %x ",
+ pic->comp_body_size,
+ pic->buf_size);
+ pr_info("mpred_mv_wr_start_adr %d\n",
+ pic->mpred_mv_wr_start_addr);
+ pr_info("dw_y_adr %d, pic_config->dw_u_v_adr =%d\n",
+ pic->dw_y_adr,
+ pic->dw_u_v_adr);
+ }
+#ifdef MV_USE_FIXED_BUF
+ }
+#endif
+ return ret;
+}
+
+static int config_pic(struct AV1HW_s *hw,
+ struct PIC_BUFFER_CONFIG_s *pic_config)
+{
+ int ret = -1;
+ int i;
+ int pic_width = hw->init_pic_w;
+ int pic_height = hw->init_pic_h;
+ //int lcu_size = ((params->p.seq_flags >> 6) & 0x1) ? 128 : 64;
+ int lcu_size = hw->current_lcu_size;
+
+ 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;
+#ifdef MV_USE_FIXED_BUF
+ u32 mpred_mv_end = hw->work_space_buf->mpred_mv.buf_start +
+ hw->work_space_buf->mpred_mv.buf_size;
+//#ifdef USE_DYNAMIC_MV_BUFFER
+// int32_t MV_MEM_UNIT = (lcu_size == 128) ? (19*4*16) : (19*16);
+// int32_t mv_buffer_size = (lcu_total*MV_MEM_UNIT);
+//#else
+ int32_t mv_buffer_size = hw->max_one_mv_buffer_size;
+//#endif
+
+#endif
+
+ u32 y_adr = 0;
+ int buf_size = 0;
+
+ int losless_comp_header_size =
+ compute_losless_comp_header_size(pic_width,
+ pic_height);
+ int losless_comp_body_size = compute_losless_comp_body_size(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(hw);
+
+ hw->lcu_total = lcu_total;
+
+ if (dw_mode && (dw_mode & 0x20) == 0) {
+ int pic_width_dw = pic_width /
+ get_double_write_ratio(hw, dw_mode);
+ int pic_height_dw = pic_height /
+ get_double_write_ratio(hw, 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;
+ if ((!hw->mmu_enable) && ((dw_mode & 0x10) == 0))
+ buf_size += (mc_buffer_size_h << 16);
+
+#ifdef USE_SPEC_BUF_FOR_MMU_HEAD
+ if (hw->mmu_enable) {
+ pic_config->header_adr =
+ hw->work_space_buf->cm_header.buf_start +
+ (pic_config->index * vav1_mmu_compress_header_size(hw));
+
+#ifdef AOM_AV1_MMU_DW
+ if (hw->dw_mmu_enable) {
+ pic_config->header_dw_adr =
+ hw->work_space_buf->cm_header_dw.buf_start +
+ (pic_config->index * vav1_mmu_compress_header_size(hw));
+
+ }
+#endif
+ }
+
+#else
+/*!USE_SPEC_BUF_FOR_MMU_HEAD*/
+ if (hw->mmu_enable) {
+ pic_config->header_adr = decoder_bmmu_box_get_phy_addr(
+ hw->bmmu_box, HEADER_BUFFER_IDX(hw->buffer_wrap[pic_config->index]));
+
+#ifdef AOM_AV1_MMU_DW
+ if (hw->dw_mmu_enable) {
+ pic_config->header_dw_adr = decoder_bmmu_box_get_phy_addr(
+ hw->bmmu_box, DW_HEADER_BUFFER_IDX(hw->buffer_wrap[pic_config->index]));
+
+ }
+ if (debug & AV1_DEBUG_BUFMGR_MORE) {
+ pr_info("MMU dw header_adr (%d, %d) %d: %d\n",
+ hw->dw_mmu_enable,
+ DW_HEADER_BUFFER_IDX(hw->buffer_wrap[pic_config->index]),
+ hw->buffer_wrap[pic_config->index],
+ pic_config->header_dw_adr);
+ }
+#endif
+
+ if (debug & AV1_DEBUG_BUFMGR_MORE) {
+ pr_info("MMU header_adr %d: %d\n",
+ hw->buffer_wrap[pic_config->index], pic_config->header_adr);
+ }
+ }
+#endif
+
+ i = pic_config->index;
+#ifdef MV_USE_FIXED_BUF
+ if ((hw->work_space_buf->mpred_mv.buf_start +
+ ((i + 1) * mv_buffer_size))
+ <= mpred_mv_end
+ ) {
+#endif
+ if (buf_size > 0) {
+ ret = decoder_bmmu_box_alloc_buf_phy(hw->bmmu_box,
+ VF_BUFFER_IDX(hw->buffer_wrap[i]),
+ buf_size, DRIVER_NAME,
+ &pic_config->cma_alloc_addr);
+ if (ret < 0) {
+ pr_info(
+ "decoder_bmmu_box_alloc_buf_phy idx %d size %d fail\n",
+ VF_BUFFER_IDX(hw->buffer_wrap[i]),
+ buf_size
+ );
+ return ret;
+ }
+
+ if (pic_config->cma_alloc_addr)
+ y_adr = pic_config->cma_alloc_addr;
+ else {
+ pr_info(
+ "decoder_bmmu_box_alloc_buf_phy idx %d size %d return null\n",
+ VF_BUFFER_IDX(hw->buffer_wrap[i]),
+ buf_size
+ );
+ return -1;
+ }
+ }
+ {
+ /*ensure get_pic_by_POC()
+ not get the buffer not decoded*/
+ pic_config->BUF_index = i;
+ pic_config->lcu_total = lcu_total;
+
+ pic_config->comp_body_size = losless_comp_body_size;
+ pic_config->buf_size = buf_size;
+
+ pic_config->mc_canvas_y = pic_config->index;
+ pic_config->mc_canvas_u_v = pic_config->index;
+ if (dw_mode & 0x10) {
+ pic_config->dw_y_adr = y_adr;
+ pic_config->dw_u_v_adr = y_adr +
+ ((mc_buffer_size_u_v_h << 16) << 1);
+
+ pic_config->mc_canvas_y =
+ (pic_config->index << 1);
+ pic_config->mc_canvas_u_v =
+ (pic_config->index << 1) + 1;
+ } else if (dw_mode && (dw_mode & 0x20) == 0) {
+ pic_config->dw_y_adr = y_adr;
+ pic_config->dw_u_v_adr = pic_config->dw_y_adr +
+ ((mc_buffer_size_u_v_h << 16) << 1);
+ }
+#ifdef MV_USE_FIXED_BUF
+ pic_config->mpred_mv_wr_start_addr =
+ hw->work_space_buf->mpred_mv.buf_start +
+ (pic_config->index * mv_buffer_size);
+#endif
+#ifdef DUMP_FILMGRAIN
+ if (pic_config->index == fg_dump_index) {
+ pic_config->fgs_table_adr = hw->fg_phy_addr;
+ pr_info("set buffer %d film grain table 0x%x\n",
+ pic_config->index, pic_config->fgs_table_adr);
+ } else
+#endif
+ pic_config->fgs_table_adr =
+ hw->work_space_buf->fgs_table.buf_start +
+ (pic_config->index * FGS_TABLE_SIZE);
+
+ if (debug) {
+ pr_info
+ ("%s index %d BUF_index %d ",
+ __func__, pic_config->index,
+ pic_config->BUF_index);
+ pr_info
+ ("comp_body_size %x comp_buf_size %x ",
+ pic_config->comp_body_size,
+ pic_config->buf_size);
+ pr_info
+ ("mpred_mv_wr_start_adr %d\n",
+ pic_config->mpred_mv_wr_start_addr);
+ pr_info("dw_y_adr %d, pic_config->dw_u_v_adr =%d\n",
+ pic_config->dw_y_adr,
+ pic_config->dw_u_v_adr);
+ }
+ ret = 0;
+ }
+#ifdef MV_USE_FIXED_BUF
+ }
+#endif
+ return ret;
+}
+
+#ifndef USE_SPEC_BUF_FOR_MMU_HEAD
+static int vav1_mmu_compress_header_size(struct AV1HW_s *hw)
+{
+ if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
+ IS_8K_SIZE(hw->max_pic_w, hw->max_pic_h))
+ return (MMU_COMPRESS_HEADER_SIZE_8K);
+
+ if (IS_4K_SIZE(hw->max_pic_w, hw->max_pic_h))
+ return MMU_COMPRESS_HEADER_SIZE_4K;
+
+ return (MMU_COMPRESS_HEADER_SIZE_1080P);
+}
+#endif
+/*#define FRAME_MMU_MAP_SIZE (MAX_FRAME_4K_NUM * 4)*/
+static int vav1_frame_mmu_map_size(struct AV1HW_s *hw)
+{
+ if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
+ IS_8K_SIZE(hw->max_pic_w, hw->max_pic_h))
+ return (MAX_FRAME_8K_NUM * 4);
+
+ return (MAX_FRAME_4K_NUM * 4);
+}
+
+#ifdef AOM_AV1_MMU_DW
+static int vaom_dw_frame_mmu_map_size(struct AV1HW_s *hw)
+{
+ if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
+ IS_8K_SIZE(hw->max_pic_w, hw->max_pic_h))
+ return (MAX_FRAME_8K_NUM * 4);
+
+ return (MAX_FRAME_4K_NUM * 4);
+}
+#endif
+
+static void init_pic_list(struct AV1HW_s *hw)
+{
+ int i;
+ struct AV1_Common_s *cm = &hw->common;
+ struct PIC_BUFFER_CONFIG_s *pic_config;
+ struct vdec_s *vdec = hw_to_vdec(hw);
+
+#ifndef USE_SPEC_BUF_FOR_MMU_HEAD
+ u32 header_size;
+ if (hw->mmu_enable && ((hw->double_write_mode & 0x10) == 0)) {
+ header_size = vav1_mmu_compress_header_size(hw);
+ /*alloc AV1 compress header first*/
+ for (i = 0; i < hw->used_buf_num; i++) {
+ unsigned long buf_addr;
+ if (decoder_bmmu_box_alloc_buf_phy
+ (hw->bmmu_box,
+ HEADER_BUFFER_IDX(i), header_size,
+ DRIVER_HEADER_NAME,
+ &buf_addr) < 0) {
+ av1_print(hw, 0, "%s malloc compress header failed %d\n",
+ DRIVER_HEADER_NAME, i);
+ hw->fatal_error |= DECODER_FATAL_ERROR_NO_MEM;
+ return;
+ }
+#ifdef AOM_AV1_MMU_DW
+ if (hw->dw_mmu_enable) {
+ if (decoder_bmmu_box_alloc_buf_phy
+ (hw->bmmu_box,
+ DW_HEADER_BUFFER_IDX(i), header_size,
+ DRIVER_HEADER_NAME,
+ &buf_addr) < 0) {
+ av1_print(hw, 0, "%s malloc compress dw header failed %d\n",
+ DRIVER_HEADER_NAME, i);
+ hw->fatal_error |= DECODER_FATAL_ERROR_NO_MEM;
+ return;
+ }
+ }
+#endif
+ }
+ }
+#endif
+ for (i = 0; i < hw->used_buf_num; i++) {
+ pic_config = &cm->buffer_pool->frame_bufs[i].buf;
+ pic_config->index = i;
+ pic_config->BUF_index = -1;
+ pic_config->mv_buf_index = -1;
+ if (vdec->parallel_dec == 1) {
+ pic_config->y_canvas_index = -1;
+ pic_config->uv_canvas_index = -1;
+ }
+ pic_config->y_crop_width = hw->init_pic_w;
+ pic_config->y_crop_height = hw->init_pic_h;
+ pic_config->double_write_mode = get_double_write_mode(hw);
+ hw->buffer_wrap[i] = i;
+
+ if (!hw->is_used_v4l) {
+ if (config_pic(hw, pic_config) < 0) {
+ if (debug)
+ av1_print(hw, 0, "Config_pic %d fail\n",
+ pic_config->index);
+ pic_config->index = -1;
+ break;
+ }
+
+ if (pic_config->double_write_mode &&
+ (pic_config->double_write_mode & 0x20) == 0) {
+ set_canvas(hw, pic_config);
+ }
+ }
+ }
+ for (; i < hw->used_buf_num; i++) {
+ pic_config = &cm->buffer_pool->frame_bufs[i].buf;
+ pic_config->index = -1;
+ pic_config->BUF_index = -1;
+ pic_config->mv_buf_index = -1;
+ hw->buffer_wrap[i] = i;
+ if (vdec->parallel_dec == 1) {
+ pic_config->y_canvas_index = -1;
+ pic_config->uv_canvas_index = -1;
+ }
+ }
+ av1_print(hw, AV1_DEBUG_BUFMGR, "%s ok, used_buf_num = %d\n",
+ __func__, hw->used_buf_num);
+
+}
+
+static void init_pic_list_hw(struct AV1HW_s *hw)
+{
+ int i;
+ struct AV1_Common_s *cm = &hw->common;
+ struct PIC_BUFFER_CONFIG_s *pic_config;
+ /*WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0x0);*/
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR,
+ (0x1 << 1) | (0x1 << 2));
+
+
+ for (i = 0; i < hw->used_buf_num; i++) {
+ pic_config = &cm->buffer_pool->frame_bufs[i].buf;
+ if (pic_config->index < 0)
+ break;
+
+ if (hw->mmu_enable && ((pic_config->double_write_mode & 0x10) == 0)) {
+
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA,
+ pic_config->header_adr >> 5);
+ } else {
+ /*WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
+ * pic_config->mc_y_adr
+ * | (pic_config->mc_canvas_y << 8) | 0x1);
+ */
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA,
+ pic_config->dw_y_adr >> 5);
+ }
+#ifndef LOSLESS_COMPRESS_MODE
+ /*WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
+ * pic_config->mc_u_v_adr
+ * | (pic_config->mc_canvas_u_v << 8)| 0x1);
+ */
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA,
+ pic_config->dw_u_v_adr >> 5);
+#else
+ if (pic_config->double_write_mode & 0x10) {
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA,
+ pic_config->dw_u_v_adr >> 5);
+ }
+#endif
+ }
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0x1);
+
+#ifdef CHANGE_REMOVED
+ /*Zero out canvas registers in IPP -- avoid simulation X*/
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
+ (0 << 8) | (0 << 1) | 1);
+#else
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
+ (1 << 8) | (0 << 1) | 1);
+#endif
+ for (i = 0; i < 32; i++)
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0);
+}
+
+
+static void dump_pic_list(struct AV1HW_s *hw)
+{
+ struct AV1_Common_s *const cm = &hw->common;
+ struct PIC_BUFFER_CONFIG_s *pic_config;
+ int i;
+ for (i = 0; i < FRAME_BUFFERS; i++) {
+ pic_config = &cm->buffer_pool->frame_bufs[i].buf;
+ av1_print(hw, 0,
+ "Buf(%d) index %d mv_buf_index %d ref_count %d vf_ref %d dec_idx %d slice_type %d w/h %d/%d adr%ld\n",
+ i,
+ pic_config->index,
+#ifndef MV_USE_FIXED_BUF
+ pic_config->mv_buf_index,
+#else
+ -1,
+#endif
+ cm->buffer_pool->
+ frame_bufs[i].ref_count,
+ pic_config->vf_ref,
+ pic_config->decode_idx,
+ pic_config->slice_type,
+ pic_config->y_crop_width,
+ pic_config->y_crop_height,
+ pic_config->cma_alloc_addr
+ );
+ }
+ return;
+}
+
+void av1_release_buf(AV1Decoder *pbi, RefCntBuffer *const buf)
+{
+
+#if 0
+ //def CHANGE_DONE
+ struct AV1HW_s *hw = (struct AV1HW_s *)(pbi->private_data);
+ if (!hw->mmu_enable)
+ return;
+ //release_buffer_4k(&av1_mmumgr_m, buf->buf.index);
+ decoder_mmu_box_free_idx(hw->mmu_box, buf->buf.index);
+#ifdef AOM_AV1_MMU_DW
+ //release_buffer_4k(&av1_mmumgr_dw, buf->buf.index);
+ decoder_mmu_box_free_idx(hw->mmu_box_dw, buf->buf.index);
+#endif
+
+#endif
+}
+
+void av1_release_bufs(struct AV1HW_s *hw)
+{
+ AV1_COMMON *cm = &hw->common;
+ RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
+ int i;
+
+ for (i = 0; i < FRAME_BUFFERS; ++i) {
+ if (frame_bufs[i].buf.vf_ref == 0 &&
+ frame_bufs[i].ref_count == 0 &&
+ frame_bufs[i].buf.index >= 0) {
+ if (frame_bufs[i].buf.aux_data_buf)
+ release_aux_data(hw, &frame_bufs[i].buf);
+ }
+ }
+}
+
+#ifdef DEBUG_CMD
+static void d_fill_zero(struct AV1HW_s *hw, unsigned int phyadr, int size)
+{
+ WRITE_VREG(HEVC_DBG_LOG_ADR, phyadr);
+ WRITE_VREG(DEBUG_REG1,
+ 0x20000000 | size);
+ debug_cmd_wait_count = 0;
+ debug_cmd_wait_type = 1;
+ while ((READ_VREG(DEBUG_REG1) & 0x1) == 0
+ && debug_cmd_wait_count < 0x7fffffff) {
+ debug_cmd_wait_count++;
+ }
+
+ WRITE_VREG(DEBUG_REG1, 0);
+ debug_cmd_wait_type = 0;
+}
+
+static void d_dump(struct AV1HW_s *hw, unsigned int phyadr, int size,
+ struct file *fp, loff_t *wr_off)
+{
+
+ int jj;
+ unsigned char *data = (unsigned char *)
+ (hw->ucode_log_addr);
+ WRITE_VREG(HEVC_DBG_LOG_ADR, hw->ucode_log_phy_addr);
+
+ WRITE_VREG(HEVC_D_ADR, phyadr);
+ WRITE_VREG(DEBUG_REG1,
+ 0x10000000 | size);
+
+ debug_cmd_wait_count = 0;
+ debug_cmd_wait_type = 3;
+ while ((READ_VREG(DEBUG_REG1) & 0x1) == 0
+ && debug_cmd_wait_count < 0x7fffffff) {
+ debug_cmd_wait_count++;
+ }
+
+ if (fp) {
+ vfs_write(fp, data,
+ size, wr_off);
+
+ } else {
+ for (jj = 0; jj < size; jj++) {
+ if ((jj & 0xf) == 0)
+ av1_print(hw, 0,
+ "%06x:", jj);
+ av1_print_cont(hw, 0,
+ "%02x ", data[jj]);
+ if (((jj + 1) & 0xf) == 0)
+ av1_print_cont(hw, 0,
+ "\n");
+ }
+ av1_print(hw, 0, "\n");
+ }
+
+ WRITE_VREG(DEBUG_REG1, 0);
+ debug_cmd_wait_type = 0;
+
+}
+
+static void mv_buffer_fill_zero(struct AV1HW_s *hw, struct PIC_BUFFER_CONFIG_s *pic_config)
+{
+ pr_info("fill dummy data pic index %d colocate addreses %x size %x\n",
+ pic_config->index, pic_config->mpred_mv_wr_start_addr,
+ hw->m_mv_BUF[pic_config->mv_buf_index].size);
+ d_fill_zero(hw, pic_config->mpred_mv_wr_start_addr,
+ hw->m_mv_BUF[pic_config->mv_buf_index].size);
+}
+
+static void dump_mv_buffer(struct AV1HW_s *hw, struct PIC_BUFFER_CONFIG_s *pic_config)
+{
+
+ unsigned int adr, size;
+ unsigned int adr_end = pic_config->mpred_mv_wr_start_addr +
+ hw->m_mv_BUF[pic_config->mv_buf_index].size;
+ mm_segment_t old_fs;
+ loff_t off = 0;
+ int mode = O_CREAT | O_WRONLY | O_TRUNC;
+ char file[64];
+ struct file *fp;
+ sprintf(&file[0], "/data/tmp/colocate%d", hw->frame_count-1);
+ fp = filp_open(file, mode, 0666);
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ for (adr = pic_config->mpred_mv_wr_start_addr;
+ adr < adr_end;
+ adr += UCODE_LOG_BUF_SIZE) {
+ size = UCODE_LOG_BUF_SIZE;
+ if (size > (adr_end - adr))
+ size = adr_end - adr;
+ pr_info("dump pic index %d colocate addreses %x size %x\n",
+ pic_config->index, adr, size);
+ d_dump(hw, adr, size, fp, &off);
+ }
+ set_fs(old_fs);
+ vfs_fsync(fp, 0);
+
+ filp_close(fp, current->files);
+}
+
+#endif
+
+static int config_pic_size(struct AV1HW_s *hw, unsigned short bit_depth)
+{
+ uint32_t data32;
+ struct AV1_Common_s *cm = &hw->common;
+ struct PIC_BUFFER_CONFIG_s *cur_pic_config = &cm->cur_frame->buf;
+ int losless_comp_header_size, losless_comp_body_size;
+#ifdef AOM_AV1_MMU_DW
+ int losless_comp_header_size_dw, losless_comp_body_size_dw;
+#endif
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ " #### config_pic_size ####, bit_depth = %d\n", bit_depth);
+
+ frame_width = cur_pic_config->y_crop_width;
+ frame_height = cur_pic_config->y_crop_height;
+ cur_pic_config->bit_depth = bit_depth;
+ cur_pic_config->double_write_mode = get_double_write_mode(hw);
+
+ /* use fixed maximum size // 128x128/4/4*3-bits = 384 Bytes
+ seg_map_size =
+ ((frame_width + 127) >> 7) * ((frame_height + 127) >> 7) * 384 ;
+ */
+ WRITE_VREG(HEVC_PARSER_PICTURE_SIZE,
+ (frame_height << 16) | frame_width);
+#ifdef DUAL_DECODE
+#else
+ WRITE_VREG(HEVC_ASSIST_PIC_SIZE_FB_READ,
+ (frame_height << 16) | frame_width);
+#endif
+#ifdef AOM_AV1_MMU
+
+ //alloc_mmu(&av1_mmumgr_m, cm->cur_frame->buf.index, frame_width, frame_height, bit_depth);
+#endif
+#ifdef AOM_AV1_MMU_DW
+
+ //alloc_mmu(&av1_mmumgr_dw, cm->cur_frame->buf.index, frame_width, frame_height, bit_depth);
+ losless_comp_header_size_dw =
+ compute_losless_comp_header_size_dw(frame_width, frame_height);
+ losless_comp_body_size_dw =
+ compute_losless_comp_body_size_dw(frame_width, frame_height,
+ (bit_depth == AOM_BITS_10));
+#endif
+
+ losless_comp_header_size =
+ compute_losless_comp_header_size
+ (frame_width, frame_height);
+ losless_comp_body_size =
+ compute_losless_comp_body_size(frame_width,
+ frame_height, (bit_depth == AOM_BITS_10));
+
+ cur_pic_config->comp_body_size = losless_comp_body_size;
+
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "%s: width %d height %d depth %d head_size 0x%x body_size 0x%x\r\n",
+ __func__, frame_width, frame_height, bit_depth,
+ losless_comp_header_size, losless_comp_body_size);
+#ifdef LOSLESS_COMPRESS_MODE
+ data32 = READ_VREG(HEVC_SAO_CTRL5);
+ if (bit_depth == AOM_BITS_10)
+ data32 &= ~(1<<9);
+ else
+ data32 |= (1<<9);
+
+ WRITE_VREG(HEVC_SAO_CTRL5, data32);
+
+ if (hw->mmu_enable) {
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1,(0x1<< 4)); // bit[4] : paged_mem_mode
+ } else {
+ if (bit_depth == AOM_BITS_10)
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0<<3)); // bit[3] smem mdoe
+ else
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (1<<3)); // bit[3] smem mdoe
+ }
+ 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);
+
+ if (get_double_write_mode(hw) & 0x10)
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31);
+
+#else
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1,0x1 << 31);
+#endif
+#ifdef AOM_AV1_MMU_DW
+ if (hw->dw_mmu_enable) {
+ WRITE_VREG(HEVC_CM_BODY_LENGTH2, losless_comp_body_size_dw);
+ WRITE_VREG(HEVC_CM_HEADER_OFFSET2, losless_comp_body_size_dw);
+ WRITE_VREG(HEVC_CM_HEADER_LENGTH2, losless_comp_header_size_dw);
+ }
+#endif
+ return 0;
+
+}
+
+static int config_mc_buffer(struct AV1HW_s *hw, unsigned short bit_depth, unsigned char inter_flag)
+{
+ int32_t i;
+ AV1_COMMON *cm = &hw->common;
+ PIC_BUFFER_CONFIG* cur_pic_config = &cm->cur_frame->buf;
+ uint8_t scale_enable = 0;
+
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ " #### config_mc_buffer %s ####\n",
+ inter_flag ? "inter" : "intra");
+
+#ifdef DEBUG_PRINT
+ if (debug&AOM_AV1_DEBUG_BUFMGR)
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "config_mc_buffer entered .....\n");
+#endif
+
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
+ (0 << 8) | (0<<1) | 1);
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR,
+ (cur_pic_config->order_hint<<24) |
+ (cur_pic_config->mc_canvas_u_v<<16) |
+ (cur_pic_config->mc_canvas_u_v<<8)|
+ cur_pic_config->mc_canvas_y);
+ for (i = LAST_FRAME; i <= ALTREF_FRAME; i++) {
+ PIC_BUFFER_CONFIG *pic_config; //cm->frame_refs[i].buf;
+ if (inter_flag)
+ pic_config = av1_get_ref_frame_spec_buf(cm, i);
+ else
+ pic_config = cur_pic_config;
+ if (pic_config) {
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR,
+ (pic_config->order_hint<<24) |
+ (pic_config->mc_canvas_u_v<<16) |
+ (pic_config->mc_canvas_u_v<<8) |
+ pic_config->mc_canvas_y);
+ if (inter_flag)
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "refid 0x%x mc_canvas_u_v 0x%x mc_canvas_y 0x%x order_hint 0x%x\n",
+ i, pic_config->mc_canvas_u_v,
+ pic_config->mc_canvas_y, pic_config->order_hint);
+ } else {
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0);
+ }
+ }
+
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
+ (16 << 8) | (0 << 1) | 1);
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR,
+ (cur_pic_config->order_hint << 24) |
+ (cur_pic_config->mc_canvas_u_v << 16) |
+ (cur_pic_config->mc_canvas_u_v << 8) |
+ cur_pic_config->mc_canvas_y);
+ for (i = LAST_FRAME; i <= ALTREF_FRAME; i++) {
+ PIC_BUFFER_CONFIG *pic_config;
+ if (inter_flag)
+ pic_config = av1_get_ref_frame_spec_buf(cm, i);
+ else
+ pic_config = cur_pic_config;
+
+ if (pic_config) {
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR,
+ (pic_config->order_hint << 24)|
+ (pic_config->mc_canvas_u_v << 16) |
+ (pic_config->mc_canvas_u_v << 8) |
+ pic_config->mc_canvas_y);
+ } else {
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0);
+ }
+ }
+
+ WRITE_VREG(AV1D_MPP_REFINFO_TBL_ACCCONFIG,
+ (0x1 << 2) | (0x0 <<3)); // auto_inc start index:0 field:0
+ for (i = 0; i <= ALTREF_FRAME; i++) {
+ int32_t ref_pic_body_size;
+ struct scale_factors * sf = NULL;
+ PIC_BUFFER_CONFIG *pic_config;
+
+ if (inter_flag && i >= LAST_FRAME)
+ pic_config = av1_get_ref_frame_spec_buf(cm, i);
+ else
+ pic_config = cur_pic_config;
+
+ if (pic_config) {
+ ref_pic_body_size =
+ compute_losless_comp_body_size(pic_config->y_crop_width,
+ pic_config->y_crop_height, (bit_depth == AOM_BITS_10));
+
+ WRITE_VREG(AV1D_MPP_REFINFO_DATA, pic_config->y_crop_width);
+ WRITE_VREG(AV1D_MPP_REFINFO_DATA, pic_config->y_crop_height);
+ if (inter_flag && i >= LAST_FRAME) {
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "refid %d: ref width/height(%d,%d), cur width/height(%d,%d) ref_pic_body_size 0x%x\n",
+ i, pic_config->y_crop_width, pic_config->y_crop_height,
+ cur_pic_config->y_crop_width, cur_pic_config->y_crop_height,
+ ref_pic_body_size);
+ }
+ } else {
+ ref_pic_body_size = 0;
+ WRITE_VREG(AV1D_MPP_REFINFO_DATA, 0);
+ WRITE_VREG(AV1D_MPP_REFINFO_DATA, 0);
+ }
+
+ if (inter_flag && i >= LAST_FRAME)
+ sf = av1_get_ref_scale_factors(cm, i);
+
+ if ((sf != NULL) && av1_is_scaled(sf)) {
+ scale_enable |= (1 << i);
+ }
+
+ if (sf) {
+ WRITE_VREG(AV1D_MPP_REFINFO_DATA, sf->x_scale_fp);
+ WRITE_VREG(AV1D_MPP_REFINFO_DATA, sf->y_scale_fp);
+
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "x_scale_fp %d, y_scale_fp %d\n",
+ sf->x_scale_fp, sf->y_scale_fp);
+ } else {
+ WRITE_VREG(AV1D_MPP_REFINFO_DATA, REF_NO_SCALE); //1<<14
+ WRITE_VREG(AV1D_MPP_REFINFO_DATA, REF_NO_SCALE);
+ }
+ if (hw->mmu_enable)
+ WRITE_VREG(AV1D_MPP_REFINFO_DATA, 0);
+ else
+ WRITE_VREG(AV1D_MPP_REFINFO_DATA,
+ ref_pic_body_size >> 5);
+ }
+ WRITE_VREG(AV1D_MPP_REF_SCALE_ENBL, scale_enable);
+ WRITE_VREG(PARSER_REF_SCALE_ENBL, scale_enable);
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "WRITE_VREG(PARSER_REF_SCALE_ENBL, 0x%x)\n",
+ scale_enable);
+ return 0;
+}
+
+static void clear_mpred_hw(struct AV1HW_s *hw)
+{
+ unsigned int data32;
+
+ data32 = READ_VREG(HEVC_MPRED_CTRL4);
+ data32 &= (~(1 << 6));
+ WRITE_VREG(HEVC_MPRED_CTRL4, data32);
+}
+
+static void config_mpred_hw(struct AV1HW_s *hw, unsigned char inter_flag)
+{
+ AV1_COMMON *cm = &hw->common;
+ PIC_BUFFER_CONFIG *cur_pic_config = &cm->cur_frame->buf;
+ //PIC_BUFFER_CONFIG *last_frame_pic_config = NULL;
+ int i, j, pos, reg_i;
+ int mv_cal_tpl_count = 0;
+ unsigned int mv_ref_id[MFMV_STACK_SIZE] = {0, 0, 0};
+ unsigned ref_offset_reg[] = {
+ HEVC_MPRED_L0_REF06_POC,
+ HEVC_MPRED_L0_REF07_POC,
+ HEVC_MPRED_L0_REF08_POC,
+ HEVC_MPRED_L0_REF09_POC,
+ HEVC_MPRED_L0_REF10_POC,
+ HEVC_MPRED_L0_REF11_POC,
+ };
+ unsigned ref_buf_reg[] = {
+ HEVC_MPRED_L0_REF03_POC,
+ HEVC_MPRED_L0_REF04_POC,
+ HEVC_MPRED_L0_REF05_POC
+ };
+ unsigned ref_offset_val[6] =
+ {0, 0, 0, 0, 0, 0};
+ unsigned ref_buf_val[3] = {0, 0, 0};
+
+ uint32_t data32;
+ int32_t mpred_curr_lcu_x;
+ int32_t mpred_curr_lcu_y;
+ //int32_t mpred_mv_rd_end_addr;
+
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ " #### config_mpred_hw ####\n");
+
+ /*if (cm->prev_frame)
+ last_frame_pic_config = &cm->prev_frame->buf;
+ mpred_mv_rd_end_addr = last_frame_pic_config->mpred_mv_wr_start_addr
+ + (last_frame_pic_config->lcu_total * MV_MEM_UNIT);
+ */
+
+ data32 = READ_VREG(HEVC_MPRED_CURR_LCU);
+ mpred_curr_lcu_x =data32 & 0xffff;
+ mpred_curr_lcu_y =(data32>>16) & 0xffff;
+
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "cur pic index %d\n", cur_pic_config->index);
+ /*printk("cur pic index %d col pic index %d\n",
+ cur_pic_config->index, last_frame_pic_config->index);*/
+
+ //WRITE_VREG(HEVC_MPRED_CTRL3,0x24122412);
+ WRITE_VREG(HEVC_MPRED_CTRL3, 0x13151315); // 'd19, 'd21 for AV1
+ WRITE_VREG(HEVC_MPRED_ABV_START_ADDR,
+ hw->pbi->work_space_buf->mpred_above.buf_start);
+
+#if 0
+ data32 = READ_VREG(HEVC_MPRED_CTRL4);
+ data32 &= (~(1<<6));
+ data32 |= (cm->use_prev_frame_mvs << 6);
+ WRITE_VREG(HEVC_MPRED_CTRL4, data32);
+#endif
+ if (inter_flag) {
+ /* config sign_bias */
+ //data32 = (cm->cur_frame_force_integer_mv & 0x1) << 9;
+ data32 = READ_VREG(HEVC_MPRED_CTRL4);
+ data32 &= (~(0xff << 12));
+ //for (i = LAST_FRAME; i <= ALTREF_FRAME; i++) {
+ /* HEVC_MPRED_CTRL4[bit 12] is for cm->ref_frame_sign_bias[0]
+ instead of cm->ref_frame_sign_bias[LAST_FRAME] */
+ for (i = 0; i <= ALTREF_FRAME; i++) {
+ data32 |= ((cm->ref_frame_sign_bias[i] & 0x1) << (12 + i));
+ }
+ WRITE_VREG(HEVC_MPRED_CTRL4, data32);
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "WRITE_VREG(HEVC_MPRED_CTRL4, 0x%x)\n", data32);
+ }
+#if 1
+ data32 = (
+ (cm->seq_params.order_hint_info.enable_order_hint << 27) |
+ (cm->seq_params.order_hint_info.order_hint_bits_minus_1 << 24) |
+ (cm->cur_frame->order_hint <<16 ) |
+ (0x13 << 8) | (0x13 << 0));
+#else
+ data32 = READ_VREG(HEVC_MPRED_L0_REF00_POC);
+ data32 &= (~(0xff << 16));
+ data32 |= (cm->cur_frame->order_hint & 0xff);
+ data32 &= (~(1 << 27));
+ data32 |= (cm->seq_params.order_hint_info.enable_order_hint << 27);
+#endif
+ WRITE_VREG(HEVC_MPRED_L0_REF00_POC, data32);
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "WRITE_VREG(HEVC_MPRED_L0_REF00_POC, 0x%x)\n", data32);
+
+ if (inter_flag) {
+ /* config ref_buf id and order hint */
+ data32 = 0;
+ pos = 25;
+ reg_i = 0;
+ for (i = ALTREF_FRAME; i >= LAST_FRAME; i--) {
+ PIC_BUFFER_CONFIG *pic_config =
+ av1_get_ref_frame_spec_buf(cm, i);
+ if (pic_config) {
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "pic_config for %d th ref: index %d, reg[%d] pos %d\n",
+ i, pic_config->index, reg_i, pos);
+ data32 |= ((pic_config->index < 0)? 0 : pic_config->index) << pos;
+ } else
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "pic_config is null for %d th ref\n", i);
+ if (pos == 0) {
+ //WRITE_VREG(ref_buf_reg[reg_i], data32);
+ ref_buf_val[reg_i] = data32;
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "ref_buf_reg[%d], WRITE_VREG(0x%x, 0x%x)\n",
+ reg_i, ref_buf_reg[reg_i], data32);
+ reg_i++;
+ data32 = 0;
+ pos = 24; //for P_HEVC_MPRED_L0_REF04_POC
+ } else {
+ if (pos == 24)
+ pos -= 8; //for P_HEVC_MPRED_L0_REF04_POC
+ else
+ pos -= 5; //for P_HEVC_MPRED_L0_REF03_POC
+ }
+ }
+ for (i = ALTREF_FRAME; i >= LAST_FRAME; i--) {
+ PIC_BUFFER_CONFIG *pic_config =
+ av1_get_ref_frame_spec_buf(cm, i);
+ if (pic_config) {
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "pic_config for %d th ref: order_hint %d, reg[%d] pos %d\n",
+ i, pic_config->order_hint, reg_i, pos);
+ data32 |= ((pic_config->index < 0)? 0 : pic_config->order_hint) << pos;
+ } else
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "pic_config is null for %d th ref\n", i);
+ if (pos == 0) {
+ //WRITE_VREG(ref_buf_reg[reg_i], data32);
+ ref_buf_val[reg_i] = data32;
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "ref_buf_reg[%d], WRITE_VREG(0x%x, 0x%x)\n",
+ reg_i, ref_buf_reg[reg_i], data32);
+ reg_i++;
+ data32 = 0;
+ pos = 24;
+ } else
+ pos -= 8;
+ }
+ if (pos != 24) {
+ //WRITE_VREG(ref_buf_reg[reg_i], data32);
+ ref_buf_val[reg_i] = data32;
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "ref_buf_reg[%d], WRITE_VREG(0x%x, 0x%x)\n",
+ reg_i, ref_buf_reg[reg_i], data32);
+ }
+ /* config ref_offset */
+ data32 = 0;
+ pos = 24;
+ mv_cal_tpl_count = 0;
+ reg_i = 0;
+ for (i = 0; i < cm->mv_ref_id_index; i++) {
+ if (cm->mv_cal_tpl_mvs[i]) {
+ mv_ref_id[mv_cal_tpl_count] = cm->mv_ref_id[i];
+ mv_cal_tpl_count++;
+ for (j = LAST_FRAME; j <= ALTREF_FRAME; j++) {
+ /*offset can be negative*/
+ unsigned char offval =
+ cm->mv_ref_offset[i][j] & 0xff;
+ data32 |= (offval << pos);
+ if (pos == 0) {
+ //WRITE_VREG(ref_offset_reg[reg_i], data32);
+ ref_offset_val[reg_i] = data32;
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "ref_offset_reg[%d], WRITE_VREG(0x%x, 0x%x)\n",
+ reg_i, ref_offset_reg[reg_i], data32);
+ reg_i++;
+ data32 = 0;
+ pos = 24;
+ } else
+ pos -= 8;
+ }
+ }
+ }
+ if (pos != 24) {
+ //WRITE_VREG(ref_offset_reg[reg_i], data32);
+ ref_offset_val[reg_i] = data32;
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "ref_offset_reg[%d], WRITE_VREG(0x%x, 0x%x)\n",
+ reg_i, ref_offset_reg[reg_i], data32);
+ }
+
+ data32 = ref_offset_val[5] | //READ_VREG(HEVC_MPRED_L0_REF11_POC) |
+ mv_cal_tpl_count | (mv_ref_id[0] << 2) |
+ (mv_ref_id[1] << 5) | (mv_ref_id[2] << 8);
+ ref_offset_val[5] = data32;
+ //WRITE_VREG(HEVC_MPRED_L0_REF11_POC, data32);
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "WRITE_VREG(HEVC_MPRED_L0_REF11_POC 0x%x, 0x%x)\n",
+ HEVC_MPRED_L0_REF11_POC, data32);
+ }
+ for (i = 0; i < 3; i++)
+ WRITE_VREG(ref_buf_reg[i], ref_buf_val[i]);
+ for (i = 0; i < 6; i++)
+ WRITE_VREG(ref_offset_reg[i], ref_offset_val[i]);
+
+ WRITE_VREG(HEVC_MPRED_MV_WR_START_ADDR,
+ cur_pic_config->mpred_mv_wr_start_addr);
+ WRITE_VREG(HEVC_MPRED_MV_WPTR,
+ cur_pic_config->mpred_mv_wr_start_addr);
+
+ if ((inter_flag) && (mv_cal_tpl_count <= 3)) {
+ for (i = 0; i < mv_cal_tpl_count; i++) {
+ PIC_BUFFER_CONFIG *pic_config =
+ av1_get_ref_frame_spec_buf(cm, mv_ref_id[i]);
+ if (pic_config == NULL)
+ continue;
+ if (i == 0) {
+ WRITE_VREG(HEVC_MPRED_MV_RD_START_ADDR,
+ pic_config->mpred_mv_wr_start_addr);
+ WRITE_VREG(HEVC_MPRED_MV_RPTR,
+ pic_config->mpred_mv_wr_start_addr);
+ } else if (i == 1) {
+ WRITE_VREG(HEVC_MPRED_L0_REF01_POC,
+ pic_config->mpred_mv_wr_start_addr);
+ WRITE_VREG(HEVC_MPRED_MV_RPTR_1,
+ pic_config->mpred_mv_wr_start_addr);
+ } else if (i == 2) {
+ WRITE_VREG(HEVC_MPRED_L0_REF02_POC,
+ pic_config->mpred_mv_wr_start_addr);
+ WRITE_VREG(HEVC_MPRED_MV_RPTR_2,
+ pic_config->mpred_mv_wr_start_addr);
+ }
+ }
+ }
+ data32 = READ_VREG(HEVC_MPRED_CTRL0);
+ data32 &= ~((1 << 10) | (1 << 11));
+ data32 |= (1 << 10); /*write enable*/
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "current_frame.frame_type=%d, cur_frame->frame_type=%d, allow_ref_frame_mvs=%d\n",
+ cm->current_frame.frame_type, cm->cur_frame->frame_type,
+ cm->allow_ref_frame_mvs);
+
+ if (av1_frame_is_inter(&hw->common)) {
+ if (cm->allow_ref_frame_mvs) {
+ data32 |= (1 << 11); /*read enable*/
+ }
+ }
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "WRITE_VREG(HEVC_MPRED_CTRL0 0x%x, 0x%x)\n",
+ HEVC_MPRED_CTRL0, data32);
+ WRITE_VREG(HEVC_MPRED_CTRL0, data32);
+ /*
+ printk("config_mpred: (%x) wr_start_addr %x from indx %d;
+ (%x) rd_start_addr %x from index %d\n",
+ cur_pic_config, cur_pic_config->mpred_mv_wr_start_addr, cur_pic_config->index,
+ last_frame_pic_config, last_frame_pic_config->mpred_mv_wr_start_addr, last_frame_pic_config->index);
+ data32 = ((pbi->lcu_x_num - pbi->tile_width_lcu)*MV_MEM_UNIT);
+ WRITE_VREG(HEVC_MPRED_MV_WR_ROW_JUMP,data32);
+ WRITE_VREG(HEVC_MPRED_MV_RD_ROW_JUMP,data32);
+
+ WRITE_VREG(HEVC_MPRED_MV_RD_END_ADDR, mpred_mv_rd_end_addr);
+ */
+}
+
+static void config_sao_hw(struct AV1HW_s *hw, union param_u *params)
+{
+ /*
+ !!!!!!!!!!!!!!!!!!!!!!!!!TODO .... !!!!!!!!!!!
+ mem_map_mode, endian, get_double_write_mode
+ */
+ AV1_COMMON *cm = &hw->common;
+ PIC_BUFFER_CONFIG* pic_config = &cm->cur_frame->buf;
+ uint32_t data32;
+ int32_t lcu_size =
+ ((params->p.seq_flags >> 6) & 0x1) ? 128 : 64;
+ int32_t mc_buffer_size_u_v =
+ pic_config->lcu_total*lcu_size*lcu_size/2;
+ int32_t mc_buffer_size_u_v_h =
+ (mc_buffer_size_u_v + 0xffff)>>16; //64k alignment
+ struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx;
+
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "[test.c] #### config_sao_hw ####, lcu_size %d\n", lcu_size);
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "[config_sao_hw] lcu_total : %d\n", pic_config->lcu_total);
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "[config_sao_hw] mc_y_adr : 0x%x\n", pic_config->mc_y_adr);
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "[config_sao_hw] mc_u_v_adr : 0x%x\n", pic_config->mc_u_v_adr);
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "[config_sao_hw] header_adr : 0x%x\n", pic_config->header_adr);
+#ifdef AOM_AV1_MMU_DW
+ if (hw->dw_mmu_enable)
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "[config_sao_hw] header_dw_adr : 0x%x\n", pic_config->header_dw_adr);
+#endif
+ data32 = READ_VREG(HEVC_SAO_CTRL9) | (1 << 1);
+ WRITE_VREG(HEVC_SAO_CTRL9, data32);
+
+ data32 = READ_VREG(HEVC_SAO_CTRL5);
+ data32 |= (0x1 << 14); /* av1 mode */
+ data32 |= (0xff << 16); /* dw {v1,v0,h1,h0} ctrl_y_cbus */
+ WRITE_VREG(HEVC_SAO_CTRL5, data32);
+
+ WRITE_VREG(HEVC_SAO_CTRL0,
+ lcu_size == 128 ? 0x7 : 0x6); /*lcu_size_log2*/
+#ifdef LOSLESS_COMPRESS_MODE
+ WRITE_VREG(HEVC_CM_BODY_START_ADDR, pic_config->mc_y_adr);
+#ifdef AOM_AV1_MMU
+ WRITE_VREG(HEVC_CM_HEADER_START_ADDR, pic_config->header_adr);
+#endif
+#ifdef AOM_AV1_MMU_DW
+ if (hw->dw_mmu_enable)
+ WRITE_VREG(HEVC_CM_HEADER_START_ADDR2, pic_config->header_dw_adr);
+#endif
+#else
+/*!LOSLESS_COMPRESS_MODE*/
+ WRITE_VREG(HEVC_SAO_Y_START_ADDR, pic_config->mc_y_adr);
+#endif
+
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "[config_sao_hw] sao_body_addr:%x\n", pic_config->mc_y_adr);
+ //printk("[config_sao_hw] sao_header_addr:%x\n", pic_config->mc_y_adr + losless_comp_body_size );
+
+#ifdef VPU_FILMGRAIN_DUMP
+ // Let Microcode to increase
+ // WRITE_VREG(HEVC_FGS_TABLE_START, pic_config->fgs_table_adr);
+#else
+ WRITE_VREG(HEVC_FGS_TABLE_START, pic_config->fgs_table_adr);
+#endif
+ WRITE_VREG(HEVC_FGS_TABLE_LENGTH, FGS_TABLE_SIZE * 8);
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "[config_sao_hw] fgs_table adr:0x%x , length 0x%x bits\n",
+ pic_config->fgs_table_adr, FGS_TABLE_SIZE * 8);
+
+ data32 = (mc_buffer_size_u_v_h<<16)<<1;
+ //printk("data32 = %x, mc_buffer_size_u_v_h = %x, lcu_total = %x\n", data32, mc_buffer_size_u_v_h, pic_config->lcu_total);
+ WRITE_VREG(HEVC_SAO_Y_LENGTH ,data32);
+
+#ifndef LOSLESS_COMPRESS_MODE
+ WRITE_VREG(HEVC_SAO_C_START_ADDR, pic_config->mc_u_v_adr);
+#else
+#endif
+
+ data32 = (mc_buffer_size_u_v_h<<16);
+ WRITE_VREG(HEVC_SAO_C_LENGTH ,data32);
+
+#ifndef LOSLESS_COMPRESS_MODE
+ /* multi tile to do... */
+ WRITE_VREG(HEVC_SAO_Y_WPTR, pic_config->mc_y_adr);
+
+ WRITE_VREG(HEVC_SAO_C_WPTR, pic_config->mc_u_v_adr);
+#else
+ if (get_double_write_mode(hw) &&
+ (get_double_write_mode(hw) & 0x20) == 0) {
+ WRITE_VREG(HEVC_SAO_Y_START_ADDR, pic_config->dw_y_adr);
+ WRITE_VREG(HEVC_SAO_C_START_ADDR, pic_config->dw_u_v_adr);
+ WRITE_VREG(HEVC_SAO_Y_WPTR, pic_config->dw_y_adr);
+ WRITE_VREG(HEVC_SAO_C_WPTR, pic_config->dw_u_v_adr);
+ } else {
+ //WRITE_VREG(HEVC_SAO_Y_START_ADDR, 0xffffffff);
+ //WRITE_VREG(HEVC_SAO_C_START_ADDR, 0xffffffff);
+ }
+#endif
+
+
+#ifndef AOM_AV1_NV21
+#ifdef AOM_AV1_MMU_DW
+ if (hw->dw_mmu_enable) {
+ }
+#endif
+#endif
+
+#ifdef AOM_AV1_NV21
+#ifdef DOS_PROJECT
+ data32 = READ_VREG(HEVC_SAO_CTRL1);
+ data32 &= (~0x3000);
+ data32 |= (MEM_MAP_MODE << 12); // [13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32
+ data32 &= (~0x3);
+ data32 |= 0x1; // [1]:dw_disable [0]:cm_disable
+ WRITE_VREG(HEVC_SAO_CTRL1, data32);
+
+ data32 = READ_VREG(HEVC_SAO_CTRL5); // [23:22] dw_v1_ctrl [21:20] dw_v0_ctrl [19:18] dw_h1_ctrl [17:16] dw_h0_ctrl
+ data32 &= ~(0xff << 16); // set them all 0 for AOM_AV1_NV21 (no down-scale)
+ WRITE_VREG(HEVC_SAO_CTRL5, data32);
+
+ data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG);
+ data32 &= (~0x30);
+ data32 |= (MEM_MAP_MODE << 4); // [5:4] -- address_format 00:linear 01:32x32 10:64x32
+ WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32);
+#else
+// m8baby test1902
+ data32 = READ_VREG(HEVC_SAO_CTRL1);
+ data32 &= (~0x3000);
+ data32 |= (MEM_MAP_MODE << 12); // [13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32
+ data32 &= (~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);
+
+ data32 = READ_VREG(HEVC_SAO_CTRL5); // [23:22] dw_v1_ctrl [21:20] dw_v0_ctrl [19:18] dw_h1_ctrl [17:16] dw_h0_ctrl
+ data32 &= ~(0xff << 16); // set them all 0 for AOM_AV1_NV21 (no down-scale)
+ WRITE_VREG(HEVC_SAO_CTRL5, data32);
+
+ data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG);
+ data32 &= (~0x30);
+ data32 |= (MEM_MAP_MODE << 4); // [5:4] -- address_format 00:linear 01:32x32 10:64x32
+ data32 &= (~0xF);
+ data32 |= 0x8; // Big-Endian per 64-bit
+ WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32);
+#endif
+#else
+/*CHANGE_DONE nnn*/
+ data32 = READ_VREG(HEVC_SAO_CTRL1);
+ data32 &= (~0x3000);
+ data32 |= (mem_map_mode <<
+ 12);
+
+/* [13:12] axi_aformat, 0-Linear,
+ * 1-32x32, 2-64x32
+ */
+ data32 &= (~0xff0);
+ /* data32 |= 0x670; // Big-Endian per 64-bit */
+#ifdef AOM_AV1_MMU_DW
+ if (hw->dw_mmu_enable == 0)
+ data32 |= endian; /* Big-Endian per 64-bit */
+#else
+ data32 |= endian; /* Big-Endian per 64-bit */
+#endif
+ data32 &= (~0x3); /*[1]:dw_disable [0]:cm_disable*/
+ if (get_double_write_mode(hw) == 0)
+ data32 |= 0x2; /*disable double write*/
+ else if (get_double_write_mode(hw) & 0x10)
+ data32 |= 0x1; /*disable cm*/
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { /* >= G12A dw write control */
+ unsigned int data;
+ data = READ_VREG(HEVC_DBLK_CFGB);
+ data &= (~0x300); /*[8]:first write enable (compress) [9]:double write enable (uncompress)*/
+ if (get_double_write_mode(hw) == 0)
+ data |= (0x1 << 8); /*enable first write*/
+ else if (get_double_write_mode(hw) & 0x10)
+ data |= (0x1 << 9); /*double write only*/
+ else
+ data |= ((0x1 << 8) |(0x1 << 9));
+ WRITE_VREG(HEVC_DBLK_CFGB, data);
+ }
+
+ /* swap uv */
+ if (hw->is_used_v4l) {
+ if ((v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21) ||
+ (v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21M))
+ data32 &= ~(1 << 8); /* NV21 */
+ else
+ data32 |= (1 << 8); /* NV12 */
+ }
+
+ /*
+ * [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(hw) & 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 {
+ data32 = READ_VREG(HEVC_SAO_CTRL5);
+ data32 &= (~(0xff << 16));
+ if ((get_double_write_mode(hw) & 0xf) == 2 ||
+ (get_double_write_mode(hw) & 0xf) == 3)
+ data32 |= (0xff<<16);
+ else if ((get_double_write_mode(hw) & 0xf) == 4 ||
+ (get_double_write_mode(hw) & 0xf) == 5)
+ data32 |= (0x33<<16);
+ WRITE_VREG(HEVC_SAO_CTRL5, data32);
+ }
+
+ data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG);
+ data32 &= (~0x30);
+ /* [5:4] -- address_format 00:linear 01:32x32 10:64x32 */
+ data32 |= (mem_map_mode <<
+ 4);
+ data32 &= (~0xF);
+ data32 |= 0xf; /* valid only when double write only */
+ /*data32 |= 0x8;*/ /* Big-Endian per 64-bit */
+
+ /* swap uv */
+ if (hw->is_used_v4l) {
+ if ((v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21) ||
+ (v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21M))
+ data32 |= (1 << 12); /* NV21 */
+ else
+ data32 &= ~(1 << 12); /* NV12 */
+ }
+
+ /*
+ * [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
+ */
+ WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32);
+
+#endif
+
+}
+
+
+#ifdef AOM_AV1_DBLK_INIT
+/*
+ * Defines, declarations, sub-functions for av1 de-block loop filter Thr/Lvl table update
+ * - struct segmentation_lf is for loop filter only (removed something)
+ * - function "av1_loop_filter_init" and "av1_loop_filter_frame_init" will be instantiated in C_Entry
+ * - av1_loop_filter_init run once before decoding start
+ * - av1_loop_filter_frame_init run before every frame decoding start
+ * - set video format to AOM_AV1 is in av1_loop_filter_init
+ */
+#define MAX_LOOP_FILTER 63
+#define MAX_MODE_LF_DELTAS 2
+#define MAX_SEGMENTS 8
+#define MAX_MB_PLANE 3
+
+typedef enum {
+ SEG_LVL_ALT_Q, // Use alternate Quantizer ....
+ SEG_LVL_ALT_LF_Y_V, // Use alternate loop filter value on y plane vertical
+ SEG_LVL_ALT_LF_Y_H, // Use alternate loop filter value on y plane horizontal
+ SEG_LVL_ALT_LF_U, // Use alternate loop filter value on u plane
+ SEG_LVL_ALT_LF_V, // Use alternate loop filter value on v plane
+ SEG_LVL_REF_FRAME, // Optional Segment reference frame
+ SEG_LVL_SKIP, // Optional Segment (0,0) + skip mode
+ SEG_LVL_GLOBALMV,
+ SEG_LVL_MAX
+} SEG_LVL_FEATURES;
+
+static const SEG_LVL_FEATURES seg_lvl_lf_lut[MAX_MB_PLANE][2] = {
+ { SEG_LVL_ALT_LF_Y_V, SEG_LVL_ALT_LF_Y_H },
+ { SEG_LVL_ALT_LF_U, SEG_LVL_ALT_LF_U },
+ { SEG_LVL_ALT_LF_V, SEG_LVL_ALT_LF_V }
+};
+
+struct segmentation_lf { // for loopfilter only
+ uint8_t enabled;
+ /*
+ SEG_LVL_ALT_LF_Y_V feature_enable: seg_lf_info_y[bit7]
+ SEG_LVL_ALT_LF_Y_V data: seg_lf_info_y[bit0~6]
+ SEG_LVL_ALT_LF_Y_H feature enable: seg_lf_info_y[bit15]
+ SEG_LVL_ALT_LF_Y_H data: seg_lf_info_y[bit8~14]
+ */
+ uint16_t seg_lf_info_y[8];
+ /*
+ SEG_LVL_ALT_LF_U feature_enable: seg_lf_info_c[bit7]
+ SEG_LVL_ALT_LF_U data: seg_lf_info_c[bit0~6]
+ SEG_LVL_ALT_LF_V feature enable: seg_lf_info_c[bit15]
+ SEG_LVL_ALT_LF_V data: seg_lf_info_c[bit8~14]
+ */
+ uint16_t seg_lf_info_c[8];
+};
+
+typedef struct {
+ uint8_t mblim;
+ uint8_t lim;
+ uint8_t hev_thr;
+} loop_filter_thresh;
+
+typedef struct loop_filter_info_n_s {
+ loop_filter_thresh lfthr[MAX_LOOP_FILTER + 1];
+ uint8_t lvl[MAX_MB_PLANE][MAX_SEGMENTS][2][REF_FRAMES][MAX_MODE_LF_DELTAS];
+} loop_filter_info_n;
+
+struct loopfilter {
+ int32_t filter_level[2];
+ int32_t filter_level_u;
+ int32_t filter_level_v;
+
+ int32_t sharpness_level;
+
+ uint8_t mode_ref_delta_enabled;
+ uint8_t mode_ref_delta_update;
+
+ // 0 = Intra, Last, Last2+Last3,
+ // GF, BRF, ARF2, ARF
+ int8_t ref_deltas[REF_FRAMES];
+
+ // 0 = ZERO_MV, MV
+ int8_t mode_deltas[MAX_MODE_LF_DELTAS];
+
+ int32_t combine_vert_horz_lf;
+
+ int32_t lf_pic_cnt;
+
+//#if LOOP_FILTER_BITMASK
+ //LoopFilterMask *lfm;
+ //size_t lfm_num;
+ //int lfm_stride;
+ //LpfSuperblockInfo neighbor_sb_lpf_info;
+//#endif // LOOP_FILTER_BITMASK
+};
+#ifdef DBG_LPF_DBLK_LVL
+static int32_t myclamp(int32_t value, int32_t low, int32_t high) {
+ return value < low ? low : (value > high ? high : value);
+}
+#endif
+/*static int8_t extend_sign_7bits(uint8_t value) {
+ return (((value>>6) & 0x1)<<7) | (value&0x7f);
+}*/
+
+// convert data to int8_t variable
+// value : signed data (with any bitwidth<8) which is assigned to uint8_t variable as an input
+// bw : bitwidth of signed data, (from 1 to 7)
+static int8_t conv2int8 (uint8_t value, uint8_t bw) {
+ if (bw<1 || bw>7) return (int8_t)value;
+ else {
+ const uint8_t data_bits = value & ((1<<bw)-1);
+ const uint8_t sign_bit = (value>>(bw-1)) & 0x1;
+ const uint8_t sign_bit_ext = sign_bit | sign_bit<<1 | sign_bit<<2 | sign_bit<<3 | sign_bit<<4 | sign_bit<<5 | sign_bit<<6 | sign_bit<<7;
+ return (int8_t)((sign_bit_ext<<bw) | data_bits);
+ }
+}
+
+static void av1_update_sharpness(loop_filter_info_n *lfi, int32_t sharpness_lvl) {
+ int32_t lvl;
+
+ // For each possible value for the loop filter fill out limits
+ for (lvl = 0; lvl <= MAX_LOOP_FILTER; lvl++) {
+ // Set loop filter parameters that control sharpness.
+ int32_t block_inside_limit =
+ lvl >> ((sharpness_lvl > 0) + (sharpness_lvl > 4));
+
+ if (sharpness_lvl > 0) {
+ if (block_inside_limit > (9 - sharpness_lvl))
+ block_inside_limit = (9 - sharpness_lvl);
+ }
+
+ if (block_inside_limit < 1)
+ block_inside_limit = 1;
+
+ lfi->lfthr[lvl].lim = (uint8_t)block_inside_limit;
+ lfi->lfthr[lvl].mblim = (uint8_t)(2 * (lvl + 2) + block_inside_limit);
+ }
+}
+
+// instantiate this function once when decode is started
+void av1_loop_filter_init(loop_filter_info_n *lfi, struct loopfilter *lf) {
+ int32_t i;
+ uint32_t data32;
+
+ // init limits for given sharpness
+ av1_update_sharpness(lfi, lf->sharpness_level);
+
+ // Write to register
+ for (i = 0; i < 32; i++) {
+ uint32_t thr;
+ thr = ((lfi->lfthr[i*2+1].lim & 0x3f)<<8) |
+ (lfi->lfthr[i*2+1].mblim & 0xff);
+ thr = (thr<<16) | ((lfi->lfthr[i*2].lim & 0x3f)<<8) |
+ (lfi->lfthr[i*2].mblim & 0xff);
+ WRITE_VREG(HEVC_DBLK_CFG9, thr);
+ }
+ // video format is AOM_AV1
+ data32 = (0x57 << 8) | // 1st/2nd write both enable
+ (0x4 << 0); // aom_av1 video format
+ WRITE_VREG(HEVC_DBLK_CFGB, data32);
+ av1_print2(AOM_DEBUG_HW_MORE,
+ "[DBLK DEBUG] CFGB : 0x%x\n", data32);
+}
+
+// perform this function per frame
+void av1_loop_filter_frame_init(AV1Decoder* pbi, struct segmentation_lf *seg,
+ loop_filter_info_n *lfi,
+ struct loopfilter *lf,
+ int32_t pic_width) {
+ BuffInfo_t* buf_spec = pbi->work_space_buf;
+ int32_t i;
+#ifdef DBG_LPF_DBLK_LVL
+ int32_t dir;
+ int32_t filt_lvl[MAX_MB_PLANE], filt_lvl_r[MAX_MB_PLANE];
+ int32_t plane;
+ int32_t seg_id;
+#endif
+ // n_shift is the multiplier for lf_deltas
+ // the multiplier is 1 for when filter_lvl is between 0 and 31;
+ // 2 when filter_lvl is between 32 and 63
+
+ // update limits if sharpness has changed
+ av1_update_sharpness(lfi, lf->sharpness_level);
+
+ // Write to register
+ for (i = 0; i < 32; i++) {
+ uint32_t thr;
+ thr = ((lfi->lfthr[i*2+1].lim & 0x3f)<<8)
+ | (lfi->lfthr[i*2+1].mblim & 0xff);
+ thr = (thr<<16) | ((lfi->lfthr[i*2].lim & 0x3f)<<8)
+ | (lfi->lfthr[i*2].mblim & 0xff);
+ WRITE_VREG(HEVC_DBLK_CFG9, thr);
+ }
+#ifdef DBG_LPF_DBLK_LVL
+ filt_lvl[0] = lf->filter_level[0];
+ filt_lvl[1] = lf->filter_level_u;
+ filt_lvl[2] = lf->filter_level_v;
+
+ filt_lvl_r[0] = lf->filter_level[1];
+ filt_lvl_r[1] = lf->filter_level_u;
+ filt_lvl_r[2] = lf->filter_level_v;
+
+#ifdef DBG_LPF_PRINT
+ printk("LF_PRINT: pic_cnt(%d) base_filter_level(%d,%d,%d,%d)\n",
+ lf->lf_pic_cnt, lf->filter_level[0],
+ lf->filter_level[1], lf->filter_level_u, lf->filter_level_v);
+#endif
+
+ for (plane = 0; plane < 3; plane++) {
+ if (plane == 0 && !filt_lvl[0] && !filt_lvl_r[0])
+ break;
+ else if (plane == 1 && !filt_lvl[1])
+ continue;
+ else if (plane == 2 && !filt_lvl[2])
+ continue;
+
+ for (seg_id = 0; seg_id < MAX_SEGMENTS; seg_id++) { // MAX_SEGMENTS==8
+ for (dir = 0; dir < 2; ++dir) {
+ int32_t lvl_seg = (dir == 0) ? filt_lvl[plane] : filt_lvl_r[plane];
+ //assert(plane >= 0 && plane <= 2);
+ const uint8_t seg_lf_info_y0 = seg->seg_lf_info_y[seg_id] & 0xff;
+ const uint8_t seg_lf_info_y1 = (seg->seg_lf_info_y[seg_id]>>8) & 0xff;
+ const uint8_t seg_lf_info_u = seg->seg_lf_info_c[seg_id] & 0xff;
+ const uint8_t seg_lf_info_v = (seg->seg_lf_info_c[seg_id]>>8) & 0xff;
+ const uint8_t seg_lf_info = (plane==2) ? seg_lf_info_v : (plane==1) ?
+ seg_lf_info_u : ((dir==0) ? seg_lf_info_y0 : seg_lf_info_y1);
+ const int8_t seg_lf_active = ((seg->enabled) && ((seg_lf_info>>7) & 0x1));
+ const int8_t seg_lf_data = conv2int8(seg_lf_info,7);
+#ifdef DBG_LPF_PRINT
+ const int8_t seg_lf_data_clip = (seg_lf_data>63) ? 63 :
+ (seg_lf_data<-63) ? -63 : seg_lf_data;
+#endif
+ if (seg_lf_active) {
+ lvl_seg = myclamp(lvl_seg + (int32_t)seg_lf_data, 0, MAX_LOOP_FILTER);
+ }
+
+#ifdef DBG_LPF_PRINT
+ printk("LF_PRINT:plane(%d) seg_id(%d) dir(%d) seg_lf_info(%d,0x%x),lvl_seg(0x%x)\n",
+ plane,seg_id,dir,seg_lf_active,seg_lf_data_clip,lvl_seg);
+#endif
+
+ if (!lf->mode_ref_delta_enabled) {
+ // we could get rid of this if we assume that deltas are set to
+ // zero when not in use; encoder always uses deltas
+ memset(lfi->lvl[plane][seg_id][dir], lvl_seg,
+ sizeof(lfi->lvl[plane][seg_id][dir]));
+ } else {
+ int32_t ref, mode;
+ const int32_t scale = 1 << (lvl_seg >> 5);
+ const int32_t intra_lvl = lvl_seg + lf->ref_deltas[INTRA_FRAME] * scale;
+ lfi->lvl[plane][seg_id][dir][INTRA_FRAME][0] =
+ myclamp(intra_lvl, 0, MAX_LOOP_FILTER);
+#ifdef DBG_LPF_PRINT
+ printk("LF_PRINT:ref_deltas[INTRA_FRAME](%d)\n",lf->ref_deltas[INTRA_FRAME]);
+#endif
+ for (ref = LAST_FRAME; ref < REF_FRAMES; ++ref) { // LAST_FRAME==1 REF_FRAMES==8
+ for (mode = 0; mode < MAX_MODE_LF_DELTAS; ++mode) { // MAX_MODE_LF_DELTAS==2
+ const int32_t inter_lvl =
+ lvl_seg + lf->ref_deltas[ref] * scale +
+ lf->mode_deltas[mode] * scale;
+ lfi->lvl[plane][seg_id][dir][ref][mode] =
+ myclamp(inter_lvl, 0, MAX_LOOP_FILTER);
+#ifdef DBG_LPF_PRINT
+ printk("LF_PRINT:ref_deltas(%d) mode_deltas(%d)\n",
+ lf->ref_deltas[ref], lf->mode_deltas[mode]);
+#endif
+ }
+ }
+ }
+ }
+ }
+ }
+
+#ifdef DBG_LPF_PRINT
+ for (i = 0; i <= MAX_LOOP_FILTER; i++) {
+ printk("LF_PRINT:(%2d) thr=%d,blim=%3d,lim=%2d\n",
+ i, lfi->lfthr[i].hev_thr,
+ lfi->lfthr[i].mblim, lfi->lfthr[i].lim);
+ }
+ for (plane = 0; plane < 3; plane++) {
+ for (seg_id = 0; seg_id < MAX_SEGMENTS; seg_id++) { // MAX_SEGMENTS==8
+ for (dir = 0; dir < 2; ++dir) {
+ int32_t mode;
+ for (mode = 0; mode < 2; ++mode) {
+ printk("assign {lvl[%d][%d][%d][0][%d],lvl[%d][%d][%d][1][%d],lvl[%d][%d][%d][2][%d],lvl[%d][%d][%d][3][%d],lvl[%d][%d][%d][4][%d],lvl[%d][%d][%d][5][%d],lvl[%d][%d][%d][6][%d],lvl[%d][%d][%d][7][%d]}={6'd%2d,6'd%2d,6'd%2d,6'd%2d,6'd%2d,6'd%2d,6'd%2d,6'd%2d};\n",
+ plane, seg_id, dir, mode,
+ plane, seg_id, dir, mode,
+ plane, seg_id, dir, mode,
+ plane, seg_id, dir, mode,
+ plane, seg_id, dir, mode,
+ plane, seg_id, dir, mode,
+ plane, seg_id, dir, mode,
+ plane, seg_id, dir, mode,
+ lfi->lvl[plane][seg_id][dir][0][mode],
+ lfi->lvl[plane][seg_id][dir][1][mode],
+ lfi->lvl[plane][seg_id][dir][2][mode],
+ lfi->lvl[plane][seg_id][dir][3][mode],
+ lfi->lvl[plane][seg_id][dir][4][mode],
+ lfi->lvl[plane][seg_id][dir][5][mode],
+ lfi->lvl[plane][seg_id][dir][6][mode],
+ lfi->lvl[plane][seg_id][dir][7][mode]);
+ }
+ }
+ }
+ }
+#endif
+ // Write to register
+ for (i = 0; i < 192; i++) {
+ uint32_t level;
+ level = ((lfi->lvl[i>>6&3][i>>3&7][1][i&7][1] & 0x3f)<<24) |
+ ((lfi->lvl[i>>6&3][i>>3&7][1][i&7][0] & 0x3f)<<16) |
+ ((lfi->lvl[i>>6&3][i>>3&7][0][i&7][1] & 0x3f)<<8) |
+ (lfi->lvl[i>>6&3][i>>3&7][0][i&7][0] & 0x3f);
+ if (!lf->filter_level[0] && !lf->filter_level[1])
+ level = 0;
+ WRITE_VREG(HEVC_DBLK_CFGA, level);
+ }
+#endif // DBG_LPF_DBLK_LVL
+
+#ifdef DBG_LPF_DBLK_FORCED_OFF
+ if (lf->lf_pic_cnt == 2) {
+ printk("LF_PRINT: pic_cnt(%d) dblk forced off !!!\n", lf->lf_pic_cnt);
+ WRITE_VREG(HEVC_DBLK_DBLK0, 0);
+ } else
+ WRITE_VREG(HEVC_DBLK_DBLK0,
+ lf->filter_level[0] | lf->filter_level[1] << 6 |
+ lf->filter_level_u << 12 | lf->filter_level_v << 18);
+#else
+ WRITE_VREG(HEVC_DBLK_DBLK0,
+ lf->filter_level[0] | lf->filter_level[1]<<6 |
+ lf->filter_level_u<<12 | lf->filter_level_v<<18);
+#endif
+ for (i =0; i < 10; i++)
+ WRITE_VREG(HEVC_DBLK_DBLK1,
+ ((i<2) ? lf->mode_deltas[i&1] : lf->ref_deltas[(i-2)&7]));
+ for (i = 0; i < 8; i++)
+ WRITE_VREG(HEVC_DBLK_DBLK2,
+ (uint32_t)(seg->seg_lf_info_y[i]) | (uint32_t)(seg->seg_lf_info_c[i]<<16));
+
+ // Set P_HEVC_DBLK_CFGB again
+ {
+ uint32_t lpf_data32 = READ_VREG(HEVC_DBLK_CFGB);
+ if (lf->mode_ref_delta_enabled)
+ lpf_data32 |= (0x1<<28); // mode_ref_delta_enabled
+ else
+ lpf_data32 &= ~(0x1<<28);
+ if (seg->enabled)
+ lpf_data32 |= (0x1<<29); // seg enable
+ else
+ lpf_data32 &= ~(0x1<<29);
+ if (pic_width >= 1280)
+ lpf_data32 |= (0x1 << 4); // dblk pipeline mode=1 for performance
+ else
+ lpf_data32 &= ~(0x3 << 4);
+ WRITE_VREG(HEVC_DBLK_CFGB, lpf_data32);
+ }
+ // Set CDEF
+ WRITE_VREG(HEVC_DBLK_CDEF0, buf_spec->cdef_data.buf_start);
+ {
+ uint32_t cdef_data32 = (READ_VREG(HEVC_DBLK_CDEF1) & 0xffffff00);
+ cdef_data32 |= 17; // TODO ERROR :: cdef temp dma address left offset
+#ifdef DBG_LPF_CDEF_NO_PIPELINE
+ cdef_data32 |= (1<<17); // cdef test no pipeline for very small picture
+#endif
+ WRITE_VREG(HEVC_DBLK_CDEF1, cdef_data32);
+ }
+ // Picture count
+ lf->lf_pic_cnt++;
+}
+#endif // #ifdef AOM_AV1_DBLK_INIT
+
+#ifdef AOM_AV1_UPSCALE_INIT
+/*
+ * these functions here for upscaling updated in every picture
+ */
+#define RS_SUBPEL_BITS 6
+#define RS_SUBPEL_MASK ((1 << RS_SUBPEL_BITS) - 1)
+#define RS_SCALE_SUBPEL_BITS 14
+#define RS_SCALE_SUBPEL_MASK ((1 << RS_SCALE_SUBPEL_BITS) - 1)
+#define RS_SCALE_EXTRA_BITS (RS_SCALE_SUBPEL_BITS - RS_SUBPEL_BITS)
+#define RS_SCALE_EXTRA_OFF (1 << (RS_SCALE_EXTRA_BITS - 1))
+
+static int32_t av1_get_upscale_convolve_step(int32_t in_length, int32_t out_length) {
+ return ((in_length << RS_SCALE_SUBPEL_BITS) + out_length / 2) / out_length;
+}
+
+static int32_t get_upscale_convolve_x0(int32_t in_length, int32_t out_length,
+ int32_t x_step_qn) {
+ const int32_t err = out_length * x_step_qn - (in_length << RS_SCALE_SUBPEL_BITS);
+ const int32_t x0 =
+ (-((out_length - in_length) << (RS_SCALE_SUBPEL_BITS - 1)) +
+ out_length / 2) /
+ out_length +
+ RS_SCALE_EXTRA_OFF - err / 2;
+ return (int32_t)((uint32_t)x0 & RS_SCALE_SUBPEL_MASK);
+}
+
+void av1_upscale_frame_init(AV1Decoder* pbi, AV1_COMMON *cm, param_t* params)
+{
+ BuffInfo_t* buf_spec = pbi->work_space_buf;
+ //uint32_t data32;
+ const int32_t width = cm->dec_width;
+ const int32_t superres_upscaled_width = cm->superres_upscaled_width;
+ const int32_t x_step_qn_luma = av1_get_upscale_convolve_step(width, superres_upscaled_width);
+ const int32_t x0_qn_luma = get_upscale_convolve_x0(width, superres_upscaled_width, x_step_qn_luma);
+ const int32_t x_step_qn_chroma = av1_get_upscale_convolve_step((width+1)>>1, (superres_upscaled_width+1)>>1);
+ const int32_t x0_qn_chroma = get_upscale_convolve_x0((width+1)>>1, (superres_upscaled_width+1)>>1, x_step_qn_chroma);
+ av1_print2(AOM_DEBUG_HW_MORE,
+ "UPS_PRINT: width(%d -> %d)\n",
+ width, superres_upscaled_width);
+ av1_print2(AOM_DEBUG_HW_MORE,
+ "UPS_PRINT: xstep(%d,%d)(0x%X, 0x%X) x0qn(%d,%d)(0x%X, 0x%X)\n",
+ x_step_qn_luma,x_step_qn_chroma,
+ x_step_qn_luma,x_step_qn_chroma,
+ x0_qn_luma,x0_qn_chroma,
+ x0_qn_luma,x0_qn_chroma);
+ WRITE_VREG(HEVC_DBLK_UPS1, buf_spec->ups_data.buf_start);
+ WRITE_VREG(HEVC_DBLK_UPS2, x0_qn_luma); // x0_qn y
+ WRITE_VREG(HEVC_DBLK_UPS3, x0_qn_chroma); // x0_qn c
+ WRITE_VREG(HEVC_DBLK_UPS4, x_step_qn_luma); // x_step y
+ WRITE_VREG(HEVC_DBLK_UPS5, x_step_qn_chroma); // x_step c
+ WRITE_VREG(AV1_UPSCALE_X0_QN, (x0_qn_chroma<<16)|x0_qn_luma);
+ WRITE_VREG(AV1_UPSCALE_STEP_QN, (x_step_qn_chroma<<16)|x_step_qn_luma);
+
+/*
+ * TileR calculation here if cm needs an exactly accurate value
+ */
+//#define AV1_UPSCALE_TILER_CALCULATION
+#ifdef AV1_UPSCALE_TILER_CALCULATION
+ uint32_t upscl_enabled = 1; // 1 just for example, actually this is use_superres flag
+ uint32_t tiler_x = 192; // 192 just for example, actually this is tile end
+ uint32_t ux;
+ uint32_t ux_tiler,ux_tiler_rnd32;
+ uint32_t xqn_y;
+ uint32_t xqn_c;
+ uint32_t tiler_x_y = tiler_x - 8 - 3; // dblk/cdef left-shift-8 plus upscaling extra-3
+ uint32_t tiler_x_c = (tiler_x/2) - 4 - 3; // dblk/cdef left-shift-4 plus upscaling extra-3
+
+ xqn_y = x0_qn_luma;
+ xqn_c = x0_qn_chroma;
+ ux_tiler = 0;
+ ux_tiler_rnd32 = 0;
+ for (ux=0; ux<16384; ux+=8) {
+ uint32_t x1qn_y = xqn_y + x_step_qn_luma *( 7+3); // extra-3 is for lrf
+ uint32_t x1qn_c = xqn_c + x_step_qn_chroma*( 3+3); // extra-3 is for lrf
+ uint32_t x1qn_y_nxt = xqn_y + x_step_qn_luma *(8+7+3); // extra-3 is for lrf
+ uint32_t x1qn_c_nxt = xqn_c + x_step_qn_chroma*(4+3+3); // extra-3 is for lrf
+
+ uint32_t x1_y = upscl_enabled ? (x1qn_y>>14) : ux +7+3;
+ uint32_t x1_c = upscl_enabled ? (x1qn_c>>14) : (ux/2)+3+3;
+ uint32_t x1_y_nxt = upscl_enabled ? (x1qn_y_nxt>>14) : ux +8+7+3;
+ uint32_t x1_c_nxt = upscl_enabled ? (x1qn_c_nxt>>14) : (ux/2)+4+3+3;
+
+ if ((x1_y<tiler_x_y && x1_c<tiler_x_c) &&
+ (x1_y_nxt>=tiler_x_y || x1_c_nxt>=tiler_x_c)) {
+ ux_tiler = ux;
+ ux_tiler_rnd32 = (ux_tiler/32 + (ux_tiler%32 ? 1 : 0)) * 32;
+ break;
+ }
+
+ xqn_y += x_step_qn_luma*8;
+ xqn_c += x_step_qn_chroma*4;
+ }
+
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "UPS_PRINT: xqn_y(0x%x), xqn_c(0x%x), x1qn_y(0x%x), x1qn_c(0x%x)\n",
+ xqn_y, xqn_c, x1qn_y, x1qn_c);
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "UPS_PRINT: ux_tiler(%d)(0x%x), ux_tiler_rnd32(%d)(0x%x)\n",
+ ux_tiler, ux_tiler, ux_tiler_rnd32, ux_tiler_rnd32);
+#endif
+
+ // TEMP write lrf register here
+ //WRITE_VREG(HEVC_DBLK_LRF0, 1<<0 | 1<<2); // LRF UNIT SIZE
+ //WRITE_VREG(HEVC_DBLK_LRF1, 3<<0 | 1<<8 | 1<<16 | 1<<24); // LRF UNIT NUMBER
+
+ // TEMP Global Enables write here
+ /*
+ const uint32_t dblk_enable = (!cm->allow_intrabc && !cm->single_tile_decoding && (cm->lf.filter_level[0] || cm->lf.filter_level[1]));
+ const uint32_t cdef_enable = (!cm->allow_intrabc && !cm->single_tile_decoding && !cm->skip_loop_filter && !cm->coded_lossless && (cm->cdef_bits || cm->cdef_strengths[0] || cm->cdef_uv_strengths[0]));
+ printk("LPF_ENABLES : dblk(%d) cdef(%d)\n", dblk_enable, cdef_enable);
+ data32 = READ_VREG(HEVC_DBLK_CFGB );
+ data32 &= ~(0xf<<20);
+ data32 |= (dblk_enable<<20);
+ data32 |= (cdef_enable<<23);
+ WRITE_VREG(HEVC_DBLK_CFGB, data32);
+ */
+}
+
+#endif // #ifdef AOM_AV1_UPSCALE_INIT
+
+static void release_dblk_struct(struct AV1HW_s *hw)
+{
+#ifdef AOM_AV1_DBLK_INIT
+ if (hw->lfi)
+ vfree(hw->lfi);
+ if (hw->lf)
+ vfree(hw->lf);
+ if (hw->seg_4lf)
+ vfree(hw->seg_4lf);
+ hw->lfi = NULL;
+ hw->lf = NULL;
+ hw->seg_4lf = NULL;
+#endif
+}
+
+static int init_dblk_struc(struct AV1HW_s *hw)
+{
+#ifdef AOM_AV1_DBLK_INIT
+ hw->lfi = vmalloc(sizeof(loop_filter_info_n));
+ hw->lf = vmalloc(sizeof(struct loopfilter));
+ hw->seg_4lf = vmalloc(sizeof(struct segmentation_lf));
+
+ if (hw->lfi == NULL || hw->lf == NULL || hw->seg_4lf == NULL) {
+ printk("[test.c] aom_loop_filter init malloc error!!!\n");
+ release_dblk_struct(hw);
+ return -1;
+ }
+
+ hw->lf->mode_ref_delta_enabled = 1; // set default here
+ hw->lf->mode_ref_delta_update = 1; // set default here
+ hw->lf->sharpness_level = 0; // init to 0
+ hw->lf->lf_pic_cnt = 0; // init to 0
+#endif
+ return 0;
+}
+
+static void config_dblk_hw(struct AV1HW_s *hw)
+{
+ AV1Decoder *pbi = hw->pbi;
+ AV1_COMMON *cm = &hw->common;
+ loop_filter_info_n *lfi = hw->lfi;
+ struct loopfilter *lf = hw->lf;
+ struct segmentation_lf *seg_4lf = hw->seg_4lf;
+ BuffInfo_t* buf_spec = pbi->work_space_buf;
+ PIC_BUFFER_CONFIG* cur_pic_config = &cm->cur_frame->buf;
+ PIC_BUFFER_CONFIG* prev_pic_config = &cm->prev_frame->buf;
+ int i;
+
+#ifdef AOM_AV1_DBLK_INIT
+#ifdef DUAL_DECODE
+#else
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "[test.c ref_delta] cur_frame : %p prev_frame : %p - %p \n",
+ cm->cur_frame, cm->prev_frame,
+ av1_get_primary_ref_frame_buf(cm));
+ // get lf parameters from parser
+ lf->mode_ref_delta_enabled =
+ (hw->aom_param.p.loop_filter_mode_ref_delta_enabled & 1);
+ lf->mode_ref_delta_update =
+ ((hw->aom_param.p.loop_filter_mode_ref_delta_enabled >> 1) & 1);
+ lf->sharpness_level =
+ hw->aom_param.p.loop_filter_sharpness_level;
+ if (((hw->aom_param.p.loop_filter_mode_ref_delta_enabled)&3) == 3) { // enabled but and update
+ if (cm->prev_frame == NULL) {
+ // already initialized in Microcode
+ lf->ref_deltas[0] = conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_0),7);
+ lf->ref_deltas[1] = conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_0>>8),7);
+ lf->ref_deltas[2] = conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_1),7);
+ lf->ref_deltas[3] = conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_1>>8),7);
+ lf->ref_deltas[4] = conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_2),7);
+ lf->ref_deltas[5] = conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_2>>8),7);
+ lf->ref_deltas[6] = conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_3),7);
+ lf->ref_deltas[7] = conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_3>>8),7);
+ lf->mode_deltas[0] = conv2int8((uint8_t)(hw->aom_param.p.loop_filter_mode_deltas_0),7);
+ lf->mode_deltas[1] = conv2int8((uint8_t)(hw->aom_param.p.loop_filter_mode_deltas_0>>8),7);
+ } else {
+ lf->ref_deltas[0] = (hw->aom_param.p.loop_filter_ref_deltas_0 & 0x80) ?
+ conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_0),7) :
+ cm->prev_frame->ref_deltas[0];
+ lf->ref_deltas[1] = (hw->aom_param.p.loop_filter_ref_deltas_0 & 0x8000) ?
+ conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_0>>8),7) :
+ cm->prev_frame->ref_deltas[1];
+ lf->ref_deltas[2] = (hw->aom_param.p.loop_filter_ref_deltas_1 & 0x80) ?
+ conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_1),7) :
+ cm->prev_frame->ref_deltas[2];
+ lf->ref_deltas[3] = (hw->aom_param.p.loop_filter_ref_deltas_1 & 0x8000) ?
+ conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_1>>8),7) :
+ cm->prev_frame->ref_deltas[3];
+ lf->ref_deltas[4] = (hw->aom_param.p.loop_filter_ref_deltas_2 & 0x80) ?
+ conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_2),7) :
+ cm->prev_frame->ref_deltas[4];
+ lf->ref_deltas[5] = (hw->aom_param.p.loop_filter_ref_deltas_2 & 0x8000) ?
+ conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_2>>8),7) :
+ cm->prev_frame->ref_deltas[5];
+ lf->ref_deltas[6] = (hw->aom_param.p.loop_filter_ref_deltas_3 & 0x80) ?
+ conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_3),7) :
+ cm->prev_frame->ref_deltas[6];
+ lf->ref_deltas[7] = (hw->aom_param.p.loop_filter_ref_deltas_3 & 0x8000) ?
+ conv2int8((uint8_t)(hw->aom_param.p.loop_filter_ref_deltas_3>>8),7) :
+ cm->prev_frame->ref_deltas[7];
+ lf->mode_deltas[0] = (hw->aom_param.p.loop_filter_mode_deltas_0 & 0x80) ?
+ conv2int8((uint8_t)(hw->aom_param.p.loop_filter_mode_deltas_0),7) :
+ cm->prev_frame->mode_deltas[0];
+ lf->mode_deltas[1] = (hw->aom_param.p.loop_filter_mode_deltas_0 & 0x8000) ?
+ conv2int8((uint8_t)(hw->aom_param.p.loop_filter_mode_deltas_0>>8),7) :
+ cm->prev_frame->mode_deltas[1];
+ }
+ } //else if (hw->aom_param.p.loop_filter_mode_ref_delta_enabled == 1) { // enabled but no update
+ else { // match c code -- not enabled, still need to copy prev to used for next
+ if ((cm->prev_frame == NULL) | (hw->aom_param.p.loop_filter_mode_ref_delta_enabled & 4)) {
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "[test.c] mode_ref_delta set to default\n");
+ lf->ref_deltas[0] = conv2int8((uint8_t)1,7);
+ lf->ref_deltas[1] = conv2int8((uint8_t)0,7);
+ lf->ref_deltas[2] = conv2int8((uint8_t)0,7);
+ lf->ref_deltas[3] = conv2int8((uint8_t)0,7);
+ lf->ref_deltas[4] = conv2int8((uint8_t)0xff,7);
+ lf->ref_deltas[5] = conv2int8((uint8_t)0,7);
+ lf->ref_deltas[6] = conv2int8((uint8_t)0xff,7);
+ lf->ref_deltas[7] = conv2int8((uint8_t)0xff,7);
+ lf->mode_deltas[0] = conv2int8((uint8_t)0,7);
+ lf->mode_deltas[1] = conv2int8((uint8_t)0,7);
+ } else {
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "[test.c] mode_ref_delta copy from prev_frame\n");
+ if (cm->prev_frame) {
+ lf->ref_deltas[0] = cm->prev_frame->ref_deltas[0];
+ lf->ref_deltas[1] = cm->prev_frame->ref_deltas[1];
+ lf->ref_deltas[2] = cm->prev_frame->ref_deltas[2];
+ lf->ref_deltas[3] = cm->prev_frame->ref_deltas[3];
+ lf->ref_deltas[4] = cm->prev_frame->ref_deltas[4];
+ lf->ref_deltas[5] = cm->prev_frame->ref_deltas[5];
+ lf->ref_deltas[6] = cm->prev_frame->ref_deltas[6];
+ lf->ref_deltas[7] = cm->prev_frame->ref_deltas[7];
+ lf->mode_deltas[0] = cm->prev_frame->mode_deltas[0];
+ lf->mode_deltas[1] = cm->prev_frame->mode_deltas[1];
+ }
+ }
+ }
+ lf->filter_level[0] = hw->aom_param.p.loop_filter_level_0;
+ lf->filter_level[1] = hw->aom_param.p.loop_filter_level_1;
+ lf->filter_level_u = hw->aom_param.p.loop_filter_level_u;
+ lf->filter_level_v = hw->aom_param.p.loop_filter_level_v;
+
+ if (cm->cur_frame) {
+ cm->cur_frame->ref_deltas[0] = lf->ref_deltas[0];
+ cm->cur_frame->ref_deltas[1] = lf->ref_deltas[1];
+ cm->cur_frame->ref_deltas[2] = lf->ref_deltas[2];
+ cm->cur_frame->ref_deltas[3] = lf->ref_deltas[3];
+ cm->cur_frame->ref_deltas[4] = lf->ref_deltas[4];
+ cm->cur_frame->ref_deltas[5] = lf->ref_deltas[5];
+ cm->cur_frame->ref_deltas[6] = lf->ref_deltas[6];
+ cm->cur_frame->ref_deltas[7] = lf->ref_deltas[7];
+ cm->cur_frame->mode_deltas[0] = lf->mode_deltas[0];
+ cm->cur_frame->mode_deltas[1] = lf->mode_deltas[1];
+
+ // get seg_4lf parameters from parser
+ seg_4lf->enabled = hw->aom_param.p.segmentation_enabled & 1;
+ cm->cur_frame->segmentation_enabled = hw->aom_param.p.segmentation_enabled & 1;
+ cm->cur_frame->intra_only = (hw->aom_param.p.segmentation_enabled >> 2) & 1;
+ cm->cur_frame->segmentation_update_map = (hw->aom_param.p.segmentation_enabled >> 3) & 1;
+ }
+ if (hw->aom_param.p.segmentation_enabled & 1) { // segmentation_enabled
+ if (hw->aom_param.p.segmentation_enabled & 2) { // segmentation_update_data
+ for (i = 0; i < MAX_SEGMENTS; i++) {
+ seg_4lf->seg_lf_info_y[i] = hw->aom_param.p.seg_lf_info_y[i];
+ seg_4lf->seg_lf_info_c[i] = hw->aom_param.p.seg_lf_info_c[i];
+ #ifdef DBG_LPF_PRINT
+ printk(" read seg_lf_info [%d] : 0x%x, 0x%x\n",
+ i, seg_4lf->seg_lf_info_y[i], seg_4lf->seg_lf_info_c[i]);
+ #endif
+ }
+ } // segmentation_update_data
+ else { // no segmentation_update_data
+ if (cm->prev_frame == NULL) {
+ for (i=0;i<MAX_SEGMENTS;i++) {
+ seg_4lf->seg_lf_info_y[i] = 0;
+ seg_4lf->seg_lf_info_c[i] = 0;
+ }
+ } else {
+ for (i = 0; i < MAX_SEGMENTS; i++) {
+ seg_4lf->seg_lf_info_y[i] = cm->prev_frame->seg_lf_info_y[i];
+ seg_4lf->seg_lf_info_c[i] = cm->prev_frame->seg_lf_info_c[i];
+ #ifdef DBG_LPF_PRINT
+ printk(" Refrence seg_lf_info [%d] : 0x%x, 0x%x\n",
+ i, seg_4lf->seg_lf_info_y[i], seg_4lf->seg_lf_info_c[i]);
+ #endif
+ }
+ }
+ } // no segmentation_update_data
+ } // segmentation_enabled
+ else {
+ for (i=0;i<MAX_SEGMENTS;i++) {
+ seg_4lf->seg_lf_info_y[i] = 0;
+ seg_4lf->seg_lf_info_c[i] = 0;
+ }
+ } // NOT segmentation_enabled
+ for (i=0;i<MAX_SEGMENTS;i++) {
+ cm->cur_frame->seg_lf_info_y[i] = seg_4lf->seg_lf_info_y[i];
+ cm->cur_frame->seg_lf_info_c[i] = seg_4lf->seg_lf_info_c[i];
+#ifdef DBG_LPF_PRINT
+ printk(" SAVE seg_lf_info [%d] : 0x%x, 0x%x\n",
+ i, cm->cur_frame->seg_lf_info_y[i],
+ cm->cur_frame->seg_lf_info_c[i]);
+#endif
+ }
+
+ /*
+ * Update loop filter Thr/Lvl table for every frame
+ */
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "[test.c] av1_loop_filter_frame_init (run before every frame decoding start)\n");
+ av1_loop_filter_frame_init(pbi, seg_4lf, lfi, lf, cm->dec_width);
+#endif // not DUAL_DECODE
+#endif
+
+#ifdef AOM_AV1_UPSCALE_INIT
+ /*
+ * init for upscaling
+ */
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "[test.c] av1_upscale_frame_init (run before every frame decoding start)\n");
+ av1_upscale_frame_init(pbi,
+ pbi->common, &hw->aom_param);
+#endif // #ifdef AOM_AV1_UPSCALE_INIT
+
+ //BuffInfo_t* buf_spec = pbi->work_space_buf;
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "[test.c] cur_frame : %p prev_frame : %p - %p \n",
+ cm->cur_frame, cm->prev_frame, av1_get_primary_ref_frame_buf(cm));
+ if (cm->cur_frame == NULL) {
+ WRITE_VREG(AOM_AV1_CDF_BUFFER_W, buf_spec->cdf_buf.buf_start);
+ WRITE_VREG(AOM_AV1_SEG_MAP_BUFFER_W, buf_spec->seg_map.buf_start);
+ }
+ else {
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "[test.c] Config WRITE CDF_BUF/SEG_MAP_BUF : %d\n",
+ cur_pic_config->index);
+ WRITE_VREG(AOM_AV1_CDF_BUFFER_W,
+ buf_spec->cdf_buf.buf_start + (0x8000*cur_pic_config->index));
+ WRITE_VREG(AOM_AV1_SEG_MAP_BUFFER_W,
+ buf_spec->seg_map.buf_start + ((buf_spec->seg_map.buf_size / 16) * cur_pic_config->index));
+ }
+ cm->cur_frame->seg_mi_rows = cm->cur_frame->mi_rows;
+ cm->cur_frame->seg_mi_cols = cm->cur_frame->mi_cols;
+ if (cm->prev_frame == NULL) {
+ WRITE_VREG(AOM_AV1_CDF_BUFFER_R, buf_spec->cdf_buf.buf_start);
+ WRITE_VREG(AOM_AV1_SEG_MAP_BUFFER_R, buf_spec->seg_map.buf_start);
+ } else {
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "[test.c] Config READ CDF_BUF/SEG_MAP_BUF : %d\n",
+ prev_pic_config->index);
+ WRITE_VREG(AOM_AV1_CDF_BUFFER_R,
+ buf_spec->cdf_buf.buf_start + (0x8000*prev_pic_config->index));
+ WRITE_VREG(AOM_AV1_SEG_MAP_BUFFER_R,
+ buf_spec->seg_map.buf_start + ((buf_spec->seg_map.buf_size / 16) * prev_pic_config->index));
+
+ // segmentation_enabled but no segmentation_update_data
+ if ((hw->aom_param.p.segmentation_enabled & 3) == 1) {
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "[test.c] segfeatures_copy from prev_frame\n");
+ for (i = 0; i < 8; i++) {
+ WRITE_VREG(AOM_AV1_SEGMENT_FEATURE,
+ cm->prev_frame->segment_feature[i]);
+ }
+ }
+ // segmentation_enabled but no segmentation_update_map
+ if ((hw->aom_param.p.segmentation_enabled & 9) == 1) {
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "[test.c] seg_map_size copy from prev_frame\n");
+ cm->cur_frame->seg_mi_rows = cm->prev_frame->seg_mi_rows;
+ cm->cur_frame->seg_mi_cols = cm->prev_frame->seg_mi_cols;
+ }
+ }
+#ifdef PRINT_HEVC_DATA_PATH_MONITOR
+ {
+ uint32_t total_clk_count;
+ uint32_t path_transfer_count;
+ uint32_t path_wait_count;
+ float path_wait_ratio;
+ if (pbi->decode_idx > 1) {
+ WRITE_VREG(HEVC_PATH_MONITOR_CTRL, 0); // Disabble monitor and set rd_idx to 0
+ total_clk_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+
+ WRITE_VREG(HEVC_PATH_MONITOR_CTRL, (1<<4)); // Disabble monitor and set rd_idx to 0
+
+ // parser --> iqit
+ path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ if (path_transfer_count == 0)
+ path_wait_ratio = 0.0;
+ else
+ path_wait_ratio =
+ (float)path_wait_count/(float)path_transfer_count;
+ printk("[P%d HEVC PATH] Parser/IQIT/IPP/DBLK/OW/DDR/CMD WAITING \% : %.2f",
+ pbi->decode_idx - 2,
+ path_wait_ratio);
+
+ // iqit --> ipp
+ path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ if (path_transfer_count == 0)
+ path_wait_ratio = 0.0;
+ else
+ path_wait_ratio = (float)path_wait_count/(float)path_transfer_count;
+ printk(" %.2f", path_wait_ratio);
+
+ // dblk <-- ipp
+ path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ if (path_transfer_count == 0)
+ path_wait_ratio = 0.0;
+ else
+ path_wait_ratio = (float)path_wait_count/(float)path_transfer_count;
+ printk(" %.2f", path_wait_ratio);
+
+ // dblk --> ow
+ path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ if (path_transfer_count == 0)
+ path_wait_ratio = 0.0;
+ else path_wait_ratio =
+ (float)path_wait_count/(float)path_transfer_count;
+ printk(" %.2f", path_wait_ratio);
+
+ // <--> DDR
+ path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ if (path_transfer_count == 0)
+ path_wait_ratio = 0.0;
+ else path_wait_ratio =
+ (float)path_wait_count/(float)path_transfer_count;
+ printk(" %.2f", path_wait_ratio);
+
+ // CMD
+ path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ if (path_transfer_count == 0)
+ path_wait_ratio = 0.0;
+ else
+ path_wait_ratio = (float)path_wait_count/(float)path_transfer_count;
+ printk(" %.2f\n", path_wait_ratio);
+ }
+ }
+
+#endif
+
+}
+
+static void aom_config_work_space_hw(struct AV1HW_s *hw, u32 mask)
+{
+ struct BuffInfo_s *buf_spec = hw->work_space_buf;
+ unsigned int data32;
+ av1_print(hw, AOM_DEBUG_HW_MORE, "%s %d\n", __func__, __LINE__);
+ if (debug && hw->init_flag == 0)
+ av1_print(hw, AOM_DEBUG_HW_MORE, "%s %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->sao_up.buf_start,
+ buf_spec->swap_buf.buf_start,
+ buf_spec->scalelut.buf_start,
+ buf_spec->dblk_para.buf_start,
+ buf_spec->dblk_data.buf_start);
+ if (mask & HW_MASK_FRONT) {
+ av1_print(hw, AOM_DEBUG_HW_MORE, "%s %d\n", __func__, __LINE__);
+ if ((debug & AOM_AV1_DEBUG_SEND_PARAM_WITH_REG) == 0)
+ WRITE_VREG(HEVC_RPM_BUFFER, (u32)hw->rpm_phy_addr);
+
+ /*WRITE_VREG(HEVC_STREAM_SWAP_BUFFER,
+ buf_spec->swap_buf.buf_start);*/
+ WRITE_VREG(LMEM_DUMP_ADR, (u32)hw->lmem_phy_addr);
+
+ }
+
+ av1_print(hw, AOM_DEBUG_HW_MORE, "%s %d\n", __func__, __LINE__);
+
+ WRITE_VREG(AOM_AV1_DAALA_TOP_BUFFER,
+ buf_spec->daala_top.buf_start);
+ WRITE_VREG(AV1_GMC_PARAM_BUFF_ADDR,
+ buf_spec->gmc_buf.buf_start);
+
+ WRITE_VREG(HEVC_DBLK_CFG4,
+ buf_spec->dblk_para.buf_start); // cfg_addr_cif
+ WRITE_VREG(HEVC_DBLK_CFG5,
+ buf_spec->dblk_data.buf_start); // cfg_addr_xio
+
+ if (mask & HW_MASK_BACK) {
+#ifdef LOSLESS_COMPRESS_MODE
+ int losless_comp_header_size =
+ compute_losless_comp_header_size(hw->init_pic_w,
+ hw->init_pic_h);
+ int losless_comp_body_size =
+ compute_losless_comp_body_size(hw->init_pic_w,
+ hw->init_pic_h, buf_alloc_depth == 10);
+#endif
+#ifdef AOM_AV1_MMU_DW
+ int losless_comp_header_size_dw =
+ compute_losless_comp_header_size_dw(hw->init_pic_w,
+ hw->init_pic_h);
+ int losless_comp_body_size_dw =
+ compute_losless_comp_body_size_dw(hw->init_pic_w,
+ hw->init_pic_h, buf_alloc_depth == 10);
+#endif
+ WRITE_VREG(HEVCD_IPP_LINEBUFF_BASE,
+ buf_spec->ipp.buf_start);
+ //WRITE_VREG(HEVC_SAO_UP, buf_spec->sao_up.buf_start);
+ //WRITE_VREG(HEVC_SCALELUT, buf_spec->scalelut.buf_start);
+#ifdef CHANGE_REMOVED
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) {
+ /* cfg_addr_adp*/
+ WRITE_VREG(HEVC_DBLK_CFGE, buf_spec->dblk_para.buf_start);
+ if (debug & AV1_DEBUG_BUFMGR_MORE)
+ pr_info("Write HEVC_DBLK_CFGE\n");
+ }
+#endif
+ /* cfg_p_addr */
+ WRITE_VREG(HEVC_DBLK_CFG4, buf_spec->dblk_para.buf_start);
+ /* cfg_d_addr */
+ WRITE_VREG(HEVC_DBLK_CFG5, buf_spec->dblk_data.buf_start);
+
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) {
+ 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]
+ av1_print(hw, AV1_DEBUG_BUFMGR_MORE,
+ "HEVC_DBLK_CFG3 = %x\n", READ_VREG(HEVC_DBLK_CFG3));
+ }
+
+#ifdef LOSLESS_COMPRESS_MODE
+ if (hw->mmu_enable) {
+ /*bit[4] : paged_mem_mode*/
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0x1 << 4));
+#ifdef CHANGE_REMOVED
+ if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SM1)
+#endif
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL2, 0);
+ } else {
+ /*if (cur_pic_config->bit_depth == AOM_BITS_10)
+ * WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0<<3));
+ */
+ /*bit[3] smem mdoe*/
+ /*else WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (1<<3));*/
+ /*bit[3] smem mdoe*/
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL2,
+ (losless_comp_body_size >> 5));
+ }
+ /*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);
+ if (get_double_write_mode(hw) & 0x10)
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31);
+#else
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31);
+#endif
+
+ if (hw->mmu_enable) {
+ 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);
+ WRITE_VREG(HEVC_SAO_CTRL5, data32);
+ }
+#ifdef AOM_AV1_MMU_DW
+ data32 = READ_VREG(HEVC_SAO_CTRL5);
+ if (hw->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_dw);
+ WRITE_VREG(HEVC_CM_HEADER_OFFSET2,losless_comp_body_size_dw);
+ WRITE_VREG(HEVC_CM_HEADER_LENGTH2,losless_comp_header_size_dw);
+
+ WRITE_VREG(HEVC_SAO_MMU_VH0_ADDR2, buf_spec->mmu_vbh_dw.buf_start);
+ WRITE_VREG(HEVC_SAO_MMU_VH1_ADDR2, buf_spec->mmu_vbh_dw.buf_start
+ + DW_VBH_BUF_SIZE(buf_spec));
+
+ WRITE_VREG(HEVC_DW_VH0_ADDDR, buf_spec->mmu_vbh_dw.buf_start
+ + (2 * DW_VBH_BUF_SIZE(buf_spec)));
+ WRITE_VREG(HEVC_DW_VH1_ADDDR, buf_spec->mmu_vbh_dw.buf_start
+ + (3 * DW_VBH_BUF_SIZE(buf_spec)));
+
+ /* use HEVC_CM_HEADER_START_ADDR */
+ data32 |= (1<<15);
+ } else
+ data32 &= ~(1<<15);
+ WRITE_VREG(HEVC_SAO_CTRL5, data32);
+#endif
+
+ WRITE_VREG(LMEM_DUMP_ADR, (u32)hw->lmem_phy_addr);
+#ifdef CHANGE_REMOVED
+
+ WRITE_VREG(AV1_SEG_MAP_BUFFER, buf_spec->seg_map.buf_start);
+
+ /**/
+ WRITE_VREG(AV1_PROB_SWAP_BUFFER, hw->prob_buffer_phy_addr);
+ WRITE_VREG(AV1_COUNT_SWAP_BUFFER, hw->count_buffer_phy_addr);
+ if (hw->mmu_enable) {
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
+ WRITE_VREG(HEVC_ASSIST_MMU_MAP_ADDR, hw->frame_mmu_map_phy_addr);
+ else
+ WRITE_VREG(AV1_MMU_MAP_BUFFER, hw->frame_mmu_map_phy_addr);
+ }
+#else
+ if (hw->mmu_enable)
+ WRITE_VREG(HEVC_SAO_MMU_DMA_CTRL, hw->frame_mmu_map_phy_addr);
+#ifdef AOM_AV1_MMU_DW
+ if (hw->dw_mmu_enable) {
+ WRITE_VREG(HEVC_SAO_MMU_DMA_CTRL2, hw->dw_frame_mmu_map_phy_addr);
+ //default of 0xffffffff will disable dw
+ WRITE_VREG(HEVC_SAO_Y_START_ADDR, 0);
+ WRITE_VREG(HEVC_SAO_C_START_ADDR, 0);
+ }
+#endif
+#endif
+ }
+
+ config_aux_buf(hw);
+}
+
+#ifdef MCRCC_ENABLE
+static u32 mcrcc_cache_alg_flag = 1;
+static void mcrcc_perfcount_reset(struct AV1HW_s *hw);
+static void decomp_perfcount_reset(struct AV1HW_s *hw);
+#endif
+
+static void aom_init_decoder_hw(struct AV1HW_s *hw, u32 mask)
+{
+ unsigned int data32;
+ int i;
+ const 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
+ };
+#if 0
+ if (get_cpu_major_id() >= MESON_CPU_MAJOR_ID_G12A) {
+ /* Set MCR fetch priorities*/
+ data32 = 0x1 | (0x1 << 2) | (0x1 <<3) |
+ (24 << 4) | (32 << 11) | (24 << 18) | (32 << 25);
+ WRITE_VREG(HEVCD_MPP_DECOMP_AXIURG_CTL, data32);
+ }
+#endif
+ /*if (debug & AV1_DEBUG_BUFMGR_MORE)
+ pr_info("%s\n", __func__);*/
+ if (mask & HW_MASK_FRONT) {
+ data32 = READ_VREG(HEVC_PARSER_INT_CONTROL);
+#ifdef CHANGE_REMOVED
+#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*/
+ ;
+#else
+ data32 = data32 & 0x03ffffff;
+ data32 = data32 |
+ (3 << 29) | // stream_buffer_empty_int_ctl ( 0x200 interrupt)
+ (3 << 26) | // stream_fifo_empty_int_ctl ( 4 interrupt)
+ (1 << 24) | // stream_buffer_empty_int_amrisc_enable
+ (1 << 22) | // stream_fifo_empty_int_amrisc_enable
+#ifdef AOM_AV1_HED_FB
+#ifdef DUAL_DECODE
+ // For HALT CCPU test. Use Pull inside CCPU to generate interrupt
+ // (1 << 9) | // fed_fb_slice_done_int_amrisc_enable
+#else
+ (1 << 10) | // fed_fb_slice_done_int_cpu_enable
+#endif
+#endif
+ (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
+ ;
+#endif
+ WRITE_VREG(HEVC_PARSER_INT_CONTROL, data32);
+
+ data32 = READ_VREG(HEVC_SHIFT_STATUS);
+ data32 = data32 |
+ (0 << 1) |/*emulation_check_off AV1
+ do not have emulation*/
+ (1 << 0)/*startcode_check_on*/
+ ;
+ WRITE_VREG(HEVC_SHIFT_STATUS, data32);
+ WRITE_VREG(HEVC_SHIFT_CONTROL,
+ (0 << 14) | /*disable_start_code_protect*/
+ (1 << 10) | /*length_zero_startcode_en for AV1*/
+ (1 << 9) | /*length_valid_startcode_en for AV1*/
+ (3 << 6) | /*sft_valid_wr_position*/
+ (2 << 4) | /*emulate_code_length_sub_1*/
+ (3 << 1) | /*start_code_length_sub_1
+ AV1 use 0x00000001 as startcode (4 Bytes)*/
+ (1 << 0) /*stream_shift_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);
+ }
+
+ if (mask & HW_MASK_BACK) {
+ /*Initial IQIT_SCALELUT memory
+ -- just to avoid X in simulation*/
+
+ WRITE_VREG(HEVC_IQIT_SCALELUT_WR_ADDR, 0);/*cfg_p_addr*/
+ for (i = 0; i < 1024; i++)
+ WRITE_VREG(HEVC_IQIT_SCALELUT_DATA, 0);
+ }
+
+ if (mask & HW_MASK_FRONT) {
+ u32 decode_mode;
+/*
+#ifdef ENABLE_SWAP_TEST
+ WRITE_VREG(HEVC_STREAM_SWAP_TEST, 100);
+#else
+ WRITE_VREG(HEVC_STREAM_SWAP_TEST, 0);
+#endif
+*/
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (!hw->m_ins_flag) {
+ if (hw->low_latency_flag)
+ decode_mode = DECODE_MODE_SINGLE_LOW_LATENCY;
+ else
+ decode_mode = DECODE_MODE_SINGLE;
+ } else if (vdec_frame_based(hw_to_vdec(hw)))
+ decode_mode = hw->no_head ?
+ DECODE_MODE_MULTI_FRAMEBASE_NOHEAD :
+ DECODE_MODE_MULTI_FRAMEBASE;
+ else
+ decode_mode = DECODE_MODE_MULTI_STREAMBASE;
+ if (debug & AOM_DEBUG_BUFMGR_ONLY)
+ decode_mode |= (1 << 16);
+ WRITE_VREG(DECODE_MODE, decode_mode);
+ WRITE_VREG(HEVC_DECODE_SIZE, 0);
+ WRITE_VREG(HEVC_DECODE_COUNT, 0);
+#else
+ WRITE_VREG(DECODE_MODE, DECODE_MODE_SINGLE);
+ WRITE_VREG(HEVC_DECODE_PIC_BEGIN_REG, 0);
+ WRITE_VREG(HEVC_DECODE_PIC_NUM_REG, 0x7fffffff); /*to remove*/
+#endif
+ /*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 << 8) |*/ /*sao_sw_pred_enable*/
+ (1 << 5) | /*parser_sao_if_en*/
+ (1 << 2) | /*parser_mpred_if_en*/
+ (1 << 0) /*parser_scaler_if_en*/
+ );
+ }
+
+ if (mask & HW_MASK_BACK) {
+ /*Changed to Start MPRED in microcode*/
+ /*
+ pr_info("[test.c] Start MPRED\n");
+ WRITE_VREG(HEVC_MPRED_INT_STATUS,
+ (1<<31)
+ );
+ */
+ WRITE_VREG(HEVCD_IPP_TOP_CNTL,
+ (0 << 1) | /*enable ipp*/
+ (1 << 0) /*software reset ipp and mpp*/
+ );
+#ifdef CHANGE_REMOVED
+ WRITE_VREG(HEVCD_IPP_TOP_CNTL,
+ (1 << 1) | /*enable ipp*/
+ (0 << 0) /*software reset ipp and mpp*/
+ );
+#else
+ WRITE_VREG(HEVCD_IPP_TOP_CNTL,
+ (3 << 4) | // av1
+ (1 << 1) | /*enable ipp*/
+ (0 << 0) /*software reset ipp and mpp*/
+ );
+#endif
+ if (get_double_write_mode(hw) & 0x10) {
+ /*Enable NV21 reference read mode for MC*/
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31);
+ }
+#ifdef MCRCC_ENABLE
+ /*Initialize mcrcc and decomp perf counters*/
+ if (mcrcc_cache_alg_flag &&
+ hw->init_flag == 0) {
+ mcrcc_perfcount_reset(hw);
+ decomp_perfcount_reset(hw);
+ }
+#endif
+ }
+#ifdef CHANGE_REMOVED
+#else
+// Set MCR fetch priorities
+ data32 = 0x1 | (0x1 << 2) | (0x1 <<3) |
+ (24 << 4) | (32 << 11) | (24 << 18) | (32 << 25);
+ WRITE_VREG(HEVCD_MPP_DECOMP_AXIURG_CTL, data32);
+#endif
+ return;
+}
+
+
+#ifdef CONFIG_HEVC_CLK_FORCED_ON
+static void config_av1_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 int vav1_mmu_map_alloc(struct AV1HW_s *hw)
+{
+ if (hw->mmu_enable) {
+ u32 mmu_map_size = vav1_frame_mmu_map_size(hw);
+ hw->frame_mmu_map_addr =
+ dma_alloc_coherent(amports_get_dma_device(),
+ 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 -1;
+ }
+ memset(hw->frame_mmu_map_addr, 0, mmu_map_size);
+ }
+#ifdef AOM_AV1_MMU_DW
+ if (hw->dw_mmu_enable) {
+ u32 mmu_map_size = vaom_dw_frame_mmu_map_size(hw);
+ hw->dw_frame_mmu_map_addr =
+ dma_alloc_coherent(amports_get_dma_device(),
+ mmu_map_size,
+ &hw->dw_frame_mmu_map_phy_addr, GFP_KERNEL);
+ if (hw->dw_frame_mmu_map_addr == NULL) {
+ pr_err("%s: failed to alloc count_buffer\n", __func__);
+ return -1;
+ }
+ memset(hw->dw_frame_mmu_map_addr, 0, mmu_map_size);
+ }
+#endif
+ return 0;
+}
+
+
+static void vav1_mmu_map_free(struct AV1HW_s *hw)
+{
+ if (hw->mmu_enable) {
+ u32 mmu_map_size = vav1_frame_mmu_map_size(hw);
+ if (hw->frame_mmu_map_addr) {
+ if (hw->frame_mmu_map_phy_addr)
+ dma_free_coherent(amports_get_dma_device(),
+ mmu_map_size,
+ hw->frame_mmu_map_addr,
+ hw->frame_mmu_map_phy_addr);
+ hw->frame_mmu_map_addr = NULL;
+ }
+ }
+#ifdef AOM_AV1_MMU_DW
+ if (hw->dw_mmu_enable) {
+ u32 mmu_map_size = vaom_dw_frame_mmu_map_size(hw);
+ if (hw->dw_frame_mmu_map_addr) {
+ if (hw->dw_frame_mmu_map_phy_addr)
+ dma_free_coherent(amports_get_dma_device(),
+ mmu_map_size,
+ hw->dw_frame_mmu_map_addr,
+ hw->dw_frame_mmu_map_phy_addr);
+ hw->dw_frame_mmu_map_addr = NULL;
+ }
+ }
+#endif
+}
+
+
+static void av1_local_uninit(struct AV1HW_s *hw)
+{
+ hw->rpm_ptr = NULL;
+ hw->lmem_ptr = NULL;
+#ifdef DUMP_FILMGRAIN
+ hw->fg_ptr = NULL;
+ if (hw->fg_addr) {
+ if (hw->fg_phy_addr)
+ dma_free_coherent(amports_get_dma_device(),
+ FGS_TABLE_SIZE, hw->fg_addr,
+ hw->fg_phy_addr);
+ hw->fg_addr = NULL;
+ }
+#endif
+ if (hw->rpm_addr) {
+ dma_free_coherent(amports_get_dma_device(),
+ RPM_BUF_SIZE,
+ hw->rpm_addr,
+ hw->rpm_phy_addr);
+ hw->rpm_addr = NULL;
+ }
+ 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 (defined DEBUG_UCODE_LOG) || (defined DEBUG_CMD)
+ if (hw->ucode_log_addr) {
+ dma_free_coherent(amports_get_dma_device(),
+ UCODE_LOG_BUF_SIZE, hw->ucode_log_addr,
+ hw->ucode_log_phy_addr);
+ hw->ucode_log_addr = NULL;
+ }
+#endif
+ if (hw->lmem_addr) {
+ if (hw->lmem_phy_addr)
+ dma_free_coherent(amports_get_dma_device(),
+ LMEM_BUF_SIZE, hw->lmem_addr,
+ hw->lmem_phy_addr);
+ hw->lmem_addr = NULL;
+ }
+ if (hw->prob_buffer_addr) {
+ if (hw->prob_buffer_phy_addr)
+ dma_free_coherent(amports_get_dma_device(),
+ PROB_BUF_SIZE, hw->prob_buffer_addr,
+ hw->prob_buffer_phy_addr);
+
+ hw->prob_buffer_addr = NULL;
+ }
+ if (hw->count_buffer_addr) {
+ if (hw->count_buffer_phy_addr)
+ dma_free_coherent(amports_get_dma_device(),
+ COUNT_BUF_SIZE, hw->count_buffer_addr,
+ hw->count_buffer_phy_addr);
+
+ hw->count_buffer_addr = NULL;
+ }
+
+ vav1_mmu_map_free(hw);
+
+ if (hw->gvs)
+ vfree(hw->gvs);
+ hw->gvs = NULL;
+}
+
+static int av1_local_init(struct AV1HW_s *hw)
+{
+ int ret = -1;
+ /*int losless_comp_header_size, losless_comp_body_size;*/
+
+ struct BuffInfo_s *cur_buf_info = NULL;
+
+ memset(&hw->param, 0, sizeof(union param_u));
+#ifdef MULTI_INSTANCE_SUPPORT
+ cur_buf_info = &hw->work_space_buf_store;
+ hw->pbi->work_space_buf = cur_buf_info;
+#if 0
+ if (vdec_is_support_4k()) {
+ memcpy(cur_buf_info, &aom_workbuff_spec[1], /* 8k */
+ sizeof(struct BuffInfo_s));
+ } else
+ memcpy(cur_buf_info, &aom_workbuff_spec[0],/* 1080p */
+ sizeof(struct BuffInfo_s));
+#endif
+ memcpy(cur_buf_info, &aom_workbuff_spec[hw->buffer_spec_index],
+ sizeof(struct BuffInfo_s));
+
+ cur_buf_info->start_adr = hw->buf_start;
+ if (!hw->mmu_enable)
+ hw->mc_buf_spec.buf_end = hw->buf_start + hw->buf_size;
+
+#else
+/*! MULTI_INSTANCE_SUPPORT*/
+#if 0
+ if (vdec_is_support_4k()) {
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1)
+ cur_buf_info = &aom_workbuff_spec[1];/* 8k work space */
+ else
+ cur_buf_info = &aom_workbuff_spec[1];/* 4k2k work space */
+ } else
+ cur_buf_info = &aom_workbuff_spec[0];/* 1080p work space */
+#endif
+ memcpy(cur_buf_info, &aom_workbuff_spec[hw->buffer_spec_index],
+ sizeof(struct BuffInfo_s));
+#endif
+
+ init_buff_spec(hw, cur_buf_info);
+ aom_bufmgr_init(hw, cur_buf_info, NULL);
+
+ if (!vdec_is_support_4k()
+ && (buf_alloc_width > 1920 && buf_alloc_height > 1088)) {
+ buf_alloc_width = 1920;
+ buf_alloc_height = 1088;
+ if (hw->max_pic_w > 1920 && hw->max_pic_h > 1088) {
+ hw->max_pic_w = 1920;
+ hw->max_pic_h = 1088;
+ }
+ } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) {
+ buf_alloc_width = 8192;
+ buf_alloc_height = 4608;
+ }
+#if 0
+ hw->init_pic_w = hw->max_pic_w ? hw->max_pic_w :
+ (buf_alloc_width ? buf_alloc_width :
+ (hw->vav1_amstream_dec_info.width ?
+ hw->vav1_amstream_dec_info.width :
+ hw->work_space_buf->max_width));
+ hw->init_pic_h = hw->max_pic_h ? hw->max_pic_h :
+ (buf_alloc_height ? buf_alloc_height :
+ (hw->vav1_amstream_dec_info.height ?
+ hw->vav1_amstream_dec_info.height :
+ hw->work_space_buf->max_height));
+#else
+ hw->init_pic_w = hw->max_pic_w ? hw->max_pic_w :
+ (hw->vav1_amstream_dec_info.width ? hw->vav1_amstream_dec_info.width :
+ (buf_alloc_width ? buf_alloc_width : hw->work_space_buf->max_width));
+ hw->init_pic_h = hw->max_pic_h ? hw->max_pic_h :
+ (hw->vav1_amstream_dec_info.height ? hw->vav1_amstream_dec_info.height :
+ (buf_alloc_height ? buf_alloc_height : hw->work_space_buf->max_height));
+#endif
+ hw->pbi->frame_width = hw->init_pic_w;
+ hw->pbi->frame_height = hw->init_pic_h;
+
+ /* video is not support unaligned with 64 in tl1
+ ** vdec canvas mode will be linear when dump yuv is set
+ */
+ if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
+ (hw->double_write_mode != 0) &&
+ (((hw->max_pic_w % 64) != 0) ||
+ (hw->vav1_amstream_dec_info.width % 64) != 0)) {
+ if (hw_to_vdec(hw)->canvas_mode !=
+ CANVAS_BLKMODE_LINEAR)
+ mem_map_mode = 2;
+ else {
+ mem_map_mode = 0;
+ av1_print(hw, AOM_DEBUG_HW_MORE, "vdec blkmod linear, force mem_map_mode 0\n");
+ }
+ }
+
+#if 0
+//ndef MV_USE_FIXED_BUF
+ if (init_mv_buf_list(hw) < 0) {
+ pr_err("%s: init_mv_buf_list fail\n", __func__);
+ return -1;
+ }
+#endif
+
+ hw->mv_buf_margin = mv_buf_margin;
+ if (IS_4K_SIZE(hw->init_pic_w, hw->init_pic_h)) {
+ hw->used_buf_num = MAX_BUF_NUM_LESS + dynamic_buf_num_margin;
+ if (hw->used_buf_num > REF_FRAMES_4K)
+ hw->mv_buf_margin = hw->used_buf_num - REF_FRAMES_4K + 1;
+ }
+ else
+ hw->used_buf_num = max_buf_num + dynamic_buf_num_margin;
+
+ if (hw->is_used_v4l)
+ hw->used_buf_num = 9 + hw->dynamic_buf_num_margin;
+
+ if (hw->used_buf_num > MAX_BUF_NUM)
+ hw->used_buf_num = MAX_BUF_NUM;
+ if (hw->used_buf_num > FRAME_BUFFERS)
+ hw->used_buf_num = FRAME_BUFFERS;
+
+ hw->pts_unstable = ((unsigned long)(hw->vav1_amstream_dec_info.param)
+ & 0x40) >> 6;
+
+ if ((debug & AOM_AV1_DEBUG_SEND_PARAM_WITH_REG) == 0) {
+ hw->rpm_addr = dma_alloc_coherent(amports_get_dma_device(),
+ RPM_BUF_SIZE,
+ &hw->rpm_phy_addr, GFP_KERNEL);
+ if (hw->rpm_addr == NULL) {
+ pr_err("%s: failed to alloc rpm buffer\n", __func__);
+ return -1;
+ }
+ hw->rpm_ptr = hw->rpm_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__);
+ goto dma_alloc_fail;
+ }
+ }
+#if (defined DEBUG_UCODE_LOG) || (defined DEBUG_CMD)
+ //if (udebug_flag & 0x8) {
+ hw->ucode_log_addr = dma_alloc_coherent(amports_get_dma_device(),
+ UCODE_LOG_BUF_SIZE, &hw->ucode_log_phy_addr, GFP_KERNEL);
+ if (hw->ucode_log_addr == NULL) {
+ hw->ucode_log_phy_addr = 0;
+ }
+ pr_info("%s: alloc ucode log buffer %p\n",
+ __func__, hw->ucode_log_addr);
+ //}
+#endif
+#ifdef DUMP_FILMGRAIN
+ hw->fg_addr = dma_alloc_coherent(amports_get_dma_device(),
+ FGS_TABLE_SIZE,
+ &hw->fg_phy_addr, GFP_KERNEL);
+ if (hw->fg_addr == NULL) {
+ pr_err("%s: failed to alloc fg buffer\n", __func__);
+ }
+ hw->fg_ptr = hw->fg_addr;
+#endif
+ hw->lmem_addr = dma_alloc_coherent(amports_get_dma_device(),
+ LMEM_BUF_SIZE,
+ &hw->lmem_phy_addr, GFP_KERNEL);
+ if (hw->lmem_addr == NULL) {
+ pr_err("%s: failed to alloc lmem buffer\n", __func__);
+ goto dma_alloc_fail;
+ }
+ hw->lmem_ptr = hw->lmem_addr;
+
+ hw->prob_buffer_addr = dma_alloc_coherent(amports_get_dma_device(),
+ PROB_BUF_SIZE,
+ &hw->prob_buffer_phy_addr, GFP_KERNEL);
+ if (hw->prob_buffer_addr == NULL) {
+ pr_err("%s: failed to alloc prob_buffer\n", __func__);
+ goto dma_alloc_fail;
+ }
+ memset(hw->prob_buffer_addr, 0, PROB_BUF_SIZE);
+ hw->count_buffer_addr = dma_alloc_coherent(amports_get_dma_device(),
+ COUNT_BUF_SIZE,
+ &hw->count_buffer_phy_addr, GFP_KERNEL);
+ if (hw->count_buffer_addr == NULL) {
+ pr_err("%s: failed to alloc count_buffer\n", __func__);
+ goto dma_alloc_fail;
+ }
+ memset(hw->count_buffer_addr, 0, COUNT_BUF_SIZE);
+
+ ret = vav1_mmu_map_alloc(hw);
+ if (ret < 0)
+ goto dma_alloc_fail;
+
+ return ret;
+
+dma_alloc_fail:
+ av1_local_uninit(hw);
+ return -1;
+}
+
+
+#define spec2canvas(x) \
+ (((x)->uv_canvas_index << 16) | \
+ ((x)->uv_canvas_index << 8) | \
+ ((x)->y_canvas_index << 0))
+
+
+static void set_canvas(struct AV1HW_s *hw,
+ struct PIC_BUFFER_CONFIG_s *pic_config)
+{
+ struct vdec_s *vdec = hw_to_vdec(hw);
+ int canvas_w = ALIGN(pic_config->y_crop_width, 64)/4;
+ int canvas_h = ALIGN(pic_config->y_crop_height, 32)/4;
+ int blkmode = mem_map_mode;
+ /*CANVAS_BLKMODE_64X32*/
+ if (pic_config->double_write_mode) {
+ canvas_w = pic_config->y_crop_width /
+ get_double_write_ratio(hw,
+ pic_config->double_write_mode);
+ canvas_h = pic_config->y_crop_height /
+ get_double_write_ratio(hw,
+ pic_config->double_write_mode);
+
+ if (mem_map_mode == 0)
+ canvas_w = ALIGN(canvas_w, 32);
+ else
+ canvas_w = ALIGN(canvas_w, 64);
+ canvas_h = ALIGN(canvas_h, 32);
+
+ if (vdec->parallel_dec == 1) {
+ if (pic_config->y_canvas_index == -1)
+ pic_config->y_canvas_index =
+ vdec->get_canvas_ex(CORE_MASK_HEVC, vdec->id);
+ if (pic_config->uv_canvas_index == -1)
+ pic_config->uv_canvas_index =
+ vdec->get_canvas_ex(CORE_MASK_HEVC, vdec->id);
+ } else {
+ pic_config->y_canvas_index = 128 + pic_config->index * 2;
+ pic_config->uv_canvas_index = 128 + pic_config->index * 2 + 1;
+ }
+
+ canvas_config_ex(pic_config->y_canvas_index,
+ pic_config->dw_y_adr, canvas_w, canvas_h,
+ CANVAS_ADDR_NOWRAP, blkmode, hw->is_used_v4l ? 0 : 7);
+ canvas_config_ex(pic_config->uv_canvas_index,
+ pic_config->dw_u_v_adr, canvas_w, canvas_h,
+ CANVAS_ADDR_NOWRAP, blkmode, hw->is_used_v4l ? 0 : 7);
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ pic_config->canvas_config[0].phy_addr =
+ pic_config->dw_y_adr;
+ pic_config->canvas_config[0].width =
+ canvas_w;
+ pic_config->canvas_config[0].height =
+ canvas_h;
+ pic_config->canvas_config[0].block_mode =
+ blkmode;
+ pic_config->canvas_config[0].endian = hw->is_used_v4l ? 0 : 7;
+
+ pic_config->canvas_config[1].phy_addr =
+ pic_config->dw_u_v_adr;
+ pic_config->canvas_config[1].width =
+ canvas_w;
+ pic_config->canvas_config[1].height =
+ canvas_h;
+ pic_config->canvas_config[1].block_mode =
+ blkmode;
+ pic_config->canvas_config[1].endian = hw->is_used_v4l ? 0 : 7;
+#endif
+ }
+}
+
+static void set_frame_info(struct AV1HW_s *hw, struct vframe_s *vf)
+{
+ unsigned int ar = DISP_RATIO_ASPECT_RATIO_MAX;
+ vf->duration = hw->frame_dur;
+ vf->duration_pulldown = 0;
+ vf->flag = 0;
+ vf->prop.master_display_colour = hw->vf_dp;
+ vf->signal_type = hw->video_signal_type;
+ if (vf->compWidth && vf->compHeight)
+ hw->frame_ar = vf->compHeight * 0x100 / vf->compWidth;
+ ar = min_t(u32, ar, DISP_RATIO_ASPECT_RATIO_MAX);
+ vf->ratio_control = (ar << DISP_RATIO_ASPECT_RATIO_BIT);
+ vf->sar_width = 1;
+ vf->sar_height = 1;
+
+ if (hw->is_used_v4l && hw->vf_dp.present_flag) {
+ 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 = vf->signal_type;
+ hdr.color_parms = hw->vf_dp;
+ vdec_v4l_set_hdr_infos(ctx, &hdr);
+ }
+
+ vf->sidebind_type = hw->sidebind_type;
+ vf->sidebind_channel_id = hw->sidebind_channel_id;
+}
+
+static int vav1_vf_states(struct vframe_states *states, void *op_arg)
+{
+ struct AV1HW_s *hw = (struct AV1HW_s *)op_arg;
+
+ 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);
+
+ if (step == 2)
+ states->buf_avail_num = 0;
+ return 0;
+}
+
+static struct vframe_s *vav1_vf_peek(void *op_arg)
+{
+ struct vframe_s *vf[2] = {0, 0};
+ struct AV1HW_s *hw = (struct AV1HW_s *)op_arg;
+
+ if (step == 2)
+ 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 *vav1_vf_get(void *op_arg)
+{
+ struct vframe_s *vf;
+ struct AV1HW_s *hw = (struct AV1HW_s *)op_arg;
+
+ if (step == 2)
+ return NULL;
+ else if (step == 1)
+ step = 2;
+
+ if (kfifo_get(&hw->display_q, &vf)) {
+ struct vframe_s *next_vf = NULL;
+ uint8_t index = vf->index & 0xff;
+ ATRACE_COUNTER(hw->disp_q_name, kfifo_len(&hw->display_q));
+ if (index < hw->used_buf_num ||
+ (vf->type & VIDTYPE_V4L_EOS)) {
+ hw->vf_get_count++;
+ if (debug & AOM_DEBUG_VFRAME) {
+ struct BufferPool_s *pool = hw->common.buffer_pool;
+ struct PIC_BUFFER_CONFIG_s *pic =
+ &pool->frame_bufs[index].buf;
+ unsigned long flags;
+ lock_buffer_pool(hw->common.buffer_pool, flags);
+ av1_print(hw, AOM_DEBUG_VFRAME, "%s index 0x%x type 0x%x w/h %d/%d, aux size %d, pts %d, %lld, ts: %llu\n",
+ __func__, vf->index, vf->type,
+ vf->width, vf->height,
+ pic->aux_data_size,
+ vf->pts,
+ vf->pts_us64,
+ vf->timestamp);
+ unlock_buffer_pool(hw->common.buffer_pool, flags);
+ }
+
+ 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;
+#ifdef DUMP_FILMGRAIN
+ if (index == fg_dump_index) {
+ unsigned long flags;
+ int ii;
+ lock_buffer_pool(hw->common.buffer_pool, flags);
+ pr_info("FGS_TABLE for buffer %d:\n", index);
+ for (ii = 0; ii < FGS_TABLE_SIZE; ii++) {
+ pr_info("%02x ", hw->fg_ptr[ii]);
+ if (((ii+ 1) & 0xf) == 0)
+ pr_info("\n");
+ }
+ unlock_buffer_pool(hw->common.buffer_pool, flags);
+ }
+#endif
+
+ return vf;
+ }
+ }
+ return NULL;
+}
+
+static void vav1_vf_put(struct vframe_s *vf, void *op_arg)
+{
+ struct AV1HW_s *hw = (struct AV1HW_s *)op_arg;
+ uint8_t index;
+ unsigned long flags;
+
+ if ((vf == NULL) || (hw == NULL))
+ return;
+
+ index = vf->index & 0xff;
+
+ kfifo_put(&hw->newframe_q, (const struct vframe_s *)vf);
+ ATRACE_COUNTER(hw->new_q_name, kfifo_len(&hw->newframe_q));
+ hw->vf_put_count++;
+ if (debug & AOM_DEBUG_VFRAME) {
+ lock_buffer_pool(hw->common.buffer_pool, flags);
+ av1_print(hw, AOM_DEBUG_VFRAME, "%s index 0x%x type 0x%x w/h %d/%d, pts %d, %lld, ts: %llu\n",
+ __func__, vf->index, vf->type,
+ vf->width, vf->height,
+ vf->pts,
+ vf->pts_us64,
+ vf->timestamp);
+ unlock_buffer_pool(hw->common.buffer_pool, flags);
+ }
+
+ if (index < hw->used_buf_num) {
+ struct AV1_Common_s *cm = &hw->common;
+ struct BufferPool_s *pool = cm->buffer_pool;
+
+ lock_buffer_pool(hw->common.buffer_pool, flags);
+ if ((debug & AV1_DEBUG_IGNORE_VF_REF) == 0) {
+ if (pool->frame_bufs[index].buf.vf_ref > 0)
+ pool->frame_bufs[index].buf.vf_ref--;
+ }
+
+ if (hw->is_used_v4l)
+ pool->frame_bufs[index].buf.vframe_bound = true;
+
+ if (hw->wait_buf)
+ WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG,
+ 0x1);
+ hw->last_put_idx = index;
+ hw->new_frame_displayed++;
+ unlock_buffer_pool(hw->common.buffer_pool, flags);
+ }
+
+}
+
+static int vav1_event_cb(int type, void *data, void *op_arg)
+{
+ unsigned long flags;
+ struct AV1HW_s *hw = (struct AV1HW_s *)op_arg;
+ struct AV1_Common_s *cm = &hw->common;
+ struct BufferPool_s *pool = cm->buffer_pool;
+
+ if (type & VFRAME_EVENT_RECEIVER_RESET) {
+#if 0
+ unsigned long flags;
+
+ amhevc_stop();
+#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vf_light_unreg_provider(&vav1_vf_prov);
+#endif
+ spin_lock_irqsave(&hw->lock, flags);
+ vav1_local_init();
+ vav1_prot_init();
+ spin_unlock_irqrestore(&hw->lock, flags);
+#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vf_reg_provider(&vav1_vf_prov);
+#endif
+ amhevc_start();
+#endif
+ } else if (type & VFRAME_EVENT_RECEIVER_GET_AUX_DATA) {
+ struct provider_aux_req_s *req =
+ (struct provider_aux_req_s *)data;
+ unsigned char index;
+
+ lock_buffer_pool(hw->common.buffer_pool, flags);
+ index = req->vf->index & 0xff;
+ req->aux_buf = NULL;
+ req->aux_size = 0;
+ if (req->bot_flag)
+ index = (req->vf->index >> 8) & 0xff;
+ if (index != 0xff
+ && index < hw->used_buf_num) {
+ struct PIC_BUFFER_CONFIG_s *pic_config =
+ &pool->frame_bufs[index].buf;
+ req->aux_buf = pic_config->aux_data_buf;
+ req->aux_size = pic_config->aux_data_size;
+#if 0
+//def CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ if (hw->bypass_dvenl && !dolby_meta_with_el)
+ req->dv_enhance_exist = false;
+ else
+ req->dv_enhance_exist =
+ pic_config->dv_enhance_exist;
+ av1_print(hw, AOM_DEBUG_VFRAME,
+ "query dv_enhance_exist for pic (vf 0x%p, poc %d index %d) flag => %d, aux sizd 0x%x\n",
+ req->vf,
+ pic_config->POC, index,
+ req->dv_enhance_exist, req->aux_size);
+#else
+ req->dv_enhance_exist = 0;
+#endif
+ }
+ unlock_buffer_pool(hw->common.buffer_pool, flags);
+
+ if (debug & AOM_DEBUG_AUX_DATA)
+ av1_print(hw, 0,
+ "%s(type 0x%x vf index 0x%x)=>size 0x%x\n",
+ __func__, type, index, 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(hw_to_vdec(hw));
+ else
+ req->req_result[0] = 0xffffffff;
+ }
+ return 0;
+}
+
+void av1_inc_vf_ref(struct AV1HW_s *hw, int index)
+{
+ struct AV1_Common_s *cm = &hw->common;
+
+ if ((debug & AV1_DEBUG_IGNORE_VF_REF) == 0) {
+ cm->buffer_pool->frame_bufs[index].buf.vf_ref++;
+
+ av1_print(hw, AV1_DEBUG_BUFMGR_MORE, "%s index = %d new vf_ref = %d\r\n",
+ __func__, index,
+ cm->buffer_pool->frame_bufs[index].buf.vf_ref);
+ }
+}
+#if 0
+static int frame_duration_adapt(struct AV1HW_s *hw, struct vframe_s *vf, u32 valid)
+{
+ u32 old_duration, pts_duration = 0;
+ u32 pts = vf->pts;
+
+ if (hw->get_frame_dur == true)
+ return true;
+
+ hw->frame_cnt_window++;
+ if (!(hw->av1_first_pts_ready == 1)) {
+ if (valid) {
+ hw->pts1 = pts;
+ hw->frame_cnt_window = 0;
+ hw->duration_from_pts_done = 0;
+ hw->av1_first_pts_ready = 1;
+ } else {
+ return false;
+ }
+ } else {
+ if (pts < hw->pts1) {
+ if (hw->frame_cnt_window > FRAME_CNT_WINDOW_SIZE) {
+ hw->pts1 = pts;
+ hw->frame_cnt_window = 0;
+ }
+ }
+
+ if (valid && (hw->frame_cnt_window > FRAME_CNT_WINDOW_SIZE) &&
+ (pts > hw->pts1) && (hw->duration_from_pts_done == 0)) {
+ old_duration = hw->frame_dur;
+ hw->pts2 = pts;
+ pts_duration = (((hw->pts2 - hw->pts1) * 16) /
+ (hw->frame_cnt_window * 15));
+
+ if (close_to(pts_duration, old_duration, 2000)) {
+ hw->frame_dur = pts_duration;
+ av1_print(hw, AV1_DEBUG_OUT_PTS,
+ "use calc duration %d\n", pts_duration);
+ }
+
+ if (hw->duration_from_pts_done == 0) {
+ if (close_to(pts_duration, old_duration, RATE_CORRECTION_THRESHOLD)) {
+ hw->duration_from_pts_done = 1;
+ } else {
+ if (!close_to(pts_duration,
+ old_duration, 1000) &&
+ !close_to(pts_duration,
+ hw->frame_dur, 1000) &&
+ close_to(pts_duration,
+ hw->last_duration, 200)) {
+ /* frame_dur must
+ * wrong,recover it.
+ */
+ hw->frame_dur = pts_duration;
+ }
+ hw->pts1 = hw->pts2;
+ hw->frame_cnt_window = 0;
+ hw->duration_from_pts_done = 0;
+ }
+ }
+ hw->last_duration = pts_duration;
+ }
+ }
+ return true;
+}
+#endif
+
+static void update_vf_memhandle(struct AV1HW_s *hw,
+ struct vframe_s *vf, struct PIC_BUFFER_CONFIG_s *pic)
+{
+ /* keeper not needed for v4l solution */
+ if (hw->is_used_v4l)
+ return;
+
+ if (pic->index < 0) {
+ vf->mem_handle = NULL;
+ vf->mem_head_handle = NULL;
+ vf->mem_dw_handle = NULL;
+ } else if (vf->type & VIDTYPE_SCATTER) {
+#ifdef AOM_AV1_MMU_DW
+ if (pic->double_write_mode & 0x20 &&
+ (debug & AOM_DEBUG_DW_DISP_MAIN) == 0) {
+ vf->mem_handle =
+ decoder_mmu_box_get_mem_handle(
+ hw->mmu_box_dw, hw->buffer_wrap[pic->index]);
+ vf->mem_head_handle =
+ decoder_bmmu_box_get_mem_handle(
+ hw->bmmu_box,
+ DW_HEADER_BUFFER_IDX(hw->buffer_wrap[pic->BUF_index]));
+ vf->mem_dw_handle = NULL;
+ } else
+#endif
+ {
+ vf->mem_handle =
+ decoder_mmu_box_get_mem_handle(
+ hw->mmu_box, hw->buffer_wrap[pic->index]);
+ vf->mem_head_handle =
+ decoder_bmmu_box_get_mem_handle(
+ hw->bmmu_box,
+ HEADER_BUFFER_IDX(hw->buffer_wrap[pic->BUF_index]));
+ if (hw->double_write_mode == 3)
+ vf->mem_dw_handle =
+ decoder_bmmu_box_get_mem_handle(
+ hw->bmmu_box,
+ VF_BUFFER_IDX(hw->buffer_wrap[pic->BUF_index]));
+ else
+ vf->mem_dw_handle = NULL;
+ }
+#ifdef USE_SPEC_BUF_FOR_MMU_HEAD
+ vf->mem_head_handle = NULL;
+#endif
+ } else {
+ vf->mem_handle =
+ decoder_bmmu_box_get_mem_handle(
+ hw->bmmu_box, VF_BUFFER_IDX(hw->buffer_wrap[pic->BUF_index]));
+ vf->mem_head_handle = NULL;
+ vf->mem_dw_handle = NULL;
+ /*vf->mem_head_handle =
+ *decoder_bmmu_box_get_mem_handle(
+ *hw->bmmu_box, VF_BUFFER_IDX(BUF_index));
+ */
+ }
+}
+
+static int prepare_display_buf(struct AV1HW_s *hw,
+ struct PIC_BUFFER_CONFIG_s *pic_config)
+{
+ struct vframe_s *vf = NULL;
+ int stream_offset = pic_config->stream_offset;
+ struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx;
+ ulong nv_order = VIDTYPE_VIU_NV21;
+ u32 pts_valid = 0, pts_us64_valid = 0;
+ u32 frame_size = 0;
+ int i, reclac_flag = 0;
+
+ av1_print(hw, AOM_DEBUG_VFRAME, "%s index = %d\r\n", __func__, pic_config->index);
+ if (kfifo_get(&hw->newframe_q, &vf) == 0) {
+ av1_print(hw, 0, "fatal error, no available buffer slot.");
+ return -1;
+ }
+ /* swap uv */
+ if (hw->is_used_v4l) {
+ if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12) ||
+ (v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12M))
+ nv_order = VIDTYPE_VIU_NV12;
+ }
+
+ if (pic_config->double_write_mode &&
+ (pic_config->double_write_mode & 0x20) == 0)
+ set_canvas(hw, pic_config);
+
+ display_frame_count[hw->index]++;
+ if (vf) {
+ if (!force_pts_unstable && (hw->av1_first_pts_ready)) {
+ if (hw->is_used_v4l) {
+ if ((pic_config->timestamp == 0) || (pic_config->timestamp <= hw->last_timestamp)) {
+ for (i = (FRAME_BUFFERS - 1); i > 0; i--) {
+ if (hw->last_timestamp == hw->frame_mode_timestamp_save[i]) {
+ pic_config->timestamp = hw->frame_mode_timestamp_save[i - 1];
+ break;
+ }
+ }
+
+ if ((i == 0) || (pic_config->timestamp <= hw->last_timestamp)) {
+ av1_print(hw, AV1_DEBUG_OUT_PTS,
+ "no found timestamp %d, set 0. %lld, %lld\n",
+ i, pic_config->timestamp, hw->last_timestamp);
+ pic_config->timestamp = 0;
+ }
+ }
+ } else {
+ if ((pic_config->pts == 0) || (pic_config->pts <= hw->last_pts)) {
+ for (i = (FRAME_BUFFERS - 1); i > 0; i--) {
+ if ((hw->last_pts == hw->frame_mode_pts_save[i]) ||
+ (hw->last_pts_us64 == hw->frame_mode_pts64_save[i])) {
+ pic_config->pts = hw->frame_mode_pts_save[i - 1];
+ pic_config->pts64 = hw->frame_mode_pts64_save[i - 1];
+ break;
+ }
+ }
+
+ if ((i == 0) || (pic_config->pts <= hw->last_pts)) {
+ av1_print(hw, AV1_DEBUG_OUT_PTS,
+ "no found pts %d, set 0. %d, %d\n",
+ i, pic_config->pts, hw->last_pts);
+ pic_config->pts = 0;
+ pic_config->pts64 = 0;
+ }
+ }
+ }
+ }
+
+ if (hw->is_used_v4l) {
+ vf->v4l_mem_handle
+ = hw->m_BUF[pic_config->BUF_index].v4l_ref_buf_addr;
+ if (hw->mmu_enable) {
+ vf->mm_box.bmmu_box = hw->bmmu_box;
+ vf->mm_box.bmmu_idx = HEADER_BUFFER_IDX(hw->buffer_wrap[pic_config->BUF_index]);
+ vf->mm_box.mmu_box = hw->mmu_box;
+ vf->mm_box.mmu_idx = hw->buffer_wrap[pic_config->BUF_index];
+ }
+ }
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (vdec_frame_based(hw_to_vdec(hw))) {
+ vf->pts = pic_config->pts;
+ vf->pts_us64 = pic_config->pts64;
+ vf->timestamp = pic_config->timestamp;
+ if (vf->pts != 0 || vf->pts_us64 != 0) {
+ pts_valid = 1;
+ pts_us64_valid = 1;
+ } else {
+ pts_valid = 0;
+ pts_us64_valid = 0;
+ }
+ } else
+#endif
+ if (pts_lookup_offset_us64
+ (PTS_TYPE_VIDEO, stream_offset, &vf->pts,
+ &frame_size, 0,
+ &vf->pts_us64) != 0) {
+#ifdef DEBUG_PTS
+ hw->pts_missed++;
+#endif
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+ pts_valid = 0;
+ pts_us64_valid = 0;
+ } else {
+#ifdef DEBUG_PTS
+ hw->pts_hit++;
+#endif
+ pts_valid = 1;
+ pts_us64_valid = 1;
+ }
+
+ if (hw->av1_first_pts_ready) {
+ if (hw->is_used_v4l) {
+ if (hw->frame_dur && (vf->timestamp == 0)) {
+ vf->timestamp = hw->last_timestamp +
+ hw->timestamp_duration;
+ }
+
+ if (!close_to(vf->timestamp, (hw->last_timestamp +
+ hw->timestamp_duration), 100)) {
+ vf->timestamp = hw->last_timestamp +
+ hw->timestamp_duration;
+ }
+ } else {
+ if (hw->frame_dur && ((vf->pts == 0) || (vf->pts_us64 == 0))) {
+ vf->pts = hw->last_pts + DUR2PTS(hw->frame_dur);
+ vf->pts_us64 = hw->last_pts_us64 +
+ (DUR2PTS(hw->frame_dur) * 100 / 9);
+ reclac_flag = 1;
+ }
+
+ if (!close_to(vf->pts, (hw->last_pts + DUR2PTS(hw->frame_dur)), 100)) {
+ vf->pts = hw->last_pts + DUR2PTS(hw->frame_dur);
+ vf->pts_us64 = hw->last_pts_us64 +
+ (DUR2PTS(hw->frame_dur) * 100 / 9);
+ reclac_flag = 2;
+ }
+ }
+
+ /* try find the closed pts in saved pts pool */
+ if (reclac_flag) {
+ for (i = 0; i < FRAME_BUFFERS - 1; i++) {
+ if ((hw->frame_mode_pts_save[i] > vf->pts) &&
+ (hw->frame_mode_pts_save[i + 1] < vf->pts)) {
+ if ((hw->frame_mode_pts_save[i] - vf->pts) >
+ (vf->pts - hw->frame_mode_pts_save[i + 1])) {
+ vf->pts = hw->frame_mode_pts_save[i + 1];
+ vf->pts_us64 = hw->frame_mode_pts64_save[i + 1];
+ } else {
+ vf->pts = hw->frame_mode_pts_save[i];
+ vf->pts_us64 = hw->frame_mode_pts64_save[i];
+ }
+ break;
+ }
+ }
+ if (i == (FRAME_BUFFERS - 1))
+ hw->dur_recalc_flag = 1;
+ }
+ } else {
+ av1_print(hw, AV1_DEBUG_OUT_PTS,
+ "first pts %d change to save[%d] %d, ts: %llu\n",
+ vf->pts, hw->first_pts_index - 1,
+ hw->frame_mode_pts_save[hw->first_pts_index - 1],
+ hw->frame_mode_timestamp_save[hw->first_pts_index - 1]);
+ vf->pts = hw->frame_mode_pts_save[hw->first_pts_index - 1];
+ vf->pts_us64 = hw->frame_mode_pts64_save[hw->first_pts_index - 1];
+ vf->timestamp = hw->frame_mode_timestamp_save[hw->first_pts_index - 1];
+ }
+ hw->last_pts = vf->pts;
+ hw->last_pts_us64 = vf->pts_us64;
+ hw->last_timestamp = vf->timestamp;
+ hw->av1_first_pts_ready = true;
+ av1_print(hw, AV1_DEBUG_OUT_PTS,
+ "av1 output slice type %d, dur %d, pts %d, pts64 %lld, ts: %llu\n",
+ pic_config->slice_type, hw->frame_dur, vf->pts, vf->pts_us64, vf->timestamp);
+
+ fill_frame_info(hw, pic_config, frame_size, vf->pts);
+
+ vf->index = 0xff00 | pic_config->index;
+ if (pic_config->double_write_mode & 0x10) {
+ /* double write only */
+ vf->compBodyAddr = 0;
+ vf->compHeadAddr = 0;
+#ifdef AOM_AV1_MMU_DW
+ vf->dwBodyAddr = 0;
+ vf->dwHeadAddr = 0;
+#endif
+ } else {
+ if (hw->mmu_enable) {
+ vf->compBodyAddr = 0;
+ vf->compHeadAddr = pic_config->header_adr;
+ vf->fgs_table_adr = pic_config->fgs_table_adr;
+ vf->fgs_valid = hw->fgs_valid;
+#ifdef AOM_AV1_MMU_DW
+ vf->dwBodyAddr = 0;
+ vf->dwHeadAddr = 0;
+ if (pic_config->double_write_mode & 0x20) {
+ u32 mode = pic_config->double_write_mode & 0xf;
+ if (mode == 5 || mode == 3)
+ vf->dwHeadAddr = pic_config->header_dw_adr;
+ else if ((mode == 1 || mode == 2 || mode == 4)
+ && (debug & AOM_DEBUG_DW_DISP_MAIN) == 0) {
+ vf->compHeadAddr = pic_config->header_dw_adr;
+ vf->fgs_valid = 0;
+ av1_print(hw, AOM_DEBUG_VFRAME,
+ "Use dw mmu for display\n");
+ }
+ }
+#endif
+ } else {
+ /*vf->compBodyAddr = pic_config->mc_y_adr;
+ *vf->compHeadAddr = pic_config->mc_y_adr +
+ *pic_config->comp_body_size; */
+ /*head adr*/
+ }
+ vf->canvas0Addr = vf->canvas1Addr = 0;
+ }
+ if (pic_config->double_write_mode &&
+ (pic_config->double_write_mode & 0x20) == 0) {
+ vf->type = VIDTYPE_PROGRESSIVE |
+ VIDTYPE_VIU_FIELD;
+ vf->type |= VIDTYPE_VIU_NV21;
+ if ((pic_config->double_write_mode == 3 ||
+ pic_config->double_write_mode == 5) &&
+ (!IS_8K_SIZE(pic_config->y_crop_width,
+ pic_config->y_crop_height))) {
+ vf->type |= VIDTYPE_COMPRESS;
+ if (hw->mmu_enable)
+ vf->type |= VIDTYPE_SCATTER;
+ }
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (hw->m_ins_flag) {
+ vf->canvas0Addr = vf->canvas1Addr = -1;
+ vf->plane_num = 2;
+ vf->canvas0_config[0] =
+ pic_config->canvas_config[0];
+ vf->canvas0_config[1] =
+ pic_config->canvas_config[1];
+ vf->canvas1_config[0] =
+ pic_config->canvas_config[0];
+ vf->canvas1_config[1] =
+ pic_config->canvas_config[1];
+
+ } else
+#endif
+ vf->canvas0Addr = vf->canvas1Addr =
+ spec2canvas(pic_config);
+ } else {
+ vf->canvas0Addr = vf->canvas1Addr = 0;
+ vf->type = VIDTYPE_COMPRESS | VIDTYPE_VIU_FIELD;
+ if (hw->mmu_enable)
+ vf->type |= VIDTYPE_SCATTER;
+ }
+
+ switch (pic_config->bit_depth) {
+ case AOM_BITS_8:
+ vf->bitdepth = BITDEPTH_Y8 |
+ BITDEPTH_U8 | BITDEPTH_V8;
+ break;
+ case AOM_BITS_10:
+ case AOM_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_config->bit_depth == AOM_BITS_8)
+ vf->bitdepth |= BITDEPTH_SAVING_MODE;
+
+ /* if ((vf->width!=pic_config->width)|
+ * (vf->height!=pic_config->height))
+ */
+ /* pr_info("aaa: %d/%d, %d/%d\n",
+ vf->width,vf->height, pic_config->width,
+ pic_config->height); */
+ vf->width = pic_config->y_crop_width /
+ get_double_write_ratio(hw,
+ pic_config->double_write_mode);
+ vf->height = pic_config->y_crop_height /
+ get_double_write_ratio(hw,
+ pic_config->double_write_mode);
+ if (force_w_h != 0) {
+ vf->width = (force_w_h >> 16) & 0xffff;
+ vf->height = force_w_h & 0xffff;
+ }
+ if ((pic_config->double_write_mode & 0x20) &&
+ ((pic_config->double_write_mode & 0xf) == 2 ||
+ (pic_config->double_write_mode & 0xf) == 4)) {
+ vf->compWidth = pic_config->y_crop_width /
+ get_double_write_ratio(hw,
+ pic_config->double_write_mode);
+ vf->compHeight = pic_config->y_crop_height /
+ get_double_write_ratio(hw,
+ pic_config->double_write_mode);
+ } else {
+ vf->compWidth = pic_config->y_crop_width;
+ vf->compHeight = pic_config->y_crop_height;
+ }
+ set_frame_info(hw, vf);
+ if (force_fps & 0x100) {
+ u32 rate = force_fps & 0xff;
+
+ if (rate)
+ vf->duration = 96000/rate;
+ else
+ vf->duration = 0;
+ }
+ update_vf_memhandle(hw, vf, pic_config);
+
+ av1_inc_vf_ref(hw, pic_config->index);
+ decoder_do_frame_check(hw_to_vdec(hw), vf);
+ vdec_vframe_ready(hw_to_vdec(hw), vf);
+ kfifo_put(&hw->display_q, (const struct vframe_s *)vf);
+ ATRACE_COUNTER(hw->pts_name, vf->pts);
+ ATRACE_COUNTER(hw->new_q_name, kfifo_len(&hw->newframe_q));
+ ATRACE_COUNTER(hw->disp_q_name, kfifo_len(&hw->display_q));
+
+ hw->vf_pre_count++;
+#ifndef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ /*count info*/
+ gvs->frame_dur = hw->frame_dur;
+ vdec_count_info(gvs, 0, stream_offset);
+#endif
+ hw_to_vdec(hw)->vdec_fps_detec(hw_to_vdec(hw)->id);
+ if (without_display_mode == 0) {
+ vf_notify_receiver(hw->provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
+ } else
+ vav1_vf_put(vav1_vf_get(hw), hw);
+ }
+
+ return 0;
+}
+
+void av1_raw_write_image(AV1Decoder *pbi, PIC_BUFFER_CONFIG *sd)
+{
+ sd->stream_offset = pbi->pre_stream_offset;
+ prepare_display_buf((struct AV1HW_s *)(pbi->private_data), sd);
+ pbi->pre_stream_offset = READ_VREG(HEVC_SHIFT_BYTE_COUNT);
+}
+
+static int notify_v4l_eos(struct vdec_s *vdec)
+{
+ struct AV1HW_s *hw = (struct AV1HW_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_fb(hw))) {
+ if (time_after(jiffies, expires) ||
+ v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx))
+ break;
+ }
+
+ if (index == INVALID_IDX) {
+ if (vdec_v4l_get_buffer(hw->v4l2_ctx, &fb) < 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->m_BUF[index].v4l_ref_buf_addr;
+
+ vdec_vframe_ready(vdec, vf);
+ kfifo_put(&hw->display_q, (const struct vframe_s *)vf);
+ vf_notify_receiver(vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
+
+ av1_print(hw, PRINT_FLAG_V4L_DETAIL,
+ "[%d] AV1 EOS notify.\n", (hw->is_used_v4l)?ctx->id:vdec->id);
+ }
+
+ return 0;
+}
+
+static void get_rpm_param(union param_u *params)
+{
+ int i;
+ unsigned int data32;
+
+ if (debug & AV1_DEBUG_BUFMGR)
+ pr_info("enter %s\r\n", __func__);
+ for (i = 0; i < 128; 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 & AV1_DEBUG_BUFMGR)
+ pr_info("leave %s\r\n", __func__);
+}
+
+#ifdef CHANGE_REMOVED
+static int recycle_mmu_buf_tail(struct AV1HW_s *hw,
+ bool check_dma)
+{
+ struct AV1_Common_s *const cm = &hw->common;
+
+ hw->used_4k_num =
+ READ_VREG(HEVC_SAO_MMU_STATUS) >> 16;
+
+ av1_print(hw, 0, "pic index %d page_start %d\n",
+ cm->cur_fb_idx_mmu, hw->used_4k_num);
+
+ if (check_dma)
+ hevc_mmu_dma_check(hw_to_vdec(hw));
+
+ decoder_mmu_box_free_idx_tail(
+ hw->mmu_box,
+ hw->buffer_wrap[cm->cur_fb_idx_mmu],
+ hw->used_4k_num);
+
+ cm->cur_fb_idx_mmu = INVALID_IDX;
+ hw->used_4k_num = -1;
+
+ return 0;
+}
+#endif
+
+#ifdef CHANGE_REMOVED
+static void av1_recycle_mmu_buf_tail(struct AV1HW_s *hw)
+{
+ struct AV1_Common_s *const cm = &hw->common;
+ if (hw->double_write_mode & 0x10)
+ return;
+
+ if (cm->cur_fb_idx_mmu != INVALID_IDX) {
+ recycle_mmu_buf_tail(hw,
+ ((hw->used_4k_num == -1) &&
+ hw->m_ins_flag) ? 1 : 0);
+ }
+}
+#endif
+
+static void av1_recycle_mmu_buf(struct AV1HW_s *hw)
+{
+ struct AV1_Common_s *const cm = &hw->common;
+
+ if (hw->is_used_v4l)
+ return;
+
+ if (hw->double_write_mode & 0x10)
+ return;
+ if (cm->cur_fb_idx_mmu != INVALID_IDX) {
+ decoder_mmu_box_free_idx(hw->mmu_box,
+ hw->buffer_wrap[cm->cur_fb_idx_mmu]);
+
+ cm->cur_fb_idx_mmu = INVALID_IDX;
+ hw->used_4k_num = -1;
+ }
+}
+
+static void dec_again_process(struct AV1HW_s *hw)
+{
+ amhevc_stop();
+ hw->dec_result = DEC_RESULT_AGAIN;
+ if (hw->process_state ==
+ PROC_STATE_DECODESLICE) {
+ hw->process_state =
+ PROC_STATE_SENDAGAIN;
+ if (hw->mmu_enable)
+ av1_recycle_mmu_buf(hw);
+ }
+ reset_process_time(hw);
+ vdec_schedule_work(&hw->work);
+}
+
+static void read_film_grain_reg(struct AV1HW_s *hw)
+{
+ AV1_COMMON *cm = &hw->common;
+ int i;
+ if (cm->cur_frame == NULL) {
+ av1_print(hw, AOM_DEBUG_HW_MORE, "%s, cur_frame not exist!!!\n", __func__);
+ return;
+ } else
+ av1_print(hw, AOM_DEBUG_HW_MORE, "%s\n", __func__);
+ WRITE_VREG(HEVC_FGS_IDX, 0);
+ for (i = 0; i < FILM_GRAIN_REG_SIZE; i++) {
+ cm->cur_frame->film_grain_reg[i] = READ_VREG(HEVC_FGS_DATA);
+ }
+ cm->cur_frame->film_grain_reg_valid = 1;
+}
+
+static void config_film_grain_reg(struct AV1HW_s *hw, int film_grain_params_ref_idx)
+{
+
+ AV1_COMMON *cm = &hw->common;
+ int i;
+ unsigned char found = 0;
+ RefCntBuffer *buf;
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ " ## %s frome reference idx %d\n",
+ __func__, film_grain_params_ref_idx);
+ for (i = 0; i < INTER_REFS_PER_FRAME; ++i) {
+ if (film_grain_params_ref_idx == cm->remapped_ref_idx[i]) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "%s Error, Invalid film grain reference idx %d\n",
+ __func__, film_grain_params_ref_idx);
+ return;
+ }
+ buf = cm->ref_frame_map[film_grain_params_ref_idx];
+
+ if (buf->film_grain_reg_valid == 0) {
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "%s Error, film grain register data invalid for reference idx %d\n",
+ __func__, film_grain_params_ref_idx);
+ return;
+ }
+
+ if (cm->cur_frame == NULL) {
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "%s, cur_frame not exist!!!\n", __func__);
+ }
+ WRITE_VREG(HEVC_FGS_IDX, 0);
+ for (i = 0; i < FILM_GRAIN_REG_SIZE; i++) {
+ WRITE_VREG(HEVC_FGS_DATA, buf->film_grain_reg[i]);
+ if (cm->cur_frame)
+ cm->cur_frame->film_grain_reg[i] = buf->film_grain_reg[i];
+ }
+ if (cm->cur_frame)
+ cm->cur_frame->film_grain_reg_valid = 1;
+ WRITE_VREG(HEVC_FGS_CTRL, READ_VREG(HEVC_FGS_CTRL) | 1); // set fil_grain_start
+}
+
+void config_next_ref_info_hw(struct AV1HW_s *hw)
+{
+ int j;
+ AV1_COMMON *const cm = &hw->common;
+
+ av1_set_next_ref_frame_map(hw->pbi);
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2)
+ WRITE_VREG(HEVC_PARSER_MEM_WR_ADDR, 0x11a0);
+ else
+ WRITE_VREG(HEVC_PARSER_MEM_WR_ADDR, 0x1000);
+
+ for (j = 0; j < 12; j++) {
+ unsigned int info =
+ av1_get_next_used_ref_info(cm, j);
+
+ WRITE_VREG(HEVC_PARSER_MEM_RW_DATA, info);
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "config next ref info %d 0x%x\n", j, info);
+ }
+}
+
+
+
+#ifdef PRINT_HEVC_DATA_PATH_MONITOR
+void datapath_monitor(struct AV1HW_s *hw)
+{
+ uint32_t total_clk_count;
+ uint32_t path_transfer_count;
+ uint32_t path_wait_count;
+ float path_wait_ratio;
+ if (pbi->decode_idx > 1) {
+ WRITE_VREG(HEVC_PATH_MONITOR_CTRL, 0); // Disabble monitor and set rd_idx to 0
+ total_clk_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+
+ WRITE_VREG(HEVC_PATH_MONITOR_CTRL, (1<<4)); // Disabble monitor and set rd_idx to 0
+
+// parser --> iqit
+ path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ if (path_transfer_count == 0) path_wait_ratio = 0.0;
+ else path_wait_ratio = (float)path_wait_count/(float)path_transfer_count;
+ printk("[P%d HEVC PATH] Parser/IQIT/IPP/DBLK/OW/DDR/CMD WAITING \% : %.2f",
+ pbi->decode_idx - 2, path_wait_ratio);
+
+// iqit --> ipp
+ path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ if (path_transfer_count == 0) path_wait_ratio = 0.0;
+ else path_wait_ratio = (float)path_wait_count/(float)path_transfer_count;
+ printk(" %.2f", path_wait_ratio);
+
+// dblk <-- ipp
+ path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ if (path_transfer_count == 0) path_wait_ratio = 0.0;
+ else path_wait_ratio = (float)path_wait_count/(float)path_transfer_count;
+ printk(" %.2f", path_wait_ratio);
+
+// dblk --> ow
+ path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ if (path_transfer_count == 0) path_wait_ratio = 0.0;
+ else path_wait_ratio = (float)path_wait_count/(float)path_transfer_count;
+ printk(" %.2f", path_wait_ratio);
+
+// <--> DDR
+ path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ if (path_transfer_count == 0) path_wait_ratio = 0.0;
+ else path_wait_ratio = (float)path_wait_count/(float)path_transfer_count;
+ printk(" %.2f", path_wait_ratio);
+
+// CMD
+ path_transfer_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ path_wait_count = READ_VREG(HEVC_PATH_MONITOR_DATA);
+ if (path_transfer_count == 0) path_wait_ratio = 0.0;
+ else path_wait_ratio = (float)path_wait_count/(float)path_transfer_count;
+ printk(" %.2f\n", path_wait_ratio);
+ }
+}
+
+#endif
+
+#ifdef MCRCC_ENABLE
+
+static int mcrcc_hit_rate;
+static int mcrcc_bypass_rate;
+
+#define C_Reg_Wr WRITE_VREG
+static void C_Reg_Rd(unsigned int adr, unsigned int *val)
+{
+ *val = READ_VREG(adr);
+}
+
+static void mcrcc_perfcount_reset(struct AV1HW_s *hw)
+{
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE,
+ "[cache_util.c] Entered mcrcc_perfcount_reset...\n");
+ C_Reg_Wr(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)0x1);
+ C_Reg_Wr(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)0x0);
+ return;
+}
+
+static unsigned raw_mcr_cnt_total_prev;
+static unsigned hit_mcr_0_cnt_total_prev;
+static unsigned hit_mcr_1_cnt_total_prev;
+static unsigned byp_mcr_cnt_nchcanv_total_prev;
+static unsigned byp_mcr_cnt_nchoutwin_total_prev;
+
+static void mcrcc_get_hitrate(struct AV1HW_s *hw, unsigned reset_pre)
+{
+ unsigned delta_hit_mcr_0_cnt;
+ unsigned delta_hit_mcr_1_cnt;
+ unsigned delta_raw_mcr_cnt;
+ unsigned delta_mcr_cnt_nchcanv;
+ unsigned delta_mcr_cnt_nchoutwin;
+
+ unsigned tmp;
+ unsigned raw_mcr_cnt;
+ unsigned hit_mcr_cnt;
+ unsigned byp_mcr_cnt_nchoutwin;
+ unsigned byp_mcr_cnt_nchcanv;
+ int hitrate;
+
+ if (reset_pre) {
+ raw_mcr_cnt_total_prev = 0;
+ hit_mcr_0_cnt_total_prev = 0;
+ hit_mcr_1_cnt_total_prev = 0;
+ byp_mcr_cnt_nchcanv_total_prev = 0;
+ byp_mcr_cnt_nchoutwin_total_prev = 0;
+ }
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "[cache_util.c] Entered mcrcc_get_hitrate...\n");
+ C_Reg_Wr(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x0<<1));
+ C_Reg_Rd(HEVCD_MCRCC_PERFMON_DATA, &raw_mcr_cnt);
+ C_Reg_Wr(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x1<<1));
+ C_Reg_Rd(HEVCD_MCRCC_PERFMON_DATA, &hit_mcr_cnt);
+ C_Reg_Wr(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x2<<1));
+ C_Reg_Rd(HEVCD_MCRCC_PERFMON_DATA, &byp_mcr_cnt_nchoutwin);
+ C_Reg_Wr(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x3<<1));
+ C_Reg_Rd(HEVCD_MCRCC_PERFMON_DATA, &byp_mcr_cnt_nchcanv);
+
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "raw_mcr_cnt_total: %d\n",raw_mcr_cnt);
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "hit_mcr_cnt_total: %d\n",hit_mcr_cnt);
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "byp_mcr_cnt_nchoutwin_total: %d\n",byp_mcr_cnt_nchoutwin);
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "byp_mcr_cnt_nchcanv_total: %d\n",byp_mcr_cnt_nchcanv);
+
+ delta_raw_mcr_cnt = raw_mcr_cnt - raw_mcr_cnt_total_prev;
+ delta_mcr_cnt_nchcanv = byp_mcr_cnt_nchcanv - byp_mcr_cnt_nchcanv_total_prev;
+ delta_mcr_cnt_nchoutwin = byp_mcr_cnt_nchoutwin - byp_mcr_cnt_nchoutwin_total_prev;
+ raw_mcr_cnt_total_prev = raw_mcr_cnt;
+ byp_mcr_cnt_nchcanv_total_prev = byp_mcr_cnt_nchcanv;
+ byp_mcr_cnt_nchoutwin_total_prev = byp_mcr_cnt_nchoutwin;
+
+ C_Reg_Wr(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x4<<1));
+ C_Reg_Rd(HEVCD_MCRCC_PERFMON_DATA, &tmp);
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "miss_mcr_0_cnt_total: %d\n",tmp);
+ C_Reg_Wr(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x5<<1));
+ C_Reg_Rd(HEVCD_MCRCC_PERFMON_DATA, &tmp);
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "miss_mcr_1_cnt_total: %d\n",tmp);
+ C_Reg_Wr(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x6<<1));
+ C_Reg_Rd(HEVCD_MCRCC_PERFMON_DATA, &tmp);
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "hit_mcr_0_cnt_total: %d\n",tmp);
+ delta_hit_mcr_0_cnt = tmp - hit_mcr_0_cnt_total_prev;
+ hit_mcr_0_cnt_total_prev = tmp;
+ C_Reg_Wr(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x7<<1));
+ C_Reg_Rd(HEVCD_MCRCC_PERFMON_DATA, &tmp);
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "hit_mcr_1_cnt_total: %d\n",tmp);
+ delta_hit_mcr_1_cnt = tmp - hit_mcr_1_cnt_total_prev;
+ hit_mcr_1_cnt_total_prev = tmp;
+
+ if ( delta_raw_mcr_cnt != 0 ) {
+ hitrate = 100 * delta_hit_mcr_0_cnt/ delta_raw_mcr_cnt;
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "CANV0_HIT_RATE : %d\n", hitrate);
+ hitrate = 100 * delta_hit_mcr_1_cnt/delta_raw_mcr_cnt;
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "CANV1_HIT_RATE : %d\n", hitrate);
+ hitrate = 100 * delta_mcr_cnt_nchcanv/delta_raw_mcr_cnt;
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "NONCACH_CANV_BYP_RATE : %d\n", hitrate);
+ hitrate = 100 * delta_mcr_cnt_nchoutwin/delta_raw_mcr_cnt;
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "CACHE_OUTWIN_BYP_RATE : %d\n", hitrate);
+ }
+
+ if (raw_mcr_cnt != 0)
+ {
+ hitrate = 100*hit_mcr_cnt/raw_mcr_cnt;
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "MCRCC_HIT_RATE : %d\n", hitrate);
+ hitrate = 100*(byp_mcr_cnt_nchoutwin + byp_mcr_cnt_nchcanv)/raw_mcr_cnt;
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "MCRCC_BYP_RATE : %d\n", hitrate);
+ mcrcc_hit_rate = 100*hit_mcr_cnt/raw_mcr_cnt;
+ mcrcc_bypass_rate = 100*(byp_mcr_cnt_nchoutwin + byp_mcr_cnt_nchcanv)/raw_mcr_cnt;
+ } else {
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "MCRCC_HIT_RATE : na\n");
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "MCRCC_BYP_RATE : na\n");
+ }
+
+ return;
+}
+
+static void decomp_perfcount_reset(struct AV1HW_s *hw)
+{
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "[cache_util.c] Entered decomp_perfcount_reset...\n");
+ C_Reg_Wr(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)0x1);
+ C_Reg_Wr(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)0x0);
+ return;
+}
+
+static void decomp_get_hitrate(struct AV1HW_s *hw)
+{
+ unsigned raw_mcr_cnt;
+ unsigned hit_mcr_cnt;
+ int hitrate;
+
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "[cache_util.c] Entered decomp_get_hitrate...\n");
+ C_Reg_Wr(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x0<<1));
+ C_Reg_Rd(HEVCD_MPP_DECOMP_PERFMON_DATA, &raw_mcr_cnt);
+ C_Reg_Wr(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x1<<1));
+ C_Reg_Rd(HEVCD_MPP_DECOMP_PERFMON_DATA, &hit_mcr_cnt);
+
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "hcache_raw_cnt_total: %d\n",raw_mcr_cnt);
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "hcache_hit_cnt_total: %d\n",hit_mcr_cnt);
+
+ if ( raw_mcr_cnt != 0 ) {
+ hitrate = 100*hit_mcr_cnt/raw_mcr_cnt;
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "DECOMP_HCACHE_HIT_RATE : %d\n", hitrate);
+ } else {
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "DECOMP_HCACHE_HIT_RATE : na\n");
+ }
+ C_Reg_Wr(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x2<<1));
+ C_Reg_Rd(HEVCD_MPP_DECOMP_PERFMON_DATA, &raw_mcr_cnt);
+ C_Reg_Wr(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x3<<1));
+ C_Reg_Rd(HEVCD_MPP_DECOMP_PERFMON_DATA, &hit_mcr_cnt);
+
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "dcache_raw_cnt_total: %d\n",raw_mcr_cnt);
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "dcache_hit_cnt_total: %d\n",hit_mcr_cnt);
+
+ if ( raw_mcr_cnt != 0 ) {
+ hitrate = 100*hit_mcr_cnt/raw_mcr_cnt;
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "DECOMP_DCACHE_HIT_RATE : %d\n", hitrate);
+
+ //hitrate = ((float)hit_mcr_cnt/(float)raw_mcr_cnt);
+ //hitrate = (mcrcc_hit_rate + (mcrcc_bypass_rate * hitrate))*100;
+ hitrate = mcrcc_hit_rate + (mcrcc_bypass_rate * hit_mcr_cnt/raw_mcr_cnt);
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "MCRCC_DECOMP_DCACHE_EFFECTIVE_HIT_RATE : %d\n", hitrate);
+
+ } else {
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "DECOMP_DCACHE_HIT_RATE : na\n");
+ }
+
+ return;
+}
+
+static void decomp_get_comprate(struct AV1HW_s *hw)
+{
+ unsigned raw_ucomp_cnt;
+ unsigned fast_comp_cnt;
+ unsigned slow_comp_cnt;
+ int comprate;
+
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "[cache_util.c] Entered decomp_get_comprate...\n");
+ C_Reg_Wr(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x4<<1));
+ C_Reg_Rd(HEVCD_MPP_DECOMP_PERFMON_DATA, &fast_comp_cnt);
+ C_Reg_Wr(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x5<<1));
+ C_Reg_Rd(HEVCD_MPP_DECOMP_PERFMON_DATA, &slow_comp_cnt);
+ C_Reg_Wr(HEVCD_MPP_DECOMP_PERFMON_CTL, (unsigned int)(0x6<<1));
+ C_Reg_Rd(HEVCD_MPP_DECOMP_PERFMON_DATA, &raw_ucomp_cnt);
+
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "decomp_fast_comp_total: %d\n",fast_comp_cnt);
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "decomp_slow_comp_total: %d\n",slow_comp_cnt);
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "decomp_raw_uncomp_total: %d\n",raw_ucomp_cnt);
+
+ if ( raw_ucomp_cnt != 0 )
+ {
+ comprate = 100*(fast_comp_cnt + slow_comp_cnt)/raw_ucomp_cnt;
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "DECOMP_COMP_RATIO : %d\n", comprate);
+ } else
+ {
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "DECOMP_COMP_RATIO : na\n");
+ }
+ return;
+}
+
+static void dump_hit_rate(struct AV1HW_s *hw)
+{
+ if (debug & AV1_DEBUG_CACHE_HIT_RATE) {
+ mcrcc_get_hitrate(hw, hw->m_ins_flag);
+ decomp_get_hitrate(hw);
+ decomp_get_comprate(hw);
+ }
+}
+
+static uint32_t mcrcc_get_abs_frame_distance(struct AV1HW_s *hw, uint32_t refid, uint32_t ref_ohint, uint32_t curr_ohint, uint32_t ohint_bits_min1)
+{
+ int32_t diff_ohint0;
+ int32_t diff_ohint1;
+ uint32_t abs_dist;
+ uint32_t m;
+ uint32_t m_min1;
+
+ diff_ohint0 = ref_ohint - curr_ohint;
+
+ m = (1 << ohint_bits_min1);
+ m_min1 = m -1;
+
+ diff_ohint1 = (diff_ohint0 & m_min1 ) - (diff_ohint0 & m);
+
+ abs_dist = (diff_ohint1 < 0) ? -diff_ohint1 : diff_ohint1;
+
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE,
+ "[cache_util.c] refid:%0x ref_orderhint:%0x curr_orderhint:%0x orderhint_bits_min1:%0x abd_dist:%0x\n",
+ refid, ref_ohint, curr_ohint, ohint_bits_min1,abs_dist);
+
+ return abs_dist;
+}
+
+static void config_mcrcc_axi_hw_nearest_ref(struct AV1HW_s *hw)
+{
+ uint32_t i;
+ uint32_t rdata32;
+ uint32_t dist_array[8];
+ uint32_t refcanvas_array[2];
+ uint32_t orderhint_bits;
+ unsigned char is_inter;
+ AV1_COMMON *cm = &hw->common;
+ PIC_BUFFER_CONFIG *curr_pic_config;
+ int32_t curr_orderhint;
+ int cindex0 = LAST_FRAME;
+ uint32_t last_ref_orderhint_dist = 1023; // large distance
+ uint32_t curr_ref_orderhint_dist = 1023; // large distance
+ int cindex1;
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE,
+ "[test.c] #### config_mcrcc_axi_hw ####\n");
+
+ WRITE_VREG(HEVCD_MCRCC_CTL1, 0x2); // reset mcrcc
+
+ is_inter = av1_frame_is_inter(&hw->common); //((pbi->common.frame_type != KEY_FRAME) && (!pbi->common.intra_only)) ? 1 : 0;
+ if ( !is_inter ) { // I-PIC
+ //WRITE_VREG(HEVCD_MCRCC_CTL1, 0x1); // remove reset -- disables clock
+ WRITE_VREG(HEVCD_MCRCC_CTL2, 0xffffffff); // Replace with current-frame canvas
+ WRITE_VREG(HEVCD_MCRCC_CTL3, 0xffffffff); //
+ WRITE_VREG(HEVCD_MCRCC_CTL1, 0xff0); // enable mcrcc progressive-mode
+ return;
+ }
+
+#if 0
+ //printk("before call mcrcc_get_hitrate\r\n");
+ mcrcc_get_hitrate(hw);
+ decomp_get_hitrate(hw);
+ decomp_get_comprate(hw);
+#endif
+
+ // Find absolute orderhint delta
+ curr_pic_config = &cm->cur_frame->buf;
+ curr_orderhint = curr_pic_config->order_hint;
+ orderhint_bits = cm->seq_params.order_hint_info.order_hint_bits_minus_1;
+ for (i = LAST_FRAME; i <= ALTREF_FRAME; i++) {
+ int32_t ref_orderhint = 0;
+ PIC_BUFFER_CONFIG *pic_config;
+ //int32_t tmp;
+ pic_config = av1_get_ref_frame_spec_buf(cm,i);
+ if (pic_config)
+ ref_orderhint = pic_config->order_hint;
+ //tmp = curr_orderhint - ref_orderhint;
+ //dist_array[i] = (tmp < 0) ? -tmp : tmp;
+ dist_array[i] = mcrcc_get_abs_frame_distance(hw, i,ref_orderhint, curr_orderhint, orderhint_bits);
+ }
+ // Get smallest orderhint distance refid
+ for (i = LAST_FRAME; i <= ALTREF_FRAME; i++) {
+ PIC_BUFFER_CONFIG *pic_config;
+ pic_config = av1_get_ref_frame_spec_buf(cm, i);
+ curr_ref_orderhint_dist = dist_array[i];
+ if ( curr_ref_orderhint_dist < last_ref_orderhint_dist) {
+ cindex0 = i;
+ last_ref_orderhint_dist = curr_ref_orderhint_dist;
+ }
+ }
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, (cindex0 << 8) | (1<<1) | 0);
+ refcanvas_array[0] = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR) & 0xffff;
+
+ last_ref_orderhint_dist = 1023; // large distance
+ curr_ref_orderhint_dist = 1023; // large distance
+ // Get 2nd smallest orderhint distance refid
+ cindex1 = LAST_FRAME;
+ for (i = LAST_FRAME; i <= ALTREF_FRAME; i++) {
+ PIC_BUFFER_CONFIG *pic_config;
+ pic_config = av1_get_ref_frame_spec_buf(cm, i);
+ curr_ref_orderhint_dist = dist_array[i];
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, (i << 8) | (1<<1) | 0);
+ refcanvas_array[1] = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR) & 0xffff;
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "[cache_util.c] curr_ref_orderhint_dist:%x last_ref_orderhint_dist:%x refcanvas_array[0]:%x refcanvas_array[1]:%x\n",
+ curr_ref_orderhint_dist, last_ref_orderhint_dist, refcanvas_array[0],refcanvas_array[1]);
+ if ((curr_ref_orderhint_dist < last_ref_orderhint_dist) && (refcanvas_array[0] != refcanvas_array[1])) {
+ cindex1 = i;
+ last_ref_orderhint_dist = curr_ref_orderhint_dist;
+ }
+ }
+
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, (cindex0 << 8) | (1<<1) | 0);
+ refcanvas_array[0] = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, (cindex1 << 8) | (1<<1) | 0);
+ refcanvas_array[1] = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
+
+ av1_print(hw, AV1_DEBUG_CACHE_HIT_RATE, "[cache_util.c] refcanvas_array[0](index %d):%x refcanvas_array[1](index %d):%x\n",
+ cindex0, refcanvas_array[0], cindex1, refcanvas_array[1]);
+
+ // lowest delta_picnum
+ rdata32 = refcanvas_array[0];
+ rdata32 = rdata32 & 0xffff;
+ rdata32 = rdata32 | ( rdata32 << 16);
+ WRITE_VREG(HEVCD_MCRCC_CTL2, rdata32);
+
+ // 2nd-lowest delta_picnum
+ rdata32 = refcanvas_array[1];
+ rdata32 = rdata32 & 0xffff;
+ rdata32 = rdata32 | ( rdata32 << 16);
+ WRITE_VREG(HEVCD_MCRCC_CTL3, rdata32);
+
+ WRITE_VREG(HEVCD_MCRCC_CTL1, 0xff0); // enable mcrcc progressive-mode
+ return;
+}
+
+
+#endif
+
+int av1_continue_decoding(struct AV1HW_s *hw, int obu_type)
+{
+ int ret;
+#if 1
+ //def CHANGE_DONE
+ AV1Decoder *pbi = hw->pbi;
+ AV1_COMMON *const cm = pbi->common;
+ struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx);
+ int i;
+
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "%s: pbi %p cm %p cur_frame %p %d has_seq %d has_keyframe %d\n",
+ __func__, pbi, cm, cm->cur_frame,
+ pbi->bufmgr_proc_count,
+ hw->has_sequence,
+ hw->has_keyframe);
+
+ if (hw->has_sequence == 0) {
+ av1_print(hw, 0,
+ "no sequence head, skip\n");
+ if (!hw->m_ins_flag)
+ WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_SEARCH_HEAD);
+ return -2;
+ } else if (hw->has_keyframe == 0 &&
+ hw->aom_param.p.frame_type != KEY_FRAME){
+ av1_print(hw, 0,
+ "no key frame, skip\n");
+ on_no_keyframe_skiped++;
+ if (!hw->m_ins_flag)
+ WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_SEARCH_HEAD);
+ return -2;
+ }
+ hw->has_keyframe = 1;
+ on_no_keyframe_skiped = 0;
+
+ if (hw->is_used_v4l && ctx->param_sets_from_ucode)
+ hw->res_ch_flag = 0;
+
+ //pre_decode_idx = pbi->decode_idx;
+ if (pbi->bufmgr_proc_count == 0 ||
+ hw->one_compressed_data_done) {
+ hw->new_compressed_data = 1;
+ hw->one_compressed_data_done = 0;
+ } else {
+ hw->new_compressed_data = 0;
+ }
+ ret = av1_bufmgr_process(pbi, &hw->aom_param,
+ hw->new_compressed_data, obu_type);
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "%s: pbi %p cm %p cur_frame %p\n",
+ __func__, pbi, cm, cm->cur_frame);
+
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "1+++++++++++++++++++++++++++++++++++%d %p\n",
+ ret, cm->cur_frame);
+ if (hw->new_compressed_data)
+ WRITE_VREG(PIC_END_LCU_COUNT, 0);
+
+ if (ret > 0) {
+ /* the case when cm->show_existing_frame is 1 */
+ /*case 3016*/
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "Decoding done (index=%d, show_existing_frame = %d)\n",
+ cm->cur_frame? cm->cur_frame->buf.index:-1,
+ cm->show_existing_frame
+ );
+
+ if (cm->cur_frame) {
+ PIC_BUFFER_CONFIG* cur_pic_config = &cm->cur_frame->buf;
+ if (debug &
+ AV1_DEBUG_BUFMGR_MORE)
+ dump_aux_buf(hw);
+ set_pic_aux_data(hw,
+ cur_pic_config, 0, 0);
+ }
+ config_next_ref_info_hw(hw);
+
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "aom_bufmgr_process=> %d,decode done, AOM_AV1_SEARCH_HEAD\r\n", ret);
+ WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_SEARCH_HEAD);
+ pbi->decode_idx++;
+ pbi->bufmgr_proc_count++;
+ hw->frame_decoded = 1;
+ return 0;
+ }
+ else if (ret < 0) {
+ hw->frame_decoded = 1;
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "aom_bufmgr_process=> %d, bufmgr e.r.r.o.r., AOM_AV1_SEARCH_HEAD\r\n", ret);
+ WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_SEARCH_HEAD);
+ return 0;
+ }
+ else if (ret == 0) {
+ PIC_BUFFER_CONFIG* cur_pic_config = &cm->cur_frame->buf;
+ PIC_BUFFER_CONFIG* prev_pic_config = &cm->prev_frame->buf;
+ //struct segmentation_lf *seg_4lf = &hw->seg_4lf_store;
+ if (debug &
+ AV1_DEBUG_BUFMGR_MORE)
+ dump_aux_buf(hw);
+ set_dv_data(hw);
+ if (cm->show_frame &&
+ hw->dv_data_buf != NULL)
+ copy_dv_data(hw, cur_pic_config);
+ /* to do:..
+ set_pic_aux_data(hw,
+ cur_pic_config, 0, 2);*/
+ hw->frame_decoded = 0;
+ pbi->bufmgr_proc_count++;
+ if (hw->new_compressed_data == 0) {
+ WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_DECODE_SLICE);
+ return 0;
+ }
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ " [PICTURE %d] cm->cur_frame->mi_size : (%d X %d) y_crop_size :(%d X %d)\n",
+ hw->frame_count,
+ cm->cur_frame->mi_cols,
+ cm->cur_frame->mi_rows,
+ cur_pic_config->y_crop_width,
+ cur_pic_config->y_crop_height);
+ if (cm->prev_frame > 0) {
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ " [SEGMENT] cm->prev_frame->segmentation_enabled : %d\n",
+ cm->prev_frame->segmentation_enabled);
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ " [SEGMENT] cm->prev_frame->mi_size : (%d X %d)\n",
+ cm->prev_frame->mi_cols, cm->prev_frame->mi_rows);
+ }
+ cm->cur_frame->prev_segmentation_enabled = (cm->prev_frame > 0) ?
+ (cm->prev_frame->segmentation_enabled & (cm->prev_frame->segmentation_update_map
+ | cm->prev_frame->prev_segmentation_enabled) &
+ (cm->cur_frame->mi_rows == cm->prev_frame->mi_rows) &
+ (cm->cur_frame->mi_cols == cm->prev_frame->mi_cols)) : 0;
+ WRITE_VREG(AV1_SKIP_MODE_INFO,
+ (cm->cur_frame->prev_segmentation_enabled << 31) |
+ (((cm->prev_frame > 0) ? cm->prev_frame->intra_only : 0) << 30) |
+ (((cm->prev_frame > 0) ? prev_pic_config->index : 0x1f) << 24) |
+ (((cm->cur_frame > 0) ? cur_pic_config->index : 0x1f) << 16) |
+ (cm->current_frame.skip_mode_info.ref_frame_idx_0 & 0xf) |
+ ((cm->current_frame.skip_mode_info.ref_frame_idx_1 & 0xf) << 4) |
+ (cm->current_frame.skip_mode_info.skip_mode_allowed << 8));
+ cur_pic_config->decode_idx = pbi->decode_idx;
+
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "Decode Frame Data %d frame_type %d (%d) bufmgr_proc_count %d\n",
+ pbi->decode_idx,
+ cm->cur_frame->frame_type,
+ cm->current_frame.frame_type,
+ pbi->bufmgr_proc_count);
+ pbi->decode_idx++;
+ hw->frame_count++;
+ cur_pic_config->slice_type = cm->cur_frame->frame_type;
+ if (hw->chunk) {
+ av1_print(hw, AV1_DEBUG_OUT_PTS,
+ "%s, config pic pts %d, pts64 %lld\n",
+ __func__, hw->chunk->pts, hw->chunk->pts64);
+ cur_pic_config->pts = hw->chunk->pts;
+ cur_pic_config->pts64 = hw->chunk->pts64;
+ cur_pic_config->timestamp = hw->chunk->timestamp;
+ hw->chunk->pts = 0;
+ hw->chunk->pts64 = 0;
+ hw->chunk->timestamp = 0;
+ }
+#ifdef DUAL_DECODE
+#else
+ config_pic_size(hw, hw->aom_param.p.bit_depth);
+#endif
+ if (get_mv_buf(hw, &cm->cur_frame->buf) < 0) {
+ av1_print(hw, 0,
+ "%s: Error get_mv_buf fail\n",
+ __func__);
+ ret = -1;
+ }
+
+ if (ret >= 0 && hw->mmu_enable && ((hw->double_write_mode & 0x10) == 0)) {
+ ret = av1_alloc_mmu(hw,
+ cm->cur_frame->buf.index,
+ cur_pic_config->y_crop_width,
+ cur_pic_config->y_crop_height,
+ hw->aom_param.p.bit_depth,
+ hw->frame_mmu_map_addr);
+ if (ret >= 0)
+ cm->cur_fb_idx_mmu = cm->cur_frame->buf.index;
+ else
+ pr_err("can't alloc need mmu1,idx %d ret =%d\n",
+ cm->cur_frame->buf.index, ret);
+#ifdef AOM_AV1_MMU_DW
+ if (hw->dw_mmu_enable) {
+ ret = av1_alloc_mmu_dw(hw,
+ cm->cur_frame->buf.index,
+ cur_pic_config->y_crop_width,
+ cur_pic_config->y_crop_height,
+ hw->aom_param.p.bit_depth,
+ hw->dw_frame_mmu_map_addr);
+ if (ret >= 0)
+ cm->cur_fb_idx_mmu_dw = cm->cur_frame->buf.index;
+ else
+ pr_err("can't alloc need dw mmu1,idx %d ret =%d\n",
+ cm->cur_frame->buf.index, ret);
+ }
+#endif
+#ifdef DEBUG_CRC_ERROR
+ if (crc_debug_flag & 0x40)
+ mv_buffer_fill_zero(hw, &cm->cur_frame->buf);
+#endif
+ } else {
+ ret = 0;
+ }
+ if (av1_frame_is_inter(&hw->common)) {
+ //if ((pbi->common.frame_type != KEY_FRAME) && (!pbi->common.intra_only)) {
+#ifdef DUAL_DECODE
+#else
+ config_mc_buffer(hw, hw->aom_param.p.bit_depth, 1);
+#endif
+ config_mpred_hw(hw, 1);
+ }
+ else {
+ config_mc_buffer(hw, hw->aom_param.p.bit_depth, 0);
+ clear_mpred_hw(hw);
+ config_mpred_hw(hw, 0);
+ }
+#ifdef DUAL_DECODE
+#else
+#ifdef MCRCC_ENABLE
+ config_mcrcc_axi_hw_nearest_ref(hw);
+#endif
+ config_sao_hw(hw, &hw->aom_param);
+#endif
+
+ config_dblk_hw(hw);
+
+ av1_print(hw, AOM_DEBUG_HW_MORE, "HEVC_DEC_STATUS_REG <= AOM_AV1_DECODE_SLICE\n");
+ WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_DECODE_SLICE);
+
+ // Save segment_feature while hardware decoding
+ if (hw->seg_4lf->enabled) {
+ for (i = 0; i < 8; i++) {
+ cm->cur_frame->segment_feature[i] = READ_VREG(AOM_AV1_SEGMENT_FEATURE);
+ }
+ } else {
+ for (i = 0; i < 8; i++) {
+ cm->cur_frame->segment_feature[i] = (0x80000000 | (i << 22));
+ }
+ }
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2)
+ WRITE_VREG(HEVC_PARSER_MEM_WR_ADDR, 0x11b0 + (cur_pic_config->index));
+ else
+ WRITE_VREG(HEVC_PARSER_MEM_WR_ADDR, 0x1010 + (cur_pic_config->index));
+ if (hw->aom_param.p.segmentation_enabled & 1) // segmentation_enabled
+ WRITE_VREG(HEVC_PARSER_MEM_RW_DATA, READ_VREG(AV1_REF_SEG_INFO));
+ else
+ WRITE_VREG(HEVC_PARSER_MEM_RW_DATA, 0);
+ }
+ return ret;
+
+#else
+
+ bit_depth_luma = av1_param.p.bit_depth;
+ bit_depth_chroma = av1_param.p.bit_depth;
+
+ if (hw->process_state != PROC_STATE_SENDAGAIN) {
+ ret = av1_bufmgr_process(hw, &av1_param);
+ if (!hw->m_ins_flag)
+ hw->result_done_count++;
+ } else {
+ union param_u *params = &av1_param;
+ if (hw->mmu_enable && ((hw->double_write_mode & 0x10) == 0)) {
+ ret = av1_alloc_mmu(hw,
+ cm->new_fb_idx,
+ params->p.width,
+ params->p.height,
+ params->p.bit_depth,
+ hw->frame_mmu_map_addr);
+ if (ret >= 0)
+ cm->cur_fb_idx_mmu = cm->new_fb_idx;
+ else
+ pr_err("can't alloc need mmu1,idx %d ret =%d\n",
+ cm->new_fb_idx, ret);
+ } else {
+ ret = 0;
+ }
+ WRITE_VREG(HEVC_PARSER_PICTURE_SIZE,
+ (params->p.height << 16) | params->p.width);
+ }
+ if (ret < 0) {
+ pr_info("av1_bufmgr_process=> %d, AV1_10B_DISCARD_NAL\r\n", ret);
+ WRITE_VREG(HEVC_DEC_STATUS_REG, AV1_10B_DISCARD_NAL);
+ cm->show_frame = 0;
+ if (hw->mmu_enable)
+ av1_recycle_mmu_buf(hw);
+
+ if (hw->m_ins_flag) {
+ hw->dec_result = DEC_RESULT_DONE;
+ amhevc_stop();
+ vdec_schedule_work(&hw->work);
+ }
+ return ret;
+ } else if (ret == 0) {
+ struct PIC_BUFFER_CONFIG_s *cur_pic_config
+ = &cm->cur_frame->buf;
+ cur_pic_config->decode_idx = hw->frame_count;
+
+ if (hw->process_state != PROC_STATE_SENDAGAIN) {
+ if (!hw->m_ins_flag) {
+ hw->frame_count++;
+ decode_frame_count[hw->index]
+ = hw->frame_count;
+ }
+ if (hw->chunk) {
+ cur_pic_config->pts = hw->chunk->pts;
+ cur_pic_config->pts64 = hw->chunk->pts64;
+ }
+ }
+ /*pr_info("Decode Frame Data %d\n", hw->frame_count);*/
+ config_pic_size(hw, av1_param.p.bit_depth);
+
+ if ((hw->common.frame_type != KEY_FRAME)
+ && (!hw->common.intra_only)) {
+ config_mc_buffer(hw, av1_param.p.bit_depth);
+ config_mpred_hw(hw);
+ } else {
+ clear_mpred_hw(hw);
+ }
+#ifdef MCRCC_ENABLE
+ if (mcrcc_cache_alg_flag)
+ config_mcrcc_axi_hw_new(hw);
+ else
+ config_mcrcc_axi_hw(hw);
+#endif
+ config_sao_hw(hw, &av1_param);
+ /*pr_info("HEVC_DEC_STATUS_REG <= AV1_10B_DECODE_SLICE\n");*/
+ WRITE_VREG(HEVC_DEC_STATUS_REG, AV1_10B_DECODE_SLICE);
+ } else {
+ pr_info("Skip search next start code\n");
+ cm->prev_fb_idx = INVALID_IDX;
+ /*skip, search next start code*/
+ WRITE_VREG(HEVC_DEC_STATUS_REG, AV1_10B_DECODE_SLICE);
+ }
+ hw->process_state = PROC_STATE_DECODESLICE;
+ if (hw->mmu_enable && ((hw->double_write_mode & 0x10) == 0)) {
+ if (hw->last_put_idx < hw->used_buf_num) {
+ struct RefCntBuffer_s *frame_bufs =
+ cm->buffer_pool->frame_bufs;
+ int i = hw->last_put_idx;
+ /*free not used buffers.*/
+ if ((frame_bufs[i].ref_count == 0) &&
+ (frame_bufs[i].buf.vf_ref == 0) &&
+ (frame_bufs[i].buf.index != -1)) {
+ if (pbi->is_used_v4l) {
+ struct internal_comp_buf *ibuf =
+ index_to_icomp_buf(pbi, i);
+
+ decoder_mmu_box_free_idx(ibuf->mmu_box, i);
+ } else {
+ decoder_mmu_box_free_idx(pbi->mmu_box, i);
+ }
+ }
+ hw->last_put_idx = -1;
+ }
+ }
+ return ret;
+#endif
+}
+
+static void fill_frame_info(struct AV1HW_s *hw,
+ struct PIC_BUFFER_CONFIG_s *frame,
+ unsigned int framesize,
+ unsigned int pts)
+{
+ struct vframe_qos_s *vframe_qos = &hw->vframe_qos;
+
+ if (frame->slice_type == KEY_FRAME)
+ vframe_qos->type = 1;
+ else if (frame->slice_type == INTER_FRAME)
+ vframe_qos->type = 2;
+/*
+#define SHOW_QOS_INFO
+*/
+ vframe_qos->size = framesize;
+ vframe_qos->pts = pts;
+#ifdef SHOW_QOS_INFO
+ av1_print(hw, 0, "slice:%d\n", frame->slice_type);
+#endif
+ vframe_qos->max_mv = frame->max_mv;
+ vframe_qos->avg_mv = frame->avg_mv;
+ vframe_qos->min_mv = frame->min_mv;
+#ifdef SHOW_QOS_INFO
+ av1_print(hw, 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 = frame->max_qp;
+ vframe_qos->avg_qp = frame->avg_qp;
+ vframe_qos->min_qp = frame->min_qp;
+#ifdef SHOW_QOS_INFO
+ av1_print(hw, 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 = frame->max_skip;
+ vframe_qos->avg_skip = frame->avg_skip;
+ vframe_qos->min_skip = frame->min_skip;
+#ifdef SHOW_QOS_INFO
+ av1_print(hw, 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++;
+ /*
+ if (hw->frameinfo_enable)
+ vdec_fill_frame_info(vframe_qos, 1);
+ */
+}
+
+/* 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 AV1HW_s *hw)
+{
+ struct PIC_BUFFER_CONFIG_s *frame = &hw->cur_buf->buf;
+
+ if (!frame)
+ return;
+
+ 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 (frame->slice_type == KEY_FRAME)
+ 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;
+ }
+ }
+ }
+ frame->max_mv = a[2];
+ frame->avg_mv = a[1];
+ frame->min_mv = a[0];
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "mv data %lx a[0]= %x a[1]= %x a[2]= %x\n",
+ data, a[0], a[1], a[2]);
+
+ 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;
+ }
+ }
+ }
+ frame->max_qp = a[2];
+ frame->avg_qp = a[1];
+ frame->min_qp = a[0];
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "qp data %lx a[0]= %x a[1]= %x a[2]= %x\n",
+ data, a[0], a[1], a[2]);
+
+ 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;
+ }
+ }
+ }
+ frame->max_skip = a[2];
+ frame->avg_skip = a[1];
+ frame->min_skip = a[0];
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "skip data %lx a[0]= %x a[1]= %x a[2]= %x\n",
+ 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;
+ int pic_number = frame->decode_idx;
+
+ frame->max_mv = 0;
+ frame->avg_mv = 0;
+ frame->min_mv = 0;
+
+ frame->max_skip = 0;
+ frame->avg_skip = 0;
+ frame->min_skip = 0;
+
+ frame->max_qp = 0;
+ frame->avg_qp = 0;
+ frame->min_qp = 0;
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO, "slice_type:%d, poc:%d\n",
+ frame->slice_type,
+ pic_number);
+
+ /* 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) {
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] NO Data yet.\n",
+ pic_number);
+
+ /* reset all counts */
+ WRITE_VREG(HEVC_PIC_QUALITY_CTRL, (1<<8));
+ return;
+ }
+ /* qp_y_sum */
+ rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] Y QP AVG : %d (%d/%d)\n",
+ pic_number, rdata32/blk88_y_count,
+ rdata32, blk88_y_count);
+
+ frame->avg_qp = rdata32/blk88_y_count;
+ /* intra_y_count */
+ rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] Y intra rate : %d%c (%d)\n",
+ pic_number, rdata32*100/blk88_y_count,
+ '%', rdata32);
+
+ /* skipped_y_count */
+ rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] Y skipped rate : %d%c (%d)\n",
+ pic_number, rdata32*100/blk88_y_count,
+ '%', rdata32);
+
+ frame->avg_skip = rdata32*100/blk88_y_count;
+ /* coeff_non_zero_y_count */
+ rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] Y ZERO_Coeff rate : %d%c (%d)\n",
+ pic_number, (100 - rdata32*100/(blk88_y_count*1)),
+ '%', rdata32);
+
+ /* blk66_c_count */
+ blk88_c_count = READ_VREG(HEVC_PIC_QUALITY_DATA);
+ if (blk88_c_count == 0) {
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] NO Data yet.\n",
+ pic_number);
+ /* reset all counts */
+ WRITE_VREG(HEVC_PIC_QUALITY_CTRL, (1<<8));
+ return;
+ }
+ /* qp_c_sum */
+ rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] C QP AVG : %d (%d/%d)\n",
+ pic_number, rdata32/blk88_c_count,
+ rdata32, blk88_c_count);
+
+ /* intra_c_count */
+ rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] C intra rate : %d%c (%d)\n",
+ pic_number, rdata32*100/blk88_c_count,
+ '%', rdata32);
+
+ /* skipped_cu_c_count */
+ rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] C skipped rate : %d%c (%d)\n",
+ pic_number, rdata32*100/blk88_c_count,
+ '%', rdata32);
+
+ /* coeff_non_zero_c_count */
+ rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] C ZERO_Coeff rate : %d%c (%d)\n",
+ pic_number, (100 - rdata32*100/(blk88_c_count*1)),
+ '%', rdata32);
+
+ /* 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);
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] Y QP min : %d\n",
+ pic_number, (rdata32>>0)&0xff);
+
+ frame->min_qp = (rdata32>>0)&0xff;
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] Y QP max : %d\n",
+ pic_number, (rdata32>>8)&0xff);
+
+ frame->max_qp = (rdata32>>8)&0xff;
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] C QP min : %d\n",
+ pic_number, (rdata32>>16)&0xff);
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] C QP max : %d\n",
+ pic_number, (rdata32>>24)&0xff);
+
+ /* blk22_mv_count */
+ blk22_mv_count = READ_VREG(HEVC_PIC_QUALITY_DATA);
+ if (blk22_mv_count == 0) {
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] NO MV Data yet.\n",
+ pic_number);
+ /* 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 */
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] MV AVG High Bits: 0x%X\n",
+ pic_number, rdata32);
+
+ 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);
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] MVX_L0 AVG : %d (%lld/%d)\n",
+ pic_number, (int)value,
+ value, blk22_mv_count);
+
+ frame->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;
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] MVY_L0 AVG : %d (%lld/%d)\n",
+ pic_number, rdata32_l/blk22_mv_count,
+ value, blk22_mv_count);
+
+ /* 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;
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] MVX_L1 AVG : %d (%lld/%d)\n",
+ pic_number, rdata32_l/blk22_mv_count,
+ value, blk22_mv_count);
+
+ /* 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;
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] MVY_L1 AVG : %d (%lld/%d)\n",
+ pic_number, rdata32_l/blk22_mv_count,
+ value, blk22_mv_count);
+
+ /* {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;
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] MVX_L0 MAX : %d\n",
+ pic_number, mv_hi);
+
+ frame->max_mv = mv_hi;
+
+ mv_lo = (rdata32>>0)&0xffff;
+ if (mv_lo & 0x8000)
+ mv_lo = 0x8000 - mv_lo;
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] MVX_L0 MIN : %d\n",
+ pic_number, mv_lo);
+
+ frame->min_mv = mv_lo;
+
+ /* {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;
+
+ av1_print(hw, AV1_DEBUG_QOS_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;
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[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;
+
+ av1_print(hw, AV1_DEBUG_QOS_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;
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[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;
+
+ av1_print(hw, AV1_DEBUG_QOS_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;
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] MVY_L1 MIN : %d\n",
+ pic_number, mv_lo);
+
+ rdata32 = READ_VREG(HEVC_PIC_QUALITY_CTRL);
+
+ av1_print(hw, AV1_DEBUG_QOS_INFO,
+ "[Picture %d Quality] After Read : VDEC_PIC_QUALITY_CTRL : 0x%x\n",
+ pic_number, rdata32);
+
+ /* reset all counts */
+ WRITE_VREG(HEVC_PIC_QUALITY_CTRL, (1<<8));
+ }
+}
+
+static int load_param(struct AV1HW_s *hw, union param_u *params, uint32_t dec_status)
+{
+ int i;
+ unsigned long flags;
+ int head_type = 0;
+ if (dec_status == AOM_AV1_SEQ_HEAD_PARSER_DONE)
+ head_type = OBU_SEQUENCE_HEADER;
+ else if (dec_status == AOM_AV1_FRAME_HEAD_PARSER_DONE)
+ head_type = OBU_FRAME_HEADER;
+ else if (dec_status == AOM_AV1_FRAME_PARSER_DONE)
+ head_type = OBU_FRAME;
+ else if (dec_status == AOM_AV1_REDUNDANT_FRAME_HEAD_PARSER_DONE)
+ head_type = OBU_REDUNDANT_FRAME_HEADER;
+ else {
+ //printf("Error, dec_status of 0x%x, not supported!!!\n", dec_status);
+ return -1;
+ }
+ av1_print2(AOM_DEBUG_HW_MORE, "load_param: ret 0x%x\n", head_type);
+
+ if (debug&AOM_AV1_DEBUG_SEND_PARAM_WITH_REG) {
+ get_rpm_param(params);
+ }
+ else {
+ for (i = 0; i < (RPM_END-RPM_BEGIN); i += 4) {
+ int32_t ii;
+ for (ii = 0; ii < 4; ii++) {
+ params->l.data[i+ii]=hw->rpm_ptr[i+3-ii];
+ }
+ }
+ }
+
+ params->p.enable_ref_frame_mvs = (params->p.seq_flags >> 7) & 0x1;
+ params->p.enable_superres = (params->p.seq_flags >> 15) & 0x1;
+
+ if (debug & AV1_DEBUG_BUFMGR_MORE) {
+ lock_buffer_pool(hw->common.buffer_pool, flags);
+ pr_info("aom_param: (%d)\n", hw->pbi->decode_idx);
+ //pbi->slice_idx++;
+ for ( i = 0; i < (RPM_END-RPM_BEGIN); i++) {
+ pr_info("%04x ", params->l.data[i]);
+ if (((i + 1) & 0xf) == 0)
+ pr_info("\n");
+ }
+ unlock_buffer_pool(hw->common.buffer_pool, flags);
+ }
+ return head_type;
+}
+
+static int av1_postproc(struct AV1HW_s *hw)
+{
+ if (hw->postproc_done)
+ return 0;
+ hw->postproc_done = 1;
+ return av1_bufmgr_postproc(hw->pbi, hw->frame_decoded);
+}
+
+static int vav1_get_ps_info(struct AV1HW_s *hw, struct aml_vdec_ps_infos *ps)
+{
+ int dw_mode = v4l_parser_get_double_write_mode(hw);
+
+ ps->visible_width = hw->frame_width / get_double_write_ratio(hw, dw_mode);
+ ps->visible_height = hw->frame_height / get_double_write_ratio(hw, dw_mode);
+ ps->coded_width = ALIGN(hw->frame_width, 32) / get_double_write_ratio(hw, dw_mode);
+ ps->coded_height = ALIGN(hw->frame_height, 32) / get_double_write_ratio(hw, dw_mode);
+ ps->dpb_size = hw->used_buf_num;
+
+ return 0;
+}
+
+
+static int v4l_res_change(struct AV1HW_s *hw)
+{
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(hw->v4l2_ctx);
+ struct AV1_Common_s *const cm = &hw->common;
+ int ret = 0;
+
+ if (ctx->param_sets_from_ucode &&
+ hw->res_ch_flag == 0) {
+ struct aml_vdec_ps_infos ps;
+
+ if ((cm->width != 0 &&
+ cm->height != 0) &&
+ (hw->frame_width != cm->width ||
+ hw->frame_height != cm->height)) {
+
+ av1_print(hw, 0,
+ "%s (%d,%d)=>(%d,%d)\r\n", __func__, cm->width,
+ cm->height, hw->frame_width, hw->frame_height);
+
+ vav1_get_ps_info(hw, &ps);
+ vdec_v4l_set_ps_infos(ctx, &ps);
+ vdec_v4l_res_ch_event(ctx);
+ hw->v4l_params_parsed = false;
+ hw->res_ch_flag = 1;
+ ctx->v4l_resolution_change = 1;
+ hw->eos = 1;
+ //del_timer_sync(&pbi->timer);
+ notify_v4l_eos(hw_to_vdec(hw));
+ ret = 1;
+ }
+ }
+
+ return ret;
+}
+
+static irqreturn_t vav1_isr_thread_fn(int irq, void *data)
+{
+ struct AV1HW_s *hw = (struct AV1HW_s *)data;
+ unsigned int dec_status = hw->dec_status;
+ int obu_type;
+ int ret = 0;
+
+ /*if (hw->wait_buf)
+ * pr_info("set wait_buf to 0\r\n");
+ */
+ if (hw->eos)
+ return IRQ_HANDLED;
+ hw->wait_buf = 0;
+ if ((dec_status == AOM_NAL_DECODE_DONE) ||
+ (dec_status == AOM_SEARCH_BUFEMPTY) ||
+ (dec_status == AOM_DECODE_BUFEMPTY)
+ ) {
+ if (hw->m_ins_flag) {
+ reset_process_time(hw);
+ if (!vdec_frame_based(hw_to_vdec(hw)))
+ dec_again_process(hw);
+ else {
+ hw->dec_result = DEC_RESULT_DONE;
+ vdec_schedule_work(&hw->work);
+ }
+ }
+ hw->process_busy = 0;
+ return IRQ_HANDLED;
+ } else if (dec_status == AOM_AV1_DEC_PIC_END) {
+ struct AV1_Common_s *const cm = &hw->common;
+#if 1
+ u32 fg_reg0, fg_reg1, num_y_points, num_cb_points, num_cr_points;
+ WRITE_VREG(HEVC_FGS_IDX, 0);
+ fg_reg0 = READ_VREG(HEVC_FGS_DATA);
+ fg_reg1 = READ_VREG(HEVC_FGS_DATA);
+ num_y_points = fg_reg1 & 0xf;
+ num_cr_points = (fg_reg1 >> 8) & 0xf;
+ num_cb_points = (fg_reg1 >> 4) & 0xf;
+ if ((num_y_points > 0) ||
+ ((num_cb_points > 0) | ((fg_reg0 >> 17) & 0x1)) ||
+ ((num_cr_points > 0) | ((fg_reg0 >> 17) & 0x1)))
+ hw->fgs_valid = 1;
+ else
+ hw->fgs_valid = 0;
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "fg_data0 0x%x fg_data1 0x%x fg_valid %d\n",
+ fg_reg0, fg_reg1, hw->fgs_valid);
+#else
+ if (READ_VREG(HEVC_FGS_CTRL) &
+ ((1 << 4) | (1 << 5) | (1 << 6)))
+ hw->fgs_valid = 1;
+ else
+ hw->fgs_valid = 0;
+#endif
+ decode_frame_count[hw->index] = hw->frame_count;
+ if (hw->m_ins_flag) {
+#ifdef USE_DEC_PIC_END
+ if (READ_VREG(PIC_END_LCU_COUNT) != 0) {
+ hw->frame_decoded = 1;
+ /*
+ In c module, multi obus are put in one packet, which is decoded
+ with av1_receive_compressed_data().
+ For STREAM_MODE or SINGLE_MODE, there is no packet boundary,
+ we assume each packet must and only include one picture of data (LCUs)
+ or cm->show_existing_frame is 1
+ */
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "Decoding done (index %d), fgs_valid %d data_size 0x%x shiftbyte 0x%x\n",
+ cm->cur_frame? cm->cur_frame->buf.index:-1,
+ hw->fgs_valid,
+ hw->data_size,
+ READ_VREG(HEVC_SHIFT_BYTE_COUNT));
+ hw->config_next_ref_info_flag = 1; /*to do: low_latency_flag case*/
+ //config_next_ref_info_hw(hw);
+ }
+#endif
+
+ if (get_picture_qos)
+ get_picture_qos_info(hw);
+
+ reset_process_time(hw);
+
+ if (hw->m_ins_flag && hw->mmu_enable &&
+ (debug & AOM_DEBUG_DIS_RECYCLE_MMU_TAIL) == 0) {
+ long used_4k_num =
+ (READ_VREG(HEVC_SAO_MMU_STATUS) >> 16);
+ if (cm->cur_frame != NULL) {
+ hevc_mmu_dma_check(hw_to_vdec(hw));
+
+ av1_print(hw, AOM_DEBUG_HW_MORE, "mmu free tail, index %d used_num 0x%lx\n",
+ cm->cur_frame->buf.index, used_4k_num);
+ decoder_mmu_box_free_idx_tail(hw->mmu_box,
+ hw->buffer_wrap[cm->cur_frame->buf.index], used_4k_num);
+#ifdef AOM_AV1_MMU_DW
+ if (hw->dw_mmu_enable) {
+ used_4k_num =
+ (READ_VREG(HEVC_SAO_MMU_STATUS2) >> 16);
+ decoder_mmu_box_free_idx_tail(hw->mmu_box_dw,
+ hw->buffer_wrap[cm->cur_frame->buf.index], used_4k_num);
+ av1_print(hw, AOM_DEBUG_HW_MORE, "dw mmu free tail, index %d used_num 0x%lx\n",
+ cm->cur_frame->buf.index, used_4k_num);
+ }
+#endif
+ }
+
+
+ }
+ /*
+ if (debug &
+ AV1_DEBUG_BUFMGR_MORE)
+ dump_aux_buf(hw);
+ set_aux_data(hw,
+ &cm->cur_frame->buf, 0, 0);
+ */
+ if (/*hw->vf_pre_count == 0 ||*/ hw->low_latency_flag)
+ av1_postproc(hw);
+
+ if (multi_frames_in_one_pack &&
+ hw->frame_decoded &&
+ READ_VREG(HEVC_SHIFT_BYTE_COUNT) < hw->data_size) {
+#ifdef DEBUG_CRC_ERROR
+ if (crc_debug_flag & 0x40)
+ dump_mv_buffer(hw, &cm->cur_frame->buf);
+#endif
+ WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_SEARCH_HEAD);
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "PIC_END, fgs_valid %d search head ...\n",
+ hw->fgs_valid);
+ if (hw->config_next_ref_info_flag)
+ config_next_ref_info_hw(hw);
+ } else {
+#ifdef DEBUG_CRC_ERROR
+ if (crc_debug_flag & 0x40)
+ dump_mv_buffer(hw, &cm->cur_frame->buf);
+#endif
+ hw->dec_result = DEC_RESULT_DONE;
+ amhevc_stop();
+#ifdef MCRCC_ENABLE
+ if (mcrcc_cache_alg_flag)
+ dump_hit_rate(hw);
+#endif
+ vdec_schedule_work(&hw->work);
+ }
+ } else {
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "PIC_END, fgs_valid %d search head ...\n",
+ hw->fgs_valid);
+ WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_SEARCH_HEAD);
+#ifdef USE_DEC_PIC_END
+ if (READ_VREG(PIC_END_LCU_COUNT) != 0) {
+ hw->frame_decoded = 1;
+ /*
+ In c module, multi obus are put in one packet, which is decoded
+ with av1_receive_compressed_data().
+ For STREAM_MODE or SINGLE_MODE, there is no packet boundary,
+ we assume each packet must and only include one picture of data (LCUs)
+ or cm->show_existing_frame is 1
+ */
+ av1_print(hw, AOM_DEBUG_HW_MORE, "Decoding done (index %d)\n",
+ cm->cur_frame? cm->cur_frame->buf.index:-1);
+ config_next_ref_info_hw(hw);
+ }
+#endif
+ /*
+ if (debug &
+ AV1_DEBUG_BUFMGR_MORE)
+ dump_aux_buf(hw);
+ set_aux_data(hw,
+ &cm->cur_frame->buf, 0, 0);
+ */
+ if (hw->low_latency_flag) {
+ av1_postproc(hw);
+ vdec_profile(hw_to_vdec(hw), VDEC_PROFILE_EVENT_CB);
+ if (debug & PRINT_FLAG_VDEC_DETAIL)
+ pr_info("%s AV1 frame done \n", __func__);
+ }
+ }
+
+ hw->process_busy = 0;
+ return IRQ_HANDLED;
+ }
+
+ if (dec_status == AOM_EOS) {
+ if (hw->m_ins_flag)
+ reset_process_time(hw);
+
+ av1_print(hw, AOM_DEBUG_HW_MORE, "AV1_EOS, flush buffer\r\n");
+
+ av1_postproc(hw);
+
+ av1_print(hw, AOM_DEBUG_HW_MORE, "send AV1_10B_DISCARD_NAL\r\n");
+ WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_DISCARD_NAL);
+ hw->process_busy = 0;
+ if (hw->m_ins_flag) {
+ hw->dec_result = DEC_RESULT_DONE;
+ amhevc_stop();
+ vdec_schedule_work(&hw->work);
+ }
+ return IRQ_HANDLED;
+ } else if (dec_status == AOM_DECODE_OVER_SIZE) {
+ av1_print(hw, AOM_DEBUG_HW_MORE, "av1 decode oversize !!\n");
+ /*debug |= (AV1_DEBUG_DIS_LOC_ERROR_PROC |
+ AV1_DEBUG_DIS_SYS_ERROR_PROC);*/
+ hw->fatal_error |= DECODER_FATAL_ERROR_SIZE_OVERFLOW;
+ hw->process_busy = 0;
+ if (hw->m_ins_flag)
+ reset_process_time(hw);
+ return IRQ_HANDLED;
+ }
+
+ obu_type = load_param(hw, &hw->aom_param, dec_status);
+ if (obu_type < 0) {
+ hw->process_busy = 0;
+ return IRQ_HANDLED;
+ }
+
+ if (obu_type == OBU_SEQUENCE_HEADER) {
+ int next_lcu_size;
+ hw->has_sequence = 1;
+ av1_bufmgr_process(hw->pbi, &hw->aom_param, 0, obu_type);
+
+ if ((hw->max_pic_w < hw->aom_param.p.max_frame_width) ||
+ (hw->max_pic_h < hw->aom_param.p.max_frame_height)) {
+ av1_print(hw, 0, "%s, max size change (%d, %d) -> (%d, %d)\n",
+ __func__, hw->max_pic_w, hw->max_pic_h,
+ hw->aom_param.p.max_frame_width, hw->aom_param.p.max_frame_height);
+ vav1_mmu_map_free(hw);
+ hw->max_pic_w = hw->aom_param.p.max_frame_width;
+ hw->max_pic_h = hw->aom_param.p.max_frame_height;
+ hw->init_pic_w = hw->max_pic_w;
+ hw->init_pic_h = hw->max_pic_h;
+ hw->pbi->frame_width = hw->init_pic_w;
+ hw->pbi->frame_height = hw->init_pic_h;
+ if (IS_8K_SIZE(hw->max_pic_w, hw->max_pic_h)) {
+ hw->double_write_mode = 4;
+ hw->used_buf_num = MAX_BUF_NUM_LESS;
+ if (hw->used_buf_num > REF_FRAMES_4K)
+ hw->mv_buf_margin = hw->used_buf_num - REF_FRAMES_4K + 1;
+ if (((hw->max_pic_w % 64) != 0) &&
+ (hw_to_vdec(hw)->canvas_mode != CANVAS_BLKMODE_LINEAR))
+ mem_map_mode = 2;
+ av1_print(hw, 0, "force 8k double write 4, mem_map_mode %d\n", mem_map_mode);
+ }
+ vav1_mmu_map_alloc(hw);
+ if (hw->mmu_enable)
+ WRITE_VREG(HEVC_SAO_MMU_DMA_CTRL, hw->frame_mmu_map_phy_addr);
+#ifdef AOM_AV1_MMU_DW
+ if (hw->dw_mmu_enable) {
+ WRITE_VREG(HEVC_SAO_MMU_DMA_CTRL2, hw->dw_frame_mmu_map_phy_addr);
+ //default of 0xffffffff will disable dw
+ WRITE_VREG(HEVC_SAO_Y_START_ADDR, 0);
+ WRITE_VREG(HEVC_SAO_C_START_ADDR, 0);
+ }
+#endif
+ }
+ bit_depth_luma = hw->aom_param.p.bit_depth;
+ bit_depth_chroma = hw->aom_param.p.bit_depth;
+ next_lcu_size = ((hw->aom_param.p.seq_flags >> 6) & 0x1) ? 128 : 64;
+ hw->video_signal_type = (hw->aom_param.p.video_signal_type << 16
+ | hw->aom_param.p.color_description);
+
+ if (next_lcu_size != hw->current_lcu_size) {
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ " ## lcu_size changed from %d to %d\n",
+ hw->current_lcu_size, next_lcu_size);
+ hw->current_lcu_size = next_lcu_size;
+ }
+
+ if (!hw->pic_list_init_done) {
+#if 0
+ if (hw->m_ins_flag) {
+ /* picture list init.*/
+ hw->dec_result = DEC_INIT_PICLIST;
+ vdec_schedule_work(&hw->work);
+ } else
+#endif
+ {
+ init_pic_list(hw);
+ init_pic_list_hw(hw);
+#ifndef MV_USE_FIXED_BUF
+ if (init_mv_buf_list(hw) < 0) {
+ pr_err("%s: !!!!Error, init_mv_buf_list fail\n", __func__);
+ }
+#endif
+ }
+ hw->pic_list_init_done = true;
+ }
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "AOM_AV1_SEQ_HEAD_PARSER_DONE, search head ...\n");
+ WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_SEARCH_HEAD);
+ hw->process_busy = 0;
+ return IRQ_HANDLED;
+ }
+#ifndef USE_DEC_PIC_END
+ //if (pbi->wait_buf) {
+ if (pbi->bufmgr_proc_count > 0) {
+ if (READ_VREG(PIC_END_LCU_COUNT) != 0) {
+ hw->frame_decoded = 1;
+ /*
+ In c module, multi obus are put in one packet, which is decoded
+ with av1_receive_compressed_data().
+ For STREAM_MODE or SINGLE_MODE, there is no packet boundary,
+ we assume each packet must and only include one picture of data (LCUs)
+ or cm->show_existing_frame is 1
+ */
+ av1_print(hw, AOM_DEBUG_HW_MORE, "Decoding done (index %d)\n",
+ cm->cur_frame? cm->cur_frame->buf.index:-1);
+ }
+ }
+#endif
+#if 1
+/*def CHECK_OBU_REDUNDANT_FRAME_HEADER*/
+ if (debug & AOM_DEBUG_BUFMGR_ONLY) {
+ if (READ_VREG(PIC_END_LCU_COUNT) != 0)
+ hw->obu_frame_frame_head_come_after_tile = 0;
+
+ if (obu_type == OBU_FRAME_HEADER ||
+ obu_type == OBU_FRAME) {
+ hw->obu_frame_frame_head_come_after_tile = 1;
+ } else if (obu_type == OBU_REDUNDANT_FRAME_HEADER &&
+ hw->obu_frame_frame_head_come_after_tile == 0) {
+ if (hw->frame_decoded == 1) {
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "Warning, OBU_REDUNDANT_FRAME_HEADER come without OBU_FRAME or OBU_FRAME_HEAD\n");
+ hw->frame_decoded = 0;
+ }
+ }
+ }
+#endif
+ if (hw->frame_decoded)
+ hw->one_compressed_data_done = 1;
+
+ if (hw->m_ins_flag)
+ reset_process_time(hw);
+
+ if (hw->process_state != PROC_STATE_SENDAGAIN
+ ) {
+ if (hw->one_compressed_data_done) {
+ av1_postproc(hw);
+ av1_release_bufs(hw);
+#ifndef MV_USE_FIXED_BUF
+ put_un_used_mv_bufs(hw);
+#endif
+ }
+ }
+
+ if (hw->is_used_v4l) {
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(hw->v4l2_ctx);
+
+ hw->frame_width = hw->common.seq_params.max_frame_width;
+ hw->frame_height = hw->common.seq_params.max_frame_height;
+
+ if (!v4l_res_change(hw)) {
+ if (ctx->param_sets_from_ucode && !hw->v4l_params_parsed) {
+ struct aml_vdec_ps_infos ps;
+
+ pr_info("set ucode parse\n");
+ vav1_get_ps_info(hw, &ps);
+ /*notice the v4l2 codec.*/
+ vdec_v4l_set_ps_infos(ctx, &ps);
+ hw->v4l_params_parsed = true;
+ hw->postproc_done = 0;
+ hw->process_busy = 0;
+ dec_again_process(hw);
+ return IRQ_HANDLED;
+ }
+ } else {
+ hw->postproc_done = 0;
+ hw->process_busy = 0;
+ dec_again_process(hw);
+ return IRQ_HANDLED;
+ }
+ }
+
+ ret = av1_continue_decoding(hw, obu_type);
+ hw->postproc_done = 0;
+ hw->process_busy = 0;
+
+ if (hw->m_ins_flag) {
+ if (ret >= 0)
+ start_process_time(hw);
+ else {
+ hw->dec_result = DEC_RESULT_DONE;
+ amhevc_stop();
+ vdec_schedule_work(&hw->work);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t vav1_isr(int irq, void *data)
+{
+ int i;
+ unsigned int dec_status;
+ struct AV1HW_s *hw = (struct AV1HW_s *)data;
+ //struct AV1_Common_s *const cm = &hw->common;
+ uint debug_tag;
+
+ WRITE_VREG(HEVC_ASSIST_MBOX0_CLR_REG, 1);
+
+ dec_status = READ_VREG(HEVC_DEC_STATUS_REG) & 0xff;
+ if (!hw)
+ return IRQ_HANDLED;
+ if (hw->init_flag == 0)
+ return IRQ_HANDLED;
+ if (hw->process_busy)/*on process.*/
+ return IRQ_HANDLED;
+ hw->dec_status = dec_status;
+ hw->process_busy = 1;
+ if (debug & AV1_DEBUG_BUFMGR)
+ av1_print(hw, AV1_DEBUG_BUFMGR,
+ "av1 isr (%d) dec status = 0x%x (0x%x), lcu 0x%x shiftbyte 0x%x shifted_data 0x%x (%x %x lev %x, wr %x, rd %x) log %x\n",
+ irq,
+ dec_status, READ_VREG(HEVC_DEC_STATUS_REG),
+ READ_VREG(HEVC_PARSER_LCU_START),
+ READ_VREG(HEVC_SHIFT_BYTE_COUNT),
+ READ_VREG(HEVC_SHIFTED_DATA),
+ 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),
+#ifdef DEBUG_UCODE_LOG
+ READ_VREG(HEVC_DBG_LOG_ADR)
+#else
+ 0
+#endif
+ );
+#ifdef DEBUG_UCODE_LOG
+ if ((udebug_flag & 0x8) &&
+ (hw->ucode_log_addr != 0) &&
+ (READ_VREG(HEVC_DEC_STATUS_REG) & 0x100)) {
+ unsigned long flags;
+ unsigned short *log_adr =
+ (unsigned short *)hw->ucode_log_addr;
+ lock_buffer_pool(hw->pbi->common.buffer_pool, flags);
+ while (*(log_adr + 3)) {
+ pr_info("dbg%04x %04x %04x %04x\n",
+ *(log_adr + 3), *(log_adr + 2), *(log_adr + 1), *(log_adr + 0)
+ );
+ log_adr += 4;
+ }
+ unlock_buffer_pool(hw->pbi->common.buffer_pool, flags);
+ }
+#endif
+ debug_tag = READ_HREG(DEBUG_REG1);
+ if (debug_tag & 0x10000) {
+ 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 ",
+ hw->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 == hw->result_done_count) &&
+ (udebug_pause_val == 0 ||
+ udebug_pause_val == READ_HREG(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_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 == hw->result_done_count) &&
+ (udebug_pause_val == 0 ||
+ udebug_pause_val == READ_HREG(DEBUG_REG2))) {
+ udebug_pause_pos &= 0xffff;
+ hw->ucode_pause_pos = udebug_pause_pos;
+ }
+ if (hw->ucode_pause_pos)
+ reset_process_time(hw);
+ else
+ WRITE_HREG(DEBUG_REG1, 0);
+ hw->process_busy = 0;
+ return IRQ_HANDLED;
+ }
+
+ //if (READ_VREG(HEVC_FG_STATUS) == AOM_AV1_FGS_PARAM) {
+ if (hw->dec_status == AOM_AV1_FGS_PARAM) {
+ uint32_t status_val = READ_VREG(HEVC_FG_STATUS);
+ WRITE_VREG(HEVC_FG_STATUS, AOM_AV1_FGS_PARAM_CONT);
+ WRITE_VREG(HEVC_DEC_STATUS_REG, AOM_AV1_FGS_PARAM_CONT);
+ // Bit[11] - 0 Read, 1 - Write
+ // Bit[10:8] - film_grain_params_ref_idx // For Write request
+ if ((status_val >> 11) & 0x1) {
+ uint32_t film_grain_params_ref_idx = (status_val >> 8) & 0x7;
+ config_film_grain_reg(hw, film_grain_params_ref_idx);
+ }
+ else
+ read_film_grain_reg(hw);
+ hw->process_busy = 0;
+ return IRQ_HANDLED;
+ }
+
+ if (!hw->m_ins_flag) {
+ av1_print(hw, AV1_DEBUG_BUFMGR,
+ "error flag = %d\n", hw->error_flag);
+ if (hw->error_flag == 1) {
+ hw->error_flag = 2;
+ hw->process_busy = 0;
+ return IRQ_HANDLED;
+ } else if (hw->error_flag == 3) {
+ hw->process_busy = 0;
+ return IRQ_HANDLED;
+ }
+ }
+ if (get_free_buf_count(hw) <= 0) {
+ /*
+ if (hw->wait_buf == 0)
+ pr_info("set wait_buf to 1\r\n");
+ */
+ hw->wait_buf = 1;
+ hw->process_busy = 0;
+ av1_print(hw, AV1_DEBUG_BUFMGR,
+ "free buf not enough = %d\n",
+ get_free_buf_count(hw));
+ return IRQ_HANDLED;
+ }
+ return IRQ_WAKE_THREAD;
+}
+
+static void av1_set_clk(struct work_struct *work)
+{
+ struct AV1HW_s *hw = container_of(work,
+ struct AV1HW_s, set_clk_work);
+ int fps = 96000 / hw->frame_dur;
+
+ if (hevc_source_changed(VFORMAT_AV1,
+ frame_width, frame_height, fps) > 0)
+ hw->saved_resolution = frame_width *
+ frame_height * fps;
+}
+
+static void vav1_put_timer_func(unsigned long arg)
+{
+ struct AV1HW_s *hw = (struct AV1HW_s *)arg;
+ struct timer_list *timer = &hw->timer;
+ uint8_t empty_flag;
+ unsigned int buf_level;
+
+ enum receviver_start_e state = RECEIVER_INACTIVE;
+
+ if (hw->m_ins_flag) {
+ if (hw_to_vdec(hw)->next_status
+ == VDEC_STATUS_DISCONNECTED) {
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(hw->v4l2_ctx);
+ if (!hw->is_used_v4l || ctx->is_stream_off) {
+ hw->dec_result = DEC_RESULT_FORCE_EXIT;
+ vdec_schedule_work(&hw->work);
+ pr_debug("vdec requested to be disconnected\n");
+ return;
+ }
+ }
+ }
+ if (hw->init_flag == 0) {
+ if (hw->stat & STAT_TIMER_ARM) {
+ timer->expires = jiffies + PUT_INTERVAL;
+ add_timer(&hw->timer);
+ }
+ return;
+ }
+ if (hw->m_ins_flag == 0) {
+ if (vf_get_receiver(hw->provider_name)) {
+ state =
+ vf_notify_receiver(hw->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 & AV1_DEBUG_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(&hw->display_q) &&
+ buf_level > 0x200)
+ ) {
+ WRITE_VREG
+ (HEVC_ASSIST_MBOX0_IRQ_REG,
+ 0x1);
+ }
+ }
+
+ }
+ }
+#ifdef MULTI_INSTANCE_SUPPORT
+ else {
+ if (
+ (decode_timeout_val > 0) &&
+ (hw->start_process_time > 0) &&
+ ((1000 * (jiffies - hw->start_process_time) / HZ)
+ > decode_timeout_val)
+ ) {
+ int current_lcu_idx =
+ READ_VREG(HEVC_PARSER_LCU_START)
+ & 0xffffff;
+ if (hw->last_lcu_idx == current_lcu_idx) {
+ if (hw->decode_timeout_count > 0)
+ hw->decode_timeout_count--;
+ if (hw->decode_timeout_count == 0) {
+ if (input_frame_based(
+ hw_to_vdec(hw)) ||
+ (READ_VREG(HEVC_STREAM_LEVEL) > 0x200))
+ timeout_process(hw);
+ else {
+ av1_print(hw, 0,
+ "timeout & empty, again\n");
+ dec_again_process(hw);
+ }
+ }
+ } else {
+ start_process_time(hw);
+ hw->last_lcu_idx = current_lcu_idx;
+ }
+ }
+ }
+#endif
+
+ if ((hw->ucode_pause_pos != 0) &&
+ (hw->ucode_pause_pos != 0xffffffff) &&
+ udebug_pause_pos != hw->ucode_pause_pos) {
+ hw->ucode_pause_pos = 0;
+ WRITE_HREG(DEBUG_REG1, 0);
+ }
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (debug & AV1_DEBUG_DUMP_DATA) {
+ debug &= ~AV1_DEBUG_DUMP_DATA;
+ av1_print(hw, 0,
+ "%s: chunk size 0x%x off 0x%x sum 0x%x\n",
+ __func__,
+ hw->chunk->size,
+ hw->chunk->offset,
+ get_data_check_sum(hw, hw->chunk->size)
+ );
+ dump_data(hw, hw->chunk->size);
+ }
+#endif
+ if (debug & AV1_DEBUG_DUMP_PIC_LIST) {
+ /*dump_pic_list(hw);*/
+ av1_dump_state(hw_to_vdec(hw));
+ debug &= ~AV1_DEBUG_DUMP_PIC_LIST;
+ }
+ if (debug & AV1_DEBUG_TRIG_SLICE_SEGMENT_PROC) {
+ WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG, 0x1);
+ debug &= ~AV1_DEBUG_TRIG_SLICE_SEGMENT_PROC;
+ }
+ /*if (debug & AV1_DEBUG_HW_RESET) {
+ }*/
+
+ if (radr != 0) {
+ if ((radr >> 24) != 0) {
+ int count = radr >> 24;
+ int adr = radr & 0xffffff;
+ int i;
+ for (i = 0; i < count; i++)
+ pr_info("READ_VREG(%x)=%x\n", adr+i, READ_VREG(adr+i));
+ } else 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(hw) == 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 (hw->get_frame_dur && hw->show_frame_num > 60 &&
+ hw->frame_dur > 0 && hw->saved_resolution !=
+ frame_width * frame_height *
+ (96000 / hw->frame_dur))
+ vdec_schedule_work(&hw->set_clk_work);
+
+ timer->expires = jiffies + PUT_INTERVAL;
+ add_timer(timer);
+}
+
+
+int vav1_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus)
+{
+ struct AV1HW_s *av1 =
+ (struct AV1HW_s *)vdec->private;
+
+ if (!av1)
+ return -1;
+
+ vstatus->frame_width = frame_width;
+ vstatus->frame_height = frame_height;
+ if (av1->frame_dur != 0)
+ vstatus->frame_rate = 96000 / av1->frame_dur;
+ else
+ vstatus->frame_rate = -1;
+ vstatus->error_count = 0;
+ vstatus->status = av1->stat | av1->fatal_error;
+ vstatus->frame_dur = av1->frame_dur;
+#ifndef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ vstatus->bit_rate = gvs->bit_rate;
+ vstatus->frame_data = gvs->frame_data;
+ vstatus->total_data = gvs->total_data;
+ vstatus->frame_count = gvs->frame_count;
+ vstatus->error_frame_count = gvs->error_frame_count;
+ vstatus->drop_frame_count = gvs->drop_frame_count;
+ vstatus->total_data = gvs->total_data;
+ vstatus->samp_cnt = gvs->samp_cnt;
+ vstatus->offset = gvs->offset;
+ snprintf(vstatus->vdec_name, sizeof(vstatus->vdec_name),
+ "%s", DRIVER_NAME);
+#endif
+ return 0;
+}
+
+int vav1_set_isreset(struct vdec_s *vdec, int isreset)
+{
+ is_reset = isreset;
+ return 0;
+}
+
+#if 0
+static void AV1_DECODE_INIT(void)
+{
+ /* enable av1 clocks */
+ WRITE_VREG(DOS_GCLK_EN3, 0xffffffff);
+ /* *************************************************************** */
+ /* Power ON HEVC */
+ /* *************************************************************** */
+ /* Powerup HEVC */
+ WRITE_VREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_VREG(AO_RTI_GEN_PWR_SLEEP0) & (~(0x3 << 6)));
+ WRITE_VREG(DOS_MEM_PD_HEVC, 0x0);
+ WRITE_VREG(DOS_SW_RESET3, READ_VREG(DOS_SW_RESET3) | (0x3ffff << 2));
+ WRITE_VREG(DOS_SW_RESET3, READ_VREG(DOS_SW_RESET3) & (~(0x3ffff << 2)));
+ /* remove isolations */
+ WRITE_VREG(AO_RTI_GEN_PWR_ISO0,
+ READ_VREG(AO_RTI_GEN_PWR_ISO0) & (~(0x3 << 10)));
+
+}
+#endif
+
+static void vav1_prot_init(struct AV1HW_s *hw, u32 mask)
+{
+ unsigned int data32;
+ /* AV1_DECODE_INIT(); */
+ av1_print(hw, AOM_DEBUG_HW_MORE, "%s %d\n", __func__, __LINE__);
+
+ aom_config_work_space_hw(hw, mask);
+ if (mask & HW_MASK_BACK) {
+ //to do: .. for single instance, called after init_pic_list()
+ if (hw->m_ins_flag)
+ init_pic_list_hw(hw);
+ }
+
+ aom_init_decoder_hw(hw, mask);
+
+#ifdef AOM_AV1_DBLK_INIT
+ av1_print(hw, AOM_DEBUG_HW_MORE,
+ "[test.c] av1_loop_filter_init (run once before decoding start)\n");
+ av1_loop_filter_init(hw->lfi, hw->lf);
+#endif
+ if ((mask & HW_MASK_FRONT) == 0)
+ return;
+#if 1
+ if (debug & AV1_DEBUG_BUFMGR_MORE)
+ pr_info("%s\n", __func__);
+ data32 = READ_VREG(HEVC_STREAM_CONTROL);
+ data32 = data32 |
+ (1 << 0)/*stream_fetch_enable*/
+ ;
+ WRITE_VREG(HEVC_STREAM_CONTROL, data32);
+
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) {
+ if (debug & AV1_DEBUG_BUFMGR)
+ pr_info("[test.c] Config STREAM_FIFO_CTL\n");
+ data32 = READ_VREG(HEVC_STREAM_FIFO_CTL);
+ data32 = data32 |
+ (1 << 29) // stream_fifo_hole
+ ;
+ WRITE_VREG(HEVC_STREAM_FIFO_CTL, data32);
+ }
+#if 0
+ data32 = READ_VREG(HEVC_SHIFT_STARTCODE);
+ if (data32 != 0x00000100) {
+ pr_info("av1 prot init error %d\n", __LINE__);
+ return;
+ }
+ data32 = READ_VREG(HEVC_SHIFT_EMULATECODE);
+ if (data32 != 0x00000300) {
+ pr_info("av1 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("av1 prot init error %d\n", __LINE__);
+ return;
+ }
+ data32 = READ_VREG(HEVC_SHIFT_EMULATECODE);
+ if (data32 != 0x9abcdef0) {
+ pr_info("av1 prot init error %d\n", __LINE__);
+ return;
+ }
+#endif
+ WRITE_VREG(HEVC_SHIFT_STARTCODE, 0x000000001);
+ WRITE_VREG(HEVC_SHIFT_EMULATECODE, 0x00000300);
+#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);
+#if (defined DEBUG_UCODE_LOG) || (defined DEBUG_CMD)
+ WRITE_VREG(HEVC_DBG_LOG_ADR, hw->ucode_log_phy_addr);
+#endif
+}
+
+static int vav1_local_init(struct AV1HW_s *hw)
+{
+ int i;
+ int ret;
+ int width, height;
+
+ hw->gvs = vzalloc(sizeof(struct vdec_info));
+ if (NULL == hw->gvs) {
+ pr_info("the struct of vdec status malloc failed.\n");
+ return -1;
+ }
+#ifdef DEBUG_PTS
+ hw->pts_missed = 0;
+ hw->pts_hit = 0;
+#endif
+ hw->new_frame_displayed = 0;
+ hw->last_put_idx = -1;
+ hw->saved_resolution = 0;
+ hw->get_frame_dur = false;
+ on_no_keyframe_skiped = 0;
+ hw->first_pts_index = 0;
+ hw->dur_recalc_flag = 0;
+ hw->av1_first_pts_ready = false;
+ width = hw->vav1_amstream_dec_info.width;
+ height = hw->vav1_amstream_dec_info.height;
+ hw->frame_dur =
+ (hw->vav1_amstream_dec_info.rate ==
+ 0) ? 3200 : hw->vav1_amstream_dec_info.rate;
+ if (width && height)
+ hw->frame_ar = height * 0x100 / width;
+/*
+ *TODO:FOR VERSION
+ */
+ pr_info("av1: ver (%d,%d) decinfo: %dx%d rate=%d\n", av1_version,
+ 0, width, height, hw->frame_dur);
+
+ if (hw->frame_dur == 0)
+ hw->frame_dur = 96000 / 24;
+
+ INIT_KFIFO(hw->display_q);
+ INIT_KFIFO(hw->newframe_q);
+
+ for (i = 0; i < FRAME_BUFFERS; i++) {
+ hw->buffer_wrap[i] = i;
+ }
+
+ for (i = 0; i < VF_POOL_SIZE; i++) {
+ const struct vframe_s *vf = &hw->vfpool[i];
+
+ hw->vfpool[i].index = -1;
+ kfifo_put(&hw->newframe_q, vf);
+ }
+
+ ret = av1_local_init(hw);
+
+ if (force_pts_unstable) {
+ if (!hw->pts_unstable) {
+ hw->pts_unstable =
+ (hw->vav1_amstream_dec_info.rate == 0)?1:0;
+ pr_info("set pts unstable\n");
+ }
+ }
+
+ return ret;
+}
+
+
+#ifdef MULTI_INSTANCE_SUPPORT
+static s32 vav1_init(struct vdec_s *vdec)
+{
+ struct AV1HW_s *hw = (struct AV1HW_s *)vdec->private;
+#else
+static s32 vav1_init(struct AV1HW_s *hw)
+{
+#endif
+ int ret;
+ int fw_size = 0x1000 * 16;
+ struct firmware_s *fw = NULL;
+
+ hw->stat |= STAT_TIMER_INIT;
+
+ if (vav1_local_init(hw) < 0)
+ return -EBUSY;
+
+ fw = vmalloc(sizeof(struct firmware_s) + fw_size);
+ if (IS_ERR_OR_NULL(fw))
+ return -ENOMEM;
+
+ av1_print(hw, AOM_DEBUG_HW_MORE, "%s %d\n", __func__, __LINE__);
+#ifdef DEBUG_USE_VP9_DEVICE_NAME
+ if (get_firmware_data(VIDEO_DEC_VP9_MMU, fw->data) < 0) {
+#else
+ if (get_firmware_data(VIDEO_DEC_AV1_MMU, fw->data) < 0) {
+#endif
+ pr_err("get firmware fail.\n");
+ printk("%s %d\n", __func__, __LINE__);
+ vfree(fw);
+ return -1;
+ }
+ av1_print(hw, AOM_DEBUG_HW_MORE, "%s %d\n", __func__, __LINE__);
+ fw->len = fw_size;
+
+ INIT_WORK(&hw->set_clk_work, av1_set_clk);
+ init_timer(&hw->timer);
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (hw->m_ins_flag) {
+ hw->timer.data = (ulong) hw;
+ hw->timer.function = vav1_put_timer_func;
+ hw->timer.expires = jiffies + PUT_INTERVAL;
+
+ /*add_timer(&hw->timer);
+
+ hw->stat |= STAT_TIMER_ARM;
+ hw->stat |= STAT_ISR_REG;*/
+
+ INIT_WORK(&hw->work, av1_work);
+ hw->fw = fw;
+
+ return 0; /*multi instance return */
+ }
+#endif
+ amhevc_enable();
+
+ ret = amhevc_loadmc_ex(VFORMAT_AV1, NULL, fw->data);
+ if (ret < 0) {
+ amhevc_disable();
+ vfree(fw);
+ pr_err("AV1: the %s fw loading failed, err: %x\n",
+ tee_enabled() ? "TEE" : "local", ret);
+ return -EBUSY;
+ }
+
+ vfree(fw);
+
+ hw->stat |= STAT_MC_LOAD;
+
+ /* enable AMRISC side protocol */
+ vav1_prot_init(hw, HW_MASK_FRONT | HW_MASK_BACK);
+
+ if (vdec_request_threaded_irq(VDEC_IRQ_0,
+ vav1_isr,
+ vav1_isr_thread_fn,
+ IRQF_ONESHOT,/*run thread on this irq disabled*/
+ "vav1-irq", (void *)hw)) {
+ pr_info("vav1 irq register error.\n");
+ amhevc_disable();
+ return -ENOENT;
+ }
+
+ hw->stat |= STAT_ISR_REG;
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ if (force_dv_enable)
+ hw->provider_name = DV_PROVIDER_NAME;
+ else
+#endif
+ hw->provider_name = PROVIDER_NAME;
+#ifdef MULTI_INSTANCE_SUPPORT
+ vf_provider_init(&vav1_vf_prov, hw->provider_name,
+ &vav1_vf_provider, hw);
+ vf_reg_provider(&vav1_vf_prov);
+ vf_notify_receiver(hw->provider_name, VFRAME_EVENT_PROVIDER_START, NULL);
+ if (hw->frame_dur != 0) {
+ if (!is_reset)
+ vf_notify_receiver(hw->provider_name,
+ VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)
+ ((unsigned long)hw->frame_dur));
+ }
+#else
+ vf_provider_init(&vav1_vf_prov, hw->provider_name, &vav1_vf_provider,
+ hw);
+ vf_reg_provider(&vav1_vf_prov);
+ vf_notify_receiver(hw->provider_name, VFRAME_EVENT_PROVIDER_START, NULL);
+ if (!is_reset)
+ vf_notify_receiver(hw->provider_name, VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)((unsigned long)hw->frame_dur));
+#endif
+ hw->stat |= STAT_VF_HOOK;
+
+ hw->timer.data = (ulong)hw;
+ hw->timer.function = vav1_put_timer_func;
+ hw->timer.expires = jiffies + PUT_INTERVAL;
+
+ hw->stat |= STAT_VDEC_RUN;
+
+ add_timer(&hw->timer);
+ hw->stat |= STAT_TIMER_ARM;
+
+ amhevc_start();
+
+ hw->init_flag = 1;
+ hw->process_busy = 0;
+ pr_info("%d, vav1_init, RP=0x%x\n",
+ __LINE__, READ_VREG(HEVC_STREAM_RD_PTR));
+ return 0;
+}
+
+static int vmav1_stop(struct AV1HW_s *hw)
+{
+ hw->init_flag = 0;
+
+ if (hw->stat & STAT_VDEC_RUN) {
+ amhevc_stop();
+ hw->stat &= ~STAT_VDEC_RUN;
+ }
+ if (hw->stat & STAT_ISR_REG) {
+ vdec_free_irq(VDEC_IRQ_0, (void *)hw);
+ hw->stat &= ~STAT_ISR_REG;
+ }
+ if (hw->stat & STAT_TIMER_ARM) {
+ del_timer_sync(&hw->timer);
+ hw->stat &= ~STAT_TIMER_ARM;
+ }
+
+ if (hw->stat & STAT_VF_HOOK) {
+ if (!is_reset)
+ vf_notify_receiver(hw->provider_name,
+ VFRAME_EVENT_PROVIDER_FR_END_HINT,
+ NULL);
+
+ vf_unreg_provider(&vav1_vf_prov);
+ hw->stat &= ~STAT_VF_HOOK;
+ }
+ av1_local_uninit(hw);
+ reset_process_time(hw);
+ cancel_work_sync(&hw->work);
+ cancel_work_sync(&hw->set_clk_work);
+ uninit_mmu_buffers(hw);
+ if (hw->fw)
+ vfree(hw->fw);
+ hw->fw = NULL;
+ return 0;
+}
+
+static int vav1_stop(struct AV1HW_s *hw)
+{
+
+ hw->init_flag = 0;
+ hw->first_sc_checked = 0;
+ if (hw->stat & STAT_VDEC_RUN) {
+ amhevc_stop();
+ hw->stat &= ~STAT_VDEC_RUN;
+ }
+
+ if (hw->stat & STAT_ISR_REG) {
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (!hw->m_ins_flag)
+#endif
+ WRITE_VREG(HEVC_ASSIST_MBOX0_MASK, 0);
+ vdec_free_irq(VDEC_IRQ_0, (void *)hw);
+ hw->stat &= ~STAT_ISR_REG;
+ }
+
+ if (hw->stat & STAT_TIMER_ARM) {
+ del_timer_sync(&hw->timer);
+ hw->stat &= ~STAT_TIMER_ARM;
+ }
+
+ if (hw->stat & STAT_VF_HOOK) {
+ if (!is_reset)
+ vf_notify_receiver(hw->provider_name,
+ VFRAME_EVENT_PROVIDER_FR_END_HINT,
+ NULL);
+
+ vf_unreg_provider(&vav1_vf_prov);
+ hw->stat &= ~STAT_VF_HOOK;
+ }
+ av1_local_uninit(hw);
+
+ cancel_work_sync(&hw->set_clk_work);
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (hw->m_ins_flag) {
+ cancel_work_sync(&hw->work);
+ } else
+ amhevc_disable();
+#else
+ amhevc_disable();
+#endif
+ uninit_mmu_buffers(hw);
+
+ vfree(hw->fw);
+ hw->fw = NULL;
+ return 0;
+}
+static int amvdec_av1_mmu_init(struct AV1HW_s *hw)
+{
+ int tvp_flag = vdec_secure(hw_to_vdec(hw)) ?
+ CODEC_MM_FLAGS_TVP : 0;
+ int buf_size = 48;
+
+ if ((hw->max_pic_w * hw->max_pic_h > 1280*736) &&
+ (hw->max_pic_w * hw->max_pic_h <= 1920*1088)) {
+ buf_size = 12;
+ } else if ((hw->max_pic_w * hw->max_pic_h > 0) &&
+ (hw->max_pic_w * hw->max_pic_h <= 1280*736)) {
+ buf_size = 4;
+ }
+ hw->need_cache_size = buf_size * SZ_1M;
+ hw->sc_start_time = get_jiffies_64();
+ if (hw->mmu_enable) {
+ int count = FRAME_BUFFERS;
+ hw->mmu_box = decoder_mmu_box_alloc_box(DRIVER_NAME,
+ hw->index /* * 2*/, count,
+ hw->need_cache_size,
+ tvp_flag
+ );
+ if (!hw->mmu_box) {
+ pr_err("av1 alloc mmu box failed!!\n");
+ return -1;
+ }
+#ifdef AOM_AV1_MMU_DW
+ if (hw->dw_mmu_enable) {
+ hw->mmu_box_dw = decoder_mmu_box_alloc_box(DRIVER_NAME,
+ hw->index /** 2 + 1*/, count,
+ hw->need_cache_size,
+ tvp_flag
+ );
+ if (!hw->mmu_box_dw) {
+ pr_err("av1 alloc dw mmu box failed!!\n");
+ return -1;
+ }
+ }
+#endif
+
+ }
+ hw->bmmu_box = decoder_bmmu_box_alloc_box(
+ DRIVER_NAME,
+ hw->index,
+ MAX_BMMU_BUFFER_NUM,
+ 4 + PAGE_SHIFT,
+ CODEC_MM_FLAGS_CMA_CLEAR |
+ CODEC_MM_FLAGS_FOR_VDECODER |
+ tvp_flag);
+ av1_print(hw, AV1_DEBUG_BUFMGR,
+ "%s, MAX_BMMU_BUFFER_NUM = %d\n",
+ __func__,
+ MAX_BMMU_BUFFER_NUM);
+ if (!hw->bmmu_box) {
+ pr_err("av1 alloc bmmu box failed!!\n");
+ return -1;
+ }
+ return 0;
+}
+
+static struct AV1HW_s *gHevc;
+
+
+static int amvdec_av1_probe(struct platform_device *pdev)
+{
+ struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
+
+ struct AV1HW_s *hw;
+ AV1Decoder *pbi;
+ int ret;
+ u32 work_buf_size;
+ struct BuffInfo_s *p_buf_info;
+#ifndef MULTI_INSTANCE_SUPPORT
+ int i;
+#endif
+ pr_debug("%s\n", __func__);
+
+ if (!(is_cpu_tm2_revb() ||
+ (get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_TM2))) {
+ pr_err("unsupport av1, cpu %d, is_tm2_revb %d\n",
+ get_cpu_major_id(), is_cpu_tm2_revb());
+ return -EFAULT;
+ }
+
+ mutex_lock(&vav1_mutex);
+ hw = vzalloc(sizeof(struct AV1HW_s));
+ if (hw == NULL) {
+ av1_print(hw, 0, "\namvdec_av1 device data allocation failed\n");
+ mutex_unlock(&vav1_mutex);
+ return -ENOMEM;
+ }
+ gHevc = hw;
+ /*
+ memcpy(&BUF[0], &hw->m_BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM);
+ memset(hw, 0, sizeof(struct AV1HW_s));
+ memcpy(&hw->m_BUF[0], &BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM);
+ */
+ if (init_dblk_struc(hw) < 0) {
+ av1_print(hw, 0, "\nammvdec_av1 device data allocation failed\n");
+ vfree(hw);
+ return -ENOMEM;
+ }
+
+ pbi = av1_decoder_create(&hw->av1_buffer_pool, &hw->common); //&aom_decoder;
+ hw->pbi = pbi;
+ if (hw->pbi == NULL) {
+ pr_info("\nammvdec_av1 device data allocation failed\n");
+ release_dblk_struct(hw);
+ vfree(hw);
+ return -ENOMEM;
+ }
+ //hw->common.buffer_pool = &hw->av1_buffer_pool; //????
+ hw->pbi->private_data = hw;
+
+ hw->init_flag = 0;
+ hw->first_sc_checked= 0;
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ hw->eos = 0;
+ hw->start_process_time = 0;
+ hw->timeout_num = 0;
+#endif
+ hw->fatal_error = 0;
+ hw->show_frame_num = 0;
+ if (pdata == NULL) {
+ av1_print(hw, 0, "\namvdec_av1 memory resource undefined.\n");
+ vfree(hw);
+ mutex_unlock(&vav1_mutex);
+ return -EFAULT;
+ }
+
+ if (pdata->sys_info) {
+ hw->vav1_amstream_dec_info = *pdata->sys_info;
+ av1_max_pic_w = (hw->vav1_amstream_dec_info.width) ?
+ (hw->vav1_amstream_dec_info.width) : 8192;
+
+ av1_max_pic_h = (hw->vav1_amstream_dec_info.height) ?
+ (hw->vav1_amstream_dec_info.height) : 4608;
+ } else {
+ hw->vav1_amstream_dec_info.width = 0;
+ hw->vav1_amstream_dec_info.height = 0;
+ hw->vav1_amstream_dec_info.rate = 30;
+ av1_max_pic_w = 8192;
+ av1_max_pic_h = 4608;
+ }
+ hw->max_pic_w = av1_max_pic_w;
+ hw->max_pic_h = av1_max_pic_h;
+
+ hw->m_ins_flag = 0;
+
+ if (force_bufspec) {
+ hw->buffer_spec_index = force_bufspec & 0xf;
+ pr_info("force buffer spec %d\n", force_bufspec & 0xf);
+ } else if (vdec_is_support_4k()) {
+ if (IS_8K_SIZE(hw->max_pic_w, hw->max_pic_h))
+ hw->buffer_spec_index = 2;
+ else if (IS_4K_SIZE(hw->max_pic_w, hw->max_pic_h))
+ hw->buffer_spec_index = 1;
+ else
+ hw->buffer_spec_index = 0;
+ } else
+ hw->buffer_spec_index = 0;
+
+ if (hw->buffer_spec_index == 0)
+ hw->max_one_mv_buffer_size =
+ (get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_SC2) ?
+ MAX_ONE_MV_BUFFER_SIZE_1080P : MAX_ONE_MV_BUFFER_SIZE_1080P_TM2REVB;
+ else if (hw->buffer_spec_index == 1)
+ hw->max_one_mv_buffer_size =
+ (get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_SC2) ?
+ MAX_ONE_MV_BUFFER_SIZE_4K : MAX_ONE_MV_BUFFER_SIZE_4K_TM2REVB;
+ else
+ hw->max_one_mv_buffer_size =
+ (get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_SC2) ?
+ MAX_ONE_MV_BUFFER_SIZE_8K : MAX_ONE_MV_BUFFER_SIZE_8K_TM2REVB;
+
+ p_buf_info = &aom_workbuff_spec[hw->buffer_spec_index];
+ work_buf_size = (p_buf_info->end_adr - p_buf_info->start_adr
+ + 0xffff) & (~0xffff);
+ av1_print(hw, 0,
+ "vdec_is_support_4k() %d max_pic_w %d max_pic_h %d buffer_spec_index %d work_buf_size 0x%x\n",
+ vdec_is_support_4k(), hw->max_pic_w, hw->max_pic_h,
+ hw->buffer_spec_index, work_buf_size);
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ hw->platform_dev = pdev;
+ platform_set_drvdata(pdev, pdata);
+#endif
+ hw->double_write_mode = double_write_mode;
+ hw->mmu_enable = 1;
+#ifdef AOM_AV1_MMU_DW
+ hw->dw_mmu_enable =
+ get_double_write_mode_init(hw) & 0x20 ? 1 : 0;
+#endif
+ if (amvdec_av1_mmu_init(hw) < 0) {
+ vfree(hw);
+ mutex_unlock(&vav1_mutex);
+ pr_err("av1 alloc bmmu box failed!!\n");
+ return -1;
+ }
+
+ ret = decoder_bmmu_box_alloc_buf_phy(hw->bmmu_box, WORK_SPACE_BUF_ID,
+ work_buf_size, DRIVER_NAME, &pdata->mem_start);
+ if (ret < 0) {
+ uninit_mmu_buffers(hw);
+ vfree(hw);
+ mutex_unlock(&vav1_mutex);
+ return ret;
+ }
+ hw->buf_size = work_buf_size;
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ hw->buf_start = pdata->mem_start;
+#else
+ if (!hw->mmu_enable)
+ hw->mc_buf_spec.buf_end = pdata->mem_start + hw->buf_size;
+
+ for (i = 0; i < WORK_BUF_SPEC_NUM; i++)
+ aom_workbuff_spec[i].start_adr = pdata->mem_start;
+#endif
+
+ if (debug) {
+ av1_print(hw, AOM_DEBUG_HW_MORE, "===AV1 decoder mem resource 0x%lx size 0x%x\n",
+ pdata->mem_start, hw->buf_size);
+ }
+
+ hw->no_head = no_head;
+#ifdef MULTI_INSTANCE_SUPPORT
+ hw->cma_dev = pdata->cma_dev;
+#else
+ cma_dev = pdata->cma_dev;
+#endif
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ pdata->private = hw;
+ pdata->dec_status = vav1_dec_status;
+ pdata->set_isreset = vav1_set_isreset;
+ is_reset = 0;
+ if (vav1_init(pdata) < 0) {
+#else
+ if (vav1_init(hw) < 0) {
+#endif
+ av1_print(hw, 0, "\namvdec_av1 init failed.\n");
+ av1_local_uninit(hw);
+ uninit_mmu_buffers(hw);
+ vfree(hw);
+ pdata->dec_status = NULL;
+ mutex_unlock(&vav1_mutex);
+ return -ENODEV;
+ }
+ /*set the max clk for smooth playing...*/
+ hevc_source_changed(VFORMAT_AV1, 4096, 2048, 60);
+ mutex_unlock(&vav1_mutex);
+
+ return 0;
+}
+
+static int amvdec_av1_remove(struct platform_device *pdev)
+{
+ struct AV1HW_s *hw = gHevc;
+ struct vdec_s *vdec = hw_to_vdec(hw);
+ int i;
+
+ if (debug)
+ av1_print(hw, AOM_DEBUG_HW_MORE, "amvdec_av1_remove\n");
+
+ mutex_lock(&vav1_mutex);
+
+ vav1_stop(hw);
+
+ hevc_source_changed(VFORMAT_AV1, 0, 0, 0);
+
+ if (vdec->parallel_dec == 1) {
+ for (i = 0; i < FRAME_BUFFERS; i++) {
+ vdec->free_canvas_ex(hw->common.buffer_pool->
+ frame_bufs[i].buf.y_canvas_index, vdec->id);
+ vdec->free_canvas_ex(hw->common.buffer_pool->
+ frame_bufs[i].buf.uv_canvas_index, vdec->id);
+ }
+ }
+
+#ifdef DEBUG_PTS
+ pr_info("pts missed %ld, pts hit %ld, duration %d\n",
+ hw->pts_missed, hw->pts_hit, hw->frame_dur);
+#endif
+ vfree(hw->pbi);
+ release_dblk_struct(hw);
+ vfree(hw);
+ mutex_unlock(&vav1_mutex);
+
+ return 0;
+}
+
+/****************************************/
+#ifdef CONFIG_PM
+static int av1_suspend(struct device *dev)
+{
+ amhevc_suspend(to_platform_device(dev), dev->power.power_state);
+ return 0;
+}
+
+static int av1_resume(struct device *dev)
+{
+ amhevc_resume(to_platform_device(dev));
+ return 0;
+}
+
+static const struct dev_pm_ops av1_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(av1_suspend, av1_resume)
+};
+#endif
+
+static struct platform_driver amvdec_av1_driver = {
+ .probe = amvdec_av1_probe,
+ .remove = amvdec_av1_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &av1_pm_ops,
+#endif
+ }
+};
+
+static struct codec_profile_t amvdec_av1_profile = {
+#ifdef DEBUG_USE_VP9_DEVICE_NAME
+ .name = "vp9",
+#else
+ .name = "av1",
+#endif
+ .profile = ""
+};
+
+static struct codec_profile_t amvdec_av1_profile_mult;
+
+static unsigned int get_data_check_sum
+ (struct AV1HW_s *hw, int size)
+{
+ 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;
+
+ sum = crc32_le(0, data, size);
+
+ if (!hw->chunk->block->is_mapped)
+ codec_mm_unmap_phyaddr(data);
+ return sum;
+}
+
+static void dump_data(struct AV1HW_s *hw, int size)
+{
+ int jj;
+ u8 *data = NULL;
+ int padding_size = hw->chunk->offset &
+ (VDEC_FIFO_ALIGN - 1);
+
+ 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;
+
+ av1_print(hw, 0, "padding: ");
+ for (jj = padding_size; jj > 0; jj--)
+ av1_print_cont(hw,
+ 0,
+ "%02x ", *(data - jj));
+ av1_print_cont(hw, 0, "data adr %p\n",
+ data);
+
+ for (jj = 0; jj < size; jj++) {
+ if ((jj & 0xf) == 0)
+ av1_print(hw,
+ 0,
+ "%06x:", jj);
+ av1_print_cont(hw,
+ 0,
+ "%02x ", data[jj]);
+ if (((jj + 1) & 0xf) == 0)
+ av1_print(hw,
+ 0,
+ "\n");
+ }
+ av1_print(hw,
+ 0,
+ "\n");
+
+ if (!hw->chunk->block->is_mapped)
+ codec_mm_unmap_phyaddr(data);
+}
+
+static void av1_work(struct work_struct *work)
+{
+ struct AV1HW_s *hw = container_of(work,
+ struct AV1HW_s, work);
+ struct vdec_s *vdec = hw_to_vdec(hw);
+ /* finished decoding one frame or error,
+ * notify vdec core to switch context
+ */
+ av1_print(hw, PRINT_FLAG_VDEC_DETAIL,
+ "%s dec_result %d %x %x %x\n",
+ __func__,
+ hw->dec_result,
+ READ_VREG(HEVC_STREAM_LEVEL),
+ READ_VREG(HEVC_STREAM_WR_PTR),
+ READ_VREG(HEVC_STREAM_RD_PTR));
+ 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) {
+ av1_print(hw, 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, hw->chunk);
+ vdec_clean_input(vdec);
+ }
+
+ if (get_free_buf_count(hw) >=
+ run_ready_min_buf_num) {
+ int r;
+ int decode_size;
+ r = vdec_prepare_input(vdec, &hw->chunk);
+ if (r < 0) {
+ hw->dec_result = DEC_RESULT_GET_DATA_RETRY;
+
+ av1_print(hw,
+ PRINT_FLAG_VDEC_DETAIL,
+ "amvdec_vh265: Insufficient data\n");
+
+ vdec_schedule_work(&hw->work);
+ return;
+ }
+ hw->dec_result = DEC_RESULT_NONE;
+ av1_print(hw, PRINT_FLAG_VDEC_STATUS,
+ "%s: chunk size 0x%x sum 0x%x\n",
+ __func__, r,
+ (debug & PRINT_FLAG_VDEC_STATUS) ?
+ get_data_check_sum(hw, r) : 0
+ );
+
+ if (debug & PRINT_FLAG_VDEC_DATA)
+ dump_data(hw, hw->chunk->size);
+
+ decode_size = hw->chunk->size +
+ (hw->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, HEVC_ACTION_DONE);
+
+ start_process_time(hw);
+
+ } else {
+ hw->dec_result = DEC_RESULT_GET_DATA_RETRY;
+
+ av1_print(hw, PRINT_FLAG_VDEC_DETAIL,
+ "amvdec_vh265: Insufficient data\n");
+
+ vdec_schedule_work(&hw->work);
+ }
+ return;
+ } else if (hw->dec_result == DEC_RESULT_DONE) {
+ /* if (!hw->ctx_valid)
+ hw->ctx_valid = 1; */
+ hw->result_done_count++;
+ hw->process_state = PROC_STATE_INIT;
+
+ av1_print(hw, PRINT_FLAG_VDEC_STATUS,
+ "%s (===> %d) dec_result %d (%d) %x %x %x shiftbytes 0x%x decbytes 0x%x\n",
+ __func__,
+ hw->frame_count,
+ hw->dec_result,
+ hw->result_done_count,
+ 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) -
+ hw->start_shift_bytes
+ );
+ vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk);
+ } 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->dec_result = DEC_RESULT_EOS;
+ vdec_schedule_work(&hw->work);
+ return;
+ }
+ } else if (hw->dec_result == DEC_RESULT_EOS) {
+ av1_print(hw, PRINT_FLAG_VDEC_STATUS,
+ "%s: end of stream\n",
+ __func__);
+ hw->eos = 1;
+ av1_postproc(hw);
+
+ notify_v4l_eos(hw_to_vdec(hw));
+
+ vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk);
+ } else if (hw->dec_result == DEC_RESULT_FORCE_EXIT) {
+ av1_print(hw, PRINT_FLAG_VDEC_STATUS,
+ "%s: force exit\n",
+ __func__);
+ if (hw->stat & STAT_VDEC_RUN) {
+ amhevc_stop();
+ hw->stat &= ~STAT_VDEC_RUN;
+ }
+
+ if (hw->stat & STAT_ISR_REG) {
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (!hw->m_ins_flag)
+#endif
+ WRITE_VREG(HEVC_ASSIST_MBOX0_MASK, 0);
+ vdec_free_irq(VDEC_IRQ_0, (void *)hw);
+ hw->stat &= ~STAT_ISR_REG;
+ }
+ }
+ if (hw->stat & STAT_VDEC_RUN) {
+ amhevc_stop();
+ hw->stat &= ~STAT_VDEC_RUN;
+ }
+
+ if (hw->stat & STAT_TIMER_ARM) {
+ del_timer_sync(&hw->timer);
+ hw->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(hw_to_vdec(hw), CORE_MASK_VDEC_1
+ | CORE_MASK_HEVC);
+ trigger_schedule(hw);
+}
+
+static int av1_hw_ctx_restore(struct AV1HW_s *hw)
+{
+ vav1_prot_init(hw, HW_MASK_FRONT | HW_MASK_BACK);
+ return 0;
+}
+static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask)
+{
+ struct AV1HW_s *hw =
+ (struct AV1HW_s *)vdec->private;
+ int tvp = vdec_secure(hw_to_vdec(hw)) ?
+ CODEC_MM_FLAGS_TVP : 0;
+ unsigned long ret = 0;
+
+ if (!hw->pic_list_init_done2 || hw->eos)
+ return ret;
+
+ if (!hw->first_sc_checked && hw->mmu_enable) {
+ int size = decoder_mmu_box_sc_check(hw->mmu_box, tvp);
+
+ hw->first_sc_checked = 1;
+ av1_print(hw, 0, "av1 cached=%d need_size=%d speed= %d ms\n",
+ size, (hw->need_cache_size >> PAGE_SHIFT),
+ (int)(get_jiffies_64() - hw->sc_start_time) * 1000/HZ);
+#ifdef AOM_AV1_MMU_DW
+ /*!!!!!! To do ... */
+ if (hw->dw_mmu_enable) {
+
+ }
+#endif
+ }
+
+ if (get_free_buf_count(hw) >=
+ run_ready_min_buf_num) {
+ if (vdec->parallel_dec == 1)
+ ret = CORE_MASK_HEVC;
+ else
+ ret = CORE_MASK_VDEC_1 | CORE_MASK_HEVC;
+ }
+
+ 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.in < hw->used_buf_num) &&
+ v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) <
+ run_ready_min_buf_num)
+ ret = 0;
+ } else {
+ if (ctx->v4l_resolution_change)
+ ret = 0;
+ }
+ } else if (ctx->cap_pool.in < ctx->dpb_size) {
+ if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) <
+ run_ready_min_buf_num)
+ ret = 0;
+ }
+ }
+
+ if (ret)
+ not_run_ready[hw->index] = 0;
+ else
+ not_run_ready[hw->index]++;
+
+ /*av1_print(hw,
+ PRINT_FLAG_VDEC_DETAIL, "%s mask %lx=>%lx\r\n",
+ __func__, mask, ret);*/
+ return ret;
+}
+
+static void av1_frame_mode_pts_save(struct AV1HW_s *hw)
+{
+ u64 i, valid_pts_diff_cnt, pts_diff_sum;
+ u64 in_pts_diff, last_valid_pts_diff, calc_dur;
+
+ if (hw->chunk == NULL)
+ return;
+ /* no return when first pts is 0 */
+ if (hw->first_pts_index) {
+ /* filtration pts 0 and continuous same pts */
+ if ((hw->chunk->pts == 0) ||
+ (hw->frame_mode_pts_save[0] == hw->chunk->pts))
+ return;
+
+ /* fps change, frame dur change to lower or higher,
+ * can't find closed pts in saved pool */
+ if ((hw->dur_recalc_flag) ||
+ (hw->last_pts > hw->chunk->pts)) {
+ hw->av1_first_pts_ready = 0;
+ hw->first_pts_index = 0;
+ hw->get_frame_dur = 0;
+ hw->dur_recalc_flag = 0;
+ memset(hw->frame_mode_pts_save, 0,
+ sizeof(hw->frame_mode_pts_save));
+ memset(hw->frame_mode_pts64_save, 0,
+ sizeof(hw->frame_mode_pts64_save));
+ /*v4l use*/
+ memset(hw->frame_mode_timestamp_save, 0,
+ sizeof(hw->frame_mode_timestamp_save));
+ }
+ }
+ av1_print(hw, AV1_DEBUG_OUT_PTS,
+ "run_front: pts %d, pts64 %lld, ts: %llu\n",
+ hw->chunk->pts, hw->chunk->pts64, hw->chunk->timestamp);
+
+ for (i = (FRAME_BUFFERS - 1); i > 0; i--) {
+ hw->frame_mode_pts_save[i] = hw->frame_mode_pts_save[i - 1];
+ hw->frame_mode_pts64_save[i] = hw->frame_mode_pts64_save[i - 1];
+ hw->frame_mode_timestamp_save[i] = hw->frame_mode_timestamp_save[i - 1];
+ }
+ hw->frame_mode_pts_save[0] = hw->chunk->pts;
+ hw->frame_mode_pts64_save[0] = hw->chunk->pts64;
+ hw->frame_mode_timestamp_save[0] = hw->chunk->timestamp;
+ if (hw->first_pts_index < ARRAY_SIZE(hw->frame_mode_pts_save))
+ hw->first_pts_index++;
+ /* frame duration check, vdec_secure return for nts problem */
+ if ((!hw->first_pts_index) || hw->get_frame_dur || vdec_secure(hw_to_vdec(hw)))
+ return;
+ valid_pts_diff_cnt = 0;
+ pts_diff_sum = 0;
+
+ for (i = 0; i < FRAME_BUFFERS - 1; i++) {
+ if (hw->is_used_v4l) {
+ if ((hw->frame_mode_timestamp_save[i] > hw->frame_mode_timestamp_save[i + 1]) &&
+ (hw->frame_mode_timestamp_save[i + 1] != 0))
+ in_pts_diff = hw->frame_mode_timestamp_save[i]
+ - hw->frame_mode_timestamp_save[i + 1];
+ else
+ in_pts_diff = 0;
+ } else {
+ if ((hw->frame_mode_pts_save[i] > hw->frame_mode_pts_save[i + 1]) &&
+ (hw->frame_mode_pts_save[i + 1] != 0))
+ in_pts_diff = hw->frame_mode_pts_save[i]
+ - hw->frame_mode_pts_save[i + 1];
+ else
+ in_pts_diff = 0;
+ }
+
+ if (in_pts_diff < 100 ||
+ (valid_pts_diff_cnt && (!close_to(in_pts_diff, last_valid_pts_diff, 100))))
+ in_pts_diff = 0;
+ else {
+ last_valid_pts_diff = in_pts_diff;
+ valid_pts_diff_cnt++;
+ }
+
+ pts_diff_sum += in_pts_diff;
+ }
+
+ if (!valid_pts_diff_cnt) {
+ av1_print(hw, 0, "checked no avaliable pts\n");
+ return;
+ }
+
+ calc_dur = PTS2DUR(pts_diff_sum / valid_pts_diff_cnt);
+ if ((!close_to(calc_dur, hw->frame_dur, 10)) &&
+ (calc_dur < 9601) && (calc_dur > 800)) {
+ av1_print(hw, 0, "change to calc dur %lld, old dur %d\n", calc_dur, hw->frame_dur);
+ hw->frame_dur = calc_dur;
+ hw->get_frame_dur = true;
+ } else {
+ if (hw->frame_count > FRAME_BUFFERS)
+ hw->get_frame_dur = true;
+ }
+
+ if (hw->is_used_v4l) {
+ hw->timestamp_duration =
+ pts_diff_sum / valid_pts_diff_cnt;
+ }
+}
+
+static void run_front(struct vdec_s *vdec)
+{
+ struct AV1HW_s *hw =
+ (struct AV1HW_s *)vdec->private;
+ int ret, size;
+
+ run_count[hw->index]++;
+ /* hw->chunk = vdec_prepare_input(vdec); */
+ hevc_reset_core(vdec);
+
+ size = vdec_prepare_input(vdec, &hw->chunk);
+ if (size < 0) {
+ input_empty[hw->index]++;
+
+ hw->dec_result = DEC_RESULT_AGAIN;
+
+ av1_print(hw, PRINT_FLAG_VDEC_DETAIL,
+ "ammvdec_av1: Insufficient data\n");
+
+ vdec_schedule_work(&hw->work);
+ return;
+ }
+ input_empty[hw->index] = 0;
+ hw->dec_result = DEC_RESULT_NONE;
+ hw->start_shift_bytes = READ_VREG(HEVC_SHIFT_BYTE_COUNT);
+
+ av1_frame_mode_pts_save(hw);
+ if (debug & PRINT_FLAG_VDEC_STATUS) {
+ if (vdec_frame_based(vdec) && hw->chunk && !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;
+
+ //print_hex_debug(data, size, size > 64 ? 64 : size);
+ av1_print(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]);
+ av1_print(hw, 0,
+ "%s frm cnt (%d): chunk (0x%x 0x%x) (%x %x %x %x %x) bytes 0x%x\n",
+ __func__, hw->frame_count, hw->chunk->size, hw->chunk->offset,
+ 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),
+ hw->start_shift_bytes);
+
+ if (!hw->chunk->block->is_mapped)
+ codec_mm_unmap_phyaddr(data);
+ } else {
+ av1_print(hw, 0,
+ "%s (%d): size 0x%x (0x%x 0x%x) (%x %x %x %x %x) bytes 0x%x\n",
+ __func__,
+ hw->frame_count, size,
+ hw->chunk ? hw->chunk->size : 0,
+ hw->chunk ? hw->chunk->offset : 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),
+ hw->start_shift_bytes);
+ }
+ }
+ if (vdec->mc_loaded) {
+ /*firmware have load before,
+ and not changes to another.
+ ignore reload.
+ */
+ } else {
+#ifdef DEBUG_USE_VP9_DEVICE_NAME
+ ret = amhevc_loadmc_ex(VFORMAT_VP9, NULL, hw->fw->data);
+#else
+ ret = amhevc_loadmc_ex(VFORMAT_AV1, NULL, hw->fw->data);
+#endif
+ if (ret < 0) {
+ amhevc_disable();
+ av1_print(hw, PRINT_FLAG_ERROR,
+ "AV1: 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_loaded = 1;
+#ifdef DEBUG_USE_VP9_DEVICE_NAME
+ vdec->mc_type = VFORMAT_VP9;
+#else
+ vdec->mc_type = VFORMAT_AV1;
+#endif
+ }
+
+ if (av1_hw_ctx_restore(hw) < 0) {
+ vdec_schedule_work(&hw->work);
+ return;
+ }
+
+ vdec_enable_input(vdec);
+
+ WRITE_VREG(HEVC_DEC_STATUS_REG, HEVC_ACTION_DONE);
+
+ if (vdec_frame_based(vdec)) {
+ if (debug & PRINT_FLAG_VDEC_DATA)
+ dump_data(hw, hw->chunk->size);
+
+ WRITE_VREG(HEVC_SHIFT_BYTE_COUNT, 0);
+ size = hw->chunk->size +
+ (hw->chunk->offset & (VDEC_FIFO_ALIGN - 1));
+ }
+ hw->data_size = size;
+ WRITE_VREG(HEVC_DECODE_SIZE, size);
+ WRITE_VREG(HEVC_DECODE_COUNT, hw->result_done_count);
+ WRITE_VREG(LMEM_DUMP_ADR, (u32)hw->lmem_phy_addr);
+ if (hw->config_next_ref_info_flag)
+ config_next_ref_info_hw(hw);
+ hw->config_next_ref_info_flag = 0;
+ hw->init_flag = 1;
+
+ av1_print(hw, PRINT_FLAG_VDEC_DETAIL,
+ "%s: start hw (%x %x %x) HEVC_DECODE_SIZE 0x%x\n",
+ __func__,
+ READ_VREG(HEVC_DEC_STATUS_REG),
+ READ_VREG(HEVC_MPC_E),
+ READ_VREG(HEVC_MPSR),
+ READ_VREG(HEVC_DECODE_SIZE));
+
+ start_process_time(hw);
+ mod_timer(&hw->timer, jiffies);
+ hw->stat |= STAT_TIMER_ARM;
+ hw->stat |= STAT_ISR_REG;
+ amhevc_start();
+ hw->stat |= STAT_VDEC_RUN;
+}
+
+static void run(struct vdec_s *vdec, unsigned long mask,
+ void (*callback)(struct vdec_s *, void *), void *arg)
+{
+ struct AV1HW_s *hw =
+ (struct AV1HW_s *)vdec->private;
+
+ av1_print(hw,
+ PRINT_FLAG_VDEC_DETAIL, "%s mask %lx\r\n",
+ __func__, mask);
+
+ run_count[hw->index]++;
+ hw->vdec_cb_arg = arg;
+ hw->vdec_cb = callback;
+ run_front(vdec);
+}
+
+static void av1_decode_ctx_reset(struct AV1HW_s *hw)
+{
+ struct AV1_Common_s *const cm = &hw->common;
+ struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs;
+ int i;
+
+ for (i = 0; i < FRAME_BUFFERS; ++i) {
+ frame_bufs[i].ref_count = 0;
+ frame_bufs[i].buf.vf_ref = 0;
+ frame_bufs[i].buf.decode_idx = 0;
+ frame_bufs[i].buf.cma_alloc_addr = 0;
+ frame_bufs[i].buf.index = i;
+ frame_bufs[i].buf.BUF_index = -1;
+ frame_bufs[i].buf.mv_buf_index = -1;
+ }
+
+ for (i = 0; i < MV_BUFFER_NUM; i++) {
+ if (hw->m_mv_BUF[i].start_adr) {
+ if (mv_buf_dynamic_alloc) {
+ decoder_bmmu_box_free_idx(hw->bmmu_box, MV_BUFFER_IDX(i));
+ hw->m_mv_BUF[i].start_adr = 0;
+ hw->m_mv_BUF[i].size = 0;
+ }
+ hw->m_mv_BUF[i].used_flag = 0;
+ }
+ }
+
+ hw->one_compressed_data_done = 0;
+ hw->config_next_ref_info_flag = 0;
+ hw->init_flag = 0;
+ hw->first_sc_checked = 0;
+ hw->fatal_error = 0;
+ hw->show_frame_num = 0;
+ hw->postproc_done = 0;
+ hw->process_busy = 0;
+ hw->process_state = 0;
+ hw->frame_decoded = 0;
+ hw->eos = 0;
+}
+
+static void reset(struct vdec_s *vdec)
+{
+ struct AV1HW_s *hw =
+ (struct AV1HW_s *)vdec->private;
+
+ cancel_work_sync(&hw->work);
+ cancel_work_sync(&hw->set_clk_work);
+
+ if (hw->stat & STAT_VDEC_RUN) {
+ amhevc_stop();
+ hw->stat &= ~STAT_VDEC_RUN;
+ }
+
+ if (hw->stat & STAT_TIMER_ARM) {
+ del_timer_sync(&hw->timer);
+ hw->stat &= ~STAT_TIMER_ARM;
+ }
+
+ reset_process_time(hw);
+
+ av1_bufmgr_ctx_reset(hw->pbi, &hw->av1_buffer_pool, &hw->common);
+ hw->pbi->private_data = hw;
+
+ av1_local_uninit(hw);
+ if (vav1_local_init(hw) < 0)
+ av1_print(hw, 0, "%s local_init failed \r\n", __func__);
+
+ av1_decode_ctx_reset(hw);
+
+ av1_print(hw, PRINT_FLAG_VDEC_DETAIL, "%s\r\n", __func__);
+}
+
+static irqreturn_t av1_irq_cb(struct vdec_s *vdec, int irq)
+{
+ struct AV1HW_s *hw =
+ (struct AV1HW_s *)vdec->private;
+ return vav1_isr(0, hw);
+}
+
+static irqreturn_t av1_threaded_irq_cb(struct vdec_s *vdec, int irq)
+{
+ struct AV1HW_s *hw =
+ (struct AV1HW_s *)vdec->private;
+ return vav1_isr_thread_fn(0, hw);
+}
+
+static void av1_dump_state(struct vdec_s *vdec)
+{
+ struct AV1HW_s *hw =
+ (struct AV1HW_s *)vdec->private;
+ struct AV1_Common_s *const cm = &hw->common;
+ int i;
+ av1_print(hw, 0, "====== %s\n", __func__);
+
+ av1_print(hw, 0,
+ "width/height (%d/%d), used_buf_num %d\n",
+ cm->width,
+ cm->height,
+ hw->used_buf_num
+ );
+
+ av1_print(hw, 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 low_latency %d no_head %d \n",
+ input_frame_based(vdec),
+ hw->eos,
+ hw->dec_result,
+ decode_frame_count[hw->index],
+ display_frame_count[hw->index],
+ run_count[hw->index],
+ not_run_ready[hw->index],
+ input_empty[hw->index],
+ hw->low_latency_flag,
+ hw->no_head
+ );
+
+ 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);
+ av1_print(hw, 0,
+ "\nreceiver(%s) state %d\n",
+ vdec->vf_provider_name,
+ state);
+ }
+
+ av1_print(hw, 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(&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,
+ get_free_buf_count(hw),
+ run_ready_min_buf_num
+ );
+
+ dump_pic_list(hw);
+
+ for (i = 0; i < MAX_BUF_NUM; i++) {
+ av1_print(hw, 0,
+ "mv_Buf(%d) start_adr 0x%lx size 0x%x used %d\n",
+ i,
+ hw->m_mv_BUF[i].start_adr,
+ hw->m_mv_BUF[i].size,
+ hw->m_mv_BUF[i].used_flag);
+ }
+
+ av1_print(hw, 0,
+ "HEVC_DEC_STATUS_REG=0x%x\n",
+ READ_VREG(HEVC_DEC_STATUS_REG));
+ av1_print(hw, 0,
+ "HEVC_MPC_E=0x%x\n",
+ READ_VREG(HEVC_MPC_E));
+ av1_print(hw, 0,
+ "DECODE_MODE=0x%x\n",
+ READ_VREG(DECODE_MODE));
+ av1_print(hw, 0,
+ "NAL_SEARCH_CTL=0x%x\n",
+ READ_VREG(NAL_SEARCH_CTL));
+ av1_print(hw, 0,
+ "HEVC_PARSER_LCU_START=0x%x\n",
+ READ_VREG(HEVC_PARSER_LCU_START));
+ av1_print(hw, 0,
+ "HEVC_DECODE_SIZE=0x%x\n",
+ READ_VREG(HEVC_DECODE_SIZE));
+ av1_print(hw, 0,
+ "HEVC_SHIFT_BYTE_COUNT=0x%x\n",
+ READ_VREG(HEVC_SHIFT_BYTE_COUNT));
+ av1_print(hw, 0,
+ "HEVC_STREAM_START_ADDR=0x%x\n",
+ READ_VREG(HEVC_STREAM_START_ADDR));
+ av1_print(hw, 0,
+ "HEVC_STREAM_END_ADDR=0x%x\n",
+ READ_VREG(HEVC_STREAM_END_ADDR));
+ av1_print(hw, 0,
+ "HEVC_STREAM_LEVEL=0x%x\n",
+ READ_VREG(HEVC_STREAM_LEVEL));
+ av1_print(hw, 0,
+ "HEVC_STREAM_WR_PTR=0x%x\n",
+ READ_VREG(HEVC_STREAM_WR_PTR));
+ av1_print(hw, 0,
+ "HEVC_STREAM_RD_PTR=0x%x\n",
+ READ_VREG(HEVC_STREAM_RD_PTR));
+ av1_print(hw, 0,
+ "PARSER_VIDEO_RP=0x%x\n",
+ STBUF_READ(&vdec->vbuf, get_rp));
+ av1_print(hw, 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 (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;
+ av1_print(hw, 0,
+ "frame data size 0x%x\n",
+ hw->chunk->size);
+ for (jj = 0; jj < hw->chunk->size; jj++) {
+ if ((jj & 0xf) == 0)
+ av1_print(hw, 0,
+ "%06x:", jj);
+ av1_print_cont(hw, 0,
+ "%02x ", data[jj]);
+ if (((jj + 1) & 0xf) == 0)
+ av1_print_cont(hw, 0,
+ "\n");
+ }
+
+ if (!hw->chunk->block->is_mapped)
+ codec_mm_unmap_phyaddr(data);
+ }
+ }
+
+}
+
+static int ammvdec_av1_probe(struct platform_device *pdev)
+{
+ struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
+ int ret;
+ int config_val;
+ struct vframe_content_light_level_s content_light_level;
+ struct vframe_master_display_colour_s vf_dp;
+ u32 work_buf_size;
+ struct BuffInfo_s *p_buf_info;
+
+ struct BUF_s BUF[MAX_BUF_NUM];
+ struct AV1HW_s *hw = NULL;
+ pr_debug("%s\n", __func__);
+
+ if (!(is_cpu_tm2_revb() ||
+ (get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_TM2))) {
+ pr_err("unsupport av1, cpu %d, is_tm2_revb %d\n",
+ get_cpu_major_id(), is_cpu_tm2_revb());
+ return -EFAULT;
+ }
+
+ if (pdata == NULL) {
+ av1_print(hw, 0, "\nammvdec_av1 memory resource undefined.\n");
+ return -EFAULT;
+ }
+ memset(&vf_dp, 0, sizeof(struct vframe_master_display_colour_s));
+
+ hw = vzalloc(sizeof(struct AV1HW_s));
+ if (hw == NULL) {
+ av1_print(hw, 0, "\nammvdec_av1 device data allocation failed\n");
+ return -ENOMEM;
+ }
+
+ if (init_dblk_struc(hw) < 0) {
+ av1_print(hw, 0, "\nammvdec_av1 device data allocation failed\n");
+ vfree(hw);
+ return -ENOMEM;
+ }
+
+ hw->pbi = av1_decoder_create(&hw->av1_buffer_pool, &hw->common); //&aom_decoder;
+ if (hw->pbi == NULL) {
+ av1_print(hw, 0, "\nammvdec_av1 device data allocation failed\n");
+ release_dblk_struct(hw);
+ vfree(hw);
+ return -ENOMEM;
+ }
+
+ hw->pbi->private_data = hw;
+ /* the ctx from v4l2 driver. */
+ hw->v4l2_ctx = pdata->private;
+
+ pdata->private = hw;
+ pdata->dec_status = vav1_dec_status;
+ /* pdata->set_trickmode = set_trickmode; */
+ pdata->run_ready = run_ready;
+ pdata->run = run;
+ pdata->reset = reset;
+ pdata->irq_handler = av1_irq_cb;
+ pdata->threaded_irq_handler = av1_threaded_irq_cb;
+ pdata->dump_state = av1_dump_state;
+
+ memcpy(&BUF[0], &hw->m_BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM);
+ memcpy(&hw->m_BUF[0], &BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM);
+
+ hw->index = pdev->id;
+
+ snprintf(hw->vdec_name, sizeof(hw->vdec_name),
+ "av1-%d", hw->index);
+ snprintf(hw->pts_name, sizeof(hw->pts_name),
+ "%s-pts", hw->vdec_name);
+ snprintf(hw->new_q_name, sizeof(hw->new_q_name),
+ "%s-newframe_q", hw->vdec_name);
+ snprintf(hw->disp_q_name, sizeof(hw->disp_q_name),
+ "%s-dispframe_q", hw->vdec_name);
+ if (pdata->use_vfm_path)
+ snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE,
+ VFM_DEC_PROVIDER_NAME);
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ else if (vdec_dual(pdata)) {
+ struct AV1HW_s *hevc_pair = NULL;
+
+ if (dv_toggle_prov_name) /*debug purpose*/
+ snprintf(pdata->vf_provider_name,
+ VDEC_PROVIDER_NAME_SIZE,
+ (pdata->master) ? VFM_DEC_DVBL_PROVIDER_NAME :
+ VFM_DEC_DVEL_PROVIDER_NAME);
+ else
+ snprintf(pdata->vf_provider_name,
+ VDEC_PROVIDER_NAME_SIZE,
+ (pdata->master) ? VFM_DEC_DVEL_PROVIDER_NAME :
+ VFM_DEC_DVBL_PROVIDER_NAME);
+ if (pdata->master)
+ hevc_pair = (struct AV1HW_s *)pdata->master->private;
+ else if (pdata->slave)
+ hevc_pair = (struct AV1HW_s *)pdata->slave->private;
+
+ if (hevc_pair)
+ hw->shift_byte_count_lo = hevc_pair->shift_byte_count_lo;
+ }
+#endif
+ else
+ snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE,
+ MULTI_INSTANCE_PROVIDER_NAME ".%02x", pdev->id & 0xff);
+
+ vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name,
+ &vav1_vf_provider, hw);
+
+ hw->provider_name = pdata->vf_provider_name;
+ platform_set_drvdata(pdev, pdata);
+
+ hw->platform_dev = pdev;
+ hw->video_signal_type = 0;
+ hw->m_ins_flag = 1;
+
+ if (pdata->sys_info) {
+ hw->vav1_amstream_dec_info = *pdata->sys_info;
+ if ((unsigned long) hw->vav1_amstream_dec_info.param
+ & 0x08) {
+ hw->low_latency_flag = 1;
+ } else
+ hw->low_latency_flag = 0;
+ } else {
+ hw->vav1_amstream_dec_info.width = 0;
+ hw->vav1_amstream_dec_info.height = 0;
+ hw->vav1_amstream_dec_info.rate = 30;
+ }
+
+ if ((debug & IGNORE_PARAM_FROM_CONFIG) == 0 &&
+ pdata->config_len) {
+#ifdef MULTI_INSTANCE_SUPPORT
+ int av1_buf_width = 0;
+ int av1_buf_height = 0;
+ /*use ptr config for doubel_write_mode, etc*/
+ av1_print(hw, 0, "pdata->config=%s\n", pdata->config);
+ if (get_config_int(pdata->config, "av1_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, "save_buffer_mode",
+ &config_val) == 0)
+ hw->save_buffer_mode = config_val;
+ else
+ hw->save_buffer_mode = 0;
+ if (get_config_int(pdata->config, "av1_buf_width",
+ &config_val) == 0) {
+ av1_buf_width = config_val;
+ }
+ if (get_config_int(pdata->config, "av1_buf_height",
+ &config_val) == 0) {
+ av1_buf_height = config_val;
+ }
+
+ if (get_config_int(pdata->config, "no_head",
+ &config_val) == 0)
+ hw->no_head = config_val;
+ else
+ hw->no_head = no_head;
+
+ /*use ptr config for max_pic_w, etc*/
+ if (get_config_int(pdata->config, "av1_max_pic_w",
+ &config_val) == 0) {
+ hw->max_pic_w = config_val;
+ }
+ if (get_config_int(pdata->config, "av1_max_pic_h",
+ &config_val) == 0) {
+ hw->max_pic_h = config_val;
+ }
+ if ((hw->max_pic_w * hw->max_pic_h)
+ < (av1_buf_width * av1_buf_height)) {
+ hw->max_pic_w = av1_buf_width;
+ hw->max_pic_h = av1_buf_height;
+ av1_print(hw, 0, "use buf resolution\n");
+ }
+
+ 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_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->dynamic_buf_num_margin = config_val;
+
+ if (get_config_int(pdata->config,
+ "parm_v4l_canvas_mem_mode",
+ &config_val) == 0)
+ hw->mem_map_mode = config_val;
+
+ if (get_config_int(pdata->config,
+ "parm_v4l_low_latency_mode",
+ &config_val) == 0)
+ hw->low_latency_flag = config_val;
+
+#endif
+ 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;
+ hw->video_signal_type = (1 << 29)
+ | (5 << 26) /* unspecified */
+ | (0 << 25) /* limit */
+ | (1 << 24) /* color available */
+ | (9 << 16) /* 2020 */
+ | (16 << 8) /* 2084 */
+ | (9 << 0); /* 2020 */
+ }
+ hw->vf_dp = vf_dp;
+ } else {
+ /*hw->vav1_amstream_dec_info.width = 0;
+ hw->vav1_amstream_dec_info.height = 0;
+ hw->vav1_amstream_dec_info.rate = 30;*/
+ if (hw->vav1_amstream_dec_info.width)
+ hw->max_pic_w = hw->vav1_amstream_dec_info.width;
+ else
+ hw->max_pic_w = 8192;
+
+ if (hw->vav1_amstream_dec_info.height)
+ hw->max_pic_h = hw->vav1_amstream_dec_info.height;
+ else
+ hw->max_pic_h = 4608;
+ hw->double_write_mode = double_write_mode;
+ }
+
+ if (!hw->is_used_v4l) {
+ hw->mem_map_mode = mem_map_mode;
+ }
+
+ if (is_oversize(hw->max_pic_w, hw->max_pic_h)) {
+ pr_err("over size: %dx%d, probe failed\n",
+ hw->max_pic_w, hw->max_pic_h);
+ return -1;
+ }
+ if (force_bufspec) {
+ hw->buffer_spec_index = force_bufspec & 0xf;
+ pr_info("force buffer spec %d\n", force_bufspec & 0xf);
+ } else if (vdec_is_support_4k()) {
+ if (IS_8K_SIZE(hw->max_pic_w, hw->max_pic_h))
+ hw->buffer_spec_index = 2;
+ else if (IS_4K_SIZE(hw->max_pic_w, hw->max_pic_h))
+ hw->buffer_spec_index = 1;
+ else
+ hw->buffer_spec_index = 0;
+ } else
+ hw->buffer_spec_index = 0;
+
+ if (hw->buffer_spec_index == 0)
+ hw->max_one_mv_buffer_size =
+ (get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_SC2) ?
+ MAX_ONE_MV_BUFFER_SIZE_1080P : MAX_ONE_MV_BUFFER_SIZE_1080P_TM2REVB;
+ else if (hw->buffer_spec_index == 1)
+ hw->max_one_mv_buffer_size =
+ (get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_SC2) ?
+ MAX_ONE_MV_BUFFER_SIZE_4K : MAX_ONE_MV_BUFFER_SIZE_4K_TM2REVB;
+ else
+ hw->max_one_mv_buffer_size =
+ (get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_SC2) ?
+ MAX_ONE_MV_BUFFER_SIZE_8K : MAX_ONE_MV_BUFFER_SIZE_8K_TM2REVB;
+
+ p_buf_info = &aom_workbuff_spec[hw->buffer_spec_index];
+ work_buf_size = (p_buf_info->end_adr - p_buf_info->start_adr
+ + 0xffff) & (~0xffff);
+
+ av1_print(hw, 0,
+ "vdec_is_support_4k() %d max_pic_w %d max_pic_h %d buffer_spec_index %d work_buf_size 0x%x\n",
+ vdec_is_support_4k(), hw->max_pic_w, hw->max_pic_h,
+ hw->buffer_spec_index, work_buf_size);
+
+ if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_GXL ||
+ hw->double_write_mode == 0x10)
+ hw->mmu_enable = 0;
+ else
+ hw->mmu_enable = 1;
+
+ video_signal_type = hw->video_signal_type;
+
+ if (pdata->sys_info) {
+ hw->vav1_amstream_dec_info = *pdata->sys_info;
+ if ((unsigned long) hw->vav1_amstream_dec_info.param
+ & 0x08) {
+ hw->low_latency_flag = 1;
+ } else
+ hw->low_latency_flag = 0;
+ } else {
+ hw->vav1_amstream_dec_info.width = 0;
+ hw->vav1_amstream_dec_info.height = 0;
+ hw->vav1_amstream_dec_info.rate = 30;
+ }
+
+#ifdef AOM_AV1_MMU_DW
+ hw->dw_mmu_enable =
+ get_double_write_mode_init(hw) & 0x20 ? 1 : 0;
+
+#endif
+ av1_print(hw, 0,
+ "no_head %d low_latency %d\n",
+ hw->no_head, hw->low_latency_flag);
+#if 0
+ hw->buf_start = pdata->mem_start;
+ hw->buf_size = pdata->mem_end - pdata->mem_start + 1;
+#else
+ if (amvdec_av1_mmu_init(hw) < 0) {
+ pr_err("av1 alloc bmmu box failed!!\n");
+ /* devm_kfree(&pdev->dev, (void *)hw); */
+ vfree((void *)hw);
+ pdata->dec_status = NULL;
+ return -1;
+ }
+
+ hw->cma_alloc_count = PAGE_ALIGN(work_buf_size) / PAGE_SIZE;
+ ret = decoder_bmmu_box_alloc_buf_phy(hw->bmmu_box, WORK_SPACE_BUF_ID,
+ hw->cma_alloc_count * PAGE_SIZE, DRIVER_NAME,
+ &hw->cma_alloc_addr);
+ if (ret < 0) {
+ uninit_mmu_buffers(hw);
+ /* devm_kfree(&pdev->dev, (void *)hw); */
+ vfree((void *)hw);
+ pdata->dec_status = NULL;
+ return ret;
+ }
+ hw->buf_start = hw->cma_alloc_addr;
+ hw->buf_size = work_buf_size;
+#endif
+
+ hw->init_flag = 0;
+ hw->first_sc_checked = 0;
+ hw->fatal_error = 0;
+ hw->show_frame_num = 0;
+
+ if (debug) {
+ av1_print(hw, AOM_DEBUG_HW_MORE, "===AV1 decoder mem resource 0x%lx size 0x%x\n",
+ hw->buf_start,
+ hw->buf_size);
+ }
+
+ hw->cma_dev = pdata->cma_dev;
+ if (vav1_init(pdata) < 0) {
+ av1_print(hw, 0, "\namvdec_av1 init failed.\n");
+ av1_local_uninit(hw);
+ uninit_mmu_buffers(hw);
+ /* devm_kfree(&pdev->dev, (void *)hw); */
+ vfree((void *)hw);
+ pdata->dec_status = NULL;
+ return -ENODEV;
+ }
+ vdec_set_prepare_level(pdata, start_decode_buf_level);
+ hevc_source_changed(VFORMAT_AV1, 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);
+
+ hw->pic_list_init_done2 = true;
+ return 0;
+}
+
+static int ammvdec_av1_remove(struct platform_device *pdev)
+{
+ struct AV1HW_s *hw = (struct AV1HW_s *)
+ (((struct vdec_s *)(platform_get_drvdata(pdev)))->private);
+ struct vdec_s *vdec = hw_to_vdec(hw);
+ int i;
+ if (debug)
+ av1_print(hw, AOM_DEBUG_HW_MORE, "amvdec_av1_remove\n");
+
+ vmav1_stop(hw);
+
+ if (vdec->parallel_dec == 1)
+ vdec_core_release(hw_to_vdec(hw), CORE_MASK_HEVC);
+ 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 < FRAME_BUFFERS; i++) {
+ vdec->free_canvas_ex
+ (hw->common.buffer_pool->frame_bufs[i].buf.y_canvas_index,
+ vdec->id);
+ vdec->free_canvas_ex
+ (hw->common.buffer_pool->frame_bufs[i].buf.uv_canvas_index,
+ vdec->id);
+ }
+ }
+
+#ifdef DEBUG_PTS
+ pr_info("pts missed %ld, pts hit %ld, duration %d\n",
+ hw->pts_missed, hw->pts_hit, hw->frame_dur);
+#endif
+ /* devm_kfree(&pdev->dev, (void *)hw); */
+ vfree(hw->pbi);
+ release_dblk_struct(hw);
+ vfree((void *)hw);
+ return 0;
+}
+
+static struct platform_driver ammvdec_av1_driver = {
+ .probe = ammvdec_av1_probe,
+ .remove = ammvdec_av1_remove,
+ .driver = {
+ .name = MULTI_DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &av1_pm_ops,
+#endif
+ }
+};
+#endif
+static struct mconfig av1_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),
+ MC_PU32("av1_max_pic_w", &av1_max_pic_w),
+ MC_PU32("av1_max_pic_h", &av1_max_pic_h),
+};
+static struct mconfig_node av1_node;
+
+static int __init amvdec_av1_driver_init_module(void)
+{
+ //struct BuffInfo_s *p_buf_info;
+ int i;
+#ifdef BUFMGR_ONLY_OLD_CHIP
+ debug |= AOM_DEBUG_BUFMGR_ONLY;
+#endif
+ /*
+ if (vdec_is_support_4k()) {
+ p_buf_info = &aom_workbuff_spec[1];
+ } else
+ p_buf_info = &aom_workbuff_spec[0];
+
+ init_buff_spec(NULL, p_buf_info);
+ work_buf_size =
+ (p_buf_info->end_adr - p_buf_info->start_adr
+ + 0xffff) & (~0xffff);
+ */
+ for (i = 0; i < WORK_BUF_SPEC_NUM; i++)
+ init_buff_spec(NULL, &aom_workbuff_spec[i]);
+
+ pr_debug("amvdec_av1 module init\n");
+
+ error_handle_policy = 0;
+
+#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;
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (platform_driver_register(&ammvdec_av1_driver))
+ pr_err("failed to register ammvdec_av1 driver\n");
+
+#endif
+ if (platform_driver_register(&amvdec_av1_driver)) {
+ pr_err("failed to register amvdec_av1 driver\n");
+ return -ENODEV;
+ }
+
+ if ((get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_TM2) || is_cpu_tm2_revb()) {
+ amvdec_av1_profile.profile =
+ "8k, 10bit, dwrite, compressed, no_head, frame_dv";
+ } else {
+ amvdec_av1_profile.name = "av1_unsupport";
+ }
+
+ vcodec_profile_register(&amvdec_av1_profile);
+ amvdec_av1_profile_mult = amvdec_av1_profile;
+#ifdef DEBUG_USE_VP9_DEVICE_NAME
+
+ amvdec_av1_profile_mult.name = "mvp9";
+ vcodec_profile_register(&amvdec_av1_profile_mult);
+ INIT_REG_NODE_CONFIGS("media.decoder", &av1_node,
+ "vp9", av1_configs, CONFIG_FOR_RW);
+
+#else
+ amvdec_av1_profile_mult.name = "mav1";
+ vcodec_profile_register(&amvdec_av1_profile_mult);
+ INIT_REG_NODE_CONFIGS("media.decoder", &av1_node,
+ "av1", av1_configs, CONFIG_FOR_RW);
+#endif
+
+ return 0;
+}
+
+static void __exit amvdec_av1_driver_remove_module(void)
+{
+ pr_debug("amvdec_av1 module remove.\n");
+#ifdef MULTI_INSTANCE_SUPPORT
+ platform_driver_unregister(&ammvdec_av1_driver);
+#endif
+ platform_driver_unregister(&amvdec_av1_driver);
+}
+
+/****************************************/
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+module_param(force_dv_enable, uint, 0664);
+MODULE_PARM_DESC(force_dv_enable, "\n amvdec_av1 force_dv_enable\n");
+#endif
+
+module_param(bit_depth_luma, uint, 0664);
+MODULE_PARM_DESC(bit_depth_luma, "\n amvdec_av1 bit_depth_luma\n");
+
+module_param(bit_depth_chroma, uint, 0664);
+MODULE_PARM_DESC(bit_depth_chroma, "\n amvdec_av1 bit_depth_chroma\n");
+
+module_param(frame_width, uint, 0664);
+MODULE_PARM_DESC(frame_width, "\n amvdec_av1 frame_width\n");
+
+module_param(frame_height, uint, 0664);
+MODULE_PARM_DESC(frame_height, "\n amvdec_av1 frame_height\n");
+
+module_param(multi_frames_in_one_pack, uint, 0664);
+MODULE_PARM_DESC(multi_frames_in_one_pack, "\n multi_frames_in_one_pack\n");
+
+module_param(debug, uint, 0664);
+MODULE_PARM_DESC(debug, "\n amvdec_av1 debug\n");
+
+module_param(radr, uint, 0664);
+MODULE_PARM_DESC(radr, "\n radr\n");
+
+module_param(rval, uint, 0664);
+MODULE_PARM_DESC(rval, "\n rval\n");
+
+module_param(pop_shorts, uint, 0664);
+MODULE_PARM_DESC(pop_shorts, "\n rval\n");
+
+module_param(dbg_cmd, uint, 0664);
+MODULE_PARM_DESC(dbg_cmd, "\n dbg_cmd\n");
+
+module_param(dbg_skip_decode_index, uint, 0664);
+MODULE_PARM_DESC(dbg_skip_decode_index, "\n dbg_skip_decode_index\n");
+
+module_param(endian, uint, 0664);
+MODULE_PARM_DESC(endian, "\n rval\n");
+
+module_param(step, uint, 0664);
+MODULE_PARM_DESC(step, "\n amvdec_av1 step\n");
+
+module_param(decode_pic_begin, uint, 0664);
+MODULE_PARM_DESC(decode_pic_begin, "\n amvdec_av1 decode_pic_begin\n");
+
+module_param(slice_parse_begin, uint, 0664);
+MODULE_PARM_DESC(slice_parse_begin, "\n amvdec_av1 slice_parse_begin\n");
+
+module_param(i_only_flag, uint, 0664);
+MODULE_PARM_DESC(i_only_flag, "\n amvdec_av1 i_only_flag\n");
+
+module_param(low_latency_flag, uint, 0664);
+MODULE_PARM_DESC(low_latency_flag, "\n amvdec_av1 low_latency_flag\n");
+
+module_param(no_head, uint, 0664);
+MODULE_PARM_DESC(no_head, "\n amvdec_av1 no_head\n");
+
+module_param(error_handle_policy, uint, 0664);
+MODULE_PARM_DESC(error_handle_policy, "\n amvdec_av1 error_handle_policy\n");
+
+module_param(buf_alloc_width, uint, 0664);
+MODULE_PARM_DESC(buf_alloc_width, "\n buf_alloc_width\n");
+
+module_param(buf_alloc_height, uint, 0664);
+MODULE_PARM_DESC(buf_alloc_height, "\n buf_alloc_height\n");
+
+module_param(buf_alloc_depth, uint, 0664);
+MODULE_PARM_DESC(buf_alloc_depth, "\n buf_alloc_depth\n");
+
+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");
+
+module_param(mv_buf_margin, uint, 0664);
+MODULE_PARM_DESC(mv_buf_margin, "\n mv_buf_margin\n");
+
+module_param(mv_buf_dynamic_alloc, uint, 0664);
+MODULE_PARM_DESC(mv_buf_dynamic_alloc, "\n mv_buf_dynamic_alloc\n");
+
+module_param(force_max_one_mv_buffer_size, uint, 0664);
+MODULE_PARM_DESC(force_max_one_mv_buffer_size, "\n force_max_one_mv_buffer_size\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");
+
+#ifdef SUPPORT_10BIT
+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");
+#endif
+
+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");
+
+#ifdef MCRCC_ENABLE
+module_param(mcrcc_cache_alg_flag, uint, 0664);
+MODULE_PARM_DESC(mcrcc_cache_alg_flag, "\n mcrcc_cache_alg_flag\n");
+#endif
+
+#ifdef MULTI_INSTANCE_SUPPORT
+module_param(start_decode_buf_level, int, 0664);
+MODULE_PARM_DESC(start_decode_buf_level,
+ "\n av1 start_decode_buf_level\n");
+
+module_param(decode_timeout_val, uint, 0664);
+MODULE_PARM_DESC(decode_timeout_val,
+ "\n av1 decode_timeout_val\n");
+
+module_param(av1_max_pic_w, uint, 0664);
+MODULE_PARM_DESC(av1_max_pic_w, "\n av1_max_pic_w\n");
+
+module_param(av1_max_pic_h, uint, 0664);
+MODULE_PARM_DESC(av1_max_pic_h, "\n av1_max_pic_h\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);
+
+#ifdef AOM_AV1_MMU_DW
+module_param_array(dw_mmu_enable, uint,
+ &max_decode_instance_num, 0664);
+#endif
+
+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");
+
+#endif
+
+#ifdef DUMP_FILMGRAIN
+module_param(fg_dump_index, uint, 0664);
+MODULE_PARM_DESC(fg_dump_index, "\n fg_dump_index\n");
+#endif
+
+module_param(get_picture_qos, uint, 0664);
+MODULE_PARM_DESC(get_picture_qos, "\n amvdec_av1 get_picture_qos\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");
+
+#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");
+#endif
+
+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");
+
+#ifdef DEBUG_CRC_ERROR
+module_param(crc_debug_flag, uint, 0664);
+MODULE_PARM_DESC(crc_debug_flag, "\n crc_debug_flag\n");
+#endif
+
+#ifdef DEBUG_CMD
+module_param(debug_cmd_wait_type, uint, 0664);
+MODULE_PARM_DESC(debug_cmd_wait_type, "\n debug_cmd_wait_type\n");
+
+module_param(debug_cmd_wait_count, uint, 0664);
+MODULE_PARM_DESC(debug_cmd_wait_count, "\n debug_cmd_wait_count\n");
+
+module_param(header_dump_size, uint, 0664);
+MODULE_PARM_DESC(header_dump_size, "\n header_dump_size\n");
+#endif
+
+module_param(force_pts_unstable, uint, 0664);
+MODULE_PARM_DESC(force_pts_unstable, "\n force_pts_unstable\n");
+
+module_param(without_display_mode, uint, 0664);
+MODULE_PARM_DESC(without_display_mode, "\n without_display_mode\n");
+
+module_init(amvdec_av1_driver_init_module);
+module_exit(amvdec_av1_driver_remove_module);
+
+MODULE_DESCRIPTION("AMLOGIC av1 Video Decoder Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/frame_provider/decoder/vav1/vav1.h b/drivers/frame_provider/decoder/vav1/vav1.h
new file mode 100644
index 0000000..0f2b765
--- /dev/null
+++ b/drivers/frame_provider/decoder/vav1/vav1.h
@@ -0,0 +1,22 @@
+/*
+ * drivers/amlogic/amports/vav1.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 VAV1_H
+#define VAV1_H
+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/vc1/Makefile b/drivers/frame_provider/decoder/vc1/Makefile
new file mode 100644
index 0000000..b43a600
--- /dev/null
+++ b/drivers/frame_provider/decoder/vc1/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_VC1) += amvdec_vc1.o
+amvdec_vc1-objs += vvc1.o
diff --git a/drivers/frame_provider/decoder/vc1/vvc1.c b/drivers/frame_provider/decoder/vc1/vvc1.c
new file mode 100644
index 0000000..aa215a9
--- /dev/null
+++ b/drivers/frame_provider/decoder/vc1/vvc1.c
@@ -0,0 +1,1398 @@
+/*
+ * drivers/amlogic/amports/vvc1.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/module.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/canvas/canvas.h>
+#include <linux/amlogic/media/canvas/canvas_mgr.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/vdec_reg.h>
+#include "../utils/amvdec.h"
+#include "../utils/vdec.h"
+#include <linux/amlogic/media/registers/register.h>
+#include "../../../stream_input/amports/amports_priv.h"
+#include "../utils/decoder_mmu_box.h"
+#include "../utils/decoder_bmmu_box.h"
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include <linux/amlogic/media/codec_mm/configs.h>
+#include "../utils/firmware.h"
+#include <linux/amlogic/tee.h>
+#include <linux/delay.h>
+#include "../../../common/chips/decoder_cpu_ver_info.h"
+
+
+#define DRIVER_NAME "amvdec_vc1"
+#define MODULE_NAME "amvdec_vc1"
+
+#define DEBUG_PTS
+#if 1 /* //MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+#define NV21
+#endif
+
+#define VC1_MAX_SUPPORT_SIZE (1920*1088)
+
+#define I_PICTURE 0
+#define P_PICTURE 1
+#define B_PICTURE 2
+
+#define ORI_BUFFER_START_ADDR 0x01000000
+
+#define INTERLACE_FLAG 0x80
+#define BOTTOM_FIELD_FIRST_FLAG 0x40
+
+/* protocol registers */
+#define VC1_PIC_RATIO AV_SCRATCH_0
+#define VC1_ERROR_COUNT AV_SCRATCH_6
+#define VC1_SOS_COUNT AV_SCRATCH_7
+#define VC1_BUFFERIN AV_SCRATCH_8
+#define VC1_BUFFEROUT AV_SCRATCH_9
+#define VC1_REPEAT_COUNT AV_SCRATCH_A
+#define VC1_TIME_STAMP AV_SCRATCH_B
+#define VC1_OFFSET_REG AV_SCRATCH_C
+#define MEM_OFFSET_REG AV_SCRATCH_F
+
+#define VF_POOL_SIZE 16
+#define DECODE_BUFFER_NUM_MAX 4
+#define WORKSPACE_SIZE (2 * SZ_1M)
+#define MAX_BMMU_BUFFER_NUM (DECODE_BUFFER_NUM_MAX + 1)
+#define VF_BUFFER_IDX(n) (1 + n)
+#define DCAC_BUFF_START_ADDR 0x01f00000
+
+
+#define PUT_INTERVAL (HZ/100)
+
+#if 1 /* /MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+/* TODO: move to register headers */
+#define VPP_VD1_POSTBLEND (1 << 10)
+#define MEM_FIFO_CNT_BIT 16
+#define MEM_LEVEL_CNT_BIT 18
+#endif
+static struct vdec_info *gvs;
+static struct vdec_s *vdec = NULL;
+
+static struct vframe_s *vvc1_vf_peek(void *);
+static struct vframe_s *vvc1_vf_get(void *);
+static void vvc1_vf_put(struct vframe_s *, void *);
+static int vvc1_vf_states(struct vframe_states *states, void *);
+static int vvc1_event_cb(int type, void *data, void *private_data);
+
+static int vvc1_prot_init(void);
+static void vvc1_local_init(bool is_reset);
+
+static const char vvc1_dec_id[] = "vvc1-dev";
+
+#define PROVIDER_NAME "decoder.vc1"
+static const struct vframe_operations_s vvc1_vf_provider = {
+ .peek = vvc1_vf_peek,
+ .get = vvc1_vf_get,
+ .put = vvc1_vf_put,
+ .event_cb = vvc1_event_cb,
+ .vf_states = vvc1_vf_states,
+};
+static void *mm_blk_handle;
+static struct vframe_provider_s vvc1_vf_prov;
+
+static DECLARE_KFIFO(newframe_q, struct vframe_s *, VF_POOL_SIZE);
+static DECLARE_KFIFO(display_q, struct vframe_s *, VF_POOL_SIZE);
+static DECLARE_KFIFO(recycle_q, struct vframe_s *, VF_POOL_SIZE);
+
+static struct vframe_s vfpool[VF_POOL_SIZE];
+static struct vframe_s vfpool2[VF_POOL_SIZE];
+static int cur_pool_idx;
+
+static s32 vfbuf_use[DECODE_BUFFER_NUM_MAX];
+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 unstable_pts_debug;
+static u32 unstable_pts;
+static u32 vvc1_ratio;
+static u32 vvc1_format;
+
+static u32 intra_output;
+static u32 frame_width, frame_height, frame_dur;
+static u32 saved_resolution;
+static u32 pts_by_offset = 1;
+static u32 total_frame;
+static u32 next_pts;
+static u64 next_pts_us64;
+static bool is_reset;
+static struct work_struct set_clk_work;
+static struct work_struct error_wd_work;
+spinlock_t vc1_rp_lock;
+
+
+#ifdef DEBUG_PTS
+static u32 pts_hit, pts_missed, pts_i_hit, pts_i_missed;
+#endif
+static DEFINE_SPINLOCK(lock);
+
+static struct dec_sysinfo vvc1_amstream_dec_info;
+
+struct frm_s {
+ int state;
+ u32 start_pts;
+ int num;
+ u32 end_pts;
+ u32 rate;
+ u32 trymax;
+};
+
+static struct frm_s frm;
+
+enum {
+ RATE_MEASURE_START_PTS = 0,
+ RATE_MEASURE_END_PTS,
+ RATE_MEASURE_DONE
+};
+#define RATE_MEASURE_NUM 8
+#define RATE_CORRECTION_THRESHOLD 5
+#define RATE_24_FPS 3755 /* 23.97 */
+#define RATE_30_FPS 3003 /* 29.97 */
+#define DUR2PTS(x) ((x)*90/96)
+#define PTS2DUR(x) ((x)*96/90)
+
+static inline int pool_index(struct vframe_s *vf)
+{
+ if ((vf >= &vfpool[0]) && (vf <= &vfpool[VF_POOL_SIZE - 1]))
+ return 0;
+ else if ((vf >= &vfpool2[0]) && (vf <= &vfpool2[VF_POOL_SIZE - 1]))
+ return 1;
+ else
+ return -1;
+}
+
+static inline bool close_to(int a, int b, int m)
+{
+ return abs(a - b) < m;
+}
+
+static inline u32 index2canvas(u32 index)
+{
+ const u32 canvas_tab[DECODE_BUFFER_NUM_MAX] = {
+#if 1 /* ALWASY.MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+ 0x010100, 0x030302, 0x050504, 0x070706/*,
+ 0x090908, 0x0b0b0a, 0x0d0d0c, 0x0f0f0e*/
+#else
+ 0x020100, 0x050403, 0x080706, 0x0b0a09
+#endif
+ };
+
+ return canvas_tab[index];
+}
+
+static void set_aspect_ratio(struct vframe_s *vf, unsigned int pixel_ratio)
+{
+ int ar = 0;
+
+ if (vvc1_ratio == 0) {
+ /* always stretch to 16:9 */
+ vf->ratio_control |= (0x90 << DISP_RATIO_ASPECT_RATIO_BIT);
+ } else if (pixel_ratio > 0x0f) {
+ ar = (vvc1_amstream_dec_info.height * (pixel_ratio & 0xff) *
+ vvc1_ratio) / (vvc1_amstream_dec_info.width *
+ (pixel_ratio >> 8));
+ } else {
+ switch (pixel_ratio) {
+ case 0:
+ ar = (vvc1_amstream_dec_info.height * vvc1_ratio) /
+ vvc1_amstream_dec_info.width;
+ break;
+ case 1:
+ vf->sar_width = 1;
+ vf->sar_height = 1;
+ ar = (vf->height * vvc1_ratio) / vf->width;
+ break;
+ case 2:
+ vf->sar_width = 12;
+ vf->sar_height = 11;
+ ar = (vf->height * 11 * vvc1_ratio) / (vf->width * 12);
+ break;
+ case 3:
+ vf->sar_width = 10;
+ vf->sar_height = 11;
+ ar = (vf->height * 11 * vvc1_ratio) / (vf->width * 10);
+ break;
+ case 4:
+ vf->sar_width = 16;
+ vf->sar_height = 11;
+ ar = (vf->height * 11 * vvc1_ratio) / (vf->width * 16);
+ break;
+ case 5:
+ vf->sar_width = 40;
+ vf->sar_height = 33;
+ ar = (vf->height * 33 * vvc1_ratio) / (vf->width * 40);
+ break;
+ case 6:
+ vf->sar_width = 24;
+ vf->sar_height = 11;
+ ar = (vf->height * 11 * vvc1_ratio) / (vf->width * 24);
+ break;
+ case 7:
+ vf->sar_width = 20;
+ vf->sar_height = 11;
+ ar = (vf->height * 11 * vvc1_ratio) / (vf->width * 20);
+ break;
+ case 8:
+ vf->sar_width = 32;
+ vf->sar_height = 11;
+ ar = (vf->height * 11 * vvc1_ratio) / (vf->width * 32);
+ break;
+ case 9:
+ vf->sar_width = 80;
+ vf->sar_height = 33;
+ ar = (vf->height * 33 * vvc1_ratio) / (vf->width * 80);
+ break;
+ case 10:
+ vf->sar_width = 18;
+ vf->sar_height = 11;
+ ar = (vf->height * 11 * vvc1_ratio) / (vf->width * 18);
+ break;
+ case 11:
+ vf->sar_width = 15;
+ vf->sar_height = 11;
+ ar = (vf->height * 11 * vvc1_ratio) / (vf->width * 15);
+ break;
+ case 12:
+ vf->sar_width = 64;
+ vf->sar_height = 33;
+ ar = (vf->height * 33 * vvc1_ratio) / (vf->width * 64);
+ break;
+ case 13:
+ vf->sar_width = 160;
+ vf->sar_height = 99;
+ ar = (vf->height * 99 * vvc1_ratio) /
+ (vf->width * 160);
+ break;
+ default:
+ vf->sar_width = 1;
+ vf->sar_height = 1;
+ ar = (vf->height * vvc1_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;*/
+}
+
+static void vc1_set_rp(void) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&vc1_rp_lock, flags);
+ STBUF_WRITE(&vdec->vbuf, set_rp,
+ READ_VREG(VLD_MEM_VIFIFO_RP));
+ spin_unlock_irqrestore(&vc1_rp_lock, flags);
+}
+
+static irqreturn_t vvc1_isr(int irq, void *dev_id)
+{
+ u32 reg;
+ struct vframe_s *vf = NULL;
+ u32 repeat_count;
+ u32 picture_type;
+ u32 buffer_index;
+ unsigned int pts, pts_valid = 0, offset = 0;
+ u32 v_width, v_height;
+ u64 pts_us64 = 0;
+ u32 frame_size;
+
+ reg = READ_VREG(VC1_BUFFEROUT);
+
+ if (reg) {
+ v_width = READ_VREG(AV_SCRATCH_J);
+ v_height = READ_VREG(AV_SCRATCH_K);
+
+ vc1_set_rp();
+
+ if (v_width && v_width <= 4096
+ && (v_width != vvc1_amstream_dec_info.width)) {
+ pr_info("frame width changed %d to %d\n",
+ vvc1_amstream_dec_info.width, v_width);
+ vvc1_amstream_dec_info.width = v_width;
+ frame_width = v_width;
+ }
+ if (v_height && v_height <= 4096
+ && (v_height != vvc1_amstream_dec_info.height)) {
+ pr_info("frame height changed %d to %d\n",
+ vvc1_amstream_dec_info.height, v_height);
+ vvc1_amstream_dec_info.height = v_height;
+ frame_height = v_height;
+ }
+
+ if (pts_by_offset) {
+ offset = READ_VREG(VC1_OFFSET_REG);
+ 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(VC1_REPEAT_COUNT);
+ buffer_index = ((reg & 0x7) - 1) & 3;
+ picture_type = (reg >> 3) & 7;
+
+ if (buffer_index >= DECODE_BUFFER_NUM_MAX) {
+ pr_info("fatal error, invalid buffer index.");
+ return IRQ_HANDLED;
+ }
+
+ if ((intra_output == 0) && (picture_type != 0)) {
+ WRITE_VREG(VC1_BUFFERIN, ~(1 << buffer_index));
+ WRITE_VREG(VC1_BUFFEROUT, 0);
+ WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
+
+ return IRQ_HANDLED;
+ }
+
+ intra_output = 1;
+
+#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 ((pts_valid) && (frm.state != RATE_MEASURE_DONE)) {
+ if (frm.state == RATE_MEASURE_START_PTS) {
+ frm.start_pts = pts;
+ frm.state = RATE_MEASURE_END_PTS;
+ frm.trymax = RATE_MEASURE_NUM;
+ } else if (frm.state == RATE_MEASURE_END_PTS) {
+ if (frm.num >= frm.trymax) {
+ frm.end_pts = pts;
+ frm.rate = (frm.end_pts -
+ frm.start_pts) / frm.num;
+ pr_info("frate before=%d,%d,num=%d\n",
+ frm.rate,
+ DUR2PTS(vvc1_amstream_dec_info.rate),
+ frm.num);
+ /* check if measured rate is same as
+ * settings from upper layer
+ * and correct it if necessary
+ */
+ if ((close_to(frm.rate, RATE_30_FPS,
+ RATE_CORRECTION_THRESHOLD) &&
+ close_to(
+ DUR2PTS(
+ vvc1_amstream_dec_info.rate),
+ RATE_24_FPS,
+ RATE_CORRECTION_THRESHOLD))
+ ||
+ (close_to(
+ frm.rate, RATE_24_FPS,
+ RATE_CORRECTION_THRESHOLD)
+ &&
+ close_to(DUR2PTS(
+ vvc1_amstream_dec_info.rate),
+ RATE_30_FPS,
+ RATE_CORRECTION_THRESHOLD))) {
+ pr_info(
+ "vvc1: frate from %d to %d\n",
+ vvc1_amstream_dec_info.rate,
+ PTS2DUR(frm.rate));
+
+ vvc1_amstream_dec_info.rate =
+ PTS2DUR(frm.rate);
+ frm.state = RATE_MEASURE_DONE;
+ } else if (close_to(frm.rate,
+ DUR2PTS(
+ vvc1_amstream_dec_info.rate),
+ RATE_CORRECTION_THRESHOLD))
+ frm.state = RATE_MEASURE_DONE;
+ else {
+
+/* maybe still have problem,
+ * try next double frames....
+ */
+ frm.state = RATE_MEASURE_DONE;
+ frm.start_pts = pts;
+ frm.state =
+ RATE_MEASURE_END_PTS;
+ /*60 fps*60 S */
+ frm.num = 0;
+ }
+ }
+ }
+ }
+
+ if (frm.state != RATE_MEASURE_DONE)
+ frm.num += (repeat_count > 1) ? repeat_count : 1;
+ if (vvc1_amstream_dec_info.rate == 0)
+ vvc1_amstream_dec_info.rate = PTS2DUR(frm.rate);
+
+ if (reg & INTERLACE_FLAG) { /* interlace */
+ if (kfifo_get(&newframe_q, &vf) == 0) {
+ pr_info
+ ("fatal error, no available buffer slot.");
+ return IRQ_HANDLED;
+ }
+ vf->signal_type = 0;
+ vf->index = buffer_index;
+ vf->width = vvc1_amstream_dec_info.width;
+ vf->height = vvc1_amstream_dec_info.height;
+ vf->bufWidth = 1920;
+ vf->flag = 0;
+
+ if (pts_valid) {
+ vf->pts = pts;
+ vf->pts_us64 = pts_us64;
+ if ((repeat_count > 1) && avi_flag) {
+ vf->duration =
+ vvc1_amstream_dec_info.rate *
+ repeat_count >> 1;
+ next_pts = pts +
+ (vvc1_amstream_dec_info.rate *
+ repeat_count >> 1) * 15 / 16;
+ next_pts_us64 = pts_us64 +
+ ((vvc1_amstream_dec_info.rate *
+ repeat_count >> 1) * 15 / 16) *
+ 100 / 9;
+ } else {
+ vf->duration =
+ vvc1_amstream_dec_info.rate >> 1;
+ next_pts = 0;
+ next_pts_us64 = 0;
+ if (picture_type != I_PICTURE &&
+ unstable_pts) {
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+ }
+ }
+ } else {
+ vf->pts = next_pts;
+ vf->pts_us64 = next_pts_us64;
+ if ((repeat_count > 1) && avi_flag) {
+ vf->duration =
+ vvc1_amstream_dec_info.rate *
+ repeat_count >> 1;
+ if (next_pts != 0) {
+ next_pts += ((vf->duration) -
+ ((vf->duration) >> 4));
+ }
+ if (next_pts_us64 != 0) {
+ next_pts_us64 +=
+ (u64)((vf->duration) -
+ ((vf->duration) >> 4)) *
+ 100 / 9;
+ }
+ } else {
+ vf->duration =
+ vvc1_amstream_dec_info.rate >> 1;
+ next_pts = 0;
+ next_pts_us64 = 0;
+ if (picture_type != I_PICTURE &&
+ unstable_pts) {
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+ }
+ }
+ }
+
+ vf->duration_pulldown = 0;
+ vf->type = (reg & BOTTOM_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->orientation = 0;
+ vf->type_original = vf->type;
+ set_aspect_ratio(vf, READ_VREG(VC1_PIC_RATIO));
+
+ 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);
+
+ if (kfifo_get(&newframe_q, &vf) == 0) {
+ pr_info
+ ("fatal error, no available buffer slot.");
+ return IRQ_HANDLED;
+ }
+ vf->signal_type = 0;
+ vf->index = buffer_index;
+ vf->width = vvc1_amstream_dec_info.width;
+ vf->height = vvc1_amstream_dec_info.height;
+ vf->bufWidth = 1920;
+ vf->flag = 0;
+
+ vf->pts = next_pts;
+ vf->pts_us64 = next_pts_us64;
+ if ((repeat_count > 1) && avi_flag) {
+ vf->duration =
+ vvc1_amstream_dec_info.rate *
+ repeat_count >> 1;
+ if (next_pts != 0) {
+ next_pts +=
+ ((vf->duration) -
+ ((vf->duration) >> 4));
+ }
+ if (next_pts_us64 != 0) {
+ next_pts_us64 += (u64)((vf->duration) -
+ ((vf->duration) >> 4)) * 100 / 9;
+ }
+ } else {
+ vf->duration =
+ vvc1_amstream_dec_info.rate >> 1;
+ next_pts = 0;
+ next_pts_us64 = 0;
+ if (picture_type != I_PICTURE &&
+ unstable_pts) {
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+ }
+ }
+
+ vf->duration_pulldown = 0;
+ vf->type = (reg & BOTTOM_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->orientation = 0;
+ vf->type_original = vf->type;
+ set_aspect_ratio(vf, READ_VREG(VC1_PIC_RATIO));
+
+ 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);
+ } else { /* progressive */
+ if (kfifo_get(&newframe_q, &vf) == 0) {
+ pr_info
+ ("fatal error, no available buffer slot.");
+ return IRQ_HANDLED;
+ }
+ vf->signal_type = 0;
+ vf->index = buffer_index;
+ vf->width = vvc1_amstream_dec_info.width;
+ vf->height = vvc1_amstream_dec_info.height;
+ vf->bufWidth = 1920;
+ vf->flag = 0;
+
+ if (pts_valid) {
+ vf->pts = pts;
+ vf->pts_us64 = pts_us64;
+ if ((repeat_count > 1) && avi_flag) {
+ vf->duration =
+ vvc1_amstream_dec_info.rate *
+ repeat_count;
+ next_pts =
+ pts +
+ (vvc1_amstream_dec_info.rate *
+ repeat_count) * 15 / 16;
+ next_pts_us64 = pts_us64 +
+ ((vvc1_amstream_dec_info.rate *
+ repeat_count) * 15 / 16) *
+ 100 / 9;
+ } else {
+ vf->duration =
+ vvc1_amstream_dec_info.rate;
+ next_pts = 0;
+ next_pts_us64 = 0;
+ if (picture_type != I_PICTURE &&
+ unstable_pts) {
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+ }
+ }
+ } else {
+ vf->pts = next_pts;
+ vf->pts_us64 = next_pts_us64;
+ if ((repeat_count > 1) && avi_flag) {
+ vf->duration =
+ vvc1_amstream_dec_info.rate *
+ repeat_count;
+ if (next_pts != 0) {
+ next_pts += ((vf->duration) -
+ ((vf->duration) >> 4));
+ }
+ if (next_pts_us64 != 0) {
+ next_pts_us64 +=
+ (u64)((vf->duration) -
+ ((vf->duration) >> 4)) *
+ 100 / 9;
+ }
+ } else {
+ vf->duration =
+ vvc1_amstream_dec_info.rate;
+ next_pts = 0;
+ next_pts_us64 = 0;
+ if (picture_type != I_PICTURE &&
+ unstable_pts) {
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+ }
+ }
+ }
+
+ vf->duration_pulldown = 0;
+#ifdef NV21
+ vf->type =
+ VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD |
+ VIDTYPE_VIU_NV21;
+#else
+ vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD;
+#endif
+ vf->canvas0Addr = vf->canvas1Addr =
+ index2canvas(buffer_index);
+ vf->orientation = 0;
+ vf->type_original = vf->type;
+ set_aspect_ratio(vf, READ_VREG(VC1_PIC_RATIO));
+
+ 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);
+ }
+ frame_dur = vvc1_amstream_dec_info.rate;
+ total_frame++;
+
+ /*count info*/
+ gvs->frame_dur = frame_dur;
+ vdec_count_info(gvs, 0, offset);
+
+ /* pr_info("PicType = %d, PTS = 0x%x, repeat
+ *count %d\n", picture_type, vf->pts, repeat_count);
+ */
+ WRITE_VREG(VC1_BUFFEROUT, 0);
+ }
+
+ WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
+
+ return IRQ_HANDLED;
+}
+
+static struct vframe_s *vvc1_vf_peek(void *op_arg)
+{
+ struct vframe_s *vf;
+
+ if (kfifo_peek(&display_q, &vf))
+ return vf;
+
+ return NULL;
+}
+
+static struct vframe_s *vvc1_vf_get(void *op_arg)
+{
+ struct vframe_s *vf;
+
+ if (kfifo_get(&display_q, &vf))
+ return vf;
+
+ return NULL;
+}
+
+static void vvc1_vf_put(struct vframe_s *vf, void *op_arg)
+{
+ if (pool_index(vf) == cur_pool_idx)
+ kfifo_put(&recycle_q, (const struct vframe_s *)vf);
+}
+
+static int vvc1_vf_states(struct vframe_states *states, void *op_arg)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ states->vf_pool_size = VF_POOL_SIZE;
+ states->buf_free_num = kfifo_len(&newframe_q);
+ states->buf_avail_num = kfifo_len(&display_q);
+ states->buf_recycle_num = kfifo_len(&recycle_q);
+
+ spin_unlock_irqrestore(&lock, flags);
+
+ return 0;
+}
+
+static int vvc1_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(&vvc1_vf_prov);
+#endif
+ spin_lock_irqsave(&lock, flags);
+ vvc1_local_init(true);
+ vvc1_prot_init();
+ spin_unlock_irqrestore(&lock, flags);
+#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vf_reg_provider(&vvc1_vf_prov);
+#endif
+ amvdec_start();
+ }
+
+ 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 vvc1_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus)
+{
+ if (!(stat & STAT_VDEC_RUN))
+ return -1;
+
+ vstatus->frame_width = vvc1_amstream_dec_info.width;
+ vstatus->frame_height = vvc1_amstream_dec_info.height;
+ if (vvc1_amstream_dec_info.rate != 0)
+ vstatus->frame_rate = 96000 / vvc1_amstream_dec_info.rate;
+ 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 = vvc1_amstream_dec_info.rate;
+ vstatus->frame_data = gvs->frame_data;
+ vstatus->total_data = gvs->total_data;
+ vstatus->frame_count = gvs->frame_count;
+ vstatus->error_frame_count = gvs->error_frame_count;
+ vstatus->drop_frame_count = gvs->drop_frame_count;
+ vstatus->total_data = gvs->total_data;
+ vstatus->samp_cnt = gvs->samp_cnt;
+ vstatus->offset = gvs->offset;
+ snprintf(vstatus->vdec_name, sizeof(vstatus->vdec_name),
+ "%s", DRIVER_NAME);
+
+ return 0;
+}
+
+int vvc1_set_isreset(struct vdec_s *vdec, int isreset)
+{
+ is_reset = isreset;
+ return 0;
+}
+
+static int vvc1_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 vvc1_canvas_init(void)
+{
+ int i, ret;
+ u32 canvas_width, canvas_height;
+ u32 alloc_size, decbuf_size, decbuf_y_size, decbuf_uv_size;
+ unsigned long buf_start;
+
+ 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;
+ }
+
+ for (i = 0; i < MAX_BMMU_BUFFER_NUM; i++) {
+ /* workspace mem */
+ if (i == (MAX_BMMU_BUFFER_NUM - 1))
+ alloc_size = WORKSPACE_SIZE;
+ else
+ alloc_size = decbuf_size;
+
+ ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle, i,
+ alloc_size, DRIVER_NAME, &buf_start);
+ if (ret < 0)
+ return ret;
+ if (i == (MAX_BMMU_BUFFER_NUM - 1)) {
+ buf_offset = buf_start - DCAC_BUFF_START_ADDR;
+ continue;
+ }
+
+#ifdef NV21
+ canvas_config(2 * i + 0,
+ buf_start,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+ canvas_config(2 * i + 1,
+ buf_start +
+ decbuf_y_size, canvas_width,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+#else
+ canvas_config(3 * i + 0,
+ buf_start,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+ canvas_config(3 * i + 1,
+ buf_start +
+ decbuf_y_size, canvas_width / 2,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+ canvas_config(3 * i + 2,
+ buf_start +
+ decbuf_y_size + decbuf_uv_size,
+ canvas_width / 2, canvas_height / 2,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+#endif
+
+ }
+ return 0;
+}
+
+static int vvc1_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
+
+ 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 = vvc1_canvas_init();
+
+ /* index v << 16 | u << 8 | y */
+#ifdef NV21
+ WRITE_VREG(AV_SCRATCH_0, 0x010100);
+ WRITE_VREG(AV_SCRATCH_1, 0x030302);
+ WRITE_VREG(AV_SCRATCH_2, 0x050504);
+ WRITE_VREG(AV_SCRATCH_3, 0x070706);
+/* WRITE_VREG(AV_SCRATCH_G, 0x090908);
+ WRITE_VREG(AV_SCRATCH_H, 0x0b0b0a);
+ WRITE_VREG(AV_SCRATCH_I, 0x0d0d0c);
+ WRITE_VREG(AV_SCRATCH_J, 0x0f0f0e);*/
+#else
+ WRITE_VREG(AV_SCRATCH_0, 0x020100);
+ WRITE_VREG(AV_SCRATCH_1, 0x050403);
+ WRITE_VREG(AV_SCRATCH_2, 0x080706);
+ WRITE_VREG(AV_SCRATCH_3, 0x0b0a09);
+ WRITE_VREG(AV_SCRATCH_G, 0x090908);
+ WRITE_VREG(AV_SCRATCH_H, 0x0b0b0a);
+ WRITE_VREG(AV_SCRATCH_I, 0x0d0d0c);
+ WRITE_VREG(AV_SCRATCH_J, 0x0f0f0e);
+#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(VC1_SOS_COUNT, 0);
+ WRITE_VREG(VC1_BUFFERIN, 0);
+ WRITE_VREG(VC1_BUFFEROUT, 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
+ return r;
+}
+
+static void vvc1_local_init(bool is_reset)
+{
+ int i;
+
+ /* vvc1_ratio = 0x100; */
+ vvc1_ratio = vvc1_amstream_dec_info.ratio;
+
+ avi_flag = (unsigned long) vvc1_amstream_dec_info.param & 0x01;
+
+ unstable_pts = (((unsigned long) vvc1_amstream_dec_info.param & 0x40) >> 6);
+ if (unstable_pts_debug == 1) {
+ unstable_pts = 1;
+ pr_info("vc1 init , unstable_pts_debug = %u\n",unstable_pts_debug);
+ }
+ total_frame = 0;
+
+ next_pts = 0;
+
+ next_pts_us64 = 0;
+ saved_resolution = 0;
+ frame_width = frame_height = frame_dur = 0;
+#ifdef DEBUG_PTS
+ pts_hit = pts_missed = pts_i_hit = pts_i_missed = 0;
+#endif
+
+ memset(&frm, 0, sizeof(frm));
+
+ if (!is_reset) {
+ for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++)
+ vfbuf_use[i] = 0;
+
+ INIT_KFIFO(display_q);
+ INIT_KFIFO(recycle_q);
+ INIT_KFIFO(newframe_q);
+ cur_pool_idx ^= 1;
+ for (i = 0; i < VF_POOL_SIZE; i++) {
+ const struct vframe_s *vf;
+
+ if (cur_pool_idx == 0) {
+ vf = &vfpool[i];
+ vfpool[i].index = DECODE_BUFFER_NUM_MAX;
+ } else {
+ vf = &vfpool2[i];
+ vfpool2[i].index = DECODE_BUFFER_NUM_MAX;
+ }
+ kfifo_put(&newframe_q, (const struct vframe_s *)vf);
+ }
+ }
+
+ if (mm_blk_handle) {
+ decoder_bmmu_box_free(mm_blk_handle);
+ mm_blk_handle = NULL;
+ }
+
+ mm_blk_handle = decoder_bmmu_box_alloc_box(
+ DRIVER_NAME,
+ 0,
+ MAX_BMMU_BUFFER_NUM,
+ 4 + PAGE_SHIFT,
+ CODEC_MM_FLAGS_CMA_CLEAR |
+ CODEC_MM_FLAGS_FOR_VDECODER);
+}
+
+#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+static void vvc1_ppmgr_reset(void)
+{
+ vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_RESET, NULL);
+
+ vvc1_local_init(true);
+
+ /* vf_notify_receiver(PROVIDER_NAME,
+ * VFRAME_EVENT_PROVIDER_START,NULL);
+ */
+
+ pr_info("vvc1dec: vf_ppmgr_reset\n");
+}
+#endif
+
+static void vvc1_set_clk(struct work_struct *work)
+{
+ int fps = 96000 / frame_dur;
+
+ saved_resolution = frame_width * frame_height * fps;
+ vdec_source_changed(VFORMAT_VC1,
+ frame_width, frame_height, fps);
+
+}
+
+static void error_do_work(struct work_struct *work)
+{
+ amvdec_stop();
+ msleep(20);
+#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vvc1_ppmgr_reset();
+#else
+ vf_light_unreg_provider(&vvc1_vf_prov);
+ vvc1_local_init(true);
+ vf_reg_provider(&vvc1_vf_prov);
+#endif
+ vvc1_prot_init();
+ amvdec_start();
+}
+
+
+static void vvc1_put_timer_func(unsigned long arg)
+{
+ struct timer_list *timer = (struct timer_list *)arg;
+
+ if (READ_VREG(VC1_SOS_COUNT) > 10)
+ schedule_work(&error_wd_work);
+
+ vc1_set_rp();
+
+ while (!kfifo_is_empty(&recycle_q) && (READ_VREG(VC1_BUFFERIN) == 0)) {
+ struct vframe_s *vf;
+
+ if (kfifo_get(&recycle_q, &vf)) {
+ if ((vf->index < DECODE_BUFFER_NUM_MAX) &&
+ (--vfbuf_use[vf->index] == 0)) {
+ WRITE_VREG(VC1_BUFFERIN, ~(1 << vf->index));
+ vf->index = DECODE_BUFFER_NUM_MAX;
+ }
+ if (pool_index(vf) == cur_pool_idx)
+ 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);
+}
+
+static s32 vvc1_init(void)
+{
+ int ret = -1;
+ char *buf = vmalloc(0x1000 * 16);
+ int fw_type = VIDEO_DEC_VC1;
+
+ if (IS_ERR_OR_NULL(buf))
+ return -ENOMEM;
+
+ pr_info("vvc1_init, format %d\n", vvc1_amstream_dec_info.format);
+ init_timer(&recycle_timer);
+
+ stat |= STAT_TIMER_INIT;
+
+ intra_output = 0;
+ amvdec_enable();
+
+ vvc1_local_init(false);
+
+ if (vvc1_amstream_dec_info.format == VIDEO_DEC_FORMAT_WMV3) {
+ pr_info("WMV3 dec format\n");
+ vvc1_format = VIDEO_DEC_FORMAT_WMV3;
+ WRITE_VREG(AV_SCRATCH_4, 0);
+ } else if (vvc1_amstream_dec_info.format == VIDEO_DEC_FORMAT_WVC1) {
+ pr_info("WVC1 dec format\n");
+ vvc1_format = VIDEO_DEC_FORMAT_WVC1;
+ WRITE_VREG(AV_SCRATCH_4, 1);
+ } else
+ pr_info("not supported VC1 format\n");
+
+ if (get_firmware_data(fw_type, buf) < 0) {
+ amvdec_disable();
+ pr_err("get firmware fail.");
+ vfree(buf);
+ return -1;
+ }
+
+ ret = amvdec_loadmc_ex(VFORMAT_VC1, NULL, buf);
+ if (ret < 0) {
+ amvdec_disable();
+ vfree(buf);
+ pr_err("VC1: 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 = vvc1_prot_init();
+ if (ret < 0)
+ return ret;
+
+ if (vdec_request_irq(VDEC_IRQ_1, vvc1_isr,
+ "vvc1-irq", (void *)vvc1_dec_id)) {
+ amvdec_disable();
+
+ pr_info("vvc1 irq register error.\n");
+ return -ENOENT;
+ }
+
+ stat |= STAT_ISR_REG;
+#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vf_provider_init(&vvc1_vf_prov,
+ PROVIDER_NAME, &vvc1_vf_provider, NULL);
+ vf_reg_provider(&vvc1_vf_prov);
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_START, NULL);
+#else
+ vf_provider_init(&vvc1_vf_prov,
+ PROVIDER_NAME, &vvc1_vf_provider, NULL);
+ vf_reg_provider(&vvc1_vf_prov);
+#endif
+
+ if (!is_reset)
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)
+ ((unsigned long)vvc1_amstream_dec_info.rate));
+
+ stat |= STAT_VF_HOOK;
+
+ recycle_timer.data = (ulong)&recycle_timer;
+ recycle_timer.function = vvc1_put_timer_func;
+ recycle_timer.expires = jiffies + PUT_INTERVAL;
+
+ add_timer(&recycle_timer);
+
+ stat |= STAT_TIMER_ARM;
+
+ amvdec_start();
+
+ stat |= STAT_VDEC_RUN;
+
+ return 0;
+}
+
+static int amvdec_vc1_probe(struct platform_device *pdev)
+{
+ struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
+
+ if (pdata == NULL) {
+ pr_info("amvdec_vc1 memory resource undefined.\n");
+ return -EFAULT;
+ }
+
+ if (pdata->sys_info) {
+ vvc1_amstream_dec_info = *pdata->sys_info;
+
+ if ((vvc1_amstream_dec_info.height != 0) &&
+ (vvc1_amstream_dec_info.width >
+ (VC1_MAX_SUPPORT_SIZE/vvc1_amstream_dec_info.height))) {
+ pr_info("amvdec_vc1: over size, unsupport: %d * %d\n",
+ vvc1_amstream_dec_info.width,
+ vvc1_amstream_dec_info.height);
+ return -EFAULT;
+ }
+ }
+ pdata->dec_status = vvc1_dec_status;
+ pdata->set_isreset = vvc1_set_isreset;
+ is_reset = 0;
+ vdec = pdata;
+
+ vvc1_vdec_info_init();
+
+ INIT_WORK(&error_wd_work, error_do_work);
+ INIT_WORK(&set_clk_work, vvc1_set_clk);
+ spin_lock_init(&vc1_rp_lock);
+ if (vvc1_init() < 0) {
+ pr_info("amvdec_vc1 init failed.\n");
+ kfree(gvs);
+ gvs = NULL;
+ pdata->dec_status = NULL;
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int amvdec_vc1_remove(struct platform_device *pdev)
+{
+ cancel_work_sync(&error_wd_work);
+ if (stat & STAT_VDEC_RUN) {
+ amvdec_stop();
+ stat &= ~STAT_VDEC_RUN;
+ }
+
+ if (stat & STAT_ISR_REG) {
+ vdec_free_irq(VDEC_IRQ_1, (void *)vvc1_dec_id);
+ stat &= ~STAT_ISR_REG;
+ }
+
+ if (stat & STAT_TIMER_ARM) {
+ del_timer_sync(&recycle_timer);
+ stat &= ~STAT_TIMER_ARM;
+ }
+
+ cancel_work_sync(&set_clk_work);
+ if (stat & STAT_VF_HOOK) {
+ if (!is_reset)
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_FR_END_HINT,
+ NULL);
+
+ vf_unreg_provider(&vvc1_vf_prov);
+ stat &= ~STAT_VF_HOOK;
+ }
+
+ amvdec_disable();
+
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_TM2)
+ vdec_reset_core(NULL);
+
+ 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,
+ vvc1_amstream_dec_info.rate);
+#endif
+ kfree(gvs);
+ gvs = NULL;
+ vdec = NULL;
+
+ return 0;
+}
+
+/****************************************/
+#ifdef CONFIG_PM
+static int vc1_suspend(struct device *dev)
+{
+ amvdec_suspend(to_platform_device(dev), dev->power.power_state);
+ return 0;
+}
+
+static int vc1_resume(struct device *dev)
+{
+ amvdec_resume(to_platform_device(dev));
+ return 0;
+}
+
+static const struct dev_pm_ops vc1_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(vc1_suspend, vc1_resume)
+};
+#endif
+
+static struct platform_driver amvdec_vc1_driver = {
+ .probe = amvdec_vc1_probe,
+ .remove = amvdec_vc1_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &vc1_pm_ops,
+#endif
+ }
+};
+
+#if defined(CONFIG_ARCH_MESON) /*meson1 only support progressive */
+static struct codec_profile_t amvdec_vc1_profile = {
+ .name = "vc1",
+ .profile = "progressive, wmv3"
+};
+#else
+static struct codec_profile_t amvdec_vc1_profile = {
+ .name = "vc1",
+ .profile = "progressive, interlace, wmv3"
+};
+#endif
+
+static int __init amvdec_vc1_driver_init_module(void)
+{
+ pr_debug("amvdec_vc1 module init\n");
+
+ if (platform_driver_register(&amvdec_vc1_driver)) {
+ pr_err("failed to register amvdec_vc1 driver\n");
+ return -ENODEV;
+ }
+ vcodec_profile_register(&amvdec_vc1_profile);
+ return 0;
+}
+
+static void __exit amvdec_vc1_driver_remove_module(void)
+{
+ pr_debug("amvdec_vc1 module remove.\n");
+
+ platform_driver_unregister(&amvdec_vc1_driver);
+}
+module_param(unstable_pts_debug, uint, 0664);
+MODULE_PARM_DESC(unstable_pts_debug, "\n amvdec_vc1 unstable_pts\n");
+
+/****************************************/
+module_init(amvdec_vc1_driver_init_module);
+module_exit(amvdec_vc1_driver_remove_module);
+
+MODULE_DESCRIPTION("AMLOGIC VC1 Video Decoder Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Qi Wang <qi.wang@amlogic.com>");
diff --git a/drivers/frame_provider/decoder/vp9/Makefile b/drivers/frame_provider/decoder/vp9/Makefile
new file mode 100644
index 0000000..51edefe
--- /dev/null
+++ b/drivers/frame_provider/decoder/vp9/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_VP9) += amvdec_vp9.o
+amvdec_vp9-objs += vvp9.o
diff --git a/drivers/frame_provider/decoder/vp9/vvp9.c b/drivers/frame_provider/decoder/vp9/vvp9.c
new file mode 100644
index 0000000..6e6c859
--- /dev/null
+++ b/drivers/frame_provider/decoder/vp9/vvp9.c
@@ -0,0 +1,11647 @@
+ /*
+ * drivers/amlogic/amports/vvp9.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/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 "../../../stream_input/amports/amports_priv.h"
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include "../utils/decoder_mmu_box.h"
+#include "../utils/decoder_bmmu_box.h"
+
+#define MEM_NAME "codec_vp9"
+/* #include <mach/am_regs.h> */
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "../utils/vdec.h"
+#include "../utils/amvdec.h"
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+#include "../utils/vdec_profile.h"
+#endif
+
+#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_v4l2_buffer_ops.h"
+#include <media/v4l2-mem2mem.h>
+
+#define MIX_STREAM_SUPPORT
+
+#include "vvp9.h"
+
+
+/*#define SUPPORT_FB_DECODING*/
+/*#define FB_DECODING_TEST_SCHEDULE*/
+
+
+#define HW_MASK_FRONT 0x1
+#define HW_MASK_BACK 0x2
+
+#define VP9D_MPP_REFINFO_TBL_ACCCONFIG 0x3442
+#define VP9D_MPP_REFINFO_DATA 0x3443
+#define VP9D_MPP_REF_SCALE_ENBL 0x3441
+#define HEVC_MPRED_CTRL4 0x324c
+#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_MV_INFO 0x310d
+#define HEVC_QP_INFO 0x3137
+#define HEVC_SKIP_INFO 0x3136
+
+#define VP9_10B_DEC_IDLE 0
+#define VP9_10B_DEC_FRAME_HEADER 1
+#define VP9_10B_DEC_SLICE_SEGMENT 2
+#define VP9_10B_DECODE_SLICE 5
+#define VP9_10B_DISCARD_NAL 6
+#define VP9_DUMP_LMEM 7
+#define HEVC_DECPIC_DATA_DONE 0xa
+#define HEVC_DECPIC_DATA_ERROR 0xb
+#define HEVC_NAL_DECODE_DONE 0xe
+#define HEVC_DECODE_BUFEMPTY 0x20
+#define HEVC_DECODE_TIMEOUT 0x21
+#define HEVC_SEARCH_BUFEMPTY 0x22
+#define HEVC_DECODE_OVER_SIZE 0x23
+#define HEVC_S2_DECODING_DONE 0x50
+#define VP9_HEAD_PARSER_DONE 0xf0
+#define VP9_HEAD_SEARCH_DONE 0xf1
+#define VP9_EOS 0xf2
+#define HEVC_ACTION_DONE 0xff
+
+#define VF_POOL_SIZE 32
+
+#undef pr_info
+#define pr_info printk
+
+#define DECODE_MODE_SINGLE ((0x80 << 24) | 0)
+#define DECODE_MODE_MULTI_STREAMBASE ((0x80 << 24) | 1)
+#define DECODE_MODE_MULTI_FRAMEBASE ((0x80 << 24) | 2)
+#define DECODE_MODE_SINGLE_LOW_LATENCY ((0x80 << 24) | 3)
+#define DECODE_MODE_MULTI_FRAMEBASE_NOHEAD ((0x80 << 24) | 4)
+
+#define VP9_TRIGGER_FRAME_DONE 0x100
+#define VP9_TRIGGER_FRAME_ENABLE 0x200
+
+#define MV_MEM_UNIT 0x240
+/*---------------------------------------------------
+ * 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
+
+/*#define HEVC_PIC_STRUCT_SUPPORT*/
+/* to remove, fix build error */
+
+/*#define CODEC_MM_FLAGS_FOR_VDECODER 0*/
+
+#define MULTI_INSTANCE_SUPPORT
+#define SUPPORT_10BIT
+/* #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_vp9"
+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 force_pts_unstable;
+
+static u32 mv_buf_margin;
+
+static u32 mv_buf_dynamic_alloc;
+
+/* 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;
+ * 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;
+
+#define DRIVER_NAME "amvdec_vp9"
+#define DRIVER_HEADER_NAME "amvdec_vp9_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 VP9Decoder_s;
+static int vvp9_vf_states(struct vframe_states *states, void *);
+static struct vframe_s *vvp9_vf_peek(void *);
+static struct vframe_s *vvp9_vf_get(void *);
+static void vvp9_vf_put(struct vframe_s *, void *);
+static int vvp9_event_cb(int type, void *data, void *private_data);
+
+static int vvp9_stop(struct VP9Decoder_s *pbi);
+#ifdef MULTI_INSTANCE_SUPPORT
+static s32 vvp9_init(struct vdec_s *vdec);
+#else
+static s32 vvp9_init(struct VP9Decoder_s *pbi);
+#endif
+static void vvp9_prot_init(struct VP9Decoder_s *pbi, u32 mask);
+static int vvp9_local_init(struct VP9Decoder_s *pbi);
+static void vvp9_put_timer_func(unsigned long arg);
+static void dump_data(struct VP9Decoder_s *pbi, int size);
+static unsigned char get_data_check_sum
+ (struct VP9Decoder_s *pbi, int size);
+static void dump_pic_list(struct VP9Decoder_s *pbi);
+static int vp9_alloc_mmu(
+ struct VP9Decoder_s *pbi,
+ int cur_buf_idx,
+ int pic_width,
+ int pic_height,
+ unsigned short bit_depth,
+ unsigned int *mmu_index_adr);
+
+
+static const char vvp9_dec_id[] = "vvp9-dev";
+
+#define PROVIDER_NAME "decoder.vp9"
+#define MULTI_INSTANCE_PROVIDER_NAME "vdec.vp9"
+
+static const struct vframe_operations_s vvp9_vf_provider = {
+ .peek = vvp9_vf_peek,
+ .get = vvp9_vf_get,
+ .put = vvp9_vf_put,
+ .event_cb = vvp9_event_cb,
+ .vf_states = vvp9_vf_states,
+};
+
+static struct vframe_provider_s vvp9_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 on_no_keyframe_skiped;
+
+#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 HEVC_ASSIST_MMU_MAP_ADDR 0x3009
+
+#ifdef SUPPORT_FB_DECODING
+/* register define */
+#define HEVC_ASSIST_HED_FB_W_CTL 0x3006
+#define HEVC_ASSIST_HED_FB_R_CTL 0x3007
+#define HEVC_ASSIST_HED_FB_ADDR 0x3008
+#define HEVC_ASSIST_FB_MMU_MAP_ADDR 0x300a
+#define HEVC_ASSIST_FBD_MMU_MAP_ADDR 0x300b
+
+
+#define MAX_STAGE_PAGE_NUM 0x1200
+#define STAGE_MMU_MAP_SIZE (MAX_STAGE_PAGE_NUM * 4)
+#endif
+static inline int div_r32(int64_t m, int n)
+{
+/*
+ *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
+}
+
+/*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;
+ ulong v4l_ref_buf_addr;
+ ulong header_addr;
+ u32 header_size;
+ u32 luma_size;
+ ulong chroma_addr;
+ u32 chroma_size;
+} /*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 WR_PTR_INC_NUM 1
+
+#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*/
+#define MCRCC_ENABLE
+
+#define VP9_LPF_LVL_UPDATE
+/*#define DBG_LF_PRINT*/
+
+#ifdef VP9_10B_NV21
+#else
+#define LOSLESS_COMPRESS_MODE
+#endif
+
+#define DOUBLE_WRITE_YSTART_TEMP 0x02000000
+#define DOUBLE_WRITE_CSTART_TEMP 0x02900000
+
+
+
+typedef unsigned int u32;
+typedef unsigned short u16;
+
+#define VP9_DEBUG_BUFMGR 0x01
+#define VP9_DEBUG_BUFMGR_MORE 0x02
+#define VP9_DEBUG_BUFMGR_DETAIL 0x04
+#define VP9_DEBUG_OUT_PTS 0x10
+#define VP9_DEBUG_SEND_PARAM_WITH_REG 0x100
+#define VP9_DEBUG_MERGE 0x200
+#define VP9_DEBUG_DBG_LF_PRINT 0x400
+#define VP9_DEBUG_REG 0x800
+#define VP9_DEBUG_2_STAGE 0x1000
+#define VP9_DEBUG_2_STAGE_MORE 0x2000
+#define VP9_DEBUG_QOS_INFO 0x4000
+#define VP9_DEBUG_DIS_LOC_ERROR_PROC 0x10000
+#define VP9_DEBUG_DIS_SYS_ERROR_PROC 0x20000
+#define VP9_DEBUG_DUMP_PIC_LIST 0x40000
+#define VP9_DEBUG_TRIG_SLICE_SEGMENT_PROC 0x80000
+#define VP9_DEBUG_NO_TRIGGER_FRAME 0x100000
+#define VP9_DEBUG_LOAD_UCODE_FROM_FILE 0x200000
+#define VP9_DEBUG_FORCE_SEND_AGAIN 0x400000
+#define VP9_DEBUG_DUMP_DATA 0x800000
+#define VP9_DEBUG_CACHE 0x1000000
+#define VP9_DEBUG_CACHE_HIT_RATE 0x2000000
+#define IGNORE_PARAM_FROM_CONFIG 0x8000000
+#ifdef MULTI_INSTANCE_SUPPORT
+#define PRINT_FLAG_ERROR 0x0
+#define PRINT_FLAG_V4L_DETAIL 0x10000000
+#define PRINT_FLAG_VDEC_STATUS 0x20000000
+#define PRINT_FLAG_VDEC_DETAIL 0x40000000
+#define PRINT_FLAG_VDEC_DATA 0x80000000
+#endif
+static u32 force_bufspec;
+static u32 debug;
+static bool is_reset;
+/*for debug*/
+/*
+ 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 without_display_mode;
+
+/*
+ *[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 DEBUG_REG
+#ifdef DEBUG_REG
+void WRITE_VREG_DBG2(unsigned int adr, unsigned int val)
+{
+ if (debug & VP9_DEBUG_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 FRAME_CNT_WINDOW_SIZE 59
+#define RATE_CORRECTION_THRESHOLD 5
+/**************************************************
+
+VP9 buffer management start
+
+***************************************************/
+#define MMU_COMPRESS_HEADER_SIZE_1080P 0x10000
+#define MMU_COMPRESS_HEADER_SIZE_4K 0x48000
+#define MMU_COMPRESS_HEADER_SIZE_8K 0x120000
+
+
+//#define MMU_COMPRESS_HEADER_SIZE 0x48000
+//#define MMU_COMPRESS_HEADER_SIZE_DW 0x48000
+//#define MMU_COMPRESS_8K_HEADER_SIZE (MMU_COMPRESS_HEADER_SIZE * 4)
+
+#define MMU_COMPRESS_HEADER_SIZE 0x48000
+#define MMU_COMPRESS_8K_HEADER_SIZE (0x48000*4)
+#define MAX_SIZE_8K (8192 * 4608)
+#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))
+
+#define INVALID_IDX -1 /* Invalid buffer index.*/
+
+#define RPM_BEGIN 0x200
+#define RPM_END 0x280
+
+union param_u {
+ struct {
+ unsigned short data[RPM_END - RPM_BEGIN];
+ } l;
+ struct {
+ /* from ucode lmem, do not change this struct */
+ unsigned short profile;
+ unsigned short show_existing_frame;
+ unsigned short frame_to_show_idx;
+ unsigned short frame_type; /*1 bit*/
+ unsigned short show_frame; /*1 bit*/
+ unsigned short error_resilient_mode; /*1 bit*/
+ unsigned short intra_only; /*1 bit*/
+ unsigned short display_size_present; /*1 bit*/
+ unsigned short reset_frame_context;
+ unsigned short refresh_frame_flags;
+ unsigned short width;
+ unsigned short height;
+ unsigned short display_width;
+ unsigned short display_height;
+ /*
+ *bit[11:8] - ref_frame_info_0 (ref(3-bits), ref_frame_sign_bias(1-bit))
+ *bit[7:4] - ref_frame_info_1 (ref(3-bits), ref_frame_sign_bias(1-bit))
+ *bit[3:0] - ref_frame_info_2 (ref(3-bits), ref_frame_sign_bias(1-bit))
+ */
+ unsigned short ref_info;
+ /*
+ *bit[2]: same_frame_size0
+ *bit[1]: same_frame_size1
+ *bit[0]: same_frame_size2
+ */
+ unsigned short same_frame_size;
+
+ unsigned short mode_ref_delta_enabled;
+ unsigned short ref_deltas[4];
+ unsigned short mode_deltas[2];
+ unsigned short filter_level;
+ unsigned short sharpness_level;
+ unsigned short bit_depth;
+ unsigned short seg_quant_info[8];
+ unsigned short seg_enabled;
+ unsigned short seg_abs_delta;
+ /* bit 15: feature enabled; bit 8, sign; bit[5:0], data */
+ unsigned short seg_lf_info[8];
+ } p;
+};
+
+
+struct vpx_codec_frame_buffer_s {
+ uint8_t *data; /**< Pointer to the data buffer */
+ size_t size; /**< Size of data in bytes */
+ void *priv; /**< Frame's private data */
+};
+
+enum vpx_color_space_t {
+ VPX_CS_UNKNOWN = 0, /**< Unknown */
+ VPX_CS_BT_601 = 1, /**< BT.601 */
+ VPX_CS_BT_709 = 2, /**< BT.709 */
+ VPX_CS_SMPTE_170 = 3, /**< SMPTE.170 */
+ VPX_CS_SMPTE_240 = 4, /**< SMPTE.240 */
+ VPX_CS_BT_2020 = 5, /**< BT.2020 */
+ VPX_CS_RESERVED = 6, /**< Reserved */
+ VPX_CS_SRGB = 7 /**< sRGB */
+}; /**< alias for enum vpx_color_space */
+
+enum vpx_bit_depth_t {
+ VPX_BITS_8 = 8, /**< 8 bits */
+ VPX_BITS_10 = 10, /**< 10 bits */
+ VPX_BITS_12 = 12, /**< 12 bits */
+};
+
+#define MAX_SLICE_NUM 1024
+struct PIC_BUFFER_CONFIG_s {
+ int index;
+ int BUF_index;
+ int mv_buf_index;
+ int comp_body_size;
+ int buf_size;
+ int vf_ref;
+ int y_canvas_index;
+ int uv_canvas_index;
+#ifdef MULTI_INSTANCE_SUPPORT
+ struct canvas_config_s canvas_config[2];
+#endif
+ int decode_idx;
+ int slice_type;
+ int stream_offset;
+ u32 pts;
+ u64 pts64;
+ u64 timestamp;
+ uint8_t error_mark;
+ /**/
+ int slice_idx;
+ /*buffer*/
+ unsigned long header_adr;
+ unsigned long mpred_mv_wr_start_addr;
+ int mv_size;
+ /*unsigned long mc_y_adr;
+ *unsigned long mc_u_v_adr;
+ */
+ unsigned int dw_y_adr;
+ unsigned int dw_u_v_adr;
+ int mc_canvas_y;
+ int mc_canvas_u_v;
+
+ int lcu_total;
+ /**/
+ int y_width;
+ int y_height;
+ int y_crop_width;
+ int y_crop_height;
+ int y_stride;
+
+ int uv_width;
+ int uv_height;
+ int uv_crop_width;
+ int uv_crop_height;
+ int uv_stride;
+
+ int alpha_width;
+ int alpha_height;
+ int alpha_stride;
+
+ uint8_t *y_buffer;
+ uint8_t *u_buffer;
+ uint8_t *v_buffer;
+ uint8_t *alpha_buffer;
+
+ uint8_t *buffer_alloc;
+ int buffer_alloc_sz;
+ int border;
+ int frame_size;
+ int subsampling_x;
+ int subsampling_y;
+ unsigned int bit_depth;
+ enum vpx_color_space_t color_space;
+
+ int corrupted;
+ int flags;
+ unsigned long cma_alloc_addr;
+
+ int double_write_mode;
+
+ /* 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_size2; // For frame base mode
+ bool vframe_bound;
+
+ /* vdec sync. */
+ struct fence *fence;
+
+ /* hdr10 plus data */
+ u32 hdr10p_data_size;
+ char *hdr10p_data_buf;
+} PIC_BUFFER_CONFIG;
+
+enum BITSTREAM_PROFILE {
+ PROFILE_0,
+ PROFILE_1,
+ PROFILE_2,
+ PROFILE_3,
+ MAX_PROFILES
+};
+
+enum FRAME_TYPE {
+ KEY_FRAME = 0,
+ INTER_FRAME = 1,
+ FRAME_TYPES,
+};
+
+enum REFERENCE_MODE {
+ SINGLE_REFERENCE = 0,
+ COMPOUND_REFERENCE = 1,
+ REFERENCE_MODE_SELECT = 2,
+ REFERENCE_MODES = 3,
+};
+
+#define NONE -1
+#define INTRA_FRAME 0
+#define LAST_FRAME 1
+#define GOLDEN_FRAME 2
+#define ALTREF_FRAME 3
+#define MAX_REF_FRAMES 4
+
+#define REFS_PER_FRAME 3
+
+#define REF_FRAMES_LOG2 3
+#define REF_FRAMES (1 << REF_FRAMES_LOG2)
+#define REF_FRAMES_4K (6)
+
+/*4 scratch frames for the new frames to support a maximum of 4 cores decoding
+ *in parallel, 3 for scaled references on the encoder.
+ *TODO(hkuang): Add ondemand frame buffers instead of hardcoding the number
+ * // of framebuffers.
+ *TODO(jkoleszar): These 3 extra references could probably come from the
+ *normal reference pool.
+ */
+#define FRAME_BUFFERS (REF_FRAMES + 16)
+#define HEADER_FRAME_BUFFERS (FRAME_BUFFERS)
+#define MAX_BUF_NUM (FRAME_BUFFERS)
+#define MV_BUFFER_NUM FRAME_BUFFERS
+#ifdef SUPPORT_FB_DECODING
+#define STAGE_MAX_BUFFERS 16
+#else
+#define STAGE_MAX_BUFFERS 0
+#endif
+
+#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)
+#define VF_BUFFER_IDX(n) (n)
+#define HEADER_BUFFER_IDX(n) (FRAME_BUFFERS + n)
+#define WORK_SPACE_BUF_ID (FRAME_BUFFERS + HEADER_FRAME_BUFFERS)
+#else
+#define MAX_BMMU_BUFFER_NUM \
+ (FRAME_BUFFERS + HEADER_FRAME_BUFFERS + MV_BUFFER_NUM + 1)
+#define VF_BUFFER_IDX(n) (n)
+#define HEADER_BUFFER_IDX(n) (FRAME_BUFFERS + n)
+#define MV_BUFFER_IDX(n) (FRAME_BUFFERS + HEADER_FRAME_BUFFERS + n)
+#define WORK_SPACE_BUF_ID \
+ (FRAME_BUFFERS + HEADER_FRAME_BUFFERS + MV_BUFFER_NUM)
+#endif
+
+struct RefCntBuffer_s {
+ int ref_count;
+ /*MV_REF *mvs;*/
+ int mi_rows;
+ int mi_cols;
+ struct vpx_codec_frame_buffer_s raw_frame_buffer;
+ struct PIC_BUFFER_CONFIG_s buf;
+
+/*The Following variables will only be used in frame parallel decode.
+ *
+ *frame_worker_owner indicates which FrameWorker owns this buffer. NULL means
+ *that no FrameWorker owns, or is decoding, this buffer.
+ *VP9Worker *frame_worker_owner;
+ *
+ *row and col indicate which position frame has been decoded to in real
+ *pixel unit. They are reset to -1 when decoding begins and set to INT_MAX
+ *when the frame is fully decoded.
+ */
+ int row;
+ int col;
+} RefCntBuffer;
+
+struct RefBuffer_s {
+/*TODO(dkovalev): idx is not really required and should be removed, now it
+ *is used in vp9_onyxd_if.c
+ */
+ int idx;
+ struct PIC_BUFFER_CONFIG_s *buf;
+ /*struct scale_factors sf;*/
+} RefBuffer;
+
+struct InternalFrameBuffer_s {
+ uint8_t *data;
+ size_t size;
+ int in_use;
+} InternalFrameBuffer;
+
+struct InternalFrameBufferList_s {
+ int num_internal_frame_buffers;
+ struct InternalFrameBuffer_s *int_fb;
+} InternalFrameBufferList;
+
+struct BufferPool_s {
+/*Protect BufferPool from being accessed by several FrameWorkers at
+ *the same time during frame parallel decode.
+ *TODO(hkuang): Try to use atomic variable instead of locking the whole pool.
+ *
+ *Private data associated with the frame buffer callbacks.
+ *void *cb_priv;
+ *
+ *vpx_get_frame_buffer_cb_fn_t get_fb_cb;
+ *vpx_release_frame_buffer_cb_fn_t release_fb_cb;
+ */
+
+ struct RefCntBuffer_s frame_bufs[FRAME_BUFFERS];
+
+/*Frame buffers allocated internally by the codec.*/
+ struct InternalFrameBufferList_s int_frame_buffers;
+ unsigned long flags;
+ spinlock_t lock;
+
+} BufferPool;
+
+#define lock_buffer_pool(pool, flags) \
+ spin_lock_irqsave(&pool->lock, flags)
+
+#define unlock_buffer_pool(pool, flags) \
+ spin_unlock_irqrestore(&pool->lock, flags)
+
+struct VP9_Common_s {
+ enum vpx_color_space_t color_space;
+ int width;
+ int height;
+ int display_width;
+ int display_height;
+ int last_width;
+ int last_height;
+
+ int subsampling_x;
+ int subsampling_y;
+
+ int use_highbitdepth;/*Marks if we need to use 16bit frame buffers.*/
+
+ struct PIC_BUFFER_CONFIG_s *frame_to_show;
+ struct RefCntBuffer_s *prev_frame;
+
+ /*TODO(hkuang): Combine this with cur_buf in macroblockd.*/
+ struct RefCntBuffer_s *cur_frame;
+
+ int ref_frame_map[REF_FRAMES]; /* maps fb_idx to reference slot */
+
+ /*Prepare ref_frame_map for the next frame.
+ *Only used in frame parallel decode.
+ */
+ int next_ref_frame_map[REF_FRAMES];
+
+ /* TODO(jkoleszar): could expand active_ref_idx to 4,
+ *with 0 as intra, and roll new_fb_idx into it.
+ */
+
+ /*Each frame can reference REFS_PER_FRAME buffers*/
+ struct RefBuffer_s frame_refs[REFS_PER_FRAME];
+
+ int prev_fb_idx;
+ int new_fb_idx;
+ int cur_fb_idx_mmu;
+ /*last frame's frame type for motion search*/
+ enum FRAME_TYPE last_frame_type;
+ enum FRAME_TYPE frame_type;
+
+ int show_frame;
+ int last_show_frame;
+ int show_existing_frame;
+
+ /*Flag signaling that the frame is encoded using only INTRA modes.*/
+ uint8_t intra_only;
+ uint8_t last_intra_only;
+
+ int allow_high_precision_mv;
+
+ /*Flag signaling that the frame context should be reset to default
+ *values. 0 or 1 implies don't reset, 2 reset just the context
+ *specified in the frame header, 3 reset all contexts.
+ */
+ int reset_frame_context;
+
+ /*MBs, mb_rows/cols is in 16-pixel units; mi_rows/cols is in
+ * MODE_INFO (8-pixel) units.
+ */
+ int MBs;
+ int mb_rows, mi_rows;
+ int mb_cols, mi_cols;
+ int mi_stride;
+
+ /*Whether to use previous frame's motion vectors for prediction.*/
+ int use_prev_frame_mvs;
+
+ int refresh_frame_context; /* Two state 0 = NO, 1 = YES */
+
+ int ref_frame_sign_bias[MAX_REF_FRAMES]; /* Two state 0, 1 */
+
+ /*struct loopfilter lf;*/
+ /*struct segmentation seg;*/
+
+ /*TODO(hkuang):Remove this as it is the same as frame_parallel_decode*/
+ /* in pbi.*/
+ int frame_parallel_decode; /* frame-based threading.*/
+
+ /*Context probabilities for reference frame prediction*/
+ /*MV_REFERENCE_FRAME comp_fixed_ref;*/
+ /*MV_REFERENCE_FRAME comp_var_ref[2];*/
+ enum REFERENCE_MODE reference_mode;
+
+ /*FRAME_CONTEXT *fc; */ /* this frame entropy */
+ /*FRAME_CONTEXT *frame_contexts; */ /*FRAME_CONTEXTS*/
+ /*unsigned int frame_context_idx; *//* Context to use/update */
+ /*FRAME_COUNTS counts;*/
+
+ unsigned int current_video_frame;
+ enum BITSTREAM_PROFILE profile;
+
+ enum vpx_bit_depth_t bit_depth;
+
+ int error_resilient_mode;
+ int frame_parallel_decoding_mode;
+
+ int byte_alignment;
+ int skip_loop_filter;
+
+ /*External BufferPool passed from outside.*/
+ struct BufferPool_s *buffer_pool;
+
+ int above_context_alloc_cols;
+
+};
+
+static void set_canvas(struct VP9Decoder_s *pbi,
+ struct PIC_BUFFER_CONFIG_s *pic_config);
+static int prepare_display_buf(struct VP9Decoder_s *pbi,
+ struct PIC_BUFFER_CONFIG_s *pic_config);
+
+static void fill_frame_info(struct VP9Decoder_s *pbi,
+ struct PIC_BUFFER_CONFIG_s *frame,
+ unsigned int framesize,
+ unsigned int pts);
+
+static struct PIC_BUFFER_CONFIG_s *get_frame_new_buffer(struct VP9_Common_s *cm)
+{
+ return &cm->buffer_pool->frame_bufs[cm->new_fb_idx].buf;
+}
+
+static void ref_cnt_fb(struct RefCntBuffer_s *bufs, int *idx, int new_idx)
+{
+ const int ref_index = *idx;
+
+ if (ref_index >= 0 && bufs[ref_index].ref_count > 0) {
+ bufs[ref_index].ref_count--;
+ /*pr_info("[MMU DEBUG 2] dec ref_count[%d] : %d\r\n",
+ * ref_index, bufs[ref_index].ref_count);
+ */
+ }
+
+ *idx = new_idx;
+
+ bufs[new_idx].ref_count++;
+ /*pr_info("[MMU DEBUG 3] inc ref_count[%d] : %d\r\n",
+ * new_idx, bufs[new_idx].ref_count);
+ */
+}
+
+int vp9_release_frame_buffer(struct vpx_codec_frame_buffer_s *fb)
+{
+ struct InternalFrameBuffer_s *const int_fb =
+ (struct InternalFrameBuffer_s *)fb->priv;
+ if (int_fb)
+ int_fb->in_use = 0;
+ return 0;
+}
+
+static int compute_losless_comp_body_size(int width, int height,
+ uint8_t is_bit_depth_10);
+
+static void setup_display_size(struct VP9_Common_s *cm, union param_u *params,
+ int print_header_info)
+{
+ cm->display_width = cm->width;
+ cm->display_height = cm->height;
+ if (params->p.display_size_present) {
+ if (print_header_info)
+ pr_info(" * 1-bit display_size_present read : 1\n");
+ cm->display_width = params->p.display_width;
+ cm->display_height = params->p.display_height;
+ /*vp9_read_frame_size(rb, &cm->display_width,
+ * &cm->display_height);
+ */
+ } else {
+ if (print_header_info)
+ pr_info(" * 1-bit display_size_present read : 0\n");
+ }
+}
+
+
+uint8_t print_header_info = 0;
+
+struct buff_s {
+ u32 buf_start;
+ u32 buf_size;
+ u32 buf_end;
+} buff_t;
+
+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 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 seg_map;
+ struct buff_s mmu_vbh;
+ struct buff_s cm_header;
+ struct buff_s mpred_above;
+#ifdef MV_USE_FIXED_BUF
+ struct buff_s mpred_mv;
+#endif
+ struct buff_s rpm;
+ struct buff_s lmem;
+} BuffInfo_t;
+#ifdef MULTI_INSTANCE_SUPPORT
+#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
+#define DEC_RESULT_NEED_MORE_BUFFER 11
+#define DEC_V4L2_CONTINUE_DECODING 18
+
+#define DEC_S1_RESULT_NONE 0
+#define DEC_S1_RESULT_DONE 1
+#define DEC_S1_RESULT_FORCE_EXIT 2
+#define DEC_S1_RESULT_TEST_TRIGGER_DONE 0xf0
+
+#ifdef FB_DECODING_TEST_SCHEDULE
+#define TEST_SET_NONE 0
+#define TEST_SET_PIC_DONE 1
+#define TEST_SET_S2_DONE 2
+#endif
+
+static void vp9_work(struct work_struct *work);
+#endif
+struct loop_filter_info_n;
+struct loopfilter;
+struct segmentation;
+
+#ifdef SUPPORT_FB_DECODING
+static void mpred_process(struct VP9Decoder_s *pbi);
+static void vp9_s1_work(struct work_struct *work);
+
+struct stage_buf_s {
+ int index;
+ unsigned short rpm[RPM_END - RPM_BEGIN];
+};
+
+static unsigned int not_run2_ready[MAX_DECODE_INSTANCE_NUM];
+
+static unsigned int run2_count[MAX_DECODE_INSTANCE_NUM];
+
+#ifdef FB_DECODING_TEST_SCHEDULE
+u32 stage_buf_num; /* = 16;*/
+#else
+u32 stage_buf_num;
+#endif
+#endif
+
+struct VP9Decoder_s {
+#ifdef MULTI_INSTANCE_SUPPORT
+ unsigned char index;
+
+ 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;
+ struct work_struct recycle_mmu_work;
+ struct work_struct set_clk_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 save_buffer_mode;
+
+ int double_write_mode;
+#endif
+ long used_4k_num;
+
+ unsigned char m_ins_flag;
+ char *provider_name;
+ union param_u param;
+ int frame_count;
+ int pic_count;
+ u32 stat;
+ struct timer_list timer;
+ u32 frame_dur;
+ u32 frame_ar;
+ int fatal_error;
+ uint8_t init_flag;
+ uint8_t first_sc_checked;
+ uint8_t process_busy;
+#define PROC_STATE_INIT 0
+#define PROC_STATE_DECODESLICE 1
+#define PROC_STATE_SENDAGAIN 2
+ uint8_t process_state;
+ u32 ucode_pause_pos;
+
+ int show_frame_num;
+ struct buff_s mc_buf_spec;
+ struct dec_sysinfo vvp9_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;
+
+ void *prob_buffer_addr;
+ void *count_buffer_addr;
+ dma_addr_t prob_buffer_phy_addr;
+ dma_addr_t count_buffer_phy_addr;
+
+ void *frame_mmu_map_addr;
+ dma_addr_t frame_mmu_map_phy_addr;
+
+ unsigned int use_cma_flag;
+
+ struct BUF_s m_BUF[MAX_BUF_NUM];
+ struct MVBUF_s m_mv_BUF[MV_BUFFER_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;
+ int pic_num;
+ int lcu_size_log2;
+ unsigned int losless_comp_body_size;
+
+ u32 video_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 pts_unstable;
+ u32 frame_cnt_window;
+ u32 pts1, pts2;
+ u32 last_duration;
+ u32 duration_from_pts_done;
+ bool vp9_first_pts_ready;
+
+ 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;
+
+ /**/
+ struct VP9_Common_s common;
+ struct RefCntBuffer_s *cur_buf;
+ int refresh_frame_flags;
+ uint8_t need_resync;
+ uint8_t hold_ref_buf;
+ uint8_t ready_for_new_data;
+ struct BufferPool_s vp9_buffer_pool;
+
+ struct BuffInfo_s *work_space_buf;
+
+ struct buff_s *mc_buf;
+
+ unsigned int frame_width;
+ unsigned int frame_height;
+
+ unsigned short *rpm_ptr;
+ int init_pic_w;
+ int init_pic_h;
+ int lcu_total;
+ int lcu_size;
+
+ int slice_type;
+
+ int skip_flag;
+ int decode_idx;
+ int slice_idx;
+ uint8_t has_keyframe;
+ uint8_t wait_buf;
+ uint8_t error_flag;
+
+ /* bit 0, for decoding; bit 1, for displaying */
+ uint8_t ignore_bufmgr_error;
+ int PB_skip_mode;
+ int PB_skip_count_after_decoding;
+ /*hw*/
+
+ /*lf*/
+ int default_filt_lvl;
+ struct loop_filter_info_n *lfi;
+ struct loopfilter *lf;
+ struct segmentation *seg_4lf;
+ /**/
+ struct vdec_info *gvs;
+
+ u32 pre_stream_offset;
+
+ unsigned int dec_status;
+ u32 last_put_idx;
+ int new_frame_displayed;
+ void *mmu_box;
+ void *bmmu_box;
+ int mmu_enable;
+ struct vframe_master_display_colour_s vf_dp;
+ struct firmware_s *fw;
+ int max_pic_w;
+ int max_pic_h;
+#ifdef SUPPORT_FB_DECODING
+ int dec_s1_result;
+ int s1_test_cmd;
+ struct work_struct s1_work;
+ int used_stage_buf_num;
+ int s1_pos;
+ int s2_pos;
+ void *stage_mmu_map_addr;
+ dma_addr_t stage_mmu_map_phy_addr;
+ struct stage_buf_s *s1_buf;
+ struct stage_buf_s *s2_buf;
+ struct stage_buf_s *stage_bufs
+ [STAGE_MAX_BUFFERS];
+ unsigned char run2_busy;
+
+ int s1_mv_buf_index;
+ int s1_mv_buf_index_pre;
+ int s1_mv_buf_index_pre_pre;
+ unsigned long s1_mpred_mv_wr_start_addr;
+ unsigned long s1_mpred_mv_wr_start_addr_pre;
+ unsigned short s1_intra_only;
+ unsigned short s1_frame_type;
+ unsigned short s1_width;
+ unsigned short s1_height;
+ unsigned short s1_last_show_frame;
+ union param_u s1_param;
+ u8 back_not_run_ready;
+#endif
+ int need_cache_size;
+ u64 sc_start_time;
+ bool postproc_done;
+ int low_latency_flag;
+ bool no_head;
+ bool pic_list_init_done;
+ bool pic_list_init_done2;
+ bool is_used_v4l;
+ void *v4l2_ctx;
+ bool v4l_params_parsed;
+ int frameinfo_enable;
+ struct vframe_qos_s vframe_qos;
+ u32 mem_map_mode;
+ u32 dynamic_buf_num_margin;
+ struct vframe_s vframe_dummy;
+ u32 res_ch_flag;
+ /*struct VP9Decoder_s vp9_decoder;*/
+ union param_u vp9_param;
+ int sidebind_type;
+ int sidebind_channel_id;
+ bool enable_fence;
+ int fence_usage;
+ u32 frame_mode_pts_save[FRAME_BUFFERS];
+ u64 frame_mode_pts64_save[FRAME_BUFFERS];
+ int run_ready_min_buf_num;
+ int one_package_frame_cnt;
+ u32 error_frame_width;
+ u32 error_frame_height;
+ char vdec_name[32];
+ char pts_name[32];
+ char new_q_name[32];
+ char disp_q_name[32];
+};
+
+static int vp9_print(struct VP9Decoder_s *pbi,
+ int flag, const char *fmt, ...)
+{
+#define HEVC_PRINT_BUF 256
+ unsigned char buf[HEVC_PRINT_BUF];
+ int len = 0;
+
+ if (pbi == NULL ||
+ (flag == 0) ||
+ (debug & flag)) {
+ va_list args;
+
+ va_start(args, fmt);
+ if (pbi)
+ len = sprintf(buf, "[%d]", pbi->index);
+ vsnprintf(buf + len, HEVC_PRINT_BUF - len, fmt, args);
+ pr_debug("%s", buf);
+ va_end(args);
+ }
+ return 0;
+}
+
+static int is_oversize(int w, int h)
+{
+ int max = (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1)?
+ MAX_SIZE_8K : MAX_SIZE_4K;
+
+ if (w <= 0 || h <= 0)
+ return true;
+
+ if (h != 0 && (w > max / h))
+ return true;
+
+ return false;
+}
+
+static int v4l_alloc_and_config_pic(struct VP9Decoder_s *pbi,
+ struct PIC_BUFFER_CONFIG_s *pic);
+
+static void resize_context_buffers(struct VP9Decoder_s *pbi,
+ struct VP9_Common_s *cm, int width, int height)
+{
+ if (cm->width != width || cm->height != height) {
+ /* to do ..*/
+ if (pbi != NULL) {
+ pbi->vp9_first_pts_ready = 0;
+ pbi->duration_from_pts_done = 0;
+ }
+ pr_info("%s (%d,%d)=>(%d,%d)\r\n", __func__, cm->width,
+ cm->height, width, height);
+ cm->width = width;
+ cm->height = height;
+ }
+ /*
+ *if (cm->cur_frame->mvs == NULL ||
+ * cm->mi_rows > cm->cur_frame->mi_rows ||
+ * cm->mi_cols > cm->cur_frame->mi_cols) {
+ * resize_mv_buffer(cm);
+ *}
+ */
+}
+
+static int valid_ref_frame_size(int ref_width, int ref_height,
+ int this_width, int this_height) {
+ return 2 * this_width >= ref_width &&
+ 2 * this_height >= ref_height &&
+ this_width <= 16 * ref_width &&
+ this_height <= 16 * ref_height;
+}
+
+/*
+ *static int valid_ref_frame_img_fmt(enum vpx_bit_depth_t ref_bit_depth,
+ * int ref_xss, int ref_yss,
+ * enum vpx_bit_depth_t this_bit_depth,
+ * int this_xss, int this_yss) {
+ * return ref_bit_depth == this_bit_depth && ref_xss == this_xss &&
+ * ref_yss == this_yss;
+ *}
+ */
+
+
+static int setup_frame_size(
+ struct VP9Decoder_s *pbi,
+ struct VP9_Common_s *cm, union param_u *params,
+ unsigned int *mmu_index_adr,
+ int print_header_info) {
+ int width, height;
+ struct BufferPool_s * const pool = cm->buffer_pool;
+ struct PIC_BUFFER_CONFIG_s *ybf;
+ int ret = 0;
+
+ width = params->p.width;
+ height = params->p.height;
+ if (is_oversize(width, height)) {
+ pbi->error_frame_width = width;
+ pbi->error_frame_height = height;
+ vp9_print(pbi, 0, "%s, Error: Invalid frame size\n", __func__);
+ return -1;
+ }
+ pbi->error_frame_width = 0;
+ pbi->error_frame_height = 0;
+
+ /*vp9_read_frame_size(rb, &width, &height);*/
+ if (print_header_info)
+ pr_info(" * 16-bits w read : %d (width : %d)\n", width, height);
+ if (print_header_info)
+ pr_info
+ (" * 16-bits h read : %d (height : %d)\n", width, height);
+
+ WRITE_VREG(HEVC_PARSER_PICTURE_SIZE, (height << 16) | width);
+#ifdef VP9_10B_HED_FB
+ WRITE_VREG(HEVC_ASSIST_PIC_SIZE_FB_READ, (height << 16) | width);
+#endif
+ if (pbi->mmu_enable && ((pbi->double_write_mode & 0x10) == 0)) {
+ ret = vp9_alloc_mmu(pbi,
+ cm->new_fb_idx,
+ params->p.width,
+ params->p.height,
+ params->p.bit_depth,
+ mmu_index_adr);
+ if (ret != 0) {
+ pr_err("can't alloc need mmu1,idx %d ret =%d\n",
+ cm->new_fb_idx,
+ ret);
+ return ret;
+ }
+ cm->cur_fb_idx_mmu = cm->new_fb_idx;
+ }
+
+ resize_context_buffers(pbi, cm, width, height);
+ setup_display_size(cm, params, print_header_info);
+#if 0
+ lock_buffer_pool(pool);
+ if (vp9_realloc_frame_buffer(
+ get_frame_new_buffer(cm), cm->width, cm->height,
+ cm->subsampling_x, cm->subsampling_y,
+#if CONFIG_VP9_HIGHBITDEPTH
+ cm->use_highbitdepth,
+#endif
+ VP9_DEC_BORDER_IN_PIXELS,
+ cm->byte_alignment,
+ &pool->frame_bufs[cm->new_fb_idx].raw_frame_buffer,
+ pool->get_fb_cb, pool->cb_priv)) {
+ unlock_buffer_pool(pool);
+ vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
+ "Failed to allocate frame buffer");
+ }
+ unlock_buffer_pool(pool);
+#else
+ /* porting */
+ ybf = get_frame_new_buffer(cm);
+ if (!ybf)
+ return -1;
+
+ ybf->y_crop_width = width;
+ ybf->y_crop_height = height;
+ ybf->bit_depth = params->p.bit_depth;
+#endif
+ pool->frame_bufs[cm->new_fb_idx].buf.subsampling_x = cm->subsampling_x;
+ pool->frame_bufs[cm->new_fb_idx].buf.subsampling_y = cm->subsampling_y;
+ pool->frame_bufs[cm->new_fb_idx].buf.bit_depth =
+ (unsigned int)cm->bit_depth;
+ pool->frame_bufs[cm->new_fb_idx].buf.color_space = cm->color_space;
+ return ret;
+}
+
+static int setup_frame_size_with_refs(
+ struct VP9Decoder_s *pbi,
+ struct VP9_Common_s *cm,
+ union param_u *params,
+ unsigned int *mmu_index_adr,
+ int print_header_info) {
+
+ int width, height;
+ int found = 0, i;
+ int has_valid_ref_frame = 0;
+ struct PIC_BUFFER_CONFIG_s *ybf;
+ struct BufferPool_s * const pool = cm->buffer_pool;
+ int ret = 0;
+
+ for (i = 0; i < REFS_PER_FRAME; ++i) {
+ if ((params->p.same_frame_size >>
+ (REFS_PER_FRAME - i - 1)) & 0x1) {
+ struct PIC_BUFFER_CONFIG_s *const buf =
+ cm->frame_refs[i].buf;
+ /*if (print_header_info)
+ * pr_info
+ * ("1-bit same_frame_size[%d] read : 1\n", i);
+ */
+ width = buf->y_crop_width;
+ height = buf->y_crop_height;
+ /*if (print_header_info)
+ * pr_info
+ * (" - same_frame_size width : %d\n", width);
+ */
+ /*if (print_header_info)
+ * pr_info
+ * (" - same_frame_size height : %d\n", height);
+ */
+ found = 1;
+ break;
+ } else {
+ /*if (print_header_info)
+ * pr_info
+ * ("1-bit same_frame_size[%d] read : 0\n", i);
+ */
+ }
+ }
+
+ if (!found) {
+ /*vp9_read_frame_size(rb, &width, &height);*/
+ width = params->p.width;
+ height = params->p.height;
+ /*if (print_header_info)
+ * pr_info
+ * (" * 16-bits w read : %d (width : %d)\n",
+ * width, height);
+ *if (print_header_info)
+ * pr_info
+ * (" * 16-bits h read : %d (height : %d)\n",
+ * width, height);
+ */
+ }
+
+ if (is_oversize(width, height)) {
+ pbi->error_frame_width = width;
+ pbi->error_frame_height = height;
+ vp9_print(pbi, 0, "%s, Error: Invalid frame size\n", __func__);
+ return -1;
+ }
+ pbi->error_frame_width = 0;
+ pbi->error_frame_height = 0;
+
+ params->p.width = width;
+ params->p.height = height;
+
+ WRITE_VREG(HEVC_PARSER_PICTURE_SIZE, (height << 16) | width);
+ if (pbi->mmu_enable && ((pbi->double_write_mode & 0x10) == 0)) {
+ /*if(cm->prev_fb_idx >= 0) release_unused_4k(cm->prev_fb_idx);
+ *cm->prev_fb_idx = cm->new_fb_idx;
+ */
+ /* pr_info
+ * ("[DEBUG DEBUG]Before alloc_mmu,
+ * prev_fb_idx : %d, new_fb_idx : %d\r\n",
+ * cm->prev_fb_idx, cm->new_fb_idx);
+ */
+ ret = vp9_alloc_mmu(pbi, cm->new_fb_idx,
+ params->p.width, params->p.height,
+ params->p.bit_depth, mmu_index_adr);
+ if (ret != 0) {
+ pr_err("can't alloc need mmu,idx %d\r\n",
+ cm->new_fb_idx);
+ return ret;
+ }
+ cm->cur_fb_idx_mmu = cm->new_fb_idx;
+ }
+
+ /*Check to make sure at least one of frames that this frame references
+ *has valid dimensions.
+ */
+ for (i = 0; i < REFS_PER_FRAME; ++i) {
+ struct RefBuffer_s * const ref_frame = &cm->frame_refs[i];
+
+ has_valid_ref_frame |=
+ valid_ref_frame_size(ref_frame->buf->y_crop_width,
+ ref_frame->buf->y_crop_height,
+ width, height);
+ }
+ if (!has_valid_ref_frame) {
+ pr_err("Error: Referenced frame has invalid size\r\n");
+ return -1;
+ }
+#if 0
+ for (i = 0; i < REFS_PER_FRAME; ++i) {
+ struct RefBuffer_s * const ref_frame =
+ &cm->frame_refs[i];
+ if (!valid_ref_frame_img_fmt(
+ ref_frame->buf->bit_depth,
+ ref_frame->buf->subsampling_x,
+ ref_frame->buf->subsampling_y,
+ cm->bit_depth,
+ cm->subsampling_x,
+ cm->subsampling_y))
+ pr_err
+ ("Referenced frame incompatible color fmt\r\n");
+ return -1;
+ }
+#endif
+ resize_context_buffers(pbi, cm, width, height);
+ setup_display_size(cm, params, print_header_info);
+
+#if 0
+ lock_buffer_pool(pool);
+ if (vp9_realloc_frame_buffer(
+ get_frame_new_buffer(cm), cm->width, cm->height,
+ cm->subsampling_x, cm->subsampling_y,
+#if CONFIG_VP9_HIGHBITDEPTH
+ cm->use_highbitdepth,
+#endif
+ VP9_DEC_BORDER_IN_PIXELS,
+ cm->byte_alignment,
+ &pool->frame_bufs[cm->new_fb_idx].raw_frame_buffer,
+ pool->get_fb_cb,
+ pool->cb_priv)) {
+ unlock_buffer_pool(pool);
+ vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
+ "Failed to allocate frame buffer");
+ }
+ unlock_buffer_pool(pool);
+#else
+ /* porting */
+ ybf = get_frame_new_buffer(cm);
+ if (!ybf)
+ return -1;
+
+ ybf->y_crop_width = width;
+ ybf->y_crop_height = height;
+ ybf->bit_depth = params->p.bit_depth;
+#endif
+ pool->frame_bufs[cm->new_fb_idx].buf.subsampling_x = cm->subsampling_x;
+ pool->frame_bufs[cm->new_fb_idx].buf.subsampling_y = cm->subsampling_y;
+ pool->frame_bufs[cm->new_fb_idx].buf.bit_depth =
+ (unsigned int)cm->bit_depth;
+ pool->frame_bufs[cm->new_fb_idx].buf.color_space = cm->color_space;
+ return ret;
+}
+
+static inline bool close_to(int a, int b, int m)
+{
+ return (abs(a - b) < m) ? true : false;
+}
+
+#ifdef MULTI_INSTANCE_SUPPORT
+static int vp9_print_cont(struct VP9Decoder_s *pbi,
+ int flag, const char *fmt, ...)
+{
+ unsigned char buf[HEVC_PRINT_BUF];
+ int len = 0;
+
+ if (pbi == NULL ||
+ (flag == 0) ||
+ (debug & flag)) {
+ va_list args;
+
+ va_start(args, fmt);
+ vsnprintf(buf + len, HEVC_PRINT_BUF - len, fmt, args);
+ pr_debug("%s", buf);
+ va_end(args);
+ }
+ return 0;
+}
+
+static void trigger_schedule(struct VP9Decoder_s *pbi)
+{
+ if (pbi->is_used_v4l) {
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(pbi->v4l2_ctx);
+
+ if (ctx->param_sets_from_ucode &&
+ !pbi->v4l_params_parsed)
+ vdec_v4l_write_frame_sync(ctx);
+ }
+
+ if (pbi->vdec_cb)
+ pbi->vdec_cb(hw_to_vdec(pbi), pbi->vdec_cb_arg);
+}
+
+static void reset_process_time(struct VP9Decoder_s *pbi)
+{
+ if (pbi->start_process_time) {
+ unsigned process_time =
+ 1000 * (jiffies - pbi->start_process_time) / HZ;
+ pbi->start_process_time = 0;
+ if (process_time > max_process_time[pbi->index])
+ max_process_time[pbi->index] = process_time;
+ }
+}
+
+static void start_process_time(struct VP9Decoder_s *pbi)
+{
+ pbi->start_process_time = jiffies;
+ pbi->decode_timeout_count = 0;
+ pbi->last_lcu_idx = 0;
+}
+
+static void timeout_process(struct VP9Decoder_s *pbi)
+{
+ pbi->timeout_num++;
+ amhevc_stop();
+ vp9_print(pbi,
+ 0, "%s decoder timeout\n", __func__);
+
+ pbi->dec_result = DEC_RESULT_DONE;
+ reset_process_time(pbi);
+ vdec_schedule_work(&pbi->work);
+}
+
+static u32 get_valid_double_write_mode(struct VP9Decoder_s *pbi)
+{
+ return ((double_write_mode & 0x80000000) == 0) ?
+ pbi->double_write_mode :
+ (double_write_mode & 0x7fffffff);
+}
+
+static int v4l_parser_get_double_write_mode(struct VP9Decoder_s *pbi)
+{
+ u32 valid_dw_mode = get_valid_double_write_mode(pbi);
+ u32 dw;
+ int w, h;
+
+ /* mask for supporting double write value bigger than 0x100 */
+ if (valid_dw_mode & 0xffffff00) {
+ w = pbi->frame_width;
+ h = pbi->frame_height;
+
+ dw = 0x1; /*1:1*/
+ switch (valid_dw_mode) {
+ case 0x100:
+ if (w > 1920 && h > 1088)
+ dw = 0x4; /*1:2*/
+ break;
+ case 0x200:
+ if (w > 1920 && h > 1088)
+ dw = 0x2; /*1:4*/
+ break;
+ case 0x300:
+ if (w > 1280 && h > 720)
+ dw = 0x4; /*1:2*/
+ break;
+ default:
+ break;
+ }
+ return dw;
+ }
+
+ return valid_dw_mode;
+}
+
+
+static int get_double_write_mode(struct VP9Decoder_s *pbi)
+{
+ u32 valid_dw_mode = get_valid_double_write_mode(pbi);
+ u32 dw;
+ int w, h;
+ struct VP9_Common_s *cm = &pbi->common;
+ struct PIC_BUFFER_CONFIG_s *cur_pic_config;
+
+ /* mask for supporting double write value bigger than 0x100 */
+ if (valid_dw_mode & 0xffffff00) {
+ if (!cm->cur_frame)
+ return 1;/*no valid frame,*/
+ cur_pic_config = &cm->cur_frame->buf;
+ w = cur_pic_config->y_crop_width;
+ h = cur_pic_config->y_crop_height;
+
+ dw = 0x1; /*1:1*/
+ switch (valid_dw_mode) {
+ case 0x100:
+ if (w > 1920 && h > 1088)
+ dw = 0x4; /*1:2*/
+ break;
+ case 0x200:
+ if (w > 1920 && h > 1088)
+ dw = 0x2; /*1:4*/
+ break;
+ case 0x300:
+ if (w > 1280 && h > 720)
+ dw = 0x4; /*1:2*/
+ break;
+ default:
+ break;
+ }
+ return dw;
+ }
+
+ return valid_dw_mode;
+}
+
+/* for double write buf alloc */
+static int get_double_write_mode_init(struct VP9Decoder_s *pbi)
+{
+ u32 valid_dw_mode = get_valid_double_write_mode(pbi);
+ u32 dw;
+ int w = pbi->init_pic_w;
+ int h = pbi->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;
+}
+#endif
+
+static int get_double_write_ratio(struct VP9Decoder_s *pbi,
+ int dw_mode)
+{
+ int ratio = 1;
+ if ((dw_mode == 2) ||
+ (dw_mode == 3))
+ ratio = 4;
+ else if (dw_mode == 4)
+ ratio = 2;
+ return ratio;
+}
+
+//#define MAX_4K_NUM 0x1200
+
+int vp9_alloc_mmu(
+ struct VP9Decoder_s *pbi,
+ 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 == VPX_BITS_10);
+ int picture_size;
+ int cur_mmu_4k_number, max_frame_num;
+ if (!pbi->mmu_box) {
+ pr_err("error no mmu box!\n");
+ return -1;
+ }
+ if (get_double_write_mode(pbi) == 0x10)
+ return 0;
+ if (bit_depth >= VPX_BITS_12) {
+ pbi->fatal_error = DECODER_FATAL_ERROR_SIZE_OVERFLOW;
+ pr_err("fatal_error, un support bit depth 12!\n\n");
+ return -1;
+ }
+ picture_size = compute_losless_comp_body_size(pic_width, pic_height,
+ bit_depth_10);
+ cur_mmu_4k_number = ((picture_size + (1 << 12) - 1) >> 12);
+
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1)
+ max_frame_num = MAX_FRAME_8K_NUM;
+ else
+ max_frame_num = MAX_FRAME_4K_NUM;
+
+ 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(
+ pbi->mmu_box,
+ cur_buf_idx,
+ cur_mmu_4k_number,
+ mmu_index_adr);
+}
+
+
+#ifndef MV_USE_FIXED_BUF
+static void dealloc_mv_bufs(struct VP9Decoder_s *pbi)
+{
+ int i;
+ for (i = 0; i < MV_BUFFER_NUM; i++) {
+ if (pbi->m_mv_BUF[i].start_adr) {
+ if (debug)
+ pr_info(
+ "dealloc mv buf(%d) adr %ld size 0x%x used_flag %d\n",
+ i, pbi->m_mv_BUF[i].start_adr,
+ pbi->m_mv_BUF[i].size,
+ pbi->m_mv_BUF[i].used_flag);
+ decoder_bmmu_box_free_idx(
+ pbi->bmmu_box,
+ MV_BUFFER_IDX(i));
+ pbi->m_mv_BUF[i].start_adr = 0;
+ pbi->m_mv_BUF[i].size = 0;
+ pbi->m_mv_BUF[i].used_flag = 0;
+ }
+ }
+}
+
+static int alloc_mv_buf(struct VP9Decoder_s *pbi,
+ int i, int size)
+{
+ int ret = 0;
+
+ if (pbi->m_mv_BUF[i].start_adr &&
+ size > pbi->m_mv_BUF[i].size) {
+ dealloc_mv_bufs(pbi);
+ } else if (pbi->m_mv_BUF[i].start_adr)
+ return 0;
+
+ if (decoder_bmmu_box_alloc_buf_phy
+ (pbi->bmmu_box,
+ MV_BUFFER_IDX(i), size,
+ DRIVER_NAME,
+ &pbi->m_mv_BUF[i].start_adr) < 0) {
+ pbi->m_mv_BUF[i].start_adr = 0;
+ ret = -1;
+ } else {
+ pbi->m_mv_BUF[i].size = size;
+ pbi->m_mv_BUF[i].used_flag = 0;
+ ret = 0;
+ if (debug) {
+ pr_info(
+ "MV Buffer %d: start_adr %p size %x\n",
+ i,
+ (void *)pbi->m_mv_BUF[i].start_adr,
+ pbi->m_mv_BUF[i].size);
+ }
+ }
+ return ret;
+}
+
+static int cal_mv_buf_size(struct VP9Decoder_s *pbi, int pic_width, int pic_height)
+{
+ int lcu_size = 64; /*fixed 64*/
+ int pic_width_64 = (pic_width + 63) & (~0x3f);
+ int pic_height_32 = (pic_height + 31) & (~0x1f);
+ int pic_width_lcu = (pic_width_64 % lcu_size) ?
+ pic_width_64 / lcu_size + 1
+ : pic_width_64 / lcu_size;
+ int pic_height_lcu = (pic_height_32 % lcu_size) ?
+ pic_height_32 / lcu_size + 1
+ : pic_height_32 / lcu_size;
+ int lcu_total = pic_width_lcu * pic_height_lcu;
+ int size_a = lcu_total * 36 * 16;
+ int size_b = pic_width_lcu * 16 *
+ ((pic_height_lcu >> 3) + (pic_height_lcu & 0x7));
+ int size = (size_a + size_b + 0xffff) &
+ (~0xffff);
+
+ return size;
+}
+
+
+static int init_mv_buf_list(struct VP9Decoder_s *pbi)
+{
+ int i;
+ int ret = 0;
+ int count = MV_BUFFER_NUM;
+ int pic_width = pbi->init_pic_w;
+ int pic_height = pbi->init_pic_h;
+ int size = cal_mv_buf_size(pbi, pic_width, pic_height);
+
+ if (mv_buf_dynamic_alloc)
+ return 0;
+
+ if (mv_buf_margin > 0)
+ count = REF_FRAMES + mv_buf_margin;
+
+ if (pbi->init_pic_w > 2048 && pbi->init_pic_h > 1088)
+ count = REF_FRAMES_4K + mv_buf_margin;
+
+ if (debug) {
+ pr_info("%s w:%d, h:%d, count: %d\n",
+ __func__, pbi->init_pic_w, pbi->init_pic_h, count);
+ }
+
+ for (i = 0;
+ i < count && i < MV_BUFFER_NUM; i++) {
+ if (alloc_mv_buf(pbi, i, size) < 0) {
+ ret = -1;
+ break;
+ }
+ }
+ return ret;
+}
+
+static int get_mv_buf(struct VP9Decoder_s *pbi,
+ struct PIC_BUFFER_CONFIG_s *pic_config)
+{
+ int i;
+ int ret = -1;
+ if (mv_buf_dynamic_alloc) {
+ union param_u *params = &pbi->vp9_param;
+ int size = cal_mv_buf_size(pbi,
+ params->p.width, params->p.height);
+ for (i = 0; i < MV_BUFFER_NUM; i++) {
+ if (pbi->m_mv_BUF[i].start_adr == 0) {
+ ret = i;
+ break;
+ }
+ }
+ if (i == MV_BUFFER_NUM) {
+ pr_info(
+ "%s: Error, mv buf MV_BUFFER_NUM is not enough\n",
+ __func__);
+ return ret;
+ }
+
+ if (alloc_mv_buf(pbi, ret, size) >= 0) {
+ pic_config->mv_buf_index = ret;
+ pic_config->mpred_mv_wr_start_addr =
+ (pbi->m_mv_BUF[ret].start_adr + 0xffff) &
+ (~0xffff);
+ pic_config->mv_size = size;
+
+ if (debug & VP9_DEBUG_BUFMGR_MORE)
+ pr_info(
+ "%s alloc => %d (%ld) size 0x%x\n",
+ __func__, ret,
+ pic_config->mpred_mv_wr_start_addr,
+ pic_config->mv_size);
+ } else {
+ pr_info(
+ "%s: Error, mv buf alloc fail\n",
+ __func__);
+ }
+ return ret;
+ }
+
+ for (i = 0; i < MV_BUFFER_NUM; i++) {
+ if (pbi->m_mv_BUF[i].start_adr &&
+ pbi->m_mv_BUF[i].used_flag == 0) {
+ pbi->m_mv_BUF[i].used_flag = 1;
+ ret = i;
+ break;
+ }
+ }
+
+ if (ret >= 0) {
+ pic_config->mv_buf_index = ret;
+ pic_config->mpred_mv_wr_start_addr =
+ (pbi->m_mv_BUF[ret].start_adr + 0xffff) &
+ (~0xffff);
+ pic_config->mv_size = pbi->m_mv_BUF[ret].size;
+ if (debug & VP9_DEBUG_BUFMGR_MORE)
+ pr_info(
+ "%s => %d (%ld) size 0x%x\n",
+ __func__, ret,
+ pic_config->mpred_mv_wr_start_addr,
+ pic_config->mv_size);
+ } else {
+ pr_info(
+ "%s: Error, mv buf is not enough\n",
+ __func__);
+ }
+ return ret;
+}
+
+static void put_mv_buf(struct VP9Decoder_s *pbi,
+ int *mv_buf_index)
+{
+ int i = *mv_buf_index;
+ if (i >= MV_BUFFER_NUM) {
+ if (debug & VP9_DEBUG_BUFMGR_MORE)
+ pr_info(
+ "%s: index %d beyond range\n",
+ __func__, i);
+ return;
+ }
+
+ if (mv_buf_dynamic_alloc) {
+ if (pbi->m_mv_BUF[i].start_adr) {
+ if (debug)
+ pr_info(
+ "dealloc mv buf(%d) adr %ld size 0x%x used_flag %d\n",
+ i, pbi->m_mv_BUF[i].start_adr,
+ pbi->m_mv_BUF[i].size,
+ pbi->m_mv_BUF[i].used_flag);
+ decoder_bmmu_box_free_idx(
+ pbi->bmmu_box,
+ MV_BUFFER_IDX(i));
+ pbi->m_mv_BUF[i].start_adr = 0;
+ pbi->m_mv_BUF[i].size = 0;
+ pbi->m_mv_BUF[i].used_flag = 0;
+ }
+ *mv_buf_index = -1;
+ return;
+ }
+ if (debug & VP9_DEBUG_BUFMGR_MORE)
+ pr_info(
+ "%s(%d): used_flag(%d)\n",
+ __func__, i,
+ pbi->m_mv_BUF[i].used_flag);
+
+ *mv_buf_index = -1;
+ if (pbi->m_mv_BUF[i].start_adr &&
+ pbi->m_mv_BUF[i].used_flag)
+ pbi->m_mv_BUF[i].used_flag = 0;
+}
+
+static void put_un_used_mv_bufs(struct VP9Decoder_s *pbi)
+{
+ struct VP9_Common_s *const cm = &pbi->common;
+ struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs;
+ int i;
+ for (i = 0; i < pbi->used_buf_num; ++i) {
+ if ((frame_bufs[i].ref_count == 0) &&
+ (frame_bufs[i].buf.index != -1) &&
+ (frame_bufs[i].buf.mv_buf_index >= 0)
+ )
+ put_mv_buf(pbi, &frame_bufs[i].buf.mv_buf_index);
+ }
+}
+
+#ifdef SUPPORT_FB_DECODING
+static bool mv_buf_available(struct VP9Decoder_s *pbi)
+{
+ int i;
+ bool ret = 0;
+ for (i = 0; i < MV_BUFFER_NUM; i++) {
+ if (pbi->m_mv_BUF[i].start_adr &&
+ pbi->m_mv_BUF[i].used_flag == 0) {
+ ret = 1;
+ break;
+ }
+ }
+ return ret;
+}
+#endif
+#endif
+
+#ifdef SUPPORT_FB_DECODING
+static void init_stage_buf(struct VP9Decoder_s *pbi)
+{
+ uint i;
+ for (i = 0; i < STAGE_MAX_BUFFERS
+ && i < stage_buf_num; i++) {
+ pbi->stage_bufs[i] =
+ vmalloc(sizeof(struct stage_buf_s));
+ if (pbi->stage_bufs[i] == NULL) {
+ vp9_print(pbi,
+ 0, "%s vmalloc fail\n", __func__);
+ break;
+ }
+ pbi->stage_bufs[i]->index = i;
+ }
+ pbi->used_stage_buf_num = i;
+ pbi->s1_pos = 0;
+ pbi->s2_pos = 0;
+ pbi->s1_buf = NULL;
+ pbi->s2_buf = NULL;
+ pbi->s1_mv_buf_index = FRAME_BUFFERS;
+ pbi->s1_mv_buf_index_pre = FRAME_BUFFERS;
+ pbi->s1_mv_buf_index_pre_pre = FRAME_BUFFERS;
+
+ if (pbi->used_stage_buf_num > 0)
+ vp9_print(pbi,
+ 0, "%s 2 stage decoding buf %d\n",
+ __func__,
+ pbi->used_stage_buf_num);
+}
+
+static void uninit_stage_buf(struct VP9Decoder_s *pbi)
+{
+ int i;
+ for (i = 0; i < pbi->used_stage_buf_num; i++) {
+ if (pbi->stage_bufs[i])
+ vfree(pbi->stage_bufs[i]);
+ pbi->stage_bufs[i] = NULL;
+ }
+ pbi->used_stage_buf_num = 0;
+ pbi->s1_pos = 0;
+ pbi->s2_pos = 0;
+ pbi->s1_buf = NULL;
+ pbi->s2_buf = NULL;
+}
+
+static int get_s1_buf(
+ struct VP9Decoder_s *pbi)
+{
+ struct stage_buf_s *buf = NULL;
+ int ret = -1;
+ int buf_page_num = MAX_STAGE_PAGE_NUM;
+ int next_s1_pos = pbi->s1_pos + 1;
+
+ if (next_s1_pos >= pbi->used_stage_buf_num)
+ next_s1_pos = 0;
+ if (next_s1_pos == pbi->s2_pos) {
+ pbi->s1_buf = NULL;
+ return ret;
+ }
+
+ buf = pbi->stage_bufs[pbi->s1_pos];
+ ret = decoder_mmu_box_alloc_idx(
+ pbi->mmu_box,
+ buf->index,
+ buf_page_num,
+ pbi->stage_mmu_map_addr);
+ if (ret < 0) {
+ vp9_print(pbi, 0,
+ "%s decoder_mmu_box_alloc fail for index %d (s1_pos %d s2_pos %d)\n",
+ __func__, buf->index,
+ pbi->s1_pos, pbi->s2_pos);
+ buf = NULL;
+ } else {
+ vp9_print(pbi, VP9_DEBUG_2_STAGE,
+ "%s decoder_mmu_box_alloc %d page for index %d (s1_pos %d s2_pos %d)\n",
+ __func__, buf_page_num, buf->index,
+ pbi->s1_pos, pbi->s2_pos);
+ }
+ pbi->s1_buf = buf;
+ return ret;
+}
+
+static void inc_s1_pos(struct VP9Decoder_s *pbi)
+{
+ struct stage_buf_s *buf =
+ pbi->stage_bufs[pbi->s1_pos];
+
+ int used_page_num =
+#ifdef FB_DECODING_TEST_SCHEDULE
+ MAX_STAGE_PAGE_NUM/2;
+#else
+ (READ_VREG(HEVC_ASSIST_HED_FB_W_CTL) >> 16);
+#endif
+ decoder_mmu_box_free_idx_tail(pbi->mmu_box,
+ FRAME_BUFFERS + buf->index, used_page_num);
+
+ pbi->s1_pos++;
+ if (pbi->s1_pos >= pbi->used_stage_buf_num)
+ pbi->s1_pos = 0;
+
+ vp9_print(pbi, VP9_DEBUG_2_STAGE,
+ "%s (used_page_num %d) for index %d (s1_pos %d s2_pos %d)\n",
+ __func__, used_page_num, buf->index,
+ pbi->s1_pos, pbi->s2_pos);
+}
+
+#define s2_buf_available(pbi) (pbi->s1_pos != pbi->s2_pos)
+
+static int get_s2_buf(
+ struct VP9Decoder_s *pbi)
+{
+ int ret = -1;
+ struct stage_buf_s *buf = NULL;
+ if (s2_buf_available(pbi)) {
+ buf = pbi->stage_bufs[pbi->s2_pos];
+ vp9_print(pbi, VP9_DEBUG_2_STAGE,
+ "%s for index %d (s1_pos %d s2_pos %d)\n",
+ __func__, buf->index,
+ pbi->s1_pos, pbi->s2_pos);
+ pbi->s2_buf = buf;
+ ret = 0;
+ }
+ return ret;
+}
+
+static void inc_s2_pos(struct VP9Decoder_s *pbi)
+{
+ struct stage_buf_s *buf =
+ pbi->stage_bufs[pbi->s2_pos];
+ decoder_mmu_box_free_idx(pbi->mmu_box,
+ FRAME_BUFFERS + buf->index);
+ pbi->s2_pos++;
+ if (pbi->s2_pos >= pbi->used_stage_buf_num)
+ pbi->s2_pos = 0;
+ vp9_print(pbi, VP9_DEBUG_2_STAGE,
+ "%s for index %d (s1_pos %d s2_pos %d)\n",
+ __func__, buf->index,
+ pbi->s1_pos, pbi->s2_pos);
+}
+
+static int get_free_stage_buf_num(struct VP9Decoder_s *pbi)
+{
+ int num;
+ if (pbi->s1_pos >= pbi->s2_pos)
+ num = pbi->used_stage_buf_num -
+ (pbi->s1_pos - pbi->s2_pos) - 1;
+ else
+ num = (pbi->s2_pos - pbi->s1_pos) - 1;
+ return num;
+}
+
+#ifndef FB_DECODING_TEST_SCHEDULE
+static DEFINE_SPINLOCK(fb_core_spin_lock);
+
+static u8 is_s2_decoding_finished(struct VP9Decoder_s *pbi)
+{
+ /* to do: VLSI review
+ completion of last LCU decoding in BACK
+ */
+ return 1;
+}
+
+static void start_s1_decoding(struct VP9Decoder_s *pbi)
+{
+ /* to do: VLSI review
+ after parser, how to start LCU decoding in BACK
+ */
+}
+
+static void fb_reset_core(struct vdec_s *vdec, u32 mask)
+{
+ /* to do: VLSI review
+ 1. how to disconnect DMC for FRONT and BACK
+ 2. reset bit 13, 24, FRONT or BACK ??
+ */
+
+ unsigned long flags;
+ u32 reset_bits = 0;
+ if (mask & HW_MASK_FRONT)
+ WRITE_VREG(HEVC_STREAM_CONTROL, 0);
+ spin_lock_irqsave(&fb_core_spin_lock, flags);
+ codec_dmcbus_write(DMC_REQ_CTRL,
+ codec_dmcbus_read(DMC_REQ_CTRL) & (~(1 << 4)));
+ spin_unlock_irqrestore(&fb_core_spin_lock, flags);
+
+ while (!(codec_dmcbus_read(DMC_CHAN_STS)
+ & (1 << 4)))
+ ;
+
+ if ((mask & HW_MASK_FRONT) &&
+ input_frame_based(vdec))
+ WRITE_VREG(HEVC_STREAM_CONTROL, 0);
+
+ /*
+ * 2: assist
+ * 3: parser
+ * 4: parser_state
+ * 8: dblk
+ * 11:mcpu
+ * 12:ccpu
+ * 13:ddr
+ * 14:iqit
+ * 15:ipp
+ * 17:qdct
+ * 18:mpred
+ * 19:sao
+ * 24:hevc_afifo
+ */
+ if (mask & HW_MASK_FRONT) {
+ reset_bits =
+ (1<<3)|(1<<4)|(1<<11)|
+ (1<<12)|(1<<18);
+ }
+ if (mask & HW_MASK_BACK) {
+ reset_bits =
+ (1<<8)|(1<<13)|(1<<14)|(1<<15)|
+ (1<<17)|(1<<19)|(1<<24);
+ }
+ WRITE_VREG(DOS_SW_RESET3, reset_bits);
+#if 0
+ (1<<3)|(1<<4)|(1<<8)|(1<<11)|
+ (1<<12)|(1<<13)|(1<<14)|(1<<15)|
+ (1<<17)|(1<<18)|(1<<19)|(1<<24);
+#endif
+ WRITE_VREG(DOS_SW_RESET3, 0);
+
+
+ spin_lock_irqsave(&fb_core_spin_lock, flags);
+ codec_dmcbus_write(DMC_REQ_CTRL,
+ codec_dmcbus_read(DMC_REQ_CTRL) | (1 << 4));
+ spin_unlock_irqrestore(&fb_core_spin_lock, flags);
+
+}
+#endif
+
+#endif
+
+static void init_pic_list_hw(struct VP9Decoder_s *pbi);
+
+static int get_free_fb(struct VP9Decoder_s *pbi)
+{
+ struct VP9_Common_s *const cm = &pbi->common;
+ struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs;
+ int i;
+ unsigned long flags;
+
+ lock_buffer_pool(cm->buffer_pool, flags);
+ if (debug & VP9_DEBUG_BUFMGR_MORE) {
+ for (i = 0; i < pbi->used_buf_num; ++i) {
+ pr_info("%s:%d, ref_count %d vf_ref %d index %d\r\n",
+ __func__, i, frame_bufs[i].ref_count,
+ frame_bufs[i].buf.vf_ref,
+ frame_bufs[i].buf.index);
+ }
+ }
+ for (i = 0; i < pbi->used_buf_num; ++i) {
+ if ((frame_bufs[i].ref_count == 0) &&
+ (frame_bufs[i].buf.vf_ref == 0) &&
+ (frame_bufs[i].buf.index != -1)
+ )
+ break;
+ }
+ if (i != pbi->used_buf_num) {
+ frame_bufs[i].ref_count = 1;
+ /*pr_info("[MMU DEBUG 1] set ref_count[%d] : %d\r\n",
+ i, frame_bufs[i].ref_count);*/
+ } else {
+ /* Reset i to be INVALID_IDX to indicate
+ no free buffer found*/
+ i = INVALID_IDX;
+ }
+
+ unlock_buffer_pool(cm->buffer_pool, flags);
+ return i;
+}
+
+static int v4l_get_free_fb(struct VP9Decoder_s *pbi)
+{
+ struct VP9_Common_s *const cm = &pbi->common;
+ struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs;
+ struct aml_vcodec_ctx * v4l = pbi->v4l2_ctx;
+ struct v4l_buff_pool *pool = &v4l->cap_pool;
+ struct PIC_BUFFER_CONFIG_s *pic = NULL;
+ int i, idx = INVALID_IDX;
+ ulong flags;
+
+ lock_buffer_pool(cm->buffer_pool, flags);
+
+ for (i = 0; i < pool->in; ++i) {
+ u32 state = (pool->seq[i] >> 16);
+ u32 index = (pool->seq[i] & 0xffff);
+
+ switch (state) {
+ case V4L_CAP_BUFF_IN_DEC:
+ pic = &frame_bufs[i].buf;
+ if ((frame_bufs[i].ref_count == 0) &&
+ (pic->vf_ref == 0) &&
+ (pic->index != -1) &&
+ pic->cma_alloc_addr) {
+ idx = i;
+ }
+ break;
+ case V4L_CAP_BUFF_IN_M2M:
+ pic = &frame_bufs[index].buf;
+ pic->y_crop_width = pbi->frame_width;
+ pic->y_crop_height = pbi->frame_height;
+ if (!v4l_alloc_and_config_pic(pbi, pic)) {
+ set_canvas(pbi, pic);
+ init_pic_list_hw(pbi);
+ idx = index;
+ }
+ break;
+ default:
+ pr_err("v4l buffer state err %d.\n", state);
+ break;
+ }
+
+ if (idx != INVALID_IDX) {
+ frame_bufs[idx].ref_count = 1;
+ break;
+ }
+ }
+
+ unlock_buffer_pool(cm->buffer_pool, flags);
+
+ return idx;
+}
+
+static int get_free_buf_count(struct VP9Decoder_s *pbi)
+{
+ struct VP9_Common_s *const cm = &pbi->common;
+ struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs;
+ int i;
+ int free_buf_count = 0;
+ for (i = 0; i < pbi->used_buf_num; ++i)
+ if ((frame_bufs[i].ref_count == 0) &&
+ (frame_bufs[i].buf.vf_ref == 0) &&
+ (frame_bufs[i].buf.index != -1)
+ )
+ free_buf_count++;
+ return free_buf_count;
+}
+
+static void decrease_ref_count(int idx, struct RefCntBuffer_s *const frame_bufs,
+ struct BufferPool_s *const pool)
+{
+ if (idx >= 0) {
+ --frame_bufs[idx].ref_count;
+ /*pr_info("[MMU DEBUG 7] dec ref_count[%d] : %d\r\n", idx,
+ * frame_bufs[idx].ref_count);
+ */
+ /*A worker may only get a free framebuffer index when
+ *calling get_free_fb. But the private buffer is not set up
+ *until finish decoding header. So any error happens during
+ *decoding header, the frame_bufs will not have valid priv
+ *buffer.
+ */
+
+ if (frame_bufs[idx].ref_count == 0 &&
+ frame_bufs[idx].raw_frame_buffer.priv)
+ vp9_release_frame_buffer
+ (&frame_bufs[idx].raw_frame_buffer);
+ }
+}
+
+static void generate_next_ref_frames(struct VP9Decoder_s *pbi)
+{
+ struct VP9_Common_s *const cm = &pbi->common;
+ struct RefCntBuffer_s *frame_bufs = cm->buffer_pool->frame_bufs;
+ struct BufferPool_s *const pool = cm->buffer_pool;
+ int mask, ref_index = 0;
+ unsigned long flags;
+
+ /* Generate next_ref_frame_map.*/
+ lock_buffer_pool(pool, flags);
+ for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) {
+ if (mask & 1) {
+ cm->next_ref_frame_map[ref_index] = cm->new_fb_idx;
+ ++frame_bufs[cm->new_fb_idx].ref_count;
+ /*pr_info("[MMU DEBUG 4] inc ref_count[%d] : %d\r\n",
+ *cm->new_fb_idx, frame_bufs[cm->new_fb_idx].ref_count);
+ */
+ } else
+ cm->next_ref_frame_map[ref_index] =
+ cm->ref_frame_map[ref_index];
+ /* Current thread holds the reference frame.*/
+ if (cm->ref_frame_map[ref_index] >= 0) {
+ ++frame_bufs[cm->ref_frame_map[ref_index]].ref_count;
+ /*pr_info
+ *("[MMU DEBUG 5] inc ref_count[%d] : %d\r\n",
+ *cm->ref_frame_map[ref_index],
+ *frame_bufs[cm->ref_frame_map[ref_index]].ref_count);
+ */
+ }
+ ++ref_index;
+ }
+
+ for (; ref_index < REF_FRAMES; ++ref_index) {
+ cm->next_ref_frame_map[ref_index] =
+ cm->ref_frame_map[ref_index];
+ /* Current thread holds the reference frame.*/
+ if (cm->ref_frame_map[ref_index] >= 0) {
+ ++frame_bufs[cm->ref_frame_map[ref_index]].ref_count;
+ /*pr_info("[MMU DEBUG 6] inc ref_count[%d] : %d\r\n",
+ *cm->ref_frame_map[ref_index],
+ *frame_bufs[cm->ref_frame_map[ref_index]].ref_count);
+ */
+ }
+ }
+ unlock_buffer_pool(pool, flags);
+ return;
+}
+
+static void refresh_ref_frames(struct VP9Decoder_s *pbi)
+
+{
+ struct VP9_Common_s *const cm = &pbi->common;
+ struct BufferPool_s *pool = cm->buffer_pool;
+ struct RefCntBuffer_s *frame_bufs = cm->buffer_pool->frame_bufs;
+ int mask, ref_index = 0;
+ unsigned long flags;
+
+ lock_buffer_pool(pool, flags);
+ for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) {
+ const int old_idx = cm->ref_frame_map[ref_index];
+ /*Current thread releases the holding of reference frame.*/
+ decrease_ref_count(old_idx, frame_bufs, pool);
+
+ /*Release the reference frame in reference map.*/
+ if ((mask & 1) && old_idx >= 0)
+ decrease_ref_count(old_idx, frame_bufs, pool);
+ cm->ref_frame_map[ref_index] =
+ cm->next_ref_frame_map[ref_index];
+ ++ref_index;
+ }
+
+ /*Current thread releases the holding of reference frame.*/
+ for (; ref_index < REF_FRAMES && !cm->show_existing_frame;
+ ++ref_index) {
+ const int old_idx = cm->ref_frame_map[ref_index];
+
+ decrease_ref_count(old_idx, frame_bufs, pool);
+ cm->ref_frame_map[ref_index] =
+ cm->next_ref_frame_map[ref_index];
+ }
+ unlock_buffer_pool(pool, flags);
+ return;
+}
+
+int vp9_bufmgr_process(struct VP9Decoder_s *pbi, union param_u *params)
+{
+ struct VP9_Common_s *const cm = &pbi->common;
+ struct BufferPool_s *pool = cm->buffer_pool;
+ struct RefCntBuffer_s *frame_bufs = cm->buffer_pool->frame_bufs;
+ struct PIC_BUFFER_CONFIG_s *pic = NULL;
+ int i;
+ int ret;
+
+ pbi->ready_for_new_data = 0;
+
+ if (pbi->has_keyframe == 0 &&
+ params->p.frame_type != KEY_FRAME){
+ on_no_keyframe_skiped++;
+ return -2;
+ }
+ pbi->has_keyframe = 1;
+ on_no_keyframe_skiped = 0;
+#if 0
+ if (pbi->mmu_enable) {
+ if (!pbi->m_ins_flag)
+ pbi->used_4k_num = (READ_VREG(HEVC_SAO_MMU_STATUS) >> 16);
+ if (cm->prev_fb_idx >= 0) {
+ decoder_mmu_box_free_idx_tail(pbi->mmu_box,
+ cm->prev_fb_idx, pbi->used_4k_num);
+ }
+ }
+#endif
+ if (cm->new_fb_idx >= 0
+ && frame_bufs[cm->new_fb_idx].ref_count == 0){
+ vp9_release_frame_buffer
+ (&frame_bufs[cm->new_fb_idx].raw_frame_buffer);
+ }
+ /*pr_info("Before get_free_fb, prev_fb_idx : %d, new_fb_idx : %d\r\n",
+ cm->prev_fb_idx, cm->new_fb_idx);*/
+#ifndef MV_USE_FIXED_BUF
+ put_un_used_mv_bufs(pbi);
+ if (debug & VP9_DEBUG_BUFMGR_DETAIL)
+ dump_pic_list(pbi);
+#endif
+ cm->new_fb_idx = pbi->is_used_v4l ?
+ v4l_get_free_fb(pbi) :
+ get_free_fb(pbi);
+ if (cm->new_fb_idx == INVALID_IDX) {
+ pr_info("get_free_fb error\r\n");
+ return -1;
+ }
+
+#ifndef MV_USE_FIXED_BUF
+#ifdef SUPPORT_FB_DECODING
+ if (pbi->used_stage_buf_num == 0) {
+#endif
+ if (get_mv_buf(pbi,
+ &pool->frame_bufs[cm->new_fb_idx].
+ buf) < 0) {
+ pr_info("get_mv_buf fail\r\n");
+ return -1;
+ }
+ if (debug & VP9_DEBUG_BUFMGR_DETAIL)
+ dump_pic_list(pbi);
+#ifdef SUPPORT_FB_DECODING
+ }
+#endif
+#endif
+ cm->cur_frame = &pool->frame_bufs[cm->new_fb_idx];
+ /*if (debug & VP9_DEBUG_BUFMGR)
+ pr_info("[VP9 DEBUG]%s(get_free_fb): %d\r\n", __func__,
+ cm->new_fb_idx);*/
+
+ pbi->cur_buf = &frame_bufs[cm->new_fb_idx];
+ if (pbi->mmu_enable) {
+ /* moved to after picture size ready
+ *alloc_mmu(cm, params->p.width, params->p.height,
+ *params->p.bit_depth, pbi->frame_mmu_map_addr);
+ */
+ cm->prev_fb_idx = cm->new_fb_idx;
+ }
+ /*read_uncompressed_header()*/
+ cm->last_frame_type = cm->frame_type;
+ cm->last_intra_only = cm->intra_only;
+ cm->profile = params->p.profile;
+ if (cm->profile >= MAX_PROFILES) {
+ pr_err("Error: Unsupported profile %d\r\n", cm->profile);
+ return -1;
+ }
+ cm->show_existing_frame = params->p.show_existing_frame;
+ if (cm->show_existing_frame) {
+ /* Show an existing frame directly.*/
+ int frame_to_show_idx = params->p.frame_to_show_idx;
+ int frame_to_show;
+ unsigned long flags;
+ if (frame_to_show_idx >= REF_FRAMES) {
+ pr_info("frame_to_show_idx %d exceed max index\r\n",
+ frame_to_show_idx);
+ return -1;
+ }
+
+ frame_to_show = cm->ref_frame_map[frame_to_show_idx];
+ /*pr_info("frame_to_show %d\r\n", frame_to_show);*/
+ lock_buffer_pool(pool, flags);
+ if (frame_to_show < 0 ||
+ frame_bufs[frame_to_show].ref_count < 1) {
+ unlock_buffer_pool(pool, flags);
+ pr_err
+ ("Error:Buffer %d does not contain a decoded frame",
+ frame_to_show);
+ return -1;
+ }
+
+ ref_cnt_fb(frame_bufs, &cm->new_fb_idx, frame_to_show);
+ unlock_buffer_pool(pool, flags);
+ pbi->refresh_frame_flags = 0;
+ /*cm->lf.filter_level = 0;*/
+ cm->show_frame = 1;
+
+ /*
+ *if (pbi->frame_parallel_decode) {
+ * for (i = 0; i < REF_FRAMES; ++i)
+ * cm->next_ref_frame_map[i] =
+ * cm->ref_frame_map[i];
+ *}
+ */
+ /* do not decode, search next start code */
+ return 1;
+ }
+ cm->frame_type = params->p.frame_type;
+ cm->show_frame = params->p.show_frame;
+ cm->bit_depth = params->p.bit_depth;
+ cm->error_resilient_mode = params->p.error_resilient_mode;
+
+
+ if (cm->frame_type == KEY_FRAME) {
+ pbi->refresh_frame_flags = (1 << REF_FRAMES) - 1;
+
+ for (i = 0; i < REFS_PER_FRAME; ++i) {
+ cm->frame_refs[i].idx = INVALID_IDX;
+ cm->frame_refs[i].buf = NULL;
+ }
+
+ ret = setup_frame_size(pbi,
+ cm, params, pbi->frame_mmu_map_addr,
+ print_header_info);
+ if (ret)
+ return -1;
+ if (pbi->need_resync) {
+ memset(&cm->ref_frame_map, -1,
+ sizeof(cm->ref_frame_map));
+ pbi->need_resync = 0;
+ }
+ } else {
+ cm->intra_only = cm->show_frame ? 0 : params->p.intra_only;
+ /*if (print_header_info) {
+ * if (cm->show_frame)
+ * pr_info
+ * ("intra_only set to 0 because of show_frame\n");
+ * else
+ * pr_info
+ * ("1-bit intra_only read: %d\n", cm->intra_only);
+ *}
+ */
+
+
+ cm->reset_frame_context = cm->error_resilient_mode ?
+ 0 : params->p.reset_frame_context;
+ if (print_header_info) {
+ if (cm->error_resilient_mode)
+ pr_info
+ ("reset to 0 error_resilient_mode\n");
+ else
+ pr_info
+ (" * 2-bits reset_frame_context read : %d\n",
+ cm->reset_frame_context);
+ }
+
+ if (cm->intra_only) {
+ if (cm->profile > PROFILE_0) {
+ /*read_bitdepth_colorspace_sampling(cm,
+ * rb, print_header_info);
+ */
+ } else {
+ /*NOTE: The intra-only frame header
+ *does not include the specification
+ *of either the color format or
+ *color sub-sampling
+ *in profile 0. VP9 specifies that the default
+ *color format should be YUV 4:2:0 in this
+ *case (normative).
+ */
+ cm->color_space = VPX_CS_BT_601;
+ cm->subsampling_y = cm->subsampling_x = 1;
+ cm->bit_depth = VPX_BITS_8;
+ cm->use_highbitdepth = 0;
+ }
+
+ pbi->refresh_frame_flags =
+ params->p.refresh_frame_flags;
+ /*if (print_header_info)
+ * pr_info("*%d-bits refresh_frame read:0x%x\n",
+ * REF_FRAMES, pbi->refresh_frame_flags);
+ */
+ ret = setup_frame_size(pbi,
+ cm,
+ params,
+ pbi->frame_mmu_map_addr,
+ print_header_info);
+ if (ret)
+ return -1;
+ if (pbi->need_resync) {
+ memset(&cm->ref_frame_map, -1,
+ sizeof(cm->ref_frame_map));
+ pbi->need_resync = 0;
+ }
+ } else if (pbi->need_resync != 1) { /* Skip if need resync */
+ pbi->refresh_frame_flags =
+ params->p.refresh_frame_flags;
+ if (print_header_info)
+ pr_info
+ ("*%d-bits refresh_frame read:0x%x\n",
+ REF_FRAMES, pbi->refresh_frame_flags);
+ for (i = 0; i < REFS_PER_FRAME; ++i) {
+ const int ref =
+ (params->p.ref_info >>
+ (((REFS_PER_FRAME-i-1)*4)+1))
+ & 0x7;
+ const int idx =
+ cm->ref_frame_map[ref];
+ struct RefBuffer_s * const ref_frame =
+ &cm->frame_refs[i];
+ if (print_header_info)
+ pr_info("*%d-bits ref[%d]read:%d\n",
+ REF_FRAMES_LOG2, i, ref);
+ ref_frame->idx = idx;
+ ref_frame->buf = &frame_bufs[idx].buf;
+ cm->ref_frame_sign_bias[LAST_FRAME + i]
+ = (params->p.ref_info >>
+ ((REFS_PER_FRAME-i-1)*4)) & 0x1;
+ if (print_header_info)
+ pr_info("1bit ref_frame_sign_bias");
+ /*pr_info
+ *("%dread: %d\n",
+ *LAST_FRAME+i,
+ *cm->ref_frame_sign_bias
+ *[LAST_FRAME + i]);
+ */
+ /*pr_info
+ *("[VP9 DEBUG]%s(get ref):%d\r\n",
+ *__func__, ref_frame->idx);
+ */
+
+ }
+
+ ret = setup_frame_size_with_refs(
+ pbi,
+ cm,
+ params,
+ pbi->frame_mmu_map_addr,
+ print_header_info);
+ if (ret)
+ return -1;
+ for (i = 0; i < REFS_PER_FRAME; ++i) {
+ /*struct RefBuffer_s *const ref_buf =
+ *&cm->frame_refs[i];
+ */
+ /* to do:
+ *vp9_setup_scale_factors_for_frame
+ */
+ }
+ }
+ }
+
+ pic = get_frame_new_buffer(cm);
+ if (!pic)
+ return -1;
+
+ pic->bit_depth = cm->bit_depth;
+ pic->color_space = cm->color_space;
+ pic->slice_type = cm->frame_type;
+
+ if (pbi->need_resync) {
+ pr_err
+ ("Error: Keyframe/intra-only frame required to reset\r\n");
+ return -1;
+ }
+ generate_next_ref_frames(pbi);
+ pbi->hold_ref_buf = 1;
+
+#if 0
+ if (frame_is_intra_only(cm) || cm->error_resilient_mode)
+ vp9_setup_past_independence(cm);
+ setup_loopfilter(&cm->lf, rb, print_header_info);
+ setup_quantization(cm, &pbi->mb, rb, print_header_info);
+ setup_segmentation(&cm->seg, rb, print_header_info);
+ setup_segmentation_dequant(cm, print_header_info);
+
+ setup_tile_info(cm, rb, print_header_info);
+ sz = vp9_rb_read_literal(rb, 16);
+ if (print_header_info)
+ pr_info(" * 16-bits size read : %d (0x%x)\n", sz, sz);
+
+ if (sz == 0)
+ vpx_internal_error(&cm->error, VPX_CODEC_CORRUPT_FRAME,
+ "Invalid header size");
+#endif
+ /*end read_uncompressed_header()*/
+ cm->use_prev_frame_mvs = !cm->error_resilient_mode &&
+ cm->width == cm->last_width &&
+ cm->height == cm->last_height &&
+ !cm->last_intra_only &&
+ cm->last_show_frame &&
+ (cm->last_frame_type != KEY_FRAME);
+
+ /*pr_info
+ *("set use_prev_frame_mvs to %d (last_width %d last_height %d",
+ *cm->use_prev_frame_mvs, cm->last_width, cm->last_height);
+ *pr_info
+ *(" last_intra_only %d last_show_frame %d last_frame_type %d)\n",
+ *cm->last_intra_only, cm->last_show_frame, cm->last_frame_type);
+ */
+
+ if (pbi->enable_fence && cm->show_frame) {
+ struct PIC_BUFFER_CONFIG_s *pic = &cm->cur_frame->buf;
+ struct vdec_s *vdec = hw_to_vdec(pbi);
+
+ /* create fence for each buffers. */
+ ret = vdec_timeline_create_fence(&vdec->sync);
+ if (ret < 0)
+ return ret;
+
+ pic->fence = vdec->sync.fence;
+ pic->bit_depth = cm->bit_depth;
+ pic->slice_type = cm->frame_type;
+ pic->stream_offset = pbi->pre_stream_offset;
+
+ if (pbi->chunk) {
+ pic->pts = pbi->chunk->pts;
+ pic->pts64 = pbi->chunk->pts64;
+ pic->timestamp = pbi->chunk->timestamp;
+ }
+
+ /* post video vframe. */
+ prepare_display_buf(pbi, pic);
+ }
+
+ return 0;
+}
+
+
+void swap_frame_buffers(struct VP9Decoder_s *pbi)
+{
+ int ref_index = 0;
+ struct VP9_Common_s *const cm = &pbi->common;
+ struct BufferPool_s *const pool = cm->buffer_pool;
+ struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs;
+ unsigned long flags;
+ refresh_ref_frames(pbi);
+ pbi->hold_ref_buf = 0;
+ cm->frame_to_show = get_frame_new_buffer(cm);
+
+ if (cm->frame_to_show) {
+ /*if (!pbi->frame_parallel_decode || !cm->show_frame) {*/
+ lock_buffer_pool(pool, flags);
+ --frame_bufs[cm->new_fb_idx].ref_count;
+ /*pr_info("[MMU DEBUG 8] dec ref_count[%d] : %d\r\n", cm->new_fb_idx,
+ * frame_bufs[cm->new_fb_idx].ref_count);
+ */
+ unlock_buffer_pool(pool, flags);
+ /*}*/
+ }
+
+ /*Invalidate these references until the next frame starts.*/
+ for (ref_index = 0; ref_index < 3; ref_index++)
+ cm->frame_refs[ref_index].idx = -1;
+}
+
+#if 0
+static void check_resync(vpx_codec_alg_priv_t *const ctx,
+ const struct VP9Decoder_s *const pbi)
+{
+ /* Clear resync flag if worker got a key frame or intra only frame.*/
+ if (ctx->need_resync == 1 && pbi->need_resync == 0 &&
+ (pbi->common.intra_only || pbi->common.frame_type == KEY_FRAME))
+ ctx->need_resync = 0;
+}
+#endif
+
+int vp9_get_raw_frame(struct VP9Decoder_s *pbi, struct PIC_BUFFER_CONFIG_s *sd)
+{
+ struct VP9_Common_s *const cm = &pbi->common;
+ int ret = -1;
+
+ if (pbi->ready_for_new_data == 1)
+ return ret;
+
+ pbi->ready_for_new_data = 1;
+
+ /* no raw frame to show!!! */
+ if (!cm->show_frame)
+ return ret;
+
+ /* may not be get buff in v4l2 */
+ if (!cm->frame_to_show)
+ return ret;
+
+ pbi->ready_for_new_data = 1;
+
+ *sd = *cm->frame_to_show;
+ ret = 0;
+
+ return ret;
+}
+
+int vp9_bufmgr_init(struct VP9Decoder_s *pbi, struct BuffInfo_s *buf_spec_i,
+ struct buff_s *mc_buf_i) {
+ struct VP9_Common_s *cm = &pbi->common;
+
+ /*memset(pbi, 0, sizeof(struct VP9Decoder_s));*/
+ pbi->frame_count = 0;
+ pbi->pic_count = 0;
+ pbi->pre_stream_offset = 0;
+ cm->buffer_pool = &pbi->vp9_buffer_pool;
+ spin_lock_init(&cm->buffer_pool->lock);
+ cm->prev_fb_idx = INVALID_IDX;
+ cm->new_fb_idx = INVALID_IDX;
+ pbi->used_4k_num = -1;
+ cm->cur_fb_idx_mmu = INVALID_IDX;
+ pr_debug
+ ("After vp9_bufmgr_init, prev_fb_idx : %d, new_fb_idx : %d\r\n",
+ cm->prev_fb_idx, cm->new_fb_idx);
+ pbi->need_resync = 1;
+ /* Initialize the references to not point to any frame buffers.*/
+ memset(&cm->ref_frame_map, -1, sizeof(cm->ref_frame_map));
+ memset(&cm->next_ref_frame_map, -1, sizeof(cm->next_ref_frame_map));
+ cm->current_video_frame = 0;
+ pbi->ready_for_new_data = 1;
+
+ /* private init */
+ pbi->work_space_buf = buf_spec_i;
+ if (!pbi->mmu_enable)
+ pbi->mc_buf = mc_buf_i;
+
+ pbi->rpm_addr = NULL;
+ pbi->lmem_addr = NULL;
+
+ pbi->use_cma_flag = 0;
+ pbi->decode_idx = 0;
+ pbi->slice_idx = 0;
+ /*int m_uiMaxCUWidth = 1<<7;*/
+ /*int m_uiMaxCUHeight = 1<<7;*/
+ pbi->has_keyframe = 0;
+ pbi->skip_flag = 0;
+ pbi->wait_buf = 0;
+ pbi->error_flag = 0;
+
+ pbi->pts_mode = PTS_NORMAL;
+ pbi->last_pts = 0;
+ pbi->last_lookup_pts = 0;
+ pbi->last_pts_us64 = 0;
+ pbi->last_lookup_pts_us64 = 0;
+ pbi->shift_byte_count = 0;
+ pbi->shift_byte_count_lo = 0;
+ pbi->shift_byte_count_hi = 0;
+ pbi->pts_mode_switching_count = 0;
+ pbi->pts_mode_recovery_count = 0;
+
+ pbi->buf_num = 0;
+ pbi->pic_num = 0;
+
+ return 0;
+}
+
+int vp9_bufmgr_postproc(struct VP9Decoder_s *pbi)
+{
+ struct vdec_s *vdec = hw_to_vdec(pbi);
+ struct VP9_Common_s *cm = &pbi->common;
+ struct PIC_BUFFER_CONFIG_s sd;
+
+ if (pbi->postproc_done)
+ return 0;
+ pbi->postproc_done = 1;
+ swap_frame_buffers(pbi);
+ if (!cm->show_existing_frame) {
+ cm->last_show_frame = cm->show_frame;
+ cm->prev_frame = cm->cur_frame;
+#if 0
+ if (cm->seg.enabled && !pbi->frame_parallel_decode)
+ vp9_swap_current_and_last_seg_map(cm);
+#endif
+ }
+ cm->last_width = cm->width;
+ cm->last_height = cm->height;
+ if (cm->show_frame)
+ cm->current_video_frame++;
+
+ if (vp9_get_raw_frame(pbi, &sd) == 0) {
+ /*pr_info("Display frame index %d\r\n", sd.index);*/
+ sd.stream_offset = pbi->pre_stream_offset;
+
+ if (pbi->enable_fence) {
+ /* notify signal to wake up wq of fence. */
+ vdec_timeline_increase(&vdec->sync, 1);
+ } else {
+ prepare_display_buf(pbi, &sd);
+ }
+
+ pbi->pre_stream_offset = READ_VREG(HEVC_SHIFT_BYTE_COUNT);
+ }
+
+/* else
+ * pr_info
+ * ("Not display this frame,ready_for_new_data%d show_frame%d\r\n",
+ * pbi->ready_for_new_data, cm->show_frame);
+ */
+ return 0;
+}
+
+/**************************************************
+ *
+ *VP9 buffer management end
+ *
+ ***************************************************
+ */
+
+
+#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*/
+#ifdef VP9_10B_NV21
+static u32 mem_map_mode = 2 /* 0:linear 1:32x32 2:64x32*/
+#else
+static u32 mem_map_mode; /* 0:linear 1:32x32 2:64x32 ; m8baby test1902 */
+#endif
+static u32 enable_mem_saving = 1;
+static u32 force_w_h;
+
+static u32 force_fps;
+
+
+const u32 vp9_version = 201602101;
+static u32 debug;
+static u32 radr;
+static u32 rval;
+static u32 pop_shorts;
+static u32 dbg_cmd;
+static u32 dbg_skip_decode_index;
+static u32 endian = 0xff0;
+#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 vp9_max_pic_w = 4096;
+static u32 vp9_max_pic_h = 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
+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 low_latency_flag;
+
+static u32 no_head;
+
+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 (vp9_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
+ *
+ */
+
+static u32 error_handle_policy;
+/*static u32 parser_sei_enable = 1;*/
+#define MAX_BUF_NUM_NORMAL 12
+#define MAX_BUF_NUM_LESS 10
+static u32 max_buf_num = MAX_BUF_NUM_NORMAL;
+#define MAX_BUF_NUM_SAVE_BUF 8
+
+static u32 run_ready_min_buf_num = 2;
+
+
+static DEFINE_MUTEX(vvp9_mutex);
+#ifndef MULTI_INSTANCE_SUPPORT
+static struct device *cma_dev;
+#endif
+
+#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 VP9_ADAPT_PROB_REG HEVC_ASSIST_SCRATCH_3
+#define VP9_MMU_MAP_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 VP9_PROB_SWAP_BUFFER HEVC_ASSIST_SCRATCH_9
+#define VP9_COUNT_SWAP_BUFFER HEVC_ASSIST_SCRATCH_A
+#define VP9_SEG_MAP_BUFFER HEVC_ASSIST_SCRATCH_B
+//#define HEVC_SCALELUT HEVC_ASSIST_SCRATCH_D
+#define HEVC_WAIT_FLAG HEVC_ASSIST_SCRATCH_E
+#define RPM_CMD_REG HEVC_ASSIST_SCRATCH_F
+#define LMEM_DUMP_ADR HEVC_ASSIST_SCRATCH_F
+#define HEVC_STREAM_SWAP_TEST HEVC_ASSIST_SCRATCH_L
+#ifdef MULTI_INSTANCE_SUPPORT
+#define HEVC_DECODE_COUNT HEVC_ASSIST_SCRATCH_M
+#define HEVC_DECODE_SIZE HEVC_ASSIST_SCRATCH_N
+#else
+#define HEVC_DECODE_PIC_BEGIN_REG HEVC_ASSIST_SCRATCH_M
+#define HEVC_DECODE_PIC_NUM_REG HEVC_ASSIST_SCRATCH_N
+#endif
+#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
+ /*[31:24] chip feature
+ 31: 0, use MBOX1; 1, use MBOX0
+ */
+#define DECODE_MODE HEVC_ASSIST_SCRATCH_J
+#define DECODE_STOP_POS HEVC_ASSIST_SCRATCH_K
+
+#ifdef MULTI_INSTANCE_SUPPORT
+#define RPM_BUF_SIZE (0x400 * 2)
+#else
+#define RPM_BUF_SIZE (0x80*2)
+#endif
+#define LMEM_BUF_SIZE (0x400 * 2)
+
+//#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)
+
+#define WORK_BUF_SPEC_NUM 3
+static struct BuffInfo_s amvvp9_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 = 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,
+ },
+ .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,
+ },
+ .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 = 0x49000,
+ },
+ .dblk_data = {
+ .buf_size = 0x49000,
+ },
+ .seg_map = {
+ /*4096x2304/64/64 *24 = 0xd800 Bytes*/
+ .buf_size = 0x3000, //0x2fd0,
+ },
+ .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
+ .mpred_above = {
+ .buf_size = 0x2200, //0x21c0, /* 2 * size of hevc*/
+ },
+#ifdef MV_USE_FIXED_BUF
+ .mpred_mv = {/* 1080p, 0x40000 per buffer */
+ .buf_size = 0x48200 * 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,
+ },
+ .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,
+ },
+ .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 = 0x52800,
+ },
+ .dblk_data = {
+ .buf_size = 0x52800,
+ },
+ .seg_map = {
+ /*4096x2304/64/64 *24 = 0xd800 Bytes*/
+ .buf_size = 0xd800,
+ },
+ .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
+ .mpred_above = {
+ .buf_size = 0x4800, /* 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 = 0x145400 * 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,
+ },
+ .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,
+ },
+ .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 = 0xa4800,
+ },
+ .dblk_data = {
+ .buf_size = 0xa4800,
+ },
+ .seg_map = {
+ /*4096x2304/64/64 *24 = 0xd800 Bytes*/
+ .buf_size = 0x36000,
+ },
+ .mmu_vbh = {
+ .buf_size = VBH_BUF_SIZE_8K, //2*16*(more than 2304)/4, 4K
+ },
+#if 0
+ .cm_header = {
+ //.buf_size = MMU_COMPRESS_HEADER_SIZE*8, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8)
+ .buf_size = MMU_COMPRESS_HEADER_SIZE*16, // 0x44000 = ((1088*2*1024*4)/32/4)*(32/8)
+ },
+#endif
+ .mpred_above = {
+ .buf_size = 0x9000,
+ },
+#ifdef MV_USE_FIXED_BUF
+ .mpred_mv = {
+ //4k2k , 0x100000 per buffer */
+ /* 4096x2304 , 0x120000 per buffer */
+ .buf_size = 0x514800 * FRAME_BUFFERS,
+ },
+#endif
+ .rpm = {
+ .buf_size = RPM_BUF_SIZE,
+ },
+ .lmem = {
+ .buf_size = 0x400 * 2,
+ }
+ }
+};
+
+
+/*Losless compression body buffer size 4K per 64x32 (jt)*/
+int compute_losless_comp_body_size(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;
+ bsize = (is_bit_depth_10?4096:3200)*width_x64*height_x32;
+ if (debug & VP9_DEBUG_BUFMGR_MORE)
+ pr_info("%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(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;
+ if (debug & VP9_DEBUG_BUFMGR_MORE)
+ pr_info("%s(%d,%d)=>%d\n",
+ __func__, width, height,
+ hsize);
+
+ return hsize;
+}
+
+static void init_buff_spec(struct VP9Decoder_s *pbi,
+ struct BuffInfo_s *buf_spec)
+{
+ void *mem_start_virt;
+
+ buf_spec->ipp.buf_start = buf_spec->start_adr;
+ buf_spec->sao_abv.buf_start =
+ buf_spec->ipp.buf_start + buf_spec->ipp.buf_size;
+
+ buf_spec->sao_vb.buf_start =
+ buf_spec->sao_abv.buf_start + buf_spec->sao_abv.buf_size;
+ buf_spec->short_term_rps.buf_start =
+ buf_spec->sao_vb.buf_start + buf_spec->sao_vb.buf_size;
+ buf_spec->vps.buf_start =
+ buf_spec->short_term_rps.buf_start +
+ buf_spec->short_term_rps.buf_size;
+ buf_spec->sps.buf_start =
+ buf_spec->vps.buf_start + buf_spec->vps.buf_size;
+ buf_spec->pps.buf_start =
+ buf_spec->sps.buf_start + buf_spec->sps.buf_size;
+ buf_spec->sao_up.buf_start =
+ buf_spec->pps.buf_start + buf_spec->pps.buf_size;
+ buf_spec->swap_buf.buf_start =
+ buf_spec->sao_up.buf_start + buf_spec->sao_up.buf_size;
+ buf_spec->swap_buf2.buf_start =
+ buf_spec->swap_buf.buf_start + buf_spec->swap_buf.buf_size;
+ buf_spec->scalelut.buf_start =
+ buf_spec->swap_buf2.buf_start + buf_spec->swap_buf2.buf_size;
+ buf_spec->dblk_para.buf_start =
+ buf_spec->scalelut.buf_start + buf_spec->scalelut.buf_size;
+ buf_spec->dblk_data.buf_start =
+ buf_spec->dblk_para.buf_start + buf_spec->dblk_para.buf_size;
+ buf_spec->seg_map.buf_start =
+ buf_spec->dblk_data.buf_start + buf_spec->dblk_data.buf_size;
+ if (pbi == NULL || pbi->mmu_enable) {
+ buf_spec->mmu_vbh.buf_start =
+ buf_spec->seg_map.buf_start +
+ buf_spec->seg_map.buf_size;
+ buf_spec->mpred_above.buf_start =
+ buf_spec->mmu_vbh.buf_start +
+ buf_spec->mmu_vbh.buf_size;
+ } else {
+ buf_spec->mpred_above.buf_start =
+ buf_spec->seg_map.buf_start + buf_spec->seg_map.buf_size;
+ }
+#ifdef MV_USE_FIXED_BUF
+ buf_spec->mpred_mv.buf_start =
+ buf_spec->mpred_above.buf_start +
+ buf_spec->mpred_above.buf_size;
+
+ buf_spec->rpm.buf_start =
+ buf_spec->mpred_mv.buf_start +
+ buf_spec->mpred_mv.buf_size;
+#else
+ buf_spec->rpm.buf_start =
+ buf_spec->mpred_above.buf_start +
+ buf_spec->mpred_above.buf_size;
+
+#endif
+ buf_spec->lmem.buf_start =
+ buf_spec->rpm.buf_start +
+ buf_spec->rpm.buf_size;
+ buf_spec->end_adr =
+ buf_spec->lmem.buf_start +
+ buf_spec->lmem.buf_size;
+
+ if (!pbi)
+ return;
+
+ if (!vdec_secure(hw_to_vdec(pbi))) {
+ 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 {
+ mem_start_virt = codec_mm_vmap(
+ buf_spec->dblk_para.buf_start,
+ buf_spec->dblk_para.buf_size);
+ 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);
+ codec_mm_unmap_phyaddr(mem_start_virt);
+ } 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("vps.buf_start :%x\n",
+ buf_spec->vps.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("seg_map.buf_start :%x\n",
+ buf_spec->seg_map.buf_start);
+ if (pbi->mmu_enable) {
+ pr_info("mmu_vbh.buf_start :%x\n",
+ buf_spec->mmu_vbh.buf_start);
+ }
+ 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 & VP9_DEBUG_SEND_PARAM_WITH_REG) == 0) {
+ pr_info("rpm.buf_start :%x\n",
+ buf_spec->rpm.buf_start);
+ }
+ }
+}
+
+/* cache_util.c */
+#define THODIYIL_MCRCC_CANVAS_ALGX 4
+
+static u32 mcrcc_cache_alg_flag = THODIYIL_MCRCC_CANVAS_ALGX;
+
+static void mcrcc_perfcount_reset(void)
+{
+ if (debug & VP9_DEBUG_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 unsigned raw_mcr_cnt_total_prev;
+static unsigned hit_mcr_0_cnt_total_prev;
+static unsigned hit_mcr_1_cnt_total_prev;
+static unsigned byp_mcr_cnt_nchcanv_total_prev;
+static unsigned byp_mcr_cnt_nchoutwin_total_prev;
+
+static void mcrcc_get_hitrate(unsigned reset_pre)
+{
+ unsigned delta_hit_mcr_0_cnt;
+ unsigned delta_hit_mcr_1_cnt;
+ unsigned delta_raw_mcr_cnt;
+ unsigned delta_mcr_cnt_nchcanv;
+ unsigned delta_mcr_cnt_nchoutwin;
+
+ unsigned tmp;
+ unsigned raw_mcr_cnt;
+ unsigned hit_mcr_cnt;
+ unsigned byp_mcr_cnt_nchoutwin;
+ unsigned byp_mcr_cnt_nchcanv;
+ int hitrate;
+ if (reset_pre) {
+ raw_mcr_cnt_total_prev = 0;
+ hit_mcr_0_cnt_total_prev = 0;
+ hit_mcr_1_cnt_total_prev = 0;
+ byp_mcr_cnt_nchcanv_total_prev = 0;
+ byp_mcr_cnt_nchoutwin_total_prev = 0;
+ }
+ if (debug & VP9_DEBUG_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 & VP9_DEBUG_CACHE)
+ pr_info("raw_mcr_cnt_total: %d\n",
+ raw_mcr_cnt);
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("hit_mcr_cnt_total: %d\n",
+ hit_mcr_cnt);
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("byp_mcr_cnt_nchoutwin_total: %d\n",
+ byp_mcr_cnt_nchoutwin);
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("byp_mcr_cnt_nchcanv_total: %d\n",
+ byp_mcr_cnt_nchcanv);
+
+ delta_raw_mcr_cnt = raw_mcr_cnt -
+ raw_mcr_cnt_total_prev;
+ delta_mcr_cnt_nchcanv = byp_mcr_cnt_nchcanv -
+ byp_mcr_cnt_nchcanv_total_prev;
+ delta_mcr_cnt_nchoutwin = byp_mcr_cnt_nchoutwin -
+ byp_mcr_cnt_nchoutwin_total_prev;
+ raw_mcr_cnt_total_prev = raw_mcr_cnt;
+ byp_mcr_cnt_nchcanv_total_prev = byp_mcr_cnt_nchcanv;
+ byp_mcr_cnt_nchoutwin_total_prev = byp_mcr_cnt_nchoutwin;
+
+ WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x4<<1));
+ tmp = READ_VREG(HEVCD_MCRCC_PERFMON_DATA);
+ if (debug & VP9_DEBUG_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 & VP9_DEBUG_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 & VP9_DEBUG_CACHE)
+ pr_info("hit_mcr_0_cnt_total: %d\n", tmp);
+ delta_hit_mcr_0_cnt = tmp - hit_mcr_0_cnt_total_prev;
+ hit_mcr_0_cnt_total_prev = tmp;
+ WRITE_VREG(HEVCD_MCRCC_PERFMON_CTL, (unsigned int)(0x7<<1));
+ tmp = READ_VREG(HEVCD_MCRCC_PERFMON_DATA);
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("hit_mcr_1_cnt_total: %d\n", tmp);
+ delta_hit_mcr_1_cnt = tmp - hit_mcr_1_cnt_total_prev;
+ hit_mcr_1_cnt_total_prev = tmp;
+
+ if (delta_raw_mcr_cnt != 0) {
+ hitrate = 100 * delta_hit_mcr_0_cnt
+ / delta_raw_mcr_cnt;
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("CANV0_HIT_RATE : %d\n", hitrate);
+ hitrate = 100 * delta_hit_mcr_1_cnt
+ / delta_raw_mcr_cnt;
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("CANV1_HIT_RATE : %d\n", hitrate);
+ hitrate = 100 * delta_mcr_cnt_nchcanv
+ / delta_raw_mcr_cnt;
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("NONCACH_CANV_BYP_RATE : %d\n", hitrate);
+ hitrate = 100 * delta_mcr_cnt_nchoutwin
+ / delta_raw_mcr_cnt;
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("CACHE_OUTWIN_BYP_RATE : %d\n", hitrate);
+ }
+
+
+ if (raw_mcr_cnt != 0) {
+ hitrate = 100 * hit_mcr_cnt / raw_mcr_cnt;
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("MCRCC_HIT_RATE : %d\n", hitrate);
+ hitrate = 100 * (byp_mcr_cnt_nchoutwin + byp_mcr_cnt_nchcanv)
+ / raw_mcr_cnt;
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("MCRCC_BYP_RATE : %d\n", hitrate);
+ } else {
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("MCRCC_HIT_RATE : na\n");
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("MCRCC_BYP_RATE : na\n");
+ }
+ return;
+}
+
+
+static void decomp_perfcount_reset(void)
+{
+ if (debug & VP9_DEBUG_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 decomp_get_hitrate(void)
+{
+ unsigned raw_mcr_cnt;
+ unsigned hit_mcr_cnt;
+ int hitrate;
+ if (debug & VP9_DEBUG_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 & VP9_DEBUG_CACHE)
+ pr_info("hcache_raw_cnt_total: %d\n", raw_mcr_cnt);
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("hcache_hit_cnt_total: %d\n", hit_mcr_cnt);
+
+ if (raw_mcr_cnt != 0) {
+ hitrate = hit_mcr_cnt * 100 / raw_mcr_cnt;
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("DECOMP_HCACHE_HIT_RATE : %d\n", hitrate);
+ } else {
+ if (debug & VP9_DEBUG_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 & VP9_DEBUG_CACHE)
+ pr_info("dcache_raw_cnt_total: %d\n", raw_mcr_cnt);
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("dcache_hit_cnt_total: %d\n", hit_mcr_cnt);
+
+ if (raw_mcr_cnt != 0) {
+ hitrate = hit_mcr_cnt * 100 / raw_mcr_cnt;
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("DECOMP_DCACHE_HIT_RATE : %d\n", hitrate);
+ } else {
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("DECOMP_DCACHE_HIT_RATE : na\n");
+ }
+ return;
+}
+
+static void decomp_get_comprate(void)
+{
+ unsigned raw_ucomp_cnt;
+ unsigned fast_comp_cnt;
+ unsigned slow_comp_cnt;
+ int comprate;
+
+ if (debug & VP9_DEBUG_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 & VP9_DEBUG_CACHE)
+ pr_info("decomp_fast_comp_total: %d\n", fast_comp_cnt);
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("decomp_slow_comp_total: %d\n", slow_comp_cnt);
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("decomp_raw_uncomp_total: %d\n", raw_ucomp_cnt);
+
+ if (raw_ucomp_cnt != 0) {
+ comprate = (fast_comp_cnt + slow_comp_cnt)
+ * 100 / raw_ucomp_cnt;
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("DECOMP_COMP_RATIO : %d\n", comprate);
+ } else {
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("DECOMP_COMP_RATIO : na\n");
+ }
+ return;
+}
+/* cache_util.c end */
+
+/*====================================================
+ *========================================================================
+ *vp9_prob define
+ *========================================================================
+ */
+#define VP9_PARTITION_START 0
+#define VP9_PARTITION_SIZE_STEP (3 * 4)
+#define VP9_PARTITION_ONE_SIZE (4 * VP9_PARTITION_SIZE_STEP)
+#define VP9_PARTITION_KEY_START 0
+#define VP9_PARTITION_P_START VP9_PARTITION_ONE_SIZE
+#define VP9_PARTITION_SIZE (2 * VP9_PARTITION_ONE_SIZE)
+#define VP9_SKIP_START (VP9_PARTITION_START + VP9_PARTITION_SIZE)
+#define VP9_SKIP_SIZE 4 /* only use 3*/
+#define VP9_TX_MODE_START (VP9_SKIP_START+VP9_SKIP_SIZE)
+#define VP9_TX_MODE_8_0_OFFSET 0
+#define VP9_TX_MODE_8_1_OFFSET 1
+#define VP9_TX_MODE_16_0_OFFSET 2
+#define VP9_TX_MODE_16_1_OFFSET 4
+#define VP9_TX_MODE_32_0_OFFSET 6
+#define VP9_TX_MODE_32_1_OFFSET 9
+#define VP9_TX_MODE_SIZE 12
+#define VP9_COEF_START (VP9_TX_MODE_START+VP9_TX_MODE_SIZE)
+#define VP9_COEF_BAND_0_OFFSET 0
+#define VP9_COEF_BAND_1_OFFSET (VP9_COEF_BAND_0_OFFSET + 3 * 3 + 1)
+#define VP9_COEF_BAND_2_OFFSET (VP9_COEF_BAND_1_OFFSET + 6 * 3)
+#define VP9_COEF_BAND_3_OFFSET (VP9_COEF_BAND_2_OFFSET + 6 * 3)
+#define VP9_COEF_BAND_4_OFFSET (VP9_COEF_BAND_3_OFFSET + 6 * 3)
+#define VP9_COEF_BAND_5_OFFSET (VP9_COEF_BAND_4_OFFSET + 6 * 3)
+#define VP9_COEF_SIZE_ONE_SET 100 /* ((3 +5*6)*3 + 1 padding)*/
+#define VP9_COEF_4X4_START (VP9_COEF_START + 0 * VP9_COEF_SIZE_ONE_SET)
+#define VP9_COEF_8X8_START (VP9_COEF_START + 4 * VP9_COEF_SIZE_ONE_SET)
+#define VP9_COEF_16X16_START (VP9_COEF_START + 8 * VP9_COEF_SIZE_ONE_SET)
+#define VP9_COEF_32X32_START (VP9_COEF_START + 12 * VP9_COEF_SIZE_ONE_SET)
+#define VP9_COEF_SIZE_PLANE (2 * VP9_COEF_SIZE_ONE_SET)
+#define VP9_COEF_SIZE (4 * 2 * 2 * VP9_COEF_SIZE_ONE_SET)
+#define VP9_INTER_MODE_START (VP9_COEF_START+VP9_COEF_SIZE)
+#define VP9_INTER_MODE_SIZE 24 /* only use 21 ( #*7)*/
+#define VP9_INTERP_START (VP9_INTER_MODE_START+VP9_INTER_MODE_SIZE)
+#define VP9_INTERP_SIZE 8
+#define VP9_INTRA_INTER_START (VP9_INTERP_START+VP9_INTERP_SIZE)
+#define VP9_INTRA_INTER_SIZE 4
+#define VP9_INTERP_INTRA_INTER_START VP9_INTERP_START
+#define VP9_INTERP_INTRA_INTER_SIZE (VP9_INTERP_SIZE + VP9_INTRA_INTER_SIZE)
+#define VP9_COMP_INTER_START \
+ (VP9_INTERP_INTRA_INTER_START+VP9_INTERP_INTRA_INTER_SIZE)
+#define VP9_COMP_INTER_SIZE 5
+#define VP9_COMP_REF_START (VP9_COMP_INTER_START+VP9_COMP_INTER_SIZE)
+#define VP9_COMP_REF_SIZE 5
+#define VP9_SINGLE_REF_START (VP9_COMP_REF_START+VP9_COMP_REF_SIZE)
+#define VP9_SINGLE_REF_SIZE 10
+#define VP9_REF_MODE_START VP9_COMP_INTER_START
+#define VP9_REF_MODE_SIZE \
+ (VP9_COMP_INTER_SIZE+VP9_COMP_REF_SIZE+VP9_SINGLE_REF_SIZE)
+#define VP9_IF_Y_MODE_START (VP9_REF_MODE_START+VP9_REF_MODE_SIZE)
+#define VP9_IF_Y_MODE_SIZE 36
+#define VP9_IF_UV_MODE_START (VP9_IF_Y_MODE_START+VP9_IF_Y_MODE_SIZE)
+#define VP9_IF_UV_MODE_SIZE 92 /* only use 90*/
+#define VP9_MV_JOINTS_START (VP9_IF_UV_MODE_START+VP9_IF_UV_MODE_SIZE)
+#define VP9_MV_JOINTS_SIZE 3
+#define VP9_MV_SIGN_0_START (VP9_MV_JOINTS_START+VP9_MV_JOINTS_SIZE)
+#define VP9_MV_SIGN_0_SIZE 1
+#define VP9_MV_CLASSES_0_START (VP9_MV_SIGN_0_START+VP9_MV_SIGN_0_SIZE)
+#define VP9_MV_CLASSES_0_SIZE 10
+#define VP9_MV_CLASS0_0_START (VP9_MV_CLASSES_0_START+VP9_MV_CLASSES_0_SIZE)
+#define VP9_MV_CLASS0_0_SIZE 1
+#define VP9_MV_BITS_0_START (VP9_MV_CLASS0_0_START+VP9_MV_CLASS0_0_SIZE)
+#define VP9_MV_BITS_0_SIZE 10
+#define VP9_MV_SIGN_1_START (VP9_MV_BITS_0_START+VP9_MV_BITS_0_SIZE)
+#define VP9_MV_SIGN_1_SIZE 1
+#define VP9_MV_CLASSES_1_START \
+ (VP9_MV_SIGN_1_START+VP9_MV_SIGN_1_SIZE)
+#define VP9_MV_CLASSES_1_SIZE 10
+#define VP9_MV_CLASS0_1_START \
+ (VP9_MV_CLASSES_1_START+VP9_MV_CLASSES_1_SIZE)
+#define VP9_MV_CLASS0_1_SIZE 1
+#define VP9_MV_BITS_1_START \
+ (VP9_MV_CLASS0_1_START+VP9_MV_CLASS0_1_SIZE)
+#define VP9_MV_BITS_1_SIZE 10
+#define VP9_MV_CLASS0_FP_0_START \
+ (VP9_MV_BITS_1_START+VP9_MV_BITS_1_SIZE)
+#define VP9_MV_CLASS0_FP_0_SIZE 9
+#define VP9_MV_CLASS0_FP_1_START \
+ (VP9_MV_CLASS0_FP_0_START+VP9_MV_CLASS0_FP_0_SIZE)
+#define VP9_MV_CLASS0_FP_1_SIZE 9
+#define VP9_MV_CLASS0_HP_0_START \
+ (VP9_MV_CLASS0_FP_1_START+VP9_MV_CLASS0_FP_1_SIZE)
+#define VP9_MV_CLASS0_HP_0_SIZE 2
+#define VP9_MV_CLASS0_HP_1_START \
+ (VP9_MV_CLASS0_HP_0_START+VP9_MV_CLASS0_HP_0_SIZE)
+#define VP9_MV_CLASS0_HP_1_SIZE 2
+#define VP9_MV_START VP9_MV_JOINTS_START
+#define VP9_MV_SIZE 72 /*only use 69*/
+
+#define VP9_TOTAL_SIZE (VP9_MV_START + VP9_MV_SIZE)
+
+
+/*========================================================================
+ * vp9_count_mem define
+ *========================================================================
+ */
+#define VP9_COEF_COUNT_START 0
+#define VP9_COEF_COUNT_BAND_0_OFFSET 0
+#define VP9_COEF_COUNT_BAND_1_OFFSET \
+ (VP9_COEF_COUNT_BAND_0_OFFSET + 3*5)
+#define VP9_COEF_COUNT_BAND_2_OFFSET \
+ (VP9_COEF_COUNT_BAND_1_OFFSET + 6*5)
+#define VP9_COEF_COUNT_BAND_3_OFFSET \
+ (VP9_COEF_COUNT_BAND_2_OFFSET + 6*5)
+#define VP9_COEF_COUNT_BAND_4_OFFSET \
+ (VP9_COEF_COUNT_BAND_3_OFFSET + 6*5)
+#define VP9_COEF_COUNT_BAND_5_OFFSET \
+ (VP9_COEF_COUNT_BAND_4_OFFSET + 6*5)
+#define VP9_COEF_COUNT_SIZE_ONE_SET 165 /* ((3 +5*6)*5 */
+#define VP9_COEF_COUNT_4X4_START \
+ (VP9_COEF_COUNT_START + 0*VP9_COEF_COUNT_SIZE_ONE_SET)
+#define VP9_COEF_COUNT_8X8_START \
+ (VP9_COEF_COUNT_START + 4*VP9_COEF_COUNT_SIZE_ONE_SET)
+#define VP9_COEF_COUNT_16X16_START \
+ (VP9_COEF_COUNT_START + 8*VP9_COEF_COUNT_SIZE_ONE_SET)
+#define VP9_COEF_COUNT_32X32_START \
+ (VP9_COEF_COUNT_START + 12*VP9_COEF_COUNT_SIZE_ONE_SET)
+#define VP9_COEF_COUNT_SIZE_PLANE (2 * VP9_COEF_COUNT_SIZE_ONE_SET)
+#define VP9_COEF_COUNT_SIZE (4 * 2 * 2 * VP9_COEF_COUNT_SIZE_ONE_SET)
+
+#define VP9_INTRA_INTER_COUNT_START \
+ (VP9_COEF_COUNT_START+VP9_COEF_COUNT_SIZE)
+#define VP9_INTRA_INTER_COUNT_SIZE (4*2)
+#define VP9_COMP_INTER_COUNT_START \
+ (VP9_INTRA_INTER_COUNT_START+VP9_INTRA_INTER_COUNT_SIZE)
+#define VP9_COMP_INTER_COUNT_SIZE (5*2)
+#define VP9_COMP_REF_COUNT_START \
+ (VP9_COMP_INTER_COUNT_START+VP9_COMP_INTER_COUNT_SIZE)
+#define VP9_COMP_REF_COUNT_SIZE (5*2)
+#define VP9_SINGLE_REF_COUNT_START \
+ (VP9_COMP_REF_COUNT_START+VP9_COMP_REF_COUNT_SIZE)
+#define VP9_SINGLE_REF_COUNT_SIZE (10*2)
+#define VP9_TX_MODE_COUNT_START \
+ (VP9_SINGLE_REF_COUNT_START+VP9_SINGLE_REF_COUNT_SIZE)
+#define VP9_TX_MODE_COUNT_SIZE (12*2)
+#define VP9_SKIP_COUNT_START \
+ (VP9_TX_MODE_COUNT_START+VP9_TX_MODE_COUNT_SIZE)
+#define VP9_SKIP_COUNT_SIZE (3*2)
+#define VP9_MV_SIGN_0_COUNT_START \
+ (VP9_SKIP_COUNT_START+VP9_SKIP_COUNT_SIZE)
+#define VP9_MV_SIGN_0_COUNT_SIZE (1*2)
+#define VP9_MV_SIGN_1_COUNT_START \
+ (VP9_MV_SIGN_0_COUNT_START+VP9_MV_SIGN_0_COUNT_SIZE)
+#define VP9_MV_SIGN_1_COUNT_SIZE (1*2)
+#define VP9_MV_BITS_0_COUNT_START \
+ (VP9_MV_SIGN_1_COUNT_START+VP9_MV_SIGN_1_COUNT_SIZE)
+#define VP9_MV_BITS_0_COUNT_SIZE (10*2)
+#define VP9_MV_BITS_1_COUNT_START \
+ (VP9_MV_BITS_0_COUNT_START+VP9_MV_BITS_0_COUNT_SIZE)
+#define VP9_MV_BITS_1_COUNT_SIZE (10*2)
+#define VP9_MV_CLASS0_HP_0_COUNT_START \
+ (VP9_MV_BITS_1_COUNT_START+VP9_MV_BITS_1_COUNT_SIZE)
+#define VP9_MV_CLASS0_HP_0_COUNT_SIZE (2*2)
+#define VP9_MV_CLASS0_HP_1_COUNT_START \
+ (VP9_MV_CLASS0_HP_0_COUNT_START+VP9_MV_CLASS0_HP_0_COUNT_SIZE)
+#define VP9_MV_CLASS0_HP_1_COUNT_SIZE (2*2)
+/* Start merge_tree*/
+#define VP9_INTER_MODE_COUNT_START \
+ (VP9_MV_CLASS0_HP_1_COUNT_START+VP9_MV_CLASS0_HP_1_COUNT_SIZE)
+#define VP9_INTER_MODE_COUNT_SIZE (7*4)
+#define VP9_IF_Y_MODE_COUNT_START \
+ (VP9_INTER_MODE_COUNT_START+VP9_INTER_MODE_COUNT_SIZE)
+#define VP9_IF_Y_MODE_COUNT_SIZE (10*4)
+#define VP9_IF_UV_MODE_COUNT_START \
+ (VP9_IF_Y_MODE_COUNT_START+VP9_IF_Y_MODE_COUNT_SIZE)
+#define VP9_IF_UV_MODE_COUNT_SIZE (10*10)
+#define VP9_PARTITION_P_COUNT_START \
+ (VP9_IF_UV_MODE_COUNT_START+VP9_IF_UV_MODE_COUNT_SIZE)
+#define VP9_PARTITION_P_COUNT_SIZE (4*4*4)
+#define VP9_INTERP_COUNT_START \
+ (VP9_PARTITION_P_COUNT_START+VP9_PARTITION_P_COUNT_SIZE)
+#define VP9_INTERP_COUNT_SIZE (4*3)
+#define VP9_MV_JOINTS_COUNT_START \
+ (VP9_INTERP_COUNT_START+VP9_INTERP_COUNT_SIZE)
+#define VP9_MV_JOINTS_COUNT_SIZE (1 * 4)
+#define VP9_MV_CLASSES_0_COUNT_START \
+ (VP9_MV_JOINTS_COUNT_START+VP9_MV_JOINTS_COUNT_SIZE)
+#define VP9_MV_CLASSES_0_COUNT_SIZE (1*11)
+#define VP9_MV_CLASS0_0_COUNT_START \
+ (VP9_MV_CLASSES_0_COUNT_START+VP9_MV_CLASSES_0_COUNT_SIZE)
+#define VP9_MV_CLASS0_0_COUNT_SIZE (1*2)
+#define VP9_MV_CLASSES_1_COUNT_START \
+ (VP9_MV_CLASS0_0_COUNT_START+VP9_MV_CLASS0_0_COUNT_SIZE)
+#define VP9_MV_CLASSES_1_COUNT_SIZE (1*11)
+#define VP9_MV_CLASS0_1_COUNT_START \
+ (VP9_MV_CLASSES_1_COUNT_START+VP9_MV_CLASSES_1_COUNT_SIZE)
+#define VP9_MV_CLASS0_1_COUNT_SIZE (1*2)
+#define VP9_MV_CLASS0_FP_0_COUNT_START \
+ (VP9_MV_CLASS0_1_COUNT_START+VP9_MV_CLASS0_1_COUNT_SIZE)
+#define VP9_MV_CLASS0_FP_0_COUNT_SIZE (3*4)
+#define VP9_MV_CLASS0_FP_1_COUNT_START \
+ (VP9_MV_CLASS0_FP_0_COUNT_START+VP9_MV_CLASS0_FP_0_COUNT_SIZE)
+#define VP9_MV_CLASS0_FP_1_COUNT_SIZE (3*4)
+
+
+#define DC_PRED 0 /* Average of above and left pixels*/
+#define V_PRED 1 /* Vertical*/
+#define H_PRED 2 /* Horizontal*/
+#define D45_PRED 3 /*Directional 45 deg = round(arctan(1/1) * 180/pi)*/
+#define D135_PRED 4 /* Directional 135 deg = 180 - 45*/
+#define D117_PRED 5 /* Directional 117 deg = 180 - 63*/
+#define D153_PRED 6 /* Directional 153 deg = 180 - 27*/
+#define D207_PRED 7 /* Directional 207 deg = 180 + 27*/
+#define D63_PRED 8 /*Directional 63 deg = round(arctan(2/1) * 180/pi)*/
+#define TM_PRED 9 /*True-motion*/
+
+int clip_prob(int p)
+{
+ return (p > 255) ? 255 : (p < 1) ? 1 : p;
+}
+
+#define ROUND_POWER_OF_TWO(value, n) \
+ (((value) + (1 << ((n) - 1))) >> (n))
+
+#define MODE_MV_COUNT_SAT 20
+static const int count_to_update_factor[MODE_MV_COUNT_SAT + 1] = {
+ 0, 6, 12, 19, 25, 32, 38, 44, 51, 57, 64,
+ 70, 76, 83, 89, 96, 102, 108, 115, 121, 128
+};
+
+void vp9_tree_merge_probs(unsigned int *prev_prob, unsigned int *cur_prob,
+ int coef_node_start, int tree_left, int tree_right, int tree_i,
+ int node) {
+
+ int prob_32, prob_res, prob_shift;
+ int pre_prob, new_prob;
+ int den, m_count, get_prob, factor;
+
+ prob_32 = prev_prob[coef_node_start / 4 * 2];
+ prob_res = coef_node_start & 3;
+ prob_shift = prob_res * 8;
+ pre_prob = (prob_32 >> prob_shift) & 0xff;
+
+ den = tree_left + tree_right;
+
+ if (den == 0)
+ new_prob = pre_prob;
+ else {
+ m_count = (den < MODE_MV_COUNT_SAT) ?
+ den : MODE_MV_COUNT_SAT;
+ get_prob = clip_prob(
+ div_r32(((int64_t)tree_left * 256 + (den >> 1)),
+ den));
+ /*weighted_prob*/
+ factor = count_to_update_factor[m_count];
+ new_prob = ROUND_POWER_OF_TWO(pre_prob * (256 - factor)
+ + get_prob * factor, 8);
+ }
+ cur_prob[coef_node_start / 4 * 2] = (cur_prob[coef_node_start / 4 * 2]
+ & (~(0xff << prob_shift))) | (new_prob << prob_shift);
+
+ /*pr_info(" - [%d][%d] 0x%02X --> 0x%02X (0x%X 0x%X) (%X)\n",
+ *tree_i, node, pre_prob, new_prob, tree_left, tree_right,
+ *cur_prob[coef_node_start/4*2]);
+ */
+}
+
+
+/*void adapt_coef_probs(void)*/
+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)
+{
+ /* 80 * 64bits = 0xF00 ( use 0x1000 4K bytes)
+ *unsigned int prev_prob[496*2];
+ *unsigned int cur_prob[496*2];
+ *0x300 * 128bits = 0x3000 (32K Bytes)
+ *unsigned int count[0x300*4];
+ */
+
+ int tx_size, coef_tx_size_start, coef_count_tx_size_start;
+ int plane, coef_plane_start, coef_count_plane_start;
+ int type, coef_type_start, coef_count_type_start;
+ int band, coef_band_start, coef_count_band_start;
+ int cxt_num;
+ int cxt, coef_cxt_start, coef_count_cxt_start;
+ int node, coef_node_start, coef_count_node_start;
+
+ int tree_i, tree_left, tree_right;
+ int mvd_i;
+
+ int count_sat = 24;
+ /*int update_factor = 112;*/ /*If COEF_MAX_UPDATE_FACTOR_AFTER_KEY,
+ *use 128
+ */
+ /* If COEF_MAX_UPDATE_FACTOR_AFTER_KEY, use 128*/
+ /*int update_factor = (pic_count == 1) ? 128 : 112;*/
+ int update_factor = cur_kf ? 112 :
+ prev_kf ? 128 : 112;
+
+ int prob_32;
+ int prob_res;
+ int prob_shift;
+ int pre_prob;
+
+ int num, den;
+ int get_prob;
+ int m_count;
+ int factor;
+
+ int new_prob;
+
+ if (debug & VP9_DEBUG_MERGE)
+ pr_info
+ ("\n ##adapt_coef_probs (pre_fc : %d ,prev_kf : %d,cur_kf : %d)##\n\n",
+ pre_fc, prev_kf, cur_kf);
+
+ /*adapt_coef_probs*/
+ for (tx_size = 0; tx_size < 4; tx_size++) {
+ coef_tx_size_start = VP9_COEF_START
+ + tx_size * 4 * VP9_COEF_SIZE_ONE_SET;
+ coef_count_tx_size_start = VP9_COEF_COUNT_START
+ + tx_size * 4 * VP9_COEF_COUNT_SIZE_ONE_SET;
+ coef_plane_start = coef_tx_size_start;
+ coef_count_plane_start = coef_count_tx_size_start;
+ for (plane = 0; plane < 2; plane++) {
+ coef_type_start = coef_plane_start;
+ coef_count_type_start = coef_count_plane_start;
+ for (type = 0; type < 2; type++) {
+ coef_band_start = coef_type_start;
+ coef_count_band_start = coef_count_type_start;
+ for (band = 0; band < 6; band++) {
+ if (band == 0)
+ cxt_num = 3;
+ else
+ cxt_num = 6;
+ coef_cxt_start = coef_band_start;
+ coef_count_cxt_start =
+ coef_count_band_start;
+ for (cxt = 0; cxt < cxt_num; cxt++) {
+ const int n0 =
+ count[coef_count_cxt_start];
+ const int n1 =
+ count[coef_count_cxt_start + 1];
+ const int n2 =
+ count[coef_count_cxt_start + 2];
+ const int neob =
+ count[coef_count_cxt_start + 3];
+ const int nneob =
+ count[coef_count_cxt_start + 4];
+ const unsigned int
+ branch_ct[3][2] = {
+ { neob, nneob },
+ { n0, n1 + n2 },
+ { n1, n2 }
+ };
+ coef_node_start =
+ coef_cxt_start;
+ for
+ (node = 0; node < 3; node++) {
+ prob_32 =
+ prev_prob[
+ coef_node_start
+ / 4 * 2];
+ prob_res =
+ coef_node_start & 3;
+ prob_shift =
+ prob_res * 8;
+ pre_prob =
+ (prob_32 >> prob_shift)
+ & 0xff;
+
+ /*get_binary_prob*/
+ num =
+ branch_ct[node][0];
+ den =
+ branch_ct[node][0] +
+ branch_ct[node][1];
+ m_count = (den <
+ count_sat)
+ ? den : count_sat;
+
+ get_prob =
+ (den == 0) ? 128u :
+ clip_prob(
+ div_r32(((int64_t)
+ num * 256
+ + (den >> 1)),
+ den));
+
+ factor =
+ update_factor * m_count
+ / count_sat;
+ new_prob =
+ ROUND_POWER_OF_TWO
+ (pre_prob *
+ (256 - factor) +
+ get_prob * factor, 8);
+
+ cur_prob[coef_node_start
+ / 4 * 2] =
+ (cur_prob
+ [coef_node_start
+ / 4 * 2] & (~(0xff <<
+ prob_shift))) |
+ (new_prob <<
+ prob_shift);
+
+ coef_node_start += 1;
+ }
+
+ coef_cxt_start =
+ coef_cxt_start + 3;
+ coef_count_cxt_start =
+ coef_count_cxt_start
+ + 5;
+ }
+ if (band == 0) {
+ coef_band_start += 10;
+ coef_count_band_start += 15;
+ } else {
+ coef_band_start += 18;
+ coef_count_band_start += 30;
+ }
+ }
+ coef_type_start += VP9_COEF_SIZE_ONE_SET;
+ coef_count_type_start +=
+ VP9_COEF_COUNT_SIZE_ONE_SET;
+ }
+ coef_plane_start += 2 * VP9_COEF_SIZE_ONE_SET;
+ coef_count_plane_start +=
+ 2 * VP9_COEF_COUNT_SIZE_ONE_SET;
+ }
+ }
+
+ if (cur_kf == 0) {
+ /*mode_mv_merge_probs - merge_intra_inter_prob*/
+ for (coef_count_node_start = VP9_INTRA_INTER_COUNT_START;
+ coef_count_node_start < (VP9_MV_CLASS0_HP_1_COUNT_START +
+ VP9_MV_CLASS0_HP_1_COUNT_SIZE); coef_count_node_start += 2) {
+
+ if (coef_count_node_start ==
+ VP9_INTRA_INTER_COUNT_START) {
+ if (debug & VP9_DEBUG_MERGE)
+ pr_info(" # merge_intra_inter_prob\n");
+ coef_node_start = VP9_INTRA_INTER_START;
+ } else if (coef_count_node_start ==
+ VP9_COMP_INTER_COUNT_START) {
+ if (debug & VP9_DEBUG_MERGE)
+ pr_info(" # merge_comp_inter_prob\n");
+ coef_node_start = VP9_COMP_INTER_START;
+ }
+ /*
+ *else if (coef_count_node_start ==
+ * VP9_COMP_REF_COUNT_START) {
+ * pr_info(" # merge_comp_inter_prob\n");
+ * coef_node_start = VP9_COMP_REF_START;
+ *}
+ *else if (coef_count_node_start ==
+ * VP9_SINGLE_REF_COUNT_START) {
+ * pr_info(" # merge_comp_inter_prob\n");
+ * coef_node_start = VP9_SINGLE_REF_START;
+ *}
+ */
+ else if (coef_count_node_start ==
+ VP9_TX_MODE_COUNT_START) {
+ if (debug & VP9_DEBUG_MERGE)
+ pr_info(" # merge_tx_mode_probs\n");
+ coef_node_start = VP9_TX_MODE_START;
+ } else if (coef_count_node_start ==
+ VP9_SKIP_COUNT_START) {
+ if (debug & VP9_DEBUG_MERGE)
+ pr_info(" # merge_skip_probs\n");
+ coef_node_start = VP9_SKIP_START;
+ } else if (coef_count_node_start ==
+ VP9_MV_SIGN_0_COUNT_START) {
+ if (debug & VP9_DEBUG_MERGE)
+ pr_info(" # merge_sign_0\n");
+ coef_node_start = VP9_MV_SIGN_0_START;
+ } else if (coef_count_node_start ==
+ VP9_MV_SIGN_1_COUNT_START) {
+ if (debug & VP9_DEBUG_MERGE)
+ pr_info(" # merge_sign_1\n");
+ coef_node_start = VP9_MV_SIGN_1_START;
+ } else if (coef_count_node_start ==
+ VP9_MV_BITS_0_COUNT_START) {
+ if (debug & VP9_DEBUG_MERGE)
+ pr_info(" # merge_bits_0\n");
+ coef_node_start = VP9_MV_BITS_0_START;
+ } else if (coef_count_node_start ==
+ VP9_MV_BITS_1_COUNT_START) {
+ if (debug & VP9_DEBUG_MERGE)
+ pr_info(" # merge_bits_1\n");
+ coef_node_start = VP9_MV_BITS_1_START;
+ } else if (coef_count_node_start ==
+ VP9_MV_CLASS0_HP_0_COUNT_START) {
+ if (debug & VP9_DEBUG_MERGE)
+ pr_info(" # merge_class0_hp\n");
+ coef_node_start = VP9_MV_CLASS0_HP_0_START;
+ }
+
+
+ den = count[coef_count_node_start] +
+ count[coef_count_node_start + 1];
+
+ prob_32 = prev_prob[coef_node_start / 4 * 2];
+ prob_res = coef_node_start & 3;
+ prob_shift = prob_res * 8;
+ pre_prob = (prob_32 >> prob_shift) & 0xff;
+
+ if (den == 0)
+ new_prob = pre_prob;
+ else {
+ m_count = (den < MODE_MV_COUNT_SAT) ?
+ den : MODE_MV_COUNT_SAT;
+ get_prob =
+ clip_prob(
+ div_r32(((int64_t)count[coef_count_node_start]
+ * 256 + (den >> 1)),
+ den));
+ /*weighted_prob*/
+ factor = count_to_update_factor[m_count];
+ new_prob =
+ ROUND_POWER_OF_TWO(pre_prob * (256 - factor)
+ + get_prob * factor, 8);
+ }
+ cur_prob[coef_node_start / 4 * 2] =
+ (cur_prob[coef_node_start / 4 * 2] &
+ (~(0xff << prob_shift)))
+ | (new_prob << prob_shift);
+
+ coef_node_start = coef_node_start + 1;
+ }
+ if (debug & VP9_DEBUG_MERGE)
+ pr_info(" # merge_vp9_inter_mode_tree\n");
+ coef_node_start = VP9_INTER_MODE_START;
+ coef_count_node_start = VP9_INTER_MODE_COUNT_START;
+ for (tree_i = 0; tree_i < 7; tree_i++) {
+ for (node = 0; node < 3; node++) {
+ switch (node) {
+ case 2:
+ tree_left =
+ count[coef_count_node_start + 1];
+ tree_right =
+ count[coef_count_node_start + 3];
+ break;
+ case 1:
+ tree_left =
+ count[coef_count_node_start + 0];
+ tree_right =
+ count[coef_count_node_start + 1]
+ + count[coef_count_node_start + 3];
+ break;
+ default:
+ tree_left =
+ count[coef_count_node_start + 2];
+ tree_right =
+ count[coef_count_node_start + 0]
+ + count[coef_count_node_start + 1]
+ + count[coef_count_node_start + 3];
+ break;
+
+ }
+
+ vp9_tree_merge_probs(prev_prob, cur_prob,
+ coef_node_start, tree_left, tree_right,
+ tree_i, node);
+
+ coef_node_start = coef_node_start + 1;
+ }
+ coef_count_node_start = coef_count_node_start + 4;
+ }
+ if (debug & VP9_DEBUG_MERGE)
+ pr_info(" # merge_vp9_intra_mode_tree\n");
+ coef_node_start = VP9_IF_Y_MODE_START;
+ coef_count_node_start = VP9_IF_Y_MODE_COUNT_START;
+ for (tree_i = 0; tree_i < 14; tree_i++) {
+ for (node = 0; node < 9; node++) {
+ switch (node) {
+ case 8:
+ tree_left =
+ count[coef_count_node_start+D153_PRED];
+ tree_right =
+ count[coef_count_node_start+D207_PRED];
+ break;
+ case 7:
+ tree_left =
+ count[coef_count_node_start+D63_PRED];
+ tree_right =
+ count[coef_count_node_start+D207_PRED] +
+ count[coef_count_node_start+D153_PRED];
+ break;
+ case 6:
+ tree_left =
+ count[coef_count_node_start + D45_PRED];
+ tree_right =
+ count[coef_count_node_start+D207_PRED] +
+ count[coef_count_node_start+D153_PRED] +
+ count[coef_count_node_start+D63_PRED];
+ break;
+ case 5:
+ tree_left =
+ count[coef_count_node_start+D135_PRED];
+ tree_right =
+ count[coef_count_node_start+D117_PRED];
+ break;
+ case 4:
+ tree_left =
+ count[coef_count_node_start+H_PRED];
+ tree_right =
+ count[coef_count_node_start+D117_PRED] +
+ count[coef_count_node_start+D135_PRED];
+ break;
+ case 3:
+ tree_left =
+ count[coef_count_node_start+H_PRED] +
+ count[coef_count_node_start+D117_PRED] +
+ count[coef_count_node_start+D135_PRED];
+ tree_right =
+ count[coef_count_node_start+D45_PRED] +
+ count[coef_count_node_start+D207_PRED] +
+ count[coef_count_node_start+D153_PRED] +
+ count[coef_count_node_start+D63_PRED];
+ break;
+ case 2:
+ tree_left =
+ count[coef_count_node_start+V_PRED];
+ tree_right =
+ count[coef_count_node_start+H_PRED] +
+ count[coef_count_node_start+D117_PRED] +
+ count[coef_count_node_start+D135_PRED] +
+ count[coef_count_node_start+D45_PRED] +
+ count[coef_count_node_start+D207_PRED] +
+ count[coef_count_node_start+D153_PRED] +
+ count[coef_count_node_start+D63_PRED];
+ break;
+ case 1:
+ tree_left =
+ count[coef_count_node_start+TM_PRED];
+ tree_right =
+ count[coef_count_node_start+V_PRED] +
+ count[coef_count_node_start+H_PRED] +
+ count[coef_count_node_start+D117_PRED] +
+ count[coef_count_node_start+D135_PRED] +
+ count[coef_count_node_start+D45_PRED] +
+ count[coef_count_node_start+D207_PRED] +
+ count[coef_count_node_start+D153_PRED] +
+ count[coef_count_node_start+D63_PRED];
+ break;
+ default:
+ tree_left =
+ count[coef_count_node_start+DC_PRED];
+ tree_right =
+ count[coef_count_node_start+TM_PRED] +
+ count[coef_count_node_start+V_PRED] +
+ count[coef_count_node_start+H_PRED] +
+ count[coef_count_node_start+D117_PRED] +
+ count[coef_count_node_start+D135_PRED] +
+ count[coef_count_node_start+D45_PRED] +
+ count[coef_count_node_start+D207_PRED] +
+ count[coef_count_node_start+D153_PRED] +
+ count[coef_count_node_start+D63_PRED];
+ break;
+
+ }
+
+ vp9_tree_merge_probs(prev_prob, cur_prob,
+ coef_node_start, tree_left, tree_right,
+ tree_i, node);
+
+ coef_node_start = coef_node_start + 1;
+ }
+ coef_count_node_start = coef_count_node_start + 10;
+ }
+
+ if (debug & VP9_DEBUG_MERGE)
+ pr_info(" # merge_vp9_partition_tree\n");
+ coef_node_start = VP9_PARTITION_P_START;
+ coef_count_node_start = VP9_PARTITION_P_COUNT_START;
+ for (tree_i = 0; tree_i < 16; tree_i++) {
+ for (node = 0; node < 3; node++) {
+ switch (node) {
+ case 2:
+ tree_left =
+ count[coef_count_node_start + 2];
+ tree_right =
+ count[coef_count_node_start + 3];
+ break;
+ case 1:
+ tree_left =
+ count[coef_count_node_start + 1];
+ tree_right =
+ count[coef_count_node_start + 2] +
+ count[coef_count_node_start + 3];
+ break;
+ default:
+ tree_left =
+ count[coef_count_node_start + 0];
+ tree_right =
+ count[coef_count_node_start + 1] +
+ count[coef_count_node_start + 2] +
+ count[coef_count_node_start + 3];
+ break;
+
+ }
+
+ vp9_tree_merge_probs(prev_prob, cur_prob,
+ coef_node_start,
+ tree_left, tree_right, tree_i, node);
+
+ coef_node_start = coef_node_start + 1;
+ }
+ coef_count_node_start = coef_count_node_start + 4;
+ }
+
+ if (debug & VP9_DEBUG_MERGE)
+ pr_info(" # merge_vp9_switchable_interp_tree\n");
+ coef_node_start = VP9_INTERP_START;
+ coef_count_node_start = VP9_INTERP_COUNT_START;
+ for (tree_i = 0; tree_i < 4; tree_i++) {
+ for (node = 0; node < 2; node++) {
+ switch (node) {
+ case 1:
+ tree_left =
+ count[coef_count_node_start + 1];
+ tree_right =
+ count[coef_count_node_start + 2];
+ break;
+ default:
+ tree_left =
+ count[coef_count_node_start + 0];
+ tree_right =
+ count[coef_count_node_start + 1] +
+ count[coef_count_node_start + 2];
+ break;
+
+ }
+
+ vp9_tree_merge_probs(prev_prob, cur_prob,
+ coef_node_start,
+ tree_left, tree_right, tree_i, node);
+
+ coef_node_start = coef_node_start + 1;
+ }
+ coef_count_node_start = coef_count_node_start + 3;
+ }
+
+ if (debug & VP9_DEBUG_MERGE)
+ pr_info("# merge_vp9_mv_joint_tree\n");
+ coef_node_start = VP9_MV_JOINTS_START;
+ coef_count_node_start = VP9_MV_JOINTS_COUNT_START;
+ for (tree_i = 0; tree_i < 1; tree_i++) {
+ for (node = 0; node < 3; node++) {
+ switch (node) {
+ case 2:
+ tree_left =
+ count[coef_count_node_start + 2];
+ tree_right =
+ count[coef_count_node_start + 3];
+ break;
+ case 1:
+ tree_left =
+ count[coef_count_node_start + 1];
+ tree_right =
+ count[coef_count_node_start + 2] +
+ count[coef_count_node_start + 3];
+ break;
+ default:
+ tree_left =
+ count[coef_count_node_start + 0];
+ tree_right =
+ count[coef_count_node_start + 1] +
+ count[coef_count_node_start + 2] +
+ count[coef_count_node_start + 3];
+ break;
+ }
+
+ vp9_tree_merge_probs(prev_prob, cur_prob,
+ coef_node_start,
+ tree_left, tree_right, tree_i, node);
+
+ coef_node_start = coef_node_start + 1;
+ }
+ coef_count_node_start = coef_count_node_start + 4;
+ }
+
+ for (mvd_i = 0; mvd_i < 2; mvd_i++) {
+ if (debug & VP9_DEBUG_MERGE)
+ pr_info(" # merge_vp9_mv_class_tree [%d] -\n", mvd_i);
+ coef_node_start =
+ mvd_i ? VP9_MV_CLASSES_1_START : VP9_MV_CLASSES_0_START;
+ coef_count_node_start =
+ mvd_i ? VP9_MV_CLASSES_1_COUNT_START
+ : VP9_MV_CLASSES_0_COUNT_START;
+ tree_i = 0;
+ for (node = 0; node < 10; node++) {
+ switch (node) {
+ case 9:
+ tree_left =
+ count[coef_count_node_start + 9];
+ tree_right =
+ count[coef_count_node_start + 10];
+ break;
+ case 8:
+ tree_left =
+ count[coef_count_node_start + 7];
+ tree_right =
+ count[coef_count_node_start + 8];
+ break;
+ case 7:
+ tree_left =
+ count[coef_count_node_start + 7] +
+ count[coef_count_node_start + 8];
+ tree_right =
+ count[coef_count_node_start + 9] +
+ count[coef_count_node_start + 10];
+ break;
+ case 6:
+ tree_left =
+ count[coef_count_node_start + 6];
+ tree_right =
+ count[coef_count_node_start + 7] +
+ count[coef_count_node_start + 8] +
+ count[coef_count_node_start + 9] +
+ count[coef_count_node_start + 10];
+ break;
+ case 5:
+ tree_left =
+ count[coef_count_node_start + 4];
+ tree_right =
+ count[coef_count_node_start + 5];
+ break;
+ case 4:
+ tree_left =
+ count[coef_count_node_start + 4] +
+ count[coef_count_node_start + 5];
+ tree_right =
+ count[coef_count_node_start + 6] +
+ count[coef_count_node_start + 7] +
+ count[coef_count_node_start + 8] +
+ count[coef_count_node_start + 9] +
+ count[coef_count_node_start + 10];
+ break;
+ case 3:
+ tree_left =
+ count[coef_count_node_start + 2];
+ tree_right =
+ count[coef_count_node_start + 3];
+ break;
+ case 2:
+ tree_left =
+ count[coef_count_node_start + 2] +
+ count[coef_count_node_start + 3];
+ tree_right =
+ count[coef_count_node_start + 4] +
+ count[coef_count_node_start + 5] +
+ count[coef_count_node_start + 6] +
+ count[coef_count_node_start + 7] +
+ count[coef_count_node_start + 8] +
+ count[coef_count_node_start + 9] +
+ count[coef_count_node_start + 10];
+ break;
+ case 1:
+ tree_left =
+ count[coef_count_node_start + 1];
+ tree_right =
+ count[coef_count_node_start + 2] +
+ count[coef_count_node_start + 3] +
+ count[coef_count_node_start + 4] +
+ count[coef_count_node_start + 5] +
+ count[coef_count_node_start + 6] +
+ count[coef_count_node_start + 7] +
+ count[coef_count_node_start + 8] +
+ count[coef_count_node_start + 9] +
+ count[coef_count_node_start + 10];
+ break;
+ default:
+ tree_left =
+ count[coef_count_node_start + 0];
+ tree_right =
+ count[coef_count_node_start + 1] +
+ count[coef_count_node_start + 2] +
+ count[coef_count_node_start + 3] +
+ count[coef_count_node_start + 4] +
+ count[coef_count_node_start + 5] +
+ count[coef_count_node_start + 6] +
+ count[coef_count_node_start + 7] +
+ count[coef_count_node_start + 8] +
+ count[coef_count_node_start + 9] +
+ count[coef_count_node_start + 10];
+ break;
+
+ }
+
+ vp9_tree_merge_probs(prev_prob, cur_prob,
+ coef_node_start, tree_left, tree_right,
+ tree_i, node);
+
+ coef_node_start = coef_node_start + 1;
+ }
+
+ if (debug & VP9_DEBUG_MERGE)
+ pr_info(" # merge_vp9_mv_class0_tree [%d] -\n", mvd_i);
+ coef_node_start =
+ mvd_i ? VP9_MV_CLASS0_1_START : VP9_MV_CLASS0_0_START;
+ coef_count_node_start =
+ mvd_i ? VP9_MV_CLASS0_1_COUNT_START :
+ VP9_MV_CLASS0_0_COUNT_START;
+ tree_i = 0;
+ node = 0;
+ tree_left = count[coef_count_node_start + 0];
+ tree_right = count[coef_count_node_start + 1];
+
+ vp9_tree_merge_probs(prev_prob, cur_prob, coef_node_start,
+ tree_left, tree_right, tree_i, node);
+ if (debug & VP9_DEBUG_MERGE)
+ pr_info(" # merge_vp9_mv_fp_tree_class0_fp [%d] -\n",
+ mvd_i);
+ coef_node_start =
+ mvd_i ? VP9_MV_CLASS0_FP_1_START :
+ VP9_MV_CLASS0_FP_0_START;
+ coef_count_node_start =
+ mvd_i ? VP9_MV_CLASS0_FP_1_COUNT_START :
+ VP9_MV_CLASS0_FP_0_COUNT_START;
+ for (tree_i = 0; tree_i < 3; tree_i++) {
+ for (node = 0; node < 3; node++) {
+ switch (node) {
+ case 2:
+ tree_left =
+ count[coef_count_node_start + 2];
+ tree_right =
+ count[coef_count_node_start + 3];
+ break;
+ case 1:
+ tree_left =
+ count[coef_count_node_start + 1];
+ tree_right =
+ count[coef_count_node_start + 2]
+ + count[coef_count_node_start + 3];
+ break;
+ default:
+ tree_left =
+ count[coef_count_node_start + 0];
+ tree_right =
+ count[coef_count_node_start + 1]
+ + count[coef_count_node_start + 2]
+ + count[coef_count_node_start + 3];
+ break;
+
+ }
+
+ vp9_tree_merge_probs(prev_prob, cur_prob,
+ coef_node_start, tree_left, tree_right,
+ tree_i, node);
+
+ coef_node_start = coef_node_start + 1;
+ }
+ coef_count_node_start = coef_count_node_start + 4;
+ }
+
+ } /* for mvd_i (mvd_y or mvd_x)*/
+}
+
+}
+
+static bool v4l_is_there_vframe_bound(struct VP9Decoder_s *pbi)
+{
+ int i;
+ struct VP9_Common_s *const cm = &pbi->common;
+ struct RefCntBuffer_s *frame_bufs = cm->buffer_pool->frame_bufs;
+
+ for (i = 0; i < pbi->used_buf_num; ++i) {
+ if (frame_bufs[i].buf.vframe_bound)
+ return true;
+ }
+
+ return false;
+}
+
+static void v4l_mmu_buffer_release(struct VP9Decoder_s *pbi)
+{
+ struct VP9_Common_s *const cm = &pbi->common;
+ struct RefCntBuffer_s *frame_bufs = cm->buffer_pool->frame_bufs;
+ int i;
+
+ /* release workspace */
+ if (pbi->bmmu_box)
+ decoder_bmmu_box_free_idx(pbi->bmmu_box,
+ WORK_SPACE_BUF_ID);
+ /*
+ * it's only when vframe get back to driver, right now we can be sure
+ * that vframe and fd are related. if the playback exits, the capture
+ * requires the upper app to release when the fd is closed, and others
+ * buffers drivers are released by driver.
+ */
+ for (i = 0; i < pbi->used_buf_num; ++i) {
+ if (!frame_bufs[i].buf.vframe_bound) {
+ if (pbi->bmmu_box)
+ decoder_bmmu_box_free_idx(pbi->bmmu_box,
+ HEADER_BUFFER_IDX(i));
+ if (pbi->mmu_box)
+ decoder_mmu_box_free_idx(pbi->mmu_box, i);
+
+ vp9_print(pbi, PRINT_FLAG_V4L_DETAIL,
+ "%s free buffer[%d], bmmu_box: %p, mmu_box: %p\n",
+ __func__, i, pbi->bmmu_box, pbi->mmu_box);
+ }
+ }
+}
+
+static void uninit_mmu_buffers(struct VP9Decoder_s *pbi)
+{
+#ifndef MV_USE_FIXED_BUF
+ dealloc_mv_bufs(pbi);
+#endif
+ if (pbi->is_used_v4l &&
+ v4l_is_there_vframe_bound(pbi)) {
+ if (get_double_write_mode(pbi) != 0x10) {
+ v4l_mmu_buffer_release(pbi);
+ return;
+ }
+ }
+
+ if (pbi->mmu_box)
+ decoder_mmu_box_free(pbi->mmu_box);
+ pbi->mmu_box = NULL;
+
+ if (pbi->bmmu_box)
+ decoder_bmmu_box_free(pbi->bmmu_box);
+ pbi->bmmu_box = NULL;
+}
+
+static int calc_luc_quantity(u32 w, u32 h)
+{
+ int lcu_size = 64; /*fixed 64*/
+ int pic_width_64 = (w + 63) & (~0x3f);
+ int pic_height_32 = (h + 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;
+
+ return pic_width_lcu * pic_height_lcu;
+}
+
+static int v4l_alloc_and_config_pic(struct VP9Decoder_s *pbi,
+ struct PIC_BUFFER_CONFIG_s *pic)
+{
+ int ret = -1;
+ int i = pic->index;
+ int dw_mode = get_double_write_mode_init(pbi);
+ int lcu_total = calc_luc_quantity(pbi->frame_width, pbi->frame_height);
+#ifdef MV_USE_FIXED_BUF
+ u32 mpred_mv_end = pbi->work_space_buf->mpred_mv.buf_start +
+ pbi->work_space_buf->mpred_mv.buf_size;
+ int mv_size = cal_mv_buf_size(pbi, pbi->frame_width, pbi->frame_height);
+#endif
+ struct vdec_v4l2_buffer *fb = NULL;
+
+ if (i < 0)
+ return ret;
+
+ ret = vdec_v4l_get_buffer(pbi->v4l2_ctx, &fb);
+ if (ret < 0) {
+ vp9_print(pbi, 0, "[%d] VP9 get buffer fail.\n",
+ ((struct aml_vcodec_ctx *) (pbi->v4l2_ctx))->id);
+ return ret;
+ }
+
+ if (pbi->mmu_enable) {
+ pbi->m_BUF[i].header_addr = decoder_bmmu_box_get_phy_addr(
+ pbi->bmmu_box, HEADER_BUFFER_IDX(i));
+ if (debug & VP9_DEBUG_BUFMGR_MORE) {
+ pr_info("MMU header_adr %d: %ld\n",
+ i, pbi->m_BUF[i].header_addr);
+ }
+ }
+
+#ifdef MV_USE_FIXED_BUF
+ if ((pbi->work_space_buf->mpred_mv.buf_start +
+ ((i + 1) * mv_size))
+ <= mpred_mv_end) {
+#endif
+ pbi->m_BUF[i].v4l_ref_buf_addr = (ulong)fb;
+ pic->cma_alloc_addr = fb->m.mem[0].addr;
+ if (fb->num_planes == 1) {
+ pbi->m_BUF[i].start_adr = fb->m.mem[0].addr;
+ pbi->m_BUF[i].luma_size = fb->m.mem[0].offset;
+ pbi->m_BUF[i].size = fb->m.mem[0].size;
+ fb->m.mem[0].bytes_used = fb->m.mem[0].size;
+ pic->dw_y_adr = pbi->m_BUF[i].start_adr;
+ pic->dw_u_v_adr = pic->dw_y_adr + pbi->m_BUF[i].luma_size;
+ } else if (fb->num_planes == 2) {
+ pbi->m_BUF[i].start_adr = fb->m.mem[0].addr;
+ pbi->m_BUF[i].size = fb->m.mem[0].size;
+ pbi->m_BUF[i].chroma_addr = fb->m.mem[1].addr;
+ pbi->m_BUF[i].chroma_size = fb->m.mem[1].size;
+ fb->m.mem[0].bytes_used = fb->m.mem[0].size;
+ fb->m.mem[1].bytes_used = fb->m.mem[1].size;
+ pic->dw_y_adr = pbi->m_BUF[i].start_adr;
+ pic->dw_u_v_adr = pbi->m_BUF[i].chroma_addr;
+ }
+
+ /* config frame buffer */
+ if (pbi->mmu_enable)
+ pic->header_adr = pbi->m_BUF[i].header_addr;
+
+ pic->BUF_index = i;
+ pic->lcu_total = lcu_total;
+ pic->mc_canvas_y = pic->index;
+ pic->mc_canvas_u_v = pic->index;
+
+ if (dw_mode & 0x10) {
+ pic->mc_canvas_y = (pic->index << 1);
+ pic->mc_canvas_u_v = (pic->index << 1) + 1;
+ }
+
+#ifdef MV_USE_FIXED_BUF
+ pic->mpred_mv_wr_start_addr =
+ pbi->work_space_buf->mpred_mv.buf_start +
+ (pic->index * mv_size);
+ pic->mv_size = mv_size;
+#endif
+ if (debug) {
+ pr_info("%s index %d BUF_index %d ",
+ __func__, pic->index,
+ pic->BUF_index);
+ pr_info("comp_body_size %x comp_buf_size %x ",
+ pic->comp_body_size,
+ pic->buf_size);
+ pr_info("mpred_mv_wr_start_adr %ld\n",
+ pic->mpred_mv_wr_start_addr);
+ pr_info("dw_y_adr %d, pic_config->dw_u_v_adr =%d\n",
+ pic->dw_y_adr,
+ pic->dw_u_v_adr);
+ }
+#ifdef MV_USE_FIXED_BUF
+ }
+#endif
+ return ret;
+}
+
+static int config_pic(struct VP9Decoder_s *pbi,
+ struct PIC_BUFFER_CONFIG_s *pic_config)
+{
+ int ret = -1;
+ int i;
+ int pic_width = pbi->init_pic_w;
+ int pic_height = pbi->init_pic_h;
+ int lcu_size = 64; /*fixed 64*/
+ int pic_width_64 = (pic_width + 63) & (~0x3f);
+ int pic_height_32 = (pic_height + 31) & (~0x1f);
+ int pic_width_lcu = (pic_width_64 % lcu_size) ?
+ pic_width_64 / lcu_size + 1
+ : pic_width_64 / lcu_size;
+ int pic_height_lcu = (pic_height_32 % lcu_size) ?
+ pic_height_32 / lcu_size + 1
+ : pic_height_32 / lcu_size;
+ int lcu_total = pic_width_lcu * pic_height_lcu;
+#ifdef MV_USE_FIXED_BUF
+ u32 mpred_mv_end = pbi->work_space_buf->mpred_mv.buf_start +
+ pbi->work_space_buf->mpred_mv.buf_size;
+ int mv_size = cal_mv_buf_size(pbi, pbi->init_pic_w, pbi->init_pic_h);
+#endif
+ u32 y_adr = 0;
+ int buf_size = 0;
+
+ int losless_comp_header_size =
+ compute_losless_comp_header_size(pic_width,
+ pic_height);
+ int losless_comp_body_size = compute_losless_comp_body_size(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(pbi);
+
+ pbi->lcu_total = lcu_total;
+
+ if (dw_mode) {
+ int pic_width_dw = pic_width /
+ get_double_write_ratio(pbi, dw_mode);
+ int pic_height_dw = pic_height /
+ get_double_write_ratio(pbi, 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;
+ if ((!pbi->mmu_enable) && ((dw_mode & 0x10) == 0))
+ buf_size += (mc_buffer_size_h << 16);
+
+ if (pbi->mmu_enable) {
+ pic_config->header_adr = decoder_bmmu_box_get_phy_addr(
+ pbi->bmmu_box, HEADER_BUFFER_IDX(pic_config->index));
+
+ if (debug & VP9_DEBUG_BUFMGR_MORE) {
+ pr_info("MMU header_adr %d: %ld\n",
+ pic_config->index, pic_config->header_adr);
+ }
+ }
+
+ i = pic_config->index;
+#ifdef MV_USE_FIXED_BUF
+ if ((pbi->work_space_buf->mpred_mv.buf_start +
+ ((i + 1) * mv_size))
+ <= mpred_mv_end
+ ) {
+#endif
+ if (buf_size > 0) {
+ ret = decoder_bmmu_box_alloc_buf_phy(pbi->bmmu_box,
+ VF_BUFFER_IDX(i),
+ buf_size, DRIVER_NAME,
+ &pic_config->cma_alloc_addr);
+ if (ret < 0) {
+ pr_info(
+ "decoder_bmmu_box_alloc_buf_phy idx %d size %d fail\n",
+ VF_BUFFER_IDX(i),
+ buf_size
+ );
+ return ret;
+ }
+
+ if (pic_config->cma_alloc_addr)
+ y_adr = pic_config->cma_alloc_addr;
+ else {
+ pr_info(
+ "decoder_bmmu_box_alloc_buf_phy idx %d size %d return null\n",
+ VF_BUFFER_IDX(i),
+ buf_size
+ );
+ return -1;
+ }
+ }
+ {
+ /*ensure get_pic_by_POC()
+ not get the buffer not decoded*/
+ pic_config->BUF_index = i;
+ pic_config->lcu_total = lcu_total;
+
+ pic_config->comp_body_size = losless_comp_body_size;
+ pic_config->buf_size = buf_size;
+
+ pic_config->mc_canvas_y = pic_config->index;
+ pic_config->mc_canvas_u_v = pic_config->index;
+ if (dw_mode & 0x10) {
+ pic_config->dw_y_adr = y_adr;
+ pic_config->dw_u_v_adr = y_adr +
+ ((mc_buffer_size_u_v_h << 16) << 1);
+
+ pic_config->mc_canvas_y =
+ (pic_config->index << 1);
+ pic_config->mc_canvas_u_v =
+ (pic_config->index << 1) + 1;
+ } else if (dw_mode) {
+ pic_config->dw_y_adr = y_adr;
+ pic_config->dw_u_v_adr = pic_config->dw_y_adr +
+ ((mc_buffer_size_u_v_h << 16) << 1);
+ }
+#ifdef MV_USE_FIXED_BUF
+ pic_config->mpred_mv_wr_start_addr =
+ pbi->work_space_buf->mpred_mv.buf_start +
+ (pic_config->index * mv_size);
+ pic_config->mv_size = mv_size;
+#endif
+ if (debug) {
+ pr_info
+ ("%s index %d BUF_index %d ",
+ __func__, pic_config->index,
+ pic_config->BUF_index);
+ pr_info
+ ("comp_body_size %x comp_buf_size %x ",
+ pic_config->comp_body_size,
+ pic_config->buf_size);
+ pr_info
+ ("mpred_mv_wr_start_adr %ld\n",
+ pic_config->mpred_mv_wr_start_addr);
+ pr_info("dw_y_adr %d, pic_config->dw_u_v_adr =%d\n",
+ pic_config->dw_y_adr,
+ pic_config->dw_u_v_adr);
+ }
+ ret = 0;
+ }
+#ifdef MV_USE_FIXED_BUF
+ }
+#endif
+ return ret;
+}
+
+static int vvp9_mmu_compress_header_size(struct VP9Decoder_s *pbi)
+{
+ if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
+ IS_8K_SIZE(pbi->max_pic_w, pbi->max_pic_h))
+ return (MMU_COMPRESS_8K_HEADER_SIZE);
+
+ return (MMU_COMPRESS_HEADER_SIZE);
+}
+
+/*#define FRAME_MMU_MAP_SIZE (MAX_FRAME_4K_NUM * 4)*/
+static int vvp9_frame_mmu_map_size(struct VP9Decoder_s *pbi)
+{
+ if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
+ IS_8K_SIZE(pbi->max_pic_w, pbi->max_pic_h))
+ return (MAX_FRAME_8K_NUM * 4);
+
+ return (MAX_FRAME_4K_NUM * 4);
+}
+
+static void init_pic_list(struct VP9Decoder_s *pbi)
+{
+ int i;
+ struct VP9_Common_s *cm = &pbi->common;
+ struct PIC_BUFFER_CONFIG_s *pic_config;
+ u32 header_size;
+ struct vdec_s *vdec = hw_to_vdec(pbi);
+
+ if (pbi->mmu_enable && ((pbi->double_write_mode & 0x10) == 0)) {
+ header_size = vvp9_mmu_compress_header_size(pbi);
+ /*alloc VP9 compress header first*/
+ for (i = 0; i < pbi->used_buf_num; i++) {
+ unsigned long buf_addr;
+ if (decoder_bmmu_box_alloc_buf_phy
+ (pbi->bmmu_box,
+ HEADER_BUFFER_IDX(i), header_size,
+ DRIVER_HEADER_NAME,
+ &buf_addr) < 0) {
+ pr_info("%s malloc compress header failed %d\n",
+ DRIVER_HEADER_NAME, i);
+ pbi->fatal_error |= DECODER_FATAL_ERROR_NO_MEM;
+ return;
+ }
+ }
+ }
+ for (i = 0; i < pbi->used_buf_num; i++) {
+ pic_config = &cm->buffer_pool->frame_bufs[i].buf;
+ pic_config->index = i;
+ pic_config->BUF_index = -1;
+ pic_config->mv_buf_index = -1;
+ if (vdec->parallel_dec == 1) {
+ pic_config->y_canvas_index = -1;
+ pic_config->uv_canvas_index = -1;
+ }
+ pic_config->y_crop_width = pbi->init_pic_w;
+ pic_config->y_crop_height = pbi->init_pic_h;
+ pic_config->double_write_mode = get_double_write_mode(pbi);
+
+ if (!pbi->is_used_v4l) {
+ if (config_pic(pbi, pic_config) < 0) {
+ if (debug)
+ pr_info("Config_pic %d fail\n",
+ pic_config->index);
+ pic_config->index = -1;
+ break;
+ }
+
+ if (pic_config->double_write_mode) {
+ set_canvas(pbi, pic_config);
+ }
+ }
+ }
+ for (; i < pbi->used_buf_num; i++) {
+ pic_config = &cm->buffer_pool->frame_bufs[i].buf;
+ pic_config->index = -1;
+ pic_config->BUF_index = -1;
+ pic_config->mv_buf_index = -1;
+ if (vdec->parallel_dec == 1) {
+ pic_config->y_canvas_index = -1;
+ pic_config->uv_canvas_index = -1;
+ }
+ }
+ pr_info("%s ok, used_buf_num = %d\n",
+ __func__, pbi->used_buf_num);
+}
+
+static void init_pic_list_hw(struct VP9Decoder_s *pbi)
+{
+ int i;
+ struct VP9_Common_s *cm = &pbi->common;
+ struct PIC_BUFFER_CONFIG_s *pic_config;
+ /*WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0x0);*/
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR,
+ (0x1 << 1) | (0x1 << 2));
+
+
+ for (i = 0; i < pbi->used_buf_num; i++) {
+ pic_config = &cm->buffer_pool->frame_bufs[i].buf;
+ if (pic_config->index < 0)
+ break;
+
+ if (pbi->mmu_enable && ((pic_config->double_write_mode & 0x10) == 0)) {
+
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA,
+ pic_config->header_adr >> 5);
+ } else {
+ /*WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
+ * pic_config->mc_y_adr
+ * | (pic_config->mc_canvas_y << 8) | 0x1);
+ */
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA,
+ pic_config->dw_y_adr >> 5);
+ }
+#ifndef LOSLESS_COMPRESS_MODE
+ /*WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
+ * pic_config->mc_u_v_adr
+ * | (pic_config->mc_canvas_u_v << 8)| 0x1);
+ */
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA,
+ pic_config->header_adr >> 5);
+#else
+ if (pic_config->double_write_mode & 0x10) {
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA,
+ pic_config->dw_u_v_adr >> 5);
+ }
+#endif
+ }
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0x1);
+
+ /*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);
+}
+
+
+static void dump_pic_list(struct VP9Decoder_s *pbi)
+{
+ struct VP9_Common_s *const cm = &pbi->common;
+ struct PIC_BUFFER_CONFIG_s *pic_config;
+ int i;
+ for (i = 0; i < FRAME_BUFFERS; i++) {
+ pic_config = &cm->buffer_pool->frame_bufs[i].buf;
+ vp9_print(pbi, 0,
+ "Buf(%d) index %d mv_buf_index %d ref_count %d vf_ref %d dec_idx %d slice_type %d w/h %d/%d adr%ld\n",
+ i,
+ pic_config->index,
+#ifndef MV_USE_FIXED_BUF
+ pic_config->mv_buf_index,
+#else
+ -1,
+#endif
+ cm->buffer_pool->
+ frame_bufs[i].ref_count,
+ pic_config->vf_ref,
+ pic_config->decode_idx,
+ pic_config->slice_type,
+ pic_config->y_crop_width,
+ pic_config->y_crop_height,
+ pic_config->cma_alloc_addr
+ );
+ }
+ return;
+}
+
+static int config_pic_size(struct VP9Decoder_s *pbi, unsigned short bit_depth)
+{
+#ifdef LOSLESS_COMPRESS_MODE
+ unsigned int data32;
+#endif
+ int losless_comp_header_size, losless_comp_body_size;
+ struct VP9_Common_s *cm = &pbi->common;
+ struct PIC_BUFFER_CONFIG_s *cur_pic_config = &cm->cur_frame->buf;
+
+ frame_width = cur_pic_config->y_crop_width;
+ frame_height = cur_pic_config->y_crop_height;
+ cur_pic_config->bit_depth = bit_depth;
+ cur_pic_config->double_write_mode = get_double_write_mode(pbi);
+ losless_comp_header_size =
+ compute_losless_comp_header_size(cur_pic_config->y_crop_width,
+ cur_pic_config->y_crop_height);
+ losless_comp_body_size =
+ compute_losless_comp_body_size(cur_pic_config->y_crop_width,
+ cur_pic_config->y_crop_height, (bit_depth == VPX_BITS_10));
+ cur_pic_config->comp_body_size = losless_comp_body_size;
+#ifdef LOSLESS_COMPRESS_MODE
+ data32 = READ_VREG(HEVC_SAO_CTRL5);
+ if (bit_depth == VPX_BITS_10)
+ data32 &= ~(1 << 9);
+ else
+ data32 |= (1 << 9);
+
+ WRITE_VREG(HEVC_SAO_CTRL5, data32);
+
+ if (pbi->mmu_enable) {
+ /*bit[4] : paged_mem_mode*/
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0x1 << 4));
+ } else {
+ /*bit[3] smem mdoe*/
+ if (bit_depth == VPX_BITS_10)
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0 << 3));
+ else
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (1 << 3));
+ }
+ if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SM1)
+ 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);
+ if (get_double_write_mode(pbi) & 0x10)
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31);
+#else
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31);
+#endif
+ return 0;
+}
+
+static int config_mc_buffer(struct VP9Decoder_s *pbi, unsigned short bit_depth)
+{
+ int i;
+ struct VP9_Common_s *cm = &pbi->common;
+ struct PIC_BUFFER_CONFIG_s *cur_pic_config = &cm->cur_frame->buf;
+ uint8_t scale_enable = 0;
+
+ if (debug&VP9_DEBUG_BUFMGR_MORE)
+ pr_info("config_mc_buffer entered .....\n");
+
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
+ (0 << 8) | (0 << 1) | 1);
+ for (i = 0; i < REFS_PER_FRAME; ++i) {
+ struct PIC_BUFFER_CONFIG_s *pic_config = cm->frame_refs[i].buf;
+ if (!pic_config)
+ continue;
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR,
+ (pic_config->mc_canvas_u_v << 16)
+ | (pic_config->mc_canvas_u_v << 8)
+ | pic_config->mc_canvas_y);
+ if (debug & VP9_DEBUG_BUFMGR_MORE)
+ pr_info("refid %x mc_canvas_u_v %x mc_canvas_y %x\n",
+ i, pic_config->mc_canvas_u_v,
+ pic_config->mc_canvas_y);
+ }
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
+ (16 << 8) | (0 << 1) | 1);
+ for (i = 0; i < REFS_PER_FRAME; ++i) {
+ struct PIC_BUFFER_CONFIG_s *pic_config = cm->frame_refs[i].buf;
+ if (!pic_config)
+ continue;
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR,
+ (pic_config->mc_canvas_u_v << 16)
+ | (pic_config->mc_canvas_u_v << 8)
+ | pic_config->mc_canvas_y);
+ }
+
+ /*auto_inc start index:0 field:0*/
+ WRITE_VREG(VP9D_MPP_REFINFO_TBL_ACCCONFIG, 0x1 << 2);
+ /*index 0:last 1:golden 2:altref*/
+ for (i = 0; i < REFS_PER_FRAME; i++) {
+ int ref_pic_body_size;
+ struct PIC_BUFFER_CONFIG_s *pic_config = cm->frame_refs[i].buf;
+ if (!pic_config)
+ continue;
+ WRITE_VREG(VP9D_MPP_REFINFO_DATA, pic_config->y_crop_width);
+ WRITE_VREG(VP9D_MPP_REFINFO_DATA, pic_config->y_crop_height);
+
+ if (pic_config->y_crop_width != cur_pic_config->y_crop_width ||
+ pic_config->y_crop_height != cur_pic_config->y_crop_height) {
+ scale_enable |= (1 << i);
+ }
+ ref_pic_body_size =
+ compute_losless_comp_body_size(pic_config->y_crop_width,
+ pic_config->y_crop_height, (bit_depth == VPX_BITS_10));
+ WRITE_VREG(VP9D_MPP_REFINFO_DATA,
+ (pic_config->y_crop_width << 14)
+ / cur_pic_config->y_crop_width);
+ WRITE_VREG(VP9D_MPP_REFINFO_DATA,
+ (pic_config->y_crop_height << 14)
+ / cur_pic_config->y_crop_height);
+ if (pbi->mmu_enable)
+ WRITE_VREG(VP9D_MPP_REFINFO_DATA, 0);
+ else
+ WRITE_VREG(VP9D_MPP_REFINFO_DATA, ref_pic_body_size >> 5);
+ }
+ WRITE_VREG(VP9D_MPP_REF_SCALE_ENBL, scale_enable);
+ return 0;
+}
+
+static void clear_mpred_hw(struct VP9Decoder_s *pbi)
+{
+ unsigned int data32;
+
+ data32 = READ_VREG(HEVC_MPRED_CTRL4);
+ data32 &= (~(1 << 6));
+ WRITE_VREG(HEVC_MPRED_CTRL4, data32);
+}
+
+static void config_mpred_hw(struct VP9Decoder_s *pbi)
+{
+ struct VP9_Common_s *cm = &pbi->common;
+ struct PIC_BUFFER_CONFIG_s *cur_pic_config = &cm->cur_frame->buf;
+ struct PIC_BUFFER_CONFIG_s *last_frame_pic_config =
+ &cm->prev_frame->buf;
+
+ unsigned int data32;
+ int mpred_curr_lcu_x;
+ int mpred_curr_lcu_y;
+ int mpred_mv_rd_end_addr;
+
+
+ mpred_mv_rd_end_addr = last_frame_pic_config->mpred_mv_wr_start_addr
+ + last_frame_pic_config->mv_size;
+ //+ (last_frame_pic_config->lcu_total * MV_MEM_UNIT);
+
+ data32 = READ_VREG(HEVC_MPRED_CURR_LCU);
+ mpred_curr_lcu_x = data32 & 0xffff;
+ mpred_curr_lcu_y = (data32 >> 16) & 0xffff;
+
+ if (debug & VP9_DEBUG_BUFMGR)
+ pr_info("cur pic_config index %d col pic_config index %d\n",
+ cur_pic_config->index, last_frame_pic_config->index);
+ WRITE_VREG(HEVC_MPRED_CTRL3, 0x24122412);
+ WRITE_VREG(HEVC_MPRED_ABV_START_ADDR,
+ pbi->work_space_buf->mpred_above.buf_start);
+
+ data32 = READ_VREG(HEVC_MPRED_CTRL4);
+
+ data32 &= (~(1 << 6));
+ data32 |= (cm->use_prev_frame_mvs << 6);
+ WRITE_VREG(HEVC_MPRED_CTRL4, data32);
+
+ WRITE_VREG(HEVC_MPRED_MV_WR_START_ADDR,
+ cur_pic_config->mpred_mv_wr_start_addr);
+ WRITE_VREG(HEVC_MPRED_MV_WPTR, cur_pic_config->mpred_mv_wr_start_addr);
+
+ WRITE_VREG(HEVC_MPRED_MV_RD_START_ADDR,
+ last_frame_pic_config->mpred_mv_wr_start_addr);
+ WRITE_VREG(HEVC_MPRED_MV_RPTR,
+ last_frame_pic_config->mpred_mv_wr_start_addr);
+ /*data32 = ((pbi->lcu_x_num - pbi->tile_width_lcu)*MV_MEM_UNIT);*/
+ /*WRITE_VREG(HEVC_MPRED_MV_WR_ROW_JUMP,data32);*/
+ /*WRITE_VREG(HEVC_MPRED_MV_RD_ROW_JUMP,data32);*/
+ WRITE_VREG(HEVC_MPRED_MV_RD_END_ADDR, mpred_mv_rd_end_addr);
+
+}
+
+static void config_sao_hw(struct VP9Decoder_s *pbi, union param_u *params)
+{
+ struct VP9_Common_s *cm = &pbi->common;
+ struct PIC_BUFFER_CONFIG_s *pic_config = &cm->cur_frame->buf;
+
+ unsigned int data32;
+ int lcu_size = 64;
+ int mc_buffer_size_u_v =
+ pic_config->lcu_total * lcu_size*lcu_size/2;
+ int mc_buffer_size_u_v_h =
+ (mc_buffer_size_u_v + 0xffff) >> 16;/*64k alignment*/
+ struct aml_vcodec_ctx * v4l2_ctx = pbi->v4l2_ctx;
+
+ if (get_double_write_mode(pbi)) {
+ WRITE_VREG(HEVC_SAO_Y_START_ADDR, pic_config->dw_y_adr);
+ WRITE_VREG(HEVC_SAO_C_START_ADDR, pic_config->dw_u_v_adr);
+ WRITE_VREG(HEVC_SAO_Y_WPTR, pic_config->dw_y_adr);
+ WRITE_VREG(HEVC_SAO_C_WPTR, pic_config->dw_u_v_adr);
+ } else {
+ WRITE_VREG(HEVC_SAO_Y_START_ADDR, 0xffffffff);
+ WRITE_VREG(HEVC_SAO_C_START_ADDR, 0xffffffff);
+ }
+ if (pbi->mmu_enable)
+ WRITE_VREG(HEVC_CM_HEADER_START_ADDR, pic_config->header_adr);
+
+ data32 = (mc_buffer_size_u_v_h << 16) << 1;
+ /*pr_info("data32=%x,mc_buffer_size_u_v_h=%x,lcu_total=%x\n",
+ * data32, mc_buffer_size_u_v_h, pic_config->lcu_total);
+ */
+ WRITE_VREG(HEVC_SAO_Y_LENGTH, data32);
+
+ data32 = (mc_buffer_size_u_v_h << 16);
+ WRITE_VREG(HEVC_SAO_C_LENGTH, data32);
+
+#ifdef VP9_10B_NV21
+#ifdef DOS_PROJECT
+ data32 = READ_VREG(HEVC_SAO_CTRL1);
+ data32 &= (~0x3000);
+ /*[13:12] axi_aformat, 0-Linear, 1-32x32, 2-64x32*/
+ data32 |= (pbi->mem_map_mode << 12);
+ 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);
+ data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG);
+ data32 &= (~0x30);
+ /*[5:4] address_format 00:linear 01:32x32 10:64x32*/
+ data32 |= (pbi->mem_map_mode << 4);
+ 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 |= (pbi->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);
+
+ data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG);
+ data32 &= (~0x30);
+ /*[5:4] address_format 00:linear 01:32x32 10:64x32*/
+ data32 |= (pbi->mem_map_mode << 4);
+ data32 &= (~0xF);
+ data32 |= 0x8; /*Big-Endian per 64-bit*/
+ WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32);
+#endif
+#else
+ data32 = READ_VREG(HEVC_SAO_CTRL1);
+ data32 &= (~0x3000);
+ data32 |= (pbi->mem_map_mode <<
+ 12);
+
+/* [13:12] axi_aformat, 0-Linear,
+ * 1-32x32, 2-64x32
+ */
+ data32 &= (~0xff0);
+ /* data32 |= 0x670; // Big-Endian per 64-bit */
+ data32 |= endian; /* Big-Endian per 64-bit */
+ data32 &= (~0x3); /*[1]:dw_disable [0]:cm_disable*/
+ if (get_double_write_mode(pbi) == 0)
+ data32 |= 0x2; /*disable double write*/
+ else if (get_double_write_mode(pbi) & 0x10)
+ data32 |= 0x1; /*disable cm*/
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { /* >= G12A dw write control */
+ unsigned int data;
+ data = READ_VREG(HEVC_DBLK_CFGB);
+ data &= (~0x300); /*[8]:first write enable (compress) [9]:double write enable (uncompress)*/
+ if (get_double_write_mode(pbi) == 0)
+ data |= (0x1 << 8); /*enable first write*/
+ else if (get_double_write_mode(pbi) & 0x10)
+ data |= (0x1 << 9); /*double write only*/
+ else
+ data |= ((0x1 << 8) |(0x1 << 9));
+ WRITE_VREG(HEVC_DBLK_CFGB, data);
+ }
+
+ /* swap uv */
+ if (pbi->is_used_v4l) {
+ if ((v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21) ||
+ (v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21M))
+ data32 &= ~(1 << 8); /* NV21 */
+ else
+ data32 |= (1 << 8); /* NV12 */
+ }
+
+ /*
+ * [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(pbi) & 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 {
+ data32 = READ_VREG(HEVC_SAO_CTRL5);
+ data32 &= (~(0xff << 16));
+ if (get_double_write_mode(pbi) == 2 ||
+ get_double_write_mode(pbi) == 3)
+ data32 |= (0xff<<16);
+ else if (get_double_write_mode(pbi) == 4)
+ data32 |= (0x33<<16);
+ WRITE_VREG(HEVC_SAO_CTRL5, data32);
+ }
+
+ data32 = READ_VREG(HEVCD_IPP_AXIIF_CONFIG);
+ data32 &= (~0x30);
+ /* [5:4] -- address_format 00:linear 01:32x32 10:64x32 */
+ data32 |= (pbi->mem_map_mode <<
+ 4);
+ data32 &= (~0xF);
+ data32 |= 0xf; /* valid only when double write only */
+ /*data32 |= 0x8;*/ /* Big-Endian per 64-bit */
+
+ /* swap uv */
+ if (pbi->is_used_v4l) {
+ if ((v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21) ||
+ (v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21M))
+ data32 |= (1 << 12); /* NV21 */
+ else
+ data32 &= ~(1 << 12); /* NV12 */
+ }
+
+ /*
+ * [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
+ */
+ WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32);
+#endif
+}
+
+static void vp9_config_work_space_hw(struct VP9Decoder_s *pbi, u32 mask)
+{
+ struct BuffInfo_s *buf_spec = pbi->work_space_buf;
+ unsigned int data32;
+ int losless_comp_header_size, losless_comp_body_size;
+
+ if (debug && pbi->init_flag == 0)
+ pr_info("%s w %d h %d %x %x %x %x %x %x %x %x %x %x %x %x\n",
+ __func__,
+ buf_spec->max_width,
+ buf_spec->max_height,
+ buf_spec->ipp.buf_start,
+ buf_spec->start_adr,
+ buf_spec->short_term_rps.buf_start,
+ buf_spec->vps.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);
+
+ if (mask & HW_MASK_FRONT) {
+ if ((debug & VP9_DEBUG_SEND_PARAM_WITH_REG) == 0)
+ WRITE_VREG(HEVC_RPM_BUFFER, (u32)pbi->rpm_phy_addr);
+
+ WRITE_VREG(HEVC_SHORT_TERM_RPS,
+ buf_spec->short_term_rps.buf_start);
+ /*WRITE_VREG(HEVC_VPS_BUFFER, buf_spec->vps.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_STREAM_SWAP_BUFFER,
+ buf_spec->swap_buf.buf_start);
+ WRITE_VREG(HEVC_STREAM_SWAP_BUFFER2,
+ buf_spec->swap_buf2.buf_start);
+ WRITE_VREG(LMEM_DUMP_ADR, (u32)pbi->lmem_phy_addr);
+
+ }
+
+ if (mask & HW_MASK_BACK) {
+#ifdef LOSLESS_COMPRESS_MODE
+ losless_comp_header_size =
+ compute_losless_comp_header_size(pbi->init_pic_w,
+ pbi->init_pic_h);
+ losless_comp_body_size =
+ compute_losless_comp_body_size(pbi->init_pic_w,
+ pbi->init_pic_h, buf_alloc_depth == 10);
+#endif
+ WRITE_VREG(HEVCD_IPP_LINEBUFF_BASE,
+ buf_spec->ipp.buf_start);
+ //WRITE_VREG(HEVC_SAO_UP, buf_spec->sao_up.buf_start);
+ //WRITE_VREG(HEVC_SCALELUT, buf_spec->scalelut.buf_start);
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) {
+ /* cfg_addr_adp*/
+ WRITE_VREG(HEVC_DBLK_CFGE, buf_spec->dblk_para.buf_start);
+ if (debug & VP9_DEBUG_BUFMGR_MORE)
+ pr_info("Write HEVC_DBLK_CFGE\n");
+ }
+ /* cfg_p_addr */
+ WRITE_VREG(HEVC_DBLK_CFG4, buf_spec->dblk_para.buf_start);
+ /* cfg_d_addr */
+ WRITE_VREG(HEVC_DBLK_CFG5, buf_spec->dblk_data.buf_start);
+
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) {
+ /*
+ * data32 = (READ_VREG(P_HEVC_DBLK_CFG3)>>8) & 0xff; // xio left offset, default is 0x40
+ * data32 = data32 * 2;
+ * data32 = (READ_VREG(P_HEVC_DBLK_CFG3)>>16) & 0xff; // adp left offset, default is 0x040
+ * data32 = data32 * 2;
+ */
+ 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]
+ vp9_print(pbi, VP9_DEBUG_BUFMGR_MORE,
+ "HEVC_DBLK_CFG3 = %x\n", READ_VREG(HEVC_DBLK_CFG3));
+ }
+#ifdef LOSLESS_COMPRESS_MODE
+ if (pbi->mmu_enable) {
+ /*bit[4] : paged_mem_mode*/
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0x1 << 4));
+ if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SM1)
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL2, 0);
+ } else {
+ /*if(cur_pic_config->bit_depth == VPX_BITS_10)
+ * WRITE_VREG(P_HEVCD_MPP_DECOMP_CTL1, (0<<3));
+ */
+ /*bit[3] smem mdoe*/
+ /*else WRITE_VREG(P_HEVCD_MPP_DECOMP_CTL1, (1<<3));*/
+ /*bit[3] smem mdoe*/
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL2,
+ (losless_comp_body_size >> 5));
+ }
+ /*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);
+ if (get_double_write_mode(pbi) & 0x10)
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31);
+#else
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31);
+#endif
+
+ if (pbi->mmu_enable) {
+ 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(P_HEVC_SAO_CTRL9);*/
+ /*data32 |= 0x1;*/
+ /*WRITE_VREG(P_HEVC_SAO_CTRL9, data32);*/
+
+ /* use HEVC_CM_HEADER_START_ADDR */
+ data32 = READ_VREG(HEVC_SAO_CTRL5);
+ data32 |= (1<<10);
+ WRITE_VREG(HEVC_SAO_CTRL5, data32);
+ }
+
+ WRITE_VREG(VP9_SEG_MAP_BUFFER, buf_spec->seg_map.buf_start);
+
+ WRITE_VREG(LMEM_DUMP_ADR, (u32)pbi->lmem_phy_addr);
+ /**/
+ WRITE_VREG(VP9_PROB_SWAP_BUFFER, pbi->prob_buffer_phy_addr);
+ WRITE_VREG(VP9_COUNT_SWAP_BUFFER, pbi->count_buffer_phy_addr);
+ if (pbi->mmu_enable) {
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
+ WRITE_VREG(HEVC_ASSIST_MMU_MAP_ADDR, pbi->frame_mmu_map_phy_addr);
+ else
+ WRITE_VREG(VP9_MMU_MAP_BUFFER, pbi->frame_mmu_map_phy_addr);
+ }
+ }
+}
+
+
+#ifdef VP9_LPF_LVL_UPDATE
+/*
+ * Defines, declarations, sub-functions for vp9 de-block loop
+ filter Thr/Lvl table update
+ * - struct segmentation is for loop filter only (removed something)
+ * - function "vp9_loop_filter_init" and "vp9_loop_filter_frame_init" will
+ be instantiated in C_Entry
+ * - vp9_loop_filter_init run once before decoding start
+ * - vp9_loop_filter_frame_init run before every frame decoding start
+ * - set video format to VP9 is in vp9_loop_filter_init
+ */
+#define MAX_LOOP_FILTER 63
+#define MAX_REF_LF_DELTAS 4
+#define MAX_MODE_LF_DELTAS 2
+/*#define INTRA_FRAME 0*/
+/*#define LAST_FRAME 1*/
+/*#define MAX_REF_FRAMES 4*/
+#define SEGMENT_DELTADATA 0
+#define SEGMENT_ABSDATA 1
+#define MAX_SEGMENTS 8
+/*.#define SEG_TREE_PROBS (MAX_SEGMENTS-1)*/
+/*no use for loop filter, if this struct for common use, pls add it back*/
+/*#define PREDICTION_PROBS 3*/
+/* no use for loop filter, if this struct for common use, pls add it back*/
+
+enum SEG_LVL_FEATURES {
+ SEG_LVL_ALT_Q = 0, /*Use alternate Quantizer ....*/
+ SEG_LVL_ALT_LF = 1, /*Use alternate loop filter value...*/
+ SEG_LVL_REF_FRAME = 2, /*Optional Segment reference frame*/
+ SEG_LVL_SKIP = 3, /*Optional Segment (0,0) + skip mode*/
+ SEG_LVL_MAX = 4 /*Number of features supported*/
+};
+
+struct segmentation {
+ uint8_t enabled;
+ uint8_t update_map;
+ uint8_t update_data;
+ uint8_t abs_delta;
+ uint8_t temporal_update;
+
+ /*no use for loop filter, if this struct
+ *for common use, pls add it back
+ */
+ /*vp9_prob tree_probs[SEG_TREE_PROBS]; */
+ /* no use for loop filter, if this struct
+ * for common use, pls add it back
+ */
+ /*vp9_prob pred_probs[PREDICTION_PROBS];*/
+
+ int16_t feature_data[MAX_SEGMENTS][SEG_LVL_MAX];
+ unsigned int feature_mask[MAX_SEGMENTS];
+};
+
+struct loop_filter_thresh {
+ uint8_t mblim;
+ uint8_t lim;
+ uint8_t hev_thr;
+};
+
+struct loop_filter_info_n {
+ struct loop_filter_thresh lfthr[MAX_LOOP_FILTER + 1];
+ uint8_t lvl[MAX_SEGMENTS][MAX_REF_FRAMES][MAX_MODE_LF_DELTAS];
+};
+
+struct loopfilter {
+ int filter_level;
+
+ int sharpness_level;
+ int last_sharpness_level;
+
+ uint8_t mode_ref_delta_enabled;
+ uint8_t mode_ref_delta_update;
+
+ /*0 = Intra, Last, GF, ARF*/
+ signed char ref_deltas[MAX_REF_LF_DELTAS];
+ signed char last_ref_deltas[MAX_REF_LF_DELTAS];
+
+ /*0 = ZERO_MV, MV*/
+ signed char mode_deltas[MAX_MODE_LF_DELTAS];
+ signed char last_mode_deltas[MAX_MODE_LF_DELTAS];
+};
+
+static int vp9_clamp(int value, int low, int high)
+{
+ return value < low ? low : (value > high ? high : value);
+}
+
+int segfeature_active(struct segmentation *seg,
+ int segment_id,
+ enum SEG_LVL_FEATURES feature_id) {
+ return seg->enabled &&
+ (seg->feature_mask[segment_id] & (1 << feature_id));
+}
+
+int get_segdata(struct segmentation *seg, int segment_id,
+ enum SEG_LVL_FEATURES feature_id) {
+ return seg->feature_data[segment_id][feature_id];
+}
+
+static void vp9_update_sharpness(struct loop_filter_info_n *lfi,
+ int sharpness_lvl)
+{
+ int lvl;
+ /*For each possible value for the loop filter fill out limits*/
+ for (lvl = 0; lvl <= MAX_LOOP_FILTER; lvl++) {
+ /*Set loop filter parameters that control sharpness.*/
+ int block_inside_limit = lvl >> ((sharpness_lvl > 0) +
+ (sharpness_lvl > 4));
+
+ if (sharpness_lvl > 0) {
+ if (block_inside_limit > (9 - sharpness_lvl))
+ block_inside_limit = (9 - sharpness_lvl);
+ }
+
+ if (block_inside_limit < 1)
+ block_inside_limit = 1;
+
+ lfi->lfthr[lvl].lim = (uint8_t)block_inside_limit;
+ lfi->lfthr[lvl].mblim = (uint8_t)(2 * (lvl + 2) +
+ block_inside_limit);
+ }
+}
+
+/*instantiate this function once when decode is started*/
+void vp9_loop_filter_init(struct VP9Decoder_s *pbi)
+{
+ struct loop_filter_info_n *lfi = pbi->lfi;
+ struct loopfilter *lf = pbi->lf;
+ struct segmentation *seg_4lf = pbi->seg_4lf;
+ int i;
+ unsigned int data32;
+
+ memset(lfi, 0, sizeof(struct loop_filter_info_n));
+ memset(lf, 0, sizeof(struct loopfilter));
+ memset(seg_4lf, 0, sizeof(struct segmentation));
+ lf->sharpness_level = 0; /*init to 0 */
+ /*init limits for given sharpness*/
+ vp9_update_sharpness(lfi, lf->sharpness_level);
+ lf->last_sharpness_level = lf->sharpness_level;
+ /*init hev threshold const vectors (actually no use)
+ *for (i = 0; i <= MAX_LOOP_FILTER; i++)
+ * lfi->lfthr[i].hev_thr = (uint8_t)(i >> 4);
+ */
+
+ /*Write to register*/
+ for (i = 0; i < 32; i++) {
+ unsigned int thr;
+
+ thr = ((lfi->lfthr[i * 2 + 1].lim & 0x3f)<<8) |
+ (lfi->lfthr[i * 2 + 1].mblim & 0xff);
+ thr = (thr<<16) | ((lfi->lfthr[i*2].lim & 0x3f)<<8) |
+ (lfi->lfthr[i * 2].mblim & 0xff);
+ WRITE_VREG(HEVC_DBLK_CFG9, thr);
+ }
+
+ /*video format is VP9*/
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) {
+ data32 = (0x3 << 14) | // (dw fifo thres r and b)
+ (0x3 << 12) | // (dw fifo thres r or b)
+ (0x3 << 10) | // (dw fifo thres not r/b)
+ (0x3 << 8) | // 1st/2nd write both enable
+ (0x1 << 0); // vp9 video format
+ if (get_double_write_mode(pbi) == 0x10)
+ data32 &= (~0x100);
+ } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) {
+ data32 = (0x57 << 8) | /*1st/2nd write both enable*/
+ (0x1 << 0); /*vp9 video format*/
+ if (get_double_write_mode(pbi) == 0x10)
+ data32 &= (~0x100);
+ } else
+ data32 = 0x40400001;
+
+ WRITE_VREG(HEVC_DBLK_CFGB, data32);
+ if (debug & VP9_DEBUG_BUFMGR_MORE)
+ pr_info("[DBLK DEBUG] CFGB : 0x%x\n", data32);
+}
+ /* perform this function per frame*/
+void vp9_loop_filter_frame_init(struct segmentation *seg,
+ struct loop_filter_info_n *lfi, struct loopfilter *lf,
+ int default_filt_lvl) {
+ int i;
+ int seg_id;
+ /*n_shift is the multiplier for lf_deltas
+ *the multiplier is 1 for when filter_lvl is between 0 and 31;
+ *2 when filter_lvl is between 32 and 63
+ */
+ const int scale = 1 << (default_filt_lvl >> 5);
+
+ /*update limits if sharpness has changed*/
+ if (lf->last_sharpness_level != lf->sharpness_level) {
+ vp9_update_sharpness(lfi, lf->sharpness_level);
+ lf->last_sharpness_level = lf->sharpness_level;
+
+ /*Write to register*/
+ for (i = 0; i < 32; i++) {
+ unsigned int thr;
+
+ thr = ((lfi->lfthr[i * 2 + 1].lim & 0x3f) << 8)
+ | (lfi->lfthr[i * 2 + 1].mblim & 0xff);
+ thr = (thr << 16) | ((lfi->lfthr[i * 2].lim & 0x3f) << 8)
+ | (lfi->lfthr[i * 2].mblim & 0xff);
+ WRITE_VREG(HEVC_DBLK_CFG9, thr);
+ }
+ }
+
+ for (seg_id = 0; seg_id < MAX_SEGMENTS; seg_id++) {/*MAX_SEGMENTS = 8*/
+ int lvl_seg = default_filt_lvl;
+
+ if (segfeature_active(seg, seg_id, SEG_LVL_ALT_LF)) {
+ const int data = get_segdata(seg, seg_id,
+ SEG_LVL_ALT_LF);
+ lvl_seg = vp9_clamp(seg->abs_delta == SEGMENT_ABSDATA ?
+ data : default_filt_lvl + data,
+ 0, MAX_LOOP_FILTER);
+#ifdef DBG_LF_PRINT
+ pr_info("segfeature_active!!!seg_id=%d,lvl_seg=%d\n", seg_id, lvl_seg);
+#endif
+ }
+
+ if (!lf->mode_ref_delta_enabled) {
+ /*we could get rid of this if we assume that deltas are set to
+ *zero when not in use; encoder always uses deltas
+ */
+ memset(lfi->lvl[seg_id], lvl_seg, sizeof(lfi->lvl[seg_id]));
+ } else {
+ int ref, mode;
+ const int intra_lvl = lvl_seg + lf->ref_deltas[INTRA_FRAME]
+ * scale;
+#ifdef DBG_LF_PRINT
+ pr_info("LF_PRINT:vp9_loop_filter_frame_init,seg_id=%d\n", seg_id);
+ pr_info("ref_deltas[INTRA_FRAME]=%d\n", lf->ref_deltas[INTRA_FRAME]);
+#endif
+ lfi->lvl[seg_id][INTRA_FRAME][0] =
+ vp9_clamp(intra_lvl, 0, MAX_LOOP_FILTER);
+
+ for (ref = LAST_FRAME; ref < MAX_REF_FRAMES; ++ref) {
+ /* LAST_FRAME = 1, MAX_REF_FRAMES = 4*/
+ for (mode = 0; mode < MAX_MODE_LF_DELTAS; ++mode) {
+ /*MAX_MODE_LF_DELTAS = 2*/
+ const int inter_lvl =
+ lvl_seg + lf->ref_deltas[ref] * scale
+ + lf->mode_deltas[mode] * scale;
+#ifdef DBG_LF_PRINT
+#endif
+ lfi->lvl[seg_id][ref][mode] =
+ vp9_clamp(inter_lvl, 0,
+ MAX_LOOP_FILTER);
+ }
+ }
+ }
+ }
+
+#ifdef DBG_LF_PRINT
+ /*print out thr/lvl table per frame*/
+ for (i = 0; i <= MAX_LOOP_FILTER; i++) {
+ pr_info("LF_PRINT:(%d)thr=%d,blim=%d,lim=%d\n",
+ i, lfi->lfthr[i].hev_thr, lfi->lfthr[i].mblim,
+ lfi->lfthr[i].lim);
+ }
+ for (seg_id = 0; seg_id < MAX_SEGMENTS; seg_id++) {
+ pr_info("LF_PRINT:lvl(seg_id=%d)(mode=0,%d,%d,%d,%d)\n",
+ seg_id, lfi->lvl[seg_id][0][0],
+ lfi->lvl[seg_id][1][0], lfi->lvl[seg_id][2][0],
+ lfi->lvl[seg_id][3][0]);
+ pr_info("i(mode=1,%d,%d,%d,%d)\n", lfi->lvl[seg_id][0][1],
+ lfi->lvl[seg_id][1][1], lfi->lvl[seg_id][2][1],
+ lfi->lvl[seg_id][3][1]);
+ }
+#endif
+
+ /*Write to register */
+ for (i = 0; i < 16; i++) {
+ unsigned int level;
+
+ level = ((lfi->lvl[i >> 1][3][i & 1] & 0x3f) << 24) |
+ ((lfi->lvl[i >> 1][2][i & 1] & 0x3f) << 16) |
+ ((lfi->lvl[i >> 1][1][i & 1] & 0x3f) << 8) |
+ (lfi->lvl[i >> 1][0][i & 1] & 0x3f);
+ if (!default_filt_lvl)
+ level = 0;
+ WRITE_VREG(HEVC_DBLK_CFGA, level);
+ }
+}
+/* VP9_LPF_LVL_UPDATE */
+#endif
+
+static void vp9_init_decoder_hw(struct VP9Decoder_s *pbi, u32 mask)
+{
+ unsigned int data32;
+ int i;
+ const 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
+ };
+#if 0
+ if (get_cpu_major_id() >= MESON_CPU_MAJOR_ID_G12A) {
+ /* Set MCR fetch priorities*/
+ data32 = 0x1 | (0x1 << 2) | (0x1 <<3) |
+ (24 << 4) | (32 << 11) | (24 << 18) | (32 << 25);
+ WRITE_VREG(HEVCD_MPP_DECOMP_AXIURG_CTL, data32);
+ }
+#endif
+ /*if (debug & VP9_DEBUG_BUFMGR_MORE)
+ pr_info("%s\n", __func__);*/
+ if (mask & HW_MASK_FRONT) {
+ 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*/
+ ;
+#ifdef SUPPORT_FB_DECODING
+#ifndef FB_DECODING_TEST_SCHEDULE
+ /*fed_fb_slice_done_int_cpu_enable*/
+ if (pbi->used_stage_buf_num > 0)
+ data32 |= (1 << 10);
+#endif
+#endif
+ 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,
+ (0 << 14) | /*disable_start_code_protect*/
+ (1 << 10) | /*length_zero_startcode_en for VP9*/
+ (1 << 9) | /*length_valid_startcode_en for VP9*/
+ (3 << 6) | /*sft_valid_wr_position*/
+ (2 << 4) | /*emulate_code_length_sub_1*/
+ (3 << 1) | /*start_code_length_sub_1
+ VP9 use 0x00000001 as startcode (4 Bytes)*/
+ (1 << 0) /*stream_shift_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);
+
+ }
+
+ if (mask & HW_MASK_BACK) {
+ /*Initial IQIT_SCALELUT memory
+ -- just to avoid X in simulation*/
+
+ WRITE_VREG(HEVC_IQIT_SCALELUT_WR_ADDR, 0);/*cfg_p_addr*/
+ for (i = 0; i < 1024; i++)
+ WRITE_VREG(HEVC_IQIT_SCALELUT_DATA, 0);
+ }
+
+ if (mask & HW_MASK_FRONT) {
+ u32 decode_mode;
+#ifdef ENABLE_SWAP_TEST
+ WRITE_VREG(HEVC_STREAM_SWAP_TEST, 100);
+#else
+ WRITE_VREG(HEVC_STREAM_SWAP_TEST, 0);
+#endif
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (!pbi->m_ins_flag) {
+ if (pbi->low_latency_flag)
+ decode_mode = DECODE_MODE_SINGLE_LOW_LATENCY;
+ else
+ decode_mode = DECODE_MODE_SINGLE;
+ } else if (vdec_frame_based(hw_to_vdec(pbi)))
+ decode_mode = pbi->no_head ?
+ DECODE_MODE_MULTI_FRAMEBASE_NOHEAD :
+ DECODE_MODE_MULTI_FRAMEBASE;
+ else
+ decode_mode = DECODE_MODE_MULTI_STREAMBASE;
+#ifdef SUPPORT_FB_DECODING
+#ifndef FB_DECODING_TEST_SCHEDULE
+ if (pbi->used_stage_buf_num > 0)
+ decode_mode |= (0x01 << 24);
+#endif
+#endif
+ WRITE_VREG(DECODE_MODE, decode_mode);
+ WRITE_VREG(HEVC_DECODE_SIZE, 0);
+ WRITE_VREG(HEVC_DECODE_COUNT, 0);
+#else
+ WRITE_VREG(DECODE_MODE, DECODE_MODE_SINGLE);
+ WRITE_VREG(HEVC_DECODE_PIC_BEGIN_REG, 0);
+ WRITE_VREG(HEVC_DECODE_PIC_NUM_REG, 0x7fffffff); /*to remove*/
+#endif
+ /*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 << 8) |*/ /*sao_sw_pred_enable*/
+ (1 << 5) | /*parser_sao_if_en*/
+ (1 << 2) | /*parser_mpred_if_en*/
+ (1 << 0) /*parser_scaler_if_en*/
+ );
+ }
+
+ if (mask & HW_MASK_BACK) {
+ /*Changed to Start MPRED in microcode*/
+ /*
+ pr_info("[test.c] Start MPRED\n");
+ WRITE_VREG(HEVC_MPRED_INT_STATUS,
+ (1<<31)
+ );
+ */
+ 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 (get_double_write_mode(pbi) & 0x10) {
+ /*Enable NV21 reference read mode for MC*/
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31);
+ }
+
+ /*Initialize mcrcc and decomp perf counters*/
+ if (mcrcc_cache_alg_flag &&
+ pbi->init_flag == 0) {
+ mcrcc_perfcount_reset();
+ decomp_perfcount_reset();
+ }
+ }
+ return;
+}
+
+
+#ifdef CONFIG_HEVC_CLK_FORCED_ON
+static void config_vp9_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
+
+
+#ifdef MCRCC_ENABLE
+static void dump_hit_rate(struct VP9Decoder_s *pbi)
+{
+ if (debug & VP9_DEBUG_CACHE_HIT_RATE) {
+ mcrcc_get_hitrate(pbi->m_ins_flag);
+ decomp_get_hitrate();
+ decomp_get_comprate();
+ }
+}
+
+static void config_mcrcc_axi_hw(struct VP9Decoder_s *pbi)
+{
+ unsigned int rdata32;
+ unsigned short is_inter;
+ /*pr_info("Entered config_mcrcc_axi_hw...\n");*/
+ WRITE_VREG(HEVCD_MCRCC_CTL1, 0x2);/* reset mcrcc*/
+ is_inter = ((pbi->common.frame_type != KEY_FRAME) &&
+ (!pbi->common.intra_only)) ? 1 : 0;
+ if (!is_inter) { /* 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(pbi->m_ins_flag);
+ decomp_get_hitrate();
+ decomp_get_comprate();
+ }
+
+ 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);
+}
+
+static void config_mcrcc_axi_hw_new(struct VP9Decoder_s *pbi)
+{
+ u32 curr_picnum = -1;
+ u32 lastref_picnum = -1;
+ u32 goldenref_picnum = -1;
+ u32 altref_picnum = -1;
+
+ u32 lastref_delta_picnum;
+ u32 goldenref_delta_picnum;
+ u32 altref_delta_picnum;
+
+ u32 rdata32;
+
+ u32 lastcanvas;
+ u32 goldencanvas;
+ u32 altrefcanvas;
+
+ u16 is_inter;
+ u16 lastref_inref;
+ u16 goldenref_inref;
+ u16 altref_inref;
+
+ u32 refcanvas_array[3], utmp;
+ int deltapicnum_array[3], tmp;
+
+ struct VP9_Common_s *cm = &pbi->common;
+ struct PIC_BUFFER_CONFIG_s *cur_pic_config
+ = &cm->cur_frame->buf;
+ curr_picnum = cur_pic_config->decode_idx;
+ if (cm->frame_refs[0].buf)
+ lastref_picnum = cm->frame_refs[0].buf->decode_idx;
+ if (cm->frame_refs[1].buf)
+ goldenref_picnum = cm->frame_refs[1].buf->decode_idx;
+ if (cm->frame_refs[2].buf)
+ altref_picnum = cm->frame_refs[2].buf->decode_idx;
+
+ lastref_delta_picnum = (lastref_picnum >= curr_picnum) ?
+ (lastref_picnum - curr_picnum) : (curr_picnum - lastref_picnum);
+ goldenref_delta_picnum = (goldenref_picnum >= curr_picnum) ?
+ (goldenref_picnum - curr_picnum) :
+ (curr_picnum - goldenref_picnum);
+ altref_delta_picnum =
+ (altref_picnum >= curr_picnum) ?
+ (altref_picnum - curr_picnum) : (curr_picnum - altref_picnum);
+
+ lastref_inref = (cm->frame_refs[0].idx != INVALID_IDX) ? 1 : 0;
+ goldenref_inref = (cm->frame_refs[1].idx != INVALID_IDX) ? 1 : 0;
+ altref_inref = (cm->frame_refs[2].idx != INVALID_IDX) ? 1 : 0;
+
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("%s--0--lastref_inref:%d goldenref_inref:%d altref_inref:%d\n",
+ __func__, lastref_inref, goldenref_inref, altref_inref);
+
+ WRITE_VREG(HEVCD_MCRCC_CTL1, 0x2); /* reset mcrcc */
+
+ is_inter = ((pbi->common.frame_type != KEY_FRAME)
+ && (!pbi->common.intra_only)) ? 1 : 0;
+
+ if (!is_inter) { /* I-PIC */
+ /* remove reset -- disables clock */
+ WRITE_VREG(HEVCD_MCRCC_CTL1, 0x0);
+ return;
+ }
+
+ if (!pbi->m_ins_flag)
+ dump_hit_rate(pbi);
+
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, (0 << 8) | (1<<1) | 0);
+ lastcanvas = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
+ goldencanvas = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
+ altrefcanvas = READ_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
+
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("[test.c] lastref_canv:%x goldenref_canv:%x altref_canv:%x\n",
+ lastcanvas, goldencanvas, altrefcanvas);
+
+ altref_inref = ((altref_inref == 1) &&
+ (altrefcanvas != (goldenref_inref
+ ? goldencanvas : 0xffffffff)) &&
+ (altrefcanvas != (lastref_inref ?
+ lastcanvas : 0xffffffff))) ? 1 : 0;
+ goldenref_inref = ((goldenref_inref == 1) &&
+ (goldencanvas != (lastref_inref ?
+ lastcanvas : 0xffffffff))) ? 1 : 0;
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("[test.c]--1--lastref_inref:%d goldenref_inref:%d altref_inref:%d\n",
+ lastref_inref, goldenref_inref, altref_inref);
+
+ altref_delta_picnum = altref_inref ? altref_delta_picnum : 0x7fffffff;
+ goldenref_delta_picnum = goldenref_inref ?
+ goldenref_delta_picnum : 0x7fffffff;
+ lastref_delta_picnum = lastref_inref ?
+ lastref_delta_picnum : 0x7fffffff;
+ if (debug & VP9_DEBUG_CACHE)
+ pr_info("[test.c]--1--lastref_delta_picnum:%d goldenref_delta_picnum:%d altref_delta_picnum:%d\n",
+ lastref_delta_picnum, goldenref_delta_picnum,
+ altref_delta_picnum);
+ /*ARRAY SORT HERE DELTA/CANVAS ARRAY SORT -- use DELTA*/
+
+ refcanvas_array[0] = lastcanvas;
+ refcanvas_array[1] = goldencanvas;
+ refcanvas_array[2] = altrefcanvas;
+
+ deltapicnum_array[0] = lastref_delta_picnum;
+ deltapicnum_array[1] = goldenref_delta_picnum;
+ deltapicnum_array[2] = altref_delta_picnum;
+
+ /* sort0 : 2-to-1 */
+ if (deltapicnum_array[2] < deltapicnum_array[1]) {
+ utmp = refcanvas_array[2];
+ refcanvas_array[2] = refcanvas_array[1];
+ refcanvas_array[1] = utmp;
+ tmp = deltapicnum_array[2];
+ deltapicnum_array[2] = deltapicnum_array[1];
+ deltapicnum_array[1] = tmp;
+ }
+ /* sort1 : 1-to-0 */
+ if (deltapicnum_array[1] < deltapicnum_array[0]) {
+ utmp = refcanvas_array[1];
+ refcanvas_array[1] = refcanvas_array[0];
+ refcanvas_array[0] = utmp;
+ tmp = deltapicnum_array[1];
+ deltapicnum_array[1] = deltapicnum_array[0];
+ deltapicnum_array[0] = tmp;
+ }
+ /* sort2 : 2-to-1 */
+ if (deltapicnum_array[2] < deltapicnum_array[1]) {
+ utmp = refcanvas_array[2]; refcanvas_array[2] =
+ refcanvas_array[1]; refcanvas_array[1] = utmp;
+ tmp = deltapicnum_array[2]; deltapicnum_array[2] =
+ deltapicnum_array[1]; deltapicnum_array[1] = tmp;
+ }
+ if (mcrcc_cache_alg_flag ==
+ THODIYIL_MCRCC_CANVAS_ALGX) { /*09/15/2017*/
+ /* lowest delta_picnum */
+ rdata32 = refcanvas_array[0];
+ rdata32 = rdata32 & 0xffff;
+ rdata32 = rdata32 | (rdata32 << 16);
+ WRITE_VREG(HEVCD_MCRCC_CTL2, rdata32);
+
+ /* 2nd-lowest delta_picnum */
+ rdata32 = refcanvas_array[1];
+ rdata32 = rdata32 & 0xffff;
+ rdata32 = rdata32 | (rdata32 << 16);
+ WRITE_VREG(HEVCD_MCRCC_CTL3, rdata32);
+ } else {
+ /* previous version -- LAST/GOLDEN ALWAYS -- before 09/13/2017*/
+ 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);
+ }
+
+ WRITE_VREG(HEVCD_MCRCC_CTL1, 0xff0); /* enable mcrcc progressive-mode */
+ return;
+}
+
+#endif
+
+
+static void free_lf_buf(struct VP9Decoder_s *pbi)
+{
+ if (pbi->lfi)
+ vfree(pbi->lfi);
+ if (pbi->lf)
+ vfree(pbi->lf);
+ if (pbi->seg_4lf)
+ vfree(pbi->seg_4lf);
+ pbi->lfi = NULL;
+ pbi->lf = NULL;
+ pbi->seg_4lf = NULL;
+}
+
+static int alloc_lf_buf(struct VP9Decoder_s *pbi)
+{
+ pbi->lfi = vmalloc(sizeof(struct loop_filter_info_n));
+ pbi->lf = vmalloc(sizeof(struct loopfilter));
+ pbi->seg_4lf = vmalloc(sizeof(struct segmentation));
+ if (pbi->lfi == NULL || pbi->lf == NULL || pbi->seg_4lf == NULL) {
+ free_lf_buf(pbi);
+ pr_err("[test.c] vp9_loop_filter init malloc error!!!\n");
+ return -1;
+ }
+ return 0;
+}
+
+static void vp9_local_uninit(struct VP9Decoder_s *pbi)
+{
+ pbi->rpm_ptr = NULL;
+ pbi->lmem_ptr = NULL;
+ if (pbi->rpm_addr) {
+ dma_free_coherent(amports_get_dma_device(),
+ RPM_BUF_SIZE,
+ pbi->rpm_addr,
+ pbi->rpm_phy_addr);
+ pbi->rpm_addr = NULL;
+ }
+ if (pbi->lmem_addr) {
+ if (pbi->lmem_phy_addr)
+ dma_free_coherent(amports_get_dma_device(),
+ LMEM_BUF_SIZE, pbi->lmem_addr,
+ pbi->lmem_phy_addr);
+ pbi->lmem_addr = NULL;
+ }
+ if (pbi->prob_buffer_addr) {
+ if (pbi->prob_buffer_phy_addr)
+ dma_free_coherent(amports_get_dma_device(),
+ PROB_BUF_SIZE, pbi->prob_buffer_addr,
+ pbi->prob_buffer_phy_addr);
+
+ pbi->prob_buffer_addr = NULL;
+ }
+ if (pbi->count_buffer_addr) {
+ if (pbi->count_buffer_phy_addr)
+ dma_free_coherent(amports_get_dma_device(),
+ COUNT_BUF_SIZE, pbi->count_buffer_addr,
+ pbi->count_buffer_phy_addr);
+
+ pbi->count_buffer_addr = NULL;
+ }
+ if (pbi->mmu_enable) {
+ u32 mmu_map_size = vvp9_frame_mmu_map_size(pbi);
+ if (pbi->frame_mmu_map_addr) {
+ if (pbi->frame_mmu_map_phy_addr)
+ dma_free_coherent(amports_get_dma_device(),
+ mmu_map_size,
+ pbi->frame_mmu_map_addr,
+ pbi->frame_mmu_map_phy_addr);
+ pbi->frame_mmu_map_addr = NULL;
+ }
+ }
+#ifdef SUPPORT_FB_DECODING
+ if (pbi->stage_mmu_map_addr) {
+ if (pbi->stage_mmu_map_phy_addr)
+ dma_free_coherent(amports_get_dma_device(),
+ STAGE_MMU_MAP_SIZE * STAGE_MAX_BUFFERS,
+ pbi->stage_mmu_map_addr,
+ pbi->stage_mmu_map_phy_addr);
+ pbi->stage_mmu_map_addr = NULL;
+ }
+
+ uninit_stage_buf(pbi);
+#endif
+
+#ifdef VP9_LPF_LVL_UPDATE
+ free_lf_buf(pbi);
+#endif
+ if (pbi->gvs)
+ vfree(pbi->gvs);
+ pbi->gvs = NULL;
+}
+
+static int vp9_local_init(struct VP9Decoder_s *pbi)
+{
+ int ret = -1;
+ /*int losless_comp_header_size, losless_comp_body_size;*/
+
+ struct BuffInfo_s *cur_buf_info = NULL;
+
+ memset(&pbi->param, 0, sizeof(union param_u));
+ memset(&pbi->common, 0, sizeof(struct VP9_Common_s));
+#ifdef MULTI_INSTANCE_SUPPORT
+ cur_buf_info = &pbi->work_space_buf_store;
+ if (force_bufspec) {
+ memcpy(cur_buf_info, &amvvp9_workbuff_spec[force_bufspec & 0xf],
+ sizeof(struct BuffInfo_s));
+ pr_info("force buffer spec %d\n", force_bufspec & 0xf);
+ } else if (vdec_is_support_4k()) {
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) {
+ memcpy(cur_buf_info, &amvvp9_workbuff_spec[2], /* 8k */
+ sizeof(struct BuffInfo_s));
+ } else
+ memcpy(cur_buf_info, &amvvp9_workbuff_spec[1], /* 4k */
+ sizeof(struct BuffInfo_s));
+ } else
+ memcpy(cur_buf_info, &amvvp9_workbuff_spec[0],/* 1080p */
+ sizeof(struct BuffInfo_s));
+
+ cur_buf_info->start_adr = pbi->buf_start;
+ if (!pbi->mmu_enable)
+ pbi->mc_buf_spec.buf_end = pbi->buf_start + pbi->buf_size;
+
+#else
+/*! MULTI_INSTANCE_SUPPORT*/
+ if (vdec_is_support_4k()) {
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1)
+ cur_buf_info = &amvvp9_workbuff_spec[2];/* 8k work space */
+ else
+ cur_buf_info = &amvvp9_workbuff_spec[1];/* 4k2k work space */
+ } else
+ cur_buf_info = &amvvp9_workbuff_spec[0];/* 1080p work space */
+
+#endif
+
+ init_buff_spec(pbi, cur_buf_info);
+ vp9_bufmgr_init(pbi, cur_buf_info, NULL);
+
+ if (!vdec_is_support_4k()
+ && (buf_alloc_width > 1920 && buf_alloc_height > 1088)) {
+ buf_alloc_width = 1920;
+ buf_alloc_height = 1088;
+ if (pbi->max_pic_w > 1920 && pbi->max_pic_h > 1088) {
+ pbi->max_pic_w = 1920;
+ pbi->max_pic_h = 1088;
+ }
+ } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) {
+ buf_alloc_width = 8192;
+ buf_alloc_height = 4608;
+ }
+ pbi->init_pic_w = pbi->max_pic_w ? pbi->max_pic_w :
+ (buf_alloc_width ? buf_alloc_width :
+ (pbi->vvp9_amstream_dec_info.width ?
+ pbi->vvp9_amstream_dec_info.width :
+ pbi->work_space_buf->max_width));
+ pbi->init_pic_h = pbi->max_pic_h ? pbi->max_pic_h :
+ (buf_alloc_height ? buf_alloc_height :
+ (pbi->vvp9_amstream_dec_info.height ?
+ pbi->vvp9_amstream_dec_info.height :
+ pbi->work_space_buf->max_height));
+
+ /* video is not support unaligned with 64 in tl1
+ ** vdec canvas mode will be linear when dump yuv is set
+ */
+ if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) &&
+ (pbi->double_write_mode != 0) &&
+ (((pbi->max_pic_w % 64) != 0) ||
+ (pbi->vvp9_amstream_dec_info.width % 64) != 0)) {
+ if (hw_to_vdec(pbi)->canvas_mode !=
+ CANVAS_BLKMODE_LINEAR)
+ pbi->mem_map_mode = 2;
+ else {
+ pbi->mem_map_mode = 0;
+ pr_info("vdec blkmod linear, force mem_map_mode 0\n");
+ }
+ }
+
+#ifndef MV_USE_FIXED_BUF
+ if (init_mv_buf_list(pbi) < 0) {
+ pr_err("%s: init_mv_buf_list fail\n", __func__);
+ return -1;
+ }
+#endif
+ if (pbi->save_buffer_mode)
+ pbi->used_buf_num = MAX_BUF_NUM_SAVE_BUF;
+ else {
+ if (pbi->is_used_v4l)
+ pbi->used_buf_num = 5 + pbi->dynamic_buf_num_margin;
+ else
+ pbi->used_buf_num = max_buf_num;
+ }
+
+ if (pbi->used_buf_num > MAX_BUF_NUM)
+ pbi->used_buf_num = MAX_BUF_NUM;
+ if (pbi->used_buf_num > FRAME_BUFFERS)
+ pbi->used_buf_num = FRAME_BUFFERS;
+
+ pbi->pts_unstable = ((unsigned long)(pbi->vvp9_amstream_dec_info.param)
+ & 0x40) >> 6;
+
+ if ((debug & VP9_DEBUG_SEND_PARAM_WITH_REG) == 0) {
+ pbi->rpm_addr = dma_alloc_coherent(amports_get_dma_device(),
+ RPM_BUF_SIZE,
+ &pbi->rpm_phy_addr, GFP_KERNEL);
+ if (pbi->rpm_addr == NULL) {
+ pr_err("%s: failed to alloc rpm buffer\n", __func__);
+ return -1;
+ }
+
+ pbi->rpm_ptr = pbi->rpm_addr;
+ }
+
+ pbi->lmem_addr = dma_alloc_coherent(amports_get_dma_device(),
+ LMEM_BUF_SIZE,
+ &pbi->lmem_phy_addr, GFP_KERNEL);
+ if (pbi->lmem_addr == NULL) {
+ pr_err("%s: failed to alloc lmem buffer\n", __func__);
+ return -1;
+ }
+ pbi->lmem_ptr = pbi->lmem_addr;
+
+ pbi->prob_buffer_addr = dma_alloc_coherent(amports_get_dma_device(),
+ PROB_BUF_SIZE,
+ &pbi->prob_buffer_phy_addr, GFP_KERNEL);
+ if (pbi->prob_buffer_addr == NULL) {
+ pr_err("%s: failed to alloc prob_buffer\n", __func__);
+ return -1;
+ }
+ memset(pbi->prob_buffer_addr, 0, PROB_BUF_SIZE);
+ pbi->count_buffer_addr = dma_alloc_coherent(amports_get_dma_device(),
+ COUNT_BUF_SIZE,
+ &pbi->count_buffer_phy_addr, GFP_KERNEL);
+ if (pbi->count_buffer_addr == NULL) {
+ pr_err("%s: failed to alloc count_buffer\n", __func__);
+ return -1;
+ }
+ memset(pbi->count_buffer_addr, 0, COUNT_BUF_SIZE);
+
+ if (pbi->mmu_enable) {
+ u32 mmu_map_size = vvp9_frame_mmu_map_size(pbi);
+ pbi->frame_mmu_map_addr =
+ dma_alloc_coherent(amports_get_dma_device(),
+ mmu_map_size,
+ &pbi->frame_mmu_map_phy_addr, GFP_KERNEL);
+ if (pbi->frame_mmu_map_addr == NULL) {
+ pr_err("%s: failed to alloc count_buffer\n", __func__);
+ return -1;
+ }
+ memset(pbi->frame_mmu_map_addr, 0, COUNT_BUF_SIZE);
+ }
+#ifdef SUPPORT_FB_DECODING
+ if (pbi->m_ins_flag && stage_buf_num > 0) {
+ pbi->stage_mmu_map_addr =
+ dma_alloc_coherent(amports_get_dma_device(),
+ STAGE_MMU_MAP_SIZE * STAGE_MAX_BUFFERS,
+ &pbi->stage_mmu_map_phy_addr, GFP_KERNEL);
+ if (pbi->stage_mmu_map_addr == NULL) {
+ pr_err("%s: failed to alloc count_buffer\n", __func__);
+ return -1;
+ }
+ memset(pbi->stage_mmu_map_addr,
+ 0, STAGE_MMU_MAP_SIZE * STAGE_MAX_BUFFERS);
+
+ init_stage_buf(pbi);
+ }
+#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 VP9Decoder_s *pbi,
+ struct PIC_BUFFER_CONFIG_s *pic_config)
+{
+ struct vdec_s *vdec = hw_to_vdec(pbi);
+ int canvas_w = ALIGN(pic_config->y_crop_width, 64)/4;
+ int canvas_h = ALIGN(pic_config->y_crop_height, 32)/4;
+ int blkmode = pbi->mem_map_mode;
+ /*CANVAS_BLKMODE_64X32*/
+ if (pic_config->double_write_mode) {
+ canvas_w = pic_config->y_crop_width /
+ get_double_write_ratio(pbi,
+ pic_config->double_write_mode);
+ canvas_h = pic_config->y_crop_height /
+ get_double_write_ratio(pbi,
+ pic_config->double_write_mode);
+
+ if (pbi->mem_map_mode == 0)
+ canvas_w = ALIGN(canvas_w, 32);
+ else
+ canvas_w = ALIGN(canvas_w, 64);
+ canvas_h = ALIGN(canvas_h, 32);
+
+ if (vdec->parallel_dec == 1) {
+ if (pic_config->y_canvas_index == -1)
+ pic_config->y_canvas_index =
+ vdec->get_canvas_ex(CORE_MASK_HEVC, vdec->id);
+ if (pic_config->uv_canvas_index == -1)
+ pic_config->uv_canvas_index =
+ vdec->get_canvas_ex(CORE_MASK_HEVC, vdec->id);
+ } else {
+ pic_config->y_canvas_index = 128 + pic_config->index * 2;
+ pic_config->uv_canvas_index = 128 + pic_config->index * 2 + 1;
+ }
+
+ canvas_config_ex(pic_config->y_canvas_index,
+ pic_config->dw_y_adr, canvas_w, canvas_h,
+ CANVAS_ADDR_NOWRAP, blkmode, pbi->is_used_v4l ? 0 : 7);
+ canvas_config_ex(pic_config->uv_canvas_index,
+ pic_config->dw_u_v_adr, canvas_w, canvas_h,
+ CANVAS_ADDR_NOWRAP, blkmode, pbi->is_used_v4l ? 0 : 7);
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ pic_config->canvas_config[0].phy_addr =
+ pic_config->dw_y_adr;
+ pic_config->canvas_config[0].width =
+ canvas_w;
+ pic_config->canvas_config[0].height =
+ canvas_h;
+ pic_config->canvas_config[0].block_mode =
+ blkmode;
+ pic_config->canvas_config[0].endian = pbi->is_used_v4l ? 0 : 7;
+
+ pic_config->canvas_config[1].phy_addr =
+ pic_config->dw_u_v_adr;
+ pic_config->canvas_config[1].width =
+ canvas_w;
+ pic_config->canvas_config[1].height =
+ canvas_h;
+ pic_config->canvas_config[1].block_mode =
+ blkmode;
+ pic_config->canvas_config[1].endian = pbi->is_used_v4l ? 0 : 7;
+#endif
+ }
+}
+
+
+static void set_frame_info(struct VP9Decoder_s *pbi, struct vframe_s *vf)
+{
+ unsigned int ar = DISP_RATIO_ASPECT_RATIO_MAX;
+ vf->duration = pbi->frame_dur;
+ vf->duration_pulldown = 0;
+ vf->flag = 0;
+ vf->prop.master_display_colour = pbi->vf_dp;
+ vf->signal_type = pbi->video_signal_type;
+ if (vf->compWidth && vf->compHeight)
+ pbi->frame_ar = vf->compHeight * 0x100 / vf->compWidth;
+ ar = min_t(u32, ar, DISP_RATIO_ASPECT_RATIO_MAX);
+ vf->ratio_control = (ar << DISP_RATIO_ASPECT_RATIO_BIT);
+ vf->sar_width = 1;
+ vf->sar_height = 1;
+
+ if (pbi->is_used_v4l && pbi->vf_dp.present_flag) {
+ struct aml_vdec_hdr_infos hdr;
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(pbi->v4l2_ctx);
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.signal_type = vf->signal_type;
+ hdr.color_parms = pbi->vf_dp;
+ vdec_v4l_set_hdr_infos(ctx, &hdr);
+ }
+
+ if ((pbi->chunk != NULL) && (pbi->chunk->hdr10p_data_buf != NULL)
+ && (pbi->chunk->hdr10p_data_size != 0)) {
+ char *new_buf;
+ int i = 0;
+ new_buf = vzalloc(pbi->chunk->hdr10p_data_size);
+
+ if (new_buf) {
+ memcpy(new_buf, pbi->chunk->hdr10p_data_buf, pbi->chunk->hdr10p_data_size);
+ if (debug & VP9_DEBUG_BUFMGR_MORE) {
+ vp9_print(pbi, VP9_DEBUG_BUFMGR_MORE,
+ "hdr10p data: (size %d)\n",
+ pbi->chunk->hdr10p_data_size);
+ for (i = 0; i < pbi->chunk->hdr10p_data_size; i++) {
+ vp9_print(pbi, VP9_DEBUG_BUFMGR_MORE,
+ "%02x ", pbi->chunk->hdr10p_data_buf[i]);
+ if (((i + 1) & 0xf) == 0)
+ vp9_print(pbi, VP9_DEBUG_BUFMGR_MORE, "\n");
+ }
+ vp9_print(pbi, VP9_DEBUG_BUFMGR_MORE, "\n");
+ }
+
+ vf->hdr10p_data_size = pbi->chunk->hdr10p_data_size;
+ vf->hdr10p_data_buf = new_buf;
+ } else {
+ vp9_print(pbi, 0, "%s:hdr10p data vzalloc size(%d) fail\n",
+ __func__, pbi->chunk->hdr10p_data_size);
+ vf->hdr10p_data_size = pbi->chunk->hdr10p_data_size;
+ vf->hdr10p_data_buf = new_buf;
+ }
+
+ vfree(pbi->chunk->hdr10p_data_buf);
+ pbi->chunk->hdr10p_data_buf = NULL;
+ pbi->chunk->hdr10p_data_size = 0;
+ }
+
+ vf->sidebind_type = pbi->sidebind_type;
+ vf->sidebind_channel_id = pbi->sidebind_channel_id;
+}
+
+static int vvp9_vf_states(struct vframe_states *states, void *op_arg)
+{
+ struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)op_arg;
+
+ states->vf_pool_size = VF_POOL_SIZE;
+ states->buf_free_num = kfifo_len(&pbi->newframe_q);
+ states->buf_avail_num = kfifo_len(&pbi->display_q);
+
+ if (step == 2)
+ states->buf_avail_num = 0;
+ return 0;
+}
+
+static struct vframe_s *vvp9_vf_peek(void *op_arg)
+{
+ struct vframe_s *vf[2] = {0, 0};
+ struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)op_arg;
+
+ if (step == 2)
+ return NULL;
+
+ if (kfifo_out_peek(&pbi->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 *vvp9_vf_get(void *op_arg)
+{
+ struct vframe_s *vf;
+ struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)op_arg;
+
+ if (step == 2)
+ return NULL;
+ else if (step == 1)
+ step = 2;
+
+ if (kfifo_get(&pbi->display_q, &vf)) {
+ struct vframe_s *next_vf = NULL;
+ uint8_t index = vf->index & 0xff;
+ ATRACE_COUNTER(pbi->disp_q_name, kfifo_len(&pbi->display_q));
+ if (index < pbi->used_buf_num ||
+ (vf->type & VIDTYPE_V4L_EOS)) {
+ vf->index_disp = pbi->vf_get_count;
+ pbi->vf_get_count++;
+ if (debug & VP9_DEBUG_BUFMGR)
+ pr_info("%s type 0x%x w/h %d/%d, pts %d, %lld\n",
+ __func__, vf->type,
+ vf->width, vf->height,
+ vf->pts,
+ vf->pts_us64);
+
+ if (kfifo_peek(&pbi->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 void vvp9_vf_put(struct vframe_s *vf, void *op_arg)
+{
+ struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)op_arg;
+ uint8_t index;
+
+ if (vf == (&pbi->vframe_dummy))
+ return;
+
+ if (!vf)
+ return;
+
+ index = vf->index & 0xff;
+
+ if (pbi->enable_fence && vf->fence) {
+ vdec_fence_put(vf->fence);
+ vf->fence = NULL;
+ }
+
+ if (vf->hdr10p_data_buf) {
+ vfree(vf->hdr10p_data_buf);
+ vf->hdr10p_data_buf = NULL;
+ vf->hdr10p_data_size = 0;
+ }
+
+ kfifo_put(&pbi->newframe_q, (const struct vframe_s *)vf);
+ ATRACE_COUNTER(pbi->new_q_name, kfifo_len(&pbi->newframe_q));
+ pbi->vf_put_count++;
+ if (index < pbi->used_buf_num) {
+ struct VP9_Common_s *cm = &pbi->common;
+ struct BufferPool_s *pool = cm->buffer_pool;
+ unsigned long flags;
+
+ lock_buffer_pool(pool, flags);
+ if (pool->frame_bufs[index].buf.vf_ref > 0)
+ pool->frame_bufs[index].buf.vf_ref--;
+
+ if (pbi->is_used_v4l)
+ pool->frame_bufs[index].buf.vframe_bound = true;
+
+ if (pbi->wait_buf)
+ WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG,
+ 0x1);
+ pbi->last_put_idx = index;
+ pbi->new_frame_displayed++;
+ unlock_buffer_pool(pool, flags);
+#ifdef SUPPORT_FB_DECODING
+ if (pbi->used_stage_buf_num > 0 &&
+ pbi->back_not_run_ready)
+ trigger_schedule(pbi);
+#endif
+ }
+
+}
+
+static int vvp9_event_cb(int type, void *data, void *private_data)
+{
+ struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)private_data;
+
+ if (type & VFRAME_EVENT_RECEIVER_RESET) {
+#if 0
+ unsigned long flags;
+
+ amhevc_stop();
+#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vf_light_unreg_provider(&vvp9_vf_prov);
+#endif
+ spin_lock_irqsave(&pbi->lock, flags);
+ vvp9_local_init();
+ vvp9_prot_init();
+ spin_unlock_irqrestore(&pbi->lock, flags);
+#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vf_reg_provider(&vvp9_vf_prov);
+#endif
+ amhevc_start();
+#endif
+ } 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(hw_to_vdec(pbi));
+ else
+ req->req_result[0] = 0xffffffff;
+ }
+
+ return 0;
+}
+
+void inc_vf_ref(struct VP9Decoder_s *pbi, int index)
+{
+ struct VP9_Common_s *cm = &pbi->common;
+
+ cm->buffer_pool->frame_bufs[index].buf.vf_ref++;
+
+ if (debug & VP9_DEBUG_BUFMGR_MORE)
+ pr_info("%s index = %d new vf_ref = %d\r\n",
+ __func__, index,
+ cm->buffer_pool->frame_bufs[index].buf.vf_ref);
+}
+
+static int frame_duration_adapt(struct VP9Decoder_s *pbi, struct vframe_s *vf, u32 valid)
+{
+ u32 old_duration, pts_duration = 0;
+ u32 pts = vf->pts;
+
+ if (pbi->get_frame_dur == true)
+ return true;
+
+ pbi->frame_cnt_window++;
+ if (!(pbi->vp9_first_pts_ready == 1)) {
+ if (valid) {
+ pbi->pts1 = pts;
+ pbi->frame_cnt_window = 0;
+ pbi->duration_from_pts_done = 0;
+ pbi->vp9_first_pts_ready = 1;
+ } else {
+ return false;
+ }
+ } else {
+ if (pts < pbi->pts1) {
+ if (pbi->frame_cnt_window > FRAME_CNT_WINDOW_SIZE) {
+ pbi->pts1 = pts;
+ pbi->frame_cnt_window = 0;
+ }
+ }
+
+ if (valid && (pbi->frame_cnt_window > FRAME_CNT_WINDOW_SIZE) &&
+ (pts > pbi->pts1) && (pbi->duration_from_pts_done == 0)) {
+ old_duration = pbi->frame_dur;
+ pbi->pts2 = pts;
+ pts_duration = (((pbi->pts2 - pbi->pts1) * 16) /
+ (pbi->frame_cnt_window * 15));
+
+ if (close_to(pts_duration, old_duration, 2000)) {
+ pbi->frame_dur = pts_duration;
+ if ((debug & VP9_DEBUG_OUT_PTS) != 0)
+ pr_info("use calc duration %d\n", pts_duration);
+ }
+
+ if (pbi->duration_from_pts_done == 0) {
+ if (close_to(pts_duration, old_duration, RATE_CORRECTION_THRESHOLD)) {
+ pbi->duration_from_pts_done = 1;
+ } else {
+ if (!close_to(pts_duration,
+ old_duration, 1000) &&
+ !close_to(pts_duration,
+ pbi->frame_dur, 1000) &&
+ close_to(pts_duration,
+ pbi->last_duration, 200)) {
+ /* frame_dur must
+ * wrong,recover it.
+ */
+ pbi->frame_dur = pts_duration;
+ }
+ pbi->pts1 = pbi->pts2;
+ pbi->frame_cnt_window = 0;
+ pbi->duration_from_pts_done = 0;
+ }
+ }
+ pbi->last_duration = pts_duration;
+ }
+ }
+ return true;
+}
+
+static void update_vf_memhandle(struct VP9Decoder_s *pbi,
+ struct vframe_s *vf, struct PIC_BUFFER_CONFIG_s *pic)
+{
+ if (pic->index < 0) {
+ vf->mem_handle = NULL;
+ vf->mem_head_handle = NULL;
+ vf->mem_dw_handle = NULL;
+ } else if (vf->type & VIDTYPE_SCATTER) {
+ vf->mem_handle =
+ decoder_mmu_box_get_mem_handle(
+ pbi->mmu_box, pic->index);
+ vf->mem_head_handle =
+ decoder_bmmu_box_get_mem_handle(
+ pbi->bmmu_box,
+ HEADER_BUFFER_IDX(pic->BUF_index));
+ if (pbi->double_write_mode == 3)
+ vf->mem_dw_handle =
+ decoder_bmmu_box_get_mem_handle(
+ pbi->bmmu_box,
+ VF_BUFFER_IDX(pic->BUF_index));
+ else
+ vf->mem_dw_handle = NULL;
+ } else {
+ vf->mem_handle =
+ decoder_bmmu_box_get_mem_handle(
+ pbi->bmmu_box, VF_BUFFER_IDX(pic->BUF_index));
+ vf->mem_head_handle = NULL;
+ vf->mem_dw_handle = NULL;
+ /*vf->mem_head_handle =
+ *decoder_bmmu_box_get_mem_handle(
+ *hevc->bmmu_box, VF_BUFFER_IDX(BUF_index));
+ */
+ }
+}
+
+static inline void pbi_update_gvs(struct VP9Decoder_s *pbi)
+{
+ if (pbi->gvs->frame_height != frame_height) {
+ pbi->gvs->frame_width = frame_width;
+ pbi->gvs->frame_height = frame_height;
+ }
+ if (pbi->gvs->frame_dur != pbi->frame_dur) {
+ pbi->gvs->frame_dur = pbi->frame_dur;
+ if (pbi->frame_dur != 0)
+ pbi->gvs->frame_rate = ((96000 * 10 / pbi->frame_dur) % 10) < 5 ?
+ 96000 / pbi->frame_dur : (96000 / pbi->frame_dur +1);
+ else
+ pbi->gvs->frame_rate = -1;
+ }
+ pbi->gvs->status = pbi->stat | pbi->fatal_error;
+}
+
+static int prepare_display_buf(struct VP9Decoder_s *pbi,
+ struct PIC_BUFFER_CONFIG_s *pic_config)
+{
+ struct vframe_s *vf = NULL;
+ struct vdec_s *pvdec = hw_to_vdec(pbi);
+ int stream_offset = pic_config->stream_offset;
+ unsigned short slice_type = pic_config->slice_type;
+ struct aml_vcodec_ctx * v4l2_ctx = pbi->v4l2_ctx;
+ ulong nv_order = VIDTYPE_VIU_NV21;
+ u32 pts_valid = 0, pts_us64_valid = 0;
+ u32 pts_save;
+ u64 pts_us64_save;
+ u32 frame_size = 0;
+ int i = 0;
+
+
+ if (debug & VP9_DEBUG_BUFMGR)
+ pr_info("%s index = %d\r\n", __func__, pic_config->index);
+ if (kfifo_get(&pbi->newframe_q, &vf) == 0) {
+ pr_info("fatal error, no available buffer slot.");
+ return -1;
+ }
+ /* swap uv */
+ if (pbi->is_used_v4l) {
+ if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12) ||
+ (v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12M))
+ nv_order = VIDTYPE_VIU_NV12;
+ }
+
+ if (pic_config->double_write_mode)
+ set_canvas(pbi, pic_config);
+
+ display_frame_count[pbi->index]++;
+ if (vf) {
+ if (!force_pts_unstable) {
+ if ((pic_config->pts == 0) || (pic_config->pts <= pbi->last_pts)) {
+ for (i = (FRAME_BUFFERS - 1); i > 0; i--) {
+ if ((pbi->last_pts == pbi->frame_mode_pts_save[i]) ||
+ (pbi->last_pts_us64 == pbi->frame_mode_pts64_save[i])) {
+ pic_config->pts = pbi->frame_mode_pts_save[i - 1];
+ pic_config->pts64 = pbi->frame_mode_pts64_save[i - 1];
+ break;
+ }
+ }
+ if ((i == 0) || (pic_config->pts <= pbi->last_pts)) {
+ vp9_print(pbi, VP9_DEBUG_OUT_PTS,
+ "no found pts %d, set 0. %d, %d\n",
+ i, pic_config->pts, pbi->last_pts);
+ pic_config->pts = 0;
+ pic_config->pts64 = 0;
+ }
+ }
+ }
+
+ if (pbi->is_used_v4l) {
+ vf->v4l_mem_handle
+ = pbi->m_BUF[pic_config->BUF_index].v4l_ref_buf_addr;
+ if (pbi->mmu_enable) {
+ vf->mm_box.bmmu_box = pbi->bmmu_box;
+ vf->mm_box.bmmu_idx = HEADER_BUFFER_IDX(pic_config->BUF_index);
+ vf->mm_box.mmu_box = pbi->mmu_box;
+ vf->mm_box.mmu_idx = pic_config->index;
+ }
+ }
+
+ if (pbi->enable_fence) {
+ /* fill fence information. */
+ if (pbi->fence_usage == FENCE_USE_FOR_DRIVER)
+ vf->fence = pic_config->fence;
+ }
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (vdec_frame_based(pvdec)) {
+ vf->pts = pic_config->pts;
+ vf->pts_us64 = pic_config->pts64;
+ vf->timestamp = pic_config->timestamp;
+ if (vf->pts != 0 || vf->pts_us64 != 0) {
+ pts_valid = 1;
+ pts_us64_valid = 1;
+ } else {
+ pts_valid = 0;
+ pts_us64_valid = 0;
+ }
+ } else
+#endif
+ /* if (pts_lookup_offset(PTS_TYPE_VIDEO,
+ * stream_offset, &vf->pts, 0) != 0) {
+ */
+ if ((pvdec->vbuf.no_parser == 0) || (pvdec->vbuf.use_ptsserv)) {
+ if (pts_lookup_offset_us64
+ (PTS_TYPE_VIDEO, stream_offset, &vf->pts,
+ &frame_size, 0,
+ &vf->pts_us64) != 0) {
+#ifdef DEBUG_PTS
+ pbi->pts_missed++;
+#endif
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+ pts_valid = 0;
+ pts_us64_valid = 0;
+ } else {
+#ifdef DEBUG_PTS
+ pbi->pts_hit++;
+#endif
+ pts_valid = 1;
+ pts_us64_valid = 1;
+ }
+ }
+
+ fill_frame_info(pbi, pic_config, frame_size, vf->pts);
+
+ pts_save = vf->pts;
+ pts_us64_save = vf->pts_us64;
+ if (pbi->pts_unstable) {
+ frame_duration_adapt(pbi, vf, pts_valid);
+ if (pbi->duration_from_pts_done) {
+ pbi->pts_mode = PTS_NONE_REF_USE_DURATION;
+ } else {
+ if (pts_valid || pts_us64_valid)
+ pbi->pts_mode = PTS_NORMAL;
+ }
+ }
+
+ if ((pbi->pts_mode == PTS_NORMAL) && (vf->pts != 0)
+ && pbi->get_frame_dur) {
+ int pts_diff = (int)vf->pts - pbi->last_lookup_pts;
+
+ if (pts_diff < 0) {
+ pbi->pts_mode_switching_count++;
+ pbi->pts_mode_recovery_count = 0;
+
+ if (pbi->pts_mode_switching_count >=
+ PTS_MODE_SWITCHING_THRESHOLD) {
+ pbi->pts_mode =
+ PTS_NONE_REF_USE_DURATION;
+ pr_info
+ ("HEVC: switch to n_d mode.\n");
+ }
+
+ } else {
+ int p = PTS_MODE_SWITCHING_RECOVERY_THREASHOLD;
+
+ pbi->pts_mode_recovery_count++;
+ if (pbi->pts_mode_recovery_count > p) {
+ pbi->pts_mode_switching_count = 0;
+ pbi->pts_mode_recovery_count = 0;
+ }
+ }
+ }
+
+ if (vf->pts != 0)
+ pbi->last_lookup_pts = vf->pts;
+
+ if ((pbi->pts_mode == PTS_NONE_REF_USE_DURATION)
+ && (slice_type != KEY_FRAME))
+ vf->pts = pbi->last_pts + DUR2PTS(pbi->frame_dur);
+ pbi->last_pts = vf->pts;
+
+ if (vf->pts_us64 != 0)
+ pbi->last_lookup_pts_us64 = vf->pts_us64;
+
+ if ((pbi->pts_mode == PTS_NONE_REF_USE_DURATION)
+ && (slice_type != KEY_FRAME)) {
+ vf->pts_us64 =
+ pbi->last_pts_us64 +
+ (DUR2PTS(pbi->frame_dur) * 100 / 9);
+ }
+ pbi->last_pts_us64 = vf->pts_us64;
+ if ((debug & VP9_DEBUG_OUT_PTS) != 0) {
+ pr_info
+ ("VP9 dec out pts: pts_mode=%d,dur=%d,pts(%d,%lld)(%d,%lld)\n",
+ pbi->pts_mode, pbi->frame_dur, vf->pts,
+ vf->pts_us64, pts_save, pts_us64_save);
+ }
+
+ if (pbi->pts_mode == PTS_NONE_REF_USE_DURATION) {
+ vf->disp_pts = vf->pts;
+ vf->disp_pts_us64 = vf->pts_us64;
+ vf->pts = pts_save;
+ vf->pts_us64 = pts_us64_save;
+ } else {
+ vf->disp_pts = 0;
+ vf->disp_pts_us64 = 0;
+ }
+
+ vf->index = 0xff00 | pic_config->index;
+
+ if (pic_config->double_write_mode & 0x10) {
+ /* double write only */
+ vf->compBodyAddr = 0;
+ vf->compHeadAddr = 0;
+ } else {
+ if (pbi->mmu_enable) {
+ vf->compBodyAddr = 0;
+ vf->compHeadAddr = pic_config->header_adr;
+ } else {
+ /*vf->compBodyAddr = pic_config->mc_y_adr;
+ *vf->compHeadAddr = pic_config->mc_y_adr +
+ *pic_config->comp_body_size; */
+ /*head adr*/
+ }
+ vf->canvas0Addr = vf->canvas1Addr = 0;
+ }
+ if (pic_config->double_write_mode) {
+ vf->type = VIDTYPE_PROGRESSIVE |
+ VIDTYPE_VIU_FIELD;
+ vf->type |= nv_order;
+ if ((pic_config->double_write_mode == 3) &&
+ (!IS_8K_SIZE(pic_config->y_crop_width,
+ pic_config->y_crop_height))) {
+ vf->type |= VIDTYPE_COMPRESS;
+ if (pbi->mmu_enable)
+ vf->type |= VIDTYPE_SCATTER;
+ }
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (pbi->m_ins_flag) {
+ vf->canvas0Addr = vf->canvas1Addr = -1;
+ vf->plane_num = 2;
+ vf->canvas0_config[0] =
+ pic_config->canvas_config[0];
+ vf->canvas0_config[1] =
+ pic_config->canvas_config[1];
+ vf->canvas1_config[0] =
+ pic_config->canvas_config[0];
+ vf->canvas1_config[1] =
+ pic_config->canvas_config[1];
+
+ } else
+#endif
+ vf->canvas0Addr = vf->canvas1Addr =
+ spec2canvas(pic_config);
+ } else {
+ vf->canvas0Addr = vf->canvas1Addr = 0;
+ vf->type = VIDTYPE_COMPRESS | VIDTYPE_VIU_FIELD;
+ if (pbi->mmu_enable)
+ vf->type |= VIDTYPE_SCATTER;
+ }
+
+ switch (pic_config->bit_depth) {
+ case VPX_BITS_8:
+ vf->bitdepth = BITDEPTH_Y8 |
+ BITDEPTH_U8 | BITDEPTH_V8;
+ break;
+ case VPX_BITS_10:
+ case VPX_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_config->bit_depth == VPX_BITS_8)
+ vf->bitdepth |= BITDEPTH_SAVING_MODE;
+
+ /* if((vf->width!=pic_config->width)|
+ * (vf->height!=pic_config->height))
+ */
+ /* pr_info("aaa: %d/%d, %d/%d\n",
+ vf->width,vf->height, pic_config->width,
+ pic_config->height); */
+ vf->width = pic_config->y_crop_width /
+ get_double_write_ratio(pbi,
+ pic_config->double_write_mode);
+ vf->height = pic_config->y_crop_height /
+ get_double_write_ratio(pbi,
+ pic_config->double_write_mode);
+ if (force_w_h != 0) {
+ vf->width = (force_w_h >> 16) & 0xffff;
+ vf->height = force_w_h & 0xffff;
+ }
+ vf->compWidth = pic_config->y_crop_width;
+ vf->compHeight = pic_config->y_crop_height;
+ set_frame_info(pbi, vf);
+ if (force_fps & 0x100) {
+ u32 rate = force_fps & 0xff;
+
+ if (rate)
+ vf->duration = 96000/rate;
+ else
+ vf->duration = 0;
+ }
+ update_vf_memhandle(pbi, vf, pic_config);
+ if (vdec_stream_based(pvdec) && (!pvdec->vbuf.use_ptsserv)) {
+ vf->pts_us64 = stream_offset;
+ vf->pts = 0;
+ }
+ if (!(pic_config->y_crop_width == 196
+ && pic_config->y_crop_height == 196
+ && (debug & VP9_DEBUG_NO_TRIGGER_FRAME) == 0
+ && (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_TXLX))) {
+ struct vdec_info tmp4x;
+
+ inc_vf_ref(pbi, pic_config->index);
+ decoder_do_frame_check(pvdec, vf);
+ vdec_vframe_ready(pvdec, vf);
+ kfifo_put(&pbi->display_q, (const struct vframe_s *)vf);
+ ATRACE_COUNTER(pbi->pts_name, vf->pts);
+ ATRACE_COUNTER(pbi->new_q_name, kfifo_len(&pbi->newframe_q));
+ ATRACE_COUNTER(pbi->disp_q_name, kfifo_len(&pbi->display_q));
+ pbi->vf_pre_count++;
+ pbi_update_gvs(pbi);
+ /*count info*/
+ vdec_count_info(pbi->gvs, 0, stream_offset);
+ if (stream_offset) {
+ if (slice_type == KEY_FRAME) {
+ pbi->gvs->i_decoded_frames++;
+ } else if (slice_type == INTER_FRAME) {
+ pbi->gvs->p_decoded_frames++;
+ } else if (slice_type == FRAME_TYPES) {
+ pbi->gvs->b_decoded_frames++;
+ }
+ }
+ memcpy(&tmp4x, pbi->gvs, sizeof(struct vdec_info));
+ tmp4x.bit_depth_luma = pbi->vp9_param.p.bit_depth;
+ tmp4x.bit_depth_chroma = pbi->vp9_param.p.bit_depth;
+ tmp4x.double_write_mode = get_double_write_mode(pbi);
+ vdec_fill_vdec_frame(pvdec, &pbi->vframe_qos, &tmp4x,
+ vf, pic_config->hw_decode_time);
+ pvdec->vdec_fps_detec(pvdec->id);
+ if (without_display_mode == 0) {
+ vf_notify_receiver(pbi->provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
+ } else
+ vvp9_vf_put(vvp9_vf_get(pbi), pbi);
+ } else {
+ pbi->stat |= VP9_TRIGGER_FRAME_DONE;
+ hevc_source_changed(VFORMAT_VP9, 196, 196, 30);
+ pr_debug("[%s %d] drop trigger frame width %d height %d state 0x%x\n",
+ __func__, __LINE__, vf->width,
+ vf->height, pbi->stat);
+ }
+ }
+
+ return 0;
+}
+
+static int notify_v4l_eos(struct vdec_s *vdec)
+{
+ struct VP9Decoder_s *hw = (struct VP9Decoder_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_fb(hw))) {
+ if (time_after(jiffies, expires) ||
+ v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx))
+ break;
+ }
+
+ if (index == INVALID_IDX) {
+ if (vdec_v4l_get_buffer(hw->v4l2_ctx, &fb) < 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->m_BUF[index].v4l_ref_buf_addr;
+
+ vdec_vframe_ready(vdec, vf);
+ kfifo_put(&hw->display_q, (const struct vframe_s *)vf);
+ vf_notify_receiver(vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
+
+ pr_info("[%d] VP9 EOS notify.\n", (hw->is_used_v4l)?ctx->id:vdec->id);
+ }
+
+ return 0;
+}
+
+static void get_rpm_param(union param_u *params)
+{
+ int i;
+ unsigned int data32;
+
+ if (debug & VP9_DEBUG_BUFMGR)
+ pr_info("enter %s\r\n", __func__);
+ for (i = 0; i < 128; 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 & VP9_DEBUG_BUFMGR)
+ pr_info("leave %s\r\n", __func__);
+}
+static void debug_buffer_mgr_more(struct VP9Decoder_s *pbi)
+{
+ int i;
+
+ if (!(debug & VP9_DEBUG_BUFMGR_MORE))
+ return;
+ pr_info("vp9_param: (%d)\n", pbi->slice_idx);
+ for (i = 0; i < (RPM_END-RPM_BEGIN); i++) {
+ pr_info("%04x ", pbi->vp9_param.l.data[i]);
+ if (((i + 1) & 0xf) == 0)
+ pr_info("\n");
+ }
+ pr_info("=============param==========\r\n");
+ pr_info("profile %x\r\n", pbi->vp9_param.p.profile);
+ pr_info("show_existing_frame %x\r\n",
+ pbi->vp9_param.p.show_existing_frame);
+ pr_info("frame_to_show_idx %x\r\n",
+ pbi->vp9_param.p.frame_to_show_idx);
+ pr_info("frame_type %x\r\n", pbi->vp9_param.p.frame_type);
+ pr_info("show_frame %x\r\n", pbi->vp9_param.p.show_frame);
+ pr_info("e.r.r.o.r_resilient_mode %x\r\n",
+ pbi->vp9_param.p.error_resilient_mode);
+ pr_info("intra_only %x\r\n", pbi->vp9_param.p.intra_only);
+ pr_info("display_size_present %x\r\n",
+ pbi->vp9_param.p.display_size_present);
+ pr_info("reset_frame_context %x\r\n",
+ pbi->vp9_param.p.reset_frame_context);
+ pr_info("refresh_frame_flags %x\r\n",
+ pbi->vp9_param.p.refresh_frame_flags);
+ pr_info("bit_depth %x\r\n", pbi->vp9_param.p.bit_depth);
+ pr_info("width %x\r\n", pbi->vp9_param.p.width);
+ pr_info("height %x\r\n", pbi->vp9_param.p.height);
+ pr_info("display_width %x\r\n", pbi->vp9_param.p.display_width);
+ pr_info("display_height %x\r\n", pbi->vp9_param.p.display_height);
+ pr_info("ref_info %x\r\n", pbi->vp9_param.p.ref_info);
+ pr_info("same_frame_size %x\r\n", pbi->vp9_param.p.same_frame_size);
+ if (!(debug & VP9_DEBUG_DBG_LF_PRINT))
+ return;
+ pr_info("mode_ref_delta_enabled: 0x%x\r\n",
+ pbi->vp9_param.p.mode_ref_delta_enabled);
+ pr_info("sharpness_level: 0x%x\r\n",
+ pbi->vp9_param.p.sharpness_level);
+ pr_info("ref_deltas: 0x%x, 0x%x, 0x%x, 0x%x\r\n",
+ pbi->vp9_param.p.ref_deltas[0], pbi->vp9_param.p.ref_deltas[1],
+ pbi->vp9_param.p.ref_deltas[2], pbi->vp9_param.p.ref_deltas[3]);
+ pr_info("mode_deltas: 0x%x, 0x%x\r\n", pbi->vp9_param.p.mode_deltas[0],
+ pbi->vp9_param.p.mode_deltas[1]);
+ pr_info("filter_level: 0x%x\r\n", pbi->vp9_param.p.filter_level);
+ pr_info("seg_enabled: 0x%x\r\n", pbi->vp9_param.p.seg_enabled);
+ pr_info("seg_abs_delta: 0x%x\r\n", pbi->vp9_param.p.seg_abs_delta);
+ pr_info("seg_lf_feature_enabled: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\r\n",
+ (pbi->vp9_param.p.seg_lf_info[0]>>15 & 1),
+ (pbi->vp9_param.p.seg_lf_info[1]>>15 & 1),
+ (pbi->vp9_param.p.seg_lf_info[2]>>15 & 1),
+ (pbi->vp9_param.p.seg_lf_info[3]>>15 & 1),
+ (pbi->vp9_param.p.seg_lf_info[4]>>15 & 1),
+ (pbi->vp9_param.p.seg_lf_info[5]>>15 & 1),
+ (pbi->vp9_param.p.seg_lf_info[6]>>15 & 1),
+ (pbi->vp9_param.p.seg_lf_info[7]>>15 & 1));
+ pr_info("seg_lf_feature_data: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\r\n",
+ (pbi->vp9_param.p.seg_lf_info[0] & 0x13f),
+ (pbi->vp9_param.p.seg_lf_info[1] & 0x13f),
+ (pbi->vp9_param.p.seg_lf_info[2] & 0x13f),
+ (pbi->vp9_param.p.seg_lf_info[3] & 0x13f),
+ (pbi->vp9_param.p.seg_lf_info[4] & 0x13f),
+ (pbi->vp9_param.p.seg_lf_info[5] & 0x13f),
+ (pbi->vp9_param.p.seg_lf_info[6] & 0x13f),
+ (pbi->vp9_param.p.seg_lf_info[7] & 0x13f));
+
+}
+
+
+static void vp9_recycle_mmu_buf_tail(struct VP9Decoder_s *pbi)
+{
+ struct VP9_Common_s *const cm = &pbi->common;
+ if (pbi->double_write_mode & 0x10)
+ return;
+ if (cm->cur_fb_idx_mmu != INVALID_IDX) {
+ if (pbi->used_4k_num == -1) {
+ pbi->used_4k_num =
+ (READ_VREG(HEVC_SAO_MMU_STATUS) >> 16);
+ if (pbi->m_ins_flag)
+ hevc_mmu_dma_check(hw_to_vdec(pbi));
+ }
+ decoder_mmu_box_free_idx_tail(pbi->mmu_box,
+ cm->cur_fb_idx_mmu, pbi->used_4k_num);
+ cm->cur_fb_idx_mmu = INVALID_IDX;
+ pbi->used_4k_num = -1;
+ }
+}
+
+#ifdef MULTI_INSTANCE_SUPPORT
+static void vp9_recycle_mmu_buf(struct VP9Decoder_s *pbi)
+{
+ struct VP9_Common_s *const cm = &pbi->common;
+ if (pbi->double_write_mode & 0x10)
+ return;
+ if (cm->cur_fb_idx_mmu != INVALID_IDX) {
+ decoder_mmu_box_free_idx(pbi->mmu_box,
+ cm->cur_fb_idx_mmu);
+
+ cm->cur_fb_idx_mmu = INVALID_IDX;
+ pbi->used_4k_num = -1;
+ }
+}
+
+void vp9_recycle_mmu_work(struct work_struct *work)
+{
+ struct VP9Decoder_s *pbi = container_of(work,
+ struct VP9Decoder_s, recycle_mmu_work);
+
+ if (pbi)
+ vp9_recycle_mmu_buf(pbi);
+}
+#endif
+
+
+static void dec_again_process(struct VP9Decoder_s *pbi)
+{
+ amhevc_stop();
+ pbi->dec_result = DEC_RESULT_AGAIN;
+ if (pbi->process_state ==
+ PROC_STATE_DECODESLICE) {
+ pbi->process_state =
+ PROC_STATE_SENDAGAIN;
+ if (pbi->mmu_enable) {
+ /*
+ * Because vp9_recycle_mmu_buf has sleep function,we can't
+ * call it directly. Use a recycle_mmu_work to substitude it.
+ */
+ vdec_schedule_work(&pbi->recycle_mmu_work);
+ }
+ }
+ reset_process_time(pbi);
+ vdec_schedule_work(&pbi->work);
+}
+
+int continue_decoding(struct VP9Decoder_s *pbi)
+{
+ int ret;
+ int i;
+ struct VP9_Common_s *const cm = &pbi->common;
+ struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(pbi->v4l2_ctx);
+ debug_buffer_mgr_more(pbi);
+
+ if (pbi->is_used_v4l && ctx->param_sets_from_ucode)
+ pbi->res_ch_flag = 0;
+
+ bit_depth_luma = pbi->vp9_param.p.bit_depth;
+ bit_depth_chroma = pbi->vp9_param.p.bit_depth;
+
+ if ((pbi->vp9_param.p.bit_depth >= VPX_BITS_10) &&
+ (get_double_write_mode(pbi) == 0x10)) {
+ pbi->fatal_error |= DECODER_FATAL_ERROR_SIZE_OVERFLOW;
+ pr_err("fatal err, bit_depth %d, unsupport dw 0x10\n",
+ pbi->vp9_param.p.bit_depth);
+ return -1;
+ }
+
+ if (pbi->process_state != PROC_STATE_SENDAGAIN) {
+ ret = vp9_bufmgr_process(pbi, &pbi->vp9_param);
+ if (!pbi->m_ins_flag)
+ pbi->slice_idx++;
+ } else {
+ union param_u *params = &pbi->vp9_param;
+ if (pbi->mmu_enable && ((pbi->double_write_mode & 0x10) == 0)) {
+ ret = vp9_alloc_mmu(pbi,
+ cm->new_fb_idx,
+ params->p.width,
+ params->p.height,
+ params->p.bit_depth,
+ pbi->frame_mmu_map_addr);
+ if (ret >= 0)
+ cm->cur_fb_idx_mmu = cm->new_fb_idx;
+ else
+ pr_err("can't alloc need mmu1,idx %d ret =%d\n",
+ cm->new_fb_idx,
+ ret);
+ } else {
+ ret = 0;
+ }
+ WRITE_VREG(HEVC_PARSER_PICTURE_SIZE,
+ (params->p.height << 16) | params->p.width);
+ }
+ if (ret < 0) {
+ pr_info("vp9_bufmgr_process=> %d, VP9_10B_DISCARD_NAL\r\n",
+ ret);
+ WRITE_VREG(HEVC_DEC_STATUS_REG, VP9_10B_DISCARD_NAL);
+ cm->show_frame = 0;
+ if (pbi->mmu_enable)
+ vp9_recycle_mmu_buf(pbi);
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (pbi->m_ins_flag) {
+ pbi->dec_result = DEC_RESULT_DONE;
+#ifdef SUPPORT_FB_DECODING
+ if (pbi->used_stage_buf_num == 0)
+#endif
+ amhevc_stop();
+ vdec_schedule_work(&pbi->work);
+ }
+#endif
+ return ret;
+ } else if (ret == 0) {
+ struct PIC_BUFFER_CONFIG_s *cur_pic_config
+ = &cm->cur_frame->buf;
+ cur_pic_config->decode_idx = pbi->frame_count;
+
+ if (pbi->process_state != PROC_STATE_SENDAGAIN) {
+ if (!pbi->m_ins_flag) {
+ pbi->frame_count++;
+ decode_frame_count[pbi->index]
+ = pbi->frame_count;
+ }
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (pbi->chunk) {
+ cur_pic_config->pts = pbi->chunk->pts;
+ cur_pic_config->pts64 = pbi->chunk->pts64;
+ cur_pic_config->timestamp = pbi->chunk->timestamp;
+ }
+#endif
+ }
+ /*pr_info("Decode Frame Data %d\n", pbi->frame_count);*/
+ config_pic_size(pbi, pbi->vp9_param.p.bit_depth);
+
+ if ((pbi->common.frame_type != KEY_FRAME)
+ && (!pbi->common.intra_only)) {
+ config_mc_buffer(pbi, pbi->vp9_param.p.bit_depth);
+#ifdef SUPPORT_FB_DECODING
+ if (pbi->used_stage_buf_num == 0)
+#endif
+ config_mpred_hw(pbi);
+ } else {
+#ifdef SUPPORT_FB_DECODING
+ if (pbi->used_stage_buf_num == 0)
+#endif
+ clear_mpred_hw(pbi);
+ }
+#ifdef MCRCC_ENABLE
+ if (mcrcc_cache_alg_flag)
+ config_mcrcc_axi_hw_new(pbi);
+ else
+ config_mcrcc_axi_hw(pbi);
+#endif
+ config_sao_hw(pbi, &pbi->vp9_param);
+
+#ifdef VP9_LPF_LVL_UPDATE
+ /*
+ * Get loop filter related picture level parameters from Parser
+ */
+ pbi->lf->mode_ref_delta_enabled = pbi->vp9_param.p.mode_ref_delta_enabled;
+ pbi->lf->sharpness_level = pbi->vp9_param.p.sharpness_level;
+ for (i = 0; i < 4; i++)
+ pbi->lf->ref_deltas[i] = pbi->vp9_param.p.ref_deltas[i];
+ for (i = 0; i < 2; i++)
+ pbi->lf->mode_deltas[i] = pbi->vp9_param.p.mode_deltas[i];
+ pbi->default_filt_lvl = pbi->vp9_param.p.filter_level;
+ pbi->seg_4lf->enabled = pbi->vp9_param.p.seg_enabled;
+ pbi->seg_4lf->abs_delta = pbi->vp9_param.p.seg_abs_delta;
+ for (i = 0; i < MAX_SEGMENTS; i++)
+ pbi->seg_4lf->feature_mask[i] = (pbi->vp9_param.p.seg_lf_info[i] &
+ 0x8000) ? (1 << SEG_LVL_ALT_LF) : 0;
+ for (i = 0; i < MAX_SEGMENTS; i++)
+ pbi->seg_4lf->feature_data[i][SEG_LVL_ALT_LF]
+ = (pbi->vp9_param.p.seg_lf_info[i]
+ & 0x100) ? -(pbi->vp9_param.p.seg_lf_info[i]
+ & 0x3f) : (pbi->vp9_param.p.seg_lf_info[i] & 0x3f);
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) {
+ /*Set pipeline mode*/
+ uint32_t lpf_data32 = READ_VREG(HEVC_DBLK_CFGB);
+ /*dblk pipeline mode=1 for performance*/
+ if (pbi->vp9_param.p.width >= 1280)
+ lpf_data32 |= (0x1 << 4);
+ else
+ lpf_data32 &= ~(0x3 << 4);
+ WRITE_VREG(HEVC_DBLK_CFGB, lpf_data32);
+ }
+ /*
+ * Update loop filter Thr/Lvl table for every frame
+ */
+ /*pr_info
+ ("vp9_loop_filter (run before every frame decoding start)\n");*/
+ vp9_loop_filter_frame_init(pbi->seg_4lf,
+ pbi->lfi, pbi->lf, pbi->default_filt_lvl);
+#endif
+ /*pr_info("HEVC_DEC_STATUS_REG <= VP9_10B_DECODE_SLICE\n");*/
+ WRITE_VREG(HEVC_DEC_STATUS_REG, VP9_10B_DECODE_SLICE);
+ } else {
+ pr_info("Skip search next start code\n");
+ cm->prev_fb_idx = INVALID_IDX;
+ /*skip, search next start code*/
+ WRITE_VREG(HEVC_DEC_STATUS_REG, VP9_10B_DECODE_SLICE);
+ }
+ pbi->process_state = PROC_STATE_DECODESLICE;
+ if (pbi->mmu_enable && ((pbi->double_write_mode & 0x10) == 0)) {
+ if (pbi->last_put_idx < pbi->used_buf_num) {
+ struct RefCntBuffer_s *frame_bufs =
+ cm->buffer_pool->frame_bufs;
+ int i = pbi->last_put_idx;
+ /*free not used buffers.*/
+ if ((frame_bufs[i].ref_count == 0) &&
+ (frame_bufs[i].buf.vf_ref == 0) &&
+ (frame_bufs[i].buf.index != -1)) {
+ decoder_mmu_box_free_idx(pbi->mmu_box, i);
+ }
+ pbi->last_put_idx = -1;
+ }
+ }
+ return ret;
+}
+
+static void fill_frame_info(struct VP9Decoder_s *pbi,
+ struct PIC_BUFFER_CONFIG_s *frame,
+ unsigned int framesize,
+ unsigned int pts)
+{
+ struct vframe_qos_s *vframe_qos = &pbi->vframe_qos;
+
+ if (frame->slice_type == KEY_FRAME)
+ vframe_qos->type = 1;
+ else if (frame->slice_type == INTER_FRAME)
+ vframe_qos->type = 2;
+/*
+#define SHOW_QOS_INFO
+*/
+ if (input_frame_based(hw_to_vdec(pbi)))
+ vframe_qos->size = frame->frame_size2;
+ else
+ vframe_qos->size = framesize;
+ vframe_qos->pts = pts;
+#ifdef SHOW_QOS_INFO
+ vp9_print(pbi, 0, "slice:%d\n", frame->slice_type);
+#endif
+ vframe_qos->max_mv = frame->max_mv;
+ vframe_qos->avg_mv = frame->avg_mv;
+ vframe_qos->min_mv = frame->min_mv;
+#ifdef SHOW_QOS_INFO
+ vp9_print(pbi, 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 = frame->max_qp;
+ vframe_qos->avg_qp = frame->avg_qp;
+ vframe_qos->min_qp = frame->min_qp;
+#ifdef SHOW_QOS_INFO
+ vp9_print(pbi, 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 = frame->max_skip;
+ vframe_qos->avg_skip = frame->avg_skip;
+ vframe_qos->min_skip = frame->min_skip;
+#ifdef SHOW_QOS_INFO
+ vp9_print(pbi, 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++;
+}
+
+/* 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 VP9Decoder_s *pbi)
+{
+ struct PIC_BUFFER_CONFIG_s *frame = &pbi->cur_buf->buf;
+ struct vdec_s *vdec = hw_to_vdec(pbi);
+
+ if (!frame)
+ return;
+ if (vdec->mvfrm) {
+ frame->frame_size2 = vdec->mvfrm->frame_size;
+ frame->hw_decode_time =
+ local_clock() - vdec->mvfrm->hw_decode_start;
+ }
+
+ 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 (frame->slice_type == KEY_FRAME)
+ 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;
+ }
+ }
+ }
+ frame->max_mv = a[2];
+ frame->avg_mv = a[1];
+ frame->min_mv = a[0];
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "mv data %lx a[0]= %x a[1]= %x a[2]= %x\n",
+ data, a[0], a[1], a[2]);
+
+ 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;
+ }
+ }
+ }
+ frame->max_qp = a[2];
+ frame->avg_qp = a[1];
+ frame->min_qp = a[0];
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "qp data %lx a[0]= %x a[1]= %x a[2]= %x\n",
+ data, a[0], a[1], a[2]);
+
+ 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;
+ }
+ }
+ }
+ frame->max_skip = a[2];
+ frame->avg_skip = a[1];
+ frame->min_skip = a[0];
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "skip data %lx a[0]= %x a[1]= %x a[2]= %x\n",
+ 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;
+ int pic_number = frame->decode_idx;
+
+ frame->max_mv = 0;
+ frame->avg_mv = 0;
+ frame->min_mv = 0;
+
+ frame->max_skip = 0;
+ frame->avg_skip = 0;
+ frame->min_skip = 0;
+
+ frame->max_qp = 0;
+ frame->avg_qp = 0;
+ frame->min_qp = 0;
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO, "slice_type:%d, poc:%d\n",
+ frame->slice_type,
+ pic_number);
+
+ /* 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) {
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] NO Data yet.\n",
+ pic_number);
+
+ /* reset all counts */
+ WRITE_VREG(HEVC_PIC_QUALITY_CTRL, (1<<8));
+ return;
+ }
+ /* qp_y_sum */
+ rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] Y QP AVG : %d (%d/%d)\n",
+ pic_number, rdata32/blk88_y_count,
+ rdata32, blk88_y_count);
+
+ frame->avg_qp = rdata32/blk88_y_count;
+ /* intra_y_count */
+ rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] Y intra rate : %d%c (%d)\n",
+ pic_number, rdata32*100/blk88_y_count,
+ '%', rdata32);
+
+ /* skipped_y_count */
+ rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] Y skipped rate : %d%c (%d)\n",
+ pic_number, rdata32*100/blk88_y_count,
+ '%', rdata32);
+
+ frame->avg_skip = rdata32*100/blk88_y_count;
+ /* coeff_non_zero_y_count */
+ rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] Y ZERO_Coeff rate : %d%c (%d)\n",
+ pic_number, (100 - rdata32*100/(blk88_y_count*1)),
+ '%', rdata32);
+
+ /* blk66_c_count */
+ blk88_c_count = READ_VREG(HEVC_PIC_QUALITY_DATA);
+ if (blk88_c_count == 0) {
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] NO Data yet.\n",
+ pic_number);
+ /* reset all counts */
+ WRITE_VREG(HEVC_PIC_QUALITY_CTRL, (1<<8));
+ return;
+ }
+ /* qp_c_sum */
+ rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] C QP AVG : %d (%d/%d)\n",
+ pic_number, rdata32/blk88_c_count,
+ rdata32, blk88_c_count);
+
+ /* intra_c_count */
+ rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] C intra rate : %d%c (%d)\n",
+ pic_number, rdata32*100/blk88_c_count,
+ '%', rdata32);
+
+ /* skipped_cu_c_count */
+ rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] C skipped rate : %d%c (%d)\n",
+ pic_number, rdata32*100/blk88_c_count,
+ '%', rdata32);
+
+ /* coeff_non_zero_c_count */
+ rdata32 = READ_VREG(HEVC_PIC_QUALITY_DATA);
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] C ZERO_Coeff rate : %d%c (%d)\n",
+ pic_number, (100 - rdata32*100/(blk88_c_count*1)),
+ '%', rdata32);
+
+ /* 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);
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] Y QP min : %d\n",
+ pic_number, (rdata32>>0)&0xff);
+
+ frame->min_qp = (rdata32>>0)&0xff;
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] Y QP max : %d\n",
+ pic_number, (rdata32>>8)&0xff);
+
+ frame->max_qp = (rdata32>>8)&0xff;
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] C QP min : %d\n",
+ pic_number, (rdata32>>16)&0xff);
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] C QP max : %d\n",
+ pic_number, (rdata32>>24)&0xff);
+
+ /* blk22_mv_count */
+ blk22_mv_count = READ_VREG(HEVC_PIC_QUALITY_DATA);
+ if (blk22_mv_count == 0) {
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] NO MV Data yet.\n",
+ pic_number);
+ /* 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 */
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] MV AVG High Bits: 0x%X\n",
+ pic_number, rdata32);
+
+ 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);
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] MVX_L0 AVG : %d (%lld/%d)\n",
+ pic_number, (int)value,
+ value, blk22_mv_count);
+
+ frame->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;
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] MVY_L0 AVG : %d (%lld/%d)\n",
+ pic_number, rdata32_l/blk22_mv_count,
+ value, blk22_mv_count);
+
+ /* 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;
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] MVX_L1 AVG : %d (%lld/%d)\n",
+ pic_number, rdata32_l/blk22_mv_count,
+ value, blk22_mv_count);
+
+ /* 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;
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] MVY_L1 AVG : %d (%lld/%d)\n",
+ pic_number, rdata32_l/blk22_mv_count,
+ value, blk22_mv_count);
+
+ /* {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;
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] MVX_L0 MAX : %d\n",
+ pic_number, mv_hi);
+
+ frame->max_mv = mv_hi;
+
+ mv_lo = (rdata32>>0)&0xffff;
+ if (mv_lo & 0x8000)
+ mv_lo = 0x8000 - mv_lo;
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] MVX_L0 MIN : %d\n",
+ pic_number, mv_lo);
+
+ frame->min_mv = mv_lo;
+
+ /* {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;
+
+ vp9_print(pbi, VP9_DEBUG_QOS_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;
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[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;
+
+ vp9_print(pbi, VP9_DEBUG_QOS_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;
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[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;
+
+ vp9_print(pbi, VP9_DEBUG_QOS_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;
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] MVY_L1 MIN : %d\n",
+ pic_number, mv_lo);
+
+ rdata32 = READ_VREG(HEVC_PIC_QUALITY_CTRL);
+
+ vp9_print(pbi, VP9_DEBUG_QOS_INFO,
+ "[Picture %d Quality] After Read : VDEC_PIC_QUALITY_CTRL : 0x%x\n",
+ pic_number, rdata32);
+
+ /* reset all counts */
+ WRITE_VREG(HEVC_PIC_QUALITY_CTRL, (1<<8));
+ }
+}
+
+static int vvp9_get_ps_info(struct VP9Decoder_s *pbi, struct aml_vdec_ps_infos *ps)
+{
+ int dw_mode = v4l_parser_get_double_write_mode(pbi);
+
+ ps->visible_width = pbi->frame_width / get_double_write_ratio(pbi, dw_mode);
+ ps->visible_height = pbi->frame_height / get_double_write_ratio(pbi, dw_mode);
+ ps->coded_width = ALIGN(pbi->frame_width, 32) / get_double_write_ratio(pbi, dw_mode);
+ ps->coded_height = ALIGN(pbi->frame_height, 32) / get_double_write_ratio(pbi, dw_mode);
+ ps->dpb_size = pbi->used_buf_num;
+
+ return 0;
+}
+
+
+static int v4l_res_change(struct VP9Decoder_s *pbi)
+{
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(pbi->v4l2_ctx);
+ struct VP9_Common_s *const cm = &pbi->common;
+ int ret = 0;
+
+ if (ctx->param_sets_from_ucode &&
+ pbi->res_ch_flag == 0) {
+ struct aml_vdec_ps_infos ps;
+ if ((cm->width != 0 &&
+ cm->height != 0) &&
+ (pbi->frame_width != cm->width ||
+ pbi->frame_height != cm->height)) {
+
+ vp9_print(pbi, 0, "%s (%d,%d)=>(%d,%d)\r\n", __func__, cm->width,
+ cm->height, pbi->frame_width, pbi->frame_height);
+ vvp9_get_ps_info(pbi, &ps);
+ vdec_v4l_set_ps_infos(ctx, &ps);
+ vdec_v4l_res_ch_event(ctx);
+ pbi->v4l_params_parsed = false;
+ pbi->res_ch_flag = 1;
+ ctx->v4l_resolution_change = 1;
+ pbi->eos = 1;
+ vp9_bufmgr_postproc(pbi);
+ //del_timer_sync(&pbi->timer);
+ notify_v4l_eos(hw_to_vdec(pbi));
+ ret = 1;
+ }
+ }
+
+ return ret;
+}
+
+
+static irqreturn_t vvp9_isr_thread_fn(int irq, void *data)
+{
+ struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)data;
+ unsigned int dec_status = pbi->dec_status;
+ int i;
+
+ /*if (pbi->wait_buf)
+ * pr_info("set wait_buf to 0\r\n");
+ */
+ if (pbi->eos)
+ return IRQ_HANDLED;
+ pbi->wait_buf = 0;
+#ifdef MULTI_INSTANCE_SUPPORT
+#ifdef SUPPORT_FB_DECODING
+#ifdef FB_DECODING_TEST_SCHEDULE
+ if (pbi->s1_test_cmd == TEST_SET_PIC_DONE)
+ dec_status = HEVC_DECPIC_DATA_DONE;
+ else if (pbi->s1_test_cmd == TEST_SET_S2_DONE
+ && dec_status == HEVC_DECPIC_DATA_DONE)
+ dec_status = HEVC_S2_DECODING_DONE;
+ pbi->s1_test_cmd = TEST_SET_NONE;
+#else
+ /*if (irq != VDEC_IRQ_0)
+ dec_status = HEVC_S2_DECODING_DONE;*/
+#endif
+ if (dec_status == HEVC_S2_DECODING_DONE) {
+ pbi->dec_result = DEC_RESULT_DONE;
+ vdec_schedule_work(&pbi->work);
+#ifdef FB_DECODING_TEST_SCHEDULE
+ amhevc_stop();
+ pbi->dec_s1_result = DEC_S1_RESULT_DONE;
+ vdec_schedule_work(&pbi->s1_work);
+#endif
+ } else
+#endif
+ if ((dec_status == HEVC_NAL_DECODE_DONE) ||
+ (dec_status == HEVC_SEARCH_BUFEMPTY) ||
+ (dec_status == HEVC_DECODE_BUFEMPTY)
+ ) {
+ if (pbi->m_ins_flag) {
+ reset_process_time(pbi);
+ if (!vdec_frame_based(hw_to_vdec(pbi)))
+ dec_again_process(pbi);
+ else {
+ pbi->dec_result = DEC_RESULT_GET_DATA;
+ vdec_schedule_work(&pbi->work);
+ }
+ }
+ pbi->process_busy = 0;
+ return IRQ_HANDLED;
+ } else if (dec_status == HEVC_DECPIC_DATA_DONE) {
+ if (pbi->m_ins_flag) {
+ get_picture_qos_info(pbi);
+#ifdef SUPPORT_FB_DECODING
+ if (pbi->used_stage_buf_num > 0) {
+ reset_process_time(pbi);
+ inc_s1_pos(pbi);
+ trigger_schedule(pbi);
+#ifdef FB_DECODING_TEST_SCHEDULE
+ pbi->s1_test_cmd = TEST_SET_S2_DONE;
+#else
+ amhevc_stop();
+ pbi->dec_s1_result = DEC_S1_RESULT_DONE;
+ vdec_schedule_work(&pbi->s1_work);
+#endif
+ } else
+#endif
+ {
+ reset_process_time(pbi);
+ if (pbi->vf_pre_count == 0 || pbi->low_latency_flag)
+ vp9_bufmgr_postproc(pbi);
+
+ pbi->dec_result = DEC_RESULT_DONE;
+ amhevc_stop();
+ if (mcrcc_cache_alg_flag)
+ dump_hit_rate(pbi);
+ vdec_schedule_work(&pbi->work);
+ }
+ } else {
+ if (pbi->low_latency_flag) {
+ vp9_bufmgr_postproc(pbi);
+ WRITE_VREG(HEVC_DEC_STATUS_REG, HEVC_ACTION_DONE);
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ vdec_profile(hw_to_vdec(pbi), VDEC_PROFILE_EVENT_CB);
+ if (debug & PRINT_FLAG_VDEC_DETAIL)
+ pr_info("%s VP9 frame done \n", __func__);
+#endif
+ }
+ }
+
+ pbi->process_busy = 0;
+ return IRQ_HANDLED;
+ }
+#endif
+
+ if (dec_status == VP9_EOS) {
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (pbi->m_ins_flag)
+ reset_process_time(pbi);
+#endif
+
+ pr_info("VP9_EOS, flush buffer\r\n");
+
+ vp9_bufmgr_postproc(pbi);
+
+ pr_info("send VP9_10B_DISCARD_NAL\r\n");
+ WRITE_VREG(HEVC_DEC_STATUS_REG, VP9_10B_DISCARD_NAL);
+ pbi->process_busy = 0;
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (pbi->m_ins_flag) {
+ pbi->dec_result = DEC_RESULT_DONE;
+ amhevc_stop();
+ vdec_schedule_work(&pbi->work);
+ }
+#endif
+ return IRQ_HANDLED;
+ } else if (dec_status == HEVC_DECODE_OVER_SIZE) {
+ pr_info("vp9 decode oversize !!\n");
+ debug |= (VP9_DEBUG_DIS_LOC_ERROR_PROC |
+ VP9_DEBUG_DIS_SYS_ERROR_PROC);
+ pbi->fatal_error |= DECODER_FATAL_ERROR_SIZE_OVERFLOW;
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (pbi->m_ins_flag)
+ reset_process_time(pbi);
+#endif
+ return IRQ_HANDLED;
+ }
+
+ if (dec_status != VP9_HEAD_PARSER_DONE) {
+ pbi->process_busy = 0;
+ return IRQ_HANDLED;
+ }
+
+ if (pbi->m_ins_flag &&
+ !get_free_buf_count(pbi)) {
+ pbi->run_ready_min_buf_num = pbi->one_package_frame_cnt + 1;
+ pr_err("need buffer, one package frame count = %d\n", pbi->one_package_frame_cnt + 1);
+ pbi->dec_result = DEC_RESULT_NEED_MORE_BUFFER;
+ vdec_schedule_work(&pbi->work);
+ return IRQ_HANDLED;
+ }
+
+ pbi->one_package_frame_cnt++;
+
+#ifdef MULTI_INSTANCE_SUPPORT
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ if (pbi->m_ins_flag ==0 && pbi->low_latency_flag) {
+ vdec_profile(hw_to_vdec(pbi), VDEC_PROFILE_EVENT_RUN);
+ if (debug & PRINT_FLAG_VDEC_DETAIL)
+ pr_info("%s VP9 frame header found \n", __func__);
+ }
+#endif
+ if (pbi->m_ins_flag)
+ reset_process_time(pbi);
+#endif
+ if (pbi->process_state != PROC_STATE_SENDAGAIN
+#ifdef SUPPORT_FB_DECODING
+ && pbi->used_stage_buf_num == 0
+#endif
+ ) {
+ if (pbi->mmu_enable)
+ vp9_recycle_mmu_buf_tail(pbi);
+
+
+ if (pbi->frame_count > 0)
+ vp9_bufmgr_postproc(pbi);
+ }
+
+ if (debug & VP9_DEBUG_SEND_PARAM_WITH_REG) {
+ get_rpm_param(&pbi->vp9_param);
+ } else {
+#ifdef SUPPORT_FB_DECODING
+ if (pbi->used_stage_buf_num > 0) {
+ reset_process_time(pbi);
+ get_s1_buf(pbi);
+
+ if (get_mv_buf(pbi,
+ &pbi->s1_mv_buf_index,
+ &pbi->s1_mpred_mv_wr_start_addr
+ ) < 0) {
+ vp9_print(pbi, 0,
+ "%s: Error get_mv_buf fail\n",
+ __func__);
+ }
+
+ if (pbi->s1_buf == NULL) {
+ vp9_print(pbi, 0,
+ "%s: Error get_s1_buf fail\n",
+ __func__);
+ pbi->process_busy = 0;
+ return IRQ_HANDLED;
+ }
+
+ for (i = 0; i < (RPM_END - RPM_BEGIN); i += 4) {
+ int ii;
+ for (ii = 0; ii < 4; ii++) {
+ pbi->s1_buf->rpm[i + 3 - ii] =
+ pbi->rpm_ptr[i + 3 - ii];
+ pbi->s1_param.l.data[i + ii] =
+ pbi->rpm_ptr[i + 3 - ii];
+ }
+ }
+
+ mpred_process(pbi);
+#ifdef FB_DECODING_TEST_SCHEDULE
+ pbi->dec_s1_result =
+ DEC_S1_RESULT_TEST_TRIGGER_DONE;
+ vdec_schedule_work(&pbi->s1_work);
+#else
+ WRITE_VREG(HEVC_ASSIST_FB_MMU_MAP_ADDR,
+ pbi->stage_mmu_map_phy_addr +
+ pbi->s1_buf->index * STAGE_MMU_MAP_SIZE);
+
+ start_s1_decoding(pbi);
+#endif
+ start_process_time(pbi);
+ pbi->process_busy = 0;
+ return IRQ_HANDLED;
+ } else
+#endif
+ {
+ for (i = 0; i < (RPM_END - RPM_BEGIN); i += 4) {
+ int ii;
+ for (ii = 0; ii < 4; ii++)
+ pbi->vp9_param.l.data[i + ii] =
+ pbi->rpm_ptr[i + 3 - ii];
+ }
+ }
+ }
+
+ if (pbi->is_used_v4l) {
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(pbi->v4l2_ctx);
+
+ pbi->frame_width = pbi->vp9_param.p.width;
+ pbi->frame_height = pbi->vp9_param.p.height;
+
+ if (!pbi->has_keyframe &&
+ ((pbi->frame_width == 0) ||
+ (pbi->frame_height == 0))) {
+ continue_decoding(pbi);
+ pbi->postproc_done = 0;
+ pbi->process_busy = 0;
+ return IRQ_HANDLED;
+ }
+
+ if (!v4l_res_change(pbi)) {
+ if (ctx->param_sets_from_ucode && !pbi->v4l_params_parsed) {
+ struct aml_vdec_ps_infos ps;
+
+ pr_debug("set ucode parse\n");
+ vvp9_get_ps_info(pbi, &ps);
+ /*notice the v4l2 codec.*/
+ vdec_v4l_set_ps_infos(ctx, &ps);
+ pbi->v4l_params_parsed = true;
+ pbi->postproc_done = 0;
+ pbi->process_busy = 0;
+ dec_again_process(pbi);
+ return IRQ_HANDLED;
+ }
+ } else {
+ pbi->postproc_done = 0;
+ pbi->process_busy = 0;
+ dec_again_process(pbi);
+ return IRQ_HANDLED;
+ }
+ }
+
+ continue_decoding(pbi);
+ pbi->postproc_done = 0;
+ pbi->process_busy = 0;
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (pbi->m_ins_flag)
+ start_process_time(pbi);
+#endif
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t vvp9_isr(int irq, void *data)
+{
+ int i;
+ unsigned int dec_status;
+ struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)data;
+ unsigned int adapt_prob_status;
+ struct VP9_Common_s *const cm = &pbi->common;
+ uint debug_tag;
+
+ WRITE_VREG(HEVC_ASSIST_MBOX0_CLR_REG, 1);
+
+ dec_status = READ_VREG(HEVC_DEC_STATUS_REG);
+ adapt_prob_status = READ_VREG(VP9_ADAPT_PROB_REG);
+ if (!pbi)
+ return IRQ_HANDLED;
+ if (pbi->init_flag == 0)
+ return IRQ_HANDLED;
+ if (pbi->process_busy) {/*on process.*/
+ vp9_print(pbi, PRINT_FLAG_VDEC_STATUS,
+ "%s: process_busy isr return\n", __func__);
+ return IRQ_HANDLED;
+ }
+ pbi->dec_status = dec_status;
+ pbi->process_busy = 1;
+ if (debug & VP9_DEBUG_BUFMGR)
+ pr_info("vp9 isr (%d) dec status = 0x%x, lcu 0x%x shiftbyte 0x%x (%x %x lev %x, wr %x, rd %x)\n",
+ irq,
+ 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)
+ );
+#ifdef SUPPORT_FB_DECODING
+ /*if (irq != VDEC_IRQ_0)
+ return IRQ_WAKE_THREAD;*/
+#endif
+
+ debug_tag = READ_HREG(DEBUG_REG1);
+ if (debug_tag & 0x10000) {
+ 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 ",
+ pbi->lmem_ptr[i + 3 - ii]);
+ }
+ if (((i + ii) & 0xf) == 0)
+ pr_info("\n");
+ }
+
+ if ((udebug_pause_pos == (debug_tag & 0xffff)) &&
+ (udebug_pause_decode_idx == 0 ||
+ udebug_pause_decode_idx == pbi->slice_idx) &&
+ (udebug_pause_val == 0 ||
+ udebug_pause_val == READ_HREG(DEBUG_REG2)))
+ pbi->ucode_pause_pos = udebug_pause_pos;
+ else if (debug_tag & 0x20000)
+ pbi->ucode_pause_pos = 0xffffffff;
+ if (pbi->ucode_pause_pos)
+ reset_process_time(pbi);
+ 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 == (debug_tag & 0xffff)) &&
+ (udebug_pause_decode_idx == 0 ||
+ udebug_pause_decode_idx == pbi->slice_idx) &&
+ (udebug_pause_val == 0 ||
+ udebug_pause_val == READ_HREG(DEBUG_REG2)))
+ pbi->ucode_pause_pos = udebug_pause_pos;
+ if (pbi->ucode_pause_pos)
+ reset_process_time(pbi);
+ else
+ WRITE_HREG(DEBUG_REG1, 0);
+ pbi->process_busy = 0;
+ return IRQ_HANDLED;
+ }
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (!pbi->m_ins_flag) {
+#endif
+ if (pbi->error_flag == 1) {
+ pbi->error_flag = 2;
+ pbi->process_busy = 0;
+ return IRQ_HANDLED;
+ } else if (pbi->error_flag == 3) {
+ pbi->process_busy = 0;
+ return IRQ_HANDLED;
+ }
+
+ if (get_free_buf_count(pbi) <= 0) {
+ /*
+ if (pbi->wait_buf == 0)
+ pr_info("set wait_buf to 1\r\n");
+ */
+ pbi->wait_buf = 1;
+ pbi->process_busy = 0;
+ return IRQ_HANDLED;
+ }
+#ifdef MULTI_INSTANCE_SUPPORT
+ }
+#endif
+ if ((adapt_prob_status & 0xff) == 0xfd) {
+ /*VP9_REQ_ADAPT_PROB*/
+ int pre_fc = (cm->frame_type == KEY_FRAME) ? 1 : 0;
+ uint8_t *prev_prob_b =
+ ((uint8_t *)pbi->prob_buffer_addr) +
+ ((adapt_prob_status >> 8) * 0x1000);
+ uint8_t *cur_prob_b =
+ ((uint8_t *)pbi->prob_buffer_addr) + 0x4000;
+ uint8_t *count_b = (uint8_t *)pbi->count_buffer_addr;
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (pbi->m_ins_flag)
+ reset_process_time(pbi);
+#endif
+ adapt_coef_probs(pbi->pic_count,
+ (cm->last_frame_type == KEY_FRAME),
+ pre_fc, (adapt_prob_status >> 8),
+ (unsigned int *)prev_prob_b,
+ (unsigned int *)cur_prob_b, (unsigned int *)count_b);
+
+ memcpy(prev_prob_b, cur_prob_b, PROB_SIZE);
+ WRITE_VREG(VP9_ADAPT_PROB_REG, 0);
+ pbi->pic_count += 1;
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (pbi->m_ins_flag)
+ start_process_time(pbi);
+#endif
+
+ /*return IRQ_HANDLED;*/
+ }
+ return IRQ_WAKE_THREAD;
+}
+
+static void vp9_set_clk(struct work_struct *work)
+{
+ struct VP9Decoder_s *pbi = container_of(work,
+ struct VP9Decoder_s, set_clk_work);
+ int fps = 96000 / pbi->frame_dur;
+
+ if (hevc_source_changed(VFORMAT_VP9,
+ frame_width, frame_height, fps) > 0)
+ pbi->saved_resolution = frame_width *
+ frame_height * fps;
+}
+
+static void vvp9_put_timer_func(unsigned long arg)
+{
+ struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)arg;
+ struct timer_list *timer = &pbi->timer;
+ uint8_t empty_flag;
+ unsigned int buf_level;
+
+ enum receviver_start_e state = RECEIVER_INACTIVE;
+
+ if (pbi->m_ins_flag) {
+ if (hw_to_vdec(pbi)->next_status
+ == VDEC_STATUS_DISCONNECTED &&
+ !pbi->is_used_v4l) {
+#ifdef SUPPORT_FB_DECODING
+ if (pbi->run2_busy)
+ return;
+
+ pbi->dec_s1_result = DEC_S1_RESULT_FORCE_EXIT;
+ vdec_schedule_work(&pbi->s1_work);
+#endif
+ pbi->dec_result = DEC_RESULT_FORCE_EXIT;
+ vdec_schedule_work(&pbi->work);
+ pr_debug(
+ "vdec requested to be disconnected\n");
+ return;
+ }
+ }
+ if (pbi->init_flag == 0) {
+ if (pbi->stat & STAT_TIMER_ARM) {
+ timer->expires = jiffies + PUT_INTERVAL;
+ add_timer(&pbi->timer);
+ }
+ return;
+ }
+ if (pbi->m_ins_flag == 0) {
+ if (vf_get_receiver(pbi->provider_name)) {
+ state =
+ vf_notify_receiver(pbi->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 & VP9_DEBUG_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(&pbi->display_q) &&
+ buf_level > 0x200)
+ ) {
+ WRITE_VREG
+ (HEVC_ASSIST_MBOX0_IRQ_REG,
+ 0x1);
+ }
+ }
+
+ if ((debug & VP9_DEBUG_DIS_SYS_ERROR_PROC) == 0) {
+ /* receiver has no buffer to recycle */
+ /*if ((state == RECEIVER_INACTIVE) &&
+ * (kfifo_is_empty(&pbi->display_q))) {
+ *pr_info("vp9 something error,need reset\n");
+ *}
+ */
+ }
+ }
+ }
+#ifdef MULTI_INSTANCE_SUPPORT
+ else {
+ if (
+ (decode_timeout_val > 0) &&
+ (pbi->start_process_time > 0) &&
+ ((1000 * (jiffies - pbi->start_process_time) / HZ)
+ > decode_timeout_val)
+ ) {
+ int current_lcu_idx =
+ READ_VREG(HEVC_PARSER_LCU_START)
+ & 0xffffff;
+ if (pbi->last_lcu_idx == current_lcu_idx) {
+ if (pbi->decode_timeout_count > 0)
+ pbi->decode_timeout_count--;
+ if (pbi->decode_timeout_count == 0) {
+ if (input_frame_based(
+ hw_to_vdec(pbi)) ||
+ (READ_VREG(HEVC_STREAM_LEVEL) > 0x200))
+ timeout_process(pbi);
+ else {
+ vp9_print(pbi, 0,
+ "timeout & empty, again\n");
+ dec_again_process(pbi);
+ }
+ }
+ } else {
+ start_process_time(pbi);
+ pbi->last_lcu_idx = current_lcu_idx;
+ }
+ }
+ }
+#endif
+
+ if ((pbi->ucode_pause_pos != 0) &&
+ (pbi->ucode_pause_pos != 0xffffffff) &&
+ udebug_pause_pos != pbi->ucode_pause_pos) {
+ pbi->ucode_pause_pos = 0;
+ WRITE_HREG(DEBUG_REG1, 0);
+ }
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (debug & VP9_DEBUG_FORCE_SEND_AGAIN) {
+ pr_info(
+ "Force Send Again\r\n");
+ debug &= ~VP9_DEBUG_FORCE_SEND_AGAIN;
+ reset_process_time(pbi);
+ pbi->dec_result = DEC_RESULT_AGAIN;
+ if (pbi->process_state ==
+ PROC_STATE_DECODESLICE) {
+ if (pbi->mmu_enable)
+ vp9_recycle_mmu_buf(pbi);
+ pbi->process_state =
+ PROC_STATE_SENDAGAIN;
+ }
+ amhevc_stop();
+
+ vdec_schedule_work(&pbi->work);
+ }
+
+ if (debug & VP9_DEBUG_DUMP_DATA) {
+ debug &= ~VP9_DEBUG_DUMP_DATA;
+ vp9_print(pbi, 0,
+ "%s: chunk size 0x%x off 0x%x sum 0x%x\n",
+ __func__,
+ pbi->chunk->size,
+ pbi->chunk->offset,
+ get_data_check_sum(pbi, pbi->chunk->size)
+ );
+ dump_data(pbi, pbi->chunk->size);
+ }
+#endif
+ if (debug & VP9_DEBUG_DUMP_PIC_LIST) {
+ dump_pic_list(pbi);
+ debug &= ~VP9_DEBUG_DUMP_PIC_LIST;
+ }
+ if (debug & VP9_DEBUG_TRIG_SLICE_SEGMENT_PROC) {
+ WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG, 0x1);
+ debug &= ~VP9_DEBUG_TRIG_SLICE_SEGMENT_PROC;
+ }
+ /*if (debug & VP9_DEBUG_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(pbi) == 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 (pbi->get_frame_dur && pbi->show_frame_num > 60 &&
+ pbi->frame_dur > 0 && pbi->saved_resolution !=
+ frame_width * frame_height *
+ (96000 / pbi->frame_dur))
+ vdec_schedule_work(&pbi->set_clk_work);
+
+ timer->expires = jiffies + PUT_INTERVAL;
+ add_timer(timer);
+}
+
+
+int vvp9_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus)
+{
+ struct VP9Decoder_s *vp9 =
+ (struct VP9Decoder_s *)vdec->private;
+
+ if (!vp9)
+ return -1;
+
+ vstatus->frame_width = frame_width;
+ vstatus->frame_height = frame_height;
+ if (vp9->error_frame_width &&
+ vp9->error_frame_height) {
+ vstatus->frame_width = vp9->error_frame_width;
+ vstatus->frame_height = vp9->error_frame_height;
+ }
+
+ if (vp9->frame_dur != 0)
+ vstatus->frame_rate = ((96000 * 10 / vp9->frame_dur) % 10) < 5 ?
+ 96000 / vp9->frame_dur : (96000 / vp9->frame_dur +1);
+ else
+ vstatus->frame_rate = -1;
+ vstatus->error_count = 0;
+ vstatus->status = vp9->stat | vp9->fatal_error;
+ vstatus->frame_dur = vp9->frame_dur;
+ vstatus->bit_rate = vp9->gvs->bit_rate;
+ vstatus->frame_data = vp9->gvs->frame_data;
+ vstatus->total_data = vp9->gvs->total_data;
+ vstatus->frame_count = vp9->gvs->frame_count;
+ vstatus->error_frame_count = vp9->gvs->error_frame_count;
+ vstatus->drop_frame_count = vp9->gvs->drop_frame_count;
+ vstatus->i_decoded_frames = vp9->gvs->i_decoded_frames;
+ vstatus->i_lost_frames = vp9->gvs->i_lost_frames;
+ vstatus->i_concealed_frames = vp9->gvs->i_concealed_frames;
+ vstatus->p_decoded_frames = vp9->gvs->p_decoded_frames;
+ vstatus->p_lost_frames = vp9->gvs->p_lost_frames;
+ vstatus->p_concealed_frames = vp9->gvs->p_concealed_frames;
+ vstatus->b_decoded_frames = vp9->gvs->b_decoded_frames;
+ vstatus->b_lost_frames = vp9->gvs->b_lost_frames;
+ vstatus->b_concealed_frames = vp9->gvs->b_concealed_frames;
+ vstatus->total_data = vp9->gvs->total_data;
+ vstatus->samp_cnt = vp9->gvs->samp_cnt;
+ vstatus->offset = vp9->gvs->offset;
+ snprintf(vstatus->vdec_name, sizeof(vstatus->vdec_name),
+ "%s", DRIVER_NAME);
+ return 0;
+}
+
+int vvp9_set_isreset(struct vdec_s *vdec, int isreset)
+{
+ is_reset = isreset;
+ return 0;
+}
+
+#if 0
+static void VP9_DECODE_INIT(void)
+{
+ /* enable vp9 clocks */
+ WRITE_VREG(DOS_GCLK_EN3, 0xffffffff);
+ /* *************************************************************** */
+ /* Power ON HEVC */
+ /* *************************************************************** */
+ /* Powerup HEVC */
+ WRITE_VREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_VREG(AO_RTI_GEN_PWR_SLEEP0) & (~(0x3 << 6)));
+ WRITE_VREG(DOS_MEM_PD_HEVC, 0x0);
+ WRITE_VREG(DOS_SW_RESET3, READ_VREG(DOS_SW_RESET3) | (0x3ffff << 2));
+ WRITE_VREG(DOS_SW_RESET3, READ_VREG(DOS_SW_RESET3) & (~(0x3ffff << 2)));
+ /* remove isolations */
+ WRITE_VREG(AO_RTI_GEN_PWR_ISO0,
+ READ_VREG(AO_RTI_GEN_PWR_ISO0) & (~(0x3 << 10)));
+
+}
+#endif
+
+static void vvp9_prot_init(struct VP9Decoder_s *pbi, u32 mask)
+{
+ unsigned int data32;
+ /* VP9_DECODE_INIT(); */
+ vp9_config_work_space_hw(pbi, mask);
+ if (mask & HW_MASK_BACK)
+ init_pic_list_hw(pbi);
+
+ vp9_init_decoder_hw(pbi, mask);
+
+#ifdef VP9_LPF_LVL_UPDATE
+ if (mask & HW_MASK_BACK)
+ vp9_loop_filter_init(pbi);
+#endif
+
+ if ((mask & HW_MASK_FRONT) == 0)
+ return;
+#if 1
+ if (debug & VP9_DEBUG_BUFMGR_MORE)
+ pr_info("%s\n", __func__);
+ data32 = READ_VREG(HEVC_STREAM_CONTROL);
+ data32 = data32 |
+ (1 << 0)/*stream_fetch_enable*/
+ ;
+ WRITE_VREG(HEVC_STREAM_CONTROL, data32);
+
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) {
+ if (debug & VP9_DEBUG_BUFMGR)
+ pr_info("[test.c] Config STREAM_FIFO_CTL\n");
+ data32 = READ_VREG(HEVC_STREAM_FIFO_CTL);
+ data32 = data32 |
+ (1 << 29) // stream_fifo_hole
+ ;
+ WRITE_VREG(HEVC_STREAM_FIFO_CTL, data32);
+ }
+#if 0
+ data32 = READ_VREG(HEVC_SHIFT_STARTCODE);
+ if (data32 != 0x00000100) {
+ pr_info("vp9 prot init error %d\n", __LINE__);
+ return;
+ }
+ data32 = READ_VREG(HEVC_SHIFT_EMULATECODE);
+ if (data32 != 0x00000300) {
+ pr_info("vp9 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("vp9 prot init error %d\n", __LINE__);
+ return;
+ }
+ data32 = READ_VREG(HEVC_SHIFT_EMULATECODE);
+ if (data32 != 0x9abcdef0) {
+ pr_info("vp9 prot init error %d\n", __LINE__);
+ return;
+ }
+#endif
+ WRITE_VREG(HEVC_SHIFT_STARTCODE, 0x000000001);
+ WRITE_VREG(HEVC_SHIFT_EMULATECODE, 0x00000300);
+#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);
+#ifdef SUPPORT_FB_DECODING
+#ifndef FB_DECODING_TEST_SCHEDULE
+ if (pbi->used_stage_buf_num > 0) {
+ if (mask & HW_MASK_FRONT) {
+ data32 = READ_VREG(
+ HEVC_ASSIST_HED_FB_W_CTL);
+ data32 = data32 |
+ (1 << 0) /*hed_fb_wr_en*/
+ ;
+ WRITE_VREG(HEVC_ASSIST_HED_FB_W_CTL,
+ data32);
+ }
+ if (mask & HW_MASK_BACK) {
+ data32 = READ_VREG(
+ HEVC_ASSIST_HED_FB_R_CTL);
+ while (data32 & (1 << 7)) {
+ /*wait finish*/
+ data32 = READ_VREG(
+ HEVC_ASSIST_HED_FB_R_CTL);
+ }
+ data32 &= (~(0x1 << 0));
+ /*hed_fb_rd_addr_auto_rd*/
+ data32 &= (~(0x1 << 1));
+ /*rd_id = 0, hed_rd_map_auto_halt_num,
+ after wr 2 ready, then start reading*/
+ data32 |= (0x2 << 16);
+ WRITE_VREG(HEVC_ASSIST_HED_FB_R_CTL,
+ data32);
+
+ data32 |= (0x1 << 11); /*hed_rd_map_auto_halt_en*/
+ data32 |= (0x1 << 1); /*hed_fb_rd_addr_auto_rd*/
+ data32 |= (0x1 << 0); /*hed_fb_rd_en*/
+ WRITE_VREG(HEVC_ASSIST_HED_FB_R_CTL,
+ data32);
+ }
+
+ }
+#endif
+#endif
+}
+
+static int vvp9_local_init(struct VP9Decoder_s *pbi)
+{
+ int i;
+ int ret;
+ int width, height;
+ if (alloc_lf_buf(pbi) < 0)
+ return -1;
+
+ pbi->gvs = vzalloc(sizeof(struct vdec_info));
+ if (NULL == pbi->gvs) {
+ pr_info("the struct of vdec status malloc failed.\n");
+ return -1;
+ }
+ vdec_set_vframe_comm(hw_to_vdec(pbi), DRIVER_NAME);
+#ifdef DEBUG_PTS
+ pbi->pts_missed = 0;
+ pbi->pts_hit = 0;
+#endif
+ pbi->new_frame_displayed = 0;
+ pbi->last_put_idx = -1;
+ pbi->saved_resolution = 0;
+ pbi->get_frame_dur = false;
+ on_no_keyframe_skiped = 0;
+ pbi->duration_from_pts_done = 0;
+ pbi->vp9_first_pts_ready = 0;
+ pbi->frame_cnt_window = 0;
+ width = pbi->vvp9_amstream_dec_info.width;
+ height = pbi->vvp9_amstream_dec_info.height;
+ pbi->frame_dur =
+ (pbi->vvp9_amstream_dec_info.rate ==
+ 0) ? 3200 : pbi->vvp9_amstream_dec_info.rate;
+ if (width && height)
+ pbi->frame_ar = height * 0x100 / width;
+/*
+ *TODO:FOR VERSION
+ */
+ pr_info("vp9: ver (%d,%d) decinfo: %dx%d rate=%d\n", vp9_version,
+ 0, width, height, pbi->frame_dur);
+
+ if (pbi->frame_dur == 0)
+ pbi->frame_dur = 96000 / 24;
+
+ INIT_KFIFO(pbi->display_q);
+ INIT_KFIFO(pbi->newframe_q);
+
+
+ for (i = 0; i < VF_POOL_SIZE; i++) {
+ const struct vframe_s *vf = &pbi->vfpool[i];
+
+ pbi->vfpool[i].index = -1;
+ kfifo_put(&pbi->newframe_q, vf);
+ }
+
+
+ ret = vp9_local_init(pbi);
+
+ if (!pbi->pts_unstable) {
+ pbi->pts_unstable =
+ (pbi->vvp9_amstream_dec_info.rate == 0)?1:0;
+ pr_info("set pts unstable\n");
+ }
+
+ return ret;
+}
+
+
+#ifdef MULTI_INSTANCE_SUPPORT
+static s32 vvp9_init(struct vdec_s *vdec)
+{
+ struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)vdec->private;
+#else
+static s32 vvp9_init(struct VP9Decoder_s *pbi)
+{
+#endif
+ int ret;
+ int fw_size = 0x1000 * 16;
+ struct firmware_s *fw = NULL;
+
+ pbi->stat |= STAT_TIMER_INIT;
+
+ if (vvp9_local_init(pbi) < 0)
+ return -EBUSY;
+
+ fw = vmalloc(sizeof(struct firmware_s) + fw_size);
+ if (IS_ERR_OR_NULL(fw))
+ return -ENOMEM;
+
+ if (get_firmware_data(VIDEO_DEC_VP9_MMU, fw->data) < 0) {
+ pr_err("get firmware fail.\n");
+ vfree(fw);
+ return -1;
+ }
+
+ fw->len = fw_size;
+
+ INIT_WORK(&pbi->set_clk_work, vp9_set_clk);
+ init_timer(&pbi->timer);
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (pbi->m_ins_flag) {
+ pbi->timer.data = (ulong) pbi;
+ pbi->timer.function = vvp9_put_timer_func;
+ pbi->timer.expires = jiffies + PUT_INTERVAL;
+
+ /*add_timer(&pbi->timer);
+
+ pbi->stat |= STAT_TIMER_ARM;
+ pbi->stat |= STAT_ISR_REG;*/
+
+ INIT_WORK(&pbi->work, vp9_work);
+ INIT_WORK(&pbi->recycle_mmu_work, vp9_recycle_mmu_work);
+#ifdef SUPPORT_FB_DECODING
+ if (pbi->used_stage_buf_num > 0)
+ INIT_WORK(&pbi->s1_work, vp9_s1_work);
+#endif
+ pbi->fw = fw;
+
+ /* picture list init.*/
+ pbi->dec_result = DEC_INIT_PICLIST;
+ vdec_schedule_work(&pbi->work);
+
+ return 0;
+ }
+#endif
+ amhevc_enable();
+
+ init_pic_list(pbi);
+
+ ret = amhevc_loadmc_ex(VFORMAT_VP9, NULL, fw->data);
+ if (ret < 0) {
+ amhevc_disable();
+ vfree(fw);
+ pr_err("VP9: the %s fw loading failed, err: %x\n",
+ tee_enabled() ? "TEE" : "local", ret);
+ return -EBUSY;
+ }
+
+ vfree(fw);
+
+ pbi->stat |= STAT_MC_LOAD;
+
+ /* enable AMRISC side protocol */
+ vvp9_prot_init(pbi, HW_MASK_FRONT | HW_MASK_BACK);
+
+ if (vdec_request_threaded_irq(VDEC_IRQ_0,
+ vvp9_isr,
+ vvp9_isr_thread_fn,
+ IRQF_ONESHOT,/*run thread on this irq disabled*/
+ "vvp9-irq", (void *)pbi)) {
+ pr_info("vvp9 irq register error.\n");
+ amhevc_disable();
+ return -ENOENT;
+ }
+
+ pbi->stat |= STAT_ISR_REG;
+
+ pbi->provider_name = PROVIDER_NAME;
+#ifdef MULTI_INSTANCE_SUPPORT
+ vf_provider_init(&vvp9_vf_prov, PROVIDER_NAME,
+ &vvp9_vf_provider, pbi);
+ vf_reg_provider(&vvp9_vf_prov);
+ vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_START, NULL);
+ if (pbi->frame_dur != 0) {
+ if (!is_reset)
+ vf_notify_receiver(pbi->provider_name,
+ VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)
+ ((unsigned long)pbi->frame_dur));
+ }
+#else
+ vf_provider_init(&vvp9_vf_prov, PROVIDER_NAME, &vvp9_vf_provider,
+ pbi);
+ vf_reg_provider(&vvp9_vf_prov);
+ vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_START, NULL);
+ if (!is_reset)
+ vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)((unsigned long)pbi->frame_dur));
+#endif
+ pbi->stat |= STAT_VF_HOOK;
+
+ pbi->timer.data = (ulong)pbi;
+ pbi->timer.function = vvp9_put_timer_func;
+ pbi->timer.expires = jiffies + PUT_INTERVAL;
+
+ pbi->stat |= STAT_VDEC_RUN;
+
+ add_timer(&pbi->timer);
+
+ pbi->stat |= STAT_TIMER_ARM;
+
+ amhevc_start();
+
+ pbi->init_flag = 1;
+ pbi->process_busy = 0;
+ pr_info("%d, vvp9_init, RP=0x%x\n",
+ __LINE__, READ_VREG(HEVC_STREAM_RD_PTR));
+ return 0;
+}
+
+static int vmvp9_stop(struct VP9Decoder_s *pbi)
+{
+ pbi->init_flag = 0;
+
+ if (pbi->stat & STAT_VDEC_RUN) {
+ amhevc_stop();
+ pbi->stat &= ~STAT_VDEC_RUN;
+ }
+ if (pbi->stat & STAT_ISR_REG) {
+ vdec_free_irq(VDEC_IRQ_0, (void *)pbi);
+ pbi->stat &= ~STAT_ISR_REG;
+ }
+ if (pbi->stat & STAT_TIMER_ARM) {
+ del_timer_sync(&pbi->timer);
+ pbi->stat &= ~STAT_TIMER_ARM;
+ }
+
+ if (pbi->stat & STAT_VF_HOOK) {
+ if (!is_reset)
+ vf_notify_receiver(pbi->provider_name,
+ VFRAME_EVENT_PROVIDER_FR_END_HINT,
+ NULL);
+
+ vf_unreg_provider(&vvp9_vf_prov);
+ pbi->stat &= ~STAT_VF_HOOK;
+ }
+ vp9_local_uninit(pbi);
+ reset_process_time(pbi);
+ cancel_work_sync(&pbi->work);
+ cancel_work_sync(&pbi->recycle_mmu_work);
+#ifdef SUPPORT_FB_DECODING
+ if (pbi->used_stage_buf_num > 0)
+ cancel_work_sync(&pbi->s1_work);
+#endif
+ cancel_work_sync(&pbi->set_clk_work);
+ uninit_mmu_buffers(pbi);
+ if (pbi->fw)
+ vfree(pbi->fw);
+ pbi->fw = NULL;
+ return 0;
+}
+
+static int vvp9_stop(struct VP9Decoder_s *pbi)
+{
+
+ pbi->init_flag = 0;
+ pbi->first_sc_checked = 0;
+ if (pbi->stat & STAT_VDEC_RUN) {
+ amhevc_stop();
+ pbi->stat &= ~STAT_VDEC_RUN;
+ }
+
+ if (pbi->stat & STAT_ISR_REG) {
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (!pbi->m_ins_flag)
+#endif
+ WRITE_VREG(HEVC_ASSIST_MBOX0_MASK, 0);
+ vdec_free_irq(VDEC_IRQ_0, (void *)pbi);
+ pbi->stat &= ~STAT_ISR_REG;
+ }
+
+ if (pbi->stat & STAT_TIMER_ARM) {
+ del_timer_sync(&pbi->timer);
+ pbi->stat &= ~STAT_TIMER_ARM;
+ }
+
+ if (pbi->stat & STAT_VF_HOOK) {
+ if (!is_reset)
+ vf_notify_receiver(pbi->provider_name,
+ VFRAME_EVENT_PROVIDER_FR_END_HINT,
+ NULL);
+
+ vf_unreg_provider(&vvp9_vf_prov);
+ pbi->stat &= ~STAT_VF_HOOK;
+ }
+ vp9_local_uninit(pbi);
+
+ cancel_work_sync(&pbi->set_clk_work);
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (pbi->m_ins_flag) {
+#ifdef SUPPORT_FB_DECODING
+ if (pbi->used_stage_buf_num > 0)
+ cancel_work_sync(&pbi->s1_work);
+#endif
+ cancel_work_sync(&pbi->work);
+ cancel_work_sync(&pbi->recycle_mmu_work);
+ } else
+ amhevc_disable();
+#else
+ amhevc_disable();
+#endif
+ uninit_mmu_buffers(pbi);
+
+ vfree(pbi->fw);
+ pbi->fw = NULL;
+ return 0;
+}
+static int amvdec_vp9_mmu_init(struct VP9Decoder_s *pbi)
+{
+ int tvp_flag = vdec_secure(hw_to_vdec(pbi)) ?
+ CODEC_MM_FLAGS_TVP : 0;
+ int buf_size = 48;
+
+ if ((pbi->max_pic_w * pbi->max_pic_h > 1280*736) &&
+ (pbi->max_pic_w * pbi->max_pic_h <= 1920*1088)) {
+ buf_size = 12;
+ } else if ((pbi->max_pic_w * pbi->max_pic_h > 0) &&
+ (pbi->max_pic_w * pbi->max_pic_h <= 1280*736)) {
+ buf_size = 4;
+ }
+ pbi->need_cache_size = buf_size * SZ_1M;
+ pbi->sc_start_time = get_jiffies_64();
+ if (pbi->mmu_enable && ((pbi->double_write_mode & 0x10) == 0)) {
+ pbi->mmu_box = decoder_mmu_box_alloc_box(DRIVER_NAME,
+ pbi->index, FRAME_BUFFERS,
+ pbi->need_cache_size,
+ tvp_flag
+ );
+ if (!pbi->mmu_box) {
+ pr_err("vp9 alloc mmu box failed!!\n");
+ return -1;
+ }
+ }
+ pbi->bmmu_box = decoder_bmmu_box_alloc_box(
+ DRIVER_NAME,
+ pbi->index,
+ MAX_BMMU_BUFFER_NUM,
+ 4 + PAGE_SHIFT,
+ CODEC_MM_FLAGS_CMA_CLEAR |
+ CODEC_MM_FLAGS_FOR_VDECODER |
+ tvp_flag);
+ if (!pbi->bmmu_box) {
+ pr_err("vp9 alloc bmmu box failed!!\n");
+ return -1;
+ }
+ return 0;
+}
+
+static struct VP9Decoder_s *gHevc;
+
+static int amvdec_vp9_probe(struct platform_device *pdev)
+{
+ struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
+ struct BUF_s BUF[MAX_BUF_NUM];
+ struct VP9Decoder_s *pbi;
+ int ret;
+#ifndef MULTI_INSTANCE_SUPPORT
+ int i;
+#endif
+ pr_debug("%s\n", __func__);
+
+ mutex_lock(&vvp9_mutex);
+ pbi = vmalloc(sizeof(struct VP9Decoder_s));
+ if (pbi == NULL) {
+ pr_info("\namvdec_vp9 device data allocation failed\n");
+ mutex_unlock(&vvp9_mutex);
+ return -ENOMEM;
+ }
+
+ gHevc = pbi;
+ memcpy(&BUF[0], &pbi->m_BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM);
+ memset(pbi, 0, sizeof(struct VP9Decoder_s));
+ memcpy(&pbi->m_BUF[0], &BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM);
+
+ pbi->init_flag = 0;
+ pbi->first_sc_checked= 0;
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) {
+ vp9_max_pic_w = 8192;
+ vp9_max_pic_h = 4608;
+ }
+ pbi->max_pic_w = vp9_max_pic_w;
+ pbi->max_pic_h = vp9_max_pic_h;
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ pbi->eos = 0;
+ pbi->start_process_time = 0;
+ pbi->timeout_num = 0;
+#endif
+ pbi->fatal_error = 0;
+ pbi->show_frame_num = 0;
+ if (pdata == NULL) {
+ pr_info("\namvdec_vp9 memory resource undefined.\n");
+ vfree(pbi);
+ mutex_unlock(&vvp9_mutex);
+ return -EFAULT;
+ }
+ pbi->m_ins_flag = 0;
+#ifdef MULTI_INSTANCE_SUPPORT
+ pbi->platform_dev = pdev;
+ platform_set_drvdata(pdev, pdata);
+#endif
+ pbi->double_write_mode = double_write_mode;
+ pbi->mmu_enable = 1;
+ if (amvdec_vp9_mmu_init(pbi) < 0) {
+ vfree(pbi);
+ mutex_unlock(&vvp9_mutex);
+ pr_err("vp9 alloc bmmu box failed!!\n");
+ return -1;
+ }
+
+ ret = decoder_bmmu_box_alloc_buf_phy(pbi->bmmu_box, WORK_SPACE_BUF_ID,
+ work_buf_size, DRIVER_NAME, &pdata->mem_start);
+ if (ret < 0) {
+ uninit_mmu_buffers(pbi);
+ vfree(pbi);
+ mutex_unlock(&vvp9_mutex);
+ return ret;
+ }
+ pbi->buf_size = work_buf_size;
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ pbi->buf_start = pdata->mem_start;
+#else
+ if (!pbi->mmu_enable)
+ pbi->mc_buf_spec.buf_end = pdata->mem_start + pbi->buf_size;
+
+ for (i = 0; i < WORK_BUF_SPEC_NUM; i++)
+ amvvp9_workbuff_spec[i].start_adr = pdata->mem_start;
+#endif
+
+
+ if (debug) {
+ pr_info("===VP9 decoder mem resource 0x%lx size 0x%x\n",
+ pdata->mem_start, pbi->buf_size);
+ }
+
+ if (pdata->sys_info)
+ pbi->vvp9_amstream_dec_info = *pdata->sys_info;
+ else {
+ pbi->vvp9_amstream_dec_info.width = 0;
+ pbi->vvp9_amstream_dec_info.height = 0;
+ pbi->vvp9_amstream_dec_info.rate = 30;
+ }
+ pbi->no_head = no_head;
+#ifdef MULTI_INSTANCE_SUPPORT
+ pbi->cma_dev = pdata->cma_dev;
+#else
+ cma_dev = pdata->cma_dev;
+#endif
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ pdata->private = pbi;
+ pdata->dec_status = vvp9_dec_status;
+ pdata->set_isreset = vvp9_set_isreset;
+ is_reset = 0;
+ if (vvp9_init(pdata) < 0) {
+#else
+ if (vvp9_init(pbi) < 0) {
+#endif
+ pr_info("\namvdec_vp9 init failed.\n");
+ vp9_local_uninit(pbi);
+ uninit_mmu_buffers(pbi);
+ vfree(pbi);
+ pdata->dec_status = NULL;
+ mutex_unlock(&vvp9_mutex);
+ return -ENODEV;
+ }
+ /*set the max clk for smooth playing...*/
+ hevc_source_changed(VFORMAT_VP9,
+ 4096, 2048, 60);
+ mutex_unlock(&vvp9_mutex);
+
+ return 0;
+}
+
+static void vdec_fence_release(struct VP9Decoder_s *pbi,
+ struct vdec_sync *sync)
+{
+ ulong expires;
+ int i;
+
+ /* 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;
+ }
+ }
+
+ for (i = 0; i < VF_POOL_SIZE; i++) {
+ struct vframe_s *vf = &pbi->vfpool[i];
+
+ if (vf->fence) {
+ vdec_fence_put(vf->fence);
+ vf->fence = NULL;
+ }
+ }
+
+ /* decreases refcnt of timeline. */
+ vdec_timeline_put(sync);
+}
+
+static int amvdec_vp9_remove(struct platform_device *pdev)
+{
+ struct VP9Decoder_s *pbi = gHevc;
+ struct vdec_s *vdec = hw_to_vdec(pbi);
+ int i;
+
+ if (debug)
+ pr_info("amvdec_vp9_remove\n");
+
+ mutex_lock(&vvp9_mutex);
+
+ vvp9_stop(pbi);
+
+ hevc_source_changed(VFORMAT_VP9, 0, 0, 0);
+
+ if (vdec->parallel_dec == 1) {
+ for (i = 0; i < FRAME_BUFFERS; i++) {
+ vdec->free_canvas_ex(pbi->common.buffer_pool->
+ frame_bufs[i].buf.y_canvas_index, vdec->id);
+ vdec->free_canvas_ex(pbi->common.buffer_pool->
+ frame_bufs[i].buf.uv_canvas_index, vdec->id);
+ }
+ }
+
+#ifdef DEBUG_PTS
+ pr_info("pts missed %ld, pts hit %ld, duration %d\n",
+ pbi->pts_missed, pbi->pts_hit, pbi->frame_dur);
+#endif
+ mem_map_mode = 0;
+
+ if (pbi->enable_fence)
+ vdec_fence_release(pbi, &vdec->sync);
+
+ vfree(pbi);
+ mutex_unlock(&vvp9_mutex);
+
+ return 0;
+}
+
+/****************************************/
+#ifdef CONFIG_PM
+static int vp9_suspend(struct device *dev)
+{
+ amhevc_suspend(to_platform_device(dev), dev->power.power_state);
+ return 0;
+}
+
+static int vp9_resume(struct device *dev)
+{
+ amhevc_resume(to_platform_device(dev));
+ return 0;
+}
+
+static const struct dev_pm_ops vp9_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(vp9_suspend, vp9_resume)
+};
+#endif
+
+static struct platform_driver amvdec_vp9_driver = {
+ .probe = amvdec_vp9_probe,
+ .remove = amvdec_vp9_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &vp9_pm_ops,
+#endif
+ }
+};
+
+static struct codec_profile_t amvdec_vp9_profile = {
+ .name = "vp9",
+ .profile = ""
+};
+
+static struct codec_profile_t amvdec_vp9_profile_mult;
+
+static unsigned char get_data_check_sum
+ (struct VP9Decoder_s *pbi, int size)
+{
+ int jj;
+ int sum = 0;
+ u8 *data = NULL;
+
+ if (!pbi->chunk->block->is_mapped)
+ data = codec_mm_vmap(pbi->chunk->block->start +
+ pbi->chunk->offset, size);
+ else
+ data = ((u8 *)pbi->chunk->block->start_virt) +
+ pbi->chunk->offset;
+
+ for (jj = 0; jj < size; jj++)
+ sum += data[jj];
+
+ if (!pbi->chunk->block->is_mapped)
+ codec_mm_unmap_phyaddr(data);
+ return sum;
+}
+
+static void dump_data(struct VP9Decoder_s *pbi, int size)
+{
+ int jj;
+ u8 *data = NULL;
+ int padding_size = pbi->chunk->offset &
+ (VDEC_FIFO_ALIGN - 1);
+
+ if (!pbi->chunk->block->is_mapped)
+ data = codec_mm_vmap(pbi->chunk->block->start +
+ pbi->chunk->offset, size);
+ else
+ data = ((u8 *)pbi->chunk->block->start_virt) +
+ pbi->chunk->offset;
+
+ vp9_print(pbi, 0, "padding: ");
+ for (jj = padding_size; jj > 0; jj--)
+ vp9_print_cont(pbi,
+ 0,
+ "%02x ", *(data - jj));
+ vp9_print_cont(pbi, 0, "data adr %p\n",
+ data);
+
+ for (jj = 0; jj < size; jj++) {
+ if ((jj & 0xf) == 0)
+ vp9_print(pbi,
+ 0,
+ "%06x:", jj);
+ vp9_print_cont(pbi,
+ 0,
+ "%02x ", data[jj]);
+ if (((jj + 1) & 0xf) == 0)
+ vp9_print(pbi,
+ 0,
+ "\n");
+ }
+ vp9_print(pbi,
+ 0,
+ "\n");
+
+ if (!pbi->chunk->block->is_mapped)
+ codec_mm_unmap_phyaddr(data);
+}
+
+static void vp9_work(struct work_struct *work)
+{
+ struct VP9Decoder_s *pbi = container_of(work,
+ struct VP9Decoder_s, work);
+ struct vdec_s *vdec = hw_to_vdec(pbi);
+ /* finished decoding one frame or error,
+ * notify vdec core to switch context
+ */
+ vp9_print(pbi, PRINT_FLAG_VDEC_DETAIL,
+ "%s dec_result %d %x %x %x\n",
+ __func__,
+ pbi->dec_result,
+ READ_VREG(HEVC_STREAM_LEVEL),
+ READ_VREG(HEVC_STREAM_WR_PTR),
+ READ_VREG(HEVC_STREAM_RD_PTR));
+
+ if (pbi->dec_result == DEC_INIT_PICLIST) {
+ init_pic_list(pbi);
+ pbi->pic_list_init_done = true;
+ return;
+ }
+
+ if (pbi->dec_result == DEC_RESULT_NEED_MORE_BUFFER) {
+ reset_process_time(pbi);
+ if (!get_free_buf_count(pbi)) {
+ pbi->process_busy = 0;
+ pbi->dec_result = DEC_RESULT_NEED_MORE_BUFFER;
+ vdec_schedule_work(&pbi->work);
+ } else {
+ int i;
+
+ if (pbi->mmu_enable)
+ vp9_recycle_mmu_buf_tail(pbi);
+
+ if (pbi->frame_count > 0)
+ vp9_bufmgr_postproc(pbi);
+
+ for (i = 0; i < (RPM_END - RPM_BEGIN); i += 4) {
+ int ii;
+ for (ii = 0; ii < 4; ii++)
+ pbi->vp9_param.l.data[i + ii] =
+ pbi->rpm_ptr[i + 3 - ii];
+ }
+ continue_decoding(pbi);
+ pbi->postproc_done = 0;
+ pbi->process_busy = 0;
+
+ start_process_time(pbi);
+ }
+ return;
+ }
+
+ if (((pbi->dec_result == DEC_RESULT_GET_DATA) ||
+ (pbi->dec_result == DEC_RESULT_GET_DATA_RETRY))
+ && (hw_to_vdec(pbi)->next_status !=
+ VDEC_STATUS_DISCONNECTED)) {
+ if (!vdec_has_more_input(vdec)) {
+ pbi->dec_result = DEC_RESULT_EOS;
+ vdec_schedule_work(&pbi->work);
+ return;
+ }
+
+ if (pbi->dec_result == DEC_RESULT_GET_DATA) {
+ vp9_print(pbi, 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, pbi->chunk);
+ vdec_clean_input(vdec);
+ }
+
+ if (get_free_buf_count(pbi) >=
+ pbi->run_ready_min_buf_num) {
+ int r;
+ int decode_size;
+ r = vdec_prepare_input(vdec, &pbi->chunk);
+ if (r < 0) {
+ pbi->dec_result = DEC_RESULT_GET_DATA_RETRY;
+
+ vp9_print(pbi,
+ PRINT_FLAG_VDEC_DETAIL,
+ "amvdec_vh265: Insufficient data\n");
+
+ vdec_schedule_work(&pbi->work);
+ return;
+ }
+ pbi->dec_result = DEC_RESULT_NONE;
+ vp9_print(pbi, PRINT_FLAG_VDEC_STATUS,
+ "%s: chunk size 0x%x sum 0x%x\n",
+ __func__, r,
+ (debug & PRINT_FLAG_VDEC_STATUS) ?
+ get_data_check_sum(pbi, r) : 0
+ );
+
+ if (debug & PRINT_FLAG_VDEC_DATA)
+ dump_data(pbi, pbi->chunk->size);
+
+ decode_size = pbi->chunk->size +
+ (pbi->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, HEVC_ACTION_DONE);
+
+ start_process_time(pbi);
+
+ } else{
+ pbi->dec_result = DEC_RESULT_GET_DATA_RETRY;
+
+ vp9_print(pbi, PRINT_FLAG_VDEC_DETAIL,
+ "amvdec_vh265: Insufficient data\n");
+
+ vdec_schedule_work(&pbi->work);
+ }
+ return;
+ } else if (pbi->dec_result == DEC_RESULT_DONE) {
+#ifdef SUPPORT_FB_DECODING
+ if (pbi->used_stage_buf_num > 0) {
+#ifndef FB_DECODING_TEST_SCHEDULE
+ if (!is_s2_decoding_finished(pbi)) {
+ vp9_print(pbi, PRINT_FLAG_VDEC_DETAIL,
+ "s2 decoding not done, check again later\n");
+ vdec_schedule_work(&pbi->work);
+ }
+#endif
+ inc_s2_pos(pbi);
+ if (mcrcc_cache_alg_flag)
+ dump_hit_rate(pbi);
+ }
+#endif
+ /* if (!pbi->ctx_valid)
+ pbi->ctx_valid = 1; */
+ pbi->slice_idx++;
+ pbi->frame_count++;
+ pbi->process_state = PROC_STATE_INIT;
+ decode_frame_count[pbi->index] = pbi->frame_count;
+
+ if (pbi->mmu_enable)
+ pbi->used_4k_num =
+ (READ_VREG(HEVC_SAO_MMU_STATUS) >> 16);
+ vp9_print(pbi, PRINT_FLAG_VDEC_STATUS,
+ "%s (===> %d) dec_result %d %x %x %x shiftbytes 0x%x decbytes 0x%x\n",
+ __func__,
+ pbi->frame_count,
+ pbi->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) -
+ pbi->start_shift_bytes
+ );
+ vdec_vframe_dirty(hw_to_vdec(pbi), pbi->chunk);
+ } else if (pbi->dec_result == DEC_RESULT_AGAIN) {
+ /*
+ stream base: stream buf empty or timeout
+ frame base: vdec_prepare_input fail
+ */
+ if (!vdec_has_more_input(vdec)) {
+ pbi->dec_result = DEC_RESULT_EOS;
+ vdec_schedule_work(&pbi->work);
+ return;
+ }
+ } else if (pbi->dec_result == DEC_RESULT_EOS) {
+ vp9_print(pbi, PRINT_FLAG_VDEC_STATUS,
+ "%s: end of stream\n",
+ __func__);
+ pbi->eos = 1;
+ vp9_bufmgr_postproc(pbi);
+
+ notify_v4l_eos(hw_to_vdec(pbi));
+
+ vdec_vframe_dirty(hw_to_vdec(pbi), pbi->chunk);
+ } else if (pbi->dec_result == DEC_RESULT_FORCE_EXIT) {
+ vp9_print(pbi, PRINT_FLAG_VDEC_STATUS,
+ "%s: force exit\n",
+ __func__);
+ if (pbi->stat & STAT_VDEC_RUN) {
+ amhevc_stop();
+ pbi->stat &= ~STAT_VDEC_RUN;
+ }
+
+ if (pbi->stat & STAT_ISR_REG) {
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (!pbi->m_ins_flag)
+#endif
+ WRITE_VREG(HEVC_ASSIST_MBOX0_MASK, 0);
+ vdec_free_irq(VDEC_IRQ_0, (void *)pbi);
+ pbi->stat &= ~STAT_ISR_REG;
+ }
+ }
+ if (pbi->stat & STAT_VDEC_RUN) {
+ amhevc_stop();
+ pbi->stat &= ~STAT_VDEC_RUN;
+ }
+
+ if (pbi->stat & STAT_TIMER_ARM) {
+ del_timer_sync(&pbi->timer);
+ pbi->stat &= ~STAT_TIMER_ARM;
+ }
+ /* mark itself has all HW resource released and input released */
+#ifdef SUPPORT_FB_DECODING
+ if (pbi->used_stage_buf_num > 0)
+ vdec_core_finish_run(hw_to_vdec(pbi), CORE_MASK_HEVC_BACK);
+ else
+ vdec_core_finish_run(hw_to_vdec(pbi), CORE_MASK_VDEC_1
+ | CORE_MASK_HEVC
+ | CORE_MASK_HEVC_FRONT
+ | CORE_MASK_HEVC_BACK
+ );
+#else
+ if (vdec->parallel_dec == 1)
+ vdec_core_finish_run(vdec, CORE_MASK_HEVC);
+ else
+ vdec_core_finish_run(hw_to_vdec(pbi), CORE_MASK_VDEC_1
+ | CORE_MASK_HEVC);
+#endif
+ trigger_schedule(pbi);
+}
+
+static int vp9_hw_ctx_restore(struct VP9Decoder_s *pbi)
+{
+ /* new to do ... */
+#if (!defined SUPPORT_FB_DECODING)
+ vvp9_prot_init(pbi, HW_MASK_FRONT | HW_MASK_BACK);
+#elif (defined FB_DECODING_TEST_SCHEDULE)
+ vvp9_prot_init(pbi, HW_MASK_FRONT | HW_MASK_BACK);
+#else
+ if (pbi->used_stage_buf_num > 0)
+ vvp9_prot_init(pbi, HW_MASK_FRONT);
+ else
+ vvp9_prot_init(pbi, HW_MASK_FRONT | HW_MASK_BACK);
+#endif
+ return 0;
+}
+static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask)
+{
+ struct VP9Decoder_s *pbi =
+ (struct VP9Decoder_s *)vdec->private;
+ int tvp = vdec_secure(hw_to_vdec(pbi)) ?
+ CODEC_MM_FLAGS_TVP : 0;
+ unsigned long ret = 0;
+
+ if (!(pbi->pic_list_init_done && pbi->pic_list_init_done2) || pbi->eos)
+ return ret;
+ if (!pbi->first_sc_checked && pbi->mmu_enable) {
+ int size = decoder_mmu_box_sc_check(pbi->mmu_box, tvp);
+ pbi->first_sc_checked = 1;
+ vp9_print(pbi, 0, "vp9 cached=%d need_size=%d speed= %d ms\n",
+ size, (pbi->need_cache_size >> PAGE_SHIFT),
+ (int)(get_jiffies_64() - pbi->sc_start_time) * 1000/HZ);
+ }
+
+#ifdef SUPPORT_FB_DECODING
+ if (pbi->used_stage_buf_num > 0) {
+ if (mask & CORE_MASK_HEVC_FRONT) {
+ if (get_free_stage_buf_num(pbi) > 0
+ && mv_buf_available(pbi))
+ ret |= CORE_MASK_HEVC_FRONT;
+ }
+ if (mask & CORE_MASK_HEVC_BACK) {
+ if (s2_buf_available(pbi) &&
+ (get_free_buf_count(pbi) >=
+ pbi->run_ready_min_buf_num)) {
+ ret |= CORE_MASK_HEVC_BACK;
+ pbi->back_not_run_ready = 0;
+ } else
+ pbi->back_not_run_ready = 1;
+#if 0
+ if (get_free_buf_count(pbi) <
+ run_ready_min_buf_num)
+ dump_pic_list(pbi);
+#endif
+ }
+ } else if (get_free_buf_count(pbi) >=
+ pbi->run_ready_min_buf_num)
+ ret = CORE_MASK_VDEC_1 | CORE_MASK_HEVC
+ | CORE_MASK_HEVC_FRONT
+ | CORE_MASK_HEVC_BACK;
+
+ if (ret & CORE_MASK_HEVC_FRONT)
+ not_run_ready[pbi->index] = 0;
+ else
+ not_run_ready[pbi->index]++;
+
+ if (ret & CORE_MASK_HEVC_BACK)
+ not_run2_ready[pbi->index] = 0;
+ else
+ not_run2_ready[pbi->index]++;
+
+ vp9_print(pbi,
+ PRINT_FLAG_VDEC_DETAIL, "%s mask %lx=>%lx (%d %d %d %d)\r\n",
+ __func__, mask, ret,
+ get_free_stage_buf_num(pbi),
+ mv_buf_available(pbi),
+ s2_buf_available(pbi),
+ get_free_buf_count(pbi)
+ );
+
+ return ret;
+
+#else
+ if (get_free_buf_count(pbi) >=
+ pbi->run_ready_min_buf_num) {
+ if (vdec->parallel_dec == 1)
+ ret = CORE_MASK_HEVC;
+ else
+ ret = CORE_MASK_VDEC_1 | CORE_MASK_HEVC;
+ }
+
+ if (pbi->is_used_v4l) {
+ struct aml_vcodec_ctx *ctx =
+ (struct aml_vcodec_ctx *)(pbi->v4l2_ctx);
+
+ if (ctx->param_sets_from_ucode) {
+ if (pbi->v4l_params_parsed) {
+ if ((ctx->cap_pool.in < pbi->used_buf_num) &&
+ v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) <
+ pbi->run_ready_min_buf_num)
+ ret = 0;
+ } else {
+ if (ctx->v4l_resolution_change)
+ ret = 0;
+ }
+ } else if (ctx->cap_pool.in < ctx->dpb_size) {
+ if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) <
+ pbi->run_ready_min_buf_num)
+ ret = 0;
+ }
+ }
+
+ if (ret)
+ not_run_ready[pbi->index] = 0;
+ else
+ not_run_ready[pbi->index]++;
+
+ vp9_print(pbi,
+ PRINT_FLAG_VDEC_DETAIL, "%s mask %lx=>%lx\r\n",
+ __func__, mask, ret);
+ return ret;
+#endif
+}
+
+static void vp9_frame_mode_pts_save(struct VP9Decoder_s *pbi)
+{
+ int i = 0;
+
+ if (pbi->chunk == NULL)
+ return;
+ vp9_print(pbi, VP9_DEBUG_OUT_PTS,
+ "run front: pts %d, pts64 %lld\n", pbi->chunk->pts, pbi->chunk->pts64);
+ for (i = (FRAME_BUFFERS - 1); i > 0; i--) {
+ pbi->frame_mode_pts_save[i] = pbi->frame_mode_pts_save[i - 1];
+ pbi->frame_mode_pts64_save[i] = pbi->frame_mode_pts64_save[i - 1];
+ }
+ pbi->frame_mode_pts_save[0] = pbi->chunk->pts;
+ pbi->frame_mode_pts64_save[0] = pbi->chunk->pts64;
+}
+
+static void run_front(struct vdec_s *vdec)
+{
+ struct VP9Decoder_s *pbi =
+ (struct VP9Decoder_s *)vdec->private;
+ int ret, size;
+
+ run_count[pbi->index]++;
+ /* pbi->chunk = vdec_prepare_input(vdec); */
+#if (!defined SUPPORT_FB_DECODING)
+ hevc_reset_core(vdec);
+#elif (defined FB_DECODING_TEST_SCHEDULE)
+ hevc_reset_core(vdec);
+#else
+ if (pbi->used_stage_buf_num > 0)
+ fb_reset_core(vdec, HW_MASK_FRONT);
+ else
+ hevc_reset_core(vdec);
+#endif
+
+ size = vdec_prepare_input(vdec, &pbi->chunk);
+ if (size < 0) {
+ input_empty[pbi->index]++;
+
+ pbi->dec_result = DEC_RESULT_AGAIN;
+
+ vp9_print(pbi, PRINT_FLAG_VDEC_DETAIL,
+ "ammvdec_vh265: Insufficient data\n");
+
+ vdec_schedule_work(&pbi->work);
+ return;
+ }
+
+ input_empty[pbi->index] = 0;
+ pbi->dec_result = DEC_RESULT_NONE;
+ pbi->start_shift_bytes = READ_VREG(HEVC_SHIFT_BYTE_COUNT);
+
+ vp9_frame_mode_pts_save(pbi);
+
+ if (debug & PRINT_FLAG_VDEC_STATUS) {
+ int ii;
+ vp9_print(pbi, 0,
+ "%s (%d): size 0x%x (0x%x 0x%x) sum 0x%x (%x %x %x %x %x) bytes 0x%x",
+ __func__,
+ pbi->frame_count, size,
+ pbi->chunk ? pbi->chunk->size : 0,
+ pbi->chunk ? pbi->chunk->offset : 0,
+ pbi->chunk ? ((vdec_frame_based(vdec) &&
+ (debug & PRINT_FLAG_VDEC_STATUS)) ?
+ get_data_check_sum(pbi, size) : 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),
+ pbi->start_shift_bytes);
+ if (vdec_frame_based(vdec) && pbi->chunk) {
+ u8 *data = NULL;
+
+ if (!pbi->chunk->block->is_mapped)
+ data = codec_mm_vmap(pbi->chunk->block->start +
+ pbi->chunk->offset, 8);
+ else
+ data = ((u8 *)pbi->chunk->block->start_virt) +
+ pbi->chunk->offset;
+
+ vp9_print_cont(pbi, 0, "data adr %p:",
+ data);
+ for (ii = 0; ii < 8; ii++)
+ vp9_print_cont(pbi, 0, "%02x ",
+ data[ii]);
+
+ if (!pbi->chunk->block->is_mapped)
+ codec_mm_unmap_phyaddr(data);
+ }
+ vp9_print_cont(pbi, 0, "\r\n");
+ }
+ if (vdec->mc_loaded) {
+ /*firmware have load before,
+ and not changes to another.
+ ignore reload.
+ */
+ } else {
+ ret = amhevc_loadmc_ex(VFORMAT_VP9, NULL, pbi->fw->data);
+ if (ret < 0) {
+ amhevc_disable();
+ vp9_print(pbi, PRINT_FLAG_ERROR,
+ "VP9: the %s fw loading failed, err: %x\n",
+ tee_enabled() ? "TEE" : "local", ret);
+ pbi->dec_result = DEC_RESULT_FORCE_EXIT;
+ vdec_schedule_work(&pbi->work);
+ return;
+ }
+ vdec->mc_loaded = 1;
+ vdec->mc_type = VFORMAT_VP9;
+ }
+
+ if (vp9_hw_ctx_restore(pbi) < 0) {
+ vdec_schedule_work(&pbi->work);
+ return;
+ }
+
+ vdec_enable_input(vdec);
+
+ WRITE_VREG(HEVC_DEC_STATUS_REG, HEVC_ACTION_DONE);
+
+ if (vdec_frame_based(vdec)) {
+ if (debug & PRINT_FLAG_VDEC_DATA)
+ dump_data(pbi, pbi->chunk->size);
+
+ WRITE_VREG(HEVC_SHIFT_BYTE_COUNT, 0);
+ size = pbi->chunk->size +
+ (pbi->chunk->offset & (VDEC_FIFO_ALIGN - 1));
+ if (vdec->mvfrm)
+ vdec->mvfrm->frame_size = pbi->chunk->size;
+ }
+ WRITE_VREG(HEVC_DECODE_SIZE, size);
+ WRITE_VREG(HEVC_DECODE_COUNT, pbi->slice_idx);
+ pbi->init_flag = 1;
+
+ vp9_print(pbi, 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(pbi);
+ mod_timer(&pbi->timer, jiffies);
+ pbi->stat |= STAT_TIMER_ARM;
+ pbi->stat |= STAT_ISR_REG;
+ amhevc_start();
+ pbi->stat |= STAT_VDEC_RUN;
+}
+
+#ifdef SUPPORT_FB_DECODING
+static void mpred_process(struct VP9Decoder_s *pbi)
+{
+ union param_u *params = &pbi->s1_param;
+ unsigned char use_prev_frame_mvs =
+ !params->p.error_resilient_mode &&
+ params->p.width == pbi->s1_width &&
+ params->p.height == pbi->s1_height &&
+ !pbi->s1_intra_only &&
+ pbi->s1_last_show_frame &&
+ (pbi->s1_frame_type != KEY_FRAME);
+ pbi->s1_width = params->p.width;
+ pbi->s1_height = params->p.height;
+ pbi->s1_frame_type = params->p.frame_type;
+ pbi->s1_intra_only =
+ (params->p.show_frame ||
+ params->p.show_existing_frame)
+ ? 0 : params->p.intra_only;
+ if ((pbi->s1_frame_type != KEY_FRAME)
+ && (!pbi->s1_intra_only)) {
+ unsigned int data32;
+ int mpred_mv_rd_end_addr;
+
+ mpred_mv_rd_end_addr =
+ pbi->s1_mpred_mv_wr_start_addr_pre
+ + (pbi->lcu_total * MV_MEM_UNIT);
+
+ WRITE_VREG(HEVC_MPRED_CTRL3, 0x24122412);
+ WRITE_VREG(HEVC_MPRED_ABV_START_ADDR,
+ pbi->work_space_buf->
+ mpred_above.buf_start);
+
+ data32 = READ_VREG(HEVC_MPRED_CTRL4);
+
+ data32 &= (~(1 << 6));
+ data32 |= (use_prev_frame_mvs << 6);
+ WRITE_VREG(HEVC_MPRED_CTRL4, data32);
+
+ WRITE_VREG(HEVC_MPRED_MV_WR_START_ADDR,
+ pbi->s1_mpred_mv_wr_start_addr);
+ WRITE_VREG(HEVC_MPRED_MV_WPTR,
+ pbi->s1_mpred_mv_wr_start_addr);
+
+ WRITE_VREG(HEVC_MPRED_MV_RD_START_ADDR,
+ pbi->s1_mpred_mv_wr_start_addr_pre);
+ WRITE_VREG(HEVC_MPRED_MV_RPTR,
+ pbi->s1_mpred_mv_wr_start_addr_pre);
+
+ WRITE_VREG(HEVC_MPRED_MV_RD_END_ADDR,
+ mpred_mv_rd_end_addr);
+
+ } else
+ clear_mpred_hw(pbi);
+
+ if (!params->p.show_existing_frame) {
+ pbi->s1_mpred_mv_wr_start_addr_pre =
+ pbi->s1_mpred_mv_wr_start_addr;
+ pbi->s1_last_show_frame =
+ params->p.show_frame;
+ if (pbi->s1_mv_buf_index_pre_pre != MV_BUFFER_NUM)
+ put_mv_buf(pbi, &pbi->s1_mv_buf_index_pre_pre);
+ pbi->s1_mv_buf_index_pre_pre =
+ pbi->s1_mv_buf_index_pre;
+ pbi->s1_mv_buf_index_pre = pbi->s1_mv_buf_index;
+ } else
+ put_mv_buf(pbi, &pbi->s1_mv_buf_index);
+}
+
+static void vp9_s1_work(struct work_struct *s1_work)
+{
+ struct VP9Decoder_s *pbi = container_of(s1_work,
+ struct VP9Decoder_s, s1_work);
+ vp9_print(pbi, PRINT_FLAG_VDEC_DETAIL,
+ "%s dec_s1_result %d\n",
+ __func__,
+ pbi->dec_s1_result);
+
+#ifdef FB_DECODING_TEST_SCHEDULE
+ if (pbi->dec_s1_result ==
+ DEC_S1_RESULT_TEST_TRIGGER_DONE) {
+ pbi->s1_test_cmd = TEST_SET_PIC_DONE;
+ WRITE_VREG(HEVC_ASSIST_MBOX0_IRQ_REG, 0x1);
+ }
+#endif
+ if (pbi->dec_s1_result == DEC_S1_RESULT_DONE ||
+ pbi->dec_s1_result == DEC_S1_RESULT_FORCE_EXIT) {
+
+ vdec_core_finish_run(hw_to_vdec(pbi),
+ CORE_MASK_HEVC_FRONT);
+
+ trigger_schedule(pbi);
+ /*pbi->dec_s1_result = DEC_S1_RESULT_NONE;*/
+ }
+
+}
+
+static void run_back(struct vdec_s *vdec)
+{
+ struct VP9Decoder_s *pbi =
+ (struct VP9Decoder_s *)vdec->private;
+ int i;
+ run2_count[pbi->index]++;
+ if (debug & PRINT_FLAG_VDEC_STATUS) {
+ vp9_print(pbi, 0,
+ "%s", __func__);
+ }
+ pbi->run2_busy = 1;
+#ifndef FB_DECODING_TEST_SCHEDULE
+ fb_reset_core(vdec, HW_MASK_BACK);
+
+ vvp9_prot_init(pbi, HW_MASK_BACK);
+#endif
+ vp9_recycle_mmu_buf_tail(pbi);
+
+ if (pbi->frame_count > 0)
+ vp9_bufmgr_postproc(pbi);
+
+ if (get_s2_buf(pbi) >= 0) {
+ for (i = 0; i < (RPM_END - RPM_BEGIN); i += 4) {
+ int ii;
+ for (ii = 0; ii < 4; ii++)
+ pbi->vp9_param.l.data[i + ii] =
+ pbi->s2_buf->rpm[i + 3 - ii];
+ }
+#ifndef FB_DECODING_TEST_SCHEDULE
+ WRITE_VREG(HEVC_ASSIST_FBD_MMU_MAP_ADDR,
+ pbi->stage_mmu_map_phy_addr +
+ pbi->s2_buf->index * STAGE_MMU_MAP_SIZE);
+#endif
+ continue_decoding(pbi);
+ }
+ pbi->run2_busy = 0;
+}
+#endif
+
+static void run(struct vdec_s *vdec, unsigned long mask,
+ void (*callback)(struct vdec_s *, void *), void *arg)
+{
+ struct VP9Decoder_s *pbi =
+ (struct VP9Decoder_s *)vdec->private;
+
+ vp9_print(pbi,
+ PRINT_FLAG_VDEC_DETAIL, "%s mask %lx\r\n",
+ __func__, mask);
+
+ if (vdec->mvfrm)
+ vdec->mvfrm->hw_decode_start = local_clock();
+ run_count[pbi->index]++;
+ pbi->vdec_cb_arg = arg;
+ pbi->vdec_cb = callback;
+ pbi->one_package_frame_cnt = 0;
+#ifdef SUPPORT_FB_DECODING
+ if ((mask & CORE_MASK_HEVC) ||
+ (mask & CORE_MASK_HEVC_FRONT))
+ run_front(vdec);
+
+ if ((pbi->used_stage_buf_num > 0)
+ && (mask & CORE_MASK_HEVC_BACK))
+ run_back(vdec);
+#else
+ run_front(vdec);
+#endif
+
+}
+
+static void init_frame_bufs(struct VP9Decoder_s *pbi)
+{
+ struct vdec_s *vdec = hw_to_vdec(pbi);
+ struct VP9_Common_s *const cm = &pbi->common;
+ struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs;
+ int i;
+
+ for (i = 0; i < pbi->used_buf_num; ++i) {
+ frame_bufs[i].ref_count = 0;
+ frame_bufs[i].buf.vf_ref = 0;
+ frame_bufs[i].buf.decode_idx = 0;
+ frame_bufs[i].buf.cma_alloc_addr = 0;
+ frame_bufs[i].buf.index = i;
+ frame_bufs[i].buf.vframe_bound = 0;
+ }
+
+ if (vdec->parallel_dec == 1) {
+ for (i = 0; i < FRAME_BUFFERS; i++) {
+ vdec->free_canvas_ex
+ (pbi->common.buffer_pool->frame_bufs[i].buf.y_canvas_index,
+ vdec->id);
+ vdec->free_canvas_ex
+ (pbi->common.buffer_pool->frame_bufs[i].buf.uv_canvas_index,
+ vdec->id);
+ }
+ }
+}
+
+static void reset(struct vdec_s *vdec)
+{
+ struct VP9Decoder_s *pbi =
+ (struct VP9Decoder_s *)vdec->private;
+
+ cancel_work_sync(&pbi->work);
+ if (pbi->stat & STAT_VDEC_RUN) {
+ amhevc_stop();
+ pbi->stat &= ~STAT_VDEC_RUN;
+ }
+
+ if (pbi->stat & STAT_TIMER_ARM) {
+ del_timer_sync(&pbi->timer);
+ pbi->stat &= ~STAT_TIMER_ARM;
+ }
+ pbi->dec_result = DEC_RESULT_NONE;
+ reset_process_time(pbi);
+ vp9_local_uninit(pbi);
+ if (vvp9_local_init(pbi) < 0)
+ vp9_print(pbi, 0, "%s local_init failed \r\n", __func__);
+ init_frame_bufs(pbi);
+
+ pbi->eos = 0;
+
+ vp9_print(pbi, PRINT_FLAG_VDEC_DETAIL, "%s\r\n", __func__);
+}
+
+static irqreturn_t vp9_irq_cb(struct vdec_s *vdec, int irq)
+{
+ struct VP9Decoder_s *pbi =
+ (struct VP9Decoder_s *)vdec->private;
+ return vvp9_isr(0, pbi);
+}
+
+static irqreturn_t vp9_threaded_irq_cb(struct vdec_s *vdec, int irq)
+{
+ struct VP9Decoder_s *pbi =
+ (struct VP9Decoder_s *)vdec->private;
+ return vvp9_isr_thread_fn(0, pbi);
+}
+
+static void vp9_dump_state(struct vdec_s *vdec)
+{
+ struct VP9Decoder_s *pbi =
+ (struct VP9Decoder_s *)vdec->private;
+ struct VP9_Common_s *const cm = &pbi->common;
+ int i;
+ vp9_print(pbi, 0, "====== %s\n", __func__);
+
+ vp9_print(pbi, 0,
+ "width/height (%d/%d), used_buf_num %d video_signal_type 0x%x\n",
+ cm->width,
+ cm->height,
+ pbi->used_buf_num,
+ pbi->video_signal_type
+ );
+
+ vp9_print(pbi, 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 low_latency %d no_head %d \n",
+ input_frame_based(vdec),
+ pbi->eos,
+ pbi->dec_result,
+ decode_frame_count[pbi->index],
+ display_frame_count[pbi->index],
+ run_count[pbi->index],
+ not_run_ready[pbi->index],
+ input_empty[pbi->index],
+ pbi->low_latency_flag,
+ pbi->no_head
+ );
+
+ 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);
+ vp9_print(pbi, 0,
+ "\nreceiver(%s) state %d\n",
+ vdec->vf_provider_name,
+ state);
+ }
+
+ vp9_print(pbi, 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(&pbi->newframe_q),
+ VF_POOL_SIZE,
+ kfifo_len(&pbi->display_q),
+ VF_POOL_SIZE,
+ pbi->vf_pre_count,
+ pbi->vf_get_count,
+ pbi->vf_put_count,
+ get_free_buf_count(pbi),
+ pbi->run_ready_min_buf_num
+ );
+
+ dump_pic_list(pbi);
+
+ for (i = 0; i < MAX_BUF_NUM; i++) {
+ vp9_print(pbi, 0,
+ "mv_Buf(%d) start_adr 0x%lx size 0x%x used %d\n",
+ i,
+ pbi->m_mv_BUF[i].start_adr,
+ pbi->m_mv_BUF[i].size,
+ pbi->m_mv_BUF[i].used_flag);
+ }
+
+ vp9_print(pbi, 0,
+ "HEVC_DEC_STATUS_REG=0x%x\n",
+ READ_VREG(HEVC_DEC_STATUS_REG));
+ vp9_print(pbi, 0,
+ "HEVC_MPC_E=0x%x\n",
+ READ_VREG(HEVC_MPC_E));
+ vp9_print(pbi, 0,
+ "DECODE_MODE=0x%x\n",
+ READ_VREG(DECODE_MODE));
+ vp9_print(pbi, 0,
+ "NAL_SEARCH_CTL=0x%x\n",
+ READ_VREG(NAL_SEARCH_CTL));
+ vp9_print(pbi, 0,
+ "HEVC_PARSER_LCU_START=0x%x\n",
+ READ_VREG(HEVC_PARSER_LCU_START));
+ vp9_print(pbi, 0,
+ "HEVC_DECODE_SIZE=0x%x\n",
+ READ_VREG(HEVC_DECODE_SIZE));
+ vp9_print(pbi, 0,
+ "HEVC_SHIFT_BYTE_COUNT=0x%x\n",
+ READ_VREG(HEVC_SHIFT_BYTE_COUNT));
+ vp9_print(pbi, 0,
+ "HEVC_STREAM_START_ADDR=0x%x\n",
+ READ_VREG(HEVC_STREAM_START_ADDR));
+ vp9_print(pbi, 0,
+ "HEVC_STREAM_END_ADDR=0x%x\n",
+ READ_VREG(HEVC_STREAM_END_ADDR));
+ vp9_print(pbi, 0,
+ "HEVC_STREAM_LEVEL=0x%x\n",
+ READ_VREG(HEVC_STREAM_LEVEL));
+ vp9_print(pbi, 0,
+ "HEVC_STREAM_WR_PTR=0x%x\n",
+ READ_VREG(HEVC_STREAM_WR_PTR));
+ vp9_print(pbi, 0,
+ "HEVC_STREAM_RD_PTR=0x%x\n",
+ READ_VREG(HEVC_STREAM_RD_PTR));
+ vp9_print(pbi, 0,
+ "PARSER_VIDEO_RP=0x%x\n",
+ STBUF_READ(&vdec->vbuf, get_rp));
+ vp9_print(pbi, 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 (pbi->chunk && pbi->chunk->block &&
+ pbi->chunk->size > 0) {
+ u8 *data = NULL;
+
+ if (!pbi->chunk->block->is_mapped)
+ data = codec_mm_vmap(
+ pbi->chunk->block->start +
+ pbi->chunk->offset,
+ pbi->chunk->size);
+ else
+ data = ((u8 *)pbi->chunk->block->start_virt)
+ + pbi->chunk->offset;
+ vp9_print(pbi, 0,
+ "frame data size 0x%x\n",
+ pbi->chunk->size);
+ for (jj = 0; jj < pbi->chunk->size; jj++) {
+ if ((jj & 0xf) == 0)
+ vp9_print(pbi, 0,
+ "%06x:", jj);
+ vp9_print_cont(pbi, 0,
+ "%02x ", data[jj]);
+ if (((jj + 1) & 0xf) == 0)
+ vp9_print_cont(pbi, 0,
+ "\n");
+ }
+
+ if (!pbi->chunk->block->is_mapped)
+ codec_mm_unmap_phyaddr(data);
+ }
+ }
+
+}
+
+static int ammvdec_vp9_probe(struct platform_device *pdev)
+{
+ struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
+ int ret;
+ int config_val;
+ int transfer_val;
+ struct vframe_content_light_level_s content_light_level;
+ struct vframe_master_display_colour_s vf_dp;
+
+ struct BUF_s BUF[MAX_BUF_NUM];
+ struct VP9Decoder_s *pbi = NULL;
+ pr_debug("%s\n", __func__);
+
+ if (pdata == NULL) {
+ pr_info("\nammvdec_vp9 memory resource undefined.\n");
+ return -EFAULT;
+ }
+ /*pbi = (struct VP9Decoder_s *)devm_kzalloc(&pdev->dev,
+ sizeof(struct VP9Decoder_s), GFP_KERNEL);*/
+ memset(&vf_dp, 0, sizeof(struct vframe_master_display_colour_s));
+ pbi = vmalloc(sizeof(struct VP9Decoder_s));
+ if (pbi == NULL) {
+ pr_info("\nammvdec_vp9 device data allocation failed\n");
+ return -ENOMEM;
+ }
+ memset(pbi, 0, sizeof(struct VP9Decoder_s));
+
+ /* the ctx from v4l2 driver. */
+ pbi->v4l2_ctx = pdata->private;
+
+ pdata->private = pbi;
+ pdata->dec_status = vvp9_dec_status;
+ /* pdata->set_trickmode = set_trickmode; */
+ pdata->run_ready = run_ready;
+ pdata->run = run;
+ pdata->reset = reset;
+ pdata->irq_handler = vp9_irq_cb;
+ pdata->threaded_irq_handler = vp9_threaded_irq_cb;
+ pdata->dump_state = vp9_dump_state;
+
+ memcpy(&BUF[0], &pbi->m_BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM);
+ memcpy(&pbi->m_BUF[0], &BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM);
+
+ pbi->index = pdev->id;
+
+ snprintf(pbi->vdec_name, sizeof(pbi->vdec_name),
+ "vp9-%d", pbi->index);
+ snprintf(pbi->pts_name, sizeof(pbi->pts_name),
+ "%s-pts", pbi->vdec_name);
+ snprintf(pbi->new_q_name, sizeof(pbi->new_q_name),
+ "%s-newframe_q", pbi->vdec_name);
+ snprintf(pbi->disp_q_name, sizeof(pbi->disp_q_name),
+ "%s-dispframe_q", pbi->vdec_name);
+
+ if (pdata->use_vfm_path)
+ snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE,
+ VFM_DEC_PROVIDER_NAME);
+ 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,
+ &vvp9_vf_provider, pbi);
+
+ pbi->provider_name = pdata->vf_provider_name;
+ platform_set_drvdata(pdev, pdata);
+
+ pbi->platform_dev = pdev;
+ pbi->video_signal_type = 0;
+ pbi->m_ins_flag = 1;
+ if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_TXLX)
+ pbi->stat |= VP9_TRIGGER_FRAME_ENABLE;
+
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) {
+ pbi->max_pic_w = 8192;
+ pbi->max_pic_h = 4608;
+ } else {
+ pbi->max_pic_w = 4096;
+ pbi->max_pic_h = 2304;
+ }
+#if 1
+ if ((debug & IGNORE_PARAM_FROM_CONFIG) == 0 &&
+ pdata->config_len) {
+#ifdef MULTI_INSTANCE_SUPPORT
+ int vp9_buf_width = 0;
+ int vp9_buf_height = 0;
+ /*use ptr config for doubel_write_mode, etc*/
+ vp9_print(pbi, 0, "pdata->config=%s\n", pdata->config);
+ if (get_config_int(pdata->config, "vp9_double_write_mode",
+ &config_val) == 0)
+ pbi->double_write_mode = config_val;
+ else
+ pbi->double_write_mode = double_write_mode;
+
+ if (get_config_int(pdata->config, "save_buffer_mode",
+ &config_val) == 0)
+ pbi->save_buffer_mode = config_val;
+ else
+ pbi->save_buffer_mode = 0;
+ if (get_config_int(pdata->config, "vp9_buf_width",
+ &config_val) == 0) {
+ vp9_buf_width = config_val;
+ }
+ if (get_config_int(pdata->config, "vp9_buf_height",
+ &config_val) == 0) {
+ vp9_buf_height = config_val;
+ }
+
+ if (get_config_int(pdata->config, "no_head",
+ &config_val) == 0)
+ pbi->no_head = config_val;
+ else
+ pbi->no_head = no_head;
+
+ /*use ptr config for max_pic_w, etc*/
+ if (get_config_int(pdata->config, "vp9_max_pic_w",
+ &config_val) == 0) {
+ pbi->max_pic_w = config_val;
+ }
+ if (get_config_int(pdata->config, "vp9_max_pic_h",
+ &config_val) == 0) {
+ pbi->max_pic_h = config_val;
+ }
+ if ((pbi->max_pic_w * pbi->max_pic_h)
+ < (vp9_buf_width * vp9_buf_height)) {
+ pbi->max_pic_w = vp9_buf_width;
+ pbi->max_pic_h = vp9_buf_height;
+ vp9_print(pbi, 0, "use buf resolution\n");
+ }
+
+ if (get_config_int(pdata->config, "sidebind_type",
+ &config_val) == 0)
+ pbi->sidebind_type = config_val;
+
+ if (get_config_int(pdata->config, "sidebind_channel_id",
+ &config_val) == 0)
+ pbi->sidebind_channel_id = config_val;
+
+ if (get_config_int(pdata->config,
+ "parm_v4l_codec_enable",
+ &config_val) == 0)
+ pbi->is_used_v4l = config_val;
+
+ if (get_config_int(pdata->config,
+ "parm_v4l_buffer_margin",
+ &config_val) == 0)
+ pbi->dynamic_buf_num_margin = config_val;
+
+ if (get_config_int(pdata->config,
+ "parm_v4l_canvas_mem_mode",
+ &config_val) == 0)
+ pbi->mem_map_mode = config_val;
+
+ if (get_config_int(pdata->config,
+ "parm_enable_fence",
+ &config_val) == 0)
+ pbi->enable_fence = config_val;
+
+ if (get_config_int(pdata->config,
+ "parm_fence_usage",
+ &config_val) == 0)
+ pbi->fence_usage = config_val;
+
+ if (get_config_int(pdata->config,
+ "parm_v4l_low_latency_mode",
+ &config_val) == 0)
+ pbi->low_latency_flag = config_val;
+#endif
+ 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);
+
+ get_config_int(pdata->config, "mTransfer",
+ &transfer_val);
+
+ if (transfer_val == 0)
+ transfer_val = 16;
+
+ vp9_print(pbi, 0, "transfer_val=%d\n",transfer_val);
+
+ vf_dp.content_light_level = content_light_level;
+ pbi->video_signal_type = (1 << 29)
+ | (5 << 26) /* unspecified */
+ | (0 << 25) /* limit */
+ | (1 << 24) /* color available */
+ | (9 << 16) /* 2020 */
+ | (transfer_val << 8) /* 2084 */
+ | (9 << 0); /* 2020 */
+ }
+ pbi->vf_dp = vf_dp;
+ } else
+#endif
+ {
+ if (pdata->sys_info) {
+ pbi->vvp9_amstream_dec_info = *pdata->sys_info;
+ if ((pbi->vvp9_amstream_dec_info.width != 0) &&
+ (pbi->vvp9_amstream_dec_info.height != 0)) {
+ pbi->max_pic_w = pbi->vvp9_amstream_dec_info.width;
+ pbi->max_pic_h = pbi->vvp9_amstream_dec_info.height;
+ }
+ }
+ /*pbi->vvp9_amstream_dec_info.width = 0;
+ pbi->vvp9_amstream_dec_info.height = 0;
+ pbi->vvp9_amstream_dec_info.rate = 30;*/
+ pbi->double_write_mode = double_write_mode;
+ }
+
+ if (no_head & 0x10) {
+ pbi->no_head = (no_head & 0xf);
+ }
+
+ if (!pbi->is_used_v4l) {
+ pbi->mem_map_mode = mem_map_mode;
+ }
+ pbi->run_ready_min_buf_num = run_ready_min_buf_num;
+ if (is_oversize(pbi->max_pic_w, pbi->max_pic_h)) {
+ pr_err("over size: %dx%d, probe failed\n",
+ pbi->max_pic_w, pbi->max_pic_h);
+ return -1;
+ }
+
+ if (force_config_fence) {
+ pbi->enable_fence = true;
+ pbi->fence_usage =
+ (force_config_fence >> 4) & 0xf;
+ if (force_config_fence & 0x2)
+ pbi->enable_fence = false;
+ vp9_print(pbi, 0, "enable fence: %d, fence usage: %d\n",
+ pbi->enable_fence, pbi->fence_usage);
+ }
+
+ if (pbi->enable_fence)
+ pdata->sync.usage = pbi->fence_usage;
+
+ pbi->mmu_enable = 1;
+ video_signal_type = pbi->video_signal_type;
+
+ if (pdata->sys_info) {
+ pbi->vvp9_amstream_dec_info = *pdata->sys_info;
+ } else {
+ pbi->vvp9_amstream_dec_info.width = 0;
+ pbi->vvp9_amstream_dec_info.height = 0;
+ pbi->vvp9_amstream_dec_info.rate = 30;
+ }
+
+ pbi->low_latency_flag = 1;
+ vp9_print(pbi, 0,
+ "no_head %d low_latency %d\n",
+ pbi->no_head, pbi->low_latency_flag);
+#if 0
+ pbi->buf_start = pdata->mem_start;
+ pbi->buf_size = pdata->mem_end - pdata->mem_start + 1;
+#else
+ if (amvdec_vp9_mmu_init(pbi) < 0) {
+ pr_err("vp9 alloc bmmu box failed!!\n");
+ /* devm_kfree(&pdev->dev, (void *)pbi); */
+ vfree((void *)pbi);
+ pdata->dec_status = NULL;
+ return -1;
+ }
+
+ pbi->cma_alloc_count = PAGE_ALIGN(work_buf_size) / PAGE_SIZE;
+ ret = decoder_bmmu_box_alloc_buf_phy(pbi->bmmu_box, WORK_SPACE_BUF_ID,
+ pbi->cma_alloc_count * PAGE_SIZE, DRIVER_NAME,
+ &pbi->cma_alloc_addr);
+ if (ret < 0) {
+ uninit_mmu_buffers(pbi);
+ /* devm_kfree(&pdev->dev, (void *)pbi); */
+ vfree((void *)pbi);
+ pdata->dec_status = NULL;
+ return ret;
+ }
+ pbi->buf_start = pbi->cma_alloc_addr;
+ pbi->buf_size = work_buf_size;
+#endif
+
+ pbi->init_flag = 0;
+ pbi->first_sc_checked = 0;
+ pbi->fatal_error = 0;
+ pbi->show_frame_num = 0;
+
+ if (debug) {
+ pr_info("===VP9 decoder mem resource 0x%lx size 0x%x\n",
+ pbi->buf_start,
+ pbi->buf_size);
+ }
+
+ pbi->cma_dev = pdata->cma_dev;
+ if (vvp9_init(pdata) < 0) {
+ pr_info("\namvdec_vp9 init failed.\n");
+ vp9_local_uninit(pbi);
+ uninit_mmu_buffers(pbi);
+ /* devm_kfree(&pdev->dev, (void *)pbi); */
+ vfree((void *)pbi);
+ pdata->dec_status = NULL;
+ return -ENODEV;
+ }
+ vdec_set_prepare_level(pdata, start_decode_buf_level);
+ hevc_source_changed(VFORMAT_VP9,
+ 4096, 2048, 60);
+#ifdef SUPPORT_FB_DECODING
+ if (pbi->used_stage_buf_num > 0)
+ vdec_core_request(pdata,
+ CORE_MASK_HEVC_FRONT | CORE_MASK_HEVC_BACK);
+ else
+ vdec_core_request(pdata, CORE_MASK_VDEC_1 | CORE_MASK_HEVC
+ | CORE_MASK_HEVC_FRONT | CORE_MASK_HEVC_BACK
+ | CORE_MASK_COMBINE);
+#else
+ 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);
+#endif
+ pbi->pic_list_init_done2 = true;
+
+ if (pbi->enable_fence) {
+ /* creat timeline. */
+ vdec_timeline_create(&pdata->sync, DRIVER_NAME);
+ }
+
+ return 0;
+}
+
+static int ammvdec_vp9_remove(struct platform_device *pdev)
+{
+ struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)
+ (((struct vdec_s *)(platform_get_drvdata(pdev)))->private);
+ struct vdec_s *vdec = hw_to_vdec(pbi);
+ int i;
+ if (debug)
+ pr_info("amvdec_vp9_remove\n");
+
+ vmvp9_stop(pbi);
+
+#ifdef SUPPORT_FB_DECODING
+ vdec_core_release(hw_to_vdec(pbi), CORE_MASK_VDEC_1 | CORE_MASK_HEVC
+ | CORE_MASK_HEVC_FRONT | CORE_MASK_HEVC_BACK
+ );
+#else
+ if (vdec->parallel_dec == 1)
+ vdec_core_release(hw_to_vdec(pbi), CORE_MASK_HEVC);
+ else
+ vdec_core_release(hw_to_vdec(pbi), CORE_MASK_VDEC_1 | CORE_MASK_HEVC);
+#endif
+ vdec_set_status(hw_to_vdec(pbi), VDEC_STATUS_DISCONNECTED);
+
+ if (vdec->parallel_dec == 1) {
+ for (i = 0; i < FRAME_BUFFERS; i++) {
+ vdec->free_canvas_ex
+ (pbi->common.buffer_pool->frame_bufs[i].buf.y_canvas_index,
+ vdec->id);
+ vdec->free_canvas_ex
+ (pbi->common.buffer_pool->frame_bufs[i].buf.uv_canvas_index,
+ vdec->id);
+ }
+ }
+
+ if (pbi->enable_fence)
+ vdec_fence_release(pbi, &vdec->sync);
+
+#ifdef DEBUG_PTS
+ pr_info("pts missed %ld, pts hit %ld, duration %d\n",
+ pbi->pts_missed, pbi->pts_hit, pbi->frame_dur);
+#endif
+ mem_map_mode = 0;
+
+ /* devm_kfree(&pdev->dev, (void *)pbi); */
+ vfree((void *)pbi);
+ return 0;
+}
+
+static struct platform_driver ammvdec_vp9_driver = {
+ .probe = ammvdec_vp9_probe,
+ .remove = ammvdec_vp9_remove,
+ .driver = {
+ .name = MULTI_DRIVER_NAME,
+#ifdef CONFIG_PM
+ .pm = &vp9_pm_ops,
+#endif
+ }
+};
+#endif
+static struct mconfig vp9_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),
+ MC_PU32("vp9_max_pic_w", &vp9_max_pic_w),
+ MC_PU32("vp9_max_pic_h", &vp9_max_pic_h),
+};
+static struct mconfig_node vp9_node;
+
+static int __init amvdec_vp9_driver_init_module(void)
+{
+
+ struct BuffInfo_s *p_buf_info;
+
+ if (vdec_is_support_4k()) {
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1)
+ p_buf_info = &amvvp9_workbuff_spec[2];
+ else
+ p_buf_info = &amvvp9_workbuff_spec[1];
+ } else
+ p_buf_info = &amvvp9_workbuff_spec[0];
+
+ init_buff_spec(NULL, p_buf_info);
+ work_buf_size =
+ (p_buf_info->end_adr - p_buf_info->start_adr
+ + 0xffff) & (~0xffff);
+
+ pr_debug("amvdec_vp9 module init\n");
+
+ error_handle_policy = 0;
+
+#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;
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (platform_driver_register(&ammvdec_vp9_driver))
+ pr_err("failed to register ammvdec_vp9 driver\n");
+
+#endif
+ if (platform_driver_register(&amvdec_vp9_driver)) {
+ pr_err("failed to register amvdec_vp9 driver\n");
+ return -ENODEV;
+ }
+
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) {
+ amvdec_vp9_profile.profile =
+ "8k, 10bit, dwrite, compressed, fence";
+ } else if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL
+ /*&& get_cpu_major_id() != MESON_CPU_MAJOR_ID_GXLX*/
+ && get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TXL) {
+ if (vdec_is_support_4k())
+ amvdec_vp9_profile.profile =
+ "4k, 10bit, dwrite, compressed, fence";
+ else
+ amvdec_vp9_profile.profile =
+ "10bit, dwrite, compressed, fence";
+ } else {
+ amvdec_vp9_profile.name = "vp9_unsupport";
+ }
+
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
+ max_buf_num = MAX_BUF_NUM_LESS;
+
+ vcodec_profile_register(&amvdec_vp9_profile);
+ amvdec_vp9_profile_mult = amvdec_vp9_profile;
+ amvdec_vp9_profile_mult.name = "mvp9";
+ vcodec_profile_register(&amvdec_vp9_profile_mult);
+ INIT_REG_NODE_CONFIGS("media.decoder", &vp9_node,
+ "vp9", vp9_configs, CONFIG_FOR_RW);
+
+ return 0;
+}
+
+static void __exit amvdec_vp9_driver_remove_module(void)
+{
+ pr_debug("amvdec_vp9 module remove.\n");
+#ifdef MULTI_INSTANCE_SUPPORT
+ platform_driver_unregister(&ammvdec_vp9_driver);
+#endif
+ platform_driver_unregister(&amvdec_vp9_driver);
+}
+
+/****************************************/
+
+module_param(bit_depth_luma, uint, 0664);
+MODULE_PARM_DESC(bit_depth_luma, "\n amvdec_vp9 bit_depth_luma\n");
+
+module_param(bit_depth_chroma, uint, 0664);
+MODULE_PARM_DESC(bit_depth_chroma, "\n amvdec_vp9 bit_depth_chroma\n");
+
+module_param(frame_width, uint, 0664);
+MODULE_PARM_DESC(frame_width, "\n amvdec_vp9 frame_width\n");
+
+module_param(frame_height, uint, 0664);
+MODULE_PARM_DESC(frame_height, "\n amvdec_vp9 frame_height\n");
+
+module_param(debug, uint, 0664);
+MODULE_PARM_DESC(debug, "\n amvdec_vp9 debug\n");
+
+module_param(radr, uint, 0664);
+MODULE_PARM_DESC(radr, "\n radr\n");
+
+module_param(rval, uint, 0664);
+MODULE_PARM_DESC(rval, "\n rval\n");
+
+module_param(pop_shorts, uint, 0664);
+MODULE_PARM_DESC(pop_shorts, "\n rval\n");
+
+module_param(dbg_cmd, uint, 0664);
+MODULE_PARM_DESC(dbg_cmd, "\n dbg_cmd\n");
+
+module_param(dbg_skip_decode_index, uint, 0664);
+MODULE_PARM_DESC(dbg_skip_decode_index, "\n dbg_skip_decode_index\n");
+
+module_param(endian, uint, 0664);
+MODULE_PARM_DESC(endian, "\n rval\n");
+
+module_param(step, uint, 0664);
+MODULE_PARM_DESC(step, "\n amvdec_vp9 step\n");
+
+module_param(decode_pic_begin, uint, 0664);
+MODULE_PARM_DESC(decode_pic_begin, "\n amvdec_vp9 decode_pic_begin\n");
+
+module_param(slice_parse_begin, uint, 0664);
+MODULE_PARM_DESC(slice_parse_begin, "\n amvdec_vp9 slice_parse_begin\n");
+
+module_param(i_only_flag, uint, 0664);
+MODULE_PARM_DESC(i_only_flag, "\n amvdec_vp9 i_only_flag\n");
+
+module_param(low_latency_flag, uint, 0664);
+MODULE_PARM_DESC(low_latency_flag, "\n amvdec_vp9 low_latency_flag\n");
+
+module_param(no_head, uint, 0664);
+MODULE_PARM_DESC(no_head, "\n amvdec_vp9 no_head\n");
+
+module_param(error_handle_policy, uint, 0664);
+MODULE_PARM_DESC(error_handle_policy, "\n amvdec_vp9 error_handle_policy\n");
+
+module_param(buf_alloc_width, uint, 0664);
+MODULE_PARM_DESC(buf_alloc_width, "\n buf_alloc_width\n");
+
+module_param(buf_alloc_height, uint, 0664);
+MODULE_PARM_DESC(buf_alloc_height, "\n buf_alloc_height\n");
+
+module_param(buf_alloc_depth, uint, 0664);
+MODULE_PARM_DESC(buf_alloc_depth, "\n buf_alloc_depth\n");
+
+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");
+
+module_param(mv_buf_margin, uint, 0664);
+MODULE_PARM_DESC(mv_buf_margin, "\n mv_buf_margin\n");
+
+module_param(mv_buf_dynamic_alloc, uint, 0664);
+MODULE_PARM_DESC(mv_buf_dynamic_alloc, "\n mv_buf_dynamic_alloc\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");
+
+#ifdef SUPPORT_10BIT
+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");
+#endif
+
+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(mcrcc_cache_alg_flag, uint, 0664);
+MODULE_PARM_DESC(mcrcc_cache_alg_flag, "\n mcrcc_cache_alg_flag\n");
+
+#ifdef MULTI_INSTANCE_SUPPORT
+module_param(start_decode_buf_level, int, 0664);
+MODULE_PARM_DESC(start_decode_buf_level,
+ "\n vp9 start_decode_buf_level\n");
+
+module_param(decode_timeout_val, uint, 0664);
+MODULE_PARM_DESC(decode_timeout_val,
+ "\n vp9 decode_timeout_val\n");
+
+module_param(vp9_max_pic_w, uint, 0664);
+MODULE_PARM_DESC(vp9_max_pic_w, "\n vp9_max_pic_w\n");
+
+module_param(vp9_max_pic_h, uint, 0664);
+MODULE_PARM_DESC(vp9_max_pic_h, "\n vp9_max_pic_h\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);
+#endif
+
+#ifdef SUPPORT_FB_DECODING
+module_param_array(not_run2_ready, uint,
+ &max_decode_instance_num, 0664);
+
+module_param_array(run2_count, uint,
+ &max_decode_instance_num, 0664);
+
+module_param(stage_buf_num, uint, 0664);
+MODULE_PARM_DESC(stage_buf_num, "\n amvdec_h265 stage_buf_num\n");
+#endif
+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(without_display_mode, uint, 0664);
+MODULE_PARM_DESC(without_display_mode, "\n without_display_mode\n");
+
+module_param(force_config_fence, uint, 0664);
+MODULE_PARM_DESC(force_config_fence, "\n force enable fence\n");
+
+module_param(force_pts_unstable, uint, 0664);
+MODULE_PARM_DESC(force_pts_unstable, "\n force_pts_unstable\n");
+
+module_init(amvdec_vp9_driver_init_module);
+module_exit(amvdec_vp9_driver_remove_module);
+
+MODULE_DESCRIPTION("AMLOGIC vp9 Video Decoder Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/frame_provider/decoder/vp9/vvp9.h b/drivers/frame_provider/decoder/vp9/vvp9.h
new file mode 100644
index 0000000..1db9d09
--- /dev/null
+++ b/drivers/frame_provider/decoder/vp9/vvp9.h
@@ -0,0 +1,23 @@
+/*
+ * drivers/amlogic/amports/vvp9.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 VVP9_H
+#define VVP9_H
+
+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_sink/Makefile b/drivers/frame_sink/Makefile
new file mode 100644
index 0000000..2b9754a
--- /dev/null
+++ b/drivers/frame_sink/Makefile
@@ -0,0 +1 @@
+obj-y += encoder/
diff --git a/drivers/frame_sink/encoder/Makefile b/drivers/frame_sink/encoder/Makefile
new file mode 100644
index 0000000..214c6c1
--- /dev/null
+++ b/drivers/frame_sink/encoder/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_AMLOGIC_MEDIA_VENC_H264) += h264/
+obj-$(CONFIG_AMLOGIC_MEDIA_VENC_H265) += h265/
+obj-$(CONFIG_AMLOGIC_MEDIA_VENC_JPEG) += jpeg/
\ No newline at end of file
diff --git a/drivers/frame_sink/encoder/h264/Makefile b/drivers/frame_sink/encoder/h264/Makefile
new file mode 100644
index 0000000..c12d7c3
--- /dev/null
+++ b/drivers/frame_sink/encoder/h264/Makefile
@@ -0,0 +1 @@
+obj-m += encoder.o
diff --git a/drivers/frame_sink/encoder/h264/encoder.c b/drivers/frame_sink/encoder/h264/encoder.c
new file mode 100644
index 0000000..9421b93
--- /dev/null
+++ b/drivers/frame_sink/encoder/h264/encoder.c
@@ -0,0 +1,4896 @@
+/*
+ * drivers/amlogic/amports/encoder.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 LOG_LINE() pr_err("[%s:%d]\n", __FUNCTION__, __LINE__);
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/clk.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/reset.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/ctype.h>
+#include <linux/amlogic/media/frame_sync/ptsserv.h>
+#include <linux/amlogic/media/utils/amstream.h>
+#include <linux/amlogic/media/canvas/canvas.h>
+#include <linux/amlogic/media/canvas/canvas_mgr.h>
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "../../../frame_provider/decoder/utils/vdec.h"
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/dma-contiguous.h>
+#include <linux/kthread.h>
+#include <linux/sched/rt.h>
+#include <linux/amlogic/media/utils/amports_config.h>
+#include "encoder.h"
+#include "../../../frame_provider/decoder/utils/amvdec.h"
+#include "../../../frame_provider/decoder/utils/vdec_power_ctrl.h"
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include <linux/amlogic/power_ctrl.h>
+#include <dt-bindings/power/sc2-pd.h>
+#include <linux/amlogic/pwr_ctrl.h>
+
+#include <linux/amlogic/media/utils/amlog.h>
+#include "../../../stream_input/amports/amports_priv.h"
+#include "../../../frame_provider/decoder/utils/firmware.h"
+#include <linux/of_reserved_mem.h>
+
+
+#ifdef CONFIG_AM_JPEG_ENCODER
+#include "jpegenc.h"
+#endif
+
+#define MHz (1000000)
+
+#define CHECK_RET(_ret) if (ret) {enc_pr(LOG_ERROR, \
+ "%s:%d:function call failed with result: %d\n",\
+ __FUNCTION__, __LINE__, _ret);}
+
+#define ENCODE_NAME "encoder"
+#define AMVENC_CANVAS_INDEX 0xE4
+#define AMVENC_CANVAS_MAX_INDEX 0xEF
+
+#define MIN_SIZE amvenc_buffspec[0].min_buffsize
+#define DUMP_INFO_BYTES_PER_MB 80
+
+#define ADJUSTED_QP_FLAG 64
+
+static s32 avc_device_major;
+static struct device *amvenc_avc_dev;
+#define DRIVER_NAME "amvenc_avc"
+#define CLASS_NAME "amvenc_avc"
+#define DEVICE_NAME "amvenc_avc"
+
+static struct encode_manager_s encode_manager;
+
+#define MULTI_SLICE_MC
+#define H264_ENC_CBR
+/* #define MORE_MODULE_PARAM */
+
+#define ENC_CANVAS_OFFSET AMVENC_CANVAS_INDEX
+
+#define UCODE_MODE_FULL 0
+
+/* #define ENABLE_IGNORE_FUNCTION */
+
+static u32 ie_me_mb_type;
+static u32 ie_me_mode;
+static u32 ie_pippeline_block = 3;
+static u32 ie_cur_ref_sel;
+/* static u32 avc_endian = 6; */
+static u32 clock_level = 5;
+
+static u32 encode_print_level = LOG_DEBUG;
+static u32 no_timeout;
+static int nr_mode = -1;
+static u32 qp_table_debug;
+static u32 use_reset_control;
+static u32 use_ge2d;
+
+#ifdef H264_ENC_SVC
+static u32 svc_enable = 0; /* Enable sac feature or not */
+static u32 svc_ref_conf = 0; /* Continuous no reference numbers */
+#endif
+
+struct hcodec_clks {
+ struct clk *hcodec_aclk;
+ //struct clk *hcodec_bclk;
+ //struct clk *hcodec_cclk;
+};
+
+static struct hcodec_clks s_hcodec_clks;
+struct reset_control *hcodec_rst;
+
+static u32 me_mv_merge_ctl =
+ (0x1 << 31) | /* [31] me_merge_mv_en_16 */
+ (0x1 << 30) | /* [30] me_merge_small_mv_en_16 */
+ (0x1 << 29) | /* [29] me_merge_flex_en_16 */
+ (0x1 << 28) | /* [28] me_merge_sad_en_16 */
+ (0x1 << 27) | /* [27] me_merge_mv_en_8 */
+ (0x1 << 26) | /* [26] me_merge_small_mv_en_8 */
+ (0x1 << 25) | /* [25] me_merge_flex_en_8 */
+ (0x1 << 24) | /* [24] me_merge_sad_en_8 */
+ /* [23:18] me_merge_mv_diff_16 - MV diff <= n pixel can be merged */
+ (0x12 << 18) |
+ /* [17:12] me_merge_mv_diff_8 - MV diff <= n pixel can be merged */
+ (0x2b << 12) |
+ /* [11:0] me_merge_min_sad - SAD >= 0x180 can be merged with other MV */
+ (0x80 << 0);
+ /* ( 0x4 << 18) |
+ * // [23:18] me_merge_mv_diff_16 - MV diff <= n pixel can be merged
+ */
+ /* ( 0x3f << 12) |
+ * // [17:12] me_merge_mv_diff_8 - MV diff <= n pixel can be merged
+ */
+ /* ( 0xc0 << 0);
+ * // [11:0] me_merge_min_sad - SAD >= 0x180 can be merged with other MV
+ */
+
+static u32 me_mv_weight_01 = (0x40 << 24) | (0x30 << 16) | (0x20 << 8) | 0x30;
+static u32 me_mv_weight_23 = (0x40 << 8) | 0x30;
+static u32 me_sad_range_inc = 0x03030303;
+static u32 me_step0_close_mv = 0x003ffc21;
+static u32 me_f_skip_sad;
+static u32 me_f_skip_weight;
+static u32 me_sad_enough_01;/* 0x00018010; */
+static u32 me_sad_enough_23;/* 0x00000020; */
+
+/* [31:0] NUM_ROWS_PER_SLICE_P */
+/* [15:0] NUM_ROWS_PER_SLICE_I */
+static u32 fixed_slice_cfg;
+
+/* y tnr */
+static unsigned int y_tnr_mc_en = 1;
+static unsigned int y_tnr_txt_mode;
+static unsigned int y_tnr_mot_sad_margin = 1;
+static unsigned int y_tnr_mot_cortxt_rate = 1;
+static unsigned int y_tnr_mot_distxt_ofst = 5;
+static unsigned int y_tnr_mot_distxt_rate = 4;
+static unsigned int y_tnr_mot_dismot_ofst = 4;
+static unsigned int y_tnr_mot_frcsad_lock = 8;
+static unsigned int y_tnr_mot2alp_frc_gain = 10;
+static unsigned int y_tnr_mot2alp_nrm_gain = 216;
+static unsigned int y_tnr_mot2alp_dis_gain = 128;
+static unsigned int y_tnr_mot2alp_dis_ofst = 32;
+static unsigned int y_tnr_alpha_min = 32;
+static unsigned int y_tnr_alpha_max = 63;
+static unsigned int y_tnr_deghost_os;
+/* c tnr */
+static unsigned int c_tnr_mc_en = 1;
+static unsigned int c_tnr_txt_mode;
+static unsigned int c_tnr_mot_sad_margin = 1;
+static unsigned int c_tnr_mot_cortxt_rate = 1;
+static unsigned int c_tnr_mot_distxt_ofst = 5;
+static unsigned int c_tnr_mot_distxt_rate = 4;
+static unsigned int c_tnr_mot_dismot_ofst = 4;
+static unsigned int c_tnr_mot_frcsad_lock = 8;
+static unsigned int c_tnr_mot2alp_frc_gain = 10;
+static unsigned int c_tnr_mot2alp_nrm_gain = 216;
+static unsigned int c_tnr_mot2alp_dis_gain = 128;
+static unsigned int c_tnr_mot2alp_dis_ofst = 32;
+static unsigned int c_tnr_alpha_min = 32;
+static unsigned int c_tnr_alpha_max = 63;
+static unsigned int c_tnr_deghost_os;
+/* y snr */
+static unsigned int y_snr_err_norm = 1;
+static unsigned int y_snr_gau_bld_core = 1;
+static int y_snr_gau_bld_ofst = -1;
+static unsigned int y_snr_gau_bld_rate = 48;
+static unsigned int y_snr_gau_alp0_min;
+static unsigned int y_snr_gau_alp0_max = 63;
+static unsigned int y_bld_beta2alp_rate = 16;
+static unsigned int y_bld_beta_min;
+static unsigned int y_bld_beta_max = 63;
+/* c snr */
+static unsigned int c_snr_err_norm = 1;
+static unsigned int c_snr_gau_bld_core = 1;
+static int c_snr_gau_bld_ofst = -1;
+static unsigned int c_snr_gau_bld_rate = 48;
+static unsigned int c_snr_gau_alp0_min;
+static unsigned int c_snr_gau_alp0_max = 63;
+static unsigned int c_bld_beta2alp_rate = 16;
+static unsigned int c_bld_beta_min;
+static unsigned int c_bld_beta_max = 63;
+static unsigned int qp_mode;
+
+static DEFINE_SPINLOCK(lock);
+
+#define ADV_MV_LARGE_16x8 1
+#define ADV_MV_LARGE_8x16 1
+#define ADV_MV_LARGE_16x16 1
+
+/* me weight offset should not very small, it used by v1 me module. */
+/* the min real sad for me is 16 by hardware. */
+#define ME_WEIGHT_OFFSET 0x520
+#define I4MB_WEIGHT_OFFSET 0x655
+#define I16MB_WEIGHT_OFFSET 0x560
+
+#define ADV_MV_16x16_WEIGHT 0x080
+#define ADV_MV_16_8_WEIGHT 0x0e0
+#define ADV_MV_8x8_WEIGHT 0x240
+#define ADV_MV_4x4x4_WEIGHT 0x3000
+
+#define IE_SAD_SHIFT_I16 0x001
+#define IE_SAD_SHIFT_I4 0x001
+#define ME_SAD_SHIFT_INTER 0x001
+
+#define STEP_2_SKIP_SAD 0
+#define STEP_1_SKIP_SAD 0
+#define STEP_0_SKIP_SAD 0
+#define STEP_2_SKIP_WEIGHT 0
+#define STEP_1_SKIP_WEIGHT 0
+#define STEP_0_SKIP_WEIGHT 0
+
+#define ME_SAD_RANGE_0 0x1 /* 0x0 */
+#define ME_SAD_RANGE_1 0x0
+#define ME_SAD_RANGE_2 0x0
+#define ME_SAD_RANGE_3 0x0
+
+/* use 0 for v3, 0x18 for v2 */
+#define ME_MV_PRE_WEIGHT_0 0x18
+/* use 0 for v3, 0x18 for v2 */
+#define ME_MV_PRE_WEIGHT_1 0x18
+#define ME_MV_PRE_WEIGHT_2 0x0
+#define ME_MV_PRE_WEIGHT_3 0x0
+
+/* use 0 for v3, 0x18 for v2 */
+#define ME_MV_STEP_WEIGHT_0 0x18
+/* use 0 for v3, 0x18 for v2 */
+#define ME_MV_STEP_WEIGHT_1 0x18
+#define ME_MV_STEP_WEIGHT_2 0x0
+#define ME_MV_STEP_WEIGHT_3 0x0
+
+#define ME_SAD_ENOUGH_0_DATA 0x00
+#define ME_SAD_ENOUGH_1_DATA 0x04
+#define ME_SAD_ENOUGH_2_DATA 0x11
+#define ADV_MV_8x8_ENOUGH_DATA 0x20
+
+/* V4_COLOR_BLOCK_FIX */
+#define V3_FORCE_SKIP_SAD_0 0x10
+/* 4 Blocks */
+#define V3_FORCE_SKIP_SAD_1 0x60
+/* 16 Blocks + V3_SKIP_WEIGHT_2 */
+#define V3_FORCE_SKIP_SAD_2 0x250
+/* almost disable it -- use t_lac_coeff_2 output to F_ZERO is better */
+#define V3_ME_F_ZERO_SAD (ME_WEIGHT_OFFSET + 0x10)
+
+#define V3_IE_F_ZERO_SAD_I16 (I16MB_WEIGHT_OFFSET + 0x10)
+#define V3_IE_F_ZERO_SAD_I4 (I4MB_WEIGHT_OFFSET + 0x20)
+
+#define V3_SKIP_WEIGHT_0 0x10
+/* 4 Blocks 8 separate search sad can be very low */
+#define V3_SKIP_WEIGHT_1 0x8 /* (4 * ME_MV_STEP_WEIGHT_1 + 0x100) */
+#define V3_SKIP_WEIGHT_2 0x3
+
+#define V3_LEVEL_1_F_SKIP_MAX_SAD 0x0
+#define V3_LEVEL_1_SKIP_MAX_SAD 0x6
+
+#define I4_ipred_weight_most 0x18
+#define I4_ipred_weight_else 0x28
+
+#define C_ipred_weight_V 0x04
+#define C_ipred_weight_H 0x08
+#define C_ipred_weight_DC 0x0c
+
+#define I16_ipred_weight_V 0x04
+#define I16_ipred_weight_H 0x08
+#define I16_ipred_weight_DC 0x0c
+
+/* 0x00 same as disable */
+#define v3_left_small_max_ie_sad 0x00
+#define v3_left_small_max_me_sad 0x40
+
+#define v5_use_small_diff_cnt 0
+#define v5_simple_mb_inter_all_en 1
+#define v5_simple_mb_inter_8x8_en 1
+#define v5_simple_mb_inter_16_8_en 1
+#define v5_simple_mb_inter_16x16_en 1
+#define v5_simple_mb_intra_en 1
+#define v5_simple_mb_C_en 0
+#define v5_simple_mb_Y_en 1
+#define v5_small_diff_Y 0x10
+#define v5_small_diff_C 0x18
+/* shift 8-bits, 2, 1, 0, -1, -2, -3, -4 */
+#define v5_simple_dq_setting 0x43210fed
+#define v5_simple_me_weight_setting 0
+
+#ifdef H264_ENC_CBR
+#define CBR_TABLE_SIZE 0x800
+#define CBR_SHORT_SHIFT 12 /* same as disable */
+#define CBR_LONG_MB_NUM 2
+#define START_TABLE_ID 8
+#define CBR_LONG_THRESH 4
+#endif
+
+static u32 v3_mv_sad[64] = {
+ /* For step0 */
+ 0x00000004,
+ 0x00010008,
+ 0x00020010,
+ 0x00030018,
+ 0x00040020,
+ 0x00050028,
+ 0x00060038,
+ 0x00070048,
+ 0x00080058,
+ 0x00090068,
+ 0x000a0080,
+ 0x000b0098,
+ 0x000c00b0,
+ 0x000d00c8,
+ 0x000e00e8,
+ 0x000f0110,
+ /* For step1 */
+ 0x00100002,
+ 0x00110004,
+ 0x00120008,
+ 0x0013000c,
+ 0x00140010,
+ 0x00150014,
+ 0x0016001c,
+ 0x00170024,
+ 0x0018002c,
+ 0x00190034,
+ 0x001a0044,
+ 0x001b0054,
+ 0x001c0064,
+ 0x001d0074,
+ 0x001e0094,
+ 0x001f00b4,
+ /* For step2 */
+ 0x00200006,
+ 0x0021000c,
+ 0x0022000c,
+ 0x00230018,
+ 0x00240018,
+ 0x00250018,
+ 0x00260018,
+ 0x00270030,
+ 0x00280030,
+ 0x00290030,
+ 0x002a0030,
+ 0x002b0030,
+ 0x002c0030,
+ 0x002d0030,
+ 0x002e0030,
+ 0x002f0050,
+ /* For step2 4x4-8x8 */
+ 0x00300001,
+ 0x00310002,
+ 0x00320002,
+ 0x00330004,
+ 0x00340004,
+ 0x00350004,
+ 0x00360004,
+ 0x00370006,
+ 0x00380006,
+ 0x00390006,
+ 0x003a0006,
+ 0x003b0006,
+ 0x003c0006,
+ 0x003d0006,
+ 0x003e0006,
+ 0x003f0006
+};
+
+static struct BuffInfo_s amvenc_buffspec[] = {
+ {
+ .lev_id = 0,
+ .max_width = 1920,
+ .max_height = 1088,
+ .min_buffsize = 0x1400000,
+ .dct = {
+ .buf_start = 0,
+ .buf_size = 0x800000, /* 1920x1088x4 */
+ },
+ .dec0_y = {
+ .buf_start = 0x800000,
+ .buf_size = 0x300000,
+ },
+ .dec1_y = {
+ .buf_start = 0xb00000,
+ .buf_size = 0x300000,
+ },
+ .assit = {
+ .buf_start = 0xe10000,
+ .buf_size = 0xc0000,
+ },
+ .bitstream = {
+ .buf_start = 0xf00000,
+ .buf_size = 0x100000,
+ },
+ .scale_buff = {
+ .buf_start = 0x1000000,
+ .buf_size = 0x300000,
+ },
+ .dump_info = {
+ .buf_start = 0x1300000,
+ .buf_size = 0xa0000, /* (1920x1088/256)x80 */
+ },
+ .cbr_info = {
+ .buf_start = 0x13b0000,
+ .buf_size = 0x2000,
+ }
+ }
+};
+
+enum ucode_type_e {
+ UCODE_GXL,
+ UCODE_TXL,
+ UCODE_G12A,
+ UCODE_MAX
+};
+
+const char *ucode_name[] = {
+ "gxl_h264_enc",
+ "txl_h264_enc_cavlc",
+ "ga_h264_enc_cabac",
+};
+
+static void dma_flush(u32 buf_start, u32 buf_size);
+static void cache_flush(u32 buf_start, u32 buf_size);
+static int enc_dma_buf_get_phys(struct enc_dma_cfg *cfg, unsigned long *addr);
+static void enc_dma_buf_unmap(struct enc_dma_cfg *cfg);
+
+s32 hcodec_hw_reset(void)
+{
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2 && use_reset_control) {
+ reset_control_reset(hcodec_rst);
+ enc_pr(LOG_DEBUG, "request hcodec reset from application.\n");
+ }
+ return 0;
+}
+
+s32 hcodec_clk_prepare(struct device *dev, struct hcodec_clks *clks)
+{
+ int ret;
+
+ clks->hcodec_aclk = devm_clk_get(dev, "cts_hcodec_aclk");
+
+ if (IS_ERR_OR_NULL(clks->hcodec_aclk)) {
+ enc_pr(LOG_ERROR, "failed to get hcodec aclk\n");
+ return -1;
+ }
+
+ ret = clk_set_rate(clks->hcodec_aclk, 667 * MHz);
+ CHECK_RET(ret);
+
+ ret = clk_prepare(clks->hcodec_aclk);
+ CHECK_RET(ret);
+
+ enc_pr(LOG_ERROR, "hcodec_clk_a: %lu MHz\n", clk_get_rate(clks->hcodec_aclk) / 1000000);
+
+ return 0;
+}
+
+void hcodec_clk_unprepare(struct device *dev, struct hcodec_clks *clks)
+{
+ clk_unprepare(clks->hcodec_aclk);
+ devm_clk_put(dev, clks->hcodec_aclk);
+
+ //clk_unprepare(clks->wave_bclk);
+ //devm_clk_put(dev, clks->wave_bclk);
+
+ //clk_unprepare(clks->wave_aclk);
+ //devm_clk_put(dev, clks->wave_aclk);
+}
+
+s32 hcodec_clk_config(u32 enable)
+{
+ if (enable) {
+ clk_enable(s_hcodec_clks.hcodec_aclk);
+ //clk_enable(s_hcodec_clks.wave_bclk);
+ //clk_enable(s_hcodec_clks.wave_cclk);
+ } else {
+ clk_disable(s_hcodec_clks.hcodec_aclk);
+ //clk_disable(s_hcodec_clks.wave_bclk);
+ //clk_disable(s_hcodec_clks.wave_aclk);
+ }
+
+ return 0;
+}
+
+static const char *select_ucode(u32 ucode_index)
+{
+ enum ucode_type_e ucode = UCODE_GXL;
+
+ switch (ucode_index) {
+ case UCODE_MODE_FULL:
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_G12A)
+ ucode = UCODE_G12A;
+ else if (get_cpu_type() >= MESON_CPU_MAJOR_ID_TXL)
+ ucode = UCODE_TXL;
+ else /* (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXL) */
+ ucode = UCODE_GXL;
+ break;
+ break;
+ default:
+ break;
+ }
+ return (const char *)ucode_name[ucode];
+}
+
+static void hcodec_prog_qtbl(struct encode_wq_s *wq)
+{
+ WRITE_HREG(HCODEC_Q_QUANT_CONTROL,
+ (0 << 23) | /* quant_table_addr */
+ (1 << 22)); /* quant_table_addr_update */
+
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_i4[0]);
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_i4[1]);
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_i4[2]);
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_i4[3]);
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_i4[4]);
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_i4[5]);
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_i4[6]);
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_i4[7]);
+
+ WRITE_HREG(HCODEC_Q_QUANT_CONTROL,
+ (8 << 23) | /* quant_table_addr */
+ (1 << 22)); /* quant_table_addr_update */
+
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_i16[0]);
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_i16[1]);
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_i16[2]);
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_i16[3]);
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_i16[4]);
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_i16[5]);
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_i16[6]);
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_i16[7]);
+
+ WRITE_HREG(HCODEC_Q_QUANT_CONTROL,
+ (16 << 23) | /* quant_table_addr */
+ (1 << 22)); /* quant_table_addr_update */
+
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_me[0]);
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_me[1]);
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_me[2]);
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_me[3]);
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_me[4]);
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_me[5]);
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_me[6]);
+ WRITE_HREG(HCODEC_QUANT_TABLE_DATA,
+ wq->quant_tbl_me[7]);
+}
+
+static void InitEncodeWeight(void)
+{
+ me_mv_merge_ctl =
+ (0x1 << 31) | /* [31] me_merge_mv_en_16 */
+ (0x1 << 30) | /* [30] me_merge_small_mv_en_16 */
+ (0x1 << 29) | /* [29] me_merge_flex_en_16 */
+ (0x1 << 28) | /* [28] me_merge_sad_en_16 */
+ (0x1 << 27) | /* [27] me_merge_mv_en_8 */
+ (0x1 << 26) | /* [26] me_merge_small_mv_en_8 */
+ (0x1 << 25) | /* [25] me_merge_flex_en_8 */
+ (0x1 << 24) | /* [24] me_merge_sad_en_8 */
+ (0x12 << 18) |
+ /* [23:18] me_merge_mv_diff_16 - MV diff
+ * <= n pixel can be merged
+ */
+ (0x2b << 12) |
+ /* [17:12] me_merge_mv_diff_8 - MV diff
+ * <= n pixel can be merged
+ */
+ (0x80 << 0);
+ /* [11:0] me_merge_min_sad - SAD
+ * >= 0x180 can be merged with other MV
+ */
+
+ me_mv_weight_01 = (ME_MV_STEP_WEIGHT_1 << 24) |
+ (ME_MV_PRE_WEIGHT_1 << 16) |
+ (ME_MV_STEP_WEIGHT_0 << 8) |
+ (ME_MV_PRE_WEIGHT_0 << 0);
+
+ me_mv_weight_23 = (ME_MV_STEP_WEIGHT_3 << 24) |
+ (ME_MV_PRE_WEIGHT_3 << 16) |
+ (ME_MV_STEP_WEIGHT_2 << 8) |
+ (ME_MV_PRE_WEIGHT_2 << 0);
+
+ me_sad_range_inc = (ME_SAD_RANGE_3 << 24) |
+ (ME_SAD_RANGE_2 << 16) |
+ (ME_SAD_RANGE_1 << 8) |
+ (ME_SAD_RANGE_0 << 0);
+
+ me_step0_close_mv = (0x100 << 10) |
+ /* me_step0_big_sad -- two MV sad
+ * diff bigger will use use 1
+ */
+ (2 << 5) | /* me_step0_close_mv_y */
+ (2 << 0); /* me_step0_close_mv_x */
+
+ me_f_skip_sad = (0x00 << 24) | /* force_skip_sad_3 */
+ (STEP_2_SKIP_SAD << 16) | /* force_skip_sad_2 */
+ (STEP_1_SKIP_SAD << 8) | /* force_skip_sad_1 */
+ (STEP_0_SKIP_SAD << 0); /* force_skip_sad_0 */
+
+ me_f_skip_weight = (0x00 << 24) | /* force_skip_weight_3 */
+ /* force_skip_weight_2 */
+ (STEP_2_SKIP_WEIGHT << 16) |
+ /* force_skip_weight_1 */
+ (STEP_1_SKIP_WEIGHT << 8) |
+ /* force_skip_weight_0 */
+ (STEP_0_SKIP_WEIGHT << 0);
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXTVBB) {
+ me_f_skip_sad = 0;
+ me_f_skip_weight = 0;
+ me_mv_weight_01 = 0;
+ me_mv_weight_23 = 0;
+ }
+
+ me_sad_enough_01 = (ME_SAD_ENOUGH_1_DATA << 12) |
+ /* me_sad_enough_1 */
+ (ME_SAD_ENOUGH_0_DATA << 0) |
+ /* me_sad_enough_0 */
+ (0 << 12) | /* me_sad_enough_1 */
+ (0 << 0); /* me_sad_enough_0 */
+
+ me_sad_enough_23 = (ADV_MV_8x8_ENOUGH_DATA << 12) |
+ /* adv_mv_8x8_enough */
+ (ME_SAD_ENOUGH_2_DATA << 0) |
+ /* me_sad_enough_2 */
+ (0 << 12) | /* me_sad_enough_3 */
+ (0 << 0); /* me_sad_enough_2 */
+}
+
+/*output stream buffer setting*/
+static void avc_init_output_buffer(struct encode_wq_s *wq)
+{
+ WRITE_HREG(HCODEC_VLC_VB_MEM_CTL,
+ ((1 << 31) | (0x3f << 24) |
+ (0x20 << 16) | (2 << 0)));
+ WRITE_HREG(HCODEC_VLC_VB_START_PTR,
+ wq->mem.BitstreamStart);
+ WRITE_HREG(HCODEC_VLC_VB_WR_PTR,
+ wq->mem.BitstreamStart);
+ WRITE_HREG(HCODEC_VLC_VB_SW_RD_PTR,
+ wq->mem.BitstreamStart);
+ WRITE_HREG(HCODEC_VLC_VB_END_PTR,
+ wq->mem.BitstreamEnd);
+ WRITE_HREG(HCODEC_VLC_VB_CONTROL, 1);
+ WRITE_HREG(HCODEC_VLC_VB_CONTROL,
+ ((0 << 14) | (7 << 3) |
+ (1 << 1) | (0 << 0)));
+}
+
+/*input dct buffer setting*/
+static void avc_init_input_buffer(struct encode_wq_s *wq)
+{
+ WRITE_HREG(HCODEC_QDCT_MB_START_PTR,
+ wq->mem.dct_buff_start_addr);
+ WRITE_HREG(HCODEC_QDCT_MB_END_PTR,
+ wq->mem.dct_buff_end_addr);
+ WRITE_HREG(HCODEC_QDCT_MB_WR_PTR,
+ wq->mem.dct_buff_start_addr);
+ WRITE_HREG(HCODEC_QDCT_MB_RD_PTR,
+ wq->mem.dct_buff_start_addr);
+ WRITE_HREG(HCODEC_QDCT_MB_BUFF, 0);
+}
+
+/*input reference buffer setting*/
+static void avc_init_reference_buffer(s32 canvas)
+{
+ WRITE_HREG(HCODEC_ANC0_CANVAS_ADDR, canvas);
+ WRITE_HREG(HCODEC_VLC_HCMD_CONFIG, 0);
+}
+
+static void avc_init_assit_buffer(struct encode_wq_s *wq)
+{
+ WRITE_HREG(MEM_OFFSET_REG, wq->mem.assit_buffer_offset);
+}
+
+/*deblock buffer setting, same as INI_CANVAS*/
+static void avc_init_dblk_buffer(s32 canvas)
+{
+ WRITE_HREG(HCODEC_REC_CANVAS_ADDR, canvas);
+ WRITE_HREG(HCODEC_DBKR_CANVAS_ADDR, canvas);
+ WRITE_HREG(HCODEC_DBKW_CANVAS_ADDR, canvas);
+}
+
+static void avc_init_encoder(struct encode_wq_s *wq, bool idr)
+{
+ WRITE_HREG(HCODEC_VLC_TOTAL_BYTES, 0);
+ WRITE_HREG(HCODEC_VLC_CONFIG, 0x07);
+ WRITE_HREG(HCODEC_VLC_INT_CONTROL, 0);
+
+ WRITE_HREG(HCODEC_ASSIST_AMR1_INT0, 0x15);
+ WRITE_HREG(HCODEC_ASSIST_AMR1_INT1, 0x8);
+ WRITE_HREG(HCODEC_ASSIST_AMR1_INT3, 0x14);
+
+ WRITE_HREG(IDR_PIC_ID, wq->pic.idr_pic_id);
+ WRITE_HREG(FRAME_NUMBER,
+ (idr == true) ? 0 : wq->pic.frame_number);
+ WRITE_HREG(PIC_ORDER_CNT_LSB,
+ (idr == true) ? 0 : wq->pic.pic_order_cnt_lsb);
+
+ WRITE_HREG(LOG2_MAX_PIC_ORDER_CNT_LSB,
+ wq->pic.log2_max_pic_order_cnt_lsb);
+ WRITE_HREG(LOG2_MAX_FRAME_NUM,
+ wq->pic.log2_max_frame_num);
+ WRITE_HREG(ANC0_BUFFER_ID, 0);
+ WRITE_HREG(QPPICTURE, wq->pic.init_qppicture);
+}
+
+static void avc_canvas_init(struct encode_wq_s *wq)
+{
+ u32 canvas_width, canvas_height;
+ u32 start_addr = wq->mem.buf_start;
+
+ canvas_width = ((wq->pic.encoder_width + 31) >> 5) << 5;
+ canvas_height = ((wq->pic.encoder_height + 15) >> 4) << 4;
+
+ canvas_config(ENC_CANVAS_OFFSET,
+ start_addr + wq->mem.bufspec.dec0_y.buf_start,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
+ canvas_config(1 + ENC_CANVAS_OFFSET,
+ start_addr + wq->mem.bufspec.dec0_uv.buf_start,
+ canvas_width, canvas_height / 2,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
+ /*here the third plane use the same address as the second plane*/
+ canvas_config(2 + ENC_CANVAS_OFFSET,
+ start_addr + wq->mem.bufspec.dec0_uv.buf_start,
+ canvas_width, canvas_height / 2,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
+
+ canvas_config(3 + ENC_CANVAS_OFFSET,
+ start_addr + wq->mem.bufspec.dec1_y.buf_start,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
+ canvas_config(4 + ENC_CANVAS_OFFSET,
+ start_addr + wq->mem.bufspec.dec1_uv.buf_start,
+ canvas_width, canvas_height / 2,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
+ /*here the third plane use the same address as the second plane*/
+ canvas_config(5 + ENC_CANVAS_OFFSET,
+ start_addr + wq->mem.bufspec.dec1_uv.buf_start,
+ canvas_width, canvas_height / 2,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
+}
+
+static void avc_buffspec_init(struct encode_wq_s *wq)
+{
+ u32 canvas_width, canvas_height;
+ u32 start_addr = wq->mem.buf_start;
+ u32 mb_w = (wq->pic.encoder_width + 15) >> 4;
+ u32 mb_h = (wq->pic.encoder_height + 15) >> 4;
+ u32 mbs = mb_w * mb_h;
+
+ canvas_width = ((wq->pic.encoder_width + 31) >> 5) << 5;
+ canvas_height = ((wq->pic.encoder_height + 15) >> 4) << 4;
+
+ wq->mem.dct_buff_start_addr = start_addr +
+ wq->mem.bufspec.dct.buf_start;
+ wq->mem.dct_buff_end_addr =
+ wq->mem.dct_buff_start_addr +
+ wq->mem.bufspec.dct.buf_size - 1;
+ enc_pr(LOG_INFO, "dct_buff_start_addr is 0x%x, wq:%p.\n",
+ wq->mem.dct_buff_start_addr, (void *)wq);
+
+ wq->mem.bufspec.dec0_uv.buf_start =
+ wq->mem.bufspec.dec0_y.buf_start +
+ canvas_width * canvas_height;
+ wq->mem.bufspec.dec0_uv.buf_size = canvas_width * canvas_height / 2;
+ wq->mem.bufspec.dec1_uv.buf_start =
+ wq->mem.bufspec.dec1_y.buf_start +
+ canvas_width * canvas_height;
+ wq->mem.bufspec.dec1_uv.buf_size = canvas_width * canvas_height / 2;
+ wq->mem.assit_buffer_offset = start_addr +
+ wq->mem.bufspec.assit.buf_start;
+ enc_pr(LOG_INFO, "assit_buffer_offset is 0x%x, wq: %p.\n",
+ wq->mem.assit_buffer_offset, (void *)wq);
+ /*output stream buffer config*/
+ wq->mem.BitstreamStart = start_addr +
+ wq->mem.bufspec.bitstream.buf_start;
+ wq->mem.BitstreamEnd =
+ wq->mem.BitstreamStart +
+ wq->mem.bufspec.bitstream.buf_size - 1;
+ enc_pr(LOG_INFO, "BitstreamStart is 0x%x, wq: %p.\n",
+ wq->mem.BitstreamStart, (void *)wq);
+
+ wq->mem.scaler_buff_start_addr =
+ wq->mem.buf_start + wq->mem.bufspec.scale_buff.buf_start;
+ wq->mem.dump_info_ddr_start_addr =
+ wq->mem.buf_start + wq->mem.bufspec.dump_info.buf_start;
+ enc_pr(LOG_INFO,
+ "CBR: dump_info_ddr_start_addr:%x.\n",
+ wq->mem.dump_info_ddr_start_addr);
+ enc_pr(LOG_INFO, "CBR: buf_start :%d.\n",
+ wq->mem.buf_start);
+ enc_pr(LOG_INFO, "CBR: dump_info.buf_start :%d.\n",
+ wq->mem.bufspec.dump_info.buf_start);
+ wq->mem.dump_info_ddr_size =
+ DUMP_INFO_BYTES_PER_MB * mbs;
+ wq->mem.dump_info_ddr_size =
+ (wq->mem.dump_info_ddr_size + PAGE_SIZE - 1)
+ & ~(PAGE_SIZE - 1);
+ wq->mem.cbr_info_ddr_start_addr =
+ wq->mem.buf_start + wq->mem.bufspec.cbr_info.buf_start;
+ wq->mem.cbr_info_ddr_size =
+ wq->mem.bufspec.cbr_info.buf_size;
+ wq->mem.cbr_info_ddr_virt_addr =
+ codec_mm_vmap(wq->mem.cbr_info_ddr_start_addr,
+ wq->mem.bufspec.cbr_info.buf_size);
+
+ wq->mem.dblk_buf_canvas =
+ ((ENC_CANVAS_OFFSET + 2) << 16) |
+ ((ENC_CANVAS_OFFSET + 1) << 8) |
+ (ENC_CANVAS_OFFSET);
+ wq->mem.ref_buf_canvas =
+ ((ENC_CANVAS_OFFSET + 5) << 16) |
+ ((ENC_CANVAS_OFFSET + 4) << 8) |
+ (ENC_CANVAS_OFFSET + 3);
+}
+
+static void avc_init_ie_me_parameter(struct encode_wq_s *wq, u32 quant)
+{
+ ie_cur_ref_sel = 0;
+ ie_pippeline_block = 12;
+ /* currently disable half and sub pixel */
+ ie_me_mode =
+ (ie_pippeline_block & IE_PIPPELINE_BLOCK_MASK) <<
+ IE_PIPPELINE_BLOCK_SHIFT;
+
+ WRITE_HREG(IE_ME_MODE, ie_me_mode);
+ WRITE_HREG(IE_REF_SEL, ie_cur_ref_sel);
+ WRITE_HREG(IE_ME_MB_TYPE, ie_me_mb_type);
+#ifdef MULTI_SLICE_MC
+ if (fixed_slice_cfg)
+ WRITE_HREG(FIXED_SLICE_CFG, fixed_slice_cfg);
+ else if (wq->pic.rows_per_slice !=
+ (wq->pic.encoder_height + 15) >> 4) {
+ u32 mb_per_slice = (wq->pic.encoder_height + 15) >> 4;
+
+ mb_per_slice = mb_per_slice * wq->pic.rows_per_slice;
+ WRITE_HREG(FIXED_SLICE_CFG, mb_per_slice);
+ } else
+ WRITE_HREG(FIXED_SLICE_CFG, 0);
+#else
+ WRITE_HREG(FIXED_SLICE_CFG, 0);
+#endif
+}
+
+/* for temp */
+#define HCODEC_MFDIN_REGC_MBLP (HCODEC_MFDIN_REGB_AMPC + 0x1)
+#define HCODEC_MFDIN_REG0D (HCODEC_MFDIN_REGB_AMPC + 0x2)
+#define HCODEC_MFDIN_REG0E (HCODEC_MFDIN_REGB_AMPC + 0x3)
+#define HCODEC_MFDIN_REG0F (HCODEC_MFDIN_REGB_AMPC + 0x4)
+#define HCODEC_MFDIN_REG10 (HCODEC_MFDIN_REGB_AMPC + 0x5)
+#define HCODEC_MFDIN_REG11 (HCODEC_MFDIN_REGB_AMPC + 0x6)
+#define HCODEC_MFDIN_REG12 (HCODEC_MFDIN_REGB_AMPC + 0x7)
+#define HCODEC_MFDIN_REG13 (HCODEC_MFDIN_REGB_AMPC + 0x8)
+#define HCODEC_MFDIN_REG14 (HCODEC_MFDIN_REGB_AMPC + 0x9)
+#define HCODEC_MFDIN_REG15 (HCODEC_MFDIN_REGB_AMPC + 0xa)
+#define HCODEC_MFDIN_REG16 (HCODEC_MFDIN_REGB_AMPC + 0xb)
+
+static void mfdin_basic(u32 input, u8 iformat,
+ u8 oformat, u32 picsize_x, u32 picsize_y,
+ u8 r2y_en, u8 nr, u8 ifmt_extra)
+{
+ u8 dsample_en; /* Downsample Enable */
+ u8 interp_en; /* Interpolation Enable */
+ u8 y_size; /* 0:16 Pixels for y direction pickup; 1:8 pixels */
+ u8 r2y_mode; /* RGB2YUV Mode, range(0~3) */
+ /* mfdin_reg3_canv[25:24];
+ * // bytes per pixel in x direction for index0, 0:half 1:1 2:2 3:3
+ */
+ u8 canv_idx0_bppx;
+ /* mfdin_reg3_canv[27:26];
+ * // bytes per pixel in x direction for index1-2, 0:half 1:1 2:2 3:3
+ */
+ u8 canv_idx1_bppx;
+ /* mfdin_reg3_canv[29:28];
+ * // bytes per pixel in y direction for index0, 0:half 1:1 2:2 3:3
+ */
+ u8 canv_idx0_bppy;
+ /* mfdin_reg3_canv[31:30];
+ * // bytes per pixel in y direction for index1-2, 0:half 1:1 2:2 3:3
+ */
+ u8 canv_idx1_bppy;
+ u8 ifmt444, ifmt422, ifmt420, linear_bytes4p;
+ u8 nr_enable;
+ u8 cfg_y_snr_en;
+ u8 cfg_y_tnr_en;
+ u8 cfg_c_snr_en;
+ u8 cfg_c_tnr_en;
+ u32 linear_bytesperline;
+ s32 reg_offset;
+ bool linear_enable = false;
+ bool format_err = false;
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_TXL) {
+ if ((iformat == 7) && (ifmt_extra > 2))
+ format_err = true;
+ } else if (iformat == 7)
+ format_err = true;
+
+ if (format_err) {
+ enc_pr(LOG_ERROR,
+ "mfdin format err, iformat:%d, ifmt_extra:%d\n",
+ iformat, ifmt_extra);
+ return;
+ }
+ if (iformat != 7)
+ ifmt_extra = 0;
+
+ ifmt444 = ((iformat == 1) || (iformat == 5) || (iformat == 8) ||
+ (iformat == 9) || (iformat == 12)) ? 1 : 0;
+ if (iformat == 7 && ifmt_extra == 1)
+ ifmt444 = 1;
+ ifmt422 = ((iformat == 0) || (iformat == 10)) ? 1 : 0;
+ if (iformat == 7 && ifmt_extra != 1)
+ ifmt422 = 1;
+ ifmt420 = ((iformat == 2) || (iformat == 3) || (iformat == 4) ||
+ (iformat == 11)) ? 1 : 0;
+ dsample_en = ((ifmt444 && (oformat != 2)) ||
+ (ifmt422 && (oformat == 0))) ? 1 : 0;
+ interp_en = ((ifmt422 && (oformat == 2)) ||
+ (ifmt420 && (oformat != 0))) ? 1 : 0;
+ y_size = (oformat != 0) ? 1 : 0;
+ if (iformat == 12)
+ y_size = 0;
+ r2y_mode = (r2y_en == 1) ? 1 : 0; /* Fixed to 1 (TODO) */
+ canv_idx0_bppx = (iformat == 1) ? 3 : (iformat == 0) ? 2 : 1;
+ canv_idx1_bppx = (iformat == 4) ? 0 : 1;
+ canv_idx0_bppy = 1;
+ canv_idx1_bppy = (iformat == 5) ? 1 : 0;
+
+ if ((iformat == 8) || (iformat == 9) || (iformat == 12))
+ linear_bytes4p = 3;
+ else if (iformat == 10)
+ linear_bytes4p = 2;
+ else if (iformat == 11)
+ linear_bytes4p = 1;
+ else
+ linear_bytes4p = 0;
+ if (iformat == 12)
+ linear_bytesperline = picsize_x * 4;
+ else
+ linear_bytesperline = picsize_x * linear_bytes4p;
+
+ if (iformat < 8)
+ linear_enable = false;
+ else
+ linear_enable = true;
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXBB) {
+ reg_offset = -8;
+ /* nr_mode: 0:Disabled 1:SNR Only 2:TNR Only 3:3DNR */
+ nr_enable = (nr) ? 1 : 0;
+ cfg_y_snr_en = ((nr == 1) || (nr == 3)) ? 1 : 0;
+ cfg_y_tnr_en = ((nr == 2) || (nr == 3)) ? 1 : 0;
+ cfg_c_snr_en = cfg_y_snr_en;
+ /* cfg_c_tnr_en = cfg_y_tnr_en; */
+ cfg_c_tnr_en = 0;
+
+ /* NR For Y */
+ WRITE_HREG((HCODEC_MFDIN_REG0D + reg_offset),
+ ((cfg_y_snr_en << 0) |
+ (y_snr_err_norm << 1) |
+ (y_snr_gau_bld_core << 2) |
+ (((y_snr_gau_bld_ofst) & 0xff) << 6) |
+ (y_snr_gau_bld_rate << 14) |
+ (y_snr_gau_alp0_min << 20) |
+ (y_snr_gau_alp0_max << 26)));
+ WRITE_HREG((HCODEC_MFDIN_REG0E + reg_offset),
+ ((cfg_y_tnr_en << 0) |
+ (y_tnr_mc_en << 1) |
+ (y_tnr_txt_mode << 2) |
+ (y_tnr_mot_sad_margin << 3) |
+ (y_tnr_alpha_min << 7) |
+ (y_tnr_alpha_max << 13) |
+ (y_tnr_deghost_os << 19)));
+ WRITE_HREG((HCODEC_MFDIN_REG0F + reg_offset),
+ ((y_tnr_mot_cortxt_rate << 0) |
+ (y_tnr_mot_distxt_ofst << 8) |
+ (y_tnr_mot_distxt_rate << 4) |
+ (y_tnr_mot_dismot_ofst << 16) |
+ (y_tnr_mot_frcsad_lock << 24)));
+ WRITE_HREG((HCODEC_MFDIN_REG10 + reg_offset),
+ ((y_tnr_mot2alp_frc_gain << 0) |
+ (y_tnr_mot2alp_nrm_gain << 8) |
+ (y_tnr_mot2alp_dis_gain << 16) |
+ (y_tnr_mot2alp_dis_ofst << 24)));
+ WRITE_HREG((HCODEC_MFDIN_REG11 + reg_offset),
+ ((y_bld_beta2alp_rate << 0) |
+ (y_bld_beta_min << 8) |
+ (y_bld_beta_max << 14)));
+
+ /* NR For C */
+ WRITE_HREG((HCODEC_MFDIN_REG12 + reg_offset),
+ ((cfg_y_snr_en << 0) |
+ (c_snr_err_norm << 1) |
+ (c_snr_gau_bld_core << 2) |
+ (((c_snr_gau_bld_ofst) & 0xff) << 6) |
+ (c_snr_gau_bld_rate << 14) |
+ (c_snr_gau_alp0_min << 20) |
+ (c_snr_gau_alp0_max << 26)));
+
+ WRITE_HREG((HCODEC_MFDIN_REG13 + reg_offset),
+ ((cfg_c_tnr_en << 0) |
+ (c_tnr_mc_en << 1) |
+ (c_tnr_txt_mode << 2) |
+ (c_tnr_mot_sad_margin << 3) |
+ (c_tnr_alpha_min << 7) |
+ (c_tnr_alpha_max << 13) |
+ (c_tnr_deghost_os << 19)));
+ WRITE_HREG((HCODEC_MFDIN_REG14 + reg_offset),
+ ((c_tnr_mot_cortxt_rate << 0) |
+ (c_tnr_mot_distxt_ofst << 8) |
+ (c_tnr_mot_distxt_rate << 4) |
+ (c_tnr_mot_dismot_ofst << 16) |
+ (c_tnr_mot_frcsad_lock << 24)));
+ WRITE_HREG((HCODEC_MFDIN_REG15 + reg_offset),
+ ((c_tnr_mot2alp_frc_gain << 0) |
+ (c_tnr_mot2alp_nrm_gain << 8) |
+ (c_tnr_mot2alp_dis_gain << 16) |
+ (c_tnr_mot2alp_dis_ofst << 24)));
+
+ WRITE_HREG((HCODEC_MFDIN_REG16 + reg_offset),
+ ((c_bld_beta2alp_rate << 0) |
+ (c_bld_beta_min << 8) |
+ (c_bld_beta_max << 14)));
+
+ WRITE_HREG((HCODEC_MFDIN_REG1_CTRL + reg_offset),
+ (iformat << 0) | (oformat << 4) |
+ (dsample_en << 6) | (y_size << 8) |
+ (interp_en << 9) | (r2y_en << 12) |
+ (r2y_mode << 13) | (ifmt_extra << 16) |
+ (nr_enable << 19));
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+ WRITE_HREG((HCODEC_MFDIN_REG8_DMBL + reg_offset),
+ (picsize_x << 16) | (picsize_y << 0));
+ } else {
+ WRITE_HREG((HCODEC_MFDIN_REG8_DMBL + reg_offset),
+ (picsize_x << 14) | (picsize_y << 0));
+ }
+ } else {
+ reg_offset = 0;
+ WRITE_HREG((HCODEC_MFDIN_REG1_CTRL + reg_offset),
+ (iformat << 0) | (oformat << 4) |
+ (dsample_en << 6) | (y_size << 8) |
+ (interp_en << 9) | (r2y_en << 12) |
+ (r2y_mode << 13));
+
+ WRITE_HREG((HCODEC_MFDIN_REG8_DMBL + reg_offset),
+ (picsize_x << 12) | (picsize_y << 0));
+ }
+
+ if (linear_enable == false) {
+ WRITE_HREG((HCODEC_MFDIN_REG3_CANV + reg_offset),
+ (input & 0xffffff) |
+ (canv_idx1_bppy << 30) |
+ (canv_idx0_bppy << 28) |
+ (canv_idx1_bppx << 26) |
+ (canv_idx0_bppx << 24));
+ WRITE_HREG((HCODEC_MFDIN_REG4_LNR0 + reg_offset),
+ (0 << 16) | (0 << 0));
+ WRITE_HREG((HCODEC_MFDIN_REG5_LNR1 + reg_offset), 0);
+ } else {
+ WRITE_HREG((HCODEC_MFDIN_REG3_CANV + reg_offset),
+ (canv_idx1_bppy << 30) |
+ (canv_idx0_bppy << 28) |
+ (canv_idx1_bppx << 26) |
+ (canv_idx0_bppx << 24));
+ WRITE_HREG((HCODEC_MFDIN_REG4_LNR0 + reg_offset),
+ (linear_bytes4p << 16) | (linear_bytesperline << 0));
+ WRITE_HREG((HCODEC_MFDIN_REG5_LNR1 + reg_offset), input);
+ }
+
+ if (iformat == 12)
+ WRITE_HREG((HCODEC_MFDIN_REG9_ENDN + reg_offset),
+ (2 << 0) | (1 << 3) | (0 << 6) |
+ (3 << 9) | (6 << 12) | (5 << 15) |
+ (4 << 18) | (7 << 21));
+ else
+ WRITE_HREG((HCODEC_MFDIN_REG9_ENDN + reg_offset),
+ (7 << 0) | (6 << 3) | (5 << 6) |
+ (4 << 9) | (3 << 12) | (2 << 15) |
+ (1 << 18) | (0 << 21));
+}
+
+#ifdef CONFIG_AMLOGIC_MEDIA_GE2D
+static int scale_frame(struct encode_wq_s *wq,
+ struct encode_request_s *request,
+ struct config_para_ex_s *ge2d_config,
+ u32 src_addr, bool canvas)
+{
+ struct ge2d_context_s *context = encode_manager.context;
+ int src_top, src_left, src_width, src_height;
+ struct canvas_s cs0, cs1, cs2, cd;
+ u32 src_canvas, dst_canvas;
+ u32 src_canvas_w, dst_canvas_w;
+ u32 src_h = request->src_h;
+ u32 dst_w = ((wq->pic.encoder_width + 15) >> 4) << 4;
+ u32 dst_h = ((wq->pic.encoder_height + 15) >> 4) << 4;
+ int input_format = GE2D_FORMAT_M24_NV21;
+
+ src_top = request->crop_top;
+ src_left = request->crop_left;
+ src_width = request->src_w - src_left - request->crop_right;
+ src_height = request->src_h - src_top - request->crop_bottom;
+ pr_err("request->fmt=%d, %d %d, canvas=%d\n", request->fmt, FMT_NV21, FMT_BGR888, canvas);
+
+ if (canvas) {
+ if ((request->fmt == FMT_NV21)
+ || (request->fmt == FMT_NV12)) {
+ src_canvas = src_addr & 0xffff;
+ input_format = GE2D_FORMAT_M24_NV21;
+ } else if (request->fmt == FMT_BGR888) {
+ src_canvas = src_addr & 0xffffff;
+ input_format = GE2D_FORMAT_S24_RGB; //Opposite color after ge2d
+ } else if (request->fmt == FMT_RGBA8888) {
+ src_canvas = src_addr & 0xffffff;
+ input_format = GE2D_FORMAT_S32_ABGR;
+ } else {
+ src_canvas = src_addr & 0xffffff;
+ input_format = GE2D_FORMAT_M24_YUV420;
+ }
+ } else {
+ if ((request->fmt == FMT_NV21)
+ || (request->fmt == FMT_NV12)) {
+ src_canvas_w =
+ ((request->src_w + 31) >> 5) << 5;
+ canvas_config(ENC_CANVAS_OFFSET + 9,
+ src_addr,
+ src_canvas_w, src_h,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config(ENC_CANVAS_OFFSET + 10,
+ src_addr + src_canvas_w * src_h,
+ src_canvas_w, src_h / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ src_canvas =
+ ((ENC_CANVAS_OFFSET + 10) << 8)
+ | (ENC_CANVAS_OFFSET + 9);
+ input_format = GE2D_FORMAT_M24_NV21;
+ } else if (request->fmt == FMT_BGR888) {
+ src_canvas_w =
+ ((request->src_w + 31) >> 5) << 5;
+
+ canvas_config(ENC_CANVAS_OFFSET + 9,
+ src_addr,
+ src_canvas_w * 3, src_h,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ src_canvas = ENC_CANVAS_OFFSET + 9;
+ input_format = GE2D_FORMAT_S24_RGB; //Opposite color after ge2d
+ } else if (request->fmt == FMT_RGBA8888) {
+ src_canvas_w =
+ ((request->src_w + 31) >> 5) << 5;
+ canvas_config(
+ ENC_CANVAS_OFFSET + 9,
+ src_addr,
+ src_canvas_w * 4,
+ src_h,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ src_canvas = ENC_CANVAS_OFFSET + 9;
+ input_format = GE2D_FORMAT_S32_ABGR; //Opposite color after ge2d
+ } else {
+ src_canvas_w =
+ ((request->src_w + 63) >> 6) << 6;
+ canvas_config(ENC_CANVAS_OFFSET + 9,
+ src_addr,
+ src_canvas_w, src_h,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config(ENC_CANVAS_OFFSET + 10,
+ src_addr + src_canvas_w * src_h,
+ src_canvas_w / 2, src_h / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config(ENC_CANVAS_OFFSET + 11,
+ src_addr + src_canvas_w * src_h * 5 / 4,
+ src_canvas_w / 2, src_h / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ src_canvas =
+ ((ENC_CANVAS_OFFSET + 11) << 16) |
+ ((ENC_CANVAS_OFFSET + 10) << 8) |
+ (ENC_CANVAS_OFFSET + 9);
+ input_format = GE2D_FORMAT_M24_YUV420;
+ }
+ }
+
+ dst_canvas_w = ((dst_w + 31) >> 5) << 5;
+
+ canvas_config(ENC_CANVAS_OFFSET + 6,
+ wq->mem.scaler_buff_start_addr,
+ dst_canvas_w, dst_h,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
+
+ canvas_config(ENC_CANVAS_OFFSET + 7,
+ wq->mem.scaler_buff_start_addr + dst_canvas_w * dst_h,
+ dst_canvas_w, dst_h / 2,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
+
+ dst_canvas = ((ENC_CANVAS_OFFSET + 7) << 8) |
+ (ENC_CANVAS_OFFSET + 6);
+
+ ge2d_config->alu_const_color = 0;
+ ge2d_config->bitmask_en = 0;
+ ge2d_config->src1_gb_alpha = 0;
+ ge2d_config->dst_xy_swap = 0;
+ canvas_read(src_canvas & 0xff, &cs0);
+ canvas_read((src_canvas >> 8) & 0xff, &cs1);
+ canvas_read((src_canvas >> 16) & 0xff, &cs2);
+ ge2d_config->src_planes[0].addr = cs0.addr;
+ ge2d_config->src_planes[0].w = dst_w * 4;//cs0.width;
+ ge2d_config->src_planes[0].h = dst_h;//cs0.height;
+ ge2d_config->src_planes[1].addr = cs1.addr;
+ ge2d_config->src_planes[1].w = cs1.width;
+ ge2d_config->src_planes[1].h = cs1.height;
+ ge2d_config->src_planes[2].addr = cs2.addr;
+ ge2d_config->src_planes[2].w = cs2.width;
+ ge2d_config->src_planes[2].h = cs2.height;
+
+ canvas_read(dst_canvas & 0xff, &cd);
+
+ ge2d_config->dst_planes[0].addr = cd.addr;
+ ge2d_config->dst_planes[0].w = dst_w * 4;//cd.width;
+ ge2d_config->dst_planes[0].h = dst_h;//cd.height;
+ ge2d_config->src_key.key_enable = 0;
+ ge2d_config->src_key.key_mask = 0;
+ ge2d_config->src_key.key_mode = 0;
+ ge2d_config->src_para.canvas_index = src_canvas;
+ ge2d_config->src_para.mem_type = CANVAS_TYPE_INVALID;
+ ge2d_config->src_para.format = input_format | GE2D_LITTLE_ENDIAN;
+ 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 = dst_w;//request->src_w;
+ ge2d_config->src_para.height = dst_h;//request->src_h;
+ ge2d_config->src2_para.mem_type = CANVAS_TYPE_INVALID;
+ ge2d_config->dst_para.canvas_index = dst_canvas;
+ ge2d_config->dst_para.mem_type = CANVAS_TYPE_INVALID;
+ ge2d_config->dst_para.format =
+ GE2D_FORMAT_M24_NV21 | GE2D_LITTLE_ENDIAN;
+
+ if (wq->pic.encoder_width >= 1280 && wq->pic.encoder_height >= 720) {
+ ge2d_config->dst_para.format |= wq->pic.color_space;
+ }
+
+ 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;
+ ge2d_config->dst_para.width = dst_w;
+ ge2d_config->dst_para.height = dst_h;
+ ge2d_config->dst_para.x_rev = 0;
+ ge2d_config->dst_para.y_rev = 0;
+
+
+ if (ge2d_context_config_ex(context, ge2d_config) < 0) {
+ pr_err("++ge2d configing error.\n");
+ return -1;
+ }
+ stretchblt_noalpha(context, src_left, src_top, src_width, src_height,
+ 0, 0, wq->pic.encoder_width, wq->pic.encoder_height);
+ return dst_canvas_w*dst_h * 3 / 2;
+}
+#endif
+
+static s32 set_input_format(struct encode_wq_s *wq,
+ struct encode_request_s *request)
+{
+ s32 ret = 0;
+ u8 iformat = MAX_FRAME_FMT, oformat = MAX_FRAME_FMT, r2y_en = 0;
+ u32 picsize_x, picsize_y, src_addr;
+ u32 canvas_w = 0;
+ u32 input = request->src;
+ u32 input_y = 0;
+ u32 input_u = 0;
+ u32 input_v = 0;
+ u8 ifmt_extra = 0;
+
+ if ((request->fmt == FMT_RGB565) || (request->fmt >= MAX_FRAME_FMT))
+ return -1;
+
+ picsize_x = ((wq->pic.encoder_width + 15) >> 4) << 4;
+ picsize_y = ((wq->pic.encoder_height + 15) >> 4) << 4;
+ oformat = 0;
+
+ if ((request->type == LOCAL_BUFF)
+ || (request->type == PHYSICAL_BUFF)
+ || (request->type == DMA_BUFF)) {
+ if ((request->type == LOCAL_BUFF) &&
+ (request->flush_flag & AMVENC_FLUSH_FLAG_INPUT))
+ dma_flush(wq->mem.dct_buff_start_addr,
+ request->framesize);
+ if (request->type == LOCAL_BUFF) {
+ input = wq->mem.dct_buff_start_addr;
+ src_addr =
+ wq->mem.dct_buff_start_addr;
+ } else if (request->type == DMA_BUFF) {
+ if (request->plane_num == 3) {
+ input_y = (unsigned long)request->dma_cfg[0].paddr;
+ input_u = (unsigned long)request->dma_cfg[1].paddr;
+ input_v = (unsigned long)request->dma_cfg[2].paddr;
+ } else if (request->plane_num == 2) {
+ input_y = (unsigned long)request->dma_cfg[0].paddr;
+ input_u = (unsigned long)request->dma_cfg[1].paddr;
+ input_v = input_u;
+ } else if (request->plane_num == 1) {
+ input_y = (unsigned long)request->dma_cfg[0].paddr;
+ if (request->fmt == FMT_NV21
+ || request->fmt == FMT_NV12) {
+ input_u = input_y + picsize_x * picsize_y;
+ input_v = input_u;
+ }
+ if (request->fmt == FMT_YUV420) {
+ input_u = input_y + picsize_x * picsize_y;
+ input_v = input_u + picsize_x * picsize_y / 4;
+ }
+ }
+ src_addr = input_y;
+ picsize_y = wq->pic.encoder_height;
+ enc_pr(LOG_INFO, "dma addr[0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx]\n",
+ (unsigned long)request->dma_cfg[0].vaddr,
+ (unsigned long)request->dma_cfg[0].paddr,
+ (unsigned long)request->dma_cfg[1].vaddr,
+ (unsigned long)request->dma_cfg[1].paddr,
+ (unsigned long)request->dma_cfg[2].vaddr,
+ (unsigned long)request->dma_cfg[2].paddr);
+ } else {
+ src_addr = input;
+ picsize_y = wq->pic.encoder_height;
+ }
+
+ if (request->scale_enable) {
+#ifdef CONFIG_AMLOGIC_MEDIA_GE2D
+ struct config_para_ex_s ge2d_config;
+
+ memset(&ge2d_config, 0,
+ sizeof(struct config_para_ex_s));
+ scale_frame(
+ wq, request,
+ &ge2d_config,
+ src_addr,
+ false);
+ iformat = 2;
+ r2y_en = 0;
+ input = ((ENC_CANVAS_OFFSET + 7) << 8) |
+ (ENC_CANVAS_OFFSET + 6);
+ ret = 0;
+ goto MFDIN;
+#else
+ enc_pr(LOG_ERROR,
+ "Warning: need enable ge2d for scale frame!\n");
+ return -1;
+#endif
+ }
+ if ((request->fmt <= FMT_YUV444_PLANE) ||
+ (request->fmt >= FMT_YUV422_12BIT))
+ r2y_en = 0;
+ else
+ r2y_en = 1;
+
+ if (request->fmt >= FMT_YUV422_12BIT) {
+ iformat = 7;
+ ifmt_extra = request->fmt - FMT_YUV422_12BIT;
+ if (request->fmt == FMT_YUV422_12BIT)
+ canvas_w = picsize_x * 24 / 8;
+ else if (request->fmt == FMT_YUV444_10BIT)
+ canvas_w = picsize_x * 32 / 8;
+ else
+ canvas_w = (picsize_x * 20 + 7) / 8;
+ canvas_w = ((canvas_w + 31) >> 5) << 5;
+ canvas_config(ENC_CANVAS_OFFSET + 6,
+ input,
+ canvas_w, picsize_y,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ input = ENC_CANVAS_OFFSET + 6;
+ input = input & 0xff;
+ } else if (request->fmt == FMT_YUV422_SINGLE)
+ iformat = 10;
+ else if ((request->fmt == FMT_YUV444_SINGLE)
+ || (request->fmt == FMT_RGB888)) {
+ iformat = 1;
+ if (request->fmt == FMT_RGB888)
+ r2y_en = 1;
+ canvas_w = picsize_x * 3;
+ canvas_w = ((canvas_w + 31) >> 5) << 5;
+ canvas_config(ENC_CANVAS_OFFSET + 6,
+ input,
+ canvas_w, picsize_y,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ input = ENC_CANVAS_OFFSET + 6;
+ } else if ((request->fmt == FMT_NV21)
+ || (request->fmt == FMT_NV12)) {
+ canvas_w = ((wq->pic.encoder_width + 31) >> 5) << 5;
+ iformat = (request->fmt == FMT_NV21) ? 2 : 3;
+ if (request->type == DMA_BUFF) {
+ canvas_config(ENC_CANVAS_OFFSET + 6,
+ input_y,
+ canvas_w, picsize_y,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config(ENC_CANVAS_OFFSET + 7,
+ input_u,
+ canvas_w, picsize_y / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ } else {
+ canvas_config(ENC_CANVAS_OFFSET + 6,
+ input,
+ canvas_w, picsize_y,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config(ENC_CANVAS_OFFSET + 7,
+ input + canvas_w * picsize_y,
+ canvas_w, picsize_y / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ }
+ input = ((ENC_CANVAS_OFFSET + 7) << 8) |
+ (ENC_CANVAS_OFFSET + 6);
+ } else if (request->fmt == FMT_YUV420) {
+ iformat = 4;
+ canvas_w = ((wq->pic.encoder_width + 63) >> 6) << 6;
+ if (request->type == DMA_BUFF) {
+ canvas_config(ENC_CANVAS_OFFSET + 6,
+ input_y,
+ canvas_w, picsize_y,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config(ENC_CANVAS_OFFSET + 7,
+ input_u,
+ canvas_w / 2, picsize_y / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config(ENC_CANVAS_OFFSET + 8,
+ input_v,
+ canvas_w / 2, picsize_y / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ } else {
+ canvas_config(ENC_CANVAS_OFFSET + 6,
+ input,
+ canvas_w, picsize_y,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config(ENC_CANVAS_OFFSET + 7,
+ input + canvas_w * picsize_y,
+ canvas_w / 2, picsize_y / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config(ENC_CANVAS_OFFSET + 8,
+ input + canvas_w * picsize_y * 5 / 4,
+ canvas_w / 2, picsize_y / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+
+ }
+ input = ((ENC_CANVAS_OFFSET + 8) << 16) |
+ ((ENC_CANVAS_OFFSET + 7) << 8) |
+ (ENC_CANVAS_OFFSET + 6);
+ } else if ((request->fmt == FMT_YUV444_PLANE)
+ || (request->fmt == FMT_RGB888_PLANE)) {
+ if (request->fmt == FMT_RGB888_PLANE)
+ r2y_en = 1;
+ iformat = 5;
+ canvas_w = ((wq->pic.encoder_width + 31) >> 5) << 5;
+ canvas_config(ENC_CANVAS_OFFSET + 6,
+ input,
+ canvas_w, picsize_y,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config(ENC_CANVAS_OFFSET + 7,
+ input + canvas_w * picsize_y,
+ canvas_w, picsize_y,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config(ENC_CANVAS_OFFSET + 8,
+ input + canvas_w * picsize_y * 2,
+ canvas_w, picsize_y,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ input = ((ENC_CANVAS_OFFSET + 8) << 16) |
+ ((ENC_CANVAS_OFFSET + 7) << 8) |
+ (ENC_CANVAS_OFFSET + 6);
+ } else if (request->fmt == FMT_RGBA8888) {
+ r2y_en = 1;
+ iformat = 12;
+ }
+ ret = 0;
+ } else if (request->type == CANVAS_BUFF) {
+ r2y_en = 0;
+ if (request->scale_enable) {
+#ifdef CONFIG_AMLOGIC_MEDIA_GE2D
+ struct config_para_ex_s ge2d_config;
+ memset(&ge2d_config, 0,
+ sizeof(struct config_para_ex_s));
+ scale_frame(
+ wq, request,
+ &ge2d_config,
+ input, true);
+ iformat = 2;
+ r2y_en = 0;
+ input = ((ENC_CANVAS_OFFSET + 7) << 8) |
+ (ENC_CANVAS_OFFSET + 6);
+ ret = 0;
+ goto MFDIN;
+#else
+ enc_pr(LOG_ERROR,
+ "Warning: need enable ge2d for scale frame!\n");
+ return -1;
+#endif
+ }
+ if (request->fmt == FMT_YUV422_SINGLE) {
+ iformat = 0;
+ input = input & 0xff;
+ } else if (request->fmt == FMT_YUV444_SINGLE) {
+ iformat = 1;
+ input = input & 0xff;
+ } else if ((request->fmt == FMT_NV21)
+ || (request->fmt == FMT_NV12)) {
+ iformat = (request->fmt == FMT_NV21) ? 2 : 3;
+ input = input & 0xffff;
+ } else if (request->fmt == FMT_YUV420) {
+ iformat = 4;
+ input = input & 0xffffff;
+ } else if ((request->fmt == FMT_YUV444_PLANE)
+ || (request->fmt == FMT_RGB888_PLANE)) {
+ if (request->fmt == FMT_RGB888_PLANE)
+ r2y_en = 1;
+ iformat = 5;
+ input = input & 0xffffff;
+ } else if ((request->fmt == FMT_YUV422_12BIT)
+ || (request->fmt == FMT_YUV444_10BIT)
+ || (request->fmt == FMT_YUV422_10BIT)) {
+ iformat = 7;
+ ifmt_extra = request->fmt - FMT_YUV422_12BIT;
+ input = input & 0xff;
+ } else
+ ret = -1;
+ }
+#ifdef CONFIG_AMLOGIC_MEDIA_GE2D
+MFDIN:
+#endif
+ if (ret == 0)
+ mfdin_basic(input, iformat, oformat,
+ picsize_x, picsize_y, r2y_en,
+ request->nr_mode, ifmt_extra);
+ return ret;
+}
+
+#ifdef H264_ENC_CBR
+static void ConvertTable2Risc(void *table, u32 len)
+{
+ u32 i, j;
+ u16 temp;
+ u16 *tbl = (u16 *)table;
+
+ if ((len < 8) || (len % 8) || (!table)) {
+ enc_pr(LOG_ERROR, "ConvertTable2Risc tbl %p, len %d error\n",
+ table, len);
+ return;
+ }
+ for (i = 0; i < len / 8; i++) {
+ j = i << 2;
+ temp = tbl[j];
+ tbl[j] = tbl[j + 3];
+ tbl[j + 3] = temp;
+
+ temp = tbl[j + 1];
+ tbl[j + 1] = tbl[j + 2];
+ tbl[j + 2] = temp;
+ }
+
+}
+#endif
+
+static void avc_prot_init(struct encode_wq_s *wq,
+ struct encode_request_s *request, u32 quant, bool IDR)
+{
+ u32 data32;
+ u32 pic_width, pic_height;
+ u32 pic_mb_nr;
+ u32 pic_mbx, pic_mby;
+ u32 i_pic_qp, p_pic_qp;
+ u32 i_pic_qp_c, p_pic_qp_c;
+ u32 pic_width_in_mb;
+ u32 slice_qp;
+
+ pic_width = wq->pic.encoder_width;
+ pic_height = wq->pic.encoder_height;
+ pic_mb_nr = 0;
+ pic_mbx = 0;
+ pic_mby = 0;
+ i_pic_qp = quant;
+ p_pic_qp = quant;
+
+ pic_width_in_mb = (pic_width + 15) / 16;
+ WRITE_HREG(HCODEC_HDEC_MC_OMEM_AUTO,
+ (1 << 31) | /* use_omem_mb_xy */
+ ((pic_width_in_mb - 1) << 16)); /* omem_max_mb_x */
+
+ WRITE_HREG(HCODEC_VLC_ADV_CONFIG,
+ /* early_mix_mc_hcmd -- will enable in P Picture */
+ (0 << 10) |
+ (1 << 9) | /* update_top_left_mix */
+ (1 << 8) | /* p_top_left_mix */
+ /* mv_cal_mixed_type -- will enable in P Picture */
+ (0 << 7) |
+ /* mc_hcmd_mixed_type -- will enable in P Picture */
+ (0 << 6) |
+ (1 << 5) | /* use_separate_int_control */
+ (1 << 4) | /* hcmd_intra_use_q_info */
+ (1 << 3) | /* hcmd_left_use_prev_info */
+ (1 << 2) | /* hcmd_use_q_info */
+ (1 << 1) | /* use_q_delta_quant */
+ /* detect_I16_from_I4 use qdct detected mb_type */
+ (0 << 0));
+
+ WRITE_HREG(HCODEC_QDCT_ADV_CONFIG,
+ (1 << 29) | /* mb_info_latch_no_I16_pred_mode */
+ (1 << 28) | /* ie_dma_mbxy_use_i_pred */
+ (1 << 27) | /* ie_dma_read_write_use_ip_idx */
+ (1 << 26) | /* ie_start_use_top_dma_count */
+ (1 << 25) | /* i_pred_top_dma_rd_mbbot */
+ (1 << 24) | /* i_pred_top_dma_wr_disable */
+ /* i_pred_mix -- will enable in P Picture */
+ (0 << 23) |
+ (1 << 22) | /* me_ab_rd_when_intra_in_p */
+ (1 << 21) | /* force_mb_skip_run_when_intra */
+ /* mc_out_mixed_type -- will enable in P Picture */
+ (0 << 20) |
+ (1 << 19) | /* ie_start_when_quant_not_full */
+ (1 << 18) | /* mb_info_state_mix */
+ /* mb_type_use_mix_result -- will enable in P Picture */
+ (0 << 17) |
+ /* me_cb_ie_read_enable -- will enable in P Picture */
+ (0 << 16) |
+ /* ie_cur_data_from_me -- will enable in P Picture */
+ (0 << 15) |
+ (1 << 14) | /* rem_per_use_table */
+ (0 << 13) | /* q_latch_int_enable */
+ (1 << 12) | /* q_use_table */
+ (0 << 11) | /* q_start_wait */
+ (1 << 10) | /* LUMA_16_LEFT_use_cur */
+ (1 << 9) | /* DC_16_LEFT_SUM_use_cur */
+ (1 << 8) | /* c_ref_ie_sel_cur */
+ (0 << 7) | /* c_ipred_perfect_mode */
+ (1 << 6) | /* ref_ie_ul_sel */
+ (1 << 5) | /* mb_type_use_ie_result */
+ (1 << 4) | /* detect_I16_from_I4 */
+ (1 << 3) | /* ie_not_wait_ref_busy */
+ (1 << 2) | /* ie_I16_enable */
+ (3 << 0)); /* ie_done_sel // fastest when waiting */
+
+ if (request != NULL) {
+ WRITE_HREG(HCODEC_IE_WEIGHT,
+ (request->i16_weight << 16) |
+ (request->i4_weight << 0));
+ WRITE_HREG(HCODEC_ME_WEIGHT,
+ (request->me_weight << 0));
+ WRITE_HREG(HCODEC_SAD_CONTROL_0,
+ /* ie_sad_offset_I16 */
+ (request->i16_weight << 16) |
+ /* ie_sad_offset_I4 */
+ (request->i4_weight << 0));
+ WRITE_HREG(HCODEC_SAD_CONTROL_1,
+ /* ie_sad_shift_I16 */
+ (IE_SAD_SHIFT_I16 << 24) |
+ /* ie_sad_shift_I4 */
+ (IE_SAD_SHIFT_I4 << 20) |
+ /* me_sad_shift_INTER */
+ (ME_SAD_SHIFT_INTER << 16) |
+ /* me_sad_offset_INTER */
+ (request->me_weight << 0));
+ wq->me_weight = request->me_weight;
+ wq->i4_weight = request->i4_weight;
+ wq->i16_weight = request->i16_weight;
+ } else {
+ WRITE_HREG(HCODEC_IE_WEIGHT,
+ (I16MB_WEIGHT_OFFSET << 16) |
+ (I4MB_WEIGHT_OFFSET << 0));
+ WRITE_HREG(HCODEC_ME_WEIGHT,
+ (ME_WEIGHT_OFFSET << 0));
+ WRITE_HREG(HCODEC_SAD_CONTROL_0,
+ /* ie_sad_offset_I16 */
+ (I16MB_WEIGHT_OFFSET << 16) |
+ /* ie_sad_offset_I4 */
+ (I4MB_WEIGHT_OFFSET << 0));
+ WRITE_HREG(HCODEC_SAD_CONTROL_1,
+ /* ie_sad_shift_I16 */
+ (IE_SAD_SHIFT_I16 << 24) |
+ /* ie_sad_shift_I4 */
+ (IE_SAD_SHIFT_I4 << 20) |
+ /* me_sad_shift_INTER */
+ (ME_SAD_SHIFT_INTER << 16) |
+ /* me_sad_offset_INTER */
+ (ME_WEIGHT_OFFSET << 0));
+ }
+
+ WRITE_HREG(HCODEC_ADV_MV_CTL0,
+ (ADV_MV_LARGE_16x8 << 31) |
+ (ADV_MV_LARGE_8x16 << 30) |
+ (ADV_MV_8x8_WEIGHT << 16) | /* adv_mv_8x8_weight */
+ /* adv_mv_4x4x4_weight should be set bigger */
+ (ADV_MV_4x4x4_WEIGHT << 0));
+ WRITE_HREG(HCODEC_ADV_MV_CTL1,
+ /* adv_mv_16x16_weight */
+ (ADV_MV_16x16_WEIGHT << 16) |
+ (ADV_MV_LARGE_16x16 << 15) |
+ (ADV_MV_16_8_WEIGHT << 0)); /* adv_mv_16_8_weight */
+
+ hcodec_prog_qtbl(wq);
+ if (IDR) {
+ i_pic_qp =
+ wq->quant_tbl_i4[0] & 0xff;
+ i_pic_qp +=
+ wq->quant_tbl_i16[0] & 0xff;
+ i_pic_qp /= 2;
+ p_pic_qp = i_pic_qp;
+ } else {
+ i_pic_qp =
+ wq->quant_tbl_i4[0] & 0xff;
+ i_pic_qp +=
+ wq->quant_tbl_i16[0] & 0xff;
+ p_pic_qp = wq->quant_tbl_me[0] & 0xff;
+ slice_qp = (i_pic_qp + p_pic_qp) / 3;
+ i_pic_qp = slice_qp;
+ p_pic_qp = i_pic_qp;
+ }
+#ifdef H264_ENC_CBR
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXTVBB) {
+ data32 = READ_HREG(HCODEC_SAD_CONTROL_1);
+ data32 = data32 & 0xffff; /* remove sad shift */
+ WRITE_HREG(HCODEC_SAD_CONTROL_1, data32);
+ WRITE_HREG(H264_ENC_CBR_TABLE_ADDR,
+ wq->mem.cbr_info_ddr_start_addr);
+ WRITE_HREG(H264_ENC_CBR_MB_SIZE_ADDR,
+ wq->mem.cbr_info_ddr_start_addr
+ + CBR_TABLE_SIZE);
+ WRITE_HREG(H264_ENC_CBR_CTL,
+ (wq->cbr_info.start_tbl_id << 28) |
+ (wq->cbr_info.short_shift << 24) |
+ (wq->cbr_info.long_mb_num << 16) |
+ (wq->cbr_info.long_th << 0));
+ WRITE_HREG(H264_ENC_CBR_REGION_SIZE,
+ (wq->cbr_info.block_w << 16) |
+ (wq->cbr_info.block_h << 0));
+ }
+#endif
+ WRITE_HREG(HCODEC_QDCT_VLC_QUANT_CTL_0,
+ (0 << 19) | /* vlc_delta_quant_1 */
+ (i_pic_qp << 13) | /* vlc_quant_1 */
+ (0 << 6) | /* vlc_delta_quant_0 */
+ (i_pic_qp << 0)); /* vlc_quant_0 */
+ WRITE_HREG(HCODEC_QDCT_VLC_QUANT_CTL_1,
+ (14 << 6) | /* vlc_max_delta_q_neg */
+ (13 << 0)); /* vlc_max_delta_q_pos */
+ WRITE_HREG(HCODEC_VLC_PIC_SIZE,
+ pic_width | (pic_height << 16));
+ WRITE_HREG(HCODEC_VLC_PIC_POSITION,
+ (pic_mb_nr << 16) |
+ (pic_mby << 8) |
+ (pic_mbx << 0));
+
+ /* synopsys parallel_case full_case */
+ switch (i_pic_qp) {
+ case 0:
+ i_pic_qp_c = 0;
+ break;
+ case 1:
+ i_pic_qp_c = 1;
+ break;
+ case 2:
+ i_pic_qp_c = 2;
+ break;
+ case 3:
+ i_pic_qp_c = 3;
+ break;
+ case 4:
+ i_pic_qp_c = 4;
+ break;
+ case 5:
+ i_pic_qp_c = 5;
+ break;
+ case 6:
+ i_pic_qp_c = 6;
+ break;
+ case 7:
+ i_pic_qp_c = 7;
+ break;
+ case 8:
+ i_pic_qp_c = 8;
+ break;
+ case 9:
+ i_pic_qp_c = 9;
+ break;
+ case 10:
+ i_pic_qp_c = 10;
+ break;
+ case 11:
+ i_pic_qp_c = 11;
+ break;
+ case 12:
+ i_pic_qp_c = 12;
+ break;
+ case 13:
+ i_pic_qp_c = 13;
+ break;
+ case 14:
+ i_pic_qp_c = 14;
+ break;
+ case 15:
+ i_pic_qp_c = 15;
+ break;
+ case 16:
+ i_pic_qp_c = 16;
+ break;
+ case 17:
+ i_pic_qp_c = 17;
+ break;
+ case 18:
+ i_pic_qp_c = 18;
+ break;
+ case 19:
+ i_pic_qp_c = 19;
+ break;
+ case 20:
+ i_pic_qp_c = 20;
+ break;
+ case 21:
+ i_pic_qp_c = 21;
+ break;
+ case 22:
+ i_pic_qp_c = 22;
+ break;
+ case 23:
+ i_pic_qp_c = 23;
+ break;
+ case 24:
+ i_pic_qp_c = 24;
+ break;
+ case 25:
+ i_pic_qp_c = 25;
+ break;
+ case 26:
+ i_pic_qp_c = 26;
+ break;
+ case 27:
+ i_pic_qp_c = 27;
+ break;
+ case 28:
+ i_pic_qp_c = 28;
+ break;
+ case 29:
+ i_pic_qp_c = 29;
+ break;
+ case 30:
+ i_pic_qp_c = 29;
+ break;
+ case 31:
+ i_pic_qp_c = 30;
+ break;
+ case 32:
+ i_pic_qp_c = 31;
+ break;
+ case 33:
+ i_pic_qp_c = 32;
+ break;
+ case 34:
+ i_pic_qp_c = 32;
+ break;
+ case 35:
+ i_pic_qp_c = 33;
+ break;
+ case 36:
+ i_pic_qp_c = 34;
+ break;
+ case 37:
+ i_pic_qp_c = 34;
+ break;
+ case 38:
+ i_pic_qp_c = 35;
+ break;
+ case 39:
+ i_pic_qp_c = 35;
+ break;
+ case 40:
+ i_pic_qp_c = 36;
+ break;
+ case 41:
+ i_pic_qp_c = 36;
+ break;
+ case 42:
+ i_pic_qp_c = 37;
+ break;
+ case 43:
+ i_pic_qp_c = 37;
+ break;
+ case 44:
+ i_pic_qp_c = 37;
+ break;
+ case 45:
+ i_pic_qp_c = 38;
+ break;
+ case 46:
+ i_pic_qp_c = 38;
+ break;
+ case 47:
+ i_pic_qp_c = 38;
+ break;
+ case 48:
+ i_pic_qp_c = 39;
+ break;
+ case 49:
+ i_pic_qp_c = 39;
+ break;
+ case 50:
+ i_pic_qp_c = 39;
+ break;
+ default:
+ i_pic_qp_c = 39;
+ break;
+ }
+
+ /* synopsys parallel_case full_case */
+ switch (p_pic_qp) {
+ case 0:
+ p_pic_qp_c = 0;
+ break;
+ case 1:
+ p_pic_qp_c = 1;
+ break;
+ case 2:
+ p_pic_qp_c = 2;
+ break;
+ case 3:
+ p_pic_qp_c = 3;
+ break;
+ case 4:
+ p_pic_qp_c = 4;
+ break;
+ case 5:
+ p_pic_qp_c = 5;
+ break;
+ case 6:
+ p_pic_qp_c = 6;
+ break;
+ case 7:
+ p_pic_qp_c = 7;
+ break;
+ case 8:
+ p_pic_qp_c = 8;
+ break;
+ case 9:
+ p_pic_qp_c = 9;
+ break;
+ case 10:
+ p_pic_qp_c = 10;
+ break;
+ case 11:
+ p_pic_qp_c = 11;
+ break;
+ case 12:
+ p_pic_qp_c = 12;
+ break;
+ case 13:
+ p_pic_qp_c = 13;
+ break;
+ case 14:
+ p_pic_qp_c = 14;
+ break;
+ case 15:
+ p_pic_qp_c = 15;
+ break;
+ case 16:
+ p_pic_qp_c = 16;
+ break;
+ case 17:
+ p_pic_qp_c = 17;
+ break;
+ case 18:
+ p_pic_qp_c = 18;
+ break;
+ case 19:
+ p_pic_qp_c = 19;
+ break;
+ case 20:
+ p_pic_qp_c = 20;
+ break;
+ case 21:
+ p_pic_qp_c = 21;
+ break;
+ case 22:
+ p_pic_qp_c = 22;
+ break;
+ case 23:
+ p_pic_qp_c = 23;
+ break;
+ case 24:
+ p_pic_qp_c = 24;
+ break;
+ case 25:
+ p_pic_qp_c = 25;
+ break;
+ case 26:
+ p_pic_qp_c = 26;
+ break;
+ case 27:
+ p_pic_qp_c = 27;
+ break;
+ case 28:
+ p_pic_qp_c = 28;
+ break;
+ case 29:
+ p_pic_qp_c = 29;
+ break;
+ case 30:
+ p_pic_qp_c = 29;
+ break;
+ case 31:
+ p_pic_qp_c = 30;
+ break;
+ case 32:
+ p_pic_qp_c = 31;
+ break;
+ case 33:
+ p_pic_qp_c = 32;
+ break;
+ case 34:
+ p_pic_qp_c = 32;
+ break;
+ case 35:
+ p_pic_qp_c = 33;
+ break;
+ case 36:
+ p_pic_qp_c = 34;
+ break;
+ case 37:
+ p_pic_qp_c = 34;
+ break;
+ case 38:
+ p_pic_qp_c = 35;
+ break;
+ case 39:
+ p_pic_qp_c = 35;
+ break;
+ case 40:
+ p_pic_qp_c = 36;
+ break;
+ case 41:
+ p_pic_qp_c = 36;
+ break;
+ case 42:
+ p_pic_qp_c = 37;
+ break;
+ case 43:
+ p_pic_qp_c = 37;
+ break;
+ case 44:
+ p_pic_qp_c = 37;
+ break;
+ case 45:
+ p_pic_qp_c = 38;
+ break;
+ case 46:
+ p_pic_qp_c = 38;
+ break;
+ case 47:
+ p_pic_qp_c = 38;
+ break;
+ case 48:
+ p_pic_qp_c = 39;
+ break;
+ case 49:
+ p_pic_qp_c = 39;
+ break;
+ case 50:
+ p_pic_qp_c = 39;
+ break;
+ default:
+ p_pic_qp_c = 39;
+ break;
+ }
+ WRITE_HREG(HCODEC_QDCT_Q_QUANT_I,
+ (i_pic_qp_c << 22) |
+ (i_pic_qp << 16) |
+ ((i_pic_qp_c % 6) << 12) |
+ ((i_pic_qp_c / 6) << 8) |
+ ((i_pic_qp % 6) << 4) |
+ ((i_pic_qp / 6) << 0));
+
+ WRITE_HREG(HCODEC_QDCT_Q_QUANT_P,
+ (p_pic_qp_c << 22) |
+ (p_pic_qp << 16) |
+ ((p_pic_qp_c % 6) << 12) |
+ ((p_pic_qp_c / 6) << 8) |
+ ((p_pic_qp % 6) << 4) |
+ ((p_pic_qp / 6) << 0));
+
+#ifdef ENABLE_IGNORE_FUNCTION
+ WRITE_HREG(HCODEC_IGNORE_CONFIG,
+ (1 << 31) | /* ignore_lac_coeff_en */
+ (1 << 26) | /* ignore_lac_coeff_else (<1) */
+ (1 << 21) | /* ignore_lac_coeff_2 (<1) */
+ (2 << 16) | /* ignore_lac_coeff_1 (<2) */
+ (1 << 15) | /* ignore_cac_coeff_en */
+ (1 << 10) | /* ignore_cac_coeff_else (<1) */
+ (1 << 5) | /* ignore_cac_coeff_2 (<1) */
+ (3 << 0)); /* ignore_cac_coeff_1 (<2) */
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXTVBB)
+ WRITE_HREG(HCODEC_IGNORE_CONFIG_2,
+ (1 << 31) | /* ignore_t_lac_coeff_en */
+ (1 << 26) | /* ignore_t_lac_coeff_else (<1) */
+ (2 << 21) | /* ignore_t_lac_coeff_2 (<2) */
+ (6 << 16) | /* ignore_t_lac_coeff_1 (<6) */
+ (1<<15) | /* ignore_cdc_coeff_en */
+ (0<<14) | /* ignore_t_lac_coeff_else_le_3 */
+ (1<<13) | /* ignore_t_lac_coeff_else_le_4 */
+ (1<<12) | /* ignore_cdc_only_when_empty_cac_inter */
+ (1<<11) | /* ignore_cdc_only_when_one_empty_inter */
+ /* ignore_cdc_range_max_inter 0-0, 1-1, 2-2, 3-3 */
+ (2<<9) |
+ /* ignore_cdc_abs_max_inter 0-1, 1-2, 2-3, 3-4 */
+ (0<<7) |
+ /* ignore_cdc_only_when_empty_cac_intra */
+ (1<<5) |
+ /* ignore_cdc_only_when_one_empty_intra */
+ (1<<4) |
+ /* ignore_cdc_range_max_intra 0-0, 1-1, 2-2, 3-3 */
+ (1<<2) |
+ /* ignore_cdc_abs_max_intra 0-1, 1-2, 2-3, 3-4 */
+ (0<<0));
+ else
+ WRITE_HREG(HCODEC_IGNORE_CONFIG_2,
+ (1 << 31) | /* ignore_t_lac_coeff_en */
+ (1 << 26) | /* ignore_t_lac_coeff_else (<1) */
+ (1 << 21) | /* ignore_t_lac_coeff_2 (<1) */
+ (5 << 16) | /* ignore_t_lac_coeff_1 (<5) */
+ (0 << 0));
+#else
+ WRITE_HREG(HCODEC_IGNORE_CONFIG, 0);
+ WRITE_HREG(HCODEC_IGNORE_CONFIG_2, 0);
+#endif
+
+ WRITE_HREG(HCODEC_QDCT_MB_CONTROL,
+ (1 << 9) | /* mb_info_soft_reset */
+ (1 << 0)); /* mb read buffer soft reset */
+
+ WRITE_HREG(HCODEC_QDCT_MB_CONTROL,
+ (1 << 28) | /* ignore_t_p8x8 */
+ (0 << 27) | /* zero_mc_out_null_non_skipped_mb */
+ (0 << 26) | /* no_mc_out_null_non_skipped_mb */
+ (0 << 25) | /* mc_out_even_skipped_mb */
+ (0 << 24) | /* mc_out_wait_cbp_ready */
+ (0 << 23) | /* mc_out_wait_mb_type_ready */
+ (1 << 29) | /* ie_start_int_enable */
+ (1 << 19) | /* i_pred_enable */
+ (1 << 20) | /* ie_sub_enable */
+ (1 << 18) | /* iq_enable */
+ (1 << 17) | /* idct_enable */
+ (1 << 14) | /* mb_pause_enable */
+ (1 << 13) | /* q_enable */
+ (1 << 12) | /* dct_enable */
+ (1 << 10) | /* mb_info_en */
+ (0 << 3) | /* endian */
+ (0 << 1) | /* mb_read_en */
+ (0 << 0)); /* soft reset */
+
+ WRITE_HREG(HCODEC_SAD_CONTROL,
+ (0 << 3) | /* ie_result_buff_enable */
+ (1 << 2) | /* ie_result_buff_soft_reset */
+ (0 << 1) | /* sad_enable */
+ (1 << 0)); /* sad soft reset */
+ WRITE_HREG(HCODEC_IE_RESULT_BUFFER, 0);
+
+ WRITE_HREG(HCODEC_SAD_CONTROL,
+ (1 << 3) | /* ie_result_buff_enable */
+ (0 << 2) | /* ie_result_buff_soft_reset */
+ (1 << 1) | /* sad_enable */
+ (0 << 0)); /* sad soft reset */
+
+ WRITE_HREG(HCODEC_IE_CONTROL,
+ (1 << 30) | /* active_ul_block */
+ (0 << 1) | /* ie_enable */
+ (1 << 0)); /* ie soft reset */
+
+ WRITE_HREG(HCODEC_IE_CONTROL,
+ (1 << 30) | /* active_ul_block */
+ (0 << 1) | /* ie_enable */
+ (0 << 0)); /* ie soft reset */
+
+ WRITE_HREG(HCODEC_ME_SKIP_LINE,
+ (8 << 24) | /* step_3_skip_line */
+ (8 << 18) | /* step_2_skip_line */
+ (2 << 12) | /* step_1_skip_line */
+ (0 << 6) | /* step_0_skip_line */
+ (0 << 0));
+
+ WRITE_HREG(HCODEC_ME_MV_MERGE_CTL, me_mv_merge_ctl);
+ WRITE_HREG(HCODEC_ME_STEP0_CLOSE_MV, me_step0_close_mv);
+ WRITE_HREG(HCODEC_ME_SAD_ENOUGH_01, me_sad_enough_01);
+ WRITE_HREG(HCODEC_ME_SAD_ENOUGH_23, me_sad_enough_23);
+ WRITE_HREG(HCODEC_ME_F_SKIP_SAD, me_f_skip_sad);
+ WRITE_HREG(HCODEC_ME_F_SKIP_WEIGHT, me_f_skip_weight);
+ WRITE_HREG(HCODEC_ME_MV_WEIGHT_01, me_mv_weight_01);
+ WRITE_HREG(HCODEC_ME_MV_WEIGHT_23, me_mv_weight_23);
+ WRITE_HREG(HCODEC_ME_SAD_RANGE_INC, me_sad_range_inc);
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_TXL) {
+ WRITE_HREG(HCODEC_V5_SIMPLE_MB_CTL, 0);
+ WRITE_HREG(HCODEC_V5_SIMPLE_MB_CTL,
+ (v5_use_small_diff_cnt << 7) |
+ (v5_simple_mb_inter_all_en << 6) |
+ (v5_simple_mb_inter_8x8_en << 5) |
+ (v5_simple_mb_inter_16_8_en << 4) |
+ (v5_simple_mb_inter_16x16_en << 3) |
+ (v5_simple_mb_intra_en << 2) |
+ (v5_simple_mb_C_en << 1) |
+ (v5_simple_mb_Y_en << 0));
+ WRITE_HREG(HCODEC_V5_MB_DIFF_SUM, 0);
+ WRITE_HREG(HCODEC_V5_SMALL_DIFF_CNT,
+ (v5_small_diff_C<<16) |
+ (v5_small_diff_Y<<0));
+ if (qp_mode == 1) {
+ WRITE_HREG(HCODEC_V5_SIMPLE_MB_DQUANT,
+ 0);
+ } else {
+ WRITE_HREG(HCODEC_V5_SIMPLE_MB_DQUANT,
+ v5_simple_dq_setting);
+ }
+ WRITE_HREG(HCODEC_V5_SIMPLE_MB_ME_WEIGHT,
+ v5_simple_me_weight_setting);
+ /* txlx can remove it */
+ WRITE_HREG(HCODEC_QDCT_CONFIG, 1 << 0);
+ }
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXL) {
+ WRITE_HREG(HCODEC_V4_FORCE_SKIP_CFG,
+ (i_pic_qp << 26) | /* v4_force_q_r_intra */
+ (i_pic_qp << 20) | /* v4_force_q_r_inter */
+ (0 << 19) | /* v4_force_q_y_enable */
+ (5 << 16) | /* v4_force_qr_y */
+ (6 << 12) | /* v4_force_qp_y */
+ (0 << 0)); /* v4_force_skip_sad */
+
+ /* V3 Force skip */
+ WRITE_HREG(HCODEC_V3_SKIP_CONTROL,
+ (1 << 31) | /* v3_skip_enable */
+ (0 << 30) | /* v3_step_1_weight_enable */
+ (1 << 28) | /* v3_mv_sad_weight_enable */
+ (1 << 27) | /* v3_ipred_type_enable */
+ (V3_FORCE_SKIP_SAD_1 << 12) |
+ (V3_FORCE_SKIP_SAD_0 << 0));
+ WRITE_HREG(HCODEC_V3_SKIP_WEIGHT,
+ (V3_SKIP_WEIGHT_1 << 16) |
+ (V3_SKIP_WEIGHT_0 << 0));
+ WRITE_HREG(HCODEC_V3_L1_SKIP_MAX_SAD,
+ (V3_LEVEL_1_F_SKIP_MAX_SAD << 16) |
+ (V3_LEVEL_1_SKIP_MAX_SAD << 0));
+ WRITE_HREG(HCODEC_V3_L2_SKIP_WEIGHT,
+ (V3_FORCE_SKIP_SAD_2 << 16) |
+ (V3_SKIP_WEIGHT_2 << 0));
+ if (request != NULL) {
+ unsigned int off1, off2;
+
+ off1 = V3_IE_F_ZERO_SAD_I4 - I4MB_WEIGHT_OFFSET;
+ off2 = V3_IE_F_ZERO_SAD_I16
+ - I16MB_WEIGHT_OFFSET;
+ WRITE_HREG(HCODEC_V3_F_ZERO_CTL_0,
+ ((request->i16_weight + off2) << 16) |
+ ((request->i4_weight + off1) << 0));
+ off1 = V3_ME_F_ZERO_SAD - ME_WEIGHT_OFFSET;
+ WRITE_HREG(HCODEC_V3_F_ZERO_CTL_1,
+ (0 << 25) |
+ /* v3_no_ver_when_top_zero_en */
+ (0 << 24) |
+ /* v3_no_hor_when_left_zero_en */
+ (3 << 16) | /* type_hor break */
+ ((request->me_weight + off1) << 0));
+ } else {
+ WRITE_HREG(HCODEC_V3_F_ZERO_CTL_0,
+ (V3_IE_F_ZERO_SAD_I16 << 16) |
+ (V3_IE_F_ZERO_SAD_I4 << 0));
+ WRITE_HREG(HCODEC_V3_F_ZERO_CTL_1,
+ (0 << 25) |
+ /* v3_no_ver_when_top_zero_en */
+ (0 << 24) |
+ /* v3_no_hor_when_left_zero_en */
+ (3 << 16) | /* type_hor break */
+ (V3_ME_F_ZERO_SAD << 0));
+ }
+ } else if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXTVBB) {
+ /* V3 Force skip */
+ WRITE_HREG(HCODEC_V3_SKIP_CONTROL,
+ (1 << 31) | /* v3_skip_enable */
+ (0 << 30) | /* v3_step_1_weight_enable */
+ (1 << 28) | /* v3_mv_sad_weight_enable */
+ (1 << 27) | /* v3_ipred_type_enable */
+ (0 << 12) | /* V3_FORCE_SKIP_SAD_1 */
+ (0 << 0)); /* V3_FORCE_SKIP_SAD_0 */
+ WRITE_HREG(HCODEC_V3_SKIP_WEIGHT,
+ (V3_SKIP_WEIGHT_1 << 16) |
+ (V3_SKIP_WEIGHT_0 << 0));
+ WRITE_HREG(HCODEC_V3_L1_SKIP_MAX_SAD,
+ (V3_LEVEL_1_F_SKIP_MAX_SAD << 16) |
+ (V3_LEVEL_1_SKIP_MAX_SAD << 0));
+ WRITE_HREG(HCODEC_V3_L2_SKIP_WEIGHT,
+ (0 << 16) | /* V3_FORCE_SKIP_SAD_2 */
+ (V3_SKIP_WEIGHT_2 << 0));
+ WRITE_HREG(HCODEC_V3_F_ZERO_CTL_0,
+ (0 << 16) | /* V3_IE_F_ZERO_SAD_I16 */
+ (0 << 0)); /* V3_IE_F_ZERO_SAD_I4 */
+ WRITE_HREG(HCODEC_V3_F_ZERO_CTL_1,
+ (0 << 25) | /* v3_no_ver_when_top_zero_en */
+ (0 << 24) | /* v3_no_hor_when_left_zero_en */
+ (3 << 16) | /* type_hor break */
+ (0 << 0)); /* V3_ME_F_ZERO_SAD */
+ }
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXTVBB) {
+ int i;
+ /* MV SAD Table */
+ for (i = 0; i < 64; i++)
+ WRITE_HREG(HCODEC_V3_MV_SAD_TABLE,
+ v3_mv_sad[i]);
+
+ /* IE PRED SAD Table*/
+ WRITE_HREG(HCODEC_V3_IPRED_TYPE_WEIGHT_0,
+ (C_ipred_weight_H << 24) |
+ (C_ipred_weight_V << 16) |
+ (I4_ipred_weight_else << 8) |
+ (I4_ipred_weight_most << 0));
+ WRITE_HREG(HCODEC_V3_IPRED_TYPE_WEIGHT_1,
+ (I16_ipred_weight_DC << 24) |
+ (I16_ipred_weight_H << 16) |
+ (I16_ipred_weight_V << 8) |
+ (C_ipred_weight_DC << 0));
+ WRITE_HREG(HCODEC_V3_LEFT_SMALL_MAX_SAD,
+ (v3_left_small_max_me_sad << 16) |
+ (v3_left_small_max_ie_sad << 0));
+ }
+ WRITE_HREG(HCODEC_IE_DATA_FEED_BUFF_INFO, 0);
+ WRITE_HREG(HCODEC_CURR_CANVAS_CTRL, 0);
+ data32 = READ_HREG(HCODEC_VLC_CONFIG);
+ data32 = data32 | (1 << 0); /* set pop_coeff_even_all_zero */
+ WRITE_HREG(HCODEC_VLC_CONFIG, data32);
+
+ WRITE_HREG(INFO_DUMP_START_ADDR,
+ wq->mem.dump_info_ddr_start_addr);
+
+ /* clear mailbox interrupt */
+ WRITE_HREG(HCODEC_IRQ_MBOX_CLR, 1);
+
+ /* enable mailbox interrupt */
+ WRITE_HREG(HCODEC_IRQ_MBOX_MASK, 1);
+}
+
+void amvenc_reset(void)
+{
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2 &&
+ use_reset_control) {
+ hcodec_hw_reset();
+ } else {
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+ WRITE_VREG(DOS_SW_RESET1,
+ (1 << 2) | (1 << 6) |
+ (1 << 7) | (1 << 8) |
+ (1 << 14) | (1 << 16) |
+ (1 << 17));
+ WRITE_VREG(DOS_SW_RESET1, 0);
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+ }
+}
+
+void amvenc_start(void)
+{
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2 &&
+ use_reset_control) {
+ hcodec_hw_reset();
+ } else {
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+
+ WRITE_VREG(DOS_SW_RESET1,
+ (1 << 12) | (1 << 11));
+ WRITE_VREG(DOS_SW_RESET1, 0);
+
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+ }
+
+ WRITE_HREG(HCODEC_MPSR, 0x0001);
+}
+
+void amvenc_stop(void)
+{
+ ulong timeout = jiffies + HZ;
+
+ WRITE_HREG(HCODEC_MPSR, 0);
+ WRITE_HREG(HCODEC_CPSR, 0);
+
+ while (READ_HREG(HCODEC_IMEM_DMA_CTRL) & 0x8000) {
+ if (time_after(jiffies, timeout))
+ break;
+ }
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2 &&
+ use_reset_control) {
+ hcodec_hw_reset();
+ } else {
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+
+ WRITE_VREG(DOS_SW_RESET1,
+ (1 << 12) | (1 << 11) |
+ (1 << 2) | (1 << 6) |
+ (1 << 7) | (1 << 8) |
+ (1 << 14) | (1 << 16) |
+ (1 << 17));
+
+ WRITE_VREG(DOS_SW_RESET1, 0);
+
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+ }
+
+}
+
+static void __iomem *mc_addr;
+static u32 mc_addr_map;
+#define MC_SIZE (4096 * 8)
+s32 amvenc_loadmc(const char *p, struct encode_wq_s *wq)
+{
+ ulong timeout;
+ s32 ret = 0;
+
+ /* use static mempry*/
+ if (mc_addr == NULL) {
+ mc_addr = kmalloc(MC_SIZE, GFP_KERNEL);
+ if (!mc_addr) {
+ enc_pr(LOG_ERROR, "avc loadmc iomap mc addr error.\n");
+ return -ENOMEM;
+ }
+ }
+
+ enc_pr(LOG_ALL, "avc encode ucode name is %s\n", p);
+ ret = get_data_from_name(p, (u8 *)mc_addr);
+ if (ret < 0) {
+ enc_pr(LOG_ERROR,
+ "avc microcode fail ret=%d, name: %s, wq:%p.\n",
+ ret, p, (void *)wq);
+ }
+
+ mc_addr_map = dma_map_single(
+ &encode_manager.this_pdev->dev,
+ mc_addr, MC_SIZE, DMA_TO_DEVICE);
+
+ /* mc_addr_map = wq->mem.assit_buffer_offset; */
+ /* mc_addr = ioremap_wc(mc_addr_map, MC_SIZE); */
+ /* memcpy(mc_addr, p, MC_SIZE); */
+ enc_pr(LOG_ALL, "address 0 is 0x%x\n", *((u32 *)mc_addr));
+ enc_pr(LOG_ALL, "address 1 is 0x%x\n", *((u32 *)mc_addr + 1));
+ enc_pr(LOG_ALL, "address 2 is 0x%x\n", *((u32 *)mc_addr + 2));
+ enc_pr(LOG_ALL, "address 3 is 0x%x\n", *((u32 *)mc_addr + 3));
+ WRITE_HREG(HCODEC_MPSR, 0);
+ WRITE_HREG(HCODEC_CPSR, 0);
+
+ /* Read CBUS register for timing */
+ timeout = READ_HREG(HCODEC_MPSR);
+ timeout = READ_HREG(HCODEC_MPSR);
+
+ timeout = jiffies + HZ;
+
+ WRITE_HREG(HCODEC_IMEM_DMA_ADR, mc_addr_map);
+ WRITE_HREG(HCODEC_IMEM_DMA_COUNT, 0x1000);
+ WRITE_HREG(HCODEC_IMEM_DMA_CTRL, (0x8000 | (7 << 16)));
+
+ while (READ_HREG(HCODEC_IMEM_DMA_CTRL) & 0x8000) {
+ if (time_before(jiffies, timeout))
+ schedule();
+ else {
+ enc_pr(LOG_ERROR, "hcodec load mc error\n");
+ ret = -EBUSY;
+ break;
+ }
+ }
+ dma_unmap_single(
+ &encode_manager.this_pdev->dev,
+ mc_addr_map, MC_SIZE, DMA_TO_DEVICE);
+ return ret;
+}
+
+const u32 fix_mc[] __aligned(8) = {
+ 0x0809c05a, 0x06696000, 0x0c780000, 0x00000000
+};
+
+
+/*
+ * DOS top level register access fix.
+ * When hcodec is running, a protocol register HCODEC_CCPU_INTR_MSK
+ * is set to make hcodec access one CBUS out of DOS domain once
+ * to work around a HW bug for 4k2k dual decoder implementation.
+ * If hcodec is not running, then a ucode is loaded and executed
+ * instead.
+ */
+/*void amvenc_dos_top_reg_fix(void)
+{
+ bool hcodec_on;
+ ulong flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ hcodec_on = vdec_on(VDEC_HCODEC);
+
+ if ((hcodec_on) && (READ_VREG(HCODEC_MPSR) & 1)) {
+ WRITE_HREG(HCODEC_CCPU_INTR_MSK, 1);
+ spin_unlock_irqrestore(&lock, flags);
+ return;
+ }
+
+ if (!hcodec_on)
+ vdec_poweron(VDEC_HCODEC);
+
+ amhcodec_loadmc(fix_mc);
+
+ amhcodec_start();
+
+ udelay(1000);
+
+ amhcodec_stop();
+
+ if (!hcodec_on)
+ vdec_poweroff(VDEC_HCODEC);
+
+ spin_unlock_irqrestore(&lock, flags);
+}
+
+bool amvenc_avc_on(void)
+{
+ bool hcodec_on;
+ ulong flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ hcodec_on = vdec_on(VDEC_HCODEC);
+ hcodec_on &= (encode_manager.wq_count > 0);
+
+ spin_unlock_irqrestore(&lock, flags);
+ return hcodec_on;
+}
+*/
+
+static s32 avc_poweron(u32 clock)
+{
+ ulong flags;
+ u32 data32;
+
+ data32 = 0;
+
+ amports_switch_gate("vdec", 1);
+
+ spin_lock_irqsave(&lock, flags);
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+ hcodec_clk_config(1);
+ udelay(20);
+
+ pwr_ctrl_psci_smc(PDID_DOS_HCODEC, PWR_ON);
+ udelay(20);
+ pr_err("hcodec powered on, hcodec clk rate:%ld, pwr_state:%d\n",
+ clk_get_rate(s_hcodec_clks.hcodec_aclk),
+ !pwr_ctrl_status_psci_smc(PDID_DOS_HCODEC));
+ } else {
+ WRITE_AOREG(AO_RTI_PWR_CNTL_REG0,
+ (READ_AOREG(AO_RTI_PWR_CNTL_REG0) & (~0x18)));
+ udelay(10);
+ /* Powerup HCODEC */
+ /* [1:0] HCODEC */
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) &
+ ((get_cpu_type() == MESON_CPU_MAJOR_ID_SM1 ||
+ get_cpu_type() >= MESON_CPU_MAJOR_ID_TM2)
+ ? ~0x1 : ~0x3));
+
+ udelay(10);
+ }
+
+ WRITE_VREG(DOS_SW_RESET1, 0xffffffff);
+ WRITE_VREG(DOS_SW_RESET1, 0);
+
+ /* Enable Dos internal clock gating */
+ hvdec_clock_enable(clock);
+
+ /* Powerup HCODEC memories */
+ WRITE_VREG(DOS_MEM_PD_HCODEC, 0x0);
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+
+ } else {
+ /* Remove HCODEC ISO */
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) &
+ ((get_cpu_type() == MESON_CPU_MAJOR_ID_SM1 ||
+ get_cpu_type() >= MESON_CPU_MAJOR_ID_TM2)
+ ? ~0x1 : ~0x30));
+ }
+
+ udelay(10);
+ /* Disable auto-clock gate */
+ WRITE_VREG(DOS_GEN_CTRL0,
+ (READ_VREG(DOS_GEN_CTRL0) | 0x1));
+ WRITE_VREG(DOS_GEN_CTRL0,
+ (READ_VREG(DOS_GEN_CTRL0) & 0xFFFFFFFE));
+
+ spin_unlock_irqrestore(&lock, flags);
+
+ mdelay(10);
+ return 0;
+}
+
+static s32 avc_poweroff(void)
+{
+ ulong flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+ hcodec_clk_config(0);
+ udelay(20);
+ pwr_ctrl_psci_smc(PDID_DOS_HCODEC, PWR_OFF);
+ udelay(20);
+ } else {
+ /* enable HCODEC isolation */
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) |
+ ((get_cpu_type() == MESON_CPU_MAJOR_ID_SM1 ||
+ get_cpu_type() >= MESON_CPU_MAJOR_ID_TM2)
+ ? 0x1 : 0x30));
+ }
+ /* power off HCODEC memories */
+ WRITE_VREG(DOS_MEM_PD_HCODEC, 0xffffffffUL);
+
+ /* disable HCODEC clock */
+ hvdec_clock_disable();
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+
+ } else {
+ /* HCODEC power off */
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) |
+ ((get_cpu_type() == MESON_CPU_MAJOR_ID_SM1 ||
+ get_cpu_type() >= MESON_CPU_MAJOR_ID_TM2)
+ ? 0x1 : 0x3));
+ }
+
+ spin_unlock_irqrestore(&lock, flags);
+
+ /* release DOS clk81 clock gating */
+ amports_switch_gate("vdec", 0);
+ return 0;
+}
+
+static s32 reload_mc(struct encode_wq_s *wq)
+{
+ const char *p = select_ucode(encode_manager.ucode_index);
+
+ amvenc_stop();
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2 && use_reset_control) {
+ hcodec_hw_reset();
+ } else {
+ WRITE_VREG(DOS_SW_RESET1, 0xffffffff);
+ WRITE_VREG(DOS_SW_RESET1, 0);
+ }
+
+ udelay(10);
+
+ WRITE_HREG(HCODEC_ASSIST_MMC_CTRL1, 0x32);
+ enc_pr(LOG_INFO, "reload microcode\n");
+
+ if (amvenc_loadmc(p, wq) < 0)
+ return -EBUSY;
+ return 0;
+}
+
+static void encode_isr_tasklet(ulong data)
+{
+ struct encode_manager_s *manager = (struct encode_manager_s *)data;
+
+ enc_pr(LOG_INFO, "encoder is done %d\n", manager->encode_hw_status);
+ if (((manager->encode_hw_status == ENCODER_IDR_DONE)
+ || (manager->encode_hw_status == ENCODER_NON_IDR_DONE)
+ || (manager->encode_hw_status == ENCODER_SEQUENCE_DONE)
+ || (manager->encode_hw_status == ENCODER_PICTURE_DONE))
+ && (manager->process_irq)) {
+ wake_up_interruptible(&manager->event.hw_complete);
+ }
+}
+
+/* irq function */
+static irqreturn_t enc_isr(s32 irq_number, void *para)
+{
+ struct encode_manager_s *manager = (struct encode_manager_s *)para;
+
+ enc_pr(LOG_INFO, "*****ENC_ISR*****\n");
+ WRITE_HREG(HCODEC_IRQ_MBOX_CLR, 1);
+
+ manager->encode_hw_status = READ_HREG(ENCODER_STATUS);
+ if ((manager->encode_hw_status == ENCODER_IDR_DONE)
+ || (manager->encode_hw_status == ENCODER_NON_IDR_DONE)
+ || (manager->encode_hw_status == ENCODER_SEQUENCE_DONE)
+ || (manager->encode_hw_status == ENCODER_PICTURE_DONE)) {
+ enc_pr(LOG_ALL, "encoder stage is %d\n",
+ manager->encode_hw_status);
+ }
+
+ if (((manager->encode_hw_status == ENCODER_IDR_DONE)
+ || (manager->encode_hw_status == ENCODER_NON_IDR_DONE)
+ || (manager->encode_hw_status == ENCODER_SEQUENCE_DONE)
+ || (manager->encode_hw_status == ENCODER_PICTURE_DONE))
+ && (!manager->process_irq)) {
+ manager->process_irq = true;
+ if (manager->encode_hw_status != ENCODER_SEQUENCE_DONE)
+ manager->need_reset = true;
+ tasklet_schedule(&manager->encode_tasklet);
+ }
+ return IRQ_HANDLED;
+}
+
+static s32 convert_request(struct encode_wq_s *wq, u32 *cmd_info)
+{
+ int i = 0;
+ u8 *ptr;
+ u32 data_offset;
+ u32 cmd = cmd_info[0];
+ unsigned long paddr = 0;
+ struct enc_dma_cfg *cfg = NULL;
+ s32 ret = 0;
+ struct platform_device *pdev;
+
+ if (!wq)
+ return -1;
+ memset(&wq->request, 0, sizeof(struct encode_request_s));
+ wq->request.me_weight = ME_WEIGHT_OFFSET;
+ wq->request.i4_weight = I4MB_WEIGHT_OFFSET;
+ wq->request.i16_weight = I16MB_WEIGHT_OFFSET;
+
+ if (cmd == ENCODER_SEQUENCE) {
+ wq->request.cmd = cmd;
+ wq->request.ucode_mode = cmd_info[1];
+ wq->request.quant = cmd_info[2];
+ wq->request.flush_flag = cmd_info[3];
+ wq->request.timeout = cmd_info[4];
+ wq->request.timeout = 5000; /* 5000 ms */
+ } else if ((cmd == ENCODER_IDR) || (cmd == ENCODER_NON_IDR)) {
+ wq->request.cmd = cmd;
+ wq->request.ucode_mode = cmd_info[1];
+ wq->request.type = cmd_info[2];
+ wq->request.fmt = cmd_info[3];
+ wq->request.src = cmd_info[4];
+ wq->request.framesize = cmd_info[5];
+ wq->request.quant = cmd_info[6];
+ wq->request.flush_flag = cmd_info[7];
+ wq->request.timeout = cmd_info[8];
+ wq->request.crop_top = cmd_info[9];
+ wq->request.crop_bottom = cmd_info[10];
+ wq->request.crop_left = cmd_info[11];
+ wq->request.crop_right = cmd_info[12];
+ wq->request.src_w = cmd_info[13];
+ wq->request.src_h = cmd_info[14];
+ wq->request.scale_enable = cmd_info[15];
+
+ enc_pr(LOG_INFO, "hwenc: wq->pic.encoder_width %d, ",
+ wq->pic.encoder_width);
+ enc_pr(LOG_INFO, "wq->pic.encoder_height:%d, request fmt=%d\n",
+ wq->pic.encoder_height, wq->request.fmt);
+
+ if (wq->pic.encoder_width >= 1280 && wq->pic.encoder_height >= 720
+ && wq->request.fmt == FMT_RGBA8888 && wq->pic.color_space != GE2D_FORMAT_BT601) {
+ wq->request.scale_enable = 1;
+ wq->request.src_w = wq->pic.encoder_width;
+ wq->request.src_h = wq->pic.encoder_height;
+ enc_pr(LOG_INFO, "hwenc: force wq->request.scale_enable=%d\n", wq->request.scale_enable);
+ }
+
+ wq->request.nr_mode =
+ (nr_mode > 0) ? nr_mode : cmd_info[16];
+ if (cmd == ENCODER_IDR)
+ wq->request.nr_mode = 0;
+
+ data_offset = 17 +
+ (sizeof(wq->quant_tbl_i4)
+ + sizeof(wq->quant_tbl_i16)
+ + sizeof(wq->quant_tbl_me)) / 4;
+
+ if (wq->request.quant == ADJUSTED_QP_FLAG) {
+ ptr = (u8 *) &cmd_info[17];
+ memcpy(wq->quant_tbl_i4, ptr,
+ sizeof(wq->quant_tbl_i4));
+ ptr += sizeof(wq->quant_tbl_i4);
+ memcpy(wq->quant_tbl_i16, ptr,
+ sizeof(wq->quant_tbl_i16));
+ ptr += sizeof(wq->quant_tbl_i16);
+ memcpy(wq->quant_tbl_me, ptr,
+ sizeof(wq->quant_tbl_me));
+ wq->request.i4_weight -=
+ cmd_info[data_offset++];
+ wq->request.i16_weight -=
+ cmd_info[data_offset++];
+ wq->request.me_weight -=
+ cmd_info[data_offset++];
+ if (qp_table_debug) {
+ u8 *qp_tb = (u8 *)(&wq->quant_tbl_i4[0]);
+
+ for (i = 0; i < 32; i++) {
+ enc_pr(LOG_INFO, "%d ", *qp_tb);
+ qp_tb++;
+ }
+ enc_pr(LOG_INFO, "\n");
+
+ qp_tb = (u8 *)(&wq->quant_tbl_i16[0]);
+ for (i = 0; i < 32; i++) {
+ enc_pr(LOG_INFO, "%d ", *qp_tb);
+ qp_tb++;
+ }
+ enc_pr(LOG_INFO, "\n");
+
+ qp_tb = (u8 *)(&wq->quant_tbl_me[0]);
+ for (i = 0; i < 32; i++) {
+ enc_pr(LOG_INFO, "%d ", *qp_tb);
+ qp_tb++;
+ }
+ enc_pr(LOG_INFO, "\n");
+ }
+ } else {
+ memset(wq->quant_tbl_me, wq->request.quant,
+ sizeof(wq->quant_tbl_me));
+ memset(wq->quant_tbl_i4, wq->request.quant,
+ sizeof(wq->quant_tbl_i4));
+ memset(wq->quant_tbl_i16, wq->request.quant,
+ sizeof(wq->quant_tbl_i16));
+ data_offset += 3;
+ }
+#ifdef H264_ENC_CBR
+ wq->cbr_info.block_w = cmd_info[data_offset++];
+ wq->cbr_info.block_h = cmd_info[data_offset++];
+ wq->cbr_info.long_th = cmd_info[data_offset++];
+ wq->cbr_info.start_tbl_id = cmd_info[data_offset++];
+ wq->cbr_info.short_shift = CBR_SHORT_SHIFT;
+ wq->cbr_info.long_mb_num = CBR_LONG_MB_NUM;
+#endif
+ data_offset = 17 +
+ (sizeof(wq->quant_tbl_i4)
+ + sizeof(wq->quant_tbl_i16)
+ + sizeof(wq->quant_tbl_me)) / 4 + 7;
+
+ if (wq->request.type == DMA_BUFF) {
+ wq->request.plane_num = cmd_info[data_offset++];
+ enc_pr(LOG_INFO, "wq->request.plane_num %d\n",
+ wq->request.plane_num);
+ if (wq->request.fmt == FMT_NV12 ||
+ wq->request.fmt == FMT_NV21 ||
+ wq->request.fmt == FMT_YUV420) {
+ for (i = 0; i < wq->request.plane_num; i++) {
+ cfg = &wq->request.dma_cfg[i];
+ cfg->dir = DMA_TO_DEVICE;
+ cfg->fd = cmd_info[data_offset++];
+ pdev = encode_manager.this_pdev;
+ cfg->dev = &(pdev->dev);
+
+ ret = enc_dma_buf_get_phys(cfg, &paddr);
+ if (ret < 0) {
+ enc_pr(LOG_ERROR,
+ "import fd %d failed\n",
+ cfg->fd);
+ cfg->paddr = NULL;
+ cfg->vaddr = NULL;
+ return -1;
+ }
+ cfg->paddr = (void *)paddr;
+ enc_pr(LOG_INFO, "vaddr %p\n",
+ cfg->vaddr);
+ }
+ } else {
+ enc_pr(LOG_ERROR, "error fmt = %d\n",
+ wq->request.fmt);
+ }
+ }
+
+ } else {
+ enc_pr(LOG_ERROR, "error cmd = %d, wq: %p.\n",
+ cmd, (void *)wq);
+ return -1;
+ }
+ wq->request.parent = wq;
+ return 0;
+}
+
+void amvenc_avc_start_cmd(struct encode_wq_s *wq,
+ struct encode_request_s *request)
+{
+ u32 reload_flag = 0;
+
+ if (request->ucode_mode != encode_manager.ucode_index) {
+ encode_manager.ucode_index = request->ucode_mode;
+ if (reload_mc(wq)) {
+ enc_pr(LOG_ERROR,
+ "reload mc fail, wq:%p\n", (void *)wq);
+ return;
+ }
+ reload_flag = 1;
+ encode_manager.need_reset = true;
+ }
+
+ wq->hw_status = 0;
+ wq->output_size = 0;
+ wq->ucode_index = encode_manager.ucode_index;
+
+ ie_me_mode = (0 & ME_PIXEL_MODE_MASK) << ME_PIXEL_MODE_SHIFT;
+
+ if (encode_manager.need_reset) {
+ amvenc_stop();
+ reload_flag = 1;
+ encode_manager.need_reset = false;
+ encode_manager.encode_hw_status = ENCODER_IDLE;
+ amvenc_reset();
+ avc_canvas_init(wq);
+ avc_init_encoder(wq, (request->cmd == ENCODER_IDR) ? true : false);
+ avc_init_input_buffer(wq);
+ avc_init_output_buffer(wq);
+
+ avc_prot_init(
+ wq, request, request->quant,
+ (request->cmd == ENCODER_IDR) ? true : false);
+
+ avc_init_assit_buffer(wq);
+
+ enc_pr(LOG_INFO,
+ "begin to new frame, request->cmd: %d, ucode mode: %d, wq:%p\n",
+ request->cmd, request->ucode_mode, (void *)wq);
+ }
+
+ if ((request->cmd == ENCODER_IDR) ||
+ (request->cmd == ENCODER_NON_IDR)) {
+#ifdef H264_ENC_SVC
+ /* encode non reference frame or not */
+ if (request->cmd == ENCODER_IDR)
+ wq->pic.non_ref_cnt = 0; //IDR reset counter
+
+ if (wq->pic.enable_svc && wq->pic.non_ref_cnt) {
+ enc_pr(LOG_INFO,
+ "PIC is NON REF cmd %d cnt %d value 0x%x\n",
+ request->cmd, wq->pic.non_ref_cnt,
+ ENC_SLC_NON_REF);
+ WRITE_HREG(H264_ENC_SVC_PIC_TYPE, ENC_SLC_NON_REF);
+ } else {
+ enc_pr(LOG_INFO,
+ "PIC is REF cmd %d cnt %d val 0x%x\n",
+ request->cmd, wq->pic.non_ref_cnt,
+ ENC_SLC_REF);
+ WRITE_HREG(H264_ENC_SVC_PIC_TYPE, ENC_SLC_REF);
+ }
+#else
+ /* if FW defined but not defined SVC in driver here*/
+ WRITE_HREG(H264_ENC_SVC_PIC_TYPE, ENC_SLC_REF);
+#endif
+ avc_init_dblk_buffer(wq->mem.dblk_buf_canvas);
+ avc_init_reference_buffer(wq->mem.ref_buf_canvas);
+ }
+ if ((request->cmd == ENCODER_IDR) ||
+ (request->cmd == ENCODER_NON_IDR))
+ set_input_format(wq, request);
+
+ if (request->cmd == ENCODER_IDR)
+ ie_me_mb_type = HENC_MB_Type_I4MB;
+ else if (request->cmd == ENCODER_NON_IDR)
+ ie_me_mb_type =
+ (HENC_SKIP_RUN_AUTO << 16) |
+ (HENC_MB_Type_AUTO << 4) |
+ (HENC_MB_Type_AUTO << 0);
+ else
+ ie_me_mb_type = 0;
+ avc_init_ie_me_parameter(wq, request->quant);
+
+#ifdef MULTI_SLICE_MC
+ if (fixed_slice_cfg)
+ WRITE_HREG(FIXED_SLICE_CFG, fixed_slice_cfg);
+ else if (wq->pic.rows_per_slice !=
+ (wq->pic.encoder_height + 15) >> 4) {
+ u32 mb_per_slice = (wq->pic.encoder_height + 15) >> 4;
+
+ mb_per_slice = mb_per_slice * wq->pic.rows_per_slice;
+ WRITE_HREG(FIXED_SLICE_CFG, mb_per_slice);
+ } else
+ WRITE_HREG(FIXED_SLICE_CFG, 0);
+#else
+ WRITE_HREG(FIXED_SLICE_CFG, 0);
+#endif
+
+ encode_manager.encode_hw_status = request->cmd;
+ wq->hw_status = request->cmd;
+ WRITE_HREG(ENCODER_STATUS, request->cmd);
+ if ((request->cmd == ENCODER_IDR)
+ || (request->cmd == ENCODER_NON_IDR)
+ || (request->cmd == ENCODER_SEQUENCE)
+ || (request->cmd == ENCODER_PICTURE))
+ encode_manager.process_irq = false;
+
+ if (reload_flag)
+ amvenc_start();
+ enc_pr(LOG_ALL, "amvenc_avc_start cmd out, request:%p.\n", (void*)request);
+}
+
+static void dma_flush(u32 buf_start, u32 buf_size)
+{
+ if ((buf_start == 0) || (buf_size == 0))
+ return;
+ dma_sync_single_for_device(
+ &encode_manager.this_pdev->dev, buf_start,
+ buf_size, DMA_TO_DEVICE);
+}
+
+static void cache_flush(u32 buf_start, u32 buf_size)
+{
+ if ((buf_start == 0) || (buf_size == 0))
+ return;
+ dma_sync_single_for_cpu(
+ &encode_manager.this_pdev->dev, buf_start,
+ buf_size, DMA_FROM_DEVICE);
+}
+
+static u32 getbuffer(struct encode_wq_s *wq, u32 type)
+{
+ u32 ret = 0;
+
+ switch (type) {
+ case ENCODER_BUFFER_INPUT:
+ ret = wq->mem.dct_buff_start_addr;
+ break;
+ case ENCODER_BUFFER_REF0:
+ ret = wq->mem.dct_buff_start_addr +
+ wq->mem.bufspec.dec0_y.buf_start;
+ break;
+ case ENCODER_BUFFER_REF1:
+ ret = wq->mem.dct_buff_start_addr +
+ wq->mem.bufspec.dec1_y.buf_start;
+ break;
+ case ENCODER_BUFFER_OUTPUT:
+ ret = wq->mem.BitstreamStart;
+ break;
+ case ENCODER_BUFFER_DUMP:
+ ret = wq->mem.dump_info_ddr_start_addr;
+ break;
+ case ENCODER_BUFFER_CBR:
+ ret = wq->mem.cbr_info_ddr_start_addr;
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+s32 amvenc_avc_start(struct encode_wq_s *wq, u32 clock)
+{
+ const char *p = select_ucode(encode_manager.ucode_index);
+
+ avc_poweron(clock);
+ avc_canvas_init(wq);
+
+ WRITE_HREG(HCODEC_ASSIST_MMC_CTRL1, 0x32);
+
+ if (amvenc_loadmc(p, wq) < 0)
+ return -EBUSY;
+
+ encode_manager.need_reset = true;
+ encode_manager.process_irq = false;
+ encode_manager.encode_hw_status = ENCODER_IDLE;
+ amvenc_reset();
+ avc_init_encoder(wq, true);
+ avc_init_input_buffer(wq); /* dct buffer setting */
+ avc_init_output_buffer(wq); /* output stream buffer */
+
+ ie_me_mode = (0 & ME_PIXEL_MODE_MASK) << ME_PIXEL_MODE_SHIFT;
+ avc_prot_init(wq, NULL, wq->pic.init_qppicture, true);
+
+ if (request_irq(encode_manager.irq_num, enc_isr, IRQF_SHARED,
+ "enc-irq", (void *)&encode_manager) == 0)
+ encode_manager.irq_requested = true;
+ else
+ encode_manager.irq_requested = false;
+
+ /* decoder buffer , need set before each frame start */
+ avc_init_dblk_buffer(wq->mem.dblk_buf_canvas);
+ /* reference buffer , need set before each frame start */
+ avc_init_reference_buffer(wq->mem.ref_buf_canvas);
+ avc_init_assit_buffer(wq); /* assitant buffer for microcode */
+ ie_me_mb_type = 0;
+ avc_init_ie_me_parameter(wq, wq->pic.init_qppicture);
+ WRITE_HREG(ENCODER_STATUS, ENCODER_IDLE);
+
+#ifdef MULTI_SLICE_MC
+ if (fixed_slice_cfg)
+ WRITE_HREG(FIXED_SLICE_CFG, fixed_slice_cfg);
+ else if (wq->pic.rows_per_slice !=
+ (wq->pic.encoder_height + 15) >> 4) {
+ u32 mb_per_slice = (wq->pic.encoder_height + 15) >> 4;
+
+ mb_per_slice = mb_per_slice * wq->pic.rows_per_slice;
+ WRITE_HREG(FIXED_SLICE_CFG, mb_per_slice);
+ } else
+ WRITE_HREG(FIXED_SLICE_CFG, 0);
+#else
+ WRITE_HREG(FIXED_SLICE_CFG, 0);
+#endif
+ amvenc_start();
+ return 0;
+}
+
+void amvenc_avc_stop(void)
+{
+ if ((encode_manager.irq_num >= 0) &&
+ (encode_manager.irq_requested == true)) {
+ free_irq(encode_manager.irq_num, &encode_manager);
+ encode_manager.irq_requested = false;
+ }
+ amvenc_stop();
+ avc_poweroff();
+}
+
+static s32 avc_init(struct encode_wq_s *wq)
+{
+ s32 r = 0;
+
+ encode_manager.ucode_index = wq->ucode_index;
+ r = amvenc_avc_start(wq, clock_level);
+
+ enc_pr(LOG_DEBUG,
+ "init avc encode. microcode %d, ret=%d, wq:%px\n",
+ encode_manager.ucode_index, r, (void *)wq);
+ return 0;
+}
+
+static s32 amvenc_avc_light_reset(struct encode_wq_s *wq, u32 value)
+{
+ s32 r = 0;
+
+ amvenc_avc_stop();
+
+ mdelay(value);
+
+ encode_manager.ucode_index = UCODE_MODE_FULL;
+ r = amvenc_avc_start(wq, clock_level);
+
+ enc_pr(LOG_DEBUG,
+ "amvenc_avc_light_reset finish, wq:%px, ret=%d\n",
+ (void *)wq, r);
+ return r;
+}
+
+#ifdef CONFIG_CMA
+static u32 checkCMA(void)
+{
+ u32 ret;
+
+ if (encode_manager.cma_pool_size > 0) {
+ ret = encode_manager.cma_pool_size;
+ ret = ret / MIN_SIZE;
+ } else
+ ret = 0;
+ return ret;
+}
+#endif
+
+/* file operation */
+static s32 amvenc_avc_open(struct inode *inode, struct file *file)
+{
+ s32 r = 0;
+ struct encode_wq_s *wq = NULL;
+
+ file->private_data = NULL;
+ enc_pr(LOG_DEBUG, "avc open\n");
+#ifdef CONFIG_AM_JPEG_ENCODER
+ if (jpegenc_on() == true) {
+ enc_pr(LOG_ERROR,
+ "hcodec in use for JPEG Encode now.\n");
+ return -EBUSY;
+ }
+#endif
+
+#ifdef CONFIG_CMA
+ if ((encode_manager.use_reserve == false) &&
+ (encode_manager.check_cma == false)) {
+ encode_manager.max_instance = checkCMA();
+ if (encode_manager.max_instance > 0) {
+ enc_pr(LOG_DEBUG,
+ "amvenc_avc check CMA pool success, max instance: %d.\n",
+ encode_manager.max_instance);
+ } else {
+ enc_pr(LOG_ERROR,
+ "amvenc_avc CMA pool too small.\n");
+ }
+ encode_manager.check_cma = true;
+ }
+#endif
+
+ wq = create_encode_work_queue();
+ if (wq == NULL) {
+ enc_pr(LOG_ERROR, "amvenc_avc create instance fail.\n");
+ return -EBUSY;
+ }
+
+#ifdef CONFIG_CMA
+ if (encode_manager.use_reserve == false) {
+ wq->mem.buf_start = codec_mm_alloc_for_dma(ENCODE_NAME,
+ MIN_SIZE >> PAGE_SHIFT, 0,
+ CODEC_MM_FLAGS_CPU);
+ if (wq->mem.buf_start) {
+ wq->mem.buf_size = MIN_SIZE;
+ enc_pr(LOG_DEBUG,
+ "allocating phys 0x%x, size %dk, wq:%p.\n",
+ wq->mem.buf_start,
+ wq->mem.buf_size >> 10, (void *)wq);
+ } else {
+ enc_pr(LOG_ERROR,
+ "CMA failed to allocate dma buffer for %s, wq:%p.\n",
+ encode_manager.this_pdev->name,
+ (void *)wq);
+ destroy_encode_work_queue(wq);
+ return -ENOMEM;
+ }
+ }
+#endif
+
+ if (wq->mem.buf_start == 0 ||
+ wq->mem.buf_size < MIN_SIZE) {
+ enc_pr(LOG_ERROR,
+ "alloc mem failed, start: 0x%x, size:0x%x, wq:%p.\n",
+ wq->mem.buf_start,
+ wq->mem.buf_size, (void *)wq);
+ destroy_encode_work_queue(wq);
+ return -ENOMEM;
+ }
+
+ memcpy(&wq->mem.bufspec, &amvenc_buffspec[0],
+ sizeof(struct BuffInfo_s));
+
+ enc_pr(LOG_DEBUG,
+ "amvenc_avc memory config success, buff start:0x%x, size is 0x%x, wq:%p.\n",
+ wq->mem.buf_start, wq->mem.buf_size, (void *)wq);
+
+ file->private_data = (void *) wq;
+ return r;
+}
+
+static s32 amvenc_avc_release(struct inode *inode, struct file *file)
+{
+ struct encode_wq_s *wq = (struct encode_wq_s *)file->private_data;
+
+ if (wq) {
+ enc_pr(LOG_DEBUG, "avc release, wq:%p\n", (void *)wq);
+ destroy_encode_work_queue(wq);
+ }
+ return 0;
+}
+
+static long amvenc_avc_ioctl(struct file *file, u32 cmd, ulong arg)
+{
+ long r = 0;
+ u32 amrisc_cmd = 0;
+ struct encode_wq_s *wq = (struct encode_wq_s *)file->private_data;
+#define MAX_ADDR_INFO_SIZE 52
+ u32 addr_info[MAX_ADDR_INFO_SIZE + 4];
+ ulong argV;
+ u32 buf_start;
+ s32 canvas = -1;
+ struct canvas_s dst;
+
+ switch (cmd) {
+ case AMVENC_AVC_IOC_GET_ADDR:
+ if ((wq->mem.ref_buf_canvas & 0xff) == (ENC_CANVAS_OFFSET))
+ put_user(1, (u32 *)arg);
+ else
+ put_user(2, (u32 *)arg);
+ break;
+ case AMVENC_AVC_IOC_INPUT_UPDATE:
+ break;
+ case AMVENC_AVC_IOC_NEW_CMD:
+ if (copy_from_user(addr_info, (void *)arg,
+ MAX_ADDR_INFO_SIZE * sizeof(u32))) {
+ enc_pr(LOG_ERROR,
+ "avc get new cmd error, wq:%p.\n", (void *)wq);
+ return -1;
+ }
+ r = convert_request(wq, addr_info);
+ if (r == 0)
+ r = encode_wq_add_request(wq);
+ if (r) {
+ enc_pr(LOG_ERROR,
+ "avc add new request error, wq:%p.\n",
+ (void *)wq);
+ }
+ break;
+ case AMVENC_AVC_IOC_GET_STAGE:
+ put_user(wq->hw_status, (u32 *)arg);
+ break;
+ case AMVENC_AVC_IOC_GET_OUTPUT_SIZE:
+ addr_info[0] = wq->output_size;
+ addr_info[1] = wq->me_weight;
+ addr_info[2] = wq->i4_weight;
+ addr_info[3] = wq->i16_weight;
+ r = copy_to_user((u32 *)arg,
+ addr_info, 4 * sizeof(u32));
+ break;
+ case AMVENC_AVC_IOC_CONFIG_INIT:
+ if (copy_from_user(addr_info, (void *)arg,
+ MAX_ADDR_INFO_SIZE * sizeof(u32))) {
+ enc_pr(LOG_ERROR,
+ "avc config init error, wq:%p.\n", (void *)wq);
+ return -1;
+ }
+ wq->ucode_index = UCODE_MODE_FULL;
+#ifdef MULTI_SLICE_MC
+ wq->pic.rows_per_slice = addr_info[1];
+ enc_pr(LOG_DEBUG,
+ "avc init -- rows_per_slice: %d, wq: %p.\n",
+ wq->pic.rows_per_slice, (void *)wq);
+#endif
+ enc_pr(LOG_DEBUG,
+ "avc init as mode %d, wq: %px.\n",
+ wq->ucode_index, (void *)wq);
+
+ if (addr_info[2] > wq->mem.bufspec.max_width ||
+ addr_info[3] > wq->mem.bufspec.max_height) {
+ enc_pr(LOG_ERROR,
+ "avc config init- encode size %dx%d is larger than supported (%dx%d). wq:%p.\n",
+ addr_info[2], addr_info[3],
+ wq->mem.bufspec.max_width,
+ wq->mem.bufspec.max_height, (void *)wq);
+ return -1;
+ }
+ pr_err("hwenc: AMVENC_AVC_IOC_CONFIG_INIT: w:%d, h:%d\n", wq->pic.encoder_width, wq->pic.encoder_height);
+ wq->pic.encoder_width = addr_info[2];
+ wq->pic.encoder_height = addr_info[3];
+
+ wq->pic.color_space = addr_info[4];
+ pr_err("hwenc: AMVENC_AVC_IOC_CONFIG_INIT, wq->pic.color_space=%#x\n", wq->pic.color_space);
+ if (wq->pic.encoder_width *
+ wq->pic.encoder_height >= 1280 * 720)
+ clock_level = 6;
+ else
+ clock_level = 5;
+ avc_buffspec_init(wq);
+ complete(&encode_manager.event.request_in_com);
+ addr_info[1] = wq->mem.bufspec.dct.buf_start;
+ addr_info[2] = wq->mem.bufspec.dct.buf_size;
+ addr_info[3] = wq->mem.bufspec.bitstream.buf_start;
+ addr_info[4] = wq->mem.bufspec.bitstream.buf_size;
+ addr_info[5] = wq->mem.bufspec.scale_buff.buf_start;
+ addr_info[6] = wq->mem.bufspec.scale_buff.buf_size;
+ addr_info[7] = wq->mem.bufspec.dump_info.buf_start;
+ addr_info[8] = wq->mem.bufspec.dump_info.buf_size;
+ addr_info[9] = wq->mem.bufspec.cbr_info.buf_start;
+ addr_info[10] = wq->mem.bufspec.cbr_info.buf_size;
+ r = copy_to_user((u32 *)arg, addr_info, 11*sizeof(u32));
+ break;
+ case AMVENC_AVC_IOC_FLUSH_CACHE:
+ if (copy_from_user(addr_info, (void *)arg,
+ MAX_ADDR_INFO_SIZE * sizeof(u32))) {
+ enc_pr(LOG_ERROR,
+ "avc flush cache error, wq: %p.\n", (void *)wq);
+ return -1;
+ }
+ buf_start = getbuffer(wq, addr_info[0]);
+ dma_flush(buf_start + addr_info[1],
+ addr_info[2] - addr_info[1]);
+ break;
+ case AMVENC_AVC_IOC_FLUSH_DMA:
+ if (copy_from_user(addr_info, (void *)arg,
+ MAX_ADDR_INFO_SIZE * sizeof(u32))) {
+ enc_pr(LOG_ERROR,
+ "avc flush dma error, wq:%p.\n", (void *)wq);
+ return -1;
+ }
+ buf_start = getbuffer(wq, addr_info[0]);
+ cache_flush(buf_start + addr_info[1],
+ addr_info[2] - addr_info[1]);
+ break;
+ case AMVENC_AVC_IOC_GET_BUFFINFO:
+ put_user(wq->mem.buf_size, (u32 *)arg);
+ break;
+ case AMVENC_AVC_IOC_GET_DEVINFO:
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXL) {
+ /* send the same id as GXTVBB to upper*/
+ r = copy_to_user((s8 *)arg, AMVENC_DEVINFO_GXTVBB,
+ strlen(AMVENC_DEVINFO_GXTVBB));
+ } else if (get_cpu_type() == MESON_CPU_MAJOR_ID_GXTVBB) {
+ r = copy_to_user((s8 *)arg, AMVENC_DEVINFO_GXTVBB,
+ strlen(AMVENC_DEVINFO_GXTVBB));
+ } else if (get_cpu_type() == MESON_CPU_MAJOR_ID_GXBB) {
+ r = copy_to_user((s8 *)arg, AMVENC_DEVINFO_GXBB,
+ strlen(AMVENC_DEVINFO_GXBB));
+ } else if (get_cpu_type() == MESON_CPU_MAJOR_ID_MG9TV) {
+ r = copy_to_user((s8 *)arg, AMVENC_DEVINFO_G9,
+ strlen(AMVENC_DEVINFO_G9));
+ } else {
+ r = copy_to_user((s8 *)arg, AMVENC_DEVINFO_M8,
+ strlen(AMVENC_DEVINFO_M8));
+ }
+ break;
+ case AMVENC_AVC_IOC_SUBMIT:
+ get_user(amrisc_cmd, ((u32 *)arg));
+ if (amrisc_cmd == ENCODER_IDR) {
+ wq->pic.idr_pic_id++;
+ if (wq->pic.idr_pic_id > 65535)
+ wq->pic.idr_pic_id = 0;
+ wq->pic.pic_order_cnt_lsb = 2;
+ wq->pic.frame_number = 1;
+ } else if (amrisc_cmd == ENCODER_NON_IDR) {
+#ifdef H264_ENC_SVC
+ /* only update when there is reference frame */
+ if (wq->pic.enable_svc == 0 || wq->pic.non_ref_cnt == 0) {
+ wq->pic.frame_number++;
+ enc_pr(LOG_INFO, "Increase frame_num to %d\n",
+ wq->pic.frame_number);
+ }
+#else
+ wq->pic.frame_number++;
+#endif
+
+ wq->pic.pic_order_cnt_lsb += 2;
+ if (wq->pic.frame_number > 65535)
+ wq->pic.frame_number = 0;
+ }
+#ifdef H264_ENC_SVC
+ /* only update when there is reference frame */
+ if (wq->pic.enable_svc == 0 || wq->pic.non_ref_cnt == 0) {
+ amrisc_cmd = wq->mem.dblk_buf_canvas;
+ wq->mem.dblk_buf_canvas = wq->mem.ref_buf_canvas;
+ /* current dblk buffer as next reference buffer */
+ wq->mem.ref_buf_canvas = amrisc_cmd;
+ enc_pr(LOG_INFO,
+ "switch buffer enable %d cnt %d\n",
+ wq->pic.enable_svc, wq->pic.non_ref_cnt);
+ }
+ if (wq->pic.enable_svc) {
+ wq->pic.non_ref_cnt ++;
+ if (wq->pic.non_ref_cnt > wq->pic.non_ref_limit) {
+ enc_pr(LOG_INFO, "Svc clear cnt %d conf %d\n",
+ wq->pic.non_ref_cnt,
+ wq->pic.non_ref_limit);
+ wq->pic.non_ref_cnt = 0;
+ } else
+ enc_pr(LOG_INFO,"Svc increase non ref counter to %d\n",
+ wq->pic.non_ref_cnt );
+ }
+#else
+ amrisc_cmd = wq->mem.dblk_buf_canvas;
+ wq->mem.dblk_buf_canvas = wq->mem.ref_buf_canvas;
+ /* current dblk buffer as next reference buffer */
+ wq->mem.ref_buf_canvas = amrisc_cmd;
+#endif
+ break;
+ case AMVENC_AVC_IOC_READ_CANVAS:
+ get_user(argV, ((u32 *)arg));
+ canvas = argV;
+ if (canvas & 0xff) {
+ canvas_read(canvas & 0xff, &dst);
+ addr_info[0] = dst.addr;
+ if ((canvas & 0xff00) >> 8)
+ canvas_read((canvas & 0xff00) >> 8, &dst);
+ if ((canvas & 0xff0000) >> 16)
+ canvas_read((canvas & 0xff0000) >> 16, &dst);
+ addr_info[1] = dst.addr - addr_info[0] +
+ dst.width * dst.height;
+ } else {
+ addr_info[0] = 0;
+ addr_info[1] = 0;
+ }
+ dma_flush(dst.addr, dst.width * dst.height * 3 / 2);
+ r = copy_to_user((u32 *)arg, addr_info, 2 * sizeof(u32));
+ break;
+ case AMVENC_AVC_IOC_MAX_INSTANCE:
+ put_user(encode_manager.max_instance, (u32 *)arg);
+ break;
+ case AMVENC_AVC_IOC_QP_MODE:
+ get_user(qp_mode, ((u32 *)arg));
+ pr_info("qp_mode %d\n", qp_mode);
+ break;
+ default:
+ r = -1;
+ break;
+ }
+ return r;
+}
+
+#ifdef CONFIG_COMPAT
+static long amvenc_avc_compat_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long args)
+{
+ unsigned long ret;
+
+ args = (unsigned long)compat_ptr(args);
+ ret = amvenc_avc_ioctl(filp, cmd, args);
+ return ret;
+}
+#endif
+
+static s32 avc_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct encode_wq_s *wq = (struct encode_wq_s *)filp->private_data;
+ ulong off = vma->vm_pgoff << PAGE_SHIFT;
+ ulong vma_size = vma->vm_end - vma->vm_start;
+
+ if (vma_size == 0) {
+ enc_pr(LOG_ERROR, "vma_size is 0, wq:%p.\n", (void *)wq);
+ return -EAGAIN;
+ }
+ if (!off)
+ off += wq->mem.buf_start;
+ enc_pr(LOG_ALL,
+ "vma_size is %ld , off is %ld, wq:%p.\n",
+ vma_size, off, (void *)wq);
+ vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP | VM_IO;
+ /* vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); */
+ if (remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
+ enc_pr(LOG_ERROR,
+ "set_cached: failed remap_pfn_range, wq:%p.\n",
+ (void *)wq);
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+static u32 amvenc_avc_poll(struct file *file, poll_table *wait_table)
+{
+ struct encode_wq_s *wq = (struct encode_wq_s *)file->private_data;
+
+ poll_wait(file, &wq->request_complete, wait_table);
+
+ if (atomic_read(&wq->request_ready)) {
+ atomic_dec(&wq->request_ready);
+ return POLLIN | POLLRDNORM;
+ }
+
+ return 0;
+}
+
+static const struct file_operations amvenc_avc_fops = {
+ .owner = THIS_MODULE,
+ .open = amvenc_avc_open,
+ .mmap = avc_mmap,
+ .release = amvenc_avc_release,
+ .unlocked_ioctl = amvenc_avc_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = amvenc_avc_compat_ioctl,
+#endif
+ .poll = amvenc_avc_poll,
+};
+
+/* work queue function */
+static s32 encode_process_request(struct encode_manager_s *manager,
+ struct encode_queue_item_s *pitem)
+{
+ s32 ret = 0;
+ struct encode_wq_s *wq = pitem->request.parent;
+ struct encode_request_s *request = &pitem->request;
+
+ u32 timeout = (request->timeout == 0) ?
+ 1 : msecs_to_jiffies(request->timeout);
+
+ u32 buf_start = 0;
+ u32 size = 0;
+ u32 flush_size = ((wq->pic.encoder_width + 31) >> 5 << 5) *
+ ((wq->pic.encoder_height + 15) >> 4 << 4) * 3 / 2;
+
+ struct enc_dma_cfg *cfg = NULL;
+ int i = 0;
+
+#ifdef H264_ENC_CBR
+ if (request->cmd == ENCODER_IDR || request->cmd == ENCODER_NON_IDR) {
+ if (request->flush_flag & AMVENC_FLUSH_FLAG_CBR
+ && get_cpu_type() >= MESON_CPU_MAJOR_ID_GXTVBB) {
+ void *vaddr = wq->mem.cbr_info_ddr_virt_addr;
+ ConvertTable2Risc(vaddr, 0xa00);
+ buf_start = getbuffer(wq, ENCODER_BUFFER_CBR);
+ codec_mm_dma_flush(vaddr, wq->mem.cbr_info_ddr_size, DMA_TO_DEVICE);
+ }
+ }
+#endif
+
+Again:
+ amvenc_avc_start_cmd(wq, request);
+
+ if (no_timeout) {
+ wait_event_interruptible(manager->event.hw_complete,
+ (manager->encode_hw_status == ENCODER_IDR_DONE
+ || manager->encode_hw_status == ENCODER_NON_IDR_DONE
+ || manager->encode_hw_status == ENCODER_SEQUENCE_DONE
+ || manager->encode_hw_status == ENCODER_PICTURE_DONE));
+ } else {
+ wait_event_interruptible_timeout(manager->event.hw_complete,
+ ((manager->encode_hw_status == ENCODER_IDR_DONE)
+ || (manager->encode_hw_status == ENCODER_NON_IDR_DONE)
+ || (manager->encode_hw_status == ENCODER_SEQUENCE_DONE)
+ || (manager->encode_hw_status == ENCODER_PICTURE_DONE)),
+ timeout);
+ }
+
+ if ((request->cmd == ENCODER_SEQUENCE) &&
+ (manager->encode_hw_status == ENCODER_SEQUENCE_DONE)) {
+ wq->sps_size = READ_HREG(HCODEC_VLC_TOTAL_BYTES);
+ wq->hw_status = manager->encode_hw_status;
+ request->cmd = ENCODER_PICTURE;
+ goto Again;
+ } else if ((request->cmd == ENCODER_PICTURE) &&
+ (manager->encode_hw_status == ENCODER_PICTURE_DONE)) {
+ wq->pps_size =
+ READ_HREG(HCODEC_VLC_TOTAL_BYTES) - wq->sps_size;
+ wq->hw_status = manager->encode_hw_status;
+ if (request->flush_flag & AMVENC_FLUSH_FLAG_OUTPUT) {
+ buf_start = getbuffer(wq, ENCODER_BUFFER_OUTPUT);
+ cache_flush(buf_start,
+ wq->sps_size + wq->pps_size);
+ }
+ wq->output_size = (wq->sps_size << 16) | wq->pps_size;
+ } else {
+ wq->hw_status = manager->encode_hw_status;
+
+ if ((manager->encode_hw_status == ENCODER_IDR_DONE) ||
+ (manager->encode_hw_status == ENCODER_NON_IDR_DONE)) {
+ wq->output_size = READ_HREG(HCODEC_VLC_TOTAL_BYTES);
+
+ if (request->flush_flag & AMVENC_FLUSH_FLAG_OUTPUT) {
+ buf_start = getbuffer(wq, ENCODER_BUFFER_OUTPUT);
+ cache_flush(buf_start, wq->output_size);
+ }
+
+ if (request->flush_flag & AMVENC_FLUSH_FLAG_DUMP) {
+ buf_start = getbuffer(wq, ENCODER_BUFFER_DUMP);
+ size = wq->mem.dump_info_ddr_size;
+ cache_flush(buf_start, size);
+ //enc_pr(LOG_DEBUG, "CBR flush dump_info done");
+ }
+
+ if (request->flush_flag & AMVENC_FLUSH_FLAG_REFERENCE) {
+ u32 ref_id = ENCODER_BUFFER_REF0;
+
+ if ((wq->mem.ref_buf_canvas & 0xff) == (ENC_CANVAS_OFFSET))
+ ref_id = ENCODER_BUFFER_REF0;
+ else
+ ref_id = ENCODER_BUFFER_REF1;
+
+ buf_start = getbuffer(wq, ref_id);
+ cache_flush(buf_start, flush_size);
+ }
+ } else {
+ manager->encode_hw_status = ENCODER_ERROR;
+ enc_pr(LOG_DEBUG, "avc encode light reset --- ");
+ enc_pr(LOG_DEBUG,
+ "frame type: %s, size: %dx%d, wq: %px\n",
+ (request->cmd == ENCODER_IDR) ? "IDR" : "P",
+ wq->pic.encoder_width,
+ wq->pic.encoder_height, (void *)wq);
+ enc_pr(LOG_DEBUG,
+ "mb info: 0x%x, encode status: 0x%x, dct status: 0x%x ",
+ READ_HREG(HCODEC_VLC_MB_INFO),
+ READ_HREG(ENCODER_STATUS),
+ READ_HREG(HCODEC_QDCT_STATUS_CTRL));
+ enc_pr(LOG_DEBUG,
+ "vlc status: 0x%x, me status: 0x%x, risc pc:0x%x, debug:0x%x\n",
+ READ_HREG(HCODEC_VLC_STATUS_CTRL),
+ READ_HREG(HCODEC_ME_STATUS),
+ READ_HREG(HCODEC_MPC_E),
+ READ_HREG(DEBUG_REG));
+ amvenc_avc_light_reset(wq, 30);
+ }
+
+ for (i = 0; i < request->plane_num; i++) {
+ cfg = &request->dma_cfg[i];
+ enc_pr(LOG_INFO, "request vaddr %p, paddr %p\n",
+ cfg->vaddr, cfg->paddr);
+ if (cfg->fd >= 0 && cfg->vaddr != NULL)
+ enc_dma_buf_unmap(cfg);
+ }
+ }
+ atomic_inc(&wq->request_ready);
+ wake_up_interruptible(&wq->request_complete);
+ return ret;
+}
+
+s32 encode_wq_add_request(struct encode_wq_s *wq)
+{
+ struct encode_queue_item_s *pitem = NULL;
+ struct list_head *head = NULL;
+ struct encode_wq_s *tmp = NULL;
+ bool find = false;
+
+ spin_lock(&encode_manager.event.sem_lock);
+
+ head = &encode_manager.wq;
+ list_for_each_entry(tmp, head, list) {
+ if ((wq == tmp) && (wq != NULL)) {
+ find = true;
+ break;
+ }
+ }
+
+ if (find == false) {
+ enc_pr(LOG_ERROR, "current wq (%p) doesn't register.\n",
+ (void *)wq);
+ goto error;
+ }
+
+ if (list_empty(&encode_manager.free_queue)) {
+ enc_pr(LOG_ERROR, "work queue no space, wq:%p.\n",
+ (void *)wq);
+ goto error;
+ }
+
+ pitem = list_entry(encode_manager.free_queue.next,
+ struct encode_queue_item_s, list);
+
+ if (IS_ERR(pitem))
+ goto error;
+
+ memcpy(&pitem->request, &wq->request, sizeof(struct encode_request_s));
+
+ enc_pr(LOG_INFO, "new work request %p, vaddr %p, paddr %p\n", &pitem->request,
+ pitem->request.dma_cfg[0].vaddr,pitem->request.dma_cfg[0].paddr);
+
+ memset(&wq->request, 0, sizeof(struct encode_request_s));
+ wq->request.dma_cfg[0].fd = -1;
+ wq->request.dma_cfg[1].fd = -1;
+ wq->request.dma_cfg[2].fd = -1;
+ wq->hw_status = 0;
+ wq->output_size = 0;
+ pitem->request.parent = wq;
+ list_move_tail(&pitem->list, &encode_manager.process_queue);
+ spin_unlock(&encode_manager.event.sem_lock);
+
+ enc_pr(LOG_INFO,
+ "add new work ok, cmd:%d, ucode mode: %d, wq:%p.\n",
+ pitem->request.cmd, pitem->request.ucode_mode,
+ (void *)wq);
+ complete(&encode_manager.event.request_in_com);/* new cmd come in */
+ return 0;
+error:
+ spin_unlock(&encode_manager.event.sem_lock);
+ return -1;
+}
+
+struct encode_wq_s *create_encode_work_queue(void)
+{
+ struct encode_wq_s *encode_work_queue = NULL;
+ bool done = false;
+ u32 i, max_instance;
+ struct Buff_s *reserve_buff;
+
+ encode_work_queue = kzalloc(sizeof(struct encode_wq_s), GFP_KERNEL);
+ if (IS_ERR(encode_work_queue)) {
+ enc_pr(LOG_ERROR, "can't create work queue\n");
+ return NULL;
+ }
+ max_instance = encode_manager.max_instance;
+ encode_work_queue->pic.init_qppicture = 26;
+ encode_work_queue->pic.log2_max_frame_num = 4;
+ encode_work_queue->pic.log2_max_pic_order_cnt_lsb = 4;
+ encode_work_queue->pic.idr_pic_id = 0;
+ encode_work_queue->pic.frame_number = 0;
+ encode_work_queue->pic.pic_order_cnt_lsb = 0;
+#ifdef H264_ENC_SVC
+ /* Get settings from the global*/
+ encode_work_queue->pic.enable_svc = svc_enable;
+ encode_work_queue->pic.non_ref_limit = svc_ref_conf;
+ encode_work_queue->pic.non_ref_cnt = 0;
+ enc_pr(LOG_INFO, "svc conf enable %d, duration %d\n",
+ encode_work_queue->pic.enable_svc,
+ encode_work_queue->pic.non_ref_limit);
+#endif
+ encode_work_queue->ucode_index = UCODE_MODE_FULL;
+
+#ifdef H264_ENC_CBR
+ encode_work_queue->cbr_info.block_w = 16;
+ encode_work_queue->cbr_info.block_h = 9;
+ encode_work_queue->cbr_info.long_th = CBR_LONG_THRESH;
+ encode_work_queue->cbr_info.start_tbl_id = START_TABLE_ID;
+ encode_work_queue->cbr_info.short_shift = CBR_SHORT_SHIFT;
+ encode_work_queue->cbr_info.long_mb_num = CBR_LONG_MB_NUM;
+#endif
+ init_waitqueue_head(&encode_work_queue->request_complete);
+ atomic_set(&encode_work_queue->request_ready, 0);
+ spin_lock(&encode_manager.event.sem_lock);
+ if (encode_manager.wq_count < encode_manager.max_instance) {
+ list_add_tail(&encode_work_queue->list, &encode_manager.wq);
+ encode_manager.wq_count++;
+ if (encode_manager.use_reserve == true) {
+ for (i = 0; i < max_instance; i++) {
+ reserve_buff = &encode_manager.reserve_buff[i];
+ if (reserve_buff->used == false) {
+ encode_work_queue->mem.buf_start =
+ reserve_buff->buf_start;
+ encode_work_queue->mem.buf_size =
+ reserve_buff->buf_size;
+ reserve_buff->used = true;
+ done = true;
+ break;
+ }
+ }
+ } else
+ done = true;
+ }
+ spin_unlock(&encode_manager.event.sem_lock);
+ if (done == false) {
+ kfree(encode_work_queue);
+ encode_work_queue = NULL;
+ enc_pr(LOG_ERROR, "too many work queue!\n");
+ }
+ return encode_work_queue; /* find it */
+}
+
+static void _destroy_encode_work_queue(struct encode_manager_s *manager,
+ struct encode_wq_s **wq,
+ struct encode_wq_s *encode_work_queue,
+ bool *find)
+{
+ struct list_head *head;
+ struct encode_wq_s *wp_tmp = NULL;
+ u32 i, max_instance;
+ struct Buff_s *reserve_buff;
+ u32 buf_start = encode_work_queue->mem.buf_start;
+
+ max_instance = manager->max_instance;
+ head = &manager->wq;
+ list_for_each_entry_safe((*wq), wp_tmp, head, list) {
+ if ((*wq) && (*wq == encode_work_queue)) {
+ list_del(&(*wq)->list);
+ if (manager->use_reserve == true) {
+ for (i = 0; i < max_instance; i++) {
+ reserve_buff =
+ &manager->reserve_buff[i];
+ if (reserve_buff->used == true &&
+ buf_start ==
+ reserve_buff->buf_start) {
+ reserve_buff->used = false;
+ break;
+ }
+ }
+ }
+ *find = true;
+ manager->wq_count--;
+ enc_pr(LOG_DEBUG,
+ "remove encode_work_queue %p success, %s line %d.\n",
+ (void *)encode_work_queue,
+ __func__, __LINE__);
+ break;
+ }
+ }
+}
+
+s32 destroy_encode_work_queue(struct encode_wq_s *encode_work_queue)
+{
+ struct encode_queue_item_s *pitem, *tmp;
+ struct encode_wq_s *wq = NULL;
+ bool find = false;
+
+ struct list_head *head;
+
+ if (encode_work_queue) {
+ spin_lock(&encode_manager.event.sem_lock);
+ if (encode_manager.current_wq == encode_work_queue) {
+ encode_manager.remove_flag = true;
+ spin_unlock(&encode_manager.event.sem_lock);
+ enc_pr(LOG_DEBUG,
+ "warning--Destroy the running queue, should not be here.\n");
+ wait_for_completion(
+ &encode_manager.event.process_complete);
+ spin_lock(&encode_manager.event.sem_lock);
+ } /* else we can delete it safely. */
+
+ head = &encode_manager.process_queue;
+ list_for_each_entry_safe(pitem, tmp, head, list) {
+ if (pitem && pitem->request.parent ==
+ encode_work_queue) {
+ pitem->request.parent = NULL;
+ enc_pr(LOG_DEBUG,
+ "warning--remove not process request, should not be here.\n");
+ list_move_tail(&pitem->list,
+ &encode_manager.free_queue);
+ }
+ }
+
+ _destroy_encode_work_queue(&encode_manager, &wq,
+ encode_work_queue, &find);
+ spin_unlock(&encode_manager.event.sem_lock);
+#ifdef CONFIG_CMA
+ if (encode_work_queue->mem.buf_start) {
+ if (wq->mem.cbr_info_ddr_virt_addr != NULL) {
+ codec_mm_unmap_phyaddr(wq->mem.cbr_info_ddr_virt_addr);
+ wq->mem.cbr_info_ddr_virt_addr = NULL;
+ }
+ codec_mm_free_for_dma(
+ ENCODE_NAME,
+ encode_work_queue->mem.buf_start);
+ encode_work_queue->mem.buf_start = 0;
+
+ }
+#endif
+ kfree(encode_work_queue);
+ complete(&encode_manager.event.request_in_com);
+ }
+ return 0;
+}
+
+static s32 encode_monitor_thread(void *data)
+{
+ struct encode_manager_s *manager = (struct encode_manager_s *)data;
+ struct encode_queue_item_s *pitem = NULL;
+ struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 };
+ s32 ret = 0;
+
+ enc_pr(LOG_DEBUG, "encode workqueue monitor start.\n");
+ sched_setscheduler(current, SCHED_FIFO, ¶m);
+ allow_signal(SIGTERM);
+
+ /* setup current_wq here. */
+ while (manager->process_queue_state != ENCODE_PROCESS_QUEUE_STOP) {
+ if (kthread_should_stop())
+ break;
+
+ ret = wait_for_completion_interruptible(
+ &manager->event.request_in_com);
+
+ if (ret == -ERESTARTSYS)
+ break;
+
+ if (kthread_should_stop())
+ break;
+
+ if (manager->inited == false) {
+ spin_lock(&manager->event.sem_lock);
+
+ if (!list_empty(&manager->wq)) {
+ struct encode_wq_s *first_wq =
+ list_entry(manager->wq.next,
+ struct encode_wq_s, list);
+ manager->current_wq = first_wq;
+ spin_unlock(&manager->event.sem_lock);
+
+ if (first_wq) {
+#ifdef CONFIG_AMLOGIC_MEDIA_GE2D
+ if (!manager->context)
+ manager->context =
+ create_ge2d_work_queue();
+#endif
+ avc_init(first_wq);
+ manager->inited = true;
+ }
+ spin_lock(&manager->event.sem_lock);
+ manager->current_wq = NULL;
+ spin_unlock(&manager->event.sem_lock);
+ if (manager->remove_flag) {
+ complete(
+ &manager
+ ->event.process_complete);
+ manager->remove_flag = false;
+ }
+ } else
+ spin_unlock(&manager->event.sem_lock);
+ continue;
+ }
+
+ spin_lock(&manager->event.sem_lock);
+ pitem = NULL;
+
+ if (list_empty(&manager->wq)) {
+ spin_unlock(&manager->event.sem_lock);
+ manager->inited = false;
+ amvenc_avc_stop();
+
+#ifdef CONFIG_AMLOGIC_MEDIA_GE2D
+ if (manager->context) {
+ destroy_ge2d_work_queue(manager->context);
+ manager->context = NULL;
+ }
+#endif
+
+ enc_pr(LOG_DEBUG, "power off encode.\n");
+ continue;
+ } else if (!list_empty(&manager->process_queue)) {
+ pitem = list_entry(manager->process_queue.next,
+ struct encode_queue_item_s, list);
+ list_del(&pitem->list);
+ manager->current_item = pitem;
+ manager->current_wq = pitem->request.parent;
+ }
+
+ spin_unlock(&manager->event.sem_lock);
+
+ if (pitem) {
+ encode_process_request(manager, pitem);
+ spin_lock(&manager->event.sem_lock);
+ list_add_tail(&pitem->list, &manager->free_queue);
+ manager->current_item = NULL;
+ manager->last_wq = manager->current_wq;
+ manager->current_wq = NULL;
+ spin_unlock(&manager->event.sem_lock);
+ }
+
+ if (manager->remove_flag) {
+ complete(&manager->event.process_complete);
+ manager->remove_flag = false;
+ }
+ }
+ while (!kthread_should_stop())
+ msleep(20);
+
+ enc_pr(LOG_DEBUG, "exit encode_monitor_thread.\n");
+ return 0;
+}
+
+static s32 encode_start_monitor(void)
+{
+ s32 ret = 0;
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXTVBB) {
+ y_tnr_mot2alp_nrm_gain = 216;
+ y_tnr_mot2alp_dis_gain = 144;
+ c_tnr_mot2alp_nrm_gain = 216;
+ c_tnr_mot2alp_dis_gain = 144;
+ } else {
+ /* more tnr */
+ y_tnr_mot2alp_nrm_gain = 144;
+ y_tnr_mot2alp_dis_gain = 96;
+ c_tnr_mot2alp_nrm_gain = 144;
+ c_tnr_mot2alp_dis_gain = 96;
+ }
+
+ enc_pr(LOG_DEBUG, "encode start monitor.\n");
+ encode_manager.process_queue_state = ENCODE_PROCESS_QUEUE_START;
+ encode_manager.encode_thread = kthread_run(encode_monitor_thread,
+ &encode_manager, "encode_monitor");
+ if (IS_ERR(encode_manager.encode_thread)) {
+ ret = PTR_ERR(encode_manager.encode_thread);
+ encode_manager.process_queue_state = ENCODE_PROCESS_QUEUE_STOP;
+ enc_pr(LOG_ERROR,
+ "encode monitor : failed to start kthread (%d)\n", ret);
+ }
+ return ret;
+}
+
+static s32 encode_stop_monitor(void)
+{
+ enc_pr(LOG_DEBUG, "stop encode monitor thread\n");
+ if (encode_manager.encode_thread) {
+ spin_lock(&encode_manager.event.sem_lock);
+ if (!list_empty(&encode_manager.wq)) {
+ u32 count = encode_manager.wq_count;
+
+ spin_unlock(&encode_manager.event.sem_lock);
+ enc_pr(LOG_ERROR,
+ "stop encode monitor thread error, active wq (%d) is not 0.\n",
+ count);
+ return -1;
+ }
+ spin_unlock(&encode_manager.event.sem_lock);
+ encode_manager.process_queue_state = ENCODE_PROCESS_QUEUE_STOP;
+ send_sig(SIGTERM, encode_manager.encode_thread, 1);
+ complete(&encode_manager.event.request_in_com);
+ kthread_stop(encode_manager.encode_thread);
+ encode_manager.encode_thread = NULL;
+ kfree(mc_addr);
+ mc_addr = NULL;
+ }
+ return 0;
+}
+
+static s32 encode_wq_init(void)
+{
+ u32 i = 0;
+ struct encode_queue_item_s *pitem = NULL;
+
+ enc_pr(LOG_DEBUG, "encode_wq_init.\n");
+ encode_manager.irq_requested = false;
+
+ spin_lock_init(&encode_manager.event.sem_lock);
+ init_completion(&encode_manager.event.request_in_com);
+ init_waitqueue_head(&encode_manager.event.hw_complete);
+ init_completion(&encode_manager.event.process_complete);
+ INIT_LIST_HEAD(&encode_manager.process_queue);
+ INIT_LIST_HEAD(&encode_manager.free_queue);
+ INIT_LIST_HEAD(&encode_manager.wq);
+
+ tasklet_init(&encode_manager.encode_tasklet,
+ encode_isr_tasklet,
+ (ulong)&encode_manager);
+
+ for (i = 0; i < MAX_ENCODE_REQUEST; i++) {
+ pitem = kcalloc(1,
+ sizeof(struct encode_queue_item_s),
+ GFP_KERNEL);
+ if (IS_ERR(pitem)) {
+ enc_pr(LOG_ERROR, "can't request queue item memory.\n");
+ return -1;
+ }
+ pitem->request.parent = NULL;
+ list_add_tail(&pitem->list, &encode_manager.free_queue);
+ }
+ encode_manager.current_wq = NULL;
+ encode_manager.last_wq = NULL;
+ encode_manager.encode_thread = NULL;
+ encode_manager.current_item = NULL;
+ encode_manager.wq_count = 0;
+ encode_manager.remove_flag = false;
+ InitEncodeWeight();
+ if (encode_start_monitor()) {
+ enc_pr(LOG_ERROR, "encode create thread error.\n");
+ return -1;
+ }
+ return 0;
+}
+
+static s32 encode_wq_uninit(void)
+{
+ struct encode_queue_item_s *pitem, *tmp;
+ struct list_head *head;
+ u32 count = 0;
+ s32 r = -1;
+
+ enc_pr(LOG_DEBUG, "uninit encode wq.\n");
+ if (encode_stop_monitor() == 0) {
+ if ((encode_manager.irq_num >= 0) &&
+ (encode_manager.irq_requested == true)) {
+ free_irq(encode_manager.irq_num, &encode_manager);
+ encode_manager.irq_requested = false;
+ }
+ spin_lock(&encode_manager.event.sem_lock);
+ head = &encode_manager.process_queue;
+ list_for_each_entry_safe(pitem, tmp, head, list) {
+ if (pitem) {
+ list_del(&pitem->list);
+ kfree(pitem);
+ count++;
+ }
+ }
+ head = &encode_manager.free_queue;
+ list_for_each_entry_safe(pitem, tmp, head, list) {
+ if (pitem) {
+ list_del(&pitem->list);
+ kfree(pitem);
+ count++;
+ }
+ }
+ spin_unlock(&encode_manager.event.sem_lock);
+ if (count == MAX_ENCODE_REQUEST)
+ r = 0;
+ else {
+ enc_pr(LOG_ERROR, "lost some request item %d.\n",
+ MAX_ENCODE_REQUEST - count);
+ }
+ }
+ return r;
+}
+
+static ssize_t encode_status_show(struct class *cla,
+ struct class_attribute *attr, char *buf)
+{
+ u32 process_count = 0;
+ u32 free_count = 0;
+ struct encode_queue_item_s *pitem = NULL;
+ struct encode_wq_s *current_wq = NULL;
+ struct encode_wq_s *last_wq = NULL;
+ struct list_head *head = NULL;
+ s32 irq_num = 0;
+ u32 hw_status = 0;
+ u32 process_queue_state = 0;
+ u32 wq_count = 0;
+ u32 ucode_index;
+ bool need_reset;
+ bool process_irq;
+ bool inited;
+ bool use_reserve;
+ struct Buff_s reserve_mem;
+ u32 max_instance;
+#ifdef CONFIG_CMA
+ bool check_cma = false;
+#endif
+
+ spin_lock(&encode_manager.event.sem_lock);
+ head = &encode_manager.free_queue;
+ list_for_each_entry(pitem, head, list) {
+ free_count++;
+ if (free_count > MAX_ENCODE_REQUEST)
+ break;
+ }
+
+ head = &encode_manager.process_queue;
+ list_for_each_entry(pitem, head, list) {
+ process_count++;
+ if (free_count > MAX_ENCODE_REQUEST)
+ break;
+ }
+
+ current_wq = encode_manager.current_wq;
+ last_wq = encode_manager.last_wq;
+ pitem = encode_manager.current_item;
+ irq_num = encode_manager.irq_num;
+ hw_status = encode_manager.encode_hw_status;
+ process_queue_state = encode_manager.process_queue_state;
+ wq_count = encode_manager.wq_count;
+ ucode_index = encode_manager.ucode_index;
+ need_reset = encode_manager.need_reset;
+ process_irq = encode_manager.process_irq;
+ inited = encode_manager.inited;
+ use_reserve = encode_manager.use_reserve;
+ reserve_mem.buf_start = encode_manager.reserve_mem.buf_start;
+ reserve_mem.buf_size = encode_manager.reserve_mem.buf_size;
+
+ max_instance = encode_manager.max_instance;
+#ifdef CONFIG_CMA
+ check_cma = encode_manager.check_cma;
+#endif
+
+ spin_unlock(&encode_manager.event.sem_lock);
+
+ enc_pr(LOG_DEBUG,
+ "encode process queue count: %d, free queue count: %d.\n",
+ process_count, free_count);
+ enc_pr(LOG_DEBUG,
+ "encode curent wq: %p, last wq: %p, wq count: %d, max_instance: %d.\n",
+ current_wq, last_wq, wq_count, max_instance);
+ if (current_wq)
+ enc_pr(LOG_DEBUG,
+ "encode curent wq -- encode width: %d, encode height: %d.\n",
+ current_wq->pic.encoder_width,
+ current_wq->pic.encoder_height);
+ enc_pr(LOG_DEBUG,
+ "encode curent pitem: %p, ucode_index: %d, hw_status: %d, need_reset: %s, process_irq: %s.\n",
+ pitem, ucode_index, hw_status, need_reset ? "true" : "false",
+ process_irq ? "true" : "false");
+ enc_pr(LOG_DEBUG,
+ "encode irq num: %d, inited: %s, process_queue_state: %d.\n",
+ irq_num, inited ? "true" : "false", process_queue_state);
+ if (use_reserve) {
+ enc_pr(LOG_DEBUG,
+ "encode use reserve memory, buffer start: 0x%x, size: %d MB.\n",
+ reserve_mem.buf_start,
+ reserve_mem.buf_size / SZ_1M);
+ } else {
+#ifdef CONFIG_CMA
+ enc_pr(LOG_DEBUG, "encode check cma: %s.\n",
+ check_cma ? "true" : "false");
+#endif
+ }
+ return snprintf(buf, 40, "encode max instance: %d\n", max_instance);
+}
+
+static struct class_attribute amvenc_class_attrs[] = {
+ __ATTR(encode_status,
+ S_IRUGO | S_IWUSR,
+ encode_status_show,
+ NULL),
+ __ATTR_NULL
+};
+
+static struct class amvenc_avc_class = {
+ .name = CLASS_NAME,
+ .class_attrs = amvenc_class_attrs,
+};
+
+s32 init_avc_device(void)
+{
+ s32 r = 0;
+
+ r = register_chrdev(0, DEVICE_NAME, &amvenc_avc_fops);
+ if (r <= 0) {
+ enc_pr(LOG_ERROR, "register amvenc_avc device error.\n");
+ return r;
+ }
+ avc_device_major = r;
+
+ r = class_register(&amvenc_avc_class);
+ if (r < 0) {
+ enc_pr(LOG_ERROR, "error create amvenc_avc class.\n");
+ return r;
+ }
+
+ amvenc_avc_dev = device_create(&amvenc_avc_class, NULL,
+ MKDEV(avc_device_major, 0), NULL,
+ DEVICE_NAME);
+
+ if (IS_ERR(amvenc_avc_dev)) {
+ enc_pr(LOG_ERROR, "create amvenc_avc device error.\n");
+ class_unregister(&amvenc_avc_class);
+ return -1;
+ }
+ return r;
+}
+
+s32 uninit_avc_device(void)
+{
+ if (amvenc_avc_dev)
+ device_destroy(&amvenc_avc_class, MKDEV(avc_device_major, 0));
+
+ class_destroy(&amvenc_avc_class);
+
+ unregister_chrdev(avc_device_major, DEVICE_NAME);
+ return 0;
+}
+
+static s32 avc_mem_device_init(struct reserved_mem *rmem, struct device *dev)
+{
+ s32 r;
+ struct resource res;
+
+ if (!rmem) {
+ enc_pr(LOG_ERROR,
+ "Can not obtain I/O memory, and will allocate avc buffer!\n");
+ r = -EFAULT;
+ return r;
+ }
+ res.start = (phys_addr_t)rmem->base;
+ res.end = res.start + (phys_addr_t)rmem->size - 1;
+ encode_manager.reserve_mem.buf_start = res.start;
+ encode_manager.reserve_mem.buf_size = res.end - res.start + 1;
+
+ if (encode_manager.reserve_mem.buf_size >=
+ amvenc_buffspec[0].min_buffsize) {
+ encode_manager.max_instance =
+ encode_manager.reserve_mem.buf_size /
+ amvenc_buffspec[0].min_buffsize;
+ if (encode_manager.max_instance > MAX_ENCODE_INSTANCE)
+ encode_manager.max_instance = MAX_ENCODE_INSTANCE;
+ encode_manager.reserve_buff = kzalloc(
+ encode_manager.max_instance *
+ sizeof(struct Buff_s), GFP_KERNEL);
+ if (encode_manager.reserve_buff) {
+ u32 i;
+ struct Buff_s *reserve_buff;
+ u32 max_instance = encode_manager.max_instance;
+
+ for (i = 0; i < max_instance; i++) {
+ reserve_buff = &encode_manager.reserve_buff[i];
+ reserve_buff->buf_start =
+ i *
+ amvenc_buffspec[0]
+ .min_buffsize +
+ encode_manager.reserve_mem.buf_start;
+ reserve_buff->buf_size =
+ encode_manager.reserve_mem.buf_start;
+ reserve_buff->used = false;
+ }
+ encode_manager.use_reserve = true;
+ r = 0;
+ enc_pr(LOG_DEBUG,
+ "amvenc_avc use reserve memory, buff start: 0x%x, size: 0x%x, max instance is %d\n",
+ encode_manager.reserve_mem.buf_start,
+ encode_manager.reserve_mem.buf_size,
+ encode_manager.max_instance);
+ } else {
+ enc_pr(LOG_ERROR,
+ "amvenc_avc alloc reserve buffer pointer fail. max instance is %d.\n",
+ encode_manager.max_instance);
+ encode_manager.max_instance = 0;
+ encode_manager.reserve_mem.buf_start = 0;
+ encode_manager.reserve_mem.buf_size = 0;
+ r = -ENOMEM;
+ }
+ } else {
+ enc_pr(LOG_ERROR,
+ "amvenc_avc memory resource too small, size is 0x%x. Need 0x%x bytes at least.\n",
+ encode_manager.reserve_mem.buf_size,
+ amvenc_buffspec[0]
+ .min_buffsize);
+ encode_manager.reserve_mem.buf_start = 0;
+ encode_manager.reserve_mem.buf_size = 0;
+ r = -ENOMEM;
+ }
+ return r;
+}
+
+static s32 amvenc_avc_probe(struct platform_device *pdev)
+{
+ /* struct resource mem; */
+ s32 res_irq;
+ s32 idx;
+ s32 r;
+
+ enc_pr(LOG_ERROR, "amvenc_avc probe start.\n");
+
+ encode_manager.this_pdev = pdev;
+#ifdef CONFIG_CMA
+ encode_manager.check_cma = false;
+#endif
+ encode_manager.reserve_mem.buf_start = 0;
+ encode_manager.reserve_mem.buf_size = 0;
+ encode_manager.use_reserve = false;
+ encode_manager.max_instance = 0;
+ encode_manager.reserve_buff = NULL;
+
+ idx = of_reserved_mem_device_init(&pdev->dev);
+
+ if (idx != 0) {
+ enc_pr(LOG_DEBUG,
+ "amvenc_avc_probe -- reserved memory config fail.\n");
+ }
+
+
+ if (encode_manager.use_reserve == false) {
+#ifndef CONFIG_CMA
+ enc_pr(LOG_ERROR,
+ "amvenc_avc memory is invaild, probe fail!\n");
+ return -EFAULT;
+#else
+ encode_manager.cma_pool_size =
+ (codec_mm_get_total_size() > (MIN_SIZE * 3)) ?
+ (MIN_SIZE * 3) : codec_mm_get_total_size();
+ enc_pr(LOG_DEBUG,
+ "amvenc_avc - cma memory pool size: %d MB\n",
+ (u32)encode_manager.cma_pool_size / SZ_1M);
+#endif
+ }
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+ if (hcodec_clk_prepare(&pdev->dev, &s_hcodec_clks)) {
+ //err = -ENOENT;
+ enc_pr(LOG_ERROR, "[%s:%d] probe hcodec enc failed\n", __FUNCTION__, __LINE__);
+ //goto ERROR_PROBE_DEVICE;
+ return -EINVAL;
+ }
+ }
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+ hcodec_rst = devm_reset_control_get(&pdev->dev, "hcodec_rst");
+ if (IS_ERR(hcodec_rst))
+ pr_err("amvenc probe, hcodec get reset failed: %ld\n", PTR_ERR(hcodec_rst));
+ }
+
+ res_irq = platform_get_irq(pdev, 0);
+ if (res_irq < 0) {
+ enc_pr(LOG_ERROR, "[%s] get irq error!", __func__);
+ return -EINVAL;
+ }
+
+ encode_manager.irq_num = res_irq;
+ if (encode_wq_init()) {
+ kfree(encode_manager.reserve_buff);
+ encode_manager.reserve_buff = NULL;
+ enc_pr(LOG_ERROR, "encode work queue init error.\n");
+ return -EFAULT;
+ }
+
+ r = init_avc_device();
+ enc_pr(LOG_INFO, "amvenc_avc probe end.\n");
+ return r;
+}
+
+static s32 amvenc_avc_remove(struct platform_device *pdev)
+{
+ kfree(encode_manager.reserve_buff);
+ encode_manager.reserve_buff = NULL;
+ if (encode_wq_uninit())
+ enc_pr(LOG_ERROR, "encode work queue uninit error.\n");
+ uninit_avc_device();
+ hcodec_clk_unprepare(&pdev->dev, &s_hcodec_clks);
+ enc_pr(LOG_INFO, "amvenc_avc remove.\n");
+ return 0;
+}
+
+static const struct of_device_id amlogic_avcenc_dt_match[] = {
+ {
+ .compatible = "amlogic, amvenc_avc",
+ },
+ {},
+};
+
+static struct platform_driver amvenc_avc_driver = {
+ .probe = amvenc_avc_probe,
+ .remove = amvenc_avc_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = amlogic_avcenc_dt_match,
+ }
+};
+
+static struct codec_profile_t amvenc_avc_profile = {
+ .name = "avc",
+ .profile = ""
+};
+
+static s32 __init amvenc_avc_driver_init_module(void)
+{
+ enc_pr(LOG_INFO, "amvenc_avc module init\n");
+
+ if (platform_driver_register(&amvenc_avc_driver)) {
+ enc_pr(LOG_ERROR,
+ "failed to register amvenc_avc driver\n");
+ return -ENODEV;
+ }
+ vcodec_profile_register(&amvenc_avc_profile);
+ return 0;
+}
+
+static void __exit amvenc_avc_driver_remove_module(void)
+{
+ enc_pr(LOG_INFO, "amvenc_avc module remove.\n");
+
+ platform_driver_unregister(&amvenc_avc_driver);
+}
+
+static const struct reserved_mem_ops rmem_avc_ops = {
+ .device_init = avc_mem_device_init,
+};
+
+static s32 __init avc_mem_setup(struct reserved_mem *rmem)
+{
+ rmem->ops = &rmem_avc_ops;
+ enc_pr(LOG_DEBUG, "amvenc_avc reserved mem setup.\n");
+ return 0;
+}
+
+static int enc_dma_buf_map(struct enc_dma_cfg *cfg)
+{
+ long ret = -1;
+ int fd = -1;
+ struct dma_buf *dbuf = NULL;
+ struct dma_buf_attachment *d_att = NULL;
+ struct sg_table *sg = NULL;
+ void *vaddr = NULL;
+ struct device *dev = NULL;
+ enum dma_data_direction dir;
+
+ if (cfg == NULL || (cfg->fd < 0) || cfg->dev == NULL) {
+ enc_pr(LOG_ERROR, "error input param\n");
+ return -EINVAL;
+ }
+ enc_pr(LOG_INFO, "enc_dma_buf_map, fd %d\n", cfg->fd);
+
+ fd = cfg->fd;
+ dev = cfg->dev;
+ dir = cfg->dir;
+ enc_pr(LOG_INFO, "enc_dma_buffer_map fd %d\n", fd);
+
+ dbuf = dma_buf_get(fd);
+ if (dbuf == NULL) {
+ enc_pr(LOG_ERROR, "failed to get dma buffer,fd %d\n",fd);
+ return -EINVAL;
+ }
+
+ d_att = dma_buf_attach(dbuf, dev);
+ if (d_att == NULL) {
+ enc_pr(LOG_ERROR, "failed to set dma attach\n");
+ goto attach_err;
+ }
+
+ sg = dma_buf_map_attachment(d_att, dir);
+ if (sg == NULL) {
+ enc_pr(LOG_ERROR, "failed to get dma sg\n");
+ goto map_attach_err;
+ }
+
+ ret = dma_buf_begin_cpu_access(dbuf, dir);
+ if (ret != 0) {
+ enc_pr(LOG_ERROR, "failed to access dma buff\n");
+ goto access_err;
+ }
+
+ vaddr = dma_buf_vmap(dbuf);
+ if (vaddr == NULL) {
+ enc_pr(LOG_ERROR, "failed to vmap dma buf\n");
+ goto vmap_err;
+ }
+ cfg->dbuf = dbuf;
+ cfg->attach = d_att;
+ cfg->vaddr = vaddr;
+ cfg->sg = sg;
+
+ return ret;
+
+vmap_err:
+ dma_buf_end_cpu_access(dbuf, dir);
+
+access_err:
+ dma_buf_unmap_attachment(d_att, sg, dir);
+
+map_attach_err:
+ dma_buf_detach(dbuf, d_att);
+
+attach_err:
+ dma_buf_put(dbuf);
+
+ return ret;
+}
+
+static int enc_dma_buf_get_phys(struct enc_dma_cfg *cfg, unsigned long *addr)
+{
+ struct sg_table *sg_table;
+ struct page *page;
+ int ret;
+ enc_pr(LOG_INFO, "enc_dma_buf_get_phys in\n");
+
+ ret = enc_dma_buf_map(cfg);
+ if (ret < 0) {
+ enc_pr(LOG_ERROR, "gdc_dma_buf_map failed\n");
+ return ret;
+ }
+ if (cfg->sg) {
+ sg_table = cfg->sg;
+ page = sg_page(sg_table->sgl);
+ *addr = PFN_PHYS(page_to_pfn(page));
+ ret = 0;
+ }
+ enc_pr(LOG_INFO, "enc_dma_buf_get_phys 0x%lx\n", *addr);
+ return ret;
+}
+
+static void enc_dma_buf_unmap(struct enc_dma_cfg *cfg)
+{
+ int fd = -1;
+ struct dma_buf *dbuf = NULL;
+ struct dma_buf_attachment *d_att = NULL;
+ struct sg_table *sg = NULL;
+ void *vaddr = NULL;
+ struct device *dev = NULL;
+ enum dma_data_direction dir;
+
+ if (cfg == NULL || (cfg->fd < 0) || cfg->dev == NULL
+ || cfg->dbuf == NULL || cfg->vaddr == NULL
+ || cfg->attach == NULL || cfg->sg == NULL) {
+ enc_pr(LOG_ERROR, "Error input param\n");
+ return;
+ }
+
+ fd = cfg->fd;
+ dev = cfg->dev;
+ dir = cfg->dir;
+ dbuf = cfg->dbuf;
+ vaddr = cfg->vaddr;
+ d_att = cfg->attach;
+ sg = cfg->sg;
+
+ dma_buf_vunmap(dbuf, vaddr);
+
+ dma_buf_end_cpu_access(dbuf, dir);
+
+ dma_buf_unmap_attachment(d_att, sg, dir);
+
+ dma_buf_detach(dbuf, d_att);
+
+ dma_buf_put(dbuf);
+ enc_pr(LOG_DEBUG, "enc_dma_buffer_unmap vaddr %p\n",(unsigned *)vaddr);
+}
+
+
+module_param(fixed_slice_cfg, uint, 0664);
+MODULE_PARM_DESC(fixed_slice_cfg, "\n fixed_slice_cfg\n");
+
+module_param(clock_level, uint, 0664);
+MODULE_PARM_DESC(clock_level, "\n clock_level\n");
+
+module_param(encode_print_level, uint, 0664);
+MODULE_PARM_DESC(encode_print_level, "\n encode_print_level\n");
+
+module_param(no_timeout, uint, 0664);
+MODULE_PARM_DESC(no_timeout, "\n no_timeout flag for process request\n");
+
+module_param(nr_mode, int, 0664);
+MODULE_PARM_DESC(nr_mode, "\n nr_mode option\n");
+
+module_param(qp_table_debug, uint, 0664);
+MODULE_PARM_DESC(qp_table_debug, "\n print qp table\n");
+
+module_param(use_reset_control, uint, 0664);
+MODULE_PARM_DESC(use_reset_control, "\n use_reset_control\n");
+
+module_param(use_ge2d, uint, 0664);
+MODULE_PARM_DESC(use_ge2d, "\n use_ge2d\n");
+
+#ifdef H264_ENC_SVC
+module_param(svc_enable, uint, 0664);
+MODULE_PARM_DESC(svc_enable, "\n svc enable\n");
+module_param(svc_ref_conf, uint, 0664);
+MODULE_PARM_DESC(svc_ref_conf, "\n svc reference duration config\n");
+#endif
+
+#ifdef MORE_MODULE_PARAM
+module_param(me_mv_merge_ctl, uint, 0664);
+MODULE_PARM_DESC(me_mv_merge_ctl, "\n me_mv_merge_ctl\n");
+
+module_param(me_step0_close_mv, uint, 0664);
+MODULE_PARM_DESC(me_step0_close_mv, "\n me_step0_close_mv\n");
+
+module_param(me_f_skip_sad, uint, 0664);
+MODULE_PARM_DESC(me_f_skip_sad, "\n me_f_skip_sad\n");
+
+module_param(me_f_skip_weight, uint, 0664);
+MODULE_PARM_DESC(me_f_skip_weight, "\n me_f_skip_weight\n");
+
+module_param(me_mv_weight_01, uint, 0664);
+MODULE_PARM_DESC(me_mv_weight_01, "\n me_mv_weight_01\n");
+
+module_param(me_mv_weight_23, uint, 0664);
+MODULE_PARM_DESC(me_mv_weight_23, "\n me_mv_weight_23\n");
+
+module_param(me_sad_range_inc, uint, 0664);
+MODULE_PARM_DESC(me_sad_range_inc, "\n me_sad_range_inc\n");
+
+module_param(me_sad_enough_01, uint, 0664);
+MODULE_PARM_DESC(me_sad_enough_01, "\n me_sad_enough_01\n");
+
+module_param(me_sad_enough_23, uint, 0664);
+MODULE_PARM_DESC(me_sad_enough_23, "\n me_sad_enough_23\n");
+
+module_param(y_tnr_mc_en, uint, 0664);
+MODULE_PARM_DESC(y_tnr_mc_en, "\n y_tnr_mc_en option\n");
+module_param(y_tnr_txt_mode, uint, 0664);
+MODULE_PARM_DESC(y_tnr_txt_mode, "\n y_tnr_txt_mode option\n");
+module_param(y_tnr_mot_sad_margin, uint, 0664);
+MODULE_PARM_DESC(y_tnr_mot_sad_margin, "\n y_tnr_mot_sad_margin option\n");
+module_param(y_tnr_mot_cortxt_rate, uint, 0664);
+MODULE_PARM_DESC(y_tnr_mot_cortxt_rate, "\n y_tnr_mot_cortxt_rate option\n");
+module_param(y_tnr_mot_distxt_ofst, uint, 0664);
+MODULE_PARM_DESC(y_tnr_mot_distxt_ofst, "\n y_tnr_mot_distxt_ofst option\n");
+module_param(y_tnr_mot_distxt_rate, uint, 0664);
+MODULE_PARM_DESC(y_tnr_mot_distxt_rate, "\n y_tnr_mot_distxt_rate option\n");
+module_param(y_tnr_mot_dismot_ofst, uint, 0664);
+MODULE_PARM_DESC(y_tnr_mot_dismot_ofst, "\n y_tnr_mot_dismot_ofst option\n");
+module_param(y_tnr_mot_frcsad_lock, uint, 0664);
+MODULE_PARM_DESC(y_tnr_mot_frcsad_lock, "\n y_tnr_mot_frcsad_lock option\n");
+module_param(y_tnr_mot2alp_frc_gain, uint, 0664);
+MODULE_PARM_DESC(y_tnr_mot2alp_frc_gain, "\n y_tnr_mot2alp_frc_gain option\n");
+module_param(y_tnr_mot2alp_nrm_gain, uint, 0664);
+MODULE_PARM_DESC(y_tnr_mot2alp_nrm_gain, "\n y_tnr_mot2alp_nrm_gain option\n");
+module_param(y_tnr_mot2alp_dis_gain, uint, 0664);
+MODULE_PARM_DESC(y_tnr_mot2alp_dis_gain, "\n y_tnr_mot2alp_dis_gain option\n");
+module_param(y_tnr_mot2alp_dis_ofst, uint, 0664);
+MODULE_PARM_DESC(y_tnr_mot2alp_dis_ofst, "\n y_tnr_mot2alp_dis_ofst option\n");
+module_param(y_tnr_alpha_min, uint, 0664);
+MODULE_PARM_DESC(y_tnr_alpha_min, "\n y_tnr_alpha_min option\n");
+module_param(y_tnr_alpha_max, uint, 0664);
+MODULE_PARM_DESC(y_tnr_alpha_max, "\n y_tnr_alpha_max option\n");
+module_param(y_tnr_deghost_os, uint, 0664);
+MODULE_PARM_DESC(y_tnr_deghost_os, "\n y_tnr_deghost_os option\n");
+
+module_param(c_tnr_mc_en, uint, 0664);
+MODULE_PARM_DESC(c_tnr_mc_en, "\n c_tnr_mc_en option\n");
+module_param(c_tnr_txt_mode, uint, 0664);
+MODULE_PARM_DESC(c_tnr_txt_mode, "\n c_tnr_txt_mode option\n");
+module_param(c_tnr_mot_sad_margin, uint, 0664);
+MODULE_PARM_DESC(c_tnr_mot_sad_margin, "\n c_tnr_mot_sad_margin option\n");
+module_param(c_tnr_mot_cortxt_rate, uint, 0664);
+MODULE_PARM_DESC(c_tnr_mot_cortxt_rate, "\n c_tnr_mot_cortxt_rate option\n");
+module_param(c_tnr_mot_distxt_ofst, uint, 0664);
+MODULE_PARM_DESC(c_tnr_mot_distxt_ofst, "\n c_tnr_mot_distxt_ofst option\n");
+module_param(c_tnr_mot_distxt_rate, uint, 0664);
+MODULE_PARM_DESC(c_tnr_mot_distxt_rate, "\n c_tnr_mot_distxt_rate option\n");
+module_param(c_tnr_mot_dismot_ofst, uint, 0664);
+MODULE_PARM_DESC(c_tnr_mot_dismot_ofst, "\n c_tnr_mot_dismot_ofst option\n");
+module_param(c_tnr_mot_frcsad_lock, uint, 0664);
+MODULE_PARM_DESC(c_tnr_mot_frcsad_lock, "\n c_tnr_mot_frcsad_lock option\n");
+module_param(c_tnr_mot2alp_frc_gain, uint, 0664);
+MODULE_PARM_DESC(c_tnr_mot2alp_frc_gain, "\n c_tnr_mot2alp_frc_gain option\n");
+module_param(c_tnr_mot2alp_nrm_gain, uint, 0664);
+MODULE_PARM_DESC(c_tnr_mot2alp_nrm_gain, "\n c_tnr_mot2alp_nrm_gain option\n");
+module_param(c_tnr_mot2alp_dis_gain, uint, 0664);
+MODULE_PARM_DESC(c_tnr_mot2alp_dis_gain, "\n c_tnr_mot2alp_dis_gain option\n");
+module_param(c_tnr_mot2alp_dis_ofst, uint, 0664);
+MODULE_PARM_DESC(c_tnr_mot2alp_dis_ofst, "\n c_tnr_mot2alp_dis_ofst option\n");
+module_param(c_tnr_alpha_min, uint, 0664);
+MODULE_PARM_DESC(c_tnr_alpha_min, "\n c_tnr_alpha_min option\n");
+module_param(c_tnr_alpha_max, uint, 0664);
+MODULE_PARM_DESC(c_tnr_alpha_max, "\n c_tnr_alpha_max option\n");
+module_param(c_tnr_deghost_os, uint, 0664);
+MODULE_PARM_DESC(c_tnr_deghost_os, "\n c_tnr_deghost_os option\n");
+
+module_param(y_snr_err_norm, uint, 0664);
+MODULE_PARM_DESC(y_snr_err_norm, "\n y_snr_err_norm option\n");
+module_param(y_snr_gau_bld_core, uint, 0664);
+MODULE_PARM_DESC(y_snr_gau_bld_core, "\n y_snr_gau_bld_core option\n");
+module_param(y_snr_gau_bld_ofst, int, 0664);
+MODULE_PARM_DESC(y_snr_gau_bld_ofst, "\n y_snr_gau_bld_ofst option\n");
+module_param(y_snr_gau_bld_rate, uint, 0664);
+MODULE_PARM_DESC(y_snr_gau_bld_rate, "\n y_snr_gau_bld_rate option\n");
+module_param(y_snr_gau_alp0_min, uint, 0664);
+MODULE_PARM_DESC(y_snr_gau_alp0_min, "\n y_snr_gau_alp0_min option\n");
+module_param(y_snr_gau_alp0_max, uint, 0664);
+MODULE_PARM_DESC(y_snr_gau_alp0_max, "\n y_snr_gau_alp0_max option\n");
+module_param(y_bld_beta2alp_rate, uint, 0664);
+MODULE_PARM_DESC(y_bld_beta2alp_rate, "\n y_bld_beta2alp_rate option\n");
+module_param(y_bld_beta_min, uint, 0664);
+MODULE_PARM_DESC(y_bld_beta_min, "\n y_bld_beta_min option\n");
+module_param(y_bld_beta_max, uint, 0664);
+MODULE_PARM_DESC(y_bld_beta_max, "\n y_bld_beta_max option\n");
+
+module_param(c_snr_err_norm, uint, 0664);
+MODULE_PARM_DESC(c_snr_err_norm, "\n c_snr_err_norm option\n");
+module_param(c_snr_gau_bld_core, uint, 0664);
+MODULE_PARM_DESC(c_snr_gau_bld_core, "\n c_snr_gau_bld_core option\n");
+module_param(c_snr_gau_bld_ofst, int, 0664);
+MODULE_PARM_DESC(c_snr_gau_bld_ofst, "\n c_snr_gau_bld_ofst option\n");
+module_param(c_snr_gau_bld_rate, uint, 0664);
+MODULE_PARM_DESC(c_snr_gau_bld_rate, "\n c_snr_gau_bld_rate option\n");
+module_param(c_snr_gau_alp0_min, uint, 0664);
+MODULE_PARM_DESC(c_snr_gau_alp0_min, "\n c_snr_gau_alp0_min option\n");
+module_param(c_snr_gau_alp0_max, uint, 0664);
+MODULE_PARM_DESC(c_snr_gau_alp0_max, "\n c_snr_gau_alp0_max option\n");
+module_param(c_bld_beta2alp_rate, uint, 0664);
+MODULE_PARM_DESC(c_bld_beta2alp_rate, "\n c_bld_beta2alp_rate option\n");
+module_param(c_bld_beta_min, uint, 0664);
+MODULE_PARM_DESC(c_bld_beta_min, "\n c_bld_beta_min option\n");
+module_param(c_bld_beta_max, uint, 0664);
+MODULE_PARM_DESC(c_bld_beta_max, "\n c_bld_beta_max option\n");
+#endif
+
+module_init(amvenc_avc_driver_init_module);
+module_exit(amvenc_avc_driver_remove_module);
+RESERVEDMEM_OF_DECLARE(amvenc_avc, "amlogic, amvenc-memory", avc_mem_setup);
+
+MODULE_DESCRIPTION("AMLOGIC AVC Video Encoder Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("simon.zheng <simon.zheng@amlogic.com>");
diff --git a/drivers/frame_sink/encoder/h264/encoder.h b/drivers/frame_sink/encoder/h264/encoder.h
new file mode 100644
index 0000000..b5bbe7d
--- /dev/null
+++ b/drivers/frame_sink/encoder/h264/encoder.h
@@ -0,0 +1,502 @@
+/*
+ * drivers/amlogic/amports/encoder.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 __H264_H__
+#define __H264_H__
+
+#include <linux/mutex.h>
+#include <linux/semaphore.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+
+#ifdef CONFIG_AMLOGIC_MEDIA_GE2D
+#include <linux/amlogic/media/ge2d/ge2d.h>
+#endif
+
+#include <linux/dma-buf.h>
+
+#define AMVENC_DEVINFO_M8 "AML-M8"
+#define AMVENC_DEVINFO_G9 "AML-G9"
+#define AMVENC_DEVINFO_GXBB "AML-GXBB"
+#define AMVENC_DEVINFO_GXTVBB "AML-GXTVBB"
+#define AMVENC_DEVINFO_GXL "AML-GXL"
+
+#define HCODEC_IRQ_MBOX_CLR HCODEC_ASSIST_MBOX2_CLR_REG
+#define HCODEC_IRQ_MBOX_MASK HCODEC_ASSIST_MBOX2_MASK
+
+#define H264_ENC_SVC
+
+/* M8: 2550/10 = 255M GX: 2000/10 = 200M */
+#define HDEC_L0() WRITE_HHI_REG(HHI_VDEC_CLK_CNTL, \
+ (2 << 25) | (1 << 16) | (1 << 24) | \
+ (0xffff & READ_HHI_REG(HHI_VDEC_CLK_CNTL)))
+/* M8: 2550/8 = 319M GX: 2000/8 = 250M */
+#define HDEC_L1() WRITE_HHI_REG(HHI_VDEC_CLK_CNTL, \
+ (0 << 25) | (1 << 16) | (1 << 24) | \
+ (0xffff & READ_HHI_REG(HHI_VDEC_CLK_CNTL)))
+/* M8: 2550/7 = 364M GX: 2000/7 = 285M */
+#define HDEC_L2() WRITE_HHI_REG(HHI_VDEC_CLK_CNTL, \
+ (3 << 25) | (0 << 16) | (1 << 24) | \
+ (0xffff & READ_HHI_REG(HHI_VDEC_CLK_CNTL)))
+/* M8: 2550/6 = 425M GX: 2000/6 = 333M */
+#define HDEC_L3() WRITE_HHI_REG(HHI_VDEC_CLK_CNTL, \
+ (1 << 25) | (1 << 16) | (1 << 24) | \
+ (0xffff & READ_HHI_REG(HHI_VDEC_CLK_CNTL)))
+/* M8: 2550/5 = 510M GX: 2000/5 = 400M */
+#define HDEC_L4() WRITE_HHI_REG(HHI_VDEC_CLK_CNTL, \
+ (2 << 25) | (0 << 16) | (1 << 24) | \
+ (0xffff & READ_HHI_REG(HHI_VDEC_CLK_CNTL)))
+/* M8: 2550/4 = 638M GX: 2000/4 = 500M */
+#define HDEC_L5() WRITE_HHI_REG(HHI_VDEC_CLK_CNTL, \
+ (0 << 25) | (0 << 16) | (1 << 24) | \
+ (0xffff & READ_HHI_REG(HHI_VDEC_CLK_CNTL)))
+/* M8: 2550/3 = 850M GX: 2000/3 = 667M */
+#define HDEC_L6() WRITE_HHI_REG(HHI_VDEC_CLK_CNTL, \
+ (1 << 25) | (0 << 16) | (1 << 24) | \
+ (0xffff & READ_HHI_REG(HHI_VDEC_CLK_CNTL)))
+
+#define hvdec_clock_enable(level) \
+ do { \
+ if (level == 0) \
+ HDEC_L0(); \
+ else if (level == 1) \
+ HDEC_L1(); \
+ else if (level == 2) \
+ HDEC_L2(); \
+ else if (level == 3) \
+ HDEC_L3(); \
+ else if (level == 4) \
+ HDEC_L4(); \
+ else if (level == 5) \
+ HDEC_L5(); \
+ else if (level == 6) \
+ HDEC_L6(); \
+ WRITE_VREG_BITS(DOS_GCLK_EN0, 0x7fff, 12, 15); \
+ } while (0)
+
+#define hvdec_clock_disable() \
+ do { \
+ WRITE_VREG_BITS(DOS_GCLK_EN0, 0, 12, 15); \
+ WRITE_HHI_REG_BITS(HHI_VDEC_CLK_CNTL, 0, 24, 1); \
+ } while (0)
+
+#define LOG_ALL 0
+#define LOG_INFO 1
+#define LOG_DEBUG 2
+#define LOG_ERROR 3
+
+#define enc_pr(level, x...) \
+ do { \
+ if (level >= encode_print_level) \
+ printk(x); \
+ } while (0)
+
+#define AMVENC_AVC_IOC_MAGIC 'E'
+
+#define AMVENC_AVC_IOC_GET_DEVINFO _IOW(AMVENC_AVC_IOC_MAGIC, 0xf0, u32)
+#define AMVENC_AVC_IOC_MAX_INSTANCE _IOW(AMVENC_AVC_IOC_MAGIC, 0xf1, u32)
+
+#define AMVENC_AVC_IOC_GET_ADDR _IOW(AMVENC_AVC_IOC_MAGIC, 0x00, u32)
+#define AMVENC_AVC_IOC_INPUT_UPDATE _IOW(AMVENC_AVC_IOC_MAGIC, 0x01, u32)
+#define AMVENC_AVC_IOC_NEW_CMD _IOW(AMVENC_AVC_IOC_MAGIC, 0x02, u32)
+#define AMVENC_AVC_IOC_GET_STAGE _IOW(AMVENC_AVC_IOC_MAGIC, 0x03, u32)
+#define AMVENC_AVC_IOC_GET_OUTPUT_SIZE _IOW(AMVENC_AVC_IOC_MAGIC, 0x04, u32)
+#define AMVENC_AVC_IOC_CONFIG_INIT _IOW(AMVENC_AVC_IOC_MAGIC, 0x05, u32)
+#define AMVENC_AVC_IOC_FLUSH_CACHE _IOW(AMVENC_AVC_IOC_MAGIC, 0x06, u32)
+#define AMVENC_AVC_IOC_FLUSH_DMA _IOW(AMVENC_AVC_IOC_MAGIC, 0x07, u32)
+#define AMVENC_AVC_IOC_GET_BUFFINFO _IOW(AMVENC_AVC_IOC_MAGIC, 0x08, u32)
+#define AMVENC_AVC_IOC_SUBMIT _IOW(AMVENC_AVC_IOC_MAGIC, 0x09, u32)
+#define AMVENC_AVC_IOC_READ_CANVAS _IOW(AMVENC_AVC_IOC_MAGIC, 0x0a, u32)
+#define AMVENC_AVC_IOC_QP_MODE _IOW(AMVENC_AVC_IOC_MAGIC, 0x0b, u32)
+
+
+
+#define IE_PIPPELINE_BLOCK_SHIFT 0
+#define IE_PIPPELINE_BLOCK_MASK 0x1f
+#define ME_PIXEL_MODE_SHIFT 5
+#define ME_PIXEL_MODE_MASK 0x3
+
+enum amvenc_mem_type_e {
+ LOCAL_BUFF = 0,
+ CANVAS_BUFF,
+ PHYSICAL_BUFF,
+ DMA_BUFF,
+ MAX_BUFF_TYPE
+};
+
+enum amvenc_frame_fmt_e {
+ FMT_YUV422_SINGLE = 0,
+ FMT_YUV444_SINGLE,
+ FMT_NV21,
+ FMT_NV12,
+ FMT_YUV420,
+ FMT_YUV444_PLANE,
+ FMT_RGB888,
+ FMT_RGB888_PLANE,
+ FMT_RGB565,
+ FMT_RGBA8888,
+ FMT_YUV422_12BIT,
+ FMT_YUV444_10BIT,
+ FMT_YUV422_10BIT,
+ FMT_BGR888,
+ MAX_FRAME_FMT
+};
+
+#define MAX_ENCODE_REQUEST 8 /* 64 */
+
+#define MAX_ENCODE_INSTANCE 8 /* 64 */
+
+#define ENCODE_PROCESS_QUEUE_START 0
+#define ENCODE_PROCESS_QUEUE_STOP 1
+
+#define AMVENC_FLUSH_FLAG_INPUT 0x1
+#define AMVENC_FLUSH_FLAG_OUTPUT 0x2
+#define AMVENC_FLUSH_FLAG_REFERENCE 0x4
+#define AMVENC_FLUSH_FLAG_INTRA_INFO 0x8
+#define AMVENC_FLUSH_FLAG_INTER_INFO 0x10
+#define AMVENC_FLUSH_FLAG_QP 0x20
+#define AMVENC_FLUSH_FLAG_DUMP 0x40
+#define AMVENC_FLUSH_FLAG_CBR 0x80
+
+#define ENCODER_BUFFER_INPUT 0
+#define ENCODER_BUFFER_REF0 1
+#define ENCODER_BUFFER_REF1 2
+#define ENCODER_BUFFER_OUTPUT 3
+#define ENCODER_BUFFER_INTER_INFO 4
+#define ENCODER_BUFFER_INTRA_INFO 5
+#define ENCODER_BUFFER_QP 6
+#define ENCODER_BUFFER_DUMP 7
+#define ENCODER_BUFFER_CBR 8
+
+struct encode_wq_s;
+
+struct enc_dma_cfg {
+ int fd;
+ void *dev;
+ void *vaddr;
+ void *paddr;
+ struct dma_buf *dbuf;
+ struct dma_buf_attachment *attach;
+ struct sg_table *sg;
+ enum dma_data_direction dir;
+};
+
+struct encode_request_s {
+ u32 quant;
+ u32 cmd;
+ u32 ucode_mode;
+ u32 src;
+ u32 framesize;
+
+ u32 me_weight;
+ u32 i4_weight;
+ u32 i16_weight;
+
+ u32 crop_top;
+ u32 crop_bottom;
+ u32 crop_left;
+ u32 crop_right;
+ u32 src_w;
+ u32 src_h;
+ u32 scale_enable;
+
+ u32 nr_mode;
+ u32 flush_flag;
+ u32 timeout;
+ enum amvenc_mem_type_e type;
+ enum amvenc_frame_fmt_e fmt;
+ struct encode_wq_s *parent;
+ struct enc_dma_cfg dma_cfg[3];
+ u32 plane_num;
+};
+
+struct encode_queue_item_s {
+ struct list_head list;
+ struct encode_request_s request;
+};
+
+struct Buff_s {
+ u32 buf_start;
+ u32 buf_size;
+ bool used;
+};
+
+struct BuffInfo_s {
+ u32 lev_id;
+ u32 min_buffsize;
+ u32 max_width;
+ u32 max_height;
+ struct Buff_s dct;
+ struct Buff_s dec0_y;
+ struct Buff_s dec0_uv;
+ struct Buff_s dec1_y;
+ struct Buff_s dec1_uv;
+ struct Buff_s assit;
+ struct Buff_s bitstream;
+ struct Buff_s scale_buff;
+ struct Buff_s dump_info;
+ struct Buff_s cbr_info;
+};
+
+struct encode_meminfo_s {
+ u32 buf_start;
+ u32 buf_size;
+
+ u32 BitstreamStart;
+ u32 BitstreamEnd;
+
+ /*input buffer define*/
+ u32 dct_buff_start_addr;
+ u32 dct_buff_end_addr;
+
+ /*microcode assitant buffer*/
+ u32 assit_buffer_offset;
+
+ u32 scaler_buff_start_addr;
+
+ u32 dump_info_ddr_start_addr;
+ u32 dump_info_ddr_size;
+
+ u32 cbr_info_ddr_start_addr;
+ u32 cbr_info_ddr_size;
+
+ u8 * cbr_info_ddr_virt_addr;
+
+ s32 dblk_buf_canvas;
+ s32 ref_buf_canvas;
+ struct BuffInfo_s bufspec;
+#ifdef CONFIG_CMA
+ struct page *venc_pages;
+#endif
+};
+
+struct encode_picinfo_s {
+ u32 encoder_width;
+ u32 encoder_height;
+
+ u32 rows_per_slice;
+
+ u32 idr_pic_id; /* need reset as 0 for IDR */
+ u32 frame_number; /* need plus each frame */
+ /* need reset as 0 for IDR and plus 2 for NON-IDR */
+ u32 pic_order_cnt_lsb;
+
+ u32 log2_max_pic_order_cnt_lsb;
+ u32 log2_max_frame_num;
+ u32 init_qppicture;
+#ifdef H264_ENC_SVC
+ u32 enable_svc;
+ u32 non_ref_limit;
+ u32 non_ref_cnt;
+#endif
+ u32 color_space;
+};
+
+struct encode_cbr_s {
+ u16 block_w;
+ u16 block_h;
+ u16 long_th;
+ u8 start_tbl_id;
+ u8 short_shift;
+ u8 long_mb_num;
+};
+
+struct encode_wq_s {
+ struct list_head list;
+
+ /* dev info */
+ u32 ucode_index;
+ u32 hw_status;
+ u32 output_size;
+
+ u32 sps_size;
+ u32 pps_size;
+
+ u32 me_weight;
+ u32 i4_weight;
+ u32 i16_weight;
+
+ u32 quant_tbl_i4[8];
+ u32 quant_tbl_i16[8];
+ u32 quant_tbl_me[8];
+
+ struct encode_meminfo_s mem;
+ struct encode_picinfo_s pic;
+ struct encode_request_s request;
+ struct encode_cbr_s cbr_info;
+ atomic_t request_ready;
+ wait_queue_head_t request_complete;
+};
+
+struct encode_event_s {
+ wait_queue_head_t hw_complete;
+ struct completion process_complete;
+ spinlock_t sem_lock; /* for queue switch and create destroy queue. */
+ struct completion request_in_com;
+};
+
+struct encode_manager_s {
+ struct list_head wq;
+ struct list_head process_queue;
+ struct list_head free_queue;
+
+ u32 encode_hw_status;
+ u32 process_queue_state;
+ s32 irq_num;
+ u32 wq_count;
+ u32 ucode_index;
+ u32 max_instance;
+#ifdef CONFIG_AMLOGIC_MEDIA_GE2D
+ struct ge2d_context_s *context;
+#endif
+ bool irq_requested;
+ bool need_reset;
+ bool process_irq;
+ bool inited; /* power on encode */
+ bool remove_flag; /* remove wq; */
+ bool uninit_flag; /* power off encode */
+ bool use_reserve;
+
+#ifdef CONFIG_CMA
+ bool check_cma;
+ ulong cma_pool_size;
+#endif
+ struct platform_device *this_pdev;
+ struct Buff_s *reserve_buff;
+ struct encode_wq_s *current_wq;
+ struct encode_wq_s *last_wq;
+ struct encode_queue_item_s *current_item;
+ struct task_struct *encode_thread;
+ struct Buff_s reserve_mem;
+ struct encode_event_s event;
+ struct tasklet_struct encode_tasklet;
+};
+
+extern s32 encode_wq_add_request(struct encode_wq_s *wq);
+extern struct encode_wq_s *create_encode_work_queue(void);
+extern s32 destroy_encode_work_queue(struct encode_wq_s *encode_work_queue);
+
+/********************************************
+ * AV Scratch Register Re-Define
+ ****************************************** *
+ */
+#define ENCODER_STATUS HCODEC_HENC_SCRATCH_0
+#define MEM_OFFSET_REG HCODEC_HENC_SCRATCH_1
+#define DEBUG_REG HCODEC_HENC_SCRATCH_2
+#define IDR_PIC_ID HCODEC_HENC_SCRATCH_5
+#define FRAME_NUMBER HCODEC_HENC_SCRATCH_6
+#define PIC_ORDER_CNT_LSB HCODEC_HENC_SCRATCH_7
+#define LOG2_MAX_PIC_ORDER_CNT_LSB HCODEC_HENC_SCRATCH_8
+#define LOG2_MAX_FRAME_NUM HCODEC_HENC_SCRATCH_9
+#define ANC0_BUFFER_ID HCODEC_HENC_SCRATCH_A
+#define QPPICTURE HCODEC_HENC_SCRATCH_B
+
+#define IE_ME_MB_TYPE HCODEC_HENC_SCRATCH_D
+
+/* bit 0-4, IE_PIPPELINE_BLOCK
+ * bit 5 me half pixel in m8
+ * disable i4x4 in gxbb
+ * bit 6 me step2 sub pixel in m8
+ * disable i16x16 in gxbb
+ */
+#define IE_ME_MODE HCODEC_HENC_SCRATCH_E
+#define IE_REF_SEL HCODEC_HENC_SCRATCH_F
+
+/* [31:0] NUM_ROWS_PER_SLICE_P */
+/* [15:0] NUM_ROWS_PER_SLICE_I */
+#define FIXED_SLICE_CFG HCODEC_HENC_SCRATCH_L
+
+/* For GX */
+#define INFO_DUMP_START_ADDR HCODEC_HENC_SCRATCH_I
+
+/* For CBR */
+#define H264_ENC_CBR_TABLE_ADDR HCODEC_HENC_SCRATCH_3
+#define H264_ENC_CBR_MB_SIZE_ADDR HCODEC_HENC_SCRATCH_4
+/* Bytes(Float) * 256 */
+#define H264_ENC_CBR_CTL HCODEC_HENC_SCRATCH_G
+/* [31:28] : init qp table idx */
+/* [27:24] : short_term adjust shift */
+/* [23:16] : Long_term MB_Number between adjust, */
+/* [15:0] Long_term adjust threshold(Bytes) */
+#define H264_ENC_CBR_TARGET_SIZE HCODEC_HENC_SCRATCH_H
+/* Bytes(Float) * 256 */
+#define H264_ENC_CBR_PREV_BYTES HCODEC_HENC_SCRATCH_J
+#define H264_ENC_CBR_REGION_SIZE HCODEC_HENC_SCRATCH_J
+
+/* for SVC */
+#define H264_ENC_SVC_PIC_TYPE HCODEC_HENC_SCRATCH_K
+
+/* define for PIC header */
+#define ENC_SLC_REF 0x8410
+#define ENC_SLC_NON_REF 0x8010
+
+/* --------------------------------------------------- */
+/* ENCODER_STATUS define */
+/* --------------------------------------------------- */
+#define ENCODER_IDLE 0
+#define ENCODER_SEQUENCE 1
+#define ENCODER_PICTURE 2
+#define ENCODER_IDR 3
+#define ENCODER_NON_IDR 4
+#define ENCODER_MB_HEADER 5
+#define ENCODER_MB_DATA 6
+
+#define ENCODER_SEQUENCE_DONE 7
+#define ENCODER_PICTURE_DONE 8
+#define ENCODER_IDR_DONE 9
+#define ENCODER_NON_IDR_DONE 10
+#define ENCODER_MB_HEADER_DONE 11
+#define ENCODER_MB_DATA_DONE 12
+
+#define ENCODER_NON_IDR_INTRA 13
+#define ENCODER_NON_IDR_INTER 14
+
+#define ENCODER_ERROR 0xff
+
+/********************************************
+ * defines for H.264 mb_type
+ *******************************************
+ */
+#define HENC_MB_Type_PBSKIP 0x0
+#define HENC_MB_Type_PSKIP 0x0
+#define HENC_MB_Type_BSKIP_DIRECT 0x0
+#define HENC_MB_Type_P16x16 0x1
+#define HENC_MB_Type_P16x8 0x2
+#define HENC_MB_Type_P8x16 0x3
+#define HENC_MB_Type_SMB8x8 0x4
+#define HENC_MB_Type_SMB8x4 0x5
+#define HENC_MB_Type_SMB4x8 0x6
+#define HENC_MB_Type_SMB4x4 0x7
+#define HENC_MB_Type_P8x8 0x8
+#define HENC_MB_Type_I4MB 0x9
+#define HENC_MB_Type_I16MB 0xa
+#define HENC_MB_Type_IBLOCK 0xb
+#define HENC_MB_Type_SI4MB 0xc
+#define HENC_MB_Type_I8MB 0xd
+#define HENC_MB_Type_IPCM 0xe
+#define HENC_MB_Type_AUTO 0xf
+
+#define HENC_MB_CBP_AUTO 0xff
+#define HENC_SKIP_RUN_AUTO 0xffff
+
+
+extern bool amvenc_avc_on(void);
+#endif
diff --git a/drivers/frame_sink/encoder/h265/Makefile b/drivers/frame_sink/encoder/h265/Makefile
new file mode 100644
index 0000000..833822c
--- /dev/null
+++ b/drivers/frame_sink/encoder/h265/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_AMLOGIC_MEDIA_VENC_H265) += vpu.o
diff --git a/drivers/frame_sink/encoder/h265/vmm.h b/drivers/frame_sink/encoder/h265/vmm.h
new file mode 100644
index 0000000..a32dd06
--- /dev/null
+++ b/drivers/frame_sink/encoder/h265/vmm.h
@@ -0,0 +1,665 @@
+/*
+ * vmm.h
+ *
+ * memory allocator for VPU
+ *
+ * Copyright (C) 2006 - 2013 CHIPS&MEDIA INC.
+ *
+ * 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 __CNM_VIDEO_MEMORY_MANAGEMENT_H__
+#define __CNM_VIDEO_MEMORY_MANAGEMENT_H__
+
+#define VMEM_PAGE_SIZE (16 * 1024)
+#define MAKE_KEY(_a, _b) (((vmem_key_t)_a) << 32 | _b)
+#define KEY_TO_VALUE(_key) (_key >> 32)
+
+#define VMEM_P_ALLOC(_x) vmalloc(_x)
+#define VMEM_P_FREE(_x) vfree(_x)
+
+#define VMEM_ASSERT \
+ pr_info("VMEM_ASSERT at %s:%d\n", __FILE__, __LINE__)
+
+
+#define VMEM_HEIGHT(_tree) (_tree == NULL ? -1 : _tree->height)
+
+#define MAX(_a, _b) (_a >= _b ? _a : _b)
+
+struct avl_node_t;
+#define vmem_key_t unsigned long long
+
+struct vmem_info_t {
+ ulong total_pages;
+ ulong alloc_pages;
+ ulong free_pages;
+ ulong page_size;
+};
+
+struct page_t {
+ s32 pageno;
+ ulong addr;
+ s32 used;
+ s32 alloc_pages;
+ s32 first_pageno;
+};
+
+struct avl_node_t {
+ vmem_key_t key;
+ s32 height;
+ struct page_t *page;
+ struct avl_node_t *left;
+ struct avl_node_t *right;
+};
+
+struct video_mm_t {
+ struct avl_node_t *free_tree;
+ struct avl_node_t *alloc_tree;
+ struct page_t *page_list;
+ s32 num_pages;
+ ulong base_addr;
+ ulong mem_size;
+ s32 free_page_count;
+ s32 alloc_page_count;
+};
+
+enum rotation_dir_t {
+ LEFT,
+ RIGHT
+};
+
+struct avl_node_data_t {
+ s32 key;
+ struct page_t *page;
+};
+
+static struct avl_node_t *make_avl_node(
+ vmem_key_t key,
+ struct page_t *page)
+{
+ struct avl_node_t *node =
+ (struct avl_node_t *)VMEM_P_ALLOC(sizeof(struct avl_node_t));
+ node->key = key;
+ node->page = page;
+ node->height = 0;
+ node->left = NULL;
+ node->right = NULL;
+ return node;
+}
+
+static s32 get_balance_factor(struct avl_node_t *tree)
+{
+ s32 factor = 0;
+
+ if (tree)
+ factor = VMEM_HEIGHT(tree->right) - VMEM_HEIGHT(tree->left);
+ return factor;
+}
+
+/*
+ * Left Rotation
+ *
+ * A B
+ * \ / \
+ * B => A C
+ * / \ \
+ * D C D
+ *
+ */
+static struct avl_node_t *rotation_left(struct avl_node_t *tree)
+{
+ struct avl_node_t *rchild;
+ struct avl_node_t *lchild;
+
+ if (tree == NULL)
+ return NULL;
+
+ rchild = tree->right;
+ if (rchild == NULL)
+ return tree;
+
+ lchild = rchild->left;
+ rchild->left = tree;
+ tree->right = lchild;
+
+ tree->height =
+ MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1;
+ rchild->height =
+ MAX(VMEM_HEIGHT(rchild->left), VMEM_HEIGHT(rchild->right)) + 1;
+ return rchild;
+}
+
+
+/*
+ * Reft Rotation
+ *
+ * A B
+ * \ / \
+ * B => D A
+ * / \ /
+ * D C C
+ *
+ */
+static struct avl_node_t *rotation_right(struct avl_node_t *tree)
+{
+ struct avl_node_t *rchild;
+ struct avl_node_t *lchild;
+
+ if (tree == NULL)
+ return NULL;
+
+ lchild = tree->left;
+ if (lchild == NULL)
+ return NULL;
+
+ rchild = lchild->right;
+ lchild->right = tree;
+ tree->left = rchild;
+
+ tree->height =
+ MAX(VMEM_HEIGHT(tree->left),
+ VMEM_HEIGHT(tree->right)) + 1;
+ lchild->height =
+ MAX(VMEM_HEIGHT(lchild->left),
+ VMEM_HEIGHT(lchild->right)) + 1;
+ return lchild;
+}
+
+static struct avl_node_t *do_balance(struct avl_node_t *tree)
+{
+ s32 bfactor = 0, child_bfactor;
+
+ bfactor = get_balance_factor(tree);
+ if (bfactor >= 2) {
+ child_bfactor = get_balance_factor(tree->right);
+ if (child_bfactor == 1 || child_bfactor == 0) {
+ tree = rotation_left(tree);
+ } else if (child_bfactor == -1) {
+ tree->right = rotation_right(tree->right);
+ tree = rotation_left(tree);
+ } else {
+ pr_info(
+ "invalid balancing factor: %d\n",
+ child_bfactor);
+ VMEM_ASSERT;
+ return NULL;
+ }
+ } else if (bfactor <= -2) {
+ child_bfactor = get_balance_factor(tree->left);
+ if (child_bfactor == -1 || child_bfactor == 0) {
+ tree = rotation_right(tree);
+ } else if (child_bfactor == 1) {
+ tree->left = rotation_left(tree->left);
+ tree = rotation_right(tree);
+ } else {
+ pr_info(
+ "invalid balancing factor: %d\n",
+ child_bfactor);
+ VMEM_ASSERT;
+ return NULL;
+ }
+ }
+ return tree;
+}
+
+static struct avl_node_t *unlink_end_node(
+ struct avl_node_t *tree,
+ s32 dir,
+ struct avl_node_t **found_node)
+{
+ struct avl_node_t *node;
+ *found_node = NULL;
+
+ if (tree == NULL)
+ return NULL;
+
+ if (dir == LEFT) {
+ if (tree->left == NULL) {
+ *found_node = tree;
+ return NULL;
+ }
+ } else {
+ if (tree->right == NULL) {
+ *found_node = tree;
+ return NULL;
+ }
+ }
+
+ if (dir == LEFT) {
+ node = tree->left;
+ tree->left = unlink_end_node(tree->left, LEFT, found_node);
+ if (tree->left == NULL) {
+ tree->left = (*found_node)->right;
+ (*found_node)->left = NULL;
+ (*found_node)->right = NULL;
+ }
+ } else {
+ node = tree->right;
+ tree->right = unlink_end_node(tree->right, RIGHT, found_node);
+ if (tree->right == NULL) {
+ tree->right = (*found_node)->left;
+ (*found_node)->left = NULL;
+ (*found_node)->right = NULL;
+ }
+ }
+ tree->height =
+ MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1;
+ return do_balance(tree);
+}
+
+
+static struct avl_node_t *avltree_insert(
+ struct avl_node_t *tree,
+ vmem_key_t key,
+ struct page_t *page)
+{
+ if (tree == NULL) {
+ tree = make_avl_node(key, page);
+ } else {
+ if (key >= tree->key)
+ tree->right =
+ avltree_insert(tree->right, key, page);
+ else
+ tree->left =
+ avltree_insert(tree->left, key, page);
+ }
+ tree = do_balance(tree);
+ tree->height =
+ MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1;
+ return tree;
+}
+
+static struct avl_node_t *do_unlink(struct avl_node_t *tree)
+{
+ struct avl_node_t *node;
+ struct avl_node_t *end_node;
+
+ node = unlink_end_node(tree->right, LEFT, &end_node);
+ if (node) {
+ tree->right = node;
+ } else {
+ node =
+ unlink_end_node(tree->left, RIGHT, &end_node);
+ if (node)
+ tree->left = node;
+ }
+
+ if (node == NULL) {
+ node = tree->right ? tree->right : tree->left;
+ end_node = node;
+ }
+
+ if (end_node) {
+ end_node->left =
+ (tree->left != end_node) ?
+ tree->left : end_node->left;
+ end_node->right =
+ (tree->right != end_node) ?
+ tree->right : end_node->right;
+ end_node->height =
+ MAX(VMEM_HEIGHT(end_node->left),
+ VMEM_HEIGHT(end_node->right)) + 1;
+ }
+ tree = end_node;
+ return tree;
+}
+
+static struct avl_node_t *avltree_remove(
+ struct avl_node_t *tree,
+ struct avl_node_t **found_node,
+ vmem_key_t key)
+{
+ *found_node = NULL;
+ if (tree == NULL) {
+ pr_info("failed to find key %d\n", (s32)key);
+ return NULL;
+ }
+
+ if (key == tree->key) {
+ *found_node = tree;
+ tree = do_unlink(tree);
+ } else if (key > tree->key) {
+ tree->right =
+ avltree_remove(tree->right, found_node, key);
+ } else {
+ tree->left =
+ avltree_remove(tree->left, found_node, key);
+ }
+
+ if (tree)
+ tree->height =
+ MAX(VMEM_HEIGHT(tree->left),
+ VMEM_HEIGHT(tree->right)) + 1;
+
+ tree = do_balance(tree);
+ return tree;
+}
+
+void avltree_free(struct avl_node_t *tree)
+{
+ if (tree == NULL)
+ return;
+ if (tree->left == NULL && tree->right == NULL) {
+ VMEM_P_FREE(tree);
+ return;
+ }
+
+ avltree_free(tree->left);
+ tree->left = NULL;
+ avltree_free(tree->right);
+ tree->right = NULL;
+ VMEM_P_FREE(tree);
+}
+
+static struct avl_node_t *remove_approx_value(
+ struct avl_node_t *tree,
+ struct avl_node_t **found,
+ vmem_key_t key)
+{
+ *found = NULL;
+ if (tree == NULL)
+ return NULL;
+
+ if (key == tree->key) {
+ *found = tree;
+ tree = do_unlink(tree);
+ } else if (key > tree->key) {
+ tree->right = remove_approx_value(tree->right, found, key);
+ } else {
+ tree->left = remove_approx_value(tree->left, found, key);
+ if (*found == NULL) {
+ *found = tree;
+ tree = do_unlink(tree);
+ }
+ }
+ if (tree)
+ tree->height =
+ MAX(VMEM_HEIGHT(tree->left),
+ VMEM_HEIGHT(tree->right)) + 1;
+ tree = do_balance(tree);
+ return tree;
+}
+
+static void set_blocks_free(
+ struct video_mm_t *mm,
+ s32 pageno,
+ s32 npages)
+{
+ s32 last_pageno = pageno + npages - 1;
+ s32 i;
+ struct page_t *page;
+ struct page_t *last_page;
+
+ if (npages == 0)
+ VMEM_ASSERT;
+
+ if (last_pageno >= mm->num_pages) {
+ pr_info(
+ "set_blocks_free: invalid last page number: %d\n",
+ last_pageno);
+ VMEM_ASSERT;
+ return;
+ }
+
+ for (i = pageno; i <= last_pageno; i++) {
+ mm->page_list[i].used = 0;
+ mm->page_list[i].alloc_pages = 0;
+ mm->page_list[i].first_pageno = -1;
+ }
+
+ page = &mm->page_list[pageno];
+ page->alloc_pages = npages;
+ last_page = &mm->page_list[last_pageno];
+ last_page->first_pageno = pageno;
+ mm->free_tree =
+ avltree_insert(mm->free_tree, MAKE_KEY(npages, pageno), page);
+}
+
+static void set_blocks_alloc(
+ struct video_mm_t *mm,
+ s32 pageno,
+ s32 npages)
+{
+ s32 last_pageno = pageno + npages - 1;
+ s32 i;
+ struct page_t *page;
+ struct page_t *last_page;
+
+ if (last_pageno >= mm->num_pages) {
+ pr_info(
+ "set_blocks_free: invalid last page number: %d\n",
+ last_pageno);
+ VMEM_ASSERT;
+ return;
+ }
+
+ for (i = pageno; i <= last_pageno; i++) {
+ mm->page_list[i].used = 1;
+ mm->page_list[i].alloc_pages = 0;
+ mm->page_list[i].first_pageno = -1;
+ }
+
+ page = &mm->page_list[pageno];
+ page->alloc_pages = npages;
+ last_page = &mm->page_list[last_pageno];
+ last_page->first_pageno = pageno;
+ mm->alloc_tree =
+ avltree_insert(mm->alloc_tree, MAKE_KEY(page->addr, 0), page);
+}
+
+
+s32 vmem_init(struct video_mm_t *mm, ulong addr, ulong size)
+{
+ s32 i;
+
+ if (mm == NULL)
+ return -1;
+
+ mm->base_addr = (addr + (VMEM_PAGE_SIZE - 1))
+ & ~(VMEM_PAGE_SIZE - 1);
+ mm->mem_size = size & ~VMEM_PAGE_SIZE;
+ mm->num_pages = mm->mem_size / VMEM_PAGE_SIZE;
+ mm->free_tree = NULL;
+ mm->alloc_tree = NULL;
+ mm->free_page_count = mm->num_pages;
+ mm->alloc_page_count = 0;
+ mm->page_list =
+ (struct page_t *)VMEM_P_ALLOC(
+ mm->num_pages * sizeof(struct page_t));
+ if (mm->page_list == NULL) {
+ pr_err("%s:%d failed to kmalloc(%zu)\n",
+ __func__, __LINE__,
+ mm->num_pages * sizeof(struct page_t));
+ return -1;
+ }
+
+ for (i = 0; i < mm->num_pages; i++) {
+ mm->page_list[i].pageno = i;
+ mm->page_list[i].addr =
+ mm->base_addr + i * VMEM_PAGE_SIZE;
+ mm->page_list[i].alloc_pages = 0;
+ mm->page_list[i].used = 0;
+ mm->page_list[i].first_pageno = -1;
+ }
+ set_blocks_free(mm, 0, mm->num_pages);
+ return 0;
+}
+
+s32 vmem_exit(struct video_mm_t *mm)
+{
+ if (mm == NULL) {
+ pr_info("vmem_exit: invalid handle\n");
+ return -1;
+ }
+
+ if (mm->free_tree)
+ avltree_free(mm->free_tree);
+ if (mm->alloc_tree)
+ avltree_free(mm->alloc_tree);
+
+ if (mm->page_list) {
+ VMEM_P_FREE(mm->page_list);
+ mm->page_list = NULL;
+ }
+
+ mm->base_addr = 0;
+ mm->mem_size = 0;
+ mm->num_pages = 0;
+ mm->page_list = NULL;
+ mm->free_tree = NULL;
+ mm->alloc_tree = NULL;
+ mm->free_page_count = 0;
+ mm->alloc_page_count = 0;
+ return 0;
+}
+
+ulong vmem_alloc(struct video_mm_t *mm, s32 size, ulong pid)
+{
+ struct avl_node_t *node;
+ struct page_t *free_page;
+ s32 npages, free_size;
+ s32 alloc_pageno;
+ ulong ptr;
+
+ if (mm == NULL) {
+ pr_info("vmem_alloc: invalid handle\n");
+ return -1;
+ }
+
+ if (size <= 0)
+ return -1;
+
+ npages = (size + VMEM_PAGE_SIZE - 1) / VMEM_PAGE_SIZE;
+ mm->free_tree = remove_approx_value(mm->free_tree,
+ &node, MAKE_KEY(npages, 0));
+
+ if (node == NULL)
+ return -1;
+
+ free_page = node->page;
+ free_size = KEY_TO_VALUE(node->key);
+ alloc_pageno = free_page->pageno;
+ set_blocks_alloc(mm, alloc_pageno, npages);
+ if (npages != free_size) {
+ s32 free_pageno = alloc_pageno + npages;
+
+ set_blocks_free(mm, free_pageno, (free_size-npages));
+ }
+ VMEM_P_FREE(node);
+
+ ptr = mm->page_list[alloc_pageno].addr;
+ mm->alloc_page_count += npages;
+ mm->free_page_count -= npages;
+ return ptr;
+}
+
+s32 vmem_free(struct video_mm_t *mm, ulong ptr, ulong pid)
+{
+ ulong addr;
+ struct avl_node_t *found;
+ struct page_t *page;
+ s32 pageno, prev_free_pageno, next_free_pageno;
+ s32 prev_size, next_size;
+ s32 merge_page_no, merge_page_size, free_page_size;
+
+ if (mm == NULL) {
+ pr_info("vmem_free: invalid handle\n");
+ return -1;
+ }
+
+ addr = ptr;
+ mm->alloc_tree = avltree_remove(mm->alloc_tree, &found,
+ MAKE_KEY(addr, 0));
+
+ if (found == NULL) {
+ pr_info("vmem_free: 0x%08x not found\n", (s32)addr);
+ VMEM_ASSERT;
+ return -1;
+ }
+
+ /* find previous free block */
+ page = found->page;
+ pageno = page->pageno;
+ free_page_size = page->alloc_pages;
+ prev_free_pageno = pageno - 1;
+ prev_size = -1;
+ if (prev_free_pageno >= 0) {
+ if (mm->page_list[prev_free_pageno].used == 0) {
+ prev_free_pageno =
+ mm->page_list[prev_free_pageno].first_pageno;
+ prev_size =
+ mm->page_list[prev_free_pageno].alloc_pages;
+ }
+ }
+
+ /* find next free block */
+ next_free_pageno = pageno + page->alloc_pages;
+ next_free_pageno =
+ (next_free_pageno == mm->num_pages) ? -1 : next_free_pageno;
+ next_size = -1;
+ if (next_free_pageno >= 0) {
+ if (mm->page_list[next_free_pageno].used == 0) {
+ next_size =
+ mm->page_list[next_free_pageno].alloc_pages;
+ }
+ }
+ VMEM_P_FREE(found);
+
+ /* merge */
+ merge_page_no = page->pageno;
+ merge_page_size = page->alloc_pages;
+ if (prev_size >= 0) {
+ mm->free_tree = avltree_remove(mm->free_tree, &found,
+ MAKE_KEY(prev_size, prev_free_pageno));
+ if (found == NULL) {
+ VMEM_ASSERT;
+ return -1;
+ }
+ merge_page_no = found->page->pageno;
+ merge_page_size += found->page->alloc_pages;
+ VMEM_P_FREE(found);
+ }
+ if (next_size >= 0) {
+ mm->free_tree = avltree_remove(mm->free_tree, &found,
+ MAKE_KEY(next_size, next_free_pageno));
+ if (found == NULL) {
+ VMEM_ASSERT;
+ return -1;
+ }
+ merge_page_size += found->page->alloc_pages;
+ VMEM_P_FREE(found);
+ }
+ page->alloc_pages = 0;
+ page->first_pageno = -1;
+ set_blocks_free(mm, merge_page_no, merge_page_size);
+ mm->alloc_page_count -= free_page_size;
+ mm->free_page_count += free_page_size;
+ return 0;
+}
+
+s32 vmem_get_info(struct video_mm_t *mm, struct vmem_info_t *info)
+{
+ if (mm == NULL) {
+ pr_info("vmem_get_info: invalid handle\n");
+ return -1;
+ }
+
+ if (info == NULL)
+ return -1;
+
+ info->total_pages = mm->num_pages;
+ info->alloc_pages = mm->alloc_page_count;
+ info->free_pages = mm->free_page_count;
+ info->page_size = VMEM_PAGE_SIZE;
+ return 0;
+}
+#endif /* __CNM_VIDEO_MEMORY_MANAGEMENT_H__ */
diff --git a/drivers/frame_sink/encoder/h265/vpu.c b/drivers/frame_sink/encoder/h265/vpu.c
new file mode 100644
index 0000000..70598b3
--- /dev/null
+++ b/drivers/frame_sink/encoder/h265/vpu.c
@@ -0,0 +1,2479 @@
+/*
+ * vpu.c
+ *
+ * linux device driver for VPU.
+ *
+ * Copyright (C) 2006 - 2013 CHIPS&MEDIA INC.
+ *
+ * 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/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/cdev.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/reset.h>
+#include <linux/clk.h>
+#include <linux/compat.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/of_address.h>
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include <linux/amlogic/cpu_version.h>
+#include <linux/version.h>
+#include "../../../frame_provider/decoder/utils/vdec_power_ctrl.h"
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include <linux/amlogic/power_ctrl.h>
+#include <dt-bindings/power/sc2-pd.h>
+#include <linux/amlogic/pwr_ctrl.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,1)
+#include <linux/sched/signal.h>
+#endif
+
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "../../../common/media_clock/switch/amports_gate.h"
+
+#include "vpu.h"
+#include "vmm.h"
+
+/* definitions to be changed as customer configuration */
+/* if you want to have clock gating scheme frame by frame */
+/* #define VPU_SUPPORT_CLOCK_CONTROL */
+
+//#define VPU_SUPPORT_CLOCK_CONTROL
+
+
+#define VPU_PLATFORM_DEVICE_NAME "HevcEnc"
+#define VPU_DEV_NAME "HevcEnc"
+#define VPU_CLASS_NAME "HevcEnc"
+
+#ifndef VM_RESERVED /*for kernel up to 3.7.0 version*/
+#define VM_RESERVED (VM_DONTEXPAND | VM_DONTDUMP)
+#endif
+
+#define MHz (1000000)
+
+#define VPU_INIT_VIDEO_MEMORY_SIZE_IN_BYTE (64 * SZ_1M)
+
+#define LOG_ALL 0
+#define LOG_INFO 1
+#define LOG_DEBUG 2
+#define LOG_ERROR 3
+
+#define enc_pr(level, x...) \
+ do { \
+ if (level >= print_level) \
+ printk(x); \
+ } while (0)
+
+static s32 print_level = LOG_DEBUG;
+static s32 clock_level = 4;
+
+static s32 wave_clocka;
+static s32 wave_clockb;
+static s32 wave_clockc;
+
+static struct video_mm_t s_vmem;
+static struct vpudrv_buffer_t s_video_memory = {0};
+static bool use_reserve;
+static ulong cma_pool_size;
+
+/* end customer definition */
+static struct vpudrv_buffer_t s_instance_pool = {0};
+static struct vpudrv_buffer_t s_common_memory = {0};
+static struct vpu_drv_context_t s_vpu_drv_context;
+static s32 s_vpu_major;
+static struct device *hevcenc_dev;
+
+static s32 s_vpu_open_ref_count;
+static s32 s_vpu_irq;
+static bool s_vpu_irq_requested;
+
+static struct vpudrv_buffer_t s_vpu_register = {0};
+
+static s32 s_interrupt_flag;
+static wait_queue_head_t s_interrupt_wait_q;
+
+static spinlock_t s_vpu_lock = __SPIN_LOCK_UNLOCKED(s_vpu_lock);
+static DEFINE_SEMAPHORE(s_vpu_sem);
+static struct list_head s_vbp_head = LIST_HEAD_INIT(s_vbp_head);
+static struct list_head s_inst_list_head = LIST_HEAD_INIT(s_inst_list_head);
+static struct tasklet_struct hevc_tasklet;
+static struct platform_device *hevc_pdev;
+
+static struct vpu_bit_firmware_info_t s_bit_firmware_info[MAX_NUM_VPU_CORE];
+
+static struct vpu_dma_cfg dma_cfg[3];
+
+struct vpu_clks {
+ struct clk *wave_aclk;
+ struct clk *wave_bclk;
+ struct clk *wave_cclk;
+};
+
+static struct vpu_clks s_vpu_clks;
+
+#define CHECK_RET(_ret) if (ret) {enc_pr(LOG_ERROR, \
+ "%s:%d:function call failed with result: %d\n",\
+ __FUNCTION__, __LINE__, _ret);}
+
+static u32 vpu_src_addr_config(struct vpu_dma_buf_info_t);
+static void vpu_dma_buffer_unmap(struct vpu_dma_cfg *cfg);
+
+static void dma_flush(u32 buf_start, u32 buf_size)
+{
+ if (hevc_pdev)
+ dma_sync_single_for_device(
+ &hevc_pdev->dev, buf_start,
+ buf_size, DMA_TO_DEVICE);
+}
+
+static void cache_flush(u32 buf_start, u32 buf_size)
+{
+ if (hevc_pdev)
+ dma_sync_single_for_cpu(
+ &hevc_pdev->dev, buf_start,
+ buf_size, DMA_FROM_DEVICE);
+}
+
+s32 vpu_hw_reset(void)
+{
+ enc_pr(LOG_DEBUG, "request vpu reset from application.\n");
+ return 0;
+}
+
+s32 vpu_clk_prepare(struct device *dev, struct vpu_clks *clks)
+{
+ int ret;
+
+ s32 new_clocka = 667;
+ s32 new_clockb = 400;
+ s32 new_clockc = 400;
+
+ if (wave_clocka > 0)
+ new_clocka = wave_clocka;
+ if (wave_clockb > 0)
+ new_clockb = wave_clockb;
+ if (wave_clockc > 0)
+ new_clockc = wave_clockc;
+
+ clks->wave_aclk = devm_clk_get(dev, "cts_wave420_aclk");
+ if (IS_ERR_OR_NULL(clks->wave_aclk)) {
+ enc_pr(LOG_ERROR, "failed to get wave aclk\n");
+ return -1;
+ }
+
+ clks->wave_bclk = devm_clk_get(dev, "cts_wave420_bclk");
+ if (IS_ERR_OR_NULL(clks->wave_aclk)) {
+ enc_pr(LOG_ERROR, "failed to get wave aclk\n");
+ return -1;
+ }
+
+ clks->wave_cclk = devm_clk_get(dev, "cts_wave420_cclk");
+ if (IS_ERR_OR_NULL(clks->wave_aclk)) {
+ enc_pr(LOG_ERROR, "failed to get wave aclk\n");
+ return -1;
+ }
+
+ ret = clk_set_rate(clks->wave_aclk, new_clocka * MHz);
+ CHECK_RET(ret);
+ ret = clk_set_rate(clks->wave_bclk, new_clockb * MHz);
+ CHECK_RET(ret);
+ ret = clk_set_rate(clks->wave_cclk, new_clockc * MHz);
+
+ CHECK_RET(ret);
+ ret = clk_prepare(clks->wave_aclk);
+ CHECK_RET(ret);
+ ret = clk_prepare(clks->wave_bclk);
+ CHECK_RET(ret);
+ ret = clk_prepare(clks->wave_cclk);
+ CHECK_RET(ret);
+
+ enc_pr(LOG_ERROR, "wave_clk_a: %lu MHz\n", clk_get_rate(clks->wave_aclk) / 1000000);
+ enc_pr(LOG_ERROR, "wave_clk_b: %lu MHz\n", clk_get_rate(clks->wave_bclk) / 1000000);
+ enc_pr(LOG_ERROR, "wave_clk_c: %lu MHz\n", clk_get_rate(clks->wave_cclk) / 1000000);
+
+ return 0;
+}
+
+void vpu_clk_unprepare(struct device *dev, struct vpu_clks *clks)
+{
+ clk_unprepare(clks->wave_cclk);
+ devm_clk_put(dev, clks->wave_cclk);
+
+ clk_unprepare(clks->wave_bclk);
+ devm_clk_put(dev, clks->wave_bclk);
+
+ clk_unprepare(clks->wave_aclk);
+ devm_clk_put(dev, clks->wave_aclk);
+}
+
+s32 vpu_clk_config(u32 enable)
+{
+ if (enable) {
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+ clk_enable(s_vpu_clks.wave_aclk);
+ clk_enable(s_vpu_clks.wave_bclk);
+ clk_enable(s_vpu_clks.wave_cclk);
+ } else {
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_G12A)
+ HevcEnc_MoreClock_enable();
+ HevcEnc_clock_enable(clock_level);
+ }
+ } else {
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+ clk_disable(s_vpu_clks.wave_cclk);
+ clk_disable(s_vpu_clks.wave_bclk);
+ clk_disable(s_vpu_clks.wave_aclk);
+ } else {
+ HevcEnc_clock_disable();
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_G12A)
+ HevcEnc_MoreClock_disable();
+ }
+ }
+
+ return 0;
+}
+
+static s32 vpu_alloc_dma_buffer(struct vpudrv_buffer_t *vb)
+{
+ if (!vb)
+ return -1;
+
+ vb->phys_addr = (ulong)vmem_alloc(&s_vmem, vb->size, 0);
+ if ((ulong)vb->phys_addr == (ulong)-1) {
+ enc_pr(LOG_ERROR,
+ "Physical memory allocation error size=%d\n", vb->size);
+ return -1;
+ }
+
+ enc_pr(LOG_INFO, "vpu_alloc_dma_buffer: vb->phys_addr 0x%lx \n",vb->phys_addr);
+ return 0;
+}
+
+static void vpu_free_dma_buffer(struct vpudrv_buffer_t *vb)
+{
+ if (!vb)
+ return;
+ enc_pr(LOG_INFO, "vpu_free_dma_buffer 0x%lx\n",vb->phys_addr);
+
+ if (vb->phys_addr)
+ vmem_free(&s_vmem, vb->phys_addr, 0);
+}
+
+static s32 vpu_free_instances(struct file *filp)
+{
+ struct vpudrv_instanace_list_t *vil, *n;
+ struct vpudrv_instance_pool_t *vip;
+ void *vip_base;
+
+ enc_pr(LOG_DEBUG, "vpu_free_instances\n");
+
+ list_for_each_entry_safe(vil, n, &s_inst_list_head, list) {
+ if (vil->filp == filp) {
+ vip_base = (void *)s_instance_pool.base;
+ enc_pr(LOG_INFO,
+ "free_instances instIdx=%d, coreIdx=%d, vip_base=%p\n",
+ (s32)vil->inst_idx,
+ (s32)vil->core_idx,
+ vip_base);
+ vip = (struct vpudrv_instance_pool_t *)vip_base;
+ if (vip) {
+ /* only first 4 byte is key point
+ * (inUse of CodecInst in vpuapi)
+ * to free the corresponding instance.
+ */
+ memset(&vip->codecInstPool[vil->inst_idx],
+ 0x00, 4);
+ }
+ s_vpu_open_ref_count--;
+ list_del(&vil->list);
+ kfree(vil);
+ }
+ }
+ return 1;
+}
+
+static s32 vpu_free_buffers(struct file *filp)
+{
+ struct vpudrv_buffer_pool_t *pool, *n;
+ struct vpudrv_buffer_t vb;
+
+ enc_pr(LOG_DEBUG, "vpu_free_buffers\n");
+
+ list_for_each_entry_safe(pool, n, &s_vbp_head, list) {
+ if (pool->filp == filp) {
+ vb = pool->vb;
+ if (vb.phys_addr) {
+ vpu_free_dma_buffer(&vb);
+ list_del(&pool->list);
+ kfree(pool);
+ }
+ }
+ }
+ return 0;
+}
+
+static u32 vpu_is_buffer_cached(struct file *filp, ulong vm_pgoff)
+{
+ struct vpudrv_buffer_pool_t *pool, *n;
+ struct vpudrv_buffer_t vb;
+ bool find = false;
+ u32 cached = 0;
+
+ enc_pr(LOG_ALL, "[+]vpu_is_buffer_cached\n");
+ spin_lock(&s_vpu_lock);
+ list_for_each_entry_safe(pool, n, &s_vbp_head, list) {
+ if (pool->filp == filp) {
+ vb = pool->vb;
+ if (((vb.phys_addr >> PAGE_SHIFT) == vm_pgoff)
+ && find == false){
+ cached = vb.cached;
+ find = true;
+ }
+ }
+ }
+ spin_unlock(&s_vpu_lock);
+ enc_pr(LOG_ALL, "[-]vpu_is_buffer_cached, ret:%d\n", cached);
+ return cached;
+}
+
+static void hevcenc_isr_tasklet(ulong data)
+{
+ struct vpu_drv_context_t *dev = (struct vpu_drv_context_t *)data;
+
+ enc_pr(LOG_INFO, "hevcenc_isr_tasklet interruput:0x%08lx\n",
+ dev->interrupt_reason);
+ if (dev->interrupt_reason) {
+ /* notify the interrupt to user space */
+ if (dev->async_queue) {
+ enc_pr(LOG_ALL, "kill_fasync e %s\n", __func__);
+ kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
+ }
+ s_interrupt_flag = 1;
+ wake_up_interruptible(&s_interrupt_wait_q);
+ }
+ enc_pr(LOG_ALL, "[-]%s\n", __func__);
+}
+
+static irqreturn_t vpu_irq_handler(s32 irq, void *dev_id)
+{
+ struct vpu_drv_context_t *dev = (struct vpu_drv_context_t *)dev_id;
+ /* this can be removed.
+ * it also work in VPU_WaitInterrupt of API function
+ */
+ u32 core;
+ ulong interrupt_reason = 0;
+
+ enc_pr(LOG_ALL, "[+]%s\n", __func__);
+
+ for (core = 0; core < MAX_NUM_VPU_CORE; core++) {
+ if (s_bit_firmware_info[core].size == 0) {
+ /* it means that we didn't get an information
+ * the current core from API layer.
+ * No core activated.
+ */
+ enc_pr(LOG_ERROR,
+ "s_bit_firmware_info[core].size is zero\n");
+ continue;
+ }
+ if (ReadVpuRegister(W4_VPU_VPU_INT_STS)) {
+ interrupt_reason = ReadVpuRegister(W4_VPU_INT_REASON);
+ WriteVpuRegister(W4_VPU_INT_REASON_CLEAR,
+ interrupt_reason);
+ WriteVpuRegister(W4_VPU_VINT_CLEAR, 0x1);
+ dev->interrupt_reason |= interrupt_reason;
+ }
+ enc_pr(LOG_INFO,
+ "intr_reason: 0x%08lx\n", dev->interrupt_reason);
+ }
+ if (dev->interrupt_reason)
+ tasklet_schedule(&hevc_tasklet);
+ enc_pr(LOG_ALL, "[-]%s\n", __func__);
+ return IRQ_HANDLED;
+}
+
+static s32 vpu_open(struct inode *inode, struct file *filp)
+{
+ bool alloc_buffer = false;
+ s32 r = 0;
+
+ enc_pr(LOG_DEBUG, "[+] %s\n", __func__);
+ spin_lock(&s_vpu_lock);
+ s_vpu_drv_context.open_count++;
+ if (s_vpu_drv_context.open_count == 1) {
+ alloc_buffer = true;
+ } else {
+ r = -EBUSY;
+ s_vpu_drv_context.open_count--;
+ spin_unlock(&s_vpu_lock);
+ goto Err;
+ }
+ filp->private_data = (void *)(&s_vpu_drv_context);
+ spin_unlock(&s_vpu_lock);
+ if (alloc_buffer && !use_reserve) {
+#ifdef CONFIG_CMA
+ s_video_memory.size = VPU_INIT_VIDEO_MEMORY_SIZE_IN_BYTE;
+ s_video_memory.phys_addr =
+ (ulong)codec_mm_alloc_for_dma(VPU_DEV_NAME,
+ VPU_INIT_VIDEO_MEMORY_SIZE_IN_BYTE >> PAGE_SHIFT, 0, 0);
+ if (s_video_memory.phys_addr) {
+ enc_pr(LOG_DEBUG,
+ "allocating phys 0x%lx, virt addr 0x%lx, size %dk\n",
+ s_video_memory.phys_addr,
+ s_video_memory.base,
+ s_video_memory.size >> 10);
+ if (vmem_init(&s_vmem,
+ s_video_memory.phys_addr,
+ s_video_memory.size) < 0) {
+ enc_pr(LOG_ERROR, "fail to init vmem system\n");
+ r = -ENOMEM;
+ codec_mm_free_for_dma(
+ VPU_DEV_NAME,
+ (u32)s_video_memory.phys_addr);
+ vmem_exit(&s_vmem);
+ memset(&s_video_memory, 0,
+ sizeof(struct vpudrv_buffer_t));
+ memset(&s_vmem, 0,
+ sizeof(struct video_mm_t));
+ }
+ } else {
+ enc_pr(LOG_ERROR,
+ "CMA failed to allocate dma buffer for %s, phys: 0x%lx\n",
+ VPU_DEV_NAME, s_video_memory.phys_addr);
+ if (s_video_memory.phys_addr)
+ codec_mm_free_for_dma(
+ VPU_DEV_NAME,
+ (u32)s_video_memory.phys_addr);
+ s_video_memory.phys_addr = 0;
+ r = -ENOMEM;
+ }
+#else
+ enc_pr(LOG_ERROR,
+ "No CMA and reserved memory for HevcEnc!!!\n");
+ r = -ENOMEM;
+#endif
+ } else if (!s_video_memory.phys_addr) {
+ enc_pr(LOG_ERROR,
+ "HevcEnc memory is not malloced!!!\n");
+ r = -ENOMEM;
+ }
+ if (alloc_buffer) {
+ ulong flags;
+ u32 data32;
+
+ if ((s_vpu_irq >= 0) && (s_vpu_irq_requested == false)) {
+ s32 err;
+
+ err = request_irq(s_vpu_irq, vpu_irq_handler, 0,
+ "HevcEnc-irq", (void *)(&s_vpu_drv_context));
+ if (err) {
+ enc_pr(LOG_ERROR,
+ "fail to register interrupt handler\n");
+ s_vpu_drv_context.open_count--;
+ return -EFAULT;
+ }
+ s_vpu_irq_requested = true;
+ }
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+
+ } else
+ amports_switch_gate("vdec", 1);
+
+ spin_lock_irqsave(&s_vpu_lock, flags);
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+ //vpu_clk_config(1);
+ pwr_ctrl_psci_smc(PDID_DOS_WAVE, PWR_ON);
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) &
+ (get_cpu_type() == MESON_CPU_MAJOR_ID_SM1
+ ? ~0x8 : ~(0x3<<24)));
+ }
+ udelay(10);
+
+ if (get_cpu_type() <= MESON_CPU_MAJOR_ID_TXLX) {
+ data32 = 0x700;
+ data32 |= READ_VREG(DOS_SW_RESET4);
+ WRITE_VREG(DOS_SW_RESET4, data32);
+ data32 &= ~0x700;
+ WRITE_VREG(DOS_SW_RESET4, data32);
+ } else {
+ data32 = 0xf00;
+ data32 |= READ_VREG(DOS_SW_RESET4);
+ WRITE_VREG(DOS_SW_RESET4, data32);
+ data32 &= ~0xf00;
+ WRITE_VREG(DOS_SW_RESET4, data32);
+ }
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+ pr_err("consider using reset control\n");
+ } else {
+ WRITE_MPEG_REG(RESET0_REGISTER, data32 & ~(1<<21));
+ WRITE_MPEG_REG(RESET0_REGISTER, data32 | (1<<21));
+ READ_MPEG_REG(RESET0_REGISTER);
+ READ_MPEG_REG(RESET0_REGISTER);
+ READ_MPEG_REG(RESET0_REGISTER);
+ READ_MPEG_REG(RESET0_REGISTER);
+ }
+
+#ifndef VPU_SUPPORT_CLOCK_CONTROL
+ vpu_clk_config(1);
+#endif
+ /* Enable wave420l_vpu_idle_rise_irq,
+ * Disable wave420l_vpu_idle_fall_irq
+ */
+ WRITE_VREG(DOS_WAVE420L_CNTL_STAT, 0x1);
+ WRITE_VREG(DOS_MEM_PD_WAVE420L, 0x0);
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) &
+ (get_cpu_type() == MESON_CPU_MAJOR_ID_SM1
+ ? ~0x8 : ~(0x3<<12)));
+ }
+ spin_unlock_irqrestore(&s_vpu_lock, flags);
+ }
+ memset(dma_cfg, 0, sizeof(dma_cfg));
+ dma_cfg[0].fd = -1;
+ dma_cfg[1].fd = -1;
+ dma_cfg[2].fd = -1;
+Err:
+ if (r != 0)
+ s_vpu_drv_context.open_count--;
+ enc_pr(LOG_DEBUG, "[-] %s, ret: %d\n", __func__, r);
+ return r;
+}
+
+static long vpu_ioctl(struct file *filp, u32 cmd, ulong arg)
+{
+ s32 ret = 0;
+ struct vpu_drv_context_t *dev =
+ (struct vpu_drv_context_t *)filp->private_data;
+
+ switch (cmd) {
+ case VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY:
+ {
+ struct vpudrv_buffer_pool_t *vbp;
+
+ enc_pr(LOG_ALL,
+ "[+]VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY\n");
+ ret = down_interruptible(&s_vpu_sem);
+ if (ret == 0) {
+ vbp = kzalloc(sizeof(*vbp), GFP_KERNEL);
+ if (!vbp) {
+ up(&s_vpu_sem);
+ return -ENOMEM;
+ }
+
+ ret = copy_from_user(&(vbp->vb),
+ (struct vpudrv_buffer_t *)arg,
+ sizeof(struct vpudrv_buffer_t));
+ if (ret) {
+ kfree(vbp);
+ up(&s_vpu_sem);
+ return -EFAULT;
+ }
+
+ ret = vpu_alloc_dma_buffer(&(vbp->vb));
+ if (ret == -1) {
+ ret = -ENOMEM;
+ kfree(vbp);
+ up(&s_vpu_sem);
+ break;
+ }
+ ret = copy_to_user((void __user *)arg,
+ &(vbp->vb),
+ sizeof(struct vpudrv_buffer_t));
+ if (ret) {
+ kfree(vbp);
+ ret = -EFAULT;
+ up(&s_vpu_sem);
+ break;
+ }
+
+ vbp->filp = filp;
+ spin_lock(&s_vpu_lock);
+ list_add(&vbp->list, &s_vbp_head);
+ spin_unlock(&s_vpu_lock);
+
+ up(&s_vpu_sem);
+ }
+ enc_pr(LOG_ALL,
+ "[-]VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY\n");
+ }
+ break;
+#ifdef CONFIG_COMPAT
+ case VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY32:
+ {
+ struct vpudrv_buffer_pool_t *vbp;
+ struct compat_vpudrv_buffer_t buf32;
+
+ enc_pr(LOG_ALL,
+ "[+]VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY32\n");
+ ret = down_interruptible(&s_vpu_sem);
+ if (ret == 0) {
+ vbp = kzalloc(sizeof(*vbp), GFP_KERNEL);
+ if (!vbp) {
+ up(&s_vpu_sem);
+ return -ENOMEM;
+ }
+
+ ret = copy_from_user(&buf32,
+ (struct compat_vpudrv_buffer_t *)arg,
+ sizeof(struct compat_vpudrv_buffer_t));
+ if (ret) {
+ kfree(vbp);
+ up(&s_vpu_sem);
+ return -EFAULT;
+ }
+
+ vbp->vb.size = buf32.size;
+ vbp->vb.cached = buf32.cached;
+ vbp->vb.phys_addr =
+ (ulong)buf32.phys_addr;
+ vbp->vb.virt_addr =
+ (ulong)buf32.virt_addr;
+ ret = vpu_alloc_dma_buffer(&(vbp->vb));
+ if (ret == -1) {
+ ret = -ENOMEM;
+ kfree(vbp);
+ up(&s_vpu_sem);
+ break;
+ }
+
+ buf32.size = vbp->vb.size;
+ buf32.phys_addr =
+ (compat_ulong_t)vbp->vb.phys_addr;
+ buf32.virt_addr =
+ (compat_ulong_t)vbp->vb.virt_addr;
+
+ ret = copy_to_user((void __user *)arg,
+ &buf32,
+ sizeof(struct compat_vpudrv_buffer_t));
+ if (ret) {
+ kfree(vbp);
+ ret = -EFAULT;
+ up(&s_vpu_sem);
+ break;
+ }
+
+ vbp->filp = filp;
+ spin_lock(&s_vpu_lock);
+ list_add(&vbp->list, &s_vbp_head);
+ spin_unlock(&s_vpu_lock);
+
+ up(&s_vpu_sem);
+ }
+ enc_pr(LOG_ALL,
+ "[-]VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY32\n");
+ }
+ break;
+#endif
+ case VDI_IOCTL_FREE_PHYSICALMEMORY:
+ {
+ struct vpudrv_buffer_pool_t *vbp, *n;
+ struct vpudrv_buffer_t vb;
+
+ enc_pr(LOG_ALL,
+ "[+]VDI_IOCTL_FREE_PHYSICALMEMORY\n");
+ ret = down_interruptible(&s_vpu_sem);
+ if (ret == 0) {
+ ret = copy_from_user(&vb,
+ (struct vpudrv_buffer_t *)arg,
+ sizeof(struct vpudrv_buffer_t));
+ if (ret) {
+ up(&s_vpu_sem);
+ return -EACCES;
+ }
+
+ if (vb.phys_addr)
+ vpu_free_dma_buffer(&vb);
+
+ spin_lock(&s_vpu_lock);
+ list_for_each_entry_safe(vbp, n,
+ &s_vbp_head, list) {
+ if (vbp->vb.phys_addr == vb.phys_addr) {
+ list_del(&vbp->list);
+ kfree(vbp);
+ break;
+ }
+ }
+ spin_unlock(&s_vpu_lock);
+
+ up(&s_vpu_sem);
+ }
+ enc_pr(LOG_ALL,
+ "[-]VDI_IOCTL_FREE_PHYSICALMEMORY\n");
+ }
+ break;
+#ifdef CONFIG_COMPAT
+ case VDI_IOCTL_FREE_PHYSICALMEMORY32:
+ {
+ struct vpudrv_buffer_pool_t *vbp, *n;
+ struct compat_vpudrv_buffer_t buf32;
+ struct vpudrv_buffer_t vb;
+
+ enc_pr(LOG_ALL,
+ "[+]VDI_IOCTL_FREE_PHYSICALMEMORY32\n");
+ ret = down_interruptible(&s_vpu_sem);
+ if (ret == 0) {
+ ret = copy_from_user(&buf32,
+ (struct compat_vpudrv_buffer_t *)arg,
+ sizeof(struct compat_vpudrv_buffer_t));
+ if (ret) {
+ up(&s_vpu_sem);
+ return -EACCES;
+ }
+
+ vb.size = buf32.size;
+ vb.phys_addr =
+ (ulong)buf32.phys_addr;
+ vb.virt_addr =
+ (ulong)buf32.virt_addr;
+
+ if (vb.phys_addr)
+ vpu_free_dma_buffer(&vb);
+
+ spin_lock(&s_vpu_lock);
+ list_for_each_entry_safe(vbp, n,
+ &s_vbp_head, list) {
+ if ((compat_ulong_t)vbp->vb.base
+ == buf32.base) {
+ list_del(&vbp->list);
+ kfree(vbp);
+ break;
+ }
+ }
+ spin_unlock(&s_vpu_lock);
+ up(&s_vpu_sem);
+ }
+ enc_pr(LOG_ALL,
+ "[-]VDI_IOCTL_FREE_PHYSICALMEMORY32\n");
+ }
+ break;
+#endif
+ case VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO:
+ {
+ enc_pr(LOG_ALL,
+ "[+]VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO\n");
+ if (s_video_memory.phys_addr != 0) {
+ ret = copy_to_user((void __user *)arg,
+ &s_video_memory,
+ sizeof(struct vpudrv_buffer_t));
+ if (ret != 0)
+ ret = -EFAULT;
+ } else {
+ ret = -EFAULT;
+ }
+ enc_pr(LOG_ALL,
+ "[-]VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO\n");
+ }
+ break;
+#ifdef CONFIG_COMPAT
+ case VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO32:
+ {
+ struct compat_vpudrv_buffer_t buf32;
+
+ enc_pr(LOG_ALL,
+ "[+]VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO32\n");
+
+ buf32.size = s_video_memory.size;
+ buf32.phys_addr =
+ (compat_ulong_t)s_video_memory.phys_addr;
+ buf32.virt_addr =
+ (compat_ulong_t)s_video_memory.virt_addr;
+ if (s_video_memory.phys_addr != 0) {
+ ret = copy_to_user((void __user *)arg,
+ &buf32,
+ sizeof(struct compat_vpudrv_buffer_t));
+ if (ret != 0)
+ ret = -EFAULT;
+ } else {
+ ret = -EFAULT;
+ }
+ enc_pr(LOG_ALL,
+ "[-]VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO32\n");
+ }
+ break;
+#endif
+ case VDI_IOCTL_WAIT_INTERRUPT:
+ {
+ struct vpudrv_intr_info_t info;
+
+ enc_pr(LOG_ALL,
+ "[+]VDI_IOCTL_WAIT_INTERRUPT\n");
+ ret = copy_from_user(&info,
+ (struct vpudrv_intr_info_t *)arg,
+ sizeof(struct vpudrv_intr_info_t));
+ if (ret != 0)
+ return -EFAULT;
+
+ ret = wait_event_interruptible_timeout(
+ s_interrupt_wait_q,
+ s_interrupt_flag != 0,
+ msecs_to_jiffies(info.timeout));
+ if (!ret) {
+ ret = -ETIME;
+ break;
+ }
+ enc_pr(LOG_INFO,
+ "s_interrupt_flag(%d), reason(0x%08lx)\n",
+ s_interrupt_flag, dev->interrupt_reason);
+ if (dev->interrupt_reason & (1 << W4_INT_ENC_PIC)) {
+ u32 start, end, size, core = 0;
+
+ start = ReadVpuRegister(W4_BS_RD_PTR);
+ end = ReadVpuRegister(W4_BS_WR_PTR);
+ size = ReadVpuRegister(W4_RET_ENC_PIC_BYTE);
+ enc_pr(LOG_INFO, "flush output buffer, ");
+ enc_pr(LOG_INFO,
+ "start:0x%x, end:0x%x, size:0x%x\n",
+ start, end, size);
+ if (end - start > size && end > start)
+ size = end - start;
+ if (size > 0)
+ cache_flush(start, size);
+ }
+
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+
+ enc_pr(LOG_INFO,
+ "s_interrupt_flag(%d), reason(0x%08lx)\n",
+ s_interrupt_flag, dev->interrupt_reason);
+
+ info.intr_reason = dev->interrupt_reason;
+ s_interrupt_flag = 0;
+ dev->interrupt_reason = 0;
+ ret = copy_to_user((void __user *)arg,
+ &info, sizeof(struct vpudrv_intr_info_t));
+ enc_pr(LOG_ALL,
+ "[-]VDI_IOCTL_WAIT_INTERRUPT\n");
+ if (ret != 0)
+ return -EFAULT;
+ }
+ break;
+ case VDI_IOCTL_SET_CLOCK_GATE:
+ {
+ u32 clkgate;
+
+ enc_pr(LOG_ALL,
+ "[+]VDI_IOCTL_SET_CLOCK_GATE\n");
+ if (get_user(clkgate, (u32 __user *) arg))
+ return -EFAULT;
+#ifdef VPU_SUPPORT_CLOCK_CONTROL
+ vpu_clk_config(clkgate);
+#endif
+ enc_pr(LOG_ALL,
+ "[-]VDI_IOCTL_SET_CLOCK_GATE\n");
+ }
+ break;
+ case VDI_IOCTL_GET_INSTANCE_POOL:
+ {
+ enc_pr(LOG_ALL,
+ "[+]VDI_IOCTL_GET_INSTANCE_POOL\n");
+ ret = down_interruptible(&s_vpu_sem);
+ if (ret != 0)
+ break;
+
+ if (s_instance_pool.base != 0) {
+ ret = copy_to_user((void __user *)arg,
+ &s_instance_pool,
+ sizeof(struct vpudrv_buffer_t));
+ ret = (ret != 0) ? -EFAULT : 0;
+ } else {
+ ret = copy_from_user(&s_instance_pool,
+ (struct vpudrv_buffer_t *)arg,
+ sizeof(struct vpudrv_buffer_t));
+ if (ret == 0) {
+ s_instance_pool.size =
+ PAGE_ALIGN(
+ s_instance_pool.size);
+ s_instance_pool.base =
+ (ulong)vmalloc(
+ s_instance_pool.size);
+ s_instance_pool.phys_addr =
+ s_instance_pool.base;
+ if (s_instance_pool.base == 0) {
+ ret = -EFAULT;
+ up(&s_vpu_sem);
+ break;
+ }
+ /*clearing memory*/
+ memset((void *)s_instance_pool.base,
+ 0, s_instance_pool.size);
+ ret = copy_to_user((void __user *)arg,
+ &s_instance_pool,
+ sizeof(struct vpudrv_buffer_t));
+ if (ret != 0)
+ ret = -EFAULT;
+ } else
+ ret = -EFAULT;
+ }
+ up(&s_vpu_sem);
+ enc_pr(LOG_ALL,
+ "[-]VDI_IOCTL_GET_INSTANCE_POOL\n");
+ }
+ break;
+#ifdef CONFIG_COMPAT
+ case VDI_IOCTL_GET_INSTANCE_POOL32:
+ {
+ struct compat_vpudrv_buffer_t buf32;
+
+ enc_pr(LOG_ALL,
+ "[+]VDI_IOCTL_GET_INSTANCE_POOL32\n");
+ ret = down_interruptible(&s_vpu_sem);
+ if (ret != 0)
+ break;
+ if (s_instance_pool.base != 0) {
+ buf32.size = s_instance_pool.size;
+ buf32.phys_addr =
+ (compat_ulong_t)
+ s_instance_pool.phys_addr;
+ buf32.virt_addr =
+ (compat_ulong_t)
+ s_instance_pool.virt_addr;
+ ret = copy_to_user((void __user *)arg,
+ &buf32,
+ sizeof(struct compat_vpudrv_buffer_t));
+ ret = (ret != 0) ? -EFAULT : 0;
+ } else {
+ ret = copy_from_user(&buf32,
+ (struct compat_vpudrv_buffer_t *)arg,
+ sizeof(struct compat_vpudrv_buffer_t));
+ if (ret == 0) {
+ s_instance_pool.size = buf32.size;
+ s_instance_pool.size =
+ PAGE_ALIGN(
+ s_instance_pool.size);
+ s_instance_pool.base =
+ (ulong)vmalloc(
+ s_instance_pool.size);
+ s_instance_pool.phys_addr =
+ s_instance_pool.base;
+ buf32.size =
+ s_instance_pool.size;
+ buf32.phys_addr =
+ (compat_ulong_t)
+ s_instance_pool.phys_addr;
+ buf32.base =
+ (compat_ulong_t)
+ s_instance_pool.base;
+ buf32.virt_addr =
+ (compat_ulong_t)
+ s_instance_pool.virt_addr;
+ if (s_instance_pool.base == 0) {
+ ret = -EFAULT;
+ up(&s_vpu_sem);
+ break;
+ }
+ /*clearing memory*/
+ memset((void *)s_instance_pool.base,
+ 0x0, s_instance_pool.size);
+ ret = copy_to_user((void __user *)arg,
+ &buf32,
+ sizeof(
+ struct compat_vpudrv_buffer_t));
+ if (ret != 0)
+ ret = -EFAULT;
+ } else
+ ret = -EFAULT;
+ }
+ up(&s_vpu_sem);
+ enc_pr(LOG_ALL,
+ "[-]VDI_IOCTL_GET_INSTANCE_POOL32\n");
+ }
+ break;
+#endif
+ case VDI_IOCTL_GET_COMMON_MEMORY:
+ {
+ enc_pr(LOG_ALL,
+ "[+]VDI_IOCTL_GET_COMMON_MEMORY\n");
+ if (s_common_memory.phys_addr != 0) {
+ ret = copy_to_user((void __user *)arg,
+ &s_common_memory,
+ sizeof(struct vpudrv_buffer_t));
+ if (ret != 0)
+ ret = -EFAULT;
+ } else {
+ ret = copy_from_user(&s_common_memory,
+ (struct vpudrv_buffer_t *)arg,
+ sizeof(struct vpudrv_buffer_t));
+ if (ret != 0) {
+ ret = -EFAULT;
+ break;
+ }
+ if (vpu_alloc_dma_buffer(
+ &s_common_memory) != -1) {
+ ret = copy_to_user((void __user *)arg,
+ &s_common_memory,
+ sizeof(struct vpudrv_buffer_t));
+ if (ret != 0)
+ ret = -EFAULT;
+ } else
+ ret = -EFAULT;
+ }
+ enc_pr(LOG_ALL,
+ "[-]VDI_IOCTL_GET_COMMON_MEMORY\n");
+ }
+ break;
+#ifdef CONFIG_COMPAT
+ case VDI_IOCTL_GET_COMMON_MEMORY32:
+ {
+ struct compat_vpudrv_buffer_t buf32;
+
+ enc_pr(LOG_ALL,
+ "[+]VDI_IOCTL_GET_COMMON_MEMORY32\n");
+
+ buf32.size = s_common_memory.size;
+ buf32.phys_addr =
+ (compat_ulong_t)
+ s_common_memory.phys_addr;
+ buf32.virt_addr =
+ (compat_ulong_t)
+ s_common_memory.virt_addr;
+ if (s_common_memory.phys_addr != 0) {
+ ret = copy_to_user((void __user *)arg,
+ &buf32,
+ sizeof(struct compat_vpudrv_buffer_t));
+ if (ret != 0)
+ ret = -EFAULT;
+ } else {
+ ret = copy_from_user(&buf32,
+ (struct compat_vpudrv_buffer_t *)arg,
+ sizeof(struct compat_vpudrv_buffer_t));
+ if (ret != 0) {
+ ret = -EFAULT;
+ break;
+ }
+ s_common_memory.size = buf32.size;
+ if (vpu_alloc_dma_buffer(
+ &s_common_memory) != -1) {
+ buf32.size =
+ s_common_memory.size;
+ buf32.phys_addr =
+ (compat_ulong_t)
+ s_common_memory.phys_addr;
+ buf32.virt_addr =
+ (compat_ulong_t)
+ s_common_memory.virt_addr;
+ ret = copy_to_user((void __user *)arg,
+ &buf32,
+ sizeof(
+ struct compat_vpudrv_buffer_t));
+ if (ret != 0)
+ ret = -EFAULT;
+ } else
+ ret = -EFAULT;
+ }
+ enc_pr(LOG_ALL,
+ "[-]VDI_IOCTL_GET_COMMON_MEMORY32\n");
+ }
+ break;
+#endif
+ case VDI_IOCTL_OPEN_INSTANCE:
+ {
+ struct vpudrv_inst_info_t inst_info;
+ struct vpudrv_instanace_list_t *vil, *n;
+
+ vil = kzalloc(sizeof(*vil), GFP_KERNEL);
+ if (!vil)
+ return -ENOMEM;
+
+ if (copy_from_user(&inst_info,
+ (struct vpudrv_inst_info_t *)arg,
+ sizeof(struct vpudrv_inst_info_t)))
+ return -EFAULT;
+
+ vil->inst_idx = inst_info.inst_idx;
+ vil->core_idx = inst_info.core_idx;
+ vil->filp = filp;
+
+ spin_lock(&s_vpu_lock);
+ list_add(&vil->list, &s_inst_list_head);
+
+ /* counting the current open instance number */
+ inst_info.inst_open_count = 0;
+ list_for_each_entry_safe(vil, n,
+ &s_inst_list_head, list) {
+ if (vil->core_idx == inst_info.core_idx)
+ inst_info.inst_open_count++;
+ }
+
+ /* flag just for that vpu is in opened or closed */
+ s_vpu_open_ref_count++;
+ spin_unlock(&s_vpu_lock);
+
+ if (copy_to_user((void __user *)arg,
+ &inst_info,
+ sizeof(struct vpudrv_inst_info_t))) {
+ kfree(vil);
+ return -EFAULT;
+ }
+
+ enc_pr(LOG_DEBUG,
+ "VDI_IOCTL_OPEN_INSTANCE ");
+ enc_pr(LOG_DEBUG,
+ "core_idx=%d, inst_idx=%d, ",
+ (u32)inst_info.core_idx,
+ (u32)inst_info.inst_idx);
+ enc_pr(LOG_DEBUG,
+ "s_vpu_open_ref_count=%d, inst_open_count=%d\n",
+ s_vpu_open_ref_count,
+ inst_info.inst_open_count);
+ }
+ break;
+ case VDI_IOCTL_CLOSE_INSTANCE:
+ {
+ struct vpudrv_inst_info_t inst_info;
+ struct vpudrv_instanace_list_t *vil, *n;
+
+ enc_pr(LOG_ALL,
+ "[+]VDI_IOCTL_CLOSE_INSTANCE\n");
+ if (copy_from_user(&inst_info,
+ (struct vpudrv_inst_info_t *)arg,
+ sizeof(struct vpudrv_inst_info_t)))
+ return -EFAULT;
+
+ spin_lock(&s_vpu_lock);
+ list_for_each_entry_safe(vil, n,
+ &s_inst_list_head, list) {
+ if (vil->inst_idx == inst_info.inst_idx &&
+ vil->core_idx == inst_info.core_idx) {
+ list_del(&vil->list);
+ kfree(vil);
+ break;
+ }
+ }
+
+ /* counting the current open instance number */
+ inst_info.inst_open_count = 0;
+ list_for_each_entry_safe(vil, n,
+ &s_inst_list_head, list) {
+ if (vil->core_idx == inst_info.core_idx)
+ inst_info.inst_open_count++;
+ }
+
+ /* flag just for that vpu is in opened or closed */
+ s_vpu_open_ref_count--;
+ spin_unlock(&s_vpu_lock);
+
+ if (copy_to_user((void __user *)arg,
+ &inst_info,
+ sizeof(struct vpudrv_inst_info_t)))
+ return -EFAULT;
+
+ enc_pr(LOG_DEBUG,
+ "VDI_IOCTL_CLOSE_INSTANCE ");
+ enc_pr(LOG_DEBUG,
+ "core_idx=%d, inst_idx=%d, ",
+ (u32)inst_info.core_idx,
+ (u32)inst_info.inst_idx);
+ enc_pr(LOG_DEBUG,
+ "s_vpu_open_ref_count=%d, inst_open_count=%d\n",
+ s_vpu_open_ref_count,
+ inst_info.inst_open_count);
+ }
+ break;
+ case VDI_IOCTL_GET_INSTANCE_NUM:
+ {
+ struct vpudrv_inst_info_t inst_info;
+ struct vpudrv_instanace_list_t *vil, *n;
+
+ enc_pr(LOG_ALL,
+ "[+]VDI_IOCTL_GET_INSTANCE_NUM\n");
+
+ ret = copy_from_user(&inst_info,
+ (struct vpudrv_inst_info_t *)arg,
+ sizeof(struct vpudrv_inst_info_t));
+ if (ret != 0)
+ break;
+
+ inst_info.inst_open_count = 0;
+
+ spin_lock(&s_vpu_lock);
+ list_for_each_entry_safe(vil, n,
+ &s_inst_list_head, list) {
+ if (vil->core_idx == inst_info.core_idx)
+ inst_info.inst_open_count++;
+ }
+ spin_unlock(&s_vpu_lock);
+
+ ret = copy_to_user((void __user *)arg,
+ &inst_info,
+ sizeof(struct vpudrv_inst_info_t));
+
+ enc_pr(LOG_DEBUG,
+ "VDI_IOCTL_GET_INSTANCE_NUM ");
+ enc_pr(LOG_DEBUG,
+ "core_idx=%d, inst_idx=%d, open_count=%d\n",
+ (u32)inst_info.core_idx,
+ (u32)inst_info.inst_idx,
+ inst_info.inst_open_count);
+ }
+ break;
+ case VDI_IOCTL_RESET:
+ {
+ vpu_hw_reset();
+ }
+ break;
+ case VDI_IOCTL_GET_REGISTER_INFO:
+ {
+ enc_pr(LOG_ALL,
+ "[+]VDI_IOCTL_GET_REGISTER_INFO\n");
+ ret = copy_to_user((void __user *)arg,
+ &s_vpu_register,
+ sizeof(struct vpudrv_buffer_t));
+ if (ret != 0)
+ ret = -EFAULT;
+ enc_pr(LOG_ALL,
+ "[-]VDI_IOCTL_GET_REGISTER_INFO ");
+ enc_pr(LOG_ALL,
+ "s_vpu_register.phys_addr=0x%lx, ",
+ s_vpu_register.phys_addr);
+ enc_pr(LOG_ALL,
+ "s_vpu_register.virt_addr=0x%lx, ",
+ s_vpu_register.virt_addr);
+ enc_pr(LOG_ALL,
+ "s_vpu_register.size=0x%x\n",
+ s_vpu_register.size);
+ }
+ break;
+#ifdef CONFIG_COMPAT
+ case VDI_IOCTL_GET_REGISTER_INFO32:
+ {
+ struct compat_vpudrv_buffer_t buf32;
+
+ enc_pr(LOG_ALL,
+ "[+]VDI_IOCTL_GET_REGISTER_INFO32\n");
+
+ buf32.size = s_vpu_register.size;
+ buf32.phys_addr =
+ (compat_ulong_t)
+ s_vpu_register.phys_addr;
+ buf32.virt_addr =
+ (compat_ulong_t)
+ s_vpu_register.virt_addr;
+ ret = copy_to_user((void __user *)arg,
+ &buf32,
+ sizeof(
+ struct compat_vpudrv_buffer_t));
+ if (ret != 0)
+ ret = -EFAULT;
+ enc_pr(LOG_ALL,
+ "[-]VDI_IOCTL_GET_REGISTER_INFO32 ");
+ enc_pr(LOG_ALL,
+ "s_vpu_register.phys_addr=0x%lx, ",
+ s_vpu_register.phys_addr);
+ enc_pr(LOG_ALL,
+ "s_vpu_register.virt_addr=0x%lx, ",
+ s_vpu_register.virt_addr);
+ enc_pr(LOG_ALL,
+ "s_vpu_register.size=0x%x\n",
+ s_vpu_register.size);
+ }
+ break;
+ case VDI_IOCTL_FLUSH_BUFFER32:
+ {
+ struct vpudrv_buffer_pool_t *pool, *n;
+ struct compat_vpudrv_buffer_t buf32;
+ struct vpudrv_buffer_t vb;
+ bool find = false;
+ u32 cached = 0;
+
+ enc_pr(LOG_ALL,
+ "[+]VDI_IOCTL_FLUSH_BUFFER32\n");
+
+ ret = copy_from_user(&buf32,
+ (struct compat_vpudrv_buffer_t *)arg,
+ sizeof(struct compat_vpudrv_buffer_t));
+ if (ret)
+ return -EFAULT;
+ spin_lock(&s_vpu_lock);
+ list_for_each_entry_safe(pool, n,
+ &s_vbp_head, list) {
+ if (pool->filp == filp) {
+ vb = pool->vb;
+ if (((compat_ulong_t)vb.phys_addr
+ == buf32.phys_addr)
+ && find == false){
+ cached = vb.cached;
+ find = true;
+ }
+ }
+ }
+ spin_unlock(&s_vpu_lock);
+ if (find && cached)
+ dma_flush(
+ (u32)buf32.phys_addr,
+ (u32)buf32.size);
+ enc_pr(LOG_ALL,
+ "[-]VDI_IOCTL_FLUSH_BUFFER32\n");
+ }
+ break;
+#endif
+ case VDI_IOCTL_FLUSH_BUFFER:
+ {
+ struct vpudrv_buffer_pool_t *pool, *n;
+ struct vpudrv_buffer_t vb, buf;
+ bool find = false;
+ u32 cached = 0;
+
+ enc_pr(LOG_ALL,
+ "[+]VDI_IOCTL_FLUSH_BUFFER\n");
+
+ ret = copy_from_user(&buf,
+ (struct vpudrv_buffer_t *)arg,
+ sizeof(struct vpudrv_buffer_t));
+ if (ret)
+ return -EFAULT;
+ spin_lock(&s_vpu_lock);
+ list_for_each_entry_safe(pool, n,
+ &s_vbp_head, list) {
+ if (pool->filp == filp) {
+ vb = pool->vb;
+ if ((vb.phys_addr
+ == buf.phys_addr)
+ && find == false){
+ cached = vb.cached;
+ find = true;
+ }
+ }
+ }
+ spin_unlock(&s_vpu_lock);
+ if (find && cached)
+ dma_flush(
+ (u32)buf.phys_addr,
+ (u32)buf.size);
+ enc_pr(LOG_ALL,
+ "[-]VDI_IOCTL_FLUSH_BUFFER\n");
+ }
+ break;
+ case VDI_IOCTL_CONFIG_DMA:
+ {
+ struct vpu_dma_buf_info_t dma_info;
+
+ enc_pr(LOG_ALL,
+ "[+]VDI_IOCTL_CONFIG_DMA\n");
+ if (copy_from_user(&dma_info,
+ (struct vpu_dma_buf_info_t *)arg,
+ sizeof(struct vpu_dma_buf_info_t)))
+ return -EFAULT;
+
+ if (vpu_src_addr_config(dma_info)) {
+ enc_pr(LOG_ERROR,
+ "src addr config error\n");
+ return -EFAULT;
+ }
+
+ enc_pr(LOG_ALL,
+ "[-]VDI_IOCTL_CONFIG_DMA %d, %d, %d\n",
+ dma_info.fd[0],
+ dma_info.fd[1],
+ dma_info.fd[2]);
+ }
+ break;
+ case VDI_IOCTL_UNMAP_DMA:
+ {
+ enc_pr(LOG_ALL,
+ "[+]VDI_IOCTL_UNMAP_DMA\n");
+
+ vpu_dma_buffer_unmap(&dma_cfg[0]);
+ if (dma_cfg[1].paddr != 0) {
+ vpu_dma_buffer_unmap(&dma_cfg[1]);
+ }
+ if (dma_cfg[2].paddr != 0) {
+ vpu_dma_buffer_unmap(&dma_cfg[2]);
+ }
+ enc_pr(LOG_ALL,
+ "[-]VDI_IOCTL_UNMAP_DMA\n");
+ }
+ break;
+ default:
+ {
+ enc_pr(LOG_ERROR,
+ "No such IOCTL, cmd is 0x%x\n", cmd);
+ ret = -EFAULT;
+ }
+ break;
+ }
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static long vpu_compat_ioctl(struct file *filp, u32 cmd, ulong arg)
+{
+ long ret;
+
+ arg = (ulong)compat_ptr(arg);
+ ret = vpu_ioctl(filp, cmd, arg);
+ return ret;
+}
+#endif
+
+static ssize_t vpu_write(struct file *filp,
+ const char *buf,
+ size_t len,
+ loff_t *ppos)
+{
+ enc_pr(LOG_INFO, "vpu_write len=%d\n", (int)len);
+
+ if (!buf) {
+ enc_pr(LOG_ERROR, "vpu_write buf = NULL error\n");
+ return -EFAULT;
+ }
+
+ if (len == sizeof(struct vpu_bit_firmware_info_t)) {
+ struct vpu_bit_firmware_info_t *bit_firmware_info;
+
+ bit_firmware_info =
+ kmalloc(sizeof(struct vpu_bit_firmware_info_t),
+ GFP_KERNEL);
+ if (!bit_firmware_info) {
+ enc_pr(LOG_ERROR,
+ "vpu_write bit_firmware_info allocation error\n");
+ return -EFAULT;
+ }
+
+ if (copy_from_user(bit_firmware_info, buf, len)) {
+ enc_pr(LOG_ERROR,
+ "vpu_write copy_from_user error for bit_firmware_info\n");
+ return -EFAULT;
+ }
+
+ if (bit_firmware_info->size ==
+ sizeof(struct vpu_bit_firmware_info_t)) {
+ enc_pr(LOG_INFO,
+ "vpu_write set bit_firmware_info coreIdx=0x%x, ",
+ bit_firmware_info->core_idx);
+ enc_pr(LOG_INFO,
+ "reg_base_offset=0x%x size=0x%x, bit_code[0]=0x%x\n",
+ bit_firmware_info->reg_base_offset,
+ bit_firmware_info->size,
+ bit_firmware_info->bit_code[0]);
+
+ if (bit_firmware_info->core_idx
+ > MAX_NUM_VPU_CORE) {
+ enc_pr(LOG_ERROR,
+ "vpu_write coreIdx[%d] is ",
+ bit_firmware_info->core_idx);
+ enc_pr(LOG_ERROR,
+ "exceeded than MAX_NUM_VPU_CORE[%d]\n",
+ MAX_NUM_VPU_CORE);
+ return -ENODEV;
+ }
+
+ memcpy((void *)&s_bit_firmware_info
+ [bit_firmware_info->core_idx],
+ bit_firmware_info,
+ sizeof(struct vpu_bit_firmware_info_t));
+ kfree(bit_firmware_info);
+ return len;
+ }
+ kfree(bit_firmware_info);
+ }
+ return -1;
+}
+
+static s32 vpu_release(struct inode *inode, struct file *filp)
+{
+ s32 ret = 0;
+ ulong flags;
+
+ enc_pr(LOG_DEBUG, "vpu_release\n");
+ ret = down_interruptible(&s_vpu_sem);
+ if (ret == 0) {
+ vpu_free_buffers(filp);
+ vpu_free_instances(filp);
+ s_vpu_drv_context.open_count--;
+ if (s_vpu_drv_context.open_count == 0) {
+ enc_pr(LOG_INFO,
+ "vpu_release: s_interrupt_flag(%d), reason(0x%08lx)\n",
+ s_interrupt_flag, s_vpu_drv_context.interrupt_reason);
+ s_vpu_drv_context.interrupt_reason = 0;
+ s_interrupt_flag = 0;
+ if (s_instance_pool.base) {
+ enc_pr(LOG_DEBUG, "free instance pool\n");
+ vfree((const void *)s_instance_pool.base);
+ s_instance_pool.base = 0;
+ }
+ if (s_common_memory.phys_addr) {
+ enc_pr(LOG_INFO, "vpu_release, s_common_memory 0x%lx\n",s_common_memory.phys_addr);
+ vpu_free_dma_buffer(&s_common_memory);
+ s_common_memory.phys_addr = 0;
+ }
+
+ if (s_video_memory.phys_addr && !use_reserve) {
+ enc_pr(LOG_DEBUG, "vpu_release, s_video_memory 0x%lx\n",s_video_memory.phys_addr);
+ codec_mm_free_for_dma(
+ VPU_DEV_NAME,
+ (u32)s_video_memory.phys_addr);
+ vmem_exit(&s_vmem);
+ memset(&s_video_memory,
+ 0, sizeof(struct vpudrv_buffer_t));
+ memset(&s_vmem,
+ 0, sizeof(struct video_mm_t));
+ }
+
+ if ((s_vpu_irq >= 0) && (s_vpu_irq_requested == true)) {
+ free_irq(s_vpu_irq, &s_vpu_drv_context);
+ s_vpu_irq_requested = false;
+ }
+ spin_lock_irqsave(&s_vpu_lock, flags);
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+ //vpu_clk_config(0);
+ pwr_ctrl_psci_smc(PDID_DOS_WAVE, PWR_OFF);
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) |
+ (get_cpu_type() == MESON_CPU_MAJOR_ID_SM1
+ ? 0x8 : (0x3<<12)));
+ }
+
+ udelay(10);
+
+ WRITE_VREG(DOS_MEM_PD_WAVE420L, 0xffffffff);
+#ifndef VPU_SUPPORT_CLOCK_CONTROL
+ vpu_clk_config(0);
+#endif
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) |
+ (get_cpu_type() == MESON_CPU_MAJOR_ID_SM1
+ ? 0x8 : (0x3<<24)));
+ }
+
+ udelay(10);
+ spin_unlock_irqrestore(&s_vpu_lock, flags);
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+ } else
+ amports_switch_gate("vdec", 0);
+ }
+ }
+ up(&s_vpu_sem);
+ return 0;
+}
+
+static s32 vpu_fasync(s32 fd, struct file *filp, s32 mode)
+{
+ struct vpu_drv_context_t *dev =
+ (struct vpu_drv_context_t *)filp->private_data;
+ return fasync_helper(fd, filp, mode, &dev->async_queue);
+}
+
+static s32 vpu_map_to_register(struct file *fp, struct vm_area_struct *vm)
+{
+ ulong pfn;
+
+ vm->vm_flags |= VM_IO | VM_RESERVED;
+ vm->vm_page_prot =
+ pgprot_noncached(vm->vm_page_prot);
+ pfn = s_vpu_register.phys_addr >> PAGE_SHIFT;
+ return remap_pfn_range(vm, vm->vm_start, pfn,
+ vm->vm_end - vm->vm_start,
+ vm->vm_page_prot) ? -EAGAIN : 0;
+}
+
+static s32 vpu_map_to_physical_memory(
+ struct file *fp, struct vm_area_struct *vm)
+{
+ vm->vm_flags |= VM_IO | VM_RESERVED;
+ if (vm->vm_pgoff ==
+ (s_common_memory.phys_addr >> PAGE_SHIFT)) {
+ vm->vm_page_prot =
+ pgprot_noncached(vm->vm_page_prot);
+ } else {
+ if (vpu_is_buffer_cached(fp, vm->vm_pgoff) == 0)
+ vm->vm_page_prot =
+ pgprot_noncached(vm->vm_page_prot);
+ }
+ /* vm->vm_page_prot = pgprot_writecombine(vm->vm_page_prot); */
+ if (!pfn_valid(vm->vm_pgoff)) {
+ enc_pr(LOG_ERROR, "%s invalid pfn\n", __FUNCTION__);
+ return -EAGAIN;
+ }
+ return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff,
+ vm->vm_end - vm->vm_start, vm->vm_page_prot) ? -EAGAIN : 0;
+}
+
+static s32 vpu_map_to_instance_pool_memory(
+ struct file *fp, struct vm_area_struct *vm)
+{
+ s32 ret;
+ long length = vm->vm_end - vm->vm_start;
+ ulong start = vm->vm_start;
+ s8 *vmalloc_area_ptr = (s8 *)s_instance_pool.base;
+ ulong pfn;
+
+ vm->vm_flags |= VM_RESERVED;
+
+ /* loop over all pages, map it page individually */
+ while (length > 0) {
+ pfn = vmalloc_to_pfn(vmalloc_area_ptr);
+ ret = remap_pfn_range(vm, start, pfn,
+ PAGE_SIZE, PAGE_SHARED);
+ if (ret < 0)
+ return ret;
+ start += PAGE_SIZE;
+ vmalloc_area_ptr += PAGE_SIZE;
+ length -= PAGE_SIZE;
+ }
+ return 0;
+}
+
+/*
+ * @brief memory map interface for vpu file operation
+ * @return 0 on success or negative error code on error
+ */
+static s32 vpu_mmap(struct file *fp, struct vm_area_struct *vm)
+{
+ /* if (vm->vm_pgoff == (s_vpu_register.phys_addr >> PAGE_SHIFT)) */
+ if ((vm->vm_end - vm->vm_start == s_vpu_register.size + 1) &&
+ (vm->vm_pgoff == 0)) {
+ vm->vm_pgoff = (s_vpu_register.phys_addr >> PAGE_SHIFT);
+ return vpu_map_to_register(fp, vm);
+ }
+
+ if (vm->vm_pgoff == 0)
+ return vpu_map_to_instance_pool_memory(fp, vm);
+
+ return vpu_map_to_physical_memory(fp, vm);
+}
+static int vpu_dma_buffer_map(struct vpu_dma_cfg *cfg)
+{
+ int ret = -1;
+ int fd = -1;
+ struct dma_buf *dbuf = NULL;
+ struct dma_buf_attachment *d_att = NULL;
+ struct sg_table *sg = NULL;
+ void *vaddr = NULL;
+ struct device *dev = NULL;
+ enum dma_data_direction dir;
+
+ if (cfg == NULL || (cfg->fd < 0) || cfg->dev == NULL) {
+ enc_pr(LOG_ERROR, "error dma param\n");
+ return -EINVAL;
+ }
+ fd = cfg->fd;
+ dev = cfg->dev;
+ dir = cfg->dir;
+
+ dbuf = dma_buf_get(fd);
+ if (dbuf == NULL) {
+ enc_pr(LOG_ERROR, "failed to get dma buffer,fd %d\n",fd);
+ return -EINVAL;
+ }
+
+ d_att = dma_buf_attach(dbuf, dev);
+ if (d_att == NULL) {
+ enc_pr(LOG_ERROR, "failed to set dma attach\n");
+ goto attach_err;
+ }
+
+ sg = dma_buf_map_attachment(d_att, dir);
+ if (sg == NULL) {
+ enc_pr(LOG_ERROR, "failed to get dma sg\n");
+ goto map_attach_err;
+ }
+ cfg->dbuf = dbuf;
+ cfg->attach = d_att;
+ cfg->vaddr = vaddr;
+ cfg->sg = sg;
+
+ return 0;
+
+map_attach_err:
+ dma_buf_detach(dbuf, d_att);
+attach_err:
+ dma_buf_put(dbuf);
+
+ return ret;
+}
+
+static void vpu_dma_buffer_unmap(struct vpu_dma_cfg *cfg)
+{
+ int fd = -1;
+ struct dma_buf *dbuf = NULL;
+ struct dma_buf_attachment *d_att = NULL;
+ struct sg_table *sg = NULL;
+ /*void *vaddr = NULL;*/
+ struct device *dev = NULL;
+ enum dma_data_direction dir;
+
+ if (cfg == NULL || (cfg->fd < 0) || cfg->dev == NULL
+ || cfg->dbuf == NULL /*|| cfg->vaddr == NULL*/
+ || cfg->attach == NULL || cfg->sg == NULL) {
+ enc_pr(LOG_ERROR, "unmap: Error dma param\n");
+ return;
+ }
+
+ fd = cfg->fd;
+ dev = cfg->dev;
+ dir = cfg->dir;
+ dbuf = cfg->dbuf;
+ d_att = cfg->attach;
+ sg = cfg->sg;
+
+ dma_buf_unmap_attachment(d_att, sg, dir);
+ dma_buf_detach(dbuf, d_att);
+ dma_buf_put(dbuf);
+
+ enc_pr(LOG_INFO, "vpu_dma_buffer_unmap fd %d\n",fd);
+}
+
+static int vpu_dma_buffer_get_phys(struct vpu_dma_cfg *cfg, unsigned long *addr)
+{
+ struct sg_table *sg_table;
+ struct page *page;
+ int ret;
+
+ ret = vpu_dma_buffer_map(cfg);
+ if (ret < 0) {
+ printk("vpu_dma_buffer_map failed\n");
+ return ret;
+ }
+ if (cfg->sg) {
+ sg_table = cfg->sg;
+ page = sg_page(sg_table->sgl);
+ *addr = PFN_PHYS(page_to_pfn(page));
+ ret = 0;
+ }
+ enc_pr(LOG_INFO,"vpu_dma_buffer_get_phys\n");
+
+ return ret;
+}
+
+static u32 vpu_src_addr_config(struct vpu_dma_buf_info_t info) {
+ unsigned long phy_addr_y = 0;
+ unsigned long phy_addr_u = 0;
+ unsigned long phy_addr_v = 0;
+ unsigned long Ysize = info.width * info.height;
+ unsigned long Usize = Ysize >> 2;
+ s32 ret = 0;
+ u32 core = 0;
+
+ //y
+ dma_cfg[0].dir = DMA_TO_DEVICE;
+ dma_cfg[0].fd = info.fd[0];
+ dma_cfg[0].dev = &(hevc_pdev->dev);
+ ret = vpu_dma_buffer_get_phys(&dma_cfg[0], &phy_addr_y);
+ if (ret < 0) {
+ enc_pr(LOG_ERROR, "import fd %d failed\n", info.fd[0]);
+ return -1;
+ }
+
+ //u
+ if (info.num_planes >=2) {
+ dma_cfg[1].dir = DMA_TO_DEVICE;
+ dma_cfg[1].fd = info.fd[1];
+ dma_cfg[1].dev = &(hevc_pdev->dev);
+ ret = vpu_dma_buffer_get_phys(&dma_cfg[1], &phy_addr_u);
+ if (ret < 0) {
+ enc_pr(LOG_ERROR, "import fd %d failed\n", info.fd[1]);
+ return -1;
+ }
+ }
+
+ //v
+ if (info.num_planes >=3) {
+ dma_cfg[2].dir = DMA_TO_DEVICE;
+ dma_cfg[2].fd = info.fd[2];
+ dma_cfg[2].dev = &(hevc_pdev->dev);
+ ret = vpu_dma_buffer_get_phys(&dma_cfg[2], &phy_addr_v);
+ if (ret < 0) {
+ enc_pr(LOG_ERROR, "import fd %d failed\n", info.fd[2]);
+ return -1;
+ }
+ }
+
+ enc_pr(LOG_INFO, "vpu_src_addr_config phy_addr 0x%lx, 0x%lx, 0x%lx\n",
+ phy_addr_y, phy_addr_u, phy_addr_v);
+
+ dma_cfg[0].paddr = (void *)phy_addr_y;
+ dma_cfg[1].paddr = (void *)phy_addr_u;
+ dma_cfg[2].paddr = (void *)phy_addr_v;
+
+ enc_pr(LOG_INFO, "info.num_planes %d, info.fmt %d\n",
+ info.num_planes, info.fmt);
+
+ WriteVpuRegister(W4_SRC_ADDR_Y, phy_addr_y);
+ if (info.num_planes == 1) {
+ if (info.fmt == AMVENC_YUV420) {
+ WriteVpuRegister(W4_SRC_ADDR_U, phy_addr_y + Ysize);
+ WriteVpuRegister(W4_SRC_ADDR_V, phy_addr_y + Ysize + Usize);
+ } else if (info.fmt == AMVENC_NV12 || info.fmt == AMVENC_NV21 ) {
+ WriteVpuRegister(W4_SRC_ADDR_U, phy_addr_y + Ysize);
+ WriteVpuRegister(W4_SRC_ADDR_V, phy_addr_y + Ysize);
+ } else {
+ enc_pr(LOG_ERROR, "not support fmt %d\n", info.fmt);
+ }
+
+ } else if (info.num_planes == 2) {
+ if (info.fmt == AMVENC_NV12 || info.fmt == AMVENC_NV21 ) {
+ WriteVpuRegister(W4_SRC_ADDR_U, phy_addr_u);
+ WriteVpuRegister(W4_SRC_ADDR_V, phy_addr_u);
+ } else {
+ enc_pr(LOG_ERROR, "not support fmt %d\n", info.fmt);
+ }
+
+ } else if (info.num_planes == 3) {
+ if (info.fmt == AMVENC_YUV420) {
+ WriteVpuRegister(W4_SRC_ADDR_U, phy_addr_u);
+ WriteVpuRegister(W4_SRC_ADDR_V, phy_addr_v);
+ } else {
+ enc_pr(LOG_ERROR, "not support fmt %d\n", info.fmt);
+ }
+ }
+ return 0;
+
+}
+
+static const struct file_operations vpu_fops = {
+ .owner = THIS_MODULE,
+ .open = vpu_open,
+ .release = vpu_release,
+ .write = vpu_write,
+ .unlocked_ioctl = vpu_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = vpu_compat_ioctl,
+#endif
+ .fasync = vpu_fasync,
+ .mmap = vpu_mmap,
+};
+
+static ssize_t hevcenc_status_show(struct class *cla,
+ struct class_attribute *attr, char *buf)
+{
+ return snprintf(buf, 40, "hevcenc_status_show\n");
+}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,13,1)
+static struct class_attribute hevcenc_class_attrs[] = {
+ __ATTR(encode_status,
+ S_IRUGO | S_IWUSR,
+ hevcenc_status_show,
+ NULL),
+ __ATTR_NULL
+};
+
+static struct class hevcenc_class = {
+ .name = VPU_CLASS_NAME,
+ .class_attrs = hevcenc_class_attrs,
+};
+#else /* LINUX_VERSION_CODE <= KERNEL_VERSION(4,13,1) */
+
+static CLASS_ATTR_RO(hevcenc_status);
+
+static struct attribute *hevcenc_class_attrs[] = {
+ &class_attr_hevcenc_status.attr,
+ NULL
+};
+
+ATTRIBUTE_GROUPS(hevcenc_class);
+
+static struct class hevcenc_class = {
+ .name = VPU_CLASS_NAME,
+ .class_groups = hevcenc_class_groups,
+};
+#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(4,13,1) */
+
+
+s32 init_HevcEnc_device(void)
+{
+ s32 r = 0;
+
+ r = register_chrdev(0, VPU_DEV_NAME, &vpu_fops);
+ if (r <= 0) {
+ enc_pr(LOG_ERROR, "register hevcenc device error.\n");
+ return r;
+ }
+ s_vpu_major = r;
+
+ r = class_register(&hevcenc_class);
+ if (r < 0) {
+ enc_pr(LOG_ERROR, "error create hevcenc class.\n");
+ return r;
+ }
+
+ hevcenc_dev = device_create(&hevcenc_class, NULL,
+ MKDEV(s_vpu_major, 0), NULL,
+ VPU_DEV_NAME);
+
+ if (IS_ERR(hevcenc_dev)) {
+ enc_pr(LOG_ERROR, "create hevcenc device error.\n");
+ class_unregister(&hevcenc_class);
+ return -1;
+ }
+ return r;
+}
+
+s32 uninit_HevcEnc_device(void)
+{
+ if (hevcenc_dev)
+ device_destroy(&hevcenc_class, MKDEV(s_vpu_major, 0));
+
+ class_destroy(&hevcenc_class);
+
+ unregister_chrdev(s_vpu_major, VPU_DEV_NAME);
+ return 0;
+}
+
+static s32 hevc_mem_device_init(
+ struct reserved_mem *rmem, struct device *dev)
+{
+ s32 r;
+
+ if (!rmem) {
+ enc_pr(LOG_ERROR,
+ "Can not obtain I/O memory, will allocate hevc buffer!\n");
+ r = -EFAULT;
+ return r;
+ }
+
+ if ((!rmem->base) ||
+ (rmem->size < VPU_INIT_VIDEO_MEMORY_SIZE_IN_BYTE)) {
+ enc_pr(LOG_ERROR,
+ "memory range error, 0x%lx - 0x%lx\n",
+ (ulong)rmem->base, (ulong)rmem->size);
+ r = -EFAULT;
+ return r;
+ }
+ r = 0;
+ s_video_memory.size = rmem->size;
+ s_video_memory.phys_addr = (ulong)rmem->base;
+ enc_pr(LOG_DEBUG, "hevc_mem_device_init %d, 0x%lx\n ",s_video_memory.size,s_video_memory.phys_addr);
+
+ return r;
+}
+
+static s32 vpu_probe(struct platform_device *pdev)
+{
+ s32 err = 0, irq, reg_count, idx;
+ struct resource res;
+ struct device_node *np, *child;
+
+ enc_pr(LOG_DEBUG, "vpu_probe fuck, clock_a: %d, clock_b: %d, clock_c: %d\n",
+ wave_clocka, wave_clockb, wave_clockc);
+
+ s_vpu_major = 0;
+ use_reserve = false;
+ s_vpu_irq = -1;
+ cma_pool_size = 0;
+ s_vpu_irq_requested = false;
+ s_vpu_open_ref_count = 0;
+ hevcenc_dev = NULL;
+ hevc_pdev = NULL;
+ memset(&s_video_memory, 0, sizeof(struct vpudrv_buffer_t));
+ memset(&s_vpu_register, 0, sizeof(struct vpudrv_buffer_t));
+ memset(&s_vmem, 0, sizeof(struct video_mm_t));
+ memset(&s_bit_firmware_info[0], 0, sizeof(s_bit_firmware_info));
+ memset(&res, 0, sizeof(struct resource));
+
+ idx = of_reserved_mem_device_init(&pdev->dev);
+
+ if (idx != 0) {
+ enc_pr(LOG_DEBUG,
+ "HevcEnc reserved memory config fail.\n");
+ } else if (s_video_memory.phys_addr) {
+ use_reserve = true;
+ }
+
+ if (use_reserve == false) {
+#ifndef CONFIG_CMA
+ enc_pr(LOG_ERROR,
+ "HevcEnc reserved memory is invaild, probe fail!\n");
+ err = -EFAULT;
+ goto ERROR_PROVE_DEVICE;
+#else
+ cma_pool_size =
+ (codec_mm_get_total_size() >
+ (VPU_INIT_VIDEO_MEMORY_SIZE_IN_BYTE)) ?
+ (VPU_INIT_VIDEO_MEMORY_SIZE_IN_BYTE) :
+ codec_mm_get_total_size();
+ enc_pr(LOG_DEBUG,
+ "HevcEnc - cma memory pool size: %d MB\n",
+ (u32)cma_pool_size / SZ_1M);
+#endif
+ }
+
+ /* get interrupt resource */
+ irq = platform_get_irq_byname(pdev, "wave420l_irq");
+ if (irq < 0) {
+ enc_pr(LOG_ERROR, "get HevcEnc irq resource error\n");
+ err = -ENXIO;
+ goto ERROR_PROVE_DEVICE;
+ }
+ s_vpu_irq = irq;
+ enc_pr(LOG_DEBUG, "HevcEnc - wave420l_irq: %d\n", s_vpu_irq);
+#if 0
+ rstc = devm_reset_control_get(&pdev->dev, "HevcEnc");
+ if (IS_ERR(rstc)) {
+ enc_pr(LOG_ERROR,
+ "get HevcEnc rstc error: %lx\n", PTR_ERR(rstc));
+ rstc = NULL;
+ err = -ENOENT;
+ goto ERROR_PROVE_DEVICE;
+ }
+ reset_control_assert(rstc);
+ s_vpu_rstc = rstc;
+
+ clk = clk_get(&pdev->dev, "clk_HevcEnc");
+ if (IS_ERR(clk)) {
+ enc_pr(LOG_ERROR, "cannot get clock\n");
+ clk = NULL;
+ err = -ENOENT;
+ goto ERROR_PROVE_DEVICE;
+ }
+ s_vpu_clk = clk;
+#endif
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+ if (vpu_clk_prepare(&pdev->dev, &s_vpu_clks)) {
+ err = -ENOENT;
+ //goto ERROR_PROVE_DEVICE;
+ return err;
+ }
+ }
+
+#ifndef VPU_SUPPORT_CLOCK_CONTROL
+ vpu_clk_config(1);
+#endif
+
+ np = pdev->dev.of_node;
+ reg_count = 0;
+ for_each_child_of_node(np, child) {
+ if (of_address_to_resource(child, 0, &res)
+ || (reg_count > 1)) {
+ enc_pr(LOG_ERROR,
+ "no reg ranges or more reg ranges %d\n",
+ reg_count);
+ err = -ENXIO;
+ goto ERROR_PROVE_DEVICE;
+ }
+ /* if platform driver is implemented */
+ if (res.start != 0) {
+ s_vpu_register.phys_addr = res.start;
+ s_vpu_register.virt_addr =
+ (ulong)ioremap_nocache(
+ res.start, resource_size(&res));
+ s_vpu_register.size = res.end - res.start;
+ enc_pr(LOG_DEBUG,
+ "vpu base address get from platform driver ");
+ enc_pr(LOG_DEBUG,
+ "physical base addr=0x%lx, virtual base=0x%lx\n",
+ s_vpu_register.phys_addr,
+ s_vpu_register.virt_addr);
+ } else {
+ s_vpu_register.phys_addr = VPU_REG_BASE_ADDR;
+ s_vpu_register.virt_addr =
+ (ulong)ioremap_nocache(
+ s_vpu_register.phys_addr, VPU_REG_SIZE);
+ s_vpu_register.size = VPU_REG_SIZE;
+ enc_pr(LOG_DEBUG,
+ "vpu base address get from defined value ");
+ enc_pr(LOG_DEBUG,
+ "physical base addr=0x%lx, virtual base=0x%lx\n",
+ s_vpu_register.phys_addr,
+ s_vpu_register.virt_addr);
+ }
+ reg_count++;
+ }
+
+ /* get the major number of the character device */
+ if (init_HevcEnc_device()) {
+ err = -EBUSY;
+ enc_pr(LOG_ERROR, "could not allocate major number\n");
+ goto ERROR_PROVE_DEVICE;
+ }
+ enc_pr(LOG_DEBUG, "SUCCESS alloc_chrdev_region\n");
+
+ init_waitqueue_head(&s_interrupt_wait_q);
+ tasklet_init(&hevc_tasklet,
+ hevcenc_isr_tasklet,
+ (ulong)&s_vpu_drv_context);
+ s_common_memory.base = 0;
+ s_instance_pool.base = 0;
+
+ if (use_reserve == true) {
+ if (vmem_init(&s_vmem, s_video_memory.phys_addr,
+ s_video_memory.size) < 0) {
+ enc_pr(LOG_ERROR, "fail to init vmem system\n");
+ goto ERROR_PROVE_DEVICE;
+ }
+ enc_pr(LOG_DEBUG,
+ "success to probe vpu device with video memory ");
+ enc_pr(LOG_DEBUG,
+ "phys_addr=0x%lx, base = 0x%lx\n",
+ (ulong)s_video_memory.phys_addr,
+ (ulong)s_video_memory.base);
+ } else
+ enc_pr(LOG_DEBUG,
+ "success to probe vpu device with video memory from cma\n");
+ hevc_pdev = pdev;
+ return 0;
+
+ERROR_PROVE_DEVICE:
+ if (s_vpu_register.virt_addr) {
+ iounmap((void *)s_vpu_register.virt_addr);
+ memset(&s_vpu_register, 0, sizeof(struct vpudrv_buffer_t));
+ }
+
+ if (s_video_memory.phys_addr) {
+ vmem_exit(&s_vmem);
+ memset(&s_video_memory, 0, sizeof(struct vpudrv_buffer_t));
+ memset(&s_vmem, 0, sizeof(struct video_mm_t));
+ }
+
+#ifndef VPU_SUPPORT_CLOCK_CONTROL
+ vpu_clk_config(0);
+#endif
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2)
+ vpu_clk_unprepare(&pdev->dev, &s_vpu_clks);
+
+ if (s_vpu_irq_requested == true) {
+ if (s_vpu_irq >= 0) {
+ free_irq(s_vpu_irq, &s_vpu_drv_context);
+ s_vpu_irq = -1;
+ }
+ s_vpu_irq_requested = false;
+ }
+ uninit_HevcEnc_device();
+ return err;
+}
+
+static s32 vpu_remove(struct platform_device *pdev)
+{
+ enc_pr(LOG_DEBUG, "vpu_remove\n");
+
+ if (s_instance_pool.base) {
+ vfree((const void *)s_instance_pool.base);
+ s_instance_pool.base = 0;
+ }
+
+ if (s_common_memory.phys_addr) {
+ vpu_free_dma_buffer(&s_common_memory);
+ s_common_memory.phys_addr = 0;
+ }
+
+ if (s_video_memory.phys_addr) {
+ if (!use_reserve) {
+ codec_mm_free_for_dma(
+ VPU_DEV_NAME,
+ (u32)s_video_memory.phys_addr);
+ }
+ vmem_exit(&s_vmem);
+ memset(&s_video_memory,
+ 0, sizeof(struct vpudrv_buffer_t));
+ memset(&s_vmem,
+ 0, sizeof(struct video_mm_t));
+ }
+
+ if (s_vpu_irq_requested == true) {
+ if (s_vpu_irq >= 0) {
+ free_irq(s_vpu_irq, &s_vpu_drv_context);
+ s_vpu_irq = -1;
+ }
+ s_vpu_irq_requested = false;
+ }
+
+ if (s_vpu_register.virt_addr) {
+ iounmap((void *)s_vpu_register.virt_addr);
+ memset(&s_vpu_register,
+ 0, sizeof(struct vpudrv_buffer_t));
+ }
+ hevc_pdev = NULL;
+#ifndef VPU_SUPPORT_CLOCK_CONTROL
+ vpu_clk_config(0);
+#endif
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2)
+ vpu_clk_unprepare(&pdev->dev, &s_vpu_clks);
+ uninit_HevcEnc_device();
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static void Wave4BitIssueCommand(u32 core, u32 cmd)
+{
+ WriteVpuRegister(W4_VPU_BUSY_STATUS, 1);
+ WriteVpuRegister(W4_CORE_INDEX, 0);
+ /* coreIdx = ReadVpuRegister(W4_VPU_BUSY_STATUS); */
+ /* coreIdx = 0; */
+ /* WriteVpuRegister(W4_INST_INDEX,
+ * (instanceIndex & 0xffff) | (codecMode << 16));
+ */
+ WriteVpuRegister(W4_COMMAND, cmd);
+ WriteVpuRegister(W4_VPU_HOST_INT_REQ, 1);
+}
+
+static s32 vpu_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ u32 core;
+ ulong timeout = jiffies + HZ; /* vpu wait timeout to 1sec */
+
+ enc_pr(LOG_DEBUG, "vpu_suspend\n");
+
+ vpu_clk_config(1);
+
+ if (s_vpu_open_ref_count > 0) {
+ for (core = 0; core < MAX_NUM_VPU_CORE; core++) {
+ if (s_bit_firmware_info[core].size == 0)
+ continue;
+ while (ReadVpuRegister(W4_VPU_BUSY_STATUS)) {
+ if (time_after(jiffies, timeout)) {
+ enc_pr(LOG_ERROR,
+ "SLEEP_VPU BUSY timeout");
+ goto DONE_SUSPEND;
+ }
+ }
+ Wave4BitIssueCommand(core, W4_CMD_SLEEP_VPU);
+
+ while (ReadVpuRegister(W4_VPU_BUSY_STATUS)) {
+ if (time_after(jiffies, timeout)) {
+ enc_pr(LOG_ERROR,
+ "SLEEP_VPU BUSY timeout");
+ goto DONE_SUSPEND;
+ }
+ }
+ if (ReadVpuRegister(W4_RET_SUCCESS) == 0) {
+ enc_pr(LOG_ERROR,
+ "SLEEP_VPU failed [0x%x]",
+ ReadVpuRegister(W4_RET_FAIL_REASON));
+ goto DONE_SUSPEND;
+ }
+ }
+ }
+
+ vpu_clk_config(0);
+ return 0;
+
+DONE_SUSPEND:
+ vpu_clk_config(0);
+ return -EAGAIN;
+}
+static s32 vpu_resume(struct platform_device *pdev)
+{
+ u32 i;
+ u32 core;
+ u32 val;
+ ulong timeout = jiffies + HZ; /* vpu wait timeout to 1sec */
+ ulong code_base;
+ u32 code_size;
+ u32 remap_size;
+ u32 regVal;
+ u32 hwOption = 0;
+
+ enc_pr(LOG_DEBUG, "vpu_resume\n");
+
+ vpu_clk_config(1);
+ if (s_vpu_open_ref_count > 0) {
+ for (core = 0; core < MAX_NUM_VPU_CORE; core++) {
+ if (s_bit_firmware_info[core].size == 0)
+ continue;
+ code_base = s_common_memory.phys_addr;
+ /* ALIGN TO 4KB */
+ code_size = (s_common_memory.size & ~0xfff);
+ if (code_size < s_bit_firmware_info[core].size * 2)
+ goto DONE_WAKEUP;
+
+ /*---- LOAD BOOT CODE */
+ for (i = 0; i < 512; i += 2) {
+ val = s_bit_firmware_info[core].bit_code[i];
+ val |= (s_bit_firmware_info[core].bit_code[i+1] << 16);
+ WriteVpu(code_base+(i*2), val);
+ }
+
+ regVal = 0;
+ WriteVpuRegister(W4_PO_CONF, regVal);
+
+ /* Reset All blocks */
+ regVal = 0x7ffffff;
+ WriteVpuRegister(W4_VPU_RESET_REQ, regVal);
+
+ /* Waiting reset done */
+ while (ReadVpuRegister(W4_VPU_RESET_STATUS)) {
+ if (time_after(jiffies, timeout))
+ goto DONE_WAKEUP;
+ }
+
+ WriteVpuRegister(W4_VPU_RESET_REQ, 0);
+
+ /* remap page size */
+ remap_size = (code_size >> 12) & 0x1ff;
+ regVal = 0x80000000 | (W4_REMAP_CODE_INDEX<<12)
+ | (0 << 16) | (1<<11) | remap_size;
+ WriteVpuRegister(W4_VPU_REMAP_CTRL, regVal);
+ /* DO NOT CHANGE! */
+ WriteVpuRegister(W4_VPU_REMAP_VADDR, 0x00000000);
+ WriteVpuRegister(W4_VPU_REMAP_PADDR, code_base);
+ WriteVpuRegister(W4_ADDR_CODE_BASE, code_base);
+ WriteVpuRegister(W4_CODE_SIZE, code_size);
+ WriteVpuRegister(W4_CODE_PARAM, 0);
+ WriteVpuRegister(W4_INIT_VPU_TIME_OUT_CNT, timeout);
+ WriteVpuRegister(W4_HW_OPTION, hwOption);
+
+ /* Interrupt */
+ regVal = (1 << W4_INT_DEC_PIC_HDR);
+ regVal |= (1 << W4_INT_DEC_PIC);
+ regVal |= (1 << W4_INT_QUERY_DEC);
+ regVal |= (1 << W4_INT_SLEEP_VPU);
+ regVal |= (1 << W4_INT_BSBUF_EMPTY);
+ regVal = 0xfffffefe;
+ WriteVpuRegister(W4_VPU_VINT_ENABLE, regVal);
+ Wave4BitIssueCommand(core, W4_CMD_INIT_VPU);
+ WriteVpuRegister(W4_VPU_REMAP_CORE_START, 1);
+ while (ReadVpuRegister(W4_VPU_BUSY_STATUS)) {
+ if (time_after(jiffies, timeout))
+ goto DONE_WAKEUP;
+ }
+
+ if (ReadVpuRegister(W4_RET_SUCCESS) == 0) {
+ enc_pr(LOG_ERROR,
+ "WAKEUP_VPU failed [0x%x]",
+ ReadVpuRegister(W4_RET_FAIL_REASON));
+ goto DONE_WAKEUP;
+ }
+ }
+ }
+
+ if (s_vpu_open_ref_count == 0)
+ vpu_clk_config(0);
+DONE_WAKEUP:
+ if (s_vpu_open_ref_count > 0)
+ vpu_clk_config(1);
+ return 0;
+}
+#else
+#define vpu_suspend NULL
+#define vpu_resume NULL
+#endif /* !CONFIG_PM */
+
+static const struct of_device_id cnm_hevcenc_dt_match[] = {
+ {
+ .compatible = "cnm, HevcEnc",
+ },
+ {},
+};
+
+static struct platform_driver vpu_driver = {
+ .driver = {
+ .name = VPU_PLATFORM_DEVICE_NAME,
+ .of_match_table = cnm_hevcenc_dt_match,
+ },
+ .probe = vpu_probe,
+ .remove = vpu_remove,
+ .suspend = vpu_suspend,
+ .resume = vpu_resume,
+};
+
+static s32 __init vpu_init(void)
+{
+ s32 res;
+
+ enc_pr(LOG_DEBUG, "vpu_init\n");
+
+ if ((get_cpu_type() != MESON_CPU_MAJOR_ID_GXM)
+ && (get_cpu_type() != MESON_CPU_MAJOR_ID_G12A)
+ && (get_cpu_type() != MESON_CPU_MAJOR_ID_GXLX)
+ && (get_cpu_type() != MESON_CPU_MAJOR_ID_G12B)
+ && (get_cpu_type() != MESON_CPU_MAJOR_ID_SM1)
+ && (get_cpu_type() != MESON_CPU_MAJOR_ID_SC2)) {
+ enc_pr(LOG_DEBUG,
+ "The chip is not support hevc encoder\n");
+ return -1;
+ }
+ if (get_cpu_type() == MESON_CPU_MAJOR_ID_G12A) {
+ if ((READ_EFUSE_REG(EFUSE_LIC2) >> 12) & 1) {
+ enc_pr(LOG_DEBUG,
+ "Chip efuse disabled H265\n");
+ return -1;
+ }
+ }
+
+ res = platform_driver_register(&vpu_driver);
+ enc_pr(LOG_INFO,
+ "end vpu_init result=0x%x\n", res);
+ return res;
+}
+
+static void __exit vpu_exit(void)
+{
+ enc_pr(LOG_DEBUG, "vpu_exit\n");
+ if ((get_cpu_type() != MESON_CPU_MAJOR_ID_GXM) &&
+ (get_cpu_type() != MESON_CPU_MAJOR_ID_G12A) &&
+ (get_cpu_type() != MESON_CPU_MAJOR_ID_GXLX) &&
+ (get_cpu_type() != MESON_CPU_MAJOR_ID_G12B) &&
+ (get_cpu_type() != MESON_CPU_MAJOR_ID_SC2) &&
+ (get_cpu_type() != MESON_CPU_MAJOR_ID_SM1)) {
+ enc_pr(LOG_INFO,
+ "The chip is not support hevc encoder\n");
+ return;
+ }
+ platform_driver_unregister(&vpu_driver);
+}
+
+static const struct reserved_mem_ops rmem_hevc_ops = {
+ .device_init = hevc_mem_device_init,
+};
+
+static s32 __init hevc_mem_setup(struct reserved_mem *rmem)
+{
+ rmem->ops = &rmem_hevc_ops;
+ enc_pr(LOG_DEBUG, "HevcEnc reserved mem setup.\n");
+ return 0;
+}
+
+module_param(print_level, uint, 0664);
+MODULE_PARM_DESC(print_level, "\n print_level\n");
+
+module_param(clock_level, uint, 0664);
+MODULE_PARM_DESC(clock_level, "\n clock_level\n");
+
+module_param(wave_clocka, uint, 0664);
+MODULE_PARM_DESC(wave_clocka, "\n wave_clocka\n");
+
+module_param(wave_clockb, uint, 0664);
+MODULE_PARM_DESC(wave_clockb, "\n wave_clockb\n");
+
+module_param(wave_clockc, uint, 0664);
+MODULE_PARM_DESC(wave_clockc, "\n wave_clockc\n");
+
+MODULE_AUTHOR("Amlogic using C&M VPU, Inc.");
+MODULE_DESCRIPTION("VPU linux driver");
+MODULE_LICENSE("GPL");
+
+module_init(vpu_init);
+module_exit(vpu_exit);
+RESERVEDMEM_OF_DECLARE(amlogic, "amlogic, HevcEnc-memory", hevc_mem_setup);
diff --git a/drivers/frame_sink/encoder/h265/vpu.h b/drivers/frame_sink/encoder/h265/vpu.h
new file mode 100644
index 0000000..b89744f
--- /dev/null
+++ b/drivers/frame_sink/encoder/h265/vpu.h
@@ -0,0 +1,355 @@
+/*
+ * vpu.h
+ *
+ * linux device driver for VPU.
+ *
+ * Copyright (C) 2006 - 2013 CHIPS&MEDIA INC.
+ *
+ * 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 __VPU_DRV_H__
+#define __VPU_DRV_H__
+
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/compat.h>
+#include <linux/dma-buf.h>
+
+#define MAX_INST_HANDLE_SIZE (32*1024)
+#define MAX_NUM_INSTANCE 4
+#define MAX_NUM_VPU_CORE 1
+
+#define W4_CMD_INIT_VPU (0x0001)
+#define W4_CMD_SLEEP_VPU (0x0400)
+#define W4_CMD_WAKEUP_VPU (0x0800)
+
+/* GXM: 2000/10 = 200M */
+#define HevcEnc_L0() WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL, \
+ (3 << 25) | (1 << 16) | (3 << 9) | (1 << 0))
+/* GXM: 2000/8 = 250M */
+#define HevcEnc_L1() WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL, \
+ (1 << 25) | (1 << 16) | (1 << 9) | (1 << 0))
+/* GXM: 2000/7 = 285M */
+#define HevcEnc_L2() WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL, \
+ (4 << 25) | (0 << 16) | (4 << 9) | (0 << 0))
+/*GXM: 2000/6 = 333M */
+#define HevcEnc_L3() WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL, \
+ (2 << 25) | (1 << 16) | (2 << 9) | (1 << 0))
+/* GXM: 2000/5 = 400M */
+#define HevcEnc_L4() WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL, \
+ (3 << 25) | (0 << 16) | (3 << 9) | (0 << 0))
+/* GXM: 2000/4 = 500M */
+#define HevcEnc_L5() WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL, \
+ (1 << 25) | (0 << 16) | (1 << 9) | (0 << 0))
+/* GXM: 2000/3 = 667M */
+#define HevcEnc_L6() WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL, \
+ (2 << 25) | (0 << 16) | (2 << 9) | (0 << 0))
+
+#define HevcEnc_clock_enable(level) \
+ do { \
+ WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL, \
+ READ_HHI_REG(HHI_WAVE420L_CLK_CNTL) \
+ & (~(1 << 8)) & (~(1 << 24))); \
+ if (level == 0) \
+ HevcEnc_L0(); \
+ else if (level == 1) \
+ HevcEnc_L1(); \
+ else if (level == 2) \
+ HevcEnc_L2(); \
+ else if (level == 3) \
+ HevcEnc_L3(); \
+ else if (level == 4) \
+ HevcEnc_L4(); \
+ else if (level == 5) \
+ HevcEnc_L5(); \
+ else if (level == 6) \
+ HevcEnc_L6(); \
+ WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL, \
+ READ_HHI_REG(HHI_WAVE420L_CLK_CNTL) \
+ | (1 << 8) | (1 << 24)); \
+ } while (0)
+
+#define HevcEnc_clock_disable() \
+ WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL, \
+ READ_HHI_REG(HHI_WAVE420L_CLK_CNTL) \
+ & (~(1 << 8)) & (~(1 << 24)))
+
+/* ACLK 667MHZ */
+#define HevcEnc_MoreClock_enable() \
+ do { \
+ WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL2, \
+ READ_HHI_REG(HHI_WAVE420L_CLK_CNTL2) \
+ & (~(1 << 8))); \
+ WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL2, \
+ (2 << 9) | (0 << 0)); \
+ WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL2, \
+ READ_HHI_REG(HHI_WAVE420L_CLK_CNTL2) \
+ | (1 << 8)); \
+ } while (0)
+
+#define HevcEnc_MoreClock_disable() \
+ WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL2, \
+ READ_HHI_REG(HHI_WAVE420L_CLK_CNTL2) \
+ & (~(1 << 8)))
+
+typedef enum
+{
+ AMVENC_YUV422_SINGLE = 0,
+ AMVENC_YUV444_SINGLE,
+ AMVENC_NV21,
+ AMVENC_NV12,
+ AMVENC_YUV420,
+ AMVENC_YUV444_PLANE,
+ AMVENC_RGB888,
+ AMVENC_RGB888_PLANE,
+ AMVENC_RGB565,
+ AMVENC_RGBA8888,
+ AMVENC_FRAME_FMT
+} AMVEncFrameFmt;
+
+#ifdef CONFIG_COMPAT
+struct compat_vpudrv_buffer_t {
+ u32 size;
+ u32 cached;
+ compat_ulong_t phys_addr;
+ compat_ulong_t base; /* kernel logical address in use kernel */
+ compat_ulong_t virt_addr; /* virtual user space address */
+};
+#endif
+
+struct vpudrv_buffer_t {
+ u32 size;
+ u32 cached;
+ ulong phys_addr;
+ ulong base; /* kernel logical address in use kernel */
+ ulong virt_addr; /* virtual user space address */
+};
+
+struct vpu_bit_firmware_info_t {
+ u32 size; /* size of this structure*/
+ u32 core_idx;
+ u32 reg_base_offset;
+ u16 bit_code[512];
+};
+
+struct vpudrv_inst_info_t {
+ u32 core_idx;
+ u32 inst_idx;
+ s32 inst_open_count; /* for output only*/
+};
+
+struct vpudrv_intr_info_t {
+ u32 timeout;
+ s32 intr_reason;
+};
+
+struct vpu_drv_context_t {
+ struct fasync_struct *async_queue;
+ ulong interrupt_reason;
+ u32 open_count; /*!<< device reference count. Not instance count */
+};
+
+/* To track the allocated memory buffer */
+struct vpudrv_buffer_pool_t {
+ struct list_head list;
+ struct vpudrv_buffer_t vb;
+ struct file *filp;
+};
+
+/* To track the instance index and buffer in instance pool */
+struct vpudrv_instanace_list_t {
+ struct list_head list;
+ ulong inst_idx;
+ ulong core_idx;
+ struct file *filp;
+};
+
+struct vpudrv_instance_pool_t {
+ u8 codecInstPool[MAX_NUM_INSTANCE][MAX_INST_HANDLE_SIZE];
+};
+
+struct vpu_dma_buf_info_t {
+ u32 width;
+ u32 height;
+ AMVEncFrameFmt fmt;
+ u32 num_planes;
+ s32 fd[3];
+};
+
+struct vpu_dma_cfg {
+ int fd;
+ void *dev;
+ void *vaddr;
+ void *paddr;
+ struct dma_buf *dbuf;
+ struct dma_buf_attachment *attach;
+ struct sg_table *sg;
+ enum dma_data_direction dir;
+};
+
+#define VPUDRV_BUF_LEN struct vpudrv_buffer_t
+#define VPUDRV_BUF_LEN32 struct compat_vpudrv_buffer_t
+#define VPUDRV_INST_LEN struct vpudrv_inst_info_t
+
+#define VDI_MAGIC 'V'
+#define VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY \
+ _IOW(VDI_MAGIC, 0, VPUDRV_BUF_LEN)
+
+#define VDI_IOCTL_FREE_PHYSICALMEMORY \
+ _IOW(VDI_MAGIC, 1, VPUDRV_BUF_LEN)
+
+#define VDI_IOCTL_WAIT_INTERRUPT \
+ _IOW(VDI_MAGIC, 2, struct vpudrv_intr_info_t)
+
+#define VDI_IOCTL_SET_CLOCK_GATE \
+ _IOW(VDI_MAGIC, 3, u32)
+
+#define VDI_IOCTL_RESET \
+ _IOW(VDI_MAGIC, 4, u32)
+
+#define VDI_IOCTL_GET_INSTANCE_POOL \
+ _IOW(VDI_MAGIC, 5, VPUDRV_BUF_LEN)
+
+#define VDI_IOCTL_GET_COMMON_MEMORY \
+ _IOW(VDI_MAGIC, 6, VPUDRV_BUF_LEN)
+
+#define VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO \
+ _IOW(VDI_MAGIC, 8, VPUDRV_BUF_LEN)
+
+#define VDI_IOCTL_OPEN_INSTANCE \
+ _IOW(VDI_MAGIC, 9, VPUDRV_INST_LEN)
+
+#define VDI_IOCTL_CLOSE_INSTANCE \
+ _IOW(VDI_MAGIC, 10, VPUDRV_INST_LEN)
+
+#define VDI_IOCTL_GET_INSTANCE_NUM \
+ _IOW(VDI_MAGIC, 11, VPUDRV_INST_LEN)
+
+#define VDI_IOCTL_GET_REGISTER_INFO \
+ _IOW(VDI_MAGIC, 12, VPUDRV_BUF_LEN)
+
+#define VDI_IOCTL_FLUSH_BUFFER \
+ _IOW(VDI_MAGIC, 13, VPUDRV_BUF_LEN)
+
+#define VDI_IOCTL_CONFIG_DMA \
+ _IOW(VDI_MAGIC, 14, struct vpu_dma_buf_info_t)
+
+#define VDI_IOCTL_UNMAP_DMA \
+ _IOW(VDI_MAGIC, 15, u32)
+
+#ifdef CONFIG_COMPAT
+#define VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY32 \
+ _IOW(VDI_MAGIC, 0, VPUDRV_BUF_LEN32)
+
+#define VDI_IOCTL_FREE_PHYSICALMEMORY32 \
+ _IOW(VDI_MAGIC, 1, VPUDRV_BUF_LEN32)
+
+#define VDI_IOCTL_GET_INSTANCE_POOL32 \
+ _IOW(VDI_MAGIC, 5, VPUDRV_BUF_LEN32)
+
+#define VDI_IOCTL_GET_COMMON_MEMORY32 \
+ _IOW(VDI_MAGIC, 6, VPUDRV_BUF_LEN32)
+
+#define VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO32 \
+ _IOW(VDI_MAGIC, 8, VPUDRV_BUF_LEN32)
+
+#define VDI_IOCTL_GET_REGISTER_INFO32 \
+ _IOW(VDI_MAGIC, 12, VPUDRV_BUF_LEN32)
+
+#define VDI_IOCTL_FLUSH_BUFFER32 \
+ _IOW(VDI_MAGIC, 13, VPUDRV_BUF_LEN32)
+#endif
+
+enum {
+ W4_INT_INIT_VPU = 0,
+ W4_INT_DEC_PIC_HDR = 1,
+ W4_INT_SET_PARAM = 1,
+ W4_INT_ENC_INIT_SEQ = 1,
+ W4_INT_FINI_SEQ = 2,
+ W4_INT_DEC_PIC = 3,
+ W4_INT_ENC_PIC = 3,
+ W4_INT_SET_FRAMEBUF = 4,
+ W4_INT_FLUSH_DEC = 5,
+ W4_INT_ENC_SLICE_INT = 7,
+ W4_INT_GET_FW_VERSION = 8,
+ W4_INT_QUERY_DEC = 9,
+ W4_INT_SLEEP_VPU = 10,
+ W4_INT_WAKEUP_VPU = 11,
+ W4_INT_CHANGE_INT = 12,
+ W4_INT_CREATE_INSTANCE = 14,
+ W4_INT_BSBUF_EMPTY = 15,
+ /*!<< Bitstream buffer empty[dec]/full[enc] */
+};
+
+/* WAVE4 registers */
+#define VPU_REG_BASE_ADDR 0xc8810000
+#define VPU_REG_SIZE (0x4000 * MAX_NUM_VPU_CORE)
+
+#define W4_REG_BASE 0x0000
+#define W4_VPU_BUSY_STATUS (W4_REG_BASE + 0x0070)
+#define W4_VPU_INT_REASON_CLEAR (W4_REG_BASE + 0x0034)
+#define W4_VPU_VINT_CLEAR (W4_REG_BASE + 0x003C)
+#define W4_VPU_VPU_INT_STS (W4_REG_BASE + 0x0044)
+#define W4_VPU_INT_REASON (W4_REG_BASE + 0x004c)
+
+#define W4_RET_SUCCESS (W4_REG_BASE + 0x0110)
+#define W4_RET_FAIL_REASON (W4_REG_BASE + 0x0114)
+
+/* WAVE4 INIT, WAKEUP */
+#define W4_PO_CONF (W4_REG_BASE + 0x0000)
+#define W4_VCPU_CUR_PC (W4_REG_BASE + 0x0004)
+
+#define W4_VPU_VINT_ENABLE (W4_REG_BASE + 0x0048)
+
+#define W4_VPU_RESET_REQ (W4_REG_BASE + 0x0050)
+#define W4_VPU_RESET_STATUS (W4_REG_BASE + 0x0054)
+
+#define W4_VPU_REMAP_CTRL (W4_REG_BASE + 0x0060)
+#define W4_VPU_REMAP_VADDR (W4_REG_BASE + 0x0064)
+#define W4_VPU_REMAP_PADDR (W4_REG_BASE + 0x0068)
+#define W4_VPU_REMAP_CORE_START (W4_REG_BASE + 0x006C)
+#define W4_VPU_BUSY_STATUS (W4_REG_BASE + 0x0070)
+
+#define W4_HW_OPTION (W4_REG_BASE + 0x0124)
+#define W4_CODE_SIZE (W4_REG_BASE + 0x011C)
+/* Note: W4_INIT_CODE_BASE_ADDR should be aligned to 4KB */
+#define W4_ADDR_CODE_BASE (W4_REG_BASE + 0x0118)
+#define W4_CODE_PARAM (W4_REG_BASE + 0x0120)
+#define W4_INIT_VPU_TIME_OUT_CNT (W4_REG_BASE + 0x0134)
+
+/* WAVE4 Wave4BitIssueCommand */
+#define W4_CORE_INDEX (W4_REG_BASE + 0x0104)
+#define W4_INST_INDEX (W4_REG_BASE + 0x0108)
+#define W4_COMMAND (W4_REG_BASE + 0x0100)
+#define W4_VPU_HOST_INT_REQ (W4_REG_BASE + 0x0038)
+
+#define W4_BS_RD_PTR (W4_REG_BASE + 0x0130)
+#define W4_BS_WR_PTR (W4_REG_BASE + 0x0134)
+#define W4_SRC_ADDR_Y (W4_REG_BASE + 0x0174)
+#define W4_SRC_ADDR_U (W4_REG_BASE + 0x0178)
+#define W4_SRC_ADDR_V (W4_REG_BASE + 0x017C)
+
+#define W4_RET_ENC_PIC_BYTE (W4_REG_BASE + 0x01C8)
+
+#define W4_REMAP_CODE_INDEX 0
+
+#define ReadVpuRegister(addr) \
+ readl((void __iomem *)(s_vpu_register.virt_addr \
+ + s_bit_firmware_info[core].reg_base_offset + addr))
+
+#define WriteVpuRegister(addr, val) \
+ writel((u32)val, (void __iomem *)(s_vpu_register.virt_addr \
+ + s_bit_firmware_info[core].reg_base_offset + addr))
+
+#define WriteVpu(addr, val) writel((u32)val, (void __iomem *)addr)
+#endif
diff --git a/drivers/frame_sink/encoder/jpeg/Makefile b/drivers/frame_sink/encoder/jpeg/Makefile
new file mode 100644
index 0000000..5d06732
--- /dev/null
+++ b/drivers/frame_sink/encoder/jpeg/Makefile
@@ -0,0 +1,6 @@
+#obj-$(CONFIG_AMLOGIC_MEDIA_VENC_JPEG) += amvenc_jpeg.o
+#obj-m += amvenc_jpeg.o
+#amvenc_jpeg-objs += jpegenc.o
+#obj-m += jpegenc.o
+
+obj-$(CONFIG_AMLOGIC_MEDIA_VENC_JPEG) += jpegenc.o
\ No newline at end of file
diff --git a/drivers/frame_sink/encoder/jpeg/jpegenc.c b/drivers/frame_sink/encoder/jpeg/jpegenc.c
new file mode 100644
index 0000000..8878fc9
--- /dev/null
+++ b/drivers/frame_sink/encoder/jpeg/jpegenc.c
@@ -0,0 +1,3737 @@
+/*
+ * drivers/amlogic/amports/jpegenc.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 LOG_LINE() pr_err("[%s:%d]\n", __FUNCTION__, __LINE__);
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/ctype.h>
+#include <linux/amlogic/media/frame_sync/ptsserv.h>
+#include <linux/amlogic/media/utils/amstream.h>
+#include <linux/amlogic/media/canvas/canvas.h>
+#include <linux/amlogic/media/canvas/canvas_mgr.h>
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "../../../frame_provider/decoder/utils/vdec.h"
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/dma-contiguous.h>
+#include <linux/amlogic/media/utils/amports_config.h>
+#include "../../../frame_provider/decoder/utils/firmware.h"
+#include "../../../frame_provider/decoder/utils/amvdec.h"
+#include "jpegenc.h"
+
+#include "../../../frame_provider/decoder/utils/vdec_power_ctrl.h"
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include <linux/amlogic/power_ctrl.h>
+#include <dt-bindings/power/sc2-pd.h>
+#include <linux/amlogic/pwr_ctrl.h>
+
+#include <linux/amlogic/media/utils/amlog.h>
+//#include "amports_priv.h"
+#include <linux/of_reserved_mem.h>
+
+#ifdef CONFIG_AM_ENCODER
+#include "encoder.h"
+#endif
+
+#define JPEGENC_CANVAS_INDEX 0xE4
+#define JPEGENC_CANVAS_MAX_INDEX 0xE7
+
+#define ENC_CANVAS_OFFSET JPEGENC_CANVAS_INDEX
+
+#define LOG_ALL 0
+#define LOG_INFO 1
+#define LOG_DEBUG 2
+#define LOG_ERROR 3
+
+#define jenc_pr(level, x...) \
+ do { \
+ if (level >= jpegenc_print_level) \
+ printk(x); \
+ } while (0)
+
+#define DRIVER_NAME "jpegenc"
+#define CLASS_NAME "jpegenc"
+#define DEVICE_NAME "jpegenc"
+
+#define MIN_SIZE jpegenc_buffspec[0].min_buffsize
+/* #define EXTEAN_QUANT_TABLE */
+
+static s32 jpegenc_device_major;
+static struct device *jpegenc_dev;
+static u32 jpegenc_print_level = 0;
+
+static u32 clock_level = 1;
+static u16 gQuantTable[2][DCTSIZE2];
+#ifdef EXTEAN_QUANT_TABLE
+static u16 *gExternalQuantTablePtr;
+static bool external_quant_table_available;
+#endif
+
+static DEFINE_SPINLOCK(lock);
+
+#define JPEGENC_BUFFER_LEVEL_VGA 0
+#define JPEGENC_BUFFER_LEVEL_2M 1
+#define JPEGENC_BUFFER_LEVEL_3M 2
+#define JPEGENC_BUFFER_LEVEL_5M 3
+#define JPEGENC_BUFFER_LEVEL_8M 4
+#define JPEGENC_BUFFER_LEVEL_13M 5
+#define JPEGENC_BUFFER_LEVEL_HD 6
+
+
+#define MHz (1000000)
+
+#define CHECK_RET(_ret) if (ret) {pr_err(\
+ "%s:%d:function call failed with result: %d\n",\
+ __FUNCTION__, __LINE__, _ret);}
+
+
+struct jpegenc_clks {
+ struct clk *jpegenc_aclk;
+ //struct clk *hcodec_bclk;
+ //struct clk *hcodec_cclk;
+};
+
+static struct jpegenc_clks s_jpegenc_clks;
+struct reset_control *jpegenc_rst;
+
+/*
+s32 jpegenc_hw_reset(void)
+{
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+ reset_control_reset(jpegenc_rst);
+ pr_err("request jpegenc reset from application.\n");
+ }
+ return 0;
+}
+*/
+
+s32 jpegenc_clk_prepare(struct device *dev, struct jpegenc_clks *clks)
+{
+ int ret;
+
+ clks->jpegenc_aclk = devm_clk_get(dev, "cts_jpegenc_aclk");
+
+ if (IS_ERR_OR_NULL(clks->jpegenc_aclk)) {
+ pr_err("failed to get jpegenc aclk: %px, %ld, dev=%px\n",
+ clks->jpegenc_aclk,
+ PTR_ERR(clks->jpegenc_aclk),
+ dev);
+ return -1;
+ }
+
+ ret = clk_set_rate(clks->jpegenc_aclk, 667 * MHz);
+ CHECK_RET(ret);
+
+ ret = clk_prepare(clks->jpegenc_aclk);
+ CHECK_RET(ret);
+
+ pr_err("jpegenc_clk_a: %lu MHz\n", clk_get_rate(clks->jpegenc_aclk) / 1000000);
+
+ return 0;
+}
+
+void jpegenc_clk_unprepare(struct device *dev, struct jpegenc_clks *clks)
+{
+ clk_unprepare(clks->jpegenc_aclk);
+ devm_clk_put(dev, clks->jpegenc_aclk);
+
+ //clk_unprepare(clks->wave_bclk);
+ //devm_clk_put(dev, clks->wave_bclk);
+
+ //clk_unprepare(clks->wave_aclk);
+ //devm_clk_put(dev, clks->wave_aclk);
+}
+
+static s32 jpegenc_clk_config(u32 enable)
+{
+ if (enable) {
+ clk_enable(s_jpegenc_clks.jpegenc_aclk);
+ //clk_enable(s_hcodec_clks.wave_bclk);
+ //clk_enable(s_hcodec_clks.wave_cclk);
+ } else {
+ clk_disable(s_jpegenc_clks.jpegenc_aclk);
+ //clk_disable(s_hcodec_clks.wave_bclk);
+ //clk_disable(s_hcodec_clks.wave_aclk);
+ }
+
+ return 0;
+}
+
+const s8 *glevel_str[] = {
+ "VGA",
+ "2M",
+ "3M",
+ "5M",
+ "8M",
+ "13M",
+ "HD",
+};
+
+const struct Jpegenc_BuffInfo_s jpegenc_buffspec[] = {
+ {
+ .lev_id = JPEGENC_BUFFER_LEVEL_VGA,
+ .max_width = 640,
+ .max_height = 640,
+ .min_buffsize = 0x330000,
+ .input = {
+ .buf_start = 0,
+ .buf_size = 0x12c000,
+ },
+ .assit = {
+ .buf_start = 0x12d000,
+ .buf_size = 0x2000,
+ },
+ .bitstream = {
+ .buf_start = 0x130000,
+ .buf_size = 0x200000,
+ }
+ }, {
+ .lev_id = JPEGENC_BUFFER_LEVEL_2M,
+ .max_width = 1600,
+ .max_height = 1600,
+ .min_buffsize = 0x960000,
+ .input = {
+ .buf_start = 0,
+ .buf_size = 0x753000,
+ },
+ .assit = {
+ .buf_start = 0x754000,
+ .buf_size = 0x2000,
+ },
+ .bitstream = {
+ .buf_start = 0x760000,
+ .buf_size = 0x200000,
+ }
+ }, {
+ .lev_id = JPEGENC_BUFFER_LEVEL_3M,
+ .max_width = 2048,
+ .max_height = 2048,
+ .min_buffsize = 0xe10000,
+ .input = {
+ .buf_start = 0,
+ .buf_size = 0xc00000,
+ },
+ .assit = {
+ .buf_start = 0xc01000,
+ .buf_size = 0x2000,
+ },
+ .bitstream = {
+ .buf_start = 0xc10000,
+ .buf_size = 0x200000,
+ }
+ }, {
+ .lev_id = JPEGENC_BUFFER_LEVEL_5M,
+ .max_width = 2624,
+ .max_height = 2624,
+ .min_buffsize = 0x1800000,
+ .input = {
+ .buf_start = 0,
+ .buf_size = 0x13B3000,
+ },
+ .assit = {
+ .buf_start = 0x13B4000,
+ .buf_size = 0x2000,
+ },
+ .bitstream = {
+ .buf_start = 0x1400000,
+ .buf_size = 0x400000,
+ }
+ }, {
+ .lev_id = JPEGENC_BUFFER_LEVEL_8M,
+ .max_width = 3264,
+ .max_height = 3264,
+ .min_buffsize = 0x2300000,
+ .input = {
+ .buf_start = 0,
+ .buf_size = 0x1e7b000,
+ },
+ .assit = {
+ .buf_start = 0x1e7c000,
+ .buf_size = 0x2000,
+ },
+ .bitstream = {
+ .buf_start = 0x1f00000,
+ .buf_size = 0x400000,
+ }
+ }, {
+ .lev_id = JPEGENC_BUFFER_LEVEL_13M,
+ .max_width = 8192,
+ .max_height = 8192,
+ .min_buffsize = 0xc400000,
+ .input = {
+ .buf_start = 0,
+ .buf_size = 0xc000000,
+ },
+ .assit = {
+ .buf_start = 0xc001000,
+ .buf_size = 0x2000,
+ },
+ .bitstream = {
+ .buf_start = 0xc010000,
+ .buf_size = 0x3f0000,
+ }
+ }, {
+ .lev_id = JPEGENC_BUFFER_LEVEL_HD,
+ .max_width = 8192,
+ .max_height = 8192,
+ .min_buffsize = 0xc400000,
+ .input = {
+ .buf_start = 0,
+ .buf_size = 0xc000000,
+ },
+ .assit = {
+ .buf_start = 0xc001000,
+ .buf_size = 0x2000,
+ },
+ .bitstream = {
+ .buf_start = 0xc010000,
+ .buf_size = 0x3f0000,
+ }
+ }
+};
+
+const char *jpegenc_ucode[] = {
+ "gxl_jpeg_enc",//"jpegenc_mc",
+};
+
+static struct jpegenc_manager_s gJpegenc;
+
+static const u16 jpeg_quant[7][DCTSIZE2] = {
+ { /* jpeg_quant[0][] : Luma, Canon */
+ 0x06, 0x06, 0x08, 0x0A, 0x0A, 0x10, 0x15, 0x19,
+ 0x06, 0x0A, 0x0A, 0x0E, 0x12, 0x1F, 0x29, 0x29,
+ 0x08, 0x0A, 0x0E, 0x12, 0x21, 0x29, 0x29, 0x29,
+ 0x0A, 0x0E, 0x12, 0x14, 0x23, 0x29, 0x29, 0x29,
+ 0x0A, 0x12, 0x21, 0x23, 0x27, 0x29, 0x29, 0x29,
+ 0x10, 0x1F, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+ 0x15, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+ 0x19, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29
+ },
+ { /* jpeg_quant[1][] : Chroma, Canon */
+ 0x0A, 0x0E, 0x10, 0x14, 0x15, 0x1D, 0x2B, 0x35,
+ 0x0E, 0x12, 0x14, 0x1D, 0x25, 0x3E, 0x54, 0x54,
+ 0x10, 0x14, 0x19, 0x25, 0x40, 0x54, 0x54, 0x54,
+ 0x14, 0x1D, 0x25, 0x27, 0x48, 0x54, 0x54, 0x54,
+ 0x15, 0x25, 0x40, 0x48, 0x4E, 0x54, 0x54, 0x54,
+ 0x1D, 0x3E, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
+ 0x2B, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
+ 0x35, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54
+ },
+ { /* jpeg_quant[2][] : Luma, spec example Table K.1 */
+ 16, 11, 10, 16, 24, 40, 51, 61,
+ 12, 12, 14, 19, 26, 58, 60, 55,
+ 14, 13, 16, 24, 40, 57, 69, 56,
+ 14, 17, 22, 29, 51, 87, 80, 62,
+ 18, 22, 37, 56, 68, 109, 103, 77,
+ 24, 35, 55, 64, 81, 104, 113, 92,
+ 49, 64, 78, 87, 103, 121, 120, 101,
+ 72, 92, 95, 98, 112, 100, 103, 99
+ },
+ { /* jpeg_quant[3][] : Chroma, spec example Table K.2 */
+ 17, 18, 24, 47, 99, 99, 99, 99,
+ 18, 21, 26, 66, 99, 99, 99, 99,
+ 24, 26, 56, 99, 99, 99, 99, 99,
+ 47, 66, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+ },
+ { /* jpeg_quant[4][] : Luma, spec example Table K.1,
+ modified to create long ZRL */
+ 16, 11, 10, 16, 24, 40, 51, 61,
+ 12, 12, 14, 19, 26, 58, 60, 55,
+ 14, 13, 16, 24, 40, 57, 69, 56,
+ 14, 17, 22, 29, 51, 87, 80, 62,
+ 18, 22, 37, 56, 68, 109, 103, 77,
+ 24, 35, 55, 64, 81, 104, 113, 92,
+ 49, 64, 78, 87, 103, 121, 120, 101,
+ 72, 92, 95, 98, 112, 100, 103, 16
+ },
+ { /* jpeg_quant[5][] : Chroma, spec example Table K.2,
+ modified to create long ZRL */
+ 17, 18, 24, 47, 99, 99, 99, 99,
+ 18, 21, 26, 66, 99, 99, 99, 99,
+ 24, 26, 56, 99, 99, 99, 99, 99,
+ 47, 66, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 17
+ },
+ { /* jpeg_quant[6][] : no compression */
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1
+ }
+}; /* jpeg_quant */
+
+static const u8 jpeg_huffman_dc[2][16 + 12] = {
+ { /* jpeg_huffman_dc[0][] */
+ 0x00, /* number of code length=1 */
+ 0x01,
+ 0x05,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00, /* number of code length=16 */
+
+ /* Entry index for code with
+ minimum code length (=2 in this case) */
+ 0x00,
+ 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06,
+ 0x07,
+ 0x08,
+ 0x09,
+ 0x0A,
+ 0x0B
+ },
+ { /* jpeg_huffman_dc[1][] */
+ 0x00, /* number of code length=1 */
+ 0x03,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00, /* number of code length=16 */
+
+ /* Entry index for code with
+ minimum code length (=2 in this case) */
+ 0x00, 0x01, 0x02,
+ 0x03,
+ 0x04,
+ 0x05,
+ 0x06,
+ 0x07,
+ 0x08,
+ 0x09,
+ 0x0A,
+ 0x0B
+ }
+}; /* jpeg_huffman_dc */
+
+static const u8 jpeg_huffman_ac[2][16 + 162] = {
+ { /* jpeg_huffman_ac[0][] */
+ 0x00, /* number of code length=1 */
+ 0x02,
+ 0x01,
+ 0x03,
+ 0x03,
+ 0x02,
+ 0x04,
+ 0x03,
+ 0x05,
+ 0x05,
+ 0x04,
+ 0x04,
+ 0x00,
+ 0x00,
+ 0x01,
+ 0x7D, /* number of code length=16 */
+
+ /* Entry index for code with
+ minimum code length (=2 in this case) */
+ 0x01, 0x02,
+ 0x03,
+ 0x00, 0x04, 0x11,
+ 0x05, 0x12, 0x21,
+ 0x31, 0x41,
+ 0x06, 0x13, 0x51, 0x61,
+ 0x07, 0x22, 0x71,
+ 0x14, 0x32, 0x81, 0x91, 0xA1,
+ 0x08, 0x23, 0x42, 0xB1, 0xC1,
+ 0x15, 0x52, 0xD1, 0xF0,
+ 0x24, 0x33, 0x62, 0x72,
+ 0x82,
+ 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19,
+ 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29,
+ 0x2A, 0x34, 0x35, 0x36,
+ 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44,
+ 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A,
+ 0x53, 0x54, 0x55, 0x56,
+ 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64,
+ 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A,
+ 0x73, 0x74, 0x75, 0x76,
+ 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84,
+ 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A,
+ 0x92, 0x93, 0x94, 0x95,
+ 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2,
+ 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
+ 0xA9, 0xAA, 0xB2, 0xB3,
+ 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9,
+ 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6,
+ 0xC7, 0xC8, 0xC9, 0xCA,
+ 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
+ 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3,
+ 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3,
+ 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9,
+ 0xFA
+ },
+ { /* jpeg_huffman_ac[1][] */
+ 0x00, /* number of code length=1 */
+ 0x02,
+ 0x01,
+ 0x02,
+ 0x04,
+ 0x04,
+ 0x03,
+ 0x04,
+ 0x07,
+ 0x05,
+ 0x04,
+ 0x04,
+ 0x00,
+ 0x01,
+ 0x02,
+ 0x77, /* number of code length=16 */
+
+ /* Entry index for code with
+ minimum code length (=2 in this case) */
+ 0x00, 0x01,
+ 0x02,
+ 0x03, 0x11,
+ 0x04, 0x05, 0x21, 0x31,
+ 0x06, 0x12, 0x41, 0x51,
+ 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81,
+ 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1,
+ 0x09, 0x23, 0x33, 0x52, 0xF0,
+ 0x15, 0x62, 0x72, 0xD1,
+ 0x0A, 0x16, 0x24, 0x34,
+
+ 0xE1,
+ 0x25, 0xF1,
+ 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27,
+ 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3A, 0x43,
+ 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5A, 0x63,
+ 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x82,
+ 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
+ 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95,
+ 0x96, 0x97, 0x98, 0x99,
+ 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+ 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3,
+ 0xB4, 0xB5, 0xB6, 0xB7,
+ 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4,
+ 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA,
+ 0xD2, 0xD3, 0xD4, 0xD5,
+ 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2,
+ 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8,
+ 0xE9, 0xEA, 0xF2, 0xF3,
+ 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA
+ }
+}; /* jpeg_huffman_ac */
+
+static void dma_flush(u32 buf_start, u32 buf_size);
+
+static s32 zigzag(s32 i)
+{
+ s32 zigzag_i;
+ switch (i) {
+ case 0:
+ zigzag_i = 0;
+ break;
+ case 1:
+ zigzag_i = 1;
+ break;
+ case 2:
+ zigzag_i = 8;
+ break;
+ case 3:
+ zigzag_i = 16;
+ break;
+ case 4:
+ zigzag_i = 9;
+ break;
+ case 5:
+ zigzag_i = 2;
+ break;
+ case 6:
+ zigzag_i = 3;
+ break;
+ case 7:
+ zigzag_i = 10;
+ break;
+ case 8:
+ zigzag_i = 17;
+ break;
+ case 9:
+ zigzag_i = 24;
+ break;
+ case 10:
+ zigzag_i = 32;
+ break;
+ case 11:
+ zigzag_i = 25;
+ break;
+ case 12:
+ zigzag_i = 18;
+ break;
+ case 13:
+ zigzag_i = 11;
+ break;
+ case 14:
+ zigzag_i = 4;
+ break;
+ case 15:
+ zigzag_i = 5;
+ break;
+ case 16:
+ zigzag_i = 12;
+ break;
+ case 17:
+ zigzag_i = 19;
+ break;
+ case 18:
+ zigzag_i = 26;
+ break;
+ case 19:
+ zigzag_i = 33;
+ break;
+ case 20:
+ zigzag_i = 40;
+ break;
+ case 21:
+ zigzag_i = 48;
+ break;
+ case 22:
+ zigzag_i = 41;
+ break;
+ case 23:
+ zigzag_i = 34;
+ break;
+ case 24:
+ zigzag_i = 27;
+ break;
+ case 25:
+ zigzag_i = 20;
+ break;
+ case 26:
+ zigzag_i = 13;
+ break;
+ case 27:
+ zigzag_i = 6;
+ break;
+ case 28:
+ zigzag_i = 7;
+ break;
+ case 29:
+ zigzag_i = 14;
+ break;
+ case 30:
+ zigzag_i = 21;
+ break;
+ case 31:
+ zigzag_i = 28;
+ break;
+ case 32:
+ zigzag_i = 35;
+ break;
+ case 33:
+ zigzag_i = 42;
+ break;
+ case 34:
+ zigzag_i = 49;
+ break;
+ case 35:
+ zigzag_i = 56;
+ break;
+ case 36:
+ zigzag_i = 57;
+ break;
+ case 37:
+ zigzag_i = 50;
+ break;
+ case 38:
+ zigzag_i = 43;
+ break;
+ case 39:
+ zigzag_i = 36;
+ break;
+ case 40:
+ zigzag_i = 29;
+ break;
+ case 41:
+ zigzag_i = 22;
+ break;
+ case 42:
+ zigzag_i = 15;
+ break;
+ case 43:
+ zigzag_i = 23;
+ break;
+ case 44:
+ zigzag_i = 30;
+ break;
+ case 45:
+ zigzag_i = 37;
+ break;
+ case 46:
+ zigzag_i = 44;
+ break;
+ case 47:
+ zigzag_i = 51;
+ break;
+ case 48:
+ zigzag_i = 58;
+ break;
+ case 49:
+ zigzag_i = 59;
+ break;
+ case 50:
+ zigzag_i = 52;
+ break;
+ case 51:
+ zigzag_i = 45;
+ break;
+ case 52:
+ zigzag_i = 38;
+ break;
+ case 53:
+ zigzag_i = 31;
+ break;
+ case 54:
+ zigzag_i = 39;
+ break;
+ case 55:
+ zigzag_i = 46;
+ break;
+ case 56:
+ zigzag_i = 53;
+ break;
+ case 57:
+ zigzag_i = 60;
+ break;
+ case 58:
+ zigzag_i = 61;
+ break;
+ case 59:
+ zigzag_i = 54;
+ break;
+ case 60:
+ zigzag_i = 47;
+ break;
+ case 61:
+ zigzag_i = 55;
+ break;
+ case 62:
+ zigzag_i = 62;
+ break;
+ default:
+ zigzag_i = 63;
+ break;
+ }
+ return zigzag_i;
+}
+
+/* Perform convertion from Q to 1/Q */
+u32 reciprocal(u32 q)
+{
+ u32 q_recip;
+
+ /* 65535 * (1/q) */
+ switch (q) {
+ case 0:
+ q_recip = 0;
+ break;
+ case 1:
+ q_recip = 65535;
+ break;
+ case 2:
+ q_recip = 32768;
+ break;
+ case 3:
+ q_recip = 21845;
+ break;
+ case 4:
+ q_recip = 16384;
+ break;
+ case 5:
+ q_recip = 13107;
+ break;
+ case 6:
+ q_recip = 10923;
+ break;
+ case 7:
+ q_recip = 9362;
+ break;
+ case 8:
+ q_recip = 8192;
+ break;
+ case 9:
+ q_recip = 7282;
+ break;
+ case 10:
+ q_recip = 6554;
+ break;
+ case 11:
+ q_recip = 5958;
+ break;
+ case 12:
+ q_recip = 5461;
+ break;
+ case 13:
+ q_recip = 5041;
+ break;
+ case 14:
+ q_recip = 4681;
+ break;
+ case 15:
+ q_recip = 4369;
+ break;
+ case 16:
+ q_recip = 4096;
+ break;
+ case 17:
+ q_recip = 3855;
+ break;
+ case 18:
+ q_recip = 3641;
+ break;
+ case 19:
+ q_recip = 3449;
+ break;
+ case 20:
+ q_recip = 3277;
+ break;
+ case 21:
+ q_recip = 3121;
+ break;
+ case 22:
+ q_recip = 2979;
+ break;
+ case 23:
+ q_recip = 2849;
+ break;
+ case 24:
+ q_recip = 2731;
+ break;
+ case 25:
+ q_recip = 2621;
+ break;
+ case 26:
+ q_recip = 2521;
+ break;
+ case 27:
+ q_recip = 2427;
+ break;
+ case 28:
+ q_recip = 2341;
+ break;
+ case 29:
+ q_recip = 2260;
+ break;
+ case 30:
+ q_recip = 2185;
+ break;
+ case 31:
+ q_recip = 2114;
+ break;
+ case 32:
+ q_recip = 2048;
+ break;
+ case 33:
+ q_recip = 1986;
+ break;
+ case 34:
+ q_recip = 1928;
+ break;
+ case 35:
+ q_recip = 1872;
+ break;
+ case 36:
+ q_recip = 1820;
+ break;
+ case 37:
+ q_recip = 1771;
+ break;
+ case 38:
+ q_recip = 1725;
+ break;
+ case 39:
+ q_recip = 1680;
+ break;
+ case 40:
+ q_recip = 1638;
+ break;
+ case 41:
+ q_recip = 1598;
+ break;
+ case 42:
+ q_recip = 1560;
+ break;
+ case 43:
+ q_recip = 1524;
+ break;
+ case 44:
+ q_recip = 1489;
+ break;
+ case 45:
+ q_recip = 1456;
+ break;
+ case 46:
+ q_recip = 1425;
+ break;
+ case 47:
+ q_recip = 1394;
+ break;
+ case 48:
+ q_recip = 1365;
+ break;
+ case 49:
+ q_recip = 1337;
+ break;
+ case 50:
+ q_recip = 1311;
+ break;
+ case 51:
+ q_recip = 1285;
+ break;
+ case 52:
+ q_recip = 1260;
+ break;
+ case 53:
+ q_recip = 1237;
+ break;
+ case 54:
+ q_recip = 1214;
+ break;
+ case 55:
+ q_recip = 1192;
+ break;
+ case 56:
+ q_recip = 1170;
+ break;
+ case 57:
+ q_recip = 1150;
+ break;
+ case 58:
+ q_recip = 1130;
+ break;
+ case 59:
+ q_recip = 1111;
+ break;
+ case 60:
+ q_recip = 1092;
+ break;
+ case 61:
+ q_recip = 1074;
+ break;
+ case 62:
+ q_recip = 1057;
+ break;
+ case 63:
+ q_recip = 1040;
+ break;
+ case 64:
+ q_recip = 1024;
+ break;
+ case 65:
+ q_recip = 1008;
+ break;
+ case 66:
+ q_recip = 993;
+ break;
+ case 67:
+ q_recip = 978;
+ break;
+ case 68:
+ q_recip = 964;
+ break;
+ case 69:
+ q_recip = 950;
+ break;
+ case 70:
+ q_recip = 936;
+ break;
+ case 71:
+ q_recip = 923;
+ break;
+ case 72:
+ q_recip = 910;
+ break;
+ case 73:
+ q_recip = 898;
+ break;
+ case 74:
+ q_recip = 886;
+ break;
+ case 75:
+ q_recip = 874;
+ break;
+ case 76:
+ q_recip = 862;
+ break;
+ case 77:
+ q_recip = 851;
+ break;
+ case 78:
+ q_recip = 840;
+ break;
+ case 79:
+ q_recip = 830;
+ break;
+ case 80:
+ q_recip = 819;
+ break;
+ case 81:
+ q_recip = 809;
+ break;
+ case 82:
+ q_recip = 799;
+ break;
+ case 83:
+ q_recip = 790;
+ break;
+ case 84:
+ q_recip = 780;
+ break;
+ case 85:
+ q_recip = 771;
+ break;
+ case 86:
+ q_recip = 762;
+ break;
+ case 87:
+ q_recip = 753;
+ break;
+ case 88:
+ q_recip = 745;
+ break;
+ case 89:
+ q_recip = 736;
+ break;
+ case 90:
+ q_recip = 728;
+ break;
+ case 91:
+ q_recip = 720;
+ break;
+ case 92:
+ q_recip = 712;
+ break;
+ case 93:
+ q_recip = 705;
+ break;
+ case 94:
+ q_recip = 697;
+ break;
+ case 95:
+ q_recip = 690;
+ break;
+ case 96:
+ q_recip = 683;
+ break;
+ case 97:
+ q_recip = 676;
+ break;
+ case 98:
+ q_recip = 669;
+ break;
+ case 99:
+ q_recip = 662;
+ break;
+ case 100:
+ q_recip = 655;
+ break;
+ case 101:
+ q_recip = 649;
+ break;
+ case 102:
+ q_recip = 643;
+ break;
+ case 103:
+ q_recip = 636;
+ break;
+ case 104:
+ q_recip = 630;
+ break;
+ case 105:
+ q_recip = 624;
+ break;
+ case 106:
+ q_recip = 618;
+ break;
+ case 107:
+ q_recip = 612;
+ break;
+ case 108:
+ q_recip = 607;
+ break;
+ case 109:
+ q_recip = 601;
+ break;
+ case 110:
+ q_recip = 596;
+ break;
+ case 111:
+ q_recip = 590;
+ break;
+ case 112:
+ q_recip = 585;
+ break;
+ case 113:
+ q_recip = 580;
+ break;
+ case 114:
+ q_recip = 575;
+ break;
+ case 115:
+ q_recip = 570;
+ break;
+ case 116:
+ q_recip = 565;
+ break;
+ case 117:
+ q_recip = 560;
+ break;
+ case 118:
+ q_recip = 555;
+ break;
+ case 119:
+ q_recip = 551;
+ break;
+ case 120:
+ q_recip = 546;
+ break;
+ case 121:
+ q_recip = 542;
+ break;
+ case 122:
+ q_recip = 537;
+ break;
+ case 123:
+ q_recip = 533;
+ break;
+ case 124:
+ q_recip = 529;
+ break;
+ case 125:
+ q_recip = 524;
+ break;
+ case 126:
+ q_recip = 520;
+ break;
+ case 127:
+ q_recip = 516;
+ break;
+ case 128:
+ q_recip = 512;
+ break;
+ case 129:
+ q_recip = 508;
+ break;
+ case 130:
+ q_recip = 504;
+ break;
+ case 131:
+ q_recip = 500;
+ break;
+ case 132:
+ q_recip = 496;
+ break;
+ case 133:
+ q_recip = 493;
+ break;
+ case 134:
+ q_recip = 489;
+ break;
+ case 135:
+ q_recip = 485;
+ break;
+ case 136:
+ q_recip = 482;
+ break;
+ case 137:
+ q_recip = 478;
+ break;
+ case 138:
+ q_recip = 475;
+ break;
+ case 139:
+ q_recip = 471;
+ break;
+ case 140:
+ q_recip = 468;
+ break;
+ case 141:
+ q_recip = 465;
+ break;
+ case 142:
+ q_recip = 462;
+ break;
+ case 143:
+ q_recip = 458;
+ break;
+ case 144:
+ q_recip = 455;
+ break;
+ case 145:
+ q_recip = 452;
+ break;
+ case 146:
+ q_recip = 449;
+ break;
+ case 147:
+ q_recip = 446;
+ break;
+ case 148:
+ q_recip = 443;
+ break;
+ case 149:
+ q_recip = 440;
+ break;
+ case 150:
+ q_recip = 437;
+ break;
+ case 151:
+ q_recip = 434;
+ break;
+ case 152:
+ q_recip = 431;
+ break;
+ case 153:
+ q_recip = 428;
+ break;
+ case 154:
+ q_recip = 426;
+ break;
+ case 155:
+ q_recip = 423;
+ break;
+ case 156:
+ q_recip = 420;
+ break;
+ case 157:
+ q_recip = 417;
+ break;
+ case 158:
+ q_recip = 415;
+ break;
+ case 159:
+ q_recip = 412;
+ break;
+ case 160:
+ q_recip = 410;
+ break;
+ case 161:
+ q_recip = 407;
+ break;
+ case 162:
+ q_recip = 405;
+ break;
+ case 163:
+ q_recip = 402;
+ break;
+ case 164:
+ q_recip = 400;
+ break;
+ case 165:
+ q_recip = 397;
+ break;
+ case 166:
+ q_recip = 395;
+ break;
+ case 167:
+ q_recip = 392;
+ break;
+ case 168:
+ q_recip = 390;
+ break;
+ case 169:
+ q_recip = 388;
+ break;
+ case 170:
+ q_recip = 386;
+ break;
+ case 171:
+ q_recip = 383;
+ break;
+ case 172:
+ q_recip = 381;
+ break;
+ case 173:
+ q_recip = 379;
+ break;
+ case 174:
+ q_recip = 377;
+ break;
+ case 175:
+ q_recip = 374;
+ break;
+ case 176:
+ q_recip = 372;
+ break;
+ case 177:
+ q_recip = 370;
+ break;
+ case 178:
+ q_recip = 368;
+ break;
+ case 179:
+ q_recip = 366;
+ break;
+ case 180:
+ q_recip = 364;
+ break;
+ case 181:
+ q_recip = 362;
+ break;
+ case 182:
+ q_recip = 360;
+ break;
+ case 183:
+ q_recip = 358;
+ break;
+ case 184:
+ q_recip = 356;
+ break;
+ case 185:
+ q_recip = 354;
+ break;
+ case 186:
+ q_recip = 352;
+ break;
+ case 187:
+ q_recip = 350;
+ break;
+ case 188:
+ q_recip = 349;
+ break;
+ case 189:
+ q_recip = 347;
+ break;
+ case 190:
+ q_recip = 345;
+ break;
+ case 191:
+ q_recip = 343;
+ break;
+ case 192:
+ q_recip = 341;
+ break;
+ case 193:
+ q_recip = 340;
+ break;
+ case 194:
+ q_recip = 338;
+ break;
+ case 195:
+ q_recip = 336;
+ break;
+ case 196:
+ q_recip = 334;
+ break;
+ case 197:
+ q_recip = 333;
+ break;
+ case 198:
+ q_recip = 331;
+ break;
+ case 199:
+ q_recip = 329;
+ break;
+ case 200:
+ q_recip = 328;
+ break;
+ case 201:
+ q_recip = 326;
+ break;
+ case 202:
+ q_recip = 324;
+ break;
+ case 203:
+ q_recip = 323;
+ break;
+ case 204:
+ q_recip = 321;
+ break;
+ case 205:
+ q_recip = 320;
+ break;
+ case 206:
+ q_recip = 318;
+ break;
+ case 207:
+ q_recip = 317;
+ break;
+ case 208:
+ q_recip = 315;
+ break;
+ case 209:
+ q_recip = 314;
+ break;
+ case 210:
+ q_recip = 312;
+ break;
+ case 211:
+ q_recip = 311;
+ break;
+ case 212:
+ q_recip = 309;
+ break;
+ case 213:
+ q_recip = 308;
+ break;
+ case 214:
+ q_recip = 306;
+ break;
+ case 215:
+ q_recip = 305;
+ break;
+ case 216:
+ q_recip = 303;
+ break;
+ case 217:
+ q_recip = 302;
+ break;
+ case 218:
+ q_recip = 301;
+ break;
+ case 219:
+ q_recip = 299;
+ break;
+ case 220:
+ q_recip = 298;
+ break;
+ case 221:
+ q_recip = 297;
+ break;
+ case 222:
+ q_recip = 295;
+ break;
+ case 223:
+ q_recip = 294;
+ break;
+ case 224:
+ q_recip = 293;
+ break;
+ case 225:
+ q_recip = 291;
+ break;
+ case 226:
+ q_recip = 290;
+ break;
+ case 227:
+ q_recip = 289;
+ break;
+ case 228:
+ q_recip = 287;
+ break;
+ case 229:
+ q_recip = 286;
+ break;
+ case 230:
+ q_recip = 285;
+ break;
+ case 231:
+ q_recip = 284;
+ break;
+ case 232:
+ q_recip = 282;
+ break;
+ case 233:
+ q_recip = 281;
+ break;
+ case 234:
+ q_recip = 280;
+ break;
+ case 235:
+ q_recip = 279;
+ break;
+ case 236:
+ q_recip = 278;
+ break;
+ case 237:
+ q_recip = 277;
+ break;
+ case 238:
+ q_recip = 275;
+ break;
+ case 239:
+ q_recip = 274;
+ break;
+ case 240:
+ q_recip = 273;
+ break;
+ case 241:
+ q_recip = 272;
+ break;
+ case 242:
+ q_recip = 271;
+ break;
+ case 243:
+ q_recip = 270;
+ break;
+ case 244:
+ q_recip = 269;
+ break;
+ case 245:
+ q_recip = 267;
+ break;
+ case 246:
+ q_recip = 266;
+ break;
+ case 247:
+ q_recip = 265;
+ break;
+ case 248:
+ q_recip = 264;
+ break;
+ case 249:
+ q_recip = 263;
+ break;
+ case 250:
+ q_recip = 262;
+ break;
+ case 251:
+ q_recip = 261;
+ break;
+ case 252:
+ q_recip = 260;
+ break;
+ case 253:
+ q_recip = 259;
+ break;
+ case 254:
+ q_recip = 258;
+ break;
+ default:
+ q_recip = 257;
+ break;
+ }
+ return q_recip;
+} /* reciprocal */
+
+static void push_word(u8 *base, s32 *offset, u32 word)
+{
+ u8 *ptr;
+ s32 i;
+ s32 bytes = (word >> 24) & 0xff;
+ for (i = bytes - 1; i >= 0; i--) {
+ ptr = base + *offset;
+ (*offset)++;
+ if (i == 0)
+ *ptr = word & 0xff;
+ else if (i == 1)
+ *ptr = (word >> 8) & 0xff;
+ else if (i == 2)
+ *ptr = (word >> 16) & 0xff;
+ }
+}
+
+static s32 jpeg_quality_scaling(s32 quality)
+{
+ if (quality <= 0)
+ quality = 1;
+ if (quality > 100)
+ quality = 100;
+
+ if (quality < 50)
+ quality = 5000 / quality;
+ else
+ quality = 200 - quality * 2;
+ return quality;
+}
+
+static void _convert_quant_table(u16 *qtable, u16 *basic_table,
+ s32 scale_factor, bool force_baseline)
+{
+ s32 i = 0;
+ s32 temp;
+ for (i = 0; i < DCTSIZE2; i++) {
+ temp = ((s32)basic_table[i] * scale_factor + 50) / 100;
+ /* limit the values to the valid range */
+ if (temp <= 0)
+ temp = 1;
+ /* max quantizer needed for 12 bits */
+ if (temp > 32767)
+ temp = 32767;
+ /* limit to baseline range if requested */
+ if (force_baseline && temp > 255)
+ temp = 255;
+ qtable[i] = (u16)temp;
+ }
+}
+
+static void convert_quant_table(u16 *qtable, u16 *basic_table,
+ s32 scale_factor)
+{
+ _convert_quant_table(qtable, basic_table, scale_factor, true);
+}
+
+static void write_jpeg_quant_lut(s32 table_num)
+{
+ s32 i;
+ u32 data32;
+
+ for (i = 0; i < DCTSIZE2; i += 2) {
+ data32 = reciprocal(gQuantTable[table_num][i]);
+ data32 |= reciprocal(gQuantTable[table_num][i + 1]) << 16;
+ WRITE_HREG(HCODEC_QDCT_JPEG_QUANT_DATA, data32);
+ }
+}
+
+static void write_jpeg_huffman_lut_dc(s32 table_num)
+{
+ u32 code_len, code_word, pos, addr;
+ u32 num_code_len;
+ u32 lut[12];
+ u32 i, j;
+
+ code_len = 1;
+ code_word = 1;
+ pos = 16;
+
+ /* Construct DC Huffman table */
+ for (i = 0; i < 16; i++) {
+ num_code_len = jpeg_huffman_dc[table_num][i];
+ for (j = 0; j < num_code_len; j++) {
+ code_word = (code_word + 1) & ((1 << code_len) - 1);
+ if (code_len < i + 1) {
+ code_word <<= (i + 1 - code_len);
+ code_len = i + 1;
+ }
+ addr = jpeg_huffman_dc[table_num][pos];
+ lut[addr] = ((code_len - 1) << 16) | (code_word);
+ pos++;
+ }
+ }
+
+ /* Write DC Huffman table to HW */
+ for (i = 0; i < 12; i++)
+ WRITE_HREG(HCODEC_VLC_HUFFMAN_DATA, lut[i]);
+}
+
+static void write_jpeg_huffman_lut_ac(s32 table_num)
+{
+ u32 code_len, code_word, pos;
+ u32 num_code_len;
+ u32 run, size;
+ u32 data, addr = 0;
+ u32 lut[162];
+ u32 i, j;
+ code_len = 1;
+ code_word = 1;
+ pos = 16;
+
+ /* Construct AC Huffman table */
+ for (i = 0; i < 16; i++) {
+ num_code_len = jpeg_huffman_ac[table_num][i];
+ for (j = 0; j < num_code_len; j++) {
+ code_word = (code_word + 1) & ((1 << code_len) - 1);
+ if (code_len < i + 1) {
+ code_word <<= (i + 1 - code_len);
+ code_len = i + 1;
+ }
+ run = jpeg_huffman_ac[table_num][pos] >> 4;
+ size = jpeg_huffman_ac[table_num][pos] & 0xf;
+ data = ((code_len - 1) << 16) | (code_word);
+ if (size == 0) {
+ if (run == 0)
+ addr = 0; /* EOB */
+ else if (run == 0xf)
+ addr = 161; /* ZRL */
+ else
+ jenc_pr(LOG_ERROR,
+ "Error: Illegal AC Huffman table format!\n");
+ } else if (size <= 0xa)
+ addr = 1 + 16 * (size - 1) + run;
+ else
+ jenc_pr(LOG_ERROR,
+ "Error: Illegal AC Huffman table format!\n");
+ lut[addr] = data;
+ pos++;
+ }
+ }
+
+ /* Write AC Huffman table to HW */
+ for (i = 0; i < 162; i++)
+ WRITE_HREG(HCODEC_VLC_HUFFMAN_DATA, lut[i]);
+}
+
+static void prepare_jpeg_header(struct jpegenc_wq_s *wq)
+{
+ s32 pic_format;
+ s32 pic_width, pic_height;
+ s32 q_sel_comp0, q_sel_comp1, q_sel_comp2;
+ s32 dc_huff_sel_comp0, dc_huff_sel_comp1, dc_huff_sel_comp2;
+ s32 ac_huff_sel_comp0, ac_huff_sel_comp1, ac_huff_sel_comp2;
+ s32 lastcoeff_sel;
+ s32 jdct_intr_sel;
+ s32 h_factor_comp0, v_factor_comp0;
+ s32 h_factor_comp1, v_factor_comp1;
+ s32 h_factor_comp2, v_factor_comp2;
+ s32 q_num;
+ s32 tq[2];
+ s32 dc_huff_num, ac_huff_num;
+ s32 dc_th[2], ac_th[2];
+ u32 header_bytes = 0;
+ u32 bak_header_bytes = 0;
+ s32 i, j;
+ u8 *assitbuf = (u8 *)wq->AssitstreamStartVirtAddr;
+
+ if (wq->cmd.output_fmt >= JPEGENC_MAX_FRAME_FMT)
+ jenc_pr(LOG_ERROR, "Input format is wrong!\n");
+ switch (wq->cmd.output_fmt) {
+ case JPEGENC_FMT_NV21:
+ case JPEGENC_FMT_NV12:
+ case JPEGENC_FMT_YUV420:
+ pic_format = 3;
+ break;
+ case JPEGENC_FMT_YUV422_SINGLE:
+ pic_format = 2;
+ break;
+ case JPEGENC_FMT_YUV444_SINGLE:
+ case JPEGENC_FMT_YUV444_PLANE:
+ pic_format = 1;
+ break;
+ default:
+ pic_format = 0;
+ break;
+ }
+
+ pic_width = wq->cmd.encoder_width;
+ pic_height = wq->cmd.encoder_height;
+
+ q_sel_comp0 = QUANT_SEL_COMP0;
+ q_sel_comp1 = QUANT_SEL_COMP1;
+ q_sel_comp2 = QUANT_SEL_COMP2;
+
+ dc_huff_sel_comp0 = DC_HUFF_SEL_COMP0;
+ dc_huff_sel_comp1 = DC_HUFF_SEL_COMP1;
+ dc_huff_sel_comp2 = DC_HUFF_SEL_COMP2;
+ ac_huff_sel_comp0 = AC_HUFF_SEL_COMP0;
+ ac_huff_sel_comp1 = AC_HUFF_SEL_COMP1;
+ ac_huff_sel_comp2 = AC_HUFF_SEL_COMP2;
+ lastcoeff_sel = JDCT_LASTCOEFF_SEL;
+ jdct_intr_sel = JDCT_INTR_SEL;
+
+ if (pic_format == 2) {
+ /* YUV422 */
+ h_factor_comp0 = 1;
+ v_factor_comp0 = 0;
+ h_factor_comp1 = 0;
+ v_factor_comp1 = 0;
+ h_factor_comp2 = 0;
+ v_factor_comp2 = 0;
+ } else if (pic_format == 3) {
+ /* YUV420 */
+ h_factor_comp0 = 1;
+ v_factor_comp0 = 1;
+ h_factor_comp1 = 0;
+ v_factor_comp1 = 0;
+ h_factor_comp2 = 0;
+ v_factor_comp2 = 0;
+ } else {
+ /* RGB or YUV */
+ h_factor_comp0 = 0;
+ v_factor_comp0 = 0;
+ h_factor_comp1 = 0;
+ v_factor_comp1 = 0;
+ h_factor_comp2 = 0;
+ v_factor_comp2 = 0;
+ }
+
+ /* SOI marke */
+ push_word(assitbuf, &header_bytes,
+ (2 << 24) | /* Number of bytes */
+ (0xffd8 << 0)); /* data: SOI marker */
+
+ /* Define quantization tables */
+ q_num = 1;
+#if 0
+ if ((q_sel_comp0 != q_sel_comp1) ||
+ (q_sel_comp0 != q_sel_comp2) ||
+ (q_sel_comp1 != q_sel_comp2))
+#endif
+ q_num++;
+#if 0
+ tq[0] = q_sel_comp0;
+ tq[1] = (q_sel_comp0 != q_sel_comp1) ? q_sel_comp1 :
+ (q_sel_comp0 != q_sel_comp2) ? q_sel_comp2 :
+ q_sel_comp0;
+#endif
+ tq[0] = 0;
+ tq[1] = q_num - 1;
+
+ /* data: DQT marker */
+ push_word(assitbuf, &header_bytes,
+ (2 << 24) | (0xffdb << 0));
+ /* data: Lq */
+ push_word(assitbuf, &header_bytes,
+ (2 << 24) | ((2 + 65 * q_num) << 0));
+
+ /* Add Quantization table bytes */
+ /* header_bytes += (2 + (2 + 65 * q_num)); */
+ for (i = 0; i < q_num; i++) {
+ /* data: {Pq,Tq} */
+ push_word(assitbuf, &header_bytes,
+ (1 << 24) | (i << 0));
+ for (j = 0; j < DCTSIZE2; j++) {
+ /* data: Qk */
+ push_word(assitbuf, &header_bytes,
+ (1 << 24) |
+ ((gQuantTable[tq[i]][zigzag(j)]) << 0));
+ }
+ }
+
+ /* Define Huffman tables */
+ dc_huff_num = 1;
+ if ((dc_huff_sel_comp0 != dc_huff_sel_comp1) ||
+ (dc_huff_sel_comp0 != dc_huff_sel_comp2) ||
+ (dc_huff_sel_comp1 != dc_huff_sel_comp2))
+ dc_huff_num++;
+
+ ac_huff_num = 1;
+ if ((ac_huff_sel_comp0 != ac_huff_sel_comp1) ||
+ (ac_huff_sel_comp0 != ac_huff_sel_comp2) ||
+ (ac_huff_sel_comp1 != ac_huff_sel_comp2))
+ ac_huff_num++;
+
+ dc_th[0] = dc_huff_sel_comp0;
+ dc_th[1] = (dc_huff_sel_comp0 != dc_huff_sel_comp1) ?
+ dc_huff_sel_comp1 : (dc_huff_sel_comp0 != dc_huff_sel_comp2) ?
+ dc_huff_sel_comp2 : dc_huff_sel_comp0;
+
+ ac_th[0] = ac_huff_sel_comp0;
+ ac_th[1] = (ac_huff_sel_comp0 != ac_huff_sel_comp1) ?
+ ac_huff_sel_comp1 : (ac_huff_sel_comp0 != ac_huff_sel_comp2) ?
+ ac_huff_sel_comp2 : ac_huff_sel_comp0;
+
+ /* data: DHT marker */
+ push_word(assitbuf, &header_bytes,
+ (2 << 24) | (0xffc4 << 0));
+ /* data: Lh */
+ push_word(assitbuf, &header_bytes,
+ (2 << 24) |
+ ((2 + (1 + 16 + 12) * dc_huff_num +
+ (1 + 16 + 162) * ac_huff_num) << 0));
+
+ /* Add Huffman table bytes */
+ /* data: {Tc,Th} */
+ for (i = 0; i < dc_huff_num; i++) {
+ push_word(assitbuf, &header_bytes,
+ (1 << 24) | (i << 0));
+ for (j = 0; j < 16 + 12; j++) {
+ /* data: Li then Vi,j */
+ push_word(assitbuf, &header_bytes,
+ (1 << 24) |
+ ((jpeg_huffman_dc[dc_th[i]][j]) << 0));
+ }
+ }
+ for (i = 0; i < ac_huff_num; i++) {
+ push_word(assitbuf, &header_bytes,
+ (1 << 24) |
+ (1 << 4) | /* data: Tc */
+ (i << 0)); /* data: Th */
+ for (j = 0; j < 16 + 162; j++) {
+ /* data: Li then Vi,j */
+ push_word(assitbuf, &header_bytes,
+ (1 << 24) |
+ ((jpeg_huffman_ac[ac_th[i]][j]) << 0));
+ }
+ }
+
+ /* Frame header */
+ /* Add Frame header bytes */
+ /* header_bytes += (2 + (8 + 3 * 3)); */
+ push_word(assitbuf, &header_bytes,
+ (2 << 24) | /* Number of bytes */
+ (0xffc0 << 0)); /* data: SOF_0 marker */
+ /* data: Lf */
+ push_word(assitbuf, &header_bytes,
+ (2 << 24) | ((8 + 3 * 3) << 0));
+ /* data: P -- Sample precision */
+ push_word(assitbuf,
+ &header_bytes, (1 << 24) | (8 << 0));
+ /* data: Y -- Number of lines */
+ push_word(assitbuf,
+ &header_bytes, (2 << 24) | (pic_height << 0));
+ /* data: X -- Number of samples per line */
+ push_word(assitbuf,
+ &header_bytes, (2 << 24) | (pic_width << 0));
+ /* data: Nf -- Number of components in a frame */
+ push_word(assitbuf,
+ &header_bytes, (1 << 24) | (3 << 0));
+ /* data: C0 -- Comp0 identifier */
+ push_word(assitbuf,
+ &header_bytes, (1 << 24) | (0 << 0));
+ push_word(assitbuf,
+ &header_bytes, (1 << 24) |
+ /* data: H0 -- Comp0 horizontal sampling factor */
+ ((h_factor_comp0 + 1) << 4) |
+ /* data: V0 -- Comp0 vertical sampling factor */
+ ((v_factor_comp0 + 1) << 0));
+
+ /* data: Tq0 -- Comp0 quantization table seletor */
+ push_word(assitbuf,
+ &header_bytes, (1 << 24) | (0 << 0));
+ /* data: C1 -- Comp1 identifier */
+ push_word(assitbuf,
+ &header_bytes, (1 << 24) | (1 << 0));
+ push_word(assitbuf,
+ &header_bytes, (1 << 24) |
+ /* data: H1 -- Comp1 horizontal sampling factor */
+ ((h_factor_comp1 + 1) << 4) |
+ /* data: V1 -- Comp1 vertical sampling factor */
+ ((v_factor_comp1 + 1) << 0));
+ /* data: Tq1 -- Comp1 quantization table seletor */
+ push_word(assitbuf,
+ &header_bytes, (1 << 24) |
+ (((q_sel_comp0 != q_sel_comp1) ? 1 : 0) << 0));
+ /* data: C2 -- Comp2 identifier */
+ push_word(assitbuf,
+ &header_bytes, (1 << 24) | (2 << 0));
+ push_word(assitbuf,
+ &header_bytes, (1 << 24) |
+ /* data: H2 -- Comp2 horizontal sampling factor */
+ ((h_factor_comp2 + 1) << 4) |
+ /* data: V2 -- Comp2 vertical sampling factor */
+ ((v_factor_comp2 + 1) << 0));
+ /* data: Tq2 -- Comp2 quantization table seletor */
+ push_word(assitbuf,
+ &header_bytes, (1 << 24) |
+ (((q_sel_comp0 != q_sel_comp2) ? 1 : 0) << 0));
+
+ /* Scan header */
+ bak_header_bytes = header_bytes + (2 + (6 + 2 * 3));
+
+ /* Add Scan header bytes */
+ /* header_bytes += (2 + (6+2*3)); */
+ /* If total header bytes is not multiple of 8,
+ then fill 0xff byte between Frame header segment
+ and the Scan header segment. */
+ /* header_bytes = ((header_bytes + 7)/8)*8; */
+ bak_header_bytes = ((bak_header_bytes + 7) / 8) * 8 - bak_header_bytes;
+ for (i = 0; i < bak_header_bytes; i++)
+ push_word(assitbuf,
+ &header_bytes,
+ (1 << 24) | (0xff << 0)); /* 0xff filler */
+
+ push_word(assitbuf,
+ &header_bytes,
+ (2 << 24) | /* Number of bytes */
+ (0xffda << 0)); /* data: SOS marker */
+
+ /* data: Ls */
+ push_word(assitbuf,
+ &header_bytes, (2 << 24) | ((6 + 2 * 3) << 0));
+ /* data: Ns -- Number of components in a scan */
+ push_word(assitbuf,
+ &header_bytes, (1 << 24) | (3 << 0));
+ /* data: Cs0 -- Comp0 identifier */
+ push_word(assitbuf,
+ &header_bytes, (1 << 24) | (0 << 0));
+ push_word(assitbuf,
+ &header_bytes, (1 << 24) |
+ (0 << 4) | /* data: Td0 -- Comp0 DC Huffman table selector */
+ (0 << 0)); /* data: Ta0 -- Comp0 AC Huffman table selector */
+ /* data: Cs1 -- Comp1 identifier */
+ push_word(assitbuf,
+ &header_bytes, (1 << 24) | (1 << 0));
+ push_word(assitbuf,
+ &header_bytes, (1 << 24) |
+ /* data: Td1 -- Comp1 DC Huffman table selector */
+ (((dc_huff_sel_comp0 != dc_huff_sel_comp1) ? 1 : 0) << 4) |
+ /* data: Ta1 -- Comp1 AC Huffman table selector */
+ (((ac_huff_sel_comp0 != ac_huff_sel_comp1) ? 1 : 0) << 0));
+ /* data: Cs2 -- Comp2 identifier */
+ push_word(assitbuf,
+ &header_bytes, (1 << 24) | (2 << 0));
+ push_word(assitbuf,
+ &header_bytes, (1 << 24) |
+ /* data: Td2 -- Comp2 DC Huffman table selector */
+ (((dc_huff_sel_comp0 != dc_huff_sel_comp2) ? 1 : 0) << 4) |
+ /* data: Ta2 -- Comp2 AC Huffman table selector */
+ (((ac_huff_sel_comp0 != ac_huff_sel_comp2) ? 1 : 0) << 0));
+ push_word(assitbuf, &header_bytes,
+ (3 << 24) |
+ (0 << 16) | /* data: Ss = 0 */
+ (63 << 8) | /* data: Se = 63 */
+ (0 << 4) | /* data: Ah = 0 */
+ (0 << 0)); /* data: Al = 0 */
+ jenc_pr(LOG_INFO, "jpeg header bytes is %d\n", header_bytes);
+ wq->headbytes = header_bytes;
+}
+
+static void init_jpeg_encoder(struct jpegenc_wq_s *wq)
+{
+ u32 data32;
+ s32 pic_format; /* 0=RGB; 1=YUV; 2=YUV422; 3=YUV420 */
+ s32 pic_x_start, pic_x_end, pic_y_start, pic_y_end;
+ s32 pic_width, pic_height;
+ s32 q_sel_comp0, q_sel_comp1, q_sel_comp2;
+ s32 dc_huff_sel_comp0, dc_huff_sel_comp1, dc_huff_sel_comp2;
+ s32 ac_huff_sel_comp0, ac_huff_sel_comp1, ac_huff_sel_comp2;
+ s32 lastcoeff_sel;
+ s32 jdct_intr_sel;
+ s32 h_factor_comp0, v_factor_comp0;
+ s32 h_factor_comp1, v_factor_comp1;
+ s32 h_factor_comp2, v_factor_comp2;
+
+ jenc_pr(LOG_INFO, "Initialize JPEG Encoder ....\n");
+ if (wq->cmd.output_fmt >= JPEGENC_MAX_FRAME_FMT)
+ jenc_pr(LOG_ERROR, "Input format is wrong!\n");
+ switch (wq->cmd.output_fmt) {
+ case JPEGENC_FMT_NV21:
+ case JPEGENC_FMT_NV12:
+ case JPEGENC_FMT_YUV420:
+ pic_format = 3;
+ break;
+ case JPEGENC_FMT_YUV422_SINGLE:
+ pic_format = 2;
+ break;
+ case JPEGENC_FMT_YUV444_SINGLE:
+ case JPEGENC_FMT_YUV444_PLANE:
+ pic_format = 1;
+ break;
+ default:
+ pic_format = 0;
+ break;
+ }
+
+ pic_x_start = 0;
+ pic_x_end = wq->cmd.encoder_width - 1;
+ pic_y_start = 0;
+ pic_y_end = wq->cmd.encoder_height - 1;
+ pic_width = wq->cmd.encoder_width;
+ pic_height = wq->cmd.encoder_height;
+
+ q_sel_comp0 = wq->cmd.QuantTable_id * 2;
+ q_sel_comp1 = q_sel_comp0 + 1;
+ q_sel_comp2 = q_sel_comp1;
+
+ dc_huff_sel_comp0 = DC_HUFF_SEL_COMP0;
+ dc_huff_sel_comp1 = DC_HUFF_SEL_COMP1;
+ dc_huff_sel_comp2 = DC_HUFF_SEL_COMP2;
+ ac_huff_sel_comp0 = AC_HUFF_SEL_COMP0;
+ ac_huff_sel_comp1 = AC_HUFF_SEL_COMP1;
+ ac_huff_sel_comp2 = AC_HUFF_SEL_COMP2;
+ lastcoeff_sel = JDCT_LASTCOEFF_SEL;
+ jdct_intr_sel = JDCT_INTR_SEL;
+
+ if (pic_format == 2) {
+ /* YUV422 */
+ h_factor_comp0 = 1;
+ v_factor_comp0 = 0;
+ h_factor_comp1 = 0;
+ v_factor_comp1 = 0;
+ h_factor_comp2 = 0;
+ v_factor_comp2 = 0;
+ } else if (pic_format == 3) {
+ /* YUV420 */
+ h_factor_comp0 = 1;
+ v_factor_comp0 = 1;
+ h_factor_comp1 = 0;
+ v_factor_comp1 = 0;
+ h_factor_comp2 = 0;
+ v_factor_comp2 = 0;
+ } else {
+ /* RGB or YUV */
+ h_factor_comp0 = 0;
+ v_factor_comp0 = 0;
+ h_factor_comp1 = 0;
+ v_factor_comp1 = 0;
+ h_factor_comp2 = 0;
+ v_factor_comp2 = 0;
+ }
+
+ /* Configure picture size and format */
+ WRITE_HREG(HCODEC_VLC_PIC_SIZE, pic_width | (pic_height << 16));
+ WRITE_HREG(HCODEC_VLC_PIC_POSITION, pic_format | (lastcoeff_sel << 4));
+ WRITE_HREG(HCODEC_QDCT_JPEG_X_START_END,
+ ((pic_x_end << 16) | (pic_x_start << 0)));
+ WRITE_HREG(HCODEC_QDCT_JPEG_Y_START_END,
+ ((pic_y_end << 16) | (pic_y_start << 0)));
+
+ /* Configure quantization tables */
+#ifdef EXTEAN_QUANT_TABLE
+ if (external_quant_table_available) {
+ convert_quant_table(&gQuantTable[0][0],
+ &gExternalQuantTablePtr[0],
+ wq->cmd.jpeg_quality);
+ convert_quant_table(&gQuantTable[1][0],
+ &gExternalQuantTablePtr[DCTSIZE2],
+ wq->cmd.jpeg_quality);
+ q_sel_comp0 = 0;
+ q_sel_comp1 = 1;
+ q_sel_comp2 = 1;
+ } else
+#endif
+ {
+ s32 tq[2];
+ tq[0] = q_sel_comp0;
+ tq[1] = (q_sel_comp0 != q_sel_comp1) ?
+ q_sel_comp1 : (q_sel_comp0 != q_sel_comp2) ?
+ q_sel_comp2 : q_sel_comp0;
+ convert_quant_table(&gQuantTable[0][0],
+ (u16 *)&jpeg_quant[tq[0]],
+ wq->cmd.jpeg_quality);
+ if (tq[0] != tq[1])
+ convert_quant_table(&gQuantTable[1][0],
+ (u16 *)&jpeg_quant[tq[1]],
+ wq->cmd.jpeg_quality);
+ q_sel_comp0 = tq[0];
+ q_sel_comp1 = tq[1];
+ q_sel_comp2 = tq[1];
+ }
+
+ /* Set Quantization LUT start address */
+ data32 = 0;
+ data32 |= 0 << 8; /* [8] 0=Write LUT, 1=Read */
+ data32 |= 0 << 0; /* [5:0] Start addr = 0 */
+
+ WRITE_HREG(HCODEC_QDCT_JPEG_QUANT_ADDR, data32);
+
+ /* Burst-write Quantization LUT data */
+ write_jpeg_quant_lut(0);
+ if (q_sel_comp0 != q_sel_comp1)
+ write_jpeg_quant_lut(1);
+#if 0
+ write_jpeg_quant_lut(q_sel_comp0);
+ if (q_sel_comp1 != q_sel_comp0)
+ write_jpeg_quant_lut(q_sel_comp1);
+ if ((q_sel_comp2 != q_sel_comp0) && (q_sel_comp2 != q_sel_comp1))
+ write_jpeg_quant_lut(q_sel_comp2);
+#endif
+
+ /* Configure Huffman tables */
+
+ /* Set DC Huffman LUT start address */
+ data32 = 0;
+ data32 |= 0 << 16; /* [16] 0=Write LUT, 1=Read */
+ data32 |= 0 << 0; /* [8:0] Start addr = 0 */
+ WRITE_HREG(HCODEC_VLC_HUFFMAN_ADDR, data32);
+
+ /* Burst-write DC Huffman LUT data */
+ write_jpeg_huffman_lut_dc(dc_huff_sel_comp0);
+ if (dc_huff_sel_comp1 != dc_huff_sel_comp0)
+ write_jpeg_huffman_lut_dc(dc_huff_sel_comp1);
+
+#if 0
+ if ((dc_huff_sel_comp2 != dc_huff_sel_comp0)
+ && (dc_huff_sel_comp2 != dc_huff_sel_comp1))
+ write_jpeg_huffman_lut_dc(dc_huff_sel_comp2);
+#endif
+
+ /* Set AC Huffman LUT start address */
+ data32 = 0;
+ data32 |= 0 << 16; /* [16] 0=Write LUT, 1=Read */
+ data32 |= 24 << 0; /* [8:0] Start addr = 0 */
+ WRITE_HREG(HCODEC_VLC_HUFFMAN_ADDR, data32);
+
+ /* Burst-write AC Huffman LUT data */
+ write_jpeg_huffman_lut_ac(ac_huff_sel_comp0);
+ if (ac_huff_sel_comp1 != ac_huff_sel_comp0)
+ write_jpeg_huffman_lut_ac(ac_huff_sel_comp1);
+
+#if 0
+ if ((ac_huff_sel_comp2 != ac_huff_sel_comp0)
+ && (ac_huff_sel_comp2 != ac_huff_sel_comp1))
+ write_jpeg_huffman_lut_ac(ac_huff_sel_comp2);
+#endif
+
+ /* Configure general control registers */
+ data32 = 0;
+ /* [19:18] dct_inflow_ctrl: 0=No halt; */
+ /* 1=DCT halts request at end of each 8x8 block; */
+ /* 2=DCT halts request at end of each MCU. */
+ data32 |= 0 << 18;
+ /* [17:16] jpeg_coeff_last_sel: */
+ /* 0=Mark last coeff at the end of an 8x8 block, */
+ /* 1=Mark last coeff at the end of an MCU */
+ /* 2=Mark last coeff at the end of a scan */
+ data32 |= lastcoeff_sel << 16;
+ /* [15] jpeg_quant_sel_comp2 */
+ data32 |= ((q_sel_comp2 == q_sel_comp0) ? 0 : 1) << 15;
+ /* [14] jpeg_v_factor_comp2 */
+ data32 |= v_factor_comp2 << 14;
+ /* [13] jpeg_h_factor_comp2 */
+ data32 |= h_factor_comp2 << 13;
+ /* [12] jpeg_comp2_en */
+ data32 |= 1 << 12;
+ /* [11] jpeg_quant_sel_comp1 */
+ data32 |= ((q_sel_comp1 == q_sel_comp0) ? 0 : 1) << 11;
+ /* [10] jpeg_v_factor_comp1 */
+ data32 |= v_factor_comp1 << 10;
+ /* [9] jpeg_h_factor_comp1 */
+ data32 |= h_factor_comp1 << 9;
+ /* [8] jpeg_comp1_en */
+ data32 |= 1 << 8;
+ /* [7] jpeg_quant_sel_comp0 */
+ data32 |= 0 << 7;
+ /* [6] jpeg_v_factor_comp0 */
+ data32 |= v_factor_comp0 << 6;
+ /* [5] jpeg_h_factor_comp0 */
+ data32 |= h_factor_comp0 << 5;
+ /* [4] jpeg_comp0_en */
+ data32 |= 1 << 4;
+ /* [3:1] jdct_intr_sel:0=Disable intr; */
+ /* 1=Intr at end of each 8x8 block of DCT input; */
+ /* 2=Intr at end of each MCU of DCT input; */
+ /* 3=Intr at end of a scan of DCT input; */
+ /* 4=Intr at end of each 8x8 block of DCT output; */
+ /* 5=Intr at end of each MCU of DCT output; */
+ /* 6=Intr at end of a scan of DCT output. */
+ data32 |= jdct_intr_sel << 1;
+ /* [0] jpeg_en */
+ data32 |= 1 << 0;
+ WRITE_HREG(HCODEC_QDCT_JPEG_CTRL, data32);
+
+ data32 = 0;
+ /* [29] jpeg_comp2_ac_table_sel */
+ /*
+ data32 |= ((ac_huff_sel_comp2 == ac_huff_sel_comp0) ? 0 : 1 << 29;
+ */
+ data32 |= 1 << 29;
+ /* [28] jpeg_comp2_dc_table_sel */
+ /*
+ data32 |= ((dc_huff_sel_comp2 == dc_huff_sel_comp0) ? 0 : 1) << 28;
+ */
+ data32 |= 1 << 28;
+ /* [26:25] jpeg_comp2_cnt_max */
+ data32 |= ((h_factor_comp2 + 1) * (v_factor_comp2 + 1) - 1) << 25;
+ /* [24] jpeg_comp2_en */
+ data32 |= 1 << 24;
+ /* [21] jpeg_comp1_ac_table_sel */
+ /*
+ data32 |= ((ac_huff_sel_comp1 == ac_huff_sel_comp0) ? 0 : 1) << 21;
+ */
+ data32 |= 1 << 21;
+ /* [20] jpeg_comp1_dc_table_sel */
+ /*
+ data32 |= ((dc_huff_sel_comp1 == dc_huff_sel_comp0) ? 0 : 1) << 20;
+ */
+ data32 |= 1 << 20;
+ /* [18:17] jpeg_comp1_cnt_max */
+ data32 |= ((h_factor_comp1 + 1) * (v_factor_comp1 + 1) - 1) << 17;
+ /* [16] jpeg_comp1_en */
+ data32 |= 1 << 16;
+ /* [13] jpeg_comp0_ac_table_sel */
+ data32 |= 0 << 13;
+ /* [12] jpeg_comp0_dc_table_sel */
+ data32 |= 0 << 12;
+ /* [10:9] jpeg_comp0_cnt_max */
+ data32 |= ((h_factor_comp0 + 1) * (v_factor_comp0 + 1) - 1) << 9;
+ /* [8] jpeg_comp0_en */
+ data32 |= 1 << 8;
+ /* [0] jpeg_en, will be enbled by amrisc */
+ data32 |= 0 << 0;
+ WRITE_HREG(HCODEC_VLC_JPEG_CTRL, data32);
+
+ WRITE_HREG(HCODEC_QDCT_MB_CONTROL,
+ (1 << 9) | /* mb_info_soft_reset */
+ (1 << 0)); /* mb read buffer soft reset */
+
+ WRITE_HREG(HCODEC_QDCT_MB_CONTROL,
+ (0 << 28) | /* ignore_t_p8x8 */
+ (0 << 27) | /* zero_mc_out_null_non_skipped_mb */
+ (0 << 26) | /* no_mc_out_null_non_skipped_mb */
+ (0 << 25) | /* mc_out_even_skipped_mb */
+ (0 << 24) | /* mc_out_wait_cbp_ready */
+ (0 << 23) | /* mc_out_wait_mb_type_ready */
+ (0 << 29) | /* ie_start_int_enable */
+ (0 << 19) | /* i_pred_enable */
+ (0 << 20) | /* ie_sub_enable */
+ (0 << 18) | /* iq_enable */
+ (0 << 17) | /* idct_enable */
+ (0 << 14) | /* mb_pause_enable */
+ (1 << 13) | /* q_enable */
+ (1 << 12) | /* dct_enable */
+ (0 << 10) | /* mb_info_en */
+ (0 << 3) | /* endian */
+ (0 << 1) | /* mb_read_en */
+ (0 << 0)); /* soft reset */
+
+ /* Assember JPEG file header */
+ prepare_jpeg_header(wq);
+}
+
+static void jpegenc_init_output_buffer(struct jpegenc_wq_s *wq)
+{
+ WRITE_HREG(HCODEC_VLC_VB_MEM_CTL,
+ ((1 << 31) | (0x3f << 24) |
+ (0x20 << 16) | (2 << 0)));
+ WRITE_HREG(HCODEC_VLC_VB_START_PTR,
+ wq->BitstreamStart);
+ WRITE_HREG(HCODEC_VLC_VB_WR_PTR,
+ wq->BitstreamStart);
+ WRITE_HREG(HCODEC_VLC_VB_SW_RD_PTR,
+ wq->BitstreamStart);
+ WRITE_HREG(HCODEC_VLC_VB_END_PTR,
+ wq->BitstreamEnd);
+ WRITE_HREG(HCODEC_VLC_VB_CONTROL, 1);
+ WRITE_HREG(HCODEC_VLC_VB_CONTROL,
+ ((0 << 14) | (7 << 3) |
+ (1 << 1) | (0 << 0)));
+}
+
+static void jpegenc_buffspec_init(struct jpegenc_wq_s *wq)
+{
+ /* input dct buffer config */
+ wq->InputBuffStart = wq->buf_start +
+ gJpegenc.mem.bufspec->input.buf_start;
+ wq->InputBuffEnd = wq->InputBuffStart +
+ gJpegenc.mem.bufspec->input.buf_size - 1;
+ jenc_pr(LOG_INFO, "InputBuffStart is 0x%x\n", wq->InputBuffStart);
+
+ /* assit stream buffer config */
+ //wq->AssitStart = wq->buf_start + gJpegenc.mem.bufspec->assit.buf_start;
+ //wq->AssitEnd = wq->BitstreamStart + gJpegenc.mem.bufspec->assit.buf_size - 1;
+ wq->AssitStart = wq->buf_start + gJpegenc.mem.bufspec->assit.buf_start;
+ wq->AssitEnd = wq->AssitStart + gJpegenc.mem.bufspec->assit.buf_size - 1;
+ /* output stream buffer config */
+ wq->BitstreamStart = wq->buf_start +
+ gJpegenc.mem.bufspec->bitstream.buf_start;
+ wq->BitstreamEnd = wq->BitstreamStart +
+ gJpegenc.mem.bufspec->bitstream.buf_size - 1;
+ jenc_pr(LOG_INFO, "BitstreamStart is 0x%x\n", wq->BitstreamStart);
+
+#if 0
+ wq->AssitstreamStartVirtAddr = phys_to_virt(wq->AssitStart);
+#else
+ wq->AssitstreamStartVirtAddr =
+ codec_mm_vmap(wq->AssitStart, (wq->AssitEnd - wq->AssitStart + 1));
+#endif
+ //jenc_pr(LOG_ERROR, "[%s:%d], (wq->AssitEnd - wq->AssitStart + 1)=%d\n",
+ //__FUNCTION__, __LINE__, (wq->AssitEnd - wq->AssitStart + 1));
+ jenc_pr(LOG_ERROR, "AssitstreamStartVirtAddr is %p\n",
+ wq->AssitstreamStartVirtAddr);
+}
+
+/* for temp */
+#define HCODEC_MFDIN_REGC_MBLP (HCODEC_MFDIN_REGB_AMPC + 0x1)
+#define HCODEC_MFDIN_REG0D (HCODEC_MFDIN_REGB_AMPC + 0x2)
+#define HCODEC_MFDIN_REG0E (HCODEC_MFDIN_REGB_AMPC + 0x3)
+#define HCODEC_MFDIN_REG0F (HCODEC_MFDIN_REGB_AMPC + 0x4)
+#define HCODEC_MFDIN_REG10 (HCODEC_MFDIN_REGB_AMPC + 0x5)
+#define HCODEC_MFDIN_REG11 (HCODEC_MFDIN_REGB_AMPC + 0x6)
+#define HCODEC_MFDIN_REG12 (HCODEC_MFDIN_REGB_AMPC + 0x7)
+#define HCODEC_MFDIN_REG13 (HCODEC_MFDIN_REGB_AMPC + 0x8)
+#define HCODEC_MFDIN_REG14 (HCODEC_MFDIN_REGB_AMPC + 0x9)
+#define HCODEC_MFDIN_REG15 (HCODEC_MFDIN_REGB_AMPC + 0xa)
+#define HCODEC_MFDIN_REG16 (HCODEC_MFDIN_REGB_AMPC + 0xb)
+
+static void mfdin_basic_jpeg(
+ u32 input, u8 iformat, u8 oformat, u32 picsize_x,
+ u32 picsize_y, u8 r2y_en, u8 ifmt_extra)
+{
+ u8 dsample_en; /* Downsample Enable */
+ u8 interp_en; /* Interpolation Enable */
+ u8 y_size; /* 0:16 Pixels for y direction pickup; 1:8 pixels */
+ u8 r2y_mode; /* RGB2YUV Mode, range(0~3) */
+ /* mfdin_reg3_canv[25:24]; */
+ /* bytes per pixel in x direction for index0, 0:half 1:1 2:2 3:3 */
+ u8 canv_idx0_bppx;
+ /* mfdin_reg3_canv[27:26]; */
+ /* bytes per pixel in x direction for index1-2, 0:half 1:1 2:2 3:3 */
+ u8 canv_idx1_bppx;
+ /* mfdin_reg3_canv[29:28]; */
+ /* bytes per pixel in y direction for index0, 0:half 1:1 2:2 3:3 */
+ u8 canv_idx0_bppy;
+ /* mfdin_reg3_canv[31:30]; */
+ /* bytes per pixel in y direction for index1-2, 0:half 1:1 2:2 3:3 */
+ u8 canv_idx1_bppy;
+ u8 ifmt444, ifmt422, ifmt420, linear_bytes4p;
+ u32 linear_bytesperline;
+ bool linear_enable = false;
+ s32 reg_offset;
+ bool format_err = false;
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_TXL) {
+ if ((iformat == 7) && (ifmt_extra > 2))
+ format_err = true;
+ } else if (iformat == 7)
+ format_err = true;
+
+ if (format_err) {
+ jenc_pr(LOG_ERROR,
+ "mfdin format err, iformat:%d, ifmt_extra:%d\n",
+ iformat, ifmt_extra);
+ return;
+ }
+ if (iformat != 7)
+ ifmt_extra = 0;
+
+ ifmt444 = ((iformat == 1) || (iformat == 5) || (iformat == 8)
+ || (iformat == 9) || (iformat == 12)) ? 1 : 0;
+ if (iformat == 7 && ifmt_extra == 1)
+ ifmt444 = 1;
+ ifmt422 = ((iformat == 0) || (iformat == 10)) ? 1 : 0;
+ if (iformat == 7 && ifmt_extra != 1)
+ ifmt422 = 1;
+ ifmt420 = ((iformat == 2) || (iformat == 3) || (iformat == 4)
+ || (iformat == 11)) ? 1 : 0;
+ dsample_en = ((ifmt444 && (oformat != 2))
+ || (ifmt422 && (oformat == 0))) ? 1 : 0;
+ interp_en = ((ifmt422 && (oformat == 2))
+ || (ifmt420 && (oformat != 0))) ? 1 : 0;
+ y_size = (oformat != 0) ? 1 : 0;
+ /* r2y_mode = (r2y_en == 1) ? 1 : 0; */
+ r2y_mode = 1;
+ canv_idx0_bppx = (iformat == 1) ? 3 : (iformat == 0) ? 2 : 1;
+ canv_idx1_bppx = (iformat == 4) ? 0 : 1;
+ canv_idx0_bppy = 1;
+ canv_idx1_bppy = (iformat == 5) ? 1 : 0;
+ if ((iformat == 8) || (iformat == 9) || (iformat == 12))
+ linear_bytes4p = 3;
+ else if (iformat == 10)
+ linear_bytes4p = 2;
+ else if (iformat == 11)
+ linear_bytes4p = 1;
+ else
+ linear_bytes4p = 0;
+ linear_bytesperline = picsize_x * linear_bytes4p;
+
+ if (iformat < 8)
+ linear_enable = false;
+ else
+ linear_enable = true;
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXBB) {
+ reg_offset = -8;
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+ WRITE_HREG((HCODEC_MFDIN_REG8_DMBL + reg_offset),
+ (picsize_x << 16) | (picsize_y << 0));
+ } else {
+ WRITE_HREG((HCODEC_MFDIN_REG8_DMBL + reg_offset),
+ (picsize_x << 14) | (picsize_y << 0));
+ }
+ } else {
+ reg_offset = 0;
+ WRITE_HREG((HCODEC_MFDIN_REG8_DMBL + reg_offset),
+ (picsize_x << 12) | (picsize_y << 0));
+ }
+
+ WRITE_HREG((HCODEC_MFDIN_REG1_CTRL + reg_offset),
+ (iformat << 0) | (oformat << 4) |
+ (dsample_en << 6) | (y_size << 8) |
+ (interp_en << 9) | (r2y_en << 12) |
+ (r2y_mode << 13) | (ifmt_extra << 16) |
+ (2 << 29));
+
+ if (linear_enable == false) {
+ WRITE_HREG((HCODEC_MFDIN_REG3_CANV + reg_offset),
+ (input & 0xffffff) |
+ (canv_idx1_bppy << 30) |
+ (canv_idx0_bppy << 28) |
+ (canv_idx1_bppx << 26) |
+ (canv_idx0_bppx << 24));
+ WRITE_HREG((HCODEC_MFDIN_REG4_LNR0 + reg_offset),
+ (0 << 16) | (0 << 0));
+ WRITE_HREG((HCODEC_MFDIN_REG5_LNR1 + reg_offset), 0);
+ } else {
+ WRITE_HREG((HCODEC_MFDIN_REG3_CANV + reg_offset),
+ (canv_idx1_bppy << 30) |
+ (canv_idx0_bppy << 28) |
+ (canv_idx1_bppx << 26) |
+ (canv_idx0_bppx << 24));
+ WRITE_HREG((HCODEC_MFDIN_REG4_LNR0 + reg_offset),
+ (linear_bytes4p << 16) | (linear_bytesperline << 0));
+ WRITE_HREG((HCODEC_MFDIN_REG5_LNR1 + reg_offset), input);
+ }
+
+ WRITE_HREG((HCODEC_MFDIN_REG9_ENDN + reg_offset),
+ (7 << 0) | (6 << 3) | (5 << 6) |
+ (4 << 9) | (3 << 12) | (2 << 15) |
+ (1 << 18) | (0 << 21));
+ return;
+}
+
+static s32 set_jpeg_input_format(struct jpegenc_wq_s *wq,
+ struct jpegenc_request_s *cmd)
+{
+ s32 ret = 0;
+ u8 iformat = JPEGENC_MAX_FRAME_FMT;
+ u8 oformat = JPEGENC_MAX_FRAME_FMT;
+ u8 r2y_en = 0;
+ u32 picsize_x, picsize_y;
+ u32 canvas_w = 0;
+ u32 input = cmd->src;
+ u8 ifmt_extra = 0;
+
+ jenc_pr(LOG_INFO, "************begin set input format**************\n");
+ jenc_pr(LOG_INFO, "type is %d\n", cmd->type);
+ jenc_pr(LOG_INFO, "input_fmt is %d\n", cmd->input_fmt);
+ jenc_pr(LOG_INFO, "output_fmt is %d\n", cmd->output_fmt);
+ jenc_pr(LOG_INFO, "input is 0x%x\n", cmd->src);
+ jenc_pr(LOG_INFO, "size is %d\n", cmd->framesize);
+ jenc_pr(LOG_INFO, "quality is %d\n", cmd->jpeg_quality);
+ jenc_pr(LOG_INFO, "quant tbl_id is %d\n", cmd->QuantTable_id);
+ jenc_pr(LOG_INFO, "flush flag is %d\n", cmd->flush_flag);
+ jenc_pr(LOG_INFO, "************end set input format**************\n");
+
+ if ((cmd->input_fmt == JPEGENC_FMT_RGB565)
+ || (cmd->input_fmt >= JPEGENC_MAX_FRAME_FMT))
+ return -1;
+
+ picsize_x = ((cmd->encoder_width + 15) >> 4) << 4;
+ picsize_y = ((cmd->encoder_height + 15) >> 4) << 4;
+ if (cmd->output_fmt == JPEGENC_FMT_YUV422_SINGLE)
+ oformat = 1;
+ else
+ oformat = 0;
+ if ((cmd->type == JPEGENC_LOCAL_BUFF) ||
+ (cmd->type == JPEGENC_PHYSICAL_BUFF)) {
+ if (cmd->type == JPEGENC_LOCAL_BUFF) {
+ if (cmd->flush_flag & JPEGENC_FLUSH_FLAG_INPUT)
+ dma_flush(wq->InputBuffStart,
+ cmd->framesize);
+ input = wq->InputBuffStart;
+ }
+ if ((cmd->input_fmt <= JPEGENC_FMT_YUV444_PLANE) ||
+ (cmd->input_fmt >= JPEGENC_FMT_YUV422_12BIT))
+ r2y_en = 0;
+ else
+ r2y_en = 1;
+
+ if (cmd->input_fmt >= JPEGENC_FMT_YUV422_12BIT) {
+ iformat = 7;
+ ifmt_extra =
+ cmd->input_fmt - JPEGENC_FMT_YUV422_12BIT;
+ if (cmd->input_fmt == JPEGENC_FMT_YUV422_12BIT)
+ canvas_w = picsize_x * 24 / 8;
+ else if (cmd->input_fmt == JPEGENC_FMT_YUV444_10BIT)
+ canvas_w = picsize_x * 32 / 8;
+ else
+ canvas_w = (picsize_x * 20 + 7) / 8;
+ canvas_w = ((canvas_w + 31) >> 5) << 5;
+ canvas_config(ENC_CANVAS_OFFSET,
+ input,
+ canvas_w, picsize_y,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ input = ENC_CANVAS_OFFSET;
+ input = input & 0xff;
+ } else if (cmd->input_fmt == JPEGENC_FMT_YUV422_SINGLE) {
+ iformat = 0;
+ canvas_w = picsize_x * 2;
+ canvas_w = ((canvas_w + 31) >> 5) << 5;
+ canvas_config(ENC_CANVAS_OFFSET,
+ input,
+ canvas_w, picsize_y,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ input = ENC_CANVAS_OFFSET;
+ } else if ((cmd->input_fmt == JPEGENC_FMT_YUV444_SINGLE)
+ || (cmd->input_fmt == JPEGENC_FMT_RGB888)) {
+ iformat = 1;
+ if (cmd->input_fmt == JPEGENC_FMT_RGB888)
+ r2y_en = 1;
+ canvas_w = picsize_x * 3;
+ canvas_w = ((canvas_w + 31) >> 5) << 5;
+ canvas_config(ENC_CANVAS_OFFSET,
+ input,
+ canvas_w, picsize_y,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ input = ENC_CANVAS_OFFSET;
+ } else if ((cmd->input_fmt == JPEGENC_FMT_NV21)
+ || (cmd->input_fmt == JPEGENC_FMT_NV12)) {
+ canvas_w = ((cmd->encoder_width + 31) >> 5) << 5;
+ iformat = (cmd->input_fmt == JPEGENC_FMT_NV21) ? 2 : 3;
+ canvas_config(ENC_CANVAS_OFFSET,
+ input,
+ canvas_w, picsize_y,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+
+ canvas_config(ENC_CANVAS_OFFSET + 1,
+ input + canvas_w * picsize_y, canvas_w,
+ picsize_y / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+
+ input = ((ENC_CANVAS_OFFSET + 1) << 8) | ENC_CANVAS_OFFSET;
+ } else if (cmd->input_fmt == JPEGENC_FMT_YUV420) {
+ iformat = 4;
+ canvas_w = ((cmd->encoder_width + 63) >> 6) << 6;
+ canvas_config(ENC_CANVAS_OFFSET,
+ input,
+ canvas_w, picsize_y,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config(ENC_CANVAS_OFFSET + 2,
+ input + canvas_w * picsize_y,
+ canvas_w / 2, picsize_y / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config(ENC_CANVAS_OFFSET + 2,
+ input + canvas_w * picsize_y * 5 / 4,
+ canvas_w / 2, picsize_y / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ input = ((ENC_CANVAS_OFFSET + 2) << 16) |
+ ((ENC_CANVAS_OFFSET + 1) << 8) |
+ ENC_CANVAS_OFFSET;
+ } else if ((cmd->input_fmt == JPEGENC_FMT_YUV444_PLANE)
+ || (cmd->input_fmt == JPEGENC_FMT_RGB888_PLANE)) {
+ iformat = 5;
+ if (cmd->input_fmt == JPEGENC_FMT_RGB888_PLANE)
+ r2y_en = 1;
+ canvas_w = ((cmd->encoder_width + 31) >> 5) << 5;
+ canvas_config(ENC_CANVAS_OFFSET,
+ input,
+ canvas_w, picsize_y,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config(ENC_CANVAS_OFFSET + 1,
+ input + canvas_w * picsize_y, canvas_w,
+ picsize_y, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config(ENC_CANVAS_OFFSET + 2,
+ input + canvas_w * picsize_y * 2,
+ canvas_w, picsize_y, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ input = ((ENC_CANVAS_OFFSET + 2) << 16) |
+ ((ENC_CANVAS_OFFSET + 1) << 8) |
+ ENC_CANVAS_OFFSET;
+ } else if (cmd->input_fmt == JPEGENC_FMT_RGBA8888) {
+ iformat = 12;
+ r2y_en = 1;
+ }
+ ret = 0;
+ } else if (cmd->type == JPEGENC_CANVAS_BUFF) {
+ r2y_en = 0;
+ if (cmd->input_fmt == JPEGENC_FMT_YUV422_SINGLE) {
+ iformat = 0;
+ input = input & 0xff;
+ } else if (cmd->input_fmt == JPEGENC_FMT_YUV444_SINGLE) {
+ iformat = 1;
+ input = input & 0xff;
+ } else if ((cmd->input_fmt == JPEGENC_FMT_NV21)
+ || (cmd->input_fmt == JPEGENC_FMT_NV12)) {
+ iformat = (cmd->input_fmt == JPEGENC_FMT_NV21) ? 2 : 3;
+ input = input & 0xffff;
+ } else if (cmd->input_fmt == JPEGENC_FMT_YUV420) {
+ iformat = 4;
+ input = input & 0xffffff;
+ } else if ((cmd->input_fmt == JPEGENC_FMT_YUV444_PLANE)
+ || (cmd->input_fmt == JPEGENC_FMT_RGB888_PLANE)) {
+ if (cmd->input_fmt == JPEGENC_FMT_RGB888_PLANE)
+ r2y_en = 1;
+ iformat = 5;
+ input = input & 0xffffff;
+ } else if ((cmd->input_fmt == JPEGENC_FMT_YUV422_12BIT)
+ || (cmd->input_fmt == JPEGENC_FMT_YUV444_10BIT)
+ || (cmd->input_fmt == JPEGENC_FMT_YUV422_10BIT)) {
+ iformat = 7;
+ ifmt_extra = cmd->input_fmt - JPEGENC_FMT_YUV422_12BIT;
+ input = input & 0xff;
+ } else
+ ret = -1;
+ }
+ if (ret == 0)
+ mfdin_basic_jpeg(input, iformat, oformat,
+ picsize_x, picsize_y, r2y_en, ifmt_extra);
+ return ret;
+}
+
+static void jpegenc_isr_tasklet(ulong data)
+{
+ struct jpegenc_manager_s *manager = (struct jpegenc_manager_s *)data;
+ jenc_pr(LOG_INFO, "encoder is done %d\n", manager->encode_hw_status);
+ if ((manager->encode_hw_status == JPEGENC_ENCODER_DONE)
+ && (manager->process_irq)) {
+ manager->wq.hw_status = manager->encode_hw_status;
+ manager->wq.output_size = READ_HREG(HCODEC_VLC_TOTAL_BYTES);
+ jenc_pr(LOG_INFO, "encoder size %d\n", manager->wq.output_size);
+ atomic_inc(&manager->wq.ready);
+ wake_up_interruptible(&manager->wq.complete);
+ }
+}
+
+static irqreturn_t jpegenc_isr(s32 irq_number, void *para)
+{
+ struct jpegenc_manager_s *manager = (struct jpegenc_manager_s *)para;
+ jenc_pr(LOG_INFO, "*****JPEGENC_ISR*****");
+ WRITE_HREG(HCODEC_ASSIST_MBOX2_CLR_REG, 1);
+ manager->encode_hw_status = READ_HREG(JPEGENC_ENCODER_STATUS);
+ if (manager->encode_hw_status == JPEGENC_ENCODER_DONE) {
+ manager->process_irq = true;
+ tasklet_schedule(&manager->tasklet);
+ }
+ return IRQ_HANDLED;
+}
+
+static void jpegenc_start(void)
+{
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+ WRITE_VREG(DOS_SW_RESET1, (1 << 12) | (1 << 11));
+ WRITE_VREG(DOS_SW_RESET1, 0);
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXBB)
+ WRITE_HREG((HCODEC_MFDIN_REG7_SCMD - 8), (1 << 28)),
+
+ WRITE_HREG(HCODEC_MPSR, 0x0001);
+}
+
+static void _jpegenc_stop(void)
+{
+ ulong timeout = jiffies + HZ;
+
+ WRITE_HREG(HCODEC_MPSR, 0);
+ WRITE_HREG(HCODEC_CPSR, 0);
+ while (READ_HREG(HCODEC_IMEM_DMA_CTRL) & 0x8000) {
+ if (time_after(jiffies, timeout))
+ break;
+ }
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXBB)
+ WRITE_VREG(DOS_SW_RESET1,
+ (1 << 12) | (1 << 11) |
+ (1 << 2) | (1 << 6) |
+ (1 << 7) | (1 << 8) |
+ (1 << 14) | (1 << 16) |
+ (1 << 17));
+ else
+ WRITE_VREG(DOS_SW_RESET1,
+ (1 << 12) | (1 << 11) |
+ (1 << 2) | (1 << 6) |
+ (1 << 7) | (1 << 8) |
+ (1 << 16) | (1 << 17));
+
+ WRITE_VREG(DOS_SW_RESET1, 0);
+
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+}
+
+static void __iomem *mc_addr;
+static u32 mc_addr_map;
+#define MC_SIZE (4096 * 4)
+s32 jpegenc_loadmc(const char *p)
+{
+ ulong timeout;
+ s32 ret = 0;
+
+ /* use static mempry*/
+ if (mc_addr == NULL) {
+ mc_addr = kmalloc(MC_SIZE, GFP_KERNEL);
+ if (!mc_addr) {
+ jenc_pr(LOG_ERROR,
+ "jpegenc loadmc iomap mc addr error.\n");
+ return -ENOMEM;
+ }
+ }
+
+#ifdef KER49
+ ret = get_decoder_firmware_data(VFORMAT_JPEG_ENC, p,
+ (u8 *)mc_addr, MC_SIZE);
+#else
+ ret = get_data_from_name(p, (u8 *)mc_addr);
+#endif
+ if (ret < 0) {
+ jenc_pr(LOG_ERROR,
+ "jpegenc microcode fail ret=%d, name: %s.\n",
+ ret, p);
+ }
+
+ mc_addr_map = dma_map_single(
+ &gJpegenc.this_pdev->dev,
+ mc_addr, MC_SIZE, DMA_TO_DEVICE);
+
+ WRITE_HREG(HCODEC_MPSR, 0);
+ WRITE_HREG(HCODEC_CPSR, 0);
+
+ /* Read CBUS register for timing */
+ timeout = READ_HREG(HCODEC_MPSR);
+ timeout = READ_HREG(HCODEC_MPSR);
+
+ timeout = jiffies + HZ;
+
+ WRITE_HREG(HCODEC_IMEM_DMA_ADR, mc_addr_map);
+ WRITE_HREG(HCODEC_IMEM_DMA_COUNT, 0x1000);
+ WRITE_HREG(HCODEC_IMEM_DMA_CTRL, (0x8000 | (7 << 16)));
+
+ while (READ_HREG(HCODEC_IMEM_DMA_CTRL) & 0x8000) {
+ if (time_before(jiffies, timeout))
+ schedule();
+ else {
+ jenc_pr(LOG_ERROR, "hcodec load mc error\n");
+ ret = -EBUSY;
+ break;
+ }
+ }
+
+ dma_unmap_single(
+ &gJpegenc.this_pdev->dev,
+ mc_addr_map, MC_SIZE, DMA_TO_DEVICE);
+ return ret;
+}
+
+/*
+bool jpegenc_on(void)
+{
+ bool hcodec_on;
+ ulong flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ hcodec_on = vdec_on(VDEC_HCODEC);
+ hcodec_on &= (gJpegenc.opened > 0);
+
+ spin_unlock_irqrestore(&lock, flags);
+ return hcodec_on;
+}
+*/
+static s32 jpegenc_poweron(u32 clock)
+{
+ ulong flags;
+ u32 data32;
+
+ data32 = 0;
+
+ amports_switch_gate("vdec", 1);
+
+ spin_lock_irqsave(&lock, flags);
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+ jpegenc_clk_config(1);
+
+ pwr_ctrl_psci_smc(PDID_DOS_HCODEC, PWR_ON);
+
+ //hvdec_clock_enable(clock);
+ } else if (get_cpu_type() >= MESON_CPU_MAJOR_ID_M8) {
+ WRITE_AOREG(AO_RTI_PWR_CNTL_REG0,
+ (READ_AOREG(AO_RTI_PWR_CNTL_REG0) & (~0x18)));
+ udelay(10);
+ /* Powerup HCODEC */
+ /* [1:0] HCODEC */
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) &
+ ((get_cpu_type() == MESON_CPU_MAJOR_ID_SM1 ||
+ get_cpu_type() >= MESON_CPU_MAJOR_ID_TM2)
+ ? ~0x1 : ~0x3));
+ udelay(10);
+ }
+
+ WRITE_VREG(DOS_SW_RESET1, 0xffffffff);
+ WRITE_VREG(DOS_SW_RESET1, 0);
+
+ /* Enable Dos internal clock gating */
+ jpegenc_clock_enable(clock);
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_M8) {
+ /* Powerup HCODEC memories */
+ WRITE_VREG(DOS_MEM_PD_HCODEC, 0x0);
+
+ /* Remove HCODEC ISO */
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) &
+ ((get_cpu_type() == MESON_CPU_MAJOR_ID_SM1 ||
+ get_cpu_type() >= MESON_CPU_MAJOR_ID_TM2)
+ ? ~0x1 : ~0x30));
+ udelay(10);
+ }
+ /* Disable auto-clock gate */
+ WRITE_VREG(DOS_GEN_CTRL0, (READ_VREG(DOS_GEN_CTRL0) | 0x1));
+ WRITE_VREG(DOS_GEN_CTRL0, (READ_VREG(DOS_GEN_CTRL0) & 0xFFFFFFFE));
+
+ spin_unlock_irqrestore(&lock, flags);
+
+ mdelay(10);
+ return 0;
+}
+
+static s32 jpegenc_poweroff(void)
+{
+ ulong flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+ jpegenc_clk_config(0);
+ pwr_ctrl_psci_smc(PDID_DOS_HCODEC, PWR_OFF);
+ //hvdec_clock_disable();
+ LOG_LINE();
+ } else if (get_cpu_type() >= MESON_CPU_MAJOR_ID_M8) {
+ /* enable HCODEC isolation */
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) | 0x30);
+ /* power off HCODEC memories */
+ WRITE_VREG(DOS_MEM_PD_HCODEC, 0xffffffffUL);
+ }
+ /* disable HCODEC clock */
+ jpegenc_clock_disable();
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_M8) {
+ /* HCODEC power off */
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | 0x3);
+ }
+
+ spin_unlock_irqrestore(&lock, flags);
+
+ /* release DOS clk81 clock gating */
+ amports_switch_gate("vdec", 0);
+ return 0;
+}
+
+void jpegenc_reset(void)
+{
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXBB)
+ WRITE_VREG(DOS_SW_RESET1,
+ (1 << 2) | (1 << 6) |
+ (1 << 7) | (1 << 8) |
+ (1 << 14) | (1 << 16) |
+ (1 << 17));
+ else
+ WRITE_VREG(DOS_SW_RESET1,
+ (1 << 2) | (1 << 6) | (1 << 7) |
+ (1 << 8) | (1 << 16) | (1 << 17));
+ WRITE_VREG(DOS_SW_RESET1, 0);
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+ READ_VREG(DOS_SW_RESET1);
+}
+
+static s32 jpegenc_init(void)
+{
+ jpegenc_poweron(clock_level);
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_MG9TV) {
+ WRITE_HREG(HCODEC_ASSIST_MMC_CTRL1, 0x32);
+ } else {
+ WRITE_HREG(HCODEC_ASSIST_MMC_CTRL1, 0x2);
+ }
+
+ jenc_pr(LOG_ALL, "start to load microcode: %s\n", jpegenc_ucode[0]);
+ if (jpegenc_loadmc(jpegenc_ucode[0]) < 0)
+ return -EBUSY;
+
+ jenc_pr(LOG_ALL, "succeed to load microcode\n");
+ gJpegenc.process_irq = false;
+
+ if (request_irq(gJpegenc.irq_num, jpegenc_isr, IRQF_SHARED,
+ "jpegenc-irq", (void *)&gJpegenc) == 0)
+ gJpegenc.irq_requested = true;
+ else
+ gJpegenc.irq_requested = false;
+
+ WRITE_HREG(JPEGENC_ENCODER_STATUS, JPEGENC_ENCODER_IDLE);
+
+ gJpegenc.inited = true;
+
+ return 0;
+}
+
+static s32 convert_cmd(struct jpegenc_wq_s *wq, u32 *cmd_info)
+{
+ if (!wq) {
+ jenc_pr(LOG_ERROR, "jpegenc convert_cmd error\n");
+ return -1;
+ }
+ memset(&wq->cmd, 0, sizeof(struct jpegenc_request_s));
+ wq->cmd.type = cmd_info[0];
+ wq->cmd.input_fmt = cmd_info[1];
+ wq->cmd.output_fmt = cmd_info[2];
+ wq->cmd.encoder_width = cmd_info[3];
+ wq->cmd.encoder_height = cmd_info[4];
+ wq->cmd.framesize = cmd_info[5];
+ wq->cmd.src = cmd_info[6];
+ wq->cmd.jpeg_quality = cmd_info[7];
+ wq->cmd.QuantTable_id = cmd_info[8];
+ wq->cmd.flush_flag = cmd_info[9];
+ if ((wq->cmd.encoder_width > wq->max_width) ||
+ (wq->cmd.encoder_height > wq->max_height)) {
+ jenc_pr(LOG_ERROR,
+ "set encode size %dx%d is larger than supported (%dx%d).\n",
+ wq->cmd.encoder_width,
+ wq->cmd.encoder_height,
+ wq->max_width,
+ wq->max_height);
+ return -1;
+ }
+ wq->cmd.jpeg_quality = jpeg_quality_scaling((s32)cmd_info[7]);
+ if (wq->cmd.QuantTable_id < 4) {
+ jenc_pr(LOG_INFO,
+ "JPEGENC_SEL_QUANT_TABLE : %d.\n",
+ wq->cmd.QuantTable_id);
+ } else {
+ wq->cmd.QuantTable_id = 0;
+ jenc_pr(LOG_ERROR,
+ "JPEGENC_SEL_QUANT_TABLE invaild. target value: %d.\n",
+ cmd_info[8]);
+ }
+ jenc_pr(LOG_INFO,
+ "target quality : %d, jpeg_quality value: %d.\n",
+ cmd_info[7], wq->cmd.jpeg_quality);
+ return 0;
+}
+
+static void jpegenc_start_cmd(struct jpegenc_wq_s *wq)
+{
+ gJpegenc.process_irq = false;
+ gJpegenc.encode_hw_status = JPEGENC_ENCODER_IDLE;
+
+ jpegenc_reset();
+ set_jpeg_input_format(wq, &wq->cmd);
+
+ init_jpeg_encoder(wq);
+ jpegenc_init_output_buffer(wq);
+ /* clear mailbox interrupt */
+ WRITE_HREG(HCODEC_ASSIST_MBOX2_CLR_REG, 1);
+
+ /* enable mailbox interrupt */
+ WRITE_HREG(HCODEC_ASSIST_MBOX2_MASK, 1);
+ gJpegenc.encode_hw_status = JPEGENC_ENCODER_IDLE;
+ WRITE_HREG(JPEGENC_ENCODER_STATUS, JPEGENC_ENCODER_IDLE);
+ gJpegenc.process_irq = false;
+ jpegenc_start();
+ jenc_pr(LOG_INFO, "jpegenc_start\n");
+}
+
+static void jpegenc_stop(void)
+{
+ if ((gJpegenc.irq_num >= 0) &&
+ (gJpegenc.irq_requested == true)) {
+ free_irq(gJpegenc.irq_num, &gJpegenc);
+ gJpegenc.irq_requested = false;
+ }
+ _jpegenc_stop();
+ jpegenc_poweroff();
+ jenc_pr(LOG_INFO, "jpegenc_stop\n");
+}
+
+static void dma_flush(u32 buf_start, u32 buf_size)
+{
+ dma_sync_single_for_device(&gJpegenc.this_pdev->dev,
+ buf_start, buf_size, DMA_TO_DEVICE);
+}
+
+static void cache_flush(u32 buf_start, u32 buf_size)
+{
+ dma_sync_single_for_cpu(&gJpegenc.this_pdev->dev,
+ buf_start, buf_size, DMA_FROM_DEVICE);
+}
+
+static s32 jpegenc_open(struct inode *inode, struct file *file)
+{
+ struct jpegenc_wq_s *wq;
+ s32 r;
+ jenc_pr(LOG_DEBUG, "jpegenc open\n");
+
+#ifdef CONFIG_AM_ENCODER
+ if (amvenc_avc_on() == true) {
+ jenc_pr(LOG_ERROR, "hcodec in use for AVC Encode now.\n");
+ return -EBUSY;
+ }
+#endif
+
+ file->private_data = NULL;
+
+ spin_lock(&gJpegenc.sem_lock);
+
+ if (gJpegenc.opened > 0) {
+ spin_unlock(&gJpegenc.sem_lock);
+ jenc_pr(LOG_ERROR, "jpegenc open busy.\n");
+ return -EBUSY;
+ }
+
+ wq = &gJpegenc.wq;
+ wq->buf_start = gJpegenc.mem.buf_start;
+ wq->buf_size = gJpegenc.mem.buf_size;
+ gJpegenc.opened++;
+ spin_unlock(&gJpegenc.sem_lock);
+#ifdef CONFIG_CMA
+ jenc_pr(LOG_ERROR, "use_reserve:%d, gJpegenc.mem.buf_sizea:%u\n",
+ gJpegenc.use_reserve, gJpegenc.mem.buf_size);
+
+ if (gJpegenc.use_reserve == false) {
+ /*wq->venc_pages = dma_alloc_from_contiguous(&gJpegenc.this_pdev->dev, gJpegenc.mem.buf_size >> PAGE_SHIFT, 0);
+ if (wq->venc_pages) {
+ wq->buf_start = page_to_phys(wq->venc_pages);
+ wq->buf_size = gJpegenc.mem.buf_size;
+ jenc_pr(LOG_DEBUG,
+ "allocating phys 0x%x, size %dk.\n",
+ wq->buf_start, wq->buf_size >> 10);
+ } else {
+ jenc_pr(LOG_ERROR,
+ "CMA failed to allocate dma buffer for %s.\n",
+ gJpegenc.this_pdev->name);
+ spin_lock(&gJpegenc.sem_lock);
+ gJpegenc.opened--;
+ spin_unlock(&gJpegenc.sem_lock);
+ return -ENOMEM;
+ }*/
+ wq->buf_start = codec_mm_alloc_for_dma(DRIVER_NAME, gJpegenc.mem.buf_size >> PAGE_SHIFT, 0, 0);
+
+ if (wq->buf_start) {
+ wq->buf_size = gJpegenc.mem.buf_size;
+
+ jenc_pr(LOG_ERROR,
+ "allocating phys 0x%x, sizeeee %dk\n",
+ wq->buf_start, wq->buf_size >> 10);//, codec_mm_vmap(wq->buf_start, wq->buf_size));
+ } else {
+ jenc_pr(LOG_ERROR,
+ "CMA failed to allocate dma buffer for %s.\n",
+ gJpegenc.this_pdev->name);
+ spin_lock(&gJpegenc.sem_lock);
+ gJpegenc.opened--;
+ spin_unlock(&gJpegenc.sem_lock);
+ return -ENOMEM;
+ }
+ }
+#endif
+
+ spin_lock(&gJpegenc.sem_lock);
+ init_waitqueue_head(&wq->complete);
+ atomic_set(&wq->ready, 0);
+ wq->AssitstreamStartVirtAddr = NULL;
+ memset(gQuantTable, 0, sizeof(gQuantTable));
+ wq->cmd.QuantTable_id = 0;
+ wq->cmd.jpeg_quality = 90;
+ wq->max_width = gJpegenc.mem.bufspec->max_width;
+ wq->max_height = gJpegenc.mem.bufspec->max_height;
+ wq->headbytes = 0;
+ file->private_data = (void *)wq;
+
+#ifdef EXTEAN_QUANT_TABLE
+ gExternalQuantTablePtr = NULL;
+ external_quant_table_available = false;
+#endif
+ spin_unlock(&gJpegenc.sem_lock);
+ r = 0;
+ return r;
+}
+
+static s32 jpegenc_release(struct inode *inode, struct file *file)
+{
+ struct jpegenc_wq_s *wq = (struct jpegenc_wq_s *)file->private_data;
+
+ if (wq != &gJpegenc.wq) {
+ jenc_pr(LOG_ERROR, "jpegenc release error\n");
+ return -1;
+ }
+ if (gJpegenc.inited) {
+ jpegenc_stop();
+ gJpegenc.inited = false;
+ }
+ memset(gQuantTable, 0, sizeof(gQuantTable));
+
+ if (wq->AssitstreamStartVirtAddr)
+ wq->AssitstreamStartVirtAddr = NULL;
+
+#ifdef CONFIG_CMA
+#if 0
+ if (wq->venc_pages) {
+ dma_release_from_contiguous(
+ &gJpegenc.this_pdev->dev,
+ wq->venc_pages,
+ wq->buf_size >> PAGE_SHIFT);
+ wq->venc_pages = NULL;
+ }
+#endif
+ if (wq->buf_start) {
+ wq->venc_pages = NULL;
+ codec_mm_free_for_dma(DRIVER_NAME, wq->buf_start);
+ jenc_pr(LOG_ERROR, "jpegenc release memory\n");
+ wq->buf_start = 0;
+ }
+#endif
+ wq->buf_start = 0;
+ wq->buf_size = 0;
+#ifdef EXTEAN_QUANT_TABLE
+ kfree(gExternalQuantTablePtr);
+ gExternalQuantTablePtr = NULL;
+ external_quant_table_available = false;
+#endif
+ spin_lock(&gJpegenc.sem_lock);
+ if (gJpegenc.opened > 0)
+ gJpegenc.opened--;
+ spin_unlock(&gJpegenc.sem_lock);
+ jenc_pr(LOG_DEBUG, "jpegenc release\n");
+ return 0;
+}
+
+static long jpegenc_ioctl(struct file *file, u32 cmd, ulong arg)
+{
+ long r = 0;
+ struct jpegenc_wq_s *wq = (struct jpegenc_wq_s *)file->private_data;
+#define MAX_ADDR_INFO_SIZE 30
+ u32 addr_info[MAX_ADDR_INFO_SIZE + 4];
+ switch (cmd) {
+ case JPEGENC_IOC_NEW_CMD:
+ if (copy_from_user(addr_info, (void *)arg,
+ MAX_ADDR_INFO_SIZE * sizeof(u32))) {
+ jenc_pr(LOG_ERROR,
+ "jpegenc get new cmd error.\n");
+ return -1;
+ }
+ if (!convert_cmd(wq, addr_info))
+ jpegenc_start_cmd(wq);
+ break;
+ case JPEGENC_IOC_GET_STAGE:
+ put_user(wq->hw_status, (u32 *)arg);
+ break;
+ case JPEGENC_IOC_GET_OUTPUT_SIZE:
+ cache_flush(wq->BitstreamStart, wq->output_size);
+ addr_info[0] = wq->headbytes;
+ addr_info[1] = wq->output_size;
+ r = copy_to_user((u32 *)arg, addr_info , 2 * sizeof(u32));
+ break;
+ case JPEGENC_IOC_CONFIG_INIT:
+ jpegenc_init();
+ jpegenc_buffspec_init(wq);
+ break;
+ case JPEGENC_IOC_GET_BUFFINFO:
+ addr_info[0] = gJpegenc.mem.buf_size;
+ addr_info[1] = gJpegenc.mem.bufspec->input.buf_start;
+ addr_info[2] = gJpegenc.mem.bufspec->input.buf_size;
+ addr_info[3] = gJpegenc.mem.bufspec->assit.buf_start;
+ addr_info[4] = gJpegenc.mem.bufspec->assit.buf_size;
+ addr_info[5] = gJpegenc.mem.bufspec->bitstream.buf_start;
+ addr_info[6] = gJpegenc.mem.bufspec->bitstream.buf_size;
+ r = copy_to_user((u32 *)arg, addr_info , 7 * sizeof(u32));
+
+ break;
+ case JPEGENC_IOC_GET_DEVINFO:
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXL) {
+ /* GXL send same id of GXTVBB to upper*/
+ r = copy_to_user((s8 *)arg, JPEGENC_DEVINFO_GXTVBB,
+ strlen(JPEGENC_DEVINFO_GXTVBB));
+ } else if (get_cpu_type() == MESON_CPU_MAJOR_ID_GXTVBB) {
+ r = copy_to_user((s8 *)arg, JPEGENC_DEVINFO_GXTVBB,
+ strlen(JPEGENC_DEVINFO_GXTVBB));
+ } else if (get_cpu_type() == MESON_CPU_MAJOR_ID_GXBB) {
+ r = copy_to_user((s8 *)arg, JPEGENC_DEVINFO_GXBB,
+ strlen(JPEGENC_DEVINFO_GXBB));
+ } else if (get_cpu_type() == MESON_CPU_MAJOR_ID_MG9TV) {
+ r = copy_to_user((s8 *)arg, JPEGENC_DEVINFO_G9,
+ strlen(JPEGENC_DEVINFO_G9));
+ } else {
+ r = copy_to_user((s8 *)arg, JPEGENC_DEVINFO_M8,
+ strlen(JPEGENC_DEVINFO_M8));
+ }
+ break;
+ case JPEGENC_IOC_SET_EXT_QUANT_TABLE:
+#ifdef EXTEAN_QUANT_TABLE
+ if (arg == 0) {
+ kfree(gExternalQuantTablePtr);
+ gExternalQuantTablePtr = NULL;
+ external_quant_table_available = false;
+ } else {
+ void __user *argp = (void __user *)arg;
+ gExternalQuantTablePtr =
+ kmalloc(sizeof(u16) * DCTSIZE2 * 2,
+ GFP_KERNEL);
+ if (gExternalQuantTablePtr) {
+ if (copy_from_user
+ (gExternalQuantTablePtr, argp,
+ sizeof(u16) * DCTSIZE2 * 2)) {
+ r = -1;
+ break;
+ }
+ external_quant_table_available = true;
+ r = 0;
+ } else {
+ jenc_pr(LOG_ERROR,
+ "gExternalQuantTablePtr malloc fail\n");
+ r = -1;
+ }
+ }
+#else
+ r = 0;
+#endif
+ break;
+ default:
+ r = -1;
+ break;
+ }
+ return r;
+}
+
+#ifdef CONFIG_COMPAT
+static long jpegenc_compat_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long args)
+{
+ unsigned long ret;
+
+ args = (unsigned long)compat_ptr(args);
+ ret = jpegenc_ioctl(filp, cmd, args);
+ return ret;
+}
+#endif
+
+static s32 jpegenc_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct jpegenc_wq_s *wq = (struct jpegenc_wq_s *)filp->private_data;
+ ulong off = vma->vm_pgoff << PAGE_SHIFT;
+ ulong vma_size = vma->vm_end - vma->vm_start;
+
+ if (vma_size == 0) {
+ jenc_pr(LOG_ERROR, "vma_size is 0\n");
+ return -EAGAIN;
+ }
+ off += wq->buf_start;
+ jenc_pr(LOG_INFO, "vma_size is %ld, off is %ld\n", vma_size, off);
+ vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP | VM_IO;
+ /* vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); */
+ if (remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
+ jenc_pr(LOG_ERROR, "set_cached: failed remap_pfn_range\n");
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+static u32 jpegenc_poll(struct file *file, poll_table *wait_table)
+{
+ struct jpegenc_wq_s *wq = (struct jpegenc_wq_s *)file->private_data;
+ poll_wait(file, &wq->complete, wait_table);
+
+ if (atomic_read(&wq->ready)) {
+ atomic_dec(&wq->ready);
+ return POLLIN | POLLRDNORM;
+ }
+ return 0;
+}
+
+static const struct file_operations jpegenc_fops = {
+ .owner = THIS_MODULE,
+ .open = jpegenc_open,
+ .mmap = jpegenc_mmap,
+ .release = jpegenc_release,
+ .unlocked_ioctl = jpegenc_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = jpegenc_compat_ioctl,
+#endif
+ .poll = jpegenc_poll,
+};
+
+static s32 jpegenc_wq_init(void)
+{
+ jenc_pr(LOG_DEBUG, "jpegenc_wq_init.\n");
+ gJpegenc.irq_requested = false;
+ gJpegenc.process_irq = false;
+ gJpegenc.inited = false;
+ gJpegenc.opened = 0;
+ gJpegenc.encode_hw_status = JPEGENC_ENCODER_IDLE;
+ spin_lock_init(&gJpegenc.sem_lock);
+
+ tasklet_init(&gJpegenc.tasklet,
+ jpegenc_isr_tasklet,
+ (ulong)&gJpegenc);
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXBB)
+ clock_level = 5;
+ else if (get_cpu_type() >= MESON_CPU_MAJOR_ID_M8M2)
+ clock_level = 3;
+ else
+ clock_level = 1;
+ return 0;
+}
+
+static s32 jpegenc_wq_uninit(void)
+{
+ s32 r = -1;
+ jenc_pr(LOG_DEBUG, "uninit encode wq.\n");
+ if (gJpegenc.encode_hw_status == JPEGENC_ENCODER_IDLE) {
+ if ((gJpegenc.irq_num >= 0) &&
+ (gJpegenc.irq_requested == true)) {
+ free_irq(gJpegenc.irq_num, &gJpegenc);
+ gJpegenc.irq_requested = false;
+ }
+ r = 0;
+ }
+ return r;
+}
+
+static ssize_t jpegenc_status_show(struct class *cla,
+ struct class_attribute *attr, char *buf)
+{
+ s32 irq_num;
+ u32 hw_status, width, height;
+ bool process_irq;
+ bool inited;
+ bool use_reserve;
+ u32 cma_size, max_w, max_h;
+ u32 buffer_start, buffer_size;
+ u8 lev, opened;
+ struct Jpegenc_Buff_s res;
+
+ spin_lock(&gJpegenc.sem_lock);
+
+ irq_num = gJpegenc.irq_num;
+ hw_status = gJpegenc.encode_hw_status;
+ process_irq = gJpegenc.process_irq;
+ inited = gJpegenc.inited;
+ opened = gJpegenc.opened;
+ use_reserve = gJpegenc.use_reserve;
+ res.buf_start = gJpegenc.mem.reserve_mem.buf_start;
+ res.buf_size = gJpegenc.mem.reserve_mem.buf_size;
+ buffer_start = gJpegenc.mem.buf_start;
+ buffer_size = gJpegenc.mem.buf_size;
+ lev = gJpegenc.mem.cur_buf_lev;
+ max_w = gJpegenc.mem.bufspec->max_width;
+ max_h = gJpegenc.mem.bufspec->max_height;
+ width = gJpegenc.wq.cmd.encoder_width;
+ height = gJpegenc.wq.cmd.encoder_height;
+#ifdef CONFIG_CMA
+ cma_size = gJpegenc.mem.cma_pool_size / SZ_1M;
+#endif
+ spin_unlock(&gJpegenc.sem_lock);
+
+ jenc_pr(LOG_DEBUG,
+ "jpegenc width: %d, encode height: %d.\n",
+ width, height);
+ jenc_pr(LOG_DEBUG,
+ "jpegenc hw_status: %d, process_irq: %s.\n",
+ hw_status, process_irq ? "true" : "false");
+ jenc_pr(LOG_DEBUG,
+ "jpegenc irq num: %d, inited: %s, opened: %d\n",
+ irq_num, inited ? "true" : "false", opened);
+ if (use_reserve) {
+ jenc_pr(LOG_DEBUG,
+ "jpegenc reserve memory, buffer start: 0x%x, size: %d MB.\n",
+ res.buf_start, res.buf_size / SZ_1M);
+ } else {
+#ifdef CONFIG_CMA
+ jenc_pr(LOG_DEBUG, "jpegenc cma pool size: %d.\n", cma_size);
+#endif
+ }
+ jenc_pr(LOG_DEBUG, "jpegenc buffer start: 0x%x, size: 0x%x\n",
+ buffer_start, buffer_size);
+ jenc_pr(LOG_DEBUG, "buffer level: %s\n", glevel_str[lev]);
+ return snprintf(buf, 40, "max size: %dx%d\n", max_w, max_h);
+}
+
+static struct class_attribute jpegenc_class_attrs[] = {
+ __ATTR(encode_status,
+ S_IRUGO | S_IWUSR,
+ jpegenc_status_show,
+ NULL),
+ __ATTR_NULL
+};
+
+static struct class jpegenc_class = {
+ .name = CLASS_NAME,
+ .class_attrs = jpegenc_class_attrs,
+};
+
+s32 init_jpegenc_device(void)
+{
+ s32 r = 0;
+ r = register_chrdev(0, DEVICE_NAME, &jpegenc_fops);
+ if (r <= 0) {
+ jenc_pr(LOG_ERROR, "register jpegenc device error\n");
+ return r;
+ }
+ jpegenc_device_major = r;
+
+ r = class_register(&jpegenc_class);
+ if (r < 0) {
+ jenc_pr(LOG_ERROR, "error create jpegenc class.\n");
+ return r;
+ }
+
+ jpegenc_dev = device_create(&jpegenc_class, NULL,
+ MKDEV(jpegenc_device_major, 0), NULL,
+ DEVICE_NAME);
+
+ if (IS_ERR(jpegenc_dev)) {
+ jenc_pr(LOG_ERROR, "create jpegenc device error.\n");
+ class_unregister(&jpegenc_class);
+ return -1;
+ }
+ return r;
+}
+
+s32 uninit_jpegenc_device(void)
+{
+ if (jpegenc_dev)
+ device_destroy(&jpegenc_class, MKDEV(jpegenc_device_major, 0));
+
+ class_destroy(&jpegenc_class);
+
+ unregister_chrdev(jpegenc_device_major, DEVICE_NAME);
+ return 0;
+}
+
+static s32 jpegenc_mem_device_init(struct reserved_mem *rmem,
+ struct device *dev)
+{
+ s32 r;
+ struct resource res;
+ if (!rmem) {
+ jenc_pr(LOG_ERROR,
+ "Can't obtain I/O memory, will allocate jpegenc buffer!\n");
+ r = -EFAULT;
+ return r;
+ }
+ res.start = (phys_addr_t) rmem->base;
+ res.end = res.start + (phys_addr_t) rmem->size - 1;
+ gJpegenc.mem.reserve_mem.buf_start = res.start;
+ gJpegenc.mem.reserve_mem.buf_size = res.end - res.start + 1;
+ if (gJpegenc.mem.reserve_mem.buf_size >=
+ jpegenc_buffspec[JPEGENC_BUFFER_LEVEL_VGA].min_buffsize)
+ gJpegenc.use_reserve = true;
+ else {
+ jenc_pr(LOG_ERROR,
+ "jpegenc reserve_mem too small, size is %d.\n",
+ gJpegenc.mem.reserve_mem.buf_size);
+ gJpegenc.mem.reserve_mem.buf_start = 0;
+ gJpegenc.mem.reserve_mem.buf_size = 0;
+ return -EFAULT;
+ }
+ return r;
+}
+
+static s32 jpegenc_probe(struct platform_device *pdev)
+{
+ s32 res_irq;
+ s32 idx;
+
+ jenc_pr(LOG_DEBUG, "jpegenc probe start.\n");
+
+ gJpegenc.this_pdev = pdev;
+ gJpegenc.use_reserve = false;
+ memset(&gJpegenc.mem, 0, sizeof(struct jpegenc_meminfo_s));
+
+ idx = of_reserved_mem_device_init(&pdev->dev);
+
+ if (idx != 0) {
+ jenc_pr(LOG_DEBUG,
+ "jpegenc memory resource undefined.\n");
+ }
+
+ if (gJpegenc.use_reserve == false) {
+#ifndef CONFIG_CMA
+ jenc_pr(LOG_ERROR,
+ "jpegenc memory is invaild, probe fail!\n");
+ return -EFAULT;
+#else
+ gJpegenc.mem.cma_pool_size = 0x2300000;
+ //codec_mm_get_total_size();
+
+ jenc_pr(LOG_ERROR,
+ "jpegenc - cma memory pool size: %d MB\n",
+ (u32)gJpegenc.mem.cma_pool_size / SZ_1M);
+
+ gJpegenc.mem.buf_size = gJpegenc.mem.cma_pool_size;
+ gJpegenc.mem.buf_size = 0x2300000;
+#endif
+ } else {
+ gJpegenc.mem.buf_start = gJpegenc.mem.reserve_mem.buf_start;
+ gJpegenc.mem.buf_size = gJpegenc.mem.reserve_mem.buf_size;
+ }
+
+ if (gJpegenc.mem.buf_size >=
+ jpegenc_buffspec[JPEGENC_BUFFER_LEVEL_HD].min_buffsize) {
+ gJpegenc.mem.cur_buf_lev = JPEGENC_BUFFER_LEVEL_HD;
+ gJpegenc.mem.bufspec = (struct Jpegenc_BuffInfo_s *)
+ &jpegenc_buffspec[JPEGENC_BUFFER_LEVEL_HD];
+ } else if (gJpegenc.mem.buf_size >=
+ jpegenc_buffspec[JPEGENC_BUFFER_LEVEL_13M].min_buffsize) {
+ gJpegenc.mem.cur_buf_lev = JPEGENC_BUFFER_LEVEL_13M;
+ gJpegenc.mem.bufspec = (struct Jpegenc_BuffInfo_s *)
+ &jpegenc_buffspec[JPEGENC_BUFFER_LEVEL_13M];
+ } else if (gJpegenc.mem.buf_size >=
+ jpegenc_buffspec[JPEGENC_BUFFER_LEVEL_8M].min_buffsize) {
+ gJpegenc.mem.cur_buf_lev = JPEGENC_BUFFER_LEVEL_8M;
+ gJpegenc.mem.bufspec = (struct Jpegenc_BuffInfo_s *)
+ &jpegenc_buffspec[JPEGENC_BUFFER_LEVEL_8M];
+ } else if (gJpegenc.mem.buf_size >=
+ jpegenc_buffspec[JPEGENC_BUFFER_LEVEL_5M].min_buffsize) {
+ gJpegenc.mem.cur_buf_lev = JPEGENC_BUFFER_LEVEL_5M;
+ gJpegenc.mem.bufspec = (struct Jpegenc_BuffInfo_s *)
+ &jpegenc_buffspec[JPEGENC_BUFFER_LEVEL_5M];
+ } else if (gJpegenc.mem.buf_size >=
+ jpegenc_buffspec[JPEGENC_BUFFER_LEVEL_3M].min_buffsize) {
+ gJpegenc.mem.cur_buf_lev = JPEGENC_BUFFER_LEVEL_3M;
+ gJpegenc.mem.bufspec = (struct Jpegenc_BuffInfo_s *)
+ &jpegenc_buffspec[JPEGENC_BUFFER_LEVEL_3M];
+ } else if (gJpegenc.mem.buf_size >=
+ jpegenc_buffspec[JPEGENC_BUFFER_LEVEL_2M].min_buffsize) {
+ gJpegenc.mem.cur_buf_lev = JPEGENC_BUFFER_LEVEL_2M;
+ gJpegenc.mem.bufspec = (struct Jpegenc_BuffInfo_s *)
+ &jpegenc_buffspec[JPEGENC_BUFFER_LEVEL_2M];
+ } else if (gJpegenc.mem.buf_size >=
+ jpegenc_buffspec[JPEGENC_BUFFER_LEVEL_VGA].min_buffsize) {
+ gJpegenc.mem.cur_buf_lev = JPEGENC_BUFFER_LEVEL_VGA;
+ gJpegenc.mem.bufspec = (struct Jpegenc_BuffInfo_s *)
+ &jpegenc_buffspec[JPEGENC_BUFFER_LEVEL_VGA];
+ } else {
+ jenc_pr(LOG_ERROR,
+ "jpegenc probe memory too small, size is %d.\n",
+ gJpegenc.mem.buf_size);
+ gJpegenc.mem.buf_start = 0;
+ gJpegenc.mem.buf_size = 0;
+ return -EFAULT;
+ }
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+ if (jpegenc_clk_prepare(&pdev->dev, &s_jpegenc_clks)) {
+ //err = -ENOENT;
+ pr_err("[%s:%d] prepare jpegenc clk failed\n", __FUNCTION__, __LINE__);
+ //goto ERROR_PROBE_DEVICE;
+ return -EINVAL;
+ }
+ }
+
+ //if (get_cpu_type() >= MESON_CPU_MAJOR_ID_SC2) {
+ // jpegenc_rst = devm_reset_control_get(&pdev->dev, "jpegenc_rst");
+ // if (IS_ERR(jpegenc_rst))
+ // pr_err("amvenc probe, jpegenc get reset failed: %ld\n", PTR_ERR(jpegenc_rst));
+ //}
+
+ res_irq = platform_get_irq(pdev, 0);
+ if (res_irq < 0) {
+ jenc_pr(LOG_ERROR, "[%s] get irq error!", __func__);
+ return -EINVAL;
+ }
+
+ gJpegenc.irq_num = res_irq;
+
+ jenc_pr(LOG_DEBUG,
+ "jpegenc memory config sucess, buff size is 0x%x, level: %s\n",
+ gJpegenc.mem.buf_size,
+ glevel_str[gJpegenc.mem.cur_buf_lev]);
+
+ jpegenc_wq_init();
+ init_jpegenc_device();
+ jenc_pr(LOG_DEBUG, "jpegenc probe end.\n");
+ return 0;
+}
+
+static s32 jpegenc_remove(struct platform_device *pdev)
+{
+ if (jpegenc_wq_uninit())
+ jenc_pr(LOG_ERROR, "jpegenc_wq_uninit error.\n");
+ uninit_jpegenc_device();
+ jenc_pr(LOG_DEBUG, "jpegenc remove.\n");
+ return 0;
+}
+
+static const struct of_device_id amlogic_jpegenc_dt_match[] = {
+ {
+ .compatible = "amlogic, jpegenc",
+ },
+ {},
+};
+
+static struct platform_driver jpegenc_driver = {
+ .probe = jpegenc_probe,
+ .remove = jpegenc_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = amlogic_jpegenc_dt_match,
+ }
+};
+
+static struct codec_profile_t jpegenc_profile = {
+ .name = "jpegenc",
+ .profile = ""
+};
+
+static s32 __init jpegenc_driver_init_module(void)
+{
+ jenc_pr(LOG_DEBUG, "jpegenc module init\n");
+
+ if (platform_driver_register(&jpegenc_driver)) {
+ jenc_pr(LOG_ERROR, "failed to register jpegenc driver\n");
+ return -ENODEV;
+ }
+ vcodec_profile_register(&jpegenc_profile);
+ return 0;
+}
+
+static void __exit jpegenc_driver_remove_module(void)
+{
+ jenc_pr(LOG_DEBUG, "jpegenc module remove.\n");
+ platform_driver_unregister(&jpegenc_driver);
+}
+
+static const struct reserved_mem_ops rmem_jpegenc_ops = {
+ .device_init = jpegenc_mem_device_init,
+};
+
+static s32 __init jpegenc_mem_setup(struct reserved_mem *rmem)
+{
+ rmem->ops = &rmem_jpegenc_ops;
+ jenc_pr(LOG_DEBUG, "jpegenc reserved mem setup.\n");
+ return 0;
+}
+
+module_param(clock_level, uint, 0664);
+MODULE_PARM_DESC(clock_level, "\n clock_level\n");
+
+module_param(jpegenc_print_level, uint, 0664);
+MODULE_PARM_DESC(jpegenc_print_level, "\n jpegenc_print_level\n");
+
+module_init(jpegenc_driver_init_module);
+module_exit(jpegenc_driver_remove_module);
+RESERVEDMEM_OF_DECLARE(jpegenc, "amlogic, jpegenc-memory", jpegenc_mem_setup);
+
+MODULE_DESCRIPTION("AMLOGIC JPEG Encoder Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("simon.zheng <simon.zheng@amlogic.com>");
diff --git a/drivers/frame_sink/encoder/jpeg/jpegenc.h b/drivers/frame_sink/encoder/jpeg/jpegenc.h
new file mode 100644
index 0000000..61062fb
--- /dev/null
+++ b/drivers/frame_sink/encoder/jpeg/jpegenc.h
@@ -0,0 +1,249 @@
+/*
+ * drivers/amlogic/amports/jpegenc.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 __JPEG_ENC_H_
+#define __JPEG_ENC_H_
+
+#define JPEGENC_DEVINFO_M8 "AML-M8"
+#define JPEGENC_DEVINFO_G9 "AML-G9"
+#define JPEGENC_DEVINFO_GXBB "AML-GXBB"
+#define JPEGENC_DEVINFO_GXTVBB "AML-GXTVBB"
+#define JPEGENC_DEVINFO_GXL "AML-GXL"
+
+/* M8: 2550/10 = 255M GX: 2000/10 = 200M */
+#define JPEGENC_HDEC_L0() WRITE_HHI_REG(HHI_VDEC_CLK_CNTL, \
+ (2 << 25) | (1 << 16) | (1 << 24) | \
+ (0xffff & READ_HHI_REG(HHI_VDEC_CLK_CNTL)))
+/* M8: 2550/8 = 319M GX: 2000/8 = 250M */
+#define JPEGENC_HDEC_L1() WRITE_HHI_REG(HHI_VDEC_CLK_CNTL, \
+ (0 << 25) | (1 << 16) | (1 << 24) | \
+ (0xffff & READ_HHI_REG(HHI_VDEC_CLK_CNTL)))
+/* M8: 2550/7 = 364M GX: 2000/7 = 285M */
+#define JPEGENC_HDEC_L2() WRITE_HHI_REG(HHI_VDEC_CLK_CNTL, \
+ (3 << 25) | (0 << 16) | (1 << 24) | \
+ (0xffff & READ_HHI_REG(HHI_VDEC_CLK_CNTL)))
+/* M8: 2550/6 = 425M GX: 2000/6 = 333M */
+#define JPEGENC_HDEC_L3() WRITE_HHI_REG(HHI_VDEC_CLK_CNTL, \
+ (1 << 25) | (1 << 16) | (1 << 24) | \
+ (0xffff & READ_HHI_REG(HHI_VDEC_CLK_CNTL)))
+/* M8: 2550/5 = 510M GX: 2000/5 = 400M */
+#define JPEGENC_HDEC_L4() WRITE_HHI_REG(HHI_VDEC_CLK_CNTL, \
+ (2 << 25) | (0 << 16) | (1 << 24) | \
+ (0xffff & READ_HHI_REG(HHI_VDEC_CLK_CNTL)))
+/* M8: 2550/4 = 638M GX: 2000/4 = 500M */
+#define JPEGENC_HDEC_L5() WRITE_HHI_REG(HHI_VDEC_CLK_CNTL, \
+ (0 << 25) | (0 << 16) | (1 << 24) | \
+ (0xffff & READ_HHI_REG(HHI_VDEC_CLK_CNTL)))
+/* M8: 2550/3 = 850M GX: 2000/3 = 667M */
+#define JPEGENC_HDEC_L6() WRITE_HHI_REG(HHI_VDEC_CLK_CNTL, \
+ (1 << 25) | (0 << 16) | (1 << 24) | \
+ (0xffff & READ_HHI_REG(HHI_VDEC_CLK_CNTL)))
+
+#define jpegenc_clock_enable(level) \
+ do { \
+ if (level == 0) \
+ JPEGENC_HDEC_L0(); \
+ else if (level == 1) \
+ JPEGENC_HDEC_L1(); \
+ else if (level == 2) \
+ JPEGENC_HDEC_L2(); \
+ else if (level == 3) \
+ JPEGENC_HDEC_L3(); \
+ else if (level == 4) \
+ JPEGENC_HDEC_L4(); \
+ else if (level == 5) \
+ JPEGENC_HDEC_L5(); \
+ else if (level == 6) \
+ JPEGENC_HDEC_L6(); \
+ WRITE_VREG_BITS(DOS_GCLK_EN0, 0x7fff, 12, 15); \
+ } while (0)
+
+#define jpegenc_clock_disable() \
+ do { \
+ WRITE_VREG_BITS(DOS_GCLK_EN0, 0, 12, 15); \
+ WRITE_HHI_REG_BITS(HHI_VDEC_CLK_CNTL, 0, 24, 1); \
+ } while (0)
+
+#define JPEGENC_IOC_MAGIC 'J'
+
+#define JPEGENC_IOC_GET_DEVINFO _IOW(JPEGENC_IOC_MAGIC, 0xf0, u32)
+
+#define JPEGENC_IOC_GET_BUFFINFO _IOW(JPEGENC_IOC_MAGIC, 0x00, u32)
+#define JPEGENC_IOC_CONFIG_INIT _IOW(JPEGENC_IOC_MAGIC, 0x01, u32)
+#define JPEGENC_IOC_NEW_CMD _IOW(JPEGENC_IOC_MAGIC, 0x02, u32)
+#define JPEGENC_IOC_GET_STAGE _IOW(JPEGENC_IOC_MAGIC, 0x03, u32)
+#define JPEGENC_IOC_GET_OUTPUT_SIZE _IOW(JPEGENC_IOC_MAGIC, 0x04, u32)
+#define JPEGENC_IOC_SET_EXT_QUANT_TABLE _IOW(JPEGENC_IOC_MAGIC, 0x05, u32)
+
+#define DCTSIZE2 64
+
+#define JPEGENC_FLUSH_FLAG_INPUT 0x1
+#define JPEGENC_FLUSH_FLAG_OUTPUT 0x2
+
+/* Define Quantization table: Max two tables */
+#define QUANT_SEL_COMP0 0
+#define QUANT_SEL_COMP1 1
+#define QUANT_SEL_COMP2 1
+
+/* Define Huffman table selection: Max two tables per DC/AC */
+#define DC_HUFF_SEL_COMP0 0
+#define DC_HUFF_SEL_COMP1 1
+#define DC_HUFF_SEL_COMP2 1
+#define AC_HUFF_SEL_COMP0 0
+#define AC_HUFF_SEL_COMP1 1
+#define AC_HUFF_SEL_COMP2 1
+
+/* DCT interrupt select:0=Disable intr;
+ 1=Intr at end of each 8x8 block of DCT input;
+ 2=Intr at end of each MCU of DCT input;
+ 3=Intr at end of a scan of DCT input;
+ 4=Intr at end of each 8x8 block of DCT output;
+ 5=Intr at end of each MCU of DCT output;
+ 6=Intr at end of a scan of DCT output; */
+#define JDCT_INTR_SEL 0
+
+/* 0=Mark last coeff at the end of an 8x8 block,
+ 1=Mark last coeff at the end of an MCU
+ 2=Mark last coeff at the end of a scan */
+#define JDCT_LASTCOEFF_SEL 1
+
+enum jpegenc_mem_type_e {
+ JPEGENC_LOCAL_BUFF = 0,
+ JPEGENC_CANVAS_BUFF,
+ JPEGENC_PHYSICAL_BUFF,
+ JPEGENC_MAX_BUFF_TYPE
+};
+
+enum jpegenc_frame_fmt_e {
+ JPEGENC_FMT_YUV422_SINGLE = 0,
+ JPEGENC_FMT_YUV444_SINGLE,
+ JPEGENC_FMT_NV21,
+ JPEGENC_FMT_NV12,
+ JPEGENC_FMT_YUV420,
+ JPEGENC_FMT_YUV444_PLANE,
+ JPEGENC_FMT_RGB888,
+ JPEGENC_FMT_RGB888_PLANE,
+ JPEGENC_FMT_RGB565,
+ JPEGENC_FMT_RGBA8888,
+ JPEGENC_FMT_YUV422_12BIT,
+ JPEGENC_FMT_YUV444_10BIT,
+ JPEGENC_FMT_YUV422_10BIT,
+ JPEGENC_MAX_FRAME_FMT
+};
+
+struct Jpegenc_Buff_s {
+ u32 buf_start;
+ u32 buf_size;
+};
+
+struct Jpegenc_BuffInfo_s {
+ u32 lev_id;
+ u32 max_width;
+ u32 max_height;
+ u32 min_buffsize;
+ struct Jpegenc_Buff_s input;
+ struct Jpegenc_Buff_s assit;
+ struct Jpegenc_Buff_s bitstream;
+};
+
+struct jpegenc_request_s {
+ u32 src;
+ u32 encoder_width;
+ u32 encoder_height;
+ u32 framesize;
+ u32 jpeg_quality;
+ u32 QuantTable_id;
+ u32 flush_flag;
+ enum jpegenc_mem_type_e type;
+ enum jpegenc_frame_fmt_e input_fmt;
+ enum jpegenc_frame_fmt_e output_fmt;
+};
+
+struct jpegenc_meminfo_s {
+ u32 buf_start;
+ u32 buf_size;
+ u8 cur_buf_lev;
+
+#ifdef CONFIG_CMA
+ ulong cma_pool_size;
+#endif
+ struct Jpegenc_Buff_s reserve_mem;
+ struct Jpegenc_BuffInfo_s *bufspec;
+};
+
+struct jpegenc_wq_s {
+ u32 hw_status;
+ u32 headbytes;
+ u32 output_size;
+
+ u32 buf_start;
+ u32 buf_size;
+
+ u32 InputBuffStart;
+ u32 InputBuffEnd;
+
+ u32 AssitStart;
+ u32 AssitEnd;
+
+ u32 BitstreamStart;
+ u32 BitstreamEnd;
+ void __iomem *AssitstreamStartVirtAddr;
+
+ u32 max_width;
+ u32 max_height;
+
+ struct jpegenc_request_s cmd;
+ atomic_t ready;
+ wait_queue_head_t complete;
+#ifdef CONFIG_CMA
+ struct page *venc_pages;
+#endif
+};
+
+struct jpegenc_manager_s {
+ u32 encode_hw_status;
+ s32 irq_num;
+
+ bool irq_requested;
+ bool process_irq;
+ bool inited;
+ bool use_reserve;
+ u8 opened;
+
+ spinlock_t sem_lock;
+ struct platform_device *this_pdev;
+ struct jpegenc_meminfo_s mem;
+ struct jpegenc_wq_s wq;
+ struct tasklet_struct tasklet;
+};
+
+/********************************************
+ * AV Scratch Register Re-Define
+********************************************/
+#define JPEGENC_ENCODER_STATUS HCODEC_HENC_SCRATCH_0
+#define JPEGENC_BITSTREAM_OFFSET HCODEC_HENC_SCRATCH_1
+
+/*********************************************
+ * ENCODER_STATUS define
+********************************************/
+#define JPEGENC_ENCODER_IDLE 0
+#define JPEGENC_ENCODER_START 1
+/* #define JPEGENC_ENCODER_SOS_HEADER 2 */
+#define JPEGENC_ENCODER_MCU 3
+#define JPEGENC_ENCODER_DONE 4
+
+extern bool jpegenc_on(void);
+#endif
diff --git a/drivers/framerate_adapter/Makefile b/drivers/framerate_adapter/Makefile
new file mode 100644
index 0000000..fc1998b
--- /dev/null
+++ b/drivers/framerate_adapter/Makefile
@@ -0,0 +1 @@
+obj-m += video_framerate_adapter.o
diff --git a/drivers/framerate_adapter/video_framerate_adapter.c b/drivers/framerate_adapter/video_framerate_adapter.c
new file mode 100644
index 0000000..f920954
--- /dev/null
+++ b/drivers/framerate_adapter/video_framerate_adapter.c
@@ -0,0 +1,145 @@
+/*
+ * drivers/framerate_adapter/video_framerate_adapter.c
+ *
+ * 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.
+ *
+ */
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include "video_framerate_adapter.h"
+
+#define CLASS_NAME "framerate_adapter"
+#define DEV_NAME "framerate_dev"
+
+#ifndef VIDEOFRAME_MAJOR
+#define VIDEOFRAME_MAJOR 550
+#endif
+
+struct frame_rate_dev_s* frame_rate_dev;
+
+ void vframe_rate_uevent(int duration)
+{
+ char *configured[2];
+ char framerate[40] = {0};
+
+ sprintf(framerate, "FRAME_RATE_HINT=%lu",
+ (unsigned long)duration);
+ configured[0] = framerate;
+ configured[1] = NULL;
+ kobject_uevent_env(&frame_rate_dev->dev->kobj,
+ KOBJ_CHANGE, configured);
+
+ pr_info("%s: sent uevent %s\n", __func__, configured[0]);
+}
+
+EXPORT_SYMBOL(vframe_rate_uevent);
+
+static const struct file_operations frame_rate_fops = {
+ .owner = THIS_MODULE
+};
+
+static struct class_attribute frame_rate_class_attrs[] = {
+ __ATTR_NULL
+};
+
+static struct class frame_rate_class = {
+ .name = CLASS_NAME,
+ .class_attrs = frame_rate_class_attrs,
+};
+
+static int frame_rate_driver_init(void)
+{
+ int ret = -1;
+
+ frame_rate_dev = kzalloc(sizeof(struct frame_rate_dev_s), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(frame_rate_dev))
+ return -ENOMEM;
+
+ frame_rate_dev->dev_no = MKDEV(VIDEOFRAME_MAJOR, 100);
+
+ ret = register_chrdev_region(frame_rate_dev->dev_no, 1, DEV_NAME);
+ if (ret < 0) {
+ pr_err("Can't get major number %d.\n", VIDEOFRAME_MAJOR);
+ goto err_4;
+ }
+
+ cdev_init(&frame_rate_dev->cdev, &frame_rate_fops);
+ frame_rate_dev->cdev.owner = THIS_MODULE;
+
+ ret = cdev_add(&frame_rate_dev->cdev, frame_rate_dev->dev_no, 1);
+ if (ret) {
+ pr_err("Error %d adding cdev fail.\n", ret);
+ goto err_3;
+ }
+
+ ret = class_register(&frame_rate_class);
+ if (ret < 0) {
+ pr_err("Failed in creating class.\n");
+ goto err_2;
+ }
+
+ frame_rate_dev->dev = device_create(&frame_rate_class, NULL,
+ frame_rate_dev->dev_no, NULL, DEV_NAME);
+ if (IS_ERR_OR_NULL(frame_rate_dev->dev)) {
+ pr_err("Create device failed.\n");
+ ret = -ENODEV;
+ goto err_1;
+ }
+ pr_info("Registered frame rate driver success.\n");
+ return 0;
+
+err_1:
+ device_destroy(&frame_rate_class, frame_rate_dev->dev_no);
+err_2:
+ class_unregister(&frame_rate_class);
+err_3:
+ cdev_del(&frame_rate_dev->cdev);
+err_4:
+ unregister_chrdev_region(frame_rate_dev->dev_no, 1);
+ kfree(frame_rate_dev);
+ return ret;
+}
+
+static void frame_rate_driver_exit(void)
+{
+ device_destroy(&frame_rate_class, frame_rate_dev->dev_no);
+ class_unregister(&frame_rate_class);
+ cdev_del(&frame_rate_dev->cdev);
+ unregister_chrdev_region(frame_rate_dev->dev_no, 1);
+ kfree(frame_rate_dev);
+}
+
+static int __init frame_rate_module_init(void)
+{
+ int ret = -1;
+
+ ret = frame_rate_driver_init();
+ if (ret) {
+ pr_info("Error %d frame_rate_module_init init fail.\n", ret);
+ }
+ return ret;
+}
+
+static void __exit frame_rate_module_exit(void)
+{
+ frame_rate_driver_exit();
+ pr_info("frame_rate_module_exit\n");
+}
+
+module_init(frame_rate_module_init);
+module_exit(frame_rate_module_exit);
+
+MODULE_AUTHOR("<shilong.yang@amlogic.com>");
+MODULE_DESCRIPTION("framerate adapter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/framerate_adapter/video_framerate_adapter.h b/drivers/framerate_adapter/video_framerate_adapter.h
new file mode 100644
index 0000000..1748843
--- /dev/null
+++ b/drivers/framerate_adapter/video_framerate_adapter.h
@@ -0,0 +1,34 @@
+/*
+ * drivers/framerate_adapter/video_framerate_adaper.h
+ *
+ * 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.
+ *
+*/
+
+#ifndef VIDEOFRAMERATEADAPTER_H
+#define VIDEOFRAMERATEADAPTER_H
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/cdev.h>
+
+
+struct frame_rate_dev_s {
+ struct cdev cdev;
+ struct device *dev;
+ dev_t dev_no;
+};
+
+#endif
+
diff --git a/drivers/include/dummy-for-git-empty-dir b/drivers/include/dummy-for-git-empty-dir
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/include/dummy-for-git-empty-dir
diff --git a/drivers/media_sync/Makefile b/drivers/media_sync/Makefile
new file mode 100644
index 0000000..7ed5b83
--- /dev/null
+++ b/drivers/media_sync/Makefile
@@ -0,0 +1,4 @@
+obj-m += media_sync.o
+
+media_sync-objs += media_sync_dev.o
+media_sync-objs += media_sync_core.o
diff --git a/drivers/media_sync/media_sync_core.c b/drivers/media_sync/media_sync_core.c
new file mode 100644
index 0000000..abe3450
--- /dev/null
+++ b/drivers/media_sync/media_sync_core.c
@@ -0,0 +1,424 @@
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/amlogic/cpu_version.h>
+#include <linux/syscalls.h>
+#include <linux/times.h>
+#include <linux/time.h>
+#include <linux/time64.h>
+#include "media_sync_core.h"
+
+#define MAX_INSTANCE_NUM 10
+mediasync_ins* vMediaSyncInsList[MAX_INSTANCE_NUM] = {0};
+
+extern int demux_get_stc(int demux_device_index, int index,
+ u64 *stc, unsigned int *base);
+extern int demux_get_pcr(int demux_device_index, int index, u64 *pcr);
+
+static u64 get_llabs(s64 value){
+ u64 llvalue;
+ if (value > 0) {
+ return value;
+ } else {
+ llvalue = (u64)(0-value);
+ return llvalue;
+ }
+}
+
+static u64 get_stc_time_us(s32 sSyncInsId, u64 *systemtime)
+{
+ /*mediasync_ins* pInstance = NULL;
+ u64 stc;
+ unsigned int base;
+ s32 index = sSyncInsId;
+ if (index < 0 || index >= MAX_INSTANCE_NUM)
+ return -1;
+
+ pInstance = vMediaSyncInsList[index];
+ demux_get_stc(pInstance->mDemuxId, 0, &stc, &base);*/
+ mediasync_ins* pInstance = NULL;
+ int ret;
+ u64 stc;
+ u64 timeus;
+ u64 pcr;
+ s64 pcr_diff;
+ s64 time_diff;
+ s32 index = sSyncInsId;
+ struct timespec64 ts_monotonic;
+ if (index < 0 || index >= MAX_INSTANCE_NUM)
+ return -1;
+ pInstance = vMediaSyncInsList[index];
+ ktime_get_ts64(&ts_monotonic);
+ timeus = ts_monotonic.tv_sec * 1000000LL + ts_monotonic.tv_nsec / 1000LL;
+ *systemtime = timeus;
+ if (pInstance->mDemuxId < 0)
+ return timeus;
+
+ ret = demux_get_pcr(pInstance->mDemuxId, 0, &pcr);
+ if (ret != 0) {
+ stc = timeus;
+ } else {
+ if (pInstance->last_pcr == 0) {
+ stc = timeus;
+ pInstance->last_pcr = pcr * 100 / 9;
+ pInstance->last_system = timeus;
+ } else {
+ pcr_diff = pcr * 100 / 9 - pInstance->last_pcr;
+ time_diff = timeus - pInstance->last_system;
+ if (time_diff && (get_llabs(pcr_diff) / time_diff
+ > 100)) {
+ pInstance->last_pcr = pcr * 100 / 9;
+ pInstance->last_system = timeus;
+ stc = timeus;
+ } else {
+ if (time_diff)
+ stc = pInstance->last_system + pcr_diff;
+ else
+ stc = timeus;
+
+ pInstance->last_pcr = pcr * 100 / 9;
+ pInstance->last_system = stc;
+ }
+ }
+ }
+ pr_debug("get_stc_time_us stc:%lld pcr:%lld system_time:%lld\n", stc, pcr * 100 / 9, timeus);
+ return stc;
+}
+
+/*static s64 get_system_time_us(void) {
+ s64 TimeUs;
+ struct timespec64 ts_monotonic;
+ ktime_get_ts64(&ts_monotonic);
+ TimeUs = ts_monotonic.tv_sec * 1000000LL + ts_monotonic.tv_nsec / 1000LL;
+ pr_debug("get_system_time_us %lld\n", TimeUs);
+ return TimeUs;
+}*/
+
+long mediasync_ins_alloc(s32 sDemuxId,
+ s32 sPcrPid,
+ s32 *sSyncInsId,
+ mediasync_ins **pIns){
+ s32 index = 0;
+ mediasync_ins* pInstance = NULL;
+ pInstance = kzalloc(sizeof(mediasync_ins), GFP_KERNEL);
+ if (pInstance == NULL) {
+ return -1;
+ }
+
+ for (index = 0; index < MAX_INSTANCE_NUM - 1; index++) {
+ if (vMediaSyncInsList[index] == NULL) {
+ vMediaSyncInsList[index] = pInstance;
+ pInstance->mSyncInsId = index;
+ *sSyncInsId = index;
+ pr_info("mediasync_ins_alloc index:%d\n", index);
+ break;
+ }
+ }
+
+ if (index == MAX_INSTANCE_NUM) {
+ kzfree(pInstance);
+ return -1;
+ }
+
+ pInstance->mDemuxId = sDemuxId;
+ pInstance->mPcrPid = sPcrPid;
+ *pIns = pInstance;
+ return 0;
+}
+
+
+long mediasync_ins_delete(s32 sSyncInsId) {
+ mediasync_ins* pInstance = NULL;
+ s32 index = sSyncInsId;
+ if (index < 0 || index >= MAX_INSTANCE_NUM)
+ return -1;
+
+ pInstance = vMediaSyncInsList[index];
+ if (pInstance == NULL)
+ return -1;
+
+ kzfree(pInstance);
+ vMediaSyncInsList[index] = NULL;
+ return 0;
+}
+
+long mediasync_ins_binder(s32 sSyncInsId,
+ mediasync_ins **pIns) {
+ mediasync_ins* pInstance = NULL;
+ s32 index = sSyncInsId;
+ if (index < 0 || index >= MAX_INSTANCE_NUM)
+ return -1;
+
+ pInstance = vMediaSyncInsList[index];
+ if (pInstance == NULL)
+ return -1;
+
+ pInstance->mRef++;
+ *pIns = pInstance;
+ return 0;
+}
+
+long mediasync_ins_unbinder(s32 sSyncInsId) {
+ mediasync_ins* pInstance = NULL;
+ s32 index = sSyncInsId;
+ if (index < 0 || index >= MAX_INSTANCE_NUM)
+ return -1;
+
+ pInstance = vMediaSyncInsList[index];
+ if (pInstance == NULL)
+ return -1;
+
+ pInstance->mRef--;
+
+ if (pInstance->mRef <= 0)
+ mediasync_ins_delete(sSyncInsId);
+
+ return 0;
+}
+
+long mediasync_ins_update_mediatime(s32 sSyncInsId,
+ s64 lMediaTime,
+ s64 lSystemTime, bool forceUpdate) {
+ mediasync_ins* pInstance = NULL;
+ u64 current_stc = 0;
+ s64 current_systemtime = 0;
+ s64 diff_system_time = 0;
+ s64 diff_mediatime = 0;
+ s32 index = sSyncInsId;
+ if (index < 0 || index >= MAX_INSTANCE_NUM)
+ return -1;
+
+ pInstance = vMediaSyncInsList[index];
+ if (pInstance == NULL)
+ return -1;
+
+ current_stc = get_stc_time_us(sSyncInsId, ¤t_systemtime);
+ //pInstance->mSyncMode = MEDIA_SYNC_PCRMASTER;
+
+ if (pInstance->mSyncMode == MEDIA_SYNC_PCRMASTER) {
+ if (lSystemTime == 0) {
+ if (current_stc != 0) {
+ diff_system_time = current_stc - pInstance->mLastStc;
+ diff_mediatime = lMediaTime - pInstance->mLastMediaTime;
+ } else {
+ diff_system_time = current_systemtime - pInstance->mLastRealTime;
+ diff_mediatime = lMediaTime - pInstance->mLastMediaTime;
+ }
+ if (diff_mediatime < 0
+ || ((diff_mediatime > 0)
+ && (get_llabs(diff_system_time - diff_mediatime) > MIN_UPDATETIME_THRESHOLD_US ))) {
+ pr_info("MEDIA_SYNC_PCRMASTER update time system diff:%lld media diff:%lld current:%lld\n",
+ diff_system_time,
+ diff_mediatime,
+ current_systemtime);
+ pInstance->mLastMediaTime = lMediaTime;
+ pInstance->mLastRealTime = current_systemtime;
+ pInstance->mLastStc = current_stc;
+ }
+ } else {
+ if (current_stc != 0) {
+ diff_system_time = current_stc + lSystemTime - current_systemtime - pInstance->mLastStc;
+ diff_mediatime = lMediaTime - pInstance->mLastMediaTime;
+ } else {
+ diff_system_time = lSystemTime - pInstance->mLastRealTime;
+ diff_mediatime = lMediaTime - pInstance->mLastMediaTime;
+ }
+
+ if (diff_mediatime < 0
+ || ((diff_mediatime > 0)
+ && (get_llabs(diff_system_time - diff_mediatime) > MIN_UPDATETIME_THRESHOLD_US ))) {
+ pr_info("MEDIA_SYNC_PCRMASTER update time stc diff:%lld media diff:%lld lSystemTime:%lld lMediaTime:%lld\n",
+ diff_system_time,
+ diff_mediatime,
+ lSystemTime,
+ lMediaTime);
+ pInstance->mLastMediaTime = lMediaTime;
+ pInstance->mLastRealTime = lSystemTime;
+ pInstance->mLastStc = current_stc + lSystemTime - current_systemtime;
+ }
+ }
+ } else {
+ if (lSystemTime == 0) {
+ pInstance->mLastMediaTime = lMediaTime;
+ pInstance->mLastRealTime = current_systemtime;
+ pInstance->mLastStc = current_stc;
+ } else {
+ pInstance->mLastMediaTime = lMediaTime;
+ pInstance->mLastRealTime = lSystemTime;
+ pInstance->mLastStc = current_stc + lSystemTime - current_systemtime;
+ }
+ }
+ pInstance->mTrackMediaTime = lMediaTime;
+ return 0;
+}
+
+long mediasync_ins_set_mediatime_speed(s32 sSyncInsId,
+ mediasync_speed fSpeed) {
+ mediasync_ins* pInstance = NULL;
+ s32 index = sSyncInsId;
+ if (index < 0 || index >= MAX_INSTANCE_NUM)
+ return -1;
+
+ pInstance = vMediaSyncInsList[index];
+ if (pInstance == NULL)
+ return -1;
+
+ pInstance->mSpeed.mNumerator = fSpeed.mNumerator;
+ pInstance->mSpeed.mDenominator = fSpeed.mDenominator;
+ return 0;
+}
+
+long mediasync_ins_set_paused(s32 sSyncInsId, s32 sPaused) {
+
+ mediasync_ins* pInstance = NULL;
+ u64 current_stc = 0;
+ s64 current_systemtime = 0;
+ s32 index = sSyncInsId;
+ if (index < 0 || index >= MAX_INSTANCE_NUM)
+ return -1;
+
+ pInstance = vMediaSyncInsList[index];
+ if (pInstance == NULL)
+ return -1;
+
+ if ((sPaused != 0 && sPaused != 1)
+ || (sPaused == pInstance->mPaused))
+ return -1;
+
+ current_stc = get_stc_time_us(sSyncInsId, ¤t_systemtime);
+
+ pInstance->mPaused = sPaused;
+ pInstance->mLastRealTime = current_systemtime;
+ pInstance->mLastStc = current_stc;
+
+ return 0;
+}
+
+long mediasync_ins_get_paused(s32 sSyncInsId, s32* spPaused) {
+
+ mediasync_ins* pInstance = NULL;
+ s32 index = sSyncInsId;
+ if (index < 0 || index >= MAX_INSTANCE_NUM)
+ return -1;
+
+ pInstance = vMediaSyncInsList[index];
+ if (pInstance == NULL)
+ return -1;
+ *spPaused = pInstance->mPaused ;
+ return 0;
+}
+
+long mediasync_ins_set_syncmode(s32 sSyncInsId, s32 sSyncMode){
+ mediasync_ins* pInstance = NULL;
+ s32 index = sSyncInsId;
+ if (index < 0 || index >= MAX_INSTANCE_NUM)
+ return -1;
+
+ pInstance = vMediaSyncInsList[index];
+ if (pInstance == NULL)
+ return -1;
+
+ pInstance->mSyncMode = sSyncMode;
+ return 0;
+}
+
+long mediasync_ins_get_syncmode(s32 sSyncInsId, s32 *sSyncMode) {
+ mediasync_ins* pInstance = NULL;
+ s32 index = sSyncInsId;
+ if (index < 0 || index >= MAX_INSTANCE_NUM)
+ return -1;
+
+ pInstance = vMediaSyncInsList[index];
+ if (pInstance == NULL)
+ return -1;
+ *sSyncMode = pInstance->mSyncMode;
+ return 0;
+}
+
+long mediasync_ins_get_mediatime_speed(s32 sSyncInsId, mediasync_speed *fpSpeed) {
+ mediasync_ins* pInstance = NULL;
+ s32 index = sSyncInsId;
+ if (index < 0 || index >= MAX_INSTANCE_NUM)
+ return -1;
+
+ pInstance = vMediaSyncInsList[index];
+ if (pInstance == NULL)
+ return -1;
+ fpSpeed->mNumerator = pInstance->mSpeed.mNumerator;
+ fpSpeed->mDenominator = pInstance->mSpeed.mDenominator;
+ return 0;
+}
+
+long mediasync_ins_get_anchor_time(s32 sSyncInsId,
+ s64* lpMediaTime,
+ s64* lpSTCTime,
+ s64* lpSystemTime) {
+ mediasync_ins* pInstance = NULL;
+ s32 index = sSyncInsId;
+
+ if (index < 0 || index >= MAX_INSTANCE_NUM)
+ return -1;
+
+ pInstance = vMediaSyncInsList[index];
+ if (pInstance == NULL)
+ return -1;
+
+ *lpMediaTime = pInstance->mLastMediaTime;
+ *lpSTCTime = pInstance->mLastStc;
+ *lpSystemTime = pInstance->mLastRealTime;
+ return 0;
+}
+
+long mediasync_ins_get_systemtime(s32 sSyncInsId, s64* lpSTC, s64* lpSystemTime){
+ mediasync_ins* pInstance = NULL;
+ u64 current_stc = 0;
+ s64 current_systemtime = 0;
+ s32 index = sSyncInsId;
+
+ if (index < 0 || index >= MAX_INSTANCE_NUM)
+ return -1;
+
+ pInstance = vMediaSyncInsList[index];
+ if (pInstance == NULL)
+ return -1;
+
+ current_stc = get_stc_time_us(sSyncInsId, ¤t_systemtime);
+
+ *lpSTC = current_stc;
+ *lpSystemTime = current_systemtime;
+
+ return 0;
+}
+
+long mediasync_ins_get_nextvsync_systemtime(s32 sSyncInsId, s64* lpSystemTime) {
+
+ return 0;
+}
+
+long mediasync_ins_get_trackmediatime(s32 sSyncInsId, s64* lpTrackMediaTime) {
+
+ mediasync_ins* pInstance = NULL;
+ s32 index = sSyncInsId;
+ if (index < 0 || index >= MAX_INSTANCE_NUM)
+ return -1;
+
+ pInstance = vMediaSyncInsList[index];
+ if (pInstance == NULL)
+ return -1;
+ *lpTrackMediaTime = pInstance->mTrackMediaTime;
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/drivers/media_sync/media_sync_core.h b/drivers/media_sync/media_sync_core.h
new file mode 100644
index 0000000..41b8910
--- /dev/null
+++ b/drivers/media_sync/media_sync_core.h
@@ -0,0 +1,69 @@
+#ifndef MEDIA_SYNC_HEAD_HH
+#define MEDIA_SYNC_HEAD_HH
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/amlogic/cpu_version.h>
+
+
+#define MIN_UPDATETIME_THRESHOLD_US 50000
+typedef enum {
+ MEDIA_SYNC_VMASTER = 0,
+ MEDIA_SYNC_AMASTER = 1,
+ MEDIA_SYNC_PCRMASTER = 2,
+ MEDIA_SYNC_MODE_MAX = 255,
+}sync_mode;
+
+typedef struct speed{
+ u32 mNumerator;
+ u32 mDenominator;
+}mediasync_speed;
+
+typedef struct instance{
+ s32 mSyncInsId;
+ s32 mDemuxId;
+ s32 mPcrPid;
+ s32 mPaused;
+ s32 mRef;
+ s32 mSyncMode;
+ s64 mLastStc;
+ s64 mLastRealTime;
+ s64 mLastMediaTime;
+ s64 mTrackMediaTime;
+ mediasync_speed mSpeed;
+ u64 last_system;
+ u64 last_pcr;
+}mediasync_ins;
+
+long mediasync_ins_alloc(s32 sDemuxId,
+ s32 sPcrPid,
+ s32 *sSyncInsId,
+ mediasync_ins **pIns);
+
+long mediasync_ins_delete(s32 sSyncInsId);
+long mediasync_ins_binder(s32 sSyncInsId,
+ mediasync_ins **pIns);
+long mediasync_ins_unbinder(s32 sSyncInsId);
+long mediasync_ins_update_mediatime(s32 sSyncInsId,
+ s64 lMediaTime,
+ s64 lSystemTime, bool forceUpdate);
+long mediasync_ins_set_mediatime_speed(s32 sSyncInsId, mediasync_speed fSpeed);
+long mediasync_ins_set_paused(s32 sSyncInsId, s32 sPaused);
+long mediasync_ins_get_paused(s32 sSyncInsId, s32* spPaused);
+long mediasync_ins_get_trackmediatime(s32 sSyncInsId, s64* lpTrackMediaTime);
+long mediasync_ins_set_syncmode(s32 sSyncInsId, s32 sSyncMode);
+long mediasync_ins_get_syncmode(s32 sSyncInsId, s32 *sSyncMode);
+long mediasync_ins_get_mediatime_speed(s32 sSyncInsId, mediasync_speed *fpSpeed);
+long mediasync_ins_get_anchor_time(s32 sSyncInsId,
+ s64* lpMediaTime,
+ s64* lpSTCTime,
+ s64* lpSystemTime);
+long mediasync_ins_get_systemtime(s32 sSyncInsId,
+ s64* lpSTC,
+ s64* lpSystemTime);
+long mediasync_ins_get_nextvsync_systemtime(s32 sSyncInsId, s64* lpSystemTime);
+#endif
+
+
diff --git a/drivers/media_sync/media_sync_debug.c b/drivers/media_sync/media_sync_debug.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/media_sync/media_sync_debug.c
diff --git a/drivers/media_sync/media_sync_dev.c b/drivers/media_sync/media_sync_dev.c
new file mode 100644
index 0000000..af0f786
--- /dev/null
+++ b/drivers/media_sync/media_sync_dev.c
@@ -0,0 +1,418 @@
+/*
+ * drivers/amlogic/media/frame_sync/tsync_pcr.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+
+#include <linux/platform_device.h>
+#include <linux/amlogic/cpu_version.h>
+#include <linux/amlogic/major.h>
+#include "media_sync_core.h"
+#include "media_sync_dev.h"
+
+#define MEDIASYNC_DEVICE_NAME "mediasync"
+static struct device *mediasync_dev;
+
+typedef struct alloc_para {
+ s32 mDemuxId;
+ s32 mPcrPid;
+} mediasync_alloc_para;
+
+typedef struct systime_para {
+ s64 mStcUs;
+ s64 mSystemTimeUs;
+}mediasync_systime_para;
+
+typedef struct updatetime_para {
+ int64_t mMediaTimeUs;
+ int64_t mSystemTimeUs;
+ bool mForceUpdate;
+}mediasync_updatetime_para;
+
+typedef struct arthortime_para {
+ int64_t mMediaTimeUs;
+ int64_t mSystemTimeUs;
+ int64_t mStcTimeUs;
+}mediasync_arthortime_para;
+
+typedef struct priv_s {
+ s32 mSyncInsId;
+ mediasync_ins *mSyncIns;
+}mediasync_priv_s;
+
+static int mediasync_open(struct inode *inode, struct file *file)
+{
+ mediasync_priv_s *priv = {0};
+ priv = kzalloc(sizeof(mediasync_priv_s), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+ priv->mSyncInsId = -1;
+ priv->mSyncIns = NULL;
+ file->private_data = priv;
+ return 0;
+}
+
+static int mediasync_release(struct inode *inode, struct file *file)
+{
+ long ret = 0;
+ mediasync_priv_s *priv = (mediasync_priv_s *)file->private_data;
+ if (priv == NULL) {
+ return -ENOMEM;
+ }
+
+ if (priv->mSyncInsId != -1) {
+ ret = mediasync_ins_unbinder(priv->mSyncInsId);
+ priv->mSyncInsId = -1;
+ priv->mSyncIns = NULL;
+ }
+ kfree(priv);
+ return 0;
+}
+
+static long mediasync_ioctl(struct file *file, unsigned int cmd, ulong arg)
+{
+ long ret = 0;
+ mediasync_speed SyncSpeed = {0};
+ s32 SyncInsId = -1;
+ s32 SyncPaused = 0;
+ s32 SyncMode = -1;
+ s64 NextVsyncSystemTime = 0;
+ s64 TrackMediaTime = 0;
+
+ mediasync_priv_s *priv = (mediasync_priv_s *)file->private_data;
+ mediasync_ins *SyncIns = NULL;
+ mediasync_alloc_para parm = {0};
+ mediasync_arthortime_para ArthorTime = {0};
+ mediasync_updatetime_para UpdateTime = {0};
+ mediasync_systime_para SystemTime = {0};
+ switch (cmd) {
+ case MEDIASYNC_IOC_INSTANCE_ALLOC:
+ if (copy_from_user ((void *)&parm,
+ (void *)arg,
+ sizeof(parm)))
+ return -EFAULT;
+ if (mediasync_ins_alloc(parm.mDemuxId,
+ parm.mPcrPid,
+ &SyncInsId,
+ &SyncIns) < 0) {
+ return -EFAULT;
+ }
+ if (SyncIns == NULL) {
+ return -EFAULT;
+ }
+ if (priv != NULL) {
+ priv->mSyncInsId = SyncInsId;
+ priv->mSyncIns = SyncIns;
+ priv->mSyncIns->mRef++;
+ }
+
+ break;
+ case MEDIASYNC_IOC_INSTANCE_GET:
+ if (priv->mSyncIns == NULL) {
+ return -EFAULT;
+ }
+
+ SyncInsId = priv->mSyncInsId;
+ if (copy_to_user((void *)arg,
+ &SyncInsId,
+ sizeof(SyncInsId))) {
+ return -EFAULT;
+ }
+ break;
+ case MEDIASYNC_IOC_INSTANCE_BINDER:
+ if (copy_from_user((void *)&SyncInsId,
+ (void *)arg,
+ sizeof(parm))) {
+ return -EFAULT;
+ }
+ ret = mediasync_ins_binder(SyncInsId, &SyncIns);
+ if (SyncIns == NULL) {
+ return -EFAULT;
+ }
+
+ priv->mSyncInsId = SyncInsId;
+ priv->mSyncIns = SyncIns;
+ break;
+
+ case MEDIASYNC_IOC_UPDATE_MEDIATIME:
+ if (copy_from_user((void *)&UpdateTime,
+ (void *)arg,
+ sizeof(UpdateTime))) {
+ return -EFAULT;
+ }
+ if (priv->mSyncIns == NULL) {
+ return -EFAULT;
+ }
+
+ ret = mediasync_ins_update_mediatime(priv->mSyncInsId,
+ UpdateTime.mMediaTimeUs,
+ UpdateTime.mSystemTimeUs,
+ UpdateTime.mForceUpdate);
+ break;
+
+ case MEDIASYNC_IOC_GET_MEDIATIME:
+ if (priv->mSyncIns == NULL) {
+ return -EFAULT;
+ }
+ ret = mediasync_ins_get_anchor_time(priv->mSyncInsId,
+ &(ArthorTime.mMediaTimeUs),
+ &(ArthorTime.mStcTimeUs),
+ &(ArthorTime.mSystemTimeUs));
+ if (ret == 0) {
+ if (copy_to_user((void *)arg,
+ &ArthorTime,
+ sizeof(ArthorTime))) {
+ return -EFAULT;
+ }
+ }
+ break;
+
+ case MEDIASYNC_IOC_GET_SYSTEMTIME:
+
+ if (priv->mSyncIns == NULL) {
+ return -EFAULT;
+ }
+
+ ret = mediasync_ins_get_systemtime(priv->mSyncInsId,
+ &(SystemTime.mStcUs),
+ &(SystemTime.mSystemTimeUs));
+ if (ret == 0) {
+ if (copy_to_user((void *)arg,
+ &SystemTime,
+ sizeof(SystemTime))) {
+ return -EFAULT;
+ }
+ }
+ break;
+
+ case MEDIASYNC_IOC_GET_NEXTVSYNC_TIME:
+ if (priv->mSyncIns == NULL)
+ return -EFAULT;
+
+ ret = mediasync_ins_get_nextvsync_systemtime(priv->mSyncInsId,
+ &NextVsyncSystemTime);
+ if (ret == 0) {
+ if (copy_to_user((void *)arg,
+ &NextVsyncSystemTime,
+ sizeof(NextVsyncSystemTime)))
+ return -EFAULT;
+ }
+ break;
+
+ case MEDIASYNC_IOC_SET_SPEED:
+ if (copy_from_user((void *)&SyncSpeed,
+ (void *)arg,
+ sizeof(SyncSpeed)))
+ return -EFAULT;
+
+ if (priv->mSyncIns == NULL)
+ return -EFAULT;
+
+ ret = mediasync_ins_set_mediatime_speed(priv->mSyncInsId,
+ SyncSpeed);
+ break;
+
+ case MEDIASYNC_IOC_GET_SPEED:
+ if (priv->mSyncIns == NULL)
+ return -EFAULT;
+
+ ret = mediasync_ins_get_mediatime_speed(priv->mSyncInsId,
+ &SyncSpeed);
+ if (ret == 0) {
+ if (copy_to_user((void *)arg,
+ &SyncSpeed,
+ sizeof(SyncSpeed)))
+ return -EFAULT;
+ }
+ break;
+
+ case MEDIASYNC_IOC_SET_PAUSE:
+ if (copy_from_user((void *)&SyncPaused,
+ (void *)arg,
+ sizeof(SyncPaused)))
+ return -EFAULT;
+
+ if (priv->mSyncIns == NULL)
+ return -EFAULT;
+
+ ret = mediasync_ins_set_paused(priv->mSyncInsId,
+ SyncPaused);
+ break;
+
+ case MEDIASYNC_IOC_GET_PAUSE:
+ if (priv->mSyncIns == NULL)
+ return -EFAULT;
+
+ ret = mediasync_ins_get_paused(priv->mSyncInsId,
+ &SyncPaused);
+ if (ret == 0) {
+ if (copy_to_user((void *)arg,
+ &SyncPaused,
+ sizeof(SyncPaused)))
+ return -EFAULT;
+ }
+ break;
+
+ case MEDIASYNC_IOC_SET_SYNCMODE:
+ if (copy_from_user((void *)&SyncMode,
+ (void *)arg,
+ sizeof(SyncMode)))
+ return -EFAULT;
+
+ if (priv->mSyncIns == NULL)
+ return -EFAULT;
+
+ ret = mediasync_ins_set_syncmode(priv->mSyncInsId,
+ SyncMode);
+ break;
+
+ case MEDIASYNC_IOC_GET_SYNCMODE:
+ if (priv->mSyncIns == NULL)
+ return -EFAULT;
+
+ ret = mediasync_ins_get_syncmode(priv->mSyncInsId,
+ &SyncMode);
+ if (ret == 0) {
+ if (copy_to_user((void *)arg,
+ &SyncMode,
+ sizeof(SyncMode)))
+ return -EFAULT;
+ }
+ break;
+ case MEDIASYNC_IOC_GET_TRACKMEDIATIME:
+ if (priv->mSyncIns == NULL) {
+ return -EFAULT;
+ }
+
+ ret = mediasync_ins_get_trackmediatime(priv->mSyncInsId,
+ &TrackMediaTime);
+ if (ret == 0) {
+ if (copy_to_user((void *)arg,
+ &TrackMediaTime,
+ sizeof(TrackMediaTime))) {
+ return -EFAULT;
+ }
+ }
+ break;
+
+ default:
+ pr_info("invalid cmd:%d\n", cmd);
+ break;
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static long mediasync_compat_ioctl(struct file *file, unsigned int cmd, ulong arg)
+{
+ long ret = 0;
+ switch (cmd) {
+ case MEDIASYNC_IOC_INSTANCE_ALLOC:
+ case MEDIASYNC_IOC_INSTANCE_GET:
+ case MEDIASYNC_IOC_INSTANCE_BINDER:
+ case MEDIASYNC_IOC_UPDATE_MEDIATIME:
+ case MEDIASYNC_IOC_GET_MEDIATIME:
+ case MEDIASYNC_IOC_GET_SYSTEMTIME:
+ case MEDIASYNC_IOC_GET_NEXTVSYNC_TIME:
+ case MEDIASYNC_IOC_SET_SPEED:
+ case MEDIASYNC_IOC_GET_SPEED:
+ case MEDIASYNC_IOC_SET_PAUSE:
+ case MEDIASYNC_IOC_GET_PAUSE:
+ case MEDIASYNC_IOC_SET_SYNCMODE:
+ case MEDIASYNC_IOC_GET_SYNCMODE:
+ case MEDIASYNC_IOC_GET_TRACKMEDIATIME:
+ return mediasync_ioctl(file, cmd, arg);
+ default:
+ return -EINVAL;
+ }
+ return ret;
+}
+#endif
+
+static const struct file_operations mediasync_fops = {
+ .owner = THIS_MODULE,
+ .open = mediasync_open,
+ .release = mediasync_release,
+ .unlocked_ioctl = mediasync_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = mediasync_compat_ioctl,
+#endif
+};
+
+static struct class_attribute mediasync_class_attrs[] = {
+ __ATTR_NULL
+};
+
+static struct class mediasync_class = {
+ .name = "mediasync",
+ .class_attrs = mediasync_class_attrs,
+};
+
+static int __init mediasync_module_init(void)
+{
+ int r;
+
+ r = class_register(&mediasync_class);
+
+ if (r) {
+ pr_err("mediasync class create fail.\n");
+ return r;
+ }
+
+ /* create tsync device */
+ r = register_chrdev(MEDIASYNC_MAJOR, "mediasync", &mediasync_fops);
+ if (r < 0) {
+ pr_info("Can't register major for tsync\n");
+ goto err2;
+ }
+
+ mediasync_dev = device_create(&mediasync_class, NULL,
+ MKDEV(MEDIASYNC_MAJOR, 0), NULL, MEDIASYNC_DEVICE_NAME);
+
+ if (IS_ERR(mediasync_dev)) {
+ pr_err("Can't create mediasync_dev device\n");
+ goto err1;
+ }
+ return 0;
+
+err1:
+ unregister_chrdev(MEDIASYNC_MAJOR, "mediasync");
+err2:
+ class_unregister(&mediasync_class);
+
+ return 0;
+}
+
+static void __exit mediasync_module_exit(void)
+{
+ device_destroy(&mediasync_class, MKDEV(MEDIASYNC_MAJOR, 0));
+ unregister_chrdev(MEDIASYNC_MAJOR, "mediasync");
+ class_unregister(&mediasync_class);
+}
+
+module_init(mediasync_module_init);
+module_exit(mediasync_module_exit);
+
+MODULE_DESCRIPTION("AMLOGIC media sync management driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lifeng Cao <lifeng.cao@amlogic.com>");
+
diff --git a/drivers/media_sync/media_sync_dev.h b/drivers/media_sync/media_sync_dev.h
new file mode 100644
index 0000000..3e0c147
--- /dev/null
+++ b/drivers/media_sync/media_sync_dev.h
@@ -0,0 +1,21 @@
+#ifndef MEDIA_SYNC_DEV_HEAD_HH
+#define MEDIA_SYNC_DEV_HEAD_HH
+
+#define MEDIASYNC_IOC_MAGIC 'M'
+
+#define MEDIASYNC_IOC_INSTANCE_ALLOC _IOW(MEDIASYNC_IOC_MAGIC, 0x01, int)
+#define MEDIASYNC_IOC_INSTANCE_GET _IOW(MEDIASYNC_IOC_MAGIC, 0x02, int)
+#define MEDIASYNC_IOC_INSTANCE_BINDER _IOW(MEDIASYNC_IOC_MAGIC, 0x03, int)
+#define MEDIASYNC_IOC_UPDATE_MEDIATIME _IOW(MEDIASYNC_IOC_MAGIC, 0x04, int)
+#define MEDIASYNC_IOC_GET_MEDIATIME _IOW(MEDIASYNC_IOC_MAGIC, 0x05, int)
+#define MEDIASYNC_IOC_GET_SYSTEMTIME _IOW(MEDIASYNC_IOC_MAGIC, 0x06, int)
+#define MEDIASYNC_IOC_GET_NEXTVSYNC_TIME _IOW(MEDIASYNC_IOC_MAGIC, 0x07, int)
+#define MEDIASYNC_IOC_SET_SPEED _IOW(MEDIASYNC_IOC_MAGIC, 0x08, int)
+#define MEDIASYNC_IOC_GET_SPEED _IOW(MEDIASYNC_IOC_MAGIC, 0x09, int)
+#define MEDIASYNC_IOC_SET_PAUSE _IOW(MEDIASYNC_IOC_MAGIC, 0x0A, int)
+#define MEDIASYNC_IOC_GET_PAUSE _IOW(MEDIASYNC_IOC_MAGIC, 0x0B, int)
+#define MEDIASYNC_IOC_SET_SYNCMODE _IOW(MEDIASYNC_IOC_MAGIC, 0x0C, int)
+#define MEDIASYNC_IOC_GET_SYNCMODE _IOW(MEDIASYNC_IOC_MAGIC, 0x0D, int)
+#define MEDIASYNC_IOC_GET_TRACKMEDIATIME _IOW(MEDIASYNC_IOC_MAGIC, 0x0E, int)
+
+#endif
diff --git a/drivers/stream_input/Makefile b/drivers/stream_input/Makefile
new file mode 100644
index 0000000..aa248ea
--- /dev/null
+++ b/drivers/stream_input/Makefile
@@ -0,0 +1,26 @@
+obj-m += stream_input.o
+
+stream_input-objs += amports/amstream.o
+stream_input-objs += amports/adec.o
+stream_input-objs += amports/thread_rw.o
+stream_input-objs += amports/streambuf.o
+stream_input-objs += amports/stream_buffer_base.o
+stream_input-objs += amports/stream_buffer_interface.o
+
+stream_input-objs += parser/esparser.o
+stream_input-objs += parser/tsdemux.o
+stream_input-objs += parser/psparser.o
+stream_input-objs += parser/rmparser.o
+stream_input-objs += parser/dvb_common.o
+stream_input-objs += subtitle/subtitle.o
+
+obj-$(CONFIG_AMLOGIC_DVB) += parser/hw_demux/
+obj-$(CONFIG_AMLOGIC_DVB) += parser/dvb_ci/
+
+ccflags-y += -I.
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
+
+#obj-y += tv_frontend/
+# obj-y += box-frontend/avl6211/
+# obj-y += box-frontend/atbm8881/
+# obj-y += box-frontend/avl68xx/
diff --git a/drivers/stream_input/amports/Makefile b/drivers/stream_input/amports/Makefile
new file mode 100644
index 0000000..82f5934
--- /dev/null
+++ b/drivers/stream_input/amports/Makefile
@@ -0,0 +1,2 @@
+obj-y += amports.o
+amports-objs += amstream.o adec.o
diff --git a/drivers/stream_input/amports/adec.c b/drivers/stream_input/amports/adec.c
new file mode 100644
index 0000000..b6da9ea
--- /dev/null
+++ b/drivers/stream_input/amports/adec.c
@@ -0,0 +1,415 @@
+/*
+ * drivers/amlogic/media/stream_input/amports/adec.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/types.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/uio_driver.h>
+#include <linux/amlogic/media/utils/aformat.h>
+#include <linux/amlogic/media/frame_sync/ptsserv.h>
+#include <linux/amlogic/media/registers/register.h>
+#include <linux/amlogic/media/codec_mm/configs.h>
+#include "../amports/streambuf.h"
+#include <linux/module.h>
+#include <linux/of.h>
+#include "amports_priv.h"
+#include "../../common/chips/decoder_cpu_ver_info.h"
+#define INFO_VALID ((astream_dev) && (astream_dev->format))
+
+struct astream_device_s {
+ char *name;
+ char *format;
+ s32 channum;
+ s32 samplerate;
+ s32 datawidth;
+ int offset;
+
+ struct device dev;
+};
+
+static char *astream_format[] = {
+ "amadec_mpeg",
+ "amadec_pcm_s16le",
+ "amadec_aac",
+ "amadec_ac3",
+ "amadec_alaw",
+ "amadec_mulaw",
+ "amadec_dts",
+ "amadec_pcm_s16be",
+ "amadec_flac",
+ "amadec_cook",
+ "amadec_pcm_u8",
+ "amadec_adpcm",
+ "amadec_amr",
+ "amadec_raac",
+ "amadec_wma",
+ "amadec_wmapro",
+ "amadec_pcm_bluray",
+ "amadec_alac",
+ "amadec_vorbis",
+ "amadec_aac_latm",
+ "amadec_ape",
+ "amadec_eac3",
+ "amadec_pcm_widi",
+ "amadec_dra",
+ "amadec_sipr",
+ "amadec_truehd",
+ "amadec_mpeg1",
+ "amadec_mpeg2",
+ "amadec_wmavoi",
+ "amadec_wmalossless",
+ "amadec_pcm_s24le",
+ "adec_max"
+};
+
+static const char *na_string = "NA";
+static struct astream_device_s *astream_dev;
+
+static ssize_t format_show(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ if (INFO_VALID && astream_dev->format)
+ return sprintf(buf, "%s\n", astream_dev->format);
+ else
+ return sprintf(buf, "%s\n", na_string);
+}
+
+static ssize_t channum_show(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ if (INFO_VALID)
+ return sprintf(buf, "%u\n", astream_dev->channum);
+ else
+ return sprintf(buf, "%s\n", na_string);
+}
+
+static ssize_t samplerate_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ if (INFO_VALID)
+ return sprintf(buf, "%u\n", astream_dev->samplerate);
+ else
+ return sprintf(buf, "%s\n", na_string);
+}
+
+static ssize_t datawidth_show(struct class *class,
+ struct class_attribute *attr,
+ char *buf)
+{
+ if (INFO_VALID)
+ return sprintf(buf, "%u\n", astream_dev->datawidth);
+ else
+ return sprintf(buf, "%s\n", na_string);
+}
+
+static ssize_t pts_show(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ u32 pts, frame_size;
+ u32 pts_margin = 0;
+
+ if (astream_dev->samplerate <= 12000)
+ pts_margin = 512;
+
+ if (INFO_VALID && (pts_lookup(PTS_TYPE_AUDIO, &pts,
+ &frame_size, pts_margin) >= 0))
+ return sprintf(buf, "0x%x\n", pts);
+ else
+ return sprintf(buf, "%s\n", na_string);
+}
+
+static ssize_t addr_offset_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", astream_dev->offset);
+}
+
+static struct class_attribute astream_class_attrs[] = {
+ __ATTR_RO(format),
+ __ATTR_RO(samplerate),
+ __ATTR_RO(channum),
+ __ATTR_RO(datawidth),
+ __ATTR_RO(pts),
+ __ATTR_RO(addr_offset),
+ __ATTR_NULL
+};
+
+static struct class astream_class = {
+ .name = "astream",
+ .class_attrs = astream_class_attrs,
+ };
+
+#if 1
+#define IO_CBUS_PHY_BASE 0xc1100000ULL
+#define IO_AOBUS_PHY_BASE 0xc8100000ULL
+#define CBUS_REG_OFFSET(reg) ((reg) << 2)
+#define IO_SECBUS_PHY_BASE 0xda000000ULL
+
+
+#define IO_AOBUS_PHY_BASE_AFTER_G12A 0xff800000ULL
+
+static struct uio_info astream_uio_info = {
+ .name = "astream_uio",
+ .version = "0.1",
+ .irq = UIO_IRQ_NONE,
+
+ .mem = {
+ [0] = {
+ .name = "AIFIFO",
+ .memtype = UIO_MEM_PHYS,
+ .addr =
+ (IO_CBUS_PHY_BASE + CBUS_REG_OFFSET(AIU_AIFIFO_CTRL))
+ &(PAGE_MASK),
+ .size = PAGE_SIZE,
+ },
+ [1] = {
+ .memtype = UIO_MEM_PHYS,
+ .addr =
+ (IO_CBUS_PHY_BASE + CBUS_REG_OFFSET(VCOP_CTRL_REG)),
+ .size = PAGE_SIZE,
+ },
+/*
+ [2] = {
+ .name = "SECBUS",
+ .memtype = UIO_MEM_PHYS,
+ .addr = (IO_SECBUS_PHY_BASE),
+ .size = PAGE_SIZE,
+ },
+*/
+ [2] = {
+ .name = "CBUS",
+ .memtype = UIO_MEM_PHYS,
+ .addr =
+ (IO_CBUS_PHY_BASE + CBUS_REG_OFFSET(ASSIST_HW_REV))
+ &(PAGE_MASK),
+ .size = PAGE_SIZE,
+ },
+ [3] = {
+ .name = "CBUS-START",
+ .memtype = UIO_MEM_PHYS,
+ .addr = (IO_CBUS_PHY_BASE + CBUS_REG_OFFSET(0x1000)),
+ .size = PAGE_SIZE,
+ },
+ [4] = {
+ .name = "AOBUS-START",
+ .memtype = UIO_MEM_PHYS,
+ .addr = (IO_AOBUS_PHY_BASE),
+ .size = PAGE_SIZE,
+ },
+ },
+};
+#endif
+
+static void astream_release(struct device *dev)
+{
+ kfree(astream_dev);
+
+ astream_dev = NULL;
+}
+
+s32 adec_init(struct stream_port_s *port)
+{
+ enum aformat_e af;
+
+ if (!astream_dev)
+ return -ENODEV;
+
+ af = port->aformat;
+
+ astream_dev->channum = port->achanl;
+ astream_dev->samplerate = port->asamprate;
+ astream_dev->datawidth = port->adatawidth;
+
+ /*wmb();don't need it...*/
+ if (af < ARRAY_SIZE(astream_format))
+ astream_dev->format = astream_format[af];
+ else
+ astream_dev->format = NULL;
+ return 0;
+}
+EXPORT_SYMBOL(adec_init);
+
+s32 adec_release(enum aformat_e vf)
+{
+ pr_info("adec_release\n");
+
+ if (!astream_dev)
+ return -ENODEV;
+
+ astream_dev->format = NULL;
+
+ return 0;
+}
+EXPORT_SYMBOL(adec_release);
+
+int amstream_adec_show_fun(const char *trigger, int id, char *sbuf, int size)
+{
+ int ret = -1;
+ void *buf, *getbuf = NULL;
+ if (size < PAGE_SIZE) {
+ getbuf = (void *)__get_free_page(GFP_KERNEL);
+ if (!getbuf)
+ return -ENOMEM;
+ buf = getbuf;
+ } else {
+ buf = sbuf;
+ }
+ switch (trigger[0]) {
+ case 'f':
+ ret = format_show(NULL, NULL, buf);
+ break;
+ case 's':
+ ret = samplerate_show(NULL, NULL, buf);
+ break;
+ case 'c':
+ ret = channum_show(NULL, NULL, buf);
+ break;
+ case 'd':
+ ret = datawidth_show(NULL, NULL, buf);
+ break;
+ case 'p':
+ ret = pts_show(NULL, NULL, buf);
+ break;
+ default:
+ ret = -1;
+ }
+ if (ret > 0 && getbuf != NULL) {
+ ret = min_t(int, ret, size);
+ strncpy(sbuf, buf, ret);
+ }
+ if (getbuf != NULL)
+ free_page((unsigned long)getbuf);
+ return ret;
+}
+
+static struct mconfig adec_configs[] = {
+ MC_FUN("format", &amstream_adec_show_fun, NULL),
+ MC_FUN("samplerate", &amstream_adec_show_fun, NULL),
+ MC_FUN("channum", &amstream_adec_show_fun, NULL),
+ MC_FUN("datawidth", &amstream_adec_show_fun, NULL),
+ MC_FUN("pts", &amstream_adec_show_fun, NULL),
+};
+static struct mconfig_node adec_node;
+
+
+s32 astream_dev_register(void)
+{
+ s32 r;
+ struct device_node *node;
+ unsigned int cbus_base = 0xffd00000;
+
+ r = class_register(&astream_class);
+ if (r) {
+ pr_info("astream class create fail.\n");
+ return r;
+ }
+
+ astream_dev = kzalloc(sizeof(struct astream_device_s), GFP_KERNEL);
+
+ if (!astream_dev) {
+ pr_info("astream device create fail.\n");
+ r = -ENOMEM;
+ goto err_3;
+ }
+
+ astream_dev->dev.class = &astream_class;
+ astream_dev->dev.release = astream_release;
+ astream_dev->offset = 0;
+ dev_set_name(&astream_dev->dev, "astream-dev");
+
+ dev_set_drvdata(&astream_dev->dev, astream_dev);
+
+ r = device_register(&astream_dev->dev);
+ if (r) {
+ pr_info("astream device register fail.\n");
+ goto err_2;
+ }
+
+ if (AM_MESON_CPU_MAJOR_ID_TXL < get_cpu_major_id()
+ && MESON_CPU_MAJOR_ID_GXLX != get_cpu_type()) {
+ node = of_find_node_by_path("/codec_io/io_cbus_base");
+ if (!node) {
+ pr_info("No io_cbus_base node found.");
+ goto err_1;
+ }
+
+#ifdef CONFIG_ARM64_A32
+ r = of_property_read_u32_index(node, "reg", 0, &cbus_base);
+#else
+ r = of_property_read_u32_index(node, "reg", 1, &cbus_base);
+#endif
+ if (r) {
+ pr_info("No find node.\n");
+ goto err_1;
+ }
+
+ /*need to offset -0x100 in txlx.*/
+ astream_dev->offset = -0x100;
+
+ /*need to offset -0x180 in g12a.*/
+ if (AM_MESON_CPU_MAJOR_ID_G12A <= get_cpu_major_id()) {
+ astream_dev->offset = -0x180;
+ /* after G12A chip, the aobus base addr changed */
+ astream_uio_info.mem[4].addr = IO_AOBUS_PHY_BASE_AFTER_G12A;
+ }
+ astream_uio_info.mem[0].addr =
+ (cbus_base + CBUS_REG_OFFSET(AIU_AIFIFO_CTRL +
+ astream_dev->offset)) & (PAGE_MASK);
+
+ astream_uio_info.mem[3].addr =
+ (cbus_base + CBUS_REG_OFFSET(ASSIST_HW_REV +
+ 0x100)) & (PAGE_MASK);
+ }
+
+#if 1
+ if (uio_register_device(&astream_dev->dev, &astream_uio_info)) {
+ pr_info("astream UIO device register fail.\n");
+ r = -ENODEV;
+ goto err_1;
+ }
+#endif
+ INIT_REG_NODE_CONFIGS("media", &adec_node,
+ "adec", adec_configs, CONFIG_FOR_R);
+ return 0;
+
+err_1:
+ device_unregister(&astream_dev->dev);
+
+err_2:
+ kfree(astream_dev);
+ astream_dev = NULL;
+
+err_3:
+ class_unregister(&astream_class);
+
+ return r;
+}
+
+void astream_dev_unregister(void)
+{
+ if (astream_dev) {
+#if 1
+ uio_unregister_device(&astream_uio_info);
+#endif
+
+ device_unregister(&astream_dev->dev);
+
+ class_unregister(&astream_class);
+ }
+}
diff --git a/drivers/stream_input/amports/adec.h b/drivers/stream_input/amports/adec.h
new file mode 100644
index 0000000..1ad276f
--- /dev/null
+++ b/drivers/stream_input/amports/adec.h
@@ -0,0 +1,32 @@
+/*
+ * drivers/amlogic/media/stream_input/amports/adec.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 ADEC_H
+#define ADEC_H
+
+#include "../amports/streambuf.h"
+#include <linux/amlogic/media/utils/aformat.h>
+
+extern s32 adec_init(struct stream_port_s *port);
+
+extern s32 adec_release(enum aformat_e af);
+
+extern s32 astream_dev_register(void);
+
+extern s32 astream_dev_unregister(void);
+
+#endif /* ADEC_H */
diff --git a/drivers/stream_input/amports/amports_priv.h b/drivers/stream_input/amports/amports_priv.h
new file mode 100644
index 0000000..296b94a
--- /dev/null
+++ b/drivers/stream_input/amports/amports_priv.h
@@ -0,0 +1,56 @@
+/*
+ * drivers/amlogic/media/stream_input/amports/amports_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_PRIV_HEAD_HH
+#define AMPORTS_PRIV_HEAD_HH
+#include "../amports/streambuf.h"
+#include "../../common/media_clock/switch/amports_gate.h"
+#include <linux/amlogic/media/vfm/vframe.h>
+#include <linux/amlogic/media/registers/register.h>
+#include <linux/amlogic/media/utils/log.h>
+
+struct port_priv_s {
+ struct vdec_s *vdec;
+ struct stream_port_s *port;
+ struct mutex mutex;
+};
+
+struct stream_buf_s *get_buf_by_type(u32 type);
+
+/*video.c provide*/
+extern u32 trickmode_i;
+struct amvideocap_req;
+extern u32 set_blackout_policy(int policy);
+extern u32 get_blackout_policy(void);
+int calculation_stream_ext_delayed_ms(u8 type);
+int ext_get_cur_video_frame(struct vframe_s **vf, int *canvas_index);
+int ext_put_video_frame(struct vframe_s *vf);
+int ext_register_end_frame_callback(struct amvideocap_req *req);
+int amstream_request_firmware_from_sys(const char *file_name,
+ char *buf, int size);
+void set_vsync_pts_inc_mode(int inc);
+
+void set_real_audio_info(void *arg);
+void amstream_wakeup_userdata_poll(struct vdec_s *vdec);
+#define dbg() pr_info("on %s,line %d\n", __func__, __LINE__);
+
+struct device *amports_get_dma_device(void);
+struct device *get_codec_cma_device(void);
+
+void amstream_wakeup_fcc_poll(struct vdec_s *vdec);
+
+#endif
diff --git a/drivers/stream_input/amports/amstream.c b/drivers/stream_input/amports/amstream.c
new file mode 100644
index 0000000..a089a6b
--- /dev/null
+++ b/drivers/stream_input/amports/amstream.c
@@ -0,0 +1,4888 @@
+/*
+ * drivers/amlogic/media/stream_input/amports/amstream.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/module.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/amlogic/major.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+
+#include <linux/amlogic/media/video_sink/video.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/video_sink/video.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/types.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+/* #include <mach/am_regs.h> */
+
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma-contiguous.h>
+#include <linux/uaccess.h>
+#include <linux/clk.h>
+#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+/* #include <mach/mod_gate.h> */
+/* #include <mach/power_gate.h> */
+#endif
+#include "../amports/streambuf.h"
+#include "../amports/streambuf_reg.h"
+#include "../parser/tsdemux.h"
+#include "../parser/psparser.h"
+#include "../parser/esparser.h"
+#include "../../frame_provider/decoder/utils/vdec.h"
+#include "adec.h"
+#include "../parser/rmparser.h"
+#include "amports_priv.h"
+#include <linux/amlogic/media/utils/amports_config.h>
+#include <linux/amlogic/media/frame_sync/tsync_pcr.h>
+#include "../amports/thread_rw.h"
+#include <linux/firmware.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/libfdt_env.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/reset.h>
+#ifdef CONFIG_COMPAT
+#include <linux/compat.h>
+#endif
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include <linux/amlogic/media/codec_mm/configs.h>
+#include "../../frame_provider/decoder/utils/firmware.h"
+#include "../../common/chips/chips.h"
+#include "../../common/chips/decoder_cpu_ver_info.h"
+#include "../subtitle/subtitle.h"
+#include "stream_buffer_base.h"
+
+//#define G12A_BRINGUP_DEBUG
+
+#define CONFIG_AM_VDEC_REAL //DEBUG_TMP
+
+#define DEVICE_NAME "amstream-dev"
+#define DRIVER_NAME "amstream"
+#define MODULE_NAME "amstream"
+
+#define MAX_AMSTREAM_PORT_NUM ARRAY_SIZE(ports)
+u32 amstream_port_num;
+u32 amstream_buf_num;
+
+u32 amstream_audio_reset = 0;
+
+#if 0
+#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESONG9TV
+#define NO_VDEC2_INIT 1
+#elif MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6TVD
+#define NO_VDEC2_INIT IS_MESON_M8M2_CPU
+#endif
+#endif
+#define NO_VDEC2_INIT 1
+
+#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)
+
+static int def_4k_vstreambuf_sizeM =
+ (DEFAULT_VIDEO_BUFFER_SIZE_4K >> 20);
+static int def_vstreambuf_sizeM =
+ (DEFAULT_VIDEO_BUFFER_SIZE >> 20);
+static int slow_input;
+
+/* #define DATA_DEBUG */
+static int use_bufferlevelx10000 = 10000;
+static int reset_canuse_buferlevel(int level);
+static struct platform_device *amstream_pdev;
+struct device *amports_get_dma_device(void)
+{
+ return &amstream_pdev->dev;
+}
+EXPORT_SYMBOL(amports_get_dma_device);
+
+#ifdef DATA_DEBUG
+#include <linux/fs.h>
+
+#define DEBUG_FILE_NAME "/sdcard/debug.tmp"
+static struct file *debug_filp;
+static loff_t debug_file_pos;
+
+void debug_file_write(const char __user *buf, size_t count)
+{
+ mm_segment_t old_fs;
+
+ if (!debug_filp)
+ return;
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ if (count != vfs_write(debug_filp, buf, count, &debug_file_pos))
+ pr_err("Failed to write debug file\n");
+
+ set_fs(old_fs);
+}
+#endif
+
+
+
+static int amstream_open(struct inode *inode, struct file *file);
+static int amstream_release(struct inode *inode, struct file *file);
+static long amstream_ioctl(struct file *file, unsigned int cmd, ulong arg);
+#ifdef CONFIG_COMPAT
+static long amstream_compat_ioctl
+ (struct file *file, unsigned int cmd, ulong arg);
+#endif
+static ssize_t amstream_vbuf_write
+(struct file *file, const char *buf, size_t count, loff_t *ppos);
+static ssize_t amstream_vframe_write
+(struct file *file, const char *buf, size_t count, loff_t *ppos);
+static ssize_t amstream_abuf_write
+(struct file *file, const char *buf, size_t count, loff_t *ppos);
+static ssize_t amstream_mpts_write
+(struct file *file, const char *buf, size_t count, loff_t *ppos);
+static ssize_t amstream_mpps_write
+(struct file *file, const char *buf, size_t count, loff_t *ppos);
+static ssize_t amstream_sub_read
+(struct file *file, char *buf, size_t count, loff_t *ppos);
+static ssize_t amstream_sub_write
+(struct file *file, const char *buf, size_t count, loff_t *ppos);
+static unsigned int amstream_sub_poll
+(struct file *file, poll_table *wait_table);
+static unsigned int amstream_userdata_poll
+(struct file *file, poll_table *wait_table);
+static int (*amstream_adec_status)
+(struct adec_status *astatus);
+#ifdef CONFIG_AM_VDEC_REAL
+static ssize_t amstream_mprm_write
+(struct file *file, const char *buf, size_t count, loff_t *ppos);
+#endif
+#ifdef VDEC_FCC_SUPPORT
+static unsigned int amstream_offset_poll
+(struct file *file, poll_table *wait_table);
+#endif
+
+static const struct file_operations vbuf_fops = {
+ .owner = THIS_MODULE,
+ .open = amstream_open,
+ .release = amstream_release,
+#ifdef VDEC_FCC_SUPPORT
+ .poll = amstream_offset_poll,
+#endif
+ .write = amstream_vbuf_write,
+ .unlocked_ioctl = amstream_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = amstream_compat_ioctl,
+#endif
+};
+
+static const struct file_operations vframe_fops = {
+ .owner = THIS_MODULE,
+ .open = amstream_open,
+ .release = amstream_release,
+ .write = amstream_vframe_write,
+ .unlocked_ioctl = amstream_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = amstream_compat_ioctl,
+#endif
+};
+
+static const struct file_operations abuf_fops = {
+ .owner = THIS_MODULE,
+ .open = amstream_open,
+ .release = amstream_release,
+ .write = amstream_abuf_write,
+ .unlocked_ioctl = amstream_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = amstream_compat_ioctl,
+#endif
+};
+
+static const struct file_operations mpts_fops = {
+ .owner = THIS_MODULE,
+ .open = amstream_open,
+ .release = amstream_release,
+ .write = amstream_mpts_write,
+ .unlocked_ioctl = amstream_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = amstream_compat_ioctl,
+#endif
+};
+
+static const struct file_operations mpps_fops = {
+ .owner = THIS_MODULE,
+ .open = amstream_open,
+ .release = amstream_release,
+ .write = amstream_mpps_write,
+ .unlocked_ioctl = amstream_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = amstream_compat_ioctl,
+#endif
+};
+
+static const struct file_operations mprm_fops = {
+ .owner = THIS_MODULE,
+ .open = amstream_open,
+ .release = amstream_release,
+#ifdef CONFIG_AM_VDEC_REAL
+ .write = amstream_mprm_write,
+#endif
+ .unlocked_ioctl = amstream_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = amstream_compat_ioctl,
+#endif
+};
+
+static const struct file_operations sub_fops = {
+ .owner = THIS_MODULE,
+ .open = amstream_open,
+ .release = amstream_release,
+ .write = amstream_sub_write,
+ .unlocked_ioctl = amstream_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = amstream_compat_ioctl,
+#endif
+};
+
+static const struct file_operations sub_read_fops = {
+ .owner = THIS_MODULE,
+ .open = amstream_open,
+ .release = amstream_release,
+ .read = amstream_sub_read,
+ .poll = amstream_sub_poll,
+ .unlocked_ioctl = amstream_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = amstream_compat_ioctl,
+#endif
+};
+
+static const struct file_operations userdata_fops = {
+ .owner = THIS_MODULE,
+ .open = amstream_open,
+ .release = amstream_release,
+ .poll = amstream_userdata_poll,
+ .unlocked_ioctl = amstream_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = amstream_compat_ioctl,
+#endif
+};
+
+static const struct file_operations amstream_fops = {
+ .owner = THIS_MODULE,
+ .open = amstream_open,
+ .release = amstream_release,
+ .unlocked_ioctl = amstream_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = amstream_compat_ioctl,
+#endif
+};
+
+/**************************************************/
+static struct audio_info audio_dec_info;
+static struct class *amstream_dev_class;
+static DEFINE_MUTEX(amstream_mutex);
+
+atomic_t subdata_ready = ATOMIC_INIT(0);
+static int sub_type;
+static int sub_port_inited;
+/* wait queue for poll */
+static wait_queue_head_t amstream_sub_wait;
+atomic_t userdata_ready = ATOMIC_INIT(0);
+static int userdata_length;
+static wait_queue_head_t amstream_userdata_wait;
+#define USERDATA_FIFO_NUM 1024
+static struct userdata_poc_info_t userdata_poc_info[USERDATA_FIFO_NUM];
+static int userdata_poc_ri, userdata_poc_wi;
+static int last_read_wi;
+
+#define MAX_USERDATA_CHANNEL_NUM 9
+
+typedef struct {
+ struct mutex mutex;
+ wait_queue_head_t userdata_wait;
+ u32 video_id;
+ u32 set_id_flag;
+ u32 ready_flag[MAX_USERDATA_CHANNEL_NUM];
+ int used[MAX_USERDATA_CHANNEL_NUM];
+ u32 id[MAX_USERDATA_CHANNEL_NUM];
+} st_userdata;
+
+st_userdata userdata;
+
+/*bit 1 force dual layer
+ *bit 2 force frame mode
+ */
+static u32 force_dv_mode;
+
+static DEFINE_MUTEX(userdata_mutex);
+
+#ifdef VDEC_FCC_SUPPORT
+static void amstream_fcc_get_one_slot(struct vdec_s *vdec);
+static void amstream_fcc_release_one_slot(struct vdec_s *vdec);
+
+#define MAX_FCC_CHANNEL_NUM 5
+
+typedef struct {
+ struct mutex mutex;
+ wait_queue_head_t offset_wait;
+ u32 offset[MAX_FCC_CHANNEL_NUM];
+ u32 offset_ready_flag[MAX_FCC_CHANNEL_NUM];
+ int used[MAX_FCC_CHANNEL_NUM];
+ int id[MAX_FCC_CHANNEL_NUM];
+} st_fcc;
+
+st_fcc fcc;
+static u32 fcc_enable;
+#endif
+
+static struct stream_port_s ports[] = {
+ {
+ .name = "amstream_vbuf",
+ .type = PORT_TYPE_ES | PORT_TYPE_VIDEO,
+ .fops = &vbuf_fops,
+ },
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ {
+ .name = "amstream_vbuf_sched",
+ .type = PORT_TYPE_ES | PORT_TYPE_VIDEO |
+ PORT_TYPE_DECODER_SCHED,
+ .fops = &vbuf_fops,
+ },
+ {
+ .name = "amstream_vframe",
+ .type = PORT_TYPE_ES | PORT_TYPE_VIDEO |
+ PORT_TYPE_FRAME | PORT_TYPE_DECODER_SCHED,
+ .fops = &vframe_fops,
+ },
+#endif
+ {
+ .name = "amstream_abuf",
+ .type = PORT_TYPE_ES | PORT_TYPE_AUDIO,
+ .fops = &abuf_fops,
+ },
+ {
+ .name = "amstream_mpts",
+ .type = PORT_TYPE_MPTS | PORT_TYPE_VIDEO |
+ PORT_TYPE_AUDIO | PORT_TYPE_SUB,
+ .fops = &mpts_fops,
+ },
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ {
+ .name = "amstream_mpts_sched",
+ .type = PORT_TYPE_MPTS | PORT_TYPE_VIDEO |
+ PORT_TYPE_AUDIO | PORT_TYPE_SUB |
+ PORT_TYPE_DECODER_SCHED,
+ .fops = &mpts_fops,
+ },
+#endif
+ {
+ .name = "amstream_mpps",
+ .type = PORT_TYPE_MPPS | PORT_TYPE_VIDEO |
+ PORT_TYPE_AUDIO | PORT_TYPE_SUB,
+ .fops = &mpps_fops,
+ },
+ {
+ .name = "amstream_rm",
+ .type = PORT_TYPE_RM | PORT_TYPE_VIDEO | PORT_TYPE_AUDIO,
+ .fops = &mprm_fops,
+ },
+ {
+ .name = "amstream_sub",
+ .type = PORT_TYPE_SUB,
+ .fops = &sub_fops,
+ },
+ {
+ .name = "amstream_sub_read",
+ .type = PORT_TYPE_SUB_RD,
+ .fops = &sub_read_fops,
+ },
+ {
+ .name = "amstream_userdata",
+ .type = PORT_TYPE_USERDATA,
+ .fops = &userdata_fops,
+ },
+ {
+ .name = "amstream_hevc",
+ .type = PORT_TYPE_ES | PORT_TYPE_VIDEO | PORT_TYPE_HEVC,
+ .fops = &vbuf_fops,
+ .vformat = VFORMAT_HEVC,
+ },
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ {
+ .name = "amstream_hevc_frame",
+ .type = PORT_TYPE_ES | PORT_TYPE_VIDEO | PORT_TYPE_HEVC |
+ PORT_TYPE_FRAME | PORT_TYPE_DECODER_SCHED,
+ .fops = &vframe_fops,
+ .vformat = VFORMAT_HEVC,
+ },
+ {
+ .name = "amstream_hevc_sched",
+ .type = PORT_TYPE_ES | PORT_TYPE_VIDEO | PORT_TYPE_HEVC |
+ PORT_TYPE_DECODER_SCHED,
+ .fops = &vbuf_fops,
+ .vformat = VFORMAT_HEVC,
+ },
+#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
+ {
+ .name = "amstream_dves_avc",
+ .type = PORT_TYPE_ES | PORT_TYPE_VIDEO |
+ PORT_TYPE_DECODER_SCHED | PORT_TYPE_DUALDEC,
+ .fops = &vbuf_fops,
+ },
+ {
+ .name = "amstream_dves_hevc",
+ .type = PORT_TYPE_ES | PORT_TYPE_VIDEO | PORT_TYPE_HEVC |
+ PORT_TYPE_DECODER_SCHED | PORT_TYPE_DUALDEC,
+ .fops = &vbuf_fops,
+ .vformat = VFORMAT_HEVC,
+ },
+ {
+ .name = "amstream_dves_avc_frame",
+ .type = PORT_TYPE_ES | PORT_TYPE_VIDEO | PORT_TYPE_FRAME |
+ PORT_TYPE_DECODER_SCHED | PORT_TYPE_DUALDEC,
+ .fops = &vframe_fops,
+ },
+ {
+ .name = "amstream_dves_hevc_frame",
+ .type = PORT_TYPE_ES | PORT_TYPE_VIDEO | PORT_TYPE_HEVC | PORT_TYPE_FRAME |
+ PORT_TYPE_DECODER_SCHED | PORT_TYPE_DUALDEC,
+ .fops = &vframe_fops,
+ .vformat = VFORMAT_HEVC,
+ },
+ {
+ .name = "amstream_dves_av1",
+ .type = PORT_TYPE_ES | PORT_TYPE_VIDEO | PORT_TYPE_HEVC | PORT_TYPE_FRAME |
+ PORT_TYPE_DECODER_SCHED | PORT_TYPE_DUALDEC,
+ .fops = &vframe_fops,
+ .vformat = VFORMAT_AV1,
+ },
+#endif
+#endif
+};
+
+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
+ },
+};
+
+struct stream_buf_s *get_buf_by_type(u32 type)
+{
+ if (PTS_TYPE_VIDEO == type)
+ return &bufs[BUF_TYPE_VIDEO];
+ if (PTS_TYPE_AUDIO == type)
+ return &bufs[BUF_TYPE_AUDIO];
+ if (has_hevc_vdec()) {
+ if (PTS_TYPE_HEVC == type)
+ return &bufs[BUF_TYPE_HEVC];
+ }
+
+ return NULL;
+}
+
+void set_sample_rate_info(int arg)
+{
+ audio_dec_info.sample_rate = arg;
+ audio_dec_info.valid = 1;
+}
+
+void set_ch_num_info(int arg)
+{
+ audio_dec_info.channels = arg;
+}
+
+struct audio_info *get_audio_info(void)
+{
+ return &audio_dec_info;
+}
+EXPORT_SYMBOL(get_audio_info);
+
+static void amstream_change_vbufsize(struct port_priv_s *priv,
+ struct stream_buf_s *pvbuf)
+{
+ if (pvbuf->buf_start != 0 || pvbuf->ext_buf_addr != 0) {
+ pr_info("streambuf is alloced, buf_start 0x%lx, extbuf 0x%lx\n",
+ pvbuf->buf_start, pvbuf->ext_buf_addr);
+ return;
+ }
+ if (priv->port->is_4k) {
+ pvbuf->buf_size = def_4k_vstreambuf_sizeM * SZ_1M;
+ if (priv->vdec->port_flag & PORT_FLAG_DRM)
+ pvbuf->buf_size = DEFAULT_VIDEO_BUFFER_SIZE_4K_TVP;
+ if ((pvbuf->buf_size > 30 * SZ_1M) &&
+ (codec_mm_get_total_size() < 220 * SZ_1M)) {
+ /*if less than 250M, used 20M for 4K & 265*/
+ pvbuf->buf_size = pvbuf->buf_size >> 1;
+ }
+ } else if (pvbuf->buf_size > def_vstreambuf_sizeM * SZ_1M) {
+ if (priv->vdec->port_flag & PORT_FLAG_DRM)
+ pvbuf->buf_size = DEFAULT_VIDEO_BUFFER_SIZE_TVP;
+ } else {
+ pvbuf->buf_size = def_vstreambuf_sizeM * SZ_1M;
+ if (priv->vdec->port_flag & PORT_FLAG_DRM)
+ pvbuf->buf_size = DEFAULT_VIDEO_BUFFER_SIZE_TVP;
+ }
+ reset_canuse_buferlevel(10000);
+}
+
+static bool port_get_inited(struct port_priv_s *priv)
+{
+ struct stream_port_s *port = priv->port;
+
+ if (port->type & PORT_TYPE_VIDEO) {
+ struct vdec_s *vdec = priv->vdec;
+
+ return vdec ? vdec->port_flag & PORT_FLAG_INITED : 0;
+ }
+
+ return port->flag & PORT_FLAG_INITED;
+}
+
+static void port_set_inited(struct port_priv_s *priv)
+{
+ struct stream_port_s *port = priv->port;
+
+ if (port->type & PORT_TYPE_VIDEO) {
+ struct vdec_s *vdec = priv->vdec;
+
+ vdec->port_flag |= PORT_FLAG_INITED;
+ port->flag |= PORT_FLAG_INITED;
+ pr_info("vdec->port_flag=0x%x, port_flag=0x%x\n",
+ vdec->port_flag, port->flag);
+ } else
+ port->flag |= PORT_FLAG_INITED;
+}
+
+static void video_port_release(struct port_priv_s *priv,
+ struct stream_buf_s *pbuf, int release_num)
+{
+ struct vdec_s *vdec = priv->vdec;
+ struct vdec_s *slave = NULL;
+
+ if (!vdec)
+ return;
+
+ switch (release_num) {
+ default:
+ /*fallthrough*/
+ case 0: /*release all */
+ case 3:
+#ifdef VDEC_FCC_SUPPORT
+ if (fcc_enable & 0x1)
+ amstream_fcc_release_one_slot(vdec);
+#endif
+ if (vdec->slave)
+ slave = vdec->slave;
+ vdec_release(vdec);
+ if (slave)
+ vdec_release(slave);
+ priv->vdec = NULL;
+ /*fallthrough*/
+ case 1:
+ ;
+ }
+}
+
+static int video_port_init(struct port_priv_s *priv,
+ struct stream_buf_s *pbuf)
+{
+ int r;
+ struct stream_port_s *port = priv->port;
+ struct vdec_s *vdec = priv->vdec;
+
+ if (vdec == NULL) {
+ pr_err("vdec is null\n");
+ return -EPERM;
+ }
+
+ if ((vdec->port_flag & PORT_FLAG_VFORMAT) == 0) {
+ pr_err("vformat not set\n");
+ return -EPERM;
+ }
+ if (vdec_dual(vdec) && vdec_secure(vdec) && (vdec->slave)) {
+ /*copy drm flags for slave dec.*/
+ vdec->slave->port_flag |= PORT_FLAG_DRM;
+ }
+ if (port->vformat == VFORMAT_H264_4K2K ||
+ (priv->vdec->sys_info->height *
+ priv->vdec->sys_info->width) > 1920*1088) {
+ port->is_4k = true;
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_TXLX
+ && port->vformat == VFORMAT_H264) {
+ vdec_poweron(VDEC_HEVC);
+ }
+ } else {
+ port->is_4k = false;
+ }
+
+ if (port->type & PORT_TYPE_FRAME) {
+ r = vdec_init(vdec,
+ (priv->vdec->sys_info->height *
+ priv->vdec->sys_info->width) > 1920*1088);
+ if (r < 0) {
+ pr_err("video_port_init %d, vdec_init failed\n",
+ __LINE__);
+ return r;
+ }
+#if 0
+ if (vdec_dual(vdec)) {
+ if (port->vformat == VFORMAT_AV1) /* av1 dv only single layer */
+ return 0;
+ r = vdec_init(vdec->slave,
+ (priv->vdec->sys_info->height *
+ priv->vdec->sys_info->width) > 1920*1088);
+ if (r < 0) {
+ vdec_release(vdec);
+ pr_err("video_port_init %d, vdec_init failed\n",
+ __LINE__);
+ return r;
+ }
+ }
+#endif
+ return 0;
+ }
+
+ amstream_change_vbufsize(priv, pbuf);
+
+ if (has_hevc_vdec()) {
+ if (port->type & PORT_TYPE_MPTS) {
+ if (pbuf->type == BUF_TYPE_HEVC)
+ vdec_poweroff(VDEC_1);
+ else
+ vdec_poweroff(VDEC_HEVC);
+ }
+ }
+
+ /* todo: set path based on port flag */
+ r = vdec_init(vdec,
+ (priv->vdec->sys_info->height *
+ priv->vdec->sys_info->width) > 1920*1088);
+
+ if (r < 0) {
+ pr_err("video_port_init %d, vdec_init failed\n", __LINE__);
+ goto err;
+ }
+
+ if (vdec_dual(vdec)) {
+ r = vdec_init(vdec->slave,
+ (priv->vdec->sys_info->height *
+ priv->vdec->sys_info->width) > 1920*1088);
+ if (r < 0) {
+ pr_err("video_port_init %d, vdec_init failed\n", __LINE__);
+ goto err;
+ }
+ }
+#ifdef VDEC_FCC_SUPPORT
+ if (fcc_enable & 0x1)
+ amstream_fcc_get_one_slot(vdec);
+#endif
+
+ return 0;
+err:
+ if (vdec->slave)
+ vdec_release(vdec->slave);
+
+ vdec_release(vdec);
+
+ priv->vdec = NULL;
+
+ return r;
+}
+
+static void audio_port_release(struct stream_port_s *port,
+ struct stream_buf_s *pbuf, int release_num)
+{
+ switch (release_num) {
+ default:
+ /*fallthrough*/
+ case 0: /*release all */
+ /*fallthrough*/
+ case 4:
+ esparser_release(pbuf);
+ /*fallthrough*/
+ case 3:
+ adec_release(port->vformat);
+ /*fallthrough*/
+ case 2:
+ stbuf_release(pbuf);
+ /*fallthrough*/
+ case 1:
+ ;
+ }
+ amstream_audio_reset = 0;
+ return;
+}
+
+static int audio_port_reset(struct stream_port_s *port,
+ struct stream_buf_s *pbuf)
+{
+ int r;
+ if ((port->flag & PORT_FLAG_AFORMAT) == 0) {
+ pr_err("aformat not set\n");
+ return 0;
+ }
+
+ pr_info("audio port reset, flag:0x%x\n", port->flag);
+ if ((port->flag & PORT_FLAG_INITED) == 0) {
+ pr_info("audio port not inited,return\n");
+ return 0;
+ }
+
+ pr_info("audio_port_reset begin\n");
+ pts_stop(PTS_TYPE_AUDIO);
+
+ stbuf_release(pbuf);
+
+ r = stbuf_init(pbuf, NULL);
+ if (r < 0) {
+ return r;
+ }
+
+ r = adec_init(port);
+ if (r < 0) {
+ audio_port_release(port, pbuf, 2);
+ return r;
+ }
+
+ if (port->type & PORT_TYPE_ES)
+ esparser_audio_reset_s(pbuf);
+
+ if (port->type & PORT_TYPE_MPTS)
+ tsdemux_audio_reset();
+
+ if (port->type & PORT_TYPE_MPPS)
+ psparser_audio_reset();
+
+#ifdef CONFIG_AM_VDEC_REAL
+ if (port->type & PORT_TYPE_RM)
+ rm_audio_reset();
+#endif
+
+ pbuf->flag |= BUF_FLAG_IN_USE;
+ amstream_audio_reset = 1;
+
+ r = pts_start(PTS_TYPE_AUDIO);
+
+ //clear audio break flag after reset
+ //tsync_audio_break(0);
+
+ pr_info("audio_port_reset done\n");
+ return r;
+}
+
+static int sub_port_reset(struct stream_port_s *port,
+ struct stream_buf_s *pbuf)
+{
+ int r;
+
+ port->flag &= (~PORT_FLAG_INITED);
+
+ stbuf_release(pbuf);
+
+ r = stbuf_init(pbuf, NULL);
+ if (r < 0)
+ return r;
+
+ if (port->type & PORT_TYPE_MPTS)
+ tsdemux_sub_reset();
+
+ if (port->type & PORT_TYPE_MPPS)
+ psparser_sub_reset();
+
+ if (port->sid == 0xffff) { /* es sub */
+ esparser_sub_reset();
+ pbuf->flag |= BUF_FLAG_PARSER;
+ }
+
+ pbuf->flag |= BUF_FLAG_IN_USE;
+
+ port->flag |= PORT_FLAG_INITED;
+
+ return 0;
+}
+
+static int audio_port_init(struct stream_port_s *port,
+ struct stream_buf_s *pbuf)
+{
+ int r;
+
+ if ((port->flag & PORT_FLAG_AFORMAT) == 0) {
+ pr_err("aformat not set\n");
+ return 0;
+ }
+
+ r = stbuf_init(pbuf, NULL);
+ if (r < 0)
+ return r;
+ r = adec_init(port);
+ if (r < 0) {
+ audio_port_release(port, pbuf, 2);
+ return r;
+ }
+ if (port->type & PORT_TYPE_ES) {
+ r = esparser_init(pbuf, NULL);
+ if (r < 0) {
+ audio_port_release(port, pbuf, 3);
+ return r;
+ }
+ }
+ pbuf->flag |= BUF_FLAG_IN_USE;
+ return 0;
+}
+
+static void sub_port_release(struct stream_port_s *port,
+ struct stream_buf_s *pbuf)
+{
+ if ((port->sid == 0xffff) &&
+ ((port->type & (PORT_TYPE_MPPS | PORT_TYPE_MPTS)) == 0)) {
+ /* this is es sub */
+ esparser_release(pbuf);
+ }
+ stbuf_release(pbuf);
+ sub_port_inited = 0;
+}
+
+static int sub_port_init(struct stream_port_s *port, struct stream_buf_s *pbuf)
+{
+ int r;
+ r = stbuf_init(pbuf, NULL);
+ if (r < 0)
+ return r;
+ if ((port->flag & PORT_FLAG_SID) == 0) {
+ pr_err("subtitle id not set\n");
+ return 0;
+ }
+
+ if ((port->sid == 0xffff) &&
+ ((port->type & (PORT_TYPE_MPPS | PORT_TYPE_MPTS)) == 0)) {
+ /* es sub */
+ r = esparser_init(pbuf, NULL);
+ if (r < 0) {
+ sub_port_release(port, pbuf);
+ return r;
+ }
+ }
+
+ sub_port_inited = 1;
+ return 0;
+}
+
+static void amstream_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;
+}
+
+#if 1
+/*DDD*/
+struct stream_buf_s *get_vbuf(void)
+{
+ return &bufs[BUF_TYPE_VIDEO];
+}
+
+EXPORT_SYMBOL(get_vbuf);
+#endif
+
+static int amstream_port_init(struct port_priv_s *priv)
+{
+ int r = 0;
+ struct stream_buf_s *pvbuf = &bufs[BUF_TYPE_VIDEO];
+ struct stream_buf_s *pabuf = &bufs[BUF_TYPE_AUDIO];
+ struct stream_buf_s *psbuf = &bufs[BUF_TYPE_SUBTITLE];
+ struct stream_port_s *port = priv->port;
+ struct vdec_s *vdec = priv->vdec;
+
+ r = vdec_resource_checking(vdec);
+ if (r < 0)
+ return r;
+
+ mutex_lock(&amstream_mutex);
+
+ if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) &&
+ (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_SC2)) {
+ r = check_efuse_chip(port->vformat);
+ if (r) {
+ pr_info("No support video format %d.\n", port->vformat);
+ mutex_unlock(&amstream_mutex);
+ return 0;
+ }
+ }
+
+ /* try to reload the fw.*/
+ r = video_fw_reload(FW_LOAD_TRY);
+ if (r)
+ pr_err("the firmware reload fail.\n");
+
+ stbuf_fetch_init();
+
+ amstream_user_buffer_init();
+
+ if (port_get_inited(priv)) {
+ mutex_unlock(&amstream_mutex);
+ return 0;
+ }
+
+ if ((port->type & PORT_TYPE_AUDIO) &&
+ (port->flag & PORT_FLAG_AFORMAT)) {
+ r = audio_port_init(port, pabuf);
+ if (r < 0) {
+ pr_err("audio_port_init failed\n");
+ goto error1;
+ }
+ }
+
+ if ((port->type & PORT_TYPE_VIDEO) &&
+ (port->flag & PORT_FLAG_VFORMAT)) {
+ if (vdec_stream_based(vdec)) {
+ struct stream_buf_ops *ops = NULL;
+ struct parser_args pars = {
+ .vid = (port->flag & PORT_FLAG_VID) ? port->vid : 0xffff,
+ .aid = (port->flag & PORT_FLAG_AID) ? port->aid : 0xffff,
+ .sid = (port->flag & PORT_FLAG_SID) ? port->sid : 0xffff,
+ .pcrid = (port->pcr_inited == 1) ? port->pcrid : 0xffff,
+ };
+
+ if (port->type & PORT_TYPE_MPTS) {
+ ops = get_tsparser_stbuf_ops();
+ } else if (port->type & PORT_TYPE_MPPS) {
+ ops = get_psparser_stbuf_ops();
+ } else {
+ ops = !vdec_single(vdec) ?
+ get_stbuf_ops() :
+ get_esparser_stbuf_ops();
+
+ /* def used stbuf with parser if the feature disable. */
+ if (!is_support_no_parser())
+ ops = get_esparser_stbuf_ops();
+ else if (vdec->format == VFORMAT_H264MVC ||
+ vdec->format == VFORMAT_VC1)
+ ops = get_stbuf_ops();
+ }
+
+ r = stream_buffer_base_init(&vdec->vbuf, ops, &pars);
+ if (r) {
+ mutex_unlock(&priv->mutex);
+ pr_err("stream buffer base init failed\n");
+ goto error2;
+ }
+ }
+
+ mutex_lock(&priv->mutex);
+ r = video_port_init(priv, &vdec->vbuf);
+ if (r < 0) {
+ mutex_unlock(&priv->mutex);
+ pr_err("video_port_init failed\n");
+ goto error2;
+ }
+ mutex_unlock(&priv->mutex);
+ }
+
+ if ((port->type & PORT_TYPE_MPTS) &&
+ !(port->flag & PORT_FLAG_VFORMAT)) {
+ r = tsdemux_init(0xffff,
+ (port->flag & PORT_FLAG_AID) ? port->aid : 0xffff,
+ (port->flag & PORT_FLAG_SID) ? port->sid : 0xffff,
+ (port->pcr_inited == 1) ? port->pcrid : 0xffff,
+ 0, vdec);
+ if (r < 0) {
+ pr_err("tsdemux_init failed\n");
+ goto error3;
+ }
+ tsync_pcr_start();
+ }
+
+ if ((port->type & PORT_TYPE_SUB) && (port->flag & PORT_FLAG_SID)) {
+ r = sub_port_init(port, psbuf);
+ if (r < 0) {
+ pr_err("sub_port_init failed\n");
+ goto error4;
+ }
+ }
+
+#ifdef CONFIG_AM_VDEC_REAL
+ if (port->type & PORT_TYPE_RM) {
+ rm_set_vasid(
+ (port->flag & PORT_FLAG_VID) ? port->vid : 0xffff,
+ (port->flag & PORT_FLAG_AID) ? port->aid : 0xffff);
+ }
+#endif
+#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6TVD */
+ if (!NO_VDEC2_INIT) {
+ if ((port->type & PORT_TYPE_VIDEO)
+ && (port->vformat == VFORMAT_H264_4K2K))
+ stbuf_vdec2_init(pvbuf);
+ }
+#endif
+
+ if ((port->type & PORT_TYPE_VIDEO) &&
+ (vdec->port_flag & PORT_FLAG_VFORMAT))
+ /* connect vdec at the end after all HW initialization */
+ vdec_connect(vdec);
+
+ tsync_audio_break(0); /* clear audio break */
+ set_vsync_pts_inc_mode(0); /* clear video inc */
+
+ port_set_inited(priv);
+
+ mutex_unlock(&amstream_mutex);
+ return 0;
+ /*errors follow here */
+
+error4:
+ if ((port->type & PORT_TYPE_MPTS) &&
+ !(port->flag & PORT_FLAG_VFORMAT))
+ tsdemux_release();
+error3:
+ if ((port->type & PORT_TYPE_VIDEO) &&
+ (port->flag & PORT_FLAG_VFORMAT))
+ video_port_release(priv, &priv->vdec->vbuf, 0);
+error2:
+ if ((port->type & PORT_TYPE_AUDIO) &&
+ (port->flag & PORT_FLAG_AFORMAT))
+ audio_port_release(port, pabuf, 0);
+error1:
+ mutex_unlock(&amstream_mutex);
+ return r;
+}
+
+static int amstream_port_release(struct port_priv_s *priv)
+{
+ struct stream_port_s *port = priv->port;
+ struct stream_buf_s *pvbuf = &priv->vdec->vbuf;
+ struct stream_buf_s *pabuf = &bufs[BUF_TYPE_AUDIO];
+ struct stream_buf_s *psbuf = &bufs[BUF_TYPE_SUBTITLE];
+
+ if ((port->type & PORT_TYPE_MPTS) &&
+ !(port->flag & PORT_FLAG_VFORMAT)) {
+ tsync_pcr_stop();
+ tsdemux_release();
+ }
+
+ if ((port->type & PORT_TYPE_MPPS) &&
+ !(port->flag & PORT_FLAG_VFORMAT)) {
+ psparser_release();
+ }
+
+ if (port->type & PORT_TYPE_VIDEO)
+ video_port_release(priv, pvbuf, 0);
+
+ if (port->type & PORT_TYPE_AUDIO)
+ audio_port_release(port, pabuf, 0);
+
+ if (port->type & PORT_TYPE_SUB)
+ sub_port_release(port, psbuf);
+
+ port->pcr_inited = 0;
+
+ if (!is_mult_inc(port->type) ||
+ (is_mult_inc(port->type) &&
+ !is_support_no_parser()))
+ port->flag = 0;
+
+ return 0;
+}
+
+static void amstream_change_avid(struct stream_port_s *port)
+{
+ if (port->type & PORT_TYPE_MPTS) {
+ tsdemux_change_avid(
+ (port->flag & PORT_FLAG_VID) ? port->vid : 0xffff,
+ (port->flag & PORT_FLAG_AID) ? port->aid : 0xffff);
+ }
+
+ if (port->type & PORT_TYPE_MPPS) {
+ psparser_change_avid(
+ (port->flag & PORT_FLAG_VID) ? port->vid : 0xffff,
+ (port->flag & PORT_FLAG_AID) ? port->aid : 0xffff);
+ }
+
+#ifdef CONFIG_AM_VDEC_REAL
+ if (port->type & PORT_TYPE_RM) {
+ rm_set_vasid(
+ (port->flag & PORT_FLAG_VID) ? port->vid : 0xffff,
+ (port->flag & PORT_FLAG_AID) ? port->aid : 0xffff);
+ }
+#endif
+}
+
+static void amstream_change_sid(struct stream_port_s *port)
+{
+ if (port->type & PORT_TYPE_MPTS) {
+ tsdemux_change_sid(
+ (port->flag & PORT_FLAG_SID) ? port->sid : 0xffff);
+ }
+
+ if (port->type & PORT_TYPE_MPPS) {
+ psparser_change_sid(
+ (port->flag & PORT_FLAG_SID) ? port->sid : 0xffff);
+ }
+}
+
+/**************************************************/
+static ssize_t amstream_vbuf_write(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct port_priv_s *priv = (struct port_priv_s *)file->private_data;
+ struct stream_buf_s *pbuf = &priv->vdec->vbuf;
+ int r;
+
+ if (!(port_get_inited(priv))) {
+ r = amstream_port_init(priv);
+ if (r < 0)
+ return r;
+ }
+
+ if (priv->vdec->port_flag & PORT_FLAG_DRM)
+ r = drm_write(file, pbuf, buf, count);
+ else
+ r = stream_buffer_write(file, pbuf, buf, count);
+ if (slow_input) {
+ pr_info("slow_input: es codec write size %x\n", r);
+ msleep(3000);
+ }
+#ifdef DATA_DEBUG
+ debug_file_write(buf, r);
+#endif
+
+ return r;
+}
+
+static ssize_t amstream_vframe_write(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct port_priv_s *priv = (struct port_priv_s *)file->private_data;
+ ssize_t ret;
+ int wait_max_cnt = 5;
+#ifdef DATA_DEBUG
+ debug_file_write(buf, count);
+#endif
+ do {
+ ret = vdec_write_vframe(priv->vdec, buf, count);
+ if (file->f_flags & O_NONBLOCK) {
+ break;/*alway return for no block mode.*/
+ } else if (ret == -EAGAIN) {
+ int level;
+ level = vdec_input_level(&priv->vdec->input);
+ if (wait_max_cnt-- < 0)
+ break;
+ msleep(20);
+ }
+ } while (ret == -EAGAIN);
+ return ret;
+}
+
+static ssize_t amstream_abuf_write(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct port_priv_s *priv = (struct port_priv_s *)file->private_data;
+ struct stream_port_s *port = priv->port;
+ struct stream_buf_s *pbuf = &bufs[BUF_TYPE_AUDIO];
+ int r;
+
+ if (!(port_get_inited(priv))) {
+ r = amstream_port_init(priv);
+ if (r < 0)
+ return r;
+ }
+
+ if (port->flag & PORT_FLAG_DRM)
+ r = drm_write(file, pbuf, buf, count);
+ else
+ r = esparser_write(file, pbuf, buf, count);
+
+ return r;
+}
+
+static ssize_t amstream_mpts_write(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct port_priv_s *priv = (struct port_priv_s *)file->private_data;
+ struct stream_port_s *port = priv->port;
+ struct stream_buf_s *pabuf = &bufs[BUF_TYPE_AUDIO];
+ struct stream_buf_s *pvbuf = &priv->vdec->vbuf;
+ int r = 0;
+
+ if (!(port_get_inited(priv))) {
+ r = amstream_port_init(priv);
+ if (r < 0)
+ return r;
+ }
+#ifdef DATA_DEBUG
+ debug_file_write(buf, count);
+#endif
+ if (port->flag & PORT_FLAG_DRM)
+ r = drm_tswrite(file, pvbuf, pabuf, buf, count);
+ else
+ r = tsdemux_write(file, pvbuf, pabuf, buf, count);
+ if (slow_input) {
+ pr_info("slow_input: ts codec write size %x\n", r);
+ msleep(3000);
+ }
+ return r;
+}
+
+static ssize_t amstream_mpps_write(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct port_priv_s *priv = (struct port_priv_s *)file->private_data;
+ struct stream_buf_s *pvbuf = &bufs[BUF_TYPE_VIDEO];
+ struct stream_buf_s *pabuf = &bufs[BUF_TYPE_AUDIO];
+ int r;
+
+ if (!(port_get_inited(priv))) {
+ r = amstream_port_init(priv);
+ if (r < 0)
+ return r;
+ }
+ return psparser_write(file, pvbuf, pabuf, buf, count);
+}
+
+#ifdef CONFIG_AM_VDEC_REAL
+static ssize_t amstream_mprm_write(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct port_priv_s *priv = (struct port_priv_s *)file->private_data;
+ struct stream_buf_s *pvbuf = &bufs[BUF_TYPE_VIDEO];
+ struct stream_buf_s *pabuf = &bufs[BUF_TYPE_AUDIO];
+ int r;
+
+ if (!(port_get_inited(priv))) {
+ r = amstream_port_init(priv);
+ if (r < 0)
+ return r;
+ }
+ return rmparser_write(file, pvbuf, pabuf, buf, count);
+}
+#endif
+
+static ssize_t amstream_sub_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ u32 sub_rp, sub_wp, sub_start, data_size, res;
+ struct stream_buf_s *s_buf = &bufs[BUF_TYPE_SUBTITLE];
+
+ if (sub_port_inited == 0)
+ return 0;
+
+ sub_rp = stbuf_sub_rp_get();
+ sub_wp = stbuf_sub_wp_get();
+ sub_start = stbuf_sub_start_get();
+
+ if (sub_wp == sub_rp || sub_rp == 0)
+ return 0;
+ /*flush sub buf before read*/
+ codec_mm_dma_flush(
+ (void*)codec_mm_phys_to_virt(sub_start),
+ stbuf_size(s_buf),
+ DMA_FROM_DEVICE);
+ if (sub_wp > sub_rp)
+ data_size = sub_wp - sub_rp;
+ else
+ data_size = s_buf->buf_size - sub_rp + sub_wp;
+
+ if (data_size > count)
+ data_size = count;
+
+ if (sub_wp < sub_rp) {
+ int first_num = s_buf->buf_size - (sub_rp - sub_start);
+
+ if (data_size <= first_num) {
+ res = copy_to_user((void *)buf,
+ (void *)(codec_mm_phys_to_virt(sub_rp)),
+ data_size);
+ stbuf_sub_rp_set(sub_rp + data_size - res);
+
+ return data_size - res;
+ } else {
+ if (first_num > 0) {
+ res = copy_to_user((void *)buf,
+ (void *)(codec_mm_phys_to_virt(sub_rp)),
+ first_num);
+ stbuf_sub_rp_set(sub_rp + first_num -
+ res);
+
+ return first_num - res;
+ }
+
+ res = copy_to_user((void *)buf,
+ (void *)(codec_mm_phys_to_virt(sub_start)),
+ data_size - first_num);
+
+ stbuf_sub_rp_set(sub_start + data_size -
+ first_num - res);
+
+ return data_size - first_num - res;
+ }
+ } else {
+ res =
+ copy_to_user((void *)buf,
+ (void *)(codec_mm_phys_to_virt(sub_rp)),
+ data_size);
+
+ stbuf_sub_rp_set(sub_rp + data_size - res);
+
+ return data_size - res;
+ }
+}
+
+static ssize_t amstream_sub_write(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct port_priv_s *priv = (struct port_priv_s *)file->private_data;
+ struct stream_buf_s *pbuf = &bufs[BUF_TYPE_SUBTITLE];
+ int r;
+
+ if (!(port_get_inited(priv))) {
+ r = amstream_port_init(priv);
+ if (r < 0)
+ return r;
+ }
+ r = esparser_write(file, pbuf, buf, count);
+ if (r < 0)
+ return r;
+
+ wakeup_sub_poll();
+
+ return r;
+}
+
+static unsigned int amstream_sub_poll(struct file *file,
+ poll_table *wait_table)
+{
+ poll_wait(file, &amstream_sub_wait, wait_table);
+
+ if (atomic_read(&subdata_ready)) {
+ atomic_dec(&subdata_ready);
+ return POLLOUT | POLLWRNORM;
+ }
+
+ return 0;
+}
+
+static void set_userdata_poc(struct userdata_poc_info_t poc)
+{
+ userdata_poc_info[userdata_poc_wi] = poc;
+ userdata_poc_wi++;
+ if (userdata_poc_wi == USERDATA_FIFO_NUM)
+ userdata_poc_wi = 0;
+}
+EXPORT_SYMBOL(set_userdata_poc);
+
+void init_userdata_fifo(void)
+{
+ userdata_poc_ri = 0;
+ userdata_poc_wi = 0;
+ userdata_length = 0;
+}
+EXPORT_SYMBOL(init_userdata_fifo);
+
+void reset_userdata_fifo(int bInit)
+{
+ struct stream_buf_s *userdata_buf;
+ int wi, ri;
+ u32 rp, wp;
+
+ mutex_lock(&userdata_mutex);
+
+ wi = userdata_poc_wi;
+ ri = userdata_poc_ri;
+
+ userdata_buf = &bufs[BUF_TYPE_USERDATA];
+ rp = userdata_buf->buf_rp;
+ wp = userdata_buf->buf_wp;
+ if (bInit) {
+ /* decoder reset */
+ userdata_buf->buf_rp = 0;
+ userdata_buf->buf_wp = 0;
+ userdata_poc_ri = 0;
+ userdata_poc_wi = 0;
+ } else {
+ /* just clean fifo buffer */
+ userdata_buf->buf_rp = userdata_buf->buf_wp;
+ userdata_poc_ri = userdata_poc_wi;
+ }
+ userdata_length = 0;
+ last_read_wi = userdata_poc_wi;
+
+ mutex_unlock(&userdata_mutex);
+ pr_debug("reset_userdata_fifo, bInit=%d, wi=%d, ri=%d, rp=%d, wp=%d\n",
+ bInit, wi, ri, rp, wp);
+}
+EXPORT_SYMBOL(reset_userdata_fifo);
+
+int wakeup_userdata_poll(struct userdata_poc_info_t poc,
+ int wp,
+ unsigned long start_phyaddr,
+ int buf_size,
+ int data_length)
+{
+ struct stream_buf_s *userdata_buf = &bufs[BUF_TYPE_USERDATA];
+ mutex_lock(&userdata_mutex);
+
+ if (data_length & 0x7)
+ data_length = (((data_length + 8) >> 3) << 3);
+ set_userdata_poc(poc);
+ userdata_buf->buf_start = start_phyaddr;
+ userdata_buf->buf_wp = wp;
+ userdata_buf->buf_size = buf_size;
+ atomic_set(&userdata_ready, 1);
+ userdata_length += data_length;
+ mutex_unlock(&userdata_mutex);
+
+ wake_up_interruptible(&amstream_userdata_wait);
+ return userdata_buf->buf_rp;
+}
+EXPORT_SYMBOL(wakeup_userdata_poll);
+
+
+void amstream_wakeup_userdata_poll(struct vdec_s *vdec)
+{
+ int i;
+
+ if (vdec == NULL) {
+ pr_info("Error, invalid vdec instance!\n");
+ return;
+ }
+
+ mutex_lock(&userdata.mutex);
+
+ for (i = 0; i < MAX_USERDATA_CHANNEL_NUM; i++) {
+ if (userdata.set_id_flag && (userdata.id[i] == vdec->video_id)) {
+ userdata.ready_flag[i] = 1;
+ break;
+ } else if (!userdata.set_id_flag) {
+ if (!userdata.used[0]) {
+ vdec->video_id = vdec->id;
+ userdata.id[0] = vdec->id;
+ userdata.used[0] = 1;
+ }
+
+ userdata.ready_flag[i] = 1;
+ break;
+ }
+ }
+
+ mutex_unlock(&userdata.mutex);
+
+ wake_up_interruptible(&userdata.userdata_wait);
+}
+EXPORT_SYMBOL(amstream_wakeup_userdata_poll);
+
+static unsigned int amstream_userdata_poll(struct file *file,
+ poll_table *wait_table)
+{
+ int fd_match = 0;
+ int i;
+
+ poll_wait(file, &userdata.userdata_wait, wait_table);
+ mutex_lock(&userdata.mutex);
+ for (i = 0; i < MAX_USERDATA_CHANNEL_NUM; i++) {
+ if (userdata.id[i] == userdata.video_id && userdata.ready_flag[i] == 1) {
+ fd_match = 1;
+ break;
+ }
+ }
+
+ if (fd_match) {
+ mutex_unlock(&userdata.mutex);
+ return POLLIN | POLLRDNORM;
+ }
+
+ mutex_unlock(&userdata.mutex);
+ return 0;
+}
+
+static void amstream_userdata_init(void)
+{
+ int i;
+
+ init_waitqueue_head(&userdata.userdata_wait);
+ mutex_init(&userdata.mutex);
+ userdata.set_id_flag = 0;
+
+ for (i = 0; i < MAX_USERDATA_CHANNEL_NUM; i++) {
+ userdata.ready_flag[i] = 0;
+ userdata.id[i] = -1;
+ userdata.used[i] = 0;
+ }
+
+ return;
+}
+
+static void amstream_userdata_deinit(void)
+{
+ int i;
+
+ mutex_lock(&userdata.mutex);
+
+ userdata.set_id_flag = 0;
+ for (i = 0; i < MAX_USERDATA_CHANNEL_NUM; i++) {
+ if (userdata.used[i] == 1) {
+ userdata.ready_flag[i] = 0;
+ userdata.id[i] = -1;
+ userdata.used[i] = 0;
+ }
+ }
+
+ mutex_unlock(&userdata.mutex);
+
+ return;
+}
+
+#ifdef VDEC_FCC_SUPPORT
+static unsigned int amstream_offset_poll(struct file *file,
+ poll_table *wait_table)
+{
+ struct port_priv_s *priv = (struct port_priv_s *)file->private_data;
+ struct vdec_s *vdec = priv->vdec;
+ int fd_match = 0;
+ int i;
+
+ if ((fcc_enable & 1) == 0)
+ return 0;
+
+ poll_wait(file, &fcc.offset_wait, wait_table);
+ mutex_lock(&fcc.mutex);
+ for (i = 0; i < MAX_FCC_CHANNEL_NUM; i++) {
+ if (fcc.id[i] == vdec->id && fcc.offset_ready_flag[i] == 1) {
+ fd_match = 1;
+ if (fcc_debug_enable())
+ pr_info("i = %d vdec->id = %d offset_ready_flag = %d\n",
+ i, vdec->id, fcc.offset_ready_flag[i]);
+ break;
+ }
+ }
+
+ if (fd_match) {
+ mutex_unlock(&fcc.mutex);
+ return POLLIN | POLLRDNORM;
+ }
+
+ mutex_unlock(&fcc.mutex);
+ return 0;
+}
+
+void amstream_wakeup_fcc_poll(struct vdec_s *vdec)
+{
+ int i;
+
+ if (vdec == NULL) {
+ pr_info("Error, invalid vdec instance!\n");
+ return;
+ }
+
+ mutex_lock(&fcc.mutex);
+
+ for (i = 0; i < MAX_FCC_CHANNEL_NUM; i++) {
+ if (fcc.id[i] == vdec->id) {
+ fcc.offset[i] = vdec->stream_offset;
+ fcc.offset_ready_flag[i] = 1;
+ if (fcc_debug_enable())
+ pr_info("i = %d vdec->id = %d stream_offset = %d\n",
+ i, vdec->id, vdec->stream_offset);
+ break;
+ }
+ }
+
+ mutex_unlock(&fcc.mutex);
+
+ wake_up_interruptible(&fcc.offset_wait);
+}
+EXPORT_SYMBOL(amstream_wakeup_fcc_poll);
+
+static void amstream_fcc_init(void)
+{
+ int i;
+
+ init_waitqueue_head(&fcc.offset_wait);
+ mutex_init(&fcc.mutex);
+
+ for (i = 0; i < MAX_FCC_CHANNEL_NUM; i++) {
+ fcc.offset_ready_flag[i] = 0;
+ fcc.id[i] = -1;
+ fcc.used[i] = 0;
+ }
+
+ return;
+}
+
+static void amstream_fcc_get_one_slot(struct vdec_s *vdec)
+{
+ int i;
+
+ mutex_lock(&fcc.mutex);
+ for (i = 0; i < MAX_FCC_CHANNEL_NUM; i++) {
+ if (!fcc.used[i]) {
+ fcc.offset_ready_flag[i] = 0;
+ fcc.id[i] = vdec->id;
+ fcc.used[i] = 1;
+ break;
+ }
+ }
+ mutex_unlock(&fcc.mutex);
+
+ if (i >= MAX_FCC_CHANNEL_NUM)
+ pr_info("Error, no free fcc slot\n");
+
+ return;
+}
+
+static void amstream_fcc_release_one_slot(struct vdec_s *vdec)
+{
+ int i;
+
+ mutex_lock(&fcc.mutex);
+ for (i = 0; i < MAX_FCC_CHANNEL_NUM; i++) {
+ if (fcc.used[i] && vdec->id == fcc.id[i]) {
+ fcc.offset_ready_flag[i] = 0;
+ fcc.id[i] = -1;
+ fcc.used[i] = 0;
+ break;
+ }
+ }
+ mutex_unlock(&fcc.mutex);
+
+ if (i >= MAX_FCC_CHANNEL_NUM)
+ pr_info("Error, no fcc slot matched to release\n");
+
+ return;
+}
+#endif
+
+static int amstream_open(struct inode *inode, struct file *file)
+{
+ s32 i;
+ struct stream_port_s *s;
+ struct stream_port_s *port = &ports[iminor(inode)];
+ struct port_priv_s *priv;
+
+ VDEC_PRINT_FUN_LINENO(__func__, __LINE__);
+#ifdef G12A_BRINGUP_DEBUG
+ if (vdec_get_debug_flags() & 0xff0000) {
+ pr_info("%s force open port %d\n",
+ __func__,
+ ((vdec_get_debug_flags() >> 16) & 0xff) - 1);
+ port = &ports[((vdec_get_debug_flags() >> 16) & 0xff) - 1];
+ }
+ pr_info("%s, port name %s\n", __func__, port->name);
+#endif
+ if (iminor(inode) >= amstream_port_num)
+ return -ENODEV;
+
+ //pr_err("%s, port name %s\n", __func__, port->name);
+ //pr_err("%s [pid=%d,tgid=%d]\n", __func__, current->pid, current->tgid);
+ mutex_lock(&amstream_mutex);
+
+ if (port->type & PORT_TYPE_VIDEO) {
+ for (s = &ports[0], i = 0; i < amstream_port_num; i++, s++) {
+ if ((!is_mult_inc(s->type)) &&
+ (s->type & PORT_TYPE_VIDEO) &&
+ (s->flag & PORT_FLAG_IN_USE)) {
+ mutex_unlock(&amstream_mutex);
+ return -EBUSY;
+ }
+ }
+ }
+
+ if (!is_support_no_parser()) {
+ if ((port->flag & PORT_FLAG_IN_USE) &&
+ ((port->type & PORT_TYPE_FRAME) == 0)) {
+ mutex_unlock(&amstream_mutex);
+ return -EBUSY;
+ }
+ }
+ /* force dv frame mode */
+ if (force_dv_mode & 0x2) {
+ port->type |= PORT_TYPE_FRAME;
+ port->fops = &vframe_fops;
+ pr_debug("%s, dobly vision force frame mode.\n", __func__);
+ }
+
+ /* esplayer stream mode force dv */
+ if (force_dv_mode & 0x1)
+ port->type |= PORT_TYPE_DUALDEC;
+
+ /* check other ports conflicts for audio */
+ for (s = &ports[0], i = 0; i < amstream_port_num; i++, s++) {
+ if ((s->flag & PORT_FLAG_IN_USE) &&
+ ((port->type) & (s->type) & PORT_TYPE_AUDIO)) {
+ mutex_unlock(&amstream_mutex);
+ return -EBUSY;
+ }
+ }
+
+ priv = kzalloc(sizeof(struct port_priv_s), GFP_KERNEL);
+ if (priv == NULL) {
+ mutex_unlock(&amstream_mutex);
+ return -ENOMEM;
+ }
+
+ mutex_init(&priv->mutex);
+
+ priv->port = port;
+
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M6) {
+ /* TODO: mod gate */
+ /* switch_mod_gate_by_name("demux", 1); */
+ amports_switch_gate("demux", 1);
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M8) {
+ /* TODO: clc gate */
+ /* CLK_GATE_ON(HIU_PARSER_TOP); */
+ amports_switch_gate("parser_top", 1);
+ }
+
+ if (port->type & PORT_TYPE_VIDEO) {
+ /* TODO: mod gate */
+ /* switch_mod_gate_by_name("vdec", 1); */
+ amports_switch_gate("vdec", 1);
+
+ if (has_hevc_vdec()) {
+ if (port->type &
+ (PORT_TYPE_MPTS | PORT_TYPE_HEVC))
+ vdec_poweron(VDEC_HEVC);
+
+ if ((port->type & PORT_TYPE_HEVC) == 0)
+ vdec_poweron(VDEC_1);
+ } else {
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M8)
+ vdec_poweron(VDEC_1);
+ }
+ }
+
+ if (port->type & PORT_TYPE_AUDIO) {
+ /* TODO: mod gate */
+ /* switch_mod_gate_by_name("audio", 1); */
+ amports_switch_gate("audio", 1);
+ }
+ }
+
+ port->vid = 0;
+ port->aid = 0;
+ port->sid = 0;
+ port->pcrid = 0xffff;
+ file->f_op = port->fops;
+ file->private_data = priv;
+
+ port->flag = PORT_FLAG_IN_USE;
+ port->pcr_inited = 0;
+#ifdef DATA_DEBUG
+ debug_filp = filp_open(DEBUG_FILE_NAME, O_WRONLY, 0);
+ if (IS_ERR(debug_filp)) {
+ pr_err("amstream: open debug file failed\n");
+ debug_filp = NULL;
+ }
+#endif
+ mutex_unlock(&amstream_mutex);
+
+ if (port->type & PORT_TYPE_VIDEO) {
+ priv->vdec = vdec_create(port, NULL);
+
+ if (priv->vdec == NULL) {
+ port->flag = 0;
+ kfree(priv);
+ pr_err("amstream: vdec creation failed\n");
+ return -ENOMEM;
+ }
+ if (!(port->type & PORT_TYPE_FRAME)) {
+ if ((port->type & PORT_TYPE_DUALDEC) ||
+ (vdec_get_debug_flags() & 0x100)) {
+ priv->vdec->slave = vdec_create(port, priv->vdec);
+
+ if (priv->vdec->slave == NULL) {
+ vdec_release(priv->vdec);
+ port->flag = 0;
+ kfree(priv);
+ pr_err("amstream: sub vdec creation failed\n");
+ return -ENOMEM;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int amstream_release(struct inode *inode, struct file *file)
+{
+ struct port_priv_s *priv = file->private_data;
+ struct stream_port_s *port = priv->port;
+ struct vdec_s *slave = NULL;
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ u32 port_flag = 0;
+#endif
+ if (iminor(inode) >= amstream_port_num)
+ return -ENODEV;
+
+ mutex_lock(&amstream_mutex);
+
+ if (port_get_inited(priv))
+ amstream_port_release(priv);
+
+ if (priv->vdec) {
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ port_flag = priv->vdec->port_flag;
+#endif
+ if (priv->vdec->slave)
+ slave = priv->vdec->slave;
+ vdec_release(priv->vdec);
+ if (slave)
+ vdec_release(slave);
+ priv->vdec = NULL;
+ }
+
+ if ((port->type & (PORT_TYPE_AUDIO | PORT_TYPE_VIDEO)) ==
+ PORT_TYPE_AUDIO) {
+ s32 i;
+ struct stream_port_s *s;
+
+ for (s = &ports[0], i = 0; i < amstream_port_num; i++, s++) {
+ if ((s->flag & PORT_FLAG_IN_USE)
+ && (s->type & PORT_TYPE_VIDEO))
+ break;
+ }
+ if (i == amstream_port_num)
+ timestamp_firstvpts_set(0);
+ }
+
+ if (!is_mult_inc(port->type) ||
+ (is_mult_inc(port->type) &&
+ !is_support_no_parser()))
+ port->flag = 0;
+
+ /* timestamp_pcrscr_set(0); */
+
+#ifdef DATA_DEBUG
+ if (debug_filp) {
+ filp_close(debug_filp, current->files);
+ debug_filp = NULL;
+ debug_file_pos = 0;
+ }
+#endif
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M6) {
+ if (port->type & PORT_TYPE_VIDEO) {
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M8) {
+#ifndef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ if (has_hevc_vdec())
+ vdec_poweroff(VDEC_HEVC);
+
+ vdec_poweroff(VDEC_1);
+#else
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_TXLX
+ && port->vformat == VFORMAT_H264
+ && port->is_4k) {
+ vdec_poweroff(VDEC_HEVC);
+ }
+
+ if ((port->vformat == VFORMAT_HEVC
+ || port->vformat == VFORMAT_AVS2
+ || port->vformat == VFORMAT_AV1
+ || port->vformat == VFORMAT_VP9)) {
+ vdec_poweroff(VDEC_HEVC);
+ } else {
+ vdec_poweroff(VDEC_1);
+ }
+#endif
+ }
+ /* TODO: mod gate */
+ /* switch_mod_gate_by_name("vdec", 0); */
+ amports_switch_gate("vdec", 0);
+ }
+
+ if (port->type & PORT_TYPE_AUDIO) {
+ /* TODO: mod gate */
+ /* switch_mod_gate_by_name("audio", 0); */
+ /* amports_switch_gate("audio", 0); */
+ }
+
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M8) {
+ /* TODO: clc gate */
+ /* CLK_GATE_OFF(HIU_PARSER_TOP); */
+ amports_switch_gate("parser_top", 0);
+ }
+ /* TODO: mod gate */
+ /* switch_mod_gate_by_name("demux", 0); */
+ amports_switch_gate("demux", 0);
+ }
+
+ amstream_userdata_deinit();
+
+ mutex_destroy(&priv->mutex);
+
+ kfree(priv);
+
+ mutex_unlock(&amstream_mutex);
+ return 0;
+}
+
+static long amstream_ioctl_get_version(struct port_priv_s *priv,
+ ulong arg)
+{
+ int version = (AMSTREAM_IOC_VERSION_FIRST & 0xffff) << 16
+ | (AMSTREAM_IOC_VERSION_SECOND & 0xffff);
+ put_user(version, (u32 __user *)arg);
+
+ return 0;
+}
+static long amstream_ioctl_get(struct port_priv_s *priv, ulong arg)
+{
+ struct stream_port_s *this = priv->port;
+ long r = 0;
+#ifdef VDEC_FCC_SUPPORT
+ int i;
+#endif
+ struct am_ioctl_parm parm;
+
+ if (copy_from_user
+ ((void *)&parm, (void *)arg,
+ sizeof(parm)))
+ r = -EFAULT;
+
+ switch (parm.cmd) {
+ case AMSTREAM_GET_SUB_LENGTH:
+ if ((this->type & PORT_TYPE_SUB) ||
+ (this->type & PORT_TYPE_SUB_RD)) {
+ u32 sub_wp, sub_rp;
+ struct stream_buf_s *psbuf = &bufs[BUF_TYPE_SUBTITLE];
+ int val;
+
+ sub_wp = stbuf_sub_wp_get();
+ sub_rp = stbuf_sub_rp_get();
+
+ if (sub_wp == sub_rp)
+ val = 0;
+ else if (sub_wp > sub_rp)
+ val = sub_wp - sub_rp;
+ else
+ val = psbuf->buf_size - (sub_rp - sub_wp);
+ parm.data_32 = val;
+ } else
+ r = -EINVAL;
+ break;
+ case AMSTREAM_GET_UD_LENGTH:
+ if (this->type & PORT_TYPE_USERDATA) {
+ parm.data_32 = userdata_length;
+ userdata_length = 0;
+ } else
+ r = -EINVAL;
+ break;
+ case AMSTREAM_GET_APTS_LOOKUP:
+ if (this->type & PORT_TYPE_AUDIO) {
+ u32 pts = 0, frame_size, offset;
+
+ offset = parm.data_32;
+ pts_lookup_offset(PTS_TYPE_AUDIO, offset, &pts,
+ &frame_size, 300);
+ parm.data_32 = pts;
+ }
+ break;
+ case AMSTREAM_GET_FIRST_APTS_FLAG:
+ if (this->type & PORT_TYPE_AUDIO) {
+ parm.data_32 = first_pts_checkin_complete(
+ PTS_TYPE_AUDIO);
+ }
+ break;
+ case AMSTREAM_GET_APTS:
+ parm.data_32 = timestamp_apts_get();
+ break;
+ case AMSTREAM_GET_VPTS:
+ parm.data_32 = timestamp_vpts_get();
+ break;
+ case AMSTREAM_GET_VPTS_U64:
+ parm.data_64 = timestamp_vpts_get_u64();
+ break;
+ case AMSTREAM_GET_APTS_U64:
+ parm.data_64 = timestamp_apts_get_u64();
+ break;
+ case AMSTREAM_GET_PCRSCR:
+ parm.data_32 = timestamp_pcrscr_get();
+ break;
+ case AMSTREAM_GET_LAST_CHECKIN_APTS:
+ parm.data_32 = get_last_checkin_pts(PTS_TYPE_AUDIO);
+ break;
+ case AMSTREAM_GET_LAST_CHECKIN_VPTS:
+ parm.data_32 = get_last_checkin_pts(PTS_TYPE_VIDEO);
+ break;
+ case AMSTREAM_GET_LAST_CHECKOUT_APTS:
+ parm.data_32 = get_last_checkout_pts(PTS_TYPE_AUDIO);
+ break;
+ case AMSTREAM_GET_LAST_CHECKOUT_VPTS:
+ parm.data_32 = get_last_checkout_pts(PTS_TYPE_VIDEO);
+ break;
+ case AMSTREAM_GET_SUB_NUM:
+ parm.data_32 = psparser_get_sub_found_num();
+ break;
+ case AMSTREAM_GET_VIDEO_DELAY_LIMIT_MS:
+ parm.data_32 = bufs[BUF_TYPE_VIDEO].max_buffer_delay_ms;
+ break;
+ case AMSTREAM_GET_AUDIO_DELAY_LIMIT_MS:
+ parm.data_32 = bufs[BUF_TYPE_AUDIO].max_buffer_delay_ms;
+ break;
+ case AMSTREAM_GET_VIDEO_CUR_DELAY_MS: {
+ int delay;
+
+ delay = calculation_stream_delayed_ms(
+ PTS_TYPE_VIDEO, NULL, NULL);
+ if (delay >= 0)
+ parm.data_32 = delay;
+ else
+ parm.data_32 = 0;
+ }
+ break;
+
+ case AMSTREAM_GET_AUDIO_CUR_DELAY_MS: {
+ int delay;
+
+ delay = calculation_stream_delayed_ms(
+ PTS_TYPE_AUDIO, NULL, NULL);
+ if (delay >= 0)
+ parm.data_32 = delay;
+ else
+ parm.data_32 = 0;
+ }
+ break;
+ case AMSTREAM_GET_AUDIO_AVG_BITRATE_BPS: {
+ int delay;
+ u32 avgbps;
+
+ delay = calculation_stream_delayed_ms(
+ PTS_TYPE_AUDIO, NULL, &avgbps);
+ if (delay >= 0)
+ parm.data_32 = avgbps;
+ else
+ parm.data_32 = 0;
+ }
+ break;
+ case AMSTREAM_GET_VIDEO_AVG_BITRATE_BPS: {
+ int delay;
+ u32 avgbps;
+
+ delay = calculation_stream_delayed_ms(
+ PTS_TYPE_VIDEO, NULL, &avgbps);
+ if (delay >= 0)
+ parm.data_32 = avgbps;
+ else
+ parm.data_32 = 0;
+ }
+ break;
+ case AMSTREAM_GET_ION_ID:
+ parm.data_32 = priv->vdec->vf_receiver_inst;
+ break;
+ case AMSTREAM_GET_NEED_MORE_DATA:
+ parm.data_32 = vdec_need_more_data(priv->vdec);
+ break;
+ case AMSTREAM_GET_FREED_HANDLE:
+ parm.data_32 = vdec_input_get_freed_handle(priv->vdec);
+ break;
+ case AMSTREAM_GET_OFFSET:
+#ifdef VDEC_FCC_SUPPORT
+ mutex_lock(&fcc.mutex);
+ for (i = 0; i < MAX_FCC_CHANNEL_NUM; i++) {
+ if (priv->vdec->id == fcc.id[i] &&
+ fcc.offset_ready_flag[i]) {
+ parm.data_32 = fcc.offset[i];
+ fcc.offset_ready_flag[i] = 0;
+ break;
+ }
+ }
+ mutex_unlock(&fcc.mutex);
+ if (i >= MAX_FCC_CHANNEL_NUM)
+ pr_info("Error, Get offset fail!\n");
+#endif
+ break;
+ default:
+ r = -ENOIOCTLCMD;
+ break;
+ }
+ /* pr_info("parm size:%d\n", sizeof(parm)); */
+ if (r == 0) {
+ if (copy_to_user((void *)arg, &parm, sizeof(parm)))
+ r = -EFAULT;
+ }
+
+ return r;
+
+}
+static long amstream_ioctl_set(struct port_priv_s *priv, ulong arg)
+{
+ struct stream_port_s *this = priv->port;
+ struct am_ioctl_parm parm;
+ long r = 0;
+ int i;
+
+ if (copy_from_user
+ ((void *)&parm, (void *)arg,
+ sizeof(parm)))
+ r = -EFAULT;
+
+ switch (parm.cmd) {
+ case AMSTREAM_SET_VB_START:
+ if ((this->type & PORT_TYPE_VIDEO) &&
+ ((priv->vdec->vbuf.flag & BUF_FLAG_IN_USE) == 0)) {
+ priv->vdec->vbuf.buf_start = parm.data_32;
+ } else
+ r = -EINVAL;
+ break;
+ case AMSTREAM_SET_VB_SIZE:
+ if ((this->type & PORT_TYPE_VIDEO) &&
+ ((priv->vdec->vbuf.flag & BUF_FLAG_IN_USE) == 0)) {
+ if (priv->vdec->vbuf.flag & BUF_FLAG_ALLOC) {
+ r += stbuf_change_size(
+ &priv->vdec->vbuf,
+ parm.data_32,
+ false);
+ }
+ } else if (this->type & PORT_TYPE_FRAME) {
+ /* todo: frame based set max buffer size */
+ r = 0;
+ } else
+ r = -EINVAL;
+ break;
+ case AMSTREAM_SET_AB_START:
+ if ((this->type & PORT_TYPE_AUDIO) &&
+ ((bufs[BUF_TYPE_AUDIO].flag & BUF_FLAG_IN_USE) == 0))
+ bufs[BUF_TYPE_AUDIO].buf_start = parm.data_32;
+ else
+ r = -EINVAL;
+ break;
+ case AMSTREAM_SET_AB_SIZE:
+ if ((this->type & PORT_TYPE_AUDIO) &&
+ ((bufs[BUF_TYPE_AUDIO].flag & BUF_FLAG_IN_USE) == 0)) {
+ if (bufs[BUF_TYPE_AUDIO].flag & BUF_FLAG_ALLOC) {
+ r = stbuf_change_size(
+ &bufs[BUF_TYPE_AUDIO],
+ parm.data_32,
+ false);
+ }
+ } else
+ r = -EINVAL;
+ break;
+ case AMSTREAM_SET_VFORMAT:
+ if ((this->type & PORT_TYPE_VIDEO) &&
+ (parm.data_vformat < VFORMAT_MAX)) {
+ this->vformat = parm.data_vformat;
+ this->flag |= PORT_FLAG_VFORMAT;
+
+ vdec_set_format(priv->vdec, this->vformat);
+ } else
+ r = -EINVAL;
+ break;
+ case AMSTREAM_SET_AFORMAT:
+ if ((this->type & PORT_TYPE_AUDIO) &&
+ (parm.data_aformat < AFORMAT_MAX)) {
+ memset(&audio_dec_info, 0,
+ sizeof(struct audio_info));
+ /* for new format,reset the audio info. */
+ this->aformat = parm.data_aformat;
+ this->flag |= PORT_FLAG_AFORMAT;
+ } else
+ r = -EINVAL;
+ break;
+ case AMSTREAM_SET_VID:
+ if (this->type & PORT_TYPE_VIDEO) {
+ this->vid = parm.data_32;
+ this->flag |= PORT_FLAG_VID;
+ } else
+ r = -EINVAL;
+
+ break;
+ case AMSTREAM_SET_AID:
+ if (this->type & PORT_TYPE_AUDIO) {
+ this->aid = parm.data_32;
+ this->flag |= PORT_FLAG_AID;
+
+ if (port_get_inited(priv)) {
+ //tsync_audio_break(1);
+ amstream_change_avid(this);
+ }
+ } else
+ r = -EINVAL;
+ break;
+ case AMSTREAM_SET_SID:
+ if (this->type & PORT_TYPE_SUB) {
+ this->sid = parm.data_32;
+ this->flag |= PORT_FLAG_SID;
+
+ if (port_get_inited(priv))
+ amstream_change_sid(this);
+ } else
+ r = -EINVAL;
+
+ break;
+ case AMSTREAM_IOC_PCRID:
+ this->pcrid = parm.data_32;
+ this->pcr_inited = 1;
+ pr_err("set pcrid = 0x%x\n", this->pcrid);
+ break;
+ case AMSTREAM_SET_ACHANNEL:
+ if (this->type & PORT_TYPE_AUDIO) {
+ this->achanl = parm.data_32;
+ set_ch_num_info(parm.data_32);
+ } else
+ r = -EINVAL;
+ break;
+ case AMSTREAM_SET_SAMPLERATE:
+ if (this->type & PORT_TYPE_AUDIO) {
+ this->asamprate = parm.data_32;
+ set_sample_rate_info(parm.data_32);
+ } else
+ r = -EINVAL;
+ break;
+ case AMSTREAM_SET_DATAWIDTH:
+ if (this->type & PORT_TYPE_AUDIO)
+ this->adatawidth = parm.data_32;
+ else
+ r = -EINVAL;
+ break;
+ case AMSTREAM_SET_TSTAMP:
+ if ((this->type & (PORT_TYPE_AUDIO | PORT_TYPE_VIDEO)) ==
+ ((PORT_TYPE_AUDIO | PORT_TYPE_VIDEO)))
+ r = -EINVAL;
+ else if (this->type & PORT_TYPE_FRAME)
+ r = vdec_set_pts(priv->vdec, parm.data_32);
+ else if ((this->type & PORT_TYPE_VIDEO) ||
+ (this->type & PORT_TYPE_HEVC)) {
+ struct stream_buf_s *vbuf = &priv->vdec->vbuf;
+ if (vbuf->no_parser) {
+ pts_checkin_offset(PTS_TYPE_VIDEO,
+ vbuf->stream_offset, parm.data_32);
+ } else {
+ r = es_vpts_checkin(vbuf, parm.data_32);
+ }
+ } else if (this->type & PORT_TYPE_AUDIO)
+ r = es_apts_checkin(&bufs[BUF_TYPE_AUDIO],
+ parm.data_32);
+ break;
+ case AMSTREAM_SET_TSTAMP_US64:
+ if ((this->type & (PORT_TYPE_AUDIO | PORT_TYPE_VIDEO)) ==
+ ((PORT_TYPE_AUDIO | PORT_TYPE_VIDEO)))
+ r = -EINVAL;
+ else {
+ u64 pts = parm.data_64;
+
+ if (this->type & PORT_TYPE_FRAME) {
+ /*
+ *todo: check upper layer for decoder handler
+ * life sequence or multi-tasking management
+ */
+ r = vdec_set_pts64(priv->vdec, pts);
+ } else if ((this->type & PORT_TYPE_HEVC) ||
+ (this->type & PORT_TYPE_VIDEO)) {
+ r = es_vpts_checkin_us64(
+ &priv->vdec->vbuf, pts);
+ } else if (this->type & PORT_TYPE_AUDIO) {
+ r = es_vpts_checkin_us64(
+ &bufs[BUF_TYPE_AUDIO], pts);
+ }
+ }
+ break;
+ case AMSTREAM_PORT_INIT:
+ r = amstream_port_init(priv);
+ break;
+ case AMSTREAM_SET_TRICKMODE:
+ if ((this->type & PORT_TYPE_VIDEO) == 0)
+ return -EINVAL;
+ r = vdec_set_trickmode(priv->vdec, parm.data_32);
+ if (r == -1)
+ return -ENODEV;
+ break;
+
+ case AMSTREAM_AUDIO_RESET:
+ if (this->type & PORT_TYPE_AUDIO) {
+ struct stream_buf_s *pabuf = &bufs[BUF_TYPE_AUDIO];
+
+ mutex_lock(&amstream_mutex);
+ r = audio_port_reset(this, pabuf);
+ mutex_unlock(&amstream_mutex);
+ } else
+ r = -EINVAL;
+
+ break;
+ case AMSTREAM_SUB_RESET:
+ if (this->type & PORT_TYPE_SUB) {
+ struct stream_buf_s *psbuf = &bufs[BUF_TYPE_SUBTITLE];
+
+ r = sub_port_reset(this, psbuf);
+ } else
+ r = -EINVAL;
+ break;
+ case AMSTREAM_DEC_RESET:
+ tsync_set_dec_reset();
+ break;
+ case AMSTREAM_SET_TS_SKIPBYTE:
+ tsdemux_set_skipbyte(parm.data_32);
+ break;
+ case AMSTREAM_SET_SUB_TYPE:
+ sub_type = parm.data_32;
+ break;
+ case AMSTREAM_SET_PCRSCR:
+ timestamp_pcrscr_set(parm.data_32);
+ break;
+ case AMSTREAM_SET_DEMUX:
+ tsdemux_set_demux(parm.data_32);
+ break;
+ case AMSTREAM_SET_VIDEO_DELAY_LIMIT_MS:
+ priv->vdec->vbuf.max_buffer_delay_ms = parm.data_32;
+ break;
+ case AMSTREAM_SET_AUDIO_DELAY_LIMIT_MS:
+ bufs[BUF_TYPE_AUDIO].max_buffer_delay_ms = parm.data_32;
+ break;
+ case AMSTREAM_SET_DRMMODE:
+ if (parm.data_32 == 1) {
+ pr_debug("set drmmode\n");
+ this->flag |= PORT_FLAG_DRM;
+ if ((this->type & PORT_TYPE_VIDEO) &&
+ (priv->vdec))
+ priv->vdec->port_flag |= PORT_FLAG_DRM;
+ } else {
+ this->flag &= (~PORT_FLAG_DRM);
+ pr_debug("no drmmode\n");
+ }
+ break;
+ case AMSTREAM_SET_WORKMODE:
+ case AMSTREAM_SET_FCC_MODE:
+#ifdef VDEC_FCC_SUPPORT
+ if (parm.cmd == AMSTREAM_SET_FCC_MODE) {
+ priv->vdec->fcc_new_msg = 1;
+ if (priv->vdec->fcc_mode == FCC_DEC_MODE) {
+ priv->vdec->fcc_new_msg = 0;
+ if (fcc_debug_enable())
+ pr_info("[%d][FCC]: Current is dec mode, ignore discard message!\n",
+ priv->vdec->id);
+ break;
+ }
+ }
+
+ if (parm.data_32 == FCC_DISCARD_MODE) {
+ if (fcc_debug_enable())
+ pr_info("[%d][FCC]: Set discard pic mode!\n",
+ priv->vdec->id);
+ if ((this->type & PORT_TYPE_VIDEO) &&
+ (priv->vdec)) {
+ priv->vdec->fcc_mode = FCC_DISCARD_MODE;
+ }
+ } else if (parm.data_32 == FCC_DEC_MODE) {
+ if ((this->type & PORT_TYPE_VIDEO) &&
+ (priv->vdec)) {
+ priv->vdec->fcc_mode = FCC_DEC_MODE;
+ }
+ if (fcc_debug_enable()) {
+ pr_info("[%d][FCC]: Set dec pic mode!\n", priv->vdec->id);
+ }
+ } else {
+ pr_info("Para error! Unknow FCC Mode! vdec id: %d\n", priv->vdec->id);
+ }
+#endif
+ break;
+ case AMSTREAM_SET_APTS: {
+ unsigned int pts;
+
+ pts = parm.data_32;
+ if (tsync_get_mode() == TSYNC_MODE_PCRMASTER)
+ tsync_pcr_set_apts(pts);
+ else
+ tsync_set_apts(pts);
+ break;
+ }
+ case AMSTREAM_SET_FRAME_BASE_PATH:
+ if (is_mult_inc(this->type) &&
+ (parm.frame_base_video_path < FRAME_BASE_PATH_MAX)) {
+ vdec_set_video_path(priv->vdec, parm.data_32);
+ } else
+ r = -EINVAL;
+ break;
+ case AMSTREAM_SET_EOS:
+ if (priv->vdec)
+ vdec_set_eos(priv->vdec, parm.data_32);
+ break;
+ case AMSTREAM_SET_RECEIVE_ID:
+ if (is_mult_inc(this->type))
+ vdec_set_receive_id(priv->vdec, parm.data_32);
+ else
+ r = -EINVAL;
+ break;
+ case AMSTREAM_SET_IS_RESET:
+ if (priv->vdec)
+ vdec_set_isreset(priv->vdec, parm.data_32);
+ break;
+ case AMSTREAM_SET_DV_META_WITH_EL:
+ if (priv->vdec) {
+ vdec_set_dv_metawithel(priv->vdec, parm.data_32);
+ if (vdec_dual(priv->vdec) && priv->vdec->slave)
+ vdec_set_dv_metawithel(priv->vdec->slave,
+ parm.data_32);
+ }
+ break;
+ case AMSTREAM_SET_NO_POWERDOWN:
+ vdec_set_no_powerdown(parm.data_32);
+ break;
+ case AMSTREAM_SET_VIDEO_ID:
+ priv->vdec->video_id = parm.data_32;
+ mutex_lock(&userdata.mutex);
+ for (i = 0;i < MAX_USERDATA_CHANNEL_NUM; i++) {
+ if (userdata.used[i] == 0) {
+ userdata.id[i] = priv->vdec->video_id;
+ userdata.used[i] = 1;
+ userdata.video_id = priv->vdec->video_id;
+ userdata.set_id_flag = 1;
+ break;
+ }
+ }
+ mutex_unlock(&userdata.mutex);
+
+ pr_info("AMSTREAM_SET_VIDEO_ID video_id: %d\n", parm.data_32);
+ break;
+ case AMSTREAM_SET_DMC_URGENT:
+ vdec_set_dmc_urgent(priv->vdec, parm.data_32);
+ break;
+
+ default:
+ r = -ENOIOCTLCMD;
+ break;
+ }
+ return r;
+}
+
+static enum E_ASPECT_RATIO get_normalized_aspect_ratio(u32 ratio_control)
+{
+ enum E_ASPECT_RATIO euAspectRatio;
+
+ ratio_control = ratio_control >> DISP_RATIO_ASPECT_RATIO_BIT;
+
+ switch (ratio_control) {
+ case 0x8c:
+ case 0x90:
+ euAspectRatio = ASPECT_RATIO_16_9;
+ /*pr_info("ASPECT_RATIO_16_9\n");*/
+ break;
+ case 0xbb:
+ case 0xc0:
+ euAspectRatio = ASPECT_RATIO_4_3;
+ /*pr_info("ASPECT_RATIO_4_3\n");*/
+ break;
+ default:
+ euAspectRatio = ASPECT_UNDEFINED;
+ /*pr_info("ASPECT_UNDEFINED and ratio_control = 0x%x\n",
+ ratio_control);*/
+ break;
+ }
+
+ return euAspectRatio;
+}
+
+static long amstream_ioctl_get_ex(struct port_priv_s *priv, ulong arg)
+{
+ struct stream_port_s *this = priv->port;
+ long r = 0;
+ struct am_ioctl_parm_ex parm;
+
+ if (copy_from_user
+ ((void *)&parm, (void *)arg,
+ sizeof(parm)))
+ r = -EFAULT;
+
+ switch (parm.cmd) {
+ case AMSTREAM_GET_EX_VB_STATUS:
+ if (this->type & PORT_TYPE_VIDEO) {
+ struct am_ioctl_parm_ex *p = &parm;
+ struct stream_buf_s *buf = NULL;
+
+ mutex_lock(&amstream_mutex);
+
+ /*
+ *todo: check upper layer for decoder
+ * handler lifecycle
+ */
+ if (priv->vdec == NULL) {
+ r = -EINVAL;
+ mutex_unlock(&amstream_mutex);
+ break;
+ }
+
+ if (this->type & PORT_TYPE_FRAME) {
+ struct vdec_input_status_s status;
+
+ r = vdec_input_get_status(&priv->vdec->input,
+ &status);
+ if (r == 0) {
+ p->status.size = status.size;
+ p->status.data_len = status.data_len;
+ p->status.free_len = status.free_len;
+ p->status.read_pointer =
+ status.read_pointer;
+ }
+ mutex_unlock(&amstream_mutex);
+ break;
+ }
+
+ buf = &priv->vdec->vbuf;
+ p->status.size = stbuf_canusesize(buf);
+ p->status.data_len = stbuf_level(buf);
+ p->status.free_len = stbuf_space(buf);
+ p->status.read_pointer = stbuf_rp(buf);
+ mutex_unlock(&amstream_mutex);
+ } else
+ r = -EINVAL;
+ break;
+ case AMSTREAM_GET_EX_AB_STATUS:
+ if (this->type & PORT_TYPE_AUDIO) {
+ struct am_ioctl_parm_ex *p = &parm;
+ struct stream_buf_s *buf = &bufs[BUF_TYPE_AUDIO];
+
+
+ p->status.size = stbuf_canusesize(buf);
+ p->status.data_len = stbuf_level(buf);
+ p->status.free_len = stbuf_space(buf);
+ p->status.read_pointer = stbuf_rp(buf);
+
+ } else
+ r = -EINVAL;
+ break;
+ case AMSTREAM_GET_EX_VDECSTAT:
+ if ((this->type & PORT_TYPE_VIDEO) == 0) {
+ pr_err("no video\n");
+ return -EINVAL;
+ } else {
+ struct vdec_info vstatus;
+ struct am_ioctl_parm_ex *p = &parm;
+
+ memset(&vstatus, 0, sizeof(vstatus));
+
+ mutex_lock(&priv->mutex);
+ if (vdec_status(priv->vdec, &vstatus) == -1) {
+ mutex_unlock(&priv->mutex);
+ return -ENODEV;
+ }
+ mutex_unlock(&priv->mutex);
+
+ p->vstatus.width = vstatus.frame_width;
+ p->vstatus.height = vstatus.frame_height;
+ p->vstatus.fps = vstatus.frame_rate;
+ p->vstatus.error_count = vstatus.error_count;
+ p->vstatus.status = vstatus.status;
+ p->vstatus.euAspectRatio =
+ get_normalized_aspect_ratio(
+ vstatus.ratio_control);
+
+ }
+ break;
+ case AMSTREAM_GET_EX_ADECSTAT:
+ if ((this->type & PORT_TYPE_AUDIO) == 0) {
+ pr_err("no audio\n");
+ return -EINVAL;
+ }
+ if (amstream_adec_status == NULL) {
+ /*
+ *pr_err("no amstream_adec_status\n");
+ *return -ENODEV;
+ */
+ memset(&parm.astatus, 0, sizeof(parm.astatus));
+ } else {
+ struct adec_status astatus;
+ struct am_ioctl_parm_ex *p = &parm;
+
+ amstream_adec_status(&astatus);
+ p->astatus.channels = astatus.channels;
+ p->astatus.sample_rate = astatus.sample_rate;
+ p->astatus.resolution = astatus.resolution;
+ p->astatus.error_count = astatus.error_count;
+ p->astatus.status = astatus.status;
+ }
+ break;
+
+ case AMSTREAM_GET_EX_UD_POC:
+ if (this->type & PORT_TYPE_USERDATA) {
+ struct userdata_poc_info_t userdata_poc =
+ userdata_poc_info[userdata_poc_ri];
+ memcpy(&parm.data_userdata_info,
+ &userdata_poc,
+ sizeof(struct userdata_poc_info_t));
+
+ userdata_poc_ri++;
+ if (userdata_poc_ri == USERDATA_FIFO_NUM)
+ userdata_poc_ri = 0;
+ } else
+ r = -EINVAL;
+ break;
+ case AMSTREAM_GET_EX_WR_COUNT:
+ {
+ struct am_ioctl_parm_ex *p = &parm;
+ struct vdec_s *vdec = priv->vdec;
+
+ mutex_lock(&amstream_mutex);
+ if (!vdec)
+ vdec = vdec_get_vdec_by_id(0); //Use id 0 as default
+ if (vdec && vdec->mvfrm)
+ p->wr_count = vdec->mvfrm->wr;
+ else
+ p->wr_count = 0;
+ mutex_unlock(&amstream_mutex);
+ r = 0;
+ }
+ break;
+ default:
+ r = -ENOIOCTLCMD;
+ break;
+ }
+ /* pr_info("parm size:%zx\n", sizeof(parm)); */
+ if (r == 0) {
+ if (copy_to_user((void *)arg, &parm, sizeof(parm)))
+ r = -EFAULT;
+ }
+ return r;
+
+}
+static long amstream_ioctl_set_ex(struct port_priv_s *priv, ulong arg)
+{
+ long r = 0;
+ return r;
+}
+static long amstream_ioctl_get_ptr(struct port_priv_s *priv, ulong arg)
+{
+ long r = 0;
+
+ struct am_ioctl_parm_ptr parm;
+
+ if (copy_from_user
+ ((void *)&parm, (void *)arg,
+ sizeof(parm)))
+ return -EFAULT;
+
+ switch (parm.cmd) {
+ case AMSTREAM_GET_PTR_SUB_INFO:
+ {
+ struct subtitle_info msub_info[MAX_SUB_NUM];
+ struct subtitle_info *psub_info[MAX_SUB_NUM];
+ int i;
+
+ for (i = 0; i < MAX_SUB_NUM; i++)
+ psub_info[i] = &msub_info[i];
+
+ r = psparser_get_sub_info(psub_info);
+
+ if (r == 0) {
+ memcpy(parm.pdata_sub_info, msub_info,
+ sizeof(struct subtitle_info)
+ * MAX_SUB_NUM);
+ }
+ }
+ break;
+ default:
+ r = -ENOIOCTLCMD;
+ break;
+ }
+ /* pr_info("parm size:%d\n", sizeof(parm)); */
+ if (r == 0) {
+ if (copy_to_user((void *)arg, &parm, sizeof(parm)))
+ r = -EFAULT;
+ }
+
+ return r;
+
+}
+static long amstream_ioctl_set_ptr(struct port_priv_s *priv, ulong arg)
+{
+ struct stream_port_s *this = priv->port;
+ struct am_ioctl_parm_ptr parm;
+ long r = 0;
+
+ if (copy_from_user
+ ((void *)&parm, (void *)arg,
+ sizeof(parm))) {
+ pr_err("[%s]%d, arg err\n", __func__, __LINE__);
+ r = -EFAULT;
+ }
+ switch (parm.cmd) {
+ case AMSTREAM_SET_PTR_AUDIO_INFO:
+ if ((this->type & PORT_TYPE_VIDEO)
+ || (this->type & PORT_TYPE_AUDIO)) {
+ if (parm.pdata_audio_info != NULL) {
+ if (copy_from_user
+ ((void *)&audio_dec_info, (void *)parm.pdata_audio_info,
+ sizeof(audio_dec_info))) {
+ pr_err("[%s]%d, arg err\n", __func__, __LINE__);
+ r = -EFAULT;
+ }
+ }
+ } else
+ r = -EINVAL;
+ break;
+ case AMSTREAM_SET_PTR_CONFIGS:
+ if (this->type & PORT_TYPE_VIDEO) {
+ if (!parm.pointer || (parm.len <= 0) ||
+ (parm.len > PAGE_SIZE)) {
+ r = -EINVAL;
+ } else {
+ r = copy_from_user(priv->vdec->config,
+ parm.pointer, parm.len);
+ if (r)
+ r = -EINVAL;
+ else
+ priv->vdec->config_len = parm.len;
+ }
+ } else
+ r = -EINVAL;
+ break;
+ case AMSTREAM_SET_PTR_HDR10P_DATA:
+ if ((this->type & PORT_TYPE_VIDEO) && (this->type & PORT_TYPE_FRAME)) {
+ if (!parm.pointer || (parm.len <= 0) ||
+ (parm.len > PAGE_SIZE)) {
+ r = -EINVAL;
+ } else {
+ r = copy_from_user(priv->vdec->hdr10p_data_buf,
+ parm.pointer, parm.len);
+ if (r) {
+ priv->vdec->hdr10p_data_size = 0;
+ priv->vdec->hdr10p_data_valid = false;
+ r = -EINVAL;
+ } else {
+ priv->vdec->hdr10p_data_size = parm.len;
+ priv->vdec->hdr10p_data_valid = true;
+ }
+ }
+ } else
+ r = -EINVAL;
+ break;
+ default:
+ r = -ENOIOCTLCMD;
+ break;
+ }
+ return r;
+}
+
+static long amstream_do_ioctl_new(struct port_priv_s *priv,
+ unsigned int cmd, ulong arg)
+{
+ long r = 0;
+ struct stream_port_s *this = priv->port;
+
+ switch (cmd) {
+ case AMSTREAM_IOC_GET_VERSION:
+ r = amstream_ioctl_get_version(priv, arg);
+ break;
+ case AMSTREAM_IOC_GET:
+ r = amstream_ioctl_get(priv, arg);
+ break;
+ case AMSTREAM_IOC_SET:
+ r = amstream_ioctl_set(priv, arg);
+ break;
+ case AMSTREAM_IOC_GET_EX:
+ r = amstream_ioctl_get_ex(priv, arg);
+ break;
+ case AMSTREAM_IOC_SET_EX:
+ r = amstream_ioctl_set_ex(priv, arg);
+ break;
+ case AMSTREAM_IOC_GET_PTR:
+ r = amstream_ioctl_get_ptr(priv, arg);
+ break;
+ case AMSTREAM_IOC_SET_PTR:
+ r = amstream_ioctl_set_ptr(priv, arg);
+ break;
+ case AMSTREAM_IOC_SYSINFO:
+ if (this->type & PORT_TYPE_VIDEO)
+ r = vdec_set_decinfo(priv->vdec, (void *)arg);
+ else
+ r = -EINVAL;
+ break;
+ case AMSTREAM_IOC_GET_QOSINFO:
+ case AMSTREAM_IOC_GET_MVDECINFO:
+ {
+ u32 slots = 0;
+ u32 struct_size = 0;
+ int vdec_id = 0;
+ struct vdec_s *vdec = priv->vdec;
+ struct vframe_counter_s *tmpbuf = kmalloc(QOS_FRAME_NUM *
+ sizeof(struct vframe_counter_s),GFP_KERNEL);
+ struct av_param_mvdec_t __user *uarg = (void *)arg;
+
+ mutex_lock(&amstream_mutex);
+ if (!tmpbuf) {
+ r = -EFAULT;
+ pr_err("kmalloc vframe_counter_s failed!\n");
+ mutex_unlock(&amstream_mutex);
+ break;
+ }
+
+ if (get_user(vdec_id, &uarg->vdec_id) < 0 ||
+ get_user(struct_size, &uarg->struct_size) < 0) {
+ r = -EFAULT;
+ kfree(tmpbuf);
+ mutex_unlock(&amstream_mutex);
+ break;
+ }
+
+ if (vdec && !vdec_id) //If vdec_id is > 0, it means user require to use it.
+ r = 0;//vdec =priv->vdec;//Nothing to do.
+ else
+ vdec = vdec_get_vdec_by_id(vdec_id);
+ if (!vdec) {
+ r = 0;
+ kfree(tmpbuf);
+ mutex_unlock(&amstream_mutex);
+ break;
+ }
+
+ slots = vdec_get_frame_vdec(vdec, tmpbuf);
+ if (AMSTREAM_IOC_GET_MVDECINFO == cmd)
+ put_user(slots, &uarg->slots);
+ if (slots) {
+ if (AMSTREAM_IOC_GET_MVDECINFO == cmd) {
+ if (vdec->mvfrm && copy_to_user((void *)&uarg->comm,
+ &vdec->mvfrm->comm,
+ sizeof(struct vframe_comm_s))) {
+ r = -EFAULT;
+ kfree(tmpbuf);
+ mutex_unlock(&amstream_mutex);
+ break;
+ }
+ if (struct_size == sizeof(struct av_param_mvdec_t_old)) {//old struct
+ struct av_param_mvdec_t_old __user *uarg_old = (void *)arg;
+ int m;
+ for (m=0; m<slots; m++) {
+ if (copy_to_user((void *)&uarg_old->minfo[m],
+ &tmpbuf[m],
+ sizeof(struct vframe_counter_s_old))) {
+ r = -EFAULT;
+ mutex_unlock(&amstream_mutex);
+ break;
+ }
+ }
+ if (r < 0) {
+ kfree(tmpbuf);
+ mutex_unlock(&amstream_mutex);
+ break;
+ }
+ } else if (struct_size == sizeof(struct av_param_mvdec_t)) {//new struct
+ if (copy_to_user((void *)&uarg->minfo[0],
+ tmpbuf,
+ slots*sizeof(struct vframe_counter_s))) {
+ r = -EFAULT;
+ kfree(tmpbuf);
+ mutex_unlock(&amstream_mutex);
+ break;
+ }
+ } else {
+ pr_err("pass in size %u,old struct size %u,current struct size %u\n",
+ struct_size, (u32)sizeof(struct av_param_mvdec_t_old),(u32)sizeof(struct av_param_mvdec_t));
+ pr_err("App use another picture size,we haven't support it.\n");
+ }
+ }else { //For compatibility, only copy the qos
+ struct av_param_qosinfo_t __user *uarg = (void *)arg;
+ int i;
+ for (i=0; i<slots; i++) {
+ if (copy_to_user((void *)&uarg->vframe_qos[i],
+ &tmpbuf[i].qos,
+ sizeof(struct vframe_qos_s))) {
+ r = -EFAULT;
+ mutex_unlock(&amstream_mutex);
+ break;
+ }
+ }
+ if (r < 0) {
+ kfree(tmpbuf);
+ mutex_unlock(&amstream_mutex);
+ break;
+ }
+ }
+ } else {
+ /*Vdec didn't produce item,wait for 10 ms to avoid user application
+ infinitely calling*/
+ //msleep(10); let user app handle it.
+ }
+ kfree(tmpbuf);
+ }
+ mutex_unlock(&amstream_mutex);
+ break;
+ case AMSTREAM_IOC_GET_AVINFO:
+ {
+ struct av_param_info_t __user *uarg = (void *)arg;
+ struct av_info_t av_info = {0};
+ int delay;
+ u32 avgbps;
+ if (this->type & PORT_TYPE_VIDEO) {
+ av_info.first_pic_coming = get_first_pic_coming();
+ av_info.current_fps = -1;
+ av_info.vpts = timestamp_vpts_get();
+ av_info.vpts_err = tsync_get_vpts_error_num();
+ av_info.apts = timestamp_apts_get();
+ av_info.apts_err = tsync_get_apts_error_num();
+ av_info.ts_error = get_discontinue_counter();
+ av_info.first_vpts = timestamp_firstvpts_get();
+ av_info.toggle_frame_count = get_toggle_frame_count();
+ delay = calculation_stream_delayed_ms(
+ PTS_TYPE_VIDEO, NULL, &avgbps);
+ if (delay >= 0)
+ av_info.dec_video_bps = avgbps;
+ else
+ av_info.dec_video_bps = 0;
+ }
+ if (copy_to_user((void *)&uarg->av_info, (void *)&av_info,
+ sizeof(struct av_info_t)))
+ r = -EFAULT;
+ }
+ break;
+ default:
+ r = -ENOIOCTLCMD;
+ break;
+ }
+
+ return r;
+}
+
+static long amstream_do_ioctl_old(struct port_priv_s *priv,
+ unsigned int cmd, ulong arg)
+{
+ struct stream_port_s *this = priv->port;
+ long r = 0;
+ int i;
+
+ switch (cmd) {
+
+ case AMSTREAM_IOC_VB_START:
+ if ((this->type & PORT_TYPE_VIDEO) &&
+ ((priv->vdec->vbuf.flag & BUF_FLAG_IN_USE) == 0)) {
+ priv->vdec->vbuf.buf_start = arg;
+ } else
+ r = -EINVAL;
+ break;
+
+ case AMSTREAM_IOC_VB_SIZE:
+ if ((this->type & PORT_TYPE_VIDEO) &&
+ ((priv->vdec->vbuf.flag & BUF_FLAG_IN_USE) == 0)) {
+ if (priv->vdec->vbuf.flag & BUF_FLAG_ALLOC) {
+ r += stbuf_change_size(
+ &priv->vdec->vbuf,
+ arg, false);
+ }
+ } else
+ r = -EINVAL;
+ break;
+
+ case AMSTREAM_IOC_AB_START:
+ if ((this->type & PORT_TYPE_AUDIO) &&
+ ((bufs[BUF_TYPE_AUDIO].flag & BUF_FLAG_IN_USE) == 0))
+ bufs[BUF_TYPE_AUDIO].buf_start = arg;
+ else
+ r = -EINVAL;
+ break;
+
+ case AMSTREAM_IOC_AB_SIZE:
+ if ((this->type & PORT_TYPE_AUDIO) &&
+ ((bufs[BUF_TYPE_AUDIO].flag & BUF_FLAG_IN_USE) == 0)) {
+ if (bufs[BUF_TYPE_AUDIO].flag & BUF_FLAG_ALLOC) {
+ r = stbuf_change_size(
+ &bufs[BUF_TYPE_AUDIO], arg, false);
+ }
+ } else
+ r = -EINVAL;
+ break;
+
+ case AMSTREAM_IOC_VFORMAT:
+ if ((this->type & PORT_TYPE_VIDEO) && (arg < VFORMAT_MAX)) {
+ this->vformat = (enum vformat_e)arg;
+ this->flag |= PORT_FLAG_VFORMAT;
+
+ vdec_set_format(priv->vdec, this->vformat);
+ } else
+ r = -EINVAL;
+ break;
+
+ case AMSTREAM_IOC_AFORMAT:
+ if ((this->type & PORT_TYPE_AUDIO) && (arg < AFORMAT_MAX)) {
+ memset(&audio_dec_info, 0,
+ sizeof(struct audio_info));
+ /* for new format,reset the audio info. */
+ this->aformat = (enum aformat_e)arg;
+ this->flag |= PORT_FLAG_AFORMAT;
+ } else
+ r = -EINVAL;
+ break;
+
+ case AMSTREAM_IOC_VID:
+ if (this->type & PORT_TYPE_VIDEO) {
+ this->vid = (u32) arg;
+ this->flag |= PORT_FLAG_VID;
+ } else
+ r = -EINVAL;
+
+ break;
+
+ case AMSTREAM_IOC_AID:
+ if (this->type & PORT_TYPE_AUDIO) {
+ this->aid = (u32) arg;
+ this->flag |= PORT_FLAG_AID;
+
+ if (port_get_inited(priv)) {
+ //tsync_audio_break(1);
+ amstream_change_avid(this);
+ }
+ } else
+ r = -EINVAL;
+ break;
+
+ case AMSTREAM_IOC_SID:
+ if (this->type & PORT_TYPE_SUB) {
+ this->sid = (u32) arg;
+ this->flag |= PORT_FLAG_SID;
+
+ if (port_get_inited(priv))
+ amstream_change_sid(this);
+ } else
+ r = -EINVAL;
+
+ break;
+
+ case AMSTREAM_IOC_PCRID:
+ this->pcrid = (u32) arg;
+ this->pcr_inited = 1;
+ pr_err("set pcrid = 0x%x\n", this->pcrid);
+ break;
+
+ case AMSTREAM_IOC_VB_STATUS:
+ if (this->type & PORT_TYPE_VIDEO) {
+ struct am_io_param para;
+ struct am_io_param *p = ¶
+ struct stream_buf_s *buf = NULL;
+
+ mutex_lock(&amstream_mutex);
+
+ /*
+ *todo: check upper layer for decoder
+ * handler lifecycle
+ */
+ if (priv->vdec == NULL) {
+ r = -EINVAL;
+ mutex_unlock(&amstream_mutex);
+ break;
+ }
+
+ if (this->type & PORT_TYPE_FRAME) {
+ struct vdec_input_status_s status;
+
+ r = vdec_input_get_status(&priv->vdec->input,
+ &status);
+ if (r == 0) {
+ p->status.size = status.size;
+ p->status.data_len = status.data_len;
+ p->status.free_len = status.free_len;
+ p->status.read_pointer =
+ status.read_pointer;
+ if (copy_to_user((void *)arg, p,
+ sizeof(para)))
+ r = -EFAULT;
+ }
+ mutex_unlock(&amstream_mutex);
+ break;
+ }
+
+ buf = &priv->vdec->vbuf;
+ p->status.size = stbuf_canusesize(buf);
+ p->status.data_len = stbuf_level(buf);
+ p->status.free_len = stbuf_space(buf);
+ p->status.read_pointer = stbuf_rp(buf);
+ if (copy_to_user((void *)arg, p, sizeof(para)))
+ r = -EFAULT;
+
+ mutex_unlock(&amstream_mutex);
+ return r;
+ }
+ r = -EINVAL;
+ break;
+
+ case AMSTREAM_IOC_AB_STATUS:
+ if (this->type & PORT_TYPE_AUDIO) {
+ struct am_io_param para;
+ struct am_io_param *p = ¶
+ struct stream_buf_s *buf = &bufs[BUF_TYPE_AUDIO];
+
+ p->status.size = stbuf_canusesize(buf);
+ p->status.data_len = stbuf_level(buf);
+ p->status.free_len = stbuf_space(buf);
+ p->status.read_pointer = stbuf_rp(buf);
+ if (copy_to_user((void *)arg, p, sizeof(para)))
+ r = -EFAULT;
+ return r;
+ }
+ r = -EINVAL;
+ break;
+
+ case AMSTREAM_IOC_SYSINFO:
+ if (this->type & PORT_TYPE_VIDEO)
+ r = vdec_set_decinfo(priv->vdec, (void *)arg);
+ else
+ r = -EINVAL;
+ break;
+
+ case AMSTREAM_IOC_ACHANNEL:
+ if (this->type & PORT_TYPE_AUDIO) {
+ this->achanl = (u32) arg;
+ set_ch_num_info((u32) arg);
+ } else
+ r = -EINVAL;
+ break;
+
+ case AMSTREAM_IOC_SAMPLERATE:
+ if (this->type & PORT_TYPE_AUDIO) {
+ this->asamprate = (u32) arg;
+ set_sample_rate_info((u32) arg);
+ } else
+ r = -EINVAL;
+ break;
+
+ case AMSTREAM_IOC_DATAWIDTH:
+ if (this->type & PORT_TYPE_AUDIO)
+ this->adatawidth = (u32) arg;
+ else
+ r = -EINVAL;
+ break;
+
+ case AMSTREAM_IOC_TSTAMP:
+ if ((this->type & (PORT_TYPE_AUDIO | PORT_TYPE_VIDEO)) ==
+ ((PORT_TYPE_AUDIO | PORT_TYPE_VIDEO)))
+ r = -EINVAL;
+ else if (this->type & PORT_TYPE_FRAME)
+ r = vdec_set_pts(priv->vdec, arg);
+ else if ((this->type & PORT_TYPE_VIDEO) ||
+ (this->type & PORT_TYPE_HEVC)) {
+ struct stream_buf_s *vbuf = &priv->vdec->vbuf;
+ if (vbuf->no_parser) {
+ pts_checkin_offset(PTS_TYPE_VIDEO,
+ vbuf->stream_offset, arg);
+ } else {
+ r = es_vpts_checkin(vbuf, arg);
+ }
+ } else if (this->type & PORT_TYPE_AUDIO)
+ r = es_apts_checkin(&bufs[BUF_TYPE_AUDIO], arg);
+ break;
+
+ case AMSTREAM_IOC_TSTAMP_uS64:
+ if ((this->type & (PORT_TYPE_AUDIO | PORT_TYPE_VIDEO)) ==
+ ((PORT_TYPE_AUDIO | PORT_TYPE_VIDEO)))
+ r = -EINVAL;
+ else {
+ u64 pts;
+
+ if (copy_from_user
+ ((void *)&pts, (void *)arg, sizeof(u64)))
+ return -EFAULT;
+ if (this->type & PORT_TYPE_FRAME) {
+ /*
+ *todo: check upper layer for decoder handler
+ * life sequence or multi-tasking management
+ */
+ if (priv->vdec)
+ r = vdec_set_pts64(priv->vdec, pts);
+ } else if ((this->type & PORT_TYPE_HEVC) ||
+ (this->type & PORT_TYPE_VIDEO)) {
+ r = es_vpts_checkin_us64(
+ &priv->vdec->vbuf, pts);
+ } else if (this->type & PORT_TYPE_AUDIO) {
+ r = es_vpts_checkin_us64(
+ &bufs[BUF_TYPE_AUDIO], pts);
+ }
+ }
+ break;
+
+ case AMSTREAM_IOC_VDECSTAT:
+ if ((this->type & PORT_TYPE_VIDEO) == 0)
+ return -EINVAL;
+ {
+ struct vdec_info vstatus;
+ struct am_io_param para;
+ struct am_io_param *p = ¶
+
+ memset(&vstatus, 0, sizeof(vstatus));
+
+ mutex_lock(&priv->mutex);
+ if (vdec_status(priv->vdec, &vstatus) == -1) {
+ mutex_unlock(&priv->mutex);
+ return -ENODEV;
+ }
+ mutex_unlock(&priv->mutex);
+
+ p->vstatus.width = vstatus.frame_width;
+ p->vstatus.height = vstatus.frame_height;
+ p->vstatus.fps = vstatus.frame_rate;
+ p->vstatus.error_count = vstatus.error_count;
+ p->vstatus.status = vstatus.status;
+ p->vstatus.euAspectRatio =
+ get_normalized_aspect_ratio(
+ vstatus.ratio_control);
+
+ if (copy_to_user((void *)arg, p, sizeof(para)))
+ r = -EFAULT;
+ return r;
+ }
+
+ case AMSTREAM_IOC_VDECINFO:
+ if ((this->type & PORT_TYPE_VIDEO) == 0)
+ return -EINVAL;
+ {
+ struct vdec_info vinfo;
+ struct am_io_info para;
+
+ memset(¶, 0x0, sizeof(struct am_io_info));
+
+ mutex_lock(&priv->mutex);
+ if (vdec_status(priv->vdec, &vinfo) == -1) {
+ mutex_unlock(&priv->mutex);
+ return -ENODEV;
+ }
+ mutex_unlock(&priv->mutex);
+
+ memcpy(¶.vinfo, &vinfo, sizeof(struct vdec_info));
+ if (copy_to_user((void *)arg, ¶, sizeof(para)))
+ r = -EFAULT;
+ return r;
+ }
+
+ case AMSTREAM_IOC_ADECSTAT:
+ if ((this->type & PORT_TYPE_AUDIO) == 0)
+ return -EINVAL;
+ if (amstream_adec_status == NULL)
+ return -ENODEV;
+ else {
+ struct adec_status astatus;
+ struct am_io_param para;
+ struct am_io_param *p = ¶
+
+ amstream_adec_status(&astatus);
+ p->astatus.channels = astatus.channels;
+ p->astatus.sample_rate = astatus.sample_rate;
+ p->astatus.resolution = astatus.resolution;
+ p->astatus.error_count = astatus.error_count;
+ p->astatus.status = astatus.status;
+ if (copy_to_user((void *)arg, p, sizeof(para)))
+ r = -EFAULT;
+ return r;
+ }
+ case AMSTREAM_IOC_PORT_INIT:
+ r = amstream_port_init(priv);
+ break;
+
+ case AMSTREAM_IOC_VDEC_RESET:
+ if ((this->type & PORT_TYPE_VIDEO) == 0)
+ return -EINVAL;
+
+ if (priv->vdec == NULL)
+ return -ENODEV;
+
+ r = vdec_reset(priv->vdec);
+ break;
+
+ case AMSTREAM_IOC_TRICKMODE:
+ if ((this->type & PORT_TYPE_VIDEO) == 0)
+ return -EINVAL;
+ r = vdec_set_trickmode(priv->vdec, arg);
+ if (r == -1)
+ return -ENODEV;
+ break;
+
+ case AMSTREAM_IOC_AUDIO_INFO:
+ if ((this->type & PORT_TYPE_VIDEO)
+ || (this->type & PORT_TYPE_AUDIO)) {
+ if (copy_from_user
+ (&audio_dec_info, (void __user *)arg,
+ sizeof(audio_dec_info)))
+ r = -EFAULT;
+ } else
+ r = -EINVAL;
+ break;
+
+ case AMSTREAM_IOC_AUDIO_RESET:
+ if (this->type & PORT_TYPE_AUDIO) {
+ struct stream_buf_s *pabuf = &bufs[BUF_TYPE_AUDIO];
+
+ mutex_lock(&amstream_mutex);
+ r = audio_port_reset(this, pabuf);
+ mutex_unlock(&amstream_mutex);
+ } else
+ r = -EINVAL;
+
+ break;
+
+ case AMSTREAM_IOC_SUB_RESET:
+ if (this->type & PORT_TYPE_SUB) {
+ struct stream_buf_s *psbuf = &bufs[BUF_TYPE_SUBTITLE];
+
+ r = sub_port_reset(this, psbuf);
+ } else
+ r = -EINVAL;
+ break;
+
+ case AMSTREAM_IOC_SUB_LENGTH:
+ if ((this->type & PORT_TYPE_SUB) ||
+ (this->type & PORT_TYPE_SUB_RD)) {
+ u32 sub_wp, sub_rp;
+ struct stream_buf_s *psbuf = &bufs[BUF_TYPE_SUBTITLE];
+ int val;
+
+ sub_wp = stbuf_sub_wp_get();
+ sub_rp = stbuf_sub_rp_get();
+
+ if (sub_wp == sub_rp)
+ val = 0;
+ else if (sub_wp > sub_rp)
+ val = sub_wp - sub_rp;
+ else
+ val = psbuf->buf_size - (sub_rp - sub_wp);
+ put_user(val, (int __user *)arg);
+ } else
+ r = -EINVAL;
+ break;
+
+ case AMSTREAM_IOC_UD_LENGTH:
+ if (this->type & PORT_TYPE_USERDATA) {
+ /* *((u32 *)arg) = userdata_length; */
+ put_user(userdata_length, (unsigned long __user *)arg);
+ userdata_length = 0;
+ } else
+ r = -EINVAL;
+ break;
+
+ case AMSTREAM_IOC_UD_POC:
+ if (this->type & PORT_TYPE_USERDATA) {
+ /* *((u32 *)arg) = userdata_length; */
+ int ri;
+#ifdef DEBUG_USER_DATA
+ int wi;
+#endif
+ int bDataAvail = 0;
+
+ mutex_lock(&userdata_mutex);
+ if (userdata_poc_wi != userdata_poc_ri) {
+ bDataAvail = 1;
+ ri = userdata_poc_ri;
+#ifdef DEBUG_USER_DATA
+ wi = userdata_poc_wi;
+#endif
+ userdata_poc_ri++;
+ if (userdata_poc_ri >= USERDATA_FIFO_NUM)
+ userdata_poc_ri = 0;
+ }
+ mutex_unlock(&userdata_mutex);
+ if (bDataAvail) {
+ int res;
+ struct userdata_poc_info_t userdata_poc =
+ userdata_poc_info[ri];
+#ifdef DEBUG_USER_DATA
+ pr_info("read poc: ri=%d, wi=%d, poc=%d, last_wi=%d\n",
+ ri, wi,
+ userdata_poc.poc_number,
+ last_read_wi);
+#endif
+ res =
+ copy_to_user((unsigned long __user *)arg,
+ &userdata_poc,
+ sizeof(struct userdata_poc_info_t));
+ if (res < 0)
+ r = -EFAULT;
+ } else {
+ r = -EFAULT;
+ }
+ } else {
+ r = -EINVAL;
+ }
+ break;
+
+ case AMSTREAM_IOC_UD_BUF_READ:
+ {
+ if (this->type & PORT_TYPE_USERDATA) {
+ struct userdata_param_t param;
+ struct userdata_param_t *p_userdata_param;
+ struct vdec_s *vdec;
+
+ p_userdata_param = ¶m;
+ if (copy_from_user(p_userdata_param,
+ (void __user *)arg,
+ sizeof(struct userdata_param_t))) {
+ r = -EFAULT;
+ break;
+ }
+ mutex_lock(&amstream_mutex);
+ vdec = vdec_get_vdec_by_video_id(p_userdata_param->instance_id);
+ if (vdec) {
+ if (vdec_read_user_data(vdec,
+ p_userdata_param) == 0) {
+ r = -EFAULT;
+ mutex_unlock(&amstream_mutex);
+ break;
+ }
+
+ if (copy_to_user((void *)arg,
+ p_userdata_param,
+ sizeof(struct userdata_param_t)))
+ r = -EFAULT;
+ } else
+ r = -EINVAL;
+ mutex_unlock(&amstream_mutex);
+ }
+ }
+ break;
+
+ case AMSTREAM_IOC_UD_AVAILABLE_VDEC:
+ {
+ unsigned int ready_vdec = 0;
+ u32 ready_flag = 0;
+
+ mutex_lock(&userdata.mutex);
+ for (i = 0; i < MAX_USERDATA_CHANNEL_NUM; i++) {
+ if (userdata.video_id == userdata.id[i] &&
+ userdata.ready_flag[i] == 1) {
+ ready_vdec = userdata.id[i];
+ userdata.ready_flag[i] = 0;
+ ready_flag = 1;
+ break;
+ }
+ }
+ if (!ready_flag)
+ r = -EINVAL;
+ mutex_unlock(&userdata.mutex);
+
+ put_user(ready_vdec, (uint32_t __user *)arg);
+ }
+ break;
+
+ case AMSTREAM_IOC_GET_VDEC_ID:
+ if (this->type & PORT_TYPE_VIDEO && priv->vdec) {
+ put_user(priv->vdec->id, (int32_t __user *)arg);
+ } else
+ r = -EINVAL;
+ break;
+
+
+ case AMSTREAM_IOC_UD_FLUSH_USERDATA:
+ if (this->type & PORT_TYPE_USERDATA) {
+ struct vdec_s *vdec;
+ int vdec_id;
+
+ mutex_lock(&amstream_mutex);
+ get_user(vdec_id, (int __user *)arg);
+ vdec = vdec_get_vdec_by_id(vdec_id);
+ if (vdec) {
+ vdec_reset_userdata_fifo(vdec, 0);
+ pr_info("reset_userdata_fifo for vdec: %d\n", vdec_id);
+ }
+ mutex_unlock(&amstream_mutex);
+ } else
+ r = -EINVAL;
+ break;
+
+ case AMSTREAM_IOC_SET_DEC_RESET:
+ tsync_set_dec_reset();
+ break;
+
+ case AMSTREAM_IOC_TS_SKIPBYTE:
+ if ((int)arg >= 0)
+ tsdemux_set_skipbyte(arg);
+ else
+ r = -EINVAL;
+ break;
+
+ case AMSTREAM_IOC_SUB_TYPE:
+ sub_type = (int)arg;
+ break;
+
+ case AMSTREAM_IOC_APTS_LOOKUP:
+ if (this->type & PORT_TYPE_AUDIO) {
+ u32 pts = 0, frame_size, offset;
+
+ get_user(offset, (unsigned long __user *)arg);
+ pts_lookup_offset(PTS_TYPE_AUDIO, offset, &pts,
+ &frame_size, 300);
+ put_user(pts, (int __user *)arg);
+ }
+ return 0;
+ case GET_FIRST_APTS_FLAG:
+ if (this->type & PORT_TYPE_AUDIO) {
+ put_user(first_pts_checkin_complete(PTS_TYPE_AUDIO),
+ (int __user *)arg);
+ }
+ break;
+
+ case AMSTREAM_IOC_APTS:
+ put_user(timestamp_apts_get(), (int __user *)arg);
+ break;
+
+ case AMSTREAM_IOC_VPTS:
+ put_user(timestamp_vpts_get(), (int __user *)arg);
+ break;
+
+ case AMSTREAM_IOC_PCRSCR:
+ put_user(timestamp_pcrscr_get(), (int __user *)arg);
+ break;
+
+ case AMSTREAM_IOC_SET_PCRSCR:
+ timestamp_pcrscr_set(arg);
+ break;
+ case AMSTREAM_IOC_GET_LAST_CHECKIN_APTS:
+ put_user(get_last_checkin_pts(PTS_TYPE_AUDIO), (int *)arg);
+ break;
+ case AMSTREAM_IOC_GET_LAST_CHECKIN_VPTS:
+ put_user(get_last_checkin_pts(PTS_TYPE_VIDEO), (int *)arg);
+ break;
+ case AMSTREAM_IOC_GET_LAST_CHECKOUT_APTS:
+ put_user(get_last_checkout_pts(PTS_TYPE_AUDIO), (int *)arg);
+ break;
+ case AMSTREAM_IOC_GET_LAST_CHECKOUT_VPTS:
+ put_user(get_last_checkout_pts(PTS_TYPE_VIDEO), (int *)arg);
+ break;
+ case AMSTREAM_IOC_SUB_NUM:
+ put_user(psparser_get_sub_found_num(), (int *)arg);
+ break;
+
+ case AMSTREAM_IOC_SUB_INFO:
+ if (arg > 0) {
+ struct subtitle_info msub_info[MAX_SUB_NUM];
+ struct subtitle_info *psub_info[MAX_SUB_NUM];
+ int i;
+
+ for (i = 0; i < MAX_SUB_NUM; i++)
+ psub_info[i] = &msub_info[i];
+
+ r = psparser_get_sub_info(psub_info);
+
+ if (r == 0) {
+ if (copy_to_user((void __user *)arg, msub_info,
+ sizeof(struct subtitle_info) * MAX_SUB_NUM))
+ r = -EFAULT;
+ }
+ }
+ break;
+ case AMSTREAM_IOC_SET_DEMUX:
+ tsdemux_set_demux((int)arg);
+ break;
+ case AMSTREAM_IOC_SET_VIDEO_DELAY_LIMIT_MS:
+ priv->vdec->vbuf.max_buffer_delay_ms = (int)arg;
+ break;
+ case AMSTREAM_IOC_SET_AUDIO_DELAY_LIMIT_MS:
+ bufs[BUF_TYPE_AUDIO].max_buffer_delay_ms = (int)arg;
+ break;
+ case AMSTREAM_IOC_GET_VIDEO_DELAY_LIMIT_MS:
+ put_user(priv->vdec->vbuf.max_buffer_delay_ms, (int *)arg);
+ break;
+ case AMSTREAM_IOC_GET_AUDIO_DELAY_LIMIT_MS:
+ put_user(bufs[BUF_TYPE_AUDIO].max_buffer_delay_ms, (int *)arg);
+ break;
+ case AMSTREAM_IOC_GET_VIDEO_CUR_DELAY_MS: {
+ int delay;
+
+ delay = calculation_stream_delayed_ms(
+ PTS_TYPE_VIDEO, NULL, NULL);
+ if (delay >= 0)
+ put_user(delay, (int *)arg);
+ else
+ put_user(0, (int *)arg);
+ }
+ break;
+
+ case AMSTREAM_IOC_GET_AUDIO_CUR_DELAY_MS: {
+ int delay;
+
+ delay = calculation_stream_delayed_ms(PTS_TYPE_AUDIO, NULL,
+ NULL);
+ if (delay >= 0)
+ put_user(delay, (int *)arg);
+ else
+ put_user(0, (int *)arg);
+ }
+ break;
+ case AMSTREAM_IOC_GET_AUDIO_AVG_BITRATE_BPS: {
+ int delay;
+ u32 avgbps;
+
+ delay = calculation_stream_delayed_ms(PTS_TYPE_AUDIO, NULL,
+ &avgbps);
+ if (delay >= 0)
+ put_user(avgbps, (int *)arg);
+ else
+ put_user(0, (int *)arg);
+ break;
+ }
+ case AMSTREAM_IOC_GET_VIDEO_AVG_BITRATE_BPS: {
+ int delay;
+ u32 avgbps;
+
+ delay = calculation_stream_delayed_ms(PTS_TYPE_VIDEO, NULL,
+ &avgbps);
+ if (delay >= 0)
+ put_user(avgbps, (int *)arg);
+ else
+ put_user(0, (int *)arg);
+ break;
+ }
+ case AMSTREAM_IOC_SET_DRMMODE:
+ if ((u32) arg == 1) {
+ pr_err("set drmmode, input must be secure buffer\n");
+ this->flag |= PORT_FLAG_DRM;
+ if ((this->type & PORT_TYPE_VIDEO) &&
+ (priv->vdec))
+ priv->vdec->port_flag |= PORT_FLAG_DRM;
+ } else if ((u32)arg == 2) {
+ pr_err("set drmmode, input must be normal buffer\n");
+ if ((this->type & PORT_TYPE_VIDEO) &&
+ (priv->vdec)) {
+ pr_err("vdec port_flag with drmmode\n");
+ priv->vdec->port_flag |= PORT_FLAG_DRM;
+ }
+ } else {
+ this->flag &= (~PORT_FLAG_DRM);
+ pr_err("no drmmode\n");
+ }
+ break;
+ case AMSTREAM_IOC_SET_APTS: {
+ unsigned long pts;
+
+ if (get_user(pts, (unsigned long __user *)arg)) {
+ pr_err
+ ("Get audio pts from user space fault!\n");
+ return -EFAULT;
+ }
+ if (tsync_get_mode() == TSYNC_MODE_PCRMASTER)
+ tsync_pcr_set_apts(pts);
+ else
+ tsync_set_apts(pts);
+ break;
+ }
+ case AMSTREAM_IOC_SET_CRC: {
+ struct usr_crc_info_t crc_info;
+ struct vdec_s *vdec;
+
+ if (copy_from_user(&crc_info, (void __user *)arg,
+ sizeof(struct usr_crc_info_t))) {
+ return -EFAULT;
+ }
+ /*
+ pr_info("id %d, frame %d, y_crc: %08x, uv_crc: %08x\n", crc_info.id,
+ crc_info.pic_num, crc_info.y_crc, crc_info.uv_crc);
+ */
+ vdec = vdec_get_vdec_by_id(crc_info.id);
+ if (vdec == NULL)
+ return -ENODEV;
+ if (vdec->vfc.cmp_pool == NULL) {
+ vdec->vfc.cmp_pool =
+ vmalloc(USER_CMP_POOL_MAX_SIZE *
+ sizeof(struct usr_crc_info_t));
+ if (vdec->vfc.cmp_pool == NULL)
+ return -ENOMEM;
+ }
+ if (vdec->vfc.usr_cmp_num >= USER_CMP_POOL_MAX_SIZE) {
+ pr_info("warn: could not write any more, max %d",
+ USER_CMP_POOL_MAX_SIZE);
+ return -EFAULT;
+ }
+ memcpy(&vdec->vfc.cmp_pool[vdec->vfc.usr_cmp_num], &crc_info,
+ sizeof(struct usr_crc_info_t));
+ vdec->vfc.usr_cmp_num++;
+ break;
+ }
+ case AMSTREAM_IOC_GET_CRC_CMP_RESULT: {
+ int val, vdec_id;
+ struct vdec_s *vdec;
+
+ if (get_user(val, (int __user *)arg)) {
+ return -EFAULT;
+ }
+ vdec_id = val & 0x00ff;
+ vdec = vdec_get_vdec_by_id(vdec_id);
+ if (vdec == NULL)
+ return -ENODEV;
+ if (val & 0xff00)
+ put_user(vdec->vfc.usr_cmp_num, (int *)arg);
+ else
+ put_user(vdec->vfc.usr_cmp_result, (int *)arg);
+ /*
+ pr_info("amstream get crc32 cmpare num %d result: %d\n",
+ vdec->vfc.usr_cmp_num, vdec->vfc.usr_cmp_result);
+ */
+ break;
+ }
+ case AMSTREAM_IOC_INIT_EX_STBUF: {
+ struct stream_buffer_metainfo parm;
+ struct stream_buf_s *vbuf = NULL;
+
+ if (priv->vdec == NULL) {
+ pr_err("init %s, no vdec.\n", __func__);
+ return -EFAULT;
+ }
+
+ vbuf = &priv->vdec->vbuf;
+ if (vbuf == NULL) {
+ pr_err("init %s, no stbuf.\n", __func__);
+ return -EFAULT;
+ }
+
+ if (copy_from_user(&parm, (void __user *)arg,
+ sizeof(struct stream_buffer_metainfo))) {
+ return -EFAULT;
+ }
+ stream_buffer_set_ext_buf(vbuf, parm.stbuf_start,
+ parm.stbuf_size, parm.stbuf_flag);
+ break;
+ }
+ case AMSTREAM_IOC_WR_STBUF_META: {
+ struct stream_buffer_metainfo meta;
+ struct stream_buf_s *vbuf = NULL;
+
+ if (priv->vdec == NULL) {
+ pr_err("write %s, no vdec.\n", __func__);
+ return -EFAULT;
+ }
+
+ vbuf = &priv->vdec->vbuf;
+ if (vbuf == NULL) {
+ pr_err("write %s, no stbuf.\n", __func__);
+ return -EFAULT;
+ }
+
+ if (vbuf->ops == NULL) {
+ pr_err("write %s, no ops.\n", __func__);
+ return -EFAULT;
+ }
+
+ if (copy_from_user(&meta, (void __user *)arg,
+ sizeof(struct stream_buffer_metainfo))) {
+ return -EFAULT;
+ }
+ if (!vbuf->ext_buf_addr)
+ return -ENODEV;
+
+ stream_buffer_meta_write(vbuf, &meta);
+ break;
+ }
+ case AMSTREAM_IOC_GET_STBUF_STATUS: {
+ struct stream_buffer_status st = {0};
+ struct stream_buf_s *pbuf = NULL;
+
+ if (priv->vdec == NULL) {
+ pr_err("get status %s, no vdec.\n", __func__);
+ return -EFAULT;
+ }
+
+ pbuf = &priv->vdec->vbuf;
+ if (pbuf == NULL) {
+ pr_err("get status %s, no stbuf.\n", __func__);
+ return -EFAULT;
+ }
+
+ if (pbuf->ops == NULL) {
+ pr_err("get status %s, no ops.\n", __func__);
+ return -EFAULT;
+ }
+
+ st.stbuf_start = pbuf->ext_buf_addr;
+ st.stbuf_size = pbuf->buf_size;
+ st.stbuf_rp = pbuf->ops->get_rp(pbuf);
+ st.stbuf_wp = pbuf->ops->get_wp(pbuf);
+ if (copy_to_user((void __user *)arg, &st,
+ sizeof(struct stream_buffer_status))) {
+ return -EFAULT;
+ }
+ break;
+ }
+ default:
+ r = -ENOIOCTLCMD;
+ break;
+ }
+
+ return r;
+}
+
+static long amstream_do_ioctl(struct port_priv_s *priv,
+ unsigned int cmd, ulong arg)
+{
+ long r = 0;
+
+ switch (cmd) {
+ case AMSTREAM_IOC_GET_VERSION:
+ case AMSTREAM_IOC_GET:
+ case AMSTREAM_IOC_SET:
+ case AMSTREAM_IOC_GET_EX:
+ case AMSTREAM_IOC_SET_EX:
+ case AMSTREAM_IOC_GET_PTR:
+ case AMSTREAM_IOC_SET_PTR:
+ case AMSTREAM_IOC_SYSINFO:
+ case AMSTREAM_IOC_GET_QOSINFO:
+ case AMSTREAM_IOC_GET_MVDECINFO:
+ case AMSTREAM_IOC_GET_AVINFO:
+ r = amstream_do_ioctl_new(priv, cmd, arg);
+ break;
+ default:
+ r = amstream_do_ioctl_old(priv, cmd, arg);
+ break;
+ }
+ if (r != 0)
+ pr_debug("amstream_do_ioctl error :%lx, %x\n", r, cmd);
+
+ return r;
+}
+static long amstream_ioctl(struct file *file, unsigned int cmd, ulong arg)
+{
+ struct port_priv_s *priv = (struct port_priv_s *)file->private_data;
+ struct stream_port_s *this = priv->port;
+
+ if (!this)
+ return -ENODEV;
+
+ return amstream_do_ioctl(priv, cmd, arg);
+}
+
+#ifdef CONFIG_COMPAT
+struct dec_sysinfo32 {
+
+ u32 format;
+
+ u32 width;
+
+ u32 height;
+
+ u32 rate;
+
+ u32 extra;
+
+ u32 status;
+
+ u32 ratio;
+
+ compat_uptr_t param;
+
+ u64 ratio64;
+};
+
+struct am_ioctl_parm_ptr32 {
+ union {
+ compat_uptr_t pdata_audio_info;
+ compat_uptr_t pdata_sub_info;
+ compat_uptr_t pointer;
+ char data[8];
+ };
+ u32 cmd;
+ u32 len;
+};
+
+static long amstream_ioc_setget_ptr(struct port_priv_s *priv,
+ unsigned int cmd, struct am_ioctl_parm_ptr32 __user *arg)
+{
+ struct am_ioctl_parm_ptr __user *data;
+ struct am_ioctl_parm_ptr32 param;
+ int ret;
+
+ if (copy_from_user(¶m,
+ (void __user *)arg,
+ sizeof(struct am_ioctl_parm_ptr32)))
+ return -EFAULT;
+
+ data = compat_alloc_user_space(sizeof(*data));
+ if (!access_ok(VERIFY_WRITE, data, sizeof(*data)))
+ return -EFAULT;
+
+ if (put_user(param.cmd, &data->cmd) ||
+ put_user(compat_ptr(param.pointer), &data->pointer) ||
+ put_user(param.len, &data->len))
+ return -EFAULT;
+
+ ret = amstream_do_ioctl(priv, cmd, (unsigned long)data);
+ if (ret < 0)
+ return ret;
+ return 0;
+
+}
+
+static long amstream_set_sysinfo(struct port_priv_s *priv,
+ struct dec_sysinfo32 __user *arg)
+{
+ struct dec_sysinfo __user *data;
+ struct dec_sysinfo32 __user *data32 = arg;
+ int ret;
+ struct dec_sysinfo32 param;
+
+ if (copy_from_user(¶m,
+ (void __user *)arg,
+ sizeof(struct dec_sysinfo32)))
+ return -EFAULT;
+
+ data = compat_alloc_user_space(sizeof(*data));
+ if (!access_ok(VERIFY_WRITE, data, sizeof(*data)))
+ return -EFAULT;
+ if (copy_in_user(data, data32, 7 * sizeof(u32)))
+ return -EFAULT;
+ if (put_user(compat_ptr(param.param), &data->param))
+ return -EFAULT;
+ if (copy_in_user(&data->ratio64, &data32->ratio64,
+ sizeof(data->ratio64)))
+ return -EFAULT;
+
+ ret = amstream_do_ioctl(priv, AMSTREAM_IOC_SYSINFO,
+ (unsigned long)data);
+ if (ret < 0)
+ return ret;
+
+ if (copy_in_user(&arg->format, &data->format, 7 * sizeof(u32)) ||
+ copy_in_user(&arg->ratio64, &data->ratio64,
+ sizeof(arg->ratio64)))
+ return -EFAULT;
+
+ return 0;
+}
+
+
+struct userdata_param32_t {
+ uint32_t version;
+ uint32_t instance_id; /*input, 0~9*/
+ uint32_t buf_len; /*input*/
+ uint32_t data_size; /*output*/
+ compat_uptr_t pbuf_addr; /*input*/
+ struct userdata_meta_info_t meta_info; /*output*/
+};
+
+
+static long amstream_ioc_get_userdata(struct port_priv_s *priv,
+ struct userdata_param32_t __user *arg)
+{
+ struct userdata_param_t __user *data;
+ struct userdata_param32_t __user *data32 = arg;
+ int ret;
+ struct userdata_param32_t param;
+
+
+ if (copy_from_user(¶m,
+ (void __user *)arg,
+ sizeof(struct userdata_param32_t)))
+ return -EFAULT;
+
+ data = compat_alloc_user_space(sizeof(*data));
+ if (!access_ok(VERIFY_WRITE, data, sizeof(*data)))
+ return -EFAULT;
+
+ if (copy_in_user(data, data32, 4 * sizeof(u32)))
+ return -EFAULT;
+
+ if (copy_in_user(&data->meta_info, &data32->meta_info,
+ sizeof(data->meta_info)))
+ return -EFAULT;
+
+ if (put_user(compat_ptr(param.pbuf_addr), &data->pbuf_addr))
+ return -EFAULT;
+
+ ret = amstream_do_ioctl(priv, AMSTREAM_IOC_UD_BUF_READ,
+ (unsigned long)data);
+ if (ret < 0)
+ return ret;
+
+ if (copy_in_user(&data32->version, &data->version, 4 * sizeof(u32)) ||
+ copy_in_user(&data32->meta_info, &data->meta_info,
+ sizeof(data32->meta_info)))
+ return -EFAULT;
+
+ return 0;
+}
+
+
+static long amstream_compat_ioctl(struct file *file,
+ unsigned int cmd, ulong arg)
+{
+ s32 r = 0;
+ struct port_priv_s *priv = (struct port_priv_s *)file->private_data;
+
+ switch (cmd) {
+ case AMSTREAM_IOC_GET_VERSION:
+ case AMSTREAM_IOC_GET:
+ case AMSTREAM_IOC_SET:
+ case AMSTREAM_IOC_GET_EX:
+ case AMSTREAM_IOC_SET_EX:
+ return amstream_do_ioctl(priv, cmd, (ulong)compat_ptr(arg));
+ case AMSTREAM_IOC_GET_PTR:
+ case AMSTREAM_IOC_SET_PTR:
+ return amstream_ioc_setget_ptr(priv, cmd, compat_ptr(arg));
+ case AMSTREAM_IOC_SYSINFO:
+ return amstream_set_sysinfo(priv, compat_ptr(arg));
+ case AMSTREAM_IOC_UD_BUF_READ:
+ return amstream_ioc_get_userdata(priv, compat_ptr(arg));
+ default:
+ return amstream_do_ioctl(priv, cmd, (ulong)compat_ptr(arg));
+ }
+
+ return r;
+}
+#endif
+
+static ssize_t ports_show(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ int i;
+ char *pbuf = buf;
+ struct stream_port_s *p = NULL;
+
+ for (i = 0; i < amstream_port_num; i++) {
+ p = &ports[i];
+ /*name */
+ pbuf += sprintf(pbuf, "%s\t:\n", p->name);
+ /*type */
+ pbuf += sprintf(pbuf, "\ttype:%d( ", p->type);
+ if (p->type & PORT_TYPE_VIDEO)
+ pbuf += sprintf(pbuf, "%s ", "Video");
+ if (p->type & PORT_TYPE_AUDIO)
+ pbuf += sprintf(pbuf, "%s ", "Audio");
+ if (p->type & PORT_TYPE_MPTS)
+ pbuf += sprintf(pbuf, "%s ", "TS");
+ if (p->type & PORT_TYPE_MPPS)
+ pbuf += sprintf(pbuf, "%s ", "PS");
+ if (p->type & PORT_TYPE_ES)
+ pbuf += sprintf(pbuf, "%s ", "ES");
+ if (p->type & PORT_TYPE_RM)
+ pbuf += sprintf(pbuf, "%s ", "RM");
+ if (p->type & PORT_TYPE_SUB)
+ pbuf += sprintf(pbuf, "%s ", "Subtitle");
+ if (p->type & PORT_TYPE_SUB_RD)
+ pbuf += sprintf(pbuf, "%s ", "Subtitle_Read");
+ if (p->type & PORT_TYPE_USERDATA)
+ pbuf += sprintf(pbuf, "%s ", "userdata");
+ pbuf += sprintf(pbuf, ")\n");
+ /*flag */
+ pbuf += sprintf(pbuf, "\tflag:%d( ", p->flag);
+ if (p->flag & PORT_FLAG_IN_USE)
+ pbuf += sprintf(pbuf, "%s ", "Used");
+ else
+ pbuf += sprintf(pbuf, "%s ", "Unused");
+ if ((p->type & PORT_TYPE_VIDEO) == 0) {
+ if (p->flag & PORT_FLAG_INITED)
+ pbuf += sprintf(pbuf, "%s ", "inited");
+ else
+ pbuf += sprintf(pbuf, "%s ", "uninited");
+ }
+ pbuf += sprintf(pbuf, ")\n");
+ /*others */
+ pbuf += sprintf(pbuf, "\tVformat:%d\n",
+ (p->flag & PORT_FLAG_VFORMAT) ? p->vformat : -1);
+ pbuf += sprintf(pbuf, "\tAformat:%d\n",
+ (p->flag & PORT_FLAG_AFORMAT) ? p->aformat : -1);
+ pbuf += sprintf(pbuf, "\tVid:%d\n",
+ (p->flag & PORT_FLAG_VID) ? p->vid : -1);
+ pbuf += sprintf(pbuf, "\tAid:%d\n",
+ (p->flag & PORT_FLAG_AID) ? p->aid : -1);
+ pbuf += sprintf(pbuf, "\tSid:%d\n",
+ (p->flag & PORT_FLAG_SID) ? p->sid : -1);
+ pbuf += sprintf(pbuf, "\tPCRid:%d\n",
+ (p->pcr_inited == 1) ? p->pcrid : -1);
+ pbuf += sprintf(pbuf, "\tachannel:%d\n", p->achanl);
+ pbuf += sprintf(pbuf, "\tasamprate:%d\n", p->asamprate);
+ pbuf += sprintf(pbuf, "\tadatawidth:%d\n\n", p->adatawidth);
+ }
+ return pbuf - buf;
+}
+
+static int show_vbuf_status_cb(struct stream_buf_s *p, char *buf)
+{
+ char *pbuf = buf;
+
+ if (!p->buf_start)
+ return 0;
+ /*type */
+ pbuf += sprintf(pbuf, "Video-%d buffer:", p->id);
+ /*flag */
+ pbuf += sprintf(pbuf, "\tflag:%d( ", p->flag);
+ if (p->flag & BUF_FLAG_ALLOC)
+ pbuf += sprintf(pbuf, "%s ", "Alloc");
+ else
+ pbuf += sprintf(pbuf, "%s ", "Unalloc");
+ if (p->flag & BUF_FLAG_IN_USE)
+ pbuf += sprintf(pbuf, "%s ", "Used");
+ else
+ pbuf += sprintf(pbuf, "%s ", "Noused");
+ if (p->flag & BUF_FLAG_PARSER)
+ pbuf += sprintf(pbuf, "%s ", "Parser");
+ else
+ pbuf += sprintf(pbuf, "%s ", "noParser");
+ if (p->flag & BUF_FLAG_FIRST_TSTAMP)
+ pbuf += sprintf(pbuf, "%s ", "firststamp");
+ else
+ pbuf += sprintf(pbuf, "%s ", "nofirststamp");
+ pbuf += sprintf(pbuf, ")\n");
+
+ /*buf stats */
+ pbuf += sprintf(pbuf, "\tbuf addr:%p\n", (void *)p->buf_start);
+ pbuf += sprintf(pbuf, "\tbuf size:%#x\n", p->buf_size);
+ pbuf += sprintf(pbuf, "\tbuf canusesize:%#x\n", p->canusebuf_size);
+ pbuf += sprintf(pbuf, "\tbuf regbase:%#lx\n", p->reg_base);
+
+ if (p->reg_base && p->flag & BUF_FLAG_IN_USE) {
+ pbuf += sprintf(pbuf, "\tbuf level:%#x\n",
+ stbuf_level(p));
+ pbuf += sprintf(pbuf, "\tbuf space:%#x\n",
+ stbuf_space(p));
+ pbuf += sprintf(pbuf, "\tbuf read pointer:%#x\n",
+ stbuf_rp(p));
+ } else
+ pbuf += sprintf(pbuf, "\tbuf no used.\n");
+
+ return pbuf - buf;
+}
+
+static ssize_t bufs_show(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ int i;
+ char *pbuf = buf;
+ struct stream_buf_s *p = NULL;
+ char buf_type[][12] = { "Video", "Audio", "Subtitle",
+ "UserData", "HEVC" };
+
+ for (i = 0; i < amstream_buf_num; i++) {
+ p = &bufs[i];
+
+ if (!p->buf_start)
+ continue;
+
+ /*type */
+ pbuf += sprintf(pbuf, "%s buffer:", buf_type[p->type]);
+ /*flag */
+ pbuf += sprintf(pbuf, "\tflag:%d( ", p->flag);
+ if (p->flag & BUF_FLAG_ALLOC)
+ pbuf += sprintf(pbuf, "%s ", "Alloc");
+ else
+ pbuf += sprintf(pbuf, "%s ", "Unalloc");
+ if (p->flag & BUF_FLAG_IN_USE)
+ pbuf += sprintf(pbuf, "%s ", "Used");
+ else
+ pbuf += sprintf(pbuf, "%s ", "Noused");
+ if (p->flag & BUF_FLAG_PARSER)
+ pbuf += sprintf(pbuf, "%s ", "Parser");
+ else
+ pbuf += sprintf(pbuf, "%s ", "noParser");
+ if (p->flag & BUF_FLAG_FIRST_TSTAMP)
+ pbuf += sprintf(pbuf, "%s ", "firststamp");
+ else
+ pbuf += sprintf(pbuf, "%s ", "nofirststamp");
+ pbuf += sprintf(pbuf, ")\n");
+ /*buf stats */
+
+ pbuf += sprintf(pbuf, "\tbuf addr:%p\n", (void *)p->buf_start);
+
+ if (p->type != BUF_TYPE_SUBTITLE) {
+ pbuf += sprintf(pbuf, "\tbuf size:%#x\n", p->buf_size);
+ pbuf += sprintf(pbuf,
+ "\tbuf canusesize:%#x\n",
+ p->canusebuf_size);
+ pbuf += sprintf(pbuf,
+ "\tbuf regbase:%#lx\n", p->reg_base);
+
+ if (p->reg_base && p->flag & BUF_FLAG_IN_USE) {
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M6) {
+ /* TODO: mod gate */
+ /* switch_mod_gate_by_name("vdec", 1);*/
+ amports_switch_gate("vdec", 1);
+ }
+ pbuf += sprintf(pbuf, "\tbuf level:%#x\n",
+ stbuf_level(p));
+ pbuf += sprintf(pbuf, "\tbuf space:%#x\n",
+ stbuf_space(p));
+ pbuf += sprintf(pbuf,
+ "\tbuf read pointer:%#x\n",
+ stbuf_rp(p));
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_M6) {
+ /* TODO: mod gate */
+ /* switch_mod_gate_by_name("vdec", 0);*/
+ amports_switch_gate("vdec", 0);
+ }
+ } else
+ pbuf += sprintf(pbuf, "\tbuf no used.\n");
+
+ if (p->type == BUF_TYPE_USERDATA) {
+ pbuf += sprintf(pbuf,
+ "\tbuf write pointer:%#x\n",
+ p->buf_wp);
+ pbuf += sprintf(pbuf,
+ "\tbuf read pointer:%#x\n",
+ p->buf_rp);
+ }
+ } else {
+ u32 sub_wp, sub_rp, data_size;
+
+ sub_wp = stbuf_sub_wp_get();
+ sub_rp = stbuf_sub_rp_get();
+ if (sub_wp >= sub_rp)
+ data_size = sub_wp - sub_rp;
+ else
+ data_size = p->buf_size - sub_rp + sub_wp;
+ pbuf += sprintf(pbuf, "\tbuf size:%#x\n", p->buf_size);
+ pbuf +=
+ sprintf(pbuf, "\tbuf canusesize:%#x\n",
+ p->canusebuf_size);
+ pbuf +=
+ sprintf(pbuf, "\tbuf start:%#x\n",
+ stbuf_sub_start_get());
+ pbuf += sprintf(pbuf,
+ "\tbuf write pointer:%#x\n", sub_wp);
+ pbuf += sprintf(pbuf,
+ "\tbuf read pointer:%#x\n", sub_rp);
+ pbuf += sprintf(pbuf, "\tbuf level:%#x\n", data_size);
+ }
+
+ pbuf += sprintf(pbuf, "\tbuf first_stamp:%#x\n",
+ p->first_tstamp);
+ pbuf += sprintf(pbuf, "\tbuf wcnt:%#x\n\n", p->wcnt);
+ pbuf += sprintf(pbuf, "\tbuf max_buffer_delay_ms:%dms\n",
+ p->max_buffer_delay_ms);
+
+ if (p->reg_base && p->flag & BUF_FLAG_IN_USE) {
+ int calc_delayms = 0;
+ u32 bitrate = 0, avg_bitrate = 0;
+
+ calc_delayms = calculation_stream_delayed_ms(
+ (p->type == BUF_TYPE_AUDIO) ? PTS_TYPE_AUDIO :
+ PTS_TYPE_VIDEO,
+ &bitrate,
+ &avg_bitrate);
+
+ if (calc_delayms >= 0) {
+ pbuf += sprintf(pbuf,
+ "\tbuf current delay:%dms\n",
+ calc_delayms);
+ pbuf += sprintf(pbuf,
+ "\tbuf bitrate latest:%dbps,avg:%dbps\n",
+ bitrate, avg_bitrate);
+ pbuf += sprintf(pbuf,
+ "\tbuf time after last pts:%d ms\n",
+ calculation_stream_ext_delayed_ms
+ ((p->type == BUF_TYPE_AUDIO) ? PTS_TYPE_AUDIO :
+ PTS_TYPE_VIDEO));
+
+ pbuf += sprintf(pbuf,
+ "\tbuf time after last write data :%d ms\n",
+ (int)(jiffies_64 -
+ p->last_write_jiffies64) * 1000 / HZ);
+ }
+ }
+ if (p->write_thread) {
+ pbuf += sprintf(pbuf,
+ "\twrite thread:%d/%d,fifo %d:%d,passed:%d\n",
+ threadrw_buffer_level(p),
+ threadrw_buffer_size(p),
+ threadrw_datafifo_len(p),
+ threadrw_freefifo_len(p),
+ threadrw_passed_len(p)
+ );
+ }
+ }
+
+ pbuf += show_stream_buffer_status(pbuf, show_vbuf_status_cb);
+
+ return pbuf - buf;
+}
+
+static ssize_t videobufused_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ char *pbuf = buf;
+ struct stream_buf_s *p = NULL;
+
+ p = &bufs[0];
+
+ if (p->flag & BUF_FLAG_IN_USE)
+ pbuf += sprintf(pbuf, "%d ", 1);
+ else
+ pbuf += sprintf(pbuf, "%d ", 0);
+ return 1;
+}
+
+static ssize_t vcodec_profile_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ return vcodec_profile_read(buf);
+}
+
+static int reset_canuse_buferlevel(int levelx10000)
+{
+ int i;
+ struct stream_buf_s *p = NULL;
+
+ if (levelx10000 >= 0 && levelx10000 <= 10000)
+ use_bufferlevelx10000 = levelx10000;
+ else
+ use_bufferlevelx10000 = 10000;
+ for (i = 0; i < amstream_buf_num; i++) {
+ p = &bufs[i];
+ p->canusebuf_size = ((p->buf_size / 1024) *
+ use_bufferlevelx10000 / 10000) * 1024;
+ p->canusebuf_size += 1023;
+ p->canusebuf_size &= ~1023;
+ if (p->canusebuf_size > p->buf_size)
+ p->canusebuf_size = p->buf_size;
+ }
+ return 0;
+}
+
+static ssize_t show_canuse_buferlevel(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ ssize_t size = sprintf(buf,
+ "use_bufferlevel=%d/10000[=(set range[ 0~10000])=\n",
+ use_bufferlevelx10000);
+ return size;
+}
+
+static ssize_t store_canuse_buferlevel(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned int val;
+ ssize_t ret;
+
+ /*ret = sscanf(buf, "%d", &val);*/
+ ret = kstrtoint(buf, 0, &val);
+
+ if (ret != 0)
+ return -EINVAL;
+ val = val;
+ reset_canuse_buferlevel(val);
+ return size;
+}
+
+static ssize_t store_maxdelay(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned int val;
+ ssize_t ret;
+ int i;
+
+ /*ret = sscanf(buf, "%d", &val);*/
+ ret = kstrtoint(buf, 0, &val);
+ if (ret != 0)
+ return -EINVAL;
+ for (i = 0; i < amstream_buf_num; i++)
+ bufs[i].max_buffer_delay_ms = val;
+ return size;
+}
+
+static ssize_t show_maxdelay(struct class *class,
+ struct class_attribute *attr,
+ char *buf)
+{
+ ssize_t size = 0;
+
+ size += sprintf(buf, "%dms video max buffered data delay ms\n",
+ bufs[0].max_buffer_delay_ms);
+ size += sprintf(buf, "%dms audio max buffered data delay ms\n",
+ bufs[1].max_buffer_delay_ms);
+ return size;
+}
+
+static ssize_t audio_path_store(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned int val = 0;
+ int i;
+ ssize_t ret;
+ struct stream_buf_s *pabuf = &bufs[BUF_TYPE_AUDIO];
+ struct stream_port_s *this;
+ ret = kstrtoint(buf, 0, &val);
+ if (ret != 0)
+ return -EINVAL;
+ if (val != 1)
+ return -EINVAL;
+ mutex_lock(&amstream_mutex);
+ for (i = 0; i < MAX_AMSTREAM_PORT_NUM; i++) {
+ if (strcmp(ports[i].name, "amstream_mpts") == 0 ||
+ strcmp(ports[i].name, "amstream_mpts_sched") == 0) {
+ this = &ports[i];
+ if ((this->flag & PORT_FLAG_AFORMAT) != 0) {
+ pr_info("audio_port_reset %s\n", ports[i].name);
+ audio_port_reset(this, pabuf);
+ }
+ }
+ }
+ mutex_unlock(&amstream_mutex);
+ return size;
+}
+
+ssize_t dump_stream_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ char *p_buf = buf;
+
+ p_buf += sprintf(p_buf, "\nmdkir -p /data/tmp -m 777;setenforce 0;\n\n");
+ p_buf += sprintf(p_buf, "video:\n\t echo 0 > /sys/class/amstream/dump_stream;\n");
+ p_buf += sprintf(p_buf, "hevc :\n\t echo 4 > /sys/class/amstream/dump_stream;\n");
+
+ return p_buf - buf;
+}
+
+#define DUMP_STREAM_FILE "/data/tmp/dump_stream.h264"
+ssize_t dump_stream_store(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct stream_buf_s *p_buf;
+ int ret = 0, id = 0;
+ unsigned int stride, remain, level, vmap_size;
+ int write_size;
+ void *stbuf_vaddr;
+ unsigned long offset;
+ struct file *fp;
+ mm_segment_t old_fs;
+ loff_t fpos;
+
+ ret = sscanf(buf, "%d", &id);
+ if (ret < 0) {
+ pr_info("paser buf id fail, default id = 0\n");
+ id = 0;
+ }
+ if (id != BUF_TYPE_VIDEO && id != BUF_TYPE_HEVC) {
+ pr_info("buf id out of range, max %d, id %d, set default id 0\n", BUF_MAX_NUM - 1, id);
+ id = 0;
+ }
+ p_buf = get_stream_buffer(id);
+ if (!p_buf) {
+ pr_info("get buf fail, id %d\n", id);
+ return size;
+ }
+ if ((!p_buf->buf_size) || (p_buf->is_secure) || (!(p_buf->flag & BUF_FLAG_IN_USE))) {
+ pr_info("buf size %d, is_secure %d, in_use %d, it can not dump\n",
+ p_buf->buf_size, p_buf->is_secure, (p_buf->flag & BUF_FLAG_IN_USE));
+ return size;
+ }
+
+ level = stbuf_level(p_buf);
+ if (!level || level > p_buf->buf_size) {
+ pr_info("stream buf level %d, buf size %d, error return\n", level, p_buf->buf_size);
+ return size;
+ }
+
+ fp = filp_open(DUMP_STREAM_FILE, O_CREAT | O_RDWR, 0666);
+ if (IS_ERR(fp)) {
+ fp = NULL;
+ pr_info("create dump stream file failed\n");
+ return size;
+ }
+
+ offset = p_buf->buf_start;
+ remain = level;
+ stride = SZ_1M;
+ vmap_size = 0;
+ fpos = 0;
+ pr_info("create file success, it will dump from addr 0x%lx, size 0x%x\n", offset, remain);
+ while (remain > 0) {
+ if (remain > stride)
+ vmap_size = stride;
+ else {
+ stride = remain;
+ vmap_size = stride;
+ }
+
+ stbuf_vaddr = codec_mm_vmap(offset, vmap_size);
+ if (stbuf_vaddr == NULL) {
+ stride >>= 1;
+ pr_info("vmap fail change vmap stide size 0x%x\n", stride);
+ continue;
+ }
+ codec_mm_dma_flush(stbuf_vaddr, vmap_size, DMA_FROM_DEVICE);
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ write_size = vfs_write(fp, stbuf_vaddr, vmap_size, &fpos);
+ if (write_size < vmap_size) {
+ write_size += vfs_write(fp, stbuf_vaddr + write_size, vmap_size - write_size, &fpos);
+ pr_info("fail write retry, total %d, write %d\n", vmap_size, write_size);
+ if (write_size < vmap_size) {
+ pr_info("retry fail, interrupt dump stream, break\n");
+ break;
+ }
+ }
+ set_fs(old_fs);
+ vfs_fsync(fp, 0);
+ pr_info("vmap_size 0x%x dump size 0x%x\n", vmap_size, write_size);
+
+ offset += vmap_size;
+ remain -= vmap_size;
+ codec_mm_unmap_phyaddr(stbuf_vaddr);
+ }
+
+ filp_close(fp, current->files);
+ pr_info("dump stream buf end\n");
+
+ return size;
+}
+
+
+
+
+static struct class_attribute amstream_class_attrs[] = {
+ __ATTR_RO(ports),
+ __ATTR_RO(bufs),
+ __ATTR_RO(vcodec_profile),
+ __ATTR_RO(videobufused),
+ __ATTR(canuse_buferlevel, S_IRUGO | S_IWUSR | S_IWGRP,
+ show_canuse_buferlevel, store_canuse_buferlevel),
+ __ATTR(max_buffer_delay_ms, S_IRUGO | S_IWUSR | S_IWGRP, show_maxdelay,
+ store_maxdelay),
+ __ATTR(reset_audio_port, S_IRUGO | S_IWUSR | S_IWGRP,
+ NULL, audio_path_store),
+ __ATTR(dump_stream, S_IRUGO | S_IWUSR | S_IWGRP,
+ dump_stream_show, dump_stream_store),
+ __ATTR_NULL
+};
+
+static struct class amstream_class = {
+ .name = "amstream",
+ .class_attrs = amstream_class_attrs,
+};
+
+int amstream_request_firmware_from_sys(const char *file_name,
+ char *buf, int size)
+{
+ const struct firmware *firmware;
+ int err = 0;
+ struct device *micro_dev;
+
+ pr_info("try load %s ...", file_name);
+ micro_dev = device_create(&amstream_class,
+ NULL, MKDEV(AMSTREAM_MAJOR, 100),
+ NULL, "videodec");
+ if (micro_dev == NULL) {
+ pr_err("device_create failed =%d\n", err);
+ return -1;
+ }
+ err = request_firmware(&firmware, file_name, micro_dev);
+ if (err < 0) {
+ pr_err("can't load the %s,err=%d\n", file_name, err);
+ goto error1;
+ }
+ if (firmware->size > size) {
+ pr_err("not enough memory size for audiodsp code\n");
+ err = -ENOMEM;
+ goto release;
+ }
+
+ memcpy(buf, (char *)firmware->data, firmware->size);
+ /*mb(); don't need it*/
+ pr_err("load mcode size=%zd\n mcode name %s\n", firmware->size,
+ file_name);
+ err = firmware->size;
+release:
+ release_firmware(firmware);
+error1:
+ device_destroy(&amstream_class, MKDEV(AMSTREAM_MAJOR, 100));
+ return err;
+}
+
+int videobufused_show_fun(const char *trigger, int id, char *sbuf, int size)
+{
+ int ret = -1;
+ void *buf, *getbuf = NULL;
+ if (size < PAGE_SIZE) {
+ getbuf = (void *)__get_free_page(GFP_KERNEL);
+ if (!getbuf)
+ return -ENOMEM;
+ buf = getbuf;
+ } else {
+ buf = sbuf;
+ }
+
+ switch (id) {
+ case 0:
+ ret = videobufused_show(NULL, NULL , buf);
+ break;
+ default:
+ ret = -1;
+ }
+ if (ret > 0 && getbuf != NULL) {
+ ret = min_t(int, ret, size);
+ strncpy(sbuf, buf, ret);
+ }
+ if (getbuf != NULL)
+ free_page((unsigned long)getbuf);
+ return ret;
+}
+
+static struct mconfig amports_configs[] = {
+ MC_PI32("def_4k_vstreambuf_sizeM", &def_4k_vstreambuf_sizeM),
+ MC_PI32("def_vstreambuf_sizeM", &def_vstreambuf_sizeM),
+ MC_PI32("slow_input", &slow_input),
+ MC_FUN_ID("videobufused", videobufused_show_fun, NULL, 0),
+};
+
+
+
+/*static struct resource memobj;*/
+static int amstream_probe(struct platform_device *pdev)
+{
+ int i;
+ int r;
+ struct stream_port_s *st;
+
+ pr_err("Amlogic A/V streaming port init\n");
+
+ amstream_port_num = MAX_AMSTREAM_PORT_NUM;
+ amstream_buf_num = BUF_MAX_NUM;
+/*
+ * r = of_reserved_mem_device_init(&pdev->dev);
+ * if (r == 0)
+ * pr_info("of probe done");
+ * else {
+ * r = -ENOMEM;
+ * return r;
+ * }
+ */
+ r = class_register(&amstream_class);
+ if (r) {
+ pr_err("amstream class create fail.\n");
+ return r;
+ }
+
+ r = astream_dev_register();
+ if (r)
+ return r;
+
+ r = register_chrdev(AMSTREAM_MAJOR, "amstream", &amstream_fops);
+ if (r < 0) {
+ pr_err("Can't allocate major for amstreaming device\n");
+
+ goto error2;
+ }
+
+ amstream_dev_class = class_create(THIS_MODULE, DEVICE_NAME);
+
+ for (st = &ports[0], i = 0; i < amstream_port_num; i++, st++) {
+ st->class_dev = device_create(amstream_dev_class, NULL,
+ MKDEV(AMSTREAM_MAJOR, i), NULL,
+ ports[i].name);
+ }
+
+ amstream_adec_status = NULL;
+ if (tsdemux_class_register() != 0) {
+ r = (-EIO);
+ goto error3;
+ }
+ tsdemux_tsync_func_init();
+ init_waitqueue_head(&amstream_sub_wait);
+ init_waitqueue_head(&amstream_userdata_wait);
+ reset_canuse_buferlevel(10000);
+ amstream_pdev = pdev;
+ amports_clock_gate_init(&amstream_pdev->dev);
+
+ /*prealloc fetch buf to avoid no continue buffer later...*/
+ stbuf_fetch_init();
+ REG_PATH_CONFIGS("media.amports", amports_configs);
+#ifdef VDEC_FCC_SUPPORT
+ if (fcc_enable & 0x1)
+ amstream_fcc_init();
+#endif
+
+ amstream_userdata_init();
+ /* poweroff the decode core because dos can not be reset when reboot */
+ if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_G12A)
+ vdec_power_reset();
+
+ return 0;
+
+ /*
+ * error4:
+ * tsdemux_class_unregister();
+ */
+error3:
+ for (st = &ports[0], i = 0; i < amstream_port_num; i++, st++)
+ device_destroy(amstream_dev_class, MKDEV(AMSTREAM_MAJOR, i));
+ class_destroy(amstream_dev_class);
+error2:
+ unregister_chrdev(AMSTREAM_MAJOR, "amstream");
+ /* error1: */
+ astream_dev_unregister();
+ return r;
+}
+
+static int amstream_remove(struct platform_device *pdev)
+{
+ int i;
+ struct stream_port_s *st;
+
+ if (bufs[BUF_TYPE_AUDIO].flag & BUF_FLAG_ALLOC)
+ stbuf_change_size(&bufs[BUF_TYPE_AUDIO], 0, false);
+ stbuf_fetch_release();
+ tsdemux_class_unregister();
+ for (st = &ports[0], i = 0; i < amstream_port_num; i++, st++)
+ device_destroy(amstream_dev_class, MKDEV(AMSTREAM_MAJOR, i));
+
+ class_destroy(amstream_dev_class);
+
+ unregister_chrdev(AMSTREAM_MAJOR, "amstream");
+
+ class_unregister(&amstream_class);
+
+ astream_dev_unregister();
+
+ amstream_adec_status = NULL;
+
+ pr_err("Amlogic A/V streaming port release\n");
+
+ return 0;
+}
+
+void set_adec_func(int (*adec_func)(struct adec_status *))
+{
+ amstream_adec_status = adec_func;
+}
+
+void wakeup_sub_poll(void)
+{
+ atomic_inc(&subdata_ready);
+ wake_up_interruptible(&amstream_sub_wait);
+}
+
+int get_sub_type(void)
+{
+ return sub_type;
+}
+
+u32 get_audio_reset(void)
+{
+ return amstream_audio_reset;
+}
+
+/*get pes buffers */
+
+struct stream_buf_s *get_stream_buffer(int id)
+{
+ if (id >= BUF_MAX_NUM)
+ return 0;
+ return &bufs[id];
+}
+EXPORT_SYMBOL(get_stream_buffer);
+static const struct of_device_id amlogic_mesonstream_dt_match[] = {
+ {
+ .compatible = "amlogic, codec, streambuf",
+ },
+ {},
+};
+
+static struct platform_driver amstream_driver = {
+ .probe = amstream_probe,
+ .remove = amstream_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "mesonstream",
+ .of_match_table = amlogic_mesonstream_dt_match,
+ }
+};
+
+static int __init amstream_module_init(void)
+{
+ if (platform_driver_register(&amstream_driver)) {
+ pr_err("failed to register amstream module\n");
+ return -ENODEV;
+ }
+
+ if (subtitle_init()) {
+ pr_err("failed to init subtitle\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void __exit amstream_module_exit(void)
+{
+ platform_driver_unregister(&amstream_driver);
+ subtitle_exit();
+}
+
+module_init(amstream_module_init);
+module_exit(amstream_module_exit);
+
+module_param(force_dv_mode, uint, 0664);
+MODULE_PARM_DESC(force_dv_mode,
+ "\n force_dv_mode \n");
+
+#ifdef VDEC_FCC_SUPPORT
+module_param(fcc_enable, uint, 0664);
+MODULE_PARM_DESC(fcc_enable,
+ "\n fcc_enable \n");
+#endif
+
+module_param(def_4k_vstreambuf_sizeM, uint, 0664);
+MODULE_PARM_DESC(def_4k_vstreambuf_sizeM,
+ "\nDefault video Stream buf size for 4K MByptes\n");
+
+module_param(def_vstreambuf_sizeM, uint, 0664);
+MODULE_PARM_DESC(def_vstreambuf_sizeM,
+ "\nDefault video Stream buf size for < 1080p MByptes\n");
+
+module_param(slow_input, uint, 0664);
+MODULE_PARM_DESC(slow_input, "\n amstream slow_input\n");
+
+MODULE_DESCRIPTION("AMLOGIC streaming port driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tim Yao <timyao@amlogic.com>");
diff --git a/drivers/stream_input/amports/stream_buffer_base.c b/drivers/stream_input/amports/stream_buffer_base.c
new file mode 100644
index 0000000..b5e06db
--- /dev/null
+++ b/drivers/stream_input/amports/stream_buffer_base.c
@@ -0,0 +1,273 @@
+/*
+ * drivers/amlogic/media/stream_input/parser/stream_buffer_base.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/wait.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/uaccess.h>
+#include <linux/atomic.h>
+#include <linux/delay.h>
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include "../../frame_provider/decoder/utils/vdec.h"
+#include "amports_priv.h"
+#include "stream_buffer_base.h"
+#include "thread_rw.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)
+
+static struct stream_buf_s vdec_buf_def = {
+ .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
+};
+
+static struct stream_buf_s hevc_buf_def = {
+ .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
+};
+
+static struct stream_buf_s *get_def_parms(int f)
+{
+ switch (f) {
+ case VFORMAT_HEVC:
+ case VFORMAT_AVS2:
+ case VFORMAT_AV1:
+ case VFORMAT_VP9:
+ return &hevc_buf_def;
+ default:
+ return &vdec_buf_def;
+ }
+}
+
+int stream_buffer_base_init(struct stream_buf_s *stbuf,
+ struct stream_buf_ops *ops,
+ struct parser_args *pars)
+{
+ struct vdec_s *vdec =
+ container_of(stbuf, struct vdec_s, vbuf);
+ struct stream_port_s *port = NULL;
+ u32 format, width, height;
+
+ /* sanity check. */
+ if (WARN_ON(!stbuf) || WARN_ON(!ops))
+ return -EINVAL;
+
+ port = vdec->port;
+ format = vdec->port->vformat;
+ width = vdec->sys_info->width;
+ height = vdec->sys_info->height;
+
+ if (!stbuf->ext_buf_addr) {
+ memcpy(stbuf, get_def_parms(format),
+ sizeof(*stbuf));
+ }
+
+ stbuf->id = vdec->id;
+ stbuf->is_hevc = ((format == VFORMAT_HEVC) ||
+ (format == VFORMAT_AVS2) ||
+ (format == VFORMAT_AV1) ||
+ (format == VFORMAT_VP9));
+ stbuf->for_4k = ((width * height) >
+ (1920 * 1088)) ? 1 : 0;
+ stbuf->is_multi_inst = !vdec_single(vdec);
+ memcpy(&stbuf->pars, pars, sizeof(*pars));
+
+ /* register ops func. */
+ stbuf->ops = ops;
+
+ return 0;
+}
+EXPORT_SYMBOL(stream_buffer_base_init);
+
+void stream_buffer_set_ext_buf(struct stream_buf_s *stbuf,
+ ulong addr,
+ u32 size,
+ u32 flag)
+{
+ stbuf->ext_buf_addr = addr;
+ stbuf->buf_size = size;
+ stbuf->is_secure = ((flag & STBUF_META_FLAG_SECURE) != 0);
+ stbuf->use_ptsserv = ((flag & STBUF_META_FLAG_PTS_SERV) != 0);
+ /*
+ pr_debug("%s, addr %lx, size 0x%x, secure %d\n", __func__,
+ stbuf->ext_buf_addr, stbuf->buf_size, stbuf->is_secure);
+ */
+}
+EXPORT_SYMBOL(stream_buffer_set_ext_buf);
+
+#ifdef VDEC_FCC_SUPPORT
+void fcc_wakeup_jump_back(struct vdec_s *vdec,
+ struct stream_buffer_metainfo *meta)
+{
+ u32 first_ptr;
+ u32 round_down_size = 0;
+ if (fcc_debug_enable())
+ pr_info("[%d][FCC]: jump_back_done = %d jump_back_flag = %d stbuf_pktaddr = 0x%x size = 0x%x\n",
+ vdec->id, vdec->jump_back_done, meta->jump_back_flag,
+ meta->stbuf_pktaddr, meta->stbuf_size);
+ if (vdec->fcc_mode == FCC_DEC_MODE && vdec->fcc_status != SWITCH_DONE_STATUS) {
+ mutex_lock(&vdec->jump_back_mutex);
+ if (meta->jump_back_flag && !vdec->jump_back_done) {
+ if (vdec->input.target == VDEC_INPUT_TARGET_HEVC)
+ round_down_size = 0x80;
+ else if (vdec->input.target == VDEC_INPUT_TARGET_VLD)
+ round_down_size = 0x100;
+
+ if (vdec->vbuf.ext_buf_addr > (meta->stbuf_pktaddr - round_down_size))
+ first_ptr = vdec->vbuf.ext_buf_addr;
+ else {
+ first_ptr = round_down(meta->stbuf_pktaddr, round_down_size);
+ }
+ vdec->jump_back_done = 1;
+ vdec->jump_back_rp = first_ptr;
+ wake_up_interruptible(&vdec->jump_back_wq);
+ } else if (!vdec->jump_back_done && !vdec->jump_back_error) {
+ vdec->jump_back_error = 1;
+ wake_up_interruptible(&vdec->jump_back_wq);
+ }
+ mutex_unlock(&vdec->jump_back_mutex);
+ }
+
+ return;
+}
+#endif
+
+void stream_buffer_meta_write(struct stream_buf_s *stbuf,
+ struct stream_buffer_metainfo *meta)
+{
+ u32 wp = stbuf->ops->get_wp(stbuf);
+
+ if ((stbuf->stream_offset == 0) &&
+ /*(wp == stbuf->ext_buf_addr) &&*/ /*For fcc, when switching to dec mode it doesn't meet*/
+ (meta->stbuf_pktaddr > stbuf->ext_buf_addr)) {
+ struct vdec_s *vdec = container_of(stbuf, struct vdec_s, vbuf);
+ u32 first_ptr;
+ u32 round_down_size = 0;
+
+ /*RP max alignment requirement*/
+ if (vdec->input.target == VDEC_INPUT_TARGET_HEVC)
+ round_down_size = 0x80;
+ else if (vdec->input.target == VDEC_INPUT_TARGET_VLD)
+ round_down_size = 0x100;
+
+ if (stbuf->ext_buf_addr > (meta->stbuf_pktaddr - round_down_size))
+ first_ptr = stbuf->ext_buf_addr;
+ else {
+ first_ptr = round_down(meta->stbuf_pktaddr, round_down_size);
+ pr_info("warn: first packet_wp(%x round_down %x) is not stbuf start addr(%lx)\n",
+ meta->stbuf_pktaddr, first_ptr, stbuf->ext_buf_addr);
+ }
+
+ stbuf->ops->set_wp(stbuf, first_ptr);
+ stbuf->ops->set_rp(stbuf, first_ptr);
+ vdec->input.swap_rp = first_ptr;
+ if (vdec->slave)
+ vdec->slave->input.swap_rp = first_ptr;
+ if (vdec->input.target != VDEC_INPUT_TARGET_HEVC)
+ stbuf->stream_offset += (meta->stbuf_pktaddr - stbuf->ext_buf_addr);
+ else
+ stbuf->stream_offset += (meta->stbuf_pktaddr - first_ptr);
+ }
+
+ if (meta->stbuf_pktaddr + meta->stbuf_pktsize < stbuf->buf_start + stbuf->buf_size)
+ wp = meta->stbuf_pktaddr + meta->stbuf_pktsize;
+ else
+ wp = meta->stbuf_pktaddr + meta->stbuf_pktsize - stbuf->buf_size;
+
+ stbuf->ops->set_wp(stbuf, wp);
+
+ stbuf->stream_offset += meta->stbuf_pktsize;
+
+#ifdef VDEC_FCC_SUPPORT
+ fcc_wakeup_jump_back(container_of(stbuf, struct vdec_s, vbuf), meta);
+#endif
+ /*
+ pr_debug("%s, update wp 0x%x + sz 0x%x --> 0x%x, stream_offset 0x%x\n",
+ __func__, meta->stbuf_pktaddr, meta->stbuf_pktsize, wp, stbuf->stream_offset);
+ */
+}
+EXPORT_SYMBOL(stream_buffer_meta_write);
+
+ssize_t stream_buffer_write_ex(struct file *file,
+ struct stream_buf_s *stbuf,
+ const char __user *buf,
+ size_t count, int flags)
+{
+ int r;
+ u32 len = count;
+
+ if (buf == NULL || count == 0)
+ return -EINVAL;
+
+ if (stbuf_space(stbuf) < count) {
+ if ((flags & 2) || ((file != NULL) &&
+ (file->f_flags & O_NONBLOCK))) {
+ len = stbuf_space(stbuf);
+ if (len < 256) /* <1k.do eagain, */
+ return -EAGAIN;
+ } else {
+ len = min(stbuf_canusesize(stbuf) / 8, len);
+ if (stbuf_space(stbuf) < len) {
+ r = stbuf_wait_space(stbuf, len);
+ if (r < 0)
+ return r;
+ }
+ }
+ }
+
+ stbuf->last_write_jiffies64 = jiffies_64;
+ stbuf->is_phybuf = (flags & 1);
+
+ len = min_t(u32, len, count);
+
+ r = stbuf->ops->write(stbuf, buf, len);
+ if (r > 0)
+ stbuf->stream_offset += r;
+
+ return r;
+}
+EXPORT_SYMBOL(stream_buffer_write_ex);
+
+int stream_buffer_write(struct file *file,
+ struct stream_buf_s *stbuf,
+ const char *buf,
+ size_t count)
+{
+ if (stbuf->write_thread)
+ return threadrw_write(file, stbuf, buf, count);
+ else
+ return stream_buffer_write_ex(file, stbuf, buf, count, 0);
+}
+EXPORT_SYMBOL(stream_buffer_write);
+
diff --git a/drivers/stream_input/amports/stream_buffer_base.h b/drivers/stream_input/amports/stream_buffer_base.h
new file mode 100644
index 0000000..3360e64
--- /dev/null
+++ b/drivers/stream_input/amports/stream_buffer_base.h
@@ -0,0 +1,66 @@
+/*
+ * drivers/amlogic/media/stream_input/parser/stream_buffer_base.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 STREAM_BUFFER_INTERFACE_H
+#define STREAM_BUFFER_INTERFACE_H
+#include "streambuf.h"
+#include "streambuf_reg.h"
+
+#define STBUF_READ(s, func, args...) \
+({ \
+ u32 ret = 0; \
+ if ((s) && (s)->ops) \
+ ret = (s)->ops->func((s), ##args); \
+ ret; \
+})
+
+#define STBUF_WRITE(s, func, args...) \
+({ \
+ if ((s) && (s)->ops) \
+ (s)->ops->func((s), ##args); \
+})
+
+extern struct stream_buf_ops *get_stbuf_ops(void);
+extern struct stream_buf_ops *get_esparser_stbuf_ops(void);
+extern struct stream_buf_ops *get_tsparser_stbuf_ops(void);
+extern struct stream_buf_ops *get_psparser_stbuf_ops(void);
+
+int stream_buffer_base_init(struct stream_buf_s *stbuf,
+ struct stream_buf_ops *ops,
+ struct parser_args *pars);
+
+void stream_buffer_set_ext_buf(struct stream_buf_s *stbuf,
+ ulong addr,
+ u32 size,
+ u32 flag);
+
+int stream_buffer_write(struct file *file,
+ struct stream_buf_s *stbuf,
+ const char *buf,
+ size_t count);
+
+ssize_t stream_buffer_write_ex(struct file *file,
+ struct stream_buf_s *stbuf,
+ const char __user *buf,
+ size_t count,
+ int flags);
+
+void stream_buffer_meta_write(struct stream_buf_s *stbuf,
+ struct stream_buffer_metainfo *meta);
+
+#endif /* STREAM_BUFFER_INTERFACE_H */
+
diff --git a/drivers/stream_input/amports/stream_buffer_interface.c b/drivers/stream_input/amports/stream_buffer_interface.c
new file mode 100644
index 0000000..04ceaf5
--- /dev/null
+++ b/drivers/stream_input/amports/stream_buffer_interface.c
@@ -0,0 +1,323 @@
+/*
+ * drivers/amlogic/media/stream_input/parser/stream_bufffer_interface.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/wait.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/uaccess.h>
+#include <linux/atomic.h>
+#include <linux/delay.h>
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include <linux/amlogic/media/frame_sync/ptsserv.h>
+#include <linux/amlogic/media/frame_sync/tsync_pcr.h>
+#include "../../frame_provider/decoder/utils/vdec.h"
+#include "../../common/chips/decoder_cpu_ver_info.h"
+#include "stream_buffer_base.h"
+#include "amports_priv.h"
+#include "thread_rw.h"
+
+#define MEM_NAME "stbuf"
+#define MAP_RANGE (SZ_1M)
+
+static void stream_buffer_release(struct stream_buf_s *stbuf);
+
+static const char *type_to_str(int t)
+{
+ switch (t) {
+ case BUF_TYPE_VIDEO:
+ return "VIDEO";
+ case BUF_TYPE_AUDIO:
+ return "AUDIO";
+ case BUF_TYPE_SUBTITLE:
+ return "SUB";
+ case BUF_TYPE_USERDATA:
+ return "USER";
+ case BUF_TYPE_HEVC:
+ return "HEVC";
+ default:
+ return "ERR";
+ }
+}
+
+static int stream_buffer_init(struct stream_buf_s *stbuf, struct vdec_s *vdec)
+{
+ int ret = 0;
+ u32 flags = CODEC_MM_FLAGS_DMA;
+ bool is_secure = 0;
+ u32 addr = 0;
+ int pages = 0;
+ u32 size;
+
+ if (stbuf->buf_start)
+ return 0;
+
+ snprintf(stbuf->name, sizeof(stbuf->name),
+ "%s-%d", MEM_NAME, vdec->id);
+
+ if (stbuf->ext_buf_addr) {
+ addr = stbuf->ext_buf_addr;
+ size = stbuf->buf_size;
+ is_secure = stbuf->is_secure;
+ pages = (size >> PAGE_SHIFT);
+ } else {
+ flags |= CODEC_MM_FLAGS_FOR_VDECODER;
+ if (vdec->port_flag & PORT_FLAG_DRM) {
+ flags |= CODEC_MM_FLAGS_TVP;
+ is_secure = true;
+ }
+
+ size = PAGE_ALIGN(stbuf->buf_size);
+ pages = (size >> PAGE_SHIFT);
+ addr = codec_mm_alloc_for_dma(stbuf->name,
+ pages, PAGE_SHIFT + 4, flags);
+ if (!addr) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ stbuf->use_ptsserv = 1;
+ }
+ vdec_config_vld_reg(vdec, addr, size);
+
+ ret = vdec_set_input_buffer(vdec, addr, size);
+ if (ret) {
+ pr_err("[%d]: set input buffer err.\n", stbuf->id);
+ goto err;
+ }
+
+ atomic_set(&stbuf->payload, 0);
+ init_waitqueue_head(&stbuf->wq);
+
+ stbuf->buf_start = addr;
+ stbuf->buf_wp = addr;
+ stbuf->buf_rp = addr;
+ stbuf->buf_size = size;
+ stbuf->is_secure = is_secure;
+ stbuf->no_parser = true;
+ stbuf->buf_page_num = pages;
+ stbuf->canusebuf_size = size;
+ stbuf->stream_offset = 0;
+
+ /* init thread write. */
+ if (!(vdec_get_debug_flags() & 1) &&
+ !codec_mm_video_tvp_enabled() &&
+ (!stbuf->ext_buf_addr)) {
+ int block_size = PAGE_SIZE << 4;
+ int buf_num = (2 * SZ_1M) / (PAGE_SIZE << 4);
+
+ stbuf->write_thread =
+ threadrw_alloc(buf_num, block_size,
+ stream_buffer_write_ex, 0);
+ }
+
+ stbuf->flag |= BUF_FLAG_ALLOC;
+ stbuf->flag |= BUF_FLAG_IN_USE;
+
+ pr_info("[%d]: [%s-%s] addr: %lx, size: %x, thrRW: %d, extbuf: %d, secure: %d\n",
+ stbuf->id, type_to_str(stbuf->type), stbuf->name,
+ stbuf->buf_start, stbuf->buf_size,
+ !!stbuf->write_thread,
+ !!stbuf->ext_buf_addr,
+ stbuf->is_secure);
+
+ return 0;
+err:
+ stream_buffer_release(stbuf);
+
+ return ret;
+}
+
+static void stream_buffer_release(struct stream_buf_s *stbuf)
+{
+ if (stbuf->write_thread)
+ threadrw_release(stbuf);
+
+ if (stbuf->flag & BUF_FLAG_ALLOC && stbuf->buf_start) {
+ if (!stbuf->ext_buf_addr)
+ codec_mm_free_for_dma(MEM_NAME, stbuf->buf_start);
+
+ stbuf->flag &= ~BUF_FLAG_ALLOC;
+ stbuf->ext_buf_addr = 0;
+ stbuf->buf_start = 0;
+ stbuf->is_secure = false;
+ }
+ stbuf->flag &= ~BUF_FLAG_IN_USE;
+}
+
+static int get_free_space(struct stream_buf_s *stbuf)
+{
+ u32 len = stbuf->buf_size;
+ int idle = 0;
+
+ if (!atomic_read(&stbuf->payload) && (stbuf->buf_rp == stbuf->buf_wp))
+ idle = len;
+ else if (stbuf->buf_wp > stbuf->buf_rp)
+ idle = len - (stbuf->buf_wp - stbuf->buf_rp);
+ else if (stbuf->buf_wp < stbuf->buf_rp)
+ idle = stbuf->buf_rp - stbuf->buf_wp;
+
+ /*pr_info("[%d]: wp: %x, rp: %x, payload: %d, free space: %d\n",
+ stbuf->id, stbuf->buf_wp, stbuf->buf_rp,
+ atomic_read(&stbuf->payload), idle);*/
+
+ return idle;
+}
+
+static int aml_copy_from_user(void *to, const void *from, ulong n)
+{
+ int ret =0;
+
+ if (likely(access_ok(VERIFY_READ, from, n)))
+ ret = copy_from_user(to, from, n);
+ else
+ memcpy(to, from, n);
+
+ return ret;
+}
+
+static int stream_buffer_copy(struct stream_buf_s *stbuf, const u8 *buf, u32 size)
+{
+ int ret = 0;
+ void *src = NULL, *dst = NULL;
+ int i, len;
+
+ for (i = 0; i < size; i += MAP_RANGE) {
+ len = ((size - i) > MAP_RANGE) ? MAP_RANGE : size - i;
+ src = stbuf->is_phybuf ?
+ codec_mm_vmap((ulong) buf + i, len) :
+ (void *) buf;
+ dst = codec_mm_vmap(stbuf->buf_wp + i, len);
+ if (!src || !dst) {
+ ret = -EFAULT;
+ pr_err("[%d]: %s, src or dst is invalid.\n",
+ stbuf->id, __func__);
+ goto err;
+ }
+
+ if (aml_copy_from_user(dst, src, len)) {
+ ret = -EAGAIN;
+ goto err;
+ }
+
+ codec_mm_dma_flush(dst, len, DMA_TO_DEVICE);
+ codec_mm_unmap_phyaddr(dst);
+
+ if (stbuf->is_phybuf)
+ codec_mm_unmap_phyaddr(src);
+ }
+
+ return 0;
+err:
+ if (stbuf->is_phybuf && src)
+ codec_mm_unmap_phyaddr(src);
+ if (dst)
+ codec_mm_unmap_phyaddr(dst);
+ return ret;
+}
+
+static int rb_push_data(struct stream_buf_s *stbuf, const u8 *in, u32 size)
+{
+ int ret, len;
+ u32 wp = stbuf->buf_wp;
+ u32 sp = (stbuf->buf_wp + size);
+ u32 ep = (stbuf->buf_start + stbuf->buf_size);
+
+ len = sp > ep ? ep - wp : size;
+
+ if (!stbuf->ext_buf_addr) {
+ ret = stream_buffer_copy(stbuf, in, len);
+ if (ret)
+ return ret;
+ }
+
+ stbuf->ops->set_wp(stbuf, (wp + len >= ep) ?
+ stbuf->buf_start : (wp + len));
+
+ if (stbuf->buf_wp == stbuf->buf_rp) {
+ pr_debug("[%d]: stream buffer is full, payload: %d\n",
+ stbuf->id, atomic_read(&stbuf->payload));
+ }
+
+ return len;
+}
+
+static int stream_buffer_write_inner(struct stream_buf_s *stbuf,
+ const u8 *in, u32 size)
+{
+ if (in == NULL || size > stbuf->buf_size) {
+ pr_err("[%d]: params are not valid.\n", stbuf->id);
+ return -1;
+ }
+
+ if (get_free_space(stbuf) < size)
+ return -EAGAIN;
+
+ return rb_push_data(stbuf, in, size);
+}
+
+static u32 stream_buffer_get_wp(struct stream_buf_s *stbuf)
+{
+ return stbuf->buf_wp;
+}
+
+static void stream_buffer_set_wp(struct stream_buf_s *stbuf, u32 val)
+{
+ int len = (val >= stbuf->buf_wp) ? (val - stbuf->buf_wp) :
+ (stbuf->buf_size - stbuf->buf_wp + val);
+
+ stbuf->buf_wp = val;
+ vdec_set_vld_wp(container_of(stbuf, struct vdec_s, vbuf), stbuf->buf_wp);
+
+ atomic_add(len, &stbuf->payload);
+}
+
+static u32 stream_buffer_get_rp(struct stream_buf_s *stbuf)
+{
+ return stbuf->buf_rp;
+}
+
+static void stream_buffer_set_rp(struct stream_buf_s *stbuf, u32 val)
+{
+ int len = (val >= stbuf->buf_rp) ? (val - stbuf->buf_rp) :
+ (stbuf->buf_size - stbuf->buf_rp + val);
+
+ stbuf->buf_rp = val;
+ atomic_sub(len, &stbuf->payload);
+}
+
+static struct stream_buf_ops stream_buffer_ops = {
+ .init = stream_buffer_init,
+ .release = stream_buffer_release,
+ .write = stream_buffer_write_inner,
+ .get_wp = stream_buffer_get_wp,
+ .set_wp = stream_buffer_set_wp,
+ .get_rp = stream_buffer_get_rp,
+ .set_rp = stream_buffer_set_rp,
+};
+
+struct stream_buf_ops *get_stbuf_ops(void)
+{
+ return &stream_buffer_ops;
+}
+EXPORT_SYMBOL(get_stbuf_ops);
+
diff --git a/drivers/stream_input/amports/streambuf.c b/drivers/stream_input/amports/streambuf.c
new file mode 100644
index 0000000..fe360f2
--- /dev/null
+++ b/drivers/stream_input/amports/streambuf.c
@@ -0,0 +1,496 @@
+/*
+ * drivers/amlogic/media/stream_input/parser/streambuf.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/spinlock.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/amlogic/media/frame_sync/ptsserv.h>
+#include <linux/amlogic/media/utils/vformat.h>
+#include <linux/amlogic/iomap.h>
+#include <asm/cacheflush.h>
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+/* #include <mach/am_regs.h> */
+
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "../../frame_provider/decoder/utils/vdec.h"
+#include "streambuf_reg.h"
+#include "streambuf.h"
+#include <linux/amlogic/media/utils/amports_config.h>
+#include "../amports/amports_priv.h"
+#include <linux/dma-mapping.h>
+#include <linux/dma-contiguous.h>
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+
+#define STBUF_SIZE (64*1024)
+#define STBUF_WAIT_INTERVAL (HZ/100)
+#define MEM_NAME "streambuf"
+
+void *fetchbuf = 0;
+
+static s32 _stbuf_alloc(struct stream_buf_s *buf, bool is_secure)
+{
+ if (buf->buf_size == 0)
+ return -ENOBUFS;
+
+ while (buf->buf_start == 0) {
+ int flags = CODEC_MM_FLAGS_DMA;
+
+ buf->buf_page_num = PAGE_ALIGN(buf->buf_size) / PAGE_SIZE;
+ if (buf->type == BUF_TYPE_SUBTITLE)
+ flags = CODEC_MM_FLAGS_DMA_CPU;
+
+ /*
+ *if 4k,
+ *used cma first,for less mem fragments.
+ */
+ if (((buf->type == BUF_TYPE_HEVC) ||
+ (buf->type == BUF_TYPE_VIDEO)) &&
+ buf->for_4k)
+ flags |= CODEC_MM_FLAGS_CMA_FIRST;
+ if (buf->buf_size > 20 * 1024 * 1024)
+ flags |= CODEC_MM_FLAGS_CMA_FIRST;
+
+ if ((buf->type == BUF_TYPE_HEVC) ||
+ (buf->type == BUF_TYPE_VIDEO)) {
+ flags |= CODEC_MM_FLAGS_FOR_VDECODER;
+ } else if (buf->type == BUF_TYPE_AUDIO) {
+ flags |= CODEC_MM_FLAGS_FOR_ADECODER;
+ flags |= CODEC_MM_FLAGS_DMA_CPU;
+ }
+
+ if (is_secure)
+ flags |= CODEC_MM_FLAGS_TVP;
+
+ buf->buf_start = codec_mm_alloc_for_dma(MEM_NAME,
+ buf->buf_page_num, 4+PAGE_SHIFT, flags);
+ if (!buf->buf_start) {
+ int is_video = (buf->type == BUF_TYPE_HEVC) ||
+ (buf->type == BUF_TYPE_VIDEO);
+ if (is_video && buf->buf_size >= 9 * SZ_1M) {/*min 6M*/
+ int old_size = buf->buf_size;
+
+ buf->buf_size =
+ PAGE_ALIGN(buf->buf_size * 2/3);
+ pr_info("%s stbuf alloced size = %d failed try small %d size\n",
+ (buf->type == BUF_TYPE_HEVC) ? "HEVC" :
+ (buf->type == BUF_TYPE_VIDEO) ? "Video" :
+ (buf->type == BUF_TYPE_AUDIO) ? "Audio" :
+ "Subtitle", old_size, buf->buf_size);
+ continue;
+ }
+ pr_info("%s stbuf alloced size = %d failed\n",
+ (buf->type == BUF_TYPE_HEVC) ? "HEVC" :
+ (buf->type == BUF_TYPE_VIDEO) ? "Video" :
+ (buf->type == BUF_TYPE_AUDIO) ? "Audio" :
+ "Subtitle", buf->buf_size);
+ return -ENOMEM;
+ }
+
+ buf->is_secure = is_secure;
+
+ pr_debug("%s stbuf alloced at %p, secure = %d, size = %d\n",
+ (buf->type == BUF_TYPE_HEVC) ? "HEVC" :
+ (buf->type == BUF_TYPE_VIDEO) ? "Video" :
+ (buf->type == BUF_TYPE_AUDIO) ? "Audio" :
+ "Subtitle", (void *)buf->buf_start,
+ buf->is_secure,
+ buf->buf_size);
+ }
+
+ buf->canusebuf_size = buf->buf_size;
+ buf->flag |= BUF_FLAG_ALLOC;
+
+ return 0;
+}
+
+int stbuf_change_size(struct stream_buf_s *buf, int size, bool is_secure)
+{
+ unsigned long old_buf;
+ int old_size, old_pagenum;
+ int ret;
+
+ pr_info("buffersize=%d,%d,start=%p, secure=%d\n", size, buf->buf_size,
+ (void *)buf->buf_start, is_secure);
+
+ if (buf->buf_size == size && buf->buf_start != 0)
+ return 0;
+
+ old_buf = buf->buf_start;
+ old_size = buf->buf_size;
+ old_pagenum = buf->buf_page_num;
+ buf->buf_start = 0;
+ buf->buf_size = size;
+ ret = size;
+
+ if (size == 0 ||
+ _stbuf_alloc(buf, is_secure) == 0) {
+ /*
+ * size=0:We only free the old memory;
+ * alloc ok,changed to new buffer
+ */
+ if (old_buf != 0) {
+ codec_mm_free_for_dma(MEM_NAME, old_buf);
+ }
+
+ if (size == 0)
+ buf->is_secure = false;
+
+ pr_info("changed the (%d) buffer size from %d to %d\n",
+ buf->type, old_size, size);
+ return 0;
+ } else {
+ /* alloc failed */
+ buf->buf_start = old_buf;
+ buf->buf_size = old_size;
+ buf->buf_page_num = old_pagenum;
+ pr_info("changed the (%d) buffer size from %d to %d,failed\n",
+ buf->type, old_size, size);
+ }
+
+ return ret;
+}
+
+int stbuf_fetch_init(void)
+{
+ if (NULL != fetchbuf)
+ return 0;
+
+ fetchbuf = (void *)__get_free_pages(GFP_KERNEL,
+ get_order(FETCHBUF_SIZE));
+
+ if (!fetchbuf) {
+ pr_info("%s: Can not allocate fetch working buffer\n",
+ __func__);
+ return -ENOMEM;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(stbuf_fetch_init);
+
+void stbuf_fetch_release(void)
+{
+ if (0 && fetchbuf) {
+ /* always don't free.for safe alloc/free*/
+ free_pages((unsigned long)fetchbuf, get_order(FETCHBUF_SIZE));
+ fetchbuf = 0;
+ }
+}
+
+static void _stbuf_timer_func(unsigned long arg)
+{
+ struct stream_buf_s *p = (struct stream_buf_s *)arg;
+
+ if (stbuf_space(p) < p->wcnt) {
+ p->timer.expires = jiffies + STBUF_WAIT_INTERVAL;
+
+ add_timer(&p->timer);
+ } else
+ wake_up_interruptible(&p->wq);
+
+}
+
+u32 stbuf_level(struct stream_buf_s *buf)
+{
+ if ((buf->type == BUF_TYPE_HEVC) || (buf->type == BUF_TYPE_VIDEO)) {
+ if (buf->no_parser) {
+ int level = buf->buf_wp - buf->buf_rp;
+ if (level < 0)
+ level += buf->buf_size;
+ return level;
+ } else {
+ if (READ_PARSER_REG(PARSER_ES_CONTROL) & 1) {
+ int level = READ_PARSER_REG(PARSER_VIDEO_WP) -
+ READ_PARSER_REG(PARSER_VIDEO_RP);
+ if (level < 0)
+ level += READ_PARSER_REG(PARSER_VIDEO_END_PTR) -
+ READ_PARSER_REG(PARSER_VIDEO_START_PTR) + 8;
+ return (u32)level;
+ } else
+ return (buf->type == BUF_TYPE_HEVC) ?
+ READ_VREG(HEVC_STREAM_LEVEL) :
+ _READ_ST_REG(LEVEL);
+ }
+ }
+
+ return _READ_ST_REG(LEVEL);
+}
+
+u32 stbuf_rp(struct stream_buf_s *buf)
+{
+ if ((buf->type == BUF_TYPE_HEVC) || (buf->type == BUF_TYPE_VIDEO)) {
+ if (buf->no_parser)
+ return buf->buf_rp;
+ else {
+ if (READ_PARSER_REG(PARSER_ES_CONTROL) & 1)
+ return READ_PARSER_REG(PARSER_VIDEO_RP);
+ else
+ return (buf->type == BUF_TYPE_HEVC) ?
+ READ_VREG(HEVC_STREAM_RD_PTR) :
+ _READ_ST_REG(RP);
+ }
+ }
+
+ return _READ_ST_REG(RP);
+}
+
+u32 stbuf_space(struct stream_buf_s *buf)
+{
+ /* reserved space for safe write,
+ * the parser fifo size is 1024byts, so reserve it
+ */
+ int size;
+
+ size = buf->canusebuf_size - stbuf_level(buf);
+
+ if (buf->canusebuf_size >= buf->buf_size / 2) {
+ /* old reversed value,tobe full, reversed only... */
+ size = size - 6 * 1024;
+ }
+
+ if (!buf->no_parser) {
+ if ((buf->type == BUF_TYPE_VIDEO)
+ || (has_hevc_vdec() && buf->type == BUF_TYPE_HEVC))
+ size -= READ_PARSER_REG(PARSER_VIDEO_HOLE);
+ }
+ return size > 0 ? size : 0;
+}
+
+u32 stbuf_size(struct stream_buf_s *buf)
+{
+ return buf->buf_size;
+}
+
+u32 stbuf_canusesize(struct stream_buf_s *buf)
+{
+ return buf->canusebuf_size;
+}
+
+s32 stbuf_init(struct stream_buf_s *buf, struct vdec_s *vdec)
+{
+ s32 r;
+ u32 dummy;
+ u32 addr32;
+
+ VDEC_PRINT_FUN_LINENO(__func__, __LINE__);
+
+ if (!buf->buf_start) {
+ r = _stbuf_alloc(buf, (vdec) ?
+ vdec->port_flag & PORT_FLAG_DRM : 0);
+ if (r < 0)
+ return r;
+ }
+ addr32 = buf->buf_start & 0xffffffff;
+ buf->use_ptsserv = true;
+ init_waitqueue_head(&buf->wq);
+
+ /*
+ * For multidec, do not touch HW stream buffers during port
+ * init and release.
+ */
+ if ((buf->type == BUF_TYPE_VIDEO) || (buf->type == BUF_TYPE_HEVC)) {
+ if (vdec) {
+ if (vdec_stream_based(vdec))
+ vdec_set_input_buffer(vdec, addr32,
+ buf->buf_size);
+ else
+ return vdec_set_input_buffer(vdec, addr32,
+ buf->buf_size);
+ }
+ }
+
+ buf->write_thread = 0;
+ if (((vdec && !vdec_single(vdec)) || (buf->is_multi_inst)) &&
+ (vdec_get_debug_flags() & 0x2) == 0)
+ return 0;
+ if (has_hevc_vdec() && buf->type == BUF_TYPE_HEVC) {
+ CLEAR_VREG_MASK(HEVC_STREAM_CONTROL, 1);
+ WRITE_VREG(HEVC_STREAM_START_ADDR, addr32);
+ WRITE_VREG(HEVC_STREAM_END_ADDR, addr32 + buf->buf_size);
+ WRITE_VREG(HEVC_STREAM_RD_PTR, addr32);
+ WRITE_VREG(HEVC_STREAM_WR_PTR, addr32);
+
+ return 0;
+ }
+
+ if (buf->type == BUF_TYPE_VIDEO) {
+ VDEC_PRINT_FUN_LINENO(__func__, __LINE__);
+
+ _WRITE_ST_REG(CONTROL, 0);
+ /* reset VLD before setting all pointers */
+ WRITE_VREG(VLD_MEM_VIFIFO_WRAP_COUNT, 0);
+ /*TODO: only > m6*/
+#if 1/* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+ WRITE_VREG(DOS_SW_RESET0, (1 << 4));
+ WRITE_VREG(DOS_SW_RESET0, 0);
+#else
+ WRITE_RESET_REG(RESET0_REGISTER, RESET_VLD);
+#endif
+
+ dummy = READ_RESET_REG(RESET0_REGISTER);
+ WRITE_VREG(POWER_CTL_VLD, 1 << 4);
+ } else if (buf->type == BUF_TYPE_AUDIO) {
+ _WRITE_ST_REG(CONTROL, 0);
+
+ WRITE_AIU_REG(AIU_AIFIFO_GBIT, 0x80);
+ }
+
+ if (buf->type == BUF_TYPE_SUBTITLE) {
+ WRITE_PARSER_REG(PARSER_SUB_RP, addr32);
+ WRITE_PARSER_REG(PARSER_SUB_START_PTR, addr32);
+ WRITE_PARSER_REG(PARSER_SUB_END_PTR,
+ addr32 + buf->buf_size - 8);
+
+ return 0;
+ }
+
+ _WRITE_ST_REG(START_PTR, addr32);
+ _WRITE_ST_REG(CURR_PTR, addr32);
+ _WRITE_ST_REG(END_PTR, addr32 + buf->buf_size - 8);
+
+ _SET_ST_REG_MASK(CONTROL, MEM_BUFCTRL_INIT);
+ _CLR_ST_REG_MASK(CONTROL, MEM_BUFCTRL_INIT);
+
+ _WRITE_ST_REG(BUF_CTRL, MEM_BUFCTRL_MANUAL);
+ _WRITE_ST_REG(WP, addr32);
+
+ _SET_ST_REG_MASK(BUF_CTRL, MEM_BUFCTRL_INIT);
+ _CLR_ST_REG_MASK(BUF_CTRL, MEM_BUFCTRL_INIT);
+
+ _SET_ST_REG_MASK(CONTROL,
+ (0x11 << 16) | MEM_FILL_ON_LEVEL | MEM_CTRL_FILL_EN |
+ MEM_CTRL_EMPTY_EN);
+
+ if (buf->no_parser)
+ _SET_ST_REG_MASK(CONTROL, 7 << 3);
+
+ return 0;
+}
+EXPORT_SYMBOL(stbuf_init);
+
+void stbuf_vdec2_init(struct stream_buf_s *buf)
+{
+
+ _WRITE_VDEC2_ST_REG(CONTROL, 0);
+
+ _WRITE_VDEC2_ST_REG(START_PTR, _READ_ST_REG(START_PTR));
+ _WRITE_VDEC2_ST_REG(END_PTR, _READ_ST_REG(END_PTR));
+ _WRITE_VDEC2_ST_REG(CURR_PTR, _READ_ST_REG(CURR_PTR));
+
+ _WRITE_VDEC2_ST_REG(CONTROL, MEM_FILL_ON_LEVEL | MEM_BUFCTRL_INIT);
+ _WRITE_VDEC2_ST_REG(CONTROL, MEM_FILL_ON_LEVEL);
+
+ _WRITE_VDEC2_ST_REG(BUF_CTRL, MEM_BUFCTRL_INIT);
+ _WRITE_VDEC2_ST_REG(BUF_CTRL, 0);
+
+ _WRITE_VDEC2_ST_REG(CONTROL,
+ (0x11 << 16) | MEM_FILL_ON_LEVEL | MEM_CTRL_FILL_EN
+ | MEM_CTRL_EMPTY_EN);
+}
+
+s32 stbuf_wait_space(struct stream_buf_s *stream_buf, size_t count)
+{
+ struct stream_buf_s *p = stream_buf;
+ long time_out = 200;
+
+ p->wcnt = count;
+
+ setup_timer(&p->timer, _stbuf_timer_func, (ulong) p);
+
+ mod_timer(&p->timer, jiffies + STBUF_WAIT_INTERVAL);
+
+ if (wait_event_interruptible_timeout
+ (p->wq, stbuf_space(p) >= count,
+ msecs_to_jiffies(time_out)) == 0) {
+ del_timer_sync(&p->timer);
+
+ return -EAGAIN;
+ }
+
+ del_timer_sync(&p->timer);
+
+ return 0;
+}
+
+void stbuf_release(struct stream_buf_s *buf)
+{
+ int r;
+
+ buf->first_tstamp = INVALID_PTS;
+ if (!buf->ext_buf_addr) {
+ r = stbuf_init(buf, NULL);/* reinit buffer */
+ if (r < 0)
+ pr_err("stbuf_release %d, stbuf_init failed\n", __LINE__);
+ }
+ if (buf->flag & BUF_FLAG_ALLOC && buf->buf_start) {
+ codec_mm_free_for_dma(MEM_NAME, buf->buf_start);
+ buf->flag &= ~BUF_FLAG_ALLOC;
+ buf->buf_start = 0;
+ buf->is_secure = false;
+ }
+ buf->flag &= ~BUF_FLAG_IN_USE;
+}
+EXPORT_SYMBOL(stbuf_release);
+
+u32 stbuf_sub_rp_get(void)
+{
+ return READ_PARSER_REG(PARSER_SUB_RP);
+}
+
+void stbuf_sub_rp_set(unsigned int sub_rp)
+{
+ WRITE_PARSER_REG(PARSER_SUB_RP, sub_rp);
+ return;
+}
+
+u32 stbuf_sub_wp_get(void)
+{
+ return READ_PARSER_REG(PARSER_SUB_WP);
+}
+
+u32 stbuf_sub_start_get(void)
+{
+ return READ_PARSER_REG(PARSER_SUB_START_PTR);
+}
+
+u32 parser_get_wp(struct stream_buf_s *vb)
+{
+ return READ_PARSER_REG(PARSER_VIDEO_WP);
+}
+EXPORT_SYMBOL(parser_get_wp);
+
+void parser_set_wp(struct stream_buf_s *vb, u32 val)
+{
+ WRITE_PARSER_REG(PARSER_VIDEO_WP, val);
+}
+EXPORT_SYMBOL(parser_set_wp);
+
+u32 parser_get_rp(struct stream_buf_s *vb)
+{
+ return READ_PARSER_REG(PARSER_VIDEO_RP);
+}
+EXPORT_SYMBOL(parser_get_rp);
+
+void parser_set_rp(struct stream_buf_s *vb, u32 val)
+{
+ WRITE_PARSER_REG(PARSER_VIDEO_RP, val);
+}
+EXPORT_SYMBOL(parser_set_rp);
+
diff --git a/drivers/stream_input/amports/streambuf.h b/drivers/stream_input/amports/streambuf.h
new file mode 100644
index 0000000..afb2ebe
--- /dev/null
+++ b/drivers/stream_input/amports/streambuf.h
@@ -0,0 +1,206 @@
+/*
+ * drivers/amlogic/media/stream_input/parser/streambuf.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 STREAMBUF_H
+#define STREAMBUF_H
+#include <linux/amlogic/media/utils/amports_config.h>
+
+#define BUF_FLAG_ALLOC 0x01
+#define BUF_FLAG_IN_USE 0x02
+#define BUF_FLAG_PARSER 0x04
+#define BUF_FLAG_FIRST_TSTAMP 0x08
+#define BUF_FLAG_IOMEM 0x10
+
+#define BUF_TYPE_VIDEO 0
+#define BUF_TYPE_AUDIO 1
+#define BUF_TYPE_SUBTITLE 2
+#define BUF_TYPE_USERDATA 3
+#define BUF_TYPE_HEVC 4
+#define BUF_MAX_NUM 5
+
+#define INVALID_PTS 0xffffffff
+
+#define FETCHBUF_SIZE (64*1024)
+#define USER_DATA_SIZE (8*1024)
+
+/* stream_buffer_metainfo stbuf_flag */
+#define STBUF_META_FLAG_SECURE (1 << 0)
+#define STBUF_META_FLAG_PTS_SERV (1 << 1) /* use pts server flag */
+#define STBUF_META_FLAG_XXX1 (1 << 2)
+
+struct vdec_s;
+struct stream_buf_s;
+
+struct parser_args {
+ u32 vid;
+ u32 aid;
+ u32 sid;
+ u32 pcrid;
+};
+
+struct stream_buf_ops {
+ int (*init) (struct stream_buf_s *, struct vdec_s *);
+ void (*release) (struct stream_buf_s *);
+ int (*write) (struct stream_buf_s *, const u8 *, u32);
+ u32 (*get_wp) (struct stream_buf_s *);
+ void (*set_wp) (struct stream_buf_s *, u32);
+ u32 (*get_rp) (struct stream_buf_s *);
+ void (*set_rp) (struct stream_buf_s *, u32);
+};
+
+struct stream_buf_s {
+ int id;
+ u8 name[16];
+ s32 flag;
+ u32 type;
+ unsigned long buf_start;
+ struct page *buf_pages;
+ int buf_page_num;
+ u32 buf_size;
+ u32 default_buf_size;
+ u32 canusebuf_size;
+ u32 first_tstamp;
+ const ulong reg_base;
+ wait_queue_head_t wq;
+ struct timer_list timer;
+ u32 wcnt;
+ u32 buf_wp;
+ u32 buf_rp;
+ u32 max_buffer_delay_ms;
+ u64 last_write_jiffies64;
+ void *write_thread;
+ int for_4k;
+ bool is_secure;
+ bool is_multi_inst;
+ bool no_parser;
+ bool is_phybuf;
+ bool is_hevc;
+ bool use_ptsserv;
+ u32 drm_flag;
+ ulong ext_buf_addr;
+ atomic_t payload;
+ u32 stream_offset;
+ struct parser_args pars;
+ struct stream_buf_ops *ops;
+} /*stream_buf_t */;
+
+struct stream_port_s {
+ /* driver info */
+ const char *name;
+ struct device *class_dev;
+ const struct file_operations *fops;
+
+ /* ports control */
+ s32 type;
+ s32 flag;
+ s32 pcr_inited;
+
+ /* decoder info */
+ s32 vformat;
+ s32 aformat;
+ s32 achanl;
+ s32 asamprate;
+ s32 adatawidth;
+
+ /* parser info */
+ u32 vid;
+ u32 aid;
+ u32 sid;
+ u32 pcrid;
+ bool is_4k;
+} /*stream_port_t */;
+enum drm_level_e {
+ DRM_LEVEL1 = 1,
+ DRM_LEVEL2 = 2,
+ DRM_LEVEL3 = 3,
+ DRM_NONE = 4,
+};
+
+struct drm_info {
+ enum drm_level_e drm_level;
+ u32 drm_flag;
+ u32 drm_hasesdata;
+ u32 drm_priv;
+ u32 drm_pktsize;
+ u32 drm_pktpts;
+ u32 drm_phy;
+ u32 drm_vir;
+ u32 drm_remap;
+ u32 data_offset;
+ u32 handle;
+ u32 extpad[7];
+} /*drminfo_t */;
+
+struct stream_buffer_metainfo {
+ union {
+ u32 stbuf_start;
+ u32 stbuf_pktaddr; //stbuf_pktaddr + stbuf_pktsize = wp
+ };
+ union {
+ u32 stbuf_size;
+ u32 stbuf_pktsize;
+ };
+ u32 stbuf_flag;
+ u32 stbuf_private;
+ u32 jump_back_flag;
+ u32 reserved[15];
+};
+
+struct stream_buffer_status {
+ u32 stbuf_wp;
+ u32 stbuf_rp;
+ u32 stbuf_start;
+ u32 stbuf_size;
+ u32 reserved[16];
+};
+
+
+#define TYPE_DRMINFO_V2 0x100
+#define TYPE_DRMINFO 0x80
+#define TYPE_PATTERN 0x40
+
+struct vdec_s;
+
+extern void *fetchbuf;
+
+extern u32 stbuf_level(struct stream_buf_s *buf);
+extern u32 stbuf_rp(struct stream_buf_s *buf);
+extern u32 stbuf_space(struct stream_buf_s *buf);
+extern u32 stbuf_size(struct stream_buf_s *buf);
+extern u32 stbuf_canusesize(struct stream_buf_s *buf);
+extern s32 stbuf_init(struct stream_buf_s *buf, struct vdec_s *vdec);
+extern s32 stbuf_wait_space(struct stream_buf_s *stream_buf, size_t count);
+extern void stbuf_release(struct stream_buf_s *buf);
+extern int stbuf_change_size(struct stream_buf_s *buf, int size,
+ bool is_secure);
+extern int stbuf_fetch_init(void);
+extern void stbuf_fetch_release(void);
+extern u32 stbuf_sub_rp_get(void);
+extern void stbuf_sub_rp_set(unsigned int sub_rp);
+extern u32 stbuf_sub_wp_get(void);
+extern u32 stbuf_sub_start_get(void);
+extern u32 stbuf_userdata_start_get(void);
+extern struct stream_buf_s *get_stream_buffer(int id);
+
+extern void stbuf_vdec2_init(struct stream_buf_s *buf);
+
+u32 parser_get_wp(struct stream_buf_s *vb);
+void parser_set_wp(struct stream_buf_s *vb, u32 val);
+u32 parser_get_rp(struct stream_buf_s *vb);
+void parser_set_rp(struct stream_buf_s *vb, u32 val);
+
+#endif /* STREAMBUF_H */
diff --git a/drivers/stream_input/amports/streambuf_reg.h b/drivers/stream_input/amports/streambuf_reg.h
new file mode 100644
index 0000000..5f0c8ca
--- /dev/null
+++ b/drivers/stream_input/amports/streambuf_reg.h
@@ -0,0 +1,114 @@
+/*
+ * drivers/amlogic/media/stream_input/parser/streambuf_reg.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 STREAMBUF_REG_H
+#define STREAMBUF_REG_H
+
+#define HEVC_STREAM_REG_BASE HEVC_STREAM_START_ADDR
+
+#define VLD_MEM_VIFIFO_REG_BASE VLD_MEM_VIFIFO_START_PTR
+#define AIU_MEM_AIFIFO_REG_BASE AIU_MEM_AIFIFO_START_PTR
+
+#define START_PTR 0
+#define CURR_PTR 1
+#define END_PTR 2
+#define BYTES_AVAIL 3
+#define CONTROL 4
+#define WP 5
+#define RP 6
+#define LEVEL 7
+#define BUF_CTRL 8
+
+/*
+ *#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6
+ *#define _WRITE_ST_REG(r, val) \
+ * __raw_writel(val, (volatile void __iomem *)(buf->reg_base+(r<<2)))
+ *#define _WRITE_ST_REG_BITS(r, val, s, e) \
+ * __raw_writel((((_READ_ST_REG(r) & \
+ * (((1L<<(e)-1)<<(s))-1)<<(s)))|((unsigned)((val)&((1L<<(e))-1))<<(s))), \
+ * (volatile void __iomem *)(buf->reg_base+(r<<2)))
+ *#define _SET_ST_REG_MASK(r, val) \
+ * __raw_writel(_READ_ST_REG(r)| (val), \
+ * (volatile void __iomem *)(buf->reg_base+(r<<2)))
+ *#define _CLR_ST_REG_MASK(r, val) \
+ * __raw_writel(_READ_ST_REG(r)&~(val), \
+ * (volatile void __iomem *)(buf->reg_base+(r<<2)))
+ *#define _READ_ST_REG(r) \
+ * (__raw_readl((volatile void __iomem *)(buf->reg_base+(r<<2))))
+ *
+ *#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6TVD
+ *#define _READ_VDEC2_ST_REG(r) \
+ * (__raw_readl((volatile void __iomem *)(buf->reg_base + \
+ * DOS_REG_ADDR(VDEC2_VLD_MEM_VIFIFO_START_PTR) - \
+ * DOS_REG_ADDR(VLD_MEM_VIFIFO_START_PTR) + (r<<2))))
+ *#define _WRITE_VDEC2_ST_REG(r, val) \
+ * __raw_writel(val, (volatile void __iomem *)(buf->reg_base + \
+ * DOS_REG_ADDR(VDEC2_VLD_MEM_VIFIFO_START_PTR) - \
+ * DOS_REG_ADDR(VLD_MEM_VIFIFO_START_PTR) + (r<<2)))
+ *#endif
+ *
+ *#define MEM_BUFCTRL_MANUAL (1<<1)
+ *#define MEM_BUFCTRL_INIT (1<<0)
+ *#define MEM_LEVEL_CNT_BIT 18
+ *#define MEM_FIFO_CNT_BIT 16
+ *#define MEM_FILL_ON_LEVEL (1<<10)
+ *#define MEM_CTRL_EMPTY_EN (1<<2)
+ *#define MEM_CTRL_FILL_EN (1<<1)
+ *#define MEM_CTRL_INIT (1<<0)
+ *
+ *#else
+ *#define _WRITE_ST_REG(r, val) \
+ *WRITE_MPEG_REG(buf->reg_base + (r), \
+ * (val))
+ *#define _WRITE_ST_REG_BITS(r, val, s, e)\
+ * WRITE_MPEG_REG(buf->reg_base + (r), \
+ * (val), (s), (e))
+ *#define _SET_ST_REG_MASK(r, val) SET_MPEG_REG_MASK(buf->reg_base + \
+ * (r), (val))
+ *#define _CLR_ST_REG_MASK(r, val) CLEAR_MPEG_REG_MASK(buf->reg_base + \
+ * (r), (val))
+ *#define _READ_ST_REG(r) READ_MPEG_REG(buf->reg_base + (r))
+ *#endif
+ */
+
+ /*TODO*/
+#define _WRITE_ST_REG(r, val) do { \
+ if (buf->reg_base == VLD_MEM_VIFIFO_REG_BASE) \
+ codec_dosbus_write((buf->reg_base+(r)), (val)); \
+ else \
+ codec_aiubus_write((buf->reg_base+(r)), (val)); \
+ } while (0)
+#define _READ_ST_REG(r) \
+ ((buf->reg_base == VLD_MEM_VIFIFO_REG_BASE) ? \
+ codec_dosbus_read(buf->reg_base+(r)) : \
+ codec_aiubus_read(buf->reg_base+(r)))
+
+#define _SET_ST_REG_MASK(r, val) _WRITE_ST_REG(r, _READ_ST_REG(r) | (val))
+#define _CLR_ST_REG_MASK(r, val) _WRITE_ST_REG(r, _READ_ST_REG(r)&~(val))
+#define _READ_VDEC2_ST_REG(r) (codec_dosbus_read(\
+ (VDEC2_VLD_MEM_VIFIFO_START_PTR+(r))))
+#define _WRITE_VDEC2_ST_REG(r, val) codec_dosbus_write(\
+ (VDEC2_VLD_MEM_VIFIFO_START_PTR+r), val)
+#define MEM_BUFCTRL_MANUAL (1<<1)
+#define MEM_BUFCTRL_INIT (1<<0)
+#define MEM_LEVEL_CNT_BIT 18
+#define MEM_FIFO_CNT_BIT 16
+#define MEM_FILL_ON_LEVEL (1<<10)
+#define MEM_CTRL_EMPTY_EN (1<<2)
+#define MEM_CTRL_FILL_EN (1<<1)
+#define MEM_CTRL_INIT (1<<0)
+#endif /* STREAMBUF_REG_H */
diff --git a/drivers/stream_input/amports/thread_rw.c b/drivers/stream_input/amports/thread_rw.c
new file mode 100644
index 0000000..0d386ce
--- /dev/null
+++ b/drivers/stream_input/amports/thread_rw.c
@@ -0,0 +1,630 @@
+/*
+ * drivers/amlogic/media/stream_input/parser/thread_rw.c
+ *
+ * Copyright (C) 2016 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/kfifo.h>
+#include <linux/workqueue.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma-contiguous.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+
+/* #include <mach/am_regs.h> */
+#include <linux/delay.h>
+
+#include "streambuf.h"
+#include "amports_priv.h"
+#include "thread_rw.h"
+
+#define BUF_NAME "fetchbuf"
+
+#define DEFAULT_BLOCK_SIZE (64*1024)
+
+struct threadrw_buf {
+ void *vbuffer;
+ dma_addr_t dma_handle;
+ int write_off;
+ int data_size;
+ int buffer_size;
+ int from_cma;
+};
+
+#define MAX_MM_BUFFER_NUM 16
+struct threadrw_write_task {
+ struct file *file;
+ struct delayed_work write_work;
+ DECLARE_KFIFO_PTR(datafifo, void *);
+ DECLARE_KFIFO_PTR(freefifo, void *);
+ int bufs_num;
+ int max_bufs;
+ int errors;
+ spinlock_t lock;
+ struct mutex mutex;
+ struct stream_buf_s *sbuf;
+ int buffered_data_size;
+ int passed_data_len;
+ int buffer_size;
+ int def_block_size;
+ int data_offset;
+ int writework_on;
+ unsigned long codec_mm_buffer[MAX_MM_BUFFER_NUM];
+ int manual_write;
+ int failed_onmore;
+ wait_queue_head_t wq;
+ ssize_t (*write)(struct file *,
+ struct stream_buf_s *,
+ const char __user *,
+ size_t, int);
+ struct threadrw_buf buf[1];
+ /*don't add any after buf[] define */
+};
+
+static int free_task_buffers(struct threadrw_write_task *task);
+
+static struct workqueue_struct *threadrw_wq_get(void)
+{
+ static struct workqueue_struct *threadrw_wq;
+
+ if (!threadrw_wq)
+ threadrw_wq = create_singlethread_workqueue("threadrw");
+ return threadrw_wq;
+}
+
+static int threadrw_schedule_delayed_work(
+ struct threadrw_write_task *task,
+ unsigned long delay)
+{
+ bool ret;
+
+ if (threadrw_wq_get()) {
+ ret = queue_delayed_work(threadrw_wq_get(),
+ &task->write_work, delay);
+ } else
+ ret = schedule_delayed_work(&task->write_work, delay);
+ if (!ret) {
+ cancel_delayed_work(&task->write_work);
+ if (threadrw_wq_get())
+ ret = queue_delayed_work(threadrw_wq_get(),
+ &task->write_work, 0);
+ else
+ ret = schedule_delayed_work(&task->write_work, 0);
+ }
+ return 0;
+}
+
+static ssize_t threadrw_write_onece(
+ struct threadrw_write_task *task,
+ struct file *file,
+ struct stream_buf_s *stbuf,
+ const char __user *buf, size_t count)
+{
+ struct threadrw_buf *rwbuf = NULL;
+ int ret = 0;
+ int to_write;
+
+ if (!kfifo_get(&task->freefifo, (void *)&rwbuf)) {
+ if (task->errors)
+ return task->errors;
+ return -EAGAIN;
+ }
+
+ to_write = min_t(u32, rwbuf->buffer_size, count);
+ if (copy_from_user(rwbuf->vbuffer, buf, to_write)) {
+ kfifo_put(&task->freefifo, (const void *)buf);
+ ret = -EFAULT;
+ goto err;
+ }
+ rwbuf->data_size = to_write;
+ rwbuf->write_off = 0;
+ kfifo_put(&task->datafifo, (const void *)rwbuf);
+ threadrw_schedule_delayed_work(task, 0);
+ return to_write;
+err:
+ return ret;
+}
+
+static ssize_t threadrw_write_in(
+ struct threadrw_write_task *task,
+ struct stream_buf_s *stbuf,
+ const char __user *buf, size_t count)
+{
+ int ret = 0;
+ int off = 0;
+ /* int change to size_t for buffer overflow on OTT-5057 */
+ size_t left = count;
+ int wait_num = 0;
+ unsigned long flags;
+
+ while (left > 0) {
+ ret = threadrw_write_onece(task,
+ task->file,
+ stbuf, buf + off, left);
+
+ /* firstly check ret < 0, avoid the risk of -EAGAIN in ret
+ * implicit convert to size_t when compare with "size_t left".
+ */
+ if (ret < 0) {
+ if (off > 0) {
+ break; /*have write ok some data. */
+ } else if (ret == -EAGAIN) {
+ if (!(task->file->f_flags & O_NONBLOCK) &&
+ (++wait_num < 10)) {
+ wait_event_interruptible_timeout(
+ task->wq,
+ !kfifo_is_empty(
+ &task->freefifo),
+ HZ / 100);
+ continue; /* write again. */
+ }
+ ret = -EAGAIN;
+ break;
+ }
+ break; /*to end */
+ } else if (ret >= left) {
+ off = count;
+ left = 0;
+ } else if (ret > 0) {
+ off += ret;
+ left -= ret;
+ }
+ }
+
+ /*end: */
+ spin_lock_irqsave(&task->lock, flags);
+ if (off > 0) {
+ task->buffered_data_size += off;
+ task->data_offset += off;
+ }
+ spin_unlock_irqrestore(&task->lock, flags);
+ if (off > 0)
+ return off;
+ else
+ return ret;
+}
+
+static int do_write_work_in(struct threadrw_write_task *task)
+{
+ struct threadrw_buf *rwbuf = NULL;
+ int ret;
+ int need_re_write = 0;
+ int write_len = 0;
+ unsigned long flags;
+
+ if (kfifo_is_empty(&task->datafifo))
+ return 0;
+ if (!kfifo_peek(&task->datafifo, (void *)&rwbuf))
+ return 0;
+ if (!task->manual_write &&
+ rwbuf->from_cma &&
+ !rwbuf->write_off)
+ codec_mm_dma_flush(rwbuf->vbuffer,
+ rwbuf->buffer_size,
+ DMA_TO_DEVICE);
+ if (task->manual_write) {
+ ret = task->write(task->file, task->sbuf,
+ (const char __user *)rwbuf->vbuffer + rwbuf->write_off,
+ rwbuf->data_size,
+ 2); /* noblock,virtual addr */
+ } else {
+ ret = task->write(task->file, task->sbuf,
+ (const char __user *)rwbuf->dma_handle + rwbuf->write_off,
+ rwbuf->data_size,
+ 3); /* noblock,phy addr */
+ }
+ if (ret == -EAGAIN) {
+ need_re_write = 0;
+ /*do later retry. */
+ } else if (ret >= rwbuf->data_size) {
+ write_len += rwbuf->data_size;
+ if (kfifo_get(&task->datafifo, (void *)&rwbuf)) {
+ rwbuf->data_size = 0;
+ kfifo_put(&task->freefifo, (const void *)rwbuf);
+ /*wakeup write thread. */
+ wake_up_interruptible(&task->wq);
+ } else
+ pr_err("write ok,but kfifo_get data failed.!!!\n");
+ need_re_write = 1;
+ } else if (ret > 0) {
+ rwbuf->data_size -= ret; /* half data write */
+ rwbuf->write_off += ret;
+ write_len += ret;
+ need_re_write = 1;
+ } else { /*ret <=0 */
+ pr_err("get errors ret=%d size=%d\n", ret,
+ rwbuf->data_size);
+ task->errors = ret;
+ }
+ if (write_len > 0) {
+ spin_lock_irqsave(&task->lock, flags);
+ task->passed_data_len += write_len;
+ spin_unlock_irqrestore(&task->lock, flags);
+ }
+ return need_re_write;
+
+}
+
+static void do_write_work(struct work_struct *work)
+{
+ struct threadrw_write_task *task = container_of(work,
+ struct threadrw_write_task,
+ write_work.work);
+ int need_retry = 1;
+
+ task->writework_on = 1;
+ while (need_retry) {
+ mutex_lock(&task->mutex);
+ need_retry = do_write_work_in(task);
+ mutex_unlock(&task->mutex);
+ }
+ threadrw_schedule_delayed_work(task, HZ / 10);
+ task->writework_on = 0;
+}
+
+static int alloc_task_buffers_inlock(struct threadrw_write_task *task,
+ int new_bubffers,
+ int block_size)
+{
+ struct threadrw_buf *rwbuf;
+ int i;
+ int used_codec_mm = task->manual_write ? 0 : 1;
+ int new_num = new_bubffers;
+ int mm_slot = -1;
+ int start_idx = task->bufs_num;
+ int total_mm = 0;
+ unsigned long addr;
+
+ if (codec_mm_get_total_size() < 80 ||
+ codec_mm_get_free_size() < 40)
+ used_codec_mm = 0;
+ if (task->bufs_num + new_num > task->max_bufs)
+ new_num = task->max_bufs - task->bufs_num;
+ for (i = 0; i < MAX_MM_BUFFER_NUM; i++) {
+ if (task->codec_mm_buffer[i] == 0) {
+ mm_slot = i;
+ break;
+ }
+ }
+ if (mm_slot < 0)
+ used_codec_mm = 0;
+ if (block_size <= 0)
+ block_size = DEFAULT_BLOCK_SIZE;
+
+ if (used_codec_mm && (block_size * new_num) >= 128 * 1024) {
+ total_mm = ALIGN(block_size * new_num, (1 << 17));
+ addr =
+ codec_mm_alloc_for_dma(BUF_NAME,
+ total_mm / PAGE_SIZE, 0,
+ CODEC_MM_FLAGS_DMA_CPU);
+ if (addr != 0) {
+ task->codec_mm_buffer[mm_slot] = addr;
+ task->buffer_size += total_mm;
+ } else {
+ used_codec_mm = 0;
+ }
+ }
+ for (i = 0; i < new_num; i++) {
+ int bufidx = start_idx + i;
+
+ rwbuf = &task->buf[bufidx];
+ rwbuf->buffer_size = block_size;
+ if (used_codec_mm) {
+ unsigned long start_addr =
+ task->codec_mm_buffer[mm_slot];
+ if (i == new_num - 1)
+ rwbuf->buffer_size = total_mm -
+ block_size * i;
+ rwbuf->dma_handle = (dma_addr_t) start_addr +
+ block_size * i;
+ rwbuf->vbuffer = codec_mm_phys_to_virt(
+ rwbuf->dma_handle);
+ rwbuf->from_cma = 1;
+
+ } else {
+ rwbuf->vbuffer = dma_alloc_coherent(
+ amports_get_dma_device(),
+ rwbuf->buffer_size,
+ &rwbuf->dma_handle, GFP_KERNEL);
+ if (!rwbuf->vbuffer) {
+ rwbuf->buffer_size = 0;
+ rwbuf->dma_handle = 0;
+ task->bufs_num = bufidx;
+ break;
+ }
+ rwbuf->from_cma = 0;
+ task->buffer_size += rwbuf->buffer_size;
+ }
+
+ kfifo_put(&task->freefifo, (const void *)rwbuf);
+ task->bufs_num = bufidx + 1;
+ }
+ if (start_idx > 0 ||/*have buffers before*/
+ task->bufs_num >= 3 ||
+ task->bufs_num == new_num) {
+ if (!task->def_block_size)
+ task->def_block_size = task->buf[0].buffer_size;
+ return 0; /*must >=3 for swap buffers. */
+ }
+ if (task->bufs_num > 0)
+ free_task_buffers(task);
+ return -1;
+}
+
+static int free_task_buffers(struct threadrw_write_task *task)
+{
+ int i;
+
+ for (i = 0; i < MAX_MM_BUFFER_NUM; i++) {
+ if (task->codec_mm_buffer[i])
+ codec_mm_free_for_dma(BUF_NAME,
+ task->codec_mm_buffer[i]);
+ }
+ for (i = 0; i < task->bufs_num; i++) {
+ if (task->buf[i].vbuffer && task->buf[i].from_cma == 0)
+ dma_free_coherent(amports_get_dma_device(),
+ task->buf[i].buffer_size,
+ task->buf[i].vbuffer,
+ task->buf[i].dma_handle);
+ }
+ return 0;
+}
+
+static struct threadrw_write_task *threadrw_alloc_in(int num,
+ int block_size,
+ ssize_t (*write)(struct file *,
+ struct stream_buf_s *,
+ const char __user *, size_t, int),
+ int flags)
+{
+ int max_bufs = num;
+ int task_buffer_size;
+ struct threadrw_write_task *task;
+ int ret;
+
+ if (!(flags & 1)) /*not audio*/
+ max_bufs = 300; /*can great for video bufs.*/
+ task_buffer_size = sizeof(struct threadrw_write_task) +
+ sizeof(struct threadrw_buf) * max_bufs;
+ task = vmalloc(task_buffer_size);
+
+ if (!task)
+ return NULL;
+ memset(task, 0, task_buffer_size);
+
+ spin_lock_init(&task->lock);
+ mutex_init(&task->mutex);
+ INIT_DELAYED_WORK(&task->write_work, do_write_work);
+ init_waitqueue_head(&task->wq);
+ ret = kfifo_alloc(&task->datafifo, max_bufs, GFP_KERNEL);
+ if (ret)
+ goto err1;
+ ret = kfifo_alloc(&task->freefifo, max_bufs, GFP_KERNEL);
+ if (ret)
+ goto err2;
+ task->write = write;
+ task->file = NULL;
+ task->buffer_size = 0;
+ task->manual_write = flags & 1;
+ task->max_bufs = max_bufs;
+ mutex_lock(&task->mutex);
+ ret = alloc_task_buffers_inlock(task, num, block_size);
+ mutex_unlock(&task->mutex);
+ if (ret < 0)
+ goto err3;
+ threadrw_wq_get(); /*start thread. */
+ return task;
+
+err3:
+ kfifo_free(&task->freefifo);
+err2:
+ kfifo_free(&task->datafifo);
+err1:
+ vfree(task);
+ pr_err("alloc threadrw failed num:%d,block:%d\n", num, block_size);
+ return NULL;
+}
+
+/*
+ *fifo data size;
+ */
+
+void threadrw_update_buffer_level(struct stream_buf_s *stbuf,
+ int parsed_size)
+{
+ struct threadrw_write_task *task = stbuf->write_thread;
+ unsigned long flags;
+
+ if (task)
+ {
+ spin_lock_irqsave(&task->lock, flags);
+ task->buffered_data_size -= parsed_size;
+ spin_unlock_irqrestore(&task->lock, flags);
+ }
+
+}
+EXPORT_SYMBOL(threadrw_update_buffer_level);
+
+int threadrw_buffer_level(struct stream_buf_s *stbuf)
+{
+ struct threadrw_write_task *task = stbuf->write_thread;
+
+ if (task)
+ return task->buffered_data_size;
+ return 0;
+}
+
+int threadrw_buffer_size(struct stream_buf_s *stbuf)
+{
+ struct threadrw_write_task *task = stbuf->write_thread;
+
+ if (task)
+ return task->buffer_size;
+ return 0;
+}
+
+int threadrw_datafifo_len(struct stream_buf_s *stbuf)
+{
+ struct threadrw_write_task *task = stbuf->write_thread;
+
+ if (task)
+ return kfifo_len(&task->datafifo);
+ return 0;
+}
+
+int threadrw_freefifo_len(struct stream_buf_s *stbuf)
+{
+ struct threadrw_write_task *task = stbuf->write_thread;
+
+ if (task)
+ return kfifo_len(&task->freefifo);
+ return 0;
+}
+int threadrw_support_more_buffers(struct stream_buf_s *stbuf)
+{
+ struct threadrw_write_task *task = stbuf->write_thread;
+
+ if (!task)
+ return 0;
+ if (task->failed_onmore)
+ return 0;
+ return task->max_bufs - task->bufs_num;
+}
+
+/*
+ *data len out fifo;
+ */
+int threadrw_passed_len(struct stream_buf_s *stbuf)
+{
+ struct threadrw_write_task *task = stbuf->write_thread;
+
+ if (task)
+ return task->passed_data_len;
+ return 0;
+
+}
+/*
+ *all data writed.;
+ */
+int threadrw_dataoffset(struct stream_buf_s *stbuf)
+{
+ struct threadrw_write_task *task = stbuf->write_thread;
+ int offset = 0;
+
+ if (task)
+ return task->data_offset;
+ return offset;
+
+}
+
+ssize_t threadrw_write(struct file *file, struct stream_buf_s *stbuf,
+ const char __user *buf, size_t count)
+{
+ struct threadrw_write_task *task = stbuf->write_thread;
+ ssize_t size;
+
+ if (!task->file) {
+ task->file = file;
+ task->sbuf = stbuf;
+ }
+ mutex_lock(&task->mutex);
+ size = threadrw_write_in(task, stbuf, buf, count);
+ mutex_unlock(&task->mutex);
+ return size;
+}
+
+int threadrw_flush_buffers(struct stream_buf_s *stbuf)
+{
+ struct threadrw_write_task *task = stbuf->write_thread;
+ int max_retry = 20;
+
+ if (!task)
+ return 0;
+ while (!kfifo_is_empty(&task->datafifo) && max_retry-- > 0) {
+ threadrw_schedule_delayed_work(task, 0);
+ msleep(20);
+ }
+ if (!kfifo_is_empty(&task->datafifo))
+ return -1;/*data not flushed*/
+ return 0;
+}
+int threadrw_alloc_more_buffer_size(
+ struct stream_buf_s *stbuf,
+ int size)
+{
+ struct threadrw_write_task *task = stbuf->write_thread;
+ int block_size;
+ int new_num;
+ int ret = -1;
+ int old_num;
+
+ if (!task)
+ return -1;
+ mutex_lock(&task->mutex);
+ block_size = task->def_block_size;
+ if (block_size == 0)
+ block_size = 32 * 1024;
+ new_num = size / block_size;
+ old_num = task->bufs_num;
+ if (new_num == 0)
+ new_num = 1;
+ else if (new_num > task->max_bufs - task->bufs_num)
+ new_num = task->max_bufs - task->bufs_num;
+ if (new_num != 0)
+ ret = alloc_task_buffers_inlock(task, new_num,
+ block_size);
+ mutex_unlock(&task->mutex);
+ pr_info("threadrw add more buffer from %d -> %d for size %d\n",
+ old_num, task->bufs_num,
+ size);
+ if (ret < 0 || old_num == task->bufs_num)
+ task->failed_onmore = 1;
+ return ret;
+}
+
+void *threadrw_alloc(int num,
+ int block_size,
+ ssize_t (*write)(struct file *,
+ struct stream_buf_s *,
+ const char __user *,
+ size_t, int),
+ int flags)
+{
+ return threadrw_alloc_in(num, block_size, write, flags);
+}
+
+void threadrw_release(struct stream_buf_s *stbuf)
+{
+ struct threadrw_write_task *task = stbuf->write_thread;
+
+ if (task) {
+ wake_up_interruptible(&task->wq);
+ cancel_delayed_work_sync(&task->write_work);
+ mutex_lock(&task->mutex);
+ free_task_buffers(task);
+ mutex_unlock(&task->mutex);
+ kfifo_free(&task->freefifo);
+ kfifo_free(&task->datafifo);
+ vfree(task);
+ }
+ stbuf->write_thread = NULL;
+}
diff --git a/drivers/stream_input/amports/thread_rw.h b/drivers/stream_input/amports/thread_rw.h
new file mode 100644
index 0000000..4a93dee
--- /dev/null
+++ b/drivers/stream_input/amports/thread_rw.h
@@ -0,0 +1,53 @@
+/*
+ * drivers/amlogic/media/stream_input/parser/thread_rw.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 THREAD_RW_H
+#define THREAD_RW_H
+#include "../../stream_input/amports/streambuf_reg.h"
+#include "../../stream_input/amports/streambuf.h"
+#include "../../stream_input/parser/esparser.h"
+#include "../../stream_input/amports/amports_priv.h"
+
+ssize_t threadrw_write(struct file *file,
+ struct stream_buf_s *stbuf,
+ const char __user *buf,
+ size_t count);
+
+void *threadrw_alloc(int num,
+ int block_size,
+ ssize_t (*write)(struct file *,
+ struct stream_buf_s *,
+ const char __user *,
+ size_t, int),
+ int flags);/*flags &1: manual mode*/
+
+void threadrw_release(struct stream_buf_s *stbuf);
+
+int threadrw_buffer_level(struct stream_buf_s *stbuf);
+int threadrw_buffer_size(struct stream_buf_s *stbuf);
+int threadrw_datafifo_len(struct stream_buf_s *stbuf);
+int threadrw_freefifo_len(struct stream_buf_s *stbuf);
+int threadrw_passed_len(struct stream_buf_s *stbuf);
+int threadrw_flush_buffers(struct stream_buf_s *stbuf);
+int threadrw_dataoffset(struct stream_buf_s *stbuf);
+int threadrw_alloc_more_buffer_size(
+ struct stream_buf_s *stbuf,
+ int size);
+int threadrw_support_more_buffers(struct stream_buf_s *stbuf);
+void threadrw_update_buffer_level(struct stream_buf_s *stbuf,
+ int parsed_size);
+#endif
diff --git a/drivers/stream_input/parser/dvb_ci/Makefile b/drivers/stream_input/parser/dvb_ci/Makefile
new file mode 100644
index 0000000..25cdcb9
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/Makefile
@@ -0,0 +1,16 @@
+obj-m += ci.o cimax-usb.o
+
+ci-objs = $(amlci-objs) $(cimcu-objs) $(cimax-objs)
+
+amlci-objs = aml_pcmcia.o aml_ci.o aml_spi.o
+cimcu-objs = cimcu/dvb_ca_en50221_cimcu.o
+cimax-objs = cimax/dvb_ca_en50221_cimax.o cimax/aml_cimax.o cimax/dvb_ringbuffer.o
+cimax-usb-objs += cimax/usb/SRC/cimax+usb-driver.o cimax/usb/SRC/cimax+usb_fw.o
+cimax-usb-objs += cimax/usb/SRC/cimax+usb_config.o
+cimax-objs += cimax/aml_cimax_usb.o
+
+ccflags-y += -I$(srctree)/
+ccflags-y += -I$(srctree)/include
+ccflags-y += -I$(srctree)/drivers/gpio
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
+
diff --git a/drivers/stream_input/parser/dvb_ci/aml_ci.c b/drivers/stream_input/parser/dvb_ci/aml_ci.c
new file mode 100644
index 0000000..d457a05
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/aml_ci.c
@@ -0,0 +1,767 @@
+/*
+* 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/init.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include "aml_ci.h"
+#include "aml_spi.h"
+#include "cimax/aml_cimax.h"
+
+//#include "dvb_ca_en50221.h"
+#include <dvbdev.h>
+
+MODULE_PARM_DESC(aml_ci_debug, "\n\t\t dvb ci debug");
+static int aml_ci_debug = 1;
+module_param(aml_ci_debug, int, S_IRUGO);
+
+#define pr_dbg(args...)\
+ do {\
+ if (aml_ci_debug)\
+ printk(args);\
+ } while (0)
+#define pr_error(fmt, args...) printk("DVBCI: " fmt, ## args)
+
+
+extern struct dvb_adapter *aml_get_dvb_adapter(void);
+/**\brief aml_ci_mem_read:mem read from cam
+ * \param en50221: en50221 obj,used this data to get dvb_ci obj
+ * \param slot: slot index
+ * \param addr: read addr
+ * \return
+ * - read value:ok
+ * - -EINVAL : error
+ */
+static int aml_ci_mem_read(struct dvb_ca_en50221_cimcu *en50221, int slot, int addr)
+{
+ struct aml_ci *ci = en50221->data;
+
+ if (slot != 0) {
+ pr_error("slot !=0 %s :%d\r\n", __func__, slot);
+ return -EINVAL;
+ }
+
+ if (ci->ci_mem_read != NULL)
+ return ci->ci_mem_read(ci, slot, addr);
+
+ pr_error("ci_mem_read is null %s\r\n", __func__);
+ return -EINVAL;
+}
+/**\brief aml_ci_mem_write:mem write to cam
+ * \param en50221: en50221 obj,used this data to get dvb_ci obj
+ * \param slot: slot index
+ * \param addr: write addr
+ * \param addr: write value
+ * \return
+ * - 0:ok
+ * - -EINVAL : error
+ */
+static int aml_ci_mem_write(struct dvb_ca_en50221_cimcu *en50221,
+ int slot, int addr, u8 data)
+{
+
+ struct aml_ci *ci = en50221->data;
+
+ if (slot != 0) {
+ pr_error("slot not 0 %s :%d\r\n", __func__, slot);
+ return -EINVAL;
+ }
+
+ if (ci->ci_mem_write != NULL)
+ return ci->ci_mem_write(ci, slot, addr, data);
+ pr_error("ci_mem_write is null %s\r\n", __func__);
+ return -EINVAL;
+}
+/**\brief aml_ci_io_read:io read from cam
+ * \param en50221: en50221 obj,used this data to get dvb_ci obj
+ * \param slot: slot index
+ * \param addr: read addr
+ * \return
+ * - read value:ok
+ * - -EINVAL : error
+ */
+static int aml_ci_io_read(struct dvb_ca_en50221_cimcu *en50221, int slot, u8 addr)
+{
+ struct aml_ci *ci = en50221->data;
+
+ if (slot != 0) {
+ pr_error("slot !=0 %s :%d\r\n", __func__, slot);
+ return -EINVAL;
+ }
+
+ if (ci->ci_io_read != NULL)
+ return ci->ci_io_read(ci, slot, addr);
+
+ pr_error("ci_io_read is null %s\r\n", __func__);
+ return -EINVAL;
+}
+/**\brief aml_ci_io_write:io write to cam
+ * \param en50221: en50221 obj,used this data to get dvb_ci obj
+ * \param slot: slot index
+ * \param addr: write addr
+ * \param addr: write value
+ * \return
+ * - 0:ok
+ * - -EINVAL : error
+ */
+static int aml_ci_io_write(struct dvb_ca_en50221_cimcu *en50221,
+ int slot, u8 addr, u8 data)
+{
+ struct aml_ci *ci = en50221->data;
+
+ if (slot != 0) {
+ pr_error("slot !=0 %s :%d\r\n", __func__, slot);
+ return -EINVAL;
+ }
+
+ if (ci->ci_mem_write != NULL)
+ return ci->ci_io_write(ci, slot, addr, data);
+
+ pr_error("ci_io_write is null %s\r\n", __func__);
+ return -EINVAL;
+}
+/**\brief aml_ci_slot_reset:reset slot
+ * \param en50221: en50221 obj,used this data to get dvb_ci obj
+ * \param slot: slot index
+ * \return
+ * - 0:ok
+ * - -EINVAL : error
+ */
+static int aml_ci_slot_reset(struct dvb_ca_en50221_cimcu *en50221, int slot)
+{
+ struct aml_ci *ci = en50221->data;
+ pr_dbg("Slot(%d): Slot RESET\n", slot);
+ if (ci->ci_slot_reset != NULL) {
+ ci->ci_slot_reset(ci, slot);
+ } else {
+ pr_error("ci_slot_reset is null %s\r\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+/**\brief aml_ci_slot_shutdown:show slot
+ * \param en50221: en50221 obj,used this data to get dvb_ci obj
+ * \param slot: slot index
+ * \return
+ * - 0:ok
+ * - -EINVAL : error
+ */
+static int aml_ci_slot_shutdown(struct dvb_ca_en50221_cimcu *en50221, int slot)
+{
+ struct aml_ci *ci = en50221->data;
+ pr_dbg("Slot(%d): Slot shutdown\n", slot);
+ if (ci->ci_slot_shutdown != NULL) {
+ ci->ci_slot_shutdown(ci, slot);
+ } else {
+ pr_error("aml_ci_slot_shutdown is null %s\r\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+/**\brief aml_ci_ts_control:control slot ts
+ * \param en50221: en50221 obj,used this data to get dvb_ci obj
+ * \param slot: slot index
+ * \return
+ * - 0:ok
+ * - -EINVAL : error
+ */
+static int aml_ci_ts_control(struct dvb_ca_en50221_cimcu *en50221, int slot)
+{
+
+ struct aml_ci *ci = en50221->data;
+ pr_dbg("Slot(%d): TS control\n", slot);
+ if (ci->ci_slot_ts_enable != NULL) {
+ ci->ci_slot_ts_enable(ci, slot);
+ } else {
+ pr_error("aml_ci_ts_control is null %s\r\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+/**\brief aml_ci_slot_status:get slot status
+ * \param en50221: en50221 obj,used this data to get dvb_ci obj
+ * \param slot: slot index
+ * \param open: no used
+ * \return
+ * - cam status
+ * - -EINVAL : error
+ */
+static int aml_ci_slot_status(struct dvb_ca_en50221_cimcu *en50221,
+ int slot, int open)
+{
+ struct aml_ci *ci = en50221->data;
+
+ pr_dbg("Slot(%d): Poll Slot status\n", slot);
+
+ if (ci->ci_poll_slot_status != NULL) {
+ return ci->ci_poll_slot_status(ci, slot, open);
+ } else {
+ /*pr_error("ci_poll_slot_status is null %s\r\n", __func__);*/
+ }
+
+ return 0;
+}
+static int aml_ci_cimax_slot_reset(struct dvb_ca_en50221_cimax *en50221,
+ int slot)
+{
+ struct aml_ci *ci = en50221->data;
+ pr_dbg("Slot(%d): Slot RESET\n", slot);
+ if (ci->ci_slot_reset != NULL) {
+ ci->ci_slot_reset(ci, slot);
+ } else {
+ pr_error("ci_slot_reset is null %s\r\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+/**\brief aml_ci_slot_shutdown:show slot
+ * \param en50221: en50221 obj,used this data to get dvb_ci obj
+ * \param slot: slot index
+ * \return
+ * - 0:ok
+ * - -EINVAL : error
+ */
+static int aml_ci_cimax_slot_shutdown(struct dvb_ca_en50221_cimax *en50221,
+ int slot)
+{
+ struct aml_ci *ci = en50221->data;
+ pr_dbg("Slot(%d): Slot shutdown\n", slot);
+ if (ci->ci_slot_shutdown != NULL) {
+ ci->ci_slot_shutdown(ci, slot);
+ } else {
+ pr_error("aml_ci_slot_shutdown is null %s\r\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+/**\brief aml_ci_ts_control:control slot ts
+ * \param en50221: en50221 obj,used this data to get dvb_ci obj
+ * \param slot: slot index
+ * \return
+ * - 0:ok
+ * - -EINVAL : error
+ */
+static int aml_ci_cimax_ts_control(struct dvb_ca_en50221_cimax *en50221,
+ int slot)
+{
+
+ struct aml_ci *ci = en50221->data;
+ pr_dbg("Slot(%d): TS control\n", slot);
+ if (ci->ci_slot_ts_enable != NULL) {
+ ci->ci_slot_ts_enable(ci, slot);
+ } else {
+ pr_error("aml_ci_ts_control is null %s\r\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+/**\brief aml_ci_cimax_slot_status:get slot status
+ * \param en50221: en50221_cimax obj,used this data to get dvb_ci obj
+ * \param slot: slot index
+ * \param open: no used
+ * \return
+ * - cam status
+ * - -EINVAL : error
+ */
+static int aml_ci_cimax_slot_status(
+ struct dvb_ca_en50221_cimax *en50221, int slot, int open)
+{
+ struct aml_ci *ci = en50221->data;
+
+ /*pr_dbg("Slot(%d): Poll Slot status\n", slot);*/
+
+ if (ci->ci_poll_slot_status != NULL) {
+ return ci->ci_poll_slot_status(ci, slot, open);
+ } else {
+ /*pr_error("ci_poll_slot_status is null %s\r\n", __func__);*/
+ }
+
+ return 0;
+}
+
+/**\brief aml_ci_read_cis: read cis
+ * \param en50221_max: en50221 obj,used this data to get dvb_ci obj
+ * \param slot: slot index
+ * \param buf: buf for cis data
+ * \param size: buf size
+ * \return
+ * --EINVAL : error
+ * - : actual size read
+ */
+static int aml_ci_read_cis(struct dvb_ca_en50221_cimax *en50221,
+ int slot, u8 *buf, int size)
+{
+ struct aml_ci *ci = en50221->data;
+
+ if (slot != 0) {
+ pr_error("slot !=0 %s :%d\r\n", __func__, slot);
+ return -EINVAL;
+ }
+
+ if (ci->ci_read_cis != NULL)
+ return ci->ci_read_cis(ci, slot, buf, size);
+
+ pr_error("ci_read_cis is null %s\r\n", __func__);
+ return -EINVAL;
+}
+/**\brief aml_ci_write_cor: write cor
+ * \param en50221_max: en50221 obj,used this data to get dvb_ci obj
+ * \param slot: slot index
+ * \param addr:
+ * \param buf:
+ * \return
+ * --EINVAL : error
+ * -0 : ok
+ */
+static int aml_ci_write_cor(struct dvb_ca_en50221_cimax *en50221,
+ int slot, int address, u8 *buf)
+{
+ struct aml_ci *ci = en50221->data;
+
+ if (slot != 0) {
+ pr_error("slot !=0 %s :%d\r\n", __func__, slot);
+ return -EINVAL;
+ }
+
+ if (ci->ci_write_cor != NULL)
+ return ci->ci_write_cor(ci, slot, address, buf);
+
+ pr_error("ci_write_cor is null %s\r\n", __func__);
+ return -EINVAL;
+}
+/**\brief aml_ci_negociate: negotiate
+ * \param en50221_max: en50221 obj,used this data to get dvb_ci obj
+ * \param slot: slot index
+ * \param size: suggested size
+ * \return
+ * --EINVAL : error
+ * - : size negotiated
+ */
+static int aml_ci_negotiate(struct dvb_ca_en50221_cimax *en50221,
+ int slot, int size)
+{
+ struct aml_ci *ci = en50221->data;
+
+ if (slot != 0) {
+ pr_error("slot !=0 %s :%d\r\n", __func__, slot);
+ return -EINVAL;
+ }
+
+ if (ci->ci_negotiate != NULL)
+ return ci->ci_negotiate(ci, slot, size);
+
+ pr_error("ci_negotiate is null %s\r\n", __func__);
+ return -EINVAL;
+}
+/**\brief aml_ci_read_lpdu: read lpdu
+ * \param en50221_max: en50221 obj,used this data to get dvb_ci obj
+ * \param slot: slot index
+ * \param buf: buf
+ * \param size: buf size
+ * \return
+ * --EINVAL : error
+ * - : size read
+ */
+static int aml_ci_read_lpdu(struct dvb_ca_en50221_cimax *en50221,
+ int slot, u8 *buf, int size)
+{
+ struct aml_ci *ci = en50221->data;
+
+ if (slot != 0) {
+ pr_error("slot !=0 %s :%d\r\n", __func__, slot);
+ return -EINVAL;
+ }
+
+ if (ci->ci_read_lpdu != NULL)
+ return ci->ci_read_lpdu(ci, slot, buf, size);
+
+ pr_error("ci_read_lpdu is null %s\r\n", __func__);
+ return -EINVAL;
+}
+
+/**\brief aml_ci_write_lpdu: write lpdu
+ * \param en50221_max: en50221 obj,used this data to get dvb_ci obj
+ * \param slot: slot index
+ * \param buf: buf
+ * \param size: write size
+ * \return
+ * --EINVAL : error
+ * - : size written
+ */
+static int aml_ci_write_lpdu(struct dvb_ca_en50221_cimax *en50221,
+ int slot, u8 *buf, int size)
+{
+ struct aml_ci *ci = en50221->data;
+
+ if (slot != 0) {
+ pr_error("slot !=0 %s :%d\r\n", __func__, slot);
+ return -EINVAL;
+ }
+
+ if (ci->ci_write_lpdu != NULL)
+ return ci->ci_write_lpdu(ci, slot, buf, size);
+
+ pr_error("ci_write_lpdu is null %s\r\n", __func__);
+ return -EINVAL;
+}
+
+static int aml_ci_read_cam_status(struct dvb_ca_en50221_cimax *en50221,
+ int slot)
+{
+ struct aml_ci *ci = en50221->data;
+
+ if (slot != 0) {
+ pr_error("slot !=0 %s :%d\r\n", __func__, slot);
+ return -EINVAL;
+ }
+
+ if (ci->ci_read_cam_status != NULL)
+ return ci->ci_read_cam_status(ci, slot);
+
+ pr_error("ci_read_cam_status is null %s\r\n", __func__);
+ return -EINVAL;
+}
+
+static int aml_ci_cam_reset(struct dvb_ca_en50221_cimax *en50221, int slot)
+{
+ struct aml_ci *ci = en50221->data;
+
+ if (slot != 0) {
+ pr_error("slot !=0 %s :%d\r\n", __func__, slot);
+ return -EINVAL;
+ }
+
+ if (ci->ci_cam_reset != NULL)
+ return ci->ci_cam_reset(ci, slot);
+
+ pr_error("ci_cam_reset is null %s\r\n", __func__);
+ return -EINVAL;
+}
+
+/**\brief aml_ci_get_capbility
+ * \param en50221_max: en50221 obj,used this data to get dvb_ci obj
+ * \param slot: slot index
+ * \return
+ * - : capbilities
+ */
+static int aml_ci_get_capbility(struct dvb_ca_en50221_cimax *en50221, int slot)
+{
+ struct aml_ci *ci = en50221->data;
+
+ if (slot != 0) {
+ pr_error("slot !=0 %s :%d\r\n", __func__, slot);
+ return 0;
+ }
+
+ if (ci->ci_get_capbility != NULL)
+ return ci->ci_get_capbility(ci, slot);
+
+ pr_error("ci_get_capbility is null %s\r\n", __func__);
+ return 0;
+}
+
+
+/**\brief get ci config from dts
+ * \param np: device node
+ * \return
+ * - 0 成功
+ * - 其他值 :
+ */
+static int aml_ci_get_config_from_dts(struct platform_device *pdev,
+ struct aml_ci *ci)
+{
+ char buf[32];
+ int ret = 0;
+ int value;
+
+ snprintf(buf, sizeof(buf), "%s", "io_type");
+ ret = of_property_read_u32(pdev->dev.of_node, buf, &value);
+ if (!ret) {
+ pr_dbg("%s: 0x%x\n", buf, value);
+ ci->io_type = value;
+ }
+ return 0;
+}
+
+/**\brief aml_ci_init:ci dev init
+ * \param pdev: platform_device device node,used to get dts info
+ * \param dvb: aml_dvb obj,used to get dvb_adapter for en0211 to use
+ * \param cip: ci_dev pp
+ * \return
+ * - 0 成功
+ * - 其他值 :
+ */
+int aml_ci_init(struct platform_device *pdev,
+ struct dvb_adapter *dvb_adapter, struct aml_ci **cip)
+{
+ struct aml_ci *ci = NULL;
+ int ca_flags = 0, result;
+
+ ci = kzalloc(sizeof(struct aml_ci), GFP_KERNEL);
+ if (!ci) {
+ pr_error("Out of memory!, exiting ..\n");
+ result = -ENOMEM;
+ goto err;
+ }
+ ci->id = 0;
+ aml_ci_get_config_from_dts(pdev, ci);
+
+// ci->priv = dvb;
+ /* register CA interface */
+ if (ci->io_type == AML_DVB_IO_TYPE_CIMAX) {
+ ci->en50221_cimax.owner = THIS_MODULE;
+ ci->en50221_cimax.read_cis = aml_ci_read_cis;
+ ci->en50221_cimax.write_cor = aml_ci_write_cor;
+ ci->en50221_cimax.negotiate = aml_ci_negotiate;
+ ci->en50221_cimax.read_lpdu = aml_ci_read_lpdu;
+ ci->en50221_cimax.write_lpdu = aml_ci_write_lpdu;
+ ci->en50221_cimax.read_cam_status = aml_ci_read_cam_status;
+ ci->en50221_cimax.cam_reset = aml_ci_cam_reset;
+ ci->en50221_cimax.get_capbility = aml_ci_get_capbility;
+ ci->en50221_cimax.slot_reset = aml_ci_cimax_slot_reset;
+ ci->en50221_cimax.slot_shutdown = aml_ci_cimax_slot_shutdown;
+ ci->en50221_cimax.slot_ts_enable = aml_ci_cimax_ts_control;
+ ci->en50221_cimax.poll_slot_status = aml_ci_cimax_slot_status;
+ ci->en50221_cimax.data = ci;
+
+ pr_dbg("Registering EN50221 CIMAX device\n");
+ result = dvb_ca_en50221_cimax_init(dvb_adapter,
+ &ci->en50221_cimax, ca_flags, 1);
+ if (result != 0) {
+ pr_error("EN50221 CIMAX: Initialization failed <%d>\n",
+ result);
+ goto err;
+ }
+ } else {
+ ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE;
+ /* register CA interface */
+ ci->en50221_cimcu.owner = THIS_MODULE;
+ ci->en50221_cimcu.read_attribute_mem = aml_ci_mem_read;
+ ci->en50221_cimcu.write_attribute_mem = aml_ci_mem_write;
+ ci->en50221_cimcu.read_cam_control = aml_ci_io_read;
+ ci->en50221_cimcu.write_cam_control = aml_ci_io_write;
+ ci->en50221_cimcu.slot_reset = aml_ci_slot_reset;
+ ci->en50221_cimcu.slot_shutdown = aml_ci_slot_shutdown;
+ ci->en50221_cimcu.slot_ts_enable = aml_ci_ts_control;
+ ci->en50221_cimcu.poll_slot_status = aml_ci_slot_status;
+ ci->en50221_cimcu.data = ci;
+
+
+ pr_dbg("Registering EN50221 device\n");
+ result = dvb_ca_en50221_cimcu_init(dvb_adapter,
+ &ci->en50221_cimcu, ca_flags, 1);
+ if (result != 0) {
+ pr_error("EN50221_cimcu: Initialization failed <%d>\n",
+ result);
+ goto err;
+ }
+ }
+ *cip = ci;
+ pr_dbg("Registered EN50221 device\n");
+
+ if (ci->io_type == AML_DVB_IO_TYPE_SPI || ci->io_type == AML_DVB_IO_TYPE_SPI_T312) {
+ /* spi init */
+ ci->ci_init = aml_spi_init;
+ ci->ci_exit = aml_spi_exit;
+ } else if (ci->io_type == AML_DVB_IO_TYPE_CIMAX) {
+ ci->ci_init = aml_cimax_init;
+ ci->ci_exit = aml_cimax_exit;
+ } else {
+ /* no io dev init,is error */
+ pr_dbg("unknown io type, please check io_type in dts file\r\n");
+ }
+
+ if (ci->ci_init)
+ result = ci->ci_init(pdev, ci);
+ if (ci->io_type == AML_DVB_IO_TYPE_CIMAX) {
+ if (result)
+ dvb_ca_en50221_cimax_release(&ci->en50221_cimax);
+ }
+ return result;
+err:
+ kfree(ci);
+ return result;
+}
+
+void aml_ci_exit(struct aml_ci *ci)
+{
+ pr_dbg("Unregistering EN50221 device\n");
+ if (ci) {
+ if (ci->io_type == AML_DVB_IO_TYPE_CIMAX)
+ dvb_ca_en50221_cimax_release(&ci->en50221_cimax);
+ else
+ dvb_ca_en50221_cimcu_release(&ci->en50221_cimcu);
+ if (ci->ci_exit)
+ ci->ci_exit(ci);
+ kfree(ci);
+ }
+}
+
+static struct aml_ci *ci_dev;
+
+static ssize_t aml_ci_ts_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ int ret;
+ ret = sprintf(buf, "ts%d\n", 1);
+ return ret;
+}
+
+static struct class_attribute amlci_class_attrs[] = {
+ __ATTR(ts, S_IRUGO | S_IWUSR, aml_ci_ts_show, NULL),
+ __ATTR_NULL
+};
+
+static int aml_ci_register_class(struct aml_ci *ci)
+{
+ #define CLASS_NAME_LEN 48
+ int ret;
+ struct class *clp;
+
+ clp = &(ci->class);
+
+ clp->name = kzalloc(CLASS_NAME_LEN, GFP_KERNEL);
+ if (!clp->name)
+ return -ENOMEM;
+
+ snprintf((char *)clp->name, CLASS_NAME_LEN, "amlci-%d", ci->id);
+ clp->owner = THIS_MODULE;
+ clp->class_attrs = amlci_class_attrs;
+ ret = class_register(clp);
+ if (ret)
+ kfree(clp->name);
+
+ return 0;
+}
+
+static int aml_ci_unregister_class(struct aml_ci *ci)
+{
+ class_unregister(&ci->class);
+ kzfree(ci->class.name);
+ return 0;
+}
+
+
+static int aml_ci_probe(struct platform_device *pdev)
+{
+ struct dvb_adapter *dvb_adapter = aml_get_dvb_adapter();
+ int err = 0;
+ pr_dbg("---Amlogic CI Init---\n");
+ err = aml_ci_init(pdev, dvb_adapter, &ci_dev);
+ if (err < 0)
+ return err;
+ platform_set_drvdata(pdev, ci_dev);
+ aml_ci_register_class(ci_dev);
+ if (ci_dev->io_type == AML_DVB_IO_TYPE_SPI ||
+ ci_dev->io_type == AML_DVB_IO_TYPE_SPI_T312)
+ aml_spi_mod_init();
+ return 0;
+}
+
+static int aml_ci_remove(struct platform_device *pdev)
+{
+ aml_ci_unregister_class(ci_dev);
+ platform_set_drvdata(pdev, NULL);
+ if (ci_dev->io_type == AML_DVB_IO_TYPE_SPI ||
+ ci_dev->io_type == AML_DVB_IO_TYPE_SPI_T312) {
+ aml_spi_exit(ci_dev);
+ aml_spi_mod_exit();
+ }
+ else if (ci_dev->io_type == AML_DVB_IO_TYPE_CIMAX)
+ aml_cimax_exit(ci_dev);
+ else
+ pr_dbg("---Amlogic CI remove unkown io type---\n");
+
+ aml_ci_exit(ci_dev);
+ return 0;
+}
+
+static int aml_ci_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ pr_dbg("Amlogic CI Suspend!\n");
+ if (ci_dev->io_type == AML_DVB_IO_TYPE_SPI ||
+ ci_dev->io_type == AML_DVB_IO_TYPE_SPI_T312) {
+ aml_spi_exit(ci_dev);
+ }
+ else if (ci_dev->io_type == AML_DVB_IO_TYPE_CIMAX)
+ aml_cimax_exit(ci_dev);
+ else
+ pr_dbg("---Amlogic CI remove unkown io type---\n");
+
+ return 0;
+}
+
+static int aml_ci_resume(struct platform_device *pdev)
+{
+ int err = 0;
+ pr_dbg("Amlogic CI Resume!\n");
+ if (ci_dev->io_type == AML_DVB_IO_TYPE_SPI ||
+ ci_dev->io_type == AML_DVB_IO_TYPE_SPI_T312) {
+ aml_spi_init(pdev, ci_dev);
+ }
+ else if (ci_dev->io_type == AML_DVB_IO_TYPE_CIMAX)
+ aml_cimax_init(pdev, ci_dev);
+ else
+ pr_dbg("---Amlogic CI remove unkown io type---\n");
+ return err;
+}
+
+static const struct of_device_id dvbci_dev_dt_match[] = {
+ {
+ .compatible = "amlogic, dvbci",
+ },
+ {},
+};
+
+
+
+static struct platform_driver aml_ci_driver = {
+ .probe = aml_ci_probe,
+ .remove = aml_ci_remove,
+ .suspend = aml_ci_suspend,
+ .resume = aml_ci_resume,
+ .driver = {
+ .name = "dvbci",
+ .of_match_table = dvbci_dev_dt_match,
+ .owner = THIS_MODULE,
+ }
+};
+
+static int aml_ci_mod_init(void)
+{
+ pr_dbg("Amlogic CI mode init\n");
+ return platform_driver_register(&aml_ci_driver);
+}
+
+static void aml_ci_mod_exit(void)
+{
+ pr_dbg("Amlogic CI mode Exit\n");
+ platform_driver_unregister(&aml_ci_driver);
+}
+
+module_init(aml_ci_mod_init);
+module_exit(aml_ci_mod_exit);
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/stream_input/parser/dvb_ci/aml_ci.h b/drivers/stream_input/parser/dvb_ci/aml_ci.h
new file mode 100644
index 0000000..9006b7e
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/aml_ci.h
@@ -0,0 +1,105 @@
+/*
+* 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_CI_H_
+#define __AML_CI_H_
+
+//#include "drivers/media/dvb-core/dvb_ca_en50221.h"
+#include "cimcu/dvb_ca_en50221_cimcu.h"
+#include "cimax/dvb_ca_en50221_cimax.h"
+#include <linux/platform_device.h>
+
+enum aml_dvb_io_type_e {
+ AML_DVB_IO_TYPE_IOBUS = 0,
+ AML_DVB_IO_TYPE_SPI,
+ AML_DVB_IO_TYPE_CIMAX,
+ AML_DVB_IO_TYPE_SPI_T312,
+ AML_DVB_IO_TYPE_MAX,
+};
+
+struct aml_ci {
+// struct dvb_ca_en50221 en50221;
+ struct dvb_ca_en50221_cimcu en50221_cimcu;
+ struct mutex ci_lock;
+ int io_type;
+ void *priv;
+ int id;
+ struct class class;
+
+ int (*ci_init)(struct platform_device *pdev, struct aml_ci *ci);
+ int (*ci_exit)(struct aml_ci *ci);
+
+ /* NOTE: the read_*, write_* and poll_slot_status functions will be
+ * called for different slots concurrently and need to use locks where
+ * and if appropriate. There will be no concurrent access to one slot.
+ */
+
+ /* functions for accessing attribute memory on the CAM */
+ int (*ci_mem_read)(struct aml_ci *ca, int slot, int address);
+ int (*ci_mem_write)(struct aml_ci *ca, int slot, int address, u8 value);
+
+ /* functions for accessing the control interface on the CAM */
+ int (*ci_io_read)(struct aml_ci *ca, int slot, int address);
+ int (*ci_io_write)(struct aml_ci *ca, int slot, int address, u8 value);
+
+ /* Functions for controlling slots */
+ int (*ci_slot_reset)(struct aml_ci *ca, int slot);
+ int (*ci_slot_shutdown)(struct aml_ci *ca, int slot);
+ int (*ci_slot_ts_enable)(struct aml_ci *ca, int slot);
+
+ /*
+ * Poll slot status.
+ * Only necessary if DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE is not set
+ */
+ int (*ci_poll_slot_status)(struct aml_ci *ca, int slot, int open);
+
+
+ struct dvb_ca_en50221_cimax en50221_cimax;
+
+ int (*ci_read_cis)(struct aml_ci *ca, int slot, u8 *buf, int size);
+ int (*ci_write_cor)(struct aml_ci *ca, int slot, int address, u8 *buf);
+ /*return the final size or -1 for error*/
+ int (*ci_negotiate)(struct aml_ci *ca, int slot, int size);
+
+ /* functions for accessing the control interface on the CAM */
+ int (*ci_read_lpdu)(struct aml_ci *ca, int slot, u8 *buf, int size);
+ int (*ci_write_lpdu)(struct aml_ci *ca, int slot, u8 *buf, int size);
+
+ int (*ci_get_capbility)(struct aml_ci *ca, int slot);
+
+ int (*ci_cam_reset)(struct aml_ci *ca, int slot);
+ int (*ci_read_cam_status)(struct aml_ci *ca, int slot);
+
+ /* private data, used by caller */
+ void *data;
+};
+
+struct ci_dev_config_s {
+ char name[20];
+ unsigned char type;
+ int cs_hold_delay;
+ int cs_clk_delay;
+};
+extern int aml_ci_init(struct platform_device *pdev,
+ struct dvb_adapter *dvb_adapter, struct aml_ci **cip);
+extern void aml_ci_exit(struct aml_ci *ci);
+
+#endif /* __AML_CI_H_ */
+
diff --git a/drivers/stream_input/parser/dvb_ci/aml_pcmcia.c b/drivers/stream_input/parser/dvb_ci/aml_pcmcia.c
new file mode 100644
index 0000000..e84f376
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/aml_pcmcia.c
@@ -0,0 +1,251 @@
+/*
+* 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/sched.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+
+#include "aml_pcmcia.h"
+#include "aml_ci.h"
+
+static int aml_pcmcia_debug = 1;
+
+module_param_named(pcmcia_debug, aml_pcmcia_debug, int, 0644);
+MODULE_PARM_DESC(pcmcia_debug, "enable verbose debug messages");
+
+#define pr_dbg(args...)\
+ do {\
+ if (aml_pcmcia_debug)\
+ printk(args);\
+ } while (0)
+#define pr_error(fmt, args...) printk("PCMCIA: " fmt, ## args)
+
+
+static int pcmcia_plugin(struct aml_pcmcia *pc)
+{
+ if (pc->slot_state == MODULE_XTRACTED) {
+ pr_dbg(" CAM Plugged IN: Adapter(%d) Slot(0)\n", 0);
+ udelay(50);
+ aml_pcmcia_reset(pc);
+ /*wait unplug*/
+ pc->init_irq(pc, IRQF_TRIGGER_RISING);
+ udelay(500);
+ pc->slot_state = MODULE_INSERTED;
+ } else {
+ pr_error("repeat into pcmcia insert \r\n");
+ aml_pcmcia_reset(pc);
+ }
+ udelay(100);
+ pc->pcmcia_plugin(pc, 1);
+
+ return 0;
+}
+
+static int pcmcia_unplug(struct aml_pcmcia *pc)
+{
+ if (pc->slot_state == MODULE_INSERTED) {
+ pr_dbg(" CAM Unplugged: Adapter(%d) Slot(0)\n", 0);
+ /*udelay(50);*/
+ /*aml_pcmcia_reset(pc);*/
+ /*wait plugin*/
+ pc->init_irq(pc, IRQF_TRIGGER_FALLING);
+ udelay(500);
+ pc->slot_state = MODULE_XTRACTED;
+ }
+ udelay(100);
+ pc->pcmcia_plugin(pc, 0);
+
+ return 0;
+}
+
+static irqreturn_t pcmcia_irq_handler(int irq, void *dev_id)
+{
+ struct aml_pcmcia *pc = (struct aml_pcmcia *)dev_id;
+ pr_dbg("pcmcia_irq_handler--into--\r\n");
+ disable_irq_nosync(pc->irq);
+ schedule_work(&pc->pcmcia_work);
+ enable_irq(pc->irq);
+ return IRQ_HANDLED;
+}
+
+static void aml_pcmcia_work(struct work_struct *work)
+{
+ int cd1, cd2;
+ struct aml_pcmcia *pc = container_of(
+ work, struct aml_pcmcia, pcmcia_work);
+
+ cd1 = pc->get_cd1(pc);
+ cd2 = pc->get_cd2(pc);
+
+ if (cd1 != cd2)
+ pr_error("CAM card not inerted.\n");
+ else {
+ if (!cd1) {
+ pr_error("Adapter(%d) Slot(0): CAM Plugin\n", 0);
+ pcmcia_plugin(pc);
+ } else {
+ pr_error("Adapter(%d) Slot(0): CAM Unplug\n", 0);
+ pcmcia_unplug(pc);
+ }
+ }
+}
+
+static void aml_pcmcia_detect_cam(struct aml_pcmcia *pc)
+{
+ int cd1, cd2;
+
+ if (pc == NULL) {
+ return;
+ }
+ cd1 = pc->get_cd1(pc);
+ cd2 = pc->get_cd2(pc);
+
+ if (cd1 != cd2)
+ pr_error("CAM card not inerted. check end\n");
+ else {
+ if (!cd1) {
+ pr_error("Adapter(%d) Slot(0): CAM Plugin\n", 0);
+ pcmcia_plugin(pc);
+ } else {
+ pr_error("Adapter(%d) Slot(0): CAM Unplug\n", 0);
+ pcmcia_unplug(pc);
+ }
+ }
+}
+static struct aml_pcmcia *pc_cur;
+
+int aml_pcmcia_init(struct aml_pcmcia *pc)
+{
+ int err = 0;
+ unsigned long mode;
+ pr_dbg("aml_pcmcia_init start pc->irq=%d\r\n", pc->irq);
+ pc->rst(pc, AML_L);
+ /*power on*/
+ pc->pwr(pc, AML_PWR_OPEN);/*hi is open power*/
+ /*assuming cam unpluged, config the INT to waiting-for-plugin mode*/
+ pc->init_irq(pc, IRQF_TRIGGER_LOW);
+
+ INIT_WORK(&pc->pcmcia_work, aml_pcmcia_work);
+
+ mode = IRQF_ONESHOT;
+ if (pc->io_device_type == AML_DVB_IO_TYPE_SPI_T312) {
+ mode = mode | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
+ }
+
+ err = request_irq(pc->irq,
+ pcmcia_irq_handler,
+ mode, "aml-pcmcia", pc);
+ if (err != 0) {
+ pr_error("ERROR: IRQ registration failed ! <%d>", err);
+ return -ENODEV;
+ }
+
+ pc_cur = pc;
+ pr_dbg("aml_pcmcia_init ok\r\n");
+ if (pc->io_device_type == AML_DVB_IO_TYPE_SPI_T312) {
+ //mcu start very fast,so she can detect cam before soc init end.
+ //so we need add detect cam fun for first time.
+ aml_pcmcia_detect_cam(pc);
+ }
+ return 0;
+}
+EXPORT_SYMBOL(aml_pcmcia_init);
+
+int aml_pcmcia_exit(struct aml_pcmcia *pc)
+{
+ free_irq(pc->irq, pc);
+ return 0;
+}
+EXPORT_SYMBOL(aml_pcmcia_exit);
+
+int aml_pcmcia_reset(struct aml_pcmcia *pc)
+{
+ pr_dbg("CAM RESET-->\n");
+ /* viaccess neotion cam need delay 2000 and 3000 */
+ /* smit cam need delay 1000 and 1500 */
+ /* need change delay according cam vendor */
+ pc->rst(pc, AML_H);/*HI is reset*/
+ mdelay(1000);
+ pc->rst(pc, AML_L);/*defaule LOW*/
+ pr_dbg("CAM RESET--\n");
+ mdelay(1500);
+ pr_dbg("CAM RESET--end\n");
+ return 0;
+}
+EXPORT_SYMBOL(aml_pcmcia_reset);
+
+
+#if 0
+static ssize_t aml_pcmcia_test_cmd(struct class *class,
+struct class_attribute *attr, const char *buf, size_t size)
+{
+ pr_dbg("pcmcia cmd: %s\n", buf);
+ if (pc_cur) {
+ if (memcmp(buf, "reset", 5) == 0)
+ aml_pcmcia_reset(pc_cur);
+ else if (memcmp(buf, "on", 2) == 0)
+ pc_cur->pwr(pc_cur, AML_PWR_OPEN);
+ else if (memcmp(buf, "off", 3) == 0)
+ pc_cur->pwr(pc_cur, AML_PWR_CLOSE);
+ else if (memcmp(buf, "poll", 4) == 0)
+ schedule_work(&pc_cur->pcmcia_work);
+ else if (memcmp(buf, "intr", 4) == 0)
+ pc_cur->init_irq(pc_cur, IRQF_TRIGGER_RISING);
+ else if (memcmp(buf, "intf", 4) == 0)
+ pc_cur->init_irq(pc_cur, IRQF_TRIGGER_FALLING);
+ }
+ return size;
+}
+
+static struct class_attribute aml_pcmcia_class_attrs[] = {
+ __ATTR(cmd, S_IRUGO | S_IWUSR, NULL, aml_pcmcia_test_cmd),
+ __ATTR_NULL
+};
+
+static struct class aml_pcmcia_class = {
+ .name = "aml_pcmcia_test",
+ .class_attrs = aml_pcmcia_class_attrs,
+};
+
+static int __init aml_pcmcia_mod_init(void)
+{
+ pr_dbg("Amlogic PCMCIA Init\n");
+
+ class_register(&aml_pcmcia_class);
+
+ return 0;
+}
+
+static void __exit aml_pcmcia_mod_exit(void)
+{
+ pr_dbg("Amlogic PCMCIA Exit\n");
+
+ class_unregister(&aml_pcmcia_class);
+}
+
+
+
+module_init(aml_pcmcia_mod_init);
+module_exit(aml_pcmcia_mod_exit);
+
+MODULE_LICENSE("GPL");
+#endif
diff --git a/drivers/stream_input/parser/dvb_ci/aml_pcmcia.h b/drivers/stream_input/parser/dvb_ci/aml_pcmcia.h
new file mode 100644
index 0000000..7d0a275
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/aml_pcmcia.h
@@ -0,0 +1,61 @@
+/*
+* 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_PCMCIA_
+#define _AML_PCMCIA_
+
+enum aml_slot_state {
+ MODULE_INSERTED = 3,
+ MODULE_XTRACTED = 4
+};
+
+enum aml_pwr_cmd {
+ AML_PWR_OPEN = 0,
+ AML_PWR_CLOSE = 1
+};
+enum aml_reset_cmd {
+ AML_L = 0,
+ AML_H = 1
+};
+struct aml_pcmcia {
+ enum aml_slot_state slot_state;
+ struct work_struct pcmcia_work;
+ int run_type;/*0:irq;1:poll*/
+ int irq;
+ int (*init_irq)(struct aml_pcmcia *pc, int flag);
+ int (*get_cd1)(struct aml_pcmcia *pc);
+ int (*get_cd2)(struct aml_pcmcia *pc);
+ int (*pwr)(struct aml_pcmcia *pc, int enable);
+ int (*rst)(struct aml_pcmcia *pc, int enable);
+
+ int (*pcmcia_plugin)(struct aml_pcmcia *pc, int plugin);
+
+ void *priv;
+ /*device type*/
+ int io_device_type;
+};
+
+int aml_pcmcia_init(struct aml_pcmcia *pc);
+int aml_pcmcia_exit(struct aml_pcmcia *pc);
+int aml_pcmcia_reset(struct aml_pcmcia *pc);
+
+
+#endif /*_AML_PCMCIA_*/
+
diff --git a/drivers/stream_input/parser/dvb_ci/aml_spi.c b/drivers/stream_input/parser/dvb_ci/aml_spi.c
new file mode 100644
index 0000000..49498fa
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/aml_spi.c
@@ -0,0 +1,1862 @@
+/*
+* 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/delay.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/amlogic/aml_gpio_consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/amlogic/sd.h>
+#include <linux/of_irq.h>
+#include <linux/irq.h>
+#include "aml_spi.h"
+#include "aml_ci.h"
+
+#define AML_MODE_NAME "aml_dvbci_spi"
+
+#define AML_SPI_READ_LEN 16
+
+static int AML_CI_GPIO_IRQ_BASE = 251;
+static struct aml_spi *g_spi_dev;
+static int aml_spi_debug = 1;
+static int G_rec_flag = AM_SPI_STEP_INIT;
+
+
+module_param_named(spi_debug, aml_spi_debug, int, 0644);
+MODULE_PARM_DESC(spi_debug, "enable verbose debug messages");
+
+
+#define pr_dbg(args...)\
+ do {\
+ if (aml_spi_debug)\
+ printk(args);\
+ } while (0)
+#define pr_error(fmt, args...) printk("AML_CI_SPI: " fmt, ## args)
+
+struct spi_board_info aml_ci_spi_bdinfo = {
+ .modalias = "ci_spi_dev",
+ .mode = SPI_MODE_0,
+ .max_speed_hz = 1000000, /* 1MHz */
+ .bus_num = 0, /* SPI bus No. */
+ .chip_select = 0, /* the device index on the spi bus */
+ .controller_data = NULL,
+};
+
+#define NORMAL_MSG (0<<7)
+#define BROADCAST_MSG (1<<7)
+#define BLOCK_DATA (0<<6)
+#define SINGLE_DATA (1<<6)
+#define CISPI_DEV_ADDR 1
+
+#define INPUT 0
+#define OUTPUT 1
+#define OUTLEVEL_LOW 0
+#define OUTLEVEL_HIGH 1
+#define PULLLOW 1
+#define PULLHIGH 0
+
+/*
+sendbuf data struct
+----------------------------------------------------
+|start flag| cmd | data | addr |end flag |
+----------------------------------------------------
+| 2 byte | 1byte | 1byte | 2 byte| 2 byte |
+----------------------------------------------------
+*/
+
+#define SENDBUFLEN 8
+static u8 sendbuf[SENDBUFLEN];/* send data */
+static u8 rbuf[SENDBUFLEN];/*save get data */
+/**\brief aml_init_send_buf:init spi send buf
+* \param cmd: ci cmd
+* \param data: write value
+* \param addr: read or write addr
+* \return
+* - read value:ok
+* - -EINVAL : error
+*/
+static int aml_init_send_buf(u8 cmd, u8 data, u16 addr)
+{
+ /* start flag */
+ sendbuf[0] = DATASTART;
+ sendbuf[1] = DATASTART;
+ /* cmd */
+ sendbuf[2] = cmd;
+ /* data */
+ sendbuf[3] = data;
+ /* addr senf low 8 bit first,and then send hi 8bit */
+ sendbuf[4] = addr & 0x00ff;
+ sendbuf[5] = (addr>>8) & 0xff;
+ /* end flag */
+ sendbuf[6] = DATAEND;
+ sendbuf[7] = DATAEND;
+ return 0;
+}
+/**\brief aml_ci_spi_reciver
+* \param[out] None
+* \param[in] value,get from spi
+* \return
+* - 0:reciver end,-1:reciver
+* -
+*/
+/*
+data strouct
+----------------------------------------------------
+|start flag| cmd | data | addr |end flag |
+----------------------------------------------------
+| 2 byte | 1byte | 1byte | 2 byte| 2 byte |
+----------------------------------------------------
+*/
+int aml_ci_spi_paser_bit(uint8_t value)
+{
+ /* read spi data from slave */
+ if (G_rec_flag == AM_SPI_STEP_INIT) {
+ /* start type first */
+ if (value == DATASTART) {
+ rbuf[0] = value;
+ G_rec_flag = AM_SPI_STEP_START1;
+ }
+ } else if (G_rec_flag == AM_SPI_STEP_START1) {
+ /* start2 type seccond */
+ if (value == DATASTART) {
+ rbuf[1] = value;
+ G_rec_flag = AM_SPI_STEP_START2;
+ }
+ } else if (G_rec_flag == AM_SPI_STEP_START2) {
+ /* cmd type */
+ /* pr_dbg("spi value=%d\r\n",value); */
+ rbuf[2] = value;
+ G_rec_flag = AM_SPI_STEP_CMD;
+ } else if (G_rec_flag == AM_SPI_STEP_CMD) {
+ /* data */
+ rbuf[3] = value;
+ G_rec_flag = AM_SPI_STEP_DATA;
+ } else if (G_rec_flag == AM_SPI_STEP_DATA) {
+ /* ADDR1 */
+ rbuf[4] = value;
+ G_rec_flag = AM_SPI_STEP_ADDR1;
+ } else if (G_rec_flag == AM_SPI_STEP_ADDR1) {
+ /* ADDR2 type */
+ rbuf[5] = value;
+ G_rec_flag = AM_SPI_STEP_ADDR2;
+ } else if (G_rec_flag == AM_SPI_STEP_ADDR2) {
+ /* END1 type */
+ if (value == DATAEND) {
+ rbuf[6] = value;
+ G_rec_flag = AM_SPI_STEP_END1;
+ }
+ } else if (G_rec_flag == AM_SPI_STEP_END1) {
+ /* END2 type */
+ if (value == DATAEND) {
+ rbuf[7] = value;
+ G_rec_flag = AM_SPI_STEP_END2;
+ /* pr_dbg("spi read value ok end\r\n"); */
+ return 0;
+ }
+ }
+ return -1;
+}
+
+/**\brief aml_spi_io_api:spi read or write api with mcu
+* \param spi_dev: aml_spi obj,used this data to get spi obj
+* \param val: write value
+* \param len: write value len
+* \param mode: cmd
+* \return
+* - read value:ok
+* - -EINVAL : error
+*/
+static int aml_spi_io_api(struct aml_spi *spi_dev, u8 *val, int len, int mode)
+{
+ u8 rb[32] = {0};
+ int ret = 0;
+ int i = 0;
+ u8 rd = 0;
+ int j = 0;
+ int is_retry = 0;
+ if (spi_dev == NULL ) {
+ pr_error("%s spi_dev is null\r\n", __func__);
+ return -EINVAL;
+ }
+ if (spi_dev->spi == NULL) {
+ pr_error("%s spi is null\r\n", __func__);
+ return -EINVAL;
+ }
+ spin_lock(&spi_dev->spi_lock);
+ if (spi_dev->cs_hold_delay)
+ udelay(spi_dev->cs_hold_delay);
+restart:
+ dirspi_start(spi_dev->spi);
+ if (spi_dev->cs_clk_delay)
+ udelay(spi_dev->cs_clk_delay);
+
+ ret = dirspi_xfer(spi_dev->spi, val, rb, len);
+ if (ret != 0)
+ pr_dbg("spi xfer value errro ret %d\r\n", ret);
+ /* wait mcu io 1ms */
+ udelay(1000);
+ /* init rec flag */
+ G_rec_flag = AM_SPI_STEP_INIT;
+ memset(rbuf, 0, 8);
+
+ for (i = 0; i < 4 * len; i++) {
+ udelay(50);
+ memset(rb, 0, 32);
+ ret = dirspi_read(spi_dev->spi, rb, AML_SPI_READ_LEN);
+ if (ret != 0) {
+ pr_dbg("spi read value timeout:%x ret %d\r\n", rd, ret);
+ }
+ for (j = 0; j < AML_SPI_READ_LEN; j++) {
+ /*pr_dbg("spi read value rb[%d]: 0x%2x\r\n", j, rb[j]);*/
+ ret = aml_ci_spi_paser_bit(rb[j]);
+ if (ret == 0)
+ break;
+ }
+ if (ret == 0)
+ break;
+ }
+ if (ret == 0) {
+ rd = rbuf[3];/* data */
+ } else {
+ pr_dbg("*spi rec flag[%d]index [%d] read error[0x%x] mode[%d]addr[%d]****\r\n",
+ G_rec_flag, i,rd, mode, (val[5] << 8 | val[4]) & 0xffff);
+ dirspi_stop(spi_dev->spi);
+ //only retry once
+ if (is_retry == 0) {
+ is_retry = 1;
+ goto restart;
+ }
+ }
+ if (spi_dev->cs_clk_delay)
+ udelay(spi_dev->cs_clk_delay);
+
+ /* pr_error("ci spi is stop in %s rd=%d\r\n",__func__,rd);*/
+ dirspi_stop(spi_dev->spi);
+
+ spin_unlock(&spi_dev->spi_lock);
+
+ return rd;
+}
+
+/********************************************************/
+/********************************************************/
+/******* gpio api *************/
+/********************************************************/
+/********************************************************/
+/**\brief aml_set_gpio_out:set gio out and set val value
+* \param gpio: gpio_desc obj,
+* \param val: set val
+* \return
+* - 0:ok
+* - -EINVAL : error
+*/
+static int aml_set_gpio_out(struct gpio_desc *gpio, int val)
+{
+ int ret = 0;
+ if (val < 0) {
+ pr_dbg("gpio out val = -1.\n");
+ return -1;
+ }
+ if (val != 0)
+ val = 1;
+ ret = gpiod_direction_output(gpio, val);
+ pr_dbg("dvb ci gpio out ret %d set val:%d\n", ret, val);
+ return ret;
+}
+#if 0//no used
+/**\brief aml_set_gpio_in:set gio in
+* \param gpio: gpio_desc obj,
+* \return
+* - 0:ok
+* - -EINVAL : error
+*/
+static int aml_set_gpio_in(struct gpio_desc *gpio)
+{
+ gpiod_direction_input(gpio);
+ return 0;
+}
+#endif
+
+/**\brief aml_get_gpio_value:get gio value
+* \param gpio: gpio_desc obj,
+* \return
+* - gpio value:ok
+* - -EINVAL : error
+*/
+static int aml_get_gpio_value(struct gpio_desc *gpio)
+{
+ int ret = 0;
+ ret = gpiod_get_value(gpio);
+ return ret;
+}
+/**\brief aml_gpio_free:free gio
+* \param gpio: gpio_desc obj,
+* \return
+* - 0:ok
+* - -EINVAL : error
+*/
+static int aml_gpio_free(struct gpio_desc *gpio)
+{
+ gpiod_put(gpio);
+ return 0;
+}
+/**\brief spi_get_gpio_by_name:get gpio desc from dts file
+* \param spi_dev: aml_spi obj
+* \param gpiod: gpio_desc * obj
+* \param str: gpio name at dts file
+* \param input_output: gpio input or output type
+* \param output_value: gpio out put value
+* \return
+* - 0:ok
+* - -EINVAL : error
+*/
+static int spi_get_gpio_by_name(struct aml_spi *spi_dev,
+struct gpio_desc **gpiod, int *pin_value,
+char *str, int input_output, int output_level)
+{
+ int ret = 0;
+ struct device_node *child = NULL;
+ struct platform_device *pdev = spi_dev->pdev;
+ struct device_node *np = pdev->dev.of_node;
+
+ /*get spi and gpio config from dts*/
+ /* get device config for dvbci_io*/
+ child = of_get_child_by_name(np, "dvbci_io");
+ if (IS_ERR(*gpiod)) {
+ pr_dbg("dvb ci spi %s request failed\n", str);
+ return -1;
+ }
+
+ *pin_value = of_get_named_gpio_flags(child, str, 0, NULL);
+ *gpiod = gpio_to_desc(*pin_value);
+ if (IS_ERR(*gpiod)) {
+ pr_dbg("spi %s request failed\n", str);
+ return -1;
+ }
+ pr_dbg("spi get_gpio %s %p %d\n", str, *gpiod, *pin_value);
+ gpio_request(*pin_value, AML_MODE_NAME);
+
+ if (input_output == OUTPUT) {
+ ret = gpiod_direction_output(*gpiod, output_level);
+ } else if (input_output == INPUT) {
+ ret = gpiod_direction_input(*gpiod);
+ /*ret |= gpiod_set_pullup(*gpiod, 1);*/
+ } else {
+ pr_error("spi Request gpio direction invalid\n");
+ }
+ return ret;
+}
+/********************************************************/
+/********************************************************/
+/******* gpio api end *************/
+/********************************************************/
+/********************************************************/
+#if 1
+/**\brief aml_ci_cis_test_by_spi:test cis
+* \param ci_dev: aml_ci obj,used this data to get spi_dev obj
+* \param slot: slot index
+* \param addr: read addr
+* \return
+* - test :ok
+* - -EINVAL : error
+*/
+/**\brief aml_ci_full_test_by_spi:ci full test
+* \param ci_dev: aml_ci obj,used this data to get spi_dev obj
+* \param slot: slot index
+* \param addr: read addr
+* \return
+* - read value:ok
+* - -EINVAL : error
+*/
+static int aml_ci_full_test_by_spi(
+ struct aml_ci *ci_dev, int slot, int addr)
+{
+ u8 data = 0;
+ u16 addres = addr;
+ int value = 0;
+ struct aml_spi *spi_dev = ci_dev->data;
+ aml_init_send_buf(AM_CI_CMD_FULLTEST, data, addres);
+ value = aml_spi_io_api(spi_dev,
+ sendbuf, SENDBUFLEN, AM_CI_CMD_FULLTEST);
+ pr_dbg("FULL : TEST END \r\n");
+ return value;
+}
+#endif
+/**\brief aml_ci_mem_read_by_spi:io read from cam
+* \param ci_dev: aml_ci obj,used this data to get spi_dev obj
+* \param slot: slot index
+* \param addr: read addr
+* \return
+* - read value:ok
+* - -EINVAL : error
+*/
+static int aml_ci_mem_read_by_spi(
+ struct aml_ci *ci_dev, int slot, int addr)
+{
+ u8 data = 0;
+ u16 addres = addr;
+ int value = 0;
+ struct aml_spi *spi_dev = ci_dev->data;
+ aml_init_send_buf(AM_CI_CMD_MEMR, data, addres);
+ value = aml_spi_io_api(spi_dev, sendbuf, SENDBUFLEN, AM_CI_CMD_MEMR);
+ /*pr_dbg("Read : mem[%d] = 0x%x\n", addr, value);*/
+ return value;
+}
+/**\brief aml_ci_mem_write_by_spi:io write to cam by spi api
+* \param ci_dev: aml_ci obj,used this data to get spi_dev obj
+* \param slot: slot index
+* \param addr: write addr
+* \param addr: write value
+* \return
+* - 0:ok
+* - -EINVAL : error
+*/
+static int aml_ci_mem_write_by_spi(
+ struct aml_ci *ci_dev, int slot, int addr, u8 val)
+{
+ u8 data = val;
+ u16 addres = addr;
+ int value = 0;
+ struct aml_spi *spi_dev = ci_dev->data;
+ aml_init_send_buf(AM_CI_CMD_MEMW, data, addres);
+ value = aml_spi_io_api(spi_dev, sendbuf, SENDBUFLEN, AM_CI_CMD_MEMW);
+ /*pr_dbg("write : mem[%d] = 0x%x\n", addr, data);*/
+return value;
+}
+/**\brief aml_ci_io_read_by_spi:io read from cam by spi api
+* \param ci_dev: aml_ci obj,used this data to get spi_dev obj
+* \param slot: slot index
+* \param addr: read addr
+* \return
+* - read value:ok
+* - -EINVAL : error
+*/
+static int aml_ci_io_read_by_spi(
+ struct aml_ci *ci_dev, int slot, int addr)
+{
+ u8 data = 0;
+ u16 addres = addr;
+ int value = 0;
+ struct aml_spi *spi_dev = ci_dev->data;
+ aml_init_send_buf(AM_CI_CMD_IOR, data, addres);
+ value = aml_spi_io_api(spi_dev, sendbuf, SENDBUFLEN, AM_CI_CMD_IOR);
+ /*pr_dbg("read : io[%d] = 0x%x\n", addr, value);*/
+ return value;
+}
+/**\brief aml_ci_io_write_by_spi:io write to cam
+* \param ci_dev: aml_ci obj,used this data to get spi_dev obj
+* \param slot: slot index
+* \param addr: write addr
+* \param addr: write value
+* \return
+* - 0:ok
+* - -EINVAL : error
+*/
+static int aml_ci_io_write_by_spi(
+ struct aml_ci *ci_dev, int slot, int addr, u8 val)
+{
+ u8 data = val;
+ u16 addres = addr;
+ int value = 0;
+ struct aml_spi *spi_dev = ci_dev->data;
+ /*add by chl,need add time delay*/
+ mdelay(10);
+ aml_init_send_buf(AM_CI_CMD_IOW, data, addres);
+ value = aml_spi_io_api(spi_dev, sendbuf, SENDBUFLEN, AM_CI_CMD_IOW);
+ /*pr_dbg("write : ATTR[%d] = 0x%x\n", addr, data);*/
+ return value;
+}
+
+
+/**\brief aml_ci_rst_by_spi:reset cam by spi
+* \param ci_dev: aml_ci obj,used this data to get spi_dev obj
+* \param slot: slot index
+* \return
+* - 0:ok
+* - -EINVAL : error
+*/
+static int aml_ci_rst_by_spi(
+ struct aml_ci *ci_dev, int slot, int level)
+{
+ u8 data = (u8)level;
+ u16 addres = 0;
+ int value = 0;
+ struct aml_spi *spi_dev = ci_dev->data;
+ /*add by chl,need add time delay*/
+ mdelay(10);
+ aml_init_send_buf(AM_CI_CMD_RESET, data, addres);
+ value = aml_spi_io_api(spi_dev, sendbuf, SENDBUFLEN, AM_CI_CMD_RESET);
+ return value;
+}
+
+/**\brief aml_ci_power_by_spi:power cam by spi
+* \param ci_dev: aml_ci obj,used this data to get spi_dev obj
+* \param slot: slot index
+* \param enable: enable or disable cam
+* \return
+* - 0:ok
+* - -EINVAL : error
+*/
+static int aml_ci_power_by_spi(
+ struct aml_ci *ci_dev, int slot, int enable)
+{
+ u8 data = (u8)enable;
+ u16 addres = 0;
+ int value = 0;
+ struct aml_spi *spi_dev = ci_dev->data;
+ /*add by chl,need add time delay*/
+ /*power is controled by mcu*/
+ if (0) {
+ mdelay(10);
+ aml_init_send_buf(AM_CI_CMD_POWER, data, addres);
+ value = aml_spi_io_api(spi_dev, sendbuf, SENDBUFLEN, AM_CI_CMD_POWER);
+ }
+ return value;
+}
+
+/**\brief aml_ci_getcd12_by_spi:get cd12 cam by spi
+* \param ci_dev: aml_ci obj,used this data to get spi_dev obj
+* \param slot: slot index
+* \param cd12: cd1 or cd2 value
+* \return
+* - 0:ok
+* - -EINVAL : error
+*/
+static int aml_ci_getcd12_by_spi(
+ struct aml_ci *ci_dev, int slot, int cd12)
+{
+ u8 data = (u8)cd12;
+ u16 addres = 0;
+ int value = 0;
+ struct aml_spi *spi_dev = ci_dev->data;
+ /*add by chl,need add time delay*/
+ mdelay(10);
+ aml_init_send_buf(AM_CI_CMD_GETCD12, data, addres);
+ value = aml_spi_io_api(spi_dev, sendbuf, SENDBUFLEN, AM_CI_CMD_GETCD12);
+ return value;
+}
+
+
+
+/**\brief aml_ci_slot_reset:reset slot
+* \param ci_dev: aml_ci obj,used this data to get spi_dev obj
+* \param slot: slot index
+* \return
+* - 0:ok
+* - -EINVAL : error
+*/
+static int aml_ci_slot_reset(struct aml_ci *ci_dev, int slot)
+{
+ struct aml_spi *spi_dev = ci_dev->data;
+ pr_dbg("Slot(%d): Slot RESET\n", slot);
+ aml_pcmcia_reset(&spi_dev->pc);
+ dvb_ca_en50221_cimcu_camready_irq(&ci_dev->en50221_cimcu, 0);
+ return 0;
+}
+/**\brief aml_ci_slot_shutdown:show slot
+* \param ci_dev: aml_ci obj,used this data to get spi_dev obj
+* \param slot: slot index
+* \return
+* - 0:ok
+* - -EINVAL : error
+* readme:no use this api
+*/
+static int aml_ci_slot_shutdown(struct aml_ci *ci_dev, int slot)
+{
+ pr_dbg("Slot(%d): Slot shutdown\n", slot);
+ return 0;
+}
+/**\brief aml_ci_ts_control:control slot ts
+* \param ci_dev: aml_ci obj,used this data to get spi_dev obj
+* \param slot: slot index
+* \return
+* - 0:ok
+* - -EINVAL : error
+* readme:no use this api
+*/
+static int aml_ci_ts_control(struct aml_ci *ci_dev, int slot)
+{
+ pr_dbg("Slot(%d): TS control\n", slot);
+ return 0;
+}
+/**\brief aml_ci_slot_status:get slot status
+* \param ci_dev: aml_ci obj,used this data to get spi_dev obj
+* \param slot: slot index
+* \param open: no used
+* \return
+* - cam status
+* - -EINVAL : error
+*/
+static int aml_ci_slot_status(struct aml_ci *ci_dev, int slot, int open)
+{
+ struct aml_spi *spi_dev = ci_dev->data;
+
+ pr_dbg("Slot(%d): Poll Slot status\n", slot);
+
+ if (spi_dev->pc.slot_state == MODULE_INSERTED) {
+ pr_dbg("CA Module present and ready\n");
+ return DVB_CA_EN50221_POLL_CAM_PRESENT |
+ DVB_CA_EN50221_POLL_CAM_READY;
+ } else {
+ pr_error("CA Module not present or not ready\n");
+ }
+ return -EINVAL;
+}
+#if 1
+/**\brief aml_ci_gio_get_irq:get gpio cam irq pin value
+* \return
+* - irq pin value
+* - -EINVAL : error
+*/
+static int aml_ci_gio_get_irq(void)
+{
+ int ret = 0;
+ if (g_spi_dev->io_device_type == AML_DVB_IO_TYPE_SPI)
+ ret = aml_get_gpio_value(g_spi_dev->irq_cam_pin);
+ else if (g_spi_dev->io_device_type == AML_DVB_IO_TYPE_SPI)
+ ret = aml_get_gpio_value(g_spi_dev->mcu_irq_pin);
+ else
+ pr_error("aml_ci_gio_get_irq io type not surport\n");
+ return ret;
+}
+#endif
+
+/********************************************************/
+/********************************************************/
+/******* for pcmcid api *************/
+/********************************************************/
+/********************************************************/
+/**\brief aml_gio_power:set power gpio hi or low
+* \param pc: aml_pcmcia obj,used this priv to get spi_dev obj
+* \param enable: power pin hi or low
+* \return
+* - 0
+* - -EINVAL : error
+*/
+static int aml_gio_power(struct aml_pcmcia *pc, int enable)
+{
+ int ret = 0;
+ struct aml_spi *spi_dev = pc->priv;
+ if (spi_dev == NULL) {
+ pr_dbg("spi dev is null %s : %d\r\n", __func__, enable);
+ return -1;
+ }
+ pr_dbg("%s : %d\r\n", __func__, enable);
+ if (spi_dev->io_device_type == AML_DVB_IO_TYPE_SPI) {
+ if (enable == AML_PWR_OPEN) {
+ /*hi level ,open power*/
+ ret = aml_set_gpio_out(spi_dev->pwr_pin, AML_GPIO_HIGH);
+ } else {
+ /*low level ,close power*/
+ ret = aml_set_gpio_out(spi_dev->pwr_pin, AML_GPIO_LOW);
+ }
+ } else if (spi_dev->io_device_type == AML_DVB_IO_TYPE_SPI_T312) {
+ //no need power cam,we power cam card on MCU.
+ aml_ci_power_by_spi((struct aml_ci *)spi_dev->priv, 0, enable);
+ } else {
+ pr_dbg("aml_gio_power type [%d] enable: %d\r\n", spi_dev->io_device_type, enable);
+ }
+ return ret;
+}
+/**\brief aml_gio_reset:set reset gpio hi or low
+* \param pc: aml_pcmcia obj,used this priv to get spi_dev obj
+* \param enable: reset pin hi or low
+* \return
+* - 0
+* - -EINVAL : error
+*/
+static int aml_gio_reset(struct aml_pcmcia *pc, int enable)
+{
+ /*need set hi and sleep set low*/
+ int ret = 0;
+ struct aml_spi *spi_dev = pc->priv;
+
+ if (spi_dev != NULL)
+ pr_dbg("%s : %d \r\n", __func__, enable);
+
+ pr_dbg("%s : %d type: %d\r\n", __func__, enable, spi_dev->io_device_type);
+ if (spi_dev->io_device_type == AML_DVB_IO_TYPE_SPI) {
+ if (enable == AML_L)
+ ret = aml_set_gpio_out(spi_dev->reset_pin, AML_GPIO_LOW);
+ else
+ ret = aml_set_gpio_out(spi_dev->reset_pin, AML_GPIO_HIGH);
+ } else if (spi_dev->io_device_type == AML_DVB_IO_TYPE_SPI_T312) {
+ if (spi_dev == NULL || spi_dev->priv == NULL) {
+ pr_dbg("rst by spi-spidev-null-\r\n");
+ return -1;
+ }
+ aml_ci_rst_by_spi((struct aml_ci *)spi_dev->priv, 0, enable);
+ } else {
+ pr_dbg("aml_gio_power type [%d] enable: %d\r\n", spi_dev->io_device_type, enable);
+ }
+ return ret;
+}
+
+/**\brief aml_gio_init_irq:set gpio irq
+* \param pc: aml_pcmcia obj,used this priv to get spi_dev obj
+* \param flag: rising or falling or hi or low
+* \return
+* - 0
+* - -EINVAL : error
+*/
+/*need change*/
+static int aml_gio_init_irq(struct aml_pcmcia *pc, int flag)
+{
+ struct aml_spi *spi_dev = (struct aml_spi *)pc->priv;
+
+#if 0
+ int cd1_pin = desc_to_gpio(spi_dev->cd_pin1);
+
+ int irq = pc->irq-AML_CI_GPIO_IRQ_BASE;
+
+ printk("----cd1_pin=%d irq=%d\r\n", cd1_pin, irq);
+ aml_set_gpio_in(spi_dev->cd_pin1);
+
+ if (flag == IRQF_TRIGGER_RISING)
+ gpio_for_irq(cd1_pin,
+ AML_GPIO_IRQ(irq, FILTER_NUM7, GPIO_IRQ_RISING));
+ else if (flag == IRQF_TRIGGER_FALLING)
+ gpio_for_irq(cd1_pin,
+ AML_GPIO_IRQ(irq, FILTER_NUM7, GPIO_IRQ_FALLING));
+ else if (flag == IRQF_TRIGGER_HIGH)
+ gpio_for_irq(cd1_pin,
+ AML_GPIO_IRQ(irq, FILTER_NUM7, GPIO_IRQ_HIGH));
+ else if (flag == IRQF_TRIGGER_LOW)
+ gpio_for_irq(cd1_pin,
+ AML_GPIO_IRQ(irq, FILTER_NUM7, GPIO_IRQ_LOW));
+ else
+ return -1;
+#endif
+ if (spi_dev->io_device_type == AML_DVB_IO_TYPE_SPI) {
+ gpiod_to_irq(spi_dev->cd_pin1);
+ } else if (spi_dev->io_device_type == AML_DVB_IO_TYPE_SPI_T312) {
+ gpiod_to_irq(spi_dev->mcu_irq_pin);
+ } else {
+ pr_dbg("aml_gio_init_irq type [%d] \r\n", spi_dev->io_device_type);
+ }
+ return 0;
+}
+
+/**\brief aml_gio_get_cd1:get gpio cd1 pin value
+* \param pc: aml_pcmcia obj,used this priv to get spi_dev obj
+* \return
+* - cd1 pin value
+* - -EINVAL : error
+*/
+static int aml_gio_get_cd1(struct aml_pcmcia *pc)
+{
+ int ret = 1;
+ struct aml_spi *spi_dev = pc->priv;
+ if (spi_dev->io_device_type == AML_DVB_IO_TYPE_SPI) {
+ ret = aml_get_gpio_value(spi_dev->cd_pin1);
+ } else if (spi_dev->io_device_type == AML_DVB_IO_TYPE_SPI_T312) {
+ ret = aml_ci_getcd12_by_spi((struct aml_ci *)spi_dev->priv, 0, 0);
+ } else {
+ pr_dbg("aml_gio_get_cd1 not surport type [%d] \r\n", spi_dev->io_device_type);
+ }
+ return ret;
+}
+/**\brief aml_gio_get_cd2:get gpio cd2 pin value
+* \param pc: aml_pcmcia obj,used this priv to get spi_dev obj
+* \return
+* - cd2 pin value
+* - -EINVAL : error
+*/
+static int aml_gio_get_cd2(struct aml_pcmcia *pc)
+{
+ int ret = 0;
+ struct aml_spi *spi_dev = pc->priv;
+ if (spi_dev->io_device_type == AML_DVB_IO_TYPE_SPI) {
+ ret = aml_get_gpio_value(spi_dev->cd_pin2);
+ } else if (spi_dev->io_device_type == AML_DVB_IO_TYPE_SPI_T312) {
+ ret = aml_ci_getcd12_by_spi((struct aml_ci *)spi_dev->priv, 0, 1);
+ } else {
+ pr_dbg("aml_gio_get_cd2 not surport type [%d] \r\n", spi_dev->io_device_type);
+ }
+ return ret;
+}
+/**\brief aml_cam_plugin:notify en50221 cam card in or out
+* \param pc: aml_pcmcia obj,used this priv to get spi_dev obj
+* \plugin: 0:remove;1:in
+* \return
+* - 0
+* - -EINVAL : error
+*/
+static int aml_cam_plugin(struct aml_pcmcia *pc, int plugin)
+{
+ struct aml_ci *ci = (struct aml_ci *)
+ ((struct aml_spi *)(pc->priv))->priv;
+ pr_dbg("%s : %d\r\n", __func__, plugin);
+ if (plugin) {
+ dvb_ca_en50221_cimcu_camchange_irq(&ci->en50221_cimcu,
+ 0, DVB_CA_EN50221_CAMCHANGE_INSERTED);
+ } else {
+ dvb_ca_en50221_cimcu_camchange_irq(&ci->en50221_cimcu,
+ 0, DVB_CA_EN50221_CAMCHANGE_REMOVED);
+ }
+ return 0;
+}
+/**\brief aml_pcmcia_alloc:alloc nad init pcmcia obj
+* \param spi_dev: aml_spi obj,
+* \param pcmcia: aml_pcmcia * obj,
+* \return
+* - 0
+* - -EINVAL : error
+*/
+static void aml_pcmcia_alloc(struct aml_spi *spi_dev,
+ struct aml_pcmcia **pcmcia)
+{
+ pr_dbg("aml_pcmcia_alloc----\n");
+ *pcmcia = &spi_dev->pc;
+ (*pcmcia)->irq = spi_dev->irq;
+ (*pcmcia)->init_irq = aml_gio_init_irq;
+ (*pcmcia)->get_cd1 = aml_gio_get_cd1;
+ (*pcmcia)->get_cd2 = aml_gio_get_cd2;
+ (*pcmcia)->pwr = aml_gio_power;
+ (*pcmcia)->rst = aml_gio_reset;
+ (*pcmcia)->pcmcia_plugin = aml_cam_plugin;
+ (*pcmcia)->slot_state = MODULE_XTRACTED;
+ (*pcmcia)->priv = spi_dev;
+ (*pcmcia)->run_type = 0;/*0:irq;1:poll*/
+ (*pcmcia)->io_device_type = AML_DVB_IO_TYPE_CIMAX;
+}
+
+/**\brief aml_spi_get_config_from_dts:get spi config and gpio config from dts
+* \param spi_dev: aml_spi obj,
+* \return
+* - 0
+* - -EINVAL : error
+*/
+static int aml_spi_get_config_from_dts(struct aml_spi *spi_dev)
+{
+ struct device_node *child = NULL;
+ struct platform_device *pdev = spi_dev->pdev;
+ struct device_node *np = pdev->dev.of_node;
+ unsigned int temp[5], val;
+ int ret = 0;
+ pr_dbg("into get spi dts \r\n");
+
+ /*get spi and gpio config from dts*/
+ /* get device config for dvbci_io*/
+ child = of_get_child_by_name(np, "dvbci_io");
+ if (child == NULL) {
+ pr_error("failed to get dvbci_io\n");
+ return -1;
+ }
+ spi_dev->spi_bdinfo = &aml_ci_spi_bdinfo;
+ /* get spi config */
+ ret = of_property_read_u32_array(child, "spi_bus_num", temp, 1);
+ if (ret) {
+ pr_error("failed to get spi_bus_num\n");
+ } else {
+ aml_ci_spi_bdinfo.bus_num = temp[0];
+ pr_dbg("bus_num: %d\n", aml_ci_spi_bdinfo.bus_num);
+ }
+ ret = of_property_read_u32_array(child, "spi_chip_select",
+ temp, 1);
+ if (ret) {
+ pr_error("failed to get spi_chip_select\n");
+ } else {
+ aml_ci_spi_bdinfo.chip_select = temp[0];
+ pr_dbg("chip_select: %d\n", aml_ci_spi_bdinfo.chip_select);
+ }
+ ret = of_property_read_u32_array(child, "spi_max_frequency",
+ temp, 1);
+ if (ret) {
+ pr_error("failed to get spi_chip_select\n");
+ } else {
+ aml_ci_spi_bdinfo.max_speed_hz = temp[0];
+ pr_dbg("max_speed_hz: %d\n", aml_ci_spi_bdinfo.max_speed_hz);
+ }
+ ret = of_property_read_u32_array(child, "spi_mode", temp, 1);
+ if (ret) {
+ pr_error("failed to get spi_mode\n");
+ } else {
+ aml_ci_spi_bdinfo.mode = temp[0];
+ pr_dbg("mode: %d\n", aml_ci_spi_bdinfo.mode);
+ }
+ ret = of_property_read_u32_array(child, "spi_cs_delay",
+ &temp[0], 2);
+ if (ret) {
+ spi_dev->cs_hold_delay = 0;
+ spi_dev->cs_clk_delay = 0;
+ } else {
+ spi_dev->cs_hold_delay = temp[0];
+ spi_dev->cs_clk_delay = temp[1];
+ }
+ ret = of_property_read_u32(child, "spi_write_check", &val);
+ if (ret)
+ spi_dev->write_check = 0;
+ else
+ spi_dev->write_check = (unsigned char)val;
+
+ //below is get cd1 cd2 pwr irq reset gpio info
+ if (spi_dev->io_device_type == AML_DVB_IO_TYPE_SPI) {
+ /*get cd1 irq num*/
+ ret = of_property_read_u32(child, "irq_cd1", &val);
+ if (ret) {
+ spi_dev->irq = 5;
+ } else {
+ /*set irq value need add
+ AML_CI_GPIO_IRQ_BASE,but
+ we need minus
+ AML_CI_GPIO_IRQ_BASE
+ when gpio request irq */
+ spi_dev->irq = val+AML_CI_GPIO_IRQ_BASE;
+ }
+
+ spi_dev->irq = irq_of_parse_and_map(
+ pdev->dev.of_node, 0);
+ AML_CI_GPIO_IRQ_BASE = spi_dev->irq - val;
+ pr_dbg("get spi irq : %d 0:%d USEDBASE:%d val:%d\r\n",
+ spi_dev->irq, INT_GPIO_0, AML_CI_GPIO_IRQ_BASE, val);
+ /*get reset pwd cd1 cd2 gpio pin*/
+ spi_dev->reset_pin = NULL;
+ ret = spi_get_gpio_by_name(spi_dev, &spi_dev->reset_pin,
+ &spi_dev->reset_pin_value, "reset_pin",
+ OUTPUT, OUTLEVEL_HIGH);
+ if (ret) {
+ pr_error("dvb ci reset pin request failed\n");
+ return -1;
+ }
+ spi_dev->cd_pin1 = NULL;
+ ret = spi_get_gpio_by_name(spi_dev,
+ &spi_dev->cd_pin1,
+ &spi_dev->cd_pin1_value, "cd_pin1",
+ INPUT, OUTLEVEL_HIGH);
+ if (ret) {
+ pr_error("dvb ci cd_pin1 pin request failed\n");
+ return -1;
+ }
+ spi_dev->cd_pin2 = spi_dev->cd_pin1;
+ spi_dev->cd_pin2_value = spi_dev->cd_pin1_value;
+ spi_dev->pwr_pin = NULL;
+ pr_dbg("spi_dev->cd_pin1_value==%d\r\n", spi_dev->cd_pin1_value);
+ ret = spi_get_gpio_by_name(spi_dev,
+ &spi_dev->pwr_pin, &spi_dev->pwr_pin_value,
+ "pwr_pin", OUTPUT, OUTLEVEL_HIGH);
+ if (ret) {
+ pr_error("dvb ci pwr_pin pin request failed\n");
+ return -1;
+ }
+ spi_dev->irq_cam_pin = NULL;
+ ret = spi_get_gpio_by_name(spi_dev,
+ &spi_dev->irq_cam_pin, &spi_dev->irq_cam_pin_value,
+ "irq_cam_pin", INPUT, OUTLEVEL_HIGH);
+ if (ret) {
+ pr_error("dvbci irq_cam_pin pin request failed\n");
+ return -1;
+ }
+ } else if (spi_dev->io_device_type == AML_DVB_IO_TYPE_SPI_T312) {
+ //get mcu irq gpio
+ spi_dev->mcu_irq_pin = NULL;
+ ret = spi_get_gpio_by_name(spi_dev,
+ &spi_dev->mcu_irq_pin,
+ &spi_dev->mcu_irq_pin_value, "mcu_irq_pin",
+ INPUT, OUTLEVEL_HIGH);
+ if (ret) {
+ pr_error("dvb ci mcu_irq_pin pin request failed\n");
+ return -1;
+ }
+ spi_dev->irq = gpiod_to_irq(spi_dev->mcu_irq_pin) ;
+ } else {
+ pr_error("dvbci io device type error [%d]\n", spi_dev->io_device_type);
+ }
+ return 0;
+}
+/**\brief aml_ci_free_gpio:free ci gpio
+* \param spi_dev: aml_spi obj,
+* \return
+* - 0
+* - -EINVAL : error
+*/
+static void aml_ci_free_gpio(struct aml_spi *spi_dev)
+{
+ if (spi_dev == NULL) {
+ pr_error("spi_dev is NULL,no need free gpio res\r\n");
+ return;
+ }
+
+ if (spi_dev->pwr_pin) {
+ aml_gpio_free(spi_dev->pwr_pin);
+ spi_dev->pwr_pin = NULL;
+ }
+ if (spi_dev->cd_pin1) {
+ aml_gpio_free(spi_dev->cd_pin1);
+ spi_dev->cd_pin1 = NULL;
+ spi_dev->cd_pin2 = NULL;
+ }
+ if (spi_dev->reset_pin) {
+ aml_gpio_free(spi_dev->reset_pin);
+ spi_dev->reset_pin = NULL;
+ }
+ if (spi_dev->irq_cam_pin) {
+ aml_gpio_free(spi_dev->irq_cam_pin);
+ spi_dev->irq_cam_pin = NULL;
+ }
+ return;
+}
+
+
+/**\brief ci_spi_dev_remove:spi probe api
+* \param spi: spi obj,
+* \return
+* - 0
+* - -EINVAL : error
+*/
+static int ci_spi_dev_probe(struct spi_device *spi)
+{
+ int ret;
+ pr_dbg("spi Dev probe--\r\n");
+ spin_lock(&(g_spi_dev->spi_lock));
+ if (g_spi_dev)
+ g_spi_dev->spi = spi;
+ else
+ pr_dbg("spi Dev probe-error-\n");
+ spi->bits_per_word = 8;
+ ret = spi_setup(spi);
+ if (ret)
+ pr_dbg("spi setup failed\n");
+ spin_unlock(&(g_spi_dev->spi_lock));
+ return ret;
+}
+/**\brief ci_spi_dev_remove:spi remove api
+* \param spi: spi obj,
+* \return
+* - 0
+* - -EINVAL : error
+*/
+static int ci_spi_dev_remove(struct spi_device *spi)
+{
+ pr_dbg("spi Dev remove--\n");
+ if (g_spi_dev)
+ g_spi_dev->spi = NULL;
+
+ return 0;
+}
+
+static struct spi_driver ci_spi_dev_driver = {
+ .probe = ci_spi_dev_probe,
+ .remove = ci_spi_dev_remove,
+ .driver = {
+ .name = "ci_spi_dev",/*set same with board info modalias*/
+ .owner = THIS_MODULE,
+ },
+};
+/**\brief aml_spi_init:spi_dev init
+* \param ci_dev: aml_ci obj,
+* \param pdev: platform_device obj,used to get dts info
+* \return
+* - 0
+* - -EINVAL : error
+*/
+int aml_spi_init(struct platform_device *pdev, struct aml_ci *ci_dev)
+{
+ struct aml_spi *spi_dev = NULL;
+ struct aml_pcmcia *pc;
+ int result;
+
+ spi_dev = kmalloc(sizeof(struct aml_spi), GFP_KERNEL);
+ if (!spi_dev) {
+ pr_error("Out of memory!, exiting ..\n");
+ result = -ENOMEM;
+ goto err;
+ }
+ g_spi_dev = spi_dev;
+ spi_dev->pdev = pdev;
+ spi_dev->priv = ci_dev;
+ spi_dev->spi = NULL;
+ /*init io device type*/
+ spi_dev->io_device_type = ci_dev->io_type;
+ pr_dbg("*********spi Dev type [%d]\n", ci_dev->io_type);
+ /*get config from dts*/
+ aml_spi_get_config_from_dts(spi_dev);
+
+ /*init spi_lock*/
+ spin_lock_init(&(spi_dev->spi_lock));
+ /*regist api dev*/
+ pr_dbg("*********spi Dev regist**********\r\n");
+ result = dirspi_register_board_info(spi_dev->spi_bdinfo, 1);
+ if (result) {
+ pr_error("register amlspi_dev spi boardinfo failed\n");
+ goto fail1;
+ }
+ result = spi_register_driver(&ci_spi_dev_driver);
+ if (result) {
+ pr_error("register amlspi_dev spi driver failed\n");
+ goto fail1;
+ }
+
+ /*init ci_dev used api.*/
+ ci_dev->ci_mem_read = aml_ci_mem_read_by_spi;
+ ci_dev->ci_mem_write = aml_ci_mem_write_by_spi;
+ ci_dev->ci_io_read = aml_ci_io_read_by_spi;
+ ci_dev->ci_io_write = aml_ci_io_write_by_spi;
+ ci_dev->ci_slot_reset = aml_ci_slot_reset;
+ ci_dev->ci_slot_shutdown = aml_ci_slot_shutdown;
+ ci_dev->ci_slot_ts_enable = aml_ci_ts_control;
+ ci_dev->ci_poll_slot_status = aml_ci_slot_status;
+ ci_dev->data = spi_dev;
+
+ aml_pcmcia_alloc(spi_dev, &pc);
+ pc->io_device_type = spi_dev->io_device_type;
+ result = aml_pcmcia_init(pc);
+ if (result < 0) {
+ pr_error("aml_pcmcia_init failed\n");
+ goto fail2;
+ }
+ return 0;
+fail2:
+ spi_unregister_driver(&ci_spi_dev_driver);
+fail1:
+ kfree(spi_dev);
+ spi_dev = NULL;
+err:
+ return -1;
+}
+EXPORT_SYMBOL(aml_spi_init);
+/**\brief aml_spi_exit:spi exit
+* \return
+* - 0
+* - -EINVAL : error
+*/
+int aml_spi_exit(struct aml_ci *ci)
+{
+ /*exit pc card*/
+ aml_pcmcia_exit(&g_spi_dev->pc);
+ /*un regist spi driver*/
+ spi_unregister_driver(&ci_spi_dev_driver);
+ /*free gpio*/
+ aml_ci_free_gpio(g_spi_dev);
+ /*free spi dev*/
+ kfree(g_spi_dev);
+ g_spi_dev = NULL;
+
+ return 0;
+}
+EXPORT_SYMBOL(aml_spi_exit);
+
+
+#if 1
+/********************************************************/
+/********************************************************/
+/******* for spi test api *************/
+/********************************************************/
+/********************************************************/
+
+/*cam difines*/
+#define DA 0x80
+#define FR 0x40
+#define WE 0x02
+#define RE 0x01
+
+#define RS 0x08
+#define SR 0x04
+#define SW 0x02
+#define HC 0x01
+#define DATA_REG 0
+#define COM_STA_REG 1
+#define SIZE_REG_L 2
+#define SIZE_REG_M 3
+static void aml_spi_ca_full_test(struct aml_ci *ci_dev)
+{
+ unsigned int BUF_SIZE = 0;
+ unsigned int i = 0;
+ unsigned char cc = 0;
+ unsigned char reg;
+ unsigned int bsize = 0;
+ int cnt = 0;
+ unsigned char buf[10];
+ int count = 1000;
+ mdelay(1000);
+ pr_dbg("READ CIS START\r\n");
+ for (i = 0; i < 267; i++) {
+ mdelay(100);
+ cc = aml_ci_mem_read_by_spi(ci_dev, 0, i);
+ pr_dbg("0x%x ", cc);
+ if ((i + 1) % 16 == 0)
+ pr_dbg(" \r\n");
+ }
+ pr_dbg("READ CIS OVER\r\n");
+ mdelay(1000);
+ pr_dbg("SW rst CAM...\r\n");
+ aml_ci_io_write_by_spi(ci_dev, 0, COM_STA_REG, RS);
+ pr_dbg("SW rst over.\r\n");
+ pr_dbg("-----------------------------------\r\n");
+ pr_dbg("TO delay 2000ms\r\n");
+ mdelay(2000);
+ pr_dbg("\r\n");
+ pr_dbg("--------------clear rs--!!!-YOU MUST CLEAR RS BIT--no sleep--------\r\n");
+ aml_ci_io_write_by_spi(ci_dev, 0, COM_STA_REG, 0);
+ pr_dbg("--------------sleep---------------------\r\n");
+ mdelay(2000);
+ pr_dbg("TO check sw-rst is OK\r\n");
+ pr_dbg("start read fr \r\n");
+ if (1) {
+ unsigned char reg;
+ unsigned char reg1;
+ int count1 = 4000;
+ while (1) {
+ mdelay(20);
+ count1--;
+ reg1 = aml_ci_io_read_by_spi(
+ ci_dev, 0, COM_STA_REG);
+ if (FR != (FR & reg1)) {
+ continue;
+ } else {
+ pr_dbg("CAM Reset Ok\r\n");
+ break;
+ }
+ }
+ reg = aml_ci_io_read_by_spi(ci_dev, 0, COM_STA_REG);
+ pr_dbg("STA_REG = 0x%2.2x\r\n", reg);
+ if (FR & reg) {
+ pr_dbg("SW-RST is OK!\r\n");
+ } else {
+ pr_dbg("SW-RST is ERR!\r\n");
+ goto end;
+ }
+ }
+end:
+ pr_dbg("TO check sw-rst over.\r\n");
+ pr_dbg("\r\n");
+ pr_dbg("-----------------------------------\r\n");
+ pr_dbg("TO buffer size negotiation protocol...\r\n");
+ pr_dbg("Get which buf size CAM can support\r\n");
+ aml_ci_io_write_by_spi(ci_dev, 0, COM_STA_REG, SR);
+ mdelay(1000);
+ while (1) {
+
+ reg = aml_ci_io_read_by_spi(ci_dev, 0, COM_STA_REG);
+ if ((reg & DA) == DA) {
+ pr_dbg("Buffer negotiate size date avalible.\r\n");
+ break;
+ } else {
+ /*pr_dbg("Buffer negotiate
+ size date NOT avalible\r\n");*/
+ continue;
+ }
+ mdelay(100);
+ }
+ cnt = (aml_ci_io_read_by_spi(ci_dev, 0, SIZE_REG_L)) +
+ ((aml_ci_io_read_by_spi(ci_dev, 0, SIZE_REG_M)) * 256);
+ pr_dbg("Moudle have <%d> Bytes send to host.\r\n", cnt);
+ if (cnt != 2) {
+ pr_dbg("The Bytes will be tx is ERR!\r\n");
+ return;
+ }
+ for (i = 0; i < cnt; i++)
+ buf[i] = aml_ci_io_read_by_spi(ci_dev, 0, DATA_REG);
+
+ reg = aml_ci_io_read_by_spi(ci_dev, 0, COM_STA_REG);
+ if (RE == (RE & reg)) {
+ pr_dbg("(1)Read CAM buf size ERR!\r\n");
+ return;
+ }
+ aml_ci_io_write_by_spi(ci_dev, 0, (COM_STA_REG), 0);
+
+ mdelay(1000);
+
+ while (count--) {
+ reg = aml_ci_io_read_by_spi(ci_dev, 0, COM_STA_REG);
+ if (FR != (FR & reg)) {
+ pr_dbg("CAM is busy 2, waiting...\r\n");
+ continue;
+ } else {
+ pr_dbg("CAM is OK 2.\r\n");
+ break;
+ }
+ }
+ reg = aml_ci_io_read_by_spi(ci_dev, 0, COM_STA_REG);
+ if (FR != (FR & reg)) {
+ pr_dbg("(2)Read CAM buf size ERR!-\r\n");
+ return;
+ }
+ bsize = (buf[0] * 256) + buf[1];
+
+ pr_dbg("CAM can support buf size is: <%d>B\r\n", bsize);
+
+ pr_dbg("Tell CAM which size buf is be used\r\n");
+ reg = aml_ci_io_read_by_spi(ci_dev, 0, COM_STA_REG);
+ if (FR != (FR & reg))
+ pr_dbg("CAM is busy, waiting free\r\n");
+ while (1) {
+ reg = aml_ci_io_read_by_spi(ci_dev, 0, COM_STA_REG);
+ if (FR != (FR & reg)) {
+ pr_dbg("CAM is busy 3, waiting\r\n");
+ continue;
+ } else {
+ pr_dbg("CAM is OK 3\r\n");
+ break;
+ }
+ }
+
+ bsize = bsize - 0;
+ BUF_SIZE = bsize;
+ pr_dbg("We will use this buf size: <%d>B\r\n", bsize);
+ aml_ci_io_write_by_spi(ci_dev, 0, COM_STA_REG, SW);
+ reg = aml_ci_io_read_by_spi(ci_dev, 0, COM_STA_REG);
+ if (FR != (FR & reg))
+ pr_dbg("CAM is busy, waiting\r\n");
+
+ while (1) {
+ reg = aml_ci_io_read_by_spi(ci_dev, 0, COM_STA_REG);
+ if (FR != (FR & reg)) {
+ pr_dbg("CAM is busy 4, waiting\r\n");
+ continue;
+ } else {
+ pr_dbg("CAM is OK 4\r\n");
+ break;
+ }
+ }
+ /*SHOULD CHECK DA!!!!!*/
+ /*PLS ADD THIS CHECK CODE:*/
+ pr_dbg("PRIOR to check CAM'S DA\r\n");
+ reg = aml_ci_io_read_by_spi(ci_dev, 0, COM_STA_REG);
+ if ((reg & DA) == DA) {
+ pr_dbg("CAM have data send to HOST\r\n");
+ return;
+ }
+
+
+ buf[0] = (unsigned char)((bsize >> 8) & 0xff);
+ buf[1] = (unsigned char)(bsize & 0xff);
+
+ while (1) {
+ mdelay(10);
+ aml_ci_io_write_by_spi(ci_dev,
+ 0, COM_STA_REG, HC | SW);
+ mdelay(100);
+ reg = aml_ci_io_read_by_spi(ci_dev,
+ 0, COM_STA_REG);
+ if (FR != (FR & reg)) {
+ pr_dbg("CAM is busy 5, waiting\r\n");
+ aml_ci_io_write_by_spi(ci_dev,
+ 0, COM_STA_REG, SW);
+ continue;
+ } else {
+ pr_dbg("CAM is OK 5\r\n");
+ break;
+ }
+ }
+ pr_dbg("<2> Bytes send to CAM\r\n");
+ aml_ci_io_write_by_spi(ci_dev, 0, SIZE_REG_M, 0);
+ aml_ci_io_write_by_spi(ci_dev, 0, SIZE_REG_L, 2);
+ for (i = 0; i < 2; i++)
+ aml_ci_io_write_by_spi(ci_dev, 0, DATA_REG, buf[i]);
+
+ reg = aml_ci_io_read_by_spi(ci_dev, 0, COM_STA_REG);
+ if (WE == (WE & reg)) {
+ pr_dbg("Write CAM ERR!\r\n");
+ return;
+ } else {
+ aml_ci_io_write_by_spi(ci_dev, 0, COM_STA_REG, SW);
+ mdelay(100);
+ aml_ci_io_write_by_spi(ci_dev, 0, COM_STA_REG, 0);
+ pr_dbg("Buffer size negotiation over!\r\n");
+ pr_dbg("NOW, HOST can communicates with CAM\r\n");
+ pr_dbg("NOW, TEST END\r\n");
+ }
+}
+
+/**
+* Read a tuple from attribute memory.
+*
+* @param ca CA instance.
+* @param slot Slot id.
+* @param address Address to read from. Updated.
+* @param tupleType Tuple id byte. Updated.
+* @param tupleLength Tuple length. Updated.
+* @param tuple Dest buffer for tuple (must be 256 bytes). Updated.
+*
+* @return 0 on success, nonzero on error.
+*/
+static int dvb_ca_en50221_read_tuple(
+int *address, int *tupleType, int *tupleLength, u8 *tuple)
+{
+ int i;
+ int _tupleType;
+ int _tupleLength;
+ int _address = *address;
+
+ /* grab the next tuple length and type */
+ _tupleType = aml_ci_mem_read_by_spi((struct aml_ci *)
+ g_spi_dev->priv, 0, _address);
+ if (_tupleType < 0)
+ return _tupleType;
+ if (_tupleType == 0xff) {
+ pr_dbg("END OF CHAIN TUPLE type:0x%x\n", _tupleType);
+ *address += 2;
+ *tupleType = _tupleType;
+ *tupleLength = 0;
+ return 0;
+ }
+ _tupleLength = aml_ci_mem_read_by_spi((struct aml_ci *)
+ g_spi_dev->priv, 0, _address + 2);
+ if (_tupleLength < 0)
+ return _tupleLength;
+ _address += 4;
+
+ pr_dbg("TUPLE type:0x%x length:%i\n", _tupleType, _tupleLength);
+
+ /* read in the whole tuple */
+ for (i = 0; i < _tupleLength; i++) {
+ tuple[i] = aml_ci_mem_read_by_spi((struct aml_ci *)
+ g_spi_dev->priv, 0, _address + (i * 2));
+ pr_dbg(" 0x%02x: 0x%02x %c\n",
+ i, tuple[i] & 0xff,
+ ((tuple[i] > 31) && (tuple[i] < 127)) ? tuple[i] : '.');
+ }
+ _address += (_tupleLength * 2);
+
+ /* success */
+ *tupleType = _tupleType;
+ *tupleLength = _tupleLength;
+ *address = _address;
+ return 0;
+}
+static char *findstr(char *haystack, int hlen, char *needle, int nlen)
+{
+ int i;
+
+ if (hlen < nlen)
+ return NULL;
+
+ for (i = 0; i <= hlen - nlen; i++) {
+ if (!strncmp(haystack + i, needle, nlen))
+ return haystack + i;
+ }
+
+ return NULL;
+}
+
+/**
+* Parse attribute memory of a CAM module, extracting Config register, and checking
+* it is a DVB CAM module.
+*
+* @param ca CA instance.
+* @param slot Slot id.
+*
+* @return 0 on success, <0 on failure.
+*/
+static int dvb_ca_en50221_parse_attributes(void)
+{
+ int address = 0;
+ int tupleLength;
+ int tupleType;
+ u8 tuple[257];
+ char *dvb_str;
+ int rasz;
+ int status;
+ int got_cftableentry = 0;
+ int end_chain = 0;
+ int i;
+ u16 manfid = 0;
+ u16 devid = 0;
+ int config_base = 0;
+ int config_option;
+
+ /* CISTPL_DEVICE_0A */
+ status = dvb_ca_en50221_read_tuple(&address,
+ &tupleType, &tupleLength, tuple);
+ if (status < 0) {
+ pr_error("read status error\r\n");
+ return status;
+ }
+ if (tupleType != 0x1D) {
+ pr_error("read tupleType error [0x%x]\r\n", tupleType);
+ return -EINVAL;
+ }
+
+
+
+ /* CISTPL_DEVICE_0C */
+ status = dvb_ca_en50221_read_tuple(&address,
+ &tupleType, &tupleLength, tuple);
+ if (status < 0) {
+ pr_error("read read cis error\r\n");
+ return status;
+ }
+ if (tupleType != 0x1C) {
+ pr_error("read read cis type error\r\n");
+ return -EINVAL;
+ }
+
+
+
+ /* CISTPL_VERS_1 */
+ status = dvb_ca_en50221_read_tuple(&address,
+ &tupleType, &tupleLength, tuple);
+ if (status < 0) {
+ pr_error("read read cis version error\r\n");
+ return status;
+ }
+ if (tupleType != 0x15) {
+ pr_error("read read cis version type error\r\n");
+ return -EINVAL;
+ }
+
+
+
+ /* CISTPL_MANFID */
+ status = dvb_ca_en50221_read_tuple(&address, &tupleType,
+ &tupleLength, tuple);
+ if (status < 0) {
+ pr_error("read read cis manfid error\r\n");
+ return status;
+ }
+ if (tupleType != 0x20) {
+ pr_error("read read cis manfid type error\r\n");
+ return -EINVAL;
+ }
+ if (tupleLength != 4) {
+ pr_error("read read cis manfid len error\r\n");
+ return -EINVAL;
+ }
+ manfid = (tuple[1] << 8) | tuple[0];
+ devid = (tuple[3] << 8) | tuple[2];
+
+
+
+ /* CISTPL_CONFIG */
+ status = dvb_ca_en50221_read_tuple(&address, &tupleType,
+ &tupleLength, tuple);
+ if (status < 0) {
+ pr_error("read read cis config error\r\n");
+ return status;
+ }
+ if (tupleType != 0x1A) {
+ pr_error("read read cis config type error\r\n");
+ return -EINVAL;
+ }
+ if (tupleLength < 3) {
+ pr_error("read read cis config len error\r\n");
+ return -EINVAL;
+ }
+
+ /* extract the configbase */
+ rasz = tuple[0] & 3;
+ if (tupleLength < (3 + rasz + 14)) {
+ pr_error("read extract the configbase error\r\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < rasz + 1; i++)
+ config_base |= (tuple[2 + i] << (8 * i));
+
+
+ /* check it contains the correct DVB string */
+ dvb_str = findstr((char *)tuple, tupleLength, "DVB_CI_V", 8);
+ if (dvb_str == NULL) {
+ pr_error("find dvb str DVB_CI_V error\r\n");
+ return -EINVAL;
+ }
+ if (tupleLength < ((dvb_str - (char *) tuple) + 12)) {
+ pr_error("find dvb str DVB_CI_V len error\r\n");
+ return -EINVAL;
+ }
+
+ /* is it a version we support? */
+ if (strncmp(dvb_str + 8, "1.00", 4)) {
+ pr_error(" Unsupported DVB CAM module version %c%c%c%c\n",
+ dvb_str[8], dvb_str[9], dvb_str[10], dvb_str[11]);
+ return -EINVAL;
+ }
+
+/* process the CFTABLE_ENTRY tuples, and any after those */
+while ((!end_chain) && (address < 0x1000)) {
+ status = dvb_ca_en50221_read_tuple(&address, &tupleType,
+ &tupleLength, tuple);
+ if (status < 0) {
+ pr_error("process the CFTABLE_ENTRY tuples error\r\n");
+ return status;
+ }
+
+ switch (tupleType) {
+ case 0x1B: /* CISTPL_CFTABLE_ENTRY */
+ if (tupleLength < (2 + 11 + 17))
+ break;
+
+ /* if we've already parsed one, just use it */
+ if (got_cftableentry)
+ break;
+
+ /* get the config option */
+ config_option = tuple[0] & 0x3f;
+
+ /* OK, check it contains the correct strings */
+ if ((findstr((char *)tuple,
+ tupleLength, "DVB_HOST", 8) == NULL) ||
+ (findstr((char *)tuple,
+ tupleLength, "DVB_CI_MODULE", 13) == NULL))
+ break;
+
+
+ got_cftableentry = 1;
+ break;
+
+ case 0x14: /* CISTPL_NO_LINK*/
+ break;
+
+ case 0xFF: /* CISTPL_END */
+ end_chain = 1;
+ break;
+
+ default:
+ /* Unknown tuple type - just skip
+ *this tuple and move to the next one
+ */
+pr_error("Skipping unknown tupletype:0x%x L:0x%x\n",
+ tupleType, tupleLength);
+ break;
+ }
+ }
+
+ if ((address > 0x1000) || (!got_cftableentry)) {
+ pr_error("got_cftableentry :%d\r\n", got_cftableentry);
+ return -EINVAL;
+ }
+
+ pr_error("----------ci cis ok-----\r\n");
+ return 0;
+}
+
+static ssize_t aml_spi_ci_reset_help(struct class *class,
+struct class_attribute *attr, char *buf)
+{
+ int ret;
+ ret = sprintf(buf, "echo 1 > %s\n\t", attr->attr.name);
+ return ret;
+}
+
+static ssize_t aml_spi_ci_reset(struct class *class,
+struct class_attribute *attr, const char *buf, size_t size)
+{
+ int ret;
+ struct aml_ci *ci = (struct aml_ci *)g_spi_dev->priv;
+ ret = aml_ci_slot_reset(ci, 0);
+ return size;
+}
+
+static ssize_t aml_spi_ci_pwr_help(struct class *class,
+struct class_attribute *attr, char *buf)
+{
+ int ret;
+ ret = sprintf(buf, "echo 1|0> %s\n\t", attr->attr.name);
+ return ret;
+}
+
+static ssize_t aml_spi_ci_pwr(struct class *class,
+struct class_attribute *attr, const char *buf, size_t size)
+{
+ int ret = 0;
+ int enable = 0;
+ long value;
+ if (kstrtol(buf, 0, &value) == 0)
+ enable = (int)value;
+ ret = aml_gio_power(&g_spi_dev->pc, enable);
+ return size;
+}
+static ssize_t aml_spi_ci_state_show(struct class *class,
+struct class_attribute *attr, char *buf)
+{
+ int ret;
+ struct aml_ci *ci = (struct aml_ci *)g_spi_dev->priv;
+ ret = aml_ci_slot_status(ci, 0, 0);
+ ret = sprintf(buf, "%s: %d;\n\t", attr->attr.name, ret);
+ return ret;
+}
+
+static ssize_t aml_spi_ci_irq_show(struct class *class,
+struct class_attribute *attr, char *buf)
+{
+ int ret;
+ ret = aml_ci_gio_get_irq();
+ ret = sprintf(buf, "%s irq: %d\n\t", attr->attr.name, ret);
+ return ret;
+}
+
+static ssize_t aml_spi_io_test_help(struct class *class,
+struct class_attribute *attr, char *buf)
+{
+ int ret;
+ ret = sprintf(buf, "echo (r|w|f|c)(i|a) addr data > %s\n",
+ attr->attr.name);
+ return ret;
+}
+
+static ssize_t aml_spi_io_test(struct class *class,
+struct class_attribute *attr, const char *buf, size_t size)
+{
+ int n = 0;
+ int i = 0;
+ char *buf_orig, *ps, *token;
+ char *parm[3];
+ unsigned int addr = 0, val = 0, retval = 0;
+ long value = 0;
+ struct aml_ci *ci = (struct aml_ci *)g_spi_dev->priv;
+ buf_orig = kstrdup(buf, GFP_KERNEL);
+ ps = buf_orig;
+ while (1) {
+ /*need set '\n' to ' \n'*/
+ token = strsep(&ps, " ");
+ if (token == NULL)
+ break;
+ if (*token == '\0')
+ continue;
+ parm[n++] = token;
+ }
+
+ if (!n || ((n > 0) && (strlen(parm[0]) != 2))) {
+ pr_err("invalid command n[%x]p[%x][%s]\n", n,(int)strlen(parm[0]),parm[0]);
+ kfree(buf_orig);
+ return size;
+ }
+
+ if ((parm[0][0] == 'r')) {
+ if (n > 2) {
+ pr_err("read: invalid parameter\n");
+ kfree(buf_orig);
+ return size;
+ }
+ if (kstrtol(parm[1], 0, &value) == 0)
+ addr = (int)value;
+ pr_err("%s 0x%x\n", parm[0], addr);
+ switch ((char)parm[0][1]) {
+ case 'i':
+ for (i = 0; i < 1000; i++)
+ retval = aml_ci_io_read_by_spi(ci, 0, addr);
+ break;
+ case 'a':
+ for (i = 0; i < 1000; i++)
+ retval = aml_ci_mem_read_by_spi(ci, 0, addr);
+ break;
+ default:
+ break;
+ }
+ pr_dbg("%s: 0x%x --> 0x%x\n", parm[0], addr, retval);
+ } else if ((parm[0][0] == 'w')) {
+ if (n != 3) {
+ pr_err("write: invalid parameter\n");
+ kfree(buf_orig);
+ return size;
+ }
+ if (kstrtol(parm[1], 0, &value) == 0)
+ addr = (int)value;
+ if (kstrtol(parm[2], 0, &value) == 0)
+ val = (int)value;
+
+ pr_err("%s 0x%x 0x%x", parm[0], addr, val);
+ /*switch ((char)parm[0][1]) {
+ case 'i':
+retval = aml_ci_io_write_by_spi(ci, 0, addr, val);
+ break;
+ case 'a':
+retval = aml_ci_mem_write_by_spi(ci, 0, addr, val);
+ break;
+ default:
+ break;
+ }*/
+ pr_dbg("%s: 0x%x <-- 0x%x\n", parm[0], addr, retval);
+ } else if ((parm[0][0] == 'f')) {
+ pr_dbg("full test----\r\n");
+ aml_spi_ca_full_test(ci);
+ } else if ((parm[0][0] == 'c')) {
+ pr_dbg("cis test----\r\n");
+ aml_ci_full_test_by_spi(ci, 0, addr);
+ } else if ((parm[0][0] == 'p')) {
+ pr_dbg("cis dvb_ca_en50221_parse_attributes----\r\n");
+ dvb_ca_en50221_parse_attributes();
+ }
+
+ kfree(buf_orig);
+ return size;
+}
+
+static struct class_attribute aml_spi_class_attrs[] = {
+ __ATTR(reset, S_IRUGO | S_IWUSR,
+ aml_spi_ci_reset_help, aml_spi_ci_reset),
+ __ATTR(pwr, S_IRUGO | S_IWUSR,
+ aml_spi_ci_pwr_help, aml_spi_ci_pwr),
+ __ATTR(irq, S_IRUGO | S_IWUSR,
+ aml_spi_ci_irq_show, NULL),
+ __ATTR(status, S_IRUGO | S_IWUSR,
+ aml_spi_ci_state_show, NULL),
+ __ATTR(iotest, S_IRUGO | S_IWUSR,
+ aml_spi_io_test_help, aml_spi_io_test),
+ __ATTR_NULL
+};
+
+static struct class aml_spi_class = {
+ .name = "aml_dvb_spi_test",
+ .class_attrs = aml_spi_class_attrs,
+};
+
+
+/**\brief aml_con_gpio_by_spi:control gpio by spi
+* \param gpio: the value is from AM_CON_GPIO def
+* \param level: 0: set low,1:set hight
+* \return
+* - 0:ok
+* - -EINVAL : error
+*/
+int aml_con_gpio_by_spi(int gpio, int level)
+{
+ u8 data = gpio;
+ u16 addres = level;
+ int value = 0;
+ struct aml_spi *spi_dev = g_spi_dev;
+ /*add by chl,need add time delay*/
+ mdelay(10);
+ aml_init_send_buf(AM_CI_CMD_CONGPIO, data, addres);
+ value = aml_spi_io_api(spi_dev, sendbuf, SENDBUFLEN, AM_CI_CMD_CONGPIO);
+ return value;
+}
+EXPORT_SYMBOL(aml_con_gpio_by_spi);
+
+int aml_spi_mod_init(void)
+{
+ int ret;
+ pr_dbg("Amlogic DVB SPI Init\n");
+ ret = class_register(&aml_spi_class);
+ return 0;
+}
+//EXPORT_SYMBOL(aml_spi_mod_init);
+void aml_spi_mod_exit(void)
+{
+ pr_dbg("Amlogic DVB SPI Exit\n");
+ class_unregister(&aml_spi_class);
+}
+EXPORT_SYMBOL(aml_spi_mod_exit);
+#endif
+#if 0
+module_init(aml_spi_mod_init);
+module_exit(aml_spi_mod_exit);
+
+MODULE_LICENSE("GPL");
+#endif
diff --git a/drivers/stream_input/parser/dvb_ci/aml_spi.h b/drivers/stream_input/parser/dvb_ci/aml_spi.h
new file mode 100644
index 0000000..7a9493e
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/aml_spi.h
@@ -0,0 +1,122 @@
+/*
+* 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_SPI_H_
+#define __AML_SPI_H_
+
+#include <linux/amlogic/aml_gpio_consumer.h>
+#include <linux/gpio/consumer.h>
+#include "aml_pcmcia.h"
+#include "aml_ci.h"
+#include "drivers/media/dvb-core/dvb_ca_en50221.h"
+
+/*
+aml spi dev
+*/
+struct aml_spi {
+ spinlock_t spi_lock;
+
+ /* add SPI DEV */
+ struct spi_board_info *spi_bdinfo;
+ struct spi_device *spi;
+ struct platform_device *pdev;
+ struct device *dev;
+
+ /* spi otherconfig */
+ int cs_hold_delay;
+ int cs_clk_delay;
+ int write_check;
+
+ /* add gpio pin */
+ struct gpio_desc *reset_pin;
+ int reset_pin_value;
+ struct gpio_desc *cd_pin1;
+ int cd_pin1_value;
+ struct gpio_desc *cd_pin2;
+ int cd_pin2_value;
+ struct gpio_desc *pwr_pin;
+ int pwr_pin_value;
+
+ /* cam and mcu irq */
+ struct gpio_desc *irq_cam_pin;
+ int irq_cam_pin_value;
+ int irq;
+ struct aml_pcmcia pc;
+ void *priv;
+ /*for AML_DVB_IO_TYPE_SPI_T312 device*/
+ struct gpio_desc *mcu_irq_pin;
+ int mcu_irq_pin_value;
+ /*device type*/
+ int io_device_type;
+};
+enum aml_gpio_level_e {
+ AML_GPIO_LOW = 0,
+ AML_GPIO_HIGH
+};
+
+/* used to mcu */
+#define DATASTART 0xef
+#define DATAEND 0xfe
+enum AM_CI_CMD {
+ AM_CI_CMD_IOR = 0,
+ AM_CI_CMD_IOW,
+ AM_CI_CMD_MEMR,
+ AM_CI_CMD_MEMW,
+ AM_CI_CMD_FULLTEST,
+ AM_CI_CMD_CISTEST,
+ AM_CI_CMD_GETCD12,
+ AM_CI_CMD_POWER,
+ AM_CI_CMD_RESET,
+ AM_CI_CMD_CONGPIO,
+};
+enum AM_SPI_RECIVERSTEP {
+ AM_SPI_STEP_INIT = 0,
+ AM_SPI_STEP_START1,
+ AM_SPI_STEP_START2,
+ AM_SPI_STEP_CMD,
+ AM_SPI_STEP_DATA,
+ AM_SPI_STEP_ADDR1,
+ AM_SPI_STEP_ADDR2,
+ AM_SPI_STEP_END1,
+ AM_SPI_STEP_END2
+};
+
+enum AM_CON_GPIO
+{
+ AM_CONGPIO_SEL_LVDS = 0,
+ AM_CONGPIO_SCN_EN,
+ AM_CONGPIO_LD_EN2,
+ AM_CONGPIO_2D3D,
+ AM_CONGPIO_AMP_RST,
+};
+
+extern int dirspi_xfer(struct spi_device *spi, u8 *tx_buf, u8 *rx_buf,
+ int len);
+extern int dirspi_write(struct spi_device *spi, u8 *buf, int len);
+extern int dirspi_read(struct spi_device *spi, u8 *buf, int len);
+extern void dirspi_start(struct spi_device *spi);
+extern void dirspi_stop(struct spi_device *spi);
+extern int dirspi_register_board_info(struct spi_board_info const *info, unsigned n);
+extern void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot);
+extern int aml_spi_init(struct platform_device *pdev, struct aml_ci *ci_dev);
+extern int aml_spi_exit(struct aml_ci *ci_dev);
+extern int aml_spi_mod_init(void);
+extern void aml_spi_mod_exit(void);
+
+#endif /* __AML_SPI_H_ */
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/aml_cimax.c b/drivers/stream_input/parser/dvb_ci/cimax/aml_cimax.c
new file mode 100644
index 0000000..a462d88
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/aml_cimax.c
@@ -0,0 +1,293 @@
+
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ *
+***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/of.h>
+#include "../aml_ci.h"
+#include "aml_cimax.h"
+#include "aml_cimax_spi.h"
+#include "aml_cimax_usb.h"
+
+#define MODUDLE_NAME "aml_cimax"
+
+MODULE_PARM_DESC(cimax_debug, "enable verbose debug messages");
+static int aml_cimax_debug = 1;
+module_param_named(cimax_debug, aml_cimax_debug, int, 0644);
+
+//static struct switch_dev slot_state = {
+// .name = "ci_slot",
+//};
+
+#define pr_dbg(fmt...)\
+ do {\
+ if (aml_cimax_debug)\
+ pr_info("AML_CIMAX: " fmt);\
+ } while (0)
+#define pr_error(fmt...) pr_err("AML_CIMAX: " fmt)
+
+static int aml_cimax_slot_reset(struct aml_ci *ci, int slot)
+{
+ int ret = 0;
+ struct aml_cimax *cimax = ci->data;
+ pr_dbg("cimax: slot(%d) reset\n", slot);
+ if (cimax->ops.slot_reset)
+ ret = cimax->ops.slot_reset(cimax, slot);
+ return ret;
+}
+
+static int aml_cimax_slot_shutdown(struct aml_ci *ci, int slot)
+{
+ pr_dbg("slot(%d) shutdown\n", slot);
+ return 0;
+}
+
+static int aml_cimax_slot_ts_enable(struct aml_ci *ci, int slot)
+{
+ pr_dbg("slot(%d) ts control\n", slot);
+ return 0;
+}
+
+static int aml_cimax_slot_status(struct aml_ci *ci, int slot, int open)
+{
+ int ret = 0;
+ struct aml_cimax *cimax = ci->data;
+
+ /*pr_dbg("cimax: slot(%d) poll\n", slot);*/
+ if (cimax->ops.slot_status)
+ ret = cimax->ops.slot_status(cimax, slot);
+ return ret;
+}
+
+#define DEF_FUNC_WRAPPER3(_pre, _fn, _S, _P1, _P2, _P3) \
+static int _pre##_fn(_S s, _P1 p1, _P2 p2, _P3 p3)\
+{\
+ struct aml_cimax *cimax = s->data;\
+ /*pr_dbg("%s\n", #_fn);*/\
+ if (cimax->ops._fn)\
+ return cimax->ops._fn(cimax, p1, p2, p3);\
+ return 0;\
+}
+
+/*DEF_FUNC_WRAPPER3(aml_cimax_, read_reg, struct aml_ci*, int, u8*, int)*/
+/*DEF_FUNC_WRAPPER3(aml_cimax_, write_reg, struct aml_ci*, int, u8*, int)*/
+DEF_FUNC_WRAPPER3(aml_cimax_, read_cis, struct aml_ci*, int, u8*, int)
+DEF_FUNC_WRAPPER3(aml_cimax_, read_lpdu, struct aml_ci*, int, u8*, int)
+DEF_FUNC_WRAPPER3(aml_cimax_, write_lpdu, struct aml_ci*, int, u8*, int)
+
+static int aml_cimax_write_cor(struct aml_ci *ci, int slot, int addr, u8 *buf)
+{
+ struct aml_cimax *cimax = ci->data;
+ pr_dbg("write_cor\n");
+ if (cimax->ops.write_cor)
+ return cimax->ops.write_cor(cimax, slot, addr, buf);
+ return 0;
+}
+
+static int aml_cimax_negotiate(struct aml_ci *ci, int slot, int size)
+{
+ struct aml_cimax *cimax = ci->data;
+ pr_dbg("negotiate\n");
+ if (cimax->ops.negotiate)
+ return cimax->ops.negotiate(cimax, slot, size);
+ return 0;
+}
+
+static int aml_cimax_read_cam_status(struct aml_ci *ci, int slot)
+{
+ struct aml_cimax *cimax = ci->data;
+ if (cimax->ops.read_cam_status)
+ return cimax->ops.read_cam_status(cimax, slot);
+ return 0;
+}
+
+static int aml_cimax_cam_reset(struct aml_ci *ci, int slot)
+{
+ struct aml_cimax *cimax = ci->data;
+ if (cimax->ops.cam_reset)
+ return cimax->ops.cam_reset(cimax, slot);
+ return 0;
+}
+
+static int aml_cimax_get_capbility(struct aml_ci *ci, int slot)
+{
+ return 0;
+}
+
+int aml_cimax_camchanged(struct aml_cimax *cimax, int slot, int plugin)
+{
+ struct aml_ci *ci = cimax->ci;
+ if (plugin) {
+ dvb_ca_en50221_cimax_camchange_irq(&ci->en50221_cimax,
+ slot, DVB_CA_EN50221_CAMCHANGE_INSERTED);
+ } else {
+ dvb_ca_en50221_cimax_camchange_irq(&ci->en50221_cimax,
+ slot, DVB_CA_EN50221_CAMCHANGE_REMOVED);
+ }
+ return 0;
+}
+
+static int aml_cimax_start(struct aml_cimax *cimax)
+{
+ int ret = 0;
+ if (cimax->ops.start)
+ ret = cimax->ops.start(cimax);
+ return ret;
+}
+
+static int aml_cimax_stop(struct aml_cimax *cimax)
+{
+ int ret = 0;
+ if (cimax->ops.stop)
+ ret = cimax->ops.stop(cimax);
+ return ret;
+}
+
+static int aml_cimax_get_config_from_dts(struct aml_cimax *cimax)
+{
+ struct device_node *child = NULL;
+ struct platform_device *pdev = cimax->pdev;
+ struct device_node *np = pdev->dev.of_node;
+ unsigned int val;
+ int ret = 0;
+ pr_dbg("get cimax dts\n");
+
+ child = of_get_child_by_name(np, "cimax");
+ if (child == NULL) {
+ pr_error("failed to get cimax\n");
+ return -1;
+ }
+ ret = of_property_read_u32(child, "io_type", &val);
+ if (ret)
+ cimax->io_type = IO_TYPE_SPI;
+ else
+ cimax->io_type = val;
+
+ return 0;
+}
+
+int aml_cimax_init(struct platform_device *pdev, struct aml_ci *ci)
+{
+ struct aml_cimax *cimax = NULL;
+ int ret = 0;
+
+ cimax = kzalloc(sizeof(struct aml_cimax), GFP_KERNEL);
+ if (!cimax) {
+ pr_error("Out of memory!, exiting ..\n");
+ return -ENOMEM;
+ }
+ cimax->pdev = pdev;
+ cimax->ci = ci;
+
+ aml_cimax_get_config_from_dts(cimax);
+
+ if (cimax->io_type == IO_TYPE_SPI) {
+ //ret = aml_cimax_spi_init(pdev, cimax);
+ }
+ else {
+ ret = aml_cimax_usb_init(pdev, cimax);
+ }
+
+ if (ret != 0) {
+ kfree(cimax);
+ cimax = NULL;
+ return -EIO;
+ }
+
+ ret = aml_cimax_start(cimax);
+ if (ret != 0)
+ return ret;
+
+ ci->data = cimax;
+
+ ci->ci_read_cis = aml_cimax_read_cis;
+ ci->ci_write_cor = aml_cimax_write_cor;
+ ci->ci_negotiate = aml_cimax_negotiate;
+ ci->ci_read_lpdu = aml_cimax_read_lpdu;
+ ci->ci_write_lpdu = aml_cimax_write_lpdu;
+ ci->ci_read_cam_status = aml_cimax_read_cam_status;
+ ci->ci_cam_reset = aml_cimax_cam_reset;
+ ci->ci_get_capbility = aml_cimax_get_capbility;
+ ci->ci_slot_reset = aml_cimax_slot_reset;
+ ci->ci_slot_shutdown = aml_cimax_slot_shutdown;
+ ci->ci_slot_ts_enable = aml_cimax_slot_ts_enable;
+ ci->ci_poll_slot_status = aml_cimax_slot_status;
+
+ return 0;
+}
+EXPORT_SYMBOL(aml_cimax_init);
+
+int aml_cimax_exit(struct aml_ci *ci)
+{
+ struct aml_cimax *cimax = ci->data;
+
+ ci->ci_read_cis = NULL;
+ ci->ci_write_cor = NULL;
+ ci->ci_negotiate = NULL;
+ ci->ci_read_lpdu = NULL;
+ ci->ci_write_lpdu = NULL;
+ ci->ci_read_cam_status = NULL;
+ ci->ci_cam_reset = NULL;
+ ci->ci_get_capbility = NULL;
+ ci->ci_slot_reset = NULL;
+ ci->ci_slot_shutdown = NULL;
+ ci->ci_slot_ts_enable = NULL;
+ ci->ci_poll_slot_status = NULL;
+
+ aml_cimax_stop(cimax);
+
+ if (cimax->io_type == IO_TYPE_SPI) {
+ //aml_cimax_spi_exit(cimax);
+ }
+ else {
+ aml_cimax_usb_exit(cimax);
+ }
+ kfree(cimax);
+ ci->data = NULL;
+
+ return 0;
+}
+EXPORT_SYMBOL(aml_cimax_exit);
+
+int aml_cimax_slot_state_changed(struct aml_cimax *cimax, int slot, int state)
+{
+ //if (slot == 0)
+ // switch_set_state(&slot_state, state);
+ return 0;
+}
+EXPORT_SYMBOL(aml_cimax_slot_state_changed);
+#if 0
+static int __init aml_cimax_mod_init(void)
+{
+ pr_dbg("Amlogic DVB CIMAX Init\n");
+ //switch_dev_register(&slot_state);
+ //switch_set_state(&slot_state, 0);
+ return 0;
+}
+
+static void __exit aml_cimax_mod_exit(void)
+{
+ pr_dbg("Amlogic DVB CIMAX Exit\n");
+ //switch_dev_unregister(&slot_state);
+}
+
+module_init(aml_cimax_mod_init);
+module_exit(aml_cimax_mod_exit);
+
+MODULE_LICENSE("GPL");
+#endif
+
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/aml_cimax.h b/drivers/stream_input/parser/dvb_ci/cimax/aml_cimax.h
new file mode 100644
index 0000000..17c62fa
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/aml_cimax.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ *
+***************************************************************************/
+
+#ifndef __AML_CIMAX_H_
+#define __AML_CIMAX_H_
+
+#include "../aml_ci.h"
+#include "dvb_ca_en50221_cimax.h"
+
+struct aml_cimax;
+
+struct aml_cimax_ops {
+ int (*read_cis)(struct aml_cimax *cimax, int slot, u8 *buf, int size);
+ int (*write_cor)(struct aml_cimax *cimax,
+ int slot, int address, u8 *buf);
+ int (*negotiate)(struct aml_cimax *cimax, int slot, int size);
+ int (*read_lpdu)(struct aml_cimax *cimax, int slot, u8 *buf, int size);
+ int (*write_lpdu)(struct aml_cimax *cimax, int slot, u8 *buf, int size);
+ int (*read_cam_status)(struct aml_cimax *cimax, int slot);
+ int (*cam_reset)(struct aml_cimax *cimax, int slot);
+ int (*get_capblility)(struct aml_cimax *cimax, int slot);
+
+ int (*slot_reset)(struct aml_cimax *cimax, int slot);
+ int (*slot_shutdown)(struct aml_cimax *cimax, int slot);
+ int (*slot_ts_enable)(struct aml_cimax *cimax, int slot);
+ int (*slot_status)(struct aml_cimax *cimax, int slot);
+
+ /*load fw etc.*/
+ int (*start)(struct aml_cimax *cimax);
+ int (*stop)(struct aml_cimax *cimax);
+
+ /*cimax reg*/
+ int (*read_reg)(struct aml_cimax *cimax, int addr, u8 *buf, int size);
+ int (*write_reg)(struct aml_cimax *cimax, int addr, u8 *buf, int size);
+};
+
+struct aml_cimax {
+ struct platform_device *pdev;
+ struct device *dev;
+ struct aml_ci *ci;
+
+ int io_type;
+#define IO_TYPE_SPI 0
+#define IO_TYPE_USB 1
+ struct aml_cimax_ops ops;
+ void *priv;
+};
+
+int aml_cimax_init(struct platform_device *pdev, struct aml_ci *ci_dev);
+int aml_cimax_exit(struct aml_ci *ci_dev);
+
+int aml_cimax_camchanged(struct aml_cimax *cimax, int slot, int plugin);
+int aml_cimax_slot_state_changed(struct aml_cimax *cimax, int slot, int state);
+#endif
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/aml_cimax_spi.c b/drivers/stream_input/parser/dvb_ci/cimax/aml_cimax_spi.c
new file mode 100644
index 0000000..a4aadda
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/aml_cimax_spi.c
@@ -0,0 +1,2139 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ *
+***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/amlogic/aml_gpio_consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/amlogic/sd.h>
+#include <linux/of_irq.h>
+#include <linux/irq.h>
+#include <linux/mutex.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+
+#include "aml_cimax.h"
+
+#define MOD_NAME "aml_cimax_spi"
+
+#define pr_dbg(fmt...)\
+ do {\
+ if (cimax_spi_debug)\
+ pr_info("cimax_spi: "fmt);\
+ } while (0)
+#define pr_error(fmt...) pr_err("AML_CIMAX_SPI: " fmt)
+
+#define BUFFIN_CFG 0x0000
+#define BUFFIN_ADDR_LSB 0x0001
+#define BUFFIN_ADDR_MSB 0x0002
+#define BUFFIN_DATA 0x0003
+#define BUFFOUT_CFG 0x0004
+#define BUFFOUT_ADDR_LSB 0x0005
+#define BUFFOUT_ADDR_MSB 0x0006
+#define BUFFOUT_DATA 0x0007
+#define BOOT_Key 0x0008
+#define BOOT_Status 0x0009
+#define BOOT_Test 0x000A
+#define usb2_0_irq_mask 0x0010
+#define usb2_0_status 0x0011
+#define usb2_0_rx 0x0012
+#define usb2_0_tx 0x0013
+#define SPI_Slave_Ctrl 0x0018
+#define SPI_Slave_Status 0x0019
+#define SPI_Slave_Rx 0x001A
+#define SPI_Slave_Tx 0x001B
+#define SPI_Slave_Mask 0x001C
+#define UCSG_Ctrl 0x0020
+#define UCSG_Status 0x0021
+#define UCSG_RxData 0x0022
+#define UCSG_TxData 0x0023
+#define PCtrl_Ctrl 0x0028
+#define PCtrl_Status 0x0029
+#define PCtrl_NbByte_LSB 0x002A
+#define PCtrl_NbByte_MSB 0x002B
+#define SPI_Master_Ctl 0x0030
+#define SPI_Master_NCS 0x0031
+#define SPI_Master_Status 0x0032
+#define SPI_Master_TxBuf 0x0033
+#define SPI_Master_RxBuf 0x0034
+#define BISTRAM_Ctl 0x0038
+#define BISTRAM_Bank 0x0039
+#define BISTRAM_Pat 0x003A
+#define BISTRAM_SM 0x003B
+#define BISTRAM_AddrLSB 0x003C
+#define BISTROM_Config 0x0040
+#define BISTROM_SignatureLSB 0x0041
+#define BISTROM_SignatureMSB 0x0042
+#define BISTROM_StartAddrLSB 0x0043
+#define BISTROM_StartAddrMSB 0x0043
+#define BISTROM_StopAddrLSB 0x0043
+#define BISTROM_StopAddrMSB 0x0043
+#define CkMan_Config 0x0048
+#define CkMan_Select 0x0049
+#define CkMan_Test 0x004A
+#define Revision_Number 0x004B
+#define ResMan_Config 0x0050
+#define ResMan_Status 0x0051
+#define ResMan_WD 0x0052
+#define ResMan_WD_MSB 0x0053
+#define CPU_Test 0x0060
+#define IrqMan_Config0 0x0068
+#define IrqMan_Config1 0x0069
+#define IrqMan_Irq0 0x006A
+#define IrqMan_NMI 0x006B
+#define IrqMan_SleepKey 0x006C
+#define Tim_Config 0x0070
+#define Tim_Value_LSB 0x0071
+#define Tim_Value_MSB 0x0072
+#define Tim_Comp_LSB 0x0073
+#define Tim_Comp_MSB 0x0074
+#define TI_Config 0x0076
+#define TI_Data 0x0077
+#define TI_Reg0 0x0078
+#define TI_Reg1 0x0079
+#define TI_Reg2 0x007A
+#define TI_Reg3 0x007B
+#define TI_Reg4 0x007C
+#define TI_ROM1 0x007D
+#define TI_ROM2 0x007E
+#define TI_ROM3 0x007F
+#define DVBCI_START_ADDR 0x0100
+#define DVBCI_END_ADDR 0x017F
+#define DATA 0x0180
+/*#define CTRL 0x0181*/
+#define QB_HOST 0x0182
+#define LEN_HOST_LSB 0x0183
+#define LEN_HOST_MSB 0x0184
+#define FIFO_TX_TH_LSB 0x0185
+#define FIFO_TX_TH_MSB 0x0186
+#define FIFO_TX_D_NB_LSB 0x0187
+#define FIFO_TX_D_NB_MSB 0x0188
+#define QB_MOD_CURR 0x0189
+#define LEN_MOD_CURR_LSB 0x018A
+#define LEN_MOD_CURR_MSB 0x018B
+#define QB_MOD 0x018C
+#define LEN_MOD_LSB 0x018D
+#define LEN_MOD_MSB 0x018E
+#define FIFO_RX_TH_LSB 0x018F
+#define FIFO_RX_TH_MSB 0x0190
+#define FIFO_RX_D_NB_LSB 0x0191
+#define FIFO_RX_D_NB_MSB 0x0192
+#define IT_STATUS_0 0x0193
+#define IT_STATUS_1 0x0194
+#define IT_MASK_0 0x0195
+#define IT_MASK_1 0x0196
+#define IT_HOST_PIN_CFG 0x0200
+#define CFG_0 0x0201
+#define CFG_1 0x0202
+#define CFG_2 0x0203
+#define IT_HOST 0x0204
+#define MOD_IT_STATUS 0x0205
+#define MOD_IT_MASK 0x0206
+#define MOD_CTRL_A 0x0207
+#define MOD_CTRL_B 0x0208
+#define DEST_SEL 0x0209
+#define CAM_MSB_ADD 0x020A
+#define GPIO0_DIR 0x020B
+#define GPIO0_DATA_IN 0x020C
+#define GPIO0_DATA_OUT 0x020D
+#define GPIO0_STATUS 0x020E
+#define GPIO0_IT_MASK 0x020F
+#define GPIO0_DFT 0x0210
+#define GPIO0_MASK_DATA 0x0211
+#define GPIO1_DIR 0x0212
+#define GPIO1_DATA_IN 0x0213
+#define GPIO1_DATA_OUT 0x0214
+#define GPIO1_STATUS 0x0215
+#define GPIO1_IT_MASK 0x0216
+#define MEM_ACC_TIME_A 0x0217
+#define MEM_ACC_TIME_B 0x0218
+#define IO_ACC_TIME_A 0x0219
+#define IO_ACC_TIME_B 0x021A
+#define EXT_CH_ACC_TIME_A 0x021B
+#define EXT_CH_ACC_TIME_B 0x021C
+#define PAR_IF_0 0x021D
+#define PAR_IF_1 0x021E
+#define PAR_IF_CTRL 0x021F
+#define PCK_LENGTH 0x0220
+#define USB2TS_CTRL 0x0221
+#define USB2TS0_RDL 0x0222
+#define USB2TS1_RDL 0x0223
+#define TS2USB_CTRL 0x0224
+#define TSOUT_PAR_CTRL 0x0225
+#define TSOUT_PAR_CLK_SEL 0x0226
+#define S2P_CH0_CTRL 0x0227
+#define S2P_CH1_CTRL 0x0228
+#define P2S_CH0_CTRL 0x0229
+#define P2S_CH1_CTRL 0x022A
+#define TS_IT_STATUS 0x022B
+#define TS_IT_MASK 0x022C
+#define IN_SEL 0x022D
+#define OUT_SEL 0x022E
+#define ROUTER_CAM_CH 0x022F
+#define ROUTER_CAM_MOD 0x0230
+#define FIFO_CTRL 0x0231
+#define FIFO1_2_STATUS 0x0232
+#define FIFO3_4_STATUS 0x0233
+#define GAP_REMOVER_CH0_CTRL 0x0234
+#define GAP_REMOVER_CH1_CTRL 0x0235
+#define SYNC_RTV_CTRL 0x0236
+#define SYNC_RTV_CH0_SYNC_NB 0x0237
+#define SYNC_RTV_CH0_PATTERN 0x0238
+#define SYNC_RTV_CH1_SYNC_NB 0x0239
+#define SYNC_RTV_CH1_PATTERN 0x023A
+#define SYNC_RTV_OFFSET_PATT 0x023B
+#define CTRL_FILTER 0x023D
+#define PID_EN_FILTER_CH0 0x023E
+#define PID_EN_FILTER_CH1 0x023F
+#define PID_LSB_FILTER_CH0_0 0x0240
+#define PID_MSB_FILTER_CH0_0 0x0241
+#define PID_LSB_FILTER_CH0_1 0x0242
+#define PID_MSB_FILTER_CH0_1 0x0243
+#define PID_LSB_FILTER_CH0_2 0x0244
+#define PID_MSB_FILTER_CH0_2 0x0245
+#define PID_LSB_FILTER_CH0_3 0x0246
+#define PID_MSB_FILTER_CH0_3 0x0247
+#define PID_LSB_FILTER_CH0_4 0x0248
+#define PID_MSB_FILTER_CH0_4 0x0249
+#define PID_LSB_FILTER_CH0_5 0x024A
+#define PID_MSB_FILTER_CH0_5 0x024B
+#define PID_LSB_FILTER_CH0_6 0x024C
+#define PID_MSB_FILTER_CH0_6 0x024D
+#define PID_LSB_FILTER_CH0_7 0x024E
+#define PID_MSB_FILTER_CH0_7 0x024F
+#define PID_LSB_FILTER_CH1_0 0x0260
+#define PID_MSB_FILTER_CH1_0 0x0261
+#define PID_LSB_FILTER_CH1_1 0x0262
+#define PID_MSB_FILTER_CH1_1 0x0263
+#define PID_LSB_FILTER_CH1_2 0x0264
+#define PID_MSB_FILTER_CH1_2 0x0265
+#define PID_LSB_FILTER_CH1_3 0x0266
+#define PID_MSB_FILTER_CH1_3 0x0267
+#define PID_LSB_FILTER_CH1_4 0x0268
+#define PID_MSB_FILTER_CH1_4 0x0269
+#define PID_LSB_FILTER_CH1_5 0x026A
+#define PID_MSB_FILTER_CH1_5 0x026B
+#define PID_LSB_FILTER_CH1_6 0x026C
+#define PID_MSB_FILTER_CH1_6 0x026D
+#define PID_LSB_FILTER_CH1_7 0x026E
+#define PID_MSB_FILTER_CH1_7 0x026F
+#define PID_OLD_LSB_REMAPPER_0 0x0280
+#define PID_OLD_MSB_REMAPPER_0 0x0281
+#define PID_OLD_LSB_REMAPPER_1 0x0282
+#define PID_OLD_MSB_REMAPPER_1 0x0283
+#define PID_OLD_LSB_REMAPPER_2 0x0284
+#define PID_OLD_MSB_REMAPPER_2 0x0285
+#define PID_OLD_LSB_REMAPPER_3 0x0286
+#define PID_OLD_MSB_REMAPPER_3 0x0287
+#define PID_OLD_LSB_REMAPPER_4 0x0288
+#define PID_OLD_MSB_REMAPPER_4 0x0289
+#define PID_OLD_LSB_REMAPPER_5 0x028A
+#define PID_OLD_MSB_REMAPPER_5 0x028B
+#define PID_OLD_LSB_REMAPPER_6 0x028C
+#define PID_OLD_MSB_REMAPPER_6 0x028D
+#define PID_OLD_LSB_REMAPPER_7 0x028E
+#define PID_OLD_MSB_REMAPPER_7 0x028F
+#define PID_NEW_LSB_REMAPPER_0 0x02A0
+#define PID_NEW_MSB_REMAPPER_0 0x02A1
+#define PID_NEW_LSB_REMAPPER_1 0x02A2
+#define PID_NEW_MSB_REMAPPER_1 0x02A3
+#define PID_NEW_LSB_REMAPPER_2 0x02A4
+#define PID_NEW_MSB_REMAPPER_2 0x02A5
+#define PID_NEW_LSB_REMAPPER_3 0x02A6
+#define PID_NEW_MSB_REMAPPER_3 0x02A7
+#define PID_NEW_LSB_REMAPPER_4 0x02A8
+#define PID_NEW_MSB_REMAPPER_4 0x02A9
+#define PID_NEW_LSB_REMAPPER_5 0x02AA
+#define PID_NEW_MSB_REMAPPER_5 0x02AB
+#define PID_NEW_LSB_REMAPPER_6 0x02AC
+#define PID_NEW_MSB_REMAPPER_6 0x02AD
+#define PID_NEW_LSB_REMAPPER_7 0x02AE
+#define PID_NEW_MSB_REMAPPER_7 0x02AF
+#define MERGER_DIV_MICLK 0x02C0
+#define PID_AND_SYNC_REMAPPER_CTRL 0x02C1
+#define PID_EN_REMAPPER 0x02C2
+#define SYNC_SYMBOL 0x02C3
+#define PID_AND_SYNC_REMAPPER_INV_CTRL 0x02C4
+#define BITRATE_CH0_LSB 0x02C5
+#define BITRATE_CH0_MSB 0x02C6
+#define BITRATE_CH1_LSB 0x02C7
+#define BITRATE_CH1_MSB 0x02C8
+#define STATUS_CLK_SWITCH_0 0x02C9
+#define STATUS_CLK_SWITCH_1 0x02CA
+#define RESET_CLK_SWITCH_0 0x02CB
+#define RESET_CLK_SWITCH_1 0x02CC
+#define PAD_DRVSTR_CTRL 0x02CD
+#define PAD_PUPD_CTRL 0x02CE
+#define PRE_HEADER_ADDER_CH0_0 0x02D0
+#define PRE_HEADER_ADDER_CH0_1 0x02D1
+#define PRE_HEADER_ADDER_CH0_2 0x02D2
+#define PRE_HEADER_ADDER_CH0_3 0x02D3
+#define PRE_HEADER_ADDER_CH0_4 0x02D4
+#define PRE_HEADER_ADDER_CH0_5 0x02D5
+#define PRE_HEADER_ADDER_CH0_6 0x02D6
+#define PRE_HEADER_ADDER_CH0_7 0x02D7
+#define PRE_HEADER_ADDER_CH0_8 0x02D8
+#define PRE_HEADER_ADDER_CH0_9 0x02D9
+#define PRE_HEADER_ADDER_CH0_10 0x02DA
+#define PRE_HEADER_ADDER_CH0_11 0x02DB
+#define PRE_HEADER_ADDER_CH1_0 0x02E0
+#define PRE_HEADER_ADDER_CH1_1 0x02E1
+#define PRE_HEADER_ADDER_CH1_2 0x02E2
+#define PRE_HEADER_ADDER_CH1_3 0x02E3
+#define PRE_HEADER_ADDER_CH1_4 0x02E4
+#define PRE_HEADER_ADDER_CH1_5 0x02E5
+#define PRE_HEADER_ADDER_CH1_6 0x02E6
+#define PRE_HEADER_ADDER_CH1_7 0x02E7
+#define PRE_HEADER_ADDER_CH1_8 0x02E8
+#define PRE_HEADER_ADDER_CH1_9 0x02E9
+#define PRE_HEADER_ADDER_CH1_10 0x02EA
+#define PRE_HEADER_ADDER_CH1_11 0x02EB
+#define PRE_HEADER_ADDER_CTRL 0x02EC
+#define PRE_HEADER_ADDER_LEN 0x02ED
+#define PRE_HEADER_REMOVER_CTRL 0x02EE
+#define FSM_DVB 0x02F0
+#define TS2USB_FSM_DEBUG 0x02F2
+#define TSOUT_PAR_FSM_DEBUG 0x02F3
+#define GAP_REMOVER_FSM_DEBUG 0x02F4
+#define PID_AND_SYNC_REMAPPER_FSM_DEBUG 0x02F5
+#define PRE_HEADER_ADDER_FSM_DEBUG 0x02F6
+#define SYNC_RTV_FSM_DEBUG 0x02F7
+#define CHECK_PHY_CLK 0x0E00
+#define USB_CTRL1 0x0E01
+#define USB_ISO2_out 0x0800
+#define USB_ISO1_out 0x1000
+#define USB_Interrupt_out 0x1E00
+#define USB_Bulk_in 0x1F00
+#define CC2_Buffer_out 0x2000
+#define USB_EP0 0x30C0
+#define CC2_Buffer_in 0x4000
+#define USB_ISO2_in 0x5800
+#define USB_ISO1_in 0x6000
+#define nmb_vector_address_lsb 0xFFFA
+#define nmb_vector_address_msb 0xFFFB
+#define reset_vector_address_lsb 0xFFFC
+#define reset_vector_address_msb 0xFFFD
+#define irb_vector_address_lsb 0xFFFE
+#define irb_vector_address_msb 0xFFFF
+
+
+#define CIMAX_REG_HDR_SIZE 4
+#define CIMAX_REG_PLD_SIZE 255
+#define CIMAX_CAM_HDR_SIZE 4
+#define CIMAX_CAM_PLD_SIZE 65535
+
+#define DEF_LOCK(_l_) struct mutex _l_
+
+struct cimax_spi {
+ struct platform_device *pdev;
+ struct spi_device *dev;
+
+ struct aml_cimax *cimax;
+
+ u8 buf[CIMAX_REG_HDR_SIZE + CIMAX_CAM_HDR_SIZE + CIMAX_CAM_PLD_SIZE];
+
+ int cam_inserted[2];
+ int cam_data_ready[2];
+
+ int poll_mode;
+#define STOP_MODE 0
+#define POLL_MODE 1
+#define INT_MODE 2
+
+ int irq;
+ int irq_io;
+ int rst_io;
+
+ struct workqueue_struct *workq;
+ struct delayed_work work;
+ int work_cnt;
+
+ DEF_LOCK(lock);
+#define lock_init(_spi) mutex_init(&(_spi)->lock)
+#define lock_lock(_spi) do {\
+ int err = mutex_lock_interruptible(&(_spi)->lock);\
+ if (err)\
+ return err;\
+} while (0)
+#define lock_unlock(_spi) mutex_unlock(&(_spi)->lock)
+
+ u8 *cis;
+#define CIS_MAX 512
+};
+
+static struct cimax_spi *g_spi;
+
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+static int cimax_spi_debug = 1;
+module_param_named(debug, cimax_spi_debug, int, 0644);
+
+MODULE_PARM_DESC(poll_interval, "interval for spi poll");
+static int spi_poll_interval = 100;
+module_param_named(poll_interval, spi_poll_interval, int, 0644);
+
+MODULE_PARM_DESC(poll_mode, "set cimax poll mode, need reset");
+static int cimax_poll_mode = 1;
+module_param_named(poll_mode, cimax_poll_mode, int, 0644);
+
+MODULE_PARM_DESC(cam_irq_mode, "set cam irq mode, need reset");
+static int cam_irq_mode;
+module_param_named(cam_irq_mode, cam_irq_mode, int, 0644);
+
+#define CIMAX_REG_READ 0xff
+#define CIMAX_REG_READ_OK 0x4c
+#define CIMAX_REG_WRITE 0x7f
+#define CIMAX_REG_WRITE_OK 0x4d
+#define CIMAX_REG_INIT 0x00
+#define CIMAX_REG_INIT_OK 0x4b
+#define CIMAX_REG_CMD_ERROR 0x51
+
+#define CIMAX_CAM_RESET 0x01
+#define CIMAX_CAM_RESET_OK 0x40
+#define CIMAX_CAM_CIS 0x02
+#define CIMAX_CAM_CIS_OK 0x41
+#define CIMAX_CAM_COR 0x03
+#define CIMAX_CAM_COR_OK 0x42
+#define CIMAX_CAM_NEG 0x04
+#define CIMAX_CAM_NEG_OK 0x43
+#define CIMAX_CAM_WLPDU 0x05
+#define CIMAX_CAM_WLPDU_OK 0x44
+#define CIMAX_CAM_RLPDU 0x06
+#define CIMAX_CAM_RLPDU_OK 0x46
+#define CIMAX_CAM_EVT 0x0d
+#define CIMAX_CAM_DET_OK 0x45
+#define CIMAX_CAM_NOCAM 0x49
+#define CIMAX_CAM_ERROR 0x4a
+#define CIMAX_CAM_NOEVT 0x55
+#define CIMAX_CAM_DATA_READY 0x4e
+#define CIMAX_CAM_WBUSY 0x54
+#define CIMAX_CAM_PENDING 0x56
+#define CIMAX_CAM_REGSTAT 0x0e
+#define CIMAX_CAM_REGSTAT_OK 0x57
+
+
+#define CIMAX_CAM_PKT_CNT_VAL 1
+
+#define CIMAX_SLOT_A 0
+#define CIMAX_SLOT_B 1
+
+#define CIMAX_CMD_RESP_MASK 0x7f
+
+#define cimax_to_spi(_c) ((struct cimax_spi *)((_c)->priv))
+#define dev_to_spi(_d) ((struct cimax_spi *)spi_get_drvdata(_d))
+
+#define byte_to_u16(_b1, _b2) (((_b1)<<8) | (_b2))
+
+#define hdr_cmd_resp(_s) ((_s)->buf[0] & CIMAX_CMD_RESP_MASK)
+
+#define reg_hdr(_s) ((_s)->buf)
+#define reg_addr(_s) byte_to_u16((_s)->buf[1], (_s)->buf[2])
+#define reg_hdr_dat_size(_s) ((_s)->buf[3])
+#define reg_dat(_s) (&((_s)->buf[CIMAX_REG_HDR_SIZE]))
+
+#define cam_hdr(_s) ((_s)->buf)
+#define cam_hdr_slot(_s) (((_s)->buf[0] & 0x80) ? 1 : 0)
+#define cam_hdr_pkt_cnt(_s) ((_s)->buf[1])
+#define cam_hdr_dat_size(_s) byte_to_u16((_s)->buf[2], (_s)->buf[3])
+#define cam_dat(_s) (&((_s)->buf[CIMAX_CAM_HDR_SIZE]))
+
+#define REG_TIMEOUT 500
+#define CAM_TIMEOUT 5000
+
+#define USE_INT_PIO
+
+static int aml_cimax_spi_mod_init(void);
+static void aml_cimax_spi_mod_exit(void);
+
+static void dump(char *title, u8 *buf, int size)
+{
+ int i;
+ pr_info("%s\n", title);
+ for (i = 0; i < size; i++) {
+ if (!(i & 0xf))
+ pr_info("\n\t");
+ pr_info("%02x ", *(buf+i));
+ }
+ pr_info("\n");
+}
+
+static void perr(char *err, struct cimax_spi *spi)
+{
+ pr_error("error: %s\n", err);
+ dump("dump:", spi->buf, 16);
+}
+
+static inline unsigned long get_jiffies(void)
+{
+ return (unsigned long)(sched_clock()/10000000);
+}
+
+static inline void set_spi_cam_ready(struct cimax_spi *spi, int slot)
+{
+ if (spi->cam_inserted[slot] == 1) {
+ spi->cam_inserted[slot] = 2;
+ aml_cimax_slot_state_changed(spi->cimax,
+ slot, spi->cam_inserted[slot]);
+ }
+}
+
+
+static int cimax_spi_get_resp(struct cimax_spi *spi, int timeout)
+{
+ struct spi_device *dev = spi->dev;
+ int ret = 0;
+ unsigned long start = get_jiffies();
+#ifndef USE_INT_PIO
+ u8 t = 0;
+
+ while (!t && jiffies_to_msecs(get_jiffies() - start) < timeout) {
+ ret = spi_read(dev, &t, 1);
+ if (ret)
+ return ret;
+ usleep_range(1000, 2000);
+ }
+ if (!t) {
+ pr_error("resp timeout: %dms\n", timeout);
+ return -EIO;
+ }
+ cam_hdr(spi)[0] = t;
+ ret = spi_read(dev, cam_hdr(spi)+1, CIMAX_CAM_HDR_SIZE-1);
+ if (ret)
+ return ret;
+#else
+ do {
+ if (jiffies_to_msecs(get_jiffies() - start) >= timeout) {
+ pr_error("resp timeout: %dms\n", timeout);
+ return -EIO;
+ }
+ usleep_range(1000, 2000);
+ } while (gpio_get_value(spi->irq_io));
+
+ ret = spi_read(dev, cam_hdr(spi), CIMAX_CAM_HDR_SIZE);
+ if (ret)
+ return ret;
+#endif
+ /*pr_dbg("rp: %02x:%02x:%02x:%02x\n",
+ cam_hdr(spi)[0], cam_hdr(spi)[1],
+ cam_hdr(spi)[2], cam_hdr(spi)[3]);*/
+ switch (hdr_cmd_resp(spi)) {
+ case CIMAX_REG_READ_OK:
+ case CIMAX_REG_WRITE_OK:
+ case CIMAX_REG_INIT_OK:
+ case CIMAX_REG_CMD_ERROR: {
+ int len = reg_hdr_dat_size(spi);
+ if (len) {
+ ret = spi_read(dev, reg_dat(spi), len);
+ if (ret != 0)
+ return ret;
+ }
+ } break;
+ case CIMAX_CAM_RESET_OK:
+ case CIMAX_CAM_CIS_OK:
+ case CIMAX_CAM_COR_OK:
+ case CIMAX_CAM_NEG_OK:
+ case CIMAX_CAM_WLPDU_OK:
+ case CIMAX_CAM_RLPDU_OK:
+ case CIMAX_CAM_NOCAM:
+ case CIMAX_CAM_ERROR:
+ case CIMAX_CAM_WBUSY:
+ case CIMAX_CAM_DET_OK:
+ case CIMAX_CAM_DATA_READY:
+ case CIMAX_CAM_PENDING:
+ case CIMAX_CAM_REGSTAT_OK:
+ case CIMAX_CAM_NOEVT: {
+ int len = cam_hdr_dat_size(spi);
+ if (len) {
+ ret = spi_read(dev, cam_dat(spi), len);
+ if (ret != 0)
+ return ret;
+ /*if (len)
+ dump("dat:", cam_dat(spi), len);*/
+ }
+ }
+ break;
+ default:
+ pr_error("unknown resp:0x%02x\n", hdr_cmd_resp(spi));
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int init_reg_hdr(u8 *hdr, u8 tag, int addr, int size)
+{
+ hdr[0] = tag;
+ hdr[1] = (addr>>8) & 0xff;
+ hdr[2] = addr & 0xff;
+ hdr[3] = size;
+ return 0;
+}
+
+static int check_reg_hdr(u8 *hdr, u8 tag, int addr, int size)
+{
+ return hdr[0] != tag
+ || hdr[1] != ((addr>>8) & 0xff)
+ || hdr[2] != (addr & 0xff)
+ || hdr[3] != size;
+}
+
+static int aml_cimax_spi_read_reg(struct aml_cimax *cimax, int addr,
+ u8 *buf, int size)
+{
+ struct cimax_spi *spi = cimax_to_spi(cimax);
+ struct spi_device *dev = spi->dev;
+ int err = 0;
+
+ init_reg_hdr(spi->buf, CIMAX_REG_READ, addr, size);
+
+ lock_lock(spi);
+
+ pr_dbg("rd %02x:%02x:%02x:%02x\n",
+ reg_hdr(spi)[0], reg_hdr(spi)[1],
+ reg_hdr(spi)[2], reg_hdr(spi)[3]);
+ err = spi_write(dev, spi->buf, CIMAX_REG_HDR_SIZE);
+ if (err)
+ goto end;
+ err = cimax_spi_get_resp(spi, REG_TIMEOUT);
+ if (err)
+ goto end;
+ if (check_reg_hdr(reg_hdr(spi), CIMAX_REG_READ_OK, addr, size) != 0) {
+ perr("read reg fail.", spi);
+ err = -EINVAL;
+ goto end;
+ }
+ memcpy(buf, reg_dat(spi), size);
+end:
+ lock_unlock(spi);
+ return err;
+}
+
+static int aml_cimax_spi_write_reg(struct aml_cimax *cimax, int addr,
+ u8 *buf, int size)
+{
+ struct cimax_spi *spi = cimax_to_spi(cimax);
+ struct spi_device *dev = spi->dev;
+ int err = 0;
+
+ init_reg_hdr(spi->buf, CIMAX_REG_WRITE, addr, size);
+ memcpy(&spi->buf[CIMAX_REG_HDR_SIZE], buf, size);
+
+ lock_lock(spi);
+
+ pr_dbg("wr %02x:%02x:%02x:%02x\n",
+ reg_hdr(spi)[0], reg_hdr(spi)[1],
+ reg_hdr(spi)[2], reg_hdr(spi)[3]);
+ err = spi_write(dev, spi->buf, CIMAX_REG_HDR_SIZE + size);
+ if (err)
+ goto end;
+ err = cimax_spi_get_resp(spi, REG_TIMEOUT);
+ if (err)
+ goto end;
+ if (check_reg_hdr(reg_hdr(spi), CIMAX_REG_WRITE_OK, addr, 0) != 0) {
+ perr("write reg fail.", spi);
+ err = -EINVAL;
+ goto end;
+ }
+end:
+ lock_unlock(spi);
+ return err;
+}
+
+static inline int init_cam_hdr(u8 *hdr, int cmd, int size)
+{
+ hdr[0] = cmd;
+ hdr[1] = CIMAX_CAM_PKT_CNT_VAL;
+ hdr[2] = (size>>8) & 0xff;
+ hdr[3] = size & 0xff;
+ return 0;
+}
+
+static inline int cam_err(struct cimax_spi *spi)
+{
+ if (hdr_cmd_resp(spi) != CIMAX_CAM_ERROR
+ || cam_hdr_pkt_cnt(spi) != CIMAX_CAM_PKT_CNT_VAL
+ || cam_hdr_dat_size(spi) != 2)
+ return 0;
+ return byte_to_u16(cam_dat(spi)[0], cam_dat(spi)[1]);
+}
+
+static inline char *cam_err_str(int err)
+{
+#define CAMERROR_RESET 0x0101
+#define CAMERROR_CIS_BUF 0x0201
+#define CAMERROR_CIS_SIZE 0x0202
+#define CAMERROR_CAM_NOT_ACT 0x0203
+#define CAMERROR_COR_NOT_READY 0x0301
+#define CAMERROR_COR_VAL_CHK 0x0302
+#define CAMERROR_NEG_NO_RESP 0x0401
+#define CAMERROR_NEG_BAD_SIZE 0x0402
+#define CAMERROR_NEG_NOT_READY 0x0403
+#define CAMERROR_LPDU_NOT_AVAIL 0x0601
+ struct { int err; char *str; } cam_err_strings[] = {
+ {CAMERROR_RESET, "reset error, not ready."},
+ {CAMERROR_CIS_BUF, "cis error, buffer not allocated."},
+ {CAMERROR_CIS_SIZE, "cis error, bad cis size."},
+ {CAMERROR_CAM_NOT_ACT, "cam not activated."},
+ {CAMERROR_COR_NOT_READY, "cam not ready during write COR."},
+ {CAMERROR_COR_VAL_CHK, "COR value check failed."},
+ {CAMERROR_NEG_NO_RESP, "cam not responding when negotiation."},
+ {CAMERROR_NEG_BAD_SIZE, "cam buf size length != 2."},
+ {CAMERROR_NEG_NOT_READY, "cam not ready during negotiation."},
+ {CAMERROR_LPDU_NOT_AVAIL, "lpdu not available."}
+ };
+ int i;
+ for (i = 0;
+ i < sizeof(cam_err_strings)/sizeof(cam_err_strings[0]); i++) {
+ if (cam_err_strings[i].err == err)
+ return cam_err_strings[i].str;
+ }
+ return "err unknown.";
+}
+
+static int cimax_spi_access_cam(struct cimax_spi *spi, int slot,
+ int cmd, u8 *buf, int size)
+{
+ struct spi_device *dev = spi->dev;
+ int err = 0;
+
+ cmd |= slot ? 0x80 : 0;
+ init_cam_hdr(cam_hdr(spi), cmd, size);
+ memcpy(cam_dat(spi), buf, size);
+ /*dump("access cam:", cam_hdr(spi), CIMAX_CAM_HDR_SIZE+size);*/
+ err = spi_write(dev, cam_hdr(spi), CIMAX_CAM_HDR_SIZE + size);
+ if (err)
+ return err;
+ err = cimax_spi_get_resp(spi, CAM_TIMEOUT);
+ if (err)
+ return err;
+ if (cam_hdr_slot(spi) != slot) {
+ pr_error("expect slot(%d), but slot(%d)\n",
+ slot, cam_hdr_slot(spi));
+ return -EINVAL;
+ }
+ switch (hdr_cmd_resp(spi)) {
+ case CIMAX_CAM_NOCAM:
+ pr_dbg("no cam\n");
+ err = -ENODEV;
+ break;
+ case CIMAX_CAM_ERROR:
+ pr_error("cam error\n");
+ pr_error("err code: 0x%04x(%s)\n", cam_err(spi),
+ cam_err_str(cam_err(spi)));
+ err = -ENODEV;
+ break;
+ case CIMAX_CAM_WBUSY:
+ pr_dbg("cam busy\n");
+ err = -EBUSY;
+ break;
+ case CIMAX_CAM_PENDING:
+ pr_dbg("cam pending\n");
+ err = -EAGAIN;
+ break;
+ }
+ return err;
+}
+
+static int aml_cimax_spi_read_cis(struct aml_cimax *cimax, int slot,
+ u8 *buf, int size)
+{
+ struct cimax_spi *spi = cimax_to_spi(cimax);
+ int err = 0;
+ int len;
+
+ lock_lock(spi);
+
+ err = cimax_spi_access_cam(spi, slot, CIMAX_CAM_CIS, NULL, 0);
+ if (err)
+ goto end;
+ if (hdr_cmd_resp(spi) != CIMAX_CAM_CIS_OK
+ || cam_hdr_pkt_cnt(spi) != CIMAX_CAM_PKT_CNT_VAL) {
+ perr("read cis fail.", spi);
+ err = -EINVAL;
+ goto end;
+ }
+ len = cam_hdr_dat_size(spi);
+ if (size < len) {
+ pr_error("cis size too large, expect<%d, but:%d\n", size, len);
+ perr("cis fail.", spi);
+ err = -EINVAL;
+ goto end;
+ }
+ memcpy(buf, cam_dat(spi), len);
+
+ if (!spi->cis)
+ spi->cis = kzalloc((len < 512) ? 512 : len, GFP_KERNEL);
+ if (spi->cis)
+ memcpy(spi->cis, cam_dat(spi), len);
+
+end:
+ lock_unlock(spi);
+ return err;
+}
+#define CIMAX_CAM_COR_PLD_SIZE 5
+static int aml_cimax_spi_write_cor(struct aml_cimax *cimax, int slot,
+ int addr, u8 *buf)
+{
+ struct cimax_spi *spi = cimax_to_spi(cimax);
+ int err = 0;
+ u8 out[CIMAX_CAM_COR_PLD_SIZE + 8];
+ int sz = CIMAX_CAM_COR_PLD_SIZE;
+
+ out[0] = addr>>8 & 0xff;
+ out[1] = addr & 0xff;
+ out[2] = buf[0];
+ out[3] = 0;
+ out[4] = 0;
+
+ if (!cam_irq_mode) {
+ out[5] = 0x40;/*cam poll mode*/
+ sz++;
+ }
+
+ lock_lock(spi);
+
+ err = cimax_spi_access_cam(spi, slot, CIMAX_CAM_COR, out, sz);
+ if (err)
+ goto end;
+ if (hdr_cmd_resp(spi) != CIMAX_CAM_COR_OK
+ || cam_hdr_pkt_cnt(spi) != CIMAX_CAM_PKT_CNT_VAL
+ || cam_hdr_dat_size(spi) != 0) {
+ perr("write cor fail.", spi);
+ err = -EINVAL;
+ goto end;
+ }
+end:
+ lock_unlock(spi);
+ return err;
+}
+#define CIMAX_CAM_NEG_PLD_SIZE 2
+static int aml_cimax_spi_negotiate(struct aml_cimax *cimax, int slot, int size)
+{
+ struct cimax_spi *spi = cimax_to_spi(cimax);
+ int ret = 0;
+ u8 out[CIMAX_CAM_NEG_PLD_SIZE];
+
+ out[0] = (size>>8) & 0xff;
+ out[1] = size & 0xff;
+
+ lock_lock(spi);
+
+ ret = cimax_spi_access_cam(spi, slot, CIMAX_CAM_NEG,
+ out, CIMAX_CAM_NEG_PLD_SIZE);
+ if (ret)
+ goto end;
+ if (hdr_cmd_resp(spi) != CIMAX_CAM_NEG_OK
+ || cam_hdr_pkt_cnt(spi) != CIMAX_CAM_PKT_CNT_VAL
+ || cam_hdr_dat_size(spi) != 2) {
+ perr("negotiate fail.", spi);
+ ret = -EINVAL;
+ goto end;
+ }
+ ret = byte_to_u16(cam_dat(spi)[0], cam_dat(spi)[1]);
+
+ set_spi_cam_ready(spi, slot);
+end:
+ lock_unlock(spi);
+ return ret;
+}
+
+static int aml_cimax_spi_write_lpdu(struct aml_cimax *cimax, int slot,
+ u8 *buf, int size)
+{
+ struct cimax_spi *spi = cimax_to_spi(cimax);
+ int ret = 0;
+
+ lock_lock(spi);
+
+ /*dump("lpdu ->", buf, size);*/
+ ret = cimax_spi_access_cam(spi, slot, CIMAX_CAM_WLPDU, buf, size);
+ if (ret)
+ goto end;
+ if (hdr_cmd_resp(spi) != CIMAX_CAM_WLPDU_OK
+ || cam_hdr_pkt_cnt(spi) != CIMAX_CAM_PKT_CNT_VAL
+ || cam_hdr_dat_size(spi) != 0) {
+ perr("write lpdu fail.", spi);
+ ret = -EINVAL;
+ goto end;
+ }
+ ret = size;
+end:
+ lock_unlock(spi);
+ return ret;
+}
+
+static int aml_cimax_spi_read_lpdu(struct aml_cimax *cimax, int slot,
+ u8 *buf, int size)
+{
+ struct cimax_spi *spi = cimax_to_spi(cimax);
+ int ret = 0;
+
+ lock_lock(spi);
+
+ ret = cimax_spi_access_cam(spi, slot, CIMAX_CAM_RLPDU, NULL, 0);
+ if (ret)
+ goto end;
+ if (hdr_cmd_resp(spi) != CIMAX_CAM_RLPDU_OK
+ || cam_hdr_pkt_cnt(spi) != CIMAX_CAM_PKT_CNT_VAL) {
+ perr("read lpdu fail.", spi);
+ ret = -EINVAL;
+ goto end;
+ }
+ ret = cam_hdr_dat_size(spi);
+ memcpy(buf, cam_dat(spi), ret);
+
+ /*dump("lpdu <-", buf, ret);*/
+
+ spi->cam_data_ready[slot] = 0;
+end:
+ lock_unlock(spi);
+ return ret;
+}
+
+static int aml_cimax_spi_read_cam_status(struct aml_cimax *cimax, int slot)
+{
+ struct cimax_spi *spi = cimax_to_spi(cimax);
+ int ret = 0;
+
+ if (cam_irq_mode && spi->cam_data_ready[slot])
+ return 0x80;
+
+ lock_lock(spi);
+
+ ret = cimax_spi_access_cam(spi, slot, CIMAX_CAM_REGSTAT, NULL, 0);
+ if (ret)
+ goto end;
+ if (hdr_cmd_resp(spi) != CIMAX_CAM_REGSTAT_OK
+ || cam_hdr_pkt_cnt(spi) != CIMAX_CAM_PKT_CNT_VAL
+ || cam_hdr_dat_size(spi) != 1) {
+ perr("read cam status fail.", spi);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ ret = cam_dat(spi)[0];
+end:
+ lock_unlock(spi);
+ return ret;
+}
+
+static int aml_cimax_spi_slot_reset(struct aml_cimax *cimax, int slot)
+{
+ struct cimax_spi *spi = cimax_to_spi(cimax);
+ int ret = 0;
+
+ spi->cam_data_ready[slot] = 0;
+
+ lock_lock(spi);
+
+ ret = cimax_spi_access_cam(spi, slot, CIMAX_CAM_RESET, NULL, 0);
+ if (ret)
+ goto end;
+ if (hdr_cmd_resp(spi) != CIMAX_CAM_RESET_OK
+ || cam_hdr_pkt_cnt(spi) != CIMAX_CAM_PKT_CNT_VAL
+ || cam_hdr_dat_size(spi) != 0) {
+ perr("slot reset fail.", spi);
+ ret = -EINVAL;
+ goto end;
+ }
+end:
+ lock_unlock(spi);
+ return ret;
+}
+
+static int aml_cimax_spi_cam_reset(struct aml_cimax *cimax, int slot)
+{
+ pr_dbg("Slot(%d): camreset\n", slot);
+ return 0;
+}
+
+static int aml_cimax_spi_slot_shutdown(struct aml_cimax *cimax, int slot)
+{
+ pr_dbg("Slot(%d): shutdown\n", slot);
+ return 0;
+}
+static int aml_cimax_spi_slot_ts_enable(struct aml_cimax *cimax, int slot)
+{
+ pr_dbg("Slot(%d): ts control\n", slot);
+ return 0;
+}
+static int aml_cimax_spi_slot_status(struct aml_cimax *cimax, int slot)
+{
+ struct cimax_spi *spi = cimax_to_spi(cimax);
+ if (spi->cam_inserted[slot]) {
+ /*pr_dbg("CA Module present and ready\n");*/
+ return DVB_CA_EN50221_POLL_CAM_PRESENT |
+ DVB_CA_EN50221_POLL_CAM_READY;
+ } else {
+ /*pr_error("CA Module not present or not ready\n");*/
+ }
+ return 0;
+}
+
+static int cimax_spi_cam_plugin(struct cimax_spi *spi, int slot, int plugin)
+{
+ pr_dbg("cam plug: slot(%d) %s\n",
+ slot, plugin ? "plugged" : "unplugged");
+ return aml_cimax_camchanged(spi->cimax, slot, plugin);
+}
+
+static int cimax_spi_poll(struct cimax_spi *spi)
+{
+ struct spi_device *dev = spi->dev;
+ int err = 0;
+
+ lock_lock(spi);
+
+#ifdef USE_INT_PIO
+ if (gpio_get_value(spi->irq_io))
+ goto end;
+#endif
+
+ init_reg_hdr(spi->buf, CIMAX_CAM_EVT, 0x100, 0);
+ err = spi_write(dev, spi->buf, CIMAX_REG_HDR_SIZE);
+ if (err)
+ goto end;
+ err = cimax_spi_get_resp(spi, CAM_TIMEOUT);
+ if (err)
+ goto end;
+ switch (hdr_cmd_resp(spi)) {
+ case CIMAX_CAM_DET_OK: {
+ int slot = cam_hdr_slot(spi);
+ int insert = cam_dat(spi)[0];
+ if (!!spi->cam_inserted[slot] != insert) {
+ spi->cam_inserted[slot] = insert;
+ cimax_spi_cam_plugin(spi, slot, insert);
+ aml_cimax_slot_state_changed(spi->cimax, slot,
+ spi->cam_inserted[slot]);
+ }
+ } break;
+ case CIMAX_CAM_DATA_READY: {
+ int slot = cam_hdr_slot(spi);
+ spi->cam_data_ready[slot] = 1;
+ } break;
+ case CIMAX_CAM_NOEVT:
+ break;
+ default:
+ pr_error("unknown resp:%02x\n", hdr_cmd_resp(spi));
+ break;
+ }
+end:
+ queue_delayed_work(spi->workq, &spi->work, spi_poll_interval);
+ lock_unlock(spi);
+ return 0;
+}
+
+static void cimax_spi_poll_work(struct work_struct *work)
+{
+ struct cimax_spi *spi =
+ container_of(to_delayed_work(work), struct cimax_spi, work);
+ spi->work_cnt++;
+ cimax_spi_poll(spi);
+}
+
+static irqreturn_t cimax_irq_handler(int irq, void *para)
+{
+ return IRQ_HANDLED;
+}
+
+#define CTRL_DISABLE -1
+#define CTRL_STOP 0
+#define CTRL_START 1
+
+static inline int cimax_spi_poll_ctrl(struct cimax_spi *spi, int ctrl)
+{
+ if (ctrl == CTRL_START) {
+ spi->workq = create_singlethread_workqueue("cimax_spi");
+ INIT_DELAYED_WORK(&spi->work, &cimax_spi_poll_work);
+ queue_delayed_work(spi->workq,
+ &spi->work, spi_poll_interval);
+ pr_dbg("poll started\n");
+ } else {
+ if (!spi->workq)
+ return 0;
+ cancel_delayed_work_sync(&spi->work);
+ destroy_workqueue(spi->workq);
+ spi->workq = NULL;
+ pr_dbg("poll stopped\n");
+ }
+ return 0;
+}
+
+static inline int cimax_spi_intr_ctrl(struct cimax_spi *spi, int ctrl)
+{
+ if (ctrl == CTRL_START) {
+ int ret;
+ if (spi->irq == -1) {
+ pr_error("incorrect irq");
+ return -1;
+ }
+ ret = request_irq(spi->irq, cimax_irq_handler,
+ IRQF_SHARED|IRQF_TRIGGER_RISING,
+ "cimax irq", spi);
+ enable_irq(spi->irq);
+ } else {
+ if (spi->irq == -1)
+ return 0;
+ disable_irq(spi->irq);
+ free_irq(spi->irq, spi);
+ }
+ return 0;
+}
+
+static int cimax_spi_setup_poll(struct cimax_spi *spi, int poll_mode)
+{
+ if (poll_mode == spi->poll_mode)
+ return 0;
+ switch (poll_mode) {
+ case POLL_MODE:
+ if (spi->poll_mode == INT_MODE)
+ cimax_spi_intr_ctrl(spi, CTRL_DISABLE);
+ cimax_spi_poll_ctrl(spi, CTRL_START);
+ spi->poll_mode = POLL_MODE;
+ break;
+ case INT_MODE:
+ if (spi->poll_mode == POLL_MODE)
+ cimax_spi_poll_ctrl(spi, CTRL_DISABLE);
+ cimax_spi_intr_ctrl(spi, CTRL_START);
+ spi->poll_mode = INT_MODE;
+ break;
+ case STOP_MODE:
+ if (spi->poll_mode == POLL_MODE)
+ cimax_spi_poll_ctrl(spi, CTRL_DISABLE);
+ else if (spi->poll_mode == INT_MODE)
+ cimax_spi_intr_ctrl(spi, CTRL_DISABLE);
+ spi->poll_mode = STOP_MODE;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int cimax_spi_hw_reset(struct cimax_spi *spi, int reset_val)
+{
+ /*trigger reset io*/
+ if (spi->rst_io) {
+ gpio_direction_output(spi->rst_io, reset_val ? 1 : 0);
+ msleep(50);
+ gpio_direction_output(spi->rst_io, reset_val ? 0 : 1);
+ }
+ return 0;
+}
+
+
+enum regOperation_e {
+ /** Read register. */
+ REG_OP_READ,
+ /** Write register. */
+ REG_OP_WRITE,
+ /** Read register until some bits are set. */
+ REG_OP_WAIT_TO_BE_SET,
+ /** Read register until some bits are cleared. */
+ REG_OP_WAIT_TO_BE_CLEARED,
+ /** Read register until it's value is not equal to defined. */
+ REG_OP_WAIT_EQUAL,
+ /** Perform logical AND over register. */
+ REG_OP_LOGICAL_AND,
+ /** Perform logical OR over register. */
+ REG_OP_LOGICAL_OR,
+ /** Wait timeout in miliseconds. */
+ REG_OP_WAIT
+};
+
+struct regSettings_s {
+ /** CIMaX+ register address. */
+ u16 reg;
+ /** CIMaX+ register value. */
+ u16 val;
+ /** CIMaX+ register operation. */
+ enum regOperation_e op;
+};
+
+static struct regSettings_s spiRegSettings[] = {
+ /** TS interface init. */
+ {IN_SEL, 0x00, REG_OP_WRITE}, /** Close TS input. */
+ {OUT_SEL, 0x00, REG_OP_WRITE}, /** Close TS output. */
+ {FIFO_CTRL, 0x0f, REG_OP_WRITE}, /** Reset TS FIFO. */
+ {SYNC_RTV_CTRL, 0x0f, REG_OP_WRITE},
+
+ /** CAM power. */
+ {GPIO0_DATA_OUT, 0x00, REG_OP_WRITE},
+ /** Unlock CFG. */
+ {CFG_2, 0x00, REG_OP_WRITE},
+ /** 1) DVB/CI/CI+/SCARD 2slot. */
+ {CFG_1, 0x00, REG_OP_WRITE},
+ /** 2) Set the Default "power off" state
+ such as VCC_MODA=VCC_MODB=VPPx_MODA=VPPx_MODB='Z'. */
+ {GPIO0_DFT, 0x00, REG_OP_WRITE},
+ /** 3) Set GPIO3 as external power switch driver. */
+ {GPIO0_MASK_DATA, 0x07, REG_OP_WRITE},
+ /** 4) Set "power on" state (VCC=VPP1=VPP2= 5V). */
+ {GPIO0_DATA_OUT, 0x03, REG_OP_WRITE},
+ /** 5) Lock config. */
+ {CFG_2, 0x01, REG_OP_WRITE},
+ /** 6) Write in the GPIO0_DIR_REG: defines the GPIOs,
+ which are used to drive the external power switch, in output mode. */
+ {GPIO0_DIR, 0x07, REG_OP_WRITE},
+ /** 7) Check VCCENable. */
+ {CFG_1, 0x20, REG_OP_WAIT_TO_BE_SET},
+ /** 8) Set & wait for PcmciaOutputEnable. */
+ {CFG_1, 0x08, REG_OP_LOGICAL_OR},
+ {CFG_1, 0x08, REG_OP_WAIT_TO_BE_SET},
+
+ /** Set router CAM. */
+ /** CH0 & CH1 from CAM A & B, CAM A & B from CH0 & CH1. */
+ {ROUTER_CAM_MOD, 0x21, REG_OP_WRITE},
+ {ROUTER_CAM_CH, 0x00, REG_OP_WRITE},
+ /** Wait 200 miliseconds. */
+ {0x0000, 200, REG_OP_WAIT},
+
+ /** Set In/Out. */
+ /** Route CAM Channel 0 to Channel 0, Channel 1 null. */
+ {ROUTER_CAM_CH, 0x80, REG_OP_WRITE},
+
+#ifdef PARALLEL_OUT
+#else
+#if 1
+ /*72M internal clock source*/
+ /*CLK Select SER0->72M*/
+ {CkMan_Select, 0x20, REG_OP_WRITE},
+ /*Enable SER0 clk source, Enable 72M clk source*/
+ {CkMan_Config, 0x44, REG_OP_LOGICAL_OR},
+#else
+ /*108M internal clock source*/
+ /*CLK Select SER0->108M*/
+ {CkMan_Select, 0x30, REG_OP_WRITE},
+ /*Enable SER0 clk source, Enable 108M clk source*/
+ {CkMan_Config, 0x48, REG_OP_LOGICAL_OR},
+#endif
+ {P2S_CH0_CTRL, 0x19, REG_OP_WRITE}, /*Enable p2s*/
+ {OUT_SEL, 0x02, REG_OP_WRITE}, /*Out1=p2s0*/
+#endif /*Parallel out*/
+
+ /** Input Ch0=Parallel, Ch1=null. */
+ {IN_SEL, 0x01, REG_OP_WRITE},
+};
+
+int downloadCfg(struct cimax_spi *spi)
+{
+ u32 cnt;
+ u8 buf[CIMAX_REG_PLD_SIZE];
+ struct aml_cimax *cimax = spi->cimax;
+
+ pr_info("Download CIMaX+ configuration(register settings):\n");
+
+ for (cnt = 0; cnt < sizeof(spiRegSettings)/sizeof(struct regSettings_s);
+ cnt++) {
+ pr_dbg("reg:%04x, val:%02x, op:%d\n",
+ spiRegSettings[cnt].reg,
+ spiRegSettings[cnt].val,
+ spiRegSettings[cnt].op);
+ switch (spiRegSettings[cnt].op) {
+ case REG_OP_READ:
+ /* Read register. */
+ if (aml_cimax_spi_read_reg(cimax,
+ spiRegSettings[cnt].reg, buf, 1) < 0) {
+ /* CIMaX+ read error. */
+ pr_error("FAILED at REG_OP_READ operation.\n");
+ return -1;
+ }
+ break;
+ case REG_OP_WRITE:
+ /* Write register. */
+ if (aml_cimax_spi_write_reg(cimax,
+ spiRegSettings[cnt].reg,
+ (u8 *)&spiRegSettings[cnt].val,
+ 1) < 0) {
+ /* CIMaX+ write error. */
+ pr_error("FAILED at REG_OP_WRITE operation.\n");
+ return -1;
+ }
+ break;
+ case REG_OP_WAIT_TO_BE_SET:
+ do {
+ if (aml_cimax_spi_read_reg(cimax,
+ spiRegSettings[cnt].reg, buf, 1) < 0) {
+ /* CIMaX+ read error. */
+ pr_error("E REG_OP_WAIT_TO_BE_SET\n");
+ return -1;
+ }
+ } while ((buf[0] & spiRegSettings[cnt].val)
+ != spiRegSettings[cnt].val);
+ break;
+ case REG_OP_WAIT_TO_BE_CLEARED:
+ do {
+ if (aml_cimax_spi_read_reg(cimax,
+ spiRegSettings[cnt].reg, buf, 1) < 0) {
+ /* CIMaX+ read error. */
+ pr_error("REG_OP_WAIT_TO_BE_CLEARED\n");
+ return -1;
+ }
+ } while ((buf[0] & spiRegSettings[cnt].val) != 0);
+ break;
+ case REG_OP_WAIT_EQUAL:
+ do {
+ if (aml_cimax_spi_read_reg(cimax,
+ spiRegSettings[cnt].reg, buf, 1) < 0) {
+ /* CIMaX+ read error. */
+ pr_error("REG_OP_WAIT_EQUAL.\n");
+ return -1;
+ }
+ } while (buf[0] != spiRegSettings[cnt].val);
+ break;
+ case REG_OP_LOGICAL_AND:
+ if (aml_cimax_spi_read_reg(cimax,
+ spiRegSettings[cnt].reg, buf, 1) < 0) {
+ /* CIMaX+ read error. */
+ pr_error("FAILED at REG_OP_LOGICAL_AND(r).\n");
+ return -1;
+ }
+ buf[0] &= spiRegSettings[cnt].val;
+ if (aml_cimax_spi_write_reg(cimax,
+ spiRegSettings[cnt].reg, buf, 1) < 0) {
+ /* CIMaX+ write error. */
+ pr_error("FAILED at REG_OP_LOGICAL_AND(w).\n");
+ return -1;
+ }
+ break;
+ case REG_OP_LOGICAL_OR:
+ if (aml_cimax_spi_read_reg(cimax,
+ spiRegSettings[cnt].reg, buf, 1) < 0) {
+ /* CIMaX+ read error. */
+ pr_error("FAILED at REG_OP_LOGICAL_OR(r).\n");
+ return -1;
+ }
+ buf[0] |= spiRegSettings[cnt].val;
+ if (aml_cimax_spi_write_reg(cimax,
+ spiRegSettings[cnt].reg, buf, 1) < 0) {
+ /* CIMaX+ write error. */
+ pr_error("FAILED at REG_OP_LOGICAL_AND(w).\n");
+ return -1;
+ }
+ break;
+ case REG_OP_WAIT:
+ msleep(spiRegSettings[cnt].val);
+ break;
+ default:
+ pr_error("\nInvalid operation 0x%02x!\n",
+ spiRegSettings[cnt].op);
+ }
+ }
+ pr_info("config OK.\n");
+ return 0;
+}
+
+
+#define CIMAX_FW_PKT_SIZE 128
+#define CIMAX_FW_START_ADDR 0x8000
+#define CIMAX_FW_STOP_ADDR 0xcff9
+#define CIMAX_FW_VECT_ADDR 0xfffa
+#define CIMAX_FW_VECT_SIZE 6
+
+static u32 compute_bistrom(const u8 *ptr, int size, u32 sign)
+{
+ int k, i;
+ u16 s;
+
+ for (k = 0; k < size; k++) {
+ s = ptr[k]&0x01;
+ for (i = 0; i < 16; i++)
+ if (0x88B7 & (1<<i))
+ s ^= (sign>>i) & 0x01;
+ s |= ((sign<<1) ^ (ptr[k])) & 0x00FE;
+ s |= (sign<<1) & 0x00FF00;
+ sign = s;
+ }
+ return sign;
+}
+
+static int cimax_spi_upload_firmware(struct cimax_spi *spi,
+ const u8 *fw_data, u32 *sign)
+{
+ struct aml_cimax *cimax = spi->cimax;
+ int err = 0;
+ int addr;
+ const u8 *ptr;
+ int size;
+ int debug = cimax_spi_debug;
+ u8 *ptmp = kzalloc(CIMAX_FW_PKT_SIZE + CIMAX_REG_HDR_SIZE, GFP_KERNEL);
+
+ if (!ptmp)
+ return -ENOMEM;
+
+ cimax_spi_debug = 0;
+
+ addr = CIMAX_FW_START_ADDR;
+ ptr = fw_data + addr;
+ while (addr < CIMAX_FW_STOP_ADDR) {
+ size = (addr <= (CIMAX_FW_STOP_ADDR+1-CIMAX_FW_PKT_SIZE)) ?
+ CIMAX_FW_PKT_SIZE : (CIMAX_FW_STOP_ADDR+1-addr);
+
+ *sign = compute_bistrom(ptr, size, *sign);
+
+ pr_dbg(">>%x@%x\n", size, addr);
+
+ /*dump("w:", (u8*)ptr, size);*/
+ err = aml_cimax_spi_write_reg(cimax, addr, (u8 *)ptr, size);
+ if (err)
+ break;
+ err = aml_cimax_spi_read_reg(cimax, addr, ptmp, size);
+ if (err)
+ break;
+ /*dump("r:", ptmp, size);*/
+ if (memcmp(ptr, ptmp, size)) {
+ pr_error("fw write error.\n");
+ err = -ENODEV;
+ break;
+ }
+
+ addr += size;
+ ptr += size;
+ }
+
+ if (!err) {
+ addr = CIMAX_FW_VECT_ADDR;
+ ptr = fw_data + addr;
+ size = CIMAX_FW_VECT_SIZE;
+
+ *sign = compute_bistrom(ptr, size, *sign);
+
+ err = aml_cimax_spi_write_reg(cimax, addr, (u8 *)ptr, size);
+ if (err)
+ goto end;
+ err = aml_cimax_spi_read_reg(cimax, addr, ptmp, size);
+ if (err)
+ goto end;
+ if (memcmp(ptr, ptmp, size)) {
+ pr_error("fw vect write error.\n");
+ err = -ENODEV;
+ goto end;
+ }
+ }
+end:
+ kfree(ptmp);
+
+ cimax_spi_debug = debug;
+ return err;
+}
+
+static int cimax_spi_check_bistrom(struct cimax_spi *spi,
+ int start, int end, u32 sign)
+{
+ struct aml_cimax *cimax = spi->cimax;
+ int err = 0;
+ u8 buf[2];
+
+ buf[0] = (0xd000-start) & 0xff;
+ buf[1] = (0xd000-start) >> 8;
+ err = aml_cimax_spi_write_reg(cimax, 0x8d, buf, 2);
+ if (err)
+ return err;
+ buf[0] = sign & 0xff;
+ buf[1] = sign >> 8;
+ err = aml_cimax_spi_write_reg(cimax, 0x80, buf, 2);
+ if (err)
+ return err;
+ buf[0] = 0xf;
+ err = aml_cimax_spi_write_reg(cimax, 0x82, buf, 1);
+ if (err)
+ return err;
+ err = aml_cimax_spi_read_reg(cimax, 0x41, buf, 2);
+ if (err)
+ return err;
+ pr_dbg("bist checked: 0x%04x\n", byte_to_u16(buf[0], buf[1]));
+ err = aml_cimax_spi_read_reg(cimax, 0x09, buf, 1);
+ if (err)
+ return err;
+ pr_dbg("rom status: 0x%02x\n", buf[0]);
+ return buf[0];
+}
+
+static int cimax_spi_init_firmware(struct cimax_spi *spi)
+{
+ struct spi_device *dev = spi->dev;
+ int err = 0;
+
+ init_reg_hdr(spi->buf, CIMAX_REG_INIT, 0, 0);
+ err = spi_write(dev, spi->buf, CIMAX_REG_HDR_SIZE);
+ if (err)
+ return err;
+ err = cimax_spi_get_resp(spi, REG_TIMEOUT);
+ if (err)
+ return err;
+ if (check_reg_hdr(spi->buf, CIMAX_REG_INIT_OK, 0, 0)) {
+ perr("init fw fail.", spi);
+ return -EINVAL;
+ }
+ return err;
+}
+
+static void request_fw_callback(const struct firmware *fw, void *context)
+{
+ u32 sign = 0;
+ int err = 0;
+ struct cimax_spi *spi = (struct cimax_spi *)context;
+
+ if (!fw)
+ return;
+
+ pr_dbg("got fw: %zd @ %p\n", fw->size, fw->data);
+
+ /*cimax_spi_hw_reset(spi, 1);*/
+
+ err = cimax_spi_upload_firmware(spi, fw->data, &sign);
+ if (err)
+ goto end;
+ pr_dbg("upload fw done.\n");
+ err = cimax_spi_check_bistrom(spi,
+ CIMAX_FW_START_ADDR, CIMAX_FW_STOP_ADDR, sign);
+ if (err != 0x2)
+ goto end;
+ pr_dbg("check bistrom done.\n");
+ err = cimax_spi_init_firmware(spi);
+ if (err)
+ goto end;
+end:
+ if (fw)
+ release_firmware(fw);
+ if (err)
+ return;
+
+ if (downloadCfg(spi)) {
+ pr_error("download config fail.\n");
+ return;
+ }
+
+ cimax_spi_setup_poll(spi, cimax_poll_mode ? POLL_MODE : INT_MODE);
+
+ return;
+}
+
+static int cimax_spi_load_fw(struct cimax_spi *spi)
+{
+ char *name = "cimax_spidvb.bin";
+ return request_firmware_nowait(THIS_MODULE, 1, name,
+ &spi->dev->dev, GFP_KERNEL, spi, request_fw_callback);
+}
+
+static int cimax_spi_dev_probe(struct spi_device *spi)
+{
+ int ret;
+ struct cimax_spi *cimax_spi;
+
+ pr_dbg("dev probe\n");
+ /*setup again?*/
+ spi->bits_per_word = 8;
+ ret = spi_setup(spi);
+ if (ret)
+ pr_dbg("spi setup failed\n");
+
+ cimax_spi = dev_get_platdata(&spi->dev);
+ cimax_spi->dev = spi;
+
+ spi_set_drvdata(spi, cimax_spi);
+
+ return cimax_spi_load_fw(cimax_spi);
+}
+
+static int cimax_spi_dev_remove(struct spi_device *spi)
+{
+ struct cimax_spi *cimax_spi = dev_get_drvdata(&spi->dev);
+
+ pr_dbg("dev remove\n");
+ cimax_spi_setup_poll(cimax_spi, STOP_MODE);
+ return 0;
+}
+
+static int cimax_spi_get_config_from_dts(struct cimax_spi *spi,
+ struct spi_board_info *bdinfo)
+{
+ struct device_node *child = NULL;
+ struct platform_device *pdev = spi->pdev;
+ struct device_node *np = pdev->dev.of_node;
+ unsigned int val;
+ int ret = 0;
+ pr_dbg("fetch cimax spi in dts\n");
+
+ child = of_get_child_by_name(np, "cimax");
+ if (child == NULL) {
+ pr_error("cimax not found in dts\n");
+ return -1;
+ }
+ child = of_get_child_by_name(child, "spi");
+ if (!child) {
+ pr_error("spi not found in cimax");
+ return -1;
+ }
+
+ /* get spi config */
+ ret = of_property_read_u32(child, "bus_num", &val);
+ if (ret)
+ pr_error("bus_num not found, use default.\n");
+ else
+ bdinfo->bus_num = val;
+ pr_dbg("bus_num: %d\n", bdinfo->bus_num);
+ ret = of_property_read_u32(child, "chip_select", &val);
+ if (ret)
+ pr_error("chip_select not found, use default.\n");
+ else
+ bdinfo->chip_select = val;
+ pr_dbg("chip_select: %d\n", bdinfo->chip_select);
+ ret = of_property_read_u32(child, "max_frequency", &val);
+ if (ret)
+ pr_error("max_frequency not found, use default.\n");
+ else
+ bdinfo->max_speed_hz = val;
+ pr_dbg("max_speed_hz: %d\n", bdinfo->max_speed_hz);
+ ret = of_property_read_u32(child, "mode", &val);
+ if (ret)
+ pr_error("mode not found, use default.\n");
+ else
+ bdinfo->mode = val;
+ pr_dbg("mode: %d\n", bdinfo->mode);
+/*
+dvbci {
+ compatible = "amlogic, dvbci";
+ dev_name = "dvbci";
+ io_type = <2>;//0:iobus,1:spi,2:cimax
+ cimax {
+ io_type = <0> //0:spi 1:usb
+ spi {
+ spi_bus_num = <0>;
+ spi_chip_select = <0>;
+ spi_max_frequency = <3000000>;
+
+ rst_gpio = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_HIGH>;
+
+ irq_gpio = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_HIGH>;
+ irq = <2>;
+ interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ };
+
+};
+*/
+#ifdef USE_INT_PIO
+ {
+ int ret = 0;
+ int gpio = -1;
+ gpio = of_get_named_gpio_flags(child, "irq-gpios", 0, NULL);
+ ret = gpio_request(gpio, "cimax-irq");
+ if (ret < 0) {
+ pr_error("irq-gpios request fail.\n");
+ return ret;
+ }
+
+ ret = gpio_direction_input(gpio);
+
+ spi->irq_io = gpio;
+ pr_dbg("irq_io: %d\n", spi->irq_io);
+ }
+#ifdef CIMAX_IRQ
+ {
+ int irq;
+ unsigned int irqflag;
+ ret = of_property_read_u32(child, "irq", &gpio_irq);
+ irq = irq_of_parse_and_map(child, 0);
+
+ gpio_for_irq(gpio,
+ AML_GPIO_IRQ(gpio_irq, FILTER_NUM7, GPIO_IRQ_FALLING));
+ spi->irq = irq;
+ pr_dbg("irq: %d\n", spi->irq);
+ }
+#else
+ spi->irq = -1;
+#endif
+#endif/*USE_INT_PIO*/
+ {
+ int ret = 0;
+ int gpio = -1;
+ gpio = of_get_named_gpio_flags(child, "rst-gpios", 0, NULL);
+ if (gpio != -1) {
+ ret = gpio_request(gpio, "cimax");
+ if (ret < 0) {
+ pr_error("rst-gpios request fail.\n");
+ return ret;
+ }
+
+ cimax_spi_hw_reset(spi, 1);
+
+ spi->rst_io = gpio;
+ pr_dbg("rst: %d\n", spi->rst_io);
+ } else {
+ pr_error("rst io got fail, %d\n", gpio);
+ }
+ }
+ return 0;
+}
+
+static struct spi_board_info cimax_spi_bdinfo = {
+ .modalias = "cimax_spi",
+ .mode = SPI_MODE_3,
+ .max_speed_hz = 1000000, /* 1MHz */
+ .bus_num = 0, /* SPI bus No. */
+ .chip_select = 0, /* the device index on the spi bus */
+ .controller_data = NULL,
+};
+
+static struct spi_driver cimax_spi_dev_driver = {
+ .probe = cimax_spi_dev_probe,
+ .remove = cimax_spi_dev_remove,
+ .driver = {
+ .name = "cimax_spi",
+ .owner = THIS_MODULE,
+ },
+};
+
+int aml_cimax_spi_init(struct platform_device *pdev, struct aml_cimax *cimax)
+{
+ int ret;
+ struct cimax_spi *cimax_spi;
+
+ cimax_spi = kzalloc(sizeof(struct cimax_spi), GFP_KERNEL);
+ if (!cimax_spi)
+ return -ENOMEM;
+
+ cimax_spi->pdev = pdev;
+ cimax_spi->cimax = cimax;
+ cimax_spi_get_config_from_dts(cimax_spi, &cimax_spi_bdinfo);
+
+ /*init spi_lock*/
+ lock_init(cimax_spi);
+
+ /*register device*/
+ cimax_spi_bdinfo.platform_data = cimax_spi;
+ spi_register_board_info(&cimax_spi_bdinfo, 1);
+
+ /*register driver*/
+ ret = spi_register_driver(&cimax_spi_dev_driver);
+ if (ret) {
+ pr_error("register cimax spi driver failed\n");
+ return ret;
+ }
+
+ /*init cimax used api.*/
+#define WI(_f)\
+ cimax->ops._f = aml_cimax_spi_##_f
+ WI(read_cis);
+ WI(write_cor);
+ WI(negotiate);
+ WI(read_lpdu);
+ WI(write_lpdu);
+ WI(read_cam_status);
+ WI(cam_reset);
+ WI(slot_reset);
+ WI(slot_shutdown);
+ WI(slot_ts_enable);
+ WI(slot_status);
+ /*WI(start);*/
+ /*WI(stop);*/
+ WI(read_reg);
+ WI(write_reg);
+
+ cimax->priv = cimax_spi;
+
+ g_spi = cimax_spi;
+
+ aml_cimax_spi_mod_init();
+
+ return 0;
+}
+EXPORT_SYMBOL(aml_cimax_spi_init);
+
+int aml_cimax_spi_exit(struct aml_cimax *cimax)
+{
+ struct cimax_spi *spi = cimax_to_spi(cimax);
+
+ if (!spi)
+ return -ENODEV;
+
+ aml_cimax_spi_mod_exit();
+
+ /*unregister driver*/
+ spi_unregister_driver(&cimax_spi_dev_driver);
+ /*unregister device*/
+ spi_unregister_device(spi->dev);
+
+ if (spi->irq_io)
+ gpio_free(spi->irq_io);
+ if (spi->rst_io)
+ gpio_free(spi->rst_io);
+
+ kfree(spi->cis);
+
+ kfree(spi);
+ cimax->priv = NULL;
+
+ g_spi = NULL;
+ return 0;
+}
+EXPORT_SYMBOL(aml_cimax_spi_exit);
+
+static int cimax_spi_reset(struct cimax_spi *spi, int reset_val)
+{
+ pr_dbg("reset spi:%p, rst:%d\n", spi, spi ? spi->rst_io : -1);
+ if (!spi)
+ return -ENODEV;
+
+ pr_dbg("cimax spi reset\n");
+
+ cimax_spi_setup_poll(spi, STOP_MODE);
+
+ cimax_spi_hw_reset(spi, reset_val);
+
+ /*notify unplugged*/
+ aml_cimax_camchanged(spi->cimax, 0, 0);
+ aml_cimax_camchanged(spi->cimax, 1, 0);
+
+ spi->cam_inserted[0] = spi->cam_inserted[1] = 0;
+ spi->cam_data_ready[0] = spi->cam_data_ready[1] = 0;
+
+ /*async start fw*/
+ cimax_spi_load_fw(spi);
+
+ /*cimax_spi_setup_poll(spi, cimax_poll_mode? POLL_MODE : INT_MODE);*/
+ return 0;
+}
+
+static ssize_t reset_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ int ret;
+ ret = sprintf(buf, "echo 1 > %s\n", attr->attr.name);
+ return ret;
+}
+
+static ssize_t reset_store(struct class *class,
+ struct class_attribute *attr, const char *buf, size_t size)
+{
+ int ret;
+ int val = 0;
+ if (!g_spi)
+ return size;
+ ret = sscanf(buf, "%i", &val);
+ if (ret == 1)
+ ret = cimax_spi_reset(g_spi, val);
+ return size;
+}
+
+static ssize_t debug_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ int ret = 0;
+ if (!g_spi)
+ return ret;
+
+ ret = sprintf(buf, "poll mode: %d\n", g_spi->poll_mode);
+ ret += sprintf(buf+ret, "status slot[0]=[%d] slot[1]=[%d]\n",
+ g_spi->cam_inserted[0], g_spi->cam_inserted[1]);
+ ret += sprintf(buf+ret, "data slot[0]=[%d] slot[1]=[%d]\n",
+ g_spi->cam_data_ready[0], g_spi->cam_data_ready[1]);
+ ret += sprintf(buf+ret, "work cnt:%d\n", g_spi->work_cnt);
+ return ret;
+}
+
+static int reg_addr;
+static ssize_t addr_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ int ret = 0;
+ ret = sprintf(buf, "addr = 0x%04x\n", reg_addr);
+ return ret;
+}
+
+static ssize_t addr_store(struct class *class,
+ struct class_attribute *attr, const char *buf, size_t size)
+{
+ if (!g_spi)
+ return size;
+ if (sscanf(buf, "%i", ®_addr) == 1)
+ return size;
+ return size;
+}
+
+static ssize_t reg_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ int ret = 0;
+ u8 reg_val = 0;
+ struct aml_cimax *cimax = NULL;
+
+ if (!g_spi)
+ return ret;
+
+ cimax = g_spi->cimax;
+ ret = aml_cimax_spi_read_reg(cimax, reg_addr, ®_val, 1);
+ if (ret)
+ ret = sprintf(buf, "read fail, err=%d\n", ret);
+ else
+ ret = sprintf(buf, "reg[0x%04x] = 0x%02x\n", reg_addr, reg_val);
+ return ret;
+}
+
+static ssize_t reg_store(struct class *class,
+ struct class_attribute *attr, const char *buf, size_t size)
+{
+ int ret = 0;
+ struct aml_cimax *cimax = NULL;
+ int val = 0;
+ u8 reg_val = 0;
+
+ if (!g_spi)
+ return size;
+
+ if (sscanf(buf, "%i", &val) != 1)
+ return size;
+ reg_val = val;
+ cimax = g_spi->cimax;
+ ret = aml_cimax_spi_write_reg(cimax, reg_addr, ®_val, 1);
+ if (ret)
+ return ret;
+ return size;
+}
+
+static int cis_mode; /*0:hex 1:binary*/
+static ssize_t cis_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ int ret = 0;
+
+ if (!g_spi || !g_spi->cis)
+ return ret;
+
+ if (cis_mode == 0) {
+ int i;
+ for (i = 0; i < CIS_MAX; i++) {
+ if (i && !(i & 0xf))
+ ret += sprintf(buf+ret, "\n");
+ ret += sprintf(buf+ret, "%02X ", g_spi->cis[i]);
+ }
+ ret += sprintf(buf+ret, "\n");
+ return ret;
+ } else {
+ memcpy(buf, g_spi->cis, CIS_MAX);
+ return CIS_MAX;
+ }
+ return ret;
+}
+
+static ssize_t cis_store(struct class *class,
+ struct class_attribute *attr, const char *buf, size_t size)
+{
+ if (size >= 3
+ && !memcmp(buf, "bin", 3))
+ cis_mode = 1;
+ else
+ cis_mode = 0;
+ return size;
+}
+
+static ssize_t ts_rate_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ int ret = 0;
+ u8 lsb = 0, msb = 0, plen = 0;
+ struct aml_cimax *cimax = NULL;
+ int err = 0;
+
+ if (!g_spi)
+ return ret;
+
+ cimax = g_spi->cimax;
+ err = aml_cimax_spi_read_reg(cimax, PCK_LENGTH, &plen, 1);
+ err |= aml_cimax_spi_read_reg(cimax, BITRATE_CH0_LSB, &lsb, 1);
+ err |= aml_cimax_spi_read_reg(cimax, BITRATE_CH0_MSB, &msb, 1);
+ if (err || !byte_to_u16(msb, lsb))
+ ret += sprintf(buf+ret, "read fail, err=%d\n", err);
+ else
+ ret += sprintf(buf+ret, "rate[0] = %d Kbps\n",
+ 540*plen*8/byte_to_u16(msb, lsb));
+ if (err)
+ return ret;
+
+ err = aml_cimax_spi_read_reg(cimax, BITRATE_CH1_LSB, &lsb, 1);
+ err |= aml_cimax_spi_read_reg(cimax, BITRATE_CH1_MSB, &msb, 1);
+ if (err || !byte_to_u16(msb, lsb))
+ ret += sprintf(buf+ret, "read fail, err=%d\n", err);
+ else
+ ret += sprintf(buf+ret, "rate[1] = %d Kbps\n",
+ 540*plen*8/byte_to_u16(msb, lsb));
+ return ret;
+}
+
+static ssize_t loop_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ int ret = 0;
+ u8 ch = 0, mod = 0;
+ struct aml_cimax *cimax = NULL;
+ int err = 0;
+
+ if (!g_spi)
+ return ret;
+
+ cimax = g_spi->cimax;
+ err = aml_cimax_spi_read_reg(cimax, ROUTER_CAM_CH, &ch, 1);
+ err |= aml_cimax_spi_read_reg(cimax, ROUTER_CAM_MOD, &mod, 1);
+ if (err) {
+ ret = sprintf(buf, "read fail, err=%d\n", err);
+ return ret;
+ }
+ ret += sprintf(buf + ret, "OUT-0 <= ");
+ switch (ch & 0x0f) {
+ case 0x0:
+ ret += sprintf(buf + ret, "CAM-A"); break;
+ case 0x1:
+ ret += sprintf(buf + ret, "CH0-IN"); break;
+ case 0x2:
+ ret += sprintf(buf + ret, "CH1-IN"); break;
+ case 0x3:
+ ret += sprintf(buf + ret, "REMAPPER"); break;
+ case 0x4:
+ ret += sprintf(buf + ret, "PREHEADER"); break;
+ case 0x5:
+ ret += sprintf(buf + ret, "CAM-B"); break;
+ case 0x6:
+ ret += sprintf(buf + ret, "GAPREMOVER-0"); break;
+ case 0x7:
+ ret += sprintf(buf + ret, "GAPREMOVER-1"); break;
+ case 0x8:
+ ret += sprintf(buf + ret, "NONE"); break;
+ default:
+ ret += sprintf(buf + ret, "UNKNOWN"); break;
+ }
+ ret += sprintf(buf + ret, "\nCAM-A <= ");
+ switch (mod & 0x07) {
+ case 0x1:
+ ret += sprintf(buf + ret, "CH0-IN"); break;
+ case 0x2:
+ ret += sprintf(buf + ret, "CH1-IN"); break;
+ case 0x3:
+ ret += sprintf(buf + ret, "REMAPPER"); break;
+ case 0x4:
+ ret += sprintf(buf + ret, "PREHEADER"); break;
+ case 0x5:
+ ret += sprintf(buf + ret, "CAM-B"); break;
+ case 0x6:
+ ret += sprintf(buf + ret, "GAPREMOVER-0"); break;
+ case 0x7:
+ ret += sprintf(buf + ret, "GAPREMOVER-1"); break;
+ default:
+ ret += sprintf(buf + ret, "NONE"); break;
+ }
+ ret += sprintf(buf + ret, "\n");
+
+ return ret;
+}
+
+
+static ssize_t loop_store(struct class *class,
+ struct class_attribute *attr, const char *buf, size_t size)
+{
+ int loop = 0;
+ int err = 0;
+ struct aml_cimax *cimax = NULL;
+
+ if (!g_spi)
+ return size;
+
+ if (sscanf(buf, "%i", &loop) == 1) {
+ int a = g_spi->cam_inserted[0];
+ int b = g_spi->cam_inserted[1];
+ u8 cm[2];
+ cm[0] = loop ? (b ? 0x85 : 0x80) : 0x81;/*CH*/
+ cm[1] = loop ? (a ? 0x51 : 0x11) : 0x00;/*MOD*/
+ cimax = g_spi->cimax;
+ err = aml_cimax_spi_write_reg(cimax, ROUTER_CAM_CH, cm, 2);
+ }
+ return size;
+}
+
+static ssize_t slot_reset_store(struct class *class,
+ struct class_attribute *attr, const char *buf, size_t size)
+{
+ int err = 0;
+ int slot = 0;
+ struct aml_cimax *cimax = NULL;
+
+ if (!g_spi)
+ return size;
+
+ if (sscanf(buf, "%i", &slot) == 1) {
+ if (slot == 0 || slot == 1) {
+ pr_dbg("reset slot %d\n", slot);
+ cimax = g_spi->cimax;
+ err = aml_cimax_spi_slot_reset(cimax, slot);
+ }
+ }
+ return size;
+}
+
+static ssize_t detect_store(struct class *class,
+ struct class_attribute *attr, const char *buf, size_t size)
+{
+ int err = 0;
+ int slot = 0;
+ struct aml_cimax *cimax = NULL;
+
+ if (!g_spi)
+ return size;
+
+ if (sscanf(buf, "%i", &slot) == 1) {
+ if (slot == 0 || slot == 1) {
+ int addr = (!slot) ? MOD_CTRL_A : MOD_CTRL_B;
+ u8 reg = 0;
+ cimax = g_spi->cimax;
+ err = aml_cimax_spi_read_reg(cimax, addr, ®, 1);
+ g_spi->cam_inserted[slot] = reg & 1;
+ pr_dbg("detect slot(%d): %d\n", slot, reg & 1);
+ }
+ }
+ return size;
+}
+
+static struct class_attribute cimax_spi_class_attrs[] = {
+ __ATTR_RW(reset),
+ __ATTR_RO(debug),
+ __ATTR_RW(addr),
+ __ATTR_RW(reg),
+ __ATTR_RW(cis),
+ __ATTR_RO(ts_rate),
+ __ATTR_RW(loop),
+ __ATTR_WO(slot_reset),
+ __ATTR_WO(detect),
+ __ATTR_NULL
+};
+
+static struct class cimax_spi_class = {
+ .name = "cimax_spi",
+ .class_attrs = cimax_spi_class_attrs,
+};
+
+static int aml_cimax_spi_mod_init(void)
+{
+ int ret;
+ pr_dbg("Amlogic CIMAX SPI Init\n");
+ ret = class_register(&cimax_spi_class);
+ return 0;
+}
+
+static void aml_cimax_spi_mod_exit(void)
+{
+ pr_dbg("Amlogic CIMAX SPI Exit\n");
+ class_unregister(&cimax_spi_class);
+}
+
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/aml_cimax_spi.h b/drivers/stream_input/parser/dvb_ci/cimax/aml_cimax_spi.h
new file mode 100644
index 0000000..3548de0
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/aml_cimax_spi.h
@@ -0,0 +1,20 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ *
+***************************************************************************/
+
+#ifndef _AML_CIMAX_SPI_H_
+#define _AML_CIMAX_SPI_H_
+
+#include <linux/platform_device.h>
+#include "aml_cimax.h"
+
+int aml_cimax_spi_init(struct platform_device *pdev, struct aml_cimax *ci);
+int aml_cimax_spi_exit(struct aml_cimax *ci);
+
+#endif
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/aml_cimax_usb.c b/drivers/stream_input/parser/dvb_ci/cimax/aml_cimax_usb.c
new file mode 100644
index 0000000..b74b34a
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/aml_cimax_usb.c
@@ -0,0 +1,1714 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ *
+***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/amlogic/aml_gpio_consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/of_irq.h>
+#include <linux/irq.h>
+#include <linux/mutex.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+//#include <linux/switch.h>
+
+#include "aml_cimax.h"
+#include "./usb/SRC/cimax+usb-driver.h"
+
+#define MOD_NAME "aml_cimax_usb"
+
+#define pr_dbg(fmt...)\
+ do {\
+ if (cimax_usb_debug)\
+ pr_info("cimax_usb: "fmt);\
+ } while (0)
+#define pr_inf(fmt...) pr_info("cimax_usb: "fmt)
+#define pr_error(fmt...) pr_err("AML_CIMAX_USB: " fmt)
+
+/*
+ Uncomment below and enable permanent power in cfg
+ to disable dynamic power control mechanism
+*/
+/*#define DISABLE_POWER_PATCH*/
+
+#define BUFFIN_CFG 0x0000
+#define BUFFIN_ADDR_LSB 0x0001
+#define BUFFIN_ADDR_MSB 0x0002
+#define BUFFIN_DATA 0x0003
+#define BUFFOUT_CFG 0x0004
+#define BUFFOUT_ADDR_LSB 0x0005
+#define BUFFOUT_ADDR_MSB 0x0006
+#define BUFFOUT_DATA 0x0007
+#define BOOT_Key 0x0008
+#define BOOT_Status 0x0009
+#define BOOT_Test 0x000A
+#define usb2_0_irq_mask 0x0010
+#define usb2_0_status 0x0011
+#define usb2_0_rx 0x0012
+#define usb2_0_tx 0x0013
+#define SPI_Slave_Ctrl 0x0018
+#define SPI_Slave_Status 0x0019
+#define SPI_Slave_Rx 0x001A
+#define SPI_Slave_Tx 0x001B
+#define SPI_Slave_Mask 0x001C
+#define UCSG_Ctrl 0x0020
+#define UCSG_Status 0x0021
+#define UCSG_RxData 0x0022
+#define UCSG_TxData 0x0023
+#define PCtrl_Ctrl 0x0028
+#define PCtrl_Status 0x0029
+#define PCtrl_NbByte_LSB 0x002A
+#define PCtrl_NbByte_MSB 0x002B
+#define SPI_Master_Ctl 0x0030
+#define SPI_Master_NCS 0x0031
+#define SPI_Master_Status 0x0032
+#define SPI_Master_TxBuf 0x0033
+#define SPI_Master_RxBuf 0x0034
+#define BISTRAM_Ctl 0x0038
+#define BISTRAM_Bank 0x0039
+#define BISTRAM_Pat 0x003A
+#define BISTRAM_SM 0x003B
+#define BISTRAM_AddrLSB 0x003C
+#define BISTROM_Config 0x0040
+#define BISTROM_SignatureLSB 0x0041
+#define BISTROM_SignatureMSB 0x0042
+#define BISTROM_StartAddrLSB 0x0043
+#define BISTROM_StartAddrMSB 0x0043
+#define BISTROM_StopAddrLSB 0x0043
+#define BISTROM_StopAddrMSB 0x0043
+#define CkMan_Config 0x0048
+#define CkMan_Select 0x0049
+#define CkMan_Test 0x004A
+#define Revision_Number 0x004B
+#define ResMan_Config 0x0050
+#define ResMan_Status 0x0051
+#define ResMan_WD 0x0052
+#define ResMan_WD_MSB 0x0053
+#define CPU_Test 0x0060
+#define IrqMan_Config0 0x0068
+#define IrqMan_Config1 0x0069
+#define IrqMan_Irq0 0x006A
+#define IrqMan_NMI 0x006B
+#define IrqMan_SleepKey 0x006C
+#define Tim_Config 0x0070
+#define Tim_Value_LSB 0x0071
+#define Tim_Value_MSB 0x0072
+#define Tim_Comp_LSB 0x0073
+#define Tim_Comp_MSB 0x0074
+#define TI_Config 0x0076
+#define TI_Data 0x0077
+#define TI_Reg0 0x0078
+#define TI_Reg1 0x0079
+#define TI_Reg2 0x007A
+#define TI_Reg3 0x007B
+#define TI_Reg4 0x007C
+#define TI_ROM1 0x007D
+#define TI_ROM2 0x007E
+#define TI_ROM3 0x007F
+#define DVBCI_START_ADDR 0x0100
+#define DVBCI_END_ADDR 0x017F
+#define DATA 0x0180
+/*#define CTRL 0x0181*/
+#define QB_HOST 0x0182
+#define LEN_HOST_LSB 0x0183
+#define LEN_HOST_MSB 0x0184
+#define FIFO_TX_TH_LSB 0x0185
+#define FIFO_TX_TH_MSB 0x0186
+#define FIFO_TX_D_NB_LSB 0x0187
+#define FIFO_TX_D_NB_MSB 0x0188
+#define QB_MOD_CURR 0x0189
+#define LEN_MOD_CURR_LSB 0x018A
+#define LEN_MOD_CURR_MSB 0x018B
+#define QB_MOD 0x018C
+#define LEN_MOD_LSB 0x018D
+#define LEN_MOD_MSB 0x018E
+#define FIFO_RX_TH_LSB 0x018F
+#define FIFO_RX_TH_MSB 0x0190
+#define FIFO_RX_D_NB_LSB 0x0191
+#define FIFO_RX_D_NB_MSB 0x0192
+#define IT_STATUS_0 0x0193
+#define IT_STATUS_1 0x0194
+#define IT_MASK_0 0x0195
+#define IT_MASK_1 0x0196
+#define IT_HOST_PIN_CFG 0x0200
+#define CFG_0 0x0201
+#define CFG_1 0x0202
+#define CFG_2 0x0203
+#define IT_HOST 0x0204
+#define MOD_IT_STATUS 0x0205
+#define MOD_IT_MASK 0x0206
+#define MOD_CTRL_A 0x0207
+#define MOD_CTRL_B 0x0208
+#define DEST_SEL 0x0209
+#define CAM_MSB_ADD 0x020A
+#define GPIO0_DIR 0x020B
+#define GPIO0_DATA_IN 0x020C
+#define GPIO0_DATA_OUT 0x020D
+#define GPIO0_STATUS 0x020E
+#define GPIO0_IT_MASK 0x020F
+#define GPIO0_DFT 0x0210
+#define GPIO0_MASK_DATA 0x0211
+#define GPIO1_DIR 0x0212
+#define GPIO1_DATA_IN 0x0213
+#define GPIO1_DATA_OUT 0x0214
+#define GPIO1_STATUS 0x0215
+#define GPIO1_IT_MASK 0x0216
+#define MEM_ACC_TIME_A 0x0217
+#define MEM_ACC_TIME_B 0x0218
+#define IO_ACC_TIME_A 0x0219
+#define IO_ACC_TIME_B 0x021A
+#define EXT_CH_ACC_TIME_A 0x021B
+#define EXT_CH_ACC_TIME_B 0x021C
+#define PAR_IF_0 0x021D
+#define PAR_IF_1 0x021E
+#define PAR_IF_CTRL 0x021F
+#define PCK_LENGTH 0x0220
+#define USB2TS_CTRL 0x0221
+#define USB2TS0_RDL 0x0222
+#define USB2TS1_RDL 0x0223
+#define TS2USB_CTRL 0x0224
+#define TSOUT_PAR_CTRL 0x0225
+#define TSOUT_PAR_CLK_SEL 0x0226
+#define S2P_CH0_CTRL 0x0227
+#define S2P_CH1_CTRL 0x0228
+#define P2S_CH0_CTRL 0x0229
+#define P2S_CH1_CTRL 0x022A
+#define TS_IT_STATUS 0x022B
+#define TS_IT_MASK 0x022C
+#define IN_SEL 0x022D
+#define OUT_SEL 0x022E
+#define ROUTER_CAM_CH 0x022F
+#define ROUTER_CAM_MOD 0x0230
+#define FIFO_CTRL 0x0231
+#define FIFO1_2_STATUS 0x0232
+#define FIFO3_4_STATUS 0x0233
+#define GAP_REMOVER_CH0_CTRL 0x0234
+#define GAP_REMOVER_CH1_CTRL 0x0235
+#define SYNC_RTV_CTRL 0x0236
+#define SYNC_RTV_CH0_SYNC_NB 0x0237
+#define SYNC_RTV_CH0_PATTERN 0x0238
+#define SYNC_RTV_CH1_SYNC_NB 0x0239
+#define SYNC_RTV_CH1_PATTERN 0x023A
+#define SYNC_RTV_OFFSET_PATT 0x023B
+#define CTRL_FILTER 0x023D
+#define PID_EN_FILTER_CH0 0x023E
+#define PID_EN_FILTER_CH1 0x023F
+#define PID_LSB_FILTER_CH0_0 0x0240
+#define PID_MSB_FILTER_CH0_0 0x0241
+#define PID_LSB_FILTER_CH0_1 0x0242
+#define PID_MSB_FILTER_CH0_1 0x0243
+#define PID_LSB_FILTER_CH0_2 0x0244
+#define PID_MSB_FILTER_CH0_2 0x0245
+#define PID_LSB_FILTER_CH0_3 0x0246
+#define PID_MSB_FILTER_CH0_3 0x0247
+#define PID_LSB_FILTER_CH0_4 0x0248
+#define PID_MSB_FILTER_CH0_4 0x0249
+#define PID_LSB_FILTER_CH0_5 0x024A
+#define PID_MSB_FILTER_CH0_5 0x024B
+#define PID_LSB_FILTER_CH0_6 0x024C
+#define PID_MSB_FILTER_CH0_6 0x024D
+#define PID_LSB_FILTER_CH0_7 0x024E
+#define PID_MSB_FILTER_CH0_7 0x024F
+#define PID_LSB_FILTER_CH1_0 0x0260
+#define PID_MSB_FILTER_CH1_0 0x0261
+#define PID_LSB_FILTER_CH1_1 0x0262
+#define PID_MSB_FILTER_CH1_1 0x0263
+#define PID_LSB_FILTER_CH1_2 0x0264
+#define PID_MSB_FILTER_CH1_2 0x0265
+#define PID_LSB_FILTER_CH1_3 0x0266
+#define PID_MSB_FILTER_CH1_3 0x0267
+#define PID_LSB_FILTER_CH1_4 0x0268
+#define PID_MSB_FILTER_CH1_4 0x0269
+#define PID_LSB_FILTER_CH1_5 0x026A
+#define PID_MSB_FILTER_CH1_5 0x026B
+#define PID_LSB_FILTER_CH1_6 0x026C
+#define PID_MSB_FILTER_CH1_6 0x026D
+#define PID_LSB_FILTER_CH1_7 0x026E
+#define PID_MSB_FILTER_CH1_7 0x026F
+#define PID_OLD_LSB_REMAPPER_0 0x0280
+#define PID_OLD_MSB_REMAPPER_0 0x0281
+#define PID_OLD_LSB_REMAPPER_1 0x0282
+#define PID_OLD_MSB_REMAPPER_1 0x0283
+#define PID_OLD_LSB_REMAPPER_2 0x0284
+#define PID_OLD_MSB_REMAPPER_2 0x0285
+#define PID_OLD_LSB_REMAPPER_3 0x0286
+#define PID_OLD_MSB_REMAPPER_3 0x0287
+#define PID_OLD_LSB_REMAPPER_4 0x0288
+#define PID_OLD_MSB_REMAPPER_4 0x0289
+#define PID_OLD_LSB_REMAPPER_5 0x028A
+#define PID_OLD_MSB_REMAPPER_5 0x028B
+#define PID_OLD_LSB_REMAPPER_6 0x028C
+#define PID_OLD_MSB_REMAPPER_6 0x028D
+#define PID_OLD_LSB_REMAPPER_7 0x028E
+#define PID_OLD_MSB_REMAPPER_7 0x028F
+#define PID_NEW_LSB_REMAPPER_0 0x02A0
+#define PID_NEW_MSB_REMAPPER_0 0x02A1
+#define PID_NEW_LSB_REMAPPER_1 0x02A2
+#define PID_NEW_MSB_REMAPPER_1 0x02A3
+#define PID_NEW_LSB_REMAPPER_2 0x02A4
+#define PID_NEW_MSB_REMAPPER_2 0x02A5
+#define PID_NEW_LSB_REMAPPER_3 0x02A6
+#define PID_NEW_MSB_REMAPPER_3 0x02A7
+#define PID_NEW_LSB_REMAPPER_4 0x02A8
+#define PID_NEW_MSB_REMAPPER_4 0x02A9
+#define PID_NEW_LSB_REMAPPER_5 0x02AA
+#define PID_NEW_MSB_REMAPPER_5 0x02AB
+#define PID_NEW_LSB_REMAPPER_6 0x02AC
+#define PID_NEW_MSB_REMAPPER_6 0x02AD
+#define PID_NEW_LSB_REMAPPER_7 0x02AE
+#define PID_NEW_MSB_REMAPPER_7 0x02AF
+#define MERGER_DIV_MICLK 0x02C0
+#define PID_AND_SYNC_REMAPPER_CTRL 0x02C1
+#define PID_EN_REMAPPER 0x02C2
+#define SYNC_SYMBOL 0x02C3
+#define PID_AND_SYNC_REMAPPER_INV_CTRL 0x02C4
+#define BITRATE_CH0_LSB 0x02C5
+#define BITRATE_CH0_MSB 0x02C6
+#define BITRATE_CH1_LSB 0x02C7
+#define BITRATE_CH1_MSB 0x02C8
+#define STATUS_CLK_SWITCH_0 0x02C9
+#define STATUS_CLK_SWITCH_1 0x02CA
+#define RESET_CLK_SWITCH_0 0x02CB
+#define RESET_CLK_SWITCH_1 0x02CC
+#define PAD_DRVSTR_CTRL 0x02CD
+#define PAD_PUPD_CTRL 0x02CE
+#define PRE_HEADER_ADDER_CH0_0 0x02D0
+#define PRE_HEADER_ADDER_CH0_1 0x02D1
+#define PRE_HEADER_ADDER_CH0_2 0x02D2
+#define PRE_HEADER_ADDER_CH0_3 0x02D3
+#define PRE_HEADER_ADDER_CH0_4 0x02D4
+#define PRE_HEADER_ADDER_CH0_5 0x02D5
+#define PRE_HEADER_ADDER_CH0_6 0x02D6
+#define PRE_HEADER_ADDER_CH0_7 0x02D7
+#define PRE_HEADER_ADDER_CH0_8 0x02D8
+#define PRE_HEADER_ADDER_CH0_9 0x02D9
+#define PRE_HEADER_ADDER_CH0_10 0x02DA
+#define PRE_HEADER_ADDER_CH0_11 0x02DB
+#define PRE_HEADER_ADDER_CH1_0 0x02E0
+#define PRE_HEADER_ADDER_CH1_1 0x02E1
+#define PRE_HEADER_ADDER_CH1_2 0x02E2
+#define PRE_HEADER_ADDER_CH1_3 0x02E3
+#define PRE_HEADER_ADDER_CH1_4 0x02E4
+#define PRE_HEADER_ADDER_CH1_5 0x02E5
+#define PRE_HEADER_ADDER_CH1_6 0x02E6
+#define PRE_HEADER_ADDER_CH1_7 0x02E7
+#define PRE_HEADER_ADDER_CH1_8 0x02E8
+#define PRE_HEADER_ADDER_CH1_9 0x02E9
+#define PRE_HEADER_ADDER_CH1_10 0x02EA
+#define PRE_HEADER_ADDER_CH1_11 0x02EB
+#define PRE_HEADER_ADDER_CTRL 0x02EC
+#define PRE_HEADER_ADDER_LEN 0x02ED
+#define PRE_HEADER_REMOVER_CTRL 0x02EE
+#define FSM_DVB 0x02F0
+#define TS2USB_FSM_DEBUG 0x02F2
+#define TSOUT_PAR_FSM_DEBUG 0x02F3
+#define GAP_REMOVER_FSM_DEBUG 0x02F4
+#define PID_AND_SYNC_REMAPPER_FSM_DEBUG 0x02F5
+#define PRE_HEADER_ADDER_FSM_DEBUG 0x02F6
+#define SYNC_RTV_FSM_DEBUG 0x02F7
+#define CHECK_PHY_CLK 0x0E00
+#define USB_CTRL1 0x0E01
+#define USB_ISO2_out 0x0800
+#define USB_ISO1_out 0x1000
+#define USB_Interrupt_out 0x1E00
+#define USB_Bulk_in 0x1F00
+#define CC2_Buffer_out 0x2000
+#define USB_EP0 0x30C0
+#define CC2_Buffer_in 0x4000
+#define USB_ISO2_in 0x5800
+#define USB_ISO1_in 0x6000
+#define nmb_vector_address_lsb 0xFFFA
+#define nmb_vector_address_msb 0xFFFB
+#define reset_vector_address_lsb 0xFFFC
+#define reset_vector_address_msb 0xFFFD
+#define irb_vector_address_lsb 0xFFFE
+#define irb_vector_address_msb 0xFFFF
+
+
+#define CIMAX_REG_HDR_SIZE 4
+#define CIMAX_REG_PLD_SIZE 255
+#define CIMAX_CAM_HDR_SIZE 4
+#define CIMAX_CAM_PLD_SIZE 65535
+
+#define DEF_LOCK(_l_) struct mutex _l_
+
+struct cimax_usb {
+ struct platform_device *pdev;
+ struct device_s *dev;
+
+ struct aml_cimax *cimax;
+
+ u8 buf[CIMAX_REG_HDR_SIZE + CIMAX_CAM_HDR_SIZE + CIMAX_CAM_PLD_SIZE];
+ int buf_size;
+
+ int cam_inserted[2];
+#define IN_INSERTED 0x01
+#define IN_POWERED 0x02
+#define IN_LINKED 0x04
+ int cam_data_ready[2];
+
+ int poll_mode;
+#define STOP_MODE 0
+#define POLL_MODE 1
+#define INT_MODE 2
+
+ int rst_io;
+
+ struct workqueue_struct *workq;
+ struct delayed_work work;
+ int work_auto_restart;
+ int work_cnt;
+
+ struct delayed_work power_work;
+ int power_work_cnt;
+ int cam_det;
+
+ DEF_LOCK(lock);
+#define lock_init(_usb) mutex_init(&(_usb)->lock)
+#define lock_lock(_usb) do {\
+ int err = mutex_lock_interruptible(&(_usb)->lock);\
+ if (err)\
+ return err;\
+} while (0)
+#define lock_unlock(_usb) mutex_unlock(&(_usb)->lock)
+
+ u8 *cis;
+#define CIS_MAX 512
+};
+
+static struct cimax_usb *g_usb;
+
+MODULE_PARM_DESC(usbdebug, "enable verbose debug messages");
+static int cimax_usb_debug = 1;
+module_param_named(usbdebug, cimax_usb_debug, int, 0644);
+
+MODULE_PARM_DESC(usbpoll_interval, "interval for usb poll");
+static int usb_poll_interval = 100;
+module_param_named(usbpoll_interval, usb_poll_interval, int, 0644);
+
+MODULE_PARM_DESC(usbpoll_mode, "set cimax poll mode, need reset");
+static int cimax_poll_mode = 1;
+module_param_named(usbpoll_mode, cimax_poll_mode, int, 0644);
+
+MODULE_PARM_DESC(usbcam_irq_mode, "set cam irq mode, need reset");
+static int cam_irq_mode;
+module_param_named(usbcam_irq_mode, cam_irq_mode, int, 0644);
+
+
+#define CIMAX_REG_READ 0xff
+#define CIMAX_REG_READ_OK 0x4c
+#define CIMAX_REG_WRITE 0x7f
+#define CIMAX_REG_WRITE_OK 0x4d
+#define CIMAX_REG_INIT 0x00
+#define CIMAX_REG_INIT_OK 0x4b
+#define CIMAX_REG_CMD_ERROR 0x51
+
+#define CIMAX_CAM_RESET 0x01
+#define CIMAX_CAM_RESET_OK 0x40
+#define CIMAX_CAM_CIS 0x02
+#define CIMAX_CAM_CIS_OK 0x41
+#define CIMAX_CAM_COR 0x03
+#define CIMAX_CAM_COR_OK 0x42
+#define CIMAX_CAM_NEG 0x04
+#define CIMAX_CAM_NEG_OK 0x43
+#define CIMAX_CAM_WLPDU 0x05
+#define CIMAX_CAM_WLPDU_OK 0x44
+#define CIMAX_CAM_RLPDU 0x06
+#define CIMAX_CAM_RLPDU_OK 0x46
+#define CIMAX_CAM_EVT 0x0d
+#define CIMAX_CAM_DET_OK 0x45
+#define CIMAX_CAM_NOCAM 0x49
+#define CIMAX_CAM_ERROR 0x4a
+#define CIMAX_CAM_NOEVT 0x55
+#define CIMAX_CAM_DATA_READY 0x4e
+#define CIMAX_CAM_WBUSY 0x54
+#define CIMAX_CAM_PENDING 0x56
+#define CIMAX_CAM_REGSTAT 0x0e
+#define CIMAX_CAM_REGSTAT_OK 0x57
+
+
+#define CIMAX_CAM_PKT_CNT_VAL 1
+
+#define CIMAX_SLOT_A 0
+#define CIMAX_SLOT_B 1
+
+#define CIMAX_CMD_RESP_MASK 0x7f
+
+#define cimax_to_usb(_c) ((struct cimax_usb *)((_c)->priv))
+#define dev_to_usb(_d) ((struct cimax_usb *)usb_get_drvdata(_d))
+
+#define byte_to_u16(_b1, _b2) (((_b1)<<8) | (_b2))
+
+#define hdr_cmd_resp(_s) ((_s)->buf[0] & CIMAX_CMD_RESP_MASK)
+
+#define reg_hdr(_s) ((_s)->buf)
+#define reg_addr(_s) byte_to_u16((_s)->buf[1], (_s)->buf[2])
+#define reg_hdr_dat_size(_s) ((_s)->buf[3])
+#define reg_dat(_s) (&((_s)->buf[CIMAX_REG_HDR_SIZE]))
+
+#define cam_hdr(_s) ((_s)->buf)
+#define cam_hdr_slot(_s) (((_s)->buf[0] & 0x80) ? 1 : 0)
+#define cam_hdr_pkt_cnt(_s) ((_s)->buf[1])
+#define cam_hdr_dat_size(_s) byte_to_u16((_s)->buf[2], (_s)->buf[3])
+#define cam_dat(_s) (&((_s)->buf[CIMAX_CAM_HDR_SIZE]))
+
+#define REG_TIMEOUT 500
+#define CAM_TIMEOUT 5000
+
+static int aml_cimax_usb_mod_init(void);
+static void aml_cimax_usb_mod_exit(void);
+
+static int cimax_usb_set_loop(struct cimax_usb *usb, int loop);
+
+static void dump(char *title, u8 *buf, int size)
+{
+ int i;
+ pr_info("%s\n", title);
+ for (i = 0; i < size; i++) {
+ if (!(i & 0xf))
+ pr_info("\n\t");
+ pr_info("%02x ", *(buf+i));
+ }
+ pr_info("\n");
+}
+
+static void perr(char *err, struct cimax_usb *usb)
+{
+ pr_error("error: %s\n", err);
+ dump("dump:", usb->buf, 16);
+}
+
+static inline unsigned long get_jiffies(void)
+{
+ return (unsigned long)(sched_clock()/10000000);
+}
+
+static int cam_usb_cam_detect(struct cimax_usb *usb, int slot, int flag)
+{
+ usb->cam_inserted[slot] = flag;
+ pr_inf("detect slot(%d): 0x%x(%s)\n",
+ slot, usb->cam_inserted[slot],
+ (!flag) ? "none" :
+ (flag & IN_LINKED) ? "linked" :
+ (flag & IN_POWERED) ? "powered" :
+ (flag & IN_INSERTED) ? "inserted" :
+ "unknown");
+ aml_cimax_slot_state_changed(usb->cimax, slot,
+ usb->cam_inserted[slot]);
+ return 0;
+}
+
+static inline void set_usb_cam_ready(struct cimax_usb *usb, int slot)
+{
+ if (usb->cam_inserted[slot] & IN_POWERED) {
+ cam_usb_cam_detect(usb, slot,
+ usb->cam_inserted[slot] | IN_LINKED);
+ cimax_usb_set_loop(usb, 1);/*set auto-loop*/
+ }
+}
+
+static int init_reg_hdr(u8 *hdr, u8 tag, int addr, int size)
+{
+ hdr[0] = tag;
+ hdr[1] = (addr>>8) & 0xff;
+ hdr[2] = addr & 0xff;
+ hdr[3] = size;
+ return 0;
+}
+
+static int check_reg_hdr(u8 *hdr, u8 tag, int addr, int size)
+{
+ return hdr[0] != tag
+ || hdr[1] != ((addr>>8) & 0xff)
+ || hdr[2] != (addr & 0xff)
+ || hdr[3] != size;
+}
+
+static int aml_cimax_usb_read_reg(struct aml_cimax *cimax, int addr,
+ u8 *buf, int size)
+{
+ struct cimax_usb *usb = cimax_to_usb(cimax);
+ struct device_s *dev = usb->dev;
+ u8 out[CIMAX_REG_HDR_SIZE];
+ int err = 0;
+
+ init_reg_hdr(out, CIMAX_REG_READ, addr, size);
+
+ lock_lock(usb);
+
+ /*pr_dbg("rd %02x:%02x:%02x:%02x\n",
+ out[0], out[1],
+ out[2], out[3]);*/
+ err = cimax_usb_ci_write(dev,
+ out, CIMAX_REG_HDR_SIZE, usb->buf, sizeof(usb->buf));
+ if (err)
+ goto end;
+ if (check_reg_hdr(reg_hdr(usb), CIMAX_REG_READ_OK, addr, size) != 0) {
+ pr_dbg("rd %02x:%02x:%02x:%02x\n",
+ out[0], out[1],
+ out[2], out[3]);
+ perr("read reg fail.", usb);
+ err = -EINVAL;
+ goto end;
+ }
+ memcpy(buf, reg_dat(usb), size);
+end:
+ lock_unlock(usb);
+ return err;
+}
+
+static int aml_cimax_usb_write_reg(struct aml_cimax *cimax, int addr,
+ u8 *buf, int size)
+{
+ struct cimax_usb *usb = cimax_to_usb(cimax);
+ struct device_s *dev = usb->dev;
+ u8 out[CIMAX_REG_HDR_SIZE + CIMAX_REG_PLD_SIZE];
+ int err = 0;
+
+ init_reg_hdr(out, CIMAX_REG_WRITE, addr, size);
+ memcpy(&out[CIMAX_REG_HDR_SIZE], buf, size);
+
+ lock_lock(usb);
+
+ pr_dbg("wr %02x:%02x:%02x:%02x\n",
+ out[0], out[1],
+ out[2], out[3]);
+ err = cimax_usb_ci_write(dev,
+ out, CIMAX_REG_HDR_SIZE + size, usb->buf, sizeof(usb->buf));
+ if (err)
+ goto end;
+ if (check_reg_hdr(reg_hdr(usb), CIMAX_REG_WRITE_OK, addr, 0) != 0) {
+ perr("write reg fail.", usb);
+ err = -EINVAL;
+ goto end;
+ }
+end:
+ lock_unlock(usb);
+ return err;
+}
+
+static inline int init_cam_hdr(u8 *hdr, int cmd, int size)
+{
+ hdr[0] = cmd;
+ hdr[1] = CIMAX_CAM_PKT_CNT_VAL;
+ hdr[2] = (size>>8) & 0xff;
+ hdr[3] = size & 0xff;
+ return 0;
+}
+
+static inline int cam_err(struct cimax_usb *usb)
+{
+ if (hdr_cmd_resp(usb) != CIMAX_CAM_ERROR
+ || cam_hdr_pkt_cnt(usb) != CIMAX_CAM_PKT_CNT_VAL
+ || cam_hdr_dat_size(usb) != 2)
+ return 0;
+ return byte_to_u16(cam_dat(usb)[0], cam_dat(usb)[1]);
+}
+
+static inline char *cam_err_str(int err)
+{
+#define CAMERROR_RESET 0x0101
+#define CAMERROR_CIS_BUF 0x0201
+#define CAMERROR_CIS_SIZE 0x0202
+#define CAMERROR_CAM_NOT_ACT 0x0203
+#define CAMERROR_COR_NOT_READY 0x0301
+#define CAMERROR_COR_VAL_CHK 0x0302
+#define CAMERROR_NEG_NO_RESP 0x0401
+#define CAMERROR_NEG_BAD_SIZE 0x0402
+#define CAMERROR_NEG_NOT_READY 0x0403
+#define CAMERROR_LPDU_NOT_AVAIL 0x0601
+ struct { int err; char *str; } cam_err_strings[] = {
+ {CAMERROR_RESET, "reset error, not ready."},
+ {CAMERROR_CIS_BUF, "cis error, buffer not allocated."},
+ {CAMERROR_CIS_SIZE, "cis error, bad cis size."},
+ {CAMERROR_CAM_NOT_ACT, "cam not activated."},
+ {CAMERROR_COR_NOT_READY, "cam not ready during write COR."},
+ {CAMERROR_COR_VAL_CHK, "COR value check failed."},
+ {CAMERROR_NEG_NO_RESP, "cam not responding when negotiation."},
+ {CAMERROR_NEG_BAD_SIZE, "cam buf size length != 2."},
+ {CAMERROR_NEG_NOT_READY, "cam not ready during negotiation."},
+ {CAMERROR_LPDU_NOT_AVAIL, "lpdu not available."}
+ };
+ int i;
+ for (i = 0;
+ i < sizeof(cam_err_strings)/sizeof(cam_err_strings[0]); i++) {
+ if (cam_err_strings[i].err == err)
+ return cam_err_strings[i].str;
+ }
+ return "err unknown.";
+}
+
+static int cimax_usb_access_cam(struct cimax_usb *usb, int slot,
+ int cmd, u8 *tx, int tx_size, u8 *rx, int rx_size)
+{
+ struct device_s *dev = usb->dev;
+ u8 *out = NULL;
+ int err = 0;
+
+ out = kzalloc(CIMAX_CAM_HDR_SIZE + CIMAX_CAM_PLD_SIZE, GFP_KERNEL);
+ if (!out) {
+ pr_err("no mem for access cam.\n");
+ return -ENOMEM;
+ }
+
+ cmd |= slot ? 0x80 : 0;
+ init_cam_hdr(out, cmd, tx_size);
+ memcpy(&out[CIMAX_CAM_HDR_SIZE], tx, tx_size);
+ /*dump("access cam:", out, CIMAX_CAM_HDR_SIZE+size);*/
+
+ lock_lock(usb);
+
+ err = cimax_usb_ci_write(dev,
+ out, CIMAX_CAM_HDR_SIZE + tx_size, rx, rx_size);
+ if (err)
+ goto end;
+ if (cam_hdr_slot(usb) != slot) {
+ pr_error("expect slot(%d), but slot(%d)\n",
+ slot, cam_hdr_slot(usb));
+ err = -EINVAL;
+ goto end;
+ }
+ switch (hdr_cmd_resp(usb)) {
+ case CIMAX_CAM_NOCAM:
+ pr_dbg("no cam\n");
+ err = -ENODEV;
+ break;
+ case CIMAX_CAM_ERROR:
+ pr_error("cam error\n");
+ pr_error("err code: 0x%04x(%s)\n", cam_err(usb),
+ cam_err_str(cam_err(usb)));
+ err = -ENODEV;
+ break;
+ case CIMAX_CAM_WBUSY:
+ pr_dbg("cam busy\n");
+ err = -EBUSY;
+ break;
+ case CIMAX_CAM_PENDING:
+ pr_dbg("cam pending\n");
+ err = -EAGAIN;
+ break;
+ }
+end:
+ kfree(out);
+ lock_unlock(usb);
+ return err;
+}
+
+static int aml_cimax_usb_read_cis(struct aml_cimax *cimax, int slot,
+ u8 *buf, int size)
+{
+ struct cimax_usb *usb = cimax_to_usb(cimax);
+ int err = 0;
+ int len;
+
+ err = cimax_usb_access_cam(usb, slot, CIMAX_CAM_CIS,
+ NULL, 0, usb->buf, sizeof(usb->buf));
+ if (err)
+ goto end;
+ if (hdr_cmd_resp(usb) != CIMAX_CAM_CIS_OK
+ || cam_hdr_pkt_cnt(usb) != CIMAX_CAM_PKT_CNT_VAL) {
+ perr("read cis fail.", usb);
+ err = -EINVAL;
+ goto end;
+ }
+ len = cam_hdr_dat_size(usb);
+ if (size < len) {
+ pr_error("cis size too large, expect<%d, but:%d\n", size, len);
+ perr("cis fail.", usb);
+ err = -EINVAL;
+ goto end;
+ }
+ memcpy(buf, cam_dat(usb), len);
+
+ if (!usb->cis)
+ usb->cis = kzalloc((len < 512) ? 512 : len, GFP_KERNEL);
+ if (usb->cis)
+ memcpy(usb->cis, cam_dat(usb), len);
+
+end:
+ return err;
+}
+#define CIMAX_CAM_COR_PLD_SIZE 5
+static int aml_cimax_usb_write_cor(struct aml_cimax *cimax, int slot,
+ int addr, u8 *buf)
+{
+ struct cimax_usb *usb = cimax_to_usb(cimax);
+ int err = 0;
+ u8 out[CIMAX_CAM_COR_PLD_SIZE + 8];
+ int sz = CIMAX_CAM_COR_PLD_SIZE;
+
+ out[0] = addr>>8 & 0xff;
+ out[1] = addr & 0xff;
+ out[2] = buf[0];
+ out[3] = 0;
+ out[4] = 0;
+
+ if (!cam_irq_mode) {
+ out[5] = 0x40;/*cam poll mode*/
+ sz++;
+ }
+
+ err = cimax_usb_access_cam(usb, slot, CIMAX_CAM_COR,
+ out, sz, usb->buf, sizeof(usb->buf));
+ if (err)
+ goto end;
+ if (hdr_cmd_resp(usb) != CIMAX_CAM_COR_OK
+ || cam_hdr_pkt_cnt(usb) != CIMAX_CAM_PKT_CNT_VAL
+ || cam_hdr_dat_size(usb) != 0) {
+ perr("write cor fail.", usb);
+ err = -EINVAL;
+ goto end;
+ }
+end:
+ return err;
+}
+#define CIMAX_CAM_NEG_PLD_SIZE 2
+static int aml_cimax_usb_negotiate(struct aml_cimax *cimax, int slot, int size)
+{
+ struct cimax_usb *usb = cimax_to_usb(cimax);
+ int ret = 0;
+ u8 out[CIMAX_CAM_NEG_PLD_SIZE];
+
+ out[0] = (size>>8) & 0xff;
+ out[1] = size & 0xff;
+
+ ret = cimax_usb_access_cam(usb, slot, CIMAX_CAM_NEG,
+ out, CIMAX_CAM_NEG_PLD_SIZE,
+ usb->buf, sizeof(usb->buf));
+ if (ret)
+ goto end;
+ if (hdr_cmd_resp(usb) != CIMAX_CAM_NEG_OK
+ || cam_hdr_pkt_cnt(usb) != CIMAX_CAM_PKT_CNT_VAL
+ || cam_hdr_dat_size(usb) != 2) {
+ perr("negotiate fail.", usb);
+ ret = -EINVAL;
+ goto end;
+ }
+ ret = byte_to_u16(cam_dat(usb)[0], cam_dat(usb)[1]);
+
+ set_usb_cam_ready(usb, slot);
+end:
+ return ret;
+}
+
+static int aml_cimax_usb_write_lpdu(struct aml_cimax *cimax, int slot,
+ u8 *buf, int size)
+{
+ struct cimax_usb *usb = cimax_to_usb(cimax);
+ int ret = 0;
+
+ /*dump("lpdu ->", buf, size);*/
+ ret = cimax_usb_access_cam(usb, slot, CIMAX_CAM_WLPDU,
+ buf, size, usb->buf, sizeof(usb->buf));
+ if (ret)
+ goto end;
+ if (hdr_cmd_resp(usb) != CIMAX_CAM_WLPDU_OK
+ || cam_hdr_pkt_cnt(usb) != CIMAX_CAM_PKT_CNT_VAL
+ || cam_hdr_dat_size(usb) != 0) {
+ perr("write lpdu fail.", usb);
+ ret = -EINVAL;
+ goto end;
+ }
+ ret = size;
+end:
+ return ret;
+}
+
+static int aml_cimax_usb_read_lpdu(struct aml_cimax *cimax, int slot,
+ u8 *buf, int size)
+{
+ struct cimax_usb *usb = cimax_to_usb(cimax);
+ int ret = 0;
+
+ ret = cimax_usb_access_cam(usb, slot, CIMAX_CAM_RLPDU,
+ NULL, 0, usb->buf, sizeof(usb->buf));
+ if (ret)
+ goto end;
+ if (hdr_cmd_resp(usb) != CIMAX_CAM_RLPDU_OK
+ || cam_hdr_pkt_cnt(usb) != CIMAX_CAM_PKT_CNT_VAL) {
+ perr("read lpdu fail.", usb);
+ ret = -EINVAL;
+ goto end;
+ }
+ ret = cam_hdr_dat_size(usb);
+ memcpy(buf, cam_dat(usb), ret);
+
+ /*dump("lpdu <-", buf, ret);*/
+
+ usb->cam_data_ready[slot] = 0;
+end:
+ return ret;
+}
+
+static int aml_cimax_usb_read_cam_status(struct aml_cimax *cimax, int slot)
+{
+ struct cimax_usb *usb = cimax_to_usb(cimax);
+ int ret = 0;
+
+ if (cam_irq_mode && usb->cam_data_ready[slot])
+ return 0x80;
+
+ ret = cimax_usb_access_cam(usb, slot, CIMAX_CAM_REGSTAT,
+ NULL, 0, usb->buf, sizeof(usb->buf));
+ if (ret)
+ goto end;
+ if (hdr_cmd_resp(usb) != CIMAX_CAM_REGSTAT_OK
+ || cam_hdr_pkt_cnt(usb) != CIMAX_CAM_PKT_CNT_VAL
+ || cam_hdr_dat_size(usb) != 1) {
+ perr("read cam status fail.", usb);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ ret = cam_dat(usb)[0];
+end:
+ return ret;
+}
+
+static int aml_cimax_usb_slot_reset(struct aml_cimax *cimax, int slot)
+{
+ struct cimax_usb *usb = cimax_to_usb(cimax);
+ int ret = 0;
+
+ usb->cam_data_ready[slot] = 0;
+
+ ret = cimax_usb_access_cam(usb, slot, CIMAX_CAM_RESET,
+ NULL, 0, usb->buf, sizeof(usb->buf));
+ if (ret)
+ goto end;
+ if (hdr_cmd_resp(usb) != CIMAX_CAM_RESET_OK
+ || cam_hdr_pkt_cnt(usb) != CIMAX_CAM_PKT_CNT_VAL
+ || cam_hdr_dat_size(usb) != 0) {
+ perr("slot reset fail.", usb);
+ ret = -EINVAL;
+ goto end;
+ }
+end:
+ return ret;
+}
+
+static int aml_cimax_usb_cam_reset(struct aml_cimax *cimax, int slot)
+{
+ pr_dbg("Slot(%d): camreset\n", slot);
+ return 0;
+}
+
+static int aml_cimax_usb_slot_shutdown(struct aml_cimax *cimax, int slot)
+{
+ pr_dbg("Slot(%d): shutdown\n", slot);
+ return 0;
+}
+static int aml_cimax_usb_slot_ts_enable(struct aml_cimax *cimax, int slot)
+{
+ pr_dbg("Slot(%d): ts control\n", slot);
+ return 0;
+}
+static int aml_cimax_usb_slot_status(struct aml_cimax *cimax, int slot)
+{
+ struct cimax_usb *usb = cimax_to_usb(cimax);
+ if (usb->cam_inserted[slot] & IN_POWERED) {
+ /*pr_dbg("CA Module present and ready\n");*/
+ return DVB_CA_EN50221_POLL_CAM_PRESENT |
+ DVB_CA_EN50221_POLL_CAM_READY;
+ } else {
+ /*pr_error("CA Module not present or not ready\n");*/
+ }
+ return 0;
+}
+
+static int cimax_usb_cam_plugin(struct cimax_usb *usb, int slot, int plugin)
+{
+ pr_dbg("cam plug: slot(%d) %s\n",
+ slot, plugin ? "plugged" : "unplugged");
+ return aml_cimax_camchanged(usb->cimax, slot, plugin);
+}
+
+static int cimax_usb_set_power(struct cimax_usb *usb, int on)
+{
+ u8 reg = 0;
+ int err = 0;
+ if (!on) {
+ reg = 0;
+ err = aml_cimax_usb_read_reg(usb->cimax, MOD_IT_MASK, ®, 1);
+ if (err)
+ return err;
+ reg |= 0x03;
+ reg &= 0xf3;
+
+ err = aml_cimax_usb_write_reg(usb->cimax, MOD_IT_MASK, ®, 1);
+ if (err)
+ return err;
+ }
+ reg = on ? 0x3 : 0x0;
+ return aml_cimax_usb_write_reg(usb->cimax, GPIO0_DATA_OUT, ®, 1);
+}
+
+static int cimax_usb_check_poe(struct cimax_usb *usb, int *on)
+{
+ u8 reg = 0;
+ int err = 0;
+
+ *on = 0;
+
+ err = aml_cimax_usb_read_reg(usb->cimax, CFG_1, ®, 1);
+ if (err)
+ return err;
+ if (reg & 0x20) {/*if VCCEN*/
+ reg |= 0x08;/*set POE*/
+ err = aml_cimax_usb_write_reg(usb->cimax, CFG_1, ®, 1);
+ if (err)
+ return err;
+ err = aml_cimax_usb_read_reg(usb->cimax, CFG_1, ®, 1);
+ if (err)
+ return err;
+ if (reg & 0x08)/*if POE ok*/
+ *on = 1;
+ }
+ return err;
+}
+
+static void cimax_usb_power_work(struct work_struct *work)
+{
+ struct cimax_usb *usb = container_of(to_delayed_work(work),
+ struct cimax_usb, power_work);
+ int power = 0;
+ int err = 0;
+
+ usb->power_work_cnt++;
+ err = cimax_usb_set_power(usb, 1);
+ if (err)
+ return;
+
+ err = cimax_usb_check_poe(usb, &power);
+ if (err)
+ return;
+
+ if (power) {
+ return;
+ }
+
+ schedule_delayed_work(&usb->power_work, usb_poll_interval);
+}
+
+static int cimax_usb_cam_powerctrl(struct cimax_usb *usb,
+ int slot, int power)
+{
+ if (slot != 0)
+ return 0;
+
+#ifdef DISABLE_POWER_PATCH
+ if (power) {
+ cam_usb_cam_detect(usb, slot,
+ usb->cam_inserted[slot] | IN_POWERED);
+ cimax_usb_cam_plugin(usb, slot, 1);
+ }
+ return 0;
+#else
+ pr_inf("cancel power ctrl previous\n");
+ cancel_delayed_work_sync(&usb->power_work);
+
+ if (!power) {
+ int err = 0;
+ err = cimax_usb_set_power(usb, 0);
+ pr_inf("slot[%d] power off\n", slot);
+ return 0;
+ }
+
+ INIT_DELAYED_WORK(&usb->power_work, &cimax_usb_power_work);
+ schedule_delayed_work(&usb->power_work, usb_poll_interval);
+ pr_inf("slot[%d] power ctrl started\n", slot);
+#endif
+ return 0;
+}
+
+static int cimax_usb_poll(struct cimax_usb *usb)
+{
+ struct device_s *dev = usb->dev;
+ int power = 0;
+ int err = 0;
+ int slot = 0;
+
+ if (!usb->cam_det) {
+ for (slot = 0; slot < 2; slot++) {
+ int addr = (!slot) ? MOD_CTRL_A : MOD_CTRL_B;
+ u8 reg = 0;
+ err = aml_cimax_usb_read_reg(usb->cimax,
+ addr, ®, 1);
+ if (reg & 1) {
+ cam_usb_cam_detect(usb, slot,
+ (reg & 1) ? IN_INSERTED : 0);
+ msleep(200);
+ err = cimax_usb_set_power(usb, (reg & 1));
+ err = cimax_usb_check_poe(usb, &power);
+ pr_inf("slot[%d] power on\n", slot);
+ msleep(200);
+ if (power) {
+ cam_usb_cam_detect(usb, slot,
+ usb->cam_inserted[slot] | IN_POWERED);
+ cimax_usb_cam_plugin(usb, slot, 1);
+ usb->cam_det = 1;
+ }
+ }
+ }
+ return 0;
+ }
+ err = cimax_usb_ci_read_evt(dev, CIMAX_SLOT_A,
+ usb->buf, sizeof(usb->buf));
+ if (err)
+ goto end;
+
+ switch (hdr_cmd_resp(usb)) {
+ case CIMAX_CAM_DET_OK: {
+ int slot = cam_hdr_slot(usb);
+ int insert = cam_dat(usb)[0];
+ if ((!!usb->cam_inserted[slot]) != insert) {
+ cam_usb_cam_detect(usb, slot,
+ insert ? IN_INSERTED : 0);
+ cimax_usb_cam_powerctrl(usb, slot, insert);
+ }
+ if (!insert)
+ usb->cam_det = 0;
+ } break;
+ case CIMAX_CAM_DATA_READY: {
+ int slot = cam_hdr_slot(usb);
+ usb->cam_data_ready[slot] = 1;
+ } break;
+ case CIMAX_CAM_NOEVT:
+ break;
+ default:
+ pr_error("unknown resp:%02x\n", hdr_cmd_resp(usb));
+ break;
+ }
+end:
+ return 0;
+}
+
+static void cimax_usb_poll_work(struct work_struct *work)
+{
+ struct cimax_usb *usb =
+ container_of(to_delayed_work(work), struct cimax_usb, work);
+ usb->work_cnt++;
+ cimax_usb_poll(usb);
+ if (usb->work_auto_restart)
+ queue_delayed_work(usb->workq, &usb->work, usb_poll_interval);
+}
+
+#define CTRL_DISABLE -1
+#define CTRL_STOP 0
+#define CTRL_START 1
+
+static inline int cimax_usb_poll_ctrl(struct cimax_usb *usb, int ctrl)
+{
+ if (ctrl == CTRL_START) {
+ if (usb->workq)
+ return 0;
+ usb->work_auto_restart = 1;
+ usb->workq = create_singlethread_workqueue("cimax_usb");
+ INIT_DELAYED_WORK(&usb->work, &cimax_usb_poll_work);
+ queue_delayed_work(usb->workq,
+ &usb->work, usb_poll_interval);
+ pr_inf("poll started\n");
+ } else {
+ if (!usb->workq)
+ return 0;
+ usb->work_auto_restart = 0;
+ cancel_delayed_work_sync(&usb->work);
+ destroy_workqueue(usb->workq);
+ usb->workq = NULL;
+ pr_inf("poll stopped\n");
+ }
+ return 0;
+}
+
+static int cimax_usb_setup_poll(struct cimax_usb *usb, int poll_mode)
+{
+ if (poll_mode == usb->poll_mode)
+ return 0;
+ switch (poll_mode) {
+ case POLL_MODE:
+ cimax_usb_poll_ctrl(usb, CTRL_START);
+ usb->poll_mode = POLL_MODE;
+ break;
+ case STOP_MODE:
+ if (usb->poll_mode == POLL_MODE)
+ cimax_usb_poll_ctrl(usb, CTRL_DISABLE);
+ usb->poll_mode = STOP_MODE;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int cimax_usb_hw_reset(struct cimax_usb *usb, int reset_val)
+{
+ /*trigger reset io*/
+ if (usb->rst_io) {
+ gpio_direction_output(usb->rst_io, reset_val ? 1 : 0);
+ msleep(50);
+ gpio_direction_output(usb->rst_io, reset_val ? 0 : 1);
+ }
+ return 0;
+}
+
+static int cimax_usb_set_loop(struct cimax_usb *usb, int loop)
+{
+ int a = usb->cam_inserted[0];
+ int b = usb->cam_inserted[1];
+ u8 cm[2];
+
+ pr_inf("set loop: %d\n", loop);
+
+ cm[0] = loop ? (b ? 0x85 : 0x80) : 0x81;/*CH*/
+ cm[1] = loop ? (a ? 0x51 : 0x11) : 0x00;/*MOD*/
+
+ return aml_cimax_usb_write_reg(usb->cimax, ROUTER_CAM_CH, cm, 2);
+}
+
+int cimax_usb_dev_add(struct device_s *dev, int id)
+{
+ pr_inf("dev add\n");
+ if (!g_usb)
+ return 0;
+
+ id = id;
+
+ cimax_usb_device_open(dev);
+ cimax_usb_select_interface(dev, 3);
+
+ lock_lock(g_usb);
+ g_usb->dev = dev;
+ lock_unlock(g_usb);
+
+ if (0)
+ {
+ /*
+ the cimax's fw do not report cam status
+ when board power on with cam plugged,
+ have to check manually here.
+ */
+ int slot = 0;
+ int err = 0;
+ for (slot = 0; slot < 2; slot++) {
+ int addr = (!slot) ? MOD_CTRL_A : MOD_CTRL_B;
+ u8 reg = 0;
+ err = aml_cimax_usb_read_reg(g_usb->cimax,
+ addr, ®, 1);
+ cam_usb_cam_detect(g_usb, slot,
+ (reg & 1) ? IN_INSERTED : 0);
+ cimax_usb_cam_powerctrl(g_usb, slot, (reg & 1));
+ }
+ }
+ cimax_usb_set_power(g_usb, 0);
+ cimax_usb_setup_poll(g_usb, cimax_poll_mode ? POLL_MODE : INT_MODE);
+ return 0;
+}
+EXPORT_SYMBOL(cimax_usb_dev_add);
+
+int cimax_usb_dev_remove(struct device_s *dev, int id)
+{
+ pr_dbg("dev remove\n");
+ if (!g_usb)
+ return 0;
+ id = id;
+ pr_dbg("setup poll -> stop\n");
+ cimax_usb_setup_poll(g_usb, STOP_MODE);
+ pr_dbg("setup poll end\n");
+ lock_lock(g_usb);
+ g_usb->dev = NULL;
+ lock_unlock(g_usb);
+ return 0;
+}
+EXPORT_SYMBOL(cimax_usb_dev_remove);
+
+static int cimax_usb_get_config_from_dts(struct cimax_usb *usb)
+{
+ struct device_node *child = NULL;
+ struct platform_device *pdev = usb->pdev;
+ struct device_node *np = pdev->dev.of_node;
+ pr_dbg("fetch cimax usb in dts\n");
+
+ child = of_get_child_by_name(np, "cimax");
+ if (child == NULL) {
+ pr_error("cimax not found in dts\n");
+ return -1;
+ }
+ child = of_get_child_by_name(child, "usb");
+ if (!child) {
+ pr_error("usb not found in cimax");
+ return -1;
+ }
+/*
+dvbci {
+ compatible = "amlogic, dvbci";
+ dev_name = "dvbci";
+ io_type = <2>;//0:iobus,1:usb,2:cimax
+ cimax {
+ io_type = <1> //0:spi 1:usb
+ usb {
+ rst_gpio = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_HIGH>;
+ };
+ };
+
+};
+*/
+ {
+ int ret = 0;
+ int gpio = -1;
+ gpio = of_get_named_gpio_flags(child, "rst-gpios", 0, NULL);
+ if (gpio != -1) {
+ ret = gpio_request(gpio, "cimax");
+ if (ret < 0) {
+ pr_error("rst-gpios request fail.\n");
+ return ret;
+ }
+ usb->rst_io = gpio;
+ cimax_usb_hw_reset(usb, 1);
+ pr_dbg("rst: %d\n", usb->rst_io);
+ } else {
+ pr_error("rst io got fail, %d\n", gpio);
+ }
+ }
+ return 0;
+}
+
+int aml_cimax_usb_init(struct platform_device *pdev, struct aml_cimax *cimax)
+{
+ struct cimax_usb *cimax_usb;
+
+ cimax_usb = kzalloc(sizeof(struct cimax_usb), GFP_KERNEL);
+ if (!cimax_usb)
+ return -ENOMEM;
+
+ cimax_usb->pdev = pdev;
+ cimax_usb->cimax = cimax;
+ cimax_usb_get_config_from_dts(cimax_usb);
+
+ /*init usb_lock*/
+ lock_init(cimax_usb);
+
+ /*init cimax used api.*/
+#define WI(_f)\
+ cimax->ops._f = aml_cimax_usb_##_f
+ WI(read_cis);
+ WI(write_cor);
+ WI(negotiate);
+ WI(read_lpdu);
+ WI(write_lpdu);
+ WI(read_cam_status);
+ WI(cam_reset);
+ WI(slot_reset);
+ WI(slot_shutdown);
+ WI(slot_ts_enable);
+ WI(slot_status);
+ WI(read_reg);
+ WI(write_reg);
+
+ cimax->priv = cimax_usb;
+
+ g_usb = cimax_usb;
+
+ aml_cimax_usb_mod_init();
+
+ cimax_usb_set_cb(cimax_usb_dev_add, cimax_usb_dev_remove);
+
+ return 0;
+}
+EXPORT_SYMBOL(aml_cimax_usb_init);
+
+int aml_cimax_usb_exit(struct aml_cimax *cimax)
+{
+ struct cimax_usb *usb = cimax_to_usb(cimax);
+
+ if (!usb)
+ return -ENODEV;
+
+ aml_cimax_usb_mod_exit();
+
+ cimax_usb_device_close(usb->dev);
+ cimax_usb_setup_poll(usb, STOP_MODE);
+
+ if (usb->rst_io)
+ gpio_free(usb->rst_io);
+
+ kfree(usb->cis);
+
+ kfree(usb);
+ cimax->priv = NULL;
+
+ g_usb = NULL;
+ return 0;
+}
+EXPORT_SYMBOL(aml_cimax_usb_exit);
+
+static int cimax_usb_reset(struct cimax_usb *usb, int reset_val)
+{
+ pr_dbg("reset usb:%p, rst:%d\n", usb, usb ? usb->rst_io : -1);
+ if (!usb)
+ return -ENODEV;
+
+ pr_inf("cimax usb reset\n");
+
+ /*notify unplugged*/
+ aml_cimax_camchanged(usb->cimax, 0, 0);
+ aml_cimax_camchanged(usb->cimax, 1, 0);
+
+ if (usb->dev)
+ cimax_usb_device_close(usb->dev);
+
+ cimax_usb_setup_poll(usb, STOP_MODE);
+
+ usb->cam_inserted[0] = usb->cam_inserted[1] = 0;
+ usb->cam_data_ready[0] = usb->cam_data_ready[1] = 0;
+
+ cimax_usb_hw_reset(usb, reset_val);
+
+ pr_inf("cimax usb reset end\n");
+ return 0;
+}
+
+static ssize_t reset_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ int ret;
+ ret = sprintf(buf, "echo 1 > %s\n", attr->attr.name);
+ return ret;
+}
+
+static ssize_t reset_store(struct class *class,
+ struct class_attribute *attr, const char *buf, size_t size)
+{
+ int ret;
+ int val = 0;
+ if (!g_usb)
+ return size;
+ ret = sscanf(buf, "%i", &val);
+ if (ret == 1)
+ ret = cimax_usb_reset(g_usb, val);
+ return size;
+}
+
+static ssize_t debug_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ int ret = 0;
+ if (!g_usb)
+ return ret;
+
+ ret = sprintf(buf, "poll mode: %d\n", g_usb->poll_mode);
+ ret += sprintf(buf+ret, "status slot[0]=[%d] slot[1]=[%d]\n",
+ g_usb->cam_inserted[0], g_usb->cam_inserted[1]);
+ {
+ int power = 0;
+ int err = cimax_usb_check_poe(g_usb, &power);
+ ret += sprintf(buf+ret, "power slot[0]=[%d] slot[1]=[%d]\n",
+ err ? -1 : power, 0);
+ }
+ ret += sprintf(buf+ret, "data slot[0]=[%d] slot[1]=[%d]\n",
+ g_usb->cam_data_ready[0], g_usb->cam_data_ready[1]);
+ ret += sprintf(buf+ret, "work cnt:%d\n", g_usb->work_cnt);
+ ret += sprintf(buf+ret, "pwr work cnt:%d\n", g_usb->power_work_cnt);
+ return ret;
+}
+
+static int reg_addr;
+static ssize_t addr_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ int ret = 0;
+ ret = sprintf(buf, "addr = 0x%04x\n", reg_addr);
+ return ret;
+}
+
+static ssize_t addr_store(struct class *class,
+ struct class_attribute *attr, const char *buf, size_t size)
+{
+ if (!g_usb)
+ return size;
+ if (sscanf(buf, "%i", ®_addr) != 1)
+ return size;
+ return size;
+}
+
+static ssize_t reg_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ int ret = 0;
+ u8 reg_val = 0;
+ struct aml_cimax *cimax = NULL;
+
+ if (!g_usb)
+ return ret;
+
+ cimax = g_usb->cimax;
+ ret = aml_cimax_usb_read_reg(cimax, reg_addr, ®_val, 1);
+ if (ret)
+ ret = sprintf(buf, "read fail, err=%d\n", ret);
+ else
+ ret = sprintf(buf, "reg[0x%04x] = 0x%02x\n", reg_addr, reg_val);
+ return ret;
+}
+
+static ssize_t reg_store(struct class *class,
+ struct class_attribute *attr, const char *buf, size_t size)
+{
+ int ret = 0;
+ struct aml_cimax *cimax = NULL;
+ int val = 0;
+ u8 reg_val = 0;
+
+ if (!g_usb)
+ return size;
+
+ if (sscanf(buf, "%i", &val) != 1)
+ return size;
+ reg_val = val;
+ cimax = g_usb->cimax;
+ ret = aml_cimax_usb_write_reg(cimax, reg_addr, ®_val, 1);
+ if (ret)
+ return ret;
+ return size;
+}
+
+static int cis_mode; /*0:hex 1:binary*/
+static ssize_t cis_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ int ret = 0;
+
+ if (!g_usb || !g_usb->cis)
+ return ret;
+
+ if (cis_mode == 0) {
+ int i;
+ for (i = 0; i < CIS_MAX; i++) {
+ if (i && !(i & 0xf))
+ ret += sprintf(buf+ret, "\n");
+ ret += sprintf(buf+ret, "%02X ", g_usb->cis[i]);
+ }
+ ret += sprintf(buf+ret, "\n");
+ return ret;
+ } else {
+ memcpy(buf, g_usb->cis, CIS_MAX);
+ return CIS_MAX;
+ }
+ return ret;
+}
+
+static ssize_t cis_store(struct class *class,
+ struct class_attribute *attr, const char *buf, size_t size)
+{
+ if (size >= 3
+ && !memcmp(buf, "bin", 3))
+ cis_mode = 1;
+ else
+ cis_mode = 0;
+ return size;
+}
+
+static ssize_t ts_rate_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ int ret = 0;
+ u8 lsb = 0, msb = 0, plen = 0;
+ struct aml_cimax *cimax = NULL;
+ int err = 0;
+
+ if (!g_usb)
+ return ret;
+
+ cimax = g_usb->cimax;
+ err = aml_cimax_usb_read_reg(cimax, PCK_LENGTH, &plen, 1);
+ err |= aml_cimax_usb_read_reg(cimax, BITRATE_CH0_LSB, &lsb, 1);
+ err |= aml_cimax_usb_read_reg(cimax, BITRATE_CH0_MSB, &msb, 1);
+ if (err)
+ ret += sprintf(buf+ret, "read fail, err=%d\n", err);
+ else if (!byte_to_u16(msb, lsb))
+ ret += sprintf(buf+ret, "rate[0] = 0 Kbps\n");
+ else
+ ret += sprintf(buf+ret, "rate[0] = %d Kbps\n",
+ 540*plen*8/byte_to_u16(msb, lsb));
+ if (err)
+ return ret;
+
+ err = aml_cimax_usb_read_reg(cimax, BITRATE_CH1_LSB, &lsb, 1);
+ err |= aml_cimax_usb_read_reg(cimax, BITRATE_CH1_MSB, &msb, 1);
+ if (err)
+ ret += sprintf(buf+ret, "read fail, err=%d\n", err);
+ else if (!byte_to_u16(msb, lsb))
+ ret += sprintf(buf+ret, "rate[1] = 0 Kbps\n");
+ else
+ ret += sprintf(buf+ret, "rate[1] = %d Kbps\n",
+ 540*plen*8/byte_to_u16(msb, lsb));
+ return ret;
+}
+
+static ssize_t loop_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ int ret = 0;
+ u8 ch = 0, mod = 0;
+ struct aml_cimax *cimax = NULL;
+ int err = 0;
+
+ if (!g_usb)
+ return ret;
+
+ cimax = g_usb->cimax;
+ err = aml_cimax_usb_read_reg(cimax, ROUTER_CAM_CH, &ch, 1);
+ err |= aml_cimax_usb_read_reg(cimax, ROUTER_CAM_MOD, &mod, 1);
+ if (err) {
+ ret = sprintf(buf, "read fail, err=%d\n", err);
+ return ret;
+ }
+ ret += sprintf(buf + ret, "OUT-0 <= ");
+ switch (ch & 0x0f) {
+ case 0x0:
+ ret += sprintf(buf + ret, "CAM-A"); break;
+ case 0x1:
+ ret += sprintf(buf + ret, "CH0-IN"); break;
+ case 0x2:
+ ret += sprintf(buf + ret, "CH1-IN"); break;
+ case 0x3:
+ ret += sprintf(buf + ret, "REMAPPER"); break;
+ case 0x4:
+ ret += sprintf(buf + ret, "PREHEADER"); break;
+ case 0x5:
+ ret += sprintf(buf + ret, "CAM-B"); break;
+ case 0x6:
+ ret += sprintf(buf + ret, "GAPREMOVER-0"); break;
+ case 0x7:
+ ret += sprintf(buf + ret, "GAPREMOVER-1"); break;
+ case 0x8:
+ ret += sprintf(buf + ret, "NONE"); break;
+ default:
+ ret += sprintf(buf + ret, "UNKNOWN"); break;
+ }
+ ret += sprintf(buf + ret, "\nCAM-A <= ");
+ switch (mod & 0x07) {
+ case 0x1:
+ ret += sprintf(buf + ret, "CH0-IN"); break;
+ case 0x2:
+ ret += sprintf(buf + ret, "CH1-IN"); break;
+ case 0x3:
+ ret += sprintf(buf + ret, "REMAPPER"); break;
+ case 0x4:
+ ret += sprintf(buf + ret, "PREHEADER"); break;
+ case 0x5:
+ ret += sprintf(buf + ret, "CAM-B"); break;
+ case 0x6:
+ ret += sprintf(buf + ret, "GAPREMOVER-0"); break;
+ case 0x7:
+ ret += sprintf(buf + ret, "GAPREMOVER-1"); break;
+ default:
+ ret += sprintf(buf + ret, "NONE"); break;
+ }
+ ret += sprintf(buf + ret, "\n");
+
+ return ret;
+}
+
+static ssize_t loop_store(struct class *class,
+ struct class_attribute *attr, const char *buf, size_t size)
+{
+ int loop = 0;
+
+ if (!g_usb)
+ return size;
+
+ if (sscanf(buf, "%i", &loop) == 1)
+ cimax_usb_set_loop(g_usb, loop);
+ return size;
+}
+
+static ssize_t slot_reset_store(struct class *class,
+ struct class_attribute *attr, const char *buf, size_t size)
+{
+ int err = 0;
+ int slot = 0;
+ struct aml_cimax *cimax = NULL;
+
+ if (!g_usb)
+ return size;
+
+ if (sscanf(buf, "%i", &slot) == 1) {
+ if (slot == 0 || slot == 1) {
+ pr_dbg("reset slot %d\n", slot);
+ cimax = g_usb->cimax;
+ err = aml_cimax_usb_slot_reset(cimax, slot);
+ }
+ }
+ return size;
+}
+
+static ssize_t detect_store(struct class *class,
+ struct class_attribute *attr, const char *buf, size_t size)
+{
+ int err = 0;
+ int slot = 0;
+ struct aml_cimax *cimax = NULL;
+
+ if (!g_usb)
+ return size;
+
+ if (sscanf(buf, "%i", &slot) == 1) {
+ if (slot == 0 || slot == 1) {
+ int addr = (!slot) ? MOD_CTRL_A : MOD_CTRL_B;
+ u8 reg = 0;
+ cimax = g_usb->cimax;
+ err = aml_cimax_usb_read_reg(cimax, addr, ®, 1);
+ cam_usb_cam_detect(g_usb, slot,
+ (reg & 1) ? IN_INSERTED : 0);
+ cimax_usb_cam_powerctrl(g_usb, slot, (reg & 1));
+ }
+ }
+ return size;
+}
+
+
+static struct class_attribute cimax_usb_class_attrs[] = {
+ __ATTR_RW(reset),
+ __ATTR_RO(debug),
+ __ATTR_RW(addr),
+ __ATTR_RW(reg),
+ __ATTR_RW(cis),
+ __ATTR_RO(ts_rate),
+ __ATTR_RW(loop),
+ __ATTR_WO(slot_reset),
+ __ATTR_WO(detect),
+ __ATTR_NULL
+};
+
+static struct class cimax_usb_class = {
+ .name = "cimax_usb",
+ .class_attrs = cimax_usb_class_attrs,
+};
+
+static int aml_cimax_usb_mod_init(void)
+{
+ int ret;
+ pr_dbg("Amlogic CIMAX USB Init\n");
+ ret = class_register(&cimax_usb_class);
+ return 0;
+}
+
+static void aml_cimax_usb_mod_exit(void)
+{
+ pr_dbg("Amlogic CIMAX USB Exit\n");
+ class_unregister(&cimax_usb_class);
+}
+
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/aml_cimax_usb.h b/drivers/stream_input/parser/dvb_ci/cimax/aml_cimax_usb.h
new file mode 100644
index 0000000..471d2da
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/aml_cimax_usb.h
@@ -0,0 +1,20 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ *
+***************************************************************************/
+
+#ifndef _AML_CIMAX_USB_H_
+#define _AML_CIMAX_USB_H_
+
+#include <linux/platform_device.h>
+#include "aml_cimax.h"
+
+int aml_cimax_usb_init(struct platform_device *pdev, struct aml_cimax *ci);
+int aml_cimax_usb_exit(struct aml_cimax *ci);
+
+#endif
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/aml_cimax_usb_priv.h b/drivers/stream_input/parser/dvb_ci/cimax/aml_cimax_usb_priv.h
new file mode 100644
index 0000000..aec694c
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/aml_cimax_usb_priv.h
@@ -0,0 +1,22 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ *
+***************************************************************************/
+
+#ifndef _CIMAX_USB_DEV_H_
+#define _CIMAX_USB_DEV_H_
+
+#if 0
+__attribute__ ((weak))
+int cimax_usb_dev_add(struct device_s *device, int id);
+__attribute__ ((weak))
+int cimax_usb_dev_remove(struct device_s *device, int id);
+#endif
+
+#endif
+
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/dvb_ca_en50221_cimax.c b/drivers/stream_input/parser/dvb_ci/cimax/dvb_ca_en50221_cimax.c
new file mode 100644
index 0000000..0f09799
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/dvb_ca_en50221_cimax.c
@@ -0,0 +1,1985 @@
+/*
+ * dvb_ca.c: generic DVB functions for EN50221 CAM CIMAX interfaces
+ *
+ * Parts of this file were based on sources as follows:
+ *
+ * based on code:
+ *
+ * Copyright (C) 1999-2002 Ralph Metzler
+ * & Marcus Metzler for convergence integrated media GmbH
+ *
+ * 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/errno.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+
+#include "dvb_ca_en50221_cimax.h"
+#include "dvb_ringbuffer.h"
+
+#define READ_LPDU_PKT
+
+static int dvb_ca_en50221_debug = 1;
+
+module_param_named(cam_debug, dvb_ca_en50221_debug, int, 0644);
+MODULE_PARM_DESC(cam_debug, "enable verbose debug messages");
+
+#define HOST_LINK_BUF_SIZE 0x1000
+
+static int dvb_ca_en50221_link_size = HOST_LINK_BUF_SIZE;
+module_param_named(link_size, dvb_ca_en50221_link_size, int, 0644);
+MODULE_PARM_DESC(link_size, "debug only, no more than 0x1000");
+
+static int dvb_ca_en50221_buffer_free;
+module_param_named(buffer_free, dvb_ca_en50221_buffer_free, int, 0644);
+MODULE_PARM_DESC(buffer_free, "debug only");
+
+#define dprintk(args...)\
+ do {\
+ if (dvb_ca_en50221_debug)\
+ printk(args);\
+ } while (0)
+#define pr_error(fmt, args...) printk("CA EN50211: " fmt, ## args)
+
+#define INIT_TIMEOUT_SECS 40
+
+
+#define RX_BUFFER_SIZE 65535
+
+#define MAX_RX_PACKETS_PER_ITERATION 10
+
+#define CTRLIF_DATA 0
+#define CTRLIF_COMMAND 1
+#define CTRLIF_STATUS 1
+#define CTRLIF_SIZE_LOW 2
+#define CTRLIF_SIZE_HIGH 3
+
+#define CMDREG_HC 1 /* Host control */
+#define CMDREG_SW 2 /* Size write */
+#define CMDREG_SR 4 /* Size read */
+#define CMDREG_RS 8 /* Reset interface */
+#define CMDREG_FRIE 0x40 /* Enable FR interrupt */
+#define CMDREG_DAIE 0x80 /* Enable DA interrupt */
+#define IRQEN (CMDREG_DAIE)
+
+#define STATUSREG_RE 1 /* read error */
+#define STATUSREG_WE 2 /* write error */
+#define STATUSREG_FR 0x40 /* module free */
+#define STATUSREG_DA 0x80 /* data available */
+#define STATUSREG_TXERR (STATUSREG_RE|STATUSREG_WE)/* general transfer error */
+
+
+#define DVB_CA_SLOTSTATE_NONE 0
+#define DVB_CA_SLOTSTATE_UNINITIALISED 1
+#define DVB_CA_SLOTSTATE_RUNNING 2
+#define DVB_CA_SLOTSTATE_INVALID 3
+#define DVB_CA_SLOTSTATE_WAITREADY 4
+#define DVB_CA_SLOTSTATE_VALIDATE 5
+#define DVB_CA_SLOTSTATE_WAITFR 6
+#define DVB_CA_SLOTSTATE_LINKINIT 7
+#define DVB_CA_SLOTSTATE_WAITLINKINIT 8
+
+#define MAX_CIS_SIZE 512
+
+/* Information on a CA slot */
+struct dvb_ca_slot {
+
+ /* current state of the CAM */
+ int slot_state;
+
+ /* mutex used for serializing access to one CI slot */
+ struct mutex slot_lock;
+
+ /* Number of CAMCHANGES that have occurred since last processing */
+ atomic_t camchange_count;
+
+ /* Type of last CAMCHANGE */
+ int camchange_type;
+
+ /* base address of CAM config */
+ u32 config_base;
+
+ /* value to write into Config Control register */
+ u8 config_option;
+
+ /* if 1, the CAM supports DA IRQs */
+ u8 da_irq_supported:1;
+
+#ifdef READ_LPDU_PKT
+ /* Offset into current ringbuffer when user buffer was not big enough
+ to return entire pkt */
+ int rx_offset;
+#endif
+
+ /* size of the buffer to use when talking to the CAM */
+ int link_buf_size;
+
+ /* buffer for incoming packets */
+ struct dvb_ringbuffer rx_buffer;
+
+ /* timer used during various states of the slot */
+ unsigned long timeout;
+};
+
+/* Private CA-interface information */
+struct dvb_ca_private {
+
+ /* pointer back to the public data structure */
+ struct dvb_ca_en50221_cimax *pub;
+
+ /* the DVB device */
+ struct dvb_device *dvbdev;
+
+ /* Flags describing the interface (DVB_CA_FLAG_*) */
+ u32 flags;
+
+ /* number of slots supported by this CA interface */
+ unsigned int slot_count;
+
+ /* information on each slot */
+ struct dvb_ca_slot *slot_info;
+
+ /* wait queues for read() and write() operations */
+ wait_queue_head_t wait_queue;
+
+ /* PID of the monitoring thread */
+ struct task_struct *thread;
+
+ /* Flag indicating if the CA device is open */
+ unsigned int open:1;
+
+ /* Flag indicating the thread should wake up now */
+ unsigned int wakeup:1;
+
+ /* Delay the main thread should use */
+ unsigned long delay;
+
+ /* Slot to start looking for data
+ to read from in the next user-space read operation */
+ int next_read_slot;
+
+ /* mutex serializing ioctls */
+ struct mutex ioctl_mutex;
+
+ /*two bufs for read/write*/
+ u8 *rbuf;
+ u8 *wbuf;
+};
+
+static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca);
+static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca,
+ int slot, u8 *ebuf, int ecount);
+static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca,
+ int slot, u8 *ebuf, int ecount);
+
+
+/**
+ * Safely find needle in haystack.
+ *
+ * @param haystack Buffer to look in.
+ * @param hlen Number of bytes in haystack.
+ * @param needle Buffer to find.
+ * @param nlen Number of bytes in needle.
+ * @return Pointer into haystack needle was found at, or NULL if not found.
+ */
+static char *findstr(char *haystack, int hlen, char *needle, int nlen)
+{
+ int i;
+
+ if (hlen < nlen)
+ return NULL;
+
+ for (i = 0; i <= hlen - nlen; i++) {
+ if (!strncmp(haystack + i, needle, nlen))
+ return haystack + i;
+ }
+
+ return NULL;
+}
+
+
+
+/* ************************************************************************** */
+/* EN50221 physical interface functions */
+
+
+/**
+ * Check CAM status.
+ */
+static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot)
+{
+ int slot_status;
+ int cam_present;
+ int cam_changed;
+
+ /* IRQ mode */
+ if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)
+ return atomic_read(&ca->slot_info[slot].camchange_count) != 0;
+
+ /* poll mode */
+ slot_status = ca->pub->poll_slot_status(ca->pub, slot, ca->open);
+
+ cam_present = (slot_status & DVB_CA_EN50221_POLL_CAM_PRESENT) ? 1 : 0;
+ cam_changed = (slot_status & DVB_CA_EN50221_POLL_CAM_CHANGED) ? 1 : 0;
+ if (!cam_changed) {
+ int cam_present_old =
+ (ca->slot_info[slot].slot_state
+ != DVB_CA_SLOTSTATE_NONE);
+ cam_changed = (cam_present != cam_present_old);
+ }
+
+ if (cam_changed) {
+ if (!cam_present) {
+ ca->slot_info[slot].camchange_type =
+ DVB_CA_EN50221_CAMCHANGE_REMOVED;
+ } else {
+ ca->slot_info[slot].camchange_type =
+ DVB_CA_EN50221_CAMCHANGE_INSERTED;
+ }
+ atomic_set(&ca->slot_info[slot].camchange_count, 1);
+ } else {
+ if ((ca->slot_info[slot].slot_state
+ == DVB_CA_SLOTSTATE_WAITREADY) &&
+ (slot_status & DVB_CA_EN50221_POLL_CAM_READY)) {
+ /* move to validate state if reset is completed */
+ ca->slot_info[slot].slot_state =
+ DVB_CA_SLOTSTATE_VALIDATE;
+ }
+ }
+ return cam_changed;
+}
+
+
+/**
+ * Initialise the link layer connection to a CAM.
+ *
+ * @param ca CA instance.
+ * @param slot Slot id.
+ *
+ * @return 0 on success, nonzero on failure.
+ */
+static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot)
+{
+ int ret;
+ dprintk("%s\n", __func__);
+
+ /* we'll be determining these during this function */
+ ca->slot_info[slot].da_irq_supported = 0;
+#ifdef READ_LPDU_PKT
+ ca->slot_info[slot].rx_offset = 0;
+#endif
+ /* set the host link buffer size temporarily.
+ it will be overwritten with the real negotiated size later. */
+ ca->slot_info[slot].link_buf_size = dvb_ca_en50221_link_size;
+ dprintk("negotiate: host(%i)\n", ca->slot_info[slot].link_buf_size);
+
+ ret = ca->pub->negotiate(ca->pub,
+ slot, ca->slot_info[slot].link_buf_size);
+ if (ret <= 0)
+ return ret;
+
+ ca->slot_info[slot].link_buf_size = ret;
+ dprintk("Chosen link buffer size of %i\n", ret);
+
+ /* success */
+ return 0;
+}
+
+/**
+ * Read a tuple from attribute memory.
+ *
+ * @param ca CA instance.
+ * @param slot Slot id.
+ * @param cis CIS data
+ * @param address Address to read from. Updated.
+ * @param tupleType Tuple id byte. Updated.
+ * @param tupleLength Tuple length. Updated.
+ * @param tuple Dest buffer for tuple (must be 256 bytes). Updated.
+ *
+ * @return 0 on success, nonzero on error.
+ */
+static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca,
+ int slot, u8 *cis,
+ int *address, int *tupleType, int *tupleLength, u8 *tuple)
+{
+ int i;
+ int _tupleType;
+ int _tupleLength;
+ int _address = *address;
+
+ /* grab the next tuple length and type */
+ _tupleType = cis[_address];
+ if (_tupleType < 0)
+ return _tupleType;
+ if (_tupleType == 0xff) {
+ dprintk("END OF CHAIN TUPLE type:0x%x\n", _tupleType);
+ *address += 1;
+ *tupleType = _tupleType;
+ *tupleLength = 0;
+ return 0;
+ }
+ _tupleLength = cis[_address + 1];
+ if (_tupleLength < 0)
+ return _tupleLength;
+ _address += 2;
+
+ dprintk("TUPLE type:0x%x length:%i\n", _tupleType, _tupleLength);
+
+ /* read in the whole tuple */
+ for (i = 0; i < _tupleLength; i++) {
+ tuple[i] = cis[_address + (i)];
+ dprintk(" 0x%02x: 0x%02x %c\n",
+ i, tuple[i] & 0xff,
+ ((tuple[i] > 31) && (tuple[i] < 127)) ? tuple[i] : '.');
+ }
+ _address += (_tupleLength);
+
+ /* success */
+ *tupleType = _tupleType;
+ *tupleLength = _tupleLength;
+ *address = _address;
+ return 0;
+}
+
+
+/**
+ * Parse attribute memory of a CAM module, extracting Config register,
+ * and checking it is a DVB CAM module.
+ *
+ * @param ca CA instance.
+ * @param slot Slot id.
+ *
+ * @return 0 on success, <0 on failure.
+ */
+static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot)
+{
+ int address = 0;
+ int tupleLength;
+ int tupleType;
+ u8 tuple[257];
+ char *dvb_str;
+ int rasz;
+ int status;
+ int got_cftableentry = 0;
+ int end_chain = 0;
+ int i;
+ u16 manfid = 0;
+ u16 devid = 0;
+ u8 cis[MAX_CIS_SIZE];
+
+ status = ca->pub->read_cis(ca->pub, slot, cis, MAX_CIS_SIZE);
+ if (status != 0)
+ return -EINVAL;
+
+ /* CISTPL_DEVICE_0A */
+ status =
+ dvb_ca_en50221_read_tuple(ca, slot, cis, &address,
+ &tupleType, &tupleLength, tuple);
+ if (status < 0) {
+ pr_error("read status error\r\n");
+ return status;
+ }
+ if (tupleType != 0x1D) {
+ pr_error("read tupleType error [0x%x]\r\n", tupleType);
+ return -EINVAL;
+ }
+
+
+
+ /* CISTPL_DEVICE_0C */
+ status = dvb_ca_en50221_read_tuple(ca, slot, cis, &address,
+ &tupleType, &tupleLength, tuple);
+
+ if (status < 0) {
+ pr_error("read read cis error\r\n");
+ return -EINVAL;
+ }
+ if (tupleType != 0x1C) {
+ pr_error("read read cis type error\r\n");
+ return -EINVAL;
+ }
+
+
+
+ /* CISTPL_VERS_1 */
+ status =
+ dvb_ca_en50221_read_tuple(ca, slot, cis,
+ &address, &tupleType, &tupleLength, tuple);
+ if (status < 0) {
+ pr_error("read read cis version error\r\n");
+ return status;
+ }
+ if (tupleType != 0x15) {
+ pr_error("read read cis version type error\r\n");
+ return -EINVAL;
+ }
+
+
+
+ /* CISTPL_MANFID */
+ status = dvb_ca_en50221_read_tuple(ca, slot, cis, &address, &tupleType,
+ &tupleLength, tuple);
+ if (status < 0) {
+ pr_error("read read cis manfid error\r\n");
+ return status;
+ }
+ if (tupleType != 0x20) {
+ pr_error("read read cis manfid type error\r\n");
+ return -EINVAL;
+ }
+ if (tupleLength != 4) {
+ pr_error("read read cis manfid len error\r\n");
+ return -EINVAL;
+ }
+ manfid = (tuple[1] << 8) | tuple[0];
+ devid = (tuple[3] << 8) | tuple[2];
+
+
+
+ /* CISTPL_CONFIG */
+ status = dvb_ca_en50221_read_tuple(ca, slot, cis, &address, &tupleType,
+ &tupleLength, tuple);
+ if (status < 0) {
+ pr_error("read read cis config error\r\n");
+ return status;
+ }
+ if (tupleType != 0x1A) {
+ pr_error("read read cis config type error\r\n");
+ return -EINVAL;
+ }
+ if (tupleLength < 3) {
+ pr_error("read read cis config len error\r\n");
+ return -EINVAL;
+ }
+
+ /* extract the configbase */
+ rasz = tuple[0] & 3;
+ if (tupleLength < (3 + rasz + 14)) {
+ pr_error("read extract the configbase error\r\n");
+ return -EINVAL;
+ }
+ ca->slot_info[slot].config_base = 0;
+ for (i = 0; i < rasz + 1; i++)
+ ca->slot_info[slot].config_base |= (tuple[2 + i] << (8 * i));
+
+ /* check it contains the correct DVB string */
+ dvb_str = findstr((char *)tuple, tupleLength, "DVB_CI_V", 8);
+ if (dvb_str == NULL) {
+ pr_error("find dvb str DVB_CI_V error\r\n");
+ return -EINVAL;
+ }
+ if (tupleLength < ((dvb_str - (char *) tuple) + 12)) {
+ pr_error("find dvb str DVB_CI_V len error\r\n");
+ return -EINVAL;
+ }
+
+ /* is it a version we support? */
+ if (strncmp(dvb_str + 8, "1.00", 4)) {
+ pr_info("dvb_ca adapter %d: ", ca->dvbdev->adapter->num);
+ pr_info("Unsupported DVB CAM module version %c%c%c%c\n",
+ dvb_str[8], dvb_str[9], dvb_str[10], dvb_str[11]);
+ return -EINVAL;
+ }
+
+ /* process the CFTABLE_ENTRY tuples, and any after those */
+ while ((!end_chain) && (address < 0x1000)) {
+ status = dvb_ca_en50221_read_tuple(ca, slot, cis, &address,
+ &tupleType, &tupleLength, tuple);
+ if (status < 0) {
+ pr_error("process tuples error\r\n");
+ return status;
+ }
+
+ switch (tupleType) {
+ case 0x1B: /* CISTPL_CFTABLE_ENTRY */
+ if (tupleLength < (2 + 11 + 17))
+ break;
+
+ /* if we've already parsed one, just use it */
+ if (got_cftableentry)
+ break;
+
+ /* get the config option */
+ ca->slot_info[slot].config_option = tuple[0] & 0x3f;
+
+ /* OK, check it contains the correct strings */
+ if ((findstr((char *)tuple, tupleLength, "DVB_HOST", 8)
+ == NULL)
+ || (findstr((char *)tuple,
+ tupleLength, "DVB_CI_MODULE", 13)
+ == NULL)) {
+ break;
+ }
+ got_cftableentry = 1;
+ break;
+
+ case 0x14: /* CISTPL_NO_LINK */
+ break;
+
+ case 0xFF: /* CISTPL_END */
+ end_chain = 1;
+ break;
+
+ default: /* Unknown tuple type
+ -just skip this tuple and move to the next one */
+ dprintk("dvb_ca: Skipping unknown tuple type:0x%x",
+ tupleType);
+ dprintk(" length:0x%x\n", tupleLength);
+ break;
+ }
+ }
+
+ if ((address > 0x1000) || (!got_cftableentry)) {
+ pr_error("got_cftableentry :%d\r\n", got_cftableentry);
+ return -EINVAL;
+ }
+
+ dprintk("Valid DVB CAM detected MANID:%x DEVID:%x", manfid, devid);
+ dprintk(" CONFIGBASE:0x%x CONFIGOPTION:0x%x\n",
+ ca->slot_info[slot].config_base,
+ ca->slot_info[slot].config_option);
+
+ /* success! */
+ return 0;
+}
+
+
+/**
+ * Set CAM's configoption correctly.
+ *
+ * @param ca CA instance.
+ * @param slot Slot containing the CAM.
+ */
+static int dvb_ca_en50221_set_configoption(struct dvb_ca_private *ca, int slot)
+{
+ int configoption;
+
+ dprintk("%s\n", __func__);
+
+ /* set the config option */
+ ca->pub->write_cor(ca->pub, slot,
+ ca->slot_info[slot].config_base,
+ &ca->slot_info[slot].config_option);
+
+ configoption = ca->slot_info[slot].config_option;
+ dprintk("Set configoption 0x%x, base 0x%x\n",
+ ca->slot_info[slot].config_option,
+ ca->slot_info[slot].config_base);
+
+ /* fine! */
+ return 0;
+
+}
+
+
+/**
+ * This function talks to an EN50221 CAM control interface. It reads a buffer of
+ * data from the CAM. The data can either be stored in a supplied buffer, or
+ * automatically be added to the slot's rx_buffer.
+ *
+ * @param ca CA instance.
+ * @param slot Slot to read from.
+ * @param ebuf If non-NULL, the data will be written to this buffer. If NULL,
+ * the data will be added into the buffering system as a normal fragment.
+ * @param ecount Size of ebuf. Ignored if ebuf is NULL.
+ *
+ * @return Number of bytes read, or < 0 on error
+ */
+static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca,
+ int slot, u8 *ebuf, int ecount)
+{
+ int bytes_read;
+ int status;
+ u8 *buf = ca->rbuf;
+
+ /* dprintk("%s\n", __func__); */
+
+ /* check if we have space for a link buf in the rx_buffer */
+ if (ebuf == NULL) {
+ int buf_free;
+
+ if (ca->slot_info[slot].rx_buffer.data == NULL) {
+ status = -EIO;
+ goto exit;
+ }
+ buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer);
+ dvb_ca_en50221_buffer_free = buf_free;
+
+ if (buf_free < (ca->slot_info[slot].link_buf_size
+ + DVB_RINGBUFFER_PKTHDRSIZE)) {
+ status = -EAGAIN;
+ goto exit;
+ }
+ }
+
+ /* check if there is data available */
+ status = ca->pub->read_cam_status(ca->pub, slot);
+ if (status < 0)
+ goto exit;
+ if (!(status & STATUSREG_DA)) {
+ /* no data */
+ status = 0;
+ goto exit;
+ }
+
+ /* read the amount of data */
+ status = ca->pub->read_lpdu(ca->pub,
+ slot, buf, dvb_ca_en50221_link_size);
+ if (status < 0) {
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+ status = -EIO;
+ goto exit;
+ }
+
+ bytes_read = status;
+
+ /* check it will fit */
+ if (ebuf == NULL) {
+ if (bytes_read > ca->slot_info[slot].link_buf_size) {
+ pr_error("dvb_ca adapter %d:",
+ ca->dvbdev->adapter->num);
+ pr_error(" CAM tried to send a buffer larger ");
+ pr_error("than the link buffer size(%i > %i)!\n",
+ bytes_read, ca->slot_info[slot].link_buf_size);
+ ca->slot_info[slot].slot_state =
+ DVB_CA_SLOTSTATE_LINKINIT;
+ status = -EIO;
+ goto exit;
+ }
+ if (bytes_read < 2) {
+ pr_error("dvb_ca adapter %d: ",
+ ca->dvbdev->adapter->num);
+ pr_error("CAM sent a buffer");
+ pr_error("that was less than 2B!\n");
+ ca->slot_info[slot].slot_state =
+ DVB_CA_SLOTSTATE_LINKINIT;
+ status = -EIO;
+ goto exit;
+ }
+ } else {
+ if (bytes_read > ecount) {
+ pr_error("dvb_ca adapter %d:",
+ ca->dvbdev->adapter->num);
+ pr_error(" CAM tried to send a buffer larger");
+ pr_error(" than the ecount size!\n");
+ status = -EIO;
+ goto exit;
+ }
+ }
+
+ /* OK, add it to the receive buffer,
+ or copy into external buffer if supplied */
+ if (ebuf == NULL) {
+ if (ca->slot_info[slot].rx_buffer.data == NULL) {
+ status = -EIO;
+ goto exit;
+ }
+ dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer,
+ buf, bytes_read);
+ } else {
+ memcpy(ebuf, buf, bytes_read);
+ }
+
+#ifndef READ_LPDU_PKT
+ /* wake up readers when a last_fragment is received */
+ if ((buf[1] & 0x80) == 0x00)
+#endif
+ wake_up_interruptible(&ca->wait_queue);
+ status = bytes_read;
+
+exit:
+ return status;
+}
+
+
+/**
+ * This function talks to an EN50221 CAM control interface.
+ * It writes a buffer of data
+ * to a CAM.
+ *
+ * @param ca CA instance.
+ * @param slot Slot to write to.
+ * @param ebuf The data in this buffer
+ * is treated as a complete link-level packet to be written.
+ * @param count Size of ebuf.
+ *
+ * @return Number of bytes written, or < 0 on error.
+ */
+static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca,
+ int slot, u8 *buf, int bytes_write)
+{
+ int status;
+
+ /* dprintk("%s\n", __func__); */
+
+ /* sanity check */
+ if (bytes_write > ca->slot_info[slot].link_buf_size)
+ return -EINVAL;
+
+ /* it is possible we are dealing with a single buffer implementation,
+ thus if there is data available for read or if there is even a read
+ already in progress, we do nothing but awake the kernel thread to
+ process the data if necessary. */
+ status = ca->pub->read_cam_status(ca->pub, slot);
+ if (status < 0)
+ return status;
+ if (status & (STATUSREG_DA | STATUSREG_RE)) {
+ if (status & STATUSREG_DA)
+ dvb_ca_en50221_thread_wakeup(ca);
+ status = -EAGAIN;
+ return status;
+ }
+
+ if (!(status & STATUSREG_FR)) {
+ status = -EAGAIN;
+ return status;
+ }
+
+ status = ca->pub->write_lpdu(ca->pub, slot, buf, bytes_write);
+ if (status < 0) {
+ if (status == -EBUSY) {
+ status = -EAGAIN;
+ return status;
+ } else {
+ ca->slot_info[slot].slot_state =
+ DVB_CA_SLOTSTATE_LINKINIT;
+ status = -EIO;
+ return status;
+ }
+ }
+
+ status = bytes_write;
+
+ return status;
+}
+EXPORT_SYMBOL(dvb_ca_en50221_cimax_camchange_irq);
+
+
+
+/* ************************************************************************** */
+/* EN50221 higher level functions */
+
+
+/**
+ * A CAM has been removed => shut it down.
+ *
+ * @param ca CA instance.
+ * @param slot Slot to shut down.
+ */
+static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot)
+{
+ dprintk("%s\n", __func__);
+
+ ca->pub->slot_shutdown(ca->pub, slot);
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+
+ /* need to wake up all processes to check if they're now
+ trying to write to a defunct CAM */
+ wake_up_interruptible(&ca->wait_queue);
+
+ dprintk("Slot %i shutdown\n", slot);
+
+ /* success */
+ return 0;
+}
+EXPORT_SYMBOL(dvb_ca_en50221_cimax_camready_irq);
+
+
+/**
+ * A CAMCHANGE IRQ has occurred.
+ *
+ * @param ca CA instance.
+ * @param slot Slot concerned.
+ * @param change_type One of the DVB_CA_CAMCHANGE_* values.
+ */
+void dvb_ca_en50221_cimax_camchange_irq(struct dvb_ca_en50221_cimax *pubca,
+ int slot, int change_type)
+{
+ struct dvb_ca_private *ca = pubca->private;
+
+ dprintk("CAMCHANGE IRQ slot:%i change_type:%i\n", slot, change_type);
+
+ switch (change_type) {
+ case DVB_CA_EN50221_CAMCHANGE_REMOVED:
+ case DVB_CA_EN50221_CAMCHANGE_INSERTED:
+ break;
+
+ default:
+ return;
+ }
+
+ ca->slot_info[slot].camchange_type = change_type;
+ atomic_inc(&ca->slot_info[slot].camchange_count);
+ dvb_ca_en50221_thread_wakeup(ca);
+}
+EXPORT_SYMBOL(dvb_ca_en50221_cimax_frda_irq);
+
+
+/**
+ * A CAMREADY IRQ has occurred.
+ *
+ * @param ca CA instance.
+ * @param slot Slot concerned.
+ */
+void dvb_ca_en50221_cimax_camready_irq(struct dvb_ca_en50221_cimax *pubca,
+ int slot)
+{
+ struct dvb_ca_private *ca = pubca->private;
+
+ dprintk("CAMREADY IRQ slot:%i\n", slot);
+
+ if (ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) {
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE;
+ dvb_ca_en50221_thread_wakeup(ca);
+ }
+}
+
+
+/**
+ * An FR or DA IRQ has occurred.
+ *
+ * @param ca CA instance.
+ * @param slot Slot concerned.
+ */
+void dvb_ca_en50221_cimax_frda_irq(struct dvb_ca_en50221_cimax *pubca,
+ int slot)
+{
+ struct dvb_ca_private *ca = pubca->private;
+ int flags;
+
+ dprintk("FR/DA IRQ slot:%i\n", slot);
+
+ switch (ca->slot_info[slot].slot_state) {
+ case DVB_CA_SLOTSTATE_LINKINIT:
+ flags = ca->pub->get_capbility(pubca, slot);
+ if (flags & DVB_CA_EN50221_CAP_IRQ) {
+ dprintk("CAM supports DA IRQ\n");
+ ca->slot_info[slot].da_irq_supported = 1;
+ }
+ break;
+
+ case DVB_CA_SLOTSTATE_RUNNING:
+ if (ca->open)
+ dvb_ca_en50221_thread_wakeup(ca);
+ break;
+ }
+}
+
+
+
+/* ************************************************************************** */
+/* EN50221 thread functions */
+
+/**
+ * Wake up the DVB CA thread
+ *
+ * @param ca CA instance.
+ */
+static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca)
+{
+
+ dprintk("%s\n", __func__);
+
+ ca->wakeup = 1;
+ mb(); /*original*/
+ wake_up_process(ca->thread);
+}
+
+/**
+ * Update the delay used by the thread.
+ *
+ * @param ca CA instance.
+ */
+static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca)
+{
+ int delay;
+ int curdelay = 100000000;
+ int slot;
+
+ /* Beware of too high polling frequency, because one polling
+ * call might take several hundred milliseconds until timeout!
+ */
+ for (slot = 0; slot < ca->slot_count; slot++) {
+ switch (ca->slot_info[slot].slot_state) {
+ default:
+ case DVB_CA_SLOTSTATE_NONE:
+ delay = HZ * 60; /* 60s */
+ if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+ delay = HZ * 5; /* 5s */
+ break;
+ case DVB_CA_SLOTSTATE_INVALID:
+ delay = HZ * 60; /* 60s */
+ if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+ delay = HZ / 10; /* 100ms */
+ break;
+
+ case DVB_CA_SLOTSTATE_UNINITIALISED:
+ case DVB_CA_SLOTSTATE_WAITREADY:
+ case DVB_CA_SLOTSTATE_VALIDATE:
+ case DVB_CA_SLOTSTATE_WAITFR:
+ case DVB_CA_SLOTSTATE_LINKINIT:
+ delay = HZ / 10; /* 100ms */
+ break;
+ case DVB_CA_SLOTSTATE_WAITLINKINIT:
+ delay = HZ * 2;
+ break;
+
+ case DVB_CA_SLOTSTATE_RUNNING:
+ delay = HZ * 60; /* 60s */
+ if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+ delay = HZ / 10; /* 100ms */
+ if (ca->open) {
+ if ((!ca->slot_info[slot].da_irq_supported) ||
+ (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA)))
+ delay = HZ / 10; /* 100ms */
+ }
+ break;
+ }
+
+ if (delay < curdelay)
+ curdelay = delay;
+ }
+
+ ca->delay = curdelay;
+}
+
+static int dvb_ca_en50221_slot_process(struct dvb_ca_private *ca, int slot)
+{
+ int flags;
+ int status;
+ int pktcount;
+ void *rxbuf;
+
+ mutex_lock(&ca->slot_info[slot].slot_lock);
+
+ /*check the cam status + deal with CAMCHANGEs*/
+ while (dvb_ca_en50221_check_camstatus(ca, slot)) {
+ /* clear down an old CI slot if necessary */
+ if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE)
+ dvb_ca_en50221_slot_shutdown(ca, slot);
+
+ /* if a CAM is NOW present, initialise it */
+ if (ca->slot_info[slot].camchange_type
+ == DVB_CA_EN50221_CAMCHANGE_INSERTED)
+ ca->slot_info[slot].slot_state =
+ DVB_CA_SLOTSTATE_UNINITIALISED;
+
+ /* we've handled one CAMCHANGE */
+ dvb_ca_en50221_thread_update_delay(ca);
+ atomic_dec(&ca->slot_info[slot].camchange_count);
+ }
+
+ /* CAM state machine */
+ switch (ca->slot_info[slot].slot_state) {
+ case DVB_CA_SLOTSTATE_NONE:
+ case DVB_CA_SLOTSTATE_INVALID:
+ /* no action needed */
+ break;
+
+ case DVB_CA_SLOTSTATE_UNINITIALISED:
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITREADY;
+ ca->pub->slot_reset(ca->pub, slot);
+ ca->slot_info[slot].timeout = jiffies
+ + (INIT_TIMEOUT_SECS * HZ);
+ break;
+
+ case DVB_CA_SLOTSTATE_WAITREADY:
+ if (time_after(jiffies, ca->slot_info[slot].timeout)) {
+ dprintk("%d: PC card did not respond\n",
+ ca->dvbdev->adapter->num);
+ ca->slot_info[slot].slot_state =
+ DVB_CA_SLOTSTATE_INVALID;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+ /* no other action needed; will automatically
+ * change state when ready
+ */
+ break;
+
+ case DVB_CA_SLOTSTATE_VALIDATE:
+ if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) {
+ /* we need this extra check
+ for annoying interfaces like the budget-av */
+ if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+ && (ca->pub->poll_slot_status)) {
+ status = ca->pub->poll_slot_status(ca->pub,
+ slot, 0);
+ if (!(status
+ & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
+ ca->slot_info[slot].slot_state =
+ DVB_CA_SLOTSTATE_NONE;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+ }
+ dprintk(" %d: Invalid PC card inserted :(\n",
+ ca->dvbdev->adapter->num);
+ ca->slot_info[slot].slot_state =
+ DVB_CA_SLOTSTATE_INVALID;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+ if (dvb_ca_en50221_set_configoption(ca, slot) != 0) {
+ dprintk("%d: Unable initialise CAM:(\n",
+ ca->dvbdev->adapter->num);
+ ca->slot_info[slot].slot_state =
+ DVB_CA_SLOTSTATE_INVALID;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+
+ if (ca->pub->cam_reset(ca->pub, slot) != 0) {
+ dprintk("%d: Unable to reset CAM IF\n",
+ ca->dvbdev->adapter->num);
+ ca->slot_info[slot].slot_state =
+ DVB_CA_SLOTSTATE_INVALID;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+
+ dprintk("DVB CAM validated successfully\n");
+
+ ca->slot_info[slot].timeout =
+ jiffies + (INIT_TIMEOUT_SECS * HZ);
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITFR;
+ ca->wakeup = 1;
+ break;
+
+ case DVB_CA_SLOTSTATE_WAITFR:
+ if (time_after(jiffies, ca->slot_info[slot].timeout)) {
+ pr_error("dvb_ca adapter %d: ",
+ ca->dvbdev->adapter->num);
+ pr_error("DVB CAM did not respond :(\n");
+ ca->slot_info[slot].slot_state =
+ DVB_CA_SLOTSTATE_INVALID;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+
+ /*flags = ca->pub->read_cam_status(ca->pub, slot);*/
+ flags = STATUSREG_FR;
+ if (flags & STATUSREG_FR) {
+ ca->slot_info[slot].slot_state =
+ DVB_CA_SLOTSTATE_LINKINIT;
+ ca->wakeup = 1;
+ }
+ break;
+
+ case DVB_CA_SLOTSTATE_WAITLINKINIT:
+ if (time_after(jiffies, ca->slot_info[slot].timeout)) {
+ pr_error("dvb_ca adapter %d: ",
+ ca->dvbdev->adapter->num);
+ pr_error("DVB CAM link initialisation failed :(\n");
+ ca->slot_info[slot].slot_state =
+ DVB_CA_SLOTSTATE_INVALID;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+
+ case DVB_CA_SLOTSTATE_LINKINIT:
+ if (dvb_ca_en50221_link_init(ca, slot) != 0) {
+ /* we need this extra check for annoying interfaces
+ like the budget-av */
+ if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+ && (ca->pub->poll_slot_status)) {
+ status = ca->pub->poll_slot_status(ca->pub,
+ slot, 0);
+ if (!(status
+ & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
+ ca->slot_info[slot].slot_state =
+ DVB_CA_SLOTSTATE_NONE;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+ }
+
+ ca->slot_info[slot].timeout =
+ jiffies + (INIT_TIMEOUT_SECS * HZ);
+ ca->slot_info[slot].slot_state =
+ DVB_CA_SLOTSTATE_WAITLINKINIT;
+ ca->wakeup = 1;
+ break;
+ }
+
+ if (ca->slot_info[slot].rx_buffer.data == NULL) {
+ rxbuf = vmalloc(RX_BUFFER_SIZE);
+ if (rxbuf == NULL) {
+ pr_error("dvb_ca adapter %d: ",
+ ca->dvbdev->adapter->num);
+ pr_error("Unable to allocate CAM rx buffer\n");
+ ca->slot_info[slot].slot_state =
+ DVB_CA_SLOTSTATE_INVALID;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+ dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer,
+ rxbuf, RX_BUFFER_SIZE);
+ }
+
+ ca->pub->slot_ts_enable(ca->pub, slot);
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING;
+ dvb_ca_en50221_thread_update_delay(ca);
+ dprintk("%d: DVB CAM Initialised successfully\n",
+ ca->dvbdev->adapter->num);
+ break;
+
+ case DVB_CA_SLOTSTATE_RUNNING:
+ if (!ca->open)
+ break;
+
+ pktcount = 0;
+ while ((status = dvb_ca_en50221_read_data(ca, slot, NULL, 0))
+ > 0) {
+ if (!ca->open)
+ break;
+
+ /* if a CAMCHANGE occurred at some point,
+ do not do any more processing of this slot */
+ if (dvb_ca_en50221_check_camstatus(ca, slot)) {
+ /* we dont want to sleep on the next iteration
+ so we can handle the cam change*/
+ ca->wakeup = 1;
+ break;
+ }
+
+ /* check if we've hit our limit this time */
+ if (++pktcount >= MAX_RX_PACKETS_PER_ITERATION) {
+ /*dont sleep;
+ there is likely to be more data to read*/
+ ca->wakeup = 1;
+ break;
+ }
+ }
+ break;
+ }
+
+ mutex_unlock(&ca->slot_info[slot].slot_lock);
+ return 0;
+}
+
+
+/**
+ * Kernel thread which monitors CA slots for CAM changes,
+ * and performs data transfers.
+ */
+static int dvb_ca_en50221_thread(void *data)
+{
+ struct dvb_ca_private *ca = data;
+ int slot;
+
+ dprintk(" %s\n", __func__);
+ /* choose the correct initial delay */
+ dvb_ca_en50221_thread_update_delay(ca);
+
+ /* main loop */
+ while (!kthread_should_stop()) {
+ /* sleep for a bit */
+ if (!ca->wakeup) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(ca->delay);
+ if (kthread_should_stop())
+ return 0;
+ }
+ ca->wakeup = 0;
+
+ /* go through all the slots processing them */
+ for (slot = 0; slot < ca->slot_count; slot++)
+ dvb_ca_en50221_slot_process(ca, slot);
+ }
+
+ return 0;
+}
+
+
+
+/* ************************************************************************** */
+/* EN50221 IO interface functions */
+
+/**
+ * Real ioctl implementation.
+ * NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them.
+ *
+ * @param inode Inode concerned.
+ * @param file File concerned.
+ * @param cmd IOCTL command.
+ * @param arg Associated argument.
+ *
+ * @return 0 on success, <0 on error.
+ */
+static int dvb_ca_en50221_io_do_ioctl(struct file *file,
+ unsigned int cmd, void *parg)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dvb_ca_private *ca = dvbdev->priv;
+ int err = 0;
+ int slot;
+
+ if (mutex_lock_interruptible(&ca->ioctl_mutex)) {
+ pr_error("ci lock interrupt error\r\n");
+ return -ERESTARTSYS;
+ }
+
+ switch (cmd) {
+ case CA_RESET:
+ dprintk("ci reset---\r\n");
+ for (slot = 0; slot < ca->slot_count; slot++) {
+ mutex_lock(&ca->slot_info[slot].slot_lock);
+ if (ca->slot_info[slot].slot_state
+ == DVB_CA_SLOTSTATE_NONE)
+ goto next;
+ dvb_ca_en50221_slot_shutdown(ca, slot);
+ if (ca->flags
+ & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)
+ dvb_ca_en50221_cimax_camchange_irq(
+ ca->pub,
+ slot,
+ DVB_CA_EN50221_CAMCHANGE_INSERTED);
+next:
+ mutex_unlock(&ca->slot_info[slot].slot_lock);
+ }
+ ca->next_read_slot = 0;
+ dvb_ca_en50221_thread_wakeup(ca);
+ break;
+
+ case CA_GET_CAP: {
+ struct ca_caps *caps = parg;
+
+ caps->slot_num = ca->slot_count;
+ caps->slot_type = CA_CI_LINK;
+ caps->descr_num = 0;
+ caps->descr_type = 0;
+ break;
+ }
+
+ case CA_GET_SLOT_INFO: {
+ struct ca_slot_info *info = parg;
+
+ if ((info->num > ca->slot_count) || (info->num < 0)) {
+ err = -EINVAL;
+ pr_error("info num error :%d\r\n", info->num);
+ goto out_unlock;
+ }
+
+ info->type = CA_CI_LINK;
+ info->flags = 0;
+ if ((ca->slot_info[info->num].slot_state
+ != DVB_CA_SLOTSTATE_NONE)
+ && (ca->slot_info[info->num].slot_state
+ != DVB_CA_SLOTSTATE_INVALID)) {
+ info->flags = CA_CI_MODULE_PRESENT;
+ }
+ if (ca->slot_info[info->num].slot_state
+ == DVB_CA_SLOTSTATE_RUNNING) {
+ info->flags |= CA_CI_MODULE_READY;
+ }
+ break;
+ }
+
+ default:
+ pr_error("Invalid cmd :%d\r\n", cmd);
+ err = -EINVAL;
+ break;
+ }
+
+out_unlock:
+ mutex_unlock(&ca->ioctl_mutex);
+ return err;
+}
+
+
+static int dvb_usercopy__(struct file *file,
+ unsigned int cmd, unsigned long arg,
+ int (*func)(struct file *file,
+ unsigned int cmd, void *arg))
+{
+ char sbuf[128];
+ void *mbuf = NULL;
+ void *parg = NULL;
+ int err = -EINVAL;
+
+ /* Copy arguments into temp kernel buffer */
+ switch (_IOC_DIR(cmd)) {
+ case _IOC_NONE:
+ /*
+ * For this command, the pointer is actually an integer
+ * argument.
+ */
+ parg = (void *) arg;
+ break;
+ case _IOC_READ: /* some v4l ioctls are marked wrong ... */
+ case _IOC_WRITE:
+ case (_IOC_WRITE | _IOC_READ):
+ if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+ parg = sbuf;
+ } else {
+ /* too big to allocate from stack */
+ mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
+ if (NULL == mbuf)
+ return -ENOMEM;
+ parg = mbuf;
+ }
+
+ err = -EFAULT;
+ if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
+ goto out;
+ break;
+ }
+
+ /* call driver */
+ if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD)
+ err = -ENOTTY;
+
+ if (err < 0)
+ goto out;
+
+ /* Copy results into user buffer */
+ switch (_IOC_DIR(cmd))
+ {
+ case _IOC_READ:
+ case (_IOC_WRITE | _IOC_READ):
+ if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
+ err = -EFAULT;
+ break;
+ }
+
+out:
+ kfree(mbuf);
+ return err;
+}
+
+
+
+/**
+ * Wrapper for ioctl implementation.
+ *
+ * @param inode Inode concerned.
+ * @param file File concerned.
+ * @param cmd IOCTL command.
+ * @param arg Associated argument.
+ *
+ * @return 0 on success, <0 on error.
+ */
+static long dvb_ca_en50221_io_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return dvb_usercopy__(file, cmd, arg, dvb_ca_en50221_io_do_ioctl);
+}
+
+
+/**
+ * Implementation of write() syscall.
+ *
+ * @param file File structure.
+ * @param buf Source buffer.
+ * @param count Size of source buffer.
+ * @param ppos Position in file (ignored).
+ *
+ * @return Number of bytes read, or <0 on error.
+ */
+static ssize_t dvb_ca_en50221_io_write(struct file *file,
+ const char __user *buf, size_t count, loff_t *ppos)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dvb_ca_private *ca = dvbdev->priv;
+ u8 slot, connection_id;
+ int status;
+ u8 *fragbuf = ca->wbuf;
+ int fragpos = 0;
+ int fraglen;
+ unsigned long timeout;
+ int written;
+
+ /* dprintk("%s\n", __func__); */
+
+ /* Incoming packet has a 2 byte header.
+ hdr[0] = slot_id, hdr[1] = connection_id */
+ if (count < 2)
+ return -EINVAL;
+
+ /* extract slot & connection id */
+ if (copy_from_user(&slot, buf, 1))
+ return -EFAULT;
+ if (copy_from_user(&connection_id, buf + 1, 1))
+ return -EFAULT;
+ buf += 2;
+ count -= 2;
+
+ if (slot >= ca->slot_count)
+ return -EFAULT;
+ /* check if the slot is actually running */
+ if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING)
+ return -EINVAL;
+
+ /* fragment the packets & store in the buffer */
+ while (fragpos < count) {
+ fraglen = ca->slot_info[slot].link_buf_size - 2;
+ if (fraglen < 0)
+ break;
+ if (fraglen > dvb_ca_en50221_link_size - 2)
+ fraglen = dvb_ca_en50221_link_size - 2;
+ if ((count - fragpos) < fraglen)
+ fraglen = count - fragpos;
+
+ fragbuf[0] = connection_id;
+ fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00;
+ status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen);
+ if (status) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ timeout = jiffies + HZ / 2;
+ written = 0;
+ while (!time_after(jiffies, timeout)) {
+ /* check the CAM hasn't been removed/reset
+ in the meantime */
+ if (ca->slot_info[slot].slot_state
+ != DVB_CA_SLOTSTATE_RUNNING) {
+ status = -EIO;
+ goto exit;
+ }
+
+ mutex_lock(&ca->slot_info[slot].slot_lock);
+ status = dvb_ca_en50221_write_data(ca,
+ slot, fragbuf, fraglen + 2);
+ mutex_unlock(&ca->slot_info[slot].slot_lock);
+ if (status == (fraglen + 2)) {
+ written = 1;
+ break;
+ }
+ if (status != -EAGAIN)
+ goto exit;
+
+ msleep(20);
+ }
+ if (!written) {
+ status = -EIO;
+ goto exit;
+ }
+
+ fragpos += fraglen;
+ }
+ status = count + 2;
+
+exit:
+ return status;
+}
+
+
+/**
+ * Condition for waking up in dvb_ca_en50221_io_read_condition
+ */
+static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca,
+ int *result, int *_slot)
+{
+ int slot;
+ int slot_count = 0;
+ int idx;
+ size_t fraglen;
+ int connection_id = -1;
+ int found = 0;
+ u8 hdr[2];
+
+ slot = ca->next_read_slot;
+ while ((slot_count < ca->slot_count) && (!found)) {
+ if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING)
+ goto nextslot;
+
+ if (ca->slot_info[slot].rx_buffer.data == NULL)
+ return 0;
+#ifdef READ_LPDU_PKT
+ if (ca->slot_info[slot].rx_offset != 0) {
+ *_slot = slot;
+ return 1;
+ }
+#endif
+ idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer,
+ -1, &fraglen);
+ while (idx != -1) {
+ dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer,
+ idx, 0, hdr, 2);
+ if (connection_id == -1)
+ connection_id = hdr[0];
+ if ((hdr[0] == connection_id)
+#ifndef READ_LPDU_PKT
+ && ((hdr[1] & 0x80) == 0)
+#endif
+ ) {
+ *_slot = slot;
+ found = 1;
+ break;
+ }
+
+ idx = dvb_ringbuffer_pkt_next(
+ &ca->slot_info[slot].rx_buffer,
+ idx,
+ &fraglen);
+ }
+
+nextslot:
+ slot = (slot + 1) % ca->slot_count;
+ slot_count++;
+ }
+
+ ca->next_read_slot = slot;
+ return found;
+}
+
+
+/**
+ * Implementation of read() syscall.
+ *
+ * @param file File structure.
+ * @param buf Destination buffer.
+ * @param count Size of destination buffer.
+ * @param ppos Position in file (ignored).
+ *
+ * @return Number of bytes read, or <0 on error.
+ */
+static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dvb_ca_private *ca = dvbdev->priv;
+ int status;
+ int result = 0;
+ u8 hdr[2];
+ int slot;
+ int connection_id = -1;
+ size_t idx, idx2;
+ int last_fragment = 0;
+ size_t fraglen;
+ int pktlen;
+ int dispose = 0;
+
+#ifdef READ_LPDU_PKT
+ int offset;
+ u8 flag = 0;
+#endif
+
+ /* dprintk("%s\n", __func__); */
+
+ /* Outgoing packet has a 2 byte header.
+ hdr[0] = slot_id, hdr[1] = connection_id */
+ if (count < 2)
+ return -EINVAL;
+
+ /* wait for some data */
+ status = dvb_ca_en50221_io_read_condition(ca, &result, &slot);
+ if (status == 0) {
+ /* if we're in nonblocking mode, exit immediately */
+ if (file->f_flags & O_NONBLOCK)
+ return -EWOULDBLOCK;
+
+ /* wait for some data */
+ status = wait_event_interruptible(ca->wait_queue,
+ dvb_ca_en50221_io_read_condition
+ (ca, &result, &slot));
+ }
+ if ((status < 0) || (result < 0)) {
+ if (result)
+ return result;
+ return status;
+ }
+
+ idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer,
+ -1, &fraglen);
+ pktlen = 2;
+ do {
+ if (idx == -1) {
+ pr_error("dvb_ca adapter %d: ",
+ ca->dvbdev->adapter->num);
+ pr_error("BUG: read packet ended");
+ pr_error("before last_fragment encountered\n");
+ status = -EIO;
+ goto exit;
+ }
+#ifdef READ_LPDU_PKT
+ offset = 2 + ca->slot_info[slot].rx_offset;
+#endif
+ dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer,
+ idx, 0, hdr, 2);
+ if (connection_id == -1)
+ connection_id = hdr[0];
+#ifdef READ_LPDU_PKT
+ flag = hdr[1];
+ if (hdr[0] == connection_id) {
+ if (pktlen < count) {
+ if ((pktlen + fraglen - offset) > (count - 2)) {
+ fraglen = (count - 2) - pktlen;
+ ca->slot_info[slot].rx_offset +=
+ fraglen;
+ /* more data for user,
+ but cannot send,
+ so force return to user,
+ rather than dispose of it */
+ flag |= 0x80;
+ } else {
+ ca->slot_info[slot].rx_offset = 0;
+ fraglen -= offset;
+ dispose = 1;
+ }
+
+ status = dvb_ringbuffer_pkt_read_user(
+ &ca->slot_info[slot].rx_buffer,
+ idx,
+ offset,
+ buf + pktlen + 2,
+ fraglen);
+ if (status < 0)
+ goto exit;
+ pktlen += fraglen;
+ }
+
+ last_fragment = 1;
+ }
+#else
+ if (hdr[0] == connection_id) {
+ if (pktlen < count) {
+ if ((pktlen + fraglen - 2) > count)
+ fraglen = count - pktlen;
+ else
+ fraglen -= 2;
+
+ status = dvb_ringbuffer_pkt_read_user(
+ &ca->slot_info[slot].rx_buffer,
+ idx,
+ 2,
+ buf + pktlen,
+ fraglen);
+ if (status < 0)
+ goto exit;
+ pktlen += fraglen;
+ }
+
+ if ((hdr[1] & 0x80) == 0)
+ last_fragment = 1;
+ dispose = 1;
+ }
+#endif
+ idx2 = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer,
+ idx, &fraglen);
+ if (dispose)
+ dvb_ringbuffer_pkt_dispose(
+ &ca->slot_info[slot].rx_buffer, idx);
+ idx = idx2;
+ dispose = 0;
+ } while (!last_fragment);
+
+ hdr[0] = slot;
+ hdr[1] = connection_id;
+ status = copy_to_user(buf, hdr, 2);
+ if (status) {
+ status = -EFAULT;
+ goto exit;
+ }
+ status = pktlen;
+
+#ifdef READ_LPDU_PKT
+ hdr[0] = flag;
+ hdr[1] = 0;
+
+ status = copy_to_user(buf + 2, hdr, 2);
+ if (status) {
+ status = -EFAULT;
+ goto exit;
+ }
+ status = pktlen + 2;
+#endif
+exit:
+ return status;
+}
+
+
+/**
+ * Implementation of file open syscall.
+ *
+ * @param inode Inode concerned.
+ * @param file File concerned.
+ *
+ * @return 0 on success, <0 on failure.
+ */
+static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dvb_ca_private *ca = dvbdev->priv;
+ int err;
+ int i;
+
+ dprintk("%s\n", __func__);
+
+ if (!try_module_get(ca->pub->owner))
+ return -EIO;
+
+ err = dvb_generic_open(inode, file);
+ if (err < 0) {
+ module_put(ca->pub->owner);
+ return err;
+ }
+
+ for (i = 0; i < ca->slot_count; i++) {
+
+ if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) {
+ if (ca->slot_info[i].rx_buffer.data != NULL) {
+ /* it is safe to call this here without locks
+ because ca->open == 0.
+ Data is not read in this case */
+ dvb_ringbuffer_flush(
+ &ca->slot_info[i].rx_buffer);
+ }
+ }
+ }
+
+ ca->open = 1;
+ dvb_ca_en50221_thread_update_delay(ca);
+ dvb_ca_en50221_thread_wakeup(ca);
+
+ return 0;
+}
+
+
+/**
+ * Implementation of file close syscall.
+ *
+ * @param inode Inode concerned.
+ * @param file File concerned.
+ *
+ * @return 0 on success, <0 on failure.
+ */
+static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dvb_ca_private *ca = dvbdev->priv;
+ int err;
+
+ dprintk("%s\n", __func__);
+
+ /* mark the CA device as closed */
+ ca->open = 0;
+ dvb_ca_en50221_thread_update_delay(ca);
+
+ err = dvb_generic_release(inode, file);
+
+ module_put(ca->pub->owner);
+
+ return err;
+}
+
+
+/**
+ * Implementation of poll() syscall.
+ *
+ * @param file File concerned.
+ * @param wait poll wait table.
+ *
+ * @return Standard poll mask.
+ */
+static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table *wait)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dvb_ca_private *ca = dvbdev->priv;
+ unsigned int mask = 0;
+ int slot;
+ int result = 0;
+
+ /* dprintk("%s\n", __func__); */
+
+ if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1)
+ mask |= POLLIN;
+
+ /* if there is something, return now */
+ if (mask)
+ return mask;
+
+ /* wait for something to happen */
+ poll_wait(file, &ca->wait_queue, wait);
+
+ if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1)
+ mask |= POLLIN;
+
+ return mask;
+}
+EXPORT_SYMBOL(dvb_ca_en50221_cimax_init);
+
+#ifdef CONFIG_COMPAT
+static long dvb_ca_en50221_compat_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long args)
+{
+ unsigned long ret;
+
+ args = (unsigned long)compat_ptr(args);
+ ret = dvb_ca_en50221_io_ioctl(filp, cmd, args);
+ return ret;
+}
+#endif
+static const struct file_operations dvb_ca_fops = {
+ .owner = THIS_MODULE,
+ .read = dvb_ca_en50221_io_read,
+ .write = dvb_ca_en50221_io_write,
+ .unlocked_ioctl = dvb_ca_en50221_io_ioctl,
+ .open = dvb_ca_en50221_io_open,
+ .release = dvb_ca_en50221_io_release,
+ .poll = dvb_ca_en50221_io_poll,
+ .llseek = noop_llseek,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = dvb_ca_en50221_compat_ioctl,
+#endif
+};
+
+static struct dvb_device dvbdev_ca = {
+ .priv = NULL,
+ .users = 1,
+ .readers = 1,
+ .writers = 1,
+ .fops = &dvb_ca_fops,
+};
+
+
+/* ************************************************************************** */
+/* Initialisation/shutdown functions */
+
+
+/**
+ * Initialise a new DVB CA EN50221 CIMAX interface device.
+ *
+ * @param dvb_adapter DVB adapter to attach the new CA device to.
+ * @param ca The dvb_ca instance.
+ * @param flags Flags describing the CA device (DVB_CA_FLAG_*).
+ * @param slot_count Number of slots supported.
+ *
+ * @return 0 on success, nonzero on failure
+ */
+int dvb_ca_en50221_cimax_init(struct dvb_adapter *dvb_adapter,
+ struct dvb_ca_en50221_cimax *pubca,
+ int flags, int slot_count)
+{
+ int ret;
+ struct dvb_ca_private *ca = NULL;
+ int i;
+
+ dprintk("%s\n", __func__);
+
+ if (slot_count < 1)
+ return -EINVAL;
+
+ /* initialise the system data */
+ ca = kzalloc(sizeof(struct dvb_ca_private), GFP_KERNEL);
+ if (ca == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ ca->pub = pubca;
+ ca->flags = flags;
+ ca->slot_count = slot_count;
+ ca->slot_info =
+ kcalloc(slot_count, sizeof(struct dvb_ca_slot), GFP_KERNEL);
+ if (ca->slot_info == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ init_waitqueue_head(&ca->wait_queue);
+ ca->open = 0;
+ ca->wakeup = 0;
+ ca->next_read_slot = 0;
+ ca->rbuf = kcalloc(HOST_LINK_BUF_SIZE, 1, GFP_KERNEL);
+ ca->wbuf = kcalloc(HOST_LINK_BUF_SIZE, 1, GFP_KERNEL);
+ if (ca->rbuf == NULL || ca->wbuf == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ pubca->private = ca;
+
+ /* register the DVB device */
+ ret = dvb_register_device(dvb_adapter,
+ &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA, 0);
+ if (ret)
+ goto error;
+
+ /* now initialise each slot */
+ for (i = 0; i < slot_count; i++) {
+ memset(&ca->slot_info[i], 0, sizeof(struct dvb_ca_slot));
+ ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE;
+ atomic_set(&ca->slot_info[i].camchange_count, 0);
+ ca->slot_info[i].camchange_type =
+ DVB_CA_EN50221_CAMCHANGE_REMOVED;
+ mutex_init(&ca->slot_info[i].slot_lock);
+ }
+
+ mutex_init(&ca->ioctl_mutex);
+
+ if (signal_pending(current)) {
+ ret = -EINTR;
+ goto error;
+ }
+ mb();/*original*/
+
+ /* create a kthread for monitoring this CA device */
+ ca->thread = kthread_run(dvb_ca_en50221_thread, ca, "kdvb-ca-%i:%i",
+ ca->dvbdev->adapter->num, ca->dvbdev->id);
+ if (IS_ERR(ca->thread)) {
+ ret = PTR_ERR(ca->thread);
+ printk("dvb_ca_init: failed to start kernel_thread (%d)\n",
+ ret);
+ goto error;
+ }
+ return 0;
+
+error:
+ if (ca != NULL) {
+ if (ca->dvbdev != NULL)
+ dvb_unregister_device(ca->dvbdev);
+ kfree(ca->slot_info);
+ kfree(ca->rbuf);
+ kfree(ca->wbuf);
+ kfree(ca);
+ }
+ pubca->private = NULL;
+ return ret;
+}
+EXPORT_SYMBOL(dvb_ca_en50221_cimax_release);
+
+
+
+/**
+ * Release a DVB CA EN50221 CIMAX interface device.
+ *
+ * @param ca_dev The dvb_struct device_s instance for the CA device.
+ * @param ca The associated dvb_ca instance.
+ */
+void dvb_ca_en50221_cimax_release(struct dvb_ca_en50221_cimax *pubca)
+{
+ struct dvb_ca_private *ca = pubca->private;
+ int i;
+
+ dprintk("%s\n", __func__);
+
+ /* shutdown the thread if there was one */
+ kthread_stop(ca->thread);
+
+ for (i = 0; i < ca->slot_count; i++) {
+ dvb_ca_en50221_slot_shutdown(ca, i);
+ vfree(ca->slot_info[i].rx_buffer.data);
+ }
+ kfree(ca->slot_info);
+ kfree(ca->rbuf);
+ kfree(ca->wbuf);
+ dvb_unregister_device(ca->dvbdev);
+ kfree(ca);
+ pubca->private = NULL;
+}
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/dvb_ca_en50221_cimax.h b/drivers/stream_input/parser/dvb_ci/cimax/dvb_ca_en50221_cimax.h
new file mode 100644
index 0000000..e2ebde6
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/dvb_ca_en50221_cimax.h
@@ -0,0 +1,144 @@
+/*
+ * dvb_ca_cimax.h: generic DVB functions for EN50221 CA CIMAX interfaces
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 _DVB_CA_EN50221_CIMAX_H_
+#define _DVB_CA_EN50221_CIMAX_H_
+
+#include <linux/list.h>
+#include <linux/dvb/ca.h>
+
+#include "dvbdev.h"
+
+#define DVB_CA_EN50221_POLL_CAM_PRESENT 1
+#define DVB_CA_EN50221_POLL_CAM_CHANGED 2
+#define DVB_CA_EN50221_POLL_CAM_READY 4
+
+#define DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE 1
+#define DVB_CA_EN50221_FLAG_IRQ_FR 2
+#define DVB_CA_EN50221_FLAG_IRQ_DA 4
+
+#define DVB_CA_EN50221_CAMCHANGE_REMOVED 0
+#define DVB_CA_EN50221_CAMCHANGE_INSERTED 1
+
+#define DVB_CA_EN50221_CAP_IRQ 1
+
+/* Structure describing a CA interface */
+struct dvb_ca_en50221_cimax {
+
+ /* the module owning this structure */
+ struct module *owner;
+
+ /* NOTE: the read_*, write_* and poll_slot_status functions will be
+ * called for different slots concurrently and need to use locks where
+ * and if appropriate. There will be no concurrent access to one slot.
+ */
+
+ /* functions for accessing attribute memory on the CAM */
+ int (*read_cis)(struct dvb_ca_en50221_cimax *ca,
+ int slot, u8 *buf, int size);
+ int (*write_cor)(struct dvb_ca_en50221_cimax *ca,
+ int slot, int address, u8 *buf);
+ /*return the final size or -1 for error*/
+ int (*negotiate)(struct dvb_ca_en50221_cimax *ca, int slot, int size);
+
+ /* functions for accessing the control interface on the CAM */
+ int (*read_lpdu)(struct dvb_ca_en50221_cimax *ca,
+ int slot, u8 *buf, int size);
+ int (*write_lpdu)(struct dvb_ca_en50221_cimax *ca,
+ int slot, u8 *buf, int size);
+
+ int (*cam_reset)(struct dvb_ca_en50221_cimax *ca, int slot);
+ int (*read_cam_status)(struct dvb_ca_en50221_cimax *ca, int slot);
+ int (*get_capbility)(struct dvb_ca_en50221_cimax *ca, int slot);
+
+ /* Functions for controlling slots */
+ int (*slot_reset)(struct dvb_ca_en50221_cimax *ca, int slot);
+ int (*slot_shutdown)(struct dvb_ca_en50221_cimax *ca, int slot);
+ int (*slot_ts_enable)(struct dvb_ca_en50221_cimax *ca, int slot);
+
+ /*
+ * Poll slot status.
+ * Only necessary if DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE is not set
+ */
+ int (*poll_slot_status)(struct dvb_ca_en50221_cimax *ca,
+ int slot, int open);
+
+ /* private data, used by caller */
+ void *data;
+
+ /* Opaque data used by the dvb_ca core. Do not modify! */
+ void *private;
+};
+
+
+
+
+/* ************************************************************************* */
+/* Functions for reporting IRQ events */
+
+/**
+ * A CAMCHANGE IRQ has occurred.
+ *
+ * @param ca CA instance.
+ * @param slot Slot concerned.
+ * @param change_type One of the DVB_CA_CAMCHANGE_* values
+ */
+void dvb_ca_en50221_cimax_camchange_irq(struct dvb_ca_en50221_cimax *pubca,
+ int slot, int change_type);
+
+/**
+ * A CAMREADY IRQ has occurred.
+ *
+ * @param ca CA instance.
+ * @param slot Slot concerned.
+ */
+void dvb_ca_en50221_cimax_camready_irq(struct dvb_ca_en50221_cimax *pubca,
+ int slot);
+
+/**
+ * An FR or a DA IRQ has occurred.
+ *
+ * @param ca CA instance.
+ * @param slot Slot concerned.
+ */
+void dvb_ca_en50221_cimax_frda_irq(struct dvb_ca_en50221_cimax *ca, int slot);
+
+
+
+/* ************************************************************************** */
+/* Initialisation/shutdown functions */
+
+/**
+ * Initialise a new DVB CA device.
+ *
+ * @param dvb_adapter DVB adapter to attach the new CA device to.
+ * @param ca The dvb_ca instance.
+ * @param flags Flags describing the CA device (DVB_CA_EN50221_FLAG_*).
+ * @param slot_count Number of slots supported.
+ *
+ * @return 0 on success, nonzero on failure
+ */
+extern int dvb_ca_en50221_cimax_init(struct dvb_adapter *dvb_adapter,
+ struct dvb_ca_en50221_cimax *ca, int flags, int slot_count);
+
+/**
+ * Release a DVB CA device.
+ *
+ * @param ca The associated dvb_ca instance.
+ */
+extern void dvb_ca_en50221_cimax_release(struct dvb_ca_en50221_cimax *ca);
+
+
+
+#endif
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/dvb_ringbuffer.c b/drivers/stream_input/parser/dvb_ci/cimax/dvb_ringbuffer.c
new file mode 100644
index 0000000..fa5c163
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/dvb_ringbuffer.c
@@ -0,0 +1,381 @@
+/*
+ *
+ * dvb_ringbuffer.c: ring buffer implementation for the dvb driver
+ *
+ * Copyright (C) 2003 Oliver Endriss
+ * Copyright (C) 2004 Andrew de Quincey
+ *
+ * based on code originally found in av7110.c & dvb_ci.c:
+ * Copyright (C) 1999-2003 Ralph Metzler
+ * & Marcus Metzler for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <asm/uaccess.h>
+
+#include "dvb_ringbuffer.h"
+
+#define PKT_READY 0
+#define PKT_DISPOSED 1
+
+
+void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
+{
+ rbuf->pread=rbuf->pwrite=0;
+ rbuf->data=data;
+ rbuf->size=len;
+ rbuf->error=0;
+
+ init_waitqueue_head(&rbuf->queue);
+
+ spin_lock_init(&(rbuf->lock));
+}
+
+
+
+int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf)
+{
+ /* smp_load_acquire() to load write pointer on reader side
+ * this pairs with smp_store_release() in dvb_ringbuffer_write(),
+ * dvb_ringbuffer_write_user(), or dvb_ringbuffer_reset()
+ *
+ * for memory barriers also see Documentation/circular-buffers.txt
+ */
+ return (rbuf->pread == smp_load_acquire(&rbuf->pwrite));
+}
+
+
+
+ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf)
+{
+ ssize_t free;
+
+ /* ACCESS_ONCE() to load read pointer on writer side
+ * this pairs with smp_store_release() in dvb_ringbuffer_read(),
+ * dvb_ringbuffer_read_user(), dvb_ringbuffer_flush(),
+ * or dvb_ringbuffer_reset()
+ */
+ free = ACCESS_ONCE(rbuf->pread) - rbuf->pwrite;
+ if (free <= 0)
+ free += rbuf->size;
+ return free-1;
+}
+
+
+
+ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf)
+{
+ ssize_t avail;
+
+ /* smp_load_acquire() to load write pointer on reader side
+ * this pairs with smp_store_release() in dvb_ringbuffer_write(),
+ * dvb_ringbuffer_write_user(), or dvb_ringbuffer_reset()
+ */
+ avail = smp_load_acquire(&rbuf->pwrite) - rbuf->pread;
+ if (avail < 0)
+ avail += rbuf->size;
+ return avail;
+}
+
+
+
+void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf)
+{
+ /* dvb_ringbuffer_flush() counts as read operation
+ * smp_load_acquire() to load write pointer
+ * smp_store_release() to update read pointer, this ensures that the
+ * correct pointer is visible for subsequent dvb_ringbuffer_free()
+ * calls on other cpu cores
+ */
+ smp_store_release(&rbuf->pread, smp_load_acquire(&rbuf->pwrite));
+ rbuf->error = 0;
+}
+//EXPORT_SYMBOL(dvb_ringbuffer_flush);
+
+void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf)
+{
+ /* dvb_ringbuffer_reset() counts as read and write operation
+ * smp_store_release() to update read pointer
+ */
+ smp_store_release(&rbuf->pread, 0);
+ /* smp_store_release() to update write pointer */
+ smp_store_release(&rbuf->pwrite, 0);
+ rbuf->error = 0;
+}
+
+void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&rbuf->lock, flags);
+ dvb_ringbuffer_flush(rbuf);
+ spin_unlock_irqrestore(&rbuf->lock, flags);
+
+ wake_up(&rbuf->queue);
+}
+
+ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, size_t len)
+{
+ size_t todo = len;
+ size_t split;
+
+ split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
+ if (split > 0) {
+ if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
+ return -EFAULT;
+ buf += split;
+ todo -= split;
+ /* smp_store_release() for read pointer update to ensure
+ * that buf is not overwritten until read is complete,
+ * this pairs with ACCESS_ONCE() in dvb_ringbuffer_free()
+ */
+ smp_store_release(&rbuf->pread, 0);
+ }
+ if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
+ return -EFAULT;
+
+ /* smp_store_release() to update read pointer, see above */
+ smp_store_release(&rbuf->pread, (rbuf->pread + todo) % rbuf->size);
+
+ return len;
+}
+
+void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len)
+{
+ size_t todo = len;
+ size_t split;
+
+ split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
+ if (split > 0) {
+ memcpy(buf, rbuf->data+rbuf->pread, split);
+ buf += split;
+ todo -= split;
+ /* smp_store_release() for read pointer update to ensure
+ * that buf is not overwritten until read is complete,
+ * this pairs with ACCESS_ONCE() in dvb_ringbuffer_free()
+ */
+ smp_store_release(&rbuf->pread, 0);
+ }
+ memcpy(buf, rbuf->data+rbuf->pread, todo);
+
+ /* smp_store_release() to update read pointer, see above */
+ smp_store_release(&rbuf->pread, (rbuf->pread + todo) % rbuf->size);
+}
+
+
+ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len)
+{
+ size_t todo = len;
+ size_t split;
+
+ split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0;
+
+ if (split > 0) {
+ memcpy(rbuf->data+rbuf->pwrite, buf, split);
+ buf += split;
+ todo -= split;
+ /* smp_store_release() for write pointer update to ensure that
+ * written data is visible on other cpu cores before the pointer
+ * update, this pairs with smp_load_acquire() in
+ * dvb_ringbuffer_empty() or dvb_ringbuffer_avail()
+ */
+ smp_store_release(&rbuf->pwrite, 0);
+ }
+ memcpy(rbuf->data+rbuf->pwrite, buf, todo);
+ /* smp_store_release() for write pointer update, see above */
+ smp_store_release(&rbuf->pwrite, (rbuf->pwrite + todo) % rbuf->size);
+
+ return len;
+}
+
+ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
+ const u8 __user *buf, size_t len)
+{
+ int status;
+ size_t todo = len;
+ size_t split;
+
+ split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0;
+
+ if (split > 0) {
+ status = copy_from_user(rbuf->data+rbuf->pwrite, buf, split);
+ if (status)
+ return len - todo;
+ buf += split;
+ todo -= split;
+ /* smp_store_release() for write pointer update to ensure that
+ * written data is visible on other cpu cores before the pointer
+ * update, this pairs with smp_load_acquire() in
+ * dvb_ringbuffer_empty() or dvb_ringbuffer_avail()
+ */
+ smp_store_release(&rbuf->pwrite, 0);
+ }
+ status = copy_from_user(rbuf->data+rbuf->pwrite, buf, todo);
+ if (status)
+ return len - todo;
+ /* smp_store_release() for write pointer update, see above */
+ smp_store_release(&rbuf->pwrite, (rbuf->pwrite + todo) % rbuf->size);
+
+ return len;
+}
+
+ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len)
+{
+ int status;
+ ssize_t oldpwrite = rbuf->pwrite;
+
+ DVB_RINGBUFFER_WRITE_BYTE(rbuf, len >> 8);
+ DVB_RINGBUFFER_WRITE_BYTE(rbuf, len & 0xff);
+ DVB_RINGBUFFER_WRITE_BYTE(rbuf, PKT_READY);
+ status = dvb_ringbuffer_write(rbuf, buf, len);
+
+ if (status < 0) rbuf->pwrite = oldpwrite;
+ return status;
+}
+
+ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
+ int offset, u8 __user *buf, size_t len)
+{
+ size_t todo;
+ size_t split;
+ size_t pktlen;
+
+ pktlen = rbuf->data[idx] << 8;
+ pktlen |= rbuf->data[(idx + 1) % rbuf->size];
+ if (offset > pktlen) return -EINVAL;
+ if ((offset + len) > pktlen) len = pktlen - offset;
+
+ idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
+ todo = len;
+ split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
+ if (split > 0) {
+ if (copy_to_user(buf, rbuf->data+idx, split))
+ return -EFAULT;
+ buf += split;
+ todo -= split;
+ idx = 0;
+ }
+ if (copy_to_user(buf, rbuf->data+idx, todo))
+ return -EFAULT;
+
+ return len;
+}
+
+ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
+ int offset, u8* buf, size_t len)
+{
+ size_t todo;
+ size_t split;
+ size_t pktlen;
+
+ pktlen = rbuf->data[idx] << 8;
+ pktlen |= rbuf->data[(idx + 1) % rbuf->size];
+ if (offset > pktlen) return -EINVAL;
+ if ((offset + len) > pktlen) len = pktlen - offset;
+
+ idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
+ todo = len;
+ split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
+ if (split > 0) {
+ memcpy(buf, rbuf->data+idx, split);
+ buf += split;
+ todo -= split;
+ idx = 0;
+ }
+ memcpy(buf, rbuf->data+idx, todo);
+ return len;
+}
+
+void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx)
+{
+ size_t pktlen;
+
+ rbuf->data[(idx + 2) % rbuf->size] = PKT_DISPOSED;
+
+ // clean up disposed packets
+ while(dvb_ringbuffer_avail(rbuf) > DVB_RINGBUFFER_PKTHDRSIZE) {
+ if (DVB_RINGBUFFER_PEEK(rbuf, 2) == PKT_DISPOSED) {
+ pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8;
+ pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1);
+ DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE);
+ } else {
+ // first packet is not disposed, so we stop cleaning now
+ break;
+ }
+ }
+}
+
+ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen)
+{
+ int consumed;
+ int curpktlen;
+ int curpktstatus;
+
+ if (idx == -1) {
+ idx = rbuf->pread;
+ } else {
+ curpktlen = rbuf->data[idx] << 8;
+ curpktlen |= rbuf->data[(idx + 1) % rbuf->size];
+ idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
+ }
+
+ consumed = (idx - rbuf->pread) % rbuf->size;
+
+ while((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) {
+
+ curpktlen = rbuf->data[idx] << 8;
+ curpktlen |= rbuf->data[(idx + 1) % rbuf->size];
+ curpktstatus = rbuf->data[(idx + 2) % rbuf->size];
+
+ if (curpktstatus == PKT_READY) {
+ *pktlen = curpktlen;
+ return idx;
+ }
+
+ consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE;
+ idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
+ }
+
+ // no packets available
+ return -1;
+}
+
+
+#if 0
+EXPORT_SYMBOL(dvb_ringbuffer_init);
+EXPORT_SYMBOL(dvb_ringbuffer_empty);
+EXPORT_SYMBOL(dvb_ringbuffer_free);
+EXPORT_SYMBOL(dvb_ringbuffer_avail);
+EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
+EXPORT_SYMBOL(dvb_ringbuffer_read_user);
+EXPORT_SYMBOL(dvb_ringbuffer_read);
+EXPORT_SYMBOL(dvb_ringbuffer_write);
+EXPORT_SYMBOL(dvb_ringbuffer_write_user);
+#endif
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_read);
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_write);
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_next);
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_dispose);
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_read_user);
+
+
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/dvb_ringbuffer.h b/drivers/stream_input/parser/dvb_ci/cimax/dvb_ringbuffer.h
new file mode 100644
index 0000000..bbe9487
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/dvb_ringbuffer.h
@@ -0,0 +1,280 @@
+/*
+ *
+ * dvb_ringbuffer.h: ring buffer implementation for the dvb driver
+ *
+ * Copyright (C) 2003 Oliver Endriss
+ * Copyright (C) 2004 Andrew de Quincey
+ *
+ * based on code originally found in av7110.c & dvb_ci.c:
+ * Copyright (C) 1999-2003 Ralph Metzler & Marcus Metzler
+ * for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser General Public License for more details.
+ */
+
+#ifndef _DVB_RINGBUFFER_H_
+#define _DVB_RINGBUFFER_H_
+
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+
+/**
+ * struct dvb_ringbuffer - Describes a ring buffer used at DVB framework
+ *
+ * @data: Area were the ringbuffer data is written
+ * @size: size of the ringbuffer
+ * @pread: next position to read
+ * @pwrite: next position to write
+ * @error: used by ringbuffer clients to indicate that an error happened.
+ * @queue: Wait queue used by ringbuffer clients to indicate when buffer
+ * was filled
+ * @lock: Spinlock used to protect the ringbuffer
+ */
+struct dvb_ringbuffer {
+ u8 *data;
+ ssize_t size;
+ ssize_t pread;
+ ssize_t pwrite;
+ int error;
+
+ wait_queue_head_t queue;
+ spinlock_t lock;
+};
+
+#define DVB_RINGBUFFER_PKTHDRSIZE 3
+
+/**
+ * dvb_ringbuffer_init - initialize ring buffer, lock and queue
+ *
+ * @rbuf: pointer to struct dvb_ringbuffer
+ * @data: pointer to the buffer where the data will be stored
+ * @len: bytes from ring buffer into @buf
+ */
+extern void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data,
+ size_t len);
+
+/**
+ * dvb_ringbuffer_empty - test whether buffer is empty
+ *
+ * @rbuf: pointer to struct dvb_ringbuffer
+ */
+extern int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf);
+
+/**
+ * dvb_ringbuffer_free - returns the number of free bytes in the buffer
+ *
+ * @rbuf: pointer to struct dvb_ringbuffer
+ *
+ * Return: number of free bytes in the buffer
+ */
+extern ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf);
+
+/**
+ * dvb_ringbuffer_avail - returns the number of bytes waiting in the buffer
+ *
+ * @rbuf: pointer to struct dvb_ringbuffer
+ *
+ * Return: number of bytes waiting in the buffer
+ */
+extern ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf);
+
+/**
+ * dvb_ringbuffer_reset - resets the ringbuffer to initial state
+ *
+ * @rbuf: pointer to struct dvb_ringbuffer
+ *
+ * Resets the read and write pointers to zero and flush the buffer.
+ *
+ * This counts as a read and write operation
+ */
+extern void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf);
+
+/*
+ * read routines & macros
+ */
+
+/**
+ * dvb_ringbuffer_flush - flush buffer
+ *
+ * @rbuf: pointer to struct dvb_ringbuffer
+ */
+extern void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf);
+
+/**
+ * dvb_ringbuffer_flush_spinlock_wakeup- flush buffer protected by spinlock
+ * and wake-up waiting task(s)
+ *
+ * @rbuf: pointer to struct dvb_ringbuffer
+ */
+extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf);
+
+/**
+ * DVB_RINGBUFFER_PEEK - peek at byte @offs in the buffer
+ *
+ * @rbuf: pointer to struct dvb_ringbuffer
+ * @offs: offset inside the ringbuffer
+ */
+#define DVB_RINGBUFFER_PEEK(rbuf, offs) \
+ ((rbuf)->data[((rbuf)->pread + (offs)) % (rbuf)->size])
+
+/**
+ * DVB_RINGBUFFER_SKIP - advance read ptr by @num bytes
+ *
+ * @rbuf: pointer to struct dvb_ringbuffer
+ * @num: number of bytes to advance
+ */
+#define DVB_RINGBUFFER_SKIP(rbuf, num) {\
+ (rbuf)->pread = ((rbuf)->pread + (num)) % (rbuf)->size;\
+}
+
+/**
+ * dvb_ringbuffer_read_user - Reads a buffer into an user pointer
+ *
+ * @rbuf: pointer to struct dvb_ringbuffer
+ * @buf: pointer to the buffer where the data will be stored
+ * @len: bytes from ring buffer into @buf
+ *
+ * This variant assumes that the buffer is a memory at the userspace. So,
+ * it will internally call copy_to_user().
+ *
+ * Return: number of bytes transferred or -EFAULT
+ */
+extern ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf,
+ u8 __user *buf, size_t len);
+
+/**
+ * dvb_ringbuffer_read - Reads a buffer into a pointer
+ *
+ * @rbuf: pointer to struct dvb_ringbuffer
+ * @buf: pointer to the buffer where the data will be stored
+ * @len: bytes from ring buffer into @buf
+ *
+ * This variant assumes that the buffer is a memory at the Kernel space
+ *
+ * Return: number of bytes transferred or -EFAULT
+ */
+extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf,
+ u8 *buf, size_t len);
+
+/*
+ * write routines & macros
+ */
+
+/**
+ * DVB_RINGBUFFER_WRITE_BYTE - write single byte to ring buffer
+ *
+ * @rbuf: pointer to struct dvb_ringbuffer
+ * @byte: byte to write
+ */
+#define DVB_RINGBUFFER_WRITE_BYTE(rbuf, byte) \
+ { (rbuf)->data[(rbuf)->pwrite] = (byte); \
+ (rbuf)->pwrite = ((rbuf)->pwrite + 1) % (rbuf)->size; }
+
+/**
+ * dvb_ringbuffer_write - Writes a buffer into the ringbuffer
+ *
+ * @rbuf: pointer to struct dvb_ringbuffer
+ * @buf: pointer to the buffer where the data will be read
+ * @len: bytes from ring buffer into @buf
+ *
+ * This variant assumes that the buffer is a memory at the Kernel space
+ *
+ * return: number of bytes transferred or -EFAULT
+ */
+extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
+ size_t len);
+
+/**
+ * dvb_ringbuffer_write_user - Writes a buffer received via an user pointer
+ *
+ * @rbuf: pointer to struct dvb_ringbuffer
+ * @buf: pointer to the buffer where the data will be read
+ * @len: bytes from ring buffer into @buf
+ *
+ * This variant assumes that the buffer is a memory at the userspace. So,
+ * it will internally call copy_from_user().
+ *
+ * Return: number of bytes transferred or -EFAULT
+ */
+extern ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
+ const u8 __user *buf, size_t len);
+
+/**
+ * dvb_ringbuffer_pkt_write - Write a packet into the ringbuffer.
+ *
+ * @rbuf: Ringbuffer to write to.
+ * @buf: Buffer to write.
+ * @len: Length of buffer (currently limited to 65535 bytes max).
+ *
+ * Return: Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL.
+ */
+extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8 *buf,
+ size_t len);
+
+/**
+ * dvb_ringbuffer_pkt_read_user - Read from a packet in the ringbuffer.
+ *
+ * @rbuf: Ringbuffer concerned.
+ * @idx: Packet index as returned by dvb_ringbuffer_pkt_next().
+ * @offset: Offset into packet to read from.
+ * @buf: Destination buffer for data.
+ * @len: Size of destination buffer.
+ *
+ * Return: Number of bytes read, or -EFAULT.
+ *
+ * .. note::
+ *
+ * unlike dvb_ringbuffer_read(), this does **NOT** update the read pointer
+ * in the ringbuffer. You must use dvb_ringbuffer_pkt_dispose() to mark a
+ * packet as no longer required.
+ */
+extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf,
+ size_t idx,
+ int offset, u8 __user *buf,
+ size_t len);
+
+/**
+ * dvb_ringbuffer_pkt_read - Read from a packet in the ringbuffer.
+ * Note: unlike dvb_ringbuffer_read_user(), this DOES update the read pointer
+ * in the ringbuffer.
+ *
+ * @rbuf: Ringbuffer concerned.
+ * @idx: Packet index as returned by dvb_ringbuffer_pkt_next().
+ * @offset: Offset into packet to read from.
+ * @buf: Destination buffer for data.
+ * @len: Size of destination buffer.
+ *
+ * Return: Number of bytes read, or -EFAULT.
+ */
+extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
+ int offset, u8 *buf, size_t len);
+
+/**
+ * dvb_ringbuffer_pkt_dispose - Dispose of a packet in the ring buffer.
+ *
+ * @rbuf: Ring buffer concerned.
+ * @idx: Packet index as returned by dvb_ringbuffer_pkt_next().
+ */
+extern void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx);
+
+/**
+ * dvb_ringbuffer_pkt_next - Get the index of the next packet in a ringbuffer.
+ *
+ * @rbuf: Ringbuffer concerned.
+ * @idx: Previous packet index, or -1 to return the first packet index.
+ * @pktlen: On success, will be updated to contain the length of the packet
+ * in bytes.
+ * returns Packet index (if >=0), or -1 if no packets available.
+ */
+extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf,
+ size_t idx, size_t *pktlen);
+
+#endif /* _DVB_RINGBUFFER_H_ */
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/dvbdev.c b/drivers/stream_input/parser/dvb_ci/cimax/dvbdev.c
new file mode 100644
index 0000000..0e9599b
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/dvbdev.c
@@ -0,0 +1,968 @@
+/*
+ * dvbdev.c
+ *
+ * Copyright (C) 2000 Ralph Metzler <ralph@convergence.de>
+ * & Marcus Metzler <marcus@convergence.de>
+ * for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser 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.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/mutex.h>
+#include "dvbdev.h"
+
+/* Due to enum tuner_pad_index */
+#include <media/tuner.h>
+
+static DEFINE_MUTEX(dvbdev_mutex);
+static int dvbdev_debug;
+
+module_param(dvbdev_debug, int, 0644);
+MODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off).");
+
+#define dprintk if (dvbdev_debug) printk
+
+static LIST_HEAD(dvb_adapter_list);
+static DEFINE_MUTEX(dvbdev_register_lock);
+
+static const char * const dnames[] = {
+ "video", "audio", "sec", "frontend", "demux", "dvr", "ca",
+ "net", "osd"
+};
+
+#ifdef CONFIG_DVB_DYNAMIC_MINORS
+#define MAX_DVB_MINORS 256
+#define DVB_MAX_IDS MAX_DVB_MINORS
+#else
+#define DVB_MAX_IDS 4
+#define nums2minor(num, type, id) ((num << 6) | (id << 4) | type)
+#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64)
+#endif
+
+static struct class *dvb_class;
+
+static struct dvb_device *dvb_minors[MAX_DVB_MINORS];
+static DECLARE_RWSEM(minor_rwsem);
+
+static int dvb_device_open(struct inode *inode, struct file *file)
+{
+ struct dvb_device *dvbdev;
+
+ mutex_lock(&dvbdev_mutex);
+ down_read(&minor_rwsem);
+ dvbdev = dvb_minors[iminor(inode)];
+
+ if (dvbdev && dvbdev->fops) {
+ int err = 0;
+ const struct file_operations *new_fops;
+
+ new_fops = fops_get(dvbdev->fops);
+ if (!new_fops)
+ goto fail;
+ file->private_data = dvbdev;
+ replace_fops(file, new_fops);
+ if (file->f_op->open)
+ err = file->f_op->open(inode, file);
+ up_read(&minor_rwsem);
+ mutex_unlock(&dvbdev_mutex);
+ return err;
+ }
+fail:
+ up_read(&minor_rwsem);
+ mutex_unlock(&dvbdev_mutex);
+ return -ENODEV;
+}
+
+
+static const struct file_operations dvb_device_fops =
+{
+ .owner = THIS_MODULE,
+ .open = dvb_device_open,
+ .llseek = noop_llseek,
+};
+
+static struct cdev dvb_device_cdev;
+
+int dvb_generic_open(struct inode *inode, struct file *file)
+{
+ struct dvb_device *dvbdev = file->private_data;
+
+ if (!dvbdev)
+ return -ENODEV;
+
+ if (!dvbdev->users)
+ return -EBUSY;
+
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+ if (!dvbdev->readers)
+ return -EBUSY;
+ dvbdev->readers--;
+ } else {
+ if (!dvbdev->writers)
+ return -EBUSY;
+ dvbdev->writers--;
+ }
+
+ dvbdev->users--;
+ return 0;
+}
+EXPORT_SYMBOL(dvb_generic_open);
+
+
+int dvb_generic_release(struct inode *inode, struct file *file)
+{
+ struct dvb_device *dvbdev = file->private_data;
+
+ if (!dvbdev)
+ return -ENODEV;
+
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+ dvbdev->readers++;
+ } else {
+ dvbdev->writers++;
+ }
+
+ dvbdev->users++;
+ return 0;
+}
+EXPORT_SYMBOL(dvb_generic_release);
+
+
+long dvb_generic_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct dvb_device *dvbdev = file->private_data;
+
+ if (!dvbdev)
+ return -ENODEV;
+
+ if (!dvbdev->kernel_ioctl)
+ return -EINVAL;
+
+ return dvb_usercopy(file, cmd, arg, dvbdev->kernel_ioctl);
+}
+EXPORT_SYMBOL(dvb_generic_ioctl);
+
+
+static int dvbdev_get_free_id (struct dvb_adapter *adap, int type)
+{
+ u32 id = 0;
+
+ while (id < DVB_MAX_IDS) {
+ struct dvb_device *dev;
+ list_for_each_entry(dev, &adap->device_list, list_head)
+ if (dev->type == type && dev->id == id)
+ goto skip;
+ return id;
+skip:
+ id++;
+ }
+ return -ENFILE;
+}
+
+static void dvb_media_device_free(struct dvb_device *dvbdev)
+{
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+ if (dvbdev->entity) {
+ media_device_unregister_entity(dvbdev->entity);
+ kfree(dvbdev->entity);
+ kfree(dvbdev->pads);
+ dvbdev->entity = NULL;
+ dvbdev->pads = NULL;
+ }
+
+ if (dvbdev->tsout_entity) {
+ int i;
+
+ for (i = 0; i < dvbdev->tsout_num_entities; i++) {
+ media_device_unregister_entity(&dvbdev->tsout_entity[i]);
+ kfree(dvbdev->tsout_entity[i].name);
+ }
+ kfree(dvbdev->tsout_entity);
+ kfree(dvbdev->tsout_pads);
+ dvbdev->tsout_entity = NULL;
+ dvbdev->tsout_pads = NULL;
+
+ dvbdev->tsout_num_entities = 0;
+ }
+
+ if (dvbdev->intf_devnode) {
+ media_devnode_remove(dvbdev->intf_devnode);
+ dvbdev->intf_devnode = NULL;
+ }
+
+ if (dvbdev->adapter->conn) {
+ media_device_unregister_entity(dvbdev->adapter->conn);
+ dvbdev->adapter->conn = NULL;
+ kfree(dvbdev->adapter->conn_pads);
+ dvbdev->adapter->conn_pads = NULL;
+ }
+#endif
+}
+
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+static int dvb_create_tsout_entity(struct dvb_device *dvbdev,
+ const char *name, int npads)
+{
+ int i, ret = 0;
+
+ dvbdev->tsout_pads = kcalloc(npads, sizeof(*dvbdev->tsout_pads),
+ GFP_KERNEL);
+ if (!dvbdev->tsout_pads)
+ return -ENOMEM;
+
+ dvbdev->tsout_entity = kcalloc(npads, sizeof(*dvbdev->tsout_entity),
+ GFP_KERNEL);
+ if (!dvbdev->tsout_entity)
+ return -ENOMEM;
+
+ dvbdev->tsout_num_entities = npads;
+
+ for (i = 0; i < npads; i++) {
+ struct media_pad *pads = &dvbdev->tsout_pads[i];
+ struct media_entity *entity = &dvbdev->tsout_entity[i];
+
+ entity->name = kasprintf(GFP_KERNEL, "%s #%d", name, i);
+ if (!entity->name)
+ return -ENOMEM;
+
+ entity->function = MEDIA_ENT_F_IO_DTV;
+ pads->flags = MEDIA_PAD_FL_SINK;
+
+ ret = media_entity_pads_init(entity, 1, pads);
+ if (ret < 0)
+ return ret;
+
+ ret = media_device_register_entity(dvbdev->adapter->mdev,
+ entity);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+#define DEMUX_TSOUT "demux-tsout"
+#define DVR_TSOUT "dvr-tsout"
+
+static int dvb_create_media_entity(struct dvb_device *dvbdev,
+ int type, int demux_sink_pads)
+{
+ int i, ret, npads;
+
+ switch (type) {
+ case DVB_DEVICE_FRONTEND:
+ npads = 2;
+ break;
+ case DVB_DEVICE_DVR:
+ ret = dvb_create_tsout_entity(dvbdev, DVR_TSOUT,
+ demux_sink_pads);
+ return ret;
+ case DVB_DEVICE_DEMUX:
+ npads = 1 + demux_sink_pads;
+ ret = dvb_create_tsout_entity(dvbdev, DEMUX_TSOUT,
+ demux_sink_pads);
+ if (ret < 0)
+ return ret;
+ break;
+ case DVB_DEVICE_CA:
+ npads = 2;
+ break;
+ case DVB_DEVICE_NET:
+ /*
+ * We should be creating entities for the MPE/ULE
+ * decapsulation hardware (or software implementation).
+ *
+ * However, the number of for the MPE/ULE decaps may not be
+ * fixed. As we don't have yet dynamic support for PADs at
+ * the Media Controller, let's not create the decap
+ * entities yet.
+ */
+ return 0;
+ default:
+ return 0;
+ }
+
+ dvbdev->entity = kzalloc(sizeof(*dvbdev->entity), GFP_KERNEL);
+ if (!dvbdev->entity)
+ return -ENOMEM;
+
+ dvbdev->entity->name = dvbdev->name;
+
+ if (npads) {
+ dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads),
+ GFP_KERNEL);
+ if (!dvbdev->pads)
+ return -ENOMEM;
+ }
+
+ switch (type) {
+ case DVB_DEVICE_FRONTEND:
+ dvbdev->entity->function = MEDIA_ENT_F_DTV_DEMOD;
+ dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
+ dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE;
+ break;
+ case DVB_DEVICE_DEMUX:
+ dvbdev->entity->function = MEDIA_ENT_F_TS_DEMUX;
+ dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
+ for (i = 1; i < npads; i++)
+ dvbdev->pads[i].flags = MEDIA_PAD_FL_SOURCE;
+ break;
+ case DVB_DEVICE_CA:
+ dvbdev->entity->function = MEDIA_ENT_F_DTV_CA;
+ dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK;
+ dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE;
+ break;
+ default:
+ /* Should never happen, as the first switch prevents it */
+ kfree(dvbdev->entity);
+ kfree(dvbdev->pads);
+ dvbdev->entity = NULL;
+ dvbdev->pads = NULL;
+ return 0;
+ }
+
+ if (npads) {
+ ret = media_entity_pads_init(dvbdev->entity, npads, dvbdev->pads);
+ if (ret)
+ return ret;
+ }
+ ret = media_device_register_entity(dvbdev->adapter->mdev,
+ dvbdev->entity);
+ if (ret)
+ return ret;
+
+ printk(KERN_DEBUG "%s: media entity '%s' registered.\n",
+ __func__, dvbdev->entity->name);
+
+ return 0;
+}
+#endif
+
+static int dvb_register_media_device(struct dvb_device *dvbdev,
+ int type, int minor,
+ unsigned demux_sink_pads)
+{
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+ struct media_link *link;
+ u32 intf_type;
+ int ret;
+
+ if (!dvbdev->adapter->mdev)
+ return 0;
+
+ ret = dvb_create_media_entity(dvbdev, type, demux_sink_pads);
+ if (ret)
+ return ret;
+
+ switch (type) {
+ case DVB_DEVICE_FRONTEND:
+ intf_type = MEDIA_INTF_T_DVB_FE;
+ break;
+ case DVB_DEVICE_DEMUX:
+ intf_type = MEDIA_INTF_T_DVB_DEMUX;
+ break;
+ case DVB_DEVICE_DVR:
+ intf_type = MEDIA_INTF_T_DVB_DVR;
+ break;
+ case DVB_DEVICE_CA:
+ intf_type = MEDIA_INTF_T_DVB_CA;
+ break;
+ case DVB_DEVICE_NET:
+ intf_type = MEDIA_INTF_T_DVB_NET;
+ break;
+ default:
+ return 0;
+ }
+
+ dvbdev->intf_devnode = media_devnode_create(dvbdev->adapter->mdev,
+ intf_type, 0,
+ DVB_MAJOR, minor);
+
+ if (!dvbdev->intf_devnode)
+ return -ENOMEM;
+
+ /*
+ * Create the "obvious" link, e. g. the ones that represent
+ * a direct association between an interface and an entity.
+ * Other links should be created elsewhere, like:
+ * DVB FE intf -> tuner
+ * DVB demux intf -> dvr
+ */
+
+ if (!dvbdev->entity)
+ return 0;
+
+ link = media_create_intf_link(dvbdev->entity, &dvbdev->intf_devnode->intf,
+ MEDIA_LNK_FL_ENABLED);
+ if (!link)
+ return -ENOMEM;
+#endif
+ return 0;
+}
+
+int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
+ const struct dvb_device *template, void *priv, int type,
+ int demux_sink_pads)
+{
+ struct dvb_device *dvbdev;
+ struct file_operations *dvbdevfops;
+ struct device *clsdev;
+ int minor;
+ int id, ret;
+
+ mutex_lock(&dvbdev_register_lock);
+
+ if ((id = dvbdev_get_free_id (adap, type)) < 0){
+ mutex_unlock(&dvbdev_register_lock);
+ *pdvbdev = NULL;
+ printk(KERN_ERR "%s: couldn't find free device id\n", __func__);
+ return -ENFILE;
+ }
+
+ *pdvbdev = dvbdev = kzalloc(sizeof(*dvbdev), GFP_KERNEL);
+
+ if (!dvbdev){
+ mutex_unlock(&dvbdev_register_lock);
+ return -ENOMEM;
+ }
+
+ dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
+
+ if (!dvbdevfops){
+ kfree (dvbdev);
+ mutex_unlock(&dvbdev_register_lock);
+ return -ENOMEM;
+ }
+
+ memcpy(dvbdev, template, sizeof(struct dvb_device));
+ dvbdev->type = type;
+ dvbdev->id = id;
+ dvbdev->adapter = adap;
+ dvbdev->priv = priv;
+ dvbdev->fops = dvbdevfops;
+ init_waitqueue_head (&dvbdev->wait_queue);
+
+ memcpy(dvbdevfops, template->fops, sizeof(struct file_operations));
+ dvbdevfops->owner = adap->module;
+
+ list_add_tail (&dvbdev->list_head, &adap->device_list);
+
+ down_write(&minor_rwsem);
+#ifdef CONFIG_DVB_DYNAMIC_MINORS
+ for (minor = 0; minor < MAX_DVB_MINORS; minor++)
+ if (dvb_minors[minor] == NULL)
+ break;
+
+ if (minor == MAX_DVB_MINORS) {
+ kfree(dvbdevfops);
+ kfree(dvbdev);
+ up_write(&minor_rwsem);
+ mutex_unlock(&dvbdev_register_lock);
+ return -EINVAL;
+ }
+#else
+ minor = nums2minor(adap->num, type, id);
+#endif
+
+ dvbdev->minor = minor;
+ dvb_minors[minor] = dvbdev;
+ up_write(&minor_rwsem);
+
+ ret = dvb_register_media_device(dvbdev, type, minor, demux_sink_pads);
+ if (ret) {
+ printk(KERN_ERR
+ "%s: dvb_register_media_device failed to create the mediagraph\n",
+ __func__);
+
+ dvb_media_device_free(dvbdev);
+ kfree(dvbdevfops);
+ kfree(dvbdev);
+ up_write(&minor_rwsem);
+ mutex_unlock(&dvbdev_register_lock);
+ return ret;
+ }
+
+ mutex_unlock(&dvbdev_register_lock);
+
+ clsdev = device_create(dvb_class, adap->device,
+ MKDEV(DVB_MAJOR, minor),
+ dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
+ if (IS_ERR(clsdev)) {
+ printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n",
+ __func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
+ return PTR_ERR(clsdev);
+ }
+ dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
+ adap->num, dnames[type], id, minor, minor);
+
+ return 0;
+}
+EXPORT_SYMBOL(dvb_register_device);
+
+
+void dvb_unregister_device(struct dvb_device *dvbdev)
+{
+ if (!dvbdev)
+ return;
+
+ down_write(&minor_rwsem);
+ dvb_minors[dvbdev->minor] = NULL;
+ up_write(&minor_rwsem);
+
+ dvb_media_device_free(dvbdev);
+
+ device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
+
+ list_del (&dvbdev->list_head);
+ kfree (dvbdev->fops);
+ kfree (dvbdev);
+}
+EXPORT_SYMBOL(dvb_unregister_device);
+
+
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+
+static int dvb_create_io_intf_links(struct dvb_adapter *adap,
+ struct media_interface *intf,
+ char *name)
+{
+ struct media_device *mdev = adap->mdev;
+ struct media_entity *entity;
+ struct media_link *link;
+
+ media_device_for_each_entity(entity, mdev) {
+ if (entity->function == MEDIA_ENT_F_IO_DTV) {
+ if (strncmp(entity->name, name, strlen(name)))
+ continue;
+ link = media_create_intf_link(entity, intf,
+ MEDIA_LNK_FL_ENABLED);
+ if (!link)
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+int dvb_create_media_graph(struct dvb_adapter *adap,
+ bool create_rf_connector)
+{
+ struct media_device *mdev = adap->mdev;
+ struct media_entity *entity, *tuner = NULL, *demod = NULL, *conn;
+ struct media_entity *demux = NULL, *ca = NULL;
+ struct media_link *link;
+ struct media_interface *intf;
+ unsigned demux_pad = 0;
+ unsigned dvr_pad = 0;
+ unsigned ntuner = 0, ndemod = 0;
+ int ret;
+ static const char *connector_name = "Television";
+
+ if (!mdev)
+ return 0;
+
+ media_device_for_each_entity(entity, mdev) {
+ switch (entity->function) {
+ case MEDIA_ENT_F_TUNER:
+ tuner = entity;
+ ntuner++;
+ break;
+ case MEDIA_ENT_F_DTV_DEMOD:
+ demod = entity;
+ ndemod++;
+ break;
+ case MEDIA_ENT_F_TS_DEMUX:
+ demux = entity;
+ break;
+ case MEDIA_ENT_F_DTV_CA:
+ ca = entity;
+ break;
+ }
+ }
+
+ /*
+ * Prepare to signalize to media_create_pad_links() that multiple
+ * entities of the same type exists and a 1:n or n:1 links need to be
+ * created.
+ * NOTE: if both tuner and demod have multiple instances, it is up
+ * to the caller driver to create such links.
+ */
+ if (ntuner > 1)
+ tuner = NULL;
+ if (ndemod > 1)
+ demod = NULL;
+
+ if (create_rf_connector) {
+ conn = kzalloc(sizeof(*conn), GFP_KERNEL);
+ if (!conn)
+ return -ENOMEM;
+ adap->conn = conn;
+
+ adap->conn_pads = kzalloc(sizeof(*adap->conn_pads), GFP_KERNEL);
+ if (!adap->conn_pads)
+ return -ENOMEM;
+
+ conn->flags = MEDIA_ENT_FL_CONNECTOR;
+ conn->function = MEDIA_ENT_F_CONN_RF;
+ conn->name = connector_name;
+ adap->conn_pads->flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(conn, 1, adap->conn_pads);
+ if (ret)
+ return ret;
+
+ ret = media_device_register_entity(mdev, conn);
+ if (ret)
+ return ret;
+
+ if (!ntuner)
+ ret = media_create_pad_links(mdev,
+ MEDIA_ENT_F_CONN_RF,
+ conn, 0,
+ MEDIA_ENT_F_DTV_DEMOD,
+ demod, 0,
+ MEDIA_LNK_FL_ENABLED,
+ false);
+ else
+ ret = media_create_pad_links(mdev,
+ MEDIA_ENT_F_CONN_RF,
+ conn, 0,
+ MEDIA_ENT_F_TUNER,
+ tuner, TUNER_PAD_RF_INPUT,
+ MEDIA_LNK_FL_ENABLED,
+ false);
+ if (ret)
+ return ret;
+ }
+
+ if (ntuner && ndemod) {
+ ret = media_create_pad_links(mdev,
+ MEDIA_ENT_F_TUNER,
+ tuner, TUNER_PAD_OUTPUT,
+ MEDIA_ENT_F_DTV_DEMOD,
+ demod, 0, MEDIA_LNK_FL_ENABLED,
+ false);
+ if (ret)
+ return ret;
+ }
+
+ if (ndemod && demux) {
+ ret = media_create_pad_links(mdev,
+ MEDIA_ENT_F_DTV_DEMOD,
+ demod, 1,
+ MEDIA_ENT_F_TS_DEMUX,
+ demux, 0, MEDIA_LNK_FL_ENABLED,
+ false);
+ if (ret)
+ return ret;
+ }
+ if (demux && ca) {
+ ret = media_create_pad_link(demux, 1, ca,
+ 0, MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ return ret;
+ }
+
+ /* Create demux links for each ringbuffer/pad */
+ if (demux) {
+ media_device_for_each_entity(entity, mdev) {
+ if (entity->function == MEDIA_ENT_F_IO_DTV) {
+ if (!strncmp(entity->name, DVR_TSOUT,
+ strlen(DVR_TSOUT))) {
+ ret = media_create_pad_link(demux,
+ ++dvr_pad,
+ entity, 0, 0);
+ if (ret)
+ return ret;
+ }
+ if (!strncmp(entity->name, DEMUX_TSOUT,
+ strlen(DEMUX_TSOUT))) {
+ ret = media_create_pad_link(demux,
+ ++demux_pad,
+ entity, 0, 0);
+ if (ret)
+ return ret;
+ }
+ }
+ }
+ }
+
+ /* Create interface links for FE->tuner, DVR->demux and CA->ca */
+ media_device_for_each_intf(intf, mdev) {
+ if (intf->type == MEDIA_INTF_T_DVB_CA && ca) {
+ link = media_create_intf_link(ca, intf,
+ MEDIA_LNK_FL_ENABLED);
+ if (!link)
+ return -ENOMEM;
+ }
+
+ if (intf->type == MEDIA_INTF_T_DVB_FE && tuner) {
+ link = media_create_intf_link(tuner, intf,
+ MEDIA_LNK_FL_ENABLED);
+ if (!link)
+ return -ENOMEM;
+ }
+#if 0
+ /*
+ * Indirect link - let's not create yet, as we don't know how
+ * to handle indirect links, nor if this will
+ * actually be needed.
+ */
+ if (intf->type == MEDIA_INTF_T_DVB_DVR && demux) {
+ link = media_create_intf_link(demux, intf,
+ MEDIA_LNK_FL_ENABLED);
+ if (!link)
+ return -ENOMEM;
+ }
+#endif
+ if (intf->type == MEDIA_INTF_T_DVB_DVR) {
+ ret = dvb_create_io_intf_links(adap, intf, DVR_TSOUT);
+ if (ret)
+ return ret;
+ }
+ if (intf->type == MEDIA_INTF_T_DVB_DEMUX) {
+ ret = dvb_create_io_intf_links(adap, intf, DEMUX_TSOUT);
+ if (ret)
+ return ret;
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dvb_create_media_graph);
+#endif
+
+static int dvbdev_check_free_adapter_num(int num)
+{
+ struct list_head *entry;
+ list_for_each(entry, &dvb_adapter_list) {
+ struct dvb_adapter *adap;
+ adap = list_entry(entry, struct dvb_adapter, list_head);
+ if (adap->num == num)
+ return 0;
+ }
+ return 1;
+}
+
+static int dvbdev_get_free_adapter_num (void)
+{
+ int num = 0;
+
+ while (num < DVB_MAX_ADAPTERS) {
+ if (dvbdev_check_free_adapter_num(num))
+ return num;
+ num++;
+ }
+
+ return -ENFILE;
+}
+
+
+int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
+ struct module *module, struct device *device,
+ short *adapter_nums)
+{
+ int i, num;
+
+ mutex_lock(&dvbdev_register_lock);
+
+ for (i = 0; i < DVB_MAX_ADAPTERS; ++i) {
+ num = adapter_nums[i];
+ if (num >= 0 && num < DVB_MAX_ADAPTERS) {
+ /* use the one the driver asked for */
+ if (dvbdev_check_free_adapter_num(num))
+ break;
+ } else {
+ num = dvbdev_get_free_adapter_num();
+ break;
+ }
+ num = -1;
+ }
+
+ if (num < 0) {
+ mutex_unlock(&dvbdev_register_lock);
+ return -ENFILE;
+ }
+
+ memset (adap, 0, sizeof(struct dvb_adapter));
+ INIT_LIST_HEAD (&adap->device_list);
+
+ printk(KERN_INFO "DVB: registering new adapter (%s)\n", name);
+
+ adap->num = num;
+ adap->name = name;
+ adap->module = module;
+ adap->device = device;
+ adap->mfe_shared = 0;
+ adap->mfe_dvbdev = NULL;
+ mutex_init (&adap->mfe_lock);
+
+ list_add_tail (&adap->list_head, &dvb_adapter_list);
+
+ mutex_unlock(&dvbdev_register_lock);
+
+ return num;
+}
+EXPORT_SYMBOL(dvb_register_adapter);
+
+
+int dvb_unregister_adapter(struct dvb_adapter *adap)
+{
+ mutex_lock(&dvbdev_register_lock);
+ list_del (&adap->list_head);
+ mutex_unlock(&dvbdev_register_lock);
+ return 0;
+}
+EXPORT_SYMBOL(dvb_unregister_adapter);
+
+/* if the miracle happens and "generic_usercopy()" is included into
+ the kernel, then this can vanish. please don't make the mistake and
+ define this as video_usercopy(). this will introduce a dependecy
+ to the v4l "videodev.o" module, which is unnecessary for some
+ cards (ie. the budget dvb-cards don't need the v4l module...) */
+int dvb_usercopy(struct file *file,
+ unsigned int cmd, unsigned long arg,
+ int (*func)(struct file *file,
+ unsigned int cmd, void *arg))
+{
+ char sbuf[128];
+ void *mbuf = NULL;
+ void *parg = NULL;
+ int err = -EINVAL;
+
+ /* Copy arguments into temp kernel buffer */
+ switch (_IOC_DIR(cmd)) {
+ case _IOC_NONE:
+ /*
+ * For this command, the pointer is actually an integer
+ * argument.
+ */
+ parg = (void *) arg;
+ break;
+ case _IOC_READ: /* some v4l ioctls are marked wrong ... */
+ case _IOC_WRITE:
+ case (_IOC_WRITE | _IOC_READ):
+ if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+ parg = sbuf;
+ } else {
+ /* too big to allocate from stack */
+ mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
+ if (NULL == mbuf)
+ return -ENOMEM;
+ parg = mbuf;
+ }
+
+ err = -EFAULT;
+ if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
+ goto out;
+ break;
+ }
+
+ /* call driver */
+ if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD)
+ err = -ENOTTY;
+
+ if (err < 0)
+ goto out;
+
+ /* Copy results into user buffer */
+ switch (_IOC_DIR(cmd))
+ {
+ case _IOC_READ:
+ case (_IOC_WRITE | _IOC_READ):
+ if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
+ err = -EFAULT;
+ break;
+ }
+
+out:
+ kfree(mbuf);
+ return err;
+}
+EXPORT_SYMBOL(dvb_usercopy);
+static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct dvb_device *dvbdev = dev_get_drvdata(dev);
+
+ add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num);
+ add_uevent_var(env, "DVB_DEVICE_TYPE=%s", dnames[dvbdev->type]);
+ add_uevent_var(env, "DVB_DEVICE_NUM=%d", dvbdev->id);
+ return 0;
+}
+
+static char *dvb_devnode(struct device *dev, umode_t *mode)
+{
+ struct dvb_device *dvbdev = dev_get_drvdata(dev);
+
+ return kasprintf(GFP_KERNEL, "dvb/adapter%d/%s%d",
+ dvbdev->adapter->num, dnames[dvbdev->type], dvbdev->id);
+}
+
+
+static int __init init_dvbdev(void)
+{
+ int retval;
+ dev_t dev = MKDEV(DVB_MAJOR, 0);
+
+ if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) {
+ printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR);
+ return retval;
+ }
+
+ cdev_init(&dvb_device_cdev, &dvb_device_fops);
+ if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) {
+ printk(KERN_ERR "dvb-core: unable register character device\n");
+ goto error;
+ }
+
+ dvb_class = class_create(THIS_MODULE, "dvb");
+ if (IS_ERR(dvb_class)) {
+ retval = PTR_ERR(dvb_class);
+ goto error;
+ }
+ dvb_class->dev_uevent = dvb_uevent;
+ dvb_class->devnode = dvb_devnode;
+ return 0;
+
+error:
+ cdev_del(&dvb_device_cdev);
+ unregister_chrdev_region(dev, MAX_DVB_MINORS);
+ return retval;
+}
+
+
+static void __exit exit_dvbdev(void)
+{
+ class_destroy(dvb_class);
+ cdev_del(&dvb_device_cdev);
+ unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS);
+}
+#if 0
+subsys_initcall(init_dvbdev);
+module_exit(exit_dvbdev);
+
+MODULE_DESCRIPTION("DVB Core Driver");
+MODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler");
+MODULE_LICENSE("GPL");
+#endif
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/dvbdev.h b/drivers/stream_input/parser/dvb_ci/cimax/dvbdev.h
new file mode 100644
index 0000000..4aff7bd
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/dvbdev.h
@@ -0,0 +1,299 @@
+/*
+ * dvbdev.h
+ *
+ * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
+ * for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Lesser Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser 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.
+ *
+ */
+
+#ifndef _DVBDEV_H_
+#define _DVBDEV_H_
+
+#include <linux/types.h>
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <media/media-device.h>
+
+#define DVB_MAJOR 212
+
+#if defined(CONFIG_DVB_MAX_ADAPTERS) && CONFIG_DVB_MAX_ADAPTERS > 0
+ #define DVB_MAX_ADAPTERS CONFIG_DVB_MAX_ADAPTERS
+#else
+ #define DVB_MAX_ADAPTERS 8
+#endif
+
+#define DVB_UNSET (-1)
+
+#define DVB_DEVICE_VIDEO 0
+#define DVB_DEVICE_AUDIO 1
+#define DVB_DEVICE_SEC 2
+#define DVB_DEVICE_FRONTEND 3
+#define DVB_DEVICE_DEMUX 4
+#define DVB_DEVICE_DVR 5
+#define DVB_DEVICE_CA 6
+#define DVB_DEVICE_NET 7
+#define DVB_DEVICE_OSD 8
+
+#define DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr) \
+ static short adapter_nr[] = \
+ {[0 ... (DVB_MAX_ADAPTERS - 1)] = DVB_UNSET }; \
+ module_param_array(adapter_nr, short, NULL, 0444); \
+ MODULE_PARM_DESC(adapter_nr, "DVB adapter numbers")
+
+struct dvb_frontend;
+
+/**
+ * struct dvb_adapter - represents a Digital TV adapter using Linux DVB API
+ *
+ * @num: Number of the adapter
+ * @list_head: List with the DVB adapters
+ * @device_list: List with the DVB devices
+ * @name: Name of the adapter
+ * @proposed_mac: proposed MAC address for the adapter
+ * @priv: private data
+ * @device: pointer to struct device
+ * @module: pointer to struct module
+ * @mfe_shared: mfe shared: indicates mutually exclusive frontends
+ * Thie usage of this flag is currently deprecated
+ * @mfe_dvbdev: Frontend device in use, in the case of MFE
+ * @mfe_lock: Lock to prevent using the other frontends when MFE is
+ * used.
+ * @mdev: pointer to struct media_device, used when the media
+ * controller is used.
+ * @conn: RF connector. Used only if the device has no separate
+ * tuner.
+ * @conn_pads: pointer to struct media_pad associated with @conn;
+ */
+struct dvb_adapter {
+ int num;
+ struct list_head list_head;
+ struct list_head device_list;
+ const char *name;
+ u8 proposed_mac [6];
+ void* priv;
+
+ struct device *device;
+
+ struct module *module;
+
+ int mfe_shared; /* indicates mutually exclusive frontends */
+ struct dvb_device *mfe_dvbdev; /* frontend device in use */
+ struct mutex mfe_lock; /* access lock for thread creation */
+
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+ struct media_device *mdev;
+ struct media_entity *conn;
+ struct media_pad *conn_pads;
+#endif
+};
+
+/**
+ * struct dvb_device - represents a DVB device node
+ *
+ * @list_head: List head with all DVB devices
+ * @fops: pointer to struct file_operations
+ * @adapter: pointer to the adapter that holds this device node
+ * @type: type of the device: DVB_DEVICE_SEC, DVB_DEVICE_FRONTEND,
+ * DVB_DEVICE_DEMUX, DVB_DEVICE_DVR, DVB_DEVICE_CA, DVB_DEVICE_NET
+ * @minor: devnode minor number. Major number is always DVB_MAJOR.
+ * @id: device ID number, inside the adapter
+ * @readers: Initialized by the caller. Each call to open() in Read Only mode
+ * decreases this counter by one.
+ * @writers: Initialized by the caller. Each call to open() in Read/Write
+ * mode decreases this counter by one.
+ * @users: Initialized by the caller. Each call to open() in any mode
+ * decreases this counter by one.
+ * @wait_queue: wait queue, used to wait for certain events inside one of
+ * the DVB API callers
+ * @kernel_ioctl: callback function used to handle ioctl calls from userspace.
+ * @name: Name to be used for the device at the Media Controller
+ * @entity: pointer to struct media_entity associated with the device node
+ * @pads: pointer to struct media_pad associated with @entity;
+ * @priv: private data
+ * @intf_devnode: Pointer to media_intf_devnode. Used by the dvbdev core to
+ * store the MC device node interface
+ * @tsout_num_entities: Number of Transport Stream output entities
+ * @tsout_entity: array with MC entities associated to each TS output node
+ * @tsout_pads: array with the source pads for each @tsout_entity
+ *
+ * This structure is used by the DVB core (frontend, CA, net, demux) in
+ * order to create the device nodes. Usually, driver should not initialize
+ * this struct diretly.
+ */
+struct dvb_device {
+ struct list_head list_head;
+ const struct file_operations *fops;
+ struct dvb_adapter *adapter;
+ int type;
+ int minor;
+ u32 id;
+
+ /* in theory, 'users' can vanish now,
+ but I don't want to change too much now... */
+ int readers;
+ int writers;
+ int users;
+
+ wait_queue_head_t wait_queue;
+ /* don't really need those !? -- FIXME: use video_usercopy */
+ int (*kernel_ioctl)(struct file *file, unsigned int cmd, void *arg);
+
+ /* Needed for media controller register/unregister */
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+ const char *name;
+
+ /* Allocated and filled inside dvbdev.c */
+ struct media_intf_devnode *intf_devnode;
+
+ unsigned tsout_num_entities;
+ struct media_entity *entity, *tsout_entity;
+ struct media_pad *pads, *tsout_pads;
+#endif
+
+ void *priv;
+};
+
+/**
+ * dvb_register_adapter - Registers a new DVB adapter
+ *
+ * @adap: pointer to struct dvb_adapter
+ * @name: Adapter's name
+ * @module: initialized with THIS_MODULE at the caller
+ * @device: pointer to struct device that corresponds to the device driver
+ * @adapter_nums: Array with a list of the numbers for @dvb_register_adapter;
+ * to select among them. Typically, initialized with:
+ * DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nums)
+ */
+int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
+ struct module *module, struct device *device,
+ short *adapter_nums);
+
+/**
+ * dvb_unregister_adapter - Unregisters a DVB adapter
+ *
+ * @adap: pointer to struct dvb_adapter
+ */
+int dvb_unregister_adapter(struct dvb_adapter *adap);
+
+/**
+ * dvb_register_device - Registers a new DVB device
+ *
+ * @adap: pointer to struct dvb_adapter
+ * @pdvbdev: pointer to the place where the new struct dvb_device will be
+ * stored
+ * @template: Template used to create &pdvbdev;
+ * @priv: private data
+ * @type: type of the device: %DVB_DEVICE_SEC, %DVB_DEVICE_FRONTEND,
+ * %DVB_DEVICE_DEMUX, %DVB_DEVICE_DVR, %DVB_DEVICE_CA,
+ * %DVB_DEVICE_NET
+ * @demux_sink_pads: Number of demux outputs, to be used to create the TS
+ * outputs via the Media Controller.
+ */
+int dvb_register_device(struct dvb_adapter *adap,
+ struct dvb_device **pdvbdev,
+ const struct dvb_device *template,
+ void *priv,
+ int type,
+ int demux_sink_pads);
+
+/**
+ * dvb_unregister_device - Unregisters a DVB device
+ *
+ * @dvbdev: pointer to struct dvb_device
+ */
+void dvb_unregister_device(struct dvb_device *dvbdev);
+
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+/**
+ * dvb_create_media_graph - Creates media graph for the Digital TV part of the
+ * device.
+ *
+ * @adap: pointer to struct dvb_adapter
+ * @create_rf_connector: if true, it creates the RF connector too
+ *
+ * This function checks all DVB-related functions at the media controller
+ * entities and creates the needed links for the media graph. It is
+ * capable of working with multiple tuners or multiple frontends, but it
+ * won't create links if the device has multiple tuners and multiple frontends
+ * or if the device has multiple muxes. In such case, the caller driver should
+ * manually create the remaining links.
+ */
+__must_check int dvb_create_media_graph(struct dvb_adapter *adap,
+ bool create_rf_connector);
+
+static inline void dvb_register_media_controller(struct dvb_adapter *adap,
+ struct media_device *mdev)
+{
+ adap->mdev = mdev;
+}
+
+static inline struct media_device
+*dvb_get_media_controller(struct dvb_adapter *adap)
+{
+ return adap->mdev;
+}
+#else
+static inline
+int dvb_create_media_graph(struct dvb_adapter *adap,
+ bool create_rf_connector)
+{
+ return 0;
+};
+#define dvb_register_media_controller(a, b) {}
+#define dvb_get_media_controller(a) NULL
+#endif
+
+int dvb_generic_open (struct inode *inode, struct file *file);
+int dvb_generic_release (struct inode *inode, struct file *file);
+long dvb_generic_ioctl (struct file *file,
+ unsigned int cmd, unsigned long arg);
+
+/* we don't mess with video_usercopy() any more,
+we simply define out own dvb_usercopy(), which will hopefully become
+generic_usercopy() someday... */
+
+int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+ int (*func)(struct file *file, unsigned int cmd, void *arg));
+
+/** generic DVB attach function. */
+#ifdef CONFIG_MEDIA_ATTACH
+#define dvb_attach(FUNCTION, ARGS...) ({ \
+ void *__r = NULL; \
+ typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
+ if (__a) { \
+ __r = (void *) __a(ARGS); \
+ if (__r == NULL) \
+ symbol_put(FUNCTION); \
+ } else { \
+ printk(KERN_ERR "DVB: Unable to find symbol "#FUNCTION"()\n"); \
+ } \
+ __r; \
+})
+
+#define dvb_detach(FUNC) symbol_put_addr(FUNC)
+
+#else
+#define dvb_attach(FUNCTION, ARGS...) ({ \
+ FUNCTION(ARGS); \
+})
+
+#define dvb_detach(FUNC) {}
+
+#endif
+
+#endif /* #ifndef _DVBDEV_H_ */
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/usb/COPYING.LESSER b/drivers/stream_input/parser/dvb_ci/cimax/usb/COPYING.LESSER
new file mode 100644
index 0000000..8f4a860
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/usb/COPYING.LESSER
@@ -0,0 +1,499 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.
+We sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/usb/README.txt b/drivers/stream_input/parser/dvb_ci/cimax/usb/README.txt
new file mode 100644
index 0000000..1d6a01c
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/usb/README.txt
@@ -0,0 +1,61 @@
+April 28, 2011
+
+Linux CIMaX+ Kernel driver.
+Release Code version:
+
+DISCLAIMER
+----------
+
+This is a Smardtv' Linux Kernel driver for use with
+the CIMaX+ USB reference board hardware.
+
+IMPORTANT NOTE
+--------------
+
+This packages contains a Linux Kernel driver to be installed in the
+/lib/modules target directory in order to be loaded automaticaly.
+
+1. High level driver: cimax+usb_driver.ko
+ This driver provide the high level interface to control the CIMaX+ USB interface.
+
+2. Firmware
+ To have a functional hardware, the firmware must be uploaded to the device.
+
+ The firmwares is delivered in 2 files for dedicated usage and must be
+ installed in the Linux firmware directory on the target board:
+
+ - /lib/firmware
+
+ A) CIMaX+ firmware binary file
+ Copy the following firmware file to the /lib/firmware directory:
+ - firmware/cimax+_usbdvb.bin
+
+ B) CIMaX+ configuration file
+ Copy the following firmware file to the /lib/firmware directory:
+ - firmware/cimax+usb.cfg
+
+
+BUILD AND INSTALLATION INSTRUCTIONS
+-----------------------------------
+
+2. Building LINUX USB DVB driver
+ On the target machine performs the following commands:
+
+ 1. cd src
+ 2. make
+ 3. make install
+
+3. Installing firmware files
+ On the target machine performs the following command:
+
+ 1. cp firmware/*.* /lib/firmware/
+
+4. Installing rules file
+ 1. cp src/99-cimax+usb.rules /etc/udev/rules.d/
+ 2. udevadm control --reload-rules
+
+5. Build modules dependencies
+ On the target machine performs the following command:
+
+ 1. depmod -a
+
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/99-cimax+usb.rules b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/99-cimax+usb.rules
new file mode 100644
index 0000000..82af370
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/99-cimax+usb.rules
@@ -0,0 +1,4 @@
+BUS=="usb", ACTION=="add", SYSFS{idProduct}=="2F00", SYSFS{idVendor}=="1B0D"
+KERNEL=="cimaxusb[0-9]", GROUP="users"
+
+
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/HOWTO.txt b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/HOWTO.txt
new file mode 100644
index 0000000..23de038
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/HOWTO.txt
@@ -0,0 +1,85 @@
+The following examples shows how to use the cimax+usb driver.
+All structures and macro are defined in file cimax+usb-driver.h.
+
+
+1.Open the device cimax+usb
+===========================
+/* open device */
+dev = open("/dev/cimaxusb0", O_RDWR);
+/* select USB alt_setting */
+ioctl(dev, DEVICE_IOC_SELECT_INTF, alt_setting);
+
+
+2.Close the device cimax+usb
+============================
+/* unlock read queue */
+ioctl(dev, DEVICE_IOC_UNLOCK_READ, 0);
+/* close device */
+close(dev);
+
+
+3.Send a CI message to a CAM through the device
+===============================================
+/* Send CAM A Reset command */
+uint8 command[5] = {0x01, /* Command */
+ 0x01, /* Counter */
+ 0x00, /* MSB data size */
+ 0x01, /* LSB data size */
+ 0x00}; /* data */
+uint8 response[4100];
+struct ioctl_data_s stData;
+stData.txData = command;
+stData.txSize = 5;
+stData.rxData = response;
+stData.rxSize = 4100;
+ioctl(dev, DEVICE_IOC_CI_WRITE, &stData);
+
+/* Send CAM B Get CIS command */
+uint8 command[5] = {0x82, /* Command */
+ 0x01, /* Counter */
+ 0x00, /* MSB data size */
+ 0x00}; /* LSB data size */
+uint8 response[4100];
+struct ioctl_data_s stData;
+stData.txData = command;
+stData.txSize = 4;
+stData.rxData = response;
+stData.rxSize = 4100;
+ioctl(dev, DEVICE_IOC_CI_WRITE, &stData);
+
+
+4.Send a Transport Stream to a CAM through the device
+=====================================================
+/* Send to CAM A */
+struct rw_data_s rwData;
+rwData.type = DEVICE_TYPE_TS_WRITE;
+rwData.moduleId = 0; /* CAM A */
+rwData.data = stream;
+rwData.size = size;
+rwData.copiedSize = 0;
+write(dev, &rwData, sizeof(struct rw_data_s));
+
+
+5.Read a Transport Stream from a CAM through the device
+=======================================================
+/* Read from CAM B */
+struct rw_data_s rwData;
+rwData.type = DEVICE_TYPE_TS_READ;
+rwData.moduleId = 1; /* CAM B */
+rwData.data = stream;
+rwData.size = size;
+rwData.copiedSize = 0;
+read(dev, &rwData, sizeof(struct rw_data_s));
+
+
+6.Read a CI message from a CAM through the device
+=================================================
+/* Read from CAM A */
+uint8 response[4096];
+struct rw_data_s rwData;
+rwData.type = DEVICE_TYPE_CI_READ;
+rwData.moduleId = 0; /* CAM A */
+rwData.data = response;
+rwData.size = 4096;
+rwData.copiedSize = 0;
+read(dev, &rwData, sizeof(struct rw_data_s));
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/Makefile b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/Makefile
new file mode 100644
index 0000000..bc79945
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/Makefile
@@ -0,0 +1,35 @@
+TARGET = cimax+usb_driver
+OBJS = cimax+usb_driver.o
+MDIR = drivers/misc
+
+ccflags-y = -DEXPORT_SYMTAB
+#ccflags-y = -DEXPORT_SYMTAB -DDEBUG
+CURRENT = $(shell uname -r)
+KDIR = /lib/modules/$(CURRENT)/build
+PWD = $(shell pwd)
+DEST = /lib/modules/$(CURRENT)/kernel/$(MDIR)
+
+obj-m := $(TARGET).o
+cimax+usb_driver-y := cimax+usb-driver.o cimax+usb_fw.o
+cimax+usb_driver-y += cimax+usb_config.o
+cimax+usb_driver-y += cimax+usb_time.o
+
+default:
+ make -C /usr/src/linux SUBDIRS=$(PWD) modules
+# make -C /lib/modules/`uname -r`/build M=$(PWD) modules
+
+$(TARGET).o: $(OBJS)
+ $(LD) $(LD_RFLAG) -r -o $@ $(OBJS)
+
+ifneq (,$(findstring 2.4.,$(CURRENT)))
+install:
+ su -c "cp -v $(TARGET).o $(DEST) && /sbin/depmod -a"
+else
+install:
+ su -c "cp -v $(TARGET).ko $(DEST) && /sbin/depmod -a"
+endif
+
+clean:
+ -rm -f *.o *.ko .*.cmd .*.flags *.mod.c
+
+-include $(KDIR)/Rules.make
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/bodydef.h b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/bodydef.h
new file mode 100644
index 0000000..f93fef5
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/bodydef.h
@@ -0,0 +1,424 @@
+/**************************************************************************//**
+ * @file bodydef.h
+ *
+ * @brief CIMaX+ USB Driver for linux based operating systems.
+ *
+ * Copyright (C) 2009-2011 Bruno Tonelli <bruno.tonelli@smardtv.com>
+ * & Franck Descours <franck.descours@smardtv.com>
+ * for SmarDTV France, La Ciotat
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ ******************************************************************************/
+
+#ifndef __BODYDEF_H
+#define __BODYDEF_H
+
+struct reg_s {
+ __u8 RegisterName[50];
+ __u16 RegAddr;
+};
+
+/*=======================================================================
+ Input/Output Ports and Data Direction Registers
+=======================================================================*/
+struct reg_s cimax_reg_map[] = {
+ {"BUFFIN_CFG" , 0x0000},
+ {"BUFFIN_ADDR_LSB" , 0x0001},
+ {"BUFFIN_ADDR_MSB" , 0x0002},
+ {"BUFFIN_DATA" , 0x0003},
+ {"BUFFOUT_CFG" , 0x0004},
+ {"BUFFOUT_ADDR_LSB" , 0x0005},
+ {"BUFFOUT_ADDR_MSB" , 0x0006},
+ {"BUFFOUT_DATA" , 0x0007},
+ {"BOOT_Key" , 0x0008},
+ {"BOOT_Status" , 0x0009},
+ {"BOOT_Test " , 0x000A},
+ {"RxDMA_Ctrl" , 0x0010},
+ {"RxDMA_Status" , 0x0011},
+ {"RxDMA_DbgL" , 0x0012},
+ {"RxDMA_DbgH" , 0x0013},
+ {"SPI_Slave_Ctrl" , 0x0018},
+ {"SPI_Slave_Status" , 0x0019},
+ {"SPI_Slave_Rx" , 0x001A},
+ {"SPI_Slave_Tx" , 0x001B},
+ {"SPI_Slave_Mask" , 0x001C},
+ {"UCSG_Ctrl" , 0x0020},
+ {"UCSG_Status" , 0x0021},
+ {"UCSG_RxData" , 0x0022},
+ {"UCSG_TxData" , 0x0023},
+ {"PCtrl_Ctrl" , 0x0028},
+ {"PCtrl_Status" , 0x0029},
+ {"PCtrl_NbByte_LSB" , 0x002A},
+ {"PCtrl_NbByte_MSB" , 0x002B},
+ {"SPI_Master_Ctl" , 0x0030},
+ {"SPI_Master_NCS" , 0x0031},
+ {"SPI_Master_Status" , 0x0032},
+ {"SPI_Master_TxBuf" , 0x0033},
+ {"SPI_Master_RxBuf" , 0x0034},
+ {"BISTRAM_Ctl" , 0x0038},
+ {"BISTRAM_Bank" , 0x0039},
+ {"BISTRAM_Pat" , 0x003A},
+ {"BISTRAM_SM" , 0x003B},
+ {"BISTRAM_AddrLSB" , 0x003C},
+ {"BISTROM_Config" , 0x0040},
+ {"BISTROM_SignatureLSB" , 0x0041},
+ {"BISTROM_SignatureMSB" , 0x0042},
+ {"BISTROM_StartAddrLSB" , 0x0043},
+ {"BISTROM_StartAddrMSB" , 0x0044},
+ {"BISTROM_StopAddrLSB" , 0x0045},
+ {"BISTROM_StopAddrMSB" , 0x0046},
+ {"CkMan_Config" , 0x0048},
+ {"CkMan_Select" , 0x0049},
+ {"CkMan_Test" , 0x004A},
+ {"Revision_Number" , 0x004B},
+ {"CkMan_PD_Key" , 0x004C},
+ {"USB_Power_Mode" , 0x004D},
+ {"ResMan_Config" , 0x0050},
+ {"ResMan_Status" , 0x0051},
+ {"ResMan_WD" , 0x0052},
+ {"ResMan_WD_MSB" , 0x0053},
+ {"TxDMA_Ctrl" , 0x0058},
+ {"TxDMA_Status" , 0x0059},
+ {"TxDMA_StartAddrL" , 0x005A},
+ {"TxDMA_StartAddrH" , 0x005B},
+ {"TxDMA_StopAddrL" , 0x005C},
+ {"TxDMA_StopAddrH" , 0x005D},
+ {"CPU_Test" , 0x0060},
+ {"IrqMan_Config0" , 0x0068},
+ {"IrqMan_Config1" , 0x0069},
+ {"IrqMan_Irq0" , 0x006A},
+ {"IrqMan_NMI" , 0x006B},
+ {"IrqMan_SleepKey" , 0x006C},
+ {"Tim_Config" , 0x0070},
+ {"Tim_Value_LSB" , 0x0071},
+ {"Tim_Value_MSB" , 0x0072},
+ {"Tim_Comp_LSB" , 0x0073},
+ {"Tim_Comp_MSB" , 0x0074},
+ {"TI_Config" , 0x0076},
+ {"TI_Data" , 0x0077},
+ {"TI_Reg0" , 0x0078},
+ {"TI_Reg1" , 0x0079},
+ {"TI_Reg2" , 0x007A},
+ {"TI_Reg3" , 0x007B},
+ {"TI_Reg4" , 0x007C},
+ {"TI_ROM1" , 0x007D},
+ {"TI_ROM2" , 0x007E},
+ {"TI_ROM3" , 0x007F},
+ {"DVBCI_START_ADDR" , 0x0100},
+ {"DVBCI_END_ADDR" , 0x017F},
+ {"DATA" , 0x0180},
+ {"CTRL" , 0x0181},
+ {"QB_HOST" , 0x0182},
+ {"LEN_HOST_LSB" , 0x0183},
+ {"LEN_HOST_MSB" , 0x0184},
+ {"FIFO_TX_TH_LSB" , 0x0185},
+ {"FIFO_TX_TH_MSB" , 0x0186},
+ {"FIFO_TX_D_NB_LSB" , 0x0187},
+ {"FIFO_TX_D_NB_MSB" , 0x0188},
+ {"QB_MOD_CURR" , 0x0189},
+ {"LEN_MOD_CURR_LSB" , 0x018A},
+ {"LEN_MOD_CURR_MSB" , 0x018B},
+ {"QB_MOD" , 0x018C},
+ {"LEN_MOD_LSB" , 0x018D},
+ {"LEN_MOD_MSB" , 0x018E},
+ {"FIFO_RX_TH_LSB" , 0x018F},
+ {"FIFO_RX_TH_MSB" , 0x0190},
+ {"FIFO_RX_D_NB_LSB" , 0x0191},
+ {"FIFO_RX_D_NB_MSB" , 0x0192},
+ {"IT_STATUS_0" , 0x0193},
+ {"IT_STATUS_1" , 0x0194},
+ {"IT_MASK_0" , 0x0195},
+ {"IT_MASK_1" , 0x0196},
+ {"IT_HOST_PIN_CFG" , 0x0200},
+ {"CFG_0" , 0x0201},
+ {"CFG_1" , 0x0202},
+ {"CFG_2" , 0x0203},
+ {"IT_HOST" , 0x0204},
+ {"MOD_IT_STATUS" , 0x0205},
+ {"MOD_IT_MASK" , 0x0206},
+ {"MOD_CTRL_A" , 0x0207},
+ {"MOD_CTRL_B" , 0x0208},
+ {"DEST_SEL" , 0x0209},
+ {"CAM_MSB_ADD" , 0x020A},
+ {"GPIO0_DIR" , 0x020B},
+ {"GPIO0_DATA_IN" , 0x020C},
+ {"GPIO0_DATA_OUT" , 0x020D},
+ {"GPIO0_STATUS" , 0x020E},
+ {"GPIO0_IT_MASK" , 0x020F},
+ {"GPIO0_DFT" , 0x0210},
+ {"GPIO0_MASK_DATA" , 0x0211},
+ {"GPIO1_DIR" , 0x0212},
+ {"GPIO1_DATA_IN" , 0x0213},
+ {"GPIO1_DATA_OUT" , 0x0214},
+ {"GPIO1_STATUS" , 0x0215},
+ {"GPIO1_IT_MASK" , 0x0216},
+ {"MEM_ACC_TIME_A" , 0x0217},
+ {"MEM_ACC_TIME_B" , 0x0218},
+ {"IO_ACC_TIME_A" , 0x0219},
+ {"IO_ACC_TIME_B" , 0x021A},
+ {"EXT_CH_ACC_TIME_A" , 0x021B},
+ {"EXT_CH_ACC_TIME_B" , 0x021C},
+ {"PAR_IF_0" , 0x021D},
+ {"PAR_IF_1" , 0x021E},
+ {"PAR_IF_CTRL" , 0x021F},
+ {"PCK_LENGTH" , 0x0220},
+ {"USB2TS_CTRL" , 0x0221},
+ {"USB2TS0_RDL" , 0x0222},
+ {"USB2TS1_RDL" , 0x0223},
+ {"TS2USB_CTRL" , 0x0224},
+ {"TSOUT_PAR_CTRL" , 0x0225},
+ {"TSOUT_PAR_CLK_SEL" , 0x0226},
+ {"S2P_CH0_CTRL" , 0x0227},
+ {"S2P_CH1_CTRL" , 0x0228},
+ {"P2S_CH0_CTRL" , 0x0229},
+ {"P2S_CH1_CTRL" , 0x022A},
+ {"TS_IT_STATUS" , 0x022B},
+ {"TS_IT_MASK" , 0x022C},
+ {"IN_SEL" , 0x022D},
+ {"OUT_SEL" , 0x022E},
+ {"ROUTER_CAM_CH" , 0x022F},
+ {"ROUTER_CAM_MOD" , 0x0230},
+ {"FIFO_CTRL" , 0x0231},
+ {"FIFO1_2_STATUS" , 0x0232},
+ {"FIFO3_4_STATUS" , 0x0233},
+ {"GAP_REMOVER_CH0_CTRL" , 0x0234},
+ {"GAP_REMOVER_CH1_CTRL" , 0x0235},
+ {"SYNC_RTV_CTRL" , 0x0236},
+ {"SYNC_RTV_CH0_SYNC_NB" , 0x0237},
+ {"SYNC_RTV_CH0_PATTERN" , 0x0238},
+ {"SYNC_RTV_CH1_SYNC_NB" , 0x0239},
+ {"SYNC_RTV_CH1_PATTERN" , 0x023A},
+ {"SYNC_RTV_OFFSET_PATT" , 0x023B},
+ {"CTRL_FILTER" , 0x023D},
+ {"PID_EN_FILTER_CH0" , 0x023E},
+ {"PID_EN_FILTER_CH1" , 0x023F},
+ {"PID_LSB_FILTER_CH0_0" , 0x0240},
+ {"PID_MSB_FILTER_CH0_0" , 0x0241},
+ {"PID_LSB_FILTER_CH0_1" , 0x0242},
+ {"PID_MSB_FILTER_CH0_1" , 0x0243},
+ {"PID_LSB_FILTER_CH0_2" , 0x0244},
+ {"PID_MSB_FILTER_CH0_2" , 0x0245},
+ {"PID_LSB_FILTER_CH0_3" , 0x0246},
+ {"PID_MSB_FILTER_CH0_3" , 0x0247},
+ {"PID_LSB_FILTER_CH0_4" , 0x0248},
+ {"PID_MSB_FILTER_CH0_4" , 0x0249},
+ {"PID_LSB_FILTER_CH0_5" , 0x024A},
+ {"PID_MSB_FILTER_CH0_5" , 0x024B},
+ {"PID_LSB_FILTER_CH0_6" , 0x024C},
+ {"PID_MSB_FILTER_CH0_6" , 0x024D},
+ {"PID_LSB_FILTER_CH0_7" , 0x024E},
+ {"PID_MSB_FILTER_CH0_7" , 0x024F},
+ {"PID_LSB_FILTER_CH1_0" , 0x0260},
+ {"PID_MSB_FILTER_CH1_0" , 0x0261},
+ {"PID_LSB_FILTER_CH1_1" , 0x0262},
+ {"PID_MSB_FILTER_CH1_1" , 0x0263},
+ {"PID_LSB_FILTER_CH1_2" , 0x0264},
+ {"PID_MSB_FILTER_CH1_2" , 0x0265},
+ {"PID_LSB_FILTER_CH1_3" , 0x0266},
+ {"PID_MSB_FILTER_CH1_3" , 0x0267},
+ {"PID_LSB_FILTER_CH1_4" , 0x0268},
+ {"PID_MSB_FILTER_CH1_4" , 0x0269},
+ {"PID_LSB_FILTER_CH1_5" , 0x026A},
+ {"PID_MSB_FILTER_CH1_5" , 0x026B},
+ {"PID_LSB_FILTER_CH1_6" , 0x026C},
+ {"PID_MSB_FILTER_CH1_6" , 0x026D},
+ {"PID_LSB_FILTER_CH1_7" , 0x026E},
+ {"PID_MSB_FILTER_CH1_7" , 0x026F},
+ {"PID_OLD_LSB_REMAPPER_0" , 0x0280},
+ {"PID_OLD_MSB_REMAPPER_0" , 0x0281},
+ {"PID_OLD_LSB_REMAPPER_1" , 0x0282},
+ {"PID_OLD_MSB_REMAPPER_1" , 0x0283},
+ {"PID_OLD_LSB_REMAPPER_2" , 0x0284},
+ {"PID_OLD_MSB_REMAPPER_2" , 0x0285},
+ {"PID_OLD_LSB_REMAPPER_3" , 0x0286},
+ {"PID_OLD_MSB_REMAPPER_3" , 0x0287},
+ {"PID_OLD_LSB_REMAPPER_4" , 0x0288},
+ {"PID_OLD_MSB_REMAPPER_4" , 0x0289},
+ {"PID_OLD_LSB_REMAPPER_5" , 0x028A},
+ {"PID_OLD_MSB_REMAPPER_5" , 0x028B},
+ {"PID_OLD_LSB_REMAPPER_6" , 0x028C},
+ {"PID_OLD_MSB_REMAPPER_6" , 0x028D},
+ {"PID_OLD_LSB_REMAPPER_7" , 0x028E},
+ {"PID_OLD_MSB_REMAPPER_7" , 0x028F},
+ {"PID_NEW_LSB_REMAPPER_0" , 0x02A0},
+ {"PID_NEW_MSB_REMAPPER_0" , 0x02A1},
+ {"PID_NEW_LSB_REMAPPER_1" , 0x02A2},
+ {"PID_NEW_MSB_REMAPPER_1" , 0x02A3},
+ {"PID_NEW_LSB_REMAPPER_2" , 0x02A4},
+ {"PID_NEW_MSB_REMAPPER_2" , 0x02A5},
+ {"PID_NEW_LSB_REMAPPER_3" , 0x02A6},
+ {"PID_NEW_MSB_REMAPPER_3" , 0x02A7},
+ {"PID_NEW_LSB_REMAPPER_4" , 0x02A8},
+ {"PID_NEW_MSB_REMAPPER_4" , 0x02A9},
+ {"PID_NEW_LSB_REMAPPER_5" , 0x02AA},
+ {"PID_NEW_MSB_REMAPPER_5" , 0x02AB},
+ {"PID_NEW_LSB_REMAPPER_6" , 0x02AC},
+ {"PID_NEW_MSB_REMAPPER_6" , 0x02AD},
+ {"PID_NEW_LSB_REMAPPER_7" , 0x02AE},
+ {"PID_NEW_MSB_REMAPPER_7" , 0x02AF},
+ {"MERGER_DIV_MICLK" , 0x02C0},
+ {"PID_AND_SYNC_REMAPPER_CTRL" , 0x02C1},
+ {"PID_EN_REMAPPER" , 0x02C2},
+ {"SYNC_SYMBOL" , 0x02C3},
+ {"PID_AND_SYNC_REMAPPER_INV_CTRL" , 0x02C4},
+ {"BITRATE_CH0_LSB" , 0x02C5},
+ {"BITRATE_CH0_MSB" , 0x02C6},
+ {"BITRATE_CH1_LSB" , 0x02C7},
+ {"BITRATE_CH1_MSB" , 0x02C8},
+ {"STATUS_CLK_SWITCH_0" , 0x02C9},
+ {"STATUS_CLK_SWITCH_1" , 0x02CA},
+ {"RESET_CLK_SWITCH_0" , 0x02CB},
+ {"RESET_CLK_SWITCH_1" , 0x02CC},
+ {"PAD_DRVSTR_CTRL" , 0x02CD},
+ {"PAD_PUPD_CTRL" , 0x02CE},
+ {"PRE_HEADER_ADDER_CH0_0" , 0x02D0},
+ {"PRE_HEADER_ADDER_CH0_1" , 0x02D1},
+ {"PRE_HEADER_ADDER_CH0_2" , 0x02D2},
+ {"PRE_HEADER_ADDER_CH0_3" , 0x02D3},
+ {"PRE_HEADER_ADDER_CH0_4" , 0x02D4},
+ {"PRE_HEADER_ADDER_CH0_5" , 0x02D5},
+ {"PRE_HEADER_ADDER_CH0_6" , 0x02D6},
+ {"PRE_HEADER_ADDER_CH0_7" , 0x02D7},
+ {"PRE_HEADER_ADDER_CH0_8" , 0x02D8},
+ {"PRE_HEADER_ADDER_CH0_9" , 0x02D9},
+ {"PRE_HEADER_ADDER_CH0_10" , 0x02DA},
+ {"PRE_HEADER_ADDER_CH0_11" , 0x02DB},
+ {"PRE_HEADER_ADDER_CH1_0" , 0x02E0},
+ {"PRE_HEADER_ADDER_CH1_1" , 0x02E1},
+ {"PRE_HEADER_ADDER_CH1_2" , 0x02E2},
+ {"PRE_HEADER_ADDER_CH1_3" , 0x02E3},
+ {"PRE_HEADER_ADDER_CH1_4" , 0x02E4},
+ {"PRE_HEADER_ADDER_CH1_5" , 0x02E5},
+ {"PRE_HEADER_ADDER_CH1_6" , 0x02E6},
+ {"PRE_HEADER_ADDER_CH1_7" , 0x02E7},
+ {"PRE_HEADER_ADDER_CH1_8" , 0x02E8},
+ {"PRE_HEADER_ADDER_CH1_9" , 0x02E9},
+ {"PRE_HEADER_ADDER_CH1_10" , 0x02EA},
+ {"PRE_HEADER_ADDER_CH1_11" , 0x02EB},
+ {"PRE_HEADER_ADDER_CTRL" , 0x02EC},
+ {"PRE_HEADER_ADDER_LEN" , 0x02ED},
+ {"PRE_HEADER_REMOVER_CTRL" , 0x02EE},
+ {"FSM_DVB" , 0x02F0},
+ {"TS2USB_FSM_DEBUG" , 0x02F2},
+ {"TSOUT_PAR_FSM_DEBUG" , 0x02F3},
+ {"GAP_REMOVER_FSM_DEBUG" , 0x02F4},
+ {"PID_AND_SYNC_REMAPPER_FSM_DEBUG" , 0x02F5},
+ {"PRE_HEADER_ADDER_FSM_DEBUG" , 0x02F6},
+ {"SYNC_RTV_FSM_DEBUG" , 0x02F7},
+ {"CHECK_PHY_CLK" , 0x0E00},
+ {"CONTROL1" , 0x0E01},
+ {"WAKE_UP" , 0x0E02},
+ {"CONTROL2" , 0x0E03},
+ {"PHY_RELATED" , 0x0E04},
+ {"EP_CFG" , 0x0E05},
+ {"MAX_PKT_EP1L" , 0x0E06},
+ {"MAX_PKT_EP1H" , 0x0E07},
+ {"MAX_PKT_EP2L" , 0x0E08},
+ {"MAX_PKT_EP2H" , 0x0E09},
+ {"MAX_PKT_EP3L" , 0x0E0A},
+ {"MAX_PKT_EP3H" , 0x0E0B},
+ {"MAX_PKT_EP4L" , 0x0E0C},
+ {"MAX_PKT_EP4H" , 0x0E0D},
+ {"EPS_STALL_SET" , 0x0E10},
+ {"EPS_STALL_CLR" , 0x0E11},
+ {"EPS_ENABLE" , 0x0E12},
+ {"DMA_ACC_EPS" , 0x0E13},
+ {"CPU_ACC_EPS_EN" , 0x0E14},
+ {"SETUP_BYTE0" , 0x0E15},
+ {"SETUP_BYTE1" , 0x0E16},
+ {"SETUP_BYTE2" , 0x0E17},
+ {"SETUP_BYTE3" , 0x0E18},
+ {"SETUP_BYTE4" , 0x0E19},
+ {"SETUP_BYTE5" , 0x0E1A},
+ {"SETUP_BYTE6" , 0x0E1B},
+ {"SETUP_BYTE7" , 0x0E1C},
+ {"SETUP_DT_VLD" , 0x0E1D},
+ {"CLR_EPS_TOG" , 0x0E1E},
+ {"EP0_CTRL" , 0x0E20},
+ {"EP0_DATA_CNT" , 0x0E21},
+ {"EP0_DATA" , 0x0E22},
+ {"EP1_CTRL" , 0x0E30},
+ {"EP1_DATA_CNTL" , 0x0E31},
+ {"EP1_DATA_CNTH" , 0x0E32},
+ {"EP1_DATA" , 0x0E33},
+ {"EP1_HEADER" , 0x0E34},
+ {"EP2_CTRL" , 0x0E40},
+ {"EP2_DATA_CNTL" , 0x0E41},
+ {"EP2_DATA_CNTH" , 0x0E42},
+ {"EP2_DATA" , 0x0E43},
+ {"EP2_HEADER" , 0x0E44},
+ {"EP3_DATA_CNTL" , 0x0E50},
+ {"EP3_DATA_CNTH" , 0x0E51},
+ {"EP3_DATA" , 0x0E52},
+ {"EP3_HEADER" , 0x0E53},
+ {"EP3_HEADER_CNT" , 0x0E54},
+ {"EP3_HEADER_DATA" , 0x0E55},
+ {"EP4_DATA_CNTL" , 0x0E60},
+ {"EP4_DATA_CNTH" , 0x0E61},
+ {"EP4_DATA" , 0x0E62},
+ {"EP4_HEADER" , 0x0E63},
+ {"EP4_HEADER_CNT" , 0x0E64},
+ {"EP4_HEADER_DATA" , 0x0E65},
+ {"EP5_CTRL" , 0x0E70},
+ {"EP5_DATA_CNTL" , 0x0E71},
+ {"EP5_DATA_CNTH" , 0x0E72},
+ {"EP5_DATA" , 0x0E73},
+ {"MAX_PKT_EP5L" , 0x0E74},
+ {"MAX_PKT_EP5H" , 0x0E75},
+ {"EP6_DATA_CNTL" , 0x0E80},
+ {"EP6_DATA_CNTH" , 0x0E81},
+ {"EP6_DATA" , 0x0E82},
+ {"MAX_PKT_EP6L" , 0x0E83},
+ {"MAX_PKT_EP6H" , 0x0E84},
+ {"FRAME_NUML" , 0x0E90},
+ {"FRAME_NUMH" , 0x0E91},
+ {"FRAME_TIMEL" , 0x0E92},
+ {"FRAME_TIMEH" , 0x0E93},
+ {"STC_DIVL" , 0x0E94},
+ {"STC_DIVM" , 0x0E95},
+ {"STC_DIVH" , 0x0E96},
+ {"USB_STATUS" , 0x0E97},
+ {"DEV_STATE1" , 0x0E98},
+ {"DEV_STATE2" , 0x0E99},
+ {"DEV_STATE3" , 0x0E9A},
+ {"DEV_STATE4" , 0x0E9B},
+ {"INTR_EN1" , 0x0EA0},
+ {"INTR_EN2" , 0x0EA1},
+ {"INTR_EN3" , 0x0EA2},
+ {"INTR_EN4" , 0x0EA3},
+ {"INTR_SRC1" , 0x0EB0},
+ {"INTR_SRC2" , 0x0EB1},
+ {"INTR_SRC3" , 0x0EB2},
+ {"INTR_SRC4" , 0x0EB3},
+ {"INTR_FLAG1" , 0x0EC0},
+ {"INTR_FLAG2" , 0x0EC1},
+ {"INTR_FLAG3" , 0x0EC2},
+ {"INTR_FLAG4" , 0x0EC3},
+ {"EP0_INAK_CNT" , 0x0ED0},
+ {"EP0_ONAK_CNT" , 0x0ED1},
+ {"EP1_NAK_CNT" , 0x0ED2},
+ {"EP2_NAK_CNT" , 0x0ED3},
+ {"EP3_NAK_CNT" , 0x0ED4},
+ {"EP4_NAK_CNT" , 0x0ED5},
+ {"EP5_NAK_CNT" , 0x0ED6},
+ {"EP6_NAK_CNT" , 0x0ED7},
+ {"NAK_CNT_LEVEL" , 0x0ED8},
+ {"CC2_Buffer_out" , 0x2000},
+ {"CC2_Buffer_in" , 0x4000},
+ {"nmb_vector_address_lsb" , 0xFFFA},
+ {"nmb_vector_address_msb" , 0xFFFB},
+ {"reset_vector_address_lsb" , 0xFFFC},
+ {"reset_vector_address_msb" , 0xFFFD},
+ {"irb_vector_address_lsb" , 0xFFFE},
+ {"irb_vector_address_msb" , 0xFFFF}
+};
+#endif
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb-driver.c b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb-driver.c
new file mode 100644
index 0000000..a941326
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb-driver.c
@@ -0,0 +1,2536 @@
+/**************************************************************************//**
+ * @file cimax+usb-driver.c
+ *
+ * @brief CIMaX+ USB Driver for linux based operating systems.
+ *
+ * Copyright (C) 2009-2011 Bruno Tonelli <bruno.tonelli@smardtv.com>
+ * & Franck Descours <franck.descours@smardtv.com>
+ * for SmarDTV France, La Ciotat
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ ******************************************************************************/
+
+#define FRBIT
+/*#define DEBUG*/
+/*#define DEBUG_BITRATE*/
+/*#define DEBUG_ISOC_IN*/
+/*#define DEBUG_ISOC_OUT*/
+/*#define DEBUG_CONTINUITY*/
+
+/******************************************************************************
+ * Include
+ ******************************************************************************/
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/usb.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
+#include <linux/dvb/ca.h>
+
+#include "cimax+usb-driver.h"
+#include "cimax+usb_fw.h"
+#include "cimax+usb_config.h"
+#ifdef TIMESTAMP
+#include "cimax+usb_time.h"
+#endif
+#include "../../aml_cimax_usb_priv.h"
+
+/******************************************************************************
+ * Defines
+ *****************************************************************************/
+#define DRIVER_VERSION "v1.1.2"
+#define DRIVER_AUTHOR "Bruno Tonelli, tonelli@smardtv.com"
+#define DRIVER_DESC "CIMaX+ USB Driver for Linux (c)2009-2011"
+
+#define DRIVER_MAX_NUMBER 1
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
+
+/******************************************************************************
+ * Structures
+ ******************************************************************************/
+/******************************************************************************
+ * Globals
+ ******************************************************************************/
+#ifdef FRBIT
+int CimaxCfg = 1;
+module_param_named(CimaxCfg, CimaxCfg, int, 0644);
+MODULE_PARM_DESC(CimaxCfg, "Turn on/off configuration of CIMaX+ (default: on)");
+int CimaxDwnl = 1;
+module_param_named(CimaxDwnl, CimaxDwnl, int, 0644);
+MODULE_PARM_DESC(CimaxDwnl, "Enable upload of FW in CIMaX+ chip (default: on)");
+#endif
+
+static struct device_s *gdevice;
+static unsigned int gdeviceNumber;
+
+static struct usb_driver device_driver;
+static struct timespec gStart;
+
+static __u8 nullHeader[] = {
+ 0x47, 0x1F, 0xFF, 0x1F, 0xFA, 0xDE, 0xBA, 0xBE
+};
+
+static struct bulk_timer_s gbulk_timer[DEVICE_NUM_CAM];
+int (*cimax_usb_dev_add)(struct device_s *device, int id);
+int (*cimax_usb_dev_remove)(struct device_s *device, int id);
+
+#ifdef TIMESTAMP
+static int bSetTimestamps;
+#endif
+
+/******************************************************************************
+ * Functions
+ ******************************************************************************/
+#ifdef DEBUG_CONTINUITY
+#define TS_MAXPIDS 8192 /* max value of a PID */
+unsigned char tab_cc[TS_MAXPIDS];
+
+__u16 get_ts_pid(unsigned char *pid)
+{
+ __u16 pp = 0;
+
+ pp = (pid[0] & 0X1f)<<8;
+ pp |= pid[1];
+
+ return pp;
+}
+
+static void init_tab_cc(void)
+{
+ memset(tab_cc, 0xff, TS_MAXPIDS);
+}
+
+static int dbg_cc(unsigned char *buf)
+{
+ int pid;
+ unsigned char cc;
+
+ if (buf[0] != DEVICE_MPEG2_SYNC_BYTE) {
+ err("Out Of Sync: ");
+ return -1;
+ }
+
+ pid = get_ts_pid(buf + 1);
+
+ if (!(buf[3] & 0x10)) /* no payload?*/
+ return 0;
+
+ if (buf[1] & 0x80)
+ err("Error in TS for PID: %d\n", pid);
+
+ /* Check continuity count*/
+ cc = tab_cc[pid];
+ if (cc == 255)
+ cc = (buf[3] & 15);
+ else {
+ cc = ((cc) + 1) & 15;
+ if (cc != (buf[3] & 15)) {
+ /* Otherwise, this is a real corruption */
+ err("pid %d cc %d expected cc %d actual\n",
+ pid, cc, buf[3] & 15);
+ cc = (buf[3] & 15);
+ }
+ }
+ return 0;
+}
+#endif
+
+/*-------------------------------------------------------------------*/
+#ifdef DEBUG
+static void dbg_dump(char *hdr, unsigned char *data, int size)
+{
+ int i;
+ char line[40];
+ char str[9];
+ line[0] = 0;
+ for (i = 0; i < size; i++) {
+ sprintf(line, "%s%.2x ", line, data[i]);
+ if ((data[i] >= 32) && (data[i] <= 126))
+ str[i%8] = data[i];
+ else
+ str[i%8] = '.';
+ if (!((i+1)%8)) {
+ str[i%8 + 1] = 0;
+ dbg_s("%s %s %s", hdr, line, str);
+ line[0] = 0;
+ } /* if */
+ } /* for */
+ if (i%8) {
+ int j;
+ str[i%8 + 1] = 0;
+ for (j = (i%8); j < 8; j++)
+ sprintf(line, "%s ", line);
+ dbg_s("%s %s %s", hdr, line, str);
+ line[0] = 0;
+ } /* if */
+} /* dbg_dump */
+#else
+#define dbg_dump(format, arg...) do {} while (0)
+#endif /* DEBUG */
+
+static unsigned long copyDataFrom(int us,
+ void *to, const void *from, unsigned long n)
+{
+ if (us)
+ return copy_from_user(to, from, n);
+ memcpy(to, from, n);
+ return 0;
+}
+
+static unsigned long copyDataTo(int us,
+ void *to, const void *from, unsigned long n)
+{
+ if (us)
+ return copy_to_user(to, from, n);
+ memcpy(to, from, n);
+ return 0;
+}
+
+static void vb_init(struct video_buf_s *buf)
+{
+ buf->readOffset = 0;
+ buf->writeOffset = 0;
+ buf->isEmpty = 1;
+} /* vb_init */
+
+static int vb_get_write_size(struct video_buf_s *buf)
+{
+ int writeSize = 0;
+
+ if (buf->writeOffset == buf->readOffset) {
+ if (buf->isEmpty)
+ writeSize = DEVICE_VB_LENGTH;
+ } else if (buf->writeOffset > buf->readOffset)
+ writeSize =
+ DEVICE_VB_LENGTH - (buf->writeOffset - buf->readOffset);
+ else
+ writeSize = buf->readOffset - buf->writeOffset;
+ return writeSize;
+} /* vb_get_write_size */
+
+static int vb_write(struct video_buf_s *buf, __u8 *data, int size)
+{
+ int writeSize = vb_get_write_size(buf);
+ int firstPart = DEVICE_VB_LENGTH - buf->writeOffset;
+ if (size > writeSize)
+ size = writeSize;
+
+ if (size < firstPart) {
+ memcpy(&buf->data[buf->writeOffset], data, size);
+ buf->writeOffset += size;
+ } /* if */ else {
+ memcpy(&buf->data[buf->writeOffset], data, firstPart);
+ memcpy(buf->data, &data[firstPart], size - firstPart);
+ buf->writeOffset = size - firstPart;
+ } /* else */
+
+ if (size > 0)
+ buf->isEmpty = 0;
+ return size;
+} /* vb_write */
+
+static int vb_read_next(struct video_buf_s *buf, __u8 *data)
+{
+ int readSize;
+ int firstPart;
+ int nextOffset;
+ int isStuffing;
+ int ret;
+
+ readSize = DEVICE_VB_LENGTH - vb_get_write_size(buf);
+ nextOffset = buf->readOffset + DEVICE_MPEG2_PACKET_SIZE;
+ if (nextOffset >= DEVICE_VB_LENGTH)
+ nextOffset -= DEVICE_VB_LENGTH;
+ while (readSize > DEVICE_MPEG2_PACKET_SIZE) {
+ if ((buf->data[buf->readOffset] == DEVICE_MPEG2_SYNC_BYTE) &&
+ (buf->data[nextOffset] == DEVICE_MPEG2_SYNC_BYTE)) {
+ /* packet in sync */
+ break;
+ } /* if */
+ buf->readOffset++;
+ if (buf->readOffset == DEVICE_VB_LENGTH)
+ buf->readOffset = 0;
+ nextOffset++;
+ if (nextOffset == DEVICE_VB_LENGTH)
+ nextOffset = 0;
+ readSize--;
+ } /* while */
+ if (readSize <= DEVICE_MPEG2_PACKET_SIZE) {
+ buf->isEmpty = 1;
+ return 0;
+ } /* if */
+
+ /* packet is in sync, check if it is a stuffing packet */
+ isStuffing = 0;
+ firstPart = DEVICE_VB_LENGTH - buf->readOffset;
+ if (firstPart < DEVICE_NULL_HEADER_SIZE) {
+ if ((memcmp(nullHeader, &buf->data[buf->readOffset], firstPart)
+ == 0) &&
+ (memcmp(&nullHeader[firstPart], buf->data,
+ DEVICE_NULL_HEADER_SIZE - firstPart)
+ == 0)) {
+ isStuffing = 1;
+ } /* if */
+ } /* if */
+ else {
+ if (memcmp(nullHeader, &buf->data[buf->readOffset],
+ DEVICE_NULL_HEADER_SIZE) == 0) {
+ isStuffing = 1;
+ } /* if */
+ } /* else */
+ readSize -= DEVICE_MPEG2_PACKET_SIZE;
+ if (readSize <= DEVICE_MPEG2_PACKET_SIZE)
+ buf->isEmpty = 1;
+
+ /* skip stuffing packet */
+ if (isStuffing) {
+ buf->readOffset = nextOffset;
+ return 0;
+ } /* if */
+
+ /* copy packet to user space */
+ if (firstPart >= DEVICE_MPEG2_PACKET_SIZE) {
+ ret = copy_to_user(data,
+ &buf->data[buf->readOffset], DEVICE_MPEG2_PACKET_SIZE);
+ } /* if */ else {
+ ret = copy_to_user(data,
+ &buf->data[buf->readOffset], firstPart);
+ ret = copy_to_user(&data[firstPart],
+ buf->data, DEVICE_MPEG2_PACKET_SIZE - firstPart);
+ } /* else */
+ buf->readOffset = nextOffset;
+ return DEVICE_MPEG2_PACKET_SIZE;
+} /* vb_read_next */
+
+/*-------------------------------------------------------------------*/
+#ifdef DEBUG_BITRATE
+static void print_bitrate(struct ts_channel_s *channel, __u8 channel_number)
+{
+ int readSize;
+ ktime_t currentTime;
+ int diffTime_us;
+ int bitrate;
+
+ currentTime = ktime_get_real();
+ if (!(channel->bitrateTime.tv64)) {
+ channel->bitrateTime = currentTime;
+ } else {
+ readSize = DEVICE_VB_LENGTH - vb_get_write_size(&channel->inVb);
+ dbg("%d bytes received\n", readSize);
+ diffTime_us = (int)(ktime_us_delta(currentTime,
+ channel->bitrateTime));
+ if (diffTime_us) {
+ bitrate = (int)((readSize * 8 * USEC_PER_SEC)
+ / diffTime_us);
+ }
+ channel->bitrateTime = currentTime;
+ dbg("received bitrate for channel[%d] = %dbps\n",
+ channel_number, bitrate);
+ }
+}
+#endif /* DEBUG_BITRATE */
+/*-------------------------------------------------------------------*/
+
+static void device_cibulk_complete(struct urb *urb)
+{
+ dbg("start");
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+ dbg("end");
+} /* device_cibulk_complete */
+
+static int device_cibulk_send(struct device_s *device,
+ struct ioctl_data_s *data,
+ int user_space)
+{
+ int res;
+ struct urb *urb;
+ int size;
+ int index = -1;
+ __u8 *ptr;
+ __u32 todo = data->txSize;
+ __u8 *userData = data->txData;
+
+ dbg("start");
+
+ do {
+ /* get a free bulk message */
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ err("alloc urb");
+ return -ENOMEM;
+ } /* if */
+ urb->dev = device->usbdev;
+
+ /* allocate bulk data */
+ size = device->ciBulk.outMaxPacketSize;
+ if (todo < size)
+ size = todo;
+ urb->transfer_buffer = kmalloc(size, GFP_KERNEL);
+ if (!urb->transfer_buffer) {
+ err("alloc transfer buffer");
+ usb_free_urb(urb);
+ return -ENOMEM;
+ } /* if */
+
+ /* copy data */
+ ptr = urb->transfer_buffer;
+ res = copyDataFrom(user_space, ptr, userData, size);
+
+#ifdef TIMESTAMP
+ if (bSetTimestamps) {
+ if (index == -1) {
+ SetTimestamp("urb %x, toSend %d, send %d",
+ urb, todo, size);
+ SetTimestamp("cmd 0x%02x", ptr[0]);
+ } else {
+ SetTimestamp("urb %x, toSend %d, send %d",
+ urb, todo, size);
+ }
+ }
+#endif
+
+ /* first packet, get index */
+ if (index == -1) {
+ if ((ptr[DEVICE_COMMAND_OFFSET] == DEVICE_CMD_INIT) ||
+ (ptr[DEVICE_COMMAND_OFFSET]
+ == DEVICE_CMD_WRITE_REG) ||
+ (ptr[DEVICE_COMMAND_OFFSET]
+ == DEVICE_CMD_READ_REG)) {
+ index = 0; /* register command, no module */
+ } else if (ptr[DEVICE_COMMAND_OFFSET]
+ & DEVICE_SEL_MASK) {
+ index = 1; /* module B */
+ } else {
+ index = 0; /* module A */
+ } /* else */
+ device->ciBulk.ciData[index].syncDataSize = 0;
+ device->ciBulk.ciData[index].syncSignal = 0;
+ } /* if */
+
+ /* submit bulk */
+ urb->pipe = usb_sndbulkpipe(device->usbdev,
+ DEVICE_BULK_OUT_PIPE);
+ urb->transfer_buffer_length = size;
+ urb->complete = device_cibulk_complete;
+ urb->context = NULL;
+ dbg_dump("txBuf", urb->transfer_buffer,
+ urb->transfer_buffer_length);
+ res = usb_submit_urb(urb, GFP_KERNEL);
+ if (res < 0) {
+ err("submit urb res = %d", res);
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+ return -ENOMEM;
+ } /* if */
+ todo -= size;
+ userData += size;
+ } while (todo);
+
+ device->ciBulk.ciData[index].bPendingSend = 1;
+ dbg("end");
+ return index;
+} /* device_cibulk_send */
+
+static void device_int_complete(struct urb *urb)
+{
+ unsigned long flags;
+ struct device_s *device = urb->context;
+ __u8 *dataToCopy;
+ int sizeToCopy, SizeReceived;
+ __u8 isFirstPacket = 0;
+ __u8 isLastPacket = 0;
+ __u8 index, i;
+ __u8 status;
+ struct message_node_s *message;
+
+ dbg("start");
+
+ if (urb->status) {
+ dbg("urb status %d, not submitted again", urb->status);
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+ for (i = 0; i < DEVICE_NUM_INT_IN_URBS; i++) {
+ if (device->ciBulk.intUrb[i] == urb)
+ device->ciBulk.intUrb[i] = NULL;
+ }
+ return;
+ } /* if */
+
+ spin_lock_irqsave(&device->ciBulk.intUrbLock, flags);
+ dbg("urb status %d, transfer_buffer_length %d actual_length %d",
+ urb->status,
+ urb->transfer_buffer_length,
+ urb->actual_length);
+ dataToCopy = urb->transfer_buffer;
+ SizeReceived = urb->actual_length;
+ dbg_dump("total rxBuf", dataToCopy, SizeReceived);
+
+
+ do {
+ if (device->ciBulk.intSizeToReceive == 0) {
+ if (!dataToCopy[DEVICE_STATUS_OFFSET] &&
+ !dataToCopy[DEVICE_LENGTH_MSB_OFFSET] &&
+ !dataToCopy[DEVICE_LENGTH_LSB_OFFSET] &&
+ !dataToCopy[DEVICE_COUNTER_OFFSET]){
+ dbg("no data receive");
+ memset(urb->transfer_buffer,
+ 0, urb->transfer_buffer_length);
+ usb_submit_urb(urb, GFP_ATOMIC);
+ return;
+ }
+ /* first packet, read header */
+ isFirstPacket = 1;
+ device->ciBulk.intCurrStatus =
+ dataToCopy[DEVICE_STATUS_OFFSET] &
+ DEVICE_CMD_MASK;
+ if (dataToCopy[DEVICE_STATUS_OFFSET]
+ & DEVICE_SEL_MASK) {
+ device->ciBulk.intCurrIndex = 1; /* module B */
+ } else {
+ device->ciBulk.intCurrIndex = 0; /* module A */
+ }
+ if ((device->ciBulk.intCurrStatus == DEVICE_READ_REGOK)
+ || (device->ciBulk.intCurrStatus
+ == DEVICE_WRITE_REGOK)) {
+ device->ciBulk.intSizeToReceive =
+ dataToCopy[DEVICE_LENGTH_LSB_OFFSET] +
+ DEVICE_DATA_OFFSET;
+ } else {
+ device->ciBulk.intSizeToReceive =
+ dataToCopy[DEVICE_LENGTH_MSB_OFFSET] * 256
+ + dataToCopy[DEVICE_LENGTH_LSB_OFFSET]
+ + DEVICE_DATA_OFFSET;
+ }
+ } /* if */
+
+ /* get last packet state */
+ status = device->ciBulk.intCurrStatus;
+ index = device->ciBulk.intCurrIndex;
+ sizeToCopy = device->ciBulk.intSizeToReceive;
+ if (sizeToCopy > urb->actual_length) {
+ /* limit size to received buffer size */
+ sizeToCopy = urb->actual_length;
+ } /* if */ else
+ isLastPacket = 1;
+ dbg_dump("rxBuf", dataToCopy, sizeToCopy);
+
+#ifndef FRBIT
+ if (status == DEVICE_DATAREADY) {
+ if (device->ciBulk.ciData[index].bPendingSend)
+ status = DEVICE_DATAREADY_SYNC;
+ }
+#endif
+
+#ifdef TIMESTAMP
+ if (device->ciBulk.intSizeToReceive > 2000)
+ bSetTimestamps = 1;
+ if (bSetTimestamps) {
+ SetTimestamp("urb %x,toReceive %d,received %d,toCopy%d",
+ urb,
+ device->ciBulk.intSizeToReceive,
+ SizeReceived,
+ sizeToCopy);
+ SetTimestamp("status 0x%02x, camIndex %d, isLast %d",
+ status, index, isLastPacket);
+ }
+#endif
+
+ switch (status) {
+ case DEVICE_INITOK:
+ case DEVICE_READ_REGOK:
+ case DEVICE_WRITE_REGOK:
+ index = 0;
+ case DEVICE_CAMRESETOK:
+ /*only for debug*/
+ if (!dataToCopy[DEVICE_STATUS_OFFSET] &&
+ !dataToCopy[DEVICE_LENGTH_MSB_OFFSET] &&
+ !dataToCopy[DEVICE_LENGTH_LSB_OFFSET] &&
+ !dataToCopy[DEVICE_COUNTER_OFFSET]){
+ break;
+ }
+ case DEVICE_CISOK:
+ case DEVICE_WRITECOROK:
+ case DEVICE_NEGOTIATEOK:
+ case DEVICE_WRITELPDUOK:
+ case DEVICE_WRITELPDUBUSY:
+ case DEVICE_READLPDUOK:
+ case DEVICE_WRITEEXTOK:
+ case DEVICE_READEXTOK:
+ case DEVICE_NO_CAM:
+ case DEVICE_NOK:
+ case DEVICE_MCARD_WRITEOK:
+ case DEVICE_CAMPARSE_ERROR:
+ case DEVICE_CMDPENDING:
+ case DEVICE_REGSTATUSOK:
+ case DEVICE_DATAREADY_SYNC:
+ /* copy partial message */
+ spin_lock_irqsave(&device->ciBulk.intLock,
+ flags);
+ memcpy(&device->ciBulk.ciData[index].
+ syncData[device->ciBulk.ciData[index].
+ syncDataSize],
+ dataToCopy, sizeToCopy);
+ device->ciBulk.intSizeToReceive -= sizeToCopy;
+ device->ciBulk.ciData[index].syncDataSize +=
+ sizeToCopy;
+ spin_unlock_irqrestore(&device->ciBulk.intLock,
+ flags);
+ dbg("copied %d bytes at offset %d", sizeToCopy,
+ device->ciBulk.ciData[index].
+ syncDataSize - sizeToCopy);
+
+ if (isLastPacket) {
+ /* last packet received, sync message */
+ device->ciBulk.ciData[index].syncSignal = 1;
+ wake_up_interruptible(&device->ciBulk.
+ ciData[index].syncWait);
+ device->ciBulk.ciData[index].bPendingSend = 0;
+ dbg("sync signal return %d %d ",
+ device->ciBulk.ciData[index].
+ syncDataSize, index);
+ } /* if */
+ break;
+ case DEVICE_CAMDET:
+ case DEVICE_DATAREADY:
+ case DEVICE_MCARD_READ:
+ case DEVICE_FRBit:
+ if (isFirstPacket) {
+ /* create new async message */
+ message = kmalloc(sizeof(struct message_node_s),
+ GFP_ATOMIC);
+ if (!message) {
+ err("cannot allocate async message");
+ break;
+ }
+ memset(message,
+ 0, sizeof(struct message_node_s));
+ list_add_tail(&message->node,
+ &device->ciBulk.ciData[index].
+ asyncDataList);
+ } /* if */
+ else {
+ /* get tail message */
+ message = list_entry((device->ciBulk.
+ ciData[index].asyncDataList.prev),
+ struct message_node_s, node);
+ } /* else */
+
+ /* copy partial message */
+ spin_lock_irqsave(&device->ciBulk.intLock, flags);
+ memcpy(&message->data[message->size],
+ dataToCopy, sizeToCopy);
+ device->ciBulk.intSizeToReceive -= sizeToCopy;
+ message->size += sizeToCopy;
+ spin_unlock_irqrestore(&device->ciBulk.intLock, flags);
+ dbg("async copied %d bytes at offset %d", sizeToCopy,
+ message->size - sizeToCopy);
+
+ if (isLastPacket) {
+ /* last packet received, signal async message */
+ wake_up_interruptible(&device->ciBulk.
+ ciData[index].asyncWait);
+ dbg("async signal %d", index);
+ } /* if */
+ break;
+ case DEVICE_GPIOCHANGE:
+ info("GPIO change %x %x %x",
+ status, dataToCopy[4], dataToCopy[5]);
+ device->ciBulk.intSizeToReceive -= sizeToCopy;
+ break;
+ default:
+ err("unknown status 0x%2x", status);
+ break;
+ } /* switch */
+ dataToCopy += sizeToCopy;
+ SizeReceived -= sizeToCopy;
+
+ } while (SizeReceived > 0);
+
+ memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
+ usb_submit_urb(urb, GFP_ATOMIC);
+
+#ifdef TIMESTAMP
+ /*if (bSetTimestamps) {
+ SetTimestamp("urb %x submitted", urb);
+ }*/
+#endif
+
+ spin_unlock_irqrestore(&device->ciBulk.intUrbLock, flags);
+
+ dbg("end");
+} /* device_int_complete */
+
+static int device_wait_sync_data(struct device_s *device,
+ __u8 index,
+ struct ioctl_data_s *data,
+ int user_space)
+{
+ unsigned long flags;
+ int ret;
+
+ dbg("start %d", index);
+
+ spin_lock_irqsave(&device->ciBulk.intLock, flags);
+ while (device->ciBulk.ciData[index].syncSignal == 0) {
+ /* nothing to copy */
+ spin_unlock_irqrestore(&device->ciBulk.intLock, flags);
+ if (wait_event_interruptible(device->ciBulk.
+ ciData[index].syncWait,
+ device->ciBulk.ciData[index].syncSignal)) {
+ device->ciBulk.ciData[index].bPendingSend = 0;
+ err("interrupt");
+ return -ERESTARTSYS;
+ /* signal: tell the fs layer to handle it */
+ } /* if */
+ /* otherwise loop, but first reacquire the lock */
+ spin_lock_irqsave(&device->ciBulk.intLock, flags);
+ } /* while */
+
+ /* copy packet to user space buffer */
+ if (device->ciBulk.ciData[index].syncDataSize < data->rxSize)
+ /* truncate returned message against user buffer size */
+ data->rxSize = device->ciBulk.ciData[index].syncDataSize;
+ spin_unlock_irqrestore(&device->ciBulk.intLock, flags);
+ /* release the lock */
+ ret = copyDataTo(user_space,
+ data->rxData,
+ device->ciBulk.ciData[index].syncData, data->rxSize);
+ dbg_dump("userMsg",
+ device->ciBulk.ciData[index].syncData, data->rxSize);
+ dbg("userRet %d", data->rxSize);
+ device->ciBulk.ciData[index].syncDataSize = 0;
+ device->ciBulk.ciData[index].syncSignal = 0;
+
+ dbg("end");
+ return 0;
+} /* device_wait_sync_data */
+
+static int device_wait_async_data(struct device_s *device,
+ __u8 index,
+ struct rw_data_s *data,
+ int user_space)
+{
+ struct list_head *item;
+ struct message_node_s *message;
+ unsigned long flags;
+ int ret;
+
+ dbg("start %d", index);
+
+ if ((device->askToRelease) || (device->askToSuspend)) {
+ err("ask to release or ask to suspend");
+ return -EINTR; /* device close interrupt */
+ } /* if */
+
+ if (index >= DEVICE_NUM_CAM) {
+ err("bad index(%d)", index);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&device->ciBulk.intLock, flags);
+ while (list_empty(&device->ciBulk.ciData[index].asyncDataList)) {
+ /* nothing to copy */
+ spin_unlock_irqrestore(&device->ciBulk.intLock, flags);
+ /* release the lock */
+ if (wait_event_interruptible(device->ciBulk.
+ ciData[index].asyncWait,
+ device->askToRelease ||
+ device->askToSuspend ||
+ (!list_empty(&device->ciBulk.
+ ciData[index].asyncDataList)))) {
+ err("interrupt");
+ return -ERESTARTSYS;
+ /* signal: tell the fs layer to handle it */
+ } /* if */
+ if ((device->askToRelease) || (device->askToSuspend)) {
+ err("ask to release or ask to suspend");
+ return -EINTR; /* device close interrupt */
+ } /* if */
+ /* otherwise loop, but first reacquire the lock */
+ spin_lock_irqsave(&device->ciBulk.intLock, flags);
+ } /* while */
+
+ /* ok, data is there, return first item */
+ item = device->ciBulk.ciData[index].asyncDataList.next;
+ message = list_entry(item, struct message_node_s, node);
+ if (message->size < data->size) {
+ /* truncate returned message against user buffer size */
+ data->size = message->size;
+ } /* if */
+ spin_unlock_irqrestore(&device->ciBulk.intLock, flags);
+ /* release the lock */
+ ret = copyDataTo(user_space, data->data, message->data, data->size);
+ dbg_dump("userMsg", message->data, data->size);
+ dbg("userRet %d", data->size);
+ list_del(item);
+ kfree(message);
+
+ dbg("end");
+ return 0;
+} /* device_wait_async_data */
+
+static int device_start_intr(struct device_s *device)
+{
+ __u8 i, j;
+ struct urb *urb;
+
+ dbg("start");
+
+ for (i = 0; i < DEVICE_NUM_INT_IN_URBS; i++) {
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ err("alloc urb");
+ return -ENOMEM;
+ } /* if */
+ urb->transfer_buffer =
+ kmalloc(device->ciBulk.inMaxPacketSize, GFP_KERNEL);
+ if (!urb->transfer_buffer) {
+ err("alloc transfer buffer");
+ usb_free_urb(urb);
+ urb = NULL;
+ return -ENOMEM;
+ } /* if */
+
+ urb->dev = device->usbdev;
+ urb->pipe = usb_rcvintpipe(device->usbdev, DEVICE_INT_IN_PIPE);
+ urb->transfer_buffer_length = device->ciBulk.inMaxPacketSize;
+ urb->complete = device_int_complete;
+ urb->context = device;
+ urb->interval = 1;
+ device->ciBulk.intUrb[i] = urb;
+ for (j = 0; j < DEVICE_NUM_CAM; j++) {
+ init_waitqueue_head(&device->ciBulk.ciData[j].syncWait);
+ init_waitqueue_head(&device->ciBulk.
+ ciData[j].asyncWait);
+ } /* for */
+ usb_submit_urb(device->ciBulk.intUrb[i], GFP_KERNEL);
+ }
+
+ dbg("end");
+ return 0;
+} /* device_start_intr */
+
+static void device_stop_intr(struct device_s *device)
+{
+ struct list_head *item;
+ struct list_head *tmp;
+ struct message_node_s *message;
+ int i, j;
+
+ dbg("start");
+
+ for (i = 0; i < DEVICE_NUM_INT_IN_URBS; i++) {
+ if (!device->ciBulk.intUrb[i])
+ break;
+ usb_unlink_urb(device->ciBulk.intUrb[i]);
+ device->ciBulk.intUrb[i] = NULL;
+ for (j = 0; j < DEVICE_NUM_CAM; j++) {
+ for (item = device->ciBulk.ciData[j].asyncDataList.next;
+ item != &device->ciBulk.ciData[j].asyncDataList;
+ ) {
+ message = list_entry(item,
+ struct message_node_s, node);
+ tmp = item->next;
+ list_del(item);
+ kfree(item);
+ item = tmp;
+ } /* for */
+ } /* for */
+ dbg("unlink urb");
+ }
+
+ dbg("end");
+} /* device_stop_intr */
+
+static void device_iso_in_complete(struct urb *urb)
+{
+ unsigned long flags;
+ struct ts_channel_s *channel = urb->context;
+ __u8 i;
+ __u8 *data;
+
+ /*dbg("start");*/
+
+ if (urb->status) {
+ dbg("urb status %d, not submitted again", urb->status);
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+ return;
+ } /* if */
+
+ spin_lock_irqsave(&channel->inLock, flags);
+ for (i = 0; i < urb->number_of_packets; i++) {
+ data = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+ if (!urb->iso_frame_desc[i].status &&
+ (urb->iso_frame_desc[i].actual_length > 0)) {
+ if (vb_get_write_size(&channel->inVb)
+ >= urb->iso_frame_desc[i].actual_length) {
+ vb_write(&channel->inVb, data,
+ urb->iso_frame_desc[i].actual_length);
+ } /* if */
+ else {
+ err("video buffer is full, packet loss %d",
+ urb->iso_frame_desc[i].actual_length);
+ } /* else */
+ } /* if */
+ else {
+ err("frame rejected, status %x, actual_length %d bytes",
+ urb->iso_frame_desc[i].status,
+ urb->iso_frame_desc[i].actual_length);
+ }
+ } /* for */
+ spin_unlock_irqrestore(&channel->inLock, flags);
+
+ if (!channel->inVb.isEmpty)
+ wake_up_interruptible(&channel->inWait);
+
+ memset(urb->transfer_buffer,
+ 0, DEVICE_ISOC_LENGTH(channel->maxPacketSize));
+ urb->transfer_buffer_length =
+ DEVICE_ISOC_LENGTH(channel->maxPacketSize);
+ urb->number_of_packets = DEVICE_NUM_FRAMES_PER_URB;
+ urb->complete = device_iso_in_complete;
+ urb->context = channel;
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->interval = 1;
+ for (i = 0; i < DEVICE_NUM_FRAMES_PER_URB; i++) {
+ urb->iso_frame_desc[i].offset = i * channel->maxPacketSize;
+ urb->iso_frame_desc[i].length = channel->maxPacketSize;
+ } /* for */
+ usb_submit_urb(urb, GFP_ATOMIC);
+
+ /*dbg("end");*/
+} /* device_iso_in_complete */
+
+static void device_tsbulk_in_complete(struct urb *urb)
+{
+ unsigned long flags;
+ struct ts_channel_s *channel = urb->context;
+ __u8 *data;
+#ifdef DEBUG_CONTINUITY
+ unsigned int i;
+#endif
+
+ /*dbg("start");*/
+
+ if (urb->status) {
+ err("urb status %d(%x), not submitted again",
+ urb->status, urb->status);
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+ return;
+ } /* if */
+
+ spin_lock_irqsave(&channel->inLock, flags);
+ data = urb->transfer_buffer;
+
+#ifdef DEBUG_CONTINUITY
+ i = 0;
+ /* check synchro byte*/
+ while (i < urb->actual_length) {
+ if (!((data[i] == DEVICE_MPEG2_SYNC_BYTE) &&
+ (data[i+DEVICE_MPEG2_PACKET_SIZE]
+ == DEVICE_MPEG2_SYNC_BYTE))) {
+ i++;
+ } else {
+ /* Synchro find*/
+ break;
+ }
+ }
+
+ /* Synchro Ok, check discontinuity*/
+ while (i < urb->actual_length) {
+ if (dbg_cc(&data[i]) < 0) {
+ dbg("(actual_length= %d i=%d pkt=%d)",
+ urb->actual_length,
+ i,
+ i/DEVICE_MPEG2_PACKET_SIZE);
+ dbg("%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ data[i-4], data[i-3], data[i-2], data[i-1],
+ data[i], data[i+1], data[i+2], data[i+3]);
+ }
+ i += DEVICE_MPEG2_PACKET_SIZE;
+ }
+#endif
+
+ if (urb->actual_length) {
+ channel->nbByteRead += urb->actual_length;
+ if (vb_get_write_size(&channel->inVb) >= urb->actual_length)
+ vb_write(&channel->inVb, data, urb->actual_length);
+ else
+ err("video buffer is full, packet loss %d",
+ urb->actual_length);
+ } else {
+ /*warn("receive size of 0\n");*/
+ }
+
+ spin_unlock_irqrestore(&channel->inLock, flags);
+ /* dbg("urb->actual_length=%d",urb->actual_length);*/
+ /* info("urb->actual_length=%d\n",urb->actual_length);*/
+
+ if (!channel->inVb.isEmpty)
+ wake_up_interruptible(&channel->inWait);
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+ /*dbg("end");*/
+} /* device_tsbulk_in_complete */
+
+static int device_fill_ts(struct device_s *device,
+ __u8 index,
+ struct rw_data_s *data)
+{
+ unsigned long flags;
+ __u32 copiedSize;
+ struct ts_channel_s *channel = &device->channel[index];
+
+ /*dbg("start");*/
+
+ spin_lock_irqsave(&channel->inLock, flags);
+ do {
+ while (channel->inVb.isEmpty) {
+ /* nothing to copy */
+ spin_unlock_irqrestore(&channel->inLock, flags);
+ /* release the lock */
+ if (wait_event_interruptible(channel->inWait,
+ device->askToRelease ||
+ device->askToSuspend ||
+ (!channel->inVb.isEmpty))) {
+ err("interrupt");
+ return -ERESTARTSYS;
+ /* signal: tell the fs layer to handle it */
+ } /* if */
+ if ((device->askToRelease) || (device->askToSuspend)) {
+ err("ask to release or ask to suspend");
+ return -EINTR; /* device close interrupt */
+ } /* if */
+ /* otherwise loop, but first reacquire the lock */
+ spin_lock_irqsave(&channel->inLock, flags);
+ } /* while */
+
+ spin_unlock_irqrestore(&channel->inLock, flags);
+
+ copiedSize = vb_read_next(&channel->inVb,
+ &data->data[data->copiedSize]);
+ if (copiedSize) {
+ /*dbg("copied %d bytes in buffer 0x%p, offset %d",
+ copiedSize, data->data, data->copiedSize);*/
+ data->copiedSize += copiedSize;
+ } /* if */
+ spin_lock_irqsave(&channel->inLock, flags);
+ } while ((data->copiedSize+DEVICE_MPEG2_PACKET_SIZE) <= data->size);
+ /* buffer not full */
+
+ spin_unlock_irqrestore(&channel->inLock, flags);
+
+#ifdef DEBUG_BITRATE
+ print_bitrate(channel, index);
+#endif
+
+ /*dbg("end, buffer 0x%p", data->data);*/
+ return 0;
+} /* device_fill_ts */
+
+static int device_start_iso_in(struct device_s *device, __u8 index)
+{
+ int i, j;
+ int ret = 0;
+ struct urb *urb;
+
+ /*dbg("start");*/
+
+#ifdef DEBUG_BITRATE
+ device->channel[index].bitrateTime = ktime_set(0, 0);
+#endif
+ for (i = 0; i < DEVICE_NUM_ISOC_IN_URBS; i++) {
+ urb = usb_alloc_urb(DEVICE_NUM_FRAMES_PER_URB, GFP_KERNEL);
+ device->channel[index].isocInUrb[i] = urb;
+ if (urb) {
+ /*urb->transfer_buffer =
+ kmalloc(DEVICE_ISOC_LENGTH, GFP_KERNEL);*/
+ urb->transfer_buffer =
+ kmalloc(DEVICE_ISOC_LENGTH(
+ device->channel[index].maxPacketSize),
+ GFP_KERNEL);
+ if (!urb->transfer_buffer) {
+ ret = -ENOMEM;
+ err("transfer_buffer allocation failed %d", i);
+ break;
+ } /* if */
+ } /* if */ else {
+ ret = -ENOMEM;
+ err("usb_alloc_urb failed %d", i);
+ break;
+ } /* if */
+ } /* for */
+
+ if (ret) {
+ /* Allocation error, must free already allocated data */
+ for (i = 0; i < DEVICE_NUM_ISOC_IN_URBS; i++) {
+ urb = device->channel[index].isocInUrb[i];
+ if (urb) {
+ kfree(urb->transfer_buffer);
+ if (urb->transfer_buffer)
+ urb->transfer_buffer = NULL;
+ usb_free_urb(urb);
+ device->channel[index].isocInUrb[i] = NULL;
+ } /* if */
+ } /* for */
+ return ret;
+ } /* if */
+
+ for (i = 0; i < DEVICE_NUM_ISOC_IN_URBS; i++) {
+ urb = device->channel[index].isocInUrb[i];
+ memset(urb->transfer_buffer,
+ 0,
+ DEVICE_ISOC_LENGTH(
+ device->channel[index].maxPacketSize));
+ urb->transfer_buffer_length =
+ DEVICE_ISOC_LENGTH(
+ device->channel[index].maxPacketSize);
+ urb->number_of_packets = DEVICE_NUM_FRAMES_PER_URB;
+ urb->complete = device_iso_in_complete;
+ urb->context = &device->channel[index];
+ urb->dev = device->usbdev;
+ urb->pipe = usb_rcvisocpipe(
+ device->usbdev, DEVICE_TS_IN_PIPE + index);
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->interval = 1;
+ for (j = 0; j < DEVICE_NUM_FRAMES_PER_URB; j++) {
+ urb->iso_frame_desc[j].offset =
+ j * device->channel[index].maxPacketSize;
+ urb->iso_frame_desc[j].length =
+ device->channel[index].maxPacketSize;
+ } /* for */
+ } /* for */
+ for (i = 0; i < DEVICE_NUM_ISOC_IN_URBS; i++)
+ usb_submit_urb(device->channel[index].isocInUrb[i], GFP_KERNEL);
+
+ /*dbg("end");*/
+ return 0;
+} /* device_start_iso_in */
+
+static void device_stop_iso_in(struct device_s *device, __u8 index)
+{
+ int i;
+
+ /*dbg("start");*/
+
+ for (i = 0; i < DEVICE_NUM_ISOC_IN_URBS; i++) {
+ if (device->channel[index].isocInUrb[i]) {
+ usb_unlink_urb(device->channel[index].isocInUrb[i]);
+ device->channel[index].isocInUrb[i] = NULL;
+ dbg("unlink urb %i", i);
+ } /* if */
+ } /* for */
+
+ /*dbg("end");*/
+} /* device_stop_iso_in */
+
+static int device_start_tsbulk_in(struct device_s *device, __u8 index)
+{
+ struct urb *urb;
+
+ dbg("start");
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (urb) {
+ urb->transfer_buffer = kmalloc(3072, GFP_KERNEL);
+ if (!urb->transfer_buffer) {
+ err("transfer_buffer allocation failed");
+ usb_free_urb(urb);
+ return -ENOMEM;
+ } /* if */
+ } /* if */ else {
+ err("usb_alloc_urb failed");
+ return -ENOMEM;
+ } /* if */
+ device->channel[index].bulkInUrb = urb;
+ memset(urb->transfer_buffer, 0, 3072);
+ urb->transfer_buffer_length = 3072;
+
+ urb->complete = device_tsbulk_in_complete;
+ urb->context = &device->channel[index];
+ urb->dev = device->usbdev;
+ urb->pipe = usb_rcvbulkpipe(device->usbdev, DEVICE_TS_IN_PIPE + index);
+ usb_submit_urb(device->channel[index].bulkInUrb, GFP_KERNEL);
+
+ dbg("end");
+ return 0;
+} /* device_start_tsbulk_in */
+
+static void device_stop_tsbulk_in(struct device_s *device, __u8 index)
+{
+ dbg("start");
+
+ if (device->channel[index].bulkInUrb) {
+ usb_unlink_urb(device->channel[index].bulkInUrb);
+ device->channel[index].bulkInUrb = NULL;
+ dbg("unlink urb");
+ } /* if */
+
+ dbg("end");
+} /* device_stop_tsbulk_in */
+
+static void device_iso_out_complete(struct urb *urb)
+{
+ struct ts_channel_s *channel = urb->context;
+ struct urb *tmpUrb;
+ int i;
+ int ret = 0;
+
+ /*dbg("start");*/
+
+/*dbg_dump("txBuf", urb->transfer_buffer, urb->transfer_buffer_length);*/
+
+ if (urb->status || channel->outStop) {
+ /* error, free all coming urbs */
+ err("free urb");
+ channel->outStop = 1;
+ atomic_dec(&channel->numOutUrbs);
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+ return;
+ } /* if */
+
+ for (i = 0; i < DEVICE_NUM_ISOC_OUT_URBS; i++) {
+ if (urb == channel->isocOutUrb[i])
+ break;
+ } /* for */
+ if (i == DEVICE_NUM_ISOC_OUT_URBS) {
+ /* urb must be deleted */
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+ } /* if */
+
+ if (atomic_dec_and_test(&channel->numOutUrbs)) {
+ /* get next free urb */
+ tmpUrb = channel->isocOutUrb[channel->nextFreeOutUrbIndex++];
+ if (channel->nextFreeOutUrbIndex == DEVICE_NUM_ISOC_OUT_URBS)
+ channel->nextFreeOutUrbIndex = 0;
+
+ /* reinitialize urb with null packets */
+ memset(tmpUrb->transfer_buffer,
+ 0xCD, DEVICE_ISOC_LENGTH(channel->maxPacketSize));
+ for (i = 0;
+ i < DEVICE_ISOC_LENGTH(channel->maxPacketSize);
+ i += DEVICE_MPEG2_PACKET_SIZE) {
+ memcpy(tmpUrb->transfer_buffer+i,
+ nullHeader, sizeof(nullHeader));
+ } /* for */
+ tmpUrb->transfer_buffer_length =
+ DEVICE_ISOC_LENGTH(channel->maxPacketSize);
+ tmpUrb->number_of_packets = DEVICE_NUM_FRAMES_PER_URB;
+ tmpUrb->complete = device_iso_out_complete;
+ tmpUrb->context = channel;
+ tmpUrb->transfer_flags = URB_ISO_ASAP;
+ tmpUrb->interval = 1;
+ for (i = 0; i < DEVICE_NUM_FRAMES_PER_URB; i++) {
+ tmpUrb->iso_frame_desc[i].offset =
+ i * channel->maxPacketSize;
+ tmpUrb->iso_frame_desc[i].length =
+ channel->maxPacketSize;
+ } /* for */
+
+ /* submit urb */
+ ret = usb_submit_urb(tmpUrb, GFP_ATOMIC);
+ if (ret)
+ err("usb_submit_urb failed %d", ret);
+
+ atomic_inc(&channel->numOutUrbs);
+ } /* if */
+
+ /*dbg("end");*/
+} /* device_iso_out_complete */
+
+static int device_tsiso_send(struct device_s *device,
+ __u8 index, __u8 *data, int size)
+{
+ int i, j;
+ struct urb **urb;
+ __u32 numUrbs;
+ int ret = 0;
+
+ /* dbg("start");*/
+
+ numUrbs =
+ size / DEVICE_ISOC_LENGTH(device->channel[index].maxPacketSize);
+ urb = kmalloc(numUrbs * sizeof(struct urb *), GFP_KERNEL);
+ if (!urb) {
+ err("urb array allocation failed %d", numUrbs);
+ return -ENOMEM;
+
+ } /* if */
+ memset(urb, 0, numUrbs * sizeof(struct urb *));
+
+ for (i = 0; i < numUrbs; i++) {
+ urb[i] = usb_alloc_urb(DEVICE_NUM_FRAMES_PER_URB, GFP_KERNEL);
+ if (urb[i]) {
+ urb[i]->transfer_buffer =
+ kmalloc(DEVICE_ISOC_LENGTH(
+ device->channel[index].maxPacketSize),
+ GFP_KERNEL);
+ if (!urb[i]->transfer_buffer) {
+ ret = -ENOMEM;
+ err("transfer_buffer allocation failed %d", i);
+ break;
+ } /* if */
+ } /* if */
+ else {
+ ret = -ENOMEM;
+ err("usb_alloc_urb failed %d", i);
+ break;
+ } /* if */
+ } /* for */
+ if (ret) {
+ /* Allocation error, must free already allocated data */
+ for (i = 0; i < numUrbs; i++) {
+ if (urb[i]) {
+ kfree(urb[i]->transfer_buffer);
+ urb[i]->transfer_buffer = NULL;
+ usb_free_urb(urb[i]);
+ urb[i] = NULL;
+ } /* if */
+ } /* for */
+ kfree(urb);
+ return ret;
+ } /* if */
+
+ for (i = 0; i < numUrbs; i++) {
+ ret = copy_from_user(urb[i]->transfer_buffer,
+ &data[i*DEVICE_ISOC_LENGTH(
+ device->channel[index].maxPacketSize)],
+ DEVICE_ISOC_LENGTH(
+ device->channel[index].maxPacketSize));
+ urb[i]->transfer_buffer_length = DEVICE_ISOC_LENGTH(
+ device->channel[index].maxPacketSize);
+ urb[i]->number_of_packets = DEVICE_NUM_FRAMES_PER_URB;
+ urb[i]->complete = device_iso_out_complete;
+ urb[i]->context = &device->channel[index];
+ urb[i]->dev = device->usbdev;
+ urb[i]->pipe = usb_sndisocpipe(device->usbdev,
+ DEVICE_TS_OUT_PIPE + index);
+ urb[i]->transfer_flags = URB_ISO_ASAP;
+ urb[i]->interval = 1;
+ for (j = 0; j < DEVICE_NUM_FRAMES_PER_URB; j++) {
+ urb[i]->iso_frame_desc[j].offset =
+ j * device->channel[index].maxPacketSize;
+ urb[i]->iso_frame_desc[j].length =
+ device->channel[index].maxPacketSize;
+ } /* for */
+ } /* for */
+
+ atomic_add(numUrbs, &device->channel[index].numOutUrbs);
+ for (i = 0; i < numUrbs; i++) {
+ ret = usb_submit_urb(urb[i], GFP_ATOMIC);
+ if (ret)
+ err("usb_submit_urb failed %d", ret);
+ } /* for */
+
+ kfree(urb);
+
+ /* dbg("end");*/
+ return size;
+} /* device_tsiso_send */
+
+static int device_start_iso_out(struct device_s *device, __u8 index)
+{
+ int i, j;
+ int ret = 0;
+ struct urb *urb;
+
+ /*dbg("start");*/
+
+ device->channel[index].outStop = 0;
+ for (i = 0; i < DEVICE_NUM_ISOC_OUT_URBS; i++) {
+ urb = usb_alloc_urb(DEVICE_NUM_FRAMES_PER_URB, GFP_KERNEL);
+ device->channel[index].isocOutUrb[i] = urb;
+ if (urb) {
+ urb->transfer_buffer = kmalloc(DEVICE_ISOC_LENGTH(
+ device->channel[index].maxPacketSize),
+ GFP_KERNEL);
+ if (!urb->transfer_buffer) {
+ ret = -ENOMEM;
+ err("transfer_buffer allocation failed %d", i);
+ break;
+ } /* if */
+ } /* if */ else {
+ ret = -ENOMEM;
+ err("usb_alloc_urb failed %d", i);
+ break;
+ } /* if */
+ } /* for */
+
+ if (ret) {
+ /* Allocation error, must free already allocated data */
+ for (i = 0; i < DEVICE_NUM_ISOC_OUT_URBS; i++) {
+ urb = device->channel[index].isocOutUrb[i];
+ if (urb) {
+ kfree(urb->transfer_buffer);
+ urb->transfer_buffer = NULL;
+ usb_free_urb(urb);
+ device->channel[index].isocOutUrb[i] = NULL;
+ } /* if */
+ } /* for */
+ return ret;
+ } /* if */
+
+ for (i = 0; i < DEVICE_NUM_ISOC_OUT_URBS; i++) {
+ urb = device->channel[index].isocOutUrb[i];
+ memset(urb->transfer_buffer, 0, DEVICE_ISOC_LENGTH(
+ device->channel[index].maxPacketSize));
+ for (j = 0;
+ j < DEVICE_ISOC_LENGTH(
+ device->channel[index].maxPacketSize);
+ j += DEVICE_MPEG2_PACKET_SIZE) {
+ memcpy(urb->transfer_buffer+j,
+ nullHeader, sizeof(nullHeader));
+ } /* for */
+ urb->transfer_buffer_length = DEVICE_ISOC_LENGTH(
+ device->channel[index].maxPacketSize);
+ urb->number_of_packets = DEVICE_NUM_FRAMES_PER_URB;
+ urb->complete = device_iso_out_complete;
+ urb->context = &device->channel[index];
+ urb->dev = device->usbdev;
+ urb->pipe = usb_sndisocpipe(device->usbdev,
+ DEVICE_TS_OUT_PIPE + index);
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->interval = 1;
+ for (j = 0; j < DEVICE_NUM_FRAMES_PER_URB; j++) {
+ urb->iso_frame_desc[j].offset =
+ j * device->channel[index].maxPacketSize;
+ urb->iso_frame_desc[j].length =
+ device->channel[index].maxPacketSize;
+ } /* for */
+ } /* for */
+ device->channel[index].nextFreeOutUrbIndex = DEVICE_NUM_ISOC_OUT_URBS-1;
+ atomic_set(&device->channel[index].numOutUrbs, 1);
+ for (i = 0; i < DEVICE_NUM_ISOC_OUT_URBS-1; i++) {
+ ret = usb_submit_urb(
+ device->channel[index].isocOutUrb[i], GFP_KERNEL);
+ if (ret)
+ err("usb_submit_urb failed %d", ret);
+ } /* for */
+
+ /*dbg("end");*/
+ return 0;
+} /* device_start_iso_out */
+
+static void device_stop_iso_out(struct device_s *device, __u8 index)
+{
+ dbg("start");
+
+ device->channel[index].outStop = 1;
+
+ dbg("end");
+} /* device_stop_iso_out */
+
+static void device_tsbulk_complete(struct urb *urb)
+{
+ struct device_s *device = urb->context;
+ __u8 index = 0;
+
+ /*dbg("start");*/
+ if (!urb->status) {
+ if (usb_endpoint_num(&(urb->ep->desc)) != DEVICE_TS_OUT_PIPE)
+ index = 1;
+ device->channel[index].nbByteSend += urb->actual_length;
+ }
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+ /*dbg("end");*/
+} /* device_tsbulk_complete */
+
+static int device_tsbulk_send(struct device_s *device,
+ __u8 index, __u8 *data, int size)
+{
+ struct urb *urb;
+ /* int todo = size;*/
+ int ret = 0;
+
+ dbg("start");
+
+ /* get a free bulk message */
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ err("alloc urb");
+ return -ENOMEM;
+ } /* if */
+ urb->dev = device->usbdev;
+
+ /* allocate bulk data */
+ urb->transfer_buffer = kmalloc(size, GFP_KERNEL);
+ if (!urb->transfer_buffer) {
+ err("alloc transfer buffer");
+ usb_free_urb(urb);
+ return -ENOMEM;
+ } /* if */
+
+ /* copy data */
+ ret = copy_from_user(urb->transfer_buffer, data, size);
+
+ /* submit bulk */
+ urb->pipe = usb_sndbulkpipe(device->usbdev, DEVICE_TS_OUT_PIPE + index);
+ urb->transfer_buffer_length = size;
+ urb->complete = device_tsbulk_complete;
+ urb->context = device;
+ /*dbg("Transmit %d bytes\n",urb->transfer_buffer_length);*/
+ /*dbg_dump("txBuf",
+ urb->transfer_buffer, urb->transfer_buffer_length);*/
+ mod_timer(&(device->channel[index].StartBulkReadTimer),
+ usecs_to_jiffies(50));
+
+ if (usb_submit_urb(urb, GFP_KERNEL) < 0) {
+ err("submit urb");
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+ return -ENOMEM;
+ } /* if */
+
+ dbg("end");
+ return 0;
+} /* device_tsbulk_send */
+
+/* ---------------------------------------------------------- */
+static void StartBulkRead_func(unsigned long context)
+{
+ struct bulk_timer_s *bulk_time = (struct bulk_timer_s *) context;
+
+ device_start_tsbulk_in(bulk_time->device, bulk_time->index);
+}
+
+static int device_drv_open(struct device_s *device)
+{
+ int index;
+ mutex_lock(&device->lock);
+
+ if (!device->usbdev) {
+ err("no dev, can not start dev");
+ mutex_unlock(&device->lock);
+ return -ENODEV;
+ }
+
+ if (device->opened) {
+ mutex_unlock(&device->lock);
+ device->opened++;
+ info("udev=%p opened=%d", (device->usbdev), device->opened);
+ return 0;
+ } /* while */
+
+ info("set interface 0");
+ if (usb_set_interface(device->usbdev, 0, 0) < 0) {
+ mutex_unlock(&device->lock);
+ err("set_interface fail");
+ return -EINVAL;
+ } /* if */
+
+ device->opened++;
+ device->askToRelease = 0;
+ mutex_unlock(&device->lock);
+
+ for (index = 0; index < DEVICE_NUM_CAM; index++) {
+ device->channel[index].nbByteSend = -376;
+ device->channel[index].nbByteRead = 0;
+ device->channel[index].FirstTransfer = true;
+ gbulk_timer[index].device = device;
+ gbulk_timer[index].index = index;
+ setup_timer(&device->channel[index].StartBulkReadTimer,
+ StartBulkRead_func,
+ (unsigned long)&(gbulk_timer[index]));
+ }
+#ifdef DEBUG_CONTINUITY
+ init_tab_cc();
+#endif
+ info("udev=%p opened=%d", (device->usbdev), device->opened);
+ return 0;
+}
+
+static int device_ci_unlock_read(struct device_s *device)
+{
+ if (device->opened) {
+ /* release blocking functions */
+ device->askToRelease = 1;
+ wake_up_interruptible(&device->ciBulk.ciData[0].asyncWait);
+ wake_up_interruptible(&device->ciBulk.ciData[1].asyncWait);
+ wake_up_interruptible(&device->channel[0].inWait);
+ wake_up_interruptible(&device->channel[1].inWait);
+ }
+ return 0;
+}
+
+static int device_drv_close(struct device_s *device)
+{
+ int i;
+ mutex_lock(&device->lock);
+ if (device->opened && ((--device->opened) == 0)) {
+ device->askToRelease = 1;
+ device_stop_intr(device);
+ for (i = 0; i < DEVICE_NUM_CAM; i++) {
+ if (device->useIsoc) {
+ device_stop_iso_out(device, i);
+ device_stop_iso_in(device, i);
+ } else
+ device_stop_tsbulk_in(device, i);
+ } /* for */
+ device->opened = 0;
+ } /* if */
+ mutex_unlock(&device->lock);
+ return 0;
+}
+
+static int device_open(struct inode *inode, struct file *file)
+{
+ int devnum = iminor(inode);
+#ifdef DEBUG
+ int type = (MINOR(inode->i_rdev) >> 4);
+ int num = (MINOR(inode->i_rdev) & 0xf);
+#endif
+ int ret = 0;
+
+ struct device_s *device;
+
+ dbg("start, devnum = %d type = %d num = %d", devnum, type, num);
+
+ if (gdeviceNumber >= DRIVER_MAX_NUMBER) {
+ dbg("only support one device open");
+ return -EINVAL;
+ }
+ device = &gdevice[gdeviceNumber];
+ /*gdeviceNumber++;*/
+
+ ktime_get_ts(&gStart);
+
+ ret = device_drv_open(device);
+ if (ret < 0)
+ return ret;
+
+ file->f_pos = 0;
+ file->private_data = device;
+
+ dbg("end");
+ return nonseekable_open(inode, file);
+} /* device_open */
+
+static int device_release(struct inode *inode, struct file *file)
+{
+ struct device_s *device = (struct device_s *)file->private_data;
+
+ dbg("start");
+ device_drv_close(device);
+ dbg("end");
+ return 0;
+} /* device_release */
+
+int cimax_usb_select_interface(struct device_s *device, unsigned long intf)
+{
+ int max = 0;
+ int mult = 0;
+ int ret = 0;
+
+ info("set interface %ld", intf);
+ if (usb_set_interface(device->usbdev, 0, intf) < 0) {
+ err("set_interface failed interface 0, altSetting %ld", intf);
+ return -EINVAL;
+ } /* if */
+
+ /* check endpoints */
+ /* CI bulk out */
+ if (!usb_endpoint_is_bulk_out(
+ &device->usbdev->ep_out[DEVICE_BULK_OUT_PIPE]->desc)) {
+ err("unexpected endpoint %d", DEVICE_BULK_OUT_PIPE);
+ return -EINVAL;
+ } /* if */
+ device->ciBulk.outMaxPacketSize = DEVICE_BULK_OUT_MAXPACKET;
+ dbg("CI bulk out (endpoint %d), packet size %d", DEVICE_BULK_OUT_PIPE,
+ device->ciBulk.outMaxPacketSize);
+ /* CI int in */
+ if (!usb_endpoint_is_int_in(
+ &device->usbdev->ep_in[DEVICE_INT_IN_PIPE]->desc)) {
+ err("unexpected endpoint %d", DEVICE_INT_IN_PIPE);
+ return -EINVAL;
+ } /* if */
+ device->ciBulk.inMaxPacketSize =
+ device->usbdev->ep_in[DEVICE_INT_IN_PIPE]->desc.wMaxPacketSize;
+ dbg("CI int in (endpoint %d), packet size %d", DEVICE_INT_IN_PIPE,
+ device->ciBulk.inMaxPacketSize);
+ /* TS out */
+ if (device->usbdev->ep_out[DEVICE_TS_OUT_PIPE] == NULL)
+ dbg("no TS endpoint");
+ else {
+ if (usb_endpoint_is_bulk_out(
+ &device->usbdev->ep_out[DEVICE_TS_OUT_PIPE]->desc)) {
+ device->useIsoc = 0;
+ dbg("TS is configured as bulk");
+ } else if (usb_endpoint_is_isoc_out(
+ &device->usbdev->ep_out[DEVICE_TS_OUT_PIPE]->desc)) {
+ device->useIsoc = 1;
+ dbg("TS is configured as isochronous");
+ } else {
+ err("unexpected endpoint %d", DEVICE_TS_OUT_PIPE);
+ return -EINVAL;
+ } /* if */
+ max = device->usbdev->
+ ep_out[DEVICE_TS_OUT_PIPE]->desc.wMaxPacketSize;
+ mult = 1 + ((max >> 11) & 0x03);
+ max &= 0x7ff;
+ device->channel[0].maxPacketSize = max * mult;
+ dbg("TS out (endpoint %d), packet size %d", DEVICE_TS_OUT_PIPE,
+ device->channel[0].maxPacketSize);
+
+ max = device->usbdev->
+ ep_out[DEVICE_TS_OUT_PIPE+1]->desc.wMaxPacketSize;
+ mult = 1 + ((max >> 11) & 0x03);
+ max &= 0x7ff;
+ device->channel[1].maxPacketSize = max * mult;
+ dbg("TS out (endpoint %d), packet size %d",
+ DEVICE_TS_OUT_PIPE + 1,
+ device->channel[1].maxPacketSize);
+ }
+
+ /* start intr urb */
+ if (device->ciBulk.intUrb[0] == NULL) {
+ ret = device_start_intr(device);
+ if (ret < 0) {
+ err("cannot start int urb");
+ return ret;
+ } /* if */
+ } /* if */
+
+ return ret;
+}
+EXPORT_SYMBOL(cimax_usb_select_interface);
+
+static int device_ci_write(struct device_s *device,
+ struct ioctl_data_s *data, int isIoctl)
+{
+ int ret = 0;
+ if (!device)
+ return -ENODEV;
+ ret = device_cibulk_send(device, data, isIoctl);
+ if (ret < 0)
+ return ret;
+ return device_wait_sync_data(device, ret, data, isIoctl);
+}
+
+static int device_ci_write_ioctl(struct device_s *device,
+ struct ioctl_data_s *data)
+{
+ return device_ci_write(device, data, 1);
+}
+
+int cimax_usb_ci_write(struct device_s *device,
+ u8 *txData, int txSize, u8 *rxData, int rxSize)
+{
+ struct ioctl_data_s data;
+ if (!device)
+ return -ENODEV;
+ memset(&data, 0, sizeof(data));
+ data.txData = txData;
+ data.txSize = txSize;
+ data.rxData = rxData;
+ data.rxSize = rxSize;
+ return device_ci_write(device, &data, 0);
+}
+EXPORT_SYMBOL(cimax_usb_ci_write);
+
+int cimax_usb_ci_read_evt(struct device_s *device,
+ int moduleId, u8 *buf, int size)
+{
+ int ret = 0;
+ struct rw_data_s data;
+ if (!device || !device->opened)
+ return -ENODEV;
+ memset(&data, 0, sizeof(data));
+ data.moduleId = moduleId;
+ data.data = buf;
+ data.size = size;
+ ret = device_wait_async_data(device, data.moduleId, &data, 0);
+ if (ret < 0) {
+ err("wait ci read failed");
+ return ret;
+ } /* if */
+ dbg("return CI, moduleId %d, data 0x%p, size %d",
+ data.moduleId, data.data, data.size);
+ return ret;
+}
+EXPORT_SYMBOL(cimax_usb_ci_read_evt);
+
+int cimax_usb_device_open(struct device_s *device)
+{
+ return device_drv_open(device);
+}
+EXPORT_SYMBOL(cimax_usb_device_open);
+
+int cimax_usb_device_unlock_read(struct device_s *device)
+{
+ int ret = 0;
+ if (!device)
+ return 0;
+ mutex_lock(&device->lock);
+ ret = device_ci_unlock_read(device);
+ mutex_unlock(&device->lock);
+ return ret;
+}
+EXPORT_SYMBOL(cimax_usb_device_unlock_read);
+
+int cimax_usb_device_close(struct device_s *device)
+{
+ if (!device)
+ return 0;
+ cimax_usb_device_unlock_read(device);
+ if (cimax_usb_dev_remove)
+ cimax_usb_dev_remove(device, gdeviceNumber);
+ return device_drv_close(device);
+}
+EXPORT_SYMBOL(cimax_usb_device_close);
+
+static long device_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct device_s *device = (struct device_s *)file->private_data;
+ int err = 0;
+ int ret = 0;
+ struct ioctl_data_s data;
+ void *transfer_buffer = NULL;
+
+ dbg("start");
+
+ /* Don't decode wrong cmds: return ENOTTY (inappropriate ioctl) */
+ if (_IOC_TYPE(cmd) != DEVICE_IOC_MAGIC)
+ return -ENOTTY;
+ if (_IOC_NR(cmd) > DEVICE_IOC_MAXNR)
+ return -ENOTTY;
+
+ /* Verify direction (read/write) */
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
+ if (err)
+ return -EFAULT;
+
+ if (mutex_lock_interruptible(&device->lock))
+ return -ERESTARTSYS;
+
+ switch (cmd) {
+ case DEVICE_IOC_SELECT_INTF:
+ dbg("DEVICE_IOC_SELECT_INTF start");
+ ret = cimax_usb_select_interface(device, arg);
+ dbg("DEVICE_IOC_SELECT_INTF end");
+ break;
+
+ case DEVICE_IOC_CI_WRITE:
+ dbg("DEVICE_IOC_CI_WRITE start");
+
+ /* send CI message */
+ ret = copy_from_user(&data,
+ (void __user *)arg, sizeof(struct ioctl_data_s));
+ dbg("inMsg, rx 0x%p, rxSize %d, tx 0x%p, txSize %d",
+ data.rxData,
+ data.rxSize,
+ data.txData,
+ data.txSize);
+ ret = device_ci_write_ioctl(device, &data);
+ if (ret < 0)
+ break;
+ ret = copy_to_user((void __user *)arg,
+ &data, sizeof(struct ioctl_data_s));
+
+ dbg("DEVICE_IOC_CI_WRITE end");
+ break;
+
+ case DEVICE_IOC_UNLOCK_READ:
+ dbg("DEVICE_IOC_UNLOCK_READ start");
+
+ ret = device_ci_unlock_read(device);
+
+ dbg("DEVICE_IOC_UNLOCK_READ end");
+ break;
+
+ case DEVICE_IOC_SET_CONFIG:
+ dbg("DEVICE_IOC_SET_CONFIG start");
+
+ /* send CI message */
+ ret = copy_from_user(&data,
+ (void __user *)arg, sizeof(struct ioctl_data_s));
+ dbg("inMsg, rx 0x%p, rxSize %d, tx 0x%p, txSize %d",
+ data.rxData, data.rxSize,
+ data.txData, data.txSize);
+ transfer_buffer = kmalloc(data.txSize, GFP_KERNEL);
+ memcpy(transfer_buffer, data.txData, data.txSize);
+ dbg_dump("New config", transfer_buffer, data.txSize);
+ err = usb_control_msg(device->usbdev,
+ usb_sndctrlpipe(device->usbdev, 0),
+ USB_REQ_SET_DESCRIPTOR,
+ USB_TYPE_STANDARD,
+ (USB_DT_CONFIG << 8),
+ 0,
+ transfer_buffer,
+ data.txSize,
+ 5000);
+ if (err < 0) {
+ err("set_config failed %d", err);
+ ret = -EINVAL;
+ }
+ kfree(transfer_buffer);
+ dbg("DEVICE_IOC_SET_CONFIG end");
+ break;
+
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+ } /* switch */
+ mutex_unlock(&device->lock);
+
+ dbg("end, ret %d", ret);
+ return ret;
+} /* device_ioctl */
+
+static ssize_t device_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int ret;
+ struct rw_data_s data;
+ struct device_s *device = (struct device_s *)file->private_data;
+
+ dbg("start");
+
+ /* get transmission buffer */
+ ret = copy_from_user(&data, buf, sizeof(struct rw_data_s));
+ dbg("txBuffer, moduleId %u, data 0x%p, size %d",
+ data.moduleId, data.data, data.size);
+ if (data.moduleId >= DEVICE_NUM_CAM) {
+ err("bad moduleId");
+ return 0;
+ }
+
+ if (device->useIsoc) {
+ if (!data.size || (data.size % DEVICE_ISOC_LENGTH(
+ device->channel[data.moduleId].maxPacketSize))) {
+ err("transmission buffer size must be a multiple of %d",
+ DEVICE_ISOC_LENGTH(
+ device->channel[data.moduleId].maxPacketSize));
+ return -EINVAL;
+ } /* if */
+ }
+
+ if (device->useIsoc) {
+ if (device->channel[data.moduleId].isocInUrb[0] == NULL) {
+ ret = device_start_iso_in(device, data.moduleId);
+ if (ret < 0)
+ return ret;
+ } /* if */
+
+ if (device->channel[data.moduleId].isocOutUrb[0] == NULL) {
+ ret = device_start_iso_out(device, data.moduleId);
+ if (ret < 0)
+ return ret;
+ } /* if */
+
+ dbg("call device_tsiso_send moduleId %d, data 0x%p, size %d",
+ data.moduleId, data.data, data.size);
+ ret = device_tsiso_send(device,
+ data.moduleId, data.data, data.size);
+ } /* if */
+ else {
+ ret = device_tsbulk_send(device,
+ data.moduleId, data.data, data.size);
+ } /* else */
+
+ dbg("end, moduleId %d return %d", data.moduleId, ret);
+ return ret;
+} /* device_write */
+
+static ssize_t device_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int res;
+ struct rw_data_s data;
+ struct device_s *device = (struct device_s *)file->private_data;
+
+ dbg("start");
+
+ if (count != sizeof(struct rw_data_s)) {
+ err("try to read uncorrect size %zd", count);
+ return -EFAULT;
+ } /* if */
+ res = copy_from_user(&data, buf, sizeof(struct rw_data_s));
+ data.copiedSize = 0;
+ if (data.type == DEVICE_TYPE_TS_READ) {
+ res = device_fill_ts(device, data.moduleId, &data);
+ if (res < 0) {
+ err("fill ts buffer failed");
+ return res;
+ } /* if */
+ dbg("return TS, moduleId %d, data 0x%p, size %d, copiedSize %d",
+ data.moduleId, data.data, data.size, data.copiedSize);
+ /*res = count;*/
+ res = data.copiedSize;
+ } /* if */
+ else if (data.type == DEVICE_TYPE_CI_READ) {
+ res = device_wait_async_data(device, data.moduleId, &data, 1);
+ if (res < 0) {
+ err("wait ci read failed");
+ return res;
+ } /* if */
+ dbg("return CI, moduleId %d, data 0x%p, size %d",
+ data.moduleId, data.data, data.size);
+ res = data.size;
+ } /* else if */
+ else {
+ err("unknown data type %d", data.type);
+ res = -EFAULT;
+ } /* else */
+
+ dbg("end, return %d", res);
+ return res;
+} /* device_read */
+
+/******************************************************************************
+ * @brief
+ * write data on Control endpoint.
+ *
+
+ * @param dev
+ * Pointer to usb device.
+ *
+ * @param addr
+
+ * register address to write.
+ *
+ * @param data
+ * data to write.
+ *
+
+ * @param size
+ * size to write.
+ *
+ * @return
+
+ * data writen or ENODEV error
+ ******************************************************************************/
+int write_ctrl_message(struct usb_device *dev, int addr, void *data, int size)
+{
+ int ret;
+ void *ptr = NULL;
+#ifdef DEBUG
+ /* int i;*/
+ /* unsigned char dump[500];*/
+#endif
+
+ /* info("%s: . addr = %04x size=%d",DRIVER_NAME,addr,size);*/
+
+ if (size <= 0)
+ return 0;
+
+ ptr = kmemdup(data, size, GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ ret = usb_control_msg
+ (dev, usb_sndctrlpipe(dev, 0), 0xA0, 0x40, addr, 0x0001,
+ ptr, size, 300);
+ if (ret != size) {
+ err("Failed to write CIMaX+ register 0x%04x", addr);
+ ret = -ENODEV;
+ }
+
+#ifdef DEBUG
+ /* dump[0] =0;
+ for(i=0;i<size;i++) {
+ if((i !=0) && ((i%16) == 0)) {
+ dbg("cimax+usb: %s",dump);
+ dump[0] =0;
+ }
+ sprintf(dump,"%s%02x ",dump,((unsigned char *)ptr)[i]);
+ }
+ dbg("cimax+usb: %s",dump);
+ */
+#endif
+ kfree(ptr);
+
+ return ret;
+}
+
+/******************************************************************************
+ * @brief
+ * read data from Control endpoint.
+ *
+
+ * @param dev
+ * Pointer to usb device.
+ *
+ * @param addr
+ * firmware address to read.
+
+ *
+ * @param data
+ * pointer to buffer to fill with register data.
+ *
+
+ * @param size
+ * size to read.
+ *
+ * @return
+ * data writen or ENODEV error
+
+ ******************************************************************************/
+int read_ctrl_message(struct usb_device *dev, int addr, void *data, int size)
+{
+ int ret;
+ ret = usb_control_msg
+ (dev, usb_rcvctrlpipe(dev, 0), 0xA0, 0xC0, addr, 0x0001,
+ (void *)data, size, 300);
+ if (ret != size) {
+ err("Failed to read CIMaX+ register 0x%04x return %d",
+ addr, ret);
+ ret = -ENODEV;
+ }
+ return ret;
+}
+
+/******************************************************************************
+ * @brief
+ * Start new Firmware.
+ *
+ * @param dev
+ * Pointer to usb device.
+ *
+ * @return
+ * None.
+ ******************************************************************************/
+int init_fw(struct usb_device *dev)
+{
+ int len;
+ char *bootStatus = NULL;
+ bootStatus = kmalloc(sizeof(char), GFP_KERNEL);
+ if (!bootStatus) {
+ pr_err("%s: init_fw kmalloc failed\n",
+ DRIVER_NAME);
+ return 0;
+ }
+
+ info("%s: .", DRIVER_NAME);
+ len = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ 0xA0, 0xC0, 0x0000, 0x0000, bootStatus, 1, 100);
+ if (len == 1) {
+ info("--> Init Status = %02X", *bootStatus);
+ if (bootStatus)
+ kfree(bootStatus);
+ return 0;
+ }
+ if (bootStatus)
+ kfree(bootStatus);
+
+ return len;
+}
+
+/******************************************************************************
+ * @brief
+ * Start new Firmware.
+ *
+ * @param dev
+ * Pointer to usb device.
+
+ *
+ * @return
+ * None.
+ ******************************************************************************/
+int write_ep6_message(struct usb_device *dev, void *data, int size)
+{
+ int ret;
+ void * ptr = NULL;
+ ptr = kmemdup(data, size, GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ if (usb_bulk_msg(dev, usb_sndbulkpipe(dev, 6),
+ ptr, size, &ret, 200) < 0) {
+ err("Failed to write cmd 0x%02x", ((unsigned char *)data)[0]);
+ ret = -ENODEV;
+ }
+ kfree(ptr);
+ return ret;
+}
+
+/******************************************************************************
+ * @brief
+ * Start new Firmware.
+ *
+ * @param dev
+ * Pointer to usb device.
+ *
+ * @return
+ * None.
+ ******************************************************************************/
+int read_ep5_message(struct usb_device *dev, void *data, int size)
+{
+ int ret;
+
+ if (usb_interrupt_msg(dev, usb_rcvintpipe(dev, 5),
+ data, size, &ret, 200) < 0) {
+ err("Failed read interrupt endpoint");
+ ret = -ENODEV;
+ }
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static long device_compat_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long args)
+{
+ unsigned long ret;
+
+ args = (unsigned long)compat_ptr(args);
+ ret = device_ioctl(filp, cmd, args);
+ return ret;
+}
+#endif
+
+static const struct file_operations device_fops = {
+ .owner = THIS_MODULE,
+ .open = device_open,
+ .release = device_release,
+ .unlocked_ioctl = device_ioctl,
+ .write = device_write,
+ .read = device_read,
+ /*
+ .poll = device_poll,
+ */
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = device_compat_ioctl,
+#endif
+};
+
+struct cimaxusb_priv_ops_t cimaxusb_priv_ops = {
+ .write_ctrl_message = write_ctrl_message,
+ .read_ctrl_message = read_ctrl_message,
+ .init_fw = init_fw,
+ .write_ep6_message = write_ep6_message,
+ .read_ep5_message = read_ep5_message
+};
+
+static struct usb_class_driver device_class = {
+ .name = "cimaxusb%d",
+ .fops = &device_fops,
+ .minor_base = DEVICE_MINOR,
+};
+
+/* ---------------------------------------------------------- */
+
+
+void cimax_usb_set_cb(void *cb1, void *cb2)
+{
+ cimax_usb_dev_add = cb1;
+ cimax_usb_dev_remove = cb2;
+}
+EXPORT_SYMBOL(cimax_usb_set_cb);
+
+static int device_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *usbdev = interface_to_usbdev(intf);
+ struct device_s *device;
+ char cmd[] = { 0x0C, 0x01, 0x00, 0x00 };
+ char *rsp;
+
+ dbg("start vendor id 0x%x, product id 0x%x, Device id 0x%x minor 0x%x",
+ le16_to_cpu(usbdev->descriptor.idVendor),
+ le16_to_cpu(usbdev->descriptor.idProduct),
+ le16_to_cpu(usbdev->descriptor.bcdDevice),
+ intf->minor);
+
+ /* device = &gdevice[intf->minor];*/
+ device = &gdevice[gdeviceNumber];
+
+ mutex_lock(&device->lock);
+ /* device->usbdev = usbdev;*/
+ device->usbdev = usb_get_dev(usbdev);
+ dbg("device->usbdev 0x%p", (device->usbdev));
+
+ /* set private callback functions */
+ device->ops = &cimaxusb_priv_ops;
+
+ device->askToSuspend = 0;
+
+ usb_set_intfdata(intf, device);
+ mutex_unlock(&device->lock);
+
+ if (usb_register_dev(intf, &device_class)) {
+ err("usb_register_dev");
+ usb_set_intfdata(intf, NULL);
+ return -ENOMEM;
+ } /* if */
+
+ /* test if firmware loafing is needed */
+#ifdef FRBIT
+ if ((le16_to_cpu(usbdev->descriptor.bcdDevice) != 0) &&
+ (CimaxDwnl == 1)) {
+#else
+ if (le16_to_cpu(usbdev->descriptor.bcdDevice) != 0) {
+#endif
+ info("start firmware download");
+ /* load firmware*/
+ cimaxusb_fw_upload(device);
+ info("end firmware download");
+ } else {
+ info("set alternate setting 1");
+ if (usb_set_interface(device->usbdev, 0, 1) < 0) {
+ err("set_interface failed intf 0, alt 1");
+ } else {
+ info("check FW version");
+ /* Get BOOT version */
+ if (write_ep6_message(device->usbdev,
+ cmd, sizeof(cmd)) == sizeof(cmd)) {
+ rsp = kcalloc(256,
+ sizeof(unsigned char),
+ GFP_KERNEL);
+ if (!rsp) {
+ err("out of memory");
+ return -ENOMEM;
+ }
+ if (read_ep5_message(device->usbdev,
+ rsp, 256) >= 0) {
+ info("=> ---- F.W. Version -------");
+ info("=>= %02X.%02X.%02X.%02X.%02X%c",
+ rsp[4], rsp[5], rsp[6],
+ rsp[7], rsp[8], rsp[9]);
+ info("=> Boot Version = %d.%d",
+ rsp[10], rsp[11]);
+ info("=> --------------------");
+ }
+ kfree(rsp);
+ }
+ }
+ info("start cfg download");
+ if (cimaxusb_configuration_setting(device) < 0)
+ err(" Error : set CIMaX+ configuration");
+ info("end cfg download");
+
+ if (cimax_usb_dev_add)
+ cimax_usb_dev_add(device, gdeviceNumber);
+ }
+
+ dbg("end");
+ return 0;
+} /* device_probe */
+
+static void device_disconnect(struct usb_interface *intf)
+{
+ struct device_s *device = usb_get_intfdata(intf);
+ int i;
+
+ dbg("start");
+
+ if (!device)
+ return;
+
+ mutex_lock(&device->lock);
+ if (device->opened) {
+ /* release blocking functions */
+ device->askToRelease = 1;
+ wake_up_interruptible(&device->ciBulk.ciData[0].asyncWait);
+ wake_up_interruptible(&device->ciBulk.ciData[1].asyncWait);
+ wake_up_interruptible(&device->channel[0].inWait);
+ wake_up_interruptible(&device->channel[1].inWait);
+ device_stop_intr(device);
+ for (i = 0; i < DEVICE_NUM_CAM; i++) {
+ if (device->useIsoc) {
+ device_stop_iso_out(device, i);
+ device_stop_iso_in(device, i);
+ } /* if */
+ else
+ device_stop_tsbulk_in(device, i);
+ } /* for */
+ device->opened = 0;
+
+ if (cimax_usb_dev_remove)
+ cimax_usb_dev_remove(device, gdeviceNumber);
+ } /* if */
+ mutex_unlock(&device->lock);
+ usb_set_intfdata(intf, NULL);
+ if (device) {
+ usb_deregister_dev(intf, &device_class);
+ device->usbdev = NULL;
+ } /* if */
+ dbg("end");
+} /* device_disconnect */
+
+static int cimaxusb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct device_s *device = usb_get_intfdata(intf);
+ int i;
+
+ dbg("start");
+
+ if (!device)
+ return 0;
+
+ mutex_lock(&device->lock);
+ if (device->opened) {
+ /* release blocking functions */
+ device->askToSuspend = 1;
+ wake_up_interruptible(&device->ciBulk.ciData[0].asyncWait);
+ wake_up_interruptible(&device->ciBulk.ciData[1].asyncWait);
+ wake_up_interruptible(&device->channel[0].inWait);
+ wake_up_interruptible(&device->channel[1].inWait);
+ device_stop_intr(device);
+ for (i = 0; i < DEVICE_NUM_CAM; i++) {
+ if (device->useIsoc) {
+ device_stop_iso_out(device, i);
+ device_stop_iso_in(device, i);
+ } /* if */
+ else
+ device_stop_tsbulk_in(device, i);
+ } /* for */
+ device->opened = 0;
+ } /* if */
+ mutex_unlock(&device->lock);
+ dbg("end");
+
+ return 0;
+}
+
+static int cimaxusb_resume(struct usb_interface *intf)
+{
+ struct device_s *device = usb_get_intfdata(intf);
+
+ dbg("start");
+
+ if (!device)
+ return 0;
+
+ device->askToSuspend = 0;
+ dbg("end");
+ return 0;
+}
+
+static struct usb_device_id device_ids[] = {
+ { USB_DEVICE(0x1b0d, 0x2f00) },
+ { USB_DEVICE(0x1b0d, 0x2f01) },
+ { USB_DEVICE(0x1b0d, 0x2f02) },
+ { USB_DEVICE(0x1b0d, 0x2f03) },
+ { USB_DEVICE(0x1b0d, 0x2f04) },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, device_ids);
+
+
+static struct usb_driver device_driver = {
+ .name = "cimaxusb",
+ .probe = device_probe,
+ .disconnect = device_disconnect,
+ .suspend = cimaxusb_suspend,
+ .resume = cimaxusb_resume,
+ .id_table = device_ids,
+};
+
+/* ---------------------------------------------------------- */
+
+static int device_init_module(void)
+{
+ int ret = 0;
+ int i, j;
+ struct device_s *device;
+
+ info("start");
+
+ if (!gdevice)
+ gdevice = kcalloc(DRIVER_MAX_NUMBER,
+ sizeof(struct device_s), GFP_KERNEL);
+ if (!gdevice) {
+ err("not enough memory");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < DRIVER_MAX_NUMBER; i++) {
+ device = &gdevice[i];
+ /* initialize struct */
+ memset(device, 0, sizeof(struct device_s));
+ mutex_init(&device->lock);
+
+ /* initialize ci bulk struct */
+ device->ciBulk.counter = 1;
+ spin_lock_init(&device->ciBulk.intLock);
+ spin_lock_init(&device->ciBulk.intUrbLock);
+ for (j = 0; j < DEVICE_NUM_CAM; j++) {
+ init_waitqueue_head(&device->ciBulk.ciData[j].syncWait);
+ init_waitqueue_head(
+ &device->ciBulk.ciData[j].asyncWait);
+ INIT_LIST_HEAD(&device->ciBulk.ciData[j].asyncDataList);
+ } /* for */
+
+ /* initialize channels */
+ for (j = 0; j < DEVICE_NUM_CAM; j++) {
+ spin_lock_init(&device->channel[j].inLock);
+ init_waitqueue_head(&device->channel[j].inWait);
+ vb_init(&device->channel[j].inVb);
+ device->channel[j].syncOffset = -1;
+ spin_lock_init(&device->channel[j].outLock);
+ } /* for */
+ } /* for */
+
+ /* register misc device */
+ ret = usb_register(&device_driver);
+
+#ifdef TIMESTAMP
+ InitTimestamp();
+#endif
+
+ if (ret)
+ info("end driver register failed");
+ else
+ info("end driver registered");
+
+ info(DRIVER_VERSION ":" DRIVER_DESC);
+
+ return ret;
+} /* device_init_module */
+
+static void device_exit_module(void)
+{
+ int i;
+ struct device_s *device;
+
+ info("start");
+
+#ifdef TIMESTAMP
+ ShowTimestamp();
+#endif
+
+ for (i = 0; i < DRIVER_MAX_NUMBER; i++) {
+ device = &gdevice[i];
+ device->askToRelease = 1;
+ /* destroy struct */
+ mutex_destroy(&device->lock);
+ } /* for */
+ usb_deregister(&device_driver);
+ gdeviceNumber = 0;
+
+ kfree(gdevice);
+ gdevice = NULL;
+ info("end");
+} /* device_exit_module */
+
+module_init(device_init_module);
+module_exit(device_exit_module);
+MODULE_LICENSE("GPL");
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb-driver.h b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb-driver.h
new file mode 100644
index 0000000..e4656e0
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb-driver.h
@@ -0,0 +1,362 @@
+/**************************************************************************//**
+ * @file cimax+usb-driver.h
+ *
+ * @brief CIMaX+ USB Driver for linux based operating systems.
+ *
+ * Copyright (C) 2009-2011 Bruno Tonelli <bruno.tonelli@smardtv.com>
+ * & Franck Descours <franck.descours@smardtv.com>
+ * for SmarDTV France, La Ciotat
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+
+#ifndef CIMAXPLUS_USB_DRIVER_H
+#define CIMAXPLUS_USB_DRIVER_H
+
+/******************************************************************************
+ * Includes
+ *****************************************************************************/
+/******************************************************************************
+ * Defines
+ *****************************************************************************/
+/**
+ * @brief
+ * Driver Name
+ */
+#define DRIVER_NAME "cimax+usb"
+/**
+ * @brief
+ * An unassigned USB minor.
+ */
+#define DEVICE_MINOR 240
+
+/**
+ * @brief
+ * Driver version.
+ */
+#define DEVICE_VERSION 0x1000
+
+/**
+ * @brief
+ * Number of CA module supported by the driver.
+ */
+#define DEVICE_NUM_CAM 2
+
+/**
+ * @brief
+ * Buffer length.
+ */
+#define DEVICE_MESSAGE_LENGTH 4100
+
+/* Offset */
+#define DEVICE_COMMAND_OFFSET 0
+#define DEVICE_STATUS_OFFSET 0
+#define DEVICE_COUNTER_OFFSET 1
+#define DEVICE_LENGTH_MSB_OFFSET 2
+#define DEVICE_LENGTH_LSB_OFFSET 3
+#define DEVICE_DATA_OFFSET 4
+
+/* Mask */
+#define DEVICE_SEL_MASK 0x80
+#define DEVICE_TYP_MASK 0x40
+#define DEVICE_CMD_MASK 0x3F
+
+/* Command tag */
+#define DEVICE_CMD_INIT 0x00
+#define DEVICE_CMD_WRITE_REG 0x7F
+#define DEVICE_CMD_READ_REG 0xFF
+#define DEVICE_CMD_CAMRESET 0x01
+#define DEVICE_CMD_GETCIS 0x02
+#define DEVICE_CMD_WRITECOR 0x03
+#define DEVICE_CMD_NEGOTIATE 0x04
+#define DEVICE_CMD_WRITELPDU 0x05
+#define DEVICE_CMD_READLPDU 0x06
+#define DEVICE_CMD_WRITEEXT 0x07
+#define DEVICE_CMD_READEXT 0x08
+#define DEVICE_CMD_CC1RESET 0x09
+#define DEVICE_CMD_MCARD_WRITE 0x0a
+
+/* Status field */
+#define DEVICE_CAMRESETOK 0x00
+#define DEVICE_CISOK 0x01
+#define DEVICE_WRITECOROK 0x02
+#define DEVICE_NEGOTIATEOK 0x03
+#define DEVICE_WRITELPDUOK 0x04
+#define DEVICE_CAMDET 0x05
+#define DEVICE_READLPDUOK 0x06
+#define DEVICE_WRITEEXTOK 0x07
+#define DEVICE_READEXTOK 0x08
+#define DEVICE_NO_CAM 0x09
+#define DEVICE_NOK 0x0a
+#define DEVICE_INITOK 0x0b
+#define DEVICE_READ_REGOK 0x0c
+#define DEVICE_WRITE_REGOK 0x0d
+#define DEVICE_DATAREADY 0x0e
+#define DEVICE_MCARD_WRITEOK 0x0f
+#define DEVICE_MCARD_READ 0x10
+#define DEVICE_CAMPARSE_ERROR 0x11
+#define DEVICE_WRITELPDUBUSY 0x14
+#define DEVICE_CMDPENDING 0x16
+#define DEVICE_REGSTATUSOK 0x17
+#define DEVICE_GPIOCHANGE 0x18
+#define DEVICE_FRBit 0x1A
+
+
+#define DEVICE_DATAREADY_SYNC 0x3e
+
+/**
+ * @brief
+ * MPEG2 transport size,.isochronous size and number of frames per URB.
+ */
+#define DEVICE_MPEG2_PACKET_SIZE 188
+#define DEVICE_MPEG2_SYNC_BYTE 0x47
+#define DEVICE_NULL_HEADER_SIZE 8
+#define DEVICE_NUM_FRAMES_PER_URB 8
+#define DEVICE_ISOC_LENGTH(x) (DEVICE_NUM_FRAMES_PER_URB*x)
+#define DEVICE_VB_LENGTH 902400
+
+/**
+ * @brief
+ * Endpoint address.
+ */
+#define DEVICE_TS_IN_PIPE 1 /* and 2 */
+#define DEVICE_TS_OUT_PIPE 3 /* and 4 */
+#define DEVICE_INT_IN_PIPE 5
+#define DEVICE_BULK_OUT_PIPE 6
+#define DEVICE_BULK_OUT_MAXPACKET 256
+
+/**
+ * @brief
+ * Number of isochronous/int URBs in the driver.
+ */
+#define DEVICE_NUM_ISOC_OUT_URBS 3
+#define DEVICE_NUM_ISOC_IN_URBS 2
+#define DEVICE_NUM_INT_IN_URBS 2
+
+/**
+ * @brief
+ * ioctl() calls definition.
+ */
+#define DEVICE_IOC_MAGIC 'a'
+#define DEVICE_IOC_SELECT_INTF _IOWR(DEVICE_IOC_MAGIC, 0, signed long)
+#define DEVICE_IOC_CI_WRITE _IOWR(DEVICE_IOC_MAGIC, 1, struct ioctl_data_s)
+#define DEVICE_IOC_UNLOCK_READ _IOWR(DEVICE_IOC_MAGIC, 2, signed long)
+#define DEVICE_IOC_SET_CONFIG _IOWR(DEVICE_IOC_MAGIC, 3, struct ioctl_data_s)
+#define DEVICE_IOC_MAXNR 4
+
+/******************************************************************************
+ * Types
+ *****************************************************************************/
+#ifdef __KERNEL__
+#include <linux/list.h>
+#include <linux/atomic.h>
+#include <linux/printk.h>
+
+#undef dbg
+#undef dbg_isoc_in
+#undef dbg_isoc_out
+
+#undef err
+#undef info
+#undef warn
+
+#define DEBUG
+
+#ifdef DEBUG
+#define dbg(format, arg...) pr_debug("cimax+usb: %s> " format "\n" , \
+ __func__, ## arg)
+#define dbg_s(format, arg...)\
+ pr_debug("cimax+usb: " format "\n" , ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#define dbg_s(format, arg...) do {} while (0)
+#endif
+
+#ifdef DEBUG_ISOC_IN
+#define dbg_isoc_in(format, arg...)\
+ pr_debug("cimax+usb: %s> " format "\n" , \
+ __func__, ## arg)
+#else
+#define dbg_isoc_in(format, arg...) do {} while (0)
+#endif
+
+#ifdef DEBUG_ISOC_OUT
+#define dbg_isoc_out(format, arg...)\
+ pr_debug("cimax+usb: %s> " format "\n" , \
+ __func__, ## arg)
+#else
+#define dbg_isoc_out(format, arg...) do {} while (0)
+#endif
+
+#define err(format, arg...)\
+ pr_err("cimax+usb: %s> ERROR " format "\n" , \
+ __func__, ## arg)
+#define info(format, arg...)\
+ pr_info("cimax+usb: %s> " format "\n" , \
+ __func__, ## arg)
+#define warn(format, arg...)\
+ pr_warn("cimax+usb: %s> WARN" format "\n" , \
+ __func__, ## arg)
+
+/**
+ * @brief
+ * Video buffer structure.
+ */
+struct video_buf_s {
+ __u8 data[DEVICE_VB_LENGTH];
+ int readOffset;
+ int writeOffset;
+ int isEmpty;
+};
+#endif
+
+/**
+ * @brief
+ * Io control data structure exchanged between user and kernel space.
+ */
+struct ioctl_data_s {
+ __u8 *txData;
+ __u32 txSize;
+ __u8 *rxData;
+ __u32 rxSize;
+};
+
+/**
+ * @brief
+ * Read/write type exchanged between user and kernel space.
+ */
+enum rw_type_e {
+ DEVICE_TYPE_CI_READ,
+ DEVICE_TYPE_TS_WRITE,
+ DEVICE_TYPE_TS_READ
+};
+
+/**
+ * @brief
+ * Read/write data structure exchanged between user and kernel space.
+ */
+struct rw_data_s {
+ enum rw_type_e type;
+ __u8 moduleId;
+ __u8 *data;
+ __u32 size;
+ __u32 copiedSize;
+};
+#ifdef __KERNEL__
+/**
+ * @brief
+ * Message node structure. Can be inserted in a list.
+ */
+struct message_node_s {
+ __u8 data[DEVICE_MESSAGE_LENGTH];
+ __u32 size;
+ struct list_head node;
+};
+
+/**
+ * @brief
+ * Received CI data.
+ */
+struct ci_rx_data_s {
+ wait_queue_head_t syncWait;
+ __u8 syncSignal;
+ __u8 syncData[DEVICE_MESSAGE_LENGTH];
+ __u32 syncDataSize;
+ wait_queue_head_t asyncWait;
+ struct list_head asyncDataList;
+ __u8 bPendingSend;
+};
+
+/**
+ * @brief
+ * CI bulk channel.
+ */
+struct ci_bulk_s {
+ __u8 counter;
+ __u16 inMaxPacketSize;
+ __u16 outMaxPacketSize;
+ struct urb *intUrb[DEVICE_NUM_INT_IN_URBS];
+ spinlock_t intLock;
+ spinlock_t intUrbLock;
+ __u8 intCurrStatus;
+ __u8 intCurrIndex;
+ __u16 intSizeToReceive;
+ struct ci_rx_data_s ciData[DEVICE_NUM_CAM];
+};
+
+/**
+ * @brief
+ * TS channel (can use isoc or bulk interface).
+ */
+struct ts_channel_s {
+ spinlock_t inLock;
+ wait_queue_head_t inWait;
+ struct video_buf_s inVb;
+ int syncOffset;
+ int prevOffset;
+ __u8 lastPacket[DEVICE_MPEG2_PACKET_SIZE];
+ __u8 lastPacketSize;
+ spinlock_t outLock;
+ __u8 nextFreeOutUrbIndex;
+ atomic_t numOutUrbs;
+ __u8 outStop;
+ __u16 maxPacketSize;
+ /* isochronous urbs */
+ struct urb *isocInUrb[DEVICE_NUM_ISOC_IN_URBS];
+ struct urb *isocOutUrb[DEVICE_NUM_ISOC_OUT_URBS];
+ /* bulk urbs */
+ struct urb *bulkInUrb;
+ int nbByteSend;
+ int nbByteRead;
+ __u8 FirstTransfer;
+ struct timer_list StartBulkReadTimer;
+
+#ifdef DEBUG_BITRATE
+ ktime_t bitrateTime
+#endif
+};
+
+struct device_s {
+ struct mutex lock;
+ struct usb_device *usbdev;
+ __u8 opened;
+ __u8 askToRelease;
+ __u8 askToSuspend;
+ struct ci_bulk_s ciBulk;
+ __u8 useIsoc;
+ struct ts_channel_s channel[DEVICE_NUM_CAM];
+ /* bus adapter private ops callback */
+ struct cimaxusb_priv_ops_t *ops;
+ int ref;
+};
+
+struct bulk_timer_s {
+ struct device_s *device;
+ __u8 index;
+};
+
+int cimax_usb_select_interface(struct device_s *device, unsigned long intf);
+int cimax_usb_ci_write(struct device_s *device,
+ u8 *txData, int txSize, u8 *rxData, int rxSize);
+int cimax_usb_ci_read_evt(struct device_s *device,
+ int moduleId, u8 *buf, int size);
+
+int cimax_usb_device_unlock_read(struct device_s *device);
+int cimax_usb_device_open(struct device_s *device);
+int cimax_usb_device_close(struct device_s *device);
+void cimax_usb_set_cb(void *cb1, void *cb2);
+
+
+#endif
+#endif
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb_config.c b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb_config.c
new file mode 100644
index 0000000..4469b87
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb_config.c
@@ -0,0 +1,684 @@
+/**************************************************************************//**
+ * @file cimax+usb_config.c
+ *
+ * @brief CIMaX+ USB Driver for linux based operating systems.
+ *
+ * Copyright (C) 2009-2011 Bruno Tonelli <bruno.tonelli@smardtv.com>
+ * & Franck Descours <franck.descours@smardtv.com>
+ * for SmarDTV France, La Ciotat
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ ******************************************************************************/
+/******************************************************************************
+ * Include
+ ******************************************************************************/
+
+
+#include <linux/slab.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/usb.h>
+
+#include <linux/errno.h>
+#include <linux/firmware.h>
+
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+
+#include "cimax+usb-driver.h"
+#include "cimax+usb_config.h"
+#include "bodydef.h"
+
+#include <linux/ctype.h>
+
+#define DEBUG
+#include <linux/printk.h>
+
+/******************************************************************************
+ * Structures
+ ******************************************************************************/
+/******************************************************************************
+ * Globals
+ ******************************************************************************/
+char *cimax_config_file[4] = {
+ "cimax+usb.cfg",
+ "cimax+usb_vcc0.cfg",
+ "cimax+usb_vcc3.cfg",
+ "cimax+usb_vcc5.cfg"
+};
+
+/******************************************************************************
+ * Functions
+ ******************************************************************************/
+/******************************************************************************
+ * @brief
+ * set CIMaX+ register value.
+ *
+ * @param bus_adap
+ * Pointer to CIMaX+ usb adapter.
+ *
+ * @param addr
+ * Addr of CIMaX+ register.
+ *
+ * @param val
+ * CIMaX+ register value to set.
+ *
+ * @return
+ * 0 if OK otherwise -1.
+ ******************************************************************************/
+int usb_setbyte(struct device_s *bus_adap, unsigned int addr, unsigned char val)
+{
+ unsigned char cmd[5];
+ unsigned char *buf;
+ int len;
+ struct usb_device *dev = bus_adap->usbdev;
+
+ cmd[0] = 0x7F;
+ cmd[1] = (unsigned char)((addr>>8)&0xff);
+ cmd[2] = (unsigned char)(addr&0xff);
+ cmd[3] = 0x01;
+ cmd[4] = val;
+ if (bus_adap->ops->write_ep6_message(dev, cmd, sizeof(cmd))
+ == sizeof(cmd)) {
+ /*pr_debug("%s-%s: cmd=0x%x\n",
+ DRIVER_NAME, __func__,cmd[0]);*/
+ buf = kcalloc(256, sizeof(unsigned char), GFP_KERNEL);
+ if (!buf) {
+ pr_err("%s-%s: out of memory.\n",
+ DRIVER_NAME, __func__);
+ return -ENOMEM;
+ }
+
+ while ((len = bus_adap->ops->read_ep5_message(dev, buf, 256))
+ >= 0) {
+ if (len == 0)
+ continue;
+ if ((len == 5) && ((buf[0] & 0x7f) == 0x45))
+ continue;
+ if (len < 4) {
+ pr_err("%s-%s: failed to read addr 0x%x\n",
+ DRIVER_NAME, __func__, addr);
+ kfree(buf);
+ return -1;
+ } else {
+ break;
+ }
+ }
+ } else {
+ pr_err("%s-%s: failed to write addr 0x%x\n",
+ DRIVER_NAME, __func__, addr);
+ return -1;
+ }
+ kfree(buf);
+ return 0;
+}
+
+/******************************************************************************
+ * @brief
+ * get CIMaX+ register value.
+ *
+ * @param bus_adap
+ * Pointer to CIMaX+ usb adapter.
+ *
+ * @param addr
+ * Addr of CIMaX+ register.
+ *
+ * @param val
+ * pointer to buffer to store CIMaX+ register value.
+ *
+ * @return
+ * 0 if OK otherwise -1.
+ ******************************************************************************/
+int usb_getbyte(struct device_s *bus_adap,
+ unsigned int addr, unsigned char *val)
+{
+ unsigned char cmd[4];
+ unsigned char *buf;
+ int len;
+ struct usb_device *dev = bus_adap->usbdev;
+
+ cmd[0] = 0xFF;
+ cmd[1] = (unsigned char)((addr>>8)&0xff);
+ cmd[2] = (unsigned char)(addr&0xff);
+ cmd[3] = 0x01;
+ if (bus_adap->ops->write_ep6_message(dev, cmd, sizeof(cmd))
+ == sizeof(cmd)) {
+ /*pr_debug("%s-%s: cmd=0x%x\n",
+ DRIVER_NAME, __func__,cmd[0]);*/
+ buf = kcalloc(256, sizeof(unsigned char), GFP_KERNEL);
+ if (!buf) {
+ pr_err("%s-%s: out of memory.\n",
+ DRIVER_NAME, __func__);
+ return -ENOMEM;
+ }
+
+ while ((len = bus_adap->ops->read_ep5_message(dev, buf, 256))
+ >= 0) {
+ if (len == 0)
+ continue;
+ /*pr_debug("%s-%s: 0x%x\n",
+ DRIVER_NAME, __func__,buf[0]);*/
+ if ((len == 5) && ((buf[0] & 0x7f) == 0x45))
+ continue;
+ if (len >= 5) {
+ *val = buf[4];
+ break;
+ } else {
+ pr_err("%s-%s: failed to read addr 0x%x\n",
+ DRIVER_NAME, __func__, addr);
+ kfree(buf);
+ return -1;
+ }
+ }
+ } else {
+ pr_err("%s-%s: failed to read addr 0x%x\n",
+ DRIVER_NAME, __func__, addr);
+ return -1;
+ }
+ kfree(buf);
+ return 0;
+}
+
+/******************************************************************************
+ * @brief
+ * compute a logical Or between CIMaX+ register value and a param value.
+ *
+ * @param bus_adap
+ * Pointer to CIMaX+ usb adapter.
+ *
+ * @param addr
+ * Addr of CIMaX+ register.
+ *
+ * @param val
+ * value to compute.
+ *
+ * @param pval
+ * pointer to buffer to store CIMaX+ register value.
+ *
+ * @return
+ * 0 if OK otherwise -1.
+ ******************************************************************************/
+int setLogicalOr(struct device_s *bus_adap,
+ unsigned int addr, unsigned char val, unsigned char *pval)
+{
+ *pval |= val;
+
+ if (usb_setbyte(bus_adap, addr, *pval) < 0)
+ return -1;
+
+ if (usb_getbyte(bus_adap, addr, pval) < 0)
+ return -1;
+
+ dbg("=> Logical OR [%02X] => %02X\n", val, *pval);
+
+ return 0;
+}
+
+/******************************************************************************
+ * @brief
+ * compute a logical And between CIMaX+ register value and a param value.
+ *
+ * @param bus_adap
+ * Pointer to CIMaX+ usb adapter.
+ *
+ * @param addr
+ * Addr of CIMaX+ register.
+ *
+ * @param val
+ * value to compute.
+ *
+ * @param pval
+ * pointer to buffer to store CIMaX+ register value.
+ *
+ * @return
+ * 0 if OK otherwise -1.
+ ******************************************************************************/
+int setLogicalAnd(struct device_s *bus_adap,
+ unsigned int addr, unsigned char val, unsigned char *pval)
+{
+ *pval &= val;
+
+ if (usb_setbyte(bus_adap, addr, *pval) < 0)
+ return -1;
+
+ if (usb_getbyte(bus_adap, addr, pval) < 0)
+ return -1;
+
+ dbg("=> Logical AND [%02X] => %02X\n", val, *pval);
+
+ return 0;
+}
+
+/******************************************************************************
+ * @brief
+ * wait CIMaX+ register value match a param value.
+ *
+ * @param bus_adap
+ * Pointer to CIMaX+ usb adapter.
+ *
+ * @param addr
+ * Addr of CIMaX+ register.
+ *
+ * @param val
+ * value to match.
+ *
+ * @param pval
+ * pointer to buffer to store CIMaX+ register value.
+ *
+ * @return
+ * 0 if OK otherwise -1.
+ ******************************************************************************/
+int waitForValue(struct device_s *bus_adap,
+ unsigned int addr, unsigned char val, unsigned char *pval)
+{
+ dbg("=> Wait for Value [%02X]\n", val);
+ if (*pval == val)
+ return 0;
+
+ while (1) {
+ if (usb_getbyte(bus_adap, addr, pval) < 0)
+ return -1;
+
+ dbg("\r => %02X", *pval);
+
+ if (*pval == val)
+ break;
+ }
+
+ dbg("\n");
+
+ return 0;
+}
+
+/******************************************************************************
+ * @brief
+ * wait CIMaX+ register bits match a param value.
+ *
+ * @param bus_adap
+ * Pointer to CIMaX+ usb adapter.
+ *
+ * @param addr
+ * Addr of CIMaX+ register.
+ *
+ * @param val
+ * value to match.
+ *
+ * @param pval
+ * pointer to buffer to store CIMaX+ register value.
+ *
+ * @return
+ * 0 if OK otherwise -1.
+ ******************************************************************************/
+int waitForBitsSet(struct device_s *bus_adap,
+ unsigned int addr, unsigned char val, unsigned char *pval)
+{
+ dbg("=> Wait for Bits set [%02X]\n", val);
+ if ((*pval & val) == val)
+ return 0;
+
+ while (1) {
+ if (usb_getbyte(bus_adap, addr, pval) < 0)
+ return -1;
+
+ dbg("\r => %02X", *pval);
+
+ if ((*pval & val) == val)
+ break;
+ }
+
+ dbg("\n");
+
+ return 0;
+}
+
+/******************************************************************************
+ * @brief
+ * wait CIMaX+ register bits cleared.
+ *
+ * @param bus_adap
+ * Pointer to CIMaX+ usb adapter.
+ *
+ * @param addr
+ * Addr of CIMaX+ register.
+ *
+ * @param val
+ * bits to check.
+ *
+ * @param pval
+ * pointer to buffer to store CIMaX+ register value.
+ *
+ * @return
+ * 0 if OK otherwise -1.
+ ******************************************************************************/
+int waitForBitsCleared(struct device_s *bus_adap,
+ unsigned int addr, unsigned char val, unsigned char *pval)
+{
+ dbg("=> Wait for Bits cleared [%02X]\n", val);
+ if ((*pval & val) == 0x00)
+ return 0;
+
+ while (1) {
+ if (usb_getbyte(bus_adap, addr, pval) < 0)
+ return -1;
+
+ dbg("\r => %02X", *pval);
+
+ if ((*pval & val) == 0x00)
+ break;
+ }
+
+ dbg("\n");
+
+ return 0;
+}
+
+/******************************************************************************
+ * @brief
+ * retreive addr of CIMaX+ register.
+ *
+ * @param dev
+ * Pointer to CIMaX+ register Name.
+ *
+ * @return
+ * Address of CIMaX+ register.
+ *****************************************************************************/
+int cimaxusb_rtr_reg_addr(char *str_addr)
+{
+ int i32NbItem = sizeof(cimax_reg_map) / sizeof(struct reg_s);
+ int i32index;
+ int i32ValAddr = -1;
+
+ for (i32index = 0; i32index < i32NbItem; i32index++) {
+ if (strcmp(str_addr, cimax_reg_map[i32index].RegisterName)
+ == 0) {
+ i32ValAddr = cimax_reg_map[i32index].RegAddr;
+ break;
+ }
+ }
+ return i32ValAddr;
+}
+
+static int cimaxusb_parse_cfg_ops(struct device_s *bus_adap,
+ unsigned char **pptr, size_t *plen)
+{
+ unsigned char op;
+ int ret;
+ char param1[256], param2[256];
+ char line[256], *ptr_line;
+ int val;
+ unsigned char val2;
+ unsigned int addr;
+ unsigned char *ptr = *pptr;
+ size_t len = *plen;
+
+ ptr_line = line;
+ op = *ptr;
+ ret = sscanf(ptr, "%s %s", param1, param2);
+ ptr++;
+ len++;
+ if (sscanf(ptr, "%s %X", param1, &val) != 2)
+ return -EFAULT;
+ /*pr_debug("%s: param1=%s,param2=%s, val=%x\n",
+ DRIVER_NAME, param1, param2, val);*/
+ strcpy(ptr_line, param1);
+ len += strlen(param1);
+ ptr += strlen(param1);
+ strncat(ptr_line, ptr, 1);
+ len++;
+ ptr++;
+ strcat(ptr_line, param2);
+ len += strlen(param2);
+ ptr += strlen(param2);
+ /*pr_debug("%s: len = %08d line: %s\n",
+ DRIVER_NAME, len, line);*/
+ addr = cimaxusb_rtr_reg_addr(param1);
+ if (((signed)addr) < 0) {
+ pr_err("%s: unknown register name: %s\n",
+ DRIVER_NAME, param1);
+ return -ENODEV;
+ }
+ if (usb_getbyte(bus_adap, addr, &val2) < 0) {
+ pr_err("%s: CIMaX+ register reading problem: %s\n",
+ DRIVER_NAME, param1);
+ return -ENODEV;
+ }
+
+ switch (op) {
+ case '=':
+ if (waitForValue(bus_adap, addr, val, &val2) == -1) {
+ pr_err("%s : waitForValue failed on : %s\n",
+ DRIVER_NAME, param1);
+ return -ENODEV;
+ }
+ pr_info("%s : wait for value ([%x] = %x = %x)\n",
+ line, addr, val, val2);
+ break;
+ case '?':
+ if (waitForBitsSet(bus_adap, addr, val, &val2) == -1) {
+ pr_err("%s : waitForBitsSet failed on : %s\n",
+ DRIVER_NAME, param1);
+ return -ENODEV;
+ }
+ pr_info("%s : wait for bitsset ([%x] = %x = %x)\n",
+ line, addr, val, val2);
+ break;
+ case '!':
+ if (waitForBitsCleared(bus_adap, addr, val, &val2)
+ == -1) {
+ pr_err("%s : waitForBitsCleared failed on : %s\n",
+ DRIVER_NAME, param1);
+ return -ENODEV;
+ }
+ pr_info("%s : wait for bits cleared ([%x] = %x = %x)\n",
+ line, addr, val, val2);
+ break;
+ case '|':
+ if (setLogicalOr(bus_adap, addr, val, &val2) == -1) {
+ pr_err("%s : setLogicalOr failed on : %s\n",
+ DRIVER_NAME, param1);
+ return -ENODEV;
+ }
+ pr_info("%s : setOr ([%x] = %x = %x)\n",
+ line, addr, val, val2);
+ break;
+ case '&':
+ if (setLogicalAnd(bus_adap, addr, val, &val2) == -1) {
+ pr_err("%s : setLogicalAnd failed on : %s\n",
+ DRIVER_NAME, param1);
+ return -ENODEV;
+ }
+ pr_info("%s : setAnd ([%x] = %x = %x)\n",
+ line, addr, val, val2);
+ break;
+ default:
+ pr_err("Error: Marker Unknown <%c> !!!\n", op);
+ return -ENODEV;
+ }
+ *pptr = ptr;
+ *plen = len;
+ return 0;
+}
+
+static int cimaxusb_parse_cfg_default(struct device_s *bus_adap,
+ unsigned char **pptr, size_t *plen)
+{
+ unsigned char *ptr = *pptr;
+ size_t len = *plen;
+ int ret;
+ char param1[256], param2[256];
+ char line[256], *ptr_line;
+ int val;
+ unsigned char val2;
+ unsigned int addr;
+
+ ptr_line = line;
+
+ ret = sscanf(ptr, "%s %s", param1, param2);
+ ret = sscanf(param2, "%X", &val);
+ /*pr_debug("%s: param1=%s,param2=%s,val=%x\n",
+ DRIVER_NAME,param1,param2,val);*/
+ strcpy(ptr_line, param1);
+ len += strlen(param1);
+ ptr += strlen(param1);
+ strncat(ptr_line, ptr, 1);
+ len++;
+ ptr++;
+ strcat(ptr_line, param2);
+ len += strlen(param2);
+ ptr += strlen(param2);
+ /*pr_debug("%s: len = %08d line: %s\n",
+ DRIVER_NAME, len, line);*/
+ addr = cimaxusb_rtr_reg_addr(param1);
+ if (((signed)addr) < 0) {
+ pr_err("%s: unknown register name: %s\n",
+ DRIVER_NAME, param1);
+ return -ENODEV;
+ }
+ if (usb_getbyte(bus_adap, addr, &val2) < 0) {
+ pr_err("%s: CIMaX+ register reading problem: %s\n",
+ DRIVER_NAME, param1);
+ return -ENODEV;
+ }
+ if (usb_setbyte(bus_adap, addr, val) < 0) {
+ pr_err("%s: CIMaX+ register writing problem: %s\n",
+ DRIVER_NAME, param1);
+ return -ENODEV;
+ }
+ if (usb_getbyte(bus_adap, addr, &val2) < 0) {
+ pr_err("%s: CIMaX+ register checking problem: %s\n",
+ DRIVER_NAME, param1);
+ return -ENODEV;
+ }
+ pr_info("set: %s(0x%04x) : 0x%02x\n", param1, addr, val);
+
+ *pptr = ptr;
+ *plen = len;
+ return 0;
+}
+
+/******************************************************************************
+ * @brief
+ * parse CIMaX+ config file.
+ *
+ * @param dev
+ * Pointer to usb device.
+ *
+ * @param fw_data
+ * Pointer to buffer with firmware data.
+ *
+ * @return
+ * O if no error otherwise errno.
+ *****************************************************************************/
+int cimaxusb_parse_cfg(struct device_s *bus_adap,
+ const unsigned char *cfg_data, size_t size)
+{
+ char line[256], *ptr_line;
+ size_t len = 0;
+ unsigned char *ptr = (unsigned char *)cfg_data;
+ int ret = -EFAULT;
+
+ dbg("%s: %s size = %zd\n", DRIVER_NAME, __func__, size);
+ do {
+ ptr_line = line;
+ switch (*ptr) {
+ case ';':
+ /* continue up to find \r character */
+ while (*ptr != 0x0A) {
+ *ptr_line++ = *ptr;
+ ptr++;
+ len++;
+ }
+ *ptr_line = 0;
+ /*pr_debug("%s: len = %08d line: %s\n",
+ DRIVER_NAME, len, line);*/
+ break;
+ case 0x0A:
+ case 0x0D:
+ ptr++;
+ len++;
+ break;
+ case '=':
+ case '?':
+ case '!':
+ case '|':
+ case '&':
+ ret = cimaxusb_parse_cfg_ops(bus_adap, &ptr, &len);
+ if (ret < 0)
+ return ret;
+ break;
+ default:
+ ret = cimaxusb_parse_cfg_default(bus_adap, &ptr, &len);
+ if (ret < 0)
+ return ret;
+ break;
+ }
+ } while (len < size);
+
+ return (ret == -EFAULT) ? 0 : ret;
+}
+
+/******************************************************************************
+ * @brief
+ * read configuration file ( CIMAX_CONFIG_NAME) and set in CIMaX+ chip.
+ *
+ * @param bus_adap
+ * Pointer to usb device.
+ *
+ * @return
+ * None.
+ ******************************************************************************/
+/*
+opt: 0: init, 1: off, 2: Vcc3.3 3: Vcc5
+*/
+int cimaxusb_configuration_setting_opt(struct device_s *bus_adap, int opt)
+{
+ int errno = -EFAULT;
+ const struct firmware *config;
+ char *cfg = cimax_config_file[opt];
+
+ struct usb_device *dev = bus_adap->usbdev;
+
+ dbg("request configuration file");
+ /* request kernel to locate firmware file */
+ errno = request_firmware(&config, cfg, &dev->dev);
+ if (errno < 0) {
+ pr_err("%s: unable to locate configuration file: %s\n",
+ DRIVER_NAME, cfg);
+ goto error;
+ }
+
+ dbg("parse configuration file");
+ errno = cimaxusb_parse_cfg(bus_adap, config->data, config->size);
+ if (errno < 0) {
+ pr_err("%s: unable to parse config file: %s\n",
+ DRIVER_NAME, cfg);
+ goto error;
+ }
+
+error:
+ /* release firmware if needed */
+ if (config != NULL)
+ release_firmware(config);
+ return errno;
+}
+
+int cimaxusb_configuration_setting(struct device_s *bus_adap)
+{
+ return cimaxusb_configuration_setting_opt(bus_adap, 0);
+}
+
+int cimaxusb_configuration_setting_vcc(struct device_s *bus_adap, int vcc)
+{
+ return cimaxusb_configuration_setting_opt(bus_adap, vcc);
+}
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb_config.h b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb_config.h
new file mode 100644
index 0000000..5c55204
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb_config.h
@@ -0,0 +1,58 @@
+/**************************************************************************//**
+ * @file cimax+usb_config.h
+ *
+ * @brief CIMaX+ USB Driver for linux based operating systems.
+ *
+ * Copyright (C) 2009-2011 Bruno Tonelli <bruno.tonelli@smardtv.com>
+ * & Franck Descours <franck.descours@smardtv.com>
+ * for SmarDTV France, La Ciotat
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ ******************************************************************************/
+
+#ifndef __CIMAXPLUS_USB_CFG_H
+#define __CIMAXPLUS_USB_CFG_H
+
+/******************************************************************************
+ * Include
+ ******************************************************************************/
+#include "cimax+usb_handle.h"
+
+/******************************************************************************
+ * Defines
+ ******************************************************************************/
+#define CIMAX_CONFIG_NAME "cimax+usb.cfg"
+
+/******************************************************************************
+ * Enums
+ ******************************************************************************/
+/******************************************************************************
+ * Structures
+ ******************************************************************************/
+
+/******************************************************************************
+ * Functions
+ ******************************************************************************/
+
+/******************************************************************************
+ * @brief
+ * read configuration file ( CIMAX_CONFIG_NAME) and set in CIMaX+ chip.
+ *
+ * @param bus_adap
+ * Pointer to usb device.
+ *
+ * @return
+ * None.
+ ******************************************************************************/
+int cimaxusb_configuration_setting(struct device_s *bus_adap);
+
+#endif
+
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb_fw.c b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb_fw.c
new file mode 100644
index 0000000..6bccf4b
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb_fw.c
@@ -0,0 +1,325 @@
+/**************************************************************************//**
+ * @file cimax+usb_fw.c
+ *
+ * @brief CIMaX+ USB Driver for linux based operating systems.
+ *
+ * Copyright (C) 2009-2011 Bruno Tonelli <bruno.tonelli@smardtv.com>
+ * & Franck Descours <franck.descours@smardtv.com>
+ * for SmarDTV France, La Ciotat
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ ******************************************************************************/
+/******************************************************************************
+ * Include
+ ******************************************************************************/
+#include <linux/slab.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/usb.h>
+
+#include <linux/errno.h>
+#include <linux/firmware.h>
+
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+
+#include <linux/printk.h>
+
+#include "cimax+usb-driver.h"
+#include "cimax+usb_fw.h"
+
+/******************************************************************************
+ * Structures
+ ******************************************************************************/
+/******************************************************************************
+ * Globals
+ ******************************************************************************/
+char cimax_fw[] = CIMAX_FIRMWARE_NAME;
+
+/******************************************************************************
+ * Functions
+ ******************************************************************************/
+/******************************************************************************
+ * @brief
+ * Start & check Bistrom.
+ *
+ * @param dev
+ * Pointer to usb device.
+ *
+ * @param startAddr
+ * start address of firmware to compute
+ *
+ * @param endAddr
+ * stop address of firmware to compute
+ *
+ * @param FWSign
+ * Current signature to check
+ *
+ *
+ * @return
+ * None.
+ ******************************************************************************/
+int checkBistRom(struct device_s *bus_adap,
+ int startAddr, int endAddr, int signature)
+{
+ unsigned char *Val;
+ int rv;
+
+ struct usb_device *dev = bus_adap->usbdev;
+
+ Val = kcalloc(2, sizeof(unsigned char), GFP_KERNEL);
+ if (!Val) {
+ pr_err("%s-%s: out of memory.\n", DRIVER_NAME, __func__);
+ return -ENOMEM;
+ }
+
+ /* Write "Flash" Size
+ (!) BistRom is computed since D000-flashSize to D0000-6
+ */
+ Val[0] = (0xD000-startAddr)&0x00ff;
+ Val[1] = (0xD000-startAddr)>>8;
+ if (bus_adap->ops->write_ctrl_message(dev, 0x008D, Val, 2) != 2) {
+ kfree(Val);
+ return -1;
+ }
+
+ /* Write Signature*/
+ Val[0] = signature&0x00ff;
+ Val[1] = signature>>8;
+ if (bus_adap->ops->write_ctrl_message(dev, 0x0080, Val, 2) != 2) {
+ kfree(Val);
+ return -1;
+ }
+
+ /* Launch BistRom [(D000-flashSize)..CFF9]+[FFFA..FFFF] computation*/
+ Val[0] = 0x0F;
+ if (bus_adap->ops->write_ctrl_message(dev, 0x0082, Val, 1) != 1) {
+ kfree(Val);
+ return -1;
+ }
+
+ pr_info("\n>>Read Signature\n");
+
+ /* Read Signature*/
+ if (bus_adap->ops->read_ctrl_message(dev, 0x0041, Val, 2) != 2) {
+ kfree(Val);
+ return -1;
+ }
+
+ pr_info("\n>> Bistrom computed = %04X\n", Val[0]|Val[1]<<8);
+
+ /* Read Boot status*/
+ if (bus_adap->ops->read_ctrl_message(dev, 0x0009, Val, 1) != 1) {
+ kfree(Val);
+ return -1;
+ }
+
+ pr_info("\n>> BootRom Status = %02X\n", Val[0]);
+ rv = Val[0];
+ kfree(Val);
+
+ return rv;
+}
+
+/******************************************************************************
+ * @brief
+ * Compute BistRom.
+ *
+ * @param ptr
+ * Pointer to buffer with register data
+ *
+ * @param size
+ * Number of register to process
+ *
+ * @param FWSign
+ * Current signature
+ *
+ * @return
+ * None.
+ ******************************************************************************/
+unsigned int MISR(const unsigned char *ptr, int size, unsigned int FWSign)
+{
+ int k, i;
+
+ unsigned short mySign;
+
+ for (k = 0; k < size; k++) {
+ mySign = ptr[k]&0x01;
+
+ for (i = 0; i < 16; i++) {
+ if (0x88B7 & (1<<i))
+ mySign ^= (FWSign>>i) & 0x01;
+ }
+
+ mySign |= ((FWSign<<1)^(ptr[k])) & 0x00FE;
+ mySign |= (FWSign<<1) & 0x00FF00;
+
+ FWSign = mySign;
+ }
+
+ return FWSign;
+}
+
+
+/******************************************************************************
+ * @brief
+ * upload firmware in CIMaX+ chip.
+ *
+ * @param dev
+ * Pointer to usb device.
+ *
+ * @param fw_data
+ * Pointer to buffer with firmware data.
+ *
+ * @param FWSign
+ * Pointer to store computed signature.
+ *
+ * @return
+ * None.
+ ******************************************************************************/
+int cimaxusb_firmware_upload(struct device_s *bus_adap,
+ const unsigned char *fw_data, unsigned int *FWSign)
+{
+ int errno = -EFAULT;
+ const unsigned char *ptr;
+ int startAddr = START_FW_ADDR;
+ unsigned char *recv;
+ int size;
+
+ struct usb_device *dev = bus_adap->usbdev;
+
+ /* data firmware */
+ ptr = fw_data;
+ ptr += START_FW_ADDR;
+
+ recv = kcalloc(300, sizeof(unsigned char), GFP_KERNEL);
+ if (!recv) {
+ pr_err("%s-%s: out of memory.\n", DRIVER_NAME, __func__);
+ return -ENOMEM;
+ }
+
+ do {
+ /* compute the size to send to CIMaX+ */
+ size = (startAddr <= (STOP_FW_ADDR + 1 - MAX_FW_PKT_SIZE)) ?
+ (MAX_FW_PKT_SIZE) : (STOP_FW_ADDR + 1 - startAddr);
+ /* compute Signature */
+ *FWSign = MISR(ptr, size, *FWSign);
+
+ pr_info("%s: firmware start address %08x size %d\n",
+ DRIVER_NAME, startAddr, size);
+
+ /* upload data firmware */
+ if (bus_adap->ops->write_ctrl_message(
+ dev, startAddr, (void *)ptr, size) != size) {
+ pr_err("Failed to load CIMaX+ firmware\n");
+ errno = -ENODEV;
+ break;
+ }
+ if (bus_adap->ops->read_ctrl_message(
+ dev, startAddr, (void *)recv, size) != size) {
+ pr_err("Failed to load CIMaX+ firmware\n");
+ errno = -ENODEV;
+ break;
+ }
+ if (memcmp(ptr, recv, size)) {
+ pr_err("Failed compare at Address 0x%04x\n",
+ startAddr);
+ errno = -ENODEV;
+ break;
+ }
+ /* update size sent to CIMaX+ */
+ startAddr += size;
+ ptr += size;
+ if (startAddr >= STOP_FW_ADDR)
+ break;
+ } while (1);
+
+ kfree(recv);
+
+ if (errno == -EFAULT) {
+ /* upload interrupt vector*/
+ ptr = fw_data;
+ ptr += START_INTVECT_ADDR;
+ startAddr = START_INTVECT_ADDR;
+
+ /* continue to compute Signature */
+ *FWSign = MISR(ptr, 6, *FWSign);
+
+ /* upload interrupt vector data*/
+ if (bus_adap->ops->write_ctrl_message(
+ dev, startAddr, (void *)ptr, 6) != 6) {
+ pr_err("Failed to load CIMaX firmware(Int vector)\n");
+ errno = -ENODEV;
+ }
+ }
+ return (errno == -EFAULT) ? 0 : errno;
+}
+
+/******************************************************************************
+ * @brief
+ * upload and start firmware in CIMaX+ chip.
+ *
+ * @param bus_adap
+ * Pointer to usb device.
+ *
+ * @return
+ * None.
+ ******************************************************************************/
+int cimaxusb_fw_upload(struct device_s *bus_adap)
+{
+ int errno = -EFAULT;
+ const struct firmware *firmware;
+ char *fw = cimax_fw;
+ unsigned int FWSign = 0;
+ int ret;
+
+ struct usb_device *dev = bus_adap->usbdev;
+
+ /* request kernel to locate firmware file */
+ errno = request_firmware(&firmware, fw, &dev->dev);
+ if (errno < 0) {
+ pr_err("%s: unable to locate firmware file: %s\n",
+ DRIVER_NAME, fw);
+ goto error;
+ }
+
+ errno = cimaxusb_firmware_upload(bus_adap, firmware->data, &FWSign);
+ if (errno < 0) {
+ pr_err("%s: unable to upload firmware file: %s\n",
+ DRIVER_NAME, fw);
+ goto error;
+ }
+
+ pr_info("%s: firmware: %s loaded with success. Current Bistrom %04X\n",
+ DRIVER_NAME, fw, FWSign);
+
+ ret = checkBistRom(bus_adap, START_FW_ADDR, STOP_FW_ADDR, FWSign);
+ if (ret != 0x02) {
+ pr_err("\nError: Fail on compare BistRom (%02X) !\n", ret);
+ errno = -ENODEV;
+ goto error;
+ }
+
+ if (bus_adap->ops->init_fw(dev) != 0) {
+ pr_err("\nError: Fail on INIT command !\n");
+ errno = -ENODEV;
+ goto error;
+ }
+
+error:
+ /* release firmware if needed */
+ if (firmware != NULL)
+ release_firmware(firmware);
+ return errno;
+}
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb_fw.h b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb_fw.h
new file mode 100644
index 0000000..bf3f64c
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb_fw.h
@@ -0,0 +1,61 @@
+/**************************************************************************//**
+ * @file cimax+usb_fw.h
+ *
+ * @brief CIMaX+ USB Driver for linux based operating systems.
+ *
+ * Copyright (C) 2009-2011 Bruno Tonelli <bruno.tonelli@smardtv.com>
+ * & Franck Descours <franck.descours@smardtv.com>
+ * for SmarDTV France, La Ciotat
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ ******************************************************************************/
+
+#ifndef __CIMAXPLUS_USB_FW_H
+#define __CIMAXPLUS_USB_FW_H
+
+/******************************************************************************
+ * Include
+ ******************************************************************************/
+#include "cimax+usb_handle.h"
+
+/******************************************************************************
+ * Defines
+ ******************************************************************************/
+#define CIMAX_FIRMWARE_NAME "cimax+_usbdvb.bin"
+#define START_FW_ADDR 0x8000
+#define STOP_FW_ADDR 0xCFF9
+#define START_INTVECT_ADDR 0xFFFA
+#define MAX_FW_PKT_SIZE 256
+
+/******************************************************************************
+ * Enums
+ ******************************************************************************/
+/******************************************************************************
+ * Structures
+ ******************************************************************************/
+
+/******************************************************************************
+ * Functions
+ ******************************************************************************/
+/******************************************************************************
+ * @brief
+ * upload firmware in CIMaX+ chip.
+ *
+ * @param bus_adap
+ * Pointer to usb device.
+ *
+ * @return
+ * None.
+ ******************************************************************************/
+int cimaxusb_fw_upload(struct device_s *bus_adap);
+
+#endif
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb_handle.h b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb_handle.h
new file mode 100644
index 0000000..936b9cf
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb_handle.h
@@ -0,0 +1,46 @@
+/**************************************************************************//**
+ * @file cimax+usb_handle.h
+ *
+ * @brief CIMaX+ USB Driver for linux based operating systems.
+ *
+ * Copyright (C) 2009-2011 Bruno Tonelli <bruno.tonelli@smardtv.com>
+ * & Franck Descours <franck.descours@smardtv.com>
+ * for SmarDTV France, La Ciotat
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ ******************************************************************************/
+
+#ifndef __CIMAXPLUS_USB_HDLE_H
+#define __CIMAXPLUS_USB_HDLE_H
+
+#ifdef __KERNEL__
+
+struct cimaxusb_priv_ops_t {
+ int (*write_ctrl_message)(
+ struct usb_device *dev, int addr, void *data, int size);
+
+ int (*read_ctrl_message)(
+ struct usb_device *dev, int addr, void *data, int size);
+
+ int (*init_fw)(
+ struct usb_device *dev);
+
+ int (*write_ep6_message)(
+ struct usb_device *dev, void *data, int size);
+
+ int (*read_ep5_message)(
+ struct usb_device *dev, void *data, int size);
+};
+
+#endif
+
+#endif
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb_time.c b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb_time.c
new file mode 100644
index 0000000..ea80b5e
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb_time.c
@@ -0,0 +1,130 @@
+/**************************************************************************//**
+ * @file cimax+usb_fw.c
+ *
+ * @brief CIMaX+ USB Driver for linux based operating systems.
+ *
+ * Copyright (C) 2009-2011 Bruno Tonelli <bruno.tonelli@smardtv.com>
+ * & Franck Descours <franck.descours@smardtv.com>
+ * for SmarDTV France, La Ciotat
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ ******************************************************************************/
+
+/*#define TIMESTAMP*/
+
+/******************************************************************************
+ * Include
+ ******************************************************************************/
+#include <linux/delay.h>
+
+#include "cimax+usb_time.h"
+
+/******************************************************************************
+ * Structures
+ ******************************************************************************/
+#define err(format, arg...)\
+ pr_err("cimax+usb_time: %s> ERROR " format "\n" , \
+ __func__, ## arg)
+#define info(format, arg...) pr_info("time> " format "\n", ## arg)
+/******************************************************************************
+ * Globals
+ ******************************************************************************/
+#ifdef TIMESTAMP
+struct item_array_s gstArray;
+#endif
+/******************************************************************************
+ * Functions
+ ******************************************************************************/
+/******************************************************************************
+ * @brief
+ * Init timestamp.
+ *
+ * @param
+ * None
+ *
+ * @return
+ * None.
+ ******************************************************************************/
+void InitTimestamp(void)
+{
+#ifdef TIMESTAMP
+ gstArray.count = 0;
+#endif
+ return;
+}
+
+/******************************************************************************
+ * @brief
+ * Set timestamp.
+ *
+ * @param pcFormat
+ * Printf-like format
+ *
+ * @return
+ * None.
+ ******************************************************************************/
+void SetTimestamp(const char *pcFormat, ...)
+{
+#ifdef TIMESTAMP
+ va_list stArgs;
+
+ if (gstArray.count >= MAX_ITEMS) {
+ if (gstArray.count++ == MAX_ITEMS)
+ ShowTimestamp();
+ return;
+ }
+ ktime_get_ts(&gstArray.stItem[gstArray.count].stTime);
+ va_start(stArgs, pcFormat);
+ vsprintf(gstArray.stItem[gstArray.count++].pcLine, pcFormat, stArgs);
+ va_end(stArgs);
+#endif
+ return;
+}
+
+/******************************************************************************
+ * @brief
+ * Display all timestamps.
+ *
+ * @param
+ * None
+ *
+ * @return
+ * None.
+ ******************************************************************************/
+void ShowTimestamp(void)
+{
+#ifdef TIMESTAMP
+ int i;
+
+ if (gstArray.count == 0) {
+ err("No timestamps available");
+ return;
+ }
+
+ info("===============================================================");
+ info(" TIMESTAMPS");
+ info("===============================================================");
+
+ for (i = 0; i < gstArray.count; i++) {
+ info("[%04d] [%03d.%09d] %s",
+ i,
+ gstArray.stItem[i].stTime.tv_sec,
+ gstArray.stItem[i].stTime.tv_nsec,
+ gstArray.stItem[i].pcLine);
+ if ((i % 100) == 0)
+ msleep(20);
+ }
+ info("===============================================================");
+ gstArray.count = 0;
+
+#endif
+ return;
+}
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb_time.h b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb_time.h
new file mode 100644
index 0000000..0012c64
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/usb/SRC/cimax+usb_time.h
@@ -0,0 +1,92 @@
+/**************************************************************************//**
+ * @file cimax+usb_time.h
+ *
+ * @brief CIMaX+ USB Driver for linux based operating systems.
+ *
+ * Copyright (C) 2009-2011 Bruno Tonelli <bruno.tonelli@smardtv.com>
+ * & Franck Descours <franck.descours@smardtv.com>
+ * for SmarDTV France, La Ciotat
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ ******************************************************************************/
+
+#ifndef __CIMAXPLUS_USB_TIME_H
+#define __CIMAXPLUS_USB_TIME_H
+
+/******************************************************************************
+ * Include
+ ******************************************************************************/
+#include <linux/ktime.h>
+
+/******************************************************************************
+ * Defines
+ ******************************************************************************/
+#define MAX_ITEMS 100000
+#define MAX_LINE_SIZE 128
+
+/******************************************************************************
+ * Enums
+ ******************************************************************************/
+/******************************************************************************
+ * Structures
+ ******************************************************************************/
+struct item_s {
+ struct timespec stTime;
+ char pcLine[MAX_LINE_SIZE];
+};
+
+struct item_array_s {
+ int count;
+ item_s stItem[MAX_ITEMS];
+};
+
+extern struct item_array_s gstArray;
+
+/******************************************************************************
+ * Functions
+ ******************************************************************************/
+/******************************************************************************
+ * @brief
+ * Init timestamp.
+ *
+ * @param
+ * None
+ *
+ * @return
+ * None.
+ ******************************************************************************/
+void InitTimestamp(void);
+
+/******************************************************************************
+ * @brief
+ * Set timestamp.
+ *
+ * @param pcFormat
+ * Printf-like format
+ *
+ * @return
+ * None.
+ ******************************************************************************/
+void SetTimestamp(const char *pcFormat, ...);
+
+/******************************************************************************
+ * @brief
+ * Display all timestamps.
+ *
+ * @param
+ * None
+ *
+ * @return
+ * None.
+ ******************************************************************************/
+void ShowTimestamp(void);
+
+#endif
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/usb/firmware/cimax+_usbdvb.bin b/drivers/stream_input/parser/dvb_ci/cimax/usb/firmware/cimax+_usbdvb.bin
new file mode 100644
index 0000000..315fe5e
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/usb/firmware/cimax+_usbdvb.bin
Binary files differ
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/usb/firmware/cimax+usb.cfg b/drivers/stream_input/parser/dvb_ci/cimax/usb/firmware/cimax+usb.cfg
new file mode 100644
index 0000000..7e792d8
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/usb/firmware/cimax+usb.cfg
@@ -0,0 +1,97 @@
+;
+; ************************
+; * INIT_TS.TXT SCRIPT *
+; ************************
+;
+; *** CLOSE INPUT ***
+;
+IN_SEL 0x00
+;
+; *** CLOSE OUPUT ***
+;
+OUT_SEL 0x00
+;
+; *** RESET FIFO ***
+;
+FIFO_CTRL 0x0f
+SYNC_RTV_CTRL 0x0f
+;
+;
+; *************************
+; * INIT_USB.TXT SCRIPT *
+; *************************
+;
+; *** Endpoint Config ***
+;
+DMA_ACC_EPS 0x3f
+EPS_ENABLE 0x7f
+;
+; *** FIFO Control ***
+;
+USB2TS_CTRL 0x0f
+TS2USB_CTRL 0x0f
+;
+; *** FREQ Control ***
+;
+USB2TS0_RDL 0x80
+USB2TS1_RDL 0x80
+;
+;-----------------------------------------------------------------------------
+; Set CAM power
+;-----------------------------------------------------------------------------
+;
+GPIO0_DATA_OUT 0x00
+;
+; unlock CFG
+CFG_2 0x00
+;
+; 1) DVB/CI/CI+/SCARD 2slot
+CFG_1 0x00
+;
+; 2) Set the Default "power off" state such as VCC_MODA=VCC_MODB=VPPx_MODA=VPPx_MODB='Z'
+GPIO0_DFT 0x00
+;
+; 3) Set GPIO3 as external power switch driver
+GPIO0_MASK_DATA 0x07
+;
+; 4) Set "power on" state (VCC=VPP1=VPP2= 5V)
+GPIO0_DATA_OUT 0x01
+;
+; 5) Lock config
+CFG_2 0x01
+;
+; 6) Write in the GPIO0_DIR_REG: defines the GPIOs, which
+; are used to drive the external power switch, in output mode.
+GPIO0_DIR 0x07
+;
+; 7) Check VCCENable
+?CFG_1 0x20
+;
+; 8) Set & wait for PcmciaOutputEnable
+|CFG_1 0x08
+?CFG_1 0x08
+;
+;---------------------------------------
+; Set Router CAM
+;---------------------------------------
+;
+;
+GAP_REMOVER_CH0_CTRL 0x0C
+GAP_REMOVER_CH1_CTRL 0x0C
+
+; 9) CH0 & CH1 from CAM A & B, CAM A & B from CH0 & CH1
+;
+ROUTER_CAM_MOD 0x21
+ROUTER_CAM_CH 0x00
+;
+;_Wait 200
+;---------------------------------------
+; ROUTER CAM
+;---------------------------------------
+OUT_SEL 0x03
+;
+USB2TS0_RDL 0x80
+USB2TS1_RDL 0x80
+;
+IN_SEL 0x22
+
diff --git a/drivers/stream_input/parser/dvb_ci/cimax/usb/firmware/cimax+usb_ms.cfg b/drivers/stream_input/parser/dvb_ci/cimax/usb/firmware/cimax+usb_ms.cfg
new file mode 100644
index 0000000..5c38429
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimax/usb/firmware/cimax+usb_ms.cfg
@@ -0,0 +1,136 @@
+;
+; ************************
+; * INIT_TS.TXT SCRIPT *
+; ************************
+;
+; *** CLOSE INPUT ***
+;
+IN_SEL 0x00
+;
+; *** CLOSE OUPUT ***
+;
+OUT_SEL 0x00
+;
+; *** RESET FIFO ***
+;
+FIFO_CTRL 0x0f
+SYNC_RTV_CTRL 0x0f
+;
+;
+; *************************
+; * INIT_USB.TXT SCRIPT *
+; *************************
+;
+; *** Endpoint Config ***
+;
+DMA_ACC_EPS 0x3f
+EPS_ENABLE 0x7f
+;
+; *** FIFO Control ***
+;
+USB2TS_CTRL 0x0f
+TS2USB_CTRL 0x0f
+;
+; *** FREQ Control ***
+;
+USB2TS0_RDL 0x80
+USB2TS1_RDL 0x80
+;
+;-----------------------------------------------------------------------------
+; Set CAM power
+;-----------------------------------------------------------------------------
+;
+GPIO0_DATA_OUT 0x00
+;
+; unlock CFG
+CFG_2 0x00
+;
+; 1) DVB/CI/CI+/SCARD 2slot
+CFG_1 0x00
+;
+; 2) Set the Default "power off" state such as VCC_MODA=VCC_MODB=VPPx_MODA=VPPx_MODB='Z'
+GPIO0_DFT 0x00
+;
+; 3) Set GPIO3 as external power switch driver
+GPIO0_MASK_DATA 0x07
+;
+; 4) Set "power on" state (VCC=VPP1=VPP2= 5V)
+GPIO0_DATA_OUT 0x01
+;
+; 5) Lock config
+CFG_2 0x01
+;
+; 6) Write in the GPIO0_DIR_REG: defines the GPIOs, which
+; are used to drive the external power switch, in output mode.
+GPIO0_DIR 0x07
+;
+; 7) Check VCCENable
+?CFG_1 0x20
+;
+; 8) Set & wait for PcmciaOutputEnable
+|CFG_1 0x08
+?CFG_1 0x08
+;
+;---------------------------------------
+; Set Router CAM
+;---------------------------------------
+;
+;
+GAP_REMOVER_CH0_CTRL 0x0C
+GAP_REMOVER_CH1_CTRL 0x0C
+
+; 9) CH0 & CH1 from CAM A & B, CAM A & B from CH0 & CH1
+;
+ROUTER_CAM_MOD 0x21
+ROUTER_CAM_CH 0x00
+;
+;_Wait 200
+;---------------------------------------
+; ROUTER CAM
+;---------------------------------------
+OUT_SEL 0x03
+;
+USB2TS0_RDL 0x80
+USB2TS1_RDL 0x80
+;
+IN_SEL 0x22
+
+; ***************************
+; * MuliStream.TXT SCRIPT *
+; ***************************
+;
+; *** CLOSE INPUT ***
+;
+IN_SEL 0x00
+;
+; *** CLOSE OUPUT ***
+;
+OUT_SEL 0x00
+;
+; *** RESET FIFO ***
+;
+FIFO_CTRL 0x0f
+SYNC_RTV_CTRL 0x0f
+;
+; *** ***
+;
+CkMan_Config 0x1f
+CkMan_Select 0x00
+MERGER_DIV_MICLK 0x02
+SYNC_SYMBOL 0x0d
+PID_AND_SYNC_REMAPPER_INV_CTRL 0x01
+
+FIFO_CTRL 0x0f
+ROUTER_CAM_MOD 0x03
+ROUTER_CAM_CH 0x80
+
+USB2TS_CTRL 0x0f
+TS2USB_CTRL 0x0f
+USB2TS0_RDL 0x20
+USB2TS1_RDL 0x20
+
+OUT_SEL 0x03
+IN_SEL 0x22
+;
+; ************************
+;
diff --git a/drivers/stream_input/parser/dvb_ci/cimcu/dvb_ca_en50221_cimcu.c b/drivers/stream_input/parser/dvb_ci/cimcu/dvb_ca_en50221_cimcu.c
new file mode 100644
index 0000000..762f5ff
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimcu/dvb_ca_en50221_cimcu.c
@@ -0,0 +1,1967 @@
+/*
+ * dvb_ca.c: generic DVB functions for EN50221 CAM interfaces
+ *
+ * Copyright (C) 2004 Andrew de Quincey
+ *
+ * Parts of this file were based on sources as follows:
+ *
+ * Copyright (C) 2003 Ralph Metzler <rjkm@metzlerbros.de>
+ *
+ * based on code:
+ *
+ * Copyright (C) 1999-2002 Ralph Metzler
+ * & Marcus Metzler for convergence integrated media GmbH
+ *
+ * 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.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+
+#include "dvb_ca_en50221_cimcu.h"
+#include "../cimax/dvb_ringbuffer.h"
+
+#define READ_LPDU_PKT
+
+static int dvb_ca_en50221_debug;
+
+module_param_named(cammcu_debug, dvb_ca_en50221_debug, int, 0644);
+MODULE_PARM_DESC(cammcu_debug, "enable verbose debug messages");
+
+#define dprintk if (dvb_ca_en50221_debug) printk
+
+#define INIT_TIMEOUT_SECS 10
+
+#define HOST_LINK_BUF_SIZE 0x200
+
+#define RX_BUFFER_SIZE 65535
+
+#define MAX_RX_PACKETS_PER_ITERATION 10
+
+#define CTRLIF_DATA 0
+#define CTRLIF_COMMAND 1
+#define CTRLIF_STATUS 1
+#define CTRLIF_SIZE_LOW 2
+#define CTRLIF_SIZE_HIGH 3
+
+#define CMDREG_HC 1 /* Host control */
+#define CMDREG_SW 2 /* Size write */
+#define CMDREG_SR 4 /* Size read */
+#define CMDREG_RS 8 /* Reset interface */
+#define CMDREG_FRIE 0x40 /* Enable FR interrupt */
+#define CMDREG_DAIE 0x80 /* Enable DA interrupt */
+#define IRQEN (CMDREG_DAIE)
+
+#define STATUSREG_RE 1 /* read error */
+#define STATUSREG_WE 2 /* write error */
+#define STATUSREG_FR 0x40 /* module free */
+#define STATUSREG_DA 0x80 /* data available */
+#define STATUSREG_TXERR (STATUSREG_RE|STATUSREG_WE) /* general transfer error */
+
+
+#define DVB_CA_SLOTSTATE_NONE 0
+#define DVB_CA_SLOTSTATE_UNINITIALISED 1
+#define DVB_CA_SLOTSTATE_RUNNING 2
+#define DVB_CA_SLOTSTATE_INVALID 3
+#define DVB_CA_SLOTSTATE_WAITREADY 4
+#define DVB_CA_SLOTSTATE_VALIDATE 5
+#define DVB_CA_SLOTSTATE_WAITFR 6
+#define DVB_CA_SLOTSTATE_LINKINIT 7
+
+
+/* Information on a CA slot */
+struct dvb_ca_slot {
+
+ /* current state of the CAM */
+ int slot_state;
+
+ /* mutex used for serializing access to one CI slot */
+ struct mutex slot_lock;
+
+ /* Number of CAMCHANGES that have occurred since last processing */
+ atomic_t camchange_count;
+
+ /* Type of last CAMCHANGE */
+ int camchange_type;
+
+ /* base address of CAM config */
+ u32 config_base;
+
+ /* value to write into Config Control register */
+ u8 config_option;
+
+ /* if 1, the CAM supports DA IRQs */
+ u8 da_irq_supported:1;
+
+#ifdef READ_LPDU_PKT
+ /* Offset into current ringbuffer when user buffer was not big enough
+ to return entire pkt */
+ int rx_offset;
+#endif
+
+ /* size of the buffer to use when talking to the CAM */
+ int link_buf_size;
+
+ /* buffer for incoming packets */
+ struct dvb_ringbuffer rx_buffer;
+
+ /* timer used during various states of the slot */
+ unsigned long timeout;
+};
+
+/* Private CA-interface information */
+struct dvb_ca_private {
+ struct kref refcount;
+
+ /* pointer back to the public data structure */
+ struct dvb_ca_en50221_cimcu *pub;
+
+ /* the DVB device */
+ struct dvb_device *dvbdev;
+
+ /* Flags describing the interface (DVB_CA_FLAG_*) */
+ u32 flags;
+
+ /* number of slots supported by this CA interface */
+ unsigned int slot_count;
+
+ /* information on each slot */
+ struct dvb_ca_slot *slot_info;
+
+ /* wait queues for read() and write() operations */
+ wait_queue_head_t wait_queue;
+
+ /* PID of the monitoring thread */
+ struct task_struct *thread;
+
+ /* Flag indicating if the CA device is open */
+ unsigned int open:1;
+
+ /* Flag indicating the thread should wake up now */
+ unsigned int wakeup:1;
+
+ /* Delay the main thread should use */
+ unsigned long delay;
+
+ /* Slot to start looking for data to read from in the next user-space read operation */
+ int next_read_slot;
+
+ /* mutex serializing ioctls */
+ struct mutex ioctl_mutex;
+};
+
+static void dvb_ca_private_free(struct dvb_ca_private *ca)
+{
+ unsigned int i;
+
+ dvb_unregister_device(ca->dvbdev);
+ for (i = 0; i < ca->slot_count; i++)
+ vfree(ca->slot_info[i].rx_buffer.data);
+
+ kfree(ca->slot_info);
+ kfree(ca);
+}
+
+static void dvb_ca_private_release(struct kref *ref)
+{
+ struct dvb_ca_private *ca = container_of(ref, struct dvb_ca_private, refcount);
+ dvb_ca_private_free(ca);
+}
+
+static void dvb_ca_private_get(struct dvb_ca_private *ca)
+{
+ kref_get(&ca->refcount);
+}
+
+static void dvb_ca_private_put(struct dvb_ca_private *ca)
+{
+ kref_put(&ca->refcount, dvb_ca_private_release);
+}
+
+static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca);
+static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount);
+static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount);
+
+
+/**
+ * Safely find needle in haystack.
+ *
+ * @haystack: Buffer to look in.
+ * @hlen: Number of bytes in haystack.
+ * @needle: Buffer to find.
+ * @nlen: Number of bytes in needle.
+ * @return Pointer into haystack needle was found at, or NULL if not found.
+ */
+static char *findstr(char * haystack, int hlen, char * needle, int nlen)
+{
+ int i;
+
+ if (hlen < nlen)
+ return NULL;
+
+ for (i = 0; i <= hlen - nlen; i++) {
+ if (!strncmp(haystack + i, needle, nlen))
+ return haystack + i;
+ }
+
+ return NULL;
+}
+
+
+
+/* ******************************************************************************** */
+/* EN50221 physical interface functions */
+
+
+/**
+ * dvb_ca_en50221_check_camstatus - Check CAM status.
+ */
+static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot)
+{
+ int slot_status;
+ int cam_present_now;
+ int cam_changed;
+
+ /* IRQ mode */
+ if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) {
+ return (atomic_read(&ca->slot_info[slot].camchange_count) != 0);
+ }
+
+ /* poll mode */
+ slot_status = ca->pub->poll_slot_status(ca->pub, slot, ca->open);
+
+ cam_present_now = (slot_status & DVB_CA_EN50221_POLL_CAM_PRESENT) ? 1 : 0;
+ cam_changed = (slot_status & DVB_CA_EN50221_POLL_CAM_CHANGED) ? 1 : 0;
+ if (!cam_changed) {
+ int cam_present_old = (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE);
+ cam_changed = (cam_present_now != cam_present_old);
+ }
+
+ if (cam_changed) {
+ if (!cam_present_now) {
+ ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED;
+ } else {
+ ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_INSERTED;
+ }
+ atomic_set(&ca->slot_info[slot].camchange_count, 1);
+ } else {
+ if ((ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) &&
+ (slot_status & DVB_CA_EN50221_POLL_CAM_READY)) {
+ // move to validate state if reset is completed
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE;
+ }
+ }
+
+ return cam_changed;
+}
+
+
+/**
+ * dvb_ca_en50221_wait_if_status - Wait for flags to become set on the STATUS
+ * register on a CAM interface, checking for errors and timeout.
+ *
+ * @ca: CA instance.
+ * @slot: Slot on interface.
+ * @waitfor: Flags to wait for.
+ * @timeout_ms: Timeout in milliseconds.
+ *
+ * @return 0 on success, nonzero on error.
+ */
+static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot,
+ u8 waitfor, int timeout_hz)
+{
+ unsigned long timeout;
+ unsigned long start;
+
+ dprintk("%s\n", __func__);
+
+ /* loop until timeout elapsed */
+ start = jiffies;
+ timeout = jiffies + timeout_hz;
+ while (1) {
+ /* read the status and check for error */
+ int res = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
+ if (res < 0)
+ return -EIO;
+
+ /* if we got the flags, it was successful! */
+ if (res & waitfor) {
+ dprintk("%s succeeded timeout:%lu\n", __func__, jiffies - start);
+ return 0;
+ }
+
+ /* check for timeout */
+ if (time_after(jiffies, timeout)) {
+ break;
+ }
+
+ /* wait for a bit */
+ msleep(1);
+ }
+
+ dprintk("%s failed timeout:%lu\n", __func__, jiffies - start);
+
+ /* if we get here, we've timed out */
+ return -ETIMEDOUT;
+}
+
+
+/**
+ * dvb_ca_en50221_link_init - Initialise the link layer connection to a CAM.
+ *
+ * @ca: CA instance.
+ * @slot: Slot id.
+ *
+ * @return 0 on success, nonzero on failure.
+ */
+static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot)
+{
+ int ret;
+ int buf_size;
+ u8 buf[2];
+
+ dprintk("%s\n", __func__);
+
+ /* we'll be determining these during this function */
+ ca->slot_info[slot].da_irq_supported = 0;
+#ifdef READ_LPDU_PKT
+ ca->slot_info[slot].rx_offset = 0;
+#endif
+ /* set the host link buffer size temporarily. it will be overwritten with the
+ * real negotiated size later. */
+ ca->slot_info[slot].link_buf_size = 2;
+
+ /* read the buffer size from the CAM */
+ if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SR)) != 0)
+ return ret;
+ if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ / 10)) != 0)
+ return ret;
+ if ((ret = dvb_ca_en50221_read_data(ca, slot, buf, 2)) != 2)
+ return -EIO;
+ if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0)
+ return ret;
+
+ /* store it, and choose the minimum of our buffer and the CAM's buffer size */
+ buf_size = (buf[0] << 8) | buf[1];
+ if (buf_size > HOST_LINK_BUF_SIZE)
+ buf_size = HOST_LINK_BUF_SIZE;
+ ca->slot_info[slot].link_buf_size = buf_size;
+ buf[0] = buf_size >> 8;
+ buf[1] = buf_size & 0xff;
+ dprintk("Chosen link buffer size of %i\n", buf_size);
+
+ /* write the buffer size to the CAM */
+ if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SW)) != 0)
+ return ret;
+ if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10)) != 0)
+ return ret;
+ if ((ret = dvb_ca_en50221_write_data(ca, slot, buf, 2)) != 2)
+ return -EIO;
+ if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0)
+ return ret;
+
+ /* success */
+ return 0;
+}
+
+/**
+ * dvb_ca_en50221_read_tuple - Read a tuple from attribute memory.
+ *
+ * @ca: CA instance.
+ * @slot: Slot id.
+ * @address: Address to read from. Updated.
+ * @tupleType: Tuple id byte. Updated.
+ * @tupleLength: Tuple length. Updated.
+ * @tuple: Dest buffer for tuple (must be 256 bytes). Updated.
+ *
+ * @return 0 on success, nonzero on error.
+ */
+static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot,
+ int *address, int *tupleType, int *tupleLength, u8 * tuple)
+{
+ int i;
+ int _tupleType;
+ int _tupleLength;
+ int _address = *address;
+
+ /* grab the next tuple length and type */
+ if ((_tupleType = ca->pub->read_attribute_mem(ca->pub, slot, _address)) < 0)
+ return _tupleType;
+ if (_tupleType == 0xff) {
+ dprintk("END OF CHAIN TUPLE type:0x%x\n", _tupleType);
+ *address += 2;
+ *tupleType = _tupleType;
+ *tupleLength = 0;
+ return 0;
+ }
+ if ((_tupleLength = ca->pub->read_attribute_mem(ca->pub, slot, _address + 2)) < 0)
+ return _tupleLength;
+ _address += 4;
+
+ dprintk("TUPLE type:0x%x length:%i\n", _tupleType, _tupleLength);
+
+ /* read in the whole tuple */
+ for (i = 0; i < _tupleLength; i++) {
+ tuple[i] = ca->pub->read_attribute_mem(ca->pub, slot, _address + (i * 2));
+ dprintk(" 0x%02x: 0x%02x %c\n",
+ i, tuple[i] & 0xff,
+ ((tuple[i] > 31) && (tuple[i] < 127)) ? tuple[i] : '.');
+ }
+ _address += (_tupleLength * 2);
+
+ // success
+ *tupleType = _tupleType;
+ *tupleLength = _tupleLength;
+ *address = _address;
+ return 0;
+}
+
+
+/**
+ * dvb_ca_en50221_parse_attributes - Parse attribute memory of a CAM module,
+ * extracting Config register, and checking it is a DVB CAM module.
+ *
+ * @ca: CA instance.
+ * @slot: Slot id.
+ *
+ * @return 0 on success, <0 on failure.
+ */
+static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot)
+{
+ int address = 0;
+ int tupleLength;
+ int tupleType;
+ u8 tuple[257];
+ char *dvb_str;
+ int rasz;
+ int status;
+ int got_cftableentry = 0;
+ int end_chain = 0;
+ int i;
+ u16 manfid = 0;
+ u16 devid = 0;
+
+
+ // CISTPL_DEVICE_0A
+ if ((status =
+ dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)
+ return status;
+ if (tupleType != 0x1D)
+ return -EINVAL;
+
+
+
+ // CISTPL_DEVICE_0C
+ if ((status =
+ dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)
+ return status;
+ if (tupleType != 0x1C)
+ return -EINVAL;
+
+
+
+ // CISTPL_VERS_1
+ if ((status =
+ dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)
+ return status;
+ if (tupleType != 0x15)
+ return -EINVAL;
+
+
+
+ // CISTPL_MANFID
+ if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,
+ &tupleLength, tuple)) < 0)
+ return status;
+ if (tupleType != 0x20)
+ return -EINVAL;
+ if (tupleLength != 4)
+ return -EINVAL;
+ manfid = (tuple[1] << 8) | tuple[0];
+ devid = (tuple[3] << 8) | tuple[2];
+
+
+
+ // CISTPL_CONFIG
+ if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,
+ &tupleLength, tuple)) < 0)
+ return status;
+ if (tupleType != 0x1A)
+ return -EINVAL;
+ if (tupleLength < 3)
+ return -EINVAL;
+
+ /* extract the configbase */
+ rasz = tuple[0] & 3;
+ if (tupleLength < (3 + rasz + 14))
+ return -EINVAL;
+ ca->slot_info[slot].config_base = 0;
+ for (i = 0; i < rasz + 1; i++) {
+ ca->slot_info[slot].config_base |= (tuple[2 + i] << (8 * i));
+ }
+
+ /* check it contains the correct DVB string */
+ dvb_str = findstr((char *)tuple, tupleLength, "DVB_CI_V", 8);
+ if (dvb_str == NULL)
+ return -EINVAL;
+ if (tupleLength < ((dvb_str - (char *) tuple) + 12))
+ return -EINVAL;
+
+ /* is it a version we support? */
+ if (strncmp(dvb_str + 8, "1.00", 4)) {
+ printk("dvb_ca adapter %d: Unsupported DVB CAM module version %c%c%c%c\n",
+ ca->dvbdev->adapter->num, dvb_str[8], dvb_str[9], dvb_str[10], dvb_str[11]);
+ return -EINVAL;
+ }
+
+ /* process the CFTABLE_ENTRY tuples, and any after those */
+ while ((!end_chain) && (address < 0x1000)) {
+ if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,
+ &tupleLength, tuple)) < 0)
+ return status;
+ switch (tupleType) {
+ case 0x1B: // CISTPL_CFTABLE_ENTRY
+ if (tupleLength < (2 + 11 + 17))
+ break;
+
+ /* if we've already parsed one, just use it */
+ if (got_cftableentry)
+ break;
+
+ /* get the config option */
+ ca->slot_info[slot].config_option = tuple[0] & 0x3f;
+
+ /* OK, check it contains the correct strings */
+ if ((findstr((char *)tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
+ (findstr((char *)tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL))
+ break;
+
+ got_cftableentry = 1;
+ break;
+
+ case 0x14: // CISTPL_NO_LINK
+ break;
+
+ case 0xFF: // CISTPL_END
+ end_chain = 1;
+ break;
+
+ default: /* Unknown tuple type - just skip this tuple and move to the next one */
+ dprintk("dvb_ca: Skipping unknown tuple type:0x%x length:0x%x\n", tupleType,
+ tupleLength);
+ break;
+ }
+ }
+
+ if ((address > 0x1000) || (!got_cftableentry))
+ return -EINVAL;
+
+ dprintk("Valid DVB CAM detected MANID:%x DEVID:%x CONFIGBASE:0x%x CONFIGOPTION:0x%x\n",
+ manfid, devid, ca->slot_info[slot].config_base, ca->slot_info[slot].config_option);
+
+ // success!
+ return 0;
+}
+
+
+/**
+ * dvb_ca_en50221_set_configoption - Set CAM's configoption correctly.
+ *
+ * @ca: CA instance.
+ * @slot: Slot containing the CAM.
+ */
+static int dvb_ca_en50221_set_configoption(struct dvb_ca_private *ca, int slot)
+{
+ int configoption;
+
+ dprintk("%s\n", __func__);
+
+ /* set the config option */
+ ca->pub->write_attribute_mem(ca->pub, slot,
+ ca->slot_info[slot].config_base,
+ ca->slot_info[slot].config_option);
+
+ /* check it */
+ configoption = ca->pub->read_attribute_mem(ca->pub, slot, ca->slot_info[slot].config_base);
+ dprintk("Set configoption 0x%x, read configoption 0x%x\n",
+ ca->slot_info[slot].config_option, configoption & 0x3f);
+
+ /* fine! */
+ return 0;
+
+}
+
+
+/**
+ * dvb_ca_en50221_read_data - This function talks to an EN50221 CAM control
+ * interface. It reads a buffer of data from the CAM. The data can either
+ * be stored in a supplied buffer, or automatically be added to the slot's
+ * rx_buffer.
+ *
+ * @ca: CA instance.
+ * @slot: Slot to read from.
+ * @ebuf: If non-NULL, the data will be written to this buffer. If NULL,
+ * the data will be added into the buffering system as a normal fragment.
+ * @ecount: Size of ebuf. Ignored if ebuf is NULL.
+ *
+ * @return Number of bytes read, or < 0 on error
+ */
+static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount)
+{
+ int bytes_read;
+ int status;
+ u8 buf[HOST_LINK_BUF_SIZE];
+ int i;
+
+ dprintk("%s\n", __func__);
+
+ /* check if we have space for a link buf in the rx_buffer */
+ if (ebuf == NULL) {
+ int buf_free;
+
+ if (ca->slot_info[slot].rx_buffer.data == NULL) {
+ status = -EIO;
+ goto exit;
+ }
+ buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer);
+
+ if (buf_free < (ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) {
+ status = -EAGAIN;
+ goto exit;
+ }
+ }
+
+ /* check if there is data available */
+ if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
+ goto exit;
+ if (!(status & STATUSREG_DA)) {
+ /* no data */
+ status = 0;
+ goto exit;
+ }
+
+ /* read the amount of data */
+ if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH)) < 0)
+ goto exit;
+ bytes_read = status << 8;
+ if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW)) < 0)
+ goto exit;
+ bytes_read |= status;
+
+ /* check it will fit */
+ if (ebuf == NULL) {
+ if (bytes_read > ca->slot_info[slot].link_buf_size) {
+ printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size (%i > %i)!\n",
+ ca->dvbdev->adapter->num, bytes_read, ca->slot_info[slot].link_buf_size);
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+ status = -EIO;
+ goto exit;
+ }
+ if (bytes_read < 2) {
+ printk("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n",
+ ca->dvbdev->adapter->num);
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+ status = -EIO;
+ goto exit;
+ }
+ } else {
+ if (bytes_read > ecount) {
+ printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n",
+ ca->dvbdev->adapter->num);
+ status = -EIO;
+ goto exit;
+ }
+ }
+
+ /* fill the buffer */
+ for (i = 0; i < bytes_read; i++) {
+ /* read byte and check */
+ if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_DATA)) < 0)
+ goto exit;
+
+ /* OK, store it in the buffer */
+ buf[i] = status;
+ }
+
+ /* check for read error (RE should now be 0) */
+ if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
+ goto exit;
+ if (status & STATUSREG_RE) {
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+ status = -EIO;
+ goto exit;
+ }
+
+ /* OK, add it to the receive buffer, or copy into external buffer if supplied */
+ if (ebuf == NULL) {
+ if (ca->slot_info[slot].rx_buffer.data == NULL) {
+ status = -EIO;
+ goto exit;
+ }
+ dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read);
+ } else {
+ memcpy(ebuf, buf, bytes_read);
+ }
+
+ dprintk("Received CA packet for slot %i connection id 0x%x last_frag:%i size:0x%x\n", slot,
+ buf[0], (buf[1] & 0x80) == 0, bytes_read);
+#ifndef READ_LPDU_PKT
+ /* wake up readers when a last_fragment is received */
+ if ((buf[1] & 0x80) == 0x00)
+#endif
+ wake_up_interruptible(&ca->wait_queue);
+ status = bytes_read;
+
+exit:
+ return status;
+}
+
+
+/**
+ * dvb_ca_en50221_write_data - This function talks to an EN50221 CAM control
+ * interface. It writes a buffer of data to a CAM.
+ *
+ * @ca: CA instance.
+ * @slot: Slot to write to.
+ * @ebuf: The data in this buffer is treated as a complete link-level packet to
+ * be written.
+ * @count: Size of ebuf.
+ *
+ * @return Number of bytes written, or < 0 on error.
+ */
+static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * buf, int bytes_write)
+{
+ int status;
+ int i;
+
+ dprintk("%s\n", __func__);
+
+
+ /* sanity check */
+ if (bytes_write > ca->slot_info[slot].link_buf_size)
+ return -EINVAL;
+
+ /* it is possible we are dealing with a single buffer implementation,
+ thus if there is data available for read or if there is even a read
+ already in progress, we do nothing but awake the kernel thread to
+ process the data if necessary. */
+ if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
+ goto exitnowrite;
+ if (status & (STATUSREG_DA | STATUSREG_RE)) {
+ if (status & STATUSREG_DA)
+ dvb_ca_en50221_thread_wakeup(ca);
+
+ status = -EAGAIN;
+ goto exitnowrite;
+ }
+
+ /* OK, set HC bit */
+ if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,
+ IRQEN | CMDREG_HC)) != 0)
+ goto exit;
+
+ /* check if interface is still free */
+ if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
+ goto exit;
+ if (!(status & STATUSREG_FR)) {
+ /* it wasn't free => try again later */
+ status = -EAGAIN;
+ goto exit;
+ }
+
+ /*
+ * It may need some time for the CAM to settle down, or there might
+ * be a race condition between the CAM, writing HC and our last
+ * check for DA. This happens, if the CAM asserts DA, just after
+ * checking DA before we are setting HC. In this case it might be
+ * a bug in the CAM to keep the FR bit, the lower layer/HW
+ * communication requires a longer timeout or the CAM needs more
+ * time internally. But this happens in reality!
+ * We need to read the status from the HW again and do the same
+ * we did for the previous check for DA
+ */
+ status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
+ if (status < 0)
+ goto exit;
+
+ if (status & (STATUSREG_DA | STATUSREG_RE)) {
+ if (status & STATUSREG_DA)
+ dvb_ca_en50221_thread_wakeup(ca);
+
+ status = -EAGAIN;
+ goto exit;
+ }
+
+ /* send the amount of data */
+ if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0)
+ goto exit;
+ if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW,
+ bytes_write & 0xff)) != 0)
+ goto exit;
+
+ /* send the buffer */
+ for (i = 0; i < bytes_write; i++) {
+ if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_DATA, buf[i])) != 0)
+ goto exit;
+ }
+
+ /* check for write error (WE should now be 0) */
+ if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
+ goto exit;
+ if (status & STATUSREG_WE) {
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+ status = -EIO;
+ goto exit;
+ }
+ status = bytes_write;
+
+ dprintk("Wrote CA packet for slot %i, connection id 0x%x last_frag:%i size:0x%x\n", slot,
+ buf[0], (buf[1] & 0x80) == 0, bytes_write);
+
+exit:
+ ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN);
+
+exitnowrite:
+ return status;
+}
+EXPORT_SYMBOL(dvb_ca_en50221_cimcu_camchange_irq);
+
+
+
+/* ******************************************************************************** */
+/* EN50221 higher level functions */
+
+
+/**
+ * dvb_ca_en50221_camready_irq - A CAM has been removed => shut it down.
+ *
+ * @ca: CA instance.
+ * @slot: Slot to shut down.
+ */
+static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot)
+{
+ dprintk("%s\n", __func__);
+
+ ca->pub->slot_shutdown(ca->pub, slot);
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+
+ /* need to wake up all processes to check if they're now
+ trying to write to a defunct CAM */
+ wake_up_interruptible(&ca->wait_queue);
+
+ dprintk("Slot %i shutdown\n", slot);
+
+ /* success */
+ return 0;
+}
+EXPORT_SYMBOL(dvb_ca_en50221_cimcu_camready_irq);
+
+
+/**
+ * dvb_ca_en50221_camready_irq - A CAMCHANGE IRQ has occurred.
+ *
+ * @ca: CA instance.
+ * @slot: Slot concerned.
+ * @change_type: One of the DVB_CA_CAMCHANGE_* values.
+ */
+void dvb_ca_en50221_cimcu_camchange_irq(struct dvb_ca_en50221_cimcu *pubca, int slot, int change_type)
+{
+ struct dvb_ca_private *ca = pubca->private;
+
+ dprintk("CAMCHANGE IRQ slot:%i change_type:%i\n", slot, change_type);
+
+ switch (change_type) {
+ case DVB_CA_EN50221_CAMCHANGE_REMOVED:
+ case DVB_CA_EN50221_CAMCHANGE_INSERTED:
+ break;
+
+ default:
+ return;
+ }
+
+ ca->slot_info[slot].camchange_type = change_type;
+ atomic_inc(&ca->slot_info[slot].camchange_count);
+ dvb_ca_en50221_thread_wakeup(ca);
+}
+EXPORT_SYMBOL(dvb_ca_en50221_cimcu_frda_irq);
+
+
+/**
+ * dvb_ca_en50221_cimcu_camready_irq - A CAMREADY IRQ has occurred.
+ *
+ * @ca: CA instance.
+ * @slot: Slot concerned.
+ */
+void dvb_ca_en50221_cimcu_camready_irq(struct dvb_ca_en50221_cimcu *pubca, int slot)
+{
+ struct dvb_ca_private *ca = pubca->private;
+
+ dprintk("CAMREADY IRQ slot:%i\n", slot);
+
+ if (ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) {
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE;
+ dvb_ca_en50221_thread_wakeup(ca);
+ }
+}
+
+
+/**
+ * An FR or DA IRQ has occurred.
+ *
+ * @ca: CA instance.
+ * @slot: Slot concerned.
+ */
+void dvb_ca_en50221_cimcu_frda_irq(struct dvb_ca_en50221_cimcu *pubca, int slot)
+{
+ struct dvb_ca_private *ca = pubca->private;
+ int flags;
+
+ dprintk("FR/DA IRQ slot:%i\n", slot);
+
+ switch (ca->slot_info[slot].slot_state) {
+ case DVB_CA_SLOTSTATE_LINKINIT:
+ flags = ca->pub->read_cam_control(pubca, slot, CTRLIF_STATUS);
+ if (flags & STATUSREG_DA) {
+ dprintk("CAM supports DA IRQ\n");
+ ca->slot_info[slot].da_irq_supported = 1;
+ }
+ break;
+
+ case DVB_CA_SLOTSTATE_RUNNING:
+ if (ca->open)
+ dvb_ca_en50221_thread_wakeup(ca);
+ break;
+ }
+}
+
+
+
+/* ******************************************************************************** */
+/* EN50221 thread functions */
+
+/**
+ * Wake up the DVB CA thread
+ *
+ * @ca: CA instance.
+ */
+static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca)
+{
+
+ dprintk("%s\n", __func__);
+
+ ca->wakeup = 1;
+ mb();
+ wake_up_process(ca->thread);
+}
+
+/**
+ * Update the delay used by the thread.
+ *
+ * @ca: CA instance.
+ */
+static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca)
+{
+ int delay;
+ int curdelay = 100000000;
+ int slot;
+
+ /* Beware of too high polling frequency, because one polling
+ * call might take several hundred milliseconds until timeout!
+ */
+ for (slot = 0; slot < ca->slot_count; slot++) {
+ switch (ca->slot_info[slot].slot_state) {
+ default:
+ case DVB_CA_SLOTSTATE_NONE:
+ delay = HZ * 60; /* 60s */
+ if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+ delay = HZ * 5; /* 5s */
+ break;
+ case DVB_CA_SLOTSTATE_INVALID:
+ delay = HZ * 60; /* 60s */
+ if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+ delay = HZ / 10; /* 100ms */
+ break;
+
+ case DVB_CA_SLOTSTATE_UNINITIALISED:
+ case DVB_CA_SLOTSTATE_WAITREADY:
+ case DVB_CA_SLOTSTATE_VALIDATE:
+ case DVB_CA_SLOTSTATE_WAITFR:
+ case DVB_CA_SLOTSTATE_LINKINIT:
+ delay = HZ / 10; /* 100ms */
+ break;
+
+ case DVB_CA_SLOTSTATE_RUNNING:
+ delay = HZ * 60; /* 60s */
+ if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+ delay = HZ / 10; /* 100ms */
+ if (ca->open) {
+ if ((!ca->slot_info[slot].da_irq_supported) ||
+ (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA)))
+ delay = HZ / 10; /* 100ms */
+ }
+ break;
+ }
+
+ if (delay < curdelay)
+ curdelay = delay;
+ }
+
+ ca->delay = curdelay;
+}
+
+
+
+/**
+ * Kernel thread which monitors CA slots for CAM changes, and performs data transfers.
+ */
+static int dvb_ca_en50221_thread(void *data)
+{
+ struct dvb_ca_private *ca = data;
+ int slot;
+ int flags;
+ int status;
+ int pktcount;
+ void *rxbuf;
+
+ dprintk("%s\n", __func__);
+
+ /* choose the correct initial delay */
+ dvb_ca_en50221_thread_update_delay(ca);
+
+ /* main loop */
+ while (!kthread_should_stop()) {
+ /* sleep for a bit */
+ if (!ca->wakeup) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(ca->delay);
+ if (kthread_should_stop())
+ return 0;
+ }
+ ca->wakeup = 0;
+
+ /* go through all the slots processing them */
+ for (slot = 0; slot < ca->slot_count; slot++) {
+
+ mutex_lock(&ca->slot_info[slot].slot_lock);
+
+ // check the cam status + deal with CAMCHANGEs
+ while (dvb_ca_en50221_check_camstatus(ca, slot)) {
+ /* clear down an old CI slot if necessary */
+ if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE)
+ dvb_ca_en50221_slot_shutdown(ca, slot);
+
+ /* if a CAM is NOW present, initialise it */
+ if (ca->slot_info[slot].camchange_type == DVB_CA_EN50221_CAMCHANGE_INSERTED) {
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_UNINITIALISED;
+ }
+
+ /* we've handled one CAMCHANGE */
+ dvb_ca_en50221_thread_update_delay(ca);
+ atomic_dec(&ca->slot_info[slot].camchange_count);
+ }
+
+ // CAM state machine
+ switch (ca->slot_info[slot].slot_state) {
+ case DVB_CA_SLOTSTATE_NONE:
+ case DVB_CA_SLOTSTATE_INVALID:
+ // no action needed
+ break;
+
+ case DVB_CA_SLOTSTATE_UNINITIALISED:
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITREADY;
+ ca->pub->slot_reset(ca->pub, slot);
+ ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ);
+ break;
+
+ case DVB_CA_SLOTSTATE_WAITREADY:
+ if (time_after(jiffies, ca->slot_info[slot].timeout)) {
+ printk("dvb_ca adaptor %d: PC card did not respond :(\n",
+ ca->dvbdev->adapter->num);
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+ // no other action needed; will automatically change state when ready
+ break;
+
+ case DVB_CA_SLOTSTATE_VALIDATE:
+ if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) {
+ /* we need this extra check for annoying interfaces like the budget-av */
+ if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
+ (ca->pub->poll_slot_status)) {
+ status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+ if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+ }
+
+ printk("dvb_ca adapter %d: Invalid PC card inserted :(\n",
+ ca->dvbdev->adapter->num);
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+ if (dvb_ca_en50221_set_configoption(ca, slot) != 0) {
+ printk("dvb_ca adapter %d: Unable to initialise CAM :(\n",
+ ca->dvbdev->adapter->num);
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+ if (ca->pub->write_cam_control(ca->pub, slot,
+ CTRLIF_COMMAND, CMDREG_RS) != 0) {
+ printk("dvb_ca adapter %d: Unable to reset CAM IF\n",
+ ca->dvbdev->adapter->num);
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+ dprintk("DVB CAM validated successfully\n");
+
+ ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ);
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITFR;
+ ca->wakeup = 1;
+ break;
+
+ case DVB_CA_SLOTSTATE_WAITFR:
+ if (time_after(jiffies, ca->slot_info[slot].timeout)) {
+ printk("dvb_ca adapter %d: DVB CAM did not respond :(\n",
+ ca->dvbdev->adapter->num);
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+
+ flags = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
+ if (flags & STATUSREG_FR) {
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+ ca->wakeup = 1;
+ }
+ break;
+
+ case DVB_CA_SLOTSTATE_LINKINIT:
+ if (dvb_ca_en50221_link_init(ca, slot) != 0) {
+ /* we need this extra check for annoying interfaces like the budget-av */
+ if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
+ (ca->pub->poll_slot_status)) {
+ status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+ if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+ }
+
+ printk("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", ca->dvbdev->adapter->num);
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+
+ if (ca->slot_info[slot].rx_buffer.data == NULL) {
+ rxbuf = vmalloc(RX_BUFFER_SIZE);
+ if (rxbuf == NULL) {
+ printk("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", ca->dvbdev->adapter->num);
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+ dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE);
+ }
+
+ ca->pub->slot_ts_enable(ca->pub, slot);
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING;
+ dvb_ca_en50221_thread_update_delay(ca);
+ printk("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", ca->dvbdev->adapter->num);
+ break;
+
+ case DVB_CA_SLOTSTATE_RUNNING:
+ if (!ca->open)
+ break;
+
+ // poll slots for data
+ pktcount = 0;
+ while ((status = dvb_ca_en50221_read_data(ca, slot, NULL, 0)) > 0) {
+ if (!ca->open)
+ break;
+
+ /* if a CAMCHANGE occurred at some point, do not do any more processing of this slot */
+ if (dvb_ca_en50221_check_camstatus(ca, slot)) {
+ // we dont want to sleep on the next iteration so we can handle the cam change
+ ca->wakeup = 1;
+ break;
+ }
+
+ /* check if we've hit our limit this time */
+ if (++pktcount >= MAX_RX_PACKETS_PER_ITERATION) {
+ // dont sleep; there is likely to be more data to read
+ ca->wakeup = 1;
+ break;
+ }
+ }
+ break;
+ }
+
+ mutex_unlock(&ca->slot_info[slot].slot_lock);
+ }
+ }
+
+ return 0;
+}
+
+
+
+/* ******************************************************************************** */
+/* EN50221 IO interface functions */
+
+/**
+ * Real ioctl implementation.
+ * NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them.
+ *
+ * @inode: Inode concerned.
+ * @file: File concerned.
+ * @cmd: IOCTL command.
+ * @arg: Associated argument.
+ *
+ * @return 0 on success, <0 on error.
+ */
+static int dvb_ca_en50221_io_do_ioctl(struct file *file,
+ unsigned int cmd, void *parg)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dvb_ca_private *ca = dvbdev->priv;
+ int err = 0;
+ int slot;
+
+ dprintk("%s\n", __func__);
+
+ if (mutex_lock_interruptible(&ca->ioctl_mutex)) {
+ printk("ci lock interrupt error\r\n");
+ return -ERESTARTSYS;
+ }
+
+ switch (cmd) {
+ case CA_RESET:
+ dprintk("ci reset---\r\n");
+ for (slot = 0; slot < ca->slot_count; slot++) {
+ mutex_lock(&ca->slot_info[slot].slot_lock);
+ if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) {
+ dvb_ca_en50221_slot_shutdown(ca, slot);
+ if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)
+ dvb_ca_en50221_cimcu_camchange_irq(ca->pub,
+ slot,
+ DVB_CA_EN50221_CAMCHANGE_INSERTED);
+ }
+ mutex_unlock(&ca->slot_info[slot].slot_lock);
+ }
+ ca->next_read_slot = 0;
+ dvb_ca_en50221_thread_wakeup(ca);
+ break;
+
+ case CA_GET_CAP: {
+ struct ca_caps *caps = parg;
+
+ caps->slot_num = ca->slot_count;
+ caps->slot_type = CA_CI_LINK;
+ caps->descr_num = 0;
+ caps->descr_type = 0;
+ break;
+ }
+
+ case CA_GET_SLOT_INFO: {
+ struct ca_slot_info *info = parg;
+
+ if ((info->num > ca->slot_count) || (info->num < 0)) {
+ err = -EINVAL;
+ goto out_unlock;
+ }
+
+ info->type = CA_CI_LINK;
+ info->flags = 0;
+ if ((ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_NONE)
+ && (ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_INVALID)) {
+ info->flags = CA_CI_MODULE_PRESENT;
+ }
+ if (ca->slot_info[info->num].slot_state == DVB_CA_SLOTSTATE_RUNNING) {
+ info->flags |= CA_CI_MODULE_READY;
+ }
+ break;
+ }
+
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+out_unlock:
+ mutex_unlock(&ca->ioctl_mutex);
+ return err;
+}
+static int dvb_usercopy__(struct file *file,
+ unsigned int cmd, unsigned long arg,
+ int (*func)(struct file *file,
+ unsigned int cmd, void *arg))
+{
+ char sbuf[128];
+ void *mbuf = NULL;
+ void *parg = NULL;
+ int err = -EINVAL;
+
+ /* Copy arguments into temp kernel buffer */
+ switch (_IOC_DIR(cmd)) {
+ case _IOC_NONE:
+ /*
+ * For this command, the pointer is actually an integer
+ * argument.
+ */
+ parg = (void *) arg;
+ break;
+ case _IOC_READ: /* some v4l ioctls are marked wrong ... */
+ case _IOC_WRITE:
+ case (_IOC_WRITE | _IOC_READ):
+ if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+ parg = sbuf;
+ } else {
+ /* too big to allocate from stack */
+ mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
+ if (NULL == mbuf)
+ return -ENOMEM;
+ parg = mbuf;
+ }
+
+ err = -EFAULT;
+ if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
+ goto out;
+ break;
+ }
+
+ /* call driver */
+ if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD)
+ err = -ENOTTY;
+
+ if (err < 0)
+ goto out;
+
+ /* Copy results into user buffer */
+ switch (_IOC_DIR(cmd))
+ {
+ case _IOC_READ:
+ case (_IOC_WRITE | _IOC_READ):
+ if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
+ err = -EFAULT;
+ break;
+ }
+
+out:
+ kfree(mbuf);
+ return err;
+}
+
+/**
+ * Wrapper for ioctl implementation.
+ *
+ * @inode: Inode concerned.
+ * @file: File concerned.
+ * @cmd: IOCTL command.
+ * @arg: Associated argument.
+ *
+ * @return 0 on success, <0 on error.
+ */
+static long dvb_ca_en50221_io_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return dvb_usercopy__(file, cmd, arg, dvb_ca_en50221_io_do_ioctl);
+}
+
+
+/**
+ * Implementation of write() syscall.
+ *
+ * @file: File structure.
+ * @buf: Source buffer.
+ * @count: Size of source buffer.
+ * @ppos: Position in file (ignored).
+ *
+ * @return Number of bytes read, or <0 on error.
+ */
+static ssize_t dvb_ca_en50221_io_write(struct file *file,
+ const char __user * buf, size_t count, loff_t * ppos)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dvb_ca_private *ca = dvbdev->priv;
+ u8 slot, connection_id;
+ int status;
+ u8 fragbuf[HOST_LINK_BUF_SIZE];
+ int fragpos = 0;
+ int fraglen;
+ unsigned long timeout;
+ int written;
+
+ dprintk("%s\n", __func__);
+
+ /* Incoming packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
+ if (count < 2)
+ return -EINVAL;
+
+ /* extract slot & connection id */
+ if (copy_from_user(&slot, buf, 1))
+ return -EFAULT;
+ if (copy_from_user(&connection_id, buf + 1, 1))
+ return -EFAULT;
+ buf += 2;
+ count -= 2;
+
+ /* check if the slot is actually running */
+ if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING)
+ return -EINVAL;
+
+ /* fragment the packets & store in the buffer */
+ while (fragpos < count) {
+ fraglen = ca->slot_info[slot].link_buf_size - 2;
+ if (fraglen < 0)
+ break;
+ if (fraglen > HOST_LINK_BUF_SIZE - 2)
+ fraglen = HOST_LINK_BUF_SIZE - 2;
+ if ((count - fragpos) < fraglen)
+ fraglen = count - fragpos;
+
+ fragbuf[0] = connection_id;
+ fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00;
+ status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen);
+ if (status) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ timeout = jiffies + HZ / 2;
+ written = 0;
+ while (!time_after(jiffies, timeout)) {
+ /* check the CAM hasn't been removed/reset in the meantime */
+ if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) {
+ status = -EIO;
+ goto exit;
+ }
+
+ mutex_lock(&ca->slot_info[slot].slot_lock);
+ status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen + 2);
+ mutex_unlock(&ca->slot_info[slot].slot_lock);
+ if (status == (fraglen + 2)) {
+ written = 1;
+ break;
+ }
+ if (status != -EAGAIN)
+ goto exit;
+
+ msleep(1);
+ }
+ if (!written) {
+ status = -EIO;
+ goto exit;
+ }
+
+ fragpos += fraglen;
+ }
+ status = count + 2;
+
+exit:
+ return status;
+}
+
+
+/**
+ * Condition for waking up in dvb_ca_en50221_io_read_condition
+ */
+static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca,
+ int *result, int *_slot)
+{
+ int slot;
+ int slot_count = 0;
+ int idx;
+ size_t fraglen;
+ int connection_id = -1;
+ int found = 0;
+ u8 hdr[2];
+
+ slot = ca->next_read_slot;
+ while ((slot_count < ca->slot_count) && (!found)) {
+ if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING)
+ goto nextslot;
+
+ if (ca->slot_info[slot].rx_buffer.data == NULL)
+ return 0;
+#ifdef READ_LPDU_PKT
+ if (ca->slot_info[slot].rx_offset != 0) {
+ *_slot = slot;
+ return 1;
+ }
+#endif
+ idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
+ while (idx != -1) {
+ dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2);
+ if (connection_id == -1)
+ connection_id = hdr[0];
+ if ((hdr[0] == connection_id)
+#ifndef READ_LPDU_PKT
+ && ((hdr[1] & 0x80) == 0)
+#endif
+ ) {
+ *_slot = slot;
+ found = 1;
+ break;
+ }
+
+ idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen);
+ }
+
+nextslot:
+ slot = (slot + 1) % ca->slot_count;
+ slot_count++;
+ }
+
+ ca->next_read_slot = slot;
+ return found;
+}
+
+
+/**
+ * Implementation of read() syscall.
+ *
+ * @file: File structure.
+ * @buf: Destination buffer.
+ * @count: Size of destination buffer.
+ * @ppos: Position in file (ignored).
+ *
+ * @return Number of bytes read, or <0 on error.
+ */
+static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
+ size_t count, loff_t * ppos)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dvb_ca_private *ca = dvbdev->priv;
+ int status;
+ int result = 0;
+ u8 hdr[2];
+ int slot;
+ int connection_id = -1;
+ size_t idx, idx2;
+ int last_fragment = 0;
+ size_t fraglen;
+ int pktlen;
+ int dispose = 0;
+
+#ifdef READ_LPDU_PKT
+ int offset;
+ u8 flag = 0;
+#endif
+ dprintk("%s\n", __func__);
+
+ /* Outgoing packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
+ if (count < 2)
+ return -EINVAL;
+
+ /* wait for some data */
+ if ((status = dvb_ca_en50221_io_read_condition(ca, &result, &slot)) == 0) {
+
+ /* if we're in nonblocking mode, exit immediately */
+ if (file->f_flags & O_NONBLOCK)
+ return -EWOULDBLOCK;
+
+ /* wait for some data */
+ status = wait_event_interruptible(ca->wait_queue,
+ dvb_ca_en50221_io_read_condition
+ (ca, &result, &slot));
+ }
+ if ((status < 0) || (result < 0)) {
+ if (result)
+ return result;
+ return status;
+ }
+
+ idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
+ pktlen = 2;
+ do {
+ if (idx == -1) {
+ printk("dvb_ca adapter %d: BUG: read packet ended before last_fragment encountered\n", ca->dvbdev->adapter->num);
+ status = -EIO;
+ goto exit;
+ }
+#ifdef READ_LPDU_PKT
+ offset = 2 + ca->slot_info[slot].rx_offset;
+#endif
+ dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2);
+ if (connection_id == -1)
+ connection_id = hdr[0];
+#ifdef READ_LPDU_PKT
+ flag = hdr[1];
+ if (hdr[0] == connection_id) {
+ if (pktlen < count) {
+ if ((pktlen + fraglen - offset) > (count - 2)) {
+ fraglen = (count - 2) - pktlen;
+ ca->slot_info[slot].rx_offset +=
+ fraglen;
+ /* more data for user,
+ but cannot send,
+ so force return to user,
+ rather than dispose of it */
+ flag |= 0x80;
+ } else {
+ ca->slot_info[slot].rx_offset = 0;
+ fraglen -= offset;
+ dispose = 1;
+ }
+
+ status = dvb_ringbuffer_pkt_read_user(
+ &ca->slot_info[slot].rx_buffer,
+ idx,
+ offset,
+ buf + pktlen + 2,
+ fraglen);
+ if (status < 0)
+ goto exit;
+ pktlen += fraglen;
+ }
+
+ last_fragment = 1;
+ }
+#else
+ if (hdr[0] == connection_id) {
+ if (pktlen < count) {
+ if ((pktlen + fraglen - 2) > count) {
+ fraglen = count - pktlen;
+ } else {
+ fraglen -= 2;
+ }
+
+ if ((status = dvb_ringbuffer_pkt_read_user(&ca->slot_info[slot].rx_buffer, idx, 2,
+ buf + pktlen, fraglen)) < 0) {
+ goto exit;
+ }
+ pktlen += fraglen;
+ }
+
+ if ((hdr[1] & 0x80) == 0)
+ last_fragment = 1;
+ dispose = 1;
+ }
+#endif
+ idx2 = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer,
+ idx, &fraglen);
+ if (dispose)
+ dvb_ringbuffer_pkt_dispose(&ca->slot_info[slot].rx_buffer, idx);
+ idx = idx2;
+ dispose = 0;
+ } while (!last_fragment);
+
+ hdr[0] = slot;
+ hdr[1] = connection_id;
+ status = copy_to_user(buf, hdr, 2);
+ if (status) {
+ status = -EFAULT;
+ goto exit;
+ }
+ status = pktlen;
+
+#ifdef READ_LPDU_PKT
+ hdr[0] = flag;
+ hdr[1] = 0;
+
+ status = copy_to_user(buf + 2, hdr, 2);
+ if (status) {
+ status = -EFAULT;
+ goto exit;
+ }
+ status = pktlen + 2;
+#endif
+exit:
+ return status;
+}
+
+
+/**
+ * Implementation of file open syscall.
+ *
+ * @inode: Inode concerned.
+ * @file: File concerned.
+ *
+ * @return 0 on success, <0 on failure.
+ */
+static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dvb_ca_private *ca = dvbdev->priv;
+ int err;
+ int i;
+
+ dprintk("%s\n", __func__);
+
+ if (!try_module_get(ca->pub->owner))
+ return -EIO;
+
+ err = dvb_generic_open(inode, file);
+ if (err < 0) {
+ module_put(ca->pub->owner);
+ return err;
+ }
+
+ for (i = 0; i < ca->slot_count; i++) {
+
+ if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) {
+ if (ca->slot_info[i].rx_buffer.data != NULL) {
+ /* it is safe to call this here without locks because
+ * ca->open == 0. Data is not read in this case */
+ dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer);
+ }
+ }
+ }
+
+ ca->open = 1;
+ dvb_ca_en50221_thread_update_delay(ca);
+ dvb_ca_en50221_thread_wakeup(ca);
+
+ dvb_ca_private_get(ca);
+
+ return 0;
+}
+
+
+/**
+ * Implementation of file close syscall.
+ *
+ * @inode: Inode concerned.
+ * @file: File concerned.
+ *
+ * @return 0 on success, <0 on failure.
+ */
+static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dvb_ca_private *ca = dvbdev->priv;
+ int err;
+
+ dprintk("%s\n", __func__);
+
+ /* mark the CA device as closed */
+ ca->open = 0;
+ dvb_ca_en50221_thread_update_delay(ca);
+
+ err = dvb_generic_release(inode, file);
+
+ module_put(ca->pub->owner);
+
+ dvb_ca_private_put(ca);
+
+ return err;
+}
+
+
+/**
+ * Implementation of poll() syscall.
+ *
+ * @file: File concerned.
+ * @wait: poll wait table.
+ *
+ * @return Standard poll mask.
+ */
+static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table * wait)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dvb_ca_private *ca = dvbdev->priv;
+ unsigned int mask = 0;
+ int slot;
+ int result = 0;
+
+ dprintk("%s\n", __func__);
+
+ if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) {
+ mask |= POLLIN;
+ }
+
+ /* if there is something, return now */
+ if (mask)
+ return mask;
+
+ /* wait for something to happen */
+ poll_wait(file, &ca->wait_queue, wait);
+
+ if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) {
+ mask |= POLLIN;
+ }
+
+ return mask;
+}
+EXPORT_SYMBOL(dvb_ca_en50221_cimcu_init);
+
+#ifdef CONFIG_AMLOGIC_DVB_COMPAT
+static long dvb_ca_en50221_compat_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long args)
+{
+ unsigned long ret;
+#ifdef CONFIG_COMPAT
+ args = (unsigned long)compat_ptr(args);
+#endif
+ ret = dvb_ca_en50221_io_ioctl(filp, cmd, args);
+ return ret;
+}
+#endif
+
+static const struct file_operations dvb_ca_fops = {
+ .owner = THIS_MODULE,
+ .read = dvb_ca_en50221_io_read,
+ .write = dvb_ca_en50221_io_write,
+ .unlocked_ioctl = dvb_ca_en50221_io_ioctl,
+ .open = dvb_ca_en50221_io_open,
+ .release = dvb_ca_en50221_io_release,
+ .poll = dvb_ca_en50221_io_poll,
+ .llseek = noop_llseek,
+#ifdef CONFIG_AMLOGIC_DVB_COMPAT
+ .compat_ioctl = dvb_ca_en50221_compat_ioctl,
+#endif
+};
+
+static const struct dvb_device dvbdev_ca = {
+ .priv = NULL,
+ .users = 1,
+ .readers = 1,
+ .writers = 1,
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
+ .name = "dvb-ca-en50221",
+#endif
+ .fops = &dvb_ca_fops,
+};
+
+/* ******************************************************************************** */
+/* Initialisation/shutdown functions */
+
+
+/**
+ * Initialise a new DVB CA EN50221 interface device.
+ *
+ * @dvb_adapter: DVB adapter to attach the new CA device to.
+ * @ca: The dvb_ca instance.
+ * @flags: Flags describing the CA device (DVB_CA_FLAG_*).
+ * @slot_count: Number of slots supported.
+ *
+ * @return 0 on success, nonzero on failure
+ */
+int dvb_ca_en50221_cimcu_init(struct dvb_adapter *dvb_adapter,
+ struct dvb_ca_en50221_cimcu *pubca, int flags, int slot_count)
+{
+ int ret;
+ struct dvb_ca_private *ca = NULL;
+ int i;
+
+ dprintk("%s\n", __func__);
+ printk("---%s\n", __func__);
+ if (slot_count < 1)
+ return -EINVAL;
+
+ /* initialise the system data */
+ if ((ca = kzalloc(sizeof(struct dvb_ca_private), GFP_KERNEL)) == NULL) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+ kref_init(&ca->refcount);
+ ca->pub = pubca;
+ ca->flags = flags;
+ ca->slot_count = slot_count;
+ if ((ca->slot_info = kcalloc(slot_count, sizeof(struct dvb_ca_slot), GFP_KERNEL)) == NULL) {
+ ret = -ENOMEM;
+ goto free_ca;
+ }
+ init_waitqueue_head(&ca->wait_queue);
+ ca->open = 0;
+ ca->wakeup = 0;
+ ca->next_read_slot = 0;
+ pubca->private = ca;
+
+ /* register the DVB device */
+ ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA, 0);
+ if (ret)
+ goto free_slot_info;
+
+ /* now initialise each slot */
+ for (i = 0; i < slot_count; i++) {
+ memset(&ca->slot_info[i], 0, sizeof(struct dvb_ca_slot));
+ ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE;
+ atomic_set(&ca->slot_info[i].camchange_count, 0);
+ ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED;
+ mutex_init(&ca->slot_info[i].slot_lock);
+ }
+
+ mutex_init(&ca->ioctl_mutex);
+
+ if (signal_pending(current)) {
+ ret = -EINTR;
+ goto unregister_device;
+ }
+ mb();
+
+ /* create a kthread for monitoring this CA device */
+ ca->thread = kthread_run(dvb_ca_en50221_thread, ca, "kdvb-ca-%i:%i",
+ ca->dvbdev->adapter->num, ca->dvbdev->id);
+ if (IS_ERR(ca->thread)) {
+ ret = PTR_ERR(ca->thread);
+ printk("dvb_ca_init: failed to start kernel_thread (%d)\n",
+ ret);
+ goto unregister_device;
+ }
+ return 0;
+
+unregister_device:
+ dvb_unregister_device(ca->dvbdev);
+free_slot_info:
+ kfree(ca->slot_info);
+free_ca:
+ kfree(ca);
+exit:
+ pubca->private = NULL;
+ return ret;
+}
+EXPORT_SYMBOL(dvb_ca_en50221_cimcu_release);
+
+
+
+/**
+ * Release a DVB CA EN50221 interface device.
+ *
+ * @ca_dev: The dvb_device_t instance for the CA device.
+ * @ca: The associated dvb_ca instance.
+ */
+void dvb_ca_en50221_cimcu_release(struct dvb_ca_en50221_cimcu *pubca)
+{
+ struct dvb_ca_private *ca = pubca->private;
+ int i;
+
+ dprintk("%s\n", __func__);
+
+ /* shutdown the thread if there was one */
+ kthread_stop(ca->thread);
+
+ for (i = 0; i < ca->slot_count; i++) {
+ dvb_ca_en50221_slot_shutdown(ca, i);
+ }
+ dvb_ca_private_put(ca);
+ pubca->private = NULL;
+}
diff --git a/drivers/stream_input/parser/dvb_ci/cimcu/dvb_ca_en50221_cimcu.h b/drivers/stream_input/parser/dvb_ci/cimcu/dvb_ca_en50221_cimcu.h
new file mode 100644
index 0000000..7102b3c
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_ci/cimcu/dvb_ca_en50221_cimcu.h
@@ -0,0 +1,135 @@
+/*
+ * dvb_ca.h: generic DVB functions for EN50221 CA interfaces
+ *
+ * Copyright (C) 2004 Andrew de Quincey
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 _DVB_CA_EN50221_CIMCU_H_
+#define _DVB_CA_EN50221_CIMCU_H_
+
+#include <linux/list.h>
+#include <linux/dvb/ca.h>
+
+#include "../cimax/dvbdev.h"
+
+#define DVB_CA_EN50221_POLL_CAM_PRESENT 1
+#define DVB_CA_EN50221_POLL_CAM_CHANGED 2
+#define DVB_CA_EN50221_POLL_CAM_READY 4
+
+#define DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE 1
+#define DVB_CA_EN50221_FLAG_IRQ_FR 2
+#define DVB_CA_EN50221_FLAG_IRQ_DA 4
+
+#define DVB_CA_EN50221_CAMCHANGE_REMOVED 0
+#define DVB_CA_EN50221_CAMCHANGE_INSERTED 1
+
+/**
+ * struct dvb_ca_en50221- Structure describing a CA interface
+ *
+ * @owner: the module owning this structure
+ * @read_attribute_mem: function for reading attribute memory on the CAM
+ * @write_attribute_mem: function for writing attribute memory on the CAM
+ * @read_cam_control: function for reading the control interface on the CAM
+ * @write_cam_control: function for reading the control interface on the CAM
+ * @slot_reset: function to reset the CAM slot
+ * @slot_shutdown: function to shutdown a CAM slot
+ * @slot_ts_enable: function to enable the Transport Stream on a CAM slot
+ * @poll_slot_status: function to poll slot status. Only necessary if
+ * DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE is not set.
+ * @data: private data, used by caller.
+ * @private: Opaque data used by the dvb_ca core. Do not modify!
+ *
+ * NOTE: the read_*, write_* and poll_slot_status functions will be
+ * called for different slots concurrently and need to use locks where
+ * and if appropriate. There will be no concurrent access to one slot.
+ */
+struct dvb_ca_en50221_cimcu {
+ struct module *owner;
+
+ int (*read_attribute_mem)(struct dvb_ca_en50221_cimcu *ca,
+ int slot, int address);
+ int (*write_attribute_mem)(struct dvb_ca_en50221_cimcu *ca,
+ int slot, int address, u8 value);
+
+ int (*read_cam_control)(struct dvb_ca_en50221_cimcu *ca,
+ int slot, u8 address);
+ int (*write_cam_control)(struct dvb_ca_en50221_cimcu *ca,
+ int slot, u8 address, u8 value);
+
+ int (*slot_reset)(struct dvb_ca_en50221_cimcu *ca, int slot);
+ int (*slot_shutdown)(struct dvb_ca_en50221_cimcu *ca, int slot);
+ int (*slot_ts_enable)(struct dvb_ca_en50221_cimcu *ca, int slot);
+
+ int (*poll_slot_status)(struct dvb_ca_en50221_cimcu *ca, int slot, int open);
+
+ void *data;
+
+ void *private;
+};
+
+/*
+ * Functions for reporting IRQ events
+ */
+
+/**
+ * dvb_ca_en50221_camchange_irq - A CAMCHANGE IRQ has occurred.
+ *
+ * @pubca: CA instance.
+ * @slot: Slot concerned.
+ * @change_type: One of the DVB_CA_CAMCHANGE_* values
+ */
+void dvb_ca_en50221_cimcu_camchange_irq(struct dvb_ca_en50221_cimcu *pubca, int slot,
+ int change_type);
+
+/**
+ * dvb_ca_en50221_camready_irq - A CAMREADY IRQ has occurred.
+ *
+ * @pubca: CA instance.
+ * @slot: Slot concerned.
+ */
+void dvb_ca_en50221_cimcu_camready_irq(struct dvb_ca_en50221_cimcu *pubca, int slot);
+
+/**
+ * dvb_ca_en50221_frda_irq - An FR or a DA IRQ has occurred.
+ *
+ * @ca: CA instance.
+ * @slot: Slot concerned.
+ */
+void dvb_ca_en50221_cimcu_frda_irq(struct dvb_ca_en50221_cimcu *ca, int slot);
+
+/*
+ * Initialisation/shutdown functions
+ */
+
+/**
+ * dvb_ca_en50221_init - Initialise a new DVB CA device.
+ *
+ * @dvb_adapter: DVB adapter to attach the new CA device to.
+ * @ca: The dvb_ca instance.
+ * @flags: Flags describing the CA device (DVB_CA_EN50221_FLAG_*).
+ * @slot_count: Number of slots supported.
+ *
+ * @return 0 on success, nonzero on failure
+ */
+extern int dvb_ca_en50221_cimcu_init(struct dvb_adapter *dvb_adapter,
+ struct dvb_ca_en50221_cimcu *ca, int flags,
+ int slot_count);
+
+/**
+ * dvb_ca_en50221_release - Release a DVB CA device.
+ *
+ * @ca: The associated dvb_ca instance.
+ */
+extern void dvb_ca_en50221_cimcu_release(struct dvb_ca_en50221_cimcu *ca);
+
+#endif
diff --git a/drivers/stream_input/parser/dvb_common.c b/drivers/stream_input/parser/dvb_common.c
new file mode 100644
index 0000000..ecea691
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_common.c
@@ -0,0 +1,17 @@
+/*
+ * ../hardware/amlogic/media_modules/drivers/stream_input/parser/dvb_common.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
diff --git a/drivers/stream_input/parser/dvb_common.h b/drivers/stream_input/parser/dvb_common.h
new file mode 100644
index 0000000..eae2625
--- /dev/null
+++ b/drivers/stream_input/parser/dvb_common.h
@@ -0,0 +1,25 @@
+/*
+ * ../hardware/amlogic/media_modules/drivers/stream_input/parser/dvb_common.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 __DVB_COMMON_H__
+#define __DVB_COMMON_H__
+
+#include <linux/amlogic/aml_dvb_extern.h>
+
+#include "dvb_frontend.h"
+
+#endif /* __DVB_COMMON_H__ */
diff --git a/drivers/stream_input/parser/esparser.c b/drivers/stream_input/parser/esparser.c
new file mode 100644
index 0000000..2675551
--- /dev/null
+++ b/drivers/stream_input/parser/esparser.c
@@ -0,0 +1,1043 @@
+/*
+ * drivers/amlogic/media/stream_input/parser/esparser.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/types.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/amlogic/media/frame_sync/ptsserv.h>
+
+#include <linux/uaccess.h>
+#include <linux/atomic.h>
+
+/* #include <mach/am_regs.h> */
+#include <linux/delay.h>
+
+#include "../../frame_provider/decoder/utils/vdec.h"
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "../amports/streambuf_reg.h"
+#include "../amports/streambuf.h"
+#include "esparser.h"
+#include "../amports/amports_priv.h"
+#include "../amports/thread_rw.h"
+
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+
+
+
+#define SAVE_SCR 0
+
+#define ES_START_CODE_PATTERN 0x00000100
+#define ES_START_CODE_MASK 0xffffff00
+#define SEARCH_PATTERN_LEN 512
+#define ES_PARSER_POP READ_PARSER_REG(PFIFO_DATA)
+
+#define PARSER_WRITE (ES_WRITE | ES_PARSER_START)
+#define PARSER_VIDEO (ES_TYPE_VIDEO)
+#define PARSER_AUDIO (ES_TYPE_AUDIO)
+#define PARSER_SUBPIC (ES_TYPE_SUBTITLE)
+#define PARSER_PASSTHROUGH (ES_PASSTHROUGH | ES_PARSER_START)
+#define PARSER_AUTOSEARCH (ES_SEARCH | ES_PARSER_START)
+#define PARSER_DISCARD (ES_DISCARD | ES_PARSER_START)
+#define PARSER_BUSY (ES_PARSER_BUSY)
+
+#define MAX_DRM_PACKAGE_SIZE 0x500000
+
+
+static unsigned char *search_pattern;
+static dma_addr_t search_pattern_map;
+static u32 audio_real_wp;
+static u32 audio_buf_start;
+static u32 audio_buf_end;
+
+static const char esparser_id[] = "esparser-id";
+
+static DECLARE_WAIT_QUEUE_HEAD(wq);
+
+
+static u32 search_done;
+static u32 video_data_parsed;
+static u32 audio_data_parsed;
+static atomic_t esparser_use_count = ATOMIC_INIT(0);
+static DEFINE_MUTEX(esparser_mutex);
+
+static inline u32 get_buf_wp(u32 type)
+{
+ if (type == BUF_TYPE_AUDIO)
+ return audio_real_wp;
+ else
+ return 0;
+}
+static inline u32 get_buf_start(u32 type)
+{
+ if (type == BUF_TYPE_AUDIO)
+ return audio_buf_start;
+ else
+ return 0;
+}
+static inline u32 get_buf_end(u32 type)
+{
+ if (type == BUF_TYPE_AUDIO)
+ return audio_buf_end;
+ else
+ return 0;
+}
+static void set_buf_wp(u32 type, u32 wp)
+{
+ if (type == BUF_TYPE_AUDIO) {
+ audio_real_wp = wp;
+ WRITE_AIU_REG(AIU_MEM_AIFIFO_MAN_WP, wp/* & 0xffffff00*/);
+ }
+ return;
+}
+
+static irqreturn_t esparser_isr(int irq, void *dev_id)
+{
+ u32 int_status = READ_PARSER_REG(PARSER_INT_STATUS);
+
+ WRITE_PARSER_REG(PARSER_INT_STATUS, int_status);
+
+ if (int_status & PARSER_INTSTAT_SC_FOUND) {
+ WRITE_PARSER_REG(PFIFO_RD_PTR, 0);
+ WRITE_PARSER_REG(PFIFO_WR_PTR, 0);
+ search_done = 1;
+ wake_up_interruptible(&wq);
+ }
+ return IRQ_HANDLED;
+}
+
+static inline u32 buf_wp(u32 type)
+{
+ u32 wp;
+
+ if ((READ_PARSER_REG(PARSER_ES_CONTROL) & ES_VID_MAN_RD_PTR) == 0) {
+ wp =
+#if 1/* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
+ (type == BUF_TYPE_HEVC) ? READ_VREG(HEVC_STREAM_WR_PTR) :
+#endif
+ (type == BUF_TYPE_VIDEO) ? READ_VREG(VLD_MEM_VIFIFO_WP) :
+ (type == BUF_TYPE_AUDIO) ?
+ READ_AIU_REG(AIU_MEM_AIFIFO_MAN_WP) :
+ READ_PARSER_REG(PARSER_SUB_START_PTR);
+ } else {
+ wp =
+#if 1/* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
+ (type == BUF_TYPE_HEVC) ? READ_PARSER_REG(PARSER_VIDEO_WP) :
+#endif
+ (type == BUF_TYPE_VIDEO) ? READ_PARSER_REG(PARSER_VIDEO_WP) :
+ (type == BUF_TYPE_AUDIO) ?
+ READ_AIU_REG(AIU_MEM_AIFIFO_MAN_WP) :
+ READ_PARSER_REG(PARSER_SUB_START_PTR);
+ }
+
+ return wp;
+}
+
+static int esparser_stbuf_write(struct stream_buf_s *stbuf, const u8 *buf, u32 count)
+{
+ size_t r = count;
+ const char __user *p = buf;
+
+ u32 len = 0;
+ u32 parser_type;
+ int ret;
+ u32 wp;
+ dma_addr_t dma_addr = 0;
+ u32 type = stbuf->type;
+
+ VDEC_PRINT_FUN_LINENO(__func__, __LINE__);
+ if (type == BUF_TYPE_HEVC)
+ parser_type = PARSER_VIDEO;
+ else if (type == BUF_TYPE_VIDEO)
+ parser_type = PARSER_VIDEO;
+ else if (type == BUF_TYPE_AUDIO)
+ parser_type = PARSER_AUDIO;
+ else
+ parser_type = PARSER_SUBPIC;
+
+ wp = buf_wp(type);
+
+ if (r > 0) {
+ if (stbuf->is_phybuf)
+ len = count;
+ else {
+ len = min_t(size_t, r, (size_t) FETCHBUF_SIZE);
+
+ if (copy_from_user(fetchbuf, p, len))
+ return -EFAULT;
+ dma_addr = dma_map_single(
+ amports_get_dma_device(), fetchbuf,
+ FETCHBUF_SIZE, DMA_TO_DEVICE);
+ if (dma_mapping_error(amports_get_dma_device(),
+ (dma_addr_t) dma_addr))
+ return -EFAULT;
+
+ }
+
+ /* wmb(); don't need */
+ /* reset the Write and read pointer to zero again */
+ WRITE_PARSER_REG(PFIFO_RD_PTR, 0);
+ WRITE_PARSER_REG(PFIFO_WR_PTR, 0);
+
+ WRITE_PARSER_REG_BITS(PARSER_CONTROL, len, ES_PACK_SIZE_BIT,
+ ES_PACK_SIZE_WID);
+ WRITE_PARSER_REG_BITS(PARSER_CONTROL,
+ parser_type | PARSER_WRITE |
+ PARSER_AUTOSEARCH, ES_CTRL_BIT,
+ ES_CTRL_WID);
+
+ if (stbuf->is_phybuf) {
+ u32 buf_32 = (unsigned long)buf & 0xffffffff;
+ WRITE_PARSER_REG(PARSER_FETCH_ADDR, buf_32);
+ } else {
+ WRITE_PARSER_REG(PARSER_FETCH_ADDR, dma_addr);
+ dma_unmap_single(amports_get_dma_device(), dma_addr,
+ FETCHBUF_SIZE, DMA_TO_DEVICE);
+ }
+
+ search_done = 0;
+ if (!(stbuf->drm_flag & TYPE_PATTERN)) {
+ WRITE_PARSER_REG(PARSER_FETCH_CMD,
+ (7 << FETCH_ENDIAN) | len);
+ WRITE_PARSER_REG(PARSER_FETCH_ADDR, search_pattern_map);
+ WRITE_PARSER_REG(PARSER_FETCH_CMD,
+ (7 << FETCH_ENDIAN) | SEARCH_PATTERN_LEN);
+ } else {
+ WRITE_PARSER_REG(PARSER_FETCH_CMD,
+ (7 << FETCH_ENDIAN) | (len + 512));
+ }
+
+ ret = wait_event_interruptible_timeout(wq, search_done != 0,
+ HZ / 5);
+ if (ret == 0) {
+ WRITE_PARSER_REG(PARSER_FETCH_CMD, 0);
+
+ if (wp == buf_wp(type)) {
+ /*no data fetched */
+ return -EAGAIN;
+ } else {
+ pr_info("W Timeout, but fetch ok,");
+ pr_info("type %d len=%d,wpdiff=%d, isphy %x\n",
+ type, len, wp - buf_wp(type), stbuf->is_phybuf);
+ }
+ } else if (ret < 0)
+ return -ERESTARTSYS;
+ }
+
+ if ((type == BUF_TYPE_VIDEO)
+ || (has_hevc_vdec() && (type == BUF_TYPE_HEVC)))
+ video_data_parsed += len;
+ else if (type == BUF_TYPE_AUDIO)
+ audio_data_parsed += len;
+
+ threadrw_update_buffer_level(stbuf, len);
+ VDEC_PRINT_FUN_LINENO(__func__, __LINE__);
+
+ return len;
+}
+
+static ssize_t _esparser_write(const char __user *buf,
+ size_t count, struct stream_buf_s *stbuf, int isphybuf)
+{
+ return esparser_stbuf_write(stbuf, buf, count);
+}
+
+static ssize_t _esparser_write_s(const char __user *buf,
+ size_t count, struct stream_buf_s *stbuf)
+{
+ size_t r = count;
+ const char __user *p = buf;
+ u32 len = 0;
+ int ret;
+ u32 wp, buf_start, buf_end;
+ u32 type = stbuf->type;
+ void *vaddr = NULL;
+
+ if (type != BUF_TYPE_AUDIO)
+ BUG();
+ wp = get_buf_wp(type);
+ buf_end = get_buf_end(type) + 8;
+ buf_start = get_buf_start(type);
+ /*pr_info("write wp 0x%x, count %d, start 0x%x, end 0x%x\n",
+ * wp, (u32)count, buf_start, buf_end);*/
+ if (wp + count > buf_end) {
+ if (wp == buf_end) {
+ wp = buf_start;
+ set_buf_wp(type, wp);
+ return -EAGAIN;
+ }
+ vaddr = codec_mm_phys_to_virt(wp);
+ ret = copy_from_user(vaddr, p, buf_end - wp);
+ if (ret > 0) {
+ len += buf_end - wp - ret;
+ codec_mm_dma_flush(vaddr, len, DMA_TO_DEVICE);
+ wp += len;
+ pr_info("copy from user not finished\n");
+ set_buf_wp(type, wp);
+ goto end_write;
+ } else if (ret == 0) {
+ len += buf_end - wp;
+ codec_mm_dma_flush(vaddr, len, DMA_TO_DEVICE);
+ wp = buf_start;
+ r = count - len;
+ set_buf_wp(type, wp);
+ } else {
+ pr_info("copy from user failed 1\n");
+ pr_info("w wp 0x%x, count %d, start 0x%x end 0x%x\n",
+ wp, (u32)count, buf_start, buf_end);
+ return -EAGAIN;
+ }
+ }
+
+ vaddr = codec_mm_phys_to_virt(wp);
+ ret = copy_from_user(vaddr, p + len, r);
+ if (ret >= 0) {
+ len += r - ret;
+ codec_mm_dma_flush(vaddr, r - ret, DMA_TO_DEVICE);
+ if (ret > 0)
+ pr_info("copy from user not finished 2\n");
+ wp += r - ret;
+ set_buf_wp(type, wp);
+ } else {
+ pr_info("copy from user failed 2\n");
+ return -EAGAIN;
+ }
+
+end_write:
+ if (type == BUF_TYPE_AUDIO)
+ {
+ audio_data_parsed += len;
+ threadrw_update_buffer_level(stbuf, len);
+ }
+
+ return len;
+}
+
+s32 es_vpts_checkin_us64(struct stream_buf_s *buf, u64 us64)
+{
+ u32 passed;
+
+ if (buf->write_thread)
+ passed = threadrw_dataoffset(buf);
+ else
+ passed = video_data_parsed;
+ return pts_checkin_offset_us64(PTS_TYPE_VIDEO, passed, us64);
+
+}
+
+s32 es_apts_checkin_us64(struct stream_buf_s *buf, u64 us64)
+{
+ u32 passed;
+
+ if (buf->write_thread)
+ passed = threadrw_dataoffset(buf);
+ else
+ passed = audio_data_parsed;
+ return pts_checkin_offset_us64(PTS_TYPE_AUDIO, passed, us64);
+}
+
+s32 es_vpts_checkin(struct stream_buf_s *buf, u32 pts)
+{
+#if 0
+ if (buf->first_tstamp == INVALID_PTS) {
+ buf->flag |= BUF_FLAG_FIRST_TSTAMP;
+ buf->first_tstamp = pts;
+ return 0;
+ }
+#endif
+ u32 passed = 0;
+
+ mutex_lock(&esparser_mutex);
+ passed = video_data_parsed + threadrw_buffer_level(buf);
+ mutex_unlock(&esparser_mutex);
+
+ return pts_checkin_offset(PTS_TYPE_VIDEO, passed, pts);
+
+}
+
+s32 es_apts_checkin(struct stream_buf_s *buf, u32 pts)
+{
+#if 0
+ if (buf->first_tstamp == INVALID_PTS) {
+ buf->flag |= BUF_FLAG_FIRST_TSTAMP;
+ buf->first_tstamp = pts;
+
+ return 0;
+ }
+#endif
+ u32 passed = 0;
+ mutex_lock(&esparser_mutex);
+ passed = audio_data_parsed + threadrw_buffer_level(buf);
+ mutex_unlock(&esparser_mutex);
+
+ return pts_checkin_offset(PTS_TYPE_AUDIO, passed, pts);
+}
+
+s32 esparser_init(struct stream_buf_s *buf, struct vdec_s *vdec)
+{
+ s32 r = 0;
+ u32 pts_type;
+ u32 parser_sub_start_ptr;
+ u32 parser_sub_end_ptr;
+ u32 parser_sub_rp;
+ bool first_use = false;
+ /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
+ VDEC_PRINT_FUN_LINENO(__func__, __LINE__);
+
+ if (has_hevc_vdec() && (buf->type == BUF_TYPE_HEVC))
+ pts_type = PTS_TYPE_HEVC;
+ else
+ /* #endif */
+ if (buf->type == BUF_TYPE_VIDEO)
+ pts_type = PTS_TYPE_VIDEO;
+ else if (buf->type == BUF_TYPE_AUDIO)
+ pts_type = PTS_TYPE_AUDIO;
+ else if (buf->type == BUF_TYPE_SUBTITLE)
+ pts_type = PTS_TYPE_MAX;
+ else
+ return -EINVAL;
+ mutex_lock(&esparser_mutex);
+ parser_sub_start_ptr = READ_PARSER_REG(PARSER_SUB_START_PTR);
+ parser_sub_end_ptr = READ_PARSER_REG(PARSER_SUB_END_PTR);
+ parser_sub_rp = READ_PARSER_REG(PARSER_SUB_RP);
+
+ buf->flag |= BUF_FLAG_PARSER;
+
+ if (atomic_add_return(1, &esparser_use_count) == 1) {
+ first_use = true;
+
+ if (fetchbuf == 0) {
+ pr_info("%s: no fetchbuf\n", __func__);
+ r = -ENOMEM;
+ goto Err_1;
+ }
+
+ if (search_pattern == NULL) {
+ search_pattern = kcalloc(1,
+ SEARCH_PATTERN_LEN,
+ GFP_KERNEL);
+
+ if (search_pattern == NULL) {
+ pr_err("%s: no search_pattern\n", __func__);
+ r = -ENOMEM;
+ goto Err_1;
+ }
+
+ /* build a fake start code to get parser interrupt */
+ search_pattern[0] = 0x00;
+ search_pattern[1] = 0x00;
+ search_pattern[2] = 0x01;
+ search_pattern[3] = 0xff;
+
+ search_pattern_map = dma_map_single(
+ amports_get_dma_device(),
+ search_pattern,
+ SEARCH_PATTERN_LEN,
+ DMA_TO_DEVICE);
+ }
+
+ /* reset PARSER with first esparser_init() call */
+ WRITE_RESET_REG(RESET1_REGISTER, RESET_PARSER);
+/* for recorded file and local play, this can't change the input source*/
+/* TS data path */
+/*
+#ifndef CONFIG_AM_DVB
+ WRITE_DEMUX_REG(FEC_INPUT_CONTROL, 0);
+#else
+ tsdemux_set_reset_flag();
+#endif */
+
+ CLEAR_DEMUX_REG_MASK(TS_HIU_CTL, 1 << USE_HI_BSF_INTERFACE);
+ CLEAR_DEMUX_REG_MASK(TS_HIU_CTL_2, 1 << USE_HI_BSF_INTERFACE);
+ CLEAR_DEMUX_REG_MASK(TS_HIU_CTL_3, 1 << USE_HI_BSF_INTERFACE);
+
+ CLEAR_DEMUX_REG_MASK(TS_FILE_CONFIG, (1 << TS_HIU_ENABLE));
+
+ WRITE_PARSER_REG(PARSER_CONFIG,
+ (10 << PS_CFG_PFIFO_EMPTY_CNT_BIT) |
+ (1 << PS_CFG_MAX_ES_WR_CYCLE_BIT) |
+ (16 << PS_CFG_MAX_FETCH_CYCLE_BIT));
+
+ WRITE_PARSER_REG(PFIFO_RD_PTR, 0);
+ WRITE_PARSER_REG(PFIFO_WR_PTR, 0);
+
+ WRITE_PARSER_REG(PARSER_SEARCH_PATTERN, ES_START_CODE_PATTERN);
+ WRITE_PARSER_REG(PARSER_SEARCH_MASK, ES_START_CODE_MASK);
+
+ WRITE_PARSER_REG(PARSER_CONFIG,
+ (10 << PS_CFG_PFIFO_EMPTY_CNT_BIT) |
+ (1 << PS_CFG_MAX_ES_WR_CYCLE_BIT) |
+ PS_CFG_STARTCODE_WID_24 |
+ PS_CFG_PFIFO_ACCESS_WID_8 |
+ /* single byte pop */
+ (16 << PS_CFG_MAX_FETCH_CYCLE_BIT));
+
+ WRITE_PARSER_REG(PARSER_CONTROL, PARSER_AUTOSEARCH);
+
+ }
+
+ /* hook stream buffer with PARSER */
+ if (has_hevc_vdec() && (pts_type == PTS_TYPE_HEVC)) {
+ WRITE_PARSER_REG(PARSER_VIDEO_START_PTR, vdec->input.start);
+ WRITE_PARSER_REG(PARSER_VIDEO_END_PTR, vdec->input.start
+ + vdec->input.size - 8);
+
+ if (vdec_single(vdec)) {
+ CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL,
+ ES_VID_MAN_RD_PTR);
+
+ /* set vififo_vbuf_rp_sel=>hevc */
+ WRITE_VREG(DOS_GEN_CTRL0, 3 << 1);
+
+ /* set use_parser_vbuf_wp */
+ SET_VREG_MASK(HEVC_STREAM_CONTROL,
+ (1 << 3) | (0 << 4));
+ /* set stream_fetch_enable */
+ SET_VREG_MASK(HEVC_STREAM_CONTROL, 1);
+
+ if (buf->no_parser) {
+ /*set endian for non-parser mode */
+ SET_VREG_MASK(HEVC_STREAM_CONTROL, 7 << 4);
+ }
+
+ /* set stream_buffer_hole with 256 bytes */
+ SET_VREG_MASK(HEVC_STREAM_FIFO_CTL, (1 << 29));
+ } else {
+ SET_PARSER_REG_MASK(PARSER_ES_CONTROL,
+ ES_VID_MAN_RD_PTR);
+ WRITE_PARSER_REG(PARSER_VIDEO_WP, vdec->input.start);
+ WRITE_PARSER_REG(PARSER_VIDEO_RP, vdec->input.start);
+ }
+ video_data_parsed = 0;
+ } else if (pts_type == PTS_TYPE_VIDEO) {
+ WRITE_PARSER_REG(PARSER_VIDEO_START_PTR,
+ vdec->input.start);
+ WRITE_PARSER_REG(PARSER_VIDEO_END_PTR,
+ vdec->input.start + vdec->input.size - 8);
+
+ if (vdec_single(vdec) || (vdec_get_debug_flags() & 0x2)) {
+ if (vdec_get_debug_flags() & 0x2)
+ pr_info("%s %d\n", __func__, __LINE__);
+ CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL,
+ ES_VID_MAN_RD_PTR);
+
+ WRITE_VREG(VLD_MEM_VIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ CLEAR_VREG_MASK(VLD_MEM_VIFIFO_BUF_CNTL,
+ MEM_BUFCTRL_INIT);
+
+ if (has_hevc_vdec()) {
+ /* set vififo_vbuf_rp_sel=>vdec */
+ WRITE_VREG(DOS_GEN_CTRL0, 0);
+ }
+ } else {
+ SET_PARSER_REG_MASK(PARSER_ES_CONTROL,
+ ES_VID_MAN_RD_PTR);
+ WRITE_PARSER_REG(PARSER_VIDEO_WP,
+ vdec->input.start);
+ WRITE_PARSER_REG(PARSER_VIDEO_RP,
+ vdec->input.start);
+ }
+ video_data_parsed = 0;
+ } else if (pts_type == PTS_TYPE_AUDIO) {
+ /* set wp as buffer start */
+ SET_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL,
+ MEM_BUFCTRL_MANUAL);
+ WRITE_AIU_REG(AIU_MEM_AIFIFO_MAN_RP,
+ READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_AIU_REG_BITS(AIU_MEM_AIFIFO_CONTROL, 7, 3, 3);
+ SET_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL,
+ MEM_BUFCTRL_INIT);
+ CLEAR_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL,
+ MEM_BUFCTRL_INIT);
+ WRITE_AIU_REG(AIU_MEM_AIFIFO_MAN_WP,
+ READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
+ audio_data_parsed = 0;
+ audio_buf_start =
+ READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR);
+ audio_real_wp = audio_buf_start;
+ audio_buf_end = READ_AIU_REG(AIU_MEM_AIFIFO_END_PTR);
+ } else if (buf->type == BUF_TYPE_SUBTITLE) {
+ WRITE_PARSER_REG(PARSER_SUB_START_PTR,
+ parser_sub_start_ptr);
+ WRITE_PARSER_REG(PARSER_SUB_END_PTR,
+ parser_sub_end_ptr);
+ WRITE_PARSER_REG(PARSER_SUB_RP, parser_sub_rp);
+ SET_PARSER_REG_MASK(PARSER_ES_CONTROL,
+ (7 << ES_SUB_WR_ENDIAN_BIT) |
+ ES_SUB_MAN_RD_PTR);
+ }
+
+ if (pts_type < PTS_TYPE_MAX) {
+ r = pts_start(pts_type);
+
+ if (r < 0) {
+ pr_info("esparser_init: pts_start failed\n");
+ goto Err_1;
+ }
+ }
+#if 0
+ if (buf->flag & BUF_FLAG_FIRST_TSTAMP) {
+ if (buf->type == BUF_TYPE_VIDEO)
+ es_vpts_checkin(buf, buf->first_tstamp);
+ else if (buf->type == BUF_TYPE_AUDIO)
+ es_apts_checkin(buf, buf->first_tstamp);
+
+ buf->flag &= ~BUF_FLAG_FIRST_TSTAMP;
+ }
+#endif
+
+ if (first_use) {
+ /*TODO irq */
+ r = vdec_request_irq(PARSER_IRQ, esparser_isr,
+ "parser", (void *)esparser_id);
+
+ if (r) {
+ pr_info("esparser_init: irq register failed.\n");
+ goto Err_2;
+ }
+ VDEC_PRINT_FUN_LINENO(__func__, __LINE__);
+
+ WRITE_PARSER_REG(PARSER_INT_STATUS, 0xffff);
+ WRITE_PARSER_REG(PARSER_INT_ENABLE,
+ PARSER_INTSTAT_SC_FOUND <<
+ PARSER_INT_HOST_EN_BIT);
+ }
+ mutex_unlock(&esparser_mutex);
+
+ if (!(vdec_get_debug_flags() & 1) &&
+ !codec_mm_video_tvp_enabled()) {
+ int block_size = (buf->type == BUF_TYPE_AUDIO) ?
+ PAGE_SIZE : PAGE_SIZE << 4;
+ int buf_num = (buf->type == BUF_TYPE_AUDIO) ?
+ 20 : (2 * SZ_1M)/(PAGE_SIZE << 4);
+ if (!(buf->type == BUF_TYPE_SUBTITLE))
+ buf->write_thread = threadrw_alloc(buf_num,
+ block_size,
+ esparser_write_ex,
+ (buf->type == BUF_TYPE_AUDIO) ? 1 : 0);
+ /*manul mode for audio*/
+ }
+
+ return 0;
+
+Err_2:
+ pts_stop(pts_type);
+
+Err_1:
+ atomic_dec(&esparser_use_count);
+ buf->flag &= ~BUF_FLAG_PARSER;
+ mutex_unlock(&esparser_mutex);
+ return r;
+}
+EXPORT_SYMBOL(esparser_init);
+
+void esparser_audio_reset_s(struct stream_buf_s *buf)
+{
+ ulong flags;
+ DEFINE_SPINLOCK(lock);
+
+ spin_lock_irqsave(&lock, flags);
+
+ SET_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_MANUAL);
+ WRITE_AIU_REG(AIU_MEM_AIFIFO_MAN_RP,
+ READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_AIU_REG_BITS(AIU_MEM_AIFIFO_CONTROL, 7, 3, 3);
+ SET_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ CLEAR_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ WRITE_AIU_REG(AIU_MEM_AIFIFO_MAN_WP,
+ READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
+
+ buf->flag |= BUF_FLAG_PARSER;
+
+ audio_data_parsed = 0;
+ audio_real_wp = READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR);
+ audio_buf_start = READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR);
+ audio_buf_end = READ_AIU_REG(AIU_MEM_AIFIFO_END_PTR);
+ spin_unlock_irqrestore(&lock, flags);
+
+ return;
+}
+
+void esparser_audio_reset(struct stream_buf_s *buf)
+{
+ ulong flags;
+ DEFINE_SPINLOCK(lock);
+
+ spin_lock_irqsave(&lock, flags);
+
+ WRITE_PARSER_REG(PARSER_AUDIO_WP,
+ READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_PARSER_REG(PARSER_AUDIO_RP,
+ READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
+
+ WRITE_PARSER_REG(PARSER_AUDIO_START_PTR,
+ READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_PARSER_REG(PARSER_AUDIO_END_PTR,
+ READ_AIU_REG(AIU_MEM_AIFIFO_END_PTR));
+ CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL, ES_AUD_MAN_RD_PTR);
+
+ WRITE_AIU_REG(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ CLEAR_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+
+ buf->flag |= BUF_FLAG_PARSER;
+
+ audio_data_parsed = 0;
+ audio_real_wp = 0;
+ audio_buf_start = 0;
+ audio_buf_end = 0;
+ spin_unlock_irqrestore(&lock, flags);
+
+}
+
+void esparser_release(struct stream_buf_s *buf)
+{
+ u32 pts_type;
+
+ /* check if esparser_init() is ever called */
+ if ((buf->flag & BUF_FLAG_PARSER) == 0)
+ return;
+
+ if (atomic_read(&esparser_use_count) == 0) {
+ pr_info
+ ("[%s:%d]###warning, esparser has been released already\n",
+ __func__, __LINE__);
+ return;
+ }
+ if (buf->write_thread)
+ threadrw_release(buf);
+ if (atomic_dec_and_test(&esparser_use_count)) {
+ WRITE_PARSER_REG(PARSER_INT_ENABLE, 0);
+ /*TODO irq */
+
+ vdec_free_irq(PARSER_IRQ, (void *)esparser_id);
+
+ if (search_pattern) {
+ dma_unmap_single(amports_get_dma_device(),
+ search_pattern_map,
+ SEARCH_PATTERN_LEN, DMA_TO_DEVICE);
+ kfree(search_pattern);
+ search_pattern = NULL;
+ }
+ }
+
+ if (has_hevc_vdec() && (buf->type == BUF_TYPE_HEVC))
+ pts_type = PTS_TYPE_VIDEO;
+ else if (buf->type == BUF_TYPE_VIDEO)
+ pts_type = PTS_TYPE_VIDEO;
+ else if (buf->type == BUF_TYPE_AUDIO)
+ pts_type = PTS_TYPE_AUDIO;
+ else if (buf->type == BUF_TYPE_SUBTITLE) {
+ buf->flag &= ~BUF_FLAG_PARSER;
+ return;
+ } else
+ return;
+
+ buf->flag &= ~BUF_FLAG_PARSER;
+ pts_stop(pts_type);
+}
+EXPORT_SYMBOL(esparser_release);
+
+ssize_t drm_write(struct file *file, struct stream_buf_s *stbuf,
+ const char __user *buf, size_t count)
+{
+ s32 r;
+ u32 len;
+ u32 realcount, totalcount;
+ u32 havewritebytes = 0;
+ u32 leftcount = 0;
+
+ struct drm_info tmpmm;
+ struct drm_info *drm = &tmpmm;
+ u32 res = 0;
+ int drm_flag = 0;
+ unsigned long realbuf;
+
+ if (buf == NULL || count == 0)
+ return -EINVAL;
+ if (stbuf->write_thread) {
+ r = threadrw_flush_buffers(stbuf);
+ if (r < 0)
+ pr_info("Warning. drm flush threadrw failed[%d]\n", r);
+ }
+ res = copy_from_user(drm, buf, sizeof(struct drm_info));
+ if (res) {
+ pr_info("drm kmalloc failed res[%d]\n", res);
+ return -EFAULT;
+ }
+
+ if ((drm->drm_flag & TYPE_DRMINFO) && (drm->drm_hasesdata == 0)) {
+ if (drm->drm_pktsize > MAX_DRM_PACKAGE_SIZE) {
+ pr_err("drm package size is error, size is %u\n", drm->drm_pktsize);
+ return -EINVAL;
+ }
+ /* buf only has drminfo not have esdata; */
+ realbuf = drm->drm_phy;
+ realcount = drm->drm_pktsize;
+ drm_flag = drm->drm_flag;
+ /* DRM_PRNT("drm_get_rawdata
+ *onlydrminfo drm->drm_hasesdata[0x%x]
+ * stbuf->type %d buf[0x%x]\n",
+ *drm->drm_hasesdata,stbuf->type,buf);
+ */
+ } else if (drm->drm_hasesdata == 1) { /* buf is drminfo+es; */
+ if (drm->drm_pktsize > MAX_DRM_PACKAGE_SIZE) {
+ pr_err("drm package size is error, size is %u\n", drm->drm_pktsize);
+ return -EINVAL;
+ }
+ realcount = drm->drm_pktsize;
+ realbuf = (unsigned long)buf + sizeof(struct drm_info);
+ drm_flag = 0;
+ /* DRM_PRNT("drm_get_rawdata
+ * drminfo+es drm->drm_hasesdata[0x%x]
+ * stbuf->type %d\n",drm->drm_hasesdata,stbuf->type);
+ */
+ } else { /* buf is hwhead; */
+ realcount = count;
+ drm_flag = 0;
+ realbuf = (unsigned long)buf;
+ /* DRM_PRNT("drm_get_rawdata
+ * drm->drm_hasesdata[0x%x]
+ * len[%d] count[%d] realcout[%d]\n",
+ * drm->drm_hasesdata,len,count,realcount);
+ */
+ }
+
+ len = realcount;
+ count = realcount;
+ totalcount = realcount;
+ stbuf->drm_flag = drm_flag;
+ stbuf->is_phybuf = drm_flag ? 1 : 0;
+
+ while (len > 0) {
+ if (stbuf->type != BUF_TYPE_SUBTITLE
+ && stbuf_space(stbuf) < count) {
+ /*should not write partial data in drm mode*/
+ r = stbuf_wait_space(stbuf, count);
+ if (r < 0)
+ return r;
+ if (stbuf_space(stbuf) < count)
+ return -EAGAIN;
+ }
+ len = min_t(u32, len, count);
+
+ mutex_lock(&esparser_mutex);
+
+ if (stbuf->type != BUF_TYPE_AUDIO)
+ r = _esparser_write((const char __user *)realbuf, len,
+ stbuf, drm_flag);
+ else
+ r = _esparser_write_s((const char __user *)realbuf, len,
+ stbuf);
+ if (r < 0) {
+ pr_info("drm_write _esparser_write failed [%d]\n", r);
+ mutex_unlock(&esparser_mutex);
+ return r;
+ }
+ havewritebytes += r;
+ leftcount = totalcount - havewritebytes;
+ if (havewritebytes == totalcount) {
+
+ mutex_unlock(&esparser_mutex);
+ break; /* write ok; */
+ } else if ((len > 0) && (havewritebytes < totalcount)) {
+ DRM_PRNT
+ ("d writebytes[%d] want[%d] total[%d] real[%d]\n",
+ havewritebytes, len, totalcount, realcount);
+ len = len - r; /* write again; */
+ realbuf = realbuf + r;
+ } else {
+ pr_info
+ ("e writebytes[%d] want[%d] total[%d] real[%d]\n",
+ havewritebytes, len, totalcount, realcount);
+ }
+ mutex_unlock(&esparser_mutex);
+ }
+
+ if ((drm->drm_flag & TYPE_DRMINFO) && (drm->drm_hasesdata == 0)) {
+ havewritebytes = sizeof(struct drm_info);
+ } else if (drm->drm_hasesdata == 1) {
+ havewritebytes += sizeof(struct drm_info);
+ }
+ return havewritebytes;
+}
+EXPORT_SYMBOL(drm_write);
+
+/*
+ *flags:
+ *1:phy
+ *2:noblock
+ */
+ssize_t esparser_write_ex(struct file *file,
+ struct stream_buf_s *stbuf,
+ const char __user *buf, size_t count,
+ int flags)
+{
+
+ s32 r;
+ u32 len = count;
+
+ if (buf == NULL || count == 0)
+ return -EINVAL;
+
+ /*subtitle have no level to check, */
+ if (stbuf->type != BUF_TYPE_SUBTITLE && stbuf_space(stbuf) < count) {
+ if ((flags & 2) || ((file != NULL) &&
+ (file->f_flags & O_NONBLOCK))) {
+ len = stbuf_space(stbuf);
+
+ if (len < 256) /* <1k.do eagain, */
+ return -EAGAIN;
+ } else {
+ len = min(stbuf_canusesize(stbuf) / 8, len);
+
+ if (stbuf_space(stbuf) < len) {
+ r = stbuf_wait_space(stbuf, len);
+ if (r < 0)
+ return r;
+ }
+ }
+ }
+
+ stbuf->last_write_jiffies64 = jiffies_64;
+
+ len = min_t(u32, len, count);
+
+ mutex_lock(&esparser_mutex);
+
+ if (flags & 1)
+ stbuf->is_phybuf = true;
+
+ if (stbuf->type == BUF_TYPE_AUDIO)
+ r = _esparser_write_s(buf, len, stbuf);
+ else
+ r = _esparser_write(buf, len, stbuf, flags & 1);
+
+ mutex_unlock(&esparser_mutex);
+
+ return r;
+}
+ssize_t esparser_write(struct file *file,
+ struct stream_buf_s *stbuf,
+ const char __user *buf, size_t count)
+{
+ if (stbuf->write_thread) {
+ ssize_t ret;
+
+ ret = threadrw_write(file, stbuf, buf, count);
+ if (ret == -EAGAIN) {
+ u32 a, b;
+ int vdelay, adelay;
+
+ if ((stbuf->type != BUF_TYPE_VIDEO) &&
+ (stbuf->type != BUF_TYPE_HEVC))
+ return ret;
+ if (stbuf->buf_size > (SZ_1M * 30) ||
+ (threadrw_buffer_size(stbuf) > SZ_1M * 10) ||
+ !threadrw_support_more_buffers(stbuf))
+ return ret;
+ /*only chang buffer for video.*/
+ vdelay = calculation_stream_delayed_ms(
+ PTS_TYPE_VIDEO, &a, &b);
+ adelay = calculation_stream_delayed_ms(
+ PTS_TYPE_AUDIO, &a, &b);
+ if ((vdelay > 100 && vdelay < 2000) && /*vdelay valid.*/
+ ((vdelay < 500) ||/*video delay is short!*/
+ (adelay > 0 && adelay < 1000))/*audio is low.*/
+ ) {
+ /*on buffer fulled.
+ *if delay is less than 100ms we think errors,
+ *And we add more buffer on delay < 2s.
+ */
+ int new_size = 2 * 1024 * 1024;
+
+ threadrw_alloc_more_buffer_size(
+ stbuf, new_size);
+ }
+ }
+ return ret;
+ }
+ return esparser_write_ex(file, stbuf, buf, count, 0);
+}
+EXPORT_SYMBOL(esparser_write);
+
+void esparser_sub_reset(void)
+{
+ ulong flags;
+ DEFINE_SPINLOCK(lock);
+ u32 parser_sub_start_ptr;
+ u32 parser_sub_end_ptr;
+
+ spin_lock_irqsave(&lock, flags);
+
+ parser_sub_start_ptr = READ_PARSER_REG(PARSER_SUB_START_PTR);
+ parser_sub_end_ptr = READ_PARSER_REG(PARSER_SUB_END_PTR);
+
+ WRITE_PARSER_REG(PARSER_SUB_START_PTR, parser_sub_start_ptr);
+ WRITE_PARSER_REG(PARSER_SUB_END_PTR, parser_sub_end_ptr);
+ WRITE_PARSER_REG(PARSER_SUB_RP, parser_sub_start_ptr);
+ WRITE_PARSER_REG(PARSER_SUB_WP, parser_sub_start_ptr);
+ SET_PARSER_REG_MASK(PARSER_ES_CONTROL,
+ (7 << ES_SUB_WR_ENDIAN_BIT) | ES_SUB_MAN_RD_PTR);
+
+ spin_unlock_irqrestore(&lock, flags);
+}
+
+static int esparser_stbuf_init(struct stream_buf_s *stbuf,
+ struct vdec_s *vdec)
+{
+ int ret = -1;
+
+ ret = stbuf_init(stbuf, vdec);
+ if (ret)
+ goto out;
+
+ ret = esparser_init(stbuf, vdec);
+ if (!ret)
+ stbuf->flag |= BUF_FLAG_IN_USE;
+out:
+ return ret;
+}
+
+static void esparser_stbuf_release(struct stream_buf_s *stbuf)
+{
+ esparser_release(stbuf);
+
+ stbuf_release(stbuf);
+}
+
+static struct stream_buf_ops esparser_stbuf_ops = {
+ .init = esparser_stbuf_init,
+ .release = esparser_stbuf_release,
+ .write = esparser_stbuf_write,
+ .get_wp = parser_get_wp,
+ .set_wp = parser_set_wp,
+ .get_rp = parser_get_rp,
+ .set_rp = parser_set_rp,
+};
+
+struct stream_buf_ops *get_esparser_stbuf_ops(void)
+{
+ return &esparser_stbuf_ops;
+}
+EXPORT_SYMBOL(get_esparser_stbuf_ops);
+
diff --git a/drivers/stream_input/parser/esparser.h b/drivers/stream_input/parser/esparser.h
new file mode 100644
index 0000000..24e6926
--- /dev/null
+++ b/drivers/stream_input/parser/esparser.h
@@ -0,0 +1,152 @@
+/*
+ * drivers/amlogic/media/stream_input/parser/esparser.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 ESPARSER_H
+#define ESPARSER_H
+
+#include "../../frame_provider/decoder/utils/vdec.h"
+
+extern ssize_t drm_write(struct file *file,
+ struct stream_buf_s *stbuf,
+ const char __user *buf, size_t count);
+
+extern s32 esparser_init(struct stream_buf_s *buf, struct vdec_s *vdec);
+extern s32 esparser_init_s(struct stream_buf_s *buf);
+extern void esparser_release(struct stream_buf_s *buf);
+extern ssize_t esparser_write(struct file *file,
+ struct stream_buf_s *stbuf,
+ const char __user *buf, size_t count);
+extern ssize_t esparser_write_ex(struct file *file,
+ struct stream_buf_s *stbuf,
+ const char __user *buf, size_t count,
+ int is_phy);
+
+extern s32 es_vpts_checkin_us64(struct stream_buf_s *buf, u64 us64);
+
+extern s32 es_apts_checkin_us64(struct stream_buf_s *buf, u64 us64);
+
+extern int es_vpts_checkin(struct stream_buf_s *buf, u32 pts);
+
+extern int es_apts_checkin(struct stream_buf_s *buf, u32 pts);
+
+extern void esparser_audio_reset(struct stream_buf_s *buf);
+extern void esparser_audio_reset_s(struct stream_buf_s *buf);
+
+extern void esparser_sub_reset(void);
+
+#ifdef CONFIG_AM_DVB
+extern int tsdemux_set_reset_flag(void);
+#endif
+
+/* TODO: move to register headers */
+#define ES_PACK_SIZE_BIT 8
+#define ES_PACK_SIZE_WID 24
+
+#define ES_CTRL_WID 8
+#define ES_CTRL_BIT 0
+#define ES_TYPE_MASK (3 << 6)
+#define ES_TYPE_VIDEO (0 << 6)
+#define ES_TYPE_AUDIO (1 << 6)
+#define ES_TYPE_SUBTITLE (2 << 6)
+
+#define ES_WRITE (1<<5)
+#define ES_PASSTHROUGH (1<<4)
+#define ES_INSERT_BEFORE_ES_WRITE (1<<3)
+#define ES_DISCARD (1<<2)
+#define ES_SEARCH (1<<1)
+#define ES_PARSER_START (1<<0)
+#define ES_PARSER_BUSY (1<<0)
+
+#define PARSER_INTSTAT_FETCH_CMD (1<<7)
+#define PARSER_INTSTAT_PARSE (1<<4)
+#define PARSER_INTSTAT_DISCARD (1<<3)
+#define PARSER_INTSTAT_INSZERO (1<<2)
+#define PARSER_INTSTAT_ACT_NOSSC (1<<1)
+#define PARSER_INTSTAT_SC_FOUND (1<<0)
+
+#define FETCH_CIR_BUF (1<<31)
+#define FETCH_CHK_BUF_STOP (1<<30)
+#define FETCH_PASSTHROUGH (1<<29)
+#define FETCH_ENDIAN 27
+#define FETCH_PASSTHROUGH_TYPE_MASK (0x3<<27)
+#define FETCH_ENDIAN_MASK (0x7<<27)
+#define FETCH_BUF_SIZE_MASK (0x7ffffff)
+#define FETCH_CMD_PTR_MASK 3
+#define FETCH_CMD_RD_PTR_BIT 5
+#define FETCH_CMD_WR_PTR_BIT 3
+#define FETCH_CMD_NUM_MASK 3
+#define FETCH_CMD_NUM_BIT 0
+
+#define ES_COUNT_MASK 0xfff
+#define ES_COUNT_BIT 20
+#define ES_REQ_PENDING (1<<19)
+#define ES_PASSTHROUGH_EN (1<<18)
+#define ES_PASSTHROUGH_TYPE_MASK (3<<16)
+#define ES_PASSTHROUGH_TYPE_VIDEO (0<<16)
+#define ES_PASSTHROUGH_TYPE_AUDIO (1<<16)
+#define ES_PASSTHROUGH_TYPE_SUBTITLE (2<<16)
+#define ES_WR_ENDIAN_MASK (0x7)
+#define ES_SUB_WR_ENDIAN_BIT 9
+#define ES_SUB_MAN_RD_PTR (1<<8)
+#define ES_AUD_WR_ENDIAN_BIT 5
+#define ES_AUD_MAN_RD_PTR (1<<4)
+#define ES_VID_WR_ENDIAN_BIT 1
+#define ES_VID_MAN_RD_PTR (1<<0)
+
+#define PS_CFG_FETCH_DMA_URGENT (1<<31)
+#define PS_CFG_STREAM_DMA_URGENT (1<<30)
+#define PS_CFG_FORCE_PFIFO_REN (1<<29)
+#define PS_CFG_PFIFO_PEAK_EN (1<<28)
+#define PS_CFG_SRC_SEL_BIT 24
+#define PS_CFG_SRC_SEL_MASK (3<<PS_CFG_SRC_SEL_BIT)
+#define PS_CFG_SRC_SEL_FETCH (0<<PS_CFG_SRC_SEL_BIT)
+#define PS_CFG_SRC_SEL_AUX1 (1<<PS_CFG_SRC_SEL_BIT) /*from NDMA */
+#define PS_CFG_SRC_SEL_AUX2 (2<<PS_CFG_SRC_SEL_BIT)
+#define PS_CFG_SRC_SEL_AUX3 (3<<PS_CFG_SRC_SEL_BIT)
+#define PS_CFG_PFIFO_EMPTY_CNT_BIT 16
+#define PS_CFG_PFIFO_EMPTY_CNT_MASK 0xff
+#define PS_CFG_MAX_ES_WR_CYCLE_BIT 12
+#define PS_CFG_MAX_ES_WR_CYCLE_MASK 0xf
+#define PS_CFG_STARTCODE_WID_MASK (0x3<<10)
+#define PS_CFG_STARTCODE_WID_8 (0x0<<10)
+#define PS_CFG_STARTCODE_WID_16 (0x1<<10)
+#define PS_CFG_STARTCODE_WID_24 (0x2<<10)
+#define PS_CFG_STARTCODE_WID_32 (0x3<<10)
+#define PS_CFG_PFIFO_ACCESS_WID_MASK (0x3<<8)
+#define PS_CFG_PFIFO_ACCESS_WID_8 (0x0<<8)
+#define PS_CFG_PFIFO_ACCESS_WID_16 (0x1<<8)
+#define PS_CFG_PFIFO_ACCESS_WID_24 (0x2<<8)
+#define PS_CFG_PFIFO_ACCESS_WID_32 (0x3<<8)
+#define PS_CFG_MAX_FETCH_CYCLE_BIT 0
+#define PS_CFG_MAX_FETCH_CYCLE_MASK 0xff
+
+#define PARSER_INT_DISABLE_CNT_MASK 0xffff
+#define PARSER_INT_DISABLE_CNT_BIT 16
+#define PARSER_INT_HOST_EN_MASK 0xff
+#define PARSER_INT_HOST_EN_BIT 8
+#define PARSER_INT_AMRISC_EN_MASK 0xff
+#define PARSER_INT_AMRISC_EN_BIT 0
+#define PARSER_INT_ALL 0xff
+
+#define RESET_PARSER (1<<8)
+#define TS_HIU_ENABLE 5
+#define USE_HI_BSF_INTERFACE 7
+
+#define DRM_PRNT(fmt, args...)
+#define TRACE() pr_info("drm--[%s::%d]\n", __func__, __LINE__)
+
+#endif /* ESPARSER_H */
diff --git a/drivers/stream_input/parser/hw_demux/Makefile b/drivers/stream_input/parser/hw_demux/Makefile
new file mode 100644
index 0000000..e031594
--- /dev/null
+++ b/drivers/stream_input/parser/hw_demux/Makefile
@@ -0,0 +1,8 @@
+obj-m += aml_hardware_dmx.o
+
+ccflags-y += -I$(srctree)/drivers/media/dvb-core -I$(srctree)/drivers/gpio -I$(srctree)/include -DENABLE_DEMUX_DRIVER
+
+aml_hardware_dmx-objs += aml_dvb.o
+aml_hardware_dmx-objs += aml_dmx.o
+
+#obj-y += dvb_ci/
diff --git a/drivers/stream_input/parser/hw_demux/aml_demod_gt.h b/drivers/stream_input/parser/hw_demux/aml_demod_gt.h
new file mode 100644
index 0000000..77658b0
--- /dev/null
+++ b/drivers/stream_input/parser/hw_demux/aml_demod_gt.h
@@ -0,0 +1,26 @@
+/*
+* 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_DEMOD_GT_H__
+#define __AML_DEMOD_GT_H__
+
+#include "../dvb_common.h"
+
+
+#endif /*__AML_DEMOD_GT_H__*/
diff --git a/drivers/stream_input/parser/hw_demux/aml_dmx.c b/drivers/stream_input/parser/hw_demux/aml_dmx.c
new file mode 100644
index 0000000..ad34987
--- /dev/null
+++ b/drivers/stream_input/parser/hw_demux/aml_dmx.c
@@ -0,0 +1,6288 @@
+/*
+* 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:
+*/
+/*
+ * AMLOGIC demux driver.
+ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/fcntl.h>
+#include <asm/irq.h>
+#include <linux/uaccess.h>
+#include <linux/poll.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <asm/cacheflush.h>
+#include <linux/dma-mapping.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/vmalloc.h>
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include <linux/amlogic/media/codec_mm/configs.h>
+#include "../../amports/streambuf.h"
+#include "c_stb_define.h"
+#include "c_stb_regs_define.h"
+#include "aml_dvb.h"
+#include "aml_dvb_reg.h"
+
+
+#define ENABLE_SEC_BUFF_WATCHDOG
+#define USE_AHB_MODE
+#define PR_ERROR_SPEED_LIMIT
+
+#define pr_dbg_flag(_f, _args...)\
+ do {\
+ if (debug_dmx&(_f))\
+ printk(_args);\
+ } while (0)
+#define pr_dbg_irq_flag(_f, _args...)\
+ do {\
+ if (debug_irq&(_f))\
+ printk(_args);\
+ } while (0)
+#define pr_dbg(args...) pr_dbg_flag(0x1, args)
+#define pr_dbg_irq(args...)pr_dbg_irq_flag(0x1, args)
+#define pr_dbg_irq_dvr(args...)pr_dbg_irq_flag(0x2, args)
+#define pr_dbg_sf(args...) pr_dbg_flag(0x4, args)
+#define pr_dbg_irq_sf(args...) pr_dbg_irq_flag(0x4, args)
+#define pr_dbg_ss(args...) pr_dbg_flag(0x8, args)
+#define pr_dbg_irq_ss(args...) pr_dbg_irq_flag(0x8, args)
+#define pr_dbg_irq_pes(args...) pr_dbg_irq_flag(0x10, args)
+#define pr_dbg_irq_sub(args...) pr_dbg_irq_flag(0x20, args)
+
+#ifdef PR_ERROR_SPEED_LIMIT
+static u32 last_pr_error_time;
+#define pr_error(fmt, _args...)\
+ do {\
+ u32 diff = jiffies_to_msecs(jiffies - last_pr_error_time);\
+ if (!last_pr_error_time || diff > 50) {\
+ pr_err("DVB:" fmt, ## _args);\
+ last_pr_error_time = jiffies;\
+ } \
+ } while (0)
+#else
+#define pr_error(fmt, args...) pr_err("DVB: " fmt, ## args)
+#endif
+
+#define pr_inf(fmt, args...) printk("DVB: " fmt, ## args)
+
+#define dump(b, l) \
+ do { \
+ int i; \
+ printk("dump: "); \
+ for (i = 0; i < (l); i++) {\
+ if (!(i&0xf)) \
+ printk("\n\t"); \
+ printk("%02x ", *(((unsigned char *)(b))+i)); \
+ } \
+ printk("\n"); \
+ } while (0)
+
+MODULE_PARM_DESC(debug_dmx, "\n\t\t Enable demux debug information");
+static int debug_dmx;
+module_param(debug_dmx, int, 0644);
+
+MODULE_PARM_DESC(debug_irq, "\n\t\t Enable demux IRQ debug information");
+static int debug_irq;
+module_param(debug_irq, int, 0644);
+
+MODULE_PARM_DESC(disable_dsc, "\n\t\t Disable discrambler");
+static int disable_dsc;
+module_param(disable_dsc, int, 0644);
+
+MODULE_PARM_DESC(enable_sec_monitor, "\n\t\t Enable sec monitor default is enable");
+static int enable_sec_monitor = 2;
+module_param(enable_sec_monitor, int, 0644);
+/*For old version kernel */
+#ifndef MESON_CPU_MAJOR_ID_GXL
+#define MESON_CPU_MAJOR_ID_GXL 0x21
+#endif
+
+static int npidtypes = CHANNEL_COUNT;
+#define MOD_PARAM_DECLARE_CHANPIDS_TYPES(_dmx) \
+MODULE_PARM_DESC(debug_dmx##_dmx##_chanpids_types, "\n\t\t pids types of dmx channels"); \
+static short debug_dmx##_dmx##_chanpids_types[CHANNEL_COUNT] = \
+ {[0 ... (CHANNEL_COUNT - 1)] = -1}; \
+module_param_array(debug_dmx##_dmx##_chanpids_types, short, &npidtypes, 0444)
+
+MOD_PARAM_DECLARE_CHANPIDS_TYPES(0);
+MOD_PARAM_DECLARE_CHANPIDS_TYPES(1);
+MOD_PARAM_DECLARE_CHANPIDS_TYPES(2);
+
+#define set_debug_dmx_chanpids_types(_dmx, _idx, _type)\
+ do { \
+ if ((_dmx) == 0) \
+ debug_dmx0_chanpids_types[(_idx)] = (_type); \
+ else if ((_dmx) == 1) \
+ debug_dmx1_chanpids_types[(_idx)] = (_type); \
+ else if ((_dmx) == 2) \
+ debug_dmx2_chanpids_types[(_idx)] = (_type); \
+ } while (0)
+
+
+static int npids = CHANNEL_COUNT;
+#define MOD_PARAM_DECLARE_CHANPIDS(_dmx) \
+MODULE_PARM_DESC(debug_dmx##_dmx##_chanpids, "\n\t\t pids of dmx channels"); \
+static short debug_dmx##_dmx##_chanpids[CHANNEL_COUNT] = \
+ {[0 ... (CHANNEL_COUNT - 1)] = -1}; \
+module_param_array(debug_dmx##_dmx##_chanpids, short, &npids, 0444)
+
+#define CIPLUS_OUTPUT_AUTO 8
+static int ciplus_out_sel = CIPLUS_OUTPUT_AUTO;
+static int ciplus_out_auto_mode = 1;
+static u32 ciplus = 0;
+#define CIPLUS_OUT_SEL 28
+#define CIPLUS_IN_SEL 26
+
+MOD_PARAM_DECLARE_CHANPIDS(0);
+MOD_PARAM_DECLARE_CHANPIDS(1);
+MOD_PARAM_DECLARE_CHANPIDS(2);
+
+#define set_debug_dmx_chanpids(_dmx, _idx, _pid)\
+ do { \
+ if ((_dmx) == 0) \
+ debug_dmx0_chanpids[(_idx)] = (_pid); \
+ else if ((_dmx) == 1) \
+ debug_dmx1_chanpids[(_idx)] = (_pid); \
+ else if ((_dmx) == 2) \
+ debug_dmx2_chanpids[(_idx)] = (_pid); \
+ if (_pid == -1) \
+ set_debug_dmx_chanpids_types(_dmx, _idx, -1); \
+ } while (0)
+
+MODULE_PARM_DESC(debug_sf_user, "\n\t\t only for sf mode check");
+static int debug_sf_user;
+module_param(debug_sf_user, int, 0444);
+
+MODULE_PARM_DESC(force_sec_sf, "\n\t\t force sf mode for sec filter");
+static int force_sec_sf;
+module_param(force_sec_sf, int, 0644);
+
+MODULE_PARM_DESC(force_pes_sf, "\n\t\t force sf mode for pes filter");
+static int force_pes_sf;
+module_param(force_pes_sf, int, 0644);
+
+MODULE_PARM_DESC(use_of_sop, "\n\t\t Enable use of sop input");
+static int use_of_sop;
+module_param(use_of_sop, int, 0644);
+
+/*#define CIPLUS_KEY0 0x16f8
+#define CIPLUS_KEY1 0x16f9
+#define CIPLUS_KEY2 0x16fa
+#define CIPLUS_KEY3 0x16fb
+#define CIPLUS_KEY_WR 0x16fc
+#define CIPLUS_CONFIG 0x16fd
+#define CIPLUS_ENDIAN 0x16fe*/
+
+
+static u32 old_stb_top_config;
+static u32 old_fec_input_control;
+static int have_old_stb_top_config = 1;
+static int have_old_fec_input_control = 1;
+
+static long pes_off_pre[DMX_DEV_COUNT];
+
+static void
+dmx_write_reg(int r, u32 v)
+{
+ u32 oldv, mask;
+
+ if (disable_dsc) {
+ if (r == STB_TOP_CONFIG) {
+ if (have_old_stb_top_config) {
+ oldv = old_stb_top_config;
+ have_old_stb_top_config = 0;
+ } else {
+ oldv = READ_MPEG_REG(STB_TOP_CONFIG);
+ }
+
+ mask = (1<<7)|(1<<15)|(3<<26)|(7<<28);
+ v &= ~mask;
+ v |= (oldv & mask);
+ } else if (r == FEC_INPUT_CONTROL) {
+ if (have_old_fec_input_control) {
+ oldv = old_fec_input_control;
+ have_old_fec_input_control = 0;
+ } else {
+ oldv = READ_MPEG_REG(FEC_INPUT_CONTROL);
+ }
+
+ mask = (1<<15);
+ v &= ~mask;
+ v |= (oldv & mask);
+ } else if ((r == RESET1_REGISTER) || (r == RESET3_REGISTER)) {
+ if (!have_old_stb_top_config) {
+ have_old_stb_top_config = 1;
+ old_stb_top_config =
+ READ_MPEG_REG(STB_TOP_CONFIG);
+ }
+ if (!have_old_fec_input_control) {
+ have_old_fec_input_control = 1;
+ old_fec_input_control =
+ READ_MPEG_REG(FEC_INPUT_CONTROL);
+ }
+ } else if ((r == TS_PL_PID_INDEX) || (r == TS_PL_PID_DATA)
+ || (r == COMM_DESC_KEY0)
+ || (r == COMM_DESC_KEY1)
+ || (r == COMM_DESC_KEY_RW)
+ || (r == CIPLUS_KEY0)
+ || (r == CIPLUS_KEY1)
+ || (r == CIPLUS_KEY2)
+ || (r == CIPLUS_KEY3)
+ || (r == CIPLUS_KEY_WR)
+ || (r == CIPLUS_CONFIG)
+ || (r == CIPLUS_ENDIAN)) {
+ return;
+ }
+ }
+ WRITE_MPEG_REG(r, v);
+}
+
+#undef WRITE_MPEG_REG
+#define WRITE_MPEG_REG(r, v) dmx_write_reg(r, v)
+
+#define DMX_READ_REG(i, r)\
+ ((i)?((i == 1)?READ_MPEG_REG(r##_2) :\
+ READ_MPEG_REG(r##_3)) : READ_MPEG_REG(r))
+
+#define DMX_WRITE_REG(i, r, d)\
+ do {\
+ if (i == 1) {\
+ WRITE_MPEG_REG(r##_2, d);\
+ } else if (i == 2) {\
+ WRITE_MPEG_REG(r##_3, d);\
+ } \
+ else {\
+ WRITE_MPEG_REG(r, d);\
+ } \
+ } while (0)
+
+#define READ_PERI_REG READ_CBUS_REG
+#define WRITE_PERI_REG WRITE_CBUS_REG
+
+#define READ_ASYNC_FIFO_REG(i, r)\
+ ((i) ? ((i-1)?READ_PERI_REG(ASYNC_FIFO1_##r):\
+ READ_PERI_REG(ASYNC_FIFO2_##r)) : READ_PERI_REG(ASYNC_FIFO_##r))
+
+#define WRITE_ASYNC_FIFO_REG(i, r, d)\
+ do {\
+ if (i == 2) {\
+ WRITE_PERI_REG(ASYNC_FIFO1_##r, d);\
+ } else if (i == 0) {\
+ WRITE_PERI_REG(ASYNC_FIFO_##r, d);\
+ } else {\
+ WRITE_PERI_REG(ASYNC_FIFO2_##r, d);\
+ } \
+ } while (0)
+
+#define CLEAR_ASYNC_FIFO_REG_MASK(i, reg, mask) \
+ WRITE_ASYNC_FIFO_REG(i, reg, \
+ (READ_ASYNC_FIFO_REG(i, reg)&(~(mask))))
+
+#define DVR_FEED(f) \
+ ((f) && ((f)->type == DMX_TYPE_TS) && \
+ (((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET))
+
+#define MOD_PARAM_DECLARE_CHANREC(_dmx) \
+MODULE_PARM_DESC(dmx##_dmx##_chanrec_enable, \
+ "\n\t\t record by channel, one time use in the beginning"); \
+static int dmx##_dmx##_chanrec_enable; \
+module_param(dmx##_dmx##_chanrec_enable, int, 0644); \
+MODULE_PARM_DESC(dmx##_dmx##_chanrec, "\n\t\t record channels bits"); \
+static int dmx##_dmx##_chanrec; \
+module_param(dmx##_dmx##_chanrec, int, 0644)
+
+MOD_PARAM_DECLARE_CHANREC(0);
+MOD_PARAM_DECLARE_CHANREC(1);
+MOD_PARAM_DECLARE_CHANREC(2);
+
+#define MOD_PARAM_DECLARE_CHANPROC(_dmx) \
+MODULE_PARM_DESC(dmx##_dmx##_chanproc_enable, "channel further processing"); \
+static int dmx##_dmx##_chanproc_enable; \
+module_param(dmx##_dmx##_chanproc_enable, int, 0644); \
+MODULE_PARM_DESC(dmx##_dmx##_chanproc, "further process channels bits"); \
+static int dmx##_dmx##_chanproc; \
+module_param(dmx##_dmx##_chanproc, int, 0644)
+
+MOD_PARAM_DECLARE_CHANPROC(0);
+MOD_PARAM_DECLARE_CHANPROC(1);
+MOD_PARAM_DECLARE_CHANPROC(2);
+
+#define DMX_CH_OP_CHANREC 0
+#define DMX_CH_OP_CHANPROC 1
+
+static inline int _setbit(int v, int b) { return v|(1<<b); }
+static inline int _clrbit(int v, int b) { return v&~(1<<b); }
+static inline int _set(int v, int b) { return b; }
+
+static int dsc_set_csa_key(struct aml_dsc_channel *ch, int flags,
+ enum ca_cw_type type, u8 *key);
+static int dsc_set_aes_des_sm4_key(struct aml_dsc_channel *ch, int flags,
+ enum ca_cw_type type, u8 *key);
+static void aml_ci_plus_disable(void);
+static void am_ci_plus_set_output(struct aml_dsc_channel *ch);
+static int set_subtitle_pes_buffer(struct aml_dmx *dmx);
+
+static void dmxn_op_chan(int dmx, int ch, int(*op)(int, int), int ch_op)
+{
+ int enable_0, enable_1, enable_2;
+ int *set_0, *set_1, *set_2;
+ int reg;
+
+ if (ch_op == DMX_CH_OP_CHANREC) {
+ enable_0 = dmx0_chanrec_enable;
+ enable_1 = dmx1_chanrec_enable;
+ enable_2 = dmx2_chanrec_enable;
+ set_0 = &dmx0_chanrec;
+ set_1 = &dmx1_chanrec;
+ set_2 = &dmx2_chanrec;
+ reg = DEMUX_CHAN_RECORD_EN;
+ } else if (ch_op == DMX_CH_OP_CHANPROC) {
+ enable_0 = dmx0_chanproc_enable;
+ enable_1 = dmx1_chanproc_enable;
+ enable_2 = dmx2_chanproc_enable;
+ set_0 = &dmx0_chanproc;
+ set_1 = &dmx1_chanproc;
+ set_2 = &dmx2_chanproc;
+ reg = DEMUX_CHAN_PROCESS_EN;
+ } else {
+ return;
+ }
+ if (dmx == 0) {
+ if (enable_0) {
+ *set_0 = op(*set_0, ch);
+ WRITE_MPEG_REG(reg+DEMUX_1_OFFSET, *set_0);
+ }
+ } else if (dmx == 1) {
+ if (enable_1) {
+ *set_1 = op(*set_1, ch);
+ WRITE_MPEG_REG(reg+DEMUX_2_OFFSET, *set_1);
+ }
+ } else if (dmx == 2) {
+ if (enable_2) {
+ *set_2 = op(*set_2, ch);
+ WRITE_MPEG_REG(reg+DEMUX_3_OFFSET, *set_2);
+ }
+ }
+}
+#define dmx_add_recchan(_dmx, _chid) \
+ do { \
+ pr_dbg("dmx[%d]_add_recchan[%d]\n", _dmx, _chid); \
+ dmxn_op_chan(_dmx, _chid, _setbit, DMX_CH_OP_CHANREC); \
+ } while (0)
+#define dmx_rm_recchan(_dmx, _chid) \
+ do { \
+ pr_dbg("dmx[%d]_rm_recchan[%ld]\n", _dmx, _chid); \
+ dmxn_op_chan(_dmx, _chid, _clrbit, DMX_CH_OP_CHANREC); \
+ } while (0)
+#define dmx_set_recchan(_dmx, _chs) \
+ do { \
+ pr_dbg("dmx[%d]_set_recchan[%d]\n", _dmx, _chs); \
+ dmxn_op_chan(_dmx, _chs, _set, DMX_CH_OP_CHANREC); \
+ } while (0)
+
+#define dmx_add_procchan(_dmx, _chid) \
+ do { \
+ pr_dbg("dmx[%d]_add_procchan[%d]\n", _dmx, _chid); \
+ dmxn_op_chan(_dmx, _chid, _setbit, DMX_CH_OP_CHANPROC); \
+ } while (0)
+#define dmx_rm_procchan(_dmx, _chid) \
+ do { \
+ pr_dbg("dmx[%d]_rm_procchan[%ld]\n", _dmx, _chid); \
+ dmxn_op_chan(_dmx, _chid, _clrbit, DMX_CH_OP_CHANPROC); \
+ } while (0)
+#define dmx_set_procchan(_dmx, _chs) \
+ do { \
+ pr_dbg("dmx[%d]_set_procchan[%d]\n", _dmx, _chs); \
+ dmxn_op_chan(_dmx, _chs, _set, DMX_CH_OP_CHANPROC); \
+ } while (0)
+
+#define NO_SUB
+#define SUB_BUF_DMX
+#define SUB_PARSER
+
+#ifndef SUB_BUF_DMX
+#undef SUB_PARSER
+#endif
+
+#define SUB_BUF_SHARED
+#define PES_BUF_SHARED
+
+#define SYS_CHAN_COUNT (4)
+#define SEC_GRP_LEN_0 (0xc)
+#define SEC_GRP_LEN_1 (0xc)
+#define SEC_GRP_LEN_2 (0xc)
+#define SEC_GRP_LEN_3 (0xc)
+#define LARGE_SEC_BUFF_MASK 0xFFFFFFFF
+#define LARGE_SEC_BUFF_COUNT 32
+#define WATCHDOG_TIMER 250
+#define ASYNCFIFO_BUFFER_SIZE_DEFAULT (512*1024)
+
+#define DEMUX_INT_MASK\
+ ((0<<(AUDIO_SPLICING_POINT)) |\
+ (0<<(VIDEO_SPLICING_POINT)) |\
+ (1<<(OTHER_PES_READY)) |\
+ (1<<(PCR_READY)) |\
+ (1<<(SUB_PES_READY)) |\
+ (1<<(SECTION_BUFFER_READY)) |\
+ (0<<(OM_CMD_READ_PENDING)) |\
+ (1<<(TS_ERROR_PIN)) |\
+ (1<<(NEW_PDTS_READY)) |\
+ (0<<(DUPLICATED_PACKET)) |\
+ (0<<(DIS_CONTINUITY_PACKET)))
+
+#define TS_SRC_MAX 3
+
+/*Reset the demux device*/
+#define RESET_DEMUX2 (1<<15)
+#define RESET_DEMUX1 (1<<14)
+#define RESET_DEMUX0 (1<<13)
+#define RESET_S2P1 (1<<12)
+#define RESET_S2P0 (1<<11)
+#define RESET_DES (1<<10)
+#define RESET_TOP (1<<9)
+
+static int dmx_remove_feed(struct aml_dmx *dmx, struct dvb_demux_feed *feed);
+static void reset_async_fifos(struct aml_dvb *dvb);
+static int dmx_add_feed(struct aml_dmx *dmx, struct dvb_demux_feed *feed);
+static int dmx_smallsec_set(struct aml_smallsec *ss, int enable, int bufsize,
+ int force);
+static int dmx_timeout_set(struct aml_dmxtimeout *dto, int enable,
+ int timeout, int ch_dis, int nomatch,
+ int force);
+
+/*Audio & Video PTS value*/
+static u32 video_pts = 0;
+static u32 audio_pts = 0;
+static u32 video_pts_bit32 = 0;
+static u32 audio_pts_bit32 = 0;
+static u32 first_video_pts = 0;
+static u32 first_audio_pts = 0;
+static int demux_skipbyte;
+static int tsfile_clkdiv = 5;
+static int asyncfifo_buf_len = ASYNCFIFO_BUFFER_SIZE_DEFAULT;
+
+#define SF_DMX_ID 2
+#define SF_AFIFO_ID 1
+
+#define sf_dmx_sf(_dmx) \
+ (((_dmx)->id == SF_DMX_ID) \
+ && ((struct aml_dvb *)(_dmx)->demux.priv)->swfilter.user)
+#define sf_afifo_sf(_afifo) \
+ (((_afifo)->id == SF_AFIFO_ID) && (_afifo)->dvb->swfilter.user)
+#define dmx_get_dev(dmx) (((struct aml_dvb *)((dmx)->demux.priv))->dev)
+#define asyncfifo_get_dev(afifo) ((afifo)->dvb->dev)
+
+
+
+/*Section buffer watchdog*/
+static void section_buffer_watchdog_func(unsigned long arg)
+{
+ struct aml_dvb *dvb = (struct aml_dvb *)arg;
+ struct aml_dmx *dmx;
+ u32 section_busy32 = 0, om_cmd_status32 = 0,
+ demux_channel_activity32 = 0;
+ u16 demux_int_status1 = 0;
+ u32 device_no = 0;
+ u32 filter_number = 0;
+ u32 i = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+
+ for (device_no = 0; device_no < DMX_DEV_COUNT; device_no++) {
+
+ dmx = &dvb->dmx[device_no];
+
+ if (dvb->dmx_watchdog_disable[device_no])
+ continue;
+
+ if (!dmx->init)
+ continue;
+
+ om_cmd_status32 =
+ DMX_READ_REG(device_no, OM_CMD_STATUS);
+ demux_channel_activity32 =
+ DMX_READ_REG(device_no, DEMUX_CHANNEL_ACTIVITY);
+ section_busy32 =
+ DMX_READ_REG(device_no, SEC_BUFF_BUSY);
+
+ if (om_cmd_status32 & 0x8fc2) {
+ /* bit 15:12 -- om_cmd_count (read only) */
+ /* bit 11:9 -- overflow_count */
+ /* bit 11:9 -- om_cmd_wr_ptr(read only) */
+ /* bit 8:6 -- om_overwrite_count */
+ /* bit 8:6 -- om_cmd_rd_ptr(read only) */
+ /* bit 5:3 -- type_stb_om_w_rd(read only) */
+ /* bit 2 -- unit_start_stb_om_w_rd(read only) */
+ /* bit 1 -- om_cmd_overflow(read only) */
+ /* bit 0 -- om_cmd_pending(read) */
+ /* bit 0 -- om_cmd_read_finished(write) */
+ /*BUG: If the recoder is running, return */
+ if (!dmx->record) {
+ /* OM status is wrong */
+ dmx->om_status_error_count++;
+ pr_dbg("demux om status \n"
+ "%04x\t%03x\t%03x\t%03x\t%01x\t%01x\t"
+ "%x\t%x\tdmx%d:status:0x%xerr_cnt:%d-%d\n",
+ (om_cmd_status32 >> 12) & 0xf,
+ (om_cmd_status32 >> 9) & 0x7,
+ (om_cmd_status32 >> 6) & 0x7,
+ (om_cmd_status32 >> 3) & 0x7,
+ (om_cmd_status32 >> 2) & 0x1,
+ (om_cmd_status32 >> 1) & 0x1,
+ demux_channel_activity32, section_busy32,
+ dmx->id, om_cmd_status32, dmx->om_status_error_count, enable_sec_monitor);
+ if (enable_sec_monitor &&
+ dmx->om_status_error_count > enable_sec_monitor) {
+ /*Reset the demux */
+ dmx_reset_dmx_hw_ex_unlock(dvb, dmx, 0);
+ /* Reset the error count */
+ dmx->om_status_error_count = 0;
+ goto end;
+ }
+ }
+ } else {
+ /* OM status is correct, reset the error count */
+ dmx->om_status_error_count = 0;
+ }
+ section_busy32 =
+ DMX_READ_REG(device_no, SEC_BUFF_BUSY);
+ if (LARGE_SEC_BUFF_MASK ==
+ (section_busy32 & LARGE_SEC_BUFF_MASK)) {
+ /*All the largest section buffers occupied,
+ * clear buffers
+ */
+ DMX_WRITE_REG(device_no,
+ SEC_BUFF_READY, section_busy32);
+ } else {
+ for (i = 0; i < SEC_BUF_COUNT; i++) {
+ if (!(section_busy32 & (1 << i)))
+ continue;
+ DMX_WRITE_REG(device_no, SEC_BUFF_NUMBER, i);
+ filter_number = DMX_READ_REG(device_no,
+ SEC_BUFF_NUMBER);
+ filter_number >>= 8;
+ if ((filter_number >= FILTER_COUNT)
+ /* >=31, do not handle this case */
+ || ((filter_number < FILTER_COUNT)
+ && dmx->filter[filter_number].used))
+ section_busy32 &= ~(1 << i);
+ }
+ if (section_busy32 & (dmx->smallsec.enable ?
+ 0x7FFFFFFF :
+ LARGE_SEC_BUFF_MASK)) {
+ /*Clear invalid buffers */
+ DMX_WRITE_REG(device_no,
+ SEC_BUFF_READY,
+ section_busy32);
+ pr_error("clear invalid buffer 0x%x\n",
+ section_busy32);
+ }
+#if 0
+ section_busy32 = 0x7fffffff;
+ for (i = 0; i < SEC_BUF_BUSY_SIZE; i++) {
+ dmx->section_busy[i] = (
+ (i == SEC_BUF_BUSY_SIZE - 1) ?
+ DMX_READ_REG(device_no, SEC_BUFF_BUSY) :
+ dmx->section_busy[i + 1]);
+ section_busy32 &= dmx->section_busy[i];
+ }
+
+ /*count the number of '1' bits */
+ i = section_busy32;
+ i = (i & 0x55555555) + ((i & 0xaaaaaaaa) >> 1);
+ i = (i & 0x33333333) + ((i & 0xcccccccc) >> 2);
+ i = (i & 0x0f0f0f0f) + ((i & 0xf0f0f0f0) >> 4);
+ i = (i & 0x00ff00ff) + ((i & 0xff00ff00) >> 8);
+ i = (i & 0x0000ffff) + ((i & 0xffff0000) >> 16);
+ if (i > LARGE_SEC_BUFF_COUNT) {
+ /*too long some of the section
+ * buffers are being processed
+ */
+ DMX_WRITE_REG(device_no, SEC_BUFF_READY,
+ section_busy32);
+ }
+#endif
+ }
+ demux_int_status1 =
+ DMX_READ_REG(device_no, STB_INT_STATUS) & 0xfff7;
+ if (demux_int_status1 & (1 << TS_ERROR_PIN)) {
+ DMX_WRITE_REG(device_no,
+ STB_INT_STATUS,
+ (1 << TS_ERROR_PIN));
+ }
+ }
+
+end:
+ spin_unlock_irqrestore(&dvb->slock, flags);
+#ifdef ENABLE_SEC_BUFF_WATCHDOG
+ mod_timer(&dvb->watchdog_timer,
+ jiffies + msecs_to_jiffies(WATCHDOG_TIMER));
+#endif
+}
+
+static inline int sec_filter_match(struct aml_dmx *dmx, struct aml_filter *f,
+ u8 *p)
+{
+ int b;
+ u8 neq = 0;
+
+ if (!f->used || !dmx->channel[f->chan_id].used)
+ return 0;
+
+ for (b = 0; b < FILTER_LEN; b++) {
+ u8 xor = p[b] ^ f->value[b];
+
+ if (xor & f->maskandmode[b])
+ return 0;
+
+ if (xor & f->maskandnotmode[b])
+ neq = 1;
+ }
+
+ if (f->neq && !neq)
+ return 0;
+
+ return 1;
+}
+
+static void trigger_crc_monitor(struct aml_dmx *dmx)
+{
+ if (!dmx->crc_check_time) {
+ dmx->crc_check_time = jiffies;
+ dmx->crc_check_count = 0;
+ }
+
+ if (dmx->crc_check_count > 100) {
+ if (jiffies_to_msecs(jiffies - dmx->crc_check_time) <= 1000) {
+ struct aml_dvb *dvb = (struct aml_dvb *)dmx->demux.priv;
+
+ pr_error("Too many crc fail (%d crc fail in %d ms)!\n",
+ dmx->crc_check_count,
+ jiffies_to_msecs(jiffies - dmx->crc_check_time)
+ );
+ dmx_reset_dmx_hw_ex_unlock(dvb, dmx, 0);
+ }
+ dmx->crc_check_time = 0;
+ }
+
+ dmx->crc_check_count++;
+}
+static int section_crc(struct aml_dmx *dmx, struct aml_filter *f, u8 *p)
+{
+ int sec_len = (((p[1] & 0xF) << 8) | p[2]) + 3;
+ struct dvb_demux_feed *feed = dmx->channel[f->chan_id].feed;
+
+ if (feed->feed.sec.check_crc) {
+ struct dvb_demux *demux = feed->demux;
+ struct dmx_section_feed *sec = &feed->feed.sec;
+ int section_syntax_indicator;
+
+ section_syntax_indicator = ((p[1] & 0x80) != 0);
+ sec->seclen = sec_len;
+ sec->crc_val = ~0;
+ if (demux->check_crc32(feed, p, sec_len)) {
+ pr_error("section CRC check failed! pid[%d]\n", feed->pid);
+
+#if 0
+{
+ int i;
+
+ pr_error("sec:[%#lx:%#lx:%#lx-%#lx:%#lx:%#lx-%#lx:%#lx:%#lx]\n",
+ dmx->sec_cnt[0], dmx->sec_cnt_match[0], dmx->sec_cnt_crc_fail[0],
+ dmx->sec_cnt[1], dmx->sec_cnt_match[1], dmx->sec_cnt_crc_fail[1],
+ dmx->sec_cnt[2], dmx->sec_cnt_match[2], dmx->sec_cnt_crc_fail[2]);
+ pr_error("bad sec[%d]:\n", sec_len);
+ /*
+ * if (sec_len > 256)
+ * sec_len = 256;
+ * for (i = 0; i < sec_len; i++) {
+ * pr_err("%02x ", p[i]);
+ * if (!((i + 1) % 16))
+ * pr_err("\n");
+ * }
+ */
+}
+#endif
+ trigger_crc_monitor(dmx);
+ return 0;
+ }
+#if 0
+ int i;
+
+ for (i = 0; i < sec_len; i++) {
+ pr_dbg("%02x ", p[i]);
+ if (!((i + 1) % 16))
+ pr_dbg("\n");
+ }
+ pr_dbg("\nsection data\n");
+#endif
+ }
+
+ return 1;
+}
+
+static void section_notify(struct aml_dmx *dmx, struct aml_filter *f, u8 *p)
+{
+ int sec_len = (((p[1] & 0xF) << 8) | p[2]) + 3;
+ struct dvb_demux_feed *feed = dmx->channel[f->chan_id].feed;
+
+ if (feed && feed->cb.sec)
+ feed->cb.sec(p, sec_len, NULL, 0, f->filter);
+}
+
+static void hardware_match_section(struct aml_dmx *dmx,
+ u16 sec_num, u16 buf_num)
+{
+ u8 *p = (u8 *) dmx->sec_buf[buf_num].addr;
+ struct aml_filter *f;
+ int chid, i;
+ int need_crc = 1;
+
+ if (sec_num >= FILTER_COUNT) {
+ pr_dbg("sec_num invalid: %d\n", sec_num);
+ return;
+ }
+
+ dma_sync_single_for_cpu(dmx_get_dev(dmx),
+ dmx->sec_pages_map + (buf_num << 0x0c),
+ (1 << 0x0c), DMA_FROM_DEVICE);
+
+ f = &dmx->filter[sec_num];
+ chid = f->chan_id;
+
+ dmx->sec_cnt[SEC_CNT_HW]++;
+
+ for (i = 0; i < FILTER_COUNT; i++) {
+ f = &dmx->filter[i];
+ if (f->chan_id != chid)
+ continue;
+ if (sec_filter_match(dmx, f, p)) {
+ if (need_crc) {
+ dmx->sec_cnt_match[SEC_CNT_HW]++;
+ if (!section_crc(dmx, f, p)) {
+ dmx->sec_cnt_crc_fail[SEC_CNT_HW]++;
+ return;
+ }
+ need_crc = 0;
+ }
+ section_notify(dmx, f, p);
+ }
+ }
+}
+
+static void software_match_section(struct aml_dmx *dmx, u16 buf_num)
+{
+ u8 *p = (u8 *) dmx->sec_buf[buf_num].addr;
+ struct aml_filter *f, *fmatch = NULL;
+ int i, fid = -1;
+
+ dma_sync_single_for_cpu(dmx_get_dev(dmx),
+ dmx->sec_pages_map + (buf_num << 0x0c),
+ (1 << 0x0c), DMA_FROM_DEVICE);
+
+ dmx->sec_cnt[SEC_CNT_SW]++;
+
+ for (i = 0; i < FILTER_COUNT; i++) {
+ f = &dmx->filter[i];
+
+ if (sec_filter_match(dmx, f, p)) {
+ pr_dbg("[software match]filter %d match, pid %d\n",
+ i, dmx->channel[f->chan_id].pid);
+ if (!fmatch) {
+ fmatch = f;
+ fid = i;
+ } else {
+ pr_error("[sw match]Muli-filter match this\n"
+ "section, will skip this section\n");
+ return;
+ }
+ }
+ }
+
+ if (fmatch) {
+ pr_dbg("[software match]dispatch\n"
+ "section to filter %d pid %d\n",
+ fid, dmx->channel[fmatch->chan_id].pid);
+ dmx->sec_cnt_match[SEC_CNT_SW]++;
+ if (section_crc(dmx, fmatch, p))
+ section_notify(dmx, fmatch, p);
+ else
+ dmx->sec_cnt_crc_fail[SEC_CNT_SW]++;
+ } else {
+ pr_dbg("[software match]this section do not\n"
+ "match any filter!!!\n");
+ }
+}
+
+
+static int _rbuf_write(struct dvb_ringbuffer *buf, const u8 *src, size_t len)
+{
+ ssize_t free;
+
+ if (!len)
+ return 0;
+ if (!buf->data)
+ return 0;
+
+ free = dvb_ringbuffer_free(buf);
+ if (len > free) {
+ pr_error("sf: buffer overflow\n");
+ return -EOVERFLOW;
+ }
+
+ return dvb_ringbuffer_write(buf, src, len);
+}
+
+static int _rbuf_filter_pkts(struct dvb_ringbuffer *rb,
+ u8 *wrapbuf,
+ void (*swfilter_packets)(struct dvb_demux *demux,
+ const u8 *buf,
+ size_t count),
+ struct dvb_demux *demux)
+{
+ ssize_t len1 = 0;
+ ssize_t len2 = 0;
+ size_t off;
+ size_t count;
+ size_t size;
+
+ if (debug_irq & 0x4)
+ dump(&rb->data[rb->pread], (debug_irq & 0xFFF00) >> 8);
+
+ /*
+ * rb|====--------===[0x47]====|
+ * ^ ^
+ * wr rd
+ */
+
+ len1 = rb->pwrite - rb->pread;
+ if (len1 < 0) {
+ len1 = rb->size - rb->pread;
+ len2 = rb->pwrite;
+ }
+
+ for (off = 0; off < len1; off++) {
+ if (rb->data[rb->pread + off] == 0x47)
+ break;
+ }
+
+ if (off)
+ pr_dbg_irq_sf("off ->|%zd\n", off);
+
+ len1 -= off;
+ rb->pread = (rb->pread + off) % rb->size;
+
+ count = len1 / 188;
+ if (count) {
+ pr_dbg_irq_sf("pkt >> 1[%zd<->%zd]\n", rb->pread, rb->pwrite);
+ swfilter_packets(demux, rb->data + rb->pread, count);
+
+ size = count * 188;
+ len1 -= size;
+ rb->pread += size;
+ }
+
+ if (len2 && len1 && ((len1 + len2) > 188)) {
+ pr_dbg_irq_sf("pkt >> 2[%zd<->%zd]\n", rb->pread, rb->pwrite);
+ size = 188 - len1;
+ memcpy(wrapbuf, rb->data + rb->pread, len1);
+ memcpy(wrapbuf + len1, rb->data, size);
+ swfilter_packets(demux, wrapbuf, 1);
+ rb->pread = size;
+ len2 -= size;
+ }
+
+ if (len2) {
+ pr_dbg_irq_sf("pkt >> 3[%zd<->%zd]\n", rb->pread, rb->pwrite);
+ count = len2 / 188;
+ if (count) {
+ swfilter_packets(demux, rb->data + rb->pread, count);
+ rb->pread += count * 188;
+ }
+ }
+ return 0;
+}
+
+static void smallsection_match_section(struct aml_dmx *dmx, u8 *p, u16 sec_num)
+{
+ struct aml_filter *f;
+ int chid, i;
+ int need_crc = 1;
+
+ if (sec_num >= FILTER_COUNT) {
+ pr_dbg("sec_num invalid: %d\n", sec_num);
+ return;
+ }
+
+ f = &dmx->filter[sec_num];
+ chid = f->chan_id;
+
+ dmx->sec_cnt[SEC_CNT_SS]++;
+
+ for (i = 0; i < FILTER_COUNT; i++) {
+ f = &dmx->filter[i];
+ if (f->chan_id != chid)
+ continue;
+ if (sec_filter_match(dmx, f, p)) {
+ if (need_crc) {
+ dmx->sec_cnt_match[SEC_CNT_SS]++;
+ if (!section_crc(dmx, f, p)) {
+ dmx->sec_cnt_crc_fail[SEC_CNT_SS]++;
+ return;
+ }
+ need_crc = 0;
+ }
+ section_notify(dmx, f, p);
+ }
+ }
+
+}
+static void process_smallsection(struct aml_dmx *dmx)
+{
+
+ u32 v, wr, rd;
+ u32 data32;
+ struct aml_smallsec *ss = &dmx->smallsec;
+
+ v = DMX_READ_REG(dmx->id, DEMUX_SMALL_SEC_CTL);
+ wr = (v >> 8) & 0xff;
+ rd = (v >> 16) & 0xff;
+
+ if (rd != wr) {
+ int n1 = wr - rd,
+ n2 = 0,
+ max = (ss->bufsize>>8);
+ int i;
+ u8 *p;
+ int sec_len;
+
+ pr_dbg_irq_ss("secbuf[31] ctrl:0x%x\n", v);
+
+ if (n1 < 0) {
+ n1 = max - rd;
+ n2 = wr;
+ }
+ if (n1) {
+ pr_dbg_irq_ss("n1:%d\n", n1);
+ dma_sync_single_for_cpu(dmx_get_dev(dmx),
+ ss->buf_map+(rd<<8),
+ n1<<8,
+ DMA_FROM_DEVICE);
+ for (i = 0; i < n1; i++) {
+ p = (u8 *)ss->buf+((rd+i)<<8);
+ sec_len = (((p[1] & 0xF) << 8) | p[2]) + 3;
+ smallsection_match_section(dmx, p,
+ *(p+sec_len+1));
+ }
+ }
+ if (n2) {
+ pr_dbg_irq_ss("n2:%d\n", n2);
+ dma_sync_single_for_cpu(dmx_get_dev(dmx),
+ ss->buf_map,
+ n2<<8,
+ DMA_FROM_DEVICE);
+ for (i = 0; i < n2; i++) {
+ p = (u8 *)ss->buf+(i<<8);
+ sec_len = (((p[1] & 0xF) << 8) | p[2]) + 3;
+ smallsection_match_section(dmx, p,
+ *(p+sec_len+1));
+ }
+ }
+
+ rd = wr;
+ data32 = (DMX_READ_REG(dmx->id, DEMUX_SMALL_SEC_CTL)
+ & 0xff00ffff)
+ | (rd << 16);
+ DMX_WRITE_REG(dmx->id, DEMUX_SMALL_SEC_CTL, data32);
+ }
+}
+
+
+static void process_section(struct aml_dmx *dmx)
+{
+ u32 ready, i, sec_busy;
+ u16 sec_num;
+
+ /*pr_dbg("section\n"); */
+ ready = DMX_READ_REG(dmx->id, SEC_BUFF_READY);
+ if (ready) {
+#ifdef USE_AHB_MODE
+ /* WRITE_ISA_REG(AHB_BRIDGE_CTRL1,
+ * READ_ISA_REG (AHB_BRIDGE_CTRL1) | (1 << 31));
+ */
+ /* WRITE_ISA_REG(AHB_BRIDGE_CTRL1,
+ * READ_ISA_REG (AHB_BRIDGE_CTRL1) & (~ (1 << 31)));
+ */
+#endif
+
+ if ((ready & (1<<31)) && dmx->smallsec.enable) {
+ u32 v, wr, rd;
+
+ v = DMX_READ_REG(dmx->id, DEMUX_SMALL_SEC_CTL);
+ wr = (v >> 8) & 0xff;
+ rd = (v >> 16) & 0xff;
+ if ((wr < rd) && (5 > (rd - wr)))
+ pr_error("warning: small ss buf [w%dr%d]\n",
+ wr, rd);
+ pr_dbg_irq_ss("ss>%x\n",
+ DMX_READ_REG(dmx->id, DEMUX_SMALL_SEC_CTL));
+ process_smallsection(dmx);
+ /*tasklet_hi_schedule(&dmx->dmx_tasklet);*/
+ /*tasklet_schedule(&dmx->dmx_tasklet);*/
+ DMX_WRITE_REG(dmx->id, SEC_BUFF_READY, (1<<31));
+ return;
+ }
+
+ for (i = 0; i < SEC_BUF_COUNT; i++) {
+
+ if (!(ready & (1 << i)))
+ continue;
+
+ /* get section busy */
+ sec_busy = DMX_READ_REG(dmx->id, SEC_BUFF_BUSY);
+ /* get filter number */
+ DMX_WRITE_REG(dmx->id, SEC_BUFF_NUMBER, i);
+ sec_num = (DMX_READ_REG(dmx->id, SEC_BUFF_NUMBER) >> 8);
+
+ /*
+ * sec_buf_watchdog_count dispatch:
+ * byte0 -- always busy=0 's watchdog count
+ * byte1 -- always busy=1 & filter_num=31 's
+ * watchdog count
+ */
+
+ /* sec_busy is not set, check busy=0 watchdog count */
+ if (!(sec_busy & (1 << i))) {
+ /* clear other wd count of this buffer */
+ dmx->sec_buf_watchdog_count[i] &= 0x000000ff;
+ dmx->sec_buf_watchdog_count[i] += 0x1;
+ pr_dbg("bit%d ready=1, busy=0,\n"
+ "sec_num=%d for %d times\n",
+ i, sec_num,
+ dmx->sec_buf_watchdog_count[i]);
+ if (dmx->sec_buf_watchdog_count[i] >= 5) {
+ pr_dbg("busy=0 reach the max count,\n"
+ "try software match.\n");
+ software_match_section(dmx, i);
+ dmx->sec_buf_watchdog_count[i] = 0;
+ DMX_WRITE_REG(dmx->id, SEC_BUFF_READY,
+ (1 << i));
+ }
+ continue;
+ }
+
+ /* filter_num == 31 && busy == 1,check watchdog count */
+ if (sec_num >= FILTER_COUNT) {
+ /* clear other wd count of this buffer */
+ dmx->sec_buf_watchdog_count[i] &= 0x0000ff00;
+ dmx->sec_buf_watchdog_count[i] += 0x100;
+ pr_dbg("bit%d ready=1,busy=1,\n"
+ "sec_num=%d for %d times\n",
+ i, sec_num,
+ dmx->sec_buf_watchdog_count[i] >> 8);
+ if (dmx->sec_buf_watchdog_count[i] >= 0x500) {
+ pr_dbg("busy=1&filter_num=31\n"
+ " reach the max count, clear\n"
+ " the buf ready & busy!\n");
+ software_match_section(dmx, i);
+ dmx->sec_buf_watchdog_count[i] = 0;
+ DMX_WRITE_REG(dmx->id,
+ SEC_BUFF_READY,
+ (1 << i));
+ DMX_WRITE_REG(dmx->id,
+ SEC_BUFF_BUSY,
+ (1 << i));
+ }
+ continue;
+ }
+
+ /* now, ready & busy are both set and
+ * filter number is valid
+ */
+ if (dmx->sec_buf_watchdog_count[i] != 0)
+ dmx->sec_buf_watchdog_count[i] = 0;
+
+ /* process this section */
+ hardware_match_section(dmx, sec_num, i);
+
+ /* clear the ready & busy bit */
+ DMX_WRITE_REG(dmx->id, SEC_BUFF_READY, (1 << i));
+ DMX_WRITE_REG(dmx->id, SEC_BUFF_BUSY, (1 << i));
+ }
+ }
+}
+
+#ifdef NO_SUB
+static void process_sub(struct aml_dmx *dmx)
+{
+
+ u32 rd_ptr = 0;
+
+ u32 wr_ptr = READ_MPEG_REG(PARSER_SUB_WP);
+ u32 start_ptr = READ_MPEG_REG(PARSER_SUB_START_PTR);
+ u32 end_ptr = READ_MPEG_REG(PARSER_SUB_END_PTR);
+
+ u32 buffer1 = 0, buffer2 = 0;
+ u8 *buffer1_virt = 0, *buffer2_virt = 0;
+ u32 len1 = 0, len2 = 0;
+
+ if (!dmx->sub_buf_base_virt)
+ return;
+
+ rd_ptr = READ_MPEG_REG(PARSER_SUB_RP);
+ if (!rd_ptr)
+ return;
+ if (rd_ptr > wr_ptr) {
+ len1 = end_ptr - rd_ptr + 8;
+ buffer1 = rd_ptr;
+
+ len2 = wr_ptr - start_ptr;
+ buffer2 = start_ptr;
+
+ rd_ptr = start_ptr + len2;
+ } else if (rd_ptr < wr_ptr) {
+ len1 = wr_ptr - rd_ptr;
+ buffer1 = rd_ptr;
+ rd_ptr += len1;
+ len2 = 0;
+ } else if (rd_ptr == wr_ptr) {
+ pr_dbg("sub no data\n");
+ }
+
+ if (buffer1 && len1)
+#ifdef SUB_BUF_DMX
+ buffer1_virt = (void *)dmx->sub_pages + (buffer1 - start_ptr);
+#else
+ buffer1_virt = (void *)dmx->sub_buf_base_virt + (buffer1 - start_ptr);
+#endif
+
+ if (buffer2 && len2)
+#ifdef SUB_BUF_DMX
+ buffer2_virt = (void *)dmx->sub_pages + (buffer2 - start_ptr);
+#else
+ buffer2_virt = (void *)dmx->sub_buf_base_virt + (buffer2 - start_ptr);
+#endif
+
+ pr_dbg_irq_sub("sub: rd_ptr:%x buf1:%x len1:%d buf2:%x len2:%d\n",
+ rd_ptr, buffer1, len1, buffer2, len2);
+ pr_dbg_irq_sub("sub: buf1_virt:%p buf2_virt:%p\n",
+ buffer1_virt, buffer2_virt);
+
+ if (len1)
+ dma_sync_single_for_cpu(dmx_get_dev(dmx),
+ (dma_addr_t) buffer1, len1,
+ DMA_FROM_DEVICE);
+ if (len2)
+ dma_sync_single_for_cpu(dmx_get_dev(dmx),
+ (dma_addr_t) buffer2, len2,
+ DMA_FROM_DEVICE);
+
+ if (dmx->channel[2].used) {
+ if (dmx->channel[2].feed && dmx->channel[2].feed->cb.ts &&
+ ((buffer1_virt != NULL && len1 !=0 ) || (buffer2_virt != NULL && len2 != 0)))
+ {
+ dmx->channel[2].feed->cb.ts(buffer1_virt, len1,
+ buffer2_virt, len2,
+ &dmx->channel[2].feed->feed.ts);
+ }
+ }
+ WRITE_MPEG_REG(PARSER_SUB_RP, rd_ptr);
+}
+#endif
+
+static void process_pes(struct aml_dmx *dmx)
+{
+ long off, off_pre = pes_off_pre[dmx->id];
+ u8 *buffer1 = 0, *buffer2 = 0;
+ u8 *buffer1_phys = 0, *buffer2_phys = 0;
+ u32 len1 = 0, len2 = 0;
+ int i = 1;
+
+ off = (DMX_READ_REG(dmx->id, OTHER_WR_PTR) << 3);
+
+ pr_dbg_irq_pes("[%d]WR:0x%x PES WR:0x%x\n", dmx->id,
+ DMX_READ_REG(dmx->id, OTHER_WR_PTR),
+ DMX_READ_REG(dmx->id, OB_PES_WR_PTR));
+ buffer1 = (u8 *)(dmx->pes_pages + off_pre);
+ pr_dbg_irq_pes("[%d]PES WR[%02x %02x %02x %02x %02x %02x %02x %02x",
+ dmx->id,
+ buffer1[0], buffer1[1], buffer1[2], buffer1[3],
+ buffer1[4], buffer1[5], buffer1[6], buffer1[7]);
+ pr_dbg_irq_pes(" %02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ buffer1[8], buffer1[9], buffer1[10], buffer1[11],
+ buffer1[12], buffer1[13], buffer1[14], buffer1[15]);
+
+ if (off > off_pre) {
+ len1 = off-off_pre;
+ buffer1 = (unsigned char *)(dmx->pes_pages + off_pre);
+ } else if (off < off_pre) {
+ len1 = dmx->pes_buf_len-off_pre;
+ buffer1 = (unsigned char *)(dmx->pes_pages + off_pre);
+ len2 = off;
+ buffer2 = (unsigned char *)dmx->pes_pages;
+ } else if (off == off_pre) {
+ pr_dbg("pes no data\n");
+ }
+ pes_off_pre[dmx->id] = off;
+ if (len1) {
+ buffer1_phys = (unsigned char *)virt_to_phys(buffer1);
+ dma_sync_single_for_cpu(dmx_get_dev(dmx),
+ (dma_addr_t)buffer1_phys, len1, DMA_FROM_DEVICE);
+ }
+ if (len2) {
+ buffer2_phys = (unsigned char *)virt_to_phys(buffer2);
+ dma_sync_single_for_cpu(dmx_get_dev(dmx),
+ (dma_addr_t)buffer2_phys, len2, DMA_FROM_DEVICE);
+ }
+ if (len1 || len2) {
+ struct aml_channel *ch;
+
+ for (i = 0; i < CHANNEL_COUNT; i++) {
+ ch = &dmx->channel[i];
+ if (ch->used && ch->feed
+ && (ch->feed->type == DMX_TYPE_TS)) {
+ if (ch->feed->ts_type & TS_PAYLOAD_ONLY) {
+ ch->feed->cb.ts(buffer1,
+ len1, buffer2, len2,
+ &ch->feed->feed.ts);
+ }
+ }
+ }
+ }
+}
+
+static void process_om_read(struct aml_dmx *dmx)
+{
+ unsigned int i;
+ unsigned short om_cmd_status_data_0 = 0;
+ unsigned short om_cmd_status_data_1 = 0;
+/* unsigned short om_cmd_status_data_2 = 0;*/
+ unsigned short om_cmd_data_out = 0;
+
+ om_cmd_status_data_0 = DMX_READ_REG(dmx->id, OM_CMD_STATUS);
+ om_cmd_status_data_1 = DMX_READ_REG(dmx->id, OM_CMD_DATA);
+/* om_cmd_status_data_2 = DMX_READ_REG(dmx->id, OM_CMD_DATA2);*/
+
+ if (om_cmd_status_data_0 & 1) {
+ DMX_WRITE_REG(dmx->id, OM_DATA_RD_ADDR,
+ (1 << 15) | ((om_cmd_status_data_1 & 0xff) << 2));
+ for (i = 0; i < (((om_cmd_status_data_1 >> 7) & 0x1fc) >> 1);
+ i++) {
+ om_cmd_data_out = DMX_READ_REG(dmx->id, OM_DATA_RD);
+ }
+
+ om_cmd_data_out = DMX_READ_REG(dmx->id, OM_DATA_RD_ADDR);
+ DMX_WRITE_REG(dmx->id, OM_DATA_RD_ADDR, 0);
+ DMX_WRITE_REG(dmx->id, OM_CMD_STATUS, 1);
+ }
+}
+
+static void dmx_irq_bh_handler(unsigned long arg)
+{
+ struct aml_dmx *dmx = (struct aml_dmx *)arg;
+#if 0
+ u32 status;
+
+ status = DMX_READ_REG(dmx->id, STB_INT_STATUS);
+
+ if (status)
+ DMX_WRITE_REG(dmx->id, STB_INT_STATUS, status);
+#endif
+ process_smallsection(dmx);
+}
+
+static irqreturn_t dmx_irq_handler(int irq_number, void *para)
+{
+ struct aml_dmx *dmx = (struct aml_dmx *)para;
+ struct aml_dvb *dvb = aml_get_dvb_device();
+ u32 status;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+ status = DMX_READ_REG(dmx->id, STB_INT_STATUS);
+ if (!status)
+ goto irq_handled;
+
+ pr_dbg_irq("demux %d irq status: 0x%08x\n", dmx->id, status);
+
+ if (status & (1 << SECTION_BUFFER_READY))
+ process_section(dmx);
+#ifdef NO_SUB
+ if (status & (1 << SUB_PES_READY)) {
+ /*If the subtitle is set by tsdemux,
+ *do not parser in demux driver.
+ */
+ if (dmx->sub_chan == -1)
+ process_sub(dmx);
+ }
+#endif
+ if (status & (1 << OTHER_PES_READY))
+ process_pes(dmx);
+ if (status & (1 << OM_CMD_READ_PENDING))
+ process_om_read(dmx);
+ /*
+ *if (status & (1 << DUPLICATED_PACKET)) {
+ *}
+ *if (status & (1 << DIS_CONTINUITY_PACKET)) {
+ *}
+ *if (status & (1 << VIDEO_SPLICING_POINT)) {
+ *}
+ *if (status & (1 << AUDIO_SPLICING_POINT)) {
+ *}
+ */
+ if (status & (1 << TS_ERROR_PIN))
+ pr_error("TS_ERROR_PIN\n");
+
+ if (status & (1 << NEW_PDTS_READY)) {
+ u32 pdts_status = DMX_READ_REG(dmx->id, STB_PTS_DTS_STATUS);
+
+ if (pdts_status & (1 << VIDEO_PTS_READY)) {
+ video_pts = DMX_READ_REG(dmx->id, VIDEO_PTS_DEMUX);
+ video_pts_bit32 =
+ (pdts_status & (1 << VIDEO_PTS_BIT32)) ? 1 : 0;
+ if (!first_video_pts
+ || 0 > (int)(video_pts - first_video_pts))
+ first_video_pts = video_pts;
+ }
+
+ if (pdts_status & (1 << AUDIO_PTS_READY)) {
+ audio_pts = DMX_READ_REG(dmx->id, AUDIO_PTS_DEMUX);
+ audio_pts_bit32 =
+ (pdts_status & (1 << AUDIO_PTS_BIT32)) ? 1 : 0;
+ if (!first_audio_pts
+ || 0 > (int)(audio_pts - first_audio_pts))
+ first_audio_pts = audio_pts;
+ }
+ }
+
+ if (dmx->irq_handler)
+ dmx->irq_handler(dmx->dmx_irq, (void *)(long)dmx->id);
+
+ DMX_WRITE_REG(dmx->id, STB_INT_STATUS, status);
+
+ /*tasklet_schedule(&dmx->dmx_tasklet);*/
+
+ {
+ if (!dmx->int_check_time) {
+ dmx->int_check_time = jiffies;
+ dmx->int_check_count = 0;
+ }
+
+ if (jiffies_to_msecs(jiffies - dmx->int_check_time) >= 100
+ || dmx->int_check_count > 1000) {
+ if (dmx->int_check_count > 1000) {
+ struct aml_dvb *dvb =
+ (struct aml_dvb *)dmx->demux.priv;
+ pr_error("Too many irq (%d irq in %d ms)!\n",
+ dmx->int_check_count,
+ jiffies_to_msecs(jiffies -
+ dmx->int_check_time));
+ if (dmx->fe && !dmx->in_tune)
+ DMX_WRITE_REG(dmx->id, STB_INT_MASK, 0);
+ dmx_reset_hw_ex(dvb, 0);
+ }
+ dmx->int_check_time = 0;
+ }
+
+ dmx->int_check_count++;
+
+ if (dmx->in_tune) {
+ dmx->error_check++;
+ if (dmx->error_check > 200)
+ DMX_WRITE_REG(dmx->id, STB_INT_MASK, 0);
+ }
+ }
+
+irq_handled:
+ spin_unlock_irqrestore(&dvb->slock, flags);
+ return IRQ_HANDLED;
+}
+
+static inline int dmx_get_order(unsigned long size)
+{
+ int order;
+
+ order = -1;
+ do {
+ size >>= 1;
+ order++;
+ } while (size);
+
+ return order;
+}
+
+static inline int dmx_get_afifo_size(struct aml_asyncfifo *afifo)
+{
+ return afifo->secure_enable && afifo->blk.len ? afifo->blk.len : asyncfifo_buf_len;
+}
+
+static void dvr_process_channel(struct aml_asyncfifo *afifo,
+ struct aml_channel *channel,
+ u32 total, u32 size,
+ struct aml_swfilter *sf)
+{
+ int cnt;
+ int ret = 0;
+ struct aml_dvr_block blk;
+
+ if (afifo->buf_read > afifo->buf_toggle) {
+ cnt = total - afifo->buf_read;
+ if (!(afifo->secure_enable && afifo->blk.addr)) {
+ dma_sync_single_for_cpu(asyncfifo_get_dev(afifo),
+ afifo->pages_map+afifo->buf_read*size,
+ cnt*size,
+ DMA_FROM_DEVICE);
+ if (sf)
+ ret = _rbuf_write(&sf->rbuf,
+ (u8 *)afifo->pages+afifo->buf_read*size,
+ cnt*size);
+ else
+ channel->dvr_feed->cb.ts(
+ (u8 *)afifo->pages+afifo->buf_read*size,
+ cnt*size, NULL, 0,
+ &channel->dvr_feed->feed.ts);
+ } else {
+ blk.addr = afifo->blk.addr+afifo->buf_read*size;
+ blk.len = cnt*size;
+ if (sf)
+ ret = _rbuf_write(&sf->rbuf,
+ (u8 *)afifo->pages+afifo->buf_read*size,
+ cnt*size);
+ else {
+ channel->dvr_feed->cb.ts(
+ (u8 *)&blk,
+ sizeof(struct aml_dvr_block),
+ NULL, 0,
+ &channel->dvr_feed->feed.ts);
+ }
+ }
+ afifo->buf_read = 0;
+ }
+
+ if (afifo->buf_toggle > afifo->buf_read) {
+ cnt = afifo->buf_toggle - afifo->buf_read;
+ if (!(afifo->secure_enable && afifo->blk.addr)) {
+ dma_sync_single_for_cpu(asyncfifo_get_dev(afifo),
+ afifo->pages_map+afifo->buf_read*size,
+ cnt*size,
+ DMA_FROM_DEVICE);
+ if (sf) {
+ if (ret >= 0)
+ ret = _rbuf_write(&sf->rbuf,
+ (u8 *)afifo->pages+afifo->buf_read*size,
+ cnt*size);
+ } else {
+ channel->dvr_feed->cb.ts(
+ (u8 *)afifo->pages+afifo->buf_read*size,
+ cnt*size, NULL, 0,
+ &channel->dvr_feed->feed.ts);
+ }
+ } else {
+ blk.addr = afifo->blk.addr+afifo->buf_read*size;
+ blk.len = cnt*size;
+ if (sf)
+ ret = _rbuf_write(&sf->rbuf,
+ (u8 *)afifo->pages+afifo->buf_read*size,
+ cnt*size);
+ else {
+ channel->dvr_feed->cb.ts(
+ (u8 *)&blk,
+ sizeof(struct aml_dvr_block),
+ NULL, 0,
+ &channel->dvr_feed->feed.ts);
+ }
+ }
+ afifo->buf_read = afifo->buf_toggle;
+ }
+
+ if (sf && ret > 0) {
+ _rbuf_filter_pkts(&sf->rbuf, sf->wrapbuf,
+ dvb_dmx_swfilter_packets,
+ channel->dvr_feed->demux);
+ } else if (sf && ret <= 0)
+ pr_error("sf rbuf write error[%d]\n", ret);
+ else
+ pr_dbg_irq_dvr("write data to dvr\n");
+}
+
+static uint32_t last_afifo_time = 0;
+static void dvr_irq_bh_handler(unsigned long arg)
+{
+ struct aml_asyncfifo *afifo = (struct aml_asyncfifo *)arg;
+ struct aml_dvb *dvb = afifo->dvb;
+ struct aml_dmx *dmx;
+ u32 size, total;
+ int i, factor;
+ unsigned long flags;
+
+ pr_dbg_irq_dvr("async fifo %d irq, interval:%d ms, %d data\n", afifo->id,
+ jiffies_to_msecs(jiffies - last_afifo_time), afifo->flush_size);
+
+ spin_lock_irqsave(&dvb->slock, flags);
+
+ if (dvb && afifo->source >= AM_DMX_0 && afifo->source < AM_DMX_MAX) {
+ dmx = &dvb->dmx[afifo->source];
+ // pr_inf("async fifo %d irq, source:%d\n", afifo->id,afifo->source);
+ if (dmx->init && dmx->record) {
+ struct aml_swfilter *sf = &dvb->swfilter;
+ int issf = 0;
+
+ total = afifo->buf_len / afifo->flush_size;
+ factor = dmx_get_order(total);
+ size = afifo->buf_len >> factor;
+
+ if (sf->user && (sf->afifo == afifo))
+ issf = 1;
+
+ for (i = 0; i < CHANNEL_COUNT; i++) {
+ if (dmx->channel[i].used
+ && dmx->channel[i].dvr_feed) {
+ dvr_process_channel(afifo,
+ &dmx->channel[i],
+ total,
+ size,
+ issf?sf:NULL);
+ break;
+ }
+ }
+
+ }
+ }
+ spin_unlock_irqrestore(&dvb->slock, flags);
+ last_afifo_time = jiffies;
+}
+
+static irqreturn_t dvr_irq_handler(int irq_number, void *para)
+{
+ struct aml_asyncfifo *afifo = (struct aml_asyncfifo *)para;
+ int factor = dmx_get_order(afifo->buf_len / afifo->flush_size);
+
+ afifo->buf_toggle++;
+ afifo->buf_toggle %= (1 << factor);
+ tasklet_schedule(&afifo->asyncfifo_tasklet);
+ return IRQ_HANDLED;
+}
+
+/*Enable the STB*/
+static void stb_enable(struct aml_dvb *dvb)
+{
+ int out_src, des_in, en_des, fec_clk, hiu, dec_clk_en;
+ int src, tso_src, i;
+ u32 fec_s0, fec_s1,fec_s2;
+ u32 invert0, invert1, invert2;
+ u32 data;
+
+ switch (dvb->stb_source) {
+ case AM_TS_SRC_DMX0:
+ src = dvb->dmx[0].source;
+ break;
+ case AM_TS_SRC_DMX1:
+ src = dvb->dmx[1].source;
+ break;
+ case AM_TS_SRC_DMX2:
+ src = dvb->dmx[2].source;
+ break;
+ default:
+ src = dvb->stb_source;
+ break;
+ }
+
+ switch (src) {
+ case AM_TS_SRC_TS0:
+ fec_clk = tsfile_clkdiv;
+ hiu = 0;
+ break;
+ case AM_TS_SRC_TS1:
+ fec_clk = tsfile_clkdiv;
+ hiu = 0;
+ break;
+ case AM_TS_SRC_TS2:
+ fec_clk = tsfile_clkdiv;
+ hiu = 0;
+ break;
+ case AM_TS_SRC_TS3:
+ fec_clk = tsfile_clkdiv;
+ hiu = 0;
+ break;
+ case AM_TS_SRC_S_TS0:
+ fec_clk = tsfile_clkdiv;
+ hiu = 0;
+ break;
+ case AM_TS_SRC_S_TS1:
+ fec_clk = tsfile_clkdiv;
+ hiu = 0;
+ break;
+ case AM_TS_SRC_S_TS2:
+ fec_clk = tsfile_clkdiv;
+ hiu = 0;
+ break;
+ case AM_TS_SRC_HIU:
+ fec_clk = tsfile_clkdiv;
+ hiu = 1;
+ break;
+ case AM_TS_SRC_HIU1:
+ fec_clk = tsfile_clkdiv;
+ hiu = 1;
+ break;
+ default:
+ fec_clk = 0;
+ hiu = 0;
+ break;
+ }
+
+ switch (dvb->dsc[0].source) {
+ case AM_TS_SRC_DMX0:
+ des_in = 0;
+ en_des = 1;
+ dec_clk_en = 1;
+ break;
+ case AM_TS_SRC_DMX1:
+ des_in = 1;
+ en_des = 1;
+ dec_clk_en = 1;
+ break;
+ case AM_TS_SRC_DMX2:
+ des_in = 2;
+ en_des = 1;
+ dec_clk_en = 1;
+ break;
+ default:
+ des_in = 0;
+ en_des = 0;
+ dec_clk_en = 0;
+ break;
+ }
+ switch (dvb->tso_source) {
+ case AM_TS_SRC_DMX0:
+ tso_src = dvb->dmx[0].source;
+ break;
+ case AM_TS_SRC_DMX1:
+ tso_src = dvb->dmx[1].source;
+ break;
+ case AM_TS_SRC_DMX2:
+ tso_src = dvb->dmx[2].source;
+ break;
+ default:
+ tso_src = dvb->tso_source;
+ break;
+ }
+
+ switch (tso_src) {
+ case AM_TS_SRC_TS0:
+ out_src = 0;
+ break;
+ case AM_TS_SRC_TS1:
+ out_src = 1;
+ break;
+ case AM_TS_SRC_TS2:
+ out_src = 2;
+ break;
+ case AM_TS_SRC_TS3:
+ out_src = 3;
+ break;
+ case AM_TS_SRC_S_TS0:
+ out_src = 6;
+ break;
+ case AM_TS_SRC_S_TS1:
+ out_src = 5;
+ break;
+ case AM_TS_SRC_S_TS2:
+ out_src = 4;
+ break;
+ case AM_TS_SRC_HIU:
+ out_src = 7;
+ break;
+ default:
+ out_src = 0;
+ break;
+ }
+
+ pr_dbg("[stb]src: %d, dsc1in: %d, tso: %d\n", src, des_in, out_src);
+
+ fec_s0 = 0;
+ fec_s1 = 0;
+ fec_s2 = 0;
+ invert0 = 0;
+ invert1 = 0;
+ invert2 = 0;
+
+ for (i = 0; i < dvb->ts_in_total_count; i++) {
+ if (dvb->ts[i].s2p_id == 0)
+ fec_s0 = i;
+ else if (dvb->ts[i].s2p_id == 1)
+ fec_s1 = i;
+ else if (dvb->ts[i].s2p_id == 2)
+ fec_s2 = i;
+ }
+
+ invert0 = dvb->s2p[0].invert;
+ invert1 = dvb->s2p[1].invert;
+
+ WRITE_MPEG_REG(STB_TOP_CONFIG,
+ (invert1 << INVERT_S2P1_FEC_CLK) |
+ (fec_s1 << S2P1_FEC_SERIAL_SEL) |
+ (out_src << TS_OUTPUT_SOURCE) |
+ (des_in << DES_INPUT_SEL) |
+ (en_des << ENABLE_DES_PL) |
+ (dec_clk_en << ENABLE_DES_PL_CLK) |
+ (invert0 << INVERT_S2P0_FEC_CLK) |
+ (fec_s0 << S2P0_FEC_SERIAL_SEL)|
+ (ciplus));
+ ciplus = 0;
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_TL1) {
+ invert2 = dvb->s2p[2].invert;
+
+ WRITE_MPEG_REG(STB_S2P2_CONFIG,
+ (invert2 << INVERT_S2P2_FEC_CLK) |
+ (fec_s2 << S2P2_FEC_SERIAL_SEL));
+ }
+
+ if (dvb->reset_flag)
+ hiu = 0;
+ /* invert ts out clk,add ci model need add this*/
+ if (dvb->ts_out_invert) {
+ printk("ts out invert ---\r\n");
+ data = READ_MPEG_REG(TS_TOP_CONFIG);
+ data |= 1 << TS_OUT_CLK_INVERT;
+ WRITE_MPEG_REG(TS_TOP_CONFIG, data);
+ }
+
+ if (src == AM_TS_SRC_HIU1) {
+ WRITE_MPEG_REG(TS_HIU1_CONFIG,
+ (demux_skipbyte << FILE_M2TS_SKIP_BYTES_HIU1) |
+ (hiu << TS_HIU_ENABLE_HIU1) |
+ (fec_clk << FEC_CLK_DIV_HIU1) |
+ (0xBB << TS_PACKAGE_LENGTH_SUB_1_HIU1) |
+ (0x47 << FEC_SYNC_BYTE_HIU1));
+ } else {
+ /* invert ts out clk end */
+ WRITE_MPEG_REG(TS_FILE_CONFIG,
+ (demux_skipbyte << 16) |
+ (6 << DES_OUT_DLY) |
+ (3 << TRANSPORT_SCRAMBLING_CONTROL_ODD) |
+ (3 << TRANSPORT_SCRAMBLING_CONTROL_ODD_2) |
+ (hiu << TS_HIU_ENABLE) | (fec_clk << FEC_FILE_CLK_DIV));
+ }
+}
+
+int dsc_set_pid(struct aml_dsc_channel *ch, int pid)
+{
+ struct aml_dsc *dsc = ch->dsc;
+ int is_dsc2 = (dsc->id == 1) ? 1 : 0;
+ u32 data;
+
+ WRITE_MPEG_REG(TS_PL_PID_INDEX,
+ ((ch->id & 0x0f) >> 1)+(is_dsc2 ? 4 : 0));
+ data = READ_MPEG_REG(TS_PL_PID_DATA);
+ if (ch->id & 1) {
+ data &= 0xFFFF0000;
+ data |= pid & 0x1fff;
+ if (!ch->used)
+ data |= 1 << PID_MATCH_DISABLE_LOW;
+ } else {
+ data &= 0xFFFF;
+ data |= (pid & 0x1fff) << 16;
+ if (!ch->used)
+ data |= 1 << PID_MATCH_DISABLE_HIGH;
+ }
+ WRITE_MPEG_REG(TS_PL_PID_INDEX,
+ ((ch->id & 0x0f) >> 1)+(is_dsc2 ? 4 : 0));
+ WRITE_MPEG_REG(TS_PL_PID_DATA, data);
+ WRITE_MPEG_REG(TS_PL_PID_INDEX, 0);
+
+ if (ch->used)
+ pr_dbg("set DSC %d ch %d PID %d\n", dsc->id, ch->id, pid);
+ else
+ pr_dbg("disable DSC %d ch %d\n", dsc->id, ch->id);
+ return 0;
+}
+
+int dsc_get_pid(struct aml_dsc_channel *ch, int *pid)
+{
+ struct aml_dsc *dsc = ch->dsc;
+ int is_dsc2 = (dsc->id == 1) ? 1 : 0;
+ u32 data;
+
+ WRITE_MPEG_REG(TS_PL_PID_INDEX,
+ ((ch->id & 0x0f) >> 1)+(is_dsc2 ? 4 : 0));
+ data = READ_MPEG_REG(TS_PL_PID_DATA);
+ if (ch->id & 1) {
+ *pid = data & 0x1fff;
+ } else {
+ *pid = (data >> 16) & 0x1fff;
+ }
+
+ /*pr_dbg("%s,get DSC %d ch %d PID %d\n", __FUNCTION__,dsc->id, ch->id, *pid);*/
+ return 0;
+}
+
+int dsc_set_key(struct aml_dsc_channel *ch, int flags, enum ca_cw_type type,
+ u8 *key)
+{
+ /*struct aml_dsc *dsc = ch->dsc;*/
+ int ret = -1;
+
+ switch (type) {
+ case CA_CW_DVB_CSA_EVEN:
+ case CA_CW_DVB_CSA_ODD:
+ aml_ci_plus_disable();
+ ret = dsc_set_csa_key(ch, flags, type, key);
+ if (ret != 0)
+ goto END;
+ /* Different with old mode, do change */
+ if (ch->work_mode == CIPLUS_MODE || ch->work_mode == -1) {
+ if (ch->work_mode == -1)
+ pr_inf("dsc[%d:%d] enable\n",
+ ch->dsc->id, ch->id);
+ else
+ pr_inf("dsc[%d:%d] enable (from ciplus)\n",
+ ch->dsc->id, ch->id);
+ ch->mode = ECB_MODE;
+ ch->work_mode = DVBCSA_MODE;
+ }
+ break;
+ case CA_CW_AES_EVEN:
+ case CA_CW_AES_ODD:
+ case CA_CW_AES_EVEN_IV:
+ case CA_CW_AES_ODD_IV:
+ case CA_CW_DES_EVEN:
+ case CA_CW_DES_ODD:
+ case CA_CW_SM4_EVEN:
+ case CA_CW_SM4_ODD:
+ case CA_CW_SM4_EVEN_IV:
+ case CA_CW_SM4_ODD_IV:
+ am_ci_plus_set_output(ch);
+ ret = dsc_set_aes_des_sm4_key(ch, flags, type, key);
+ if (ret != 0)
+ goto END;
+ /* Different with old mode, do change */
+ if (ch->work_mode == DVBCSA_MODE || ch->work_mode == -1) {
+ if (ch->work_mode == -1)
+ pr_inf("dsc[%d:%d] ciplus enable\n",
+ ch->dsc->id, ch->id);
+ else
+ pr_inf("dsc[%d:%d] ciplus enable (from dsc)\n",
+ ch->dsc->id, ch->id);
+ ch->work_mode = CIPLUS_MODE;
+ }
+ break;
+ default:
+ break;
+ }
+END:
+ return ret;
+}
+
+int dsc_set_keys(struct aml_dsc_channel *ch)
+{
+ int types = ch->set & 0xFFFFFF;
+ int flag = (ch->set >> 24) & 0xFF;
+ int i;
+ u8 *k;
+ int ret = 0;
+
+ for (i = 0; i < CA_CW_TYPE_MAX; i++) {
+ if (types & (1 << i)) {
+ k = NULL;
+ switch (i) {
+ case CA_CW_DVB_CSA_EVEN:
+ case CA_CW_AES_EVEN:
+ case CA_CW_DES_EVEN:
+ case CA_CW_SM4_EVEN:
+ k = ch->even;
+ break;
+ case CA_CW_DVB_CSA_ODD:
+ case CA_CW_AES_ODD:
+ case CA_CW_DES_ODD:
+ case CA_CW_SM4_ODD:
+ k = ch->odd;
+ break;
+ case CA_CW_AES_EVEN_IV:
+ case CA_CW_SM4_EVEN_IV:
+ k = ch->even_iv;
+ break;
+ case CA_CW_AES_ODD_IV:
+ case CA_CW_SM4_ODD_IV:
+ k = ch->odd_iv;
+ break;
+ default:
+ break;
+ }
+ /*
+ if (k)
+ pr_inf("dsc ch:%d flag:%d type:%d\n", ch->id, flag, i);
+ */
+ if (k)
+ ret = dsc_set_key(ch, flag,
+ i,
+ k);
+ }
+ }
+ return 0;
+}
+
+static int dsc_set_csa_key(struct aml_dsc_channel *ch, int flags,
+ enum ca_cw_type type, u8 *key)
+{
+ struct aml_dsc *dsc = ch->dsc;
+ int is_dsc2 = (dsc->id == 1) ? 1 : 0;
+ u16 k0, k1, k2, k3;
+ u32 key0, key1;
+ int reg;
+
+ if (flags & DSC_FROM_KL) {
+ k0 = k1 = k2 = k3 = 0;
+ /*dummy write to check if kl not working*/
+ key0 = key1 = 0;
+ WRITE_MPEG_REG(COMM_DESC_KEY0, key0);
+ WRITE_MPEG_REG(COMM_DESC_KEY1, key1);
+
+ /*tdes? :*/
+ if (get_cpu_type() == MESON_CPU_MAJOR_ID_GXBB) {
+ WRITE_MPEG_REG(COMM_DESC_KEY_RW,
+/* (type ? (1 << 6) : (1 << 5)) | */
+ ((1 << 5)) |
+ ((ch->id + type * DSC_COUNT)+
+ (is_dsc2 ? 16 : 0)));
+ }
+ if (get_cpu_type() == MESON_CPU_MAJOR_ID_GXL ||
+ get_cpu_type() == MESON_CPU_MAJOR_ID_GXM) {
+ pr_info("do kl..\n");
+ WRITE_MPEG_REG(COMM_DESC_KEY_RW,
+ (type ? (1 << 6) : (1 << 5)) | (1<<7) |
+ ((ch->id + type * DSC_COUNT)+
+ (is_dsc2 ? 16 : 0)));
+ }
+ reg = (type ? (1 << 6) : (1 << 5)) |
+ ((ch->id + type * DSC_COUNT)+
+ (is_dsc2 ? 16 : 0));
+ } else {
+ k0 = (key[0] << 8) | key[1];
+ k1 = (key[2] << 8) | key[3];
+ k2 = (key[4] << 8) | key[5];
+ k3 = (key[6] << 8) | key[7];
+
+ key0 = (k0 << 16) | k1;
+ key1 = (k2 << 16) | k3;
+ WRITE_MPEG_REG(COMM_DESC_KEY0, key0);
+ WRITE_MPEG_REG(COMM_DESC_KEY1, key1);
+
+ reg = (ch->id + type * DSC_COUNT)+(is_dsc2 ? 16 : 0);
+ WRITE_MPEG_REG(COMM_DESC_KEY_RW, reg);
+ }
+
+ return 0;
+}
+
+/************************* AES DESC************************************/
+/*#define STB_TOP_CONFIG 0x16f0
+#define CIPLUS_KEY0 0x16f8
+#define CIPLUS_KEY1 0x16f9
+#define CIPLUS_KEY2 0x16fa
+#define CIPLUS_KEY3 0x16fb
+#define CIPLUS_KEY_WR 0x16fc
+#define CIPLUS_CONFIG 0x16fd
+#define CIPLUS_ENDIAN 0x16fe*/
+
+#define ENABLE_DEC_PL 7
+#define ENABLE_DES_PL_CLK 15
+
+#define KEY_WR_AES_IV_B 5
+#define KEY_WR_AES_IV_A 4
+#define KEY_WR_AES_B 3
+#define KEY_WR_AES_A 2
+#define KEY_WR_DES_B 1
+#define KEY_WR_DES_A 0
+
+#define IDSA_MODE_BIT 31
+#define SM4_MODE 30
+#define DES2_KEY_ENDIAN 25
+#define DES2_IN_ENDIAN 21
+#define DES2_CFG 6
+#define DES2_EN 5
+#define CNTL_ENABLE 3
+#define AES_CBC_DISABLE 2
+#define AES_EN 1
+#define DES_EN 0
+
+#define AES_IV_ENDIAN 28
+#define AES_MSG_OUT_ENDIAN 24
+#define AES_MSG_IN_ENDIAN 20
+#define AES_KEY_ENDIAN 16
+#define DES_MSG_OUT_ENDIAN 8
+#define DES_MSG_IN_ENDIAN 4
+#define DES_KEY_ENDIAN 0
+
+#define ALGO_AES 0
+#define ALGO_SM4 1
+#define ALGO_DES 2
+
+#if 0
+static void aml_ci_plus_set_stb(void)
+{
+ unsigned int data;
+ /* data = READ_MPEG_REG(FEC_INPUT_CONTROL); */
+ /* data |= (0<<FEC_SEL); */
+ /* data |= (1<<FEC_CORE_SEL); */
+ /* data |= (1<<FEC_INPUT_FEC_CLK);
+ * local playback will not work if set this
+ */
+ /* WRITE_MPEG_REG(FEC_INPUT_CONTROL, data); */
+
+ data = READ_MPEG_REG(STB_TOP_CONFIG);
+ WRITE_MPEG_REG(STB_TOP_CONFIG, data |
+ (0 << CIPLUS_IN_SEL) | (0 << CIPLUS_OUT_SEL));
+ data = READ_MPEG_REG(STB_TOP_CONFIG);
+ /* data |= (1<<ENABLE_DEC_PL); bit 7 --
+ * enable_des_pl, this step was set in dsc_enable
+ */
+ /*bit 15 -- enable_des_pl_clk*/
+ /* data |= (1<<ENABLE_DES_PL_CLK); */
+ data |= (1<<CIPLUS_OUT_SEL);/*bit 28 -- ciplus_out_sel from ciplus*/
+ WRITE_MPEG_REG(STB_TOP_CONFIG, data);
+ data = READ_MPEG_REG(STB_TOP_CONFIG);
+}
+#endif
+
+/*
+ * param:
+ * key:
+ * 16bytes IV key
+ * type:
+ * AM_DSC_KEY_TYPE_AES_ODD IV odd key
+ * AM_DSC_KEY_TYPE_AES_EVEN IV even key
+ */
+void aml_ci_plus_set_iv(struct aml_dsc_channel *ch, enum ca_cw_type type,
+ u8 *key)
+{
+ unsigned int k0, k1, k2, k3;
+
+ k3 = (key[0] << 24) | (key[1] << 16) | (key[2] << 8) | key[3];
+ k2 = (key[4] << 24) | (key[5] << 16) | (key[6] << 8) | key[7];
+ k1 = (key[8] << 24) | (key[9] << 16) | (key[10] << 8) | key[11];
+ k0 = (key[12] << 24) | (key[13] << 16) | (key[14] << 8) | key[15];
+
+ if (type == CA_CW_AES_EVEN_IV ||
+ type == CA_CW_SM4_EVEN_IV) {
+ WRITE_MPEG_REG(CIPLUS_KEY0, k0);
+ WRITE_MPEG_REG(CIPLUS_KEY1, k1);
+ WRITE_MPEG_REG(CIPLUS_KEY2, k2);
+ WRITE_MPEG_REG(CIPLUS_KEY3, k3);
+ WRITE_MPEG_REG(CIPLUS_KEY_WR,
+ (ch->id << 9) | (1<<KEY_WR_AES_IV_A));
+ } else if (type == CA_CW_AES_ODD_IV ||
+ type == CA_CW_SM4_ODD_IV) {
+ WRITE_MPEG_REG(CIPLUS_KEY0, k0);
+ WRITE_MPEG_REG(CIPLUS_KEY1, k1);
+ WRITE_MPEG_REG(CIPLUS_KEY2, k2);
+ WRITE_MPEG_REG(CIPLUS_KEY3, k3);
+ WRITE_MPEG_REG(CIPLUS_KEY_WR,
+ (ch->id << 9) | (1<<KEY_WR_AES_IV_B));
+ }
+}
+
+/*
+ * Param:
+ * key_endian
+ * S905D 7 for kl 0 for set key directly
+ * mode
+ * 0 for ebc
+ * 1 for cbc
+ */
+static void aml_ci_plus_config(int key_endian, int mode, int algo)
+{
+ unsigned int data;
+ unsigned int idsa_mode = 0;
+ unsigned int sm4_mode = 0;
+ unsigned int cbc_disable = 0;
+ unsigned int des_enable = 0;
+ unsigned int aes_enable = 0;
+ unsigned int des2_key_endian = 0;
+ unsigned int des2_in_endian = 0;
+ unsigned int des2_cfg = 0;
+ unsigned int des2_enable = 0;
+
+ pr_dbg("%s mode:%d,alog:%d\n",__FUNCTION__,mode,algo);
+
+ if (get_cpu_type() < MESON_CPU_MAJOR_ID_SM1) {
+ WRITE_MPEG_REG(CIPLUS_ENDIAN,
+ (15 << AES_MSG_OUT_ENDIAN)
+ | (15 << AES_MSG_IN_ENDIAN)
+ | (key_endian << AES_KEY_ENDIAN)
+ |
+ (15 << DES_MSG_OUT_ENDIAN)
+ | (15 << DES_MSG_IN_ENDIAN)
+ | (key_endian << DES_KEY_ENDIAN)
+ );
+ } else if (algo == ALGO_DES){
+ WRITE_MPEG_REG(CIPLUS_ENDIAN,
+ (15 << AES_IV_ENDIAN)
+ | (7 << AES_MSG_OUT_ENDIAN)
+ | (15 << AES_MSG_IN_ENDIAN)
+ | (15 << AES_KEY_ENDIAN)
+ );
+ pr_inf("CIPLUS_ENDIAN is 0x%x\n", READ_MPEG_REG(CIPLUS_ENDIAN));
+ } else {
+ WRITE_MPEG_REG(CIPLUS_ENDIAN, 0);
+ }
+
+ data = READ_MPEG_REG(CIPLUS_ENDIAN);
+
+ if (algo == ALGO_SM4) {
+ sm4_mode = 1;
+ } else if (algo == ALGO_AES){
+ aes_enable = 1;
+ } else {
+ if (get_cpu_type() < MESON_CPU_MAJOR_ID_SM1) {
+ des_enable = 1;
+ } else {
+ des2_key_endian = 8;
+ des2_in_endian = 8;
+ des2_cfg = 2;
+ des2_enable = 1;
+ aes_enable = 1;
+ }
+ }
+
+ if (mode == IDSA_MODE) {
+ idsa_mode = 1;
+ cbc_disable = 0;
+ } else if (mode == CBC_MODE) {
+ cbc_disable = 0;
+ } else {
+ cbc_disable = 1;
+ }
+ pr_dbg("idsa_mode:%d sm4_mode:%d cbc_disable:%d aes_enable:%d des_enable:%d\n", \
+ idsa_mode,sm4_mode,cbc_disable,aes_enable,des_enable);
+
+ data = (idsa_mode << IDSA_MODE_BIT) |
+ (sm4_mode << SM4_MODE ) |
+ (des2_key_endian << DES2_KEY_ENDIAN) |
+ (des2_in_endian << DES2_IN_ENDIAN) |
+ (des2_cfg << DES2_CFG) |
+ (des2_enable << DES2_EN) |
+ (cbc_disable << AES_CBC_DISABLE) |
+ /*1 << AES_CBC_DISABLE : ECB
+ *0 << AES_CBC_DISABLE : CBC
+ */
+ (1 << CNTL_ENABLE) |
+ (aes_enable << AES_EN) |
+ (des_enable << DES_EN);
+
+ WRITE_MPEG_REG(CIPLUS_CONFIG, data);
+ data = READ_MPEG_REG(CIPLUS_CONFIG);
+ pr_dbg("CIPLUS_CONFIG is 0x%x\n",data);
+}
+
+/*
+ * Set output to demux set.
+ */
+static void am_ci_plus_set_output(struct aml_dsc_channel *ch)
+{
+ struct aml_dsc *dsc = ch->dsc;
+ u32 data;
+ u32 in = 0, out = 0;
+ int set = 0;
+
+ if (dsc->id != 0) {
+ pr_error("Ciplus set output can only work at dsc0 device\n");
+ return;
+ }
+
+ switch (dsc->source) {
+ case AM_TS_SRC_DMX0:
+ in = 0;
+ break;
+ case AM_TS_SRC_DMX1:
+ in = 1;
+ break;
+ case AM_TS_SRC_DMX2:
+ in = 2;
+ break;
+ default:
+ break;
+ }
+
+ if (ciplus_out_auto_mode == 1) {
+ switch (dsc->dst) {
+ case AM_TS_SRC_DMX0:
+ out = 1;
+ break;
+ case AM_TS_SRC_DMX1:
+ out = 2;
+ break;
+ case AM_TS_SRC_DMX2:
+ out = 4;
+ break;
+ default:
+ break;
+ }
+ set = 1;
+ ciplus_out_sel = out;
+ } else if (ciplus_out_sel >= 0 && ciplus_out_sel <= 7) {
+ set = 1;
+ out = ciplus_out_sel;
+ } else {
+ pr_error("dsc ciplus out config is invalid\n");
+ }
+
+ if (set) {
+ /* Set ciplus input source ,
+ * output set 0 means no output. ---> need confirm.
+ * if output set 0 still affects dsc output, we need to disable
+ * ciplus module.
+ */
+ data = READ_MPEG_REG(STB_TOP_CONFIG);
+ data &= ~(3<<CIPLUS_IN_SEL);
+ data |= in << CIPLUS_IN_SEL;
+ data &= ~(7<<CIPLUS_OUT_SEL);
+ data |= out << CIPLUS_OUT_SEL;
+ WRITE_MPEG_REG(STB_TOP_CONFIG, data);
+ pr_inf("dsc ciplus in[%x] out[%x] %s\n", in, out,
+ (ciplus_out_auto_mode) ? "" : "force");
+ }
+}
+
+#if 0
+/*
+ * Ciplus output has high priority,
+ * disable it's output will let dsc output go.
+ */
+static void aml_ci_plus_disable_output(void)
+{
+ u32 data = 0;
+
+ data = READ_MPEG_REG(STB_TOP_CONFIG);
+ WRITE_MPEG_REG(STB_TOP_CONFIG, data &
+ ~(7 << CIPLUS_OUT_SEL));
+}
+
+static void aml_ci_plus_enable(void)
+{
+ u32 data = 0;
+
+ data = READ_MPEG_REG(STB_TOP_CONFIG);
+ WRITE_MPEG_REG(CIPLUS_CONFIG,
+ (1 << CNTL_ENABLE)
+ | (1 << AES_EN)
+ | (1 << DES_EN));
+}
+#endif
+
+static void aml_ci_plus_disable(void)
+{
+ u32 data = 0;
+
+ WRITE_MPEG_REG(CIPLUS_CONFIG, 0);
+
+ data = READ_MPEG_REG(STB_TOP_CONFIG);
+ WRITE_MPEG_REG(STB_TOP_CONFIG, data &
+ ~((1 << CIPLUS_IN_SEL) | (7 << CIPLUS_OUT_SEL)));
+}
+
+static int dsc_set_aes_des_sm4_key(struct aml_dsc_channel *ch, int flags,
+ enum ca_cw_type type, u8 *key)
+{
+ unsigned int k0, k1, k2, k3;
+ int iv = 0, aes = 0, des = 0;
+ int ab_iv = 0, ab_aes = 0, ab_des = 0;
+ int from_kl = flags & CA_CW_FROM_KL;
+ int algo = 0;
+
+ if (!from_kl) {
+ if (get_cpu_type() < MESON_CPU_MAJOR_ID_SM1) {
+ k3 = (key[0] << 24) | (key[1] << 16) | (key[2] << 8) | key[3];
+ k2 = (key[4] << 24) | (key[5] << 16) | (key[6] << 8) | key[7];
+ k1 = (key[8] << 24) | (key[9] << 16) | (key[10] << 8) | key[11];
+ k0 = (key[12] << 24) | (key[13] << 16)
+ | (key[14] << 8) | key[15];
+ } else {
+ k0 = (key[0]) | (key[1] << 8) | (key[2] << 16) | (key[3] << 24);
+ k1 = (key[4]) | (key[5] << 8) | (key[6] << 16) | (key[7] << 24);
+ k2 = (key[8]) | (key[9] << 8) | (key[10] << 16)| (key[11] << 24);
+ k3 = (key[12])| (key[13] << 8)| (key[14] << 16)| (key[15] << 24);
+ }
+ } else
+ k0 = k1 = k2 = k3 = 0;
+
+ switch (type) {
+ case CA_CW_AES_EVEN:
+ case CA_CW_SM4_EVEN:
+ ab_aes = (from_kl) ? 0x2 : 0x1;
+ if (ch->mode == -1)
+ ch->mode = ECB_MODE;
+ aes = 1;
+ if (type == CA_CW_AES_EVEN)
+ algo = ALGO_AES;
+ else
+ algo = ALGO_SM4;
+ break;
+ case CA_CW_AES_ODD:
+ case CA_CW_SM4_ODD:
+ ab_aes = (from_kl) ? 0x1 : 0x2;
+ if (ch->mode == -1)
+ ch->mode = ECB_MODE;
+ aes = 1;
+ if (type == CA_CW_AES_ODD)
+ algo = ALGO_AES;
+ else
+ algo = ALGO_SM4;
+ break;
+ case CA_CW_AES_EVEN_IV:
+ case CA_CW_SM4_EVEN_IV:
+ ab_iv = 0x1;
+ if (ch->mode == -1)
+ ch->mode = CBC_MODE;
+ iv = 1;
+ if (type == CA_CW_AES_EVEN_IV)
+ algo = ALGO_AES;
+ else
+ algo = ALGO_SM4;
+ break;
+ case CA_CW_AES_ODD_IV:
+ case CA_CW_SM4_ODD_IV:
+ ab_iv = 0x2;
+ if (ch->mode == -1)
+ ch->mode = CBC_MODE;
+ iv = 1;
+ if (type == CA_CW_AES_ODD_IV)
+ algo = ALGO_AES;
+ else
+ algo = ALGO_SM4;
+ break;
+ case CA_CW_DES_EVEN:
+ if (get_cpu_type() < MESON_CPU_MAJOR_ID_SM1) {
+ ab_des = 0x1;
+ } else {
+ ab_aes = 0x1;
+ }
+ ch->mode = ECB_MODE;
+ des = 1;
+ algo = ALGO_DES;
+ break;
+ case CA_CW_DES_ODD:
+ if (get_cpu_type() < MESON_CPU_MAJOR_ID_SM1) {
+ ab_des = 0x2;
+ } else {
+ ab_aes = 0x2;
+ }
+ ch->mode = ECB_MODE;
+ algo = ALGO_DES;
+ des = 1;
+ break;
+ default:
+ break;
+ }
+
+ /* Set endian and cbc/ecb mode */
+ if (from_kl)
+ aml_ci_plus_config(7, ch->mode, algo);
+ else
+ aml_ci_plus_config(0, ch->mode, algo);
+
+ /* Write keys to work */
+ if (iv || aes) {
+ WRITE_MPEG_REG(CIPLUS_KEY0, k0);
+ WRITE_MPEG_REG(CIPLUS_KEY1, k1);
+ WRITE_MPEG_REG(CIPLUS_KEY2, k2);
+ WRITE_MPEG_REG(CIPLUS_KEY3, k3);
+ } else {/*des*/
+ WRITE_MPEG_REG(CIPLUS_KEY0, k2);
+ WRITE_MPEG_REG(CIPLUS_KEY1, k3);
+ WRITE_MPEG_REG(CIPLUS_KEY2, 0);
+ WRITE_MPEG_REG(CIPLUS_KEY3, 0);
+ }
+ WRITE_MPEG_REG(CIPLUS_KEY_WR,
+ (ch->id << 9) |
+ /* bit[11:9] the key of index,
+ need match PID index*/
+ ((from_kl && des) ? (1 << 8) : 0) |
+ /* bit[8] des key use cw[127:64]*/
+ (0 << 7) | /* bit[7] aes iv use cw*/
+ ((from_kl && (aes || des)) ? (1 << 6) : 0) |
+ /* bit[6] aes/des key use cw*/
+ /* bit[5] write AES IV B value*/
+ (ab_iv << 4) | /* bit[4] write AES IV A value*/
+ /* bit[3] write AES B key*/
+ (ab_aes << 2) | /* bit[2] write AES A key*/
+ /* bit[1] write DES B key*/
+ (ab_des)); /* bit[0] write DES A key*/
+
+ /*
+ pr_inf("k:%08x:%08x:%08x:%08x kl:%d aes:%d des:%d ab_iv:%d ab_aes:%d ab_des:%d id:%d mod:%d\n",
+ k0, k1, k2, k3,
+ from_kl, aes, des, ab_iv, ab_aes, ab_des, ch->id, ch->aes_mode);
+ */
+ return 0;
+}
+
+void dsc_release(void)
+{
+ aml_ci_plus_disable();
+}
+/************************* AES DESC************************************/
+void set_ciplus_input_source(struct aml_dsc *dsc)
+{
+ u32 data;
+ u32 in = 0;
+
+ if (dsc->id != 0) {
+ pr_error("Ciplus set output can only work at dsc0 device\n");
+ return;
+ }
+
+ switch (dsc->source) {
+ case AM_TS_SRC_DMX0:
+ in = 0;
+ break;
+ case AM_TS_SRC_DMX1:
+ in = 1;
+ break;
+ case AM_TS_SRC_DMX2:
+ in = 2;
+ break;
+ default:
+ break;
+ }
+
+ if (ciplus_out_auto_mode == 1) {
+ /* Set ciplus input source */
+ data = READ_MPEG_REG(STB_TOP_CONFIG);
+ data &= ~(3<<CIPLUS_IN_SEL);
+ data |= in << CIPLUS_IN_SEL;
+ WRITE_MPEG_REG(STB_TOP_CONFIG, data);
+ pr_inf("dsc ciplus in[%x]\n", in);
+ }
+}
+
+int dsc_enable(struct aml_dsc *dsc, int enable)
+{
+ if (dsc->id == 0) {
+ WRITE_MPEG_REG(STB_TOP_CONFIG,
+ READ_MPEG_REG(STB_TOP_CONFIG) &
+ ~((0x11 << DES_INPUT_SEL)|
+ (1 << ENABLE_DES_PL)|
+ (1 << ENABLE_DES_PL_CLK)));
+ } else if (dsc->id == 1) {
+ WRITE_MPEG_REG(COMM_DESC_2_CTL, 0);
+ }
+ return 0;
+}
+
+/*Set section buffer*/
+static int dmx_alloc_sec_buffer(struct aml_dmx *dmx)
+{
+ unsigned long base;
+ unsigned long grp_addr[SEC_BUF_GRP_COUNT];
+ int grp_len[SEC_BUF_GRP_COUNT];
+ int i;
+
+ if (dmx->sec_pages)
+ return 0;
+
+ grp_len[0] = (1 << SEC_GRP_LEN_0) * 8;
+ grp_len[1] = (1 << SEC_GRP_LEN_1) * 8;
+ grp_len[2] = (1 << SEC_GRP_LEN_2) * 8;
+ grp_len[3] = (1 << SEC_GRP_LEN_3) * 8;
+
+ dmx->sec_total_len = grp_len[0] + grp_len[1] + grp_len[2] + grp_len[3];
+ dmx->sec_pages =
+ __get_free_pages(GFP_KERNEL, get_order(dmx->sec_total_len));
+ if (!dmx->sec_pages) {
+ pr_error("cannot allocate section buffer %d bytes %d order\n",
+ dmx->sec_total_len, get_order(dmx->sec_total_len));
+ return -1;
+ }
+ dmx->sec_pages_map =
+ dma_map_single(dmx_get_dev(dmx), (void *)dmx->sec_pages,
+ dmx->sec_total_len, DMA_FROM_DEVICE);
+
+ grp_addr[0] = dmx->sec_pages_map;
+
+ grp_addr[1] = grp_addr[0] + grp_len[0];
+ grp_addr[2] = grp_addr[1] + grp_len[1];
+ grp_addr[3] = grp_addr[2] + grp_len[2];
+
+ dmx->sec_buf[0].addr = dmx->sec_pages;
+ dmx->sec_buf[0].len = grp_len[0] / 8;
+
+ for (i = 1; i < SEC_BUF_COUNT; i++) {
+ dmx->sec_buf[i].addr =
+ dmx->sec_buf[i - 1].addr + dmx->sec_buf[i - 1].len;
+ dmx->sec_buf[i].len = grp_len[i / 8] / 8;
+ }
+
+ base = grp_addr[0] & 0xFFFF0000;
+ DMX_WRITE_REG(dmx->id, SEC_BUFF_BASE, base >> 16);
+ DMX_WRITE_REG(dmx->id, SEC_BUFF_01_START,
+ (((grp_addr[0] - base) >> 8) << 16) |
+ ((grp_addr[1] - base) >> 8));
+ DMX_WRITE_REG(dmx->id, SEC_BUFF_23_START,
+ (((grp_addr[2] - base) >> 8) << 16) |
+ ((grp_addr[3] - base) >> 8));
+ DMX_WRITE_REG(dmx->id, SEC_BUFF_SIZE,
+ SEC_GRP_LEN_0 |
+ (SEC_GRP_LEN_1 << 4) |
+ (SEC_GRP_LEN_2 << 8) |
+ (SEC_GRP_LEN_3 << 12));
+
+ return 0;
+}
+
+#ifdef NO_SUB
+/*Set subtitle buffer*/
+static int dmx_alloc_sub_buffer(struct aml_dvb *dvb, struct aml_dmx *dmx)
+{
+#ifdef SUB_BUF_DMX
+ unsigned long addr;
+
+ if (dmx->sub_pages)
+ return 0;
+
+ /*check if use shared buf*/
+ if (dvb->sub_pages) {
+ dmx->sub_pages = dvb->sub_pages;
+ dmx->sub_buf_len = dvb->sub_buf_len;
+ dmx->sub_pages_map = dvb->sub_pages_map;
+ goto end_alloc;
+ }
+
+ dmx->sub_buf_len = 64 * 1024;
+ dmx->sub_pages =
+ __get_free_pages(GFP_KERNEL, get_order(dmx->sub_buf_len));
+ if (!dmx->sub_pages) {
+ pr_error("cannot allocate subtitle buffer\n");
+ return -1;
+ }
+ dmx->sub_pages_map =
+ dma_map_single(dmx_get_dev(dmx), (void *)dmx->sub_pages,
+ dmx->sub_buf_len, DMA_FROM_DEVICE);
+
+end_alloc:
+ addr = virt_to_phys((void *)dmx->sub_pages);
+#ifndef SUB_PARSER
+ DMX_WRITE_REG(dmx->id, SB_START, addr >> 12);
+ DMX_WRITE_REG(dmx->id, SB_LAST_ADDR, (dmx->sub_buf_len >> 3) - 1);
+#endif
+ if (dmx->sub_pages != dvb->sub_pages) {
+ pr_dbg("sub buff: (%d) %lx %x\n",
+ dmx->id, addr, dmx->sub_buf_len);
+ }
+#endif
+ return 0;
+}
+#ifdef SUB_BUF_SHARED
+static int dmx_alloc_sub_buffer_shared(struct aml_dvb *dvb)
+{
+#ifdef SUB_BUF_DMX
+ if (dvb->sub_pages)
+ return 0;
+
+ dvb->sub_buf_len = 64 * 1024;
+ dvb->sub_pages =
+ __get_free_pages(GFP_KERNEL, get_order(dvb->sub_buf_len));
+ if (!dvb->sub_pages) {
+ pr_error("cannot allocate subtitle buffer\n");
+ return -1;
+ }
+ dvb->sub_pages_map =
+ dma_map_single(dvb->dev, (void *)dvb->sub_pages,
+ dvb->sub_buf_len, DMA_FROM_DEVICE);
+
+ pr_dbg("sub buff shared: %lx %x\n",
+ (unsigned long)virt_to_phys((void *)dvb->sub_pages),
+ dvb->sub_buf_len);
+#endif
+ return 0;
+}
+#endif
+#endif /*NO_SUB */
+
+/*Set PES buffer*/
+static int dmx_alloc_pes_buffer(struct aml_dvb *dvb, struct aml_dmx *dmx)
+{
+ unsigned long addr;
+
+ if (dmx->pes_pages)
+ return 0;
+
+ /*check if use shared buf*/
+ if (dvb->pes_pages) {
+ dmx->pes_pages = dvb->pes_pages;
+ dmx->pes_buf_len = dvb->pes_buf_len;
+ dmx->pes_pages_map = dvb->pes_pages_map;
+ goto end_alloc;
+ }
+
+ dmx->pes_buf_len = 64 * 1024;
+ dmx->pes_pages =
+ __get_free_pages(GFP_KERNEL, get_order(dmx->pes_buf_len));
+ if (!dmx->pes_pages) {
+ pr_error("cannot allocate pes buffer\n");
+ return -1;
+ }
+ dmx->pes_pages_map =
+ dma_map_single(dmx_get_dev(dmx), (void *)dmx->pes_pages,
+ dmx->pes_buf_len, DMA_FROM_DEVICE);
+end_alloc:
+ addr = virt_to_phys((void *)dmx->pes_pages);
+ DMX_WRITE_REG(dmx->id, OB_START, addr >> 12);
+ DMX_WRITE_REG(dmx->id, OB_LAST_ADDR, (dmx->pes_buf_len >> 3) - 1);
+
+ if (dmx->pes_pages != dvb->pes_pages) {
+ pr_dbg("pes buff: (%d) %lx %x\n",
+ dmx->id, addr, dmx->pes_buf_len);
+ }
+ return 0;
+}
+#ifdef PES_BUF_SHARED
+static int dmx_alloc_pes_buffer_shared(struct aml_dvb *dvb)
+{
+ if (dvb->pes_pages)
+ return 0;
+
+ dvb->pes_buf_len = 64 * 1024;
+ dvb->pes_pages =
+ __get_free_pages(GFP_KERNEL, get_order(dvb->pes_buf_len));
+ if (!dvb->pes_pages) {
+ pr_error("cannot allocate pes buffer\n");
+ return -1;
+ }
+ dvb->pes_pages_map =
+ dma_map_single(dvb->dev, (void *)dvb->pes_pages,
+ dvb->pes_buf_len, DMA_FROM_DEVICE);
+
+ pr_dbg("pes buff shared: %lx %x\n",
+ (unsigned long)virt_to_phys((void *)dvb->pes_pages),
+ dvb->pes_buf_len);
+ return 0;
+}
+#endif
+
+/*Allocate ASYNC FIFO Buffer*/
+static unsigned long asyncfifo_alloc_buffer(struct aml_asyncfifo *afifo, int len)
+{
+ if (!afifo->stored_pages) {
+ afifo->stored_pages = __get_free_pages(GFP_KERNEL, get_order(len));
+ }
+
+ if (!afifo->stored_pages) {
+ pr_error("cannot allocate async fifo buffer\n");
+ return 0;
+ }
+ return afifo->stored_pages;
+}
+static void asyncfifo_free_buffer(unsigned long buf, int len)
+{
+ //free_pages(buf, get_order(len));
+}
+
+static int asyncfifo_set_buffer(struct aml_asyncfifo *afifo,
+ int len, unsigned long buf)
+{
+ if (afifo->pages)
+ return -1;
+
+ afifo->buf_toggle = 0;
+ afifo->buf_read = 0;
+ afifo->buf_len = dmx_get_afifo_size(afifo);
+ pr_dbg("async fifo %d buf %lu buf size %d, flush size %d, secure_enable %d, blk.addr %u\n",
+ afifo->id, buf, afifo->buf_len, afifo->flush_size, afifo->secure_enable, afifo->blk.addr);
+
+ if ((afifo->flush_size <= 0)
+ || (afifo->flush_size > (len>>1))) {
+ afifo->flush_size = len>>1;
+ } else if (afifo->flush_size < 128) {
+ afifo->flush_size = 128;
+ } else {
+ int fsize;
+
+ for (fsize = 128; fsize < (len>>1); fsize <<= 1) {
+ if (fsize >= afifo->flush_size)
+ break;
+ }
+
+ afifo->flush_size = fsize;
+ }
+
+ afifo->pages = buf;
+ if (!afifo->pages)
+ return -1;
+
+ afifo->pages_map = dma_map_single(asyncfifo_get_dev(afifo),
+ (void *)afifo->pages, len, DMA_FROM_DEVICE);
+
+ return 0;
+}
+static void asyncfifo_put_buffer(struct aml_asyncfifo *afifo)
+{
+ if (afifo->pages) {
+ dma_unmap_single(asyncfifo_get_dev(afifo),
+ afifo->pages_map, asyncfifo_buf_len, DMA_FROM_DEVICE);
+ asyncfifo_free_buffer(afifo->pages, asyncfifo_buf_len);
+ afifo->pages_map = 0;
+ afifo->pages = 0;
+ }
+}
+
+int async_fifo_init(struct aml_asyncfifo *afifo, int initirq,
+ int buf_len, unsigned long buf)
+{
+ int ret = 0;
+ int irq;
+
+ if (afifo->init)
+ return -1;
+
+ afifo->source = AM_DMX_MAX;
+ afifo->pages = 0;
+ afifo->buf_toggle = 0;
+ afifo->buf_read = 0;
+ afifo->buf_len = 0;
+
+ if (afifo->asyncfifo_irq == -1) {
+ pr_error("no irq for ASYNC_FIFO%d\n", afifo->id);
+ /*Do not return error*/
+ return -1;
+ }
+
+ tasklet_init(&afifo->asyncfifo_tasklet,
+ dvr_irq_bh_handler, (unsigned long)afifo);
+ if (initirq)
+ irq = request_irq(afifo->asyncfifo_irq, dvr_irq_handler,
+ IRQF_SHARED|IRQF_TRIGGER_RISING,
+ "dvr irq", afifo);
+ else
+ enable_irq(afifo->asyncfifo_irq);
+
+ /*alloc buffer*/
+ ret = asyncfifo_set_buffer(afifo, buf_len, buf);
+
+ afifo->init = 1;
+
+ return ret;
+}
+
+int async_fifo_deinit(struct aml_asyncfifo *afifo, int freeirq)
+{
+ struct aml_dvb *dvb = afifo->dvb;
+ unsigned long flags;
+
+ if (!afifo->init)
+ return 0;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+ CLEAR_ASYNC_FIFO_REG_MASK(afifo->id, REG1, 1 << ASYNC_FIFO_FLUSH_EN);
+ CLEAR_ASYNC_FIFO_REG_MASK(afifo->id, REG2, 1 << ASYNC_FIFO_FILL_EN);
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ asyncfifo_put_buffer(afifo);
+
+ afifo->source = AM_DMX_MAX;
+ afifo->buf_toggle = 0;
+ afifo->buf_read = 0;
+ afifo->buf_len = 0;
+
+ if (afifo->asyncfifo_irq != -1) {
+ if (freeirq)
+ free_irq(afifo->asyncfifo_irq, afifo);
+ else
+ disable_irq(afifo->asyncfifo_irq);
+ }
+ tasklet_kill(&afifo->asyncfifo_tasklet);
+
+ afifo->init = 0;
+
+ return 0;
+}
+
+static int _dmx_smallsec_enable(struct aml_smallsec *ss, int bufsize)
+{
+ if (!ss->buf) {
+
+ ss->buf = __get_free_pages(GFP_KERNEL,
+ get_order(bufsize));
+ if (!ss->buf) {
+ pr_error("cannot allocate smallsec buffer\n"
+ "%d bytes %d order\n",
+ bufsize, get_order(bufsize));
+ return -1;
+ }
+ ss->buf_map = dma_map_single(dmx_get_dev(ss->dmx),
+ (void *)ss->buf,
+ bufsize, DMA_FROM_DEVICE);
+ }
+
+ DMX_WRITE_REG(ss->dmx->id, DEMUX_SMALL_SEC_ADDR,
+ ss->buf_map);
+ DMX_WRITE_REG(ss->dmx->id, DEMUX_SMALL_SEC_CTL,
+ ((((bufsize>>8)-1)&0xff)<<24) |
+ (1<<1) |/*enable reset the wr ptr*/
+ (1<<0));
+
+ ss->bufsize = bufsize;
+ ss->enable = 1;
+
+ pr_inf("demux%d smallsec buf start: %lx, size: %d\n",
+ ss->dmx->id, ss->buf, ss->bufsize);
+ return 0;
+}
+
+static int _dmx_smallsec_disable(struct aml_smallsec *ss)
+{
+ DMX_WRITE_REG(ss->dmx->id, DEMUX_SMALL_SEC_CTL, 0);
+ if (ss->buf) {
+ dma_unmap_single(dmx_get_dev(ss->dmx), ss->buf_map,
+ ss->bufsize, DMA_FROM_DEVICE);
+ free_pages(ss->buf, get_order(ss->bufsize));
+ ss->buf = 0;
+ ss->buf_map = 0;
+ }
+ ss->enable = 0;
+ pr_inf("demux%d smallsec buf disable\n", ss->dmx->id);
+ return 0;
+}
+
+static int dmx_smallsec_set(struct aml_smallsec *ss, int enable, int bufsize,
+ int force)
+{
+ if (!enable) {/*disable*/
+
+ if (ss->enable || force)
+ _dmx_smallsec_disable(ss);
+
+ } else {/*enable*/
+
+ if (bufsize < 0)
+ bufsize = SS_BUFSIZE_DEF;
+ else if (!bufsize)
+ bufsize = ss->bufsize;
+ else {
+ /*unit:FF max:FF00*/
+ bufsize &= ~0xFF;
+ bufsize &= 0x1FF00;
+ }
+
+ if ((ss->enable && (bufsize != ss->bufsize)) || force)
+ _dmx_smallsec_disable(ss);
+
+ if (!ss->enable)
+ _dmx_smallsec_enable(ss, bufsize);
+ }
+
+ return 0;
+}
+
+static int _dmx_timeout_enable(struct aml_dmxtimeout *dto, int timeout,
+ int ch_dis, int match)
+{
+
+ DMX_WRITE_REG(dto->dmx->id, DEMUX_INPUT_TIMEOUT_C, ch_dis);
+ DMX_WRITE_REG(dto->dmx->id, DEMUX_INPUT_TIMEOUT,
+ ((!!match)<<31) |
+ (timeout&0x7fffffff));
+
+ dto->ch_disable = ch_dis;
+ dto->match = match;
+ dto->timeout = timeout;
+ dto->trigger = 0;
+ dto->enable = 1;
+
+ pr_inf("demux%d timeout enable:timeout(%d),ch(0x%x),match(%d)\n",
+ dto->dmx->id, dto->timeout, dto->ch_disable, dto->match);
+
+ return 0;
+}
+static int _dmx_timeout_disable(struct aml_dmxtimeout *dto)
+{
+
+ DMX_WRITE_REG(dto->dmx->id, DEMUX_INPUT_TIMEOUT, 0);
+ dto->enable = 0;
+ dto->trigger = 0;
+ pr_inf("demux%d timeout disable\n", dto->dmx->id);
+
+ return 0;
+}
+
+static int dmx_timeout_set(struct aml_dmxtimeout *dto, int enable,
+ int timeout, int ch_dis, int match,
+ int force)
+{
+
+ if (!enable) {/*disable*/
+
+ if (dto->enable || force)
+ _dmx_timeout_disable(dto);
+
+ } else {/*enable*/
+
+ if (timeout < 0) {
+ timeout = DTO_TIMEOUT_DEF;
+ ch_dis = DTO_CHDIS_VAS;
+ match = dto->match;
+ } else if (!timeout) {
+ timeout = dto->timeout;
+ ch_dis = dto->ch_disable;
+ match = dto->match;
+ }
+
+ if ((dto->enable && (timeout != dto->timeout))
+ || force)
+ _dmx_timeout_disable(dto);
+
+ if (!dto->enable)
+ _dmx_timeout_enable(dto, timeout, ch_dis, match);
+ }
+
+ return 0;
+}
+
+/*Initialize the registers*/
+static int dmx_init(struct aml_dmx *dmx)
+{
+ struct aml_dvb *dvb = (struct aml_dvb *)dmx->demux.priv;
+ int irq;
+ int ret = 0;
+ char buf[32];
+ u32 value = 0;
+
+ if (dmx->init)
+ return 0;
+
+ pr_dbg("[dmx_kpi] %s Enter\n", __func__);
+
+ memset(buf, 0, 32);
+ snprintf(buf, sizeof(buf), "asyncfifo_buf_len");
+ ret = of_property_read_u32(dvb->pdev->dev.of_node, buf, &value);
+ if (!ret) {
+ pr_inf("%s: 0x%x\n", buf, value);
+ asyncfifo_buf_len = value;
+ }
+ /*Register irq handlers */
+ if (dmx->dmx_irq != -1) {
+ pr_dbg("request irq\n");
+ tasklet_init(&dmx->dmx_tasklet,
+ dmx_irq_bh_handler,
+ (unsigned long)dmx);
+ irq = request_irq(dmx->dmx_irq, dmx_irq_handler,
+ IRQF_SHARED|IRQF_TRIGGER_RISING,
+ "dmx irq", dmx);
+ }
+
+ /*Allocate buffer */
+ if (dmx_alloc_sec_buffer(dmx) < 0)
+ return -1;
+#ifdef NO_SUB
+#ifdef SUB_BUF_SHARED
+ if (dmx_alloc_sub_buffer_shared(dvb) < 0)
+ return -1;
+#endif
+ if (dmx_alloc_sub_buffer(dvb, dmx) < 0)
+ return -1;
+#endif
+#ifdef PES_BUF_SHARED
+ if (dmx_alloc_pes_buffer_shared(dvb) < 0)
+ return -1;
+#endif
+ if (dmx_alloc_pes_buffer(dvb, dmx) < 0)
+ return -1;
+ /*Reset the hardware */
+ if (!dvb->dmx_init) {
+ init_timer(&dvb->watchdog_timer);
+ dvb->watchdog_timer.function = section_buffer_watchdog_func;
+ dvb->watchdog_timer.expires =
+ jiffies + msecs_to_jiffies(WATCHDOG_TIMER);
+ dvb->watchdog_timer.data = (unsigned long)dvb;
+#ifdef ENABLE_SEC_BUFF_WATCHDOG
+ add_timer(&dvb->watchdog_timer);
+#endif
+ dmx_reset_hw(dvb);
+ }
+
+ dvb->dmx_init++;
+
+ memset(dmx->sec_buf_watchdog_count, 0,
+ sizeof(dmx->sec_buf_watchdog_count));
+
+ dmx->om_status_error_count = 0;
+ dmx->init = 1;
+ pr_dbg("[dmx_kpi] %s Exit\n", __func__);
+ return 0;
+}
+
+/*Release the resource*/
+static int dmx_deinit(struct aml_dmx *dmx)
+{
+ struct aml_dvb *dvb = (struct aml_dvb *)dmx->demux.priv;
+ pr_dbg("[dmx_kpi] %s Enter\n", __func__);
+ if (!dmx->init)
+ return 0;
+
+ DMX_WRITE_REG(dmx->id, DEMUX_CONTROL, 0);
+
+ dvb->dmx_init--;
+
+ /*Reset the hardware */
+ if (!dvb->dmx_init) {
+ dmx_reset_hw(dvb);
+#ifdef ENABLE_SEC_BUFF_WATCHDOG
+ del_timer_sync(&dvb->watchdog_timer);
+#endif
+ }
+
+ if (dmx->sec_pages) {
+ dma_unmap_single(dmx_get_dev(dmx), dmx->sec_pages_map,
+ dmx->sec_total_len, DMA_FROM_DEVICE);
+ free_pages(dmx->sec_pages, get_order(dmx->sec_total_len));
+ dmx->sec_pages = 0;
+ dmx->sec_pages_map = 0;
+ }
+#ifdef NO_SUB
+#ifdef SUB_BUF_DMX
+#ifdef SUB_BUF_SHARED
+ if (dvb->sub_pages) {
+ dma_unmap_single(dvb->dev, dvb->sub_pages_map,
+ dvb->sub_buf_len, DMA_FROM_DEVICE);
+ free_pages(dvb->sub_pages, get_order(dvb->sub_buf_len));
+ dvb->sub_pages = 0;
+ }
+ dmx->sub_pages = 0;
+#else
+ if (dmx->sub_pages) {
+ dma_unmap_single(dmx_get_dev(dmx), dmx->sub_pages_map,
+ dmx->sub_buf_len, DMA_FROM_DEVICE);
+ free_pages(dmx->sub_pages, get_order(dmx->sub_buf_len));
+ dmx->sub_pages = 0;
+ }
+#endif
+#endif
+#endif
+#ifdef PES_BUF_SHARED
+ if (dvb->pes_pages) {
+ dma_unmap_single(dvb->dev, dvb->pes_pages_map,
+ dvb->pes_buf_len, DMA_FROM_DEVICE);
+ free_pages(dvb->pes_pages, get_order(dvb->pes_buf_len));
+ dvb->pes_pages = 0;
+ }
+ dmx->pes_pages = 0;
+#else
+ if (dmx->pes_pages) {
+ dma_unmap_single(dmx_get_dev(dmx), dmx->pes_pages_map,
+ dmx->pes_buf_len, DMA_FROM_DEVICE);
+ free_pages(dmx->pes_pages, get_order(dmx->pes_buf_len));
+ dmx->pes_pages = 0;
+ }
+#endif
+ if (dmx->dmx_irq != -1) {
+ free_irq(dmx->dmx_irq, dmx);
+ tasklet_kill(&dmx->dmx_tasklet);
+ }
+
+ dmx->init = 0;
+ pr_dbg("[dmx_kpi] %s Exit\n", __func__);
+ return 0;
+}
+
+/*Check the record flag*/
+static int dmx_get_record_flag(struct aml_dmx *dmx)
+{
+ int i, linked = 0, record_flag = 0;
+ struct aml_dvb *dvb = (struct aml_dvb *)dmx->demux.priv;
+
+ /*Check whether a async fifo connected to this dmx */
+ for (i = 0; i < dvb->async_fifo_total_count; i++) {
+ if (!dvb->asyncfifo[i].init)
+ continue;
+ if ((dvb->asyncfifo[i].source == dmx->id)
+ /*&& !(dvb->swfilter.user && (i==SF_AFIFO_ID)) */
+ /*sf mode reserved */
+ ) {
+ linked = 1;
+ break;
+ }
+ }
+
+ for (i = 0; i < CHANNEL_COUNT; i++) {
+ if (dmx->channel[i].used && dmx->channel[i].dvr_feed) {
+ if (!dmx->record) {
+ pr_error("dmx_get_record_flag set record dmx->id: %d\n", dmx->id);
+ dmx->record = 1;
+
+ if (linked) {
+ /*A new record will start,
+ * must reset the async fifos for
+ * linking the right demux
+ */
+ reset_async_fifos(dvb);
+ }
+ }
+ if (linked)
+ record_flag = 1;
+ goto find_done;
+ }
+ }
+
+ if (dmx->record) {
+ pr_error("dmx_get_record_flag clear record dmx->id: %d\n", dmx->id);
+ dmx->record = 0;
+ if (linked) {
+ /*A record will stop, reset the async fifos
+ *for linking the right demux
+ */
+ reset_async_fifos(dvb);
+ }
+ }
+
+find_done:
+ return record_flag;
+}
+
+static void dmx_cascade_set(int cur_dmx, int source) {
+ int fec_sel_demux = 0;
+ int data;
+
+ switch (source) {
+ case AM_TS_SRC_DMX0:
+ case AM_TS_SRC_DMX1:
+ case AM_TS_SRC_DMX2:
+ fec_sel_demux = source -AM_TS_SRC_DMX0;
+ break;
+ default:
+ fec_sel_demux = cur_dmx;
+ break;
+ }
+
+ data = READ_MPEG_REG(TS_TOP_CONFIG1);
+ data &= ~(0x3 << (cur_dmx*2));
+ data |= (fec_sel_demux << (cur_dmx*2));
+ WRITE_MPEG_REG(TS_TOP_CONFIG1,data);
+
+ pr_dbg("%s id:%d, source:%d data:0x%0x\n",__FUNCTION__,cur_dmx,fec_sel_demux,data);
+}
+
+/*Enable the demux device*/
+static int dmx_enable(struct aml_dmx *dmx)
+{
+ struct aml_dvb *dvb = (struct aml_dvb *)dmx->demux.priv;
+ int fec_sel, hi_bsf, fec_ctrl, record;
+ int fec_core_sel = 0;
+ int set_stb = 0, fec_s = 0;
+ int s2p_id;
+ u32 invert0 = 0, invert1 = 0, invert2 = 0, fec_s0 = 0, fec_s1 = 0, fec_s2 = 0;
+ u32 use_sop = 0;
+ int i = 0;
+
+ record = dmx_get_record_flag(dmx);
+ if (use_of_sop == 1) {
+ use_sop = 1;
+ pr_inf("dmx use of sop input\r\n");
+ }
+ switch (dmx->source) {
+ case AM_TS_SRC_TS0:
+ fec_sel = 0;
+ fec_ctrl = dvb->ts[0].control;
+ record = record ? 1 : 0;
+ break;
+ case AM_TS_SRC_TS1:
+ fec_sel = 1;
+ fec_ctrl = dvb->ts[1].control;
+ record = record ? 1 : 0;
+ break;
+ case AM_TS_SRC_TS2:
+ fec_sel = 2;
+ fec_ctrl = dvb->ts[2].control;
+ record = record ? 1 : 0;
+ break;
+ case AM_TS_SRC_TS3:
+ fec_sel = 3;
+ fec_ctrl = dvb->ts[3].control;
+ record = record ? 1 : 0;
+ break;
+ case AM_TS_SRC_S_TS0:
+ case AM_TS_SRC_S_TS1:
+ case AM_TS_SRC_S_TS2:
+ s2p_id = 0;
+ fec_ctrl = 0;
+ if (dmx->source == AM_TS_SRC_S_TS0) {
+ s2p_id = 0;
+ } else if (dmx->source == AM_TS_SRC_S_TS1) {
+ s2p_id = 1;
+ } else if (dmx->source == AM_TS_SRC_S_TS2) {
+ s2p_id = 2;
+ }
+ for (i = 0; i < dvb->s2p_total_count; i++) {
+ if (dvb->ts[i].s2p_id == s2p_id) {
+ fec_ctrl = dvb->ts[i].control;
+ }
+ }
+ //fec_sel = (s2p_id == 1) ? 5 : 6;
+ fec_sel = 6 - s2p_id;
+ record = record ? 1 : 0;
+ set_stb = 1;
+ fec_s = dmx->source - AM_TS_SRC_S_TS0;
+ break;
+ case AM_TS_SRC_HIU:
+ fec_sel = 7;
+ fec_ctrl = 0;
+ /*
+ support record in HIU mode
+ record = 0;
+ */
+ break;
+ case AM_TS_SRC_HIU1:
+ fec_sel = 8;
+ fec_ctrl = 0;
+ /*
+ support record in HIU mode
+ record = 0;
+ */
+ break;
+ case AM_TS_SRC_DMX0:
+ case AM_TS_SRC_DMX1:
+ case AM_TS_SRC_DMX2:
+ fec_sel = -1;
+ fec_ctrl = 0;
+ record = record ? 1 : 0;
+ break;
+ default:
+ fec_sel = 0;
+ fec_ctrl = 0;
+ record = 0;
+ break;
+ }
+
+ if (dmx->channel[0].used || dmx->channel[1].used) {
+ hi_bsf = 1;
+ if (fec_sel == 8) {
+ hi_bsf = 2; /*hi_bsf select hiu1*/
+ }
+ }else {
+ hi_bsf = 0;
+ }
+ if ((dvb->dsc[0].dst != -1)
+ && ((dvb->dsc[0].dst - AM_TS_SRC_DMX0) == dmx->id))
+ fec_core_sel = 1;
+
+ if ((dvb->dsc[1].dst != -1)
+ && ((dvb->dsc[1].dst - AM_TS_SRC_DMX0) == dmx->id)) {
+ int des_in, des_out, en_des = 0;
+
+ switch (dvb->dsc[1].source) {
+ case AM_TS_SRC_DMX0:
+ des_in = 0;
+ en_des = 1;
+ break;
+ case AM_TS_SRC_DMX1:
+ des_in = 1;
+ en_des = 1;
+ break;
+ case AM_TS_SRC_DMX2:
+ des_in = 2;
+ en_des = 1;
+ break;
+ default:
+ des_in = 0;
+ en_des = 0;
+ break;
+ }
+
+ switch (dvb->dsc[1].dst) {
+ case AM_TS_SRC_DMX0:
+ des_out = 1;
+ break;
+ case AM_TS_SRC_DMX1:
+ des_out = 2;
+ break;
+ case AM_TS_SRC_DMX2:
+ des_out = 4;
+ break;
+ default:
+ des_out = 0;
+ break;
+ }
+
+ if (!des_out)
+ en_des = 0;
+
+ WRITE_MPEG_REG(COMM_DESC_2_CTL,
+ (6 << 8) |/*des_out_dly_2*/
+ ((!!en_des) << 6) |/* des_pl_clk_2*/
+ ((!!en_des) << 5) |/* des_pl_2*/
+ (des_out << 2) |/*use_des_2*/
+ (des_in)/*des_i_sel_2*/
+ );
+ fec_core_sel = 1;
+ pr_dbg("dsc2 ctrl: 0x%x\n", READ_MPEG_REG(COMM_DESC_2_CTL));
+ }
+
+ pr_dbg("[dmx-%d]src: %d, rec: %d, hi_bsf: %d, dsc: %d\n",
+ dmx->id, dmx->source, record, hi_bsf, fec_core_sel);
+
+ if (dmx->chan_count) {
+ if (set_stb) {
+ u32 v = READ_MPEG_REG(STB_TOP_CONFIG);
+ int i;
+
+ for (i = 0; i < dvb->ts_in_total_count; i++) {
+ if (dvb->ts[i].s2p_id == 0)
+ fec_s0 = i;
+ else if (dvb->ts[i].s2p_id == 1)
+ fec_s1 = i;
+ else if (dvb->ts[i].s2p_id == 2)
+ fec_s2 = i;
+ }
+
+ invert0 = dvb->s2p[0].invert;
+ invert1 = dvb->s2p[1].invert;
+
+ v &= ~((0x3 << S2P0_FEC_SERIAL_SEL) |
+ (0x1f << INVERT_S2P0_FEC_CLK) |
+ (0x3 << S2P1_FEC_SERIAL_SEL) |
+ (0x1f << INVERT_S2P1_FEC_CLK));
+
+ v |= (fec_s0 << S2P0_FEC_SERIAL_SEL) |
+ (invert0 << INVERT_S2P0_FEC_CLK) |
+ (fec_s1 << S2P1_FEC_SERIAL_SEL) |
+ (invert1 << INVERT_S2P1_FEC_CLK);
+ WRITE_MPEG_REG(STB_TOP_CONFIG, v);
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_TL1) {
+ invert2 = dvb->s2p[2].invert;
+
+ //add s2p2 config
+ v = READ_MPEG_REG(STB_S2P2_CONFIG);
+ v &= ~((0x3 << S2P2_FEC_SERIAL_SEL) |
+ (0x1f << INVERT_S2P2_FEC_CLK));
+ v |= (fec_s2 << S2P2_FEC_SERIAL_SEL) |
+ (invert2 << INVERT_S2P2_FEC_CLK);
+ WRITE_MPEG_REG(STB_S2P2_CONFIG, v);
+ }
+ }
+
+ /*Initialize the registers */
+ DMX_WRITE_REG(dmx->id, STB_INT_MASK, DEMUX_INT_MASK);
+ DMX_WRITE_REG(dmx->id, DEMUX_MEM_REQ_EN,
+#ifdef USE_AHB_MODE
+ (1 << SECTION_AHB_DMA_EN) |
+ (0 << SUB_AHB_DMA_EN) |
+ (1 << OTHER_PES_AHB_DMA_EN) |
+#endif
+ (1 << SECTION_PACKET) |
+ (1 << VIDEO_PACKET) |
+ (1 << AUDIO_PACKET) |
+ (1 << SUB_PACKET) |
+ (1 << SCR_ONLY_PACKET) |
+ (1 << RECORDER_STREAM) |
+ (1 << OTHER_PES_PACKET));
+ DMX_WRITE_REG(dmx->id, PES_STRONG_SYNC, 0x1234);
+ DMX_WRITE_REG(dmx->id, DEMUX_ENDIAN,
+ (1<<SEPERATE_ENDIAN) |
+ (0<<OTHER_PES_ENDIAN) |
+ (7<<SCR_ENDIAN) |
+ (7<<SUB_ENDIAN) |
+ (7<<AUDIO_ENDIAN) |
+ (7<<VIDEO_ENDIAN) |
+ (7 << OTHER_ENDIAN) |
+ (7 << BYPASS_ENDIAN) | (0 << SECTION_ENDIAN));
+ if (fec_sel != 8) {
+ DMX_WRITE_REG(dmx->id, TS_HIU_CTL,
+// (0 << LAST_BURST_THRESHOLD) |
+ (hi_bsf << USE_HI_BSF_INTERFACE));
+ } else {
+ DMX_WRITE_REG(dmx->id, TS_HIU_CTL,
+ (1 << PDTS_WR_SEL) |
+ (hi_bsf << USE_HI_BSF_INTERFACE));
+ }
+
+ if (fec_sel == -1) {
+ dmx_cascade_set(dmx->id,dmx->source);
+ DMX_WRITE_REG(dmx->id, FEC_INPUT_CONTROL,
+ (fec_core_sel << FEC_CORE_SEL) |
+ (0 << FEC_SEL) | (fec_ctrl << 0));
+ } else {
+ dmx_cascade_set(dmx->id,dmx->source);
+ if (fec_sel != 8) {
+ DMX_WRITE_REG(dmx->id, FEC_INPUT_CONTROL,
+ (fec_core_sel << FEC_CORE_SEL) |
+ (fec_sel << FEC_SEL) | (fec_ctrl << 0));
+ } else {
+ DMX_WRITE_REG(dmx->id, FEC_INPUT_CONTROL,
+ (fec_core_sel << FEC_CORE_SEL) |
+ (1 << FEC_SEL_3BIT) | (fec_ctrl << 0));
+ }
+ }
+ DMX_WRITE_REG(dmx->id, STB_OM_CTL,
+ (0x40 << MAX_OM_DMA_COUNT) |
+ (0x7f << LAST_OM_ADDR));
+
+ DMX_WRITE_REG(dmx->id, VIDEO_STREAM_ID,
+ ((record && !hi_bsf) ? 0xFFFF : 0));
+
+ DMX_WRITE_REG(dmx->id, DEMUX_CONTROL,
+ (0 << BYPASS_USE_RECODER_PATH) |
+ (0 << INSERT_AUDIO_PES_STRONG_SYNC) |
+ (0 << INSERT_VIDEO_PES_STRONG_SYNC) |
+ (0 << OTHER_INT_AT_PES_BEGINING) |
+ (0 << DISCARD_AV_PACKAGE) |
+ ((!!dmx->dump_ts_select) << TS_RECORDER_SELECT) |
+ (record << TS_RECORDER_ENABLE) |
+ (1 << KEEP_DUPLICATE_PACKAGE) |
+ (1 << SECTION_END_WITH_TABLE_ID) |
+ (1 << ENABLE_FREE_CLK_FEC_DATA_VALID) |
+ (1 << ENABLE_FREE_CLK_STB_REG) |
+ (1 << STB_DEMUX_ENABLE) |
+ (use_sop << NOT_USE_OF_SOP_INPUT));
+ } else {
+ DMX_WRITE_REG(dmx->id, STB_INT_MASK, 0);
+ DMX_WRITE_REG(dmx->id, FEC_INPUT_CONTROL, 0);
+ DMX_WRITE_REG(dmx->id, DEMUX_CONTROL, 0);
+ //dmx not used, but it can cascade for other dmx
+ if ((dmx->source == AM_TS_SRC_DMX0 ||
+ dmx->source == AM_TS_SRC_DMX1 ||
+ dmx->source == AM_TS_SRC_DMX2 ) &&
+ (dmx->id != dmx->source-AM_TS_SRC_DMX0))
+ dmx_cascade_set(dmx->id,dmx->source);
+ }
+ return 0;
+}
+
+static int dmx_set_misc(struct aml_dmx *dmx, int hi_bsf, int en_dsc)
+{
+ if (hi_bsf >= 0) {
+ DMX_WRITE_REG(dmx->id, TS_HIU_CTL,
+ hi_bsf ?
+ (DMX_READ_REG(dmx->id, TS_HIU_CTL) |
+ (1 << USE_HI_BSF_INTERFACE))
+ :
+ (DMX_READ_REG(dmx->id, TS_HIU_CTL) &
+ (~(1 << USE_HI_BSF_INTERFACE))));
+ }
+
+ if (en_dsc >= 0) {
+ DMX_WRITE_REG(dmx->id, FEC_INPUT_CONTROL,
+ en_dsc ?
+ (DMX_READ_REG(dmx->id, FEC_INPUT_CONTROL) |
+ (1 << FEC_CORE_SEL))
+ :
+ (DMX_READ_REG(dmx->id, FEC_INPUT_CONTROL) &
+ (~(1 << FEC_CORE_SEL))));
+ }
+
+ return 0;
+}
+
+static int dmx_set_misc_id(struct aml_dvb *dvb, int id, int hi_bsf, int en_dsc)
+{
+ return dmx_set_misc(&dvb->dmx[id], hi_bsf, en_dsc);
+}
+
+/*Get the channel's ID by its PID*/
+static int dmx_get_chan(struct aml_dmx *dmx, int pid)
+{
+ int id;
+
+ for (id = 0; id < CHANNEL_COUNT; id++) {
+ if (dmx->channel[id].used && dmx->channel[id].pid == pid)
+ return id;
+ }
+
+ return -1;
+}
+
+/*Get the channel's target*/
+static u32 dmx_get_chan_target(struct aml_dmx *dmx, int cid)
+{
+ u32 type;
+
+ if (!dmx->channel[cid].used)
+ return 0xFFFF;
+
+ if (dmx->channel[cid].type == DMX_TYPE_SEC) {
+ type = SECTION_PACKET;
+ } else {
+ switch (dmx->channel[cid].pes_type) {
+ case DMX_PES_AUDIO:
+ type = AUDIO_PACKET;
+ break;
+ case DMX_PES_VIDEO:
+ type = VIDEO_PACKET;
+ break;
+ case DMX_PES_SUBTITLE:
+ case DMX_PES_TELETEXT:
+ type = SUB_PACKET;
+ break;
+ case DMX_PES_PCR:
+ type = SCR_ONLY_PACKET;
+ break;
+ case DMX_PES_AUDIO3:
+ type = OTHER_PES_PACKET;
+ break;
+ default:
+ type = (dmx->channel[0].used || dmx->channel[1].used) ?
+ RECORDER_STREAM : VIDEO_PACKET;
+ break;
+ }
+ }
+ dmx->channel[cid].pkt_type = type;
+
+ pr_dbg("chan target: %x %x\n", type, dmx->channel[cid].pid);
+ return (type << PID_TYPE) | dmx->channel[cid].pid;
+}
+
+/*Get the advance value of the channel*/
+static inline u32 dmx_get_chan_advance(struct aml_dmx *dmx, int cid)
+{
+ return 0;
+}
+
+/*Set the channel registers*/
+static int dmx_set_chan_regs(struct aml_dmx *dmx, int cid)
+{
+ u32 data, addr, advance, max;
+
+ pr_dbg("set channel (id:%d PID:0x%x) registers\n", cid,
+ dmx->channel[cid].pid);
+
+ while (DMX_READ_REG(dmx->id, FM_WR_ADDR) & 0x8000)
+ udelay(1);
+
+ if (cid & 1) {
+ data =
+ (dmx_get_chan_target(dmx, cid - 1) << 16) |
+ dmx_get_chan_target(dmx, cid);
+ advance =
+ (dmx_get_chan_advance(dmx, cid) << 8) |
+ dmx_get_chan_advance(dmx, cid - 1);
+
+ if (dmx->channel[cid - 1].used)
+ set_debug_dmx_chanpids_types(dmx->id, cid - 1,
+ dmx->channel[cid - 1].pkt_type);
+ } else {
+ data =
+ (dmx_get_chan_target(dmx, cid) << 16) |
+ dmx_get_chan_target(dmx, cid + 1);
+ advance =
+ (dmx_get_chan_advance(dmx, cid + 1) << 8) |
+ dmx_get_chan_advance(dmx, cid);
+
+ if (dmx->channel[cid + 1].used)
+ set_debug_dmx_chanpids_types(dmx->id, cid + 1,
+ dmx->channel[cid + 1].pkt_type);
+ }
+ addr = cid >> 1;
+ DMX_WRITE_REG(dmx->id, FM_WR_DATA, data);
+ DMX_WRITE_REG(dmx->id, FM_WR_ADDR, (advance << 16) | 0x8000 | addr);
+
+ pr_dbg("write fm %x:%x\n", (advance << 16) | 0x8000 | addr, data);
+
+ for (max = CHANNEL_COUNT - 1; max > 0; max--) {
+ if (dmx->channel[max].used)
+ break;
+ }
+
+ data = DMX_READ_REG(dmx->id, MAX_FM_COMP_ADDR) & 0xF0;
+ DMX_WRITE_REG(dmx->id, MAX_FM_COMP_ADDR, data | (max >> 1));
+
+ pr_dbg("write fm comp %x\n", data | (max >> 1));
+
+ if (DMX_READ_REG(dmx->id, OM_CMD_STATUS) & 0x8e00) {
+ pr_error("warning: send cmd %x\n",
+ DMX_READ_REG(dmx->id, OM_CMD_STATUS));
+ }
+
+ if (cid == 0) {
+ video_pts = 0;
+ first_video_pts = 0;
+ }
+ else if (cid == 1) {
+ audio_pts = 0;
+ first_audio_pts = 0;
+ }
+
+ if (dmx->channel[cid].used)
+ set_debug_dmx_chanpids_types(dmx->id, cid,
+ dmx->channel[cid].pkt_type);
+ return 0;
+}
+
+/*Get the filter target*/
+static int dmx_get_filter_target(struct aml_dmx *dmx, int fid, u32 *target,
+ u8 *advance)
+{
+ struct dmx_section_filter *filter;
+ struct aml_filter *f;
+ int i, cid, neq_bytes;
+
+ fid = fid & 0xFFFF;
+ f = &dmx->filter[fid];
+
+ if (!f->used) {
+ target[0] = 0x1fff;
+ advance[0] = 0;
+ for (i = 1; i < FILTER_LEN; i++) {
+ target[i] = 0x9fff;
+ advance[i] = 0;
+ }
+ return 0;
+ }
+
+ cid = f->chan_id;
+ filter = f->filter;
+
+ neq_bytes = 0;
+ if (filter->filter_mode[0] != 0xFF) {
+ neq_bytes = 2;
+ } else {
+ for (i = 3; i < FILTER_LEN; i++) {
+ if (filter->filter_mode[i] != 0xFF)
+ neq_bytes++;
+ }
+ }
+
+ f->neq = 0;
+
+ for (i = 0; i < FILTER_LEN; i++) {
+ u8 value = filter->filter_value[i];
+ u8 mask = filter->filter_mask[i];
+ u8 mode = filter->filter_mode[i];
+ u8 mb, mb1, nb, v, t, adv = 0;
+
+ if (!i) {
+ mb = 1;
+ mb1 = 1;
+ v = 0;
+ if ((mode == 0xFF) && mask) {
+ t = mask & 0xF0;
+ if (t) {
+ mb1 = 0;
+ adv |= t^0xF0;
+ }
+ v |= (value & 0xF0) | adv;
+
+ t = mask & 0x0F;
+ if (t) {
+ mb = 0;
+ adv |= t^0x0F;
+ }
+ v |= (value & 0x0F) | adv;
+ }
+
+ target[i] = (mb << SECTION_FIRSTBYTE_MASKLOW) |
+ (mb1 << SECTION_FIRSTBYTE_MASKHIGH) |
+ (0 << SECTION_FIRSTBYTE_DISABLE_PID_CHECK) |
+ (cid << SECTION_FIRSTBYTE_PID_INDEX) | v;
+ advance[i] = adv;
+ } else {
+ if (i < 3) {
+ value = 0;
+ mask = 0;
+ mode = 0xff;
+ }
+ mb = 1;
+ nb = 0;
+ v = 0;
+
+ if ((i >= 3) && mask) {
+ if (mode == 0xFF) {
+ mb = 0;
+ nb = 0;
+ adv = mask ^ 0xFF;
+ v = value | adv;
+ } else {
+ if (neq_bytes == 1) {
+ mb = 0;
+ nb = 1;
+ adv = mask ^ 0xFF;
+ v = value & ~adv;
+ }
+ }
+ }
+ target[i] = (mb << SECTION_RESTBYTE_MASK) |
+ (nb << SECTION_RESTBYTE_MASK_EQ) |
+ (0 << SECTION_RESTBYTE_DISABLE_PID_CHECK) |
+ (cid << SECTION_RESTBYTE_PID_INDEX) | v;
+ advance[i] = adv;
+ }
+
+ f->value[i] = value;
+ f->maskandmode[i] = mask & mode;
+ f->maskandnotmode[i] = mask & ~mode;
+
+ if (f->maskandnotmode[i])
+ f->neq = 1;
+ }
+
+ return 0;
+}
+
+/*Set the filter registers*/
+static int dmx_set_filter_regs(struct aml_dmx *dmx, int fid)
+{
+ u32 t1[FILTER_LEN], t2[FILTER_LEN];
+ u8 advance1[FILTER_LEN], advance2[FILTER_LEN];
+ u32 addr, data, max, adv;
+ int i;
+
+ pr_dbg("set filter (id:%d) registers\n", fid);
+
+ if (fid & 1) {
+ dmx_get_filter_target(dmx, fid - 1, t1, advance1);
+ dmx_get_filter_target(dmx, fid, t2, advance2);
+ } else {
+ dmx_get_filter_target(dmx, fid, t1, advance1);
+ dmx_get_filter_target(dmx, fid + 1, t2, advance2);
+ }
+
+ for (i = 0; i < FILTER_LEN; i++) {
+ while (DMX_READ_REG(dmx->id, FM_WR_ADDR) & 0x8000)
+ udelay(1);
+
+ data = (t1[i] << 16) | t2[i];
+ addr = (fid >> 1) | ((i + 1) << 4);
+ adv = (advance1[i] << 8) | advance2[i];
+
+ DMX_WRITE_REG(dmx->id, FM_WR_DATA, data);
+ DMX_WRITE_REG(dmx->id, FM_WR_ADDR, (adv << 16) | 0x8000 | addr);
+
+ pr_dbg("write fm %x:%x\n", (adv << 16) | 0x8000 | addr, data);
+ }
+
+ for (max = FILTER_COUNT - 1; max > 0; max--) {
+ if (dmx->filter[max].used)
+ break;
+ }
+
+ data = DMX_READ_REG(dmx->id, MAX_FM_COMP_ADDR) & 0xF;
+ DMX_WRITE_REG(dmx->id, MAX_FM_COMP_ADDR, data | ((max >> 1) << 4));
+
+ pr_dbg("write fm comp %x\n", data | ((max >> 1) << 4));
+
+ if (DMX_READ_REG(dmx->id, OM_CMD_STATUS) & 0x8e00) {
+ pr_error("error send cmd %x\n",
+ DMX_READ_REG(dmx->id, OM_CMD_STATUS));
+ }
+
+ return 0;
+}
+
+/*Clear the filter's buffer*/
+static void dmx_clear_filter_buffer(struct aml_dmx *dmx, int fid)
+{
+ u32 section_busy32 = DMX_READ_REG(dmx->id, SEC_BUFF_READY);
+ u32 filter_number;
+ int i;
+
+ if (!section_busy32)
+ return;
+
+ for (i = 0; i < SEC_BUF_COUNT; i++) {
+ if (section_busy32 & (1 << i)) {
+ DMX_WRITE_REG(dmx->id, SEC_BUFF_NUMBER, i);
+ filter_number =
+ (DMX_READ_REG(dmx->id, SEC_BUFF_NUMBER) >> 8);
+ if (filter_number != fid)
+ section_busy32 &= ~(1 << i);
+ }
+ }
+
+ if (section_busy32)
+ DMX_WRITE_REG(dmx->id, SEC_BUFF_READY, section_busy32);
+}
+
+static void async_fifo_disable(struct aml_asyncfifo *afifo)
+{
+ pr_inf("AF(%d) disable asyncfifo\n", afifo->id);
+ CLEAR_ASYNC_FIFO_REG_MASK(afifo->id, REG1, 1 << ASYNC_FIFO_FLUSH_EN);
+ CLEAR_ASYNC_FIFO_REG_MASK(afifo->id, REG2, 1 << ASYNC_FIFO_FILL_EN);
+ if (READ_ASYNC_FIFO_REG(afifo->id, REG2) & (1 << ASYNC_FIFO_FILL_EN)
+ || READ_ASYNC_FIFO_REG(afifo->id, REG1)
+ & (1 << ASYNC_FIFO_FLUSH_EN)) {
+ pr_error("disable failed\n");
+ } else
+ pr_inf("disable ok\n");
+ afifo->buf_toggle = 0;
+ afifo->buf_read = 0;
+}
+
+static void async_fifo_set_regs(struct aml_asyncfifo *afifo, int source_val)
+{
+ u32 start_addr = (afifo->secure_enable && afifo->blk.addr)?
+ afifo->blk.addr : virt_to_phys((void *)afifo->pages);
+ u32 size = afifo->buf_len;
+ u32 flush_size = afifo->flush_size;
+ int factor = dmx_get_order(size / flush_size);
+ u32 old_size, new_size, old_factor, new_factor;
+ int old_src, old_en;
+
+ old_en = READ_ASYNC_FIFO_REG(afifo->id, REG2)
+ & (1 << ASYNC_FIFO_FILL_EN);
+ old_src =
+ (READ_ASYNC_FIFO_REG(afifo->id, REG2) >> ASYNC_FIFO_SOURCE_LSB)
+ & 3;
+
+ new_size = (size >> 7) & 0x7fff;
+ old_size =
+ (READ_ASYNC_FIFO_REG(afifo->id, REG1)
+ >> ASYNC_FIFO_FLUSH_CNT_LSB)
+ & 0x7fff;
+
+ old_factor =
+ (READ_ASYNC_FIFO_REG(afifo->id, REG3)
+ >> ASYNC_FLUSH_SIZE_IRQ_LSB)
+ & 0x7fff;
+ new_factor = ((size >> (factor + 7)) - 1) & 0x7fff;
+
+ pr_inf("AF(%d) [%s] src:0x%x->0x%x size:0x%x->0x%x factor:0x%x->0x%x\n",
+ afifo->id,
+ old_en? "on" : "off",
+ old_src, source_val,
+ old_size, new_size,
+ old_factor, new_factor);
+
+ if (old_en
+ && (old_src == source_val)
+ && (new_size == old_size)
+ && (old_factor == new_factor))
+ return;
+
+ if (old_en) {
+ if ((old_size == new_size)
+ && (old_factor == new_factor)) {
+ /*only source changed, do not reset all*/
+ /* Connect the DEMUX to ASYNC_FIFO */
+ WRITE_ASYNC_FIFO_REG(afifo->id, REG2,
+ (READ_ASYNC_FIFO_REG(afifo->id, REG2)
+ & ~(0x3 << ASYNC_FIFO_SOURCE_LSB))
+ | (source_val << ASYNC_FIFO_SOURCE_LSB));
+ return;
+ } else {
+ /*Dynamic change setting is not supported,
+ *should disable it first.
+ *Data discontinue will be here.
+ */
+ async_fifo_disable(afifo);
+ }
+ }
+
+ pr_inf("ASYNC FIFO id=%d, link to DMX%d, start_addr %x, buf_size %d,"
+ "source value 0x%x, factor %d\n",
+ afifo->id, afifo->source, start_addr, size, source_val, factor);
+
+ /* Destination address */
+ WRITE_ASYNC_FIFO_REG(afifo->id, REG0, start_addr);
+
+ /* Setup flush parameters */
+ WRITE_ASYNC_FIFO_REG(afifo->id, REG1,
+ (0 << ASYNC_FIFO_TO_HIU) |
+ (0 << ASYNC_FIFO_FLUSH) |
+ /* don't flush the path */
+ (1 << ASYNC_FIFO_RESET) |
+ /* reset the path */
+ (1 << ASYNC_FIFO_WRAP_EN) |
+ /* wrap enable */
+ (0 << ASYNC_FIFO_FLUSH_EN) |
+ /* disable the flush path */
+ /*(0x3 << ASYNC_FIFO_FLUSH_CNT_LSB);
+ * flush 3 x 32 32-bit words
+ */
+ /*(0x7fff << ASYNC_FIFO_FLUSH_CNT_LSB);
+ * flush 4MBytes of data
+ */
+ (((size >> 7) & 0x7fff) << ASYNC_FIFO_FLUSH_CNT_LSB));
+ /* number of 128-byte blocks to flush */
+
+ /* clear the reset signal */
+ WRITE_ASYNC_FIFO_REG(afifo->id, REG1,
+ READ_ASYNC_FIFO_REG(afifo->id,
+ REG1) & ~(1 << ASYNC_FIFO_RESET));
+ /* Enable flush */
+ WRITE_ASYNC_FIFO_REG(afifo->id, REG1,
+ READ_ASYNC_FIFO_REG(afifo->id,
+ REG1) | (1 << ASYNC_FIFO_FLUSH_EN));
+
+ /*Setup Fill parameters */
+ WRITE_ASYNC_FIFO_REG(afifo->id, REG2,
+ (1 << ASYNC_FIFO_ENDIAN_LSB) |
+ (0 << ASYNC_FIFO_FILL_EN) |
+ /* disable fill path to reset fill path */
+ /*(96 << ASYNC_FIFO_FILL_CNT_LSB);
+ *3 x 32 32-bit words
+ */
+ (0 << ASYNC_FIFO_FILL_CNT_LSB));
+ /* forever FILL; */
+ WRITE_ASYNC_FIFO_REG(afifo->id, REG2,
+ READ_ASYNC_FIFO_REG(afifo->id, REG2) |
+ (1 << ASYNC_FIFO_FILL_EN));/*Enable fill path*/
+
+ /* generate flush interrupt */
+ WRITE_ASYNC_FIFO_REG(afifo->id, REG3,
+ (READ_ASYNC_FIFO_REG(afifo->id, REG3) & 0xffff0000) |
+ ((((size >> (factor + 7)) - 1) & 0x7fff) <<
+ ASYNC_FLUSH_SIZE_IRQ_LSB));
+
+ /* Connect the STB DEMUX to ASYNC_FIFO */
+ WRITE_ASYNC_FIFO_REG(afifo->id, REG2,
+ READ_ASYNC_FIFO_REG(afifo->id, REG2) |
+ (source_val << ASYNC_FIFO_SOURCE_LSB));
+}
+
+/*Reset the ASYNC FIFOS when a ASYNC FIFO connect to a different DMX*/
+static void reset_async_fifos(struct aml_dvb *dvb)
+{
+ struct aml_asyncfifo *low_dmx_fifo = NULL;
+ struct aml_asyncfifo *high_dmx_fifo = NULL;
+ struct aml_asyncfifo *highest_dmx_fifo = NULL;
+ int i, j;
+ int record_enable;
+
+ struct aml_asyncfifo *afifo = NULL;
+
+ for (j = 0; j < DMX_DEV_COUNT; j++) {
+ if (!dvb->dmx[j].init)
+ continue;
+
+ record_enable = 0;
+ for (i = 0; i < dvb->async_fifo_total_count; i++) {
+ afifo = &dvb->asyncfifo[i];
+
+ if (!afifo->init)
+ continue;
+
+ if (!dvb->dmx[j].record
+ || !(dvb->dmx[j].id == afifo->source))
+ continue;
+
+ /*This dmx is linked to the async fifo,
+ *Enable the TS_RECORDER_ENABLE
+ */
+ record_enable = 1;
+ if (!low_dmx_fifo) {
+ low_dmx_fifo = afifo;
+ } else if (low_dmx_fifo->source >
+ afifo->source) {
+ if (!high_dmx_fifo)
+ high_dmx_fifo = low_dmx_fifo;
+ else {
+ highest_dmx_fifo = high_dmx_fifo;
+ high_dmx_fifo = low_dmx_fifo;
+ }
+ low_dmx_fifo = afifo;
+ } else if (low_dmx_fifo->source < afifo->source) {
+ if (!high_dmx_fifo)
+ high_dmx_fifo = afifo;
+ else {
+ if (high_dmx_fifo->source >
+ afifo->source) {
+ highest_dmx_fifo =
+ high_dmx_fifo;
+ high_dmx_fifo = afifo;
+ } else {
+ highest_dmx_fifo = afifo;
+ }
+ }
+ }
+ break;
+ }
+
+ pr_inf("Set DMX%d TS_RECORDER_ENABLE to %d\n", dvb->dmx[j].id,
+ record_enable ? 1 : 0);
+
+ if (record_enable) {
+ int old_en =
+ DMX_READ_REG(dvb->dmx[j].id, DEMUX_CONTROL)
+ & (1 << TS_RECORDER_ENABLE);
+
+ if (!old_en) {
+ DMX_WRITE_REG(dvb->dmx[j].id, DEMUX_CONTROL,
+ DMX_READ_REG(dvb->dmx[j].id,
+ DEMUX_CONTROL)
+ | (1 << TS_RECORDER_ENABLE));
+ }
+ } else {
+ int old_en =
+ DMX_READ_REG(dvb->dmx[j].id, DEMUX_CONTROL)
+ & (1 << TS_RECORDER_ENABLE);
+
+ if (old_en) {
+ DMX_WRITE_REG(dvb->dmx[j].id, DEMUX_CONTROL,
+ DMX_READ_REG(dvb->dmx[j].id,
+ DEMUX_CONTROL)
+ & (~(1 << TS_RECORDER_ENABLE)));
+ }
+ }
+ }
+ pr_inf("reset ASYNC FIFOs\n");
+ for (i = 0; i < dvb->async_fifo_total_count; i++) {
+ int old;
+
+ afifo = &dvb->asyncfifo[i];
+
+ if (!afifo->init)
+ continue;
+
+ old = READ_ASYNC_FIFO_REG(afifo->id, REG2)
+ & (1 << ASYNC_FIFO_FILL_EN);
+
+ if (old
+ && (afifo != low_dmx_fifo)
+ && (afifo != high_dmx_fifo)
+ && (afifo != highest_dmx_fifo))
+ async_fifo_disable(afifo);
+ }
+
+ /*Set the async fifo regs */
+ if (low_dmx_fifo) {
+ async_fifo_set_regs(low_dmx_fifo, 0x3);
+
+ if (high_dmx_fifo) {
+ async_fifo_set_regs(high_dmx_fifo, 0x2);
+
+ if (highest_dmx_fifo)
+ async_fifo_set_regs(highest_dmx_fifo, 0x0);
+ }
+ }
+}
+
+/*Reset the demux device*/
+void dmx_reset_hw(struct aml_dvb *dvb)
+{
+ dmx_reset_hw_ex(dvb, 1);
+}
+
+/*Reset the demux device*/
+void dmx_reset_hw_ex(struct aml_dvb *dvb, int reset_irq)
+{
+ int id, times;
+ u32 pcr_num[DMX_DEV_COUNT];
+ u32 pcr_reg[DMX_DEV_COUNT];
+
+ pr_dbg("[dmx_kpi] demux reset begin\n");
+
+ for (id = 0; id < DMX_DEV_COUNT; id++) {
+ if (!dvb->dmx[id].init)
+ continue;
+ pcr_reg[id] = DMX_READ_REG(id, PCR90K_CTL);
+ pcr_num[id] = DMX_READ_REG(id, ASSIGN_PID_NUMBER);
+ pr_dbg("reset demux, pcr_regs[%d]:0x%x, pcr_num[%d]:0x%x\n", id, pcr_reg[id], id, pcr_num[id]);
+ if (reset_irq) {
+ if (dvb->dmx[id].dmx_irq != -1)
+ disable_irq(dvb->dmx[id].dmx_irq);
+ if (dvb->dmx[id].dvr_irq != -1)
+ disable_irq(dvb->dmx[id].dvr_irq);
+ }
+ }
+#ifdef ENABLE_SEC_BUFF_WATCHDOG
+ if (reset_irq)
+ del_timer_sync(&dvb->watchdog_timer);
+#endif
+ /*RESET_TOP will clear the dsc pid , save all dsc pid that setting in TA*/
+ for (id = 0; id < DSC_DEV_COUNT; id++) {
+ struct aml_dsc *dsc = &dvb->dsc[id];
+ int n;
+
+ for (n = 0; n < DSC_COUNT; n++) {
+ struct aml_dsc_channel *ch = &dsc->channel[n];
+ /*if(ch->used)*/
+ {
+ ch->id = n;
+ dsc_get_pid(ch,&ch->pid);
+ }
+ }
+ }
+ WRITE_MPEG_REG(RESET1_REGISTER, RESET_DEMUXSTB);
+ /*WRITE_MPEG_REG(RESET3_REGISTER, RESET_DEMUX2|RESET_DEMUX1|RESET_DEMUX0|RESET_S2P1|RESET_S2P0|RESET_TOP);*/
+
+ for (id = 0; id < DMX_DEV_COUNT; id++) {
+ times = 0;
+ while (times++ < 1000000) {
+ if (!(DMX_READ_REG(id, OM_CMD_STATUS) & 0x01))
+ break;
+ }
+ }
+ {
+ u32 data;
+ data = READ_MPEG_REG(STB_TOP_CONFIG);
+ ciplus = 0x7C000000 & data;
+ }
+
+ WRITE_MPEG_REG(STB_TOP_CONFIG, 0);
+ WRITE_MPEG_REG(STB_S2P2_CONFIG, 0);
+
+ for (id = 0; id < DMX_DEV_COUNT; id++) {
+ u32 version, data;
+
+ if (!dvb->dmx[id].init)
+ continue;
+
+ if (reset_irq) {
+ if (dvb->dmx[id].dmx_irq != -1)
+ enable_irq(dvb->dmx[id].dmx_irq);
+ if (dvb->dmx[id].dvr_irq != -1)
+ enable_irq(dvb->dmx[id].dvr_irq);
+ }
+ DMX_WRITE_REG(id, DEMUX_CONTROL, 0x0000);
+ version = DMX_READ_REG(id, STB_VERSION);
+ DMX_WRITE_REG(id, STB_TEST_REG, version);
+ pr_dbg("STB %d hardware version : %d\n", id, version);
+ DMX_WRITE_REG(id, STB_TEST_REG, 0x5550);
+ data = DMX_READ_REG(id, STB_TEST_REG);
+ if (data != 0x5550)
+ pr_error("STB %d register access failed\n", id);
+ DMX_WRITE_REG(id, STB_TEST_REG, 0xaaa0);
+ data = DMX_READ_REG(id, STB_TEST_REG);
+ if (data != 0xaaa0)
+ pr_error("STB %d register access failed\n", id);
+ DMX_WRITE_REG(id, MAX_FM_COMP_ADDR, 0x0000);
+ DMX_WRITE_REG(id, STB_INT_MASK, 0);
+ DMX_WRITE_REG(id, STB_INT_STATUS, 0xffff);
+ DMX_WRITE_REG(id, FEC_INPUT_CONTROL, 0);
+ }
+
+ stb_enable(dvb);
+
+ for (id = 0; id < DMX_DEV_COUNT; id++) {
+ struct aml_dmx *dmx = &dvb->dmx[id];
+ int n;
+ unsigned long addr;
+ unsigned long base;
+ unsigned long grp_addr[SEC_BUF_GRP_COUNT];
+ int grp_len[SEC_BUF_GRP_COUNT];
+
+ if (!dvb->dmx[id].init)
+ continue;
+
+ if (dmx->sec_pages) {
+ grp_len[0] = (1 << SEC_GRP_LEN_0) * 8;
+ grp_len[1] = (1 << SEC_GRP_LEN_1) * 8;
+ grp_len[2] = (1 << SEC_GRP_LEN_2) * 8;
+ grp_len[3] = (1 << SEC_GRP_LEN_3) * 8;
+
+ grp_addr[0] = virt_to_phys((void *)dmx->sec_pages);
+ grp_addr[1] = grp_addr[0] + grp_len[0];
+ grp_addr[2] = grp_addr[1] + grp_len[1];
+ grp_addr[3] = grp_addr[2] + grp_len[2];
+
+ base = grp_addr[0] & 0xFFFF0000;
+ DMX_WRITE_REG(dmx->id, SEC_BUFF_BASE, base >> 16);
+ DMX_WRITE_REG(dmx->id, SEC_BUFF_01_START,
+ (((grp_addr[0] - base) >> 8) << 16) |
+ ((grp_addr[1] - base) >> 8));
+ DMX_WRITE_REG(dmx->id, SEC_BUFF_23_START,
+ (((grp_addr[2] - base) >> 8) << 16) |
+ ((grp_addr[3] - base) >> 8));
+ DMX_WRITE_REG(dmx->id, SEC_BUFF_SIZE,
+ SEC_GRP_LEN_0 |
+ (SEC_GRP_LEN_1 << 4) |
+ (SEC_GRP_LEN_2 << 8) |
+ (SEC_GRP_LEN_3 << 12));
+ }
+#ifdef NO_SUB
+#ifndef SUB_PARSER
+ if (dmx->sub_pages) {
+ addr = virt_to_phys((void *)dmx->sub_pages);
+ DMX_WRITE_REG(dmx->id, SB_START, addr >> 12);
+ DMX_WRITE_REG(dmx->id, SB_LAST_ADDR,
+ (dmx->sub_buf_len >> 3) - 1);
+ }
+#endif
+#endif
+ if (dmx->pes_pages) {
+ addr = virt_to_phys((void *)dmx->pes_pages);
+ DMX_WRITE_REG(dmx->id, OB_START, addr >> 12);
+ DMX_WRITE_REG(dmx->id, OB_LAST_ADDR,
+ (dmx->pes_buf_len >> 3) - 1);
+ }
+
+ for (n = 0; n < CHANNEL_COUNT; n++) {
+ /*struct aml_channel *chan = &dmx->channel[n];*/
+
+ /*if (chan->used)*/
+ {
+#ifdef NO_SUB
+#ifdef SUB_PARSER
+ /*
+ check if subtitle channel was running,
+ the parser will be used in amstream also,
+ take care of the buff ptr.
+ */
+ u32 v = dmx_get_chan_target(dmx, n);
+ if (v != 0xFFFF &&
+ (v & (0x7 << PID_TYPE))
+ == (SUB_PACKET << PID_TYPE))
+ set_subtitle_pes_buffer(dmx);
+#endif
+#endif
+ {
+ u32 v = dmx_get_chan_target(dmx, n);
+ if (v != 0xFFFF &&
+ (v & (0x7 << PID_TYPE))
+ ==
+ (OTHER_PES_PACKET << PID_TYPE))
+ pes_off_pre[dmx->id] = 0;
+ }
+ dmx_set_chan_regs(dmx, n);
+ }
+ }
+
+ for (n = 0; n < FILTER_COUNT; n++) {
+ struct aml_filter *filter = &dmx->filter[n];
+
+ if (filter->used)
+ dmx_set_filter_regs(dmx, n);
+ }
+ dmx_enable(&dvb->dmx[id]);
+ dmx_smallsec_set(&dmx->smallsec,
+ dmx->smallsec.enable,
+ dmx->smallsec.bufsize,
+ 1);
+
+ dmx_timeout_set(&dmx->timeout,
+ dmx->timeout.enable,
+ dmx->timeout.timeout,
+ dmx->timeout.ch_disable,
+ dmx->timeout.match,
+ 1);
+ DMX_WRITE_REG(id, ASSIGN_PID_NUMBER, pcr_num[id]);
+ DMX_WRITE_REG(id, PCR90K_CTL, pcr_reg[id]);
+ }
+
+ for (id = 0; id < DSC_DEV_COUNT; id++) {
+ struct aml_dsc *dsc = &dvb->dsc[id];
+ int n;
+
+ for (n = 0; n < DSC_COUNT; n++) {
+ int flag = 0;
+ struct aml_dsc_channel *ch = &dsc->channel[n];
+ /*if(ch->used)*/
+ {
+ ch->work_mode = -1;
+ //if ta setting pid, used will 0
+ if (ch->pid != 0x1fff && !ch->used) {
+ flag = 1;
+ ch->used = 1;
+ }
+ dsc_set_pid(ch, ch->pid);
+ if (flag)
+ ch->used = 0;
+ //dsc_set_keys(ch);
+ }
+ }
+ }
+#ifdef ENABLE_SEC_BUFF_WATCHDOG
+ if (reset_irq) {
+ mod_timer(&dvb->watchdog_timer,
+ jiffies + msecs_to_jiffies(WATCHDOG_TIMER));
+ }
+#endif
+
+ pr_dbg("[dmx_kpi] demux reset end\n");
+}
+
+/*Reset the individual demux*/
+void dmx_reset_dmx_hw_ex_unlock(struct aml_dvb *dvb, struct aml_dmx *dmx,
+ int reset_irq)
+{
+ u32 pcr_num = 0;
+ u32 pcr_regs = 0;
+ {
+ if (!dmx->init)
+ return;
+ pcr_regs = DMX_READ_REG(dmx->id, PCR90K_CTL);
+ pcr_num = DMX_READ_REG(dmx->id, ASSIGN_PID_NUMBER);
+ pr_dbg("reset demux, pcr_regs:0x%x, pcr_num:0x%x\n", pcr_regs, pcr_num);
+ }
+ {
+ if (!dmx->init)
+ return;
+ if (reset_irq) {
+ if (dmx->dmx_irq != -1)
+ disable_irq(dmx->dmx_irq);
+ if (dmx->dvr_irq != -1)
+ disable_irq(dmx->dvr_irq);
+ }
+ }
+#ifdef ENABLE_SEC_BUFF_WATCHDOG
+ if (reset_irq) {
+ /*del_timer_sync(&dvb->watchdog_timer); */
+ dvb->dmx_watchdog_disable[dmx->id] = 1;
+ }
+#endif
+ pr_error("dmx_reset_dmx_hw_ex_unlock into\n");
+ WRITE_MPEG_REG(RESET3_REGISTER,
+ (dmx->id) ? ((dmx->id ==
+ 1) ? RESET_DEMUX1 : RESET_DEMUX2) :
+ RESET_DEMUX0);
+ WRITE_MPEG_REG(RESET3_REGISTER, RESET_DES);
+
+ {
+ int times;
+
+ times = 0;
+ while (times++ < 1000000) {
+ if (!(DMX_READ_REG(dmx->id, OM_CMD_STATUS) & 0x01))
+ break;
+ }
+ }
+
+ /*WRITE_MPEG_REG(STB_TOP_CONFIG, 0); */
+ {
+ u32 data;
+ data = READ_MPEG_REG(STB_TOP_CONFIG);
+ ciplus = 0x7C000000 & data;
+ }
+
+ {
+ u32 version, data;
+
+ if (!dmx->init)
+ return;
+
+ if (reset_irq) {
+ if (dmx->dmx_irq != -1)
+ enable_irq(dmx->dmx_irq);
+ if (dmx->dvr_irq != -1)
+ enable_irq(dmx->dvr_irq);
+ }
+ DMX_WRITE_REG(dmx->id, DEMUX_CONTROL, 0x0000);
+ version = DMX_READ_REG(dmx->id, STB_VERSION);
+ DMX_WRITE_REG(dmx->id, STB_TEST_REG, version);
+ pr_dbg("STB %d hardware version : %d\n", dmx->id, version);
+ DMX_WRITE_REG(dmx->id, STB_TEST_REG, 0x5550);
+ data = DMX_READ_REG(dmx->id, STB_TEST_REG);
+ if (data != 0x5550)
+ pr_error("STB %d register access failed\n", dmx->id);
+ DMX_WRITE_REG(dmx->id, STB_TEST_REG, 0xaaa0);
+ data = DMX_READ_REG(dmx->id, STB_TEST_REG);
+ if (data != 0xaaa0)
+ pr_error("STB %d register access failed\n", dmx->id);
+ DMX_WRITE_REG(dmx->id, MAX_FM_COMP_ADDR, 0x0000);
+ DMX_WRITE_REG(dmx->id, STB_INT_MASK, 0);
+ DMX_WRITE_REG(dmx->id, STB_INT_STATUS, 0xffff);
+ DMX_WRITE_REG(dmx->id, FEC_INPUT_CONTROL, 0);
+ }
+
+ stb_enable(dvb);
+
+ {
+ int n;
+ unsigned long addr;
+ unsigned long base;
+ unsigned long grp_addr[SEC_BUF_GRP_COUNT];
+ int grp_len[SEC_BUF_GRP_COUNT];
+
+ if (!dmx->init)
+ return;
+
+ if (dmx->sec_pages) {
+ grp_len[0] = (1 << SEC_GRP_LEN_0) * 8;
+ grp_len[1] = (1 << SEC_GRP_LEN_1) * 8;
+ grp_len[2] = (1 << SEC_GRP_LEN_2) * 8;
+ grp_len[3] = (1 << SEC_GRP_LEN_3) * 8;
+
+ grp_addr[0] = virt_to_phys((void *)dmx->sec_pages);
+ grp_addr[1] = grp_addr[0] + grp_len[0];
+ grp_addr[2] = grp_addr[1] + grp_len[1];
+ grp_addr[3] = grp_addr[2] + grp_len[2];
+
+ base = grp_addr[0] & 0xFFFF0000;
+ DMX_WRITE_REG(dmx->id, SEC_BUFF_BASE, base >> 16);
+ DMX_WRITE_REG(dmx->id, SEC_BUFF_01_START,
+ (((grp_addr[0] - base) >> 8) << 16) |
+ ((grp_addr[1] - base) >> 8));
+ DMX_WRITE_REG(dmx->id, SEC_BUFF_23_START,
+ (((grp_addr[2] - base) >> 8) << 16) |
+ ((grp_addr[3] - base) >> 8));
+ DMX_WRITE_REG(dmx->id, SEC_BUFF_SIZE,
+ SEC_GRP_LEN_0 |
+ (SEC_GRP_LEN_1 << 4) |
+ (SEC_GRP_LEN_2 << 8) |
+ (SEC_GRP_LEN_3 << 12));
+ }
+#ifdef NO_SUB
+#ifndef SUB_PARSER
+ if (dmx->sub_pages) {
+ addr = virt_to_phys((void *)dmx->sub_pages);
+ DMX_WRITE_REG(dmx->id, SB_START, addr >> 12);
+ DMX_WRITE_REG(dmx->id, SB_LAST_ADDR,
+ (dmx->sub_buf_len >> 3) - 1);
+ }
+#endif
+#endif
+ if (dmx->pes_pages) {
+ addr = virt_to_phys((void *)dmx->pes_pages);
+ DMX_WRITE_REG(dmx->id, OB_START, addr >> 12);
+ DMX_WRITE_REG(dmx->id, OB_LAST_ADDR,
+ (dmx->pes_buf_len >> 3) - 1);
+ }
+
+ for (n = 0; n < CHANNEL_COUNT; n++) {
+ /*struct aml_channel *chan = &dmx->channel[n];*/
+
+ /*if (chan->used)*/
+ {
+#ifdef NO_SUB
+#ifdef SUB_PARSER
+ /*
+ check if subtitle channel was running,
+ the parser will be used in amstream also,
+ take care of the buff ptr.
+ */
+ u32 v = dmx_get_chan_target(dmx, n);
+ if (v != 0xFFFF &&
+ (v & (0x7 << PID_TYPE))
+ == (SUB_PACKET << PID_TYPE))
+ set_subtitle_pes_buffer(dmx);
+#endif
+#endif
+ {
+ u32 v = dmx_get_chan_target(dmx, n);
+ if (v != 0xFFFF &&
+ (v & (0x7 << PID_TYPE))
+ ==
+ (OTHER_PES_PACKET << PID_TYPE))
+ pes_off_pre[dmx->id] = 0;
+ }
+ dmx_set_chan_regs(dmx, n);
+ }
+ }
+
+ for (n = 0; n < FILTER_COUNT; n++) {
+ struct aml_filter *filter = &dmx->filter[n];
+
+ if (filter->used)
+ dmx_set_filter_regs(dmx, n);
+ }
+
+ for (n = 0; n < SEC_CNT_MAX; n++) {
+ dmx->sec_cnt[n] = 0;
+ dmx->sec_cnt_match[n] = 0;
+ dmx->sec_cnt_crc_fail[n] = 0;
+ }
+ dmx_enable(dmx);
+ dmx_smallsec_set(&dmx->smallsec,
+ dmx->smallsec.enable,
+ dmx->smallsec.bufsize,
+ 1);
+
+ dmx_timeout_set(&dmx->timeout,
+ dmx->timeout.enable,
+ dmx->timeout.timeout,
+ dmx->timeout.ch_disable,
+ dmx->timeout.match,
+ 1);
+ }
+
+ {
+ int id;
+
+ for (id = 0; id < DSC_DEV_COUNT; id++) {
+ struct aml_dsc *dsc = &dvb->dsc[id];
+ int n;
+
+ for (n = 0; n < DSC_COUNT; n++) {
+ int flag = 0;
+ struct aml_dsc_channel *ch = &dsc->channel[n];
+ /*if(ch->used)*/ {
+ ch->id = n;
+ ch->work_mode = -1;
+ dsc_get_pid(ch,&ch->pid);
+ if (ch->pid != 0x1fff && !ch->used) {
+ flag = 1;
+ ch->used = 1;
+ }
+ dsc_set_pid(ch, ch->pid);
+ if (flag)
+ ch->used = 0;
+ //dsc_set_keys(ch);
+ }
+ }
+ }
+ }
+#ifdef ENABLE_SEC_BUFF_WATCHDOG
+ if (reset_irq) {
+ /*mod_timer(&dvb->watchdog_timer,
+ *jiffies+msecs_to_jiffies(WATCHDOG_TIMER));
+ */
+ dvb->dmx_watchdog_disable[dmx->id] = 0;
+ }
+#endif
+ {
+ DMX_WRITE_REG(dmx->id, ASSIGN_PID_NUMBER, pcr_num);
+ DMX_WRITE_REG(dmx->id, PCR90K_CTL, pcr_regs);
+ }
+}
+
+void dmx_reset_dmx_id_hw_ex_unlock(struct aml_dvb *dvb, int id, int reset_irq)
+{
+ dmx_reset_dmx_hw_ex_unlock(dvb, &dvb->dmx[id], reset_irq);
+}
+
+void dmx_reset_dmx_hw_ex(struct aml_dvb *dvb, struct aml_dmx *dmx,
+ int reset_irq)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&dvb->slock, flags);
+ dmx_reset_dmx_hw_ex_unlock(dvb, dmx, reset_irq);
+ spin_unlock_irqrestore(&dvb->slock, flags);
+}
+
+void dmx_reset_dmx_id_hw_ex(struct aml_dvb *dvb, int id, int reset_irq)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+ dmx_reset_dmx_id_hw_ex_unlock(dvb, id, reset_irq);
+ spin_unlock_irqrestore(&dvb->slock, flags);
+}
+
+void dmx_reset_dmx_hw(struct aml_dvb *dvb, int id)
+{
+ dmx_reset_dmx_id_hw_ex(dvb, id, 1);
+}
+
+/*Allocate subtitle pes buffer*/
+#if 0
+static int alloc_subtitle_pes_buffer(struct aml_dmx *dmx)
+{
+ int start_ptr = 0;
+ struct stream_buf_s *sbuff = 0;
+ u32 phy_addr;
+
+ start_ptr = READ_MPEG_REG(PARSER_SUB_START_PTR);
+ if (start_ptr) {
+ WRITE_MPEG_REG(PARSER_SUB_RP, start_ptr);
+ goto exit;
+ }
+ sbuff = get_stream_buffer(BUF_TYPE_SUBTITLE);
+ if (sbuff) {
+ if (sbuff->flag & BUF_FLAG_IOMEM)
+ phy_addr = sbuff->buf_start;
+ else
+ phy_addr = virt_to_phys((void *)sbuff->buf_start);
+
+ WRITE_MPEG_REG(PARSER_SUB_RP, phy_addr);
+ WRITE_MPEG_REG(PARSER_SUB_START_PTR, phy_addr);
+ WRITE_MPEG_REG(PARSER_SUB_END_PTR,
+ phy_addr + sbuff->buf_size - 8);
+
+ pr_dbg("pes buff=:%x %x\n", phy_addr, sbuff->buf_size);
+ } else
+ pr_dbg("Error stream buffer\n");
+exit:
+ return 0;
+}
+#endif
+
+static int set_subtitle_pes_buffer(struct aml_dmx *dmx)
+{
+#ifdef SUB_PARSER
+ if (dmx->sub_chan == -1) {
+ unsigned long addr = virt_to_phys((void *)dmx->sub_pages);
+ WRITE_MPEG_REG(PARSER_SUB_RP, addr);
+ WRITE_MPEG_REG(PARSER_SUB_START_PTR, addr);
+ WRITE_MPEG_REG(PARSER_SUB_END_PTR, addr + dmx->sub_buf_len - 8);
+ pr_inf("set sub buff: (%d) %lx %x\n", dmx->id, addr, dmx->sub_buf_len);
+ }
+#endif
+ return 0;
+}
+
+int dmx_get_sub_buffer(unsigned long *base, unsigned long *virt)
+{
+#ifndef SUB_BUF_DMX
+ unsigned long s = READ_MPEG_REG(PARSER_SUB_START_PTR);
+ if (base)
+ *base = s;
+ if (virt)
+ *virt = (unsigned long)codec_mm_phys_to_virt(s);
+#endif
+ return 0;
+}
+
+int dmx_init_sub_buffer(struct aml_dmx *dmx, unsigned long base, unsigned long virt)
+{
+#ifndef SUB_BUF_DMX
+ dmx->sub_buf_base = base;
+ pr_inf("sub buf base: 0x%lx\n", dmx->sub_buf_base);
+
+ dmx->sub_buf_base_virt = (u8 *)virt;
+ pr_inf("sub buf base virt: 0x%p\n", dmx->sub_buf_base_virt);
+#endif
+ return 0;
+}
+
+static int check_dvr_for_raw_channel(struct aml_dmx *dmx, int ch)
+{
+ switch (ch) {
+ case 0:
+ case 1: return 1;
+ case 2: return dmx->sub_chan != -1 ? 1 : 0;
+ case 3: return dmx->pcr_chan != -1 ? 1 : 0;
+ default: return 0;
+ }
+ return 0;
+}
+
+/*Allocate a new channel*/
+int dmx_alloc_chan(struct aml_dmx *dmx, int type, int pes_type, int pid)
+{
+ int id = -1;
+ int ret;
+
+ if (type == DMX_TYPE_TS) {
+ switch (pes_type) {
+ case DMX_PES_VIDEO:
+ if (!dmx->channel[0].used)
+ id = 0;
+ break;
+ case DMX_PES_AUDIO:
+ if (!dmx->channel[1].used)
+ id = 1;
+ break;
+ case DMX_PES_SUBTITLE:
+ case DMX_PES_TELETEXT:
+ if (!dmx->channel[2].used)
+ id = 2;
+ //alloc_subtitle_pes_buffer(dmx);
+ set_subtitle_pes_buffer(dmx);
+ break;
+ case DMX_PES_PCR:
+ if (!dmx->channel[3].used)
+ id = 3;
+ break;
+ case DMX_PES_AUDIO3:
+ pes_off_pre[dmx->id] = 0;
+ {
+ int i;
+
+ for (i = SYS_CHAN_COUNT;
+ i < CHANNEL_COUNT; i++) {
+ if (!dmx->channel[i].used) {
+ id = i;
+ break;
+ }
+ }
+ }
+ break;
+ case DMX_PES_OTHER:
+ {
+ int i;
+
+ for (i = SYS_CHAN_COUNT;
+ i < CHANNEL_COUNT; i++) {
+ if (!dmx->channel[i].used) {
+ id = i;
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ int i;
+
+ for (i = SYS_CHAN_COUNT; i < CHANNEL_COUNT; i++) {
+ if (!dmx->channel[i].used) {
+ id = i;
+ break;
+ }
+ }
+ }
+
+ if (id == -1) {
+ pr_error("too many channels\n");
+ return -1;
+ }
+
+ pr_dbg("allocate channel(id:%d-%d PID:0x%x)\n", dmx->id, id, pid);
+
+ if (check_dvr_for_raw_channel(dmx, id)) {
+ ret = dmx_get_chan(dmx, pid);
+ if (ret >= 0 && DVR_FEED(dmx->channel[ret].feed)) {
+ pr_dbg("raw ch fix: dmx:%d: ch[%d(dvr)] -> ch[%d]\n",
+ dmx->id, ret, id);
+ dmx_remove_feed(dmx, dmx->channel[ret].feed);
+ dmx->channel[id].dvr_feed = dmx->channel[ret].feed;
+ dmx->channel[id].dvr_feed->priv = (void *)(long)id;
+ } else {
+ dmx->channel[id].dvr_feed = NULL;
+ }
+ }
+
+ dmx->channel[id].type = type;
+ dmx->channel[id].pes_type = pes_type;
+ dmx->channel[id].pid = pid;
+ dmx->channel[id].used = 1;
+ dmx->channel[id].filter_count = 0;
+
+ dmx_set_chan_regs(dmx, id);
+
+ /* If video/audio channel started,
+ * visit all channels with type:VIDEO_PACKET
+ * change them to type:RECORDER_STREAM
+ */
+ if (id == 0 || id == 1) {
+ int i;
+ for (i = SYS_CHAN_COUNT; i < CHANNEL_COUNT; i++) {
+ if (dmx->channel[i].used
+ && dmx->channel[i].pkt_type == VIDEO_PACKET)
+ dmx_set_chan_regs(dmx, i);
+ }
+ }
+
+ set_debug_dmx_chanpids(dmx->id, id, pid);
+
+ dmx->chan_count++;
+ dmx_enable(dmx);
+
+ return id;
+}
+
+/*Free a channel*/
+void dmx_free_chan(struct aml_dmx *dmx, int cid)
+{
+ pr_dbg("free channel(id:%d-%d PID:0x%x)\n", dmx->id, cid, dmx->channel[cid].pid);
+
+ dmx->channel[cid].used = 0;
+ dmx->channel[cid].pid = 0x1fff;
+ dmx_set_chan_regs(dmx, cid);
+
+ /* video/audio channel gone,
+ * RECORDER_STREAM channels depends on AV channel's existence
+ * setup one fake video channel,
+ * then other RECORDER_STREAM channels will be happy to run.
+ */
+ if (cid == 0 || cid == 1) {
+ int i;
+ struct aml_channel *pch;
+
+ for (i = SYS_CHAN_COUNT; i < CHANNEL_COUNT; i++) {
+ pch = &dmx->channel[i];
+
+ if (pch->used) {
+ if (pch->pkt_type == RECORDER_STREAM)
+ dmx_set_chan_regs(dmx, i);
+ }
+ }
+ }
+
+ if (cid == 2) {
+ u32 parser_sub_start_ptr;
+
+ parser_sub_start_ptr = READ_MPEG_REG(PARSER_SUB_START_PTR);
+ WRITE_MPEG_REG(PARSER_SUB_RP, parser_sub_start_ptr);
+ WRITE_MPEG_REG(PARSER_SUB_WP, parser_sub_start_ptr);
+ }
+
+ set_debug_dmx_chanpids(dmx->id, cid, -1);
+ dmx->chan_count--;
+ dmx_enable(dmx);
+
+ /*Special pes type channel, check its dvr feed */
+ if (check_dvr_for_raw_channel(dmx, cid)
+ && dmx->channel[cid].dvr_feed) {
+ /*start the dvr feed */
+ pr_dbg("raw ch fix: dmx:%d: ch[%d] -> ch[(dvr)]\n",
+ dmx->id, cid);
+ dmx_add_feed(dmx, dmx->channel[cid].dvr_feed);
+ dmx->channel[cid].dvr_feed = NULL;
+ }
+}
+
+/*Add a section*/
+static int dmx_chan_add_filter(struct aml_dmx *dmx, int cid,
+ struct dvb_demux_filter *filter)
+{
+ int id = -1;
+ int i;
+
+ for (i = 0; i < FILTER_COUNT; i++) {
+ if (!dmx->filter[i].used) {
+ id = i;
+ break;
+ }
+ }
+
+ if (id == -1) {
+ pr_error("too many filters\n");
+ return -1;
+ }
+
+ pr_dbg("channel(id:%d PID:0x%x) add filter(id:%d)\n", cid,
+ filter->feed->pid, id);
+
+ dmx->filter[id].chan_id = cid;
+ dmx->filter[id].used = 1;
+ dmx->filter[id].filter = (struct dmx_section_filter *)filter;
+ dmx->channel[cid].filter_count++;
+
+ dmx_set_filter_regs(dmx, id);
+
+ return id;
+}
+
+static void dmx_remove_filter(struct aml_dmx *dmx, int cid, int fid)
+{
+ pr_dbg("channel(id:%d PID:0x%x) remove filter(id:%d)\n", cid,
+ dmx->channel[cid].pid, fid);
+
+ dmx->filter[fid].used = 0;
+ dmx->channel[cid].filter_count--;
+
+ dmx_set_filter_regs(dmx, fid);
+ dmx_clear_filter_buffer(dmx, fid);
+}
+
+static int sf_add_feed(struct aml_dmx *src_dmx, struct dvb_demux_feed *feed)
+{
+ int ret = 0;
+
+ struct aml_dvb *dvb = (struct aml_dvb *)src_dmx->demux.priv;
+ struct aml_swfilter *sf = &dvb->swfilter;
+
+ pr_dbg_sf("sf add pid[%d]\n", feed->pid);
+
+ /*init sf */
+ if (!sf->user) {
+ void *mem;
+
+ mem = vmalloc(SF_BUFFER_SIZE);
+ if (!mem) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+ dvb_ringbuffer_init(&sf->rbuf, mem, SF_BUFFER_SIZE);
+
+ sf->dmx = &dvb->dmx[SF_DMX_ID];
+ sf->afifo = &dvb->asyncfifo[SF_AFIFO_ID];
+
+ sf->dmx->source = src_dmx->source;
+ sf->afifo->source = sf->dmx->id;
+ sf->track_dmx = src_dmx->id;
+ /*sf->afifo->flush_size = 188*10; */
+
+ pr_dbg_sf("init sf mode.\n");
+
+ } else if (sf->dmx->source != src_dmx->source) {
+ pr_error(" pid=%d[src:%d] already used with sfdmx%d[src:%d]\n",
+ feed->pid, src_dmx->source, sf->dmx->id,
+ sf->dmx->source);
+ ret = -EBUSY;
+ goto fail;
+ }
+
+ /*setup feed */
+ ret = dmx_get_chan(sf->dmx, feed->pid);
+ if (ret >= 0) {
+ pr_error(" pid=%d[dmx:%d] already used [dmx:%d].\n",
+ feed->pid, src_dmx->id,
+ ((struct aml_dmx *)sf->dmx->channel[ret].feed->
+ demux)->id);
+ ret = -EBUSY;
+ goto fail;
+ }
+ ret =
+ dmx_alloc_chan(sf->dmx, DMX_TYPE_TS, DMX_PES_OTHER,
+ feed->pid);
+ if (ret < 0) {
+ pr_error(" %s: alloc chan error, ret=%d\n", __func__, ret);
+ ret = -EBUSY;
+ goto fail;
+ }
+ sf->dmx->channel[ret].feed = feed;
+ feed->priv = (void *)(long)ret;
+
+ sf->dmx->channel[ret].dvr_feed = feed;
+
+ sf->user++;
+ debug_sf_user = sf->user;
+ dmx_enable(sf->dmx);
+
+ return 0;
+
+fail:
+ feed->priv = (void *)-1;
+ return ret;
+}
+
+static int sf_remove_feed(struct aml_dmx *src_dmx, struct dvb_demux_feed *feed)
+{
+ int ret;
+
+ struct aml_dvb *dvb = (struct aml_dvb *)src_dmx->demux.priv;
+ struct aml_swfilter *sf = &dvb->swfilter;
+
+ if (!sf->user || (sf->dmx->source != src_dmx->source))
+ return 0;
+
+ /*add fail, no need to remove*/
+ if (((long)feed->priv) < 0)
+ return 0;
+
+ ret = dmx_get_chan(sf->dmx, feed->pid);
+ if (ret < 0)
+ return 0;
+
+ pr_dbg_sf("sf remove pid[%d]\n", feed->pid);
+
+ dmx_free_chan(sf->dmx, (long)feed->priv);
+
+ sf->dmx->channel[ret].feed = NULL;
+ sf->dmx->channel[ret].dvr_feed = NULL;
+
+ sf->user--;
+ debug_sf_user = sf->user;
+
+ if (!sf->user) {
+ sf->dmx->source = -1;
+ sf->afifo->source = AM_DMX_MAX;
+ sf->track_dmx = -1;
+ /*sf->afifo->flush_size = sf->afifo->buf_len>>1; */
+
+ if (sf->rbuf.data) {
+ void *mem = sf->rbuf.data;
+
+ sf->rbuf.data = NULL;
+ vfree(mem);
+ }
+ pr_dbg_sf("exit sf mode.\n");
+ }
+
+ return 0;
+}
+
+static int sf_feed_sf(struct aml_dmx *dmx, struct dvb_demux_feed *feed,
+ int add_not_remove)
+{
+ int sf = 0;
+
+ if (sf_dmx_sf(dmx)) {
+ pr_error("%s: demux %d is in sf mode\n", __func__, dmx->id);
+ return -EINVAL;
+ }
+
+ switch (feed->type) {
+ case DMX_TYPE_TS:{
+ struct dmxdev_filter *dmxdevfilter =
+ feed->feed.ts.priv;
+ if (!DVR_FEED(feed)) {
+ if (dmxdevfilter->params.pes.
+ flags & DMX_USE_SWFILTER)
+ sf = 1;
+ if (force_pes_sf)
+ sf = 1;
+ }
+ }
+ break;
+
+ case DMX_TYPE_SEC:{
+ struct dvb_demux_filter *filter;
+
+ for (filter = feed->filter; filter;
+ filter = filter->next) {
+ struct dmxdev_filter *dmxdevfilter =
+ filter->filter.priv;
+ if (dmxdevfilter->params.sec.
+ flags & DMX_USE_SWFILTER)
+ sf = 1;
+ if (add_not_remove)
+ filter->hw_handle = (u16)-1;
+ }
+ if (force_sec_sf)
+ sf = 1;
+ }
+ break;
+ }
+
+ return sf ? 0 : 1;
+}
+
+static int sf_check_feed(struct aml_dmx *dmx, struct dvb_demux_feed *feed,
+ int add_not_remove)
+{
+ int ret = 0;
+
+ ret = sf_feed_sf(dmx, feed, add_not_remove);
+ if (ret)
+ return ret;
+
+ pr_dbg_sf("%s [pid:%d] %s\n",
+ (feed->type == DMX_TYPE_TS) ? "DMX_TYPE_TS" : "DMX_TYPE_SEC",
+ feed->pid, add_not_remove ? "-> sf mode" : "sf mode ->");
+
+ if (add_not_remove)
+ ret = sf_add_feed(dmx, feed);
+ else
+ ret = sf_remove_feed(dmx, feed);
+
+ if (ret < 0) {
+ pr_error("sf %s feed fail[%d]\n",
+ add_not_remove ? "add" : "remove", ret);
+ }
+ return ret;
+}
+
+static int dmx_add_feed(struct aml_dmx *dmx, struct dvb_demux_feed *feed)
+{
+ int id, ret = 0;
+ struct dvb_demux_filter *filter;
+ struct dvb_demux_feed *dfeed = NULL;
+ int sf_ret = 0; /*<0:error, =0:sf_on, >0:sf_off */
+
+ sf_ret = sf_check_feed(dmx, feed, 1/*SF_FEED_OP_ADD */);
+ if (sf_ret < 0)
+ return sf_ret;
+
+ switch (feed->type) {
+ case DMX_TYPE_TS:
+ pr_dbg("add feed ts: pid:%d-0x%x, (%p)\n",
+ dmx->id, feed->pid, feed);
+ ret = dmx_get_chan(dmx, feed->pid);
+ if (ret >= 0) {
+ if (DVR_FEED(dmx->channel[ret].feed)) {
+ if (DVR_FEED(feed)) {
+ /*dvr feed already work */
+ pr_error("PID %d already used(DVR)\n",
+ feed->pid);
+ ret = -EBUSY;
+ goto fail;
+ }
+ if (sf_ret) {
+ /*if sf_on, we do not reset the
+ *previous dvr feed, just load the pes
+ *feed on the sf, a diffrent data path.
+ */
+ dfeed = dmx->channel[ret].feed;
+ dmx_remove_feed(dmx, dfeed);
+ }
+ } else {
+ if (DVR_FEED(feed)
+ && (!dmx->channel[ret].dvr_feed)) {
+ /*just store the dvr_feed */
+ dmx->channel[ret].dvr_feed = feed;
+ feed->priv = (void *)(long)ret;
+ if (!dmx->record)
+ dmx_enable(dmx);
+ dmx_add_recchan(dmx->id, ret);
+ return 0;
+ }
+ {
+ pr_error("PID %d already used\n",
+ feed->pid);
+ ret = -EBUSY;
+ goto fail;
+ }
+ }
+ }
+
+ if (sf_ret) { /*not sf feed. */
+ ret =
+ dmx_alloc_chan(dmx, feed->type,
+ feed->pes_type, feed->pid);
+ if (ret < 0) {
+ pr_dbg("%s: alloc chan error, ret=%d\n",
+ __func__, ret);
+ ret = -EBUSY;
+ goto fail;
+ }
+ dmx->channel[ret].feed = feed;
+ feed->priv = (void *)(long)ret;
+ dmx->channel[ret].dvr_feed = NULL;
+ }
+ /*dvr */
+ if (DVR_FEED(feed)) {
+ dmx->channel[ret].dvr_feed = feed;
+ feed->priv = (void *)(long)ret;
+ if (!dmx->record)
+ dmx_enable(dmx);
+ dmx_add_recchan(dmx->id, ret);
+ } else if (dfeed && sf_ret) {
+ dmx->channel[ret].dvr_feed = dfeed;
+ dfeed->priv = (void *)(long)ret;
+ if (!dmx->record)
+ dmx_enable(dmx);
+ dmx_add_recchan(dmx->id, ret);
+ }
+
+ break;
+ case DMX_TYPE_SEC:
+ pr_dbg("add feed sec: pid:%d-0x%x, (%p)\n",
+ dmx->id, feed->pid, feed);
+ ret = dmx_get_chan(dmx, feed->pid);
+ if (ret >= 0) {
+ if (DVR_FEED(dmx->channel[ret].feed)) {
+ if (sf_ret) {
+ /*if sf_on, we do not reset the
+ *previous dvr feed, just load the pes
+ *feed on the sf,a diffrent data path.
+ */
+ dfeed = dmx->channel[ret].feed;
+ dmx_remove_feed(dmx, dfeed);
+ }
+ } else {
+ pr_error("PID %d already used\n", feed->pid);
+ ret = -EBUSY;
+ goto fail;
+ }
+ }
+ if (sf_ret) { /*not sf feed. */
+ id = dmx_alloc_chan(dmx, feed->type,
+ feed->pes_type, feed->pid);
+ if (id < 0) {
+ pr_dbg("%s: alloc chan error, ret=%d\n",
+ __func__, id);
+ ret = -EBUSY;
+ goto fail;
+ }
+ for (filter = feed->filter; filter;
+ filter = filter->next) {
+ ret = dmx_chan_add_filter(dmx, id, filter);
+ if (ret >= 0)
+ filter->hw_handle = ret;
+ else
+ filter->hw_handle = (u16)-1;
+ }
+ dmx->channel[id].feed = feed;
+ feed->priv = (void *)(long)id;
+ dmx->channel[id].dvr_feed = NULL;
+
+ if (dfeed) {
+ dmx->channel[id].dvr_feed = dfeed;
+ dfeed->priv = (void *)(long)id;
+ if (!dmx->record)
+ dmx_enable(dmx);
+ dmx_add_recchan(dmx->id, id);
+ }
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dmx->feed_count++;
+
+ return 0;
+
+fail:
+ feed->priv = (void *)-1;
+ return ret;
+}
+
+static int dmx_remove_feed(struct aml_dmx *dmx, struct dvb_demux_feed *feed)
+{
+ struct dvb_demux_filter *filter;
+ struct dvb_demux_feed *dfeed = NULL;
+
+ int sf_ret = 0; /*<0:error, =0:sf_on, >0:sf_off */
+
+ /*add fail, no need to remove*/
+ if (((long)feed->priv) < 0)
+ return 0;
+
+ sf_ret = sf_check_feed(dmx, feed, 0/*SF_FEED_OP_RM */);
+ if (sf_ret <= 0)
+ return sf_ret;
+
+ switch (feed->type) {
+ case DMX_TYPE_TS:
+ pr_dbg("rm feed ts: pid:%d-0x%x, %p\n",
+ dmx->id, feed->pid, feed);
+ if (dmx->channel[(long)feed->priv].feed ==
+ dmx->channel[(long)feed->priv].dvr_feed) {
+ dmx_rm_recchan(dmx->id, (long)feed->priv);
+ dmx_free_chan(dmx, (long)feed->priv);
+ } else {
+ if (feed == dmx->channel[(long)feed->priv].feed) {
+ dfeed = dmx->channel[(long)feed->priv].dvr_feed;
+ dmx_rm_recchan(dmx->id, (long)feed->priv);
+ dmx_free_chan(dmx, (long)feed->priv);
+ if (dfeed) {
+ /*start the dvr feed */
+ dmx_add_feed(dmx, dfeed);
+ }
+ } else if (feed ==
+ dmx->channel[(long)feed->priv].dvr_feed) {
+ /*just remove the dvr_feed */
+ dmx->channel[(long)feed->priv].dvr_feed = NULL;
+ dmx_rm_recchan(dmx->id, (long)feed->priv);
+ if (dmx->record)
+ dmx_enable(dmx);
+ } else {
+ /*This must never happen */
+ pr_error("%s: unknown feed\n", __func__);
+ return -EINVAL;
+ }
+ }
+
+ break;
+ case DMX_TYPE_SEC:
+ pr_dbg("rm feed sec: pid:%d-0x%x, %p\n",
+ dmx->id, feed->pid, feed);
+ for (filter = feed->filter; filter; filter = filter->next) {
+ if (filter->hw_handle != (u16)-1)
+ dmx_remove_filter(dmx, (long)feed->priv,
+ (int)filter->hw_handle);
+ }
+
+ dfeed = dmx->channel[(long)feed->priv].dvr_feed;
+ dmx_rm_recchan(dmx->id, (long)feed->priv);
+ dmx_free_chan(dmx, (long)feed->priv);
+ if (dfeed) {
+ /*start the dvr feed */
+ dmx_add_feed(dmx, dfeed);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dmx->feed_count--;
+ return 0;
+}
+
+int aml_dmx_hw_init(struct aml_dmx *dmx)
+{
+ /*
+ *struct aml_dvb *dvb = (struct aml_dvb *)dmx->demux.priv;
+ *unsigned long flags;
+ */
+ int ret;
+
+ /*Demux initialize */
+ /*spin_lock_irqsave(&dvb->slock, flags);*/
+ ret = dmx_init(dmx);
+ /*spin_unlock_irqrestore(&dvb->slock, flags);*/
+
+ return ret;
+}
+
+int aml_dmx_hw_deinit(struct aml_dmx *dmx)
+{
+ struct aml_dvb *dvb = (struct aml_dvb *)dmx->demux.priv;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+ ret = dmx_deinit(dmx);
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return ret;
+}
+
+/*extern void afifo_reset(int v);*/
+
+int aml_asyncfifo_hw_init(struct aml_asyncfifo *afifo)
+{
+
+/*
+ * struct aml_dvb *dvb = afifo->dvb;
+ * unsigned long flags;
+ */
+ int ret;
+
+ int len = asyncfifo_buf_len;
+ unsigned long buf = asyncfifo_alloc_buffer(afifo, len);
+
+ if (!buf)
+ return -1;
+
+ /*Async FIFO initialize*/
+/*
+ * spin_lock_irqsave(&dvb->slock, flags);
+ */
+/*
+ *#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8
+ * CLK_GATE_ON(ASYNC_FIFO);
+ *#endif
+ */
+ /*afifo_reset(0);*/
+
+ WRITE_MPEG_REG(RESET6_REGISTER, (1<<11)|(1<<12));
+
+ ret = async_fifo_init(afifo, 1, len, buf);
+/*
+ * spin_unlock_irqrestore(&dvb->slock, flags);
+ */
+ if (ret < 0)
+ asyncfifo_free_buffer(buf, len);
+
+ return ret;
+}
+
+int aml_asyncfifo_hw_deinit(struct aml_asyncfifo *afifo)
+{
+ int ret;
+
+ ret = async_fifo_deinit(afifo, 1);
+/*
+ *#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8
+ * CLK_GATE_OFF(ASYNC_FIFO);
+ *#endif
+ */
+ /*afifo_reset(1);*/
+
+ return ret;
+}
+
+int aml_asyncfifo_hw_reset(struct aml_asyncfifo *afifo)
+{
+ struct aml_dvb *dvb = afifo->dvb;
+ unsigned long flags;
+ int ret, src = -1;
+
+ unsigned long buf = 0;
+ int len = asyncfifo_buf_len;
+ buf = asyncfifo_alloc_buffer(afifo, len);
+ if (!buf)
+ return -1;
+
+ if (afifo->init) {
+ src = afifo->source;
+ async_fifo_deinit(afifo, 0);
+ }
+
+ spin_lock_irqsave(&dvb->slock, flags);
+ ret = async_fifo_init(afifo, 0, len, buf);
+ /* restore the source */
+ if (src != -1)
+ afifo->source = src;
+
+ if ((ret == 0) && afifo->dvb)
+ reset_async_fifos(afifo->dvb);
+
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ if (ret < 0)
+ asyncfifo_free_buffer(buf, len);
+
+ return ret;
+}
+
+int aml_dmx_hw_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ struct aml_dmx *dmx = (struct aml_dmx *)dvbdmxfeed->demux;
+ struct aml_dvb *dvb = (struct aml_dvb *)dmx->demux.priv;
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+ ret = dmx_add_feed(dmx, dvbdmxfeed);
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ /*handle errors silently*/
+ if (ret != 0)
+ ret = 0;
+
+ return ret;
+}
+
+int aml_dmx_hw_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ struct aml_dmx *dmx = (struct aml_dmx *)dvbdmxfeed->demux;
+ struct aml_dvb *dvb = (struct aml_dvb *)dmx->demux.priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+ dmx_remove_feed(dmx, dvbdmxfeed);
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return 0;
+}
+
+int sf_dmx_track_source(struct aml_dmx *dmx)
+{
+ struct aml_dvb *dvb = (struct aml_dvb *)dmx->demux.priv;
+ struct aml_swfilter *sf = &dvb->swfilter;
+
+ if (sf->user && (dmx->id == sf->track_dmx)) {
+ pr_dbg_sf("tracking dmx src [%d -> %d]\n",
+ sf->dmx->source, dmx->source);
+ sf->dmx->source = dmx->source;
+ dmx_reset_dmx_hw_ex_unlock(dvb, sf->dmx, 0);
+ }
+ return 0;
+}
+
+int aml_dmx_hw_set_source(struct dmx_demux *demux, dmx_source_t src)
+{
+ struct aml_dmx *dmx = (struct aml_dmx *)demux;
+ struct aml_dvb *dvb = (struct aml_dvb *)dmx->demux.priv;
+ int ret = 0;
+ int hw_src;
+ unsigned long flags;
+
+ if (sf_dmx_sf(dmx)) {
+ pr_error("%s: demux %d is in sf mode\n", __func__, dmx->id);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&dvb->slock, flags);
+
+ hw_src = dmx->source;
+
+ switch (src) {
+ case DMX_SOURCE_FRONT0:
+ hw_src =
+ (dvb->ts[0].mode ==
+ AM_TS_SERIAL) ? (dvb->ts[0].s2p_id+AM_TS_SRC_S_TS0) : AM_TS_SRC_TS0;
+ break;
+ case DMX_SOURCE_FRONT1:
+ hw_src =
+ (dvb->ts[1].mode ==
+ AM_TS_SERIAL) ? (dvb->ts[1].s2p_id+AM_TS_SRC_S_TS0) : AM_TS_SRC_TS1;
+ break;
+ case DMX_SOURCE_FRONT2:
+ hw_src =
+ (dvb->ts[2].mode ==
+ AM_TS_SERIAL) ? (dvb->ts[2].s2p_id+AM_TS_SRC_S_TS0) : AM_TS_SRC_TS2;
+ break;
+ case DMX_SOURCE_FRONT3:
+ hw_src =
+ (dvb->ts[3].mode ==
+ AM_TS_SERIAL) ? (dvb->ts[3].s2p_id+AM_TS_SRC_S_TS0) : AM_TS_SRC_TS3;
+ break;
+ case DMX_SOURCE_DVR0:
+ hw_src = AM_TS_SRC_HIU;
+ break;
+ case DMX_SOURCE_DVR1:
+ hw_src = AM_TS_SRC_HIU1;
+ break;
+ case DMX_SOURCE_FRONT0_OFFSET:
+ hw_src = AM_TS_SRC_DMX0;
+ break;
+ case DMX_SOURCE_FRONT1_OFFSET:
+ hw_src = AM_TS_SRC_DMX1;
+ break;
+ case DMX_SOURCE_FRONT2_OFFSET:
+ hw_src = AM_TS_SRC_DMX2;
+ break;
+ default:
+ pr_error("illegal demux source %d\n", src);
+ ret = -EINVAL;
+ break;
+ }
+
+ if (hw_src != dmx->source) {
+ dmx->source = hw_src;
+ dmx_reset_dmx_hw_ex_unlock(dvb, dmx, 0);
+ sf_dmx_track_source(dmx);
+ }
+
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return ret;
+}
+
+#define IS_SRC_DMX(_src) ((_src) >= AM_TS_SRC_DMX0 && (_src) <= AM_TS_SRC_DMX2)
+
+int aml_stb_hw_set_source(struct aml_dvb *dvb, dmx_source_t src)
+{
+ unsigned long flags;
+ int hw_src;
+ int ret;
+
+ ret = 0;
+ spin_lock_irqsave(&dvb->slock, flags);
+
+ hw_src = dvb->stb_source;
+
+ switch (src) {
+ case DMX_SOURCE_FRONT0:
+ hw_src =
+ (dvb->ts[0].mode ==
+ AM_TS_SERIAL) ? (dvb->ts[0].s2p_id+AM_TS_SRC_S_TS0) : AM_TS_SRC_TS0;
+ break;
+ case DMX_SOURCE_FRONT1:
+ hw_src =
+ (dvb->ts[1].mode ==
+ AM_TS_SERIAL) ? (dvb->ts[1].s2p_id+AM_TS_SRC_S_TS0) : AM_TS_SRC_TS1;
+ break;
+ case DMX_SOURCE_FRONT2:
+ hw_src =
+ (dvb->ts[2].mode ==
+ AM_TS_SERIAL) ? (dvb->ts[2].s2p_id+AM_TS_SRC_S_TS0) : AM_TS_SRC_TS2;
+ break;
+ case DMX_SOURCE_FRONT3:
+ hw_src =
+ (dvb->ts[3].mode ==
+ AM_TS_SERIAL) ? (dvb->ts[3].s2p_id+AM_TS_SRC_S_TS0) : AM_TS_SRC_TS3;
+ break;
+ case DMX_SOURCE_DVR0:
+ hw_src = AM_TS_SRC_HIU;
+ break;
+ case DMX_SOURCE_DVR1:
+ hw_src = AM_TS_SRC_HIU1;
+ break;
+ case DMX_SOURCE_FRONT0_OFFSET:
+ hw_src = AM_TS_SRC_DMX0;
+ break;
+ case DMX_SOURCE_FRONT1_OFFSET:
+ hw_src = AM_TS_SRC_DMX1;
+ break;
+ case DMX_SOURCE_FRONT2_OFFSET:
+ hw_src = AM_TS_SRC_DMX2;
+ break;
+ default:
+ pr_error("illegal demux source %d\n", src);
+ ret = -EINVAL;
+ break;
+ }
+
+ if (dvb->stb_source != hw_src) {
+ int old_source = dvb->stb_source;
+
+ dvb->stb_source = hw_src;
+
+ if (IS_SRC_DMX(old_source)) {
+ dmx_set_misc_id(dvb,
+ (old_source - AM_TS_SRC_DMX0), 0, -1);
+ } else {
+ /*which dmx for av-play is unknown,
+ *can't avoid reset-all
+ */
+ dmx_reset_hw_ex(dvb, 0);
+ }
+
+ if (IS_SRC_DMX(dvb->stb_source)) {
+ dmx_set_misc_id(dvb,
+ (dvb->stb_source - AM_TS_SRC_DMX0), 1, -1);
+ /*dmx_reset_dmx_id_hw_ex_unlock
+ * (dvb, (dvb->stb_source-AM_TS_SRC_DMX0), 0);
+ */
+ } else {
+ /*which dmx for av-play is unknown,
+ *can't avoid reset-all
+ */
+ dmx_reset_hw_ex(dvb, 0);
+ }
+ }
+
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return ret;
+}
+
+
+
+int aml_dsc_hw_set_source(struct aml_dsc *dsc,
+ dmx_source_t src, dmx_source_t dst)
+{
+ struct aml_dvb *dvb = dsc->dvb;
+ int ret = 0;
+ unsigned long flags;
+ int hw_src = -1, hw_dst = -1, org_src = -1, org_dst = -1;
+ int src_reset = 0, dst_reset = 0;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+
+ hw_src = dsc->source;
+ hw_dst = dsc->dst;
+
+ switch (src) {
+ case DMX_SOURCE_FRONT0_OFFSET:
+ hw_src = AM_TS_SRC_DMX0;
+ break;
+ case DMX_SOURCE_FRONT1_OFFSET:
+ hw_src = AM_TS_SRC_DMX1;
+ break;
+ case DMX_SOURCE_FRONT2_OFFSET:
+ hw_src = AM_TS_SRC_DMX2;
+ break;
+ default:
+ hw_src = -1;
+ break;
+ }
+ switch (dst) {
+ case DMX_SOURCE_FRONT0_OFFSET:
+ hw_dst = AM_TS_SRC_DMX0;
+ break;
+ case DMX_SOURCE_FRONT1_OFFSET:
+ hw_dst = AM_TS_SRC_DMX1;
+ break;
+ case DMX_SOURCE_FRONT2_OFFSET:
+ hw_dst = AM_TS_SRC_DMX2;
+ break;
+ default:
+ hw_dst = -1;
+ break;
+ }
+
+ if (hw_src != dsc->source) {
+ org_src = dsc->source;
+ dsc->source = hw_src;
+ src_reset = 1;
+ }
+ if (hw_dst != dsc->dst) {
+ org_dst = dsc->dst;
+ dsc->dst = hw_dst;
+ dst_reset = 1;
+ }
+
+ if (src_reset) {
+ pr_inf("dsc%d source changed: %d -> %d\n",
+ dsc->id, org_src, hw_src);
+ if (org_src != -1) {
+ pr_inf("reset dmx%d\n", (org_src - AM_TS_SRC_DMX0));
+ dmx_reset_dmx_id_hw_ex_unlock(dvb,
+ (org_src - AM_TS_SRC_DMX0), 0);
+ }
+ if (hw_src != -1) {
+ pr_inf("reset dmx%d\n", (hw_src - AM_TS_SRC_DMX0));
+ dmx_reset_dmx_id_hw_ex_unlock(dvb,
+ (hw_src - AM_TS_SRC_DMX0), 0);
+ } else
+ dsc_enable(dsc, 0);
+ }
+ if (dst_reset) {
+ pr_inf("dsc%d dest changed: %d -> %d\n",
+ dsc->id, org_dst, hw_dst);
+ if (((!src_reset) && (org_dst != -1)) ||
+ (src_reset && (org_dst != -1) &&
+ (org_dst != org_src) && (org_dst != hw_src))) {
+ pr_inf("reset dmx%d\n", (org_dst - AM_TS_SRC_DMX0));
+ dmx_reset_dmx_id_hw_ex_unlock(dvb,
+ (org_dst - AM_TS_SRC_DMX0), 0);
+ }
+ if (((!src_reset) && (hw_dst != -1)) ||
+ (src_reset && (hw_dst != -1)
+ && (hw_dst != org_src) && (hw_dst != hw_src))) {
+ pr_inf("reset dmx%d\n", (hw_dst - AM_TS_SRC_DMX0));
+ dmx_reset_dmx_id_hw_ex_unlock(dvb,
+ (hw_dst - AM_TS_SRC_DMX0), 0);
+ }
+ if (hw_dst == -1)
+ dsc_enable(dsc, 0);
+ }
+ if (src_reset && dst_reset) {
+ set_ciplus_input_source(dsc);
+ }
+
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return ret;
+}
+
+int aml_tso_hw_set_source(struct aml_dvb *dvb, dmx_source_t src)
+{
+ int ret = 0;
+ unsigned long flags;
+ int hw_src;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+
+ hw_src = dvb->tso_source;
+
+ switch (src) {
+ case DMX_SOURCE_FRONT0:
+ hw_src = (dvb->ts[0].mode == AM_TS_SERIAL)
+ ? (dvb->ts[0].s2p_id+AM_TS_SRC_S_TS0) : AM_TS_SRC_TS0;
+ break;
+ case DMX_SOURCE_FRONT1:
+ hw_src = (dvb->ts[1].mode == AM_TS_SERIAL)
+ ? (dvb->ts[1].s2p_id+AM_TS_SRC_S_TS0) : AM_TS_SRC_TS1;
+ break;
+ case DMX_SOURCE_FRONT2:
+ hw_src = (dvb->ts[2].mode == AM_TS_SERIAL)
+ ? (dvb->ts[2].s2p_id+AM_TS_SRC_S_TS0) : AM_TS_SRC_TS2;
+ break;
+ case DMX_SOURCE_FRONT3:
+ hw_src = (dvb->ts[3].mode == AM_TS_SERIAL)
+ ? (dvb->ts[3].s2p_id+AM_TS_SRC_S_TS0) : AM_TS_SRC_TS3;
+ break;
+ case DMX_SOURCE_DVR0:
+ hw_src = AM_TS_SRC_HIU;
+ break;
+ case DMX_SOURCE_FRONT0 + 100:
+ hw_src = AM_TS_SRC_DMX0;
+ break;
+ case DMX_SOURCE_FRONT1 + 100:
+ hw_src = AM_TS_SRC_DMX1;
+ break;
+ case DMX_SOURCE_FRONT2 + 100:
+ hw_src = AM_TS_SRC_DMX2;
+ break;
+ default:
+ hw_src = -1;
+ ret = -EINVAL;
+ break;
+ }
+
+ if (hw_src != dvb->tso_source) {
+ dvb->tso_source = hw_src;
+ stb_enable(dvb);
+ }
+
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return ret;
+}
+
+int aml_asyncfifo_hw_set_source(struct aml_asyncfifo *afifo,
+ enum aml_dmx_id_t src)
+{
+ struct aml_dvb *dvb = afifo->dvb;
+ int ret = -1;
+ unsigned long flags;
+
+ if (sf_afifo_sf(afifo)) {
+ pr_error("%s: afifo %d is in sf mode\n", __func__, afifo->id);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&dvb->slock, flags);
+
+ pr_dbg("asyncfifo %d set source %d->%d",
+ afifo->id, afifo->source, src);
+ switch (src) {
+ case AM_DMX_0:
+ case AM_DMX_1:
+ case AM_DMX_2:
+ if (afifo->source != src) {
+ afifo->source = src;
+ ret = 0;
+ }
+ break;
+ default:
+ pr_error("illegal async fifo source %d\n", src);
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret == 0 && afifo->dvb)
+ reset_async_fifos(afifo->dvb);
+
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return ret;
+}
+
+int aml_dmx_hw_set_dump_ts_select(struct dmx_demux *demux, int dump_ts_select)
+{
+ struct aml_dmx *dmx = (struct aml_dmx *)demux;
+ struct aml_dvb *dvb = (struct aml_dvb *)dmx->demux.priv;
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+ dump_ts_select = !!dump_ts_select;
+ if (dmx->dump_ts_select != dump_ts_select) {
+ dmx->dump_ts_select = dump_ts_select;
+ dmx_reset_dmx_hw_ex_unlock(dvb, dmx, 0);
+ }
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return ret;
+}
+
+u32 aml_dmx_get_video_pts(struct aml_dvb *dvb)
+{
+ unsigned long flags;
+ u32 pts;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+ pts = video_pts;
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return pts;
+}
+
+u32 aml_dmx_get_audio_pts(struct aml_dvb *dvb)
+{
+ unsigned long flags;
+ u32 pts;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+ pts = audio_pts;
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return pts;
+}
+
+u32 aml_dmx_get_video_pts_bit32(struct aml_dvb *dvb)
+{
+ unsigned long flags;
+ u32 bit32;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+ bit32 = video_pts_bit32;
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return bit32;
+}
+
+u32 aml_dmx_get_audio_pts_bit32(struct aml_dvb *dvb)
+{
+ unsigned long flags;
+ u32 bit32;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+ bit32 = audio_pts_bit32;
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return bit32;
+}
+u32 aml_dmx_get_first_video_pts(struct aml_dvb *dvb)
+{
+ unsigned long flags;
+ u32 pts;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+ pts = first_video_pts;
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return pts;
+}
+
+u32 aml_dmx_get_first_audio_pts(struct aml_dvb *dvb)
+{
+ unsigned long flags;
+ u32 pts;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+ pts = first_audio_pts;
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return pts;
+}
+
+int aml_dmx_set_skipbyte(struct aml_dvb *dvb, int skipbyte)
+{
+ if (demux_skipbyte != skipbyte) {
+ pr_dbg("set skip byte %d\n", skipbyte);
+ demux_skipbyte = skipbyte;
+ dmx_reset_hw_ex(dvb, 0);
+ }
+
+ return 0;
+}
+
+int aml_dmx_set_demux(struct aml_dvb *dvb, int id)
+{
+ aml_stb_hw_set_source(dvb, DMX_SOURCE_DVR0);
+ if (id < DMX_DEV_COUNT) {
+ struct aml_dmx *dmx = &dvb->dmx[id];
+
+ aml_dmx_hw_set_source((struct dmx_demux *)dmx,
+ DMX_SOURCE_DVR0);
+ }
+
+ return 0;
+}
+
+int _set_tsfile_clkdiv(struct aml_dvb *dvb, int clkdiv)
+{
+ if (tsfile_clkdiv != clkdiv) {
+ pr_dbg("set ts file clock div %d\n", clkdiv);
+ tsfile_clkdiv = clkdiv;
+ dmx_reset_hw(dvb);
+ }
+
+ return 0;
+}
+
+static ssize_t stb_set_tsfile_clkdiv(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ /*int div = (int)simple_strtol(buf, NULL, 10);*/
+ long div;
+
+ if (kstrtol(buf, 0, &div) == 0)
+ _set_tsfile_clkdiv(aml_get_dvb_device(), (int)div);
+ return size;
+}
+
+static ssize_t stb_get_tsfile_clkdiv(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ ssize_t ret;
+
+ ret = sprintf(buf, "%d\n", tsfile_clkdiv);
+ return ret;
+}
+
+
+static int dmx_id;
+
+static ssize_t dmx_smallsec_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ ssize_t ret;
+ struct aml_dvb *dvb = aml_get_dvb_device();
+
+ ret = sprintf(buf, "%d:%d\n", dvb->dmx[dmx_id].smallsec.enable,
+ dvb->dmx[dmx_id].smallsec.bufsize);
+ return ret;
+}
+static ssize_t dmx_smallsec_store(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ int i, e, s = 0, f = 0;
+ struct aml_dvb *dvb = aml_get_dvb_device();
+
+ i = sscanf(buf, "%d:%i:%d", &e, &s, &f);
+ if (i <= 0)
+ return size;
+
+ dmx_smallsec_set(&dvb->dmx[dmx_id].smallsec, e, s, f);
+ return size;
+}
+
+static ssize_t dmx_timeout_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ ssize_t ret;
+ struct aml_dvb *dvb = aml_get_dvb_device();
+
+ ret = sprintf(buf, "%d:%d:0x%x:%d:%d\n",
+ dvb->dmx[dmx_id].timeout.enable,
+ dvb->dmx[dmx_id].timeout.timeout,
+ dvb->dmx[dmx_id].timeout.ch_disable,
+ dvb->dmx[dmx_id].timeout.match,
+ (DMX_READ_REG(dmx_id, STB_INT_STATUS)&(1<<INPUT_TIME_OUT)) ?
+ 1 : 0);
+ DMX_WRITE_REG(dmx_id, STB_INT_STATUS, (1<<INPUT_TIME_OUT));
+ return ret;
+}
+static ssize_t dmx_timeout_store(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ int i, e, t = 0, c = 0, m = 0, f = 0;
+ struct aml_dvb *dvb = aml_get_dvb_device();
+
+ i = sscanf(buf, "%d:%i:%i:%d:%d", &e, &t, &c, &m, &f);
+ if (i <= 0)
+ return size;
+
+ dmx_timeout_set(&dvb->dmx[dmx_id].timeout, e, t, c, m, f);
+ return size;
+}
+
+
+#define DEMUX_SCAMBLE_FUNC_DECL(i) \
+static ssize_t dmx_reg_value_show_demux##i##_scramble(struct class *class, \
+struct class_attribute *attr, char *buf)\
+{\
+ int data = 0;\
+ int aflag = 0;\
+ int vflag = 0;\
+ ssize_t ret = 0;\
+ data = DMX_READ_REG(i, DEMUX_SCRAMBLING_STATE);\
+ if ((data & 0x01) == 0x01) \
+ vflag = 1;\
+ if ((data & 0x02) == 0x02) \
+ aflag = 1;\
+ ret = sprintf(buf, "%d %d\n", vflag, aflag);\
+ return ret;\
+}
+
+#if DMX_DEV_COUNT > 0
+DEMUX_SCAMBLE_FUNC_DECL(0)
+#endif
+#if DMX_DEV_COUNT > 1
+DEMUX_SCAMBLE_FUNC_DECL(1)
+#endif
+#if DMX_DEV_COUNT > 2
+DEMUX_SCAMBLE_FUNC_DECL(2)
+#endif
+static ssize_t ciplus_output_ctrl_show(struct class *class,
+ struct class_attribute *attr,
+ char *buf)
+{
+ int ret;
+ char *out = "none";
+
+ pr_inf("output demux use 3 bit to indicate.\n");
+ pr_inf("1bit:demux0 2bit:demux1 3bit:demux2\n");
+
+ switch (ciplus_out_sel) {
+ case 1:
+ out = "dmx0";
+ break;
+ case 2:
+ out = "dmx1";
+ break;
+ case 4:
+ out = "dmx2";
+ break;
+ default:
+ break;
+ }
+
+ ret = sprintf(buf, "%s 0x%x %s\n",
+ out,
+ ciplus_out_sel,
+ (ciplus_out_auto_mode) ? "" : "(force)");
+ return ret;
+}
+
+static ssize_t ciplus_output_ctrl_store(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ int i, tmp;
+
+ i = kstrtoint(buf, -1, &tmp);
+ if (tmp > 8 || tmp < 0)
+ pr_error("Invalid output set\n");
+ else if (tmp == 8) {
+ ciplus_out_auto_mode = 1;
+ ciplus_out_sel = -1;
+ pr_error("Auto set output mode enable\n");
+ } else {
+ ciplus_out_auto_mode = 0;
+ ciplus_out_sel = tmp;
+ pr_error("Auto set output mode disable\n");
+ }
+ return size;
+}
+static ssize_t reset_fec_input_ctrl_show(struct class *class,
+ struct class_attribute *attr,
+ char *buf)
+{
+ return 0;
+}
+
+static ssize_t reset_fec_input_ctrl_store(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ u32 v;
+
+ v = READ_MPEG_REG(FEC_INPUT_CONTROL);
+ v &= ~(1<<11);
+ WRITE_MPEG_REG(FEC_INPUT_CONTROL, v);
+
+ pr_dbg("reset FEC_INPUT_CONTROL to %x\n", v);
+
+ return size;
+}
+static ssize_t dmx_reg_addr_show_source(struct class *class,
+ struct class_attribute *attr,
+ char *buf);
+static ssize_t dmx_reg_addr_store_source(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size);
+static ssize_t dmx_id_show_source(struct class *class,
+ struct class_attribute *attr, char *buf);
+static ssize_t dmx_id_store_source(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size);
+static ssize_t dmx_reg_value_show_source(struct class *class,
+ struct class_attribute *attr,
+ char *buf);
+static ssize_t dmx_reg_value_store_source(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size);
+static ssize_t dmx_sec_statistics_show(struct class *class,
+ struct class_attribute *attr,
+ char *buf);
+static int reg_addr;
+
+static struct class_attribute aml_dmx_class_attrs[] = {
+ __ATTR(dmx_id, 0644, dmx_id_show_source,
+ dmx_id_store_source),
+ __ATTR(register_addr, 0644, dmx_reg_addr_show_source,
+ dmx_reg_addr_store_source),
+ __ATTR(register_value, 0644, dmx_reg_value_show_source,
+ dmx_reg_value_store_source),
+ __ATTR(tsfile_clkdiv, 0644, stb_get_tsfile_clkdiv,
+ stb_set_tsfile_clkdiv),
+
+#define DEMUX_SCAMBLE_ATTR_DECL(i)\
+ __ATTR(demux##i##_scramble, 0644, \
+ dmx_reg_value_show_demux##i##_scramble, NULL)
+#if DMX_DEV_COUNT > 0
+ DEMUX_SCAMBLE_ATTR_DECL(0),
+#endif
+#if DMX_DEV_COUNT > 1
+ DEMUX_SCAMBLE_ATTR_DECL(1),
+#endif
+#if DMX_DEV_COUNT > 2
+ DEMUX_SCAMBLE_ATTR_DECL(2),
+#endif
+
+ __ATTR(dmx_smallsec, 0644,
+ dmx_smallsec_show,
+ dmx_smallsec_store),
+ __ATTR(dmx_timeout, 0644,
+ dmx_timeout_show,
+ dmx_timeout_store),
+ __ATTR(reset_fec_input_ctrl, 0644,
+ reset_fec_input_ctrl_show,
+ reset_fec_input_ctrl_store),
+ __ATTR(ciplus_output_ctrl, 0644,
+ ciplus_output_ctrl_show,
+ ciplus_output_ctrl_store),
+ __ATTR_RO(dmx_sec_statistics),
+ __ATTR_NULL
+};
+
+static struct class aml_dmx_class = {
+ .name = "dmx",
+ .class_attrs = aml_dmx_class_attrs,
+};
+
+static ssize_t dmx_id_show_source(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ int ret;
+
+ ret = sprintf(buf, "%d\n", dmx_id);
+ return ret;
+}
+
+static ssize_t dmx_id_store_source(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ int id = 0;
+ long value = 0;
+
+ if (kstrtol(buf, 0, &value) == 0)
+ id = (int)value;
+ /*id = simple_strtol(buf, 0, 16);*/
+
+ if (id < 0 || id > 2)
+ pr_dbg("dmx id must 0 ~2\n");
+ else
+ dmx_id = id;
+
+ return size;
+}
+
+static ssize_t dmx_reg_addr_show_source(struct class *class,
+ struct class_attribute *attr,
+ char *buf)
+{
+ int ret;
+
+ ret = sprintf(buf, "%x\n", reg_addr);
+ return ret;
+}
+
+static ssize_t dmx_reg_addr_store_source(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ int addr = 0;
+ /*addr = simple_strtol(buf, 0, 16);*/
+ long value = 0;
+
+ if (kstrtol(buf, 0, &value) == 0)
+ addr = (int)value;
+ reg_addr = addr;
+ return size;
+}
+
+static ssize_t dmx_reg_value_show_source(struct class *class,
+ struct class_attribute *attr,
+ char *buf)
+{
+ int ret, value;
+
+ value = READ_MPEG_REG(reg_addr);
+ ret = sprintf(buf, "%x\n", value);
+ return ret;
+}
+
+static ssize_t dmx_reg_value_store_source(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ int value = 0;
+ /*value = simple_strtol(buf, 0, 16);*/
+ long val = 0;
+
+ if (kstrtol(buf, 0, &val) == 0)
+ value = (int)val;
+ WRITE_MPEG_REG(reg_addr, value);
+ return size;
+}
+
+static ssize_t dmx_sec_statistics_show(struct class *class,
+ struct class_attribute *attr,
+ char *buf)
+{
+ ssize_t ret;
+ char tmp[128];
+ struct aml_dvb *dvb = aml_get_dvb_device();
+
+ ret = sprintf(tmp, "[hw]%#lx:%#lx:%#lx\n[sw]%#lx:%#lx:%#lx\n",
+ dvb->dmx[dmx_id].sec_cnt[SEC_CNT_HW],
+ dvb->dmx[dmx_id].sec_cnt_match[SEC_CNT_HW],
+ dvb->dmx[dmx_id].sec_cnt_crc_fail[SEC_CNT_HW],
+ dvb->dmx[dmx_id].sec_cnt[SEC_CNT_SW],
+ dvb->dmx[dmx_id].sec_cnt_match[SEC_CNT_SW],
+ dvb->dmx[dmx_id].sec_cnt_crc_fail[SEC_CNT_SW]);
+ ret = sprintf(buf, "%s[ss]%#lx:%#lx:%#lx\n",
+ tmp,
+ dvb->dmx[dmx_id].sec_cnt[SEC_CNT_SS],
+ dvb->dmx[dmx_id].sec_cnt_match[SEC_CNT_SS],
+ dvb->dmx[dmx_id].sec_cnt_crc_fail[SEC_CNT_SS]);
+ return ret;
+}
+
+int aml_regist_dmx_class(void)
+{
+
+ if (class_register(&aml_dmx_class) < 0)
+ pr_error("register class error\n");
+
+ return 0;
+}
+
+int aml_unregist_dmx_class(void)
+{
+
+ class_unregister(&aml_dmx_class);
+ return 0;
+}
+
+static struct mconfig parser_configs[] = {
+ MC_PU32("video_pts", &video_pts),
+ MC_PU32("audio_pts", &audio_pts),
+ MC_PU32("video_pts_bit32", &video_pts_bit32),
+ MC_PU32("audio_pts_bit32", &audio_pts_bit32),
+ MC_PU32("first_video_pts", &first_video_pts),
+ MC_PU32("first_audio_pts", &first_audio_pts),
+};
+
+void aml_register_parser_mconfig(void)
+{
+ REG_PATH_CONFIGS("media.parser", parser_configs);
+}
+
diff --git a/drivers/stream_input/parser/hw_demux/aml_dvb.c b/drivers/stream_input/parser/hw_demux/aml_dvb.c
new file mode 100644
index 0000000..4e1549c
--- /dev/null
+++ b/drivers/stream_input/parser/hw_demux/aml_dvb.c
@@ -0,0 +1,2808 @@
+/*
+* 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:
+*/
+ /*
+ * AMLOGIC DVB driver.
+ */
+
+//move to define in Makefile
+//#define ENABLE_DEMUX_DRIVER
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/fcntl.h>
+#include <asm/irq.h>
+#include <linux/uaccess.h>
+#include <linux/poll.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/reset.h>
+#include <linux/of_gpio.h>
+#include <linux/amlogic/media/utils/amstream.h>
+#include <linux/amlogic/cpu_version.h>
+#include <linux/clk.h>
+#include "c_stb_define.h"
+#include "c_stb_regs_define.h"
+#include "aml_dvb.h"
+#include "aml_dvb_reg.h"
+
+#include "aml_demod_gt.h"
+#include "../../../common/media_clock/switch/amports_gate.h"
+
+#define pr_dbg(args...)\
+ do {\
+ if (debug_dvb)\
+ printk(args);\
+ } while (0)
+#define pr_error(fmt, args...) printk("DVB: " fmt, ## args)
+#define pr_inf(fmt, args...) printk(fmt, ## args)
+
+MODULE_PARM_DESC(debug_dvb, "\n\t\t Enable dvb debug information");
+static int debug_dvb;
+module_param(debug_dvb, int, 0644);
+
+#define CARD_NAME "amlogic-dvb-demux"
+
+#define DVB_VERSION "V2.02"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+MODULE_PARM_DESC(dsc_max, "max number of dsc");
+static int dsc_max = DSC_DEV_COUNT;
+module_param(dsc_max, int, 0644);
+
+static struct aml_dvb aml_dvb_device;
+static struct class aml_stb_class;
+
+static int dmx_reset_all_flag = 0;
+#if 0
+static struct reset_control *aml_dvb_demux_reset_ctl;
+static struct reset_control *aml_dvb_afifo_reset_ctl;
+static struct reset_control *aml_dvb_ahbarb0_reset_ctl;
+static struct reset_control *aml_dvb_uparsertop_reset_ctl;
+#else
+/*no used reset ctl,need use clk in 4.9 kernel*/
+static struct clk *aml_dvb_demux_clk;
+static struct clk *aml_dvb_afifo_clk;
+static struct clk *aml_dvb_ahbarb0_clk;
+static struct clk *aml_dvb_uparsertop_clk;
+#endif
+
+static int aml_tsdemux_reset(void);
+static int aml_tsdemux_set_reset_flag(void);
+static int aml_tsdemux_request_irq(irq_handler_t handler, void *data);
+static int aml_tsdemux_free_irq(void);
+static int aml_tsdemux_set_vid(int vpid);
+static int aml_tsdemux_set_aid(int apid);
+static int aml_tsdemux_set_sid(int spid);
+static int aml_tsdemux_set_pcrid(int pcrpid);
+static int aml_tsdemux_set_skipbyte(int skipbyte);
+static int aml_tsdemux_set_demux(int id);
+static unsigned long aml_tsdemux_hwdmx_spin_lock(unsigned long flags);
+static int aml_tsdemux_hwdmx_spin_unlock(unsigned long flags);
+
+static struct tsdemux_ops aml_tsdemux_ops = {
+ .reset = aml_tsdemux_reset,
+ .set_reset_flag = aml_tsdemux_set_reset_flag,
+ .request_irq = aml_tsdemux_request_irq,
+ .free_irq = aml_tsdemux_free_irq,
+ .set_vid = aml_tsdemux_set_vid,
+ .set_aid = aml_tsdemux_set_aid,
+ .set_sid = aml_tsdemux_set_sid,
+ .set_pcrid = aml_tsdemux_set_pcrid,
+ .set_skipbyte = aml_tsdemux_set_skipbyte,
+ .set_demux = aml_tsdemux_set_demux,
+ .hw_dmx_lock = aml_tsdemux_hwdmx_spin_lock,
+ .hw_dmx_unlock = aml_tsdemux_hwdmx_spin_unlock
+};
+
+long aml_stb_get_base(int id)
+{
+ int newbase = 0;
+ if (MESON_CPU_MAJOR_ID_TXL < get_cpu_type()
+ && MESON_CPU_MAJOR_ID_GXLX != get_cpu_type()) {
+ newbase = 1;
+ }
+
+ switch (id) {
+ case ID_STB_CBUS_BASE:
+ return (newbase) ? 0x1800 : 0x1600;
+ case ID_SMARTCARD_REG_BASE:
+ return (newbase) ? 0x9400 : 0x2110;
+ case ID_ASYNC_FIFO_REG_BASE:
+ return (newbase) ? 0x2800 : 0x2310;
+ case ID_ASYNC_FIFO1_REG_BASE:
+ return 0x9800;
+ case ID_ASYNC_FIFO2_REG_BASE:
+ return (newbase) ? 0x2400 : 0x2314;
+ case ID_RESET_BASE:
+ return (newbase) ? 0x0400 : 0x1100;
+ case ID_PARSER_SUB_START_PTR_BASE:
+ return (newbase) ? 0x3800 : 0x2900;
+ default:
+ return 0;
+ }
+ return 0;
+}
+static void aml_dvb_dmx_release(struct aml_dvb *advb, struct aml_dmx *dmx)
+{
+ int i;
+ pr_inf("[dmx_kpi] %s Enter.\n", __func__);
+ dvb_net_release(&dmx->dvb_net);
+ aml_dmx_hw_deinit(dmx);
+ dmx->demux.dmx.close(&dmx->demux.dmx);
+ dmx->demux.dmx.remove_frontend(&dmx->demux.dmx, &dmx->mem_fe);
+
+ for (i = 0; i < DMX_DEV_COUNT; i++)
+ dmx->demux.dmx.remove_frontend(&dmx->demux.dmx, &dmx->hw_fe[i]);
+
+ dvb_dmxdev_release(&dmx->dmxdev);
+ dvb_dmx_release(&dmx->demux);
+ pr_inf("[dmx_kpi] %s Exit.\n", __func__);
+}
+
+static int aml_dvb_dmx_init(struct aml_dvb *advb, struct aml_dmx *dmx, int id)
+{
+ int i, ret;
+
+ struct resource *res;
+ char buf[32];
+
+ switch (id) {
+ case 0:
+ dmx->dmx_irq = INT_DEMUX;
+ break;
+ case 1:
+ dmx->dmx_irq = INT_DEMUX_1;
+ break;
+ case 2:
+ dmx->dmx_irq = INT_DEMUX_2;
+ break;
+ }
+
+ snprintf(buf, sizeof(buf), "demux%d_irq", id);
+ res = platform_get_resource_byname(advb->pdev, IORESOURCE_IRQ, buf);
+ if (res)
+ dmx->dmx_irq = res->start;
+
+ pr_dbg("%s irq num:%d \r\n", buf, dmx->dmx_irq);
+
+ dmx->source = -1;
+ dmx->dump_ts_select = 0;
+ dmx->dvr_irq = -1;
+
+ dmx->demux.dmx.capabilities =
+ (DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING);
+ dmx->demux.filternum = dmx->demux.feednum = FILTER_COUNT;
+ dmx->demux.priv = advb;
+ dmx->demux.start_feed = aml_dmx_hw_start_feed;
+ dmx->demux.stop_feed = aml_dmx_hw_stop_feed;
+ dmx->demux.write_to_decoder = NULL;
+ ret = dvb_dmx_init(&dmx->demux);
+ if (ret < 0) {
+ pr_error("dvb_dmx failed: error %d\n", ret);
+ goto error_dmx_init;
+ }
+
+ dmx->dmxdev.filternum = dmx->demux.feednum;
+ dmx->dmxdev.demux = &dmx->demux.dmx;
+ dmx->dmxdev.capabilities = 0;
+ ret = dvb_dmxdev_init(&dmx->dmxdev, &advb->dvb_adapter);
+ if (ret < 0) {
+ pr_error("dvb_dmxdev_init failed: error %d\n", ret);
+ goto error_dmxdev_init;
+ }
+
+ for (i = 0; i < DMX_DEV_COUNT; i++) {
+ int source = i + DMX_FRONTEND_0;
+
+ dmx->hw_fe[i].source = source;
+ ret =
+ dmx->demux.dmx.add_frontend(&dmx->demux.dmx,
+ &dmx->hw_fe[i]);
+ if (ret < 0) {
+ pr_error("adding hw_frontend to dmx failed: error %d",
+ ret);
+ dmx->hw_fe[i].source = 0;
+ goto error_add_hw_fe;
+ }
+ }
+
+ dmx->mem_fe.source = DMX_MEMORY_FE;
+ ret = dmx->demux.dmx.add_frontend(&dmx->demux.dmx, &dmx->mem_fe);
+ if (ret < 0) {
+ pr_error("adding mem_frontend to dmx failed: error %d", ret);
+ goto error_add_mem_fe;
+ }
+ ret = dmx->demux.dmx.connect_frontend(&dmx->demux.dmx, &dmx->hw_fe[1]);
+ if (ret < 0) {
+ pr_error("connect frontend failed: error %d", ret);
+ goto error_connect_fe;
+ }
+
+ dmx->id = id;
+ dmx->aud_chan = -1;
+ dmx->vid_chan = -1;
+ dmx->sub_chan = -1;
+ dmx->pcr_chan = -1;
+
+ /*smallsec*/
+ dmx->smallsec.enable = 0;
+ dmx->smallsec.bufsize = SS_BUFSIZE_DEF;
+ dmx->smallsec.dmx = dmx;
+
+ /*input timeout*/
+ dmx->timeout.enable = 1;
+ dmx->timeout.timeout = DTO_TIMEOUT_DEF;
+ dmx->timeout.ch_disable = DTO_CHDIS_VAS;
+ dmx->timeout.match = 1;
+ dmx->timeout.trigger = 0;
+ dmx->timeout.dmx = dmx;
+
+ /*CRC monitor*/
+ dmx->crc_check_count = 0;
+ dmx->crc_check_time = 0;
+
+ ret = aml_dmx_hw_init(dmx);
+ if (ret < 0) {
+ pr_error("demux hw init error %d", ret);
+ dmx->id = -1;
+ goto error_dmx_hw_init;
+ }
+
+ dvb_net_init(&advb->dvb_adapter, &dmx->dvb_net, &dmx->demux.dmx);
+
+ return 0;
+error_dmx_hw_init:
+error_connect_fe:
+ dmx->demux.dmx.remove_frontend(&dmx->demux.dmx, &dmx->mem_fe);
+error_add_mem_fe:
+error_add_hw_fe:
+ for (i = 0; i < DMX_DEV_COUNT; i++) {
+ if (dmx->hw_fe[i].source)
+ dmx->demux.dmx.remove_frontend(&dmx->demux.dmx,
+ &dmx->hw_fe[i]);
+ }
+ dvb_dmxdev_release(&dmx->dmxdev);
+error_dmxdev_init:
+ dvb_dmx_release(&dmx->demux);
+error_dmx_init:
+ return ret;
+}
+
+struct aml_dvb *aml_get_dvb_device(void)
+{
+ return &aml_dvb_device;
+}
+EXPORT_SYMBOL(aml_get_dvb_device);
+
+struct dvb_adapter *aml_get_dvb_adapter(void)
+{
+ return &aml_dvb_device.dvb_adapter;
+}
+EXPORT_SYMBOL(aml_get_dvb_adapter);
+
+static int dvb_dsc_open(struct inode *inode, struct file *file)
+{
+ int err;
+
+ err = dvb_generic_open(inode, file);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static void dsc_channel_alloc(struct aml_dsc *dsc, int id, unsigned int pid)
+{
+ struct aml_dsc_channel *ch = &dsc->channel[id];
+
+ ch->used = 1;
+ ch->work_mode = -1;
+ ch->id = id;
+ ch->pid = pid;
+ ch->set = 0;
+ ch->dsc = dsc;
+ ch->mode = -1;
+
+ dsc_set_pid(ch, ch->pid);
+}
+
+static void dsc_channel_free(struct aml_dsc_channel *ch)
+{
+ if (!ch->used)
+ return;
+
+ ch->used = 0;
+ dsc_set_pid(ch, 0x1fff);
+ dsc_release();
+
+ ch->pid = 0x1fff;
+ ch->set = 0;
+ ch->work_mode = -1;
+ ch->mode = -1;
+}
+
+static void dsc_reset(struct aml_dsc *dsc)
+{
+ int i;
+
+ for (i = 0; i < DSC_COUNT; i++)
+ dsc_channel_free(&dsc->channel[i]);
+}
+
+static int get_dsc_key_work_mode(enum ca_cw_type cw_type)
+{
+ int work_mode = DVBCSA_MODE;
+
+ switch (cw_type) {
+ case CA_CW_DVB_CSA_EVEN:
+ case CA_CW_DVB_CSA_ODD:
+ work_mode = DVBCSA_MODE;
+ break;
+ case CA_CW_AES_EVEN:
+ case CA_CW_AES_ODD:
+ case CA_CW_AES_ODD_IV:
+ case CA_CW_AES_EVEN_IV:
+ case CA_CW_DES_EVEN:
+ case CA_CW_DES_ODD:
+ case CA_CW_SM4_EVEN:
+ case CA_CW_SM4_ODD:
+ case CA_CW_SM4_ODD_IV:
+ case CA_CW_SM4_EVEN_IV:
+ work_mode = CIPLUS_MODE;
+ default:
+ break;
+ }
+ return work_mode;
+}
+
+/* Check if there are channels run in previous mode(aes/dvbcsa)
+ * in dsc0/ciplus
+ */
+static void dsc_ciplus_switch_check(struct aml_dsc_channel *ch,
+ enum ca_cw_type cw_type)
+{
+ struct aml_dsc *dsc = ch->dsc;
+ int work_mode = 0;
+ struct aml_dsc_channel *pch = NULL;
+ int i;
+
+ work_mode = get_dsc_key_work_mode(cw_type);
+ if (dsc->work_mode == work_mode)
+ return;
+
+ dsc->work_mode = work_mode;
+
+ for (i = 0; i < DSC_COUNT; i++) {
+ pch = &dsc->channel[i];
+ if (pch->work_mode != work_mode && pch->work_mode != -1) {
+ pr_error("Dsc work mode changed,");
+ pr_error("but there are still some channels");
+ pr_error("run in different mode\n");
+ pr_error("mod_pre[%d] -> mod[%d] ch[%d]\n",
+ pch->work_mode, work_mode, i);
+ }
+ }
+}
+
+static int dsc_set_cw(struct aml_dsc *dsc, struct ca_descr_ex *d)
+{
+ struct aml_dsc_channel *ch;
+
+ if (d->index >= DSC_COUNT)
+ return -EINVAL;
+
+ ch = &dsc->channel[d->index];
+
+ switch (d->type) {
+ case CA_CW_DVB_CSA_EVEN:
+ case CA_CW_AES_EVEN:
+ case CA_CW_DES_EVEN:
+ case CA_CW_SM4_EVEN:
+ memcpy(ch->even, d->cw, DSC_KEY_SIZE_MAX);
+ break;
+ case CA_CW_DVB_CSA_ODD:
+ case CA_CW_AES_ODD:
+ case CA_CW_DES_ODD:
+ case CA_CW_SM4_ODD:
+ memcpy(ch->odd, d->cw, DSC_KEY_SIZE_MAX);
+ break;
+ case CA_CW_AES_EVEN_IV:
+ case CA_CW_SM4_EVEN_IV:
+ memcpy(ch->even_iv, d->cw, DSC_KEY_SIZE_MAX);
+ break;
+ case CA_CW_AES_ODD_IV:
+ case CA_CW_SM4_ODD_IV:
+ memcpy(ch->odd_iv, d->cw, DSC_KEY_SIZE_MAX);
+ break;
+ default:
+ break;
+ }
+
+ ch->set |= (1 << d->type) | (d->flags << 24);
+
+ if (d->mode == CA_DSC_IDSA) {
+ ch->mode = IDSA_MODE;
+ }
+
+ /*do key set*/
+ dsc_set_key(ch, d->flags, d->type, d->cw);
+ dsc_ciplus_switch_check(ch, d->type);
+
+ return 0;
+}
+
+static int dvb_dsc_do_ioctl(struct file *file, unsigned int cmd,
+ void *parg)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct aml_dsc *dsc = dvbdev->priv;
+ struct aml_dvb *dvb = dsc->dvb;
+ struct aml_dsc_channel *ch;
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+
+ switch (cmd) {
+ case CA_RESET:
+ dsc_reset(dsc);
+ break;
+ case CA_GET_CAP: {
+ ca_caps_t *cap = parg;
+
+ cap->slot_num = 1;
+ cap->slot_type = CA_DESCR;
+ cap->descr_num = DSC_COUNT;
+ cap->descr_type = 0;
+ break;
+ }
+ case CA_GET_SLOT_INFO: {
+ ca_slot_info_t *slot = parg;
+
+ slot->num = 1;
+ slot->type = CA_DESCR;
+ slot->flags = 0;
+ break;
+ }
+ case CA_GET_DESCR_INFO: {
+ ca_descr_info_t *descr = parg;
+
+ descr->num = DSC_COUNT;
+ descr->type = 0;
+ break;
+ }
+ case CA_SET_DESCR: {
+ ca_descr_t *d = parg;
+ struct ca_descr_ex dex;
+
+ dex.index = d->index;
+ dex.type = d->parity ? CA_CW_DVB_CSA_ODD : CA_CW_DVB_CSA_EVEN;
+ dex.mode = -1;
+ dex.flags = 0;
+ memcpy(dex.cw, d->cw, sizeof(d->cw));
+
+ ret = dsc_set_cw(dsc, &dex);
+ break;
+ }
+ case CA_SET_PID: {
+ ca_pid_t *pi = parg;
+ int i;
+
+ if (pi->index == -1) {
+ for (i = 0; i < DSC_COUNT; i++) {
+ ch = &dsc->channel[i];
+
+ if (ch->used && (ch->pid == pi->pid)) {
+ dsc_channel_free(ch);
+ break;
+ }
+ }
+ } else if ((pi->index >= 0) && (pi->index < DSC_COUNT)) {
+ ch = &dsc->channel[pi->index];
+
+ if (pi->pid < 0x1fff) {
+ if (!ch->used) {
+ dsc_channel_alloc(dsc,
+ pi->index, pi->pid);
+ }
+ } else {
+ if (ch->used)
+ dsc_channel_free(ch);
+ }
+ } else {
+ ret = -EINVAL;
+ }
+ break;
+ }
+ case CA_SET_DESCR_EX: {
+ struct ca_descr_ex *d = parg;
+
+ ret = dsc_set_cw(dsc, d);
+ break;
+ }
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return ret;
+}
+
+static int dvb_dsc_usercopy(struct file *file,
+ unsigned int cmd, unsigned long arg,
+ int (*func)(struct file *file,
+ unsigned int cmd, void *arg))
+{
+ char sbuf[128];
+ void *mbuf = NULL;
+ void *parg = NULL;
+ int err = -EINVAL;
+
+ /* Copy arguments into temp kernel buffer */
+ switch (_IOC_DIR(cmd)) {
+ case _IOC_NONE:
+ /*
+ * For this command, the pointer is actually an integer
+ * argument.
+ */
+ parg = (void *) arg;
+ break;
+ case _IOC_READ: /* some v4l ioctls are marked wrong ... */
+ case _IOC_WRITE:
+ case (_IOC_WRITE | _IOC_READ):
+ if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+ parg = sbuf;
+ } else {
+ /* too big to allocate from stack */
+ mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
+ if (mbuf == NULL)
+ return -ENOMEM;
+ parg = mbuf;
+ }
+
+ err = -EFAULT;
+ if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
+ goto out;
+ break;
+ }
+
+ /* call driver */
+ err = func(file, cmd, parg);
+ if (err == -ENOIOCTLCMD)
+ err = -ENOTTY;
+
+ if (err < 0)
+ goto out;
+
+ /* Copy results into user buffer */
+ switch (_IOC_DIR(cmd)) {
+ case _IOC_READ:
+ case (_IOC_WRITE | _IOC_READ):
+ if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
+ err = -EFAULT;
+ break;
+ }
+
+out:
+ kfree(mbuf);
+ return err;
+}
+
+static long dvb_dsc_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return dvb_dsc_usercopy(file, cmd, arg, dvb_dsc_do_ioctl);
+}
+
+static int dvb_dsc_release(struct inode *inode, struct file *file)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct aml_dsc *dsc = dvbdev->priv;
+ struct aml_dvb *dvb = dsc->dvb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+
+ dsc_reset(dsc);
+
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ dvb_generic_release(inode, file);
+
+ return 0;
+}
+
+#ifdef CONFIG_COMPAT
+static long dvb_dsc_compat_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long args)
+{
+ unsigned long ret;
+
+ args = (unsigned long)compat_ptr(args);
+ ret = dvb_dsc_ioctl(filp, cmd, args);
+ return ret;
+}
+#endif
+
+
+static const struct file_operations dvb_dsc_fops = {
+ .owner = THIS_MODULE,
+ .read = NULL,
+ .write = NULL,
+ .unlocked_ioctl = dvb_dsc_ioctl,
+ .open = dvb_dsc_open,
+ .release = dvb_dsc_release,
+ .poll = NULL,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = dvb_dsc_compat_ioctl,
+#endif
+};
+
+static struct dvb_device dvbdev_dsc = {
+ .priv = NULL,
+ .users = 1,
+ .readers = 1,
+ .writers = 1,
+ .fops = &dvb_dsc_fops,
+};
+
+static int aml_dvb_asyncfifo_init(struct aml_dvb *advb,
+ struct aml_asyncfifo *asyncfifo, int id)
+{
+ struct resource *res;
+ char buf[32];
+
+ if (id == 0)
+ asyncfifo->asyncfifo_irq = INT_ASYNC_FIFO_FLUSH;
+ else if(id == 2)
+ asyncfifo->asyncfifo_irq = INT_ASYNC_FIFO3_FLUSH;
+ else
+ asyncfifo->asyncfifo_irq = INT_ASYNC_FIFO2_FLUSH;
+
+ snprintf(buf, sizeof(buf), "dvr%d_irq", id);
+ res = platform_get_resource_byname(advb->pdev, IORESOURCE_IRQ, buf);
+ if (res)
+ asyncfifo->asyncfifo_irq = res->start;
+ pr_dbg("%s irq num:%d \n", buf, asyncfifo->asyncfifo_irq);
+ asyncfifo->dvb = advb;
+ asyncfifo->id = id;
+ asyncfifo->init = 0;
+ asyncfifo->flush_size = 256 * 1024;
+ asyncfifo->secure_enable = 0;
+ asyncfifo->blk.addr = 0;
+ asyncfifo->blk.len = 0;
+ asyncfifo->stored_pages = 0;
+
+ return aml_asyncfifo_hw_init(asyncfifo);
+}
+static void aml_dvb_asyncfifo_release(struct aml_dvb *advb,
+ struct aml_asyncfifo *asyncfifo)
+{
+ aml_asyncfifo_hw_deinit(asyncfifo);
+}
+
+static int aml_dvb_dsc_init(struct aml_dvb *advb,
+ struct aml_dsc *dsc, int id)
+{
+ int i;
+
+ for (i = 0; i < DSC_COUNT; i++) {
+ dsc->channel[i].id = i;
+ dsc->channel[i].used = 0;
+ dsc->channel[i].set = 0;
+ dsc->channel[i].pid = 0x1fff;
+ dsc->channel[i].dsc = dsc;
+ }
+ dsc->dvb = advb;
+ dsc->id = id;
+ dsc->source = -1;
+ dsc->dst = -1;
+
+ /*Register descrambler device */
+ return dvb_register_device(&advb->dvb_adapter, &dsc->dev,
+ &dvbdev_dsc, dsc, DVB_DEVICE_CA, 0);
+}
+static void aml_dvb_dsc_release(struct aml_dvb *advb,
+ struct aml_dsc *dsc)
+{
+ if (dsc->dev)
+ dvb_unregister_device(dsc->dev);
+ dsc->dev = NULL;
+}
+
+
+/*Show the STB input source*/
+static ssize_t stb_show_source(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ ssize_t ret = 0;
+ char *src;
+
+ switch (dvb->stb_source) {
+ case AM_TS_SRC_TS0:
+ case AM_TS_SRC_S_TS0:
+ src = "ts0";
+ break;
+ case AM_TS_SRC_TS1:
+ case AM_TS_SRC_S_TS1:
+ src = "ts1";
+ break;
+ case AM_TS_SRC_TS2:
+ case AM_TS_SRC_S_TS2:
+ src = "ts2";
+ break;
+ case AM_TS_SRC_TS3:
+ src = "ts3";
+ break;
+ case AM_TS_SRC_HIU:
+ src = "hiu";
+ break;
+ case AM_TS_SRC_HIU1:
+ src = "hiu1";
+ break;
+ case AM_TS_SRC_DMX0:
+ src = "dmx0";
+ break;
+ case AM_TS_SRC_DMX1:
+ src = "dmx1";
+ break;
+ case AM_TS_SRC_DMX2:
+ src = "dmx2";
+ break;
+ default:
+ src = "disable";
+ break;
+ }
+
+ ret = sprintf(buf, "%s\n", src);
+ return ret;
+}
+
+static ssize_t stb_clear_av(struct class *class,
+ struct class_attribute *attr, const char *buf,
+ size_t size)
+{
+ if (!strncmp("1", buf, 1)) {
+ aml_tsdemux_set_vid(0x1fff);
+ aml_tsdemux_set_aid(0x1fff);
+ aml_tsdemux_set_sid(0x1fff);
+ aml_tsdemux_set_pcrid(0x1fff);
+ }
+
+ return size;
+}
+
+static int stb_check_source(const char *buf)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ int ret = 0;
+ char *src;
+
+ switch (dvb->stb_source) {
+ case AM_TS_SRC_TS0:
+ case AM_TS_SRC_S_TS0:
+ src = "ts0";
+ break;
+ case AM_TS_SRC_TS1:
+ case AM_TS_SRC_S_TS1:
+ src = "ts1";
+ break;
+ case AM_TS_SRC_TS2:
+ case AM_TS_SRC_S_TS2:
+ src = "ts2";
+ break;
+ case AM_TS_SRC_TS3:
+ src = "ts3";
+ break;
+ case AM_TS_SRC_HIU:
+ src = "hiu";
+ break;
+ case AM_TS_SRC_HIU1:
+ src = "hiu1";
+ break;
+ case AM_TS_SRC_DMX0:
+ src = "dmx0";
+ break;
+ case AM_TS_SRC_DMX1:
+ src = "dmx1";
+ break;
+ case AM_TS_SRC_DMX2:
+ src = "dmx2";
+ break;
+ default:
+ src = "disable";
+ break;
+ }
+ pr_error("stb_check_source set buf:%s, src:%s\n", buf, src);
+ ret = strcmp(buf,src);
+ return ret;
+}
+
+/*Set the STB input source*/
+static ssize_t stb_store_source(struct class *class,
+ struct class_attribute *attr, const char *buf,
+ size_t size)
+{
+ dmx_source_t src = -1;
+ if (stb_check_source(buf) == 0) {
+ pr_error("stb_store_source same source \n");
+ return size;
+ }
+ if (!strncmp("ts0", buf, 3))
+ src = DMX_SOURCE_FRONT0;
+ else if (!strncmp("ts1", buf, 3))
+ src = DMX_SOURCE_FRONT1;
+ else if (!strncmp("ts2", buf, 3))
+ src = DMX_SOURCE_FRONT2;
+ else if (!strncmp("ts3", buf, 3))
+ src = DMX_SOURCE_FRONT3;
+ else if (!strncmp("hiu1", buf, 4))
+ src = DMX_SOURCE_DVR1;
+ else if (!strncmp("hiu", buf, 3))
+ src = DMX_SOURCE_DVR0;
+ else if (!strncmp("dmx0", buf, 4))
+ src = DMX_SOURCE_FRONT0 + 100;
+ else if (!strncmp("dmx1", buf, 4))
+ src = DMX_SOURCE_FRONT1 + 100;
+ else if (!strncmp("dmx2", buf, 4))
+ src = DMX_SOURCE_FRONT2 + 100;
+ if (src != -1)
+ aml_stb_hw_set_source(&aml_dvb_device, src);
+ return size;
+}
+
+static ssize_t show_dmx_reset_all_flag(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+ char *src;
+
+ if (dmx_reset_all_flag)
+ src = "1";
+ else
+ src = "0";
+ ret = sprintf(buf, "%s\n", src);
+ return ret;
+}
+static ssize_t set_dmx_reset_all_flag(struct class *class,
+ struct class_attribute *attr, const char *buf,
+ size_t size)
+{
+ if (!strncmp("0", buf, 1))
+ dmx_reset_all_flag = 0;
+ else if (!strncmp("1", buf, 1))
+ dmx_reset_all_flag = 1;
+
+ return size;
+}
+#define CASE_PREFIX
+
+/*Show the descrambler's input source*/
+#define DSC_SOURCE_FUNC_DECL(i) \
+static ssize_t dsc##i##_show_source(struct class *class, \
+ struct class_attribute *attr, char *buf)\
+{\
+ struct aml_dvb *dvb = &aml_dvb_device;\
+ struct aml_dsc *dsc = &dvb->dsc[i];\
+ ssize_t ret = 0;\
+ char *src, *dst;\
+ switch (dsc->source) {\
+ CASE_PREFIX case AM_TS_SRC_DMX0:\
+ src = "dmx0";\
+ break;\
+ CASE_PREFIX case AM_TS_SRC_DMX1:\
+ src = "dmx1";\
+ break;\
+ CASE_PREFIX case AM_TS_SRC_DMX2:\
+ src = "dmx2";\
+ break;\
+ CASE_PREFIX default :\
+ src = "bypass";\
+ break;\
+ } \
+ switch (dsc->dst) {\
+ CASE_PREFIX case AM_TS_SRC_DMX0:\
+ dst = "dmx0";\
+ break;\
+ CASE_PREFIX case AM_TS_SRC_DMX1:\
+ dst = "dmx1";\
+ break;\
+ CASE_PREFIX case AM_TS_SRC_DMX2:\
+ dst = "dmx2";\
+ break;\
+ CASE_PREFIX default :\
+ dst = "bypass";\
+ break;\
+ } \
+ ret = sprintf(buf, "%s-%s\n", src, dst);\
+ return ret;\
+} \
+static ssize_t dsc##i##_store_source(struct class *class, \
+ struct class_attribute *attr, const char *buf, size_t size)\
+{\
+ dmx_source_t src = -1, dst = -1;\
+ \
+ if (!strncmp("dmx0", buf, 4)) {\
+ src = DMX_SOURCE_FRONT0 + 100;\
+ } else if (!strncmp("dmx1", buf, 4)) {\
+ src = DMX_SOURCE_FRONT1 + 100;\
+ } else if (!strncmp("dmx2", buf, 4)) {\
+ src = DMX_SOURCE_FRONT2 + 100;\
+ } \
+ if (buf[4] == '-') {\
+ if (!strncmp("dmx0", buf+5, 4)) {\
+ dst = DMX_SOURCE_FRONT0 + 100;\
+ } else if (!strncmp("dmx1", buf+5, 4)) {\
+ dst = DMX_SOURCE_FRONT1 + 100;\
+ } else if (!strncmp("dmx2", buf+5, 4)) {\
+ dst = DMX_SOURCE_FRONT2 + 100;\
+ } \
+ } \
+ else \
+ dst = src; \
+ aml_dsc_hw_set_source(&aml_dvb_device.dsc[i], src, dst);\
+ return size;\
+}
+
+/*Show free descramblers count*/
+#define DSC_FREE_FUNC_DECL(i) \
+static ssize_t dsc##i##_show_free_dscs(struct class *class, \
+ struct class_attribute *attr, char *buf) \
+{ \
+ struct aml_dvb *dvb = &aml_dvb_device; \
+ int fid, count; \
+ ssize_t ret = 0; \
+ unsigned long flags;\
+\
+ spin_lock_irqsave(&dvb->slock, flags); \
+ count = 0; \
+ for (fid = 0; fid < DSC_COUNT; fid++) { \
+ if (!dvb->dsc[i].channel[fid].used) \
+ count++; \
+ } \
+ spin_unlock_irqrestore(&dvb->slock, flags); \
+\
+ ret = sprintf(buf, "%d\n", count); \
+ return ret; \
+}
+
+#if DSC_DEV_COUNT > 0
+ DSC_SOURCE_FUNC_DECL(0)
+ DSC_FREE_FUNC_DECL(0)
+#endif
+#if DSC_DEV_COUNT > 1
+ DSC_SOURCE_FUNC_DECL(1)
+ DSC_FREE_FUNC_DECL(1)
+#endif
+
+/*Show the TS output source*/
+static ssize_t tso_show_source(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ ssize_t ret = 0;
+ char *src;
+
+ switch (dvb->tso_source) {
+ case AM_TS_SRC_TS0:
+ case AM_TS_SRC_S_TS0:
+ src = "ts0";
+ break;
+ case AM_TS_SRC_TS1:
+ case AM_TS_SRC_S_TS1:
+ src = "ts1";
+ break;
+ case AM_TS_SRC_TS2:
+ case AM_TS_SRC_S_TS2:
+ src = "ts2";
+ break;
+ case AM_TS_SRC_TS3:
+ src = "ts3";
+ break;
+ case AM_TS_SRC_HIU:
+ src = "hiu";
+ break;
+ case AM_TS_SRC_DMX0:
+ src = "dmx0";
+ break;
+ case AM_TS_SRC_DMX1:
+ src = "dmx1";
+ break;
+ case AM_TS_SRC_DMX2:
+ src = "dmx2";
+ break;
+ default:
+ src = "default";
+ break;
+ }
+
+ ret = sprintf(buf, "%s\n", src);
+ return ret;
+}
+
+/*Set the TS output source*/
+static ssize_t tso_store_source(struct class *class,
+ struct class_attribute *attr, const char *buf,
+ size_t size)
+{
+ dmx_source_t src = -1;
+
+ if (!strncmp("ts0", buf, 3))
+ src = DMX_SOURCE_FRONT0;
+ else if (!strncmp("ts1", buf, 3))
+ src = DMX_SOURCE_FRONT1;
+ else if (!strncmp("ts2", buf, 3))
+ src = DMX_SOURCE_FRONT2;
+ else if (!strncmp("ts3", buf, 3))
+ src = DMX_SOURCE_FRONT3;
+ else if (!strncmp("hiu", buf, 3))
+ src = DMX_SOURCE_DVR0;
+ else if (!strncmp("dmx0", buf, 4))
+ src = DMX_SOURCE_FRONT0 + 100;
+ else if (!strncmp("dmx1", buf, 4))
+ src = DMX_SOURCE_FRONT1 + 100;
+ else if (!strncmp("dmx2", buf, 4))
+ src = DMX_SOURCE_FRONT2 + 100;
+
+ aml_tso_hw_set_source(&aml_dvb_device, src);
+
+ return size;
+}
+
+/*Show PCR*/
+#define DEMUX_PCR_FUNC_DECL(i) \
+static ssize_t demux##i##_show_pcr(struct class *class, \
+ struct class_attribute *attr, char *buf)\
+{\
+ int f = 0;\
+ if (i == 0)\
+ f = READ_MPEG_REG(PCR_DEMUX);\
+ else if (i == 1)\
+ f = READ_MPEG_REG(PCR_DEMUX_2);\
+ else if (i == 2)\
+ f = READ_MPEG_REG(PCR_DEMUX_3);\
+ return sprintf(buf, "%08x\n", f);\
+}
+
+static int dmx_check_source(int i, const char *buf)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ struct aml_dmx *dmx = &dvb->dmx[i];
+ ssize_t ret = 0;
+ char *src;
+ switch (dmx->source) {
+ case AM_TS_SRC_TS0:
+ case AM_TS_SRC_S_TS0:
+ src = "ts0";
+ break;
+ case AM_TS_SRC_TS1:
+ case AM_TS_SRC_S_TS1:
+ src = "ts1";
+ break;
+ case AM_TS_SRC_TS2:
+ case AM_TS_SRC_S_TS2:
+ src = "ts2";
+ break;
+ case AM_TS_SRC_TS3:
+ src = "ts3";
+ break;
+ case AM_TS_SRC_DMX0:
+ src = "dmx0";
+ break;
+ case AM_TS_SRC_DMX1:
+ src = "dmx1";
+ break;
+ case AM_TS_SRC_DMX2:
+ src = "dmx2";
+ break;
+ case AM_TS_SRC_HIU:
+ src = "hiu";
+ break;
+ case AM_TS_SRC_HIU1:
+ src = "hiu1";
+ break;
+ default :
+ src = "";
+ break;
+ }
+ pr_error("dmx_check_source:set[%s]src[%s]dmx[%d]dmx->source:%d\n", buf, src, i, dmx->source);
+ ret = strcmp(buf, src);
+ return ret;
+}
+
+
+/*Show the STB input source*/
+#define DEMUX_SOURCE_FUNC_DECL(i) \
+static ssize_t demux##i##_show_source(struct class *class, \
+ struct class_attribute *attr, char *buf)\
+{\
+ struct aml_dvb *dvb = &aml_dvb_device;\
+ struct aml_dmx *dmx = &dvb->dmx[i];\
+ ssize_t ret = 0;\
+ char *src;\
+ switch (dmx->source) {\
+ CASE_PREFIX case AM_TS_SRC_TS0:\
+ CASE_PREFIX case AM_TS_SRC_S_TS0:\
+ src = "ts0";\
+ break;\
+ CASE_PREFIX case AM_TS_SRC_TS1:\
+ CASE_PREFIX case AM_TS_SRC_S_TS1:\
+ src = "ts1";\
+ break;\
+ CASE_PREFIX case AM_TS_SRC_TS2:\
+ CASE_PREFIX case AM_TS_SRC_S_TS2:\
+ src = "ts2";\
+ break;\
+ CASE_PREFIX case AM_TS_SRC_TS3:\
+ src = "ts3";\
+ break;\
+ CASE_PREFIX case AM_TS_SRC_DMX0:\
+ src = "dmx0";\
+ break;\
+ CASE_PREFIX case AM_TS_SRC_DMX1:\
+ src = "dmx1";\
+ break;\
+ CASE_PREFIX case AM_TS_SRC_DMX2:\
+ src = "dmx2";\
+ break;\
+ CASE_PREFIX case AM_TS_SRC_HIU:\
+ src = "hiu";\
+ break;\
+ CASE_PREFIX case AM_TS_SRC_HIU1:\
+ src = "hiu1";\
+ break;\
+ CASE_PREFIX default :\
+ src = "";\
+ break;\
+ } \
+ ret = sprintf(buf, "%s\n", src);\
+ return ret;\
+} \
+static ssize_t demux##i##_store_source(struct class *class, \
+ struct class_attribute *attr, const char *buf, size_t size)\
+{\
+ dmx_source_t src = -1;\
+ if (dmx_check_source(i, buf) == 0) {\
+ pr_error("dmx[%d] source is same [%s]\n", i, buf);\
+ return size;\
+ }\
+ if (!strncmp("ts0", buf, 3)) {\
+ src = DMX_SOURCE_FRONT0;\
+ } else if (!strncmp("ts1", buf, 3)) {\
+ src = DMX_SOURCE_FRONT1;\
+ } else if (!strncmp("ts2", buf, 3)) {\
+ src = DMX_SOURCE_FRONT2;\
+ } else if (!strncmp("ts3", buf, 3)) {\
+ src = DMX_SOURCE_FRONT3;\
+ } else if (!strncmp("hiu1", buf, 4)) {\
+ src = DMX_SOURCE_DVR1;\
+ } else if (!strncmp("hiu", buf, 3)) {\
+ src = DMX_SOURCE_DVR0;\
+ } else if (!strncmp("dmx0", buf, 4)) {\
+ src = DMX_SOURCE_FRONT0_OFFSET;\
+ } else if (!strncmp("dmx1", buf, 4)) {\
+ src = DMX_SOURCE_FRONT1_OFFSET;\
+ } else if (!strncmp("dmx2", buf, 4)) {\
+ src = DMX_SOURCE_FRONT2_OFFSET;\
+ } \
+ if (src != -1) {\
+ aml_dmx_hw_set_source(aml_dvb_device.dmx[i].dmxdev.demux, src);\
+ } \
+ return size;\
+}
+
+/*Show free filters count*/
+#define DEMUX_FREE_FILTERS_FUNC_DECL(i) \
+static ssize_t demux##i##_show_free_filters(struct class *class, \
+ struct class_attribute *attr, char *buf)\
+{\
+ struct aml_dvb *dvb = &aml_dvb_device;\
+ struct dvb_demux *dmx = &dvb->dmx[i].demux;\
+ int fid, count;\
+ ssize_t ret = 0;\
+ if (mutex_lock_interruptible(&dmx->mutex)) \
+ return -ERESTARTSYS; \
+ count = 0;\
+ for (fid = 0; fid < dmx->filternum; fid++) {\
+ if (!dmx->filter[fid].state != DMX_STATE_FREE)\
+ count++;\
+ } \
+ mutex_unlock(&dmx->mutex);\
+ ret = sprintf(buf, "%d\n", count);\
+ return ret;\
+}
+
+/*Show dmx dev open count*/
+#define DEMUX_DEV_USERS_FUNC_DECL(i) \
+static ssize_t demux##i##_show_dev_users(struct class *class, \
+ struct class_attribute *attr, char *buf)\
+{\
+ struct aml_dvb *dvb = &aml_dvb_device;\
+ struct dvb_demux *dmx = &dvb->dmx[i].demux;\
+ int count;\
+ ssize_t ret = 0;\
+ if (mutex_lock_interruptible(&dmx->mutex)) \
+ return -ERESTARTSYS; \
+ count = dvb->dmx[i].dmxdev.dvbdev->users -1;\
+ mutex_unlock(&dmx->mutex);\
+ ret = sprintf(buf, "%d\n", count);\
+ return ret;\
+}
+
+
+static ssize_t demux_state_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ int i = 0, r = 0, j = 0;
+ struct dvb_demux *dmx;
+ struct aml_dmx *dmx1;
+ int fid, count;
+ ssize_t ret = 0;
+ char *str = NULL;
+
+ for (i = 0; i < 3; i++) {
+ r = sprintf(buf, "#####dmx%d#######\n", i);
+ buf += r;
+ ret += r;
+ dmx = &dvb->dmx[i].demux;
+ if (mutex_lock_interruptible(&dmx->mutex))
+ return -ERESTARTSYS;
+
+ r = sprintf(buf, "filter:\n");
+ buf += r;
+ ret += r;
+
+ count = 0;
+ for (fid = 0; fid < dmx->filternum; fid++) {
+ if (!dmx->filter[fid].state != DMX_STATE_FREE)
+ count++;
+ else {
+ r = sprintf(buf, "fid:%d, pid:0x%0x, state:%d\n", fid, dmx->filter[fid].feed->pid,
+ dmx->filter[fid].state);
+ buf += r;
+ ret += r;
+ }
+ }
+ r = sprintf(buf, "used filter:%d, free filter:%d\n", (dmx->filternum - count), count);
+ buf += r;
+ ret += r;
+
+ r = sprintf(buf, "file users:%d\n", dvb->dmx[i].dmxdev.dvbdev->users);
+ buf += r;
+ ret += r;
+
+ r = sprintf(buf, "chan:\n");
+ buf += r;
+ ret += r;
+
+ dmx1 = &dvb->dmx[i];
+ count = 0;
+ for (j = 0; j < CHANNEL_COUNT; j++) {
+ if (dmx1->channel[j].used) {
+ if (dmx1->channel[j].type == DMX_TYPE_TS) {
+ if (dmx1->channel[j].pes_type == DMX_PES_VIDEO) {
+ str = "video";
+ } else if (dmx1->channel[j].pes_type == DMX_PES_AUDIO){
+ str = "audio";
+ } else if (dmx1->channel[j].pes_type == DMX_PES_SUBTITLE) {
+ str = "sub";
+ } else if (dmx1->channel[j].pes_type == DMX_PES_TELETEXT) {
+ str = "ttx";
+ } else if (dmx1->channel[j].pes_type == DMX_PES_TELETEXT) {
+ str = "other";
+ }
+ } else {
+ str = "sec";
+ }
+ count ++;
+ r = sprintf(buf, "id:%d, type:%s, pid:0x%0x\n", j, str, dmx1->channel[j].pid);
+ buf += r;
+ ret += r;
+ }
+ }
+ r = sprintf(buf, "used chan:%d, free chan:%d\n", count, (CHANNEL_COUNT - count));
+ buf += r;
+ ret += r;
+ mutex_unlock(&dmx->mutex);
+ }
+ return ret;
+}
+
+/*Show filter users count*/
+#define DEMUX_FILTER_USERS_FUNC_DECL(i) \
+static ssize_t demux##i##_show_filter_users(struct class *class, \
+ struct class_attribute *attr, char *buf)\
+{\
+ struct aml_dvb *dvb = &aml_dvb_device;\
+ struct aml_dmx *dmx = &dvb->dmx[i];\
+ int dmxdevfid, count;\
+ ssize_t ret = 0;\
+ unsigned long flags;\
+ spin_lock_irqsave(&dvb->slock, flags);\
+ count = 0;\
+ for (dmxdevfid = 0; dmxdevfid < dmx->dmxdev.filternum; dmxdevfid++) {\
+ if (dmx->dmxdev.filter[dmxdevfid].state >= \
+ DMXDEV_STATE_ALLOCATED)\
+ count++;\
+ } \
+ if (count > dmx->demux_filter_user) {\
+ count = dmx->demux_filter_user;\
+ } else{\
+ dmx->demux_filter_user = count;\
+ } \
+ spin_unlock_irqrestore(&dvb->slock, flags);\
+ ret = sprintf(buf, "%d\n", count);\
+ return ret;\
+} \
+static ssize_t demux##i##_store_filter_used(struct class *class, \
+ struct class_attribute *attr, const char *buf, size_t size)\
+{\
+ struct aml_dvb *dvb = &aml_dvb_device;\
+ struct aml_dmx *dmx = &dvb->dmx[i];\
+ unsigned long filter_used;\
+ unsigned long flags;/*char *endp;*/\
+ /*filter_used = simple_strtol(buf, &endp, 0);*/\
+ int ret = kstrtol(buf, 0, &filter_used);\
+ spin_lock_irqsave(&dvb->slock, flags);\
+ if (ret == 0 && filter_used) {\
+ if (dmx->demux_filter_user < FILTER_COUNT)\
+ dmx->demux_filter_user++;\
+ } else {\
+ if (dmx->demux_filter_user > 0)\
+ dmx->demux_filter_user--;\
+ } \
+ spin_unlock_irqrestore(&dvb->slock, flags);\
+ return size;\
+}
+
+/*Show ts header*/
+#define DEMUX_TS_HEADER_FUNC_DECL(i) \
+static ssize_t demux##i##_show_ts_header(struct class *class, \
+ struct class_attribute *attr, char *buf)\
+{\
+ int hdr = 0;\
+ if (i == 0)\
+ hdr = READ_MPEG_REG(TS_HEAD_1);\
+ else if (i == 1)\
+ hdr = READ_MPEG_REG(TS_HEAD_1_2);\
+ else if (i == 2)\
+ hdr = READ_MPEG_REG(TS_HEAD_1_3);\
+ return sprintf(buf, "%08x\n", hdr);\
+}
+
+/*Show channel activity*/
+#define DEMUX_CHANNEL_ACTIVITY_FUNC_DECL(i) \
+static ssize_t demux##i##_show_channel_activity(struct class *class, \
+ struct class_attribute *attr, char *buf)\
+{\
+ int f = 0;\
+ if (i == 0)\
+ f = READ_MPEG_REG(DEMUX_CHANNEL_ACTIVITY);\
+ else if (i == 1)\
+ f = READ_MPEG_REG(DEMUX_CHANNEL_ACTIVITY_2);\
+ else if (i == 2)\
+ f = READ_MPEG_REG(DEMUX_CHANNEL_ACTIVITY_3);\
+ return sprintf(buf, "%08x\n", f);\
+}
+
+#define DEMUX_RESET_FUNC_DECL(i) \
+static ssize_t demux##i##_reset_store(struct class *class, \
+ struct class_attribute *attr, \
+ const char *buf, size_t size)\
+{\
+ if (!strncmp("1", buf, 1)) { \
+ struct aml_dvb *dvb = &aml_dvb_device; \
+ pr_inf("Reset demux["#i"], call dmx_reset_dmx_hw\n"); \
+ dmx_reset_dmx_id_hw_ex(dvb, i, 0); \
+ } \
+ return size; \
+}
+
+/*DVR record mode*/
+#define DVR_MODE_FUNC_DECL(i) \
+static ssize_t dvr##i##_show_mode(struct class *class, \
+ struct class_attribute *attr, char *buf)\
+{\
+ struct aml_dvb *dvb = &aml_dvb_device;\
+ struct aml_dmx *dmx = &dvb->dmx[i];\
+ ssize_t ret = 0;\
+ char *mode;\
+ if (dmx->dump_ts_select) {\
+ mode = "ts";\
+ } else {\
+ mode = "pid";\
+ } \
+ ret = sprintf(buf, "%s\n", mode);\
+ return ret;\
+} \
+static ssize_t dvr##i##_store_mode(struct class *class, \
+ struct class_attribute *attr, const char *buf, size_t size)\
+{\
+ struct aml_dvb *dvb = &aml_dvb_device;\
+ struct aml_dmx *dmx = &dvb->dmx[i];\
+ int dump_ts_select = -1;\
+ \
+ if (!strncmp("pid", buf, 3) && dmx->dump_ts_select) {\
+ dump_ts_select = 0;\
+ } else if (!strncmp("ts", buf, 2) && !dmx->dump_ts_select) {\
+ dump_ts_select = 1;\
+ } \
+ if (dump_ts_select != -1) {\
+ aml_dmx_hw_set_dump_ts_select(\
+ aml_dvb_device.dmx[i].dmxdev.demux, dump_ts_select);\
+ } \
+ return size;\
+}
+
+#if DMX_DEV_COUNT > 0
+ DEMUX_PCR_FUNC_DECL(0)
+ DEMUX_SOURCE_FUNC_DECL(0)
+ DEMUX_FREE_FILTERS_FUNC_DECL(0)
+ DEMUX_FILTER_USERS_FUNC_DECL(0)
+ DEMUX_DEV_USERS_FUNC_DECL(0)
+ DVR_MODE_FUNC_DECL(0)
+ DEMUX_TS_HEADER_FUNC_DECL(0)
+ DEMUX_CHANNEL_ACTIVITY_FUNC_DECL(0)
+ DEMUX_RESET_FUNC_DECL(0)
+#endif
+#if DMX_DEV_COUNT > 1
+ DEMUX_PCR_FUNC_DECL(1)
+ DEMUX_SOURCE_FUNC_DECL(1)
+ DEMUX_FREE_FILTERS_FUNC_DECL(1)
+ DEMUX_FILTER_USERS_FUNC_DECL(1)
+ DEMUX_DEV_USERS_FUNC_DECL(1)
+ DVR_MODE_FUNC_DECL(1)
+ DEMUX_TS_HEADER_FUNC_DECL(1)
+ DEMUX_CHANNEL_ACTIVITY_FUNC_DECL(1)
+ DEMUX_RESET_FUNC_DECL(1)
+#endif
+#if DMX_DEV_COUNT > 2
+ DEMUX_PCR_FUNC_DECL(2)
+ DEMUX_SOURCE_FUNC_DECL(2)
+ DEMUX_FREE_FILTERS_FUNC_DECL(2)
+ DEMUX_FILTER_USERS_FUNC_DECL(2)
+ DEMUX_DEV_USERS_FUNC_DECL(2)
+ DVR_MODE_FUNC_DECL(2)
+ DEMUX_TS_HEADER_FUNC_DECL(2)
+ DEMUX_CHANNEL_ACTIVITY_FUNC_DECL(2)
+ DEMUX_RESET_FUNC_DECL(2)
+#endif
+
+/*Show the async fifo source*/
+#define ASYNCFIFO_SOURCE_FUNC_DECL(i) \
+static ssize_t asyncfifo##i##_show_source(struct class *class, \
+ struct class_attribute *attr, char *buf)\
+{\
+ struct aml_dvb *dvb = &aml_dvb_device;\
+ struct aml_asyncfifo *afifo = &dvb->asyncfifo[i];\
+ ssize_t ret = 0;\
+ char *src;\
+ if (dvb->async_fifo_total_count <= i)\
+ return ret;\
+ switch (afifo->source) {\
+ CASE_PREFIX case AM_DMX_0:\
+ src = "dmx0";\
+ break;\
+ CASE_PREFIX case AM_DMX_1:\
+ src = "dmx1";\
+ break; \
+ CASE_PREFIX case AM_DMX_2:\
+ src = "dmx2";\
+ break;\
+ CASE_PREFIX default :\
+ src = "";\
+ break;\
+ } \
+ ret = sprintf(buf, "%s\n", src);\
+ return ret;\
+} \
+static ssize_t asyncfifo##i##_store_source(struct class *class, \
+ struct class_attribute *attr, const char *buf, size_t size)\
+{\
+ enum aml_dmx_id_t src = -1;\
+ \
+ if (aml_dvb_device.async_fifo_total_count <= i)\
+ return 0;\
+ if (!strncmp("dmx0", buf, 4)) {\
+ src = AM_DMX_0;\
+ } else if (!strncmp("dmx1", buf, 4)) {\
+ src = AM_DMX_1;\
+ } else if (!strncmp("dmx2", buf, 4)) {\
+ src = AM_DMX_2;\
+ } \
+ if (src != -1) {\
+ aml_asyncfifo_hw_set_source(&aml_dvb_device.asyncfifo[i], src);\
+ } \
+ return size;\
+}
+
+#if ASYNCFIFO_COUNT > 0
+ASYNCFIFO_SOURCE_FUNC_DECL(0)
+#endif
+#if ASYNCFIFO_COUNT > 1
+ ASYNCFIFO_SOURCE_FUNC_DECL(1)
+#endif
+
+#if ASYNCFIFO_COUNT > 2
+ ASYNCFIFO_SOURCE_FUNC_DECL(2)
+#endif
+
+/*Show the async fifo flush size*/
+#define ASYNCFIFO_FLUSHSIZE_FUNC_DECL(i) \
+static ssize_t asyncfifo##i##_show_flush_size(struct class *class, \
+ struct class_attribute *attr, char *buf)\
+{\
+ struct aml_dvb *dvb = &aml_dvb_device;\
+ struct aml_asyncfifo *afifo = &dvb->asyncfifo[i];\
+ ssize_t ret = 0;\
+ if (dvb->async_fifo_total_count <= i)\
+ return ret;\
+ ret = sprintf(buf, "%d\n", afifo->flush_size);\
+ return ret;\
+} \
+static ssize_t asyncfifo##i##_store_flush_size(struct class *class, \
+ struct class_attribute *attr, \
+ const char *buf, size_t size)\
+{\
+ struct aml_dvb *dvb = &aml_dvb_device;\
+ struct aml_asyncfifo *afifo = &dvb->asyncfifo[i];\
+ /*int fsize = simple_strtol(buf, NULL, 10);*/\
+ int fsize = 0;\
+ long value;\
+ int ret =0;\
+ if (dvb->async_fifo_total_count <= i)\
+ return (size_t)0;\
+ ret = kstrtol(buf, 0, &value);\
+ if (ret == 0)\
+ fsize = value;\
+ if (fsize != afifo->flush_size) {\
+ afifo->flush_size = fsize;\
+ aml_asyncfifo_hw_reset(&aml_dvb_device.asyncfifo[i]);\
+ } \
+ return size;\
+}
+
+#if ASYNCFIFO_COUNT > 0
+ASYNCFIFO_FLUSHSIZE_FUNC_DECL(0)
+#endif
+
+#if ASYNCFIFO_COUNT > 1
+ ASYNCFIFO_FLUSHSIZE_FUNC_DECL(1)
+#endif
+
+#if ASYNCFIFO_COUNT > 2
+ ASYNCFIFO_FLUSHSIZE_FUNC_DECL(2)
+#endif
+
+/*Show the async fifo secure buffer addr*/
+#define ASYNCFIFO_SECUREADDR_FUNC_DECL(i) \
+static ssize_t asyncfifo##i##_show_secure_addr(struct class *class, \
+ struct class_attribute *attr, char *buf)\
+{\
+ struct aml_dvb *dvb = &aml_dvb_device;\
+ struct aml_asyncfifo *afifo = &dvb->asyncfifo[i];\
+ ssize_t ret = 0;\
+ if (dvb->async_fifo_total_count <= i)\
+ return ret;\
+ ret = sprintf(buf, "0x%x\n", afifo->blk.addr);\
+ return ret;\
+} \
+static ssize_t asyncfifo##i##_store_secure_addr(struct class *class, \
+ struct class_attribute *attr, \
+const char *buf, size_t size)\
+{\
+ struct aml_dvb *dvb = &aml_dvb_device;\
+ struct aml_asyncfifo *afifo = &dvb->asyncfifo[i];\
+ unsigned long value;\
+ int ret=0;\
+ if (dvb->async_fifo_total_count <= i)\
+ return (size_t)0;\
+ ret = kstrtol(buf, 0, &value);\
+ if (ret == 0 && value != afifo->blk.addr) {\
+ afifo->blk.addr = value;\
+ aml_asyncfifo_hw_reset(&aml_dvb_device.asyncfifo[i]);\
+ } \
+ return size;\
+}
+
+#if ASYNCFIFO_COUNT > 0
+ ASYNCFIFO_SECUREADDR_FUNC_DECL(0)
+#endif
+
+#if ASYNCFIFO_COUNT > 1
+ ASYNCFIFO_SECUREADDR_FUNC_DECL(1)
+#endif
+
+#if ASYNCFIFO_COUNT > 2
+ ASYNCFIFO_SECUREADDR_FUNC_DECL(2)
+#endif
+
+/*Show the async fifo secure buffer size*/
+#define ASYNCFIFO_SECUREADDR_SIZE_FUNC_DECL(i) \
+static ssize_t asyncfifo##i##_show_secure_addr_size(struct class *class, \
+ struct class_attribute *attr, char *buf)\
+{\
+ struct aml_dvb *dvb = &aml_dvb_device;\
+ struct aml_asyncfifo *afifo = &dvb->asyncfifo[i];\
+ ssize_t ret = 0;\
+ if (dvb->async_fifo_total_count <= i)\
+ return ret;\
+ ret = sprintf(buf, "0x%x\n", afifo->blk.len);\
+ return ret;\
+} \
+static ssize_t asyncfifo##i##_store_secure_addr_size(struct class *class, \
+ struct class_attribute *attr, \
+const char *buf, size_t size)\
+{\
+ struct aml_dvb *dvb = &aml_dvb_device;\
+ struct aml_asyncfifo *afifo = &dvb->asyncfifo[i];\
+ unsigned long value;\
+ int ret=0;\
+ if (dvb->async_fifo_total_count <= i)\
+ return (size_t)0;\
+ ret = kstrtol(buf, 0, &value);\
+ if (ret == 0 && value != afifo->blk.len) {\
+ afifo->blk.len = value;\
+ aml_asyncfifo_hw_reset(&aml_dvb_device.asyncfifo[i]);\
+ } \
+ return size;\
+}
+
+#if ASYNCFIFO_COUNT > 0
+ ASYNCFIFO_SECUREADDR_SIZE_FUNC_DECL(0)
+#endif
+
+#if ASYNCFIFO_COUNT > 1
+ ASYNCFIFO_SECUREADDR_SIZE_FUNC_DECL(1)
+#endif
+
+#if ASYNCFIFO_COUNT > 2
+ ASYNCFIFO_SECUREADDR_SIZE_FUNC_DECL(2)
+#endif
+
+
+/*Show the async fifo secure enable*/
+#define ASYNCFIFO_SECURENABLE_FUNC_DECL(i) \
+static ssize_t asyncfifo##i##_show_secure_enable(struct class *class, \
+ struct class_attribute *attr, char *buf)\
+{\
+ struct aml_dvb *dvb = &aml_dvb_device;\
+ struct aml_asyncfifo *afifo = &dvb->asyncfifo[i];\
+ ssize_t ret = 0;\
+ if (dvb->async_fifo_total_count <= i)\
+ return ret;\
+ ret = sprintf(buf, "%d\n", afifo->secure_enable);\
+ return ret;\
+} \
+static ssize_t asyncfifo##i##_store_secure_enable(struct class *class, \
+ struct class_attribute *attr, \
+ const char *buf, size_t size)\
+{\
+ struct aml_dvb *dvb = &aml_dvb_device;\
+ struct aml_asyncfifo *afifo = &dvb->asyncfifo[i];\
+ int enable = 0;\
+ long value;\
+ int ret=0;\
+ if (dvb->async_fifo_total_count <= i)\
+ return (size_t)0;\
+ ret = kstrtol(buf, 0, &value);\
+ if (ret == 0)\
+ enable = value;\
+ if (enable != afifo->secure_enable) {\
+ afifo->secure_enable = enable;\
+ aml_asyncfifo_hw_reset(&aml_dvb_device.asyncfifo[i]);\
+ } \
+ return size;\
+}
+
+#if ASYNCFIFO_COUNT > 0
+ASYNCFIFO_SECURENABLE_FUNC_DECL(0)
+#endif
+
+#if ASYNCFIFO_COUNT > 1
+ ASYNCFIFO_SECURENABLE_FUNC_DECL(1)
+#endif
+
+#if ASYNCFIFO_COUNT > 2
+ ASYNCFIFO_SECURENABLE_FUNC_DECL(2)
+#endif
+
+/*Reset the Demux*/
+static ssize_t demux_do_reset(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ if (!strncmp("1", buf, 1)) {
+ struct aml_dvb *dvb = &aml_dvb_device;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+ pr_inf("Reset demux, call dmx_reset_hw\n");
+ dmx_reset_hw_ex(dvb, 0);
+ spin_unlock_irqrestore(&dvb->slock, flags);
+ }
+
+ return size;
+}
+
+/*Show the Video PTS value*/
+static ssize_t demux_show_video_pts(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ ssize_t ret = 0;
+
+ ret = sprintf(buf, "%u\n", aml_dmx_get_video_pts(dvb));
+
+ return ret;
+}
+
+/*Show the Audio PTS value*/
+static ssize_t demux_show_audio_pts(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ ssize_t ret = 0;
+
+ ret = sprintf(buf, "%u\n", aml_dmx_get_audio_pts(dvb));
+
+ return ret;
+}
+
+/*Show the Video PTS bit32 value*/
+static ssize_t demux_show_video_pts_bit32(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ ssize_t ret = 0;
+
+ ret = sprintf(buf, "%u\n", aml_dmx_get_video_pts_bit32(dvb));
+
+ return ret;
+}
+
+/*Show the Audio PTS bit32 value*/
+static ssize_t demux_show_audio_pts_bit32(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ ssize_t ret = 0;
+
+ ret = sprintf(buf, "%u\n", aml_dmx_get_audio_pts_bit32(dvb));
+
+ return ret;
+}
+
+/*Show the 33bit Video PTS value*/
+static ssize_t demux_show_video_pts_u64(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ ssize_t ret = 0;
+
+ u64 pts_val = aml_dmx_get_video_pts(dvb);
+ pts_val &= 0x00000000FFFFFFFF;
+
+ if (aml_dmx_get_video_pts_bit32(dvb)) {
+ pts_val = pts_val | (1LL<<32);
+ }
+
+ ret = sprintf(buf, "%llu\n", pts_val);
+
+ return ret;
+}
+
+/*Show the 33bit Audio PTS value*/
+static ssize_t demux_show_audio_pts_u64(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ ssize_t ret = 0;
+
+ u64 pts_val = aml_dmx_get_audio_pts(dvb);
+ pts_val &= 0x00000000FFFFFFFF;
+
+ if (aml_dmx_get_audio_pts_bit32(dvb)) {
+ pts_val = pts_val | (1LL<<32);
+ }
+
+ ret = sprintf(buf, "%llu\n", pts_val);
+
+ return ret;
+}
+
+/*Show the First Video PTS value*/
+static ssize_t demux_show_first_video_pts(struct class *class,
+ struct class_attribute *attr,
+ char *buf)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ ssize_t ret = 0;
+
+ ret = sprintf(buf, "%u\n", aml_dmx_get_first_video_pts(dvb));
+
+ return ret;
+}
+
+/*Show the First Audio PTS value*/
+static ssize_t demux_show_first_audio_pts(struct class *class,
+ struct class_attribute *attr,
+ char *buf)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ ssize_t ret = 0;
+
+ ret = sprintf(buf, "%u\n", aml_dmx_get_first_audio_pts(dvb));
+
+ return ret;
+}
+
+static ssize_t stb_show_hw_setting(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ int r, total = 0;
+ int i;
+ struct aml_dvb *dvb = &aml_dvb_device;
+ int invert, ctrl;
+
+ for (i = 0; i < dvb->ts_in_total_count; i++) {
+ struct aml_ts_input *ts = &dvb->ts[i];
+
+ if (ts->s2p_id != -1)
+ invert = dvb->s2p[ts->s2p_id].invert;
+ else
+ invert = 0;
+
+ ctrl = ts->control;
+
+ r = sprintf(buf, "ts%d %s control: 0x%x invert: 0x%x\n", i,
+ ts->mode == AM_TS_DISABLE ? "disable" :
+ (ts->mode == AM_TS_SERIAL ? "serial" :
+ "parallel"), ctrl, invert);
+ buf += r;
+ total += r;
+ }
+
+ return total;
+}
+
+static ssize_t stb_store_hw_setting(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t count)
+{
+ int id, ctrl, invert, r, mode;
+ char mname[32];
+ char pname[32];
+ unsigned long flags;
+ struct aml_ts_input *ts;
+ struct aml_dvb *dvb = &aml_dvb_device;
+
+ r = sscanf(buf, "%d %s %x %x", &id, mname, &ctrl, &invert);
+ if (r != 4)
+ return -EINVAL;
+
+ if (id < 0 || id >= dvb->ts_in_total_count)
+ return -EINVAL;
+
+ if ((mname[0] == 's') || (mname[0] == 'S')) {
+ sprintf(pname, "s_ts%d", id);
+ mode = AM_TS_SERIAL;
+ } else if ((mname[0] == 'p') || (mname[0] == 'P')) {
+ sprintf(pname, "p_ts%d", id);
+ mode = AM_TS_PARALLEL;
+ } else
+ mode = AM_TS_DISABLE;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+
+ ts = &dvb->ts[id];
+
+ if ((mode == AM_TS_SERIAL) && (ts->mode != AM_TS_SERIAL)) {
+ int i;
+ int scnt = 0;
+
+ for (i = 0; i < dvb->ts_in_total_count; i++) {
+ if (dvb->ts[i].s2p_id != -1)
+ scnt++;
+ }
+
+ if (scnt >= dvb->s2p_total_count)
+ pr_error("no free s2p\n");
+ else
+ ts->s2p_id = scnt;
+ }
+
+ if ((mode != AM_TS_SERIAL) || (ts->s2p_id != -1)) {
+ if (ts->pinctrl) {
+ devm_pinctrl_put(ts->pinctrl);
+ ts->pinctrl = NULL;
+ }
+
+ ts->pinctrl = devm_pinctrl_get_select(&dvb->pdev->dev, pname);
+/* if(IS_ERR_VALUE(ts->pinctrl))*/
+/* ts->pinctrl = NULL;*/
+ ts->mode = mode;
+ ts->control = ctrl;
+
+ if (mode == AM_TS_SERIAL)
+ dvb->s2p[ts->s2p_id].invert = invert;
+ else
+ ts->s2p_id = -1;
+ }
+
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return count;
+}
+
+static struct class_attribute aml_stb_class_attrs[] = {
+ __ATTR(hw_setting, 0664, stb_show_hw_setting,
+ stb_store_hw_setting),
+ __ATTR(source, 0664, stb_show_source,
+ stb_store_source),
+ __ATTR(demux_reset_all_flag, 0664, show_dmx_reset_all_flag,
+ set_dmx_reset_all_flag),
+ __ATTR(tso_source, 0644, tso_show_source,
+ tso_store_source),
+#define DEMUX_SOURCE_ATTR_PCR(i)\
+ __ATTR(demux##i##_pcr, 0644, demux##i##_show_pcr, NULL)
+#define DEMUX_SOURCE_ATTR_DECL(i)\
+ __ATTR(demux##i##_source, 0664,\
+ demux##i##_show_source, demux##i##_store_source)
+#define DEMUX_FREE_FILTERS_ATTR_DECL(i)\
+ __ATTR(demux##i##_free_filters, 0644, \
+ demux##i##_show_free_filters, NULL)
+#define DEMUX_FILTER_USERS_ATTR_DECL(i)\
+ __ATTR(demux##i##_filter_users, 0644, \
+ demux##i##_show_filter_users, demux##i##_store_filter_used)
+#define DEMUX_DEV_USERS_ATTR_DECL(i)\
+ __ATTR(demux##i##_dev_users, 0644, \
+ demux##i##_show_dev_users, NULL)
+#define DVR_MODE_ATTR_DECL(i)\
+ __ATTR(dvr##i##_mode, 0644, dvr##i##_show_mode, \
+ dvr##i##_store_mode)
+#define DEMUX_TS_HEADER_ATTR_DECL(i)\
+ __ATTR(demux##i##_ts_header, 0644, \
+ demux##i##_show_ts_header, NULL)
+#define DEMUX_CHANNEL_ACTIVITY_ATTR_DECL(i)\
+ __ATTR(demux##i##_channel_activity, 0644, \
+ demux##i##_show_channel_activity, NULL)
+#define DMX_RESET_ATTR_DECL(i)\
+ __ATTR(demux##i##_reset, 0644, NULL, \
+ demux##i##_reset_store)
+
+#if DMX_DEV_COUNT > 0
+ DEMUX_SOURCE_ATTR_PCR(0),
+ DEMUX_SOURCE_ATTR_DECL(0),
+ DEMUX_FREE_FILTERS_ATTR_DECL(0),
+ DEMUX_FILTER_USERS_ATTR_DECL(0),
+ DEMUX_DEV_USERS_ATTR_DECL(0),
+ DVR_MODE_ATTR_DECL(0),
+ DEMUX_TS_HEADER_ATTR_DECL(0),
+ DEMUX_CHANNEL_ACTIVITY_ATTR_DECL(0),
+ DMX_RESET_ATTR_DECL(0),
+#endif
+#if DMX_DEV_COUNT > 1
+ DEMUX_SOURCE_ATTR_PCR(1),
+ DEMUX_SOURCE_ATTR_DECL(1),
+ DEMUX_FREE_FILTERS_ATTR_DECL(1),
+ DEMUX_FILTER_USERS_ATTR_DECL(1),
+ DEMUX_DEV_USERS_ATTR_DECL(1),
+ DVR_MODE_ATTR_DECL(1),
+ DEMUX_TS_HEADER_ATTR_DECL(1),
+ DEMUX_CHANNEL_ACTIVITY_ATTR_DECL(1),
+ DMX_RESET_ATTR_DECL(1),
+#endif
+#if DMX_DEV_COUNT > 2
+ DEMUX_SOURCE_ATTR_PCR(2),
+ DEMUX_SOURCE_ATTR_DECL(2),
+ DEMUX_FREE_FILTERS_ATTR_DECL(2),
+ DEMUX_FILTER_USERS_ATTR_DECL(2),
+ DEMUX_DEV_USERS_ATTR_DECL(2),
+ DVR_MODE_ATTR_DECL(2),
+ DEMUX_TS_HEADER_ATTR_DECL(2),
+ DEMUX_CHANNEL_ACTIVITY_ATTR_DECL(2),
+ DMX_RESET_ATTR_DECL(2),
+#endif
+
+#define ASYNCFIFO_SOURCE_ATTR_DECL(i)\
+ __ATTR(asyncfifo##i##_source, 0664, \
+ asyncfifo##i##_show_source, asyncfifo##i##_store_source)
+#define ASYNCFIFO_FLUSHSIZE_ATTR_DECL(i)\
+ __ATTR(asyncfifo##i##_flush_size, 0664,\
+ asyncfifo##i##_show_flush_size, \
+ asyncfifo##i##_store_flush_size)
+#define ASYNCFIFO_SECUREADDR_ATTR_DECL(i)\
+ __ATTR(asyncfifo##i##_secure_addr, S_IRUGO | S_IWUSR | S_IWGRP,\
+ asyncfifo##i##_show_secure_addr, \
+ asyncfifo##i##_store_secure_addr)
+#define ASYNCFIFO_SECUREADDR_SIZE_ATTR_DECL(i)\
+ __ATTR(asyncfifo##i##_secure_addr_size, S_IRUGO | S_IWUSR | S_IWGRP,\
+ asyncfifo##i##_show_secure_addr_size, \
+ asyncfifo##i##_store_secure_addr_size)
+#define ASYNCFIFO_SECURENABLE_ATTR_DECL(i)\
+ __ATTR(asyncfifo##i##_secure_enable, S_IRUGO | S_IWUSR | S_IWGRP,\
+ asyncfifo##i##_show_secure_enable, \
+ asyncfifo##i##_store_secure_enable)
+
+#if ASYNCFIFO_COUNT > 0
+ ASYNCFIFO_SOURCE_ATTR_DECL(0),
+ ASYNCFIFO_FLUSHSIZE_ATTR_DECL(0),
+ ASYNCFIFO_SECUREADDR_ATTR_DECL(0),
+ ASYNCFIFO_SECUREADDR_SIZE_ATTR_DECL(0),
+ ASYNCFIFO_SECURENABLE_ATTR_DECL(0),
+#endif
+#if ASYNCFIFO_COUNT > 1
+ ASYNCFIFO_SOURCE_ATTR_DECL(1),
+ ASYNCFIFO_FLUSHSIZE_ATTR_DECL(1),
+ ASYNCFIFO_SECUREADDR_ATTR_DECL(1),
+ ASYNCFIFO_SECUREADDR_SIZE_ATTR_DECL(1),
+ ASYNCFIFO_SECURENABLE_ATTR_DECL(1),
+#endif
+
+#if ASYNCFIFO_COUNT > 2
+ ASYNCFIFO_SOURCE_ATTR_DECL(2),
+ ASYNCFIFO_FLUSHSIZE_ATTR_DECL(2),
+ ASYNCFIFO_SECUREADDR_ATTR_DECL(2),
+ ASYNCFIFO_SECUREADDR_SIZE_ATTR_DECL(2),
+ ASYNCFIFO_SECURENABLE_ATTR_DECL(2),
+#endif
+
+ __ATTR(demux_reset, 0644, NULL, demux_do_reset),
+ __ATTR(video_pts, 0664, demux_show_video_pts,
+ NULL),
+ __ATTR(audio_pts, 0664, demux_show_audio_pts,
+ NULL),
+ __ATTR(video_pts_bit32, 0644, demux_show_video_pts_bit32, NULL),
+ __ATTR(audio_pts_bit32, 0644, demux_show_audio_pts_bit32, NULL),
+ __ATTR(video_pts_u64, 0644, demux_show_video_pts_u64, NULL),
+ __ATTR(audio_pts_u64, 0644, demux_show_audio_pts_u64, NULL),
+ __ATTR(first_video_pts, 0644, demux_show_first_video_pts,
+ NULL),
+ __ATTR(first_audio_pts, 0644, demux_show_first_audio_pts,
+ NULL),
+ __ATTR(clear_av, 0644, NULL, stb_clear_av),
+ __ATTR(demux_state, 0644, demux_state_show, NULL),
+
+#define DSC_SOURCE_ATTR_DECL(i)\
+ __ATTR(dsc##i##_source, 0664,\
+ dsc##i##_show_source, dsc##i##_store_source)
+#define DSC_FREE_ATTR_DECL(i) \
+ __ATTR(dsc##i##_free_dscs, 0644, \
+ dsc##i##_show_free_dscs, NULL)
+
+#if DSC_DEV_COUNT > 0
+ DSC_SOURCE_ATTR_DECL(0),
+ DSC_FREE_ATTR_DECL(0),
+#endif
+#if DSC_DEV_COUNT > 1
+ DSC_SOURCE_ATTR_DECL(1),
+ DSC_FREE_ATTR_DECL(1),
+#endif
+
+ __ATTR_NULL
+};
+
+static struct class aml_stb_class = {
+ .name = "stb",
+ .class_attrs = aml_stb_class_attrs,
+};
+
+/*
+ *extern int aml_regist_dmx_class(void);
+ *extern int aml_unregist_dmx_class(void);
+ */
+/*
+ *void afifo_reset(int v)
+ *{
+ * if (v)
+ * reset_control_assert(aml_dvb_afifo_reset_ctl);
+ * else
+ * reset_control_deassert(aml_dvb_afifo_reset_ctl);
+ *}
+ */
+
+static int aml_dvb_probe(struct platform_device *pdev)
+{
+ struct aml_dvb *advb;
+ int i, ret = 0;
+ struct devio_aml_platform_data *pd_dvb;
+
+ pr_inf("probe amlogic dvb driver [%s]\n", DVB_VERSION);
+
+ /*switch_mod_gate_by_name("demux", 1); */
+#if 0
+ /*no used reset ctl to set clk*/
+ aml_dvb_demux_reset_ctl =
+ devm_reset_control_get(&pdev->dev, "demux");
+ pr_inf("dmx rst ctl = %p\n", aml_dvb_demux_reset_ctl);
+ reset_control_deassert(aml_dvb_demux_reset_ctl);
+
+ aml_dvb_afifo_reset_ctl =
+ devm_reset_control_get(&pdev->dev, "asyncfifo");
+ pr_inf("asyncfifo rst ctl = %p\n", aml_dvb_afifo_reset_ctl);
+ reset_control_deassert(aml_dvb_afifo_reset_ctl);
+
+ aml_dvb_ahbarb0_reset_ctl =
+ devm_reset_control_get(&pdev->dev, "ahbarb0");
+ pr_inf("ahbarb0 rst ctl = %p\n", aml_dvb_ahbarb0_reset_ctl);
+ reset_control_deassert(aml_dvb_ahbarb0_reset_ctl);
+
+ aml_dvb_uparsertop_reset_ctl =
+ devm_reset_control_get(&pdev->dev, "uparsertop");
+ pr_inf("uparsertop rst ctl = %p\n", aml_dvb_uparsertop_reset_ctl);
+ reset_control_deassert(aml_dvb_uparsertop_reset_ctl);
+#else
+
+ if (get_cpu_type() < MESON_CPU_MAJOR_ID_G12A)
+ {
+ aml_dvb_demux_clk =
+ devm_clk_get(&pdev->dev, "demux");
+ if (IS_ERR_OR_NULL(aml_dvb_demux_clk)) {
+ dev_err(&pdev->dev, "get demux clk fail\n");
+ return -1;
+ }
+ clk_prepare_enable(aml_dvb_demux_clk);
+
+ aml_dvb_afifo_clk =
+ devm_clk_get(&pdev->dev, "asyncfifo");
+ if (IS_ERR_OR_NULL(aml_dvb_afifo_clk)) {
+ dev_err(&pdev->dev, "get asyncfifo clk fail\n");
+ return -1;
+ }
+ clk_prepare_enable(aml_dvb_afifo_clk);
+
+ aml_dvb_ahbarb0_clk =
+ devm_clk_get(&pdev->dev, "ahbarb0");
+ if (IS_ERR_OR_NULL(aml_dvb_ahbarb0_clk)) {
+ dev_err(&pdev->dev, "get ahbarb0 clk fail\n");
+ return -1;
+ }
+ clk_prepare_enable(aml_dvb_ahbarb0_clk);
+
+ aml_dvb_uparsertop_clk =
+ devm_clk_get(&pdev->dev, "uparsertop");
+ if (IS_ERR_OR_NULL(aml_dvb_uparsertop_clk)) {
+ dev_err(&pdev->dev, "get uparsertop clk fail\n");
+ return -1;
+ }
+ clk_prepare_enable(aml_dvb_uparsertop_clk);
+ }
+ else
+ {
+ amports_switch_gate("demux", 1);
+ amports_switch_gate("ahbarb0", 1);
+ amports_switch_gate("parser_top", 1);
+ if (get_cpu_type() == MESON_CPU_MAJOR_ID_TL1)
+ {
+ aml_dvb_afifo_clk =
+ devm_clk_get(&pdev->dev, "asyncfifo");
+ if (IS_ERR_OR_NULL(aml_dvb_afifo_clk)) {
+ dev_err(&pdev->dev, "get asyncfifo clk fail\n");
+ return -1;
+ }
+ clk_prepare_enable(aml_dvb_afifo_clk);
+ }
+ }
+#endif
+ advb = &aml_dvb_device;
+ memset(advb, 0, sizeof(aml_dvb_device));
+
+ spin_lock_init(&advb->slock);
+
+ advb->dev = &pdev->dev;
+ advb->pdev = pdev;
+ advb->stb_source = -1;
+ advb->tso_source = -1;
+
+ if (get_cpu_type() < MESON_CPU_MAJOR_ID_TL1) {
+ advb->ts_in_total_count = 3;
+ advb->s2p_total_count = 2;
+ advb->async_fifo_total_count = 2;
+ } else {
+ advb->ts_in_total_count = 4;
+ advb->s2p_total_count = 3;
+ advb->async_fifo_total_count = 3;
+ }
+
+ for (i = 0; i < DMX_DEV_COUNT; i++) {
+ advb->dmx[i].dmx_irq = -1;
+ advb->dmx[i].dvr_irq = -1;
+ }
+
+#ifdef CONFIG_OF
+ if (pdev->dev.of_node) {
+ int s2p_id = 0;
+ char buf[32];
+ const char *str;
+ u32 value;
+
+ for (i = 0; i < advb->ts_in_total_count; i++) {
+
+ advb->ts[i].mode = AM_TS_DISABLE;
+ advb->ts[i].s2p_id = -1;
+ advb->ts[i].pinctrl = NULL;
+ memset(buf, 0, 32);
+ snprintf(buf, sizeof(buf), "ts%d", i);
+ ret =
+ of_property_read_string(pdev->dev.of_node, buf,
+ &str);
+ if (!ret) {
+ if (!strcmp(str, "serial")) {
+ pr_dbg("%s: serial\n", buf);
+
+ if (s2p_id >= advb->s2p_total_count)
+ pr_error("no free s2p\n");
+ else {
+ snprintf(buf, sizeof(buf),
+ "s_ts%d", i);
+ advb->ts[i].mode = AM_TS_SERIAL;
+ advb->ts[i].pinctrl =
+ devm_pinctrl_get_select
+ (&pdev->dev, buf);
+ advb->ts[i].s2p_id = s2p_id;
+
+ s2p_id++;
+ }
+ } else if (!strcmp(str, "parallel")) {
+ pr_dbg("%s: parallel\n", buf);
+ memset(buf, 0, 32);
+ snprintf(buf, sizeof(buf), "p_ts%d", i);
+ advb->ts[i].mode = AM_TS_PARALLEL;
+ advb->ts[i].pinctrl =
+ devm_pinctrl_get_select(&pdev->dev,
+ buf);
+ } else {
+ advb->ts[i].mode = AM_TS_DISABLE;
+ advb->ts[i].pinctrl = NULL;
+ }
+
+ /* if(IS_ERR_VALUE(advb->ts[i].pinctrl)) */
+ /* advb->ts[i].pinctrl = NULL; */
+ }
+ memset(buf, 0, 32);
+ snprintf(buf, sizeof(buf), "ts%d_control", i);
+ ret =
+ of_property_read_u32(pdev->dev.of_node, buf,
+ &value);
+ if (!ret) {
+ pr_dbg("%s: 0x%x\n", buf, value);
+ advb->ts[i].control = value;
+ } else {
+ pr_dbg("read error:%s: 0x%x\n", buf, value);
+ }
+
+ if (advb->ts[i].s2p_id != -1) {
+ memset(buf, 0, 32);
+ snprintf(buf, sizeof(buf), "ts%d_invert", i);
+ ret =
+ of_property_read_u32(pdev->dev.of_node, buf,
+ &value);
+ if (!ret) {
+ pr_dbg("%s: 0x%x\n", buf, value);
+ advb->s2p[advb->ts[i].s2p_id].invert =
+ value;
+ }
+ }
+ }
+ memset(buf, 0, 32);
+ snprintf(buf, sizeof(buf), "ts_out_invert");
+ ret =
+ of_property_read_u32(pdev->dev.of_node, buf,
+ &value);
+ if (!ret) {
+ pr_dbg("%s: 0x%x\n", buf, value);
+ advb->ts_out_invert = value;
+ }
+ }
+#endif
+
+ pd_dvb = (struct devio_aml_platform_data *)advb->dev->platform_data;
+
+ ret =
+ dvb_register_adapter(&advb->dvb_adapter, CARD_NAME, THIS_MODULE,
+ advb->dev, adapter_nr);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < DMX_DEV_COUNT; i++)
+ advb->dmx[i].id = -1;
+
+ for (i = 0; i<DSC_DEV_COUNT; i++)
+ advb->dsc[i].id = -1;
+
+ for (i = 0; i < advb->async_fifo_total_count; i++)
+ advb->asyncfifo[i].id = -1;
+
+ advb->dvb_adapter.priv = advb;
+ dev_set_drvdata(advb->dev, advb);
+
+ for (i = 0; i < DSC_DEV_COUNT; i++) {
+ ret = aml_dvb_dsc_init(advb, &advb->dsc[i], i);
+ if (ret < 0)
+ goto error;
+ }
+
+ for (i = 0; i < DMX_DEV_COUNT; i++) {
+ ret = aml_dvb_dmx_init(advb, &advb->dmx[i], i);
+ if (ret < 0)
+ goto error;
+ }
+
+ /*Init the async fifos */
+ for (i = 0; i < advb->async_fifo_total_count; i++) {
+ ret = aml_dvb_asyncfifo_init(advb, &advb->asyncfifo[i], i);
+ if (ret < 0)
+ goto error;
+ }
+
+ aml_regist_dmx_class();
+
+ if (class_register(&aml_stb_class) < 0) {
+ pr_error("dvb register class error\n");
+ goto error;
+ }
+
+ aml_register_parser_mconfig();
+#ifdef ENABLE_DEMUX_DRIVER
+ tsdemux_set_ops(&aml_tsdemux_ops);
+#else
+ tsdemux_set_ops(NULL);
+#endif
+
+#if (defined CONFIG_AMLOGIC_DVB_EXTERN)
+ ret = dvb_extern_register_frontend(&advb->dvb_adapter);
+ if (ret) {
+ pr_error("aml register dvb frontend failed\n");
+ goto error;
+ }
+#endif
+
+ return 0;
+
+error:
+ for (i = 0; i < advb->async_fifo_total_count; i++) {
+ if (advb->asyncfifo[i].id != -1)
+ aml_dvb_asyncfifo_release(advb, &advb->asyncfifo[i]);
+ }
+
+ for (i = 0; i < DMX_DEV_COUNT; i++) {
+ if (advb->dmx[i].id != -1)
+ aml_dvb_dmx_release(advb, &advb->dmx[i]);
+ }
+
+ for (i = 0; i < DSC_DEV_COUNT; i++) {
+ if (advb->dsc[i].id != -1)
+ aml_dvb_dsc_release(advb, &advb->dsc[i]);
+ }
+
+ dvb_unregister_adapter(&advb->dvb_adapter);
+
+ return ret;
+}
+static int aml_dvb_remove(struct platform_device *pdev)
+{
+ struct aml_dvb *advb = (struct aml_dvb *)dev_get_drvdata(&pdev->dev);
+ int i;
+
+ pr_inf("[dmx_kpi] %s Enter.\n", __func__);
+
+#if (defined CONFIG_AMLOGIC_DVB_EXTERN)
+ dvb_extern_unregister_frontend();
+#endif
+
+ tsdemux_set_ops(NULL);
+
+ aml_unregist_dmx_class();
+ class_unregister(&aml_stb_class);
+
+ for (i = 0; i < advb->async_fifo_total_count; i++) {
+ if (advb->asyncfifo[i].id != -1)
+ aml_dvb_asyncfifo_release(advb, &advb->asyncfifo[i]);
+ }
+
+ for (i = 0; i < DMX_DEV_COUNT; i++) {
+ pr_error("remove demx %d, id is %d\n",i,advb->dmx[i].id);
+ if (advb->dmx[i].id != -1)
+ aml_dvb_dmx_release(advb, &advb->dmx[i]);
+ }
+
+ for (i = 0; i < DSC_DEV_COUNT; i++) {
+ if (advb->dsc[i].id != -1)
+ aml_dvb_dsc_release(advb, &advb->dsc[i]);
+ }
+ dvb_unregister_adapter(&advb->dvb_adapter);
+
+ for (i = 0; i < advb->ts_in_total_count; i++) {
+ if (advb->ts[i].pinctrl && !IS_ERR_VALUE(advb->ts[i].pinctrl))
+ devm_pinctrl_put(advb->ts[i].pinctrl);
+ }
+
+ /*switch_mod_gate_by_name("demux", 0); */
+#if 0
+ reset_control_assert(aml_dvb_uparsertop_reset_ctl);
+ reset_control_assert(aml_dvb_ahbarb0_reset_ctl);
+ reset_control_assert(aml_dvb_afifo_reset_ctl);
+ reset_control_assert(aml_dvb_demux_reset_ctl);
+#else
+#if 1
+ if (get_cpu_type() < MESON_CPU_MAJOR_ID_G12A)
+ {
+ clk_disable_unprepare(aml_dvb_uparsertop_clk);
+ clk_disable_unprepare(aml_dvb_ahbarb0_clk);
+ clk_disable_unprepare(aml_dvb_afifo_clk);
+ clk_disable_unprepare(aml_dvb_demux_clk);
+ }
+ else
+ {
+ amports_switch_gate("demux", 0);
+ amports_switch_gate("ahbarb0", 0);
+ amports_switch_gate("parser_top", 0);
+
+ if (get_cpu_type() == MESON_CPU_MAJOR_ID_TL1) {
+ clk_disable_unprepare(aml_dvb_afifo_clk);
+ }
+ }
+#endif
+#endif
+
+ pr_inf("[dmx_kpi] %s Exit.\n", __func__);
+ return 0;
+}
+
+static int aml_dvb_suspend(struct platform_device *dev, pm_message_t state)
+{
+ return 0;
+}
+
+static int aml_dvb_resume(struct platform_device *dev)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ int i;
+
+ for (i = 0; i < DMX_DEV_COUNT; i++)
+ dmx_reset_dmx_id_hw_ex(dvb, i, 0);
+
+ pr_inf("dvb resume\n");
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id aml_dvb_dt_match[] = {
+ {
+ .compatible = "amlogic, dvb-demux",
+ },
+ {},
+};
+#endif /*CONFIG_OF */
+
+static struct platform_driver aml_dvb_driver = {
+ .probe = aml_dvb_probe,
+ .remove = aml_dvb_remove,
+ .suspend = aml_dvb_suspend,
+ .resume = aml_dvb_resume,
+ .driver = {
+ .name = "amlogic-dvb-demux",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_OF
+ .of_match_table = aml_dvb_dt_match,
+#endif
+ }
+};
+
+static int __init aml_dvb_init(void)
+{
+ return platform_driver_register(&aml_dvb_driver);
+}
+
+static void __exit aml_dvb_exit(void)
+{
+ pr_inf("aml dvb exit\n");
+ platform_driver_unregister(&aml_dvb_driver);
+}
+
+/*Get the STB source demux*/
+static struct aml_dmx *get_stb_dmx(void)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ struct aml_dmx *dmx = NULL;
+ int i;
+
+ switch (dvb->stb_source) {
+ case AM_TS_SRC_DMX0:
+ dmx = &dvb->dmx[0];
+ break;
+ case AM_TS_SRC_DMX1:
+ dmx = &dvb->dmx[1];
+ break;
+ case AM_TS_SRC_DMX2:
+ dmx = &dvb->dmx[2];
+ break;
+ default:
+ for (i = 0; i < DMX_DEV_COUNT; i++) {
+ dmx = &dvb->dmx[i];
+ if (dmx->source == dvb->stb_source)
+ return dmx;
+ }
+ break;
+ }
+
+ return dmx;
+}
+
+static int aml_tsdemux_reset(void)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ unsigned long flags;
+ pr_inf("[dmx_kpi] %s Enter\n", __func__);
+
+ spin_lock_irqsave(&dvb->slock, flags);
+ if (dvb->reset_flag) {
+ struct aml_dmx *dmx = get_stb_dmx();
+
+ dvb->reset_flag = 0;
+ if (dmx) {
+ if (dmx_reset_all_flag)
+ dmx_reset_hw_ex(dvb, 0);
+ else
+ dmx_reset_dmx_hw_ex_unlock(dvb, dmx, 0);
+ }
+ }
+ spin_unlock_irqrestore(&dvb->slock, flags);
+ pr_inf("[dmx_kpi] %s Exit\n", __func__);
+ return 0;
+}
+
+static int aml_tsdemux_set_reset_flag(void)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+ dvb->reset_flag = 1;
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return 0;
+
+}
+
+/*Add the amstream irq handler*/
+static int aml_tsdemux_request_irq(irq_handler_t handler, void *data)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ struct aml_dmx *dmx;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+
+ dmx = get_stb_dmx();
+ if (dmx) {
+ dmx->irq_handler = handler;
+ dmx->irq_data = data;
+ }
+
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return 0;
+}
+
+/*Free the amstream irq handler*/
+static int aml_tsdemux_free_irq(void)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ struct aml_dmx *dmx;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+
+ dmx = get_stb_dmx();
+ if (dmx) {
+ dmx->irq_handler = NULL;
+ dmx->irq_data = NULL;
+ }
+
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return 0;
+}
+
+/*Reset the video PID*/
+static int aml_tsdemux_set_vid(int vpid)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ struct aml_dmx *dmx;
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+ dmx = get_stb_dmx();
+ if (dmx) {
+ if (dmx->vid_chan != -1) {
+ dmx_free_chan(dmx, dmx->vid_chan);
+ dmx->vid_chan = -1;
+ }
+
+ if ((vpid >= 0) && (vpid < 0x1FFF)) {
+ dmx->vid_chan =
+ dmx_alloc_chan(dmx, DMX_TYPE_TS,
+ DMX_PES_VIDEO, vpid);
+ if (dmx->vid_chan == -1)
+ ret = -1;
+ }
+ }
+
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return ret;
+}
+
+/*Reset the audio PID*/
+static int aml_tsdemux_set_aid(int apid)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ struct aml_dmx *dmx;
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+ dmx = get_stb_dmx();
+ if (dmx) {
+ if (dmx->aud_chan != -1) {
+ dmx_free_chan(dmx, dmx->aud_chan);
+ dmx->aud_chan = -1;
+ }
+
+ if ((apid >= 0) && (apid < 0x1FFF)) {
+ dmx->aud_chan =
+ dmx_alloc_chan(dmx, DMX_TYPE_TS,
+ DMX_PES_AUDIO, apid);
+ if (dmx->aud_chan == -1)
+ ret = -1;
+ }
+ }
+
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return ret;
+}
+
+/*Reset the subtitle PID*/
+static int aml_tsdemux_set_sid(int spid)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ struct aml_dmx *dmx;
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+
+ dmx = get_stb_dmx();
+ if (dmx) {
+ if (dmx->sub_chan != -1) {
+ dmx_free_chan(dmx, dmx->sub_chan);
+ dmx->sub_chan = -1;
+ }
+
+ if ((spid >= 0) && (spid < 0x1FFF)) {
+ dmx->sub_chan = 3;
+ dmx->sub_chan =
+ dmx_alloc_chan(dmx, DMX_TYPE_TS,
+ DMX_PES_SUBTITLE, spid);
+ if (dmx->sub_chan == -1)
+ ret = -1;
+ }
+ }
+
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return ret;
+}
+
+static int aml_tsdemux_set_pcrid(int pcrpid)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ struct aml_dmx *dmx;
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+
+ dmx = get_stb_dmx();
+ if (dmx) {
+ if (dmx->pcr_chan != -1) {
+ dmx_free_chan(dmx, dmx->pcr_chan);
+ dmx->pcr_chan = -1;
+ }
+
+ if ((pcrpid >= 0) && (pcrpid < 0x1FFF)) {
+ dmx->pcr_chan =
+ dmx_alloc_chan(dmx, DMX_TYPE_TS,
+ DMX_PES_PCR, pcrpid);
+ if (dmx->pcr_chan == -1)
+ ret = -1;
+ }
+ }
+
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return ret;
+}
+
+static int aml_tsdemux_set_skipbyte(int skipbyte)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+ aml_dmx_set_skipbyte(dvb, skipbyte);
+ spin_unlock_irqrestore(&dvb->slock, flags);
+
+ return 0;
+}
+
+static int aml_tsdemux_set_demux(int id)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+
+ aml_dmx_set_demux(dvb, id);
+ return 0;
+}
+
+static unsigned long aml_tsdemux_hwdmx_spin_lock(unsigned long flags)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+
+ spin_lock_irqsave(&dvb->slock, flags);
+ return flags;
+}
+
+static int aml_tsdemux_hwdmx_spin_unlock(unsigned long flags)
+{
+ struct aml_dvb *dvb = &aml_dvb_device;
+
+ spin_unlock_irqrestore(&dvb->slock, flags);
+ return 0;
+}
+
+module_init(aml_dvb_init);
+module_exit(aml_dvb_exit);
+
+MODULE_DESCRIPTION("driver for the AMLogic DVB card");
+MODULE_AUTHOR("AMLOGIC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/stream_input/parser/hw_demux/aml_dvb.h b/drivers/stream_input/parser/hw_demux/aml_dvb.h
new file mode 100644
index 0000000..12ed65b
--- /dev/null
+++ b/drivers/stream_input/parser/hw_demux/aml_dvb.h
@@ -0,0 +1,425 @@
+/*
+* 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_DVB_H_
+#define _AML_DVB_H_
+
+#include <linux/interrupt.h>
+#include <linux/socket.h>
+#include <linux/netdevice.h>
+#include <linux/i2c.h>
+
+#include <linux/dvb/video.h>
+#include <linux/dvb/audio.h>
+#include <linux/dvb/dmx.h>
+#include <linux/dvb/ca.h>
+#include <linux/dvb/osd.h>
+#include <linux/dvb/net.h>
+#include <linux/dvb/frontend.h>
+
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+
+#include <dvbdev.h>
+#include <demux.h>
+#include <dvb_demux.h>
+#include <dmxdev.h>
+#include <dvb_filter.h>
+#include <dvb_net.h>
+#include <dvb_ringbuffer.h>
+
+#include <linux/of.h>
+#include <linux/pinctrl/consumer.h>
+
+#include "aml_demod_gt.h"
+
+#define TS_IN_COUNT 4
+#define S2P_COUNT 3
+#define ASYNCFIFO_COUNT 3
+#if 0
+#define TS_IN_COUNT 3
+#define S2P_COUNT 2
+#define ASYNCFIFO_COUNT 2
+#endif
+
+#define DMX_DEV_COUNT 3
+#define FE_DEV_COUNT 2
+#define CHANNEL_COUNT 31
+#define FILTER_COUNT 31
+#define FILTER_LEN 15
+#define DSC_DEV_COUNT 2
+#define DSC_COUNT 8
+#define SEC_BUF_GRP_COUNT 4
+#define SEC_BUF_BUSY_SIZE 4
+#define SEC_BUF_COUNT (SEC_BUF_GRP_COUNT*8)
+
+enum aml_dmx_id_t {
+ AM_DMX_0 = 0,
+ AM_DMX_1,
+ AM_DMX_2,
+ AM_DMX_MAX,
+};
+
+enum aml_ts_source_t {
+ AM_TS_SRC_TS0,
+ AM_TS_SRC_TS1,
+ AM_TS_SRC_TS2,
+ AM_TS_SRC_TS3,
+
+ AM_TS_SRC_S_TS0,
+ AM_TS_SRC_S_TS1,
+ AM_TS_SRC_S_TS2,
+ AM_TS_SRC_S_TS3,
+
+ AM_TS_SRC_HIU,
+ AM_TS_SRC_HIU1,
+ AM_TS_SRC_DMX0,
+ AM_TS_SRC_DMX1,
+ AM_TS_SRC_DMX2
+};
+
+struct aml_sec_buf {
+ unsigned long addr;
+ int len;
+};
+
+struct aml_channel {
+ int type;
+ enum dmx_ts_pes pes_type;
+ int pid;
+ int used;
+ int filter_count;
+ struct dvb_demux_feed *feed;
+ struct dvb_demux_feed *dvr_feed;
+ int pkt_type;
+};
+
+struct aml_filter {
+ int chan_id;
+ int used;
+ struct dmx_section_filter *filter;
+ u8 value[FILTER_LEN];
+ u8 maskandmode[FILTER_LEN];
+ u8 maskandnotmode[FILTER_LEN];
+ u8 neq;
+};
+
+#define DVBCSA_MODE 0
+#define CIPLUS_MODE 1
+#define CBC_MODE 0
+#define ECB_MODE 1
+#define IDSA_MODE 2
+
+#define DSC_SET_EVEN 1
+#define DSC_SET_ODD 2
+#define DSC_SET_AES_EVEN 4
+#define DSC_SET_AES_ODD 8
+#define DSC_FROM_KL 16
+#define DSC_SET_SM4_EVEN 32
+#define DSC_SET_SM4_ODD 64
+
+#define DSC_KEY_SIZE_MAX 16
+
+struct aml_dsc_channel {
+ int pid;
+ u8 even[DSC_KEY_SIZE_MAX];
+ u8 odd[DSC_KEY_SIZE_MAX];
+ u8 even_iv[DSC_KEY_SIZE_MAX];
+ u8 odd_iv[DSC_KEY_SIZE_MAX];
+ int used;
+ int set;
+ int id;
+ struct aml_dsc *dsc;
+ int work_mode;
+ int mode;
+};
+
+struct aml_dsc {
+ struct dvb_device *dev;
+ struct aml_dsc_channel channel[DSC_COUNT];
+ enum aml_ts_source_t source;
+ enum aml_ts_source_t dst;
+ struct aml_dvb *dvb;
+ int id;
+ int work_mode;
+};
+
+struct aml_smallsec {
+ struct aml_dmx *dmx;
+
+ int enable;
+ int bufsize;
+#define SS_BUFSIZE_DEF (16*4*256) /*16KB*/
+ long buf;
+ long buf_map;
+};
+
+struct aml_dmxtimeout {
+ struct aml_dmx *dmx;
+
+ int enable;
+
+ int timeout;
+#define DTO_TIMEOUT_DEF (9000) /*0.5s*/
+ u32 ch_disable;
+#define DTO_CHDIS_VAS (0xfffffff8) /*v/a/s only*/
+ int match;
+
+ int trigger;
+};
+
+struct aml_dmx {
+ struct dvb_demux demux;
+ struct dmxdev dmxdev;
+ int id;
+ int feed_count;
+ int chan_count;
+ enum aml_ts_source_t source;
+ int init;
+ int record;
+ struct dmx_frontend hw_fe[DMX_DEV_COUNT];
+ struct dmx_frontend mem_fe;
+ struct dvb_net dvb_net;
+ int dmx_irq;
+ int dvr_irq;
+ struct tasklet_struct dmx_tasklet;
+ struct tasklet_struct dvr_tasklet;
+ unsigned long sec_pages;
+ unsigned long sec_pages_map;
+ int sec_total_len;
+ struct aml_sec_buf sec_buf[SEC_BUF_COUNT];
+ unsigned long pes_pages;
+ unsigned long pes_pages_map;
+ int pes_buf_len;
+ union {
+ unsigned long sub_pages;
+ unsigned long sub_buf_base;
+ };
+ union {
+ unsigned long sub_pages_map;
+ u8 *sub_buf_base_virt;
+ };
+ int sub_buf_len;
+
+ struct aml_channel channel[CHANNEL_COUNT+1];
+ struct aml_filter filter[FILTER_COUNT+1];
+ irq_handler_t irq_handler;
+ void *irq_data;
+ int aud_chan;
+ int vid_chan;
+ int sub_chan;
+ int pcr_chan;
+ u32 section_busy[SEC_BUF_BUSY_SIZE];
+ struct dvb_frontend *fe;
+ int int_check_count;
+ u32 int_check_time;
+ int in_tune;
+ int error_check;
+ int dump_ts_select;
+ int sec_buf_watchdog_count[SEC_BUF_COUNT];
+
+ struct aml_smallsec smallsec;
+ struct aml_dmxtimeout timeout;
+
+ int demux_filter_user;
+
+ unsigned long sec_cnt[3];
+ unsigned long sec_cnt_match[3];
+ unsigned long sec_cnt_crc_fail[3];
+ #define SEC_CNT_HW (0)
+ #define SEC_CNT_SW (1)
+ #define SEC_CNT_SS (2)
+ #define SEC_CNT_MAX (3)
+
+ int crc_check_count;
+ u32 crc_check_time;
+ int om_status_error_count;
+};
+
+struct aml_dvr_block {
+ u32 addr;
+ u32 len;
+};
+
+struct aml_asyncfifo {
+ int id;
+ int init;
+ int asyncfifo_irq;
+ enum aml_dmx_id_t source;
+ unsigned long pages;
+ unsigned long pages_map;
+ int buf_len;
+ int buf_toggle;
+ int buf_read;
+ int flush_size;
+ int secure_enable;
+ struct tasklet_struct asyncfifo_tasklet;
+ struct aml_dvb *dvb;
+ struct aml_dvr_block blk;
+ unsigned long stored_pages;
+};
+
+enum{
+ AM_TS_DISABLE,
+ AM_TS_PARALLEL,
+ AM_TS_SERIAL
+};
+
+struct aml_ts_input {
+ int mode;
+ struct pinctrl *pinctrl;
+ int control;
+ int s2p_id;
+};
+
+struct aml_s2p {
+ int invert;
+};
+
+struct aml_swfilter {
+ int user;
+ struct aml_dmx *dmx;
+ struct aml_asyncfifo *afifo;
+
+ struct dvb_ringbuffer rbuf;
+#define SF_BUFFER_SIZE (10*188*1024)
+
+ u8 wrapbuf[188];
+ int track_dmx;
+};
+
+struct aml_dvb {
+ struct dvb_device dvb_dev;
+ int ts_in_total_count;
+ struct aml_ts_input ts[TS_IN_COUNT];
+ int s2p_total_count;
+ struct aml_s2p s2p[S2P_COUNT];
+ struct aml_dmx dmx[DMX_DEV_COUNT];
+ struct aml_dsc dsc[DSC_DEV_COUNT];
+ int async_fifo_total_count;
+ struct aml_asyncfifo asyncfifo[ASYNCFIFO_COUNT];
+ struct dvb_adapter dvb_adapter;
+ struct device *dev;
+ struct platform_device *pdev;
+ enum aml_ts_source_t stb_source;
+ enum aml_ts_source_t tso_source;
+ int dmx_init;
+ int reset_flag;
+ spinlock_t slock;
+ struct timer_list watchdog_timer;
+ int dmx_watchdog_disable[DMX_DEV_COUNT];
+ struct aml_swfilter swfilter;
+ int ts_out_invert;
+
+ /*bufs for dmx shared*/
+ unsigned long pes_pages;
+ unsigned long pes_pages_map;
+ int pes_buf_len;
+ unsigned long sub_pages;
+ unsigned long sub_pages_map;
+ int sub_buf_len;
+};
+
+
+/*AMLogic demux interface*/
+extern int aml_dmx_hw_init(struct aml_dmx *dmx);
+extern int aml_dmx_hw_deinit(struct aml_dmx *dmx);
+extern int aml_dmx_hw_start_feed(struct dvb_demux_feed *dvbdmxfeed);
+extern int aml_dmx_hw_stop_feed(struct dvb_demux_feed *dvbdmxfeed);
+extern int aml_dmx_hw_set_source(struct dmx_demux *demux,
+ dmx_source_t src);
+extern int aml_stb_hw_set_source(struct aml_dvb *dvb, dmx_source_t src);
+extern int aml_dsc_hw_set_source(struct aml_dsc *dsc,
+ dmx_source_t src, dmx_source_t dst);
+extern int aml_tso_hw_set_source(struct aml_dvb *dvb, dmx_source_t src);
+extern int aml_dmx_set_skipbyte(struct aml_dvb *dvb, int skipbyte);
+extern int aml_dmx_set_demux(struct aml_dvb *dvb, int id);
+extern int aml_dmx_hw_set_dump_ts_select
+ (struct dmx_demux *demux, int dump_ts_select);
+
+extern int dmx_alloc_chan(struct aml_dmx *dmx, int type,
+ int pes_type, int pid);
+extern void dmx_free_chan(struct aml_dmx *dmx, int cid);
+
+extern int dmx_get_ts_serial(enum aml_ts_source_t src);
+
+extern int dmx_get_sub_buffer(unsigned long *base, unsigned long *virt);
+extern int dmx_init_sub_buffer(struct aml_dmx *dmx, unsigned long base, unsigned long virt);
+
+/*AMLogic dsc interface*/
+extern int dsc_set_pid(struct aml_dsc_channel *ch, int pid);
+extern int dsc_set_key(struct aml_dsc_channel *ch, int flags,
+ enum ca_cw_type type, u8 *key);
+extern void dsc_release(void);
+extern int aml_ciplus_hw_set_source(int src);
+
+/*AMLogic ASYNC FIFO interface*/
+extern int aml_asyncfifo_hw_init(struct aml_asyncfifo *afifo);
+extern int aml_asyncfifo_hw_deinit(struct aml_asyncfifo *afifo);
+extern int aml_asyncfifo_hw_set_source(struct aml_asyncfifo *afifo,
+ enum aml_dmx_id_t src);
+extern int aml_asyncfifo_hw_reset(struct aml_asyncfifo *afifo);
+
+/*Get the Audio & Video PTS*/
+extern u32 aml_dmx_get_video_pts(struct aml_dvb *dvb);
+extern u32 aml_dmx_get_audio_pts(struct aml_dvb *dvb);
+extern u32 aml_dmx_get_video_pts_bit32(struct aml_dvb *dvb);
+extern u32 aml_dmx_get_audio_pts_bit32(struct aml_dvb *dvb);
+extern u32 aml_dmx_get_first_video_pts(struct aml_dvb *dvb);
+extern u32 aml_dmx_get_first_audio_pts(struct aml_dvb *dvb);
+
+/*Get the DVB device*/
+extern struct aml_dvb *aml_get_dvb_device(void);
+
+extern int aml_regist_dmx_class(void);
+extern int aml_unregist_dmx_class(void);
+extern void aml_register_parser_mconfig(void);
+
+struct devio_aml_platform_data {
+ int (*io_setup)(void *);
+ int (*io_cleanup)(void *);
+ int (*io_power)(void *, int enable);
+ int (*io_reset)(void *, int enable);
+};
+
+void get_aml_dvb(struct aml_dvb *dvb_device);
+
+/*Reset the demux device*/
+void dmx_reset_hw(struct aml_dvb *dvb);
+void dmx_reset_hw_ex(struct aml_dvb *dvb, int reset_irq);
+
+/*Reset the individual demux*/
+void dmx_reset_dmx_hw(struct aml_dvb *dvb, int id);
+void dmx_reset_dmx_id_hw_ex(struct aml_dvb *dvb, int id, int reset_irq);
+void dmx_reset_dmx_id_hw_ex_unlock(struct aml_dvb *dvb, int id, int reset_irq);
+void dmx_reset_dmx_hw_ex(struct aml_dvb *dvb,
+ struct aml_dmx *dmx,
+ int reset_irq);
+void dmx_reset_dmx_hw_ex_unlock(struct aml_dvb *dvb,
+ struct aml_dmx *dmx,
+ int reset_irq);
+
+#endif
+
diff --git a/drivers/stream_input/parser/hw_demux/aml_dvb_reg.h b/drivers/stream_input/parser/hw_demux/aml_dvb_reg.h
new file mode 100644
index 0000000..dbfa6ba
--- /dev/null
+++ b/drivers/stream_input/parser/hw_demux/aml_dvb_reg.h
@@ -0,0 +1,58 @@
+/*
+ * drivers/amlogic/dvb_tv/dvb_reg.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 _DVB_REG_H_
+#define _DVB_REG_H_
+
+#include <linux/amlogic/iomap.h>
+
+#include <linux/amlogic/cpu_version.h>
+
+#define ID_STB_CBUS_BASE 0
+#define ID_SMARTCARD_REG_BASE 1
+#define ID_ASYNC_FIFO_REG_BASE 2
+#define ID_ASYNC_FIFO1_REG_BASE 3
+#define ID_ASYNC_FIFO2_REG_BASE 4
+#define ID_RESET_BASE 5
+#define ID_PARSER_SUB_START_PTR_BASE 6
+
+long aml_stb_get_base(int id);
+#include "c_stb_define.h"
+#include "c_stb_regs_define.h"
+
+#define WRITE_MPEG_REG(_r, _v) aml_write_cbus(_r, _v)
+#define READ_MPEG_REG(_r) aml_read_cbus(_r)
+
+#define WRITE_CBUS_REG(_r, _v) aml_write_cbus(_r, _v)
+#define READ_CBUS_REG(_r) aml_read_cbus(_r)
+
+#define WRITE_VCBUS_REG(_r, _v) aml_write_vcbus(_r, _v)
+#define READ_VCBUS_REG(_r) aml_read_vcbus(_r)
+
+#define BASE_IRQ 32
+#define AM_IRQ(reg) (reg + BASE_IRQ)
+#define INT_DEMUX AM_IRQ(23)
+#define INT_DEMUX_1 AM_IRQ(5)
+#define INT_DEMUX_2 AM_IRQ(21) //AM_IRQ(53)
+#define INT_ASYNC_FIFO_FILL AM_IRQ(18)
+#define INT_ASYNC_FIFO_FLUSH AM_IRQ(19)
+#define INT_ASYNC_FIFO2_FILL AM_IRQ(24)
+#define INT_ASYNC_FIFO2_FLUSH AM_IRQ(25)
+
+#define INT_ASYNC_FIFO3_FLUSH AM_IRQ(17)
+#endif
+
diff --git a/drivers/stream_input/parser/hw_demux/c_stb_define.h b/drivers/stream_input/parser/hw_demux/c_stb_define.h
new file mode 100644
index 0000000..6b815b6
--- /dev/null
+++ b/drivers/stream_input/parser/hw_demux/c_stb_define.h
@@ -0,0 +1,1217 @@
+/*
+* 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:
+*/
+/* ----------------------------------------------------------------------*/
+/* This file is automatically generated from the script:*/
+/**/
+/* ./create_stb_define_for_C_code.pl*/
+/**/
+/* and was applied to the file*/
+/**/
+/* ./stb_define.h*/
+/**/
+/* DO NOT EDIT!!!!!*/
+/* ----------------------------------------------------------------------*/
+/**/
+#ifdef C_STB_DEFINE_H
+#else
+#define C_STB_DEFINE_H
+
+/*=================================================*/
+/* STB Registers Start*/
+/*=================================================*/
+/* -----------------------------------------------*/
+/*#define STB_CBUS_BASE 0x1600*/
+/* -----------------------------------------------*/
+/* There are two instantiations under one CBUS slave.
+ * Each CBUS slave can support*/
+/* 256 registers.
+ * Each demux is allocated 128 registers so set the offset in*/
+/* the middle*/
+/* Copy this define but don't add a base address*/
+/*#define DEMUX_1_OFFSET 0x00*/
+/*#define DEMUX_2_OFFSET 0x50*/
+/*#define DEMUX_3_OFFSET 0xa0*/
+/*======================================================*/
+/* STB TOP Registers (8'hf0 - 8'hf7)*/
+/*======================================================*/
+/* bit 30:28 -- ciplus_o_sel*/
+/* bit 27:26 -- ciplus_i_sel*/
+/* bit 25 -- use FAIL fro TS2*/
+/* bit 24 -- use FAIL fro TS1*/
+/* bit 23 -- use FAIL fro TS0*/
+/* bit 22 -- invert fec_error for S2P1*/
+/* bit 21 -- invert fec_data for S2P1*/
+/* bit 20 -- invert fec_sync for S2P1*/
+/* bit 19 -- invert fec_valid for S2P1*/
+/* bit 18 -- invert fec_clk for S2P1*/
+/* bit 17:16 -- fec_s_sel for S2P1
+ * 00 - select TS0, 01 -- select TS1, 10 -- select TS2, 11 - TS3*/
+/* Bit 15 -- enable_des_pl_clk*/
+/* Bit 14 -- reserved*/
+/* Bit 13 -- use FAIL for TS3*/
+/* Bit 12:10 -- ts_out_select,
+ * 0-TS0, 1-TS1, 2-TS2, 3-TS3,4-S2P2, 5-S2P1, 6-S2P0, 7-File*/
+/* bit 9:8 -- des_i_sel 00 -- select demux0 as des input,
+* 01 -- select_demux1, 10 -- select_demux2, 11 - reserved*/
+/* bit 7 -- enable_des_pl*/
+/* bit 6 -- invert fec_error for S2P0*/
+/* bit 5 -- invert fec_data for S2P0*/
+/* bit 4 -- invert fec_sync for S2P0*/
+/* bit 3 -- invert fec_valid for S2P0*/
+/* bit 2 -- invert fec_clk for S2P0*/
+/* bit 1:0 -- fec_s_sel for S2P0
+ * 00 - select TS0, 01 -- select TS1, 10 -- select TS2, 11 - reserved*/
+/*#define STB_TOP_CONFIG (STB_CBUS_BASE + 0xf0) // 0x16f0*/
+/*----------- bit define -----------*/
+#define INVERT_S2P1_FEC_ERROR 22
+#define INVERT_S2P1_FEC_DATA 21
+#define INVERT_S2P1_FEC_SYNC 20
+#define INVERT_S2P1_FEC_VALID 19
+#define INVERT_S2P1_FEC_CLK 18
+#define S2P1_FEC_SERIAL_SEL 16
+#define ENABLE_DES_PL_CLK 15
+#define FAIL_TS3 13
+#define TS_OUTPUT_SOURCE 10
+#define DES_INPUT_SEL 8
+#define ENABLE_DES_PL 7
+#define INVERT_S2P0_FEC_ERROR 6
+#define INVERT_S2P0_FEC_DATA 5
+#define INVERT_S2P0_FEC_SYNC 4
+#define INVERT_S2P0_FEC_VALID 3
+#define INVERT_S2P0_FEC_CLK 2
+#define S2P0_FEC_SERIAL_SEL 0
+
+//define STB_S2P2_CONFIG
+#define S2P2_DISABLE 11
+#define S2P2_CLK_DIV 7
+#define INVERT_S2P2_FEC_ERROR 6
+#define INVERT_S2P2_FEC_DATA 5
+#define INVERT_S2P2_FEC_SYNC 4
+#define INVERT_S2P2_FEC_VALID 3
+#define INVERT_S2P2_FEC_CLK 2
+#define S2P2_FEC_SERIAL_SEL 0
+
+
+/* 31:24 -- file_m2ts_skip_bytes_hiu1*/
+/* 21 -- ts_hiu_enable_hiu1 */
+/*20:16 -- fec_clk_div_hiu1*/
+/*15:8 -- TS_package_length_sub_1_hiu1 */
+/*7:0 -- fec_sync_byte_hiu1*/
+/*#define TS_HIU1_CONFIG (STB_CBUS_BASE + 0x4e)*/
+#define FILE_M2TS_SKIP_BYTES_HIU1 24
+#define TS_HIU_ENABLE_HIU1 21
+#define FEC_CLK_DIV_HIU1 16
+#define TS_PACKAGE_LENGTH_SUB_1_HIU1 8
+#define FEC_SYNC_BYTE_HIU1 0
+
+/*5:4 -- fec_sel_demux_2, default:2*/
+/*3:2 -- fec_sel_demux_1, default:1*/
+/*1:0 -- fec_sel_demux_0, default:0*/
+/*#define TS_TOP_CONFIG1 (STB_CBUS_BASE + 0x4f)*/
+#define FEC_SEL_DEMUX_2 4
+#define FEC_SEL_DEMUX_1 2
+#define FEC_SEL_DEMUX_0 0
+
+/* 31:28 - s2p1_clk_div*/
+/* 27:24 - s2p0_clk_div*/
+/* 23 - s2p1_disable*/
+/* 22 - s2p0_disable*/
+/* 21 - Reserved*/
+/* 20 -- TS_OUT_error_INVERT*/
+/* 19 -- TS_OUT_data_INVERT*/
+/* 18 -- TS_OUT_sync_INVERT*/
+/* 17 -- TS_OUT_valid_INVERT*/
+/* 16 -- TS_OUT_clk_INVERT*/
+/* 15:8 -- TS_package_length_sub_1 (default : 187)*/
+/* 7:0 -- fec_sync_byte (default : 0x47)*/
+/*#define TS_TOP_CONFIG (STB_CBUS_BASE + 0xf1) // 0x16f1*/
+/*----------- bit define -----------*/
+#define TS_OUT_CLK_INVERT 16
+#define TS_PACKAGE_LENGTH_SUB_1 8
+#define FEC_DEFAULT_SYNC_BYTE 0
+
+/* Bit 25:24 -- transport_scrambling_control_odd_2 // should be 3*/
+/* Bit 23:16 -- file_m2ts_skip_bytes*/
+/* Bit 15:8 -- des_out_dly*/
+/* Bit 7:6 -- transport_scrambling_control_odd // should be 3*/
+/* Bit 5 -- ts_hiu_enable*/
+/* Bit 4:0 -- fec_clk_div*/
+/*#define TS_FILE_CONFIG (STB_CBUS_BASE + 0xf2) // 0x16f2*/
+/*----------- bit define -----------*/
+#define TRANSPORT_SCRAMBLING_CONTROL_ODD_2 24
+#define FILE_M2TS_SKIP_BYTES 16
+#define DES_OUT_DLY 8
+#define TRANSPORT_SCRAMBLING_CONTROL_ODD 6
+#define TS_HIU_ENABLE 5
+#define FEC_FILE_CLK_DIV 0
+
+/* Bit 19:14 -- des_2 ts pl state -- Read Only*/
+/* Bit 13:8 -- des ts pl state -- Read Only*/
+/* Bit 3:0 PID index to 8 PID to get key-set*/
+/* auto increse after TS_PL_PID_DATA read/write*/
+/*#define TS_PL_PID_INDEX (STB_CBUS_BASE + 0xf3) // 0x16f3*/
+/*----------- bit define -----------*/
+#define DES_TS_PL_STATE 8
+#define DES_2_TS_PL_STATE 14
+
+/* Bit 13 -- PID match disble*/
+/* Bit 12:0 -- PID*/
+/*#define TS_PL_PID_DATA (STB_CBUS_BASE + 0xf4) // 0x16f4*/
+/*----------- bit define -----------*/
+#define PID_MATCH_DISABLE_HIGH 29
+#define PID_MATCH_HIGH 16
+#define PID_MATCH_DISABLE_LOW 13
+#define PID_MATCH_LOW 0
+
+/*#define COMM_DESC_KEY0
+ * (STB_CBUS_BASE + 0xf5) // 0x16f5
+ Common descrambler key (key bits[63:32])*/
+/*#define COMM_DESC_KEY1
+ * (STB_CBUS_BASE + 0xf6) // 0x16f6
+ Common descrambler key (key bits[31:0])*/
+/*#define COMM_DESC_KEY_RW
+ * (STB_CBUS_BASE + 0xf7) // 0x16f7 // bits[3:0]
+ * point to the address to write the key
+ * {COMM_DESC_KEY3,...,COMM_DESC_KEY0}*/
+/* Writing this register writes the key to RAM*/
+
+/* bit 15:8 - des_out_dly_2*/
+/* bit 7 - reserved*/
+/* Bit 6-- enable_des_pl_clk_2*/
+/* bit 5 - enable_des_pl_2*/
+/* bit 4:2 -- use_des_2 bit[2] -- demux0, bit[3] -- demux1, bit[4] -- demux2*/
+/* bit 1:0 -- des_i_sel_2 00 -- select_fec_0, 01 -- select_fec_1,
+ * 10 -- select_fec_2, 11 - reserved*/
+/*#define COMM_DESC_2_CTL (STB_CBUS_BASE + 0xff) *//*0x16ff*/
+
+/*=======================================================*/
+/* Multiple STB Registers (8'h00 - 8'h45)*/
+/*=======================================================*/
+/* STB registers are 8'h0x*/
+/* Bit 15:0 -- version number : 0x0002 (v0.01)*/
+/*#define STB_VERSION
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x00) // 0x1600 // read only*/
+/*#define STB_VERSION_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x00) // 0x1650 // read only*/
+/*#define STB_VERSION_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x00) // 0x16a0 // read only*/
+
+/*#define STB_TEST_REG
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x01) // 0x1601*/
+/*#define STB_TEST_REG_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x01) // 0x1651*/
+/*#define STB_TEST_REG_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x01) // 0x16a1*/
+
+/* Bit 15 -- fec_core_select 1 - select descramble output*/
+/* Bit 14:12 - fec_select
+ * 0-TS0, 1-TS1, 2-TS2, 3,4-Reserved, 5-S2P1, 6-S2P0, 7-File*/
+/* Bit 11 -- FEC_CLK*/
+/* Bit 10 -- SOP*/
+/* Bit 9 -- D_VALID*/
+/* Bit 8 -- D_FAIL*/
+/* Bit 7:0 -- D_DATA 7:0*/
+/*#define FEC_INPUT_CONTROL
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x02) // 0x1602*/
+/*#define FEC_INPUT_CONTROL_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x02) // 0x1652*/
+/*#define FEC_INPUT_CONTROL_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x02) // 0x16a2*/
+/*----------- bit define -----------*/
+#define FEC_SEL_3BIT 16
+#define FEC_CORE_SEL 15
+#define FEC_SEL 12
+#define FEC_INPUT_FEC_CLK 11
+#define FEC_INPUT_SOP 10
+#define FEC_INPUT_D_VALID 9
+#define FEC_INPUT_D_FAIL 8
+
+/*#define FEC_INPUT_DATA
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x03) // 0x1603 // read only*/
+/*#define FEC_INPUT_DATA_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x03) // 0x1653 // read only*/
+/*#define FEC_INPUT_DATA_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x03) // 0x16a3 // read only*/
+
+/* bit 31 -- enable_free_clk_fec_data_valid*/
+/* bit 30 -- enable_free_clk_stb_reg*/
+/* bit 29 -- always_use_pes_package_length*/
+/* bit 28 -- disable_pre_incomplete_section_fix*/
+/* bit 27 -- pointer_field_multi_pre_en*/
+/* bit 26 -- ignore_pre_incomplete_section*/
+/* bit 25 -- video2_enable*/
+/* bit 24:22 -- video2_type*/
+/* bit 21 -- do_not_trust_pes_package_length*/
+/* bit 20 (bit 4) -- Bypass use recoder path*/
+/* bit 19 (bit 3) -- clear_PID_continuity_counter_valid*/
+/* bit 18 (bit 2) -- Disable Splicing*/
+/* bit 17 (bit 1) -- Insert PES_STRONG_SYNC in Audio PES*/
+/* bit 16 (bit 0) -- Insert PES_STRONG_SYNC in Video PES*/
+/* Bit 15 - do not trust section length*/
+/* Bit 14 - om cmd push even zero*/
+/* Bit 13 - reserved*/
+/* Bit 12 - SUB, OTHER PES interrupt at beginning of PES*/
+/* Bit 11 - discard_av_package -- for ts_recorder use only*/
+/* Bit 10 - ts_recorder_select 0:after PID filter 1:before PID filter*/
+/* Bit 9 - ts_recorder_enable*/
+/* Bit 8 - (table_id == 0xff) means section_end*/
+/* Bit 7 - do not send uncomplete section*/
+/* Bit 6 - do not discard duplicate package*/
+/* Bit 5 - search SOP when trasport_error_indicator*/
+/* Bit 4 - stb demux enable*/
+/* Bit 3 - do not reset state machine on SOP*/
+/* Bit 2 - search SOP when error happened
+ * ( when ignore_fail_n_sop, will have this case)*/
+/* Bit 1 - do not use SOP input ( check FEC sync byte instead )*/
+/* Bit 0 - ignore fec_error bit when non sop ( check error on SOP only)*/
+/*#define DEMUX_CONTROL
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x04) // 0x1604*/
+/*#define DEMUX_CONTROL_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x04) // 0x1654*/
+/*#define DEMUX_CONTROL_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x04) // 0x16a4*/
+/*----------- bit define -----------*/
+#define ENABLE_FREE_CLK_FEC_DATA_VALID 31
+#define ENABLE_FREE_CLK_STB_REG 30
+#define BYPASS_USE_RECODER_PATH 20
+#define CLEAR_PID_CONTINUITY_COUNTER_VALID 19
+#define DISABLE_SPLICING 18
+#define INSERT_AUDIO_PES_STRONG_SYNC 17
+#define INSERT_VIDEO_PES_STRONG_SYNC 16
+#define SECTION_LENGTH_UNTRUSTY 15
+#define OM_CMD_PUSH_EVEN_ZERO 14
+#define OTHER_INT_AT_PES_BEGINING 12
+#define DISCARD_AV_PACKAGE 11
+#define TS_RECORDER_SELECT 10
+#define TS_RECORDER_ENABLE 9
+#define SECTION_END_WITH_TABLE_ID 8
+#define SEND_COMPLETE_SECTION_ONLY 7
+#define KEEP_DUPLICATE_PACKAGE 6
+#define SEACH_SOP_ON_TRANSPORT_ERROR 5
+#define STB_DEMUX_ENABLE 4
+#define NO_RESET_ON_SOP 3
+#define SEARCH_SOP_ON_ERROR 2
+#define NOT_USE_OF_SOP_INPUT 1
+#define IGNORE_NONSOP_FEC_ERROR 0
+
+/* bit 15:8 demux package length - 1 ( default : 187 )*/
+/* bit 7:0 default is 0x47*/
+/*#define FEC_SYNC_BYTE
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x05) // 0x1605*/
+/*#define FEC_SYNC_BYTE_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x05) // 0x1655*/
+/*#define FEC_SYNC_BYTE_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x05) // 0x16a5*/
+
+/****************************************
+ * FM Memory Usage :
+ * 0-15 (32 PID filter target) ---- 15:13-PID type 12:0-PID target or force data
+ * (force data : 1 will mask corespoding bit,
+ * 0 will disable this PID filter channel)
+ * advanced setting -- bit 7:0
+ * bit 7 -- PID bit 12:11 compare result force
+ * bit 6 -- PID bit 10:9 compare result force
+ * bit 5 -- PID bit 8:7 compare result force
+ * bit 4 -- PID bit 6:5 compare result force
+ * bit 3 -- PID bit 4:3 compare result force
+ * bit 2 -- PID bit 2 compare result force
+ * bit 1 -- PID bit 1 compare result force
+ * bit 0 -- PID bit 0 compare result force
+ * 16-255(15x32 Section filter target)
+ * For first byte : Table_ID
+ * ---- 15-Mask High 4-bits
+ * 14-Mask Low 4-bits
+ * 13-disable_PID_check
+ * 12:8-PIDindex
+ * 7:0-section target (always EQ)
+ * For rest of bytes :
+ * ---- 15-Mask 14-EQ/NE 13-disable_PID_check
+ * ----12:8-PIDindex 7:0-section target (or force data)
+ * advanced setting -- bit 7:0 force compare result
+ **************************************************/
+/*----------- bit define -----------*/
+#define PID_TYPE 13
+#define PID_TARGET 0
+
+#define SECTION_FIRSTBYTE_MASKHIGH 15
+#define SECTION_FIRSTBYTE_MASKLOW 14
+#define SECTION_FIRSTBYTE_DISABLE_PID_CHECK 13
+#define SECTION_FIRSTBYTE_PID_INDEX 8
+#define SECTION_TARGET 0
+
+#define SECTION_RESTBYTE_MASK 15
+#define SECTION_RESTBYTE_MASK_EQ 14
+#define SECTION_RESTBYTE_DISABLE_PID_CHECK 13
+#define SECTION_RESTBYTE_PID_INDEX 8
+
+/* bit 31:16 -- filter memory write data hi[31:16]*/
+/* bit 15:0 -- filter memory write data low [15:0]*/
+/*#define FM_WR_DATA
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x06) // 0x1606*/
+/*#define FM_WR_DATA_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x06) // 0x1656*/
+/*#define FM_WR_DATA_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x06) // 0x16a6*/
+/*----------- bit define -----------*/
+#define FM_WR_DATA_HI 16
+
+/* bit 31:24 -- advanced setting hi*/
+/* bit 23:16 -- advanced setting low*/
+/* bit 15 -- filter memory write data request*/
+/* bit 7:0 -- filter memory write addr*/
+/*#define FM_WR_ADDR
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x07) // 0x1607*/
+/*#define FM_WR_ADDR_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x07) // 0x1657*/
+/*#define FM_WR_ADDR_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x07) // 0x16a7*/
+/*----------- bit define -----------*/
+#define FM_ADVANCED_SETTING_HI 24
+#define FM_ADVANCED_SETTING_LO 16
+#define FM_WR_DATA_REQUEST 15
+
+/* bit 13:8 demux state -- read only*/
+/* bit 7:4 -- maxnum section filter compare address*/
+/* bit 3:0 -- maxnum PID filter compare address*/
+/*#define MAX_FM_COMP_ADDR
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x08) // 0x1608*/
+/*#define MAX_FM_COMP_ADDR_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x08) // 0x1658*/
+/*#define MAX_FM_COMP_ADDR_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x08) // 0x16a8*/
+/*----------- bit define -----------*/
+#define DEMUX_STATE 8
+#define MAX_FM_SECTION_FILTER_COMP_ADDR 4
+
+/* bit 15 - transport_error_indicator*/
+/* bit 14 - payload_unit_start_indicator*/
+/* bit 13 - transport_priority*/
+/* bit 12:0 - PID*/
+/*#define TS_HEAD_0
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x09) // 0x1609*/
+/*#define TS_HEAD_0_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x09) // 0x1659*/
+/*#define TS_HEAD_0_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x09) // 0x16a9*/
+/*----------- bit define -----------*/
+#define TRANSPORT_ERROR_INDICATOR 15
+#define PAYLOAD_UNIT_START_INDICATOR 14
+#define TRANSPORT_PRIORITY 13
+
+/* bit 7:6 transport_scrambling_control*/
+/* bit 5:4 adaptation_field_control*/
+/* bit 3:0 continuity_counter*/
+/*#define TS_HEAD_1
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x0a) // 0x160a*/
+/*#define TS_HEAD_1_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x0a) // 0x165a*/
+/*#define TS_HEAD_1_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x0a) // 0x16aa*/
+/*----------- bit define -----------*/
+#define TRANSPORT_SCRAMBLING_CONTROL 6
+#define ADAPTATION_FIELD_CONTROL 4
+
+/* bit 15:12 -- om_cmd_count (read only)*/
+/* bit 11:9 -- overflow_count // bit 11:9 -- om_cmd_wr_ptr (read only)*/
+/* bit 8:6 -- om_overwrite_count // bit 8:6 -- om_cmd_rd_ptr (read only)*/
+/* bit 5:3 -- type_stb_om_w_rd (read only)*/
+/* bit 2 -- unit_start_stb_om_w_rd (read only)*/
+/* bit 1 -- om_cmd_overflow (read only)*/
+/* bit 0 -- om_cmd_pending (read)*/
+/* bit 0 -- om_cmd_read_finished (write)*/
+/*#define OM_CMD_STATUS
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x0b) // 0x160b*/
+/*#define OM_CMD_STATUS_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x0b) // 0x165b*/
+/*#define OM_CMD_STATUS_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x0b) // 0x16ab*/
+/*----------- bit define -----------*/
+#define OM_CMD_COUNT 12
+#define OM_OVERFLOW_COUNT 9
+#define OM_OVERWRITE_COUNT 6
+#define TYPE_STB_OM_W_RD 3
+#define UNIT_START_STB_OM_W_RD 2
+#define OM_CMD_OVERFLOW 1
+
+/* bit 15:9 -- count_stb_om_w_rd (read only)*/
+/* bit 8:0 -- start_stb_om_wa_rd (read only)*/
+/*#define OM_CMD_DATA
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x0c) // 0x160c*/
+/*#define OM_CMD_DATA_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x0c) // 0x165c*/
+/*#define OM_CMD_DATA_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x0c) // 0x16ac*/
+/*----------- bit define -----------*/
+#define COUNT_STB_OM_W_RD 9
+
+/* bit 11:0 -- offset for section data*/
+/*#define OM_CMD_DATA2
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x0d) // 0x160d*/
+/*#define OM_CMD_DATA2_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x0d) // 0x165d*/
+/*#define OM_CMD_DATA2_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x0d) // 0x16ad*/
+
+/* bit 31:16 -- base address for section buffer group 0
+ * (*0x400 to get real address)*/
+/* bit 15:0 -- base address for section buffer group 1
+ * (*0x400 to get real address)*/
+/*#define SEC_BUFF_01_START
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x0e) // 0x160e*/
+/*#define SEC_BUFF_01_START_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x0e) // 0x165e*/
+/*#define SEC_BUFF_01_START_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x0e) // 0x16ae*/
+/*----------- bit define -----------*/
+#define SEC_BUFF_0_BASE_ADDR 16
+
+/* bit 31:16 -- base address for section buffer group 2
+ * (*0x400 to get real address)*/
+/* bit 15:0 -- base address for section buffer group 3
+ * (*0x400 to get real address)*/
+/*#define SEC_BUFF_23_START
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x0f) // 0x160f*/
+/*#define SEC_BUFF_23_START_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x0f) // 0x165f*/
+/*#define SEC_BUFF_23_START_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x0f) // 0x16af*/
+/*----------- bit define -----------*/
+#define SEC_BUFF_2_BASE_ADDR 16
+
+/* bit 15:12 -- section buffer size for group 3*/
+/* bit 11:8 -- section buffer size for group 2*/
+/* bit 7:4 -- section buffer size for group 1*/
+/* bit 3:0 -- section buffer size for group 0
+ * (bit used, for example, 10 means 1K)*/
+/*#define SEC_BUFF_SIZE
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x10) // 0x1610*/
+/*#define SEC_BUFF_SIZE_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x10) // 0x1660*/
+/*#define SEC_BUFF_SIZE_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x10) // 0x16b0*/
+/*----------- bit define -----------*/
+#define SEC_BUFF_3_SIZE 12
+#define SEC_BUFF_2_SIZE 8
+#define SEC_BUFF_1_SIZE 4
+
+/* section buffer busy status for buff 31:0 ( Read Only )*/
+/*#define SEC_BUFF_BUSY
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x11) // 0x1611*/
+/*#define SEC_BUFF_BUSY_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x11) // 0x1661*/
+/*#define SEC_BUFF_BUSY_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x11) // 0x16b1*/
+
+/* section buffer write status for buff 31:0 -- Read*/
+/* clear buffer status ( buff READY and BUSY ) -- write*/
+/*#define SEC_BUFF_READY
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x12) // 0x1612*/
+/*#define SEC_BUFF_READY_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x12) // 0x1662*/
+/*#define SEC_BUFF_READY_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x12) // 0x16b2*/
+
+/* bit 15 -- section_reset_busy (Read Only)*/
+/* bit 14 -- output_section_buffer_valid*/
+/* bit 12:8 -- SEC_BUFFER_NUMBER for the INDEX buffer Read_Only*/
+/* bit 4:0 -- SEC_BUFFER_INDEX RW*/
+/*#define SEC_BUFF_NUMBER
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x13) // 0x1613*/
+/*#define SEC_BUFF_NUMBER_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x13) // 0x1663*/
+/*#define SEC_BUFF_NUMBER_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x13) // 0x16b3*/
+/*----------- bit define -----------*/
+#define SECTION_RESET_BUSY 15
+#define OUTPUT_SECTION_BUFFER_VALID 14
+#define INDEXED_SEC_BUFF_NUMBER 8
+
+/* bit 9:5 -- BYPASS PID number*/
+/* bit 4:0 -- PCR PID number*/
+/*#define ASSIGN_PID_NUMBER
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x14) // 0x1614*/
+/*#define ASSIGN_PID_NUMBER_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x14) // 0x1664*/
+/*#define ASSIGN_PID_NUMBER_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x14) // 0x16b4*/
+/*----------- bit define -----------*/
+#define BYPASS_PID_NUMBER 5
+
+/* bit 15:0 -- stream_id filter bit enable*/
+/* bit 7:0 -- stream_id filter target*/
+/*#define VIDEO_STREAM_ID
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x15) // 0x1615*/
+/*#define VIDEO_STREAM_ID_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x15) // 0x1665*/
+/*#define VIDEO_STREAM_ID_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x15) // 0x16b5*/
+
+/*#define AUDIO_STREAM_ID
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x16) // 0x1616*/
+/*#define AUDIO_STREAM_ID_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x16) // 0x1666*/
+/*#define AUDIO_STREAM_ID_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x16) // 0x16b6*/
+
+/*#define SUB_STREAM_ID
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x17) // 0x1617*/
+/*#define SUB_STREAM_ID_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x17) // 0x1667*/
+/*#define SUB_STREAM_ID_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x17) // 0x16b7*/
+
+/*#define OTHER_STREAM_ID
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x18) // 0x1618*/
+/*#define OTHER_STREAM_ID_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x18) // 0x1668*/
+/*#define OTHER_STREAM_ID_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x18) // 0x16b8*/
+
+/* bit 12 -- PCR_EN*/
+/* bit 11:0 -- PCR90K_DIV*/
+/*#define PCR90K_CTL
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x19) // 0x1619*/
+/*#define PCR90K_CTL_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x19) // 0x1669*/
+/*#define PCR90K_CTL_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x19) // 0x16b9*/
+/*----------- bit define -----------*/
+#define PCR_EN 12
+
+/* bit 15:0 -- PCR[31:0] R/W*/
+/*#define PCR_DEMUX
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x1a) // 0x161a*/
+/*#define PCR_DEMUX_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x1a) // 0x166a*/
+/*#define PCR_DEMUX_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x1a) // 0x16ba*/
+
+/* bit 15:0 -- VPTS[31:0] R/W*/
+/*#define VIDEO_PTS_DEMUX
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x1b) // 0x161b*/
+/*#define VIDEO_PTS_DEMUX_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x1b) // 0x166b*/
+/*#define VIDEO_PTS_DEMUX_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x1b) // 0x16bb*/
+
+/* bit 15:0 -- VDTS[31:0] R/W*/
+/*#define VIDEO_DTS_DEMUX
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x1c) // 0x161c*/
+/*#define VIDEO_DTS_DEMUX_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x1c) // 0x166c*/
+/*#define VIDEO_DTS_DEMUX_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x1c) // 0x16bc*/
+
+/* bit 15:0 -- APTS[31:0] R/W*/
+/*#define AUDIO_PTS_DEMUX
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x1d) // 0x161d*/
+/*#define AUDIO_PTS_DEMUX_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x1d) // 0x166d*/
+/*#define AUDIO_PTS_DEMUX_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x1d) // 0x16bd*/
+
+/* bit 15:0 -- SPTS[31:0] R/W*/
+/*#define SUB_PTS_DEMUX
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x1e) // 0x161e*/
+/*#define SUB_PTS_DEMUX_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x1e) // 0x166e*/
+/*#define SUB_PTS_DEMUX_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x1e) // 0x16be*/
+
+/* read -- status, write 1 clear status*/
+/* bit 15 -- SUB_PTS[32]*/
+/* bit 14 -- AUDIO_PTS[32]*/
+/* bit 13 -- VIDEO_DTS[32]*/
+/* bit 12 -- VIDEO_PTS[32]*/
+/* bit 3 -- sub_pts_ready*/
+/* bit 2 -- audio_pts_ready*/
+/* bit 1 -- video_dts_ready*/
+/* bit 0 -- video_pts_ready*/
+/*#define STB_PTS_DTS_STATUS
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x1f) // 0x161f*/
+/*#define STB_PTS_DTS_STATUS_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x1f) // 0x166f*/
+/*#define STB_PTS_DTS_STATUS_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x1f) // 0x16bf*/
+/*----------- bit define -----------*/
+#define SUB_PTS_BIT32 15
+#define AUDIO_PTS_BIT32 14
+#define VIDEO_DTS_BIT32 13
+#define VIDEO_PTS_BIT32 12
+#define SUB_PTS_READY 3
+#define AUDIO_PTS_READY 2
+#define VIDEO_DTS_READY 1
+#define VIDEO_PTS_READY 0
+
+/* bit 3:0 --*/
+/* 0 -- adaptation_field_length[7:0], adaption_field_byte_1[7:0]*/
+/* 1 -- stream_id[7:0], pes_header_bytes_left[7:0]*/
+/* 2 -- pes_package_bytes_left[15:0]*/
+/* 3 -- pes_ctr_byte[7:0], pes_flag_byte[7:0]*/
+/*#define STB_DEBUG_INDEX
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x20) // 0x1620*/
+/*#define STB_DEBUG_INDEX_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x20) // 0x1670*/
+/*#define STB_DEBUG_INDEX_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x20) // 0x16c0*/
+
+/* read only*/
+/*#define STB_DEBUG_DATA_OUT
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x21) // 0x1621*/
+/*#define STB_DEBUG_DATA_OUT_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x21) // 0x1671*/
+/*#define STB_DEBUG_DATA_OUT_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x21) // 0x16c1*/
+
+/* bit[31] -- no_match_record_en*/
+/* bit[30:16] - reserved*/
+/* default : 0x807f*/
+/* bit 15:9 -- MAX OM DMA COUNT (default: 0x40)*/
+/* bit 8:0 -- LAST ADDR OF OM ADDR (default: 127)*/
+/*#define STB_OM_CTL \
+ (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x22) // 0x1622*/
+/*#define STB_OM_CTL_2 \
+ (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x22) // 0x1672*/
+/*#define STB_OM_CTL_3 \
+ (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x22) // 0x16c2*/
+/*----------- bit define -----------*/
+#define MAX_OM_DMA_COUNT 9
+#define LAST_OM_ADDR 0
+
+/* 15:0 WRITE 1 CLEAR to clear interrupt source*/
+/*12 -- INPUT_TIME_OUT*/
+/*11 -- PCR_ready*/
+/*10 -- audio_splicing_point*/
+/* 9 -- video_splicing_point*/
+/* 8 -- other_PES_int*/
+/* 7 -- sub_PES_int*/
+/* 6 -- discontinuity*/
+/* 5 -- duplicated_pack_found*/
+/* 4 -- New PDTS ready*/
+/* 3 -- om_cmd_buffer ready for access*/
+/* 2 -- section buffer ready*/
+/* 1 -- transport_error_indicator*/
+/* 0 -- TS ERROR PIN*/
+/*#define STB_INT_STATUS
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x23) // 0x1623*/
+/*#define STB_INT_STATUS_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x23) // 0x1673*/
+/*#define STB_INT_STATUS_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x23) // 0x16c3*/
+/*----------- bit define -----------*/
+#define INPUT_TIME_OUT 12
+#define PCR_READY 11
+#define AUDIO_SPLICING_POINT 10
+#define VIDEO_SPLICING_POINT 9
+#define OTHER_PES_READY 8
+#define SUB_PES_READY 7
+#define DIS_CONTINUITY_PACKET 6
+#define DUPLICATED_PACKET 5
+#define NEW_PDTS_READY 4
+#define OM_CMD_READ_PENDING 3
+#define SECTION_BUFFER_READY 2
+#define TS_ERROR_PACKAGE 1
+#define TS_ERROR_PIN 0
+
+/* When Bit 31 - 1 write will indicate all type use sepertate endian
+ * (Write Only)*/
+/* When Bit 31 - 0 write will indicate all type else use Bit 8:6*/
+/* Bit 23:21 - demux om write endian control for OTHER_PES_PACKET*/
+/* Bit 20:18 - demux om write endian control for SCR_ONLY_PACKET*/
+/* Bit 17:15 - demux om write endian control for SUB_PACKET*/
+/* Bit 14:12 - demux om write endian control for AUDIO_PACKET*/
+/* Bit 11:9 - demux om write endian control for VIDEO_PACKET*/
+/* Bit 8:6 - demux om write endian control for else*/
+/* Bit 5:3 - demux om write endian control for bypass*/
+/* Bit 2:0 - demux om write endian control for section*/
+/*#define DEMUX_ENDIAN
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x24) // 0x1624*/
+/*#define DEMUX_ENDIAN_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x24) // 0x1674*/
+/*#define DEMUX_ENDIAN_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x24) // 0x16c4*/
+/*----------- bit define -----------*/
+#define SEPERATE_ENDIAN 31
+#define OTHER_PES_ENDIAN 21
+#define SCR_ENDIAN 18
+#define SUB_ENDIAN 15
+#define AUDIO_ENDIAN 12
+#define VIDEO_ENDIAN 9
+#define OTHER_ENDIAN 6
+#define BYPASS_ENDIAN 3
+#define SECTION_ENDIAN 0
+
+/* Bit 10:9 -- PDTS_wr_sel: 0 select video_PDTS_wr_ptr; 1 select video_PDTS_wr_ptr_parser_B; */
+/* Bit 7:8 -- use hi_bsf interface*/
+/* Bit 6:2 - fec_clk_div*/
+/* Bit 1 ts_source_sel */
+/* Bit 0 - Hiu TS generate enable */
+/*#define TS_HIU_CTL
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x25) // 0x1625*/
+/*#define TS_HIU_CTL_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x25) // 0x1675*/
+/*#define TS_HIU_CTL_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x25) // 0x16c5*/
+/*----------- bit define -----------*/
+//#define LAST_BURST_THRESHOLD 8
+#define PDTS_WR_SEL 9
+#define USE_HI_BSF_INTERFACE 7
+
+/* bit 15:0 -- base address for section buffer start
+ * (*0x10000 to get real base)*/
+/*#define SEC_BUFF_BASE
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x26) // 0x1626*/
+/*#define SEC_BUFF_BASE_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x26) // 0x1676*/
+/*#define SEC_BUFF_BASE_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x26) // 0x16c6*/
+
+/* bit 11 -- mask bit for OTHER_PES_AHB_DMA_EN*/
+/* bit 10 -- mask bit for SUB_AHB_DMA_EN*/
+/* bit 9 -- mask bit for BYPASS_AHB_DMA_EN*/
+/* bit 8 -- mask bit for SECTION_AHB_DMA_EN*/
+/* bit 7 -- mask bit for recoder stream*/
+/* bit 6:0 -- mask bit for each type*/
+/*#define DEMUX_MEM_REQ_EN
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x27) // 0x1627*/
+/*#define DEMUX_MEM_REQ_EN_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x27) // 0x1677*/
+/*#define DEMUX_MEM_REQ_EN_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x27) // 0x16c7*/
+/*----------- bit define -----------*/
+#define VIDEO2_DMA_EN_BIT 12
+#define OTHER_PES_AHB_DMA_EN 11
+#define SUB_AHB_DMA_EN 10
+#define BYPASS_AHB_DMA_EN 9
+#define SECTION_AHB_DMA_EN 8
+#define RECORDER_STREAM 7
+#define OTHER_PES_PACKET 6
+#define SCR_ONLY_PACKET 5 /*will never be used*/
+#define BYPASS_PACKET 4
+#define SECTION_PACKET 3
+#define SUB_PACKET 2
+#define AUDIO_PACKET 1
+#define VIDEO_PACKET 0
+
+/* bit 31:0 -- vb_wr_ptr for video PDTS*/
+/*#define VIDEO_PDTS_WR_PTR
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x28) // 0x1628*/
+/*#define VIDEO_PDTS_WR_PTR_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x28) // 0x1678*/
+/*#define VIDEO_PDTS_WR_PTR_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x28) // 0x16c8*/
+
+/* bit 31:0 -- ab_wr_ptr for audio PDTS*/
+/*#define AUDIO_PDTS_WR_PTR
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x29) // 0x1629*/
+/*#define AUDIO_PDTS_WR_PTR_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x29) // 0x1679*/
+/*#define AUDIO_PDTS_WR_PTR_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x29) // 0x16c9*/
+
+/* bit 20:0 -- SB_WRITE_PTR (sb_wr_ptr << 3 == byte write position)*/
+/*#define SUB_WR_PTR
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x2a) // 0x162a*/
+/*#define SUB_WR_PTR_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x2a) // 0x167a*/
+/*#define SUB_WR_PTR_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x2a) // 0x16ca*/
+
+/* bit 19:0 -- SB_START (sb_start << 12 == byte address);*/
+/*#define SB_START
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x2b) // 0x162b*/
+/*#define SB_START_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x2b) // 0x167b*/
+/*#define SB_START_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x2b) // 0x16cb*/
+
+/* bit 20:0 -- SB_SIZE (sb_size << 3 == byte size, 16M maximun)*/
+/*#define SB_LAST_ADDR
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x2c) // 0x162c*/
+/*#define SB_LAST_ADDR_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x2c) // 0x167c*/
+/*#define SB_LAST_ADDR_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x2c) // 0x16cc*/
+
+/* bit 31:0 -- sb_wr_ptr for sub PES*/
+/*#define SB_PES_WRITE_PTR
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x2d) // 0x162d*/
+/*#define SB_PES_WRITE_PTR_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x2d) // 0x167d*/
+/*#define SB_PES_WRITE_PTR_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x2d) // 0x16cd*/
+
+/* bit 31:16 -- ob_wr_ptr for other PES*/
+/* bit 20:0 -- OB_WRITE_PTR (ob_wr_ptr << 3 == byte write position)*/
+/*#define OTHER_WR_PTR
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x2e) // 0x162e*/
+/*#define OTHER_WR_PTR_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x2e) // 0x167e*/
+/*#define OTHER_WR_PTR_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x2e) // 0x16ce*/
+
+/* bit 19:0 -- OB_START (ob_start << 12 == byte address);*/
+/*#define OB_START
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x2f) // 0x162f*/
+/*#define OB_START_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x2f) // 0x167f*/
+/*#define OB_START_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x2f) // 0x16cf*/
+
+/* bit 20:0 -- OB_SIZE (ob_size << 3 == byte size, 16M maximun)*/
+/*#define OB_LAST_ADDR
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x30) // 0x1630*/
+/*#define OB_LAST_ADDR_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x30) // 0x1680*/
+/*#define OB_LAST_ADDR_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x30) // 0x16d0*/
+
+/* bit 31:0 -- ob_wr_ptr for sub PES*/
+/*#define OB_PES_WRITE_PTR
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x31) // 0x1631*/
+/*#define OB_PES_WRITE_PTR_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x31) // 0x1681*/
+/*#define OB_PES_WRITE_PTR_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x31) // 0x16d1*/
+
+/* 15:0 DEMUX interrupt MASK*/
+/* 11 -- PCR_READY*/
+/* 10 -- audio_splicing_point*/
+/* 9 -- video_splicing_point*/
+/* 8 -- other_PES_int*/
+/* 7 -- sub_PES_int*/
+/* 6 -- discontinuity*/
+/* 5 -- duplicated_pack_found*/
+/* 4 -- New PDTS ready*/
+/* 3 -- om_cmd_buffer ready for access*/
+/* 2 -- section buffer ready*/
+/* 1 -- transport_error_indicator*/
+/* 0 -- TS ERROR PIN*/
+/*#define STB_INT_MASK
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x32) // 0x1632*/
+/*#define STB_INT_MASK_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x32) // 0x1682*/
+/*#define STB_INT_MASK_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x32) // 0x16d2*/
+
+/* 31:16 VIDEO PID filter data*/
+/*15 -- splicing VIDEO PID change enable*/
+/*14:10 -- VIDEO PID FILTER ADDRESS*/
+/* 9 -- PES splicing active (Read Only)*/
+/* 8 -- splicing active (Read Only)*/
+/* 7:0 splicing countdown (Read Only)*/
+/*#define VIDEO_SPLICING_CTL
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x33) // 0x1633*/
+/*#define VIDEO_SPLICING_CTL_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x33) // 0x1683*/
+/*#define VIDEO_SPLICING_CTL_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x33) // 0x16d3*/
+/*----------- bit define -----------*/
+#define VIDEO_PID_FILTER_DATA 16
+#define VIDEO_SPLICING_PID_CHANGE_ENABLE 15
+#define VIDEO_PID_FILTER_ADDRESS 10
+#define VIDEO_PES_SPLICING_ACTIVE 9
+#define VIDEO_SPLICING_ACTIVE 8
+
+
+/* 31:16 AUDIO PID filter data*/
+/*15 -- splicing AUDIO PID change enable*/
+/*14:10 -- AUDIO PID FILTER ADDRESS*/
+/* 9 -- PES splicing active (Read Only)*/
+/* 8 -- splicing active (Read Only)*/
+/* 7:0 splicing countdown (Read Only)*/
+/*#define AUDIO_SPLICING_CTL
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x34) // 0x1634*/
+/*#define AUDIO_SPLICING_CTL_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x34) // 0x1684*/
+/*#define AUDIO_SPLICING_CTL_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x34) // 0x16d4*/
+/*----------- bit define -----------*/
+#define AUDIO_PID_FILTER_DATA 16
+#define AUDIO_SPLICING_PID_CHANGE_ENABLE 15
+#define AUDIO_PID_FILTER_ADDRESS 10
+#define AUDIO_PES_SPLICING_ACTIVE 9
+#define AUDIO_SPLICING_ACTIVE 8
+
+/* 23:16 M2TS_SKIP_BYTES*/
+/* 15:8 LAST TS PACKAGE BYTE COUNT (Read Only)*/
+/* 7:0 PACKAGE BYTE COUNT (Read Only)*/
+/*#define TS_PACKAGE_BYTE_COUNT
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x35) // 0x1635*/
+/*#define TS_PACKAGE_BYTE_COUNT_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x35) // 0x1685*/
+/*#define TS_PACKAGE_BYTE_COUNT_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x35) // 0x16d5*/
+/*----------- bit define -----------*/
+#define M2TS_SKIP_BYTES 16
+#define LAST_TS_PACKAGE_BYTE_COUNT 8
+
+/* 15:0 2 bytes strong sync add to PES*/
+/*#define PES_STRONG_SYNC
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x36) // 0x1636*/
+/*#define PES_STRONG_SYNC_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x36) // 0x1686*/
+/*#define PES_STRONG_SYNC_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x36) // 0x16d6*/
+
+/* bit 15 -- stb_om_ren*/
+/* bit 14:11 -- reserved*/
+/* bit 10:0 -- OM_DATA_RD_ADDR*/
+/*#define OM_DATA_RD_ADDR
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x37) // 0x1637*/
+/*#define OM_DATA_RD_ADDR_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x37) // 0x1687*/
+/*#define OM_DATA_RD_ADDR_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x37) // 0x16d7*/
+/*----------- bit define -----------*/
+#define STB_OM_REN 15
+
+/* bit 15:0 -- OM_DATA_RD*/
+/*#define OM_DATA_RD
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x38) // 0x1638*/
+/*#define OM_DATA_RD_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x38) // 0x1688*/
+/*#define OM_DATA_RD_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x38) // 0x16d8*/
+
+/* AUTO STOP SETTING for 32 channels*/
+/* 4-bits per channel*/
+/* when write*/
+/* bit 3 -- set section active*/
+/* bit 2:0 -- auto stop after count (0 means never stop)*/
+/* when read*/
+/* bit 3 -- current active status (1 - active, 0 - stopped )*/
+/* bit 2:0 -- count down to auto stop*/
+/* section 31:24*/
+/*#define SECTION_AUTO_STOP_3
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x39) // 0x1639*/
+/*#define SECTION_AUTO_STOP_3_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x39) // 0x1689*/
+/*#define SECTION_AUTO_STOP_3_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x39) // 0x16d9*/
+/* section 23:16*/
+/*#define SECTION_AUTO_STOP_2
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x3a) // 0x163a*/
+/*#define SECTION_AUTO_STOP_2_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x3a) // 0x168a*/
+/*#define SECTION_AUTO_STOP_2_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x3a) // 0x16da*/
+/* section 15:8*/
+/*#define SECTION_AUTO_STOP_1
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x3b) // 0x163b*/
+/*#define SECTION_AUTO_STOP_1_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x3b) // 0x168b*/
+/*#define SECTION_AUTO_STOP_1_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x3b) // 0x16db*/
+/* section 7:0*/
+/*#define SECTION_AUTO_STOP_0
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x3c) // 0x163c*/
+/*#define SECTION_AUTO_STOP_0_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x3c) // 0x168c*/
+/*#define SECTION_AUTO_STOP_0_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x3c) // 0x16dc*/
+
+/* bit 31:0 reset channel status - each bit reset each channel*/
+/* read -- 32 channel status*/
+/*#define DEMUX_CHANNEL_RESET
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x3d) // 0x163d*/
+/*#define DEMUX_CHANNEL_RESET_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x3d) // 0x168d*/
+/*#define DEMUX_CHANNEL_RESET_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x3d) // 0x16dd*/
+
+/*#define DEMUX_SCRAMBLING_STATE
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x3e) // 0x163e*/
+/*#define DEMUX_SCRAMBLING_STATE_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x3e) // 0x168e*/
+/*#define DEMUX_SCRAMBLING_STATE_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x3e) // 0x16de*/
+
+/*#define DEMUX_CHANNEL_ACTIVITY
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x3f) // 0x163f*/
+/*#define DEMUX_CHANNEL_ACTIVITY_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x3f) // 0x168f*/
+/*#define DEMUX_CHANNEL_ACTIVITY_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x3f) // 0x16df*/
+
+/* bit 4 -- video_stamp_use_dts*/
+/* bit 3 -- audio_stamp_sync_1_en*/
+/* bit 2 -- audio_stamp_insert_en*/
+/* bit 1 -- video_stamp_sync_1_en*/
+/* bit 0 -- video_stamp_insert_en*/
+/*#define DEMUX_STAMP_CTL
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x40) // 0x1640*/
+/*#define DEMUX_STAMP_CTL_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x40) // 0x1690*/
+/*#define DEMUX_STAMP_CTL_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x40) // 0x16e0*/
+
+/*#define DEMUX_VIDEO_STAMP_SYNC_0
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x41) // 0x1641*/
+/*#define DEMUX_VIDEO_STAMP_SYNC_0_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x41) // 0x1691*/
+/*#define DEMUX_VIDEO_STAMP_SYNC_0_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x41) // 0x16e1*/
+
+/*#define DEMUX_VIDEO_STAMP_SYNC_1
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x42) // 0x1642*/
+/*#define DEMUX_VIDEO_STAMP_SYNC_1_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x42) // 0x1692*/
+/*#define DEMUX_VIDEO_STAMP_SYNC_1_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x42) // 0x16e2*/
+
+/*#define DEMUX_AUDIO_STAMP_SYNC_0
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x43) // 0x1643*/
+/*#define DEMUX_AUDIO_STAMP_SYNC_0_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x43) // 0x1693*/
+/*#define DEMUX_AUDIO_STAMP_SYNC_0_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x43) // 0x16e3*/
+
+/*#define DEMUX_AUDIO_STAMP_SYNC_1
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x44) // 0x1644*/
+/*#define DEMUX_AUDIO_STAMP_SYNC_1_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x44) // 0x1694*/
+/*#define DEMUX_AUDIO_STAMP_SYNC_1_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x44) // 0x16e4*/
+
+/* Write : Bit[4:0] secter filter number for reset*/
+/* Read : select according to output_section_buffer_valid :*/
+/* per bit per section buffer valid status*/
+/* or section_buffer_ignore*/
+/*#define DEMUX_SECTION_RESET
+ * (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x45) // 0x1645*/
+/*#define DEMUX_SECTION_RESET_2
+ * (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x45) // 0x1695*/
+/*#define DEMUX_SECTION_RESET_3
+ * (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x45) // 0x16e5*/
+
+
+/* bit[31:0] - channel_reset_timeout_disable*/
+/*#define DEMUX_INPUT_TIMEOUT_C \
+ (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x46) // 0x1646*/
+/*#define DEMUX_INPUT_TIMEOUT_C_2 \
+ (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x46) // 0x1696*/
+/*#define DEMUX_INPUT_TIMEOUT_C_3 \
+ (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x46) // 0x16e6*/
+/* bit[31] - no_match_reset_timeout_disable*/
+/* bit[30:0] input_time_out_int_cnt (0 -- means disable) Wr-setting, Rd-count*/
+/*#define DEMUX_INPUT_TIMEOUT \
+ (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x47) // 0x1647*/
+/*#define DEMUX_INPUT_TIMEOUT_2 \
+ (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x47) // 0x1697*/
+/*#define DEMUX_INPUT_TIMEOUT_3 \
+ (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x47) // 0x16e7*/
+
+/* bit[31:0] - channel_packet_count_disable*/
+/*#define DEMUX_PACKET_COUNT_C \
+ (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x48) // 0x1648*/
+/*#define DEMUX_PACKET_COUNT_C_2 \
+ (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x48) // 0x1698*/
+/*#define DEMUX_PACKET_COUNT_C_3 \
+ (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x48)*/ /* 0x16e8*/
+/* bit[31] - no_match_packet_count_disable*/
+/* bit[30:0] input_packet_count*/
+/*#define DEMUX_PACKET_COUNT \
+ (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x49) // 0x1649*/
+/*#define DEMUX_PACKET_COUNT_2 \
+ (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x49) // 0x1699*/
+/*#define DEMUX_PACKET_COUNT_3 \
+ (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x49) // 0x16e9*/
+
+/* bit[31:0] channel_record_enable*/
+/*#define DEMUX_CHAN_RECORD_EN \
+ (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x4a) // 0x164a*/
+/*#define DEMUX_CHAN_RECORD_EN_2 \
+ (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x4a) // 0x169a*/
+/*#define DEMUX_CHAN_RECORD_EN_3 \
+ (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x4a) // 0x16ea*/
+
+/* bit[31:0] channel_process_enable*/
+/*#define DEMUX_CHAN_PROCESS_EN \
+ (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x4b) // 0x164b*/
+/*#define DEMUX_CHAN_PROCESS_EN_2 \
+ (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x4b) */ /* 0x169b*/
+/*#define DEMUX_CHAN_PROCESS_EN_3 \
+ (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x4b) // 0x16eb*/
+
+/* bit[31:24] small_sec_size ((n+1) * 256 Bytes)*/
+/* bit[23:16] small_sec_rd_ptr */
+/* bit[15:8] small_sec_wr_ptr */
+/* bit[7:2] reserved*/
+/* bit[1] small_sec_wr_ptr_wr_enable*/
+/* bit[0] small_section_enable*/
+/*#define DEMUX_SMALL_SEC_CTL \
+ (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x4c)*/ /* 0x164c*/
+/*#define DEMUX_SMALL_SEC_CTL_2 \
+ (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x4c) // 0x169c*/
+/*#define DEMUX_SMALL_SEC_CTL_3 \
+ (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x4c) // 0x16ec*/
+/* bit[31:0] small_sec_start_addr*/
+/*#define DEMUX_SMALL_SEC_ADDR \
+ (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x4d) // 0x164d*/
+/*#define DEMUX_SMALL_SEC_ADDR_2 \
+ (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x4d) // 0x169d*/
+/*#define DEMUX_SMALL_SEC_ADDR_3 \
+ (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x4d) // 0x16ed*/
+
+
+/*======================================================*/
+/* STB Registers End*/
+/*====================================================*/
+/* ----------------------------*/
+/* ASYNC FIFO (4)*/
+/* ----------------------------*/
+/*#define ASYNC_FIFO_REG0 0x2310*/
+/*#define ASYNC_FIFO_REG1 0x2311*/
+#define ASYNC_FIFO_FLUSH_STATUS 31
+#define ASYNC_FIFO_ERR 30
+#define ASYNC_FIFO_FIFO_EMPTY 29
+#define ASYNC_FIFO_TO_HIU 24
+#define ASYNC_FIFO_FLUSH 23
+#define ASYNC_FIFO_RESET 22
+#define ASYNC_FIFO_WRAP_EN 21
+#define ASYNC_FIFO_FLUSH_EN 20
+#define ASYNC_FIFO_RESIDUAL_MSB 19
+#define ASYNC_FIFO_RESIDUAL_LSB 15
+#define ASYNC_FIFO_FLUSH_CNT_MSB 14
+#define ASYNC_FIFO_FLUSH_CNT_LSB 0
+/*#define ASYNC_FIFO_REG2 0x2312*/
+#define ASYNC_FIFO_FIFO_FULL 26
+#define ASYNC_FIFO_FILL_STATUS 25
+#define ASYNC_FIFO_SOURCE_MSB 24
+#define ASYNC_FIFO_SOURCE_LSB 23
+#define ASYNC_FIFO_ENDIAN_MSB 22
+#define ASYNC_FIFO_ENDIAN_LSB 21
+#define ASYNC_FIFO_FILL_EN 20
+#define ASYNC_FIFO_FILL_CNT_MSB 19
+#define ASYNC_FIFO_FILL_CNT_LSB 0
+/*#define ASYNC_FIFO_REG3 0x2313*/
+#define ASYNC_FLUSH_SIZE_IRQ_MSB 15
+#define ASYNC_FLUSH_SIZE_IRQ_LSB 0
+/* ----------------------------*/
+/* ASYNC FIFO (4)*/
+/* ----------------------------*/
+/*#define ASYNC_FIFO2_REG0 0x2314*/
+/*#define ASYNC_FIFO2_REG1 0x2315*/
+/*#define ASYNC_FIFO2_REG2 0x2316*/
+/*#define ASYNC_FIFO2_REG3 0x2317*/
+
+#define RESET_DEMUXSTB (1 << 1)
+#endif /* C_STB_DEFINE_H*/
diff --git a/drivers/stream_input/parser/hw_demux/c_stb_regs_define.h b/drivers/stream_input/parser/hw_demux/c_stb_regs_define.h
new file mode 100644
index 0000000..b12db68
--- /dev/null
+++ b/drivers/stream_input/parser/hw_demux/c_stb_regs_define.h
@@ -0,0 +1,814 @@
+/*
+* 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:
+*/
+/*
+ * This file is automaticly generated by genregs.awk. Please do not edit it
+ * Base files are ..
+ * ..
+ * ..
+ * Tue Oct 22 15:28:48 CST 2013
+ **/
+
+#ifndef __MACH_MESON8_REG_ADDR_H_
+#define __MACH_MESON8_REG_ADDR_H_
+#include <linux/amlogic/iomap.h>
+#define CBUS_REG_ADDR(_r) aml_read_cbus(_r)
+
+
+#define STB_CBUS_BASE aml_stb_get_base(ID_STB_CBUS_BASE)
+#define SMARTCARD_REG_BASE aml_stb_get_base(ID_SMARTCARD_REG_BASE)
+#define ASYNC_FIFO_REG_BASE aml_stb_get_base(ID_ASYNC_FIFO_REG_BASE)
+#define ASYNC_FIFO1_REG_BASE aml_stb_get_base(ID_ASYNC_FIFO1_REG_BASE)
+#define ASYNC_FIFO2_REG_BASE aml_stb_get_base(ID_ASYNC_FIFO2_REG_BASE)
+#define RESET_BASE aml_stb_get_base(ID_RESET_BASE)
+#define PARSER_SUB_START_PTR_BASE \
+ aml_stb_get_base(ID_PARSER_SUB_START_PTR_BASE)
+
+#define HHI_CSI_PHY_CNTL_BASE 0x1000
+
+#define DEMUX_1_OFFSET 0x00
+#define DEMUX_2_OFFSET 0x50
+#define DEMUX_3_OFFSET 0xa0
+
+
+#define TS_HIU1_CONFIG (STB_CBUS_BASE + 0x4e)
+#define P_TS_HIU1_CONFIG CBUS_REG_ADDR(TS_HIU1_CONFIG)
+
+#define TS_TOP_CONFIG1 (STB_CBUS_BASE + 0x4f)
+#define P_TS_TOP_CONFIG1 CBUS_REG_ADDR(TS_TOP_CONFIG1)
+
+#define STB_S2P2_CONFIG (STB_CBUS_BASE + 0xef)
+#define P_STB_S2P2_CONFIG CBUS_REG_ADDR(STB_S2P2_CONFIG)
+
+#define STB_RECORDER2_CNTL (STB_CBUS_BASE + 0xee)
+#define P_STB_RECORDER2_CNTL CBUS_REG_ADDR(STB_RECORDER2_CNTL)
+
+#define STB_TOP_CONFIG (STB_CBUS_BASE + 0xf0)
+#define P_STB_TOP_CONFIG CBUS_REG_ADDR(STB_TOP_CONFIG)
+#define TS_TOP_CONFIG (STB_CBUS_BASE + 0xf1)
+#define P_TS_TOP_CONFIG CBUS_REG_ADDR(TS_TOP_CONFIG)
+#define TS_FILE_CONFIG (STB_CBUS_BASE + 0xf2)
+#define P_TS_FILE_CONFIG CBUS_REG_ADDR(TS_FILE_CONFIG)
+#define TS_PL_PID_INDEX (STB_CBUS_BASE + 0xf3)
+#define P_TS_PL_PID_INDEX CBUS_REG_ADDR(TS_PL_PID_INDEX)
+#define TS_PL_PID_DATA (STB_CBUS_BASE + 0xf4)
+#define P_TS_PL_PID_DATA CBUS_REG_ADDR(TS_PL_PID_DATA)
+#define COMM_DESC_KEY0 (STB_CBUS_BASE + 0xf5)
+#define P_COMM_DESC_KEY0 CBUS_REG_ADDR(COMM_DESC_KEY0)
+#define COMM_DESC_KEY1 (STB_CBUS_BASE + 0xf6)
+#define P_COMM_DESC_KEY1 CBUS_REG_ADDR(COMM_DESC_KEY1)
+#define COMM_DESC_KEY_RW (STB_CBUS_BASE + 0xf7)
+#define P_COMM_DESC_KEY_RW CBUS_REG_ADDR(COMM_DESC_KEY_RW)
+#define CIPLUS_KEY0 (STB_CBUS_BASE + 0xf8)
+#define P_CIPLUS_KEY0 CBUS_REG_ADDR(CIPLUS_KEY0)
+#define CIPLUS_KEY1 (STB_CBUS_BASE + 0xf9)
+#define P_CIPLUS_KEY1 CBUS_REG_ADDR(CIPLUS_KEY1)
+#define CIPLUS_KEY2 (STB_CBUS_BASE + 0xfa)
+#define P_CIPLUS_KEY2 CBUS_REG_ADDR(CIPLUS_KEY2)
+#define CIPLUS_KEY3 (STB_CBUS_BASE + 0xfb)
+#define P_CIPLUS_KEY3 CBUS_REG_ADDR(CIPLUS_KEY3)
+#define CIPLUS_KEY_WR (STB_CBUS_BASE + 0xfc)
+#define P_CIPLUS_KEY_WR CBUS_REG_ADDR(CIPLUS_KEY_WR)
+#define CIPLUS_CONFIG (STB_CBUS_BASE + 0xfd)
+#define P_CIPLUS_CONFIG CBUS_REG_ADDR(CIPLUS_CONFIG)
+#define CIPLUS_ENDIAN (STB_CBUS_BASE + 0xfe)
+#define P_CIPLUS_ENDIAN CBUS_REG_ADDR(CIPLUS_ENDIAN)
+
+#define SMARTCARD_REG0 (SMARTCARD_REG_BASE + 0x0)
+#define P_SMARTCARD_REG0 CBUS_REG_ADDR(SMARTCARD_REG0)
+#define SMARTCARD_REG1 (SMARTCARD_REG_BASE + 0x1)
+#define P_SMARTCARD_REG1 CBUS_REG_ADDR(SMARTCARD_REG1)
+#define SMARTCARD_REG2 (SMARTCARD_REG_BASE + 0x2)
+#define P_SMARTCARD_REG2 CBUS_REG_ADDR(SMARTCARD_REG2)
+#define SMARTCARD_STATUS (SMARTCARD_REG_BASE + 0x3)
+#define P_SMARTCARD_STATUS CBUS_REG_ADDR(SMARTCARD_STATUS)
+#define SMARTCARD_INTR (SMARTCARD_REG_BASE + 0x4)
+#define P_SMARTCARD_INTR CBUS_REG_ADDR(SMARTCARD_INTR)
+#define SMARTCARD_REG5 (SMARTCARD_REG_BASE + 0x5)
+#define P_SMARTCARD_REG5 CBUS_REG_ADDR(SMARTCARD_REG5)
+#define SMARTCARD_REG6 (SMARTCARD_REG_BASE + 0x6)
+#define P_SMARTCARD_REG6 CBUS_REG_ADDR(SMARTCARD_REG6)
+#define SMARTCARD_FIFO (SMARTCARD_REG_BASE + 0x7)
+#define P_SMARTCARD_FIFO CBUS_REG_ADDR(SMARTCARD_FIFO)
+#define SMARTCARD_REG8 (SMARTCARD_REG_BASE + 0x8)
+#define P_SMARTCARD_REG8 CBUS_REG_ADDR(SMARTCARD_REG8)
+
+#define ASYNC_FIFO_REG0 (ASYNC_FIFO_REG_BASE + 0x0)
+#define P_ASYNC_FIFO_REG0 CBUS_REG_ADDR(ASYNC_FIFO_REG0)
+#define ASYNC_FIFO_REG1 (ASYNC_FIFO_REG_BASE + 0x1)
+#define P_ASYNC_FIFO_REG1 CBUS_REG_ADDR(ASYNC_FIFO_REG1)
+#define ASYNC_FIFO_REG2 (ASYNC_FIFO_REG_BASE + 0x2)
+#define P_ASYNC_FIFO_REG2 CBUS_REG_ADDR(ASYNC_FIFO_REG2)
+#define ASYNC_FIFO_REG3 (ASYNC_FIFO_REG_BASE + 0x3)
+#define P_ASYNC_FIFO_REG3 CBUS_REG_ADDR(ASYNC_FIFO_REG3)
+#define ASYNC_FIFO_REG4 (ASYNC_FIFO_REG_BASE + 0x4)
+#define P_ASYNC_FIFO_REG4 CBUS_REG_ADDR(ASYNC_FIFO_REG4)
+#define ASYNC_FIFO_REG5 (ASYNC_FIFO_REG_BASE + 0x5)
+#define P_ASYNC_FIFO_REG5 CBUS_REG_ADDR(ASYNC_FIFO_REG5)
+
+#define ASYNC_FIFO1_REG0 (ASYNC_FIFO1_REG_BASE + 0x0)
+#define P_ASYNC_FIFO1_REG0 CBUS_REG_ADDR(ASYNC_FIFO1_REG0)
+#define ASYNC_FIFO1_REG1 (ASYNC_FIFO1_REG_BASE + 0x1)
+#define P_ASYNC_FIFO1_REG1 CBUS_REG_ADDR(ASYNC_FIFO1_REG1)
+#define ASYNC_FIFO1_REG2 (ASYNC_FIFO1_REG_BASE + 0x2)
+#define P_ASYNC_FIFO1_REG2 CBUS_REG_ADDR(ASYNC_FIFO1_REG2)
+#define ASYNC_FIFO1_REG3 (ASYNC_FIFO1_REG_BASE + 0x3)
+#define P_ASYNC_FIFO1_REG3 CBUS_REG_ADDR(ASYNC_FIFO1_REG3)
+#define ASYNC_FIFO1_REG4 (ASYNC_FIFO1_REG_BASE + 0x4)
+#define P_ASYNC_FIFO1_REG4 CBUS_REG_ADDR(ASYNC_FIFO1_REG4)
+#define ASYNC_FIFO1_REG5 (ASYNC_FIFO1_REG_BASE + 0x5)
+#define P_ASYNC_FIFO1_REG5 CBUS_REG_ADDR(ASYNC_FIFO1_REG5)
+
+
+#define ASYNC_FIFO2_REG0 (ASYNC_FIFO2_REG_BASE + 0x0)
+#define P_ASYNC_FIFO2_REG0 CBUS_REG_ADDR(ASYNC_FIFO2_REG0)
+#define ASYNC_FIFO2_REG1 (ASYNC_FIFO2_REG_BASE + 0x1)
+#define P_ASYNC_FIFO2_REG1 CBUS_REG_ADDR(ASYNC_FIFO2_REG1)
+#define ASYNC_FIFO2_REG2 (ASYNC_FIFO2_REG_BASE + 0x2)
+#define P_ASYNC_FIFO2_REG2 CBUS_REG_ADDR(ASYNC_FIFO2_REG2)
+#define ASYNC_FIFO2_REG3 (ASYNC_FIFO2_REG_BASE + 0x3)
+#define P_ASYNC_FIFO2_REG3 CBUS_REG_ADDR(ASYNC_FIFO2_REG3)
+#define ASYNC_FIFO2_REG4 (ASYNC_FIFO2_REG_BASE + 0x4)
+#define P_ASYNC_FIFO2_REG4 CBUS_REG_ADDR(ASYNC_FIFO2_REG4)
+#define ASYNC_FIFO2_REG5 (ASYNC_FIFO2_REG_BASE + 0x5)
+#define P_ASYNC_FIFO2_REG5 CBUS_REG_ADDR(ASYNC_FIFO2_REG5)
+
+
+#define RESET0_REGISTER (RESET_BASE + 0x1)
+#define P_RESET0_REGISTER CBUS_REG_ADDR(RESET0_REGISTER)
+#define RESET1_REGISTER (RESET_BASE + 0x2)
+#define P_RESET1_REGISTER CBUS_REG_ADDR(RESET1_REGISTER)
+#define RESET2_REGISTER (RESET_BASE + 0x3)
+#define P_RESET2_REGISTER CBUS_REG_ADDR(RESET2_REGISTER)
+#define RESET3_REGISTER (RESET_BASE + 0x4)
+#define P_RESET3_REGISTER CBUS_REG_ADDR(RESET3_REGISTER)
+#define RESET4_REGISTER (RESET_BASE + 0x5)
+#define P_RESET4_REGISTER CBUS_REG_ADDR(RESET4_REGISTER)
+#define RESET5_REGISTER (RESET_BASE + 0x6)
+#define P_RESET5_REGISTER CBUS_REG_ADDR(RESET5_REGISTER)
+#define RESET6_REGISTER (RESET_BASE + 0x7)
+#define P_RESET6_REGISTER CBUS_REG_ADDR(RESET6_REGISTER)
+#define RESET7_REGISTER (RESET_BASE + 0x8)
+#define P_RESET7_REGISTER CBUS_REG_ADDR(RESET7_REGISTER)
+#define RESET0_MASK (RESET_BASE + 0x10)
+#define P_RESET0_MASK CBUS_REG_ADDR(RESET0_MASK)
+#define RESET1_MASK (RESET_BASE + 0x11)
+#define P_RESET1_MASK CBUS_REG_ADDR(RESET1_MASK)
+#define RESET2_MASK (RESET_BASE + 0x12)
+#define P_RESET2_MASK CBUS_REG_ADDR(RESET2_MASK)
+#define RESET3_MASK (RESET_BASE + 0x13)
+#define P_RESET3_MASK CBUS_REG_ADDR(RESET3_MASK)
+#define RESET4_MASK (RESET_BASE + 0x14)
+#define P_RESET4_MASK CBUS_REG_ADDR(RESET4_MASK)
+#define RESET5_MASK (RESET_BASE + 0x15)
+#define P_RESET5_MASK CBUS_REG_ADDR(RESET5_MASK)
+#define RESET6_MASK (RESET_BASE + 0x16)
+#define P_RESET6_MASK CBUS_REG_ADDR(RESET6_MASK)
+#define CRT_MASK (RESET_BASE + 0x17)
+#define P_CRT_MASK CBUS_REG_ADDR(CRT_MASK)
+#define RESET7_MASK (RESET_BASE + 0x18)
+#define P_RESET7_MASK CBUS_REG_ADDR(RESET7_MASK)
+/*add from M8M2*/
+#define P_RESET0_LEVEL CBUS_REG_ADDR(RESET0_LEVEL)
+#define RESET1_LEVEL (RESET_BASE + 0x21)
+#define P_RESET1_LEVEL CBUS_REG_ADDR(RESET1_LEVEL)
+#define RESET2_LEVEL (RESET_BASE + 0x22)
+#define P_RESET2_LEVEL CBUS_REG_ADDR(RESET2_LEVEL)
+#define RESET3_LEVEL (RESET_BASE + 0x23)
+#define P_RESET3_LEVEL CBUS_REG_ADDR(RESET3_LEVEL)
+#define RESET4_LEVEL (RESET_BASE + 0x24)
+#define P_RESET4_LEVEL CBUS_REG_ADDR(RESET4_LEVEL)
+#define RESET5_LEVEL (RESET_BASE + 0x25)
+#define P_RESET5_LEVEL CBUS_REG_ADDR(RESET5_LEVEL)
+#define RESET6_LEVEL (RESET_BASE + 0x26)
+#define P_RESET6_LEVEL CBUS_REG_ADDR(RESET6_LEVEL)
+#define RESET7_LEVEL (RESET_BASE + 0x27)
+#define P_RESET7_LEVEL CBUS_REG_ADDR(RESET7_LEVEL)
+
+/*no set*/
+#ifdef MESON_M8_CPU
+#define HHI_CSI_PHY_CNTL0 (HHI_CSI_PHY_CNTL_BASE + 0xd3)
+#define P_HHI_CSI_PHY_CNTL0 CBUS_REG_ADDR(HHI_CSI_PHY_CNTL0)
+#define HHI_CSI_PHY_CNTL1 (HHI_CSI_PHY_CNTL_BASE + 0xd4)
+#define P_HHI_CSI_PHY_CNTL1 CBUS_REG_ADDR(HHI_CSI_PHY_CNTL1)
+#define HHI_CSI_PHY_CNTL2 (HHI_CSI_PHY_CNTL_BASE + 0xd5)
+#define P_HHI_CSI_PHY_CNTL2 CBUS_REG_ADDR(HHI_CSI_PHY_CNTL2)
+#define HHI_CSI_PHY_CNTL3 (HHI_CSI_PHY_CNTL_BASE + 0xd6)
+#define P_HHI_CSI_PHY_CNTL3 CBUS_REG_ADDR(HHI_CSI_PHY_CNTL3)
+#define HHI_CSI_PHY_CNTL4 (HHI_CSI_PHY_CNTL_BASE + 0xd7)
+#define P_HHI_CSI_PHY_CNTL4 CBUS_REG_ADDR(HHI_CSI_PHY_CNTL4)
+#endif
+
+#define PARSER_SUB_START_PTR (PARSER_SUB_START_PTR_BASE + 0x8a)
+#define P_PARSER_SUB_START_PTR CBUS_REG_ADDR(PARSER_SUB_START_PTR)
+#define PARSER_SUB_END_PTR (PARSER_SUB_START_PTR_BASE + 0x8b)
+#define P_PARSER_SUB_END_PTR CBUS_REG_ADDR(PARSER_SUB_END_PTR)
+#define PARSER_SUB_WP (PARSER_SUB_START_PTR_BASE + 0x8c)
+#define P_PARSER_SUB_WP CBUS_REG_ADDR(PARSER_SUB_WP)
+#define PARSER_SUB_RP (PARSER_SUB_START_PTR_BASE + 0x8d)
+#define P_PARSER_SUB_RP CBUS_REG_ADDR(PARSER_SUB_RP)
+#define PARSER_SUB_HOLE (PARSER_SUB_START_PTR_BASE + 0x8e)
+#define P_PARSER_SUB_HOLE CBUS_REG_ADDR(PARSER_SUB_HOLE)
+
+/*no set*/
+#define AO_RTI_GEN_PWR_SLEEP0 ((0x00 << 10) | (0x3a << 2))
+#define P_AO_RTI_GEN_PWR_SLEEP0 \
+ AOBUS_REG_ADDR(AO_RTI_GEN_PWR_SLEEP0)
+#define AO_RTI_GEN_PWR_ISO0 ((0x00 << 10) | (0x3b << 2))
+#define P_AO_RTI_GEN_PWR_ISO0 AOBUS_REG_ADDR(AO_RTI_GEN_PWR_ISO0)
+
+/**/
+#define STB_VERSION (STB_CBUS_BASE + 0x00)
+#define P_STB_VERSION CBUS_REG_ADDR(STB_VERSION)
+#define STB_VERSION_2 (STB_CBUS_BASE + 0x50)
+#define P_STB_VERSION_2 CBUS_REG_ADDR(STB_VERSION_2)
+#define STB_VERSION_3 (STB_CBUS_BASE + 0xa0)
+#define P_STB_VERSION_3 CBUS_REG_ADDR(STB_VERSION_3)
+#define STB_TEST_REG (STB_CBUS_BASE + 0x01)
+#define P_STB_TEST_REG CBUS_REG_ADDR(STB_TEST_REG)
+#define STB_TEST_REG_2 (STB_CBUS_BASE + 0x51)
+#define P_STB_TEST_REG_2 CBUS_REG_ADDR(STB_TEST_REG_2)
+#define STB_TEST_REG_3 (STB_CBUS_BASE + 0xa1)
+#define P_STB_TEST_REG_3 CBUS_REG_ADDR(STB_TEST_REG_3)
+
+#define FEC_INPUT_CONTROL (STB_CBUS_BASE + 0x2)
+#define P_FEC_INPUT_CONTROL CBUS_REG_ADDR(FEC_INPUT_CONTROL)
+#define FEC_INPUT_CONTROL_2 (STB_CBUS_BASE + 0x52)
+#define P_FEC_INPUT_CONTROL_2 CBUS_REG_ADDR(FEC_INPUT_CONTROL_2)
+#define FEC_INPUT_CONTROL_3 (STB_CBUS_BASE + 0xa2)
+#define P_FEC_INPUT_CONTROL_3 CBUS_REG_ADDR(FEC_INPUT_CONTROL_3)
+/*no used*/
+#define FEC_INPUT_DATA (STB_CBUS_BASE + 0x03)
+#define P_FEC_INPUT_DATA CBUS_REG_ADDR(FEC_INPUT_DATA)
+#define FEC_INPUT_DATA_2 (STB_CBUS_BASE + 0x53)
+#define P_FEC_INPUT_DATA_2 CBUS_REG_ADDR(FEC_INPUT_DATA_2)
+#define FEC_INPUT_DATA_3 (STB_CBUS_BASE + 0xa3)
+#define P_FEC_INPUT_DATA_3 CBUS_REG_ADDR(FEC_INPUT_DATA_3)
+/*no used end*/
+#define DEMUX_CONTROL (STB_CBUS_BASE + 0x04)
+#define P_DEMUX_CONTROL CBUS_REG_ADDR(DEMUX_CONTROL)
+#define DEMUX_CONTROL_2 (STB_CBUS_BASE + 0x54)
+#define P_DEMUX_CONTROL_2 CBUS_REG_ADDR(DEMUX_CONTROL_2)
+#define DEMUX_CONTROL_3 (STB_CBUS_BASE + 0xa4)
+#define P_DEMUX_CONTROL_3 CBUS_REG_ADDR(DEMUX_CONTROL_3)
+/*no used*/
+#define FEC_SYNC_BYTE (STB_CBUS_BASE + 0x05)
+#define P_FEC_SYNC_BYTE CBUS_REG_ADDR(FEC_SYNC_BYTE)
+#define FEC_SYNC_BYTE_2 (STB_CBUS_BASE + 0x55)
+#define P_FEC_SYNC_BYTE_2 CBUS_REG_ADDR(FEC_SYNC_BYTE_2)
+#define FEC_SYNC_BYTE_3 (STB_CBUS_BASE + 0xa5)
+#define P_FEC_SYNC_BYTE_3 CBUS_REG_ADDR(FEC_SYNC_BYTE_3)
+/*no used end*/
+
+#define FM_WR_DATA (STB_CBUS_BASE + 0x06)
+#define P_FM_WR_DATA CBUS_REG_ADDR(FM_WR_DATA)
+#define FM_WR_DATA_2 (STB_CBUS_BASE + 0x56)
+#define P_FM_WR_DATA_2 CBUS_REG_ADDR(FM_WR_DATA_2)
+#define FM_WR_DATA_3 (STB_CBUS_BASE + 0xa6)
+#define P_FM_WR_DATA_3 CBUS_REG_ADDR(FM_WR_DATA_3)
+#define FM_WR_ADDR (STB_CBUS_BASE + 0x07)
+#define P_FM_WR_ADDR CBUS_REG_ADDR(FM_WR_ADDR)
+#define FM_WR_ADDR_2 (STB_CBUS_BASE + 0x57)
+#define P_FM_WR_ADDR_2 CBUS_REG_ADDR(FM_WR_ADDR_2)
+#define FM_WR_ADDR_3 (STB_CBUS_BASE + 0xa7)
+#define P_FM_WR_ADDR_3 CBUS_REG_ADDR(FM_WR_ADDR_3)
+#define MAX_FM_COMP_ADDR (STB_CBUS_BASE + 0x08)
+#define P_MAX_FM_COMP_ADDR CBUS_REG_ADDR(MAX_FM_COMP_ADDR)
+#define MAX_FM_COMP_ADDR_2 (STB_CBUS_BASE + 0x58)
+#define P_MAX_FM_COMP_ADDR_2 CBUS_REG_ADDR(MAX_FM_COMP_ADDR_2)
+#define MAX_FM_COMP_ADDR_3 (STB_CBUS_BASE + 0xa8)
+#define P_MAX_FM_COMP_ADDR_3 CBUS_REG_ADDR(MAX_FM_COMP_ADDR_3)
+
+#define TS_HEAD_0 (STB_CBUS_BASE + 0x09)
+#define P_TS_HEAD_0 CBUS_REG_ADDR(TS_HEAD_0)
+#define TS_HEAD_0_2 (STB_CBUS_BASE + 0x59)
+#define P_TS_HEAD_0_2 CBUS_REG_ADDR(TS_HEAD_0_2)
+#define TS_HEAD_0_3 (STB_CBUS_BASE + 0xa9)
+#define P_TS_HEAD_0_3 CBUS_REG_ADDR(TS_HEAD_0_3)
+#define TS_HEAD_1 (STB_CBUS_BASE + 0x0a)
+#define P_TS_HEAD_1 CBUS_REG_ADDR(TS_HEAD_1)
+#define TS_HEAD_1_2 (STB_CBUS_BASE + 0x5a)
+#define P_TS_HEAD_1_2 CBUS_REG_ADDR(TS_HEAD_1_2)
+#define TS_HEAD_1_3 (STB_CBUS_BASE + 0xaa)
+#define P_TS_HEAD_1_3 CBUS_REG_ADDR(TS_HEAD_1_3)
+
+#define OM_CMD_STATUS (STB_CBUS_BASE + 0x0b)
+#define P_OM_CMD_STATUS CBUS_REG_ADDR(OM_CMD_STATUS)
+#define OM_CMD_STATUS_2 (STB_CBUS_BASE + 0x5b)
+#define P_OM_CMD_STATUS_2 CBUS_REG_ADDR(OM_CMD_STATUS_2)
+#define OM_CMD_STATUS_3 (STB_CBUS_BASE + 0xab)
+#define P_OM_CMD_STATUS_3 CBUS_REG_ADDR(OM_CMD_STATUS_3)
+
+#define OM_CMD_DATA (STB_CBUS_BASE + 0x0c)
+#define P_OM_CMD_DATA CBUS_REG_ADDR(OM_CMD_DATA)
+#define OM_CMD_DATA_2 (STB_CBUS_BASE + 0x5c)
+#define P_OM_CMD_DATA_2 CBUS_REG_ADDR(OM_CMD_DATA_2)
+#define OM_CMD_DATA_3 (STB_CBUS_BASE + 0xac)
+#define P_OM_CMD_DATA_3 CBUS_REG_ADDR(OM_CMD_DATA_3)
+#define OM_CMD_DATA2 (STB_CBUS_BASE + 0x0d)
+#define P_OM_CMD_DATA2 CBUS_REG_ADDR(OM_CMD_DATA2)
+#define OM_CMD_DATA2_2 (STB_CBUS_BASE + 0x5d)
+#define P_OM_CMD_DATA2_2 CBUS_REG_ADDR(OM_CMD_DATA2_2)
+#define OM_CMD_DATA2_3 (STB_CBUS_BASE + 0xad)
+#define P_OM_CMD_DATA2_3 CBUS_REG_ADDR(OM_CMD_DATA2_3)
+
+#define SEC_BUFF_01_START (STB_CBUS_BASE + 0x0e)
+#define P_SEC_BUFF_01_START CBUS_REG_ADDR(SEC_BUFF_01_START)
+#define SEC_BUFF_01_START_2 (STB_CBUS_BASE + 0x5e)
+#define P_SEC_BUFF_01_START_2 CBUS_REG_ADDR(SEC_BUFF_01_START_2)
+#define SEC_BUFF_01_START_3 (STB_CBUS_BASE + 0xae)
+#define P_SEC_BUFF_01_START_3 CBUS_REG_ADDR(SEC_BUFF_01_START_3)
+#define SEC_BUFF_23_START (STB_CBUS_BASE + 0x0f)
+#define P_SEC_BUFF_23_START CBUS_REG_ADDR(SEC_BUFF_23_START)
+#define SEC_BUFF_23_START_2 (STB_CBUS_BASE + 0x5f)
+#define P_SEC_BUFF_23_START_2 CBUS_REG_ADDR(SEC_BUFF_23_START_2)
+#define SEC_BUFF_23_START_3 (STB_CBUS_BASE + 0xaf)
+#define P_SEC_BUFF_23_START_3 CBUS_REG_ADDR(SEC_BUFF_23_START_3)
+#define SEC_BUFF_SIZE (STB_CBUS_BASE + 0x10)
+#define P_SEC_BUFF_SIZE CBUS_REG_ADDR(SEC_BUFF_SIZE)
+#define SEC_BUFF_SIZE_2 (STB_CBUS_BASE + 0x60)
+#define P_SEC_BUFF_SIZE_2 CBUS_REG_ADDR(SEC_BUFF_SIZE_2)
+#define SEC_BUFF_SIZE_3 (STB_CBUS_BASE + 0xb0)
+#define P_SEC_BUFF_SIZE_3 CBUS_REG_ADDR(SEC_BUFF_SIZE_3)
+#define SEC_BUFF_BUSY (STB_CBUS_BASE + 0x11)
+#define P_SEC_BUFF_BUSY CBUS_REG_ADDR(SEC_BUFF_BUSY)
+#define SEC_BUFF_BUSY_2 (STB_CBUS_BASE + 0x61)
+#define P_SEC_BUFF_BUSY_2 CBUS_REG_ADDR(SEC_BUFF_BUSY_2)
+#define SEC_BUFF_BUSY_3 (STB_CBUS_BASE + 0xb1)
+#define P_SEC_BUFF_BUSY_3 CBUS_REG_ADDR(SEC_BUFF_BUSY_3)
+#define SEC_BUFF_READY (STB_CBUS_BASE + 0x12)
+#define P_SEC_BUFF_READY CBUS_REG_ADDR(SEC_BUFF_READY)
+#define SEC_BUFF_READY_2 (STB_CBUS_BASE + 0x62)
+#define P_SEC_BUFF_READY_2 CBUS_REG_ADDR(SEC_BUFF_READY_2)
+#define SEC_BUFF_READY_3 (STB_CBUS_BASE + 0xb2)
+#define P_SEC_BUFF_READY_3 CBUS_REG_ADDR(SEC_BUFF_READY_3)
+#define SEC_BUFF_NUMBER (STB_CBUS_BASE + 0x13)
+#define P_SEC_BUFF_NUMBER CBUS_REG_ADDR(SEC_BUFF_NUMBER)
+#define SEC_BUFF_NUMBER_2 (STB_CBUS_BASE + 0x63)
+#define P_SEC_BUFF_NUMBER_2 CBUS_REG_ADDR(SEC_BUFF_NUMBER_2)
+#define SEC_BUFF_NUMBER_3 (STB_CBUS_BASE + 0xb3)
+#define P_SEC_BUFF_NUMBER_3 CBUS_REG_ADDR(SEC_BUFF_NUMBER_3)
+
+
+/**no used*/
+#define ASSIGN_PID_NUMBER (STB_CBUS_BASE + 0x14)
+#define P_ASSIGN_PID_NUMBER CBUS_REG_ADDR(ASSIGN_PID_NUMBER)
+#define ASSIGN_PID_NUMBER_2 (STB_CBUS_BASE + 0x64)
+#define P_ASSIGN_PID_NUMBER_2 CBUS_REG_ADDR(ASSIGN_PID_NUMBER_2)
+#define ASSIGN_PID_NUMBER_3 (STB_CBUS_BASE + 0xb4)
+#define P_ASSIGN_PID_NUMBER_3 CBUS_REG_ADDR(ASSIGN_PID_NUMBER_3)
+#define VIDEO_STREAM_ID (STB_CBUS_BASE + 0x15)
+#define P_VIDEO_STREAM_ID CBUS_REG_ADDR(VIDEO_STREAM_ID)
+#define VIDEO_STREAM_ID_2 (STB_CBUS_BASE + 0x65)
+#define P_VIDEO_STREAM_ID_2 CBUS_REG_ADDR(VIDEO_STREAM_ID_2)
+#define VIDEO_STREAM_ID_3 (STB_CBUS_BASE + 0xb5)
+#define P_VIDEO_STREAM_ID_3 CBUS_REG_ADDR(VIDEO_STREAM_ID_3)
+#define AUDIO_STREAM_ID (STB_CBUS_BASE + 0x16)
+#define P_AUDIO_STREAM_ID CBUS_REG_ADDR(AUDIO_STREAM_ID)
+#define AUDIO_STREAM_ID_2 (STB_CBUS_BASE + 0x66)
+#define P_AUDIO_STREAM_ID_2 CBUS_REG_ADDR(AUDIO_STREAM_ID_2)
+#define AUDIO_STREAM_ID_3 (STB_CBUS_BASE + 0xb6)
+#define P_AUDIO_STREAM_ID_3 CBUS_REG_ADDR(AUDIO_STREAM_ID_3)
+#define SUB_STREAM_ID (STB_CBUS_BASE + 0x17)
+#define P_SUB_STREAM_ID CBUS_REG_ADDR(SUB_STREAM_ID)
+#define SUB_STREAM_ID_2 (STB_CBUS_BASE + 0x67)
+#define P_SUB_STREAM_ID_2 CBUS_REG_ADDR(SUB_STREAM_ID_2)
+#define SUB_STREAM_ID_3 (STB_CBUS_BASE + 0xb7)
+#define P_SUB_STREAM_ID_3 CBUS_REG_ADDR(SUB_STREAM_ID_3)
+#define OTHER_STREAM_ID (STB_CBUS_BASE + 0x18)
+#define P_OTHER_STREAM_ID CBUS_REG_ADDR(OTHER_STREAM_ID)
+#define OTHER_STREAM_ID_2 (STB_CBUS_BASE + 0x68)
+#define P_OTHER_STREAM_ID_2 CBUS_REG_ADDR(OTHER_STREAM_ID_2)
+#define OTHER_STREAM_ID_3 (STB_CBUS_BASE + 0xb8)
+#define P_OTHER_STREAM_ID_3 CBUS_REG_ADDR(OTHER_STREAM_ID_3)
+#define PCR90K_CTL (STB_CBUS_BASE + 0x19)
+#define P_PCR90K_CTL CBUS_REG_ADDR(PCR90K_CTL)
+#define PCR90K_CTL_2 (STB_CBUS_BASE + 0x69)
+#define P_PCR90K_CTL_2 CBUS_REG_ADDR(PCR90K_CTL_2)
+#define PCR90K_CTL_3 (STB_CBUS_BASE + 0xb9)
+#define P_PCR90K_CTL_3 CBUS_REG_ADDR(PCR90K_CTL_3)
+/*no used end*/
+#define PCR_DEMUX (STB_CBUS_BASE + 0x1a)
+#define P_PCR_DEMUX CBUS_REG_ADDR(PCR_DEMUX)
+#define PCR_DEMUX_2 (STB_CBUS_BASE + 0x6a)
+#define P_PCR_DEMUX_2 CBUS_REG_ADDR(PCR_DEMUX_2)
+#define PCR_DEMUX_3 (STB_CBUS_BASE + 0xba)
+#define P_PCR_DEMUX_3 CBUS_REG_ADDR(PCR_DEMUX_3)
+
+#define VIDEO_PTS_DEMUX (STB_CBUS_BASE + 0x1b)
+#define P_VIDEO_PTS_DEMUX CBUS_REG_ADDR(VIDEO_PTS_DEMUX)
+#define VIDEO_PTS_DEMUX_2 (STB_CBUS_BASE + 0x6b)
+#define P_VIDEO_PTS_DEMUX_2 CBUS_REG_ADDR(VIDEO_PTS_DEMUX_2)
+#define VIDEO_PTS_DEMUX_3 (STB_CBUS_BASE + 0xbb)
+#define P_VIDEO_PTS_DEMUX_3 CBUS_REG_ADDR(VIDEO_PTS_DEMUX_3)
+/*no used*/
+#define VIDEO_DTS_DEMUX (STB_CBUS_BASE + 0x1c)
+#define P_VIDEO_DTS_DEMUX CBUS_REG_ADDR(VIDEO_DTS_DEMUX)
+#define VIDEO_DTS_DEMUX_2 (STB_CBUS_BASE + 0x6c)
+#define P_VIDEO_DTS_DEMUX_2 CBUS_REG_ADDR(VIDEO_DTS_DEMUX_2)
+#define VIDEO_DTS_DEMUX_3 (STB_CBUS_BASE + 0xbc)
+#define P_VIDEO_DTS_DEMUX_3 CBUS_REG_ADDR(VIDEO_DTS_DEMUX_3)
+/*no used end*/
+#define AUDIO_PTS_DEMUX (STB_CBUS_BASE + 0x1d)
+#define P_AUDIO_PTS_DEMUX CBUS_REG_ADDR(AUDIO_PTS_DEMUX)
+#define AUDIO_PTS_DEMUX_2 (STB_CBUS_BASE + 0x6d)
+#define P_AUDIO_PTS_DEMUX_2 CBUS_REG_ADDR(AUDIO_PTS_DEMUX_2)
+#define AUDIO_PTS_DEMUX_3 (STB_CBUS_BASE + 0xbd)
+#define P_AUDIO_PTS_DEMUX_3 CBUS_REG_ADDR(AUDIO_PTS_DEMUX_3)
+/*no used */
+#define SUB_PTS_DEMUX (STB_CBUS_BASE + 0x1e)
+#define P_SUB_PTS_DEMUX CBUS_REG_ADDR(SUB_PTS_DEMUX)
+#define SUB_PTS_DEMUX_2 (STB_CBUS_BASE + 0x6e)
+#define P_SUB_PTS_DEMUX_2 CBUS_REG_ADDR(SUB_PTS_DEMUX_2)
+#define SUB_PTS_DEMUX_3 (STB_CBUS_BASE + 0xbe)
+#define P_SUB_PTS_DEMUX_3 CBUS_REG_ADDR(SUB_PTS_DEMUX_3)
+/*no used end*/
+#define STB_PTS_DTS_STATUS (STB_CBUS_BASE + 0x1f)
+#define P_STB_PTS_DTS_STATUS CBUS_REG_ADDR(STB_PTS_DTS_STATUS)
+#define STB_PTS_DTS_STATUS_2 (STB_CBUS_BASE + 0x6f)
+#define P_STB_PTS_DTS_STATUS_2 CBUS_REG_ADDR(STB_PTS_DTS_STATUS_2)
+#define STB_PTS_DTS_STATUS_3 (STB_CBUS_BASE + 0xbf)
+#define P_STB_PTS_DTS_STATUS_3 CBUS_REG_ADDR(STB_PTS_DTS_STATUS_3)
+
+/*no use*/
+#define STB_DEBUG_INDEX (STB_CBUS_BASE + 0x20)
+#define P_STB_DEBUG_INDEX CBUS_REG_ADDR(STB_DEBUG_INDEX)
+#define STB_DEBUG_INDEX_2 (STB_CBUS_BASE + 0x70)
+#define P_STB_DEBUG_INDEX_2 CBUS_REG_ADDR(STB_DEBUG_INDEX_2)
+#define STB_DEBUG_INDEX_3 (STB_CBUS_BASE + 0xc0)
+#define P_STB_DEBUG_INDEX_3 CBUS_REG_ADDR(STB_DEBUG_INDEX_3)
+#define STB_DEBUG_DATAUT_O (STB_CBUS_BASE + 0x21)
+#define P_STB_DEBUG_DATAUT_O CBUS_REG_ADDR(STB_DEBUG_DATAUT_O)
+#define STB_DEBUG_DATAUT_O_2 (STB_CBUS_BASE + 0x71)
+#define P_STB_DEBUG_DATAUT_O_2 CBUS_REG_ADDR(STB_DEBUG_DATAUT_O_2)
+#define STB_DEBUG_DATAUT_O_3 (STB_CBUS_BASE + 0xc1)
+#define P_STB_DEBUG_DATAUT_O_3 CBUS_REG_ADDR(STB_DEBUG_DATAUT_O_3)
+/*no use end*/
+
+#define STBM_CTL_O (STB_CBUS_BASE + 0x22)
+#define P_STBM_CTL_O CBUS_REG_ADDR(STBM_CTL_O)
+#define STBM_CTL_O_2 (STB_CBUS_BASE + 0x72)
+#define P_STBM_CTL_O_2 CBUS_REG_ADDR(STBM_CTL_O_2)
+#define STBM_CTL_O_3 (STB_CBUS_BASE + 0xc2)
+#define P_STBM_CTL_O_3 CBUS_REG_ADDR(STBM_CTL_O_3)
+#define STB_INT_STATUS (STB_CBUS_BASE + 0x23)
+#define P_STB_INT_STATUS CBUS_REG_ADDR(STB_INT_STATUS)
+#define STB_INT_STATUS_2 (STB_CBUS_BASE + 0x73)
+#define P_STB_INT_STATUS_2 CBUS_REG_ADDR(STB_INT_STATUS_2)
+#define STB_INT_STATUS_3 (STB_CBUS_BASE + 0xc3)
+#define P_STB_INT_STATUS_3 CBUS_REG_ADDR(STB_INT_STATUS_3)
+#define DEMUX_ENDIAN (STB_CBUS_BASE + 0x24)
+#define P_DEMUX_ENDIAN CBUS_REG_ADDR(DEMUX_ENDIAN)
+#define DEMUX_ENDIAN_2 (STB_CBUS_BASE + 0x74)
+#define P_DEMUX_ENDIAN_2 CBUS_REG_ADDR(DEMUX_ENDIAN_2)
+#define DEMUX_ENDIAN_3 (STB_CBUS_BASE + 0xc4)
+#define P_DEMUX_ENDIAN_3 CBUS_REG_ADDR(DEMUX_ENDIAN_3)
+#define TS_HIU_CTL (STB_CBUS_BASE + 0x25)
+#define P_TS_HIU_CTL CBUS_REG_ADDR(TS_HIU_CTL)
+#define TS_HIU_CTL_2 (STB_CBUS_BASE + 0x75)
+#define P_TS_HIU_CTL_2 CBUS_REG_ADDR(TS_HIU_CTL_2)
+#define TS_HIU_CTL_3 (STB_CBUS_BASE + 0xc5)
+#define P_TS_HIU_CTL_3 CBUS_REG_ADDR(TS_HIU_CTL_3)
+
+#define SEC_BUFF_BASE (STB_CBUS_BASE + 0x26)
+#define P_SEC_BUFF_BASE CBUS_REG_ADDR(SEC_BUFF_BASE)
+#define SEC_BUFF_BASE_2 (STB_CBUS_BASE + 0x76)
+#define P_SEC_BUFF_BASE_2 CBUS_REG_ADDR(SEC_BUFF_BASE_2)
+#define SEC_BUFF_BASE_3 (STB_CBUS_BASE + 0xc6)
+#define P_SEC_BUFF_BASE_3 CBUS_REG_ADDR(SEC_BUFF_BASE_3)
+#define DEMUX_MEM_REQ_EN (STB_CBUS_BASE + 0x27)
+#define P_DEMUX_MEM_REQ_EN CBUS_REG_ADDR(DEMUX_MEM_REQ_EN)
+#define DEMUX_MEM_REQ_EN_2 (STB_CBUS_BASE + 0x77)
+#define P_DEMUX_MEM_REQ_EN_2 CBUS_REG_ADDR(DEMUX_MEM_REQ_EN_2)
+#define DEMUX_MEM_REQ_EN_3 (STB_CBUS_BASE + 0xc7)
+#define P_DEMUX_MEM_REQ_EN_3 CBUS_REG_ADDR(DEMUX_MEM_REQ_EN_3)
+
+
+/*no use*/
+#define VIDEO_PDTS_WR_PTR (STB_CBUS_BASE + 0x28)
+#define P_VIDEO_PDTS_WR_PTR CBUS_REG_ADDR(VIDEO_PDTS_WR_PTR)
+#define VIDEO_PDTS_WR_PTR_2 (STB_CBUS_BASE + 0x78)
+#define P_VIDEO_PDTS_WR_PTR_2 CBUS_REG_ADDR(VIDEO_PDTS_WR_PTR_2)
+#define VIDEO_PDTS_WR_PTR_3 (STB_CBUS_BASE + 0xc8)
+#define P_VIDEO_PDTS_WR_PTR_3 CBUS_REG_ADDR(VIDEO_PDTS_WR_PTR_3)
+#define AUDIO_PDTS_WR_PTR (STB_CBUS_BASE + 0x29)
+#define P_AUDIO_PDTS_WR_PTR CBUS_REG_ADDR(AUDIO_PDTS_WR_PTR)
+#define AUDIO_PDTS_WR_PTR_2 (STB_CBUS_BASE + 0x79)
+#define P_AUDIO_PDTS_WR_PTR_2 CBUS_REG_ADDR(AUDIO_PDTS_WR_PTR_2)
+#define AUDIO_PDTS_WR_PTR_3 (STB_CBUS_BASE + 0xc9)
+#define P_AUDIO_PDTS_WR_PTR_3 CBUS_REG_ADDR(AUDIO_PDTS_WR_PTR_3)
+#define SUB_WR_PTR (STB_CBUS_BASE + 0x2a)
+#define P_SUB_WR_PTR CBUS_REG_ADDR(SUB_WR_PTR)
+#define SUB_WR_PTR_2 (STB_CBUS_BASE + 0x7a)
+#define P_SUB_WR_PTR_2 CBUS_REG_ADDR(SUB_WR_PTR_2)
+#define SUB_WR_PTR_3 (STB_CBUS_BASE + 0xca)
+#define P_SUB_WR_PTR_3 CBUS_REG_ADDR(SUB_WR_PTR_3)
+/*no use*/
+
+#define SB_START (STB_CBUS_BASE + 0x2b)
+#define P_SB_START CBUS_REG_ADDR(SB_START)
+#define SB_START_2 (STB_CBUS_BASE + 0x7b)
+#define P_SB_START_2 CBUS_REG_ADDR(SB_START_2)
+#define SB_START_3 (STB_CBUS_BASE + 0xcb)
+#define P_SB_START_3 CBUS_REG_ADDR(SB_START_3)
+#define SB_LAST_ADDR (STB_CBUS_BASE + 0x2c)
+#define P_SB_LAST_ADDR CBUS_REG_ADDR(SB_LAST_ADDR)
+#define SB_LAST_ADDR_2 (STB_CBUS_BASE + 0x7c)
+#define P_SB_LAST_ADDR_2 CBUS_REG_ADDR(SB_LAST_ADDR_2)
+#define SB_LAST_ADDR_3 (STB_CBUS_BASE + 0xcc)
+#define P_SB_LAST_ADDR_3 CBUS_REG_ADDR(SB_LAST_ADDR_3)
+#define SB_PES_WR_PTR (STB_CBUS_BASE + 0x2d)
+#define P_SB_PES_WR_PTR CBUS_REG_ADDR(SB_PES_WR_PTR)
+#define SB_PES_WR_PTR_2 (STB_CBUS_BASE + 0x7d)
+#define P_SB_PES_WR_PTR_2 CBUS_REG_ADDR(SB_PES_WR_PTR_2)
+#define SB_PES_WR_PTR_3 (STB_CBUS_BASE + 0xcd)
+#define P_SB_PES_WR_PTR_3 CBUS_REG_ADDR(SB_PES_WR_PTR_3)
+#define OTHER_WR_PTR (STB_CBUS_BASE + 0x2e)
+#define P_OTHER_WR_PTR CBUS_REG_ADDR(OTHER_WR_PTR)
+#define OTHER_WR_PTR_2 (STB_CBUS_BASE + 0x7e)
+#define P_OTHER_WR_PTR_2 CBUS_REG_ADDR(OTHER_WR_PTR_2)
+#define OTHER_WR_PTR_3 (STB_CBUS_BASE + 0xce)
+#define P_OTHER_WR_PTR_3 CBUS_REG_ADDR(OTHER_WR_PTR_3)
+
+#define OB_START (STB_CBUS_BASE + 0x2f)
+#define P_OB_START CBUS_REG_ADDR(OB_START)
+#define OB_START_2 (STB_CBUS_BASE + 0x7f)
+#define P_OB_START_2 CBUS_REG_ADDR(OB_START_2)
+#define OB_START_3 (STB_CBUS_BASE + 0xcf)
+#define P_OB_START_3 CBUS_REG_ADDR(OB_START_3)
+#define OB_LAST_ADDR (STB_CBUS_BASE + 0x30)
+#define P_OB_LAST_ADDR CBUS_REG_ADDR(OB_LAST_ADDR)
+#define OB_LAST_ADDR_2 (STB_CBUS_BASE + 0x80)
+#define P_OB_LAST_ADDR_2 CBUS_REG_ADDR(OB_LAST_ADDR_2)
+#define OB_LAST_ADDR_3 (STB_CBUS_BASE + 0xd0)
+#define P_OB_LAST_ADDR_3 CBUS_REG_ADDR(OB_LAST_ADDR_3)
+#define OB_PES_WR_PTR (STB_CBUS_BASE + 0x31)
+#define P_OB_PES_WR_PTR CBUS_REG_ADDR(OB_PES_WR_PTR)
+#define OB_PES_WR_PTR_2 (STB_CBUS_BASE + 0x81)
+#define P_OB_PES_WR_PTR_2 CBUS_REG_ADDR(OB_PES_WR_PTR_2)
+#define OB_PES_WR_PTR_3 (STB_CBUS_BASE + 0xd1)
+#define P_OB_PES_WR_PTR_3 CBUS_REG_ADDR(OB_PES_WR_PTR_3)
+#define STB_INT_MASK (STB_CBUS_BASE + 0x32)
+#define P_STB_INT_MASK CBUS_REG_ADDR(STB_INT_MASK)
+#define STB_INT_MASK_2 (STB_CBUS_BASE + 0x82)
+#define P_STB_INT_MASK_2 CBUS_REG_ADDR(STB_INT_MASK_2)
+#define STB_INT_MASK_3 (STB_CBUS_BASE + 0xd2)
+#define P_STB_INT_MASK_3 CBUS_REG_ADDR(STB_INT_MASK_3)
+/*no used */
+#define VIDEO_SPLICING_CTL (STB_CBUS_BASE + 0x33)
+#define P_VIDEO_SPLICING_CTL CBUS_REG_ADDR(VIDEO_SPLICING_CTL)
+#define VIDEO_SPLICING_CTL_2 (STB_CBUS_BASE + 0x83)
+#define P_VIDEO_SPLICING_CTL_2 CBUS_REG_ADDR(VIDEO_SPLICING_CTL_2)
+#define VIDEO_SPLICING_CTL_3 (STB_CBUS_BASE + 0xd3)
+#define P_VIDEO_SPLICING_CTL_3 CBUS_REG_ADDR(VIDEO_SPLICING_CTL_3)
+#define AUDIO_SPLICING_CTL (STB_CBUS_BASE + 0x34)
+#define P_AUDIO_SPLICING_CTL CBUS_REG_ADDR(AUDIO_SPLICING_CTL)
+#define AUDIO_SPLICING_CTL_2 (STB_CBUS_BASE + 0x84)
+#define P_AUDIO_SPLICING_CTL_2 CBUS_REG_ADDR(AUDIO_SPLICING_CTL_2)
+#define AUDIO_SPLICING_CTL_3 (STB_CBUS_BASE + 0xd4)
+#define P_AUDIO_SPLICING_CTL_3 CBUS_REG_ADDR(AUDIO_SPLICING_CTL_3)
+#define TS_PACKAGE_BYTE_COUNT (STB_CBUS_BASE + 0x35)
+#define P_TS_PACKAGE_BYTE_COUNT \
+ CBUS_REG_ADDR(TS_PACKAGE_BYTE_COUNT)
+#define TS_PACKAGE_BYTE_COUNT_2 (STB_CBUS_BASE + 0x85)
+#define P_TS_PACKAGE_BYTE_COUNT_2 \
+ CBUS_REG_ADDR(TS_PACKAGE_BYTE_COUNT_2)
+#define TS_PACKAGE_BYTE_COUNT_3 (STB_CBUS_BASE + 0xd5)
+#define P_TS_PACKAGE_BYTE_COUNT_3 \
+ CBUS_REG_ADDR(TS_PACKAGE_BYTE_COUNT_3)
+/*no used end*/
+
+#define PES_STRONG_SYNC (STB_CBUS_BASE + 0x36)
+#define P_PES_STRONG_SYNC CBUS_REG_ADDR(PES_STRONG_SYNC)
+#define PES_STRONG_SYNC_2 (STB_CBUS_BASE + 0x86)
+#define P_PES_STRONG_SYNC_2 CBUS_REG_ADDR(PES_STRONG_SYNC_2)
+#define PES_STRONG_SYNC_3 (STB_CBUS_BASE + 0xd6)
+#define P_PES_STRONG_SYNC_3 CBUS_REG_ADDR(PES_STRONG_SYNC_3)
+
+#define OM_DATA_RD_ADDR (STB_CBUS_BASE + 0x37)
+#define P_OM_DATA_RD_ADDR CBUS_REG_ADDR(OM_DATA_RD_ADDR)
+#define OM_DATA_RD_ADDR_2 (STB_CBUS_BASE + 0x87)
+#define P_OM_DATA_RD_ADDR_2 CBUS_REG_ADDR(OM_DATA_RD_ADDR_2)
+#define OM_DATA_RD_ADDR_3 (STB_CBUS_BASE + 0xd7)
+#define P_OM_DATA_RD_ADDR_3 CBUS_REG_ADDR(OM_DATA_RD_ADDR_3)
+#define OM_DATA_RD (STB_CBUS_BASE + 0x38)
+#define P_OM_DATA_RD CBUS_REG_ADDR(OM_DATA_RD)
+#define OM_DATA_RD_2 (STB_CBUS_BASE + 0x88)
+#define P_OM_DATA_RD_2 CBUS_REG_ADDR(OM_DATA_RD_2)
+#define OM_DATA_RD_3 (STB_CBUS_BASE + 0xd8)
+#define P_OM_DATA_RD_3 CBUS_REG_ADDR(OM_DATA_RD_3)
+
+/*no used*/
+
+#define SECTION_AUTO_STOP_3 (STB_CBUS_BASE + 0x39)
+#define P_SECTION_AUTO_STOP_3 CBUS_REG_ADDR(SECTION_AUTO_STOP_3)
+#define SECTION_AUTO_STOP_3_2 (STB_CBUS_BASE + 0x89)
+#define P_SECTION_AUTO_STOP_3_2 \
+ CBUS_REG_ADDR(SECTION_AUTO_STOP_3_2)
+#define SECTION_AUTO_STOP_3_3 (STB_CBUS_BASE + 0xd9)
+#define P_SECTION_AUTO_STOP_3_3 \
+ CBUS_REG_ADDR(SECTION_AUTO_STOP_3_3)
+#define SECTION_AUTO_STOP_2 (STB_CBUS_BASE + 0x3a)
+#define P_SECTION_AUTO_STOP_2 \
+ CBUS_REG_ADDR(SECTION_AUTO_STOP_2)
+#define SECTION_AUTO_STOP_2_2 (STB_CBUS_BASE + 0x8a)
+#define P_SECTION_AUTO_STOP_2_2 \
+ CBUS_REG_ADDR(SECTION_AUTO_STOP_2_2)
+#define SECTION_AUTO_STOP_2_3 (STB_CBUS_BASE + 0xda)
+#define P_SECTION_AUTO_STOP_2_3 \
+ CBUS_REG_ADDR(SECTION_AUTO_STOP_2_3)
+#define SECTION_AUTO_STOP_1 (STB_CBUS_BASE + 0x3b)
+#define P_SECTION_AUTO_STOP_1 CBUS_REG_ADDR(SECTION_AUTO_STOP_1)
+#define SECTION_AUTO_STOP_1_2 (STB_CBUS_BASE + 0x8b)
+#define P_SECTION_AUTO_STOP_1_2 \
+ CBUS_REG_ADDR(SECTION_AUTO_STOP_1_2)
+#define SECTION_AUTO_STOP_1_3 (STB_CBUS_BASE + 0xdb)
+#define P_SECTION_AUTO_STOP_1_3 \
+ CBUS_REG_ADDR(SECTION_AUTO_STOP_1_3)
+#define SECTION_AUTO_STOP_0 (STB_CBUS_BASE + 0x3c)
+#define P_SECTION_AUTO_STOP_0 \
+ CBUS_REG_ADDR(SECTION_AUTO_STOP_0)
+#define SECTION_AUTO_STOP_0_2 (STB_CBUS_BASE + 0x8c)
+#define P_SECTION_AUTO_STOP_0_2 \
+ CBUS_REG_ADDR(SECTION_AUTO_STOP_0_2)
+#define SECTION_AUTO_STOP_0_3 (STB_CBUS_BASE + 0xdc)
+#define P_SECTION_AUTO_STOP_0_3 \
+ CBUS_REG_ADDR(SECTION_AUTO_STOP_0_3)
+
+#define DEMUX_CHANNEL_RESET (STB_CBUS_BASE + 0x3d)
+#define P_DEMUX_CHANNEL_RESET \
+ CBUS_REG_ADDR(DEMUX_CHANNEL_RESET)
+#define DEMUX_CHANNEL_RESET_2 (STB_CBUS_BASE + 0x8d)
+#define P_DEMUX_CHANNEL_RESET_2 \
+ CBUS_REG_ADDR(DEMUX_CHANNEL_RESET_2)
+#define DEMUX_CHANNEL_RESET_3 (STB_CBUS_BASE + 0xdd)
+#define P_DEMUX_CHANNEL_RESET_3 \
+ CBUS_REG_ADDR(DEMUX_CHANNEL_RESET_3)
+/*no use end*/
+#define DEMUX_SCRAMBLING_STATE (STB_CBUS_BASE + 0x3e)
+#define DEMUX_SCRAMBLING_STATE_2 (STB_CBUS_BASE + 0x8e)
+#define P_DEMUX_SCRAMBLING_STATE_2 \
+ CBUS_REG_ADDR(DEMUX_SCRAMBLING_STATE_2)
+#define DEMUX_SCRAMBLING_STATE_3 (STB_CBUS_BASE + 0xde)
+#define P_DEMUX_SCRAMBLING_STATE_3 \
+ CBUS_REG_ADDR(DEMUX_SCRAMBLING_STATE_3)
+#define DEMUX_CHANNEL_ACTIVITY (STB_CBUS_BASE + 0x3f)
+#define P_DEMUX_CHANNEL_ACTIVITY \
+ CBUS_REG_ADDR(DEMUX_CHANNEL_ACTIVITY)
+#define DEMUX_CHANNEL_ACTIVITY_2 (STB_CBUS_BASE + 0x8f)
+#define P_DEMUX_CHANNEL_ACTIVITY_2 \
+ CBUS_REG_ADDR(DEMUX_CHANNEL_ACTIVITY_2)
+#define DEMUX_CHANNEL_ACTIVITY_3 (STB_CBUS_BASE + 0xdf)
+#define P_DEMUX_CHANNEL_ACTIVITY_3 \
+ CBUS_REG_ADDR(DEMUX_CHANNEL_ACTIVITY_3)
+
+/*no use*/
+
+#define DEMUX_STAMP_CTL (STB_CBUS_BASE + 0x40)
+#define P_DEMUX_STAMP_CTL CBUS_REG_ADDR(DEMUX_STAMP_CTL)
+#define DEMUX_STAMP_CTL_2 (STB_CBUS_BASE + 0x90)
+#define P_DEMUX_STAMP_CTL_2 \
+ CBUS_REG_ADDR(DEMUX_STAMP_CTL_2)
+#define DEMUX_STAMP_CTL_3 (STB_CBUS_BASE + 0xe0)
+#define P_DEMUX_STAMP_CTL_3 \
+ CBUS_REG_ADDR(DEMUX_STAMP_CTL_3)
+#define DEMUX_VIDEO_STAMP_SYNC_0 (STB_CBUS_BASE + 0x41)
+#define P_DEMUX_VIDEO_STAMP_SYNC_0 \
+ CBUS_REG_ADDR(DEMUX_VIDEO_STAMP_SYNC_0)
+#define DEMUX_VIDEO_STAMP_SYNC_0_2 (STB_CBUS_BASE + 0x91)
+#define P_DEMUX_VIDEO_STAMP_SYNC_0_2 \
+ CBUS_REG_ADDR(DEMUX_VIDEO_STAMP_SYNC_0_2)
+#define DEMUX_VIDEO_STAMP_SYNC_0_3 (STB_CBUS_BASE + 0xe1)
+#define P_DEMUX_VIDEO_STAMP_SYNC_0_3 \
+ CBUS_REG_ADDR(DEMUX_VIDEO_STAMP_SYNC_0_3)
+#define DEMUX_VIDEO_STAMP_SYNC_1 (STB_CBUS_BASE + 0x42)
+#define P_DEMUX_VIDEO_STAMP_SYNC_1 \
+ CBUS_REG_ADDR(DEMUX_VIDEO_STAMP_SYNC_1)
+#define DEMUX_VIDEO_STAMP_SYNC_1_2 (STB_CBUS_BASE + 0x92)
+#define P_DEMUX_VIDEO_STAMP_SYNC_1_2 \
+ CBUS_REG_ADDR(DEMUX_VIDEO_STAMP_SYNC_1_2)
+#define DEMUX_VIDEO_STAMP_SYNC_1_3 (STB_CBUS_BASE + 0xe2)
+#define P_DEMUX_VIDEO_STAMP_SYNC_1_3 \
+ CBUS_REG_ADDR(DEMUX_VIDEO_STAMP_SYNC_1_3)
+#define DEMUX_AUDIO_STAMP_SYNC_0 (STB_CBUS_BASE + 0x43)
+#define P_DEMUX_AUDIO_STAMP_SYNC_0 \
+ CBUS_REG_ADDR(DEMUX_AUDIO_STAMP_SYNC_0)
+#define DEMUX_AUDIO_STAMP_SYNC_0_2 (STB_CBUS_BASE + 0x93)
+#define P_DEMUX_AUDIO_STAMP_SYNC_0_2 \
+ CBUS_REG_ADDR(DEMUX_AUDIO_STAMP_SYNC_0_2)
+#define DEMUX_AUDIO_STAMP_SYNC_0_3 (STB_CBUS_BASE + 0xe3)
+#define P_DEMUX_AUDIO_STAMP_SYNC_0_3 \
+ CBUS_REG_ADDR(DEMUX_AUDIO_STAMP_SYNC_0_3)
+#define DEMUX_AUDIO_STAMP_SYNC_1 (STB_CBUS_BASE + 0x44)
+#define P_DEMUX_AUDIO_STAMP_SYNC_1 \
+ CBUS_REG_ADDR(DEMUX_AUDIO_STAMP_SYNC_1)
+#define DEMUX_AUDIO_STAMP_SYNC_1_2 (STB_CBUS_BASE + 0x94)
+#define P_DEMUX_AUDIO_STAMP_SYNC_1_2 \
+ CBUS_REG_ADDR(DEMUX_AUDIO_STAMP_SYNC_1_2)
+#define DEMUX_AUDIO_STAMP_SYNC_1_3 (STB_CBUS_BASE + 0xe4)
+#define P_DEMUX_AUDIO_STAMP_SYNC_1_3 \
+ CBUS_REG_ADDR(DEMUX_AUDIO_STAMP_SYNC_1_3)
+#define DEMUX_SECTION_RESET (STB_CBUS_BASE + 0x45)
+#define P_DEMUX_SECTION_RESET CBUS_REG_ADDR(DEMUX_SECTION_RESET)
+#define DEMUX_SECTION_RESET_2 (STB_CBUS_BASE + 0x95)
+#define P_DEMUX_SECTION_RESET_2 \
+ CBUS_REG_ADDR(DEMUX_SECTION_RESET_2)
+#define DEMUX_SECTION_RESET_3 (STB_CBUS_BASE + 0xe5)
+#define P_DEMUX_SECTION_RESET_3 \
+ CBUS_REG_ADDR(DEMUX_SECTION_RESET_3)
+/*no use end*/
+
+/*from c_stb_define.h*/
+#define COMM_DESC_2_CTL (STB_CBUS_BASE + 0xff) /*0x16ff*/
+
+#define STB_OM_CTL \
+ (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x22) /* 0x1622*/
+#define STB_OM_CTL_2 \
+ (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x22) /* 0x1672*/
+#define STB_OM_CTL_3 \
+ (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x22) /* 0x16c2*/
+
+#define DEMUX_INPUT_TIMEOUT_C \
+ (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x46) /* 0x1646*/
+#define DEMUX_INPUT_TIMEOUT_C_2 \
+ (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x46) /* 0x1696*/
+#define DEMUX_INPUT_TIMEOUT_C_3 \
+ (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x46) /* 0x16e6*/
+/* bit[31] - no_match_reset_timeout_disable*/
+/* bit[30:0] input_time_out_int_cnt (0 -- means disable) Wr-setting, Rd-count*/
+#define DEMUX_INPUT_TIMEOUT \
+ (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x47) /* 0x1647*/
+#define DEMUX_INPUT_TIMEOUT_2 \
+ (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x47) /* 0x1697*/
+#define DEMUX_INPUT_TIMEOUT_3 \
+ (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x47) /* 0x16e7*/
+
+/* bit[31:0] - channel_packet_count_disable*/
+#define DEMUX_PACKET_COUNT_C \
+ (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x48) /* 0x1648*/
+#define DEMUX_PACKET_COUNT_C_2 \
+ (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x48) /* 0x1698*/
+#define DEMUX_PACKET_COUNT_C_3 \
+ (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x48) /* 0x16e8*/
+/* bit[31] - no_match_packet_count_disable*/
+/* bit[30:0] input_packet_count*/
+#define DEMUX_PACKET_COUNT \
+ (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x49) /* 0x1649*/
+#define DEMUX_PACKET_COUNT_2 \
+ (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x49) /* 0x1699*/
+#define DEMUX_PACKET_COUNT_3 \
+ (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x49) /* 0x16e9*/
+
+/* bit[31:0] channel_record_enable*/
+#define DEMUX_CHAN_RECORD_EN \
+ (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x4a) /* 0x164a*/
+#define DEMUX_CHAN_RECORD_EN_2 \
+ (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x4a) /* 0x169a*/
+#define DEMUX_CHAN_RECORD_EN_3 \
+ (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x4a) /* 0x16ea*/
+
+/* bit[31:0] channel_process_enable*/
+#define DEMUX_CHAN_PROCESS_EN \
+ (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x4b) /* 0x164b*/
+#define DEMUX_CHAN_PROCESS_EN_2 \
+ (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x4b) /* 0x169b*/
+#define DEMUX_CHAN_PROCESS_EN_3 \
+ (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x4b) /* 0x16eb*/
+
+/* bit[31:24] small_sec_size ((n+1) * 256 Bytes)*/
+/* bit[23:16] small_sec_rd_ptr */
+/* bit[15:8] small_sec_wr_ptr */
+/* bit[7:2] reserved*/
+/* bit[1] small_sec_wr_ptr_wr_enable*/
+/* bit[0] small_section_enable*/
+#define DEMUX_SMALL_SEC_CTL \
+ (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x4c) /* 0x164c*/
+#define DEMUX_SMALL_SEC_CTL_2 \
+ (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x4c) /* 0x169c*/
+#define DEMUX_SMALL_SEC_CTL_3 \
+ (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x4c) /* 0x16ec*/
+/* bit[31:0] small_sec_start_addr*/
+#define DEMUX_SMALL_SEC_ADDR \
+ (STB_CBUS_BASE + DEMUX_1_OFFSET + 0x4d) /* 0x164d*/
+#define DEMUX_SMALL_SEC_ADDR_2 \
+ (STB_CBUS_BASE + DEMUX_2_OFFSET + 0x4d) /* 0x169d*/
+#define DEMUX_SMALL_SEC_ADDR_3 \
+ (STB_CBUS_BASE + DEMUX_3_OFFSET + 0x4d) /* 0x16ed*/
+
+#endif
diff --git a/drivers/stream_input/parser/psparser.c b/drivers/stream_input/parser/psparser.c
new file mode 100644
index 0000000..20c1d1a
--- /dev/null
+++ b/drivers/stream_input/parser/psparser.c
@@ -0,0 +1,1199 @@
+/*
+ * drivers/amlogic/media/stream_input/parser/psparser.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/types.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/amlogic/media/frame_sync/ptsserv.h>
+#include <linux/amlogic/media/utils/amstream.h>
+
+#include <linux/uaccess.h>
+/* #include <mach/am_regs.h> */
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "../amports/streambuf_reg.h"
+#include "../amports/streambuf.h"
+#include "psparser.h"
+#include "../amports/amports_priv.h"
+
+
+#define TIMESTAMP_IONLY 1
+#define SAVE_SCR 0
+
+#define MPEG_START_CODE_PATTERN (0x00000100L)
+#define MPEG_START_CODE_MASK (0xffffff00L)
+#define MAX_MPG_AUDIOPK_SIZE 0x1000
+
+#define SUB_INSERT_START_CODE_HIGH 0x414d4c55
+#define SUB_INSERT_START_CODE_LOW 0xaa000000
+
+#define PARSER_WRITE (ES_WRITE | ES_PARSER_START)
+#define PARSER_VIDEO (ES_TYPE_VIDEO)
+#define PARSER_AUDIO (ES_TYPE_AUDIO)
+#define PARSER_SUBPIC (ES_TYPE_SUBTITLE)
+#define PARSER_PASSTHROUGH (ES_PASSTHROUGH | ES_PARSER_START)
+#define PARSER_AUTOSEARCH (ES_SEARCH | ES_PARSER_START)
+#define PARSER_DISCARD (ES_DISCARD | ES_PARSER_START)
+#define PARSER_BUSY (ES_PARSER_BUSY)
+
+#define PARSER_PARAMETER_LENGTH_BIT 16
+#define PARSER_PARAMETER_LOOP_BIT 24
+
+#define PARSER_POP READ_PARSER_REG(PFIFO_DATA)
+#define SET_BLOCK(size) \
+WRITE_PARSER_REG_BITS(PARSER_CONTROL, size, ES_PACK_SIZE_BIT, ES_PACK_SIZE_WID)
+#define SET_DISCARD_SIZE(size) WRITE_PARSER_REG(PARSER_PARAMETER, size)
+
+#define VIDEO_AUTO_FLUSH
+#ifdef VIDEO_AUTO_FLUSH
+static u32 video_auto_flush_state;
+#define VIDEO_AUTO_FLUSH_IDLE 0
+#define VIDEO_AUTO_FLUSH_MONITOR 1
+#define VIDEO_AUTO_FLUSH_TRIGGER 2
+#define VIDEO_AUTO_FLUSH_DONE 3
+#define VIDEO_AUTO_FLUSH_PTS_THRESHOLD 90000
+#define VIDEO_AUTO_FLUSH_BYTE_COUNT 1024
+
+static s32 audio_last_pts;
+static s32 audio_monitor_pts;
+#endif
+
+enum {
+ SEARCH_START_CODE = 0,
+ SEND_VIDEO_SEARCH,
+ SEND_AUDIO_SEARCH,
+ SEND_SUBPIC_SEARCH,
+ DISCARD_SEARCH,
+ DISCARD_ONLY
+#ifdef VIDEO_AUTO_FLUSH
+ ,
+ SEARCH_START_CODE_VIDEO_FLUSH
+#endif
+};
+
+enum {
+ AUDIO_FIRST_ACCESS_ARM = 0,
+ AUDIO_FIRST_ACCESS_POPING,
+ AUDIO_FIRST_ACCESS_DONE
+};
+
+static const char psparser_id[] = "psparser-id";
+
+static DECLARE_WAIT_QUEUE_HEAD(wq);
+
+static struct tasklet_struct psparser_tasklet;
+static u32 fetch_done;
+static u8 audio_id, video_id, sub_id, sub_id_max;
+static u32 audio_first_access;
+static u32 packet_remaining;
+static u32 video_data_parsed;
+static u32 audio_data_parsed;
+static u32 pts_equ_dts_flag;
+
+static unsigned int first_apts, first_vpts;
+static unsigned int audio_got_first_pts, video_got_first_dts, sub_got_first_pts;
+atomic_t sub_block_found = ATOMIC_INIT(0);
+
+#define DEBUG_VOB_SUB
+#ifdef DEBUG_VOB_SUB
+static u8 sub_found_num;
+static struct subtitle_info *sub_info[MAX_SUB_NUM];
+#endif
+
+static bool ptsmgr_first_vpts_ready(void)
+{
+ return (video_got_first_dts != 0) ? true : false;
+}
+
+static bool ptsmgr_first_apts_ready(void)
+{
+ return (audio_got_first_pts != 0) ? true : false;
+}
+
+static void ptsmgr_vpts_checkin(u32 pts)
+{
+ if (video_got_first_dts == 0) {
+ video_got_first_dts = 1;
+ first_vpts = pts;
+ }
+
+ pts_checkin_offset(PTS_TYPE_VIDEO, video_data_parsed, pts);
+}
+
+static void ptsmgr_apts_checkin(u32 pts)
+{
+ if (audio_got_first_pts == 0) {
+ audio_got_first_pts = 1;
+ first_apts = pts;
+ }
+ /* apts_checkin(pts); */
+ pts_checkin_offset(PTS_TYPE_AUDIO, audio_data_parsed, pts);
+
+#ifdef VIDEO_AUTO_FLUSH
+ audio_last_pts = pts;
+
+ if ((video_auto_flush_state == VIDEO_AUTO_FLUSH_IDLE)
+ && ptsmgr_first_vpts_ready()) {
+ video_auto_flush_state = VIDEO_AUTO_FLUSH_MONITOR;
+ audio_monitor_pts = pts;
+ }
+
+ if (video_auto_flush_state == VIDEO_AUTO_FLUSH_MONITOR) {
+ if ((audio_last_pts - audio_monitor_pts) >
+ VIDEO_AUTO_FLUSH_PTS_THRESHOLD)
+ video_auto_flush_state = VIDEO_AUTO_FLUSH_TRIGGER;
+ }
+#endif
+}
+
+static u32 parser_process(s32 type, s32 packet_len)
+{
+ s16 temp, header_len, misc_flags, i;
+ u32 pts = 0, dts = 0;
+ u32 pts_dts_flag = 0;
+ u16 invalid_pts = 0;
+
+ temp = PARSER_POP;
+ packet_len--;
+
+ if ((temp >> 6) == 0x02) {
+ /* mpeg-2 system */
+ misc_flags = PARSER_POP;
+ header_len = PARSER_POP;
+ packet_len -= 2;
+ packet_len -= header_len;
+
+ if ((misc_flags >> 6) > 1) {
+ /* PTS exist */
+ pts = ((PARSER_POP >> 1) & 7) << 30; /* bit 32-30 */
+ pts |= PARSER_POP << 22; /* bit 29-22 */
+ pts |= (PARSER_POP >> 1) << 15; /* bit 21-15 */
+ pts |= (PARSER_POP << 7); /* bit 14-07 */
+ pts |= (PARSER_POP >> 1); /* bit 06-00 */
+ header_len -= 5;
+ pts_dts_flag |= 2;
+ }
+
+ if ((misc_flags >> 6) > 2) {
+ /* DTS exist */
+ dts = ((PARSER_POP >> 1) & 7) << 30; /* bit 32-30 */
+ dts |= PARSER_POP << 22; /* bit 29-22 */
+ dts |= (PARSER_POP >> 1) << 15; /* bit 21-15 */
+ dts |= (PARSER_POP << 7); /* bit 14-07 */
+ dts |= (PARSER_POP >> 1); /* bit 06-00 */
+ header_len -= 5;
+ pts_dts_flag |= 1;
+ }
+
+ if (misc_flags & 0x20) {
+ /* ESCR_flag */
+ PARSER_POP;
+ PARSER_POP;
+ PARSER_POP;
+ PARSER_POP;
+ PARSER_POP;
+ PARSER_POP;
+ header_len -= 5;
+ }
+
+ if (misc_flags & 0x10) {
+ /* ES_rate_flag */
+ PARSER_POP;
+ PARSER_POP;
+ PARSER_POP;
+ header_len -= 3;
+ }
+
+ if (misc_flags & 0x08) {
+ /* DSM_trick_mode_flag */
+ PARSER_POP;
+ header_len -= 1;
+ }
+
+ if (misc_flags & 0x04) {
+ /* additional_copy_info_flag */
+ PARSER_POP;
+ header_len -= 1;
+ }
+
+ if (misc_flags & 0x02) {
+ /* PES_CRC_flag */
+ PARSER_POP;
+ PARSER_POP;
+ header_len -= 2;
+ }
+
+ if (misc_flags & 0x01) {
+ /* PES_extension_flag */
+ misc_flags = PARSER_POP;
+ header_len--;
+
+ if ((misc_flags & 0x80) && (header_len >= 128)) {
+ /* PES_private_data_flag */
+ for (i = 0; i < 128; i++)
+ PARSER_POP;
+
+ header_len -= 128;
+ }
+#if 0
+ if (misc_flags & 0x40) {
+ /* pack_header_field_flag */
+ /* Invalid case */
+ }
+#endif
+ if (misc_flags & 0x20) {
+ /* program_packet_sequence_counter_flag */
+ PARSER_POP;
+ PARSER_POP;
+ header_len -= 2;
+ }
+
+ if (misc_flags & 0x10) {
+ /* PSTD_buffer_flag */
+ PARSER_POP;
+ PARSER_POP;
+ header_len -= 2;
+ }
+
+ if (misc_flags & 1) {
+ /* PES_extension_flag_2 */
+ temp = PARSER_POP & 0x7f;
+
+ while (temp) {
+ PARSER_POP;
+ temp--;
+ header_len--;
+ }
+ }
+
+ while (header_len) {
+ PARSER_POP;
+ header_len--;
+ }
+ }
+
+ while (header_len) {
+ PARSER_POP;
+ header_len--;
+ }
+
+ } else {
+ /* mpeg-1 system */
+ while (temp == 0xff) {
+ temp = PARSER_POP;
+ packet_len--;
+ }
+
+ if ((temp >> 6) == 1) {
+ PARSER_POP; /* STD buffer size */
+ temp = PARSER_POP;
+ packet_len -= 2;
+ }
+
+ if (((temp >> 4) == 2) || ((temp >> 4) == 3)) {
+ pts = ((temp >> 1) & 7) << 30; /* bit 32-30 */
+ pts |= PARSER_POP << 22; /* bit 29-22 */
+ pts |= (PARSER_POP >> 1) << 15; /* bit 21-15 */
+ pts |= (PARSER_POP << 7); /* bit 14-07 */
+ pts |= (PARSER_POP >> 1); /* bit 06-00 */
+ packet_len -= 4;
+ pts_dts_flag |= 2;
+ }
+
+ if ((temp >> 4) == 3) {
+ dts = ((PARSER_POP >> 1) & 7) << 30; /* bit 32-30 */
+ dts |= PARSER_POP << 22; /* bit 29-22 */
+ dts |= (PARSER_POP >> 1) << 15; /* bit 21-15 */
+ dts |= (PARSER_POP << 7); /* bit 14-07 */
+ dts |= (PARSER_POP >> 1); /* bit 06-00 */
+ packet_len -= 5;
+ pts_dts_flag |= 1;
+ }
+ }
+
+ if ((pts == 0) && (dts == 0xffffffff)) {
+ invalid_pts = 1;
+ pr_info("invalid pts\n");
+ }
+
+ if (!packet_len)
+ return SEARCH_START_CODE;
+
+ else if (type == 0) {
+#ifdef VIDEO_AUTO_FLUSH
+ if (video_auto_flush_state == VIDEO_AUTO_FLUSH_MONITOR)
+ audio_monitor_pts = audio_last_pts;
+#endif
+
+ if ((pts_dts_flag) && (!invalid_pts)) {
+#if TIMESTAMP_IONLY
+ if (!ptsmgr_first_vpts_ready()) {
+ if (pts_dts_flag & 2)
+ ptsmgr_vpts_checkin(pts);
+ else
+ ptsmgr_vpts_checkin(dts);
+ } else if ((pts_dts_flag & 3) == 3) {
+ if (pts_equ_dts_flag) {
+ if (dts == pts)
+ ptsmgr_vpts_checkin(pts);
+ } else {
+ if (dts == pts)
+ pts_equ_dts_flag = 1;
+ ptsmgr_vpts_checkin(pts);
+ }
+ }
+#else
+ if (!ptsmgr_first_vpts_ready()) {
+ if (pts_dts_flag & 2)
+ ptsmgr_vpts_checkin(pts);
+ else
+ ptsmgr_vpts_checkin(dts);
+ } else if (pts_dts_flag & 2)
+ ptsmgr_vpts_checkin(pts);
+#endif
+ }
+
+ if (ptsmgr_first_vpts_ready() || invalid_pts) {
+ SET_BLOCK(packet_len);
+ video_data_parsed += packet_len;
+ return SEND_VIDEO_SEARCH;
+
+ } else {
+ SET_DISCARD_SIZE(packet_len);
+ return DISCARD_SEARCH;
+ }
+
+ } else if (type == 1) {
+ /* mpeg audio */
+ if (pts_dts_flag & 2)
+ ptsmgr_apts_checkin(pts);
+
+ if (ptsmgr_first_apts_ready()) {
+ SET_BLOCK(packet_len);
+ audio_data_parsed += packet_len;
+ return SEND_AUDIO_SEARCH;
+
+ } else {
+ SET_DISCARD_SIZE(packet_len);
+ return DISCARD_SEARCH;
+ }
+
+ } else if (type == 2) {
+ /* Private stream */
+ temp = PARSER_POP; /* sub_stream_id */
+ packet_len--;
+
+ if (((temp & 0xf8) == 0xa0) && (temp == audio_id)) {
+ /* DVD_VIDEO Audio LPCM data */
+ PARSER_POP;
+ temp = (PARSER_POP << 8) | PARSER_POP;
+ if (temp == 0)
+ temp = 4;
+ temp--;
+ packet_len -= 3;
+
+ if (audio_first_access == AUDIO_FIRST_ACCESS_ARM) {
+ if (temp) {
+ packet_remaining = packet_len - temp;
+ SET_DISCARD_SIZE(temp);
+ audio_first_access =
+ AUDIO_FIRST_ACCESS_POPING;
+ return DISCARD_ONLY;
+ }
+
+ audio_first_access = AUDIO_FIRST_ACCESS_DONE;
+
+ if (packet_len) {
+ SET_BLOCK(packet_len);
+ audio_data_parsed += packet_len;
+ return SEND_AUDIO_SEARCH;
+
+ } else
+ return SEARCH_START_CODE;
+
+ } else {
+ PARSER_POP;
+ PARSER_POP;
+ PARSER_POP;
+ packet_len -= 3;
+ }
+
+ if (pts_dts_flag & 2)
+ ptsmgr_apts_checkin(pts);
+
+ if (ptsmgr_first_apts_ready()) {
+ SET_BLOCK(packet_len);
+ audio_data_parsed += packet_len;
+ return SEND_AUDIO_SEARCH;
+
+ } else {
+ SET_DISCARD_SIZE(packet_len);
+ return DISCARD_SEARCH;
+ }
+
+ } else if (((temp & 0xf8) == 0x80) && (temp == audio_id)) {
+ /* Audio AC3 data */
+ PARSER_POP;
+ temp = (PARSER_POP << 8) | PARSER_POP;
+ packet_len -= 3;
+
+ if (audio_first_access == AUDIO_FIRST_ACCESS_ARM) {
+ if (pts_dts_flag & 2)
+ ptsmgr_apts_checkin(pts);
+
+ if ((temp > 2) && (packet_len > (temp - 2))) {
+ temp -= 2;
+ packet_remaining = packet_len - temp;
+ SET_DISCARD_SIZE(temp);
+ audio_first_access =
+ AUDIO_FIRST_ACCESS_POPING;
+ return DISCARD_ONLY;
+ }
+
+ audio_first_access = AUDIO_FIRST_ACCESS_DONE;
+
+ if (packet_len) {
+ SET_BLOCK(packet_len);
+ audio_data_parsed += packet_len;
+ return SEND_AUDIO_SEARCH;
+
+ } else
+ return SEARCH_START_CODE;
+ }
+
+ if (pts_dts_flag & 2)
+ ptsmgr_apts_checkin(pts);
+
+ if (ptsmgr_first_apts_ready()) {
+ SET_BLOCK(packet_len);
+ audio_data_parsed += packet_len;
+ return SEND_AUDIO_SEARCH;
+
+ } else {
+ SET_DISCARD_SIZE(packet_len);
+ return DISCARD_SEARCH;
+ }
+
+ } else if (((temp & 0xf8) == 0x88) && (temp == audio_id)) {
+ /* Audio DTS data */
+ PARSER_POP;
+ PARSER_POP;
+ PARSER_POP;
+ packet_len -= 3;
+
+ if (audio_first_access == AUDIO_FIRST_ACCESS_ARM)
+ audio_first_access = AUDIO_FIRST_ACCESS_DONE;
+
+ if (pts_dts_flag & 2)
+ ptsmgr_apts_checkin(pts);
+
+ if (ptsmgr_first_apts_ready()) {
+ SET_BLOCK(packet_len);
+ audio_data_parsed += packet_len;
+ return SEND_AUDIO_SEARCH;
+
+ } else {
+ SET_DISCARD_SIZE(packet_len);
+ return DISCARD_SEARCH;
+ }
+ } else if ((temp & 0xe0) == 0x20) {
+ if (temp > sub_id_max)
+ sub_id_max = temp;
+#ifdef DEBUG_VOB_SUB
+ for (i = 0; i < sub_found_num; i++) {
+ if (!sub_info[i])
+ break;
+ if (temp == sub_info[i]->id)
+ break;
+ }
+ if (i == sub_found_num && i < MAX_SUB_NUM) {
+ if (sub_info[sub_found_num]) {
+ sub_info[sub_found_num]->id = temp;
+ sub_found_num++;
+ pr_info
+ ("[%s]found new sub_id=0x%x (num %d)\n",
+ __func__, temp, sub_found_num);
+ } else {
+ pr_info
+ ("[%s]sub info NULL!\n", __func__);
+ }
+ }
+#endif
+
+ if (temp == sub_id) {
+ /* DVD sub-picture data */
+ if (!packet_len)
+ return SEARCH_START_CODE;
+
+ else {
+#if 0
+ if (pts_dts_flag & 2)
+ ptsmgr_spts_checkin(pts);
+
+ if (ptsmgr_first_spts_ready()) {
+ SET_BLOCK(packet_len);
+ return SEND_SUBPIC_SEARCH;
+
+ } else {
+ SET_DISCARD_SIZE(packet_len);
+ return DISCARD_SEARCH;
+ }
+#else
+ if (pts_dts_flag & 2)
+ sub_got_first_pts = 1;
+
+ if (sub_got_first_pts) {
+ pr_info
+ ("sub pts 0x%x, len %d\n",
+ pts, packet_len);
+ SET_BLOCK(packet_len);
+ WRITE_PARSER_REG
+ (PARSER_PARAMETER,
+ 16 <<
+ PARSER_PARAMETER_LENGTH_BIT);
+ WRITE_PARSER_REG
+ (PARSER_INSERT_DATA,
+ SUB_INSERT_START_CODE_HIGH);
+ WRITE_PARSER_REG
+ (PARSER_INSERT_DATA,
+ SUB_INSERT_START_CODE_LOW |
+ get_sub_type());
+ WRITE_PARSER_REG
+ (PARSER_INSERT_DATA,
+ packet_len);
+ WRITE_PARSER_REG
+ (PARSER_INSERT_DATA, pts);
+ atomic_set(&sub_block_found, 1);
+ return SEND_SUBPIC_SEARCH;
+ }
+
+ SET_DISCARD_SIZE(packet_len);
+ return DISCARD_SEARCH;
+#endif
+ }
+ } else {
+ SET_DISCARD_SIZE(packet_len);
+ return DISCARD_SEARCH;
+ }
+ } else {
+ SET_DISCARD_SIZE(packet_len);
+ return DISCARD_SEARCH;
+ }
+ }
+
+ return SEARCH_START_CODE;
+}
+
+static void on_start_code_found(int start_code)
+{
+ unsigned short packet_len;
+ unsigned short temp;
+ unsigned int next_action;
+#if SAVE_SCR
+ unsigned int scr;
+#endif
+
+ if (atomic_read(&sub_block_found)) {
+ wakeup_sub_poll();
+ atomic_set(&sub_block_found, 0);
+ }
+
+ if (audio_first_access == AUDIO_FIRST_ACCESS_POPING) {
+ /*
+ *we are in the procedure of poping data for audio first
+ * access, continue with last packet
+ */
+ audio_first_access = AUDIO_FIRST_ACCESS_DONE;
+
+ if (packet_remaining) {
+ next_action = SEND_AUDIO_SEARCH;
+ SET_BLOCK(packet_remaining);
+
+ } else
+ next_action = SEARCH_START_CODE;
+
+ } else if (start_code == 0xba) { /* PACK_START_CODE */
+ temp = PARSER_POP;
+
+ if ((temp >> 6) == 0x01) {
+#if SAVE_SCR
+ scr = ((temp >> 3) & 0x3) << 30; /* bit 31-30 */
+ scr |= (temp & 0x3) << 28; /* bit 29-28 */
+ scr |= (PARSER_POP) << 20; /* bit 27-20 */
+ temp = PARSER_POP;
+ scr |= (temp >> 4) << 16; /* bit 19-16 */
+ scr |= (temp & 7) << 13; /* bit 15-13 */
+ scr |= (PARSER_POP) << 5; /* bit 12-05 */
+ scr |= (PARSER_POP) >> 3; /* bit 04-00 */
+#else
+ PARSER_POP;
+ PARSER_POP;
+ PARSER_POP;
+ PARSER_POP;
+#endif
+ PARSER_POP;
+ PARSER_POP;
+ PARSER_POP;
+ PARSER_POP;
+ temp = PARSER_POP & 7;
+
+ while (temp) { /* stuff byte */
+ PARSER_POP;
+ temp--;
+ }
+
+ } else {
+ /* mpeg-1 Pack Header */
+#if SAVE_SCR
+ scr = ((temp >> 1) & 0x3) << 30; /* bit 31-30 */
+ scr |= (PARSER_POP) << 22; /* bit 29-22 */
+ scr |= (PARSER_POP >> 1) << 15; /* bit 21-15 */
+ scr |= (PARSER_POP) << 7; /* bit 14-07 */
+ scr |= (PARSER_POP >> 1); /* bit 06-00 */
+#else
+ PARSER_POP;
+ PARSER_POP;
+ PARSER_POP;
+ PARSER_POP;
+#endif
+ }
+
+#ifdef VIDEO_AUTO_FLUSH
+ if (video_auto_flush_state == VIDEO_AUTO_FLUSH_TRIGGER) {
+ next_action = SEARCH_START_CODE_VIDEO_FLUSH;
+ video_auto_flush_state = VIDEO_AUTO_FLUSH_DONE;
+ } else
+#endif
+
+ next_action = SEARCH_START_CODE;
+
+ } else {
+ packet_len = (PARSER_POP << 8) | PARSER_POP;
+
+ if (start_code == video_id)
+ next_action = parser_process(0, packet_len);
+
+ else if (start_code == audio_id) {
+ /* add mpeg audio packet length check */
+ if (packet_len > MAX_MPG_AUDIOPK_SIZE)
+ next_action = SEARCH_START_CODE;
+
+ else
+ next_action = parser_process(1, packet_len);
+
+ } else if (start_code == 0xbb) {
+ SET_DISCARD_SIZE(packet_len);
+ next_action = DISCARD_SEARCH;
+ } else if (start_code == 0xbd)
+ next_action = parser_process(2, packet_len);
+
+ else if (start_code == 0xbf) {
+ SET_DISCARD_SIZE(packet_len);
+ next_action = DISCARD_SEARCH;
+ } else if ((start_code < 0xc0) || (start_code > 0xc8))
+ next_action = SEARCH_START_CODE;
+
+ else if (packet_len) {
+ SET_DISCARD_SIZE(packet_len);
+ next_action = DISCARD_SEARCH;
+
+ } else
+ next_action = SEARCH_START_CODE;
+ }
+
+ switch (next_action) {
+ case SEARCH_START_CODE:
+ WRITE_PARSER_REG(PARSER_CONTROL, PARSER_AUTOSEARCH);
+ break;
+
+ case SEND_VIDEO_SEARCH:
+ WRITE_PARSER_REG_BITS(PARSER_CONTROL,
+ PARSER_AUTOSEARCH | PARSER_VIDEO |
+ PARSER_WRITE, ES_CTRL_BIT, ES_CTRL_WID);
+ break;
+
+ case SEND_AUDIO_SEARCH:
+ WRITE_PARSER_REG_BITS(PARSER_CONTROL,
+ PARSER_AUTOSEARCH | PARSER_AUDIO |
+ PARSER_WRITE, ES_CTRL_BIT, ES_CTRL_WID);
+ break;
+
+ case SEND_SUBPIC_SEARCH:
+ WRITE_PARSER_REG_BITS(PARSER_CONTROL,
+ PARSER_AUTOSEARCH | PARSER_SUBPIC |
+ PARSER_WRITE | ES_INSERT_BEFORE_ES_WRITE,
+ ES_CTRL_BIT, ES_CTRL_WID);
+ break;
+
+ case DISCARD_SEARCH:
+ WRITE_PARSER_REG_BITS(PARSER_CONTROL,
+ PARSER_AUTOSEARCH | PARSER_DISCARD,
+ ES_CTRL_BIT, ES_CTRL_WID);
+ break;
+
+ case DISCARD_ONLY:
+ WRITE_PARSER_REG_BITS(PARSER_CONTROL,
+ PARSER_DISCARD, ES_CTRL_BIT, ES_CTRL_WID);
+ break;
+
+#ifdef VIDEO_AUTO_FLUSH
+ case SEARCH_START_CODE_VIDEO_FLUSH:
+ WRITE_PARSER_REG(PARSER_INSERT_DATA, 0xffffffff);
+ WRITE_PARSER_REG(PARSER_INSERT_DATA, 0xffffffff);
+ WRITE_PARSER_REG(PARSER_PARAMETER,
+ ((VIDEO_AUTO_FLUSH_BYTE_COUNT /
+ 8) << PARSER_PARAMETER_LOOP_BIT) | (8 <<
+ PARSER_PARAMETER_LENGTH_BIT));
+ WRITE_PARSER_REG(PARSER_CONTROL,
+ PARSER_AUTOSEARCH | PARSER_VIDEO | PARSER_WRITE |
+ ES_INSERT_BEFORE_ES_WRITE);
+ break;
+#endif
+ }
+}
+
+static void parser_tasklet(ulong data)
+{
+ s32 sc;
+ u32 int_status = READ_PARSER_REG(PARSER_INT_STATUS);
+
+ WRITE_PARSER_REG(PARSER_INT_STATUS, int_status);
+
+ if (int_status & PARSER_INTSTAT_FETCH_CMD) {
+ fetch_done = 1;
+
+ wake_up_interruptible(&wq);
+ }
+
+ if (int_status & PARSER_INTSTAT_SC_FOUND) {
+ sc = PARSER_POP;
+
+ on_start_code_found(sc);
+
+ } else if (int_status & PARSER_INTSTAT_DISCARD)
+ on_start_code_found(0);
+}
+
+static irqreturn_t parser_isr(int irq, void *dev_id)
+{
+ tasklet_schedule(&psparser_tasklet);
+
+ return IRQ_HANDLED;
+}
+
+static ssize_t _psparser_write(const char __user *buf, size_t count)
+{
+ size_t r = count;
+ const char __user *p = buf;
+ u32 len;
+ int ret;
+ dma_addr_t dma_addr = 0;
+
+ if (r > 0) {
+ len = min_t(size_t, r, FETCHBUF_SIZE);
+ if (copy_from_user(fetchbuf, p, len))
+ return -EFAULT;
+
+ dma_addr =
+ dma_map_single(amports_get_dma_device(),
+ fetchbuf, FETCHBUF_SIZE, DMA_TO_DEVICE);
+ if (dma_mapping_error(amports_get_dma_device(), dma_addr))
+ return -EFAULT;
+
+
+ fetch_done = 0;
+
+ wmb(); /* Ensure fetchbuf contents visible */
+
+ WRITE_PARSER_REG(PARSER_FETCH_ADDR, dma_addr);
+
+ WRITE_PARSER_REG(PARSER_FETCH_CMD, (7 << FETCH_ENDIAN) | len);
+ dma_unmap_single(amports_get_dma_device(), dma_addr,
+ FETCHBUF_SIZE, DMA_TO_DEVICE);
+ ret =
+ wait_event_interruptible_timeout(wq, fetch_done != 0,
+ HZ / 10);
+ if (ret == 0) {
+ WRITE_PARSER_REG(PARSER_FETCH_CMD, 0);
+ pr_info("write timeout, retry\n");
+ return -EAGAIN;
+ } else if (ret < 0)
+ return -ERESTARTSYS;
+
+ p += len;
+ r -= len;
+ }
+
+ return count - r;
+}
+
+s32 psparser_init(u32 vid, u32 aid, u32 sid, struct vdec_s *vdec)
+{
+ s32 r;
+ u32 parser_sub_start_ptr;
+ u32 parser_sub_end_ptr;
+ u32 parser_sub_rp;
+
+#ifdef DEBUG_VOB_SUB
+ u8 i;
+
+ for (i = 0; i < MAX_SUB_NUM; i++) {
+ sub_info[i] = kzalloc(sizeof(struct subtitle_info), GFP_KERNEL);
+ if (!sub_info[i]) {
+ pr_info
+ ("[psparser_init]alloc for subtitle info failed\n");
+ } else
+ sub_info[i]->id = -1;
+ }
+ sub_found_num = 0;
+#endif
+ parser_sub_start_ptr = READ_PARSER_REG(PARSER_SUB_START_PTR);
+ parser_sub_end_ptr = READ_PARSER_REG(PARSER_SUB_END_PTR);
+ parser_sub_rp = READ_PARSER_REG(PARSER_SUB_RP);
+
+ video_id = vid;
+ audio_id = aid;
+ sub_id = sid;
+ audio_got_first_pts = 0;
+ video_got_first_dts = 0;
+ sub_got_first_pts = 0;
+ first_apts = 0;
+ first_vpts = 0;
+ pts_equ_dts_flag = 0;
+
+#ifdef VIDEO_AUTO_FLUSH
+ video_auto_flush_state = VIDEO_AUTO_FLUSH_IDLE;
+#endif
+
+ pr_info("video 0x%x, audio 0x%x, sub 0x%x\n", video_id, audio_id,
+ sub_id);
+ if (fetchbuf == 0) {
+ pr_info("%s: no fetchbuf\n", __func__);
+ return -ENOMEM;
+ }
+
+ WRITE_RESET_REG(RESET1_REGISTER, RESET_PARSER);
+
+/* for recorded file and local play, this can't change the input source*/
+ /* TS data path */
+/*
+#ifndef CONFIG_AM_DVB
+ WRITE_DEMUX_REG(FEC_INPUT_CONTROL, 0);
+#else
+ tsdemux_set_reset_flag();
+#endif */
+
+ CLEAR_DEMUX_REG_MASK(TS_HIU_CTL, 1 << USE_HI_BSF_INTERFACE);
+ CLEAR_DEMUX_REG_MASK(TS_HIU_CTL_2, 1 << USE_HI_BSF_INTERFACE);
+ CLEAR_DEMUX_REG_MASK(TS_HIU_CTL_3, 1 << USE_HI_BSF_INTERFACE);
+ CLEAR_DEMUX_REG_MASK(TS_FILE_CONFIG, (1 << TS_HIU_ENABLE));
+
+ /* hook stream buffer with PARSER */
+ WRITE_PARSER_REG(PARSER_VIDEO_START_PTR, vdec->input.start);
+ WRITE_PARSER_REG(PARSER_VIDEO_END_PTR,
+ vdec->input.start + vdec->input.size - 8);
+
+ if (vdec_single(vdec)) {
+ CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL, ES_VID_MAN_RD_PTR);
+ WRITE_VREG(VLD_MEM_VIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ CLEAR_VREG_MASK(VLD_MEM_VIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ } else {
+ SET_PARSER_REG_MASK(PARSER_ES_CONTROL, ES_VID_MAN_RD_PTR);
+ WRITE_PARSER_REG(PARSER_VIDEO_WP, vdec->input.start);
+ WRITE_PARSER_REG(PARSER_VIDEO_RP, vdec->input.start);
+ }
+
+ WRITE_PARSER_REG(PARSER_AUDIO_START_PTR,
+ READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_PARSER_REG(PARSER_AUDIO_END_PTR,
+ READ_AIU_REG(AIU_MEM_AIFIFO_END_PTR));
+ CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL, ES_AUD_MAN_RD_PTR);
+
+ WRITE_PARSER_REG(PARSER_CONFIG,
+ (10 << PS_CFG_PFIFO_EMPTY_CNT_BIT) |
+ (1 << PS_CFG_MAX_ES_WR_CYCLE_BIT) |
+ (16 << PS_CFG_MAX_FETCH_CYCLE_BIT));
+
+ if (vdec_single(vdec)) {
+ WRITE_VREG(VLD_MEM_VIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ CLEAR_VREG_MASK(VLD_MEM_VIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ }
+
+ WRITE_AIU_REG(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ CLEAR_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+
+ WRITE_PARSER_REG(PARSER_SUB_START_PTR, parser_sub_start_ptr);
+ WRITE_PARSER_REG(PARSER_SUB_END_PTR, parser_sub_end_ptr);
+ WRITE_PARSER_REG(PARSER_SUB_RP, parser_sub_start_ptr);
+ WRITE_PARSER_REG(PARSER_SUB_WP, parser_sub_start_ptr);
+ SET_PARSER_REG_MASK(PARSER_ES_CONTROL,
+ (7 << ES_SUB_WR_ENDIAN_BIT) | ES_SUB_MAN_RD_PTR);
+
+ WRITE_PARSER_REG(PFIFO_RD_PTR, 0);
+ WRITE_PARSER_REG(PFIFO_WR_PTR, 0);
+
+ WRITE_PARSER_REG(PARSER_SEARCH_PATTERN, MPEG_START_CODE_PATTERN);
+ WRITE_PARSER_REG(PARSER_SEARCH_MASK, MPEG_START_CODE_MASK);
+
+ WRITE_PARSER_REG(PARSER_CONFIG,
+ (10 << PS_CFG_PFIFO_EMPTY_CNT_BIT) |
+ (1 << PS_CFG_MAX_ES_WR_CYCLE_BIT) |
+ PS_CFG_STARTCODE_WID_24 |
+ PS_CFG_PFIFO_ACCESS_WID_8 | /* single byte pop */
+ (16 << PS_CFG_MAX_FETCH_CYCLE_BIT));
+ WRITE_PARSER_REG(PARSER_CONTROL, PARSER_AUTOSEARCH);
+
+ tasklet_init(&psparser_tasklet, parser_tasklet, 0);
+ r = pts_start(PTS_TYPE_VIDEO);
+ if (r < 0)
+ goto Err_1;
+ r = pts_start(PTS_TYPE_AUDIO);
+ if (r < 0)
+ goto Err_2;
+
+ video_data_parsed = 0;
+ audio_data_parsed = 0;
+ /*TODO irq */
+
+ r = vdec_request_irq(PARSER_IRQ, parser_isr,
+ "psparser", (void *)psparser_id);
+
+ if (r) {
+ pr_info("PS Demux irq register failed.\n");
+
+ r = -ENOENT;
+ goto Err_3;
+ }
+
+ WRITE_PARSER_REG(PARSER_INT_STATUS, 0xffff);
+ WRITE_PARSER_REG(PARSER_INT_ENABLE,
+ PARSER_INT_ALL << PARSER_INT_HOST_EN_BIT);
+
+ return 0;
+
+Err_3:
+ pts_stop(PTS_TYPE_AUDIO);
+
+Err_2:
+ pts_stop(PTS_TYPE_VIDEO);
+
+Err_1:
+ return r;
+}
+
+void psparser_release(void)
+{
+ u8 i;
+
+ pr_info("psparser_release\n");
+
+ WRITE_PARSER_REG(PARSER_INT_ENABLE, 0);
+ /*TODO irq */
+
+ vdec_free_irq(PARSER_IRQ, (void *)psparser_id);
+
+ pts_stop(PTS_TYPE_VIDEO);
+ pts_stop(PTS_TYPE_AUDIO);
+#ifdef DEBUG_VOB_SUB
+ for (i = 0; i < MAX_SUB_NUM; i++)
+ kfree(sub_info[i]);
+ pr_info("psparser release subtitle info\n");
+#endif
+}
+EXPORT_SYMBOL(psparser_release);
+
+ssize_t psparser_write(struct file *file,
+ struct stream_buf_s *vbuf,
+ struct stream_buf_s *abuf,
+ const char __user *buf, size_t count)
+{
+ s32 r;
+
+ struct port_priv_s *priv = (struct port_priv_s *)file->private_data;
+ struct stream_port_s *port = priv->port;
+
+ if ((stbuf_space(vbuf) < count) || (stbuf_space(abuf) < count)) {
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ if ((port->flag & PORT_FLAG_VID)
+ && (stbuf_space(vbuf) < count)) {
+ r = stbuf_wait_space(vbuf, count);
+ if (r < 0)
+ return r;
+ }
+ if ((port->flag & PORT_FLAG_AID)
+ && (stbuf_space(abuf) < count)) {
+ r = stbuf_wait_space(abuf, count);
+ if (r < 0)
+ return r;
+ }
+ }
+
+ return _psparser_write(buf, count);
+}
+
+void psparser_change_avid(unsigned int vid, unsigned int aid)
+{
+ video_id = vid;
+ audio_id = aid;
+}
+
+void psparser_change_sid(unsigned int sid)
+{
+ sub_id = sid;
+}
+
+void psparser_audio_reset(void)
+{
+ ulong flags;
+
+ DEFINE_SPINLOCK(lock);
+
+ spin_lock_irqsave(&lock, flags);
+
+ WRITE_PARSER_REG(PARSER_AUDIO_WP,
+ READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_PARSER_REG(PARSER_AUDIO_RP,
+ READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
+
+ WRITE_PARSER_REG(PARSER_AUDIO_START_PTR,
+ READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_PARSER_REG(PARSER_AUDIO_END_PTR,
+ READ_AIU_REG(AIU_MEM_AIFIFO_END_PTR));
+ CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL, ES_AUD_MAN_RD_PTR);
+
+ WRITE_AIU_REG(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ CLEAR_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+
+ audio_data_parsed = 0;
+
+ spin_unlock_irqrestore(&lock, flags);
+
+}
+
+void psparser_sub_reset(void)
+{
+ ulong flags;
+
+ DEFINE_SPINLOCK(lock);
+ u32 parser_sub_start_ptr;
+ u32 parser_sub_end_ptr;
+
+ spin_lock_irqsave(&lock, flags);
+
+ parser_sub_start_ptr = READ_PARSER_REG(PARSER_SUB_START_PTR);
+ parser_sub_end_ptr = READ_PARSER_REG(PARSER_SUB_END_PTR);
+
+ WRITE_PARSER_REG(PARSER_SUB_START_PTR, parser_sub_start_ptr);
+ WRITE_PARSER_REG(PARSER_SUB_END_PTR, parser_sub_end_ptr);
+ WRITE_PARSER_REG(PARSER_SUB_RP, parser_sub_start_ptr);
+ WRITE_PARSER_REG(PARSER_SUB_WP, parser_sub_start_ptr);
+ SET_PARSER_REG_MASK(PARSER_ES_CONTROL,
+ (7 << ES_SUB_WR_ENDIAN_BIT) | ES_SUB_MAN_RD_PTR);
+
+ spin_unlock_irqrestore(&lock, flags);
+
+}
+
+u8 psparser_get_sub_found_num(void)
+{
+#ifdef DEBUG_VOB_SUB
+ return sub_found_num;
+#else
+ return 0;
+#endif
+}
+
+u8 psparser_get_sub_info(struct subtitle_info **sub_infos)
+{
+#ifdef DEBUG_VOB_SUB
+ u8 i = 0;
+ int ret = 0;
+ u8 size = sizeof(struct subtitle_info);
+
+ for (i = 0; i < sub_found_num; i++) {
+ if (!sub_info[i]) {
+ pr_info
+ ("[psparser_get_sub_info:%d] sub_info[%d] NULL\n",
+ __LINE__, i);
+ ret = -1;
+ break;
+ }
+ if (!sub_infos[i]) {
+ pr_info
+ ("[psparser_get_sub_info:%d] sub_infos[%d] NULL\n",
+ __LINE__, i);
+ ret = -2;
+ break;
+ }
+ memcpy(sub_infos[i], sub_info[i], size);
+ }
+ return ret;
+#else
+ return 0;
+#endif
+}
+
+static int psparser_stbuf_init(struct stream_buf_s *stbuf,
+ struct vdec_s *vdec)
+{
+ int ret = -1;
+
+ ret = stbuf_init(stbuf, vdec);
+ if (ret)
+ goto out;
+
+ ret = psparser_init(stbuf->pars.vid,
+ stbuf->pars.aid,
+ stbuf->pars.sid,
+ vdec);
+ if (ret)
+ goto out;
+
+ stbuf->flag |= BUF_FLAG_IN_USE;
+out:
+ return ret;
+}
+
+static void psparser_stbuf_release(struct stream_buf_s *stbuf)
+{
+ psparser_release();
+
+ stbuf_release(stbuf);
+}
+
+static struct stream_buf_ops psparser_stbuf_ops = {
+ .init = psparser_stbuf_init,
+ .release = psparser_stbuf_release,
+ .get_wp = parser_get_wp,
+ .set_wp = parser_set_wp,
+ .get_rp = parser_get_rp,
+ .set_rp = parser_set_rp,
+};
+
+struct stream_buf_ops *get_psparser_stbuf_ops(void)
+{
+ return &psparser_stbuf_ops;
+}
+EXPORT_SYMBOL(get_psparser_stbuf_ops);
+
diff --git a/drivers/stream_input/parser/psparser.h b/drivers/stream_input/parser/psparser.h
new file mode 100644
index 0000000..b83e342
--- /dev/null
+++ b/drivers/stream_input/parser/psparser.h
@@ -0,0 +1,142 @@
+/*
+ * drivers/amlogic/media/stream_input/parser/psparser.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 PSPARSER_H
+#define PSPARSER_H
+
+#include "../../frame_provider/decoder/utils/vdec.h"
+
+extern s32 psparser_init(u32 vid, u32 aid, u32 sid, struct vdec_s *vdec);
+
+extern void psparser_release(void);
+
+extern ssize_t psparser_write(struct file *file,
+ struct stream_buf_s *vbuf,
+ struct stream_buf_s *abuf,
+ const char __user *buf, size_t count);
+
+extern void psparser_change_avid(unsigned int vid, unsigned int aid);
+
+extern void psparser_change_sid(unsigned int sid);
+
+extern void psparser_audio_reset(void);
+
+extern void psparser_sub_reset(void);
+
+extern u8 psparser_get_sub_found_num(void);
+
+extern u8 psparser_get_sub_info(struct subtitle_info *sub_infos[]);
+
+#ifdef CONFIG_AM_DVB
+extern int tsdemux_set_reset_flag(void);
+#endif
+
+/* TODO: move to register headers */
+#define ES_PACK_SIZE_BIT 8
+#define ES_PACK_SIZE_WID 24
+
+#define ES_CTRL_WID 8
+#define ES_CTRL_BIT 0
+#define ES_TYPE_MASK (3 << 6)
+#define ES_TYPE_VIDEO (0 << 6)
+#define ES_TYPE_AUDIO (1 << 6)
+#define ES_TYPE_SUBTITLE (2 << 6)
+
+#define ES_WRITE (1<<5)
+#define ES_PASSTHROUGH (1<<4)
+#define ES_INSERT_BEFORE_ES_WRITE (1<<3)
+#define ES_DISCARD (1<<2)
+#define ES_SEARCH (1<<1)
+#define ES_PARSER_START (1<<0)
+#define ES_PARSER_BUSY (1<<0)
+
+#define PARSER_INTSTAT_FETCH_CMD (1<<7)
+#define PARSER_INTSTAT_PARSE (1<<4)
+#define PARSER_INTSTAT_DISCARD (1<<3)
+#define PARSER_INTSTAT_INSZERO (1<<2)
+#define PARSER_INTSTAT_ACT_NOSSC (1<<1)
+#define PARSER_INTSTAT_SC_FOUND (1<<0)
+
+#define FETCH_CIR_BUF (1<<31)
+#define FETCH_CHK_BUF_STOP (1<<30)
+#define FETCH_PASSTHROUGH (1<<29)
+#define FETCH_ENDIAN 27
+#define FETCH_PASSTHROUGH_TYPE_MASK (0x3<<27)
+#define FETCH_ENDIAN_MASK (0x7<<27)
+#define FETCH_BUF_SIZE_MASK (0x7ffffff)
+#define FETCH_CMD_PTR_MASK 3
+#define FETCH_CMD_RD_PTR_BIT 5
+#define FETCH_CMD_WR_PTR_BIT 3
+#define FETCH_CMD_NUM_MASK 3
+#define FETCH_CMD_NUM_BIT 0
+
+#define ES_COUNT_MASK 0xfff
+#define ES_COUNT_BIT 20
+#define ES_REQ_PENDING (1<<19)
+#define ES_PASSTHROUGH_EN (1<<18)
+#define ES_PASSTHROUGH_TYPE_MASK (3<<16)
+#define ES_PASSTHROUGH_TYPE_VIDEO (0<<16)
+#define ES_PASSTHROUGH_TYPE_AUDIO (1<<16)
+#define ES_PASSTHROUGH_TYPE_SUBTITLE (2<<16)
+#define ES_WR_ENDIAN_MASK (0x7)
+#define ES_SUB_WR_ENDIAN_BIT 9
+#define ES_SUB_MAN_RD_PTR (1<<8)
+#define ES_AUD_WR_ENDIAN_BIT 5
+#define ES_AUD_MAN_RD_PTR (1<<4)
+#define ES_VID_WR_ENDIAN_BIT 1
+#define ES_VID_MAN_RD_PTR (1<<0)
+
+#define PS_CFG_FETCH_DMA_URGENT (1<<31)
+#define PS_CFG_STREAM_DMA_URGENT (1<<30)
+#define PS_CFG_FORCE_PFIFO_REN (1<<29)
+#define PS_CFG_PFIFO_PEAK_EN (1<<28)
+#define PS_CFG_SRC_SEL_BIT 24
+#define PS_CFG_SRC_SEL_MASK (3<<PS_CFG_SRC_SEL_BIT)
+#define PS_CFG_SRC_SEL_FETCH (0<<PS_CFG_SRC_SEL_BIT)
+#define PS_CFG_SRC_SEL_AUX1 (1<<PS_CFG_SRC_SEL_BIT) /* from NDMA */
+#define PS_CFG_SRC_SEL_AUX2 (2<<PS_CFG_SRC_SEL_BIT)
+#define PS_CFG_SRC_SEL_AUX3 (3<<PS_CFG_SRC_SEL_BIT)
+#define PS_CFG_PFIFO_EMPTY_CNT_BIT 16
+#define PS_CFG_PFIFO_EMPTY_CNT_MASK 0xff
+#define PS_CFG_MAX_ES_WR_CYCLE_BIT 12
+#define PS_CFG_MAX_ES_WR_CYCLE_MASK 0xf
+#define PS_CFG_STARTCODE_WID_MASK (0x3<<10)
+#define PS_CFG_STARTCODE_WID_8 (0x0<<10)
+#define PS_CFG_STARTCODE_WID_16 (0x1<<10)
+#define PS_CFG_STARTCODE_WID_24 (0x2<<10)
+#define PS_CFG_STARTCODE_WID_32 (0x3<<10)
+#define PS_CFG_PFIFO_ACCESS_WID_MASK (0x3<<8)
+#define PS_CFG_PFIFO_ACCESS_WID_8 (0x0<<8)
+#define PS_CFG_PFIFO_ACCESS_WID_16 (0x1<<8)
+#define PS_CFG_PFIFO_ACCESS_WID_24 (0x2<<8)
+#define PS_CFG_PFIFO_ACCESS_WID_32 (0x3<<8)
+#define PS_CFG_MAX_FETCH_CYCLE_BIT 0
+#define PS_CFG_MAX_FETCH_CYCLE_MASK 0xff
+
+#define PARSER_INT_DISABLE_CNT_MASK 0xffff
+#define PARSER_INT_DISABLE_CNT_BIT 16
+#define PARSER_INT_HOST_EN_MASK 0xff
+#define PARSER_INT_HOST_EN_BIT 8
+#define PARSER_INT_AMRISC_EN_MASK 0xff
+#define PARSER_INT_AMRISC_EN_BIT 0
+#define PARSER_INT_ALL 0xff
+
+#define RESET_PARSER (1<<8)
+#define TS_HIU_ENABLE 5
+#define USE_HI_BSF_INTERFACE 7
+
+#endif /* PSPARSER_H */
diff --git a/drivers/stream_input/parser/rmparser.c b/drivers/stream_input/parser/rmparser.c
new file mode 100644
index 0000000..902dc5a
--- /dev/null
+++ b/drivers/stream_input/parser/rmparser.c
@@ -0,0 +1,340 @@
+/*
+ * drivers/amlogic/amports/rmparser.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/sched.h>
+#include <linux/fs.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/amlogic/media/utils/amstream.h>
+#include <linux/amlogic/media/frame_sync/ptsserv.h>
+#include <linux/uaccess.h>
+
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "../amports/amports_priv.h"
+#include "../amports/streambuf.h"
+#include "../amports/streambuf_reg.h"
+#include <linux/delay.h>
+#include "rmparser.h"
+
+#define MANAGE_PTS
+
+static u32 fetch_done;
+static u32 parse_halt;
+
+static DECLARE_WAIT_QUEUE_HEAD(rm_wq);
+static const char rmparser_id[] = "rmparser-id";
+
+static irqreturn_t rm_parser_isr(int irq, void *dev_id)
+{
+ u32 int_status = READ_PARSER_REG(PARSER_INT_STATUS);
+
+ if (int_status & PARSER_INTSTAT_FETCH_CMD) {
+ WRITE_PARSER_REG(PARSER_INT_STATUS, PARSER_INTSTAT_FETCH_CMD);
+ fetch_done = 1;
+
+ wake_up_interruptible(&rm_wq);
+ }
+
+ return IRQ_HANDLED;
+}
+
+s32 rmparser_init(struct vdec_s *vdec)
+{
+ s32 r;
+
+ parse_halt = 0;
+ if (fetchbuf == 0) {
+ pr_info("%s: no fetchbuf\n", __func__);
+ return -ENOMEM;
+ }
+
+ WRITE_RESET_REG(RESET1_REGISTER, RESET_PARSER);
+
+/* for recorded file and local play, this can't change the input source*/
+ /* TS data path */
+/*
+#ifndef CONFIG_AM_DVB
+ WRITE_DEMUX_REG(FEC_INPUT_CONTROL, 0);
+#else
+ tsdemux_set_reset_flag();
+#endif */
+
+ CLEAR_DEMUX_REG_MASK(TS_HIU_CTL, 1 << USE_HI_BSF_INTERFACE);
+ CLEAR_DEMUX_REG_MASK(TS_HIU_CTL_2, 1 << USE_HI_BSF_INTERFACE);
+ CLEAR_DEMUX_REG_MASK(TS_HIU_CTL_3, 1 << USE_HI_BSF_INTERFACE);
+
+ CLEAR_DEMUX_REG_MASK(TS_FILE_CONFIG, (1 << TS_HIU_ENABLE));
+
+ /* hook stream buffer with PARSER */
+ WRITE_PARSER_REG(PARSER_VIDEO_START_PTR, vdec->input.start);
+ WRITE_PARSER_REG(PARSER_VIDEO_END_PTR,
+ vdec->input.start + vdec->input.size - 8);
+
+ CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL, ES_VID_MAN_RD_PTR);
+
+ WRITE_PARSER_REG(PARSER_AUDIO_START_PTR,
+ READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_PARSER_REG(PARSER_AUDIO_END_PTR,
+ READ_AIU_REG(AIU_MEM_AIFIFO_END_PTR));
+ CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL, ES_AUD_MAN_RD_PTR);
+
+ WRITE_VREG(VLD_MEM_VIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ CLEAR_VREG_MASK(VLD_MEM_VIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+
+ WRITE_AIU_REG(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ CLEAR_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+
+ WRITE_PARSER_REG(PFIFO_RD_PTR, 0);
+ WRITE_PARSER_REG(PFIFO_WR_PTR, 0);
+
+ WRITE_PARSER_REG(PARSER_SEARCH_MASK, 0);
+ WRITE_PARSER_REG(PARSER_CONTROL, (ES_SEARCH | ES_PARSER_START));
+
+#ifdef MANAGE_PTS
+ if (pts_start(PTS_TYPE_VIDEO) < 0)
+ goto Err_1;
+
+ if (pts_start(PTS_TYPE_AUDIO) < 0)
+ goto Err_2;
+#endif
+ /*TODO irq */
+
+ /* enable interrupt */
+
+ r = vdec_request_irq(PARSER_IRQ, rm_parser_isr,
+ "rmparser", (void *)rmparser_id);
+
+ if (r) {
+ pr_info("RM parser irq register failed.\n");
+ goto Err_3;
+ }
+
+ WRITE_PARSER_REG(PARSER_INT_STATUS, 0xffff);
+ WRITE_PARSER_REG(PARSER_INT_ENABLE,
+ ((PARSER_INT_ALL & (~PARSER_INTSTAT_FETCH_CMD)) <<
+ PARSER_INT_AMRISC_EN_BIT)
+ | (PARSER_INTSTAT_FETCH_CMD << PARSER_INT_HOST_EN_BIT));
+
+ return 0;
+
+Err_3:
+ pts_stop(PTS_TYPE_AUDIO);
+Err_2:
+ pts_stop(PTS_TYPE_VIDEO);
+Err_1:
+ return -ENOENT;
+}
+EXPORT_SYMBOL(rmparser_init);
+
+void rmparser_release(void)
+{
+ WRITE_PARSER_REG(PARSER_INT_ENABLE, 0);
+ /*TODO irq */
+
+ vdec_free_irq(PARSER_IRQ, (void *)rmparser_id);
+
+#ifdef MANAGE_PTS
+ pts_stop(PTS_TYPE_VIDEO);
+ pts_stop(PTS_TYPE_AUDIO);
+#endif
+
+}
+EXPORT_SYMBOL(rmparser_release);
+
+static inline u32 buf_wp(u32 type)
+{
+ return (type == BUF_TYPE_VIDEO) ? READ_VREG(VLD_MEM_VIFIFO_WP) :
+ (type == BUF_TYPE_AUDIO) ?
+ READ_AIU_REG(AIU_MEM_AIFIFO_MAN_WP) :
+ READ_PARSER_REG(PARSER_SUB_START_PTR);
+}
+
+static ssize_t _rmparser_write(const char __user *buf, size_t count)
+{
+ size_t r = count;
+ const char __user *p = buf;
+ u32 len;
+ int ret;
+ static int halt_droped_len;
+ u32 vwp, awp;
+ dma_addr_t dma_addr = 0;
+
+ if (r > 0) {
+ len = min_t(size_t, r, FETCHBUF_SIZE);
+
+ if (copy_from_user(fetchbuf, p, len))
+ return -EFAULT;
+ dma_addr =
+ dma_map_single(amports_get_dma_device(),
+ fetchbuf, FETCHBUF_SIZE,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(amports_get_dma_device(), dma_addr))
+ return -EFAULT;
+
+ fetch_done = 0;
+
+ wmb(); /* Ensure fetchbuf contents visible */
+ vwp = buf_wp(BUF_TYPE_VIDEO);
+ awp = buf_wp(BUF_TYPE_AUDIO);
+ WRITE_PARSER_REG(PARSER_FETCH_ADDR, dma_addr);
+
+ WRITE_PARSER_REG(PARSER_FETCH_CMD, (7 << FETCH_ENDIAN) | len);
+ dma_unmap_single(amports_get_dma_device(), dma_addr,
+ FETCHBUF_SIZE, DMA_TO_DEVICE);
+ ret =
+ wait_event_interruptible_timeout(rm_wq, fetch_done != 0,
+ HZ / 10);
+ if (ret == 0) {
+ WRITE_PARSER_REG(PARSER_FETCH_CMD, 0);
+ parse_halt++;
+ pr_info
+ ("write timeout,retry,halt_count=%d parse_control=%x\n",
+ parse_halt, READ_PARSER_REG(PARSER_CONTROL));
+
+ //vreal_set_fatal_flag(1);//DEBUG_TMP
+
+ if (parse_halt > 10) {
+ WRITE_PARSER_REG(PARSER_CONTROL,
+ (ES_SEARCH | ES_PARSER_START));
+ pr_info("reset parse_control=%x\n",
+ READ_PARSER_REG(PARSER_CONTROL));
+ }
+ return -EAGAIN;
+ } else if (ret < 0)
+ return -ERESTARTSYS;
+
+ if (vwp == buf_wp(BUF_TYPE_VIDEO)
+ && awp == buf_wp(BUF_TYPE_AUDIO)) {
+ struct stream_buf_s *v_buf_t =
+ get_buf_by_type(BUF_TYPE_VIDEO);
+ struct stream_buf_s *a_buf_t =
+ get_buf_by_type(BUF_TYPE_AUDIO);
+ int v_st_lv = stbuf_level(v_buf_t);
+ int a_st_lv = stbuf_level(a_buf_t);
+
+ if ((parse_halt + 1) % 10 == 1) {
+ pr_info("V&A WP not changed after write");
+ pr_info(",video %x->%x", vwp,
+ buf_wp(BUF_TYPE_VIDEO));
+ pr_info(",Audio:%x-->%x,parse_halt=%d\n",
+ awp, buf_wp(BUF_TYPE_AUDIO),
+ parse_halt);
+ }
+ parse_halt++;
+
+/* wp not changed ,
+ * we think have bugs on parser now.
+ */
+ if (parse_halt > 10 &&
+ (v_st_lv < 1000 || a_st_lv < 100)) {
+ /*reset while at least one is underflow. */
+ WRITE_PARSER_REG(PARSER_CONTROL,
+ (ES_SEARCH | ES_PARSER_START));
+ pr_info("reset parse_control=%x\n",
+ READ_PARSER_REG(PARSER_CONTROL));
+ }
+ if (parse_halt <= 10 ||
+ halt_droped_len < 100 * 1024) {
+ /*drops first 10 pkt ,
+ * some times maybe no av data
+ */
+ pr_info("drop this pkt=%d,len=%d\n", parse_halt,
+ len);
+ p += len;
+ r -= len;
+ halt_droped_len += len;
+ } else
+ return -EAGAIN;
+ } else {
+ halt_droped_len = 0;
+ parse_halt = 0;
+ p += len;
+ r -= len;
+ }
+ }
+ return count - r;
+}
+
+ssize_t rmparser_write(struct file *file,
+ struct stream_buf_s *vbuf,
+ struct stream_buf_s *abuf,
+ const char __user *buf, size_t count)
+{
+ s32 r;
+ struct port_priv_s *priv = (struct port_priv_s *)file->private_data;
+ struct stream_port_s *port = priv->port;
+ size_t towrite = count;
+
+ if ((stbuf_space(vbuf) < count) || (stbuf_space(abuf) < count)) {
+ if (file->f_flags & O_NONBLOCK) {
+ towrite = min(stbuf_space(vbuf), stbuf_space(abuf));
+ if (towrite < 1024) /*? can write small? */
+ return -EAGAIN;
+ } else {
+ if ((port->flag & PORT_FLAG_VID)
+ && (stbuf_space(vbuf) < count)) {
+ r = stbuf_wait_space(vbuf, count);
+ if (r < 0)
+ return r;
+ }
+ if ((port->flag & PORT_FLAG_AID)
+ && (stbuf_space(abuf) < count)) {
+ r = stbuf_wait_space(abuf, count);
+ if (r < 0)
+ return r;
+ }
+ }
+ }
+ towrite = min(towrite, count);
+ return _rmparser_write(buf, towrite);
+}
+
+void rm_set_vasid(u32 vid, u32 aid)
+{
+ pr_info("rm_set_vasid aid %d, vid %d\n", aid, vid);
+ WRITE_PARSER_REG(VAS_STREAM_ID, (aid << 8) | vid);
+}
+
+void rm_audio_reset(void)
+{
+ ulong flags;
+ DEFINE_SPINLOCK(lock);
+
+ spin_lock_irqsave(&lock, flags);
+
+ WRITE_PARSER_REG(PARSER_AUDIO_WP,
+ READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_PARSER_REG(PARSER_AUDIO_RP,
+ READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
+
+ WRITE_PARSER_REG(PARSER_AUDIO_START_PTR,
+ READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_PARSER_REG(PARSER_AUDIO_END_PTR,
+ READ_AIU_REG(AIU_MEM_AIFIFO_END_PTR));
+ CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL, ES_AUD_MAN_RD_PTR);
+
+ WRITE_AIU_REG(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ CLEAR_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+
+ spin_unlock_irqrestore(&lock, flags);
+}
+EXPORT_SYMBOL(rm_audio_reset);
diff --git a/drivers/stream_input/parser/rmparser.h b/drivers/stream_input/parser/rmparser.h
new file mode 100644
index 0000000..eb2023a
--- /dev/null
+++ b/drivers/stream_input/parser/rmparser.h
@@ -0,0 +1,136 @@
+/*
+ * drivers/amlogic/amports/rmparser.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 RMPARSER_H
+#define RMPARSER_H
+
+#include "../../frame_provider/decoder/utils/vdec.h"
+
+extern void rm_set_vasid(u32 vid, u32 aid);
+
+extern ssize_t rmparser_write(struct file *file,
+ struct stream_buf_s *vbuf,
+ struct stream_buf_s *abuf,
+ const char __user *buf, size_t count);
+
+s32 rmparser_init(struct vdec_s *vdec);
+
+extern void rmparser_release(void);
+
+extern void rm_audio_reset(void);
+
+extern void vreal_set_fatal_flag(int flag);
+
+#ifdef CONFIG_AM_DVB
+extern int tsdemux_set_reset_flag(void);
+#endif
+
+/* TODO: move to register headers */
+#define ES_PACK_SIZE_BIT 8
+#define ES_PACK_SIZE_WID 24
+
+#define ES_CTRL_WID 8
+#define ES_CTRL_BIT 0
+#define ES_TYPE_MASK (3 << 6)
+#define ES_TYPE_VIDEO (0 << 6)
+#define ES_TYPE_AUDIO (1 << 6)
+#define ES_TYPE_SUBTITLE (2 << 6)
+
+#define ES_WRITE (1<<5)
+#define ES_PASSTHROUGH (1<<4)
+#define ES_INSERT_BEFORE_ES_WRITE (1<<3)
+#define ES_DISCARD (1<<2)
+#define ES_SEARCH (1<<1)
+#define ES_PARSER_START (1<<0)
+#define ES_PARSER_BUSY (1<<0)
+
+#define PARSER_INTSTAT_FETCH_CMD (1<<7)
+#define PARSER_INTSTAT_PARSE (1<<4)
+#define PARSER_INTSTAT_DISCARD (1<<3)
+#define PARSER_INTSTAT_INSZERO (1<<2)
+#define PARSER_INTSTAT_ACT_NOSSC (1<<1)
+#define PARSER_INTSTAT_SC_FOUND (1<<0)
+
+#define FETCH_CIR_BUF (1<<31)
+#define FETCH_CHK_BUF_STOP (1<<30)
+#define FETCH_PASSTHROUGH (1<<29)
+#define FETCH_ENDIAN 27
+#define FETCH_PASSTHROUGH_TYPE_MASK (0x3<<27)
+#define FETCH_ENDIAN_MASK (0x7<<27)
+#define FETCH_BUF_SIZE_MASK (0x7ffffff)
+#define FETCH_CMD_PTR_MASK 3
+#define FETCH_CMD_RD_PTR_BIT 5
+#define FETCH_CMD_WR_PTR_BIT 3
+#define FETCH_CMD_NUM_MASK 3
+#define FETCH_CMD_NUM_BIT 0
+
+#define ES_COUNT_MASK 0xfff
+#define ES_COUNT_BIT 20
+#define ES_REQ_PENDING (1<<19)
+#define ES_PASSTHROUGH_EN (1<<18)
+#define ES_PASSTHROUGH_TYPE_MASK (3<<16)
+#define ES_PASSTHROUGH_TYPE_VIDEO (0<<16)
+#define ES_PASSTHROUGH_TYPE_AUDIO (1<<16)
+#define ES_PASSTHROUGH_TYPE_SUBTITLE (2<<16)
+#define ES_WR_ENDIAN_MASK (0x7)
+#define ES_SUB_WR_ENDIAN_BIT 9
+#define ES_SUB_MAN_RD_PTR (1<<8)
+#define ES_AUD_WR_ENDIAN_BIT 5
+#define ES_AUD_MAN_RD_PTR (1<<4)
+#define ES_VID_WR_ENDIAN_BIT 1
+#define ES_VID_MAN_RD_PTR (1<<0)
+
+#define PS_CFG_FETCH_DMA_URGENT (1<<31)
+#define PS_CFG_STREAM_DMA_URGENT (1<<30)
+#define PS_CFG_FORCE_PFIFO_REN (1<<29)
+#define PS_CFG_PFIFO_PEAK_EN (1<<28)
+#define PS_CFG_SRC_SEL_BIT 24
+#define PS_CFG_SRC_SEL_MASK (3<<PS_CFG_SRC_SEL_BIT)
+#define PS_CFG_SRC_SEL_FETCH (0<<PS_CFG_SRC_SEL_BIT)
+#define PS_CFG_SRC_SEL_AUX1 (1<<PS_CFG_SRC_SEL_BIT) /* from NDMA */
+#define PS_CFG_SRC_SEL_AUX2 (2<<PS_CFG_SRC_SEL_BIT)
+#define PS_CFG_SRC_SEL_AUX3 (3<<PS_CFG_SRC_SEL_BIT)
+#define PS_CFG_PFIFO_EMPTY_CNT_BIT 16
+#define PS_CFG_PFIFO_EMPTY_CNT_MASK 0xff
+#define PS_CFG_MAX_ES_WR_CYCLE_BIT 12
+#define PS_CFG_MAX_ES_WR_CYCLE_MASK 0xf
+#define PS_CFG_STARTCODE_WID_MASK (0x3<<10)
+#define PS_CFG_STARTCODE_WID_8 (0x0<<10)
+#define PS_CFG_STARTCODE_WID_16 (0x1<<10)
+#define PS_CFG_STARTCODE_WID_24 (0x2<<10)
+#define PS_CFG_STARTCODE_WID_32 (0x3<<10)
+#define PS_CFG_PFIFO_ACCESS_WID_MASK (0x3<<8)
+#define PS_CFG_PFIFO_ACCESS_WID_8 (0x0<<8)
+#define PS_CFG_PFIFO_ACCESS_WID_16 (0x1<<8)
+#define PS_CFG_PFIFO_ACCESS_WID_24 (0x2<<8)
+#define PS_CFG_PFIFO_ACCESS_WID_32 (0x3<<8)
+#define PS_CFG_MAX_FETCH_CYCLE_BIT 0
+#define PS_CFG_MAX_FETCH_CYCLE_MASK 0xff
+
+#define PARSER_INT_DISABLE_CNT_MASK 0xffff
+#define PARSER_INT_DISABLE_CNT_BIT 16
+#define PARSER_INT_HOST_EN_MASK 0xff
+#define PARSER_INT_HOST_EN_BIT 8
+#define PARSER_INT_AMRISC_EN_MASK 0xff
+#define PARSER_INT_AMRISC_EN_BIT 0
+#define PARSER_INT_ALL 0xff
+
+#define RESET_PARSER (1<<8)
+#define TS_HIU_ENABLE 5
+#define USE_HI_BSF_INTERFACE 7
+
+#endif /* RMPARSER_H */
diff --git a/drivers/stream_input/parser/tsdemux.c b/drivers/stream_input/parser/tsdemux.c
new file mode 100644
index 0000000..7d5788e
--- /dev/null
+++ b/drivers/stream_input/parser/tsdemux.c
@@ -0,0 +1,1313 @@
+/*
+ * drivers/amlogic/media/stream_input/parser/tsdemux.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/types.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/dma-mapping.h>
+#include <linux/amlogic/media/frame_sync/ptsserv.h>
+#include <linux/amlogic/media/frame_sync/tsync.h>
+#include <linux/amlogic/media/utils/amstream.h>
+#include <linux/amlogic/media/vfm/vframe_provider.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+
+#include <linux/uaccess.h>
+/* #include <mach/am_regs.h> */
+#include <linux/clk.h>
+/* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+/* #include <mach/mod_gate.h> */
+/* #endif */
+
+#include "../../frame_provider/decoder/utils/vdec.h"
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "../amports/streambuf_reg.h"
+#include "../amports/streambuf.h"
+#include <linux/amlogic/media/utils/amports_config.h>
+#include <linux/amlogic/media/frame_sync/tsync_pcr.h>
+
+#include "tsdemux.h"
+#include <linux/reset.h>
+#include "../amports/amports_priv.h"
+
+#define MAX_DRM_PACKAGE_SIZE 0x500000
+
+
+static const char tsdemux_fetch_id[] = "tsdemux-fetch-id";
+static const char tsdemux_irq_id[] = "tsdemux-irq-id";
+
+static u32 curr_pcr_num = 0xffff;
+static u32 curr_vid_id = 0xffff;
+static u32 curr_aud_id = 0xffff;
+static u32 curr_sub_id = 0xffff;
+static u32 curr_pcr_id = 0xffff;
+
+static DECLARE_WAIT_QUEUE_HEAD(wq);
+static u32 fetch_done;
+static u32 discontinued_counter;
+static u32 first_pcr;
+static u8 pcrscr_valid;
+static u8 pcraudio_valid;
+static u8 pcrvideo_valid;
+static u8 pcr_init_flag;
+
+static int demux_skipbyte;
+
+static struct tsdemux_ops *demux_ops;
+static DEFINE_SPINLOCK(demux_ops_lock);
+
+static int enable_demux_driver(void)
+{
+ return demux_ops ? 1 : 0;
+}
+
+void tsdemux_set_ops(struct tsdemux_ops *ops)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&demux_ops_lock, flags);
+ demux_ops = ops;
+ spin_unlock_irqrestore(&demux_ops_lock, flags);
+}
+EXPORT_SYMBOL(tsdemux_set_ops);
+
+int tsdemux_set_reset_flag_ext(void)
+{
+ int r = 0;
+
+ if (demux_ops && demux_ops->set_reset_flag)
+ r = demux_ops->set_reset_flag();
+
+ return r;
+}
+
+int tsdemux_set_reset_flag(void)
+{
+ unsigned long flags;
+ int r;
+
+ spin_lock_irqsave(&demux_ops_lock, flags);
+ r = tsdemux_set_reset_flag_ext();
+ spin_unlock_irqrestore(&demux_ops_lock, flags);
+
+ return r;
+}
+
+static int tsdemux_reset(void)
+{
+ unsigned long flags;
+ int r = 0;
+
+ spin_lock_irqsave(&demux_ops_lock, flags);
+ if (demux_ops && demux_ops->reset) {
+ tsdemux_set_reset_flag_ext();
+ r = demux_ops->reset();
+ }
+ spin_unlock_irqrestore(&demux_ops_lock, flags);
+
+ return r;
+}
+
+static int tsdemux_request_irq(irq_handler_t handler, void *data)
+{
+ unsigned long flags;
+ int r = 0;
+
+ spin_lock_irqsave(&demux_ops_lock, flags);
+ if (demux_ops && demux_ops->request_irq)
+ r = demux_ops->request_irq(handler, data);
+ spin_unlock_irqrestore(&demux_ops_lock, flags);
+
+ return r;
+}
+
+static int tsdemux_free_irq(void)
+{
+ unsigned long flags;
+ int r = 0;
+
+ spin_lock_irqsave(&demux_ops_lock, flags);
+ if (demux_ops && demux_ops->free_irq)
+ r = demux_ops->free_irq();
+ spin_unlock_irqrestore(&demux_ops_lock, flags);
+
+ return r;
+}
+
+static int tsdemux_set_vid(int vpid)
+{
+ unsigned long flags;
+ int r = 0;
+
+ spin_lock_irqsave(&demux_ops_lock, flags);
+ if (demux_ops && demux_ops->set_vid)
+ r = demux_ops->set_vid(vpid);
+ spin_unlock_irqrestore(&demux_ops_lock, flags);
+
+ return r;
+}
+
+static int tsdemux_set_aid(int apid)
+{
+ unsigned long flags;
+ int r = 0;
+
+ spin_lock_irqsave(&demux_ops_lock, flags);
+ if (demux_ops && demux_ops->set_aid)
+ r = demux_ops->set_aid(apid);
+ spin_unlock_irqrestore(&demux_ops_lock, flags);
+
+ return r;
+}
+
+static int tsdemux_set_sid(int spid)
+{
+ unsigned long flags;
+ int r = 0;
+
+ spin_lock_irqsave(&demux_ops_lock, flags);
+ if (demux_ops && demux_ops->set_sid)
+ r = demux_ops->set_sid(spid);
+ spin_unlock_irqrestore(&demux_ops_lock, flags);
+
+ return r;
+}
+
+static int tsdemux_set_pcrid(int pcrpid)
+{
+ unsigned long flags;
+ int r = 0;
+
+ spin_lock_irqsave(&demux_ops_lock, flags);
+ if (demux_ops && demux_ops->set_pcrid)
+ r = demux_ops->set_pcrid(pcrpid);
+ spin_unlock_irqrestore(&demux_ops_lock, flags);
+
+ return r;
+}
+
+static int tsdemux_set_skip_byte(int skipbyte)
+{
+ unsigned long flags;
+ int r = 0;
+
+ spin_lock_irqsave(&demux_ops_lock, flags);
+ if (demux_ops && demux_ops->set_skipbyte)
+ r = demux_ops->set_skipbyte(skipbyte);
+ spin_unlock_irqrestore(&demux_ops_lock, flags);
+
+ return r;
+}
+
+static int tsdemux_config(void)
+{
+ return 0;
+}
+
+static void tsdemux_pcr_set(unsigned int pcr);
+/*TODO irq*/
+/* bit 15 ---------------*/
+/* bit 12 --VIDEO_PTS[32]*/
+/* bit 0 ---------------*/
+/*Read the 13th bit of STB_PTS_DTS_STATUS register
+correspond to the highest bit of video pts*/
+static irqreturn_t tsdemux_isr(int irq, void *dev_id)
+{
+ u32 int_status = 0;
+ int id = (long)dev_id;
+
+ if (!enable_demux_driver()) {
+ int_status = READ_DEMUX_REG(STB_INT_STATUS);
+ } else {
+ if (id == 0)
+ int_status = READ_DEMUX_REG(STB_INT_STATUS);
+ else if (id == 1)
+ int_status = READ_DEMUX_REG(STB_INT_STATUS_2);
+ else if (id == 2)
+ int_status = READ_DEMUX_REG(STB_INT_STATUS_3);
+ }
+
+ if (int_status & (1 << NEW_PDTS_READY)) {
+ if (!enable_demux_driver()) {
+ u32 pdts_status = READ_DEMUX_REG(STB_PTS_DTS_STATUS);
+ u64 vpts;
+
+ vpts = READ_MPEG_REG(VIDEO_PTS_DEMUX);
+ vpts &= 0x00000000FFFFFFFF;
+ if (pdts_status & 0x1000) {
+ vpts = vpts | (1LL<<32);
+ }
+
+ if (pdts_status & (1 << VIDEO_PTS_READY))
+ pts_checkin_wrptr_pts33(PTS_TYPE_VIDEO,
+ READ_DEMUX_REG(VIDEO_PDTS_WR_PTR),
+ vpts);
+
+ if (pdts_status & (1 << AUDIO_PTS_READY))
+ pts_checkin_wrptr(PTS_TYPE_AUDIO,
+ READ_DEMUX_REG(AUDIO_PDTS_WR_PTR),
+ READ_DEMUX_REG(AUDIO_PTS_DEMUX));
+
+ WRITE_DEMUX_REG(STB_PTS_DTS_STATUS, pdts_status);
+ } else {
+#define DMX_READ_REG(i, r)\
+ ((i) ? ((i == 1) ? READ_DEMUX_REG(r##_2) : \
+ READ_DEMUX_REG(r##_3)) : READ_DEMUX_REG(r))
+ u64 vpts;
+ u32 pdts_status = DMX_READ_REG(id, STB_PTS_DTS_STATUS);
+ vpts = DMX_READ_REG(id, VIDEO_PTS_DEMUX);
+ vpts &= 0x00000000FFFFFFFF;
+ if (pdts_status & 0x1000) {
+ vpts = vpts | (1LL<<32);
+ }
+
+ if (pdts_status & (1 << VIDEO_PTS_READY))
+ pts_checkin_wrptr_pts33(PTS_TYPE_VIDEO,
+ DMX_READ_REG(id, VIDEO_PDTS_WR_PTR),
+ vpts);
+
+ if (pdts_status & (1 << AUDIO_PTS_READY))
+ pts_checkin_wrptr(PTS_TYPE_AUDIO,
+ DMX_READ_REG(id, AUDIO_PDTS_WR_PTR),
+ DMX_READ_REG(id, AUDIO_PTS_DEMUX));
+
+ if (id == 1)
+ WRITE_DEMUX_REG(STB_PTS_DTS_STATUS_2,
+ pdts_status);
+ else if (id == 2)
+ WRITE_DEMUX_REG(STB_PTS_DTS_STATUS_3,
+ pdts_status);
+ else
+ WRITE_DEMUX_REG(STB_PTS_DTS_STATUS,
+ pdts_status);
+ }
+ }
+ if (int_status & (1 << DIS_CONTINUITY_PACKET)) {
+ discontinued_counter++;
+ /* pr_info("discontinued counter=%d\n",discontinued_counter); */
+ }
+ if (int_status & (1 << SUB_PES_READY)) {
+ /* TODO: put data to somewhere */
+ /* pr_info("subtitle pes ready\n"); */
+ wakeup_sub_poll();
+ }
+ if (int_status & (1<<PCR_READY)) {
+ unsigned int pcr_pts = 0xffffffff;
+ pcr_pts = DMX_READ_REG(id, PCR_DEMUX);
+ tsdemux_pcr_set(pcr_pts);
+ }
+
+ if (!enable_demux_driver())
+ WRITE_DEMUX_REG(STB_INT_STATUS, int_status);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t parser_isr(int irq, void *dev_id)
+{
+ u32 int_status = READ_PARSER_REG(PARSER_INT_STATUS);
+
+ WRITE_PARSER_REG(PARSER_INT_STATUS, int_status);
+
+ if (int_status & PARSER_INTSTAT_FETCH_CMD) {
+ fetch_done = 1;
+
+ wake_up_interruptible(&wq);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static ssize_t _tsdemux_write(const char __user *buf, size_t count,
+ int isphybuf)
+{
+ size_t r = count;
+ const char __user *p = buf;
+ u32 len;
+ int ret;
+ dma_addr_t dma_addr = 0;
+
+ if (r > 0) {
+ if (isphybuf)
+ len = count;
+ else {
+ len = min_t(size_t, r, FETCHBUF_SIZE);
+ if (copy_from_user(fetchbuf, p, len))
+ return -EFAULT;
+
+ dma_addr =
+ dma_map_single(amports_get_dma_device(),
+ fetchbuf,
+ FETCHBUF_SIZE, DMA_TO_DEVICE);
+ if (dma_mapping_error(amports_get_dma_device(),
+ dma_addr))
+ return -EFAULT;
+
+
+ }
+
+ fetch_done = 0;
+
+ wmb(); /* Ensure fetchbuf contents visible */
+
+ if (isphybuf) {
+ u32 buf_32 = (unsigned long)buf & 0xffffffff;
+ WRITE_PARSER_REG(PARSER_FETCH_ADDR, buf_32);
+ } else {
+ WRITE_PARSER_REG(PARSER_FETCH_ADDR, dma_addr);
+ dma_unmap_single(amports_get_dma_device(), dma_addr,
+ FETCHBUF_SIZE, DMA_TO_DEVICE);
+ }
+
+ WRITE_PARSER_REG(PARSER_FETCH_CMD, (7 << FETCH_ENDIAN) | len);
+
+
+ ret =
+ wait_event_interruptible_timeout(wq, fetch_done != 0,
+ HZ / 2);
+ if (ret == 0) {
+ WRITE_PARSER_REG(PARSER_FETCH_CMD, 0);
+ pr_info("write timeout, retry\n");
+ return -EAGAIN;
+ } else if (ret < 0)
+ return -ERESTARTSYS;
+
+ p += len;
+ r -= len;
+ }
+
+ return count - r;
+}
+
+#define PCR_EN 12
+
+static int reset_pcr_regs(void)
+{
+ u32 pcr_num;
+ u32 pcr_regs = 0;
+
+ if (curr_pcr_id >= 0x1FFF)
+ return 0;
+ /* set paramater to fetch pcr */
+ pcr_num = 0;
+ if (curr_pcr_id == curr_vid_id)
+ pcr_num = 0;
+ else if (curr_pcr_id == curr_aud_id)
+ pcr_num = 1;
+ else if (curr_pcr_id == curr_sub_id)
+ pcr_num = 2;
+ else
+ pcr_num = 3;
+ if (pcr_num != curr_pcr_num) {
+ u32 clk_unit = 0;
+ u32 clk_81 = 0;
+ struct clk *clk;
+ //clk = clk_get(NULL,"clk81");
+ clk= devm_clk_get(amports_get_dma_device(),"clk_81");
+ if (IS_ERR(clk) || clk == 0) {
+ pr_info("[%s:%d] error clock\n", __func__, __LINE__);
+ return 0;
+ }
+ clk_81 = clk_get_rate(clk);
+ clk_unit = clk_81 / 90000;
+ pr_info("[%s:%d] clk_81 = %x clk_unit =%x\n", __func__,
+ __LINE__, clk_81, clk_unit);
+ pcr_regs = 1 << PCR_EN | clk_unit;
+ pr_info("[tsdemux_init] the set pcr_regs =%x\n", pcr_regs);
+ if (READ_DEMUX_REG(TS_HIU_CTL_2) & 0x80) {
+ WRITE_DEMUX_REG(PCR90K_CTL_2, pcr_regs);
+ WRITE_DEMUX_REG(ASSIGN_PID_NUMBER_2, pcr_num);
+ pr_info("[tsdemux_init] To use device 2,pcr_num=%d\n",
+ pcr_num);
+ pr_info("tsdemux_init] the read pcr_regs= %x\n",
+ READ_DEMUX_REG(PCR90K_CTL_2));
+ } else if (READ_DEMUX_REG(TS_HIU_CTL_3) & 0x80) {
+ WRITE_DEMUX_REG(PCR90K_CTL_3, pcr_regs);
+ WRITE_DEMUX_REG(ASSIGN_PID_NUMBER_3, pcr_num);
+ pr_info("[tsdemux_init] To use device 3,pcr_num=%d\n",
+ pcr_num);
+ pr_info("tsdemux_init] the read pcr_regs= %x\n",
+ READ_DEMUX_REG(PCR90K_CTL_3));
+ } else {
+ WRITE_DEMUX_REG(PCR90K_CTL, pcr_regs);
+ WRITE_DEMUX_REG(ASSIGN_PID_NUMBER, pcr_num);
+ pr_info("[tsdemux_init] To use device 1,pcr_num=%d\n",
+ pcr_num);
+ pr_info("tsdemux_init] the read pcr_regs= %x\n",
+ READ_DEMUX_REG(PCR90K_CTL));
+ }
+ curr_pcr_num = pcr_num;
+ }
+ return 1;
+}
+
+s32 tsdemux_init(u32 vid, u32 aid, u32 sid, u32 pcrid, bool is_hevc,
+ struct vdec_s *vdec)
+{
+ s32 r;
+ u32 parser_sub_start_ptr;
+ u32 parser_sub_end_ptr;
+ u32 parser_sub_rp;
+ pcrvideo_valid = 0;
+ pcraudio_valid = 0;
+ pcr_init_flag = 0;
+
+ /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+ /*TODO clk */
+ /*
+ *switch_mod_gate_by_type(MOD_DEMUX, 1);
+ */
+ /* #endif */
+
+ amports_switch_gate("demux", 1);
+
+ parser_sub_start_ptr = READ_PARSER_REG(PARSER_SUB_START_PTR);
+ parser_sub_end_ptr = READ_PARSER_REG(PARSER_SUB_END_PTR);
+ parser_sub_rp = READ_PARSER_REG(PARSER_SUB_RP);
+
+ WRITE_RESET_REG(RESET1_REGISTER, RESET_PARSER);
+
+ if (enable_demux_driver()) {
+ tsdemux_reset();
+ } else {
+ WRITE_RESET_REG(RESET1_REGISTER, RESET_PARSER | RESET_DEMUXSTB);
+
+ WRITE_DEMUX_REG(STB_TOP_CONFIG, 0);
+ WRITE_DEMUX_REG(DEMUX_CONTROL, 0);
+ }
+
+ /* set PID filter */
+ pr_info
+ ("tsdemux video_pid = 0x%x, audio_pid = 0x%x,",
+ vid, aid);
+ pr_info
+ ("sub_pid = 0x%x, pcrid = 0x%x\n",
+ sid, pcrid);
+
+ if (!enable_demux_driver()) {
+ WRITE_DEMUX_REG(FM_WR_DATA,
+ (((vid < 0x1fff)
+ ? (vid & 0x1fff) | (VIDEO_PACKET << 13)
+ : 0xffff) << 16)
+ | ((aid < 0x1fff)
+ ? (aid & 0x1fff) | (AUDIO_PACKET << 13)
+ : 0xffff));
+ WRITE_DEMUX_REG(FM_WR_ADDR, 0x8000);
+ while (READ_DEMUX_REG(FM_WR_ADDR) & 0x8000)
+ ;
+
+ WRITE_DEMUX_REG(FM_WR_DATA,
+ (((sid < 0x1fff)
+ ? (sid & 0x1fff) | (SUB_PACKET << 13)
+ : 0xffff) << 16)
+ | 0xffff);
+ WRITE_DEMUX_REG(FM_WR_ADDR, 0x8001);
+ while (READ_DEMUX_REG(FM_WR_ADDR) & 0x8000)
+ ;
+
+ WRITE_DEMUX_REG(MAX_FM_COMP_ADDR, 1);
+
+ WRITE_DEMUX_REG(STB_INT_MASK, 0);
+ WRITE_DEMUX_REG(STB_INT_STATUS, 0xffff);
+
+ /* TS data path */
+ WRITE_DEMUX_REG(FEC_INPUT_CONTROL, 0x7000);
+ WRITE_DEMUX_REG(DEMUX_MEM_REQ_EN,
+ (1 << VIDEO_PACKET) |
+ (1 << AUDIO_PACKET) | (1 << SUB_PACKET));
+ WRITE_DEMUX_REG(DEMUX_ENDIAN,
+ (7 << OTHER_ENDIAN) |
+ (7 << BYPASS_ENDIAN) | (0 << SECTION_ENDIAN));
+ WRITE_DEMUX_REG(TS_HIU_CTL, 1 << USE_HI_BSF_INTERFACE);
+ WRITE_DEMUX_REG(TS_FILE_CONFIG,
+ (demux_skipbyte << 16) |
+ (6 << DES_OUT_DLY) |
+ (3 << TRANSPORT_SCRAMBLING_CONTROL_ODD) |
+ (1 << TS_HIU_ENABLE) | (4 << FEC_FILE_CLK_DIV));
+
+ /* enable TS demux */
+ WRITE_DEMUX_REG(DEMUX_CONTROL,
+ (1 << STB_DEMUX_ENABLE) |
+ (1 << KEEP_DUPLICATE_PACKAGE));
+ }
+
+ if (fetchbuf == 0) {
+ pr_info("%s: no fetchbuf\n", __func__);
+ return -ENOMEM;
+ }
+
+ /* hook stream buffer with PARSER */
+ if (has_hevc_vdec() && is_hevc) {
+ WRITE_PARSER_REG(PARSER_VIDEO_START_PTR, vdec->input.start);
+ WRITE_PARSER_REG(PARSER_VIDEO_END_PTR, vdec->input.start +
+ vdec->input.size - 8);
+
+ if (vdec_single(vdec)) {
+ CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL,
+ ES_VID_MAN_RD_PTR);
+ /* set vififo_vbuf_rp_sel=>hevc */
+ WRITE_VREG(DOS_GEN_CTRL0, 3 << 1);
+ /* set use_parser_vbuf_wp */
+ SET_VREG_MASK(HEVC_STREAM_CONTROL,
+ (1 << 3) | (0 << 4));
+ /* set stream_fetch_enable */
+ SET_VREG_MASK(HEVC_STREAM_CONTROL, 1);
+ /* set stream_buffer_hole with 256 bytes */
+ SET_VREG_MASK(HEVC_STREAM_FIFO_CTL,
+ (1 << 29));
+ } else {
+ SET_PARSER_REG_MASK(PARSER_ES_CONTROL,
+ ES_VID_MAN_RD_PTR);
+ WRITE_PARSER_REG(PARSER_VIDEO_WP, vdec->input.start);
+ WRITE_PARSER_REG(PARSER_VIDEO_RP, vdec->input.start);
+ }
+ } else {
+ WRITE_PARSER_REG(PARSER_VIDEO_START_PTR, vdec->input.start);
+ WRITE_PARSER_REG(PARSER_VIDEO_END_PTR, vdec->input.start +
+ vdec->input.size - 8);
+
+ if (vdec_single(vdec)) {
+ CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL,
+ ES_VID_MAN_RD_PTR);
+
+ WRITE_VREG(VLD_MEM_VIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ CLEAR_VREG_MASK(VLD_MEM_VIFIFO_BUF_CNTL,
+ MEM_BUFCTRL_INIT);
+ /* set vififo_vbuf_rp_sel=>vdec */
+ if (has_hevc_vdec())
+ WRITE_VREG(DOS_GEN_CTRL0, 0);
+ } else {
+ SET_PARSER_REG_MASK(PARSER_ES_CONTROL,
+ ES_VID_MAN_RD_PTR);
+ WRITE_PARSER_REG(PARSER_VIDEO_WP, vdec->input.start);
+ WRITE_PARSER_REG(PARSER_VIDEO_RP, vdec->input.start);
+ }
+ }
+
+ WRITE_PARSER_REG(PARSER_AUDIO_START_PTR,
+ READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_PARSER_REG(PARSER_AUDIO_END_PTR,
+ READ_AIU_REG(AIU_MEM_AIFIFO_END_PTR));
+ CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL, ES_AUD_MAN_RD_PTR);
+
+ WRITE_PARSER_REG(PARSER_CONFIG,
+ (10 << PS_CFG_PFIFO_EMPTY_CNT_BIT) |
+ (1 << PS_CFG_MAX_ES_WR_CYCLE_BIT) |
+ (16 << PS_CFG_MAX_FETCH_CYCLE_BIT));
+
+ WRITE_AIU_REG(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ CLEAR_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+
+ if (!enable_demux_driver() || ((sid > 0) && (sid < 0x1fff))) {
+ WRITE_PARSER_REG(PARSER_SUB_START_PTR, parser_sub_start_ptr);
+ WRITE_PARSER_REG(PARSER_SUB_END_PTR, parser_sub_end_ptr);
+ WRITE_PARSER_REG(PARSER_SUB_RP, parser_sub_rp);
+ }
+ SET_PARSER_REG_MASK(PARSER_ES_CONTROL,
+ (7 << ES_SUB_WR_ENDIAN_BIT) | ES_SUB_MAN_RD_PTR);
+
+ /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
+ if (vid != 0xffff) {
+ if (has_hevc_vdec())
+ r = pts_start((is_hevc) ? PTS_TYPE_HEVC : PTS_TYPE_VIDEO);
+ else
+ /* #endif */
+ r = pts_start(PTS_TYPE_VIDEO);
+ if ((r < 0) && (r != -EBUSY)) {
+ pr_info("Video pts start failed.(%d)\n", r);
+ goto err1;
+ }
+ }
+
+ if (aid != 0xffff) {
+ r = pts_start(PTS_TYPE_AUDIO);
+ if ((r < 0) && (r != -EBUSY)) {
+ pr_info("Audio pts start failed.(%d)\n", r);
+ goto err2;
+ }
+ }
+ /*TODO irq */
+
+ r = vdec_request_irq(PARSER_IRQ, parser_isr,
+ "tsdemux-fetch", (void *)tsdemux_fetch_id);
+
+ if (r)
+ goto err3;
+
+ WRITE_PARSER_REG(PARSER_INT_STATUS, 0xffff);
+ WRITE_PARSER_REG(PARSER_INT_ENABLE,
+ PARSER_INTSTAT_FETCH_CMD << PARSER_INT_HOST_EN_BIT);
+
+ WRITE_PARSER_REG(PARSER_VIDEO_HOLE, 0x400);
+ WRITE_PARSER_REG(PARSER_AUDIO_HOLE, 0x400);
+
+ discontinued_counter = 0;
+
+ if (!enable_demux_driver()) {
+ /*TODO irq */
+
+ r = vdec_request_irq(DEMUX_IRQ, tsdemux_isr,
+ "tsdemux-irq", (void *)tsdemux_irq_id);
+
+ WRITE_DEMUX_REG(STB_INT_MASK, (1 << SUB_PES_READY)
+ | (1 << NEW_PDTS_READY)
+ | (1 << DIS_CONTINUITY_PACKET));
+ if (r)
+ goto err4;
+ } else {
+ tsdemux_config();
+ tsdemux_request_irq(tsdemux_isr, (void *)tsdemux_irq_id);
+ if (vid < 0x1FFF) {
+ curr_vid_id = vid;
+ tsdemux_set_vid(vid);
+ pcrvideo_valid = 1;
+ }
+ if (aid < 0x1FFF) {
+ curr_aud_id = aid;
+ tsdemux_set_aid(aid);
+ pcraudio_valid = 1;
+ }
+ if (sid < 0x1FFF) {
+ curr_sub_id = sid;
+ tsdemux_set_sid(sid);
+ }
+
+ curr_pcr_id = pcrid;
+ pcrscr_valid = reset_pcr_regs();
+
+ if ((pcrid < 0x1FFF) && (pcrid != vid) && (pcrid != aid)
+ && (pcrid != sid))
+ tsdemux_set_pcrid(pcrid);
+ }
+
+ first_pcr = 0;
+
+ return 0;
+
+err4:
+ /*TODO irq */
+
+ if (!enable_demux_driver())
+ vdec_free_irq(PARSER_IRQ, (void *)tsdemux_fetch_id);
+
+err3:
+ pts_stop(PTS_TYPE_AUDIO);
+err2:
+ /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
+ if (has_hevc_vdec())
+ pts_stop((is_hevc) ? PTS_TYPE_HEVC : PTS_TYPE_VIDEO);
+ else
+ /* #endif */
+ pts_stop(PTS_TYPE_VIDEO);
+err1:
+ pr_info("TS Demux init failed.\n");
+ return -ENOENT;
+}
+
+void tsdemux_release(void)
+{
+ pcrscr_valid = 0;
+ first_pcr = 0;
+ pcr_init_flag = 0;
+
+ WRITE_PARSER_REG(PARSER_INT_ENABLE, 0);
+ WRITE_PARSER_REG(PARSER_VIDEO_HOLE, 0);
+ WRITE_PARSER_REG(PARSER_AUDIO_HOLE, 0);
+
+ /*TODO irq */
+
+ vdec_free_irq(PARSER_IRQ, (void *)tsdemux_fetch_id);
+
+ if (!enable_demux_driver()) {
+ WRITE_DEMUX_REG(STB_INT_MASK, 0);
+ /*TODO irq */
+
+ vdec_free_irq(DEMUX_IRQ, (void *)tsdemux_irq_id);
+ } else {
+
+ tsdemux_set_aid(0xffff);
+ tsdemux_set_vid(0xffff);
+ tsdemux_set_sid(0xffff);
+ tsdemux_set_pcrid(0xffff);
+ tsdemux_free_irq();
+
+ curr_vid_id = 0xffff;
+ curr_aud_id = 0xffff;
+ curr_sub_id = 0xffff;
+ curr_pcr_id = 0xffff;
+ curr_pcr_num = 0xffff;
+ }
+
+ pts_stop(PTS_TYPE_VIDEO);
+ pts_stop(PTS_TYPE_AUDIO);
+
+ WRITE_RESET_REG(RESET1_REGISTER, RESET_PARSER);
+#ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
+ SET_PARSER_REG_MASK(PARSER_ES_CONTROL, ES_VID_MAN_RD_PTR);
+ WRITE_PARSER_REG(PARSER_VIDEO_WP, 0);
+ WRITE_PARSER_REG(PARSER_VIDEO_RP, 0);
+#endif
+
+ /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+ /*TODO clk */
+ /*
+ *switch_mod_gate_by_type(MOD_DEMUX, 0);
+ */
+ /* #endif */
+ amports_switch_gate("demux", 0);
+
+}
+EXPORT_SYMBOL(tsdemux_release);
+
+static int limited_delay_check(struct file *file,
+ struct stream_buf_s *vbuf,
+ struct stream_buf_s *abuf,
+ const char __user *buf, size_t count)
+{
+ struct port_priv_s *priv = (struct port_priv_s *)file->private_data;
+ struct stream_port_s *port = priv->port;
+ int write_size;
+
+ if (!((port->flag & PORT_FLAG_VID) &&
+ (port->flag & PORT_FLAG_AID))) {
+ struct stream_buf_s *buf =
+ (port->flag & PORT_FLAG_VID) ? vbuf : abuf;
+
+ return min_t(int, count, stbuf_space(buf));
+ }
+
+ if (vbuf->max_buffer_delay_ms > 0 && abuf->max_buffer_delay_ms > 0 &&
+ stbuf_level(vbuf) > 1024 && stbuf_level(abuf) > 256) {
+ int vdelay =
+ calculation_stream_delayed_ms(PTS_TYPE_VIDEO,
+ NULL, NULL);
+ int adelay =
+ calculation_stream_delayed_ms(PTS_TYPE_AUDIO,
+ NULL, NULL);
+ /*max wait 100ms,if timeout,try again top level. */
+ int maxretry = 10;
+ /*too big delay,do wait now. */
+ /*if noblock mode,don't do wait. */
+ if (!(file->f_flags & O_NONBLOCK)) {
+ while (vdelay > vbuf->max_buffer_delay_ms
+ && adelay > abuf->max_buffer_delay_ms
+ && maxretry-- > 0) {
+ msleep(20);
+ vdelay =
+ calculation_stream_delayed_ms
+ (PTS_TYPE_VIDEO, NULL, NULL);
+ adelay =
+ calculation_stream_delayed_ms
+ (PTS_TYPE_AUDIO, NULL, NULL);
+ }
+ }
+ if (vdelay > vbuf->max_buffer_delay_ms
+ && adelay > abuf->max_buffer_delay_ms)
+ return 0;
+ }
+ write_size = min(stbuf_space(vbuf), stbuf_space(abuf));
+ write_size = min_t(int, count, write_size);
+ return write_size;
+}
+
+ssize_t drm_tswrite(struct file *file,
+ struct stream_buf_s *vbuf,
+ struct stream_buf_s *abuf,
+ const char __user *buf, size_t count)
+{
+ s32 r;
+ u32 realcount = count;
+ u32 havewritebytes = 0;
+
+ struct drm_info tmpmm;
+ struct drm_info *drm = &tmpmm;
+ u32 res = 0;
+ int isphybuf = 0;
+ unsigned long realbuf;
+
+ struct port_priv_s *priv = (struct port_priv_s *)file->private_data;
+ struct stream_port_s *port = priv->port;
+ size_t wait_size, write_size;
+
+ if (buf == NULL || count == 0)
+ return -EINVAL;
+
+ res = copy_from_user(drm, buf, sizeof(struct drm_info));
+ if (res) {
+ pr_info("drm kmalloc failed res[%d]\n", res);
+ return -EFAULT;
+ }
+
+ if (drm->drm_flag == TYPE_DRMINFO && drm->drm_level == DRM_LEVEL1) {
+ /* buf only has drminfo not have esdata; */
+ if (drm->drm_pktsize <= MAX_DRM_PACKAGE_SIZE)
+ realcount = drm->drm_pktsize;
+ else {
+ pr_err("drm package size is error, size is %u\n", drm->drm_pktsize);
+ return -EINVAL;
+ }
+ realbuf = drm->drm_phy;
+ isphybuf = 1;
+ } else
+ realbuf = (unsigned long)buf;
+ /* pr_info("drm->drm_flag = 0x%x,realcount = %d , buf = 0x%x ",*/
+ /*drm->drm_flag,realcount, buf); */
+
+ count = realcount;
+
+ while (count > 0) {
+ if ((stbuf_space(vbuf) < count) ||
+ (stbuf_space(abuf) < count)) {
+ if (file->f_flags & O_NONBLOCK) {
+ int v_stbuf_space = stbuf_space(vbuf);
+ int a_stbuf_space = stbuf_space(abuf);
+
+ write_size = min(v_stbuf_space, a_stbuf_space);
+ /*have 188 bytes,write now., */
+ if (write_size <= 188)
+ return -EAGAIN;
+ } else {
+ wait_size =
+ min(stbuf_canusesize(vbuf) / 8,
+ stbuf_canusesize(abuf) / 4);
+ if ((port->flag & PORT_FLAG_VID)
+ && (stbuf_space(vbuf) < wait_size)) {
+ r = stbuf_wait_space(vbuf, wait_size);
+
+ if (r < 0) {
+ if (r != -EAGAIN)
+ pr_info
+ ("write no space--- ");
+ if (r != -EAGAIN)
+ pr_info
+ ("no space,%d--%d,r-%d\n",
+ stbuf_space(vbuf),
+ stbuf_space(abuf), r);
+ return r;
+ }
+ }
+
+ if ((port->flag & PORT_FLAG_AID)
+ && (stbuf_space(abuf) < wait_size)) {
+ r = stbuf_wait_space(abuf, wait_size);
+
+ if (r < 0) {
+ pr_info
+ ("write no stbuf_wait_space--");
+ pr_info
+ ("no space,%d--%d,r-%d\n",
+ stbuf_space(vbuf),
+ stbuf_space(abuf), r);
+ return r;
+ }
+ }
+ }
+ }
+
+ if ((port->flag & PORT_FLAG_VID) &&
+ (port->flag & PORT_FLAG_AID)) {
+ write_size = min(stbuf_space(vbuf), stbuf_space(abuf));
+ write_size = min(count, write_size);
+ } else {
+ struct stream_buf_s *buf =
+ (port->flag & PORT_FLAG_VID) ? vbuf : abuf;
+
+ write_size = min_t(int, count, stbuf_space(buf));
+ }
+ /* pr_info("write_size = %d,count = %d,\n",*/
+ /*write_size, count); */
+ if (write_size > 0) {
+ r = _tsdemux_write((const char __user *)realbuf + havewritebytes,
+ write_size, isphybuf);
+ if (r < 0) {
+ if (r != -EAGAIN)
+ pr_info
+ ("vspace %d--aspace %d,r-%d\n",
+ stbuf_space(vbuf),
+ stbuf_space(abuf), r);
+ return r;
+ }
+ }
+ else
+ return -EAGAIN;
+
+ havewritebytes += r;
+
+ /* pr_info("havewritebytes = %d, r = %d,\n",*/
+ /*havewritebytes, r); */
+ if (havewritebytes == realcount)
+ break; /* write ok; */
+ else if (havewritebytes > realcount)
+ pr_info(" error ! write too much havewritebytes = %u, r = %u\n",
+ (u32)havewritebytes,(u32)realcount);
+
+ count -= r;
+ }
+ return havewritebytes;
+}
+
+ssize_t tsdemux_write(struct file *file,
+ struct stream_buf_s *vbuf,
+ struct stream_buf_s *abuf,
+ const char __user *buf, size_t count)
+{
+ s32 r;
+ struct port_priv_s *priv = (struct port_priv_s *)file->private_data;
+ struct stream_port_s *port = priv->port;
+ size_t wait_size, write_size;
+
+ if ((stbuf_space(vbuf) < count) || (stbuf_space(abuf) < count)) {
+ if (file->f_flags & O_NONBLOCK) {
+ write_size = min(stbuf_space(vbuf), stbuf_space(abuf));
+ if (write_size <= 188) /*have 188 bytes,write now., */
+ return -EAGAIN;
+ } else {
+ wait_size =
+ min(stbuf_canusesize(vbuf) / 8,
+ stbuf_canusesize(abuf) / 4);
+ if ((port->flag & PORT_FLAG_VID)
+ && (stbuf_space(vbuf) < wait_size)) {
+ r = stbuf_wait_space(vbuf, wait_size);
+
+ if (r < 0) {
+ /* pr_info("write no space--- ");
+ * pr_info("no space,%d--%d,r-%d\n",
+ * stbuf_space(vbuf),
+ * stbuf_space(abuf),r);
+ */
+ return r;
+ }
+ }
+
+ if ((port->flag & PORT_FLAG_AID)
+ && (stbuf_space(abuf) < wait_size)) {
+ r = stbuf_wait_space(abuf, wait_size);
+
+ if (r < 0) {
+ /* pr_info("write no stbuf_wait_space")'
+ * pr_info{"---no space,%d--%d,r-%d\n",
+ * stbuf_space(vbuf),
+ * stbuf_space(abuf),r);
+ */
+ return r;
+ }
+ }
+ }
+ }
+ vbuf->last_write_jiffies64 = jiffies_64;
+ abuf->last_write_jiffies64 = jiffies_64;
+ write_size = limited_delay_check(file, vbuf, abuf, buf, count);
+ if (write_size > 0)
+ return _tsdemux_write(buf, write_size, 0);
+ else
+ return -EAGAIN;
+}
+
+int get_discontinue_counter(void)
+{
+ return discontinued_counter;
+}
+EXPORT_SYMBOL(get_discontinue_counter);
+
+static ssize_t show_discontinue_counter(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", discontinued_counter);
+}
+
+static struct class_attribute tsdemux_class_attrs[] = {
+ __ATTR(discontinue_counter, S_IRUGO, show_discontinue_counter, NULL),
+ __ATTR_NULL
+};
+
+static struct class tsdemux_class = {
+ .name = "tsdemux",
+ .class_attrs = tsdemux_class_attrs,
+ };
+
+int tsdemux_class_register(void)
+{
+ int r = class_register(&tsdemux_class);
+
+ if (r < 0)
+ pr_info("register tsdemux class error!\n");
+ discontinued_counter = 0;
+ return r;
+}
+
+void tsdemux_class_unregister(void)
+{
+ class_unregister(&tsdemux_class);
+}
+
+void tsdemux_change_avid(unsigned int vid, unsigned int aid)
+{
+ if (!enable_demux_driver()) {
+ WRITE_DEMUX_REG(FM_WR_DATA,
+ (((vid & 0x1fff) | (VIDEO_PACKET << 13)) << 16)
+ | ((aid & 0x1fff) | (AUDIO_PACKET << 13)));
+ WRITE_DEMUX_REG(FM_WR_ADDR, 0x8000);
+ while (READ_DEMUX_REG(FM_WR_ADDR) & 0x8000)
+ ;
+ }
+ else
+ {
+ if (curr_vid_id != vid) {
+ tsdemux_set_vid(vid);
+ curr_vid_id = vid;
+ }
+ if (curr_aud_id != aid) {
+ tsdemux_set_aid(aid);
+ curr_aud_id = aid;
+ }
+ reset_pcr_regs();
+ }
+}
+
+void tsdemux_change_sid(unsigned int sid)
+{
+ if (!enable_demux_driver()) {
+ WRITE_DEMUX_REG(FM_WR_DATA,
+ (((sid & 0x1fff) | (SUB_PACKET << 13)) << 16)
+ | 0xffff);
+ WRITE_DEMUX_REG(FM_WR_ADDR, 0x8001);
+ while (READ_DEMUX_REG(FM_WR_ADDR) & 0x8000)
+ ;
+ } else {
+ curr_sub_id = sid;
+
+ tsdemux_set_sid(sid);
+
+ reset_pcr_regs();
+ }
+
+}
+
+void tsdemux_audio_reset(void)
+{
+ ulong flags;
+ unsigned long xflags = 0;
+
+ spin_lock_irqsave(&demux_ops_lock, flags);
+ if (demux_ops && demux_ops->hw_dmx_lock)
+ xflags = demux_ops->hw_dmx_lock(xflags);
+
+ WRITE_PARSER_REG(PARSER_AUDIO_WP,
+ READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_PARSER_REG(PARSER_AUDIO_RP,
+ READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
+
+ WRITE_PARSER_REG(PARSER_AUDIO_START_PTR,
+ READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_PARSER_REG(PARSER_AUDIO_END_PTR,
+ READ_AIU_REG(AIU_MEM_AIFIFO_END_PTR));
+ CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL, ES_AUD_MAN_RD_PTR);
+
+ WRITE_AIU_REG(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ CLEAR_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+
+ if (demux_ops && demux_ops->hw_dmx_unlock)
+ demux_ops->hw_dmx_unlock(xflags);
+ spin_unlock_irqrestore(&demux_ops_lock, flags);
+}
+
+void tsdemux_sub_reset(void)
+{
+ ulong flags;
+ u32 parser_sub_start_ptr;
+ u32 parser_sub_end_ptr;
+ unsigned long xflags = 0;
+
+ spin_lock_irqsave(&demux_ops_lock, flags);
+ if (demux_ops && demux_ops->hw_dmx_lock)
+ xflags = demux_ops->hw_dmx_lock(xflags);
+
+ parser_sub_start_ptr = READ_PARSER_REG(PARSER_SUB_START_PTR);
+ parser_sub_end_ptr = READ_PARSER_REG(PARSER_SUB_END_PTR);
+
+ WRITE_PARSER_REG(PARSER_SUB_START_PTR, parser_sub_start_ptr);
+ WRITE_PARSER_REG(PARSER_SUB_END_PTR, parser_sub_end_ptr);
+ WRITE_PARSER_REG(PARSER_SUB_RP, parser_sub_start_ptr);
+ WRITE_PARSER_REG(PARSER_SUB_WP, parser_sub_start_ptr);
+ SET_PARSER_REG_MASK(PARSER_ES_CONTROL,
+ (7 << ES_SUB_WR_ENDIAN_BIT) | ES_SUB_MAN_RD_PTR);
+
+ if (demux_ops && demux_ops->hw_dmx_unlock)
+ demux_ops->hw_dmx_unlock(xflags);
+ spin_unlock_irqrestore(&demux_ops_lock, flags);
+}
+
+void tsdemux_set_skipbyte(int skipbyte)
+{
+ if (!enable_demux_driver())
+ demux_skipbyte = skipbyte;
+ else
+ tsdemux_set_skip_byte(skipbyte);
+
+}
+
+void tsdemux_set_demux(int dev)
+{
+ if (enable_demux_driver()) {
+ unsigned long flags;
+ int r = 0;
+
+ spin_lock_irqsave(&demux_ops_lock, flags);
+ if (demux_ops && demux_ops->set_demux)
+ r = demux_ops->set_demux(dev);
+ spin_unlock_irqrestore(&demux_ops_lock, flags);
+ }
+}
+
+u32 tsdemux_pcrscr_get(void)
+{
+ u32 pcr = 0;
+
+ if (pcrscr_valid == 0)
+ return 0;
+
+ if (READ_DEMUX_REG(TS_HIU_CTL_2) & 0x80)
+ pcr = READ_DEMUX_REG(PCR_DEMUX_2);
+ else if (READ_DEMUX_REG(TS_HIU_CTL_3) & 0x80)
+ pcr = READ_DEMUX_REG(PCR_DEMUX_3);
+ else
+ pcr = READ_DEMUX_REG(PCR_DEMUX);
+ if (first_pcr == 0)
+ first_pcr = pcr;
+ return pcr;
+}
+
+u32 tsdemux_first_pcrscr_get(void)
+{
+ if (pcrscr_valid == 0)
+ return 0;
+
+ if (first_pcr == 0) {
+ u32 pcr;
+ if (READ_DEMUX_REG(TS_HIU_CTL_2) & 0x80)
+ pcr = READ_DEMUX_REG(PCR_DEMUX_2);
+ else if (READ_DEMUX_REG(TS_HIU_CTL_3) & 0x80)
+ pcr = READ_DEMUX_REG(PCR_DEMUX_3);
+ else
+ pcr = READ_DEMUX_REG(PCR_DEMUX);
+ first_pcr = pcr;
+ /* pr_info("set first_pcr = 0x%x\n", pcr); */
+ }
+
+ return first_pcr;
+}
+
+u8 tsdemux_pcrscr_valid(void)
+{
+ return pcrscr_valid;
+}
+
+u8 tsdemux_pcraudio_valid(void)
+{
+ return pcraudio_valid;
+}
+
+u8 tsdemux_pcrvideo_valid(void)
+{
+ return pcrvideo_valid;
+}
+
+void tsdemux_pcr_set(unsigned int pcr)
+{
+ if (pcr_init_flag == 0) {
+ /*timestamp_pcrscr_set(pcr);
+ timestamp_pcrscr_enable(1);*/
+ pcr_init_flag = 1;
+ }
+}
+
+void tsdemux_tsync_func_init(void)
+{
+ register_tsync_callbackfunc(
+ TSYNC_PCRSCR_VALID, (void *)(tsdemux_pcrscr_valid));
+ register_tsync_callbackfunc(
+ TSYNC_PCRSCR_GET, (void *)(tsdemux_pcrscr_get));
+ register_tsync_callbackfunc(
+ TSYNC_FIRST_PCRSCR_GET, (void *)(tsdemux_first_pcrscr_get));
+ register_tsync_callbackfunc(
+ TSYNC_PCRAUDIO_VALID, (void *)(tsdemux_pcraudio_valid));
+ register_tsync_callbackfunc(
+ TSYNC_PCRVIDEO_VALID, (void *)(tsdemux_pcrvideo_valid));
+ register_tsync_callbackfunc(
+ TSYNC_BUF_BY_BYTE, (void *)(get_buf_by_type));
+ register_tsync_callbackfunc(
+ TSYNC_STBUF_LEVEL, (void *)(stbuf_level));
+ register_tsync_callbackfunc(
+ TSYNC_STBUF_SPACE, (void *)(stbuf_space));
+ register_tsync_callbackfunc(
+ TSYNC_STBUF_SIZE, (void *)(stbuf_size));
+}
+
+static int tsparser_stbuf_init(struct stream_buf_s *stbuf,
+ struct vdec_s *vdec)
+{
+ int ret = -1;
+
+ ret = stbuf_init(stbuf, vdec);
+ if (ret)
+ goto out;
+
+ ret = tsdemux_init(stbuf->pars.vid,
+ stbuf->pars.aid,
+ stbuf->pars.sid,
+ stbuf->pars.pcrid,
+ stbuf->is_hevc,
+ vdec);
+ if (ret)
+ goto out;
+
+ tsync_pcr_start();
+
+ stbuf->flag |= BUF_FLAG_IN_USE;
+out:
+ return ret;
+}
+
+static void tsparser_stbuf_release(struct stream_buf_s *stbuf)
+{
+ tsync_pcr_stop();
+
+ tsdemux_release();
+
+ stbuf_release(stbuf);
+}
+
+static struct stream_buf_ops tsparser_stbuf_ops = {
+ .init = tsparser_stbuf_init,
+ .release = tsparser_stbuf_release,
+ .get_wp = parser_get_wp,
+ .set_wp = parser_set_wp,
+ .get_rp = parser_get_rp,
+ .set_rp = parser_set_rp,
+};
+
+struct stream_buf_ops *get_tsparser_stbuf_ops(void)
+{
+ return &tsparser_stbuf_ops;
+}
+EXPORT_SYMBOL(get_tsparser_stbuf_ops);
+
+
diff --git a/drivers/stream_input/parser/tsdemux.h b/drivers/stream_input/parser/tsdemux.h
new file mode 100644
index 0000000..5f82309
--- /dev/null
+++ b/drivers/stream_input/parser/tsdemux.h
@@ -0,0 +1,104 @@
+/*
+ * drivers/amlogic/media/stream_input/parser/tsdemux.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 TSDEMUX_H
+#define TSDEMUX_H
+#include <linux/amlogic/media/utils/amports_config.h>
+
+/* TODO: move to register headers */
+#define NEW_PDTS_READY 4
+#define AUDIO_PTS_READY 2
+#define VIDEO_PTS_READY 0
+#define DIS_CONTINUITY_PACKET 6
+#define SUB_PES_READY 7
+#define PCR_READY 11
+
+#define PARSER_INTSTAT_FETCH_CMD (1<<7)
+
+#define FETCH_ENDIAN 27
+#define FETCH_ENDIAN_MASK (0x7<<27)
+
+#define RESET_DEMUXSTB (1<<1)
+#define RESET_PARSER (1<<8)
+
+#define VIDEO_PACKET 0
+#define AUDIO_PACKET 1
+#define SUB_PACKET 2
+
+#define OTHER_ENDIAN 6
+#define BYPASS_ENDIAN 3
+#define SECTION_ENDIAN 0
+
+#define USE_HI_BSF_INTERFACE 7
+#define DES_OUT_DLY 8
+#define TRANSPORT_SCRAMBLING_CONTROL_ODD 6
+#define TS_HIU_ENABLE 5
+#define FEC_FILE_CLK_DIV 0
+#define STB_DEMUX_ENABLE 4
+#define KEEP_DUPLICATE_PACKAGE 6
+
+#define ES_VID_MAN_RD_PTR (1<<0)
+#define ES_AUD_MAN_RD_PTR (1<<4)
+
+#define PS_CFG_PFIFO_EMPTY_CNT_BIT 16
+#define PS_CFG_MAX_ES_WR_CYCLE_BIT 12
+#define PS_CFG_MAX_FETCH_CYCLE_BIT 0
+
+#define ES_SUB_WR_ENDIAN_BIT 9
+#define ES_SUB_MAN_RD_PTR (1<<8)
+#define PARSER_INTSTAT_FETCH_CMD (1<<7)
+
+#define PARSER_INT_HOST_EN_BIT 8
+
+struct stream_buf_s;
+struct vdec_s;
+
+extern s32 tsdemux_init(u32 vid, u32 aid, u32 sid, u32 pcrid, bool is_hevc,
+ struct vdec_s *vdec);
+
+extern void tsdemux_release(void);
+extern ssize_t drm_tswrite(struct file *file,
+ struct stream_buf_s *vbuf,
+ struct stream_buf_s *abuf,
+ const char __user *buf, size_t count);
+
+extern ssize_t tsdemux_write(struct file *file,
+ struct stream_buf_s *vbuf,
+ struct stream_buf_s *abuf,
+ const char __user *buf, size_t count);
+
+extern u32 tsdemux_pcrscr_get(void);
+extern u8 tsdemux_pcrscr_valid(void);
+extern u8 tsdemux_pcraudio_valid(void);
+extern u8 tsdemux_pcrvideo_valid(void);
+extern u32 tsdemux_first_pcrscr_get(void);
+extern void timestamp_pcrscr_enable(u32 enable);
+extern void timestamp_pcrscr_set(u32 pts);
+int get_discontinue_counter(void);
+
+int tsdemux_class_register(void);
+void tsdemux_class_unregister(void);
+void tsdemux_change_avid(unsigned int vid, unsigned int aid);
+void tsdemux_change_sid(unsigned int sid);
+void tsdemux_audio_reset(void);
+void tsdemux_sub_reset(void);
+void tsdemux_set_skipbyte(int skipbyte);
+void tsdemux_set_demux(int dev);
+void tsdemux_tsync_func_init(void);
+
+
+#endif /* TSDEMUX_H */
diff --git a/drivers/stream_input/subtitle/subtitle.c b/drivers/stream_input/subtitle/subtitle.c
new file mode 100644
index 0000000..bfcf612
--- /dev/null
+++ b/drivers/stream_input/subtitle/subtitle.c
@@ -0,0 +1,715 @@
+/*
+ * drivers/amlogic/media/subtitle/subtitle.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/vmalloc.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/amlogic/media/utils/amstream.h>
+#include <linux/uaccess.h>
+//#include "amports_priv.h"
+
+//#include "amlog.h"
+//MODULE_AMLOG(AMLOG_DEFAULT_LEVEL, 0, LOG_DEFAULT_LEVEL_DESC,
+ //LOG_DEFAULT_MASK_DESC);
+#define DEVICE_NAME "amsubtitle"
+/* Dev name as it appears in /proc/devices */
+#define DEVICE_CLASS_NAME "subtitle"
+
+static int subdevice_open;
+
+#define MAX_SUBTITLE_PACKET 10
+static DEFINE_MUTEX(amsubtitle_mutex);
+
+struct subtitle_data_s {
+ int subtitle_size;
+ int subtitle_pts;
+ char *data;
+};
+static struct subtitle_data_s subtitle_data[MAX_SUBTITLE_PACKET];
+static int subtitle_enable = 1;
+static int subtitle_total;
+static int subtitle_width;
+static int subtitle_height;
+static int subtitle_type = -1;
+static int subtitle_current; /* no subtitle */
+/* sub_index node will be modified by libplayer; amlogicplayer will use */
+/* it to detect wheather libplayer switch sub finished or not */
+static int subtitle_index; /* no subtitle */
+/* static int subtitle_size = 0; */
+/* static int subtitle_read_pos = 0; */
+static int subtitle_write_pos;
+static int subtitle_start_pts;
+static int subtitle_fps;
+static int subtitle_subtype;
+static int subtitle_reset;
+/* static int *subltitle_address[MAX_SUBTITLE_PACKET]; */
+
+enum subinfo_para_e {
+ SUB_NULL = -1,
+ SUB_ENABLE = 0,
+ SUB_TOTAL,
+ SUB_WIDTH,
+ SUB_HEIGHT,
+ SUB_TYPE,
+ SUB_CURRENT,
+ SUB_INDEX,
+ SUB_WRITE_POS,
+ SUB_START_PTS,
+ SUB_FPS,
+ SUB_SUBTYPE,
+ SUB_RESET,
+ SUB_DATA_T_SIZE,
+ SUB_DATA_T_DATA
+};
+
+struct subinfo_para_s {
+ enum subinfo_para_e subinfo_type;
+ int subtitle_info;
+ char *data;
+};
+
+/* total */
+/* curr */
+/* bimap */
+/* text */
+/* type */
+/* info */
+/* pts */
+/* duration */
+/* color pallete */
+/* width/height */
+
+static ssize_t show_curr(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d: current\n", subtitle_current);
+}
+
+static ssize_t store_curr(struct class *class, struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned int curr;
+ ssize_t r;
+
+ r = kstrtoint(buf, 0, &curr);
+ if (r < 0)
+ return -EINVAL;
+
+
+ subtitle_current = curr;
+
+ return size;
+}
+
+static ssize_t show_index(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d: current\n", subtitle_index);
+}
+
+static ssize_t store_index(struct class *class, struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned int curr;
+ ssize_t r;
+
+ r = kstrtoint(buf, 0, &curr);
+ if (r < 0)
+ return -EINVAL;
+
+ subtitle_index = curr;
+
+ return size;
+}
+
+static ssize_t show_reset(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d: current\n", subtitle_reset);
+}
+
+static ssize_t store_reset(struct class *class, struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned int reset;
+ ssize_t r;
+
+ r = kstrtoint(buf, 0, &reset);
+
+ pr_info("reset is %d\n", reset);
+ if (r < 0)
+ return -EINVAL;
+
+
+ subtitle_reset = reset;
+
+ return size;
+}
+
+static ssize_t show_type(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d: type\n", subtitle_type);
+}
+
+static ssize_t store_type(struct class *class, struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned int type;
+ ssize_t r;
+
+ r = kstrtoint(buf, 0, &type);
+ if (r < 0)
+ return -EINVAL;
+
+ subtitle_type = type;
+
+ return size;
+}
+
+static ssize_t show_width(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d: width\n", subtitle_width);
+}
+
+static ssize_t store_width(struct class *class, struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned int width;
+ ssize_t r;
+
+ r = kstrtoint(buf, 0, &width);
+ if (r < 0)
+ return -EINVAL;
+
+ subtitle_width = width;
+
+ return size;
+}
+
+static ssize_t show_height(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d: height\n", subtitle_height);
+}
+
+static ssize_t store_height(struct class *class, struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned int height;
+ ssize_t r;
+
+ r = kstrtoint(buf, 0, &height);
+ if (r < 0)
+ return -EINVAL;
+
+ subtitle_height = height;
+
+ return size;
+}
+
+static ssize_t show_total(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d: num\n", subtitle_total);
+}
+
+static ssize_t store_total(struct class *class, struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned int total;
+ ssize_t r;
+
+ r = kstrtoint(buf, 0, &total);
+ if (r < 0)
+ return -EINVAL;
+ pr_info("subtitle num is %d\n", total);
+ subtitle_total = total;
+
+ return size;
+}
+
+static ssize_t show_enable(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ if (subtitle_enable)
+ return sprintf(buf, "1: enabled\n");
+
+ return sprintf(buf, "0: disabled\n");
+}
+
+static ssize_t store_enable(struct class *class, struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned int mode;
+ ssize_t r;
+
+ r = kstrtoint(buf, 0, &mode);
+ if (r < 0)
+ return -EINVAL;
+ pr_info("subtitle enable is %d\n", mode);
+ subtitle_enable = mode ? 1 : 0;
+
+ return size;
+}
+
+static ssize_t show_size(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ if (subtitle_enable)
+ return sprintf(buf, "1: size\n");
+
+ return sprintf(buf, "0: size\n");
+}
+
+static ssize_t store_size(struct class *class, struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned int ssize;
+ ssize_t r;
+
+ r = kstrtoint(buf, 0, &ssize);
+ if (r < 0)
+ return -EINVAL;
+ pr_info("subtitle size is %d\n", ssize);
+ subtitle_data[subtitle_write_pos].subtitle_size = ssize;
+
+ return size;
+}
+
+static ssize_t show_startpts(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d: pts\n", subtitle_start_pts);
+}
+
+static ssize_t store_startpts(struct class *class, struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned int spts;
+ ssize_t r;
+
+ r = kstrtoint(buf, 0, &spts);
+ if (r < 0)
+ return -EINVAL;
+ pr_info("subtitle start pts is %x\n", spts);
+ subtitle_start_pts = spts;
+
+ return size;
+}
+
+static ssize_t show_data(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+#if 0
+ if (subtitle_data[subtitle_write_pos].data)
+ return sprintf(buf, "%lld\n",
+ (unsigned long)(subtitle_data[subtitle_write_pos].data));
+#endif
+ return sprintf(buf, "0: disabled\n");
+}
+
+static ssize_t store_data(struct class *class, struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned int address;
+ ssize_t r;
+
+ r = kstrtoint(buf, 0, &address);
+ if ((r == 0))
+ return -EINVAL;
+#if 0
+ if (subtitle_data[subtitle_write_pos].subtitle_size > 0) {
+ subtitle_data[subtitle_write_pos].data = vmalloc((
+ subtitle_data[subtitle_write_pos].subtitle_size));
+ if (subtitle_data[subtitle_write_pos].data)
+ memcpy(subtitle_data[subtitle_write_pos].data,
+ (unsigned long *)address,
+ subtitle_data[subtitle_write_pos].subtitle_size);
+ }
+ pr_info("subtitle data address is %x",
+ (unsigned int)(subtitle_data[subtitle_write_pos].data));
+#endif
+ subtitle_write_pos++;
+ if (subtitle_write_pos >= MAX_SUBTITLE_PACKET)
+ subtitle_write_pos = 0;
+ return 1;
+}
+
+static ssize_t show_fps(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d: fps\n", subtitle_fps);
+}
+
+static ssize_t store_fps(struct class *class, struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned int ssize;
+ ssize_t r;
+
+ r = kstrtoint(buf, 0, &ssize);
+ if (r < 0)
+ return -EINVAL;
+ pr_info("subtitle fps is %d\n", ssize);
+ subtitle_fps = ssize;
+
+ return size;
+}
+
+static ssize_t show_subtype(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d: subtype\n", subtitle_subtype);
+}
+
+static ssize_t store_subtype(struct class *class, struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned int ssize;
+ ssize_t r;
+
+ r = kstrtoint(buf, 0, &ssize);
+ if (r < 0)
+ return -EINVAL;
+ pr_info("subtitle subtype is %d\n", ssize);
+ subtitle_subtype = ssize;
+
+ return size;
+}
+
+static struct class_attribute subtitle_class_attrs[] = {
+ __ATTR(enable, 0664, show_enable, store_enable),
+ __ATTR(total, 0664, show_total, store_total),
+ __ATTR(width, 0664, show_width, store_width),
+ __ATTR(height, 0664, show_height, store_height),
+ __ATTR(type, 0664, show_type, store_type),
+ __ATTR(curr, 0664, show_curr, store_curr),
+ __ATTR(index, 0664, show_index, store_index),
+ __ATTR(size, 0664, show_size, store_size),
+ __ATTR(data, 0664, show_data, store_data),
+ __ATTR(startpts, 0664, show_startpts,
+ store_startpts),
+ __ATTR(fps, 0664, show_fps, store_fps),
+ __ATTR(subtype, 0664, show_subtype,
+ store_subtype),
+ __ATTR(reset, 0644, show_reset, store_reset),
+ __ATTR_NULL
+};
+
+
+/*********************************************************
+ * /dev/amvideo APIs
+ *********************************************************/
+static int amsubtitle_open(struct inode *inode, struct file *file)
+{
+ mutex_lock(&amsubtitle_mutex);
+
+ if (subdevice_open) {
+ mutex_unlock(&amsubtitle_mutex);
+ return -EBUSY;
+ }
+
+ subdevice_open = 1;
+
+ try_module_get(THIS_MODULE);
+
+ mutex_unlock(&amsubtitle_mutex);
+
+ return 0;
+}
+
+static int amsubtitle_release(struct inode *inode, struct file *file)
+{
+ mutex_lock(&amsubtitle_mutex);
+
+ subdevice_open = 0;
+
+ module_put(THIS_MODULE);
+
+ mutex_unlock(&amsubtitle_mutex);
+
+ return 0;
+}
+
+static long amsubtitle_ioctl(struct file *file, unsigned int cmd, ulong arg)
+{
+ switch (cmd) {
+ case AMSTREAM_IOC_GET_SUBTITLE_INFO: {
+ struct subinfo_para_s Vstates;
+ struct subinfo_para_s *states = &Vstates;
+
+ if (copy_from_user((void *)states,
+ (void *)arg, sizeof(Vstates)))
+ return -EFAULT;
+ switch (states->subinfo_type) {
+ case SUB_ENABLE:
+ states->subtitle_info = subtitle_enable;
+ break;
+ case SUB_TOTAL:
+ states->subtitle_info = subtitle_total;
+ break;
+ case SUB_WIDTH:
+ states->subtitle_info = subtitle_width;
+ break;
+ case SUB_HEIGHT:
+ states->subtitle_info = subtitle_height;
+ break;
+ case SUB_TYPE:
+ states->subtitle_info = subtitle_type;
+ break;
+ case SUB_CURRENT:
+ states->subtitle_info = subtitle_current;
+ break;
+ case SUB_INDEX:
+ states->subtitle_info = subtitle_index;
+ break;
+ case SUB_WRITE_POS:
+ states->subtitle_info = subtitle_write_pos;
+ break;
+ case SUB_START_PTS:
+ states->subtitle_info = subtitle_start_pts;
+ break;
+ case SUB_FPS:
+ states->subtitle_info = subtitle_fps;
+ break;
+ case SUB_SUBTYPE:
+ states->subtitle_info = subtitle_subtype;
+ break;
+ case SUB_RESET:
+ states->subtitle_info = subtitle_reset;
+ break;
+ case SUB_DATA_T_SIZE:
+ states->subtitle_info =
+ subtitle_data[subtitle_write_pos].subtitle_size;
+ break;
+ case SUB_DATA_T_DATA: {
+ if (states->subtitle_info > 0)
+ states->subtitle_info =
+ (long)subtitle_data[subtitle_write_pos].data;
+ }
+ break;
+ default:
+ break;
+ }
+ if (copy_to_user((void *)arg, (void *)states, sizeof(Vstates)))
+ return -EFAULT;
+ }
+
+ break;
+ case AMSTREAM_IOC_SET_SUBTITLE_INFO: {
+ struct subinfo_para_s Vstates;
+ struct subinfo_para_s *states = &Vstates;
+
+ if (copy_from_user((void *)states,
+ (void *)arg, sizeof(Vstates)))
+ return -EFAULT;
+ switch (states->subinfo_type) {
+ case SUB_ENABLE:
+ subtitle_enable = states->subtitle_info;
+ break;
+ case SUB_TOTAL:
+ subtitle_total = states->subtitle_info;
+ break;
+ case SUB_WIDTH:
+ subtitle_width = states->subtitle_info;
+ break;
+ case SUB_HEIGHT:
+ subtitle_height = states->subtitle_info;
+ break;
+ case SUB_TYPE:
+ subtitle_type = states->subtitle_info;
+ break;
+ case SUB_CURRENT:
+ subtitle_current = states->subtitle_info;
+ break;
+ case SUB_INDEX:
+ subtitle_index = states->subtitle_info;
+ break;
+ case SUB_WRITE_POS:
+ subtitle_write_pos = states->subtitle_info;
+ break;
+ case SUB_START_PTS:
+ subtitle_start_pts = states->subtitle_info;
+ break;
+ case SUB_FPS:
+ subtitle_fps = states->subtitle_info;
+ break;
+ case SUB_SUBTYPE:
+ subtitle_subtype = states->subtitle_info;
+ break;
+ case SUB_RESET:
+ subtitle_reset = states->subtitle_info;
+ break;
+ case SUB_DATA_T_SIZE:
+ subtitle_data[subtitle_write_pos].subtitle_size =
+ states->subtitle_info;
+ break;
+ case SUB_DATA_T_DATA: {
+ if (states->subtitle_info > 0) {
+ subtitle_data[subtitle_write_pos].data =
+ vmalloc((states->subtitle_info));
+ if (subtitle_data[subtitle_write_pos].data)
+ memcpy(
+ subtitle_data[subtitle_write_pos].data,
+ (char *)states->data,
+ states->subtitle_info);
+ }
+
+ subtitle_write_pos++;
+ if (subtitle_write_pos >= MAX_SUBTITLE_PACKET)
+ subtitle_write_pos = 0;
+ }
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_COMPAT
+static long amsub_compat_ioctl(struct file *file, unsigned int cmd, ulong arg)
+{
+ long ret = 0;
+
+ ret = amsubtitle_ioctl(file, cmd, (ulong)compat_ptr(arg));
+ return ret;
+}
+#endif
+
+static const struct file_operations amsubtitle_fops = {
+ .owner = THIS_MODULE,
+ .open = amsubtitle_open,
+ .release = amsubtitle_release,
+ .unlocked_ioctl = amsubtitle_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = amsub_compat_ioctl,
+#endif
+};
+
+static struct device *amsubtitle_dev;
+static dev_t amsub_devno;
+static struct class *amsub_clsp;
+static struct cdev *amsub_cdevp;
+#define AMSUBTITLE_DEVICE_COUNT 1
+
+static void create_amsub_attrs(struct class *class)
+{
+ int i = 0;
+
+ for (i = 0; subtitle_class_attrs[i].attr.name; i++) {
+ if (class_create_file(class, &subtitle_class_attrs[i]) < 0)
+ break;
+ }
+}
+
+static void remove_amsub_attrs(struct class *class)
+{
+ int i = 0;
+
+ for (i = 0; subtitle_class_attrs[i].attr.name; i++)
+ class_remove_file(class, &subtitle_class_attrs[i]);
+}
+
+int subtitle_init(void)
+{
+ int ret = 0;
+
+ ret = alloc_chrdev_region(&amsub_devno, 0, AMSUBTITLE_DEVICE_COUNT,
+ DEVICE_NAME);
+ if (ret < 0) {
+ pr_info("amsub: failed to alloc major number\n");
+ ret = -ENODEV;
+ return ret;
+ }
+
+ amsub_clsp = class_create(THIS_MODULE, DEVICE_CLASS_NAME);
+ if (IS_ERR(amsub_clsp)) {
+ ret = PTR_ERR(amsub_clsp);
+ goto err1;
+ }
+
+ create_amsub_attrs(amsub_clsp);
+
+ amsub_cdevp = kmalloc(sizeof(struct cdev), GFP_KERNEL);
+ if (!amsub_cdevp) {
+ /*pr_info("amsub: failed to allocate memory\n");*/
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ cdev_init(amsub_cdevp, &amsubtitle_fops);
+ amsub_cdevp->owner = THIS_MODULE;
+ /* connect the major/minor number to cdev */
+ ret = cdev_add(amsub_cdevp, amsub_devno, AMSUBTITLE_DEVICE_COUNT);
+ if (ret) {
+ pr_info("amsub:failed to add cdev\n");
+ goto err3;
+ }
+
+ amsubtitle_dev = device_create(amsub_clsp,
+ NULL, MKDEV(MAJOR(amsub_devno), 0),
+ NULL, DEVICE_NAME);
+
+ if (IS_ERR(amsubtitle_dev)) {
+ pr_err("## Can't create amsubtitle device\n");
+ goto err4;
+ }
+
+ return 0;
+
+err4:
+ cdev_del(amsub_cdevp);
+err3:
+ kfree(amsub_cdevp);
+err2:
+ remove_amsub_attrs(amsub_clsp);
+ class_destroy(amsub_clsp);
+err1:
+ unregister_chrdev_region(amsub_devno, 1);
+
+ return ret;
+}
+EXPORT_SYMBOL(subtitle_init);
+
+void subtitle_exit(void)
+{
+ unregister_chrdev_region(amsub_devno, 1);
+ device_destroy(amsub_clsp, MKDEV(MAJOR(amsub_devno), 0));
+ cdev_del(amsub_cdevp);
+ kfree(amsub_cdevp);
+ remove_amsub_attrs(amsub_clsp);
+ class_destroy(amsub_clsp);
+}
+EXPORT_SYMBOL(subtitle_exit);
+
diff --git a/drivers/stream_input/subtitle/subtitle.h b/drivers/stream_input/subtitle/subtitle.h
new file mode 100644
index 0000000..375a31a
--- /dev/null
+++ b/drivers/stream_input/subtitle/subtitle.h
@@ -0,0 +1,24 @@
+/*
+ * drivers/amlogic/media/stream_input/amports/amports_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 SUBTITLE_H
+#define SUBTITLE_H
+
+int subtitle_init(void);
+void subtitle_exit(void);
+
+#endif
diff --git a/firmware/h264_enc.bin b/firmware/h264_enc.bin
new file mode 100644
index 0000000..d8bc73d
--- /dev/null
+++ b/firmware/h264_enc.bin
Binary files differ
diff --git a/firmware/video_ucode.bin b/firmware/video_ucode.bin
new file mode 100644
index 0000000..ec54a6b
--- /dev/null
+++ b/firmware/video_ucode.bin
Binary files differ