summaryrefslogtreecommitdiff
authorNanxin Qin <nanxin.qin@amlogic.com>2017-06-09 07:52:28 (GMT)
committer Nanxin Qin <nanxin.qin@amlogic.com>2017-06-10 05:37:11 (GMT)
commitb9164398172ee6bbcdbc70c4ac1d87b450bdf13b (patch)
treece1db9e64a310adeafb3f8f4a571e49768359ee7
parent3c9b6b880f22a58b22d2785f0f974573e819f677 (diff)
downloadmedia_modules-b9164398172ee6bbcdbc70c4ac1d87b450bdf13b.zip
media_modules-b9164398172ee6bbcdbc70c4ac1d87b450bdf13b.tar.gz
media_modules-b9164398172ee6bbcdbc70c4ac1d87b450bdf13b.tar.bz2
add drivers of the multimedia
Change-Id: Icde0895b71770e393cb6a61bedf04aa199f6463d Signed-off-by: Nanxin Qin <nanxin.qin@amlogic.com>
Diffstat
-rw-r--r--.gitignore101
-rw-r--r--Media.mk91
-rw-r--r--drivers/Makefile4
-rw-r--r--drivers/common/Makefile2
-rw-r--r--drivers/common/chips/chips.c158
-rw-r--r--drivers/common/chips/chips.h39
-rw-r--r--drivers/common/firmware/Makefile3
-rw-r--r--drivers/common/firmware/firmware.h113
-rw-r--r--drivers/common/firmware/firmware_cfg.h32
-rw-r--r--drivers/common/firmware/firmware_drv.c682
-rw-r--r--drivers/common/firmware/firmware_type.c57
-rw-r--r--drivers/common/firmware/firmware_type.h41
-rw-r--r--drivers/common/media_clock/Makefile5
-rw-r--r--drivers/common/media_clock/clk/clk.c405
-rw-r--r--drivers/common/media_clock/clk/clk.h155
-rw-r--r--drivers/common/media_clock/clk/clk_priv.h38
-rw-r--r--drivers/common/media_clock/clk/clkgx.c620
-rw-r--r--drivers/common/media_clock/switch/amports_gate.c189
-rw-r--r--drivers/common/media_clock/switch/amports_gate.h33
-rw-r--r--drivers/frame_provider/Makefile1
-rw-r--r--drivers/frame_provider/decoder/Makefile16
-rw-r--r--drivers/frame_provider/decoder/avs/Makefile2
-rw-r--r--drivers/frame_provider/decoder/avs/avs.c1541
-rw-r--r--drivers/frame_provider/decoder/avs/avs.h70
-rw-r--r--drivers/frame_provider/decoder/avs/avsp_trans.c4944
-rw-r--r--drivers/frame_provider/decoder/h264/vh264.c2960
-rw-r--r--drivers/frame_provider/decoder/h264/vh264.h25
-rw-r--r--drivers/frame_provider/decoder/h264/vh264_4k2k.c1839
-rw-r--r--drivers/frame_provider/decoder/h264/vh264_mvc.c1594
-rw-r--r--drivers/frame_provider/decoder/h264_multi/Makefile2
-rw-r--r--drivers/frame_provider/decoder/h264_multi/h264_dpb.c5238
-rw-r--r--drivers/frame_provider/decoder/h264_multi/h264_dpb.h788
-rw-r--r--drivers/frame_provider/decoder/h264_multi/vmh264.c2776
-rw-r--r--drivers/frame_provider/decoder/h265/vh265.c8969
-rw-r--r--drivers/frame_provider/decoder/h265/vh265.h27
-rw-r--r--drivers/frame_provider/decoder/mjpeg/vmjpeg.c912
-rw-r--r--drivers/frame_provider/decoder/mjpeg/vmjpeg_multi.c723
-rw-r--r--drivers/frame_provider/decoder/mpeg12/vmpeg12.c1110
-rw-r--r--drivers/frame_provider/decoder/mpeg12/vmpeg12.h26
-rw-r--r--drivers/frame_provider/decoder/mpeg4/vmpeg4.c1127
-rw-r--r--drivers/frame_provider/decoder/mpeg4/vmpeg4.h26
-rw-r--r--drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c1304
-rw-r--r--drivers/frame_provider/decoder/real/vreal.c1022
-rw-r--r--drivers/frame_provider/decoder/real/vreal.h26
-rw-r--r--drivers/frame_provider/decoder/utils/Makefile4
-rw-r--r--drivers/frame_provider/decoder/utils/amvdec.c998
-rw-r--r--drivers/frame_provider/decoder/utils/amvdec.h86
-rw-r--r--drivers/frame_provider/decoder/utils/config_parser.c62
-rw-r--r--drivers/frame_provider/decoder/utils/config_parser.h21
-rw-r--r--drivers/frame_provider/decoder/utils/decoder_bmmu_box.c425
-rw-r--r--drivers/frame_provider/decoder/utils/decoder_bmmu_box.h63
-rw-r--r--drivers/frame_provider/decoder/utils/decoder_mmu_box.c383
-rw-r--r--drivers/frame_provider/decoder/utils/decoder_mmu_box.h45
-rw-r--r--drivers/frame_provider/decoder/utils/utils.c66
-rw-r--r--drivers/frame_provider/decoder/utils/vdec.c2907
-rw-r--r--drivers/frame_provider/decoder/utils/vdec.h306
-rw-r--r--drivers/frame_provider/decoder/utils/vdec_input.c544
-rw-r--r--drivers/frame_provider/decoder/utils/vdec_input.h131
-rw-r--r--drivers/frame_provider/decoder/vc1/vvc1.c1170
-rw-r--r--drivers/frame_provider/decoder/vp9/vvp9.c6922
-rw-r--r--drivers/frame_provider/decoder/vp9/vvp9.h25
-rw-r--r--drivers/frame_sink/Makefile1
-rw-r--r--drivers/frame_sink/encoder/Makefile2
-rw-r--r--drivers/frame_sink/encoder/h264/Makefile1
-rw-r--r--drivers/frame_sink/encoder/h264/encoder.c4237
-rw-r--r--drivers/frame_sink/encoder/h264/encoder.h465
-rw-r--r--drivers/frame_sink/encoder/h265/Makefile1
-rw-r--r--drivers/frame_sink/encoder/h265/vmm.h661
-rw-r--r--drivers/frame_sink/encoder/h265/vpu.c1997
-rw-r--r--drivers/frame_sink/encoder/h265/vpu.h288
-rw-r--r--drivers/include/dummy-for-git-empty-dir0
-rw-r--r--drivers/stream_input/Makefile10
-rw-r--r--drivers/stream_input/amports/Makefile2
-rw-r--r--drivers/stream_input/amports/adec.c295
-rw-r--r--drivers/stream_input/amports/adec.h32
-rw-r--r--drivers/stream_input/amports/amports_priv.h56
-rw-r--r--drivers/stream_input/amports/amstream.c3651
-rw-r--r--drivers/stream_input/amports/amstream_profile.c54
-rw-r--r--drivers/stream_input/parser/esparser.c940
-rw-r--r--drivers/stream_input/parser/esparser.h149
-rw-r--r--drivers/stream_input/parser/psparser.c1160
-rw-r--r--drivers/stream_input/parser/psparser.h141
-rw-r--r--drivers/stream_input/parser/rmparser.c337
-rw-r--r--drivers/stream_input/parser/rmparser.h136
-rw-r--r--drivers/stream_input/parser/streambuf.c418
-rw-r--r--drivers/stream_input/parser/streambuf.h136
-rw-r--r--drivers/stream_input/parser/streambuf_reg.h111
-rw-r--r--drivers/stream_input/parser/thread_rw.c606
-rw-r--r--drivers/stream_input/parser/thread_rw.h52
-rw-r--r--drivers/stream_input/parser/tsdemux.c1131
-rw-r--r--drivers/stream_input/parser/tsdemux.h95
-rw-r--r--firmware/video_ucode.bin8294
92 files changed, 79453 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c9423b3
--- a/dev/null
+++ b/.gitignore
@@ -0,0 +1,101 @@
+#
+# NOTE! Don't add files that are generated in specific
+# subdirectories here. Add them in the ".gitignore" file
+# in that subdirectory instead.
+#
+# NOTE! Please use 'git ls-files -i --exclude-standard'
+# command after changing this file, to see if there are
+# any tracked files which get ignored after the change.
+#
+# Normal rules
+#
+.*
+*.o
+*.o.*
+*.a
+*.s
+*.ko
+*.so
+*.so.dbg
+*.mod.c
+*.i
+*.lst
+*.symtypes
+*.order
+modules.builtin
+*.elf
+#*.bin
+*.gz
+*.bz2
+*.lzma
+*.xz
+*.lz4
+*.lzo
+*.patch
+*.gcno
+
+#
+# Top-level generic files
+#
+/tags
+/TAGS
+/linux
+/vmlinux
+/vmlinuz
+/System.map
+/Module.markers
+Module.symvers
+
+#
+# Debian directory (make deb-pkg)
+#
+/debian/
+
+#
+# git files that we don't want to ignore even it they are dot-files
+#
+!.gitignore
+!.mailmap
+
+#
+# Generated include files
+#
+include/config
+include/generated
+arch/*/include/generated
+
+# stgit generated dirs
+patches-*
+
+# quilt's files
+patches
+series
+
+# cscope files
+cscope.*
+ncscope.*
+
+# gnu global files
+GPATH
+GRTAGS
+GSYMS
+GTAGS
+
+*.orig
+*~
+\#*#
+
+#
+# Leavings from module signing
+#
+extra_certificates
+signing_key.priv
+signing_key.x509
+x509.genkey
+
+# Kconfig presets
+all.config
+
+# customer folder
+customer
+
diff --git a/Media.mk b/Media.mk
new file mode 100644
index 0000000..2dbf863
--- a/dev/null
+++ b/Media.mk
@@ -0,0 +1,91 @@
+KERNEL_ARCH := arm64
+CONFIGS := CONFIG_AMLOGIC_MEDIA_VDEC_MPEG12=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_H264_4K2K=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_VENC_H264=m \
+ CONFIG_AMLOGIC_MEDIA_VECN_H265=m
+
+define copy-media-modules
+$(foreach m, $(shell find $(strip $(1)) -name "*.ko"),\
+ $(shell cp $(m) $(strip $(2)) -rfa))
+endef
+
+ifneq (,$(ANDROID_BUILD_TOP))
+KDIR := $(OUT)/obj/KERNEL_OBJ/
+
+MEDIA_DRIVERS := $(ANDROID_BUILD_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 := $(ANDROID_BUILD_TOP)/$(PRODUCT_OUT)/obj/media_modules
+ifeq (,$(wildcard $(MEDIA_MODULES)))
+$(shell mkdir $(MEDIA_MODULES) -p)
+endif
+
+MODS_OUT := $(ANDROID_BUILD_TOP)/$(TARGET_OUT)/lib
+
+$(shell cp $(MEDIA_DRIVERS)/* $(MEDIA_MODULES) -rfa)
+
+define media-modules
+ @$(MAKE) -C $(KDIR) M=$(MEDIA_MODULES) ARCH=$(KERNEL_ARCH) \
+ CROSS_COMPILE=$(PREFIX_CROSS_COMPILE) $(CONFIGS) \
+ EXTRA_CFLAGS+=-I$(INCLUDE) modules; \
+ find $(MEDIA_MODULES) -name "*.ko" | xargs -i cp {} $(MODS_OUT)
+endef
+
+else
+KDIR := $(PWD)/kernel
+ifeq (,$(wildcard $(KDIR)))
+$(error No find the dir of kernel.)
+endif
+
+MEDIA_DRIVERS := $(PWD)/media_modules/drivers
+ifeq (,$(wildcard $(MEDIA_DRIVERS)))
+$(error No find the dir of drivers.)
+endif
+
+INCLUDE := $(MEDIA_DRIVERS)/include
+ifeq (,$(wildcard $(INCLUDE)))
+$(error No find the dir of include.)
+endif
+
+MODS_OUT ?= $(MEDIA_DRIVERS)/../modules
+ifeq (,$(wildcard $(MODS_OUT)))
+$(shell mkdir $(MODS_OUT) -p)
+endif
+
+TOOLS := /opt/gcc-linaro-5.3-2016.02-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
+
+modules:
+ @$(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."
+ $(call copy-media-modules, $(MEDIA_DRIVERS), $(MODS_OUT))
+
+all: modules copy-modules
+
+clean:
+ $(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..f2a5148
--- a/dev/null
+++ b/drivers/Makefile
@@ -0,0 +1,4 @@
+obj-y += common/
+obj-y += frame_provider/
+obj-y += frame_sink/
+obj-y += stream_input/
diff --git a/drivers/common/Makefile b/drivers/common/Makefile
new file mode 100644
index 0000000..77ce080
--- a/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..f2e7fa6
--- a/dev/null
+++ b/drivers/common/chips/chips.c
@@ -0,0 +1,158 @@
+/*
+ * drivers/amlogic/media/common/arch/chips/chips.c
+ *
+ * Copyright (C) 2016 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+
+#include <linux/amlogic/media/utils/vformat.h>
+#include <linux/amlogic/media/old_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>
+
+#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[] = {
+ {MESON_CPU_MAJOR_ID_M6, "m6"},
+ {MESON_CPU_MAJOR_ID_M6TV, "m6tv"},
+ {MESON_CPU_MAJOR_ID_M6TVL, "m6tvl"},
+ {MESON_CPU_MAJOR_ID_M8, "m8"},
+ {MESON_CPU_MAJOR_ID_MTVD, "mtvd"},
+ {MESON_CPU_MAJOR_ID_M8B, "m8b"},
+ {MESON_CPU_MAJOR_ID_MG9TV, "mg9tv"},
+ {MESON_CPU_MAJOR_ID_M8M2, "m8"},
+ {MESON_CPU_MAJOR_ID_GXBB, "gxbb"},
+ {MESON_CPU_MAJOR_ID_GXTVBB, "gxtvbb"},
+ {MESON_CPU_MAJOR_ID_GXL, "gxl"},
+ {MESON_CPU_MAJOR_ID_GXM, "gxm"},
+ {MESON_CPU_MAJOR_ID_TXL, "txl"},
+ {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_type());
+}
+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_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_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 &current_chip_info;
+}
+EXPORT_SYMBOL(get_current_vdec_chip);
+
diff --git a/drivers/common/chips/chips.h b/drivers/common/chips/chips.h
new file mode 100644
index 0000000..7a9faba
--- a/dev/null
+++ b/drivers/common/chips/chips.h
@@ -0,0 +1,39 @@
+/*
+ * 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 "../firmware/firmware.h"
+#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);
+
+#endif
diff --git a/drivers/common/firmware/Makefile b/drivers/common/firmware/Makefile
new file mode 100644
index 0000000..748039c
--- a/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.h b/drivers/common/firmware/firmware.h
new file mode 100644
index 0000000..b7d56d7
--- a/dev/null
+++ b/drivers/common/firmware/firmware.h
@@ -0,0 +1,113 @@
+/*
+ * 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_HEADER_
+#define __VIDEO_FIRMWARE_HEADER_
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/cdev.h>
+#include "firmware_type.h"
+#include <linux/amlogic/media/utils/vformat.h>
+
+
+struct firmware_mgr_s {
+ struct list_head head;
+ spinlock_t lock;
+};
+
+struct firmware_info_s {
+ struct list_head node;
+ char name[32];
+ char path[64];
+ enum firmware_type_e type;
+ struct firmware_s *data;
+};
+
+struct ucode_info_s {
+ int cpu;
+ enum firmware_type_e type;
+ const char *name;
+};
+
+struct firmware_header_s {
+ int magic;
+ int checksum;
+ char name[32];
+ char cpu[16];
+ char format[32];
+ char version[32];
+ char author[32];
+ char date[32];
+ char commit[16];
+ int data_size;
+ unsigned int time;
+ char reserved[128];
+};
+
+struct firmware_s {
+ union {
+ struct firmware_header_s header;
+ char buf[512];
+ };
+ char data[0];
+};
+
+
+struct package_header_s {
+ int magic;
+ int size;
+ int checksum;
+ char reserved[128];
+};
+
+struct package_s {
+ union {
+ struct package_header_s header;
+ char buf[256];
+ };
+ char data[0];
+};
+
+struct info_header_s {
+ char name[32];
+ char format[32];
+ char cpu[32];
+ int length;
+};
+
+struct package_info_s {
+ union {
+ struct info_header_s header;
+ char buf[256];
+ };
+ char data[0];
+};
+
+
+struct firmware_dev_s {
+ struct cdev cdev;
+ struct device *dev;
+ dev_t dev_no;
+};
+
+int get_decoder_firmware_data(enum vformat_e type,
+ const char *file_name, char *buf, int size);
+int get_data_from_name(const char *name, char *buf);
+int get_firmware_data(enum firmware_type_e type, char *buf);
+
+#endif
diff --git a/drivers/common/firmware/firmware_cfg.h b/drivers/common/firmware/firmware_cfg.h
new file mode 100644
index 0000000..be919ff
--- a/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.*/
+{MESON_CPU_MAJOR_ID_GXBB, VIDEO_PACKAGE, "video_ucode.bin"},
+{MESON_CPU_MAJOR_ID_GXTVBB, VIDEO_PACKAGE, "video_ucode.bin"},
+{MESON_CPU_MAJOR_ID_GXL, VIDEO_PACKAGE, "video_ucode.bin"},
+{MESON_CPU_MAJOR_ID_GXM, VIDEO_PACKAGE, "video_ucode.bin"},
+{MESON_CPU_MAJOR_ID_TXL, VIDEO_PACKAGE, "video_ucode.bin"},
+
+/*firmware for a special format, to replace the format in the package.*/
+{MESON_CPU_MAJOR_ID_GXL, VIDEO_DEC_HEVC, "h265.bin"},
+{MESON_CPU_MAJOR_ID_GXL, VIDEO_DEC_H264, "h264.bin"},
+{MESON_CPU_MAJOR_ID_GXL, VIDEO_DEC_H264_MULTI, "h264_multi.bin"},
+{MESON_CPU_MAJOR_ID_GXM, VIDEO_ENC_H264, "gx_h264_enc.bin"},
+{MESON_CPU_MAJOR_ID_GXL, VIDEO_ENC_H264, "gx_h264_enc.bin"},
+
+
diff --git a/drivers/common/firmware/firmware_drv.c b/drivers/common/firmware/firmware_drv.c
new file mode 100644
index 0000000..56420e1
--- a/dev/null
+++ b/drivers/common/firmware/firmware_drv.c
@@ -0,0 +1,682 @@
+/*
+ * drivers/amlogic/media/common/firmware/firmware.c
+ *
+ * Copyright (C) 2016 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include <linux/amlogic/media/utils/vformat.h>
+#include <linux/amlogic/media/old_cpu_version.h>
+#include "../../stream_input/amports/amports_priv.h"
+#include "../../frame_provider/decoder/utils/vdec.h"
+#include "firmware.h"
+#include "../chips/chips.h"
+#include <linux/string.h>
+#include <linux/amlogic/media/utils/log.h>
+#include <linux/firmware.h>
+#include <linux/amlogic/major.h>
+#include <linux/cdev.h>
+#include <linux/crc32.h>
+
+#define CLASS_NAME "firmware_codec"
+#define DEV_NAME "firmware_vdec"
+#define DIR "video"
+#define FRIMWARE_SIZE (64*1024) /*64k*/
+#define BUFF_SIZE (512*1024)
+
+#define PACK ('P' << 24 | 'A' << 16 | 'C' << 8 | 'K')
+#define CODE ('C' << 24 | 'O' << 16 | 'D' << 8 | 'E')
+
+static DEFINE_MUTEX(mutex);
+
+static struct ucode_info_s ucode_info[] = {
+#include "firmware_cfg.h"
+};
+
+static const struct file_operations firmware_fops = {
+ .owner = THIS_MODULE
+};
+
+struct firmware_mgr_s *g_mgr;
+struct firmware_dev_s *g_dev;
+
+static u32 debug = 0;
+
+int get_firmware_data(enum firmware_type_e type, char *buf)
+{
+ int data_len, ret = -1;
+ struct firmware_mgr_s *mgr = g_mgr;
+ struct firmware_info_s *info;
+
+ if (list_empty(&mgr->head)) {
+ pr_info("the info list is empty.\n");
+ return 0;
+ }
+
+ list_for_each_entry(info, &mgr->head, node) {
+ if (type != info->type)
+ continue;
+
+ data_len = info->data->header.data_size;
+ memcpy(buf, info->data->data, data_len);
+ ret = data_len;
+
+ break;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(get_firmware_data);
+
+int get_data_from_name(const char *name, char *buf)
+{
+ int data_len, ret = -1;
+ struct firmware_mgr_s *mgr = g_mgr;
+ struct firmware_info_s *info;
+ char *firmware_name = __getname();
+
+ if (IS_ERR_OR_NULL(firmware_name))
+ return -ENOMEM;
+
+ strcat(firmware_name, name);
+ strcat(firmware_name, ".bin");
+
+ if (list_empty(&mgr->head)) {
+ pr_info("the info list is empty.\n");
+ return 0;
+ }
+
+ list_for_each_entry(info, &mgr->head, node) {
+ if (strcmp(firmware_name, info->name))
+ continue;
+
+ data_len = info->data->header.data_size;
+ memcpy(buf, info->data->data, data_len);
+ ret = data_len;
+
+ break;
+ }
+
+ __putname(firmware_name);
+
+ return ret;
+}
+EXPORT_SYMBOL(get_data_from_name);
+
+static int request_firmware_from_sys(const char *file_name,
+ char *buf, int size)
+{
+ int ret = -1;
+ const struct firmware *firmware;
+
+ pr_info("Try load %s ...\n", file_name);
+
+ ret = request_firmware(&firmware, file_name, g_dev->dev);
+ if (ret < 0) {
+ pr_info("Error : %d can't load the %s.\n", ret, file_name);
+ goto err;
+ }
+
+ if (firmware->size > size) {
+ pr_info("Not enough memory size for ucode.\n");
+ ret = -ENOMEM;
+ goto release;
+ }
+
+ memcpy(buf, (char *)firmware->data, firmware->size);
+
+ pr_info("load firmware size : %zd, Name : %s.\n",
+ firmware->size, file_name);
+ ret = firmware->size;
+release:
+ release_firmware(firmware);
+err:
+ return ret;
+}
+
+int request_decoder_firmware_on_sys(enum vformat_e type,
+ 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 type,
+ const char *file_name, char *buf, int size)
+{
+ int ret;
+
+ ret = request_decoder_firmware_on_sys(type, file_name, buf, size);
+ if (ret < 0)
+ pr_info("get_decoder_firmware_data %s for format %d failed!\n",
+ file_name, type);
+
+ return ret;
+}
+EXPORT_SYMBOL(get_decoder_firmware_data);
+
+static unsigned long firmware_mgr_lock(struct firmware_mgr_s *mgr)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mgr->lock, flags);
+ return flags;
+}
+
+static void firmware_mgr_unlock(struct firmware_mgr_s *mgr, unsigned long flags)
+{
+ spin_unlock_irqrestore(&mgr->lock, flags);
+}
+
+static void add_info(struct firmware_info_s *info)
+{
+ unsigned long flags;
+ struct firmware_mgr_s *mgr = g_mgr;
+
+ flags = firmware_mgr_lock(mgr);
+ list_add(&info->node, &mgr->head);
+ firmware_mgr_unlock(mgr, flags);
+}
+
+static void del_info(struct firmware_info_s *info)
+{
+ unsigned long flags;
+ struct firmware_mgr_s *mgr = g_mgr;
+
+ flags = firmware_mgr_lock(mgr);
+ list_del(&info->node);
+ firmware_mgr_unlock(mgr, flags);
+}
+
+static void walk_firmware_info(void)
+{
+ struct firmware_mgr_s *mgr = g_mgr;
+ struct firmware_info_s *info;
+
+ if (list_empty(&mgr->head)) {
+ pr_info("the info list is empty.\n");
+ return ;
+ }
+
+ list_for_each_entry(info, &mgr->head, node) {
+ if (IS_ERR_OR_NULL(info->data))
+ continue;
+
+ pr_info("path : %s.\n", info->path);
+ pr_info("name : %s.\n", info->name);
+ pr_info("version : %s.\n",
+ info->data->header.version);
+ pr_info("checksum : 0x%x.\n",
+ info->data->header.checksum);
+ pr_info("data size : %d.\n",
+ info->data->header.data_size);
+ pr_info("author : %s.\n",
+ info->data->header.author);
+ pr_info("date : %s.\n",
+ info->data->header.date);
+ pr_info("commit : %s.\n\n",
+ info->data->header.commit);
+ }
+}
+
+static ssize_t info_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ char *pbuf = buf;
+ struct firmware_mgr_s *mgr = g_mgr;
+ struct firmware_info_s *info;
+
+ if (list_empty(&mgr->head)) {
+ pbuf += sprintf(pbuf, "No firmware.\n");
+ goto out;
+ }
+
+ list_for_each_entry(info, &mgr->head, node) {
+ if (IS_ERR_OR_NULL(info->data))
+ continue;
+
+ pr_info( "%10s : %s\n", "name", info->name);
+ pr_info( "%10s : %d\n", "size",
+ info->data->header.data_size);
+ pr_info( "%10s : %s\n", "ver",
+ info->data->header.version);
+ pr_info( "%10s : 0x%x\n", "sum",
+ info->data->header.checksum);
+ pr_info( "%10s : %s\n", "commit",
+ info->data->header.commit);
+ pr_info( "%10s : %s\n", "author",
+ info->data->header.author);
+ pr_info( "%10s : %s\n\n", "date",
+ info->data->header.date);
+ }
+out:
+ return pbuf - buf;
+}
+
+static int set_firmware_info(void)
+{
+ int ret = 0, i, len;
+ struct firmware_info_s *info;
+ int info_size = ARRAY_SIZE(ucode_info);
+ int cpu = get_cpu_type();
+ char *path = __getname();
+ const char *name;
+
+ if (IS_ERR_OR_NULL(path))
+ return -ENOMEM;
+
+ for (i = 0; i < info_size; i++) {
+ if (cpu != ucode_info[i].cpu)
+ continue;
+
+ 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;
+
+ info = kzalloc(sizeof(struct firmware_info_s), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(info)) {
+ __putname(path);
+ return -ENOMEM;
+ }
+
+ strcpy(info->path, path);
+ strcpy(info->name, name);
+ info->type = ucode_info[i].type;
+ info->data = NULL;
+
+ add_info(info);
+ }
+
+ __putname(path);
+
+ return ret;
+}
+
+static int firmware_probe(char *buf)
+{
+ int magic = 0;
+
+ memcpy(&magic, buf, sizeof(int));
+ return magic;
+}
+
+static int checksum(struct firmware_s *firmware)
+{
+ unsigned int crc;
+
+ crc = crc32_le(~0U, firmware->data, firmware->header.data_size);
+
+ if (debug)
+ pr_info("firmware crc result : 0x%x\n", crc ^ ~0U);
+
+ return firmware->header.checksum != (crc ^ ~0U) ? 0 : 1;
+}
+
+static int check_repeat(struct firmware_s *data, enum firmware_type_e type)
+{
+ struct firmware_mgr_s *mgr = g_mgr;
+ struct firmware_info_s *info;
+
+ if (list_empty(&mgr->head)) {
+ pr_info("the info list is empty.\n");
+ return -1;
+ }
+
+ list_for_each_entry(info, &mgr->head, node) {
+ if (info->type != type)
+ continue;
+
+ if (IS_ERR_OR_NULL(info->data))
+ info->data = data;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static int firmware_parse_package(char *buf, int size)
+{
+ int ret = 0;
+ struct package_info_s *pack_info;
+ struct firmware_info_s *info;
+ struct firmware_s *data;
+ char *pack_data;
+ int info_len, len;
+ char *path = __getname();
+
+ if (IS_ERR_OR_NULL(path))
+ return -ENOMEM;
+
+ pack_data = ((struct package_s *)buf)->data;
+ pack_info = (struct package_info_s *)pack_data;
+ info_len = sizeof(struct package_info_s);
+
+ for (;;) {
+ if (!pack_info->header.length)
+ break;
+
+ len = snprintf(path, PATH_MAX, "%s/%s", DIR,
+ pack_info->header.name);
+ if (len >= PATH_MAX)
+ continue;
+
+ info = kzalloc(sizeof(struct firmware_info_s), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(info)) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ data = kzalloc(FRIMWARE_SIZE, GFP_KERNEL);
+ if (IS_ERR_OR_NULL(data)) {
+ kfree(info);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ strcpy(info->path, path);
+ strcpy(info->name, pack_info->header.name);
+ info->type = get_firmware_type(pack_info->header.format);
+
+ len = pack_info->header.length;
+ memcpy(data, pack_info->data, len);
+
+ pack_data += (pack_info->header.length + info_len);
+ pack_info = (struct package_info_s *)pack_data;
+
+ ret = checksum(data);
+ if (!ret) {
+ pr_info("check sum fail !\n");
+ kfree(data);
+ kfree(info);
+ goto out;
+ }
+
+ ret = check_repeat(data, info->type);
+ if (ret < 0) {
+ kfree(data);
+ kfree(info);
+ goto out;
+ }
+
+ if (ret) {
+ kfree(info);
+ continue;
+ }
+
+ info->data = data;
+ add_info(info);
+ }
+out:
+ __putname(path);
+
+ return ret;
+}
+
+static int firmware_parse_code(struct firmware_info_s *info,
+ char *buf, int size)
+{
+ if (!IS_ERR_OR_NULL(info->data))
+ kfree(info->data);
+
+ info->data = kzalloc(FRIMWARE_SIZE, GFP_KERNEL);
+ if (IS_ERR_OR_NULL(info->data))
+ return -ENOMEM;
+
+ memcpy(info->data, buf, size);
+
+ if (!checksum(info->data)) {
+ pr_info("check sum fail !\n");
+ kfree(info->data);
+ return -1;
+ }
+
+ 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 set_firmware_data(void)
+{
+ int ret = 0, magic = 0;
+ struct firmware_mgr_s *mgr = g_mgr;
+ struct firmware_info_s *info, *temp;
+ char *buf = NULL;
+ int size;
+
+ if (list_empty(&mgr->head)) {
+ pr_info("the info list is empty.\n");
+ return 0;
+ }
+
+ buf = vmalloc(BUFF_SIZE);
+ if (IS_ERR_OR_NULL(buf))
+ return -ENOMEM;
+
+ list_for_each_entry_safe(info, temp, &mgr->head, node) {
+ size = get_firmware_from_sys(info->path, buf, BUFF_SIZE);
+ magic = firmware_probe(buf);
+
+ switch (magic) {
+ case PACK:
+ ret = firmware_parse_package(buf, size);
+
+ del_info(info);
+ kfree(info);
+ break;
+
+ case CODE:
+ ret = firmware_parse_code(info, buf, size);
+ break;
+
+ default:
+ del_info(info);
+ pr_info("invaild type.\n");
+ }
+
+ memset(buf, 0, BUFF_SIZE);
+ }
+
+ if (debug)
+ walk_firmware_info();
+
+ vfree(buf);
+
+ return ret;
+}
+
+static int firmware_pre_load(void)
+{
+ int ret = -1;
+
+ ret = set_firmware_info();
+ if (ret < 0) {
+ pr_info("Get path fail.\n");
+ goto err;
+ }
+
+ ret = set_firmware_data();
+ if (ret < 0) {
+ pr_info("Set data fail.\n");
+ goto err;
+ }
+err:
+ return ret;
+}
+
+static int firmware_mgr_init(void)
+{
+ g_mgr = kzalloc(sizeof(struct firmware_mgr_s), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(g_mgr))
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&g_mgr->head);
+ spin_lock_init(&g_mgr->lock);
+
+ return 0;
+}
+
+static struct class_attribute firmware_class_attrs[] = {
+ __ATTR_RO(info),
+ __ATTR_NULL
+};
+
+static struct class firmware_class = {
+ .name = CLASS_NAME,
+ .class_attrs = firmware_class_attrs,
+};
+
+static int firmware_driver_init(void)
+{
+ int ret = -1;
+
+ g_dev = kzalloc(sizeof(struct firmware_dev_s), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(g_dev))
+ return -ENOMEM;
+
+ g_dev->dev_no = MKDEV(AMSTREAM_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", AMSTREAM_MAJOR);
+ goto err;
+ }
+
+ cdev_init(&g_dev->cdev, &firmware_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(&firmware_class);
+ if (ret < 0) {
+ pr_info("Failed in creating class.\n");
+ goto err;
+ }
+
+ g_dev->dev = device_create(&firmware_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 firmware_info_clean(void)
+{
+ struct firmware_mgr_s *mgr = g_mgr;
+ struct firmware_info_s *info;
+ unsigned long flags;
+
+ flags = firmware_mgr_lock(mgr);
+ while (!list_empty(&mgr->head)) {
+ info = list_entry(mgr->head.next,
+ struct firmware_info_s, node);
+ list_del(&info->node);
+ kfree(info->data);
+ kfree(info);
+ }
+ firmware_mgr_unlock(mgr, flags);
+
+ kfree(g_mgr);
+}
+
+static void firmware_driver_exit(void)
+{
+ cdev_del(&g_dev->cdev);
+ device_destroy(&firmware_class, g_dev->dev_no);
+ class_unregister(&firmware_class);
+ unregister_chrdev_region(g_dev->dev_no, 1);
+ kfree(g_dev);
+}
+
+static int __init firmware_module_init(void)
+{
+ int ret = -1;
+
+ ret = firmware_driver_init();
+ if (ret) {
+ pr_info("Error %d firmware driver init fail.\n", ret);
+ goto err;
+ }
+
+ ret = firmware_mgr_init();
+ if (ret) {
+ pr_info("Error %d firmware mgr init fail.\n", ret);
+ goto err;
+ }
+
+ ret = firmware_pre_load();
+ if (ret) {
+ pr_info("Error %d firmware pre load fail.\n", ret);
+ goto err;
+ }
+err:
+ return ret;
+}
+
+static void __exit firmware_module_exit(void)
+{
+ firmware_info_clean();
+ firmware_driver_exit();
+ pr_info("Firmware driver cleaned up.\n");
+}
+
+module_param(debug, uint, 0664);
+
+module_init(firmware_module_init);
+module_exit(firmware_module_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nanxin Qin <nanxin.qin@amlogic.com>");
diff --git a/drivers/common/firmware/firmware_type.c b/drivers/common/firmware/firmware_type.c
new file mode 100644
index 0000000..cf5e306
--- a/dev/null
+++ b/drivers/common/firmware/firmware_type.c
@@ -0,0 +1,57 @@
+#include "firmware_type.h"
+
+static const struct type_name_s type_name[] = {
+ {VIDEO_DEC_MPEG12, "mpeg12"},
+ {VIDEO_DEC_MPEG4_3, "divx311"},
+ {VIDEO_DEC_MPEG4_4, "divx4x"},
+ {VIDEO_DEC_MPEG4_5, "xvid"},
+ {VIDEO_DEC_H263, "h263"},
+ {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_AVS, "avs"},
+ {VIDEO_DEC_H264, "h264"},
+ {VIDEO_DEC_H264_4k2K, "h264_4k2k"},
+ {VIDEO_DEC_H264_4k2K_SINGLE, "h264_4k2k_single"},
+ {VIDEO_DEC_H264_MVC, "h264_mvc"},
+ {VIDEO_DEC_H264_MULTI, "h264_multi"},
+ {VIDEO_DEC_HEVC, "hevc"},
+ {VIDEO_DEC_HEVC_MMU, "hevc_mmu"},
+ {VIDEO_DEC_VP9, "vp9"},
+ {VIDEO_DEC_VP9_MMU, "vp9_mmu"},
+ {VIDEO_ENC_H264, "h264_enc"},
+ {VIDEO_ENC_JPEG, "jpeg_enc"},
+ {FIRMWARE_MAX, "unknown"},
+};
+
+
+const char *get_firmware_type_name(enum firmware_type_e type)
+{
+ const char *name = "unknown";
+ int i, size = ARRAY_SIZE(type_name);
+
+ for (i = 0; i < size; i++) {
+ if (type == type_name[i].type)
+ name = type_name[i].name;
+ }
+
+ return name;
+}
+EXPORT_SYMBOL(get_firmware_type_name);
+
+enum firmware_type_e get_firmware_type(const char *name)
+{
+ enum firmware_type_e type = FIRMWARE_MAX;
+ int i, size = ARRAY_SIZE(type_name);
+
+ for (i = 0; i < size; i++) {
+ if (!strcmp(name, type_name[i].name))
+ type = type_name[i].type;
+ }
+
+ return type;
+}
+EXPORT_SYMBOL(get_firmware_type);
+
diff --git a/drivers/common/firmware/firmware_type.h b/drivers/common/firmware/firmware_type.h
new file mode 100644
index 0000000..74c962f
--- a/dev/null
+++ b/drivers/common/firmware/firmware_type.h
@@ -0,0 +1,41 @@
+#ifndef __VIDEO_FIRMWARE_FORMAT_
+#define __VIDEO_FIRMWARE_FORMAT_
+
+#include <linux/slab.h>
+
+enum firmware_type_e {
+ VIDEO_DEC_MPEG12,
+ VIDEO_DEC_MPEG4_3,
+ VIDEO_DEC_MPEG4_4,
+ VIDEO_DEC_MPEG4_5,
+ VIDEO_DEC_H263,
+ VIDEO_DEC_MJPEG,
+ VIDEO_DEC_MJPEG_MULTI,
+ VIDEO_DEC_REAL_V8,
+ VIDEO_DEC_REAL_V9,
+ VIDEO_DEC_VC1,
+ VIDEO_DEC_AVS,
+ VIDEO_DEC_H264,
+ VIDEO_DEC_H264_4k2K,
+ VIDEO_DEC_H264_4k2K_SINGLE,
+ VIDEO_DEC_H264_MVC,
+ VIDEO_DEC_H264_MULTI,
+ VIDEO_DEC_HEVC,
+ VIDEO_DEC_HEVC_MMU,
+ VIDEO_DEC_VP9,
+ VIDEO_DEC_VP9_MMU,
+ VIDEO_ENC_H264,
+ VIDEO_ENC_JPEG,
+ VIDEO_PACKAGE,
+ FIRMWARE_MAX
+};
+
+struct type_name_s {
+ enum firmware_type_e type;
+ const char *name;
+};
+
+const char *get_firmware_type_name(enum firmware_type_e type);
+enum firmware_type_e get_firmware_type(const char *name);
+
+#endif
diff --git a/drivers/common/media_clock/Makefile b/drivers/common/media_clock/Makefile
new file mode 100644
index 0000000..25c9a10
--- a/dev/null
+++ b/drivers/common/media_clock/Makefile
@@ -0,0 +1,5 @@
+obj-m += media_clock.o
+media_clock-objs += ../chips/chips.o
+media_clock-objs += clk/clkgx.o
+media_clock-objs += clk/clk.o
+media_clock-objs += switch/amports_gate.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..18d308f
--- a/dev/null
+++ b/drivers/common/media_clock/clk/clk.c
@@ -0,0 +1,405 @@
+/*
+ * drivers/amlogic/media/common/arch/clk/clk.c
+ *
+ * Copyright (C) 2016 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+
+#include <linux/amlogic/media/utils/vformat.h>
+#include <linux/amlogic/media/old_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>
+
+#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])
+
+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_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_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) {
+ ret_clk = hevc_clock_set(clk);
+ clock_source_wxhxfps_saved[VDEC_HEVC] = 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_type() == 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_type() || vdec_type >= VDEC_MAX) {
+ /*
+ *pr_info("ignore vdec clk mgr for vdec[%d] cpu=%d\n",
+ *vdec_type, cputype);
+ */
+ return 0; /* ignore don't needed firmare. */
+ }
+ mgr = kmalloc(sizeof(struct chip_vdec_clk_s), GFP_KERNEL);
+ if (!mgr)
+ return -ENOMEM;
+ *mgr = *t_mgr;
+ /*
+ *pr_info("register vdec clk mgr for vdec[%d]\n", vdec_type);
+ */
+ if (mgr->clock_init) {
+ if (mgr->clock_init()) {
+ kfree(mgr);
+ return -ENOMEM;
+ }
+ }
+ get_current_vdec_chip()->clk_mgr[vdec_type] = mgr;
+ return 0;
+}
+
+int register_vdec_clk_mgr(int cputype[], enum vdec_type_e vdec_type,
+ struct chip_vdec_clk_s *t_mgr)
+{
+ int i = 0;
+
+ while (cputype[i] > 0) {
+ register_vdec_clk_mgr_per_cpu(cputype[i], vdec_type, t_mgr);
+ i++;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(register_vdec_clk_mgr);
+
+int unregister_vdec_clk_mgr(enum vdec_type_e vdec_type)
+{
+ kfree(get_current_vdec_chip()->clk_mgr[vdec_type]);
+
+ return 0;
+}
+EXPORT_SYMBOL(unregister_vdec_clk_mgr);
+
+static int register_vdec_clk_setting_per_cpu(int cputype,
+ struct clk_set_setting *setting, int size)
+{
+
+ struct clk_set_setting *p_setting;
+
+ if (cputype != get_cpu_type()) {
+ /*
+ *pr_info("ignore clk_set_setting for cpu=%d\n",
+ *cputype);
+ */
+ return 0; /* ignore don't needed this setting . */
+ }
+ p_setting = kmalloc(size, GFP_KERNEL);
+ if (!p_setting)
+ return -ENOMEM;
+ memcpy(p_setting, setting, size);
+
+ pr_info("register clk_set_setting cpu[%d]\n", cputype);
+
+ get_current_vdec_chip()->clk_setting_array = p_setting;
+ return 0;
+}
+
+int register_vdec_clk_setting(int cputype[],
+ struct clk_set_setting *p_seting, int size)
+{
+ int i = 0;
+
+ while (cputype[i] > 0) {
+ register_vdec_clk_setting_per_cpu(cputype[i], p_seting, size);
+ i++;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(register_vdec_clk_setting);
+
+int unregister_vdec_clk_setting(void)
+{
+ kfree(get_current_vdec_chip()->clk_setting_array);
+
+ return 0;
+}
+EXPORT_SYMBOL(unregister_vdec_clk_setting);
+
diff --git a/drivers/common/media_clock/clk/clk.h b/drivers/common/media_clock/clk/clk.h
new file mode 100644
index 0000000..1c979b4
--- a/dev/null
+++ b/drivers/common/media_clock/clk/clk.h
@@ -0,0 +1,155 @@
+/*
+ * 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 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,
+};
+#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);
+#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)
+
+#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..1898e6d
--- a/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/clkgx.c b/drivers/common/media_clock/clk/clkgx.c
new file mode 100644
index 0000000..8520738
--- a/dev/null
+++ b/drivers/common/media_clock/clk/clkgx.c
@@ -0,0 +1,620 @@
+/*
+ * 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.
+ *
+*/
+
+#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"
+#define MHz (1000000)
+
+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 clk_mux_s gclk;
+
+void vdec1_set_clk(int source, int div)
+{
+ pr_info("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);
+
+void hevc_set_clk(int source, int div)
+{
+ pr_info("hevc_set_clk %d, %d\n", source, div);
+ WRITE_HHI_REG_BITS(HHI_VDEC2_CLK_CNTL,
+ (source << 9) | (div - 1), 16, 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);
+
+/* 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_VDEC4_CLK_CNTL, 0, 31, 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);\
+ } while (0)
+
+#define HEVC_CLOCK_OFF() WRITE_HHI_REG_BITS(HHI_VDEC2_CLK_CNTL, 0, 24, 1)
+
+static int clock_real_clk[VDEC_MAX + 1];
+
+/*
+*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},
+ }
+ },
+
+};
+
+void set_clock_gate(struct gate_switch_node *nodes, int num)
+{
+ struct gate_switch_node *node = NULL;
+
+ do {
+ node = &nodes[num - 1];
+ if (IS_ERR_OR_NULL(node))
+ 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, "clk_hevc_mux"))
+ gclk.hevc_mux_node = node;
+ } while(--num);
+}
+EXPORT_SYMBOL(set_clock_gate);
+
+static int vdec_set_clk(int dec, int rate)
+{
+ struct clk *clk = NULL;
+
+ switch (dec) {
+ case VDEC_1:
+ clk = gclk.vdec_mux_node->clk;
+ WRITE_VREG_BITS(DOS_GCLK_EN0, 0x3ff, 0, 10);
+ break;
+
+ case VDEC_HCODEC:
+ clk = gclk.hcodec_mux_node->clk;
+ WRITE_VREG_BITS(DOS_GCLK_EN0, 0x7fff, 12, 15);
+ break;
+
+ case VDEC_2:
+ clk = gclk.vdec_mux_node->clk;
+ WRITE_VREG(DOS_GCLK_EN1, 0x3ff);
+ break;
+
+ case VDEC_HEVC:
+ clk = gclk.hevc_mux_node->clk;
+ WRITE_VREG(DOS_GCLK_EN3, 0xffffffff);
+ break;
+
+ case VDEC_MAX:
+ break;
+
+ default:
+ pr_info("invaild vdec type.\n");
+ }
+
+ if (IS_ERR_OR_NULL(clk)) {
+ pr_info("the mux clk err.\n");
+ return -1;
+ }
+
+ clk_set_rate(clk, rate);
+
+ return 0;
+}
+
+static int vdec_clock_init(void)
+{
+ return 0;
+}
+
+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;
+ }
+
+ vdec_set_clk(VDEC_1, clk * MHz);
+
+ clock_real_clk[VDEC_1] = clk;
+
+ pr_info("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_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;
+ clk = 667;
+ }
+
+ vdec_set_clk(VDEC_HEVC, clk * MHz);
+
+ clock_real_clk[VDEC_HEVC] = clk;
+
+ pr_info("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_info("hcodec mux clock is %lu Hz\n",
+ clk_get_rate(gclk.hcodec_mux_node->clk));
+
+ return clk;
+}
+
+static void vdec_clock_on(void)
+{
+ spin_lock_irqsave(&gclk.vdec_mux_node->lock,
+ gclk.vdec_mux_node->flags);
+ if (!gclk.vdec_mux_node->ref_count)
+ clk_prepare_enable(gclk.vdec_mux_node->clk);
+
+ gclk.vdec_mux_node->ref_count++;
+ spin_unlock_irqrestore(&gclk.vdec_mux_node->lock,
+ gclk.vdec_mux_node->flags);
+
+ pr_info("the %-15s clock off, ref cnt: %d\n",
+ gclk.vdec_mux_node->name,
+ gclk.vdec_mux_node->ref_count);
+}
+
+static void vdec_clock_off(void)
+{
+ spin_lock_irqsave(&gclk.vdec_mux_node->lock,
+ gclk.vdec_mux_node->flags);
+ 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;
+ spin_unlock_irqrestore(&gclk.vdec_mux_node->lock,
+ gclk.vdec_mux_node->flags);
+
+ pr_info("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)
+{
+ spin_lock_irqsave(&gclk.hcodec_mux_node->lock,
+ gclk.hcodec_mux_node->flags);
+ if (!gclk.hcodec_mux_node->ref_count)
+ clk_prepare_enable(gclk.hcodec_mux_node->clk);
+
+ gclk.hcodec_mux_node->ref_count++;
+ spin_unlock_irqrestore(&gclk.hcodec_mux_node->lock,
+ gclk.hcodec_mux_node->flags);
+
+ pr_info("the %-15s clock off, ref cnt: %d\n",
+ gclk.hcodec_mux_node->name,
+ gclk.hcodec_mux_node->ref_count);
+}
+
+static void hcodec_clock_off(void)
+{
+ spin_lock_irqsave(&gclk.hcodec_mux_node->lock,
+ gclk.hcodec_mux_node->flags);
+ gclk.hcodec_mux_node->ref_count--;
+ if (!gclk.hcodec_mux_node->ref_count)
+ clk_disable_unprepare(gclk.hcodec_mux_node->clk);
+
+ spin_unlock_irqrestore(&gclk.hcodec_mux_node->lock,
+ gclk.hcodec_mux_node->flags);
+
+ pr_info("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)
+{
+ spin_lock_irqsave(&gclk.hevc_mux_node->lock,
+ gclk.hevc_mux_node->flags);
+ 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);
+ spin_unlock_irqrestore(&gclk.hevc_mux_node->lock,
+ gclk.hevc_mux_node->flags);
+
+ pr_info("the %-15s clock off, ref cnt: %d\n",
+ gclk.hevc_mux_node->name,
+ gclk.hevc_mux_node->ref_count);
+}
+
+static void hevc_clock_off(void)
+{
+ spin_lock_irqsave(&gclk.hevc_mux_node->lock,
+ gclk.hevc_mux_node->flags);
+ 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;
+ spin_unlock_irqrestore(&gclk.hevc_mux_node->lock,
+ gclk.hevc_mux_node->flags);
+
+ pr_info("the %-15s clock off, ref cnt: %d\n",
+ gclk.hevc_mux_node->name,
+ gclk.hevc_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 {\
+ MESON_CPU_MAJOR_ID_GXBB,\
+ MESON_CPU_MAJOR_ID_GXTVBB,\
+ MESON_CPU_MAJOR_ID_GXL,\
+ MESON_CPU_MAJOR_ID_GXM,\
+ MESON_CPU_MAJOR_ID_TXL,\
+ 0}
+#include "clk.h"
+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..ade914a
--- a/dev/null
+++ b/drivers/common/media_clock/switch/amports_gate.c
@@ -0,0 +1,189 @@
+/*
+ * 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.
+ *
+*/
+#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_vdec_mux",
+ },
+ {
+ .name = "clk_hcodec_mux",
+ },
+ {
+ .name = "clk_hevc_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_HEVC_MUX>;
+ clock-names = "parser_top",
+ "demux",
+ "vdec",
+ "clk_vdec_mux",
+ "clk_hcodec_mux",
+ "clk_hevc_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;
+ spin_lock_init(&gates[i].lock);
+ }
+
+ 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)
+{
+ spin_lock_irqsave(&gate_node->lock, gate_node->flags);
+ if (enable) {
+ if (gate_node->ref_count == 0)
+ clk_prepare_enable(gate_node->clk);
+
+ gate_node->ref_count++;
+
+ if (DEBUG_REF)
+ pr_info("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_info("the %-15s clock off, ref cnt: %d\n",
+ gate_node->name, gate_node->ref_count);
+ }
+ spin_unlock_irqrestore(&gate_node->lock, gate_node->flags);
+ 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);
+
+static int amports_switch_gate(struct gate_switch_node *gate_node, int enable)
+{
+ return 0;
+}
+
+int amports_switch_gate(const char *name, int enable)
+{
+ amports_switch_gate(0, 0);
+ 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..75270ab
--- a/dev/null
+++ b/drivers/common/media_clock/switch/amports_gate.h
@@ -0,0 +1,33 @@
+/*
+ * 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;
+ spinlock_t lock;
+ unsigned long flags;
+ int ref_count;
+};
+
+extern int amports_clock_gate_init(struct device *dev);
+extern int amports_switch_gate(const char *name, int enable);
+
+#endif
diff --git a/drivers/frame_provider/Makefile b/drivers/frame_provider/Makefile
new file mode 100644
index 0000000..371e088
--- a/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..3a5774a
--- a/dev/null
+++ b/drivers/frame_provider/decoder/Makefile
@@ -0,0 +1,16 @@
+obj-y += utils/
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_MPEG12) += mpeg12/vmpeg12.o
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_MPEG4) += mpeg4/vmpeg4.o
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_MPEG4_MULTI) += mpeg4/vmpeg4_multi.o
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_VC1) += vc1/vvc1.o
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_H264) += h264/vh264.o
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_H264_MULTI) += h264_multi/
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_H264_MVC) += h264/vh264_mvc.o
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_H264_4K2K) += h264/vh264_4k2k.o
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_H264_MVC) += h264/vh264_mvc.o
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_H265) += h265/vh265.o
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_VP9) += vp9/vvp9.o
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_MJPEG) += mjpeg/vmjpeg.o
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_MJPEG_MULTI) += mjpeg/vmjpeg_multi.o
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_REAL) += real/vreal.o
+obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_AVS) += avs/
diff --git a/drivers/frame_provider/decoder/avs/Makefile b/drivers/frame_provider/decoder/avs/Makefile
new file mode 100644
index 0000000..cf154c9
--- a/dev/null
+++ b/drivers/frame_provider/decoder/avs/Makefile
@@ -0,0 +1,2 @@
+obj-m += vavs.o
+vavs-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..aed8497
--- a/dev/null
+++ b/drivers/frame_provider/decoder/avs/avs.c
@@ -0,0 +1,1541 @@
+/*
+ * 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/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/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/parser/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"
+
+#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 VPP_VD1_POSTBLEND (1 << 10)
+
+static int debug_flag;
+
+static int firmware_sel; /* 0, normal; 1, old ucode */
+
+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_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,
+ .vf_states = vavs_vf_states,
+};
+
+static struct vframe_provider_s vavs_vf_prov;
+
+#define VF_BUF_NUM_MAX 16
+
+/*static u32 vf_buf_num = 4*/
+static u32 vf_buf_num = 4;
+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 u32 work_buf_size;
+
+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 unsigned long buf_start;
+static u32 buf_size, 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;
+
+#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;
+
+#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 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 */
+ 96000 / 24, /* 24000/1001 (23.967) */
+ 96000 / 24,
+ 96000 / 25,
+ 96000 / 30, /* 30000/1001 (29.97) */
+ 96000 / 30,
+ 96000 / 50,
+ 96000 / 60, /* 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 *duration)
+{
+ int ar = 0;
+
+ unsigned 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;
+ }
+
+ 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;
+}
+
+#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 picture_struct;
+ unsigned int pts, pts_valid = 0, offset;
+ 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
+ schedule_work(&long_cabac_wd_work);
+ }
+#endif
+ reg = READ_VREG(AVS_BUFFEROUT);
+
+ if (reg) {
+ picture_struct = READ_VREG(AV_SCRATCH_5);
+ if (debug_flag & AVS_DEBUG_PRINT)
+ pr_info("AVS_BUFFEROUT=%x, picture_struct is 0x%x\n",
+ reg, picture_struct);
+ 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(PTS_TYPE_VIDEO, offset, &pts, 0)
+ == 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) & 3;
+
+ 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 (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) { /* 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 ((I_PICTURE == picture_type) && pts_valid) {
+ vf->pts = pts;
+ 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 ((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;
+ 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);
+ }
+
+ vfbuf_use[buffer_index]++;
+
+ kfifo_put(&display_q,
+ (const struct vframe_s *)vf);
+ 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;
+
+ vf->pts = next_pts;
+ 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;
+ 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;
+ vfbuf_use[buffer_index]++;
+
+ kfifo_put(&display_q,
+ (const struct vframe_s *)vf);
+ 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 ((I_PICTURE == picture_type) && 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 ((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;
+ if (debug_flag & AVS_DEBUG_PRINT) {
+ pr_info("buffer_index %d, canvas addr %x\n",
+ buffer_index, vf->canvas0Addr);
+ }
+
+ vfbuf_use[buffer_index]++;
+ kfifo_put(&display_q,
+ (const struct vframe_s *)vf);
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY,
+ NULL);
+ total_frame++;
+ }
+
+ /* 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 uint long_cabac_busy;
+
+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);
+
+}
+
+int vavs_dec_status(struct vdec_s *vdec, struct vdec_status *vstatus)
+{
+ vstatus->width = frame_width; /* vavs_amstream_dec_info.width; */
+ vstatus->height = frame_height; /* vavs_amstream_dec_info.height; */
+ if (0 != frame_dur /*vavs_amstream_dec_info.rate */)
+ vstatus->fps = 96000 / frame_dur;
+ else
+ vstatus->fps = 96000;
+ vstatus->error_count = READ_VREG(AVS_ERROR_COUNT);
+ vstatus->status = stat;
+
+ return 0;
+}
+
+/****************************************/
+static void vavs_canvas_init(void)
+{
+ int i;
+ u32 canvas_width, canvas_height;
+ u32 decbuf_size, decbuf_y_size, decbuf_uv_size;
+ u32 disp_addr = 0xffffffff;
+ int vf_buf_num_avail = 0;
+ 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;
+ vf_buf_num_avail =
+ ((buf_size - work_buf_size) / decbuf_size) - 1;
+ pr_info
+ ("avs(SD):buf_start %p, size %x, offset %x avail %d\n",
+ (void *)buf_start, buf_size, buf_offset,
+ vf_buf_num_avail);
+ } else {
+ /* HD & SD */
+ canvas_width = 1920;
+ canvas_height = 1088;
+ decbuf_y_size = 0x200000;
+ decbuf_uv_size = 0x80000;
+ decbuf_size = 0x300000;
+ vf_buf_num_avail =
+ ((buf_size - work_buf_size) / decbuf_size) - 1;
+ pr_info("avs: buf_start %p, buf_size %x, buf_offset %x buf avail %d\n",
+ (void *)buf_start, buf_size, buf_offset,
+ vf_buf_num_avail);
+ }
+ if (vf_buf_num_used > vf_buf_num_avail)
+ vf_buf_num_used = vf_buf_num_avail;
+
+ if (firmware_sel == 0)
+ buf_offset = buf_offset + ((vf_buf_num_used + 1) * decbuf_size);
+
+ if (READ_MPEG_REG(VPP_MISC) & VPP_VD1_POSTBLEND) {
+ struct canvas_s cur_canvas;
+
+ canvas_read((READ_MPEG_REG(VD1_IF0_CANVAS0) & 0xff),
+ &cur_canvas);
+ disp_addr = (cur_canvas.addr + 7) >> 3;
+ }
+
+ for (i = 0; i < vf_buf_num_used; i++) {
+ if (((buf_start + i * decbuf_size + 7) >> 3) == disp_addr) {
+#ifdef NV21
+ canvas_config(canvas_base + canvas_num * i + 0,
+ buf_start +
+ vf_buf_num_used * decbuf_size,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+ canvas_config(canvas_base + canvas_num * i + 1,
+ buf_start +
+ vf_buf_num_used * decbuf_size +
+ decbuf_y_size, canvas_width,
+ canvas_height / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+#else
+ canvas_config(canvas_num * i + 0,
+ buf_start + 4 * decbuf_size,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+ canvas_config(canvas_num * i + 1,
+ buf_start + 4 * decbuf_size +
+ decbuf_y_size, canvas_width / 2,
+ canvas_height / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+ canvas_config(canvas_num * i + 2,
+ buf_start + 4 * decbuf_size +
+ decbuf_y_size + decbuf_uv_size,
+ canvas_width / 2, canvas_height / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+#endif
+ if (debug_flag & AVS_DEBUG_PRINT) {
+ pr_info("canvas config %d, addr %p\n",
+ vf_buf_num_used,
+ (void *)(buf_start +
+ vf_buf_num_used * decbuf_size));
+ }
+
+ } else {
+#ifdef NV21
+ canvas_config(canvas_base + canvas_num * i + 0,
+ buf_start + i * decbuf_size,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+ canvas_config(canvas_base + canvas_num * i + 1,
+ buf_start + i * decbuf_size +
+ decbuf_y_size, canvas_width,
+ canvas_height / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+#else
+ canvas_config(canvas_num * i + 0,
+ buf_start + i * decbuf_size,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+ canvas_config(canvas_num * i + 1,
+ buf_start + i * decbuf_size +
+ decbuf_y_size, canvas_width / 2,
+ canvas_height / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+ canvas_config(canvas_num * i + 2,
+ buf_start + i * decbuf_size +
+ decbuf_y_size + decbuf_uv_size,
+ canvas_width / 2, canvas_height / 2,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+#endif
+ if (debug_flag & AVS_DEBUG_PRINT) {
+ pr_info("canvas config %d, addr %p\n", i,
+ (void *)(buf_start +
+ i * decbuf_size));
+ }
+ }
+ }
+}
+
+void vavs_recover(void)
+{
+ 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)
+ WRITE_VREG(AV_SCRATCH_5, 0);
+
+ 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
+
+}
+
+static void vavs_prot_init(void)
+{
+#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_MPEG_REG(RESET0_REGISTER,
+ RESET_IQIDCT | RESET_MC | RESET_VLD_PART);
+ READ_MPEG_REG(RESET0_REGISTER);
+ WRITE_MPEG_REG(RESET0_REGISTER,
+ RESET_IQIDCT | RESET_MC | RESET_VLD_PART);
+
+ WRITE_MPEG_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);
+ /*************************************************************/
+
+ vavs_canvas_init();
+ if (firmware_sel == 0)
+ WRITE_VREG(AV_SCRATCH_5, 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_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 */
+ 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
+}
+
+#if 0
+#ifdef AVSP_LONG_CABAC
+static unsigned char es_write_addr[MAX_CODED_FRAME_SIZE] __aligned(64);
+#endif
+#endif
+
+static void vavs_local_init(void)
+{
+ int i;
+
+ 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
+ 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;
+
+}
+
+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();
+
+ 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();
+ vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_RESET, NULL);
+ vavs_local_init();
+ vavs_recover();
+ 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 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 (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();
+ vf_reg_provider(&vavs_vf_prov);
+#endif
+ vavs_recover();
+ amvdec_start();
+ mutex_unlock(&vavs_mutex);
+ } else {
+ vavs_local_reset();
+ }
+ }
+ }
+#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)) {
+ 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);
+ }
+
+ }
+
+ 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
+
+#if 0
+#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
+#endif
+
+static s32 vavs_init(void)
+{
+ int 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();
+
+ size = get_firmware_data(VIDEO_DEC_AVS, buf);
+ if (size < 0) {
+ pr_err("get firmware fail.");
+ vfree(buf);
+ return -1;
+ }
+
+ if (amvdec_loadmc_ex(VFORMAT_AVS, NULL, buf) < 0) {
+ amvdec_disable();
+ vfree(buf);
+ return -EBUSY;
+ }
+
+ vfree(buf);
+
+ stat |= STAT_MC_LOAD;
+
+ /* enable AMRISC side protocol */
+ vavs_prot_init();
+
+#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
+
+ vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)((unsigned long)
+ vavs_amstream_dec_info.rate));
+
+ 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
+
+ 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_type() >= MESON_CPU_MAJOR_ID_GXM)
+ firmware_sel = 1;
+
+ if (firmware_sel == 1) {
+ vf_buf_num = 4;
+ canvas_base = 0;
+ canvas_num = 3;
+ } else {
+ /*if(vf_buf_num <= 4)
+ canvas_base = 0;
+ else */
+ canvas_base = 128;
+ canvas_num = 2; /*NV21*/
+ }
+
+#ifdef AVSP_LONG_CABAC
+ buf_start = pdata->mem_start;
+ buf_size = pdata->mem_end - pdata->mem_start + 1
+ - (MAX_CODED_FRAME_SIZE * 2)
+ - LOCAL_HEAP_SIZE;
+ avsp_heap_adr = codec_mm_phys_to_virt(
+ pdata->mem_start + buf_size);
+#else
+ buf_start = pdata->mem_start;
+ buf_size = pdata->mem_end - pdata->mem_start + 1;
+#endif
+
+ if (buf_start > ORI_BUFFER_START_ADDR)
+ buf_offset = buf_start - ORI_BUFFER_START_ADDR;
+ else
+ buf_offset = buf_start;
+
+ 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;
+
+ if (vavs_init() < 0) {
+ pr_info("amvdec_avs init failed.\n");
+
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int amvdec_avs_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 *)vavs_dec_id);
+ stat &= ~STAT_ISR_REG;
+ }
+
+ if (stat & STAT_TIMER_ARM) {
+ del_timer_sync(&recycle_timer);
+ 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 (stat & STAT_VF_HOOK) {
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_FR_END_HINT, NULL);
+
+ vf_unreg_provider(&vavs_vf_prov);
+ stat &= ~STAT_VF_HOOK;
+ }
+
+ amvdec_disable();
+
+ pic_type = 0;
+#ifdef DEBUG_PTS
+ pr_info("pts hit %d, pts missed %d, i hit %d, missed %d\n", pts_hit,
+ pts_missed, pts_i_hit, pts_i_missed);
+ pr_info("total frame %d, avi_flag %d, rate %d\n", total_frame, avi_flag,
+ vavs_amstream_dec_info.rate);
+#endif
+
+ return 0;
+}
+
+/****************************************/
+
+static struct platform_driver amvdec_avs_driver = {
+ .probe = amvdec_avs_probe,
+ .remove = amvdec_avs_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ }
+};
+
+static struct codec_profile_t amvdec_avs_profile = {
+ .name = "avs",
+ .profile = ""
+};
+
+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_type() >= MESON_CPU_MAJOR_ID_GXBB)
+ amvdec_avs_profile.profile = "avs+";
+
+ vcodec_profile_register(&amvdec_avs_profile);
+
+ 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(work_buf_size, uint, 0664);
+MODULE_PARM_DESC(work_buf_size, "\nwork_buf_size\n");
+
+module_param(firmware_sel, uint, 0664);
+MODULE_PARM_DESC(firmware_sel, "\firmware_sel\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..d415645
--- a/dev/null
+++ b/drivers/frame_provider/decoder/avs/avs.h
@@ -0,0 +1,70 @@
+#ifndef AVS_H_
+#define AVS_H_
+
+#define AVSP_LONG_CABAC
+/*#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..3c7f3ab
--- a/dev/null
+++ b/drivers/frame_provider/decoder/avs/avsp_trans.c
@@ -0,0 +1,4944 @@
+#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/parser/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;
+int es_buf_ptr;
+int es_write_addr;
+#else
+FILE *f_es;
+#endif
+int es_ptr;
+unsigned int es_res;
+int es_res_ptr;
+unsigned int previous_es;
+
+void init_es(void)
+{
+
+#ifdef AVSP_LONG_CABAC
+ es_write_addr = des_start;
+ 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
+ es_buf[es_buf_ptr++] = wr_es_data;
+#else
+ putc(wr_es_data, f_es);
+#endif
+ es_ptr++;
+ previous_es = ((previous_es << 8) | wr_es_data)
+ & 0xffff;
+ }
+
+ }
+}
+
+#define MIN_QP 0
+#define MAX_QP 63
+
+#ifdef BLOCK_SIZE
+#undef BLOCK_SIZE
+#endif
+
+#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;
+ int mbaddr_a, mbaddr_b, mbaddr_c, mbaddr_d;
+ 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:lenght 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:lenght 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:lenght 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;
+ else {
+ 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;
+ else {
+ 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");
+ }
+ 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 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");
+ }
+
+#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");
+ }
+ }
+#endif
+ return part_arr;
+}
+
+void 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"
+ );
+ if (1) {
+
+ currslice->mot_ctx = create_contexts_motioninfo();
+ currslice->tex_ctx = create_contexts_textureinfo();
+ }
+#if LIWR_FIX
+ currslice->max_part_nr = 1;
+#else
+ currslice->max_part_nr = 3;
+#endif
+ currslice->part_arr = alloc_partition(currslice->max_part_nr);
+}
+
+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");
+ (*array2D)[0] = (int *)local_alloc(rows * columns, sizeof(int));
+ if ((*array2D)[0] == NULL)
+ no_mem_exit("get_mem2Dint: array2D");
+
+ for (i = 1; i < rows; i++)
+ (*array2D)[i] = (*array2D)[i - 1] + columns;
+
+ return rows * columns * sizeof(int);
+}
+
+void initial_decode(void)
+{
+ int i, j;
+ int img_height = (vertical_size + img->auto_crop_bottom);
+ int memory_size = 0;
+
+ malloc_slice(img);
+ 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");
+
+ if (progressive_sequence)
+ memory_size += get_mem2Dint(&(img->ipredmode),
+ img->width / B8_SIZE * 2 + 4,
+ vertical_size / B8_SIZE * 2 + 4);
+ else
+ memory_size += get_mem2Dint(&(img->ipredmode),
+ img->width / B8_SIZE * 2 + 4,
+ (vertical_size + 32) / (2 * B8_SIZE) * 4 + 4);
+
+ 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;
+
+}
+
+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 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
+
+ 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 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;
+ es_buf = es_write_addr_virt;
+
+ if (local_heap_init(MAX_CODED_FRAME_SIZE * 4) < 0)
+ return -1;
+
+ img = (struct img_par *)local_alloc(1, sizeof(struct img_par));
+ if (img == NULL)
+ no_mem_exit("main: img");
+ stat_bits_ptr = (struct stat_bits *)local_alloc(1,
+ sizeof(struct stat_bits));
+ if (stat_bits_ptr == NULL)
+ no_mem_exit("main: stat_bits");
+
+ curr_stream = alloc_bitstream();
+
+ 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;
+
+ 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);
+
+ initial_decode();
+
+ 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);
+ read_one_macroblock(img);
+ 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 (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
+ WRITE_VREG(LONG_CABAC_REQ, 0);
+ }
+#else
+ fclose(f_es);
+#endif
+
+ local_heap_uninit();
+#ifdef PERFORMANCE_DEBUG
+ pr_info("exit %s\r\n", __func__);
+#endif
+ return (transcoding_error_flag == 0) ? 0 : -1;
+}
+#endif
diff --git a/drivers/frame_provider/decoder/h264/vh264.c b/drivers/frame_provider/decoder/h264/vh264.c
new file mode 100644
index 0000000..732ee5b
--- a/dev/null
+++ b/drivers/frame_provider/decoder/h264/vh264.c
@@ -0,0 +1,2960 @@
+/*
+ * 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.
+ *
+*/
+
+#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 <linux/amlogic/media/codec_mm/codec_mm.h>
+
+#include "../utils/vdec.h"
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "../utils/amvdec.h"
+#include "../utils/decoder_bmmu_box.h"
+#include "vh264.h"
+#include "../../../stream_input/parser/streambuf.h"
+#include <linux/delay.h>
+#include <linux/amlogic/media/video_sink/video.h>
+
+#include <linux/amlogic/media/ge2d/ge2d.h>
+
+#define DRIVER_NAME "amvdec_h264"
+#define MODULE_NAME "amvdec_h264"
+#define MEM_NAME "codec_264"
+#define HANDLE_H264_IRQ
+/* #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 50
+
+static inline bool close_to(int a, int b, int m)
+{
+ return (abs(a - b) < m) ? true : false;
+}
+
+static DEFINE_MUTEX(vh264_mutex);
+/* 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 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 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 void 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_buffer_size;
+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];
+#define MAX_BLK_BUFFERS (VF_BUF_NUM + 3)
+#define FENSE_BUFFER_IDX(n) (VF_BUF_NUM + n)
+static struct vframe_s fense_vf[2];
+
+static struct timer_list recycle_timer;
+static u32 stat;
+static unsigned long buf_start, buf_end;
+static u32 buf_size;
+static s32 buf_offset;
+static u32 ucode_map_start;
+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_bandwith;
+
+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;
+
+#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 enable_switch_fense = 1;
+#define EN_SWITCH_FENCE() (enable_switch_fense && !is_4k)
+#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;
+
+/*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 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 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 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 width, unsigned height)
+{
+ canvas_config(spec->y_canvas_index,
+ spec->y_addr,
+ width, height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+
+ canvas_config(spec->u_canvas_index,
+ spec->u_addr,
+ width, height / 2,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+}
+
+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);
+ 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 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]))
+ 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
+
+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, start_addr;
+ unsigned long addr;
+ unsigned int post_canvas;
+ unsigned int frame_mbs_only_flag;
+ unsigned int chroma_format_idc, chroma444, video_signal;
+ unsigned int crop_infor, crop_bottom, crop_right, level_idc;
+ u32 disp_addr = 0xffffffff;
+ struct canvas_s cur_canvas;
+
+ 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 */
+ vdec_source_changed(VFORMAT_H264, 3840, 2160, 60);
+ 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_type() >= MESON_CPU_MAJOR_ID_GXTVBB) {
+ if (!mb_width && mb_total)
+ mb_width = 256;
+ }
+ 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;
+
+ if (is_4k || dpb_size_adj) {
+ /*4k2k*/
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXTVBB) {
+ max_dpb_size = get_max_dpb_size(
+ level_idc, mb_width, mb_height);
+ actual_dpb_size = max_dpb_size + 5;
+ if (dpb_size_adj)
+ actual_dpb_size
+ = max_reference_size + dpb_size_adj;
+ if (actual_dpb_size > VF_BUF_NUM)
+ actual_dpb_size = VF_BUF_NUM;
+ pr_info
+ ("actual_dpb_size %d max_ref_size %d\n",
+ actual_dpb_size, max_reference_size);
+ } else {
+ vh264_running = 0;
+ fatal_error_flag =
+ DECODER_FATAL_ERROR_SIZE_OVERFLOW;
+ mutex_unlock(&vh264_mutex);
+ pr_err("oversize ! mb_total %d,\n", mb_total);
+ return;
+ }
+ } else {
+ actual_dpb_size = (frame_buffer_size - mb_total * mb_mv_byte *
+ max_reference_size) / (mb_total * 384);
+ actual_dpb_size = min(actual_dpb_size, VF_BUF_NUM);
+ max_dpb_size = get_max_dpb_size(level_idc, mb_width, mb_height);
+ if (max_reference_size > 1)
+ max_dpb_size = max_reference_size - 1;
+ else
+ max_dpb_size = max_reference_size;
+ if (actual_dpb_size < (max_dpb_size + 4)) {
+ actual_dpb_size = max_dpb_size + 4;
+ if (actual_dpb_size > VF_BUF_NUM)
+ actual_dpb_size = VF_BUF_NUM;
+ }
+ pr_info("actual_dpb_size %d max_dpb_size %d\n",
+ actual_dpb_size, max_dpb_size);
+ }
+ if (max_dpb_size == 0)
+ max_dpb_size = actual_dpb_size;
+ else
+ max_dpb_size = min(max_dpb_size, actual_dpb_size);
+ max_reference_size = min(max_reference_size, actual_dpb_size-1);
+ max_dpb_size = max(max_reference_size, max_dpb_size);
+ max_reference_size++;
+
+ start_addr = addr = buf_start;
+ if (is_4k)
+ addr += ((mb_total << 8) + (mb_total << 7));/*keep last frame */
+ WRITE_VREG(AV_SCRATCH_1, addr);
+ WRITE_VREG(AV_SCRATCH_3, post_canvas); /* should be modified later */
+ canvas_read((READ_VCBUS_REG(VD1_IF0_CANVAS0) & 0xff), &cur_canvas);
+ disp_addr = (cur_canvas.addr + 7) >> 3;
+ if ((addr + mb_total * mb_mv_byte * max_reference_size)
+ >= buf_end) {
+ fatal_error_flag =
+ DECODER_FATAL_ERROR_NO_MEM;
+ vh264_running = 0;
+ mutex_unlock(&vh264_mutex);
+ pr_err("mv buf not enough!\n");
+ return;
+ }
+ addr += mb_total * mb_mv_byte * max_reference_size;
+ WRITE_VREG(AV_SCRATCH_4, addr);
+ if (!(READ_VREG(AV_SCRATCH_F) & 0x1)) {
+ bool use_alloc = is_4k ? true:false;
+ int alloc_count = 0;
+
+ for (i = 0; i < actual_dpb_size; i++) {
+ if (((addr + (mb_total << 8) + (mb_total << 7))
+ >= buf_end) && (!use_alloc)) {
+ pr_info("start alloc for %d\n", i);
+ use_alloc = true;
+ }
+ if (use_alloc) {
+#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
+ buffer_spec[i].alloc_count = page_count;
+ if (!decoder_bmmu_box_alloc_idx_wait(
+ mm_blk_handle,
+ i,
+ page_count << PAGE_SHIFT,
+ -1,
+ -1,
+ BMMU_ALLOC_FLAGS_WAITCLEAR
+ )) {
+ buffer_spec[i].phy_addr =
+ decoder_bmmu_box_get_phy_addr(
+ mm_blk_handle,
+ i);
+ pr_info("CMA malloc ok %d\n", i);
+ alloc_count++;
+ } else {
+ buffer_spec[i].alloc_count = 0;
+ fatal_error_flag =
+ DECODER_FATAL_ERROR_NO_MEM;
+ vh264_running = 0;
+ mutex_unlock(&vh264_mutex);
+ pr_err("CMA not enough mem! %d\n",
+ i);
+ return;
+ }
+ addr = buffer_spec[i].phy_addr;
+ } else {
+ if (buffer_spec[i].phy_addr) {
+ decoder_bmmu_box_free_idx(
+ mm_blk_handle,
+ i);
+ buffer_spec[i].phy_addr = 0;
+ buffer_spec[i].alloc_count = 0;
+ }
+ }
+ /*4k keep last frame */
+ if (is_4k && ((addr + 7) >> 3) == disp_addr)
+ addr = start_addr;
+ 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;
+
+ canvas_config(128 + i * 2,
+ buffer_spec[i].y_addr,
+ mb_width << 4, mb_height << 4,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+ canvas_config(128 + i * 2 + 1,
+ buffer_spec[i].u_addr,
+ mb_width << 4, mb_height << 3,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+ 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
+ addr = buf_start + mb_total * 384 * actual_dpb_size;
+
+ 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;
+ }
+ }
+ } 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 pts_inc_by_duration(unsigned *new_pts, unsigned *new_pts_rem)
+{
+ unsigned 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;
+}
+#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;
+ 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)
+ 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;
+ }
+
+ /* add 64bit pts us ; */
+ if (unlikely
+ ((b_offset == first_offset)
+ && (first_pts_cached))) {
+ pts = first_pts;
+ pts_us64 = first_pts64;
+ 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, 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;
+#ifdef DEBUG_PTS
+ pts_missed++;
+#endif
+ }
+
+ /* 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.
+ */
+ 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,
+ buffer_index);
+ 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_bandwith |=
+ ((codec_mm_get_total_size() < 80 * SZ_1M)
+ & ((READ_VREG(AV_SCRATCH_N) & 0xf) == 3)
+ & ((frame_width * frame_height) >= 1920*1080));
+ if (high_bandwith)
+ 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,
+ buffer_index);
+ 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_bandwith)
+ 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,
+ 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 happened\n");
+ 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, 0,
+ &first_pts64) == 0)
+ first_pts_cached = true;
+ WRITE_VREG(AV_SCRATCH_0, 0);
+
+ } else if ((cpu_cmd & 0xff) == 0xa) {
+ int 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, 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,
+ buffer_index);
+ vfbuf_use[buffer_index]++;
+ p_last_vf = vf;
+ pts_discontinue = false;
+ iponly_early_mode = 1;
+ kfifo_put(&delay_display_q,
+ (const struct vframe_s *)vf);
+ WRITE_VREG(AV_SCRATCH_0, 0);
+ }
+
+ sei_itu35_flags = READ_VREG(AV_SCRATCH_J);
+ if (sei_itu35_flags & (1 << 15)) { /* data ready */
+ /* int ltemp; */
+ /* unsigned char *daddr; */
+ unsigned int sei_itu35_wp = (sei_itu35_flags >> 16) & 0xffff;
+ unsigned int sei_itu35_data_length = sei_itu35_flags & 0x7fff;
+ struct userdata_poc_info_t user_data_poc;
+
+#if 0
+ /* dump lmem for debug */
+ WRITE_VREG(0x301, 0x8000);
+ WRITE_VREG(0x31d, 0x2);
+ for (ltemp = 0; ltemp < 64; ltemp++) {
+ laddr = 0x20 + ltemp;
+ WRITE_VREG(0x31b, laddr);
+ pr_info("mem 0x%x data 0x%x\n", laddr,
+ READ_VREG(0x31c) & 0xffff);
+ }
+#endif
+#if 0
+ for (ltemp = 0; ltemp < sei_itu35_wp; ltemp++) {
+ daddr =
+ (unsigned char *)phys_to_virt(
+ sei_data_buffer_phys +
+ ltemp);
+ /* daddr = (unsigned char *)(sei_data_buffer +
+ * ltemp);
+ */
+ pr_info("0x%x\n", *daddr);
+ }
+#endif
+ /* pr_info("pocinfo 0x%x, top poc %d, wp 0x%x, length %d\n",
+ * READ_VREG(AV_SCRATCH_L), READ_VREG(AV_SCRATCH_M),
+ * sei_itu35_wp, sei_itu35_data_length);
+ */
+ user_data_poc.poc_info = READ_VREG(AV_SCRATCH_L);
+ user_data_poc.poc_number = READ_VREG(AV_SCRATCH_M);
+ set_userdata_poc(user_data_poc);
+ WRITE_VREG(AV_SCRATCH_J, 0);
+ wakeup_userdata_poll(sei_itu35_wp,
+ (unsigned long)sei_data_buffer,
+ USER_DATA_SIZE, sei_itu35_data_length);
+ }
+#ifdef HANDLE_H264_IRQ
+ return IRQ_HANDLED;
+#else
+ return;
+#endif
+}
+
+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();
+
+#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();
+ }
+ } else
+ wait_buffer_counter = 0;
+ } else if (wait_i_pass_frames > 1000) {
+ pr_info("i passed frames > 1000\n");
+ amvdec_stop();
+#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();
+ }
+ }
+
+#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 >= 0) && (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 >= 0 &&
+ (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)) {
+ 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);
+ }
+exit:
+ timer->expires = jiffies + PUT_INTERVAL;
+
+ add_timer(timer);
+}
+
+int vh264_dec_status(struct vdec_s *vdec, struct vdec_status *vstatus)
+{
+ vstatus->width = frame_width;
+ vstatus->height = frame_height;
+ if (frame_dur != 0)
+ vstatus->fps = 96000 / frame_dur;
+ else
+ vstatus->fps = -1;
+ vstatus->error_count = READ_VREG(AV_SCRATCH_D);
+ vstatus->status = stat;
+ if (fatal_error_reset)
+ vstatus->status |= fatal_error_flag;
+ 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;
+}
+
+static void vh264_prot_init(void)
+{
+
+ 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_MPEG_REG(RESET0_REGISTER,
+ RESET_IQIDCT | RESET_MC | RESET_VLD_PART);
+ READ_MPEG_REG(RESET0_REGISTER);
+ WRITE_MPEG_REG(RESET0_REGISTER,
+ RESET_IQIDCT | RESET_MC | RESET_VLD_PART);
+
+ WRITE_MPEG_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);
+ 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);
+
+ 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_type() >= 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 void vh264_local_init(void)
+{
+ int i;
+
+ vh264_ratio = vh264_amstream_dec_info.ratio;
+ /* vh264_ratio = 0x100; */
+
+ vh264_rotation = (((unsigned long) vh264_amstream_dec_info.param)
+ >> 16) & 0xffff;
+
+ frame_buffer_size = AVIL_DPB_BUFF_SIZE + buf_size - DEFAULT_MEM_SIZE;
+ 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 (!mm_blk_handle)
+ 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);
+
+ pr_info
+ ("H264 sysinfo: %dx%d duration=%d, pts_outside=%d, ",
+ frame_width, frame_height, frame_dur, pts_outside);
+ pr_debug("sync_outside=%d, use_idr_framerate=%d\n",
+ sync_outside, use_idr_framerate);
+
+ 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_bandwith = 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;
+}
+
+static s32 vh264_init(void)
+{
+ int trickmode_fffb = 0;
+ int firmwareloaded = 0;
+ int i;
+
+ /* 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;
+ saved_resolution = 0;
+ iponly_early_mode = 0;
+ saved_idc_level = 0;
+ vh264_local_init();
+
+ query_video_status(0, &trickmode_fffb);
+
+#if 0
+ if (!trickmode_fffb) {
+ void __iomem *p =
+ ioremap_nocache(ucode_map_start, V_BUF_ADDR_OFFSET);
+ if (p != NULL) {
+ memset(p, 0, V_BUF_ADDR_OFFSET);
+ iounmap(p);
+ }
+ }
+#endif
+
+ 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();
+
+ 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, size = -1;
+ char *buf = vmalloc(0x1000 * 16);
+ if (IS_ERR_OR_NULL(buf))
+ return -ENOMEM;
+
+ size = get_firmware_data(VIDEO_DEC_H264, buf);
+ if (size < 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) {
+ pr_err("h264 load orignal firmware error %d.\n", ret);
+ 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;
+ }
+ }
+
+ stat |= STAT_MC_LOAD;
+ 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;
+ if (!decoder_bmmu_box_alloc_idx_wait(
+ mm_blk_handle,
+ FENSE_BUFFER_IDX(i),
+ 3 * SZ_1M,
+ -1,
+ -1,
+ BMMU_ALLOC_FLAGS_WAITCLEAR
+ )) {
+ s->phy_addr = decoder_bmmu_box_get_phy_addr(
+ mm_blk_handle,
+ FENSE_BUFFER_IDX(i));
+ } else {
+ return -ENOMEM;
+ }
+ s->y_canvas_index = 2 * i;
+ s->u_canvas_index = 2 * i + 1;
+ s->v_canvas_index = 2 * i + 1;
+ }
+ }
+ /* 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
+
+ vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)((unsigned long)frame_dur));
+
+ 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) {
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_FR_END_HINT,
+ NULL);
+ }
+
+ 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_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 error_do_work(struct work_struct *work)
+{
+ mutex_lock(&vh264_mutex);
+
+ /*
+ * 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();
+ 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
+ msleep(30);
+ vh264_local_init();
+ vh264_prot_init();
+
+ amvdec_start();
+ vh264_reset = 0;
+ }
+
+ mutex_unlock(&vh264_mutex);
+}
+
+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);
+ 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 1
+ 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]);
+
+ /* 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;
+ }
+
+ ucode_map_start = pdata->mem_start;
+ buf_size = pdata->mem_end - pdata->mem_start + 1;
+ if (buf_size < DEFAULT_MEM_SIZE) {
+ pr_info("\namvdec_h264 memory size not enough.\n");
+ mutex_unlock(&vh264_mutex);
+ return -ENOMEM;
+ }
+
+ buf_offset = pdata->mem_start - DEF_BUF_START_ADDR;
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXTVBB)
+ buf_start = V_BUF_ADDR_OFFSET_NEW + pdata->mem_start;
+ else
+ buf_start = V_BUF_ADDR_OFFSET + pdata->mem_start;
+ buf_end = pdata->mem_end;
+ if (pdata->sys_info)
+ vh264_amstream_dec_info = *pdata->sys_info;
+ if (NULL == sei_data_buffer) {
+ sei_data_buffer =
+ dma_alloc_coherent(amports_get_dma_device(),
+ USER_DATA_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);
+ */
+ }
+ pr_debug("amvdec_h264 mem-addr=%lx,buff_offset=%x,buf_start=%lx buf_size %x\n",
+ pdata->mem_start, buf_offset, buf_start, buf_size);
+ pdata->dec_status = vh264_dec_status;
+ pdata->set_trickmode = vh264_set_trickmode;
+
+ if (vh264_init() < 0) {
+ pr_info("\namvdec_h264 init failed.\n");
+ mutex_unlock(&vh264_mutex);
+ return -ENODEV;
+ }
+
+ INIT_WORK(&error_wd_work, error_do_work);
+ INIT_WORK(&stream_switching_work, stream_switching_do);
+ INIT_WORK(&set_parameter_work, vh264_set_params);
+
+ atomic_set(&vh264_active, 1);
+
+ mutex_unlock(&vh264_mutex);
+
+ 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);
+ mutex_lock(&vh264_mutex);
+ vh264_stop(MODE_FULL);
+ vdec_source_changed(VFORMAT_H264, 0, 0, 0);
+ 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
+ mutex_unlock(&vh264_mutex);
+ return 0;
+}
+
+/****************************************/
+
+static struct platform_driver amvdec_h264_driver = {
+ .probe = amvdec_h264_probe,
+ .remove = amvdec_h264_remove,
+#ifdef CONFIG_PM
+ .suspend = amvdec_suspend,
+ .resume = amvdec_resume,
+#endif
+ .driver = {
+ .name = DRIVER_NAME,
+ }
+};
+
+static struct codec_profile_t amvdec_h264_profile = {
+ .name = "h264",
+ .profile = ""
+};
+
+static 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_type() >= MESON_CPU_MAJOR_ID_GXTVBB
+ && (codec_mm_get_total_size() > 80 * SZ_1M)) {
+ amvdec_h264_profile.profile = "4k";
+ dpb_size_adj = 0;
+ }
+ if (get_cpu_type() <= MESON_CPU_MAJOR_ID_GXBB)
+ dpb_size_adj = 0;
+
+ vcodec_profile_register(&amvdec_h264_profile);
+ 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(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");
+
+
+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..45d2849
--- a/dev/null
+++ b/drivers/frame_provider/decoder/h264/vh264.h
@@ -0,0 +1,25 @@
+/*
+ * 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 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..1c56b03
--- a/dev/null
+++ b/drivers/frame_provider/decoder/h264/vh264_4k2k.c
@@ -0,0 +1,1839 @@
+/*
+ * 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>
+
+#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"
+
+#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
+
+#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 void 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 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_recieved;
+static struct vframe_s *p_last_vf;
+
+#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, decoder_buffer_start, decoder_buffer_end;
+static unsigned long reserved_buffer;
+
+#define DECODE_BUFFER_NUM_MAX 32
+#define DISPLAY_BUFFER_NUM 6
+
+#define video_domain_addr(adr) (adr&0x7fffffff)
+#define DECODER_WORK_SPACE_SIZE 0x400000
+
+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[DECODE_BUFFER_NUM_MAX +
+ DISPLAY_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 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;
+
+ return;
+}
+
+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;
+}
+
+int init_canvas(int start_addr, long dpb_size, int dpb_number, int mb_width,
+ int mb_height, struct buffer_spec_s *buffer_spec)
+{
+ unsigned long dpb_addr, addr;
+ int i;
+ int mb_total;
+ int canvas_addr = ANC0_CANVAS_ADDR;
+ int vdec2_canvas_addr = VDEC2_ANC0_CANVAS_ADDR;
+ int index = AMVDEC_H264_4K2K_CANVAS_INDEX;
+ u32 disp_addr = 0xffffffff;
+ bool use_alloc = false;
+ int alloc_count = 0;
+ struct canvas_s cur_canvas;
+
+ dpb_addr = start_addr + dpb_size;
+
+ mb_total = mb_width * mb_height;
+
+ canvas_read((READ_VCBUS_REG(VD1_IF0_CANVAS0) & 0xff), &cur_canvas);
+ disp_addr = (cur_canvas.addr + 7) >> 3;
+
+ mutex_lock(&vh264_4k2k_mutex);
+
+ for (i = 0; i < dpb_number; i++) {
+ 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));
+ }
+
+ if (((dpb_addr + (mb_total << 8) + (mb_total << 7)) >=
+ decoder_buffer_end) && (!use_alloc)) {
+ pr_info("start alloc for %d/%d\n", i, dpb_number);
+ use_alloc = true;
+ }
+
+ if (use_alloc) {
+#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
+
+ if (buffer_spec[i].phy_addr) {
+ if (page_count != buffer_spec[i].alloc_count) {
+ pr_info("Delay release CMA buffer%d\n",
+ i);
+
+ /*dma_release_from_contiguous(cma_dev,
+ buffer_spec[i].
+ alloc_pages,
+ buffer_spec[i].
+ alloc_count);
+ */
+ 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;
+ } else
+ pr_info("Re-use CMA buffer %d\n", i);
+ }
+
+ if (!buffer_spec[i].phy_addr) {
+ if (codec_mm_get_free_size()
+ < (page_count * PAGE_SIZE)) {
+ pr_err
+ ("CMA not enough free keep buf! %d\n",
+ i);
+ try_free_keep_video(1);
+ }
+ if (!codec_mm_enough_for_size(
+ page_count * PAGE_SIZE, 1)) {
+ buffer_spec[i].alloc_count = 0;
+ fatal_error =
+ DECODER_FATAL_ERROR_NO_MEM;
+ mutex_unlock(&vh264_4k2k_mutex);
+ return -1;
+ }
+ buffer_spec[i].alloc_count = page_count;
+ buffer_spec[i].phy_addr =
+ codec_mm_alloc_for_dma(
+ MEM_NAME, buffer_spec[i].alloc_count,
+ 4 + PAGE_SHIFT,
+ CODEC_MM_FLAGS_CMA_CLEAR |
+ CODEC_MM_FLAGS_FOR_VDECODER);
+ }
+ alloc_count++;
+
+ if (!buffer_spec[i].phy_addr) {
+ buffer_spec[i].alloc_count = 0;
+ pr_info
+ ("264 4K2K decoder memory alloc failed %d.\n",
+ i);
+ mutex_unlock(&vh264_4k2k_mutex);
+ return -1;
+ }
+ addr = buffer_spec[i].phy_addr;
+ dpb_addr = addr;
+ } else {
+ 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;
+ }
+
+ addr = dpb_addr;
+ dpb_addr += dpb_size;
+#ifdef DOUBLE_WRITE
+ dpb_addr += dpb_size / 4;
+#endif
+ }
+
+ if (((addr + 7) >> 3) == disp_addr)
+ addr = start_addr;
+
+ 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);
+
+ addr += mb_total << 5;
+ index++;
+#endif
+ }
+
+ mutex_unlock(&vh264_4k2k_mutex);
+
+ pr_info
+ ("H264 4k2k decoder canvas allocation successful, ");
+ pr_info("%d CMA blocks allocated, canvas %d-%d\n",
+ alloc_count, AMVDEC_H264_4K2K_CANVAS_INDEX, index - 1);
+
+ 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;
+ int dpb_start_addr, ref_start_addr, 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);
+
+ ref_start_addr = decoder_buffer_start;
+ 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;
+ dpb_start_addr =
+ ref_start_addr + (ref_size * (max_reference_frame_num + 1)) * 2;
+ /* dpb_start_addr = reserved_buffer + dpb_size; */
+
+ pr_info
+ ("dpb_start_addr=0x%x, dpb_size=%d, total_dec_frame_buffering=%d, ",
+ dpb_start_addr, dpb_size, total_dec_frame_buffering);
+ pr_info("mb_width=%d, mb_height=%d\n",
+ mb_width, mb_height);
+
+ ret = init_canvas(dpb_start_addr, 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 */
+#if 0
+
+ pr_info("Debug: send a fake picture to config VPP %dx%d\n", frame_width,
+ frame_height);
+ WRITE_VREG(DOS_SCRATCH0, 4);
+ WRITE_VREG(DOS_SCRATCH1, 0x004c);
+
+ if (kfifo_get(&newframe_q, &vf)) {
+ vfbuf_use[0]++;
+ vf->index = 0;
+ vf->pts = 0;
+ vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD;
+ vf->canvas0Addr = vf->canvas1Addr =
+ spec2canvas(&buffer_spec[0]);
+ set_frame_info(vf);
+ kfifo_put(&display_q, (const struct vframe_s *)vf);
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
+ }
+ /* ///////////// FAKE END */
+#endif
+}
+
+static irqreturn_t vh264_4k2k_isr(int irq, void *dev_id)
+{
+ int drop_status, display_buff_id, display_POC, slice_type, error;
+ unsigned stream_offset;
+ struct vframe_s *vf = NULL;
+ int ret = READ_VREG(MAILBOX_COMMAND);
+
+ 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))) {
+ pts_lookup_offset_us64(PTS_TYPE_VIDEO,
+ stream_offset,
+ &vf->pts,
+ 0,
+ &vf->pts_us64);
+ }
+#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_recovery_mode & 2) && error)
+ || (!first_i_recieved
+ && (slice_type != SLICE_TYPE_I))) {
+ kfifo_put(&recycle_q,
+ (const struct vframe_s *)vf);
+ } else {
+ p_last_vf = vf;
+ first_i_recieved = 1;
+ kfifo_put(&display_q,
+ (const struct vframe_s *)vf);
+
+ 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_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_recieved) {
+ 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 >= 0)
+ && (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);
+ }
+ }
+ if (first_i_recieved &&/*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;
+ }
+ timer->expires = jiffies + PUT_INTERVAL;
+
+ add_timer(timer);
+}
+
+int vh264_4k2k_dec_status(struct vdec_s *vdec, struct vdec_status *vstatus)
+{
+ vstatus->width = frame_width;
+ vstatus->height = frame_height;
+ if (frame_dur != 0)
+ vstatus->fps = 96000 / frame_dur;
+ else
+ vstatus->fps = -1;
+ vstatus->error_count = 0;
+ vstatus->status = stat | fatal_error;
+ 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);
+ /*TODO for M8
+ amvenc_dos_top_reg_fix();*/
+ }
+#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 void vh264_4k2k_local_init(void)
+{
+ int i;
+
+#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_recieved = 0;
+ INIT_WORK(&alloc_work, do_alloc_work);
+
+ return;
+}
+
+static s32 vh264_4k2k_init(void)
+{
+ int ret = -1, size = -1;
+ char *buf = vmalloc(0x1000 * 16);
+ if (IS_ERR_OR_NULL(buf))
+ return -ENOMEM;
+
+ pr_info("\nvh264_4k2k_init\n");
+
+ init_timer(&recycle_timer);
+
+ stat |= STAT_TIMER_INIT;
+
+ vh264_4k2k_local_init();
+
+ 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 (amvdec_loadmc_ex(VFORMAT_H264_4K2K, NULL, buf) < 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;
+ }
+
+ 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);
+
+ if (ret < 0) {
+ amvdec_disable();
+ if (!H264_4K2K_SINGLE_CORE)
+ amvdec2_disable();
+ pr_info("vh264_4k2k load firmware error.\n");
+ 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;
+ }
+ 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;
+
+ return 0;
+}
+
+static int vh264_4k2k_stop(void)
+{
+ int i;
+ u32 disp_addr = 0xffffffff;
+ struct canvas_s cur_canvas;
+
+ 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_VSYNC_RDMA
+ msleep(100);
+#endif
+ if (!get_blackout_policy()) {
+ canvas_read((READ_VCBUS_REG(VD1_IF0_CANVAS0) & 0xff),
+ &cur_canvas);
+ disp_addr = cur_canvas.addr;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(buffer_spec); i++) {
+ if (buffer_spec[i].phy_addr) {
+ if (disp_addr ==
+ (u32)buffer_spec[i].phy_addr)
+ pr_info("Skip releasing CMA buffer %d\n", i);
+ else {
+ 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;
+ }
+ }
+
+ if (buffer_spec[i].y_addr == disp_addr) {
+ pr_info("4K2K dec stop, keeping buffer index = %d\n",
+ i);
+ }
+ }
+
+ 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);
+}
+
+#if 0 /* (MESON_CPU_TYPE == MESON_CPU_TYPE_MESON8) && (HAS_HDEC) */
+/* extern void AbortEncodeWithVdec2(int abort); */
+#endif
+
+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;
+ }
+
+ work_space_adr = pdata->mem_start;
+ decoder_buffer_start = pdata->mem_start + DECODER_WORK_SPACE_SIZE;
+ decoder_buffer_end = pdata->mem_end + 1;
+
+ if (pdata->sys_info)
+ vh264_4k2k_amstream_dec_info = *pdata->sys_info;
+ cma_dev = pdata->cma_dev;
+
+ pr_info("H.264 4k2k decoder mem resource 0x%x -- 0x%x\n",
+ (u32)decoder_buffer_start, (u32)decoder_buffer_end);
+ 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 1 /* (MESON_CPU_TYPE == MESON_CPU_TYPE_MESON8) && (has_hdec()) */
+ int count = 0;
+ if (get_vdec2_usage() != USAGE_NONE)
+ /* AbortEncodeWithVdec2(1); */ /*TODO*/
+ while ((get_vdec2_usage() != USAGE_NONE) && (count < 10)) {
+ msleep(50);
+ count++;
+ }
+
+ if (get_vdec2_usage() != USAGE_NONE) {
+ pr_info
+ ("\namvdec_h264_4k2k - vdec2 is used by encode now.\n");
+ mutex_unlock(&vh264_4k2k_mutex);
+ return -EBUSY;
+ }
+#endif
+
+ if (vdec_on(VDEC_2)) { /* ++++ */
+ vdec_poweroff(VDEC_2); /* ++++ */
+ mdelay(10);
+ }
+#if 1 /* (MESON_CPU_TYPE == MESON_CPU_TYPE_MESON8) && (has_hdec()) */
+ set_vdec2_usage(USAGE_DEC_4K2K);
+ /* AbortEncodeWithVdec2(0); */ /*TODO*/
+#endif
+ 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");
+#if 1/* (MESON_CPU_TYPE == MESON_CPU_TYPE_MESON8) && (has_hdec()) */
+ if (!H264_4K2K_SINGLE_CORE) {
+ set_vdec2_usage(USAGE_NONE);
+ /*AbortEncodeWithVdec2(0);*/ /*TODO*/
+ }
+#endif
+ mutex_unlock(&vh264_4k2k_mutex);
+ 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);
+ 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);
+
+ 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);
+#if 1/*(MESON_CPU_TYPE == MESON_CPU_TYPE_MESON8) && (has_hdec())*/
+ set_vdec2_usage(USAGE_NONE);
+#endif
+ }
+#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);
+
+ 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 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_type() < MESON_CPU_MAJOR_ID_GXTVBB)
+ vcodec_profile_register(&amvdec_h264_4k2k_profile);
+
+ 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..1683c31
--- a/dev/null
+++ b/drivers/frame_provider/decoder/h264/vh264_mvc.c
@@ -0,0 +1,1594 @@
+/*
+ * drivers/amlogic/amports/vh264mvc.c
+ *
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/platform_device.h>
+#include <linux/amlogic/media/utils/amstream.h>
+#include <linux/amlogic/media/frame_sync/ptsserv.h>
+#include <linux/amlogic/media/canvas/canvas.h>
+#include <linux/amlogic/media/vfm/vframe.h>
+#include <linux/amlogic/media/vfm/vframe_provider.h>
+#include <linux/amlogic/media/vfm/vframe_receiver.h>
+#include <linux/amlogic/media/utils/vformat.h>
+#include <linux/workqueue.h>
+#include <linux/dma-mapping.h>
+#include <linux/atomic.h>
+
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "../../../stream_input/amports/amports_priv.h"
+#include "../utils/vdec.h"
+#include "../utils/amvdec.h"
+
+#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 void 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 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 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;
+
+#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 DECODE_BUFFER_START = 0x00200000;
+unsigned DECODE_BUFFER_END = 0x05000000;
+
+#define DECODE_BUFFER_NUM_MAX 16
+#define DISPLAY_BUFFER_NUM 4
+
+static unsigned int ANC_CANVAS_ADDR;
+static unsigned int index;
+static unsigned int dpb_start_addr[3];
+static unsigned int ref_start_addr[2];
+static unsigned int max_dec_frame_buffering[2];
+static unsigned int total_dec_frame_buffering[2];
+static unsigned int level_idc, max_reference_frame_num, mb_width, mb_height;
+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 work_space_adr;
+static unsigned work_space_size = 0xa0000;
+
+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;
+};
+static struct buffer_spec_s buffer_spec0[DECODE_BUFFER_NUM_MAX +
+ DISPLAY_BUFFER_NUM];
+static struct buffer_spec_s buffer_spec1[DECODE_BUFFER_NUM_MAX +
+ DISPLAY_BUFFER_NUM];
+
+/*
+ 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;
+/**/
+#define MVC_BUF_NUM (DECODE_BUFFER_NUM_MAX+DISPLAY_BUFFER_NUM)
+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 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 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);
+ } else {
+ /* h264mvc_ar = ((float)frame_height/frame_width)
+ *customer_ratio; */
+ ar = min_t(u32, h264mvc_ar, DISP_RATIO_ASPECT_RATIO_MAX);
+
+ vf->ratio_control = (ar << DISP_RATIO_ASPECT_RATIO_BIT);
+ }
+
+ return;
+}
+
+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 (vf) {
+ 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 start_addr, long dpb_size, int dpb_number,
+ int mb_width, int mb_height,
+ struct buffer_spec_s *buffer_spec)
+{
+
+ int dpb_addr, addr;
+ int i;
+ int mb_total;
+
+ /* cav_con canvas; */
+
+ dpb_addr = start_addr;
+
+ mb_total = mb_width * mb_height;
+
+ for (i = 0; i < dpb_number; i++) {
+ WRITE_VREG(ANC_CANVAS_ADDR,
+ index | ((index + 1) << 8) |
+ ((index + 2) << 16));
+ ANC_CANVAS_ADDR++;
+
+ addr = dpb_addr;
+ 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);
+
+ addr += mb_total << 6;
+ index++;
+
+ dpb_addr = dpb_addr + dpb_size;
+ if (dpb_addr >= DECODE_BUFFER_END)
+ return -1;
+ }
+
+ return dpb_addr;
+}
+
+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;
+}
+
+#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;
+ int ret = READ_VREG(MAILBOX_COMMAND);
+ /* pr_info("vh264mvc_isr, cmd =%x\n", ret); */
+ switch (ret & 0xff) {
+ case CMD_ALLOC_VIEW_0:
+ if (dbg_mode & 0x1) {
+ pr_info
+ ("Start H264 display buffer allocation for view 0\n");
+ }
+ if ((dpb_start_addr[0] != -1) | (dpb_start_addr[1] != -1)) {
+ dpb_start_addr[0] = -1;
+ dpb_start_addr[1] = -1;
+ }
+ dpb_start_addr[0] = DECODE_BUFFER_START;
+ 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] + DISPLAY_BUFFER_NUM;
+
+ 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);
+ }
+ ref_start_addr[0] = dpb_start_addr[0] +
+ (dpb_size * total_dec_frame_buffering[0]);
+ dpb_start_addr[1] = ref_start_addr[0] +
+ (ref_size * (max_reference_frame_num + 1));
+
+ if (dbg_mode & 0x1) {
+ pr_info("dpb_start_addr[0]: 0x%x\n", dpb_start_addr[0]);
+ pr_info("ref_start_addr[0]: 0x%x\n", ref_start_addr[0]);
+ pr_info("dpb_start_addr[1]: 0x%x\n", dpb_start_addr[1]);
+ }
+ if (dpb_start_addr[1] >= DECODE_BUFFER_END) {
+ pr_info(" No enough memory for alloc view 0\n");
+ goto exit;
+ }
+
+ index = CANVAS_INDEX_START;
+ ANC_CANVAS_ADDR = ANC0_CANVAS_ADDR;
+
+ ret =
+ init_canvas(dpb_start_addr[0], dpb_size,
+ total_dec_frame_buffering[0], mb_width,
+ mb_height, buffer_spec0);
+
+ if (ret == -1) {
+ pr_info(" Un-expected memory alloc problem\n");
+ goto exit;
+ }
+
+ 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 allocation 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 allocation for view 1\n");
+ }
+ if ((dpb_start_addr[0] == -1) | (dpb_start_addr[1] == -1)) {
+ pr_info("Error: allocation view 1 before view 0 !!!\n");
+ break;
+ }
+ 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] + DISPLAY_BUFFER_NUM;
+
+ 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[1] : 0x%x\n",
+ total_dec_frame_buffering[1]);
+ pr_info("max_reference_frame_num: 0x%x\n",
+ max_reference_frame_num);
+ }
+ ref_start_addr[1] = dpb_start_addr[1] +
+ (dpb_size * total_dec_frame_buffering[1]);
+ dpb_start_addr[2] = ref_start_addr[1] +
+ (ref_size * (max_reference_frame_num + 1));
+
+ if (dbg_mode & 0x1) {
+ pr_info("dpb_start_addr[1]: 0x%x\n", dpb_start_addr[1]);
+ pr_info("ref_start_addr[1]: 0x%x\n", ref_start_addr[1]);
+ pr_info("dpb_start_addr[2]: 0x%x\n", dpb_start_addr[2]);
+ }
+ if (dpb_start_addr[2] >= DECODE_BUFFER_END) {
+ pr_info(" No enough memory for alloc view 1\n");
+ goto exit;
+ }
+
+ index = CANVAS_INDEX_START + total_dec_frame_buffering[0] * 3;
+ ANC_CANVAS_ADDR =
+ ANC0_CANVAS_ADDR + total_dec_frame_buffering[0];
+
+ ret =
+ init_canvas(dpb_start_addr[1], dpb_size,
+ total_dec_frame_buffering[1], mb_width,
+ mb_height, buffer_spec1);
+
+ if (ret == -1) {
+ pr_info(" Un-expected memory alloc problem\n");
+ goto exit;
+ }
+
+ 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 display 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;
+ 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 0
+ if (pts_lookup_offset
+ (PTS_TYPE_VIDEO,
+ vfpool_idx[slot].stream_offset,
+ &vf->pts,
+ 0) != 0)
+ vf->pts = 0;
+#endif
+ 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,
+ 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);
+ 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;
+ }
+exit:
+#ifdef HANDLE_h264mvc_IRQ
+ return IRQ_HANDLED;
+#else
+ return;
+#endif
+}
+
+static void vh264mvc_put_timer_func(unsigned long arg)
+{
+ struct timer_list *timer = (struct timer_list *)arg;
+
+ int valid_frame = 0;
+ 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);
+ }
+ }
+
+
+ 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);
+ }
+
+ /* RESTART: */
+ timer->expires = jiffies + PUT_INTERVAL;
+
+ add_timer(timer);
+}
+
+int vh264mvc_dec_status(struct vdec_s *vdec, struct vdec_status *vstatus)
+{
+ vstatus->width = frame_width;
+ vstatus->height = frame_height;
+ if (frame_dur != 0)
+ vstatus->fps = 96000 / frame_dur;
+ else
+ vstatus->fps = -1;
+ vstatus->error_count = READ_VREG(AV_SCRATCH_D);
+ vstatus->status = stat;
+ 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_MPEG_REG(RESET0_REGISTER,
+ RESET_IQIDCT | RESET_MC | RESET_VLD_PART);
+ READ_MPEG_REG(RESET0_REGISTER);
+ WRITE_MPEG_REG(RESET0_REGISTER,
+ RESET_IQIDCT | RESET_MC | RESET_VLD_PART);
+ WRITE_MPEG_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_MPEG_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 void vh264mvc_local_init(void)
+{
+ int i;
+ 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;
+
+ /**/ dpb_start_addr[0] = -1;
+ dpb_start_addr[1] = -1;
+ 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));
+ init_vf_buf();
+ return;
+}
+
+static s32 vh264mvc_init(void)
+{
+ int ret = -1, size = -1;
+ char *buf = vmalloc(0x1000 * 16);
+ if (IS_ERR_OR_NULL(buf))
+ return -ENOMEM;
+
+ pr_info("\nvh264mvc_init\n");
+ init_timer(&recycle_timer);
+
+ stat |= STAT_TIMER_INIT;
+
+ vh264mvc_local_init();
+
+ 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_mvc init: Can not allocate mc memory.\n");
+ return -ENOMEM;
+ }
+
+ WRITE_VREG(UCODE_START_ADDR, mc_dma_handle);
+
+ size = get_firmware_data(VIDEO_DEC_H264_MVC, buf);
+ if (size < 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);
+
+ vfree(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;
+ return -EBUSY;
+ }
+
+ 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();
+
+ 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 resource mem;
+ int buf_size;
+
+ struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
+
+ pr_info("amvdec_h264mvc probe start.\n");
+
+#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) {
+ pr_info("\namvdec_h264mvc memory resource undefined.\n");
+ return -EFAULT;
+ }
+ mem.start = pdata->mem_start;
+ mem.end = pdata->mem_end;
+
+ buf_size = mem.end - mem.start + 1;
+ /* buf_offset = mem->start - DEF_BUF_START_ADDR; */
+ work_space_adr = mem.start;
+ DECODE_BUFFER_START = work_space_adr + work_space_size;
+ DECODE_BUFFER_END = mem.start + buf_size;
+
+ pr_info
+ ("work_space_adr %x, DECODE_BUFFER_START %x, DECODE_BUFFER_END %x\n",
+ work_space_adr, DECODE_BUFFER_START, DECODE_BUFFER_END);
+ if (pdata->sys_info)
+ vh264mvc_amstream_dec_info = *pdata->sys_info;
+
+ pdata->dec_status = vh264mvc_dec_status;
+ /* pdata->set_trickmode = vh264mvc_set_trickmode; */
+
+ if (vh264mvc_init() < 0) {
+ pr_info("\namvdec_h264mvc init failed.\n");
+
+ return -ENODEV;
+ }
+
+ INIT_WORK(&error_wd_work, error_do_work);
+
+ atomic_set(&vh264mvc_active, 1);
+
+ 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(&error_wd_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
+
+ return 0;
+}
+
+/****************************************/
+
+static struct platform_driver amvdec_h264mvc_driver = {
+ .probe = amvdec_h264mvc_probe,
+ .remove = amvdec_h264mvc_remove,
+#ifdef CONFIG_PM
+ .suspend = amvdec_suspend,
+ .resume = amvdec_resume,
+#endif
+ .driver = {
+ .name = DRIVER_NAME,
+ }
+};
+
+static struct codec_profile_t amvdec_hmvc_profile = {
+ .name = "hmvc",
+ .profile = ""
+};
+
+static 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);
+
+ 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(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_mode, "\n amvdec_h264mvc cmd mode\n");
+
+module_param(drop_rate, uint, 0664);
+MODULE_PARM_DESC(dbg_mode, "\n amvdec_h264mvc drop rate\n");
+
+module_param(drop_thread_hold, uint, 0664);
+MODULE_PARM_DESC(dbg_mode, "\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..17cb87e
--- a/dev/null
+++ b/drivers/frame_provider/decoder/h264_multi/Makefile
@@ -0,0 +1,2 @@
+obj-m += vh264_multi.o
+vh264_multi-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..b3e8f0f
--- a/dev/null
+++ b/drivers/frame_provider/decoder/h264_multi/h264_dpb.c
@@ -0,0 +1,5238 @@
+#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 OLD_OUTPUT_CODE */
+#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);
+ if ((index & 0x100) == 0)
+ len = sprintf(buf, "%d: ", index);
+ 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; \
+ } \
+ }
+
+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 dump_dpb(struct DecodedPictureBuffer *p_Dpb);
+
+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_ERROR,
+ "%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_ERROR,
+ "%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];
+ sps->num_ref_frames = p_H264_Dpb->
+ dpb_param.l.data[MAX_REFERENCE_FRAME_NUM];
+ 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;
+ }
+ /* pSlice->adaptive_ref_pic_buffering_flag; */
+ sps->log2_max_frame_num_minus4 =
+ p_H264_Dpb->dpb_param.l.data[LOG2_MAX_FRAME_NUM] - 4;
+
+ 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]=%d, num_ref_idx_active[1]=%d nal_reference_idc %d\n",
+ __func__, pSlice->slice_type,
+ pSlice->num_ref_idx_active[LIST_0],
+ pSlice->num_ref_idx_active[LIST_1],
+ pSlice->nal_reference_idc);
+#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;
+ if (pSlice->num_ref_idx_active[LIST_1] >= MAX_LIST_SIZE)
+ pSlice->num_ref_idx_active[LIST_1] = MAX_LIST_SIZE - 1;
+#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
+ 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];
+ 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) {
+ /*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);
+ return;
+ }
+
+ picture->colocated_buf_index = -1;
+ picture->buf_spec_num = -1;
+
+ 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;
+
+ store_picture_in_dpb(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;
+}
+
+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);
+ }
+
+}
+
+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->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;
+#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;
+
+ 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]"); */
+ }
+ }
+ }
+ }
+ 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)
+{
+ 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 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 (%d) num_ref_frames = %d (%d)\n",
+ __func__, p_Dpb->size, active_sps->max_dpb_size,
+ p_Dpb->num_ref_frames,
+ 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;
+#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;
+#endif
+
+
+ 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;
+ 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;
+ }
+
+ 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;
+ /* 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)
+{
+ 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);
+#if 1
+/* rain */
+/* p->buf_spec_num = fs->index; */
+ fs->buf_spec_num = p->buf_spec_num;
+ fs->colocated_buf_index = p->colocated_buf_index;
+#endif
+ switch (p->structure) {
+ case FRAME:
+ fs->frame = p;
+ fs->is_used = 3;
+ 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->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 (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 (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;
+
+ 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;
+}
+
+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->frame = NULL;
+ f->top_field = NULL;
+ f->bottom_field = NULL;
+
+ /* free(f); */
+ }
+}
+
+static 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 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 Slice *currSlice)
+{
+ unsigned int i;
+ 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++) {
+ 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++) {
+ 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++) {
+ 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) {
+ 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) {
+ 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++) {
+ if (p_Dpb->fs_ltref[i]->is_long_term & 1) {
+ 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) {
+ 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 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->is_used = 0;
+ fs->is_long_term = 0;
+ fs->is_reference = 0;
+ fs->is_orig_reference = 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;
+ 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 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;
+}
+
+void bufmgr_h264_remove_unused_frame(struct h264_dpb_stru *p_H264_Dpb)
+{
+ struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB;
+ int ret = 0;
+ unsigned char print_flag = 0;
+ do {
+ ret = remove_unused_frame_from_dpb(p_H264_Dpb);
+ if (ret != 0)
+ print_flag = 1;
+ } while (ret != 0);
+ if (print_flag) {
+ dpb_print(p_H264_Dpb->decoder_index,
+ PRINT_FLAG_DPB_DETAIL, "%s\r\n", __func__);
+ dump_dpb(p_Dpb);
+ }
+}
+
+#ifdef OUTPUT_BUFFER_IN_C
+int is_there_unused_frame_from_dpb(struct DecodedPictureBuffer *p_Dpb)
+{
+ unsigned 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 i;
+ 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__);
+ 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;
+ 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;
+ }
+ }
+}
+
+#ifdef OLD_OUTPUT_CODE
+static int output_one_frame_from_dpb(struct h264_dpb_stru *p_H264_Dpb)
+{
+ struct DecodedPictureBuffer *p_Dpb = &p_H264_Dpb->mDPB;
+ struct VideoParameters *p_Vid = &p_H264_Dpb->mVideo;
+ int poc, pos;
+ /* diagnostics */
+ 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 output frame, DPB empty. %d\n", 150);
+ }
+
+ /* find smallest POC */
+ get_smallest_poc(p_Dpb, &poc, &pos);
+
+ if (pos == -1)
+ return 0;
+
+ /* call the output function */
+ /* dpb_print(p_H264_Dpb->decoder_index,
+ PRINT_FLAG_DPB_DETAIL,
+ "output frame with frame_num #%d, poc %d"
+ "(dpb. p_Dpb->size = %d, p_Dpb->used_size = %d)\n",
+ p_Dpb->fs[pos]->frame_num, p_Dpb->fs[pos]->frame->poc,
+ p_Dpb->size, p_Dpb->used_size);
+ */
+
+#if 0
+ /* ??? */
+ /* picture error concealment */
+ if (p_Vid->conceal_mode != 0) {
+ if (p_Dpb->last_output_poc == 0)
+ write_lost_ref_after_idr(p_Dpb, pos);
+#if (MVC_EXTENSION_ENABLE)
+ write_lost_non_ref_pic(p_Dpb, poc,
+ p_Vid->p_out_mvc[p_Dpb->layer_id]);
+#else
+ write_lost_non_ref_pic(p_Dpb, poc, p_Vid->p_out);
+#endif
+ }
+#endif
+/* JVT-P072 ends */
+
+#if 0
+/* ??? */
+#if (MVC_EXTENSION_ENABLE)
+ write_stored_frame(p_Vid, p_Dpb->fs[pos],
+ p_Vid->p_out_mvc[p_Dpb->layer_id]);
+#else
+ write_stored_frame(p_Vid, p_Dpb->fs[pos], p_Vid->p_out);
+#endif
+#endif
+ /* picture error concealment */
+ if (p_Vid->conceal_mode == 0) {
+ if (p_Dpb->last_output_poc >= poc) {
+ dpb_print(p_H264_Dpb->decoder_index,
+ PRINT_FLAG_DPB_DETAIL,
+ "output POC must be in ascending order %d\n",
+ 150);
+ }
+ }
+
+ p_Dpb->last_output_poc = poc;
+
+ /* free frame store and move empty store to end of buffer */
+/* #ifdef OUTPUT_BUFFER_IN_C */
+ if ((h264_debug_flag & OUTPUT_CURRENT_BUF) == 0) {
+ if (prepare_display_buf(p_H264_Dpb->vdec,
+ p_Dpb->fs[pos]) >= 0) {
+ p_Dpb->fs[pos]->pre_output = 1;
+ }
+ }
+/* #else */
+ else {
+ if (!is_used_for_reference(p_Dpb->fs[pos])) {
+ release_colocate_buf(p_H264_Dpb,
+ p_Dpb->fs[pos]->colocated_buf_index); /*rain*/
+ p_Dpb->fs[pos]->colocated_buf_index = -1;
+
+ release_buf_spec_num(p_H264_Dpb->vdec,
+ p_Dpb->fs[pos]->buf_spec_num);
+ p_Dpb->fs[pos]->buf_spec_num = -1;
+
+ remove_frame_from_dpb(p_H264_Dpb, pos);
+ }
+/* #endif */
+ }
+ return 1;
+}
+
+#else
+/* none OLD_OUTPUT_CODE */
+
+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;
+ 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))
+ none_displayed_num++;
+ }
+ if (none_displayed_num < p_H264_Dpb->reorder_pic_num)
+ 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
+ p_Dpb->last_output_poc = poc;
+
+ if (prepare_display_buf(p_H264_Dpb->vdec, p_Dpb->fs[pos]) >= 0)
+ p_Dpb->fs[pos]->pre_output = 1;
+
+ dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL,
+ "%s[%d] poc %d\n", __func__, pos, poc);
+
+ return 1;
+
+}
+#endif
+
+
+static 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 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]);
+
+ if (h264_debug_flag & OUTPUT_CURRENT_BUF)
+ set_frame_output_flag(p_H264_Dpb, i);
+
+ }
+
+ while (remove_unused_frame_from_dpb(p_H264_Dpb))
+ ;
+
+ /* output frames in POC order */
+#ifndef OLD_OUTPUT_CODE
+ if ((h264_debug_flag & OUTPUT_CURRENT_BUF) == 0) {
+ while (output_frames(p_H264_Dpb, 1))
+ ;
+ }
+#else
+ while (p_Dpb->used_size && output_one_frame_from_dpb(p_H264_Dpb))
+ ;
+#endif
+
+ 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;
+}
+
+static void update_ref_list(struct DecodedPictureBuffer *p_Dpb)
+{
+ unsigned 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 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 %d %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 i;
+ struct h264_dpb_stru *p_H264_Dpb = container_of(p_Dpb,
+ struct h264_dpb_stru, mDPB);
+
+ /* assert (!p->idr_flag); */
+ dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL,
+ "%s\n", __func__);
+
+ /* if this is a reference pic with sliding window,
+ unmark first ref frame */
+ if (p_Dpb->ref_frames_in_buffer == imax(
+ 1, p_Dpb->num_ref_frames) - p_Dpb->ltref_frames_in_buffer) {
+ 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);
+ }
+}
+
+static void dump_dpb(struct DecodedPictureBuffer *p_Dpb)
+{
+ 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)
+ return;
+ for (i = 0; i < p_Dpb->used_size; i++) {
+ dpb_print(p_H264_Dpb->decoder_index,
+ PRINT_FLAG_DUMP_DPB,
+ "(");
+ dpb_print(p_H264_Dpb->decoder_index,
+ PRINT_FLAG_DUMP_DPB | 0x100,
+ "fn=%d ", p_Dpb->fs[i]->frame_num);
+ if (p_Dpb->fs[i]->is_used & 1) {
+ if (p_Dpb->fs[i]->top_field)
+ dpb_print(p_H264_Dpb->decoder_index,
+ PRINT_FLAG_DUMP_DPB | 0x100,
+ "T: poc=%d ",
+ p_Dpb->fs[i]->top_field->poc);
+ else
+ dpb_print(p_H264_Dpb->decoder_index,
+ PRINT_FLAG_DUMP_DPB | 0x100,
+ "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(p_H264_Dpb->decoder_index,
+ PRINT_FLAG_DUMP_DPB | 0x100,
+ "B: poc=%d ",
+ p_Dpb->fs[i]->bottom_field->poc);
+ else
+ dpb_print(p_H264_Dpb->decoder_index,
+ PRINT_FLAG_DUMP_DPB | 0x100,
+ "B: poc=%d ",
+ p_Dpb->fs[i]->frame->bottom_poc);
+ }
+ if (p_Dpb->fs[i]->is_used == 3)
+ dpb_print(p_H264_Dpb->decoder_index,
+ PRINT_FLAG_DUMP_DPB | 0x100,
+ "F: poc=%d ",
+ p_Dpb->fs[i]->frame->poc);
+ dpb_print(p_H264_Dpb->decoder_index,
+ PRINT_FLAG_DUMP_DPB | 0x100,
+ "G: poc=%d) ", p_Dpb->fs[i]->poc);
+ if (p_Dpb->fs[i]->is_reference)
+ dpb_print(p_H264_Dpb->decoder_index,
+ PRINT_FLAG_DUMP_DPB | 0x100,
+ "ref (%d) ", p_Dpb->fs[i]->is_reference);
+ if (p_Dpb->fs[i]->is_long_term)
+ dpb_print(p_H264_Dpb->decoder_index,
+ PRINT_FLAG_DUMP_DPB | 0x100,
+ "lt_ref (%d) ", p_Dpb->fs[i]->is_reference);
+ if (p_Dpb->fs[i]->is_output)
+ dpb_print(p_H264_Dpb->decoder_index,
+ PRINT_FLAG_DUMP_DPB | 0x100,
+ "out ");
+ if (p_Dpb->fs[i]->pre_output)
+ dpb_print(p_H264_Dpb->decoder_index,
+ PRINT_FLAG_DUMP_DPB | 0x100,
+ "for_out ");
+ if (p_Dpb->fs[i]->is_used == 3) {
+ if (p_Dpb->fs[i]->frame->non_existing)
+ dpb_print(p_H264_Dpb->decoder_index,
+ PRINT_FLAG_DUMP_DPB | 0x100,
+ "ne ");
+ }
+#if (MVC_EXTENSION_ENABLE)
+ if (p_Dpb->fs[i]->is_reference)
+ dpb_print(p_H264_Dpb->decoder_index,
+ PRINT_FLAG_DUMP_DPB | 0x100,
+ "view_id (%d) ", p_Dpb->fs[i]->view_id);
+#endif
+ dpb_print(p_H264_Dpb->decoder_index,
+ PRINT_FLAG_DUMP_DPB | 0x100,
+ "\n");
+ }
+}
+
+
+/*!
+ ************************************************************************
+ * \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)
+{
+ 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++) {
+ if (p->structure == FRAME) {
+ if ((p_Dpb->fs_ref[i]->is_reference == 3) &&
+ (p_Dpb->fs_ref[i]->is_long_term == 0)) {
+ 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))) {
+ 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) {
+ 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))) {
+ 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) {
+ 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 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)(curr_pic_num >> 1))
+ unmark_for_long_term_reference(p_Dpb->fs_ltref[i]);
+}
+
+static void unmark3_top(struct DecodedPictureBuffer *p_Dpb,
+ unsigned 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 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 curr_frame_num,
+ int curr_pic_num)
+{
+ struct VideoParameters *p_Vid = p_Dpb->p_Vid;
+ unsigned 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++) {
+ if (p_Dpb->fs_ref[i]->is_reference == 3) {
+ 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++) {
+ if (p_Dpb->fs_ref[i]->is_reference & 1) {
+ 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) {
+ 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) {
+ 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) {
+ 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 i;
+ enum PictureStructure structure = FRAME;
+
+ for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) {
+ if (p_Dpb->fs_ref[i]->is_reference & 1) {
+ if (p_Dpb->fs_ref[i]->top_field->
+ pic_num == picNumX) {
+ structure = TOP_FIELD;
+ break;
+ }
+ }
+ if (p_Dpb->fs_ref[i]->is_reference & 2) {
+ 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
+ }
+}
+
+
+void store_picture_in_dpb(struct h264_dpb_stru *p_H264_Dpb,
+ struct StorablePicture *p)
+{
+ /* 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 i;
+#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 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);
+ update_ref_list(p_Dpb);
+ update_ltref_list(p_Dpb);
+ dump_dpb(p_Dpb);
+ p_Dpb->last_picture = NULL;
+ return;
+ }
+ }
+ }
+ }
+ }
+ /* 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;
+ }
+
+#ifndef OLD_OUTPUT_CODE
+ while (remove_unused_frame_from_dpb(p_H264_Dpb))
+ ;
+
+ if ((h264_debug_flag & OUTPUT_CURRENT_BUF) == 0) {
+ while (output_frames(p_H264_Dpb, 0))
+ ;
+ }
+#else
+ /* OLD_OUTPUT_CODE */
+
+ /* first try to remove unused frames */
+ if (p_Dpb->used_size == p_Dpb->size) {
+#if 0
+ /* ??? */
+ /* picture error concealment */
+ if (p_Vid->conceal_mode != 0)
+ conceal_non_ref_pics(p_Dpb, 2);
+#endif
+ remove_unused_frame_from_dpb(p_H264_Dpb);
+
+#if 0
+ /* ??? */
+ if (p_Vid->conceal_mode != 0)
+ sliding_window_poc_management(p_Dpb, p);
+#endif
+ }
+
+ /* then output frames until one can be removed */
+/* #ifdef OUTPUT_BUFFER_IN_C */
+ if ((h264_debug_flag & OUTPUT_CURRENT_BUF) == 0) {
+ if (p_Dpb->used_size > (p_Dpb->size - 5))
+ output_one_frame_from_dpb(p_H264_Dpb);
+ } else {
+/* #else */
+ while (p_Dpb->used_size == p_Dpb->size) {
+#if 0
+ /* non-reference frames may be output directly */
+ if (!p->used_for_reference) {
+ get_smallest_poc(p_Dpb, &poc, &pos);
+ if ((-1 == pos) || (p->poc < poc)) {
+#if (MVC_EXTENSION_ENABLE)
+ if (p_Vid->profile_idc >= MVC_HIGH)
+ dpb_print(
+ p_H264_Dpb->decoder_index,
+ PRINT_FLAG_DPB_DETAIL,
+ "Display order might not be correct, %d, %d\n",
+ p->view_id, p->poc);
+#endif
+#if 0
+/* ??? */
+#if (MVC_EXTENSION_ENABLE)
+ direct_output(p_Vid, p, p_Vid->
+ p_out_mvc[p_Dpb->layer_id]);
+#else
+ direct_output(p_Vid, p, p_Vid->p_out);
+#endif
+#endif
+ return;
+ }
+ }
+#endif
+ /* flush a frame */
+ output_one_frame_from_dpb(p_H264_Dpb);
+ }
+
+ }
+/* #endif */
+ /* OLD_OUTPUT_CODE */
+#endif
+
+ /* 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++) {
+ 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);
+ }
+ }
+ }
+ /* 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);
+ return;
+ }
+
+ insert_picture_in_dpb(p_H264_Dpb, p_Dpb->fs[p_Dpb->used_size], p);
+ if (h264_debug_flag & OUTPUT_CURRENT_BUF) {
+ prepare_display_buf(p_H264_Dpb->vdec,
+ p_Dpb->fs[p_Dpb->used_size]);
+ set_frame_output_flag(p_H264_Dpb, p_Dpb->used_size);
+
+ }
+
+ /* 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);
+
+ dump_dpb(p_Dpb);
+}
+
+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++) {
+ 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 (NULL == fs_list0)
+ no_mem_exit("init_lists: fs_list0");
+ fs_listlt = calloc(p_Dpb->size, sizeof(struct FrameStore *));
+ if (NULL == fs_listlt)
+ 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++) {
+ 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 VideoParameters *p_Vid,
+ struct Slice *currSlice)
+{
+ unsigned j;
+ int i;
+
+ 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) {
+ 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) {
+ 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++) {
+ 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++) {
+ 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 (NULL == fs_list0)
+ no_mem_exit("init_lists: fs_list0");
+ fs_list1 = calloc(p_Dpb->size,
+ sizeof(struct FrameStore *));
+ if (NULL == fs_list1)
+ no_mem_exit("init_lists: fs_list1");
+ fs_listlt = calloc(p_Dpb->size,
+ sizeof(struct FrameStore *));
+ if (NULL == fs_listlt)
+ 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++) {
+ 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++) {
+ 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 i;
+
+ for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) {
+ if (currSlice->structure == FRAME) {
+ if (p_Dpb->fs_ref[i]->is_reference == 3)
+ 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 {
+ if (p_Dpb->fs_ref[i]->is_reference & 1)
+ 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)
+ if ((!p_Dpb->fs_ref[i]->bottom_field->
+ is_long_term) &&
+ (p_Dpb->fs_ref[i]->bottom_field->
+ pic_num == picNum))
+ return p_Dpb->fs_ref[i]->bottom_field;
+ }
+ }
+
+ return currSlice->p_Vid->no_reference_picture;
+}
+
+
+static void reorder_short_term(struct Slice *currSlice, int cur_list,
+ int num_ref_idx_lX_active_minus1,
+ int picNumLX, int *refIdxLX)
+{
+ struct h264_dpb_stru *p_H264_Dpb = container_of(currSlice->p_Vid,
+ struct h264_dpb_stru, mVideo);
+
+ struct StorablePicture **RefPicListX = currSlice->listX[cur_list];
+ int cIdx, nIdx;
+
+ struct StorablePicture *picLX;
+
+ picLX = get_short_term_pic(currSlice, currSlice->p_Dpb, picNumLX);
+
+ for (cIdx = num_ref_idx_lX_active_minus1 + 1; cIdx > *refIdxLX;
+ cIdx--) {
+ dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL,
+ "%s: RefPicListX[ %d ] = RefPicListX[ %d ]\n",
+ __func__, cIdx, cIdx - 1);
+ RefPicListX[cIdx] = RefPicListX[cIdx - 1];
+ }
+
+ dpb_print(p_H264_Dpb->decoder_index, PRINT_FLAG_DPB_DETAIL,
+ "%s: RefPicListX[ %d ] = pic %x (%d)\n", __func__,
+ *refIdxLX, picLX, picNumLX);
+
+ RefPicListX[(*refIdxLX)++] = picLX;
+
+ nIdx = *refIdxLX;
+
+ for (cIdx = *refIdxLX; cIdx <= num_ref_idx_lX_active_minus1 + 1;
+ cIdx++) {
+ if (RefPicListX[cIdx])
+ if ((RefPicListX[cIdx]->is_long_term) ||
+ (RefPicListX[cIdx]->pic_num != picNumLX)) {
+ dpb_print(p_H264_Dpb->decoder_index,
+ PRINT_FLAG_DPB_DETAIL,
+ "%s: RefPicListX[ %d ] = RefPicListX[ %d ]\n",
+ __func__, nIdx, cIdx);
+ RefPicListX[nIdx++] = RefPicListX[cIdx];
+ }
+ }
+}
+
+
+static struct StorablePicture *get_long_term_pic(struct Slice *currSlice,
+ struct DecodedPictureBuffer *p_Dpb, int LongtermPicNum)
+{
+ unsigned int i;
+
+ for (i = 0; i < p_Dpb->ltref_frames_in_buffer; i++) {
+ if (currSlice->structure == FRAME) {
+ if (p_Dpb->fs_ltref[i]->is_reference == 3)
+ if ((p_Dpb->fs_ltref[i]->frame->
+ 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->
+ 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->
+ 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)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(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");
+ }
+ }
+
+ 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++) {
+ 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");
+ }
+ }
+
+ /* 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;
+ 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;
+ dump_dpb(p_Dpb);
+}
+
+#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 |= (NULL == dec_picture);
+
+ 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
+
+int remove_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);
+ }
+ free_picture(p_H264_Dpb, pic);
+ return 0;
+}
+
+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->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 new_pic_flag = 0;
+ struct Slice *currSlice = &p_H264_Dpb->mSlice;
+ struct VideoParameters *p_Vid = &p_H264_Dpb->mVideo;
+#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
+
+ slice_prepare(p_H264_Dpb, &p_H264_Dpb->mDPB, &p_H264_Dpb->mVideo,
+ &p_H264_Dpb->mSPS, &p_H264_Dpb->mSlice);
+
+ /* 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 &&
+ currSlice->frame_num != p_Vid->pre_frame_num &&
+ currSlice->frame_num !=
+ (p_Vid->pre_frame_num + 1) % p_Vid->max_frame_num) {
+ /*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)*/
+ fill_frame_num_gap(p_Vid, currSlice);
+ }
+
+ 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) {
+ 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 */
+ p_H264_Dpb->mVideo.dec_picture->offset_delimiter_lo =
+ p_H264_Dpb->dpb_param.l.data[OFFSET_DELIMITER_LO];
+ p_H264_Dpb->mVideo.dec_picture->offset_delimiter_hi =
+ p_H264_Dpb->dpb_param.l.data[OFFSET_DELIMITER_HI];
+
+ 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->mSlice);
+
+ 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->
+ used_for_reference) {
+ p_H264_Dpb->mVideo.dec_picture->
+ colocated_buf_index =
+ allocate_colocate_buf(
+ p_H264_Dpb);
+ }
+ }
+#endif
+ }
+ }
+
+ 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->mVideo, &p_H264_Dpb->mSlice);
+
+ if (new_pic_flag)
+ return 1;
+
+ 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..e58f084
--- a/dev/null
+++ b/drivers/frame_provider/decoder/h264_multi/h264_dpb.h
@@ -0,0 +1,788 @@
+#ifndef H264_DPB_H_
+#define H264_DPB_H_
+
+#define ERROR_CHECK
+
+#define OUTPUT_BUFFER_IN_C
+
+#define PRINT_FLAG_ERROR 0x0
+#define PRINT_FLAG_DPB 0X0001
+#define PRINT_FLAG_DPB_DETAIL 0x0002
+#define PRINT_FLAG_DUMP_DPB 0x0004
+#define PRINT_FLAG_UCODE_EVT 0x0008
+#define PRINT_FLAG_VDEC_STATUS 0x0010
+#define PRINT_FLAG_VDEC_DETAIL 0x0020
+#define PRINT_FLAG_UCODE_DBG 0x0040
+#define PRINT_FLAG_TIME_STAMP 0x0080
+#define PRINT_FLAG_RUN_SCHEDULE 0x0100
+#define PRINT_FLAG_DEBUG_POC 0x0200
+#define PRINT_FLAG_VDEC_DATA 0x0400
+#define DISABLE_ERROR_HANDLE 0x10000
+#define OUTPUT_CURRENT_BUF 0x20000
+#define ONLY_RESET_AT_START 0x40000
+#define LOAD_UCODE_ALWAYS 0x80000
+#define FORCE_NO_SLICE 0x100000
+#define REINIT_DPB_TEST 0x200000
+
+
+#define MVC_EXTENSION_ENABLE 0
+#define PRINTREFLIST 0
+
+#define MAX_LIST_SIZE 33
+
+#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_DECODE_BUFEMPTY 0x20
+#define H264_DECODE_TIMEOUT 0x21
+#define H264_SEARCH_BUFEMPTY 0x22
+ /* 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 {
+#define H_TIME_STAMP_START 0X00
+#define H_TIME_STAMP_END 0X17
+#define PTS_ZERO_0 0X18
+#define PTS_ZERO_1 0X19
+#define FIXED_FRAME_RATE_FLAG 0X1A
+
+#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
+#define POC_SELECT_NEED_SWAP 0X6C
+#define POC_SELECT_SWAP 0X6D
+#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];
+ } 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
+};
+
+#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
+};
+
+struct SPSParameters {
+ 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;
+};
+
+#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];
+};
+
+struct OldSliceParams {
+ unsigned field_pic_flag;
+ unsigned frame_num;
+ int nal_ref_idc;
+ unsigned 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 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 PicWidthInMbs;
+ unsigned 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;
+
+ int offset_delimiter_lo;
+ int offset_delimiter_hi;
+
+ u32 pts;
+ u64 pts64;
+};
+
+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 frame_num;
+ unsigned 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;
+#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 pts;
+ u64 pts64;
+};
+
+int prepare_display_buf(struct vdec_s *vdec, struct FrameStore *frame);
+
+
+/* #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 size;
+ unsigned used_size;
+ unsigned ref_frames_in_buffer;
+ unsigned 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 num_ref_frames;
+
+ struct FrameStore *last_picture;
+ unsigned 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 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];
+
+};
+
+
+extern unsigned int h264_debug_flag;
+extern unsigned int h264_debug_mask;
+
+int dpb_print(int indext, 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);
+
+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);
+
+void store_picture_in_dpb(struct h264_dpb_stru *p_H264_Dpb,
+ struct StorablePicture *p);
+
+int remove_picture(struct h264_dpb_stru *p_H264_Dpb,
+ struct StorablePicture *pic);
+
+void bufmgr_post(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);
+
+#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..59b7457
--- a/dev/null
+++ b/drivers/frame_provider/decoder/h264_multi/vmh264.c
@@ -0,0 +1,2776 @@
+/*
+ * 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.
+ *
+*/
+
+#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/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/media/utils/vdec_reg.h>
+#include "../utils/vdec.h"
+#include "../utils/amvdec.h"
+#include "../h264/vh264.h"
+#include "../../../stream_input/parser/streambuf.h"
+#include <linux/delay.h>
+
+#undef pr_info
+#define pr_info printk
+
+#define DEBUG_UCODE
+#define USE_CMA
+#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 MODULE_NAME "ammvdec_h264"
+
+#define CHECK_INTERVAL (HZ/100)
+
+#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 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 5
+
+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 unsigned int dec_control;
+static unsigned int force_rate_streambase;
+static unsigned int force_rate_framebase;
+static unsigned int fixed_frame_rate_mode;
+static unsigned int error_recovery_mode_in;
+static unsigned int start_decode_buf_level = 0x8000;
+
+static unsigned int reorder_dpb_size_margin = 6;
+static unsigned int reference_buf_margin = 4;
+
+static unsigned int decode_timeout_val = 50;
+static unsigned int radr;
+static unsigned int rval;
+static unsigned int max_decode_instance_num = H264_DEV_NUM;
+static unsigned int decode_frame_count[H264_DEV_NUM];
+static unsigned int max_process_time[H264_DEV_NUM];
+static unsigned int max_get_frame_interval[H264_DEV_NUM];
+ /* bit[3:0]:
+ 0, run ; 1, pause; 3, step
+ bit[4]:
+ 1, schedule run
+ */
+static unsigned int step[H264_DEV_NUM];
+
+#define is_in_parsing_state(status) \
+ ((status == H264_ACTION_SEARCH_HEAD) || \
+ ((status & 0xf0) == 0x80))
+
+static inline bool close_to(int a, int b, int m)
+{
+ return (abs(a - b) < m) ? true : false;
+}
+
+/* #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 0x1000000
+#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 MAX_VF_BUF_NUM 28
+#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 DEC_CONTROL_FLAG_FORCE_2997_1080P_INTERLACE 0x0001
+#define DEC_CONTROL_FLAG_FORCE_2500_576P_INTERLACE 0x0002
+
+#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:
+ 0, free; 1, used by dpb; 2,
+ used for display;
+ 3 isolated (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 NV21
+ struct canvas_config_s canvas_config[2];
+#else
+ struct canvas_config_s canvas_config[3];
+#endif
+#ifdef USE_CMA
+ /* struct page *cma_alloc_pages; */
+ unsigned long cma_alloc_addr;
+ int cma_alloc_count;
+#endif
+ unsigned int buf_adr;
+};
+
+#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_work(struct work_struct *work);
+
+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
+
+/*
+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_INFO M4_CONTROL_REG /* 0xc29 */
+#define DPB_STATUS_REG AV_SCRATCH_J
+#define MBY_MBX MB_MOTION_MODE /*0xc07*/
+
+struct vdec_h264_hw_s {
+ spinlock_t lock;
+
+ struct platform_device *platform_dev;
+ struct device *cma_dev;
+ /* struct page *cma_alloc_pages; */
+ unsigned long cma_alloc_addr;
+ int cma_alloc_count;
+ /* struct page *collocate_cma_alloc_pages; */
+ unsigned long collocate_cma_alloc_addr;
+ int collocate_cma_alloc_count;
+
+ ulong lmem_addr;
+ dma_addr_t lmem_addr_remap;
+
+ 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[MAX_VF_BUF_NUM];
+ int buffer_spec_num;
+ struct vframe_s switching_fense_vf;
+ struct h264_dpb_stru dpb;
+ u8 init_flag;
+ u8 set_params_done;
+ u32 max_reference_size;
+ u32 decode_pic_count;
+ int start_search_pos;
+
+ 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 timing_info_present_flag;
+ u32 fixed_frame_rate_flag;
+ u32 fixed_frame_rate_check_count;
+ 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 duration_on_correcting;
+ u32 last_checkout_pts;
+ u32 fatal_error_flag;
+ u32 fatal_error_reset;
+ 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 saved_resolution;
+ 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;
+
+ void *sei_data_buffer;
+ dma_addr_t sei_data_buffer_phys;
+
+ uint error_recovery_mode;
+ uint mb_total;
+ uint mb_width;
+ uint mb_height;
+
+ uint ucode_type;
+ dma_addr_t mc_dma_handle;
+ void *mc_cpu_addr;
+ int vh264_reset;
+
+ atomic_t vh264_active;
+
+ struct dec_sysinfo vh264_amstream_dec_info;
+
+ struct work_struct error_wd_work;
+
+ int dec_result;
+ struct work_struct work;
+
+ void (*vdec_cb)(struct vdec_s *, void *);
+ void *vdec_cb_arg;
+
+ struct timer_list check_timer;
+
+ /**/
+ unsigned last_frame_time;
+
+ /* timeout handle */
+ unsigned long int start_process_time;
+ unsigned last_mby_mbx;
+ unsigned last_ucode_watchdog_reg_val;
+ unsigned decode_timeout_count;
+ unsigned timeout_num;
+ unsigned search_dataempty_num;
+ unsigned decode_timeout_num;
+ unsigned decode_dataempty_num;
+ unsigned buffer_empty_recover_num;
+
+ /**/
+
+ /*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;
+};
+
+
+static void vh264_local_init(struct vdec_h264_hw_s *hw);
+static int vh264_hw_ctx_restore(struct vdec_h264_hw_s *hw);
+static int vh264_stop(struct vdec_h264_hw_s *hw, int mode);
+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);
+
+unsigned char have_free_buf_spec(struct vdec_s *vdec)
+{
+ int i;
+ struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private;
+ if ((h264_debug_flag&OUTPUT_CURRENT_BUF) == 0) {
+ for (i = 0; i < hw->buffer_spec_num; i++) {
+ if (hw->buffer_spec[i].used == 0)
+ return 1;
+ }
+ return 0;
+ } else
+ return 1;
+}
+
+#if 0
+static void buf_spec_recover(struct vdec_h264_hw_s *hw)
+{ /* do not clear buf_spec used by display */
+ int i;
+ dpb_print(hw->dpb.decoder_index,
+ PRINT_FLAG_DPB, "%s\n", __func__);
+ for (i = 0; i < hw->buffer_spec_num; i++) {
+ if (hw->buffer_spec[i].used == 2)
+ hw->buffer_spec[i].used = 3;
+ else
+ hw->buffer_spec[i].used = 0;
+ }
+}
+#endif
+
+int get_free_buf_idx(struct vdec_s *vdec)
+{
+ int i;
+ int index = -1;
+ struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private;
+
+ if ((h264_debug_flag&OUTPUT_CURRENT_BUF) == 0) {
+ for (i = hw->start_search_pos; i < hw->buffer_spec_num; i++) {
+ if (hw->buffer_spec[i].used == 0) {
+ hw->buffer_spec[i].used = 1;
+ hw->start_search_pos = i+1;
+ index = i;
+ break;
+ }
+ }
+ if (index < 0) {
+ for (i = 0; i < hw->start_search_pos; i++) {
+ if (hw->buffer_spec[i].used == 0) {
+ hw->buffer_spec[i].used = 1;
+ hw->start_search_pos = i+1;
+ index = i;
+ break;
+ }
+ }
+ }
+ } else {
+ index = hw->start_search_pos;
+ hw->start_search_pos++;
+ }
+
+ if (hw->start_search_pos >= hw->buffer_spec_num)
+ hw->start_search_pos = 0;
+
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_DPB_DETAIL,
+ "%s, buf_spec_num %d\n", __func__, index);
+
+ return index;
+}
+
+int release_buf_spec_num(struct vdec_s *vdec, int buf_spec_num)
+{
+ struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private;
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_DPB_DETAIL,
+ "%s buf_spec_num %d\n",
+ __func__, buf_spec_num);
+ if (buf_spec_num >= 0 && buf_spec_num < hw->buffer_spec_num)
+ hw->buffer_spec[buf_spec_num].used = 0;
+ return 0;
+}
+
+static int get_buf_spec_idx_by_canvas_config(struct vdec_h264_hw_s *hw,
+ struct canvas_config_s *cfg)
+{
+ int i;
+ for (i = 0; i < hw->buffer_spec_num; i++) {
+ if (hw->buffer_spec[i].canvas_config[0].phy_addr
+ == cfg->phy_addr)
+ return i;
+ }
+ return -1;
+}
+
+int prepare_display_buf(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;
+
+ if (kfifo_get(&hw->newframe_q, &vf) == 0) {
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_VDEC_STATUS,
+ "%s fatal error, no available buffer slot.\n",
+ __func__);
+ return -1;
+ }
+
+ if (vf) {
+ int buffer_index = frame->buf_spec_num;
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_DPB_DETAIL,
+ "%s, fs[%d] poc %d, buf_spec_num %d\n",
+ __func__, frame->index, frame->poc,
+ frame->buf_spec_num);
+ vf->index = frame->index;
+ vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD |
+ VIDTYPE_VIU_NV21;
+ vf->duration_pulldown = 0;
+ vf->pts = frame->pts;
+ vf->pts_us64 = frame->pts64;
+ vf->canvas0Addr = vf->canvas1Addr =
+ spec2canvas(&hw->buffer_spec[buffer_index]);
+ set_frame_info(hw, vf, buffer_index);
+ kfifo_put(&hw->display_q, (const struct vframe_s *)vf);
+ hw->buffer_spec[buffer_index].used = 2;
+
+ vf_notify_receiver(vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
+ decode_frame_count[hw->dpb.decoder_index]++;
+ }
+
+ 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)
+{
+ dpb_print(decindex, PRINT_FLAG_UCODE_EVT,
+ "%s: %s (original %s), %s, mb_aff_frame_flag %d poc %d, pic_num %d, buf_spec_num %d\n",
+ info,
+ picture_structure_name[pic->structure],
+ pic->coded_frame ? "Frame" : "Field",
+ (slice_type < 0) ? "" : slice_type_name[slice_type],
+ pic->mb_aff_frame_flag,
+ pic->poc,
+ pic->pic_num,
+ pic->buf_spec_num);
+}
+
+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[hw->dpb.decoder_index])
+ max_process_time[hw->dpb.decoder_index] = process_time;
+ }
+}
+
+void config_decode_buf(struct vdec_h264_hw_s *hw, struct StorablePicture *pic)
+{
+ /* static int count = 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;
+
+#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 */
+
+ unsigned long canvas_adr;
+ unsigned ref_reg_val;
+ unsigned one_ref_cfg = 0;
+ int h264_buffer_info_data_write_count;
+ int i, j;
+ unsigned colocate_wr_adr;
+ unsigned colocate_rd_adr;
+ unsigned char use_direct_8x8;
+
+ 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(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "%s: pic_num is %d, poc is %d (%d, %d, %d), buf_spec_num %d\n",
+ __func__, pic->pic_num, pic->poc, pic->frame_poc,
+ pic->top_poc, pic->bottom_poc, pic->buf_spec_num);
+ print_pic_info(hw->dpb.decoder_index, "cur", pic, pSlice->slice_type);
+
+ WRITE_VREG(CURR_CANVAS_CTRL, pic->buf_spec_num << 24);
+
+ canvas_adr = READ_VREG(CURR_CANVAS_CTRL) & 0xffffff;
+
+ WRITE_VREG(REC_CANVAS_ADDR, canvas_adr);
+ WRITE_VREG(DBKR_CANVAS_ADDR, canvas_adr);
+ WRITE_VREG(DBKW_CANVAS_ADDR, canvas_adr);
+
+ 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 (i = 0; i < hw->buffer_spec_num; i++) {
+ int 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 */
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "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;
+
+ for (i = 0; i < (unsigned int)(pSlice->listXsize[0]); i++) {
+ /*ref list 0 */
+ struct StorablePicture *ref = pSlice->listX[0][i];
+ unsigned cfg;
+ /* bit[6:5] - frame/field info,
+ * 01 - top, 10 - bottom, 11 - frame
+ */
+#ifdef ERROR_CHECK
+ if (ref == NULL)
+ return;
+#endif
+ if (ref->structure == TOP_FIELD)
+ cfg = 0x1;
+ else if (ref->structure == BOTTOM_FIELD)
+ cfg = 0x2;
+ else /* FRAME */
+ cfg = 0x3;
+ one_ref_cfg = (ref->buf_spec_num & 0x1f) | (cfg << 5);
+ ref_reg_val <<= 8;
+ ref_reg_val |= one_ref_cfg;
+ j++;
+
+ if (j == 4) {
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "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(hw->dpb.decoder_index, "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(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "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(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "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 cfg;
+ /* bit[6:5] - frame/field info,
+ * 01 - top, 10 - bottom, 11 - frame
+ */
+#ifdef ERROR_CHECK
+ if (ref == NULL)
+ return;
+#endif
+ if (ref->structure == TOP_FIELD)
+ cfg = 0x1;
+ else if (ref->structure == BOTTOM_FIELD)
+ cfg = 0x2;
+ else /* FRAME */
+ cfg = 0x3;
+ one_ref_cfg = (ref->buf_spec_num & 0x1f) | (cfg << 5);
+ ref_reg_val <<= 8;
+ ref_reg_val |= one_ref_cfg;
+ j++;
+
+ if (j == 4) {
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "H264_BUFFER_INFO_DATA: %x\n",
+ ref_reg_val);
+ WRITE_VREG(H264_BUFFER_INFO_DATA, ref_reg_val);
+ j = 0;
+ }
+ print_pic_info(hw->dpb.decoder_index, "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(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "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(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "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(hw->dpb.decoder_index, PRINT_FLAG_ERROR,
+ "Error, colocate buf is not enough, index is %d\n",
+ pic->colocated_buf_index);
+ val = colocate_wr_adr + colocate_adr_offset;
+ WRITE_VREG(H264_CO_MB_WR_ADDR, val);
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "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(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "WRITE_VREG(H264_CO_MB_WR_ADDR) = 0xffffffff\n");
+ }
+#else
+ 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(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "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 * pic->buf_spec_num) >>
+ (use_direct_8x8 ? 2 : 0));
+
+ if ((colocate_wr_adr + p_H264_Dpb->colocated_buf_size) >
+ p_H264_Dpb->colocated_mv_addr_end)
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_ERROR,
+ "Error, colocate buf is not enough, pic index is %d\n",
+ pic->buf_spec_num);
+ val = colocate_wr_adr + colocate_adr_offset;
+ WRITE_VREG(H264_CO_MB_WR_ADDR, val);
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "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)
+ return;
+#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(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ " 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(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ " 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(hw->dpb.decoder_index,
+ PRINT_FLAG_ERROR,
+ "Error, colocate buf is not enough, index is %d\n",
+ colocate_pic->colocated_buf_index);
+ /* 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(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "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(hw->dpb.decoder_index, PRINT_FLAG_ERROR,
+ "Error, reference pic has no colocated buf\n");
+#else
+ colocate_rd_adr = p_H264_Dpb->colocated_mv_addr_start +
+ ((p_H264_Dpb->colocated_buf_size *
+ colocate_pic->buf_spec_num)
+ >> (use_direct_8x8 ? 2 : 0));
+ if ((colocate_rd_adr + p_H264_Dpb->colocated_buf_size) >
+ p_H264_Dpb->colocated_mv_addr_end)
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_ERROR,
+ "Error, colocate buf is not enough, pic index is %d\n",
+ colocate_pic->buf_spec_num);
+ /* 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(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "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
+ }
+}
+
+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;
+ struct vdec_s *vdec = op_arg;
+ struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private;
+
+ if (!hw)
+ return NULL;
+
+ if (kfifo_peek(&hw->display_q, &vf))
+ return vf;
+
+ 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;
+
+ if (!hw)
+ return NULL;
+
+ if (kfifo_get(&hw->display_q, &vf)) {
+ int time = jiffies;
+ unsigned int frame_interval =
+ 1000*(time - hw->last_frame_time)/HZ;
+ if ((h264_debug_flag & OUTPUT_CURRENT_BUF) == 0) {
+ struct h264_dpb_stru *p_H264_Dpb = &hw->dpb;
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "%s from fs[%d], poc %d buf_spec_num %d vf %p\n",
+ __func__, vf->index,
+ p_H264_Dpb->mFrameStore[vf->index].poc,
+ p_H264_Dpb->mFrameStore[vf->index]
+ .buf_spec_num, vf);
+ }
+ if (hw->last_frame_time > 0) {
+ dpb_print(hw->dpb.decoder_index,
+ PRINT_FLAG_TIME_STAMP,
+ "%s duration %d pts %d interval %dms\r\n",
+ __func__, vf->duration, vf->pts, frame_interval);
+ if (frame_interval >
+ max_get_frame_interval[hw->dpb.decoder_index])
+ max_get_frame_interval[hw->dpb.decoder_index]
+ = frame_interval;
+ }
+ hw->last_frame_time = time;
+ return vf;
+ }
+
+ return NULL;
+}
+
+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;
+ struct h264_dpb_stru *p_H264_Dpb = &hw->dpb;
+ int buf_spec_num;
+
+ if ((h264_debug_flag & OUTPUT_CURRENT_BUF) == 0) {
+ buf_spec_num =
+ get_buf_spec_idx_by_canvas_config(hw,
+ &vf->canvas0_config[0]);
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "%s to fs[%d], poc %d buf_spec_num %d used %d\n",
+ __func__, vf->index,
+ p_H264_Dpb->mFrameStore[vf->index].poc,
+ buf_spec_num,
+ hw->buffer_spec[buf_spec_num].used);
+
+ if (hw->buffer_spec[buf_spec_num].used != 3)
+ set_frame_output_flag(&hw->dpb, vf->index);
+ }
+
+ kfifo_put(&hw->newframe_q, (const struct vframe_s *)vf);
+
+#define ASSIST_MBOX1_IRQ_REG VDEC_ASSIST_MBOX1_IRQ_REG
+ if (hw->buffer_empty_flag)
+ WRITE_VREG(ASSIST_MBOX1_IRQ_REG, 0x1);
+}
+
+static int vh264_event_cb(int type, void *data, void *private_data)
+{
+ return 0;
+}
+
+static void set_frame_info(struct vdec_h264_hw_s *hw, struct vframe_s *vf,
+ u32 index)
+{
+ int force_rate = input_frame_based(hw_to_vdec(hw)) ?
+ force_rate_framebase : force_rate_streambase;
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "%s (%d,%d) dur %d, vf %p, index %d\n", __func__,
+ hw->frame_width, hw->frame_height, hw->frame_dur, vf, index);
+
+ 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->flag = 0;
+
+ vf->canvas0Addr = vf->canvas1Addr = -1;
+#ifdef NV21
+ vf->plane_num = 2;
+#else
+ vf->plane_num = 3;
+#endif
+ vf->canvas0_config[0] = hw->buffer_spec[index].canvas_config[0];
+ vf->canvas0_config[1] = hw->buffer_spec[index].canvas_config[1];
+#ifndef NV21
+ vf->canvas0_config[2] = hw->buffer_spec[index].canvas_config[2];
+#endif
+ vf->canvas1_config[0] = hw->buffer_spec[index].canvas_config[0];
+ vf->canvas1_config[1] = hw->buffer_spec[index].canvas_config[1];
+#ifndef NV21
+ vf->canvas1_config[2] = hw->buffer_spec[index].canvas_config[2];
+#endif
+
+ return;
+}
+
+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;
+
+ return size;
+}
+
+static int vh264_set_params(struct vdec_h264_hw_s *hw)
+{
+ int mb_width, mb_total;
+ int max_reference_size, level_idc;
+ int i, mb_height, addr;
+ int mb_mv_byte;
+ struct vdec_s *vdec = hw_to_vdec(hw);
+ int reg_val;
+ int ret = 0;
+#ifdef USE_CMA
+ unsigned int buf_size;
+#endif
+
+ if (hw->set_params_done) {
+ WRITE_VREG(AV_SCRATCH_0,
+ (hw->max_reference_size << 24) |
+ (hw->buffer_spec_num << 16) |
+ (hw->buffer_spec_num << 8));
+ return 0;
+ }
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT, "%s\n",
+ __func__);
+
+#ifndef USE_CMA
+ addr = hw->buf_start;
+#endif
+
+ /* Read AV_SCRATCH_1 */
+ reg_val = READ_VREG(AV_SCRATCH_1);
+ hw->seq_info = READ_VREG(AV_SCRATCH_2);
+ hw->num_units_in_tick = READ_VREG(AV_SCRATCH_4);
+ hw->time_scale = READ_VREG(AV_SCRATCH_5);
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT, "get %x\n",
+ reg_val);
+ mb_mv_byte = (reg_val & 0x80000000) ? 24 : 96;
+
+ mb_width = reg_val & 0xff;
+ mb_total = (reg_val >> 8) & 0xffff;
+ if (!mb_width && mb_total) /*for 4k2k*/
+ mb_width = 256;
+
+ mb_height = mb_total/mb_width;
+#if 1
+ /* if (hw->frame_width == 0 || hw->frame_height == 0) { */
+ hw->frame_width = mb_width * 16;
+ hw->frame_height = mb_height * 16;
+ /* } */
+
+ if (hw->frame_dur == 0)
+ hw->frame_dur = 96000 / 30;
+#endif
+
+ mb_width = (mb_width+3) & 0xfffffffc;
+ mb_height = (mb_height+3) & 0xfffffffc;
+ mb_total = mb_width * mb_height;
+
+ reg_val = READ_VREG(AV_SCRATCH_B);
+ level_idc = reg_val & 0xff;
+ max_reference_size = (reg_val >> 8) & 0xff;
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "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);
+
+
+ hw->mb_total = mb_total;
+ hw->mb_width = mb_width;
+ hw->mb_height = mb_height;
+
+ hw->dpb.reorder_pic_num =
+ get_max_dec_frame_buf_size(level_idc,
+ max_reference_size, mb_width, mb_height);
+ hw->buffer_spec_num =
+ hw->dpb.reorder_pic_num
+ + reorder_dpb_size_margin;
+ hw->max_reference_size = max_reference_size + reference_buf_margin;
+
+ if (hw->buffer_spec_num > MAX_VF_BUF_NUM) {
+ hw->buffer_spec_num = MAX_VF_BUF_NUM;
+ hw->dpb.reorder_pic_num = hw->buffer_spec_num
+ - reorder_dpb_size_margin;
+ }
+ hw->dpb.mDPB.size = hw->buffer_spec_num;
+ hw->dpb.max_reference_size = hw->max_reference_size;
+
+ pr_info("%s buf_spec_num %d reorder_pic_num %d collocate_buf_num %d\r\n",
+ __func__, hw->buffer_spec_num,
+ hw->dpb.reorder_pic_num,
+ hw->max_reference_size);
+
+#ifdef USE_CMA
+ buf_size = (hw->mb_total << 8) + (hw->mb_total << 7);
+#endif
+ for (i = 0; i < hw->buffer_spec_num; i++) {
+ int canvas = vdec->get_canvas(i, 2);
+
+#ifdef USE_CMA
+ if (hw->buffer_spec[i].cma_alloc_count == 0) {
+ hw->buffer_spec[i].cma_alloc_count =
+ PAGE_ALIGN(buf_size) / PAGE_SIZE;
+ hw->buffer_spec[i].cma_alloc_addr =
+ codec_mm_alloc_for_dma(MEM_NAME,
+ hw->buffer_spec[i].cma_alloc_count,
+ 16, CODEC_MM_FLAGS_FOR_VDECODER);
+ }
+
+ if (!hw->buffer_spec[i].cma_alloc_addr) {
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_ERROR,
+ "CMA alloc failed, request buf size 0x%lx\n",
+ hw->buffer_spec[i].cma_alloc_count * PAGE_SIZE);
+ hw->buffer_spec[i].cma_alloc_count = 0;
+ ret = -1;
+ break;
+ }
+ hw->buffer_spec[i].buf_adr =
+ hw->buffer_spec[i].cma_alloc_addr;
+ addr = hw->buffer_spec[i].buf_adr;
+#else
+ hw->buffer_spec[i].buf_adr = addr;
+#endif
+
+ hw->buffer_spec[i].used = 0;
+ 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].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(hw->buffer_spec[i].y_canvas_index,
+ hw->buffer_spec[i].y_addr,
+ hw->mb_width << 4,
+ hw->mb_height << 4,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+
+ 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 =
+ CANVAS_BLKMODE_32X32;
+
+ canvas_config(hw->buffer_spec[i].u_canvas_index,
+ hw->buffer_spec[i].u_addr,
+ hw->mb_width << 4,
+ hw->mb_height << 3,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+
+ 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 =
+ CANVAS_BLKMODE_32X32;
+
+ WRITE_VREG(ANC0_CANVAS_ADDR + i,
+ spec2canvas(&hw->buffer_spec[i]));
+
+ pr_info("config canvas (%d)\r\n", i);
+ }
+
+
+#ifdef USE_CMA
+ if (hw->collocate_cma_alloc_count == 0) {
+ hw->collocate_cma_alloc_count =
+ PAGE_ALIGN(hw->mb_total * mb_mv_byte *
+ hw->max_reference_size) / PAGE_SIZE;
+ hw->collocate_cma_alloc_addr =
+ codec_mm_alloc_for_dma(MEM_NAME,
+ hw->collocate_cma_alloc_count,
+ 16, CODEC_MM_FLAGS_FOR_VDECODER);
+ }
+
+ if (!hw->collocate_cma_alloc_addr) {
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_ERROR,
+ "codec_mm alloc failed, request buf size 0x%lx\n",
+ hw->collocate_cma_alloc_count * PAGE_SIZE);
+ hw->collocate_cma_alloc_count = 0;
+ ret = -1;
+ } else {
+ hw->dpb.colocated_mv_addr_start =
+ hw->collocate_cma_alloc_addr;
+ hw->dpb.colocated_mv_addr_end =
+ hw->dpb.colocated_mv_addr_start +
+ (hw->mb_total * mb_mv_byte * hw->max_reference_size);
+ pr_info("callocate cma %d, %lx, %x\n",
+ hw->collocate_cma_alloc_count,
+ hw->collocate_cma_alloc_addr,
+ hw->dpb.colocated_mv_addr_start);
+ }
+#else
+ hw->dpb.colocated_mv_addr_start = addr;
+ hw->dpb.colocated_mv_addr_end = addr + (hw->mb_total * mb_mv_byte
+ * hw->max_reference_size);
+#endif
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "colocated_mv_addr_start %x colocated_mv_addr_end %x\n",
+ hw->dpb.colocated_mv_addr_start,
+ hw->dpb.colocated_mv_addr_end);
+
+ hw->timing_info_present_flag = hw->seq_info & 0x2;
+ hw->fixed_frame_rate_flag = 0;
+ if (hw->timing_info_present_flag) {
+ hw->fixed_frame_rate_flag = hw->seq_info & 0x40;
+
+ 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;
+ pr_info("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 infomation
+ is more reliable
+ if ((frame_dur * 2) != frame_dur_es) {
+ frame_dur = frame_dur_es;
+ }*/
+ }
+ }
+ } else {
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "H.264: timing_info not present\n");
+ }
+
+ if (hw->pts_unstable && (hw->fixed_frame_rate_flag == 0)) {
+ if (((RATE_2397_FPS == hw->frame_dur)
+ && (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(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "force fix frame rate\n");
+ hw->fixed_frame_rate_flag = 0x40;
+ }
+ }
+
+ hw->set_params_done = 1;
+
+ WRITE_VREG(AV_SCRATCH_0, (hw->max_reference_size<<24) |
+ (hw->buffer_spec_num<<16) |
+ (hw->buffer_spec_num<<8));
+
+ return ret;
+}
+
+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;
+
+ if ((kfifo_len(&hw->newframe_q) <= 0) ||
+ ((hw->set_params_done) && (!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) == 0))) {
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "%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;
+
+ bufmgr_h264_remove_unused_frame(p_H264_Dpb);
+ }
+
+ return buffer_available;
+}
+
+static irqreturn_t vh264_isr(struct vdec_s *vdec)
+{
+ unsigned int dec_dpb_status;
+ struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)(vdec->private);
+ struct h264_dpb_stru *p_H264_Dpb = &hw->dpb;
+ int i;
+
+ WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
+
+ if (!hw) {
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_VDEC_STATUS,
+ "decoder is not running\n");
+ return IRQ_HANDLED;
+ }
+
+ p_H264_Dpb->vdec = vdec;
+ dec_dpb_status = READ_VREG(DPB_STATUS_REG);
+
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "%s DPB_STATUS_REG: %x, sb (%x %x %x) bitcnt %x\n",
+ __func__,
+ dec_dpb_status,
+ READ_VREG(VLD_MEM_VIFIFO_LEVEL),
+ READ_VREG(VLD_MEM_VIFIFO_WP),
+ READ_VREG(VLD_MEM_VIFIFO_RP),
+ READ_VREG(VIFF_BIT_CNT));
+
+ if (dec_dpb_status == H264_CONFIG_REQUEST) {
+ WRITE_VREG(DPB_STATUS_REG, H264_ACTION_CONFIG_DONE);
+#ifdef USE_CMA
+ if (hw->set_params_done) {
+ WRITE_VREG(AV_SCRATCH_0,
+ (hw->max_reference_size<<24) |
+ (hw->buffer_spec_num<<16) |
+ (hw->buffer_spec_num<<8));
+ } else {
+ hw->dec_result = DEC_RESULT_CONFIG_PARAM;
+ schedule_work(&hw->work);
+ }
+#else
+ if (vh264_set_params(hw) < 0) {
+ hw->fatal_error_flag = DECODER_FATAL_ERROR_UNKNOW;
+ if (!hw->fatal_error_reset)
+ schedule_work(&hw->error_wd_work);
+ }
+#endif
+ } else if (dec_dpb_status == H264_SLICE_HEAD_DONE) {
+ int slice_header_process_status = 0;
+ unsigned short *p = (unsigned short *)hw->lmem_addr;
+
+ dma_sync_single_for_cpu(
+ amports_get_dma_device(),
+ hw->lmem_addr_remap,
+ PAGE_SIZE,
+ DMA_FROM_DEVICE);
+#if 0
+ if (p_H264_Dpb->mVideo.dec_picture == NULL) {
+ if (!is_buffer_available(vdec)) {
+ hw->buffer_empty_flag = 1;
+ dpb_print(hw->dpb.decoder_index,
+ 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
+ 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];
+ }
+ }
+#endif
+ dpb_print(hw->dpb.decoder_index, 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));
+
+ slice_header_process_status =
+ h264_slice_header_process(p_H264_Dpb);
+
+ if (p_H264_Dpb->mVideo.dec_picture) {
+ if (slice_header_process_status == 1) {
+ dpb_print(hw->dpb.decoder_index,
+ PRINT_FLAG_UCODE_EVT,
+ "==================> frame count %d\n",
+ hw->decode_pic_count+1);
+ }
+ config_decode_buf(hw, p_H264_Dpb->mVideo.dec_picture);
+ }
+ 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_ucode_watchdog_reg_val = 0;
+ hw->decode_timeout_count = 2;
+ } else if (dec_dpb_status == H264_PIC_DATA_DONE) {
+ if (p_H264_Dpb->mVideo.dec_picture) {
+ if (hw->chunk) {
+ p_H264_Dpb->mVideo.dec_picture->pts =
+ hw->chunk->pts;
+ p_H264_Dpb->mVideo.dec_picture->pts64 =
+ hw->chunk->pts64;
+ } else {
+ struct StorablePicture *pic =
+ p_H264_Dpb->mVideo.dec_picture;
+ u32 offset = pic->offset_delimiter_lo |
+ (pic->offset_delimiter_hi << 16);
+ if (pts_lookup_offset_us64(PTS_TYPE_VIDEO,
+ offset, &pic->pts, 0, &pic->pts64)) {
+ pic->pts = 0;
+ pic->pts64 = 0;
+ }
+ }
+ store_picture_in_dpb(p_H264_Dpb,
+ p_H264_Dpb->mVideo.dec_picture);
+
+ bufmgr_post(p_H264_Dpb);
+
+ p_H264_Dpb->mVideo.dec_picture = NULL;
+ /* dump_dpb(&p_H264_Dpb->mDPB); */
+ }
+
+ if ((h264_debug_flag&ONLY_RESET_AT_START) == 0)
+ amvdec_stop();
+ hw->decode_pic_count++,
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_VDEC_STATUS,
+ "%s H264_PIC_DATA_DONE decode slice count %d\n",
+ __func__,
+ hw->decode_pic_count);
+ /* WRITE_VREG(DPB_STATUS_REG, H264_ACTION_SEARCH_HEAD); */
+ hw->dec_result = DEC_RESULT_DONE;
+ reset_process_time(hw);
+ 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:
+ if (p_H264_Dpb->mVideo.dec_picture) {
+ remove_picture(p_H264_Dpb,
+ p_H264_Dpb->mVideo.dec_picture);
+ p_H264_Dpb->mVideo.dec_picture = NULL;
+ }
+
+ if (input_frame_based(vdec) ||
+ (READ_VREG(VLD_MEM_VIFIFO_LEVEL) > 0x200)) {
+ if (h264_debug_flag &
+ DISABLE_ERROR_HANDLE) {
+ dpb_print(hw->dpb.decoder_index,
+ PRINT_FLAG_ERROR,
+ "%s decoding error, level 0x%x\n",
+ __func__,
+ READ_VREG(VLD_MEM_VIFIFO_LEVEL));
+ goto send_again;
+ }
+ if ((h264_debug_flag & ONLY_RESET_AT_START) == 0)
+ amvdec_stop();
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_UCODE_EVT,
+ "%s %s\n", __func__,
+ (dec_dpb_status == H264_SEARCH_BUFEMPTY) ?
+ "H264_SEARCH_BUFEMPTY" :
+ (dec_dpb_status == H264_DECODE_BUFEMPTY) ?
+ "H264_DECODE_BUFEMPTY" : "H264_DECODE_TIMEOUT");
+ 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++;
+ else if (dec_dpb_status == H264_DECODE_BUFEMPTY)
+ hw->decode_dataempty_num++;
+
+
+ reset_process_time(hw);
+ schedule_work(&hw->work);
+ } else {
+ /* WRITE_VREG(DPB_STATUS_REG, H264_ACTION_INIT); */
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_VDEC_STATUS,
+ "%s DEC_RESULT_AGAIN\n", __func__);
+send_again:
+ hw->dec_result = DEC_RESULT_AGAIN;
+ schedule_work(&hw->work);
+ }
+ } else if (dec_dpb_status == H264_DATA_REQUEST) {
+ if (input_frame_based(vdec)) {
+ dpb_print(hw->dpb.decoder_index,
+ PRINT_FLAG_VDEC_STATUS,
+ "%s H264_DATA_REQUEST\n", __func__);
+ hw->dec_result = DEC_RESULT_GET_DATA;
+ schedule_work(&hw->work);
+ } else
+ goto empty_proc;
+ }
+
+ /* ucode debug */
+ if (READ_VREG(DEBUG_REG1) & 0x10000) {
+ int i;
+ unsigned short *p = (unsigned short *)hw->lmem_addr;
+
+ dma_sync_single_for_cpu(
+ amports_get_dma_device(),
+ hw->lmem_addr_remap,
+ PAGE_SIZE,
+ DMA_FROM_DEVICE);
+
+ pr_info("LMEM<tag %x>:\n", READ_VREG(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 ", p[i+3-ii]);
+ if (((i+ii) & 0xf) == 0)
+ pr_info("\n");
+ }
+ WRITE_VREG(DEBUG_REG1, 0);
+ } else if (READ_VREG(DEBUG_REG1) != 0) {
+ pr_info("dbg%x: %x\n", READ_VREG(DEBUG_REG1),
+ READ_VREG(DEBUG_REG2));
+ WRITE_VREG(DEBUG_REG1, 0);
+ }
+ /**/
+
+ return IRQ_HANDLED;
+}
+
+static void timeout_process(struct vdec_h264_hw_s *hw)
+{
+ hw->timeout_num++;
+ if ((h264_debug_flag & ONLY_RESET_AT_START) == 0)
+ amvdec_stop();
+ dpb_print(hw->dpb.decoder_index,
+ PRINT_FLAG_ERROR, "%s decoder timeout\n", __func__);
+ hw->dec_result = DEC_RESULT_DONE;
+ reset_process_time(hw);
+ schedule_work(&hw->work);
+}
+
+static void check_timer_func(unsigned long arg)
+{
+ struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)arg;
+
+ if ((h264_debug_cmd & 0x100) != 0 &&
+ hw_to_vdec(hw)->id == (h264_debug_cmd & 0xff)) {
+ hw->dec_result = DEC_RESULT_DONE;
+ schedule_work(&hw->work);
+ pr_info("vdec %d is forced to be disconnected\n",
+ h264_debug_cmd & 0xff);
+ h264_debug_cmd = 0;
+ return;
+ }
+
+ if (hw_to_vdec(hw)->next_status == VDEC_STATUS_DISCONNECTED) {
+ hw->dec_result = DEC_RESULT_DONE;
+ schedule_work(&hw->work);
+ pr_info("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 ((input_frame_based(hw_to_vdec(hw)) ||
+ (READ_VREG(VLD_MEM_VIFIFO_LEVEL) > 0x200)) &&
+ ((h264_debug_flag & DISABLE_ERROR_HANDLE) == 0) &&
+ (decode_timeout_val > 0) &&
+ (hw->start_process_time > 0) &&
+ ((1000 * (jiffies - hw->start_process_time) / HZ)
+ > decode_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)) {
+ if (hw->last_mby_mbx == mby_mbx) {
+ if (hw->decode_timeout_count > 0)
+ hw->decode_timeout_count--;
+ if (hw->decode_timeout_count == 0)
+ timeout_process(hw);
+ }
+ } else if (is_in_parsing_state(dpb_status)) {
+ if (hw->last_ucode_watchdog_reg_val ==
+ READ_VREG(UCODE_WATCHDOG_REG)) {
+ if (hw->decode_timeout_count > 0)
+ hw->decode_timeout_count--;
+ if (hw->decode_timeout_count == 0)
+ timeout_process(hw);
+ }
+ }
+ hw->last_ucode_watchdog_reg_val =
+ READ_VREG(UCODE_WATCHDOG_REG);
+ hw->last_mby_mbx = mby_mbx;
+ }
+
+ hw->check_timer.expires = jiffies + CHECK_INTERVAL;
+
+ add_timer(&hw->check_timer);
+}
+
+static int dec_status(struct vdec_s *vdec, struct vdec_status *vstatus)
+{
+ struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private;
+ vstatus->width = hw->frame_width;
+ vstatus->height = hw->frame_height;
+ if (hw->frame_dur != 0)
+ vstatus->fps = 96000 / hw->frame_dur;
+ else
+ vstatus->fps = -1;
+ vstatus->error_count = READ_VREG(AV_SCRATCH_D);
+ vstatus->status = hw->stat;
+ /* if (fatal_error_reset)
+ vstatus->status |= hw->fatal_error_flag; */
+ return 0;
+}
+
+static int vh264_hw_ctx_restore(struct vdec_h264_hw_s *hw)
+{
+ int i;
+
+ /* if (hw->init_flag == 0) { */
+ if (h264_debug_flag & 0x40000000) {
+ /* if (1) */
+ dpb_print(hw->dpb.decoder_index, 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_MPEG_REG(RESET0_REGISTER,
+ RESET_IQIDCT | RESET_MC | RESET_VLD_PART);
+ READ_MPEG_REG(RESET0_REGISTER);
+ WRITE_MPEG_REG(RESET0_REGISTER,
+ RESET_IQIDCT | RESET_MC | RESET_VLD_PART);
+
+ WRITE_MPEG_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
+
+#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
+ if (hw->decode_pic_count > 0) {
+ WRITE_VREG(AV_SCRATCH_7, (hw->max_reference_size << 24) |
+ (hw->buffer_spec_num << 16) |
+ (hw->buffer_spec_num << 8));
+ for (i = 0; i < hw->buffer_spec_num; i++) {
+ canvas_config(hw->buffer_spec[i].y_canvas_index,
+ hw->buffer_spec[i].y_addr,
+ hw->mb_width << 4,
+ hw->mb_height << 4,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+
+ canvas_config(hw->buffer_spec[i].u_canvas_index,
+ hw->buffer_spec[i].u_addr,
+ hw->mb_width << 4,
+ hw->mb_height << 3,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+
+ WRITE_VREG(ANC0_CANVAS_ADDR + i,
+ spec2canvas(&hw->buffer_spec[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);
+ 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, (READ_VREG(AV_SCRATCH_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_addr_remap);
+#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);
+ return 0;
+}
+
+static unsigned char amvdec_enable_flag;
+static void vh264_local_init(struct vdec_h264_hw_s *hw)
+{
+ int i;
+ hw->decode_timeout_count = 0;
+
+ hw->vh264_ratio = hw->vh264_amstream_dec_info.ratio;
+ /* vh264_ratio = 0x100; */
+
+ hw->vh264_rotation = (((unsigned long)
+ hw->vh264_amstream_dec_info.param) >> 16) & 0xffff;
+
+ hw->frame_prog = 0;
+ hw->frame_width = hw->vh264_amstream_dec_info.width;
+ hw->frame_height = hw->vh264_amstream_dec_info.height;
+ hw->frame_dur = hw->vh264_amstream_dec_info.rate;
+ hw->pts_outside = ((unsigned long)
+ hw->vh264_amstream_dec_info.param) & 0x01;
+ hw->sync_outside = ((unsigned long)
+ hw->vh264_amstream_dec_info.param & 0x02) >> 1;
+ hw->use_idr_framerate = ((unsigned long)
+ hw->vh264_amstream_dec_info.param & 0x04) >> 2;
+ hw->max_refer_buf = !(((unsigned long)
+ hw->vh264_amstream_dec_info.param & 0x10) >> 4);
+ if (hw->frame_dur < 96000/960) {
+ /*more than 960fps,it should not be a correct value,
+ give default 30fps*/
+ hw->frame_dur = 96000/30;
+ }
+
+ pr_info
+ ("H264 sysinfo: %dx%d duration=%d, pts_outside=%d, ",
+ hw->frame_width, hw->frame_height, hw->frame_dur, hw->pts_outside);
+ pr_info("sync_outside=%d, use_idr_framerate=%d\n",
+ hw->sync_outside, hw->use_idr_framerate);
+
+ if ((unsigned long) hw->vh264_amstream_dec_info.param & 0x08)
+ hw->ucode_type = UCODE_IP_ONLY_PARAM;
+ else
+ hw->ucode_type = 0;
+
+ if ((unsigned long) hw->vh264_amstream_dec_info.param & 0x20)
+ error_recovery_mode_in = 1;
+ else
+ error_recovery_mode_in = 3;
+
+ 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; /* VF_BUF_NUM; */
+ hw->vfpool[i].bufWidth = 1920;
+ kfifo_put(&hw->newframe_q, vf);
+ }
+
+ hw->duration_from_pts_done = 0;
+
+ hw->p_last_vf = NULL;
+ hw->fatal_error_flag = 0;
+ hw->vh264_stream_switching_state = SWITCHING_STATE_OFF;
+
+ INIT_WORK(&hw->work, vh264_work);
+
+ return;
+}
+
+static s32 vh264_init(struct vdec_h264_hw_s *hw)
+{
+ /* int trickmode_fffb = 0; */
+ int firmwareloaded = 0;
+
+ hw->init_flag = 0;
+ hw->set_params_done = 0;
+ hw->start_process_time = 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->duration_on_correcting = 0;
+ hw->fixed_frame_rate_check_count = 0;
+ hw->saved_resolution = 0;
+
+ vh264_local_init(hw);
+
+ if (!amvdec_enable_flag) {
+ amvdec_enable_flag = true;
+ amvdec_enable();
+ }
+
+ /* -- 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();
+
+ 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);
+ if (!firmwareloaded) {
+ int ret = 0, size = -1;
+ char *buf = vmalloc(0x1000 * 16);
+ if (IS_ERR_OR_NULL(buf))
+ return -ENOMEM;
+
+ pr_info("start load orignal firmware ...\n");
+
+ size = get_firmware_data(VIDEO_DEC_H264_MULTI, buf);
+ if (size < 0) {
+ pr_err("get firmware fail.\n");
+ vfree(buf);
+ return -1;
+ }
+
+ /*ret = amvdec_loadmc_ex(VFORMAT_H264, NULL, buf);*/
+
+ /*header*/
+ memcpy((u8 *) hw->mc_cpu_addr + MC_OFFSET_HEADER,
+ buf + 0x4000, MC_SWAP_SIZE);
+ /*data*/
+ memcpy((u8 *) hw->mc_cpu_addr + MC_OFFSET_DATA,
+ buf + 0x2000, MC_SWAP_SIZE);
+ /*mmco*/
+ memcpy((u8 *) hw->mc_cpu_addr + MC_OFFSET_MMCO,
+ buf + 0x6000, MC_SWAP_SIZE);
+ /*list*/
+ memcpy((u8 *) hw->mc_cpu_addr + MC_OFFSET_LIST,
+ buf + 0x3000, MC_SWAP_SIZE);
+ /*slice*/
+ memcpy((u8 *) hw->mc_cpu_addr + MC_OFFSET_SLICE,
+ buf + 0x5000, MC_SWAP_SIZE);
+ /*main*/
+ memcpy((u8 *) hw->mc_cpu_addr + MC_OFFSET_MAIN,
+ buf, 0x2000);
+ /*data*/
+ memcpy((u8 *) hw->mc_cpu_addr + MC_OFFSET_MAIN + 0x2000,
+ buf + 0x2000, 0x1000);
+ /*slice*/
+ memcpy((u8 *) hw->mc_cpu_addr + MC_OFFSET_MAIN + 0x3000,
+ buf + 0x5000, 0x1000);
+
+ vfree(buf);
+
+ if (ret < 0) {
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_ERROR,
+ "264 load orignal firmware error.\n");
+ amvdec_disable();
+ if (hw->mc_cpu_addr) {
+ dma_free_coherent(amports_get_dma_device(),
+ MC_TOTAL_SIZE, hw->mc_cpu_addr,
+ hw->mc_dma_handle);
+ hw->mc_cpu_addr = NULL;
+ }
+ return -EBUSY;
+ }
+ }
+
+#if 1 /* #ifdef BUFFER_MGR_IN_C */
+ dpb_init_global(&hw->dpb,
+ hw_to_vdec(hw)->id, 0, 0);
+ hw->lmem_addr = __get_free_page(GFP_KERNEL);
+ if (!hw->lmem_addr) {
+ pr_info("%s: failed to alloc lmem_addr\n", __func__);
+ return -ENOMEM;
+ } else {
+ hw->lmem_addr_remap = dma_map_single(
+ amports_get_dma_device(),
+ (void *)hw->lmem_addr,
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(amports_get_dma_device(),
+ hw->lmem_addr_remap)) {
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_ERROR,
+ "%s: failed to map lmem_addr\n", __func__);
+ free_page(hw->lmem_addr);
+ hw->lmem_addr = 0;
+ hw->lmem_addr_remap = 0;
+ return -ENOMEM;
+ }
+
+ pr_info("%s, vaddr=%lx phy_addr=%p\n",
+ __func__, hw->lmem_addr, (void *)hw->lmem_addr_remap);
+ }
+ /* 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, int mode)
+{
+ int i;
+
+ 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;
+ }
+ }
+#ifdef USE_CMA
+ if (hw->cma_alloc_addr) {
+ pr_info("codec_mm release buffer 0x%lx\n", hw->cma_alloc_addr);
+ codec_mm_free_for_dma(MEM_NAME, hw->cma_alloc_addr);
+ hw->cma_alloc_count = 0;
+ }
+
+ if (hw->collocate_cma_alloc_addr) {
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_ERROR,
+ "codec_mm release collocate buffer 0x%lx\n",
+ hw->collocate_cma_alloc_addr);
+ codec_mm_free_for_dma(MEM_NAME, hw->collocate_cma_alloc_addr);
+ hw->collocate_cma_alloc_count = 0;
+ }
+
+ for (i = 0; i < hw->buffer_spec_num; i++) {
+ if (hw->buffer_spec[i].cma_alloc_addr) {
+ pr_info("codec_mm release buffer_spec[%d], 0x%lx\n", i,
+ hw->buffer_spec[i].cma_alloc_addr);
+ codec_mm_free_for_dma(MEM_NAME,
+ hw->buffer_spec[i].cma_alloc_addr);
+ hw->buffer_spec[i].cma_alloc_count = 0;
+ }
+ }
+
+#endif
+
+ if (hw->lmem_addr_remap) {
+ dma_unmap_single(amports_get_dma_device(),
+ hw->lmem_addr_remap,
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ hw->lmem_addr_remap = 0;
+ }
+ if (hw->lmem_addr) {
+ free_page(hw->lmem_addr);
+ hw->lmem_addr = 0;
+ }
+ cancel_work_sync(&hw->work);
+
+ /* amvdec_disable(); */
+
+ return 0;
+}
+
+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);
+
+ /* finished decoding one frame or error,
+ * notify vdec core to switch context
+ */
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_VDEC_DETAIL,
+ "%s %x %x %x\n", __func__,
+ READ_VREG(0xc47), READ_VREG(0xc45), READ_VREG(0xc46));
+
+#ifdef USE_CMA
+ if (hw->dec_result == DEC_RESULT_CONFIG_PARAM) {
+ if (vh264_set_params(hw) < 0) {
+ hw->fatal_error_flag = DECODER_FATAL_ERROR_UNKNOWN;
+ if (!hw->fatal_error_reset)
+ schedule_work(&hw->error_wd_work);
+ }
+ return;
+ } else
+#endif
+ if ((hw->dec_result == DEC_RESULT_GET_DATA) ||
+ (hw->dec_result == DEC_RESULT_GET_DATA_RETRY)) {
+ if (hw->dec_result == DEC_RESULT_GET_DATA) {
+ dpb_print(hw->dpb.decoder_index, 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));
+ vdec_vframe_dirty(vdec, hw->chunk);
+ vdec_clean_input(vdec);
+ }
+
+ if (is_buffer_available(vdec)) {
+ int r;
+ r = vdec_prepare_input(vdec, &hw->chunk);
+ if (r < 0) {
+ hw->dec_result = DEC_RESULT_GET_DATA_RETRY;
+
+ dpb_print(hw->dpb.decoder_index,
+ PRINT_FLAG_VDEC_DETAIL,
+ "ammvdec_vh264: Insufficient data\n");
+
+ schedule_work(&hw->work);
+ return;
+ }
+ hw->dec_result = DEC_RESULT_NONE;
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_VDEC_STATUS,
+ "%s: chunk size 0x%x\n",
+ __func__, hw->chunk->size);
+ WRITE_VREG(POWER_CTL_VLD,
+ READ_VREG(POWER_CTL_VLD) |
+ (0 << 10) | (1 << 9) | (1 << 6));
+ WRITE_VREG(H264_DECODE_INFO, (1<<13));
+ WRITE_VREG(H264_DECODE_SIZE, hw->chunk->size);
+ WRITE_VREG(VIFF_BIT_CNT, (hw->chunk->size * 8));
+ vdec_enable_input(vdec);
+
+ WRITE_VREG(DPB_STATUS_REG, H264_ACTION_SEARCH_HEAD);
+ } else{
+ hw->dec_result = DEC_RESULT_GET_DATA_RETRY;
+
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_VDEC_DETAIL,
+ "ammvdec_vh264: Insufficient data\n");
+
+ schedule_work(&hw->work);
+ }
+ return;
+ } else if (hw->dec_result == DEC_RESULT_DONE) {
+ /* if (!hw->ctx_valid)
+ hw->ctx_valid = 1; */
+ dpb_print(hw->dpb.decoder_index, 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));
+ vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk);
+ } else {
+ dpb_print(hw->dpb.decoder_index, 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));
+ }
+
+ del_timer_sync(&hw->check_timer);
+ hw->stat &= ~STAT_TIMER_ARM;
+
+ /* mark itself has all HW resource released and input released */
+ vdec_set_status(hw_to_vdec(hw), VDEC_STATUS_CONNECTED);
+
+ if (hw->vdec_cb)
+ hw->vdec_cb(hw_to_vdec(hw), hw->vdec_cb_arg);
+}
+
+static bool run_ready(struct vdec_s *vdec)
+{
+ if (vdec->master)
+ return false;
+
+ if ((!input_frame_based(vdec)) && (start_decode_buf_level > 0)) {
+ u32 rp, wp;
+ u32 level;
+
+ rp = READ_MPEG_REG(PARSER_VIDEO_RP);
+ wp = READ_MPEG_REG(PARSER_VIDEO_WP);
+
+ if (wp < rp)
+ level = vdec->input.size + wp - rp;
+ else
+ level = wp - rp;
+
+ if (level < start_decode_buf_level) {
+ struct vdec_h264_hw_s *hw =
+ (struct vdec_h264_hw_s *)vdec->private;
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_VDEC_DETAIL,
+ "%s vififo level low %x(<%x) (lev%x wp%x rp%x)\n",
+ __func__, level,
+ start_decode_buf_level,
+ READ_VREG(VLD_MEM_VIFIFO_LEVEL),
+ READ_VREG(VLD_MEM_VIFIFO_WP),
+ READ_VREG(VLD_MEM_VIFIFO_RP));
+ return 0;
+ }
+ }
+
+ if (h264_debug_flag & 0x20000000) {
+ /* pr_info("%s, a\n", __func__); */
+ return 1;
+ } else {
+ return is_buffer_available(vdec);
+ }
+}
+
+static void run(struct vdec_s *vdec,
+ void (*callback)(struct vdec_s *, void *), void *arg)
+{
+ struct vdec_h264_hw_s *hw =
+ (struct vdec_h264_hw_s *)vdec->private;
+ int size;
+
+ hw->vdec_cb_arg = arg;
+ hw->vdec_cb = callback;
+
+ /* hw->chunk = vdec_prepare_input(vdec); */
+ size = vdec_prepare_input(vdec, &hw->chunk);
+ if ((size < 0) ||
+ (input_frame_based(vdec) && hw->chunk == NULL)) {
+ hw->dec_result = DEC_RESULT_AGAIN;
+
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_VDEC_DETAIL,
+ "ammvdec_vh264: Insufficient data\n");
+
+ schedule_work(&hw->work);
+ return;
+ }
+
+ hw->dec_result = DEC_RESULT_NONE;
+#if 0
+ if ((!input_frame_based(vdec)) && (start_decode_buf_level > 0)) {
+ if (READ_VREG(VLD_MEM_VIFIFO_LEVEL) <
+ start_decode_buf_level) {
+ dpb_print(hw->dpb.decoder_index,
+ PRINT_FLAG_VDEC_DETAIL,
+ "%s: VIFIFO_LEVEL %x is low (<%x)\n",
+ __func__,
+ READ_VREG(VLD_MEM_VIFIFO_LEVEL),
+ start_decode_buf_level);
+
+ hw->dec_result = DEC_RESULT_AGAIN;
+ schedule_work(&hw->work);
+ return;
+ }
+ }
+#endif
+
+ if (input_frame_based(vdec)) {
+ u8 *data = ((u8 *)hw->chunk->block->start_virt) +
+ hw->chunk->offset;
+
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_VDEC_STATUS,
+ "%s: size 0x%x %02x %02x %02x %02x %02x %02x .. %02x %02x %02x %02x\n",
+ __func__, 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]);
+ } else
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_VDEC_STATUS,
+ "%s: %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), size);
+
+ hw->start_process_time = jiffies;
+
+ if (((h264_debug_flag & ONLY_RESET_AT_START) == 0) ||
+ (hw->init_flag == 0)) {
+ if (amvdec_vdec_loadmc_ex(vdec, "vmh264_mc") < 0) {
+ amvdec_enable_flag = false;
+ amvdec_disable();
+ pr_info("%s: Error amvdec_vdec_loadmc fail\n",
+ __func__);
+ return;
+ }
+
+ if (vh264_hw_ctx_restore(hw) < 0) {
+ schedule_work(&hw->work);
+ return;
+ }
+ if (input_frame_based(vdec)) {
+ WRITE_VREG(H264_DECODE_INFO, (1<<13));
+ WRITE_VREG(H264_DECODE_SIZE, hw->chunk->size);
+ WRITE_VREG(VIFF_BIT_CNT, (hw->chunk->size * 8));
+ } 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);
+ }
+
+ vdec_enable_input(vdec);
+
+ add_timer(&hw->check_timer);
+
+ amvdec_start();
+
+ /* if (hw->init_flag) { */
+ WRITE_VREG(DPB_STATUS_REG, H264_ACTION_SEARCH_HEAD);
+ /* } */
+
+ hw->init_flag = 1;
+ } else {
+ WRITE_VREG(H264_DECODE_INFO, (1 << 13));
+ vdec_enable_input(vdec);
+
+ WRITE_VREG(DPB_STATUS_REG, H264_ACTION_SEARCH_HEAD);
+ }
+}
+
+static void reset(struct vdec_s *vdec)
+{
+ pr_info("ammvdec_h264: reset.\n");
+
+#if 0
+ struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private;
+
+ hw->init_flag = 0;
+ hw->set_params_done = 0;
+
+ vh264_local_init(hw);
+
+ dpb_init_global(&hw->dpb);
+#endif
+}
+
+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;
+
+ if (pdata == NULL) {
+ pr_info("\nammvdec_h264 memory resource undefined.\n");
+ return -EFAULT;
+ }
+
+ hw = (struct vdec_h264_hw_s *)devm_kzalloc(&pdev->dev,
+ sizeof(struct vdec_h264_hw_s), GFP_KERNEL);
+ if (hw == NULL) {
+ pr_info("\nammvdec_h264 device data allocation failed\n");
+ return -ENOMEM;
+ }
+
+ pdata->private = hw;
+ pdata->dec_status = dec_status;
+ /* pdata->set_trickmode = set_trickmode; */
+ pdata->run_ready = run_ready;
+ pdata->run = run;
+ pdata->reset = reset;
+ pdata->irq_handler = vh264_isr;
+
+ pdata->id = pdev->id;
+
+ if (pdata->use_vfm_path)
+ snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE,
+ VFM_DEC_PROVIDER_NAME);
+ else if (vdec_dual(pdata)) {
+ snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE,
+ (pdata->master) ? VFM_DEC_DVEL_PROVIDER_NAME :
+ VFM_DEC_DVBL_PROVIDER_NAME);
+ } 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);
+
+ hw->platform_dev = pdev;
+#ifndef USE_CMA
+ hw->buf_start = pdata->mem_start;
+ hw->buf_size = pdata->mem_end - pdata->mem_start + 1;
+ /* hw->ucode_map_start = pdata->mem_start; */
+ if (hw->buf_size < DEFAULT_MEM_SIZE) {
+ pr_info("\nammvdec_h264 memory size not enough.\n");
+ return -ENOMEM;
+ }
+#endif
+
+#ifdef USE_CMA
+ hw->cma_dev = pdata->cma_dev;
+ if (hw->cma_alloc_count == 0) {
+ hw->cma_alloc_count = PAGE_ALIGN(V_BUF_ADDR_OFFSET) / PAGE_SIZE;
+ hw->cma_alloc_addr = codec_mm_alloc_for_dma(MEM_NAME,
+ hw->cma_alloc_count,
+ 4, CODEC_MM_FLAGS_FOR_VDECODER);
+ }
+ if (!hw->cma_alloc_addr) {
+ dpb_print(hw->dpb.decoder_index, PRINT_FLAG_ERROR,
+ "codec_mm alloc failed, request buf size 0x%lx\n",
+ hw->cma_alloc_count * PAGE_SIZE);
+ hw->cma_alloc_count = 0;
+ return -ENOMEM;
+ }
+ hw->buf_offset = hw->cma_alloc_addr - DEF_BUF_START_ADDR;
+#else
+ hw->buf_offset = pdata->mem_start - DEF_BUF_START_ADDR;
+ hw->buf_start = V_BUF_ADDR_OFFSET + pdata->mem_start;
+#endif
+
+ if (pdata->sys_info)
+ hw->vh264_amstream_dec_info = *pdata->sys_info;
+ 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__);
+ 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); */
+ }
+#ifdef USE_CMA
+ pr_info("ammvdec_h264 mem-addr=%lx,buff_offset=%x,buf_start=%lx\n",
+ pdata->mem_start, hw->buf_offset, hw->cma_alloc_addr);
+#else
+ pr_info("ammvdec_h264 mem-addr=%lx,buff_offset=%x,buf_start=%lx\n",
+ pdata->mem_start, hw->buf_offset, hw->buf_start);
+#endif
+
+ vdec_source_changed(VFORMAT_H264, 3840, 2160, 60);
+
+ if (vh264_init(hw) < 0) {
+ pr_info("\nammvdec_h264 init failed.\n");
+ return -ENODEV;
+ }
+ atomic_set(&hw->vh264_active, 1);
+
+ return 0;
+}
+
+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);
+
+ 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, MODE_FULL);
+
+ /* vdec_source_changed(VFORMAT_H264, 0, 0, 0); */
+
+ atomic_set(&hw->vh264_active, 0);
+
+ vdec_set_status(hw_to_vdec(hw), VDEC_STATUS_DISCONNECTED);
+
+ return 0;
+}
+
+/****************************************/
+
+static struct platform_driver ammvdec_h264_driver = {
+ .probe = ammvdec_h264_probe,
+ .remove = ammvdec_h264_remove,
+#ifdef CONFIG_PM
+ .suspend = amvdec_suspend,
+ .resume = amvdec_resume,
+#endif
+ .driver = {
+ .name = DRIVER_NAME,
+ }
+};
+
+static struct codec_profile_t ammvdec_h264_profile = {
+ .name = "mh264",
+ .profile = ""
+};
+
+static 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;
+ }
+ vcodec_profile_register(&ammvdec_h264_profile);
+ 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, uint, 0664);
+MODULE_PARM_DESC(start_decode_buf_level,
+ "\n ammvdec_h264 start_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(reorder_dpb_size_margin, uint, 0664);
+MODULE_PARM_DESC(reorder_dpb_size_margin, "\n ammvdec_h264 reorder_dpb_size_margin\n");
+
+module_param(reference_buf_margin, uint, 0664);
+MODULE_PARM_DESC(reference_buf_margin, "\n ammvdec_h264 reference_buf_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(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(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(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(step, uint, &max_decode_instance_num, 0664);
+
+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/vh265.c b/drivers/frame_provider/decoder/h265/vh265.c
new file mode 100644
index 0000000..7e09b7b
--- a/dev/null
+++ b/drivers/frame_provider/decoder/h265/vh265.c
@@ -0,0 +1,8969 @@
+/*
+ * 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.
+ *
+*/
+
+#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 "../../../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"
+
+/*#define HEVC_PIC_STRUCT_SUPPORT*/
+#define MULTI_INSTANCE_SUPPORT
+
+
+
+#define MMU_COMPRESS_HEADER_SIZE 0x48000
+#define MAX_FRAME_4K_NUM 0x1200
+#define FRAME_MMU_MAP_SIZE (MAX_FRAME_4K_NUM * 4)
+#define H265_MMU_MAP_BUFFER HEVC_ASSIST_SCRATCH_7
+#define HEVC_CM_HEADER_START_ADDR 0x3628
+#define HEVC_SAO_MMU_VH1_ADDR 0x363b
+#define HEVC_SAO_MMU_VH0_ADDR 0x363a
+#define HEVC_SAO_MMU_STATUS 0x3639
+
+
+
+#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>
+
+#define SUPPORT_10BIT
+/* #define ERROR_HANDLE_DEBUG */
+#if 0/*MESON_CPU_TYPE == MESON_CPU_TYPE_MESON8B*/
+#undef SUPPORT_4K2K
+#else
+#define SUPPORT_4K2K
+#endif
+
+#ifndef STAT_KTHREAD
+#define STAT_KTHREAD 0x40
+#endif
+
+#ifdef MULTI_INSTANCE_SUPPORT
+#define MAX_DECODE_INSTANCE_NUM 12
+#define MULTI_DRIVER_NAME "ammvdec_h265"
+#endif
+#define DRIVER_NAME "amvdec_h265"
+#define MODULE_NAME "amvdec_h265"
+
+#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 HEVC_SIZE (4096*2304)
+
+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 bool run_ready(struct vdec_s *vdec);
+static void reset_process_time(struct hevc_state_s *hevc);
+static void start_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 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 unsigned int start_decode_buf_level = 0x8000;
+
+static unsigned int decode_timeout_val;
+#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 */
+/* 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
+ 0x10, double write only
+*/
+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_UCODE 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_PRINT_SEI 0x2000
+#define H265_DEBUG_PIC_STRUCT 0x4000
+#define H265_DEBUG_DIS_LOC_ERROR_PROC 0x10000
+#define H265_DEBUG_DIS_SYS_ERROR_PROC 0x20000
+#define H265_DEBUG_DUMP_PIC_LIST 0x40000
+#define H265_DEBUG_TRIG_SLICE_SEGMENT_PROC 0x80000
+#define H265_DEBUG_HW_RESET 0x100000
+#define H265_DEBUG_ERROR_TRIG 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 IGNORE_PARAM_FROM_CONFIG 0x08000000
+#define PRINT_FRAMEBASE_DATA 0x10000000
+#define PRINT_FLAG_VDEC_STATUS 0x20000000
+#define PRINT_FLAG_VDEC_DETAIL 0x40000000
+#endif
+#define MAX_BUF_NUM 24
+#define MAX_REF_PIC_NUM 24
+#define MAX_REF_ACTIVE 16
+
+#define BMMU_MAX_BUFFERS (MAX_BUF_NUM + 1)
+#define BMMU_WORKSPACE_ID (MAX_BUF_NUM)
+
+const u32 h265_version = 201602101;
+static u32 debug_mask = 0xffffffff;
+static u32 debug;
+static u32 radr;
+static u32 rval;
+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_stop_pos;
+static u32 decode_stop_pos_pre;
+static u32 decode_pic_begin;
+static uint slice_parse_begin;
+static u32 step;
+#ifdef MIX_STREAM_SUPPORT
+#ifdef SUPPORT_4K2K
+static u32 buf_alloc_width = 4096;
+static u32 buf_alloc_height = 2304;
+#else
+static u32 buf_alloc_width = 1920;
+static u32 buf_alloc_height = 1088;
+#endif
+static u32 dynamic_buf_num_margin;
+#else
+static u32 buf_alloc_width;
+static u32 buf_alloc_height;
+static u32 dynamic_buf_num_margin = 8;
+#endif
+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;
+
+/*
+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;
+static u32 suffix_aux_buf_size;
+
+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
+
+*/
+
+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;
+ /*
+ 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;
+#ifdef CONFIG_AM_VDEC_DV
+static u32 parser_dolby_vision_enable;
+#endif
+/* this is only for h265 mmu enable */
+
+#ifdef CONFIG_MULTI_DEC
+static u32 mmu_enable;
+#else
+static u32 mmu_enable = 1;
+#endif
+
+#ifdef MULTI_INSTANCE_SUPPORT
+static u32 work_buf_size = 48 * 1024 * 1024;
+static unsigned int max_decode_instance_num
+ = MAX_DECODE_INSTANCE_NUM;
+static unsigned int decode_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];
+
+#ifdef CONFIG_MULTI_DEC
+static unsigned char get_idx(struct hevc_state_s *hevc);
+#endif
+
+#ifdef CONFIG_AM_VDEC_DV
+static u32 dv_toggle_prov_name;
+
+static u32 dv_debug;
+#endif
+#endif
+
+
+#ifdef CONFIG_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)
+#else
+#define get_dbg_flag(hevc) debug
+#define get_dbg_flag2(hevc) debug
+#define get_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
+
+
+DEFINE_SPINLOCK(lock);
+struct task_struct *h265_task = NULL;
+#undef DEBUG_REG
+#ifdef DEBUG_REG
+void WRITE_VREG_DBG(unsigned adr, unsigned val)
+{
+ WRITE_VREG(adr, val);
+}
+
+#undef WRITE_VREG
+#define WRITE_VREG WRITE_VREG_DBG
+#endif
+
+static DEFINE_MUTEX(vh265_mutex);
+
+
+/**************************************************
+
+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_DATA_REQUEST 0x12
+
+#define HEVC_DECODE_BUFEMPTY 0x20
+#define HEVC_DECODE_TIMEOUT 0x21
+#define HEVC_SEARCH_BUFEMPTY 0x22
+
+#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_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
+
+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
+};
+
+/**************************************************
+
+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
+ /*set before start decoder*/
+#define HEVC_DECODE_MODE HEVC_ASSIST_SCRATCH_J
+#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 0x140
+#define RPM_END 0x180
+
+#define RPS_USED_BIT 14
+/* 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[4];
+ unsigned short tile_height[4];
+ 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;
+ } 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 mmu_vbh;
+ struct buff_s cm_header;
+ struct buff_s mpred_above;
+ struct buff_s mpred_mv;
+ struct buff_s rpm;
+ struct buff_s lmem;
+};
+#define WORK_BUF_SPEC_NUM 2
+static struct BuffInfo_s amvh265_workbuff_spec[WORK_BUF_SPEC_NUM] = {
+ {
+ /* 8M bytes */
+ .max_width = 1920,
+ .max_height = 1088,
+ .ipp = {
+ /* IPP work space calculation :
+ 4096 * (Y+CbCr+Flags) = 12k, round to 16k */
+ .buf_size = 0x4000,
+ },
+ .sao_abv = {
+ .buf_size = 0x30000,
+ },
+ .sao_vb = {
+ .buf_size = 0x30000,
+ },
+ .short_term_rps = {
+ /* SHORT_TERM_RPS - Max 64 set, 16 entry every set,
+ total 64x16x2 = 2048 bytes (0x800) */
+ .buf_size = 0x800,
+ },
+ .vps = {
+ /* VPS STORE AREA - Max 16 VPS, each has 0x80 bytes,
+ total 0x0800 bytes */
+ .buf_size = 0x800,
+ },
+ .sps = {
+ /* SPS STORE AREA - Max 16 SPS, each has 0x80 bytes,
+ total 0x0800 bytes */
+ .buf_size = 0x800,
+ },
+ .pps = {
+ /* PPS STORE AREA - Max 64 PPS, each has 0x80 bytes,
+ total 0x2000 bytes */
+ .buf_size = 0x2000,
+ },
+ .sao_up = {
+ /* SAO UP STORE AREA - Max 640(10240/16) LCU,
+ each has 16 bytes total 0x2800 bytes */
+ .buf_size = 0x2800,
+ },
+ .swap_buf = {
+ /* 256cyclex64bit = 2K bytes 0x800
+ (only 144 cycles valid) */
+ .buf_size = 0x800,
+ },
+ .swap_buf2 = {
+ .buf_size = 0x800,
+ },
+ .scalelut = {
+ /* support up to 32 SCALELUT 1024x32 =
+ 32Kbytes (0x8000) */
+ .buf_size = 0x8000,
+ },
+ .dblk_para = {
+#ifdef SUPPORT_10BIT
+ .buf_size = 0x40000,
+#else
+ /* DBLK -> Max 256(4096/16) LCU, each para
+ 512bytes(total:0x20000), data 1024bytes(total:0x40000) */
+ .buf_size = 0x20000,
+#endif
+ },
+ .dblk_data = {
+ .buf_size = 0x40000,
+ },
+ .mmu_vbh = {
+ .buf_size = 0x5000, /*2*16*2304/4, 4K*/
+ },
+ .cm_header = {/* 0x44000 = ((1088*2*1024*4)/32/4)*(32/8)*/
+ .buf_size = MMU_COMPRESS_HEADER_SIZE*(16+1),
+ },
+ .mpred_above = {
+ .buf_size = 0x8000,
+ },
+ .mpred_mv = {/* 1080p, 0x40000 per buffer */
+ .buf_size = 0x40000 * MAX_REF_PIC_NUM,
+ },
+ .rpm = {
+ .buf_size = RPM_BUF_SIZE,
+ },
+ .lmem = {
+ .buf_size = 0x500 * 2,
+ }
+ },
+ {
+ .max_width = 4096,
+ .max_height = 2048,
+ .ipp = {
+ /* IPP work space calculation :
+ 4096 * (Y+CbCr+Flags) = 12k, round to 16k */
+ .buf_size = 0x4000,
+ },
+ .sao_abv = {
+ .buf_size = 0x30000,
+ },
+ .sao_vb = {
+ .buf_size = 0x30000,
+ },
+ .short_term_rps = {
+ /* SHORT_TERM_RPS - Max 64 set, 16 entry every set,
+ total 64x16x2 = 2048 bytes (0x800) */
+ .buf_size = 0x800,
+ },
+ .vps = {
+ /* VPS STORE AREA - Max 16 VPS, each has 0x80 bytes,
+ total 0x0800 bytes */
+ .buf_size = 0x800,
+ },
+ .sps = {
+ /* SPS STORE AREA - Max 16 SPS, each has 0x80 bytes,
+ total 0x0800 bytes */
+ .buf_size = 0x800,
+ },
+ .pps = {
+ /* PPS STORE AREA - Max 64 PPS, each has 0x80 bytes,
+ total 0x2000 bytes */
+ .buf_size = 0x2000,
+ },
+ .sao_up = {
+ /* SAO UP STORE AREA - Max 640(10240/16) LCU,
+ each has 16 bytes total 0x2800 bytes */
+ .buf_size = 0x2800,
+ },
+ .swap_buf = {
+ /* 256cyclex64bit = 2K bytes 0x800
+ (only 144 cycles valid) */
+ .buf_size = 0x800,
+ },
+ .swap_buf2 = {
+ .buf_size = 0x800,
+ },
+ .scalelut = {
+ /* support up to 32 SCALELUT 1024x32 = 32Kbytes
+ (0x8000) */
+ .buf_size = 0x8000,
+ },
+ .dblk_para = {
+ /* DBLK -> Max 256(4096/16) LCU, each para
+ 512bytes(total:0x20000),
+ data 1024bytes(total:0x40000) */
+ .buf_size = 0x20000,
+ },
+ .dblk_data = {
+ .buf_size = 0x40000,
+ },
+ .mmu_vbh = {
+ .buf_size = 0x5000, /*2*16*2304/4, 4K*/
+ },
+ .cm_header = {/*0x44000 = ((1088*2*1024*4)/32/4)*(32/8)*/
+ .buf_size = MMU_COMPRESS_HEADER_SIZE * (16+1),
+ },
+ .mpred_above = {
+ .buf_size = 0x8000,
+ },
+ .mpred_mv = {
+ /* .buf_size = 0x100000*16,
+ //4k2k , 0x100000 per buffer */
+ /* 4096x2304 , 0x120000 per buffer */
+ .buf_size = 0x120000 * MAX_REF_PIC_NUM,
+ },
+ .rpm = {
+ .buf_size = RPM_BUF_SIZE,
+ },
+ .lmem = {
+ .buf_size = 0x500 * 2,
+ }
+ }
+};
+
+unsigned int get_mmu_mode(void)
+{
+ return mmu_enable;
+}
+
+#ifdef SUPPORT_10BIT
+/* Losless compression body buffer size 4K per 64x32 (jt) */
+static int compute_losless_comp_body_size(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 && 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 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->mmu_vbh.buf_start =
+ buf_spec->dblk_data.buf_start + buf_spec->dblk_data.buf_size;
+ buf_spec->cm_header.buf_start =
+ buf_spec->mmu_vbh.buf_start + buf_spec->mmu_vbh.buf_size;
+ buf_spec->mpred_above.buf_start =
+ buf_spec->cm_header.buf_start + buf_spec->cm_header.buf_size;
+ buf_spec->mpred_mv.buf_start =
+ buf_spec->mpred_above.buf_start +
+ buf_spec->mpred_above.buf_size;
+ if (get_dbg_flag2(hevc) & H265_DEBUG_SEND_PARAM_WITH_REG) {
+ buf_spec->end_adr =
+ buf_spec->mpred_mv.buf_start +
+ buf_spec->mpred_mv.buf_size;
+ } else {
+ buf_spec->rpm.buf_start =
+ buf_spec->mpred_mv.buf_start +
+ buf_spec->mpred_mv.buf_size;
+ if (get_dbg_flag2(hevc) & H265_DEBUG_UCODE) {
+ 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;
+ } else {
+ buf_spec->end_adr =
+ buf_spec->rpm.buf_start +
+ buf_spec->rpm.buf_size;
+ }
+ }
+
+ if (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);
+ }
+ if (get_dbg_flag2(hevc)) {
+ 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,
+ "mpred_above.buf_start :%x\n",
+ buf_spec->mpred_above.buf_start);
+ hevc_print(hevc, 0,
+ "mpred_mv.buf_start :%x\n",
+ buf_spec->mpred_mv.buf_start);
+ 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 {
+ int index;
+ /*buffer */
+ unsigned long start_adr;
+ unsigned int size;
+
+ unsigned int free_start_adr;
+} /*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 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;
+ unsigned char used_by_display;
+ /**/ int slice_idx;
+ int m_aiRefPOCList0[MAX_SLICE_NUM][16];
+ int m_aiRefPOCList1[MAX_SLICE_NUM][16];
+ /*buffer */
+ unsigned int header_adr;
+#ifdef CONFIG_AM_VDEC_DV
+ 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;
+ 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
+ unsigned int buf_size;
+ 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 LOSLESS_COMPRESS_MODE
+ unsigned int losless_comp_body_size;
+#endif
+ unsigned char pic_struct;
+ int vf_ref;
+
+ u32 pts;
+ u64 pts64;
+} /*PIC_t */;
+
+#define MAX_TILE_COL_NUM 5
+#define MAX_TILE_ROW_NUM 5
+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 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
+
+static void vh265_work(struct work_struct *work);
+#endif
+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;
+ struct work_struct work;
+ /* timeout handle */
+ unsigned long int start_process_time;
+ unsigned last_lcu_idx;
+ unsigned decode_timeout_count;
+ unsigned timeout_num;
+#ifdef CONFIG_AM_VDEC_DV
+ unsigned char switch_dvlayer_flag;
+#endif
+ unsigned start_parser_type;
+#endif
+ 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;
+
+ struct BuffInfo_s work_space_buf_store;
+ struct BuffInfo_s *work_space_buf;
+ struct buff_s *mc_buf;
+
+ 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 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;
+ 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;
+
+ 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;
+
+ unsigned char
+ ignore_bufmgr_error; /* bit 0, for decoding; bit 1, for displaying */
+ 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 buf_num;
+ int pic_num;
+
+ /**/
+ struct buff_s mc_buf_spec;
+ 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[MAX_BUF_NUM];
+ u32 used_buf_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 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 uninit_list;
+ u32 start_decoding_time;
+
+ int show_frame_num;
+ struct semaphore h265_sema;
+#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;
+
+ unsigned int last_put_idx_a;
+ unsigned int last_put_idx_b;
+
+ 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 buf_alloc_width;
+ int buf_alloc_height;
+ int dynamic_buf_num_margin;
+ int start_action;
+#endif
+} /*hevc_stru_t */;
+
+#ifdef CONFIG_MULTI_DEC
+static int get_double_write_mode(struct hevc_state_s *hevc)
+{
+ return hevc->double_write_mode;
+}
+
+static int get_buf_alloc_width(struct hevc_state_s *hevc)
+{
+ return hevc->buf_alloc_width;
+}
+
+static int get_buf_alloc_height(struct hevc_state_s *hevc)
+{
+ return hevc->buf_alloc_height;
+}
+
+static int get_dynamic_buf_num_margin(struct hevc_state_s *hevc)
+{
+ return hevc->dynamic_buf_num_margin;
+}
+#endif
+
+#ifdef CONFIG_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 128
+ unsigned char buf[HEVC_PRINT_BUF];
+ int len = 0;
+#ifdef CONFIG_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_info("%s", buf);
+ va_end(args);
+#ifdef CONFIG_MULTI_DEC
+ }
+#endif
+ return 0;
+}
+
+static int hevc_print_cont(struct hevc_state_s *hevc,
+ int flag, const char *fmt, ...)
+{
+#define HEVC_PRINT_BUF 128
+ unsigned char buf[HEVC_PRINT_BUF];
+ int len = 0;
+#ifdef CONFIG_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_MULTI_DEC
+ }
+#endif
+ return 0;
+}
+
+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 hevc_init_stru(struct hevc_state_s *hevc,
+ struct BuffInfo_s *buf_spec_i,
+ struct buff_s *mc_buf_i)
+{
+ int i;
+
+ hevc->work_space_buf = buf_spec_i;
+ hevc->mc_buf = mc_buf_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->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->shift_byte_count_lo = 0;
+ hevc->shift_byte_count_hi = 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;
+
+ for (i = 0; i < MAX_REF_PIC_NUM; i++)
+ hevc->m_PIC[i] = NULL;
+ hevc->buf_num = 0;
+ 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;
+#ifdef MULTI_INSTANCE_SUPPORT
+ hevc->start_process_time = 0;
+ hevc->last_lcu_idx = 0;
+ hevc->decode_timeout_count = 0;
+ hevc->timeout_num = 0;
+#endif
+}
+
+static int prepare_display_buf(struct hevc_state_s *hevc, 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);
+
+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 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;
+
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL || pic->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)
+ continue;
+ if ((pic->POC == POC) && (pic->referenced)) {
+ if (ret_pic == NULL)
+ ret_pic = pic;
+ else {
+ if (pic->decode_idx > ret_pic->decode_idx)
+ ret_pic = pic;
+ }
+ }
+ }
+
+ if (ret_pic == NULL) {
+ if (get_dbg_flag(hevc)) {
+ hevc_print(hevc, 0,
+ "Wrong, POC of %d is not in referenced list\n",
+ POC);
+ }
+ ret_pic = get_pic_by_POC(hevc, POC);
+ }
+ 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 void uninit_mmu_buffers(struct hevc_state_s *hevc)
+{
+
+ 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_buffers(struct hevc_state_s *hevc)
+{
+ if (mmu_enable) {
+ hevc->mmu_box = decoder_mmu_box_alloc_box(DRIVER_NAME,
+ hevc->index,
+ MAX_REF_PIC_NUM,
+ 64 * SZ_1M
+ );
+ 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);
+ 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;
+}
+
+static void init_buf_list(struct hevc_state_s *hevc)
+{
+ int i;
+ int buf_size;
+ int mc_buffer_end = hevc->mc_buf->buf_start + hevc->mc_buf->buf_size;
+
+ if (get_dynamic_buf_num_margin(hevc) > 0)
+ hevc->used_buf_num = hevc->sps_num_reorder_pics_0
+ + get_dynamic_buf_num_margin(hevc);
+ else
+ hevc->used_buf_num = max_buf_num;
+
+ if (hevc->used_buf_num > MAX_BUF_NUM)
+ hevc->used_buf_num = MAX_BUF_NUM;
+ if (buf_alloc_size > 0) {
+ buf_size = buf_alloc_size;
+ if (get_dbg_flag(hevc))
+ hevc_print(hevc, 0,
+ "[Buffer Management] init_buf_list:\n");
+ } else {
+ int pic_width = get_buf_alloc_width(hevc)
+ ? get_buf_alloc_width(hevc) : hevc->pic_w;
+ int pic_height =
+ get_buf_alloc_height(hevc)
+ ? get_buf_alloc_height(hevc) : hevc->pic_h;
+#ifdef LOSLESS_COMPRESS_MODE
+/*SUPPORT_10BIT*/
+ 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, hevc->mem_saving_mode);
+ int mc_buffer_size = losless_comp_header_size
+ + losless_comp_body_size;
+ int mc_buffer_size_h = (mc_buffer_size + 0xffff)>>16;
+ if (get_double_write_mode(hevc)) {
+ int pic_width_dw = ((get_double_write_mode(hevc) == 2) ||
+ (get_double_write_mode(hevc) == 3)) ?
+ pic_width / 4 : pic_width;
+ int pic_height_dw = ((get_double_write_mode(hevc) == 2) ||
+ (get_double_write_mode(hevc) == 3)) ?
+ pic_height / 4 : pic_height;
+ int lcu_size = hevc->lcu_size;
+ int pic_width_lcu = (pic_width_dw % lcu_size)
+ ? pic_width_dw / lcu_size
+ + 1 : pic_width_dw / lcu_size;
+ int pic_height_lcu = (pic_height_dw % lcu_size)
+ ? pic_height_dw / lcu_size
+ + 1 : pic_height_dw / 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 (mmu_enable) {
+ if (get_double_write_mode(hevc) == 1)
+ buf_size += (mc_buffer_size_h << 16);
+ } else {
+ if ((get_double_write_mode(hevc) & 0x10) == 0)
+ buf_size += (mc_buffer_size_h << 16);
+ }
+#else
+ 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;
+ 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;
+#endif
+ if (get_dbg_flag(hevc)) {
+ hevc_print(hevc, 0,
+ "init_buf_list num %d (width %d height %d):\n",
+ hevc->used_buf_num, pic_width, pic_height);
+ }
+ }
+
+ hevc_print(hevc, 0, "allocate begin\n");
+ //get_cma_alloc_ref();//DEBUG_TMP
+ for (i = 0; i < hevc->used_buf_num; i++) {
+ if (((i + 1) * buf_size) > hevc->mc_buf->buf_size) {
+ if (use_cma)
+ hevc->use_cma_flag = 1;
+ else {
+ if (get_dbg_flag(hevc)) {
+ hevc_print(hevc, 0,
+ "%s maximum buf size is used\n",
+ __func__);
+ }
+ break;
+ }
+ }
+
+
+ if (!mmu_enable) {
+ hevc->m_BUF[i].index = i;
+
+ if (use_cma == 2)
+ hevc->use_cma_flag = 1;
+ if (hevc->use_cma_flag) {
+ if (decoder_bmmu_box_alloc_idx_wait(
+ hevc->bmmu_box,
+ i,
+ buf_size,
+ -1,
+ -1,
+ BMMU_ALLOC_FLAGS_WAITCLEAR
+ ) < 0) {
+ /*
+ not enough mem for buffer.
+ */
+ hevc_print(hevc, 0,
+ "not enought buffer for [%d],%d\n",
+ i, buf_size);
+ hevc->m_BUF[i].start_adr = 0;
+ if (i <= 8) {
+ /*if alloced (i+1)>=9
+ don't send errors.*/
+ hevc->fatal_error |=
+ DECODER_FATAL_ERROR_NO_MEM;
+ }
+ break;
+ }
+ hevc->m_BUF[i].start_adr =
+ decoder_bmmu_box_get_phy_addr(
+ hevc->bmmu_box,
+ i);
+ pr_debug("allocate cma buffer[%d] %ld\n",
+ i,
+ hevc->m_BUF[i].start_adr);
+ } else {
+ hevc->m_BUF[i].start_adr =
+ hevc->mc_buf->buf_start + i * buf_size;
+ if (((hevc->m_BUF[i].start_adr + buf_size) >
+ mc_buffer_end)) {
+ if (get_dbg_flag(hevc)) {
+ hevc_print(hevc, 0,
+ "Max mc buffer or mpred_mv buffer is used\n");
+ }
+ break;
+ }
+ }
+ hevc->m_BUF[i].size = buf_size;
+ hevc->m_BUF[i].free_start_adr =
+ hevc->m_BUF[i].start_adr;
+
+ if (get_dbg_flag(hevc)) {
+ 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);
+ }
+ }
+ }
+ //put_cma_alloc_ref();//DEBUG_TMP
+ hevc_print(hevc, 0, "allocate end\n");
+
+ hevc->buf_num = i;
+
+}
+
+static int config_pic(struct hevc_state_s *hevc, struct PIC_s *pic,
+ unsigned int last_disp_addr)
+{
+ int ret = -1;
+ int i;
+ int pic_width = ((re_config_pic_flag == 0) &&
+ get_buf_alloc_width(hevc)) ?
+ get_buf_alloc_width(hevc) : hevc->pic_w;
+ int pic_height = ((re_config_pic_flag == 0) &&
+ get_buf_alloc_height(hevc)) ?
+ get_buf_alloc_height(hevc) : 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;
+ int lcu_total = pic_width_lcu * pic_height_lcu;
+ 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;
+ int buf_size = 0;
+#ifdef LOSLESS_COMPRESS_MODE
+/*SUPPORT_10BIT*/
+ 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, hevc->mem_saving_mode);
+ 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;
+ if (get_double_write_mode(hevc)) {
+ int pic_width_dw = ((get_double_write_mode(hevc) == 2) ||
+ (get_double_write_mode(hevc) == 3)) ?
+ pic_width / 4 : pic_width;
+ int pic_height_dw = ((get_double_write_mode(hevc) == 2) ||
+ (get_double_write_mode(hevc) == 3)) ?
+ pic_height / 4 : pic_height;
+ 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;
+
+ 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 (mc_buffer_size & 0xffff) { /*64k alignment*/
+ mc_buffer_size_h += 1;
+ }
+ if (mmu_enable) {
+ if (get_double_write_mode(hevc) == 1)
+ buf_size += (mc_buffer_size_h << 16);
+ } else {
+ if ((get_double_write_mode(hevc) & 0x10) == 0)
+ buf_size += (mc_buffer_size_h << 16);
+ }
+#else
+ 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);
+#endif
+
+
+ if (mmu_enable) {
+ if ((hevc->work_space_buf->cm_header.buf_start +
+ ((pic->index + 1)
+ * MMU_COMPRESS_HEADER_SIZE))
+ > (hevc->work_space_buf->cm_header.buf_start +
+ hevc->work_space_buf->cm_header.buf_size)) {
+ hevc_print(hevc, 0,
+ "MMU header_adr allocate fail\n");
+ return -1;
+ }
+
+ pic->header_adr = hevc->work_space_buf->cm_header.buf_start +
+ (pic->index * MMU_COMPRESS_HEADER_SIZE);
+ if (last_disp_addr && pic->header_adr == last_disp_addr) {
+ /*if same as disp add used last one.*/
+ pr_info("same as disp %d: %d\n",
+ pic->index, pic->header_adr);
+ pic->header_adr =
+ hevc->work_space_buf->cm_header.buf_start +
+ (16 * MMU_COMPRESS_HEADER_SIZE);
+ }
+ if (get_dbg_flag(hevc)&H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "MMU header_adr %d: %x\n",
+ pic->index, pic->header_adr);
+ }
+ }
+
+
+ if ((hevc->work_space_buf->mpred_mv.buf_start + (((pic->index + 1)
+ * lcu_total) * MV_MEM_UNIT))
+ <= mpred_mv_end) {
+
+ if (!mmu_enable) {
+ for (i = 0; i < hevc->buf_num; i++) {
+ y_adr = ((hevc->m_BUF[i].free_start_adr
+ + 0xffff) >> 16) << 16;
+ /*64k alignment*/
+ if ((y_adr+buf_size) <=
+ (hevc->m_BUF[i].start_adr+
+ hevc->m_BUF[i].size)) {
+ hevc->m_BUF[i].free_start_adr =
+ y_adr + buf_size;
+ break;
+ }
+ }
+ } else
+ i = pic->index;
+
+ if (i < hevc->buf_num) {
+ pic->POC = INVALID_POC;
+ /*ensure get_pic_by_POC()
+ not get the buffer not decoded*/
+ pic->BUF_index = i;
+#ifdef LOSLESS_COMPRESS_MODE
+/*SUPPORT_10BIT*/
+ pic->comp_body_size = losless_comp_body_size;
+ pic->buf_size = buf_size;
+
+ if (!mmu_enable)
+ pic->mc_y_adr = y_adr;
+ else if (get_double_write_mode(hevc)) {
+ if ((hevc->mc_buf->buf_start
+ + (i + 1) * buf_size)
+ < hevc->mc_buf->buf_end)
+ y_adr = hevc->mc_buf->buf_start
+ + i * buf_size;
+ else {
+ if (decoder_bmmu_box_alloc_idx_wait(
+ hevc->bmmu_box,
+ pic->BUF_index,
+ buf_size,
+ -1,
+ -1,
+ BMMU_ALLOC_FLAGS_WAITCLEAR
+ ) < 0) {
+ return -1;
+ }
+ pic->cma_alloc_addr =
+ decoder_bmmu_box_get_phy_addr(
+ hevc->bmmu_box,
+ pic->BUF_index);
+ if (pic->cma_alloc_addr)
+ y_adr = pic->cma_alloc_addr;
+ else
+ return -1;
+ }
+ }
+ pic->mc_canvas_y = pic->index;
+ pic->mc_canvas_u_v = pic->index;
+ if (!mmu_enable && get_double_write_mode(hevc) & 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 if (get_double_write_mode(hevc)) {
+ if (mmu_enable)
+ pic->dw_y_adr = y_adr;
+ else
+ pic->dw_y_adr = y_adr +
+ (mc_buffer_size_h << 16);
+ pic->dw_u_v_adr = pic->dw_y_adr +
+ ((mc_buffer_size_u_v_h << 16) << 1);
+ }
+#else
+ pic->buf_size = (mc_buffer_size_u_v_h << 16) * 3;
+ pic->mc_y_adr = y_adr;
+ 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;
+#endif
+ pic->mpred_mv_wr_start_addr =
+ hevc->work_space_buf->mpred_mv.buf_start +
+ ((pic->index * lcu_total)
+ * MV_MEM_UNIT);
+
+ if (get_dbg_flag(hevc)) {
+ hevc_print(hevc, 0,
+ "%s index %d BUF_index %d mc_y_adr %x ",
+ __func__, pic->index,
+ pic->BUF_index, pic->mc_y_adr);
+#ifdef LOSLESS_COMPRESS_MODE
+ hevc_print_cont(hevc, 0,
+ "comp_body_size %x comp_buf_size %x ",
+ pic->comp_body_size, pic->buf_size);
+ hevc_print_cont(hevc, 0,
+ "mpred_mv_wr_start_adr %x\n",
+ pic->mpred_mv_wr_start_addr);
+ if (mmu_enable && get_double_write_mode(hevc))
+ hevc_print(hevc, 0,
+ "mmu double write adr %ld\n",
+ pic->cma_alloc_addr);
+
+#else
+ hevc_print(hevc, 0,
+ ("mc_u_v_adr %x mpred_mv_wr_start_adr %x\n",
+ pic->mc_u_v_adr, pic->mpred_mv_wr_start_addr);
+#endif
+ }
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+/*
+*free hevc->m_BUF[..] for all free hevc->m_PIC[..]
+* with the different size of hevc->pic_w,hevc->pic_h
+*/
+static int recycle_buf(struct hevc_state_s *hevc)
+{
+ int i, j;
+
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ struct PIC_s *pic = hevc->m_PIC[i];
+ if (pic == NULL || pic->index == -1)
+ continue;
+ if (pic->width != hevc->pic_w || pic->height != hevc->pic_h) {
+ if (pic->output_mark == 0 && pic->referenced == 0
+ && pic->output_ready == 0) {
+ if (mmu_enable) {
+ decoder_mmu_box_free_idx(hevc->mmu_box,
+ pic->index);
+ }
+ pic->BUF_index = -1;
+ if (get_dbg_flag(hevc)) {
+ hevc_print(hevc, 0,
+ "%s: %d\n", __func__,
+ pic->index);
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < hevc->buf_num; i++) {
+ if (hevc->m_BUF[i].free_start_adr !=
+ hevc->m_BUF[i].start_adr) {
+ for (j = 0; j < MAX_REF_PIC_NUM; j++) {
+ struct PIC_s *pic = hevc->m_PIC[j];
+ if (pic == NULL || pic->index == -1)
+ continue;
+ if (pic->BUF_index == i)
+ break;
+ }
+ if (j == MAX_REF_PIC_NUM)
+ hevc->m_BUF[i].free_start_adr =
+ hevc->m_BUF[i].start_adr;
+ }
+ }
+ return 0;
+}
+
+static void init_pic_list(struct hevc_state_s *hevc)
+{
+ int i;
+ struct vframe_s vf;
+ unsigned long flags;
+ unsigned long disp_addr = 0;
+
+ if (!get_video0_frame_info(&vf)) {
+ spin_lock_irqsave(&lock, flags);
+ if (vf.type & VIDTYPE_SCATTER) {
+ /*sc only used header.*/
+ disp_addr = (VSYNC_RD_MPEG_REG(AFBC_HEAD_BADDR) << 4);
+ } else if (vf.type & VIDTYPE_COMPRESS) {
+ /*sc checked body.*/
+ disp_addr = (VSYNC_RD_MPEG_REG(AFBC_BODY_BADDR) << 4);
+ } else {
+ struct canvas_s cur_canvas;
+
+ canvas_read(vf.canvas0Addr & 0xff, &cur_canvas);
+ disp_addr = cur_canvas.addr;
+ }
+ spin_unlock_irqrestore(&lock, flags);
+ }
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ struct PIC_s *pic =
+ vmalloc(sizeof(struct PIC_s));
+ if (pic == NULL) {
+ hevc_print(hevc, 0,
+ "alloc pic %d fail\n", i);
+ break;
+ }
+ memset(pic, 0, sizeof(struct PIC_s));
+ hevc->m_PIC[i] = pic;
+ pic->index = i;
+ pic->BUF_index = -1;
+ if (config_pic(hevc, pic, disp_addr) < 0) {
+ if (get_dbg_flag(hevc))
+ hevc_print(hevc, 0,
+ "Config_pic %d fail\n", pic->index);
+ pic->index = -1;
+ i++;
+ break;
+ }
+ pic->width = hevc->pic_w;
+ pic->height = hevc->pic_h;
+ if (get_double_write_mode(hevc))
+ set_canvas(hevc, pic);
+ }
+
+ for (; i < MAX_REF_PIC_NUM; i++) {
+ struct PIC_s *pic =
+ vmalloc(sizeof(struct PIC_s));
+ if (pic == NULL) {
+ hevc_print(hevc, 0,
+ "alloc pic %d fail\n", i);
+ break;
+ }
+ memset(pic, 0, sizeof(struct PIC_s));
+ hevc->m_PIC[i] = pic;
+ pic->index = -1;
+ pic->BUF_index = -1;
+ }
+
+}
+
+static void uninit_pic_list(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) {
+ 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->pic_w,
+ hevc->pic_h, hevc->mem_saving_mode);
+
+ hevc->losless_comp_body_size = losless_comp_body_size;
+
+
+ if (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 (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 +
+ buf_spec->mmu_vbh.buf_size/2);
+ 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;
+
+ if (get_cpu_type() >= 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_type() >= MESON_CPU_MAJOR_ID_GXL) {
+ if (mmu_enable)
+ 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 (get_double_write_mode(hevc) & 0x10) {
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXL) {
+ if (mmu_enable)
+ 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_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;
+ for (; i < MAX_REF_PIC_NUM; i++) {
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXL) {
+ if (mmu_enable)
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA,
+ hevc->m_PIC[cur_pic_num-1]->header_adr>>5);
+ else
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA,
+ hevc->m_PIC[cur_pic_num-1]->mc_y_adr >> 5);
+#ifndef LOSLESS_COMPRESS_MODE
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_DATA,
+ hevc->m_PIC[cur_pic_num-1]->mc_u_v_adr >> 5);
+#endif
+ } else {
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
+ hevc->m_PIC[cur_pic_num-1]->mc_y_adr|
+ (hevc->m_PIC[cur_pic_num-1]->mc_canvas_y<<8)
+ | 0x1);
+#ifndef LOSLESS_COMPRESS_MODE
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
+ hevc->m_PIC[cur_pic_num-1]->mc_u_v_adr|
+ (hevc->m_PIC[cur_pic_num-1]->mc_canvas_u_v<<8)
+ | 0x1);
+#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);
+
+#ifdef LOSLESS_COMPRESS_MODE
+ if ((get_double_write_mode(hevc) & 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 decode_idx:%d, POC:%d, referenced:%d, ",
+ pic->index, pic->decode_idx, pic->POC, pic->referenced);
+ hevc_print_cont(hevc, 0,
+ "num_reorder_pic:%d, output_mark:%d, w/h %d,%d",
+ pic->num_reorder_pic, pic->output_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 struct PIC_s *output_pic(struct hevc_state_s *hevc,
+ unsigned char flush_flag)
+{
+ int num_pic_not_yet_display = 0;
+ int i;
+ struct PIC_s *pic;
+ struct PIC_s *pic_display = NULL;
+
+ if (i_only_flag & 0x4) {
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL ||
+ (pic->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;
+ }
+ } else {
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL ||
+ (pic->index == -1) || (pic->POC == INVALID_POC))
+ continue;
+ if (pic->output_mark)
+ num_pic_not_yet_display++;
+ }
+
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL ||
+ (pic->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;
+ }
+ }
+ 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;
+ }
+ }
+ 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->error_mark)
+ 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 {
+ if (get_dbg_flag(hevc)) {
+ hevc_print_cont(hevc, 0,
+ "Error %s, %dth poc (%d)",
+ __func__, i,
+ cur_pic->m_aiRefPOCList0[cur_pic->
+ slice_idx][i]);
+ hevc_print_cont(hevc, 0,
+ " of RPS is not in the pic list0\n");
+ }
+ cur_pic->error_mark = 1;
+ /* dump_lmem(); */
+ }
+ }
+ }
+ 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->error_mark)
+ 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 {
+ if (get_dbg_flag(hevc)) {
+ hevc_print_cont(hevc, 0,
+ "Error %s, %dth poc (%d)",
+ __func__, i,
+ cur_pic->m_aiRefPOCList1[cur_pic->
+ slice_idx][i]);
+ hevc_print_cont(hevc, 0,
+ " of RPS is not in the pic list1\n");
+ }
+ cur_pic->error_mark = 1;
+ /* dump_lmem(); */
+ }
+ }
+ }
+ return 0;
+}
+
+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;
+
+ /* pr_info("%s cur_poc %d\n", __func__, cur_poc); */
+ for (ii = 0; ii < MAX_REF_PIC_NUM; ii++) {
+ pic = hevc->m_PIC[ii];
+ if (pic == NULL ||
+ pic->index == -1)
+ continue;
+
+ if ((pic->referenced == 0 || pic->POC == cur_poc))
+ continue;
+ is_referenced = 0;
+ for (i = 0; i < 16; i++) {
+ int delt;
+
+ if (params->p.CUR_RPS[i] & 0x8000)
+ break;
+ 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) {
+ is_referenced = 1;
+ /* pr_info("i is %d\n", i); */
+ break;
+ }
+ }
+ if (is_referenced == 0) {
+ pic->referenced = 0;
+ /* pr_info("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];
+
+ 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++) {
+ if (params->p.CUR_RPS[i] & 0x8000)
+ break;
+ 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) {
+ 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 {
+ RefPicSetStCurr1[num_pos] = pic->POC + delt;
+ /* hevc_print(hevc, 0,
+ "RefPicSetStCurr1 %d\n",
+ RefPicSetStCurr1[num_pos]); */
+ num_pos++;
+ }
+ }
+ }
+ total_num = num_neg + num_pos;
+ 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);
+ 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);
+ }
+
+ 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] =
+ 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] =
+ 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] =
+ 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] =
+ 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;
+
+ 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, 0,
+ "%s %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);
+ 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 (mmu_enable)
+ 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);
+ /* 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_dbg_flag(hevc) & H265_DEBUG_UCODE)
+ WRITE_VREG(LMEM_DUMP_ADR, (u32)hevc->lmem_phy_addr);
+
+}
+
+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 1
+ /* m8baby test1902 */
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ hevc_print(hevc, 0,
+ "[test.c] Test Parser Register Read/Write\n");
+ 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 (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ hevc_print(hevc, 0,
+ "[test.c] Enable BitStream Fetch\n");
+ ;
+ if (!hevc->m_ins_flag) {
+ 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);
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ hevc_print(hevc, 0,
+ "[test.c] Enable HEVC Parser Interrupt\n");
+ 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);
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ hevc_print(hevc, 0,
+ "[test.c] Enable HEVC Parser Shift\n");
+
+ 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 */
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR) {
+ hevc_print(hevc, 0,
+ "[test.c] Initial IQIT_SCALELUT memory --");
+ hevc_print_cont(hevc, 0,
+ " just to avoid X in simulation...\n");
+ }
+ 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 */
+ if (get_dbg_flag(hevc))
+ hevc_print(hevc, 0,
+ "[test.c] SEND Parser Command ...\n");
+ 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 */
+ );
+
+ /* Changed to Start MPRED in microcode */
+ /*
+ hevc_print(hevc, 0, "[test.c] Start MPRED\n");
+ WRITE_VREG(HEVC_MPRED_INT_STATUS,
+ (1<<31)
+ );
+ */
+
+ if (get_dbg_flag(hevc))
+ hevc_print(hevc, 0,
+ "[test.c] Reset IPP\n");
+ 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));
+ 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 */
+ );
+
+ 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);
+ return;
+}
+#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 void config_aux_buf(struct hevc_state_s *hevc)
+{
+ WRITE_VREG(HEVC_AUX_ADR, hevc->aux_phy_addr);
+ WRITE_VREG(HEVC_AUX_DATA_SIZE,
+ ((hevc->prefix_aux_size >> 4) << 16) |
+ (hevc->suffix_aux_size >> 4)
+ );
+}
+
+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 +
+ ((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 |
+ hevc->new_pic << 2 |
+ hevc->new_tile << 3 |
+ hevc->isNextSliceSegment << 4 |
+ hevc->TMVPFlag << 5 |
+ hevc->LDCFlag << 6 |
+ hevc->ColFromL0Flag << 7 |
+ above_ptr_ctrl << 8 |
+ above_en << 9 |
+ mv_wr_en << 10 |
+ mv_rd_en << 11 |
+ col_isIntra << 12 |
+ buffer_linear << 13 |
+ hevc->LongTerm_Curr << 14 |
+ hevc->LongTerm_Col << 15 |
+ hevc->lcu_size_log2 << 16 |
+ cu_size_log2 << 20 | hevc->plevel << 24);
+ 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);
+
+ data32 = (hevc->LongTerm_Ref);
+ 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;
+
+ 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) != 1)
+ data32 |= (0xff<<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 (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) {
+ 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 0
+ data32 = READ_VREG(HEVC_SAO_CTRL1);
+ data32 &= (~0x3000);
+ data32 |= (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 |= (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 |= 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 (!mmu_enable && (get_double_write_mode(hevc) & 0x10))
+ data32 |= 0x1; /*disable cm*/
+ 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 |= (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
+ 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);
+}
+
+static void clear_used_by_display_flag(struct hevc_state_s *hevc)
+{
+ struct PIC_s *pic;
+ int i;
+ if (get_dbg_flag(hevc) & H265_DEBUG_NOT_USE_LAST_DISPBUF)
+ return;
+
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic)
+ pic->used_by_display = 0;
+ }
+}
+
+static struct PIC_s *get_new_pic(struct hevc_state_s *hevc,
+ union param_u *rpm_param)
+{
+ struct PIC_s *new_pic = NULL;
+ struct PIC_s *pic;
+ /* recycle un-used 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->used_by_display) && !mmu_enable
+ && ((READ_VCBUS_REG(AFBC_BODY_BADDR) << 4) !=
+ pic->mc_y_adr))
+ pic->used_by_display = 0;
+ if (pic->output_mark == 0 && pic->referenced == 0
+ && pic->output_ready == 0
+ && pic->used_by_display == 0) {
+ if (new_pic) {
+ if (pic->POC < new_pic->POC)
+ new_pic = pic;
+ } else
+ new_pic = pic;
+ }
+ }
+
+ /*try to allocate more pic for new resolution*/
+ if (re_config_pic_flag && new_pic == NULL) {
+ int ii;
+
+ for (ii = 0; ii < MAX_REF_PIC_NUM; ii++) {
+ if (hevc->m_PIC[ii] == NULL ||
+ hevc->m_PIC[ii]->index == -1)
+ break;
+ }
+ if (ii < MAX_REF_PIC_NUM) {
+ new_pic = hevc->m_PIC[ii];
+ if (new_pic) {
+ memset(new_pic, 0, sizeof(struct PIC_s));
+ new_pic->index = ii;
+ new_pic->BUF_index = -1;
+ }
+ }
+ }
+ /**/
+
+ if (new_pic == NULL) {
+ /* pr_info("Error: Buffer management, no free buffer\n"); */
+ return new_pic;
+ }
+
+ new_pic->referenced = 1;
+ if (new_pic->width != hevc->pic_w ||
+ new_pic->height != hevc->pic_h) {
+ if (re_config_pic_flag) {
+ /* re config pic for new resolution */
+ recycle_buf(hevc);
+ /* if(new_pic->BUF_index == -1){ */
+ if (config_pic(hevc, new_pic, 0) < 0) {
+ if (get_dbg_flag(hevc) &
+ H265_DEBUG_BUFMGR_MORE) {
+ hevc_print(hevc, 0,
+ "Config_pic %d fail\n",
+ new_pic->index);
+ dump_pic_list(hevc);
+ }
+ new_pic->index = -1;
+ new_pic = NULL;
+ } else
+ init_pic_list_hw(hevc);
+ }
+ if (new_pic) {
+ new_pic->width = hevc->pic_w;
+ new_pic->height = hevc->pic_h;
+ set_canvas(hevc, new_pic);
+ }
+ }
+ if (new_pic) {
+ 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->output_ready = 0; */
+ new_pic->num_reorder_pic = rpm_param->p.sps_num_reorder_pics_0;
+ 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);
+ }
+
+ if (mmu_enable) {
+ ret = H265_alloc_mmu(hevc, new_pic, rpm_param->p.bit_depth,
+ hevc->frame_mmu_map_addr);
+ /*pr_info("get pic index %x\n",new_pic->index);*/
+ if (ret != 0) {
+ pr_err("can't alloc need mmu1,idx %d ret =%d\n",
+ new_pic->decode_idx,
+ ret);
+ return NULL;
+ }
+
+ }
+
+ 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->output_mark = 1;
+ pic->recon_mark = 1;
+ }
+ pic->recon_mark = 1;
+ }
+ do {
+ pic_display = output_pic(hevc, 1);
+
+ if (pic_display) {
+ pic_display->referenced = 0;
+ 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");
+ }
+ } else {
+ if (i_only_flag & 0x1
+ && pic_display->slice_type != 2)
+ pic_display->output_ready = 0;
+ else {
+ prepare_display_buf(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);
+}
+
+static void set_aux_data(struct hevc_state_s *hevc,
+ struct PIC_s *pic, unsigned char suffix_flag)
+{
+ int i;
+ unsigned short *aux_adr;
+ unsigned size_reg_val =
+ READ_VREG(HEVC_AUX_DATA_SIZE);
+ unsigned aux_count = 0;
+ int aux_size = 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:old size %d count %d,suf %d\r\n",
+ __func__, pic->aux_data_size, aux_count, suffix_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)
+ heads_size += 8;
+ }
+ new_size = pic->aux_data_size + aux_count + heads_size;
+ new_buf = krealloc(pic->aux_data_buf,
+ new_size,
+ GFP_KERNEL);
+ if (new_buf) {
+ unsigned char *p =
+ new_buf +
+ pic->aux_data_size;
+ unsigned char *h = p;
+ int h_bytes = 8;
+ int len = 0;
+ int padding_len = 0;
+ pic->aux_data_buf = new_buf;
+ pic->aux_data_size += (aux_count + heads_size);
+ for (i = 0; i < aux_count; i += 4) {
+ int ii;
+ unsigned char tag = aux_adr[i + 3] >> 8;
+ if (tag != 0 && tag != 0xff) {
+ if (i > 0) {
+ 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);
+ h_bytes += 8;
+ len = 0;
+ padding_len = 0;
+ }
+ h[4] = tag;
+ h[5] = 0;
+ h[6] = 0;
+ h[7] = 0;
+ }
+ for (ii = 0; ii < 4; ii++) {
+ unsigned short aa =
+ aux_adr[i + 3
+ - ii];
+ p[h_bytes + i + ii] =
+ aa & 0xff;
+ len++;
+ if ((aa >> 8) == 0xff)
+ padding_len++;
+ }
+ }
+ 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");
+ }
+
+ }
+ }
+
+}
+
+static void release_aux_data(struct hevc_state_s *hevc,
+ struct PIC_s *pic)
+{
+ kfree(pic->aux_data_buf);
+ 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) {*/
+ 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, hevc->iPrevPOC);
+ 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;
+ }
+ }
+ pic->output_mark = 1;
+ pic->recon_mark = 1;
+ }
+ 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");
+ }
+ } else {
+ if (i_only_flag & 0x1
+ && pic_display->
+ slice_type != 2) {
+ pic_display->output_ready = 0;
+ } else {
+ prepare_display_buf
+ (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);
+ pic = get_pic_by_POC(hevc, hevc->iPrevPOC);
+ flush_output(hevc, pic);
+ }
+
+}
+
+static void check_pic_decoded_lcu_count(struct hevc_state_s *hevc)
+{
+ int current_lcu_idx = READ_VREG(HEVC_PARSER_LCU_START)&0xffffff;
+ 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)
+ 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);
+
+ }
+ hevc->lcu_x_num_pre = hevc->lcu_x_num;
+ hevc->lcu_y_num_pre = hevc->lcu_y_num;
+}
+
+static int hevc_slice_segment_header_process(struct hevc_state_s *hevc,
+ union param_u *rpm_param,
+ int decode_pic_begin)
+{
+#ifdef CONFIG_AM_VDEC_DV
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+#endif
+ int i;
+ int lcu_x_num_div;
+ int lcu_y_num_div;
+ int Col_ref;
+ int dbg_skip_flag = 0;
+
+ if (hevc->wait_buf == 0) {
+ hevc->sps_num_reorder_pics_0 =
+ rpm_param->p.sps_num_reorder_pics_0;
+ 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 (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 (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_SIZE < hevc->pic_w * hevc->pic_h) {
+ pr_info("over size : %u x %u.\n",
+ hevc->pic_w, hevc->pic_h);
+ 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 -1;
+ }
+
+ /* 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;
+ }
+ 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;
+ check_pic_decoded_lcu_count(hevc);
+ /**/ if (use_cma == 0) {
+ if (hevc->pic_list_init_flag == 0) {
+ /*USE_BUF_BLOCK*/
+ init_buf_list(hevc);
+ /**/
+ init_pic_list(hevc);
+ init_pic_list_hw(hevc);
+ init_buf_spec(hevc);
+ hevc->pic_list_init_flag = 3;
+ }
+ }
+ hevc->first_pic_after_recover = 0;
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR_MORE)
+ dump_pic_list(hevc);
+ /* 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 (mmu_enable && hevc->cur_pic != NULL) {
+ if (!(hevc->cur_pic->error_mark
+ && ((hevc->ignore_bufmgr_error & 0x1) == 0))) {
+ long used_4k_num =
+ (READ_VREG(HEVC_SAO_MMU_STATUS) >> 16);
+ decoder_mmu_box_free_idx_tail(hevc->mmu_box,
+ hevc->cur_pic->index, used_4k_num);
+ }
+
+ }
+#ifdef CONFIG_AM_VDEC_DV
+ 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;
+ }
+ if (vdec->master == NULL &&
+ vdec->slave == NULL) {
+ if (hevc->cur_pic != NULL)
+ set_aux_data(hevc, hevc->cur_pic, 1);
+ }
+#else
+ if (hevc->cur_pic != NULL)
+ set_aux_data(hevc, hevc->cur_pic, 1);
+#endif
+ /* new pic */
+ hevc->cur_pic = 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 CONFIG_AM_VDEC_DV
+ hevc->cur_pic->dv_enhance_exist = 0;
+ if (vdec->master == NULL &&
+ vdec->slave == NULL)
+ set_aux_data(hevc, hevc->cur_pic, 0);
+#else
+ set_aux_data(hevc, hevc->cur_pic, 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(hevc, hevc->cur_pic);
+ hevc->wait_buf = 2;
+ return -1;
+ }
+ } else {
+#ifdef CONFIG_AM_VDEC_DV
+ if (vdec->master == NULL &&
+ vdec->slave == NULL) {
+ if (hevc->cur_pic != NULL) {
+ set_aux_data(hevc, hevc->cur_pic, 1);
+ set_aux_data(hevc, hevc->cur_pic, 0);
+ }
+ }
+#else
+ if (hevc->cur_pic != NULL) {
+ set_aux_data(hevc, hevc->cur_pic, 1);
+ set_aux_data(hevc, hevc->cur_pic, 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) {
+ /*
+ *if (mmu_enable && hevc->cur_pic != NULL) {
+ * long used_4k_num =
+ * (READ_VREG(HEVC_SAO_MMU_STATUS) >> 16);
+ * decoder_mmu_box_free_idx_tail(hevc->mmu_box,
+ * hevc->cur_pic->index, used_4k_num);
+ *
+ * }
+ */
+ hevc->cur_pic = get_new_pic(hevc, rpm_param);
+ if (hevc->cur_pic == NULL)
+ return -1;
+
+#ifdef CONFIG_AM_VDEC_DV
+ hevc->cur_pic->dv_enhance_exist = 0;
+ if (vdec->master == NULL &&
+ vdec->slave == NULL)
+ set_aux_data(hevc, hevc->cur_pic, 0);
+#else
+ set_aux_data(hevc, hevc->cur_pic, 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\n",
+ __func__,
+ hevc->decode_idx,
+ hevc->curr_pic_struct,
+ hevc->interlace_flag);
+ }
+ 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->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->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(i_only_flag==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");
+ }
+ } else if (hevc->col_pic->error_mark) {
+ hevc->cur_pic->error_mark = 1;
+ if (get_dbg_flag(hevc)) {
+ hevc_print(hevc, 0,
+ "WRONG, Col_POC error_mark is 1\n");
+ }
+ }
+
+ if (hevc->cur_pic->error_mark
+ && ((hevc->ignore_bufmgr_error & 0x1) == 0)) {
+ 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 (hevc->cur_pic->error_mark
+ && ((hevc->ignore_bufmgr_error & 0x1) == 0)) {
+ if (get_dbg_flag(hevc))
+ hevc_print(hevc, 0,
+ "Discard this picture index %d\n",
+ hevc->cur_pic->index);
+ return 2;
+ }
+#ifdef MCRCC_ENABLE
+ config_mcrcc_axi_hw(hevc, hevc->cur_pic->slice_type);
+#endif
+ config_mpred_hw(hevc);
+
+ config_sao_hw(hevc, rpm_param);
+
+ if ((hevc->slice_type != 2) && (i_only_flag & 0x2))
+ return 0xf;
+
+ 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;
+
+ picture_size = compute_losless_comp_body_size(new_pic->width,
+ new_pic->height, !bit_depth_10);
+ cur_mmu_4k_number = ((picture_size+(1<<12)-1) >> 12);
+
+ /*
+ *pr_info("alloc_mmu cur_idx : %d picture_size : %d mmu_4k_number : %d\r\n",
+* cur_buf_idx, picture_size, cur_mmu_4k_number);
+*/
+ return decoder_mmu_box_alloc_idx(
+ hevc->mmu_box,
+ cur_buf_idx,
+ cur_mmu_4k_number,
+ mmu_index_adr);
+}
+
+
+
+
+
+
+/*
+*************************************************
+*
+*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;
+
+ if (hevc->aux_addr) {
+ dma_unmap_single(amports_get_dma_device(),
+ hevc->aux_phy_addr,
+ hevc->prefix_aux_size + hevc->suffix_aux_size,
+ DMA_FROM_DEVICE);
+ kfree(hevc->aux_addr);
+ hevc->aux_addr = NULL;
+ }
+ if (hevc->rpm_addr) {
+ dma_unmap_single(amports_get_dma_device(),
+ hevc->rpm_phy_addr, RPM_BUF_SIZE, DMA_FROM_DEVICE);
+ kfree(hevc->rpm_addr);
+ hevc->rpm_addr = NULL;
+ }
+ if (hevc->lmem_addr) {
+ dma_unmap_single(amports_get_dma_device(),
+ hevc->lmem_phy_addr, LMEM_BUF_SIZE, DMA_FROM_DEVICE);
+ kfree(hevc->lmem_addr);
+ hevc->lmem_addr = NULL;
+ }
+
+ if (mmu_enable && hevc->frame_mmu_map_addr) {
+ if (hevc->frame_mmu_map_phy_addr)
+ dma_free_coherent(amports_get_dma_device(),
+ FRAME_MMU_MAP_SIZE, hevc->frame_mmu_map_addr,
+ hevc->frame_mmu_map_phy_addr);
+
+ hevc->frame_mmu_map_addr = NULL;
+ }
+
+
+}
+
+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;
+#ifdef SUPPORT_4K2K
+ memcpy(cur_buf_info, &amvh265_workbuff_spec[1], /* 4k2k work space */
+ sizeof(struct BuffInfo_s));
+#else
+ memcpy(cur_buf_info, &amvh265_workbuff_spec[0], /* 1080p work space */
+ sizeof(struct BuffInfo_s));
+#endif
+ cur_buf_info->start_adr = hevc->buf_start;
+ hevc->mc_buf_spec.buf_end = hevc->buf_start + hevc->buf_size;
+ init_buff_spec(hevc, cur_buf_info);
+
+
+
+ hevc->mc_buf_spec.buf_start = (cur_buf_info->end_adr + 0xffff)
+ & (~0xffff);
+ hevc->mc_buf_spec.buf_size = (hevc->mc_buf_spec.buf_end
+ - hevc->mc_buf_spec.buf_start);
+
+ hevc_init_stru(hevc, cur_buf_info, &hevc->mc_buf_spec);
+
+ hevc->bit_depth_luma = 8;
+ hevc->bit_depth_chroma = 8;
+ hevc->video_signal_type = 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 = kmalloc(RPM_BUF_SIZE, GFP_KERNEL);
+ if (hevc->rpm_addr == NULL) {
+ pr_err("%s: failed to alloc rpm buffer\n", __func__);
+ return -1;
+ }
+
+ hevc->rpm_phy_addr = dma_map_single(amports_get_dma_device(),
+ hevc->rpm_addr, RPM_BUF_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(amports_get_dma_device(),
+ hevc->rpm_phy_addr)) {
+ pr_err("%s: failed to map rpm buffer\n", __func__);
+ kfree(hevc->rpm_addr);
+ hevc->rpm_addr = NULL;
+ 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 = kmalloc(aux_buf_size, GFP_KERNEL);
+ if (hevc->aux_addr == NULL) {
+ pr_err("%s: failed to alloc rpm buffer\n", __func__);
+ return -1;
+ }
+
+ hevc->aux_phy_addr = dma_map_single(amports_get_dma_device(),
+ hevc->aux_addr, aux_buf_size, DMA_FROM_DEVICE);
+ if (dma_mapping_error(amports_get_dma_device(),
+ hevc->aux_phy_addr)) {
+ pr_err("%s: failed to map rpm buffer\n", __func__);
+ kfree(hevc->aux_addr);
+ hevc->aux_addr = NULL;
+ return -1;
+ }
+ }
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_UCODE) {
+ hevc->lmem_addr = kmalloc(LMEM_BUF_SIZE, GFP_KERNEL);
+ if (hevc->lmem_addr == NULL) {
+ pr_err("%s: failed to alloc lmem buffer\n", __func__);
+ return -1;
+ }
+
+ hevc->lmem_phy_addr = dma_map_single(amports_get_dma_device(),
+ hevc->lmem_addr, LMEM_BUF_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(amports_get_dma_device(),
+ hevc->lmem_phy_addr)) {
+ pr_err("%s: failed to map lmem buffer\n", __func__);
+ kfree(hevc->lmem_addr);
+ hevc->lmem_addr = NULL;
+ return -1;
+ }
+
+ hevc->lmem_ptr = hevc->lmem_addr;
+ }
+
+ if (mmu_enable) {
+ hevc->frame_mmu_map_addr =
+ dma_alloc_coherent(amports_get_dma_device(),
+ 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, 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)
+{
+ int canvas_w = ALIGN(pic->width, 64)/4;
+ int canvas_h = ALIGN(pic->height, 32)/4;
+ int blkmode = mem_map_mode;
+
+ /*CANVAS_BLKMODE_64X32*/
+#ifdef SUPPORT_10BIT
+ if (get_double_write_mode(hevc)) {
+ canvas_w = pic->width;
+ canvas_h = pic->height;
+ if ((get_double_write_mode(hevc) == 2) ||
+ (get_double_write_mode(hevc) == 3)) {
+ canvas_w >>= 2;
+ canvas_h >>= 2;
+ }
+
+ if (mem_map_mode == 0)
+ canvas_w = ALIGN(canvas_w, 32);
+ else
+ canvas_w = ALIGN(canvas_w, 64);
+ canvas_h = ALIGN(canvas_h, 32);
+
+ 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 {
+ if (!mmu_enable) {
+ /* to change after 10bit VPU is ready ... */
+ 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);
+ }
+ }
+#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, 0x7);
+ canvas_config_ex(pic->uv_canvas_index, pic->mc_u_v_adr,
+ canvas_w, canvas_h,
+ CANVAS_ADDR_NOWRAP, blkmode, 0x7);
+#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, 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_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:
+ 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;
+ 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 void set_frame_info(struct hevc_state_s *hevc, struct vframe_s *vf)
+{
+ unsigned int ar;
+ int i, j;
+ unsigned char index;
+ char *p;
+ unsigned size = 0;
+ unsigned type = 0;
+ struct vframe_master_display_colour_s *vf_dp
+ = &vf->prop.master_display_colour;
+
+ if ((get_double_write_mode(hevc) == 2) ||
+ (get_double_write_mode(hevc) == 3)) {
+ vf->width = hevc->frame_width/4;
+ vf->height = hevc->frame_height/4;
+ } else {
+ vf->width = hevc->frame_width;
+ vf->height = hevc->frame_height;
+ }
+ 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);
+
+ /* signal_type */
+ if (hevc->video_signal_type & VIDEO_SIGNAL_TYPE_AVAILABLE_MASK)
+ vf->signal_type = hevc->video_signal_type;
+ else
+ vf->signal_type = 0;
+
+ /* parser sei */
+ index = vf->index & 0xff;
+ if (index != 0xff && index >= 0
+ && index < MAX_REF_PIC_NUM
+ && hevc->m_PIC[index]
+ && hevc->m_PIC[index]->aux_data_buf
+ && hevc->m_PIC[index]->aux_data_size) {
+ p = hevc->m_PIC[index]->aux_data_buf;
+ while (p < hevc->m_PIC[index]->aux_data_buf
+ + hevc->m_PIC[index]->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, p, size);
+ }
+ p += size;
+ }
+ }
+
+ /* 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;
+ return;
+}
+
+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;
+#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 (kfifo_peek(&hevc->display_q, &vf))
+ return vf;
+
+ 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 (kfifo_get(&hevc->display_q, &vf)) {
+ if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT)
+ hevc_print(hevc, 0,
+ "%s(type %d index 0x%x)\n",
+ __func__, vf->type, vf->index);
+
+ hevc->show_frame_num++;
+ return vf;
+ }
+
+ return NULL;
+}
+
+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 = vf->index & 0xff;
+ unsigned char index_bot = (vf->index >> 8) & 0xff;
+ if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT)
+ hevc_print(hevc, 0,
+ "%s(type %d index 0x%x)\n",
+ __func__, vf->type, vf->index);
+
+ kfifo_put(&hevc->newframe_q, (const struct vframe_s *)vf);
+ spin_lock_irqsave(&lock, flags);
+
+ if (index_top != 0xff && index_top >= 0
+ && index_top < MAX_REF_PIC_NUM
+ && hevc->m_PIC[index_top]) {
+ 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;
+ if (mmu_enable)
+ hevc->m_PIC[index_top]->
+ used_by_display = 0;
+ hevc->last_put_idx_a = index_top;
+ if (hevc->wait_buf != 0)
+ WRITE_VREG(HEVC_ASSIST_MBOX1_IRQ_REG,
+ 0x1);
+ }
+ }
+ }
+
+ if (index_bot != 0xff && index_bot >= 0
+ && index_bot < MAX_REF_PIC_NUM
+ && hevc->m_PIC[index_bot]) {
+ 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) {
+ clear_used_by_display_flag(hevc);
+ hevc->m_PIC[index_bot]->output_ready = 0;
+ hevc->last_put_idx_b = index_bot;
+ if (hevc->wait_buf != 0)
+ WRITE_VREG(HEVC_ASSIST_MBOX1_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;
+ 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 >= 0
+ && 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_AM_VDEC_DV
+ req->dv_enhance_exist =
+ hevc->m_PIC[index]->dv_enhance_exist;
+#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);
+ }
+
+ 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 (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) {
+ /* 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);
+ kfifo_put(&hevc->display_q, (const struct vframe_s *)vf);
+ }
+
+ if (kfifo_peek(&hevc->pending_q, &vf)) {
+ if (pair_pic == NULL || 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)
+ kfifo_put(&hevc->display_q,
+ (const struct vframe_s *)vf);
+ } 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) {
+ vf->type = VIDTYPE_PROGRESSIVE
+ | VIDTYPE_VIU_NV21;
+ vf->index &= 0xff;
+ vf->index |= (pair_pic->index << 8);
+ vf->canvas1Addr = spec2canvas(pair_pic);
+ pair_pic->vf_ref++;
+ kfifo_put(&hevc->display_q,
+ (const struct vframe_s *)vf);
+ 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) {
+ vf->type = VIDTYPE_PROGRESSIVE
+ | VIDTYPE_VIU_NV21;
+ vf->index &= 0xff00;
+ vf->index |= pair_pic->index;
+ vf->canvas0Addr = spec2canvas(pair_pic);
+ pair_pic->vf_ref++;
+ kfifo_put(&hevc->display_q,
+ (const struct vframe_s *)vf);
+ 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, int index)
+{
+ if (index < 0)
+ vf->mem_handle = NULL;
+ else if (vf->type & VIDTYPE_SCATTER)
+ vf->mem_handle =
+ decoder_mmu_box_get_mem_handle(
+ hevc->mmu_box, index);
+ else
+ vf->mem_handle =
+ decoder_bmmu_box_get_mem_handle(
+ hevc->bmmu_box, index);
+ return;
+}
+static int prepare_display_buf(struct hevc_state_s *hevc, struct PIC_s *pic)
+{
+ struct vframe_s *vf = NULL;
+ int stream_offset = pic->stream_offset;
+ unsigned short slice_type = pic->slice_type;
+
+ if (kfifo_get(&hevc->newframe_q, &vf) == 0) {
+ hevc_print(hevc, 0,
+ "fatal error, no available buffer slot.");
+ return -1;
+ }
+
+ if (vf) {
+ if (hevc->m_ins_flag) {
+ vf->pts = pic->pts;
+ vf->pts_us64 = pic->pts64;
+ }
+ /* if (pts_lookup_offset(PTS_TYPE_VIDEO,
+ stream_offset, &vf->pts, 0) != 0) { */
+ else if (pts_lookup_offset_us64
+ (PTS_TYPE_VIDEO, stream_offset, &vf->pts, 0,
+ &vf->pts_us64) != 0) {
+#ifdef DEBUG_PTS
+ hevc->pts_missed++;
+#endif
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+ }
+#ifdef DEBUG_PTS
+ else
+ hevc->pts_hit++;
+#endif
+ if (pts_unstable && (hevc->frame_dur > 0))
+ hevc->pts_mode = PTS_NONE_REF_USE_DURATION;
+
+ if ((hevc->pts_mode == PTS_NORMAL) && (vf->pts != 0)
+ && hevc->get_frame_dur) {
+ int pts_diff = (int)vf->pts - hevc->last_lookup_pts;
+
+ if (pts_diff < 0) {
+ hevc->pts_mode_switching_count++;
+ hevc->pts_mode_recovery_count = 0;
+
+ if (hevc->pts_mode_switching_count >=
+ PTS_MODE_SWITCHING_THRESHOLD) {
+ hevc->pts_mode =
+ PTS_NONE_REF_USE_DURATION;
+ hevc_print(hevc, 0,
+ "HEVC: switch to n_d mode.\n");
+ }
+
+ } else {
+ int p = PTS_MODE_SWITCHING_RECOVERY_THREASHOLD;
+
+ hevc->pts_mode_recovery_count++;
+ if (hevc->pts_mode_recovery_count > p) {
+ hevc->pts_mode_switching_count = 0;
+ hevc->pts_mode_recovery_count = 0;
+ }
+ }
+ }
+
+ 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 (get_double_write_mode(hevc) & 0x10) {
+ /* double write only */
+ vf->compBodyAddr = 0;
+ vf->compHeadAddr = 0;
+ } else {
+
+ if (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;
+ }
+
+ /*head adr*/
+ vf->canvas0Addr = vf->canvas1Addr = 0;
+ }
+ if (get_double_write_mode(hevc)) {
+ vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD;
+ vf->type |= VIDTYPE_VIU_NV21;
+ if (get_double_write_mode(hevc) == 3)
+ vf->type |= VIDTYPE_COMPRESS;
+ if (mmu_enable)
+ vf->type |= VIDTYPE_SCATTER;
+#ifdef MULTI_INSTANCE_SUPPORT
+ 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
+#endif
+ vf->canvas0Addr = vf->canvas1Addr
+ = spec2canvas(pic);
+ } else {
+ vf->canvas0Addr = vf->canvas1Addr = 0;
+ vf->type = VIDTYPE_COMPRESS | VIDTYPE_VIU_FIELD;
+ if (mmu_enable)
+ vf->type |= VIDTYPE_SCATTER;
+
+ }
+ vf->compWidth = pic->width;
+ vf->compHeight = pic->height;
+ update_vf_memhandle(hevc, vf, pic->index);
+ switch (hevc->bit_depth_luma) {
+ case 9:
+ vf->bitdepth = BITDEPTH_Y9;
+ break;
+ case 10:
+ vf->bitdepth = BITDEPTH_Y10;
+ break;
+ default:
+ vf->bitdepth = BITDEPTH_Y8;
+ break;
+ }
+ switch (hevc->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 (hevc->mem_saving_mode == 1)
+ vf->bitdepth |= BITDEPTH_SAVING_MODE;
+#else
+ vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD;
+ vf->type |= VIDTYPE_VIU_NV21;
+ vf->canvas0Addr = vf->canvas1Addr = spec2canvas(pic);
+#endif
+ set_frame_info(hevc, vf);
+ /* 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); */
+ if ((get_double_write_mode(hevc) == 2) ||
+ (get_double_write_mode(hevc) == 3)) {
+ vf->width = pic->width/4;
+ vf->height = pic->height/4;
+ } else {
+ 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;
+ }
+
+ /*
+ * !!! to do ...
+ * need move below code to get_new_pic(),
+ * hevc->xxx can only be used by current decoded pic
+ */
+ if (hevc->param.p.conformance_window_flag &&
+ (get_dbg_flag(hevc) &
+ H265_DEBUG_IGNORE_CONFORMANCE_WINDOW) == 0) {
+ unsigned SubWidthC, SubHeightC;
+
+ switch (hevc->param.p.chroma_format_idc) {
+ case 1:
+ SubWidthC = 2;
+ SubHeightC = 2;
+ break;
+ case 2:
+ SubWidthC = 2;
+ SubHeightC = 1;
+ break;
+ default:
+ SubWidthC = 1;
+ SubHeightC = 1;
+ break;
+ }
+ vf->width -= SubWidthC *
+ (hevc->param.p.conf_win_left_offset +
+ hevc->param.p.conf_win_right_offset);
+ vf->height -= SubHeightC *
+ (hevc->param.p.conf_win_top_offset +
+ hevc->param.p.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\n",
+ hevc->param.p.chroma_format_idc,
+ hevc->param.p.conf_win_left_offset,
+ hevc->param.p.conf_win_right_offset,
+ hevc->param.p.conf_win_top_offset,
+ hevc->param.p.conf_win_bottom_offset,
+ vf->width, vf->height);
+ }
+
+#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
+ | VIDTYPE_VIU_NV21;
+ vf2->type = VIDTYPE_INTERLACE_BOTTOM
+ | VIDTYPE_VIU_NV21;
+ } else {
+ vf->type = VIDTYPE_INTERLACE_BOTTOM
+ | VIDTYPE_VIU_NV21;
+ vf2->type = VIDTYPE_INTERLACE_TOP
+ | VIDTYPE_VIU_NV21;
+ }
+ kfifo_put(&hevc->display_q,
+ (const struct vframe_s *)vf);
+ kfifo_put(&hevc->display_q,
+ (const struct vframe_s *)vf2);
+ } 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
+ | VIDTYPE_VIU_NV21;
+ vf2->type = VIDTYPE_INTERLACE_BOTTOM
+ | VIDTYPE_VIU_NV21;
+ vf3->type = VIDTYPE_INTERLACE_TOP
+ | VIDTYPE_VIU_NV21;
+ } else {
+ vf->type = VIDTYPE_INTERLACE_BOTTOM
+ | VIDTYPE_VIU_NV21;
+ vf2->type = VIDTYPE_INTERLACE_TOP
+ | VIDTYPE_VIU_NV21;
+ vf3->type = VIDTYPE_INTERLACE_BOTTOM
+ | VIDTYPE_VIU_NV21;
+ }
+ kfifo_put(&hevc->display_q,
+ (const struct vframe_s *)vf);
+ kfifo_put(&hevc->display_q,
+ (const struct vframe_s *)vf2);
+ kfifo_put(&hevc->display_q,
+ (const struct vframe_s *)vf3);
+
+ } 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));
+
+ /* 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
+ | VIDTYPE_VIU_NV21 | VIDTYPE_VIU_FIELD;
+ process_pending_vframe(hevc,
+ hevc->pre_bot_pic, 0);
+ } else {
+ vf->type = VIDTYPE_INTERLACE_BOTTOM |
+ VIDTYPE_VIU_NV21 | VIDTYPE_VIU_FIELD;
+ vf->index = (pic->index << 8) | 0xff;
+ process_pending_vframe(hevc,
+ hevc->pre_top_pic, 1);
+ }
+
+ /**/
+ 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 |
+ VIDTYPE_VIU_NV21 | VIDTYPE_VIU_FIELD;
+ else {
+ vf->type = VIDTYPE_INTERLACE_BOTTOM |
+ VIDTYPE_VIU_NV21 | VIDTYPE_VIU_FIELD;
+ vf->index = (pic->index << 8) | 0xff;
+ }
+ kfifo_put(&hevc->pending_q,
+ (const struct vframe_s *)vf);
+
+ /**/
+ 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 |
+ VIDTYPE_VIU_NV21 | 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
+ | VIDTYPE_VIU_NV21
+ | VIDTYPE_VIU_FIELD;
+ process_pending_vframe(hevc, pic, 0);
+ hevc->pre_bot_pic = pic;
+ break;
+ }
+ kfifo_put(&hevc->display_q,
+ (const struct vframe_s *)vf);
+ }
+#else
+ vf->type_original = vf->type;
+ pic->vf_ref = 1;
+ kfifo_put(&hevc->display_q, (const struct vframe_s *)vf);
+#endif
+
+ vf_notify_receiver(hevc->provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
+ }
+
+ 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 hevc_shift_byte_count;
+ unsigned hevc_stream_start_addr;
+ unsigned hevc_stream_end_addr;
+ unsigned hevc_stream_rd_ptr;
+ unsigned hevc_stream_wr_ptr;
+ unsigned hevc_stream_control;
+ unsigned hevc_stream_fifo_ctl;
+ unsigned hevc_stream_buf_size;
+ 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();
+ ret = 0;
+ /* reset */
+ WRITE_MPEG_REG(PARSER_VIDEO_RP, READ_VREG(HEVC_STREAM_RD_PTR));
+ SET_MPEG_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_MBOX1_CLR_REG, 1);
+ /* enable mailbox interrupt */
+ WRITE_VREG(HEVC_ASSIST_MBOX1_MASK, 1);
+ /* disable PSCALE for hardware sharing */
+ WRITE_VREG(HEVC_PSCALE_CTRL, 0);
+
+ CLEAR_MPEG_REG_MASK(PARSER_ES_CONTROL, ES_VID_MAN_RD_PTR);
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_UCODE)
+ WRITE_VREG(DEBUG_REG1, 0x1);
+ else
+ 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_AM_VDEC_DV
+ 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, decode_stop_pos);
+
+ /* 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=%x\n", __func__,
+ READ_VREG(HEVC_SHIFT_BYTE_COUNT));
+
+ 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 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);
+ 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);
+ 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");
+ }
+ }
+}
+
+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;
+#ifdef CONFIG_AM_VDEC_DV
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+#endif
+ if (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) {
+ 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_AM_VDEC_DV
+ 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 (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;
+ }
+
+ 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
+ if ((dec_status == HEVC_DECPIC_DATA_DONE ||
+ dec_status == HEVC_FIND_NEXT_PIC_NAL ||
+ dec_status == HEVC_FIND_NEXT_DVEL_NAL)
+ && (hevc->m_ins_flag)) {
+ if (hevc->chunk) {
+ hevc->cur_pic->pts = hevc->chunk->pts;
+ hevc->cur_pic->pts64 = hevc->chunk->pts64;
+ } else if (pts_lookup_offset_us64
+ (PTS_TYPE_VIDEO,
+ hevc->cur_pic->stream_offset,
+ &hevc->cur_pic->pts,
+ 0,
+ &hevc->cur_pic->pts64) != 0) {
+#ifdef DEBUG_PTS
+ hevc->pts_missed++;
+#endif
+ hevc->cur_pic->pts = 0;
+ hevc->cur_pic->pts64 = 0;
+ }
+ }
+
+ if ((dec_status == HEVC_SEARCH_BUFEMPTY) ||
+ (dec_status == HEVC_DECODE_BUFEMPTY) ||
+ (dec_status == HEVC_NAL_DECODE_DONE)
+ ) {
+ if (hevc->m_ins_flag) {
+#if 1
+ if (!vdec_frame_based(hw_to_vdec(hevc))) {
+ hevc->dec_result = DEC_RESULT_AGAIN;
+ amhevc_stop();
+ } else
+ hevc->dec_result = DEC_RESULT_GET_DATA;
+#else
+ if (!vdec_frame_based(hw_to_vdec(hevc)))
+ hevc->dec_result = DEC_RESULT_AGAIN;
+ else
+ hevc->dec_result = DEC_RESULT_DONE;
+ amhevc_stop();
+#endif
+ reset_process_time(hevc);
+ schedule_work(&hevc->work);
+ }
+
+ return IRQ_HANDLED;
+ } else if (dec_status == HEVC_DECPIC_DATA_DONE) {
+ if (hevc->m_ins_flag) {
+ hevc->dec_result = DEC_RESULT_DONE;
+ amhevc_stop();
+
+ reset_process_time(hevc);
+ schedule_work(&hevc->work);
+ }
+
+ return IRQ_HANDLED;
+#ifdef CONFIG_AM_VDEC_DV
+ } else if (dec_status == HEVC_FIND_NEXT_PIC_NAL ||
+ dec_status == HEVC_FIND_NEXT_DVEL_NAL) {
+ if (hevc->m_ins_flag) {
+ unsigned next_parser_type =
+ READ_HREG(CUR_NAL_UNIT_TYPE);
+ 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_el->start_parser_type =
+ next_parser_type;
+ } 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_ba->start_parser_type =
+ next_parser_type;
+ } else {
+ hevc->switch_dvlayer_flag = 0;
+ hevc->start_parser_type =
+ next_parser_type;
+ }
+ hevc->dec_result = DEC_RESULT_DONE;
+ amhevc_stop();
+ reset_process_time(hevc);
+ if (READ_VREG(HEVC_AUX_DATA_SIZE) != 0) {
+ dma_sync_single_for_cpu(
+ amports_get_dma_device(),
+ hevc->aux_phy_addr,
+ hevc->prefix_aux_size + hevc->suffix_aux_size,
+ DMA_FROM_DEVICE);
+ if (get_dbg_flag(hevc) &
+ H265_DEBUG_BUFMGR_MORE)
+ dump_aux_buf(hevc);
+ if (hevc->cur_pic)
+ set_aux_data(hevc, hevc->cur_pic, 0);
+ }
+
+ schedule_work(&hevc->work);
+ }
+
+ return IRQ_HANDLED;
+#endif
+ } else if (dec_status == HEVC_DECODE_TIMEOUT) {
+ if (vdec_frame_based(hw_to_vdec(hevc)) ||
+ (READ_VREG(HEVC_STREAM_LEVEL) > 0x200)) {
+ if ((get_dbg_flag(hevc)
+ & H265_DEBUG_DIS_LOC_ERROR_PROC)) {
+ hevc_print(hevc, 0,
+ "%s decoding error, level 0x%x\n",
+ __func__, READ_VREG(HEVC_STREAM_LEVEL));
+ goto send_again;
+ }
+ amhevc_stop();
+ hevc_print(hevc, PRINT_FLAG_VDEC_STATUS,
+ "%s %s\n", __func__,
+ (dec_status == HEVC_SEARCH_BUFEMPTY) ?
+ "HEVC_SEARCH_BUFEMPTY" :
+ (dec_status == HEVC_DECODE_BUFEMPTY) ?
+ "HEVC_DECODE_BUFEMPTY" : "HEVC_DECODE_TIMEOUT");
+ hevc->dec_result = DEC_RESULT_DONE;
+
+ reset_process_time(hevc);
+ schedule_work(&hevc->work);
+ } else {
+ /* WRITE_VREG(dec_status_REG, H264_ACTION_INIT); */
+ hevc_print(hevc, PRINT_FLAG_VDEC_STATUS,
+ "%s DEC_RESULT_AGAIN\n", __func__);
+send_again:
+ hevc->dec_result = DEC_RESULT_AGAIN;
+ reset_process_time(hevc);
+ schedule_work(&hevc->work);
+ }
+ return IRQ_HANDLED;
+ }
+
+#endif
+
+ if (dec_status == HEVC_SEI_DAT) {
+ 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;
+ 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;
+ hevc_print(hevc, 0, "get NAL_UNIT_EOS, flush output\n");
+ 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);
+ WRITE_VREG(HEVC_DEC_STATUS_REG, HEVC_DISCARD_NAL);
+ /* Interrupt Amrisc to excute */
+ WRITE_VREG(HEVC_MCPU_INTR_REQ, AMRISC_MAIN_REQ);
+ return IRQ_HANDLED;
+ }
+
+ if (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) {
+ 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_AM_VDEC_DV
+ 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);
+
+ } else if (dec_status == HEVC_SLICE_SEGMENT_DONE) {
+ 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");
+ } else if (hevc->wait_buf == 0) {
+ u32 vui_time_scale;
+ u32 vui_num_units_in_tick;
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_SEND_PARAM_WITH_REG)
+ get_rpm_param(&hevc->param);
+ else {
+ dma_sync_single_for_cpu(
+ amports_get_dma_device(),
+ hevc->rpm_phy_addr,
+ RPM_BUF_SIZE,
+ DMA_FROM_DEVICE);
+
+ 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];
+ }
+ }
+ }
+ 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 (
+#ifdef CONFIG_AM_VDEC_DV
+ vdec->master == NULL &&
+ vdec->slave == NULL &&
+#endif
+ READ_VREG(HEVC_AUX_DATA_SIZE) != 0
+ ) {
+ dma_sync_single_for_cpu(
+ amports_get_dma_device(),
+ hevc->aux_phy_addr,
+ hevc->prefix_aux_size + hevc->suffix_aux_size,
+ DMA_FROM_DEVICE);
+ 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)) {
+ 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)) {
+ 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 ((vui_time_scale != 0)
+ && (vui_num_units_in_tick != 0)) {
+ hevc->frame_dur =
+ div_u64(96000ULL *
+ vui_num_units_in_tick,
+ vui_time_scale);
+ hevc->get_frame_dur = true;
+ }
+
+ 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 (hevc->pic_w == 0 || hevc->pic_h == 0
+ || hevc->lcu_size == 0) {
+ /* skip search next start code */
+ 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 {
+ hevc->sps_num_reorder_pics_0 =
+ hevc->param.p.sps_num_reorder_pics_0;
+ hevc->pic_list_init_flag = 1;
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (hevc->m_ins_flag) {
+ reset_process_time(hevc);
+ schedule_work(&hevc->work);
+ } else
+#endif
+ up(&hevc->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)
+ ;
+ else if (ret == 0) {
+ if ((hevc->new_pic) && (hevc->cur_pic)) {
+ hevc->cur_pic->stream_offset =
+ READ_VREG(HEVC_SHIFT_BYTE_COUNT);
+ }
+
+ 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;
+#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->dec_result = DEC_RESULT_DONE;
+ amhevc_stop();
+ reset_process_time(hevc);
+ schedule_work(&hevc->work);
+#endif
+ } else {
+ /* skip, search next start code */
+ 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);
+ }
+
+ }
+
+ if (mmu_enable) {
+ if (hevc->last_put_idx_a >= 0
+ && hevc->last_put_idx_a < MAX_REF_PIC_NUM) {
+ int i = hevc->last_put_idx_a;
+ struct PIC_s *pic = hevc->m_PIC[i];
+
+ /*free not used buffers.*/
+ if (pic &&
+ pic->output_mark == 0 && pic->referenced == 0
+ && pic->output_ready == 0
+ && pic->used_by_display == 0
+ && (pic->index != -1)) {
+ decoder_mmu_box_free_idx(hevc->mmu_box, i);
+ hevc->last_put_idx_a = -1;
+ /* hevc_print(hevc, 0, "release pic buf %x\n",i);*/
+ }
+ }
+ if (hevc->last_put_idx_b >= 0
+ && hevc->last_put_idx_b < MAX_REF_PIC_NUM) {
+ int i = hevc->last_put_idx_b;
+ struct PIC_s *pic = hevc->m_PIC[i];
+
+ /*free not used buffers.*/
+ if (pic &&
+ pic->output_mark == 0 && pic->referenced == 0
+ && pic->output_ready == 0
+ && pic->used_by_display == 0
+ && (pic->index != -1)) {
+ decoder_mmu_box_free_idx(hevc->mmu_box, i);
+ hevc->last_put_idx_b = -1;
+ }
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+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;
+
+ dec_status = READ_VREG(HEVC_DEC_STATUS_REG);
+ if (hevc->init_flag == 0)
+ return IRQ_HANDLED;
+ hevc->dec_status = dec_status;
+ if (get_dbg_flag(hevc) & H265_DEBUG_BUFMGR)
+ hevc_print(hevc, 0,
+ "265 isr dec status = 0x%x\n", dec_status);
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_UCODE) {
+ if (READ_HREG(DEBUG_REG1) & 0x10000) {
+ dma_sync_single_for_cpu(
+ amports_get_dma_device(),
+ hevc->lmem_phy_addr,
+ LMEM_BUF_SIZE,
+ DMA_FROM_DEVICE);
+
+ hevc_print(hevc, 0,
+ "LMEM<tag %x>:\n", READ_HREG(DEBUG_REG1));
+
+ if (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");
+ }
+ WRITE_HREG(DEBUG_REG1, 0);
+ } else if (READ_HREG(DEBUG_REG1) != 0) {
+ hevc_print(hevc, 0,
+ "dbg%x: %x\n", READ_HREG(DEBUG_REG1),
+ READ_HREG(DEBUG_REG2));
+ WRITE_HREG(DEBUG_REG1, 0);
+ return IRQ_HANDLED;
+ }
+
+ }
+
+ if (hevc->pic_list_init_flag == 1)
+ return IRQ_HANDLED;
+
+ return IRQ_WAKE_THREAD;
+
+}
+
+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) {
+ timer->expires = jiffies + PUT_INTERVAL;
+ add_timer(&hevc->timer);
+ }
+ return;
+ }
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (hevc->m_ins_flag &&
+ hw_to_vdec(hevc)->next_status ==
+ VDEC_STATUS_DISCONNECTED) {
+ hevc->dec_result = DEC_RESULT_DONE;
+ schedule_work(&hevc->work);
+ hevc_print(hevc,
+ 0, "vdec requested to be disconnected\n");
+ return;
+ }
+
+ if (hevc->m_ins_flag) {
+ if ((input_frame_based(hw_to_vdec(hevc)) ||
+ (READ_VREG(HEVC_STREAM_LEVEL) > 0x200)) &&
+ ((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);
+ }
+ hevc->last_lcu_idx = current_lcu_idx;
+ } else
+ 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_MBOX1_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_MBOX1_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 (decode_stop_pos != decode_stop_pos_pre) {
+ WRITE_VREG(DECODE_STOP_POS, decode_stop_pos);
+ decode_stop_pos_pre = decode_stop_pos;
+ }
+
+ 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_MBOX1_IRQ_REG, 0x1);
+ debug &= ~H265_DEBUG_TRIG_SLICE_SEGMENT_PROC;
+ }
+ 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;
+ }
+ if (get_dbg_flag(hevc) & H265_DEBUG_ERROR_TRIG) {
+ WRITE_VREG(DECODE_STOP_POS, 1);
+ debug &= ~H265_DEBUG_ERROR_TRIG;
+ }
+#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) {
+ if (rval != 0) {
+ WRITE_VREG(radr, rval);
+ hevc_print(hevc, 0,
+ "WRITE_VREG(%x,%x)\n", radr, rval);
+ } else
+ hevc_print(hevc, 0,
+ "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_type() >= 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)) {
+ 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;
+ }
+
+
+ timer->expires = jiffies + PUT_INTERVAL;
+ add_timer(timer);
+}
+
+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(&hevc->h265_sema);
+ if ((hevc->init_flag != 0) && (hevc->pic_list_init_flag == 1)) {
+ /*USE_BUF_BLOCK*/
+ init_buf_list(hevc);
+ /**/
+ 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_MBOX1_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
+ up(&hevc->h265_uninit_done_sema);
+#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_status *vstatus)
+#else
+int vh265_dec_status(struct vdec_status *vstatus)
+#endif
+{
+ struct hevc_state_s *hevc = &gHevc;
+
+ vstatus->width = hevc->frame_width;
+ vstatus->height = hevc->frame_height;
+ if (hevc->frame_dur != 0)
+ vstatus->fps = 96000 / hevc->frame_dur;
+ else
+ vstatus->fps = -1;
+ vstatus->error_count = 0;
+ vstatus->status = hevc->stat | hevc->fatal_error;
+ 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
+
+static void config_decode_mode(struct hevc_state_s *hevc)
+{
+#ifdef CONFIG_AM_VDEC_DV
+ struct vdec_s *vdec = hw_to_vdec(hevc);
+#endif
+ if (!hevc->m_ins_flag)
+ WRITE_VREG(HEVC_DECODE_MODE,
+ DECODE_MODE_SINGLE);
+ else if (vdec_frame_based(hw_to_vdec(hevc)))
+ WRITE_VREG(HEVC_DECODE_MODE,
+ DECODE_MODE_MULTI_FRAMEBASE);
+#ifdef CONFIG_AM_VDEC_DV
+ else if (vdec->slave)
+ WRITE_VREG(HEVC_DECODE_MODE,
+ (hevc->start_parser_type << 8)
+ | DECODE_MODE_MULTI_DVBAL);
+ else if (vdec->master)
+ WRITE_VREG(HEVC_DECODE_MODE,
+ (hevc->start_parser_type << 8)
+ | DECODE_MODE_MULTI_DVENL);
+#endif
+ else
+ WRITE_VREG(HEVC_DECODE_MODE,
+ DECODE_MODE_MULTI_STREAMBASE);
+}
+
+static void vh265_prot_init(struct hevc_state_s *hevc)
+{
+ /* 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_MBOX1_CLR_REG, 1);
+
+ /* enable mailbox interrupt */
+ WRITE_VREG(HEVC_ASSIST_MBOX1_MASK, 1);
+
+ /* disable PSCALE for hardware sharing */
+ WRITE_VREG(HEVC_PSCALE_CTRL, 0);
+
+ if (get_dbg_flag(hevc) & H265_DEBUG_UCODE)
+ WRITE_VREG(DEBUG_REG1, 0x1);
+ else
+ WRITE_VREG(DEBUG_REG1, 0x0);
+
+ 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;
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (hevc->m_ins_flag &&
+ hevc->init_flag) {
+ /* do not check vps/sps/pps/i-slice in ucode
+ from the 2nd picture*/
+ ctl_val = 0x2;
+ } else
+#endif
+ 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 */
+ WRITE_VREG(NAL_SEARCH_CTL, ctl_val);
+ }
+ 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_AM_VDEC_DV
+ WRITE_VREG(NAL_SEARCH_CTL,
+ READ_VREG(NAL_SEARCH_CTL) |
+ ((parser_dolby_vision_enable & 0x1) << 20));
+#endif
+ WRITE_VREG(DECODE_STOP_POS, decode_stop_pos);
+
+ config_decode_mode(hevc);
+ config_aux_buf(hevc);
+}
+
+static int vh265_local_init(struct hevc_state_s *hevc)
+{
+ int i;
+ int ret = -1;
+
+#ifdef DEBUG_PTS
+ hevc->pts_missed = 0;
+ hevc->pts_hit = 0;
+#endif
+
+ hevc->last_put_idx_a = -1;
+ hevc->last_put_idx_b = -1;
+ 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;
+ if (HEVC_SIZE < 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;
+ }
+ hevc->frame_dur =
+ (hevc->vh265_amstream_dec_info.rate ==
+ 0) ? 3600 : hevc->vh265_amstream_dec_info.rate;
+ if (hevc->frame_width && hevc->frame_height)
+ hevc->frame_ar = hevc->frame_height * 0x100 / hevc->frame_width;
+ hevc->error_watchdog_count = 0;
+ hevc->sei_present_flag = 0;
+ pts_unstable = ((unsigned long)hevc->vh265_amstream_dec_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);
+
+
+ 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 size = -1;
+ char *buf = vmalloc(0x1000 * 16);
+ if (IS_ERR_OR_NULL(buf))
+ return -ENOMEM;
+
+ init_timer(&hevc->timer);
+
+ hevc->stat |= STAT_TIMER_INIT;
+ if (vh265_local_init(hevc) < 0) {
+ vfree(buf);
+ return -EBUSY;
+ }
+
+#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;
+
+ /*add_timer(&hevc->timer);
+
+ hevc->stat |= STAT_TIMER_ARM;*/
+
+ INIT_WORK(&hevc->work, vh265_work);
+ vfree(buf);
+ return 0;
+ }
+#endif
+ amhevc_enable();
+
+ if (mmu_enable && (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXL)) {
+ size = get_firmware_data(VIDEO_DEC_HEVC_MMU, buf);
+ hevc_print(hevc, 0, "vh265 mmu ucode loaded!\n");
+ } else
+ size = get_firmware_data(VIDEO_DEC_HEVC, buf);
+
+ if (size < 0) {
+ pr_err("get firmware fail.\n");
+ vfree(buf);
+ return -1;
+ }
+
+ if (amhevc_loadmc_ex(VFORMAT_HEVC, NULL, buf) < 0) {
+ amhevc_disable();
+ vfree(buf);
+ return -EBUSY;
+ }
+
+ vfree(buf);
+
+ hevc->stat |= STAT_MC_LOAD;
+
+ /* enable AMRISC side protocol */
+ vh265_prot_init(hevc);
+
+ if (vdec_request_threaded_irq(VDEC_IRQ_1, 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);
+ vf_notify_receiver(hevc->provider_name, VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)((unsigned long)hevc->frame_dur));
+#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);
+ vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)((unsigned long)hevc->frame_dur));
+#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) {
+ if (h265_task == NULL) {
+ sema_init(&hevc->h265_sema, 1);
+#ifdef USE_UNINIT_SEMA
+ sema_init(
+ &hevc->h265_uninit_done_sema, 0);
+#endif
+ h265_task =
+ kthread_run(h265_task_handle, hevc,
+ "kthread_h265");
+ }
+ }
+ /* hevc->stat |= STAT_KTHREAD; */
+
+ 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,
+ READ_VREG(HEVCD_IPP_DYNCLKGATE_CONFIG) |
+ 0xffffffff); /* 31:0 */
+ WRITE_VREG(HEVCD_MCRCC_CTL1, READ_VREG(HEVCD_MCRCC_CTL1) |
+ (1 << 3)); /* 3 */
+ }
+
+ amhevc_start();
+
+ hevc->stat |= STAT_VDEC_RUN;
+#ifndef MULTI_INSTANCE_SUPPORT
+ set_vdec_func(&vh265_dec_status);
+#endif
+ hevc->init_flag = 1;
+ if (mmu_enable)
+ error_handle_threshold = 300;
+ else
+ error_handle_threshold = 30;
+ /* pr_info("%d, vh265_init, RP=0x%x\n",
+ __LINE__, READ_VREG(HEVC_STREAM_RD_PTR)); */
+
+ return 0;
+}
+
+static int vh265_stop(struct hevc_state_s *hevc)
+{
+
+ hevc->init_flag = 0;
+
+ 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) {
+ WRITE_VREG(HEVC_ASSIST_MBOX1_MASK, 0);
+ vdec_free_irq(VDEC_IRQ_1, (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) {
+ vf_notify_receiver(hevc->provider_name,
+ VFRAME_EVENT_PROVIDER_FR_END_HINT, NULL);
+
+ vf_unreg_provider(&vh265_vf_prov);
+ hevc->stat &= ~STAT_VF_HOOK;
+ }
+
+ hevc_local_uninit(hevc);
+
+ if (use_cma) {
+#ifdef USE_UNINIT_SEMA
+ int ret;
+#endif
+ hevc->uninit_list = 1;
+ up(&hevc->h265_sema);
+#ifdef USE_UNINIT_SEMA
+ ret = down_interruptible(
+ &hevc->h265_uninit_done_sema);
+#else
+ while (hevc->uninit_list) /* wait uninit complete */
+ msleep(20);
+#endif
+
+ }
+ uninit_mmu_buffers(hevc);
+ amhevc_disable();
+
+ return 0;
+}
+
+#ifdef MULTI_INSTANCE_SUPPORT
+static void reset_process_time(struct hevc_state_s *hevc)
+{
+ if (hevc->start_process_time) {
+ unsigned 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 timeout_process(struct hevc_state_s *hevc)
+{
+ hevc->timeout_num++;
+ amhevc_stop();
+ hevc_print(hevc,
+ 0, "%s decoder timeout\n", __func__);
+
+ hevc->dec_result = DEC_RESULT_DONE;
+ reset_process_time(hevc);
+ schedule_work(&hevc->work);
+}
+
+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;
+ /*return 1 if pic_list is not initialized yet*/
+ if (hevc->pic_list_init_flag != 3)
+ return 1;
+
+ for (i = 0; i < MAX_REF_PIC_NUM; i++) {
+ pic = hevc->m_PIC[i];
+ if (pic == NULL || pic->index == -1)
+ continue;
+ if ((pic->used_by_display)
+ && ((READ_VCBUS_REG(AFBC_BODY_BADDR) << 4) !=
+ pic->mc_y_adr))
+ pic->used_by_display = 0;
+ if (pic->output_mark == 0 && pic->referenced == 0
+ && pic->output_ready == 0
+ && pic->used_by_display == 0) {
+ if (new_pic) {
+ if (pic->POC < new_pic->POC)
+ new_pic = pic;
+ } else
+ new_pic = pic;
+ }
+ }
+ return (new_pic != NULL) ? 1 : 0;
+}
+
+static int vmh265_stop(struct hevc_state_s *hevc)
+{
+ hevc->init_flag = 0;
+
+ if (hevc->stat & STAT_TIMER_ARM) {
+ del_timer_sync(&hevc->timer);
+ hevc->stat &= ~STAT_TIMER_ARM;
+ }
+
+ if (hevc->stat & STAT_VF_HOOK) {
+ vf_notify_receiver(hevc->provider_name,
+ VFRAME_EVENT_PROVIDER_FR_END_HINT, NULL);
+
+ vf_unreg_provider(&vh265_vf_prov);
+ hevc->stat &= ~STAT_VF_HOOK;
+ }
+
+ hevc_local_uninit(hevc);
+
+ if (use_cma) {
+#ifdef USE_UNINIT_SEMA
+ int ret;
+#endif
+ hevc->uninit_list = 1;
+ reset_process_time(hevc);
+ schedule_work(&hevc->work);
+#ifdef USE_UNINIT_SEMA
+ ret = down_interruptible(
+ &hevc->h265_uninit_done_sema);
+#else
+ while (hevc->uninit_list) /* wait uninit complete */
+ msleep(20);
+#endif
+ }
+ cancel_work_sync(&hevc->work);
+ uninit_mmu_buffers(hevc);
+ return 0;
+}
+
+static unsigned int start_decode_buf_level; /* = 0x80000;*/
+
+static unsigned char get_data_check_sum
+ (struct hevc_state_s *hevc, int size)
+{
+ int jj;
+ int sum = 0;
+ u8 *data = ((u8 *)hevc->chunk->block->start_virt) +
+ hevc->chunk->offset;
+ for (jj = 0; jj < size; jj++)
+ sum += data[jj];
+ return sum;
+}
+
+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);
+ /* finished decoding one frame or error,
+ * notify vdec core to switch context
+ */
+ if ((hevc->init_flag != 0) && (hevc->pic_list_init_flag == 1)) {
+ /*USE_BUF_BLOCK*/
+ init_buf_list(hevc);
+ /**/
+ 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");
+
+ start_process_time(hevc);
+ WRITE_VREG(HEVC_ASSIST_MBOX1_IRQ_REG, 0x1);
+ return;
+ }
+
+ 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
+ up(&hevc->h265_uninit_done_sema);
+#endif
+ return;
+ }
+
+ if ((hevc->dec_result == DEC_RESULT_GET_DATA) ||
+ (hevc->dec_result == DEC_RESULT_GET_DATA_RETRY)) {
+ 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));
+ vdec_vframe_dirty(vdec, hevc->chunk);
+ vdec_clean_input(vdec);
+ }
+
+ /*if (is_new_pic_available(hevc)) {*/
+ if (run_ready(vdec)) {
+ int r;
+ 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");
+
+ 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) &&
+ input_frame_based(vdec)) {
+ int jj;
+ u8 *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");
+ }
+ }
+
+ WRITE_VREG(HEVC_DECODE_SIZE, r);
+
+ 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");
+ */
+
+ schedule_work(&hevc->work);
+ }
+ return;
+ } else if (hevc->dec_result == DEC_RESULT_DONE) {
+ /* if (!hevc->ctx_valid)
+ hevc->ctx_valid = 1; */
+ hevc_print(hevc, PRINT_FLAG_VDEC_STATUS,
+ "%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));
+#ifdef CONFIG_AM_VDEC_DV
+#if 1
+ if (vdec->slave) {
+ if (dv_debug & 0x1)
+ vdec_set_flag(vdec->slave, 0);
+ else
+ vdec_set_flag(vdec->slave,
+ VDEC_FLAG_INPUT_KEEP_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
+ vdec_vframe_dirty(hw_to_vdec(hevc), hevc->chunk);
+ } else {
+ 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->stat & STAT_TIMER_ARM) {
+ del_timer_sync(&hevc->timer);
+ hevc->stat &= ~STAT_TIMER_ARM;
+ }
+ /* mark itself has all HW resource released and input released */
+ vdec_set_status(hw_to_vdec(hevc), VDEC_STATUS_CONNECTED);
+
+#ifdef CONFIG_AM_VDEC_DV
+ 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 (hevc->vdec_cb)
+ hevc->vdec_cb(hw_to_vdec(hevc), hevc->vdec_cb_arg);
+}
+
+static int vh265_hw_ctx_restore(struct hevc_state_s *hevc)
+{
+ /* new to do ... */
+ vh265_prot_init(hevc);
+ return 0;
+}
+
+static bool run_ready(struct vdec_s *vdec)
+{
+ struct hevc_state_s *hevc =
+ (struct hevc_state_s *)vdec->private;
+
+ /*hevc_print(hevc,
+ PRINT_FLAG_VDEC_DETAIL, "%s\r\n", __func__);
+ */
+ if ((!vdec_frame_based(vdec)) && (start_decode_buf_level > 0)) {
+ u32 rp, wp;
+ u32 level;
+
+ rp = READ_MPEG_REG(PARSER_VIDEO_RP);
+ wp = READ_MPEG_REG(PARSER_VIDEO_WP);
+
+ if (wp < rp)
+ level = vdec->input.size + wp - rp;
+ else
+ level = wp - rp;
+
+ if (level < start_decode_buf_level) {
+ hevc_print(hevc, 0,
+ "level %d not run_ready\n", level);
+ return false;
+ }
+ } else if (vdec_frame_based(vdec)) {
+ if (!vdec_input_next_input_chunk(&vdec->input))
+ return false;
+ }
+
+ return is_new_pic_available(hevc);
+}
+
+static void reset_dec_hw(struct vdec_s *vdec)
+{
+ if (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
+ */
+ 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);
+}
+
+static void run(struct vdec_s *vdec,
+ void (*callback)(struct vdec_s *, void *), void *arg)
+{
+ struct hevc_state_s *hevc =
+ (struct hevc_state_s *)vdec->private;
+ int r;
+
+ hevc->vdec_cb_arg = arg;
+ hevc->vdec_cb = callback;
+
+ reset_dec_hw(vdec);
+
+ r = vdec_prepare_input(vdec, &hevc->chunk);
+ if (r < 0) {
+ hevc->dec_result = DEC_RESULT_AGAIN;
+
+ hevc_print(hevc, PRINT_FLAG_VDEC_DETAIL,
+ "ammvdec_vh265: Insufficient data\n");
+
+ schedule_work(&hevc->work);
+ return;
+ }
+
+ hevc->dec_result = DEC_RESULT_NONE;
+
+ hevc_print(hevc, PRINT_FLAG_VDEC_STATUS,
+ "%s: size 0x%x sum 0x%x (%x %x %x)\n",
+ __func__, r,
+ (vdec_frame_based(vdec) &&
+ (get_dbg_flag(hevc) & PRINT_FLAG_VDEC_STATUS)) ?
+ get_data_check_sum(hevc, r) : 0,
+ READ_VREG(HEVC_STREAM_LEVEL),
+ READ_VREG(HEVC_STREAM_WR_PTR),
+ READ_VREG(HEVC_STREAM_RD_PTR));
+ if ((get_dbg_flag(hevc) & PRINT_FRAMEBASE_DATA) &&
+ input_frame_based(vdec)) {
+ int jj;
+ u8 *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->init_flag == 0) {
+ if (amhevc_vdec_loadmc_ex(vdec, "vh265_mc") < 0) {
+ amhevc_disable();
+ hevc_print(hevc, 0,
+ "%s: Error amvdec_loadmc fail\n", __func__);
+ return;
+ }
+ }
+ if (vh265_hw_ctx_restore(hevc) < 0) {
+ 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);
+
+ 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);
+
+ start_process_time(hevc);
+ add_timer(&hevc->timer);
+ hevc->stat |= STAT_TIMER_ARM;
+ amhevc_start();
+
+}
+
+static void reset(struct vdec_s *vdec)
+{
+
+ struct hevc_state_s *hevc =
+ (struct hevc_state_s *)vdec->private;
+
+ hevc_print(hevc,
+ PRINT_FLAG_VDEC_DETAIL, "%s\r\n", __func__);
+
+}
+
+static irqreturn_t vh265_irq_cb(struct vdec_s *vdec)
+{
+ 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)
+{
+ 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
+ struct hevc_state_s *hevc = &gHevc;
+
+ if (get_dbg_flag(hevc))
+ hevc_print(hevc, 0, "%s\r\n", __func__);
+ mutex_lock(&vh265_mutex);
+
+ if ((get_cpu_type() >= MESON_CPU_MAJOR_ID_GXTVBB) &&
+ (parser_sei_enable & 0x100) == 0)
+ parser_sei_enable = 1;
+ hevc->m_ins_flag = 0;
+ hevc->init_flag = 0;
+ hevc->uninit_list = 0;
+ hevc->fatal_error = 0;
+ hevc->show_frame_num = 0;
+ if (pdata == NULL) {
+ hevc_print(hevc, 0,
+ "\namvdec_h265 memory resource undefined.\n");
+ mutex_unlock(&vh265_mutex);
+ return -EFAULT;
+ }
+#ifndef CONFIG_MULTI_DEC
+ if (get_cpu_type() < MESON_CPU_MAJOR_ID_GXL
+ || double_write_mode == 0x10)
+ mmu_enable = 0;
+ else
+ mmu_enable = 1;
+#endif
+ if (init_mmu_buffers(hevc)) {
+ hevc_print(hevc, 0,
+ "\n 265 mmu init failed!\n");
+ mutex_unlock(&vh265_mutex);
+ return -EFAULT;
+ }
+ hevc->buf_start = pdata->mem_start;
+ hevc->buf_size = pdata->mem_end - pdata->mem_start + 1;
+ /*
+ 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 -- 0x%lx\n",
+ pdata->mem_start, pdata->mem_end + 1);
+ }
+
+ 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;
+#ifdef MULTI_INSTANCE_SUPPORT
+ pdata->private = hevc;
+ pdata->dec_status = vh265_dec_status;
+ 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);
+ uninit_mmu_buffers(hevc);
+ 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
+
+ mutex_unlock(&vh265_mutex);
+
+ return 0;
+}
+/****************************************/
+
+static struct platform_driver amvdec_h265_driver = {
+ .probe = amvdec_h265_probe,
+ .remove = amvdec_h265_remove,
+#ifdef CONFIG_PM
+ .suspend = amhevc_suspend,
+ .resume = amhevc_resume,
+#endif
+ .driver = {
+ .name = DRIVER_NAME,
+ }
+};
+
+#ifdef MULTI_INSTANCE_SUPPORT
+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;
+#ifdef CONFIG_MULTI_DEC
+ int config_val;
+#endif
+ 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);
+ if (hevc == NULL) {
+ pr_info("\nammvdec_h265 device data allocation failed\n");
+ return -ENOMEM;
+ }
+ pdata->private = hevc;
+ pdata->dec_status = vh265_dec_status;
+ /* pdata->set_trickmode = 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->id = pdev->id;
+ hevc->index = pdev->id;
+
+ if (pdata->use_vfm_path)
+ snprintf(pdata->vf_provider_name,
+ VDEC_PROVIDER_NAME_SIZE,
+ VFM_DEC_PROVIDER_NAME);
+#ifdef CONFIG_AM_VDEC_DV
+ 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);
+ hevc->dolby_enhance_flag = pdata->master ? 1 : 0;
+ }
+#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 (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);
+ return -EFAULT;
+ }
+#if 0
+ hevc->buf_start = pdata->mem_start;
+ hevc->buf_size = pdata->mem_end - pdata->mem_start + 1;
+#else
+
+ if (decoder_bmmu_box_alloc_idx_wait(
+ hevc->bmmu_box,
+ BMMU_WORKSPACE_ID,
+ work_buf_size,
+ -1,
+ -1,
+ BMMU_ALLOC_FLAGS_WAITCLEAR) < 0) {
+ hevc_print(hevc, 0,
+ "workbuf alloc failed, request buf size 0x%lx\n",
+ work_buf_size);
+ uninit_mmu_buffers(hevc);
+ devm_kfree(&pdev->dev, (void *)hevc);
+ return -ENOMEM;
+ }
+ hevc->buf_start = decoder_bmmu_box_get_phy_addr(
+ hevc->bmmu_box,
+ BMMU_WORKSPACE_ID);
+ hevc->buf_size = work_buf_size;
+#endif
+ if ((get_cpu_type() >= MESON_CPU_MAJOR_ID_GXTVBB) &&
+ (parser_sei_enable & 0x100) == 0)
+ parser_sei_enable = 1;
+ hevc->m_ins_flag = 1;
+ hevc->init_flag = 0;
+ hevc->uninit_list = 0;
+ hevc->fatal_error = 0;
+ hevc->show_frame_num = 0;
+ if (pdata == NULL) {
+ hevc_print(hevc, 0,
+ "\namvdec_h265 memory resource undefined.\n");
+ uninit_mmu_buffers(hevc);
+ devm_kfree(&pdev->dev, (void *)hevc);
+ return -EFAULT;
+ }
+ /*
+ 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 -- 0x%lx\n",
+ hevc->buf_start, hevc->buf_start + hevc->buf_size);
+ }
+
+ if (((get_dbg_flag(hevc) & IGNORE_PARAM_FROM_CONFIG) == 0) &&
+ pdata->config && pdata->config_len) {
+#ifdef CONFIG_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_buf_width",
+ &config_val) == 0)
+ hevc->buf_alloc_width = config_val;
+ else
+ hevc->buf_alloc_width = buf_alloc_width;
+
+ if (get_config_int(pdata->config, "hevc_buf_height",
+ &config_val) == 0)
+ hevc->buf_alloc_height = config_val;
+ else
+ hevc->buf_alloc_height = buf_alloc_height;
+
+ if (get_config_int(pdata->config, "hevc_buf_margin",
+ &config_val) == 0)
+ hevc->dynamic_buf_num_margin = config_val;
+ else
+ hevc->dynamic_buf_num_margin = dynamic_buf_num_margin;
+
+ 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;
+#endif
+ } else {
+ hevc->vh265_amstream_dec_info.width = 0;
+ hevc->vh265_amstream_dec_info.height = 0;
+ hevc->vh265_amstream_dec_info.rate = 30;
+ hevc->buf_alloc_width = buf_alloc_width;
+ hevc->buf_alloc_height = buf_alloc_height;
+ hevc->dynamic_buf_num_margin = dynamic_buf_num_margin;
+ hevc->double_write_mode = double_write_mode;
+ }
+ hevc_print(hevc, 0,
+ "buf_alloc_width=%d\n",
+ hevc->buf_alloc_width);
+ hevc_print(hevc, 0,
+ "buf_alloc_height=%d\n",
+ hevc->buf_alloc_height);
+ 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;
+
+ if (vh265_init(pdata) < 0) {
+ hevc_print(hevc, 0,
+ "\namvdec_h265 init failed.\n");
+ hevc_local_uninit(hevc);
+ uninit_mmu_buffers(hevc);
+ devm_kfree(&pdev->dev, (void *)hevc);
+ return -ENODEV;
+ }
+
+ /*set the max clk for smooth playing...*/
+ hevc_source_changed(VFORMAT_HEVC,
+ 3840, 2160, 60);
+
+ return 0;
+}
+
+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);
+
+ if (get_dbg_flag(hevc))
+ hevc_print(hevc, 0, "%s\r\n", __func__);
+
+ vmh265_stop(hevc);
+
+ /* vdec_source_changed(VFORMAT_H264, 0, 0, 0); */
+
+ vdec_set_status(hw_to_vdec(hevc), VDEC_STATUS_DISCONNECTED);
+
+ return 0;
+}
+
+static struct platform_driver ammvdec_h265_driver = {
+ .probe = ammvdec_h265_probe,
+ .remove = ammvdec_h265_remove,
+#ifdef CONFIG_PM
+ .suspend = amvdec_suspend,
+ .resume = amvdec_resume,
+#endif
+ .driver = {
+ .name = MULTI_DRIVER_NAME,
+ }
+};
+#endif
+
+static struct codec_profile_t amvdec_h265_profile = {
+ .name = "hevc",
+ .profile = ""
+};
+
+static int __init amvdec_h265_driver_init_module(void)
+{
+ 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
+ decode_stop_pos = 0;
+ decode_stop_pos_pre = 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";
+ } else if (is_meson_m8m2_cpu()) {
+ /* m8m2 support 4k */
+ amvdec_h265_profile.profile = "4k";
+ } else if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXBB) {
+ amvdec_h265_profile.profile =
+ "4k, 9bit, 10bit, dwrite, compressed";
+ } else if (get_cpu_type() >= 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);
+
+ 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, "\nradr\n");
+
+module_param(rval, uint, 0664);
+MODULE_PARM_DESC(rval, "\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_h265 step\n");
+
+module_param(decode_stop_pos, uint, 0664);
+MODULE_PARM_DESC(decode_stop_pos, "\n amvdec_h265 decode_stop_pos\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(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(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(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");
+
+module_param(re_config_pic_flag, uint, 0664);
+MODULE_PARM_DESC(re_config_pic_flag, "\n re_config_pic_flag\n");
+
+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");
+
+#ifdef CONFIG_AM_VDEC_DV
+module_param(parser_dolby_vision_enable, uint, 0664);
+MODULE_PARM_DESC(parser_dolby_vision_enable,
+ "\n parser_dolby_vision_enable\n");
+#endif
+
+#ifdef MULTI_INSTANCE_SUPPORT
+module_param(start_decode_buf_level, uint, 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_array(decode_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);
+
+#endif
+#ifdef CONFIG_AM_VDEC_DV
+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");
+#endif
+
+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..8b10541
--- a/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/vmjpeg.c b/drivers/frame_provider/decoder/mjpeg/vmjpeg.c
new file mode 100644
index 0000000..db27382
--- a/dev/null
+++ b/drivers/frame_provider/decoder/mjpeg/vmjpeg.c
@@ -0,0 +1,912 @@
+/*
+ * 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>
+
+#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"
+
+#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 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 void vmjpeg_prot_init(void);
+static void vmjpeg_local_init(void);
+
+static const char vmjpeg_dec_id[] = "vmjpeg-dev";
+
+#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 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 unsigned long buf_start;
+static u32 buf_size;
+static DEFINE_SPINLOCK(lock);
+
+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;
+
+ 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, 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]++;
+
+ kfifo_put(&display_q, (const struct vframe_s *)vf);
+
+ 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);
+#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]++;
+
+ kfifo_put(&display_q, (const struct vframe_s *)vf);
+
+ 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 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 >= 0)
+ && (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);
+ }
+ }
+ 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);
+ }
+ timer->expires = jiffies + PUT_INTERVAL;
+
+ add_timer(timer);
+}
+
+int vmjpeg_dec_status(struct vdec_s *vdec, struct vdec_status *vstatus)
+{
+ vstatus->width = frame_width;
+ vstatus->height = frame_height;
+ if (0 != frame_dur)
+ vstatus->fps = 96000 / frame_dur;
+ else
+ vstatus->fps = 96000;
+ vstatus->error_count = 0;
+ vstatus->status = stat;
+
+ return 0;
+}
+
+/****************************************/
+static void vmjpeg_canvas_init(void)
+{
+ int i;
+ u32 canvas_width, canvas_height;
+ u32 decbuf_size, decbuf_y_size, decbuf_uv_size;
+ u32 disp_addr = 0xffffffff;
+
+ 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;
+ }
+
+ if (is_vpp_postblend()) {
+ struct canvas_s cur_canvas;
+
+ canvas_read((READ_VCBUS_REG(VD1_IF0_CANVAS0) & 0xff),
+ &cur_canvas);
+ disp_addr = (cur_canvas.addr + 7) >> 3;
+ }
+
+ for (i = 0; i < 4; i++) {
+ if (((buf_start + i * decbuf_size + 7) >> 3) == disp_addr) {
+#ifdef NV21
+ canvas_config(index2canvas0(i) & 0xff,
+ buf_start + 4 * decbuf_size,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config((index2canvas0(i) >> 8) & 0xff,
+ buf_start + 4 * decbuf_size +
+ decbuf_y_size, canvas_width,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config(index2canvas1(i) & 0xff,
+ buf_start + 4 * decbuf_size +
+ decbuf_size / 2, canvas_width,
+ canvas_height, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config((index2canvas1(i) >> 8) & 0xff,
+ buf_start + 4 * decbuf_size +
+ 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 + 4 * decbuf_size,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config((index2canvas0(i) >> 8) & 0xff,
+ buf_start + 4 * decbuf_size +
+ decbuf_y_size, canvas_width / 2,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config((index2canvas0(i) >> 16) & 0xff,
+ buf_start + 4 * decbuf_size +
+ 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 + 4 * decbuf_size +
+ decbuf_size / 2, canvas_width,
+ canvas_height, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config((index2canvas1(i) >> 8) & 0xff,
+ buf_start + 4 * decbuf_size +
+ 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 + 4 * decbuf_size +
+ decbuf_y_size + decbuf_uv_size +
+ decbuf_uv_size / 2, canvas_width / 2,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+#endif
+ } else {
+#ifdef NV21
+ canvas_config(index2canvas0(i) & 0xff,
+ buf_start + i * decbuf_size,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config((index2canvas0(i) >> 8) & 0xff,
+ buf_start + i * decbuf_size +
+ decbuf_y_size, canvas_width,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config(index2canvas1(i) & 0xff,
+ buf_start + i * decbuf_size +
+ decbuf_size / 2, canvas_width,
+ canvas_height, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config((index2canvas1(i) >> 8) & 0xff,
+ buf_start + i * decbuf_size +
+ 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 + i * decbuf_size,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config((index2canvas0(i) >> 8) & 0xff,
+ buf_start + i * decbuf_size +
+ decbuf_y_size, canvas_width / 2,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config((index2canvas0(i) >> 16) & 0xff,
+ buf_start + i * decbuf_size +
+ 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 + i * decbuf_size +
+ decbuf_size / 2, canvas_width,
+ canvas_height, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ canvas_config((index2canvas1(i) >> 8) & 0xff,
+ buf_start + i * decbuf_size +
+ 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 + i * decbuf_size +
+ decbuf_y_size + decbuf_uv_size +
+ decbuf_uv_size / 2, canvas_width / 2,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+#endif
+ }
+ }
+}
+
+static void init_scaler(void)
+{
+ /* 4 point triangle */
+ const unsigned 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_MPEG_REG(RESET2_REGISTER, RESET_PSCALE);
+#endif
+ READ_MPEG_REG(RESET2_REGISTER);
+ READ_MPEG_REG(RESET2_REGISTER);
+ READ_MPEG_REG(RESET2_REGISTER);
+
+ WRITE_VREG(PSCALE_RST, 0x7);
+ WRITE_VREG(PSCALE_RST, 0x0);
+}
+
+static void vmjpeg_prot_init(void)
+{
+#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_MPEG_REG(RESET0_REGISTER, RESET_IQIDCT | RESET_MC);
+#endif
+
+ 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
+}
+
+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);
+ }
+}
+
+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) {
+ pr_err("get firmware fail.");
+ vfree(buf);
+ return -1;
+ }
+
+ if (amvdec_loadmc_ex(VFORMAT_MJPEG, NULL, buf) < 0) {
+ amvdec_disable();
+ vfree(buf);
+ return -EBUSY;
+ }
+
+ vfree(buf);
+
+ stat |= STAT_MC_LOAD;
+
+ /* enable AMRISC side protocol */
+ vmjpeg_prot_init();
+
+ 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
+
+ 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");
+
+ if (pdata == NULL) {
+ amlog_level(LOG_LEVEL_ERROR,
+ "amvdec_mjpeg memory resource undefined.\n");
+ mutex_unlock(&vmjpeg_mutex);
+
+ return -EFAULT;
+ }
+
+ buf_start = pdata->mem_start;
+ buf_size = pdata->mem_end - pdata->mem_start + 1;
+
+ if (pdata->sys_info)
+ vmjpeg_amstream_dec_info = *pdata->sys_info;
+
+ pdata->dec_status = vmjpeg_dec_status;
+
+ if (vmjpeg_init() < 0) {
+ amlog_level(LOG_LEVEL_ERROR, "amvdec_mjpeg init failed.\n");
+ mutex_unlock(&vmjpeg_mutex);
+
+ 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);
+
+ 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) {
+ 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);
+
+ amlog_level(LOG_LEVEL_INFO, "amvdec_mjpeg remove.\n");
+
+ return 0;
+}
+
+/****************************************/
+
+static struct platform_driver amvdec_mjpeg_driver = {
+ .probe = amvdec_mjpeg_probe,
+ .remove = amvdec_mjpeg_remove,
+#ifdef CONFIG_PM
+ .suspend = amvdec_suspend,
+ .resume = amvdec_resume,
+#endif
+ .driver = {
+ .name = DRIVER_NAME,
+ }
+};
+
+static struct codec_profile_t amvdec_mjpeg_profile = {
+ .name = "mjpeg",
+ .profile = ""
+};
+
+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);
+ 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..850e0b6
--- a/dev/null
+++ b/drivers/frame_provider/decoder/mjpeg/vmjpeg_multi.c
@@ -0,0 +1,723 @@
+/*
+ * 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 <linux/amlogic/media/registers/register.h>
+#include "../../../stream_input/amports/amports_priv.h"
+
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+
+#include "../utils/vdec_input.h"
+#include "../utils/vdec.h"
+#include "../utils/amvdec.h"
+
+#define MEM_NAME "codec_mmjpeg"
+
+#define DRIVER_NAME "ammvdec_mjpeg"
+#define MODULE_NAME "ammvdec_mjpeg"
+
+/* 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 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
+
+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 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
+
+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;
+};
+
+#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;
+
+ u32 stat;
+ u32 dec_result;
+ unsigned long buf_start;
+ u32 buf_size;
+
+ 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;
+};
+
+static void set_frame_info(struct vdec_mjpeg_hw_s *hw, struct vframe_s *vf)
+{
+ vf->width = hw->frame_width;
+ vf->height = hw->frame_height;
+ vf->duration = hw->frame_dur;
+ vf->ratio_control = 0;
+ 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];
+}
+
+static irqreturn_t vmjpeg_isr(struct vdec_s *vdec)
+{
+ struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)(vdec->private);
+ u32 reg;
+ struct vframe_s *vf = NULL;
+ u32 index;
+
+ WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
+
+ if (!hw)
+ return IRQ_HANDLED;
+
+ reg = READ_VREG(MREG_FROM_AMRISC);
+ index = READ_VREG(AV_SCRATCH_5);
+
+ if (index >= DECODE_BUFFER_NUM_MAX) {
+ 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;
+ }
+
+ 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; */
+ vf->pts = hw->chunk->pts;
+ vf->pts_us64 = hw->chunk->pts64;
+ vf->orientation = 0;
+ hw->vfbuf_use[index]++;
+
+ kfifo_put(&hw->display_q, (const struct vframe_s *)vf);
+
+ vf_notify_receiver(vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY,
+ NULL);
+
+ hw->dec_result = DEC_RESULT_DONE;
+
+ schedule_work(&hw->work);
+
+ return IRQ_HANDLED;
+}
+
+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;
+
+ 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;
+
+ if (kfifo_get(&hw->display_q, &vf))
+ 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;
+
+ hw->vfbuf_use[vf->index]--;
+ kfifo_put(&hw->newframe_q, (const struct vframe_s *)vf);
+}
+
+static int vmjpeg_event_cb(int type, void *data, void *private_data)
+{
+ 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_status *vstatus)
+{
+ struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)vdec->private;
+ vstatus->width = hw->frame_width;
+ vstatus->height = hw->frame_height;
+ if (0 != hw->frame_dur)
+ vstatus->fps = 96000 / hw->frame_dur;
+ else
+ vstatus->fps = 96000;
+ vstatus->error_count = 0;
+ vstatus->status = hw->stat;
+
+ return 0;
+}
+
+/****************************************/
+static void vmjpeg_canvas_init(struct vdec_s *vdec)
+{
+ int i;
+ u32 canvas_width, canvas_height;
+ u32 decbuf_size, decbuf_y_size, decbuf_uv_size;
+ struct vdec_mjpeg_hw_s *hw =
+ (struct vdec_mjpeg_hw_s *)vdec->private;
+ ulong addr;
+
+ canvas_width = 1920;
+ canvas_height = 1088;
+ decbuf_y_size = 0x200000;
+ decbuf_uv_size = 0x80000;
+ decbuf_size = 0x300000;
+
+ for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) {
+ int canvas;
+
+ canvas = vdec->get_canvas(i, 3);
+ if (hw->buffer_spec[i].cma_alloc_count == 0) {
+ hw->buffer_spec[i].cma_alloc_count =
+ PAGE_ALIGN(decbuf_size) / PAGE_SIZE;
+ hw->buffer_spec[i].cma_alloc_addr =
+ codec_mm_alloc_for_dma(MEM_NAME,
+ hw->buffer_spec[i].cma_alloc_count,
+ 16, CODEC_MM_FLAGS_FOR_VDECODER);
+ }
+
+ if (!hw->buffer_spec[i].cma_alloc_addr) {
+ pr_err("CMA alloc failed, request buf size 0x%lx\n",
+ hw->buffer_spec[i].cma_alloc_count * PAGE_SIZE);
+ hw->buffer_spec[i].cma_alloc_count = 0;
+ break;
+ }
+
+ 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 += decbuf_y_size;
+ hw->buffer_spec[i].u_addr = addr;
+ addr += decbuf_uv_size;
+ hw->buffer_spec[i].v_addr = addr;
+
+ 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(hw->buffer_spec[i].y_canvas_index,
+ hw->buffer_spec[i].y_addr,
+ canvas_width,
+ canvas_height,
+ CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_LINEAR);
+ 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;
+
+ canvas_config(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);
+ 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;
+
+ canvas_config(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);
+ 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;
+ }
+}
+
+static void init_scaler(void)
+{
+ /* 4 point triangle */
+ const unsigned 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_MPEG_REG(RESET2_REGISTER, RESET_PSCALE);
+#endif
+ READ_MPEG_REG(RESET2_REGISTER);
+ READ_MPEG_REG(RESET2_REGISTER);
+ READ_MPEG_REG(RESET2_REGISTER);
+
+ WRITE_VREG(PSCALE_RST, 0x7);
+ WRITE_VREG(PSCALE_RST, 0x0);
+}
+
+static void vmjpeg_hw_ctx_restore(struct vdec_s *vdec, int index)
+{
+ struct vdec_mjpeg_hw_s *hw =
+ (struct vdec_mjpeg_hw_s *)vdec->private;
+
+ WRITE_VREG(DOS_SW_RESET0, (1 << 7) | (1 << 6));
+ WRITE_VREG(DOS_SW_RESET0, 0);
+
+ vmjpeg_canvas_init(vdec);
+
+ /* find next decode buffer index */
+ WRITE_VREG(AV_SCRATCH_4, spec2canvas(&hw->buffer_spec[index]));
+ WRITE_VREG(AV_SCRATCH_5, index);
+
+ 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
+}
+
+static s32 vmjpeg_init(struct vdec_s *vdec)
+{
+ int i;
+ struct vdec_mjpeg_hw_s *hw =
+ (struct vdec_mjpeg_hw_s *)vdec->private;
+
+ 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->saved_resolution = 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);
+ }
+
+ INIT_WORK(&hw->work, vmjpeg_work);
+
+ return 0;
+}
+
+static bool run_ready(struct vdec_s *vdec)
+{
+ return true;
+}
+
+static void run(struct vdec_s *vdec,
+ void (*callback)(struct vdec_s *, void *), void *arg)
+{
+ struct vdec_mjpeg_hw_s *hw =
+ (struct vdec_mjpeg_hw_s *)vdec->private;
+ int i,ret = -1,size = -1;
+ char *buf = vmalloc(0x1000 * 16);
+ if (IS_ERR_OR_NULL(buf))
+ return;
+
+ hw->vdec_cb_arg = arg;
+ hw->vdec_cb = callback;
+
+ for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) {
+ if (hw->vfbuf_use[i] == 0)
+ break;
+ }
+
+ if (i == DECODE_BUFFER_NUM_MAX) {
+ hw->dec_result = DEC_RESULT_AGAIN;
+ schedule_work(&hw->work);
+ return;
+ }
+
+ ret = vdec_prepare_input(vdec, &hw->chunk);
+ if (ret < 0) {
+ hw->dec_result = DEC_RESULT_AGAIN;
+ schedule_work(&hw->work);
+ return;
+ }
+
+ hw->dec_result = DEC_RESULT_NONE;
+
+ size = get_firmware_data(VIDEO_DEC_MJPEG_MULTI, buf);
+ if (size < 0) {
+ pr_err("get firmware fail.");
+ vfree(buf);
+ return;
+ }
+
+ if (amvdec_vdec_loadmc_buf_ex(vdec, buf, size) < 0) {
+ pr_err("%s: Error amvdec_loadmc fail\n", __func__);
+ vfree(buf);
+ return;
+ }
+
+ vfree(buf);
+
+ vmjpeg_hw_ctx_restore(vdec, i);
+
+ vdec_enable_input(vdec);
+
+ amvdec_start();
+}
+
+static void vmjpeg_work(struct work_struct *work)
+{
+ struct vdec_mjpeg_hw_s *hw = container_of(work,
+ struct vdec_mjpeg_hw_s, work);
+
+ if (hw->dec_result == DEC_RESULT_DONE)
+ vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk);
+
+ /* mark itself has all HW resource released and input released */
+ vdec_set_status(hw_to_vdec(hw), VDEC_STATUS_CONNECTED);
+
+ if (hw->vdec_cb)
+ hw->vdec_cb(hw_to_vdec(hw), hw->vdec_cb_arg);
+}
+
+static int amvdec_mjpeg_probe(struct platform_device *pdev)
+{
+ struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
+ struct vdec_mjpeg_hw_s *hw = NULL;
+
+ if (pdata == NULL) {
+ pr_info("amvdec_mjpeg memory resource undefined.\n");
+ return -EFAULT;
+ }
+
+ hw = (struct vdec_mjpeg_hw_s *)devm_kzalloc(&pdev->dev,
+ sizeof(struct vdec_mjpeg_hw_s), GFP_KERNEL);
+ if (hw == NULL) {
+ pr_info("\nammvdec_mjpeg device data allocation failed\n");
+ return -ENOMEM;
+ }
+
+ pdata->private = hw;
+ pdata->dec_status = vmjpeg_dec_status;
+
+ pdata->run = run;
+ pdata->run_ready = run_ready;
+ pdata->irq_handler = vmjpeg_isr;
+
+ pdata->id = pdev->id;
+
+ 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);
+
+ vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name,
+ &vf_provider_ops, pdata);
+
+ platform_set_drvdata(pdev, pdata);
+
+ hw->platform_dev = pdev;
+ hw->buf_start = pdata->mem_start;
+ hw->buf_size = pdata->mem_end - pdata->mem_start + 1;
+
+ if (pdata->sys_info)
+ hw->vmjpeg_amstream_dec_info = *pdata->sys_info;
+
+ if (vmjpeg_init(pdata) < 0) {
+ pr_info("amvdec_mjpeg init failed.\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int amvdec_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);
+ int i;
+
+ for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) {
+ if (hw->buffer_spec[i].cma_alloc_addr) {
+ pr_info("codec_mm release buffer_spec[%d], 0x%lx\n", i,
+ hw->buffer_spec[i].cma_alloc_addr);
+ codec_mm_free_for_dma(MEM_NAME,
+ hw->buffer_spec[i].cma_alloc_addr);
+ hw->buffer_spec[i].cma_alloc_count = 0;
+ }
+ }
+
+ cancel_work_sync(&hw->work);
+
+ vdec_set_status(hw_to_vdec(hw), VDEC_STATUS_DISCONNECTED);
+
+ return 0;
+}
+
+/****************************************/
+
+static struct platform_driver amvdec_mjpeg_driver = {
+ .probe = amvdec_mjpeg_probe,
+ .remove = amvdec_mjpeg_remove,
+#ifdef CONFIG_PM
+ .suspend = amvdec_suspend,
+ .resume = amvdec_resume,
+#endif
+ .driver = {
+ .name = DRIVER_NAME,
+ }
+};
+
+static struct codec_profile_t amvdec_mjpeg_profile = {
+ .name = "mmjpeg",
+ .profile = ""
+};
+
+static int __init amvdec_mjpeg_driver_init_module(void)
+{
+ if (platform_driver_register(&amvdec_mjpeg_driver)) {
+ pr_err("failed to register amvdec_mjpeg driver\n");
+ return -ENODEV;
+ }
+ vcodec_profile_register(&amvdec_mjpeg_profile);
+ return 0;
+}
+
+static void __exit amvdec_mjpeg_driver_remove_module(void)
+{
+ platform_driver_unregister(&amvdec_mjpeg_driver);
+}
+
+/****************************************/
+
+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/mpeg12/vmpeg12.c b/drivers/frame_provider/decoder/mpeg12/vmpeg12.c
new file mode 100644
index 0000000..1d15e11
--- a/dev/null
+++ b/drivers/frame_provider/decoder/mpeg12/vmpeg12.c
@@ -0,0 +1,1110 @@
+/*
+ * 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/amlogic/media/utils/vdec_reg.h>
+#include "vmpeg12.h"
+#include <linux/amlogic/media/registers/register.h>
+#include "../../../stream_input/amports/amports_priv.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"
+
+#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 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 VF_POOL_SIZE 32
+#define DECODE_BUFFER_NUM_MAX 8
+#define PUT_INTERVAL (HZ/100)
+
+#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 CCBUF_SIZE (5*1024)
+
+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 void 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 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 const u32 frame_rate_tab[16] = {
+ 96000 / 30, 96000 / 24, 96000 / 24, 96000 / 25,
+ 96000 / 30, 96000 / 30, 96000 / 50, 96000 / 60,
+ 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 unsigned long buf_start;
+static u32 buf_size, ccbuf_phyAddress;
+static void *ccbuf_phyAddress_virt;
+static int ccbuf_phyAddress_is_remaped_nocache;
+
+static DEFINE_SPINLOCK(lock);
+
+static u32 frame_rpt_state;
+
+static struct dec_sysinfo vmpeg12_amstream_dec_info;
+
+/* 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 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 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 {
+ vf->duration = frame_dur =
+ frame_rate_tab[(READ_VREG(MREG_SEQ_INFO) >> 4) & 0xf];
+ }
+
+ 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;
+
+ 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 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;
+
+ WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
+
+ reg = READ_VREG(MREG_BUFFEROUT);
+
+ if ((reg >> 16) == 0xfe) {
+ if (!ccbuf_phyAddress_is_remaped_nocache &&
+ ccbuf_phyAddress &&
+ ccbuf_phyAddress_virt) {
+ codec_mm_dma_flush(
+ ccbuf_phyAddress_virt,
+ CCBUF_SIZE,
+ DMA_FROM_DEVICE);
+ }
+ wakeup_userdata_poll(
+ reg & 0xffff,
+ (unsigned long)ccbuf_phyAddress_virt,
+ CCBUF_SIZE, 0);
+ WRITE_VREG(MREG_BUFFEROUT, 0);
+ } else if (reg) {
+ info = READ_VREG(MREG_PIC_INFO);
+ offset = READ_VREG(MREG_FRAME_OFFSET);
+
+ 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, 0, &pts_us64) == 0)
+ && (((info & PICINFO_TYPE_MASK) == PICINFO_TYPE_I)
+ || ((info & PICINFO_TYPE_MASK) ==
+ PICINFO_TYPE_P)))
+ pts_valid = 1;
+
+ /*if (frame_prog == 0) */
+ {
+ frame_prog = info & PICINFO_PROG;
+ }
+
+ 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);
+ 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
+ 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;
+ }
+
+ 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))) {
+ kfifo_put(&recycle_q,
+ (const struct vframe_s *)vf);
+ } else {
+ kfifo_put(&display_q,
+ (const struct vframe_s *)vf);
+ 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 (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;
+ }
+
+ if (kfifo_get(&newframe_q, &vf) == 0) {
+ pr_info
+ ("fatal error, no available buffer slot.");
+ return IRQ_HANDLED;
+ }
+
+ 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
+ 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))) {
+ kfifo_put(&recycle_q,
+ (const struct vframe_s *)vf);
+ } else {
+ kfifo_put(&display_q,
+ (const struct vframe_s *)vf);
+ 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
+ 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;
+
+ 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);
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY,
+ NULL);
+ }
+ }
+
+ WRITE_VREG(MREG_BUFFEROUT, 0);
+ }
+
+ 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 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");
+
+ 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();
+ amvdec_start();
+ }
+
+ 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)) {
+ int fps = 96000 / frame_dur;
+ saved_resolution = frame_width * frame_height * fps;
+ vdec_source_changed(VFORMAT_MPEG12,
+ frame_width, frame_height, fps);
+ }
+
+ timer->expires = jiffies + PUT_INTERVAL;
+
+ add_timer(timer);
+}
+
+int vmpeg12_dec_status(struct vdec_s *vdec, struct vdec_status *vstatus)
+{
+ vstatus->width = frame_width;
+ vstatus->height = frame_height;
+ if (frame_dur != 0)
+ vstatus->fps = 96000 / frame_dur;
+ else
+ vstatus->fps = 96000;
+ vstatus->error_count = READ_VREG(AV_SCRATCH_C);
+ vstatus->status = stat;
+
+ return 0;
+}
+
+/****************************************/
+static void vmpeg12_canvas_init(void)
+{
+ int i;
+ u32 canvas_width, canvas_height;
+ u32 decbuf_size, decbuf_y_size, decbuf_uv_size;
+ u32 disp_addr = 0xffffffff;
+
+ 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;
+ }
+
+ if (is_vpp_postblend()) {
+ struct canvas_s cur_canvas;
+
+ canvas_read((READ_VCBUS_REG(VD1_IF0_CANVAS0) & 0xff),
+ &cur_canvas);
+ disp_addr = (cur_canvas.addr + 7) >> 3;
+ }
+
+ for (i = 0; i < 8; i++) {
+ if (((buf_start + i * decbuf_size + 7) >> 3) == disp_addr) {
+#ifdef NV21
+ canvas_config(2 * i + 0,
+ buf_start + 8 * decbuf_size,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+ canvas_config(2 * i + 1,
+ buf_start + 8 * decbuf_size +
+ decbuf_y_size, canvas_width,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+#else
+ canvas_config(3 * i + 0,
+ buf_start + 8 * decbuf_size,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+ canvas_config(3 * i + 1,
+ buf_start + 8 * decbuf_size +
+ decbuf_y_size, canvas_width / 2,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+ canvas_config(3 * i + 2,
+ buf_start + 8 * decbuf_size +
+ decbuf_y_size + decbuf_uv_size,
+ canvas_width / 2, canvas_height / 2,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+#endif
+ } else {
+#ifdef NV21
+ canvas_config(2 * i + 0,
+ buf_start + i * decbuf_size,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+ canvas_config(2 * i + 1,
+ buf_start + i * decbuf_size +
+ decbuf_y_size, canvas_width,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+#else
+ canvas_config(3 * i + 0,
+ buf_start + i * decbuf_size,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+ canvas_config(3 * i + 1,
+ buf_start + i * decbuf_size +
+ decbuf_y_size, canvas_width / 2,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+ canvas_config(3 * i + 2,
+ buf_start + i * decbuf_size +
+ decbuf_y_size + decbuf_uv_size,
+ canvas_width / 2, canvas_height / 2,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+#endif
+ }
+ }
+
+ WRITE_VREG(MREG_CO_MV_START,
+ buf_start + 9 * decbuf_size + CCBUF_SIZE);
+ if (!ccbuf_phyAddress) {
+ ccbuf_phyAddress = (u32)(buf_start + 9 * decbuf_size);
+ ccbuf_phyAddress_virt = codec_mm_phys_to_virt(ccbuf_phyAddress);
+ if (!ccbuf_phyAddress_virt) {
+ ccbuf_phyAddress_virt = ioremap_nocache(
+ ccbuf_phyAddress,
+ CCBUF_SIZE);
+ ccbuf_phyAddress_is_remaped_nocache = 1;
+ }
+ }
+
+}
+
+static void vmpeg12_prot_init(void)
+{
+ if (get_cpu_type() >= 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_type() >= 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_MPEG_REG(RESET0_REGISTER, RESET_IQIDCT | RESET_MC);
+
+ 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);
+ /* 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
+}
+
+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;
+
+
+ frame_width = frame_height = frame_dur = frame_prog = 0;
+ frame_force_skip_flag = 0;
+ wait_buffer_counter = 0;
+ first_i_frame_ready = 0;
+ 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;
+ }
+
+ if (amvdec_loadmc_ex(VFORMAT_MPEG12, NULL, buf) < 0) {
+ amvdec_disable();
+ vfree(buf);
+ 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
+
+ vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)((unsigned long)vmpeg12_amstream_dec_info.rate));
+
+ 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_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;
+ }
+
+ if (pdata->sys_info)
+ vmpeg12_amstream_dec_info = *pdata->sys_info;
+
+ buf_start = pdata->mem_start;
+ buf_size = pdata->mem_end - pdata->mem_start + 1;
+
+ pdata->dec_status = vmpeg12_dec_status;
+
+ if (vmpeg12_init() < 0) {
+ amlog_level(LOG_LEVEL_ERROR, "amvdec_mpeg12 init failed.\n");
+
+ return -ENODEV;
+ }
+
+ amlog_level(LOG_LEVEL_INFO, "amvdec_mpeg12 probe end.\n");
+
+ return 0;
+}
+
+static int amvdec_mpeg12_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 *)vmpeg12_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) {
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_FR_END_HINT, NULL);
+
+ vf_unreg_provider(&vmpeg_vf_prov);
+ stat &= ~STAT_VF_HOOK;
+ }
+
+ amvdec_disable();
+ if (ccbuf_phyAddress_is_remaped_nocache)
+ iounmap(ccbuf_phyAddress_virt);
+
+ ccbuf_phyAddress_virt = NULL;
+ ccbuf_phyAddress = 0;
+ ccbuf_phyAddress_is_remaped_nocache = 0;
+ amlog_level(LOG_LEVEL_INFO, "amvdec_mpeg12 remove.\n");
+
+ return 0;
+}
+
+/****************************************/
+
+static struct platform_driver amvdec_mpeg12_driver = {
+ .probe = amvdec_mpeg12_probe,
+ .remove = amvdec_mpeg12_remove,
+#ifdef CONFIG_PM
+ .suspend = amvdec_suspend,
+ .resume = amvdec_resume,
+#endif
+ .driver = {
+ .name = DRIVER_NAME,
+ }
+};
+
+static struct codec_profile_t amvdec_mpeg12_profile = {
+ .name = "mpeg12",
+ .profile = ""
+};
+
+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);
+ 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(stat, uint, 0664);
+MODULE_PARM_DESC(stat, "\n amvdec_mpeg12 stat\n");
+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_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..2038c06
--- a/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/mpeg4/vmpeg4.c b/drivers/frame_provider/decoder/mpeg4/vmpeg4.c
new file mode 100644
index 0000000..1f1541a
--- a/dev/null
+++ b/drivers/frame_provider/decoder/mpeg4/vmpeg4.c
@@ -0,0 +1,1127 @@
+/*
+ * 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/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"
+
+
+/* #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"
+
+#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 RATE_DETECT_COUNT 5
+#define DURATION_UNIT 96000
+#define PTS_UNIT 90000
+
+#define DUR2PTS(x) ((x) - ((x) >> 4))
+
+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 void vmpeg4_prot_init(void);
+static void vmpeg4_local_init(void);
+
+static const char vmpeg4_dec_id[] = "vmpeg4-dev";
+
+#define PROVIDER_NAME "decoder.mpeg4"
+
+/*
+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 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 unsigned long buf_start;
+static u32 buf_size, buf_offset;
+static u32 vmpeg4_ratio;
+static u64 vmpeg4_ratio64;
+static u32 rate_detect;
+static u32 vmpeg4_rotation;
+
+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;
+
+#ifdef CONFIG_AM_VDEC_MPEG4_LOG
+u32 pts_hit, pts_missed, pts_i_hit, pts_i_missed;
+#endif
+
+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 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;
+
+ 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;
+ } 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 ((I_PICTURE == picture_type) ||
+ (P_PICTURE == picture_type)) {
+ 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, 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 += (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 (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]++;
+
+ kfifo_put(&display_q, (const struct vframe_s *)vf);
+
+ 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));
+
+ vfbuf_use[buffer_index]++;
+
+ amlog_mask(LOG_MASK_PTS,
+ "[%s:%d] [inte] dur=0x%x rate=%d picture_type=%d\n",
+ __func__, __LINE__, vf->duration,
+ vmpeg4_amstream_dec_info.rate, picture_type);
+
+ kfifo_put(&display_q, (const struct vframe_s *)vf);
+
+ 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]++;
+
+ kfifo_put(&display_q, (const struct vframe_s *)vf);
+
+ 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;
+ }
+
+ 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();
+ }
+ 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 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 >= 0)
+ && (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)) {
+ int fps = 96000 / frame_dur;
+ saved_resolution = frame_width * frame_height * fps;
+ vdec_source_changed(VFORMAT_MPEG4,
+ frame_width, frame_height, fps);
+ }
+ if (READ_VREG(AV_SCRATCH_L)) {
+ unsigned long flags;
+ pr_info("mpeg4 fatal error happened,need reset !!\n");
+ 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();
+ }
+
+
+ timer->expires = jiffies + PUT_INTERVAL;
+
+ add_timer(timer);
+}
+
+int vmpeg4_dec_status(struct vdec_s *vdec, struct vdec_status *vstatus)
+{
+ vstatus->width = vmpeg4_amstream_dec_info.width;
+ vstatus->height = vmpeg4_amstream_dec_info.height;
+ if (0 != vmpeg4_amstream_dec_info.rate)
+ vstatus->fps = DURATION_UNIT / vmpeg4_amstream_dec_info.rate;
+ else
+ vstatus->fps = DURATION_UNIT;
+ vstatus->error_count = READ_VREG(MP4_ERR_COUNT);
+ vstatus->status = stat;
+
+ return 0;
+}
+
+/****************************************/
+static void vmpeg4_canvas_init(void)
+{
+ int i;
+ u32 canvas_width, canvas_height;
+ u32 decbuf_size, decbuf_y_size, decbuf_uv_size;
+ u32 disp_addr = 0xffffffff;
+ u32 buff_off = 0;
+
+ 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;
+ }
+ }
+
+ if (is_vpp_postblend()) {
+ struct canvas_s cur_canvas;
+
+ canvas_read((READ_VCBUS_REG(VD1_IF0_CANVAS0) & 0xff),
+ &cur_canvas);
+ disp_addr = (cur_canvas.addr + 7) >> 3;
+ }
+
+ for (i = 0; i < 8; i++) {
+ u32 one_buf_start = buf_start + buff_off;
+ if (((one_buf_start + 7) >> 3) == disp_addr) {
+ /*last disp buffer, to next..*/
+ buff_off += decbuf_size;
+ one_buf_start = buf_start + buff_off;
+ pr_info("one_buf_start %d,=== %x disp_addr %x",
+ i, one_buf_start, disp_addr);
+ }
+ if (buff_off < 0x02000000 &&
+ buff_off + decbuf_size > 0x01b00000){
+ /*0x01b00000 is references buffer.
+ to next 32M;*/
+ buff_off = 32 * SZ_1M;/*next 32M*/
+ one_buf_start = buf_start + buff_off;
+ }
+ if (buff_off + decbuf_size > buf_size) {
+ pr_err("ERROR::too small buffer for buf%d %d x%d ,size =%d\n",
+ i,
+ canvas_width,
+ canvas_height,
+ buf_size);
+ }
+ pr_debug("alloced buffer %d at %x,%d\n",
+ i, one_buf_start, decbuf_size);
+#ifdef NV21
+ canvas_config(2 * i + 0,
+ one_buf_start,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+ canvas_config(2 * i + 1,
+ one_buf_start +
+ decbuf_y_size, canvas_width,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+#else
+ canvas_config(3 * i + 0,
+ one_buf_start,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+ canvas_config(3 * i + 1,
+ one_buf_start +
+ decbuf_y_size, canvas_width / 2,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+ canvas_config(3 * i + 2,
+ one_buf_start +
+ decbuf_y_size + decbuf_uv_size,
+ canvas_width / 2, canvas_height / 2,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+#endif
+ buff_off = buff_off + decbuf_size;
+ }
+}
+
+static void vmpeg4_prot_init(void)
+{
+#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_MPEG_REG(RESET0_REGISTER, RESET_IQIDCT | RESET_MC);
+#endif
+
+ 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);
+
+ 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);
+
+ /* 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 */
+ printk("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);
+}
+
+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;
+
+#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);
+ }
+}
+
+static s32 vmpeg4_init(void)
+{
+ int trickmode_fffb = 0;
+ int size = -1;
+ char *buf = vmalloc(0x1000 * 16);
+ if (IS_ERR_OR_NULL(buf))
+ return -ENOMEM;
+
+ query_video_status(0, &trickmode_fffb);
+
+ amlog_level(LOG_LEVEL_INFO, "vmpeg4_init\n");
+ init_timer(&recycle_timer);
+
+ stat |= STAT_TIMER_INIT;
+
+ amvdec_enable();
+
+ vmpeg4_local_init();
+
+ if (vmpeg4_amstream_dec_info.format == VIDEO_DEC_FORMAT_MPEG4_3) {
+ size = get_firmware_data(VIDEO_DEC_MPEG4_3, buf);
+
+ amlog_level(LOG_LEVEL_INFO, "load VIDEO_DEC_FORMAT_MPEG4_3\n");
+ } else if (vmpeg4_amstream_dec_info.format ==
+ VIDEO_DEC_FORMAT_MPEG4_4) {
+ size = get_firmware_data(VIDEO_DEC_MPEG4_4, buf);
+
+ amlog_level(LOG_LEVEL_INFO, "load VIDEO_DEC_FORMAT_MPEG4_4\n");
+ } else if (vmpeg4_amstream_dec_info.format ==
+ VIDEO_DEC_FORMAT_MPEG4_5) {
+ size = get_firmware_data(VIDEO_DEC_MPEG4_5, buf);
+
+ 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);
+
+ amlog_level(LOG_LEVEL_INFO, "load VIDEO_DEC_FORMAT_H263\n");
+ } else
+ amlog_level(LOG_LEVEL_ERROR, "not supported MPEG4 format\n");
+
+ if (size < 0) {
+ pr_err("get firmware fail.");
+ vfree(buf);
+ return -1;
+ }
+
+ if (amvdec_loadmc_ex(VFORMAT_MPEG4, NULL, buf) < 0) {
+ amvdec_disable();
+ vfree(buf);
+ return -EBUSY;
+ }
+
+ vfree(buf);
+
+ stat |= STAT_MC_LOAD;
+
+ /* enable AMRISC side protocol */
+ vmpeg4_prot_init();
+
+ if (vdec_request_irq(VDEC_IRQ_1, vmpeg4_isr,
+ "vmpeg4-irq", (void *)vmpeg4_dec_id)) {
+ amvdec_disable();
+
+ amlog_level(LOG_LEVEL_ERROR, "vmpeg4 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
+ vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)((unsigned long)vmpeg4_amstream_dec_info.rate));
+
+ 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;
+ }
+
+ buf_start = pdata->mem_start;
+ buf_size = pdata->mem_end - pdata->mem_start + 1;
+ buf_offset = buf_start - ORI_BUFFER_START_ADDR;
+
+ if (pdata->sys_info)
+ vmpeg4_amstream_dec_info = *pdata->sys_info;
+
+ pdata->dec_status = vmpeg4_dec_status;
+
+ if (vmpeg4_init() < 0) {
+ amlog_level(LOG_LEVEL_ERROR, "amvdec_mpeg4 init failed.\n");
+
+ 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) {
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_FR_END_HINT, NULL);
+
+ vf_unreg_provider(&vmpeg_vf_prov);
+ stat &= ~STAT_VF_HOOK;
+ }
+
+ amvdec_disable();
+
+ 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);
+
+ return 0;
+}
+
+/****************************************/
+
+static struct platform_driver amvdec_mpeg4_driver = {
+ .probe = amvdec_mpeg4_probe,
+ .remove = amvdec_mpeg4_remove,
+#ifdef CONFIG_PM
+ .suspend = amvdec_suspend,
+ .resume = amvdec_resume,
+#endif
+ .driver = {
+ .name = DRIVER_NAME,
+ }
+};
+
+static struct codec_profile_t amvdec_mpeg4_profile = {
+ .name = "mpeg4",
+ .profile = ""
+};
+
+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);
+ 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_param(stat, uint, 0664);
+MODULE_PARM_DESC(stat, "\n amvdec_mpeg4 stat\n");
+
+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..21ff478
--- a/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..5c4b242
--- a/dev/null
+++ b/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c
@@ -0,0 +1,1304 @@
+/*
+ * 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/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/media/utils/vdec_reg.h>
+#include "vmpeg4.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"
+
+#define DRIVER_NAME "ammvdec_mpeg4"
+#define MODULE_NAME "ammvdec_mpeg4"
+
+#define MEM_NAME "codec_mpeg4"
+
+#define DEBUG_PTS
+
+#define NV21
+#define I_PICTURE 0
+#define P_PICTURE 1
+#define B_PICTURE 2
+
+#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_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 16
+#define DECODE_BUFFER_NUM_MAX 4
+#define PUT_INTERVAL (HZ/100)
+
+#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 DUR2PTS(x) ((x) - ((x) >> 4))
+
+#define DEC_RESULT_NONE 0
+#define DEC_RESULT_DONE 1
+#define DEC_RESULT_AGAIN 2
+#define DEC_RESULT_ERROR 3
+
+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);
+
+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 vframe_chunk_s *chunk;
+ u32 stat;
+ u32 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 pts_hit;
+ u32 pts_missed;
+ u32 pts_i_hit;
+ u32 pts_i_missed;
+
+ u32 buffer_info[DECODE_BUFFER_NUM_MAX];
+ u32 pts[DECODE_BUFFER_NUM_MAX];
+ u64 pts64[DECODE_BUFFER_NUM_MAX];
+ bool pts_valid[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;
+
+};
+static void vmpeg4_local_init(struct vdec_mpeg4_hw_s *hw);
+static int vmpeg4_hw_ctx_restore(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 int find_buffer(struct vdec_mpeg4_hw_s *hw)
+{
+ int i;
+
+ for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) {
+ if (hw->vfbuf_use[i] == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+static int spec_to_index(struct vdec_mpeg4_hw_s *hw, u32 spec)
+{
+ int i;
+
+ for (i = 0; i < DECODE_BUFFER_NUM_MAX; 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 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);
+ /* always stretch to 16:9 */
+ } else if (pixel_ratio > 0x0f) {
+ num = (pixel_ratio >> 8) *
+ hw->vmpeg4_amstream_dec_info.width * num;
+ ar = div_u64((pixel_ratio & 0xff) *
+ hw->vmpeg4_amstream_dec_info.height * den * 0x100ULL +
+ (num >> 1), num);
+ } else {
+ switch (aspect_ratio_table[pixel_ratio]) {
+ case 0:
+ num = hw->vmpeg4_amstream_dec_info.width * num;
+ ar = (hw->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->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 irqreturn_t vmpeg4_isr(struct vdec_s *vdec)
+{
+ u32 reg;
+ struct vframe_s *vf = NULL;
+ u32 picture_type;
+ int index;
+ u32 pts, offset = 0;
+ bool pts_valid = false;
+ u64 pts_us64 = 0;
+ u32 time_increment_resolution, fixed_vop_rate, vop_time_inc;
+ u32 repeat_cnt, duration = 3200;
+ struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)(vdec->private);
+
+ WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
+
+ reg = READ_VREG(MREG_BUFFEROUT);
+
+ time_increment_resolution = READ_VREG(MP4_RATE);
+ fixed_vop_rate = time_increment_resolution >> 16;
+ time_increment_resolution &= 0xffff;
+
+ if (hw->vmpeg4_amstream_dec_info.rate == 0) {
+ if ((fixed_vop_rate != 0) && (time_increment_resolution != 0)) {
+ /* fixed VOP rate */
+ hw->vmpeg4_amstream_dec_info.rate = fixed_vop_rate *
+ DURATION_UNIT /
+ time_increment_resolution;
+ }
+ }
+
+ if (reg == 2) {
+ /* timeout when decoding next frame */
+
+ /* for frame based case, insufficient result may happen
+ * at the begining when only VOL head is available save
+ * HW context also, such as for the QTable from VCOP register
+ */
+ if (input_frame_based(vdec))
+ vmpeg4_save_hw_context(hw);
+
+ hw->dec_result = DEC_RESULT_AGAIN;
+
+ schedule_work(&hw->work);
+
+ return IRQ_HANDLED;
+ } else {
+ picture_type = (reg >> 3) & 7;
+ repeat_cnt = READ_VREG(MP4_NOT_CODED_CNT);
+ vop_time_inc = READ_VREG(MP4_VOP_TIME_INC);
+
+ index = spec_to_index(hw, READ_VREG(REC_CANVAS_ADDR));
+
+ if (index < 0) {
+ pr_err("invalid buffer index.");
+ hw->dec_result = DEC_RESULT_ERROR;
+
+ schedule_work(&hw->work);
+
+ return IRQ_HANDLED;
+ }
+
+ hw->dec_result = DEC_RESULT_DONE;
+
+ pr_debug("amvdec_mpeg4: offset = 0x%x\n",
+ READ_VREG(MP4_OFFSET_REG));
+
+ if (hw->vmpeg4_amstream_dec_info.width == 0) {
+ hw->vmpeg4_amstream_dec_info.width =
+ READ_VREG(MP4_PIC_WH) >> 16;
+ }
+#if 0
+ else {
+ pr_info("info width = %d, ucode width = %d\n",
+ hw->vmpeg4_amstream_dec_info.width,
+ READ_VREG(MP4_PIC_WH) >> 16);
+ }
+#endif
+
+ if (hw->vmpeg4_amstream_dec_info.height == 0) {
+ hw->vmpeg4_amstream_dec_info.height =
+ READ_VREG(MP4_PIC_WH) & 0xffff;
+ }
+#if 0
+ else {
+ pr_info("info height = %d, ucode height = %d\n",
+ hw->vmpeg4_amstream_dec_info.height,
+ READ_VREG(MP4_PIC_WH) & 0xffff);
+ }
+#endif
+ 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) {
+ 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;
+ }
+ } 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
+ }
+
+ if ((I_PICTURE == picture_type) ||
+ (P_PICTURE == picture_type)) {
+ offset = READ_VREG(MP4_OFFSET_REG);
+ if (hw->chunk) {
+ hw->pts_valid[index] = hw->chunk->pts_valid;
+ hw->pts[index] = hw->chunk->pts;
+ hw->pts64[index] = hw->chunk->pts64;
+ } else {
+ if (pts_lookup_offset_us64
+ (PTS_TYPE_VIDEO, offset, &pts, 3000,
+ &pts_us64) == 0) {
+ hw->pts_valid[index] = true;
+ hw->pts[index] = pts;
+ hw->pts64[index] = pts_us64;
+ hw->pts_hit++;
+ } else {
+ hw->pts_valid[index] = false;
+ hw->pts_missed++;
+ }
+ }
+ pr_debug("I/P offset 0x%x, pts_valid %d pts=0x%x\n",
+ offset, hw->pts_valid[index],
+ hw->pts[index]);
+ } else {
+ hw->pts_valid[index] = false;
+ hw->pts[index] = 0;
+ hw->pts64[index] = 0;
+ }
+
+ hw->buffer_info[index] = reg;
+ hw->vfbuf_use[index] = 0;
+
+ pr_debug("amvdec_mpeg4: decoded buffer %d, frame_type %s\n",
+ index,
+ (picture_type == I_PICTURE) ? "I" :
+ (picture_type == P_PICTURE) ? "P" : "B");
+
+ /* Buffer management
+ * todo: add sequence-end flush
+ */
+ if ((picture_type == I_PICTURE) ||
+ (picture_type == P_PICTURE)) {
+ 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];
+ }
+ } else {
+ /* if this is a B frame, then drop (depending on if
+ * there are two reference frames) or display
+ * immediately
+ */
+ if (hw->refs[1] == -1)
+ index = -1;
+ }
+
+ vmpeg4_save_hw_context(hw);
+
+ if (index < 0) {
+ schedule_work(&hw->work);
+ return IRQ_HANDLED;
+ }
+
+ reg = hw->buffer_info[index];
+ pts_valid = hw->pts_valid[index];
+ pts = hw->pts[index];
+ pts_us64 = hw->pts64[index];
+
+ pr_debug("queued buffer %d, pts = 0x%x, pts_valid=%d\n",
+ index, pts, pts_valid);
+
+ if (pts_valid) {
+ hw->last_anch_pts = pts;
+ hw->last_anch_pts_us64 = pts_us64;
+ hw->frame_num_since_last_anch = 0;
+ hw->vop_time_inc_since_last_anch = 0;
+ } else {
+ pts = hw->last_anch_pts;
+ pts_us64 = 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;
+
+ pts += hw->vop_time_inc_since_last_anch *
+ PTS_UNIT / time_increment_resolution;
+ pts_us64 += (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 = pts;
+ hw->last_anch_pts_us64 = pts_us64;
+ hw->vop_time_inc_since_last_anch = 0;
+ }
+ } else {
+ /* fixed VOP rate */
+ hw->frame_num_since_last_anch++;
+ pts += DUR2PTS(hw->frame_num_since_last_anch *
+ hw->vmpeg4_amstream_dec_info.rate);
+ pts_us64 += 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 = pts;
+ hw->last_anch_pts_us64 = pts_us64;
+ hw->frame_num_since_last_anch = 0;
+ }
+ }
+ }
+
+ if (reg & INTERLACE_FLAG) { /* interlace */
+ if (kfifo_get(&hw->newframe_q, &vf) == 0) {
+ pr_err
+ ("fatal error, no available buffer slot.");
+ return IRQ_HANDLED;
+ }
+
+ vf->index = index;
+ vf->width = hw->vmpeg4_amstream_dec_info.width;
+ vf->height = hw->vmpeg4_amstream_dec_info.height;
+ vf->bufWidth = 1920;
+ vf->flag = 0;
+ vf->orientation = hw->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
+ set_frame_info(hw, vf, index);
+
+ hw->vfbuf_use[index]++;
+
+ kfifo_put(&hw->display_q, (const struct vframe_s *)vf);
+
+ vf_notify_receiver(vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY,
+ NULL);
+
+ if (kfifo_get(&hw->newframe_q, &vf) == 0) {
+ pr_err("fatal error, no available buffer slot.");
+ hw->dec_result = DEC_RESULT_ERROR;
+ schedule_work(&hw->work);
+ return IRQ_HANDLED;
+ }
+
+ vf->index = index;
+ vf->width = hw->vmpeg4_amstream_dec_info.width;
+ vf->height = hw->vmpeg4_amstream_dec_info.height;
+ vf->bufWidth = 1920;
+ vf->flag = 0;
+ vf->orientation = hw->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
+ set_frame_info(hw, vf, index);
+
+ hw->vfbuf_use[index]++;
+
+ kfifo_put(&hw->display_q, (const struct vframe_s *)vf);
+
+ vf_notify_receiver(vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY,
+ NULL);
+
+ } else { /* progressive */
+ if (kfifo_get(&hw->newframe_q, &vf) == 0) {
+ pr_err("fatal error, no available buffer slot.");
+ return IRQ_HANDLED;
+ }
+
+ vf->index = index;
+ vf->width = hw->vmpeg4_amstream_dec_info.width;
+ vf->height = hw->vmpeg4_amstream_dec_info.height;
+ vf->bufWidth = 1920;
+ vf->flag = 0;
+ vf->orientation = hw->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
+ set_frame_info(hw, vf, index);
+
+
+ hw->vfbuf_use[index]++;
+
+ kfifo_put(&hw->display_q, (const struct vframe_s *)vf);
+
+ vf_notify_receiver(vdec->vf_provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY,
+ NULL);
+ }
+
+ hw->total_frame += repeat_cnt + 1;
+ hw->last_vop_time_inc = vop_time_inc;
+
+ schedule_work(&hw->work);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void vmpeg4_work(struct work_struct *work)
+{
+ struct vdec_mpeg4_hw_s *hw =
+ container_of(work, struct vdec_mpeg4_hw_s, work);
+
+ /* finished decoding one frame or error,
+ * notify vdec core to switch context
+ */
+ amvdec_stop();
+
+ if ((hw->dec_result == DEC_RESULT_DONE) ||
+ ((hw->chunk) &&
+ (input_frame_based(&(hw_to_vdec(hw))->input)))) {
+ if (!hw->ctx_valid)
+ hw->ctx_valid = 1;
+
+ vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk);
+ }
+
+ /* mark itself has all HW resource released and input released */
+ vdec_set_status(hw_to_vdec(hw), VDEC_STATUS_CONNECTED);
+
+ if (hw->vdec_cb)
+ hw->vdec_cb(hw_to_vdec(hw), 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;
+
+ 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;
+
+ if (kfifo_get(&hw->display_q, &vf))
+ 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;
+
+ hw->vfbuf_use[vf->index]--;
+
+ kfifo_put(&hw->newframe_q, (const struct vframe_s *)vf);
+}
+
+static int vmpeg_event_cb(int type, void *data, void *private_data)
+{
+ 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_status *vstatus)
+{
+ struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)vdec->private;
+
+ vstatus->width = hw->vmpeg4_amstream_dec_info.width;
+ vstatus->height = hw->vmpeg4_amstream_dec_info.height;
+ if (0 != hw->vmpeg4_amstream_dec_info.rate)
+ vstatus->fps = DURATION_UNIT /
+ hw->vmpeg4_amstream_dec_info.rate;
+ else
+ vstatus->fps = DURATION_UNIT;
+ vstatus->error_count = READ_VREG(MP4_ERR_COUNT);
+ vstatus->status = hw->stat;
+
+ return 0;
+}
+
+/****************************************/
+static int vmpeg4_canvas_init(struct vdec_mpeg4_hw_s *hw)
+{
+ int i;
+ u32 decbuf_size, decbuf_y_size;
+ struct vdec_s *vdec = hw_to_vdec(hw);
+ u32 decbuf_start;
+
+ int w = hw->vmpeg4_amstream_dec_info.width;
+ int h = hw->vmpeg4_amstream_dec_info.height;
+
+ if (w == 0)
+ w = 1920;
+ if (h == 0)
+ h = 1088;
+
+ w = ALIGN(w, 64);
+ h = ALIGN(h, 64);
+ decbuf_y_size = ALIGN(w * h, SZ_64K);
+ decbuf_size = ALIGN(w * h * 3/2, SZ_64K);
+
+ decbuf_start = hw->buf_start + CTX_DECBUF_OFFSET;
+
+ for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) {
+#ifdef NV21
+ unsigned int canvas = vdec->get_canvas(i, 2);
+#else
+ unsigned int canvas = vdec->get_canvas(i, 3);
+#endif
+
+ hw->canvas_spec[i] = canvas;
+
+#ifdef NV21
+ hw->canvas_config[i][0].phy_addr = decbuf_start +
+ i * decbuf_size;
+ hw->canvas_config[i][0].width = w;
+ hw->canvas_config[i][0].height = h;
+ hw->canvas_config[i][0].block_mode = CANVAS_BLKMODE_32X32;
+
+ canvas_config_config(canvas_y(canvas),
+ &hw->canvas_config[i][0]);
+
+ hw->canvas_config[i][1].phy_addr = decbuf_start +
+ i * decbuf_size + decbuf_y_size;
+ hw->canvas_config[i][1].width = w;
+ hw->canvas_config[i][1].height = h / 2;
+ hw->canvas_config[i][1].block_mode = CANVAS_BLKMODE_32X32;
+
+ canvas_config_config(canvas_u(canvas),
+ &hw->canvas_config[i][1]);
+#else
+ hw->canvas_config[i][0].phy_addr = decbuf_start +
+ i * decbuf_size;
+ hw->canvas_config[i][0].width = w;
+ hw->canvas_config[i][0].height = h;
+ hw->canvas_config[i][0].block_mode = CANVAS_BLKMODE_32X32;
+
+ canvas_config_config(canvas_y(canvas),
+ &hw->canvas_config[i][0]);
+
+ hw->canvas_config[i][1].phy_addr = decbuf_start +
+ i * decbuf_size + decbuf_y_size;
+ hw->canvas_config[i][1].width = w / 2;
+ hw->canvas_config[i][1].height = h / 2;
+ hw->canvas_config[i][1].block_mode = CANVAS_BLKMODE_32X32;
+
+ canvas_config_config(canvas_u(canvas),
+ &hw->canvas_config[i][1]);
+
+ hw->canvas_config[i][2].phy_addr = decbuf_start +
+ i * decbuf_size + decbuf_y_size +
+ decbuf_uv_size;
+ hw->canvas_config[i][2].width = w / 2;
+ hw->canvas_config[i][2].height = h / 2;
+ hw->canvas_config[i][2].block_mode = CANVAS_BLKMODE_32X32;
+
+ canvas_config_config(canvas_v(canvas),
+ &hw->canvas_config[i][2]);
+#endif
+ }
+
+ return 0;
+}
+
+static int vmpeg4_hw_ctx_restore(struct vdec_mpeg4_hw_s *hw)
+{
+ int index;
+
+
+ index = find_buffer(hw);
+ if (index < 0)
+ return -1;
+
+
+ if (vmpeg4_canvas_init(hw) < 0)
+ return -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(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]);
+
+ pr_debug("vmpeg4_hw_ctx_restore ref0=0x%x, ref1=0x%x, rec=0x%x, ctx_valid=%d\n",
+ READ_VREG(MREG_REF0),
+ READ_VREG(MREG_REF1),
+ READ_VREG(REC_CANVAS_ADDR),
+ hw->ctx_valid);
+
+ /* notify ucode the buffer start address */
+ WRITE_VREG(MEM_OFFSET_REG, hw->buf_start);
+
+ /* disable PSCALE for hardware sharing */
+ WRITE_VREG(PSCALE_CTRL, 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);
+
+ /* 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->vmpeg4_amstream_dec_info.width << 16) |
+ hw->vmpeg4_amstream_dec_info.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 (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->frame_width = hw->frame_height = hw->frame_dur = hw->frame_prog = 0;
+
+ 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->frame_num_since_last_anch = 0;
+
+ hw->pts_hit = hw->pts_missed = hw->pts_i_hit = hw->pts_i_missed = 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);
+ }
+
+ INIT_WORK(&hw->work, vmpeg4_work);
+}
+
+static s32 vmpeg4_init(struct vdec_mpeg4_hw_s *hw)
+{
+ int trickmode_fffb = 0;
+
+ query_video_status(0, &trickmode_fffb);
+
+ pr_info("vmpeg4_init\n");
+
+ amvdec_enable();
+
+ vmpeg4_local_init(hw);
+
+ return 0;
+}
+
+static bool run_ready(struct vdec_s *vdec)
+{
+ int index;
+ struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)vdec->private;
+
+ index = find_buffer(hw);
+
+ return index >= 0;
+}
+
+static void run(struct vdec_s *vdec, void (*callback)(struct vdec_s *, void *),
+ void *arg)
+{
+ struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)vdec->private;
+ int save_reg = READ_VREG(POWER_CTL_VLD);
+ int ret = -1,size = -1;
+ char *buf = vmalloc(0x1000 * 16);
+ if (IS_ERR_OR_NULL(buf))
+ return;
+
+ /* 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->vdec_cb_arg = arg;
+ hw->vdec_cb = callback;
+
+ ret = vdec_prepare_input(vdec, &hw->chunk);
+ if (ret < 0) {
+ pr_debug("amvdec_mpeg4: Input not ready\n");
+ hw->dec_result = DEC_RESULT_AGAIN;
+ schedule_work(&hw->work);
+ vfree(buf);
+ return;
+ }
+
+ vdec_enable_input(vdec);
+
+ if (hw->chunk)
+ pr_debug("input chunk offset %d, size %d\n",
+ hw->chunk->offset, hw->chunk->size);
+
+ hw->dec_result = DEC_RESULT_NONE;
+
+ if (hw->vmpeg4_amstream_dec_info.format ==
+ VIDEO_DEC_FORMAT_MPEG4_3) {
+ size = get_firmware_data(VIDEO_DEC_MPEG4_3, buf);
+
+ pr_info("load VIDEO_DEC_FORMAT_MPEG4_3\n");
+ } else if (hw->vmpeg4_amstream_dec_info.format ==
+ VIDEO_DEC_FORMAT_MPEG4_4) {
+ size = get_firmware_data(VIDEO_DEC_MPEG4_4, buf);
+
+ pr_info("load VIDEO_DEC_FORMAT_MPEG4_4\n");
+ } else if (hw->vmpeg4_amstream_dec_info.format ==
+ VIDEO_DEC_FORMAT_MPEG4_5) {
+ size = get_firmware_data(VIDEO_DEC_MPEG4_5, buf);
+
+ pr_info("load VIDEO_DEC_FORMAT_MPEG4_5\n");
+ } else if (hw->vmpeg4_amstream_dec_info.format ==
+ VIDEO_DEC_FORMAT_H263) {
+ size = get_firmware_data(VIDEO_DEC_H263, buf);
+
+ pr_info("load VIDEO_DEC_FORMAT_H263\n");
+ }
+
+ if (size < 0) {
+ pr_err("get firmware fail.");
+ vfree(buf);
+ return;
+ }
+
+ if (amvdec_vdec_loadmc_buf_ex(vdec, buf, size) < 0) {
+ hw->dec_result = DEC_RESULT_ERROR;
+ schedule_work(&hw->work);
+ vfree(buf);
+ return;
+ }
+
+ vfree(buf);
+
+ if (vmpeg4_hw_ctx_restore(hw) < 0) {
+ hw->dec_result = DEC_RESULT_ERROR;
+ pr_err("amvdec_mpeg4: error HW context restore\n");
+ schedule_work(&hw->work);
+ return;
+ }
+
+ /* wmb before ISR is handled */
+ wmb();
+
+ amvdec_start();
+}
+
+static void reset(struct vdec_s *vdec)
+{
+ struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)vdec->private;
+
+ pr_info("amvdec_mpeg4: reset.\n");
+
+ vmpeg4_local_init(hw);
+
+ hw->ctx_valid = false;
+}
+
+static int amvdec_mpeg4_probe(struct platform_device *pdev)
+{
+ struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
+ struct vdec_mpeg4_hw_s *hw = NULL;
+
+ pr_info("amvdec_mpeg4[%d] probe start.\n", pdev->id);
+
+ if (pdata == NULL) {
+ pr_err("ammvdec_mpeg4 memory resource undefined.\n");
+ return -EFAULT;
+ }
+
+ hw = (struct vdec_mpeg4_hw_s *)devm_kzalloc(&pdev->dev,
+ sizeof(struct vdec_mpeg4_hw_s), GFP_KERNEL);
+ if (hw == NULL) {
+ pr_info("\namvdec_mpeg4 decoder driver alloc failed\n");
+ return -ENOMEM;
+ }
+
+ pdata->private = hw;
+ pdata->dec_status = dec_status;
+ /* pdata->set_trickmode = set_trickmode; */
+ pdata->run_ready = run_ready;
+ pdata->run = run;
+ pdata->reset = reset;
+ pdata->irq_handler = vmpeg4_isr;
+
+ pdata->id = pdev->id;
+
+ 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);
+
+ vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name,
+ &vf_provider_ops, pdata);
+
+ platform_set_drvdata(pdev, pdata);
+
+ hw->platform_dev = pdev;
+ hw->cma_dev = pdata->cma_dev;
+
+ hw->cma_alloc_count = PAGE_ALIGN(DEFAULT_MEM_SIZE) / PAGE_SIZE;
+ hw->cma_alloc_addr = codec_mm_alloc_for_dma(MEM_NAME,
+ hw->cma_alloc_count,
+ 4, CODEC_MM_FLAGS_FOR_VDECODER);
+
+ if (!hw->cma_alloc_addr) {
+ pr_err("codec_mm alloc failed, request buf size 0x%lx\n",
+ hw->cma_alloc_count * PAGE_SIZE);
+ hw->cma_alloc_count = 0;
+ return -ENOMEM;
+ }
+ hw->buf_start = hw->cma_alloc_addr;
+ hw->buf_size = DEFAULT_MEM_SIZE;
+
+ if (pdata->sys_info)
+ hw->vmpeg4_amstream_dec_info = *pdata->sys_info;
+
+ if (vmpeg4_init(hw) < 0) {
+ pr_err("amvdec_mpeg4 init failed.\n");
+
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int amvdec_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);
+
+
+ amvdec_disable();
+
+ if (hw->cma_alloc_addr) {
+ pr_info("codec_mm release buffer 0x%lx\n", hw->cma_alloc_addr);
+ codec_mm_free_for_dma(MEM_NAME, hw->cma_alloc_addr);
+ hw->cma_alloc_count = 0;
+ }
+
+ pr_info("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_info("total frame %d, rate %d\n", hw->total_frame,
+ hw->vmpeg4_amstream_dec_info.rate);
+
+ return 0;
+}
+
+/****************************************/
+
+static struct platform_driver amvdec_mpeg4_driver = {
+ .probe = amvdec_mpeg4_probe,
+ .remove = amvdec_mpeg4_remove,
+#ifdef CONFIG_PM
+ .suspend = amvdec_suspend,
+ .resume = amvdec_resume,
+#endif
+ .driver = {
+ .name = DRIVER_NAME,
+ }
+};
+
+static struct codec_profile_t amvdec_mpeg4_profile = {
+ .name = "mmpeg4",
+ .profile = ""
+};
+
+static int __init amvdec_mmpeg4_driver_init_module(void)
+{
+ pr_info("amvdec_mmpeg4 module init\n");
+
+ if (platform_driver_register(&amvdec_mpeg4_driver)) {
+ pr_err("failed to register amvdec_mpeg4 driver\n");
+ return -ENODEV;
+ }
+ vcodec_profile_register(&amvdec_mpeg4_profile);
+ return 0;
+}
+
+static void __exit amvdec_mmpeg4_driver_remove_module(void)
+{
+ pr_info("amvdec_mmpeg4 module remove.\n");
+
+ platform_driver_unregister(&amvdec_mpeg4_driver);
+}
+
+/****************************************/
+
+module_init(amvdec_mmpeg4_driver_init_module);
+module_exit(amvdec_mmpeg4_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/vreal.c b/drivers/frame_provider/decoder/real/vreal.c
new file mode 100644
index 0000000..d47fa99
--- a/dev/null
+++ b/drivers/frame_provider/decoder/real/vreal.c
@@ -0,0 +1,1022 @@
+/*
+ * 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/parser/streambuf.h"
+#include "../../../stream_input/parser/streambuf_reg.h"
+#include "../../../stream_input/parser/rmparser.h"
+
+#include "vreal.h"
+#include <linux/amlogic/media/registers/register.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)
+
+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 void 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 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 unsigned long buf_start;
+static u32 buf_size, 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 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 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 (0 == pictype) { /* 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;
+
+ kfifo_put(&display_q, (const struct vframe_s *)vf);
+
+ 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_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 >= 0) && (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);
+ }
+ }
+
+ 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);
+ }
+
+ timer->expires = jiffies + PUT_INTERVAL;
+
+ add_timer(timer);
+}
+
+int vreal_dec_status(struct vdec_s *vdec, struct vdec_status *vstatus)
+{
+ vstatus->width = vreal_amstream_dec_info.width;
+ vstatus->height = vreal_amstream_dec_info.height;
+ if (0 != vreal_amstream_dec_info.rate)
+ vstatus->fps = 96000 / vreal_amstream_dec_info.rate;
+ else
+ vstatus->fps = 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;
+}
+
+/****************************************/
+static void vreal_canvas_init(void)
+{
+ int i;
+ u32 canvas_width, canvas_height;
+ u32 decbuf_size, decbuf_y_size, decbuf_uv_size;
+ u32 disp_addr = 0xffffffff;
+ u32 buff_off = 0;
+ 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
+ /* canvas_width = 1920;
+ canvas_height = 1088;
+ decbuf_y_size = 0x200000;
+ decbuf_uv_size = 0x80000;
+ decbuf_size = 0x300000;*/
+ }
+
+ if (is_vpp_postblend()) {
+ struct canvas_s cur_canvas;
+
+ canvas_read((READ_VCBUS_REG(VD1_IF0_CANVAS0) & 0xff),
+ &cur_canvas);
+ disp_addr = (cur_canvas.addr + 7) >> 3;
+ }
+
+ for (i = 0; i < 4; i++) {
+ u32 one_buf_start = buf_start + buff_off;
+ if (((one_buf_start + 7) >> 3) == disp_addr) {
+ /*last disp buffer, to next..*/
+ buff_off += decbuf_size;
+ one_buf_start = buf_start + buff_off;
+ pr_info("one_buf_start %d,=== %x disp_addr %x",
+ i, one_buf_start, disp_addr);
+ }
+ if (buff_off < 0x01000000 &&
+ buff_off + decbuf_size > 0x0f00000){
+ /*0x01b00000 is references buffer.
+ to next 16M;*/
+ buff_off = 16 * SZ_1M;/*next 16M*/
+ one_buf_start = buf_start + buff_off;
+ }
+ if (buff_off + decbuf_size > buf_size) {
+ pr_err("ERROR::too small buffer for buf%d %d x%d ,size =%d\n",
+ i,
+ canvas_width,
+ canvas_height,
+ buf_size);
+ }
+ pr_info("alloced buffer %d at %x,%d\n",
+ i, one_buf_start, decbuf_size);
+ #ifdef NV21
+ canvas_config(2 * i + 0,
+ one_buf_start,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+ canvas_config(2 * i + 1,
+ one_buf_start +
+ decbuf_y_size, canvas_width,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+ #else
+ canvas_config(3 * i + 0,
+ one_buf_start,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+ canvas_config(3 * i + 1,
+ one_buf_start +
+ decbuf_y_size, canvas_width / 2,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+ canvas_config(3 * i + 2,
+ one_buf_start +
+ decbuf_y_size + decbuf_uv_size,
+ canvas_width / 2, canvas_height / 2,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+ #endif
+ buff_off = buff_off + decbuf_size;
+ }
+}
+
+static void vreal_prot_init(void)
+{
+#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_MPEG_REG(RESET0_REGISTER, RESET_IQIDCT | RESET_MC);
+#endif
+
+ 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_MPEG_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
+}
+
+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);
+ }
+
+ 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);
+
+ return;
+}
+
+s32 vreal_init(struct vdec_s *vdec)
+{
+ int ret = -1,size = -1;
+ 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();
+
+ pr_info("rm parser init failed\n");
+ return ret;
+ }
+
+ if (vreal_amstream_dec_info.format == VIDEO_DEC_FORMAT_REAL_8) {
+ load_block_data((void *)pic_sz_tbl, 12);
+
+ /* TODO: need to load the table into lmem */
+ WRITE_VREG(LMEM_DMA_ADR, (unsigned)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);
+
+ 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);
+
+ pr_info("load VIDEO_DEC_FORMAT_REAL_9\n");
+ } else
+ pr_info("unsurpported real format\n");
+
+ if (size < 0) {
+ pr_err("get firmware fail.");
+ vfree(buf);
+ return -1;
+ }
+
+ if (amvdec_loadmc_ex(VFORMAT_REAL, NULL, buf) < 0) {
+ amvdec_disable();
+ vfree(buf);
+ return -EBUSY;
+ }
+
+ vfree(buf);
+
+ stat |= STAT_MC_LOAD;
+
+ /* enable AMRISC side protocol */
+ vreal_prot_init();
+
+ if (vdec_request_irq(VDEC_IRQ_1, vreal_isr,
+ "vreal-irq", (void *)vreal_dec_id)) {
+ 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
+
+ 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;
+}
+
+/*TODO encoder*/
+/* extern void AbortEncodeWithVdec2(int abort); */
+
+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;
+ }
+
+ buf_start = pdata->mem_start;
+ buf_size = pdata->mem_end - pdata->mem_start + 1;
+ buf_offset = buf_start - RM_DEF_BUFFER_ADDR;
+
+ if (pdata->sys_info)
+ vreal_amstream_dec_info = *pdata->sys_info;
+ /* #if (MESON_CPU_TYPE == MESON_CPU_TYPE_MESON8)&&(HAS_HDEC)) */
+ /* if(IS_MESON_M8_CPU){ */
+ if (has_hdec()) {
+ /* disable vdec2 dblk when miracast. */
+ int count = 0;
+ if (get_vdec2_usage() != USAGE_NONE)
+ /*TODO encoder */
+ /* AbortEncodeWithVdec2(1); */
+ while ((get_vdec2_usage() != USAGE_NONE)
+ && (count < 10)) {
+ msleep(50);
+ count++;
+ }
+
+ if (get_vdec2_usage() != USAGE_NONE) {
+ pr_info("\namvdec_real_probe --- stop vdec2 fail.\n");
+ return -EBUSY;
+ }
+ }
+ /* } */
+ /* #endif */
+
+ pdata->dec_status = vreal_dec_status;
+
+ if (vreal_init(pdata) < 0) {
+ pr_info("amvdec_real init failed.\n");
+ /* #if (MESON_CPU_TYPE == MESON_CPU_TYPE_MESON8)&&(HAS_HDEC) */
+ /* if(IS_MESON_M8_CPU) */
+ if (has_hdec()) {
+ /*TODO encoder */
+ /* AbortEncodeWithVdec2(0); */
+ }
+ /* #endif */
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int amvdec_real_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 *)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) {
+ 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 (MESON_CPU_TYPE == MESON_CPU_TYPE_MESON8)&&(HAS_HDEC) */
+ /* if(IS_MESON_M8_CPU) */
+ if (has_hdec()) {
+ /*TODO encoder */
+ /* AbortEncodeWithVdec2(0); */
+ }
+ /* #endif */
+ pr_info("frame duration %d, frames %d\n", frame_dur, frame_count);
+ return 0;
+}
+
+/****************************************/
+
+static struct platform_driver amvdec_real_driver = {
+ .probe = amvdec_real_probe,
+ .remove = amvdec_real_remove,
+#ifdef CONFIG_PM
+ .suspend = amvdec_suspend,
+ .resume = amvdec_resume,
+#endif
+ .driver = {
+ .name = DRIVER_NAME,
+ }
+};
+
+static struct codec_profile_t amvdec_real_profile = {
+ .name = "real",
+ .profile = "rmvb,1080p+"
+};
+
+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);
+ 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_param(stat, uint, 0664);
+MODULE_PARM_DESC(stat, "\n amvdec_real stat\n");
+
+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..8c0d51a
--- a/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..b7e6184
--- a/dev/null
+++ b/drivers/frame_provider/decoder/utils/Makefile
@@ -0,0 +1,4 @@
+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
diff --git a/drivers/frame_provider/decoder/utils/amvdec.c b/drivers/frame_provider/decoder/utils/amvdec.c
new file mode 100644
index 0000000..a5e1462
--- a/dev/null
+++ b/drivers/frame_provider/decoder/utils/amvdec.c
@@ -0,0 +1,998 @@
+/*
+ * 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.
+ *
+*/
+
+#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 "../../../common/firmware/firmware.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_type() >= 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 / 10;
+
+ 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 / 10;
+
+ 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 / 10;
+
+ 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 / 10;
+ 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, s32(*load)(const u32 *))
+{
+ int err;
+
+ if (!vdec->mc_loaded) {
+ int loaded;
+ loaded = get_decoder_firmware_data(vdec->format,
+ name, (u8 *)(vdec->mc), (4096 * 4 * 4));
+ if (loaded <= 0)
+ return -1;
+
+ vdec->mc_loaded = true;
+ }
+
+ err = (*load)(vdec->mc);
+ if (err < 0) {
+ pr_err("loading firmware %s to vdec ram failed!\n", name);
+ return err;
+ }
+ pr_debug("loading firmware %s to vdec ram ok!\n", name);
+ 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;
+ }
+ pr_debug("loading firmware to vdec ram ok!\n");
+ 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);
+ return err;
+ }
+ vfree(mc_addr);
+ pr_debug("loading firmware %s to vdec ram ok!\n", name);
+ 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 amvdec_loadmc_ex(enum vformat_e type, const char *name, char *def)
+{
+ return am_loadmc_ex(type, name, def, &amvdec_loadmc);
+}
+EXPORT_SYMBOL(amvdec_loadmc_ex);
+s32 amvdec_vdec_loadmc_ex(struct vdec_s *vdec, const char *name)
+{
+ return am_vdec_loadmc_ex(vdec, name, &amvdec_loadmc);
+}
+EXPORT_SYMBOL(amvdec_vdec_loadmc_ex);
+
+s32 amvdec_vdec_loadmc_buf_ex(struct vdec_s *vdec, char *buf, int size)
+{
+ 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())
+ return am_loadmc_ex(type, name, def, &amhevc_loadmc);
+ else
+ return 0;
+}
+EXPORT_SYMBOL(amhevc_loadmc_ex);
+s32 amhevc_vdec_loadmc_ex(struct vdec_s *vdec, const char *name)
+{
+ if (has_hevc_vdec())
+ return am_vdec_loadmc_ex(vdec, name, &amhevc_loadmc);
+ else
+ return 0;
+}
+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_type() >= 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_MPEG_REG(RESET0_REGISTER);
+ READ_MPEG_REG(RESET0_REGISTER);
+ READ_MPEG_REG(RESET0_REGISTER);
+ READ_MPEG_REG(RESET0_REGISTER);
+
+ WRITE_MPEG_REG(RESET0_REGISTER, RESET_VCPU | RESET_CCPU);
+
+ READ_MPEG_REG(RESET0_REGISTER);
+ READ_MPEG_REG(RESET0_REGISTER);
+ READ_MPEG_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;
+
+ WRITE_VREG(MPSR, 0);
+ WRITE_VREG(CPSR, 0);
+
+ while (READ_VREG(IMEM_DMA_CTRL) & 0x8000) {
+ if (time_after(jiffies, timeout))
+ break;
+ }
+
+ /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+ if (get_cpu_type() >= 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_MPEG_REG(RESET0_REGISTER, RESET_VCPU | RESET_CCPU);
+
+ /* additional cbus dummy register reading for timing control */
+ READ_MPEG_REG(RESET0_REGISTER);
+ READ_MPEG_REG(RESET0_REGISTER);
+ READ_MPEG_REG(RESET0_REGISTER);
+ READ_MPEG_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;
+
+ 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;
+
+ WRITE_VREG(HEVC_MPSR, 0);
+ WRITE_VREG(HEVC_CPSR, 0);
+
+ while (READ_VREG(HEVC_IMEM_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);
+
+ 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 */
+
+ 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);
+ return 0;
+}
+EXPORT_SYMBOL(amhevc_suspend);
+
+int amhevc_resume(struct platform_device *dev)
+{
+ if (has_hevc_vdec())
+ amhevc_pg_enable(true);
+ 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 == 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);
+#endif
+
+MODULE_DESCRIPTION("Amlogic Video Decoder Utility Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tim Yao <timyao@amlogic.com>");
diff --git a/drivers/frame_provider/decoder/utils/amvdec.h b/drivers/frame_provider/decoder/utils/amvdec.h
new file mode 100644
index 0000000..c6f11d7
--- a/dev/null
+++ b/drivers/frame_provider/decoder/utils/amvdec.h
@@ -0,0 +1,86 @@
+/*
+ * 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 */
+
+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(struct vdec_s *vdec, const char *name);
+
+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(struct vdec_s *vdec, const char *name);
+s32 amvdec_vdec_loadmc_buf_ex(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..b9c64f7
--- a/dev/null
+++ b/drivers/frame_provider/decoder/utils/config_parser.c
@@ -0,0 +1,62 @@
+/*
+ * 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;
+}
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..e10210a
--- a/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..7a858d5
--- a/dev/null
+++ b/drivers/frame_provider/decoder/utils/decoder_bmmu_box.c
@@ -0,0 +1,425 @@
+/*
+ * 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.
+ *
+ */
+#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>
+
+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 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;
+}
+
+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;
+ 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;
+ 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;
+ 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;
+ }
+ }
+ if (!mm) {
+ mm = codec_mm_alloc(box->name, size, align, memflags);
+ if (mm) {
+ box->mm_list[idx] = mm;
+ box->total_size += mm->buffer_size;
+ }
+ }
+ 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->max_mm_num - 1);
+ 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;
+ }
+ 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_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;
+ if (decoder_bmmu_box_get_mem_size(handle, idx) >= size)
+ 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);
+ } else {
+ ret = -ENOMEM;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(decoder_bmmu_box_alloc_idx_wait);
+
+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 (!pbuf)
+ pbuf = sbuf;
+
+#define BUFPRINT(args...) \
+ do {\
+ s = sprintf(pbuf, 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) < 128)
+ 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);
+ }
+ }
+#undef BUFPRINT
+ if (!buf)
+ pr_info("%s", sbuf);
+
+ 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 (!pbuf)
+ pbuf = sbuf;
+
+#define BUFPRINT(args...) \
+ do {\
+ s = sprintf(pbuf, 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, player_id:%d, max_num:%d, size:%d\n",
+ i, box->name,
+ box->channel_id,
+ box->max_mm_num,
+ box->total_size);
+ if (buf) {
+ tsize += decoder_bmmu_box_dump(box, pbuf, size - tsize);
+ if (tsize > 0)
+ pbuf += tsize;
+ } 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 struct class_attribute decoder_bmmu_box_class_attrs[] = {
+ __ATTR_RO(box_dump),
+ __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..99aa89b
--- a/dev/null
+++ b/drivers/frame_provider/decoder/utils/decoder_bmmu_box.h
@@ -0,0 +1,63 @@
+/*
+ * 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);
+
+#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);
+
+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..26440fe
--- a/dev/null
+++ b/drivers/frame_provider/decoder/utils/decoder_mmu_box.c
@@ -0,0 +1,383 @@
+/*
+ * 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;
+ 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;
+}
+
+
+
+void *decoder_mmu_box_alloc_box(const char *name,
+ int channel_id,
+ int max_num,
+ int min_size_M)
+/*min_size_M:wait alloc this size*/
+{
+ struct decoder_mmu_box *box;
+ int size;
+
+ 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;
+ 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);
+ 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 {
+ 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);
+ if (!sc) {
+ mutex_unlock(&box->mutex);
+ pr_err("alloc mmu failed, need pages=%d\n",
+ num_pages);
+ return -1;
+ }
+ box->sc_list[idx] = sc;
+ }
+
+ for (i = 0; i < num_pages; i++)
+ mmu_index_adr[i] = PAGE_INDEX(sc->pages_list[i]);
+ mmu_index_adr[num_pages] = 0;
+
+ 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->max_sc_num - 1);
+ 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->max_sc_num - 1);
+ 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;
+ } mutex_unlock(&box->mutex);
+ 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, 200);
+ box->sc_list[i] = NULL;
+ }
+ }
+ mutex_unlock(&box->mutex);
+ decoder_mmu_box_mgr_del_box(box);
+ kfree(box);
+ codec_mm_scatter_mgt_delay_free_swith(0, 2000, 0);
+ 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 (!pbuf)
+ pbuf = sbuf;
+
+ #define BUFPRINT(args...) \
+ do {\
+ s = sprintf(pbuf, 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;
+
+ #define BUFPRINT(args...) \
+ do {\
+ s = sprintf(pbuf, 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, player_id:%d, max_num:%d\n",
+ i,
+ box->name,
+ box->channel_id,
+ box->max_sc_num);
+ if (buf) {
+ tsize += decoder_mmu_box_dump(box, pbuf, size - tsize);
+ if (tsize > 0)
+ pbuf += tsize;
+ } 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..387dd24
--- a/dev/null
+++ b/drivers/frame_provider/decoder/utils/decoder_mmu_box.h
@@ -0,0 +1,45 @@
+/*
+ * 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 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);
+int decoder_mmu_box_init(void);
+void decoder_mmu_box_exit(void);
+
+#endif
diff --git a/drivers/frame_provider/decoder/utils/utils.c b/drivers/frame_provider/decoder/utils/utils.c
new file mode 100644
index 0000000..33ab765
--- a/dev/null
+++ b/drivers/frame_provider/decoder/utils/utils.c
@@ -0,0 +1,66 @@
+/*
+ * 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"
+
+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();
+
+ 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();
+}
+
+module_init(decoder_common_init);
+module_exit(decoder_common_exit);
diff --git a/drivers/frame_provider/decoder/utils/vdec.c b/drivers/frame_provider/decoder/utils/vdec.c
new file mode 100644
index 0000000..7c54882
--- a/dev/null
+++ b/drivers/frame_provider/decoder/utils/vdec.c
@@ -0,0 +1,2907 @@
+/*
+ * 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.
+ *
+*/
+
+#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>
+#include <linux/amlogic/media/vfm/vfm_ext.h>
+
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include "vdec.h"
+#ifdef CONFIG_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/media/old_cpu_version.h>
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include <linux/amlogic/media/video_sink/video_keeper.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;
+static int poweron_clock_level;
+static int keep_vdec_mem;
+static unsigned int debug_trace_num = 16 * 20;
+static int step_mode;
+static unsigned int clk_config;
+
+static struct page *vdec_cma_page;
+int vdec_mem_alloced_from_codec, delay_release;
+static unsigned long reserved_mem_start, reserved_mem_end;
+static int hevc_max_reset_count;
+static DEFINE_SPINLOCK(vdec_spin_lock);
+
+#define HEVC_TEST_LIMIT 100
+#define GXBB_REV_A_MINOR 0xA
+
+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_core_s {
+ struct list_head connected_vdec_list;
+ spinlock_t lock;
+
+ atomic_t vdec_nr;
+ struct vdec_s *vfm_vdec;
+ struct vdec_s *active_vdec;
+ struct platform_device *vdec_core_platform_device;
+ struct device *cma_dev;
+ unsigned long mem_start;
+ unsigned long mem_end;
+
+ struct semaphore sem;
+ struct task_struct *thread;
+
+ struct vdec_isr_context_s isr_context[VDEC_IRQ_MAX];
+ int power_ref_count[VDEC_MAX];
+};
+
+static struct vdec_core_s *vdec_core;
+
+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);
+}
+
+static int get_canvas(unsigned int index, unsigned int base)
+{
+ int start;
+ int canvas_index = index * base;
+
+ 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) {
+ return start;
+ } else if (base == 2) {
+ return ((start + 1) << 16) | ((start + 1) << 8) | start;
+ } else if (base == 3) {
+ return ((start + 2) << 16) | ((start + 1) << 8) | start;
+ } else if (base == 4) {
+ return (((start + 3) << 24) | (start + 2) << 16) |
+ ((start + 1) << 8) | start;
+ }
+
+ return -1;
+}
+
+
+int vdec_status(struct vdec_s *vdec, struct vdec_status *vstatus)
+{
+ if (vdec->dec_status)
+ return vdec->dec_status(vdec, vstatus);
+
+ return -1;
+}
+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 -1;
+}
+EXPORT_SYMBOL(vdec_set_trickmode);
+
+/*
+* 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);
+
+static bool hevc_workaround_needed(void)
+{
+ return (get_cpu_type() == MESON_CPU_MAJOR_ID_GXBB) &&
+ (get_meson_cpu_version(MESON_CPU_VERSION_LVL_MINOR)
+ == GXBB_REV_A_MINOR);
+}
+
+struct device *get_codec_cma_device(void)
+{
+ return vdec_core->cma_dev;
+}
+
+static unsigned int get_mmu_mode(void)
+{
+ return 1;//DEBUG_TMP
+}
+
+#ifdef CONFIG_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"
+};
+
+static int vdec_default_buf_size[] = {
+ 32, 32, /*"amvdec_mpeg12",*/
+ 32, 0, /*"amvdec_mpeg4",*/
+ 48, 0, /*"amvdec_h264",*/
+ 32, 32, /*"amvdec_mjpeg",*/
+ 32, 32, /*"amvdec_real",*/
+ 32, 32, /*"amjpegdec",*/
+ 32, 32, /*"amvdec_vc1",*/
+ 32, 32, /*"amvdec_avs",*/
+ 32, 32, /*"amvdec_yuv",*/
+ 64, 64, /*"amvdec_h264mvc",*/
+ 64, 64, /*"amvdec_h264_4k2k", else alloc on decoder*/
+ 48, 48, /*"amvdec_h265", else alloc on decoder*/
+ 0, 0, /* avs encoder */
+ 0, 0, /* jpg encoder */
+#ifdef VP9_10B_MMU
+ 24, 24, /*"amvdec_vp9", else alloc on decoder*/
+#else
+ 32, 32,
+#endif
+ 0
+};
+
+#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"
+};
+
+static int vdec_default_buf_size[] = {
+ 32, /*"amvdec_mpeg12",*/
+ 32, /*"amvdec_mpeg4",*/
+ 48, /*"amvdec_h264",*/
+ 32, /*"amvdec_mjpeg",*/
+ 32, /*"amvdec_real",*/
+ 32, /*"amjpegdec",*/
+ 32, /*"amvdec_vc1",*/
+ 32, /*"amvdec_avs",*/
+ 32, /*"amvdec_yuv",*/
+ 64, /*"amvdec_h264mvc",*/
+ 64, /*"amvdec_h264_4k2k", else alloc on decoder*/
+ 48, /*"amvdec_h265", else alloc on decoder*/
+ 0, /* avs encoder */
+ 0, /* jpg encoder */
+#ifdef VP9_10B_MMU
+ 24, /*"amvdec_vp9", else alloc on decoder*/
+#else
+ 32,
+#endif
+};
+#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;
+
+ 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;
+
+ if (port->type & PORT_TYPE_DECODER_SCHED)
+ type = (port->type & PORT_TYPE_FRAME) ?
+ VDEC_TYPE_FRAME_BLOCK :
+ VDEC_TYPE_STREAM_PARSER;
+
+ vdec = vzalloc(sizeof(struct vdec_s));
+
+ /* TBD */
+ if (vdec) {
+ vdec->magic = 0x43454456;
+ vdec->id = 0;
+ vdec->type = type;
+ vdec->port = port;
+ vdec->sys_info = &vdec->sys_info_store;
+
+ INIT_LIST_HEAD(&vdec->list);
+
+ vdec_input_init(&vdec->input, vdec);
+
+ atomic_inc(&vdec_core->vdec_nr);
+
+ if (master) {
+ vdec->master = master;
+ master->slave = vdec;
+ master->sched = 1;
+ }
+ }
+
+ pr_info("vdec_create instance %p, total %d\n", vdec,
+ atomic_read(&vdec_core->vdec_nr));
+
+ return vdec;
+}
+EXPORT_SYMBOL(vdec_create);
+
+int vdec_set_format(struct vdec_s *vdec, int format)
+{
+ vdec->format = format;
+
+ if (vdec->slave)
+ vdec->slave->format = format;
+
+ return 0;
+}
+EXPORT_SYMBOL(vdec_set_format);
+
+int vdec_set_pts(struct vdec_s *vdec, u32 pts)
+{
+ vdec->pts = pts;
+ vdec->pts_valid = true;
+ return 0;
+}
+EXPORT_SYMBOL(vdec_set_pts);
+
+int vdec_set_pts64(struct vdec_s *vdec, u64 pts64)
+{
+ vdec->pts64 = pts64;
+ vdec->pts_valid = true;
+ return 0;
+}
+EXPORT_SYMBOL(vdec_set_pts64);
+
+void vdec_set_status(struct vdec_s *vdec, int status)
+{
+ vdec->status = status;
+}
+EXPORT_SYMBOL(vdec_set_status);
+
+void vdec_set_next_status(struct vdec_s *vdec, int status)
+{
+ 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);
+
+/* 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);
+
+/*
+*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)
+#define FIFO_ALIGN 8
+int vdec_prepare_input(struct vdec_s *vdec, struct vframe_chunk_s **p)
+{
+ struct vdec_input_s *input = (vdec->master) ?
+ &vdec->master->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);
+
+ dummy = READ_MPEG_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,
+ 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,
+ 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, 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, FIFO_ALIGN));
+
+ /* set endian */
+ SET_VREG_MASK(HEVC_STREAM_CONTROL, 7 << 4);
+ }
+
+ *p = chunk;
+ return chunk->size;
+
+ } else {
+ u32 rp = 0, wp = 0, fifo_len = 0;
+ int size;
+ /* stream based */
+ if (input->swap_valid) {
+ if (input->target == VDEC_INPUT_TARGET_VLD) {
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 0);
+
+ /* restore read side */
+ WRITE_VREG(VLD_MEM_SWAP_ADDR,
+ page_to_phys(input->swap_page));
+ WRITE_VREG(VLD_MEM_SWAP_CTL, 1);
+
+ while (READ_VREG(VLD_MEM_SWAP_CTL) & (1<<7))
+ ;
+ WRITE_VREG(VLD_MEM_SWAP_CTL, 0);
+
+ /* 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));
+
+ /* update write side */
+ WRITE_VREG(VLD_MEM_VIFIFO_WP,
+ READ_MPEG_REG(PARSER_VIDEO_WP));
+
+ 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,
+ page_to_phys(input->swap_page));
+ WRITE_VREG(HEVC_STREAM_SWAP_CTRL, 1);
+
+ while (READ_VREG(HEVC_STREAM_SWAP_CTRL)
+ & (1<<7))
+ ;
+ WRITE_VREG(HEVC_STREAM_SWAP_CTRL, 0);
+
+ /* 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 */
+
+ /* update write side */
+ WRITE_VREG(HEVC_STREAM_WR_PTR,
+ READ_MPEG_REG(PARSER_VIDEO_WP));
+
+ wp = READ_VREG(HEVC_STREAM_WR_PTR);
+ }
+
+ } else {
+ 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);
+ WRITE_VREG(VLD_MEM_VIFIFO_WP,
+ READ_MPEG_REG(PARSER_VIDEO_WP));
+
+ rp = READ_VREG(VLD_MEM_VIFIFO_RP);
+
+ /* enable */
+ WRITE_VREG(VLD_MEM_VIFIFO_CONTROL,
+ (0x11 << 16) | (1<<10));
+
+ 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,
+ input->start);
+ WRITE_VREG(HEVC_STREAM_WR_PTR,
+ READ_MPEG_REG(PARSER_VIDEO_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;
+
+ /* 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))
+ 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);
+
+void vdec_set_flag(struct vdec_s *vdec, u32 flag)
+{
+ vdec->flag = flag;
+}
+
+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;
+ }
+}
+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)) {
+ if (vdec->slave &&
+ ((vdec->slave->flag &
+ VDEC_FLAG_INPUT_KEEP_CONTEXT) == 0)) {
+ vdec->input.swap_needed = false;
+ } else
+ vdec->input.swap_needed = true;
+
+ if (vdec->input.target == VDEC_INPUT_TARGET_VLD) {
+ WRITE_MPEG_REG(PARSER_VIDEO_RP,
+ READ_VREG(VLD_MEM_VIFIFO_RP));
+ WRITE_VREG(VLD_MEM_VIFIFO_WP,
+ READ_MPEG_REG(PARSER_VIDEO_WP));
+ } else if (vdec->input.target == VDEC_INPUT_TARGET_HEVC) {
+ WRITE_MPEG_REG(PARSER_VIDEO_RP,
+ READ_VREG(HEVC_STREAM_RD_PTR));
+ WRITE_VREG(HEVC_STREAM_WR_PTR,
+ READ_MPEG_REG(PARSER_VIDEO_WP));
+ }
+ }
+}
+EXPORT_SYMBOL(vdec_vframe_dirty);
+
+void vdec_save_input_context(struct vdec_s *vdec)
+{
+ struct vdec_input_s *input = (vdec->master) ?
+ &vdec->master->input : &vdec->input;
+
+#ifdef CONFIG_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,
+ page_to_phys(input->swap_page));
+ 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);
+ } else if (input->target == VDEC_INPUT_TARGET_HEVC) {
+ WRITE_VREG(HEVC_STREAM_SWAP_ADDR,
+ page_to_phys(input->swap_page));
+ 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);
+ }
+
+ input->swap_valid = true;
+
+ if (input->target == VDEC_INPUT_TARGET_VLD)
+ WRITE_MPEG_REG(PARSER_VIDEO_RP,
+ READ_VREG(VLD_MEM_VIFIFO_RP));
+ else
+ WRITE_MPEG_REG(PARSER_VIDEO_RP,
+ READ_VREG(HEVC_STREAM_RD_PTR));
+ }
+}
+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->flag & VFRAME_CHUNK_FLAG_CONSUMED)
+ vdec_input_release_chunk(input, chunk);
+ else
+ break;
+ }
+ vdec_save_input_context(vdec);
+}
+EXPORT_SYMBOL(vdec_clean_input);
+
+const char *vdec_status_str(struct vdec_s *vdec)
+{
+ switch (vdec->status) {
+ case VDEC_STATUS_UNINITIALIZED:
+ return "VDEC_STATUS_UNINITIALIZED";
+ case VDEC_STATUS_DISCONNECTED:
+ return "VDEC_STATUS_DISCONNECTED";
+ case VDEC_STATUS_CONNECTED:
+ return "VDEC_STATUS_CONNECTED";
+ case VDEC_STATUS_ACTIVE:
+ return "VDEC_STATUS_ACTIVE";
+ default:
+ return "invalid status";
+ }
+}
+
+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];
+}
+
+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 */
+int vdec_connect(struct vdec_s *vdec)
+{
+ unsigned long flags;
+
+ 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_MULTI_DEC
+ vdec_profile(vdec, VDEC_PROFILE_EVENT_DISCONNECT);
+#endif
+
+ if ((vdec->status != VDEC_STATUS_CONNECTED) &&
+ (vdec->status != VDEC_STATUS_ACTIVE)) {
+ return 0;
+ }
+
+ /*
+ *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);
+
+ up(&vdec_core->sem);
+
+ wait_for_completion(&vdec->inactive_done);
+
+ if (vdec->slave)
+ wait_for_completion(&vdec->slave->inactive_done);
+ else if (vdec->master)
+ wait_for_completion(&vdec->master->inactive_done);
+
+ return 0;
+}
+EXPORT_SYMBOL(vdec_disconnect);
+
+/* release vdec structure */
+int vdec_destroy(struct vdec_s *vdec)
+{
+ if (!vdec->master)
+ vdec_input_release(&vdec->input);
+
+#ifdef CONFIG_MULTI_DEC
+ vdec_profile_flush(vdec);
+#endif
+
+ vfree(vdec);
+
+ atomic_dec(&vdec_core->vdec_nr);
+
+ return 0;
+}
+EXPORT_SYMBOL(vdec_destroy);
+
+/*
+ * 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_MULTI_DEC
+ if (use_legacy_vdec)
+ return vdec_device_name[format * 2];
+ else
+ return vdec_device_name[format * 2 + 1];
+#else
+ return vdec_device_name[format];
+#endif
+}
+
+void vdec_free_cmabuf(void)
+{
+ mutex_lock(&vdec_mutex);
+
+ if (inited_vcodec_num > 0) {
+ mutex_unlock(&vdec_mutex);
+ return;
+ }
+
+ if (vdec_mem_alloced_from_codec && vdec_core->mem_start) {
+ codec_mm_free_for_dma(MEM_NAME, vdec_core->mem_start);
+ vdec_cma_page = NULL;
+ vdec_core->mem_start = reserved_mem_start;
+ vdec_core->mem_end = reserved_mem_end;
+ pr_info("force free vdec memory\n");
+ }
+
+ mutex_unlock(&vdec_mutex);
+}
+
+/*
+*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;
+ int retry_num = 0;
+ int more_buffers = 0;
+ const char *dev_name;
+
+ if (is_4k && vdec->format < VFORMAT_H264) {
+ /*
+ *old decoder don't support 4k
+ * but size is bigger;
+ * clear 4k flag, and used more buffers;
+ */
+ more_buffers = 1;
+ is_4k = 0;
+ }
+
+ 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\n",
+ dev_name, vdec_type_str(vdec));
+
+ /*
+ *todo: VFM patch control should be configurable,
+ * for now all stream based input uses default VFM path.
+ */
+ if (vdec_stream_based(vdec) && !vdec_dual(vdec)) {
+ if (vdec_core->vfm_vdec == NULL) {
+ pr_info("vdec_init set vfm decoder %p\n", vdec);
+ vdec_core->vfm_vdec = vdec;
+ } else {
+ pr_info("vdec_init vfm path busy.\n");
+ return -EBUSY;
+ }
+ }
+
+ if (vdec_single(vdec) &&
+ ((vdec->format == VFORMAT_H264_4K2K) ||
+ (vdec->format == VFORMAT_HEVC && is_4k))) {
+ try_free_keep_video(0);
+ }
+
+ /*
+ *when blackout_policy was set, vdec would not free cma buffer, if
+ * current vformat require larger buffer size than current
+ * buf size, reallocated it
+ */
+ if (vdec_single(vdec) &&
+ ((vdec_core->mem_start != vdec_core->mem_end &&
+ vdec_core->mem_end - vdec_core->mem_start + 1 <
+ vdec_default_buf_size[vdec->format] * SZ_1M))) {
+#ifdef CONFIG_MULTI_DEC
+ pr_info("current vdec size %ld, vformat %d need size %d\n",
+ vdec_core->mem_end - vdec_core->mem_start,
+ vdec->format,
+ vdec_default_buf_size[vdec->format * 2] * SZ_1M);
+#else
+ pr_info("current vdec size %ld, vformat %d need size %d\n",
+ vdec_core->mem_end - vdec_core->mem_start,
+ vdec->format,
+ vdec_default_buf_size[vdec->format] * SZ_1M);
+#endif
+ try_free_keep_video(0);
+ vdec_free_cmabuf();
+ }
+
+ 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_VP9) ?
+ VDEC_INPUT_TARGET_HEVC :
+ VDEC_INPUT_TARGET_VLD);
+
+ p->cma_dev = vdec_core->cma_dev;
+ p->get_canvas = get_canvas;
+ /* todo */
+ if (!vdec_dual(vdec))
+ p->use_vfm_path = vdec_stream_based(vdec);
+
+ if (vdec_single(vdec)) {
+ pr_info("vdec_dev_reg.mem[0x%lx -- 0x%lx]\n",
+ vdec_core->mem_start,
+ vdec_core->mem_end);
+ p->mem_start = vdec_core->mem_start;
+ p->mem_end = vdec_core->mem_end;
+ }
+
+ /* allocate base memory for decoder instance */
+ while ((p->mem_start == p->mem_end) && (vdec_single(vdec))) {
+ int alloc_size;
+
+#ifdef CONFIG_MULTI_DEC
+ alloc_size =
+ vdec_default_buf_size[vdec->format * 2 + 1]
+ * SZ_1M;
+#else
+ alloc_size = vdec_default_buf_size[vdec->format] * SZ_1M;
+#endif
+ if (alloc_size == 0)
+ break;/*alloc end*/
+ if (is_4k) {
+ /*used 264 4k's setting for 265.*/
+#ifdef CONFIG_MULTI_DEC
+ int m4k_size =
+ vdec_default_buf_size[VFORMAT_H264_4K2K * 2] *
+ SZ_1M;
+#else
+ int m4k_size =
+ vdec_default_buf_size[VFORMAT_H264_4K2K] *
+ SZ_1M;
+#endif
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXTVBB)
+ m4k_size = 32 * SZ_1M;
+ if ((m4k_size > 0) && (m4k_size < 200 * SZ_1M))
+ alloc_size = m4k_size;
+
+#ifdef VP9_10B_MMU
+ if ((vdec->format == VFORMAT_VP9) &&
+ (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXL)) {
+#ifdef CONFIG_MULTI_DEC
+ if (p->use_vfm_path)
+ alloc_size =
+ vdec_default_buf_size[VFORMAT_VP9 * 2]
+ * SZ_1M;
+ else
+ alloc_size =
+ vdec_default_buf_size[VFORMAT_VP9
+ * 2 + 1] * SZ_1M;
+
+#else
+ alloc_size =
+ vdec_default_buf_size[VFORMAT_VP9] * SZ_1M;
+#endif
+ }
+#endif
+ } else if (more_buffers) {
+ alloc_size = alloc_size + 16 * SZ_1M;
+ }
+
+ if ((vdec->format == VFORMAT_HEVC)
+ && get_mmu_mode()
+ && (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXL)) {
+#ifdef CONFIG_MULTI_DEC
+ if (p->use_vfm_path)
+ alloc_size = 33 * SZ_1M;
+ else
+ alloc_size = 33 * SZ_1M;
+#else
+ alloc_size = 33 * SZ_1M;
+#endif
+ }
+
+ if ((vdec->format == VFORMAT_H264)
+ && (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXL)
+ && codec_mm_get_total_size() <= 80 * SZ_1M) {
+#ifdef CONFIG_MULTI_DEC
+ if (p->use_vfm_path)
+ alloc_size = 32 * SZ_1M;
+ else
+ alloc_size = 32 * SZ_1M;
+#else
+ alloc_size = 32 * SZ_1M;
+#endif
+ }
+
+
+ p->mem_start = codec_mm_alloc_for_dma(MEM_NAME,
+ alloc_size / PAGE_SIZE, 4 + PAGE_SHIFT,
+ CODEC_MM_FLAGS_CMA_CLEAR | CODEC_MM_FLAGS_CPU |
+ CODEC_MM_FLAGS_FOR_VDECODER);
+ if (!p->mem_start) {
+ if (retry_num < 1) {
+ pr_err("vdec base CMA allocation failed,try again\\n");
+ retry_num++;
+ try_free_keep_video(0);
+ continue;/*retry alloc*/
+ }
+ pr_err("vdec base CMA allocation failed.\n");
+
+ mutex_lock(&vdec_mutex);
+ inited_vcodec_num--;
+ mutex_unlock(&vdec_mutex);
+
+ return -ENOMEM;
+ }
+
+ p->mem_end = p->mem_start + alloc_size - 1;
+ pr_info("vdec base memory alloced [%p -- %p]\n",
+ (void *)p->mem_start,
+ (void *)p->mem_end);
+
+ break;/*alloc end*/
+ }
+
+ if (vdec_single(vdec)) {
+ vdec_core->mem_start = p->mem_start;
+ vdec_core->mem_end = p->mem_end;
+ vdec_mem_alloced_from_codec = 1;
+ }
+
+/*alloc end:*/
+ /* vdec_dev_reg.flag = 0; */
+
+ p->dev =
+ platform_device_register_data(
+ &vdec_core->vdec_core_platform_device->dev,
+ dev_name,
+ PLATFORM_DEVID_AUTO,
+ &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;
+ }
+
+ 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;
+ } else if (!vdec_dual(vdec)) {
+ /* create IONVIDEO instance and connect decoder's
+ * vf_provider interface to it
+ */
+ 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 (p->frame_base_video_path == FRAME_BASE_PATH_IONVIDEO) {
+#if 1
+ //r = ionvideo_alloc_map(&vdec->vf_receiver_name,
+ //&vdec->vf_receiver_inst);//DEBUG_TMP
+#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,
+ "%s-%s", vdec->vf_provider_name,
+ vdec->vf_receiver_name);
+
+ } else if (p->frame_base_video_path ==
+ FRAME_BASE_PATH_AMLVIDEO_AMVIDEO) {
+ snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE,
+ "%s %s", vdec->vf_provider_name,
+ "amlvideo.0 amvideo");
+ snprintf(vdec->vfm_map_id, VDEC_MAP_NAME_SIZE,
+ "%s-%s", vdec->vf_provider_name,
+ "amlvideo.0 amvideo");
+ } 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,
+ "ppmgr amlvideo.1 amvide2");
+ snprintf(vdec->vfm_map_id, VDEC_MAP_NAME_SIZE,
+ "%s-%s", vdec->vf_provider_name,
+ "ppmgr amlvideo.1 amvide2");
+ }
+
+ 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_info("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);
+ }
+
+ pr_info("vdec_init, vf_provider_name = %s\n", p->vf_provider_name);
+
+ /* vdec is now ready to be active */
+ vdec_set_status(vdec, VDEC_STATUS_DISCONNECTED);
+
+ return 0;
+
+error:
+ return r;
+}
+EXPORT_SYMBOL(vdec_init);
+
+void vdec_release(struct vdec_s *vdec)
+{
+ vdec_disconnect(vdec);
+
+ if (vdec->vframe_provider.name)
+ vf_unreg_provider(&vdec->vframe_provider);
+
+ if (vdec_core->vfm_vdec == vdec)
+ vdec_core->vfm_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;
+ }
+
+ /*
+ *vf_receiver_inst should be > 0 since 0 is
+ * for either un-initialized vdec or a ionvideo
+ * instance reserved for legacy path.
+ */
+ //ionvideo_release_map(vdec->vf_receiver_inst);//DEBUG_TMP
+ }
+
+ platform_device_unregister(vdec->dev);
+
+ if (!vdec->use_vfm_path) {
+ if (vdec->mem_start) {
+ codec_mm_free_for_dma(MEM_NAME, vdec->mem_start);
+ vdec->mem_start = 0;
+ vdec->mem_end = 0;
+ }
+ } else if (delay_release-- <= 0 &&
+ !keep_vdec_mem &&
+ vdec_mem_alloced_from_codec &&
+ vdec_core->mem_start &&
+ get_blackout_policy()) {
+ codec_mm_free_for_dma(MEM_NAME, vdec_core->mem_start);
+ vdec_cma_page = NULL;
+ vdec_core->mem_start = reserved_mem_start;
+ vdec_core->mem_end = reserved_mem_end;
+ }
+
+ vdec_destroy(vdec);
+
+ mutex_lock(&vdec_mutex);
+ inited_vcodec_num--;
+ mutex_unlock(&vdec_mutex);
+}
+EXPORT_SYMBOL(vdec_release);
+
+int vdec_reset(struct vdec_s *vdec)
+{
+ 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_input_release(&vdec->input);
+
+ 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_connect(vdec);
+
+ return 0;
+}
+EXPORT_SYMBOL(vdec_reset);
+
+static struct vdec_s *active_vdec(struct vdec_core_s *core)
+{
+ struct vdec_s *vdec;
+ struct list_head *p;
+
+ list_for_each(p, &core->connected_vdec_list) {
+ vdec = list_entry(p, struct vdec_s, list);
+ if (vdec->status == VDEC_STATUS_ACTIVE)
+ return vdec;
+ }
+
+ return NULL;
+}
+
+/*
+*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_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->active_vdec;
+
+ if (c->dev_isr)
+ return c->dev_isr(irq, c->dev_id);
+
+ if (c != &vdec_core->isr_context[VDEC_IRQ_1]) {
+#if 0
+ pr_warn("vdec interrupt w/o a valid receiver\n");
+#endif
+ return IRQ_HANDLED;
+ }
+
+ if (!vdec) {
+#if 0
+ pr_warn("vdec interrupt w/o an active instance running. core = %p\n",
+ core);
+#endif
+ return IRQ_HANDLED;
+ }
+
+ if (!vdec->irq_handler) {
+#if 0
+ pr_warn("vdec instance has no irq handle.\n");
+#endif
+ return IRQ_HANDLED;
+ }
+
+ return vdec->irq_handler(vdec);
+}
+
+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->active_vdec;
+
+ if (c->dev_threaded_isr)
+ return c->dev_threaded_isr(irq, c->dev_id);
+
+ if (!vdec)
+ return IRQ_HANDLED;
+
+ if (!vdec->threaded_irq_handler)
+ return IRQ_HANDLED;
+
+ return vdec->threaded_irq_handler(vdec);
+}
+
+static inline bool vdec_ready_to_run(struct vdec_s *vdec)
+{
+ bool r;
+
+ if (vdec->status != VDEC_STATUS_CONNECTED)
+ return false;
+
+ if (!vdec->run_ready)
+ return false;
+
+ if ((vdec->slave || vdec->master) &&
+ (vdec->sched == 0))
+ return false;
+
+ if (step_mode) {
+ if ((step_mode & 0xff) != vdec->id)
+ return false;
+ }
+
+ step_mode &= ~0xff;
+
+#ifdef CONFIG_MULTI_DEC
+ vdec_profile(vdec, VDEC_PROFILE_EVENT_CHK_RUN_READY);
+#endif
+
+ r = vdec->run_ready(vdec);
+
+#ifdef CONFIG_MULTI_DEC
+ if (r)
+ vdec_profile(vdec, VDEC_PROFILE_EVENT_RUN_READY);
+#endif
+
+ return r;
+}
+
+/* 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)
+{
+ unsigned long flags;
+ struct vdec_core_s *core = (struct vdec_core_s *)data;
+
+ struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1};
+
+ sched_setscheduler(current, SCHED_FIFO, &param);
+
+ allow_signal(SIGTERM);
+
+ while (down_interruptible(&core->sem) == 0) {
+ struct vdec_s *vdec, *tmp;
+ LIST_HEAD(disconnecting_list);
+
+ if (kthread_should_stop())
+ break;
+
+ /* clean up previous active vdec's input */
+ if ((core->active_vdec) &&
+ (core->active_vdec->status == VDEC_STATUS_CONNECTED)) {
+ struct vdec_input_s *input = &core->active_vdec->input;
+
+ while (!list_empty(&input->vframe_chunk_list)) {
+ struct vframe_chunk_s *chunk =
+ vdec_input_next_chunk(input);
+ if (chunk->flag & VFRAME_CHUNK_FLAG_CONSUMED)
+ vdec_input_release_chunk(input, chunk);
+ else
+ break;
+ }
+
+ vdec_save_input_context(core->active_vdec);
+ }
+
+ /*
+ *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)) {
+ * }
+ */
+
+ flags = vdec_core_lock(core);
+
+ /* check disconnected decoders */
+ 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->active_vdec == vdec)
+ core->active_vdec = NULL;
+ list_move(&vdec->list, &disconnecting_list);
+ }
+ }
+
+ /* activate next decoder instance if there is none */
+ vdec = active_vdec(core);
+
+ if (!vdec) {
+ /*
+ *round-robin decoder scheduling
+ * start from the decoder after previous active
+ * decoder instance, if not, then start from beginning
+ */
+ if (core->active_vdec)
+ vdec = list_entry(
+ core->active_vdec->list.next,
+ struct vdec_s, list);
+ else
+ vdec = list_entry(
+ core->connected_vdec_list.next,
+ struct vdec_s, list);
+
+ list_for_each_entry_from(vdec,
+ &core->connected_vdec_list, list) {
+ if (vdec_ready_to_run(vdec))
+ break;
+ }
+
+ if ((&vdec->list == &core->connected_vdec_list) &&
+ (core->active_vdec)) {
+ /* search from beginning */
+ list_for_each_entry(vdec,
+ &core->connected_vdec_list, list) {
+ if (vdec_ready_to_run(vdec))
+ break;
+
+ if (vdec == core->active_vdec) {
+ vdec = NULL;
+ break;
+ }
+ }
+ }
+
+ if (&vdec->list == &core->connected_vdec_list)
+ vdec = NULL;
+
+ core->active_vdec = NULL;
+ }
+
+ vdec_core_unlock(core, flags);
+
+ /* start the vdec instance */
+ if ((vdec) && (vdec->status != VDEC_STATUS_ACTIVE)) {
+ vdec_set_status(vdec, VDEC_STATUS_ACTIVE);
+
+ /* activatate the decoder instance to run */
+ core->active_vdec = vdec;
+#ifdef CONFIG_MULTI_DEC
+ vdec_profile(vdec, VDEC_PROFILE_EVENT_RUN);
+#endif
+ vdec->run(vdec, vdec_callback, core);
+ }
+
+ /* 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);
+ complete(&vdec->inactive_done);
+ }
+
+ if (!core->active_vdec) {
+ msleep(20);
+ up(&core->sem);
+ }
+ }
+
+ return 0;
+}
+
+#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
+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;
+}
+
+void vdec_poweron(enum vdec_type_e core)
+{
+ void *decomp_addr = NULL;
+ dma_addr_t decomp_dma_addr;
+ u32 decomp_addr_aligned = 0;
+ int hevc_loop = 0;
+
+ 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;
+ }
+
+ if (hevc_workaround_needed() &&
+ (core == VDEC_HEVC)) {
+ decomp_addr = codec_mm_dma_alloc_coherent(MEM_NAME,
+ SZ_64K + SZ_4K, &decomp_dma_addr, GFP_KERNEL, 0);
+
+ 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 (core == VDEC_1) {
+ /* vdec1 power on */
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~0xc);
+ /* 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
+ */
+ vdec_clock_hi_enable();
+ /* power up vdec memories */
+ WRITE_VREG(DOS_MEM_PD_VDEC, 0);
+ /* remove vdec1 isolation */
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~0xC0);
+ /* reset DOS top registers */
+ WRITE_VREG(DOS_VDEC_MCRCC_STALL_CTRL, 0);
+ if (get_cpu_type() >=
+ MESON_CPU_MAJOR_ID_GXBB) {
+ /*
+ *enable VDEC_1 DMC request
+ */
+ unsigned long flags;
+
+ spin_lock_irqsave(&vdec_spin_lock, flags);
+ codec_dmcbus_write(DMC_REQ_CTRL,
+ codec_dmcbus_read(DMC_REQ_CTRL) | (1 << 13));
+ spin_unlock_irqrestore(&vdec_spin_lock, flags);
+ }
+ } else if (core == 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 (core == VDEC_HCODEC) {
+ if (has_hdec()) {
+ /* hcodec power on */
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) &
+ ~0x3);
+ /* 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 */
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) &
+ ~0x30);
+ }
+ } else if (core == VDEC_HEVC) {
+ if (has_hevc_vdec()) {
+ bool hevc_fixed = false;
+
+ while (!hevc_fixed) {
+ /* hevc power on */
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) &
+ ~0xc0);
+ /* wait 10uS */
+ udelay(10);
+ /* hevc soft reset */
+ WRITE_VREG(DOS_SW_RESET3, 0xffffffff);
+ WRITE_VREG(DOS_SW_RESET3, 0);
+ /* enable hevc clock */
+ hevc_clock_hi_enable();
+ /* power up hevc memories */
+ WRITE_VREG(DOS_MEM_PD_HEVC, 0);
+ /* remove hevc isolation */
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) &
+ ~0xc00);
+
+ if (!hevc_workaround_needed())
+ break;
+
+ if (decomp_addr)
+ hevc_fixed = test_hevc(
+ decomp_addr_aligned, 20);
+
+ if (!hevc_fixed) {
+ hevc_loop++;
+
+ mutex_unlock(&vdec_mutex);
+
+ 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;
+ }
+
+ vdec_poweroff(VDEC_HEVC);
+
+ mdelay(10);
+
+ mutex_lock(&vdec_mutex);
+ }
+ }
+
+ 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_NAME,
+ SZ_64K + SZ_4K, decomp_addr, decomp_dma_addr, 0);
+
+ 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;
+ }
+
+ if (core == VDEC_1) {
+ if (get_cpu_type() >=
+ MESON_CPU_MAJOR_ID_GXBB) {
+ /* disable VDEC_1 DMC REQ*/
+ unsigned long flags;
+
+ spin_lock_irqsave(&vdec_spin_lock, flags);
+ codec_dmcbus_write(DMC_REQ_CTRL,
+ codec_dmcbus_read(DMC_REQ_CTRL) & (~(1 << 13)));
+ spin_unlock_irqrestore(&vdec_spin_lock, flags);
+ udelay(10);
+ }
+ /* 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);
+ /* disable vdec1 clock */
+ vdec_clock_off();
+ /* vdec1 power off */
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | 0xc);
+ } else if (core == 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 (core == VDEC_HCODEC) {
+ 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);
+ /* disable hcodec clock */
+ hcodec_clock_off();
+ /* hcodec power off */
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | 3);
+ }
+ } else if (core == VDEC_HEVC) {
+ 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);
+ /* disable hevc clock */
+ hevc_clock_off();
+ /* hevc power off */
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) |
+ 0xc0);
+ }
+ }
+ mutex_unlock(&vdec_mutex);
+}
+EXPORT_SYMBOL(vdec_poweroff);
+
+bool vdec_on(enum vdec_type_e core)
+{
+ bool ret = false;
+
+ if (core == VDEC_1) {
+ if (((READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & 0xc) == 0) &&
+ (READ_HHI_REG(HHI_VDEC_CLK_CNTL) & 0x100))
+ ret = true;
+ } else if (core == 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 (core == VDEC_HCODEC) {
+ if (has_hdec()) {
+ if (((READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & 0x3) == 0) &&
+ (READ_HHI_REG(HHI_VDEC_CLK_CNTL) & 0x1000000))
+ ret = true;
+ }
+ } else if (core == VDEC_HEVC) {
+ if (has_hevc_vdec()) {
+ if (((READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & 0xc0) == 0) &&
+ (READ_HHI_REG(HHI_VDEC2_CLK_CNTL) & 0x1000000))
+ ret = true;
+ }
+ }
+
+ return ret;
+}
+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_info("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);
+
+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_info("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_info("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 enum vdec2_usage_e vdec2_usage = USAGE_NONE;
+void set_vdec2_usage(enum vdec2_usage_e usage)
+{
+ if (has_vdec2()) {
+ mutex_lock(&vdec_mutex);
+ vdec2_usage = usage;
+ mutex_unlock(&vdec_mutex);
+ }
+}
+EXPORT_SYMBOL(set_vdec2_usage);
+
+enum vdec2_usage_e get_vdec2_usage(void)
+{
+ if (has_vdec2())
+ return vdec2_usage;
+ else
+ return 0;
+}
+EXPORT_SYMBOL(get_vdec2_usage);
+
+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 val;
+ ssize_t ret;
+
+ if (get_cpu_type() >= 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_type() >= 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_type() >= MESON_CPU_MAJOR_ID_M8)
+ mutex_unlock(&vdec_mutex);
+ else if (get_cpu_type() >= 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 = kmalloc(debug_trace_num * 2, GFP_KERNEL);
+
+ if (!trace_buf) {
+ pbuf += sprintf(pbuf, "No Memory bug\n");
+ ret = pbuf - buf;
+ return ret;
+ }
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_M8) {
+ mutex_lock(&vdec_mutex);
+ if (!vdec_on(VDEC_1)) {
+ mutex_unlock(&vdec_mutex);
+ kfree(trace_buf);
+ pbuf += sprintf(pbuf, "amrisc is power off\n");
+ ret = pbuf - buf;
+ return ret;
+ }
+ } else if (get_cpu_type() >= 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_type() >= MESON_CPU_MAJOR_ID_M8)
+ mutex_unlock(&vdec_mutex);
+ else if (get_cpu_type() >= 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)
+ ;
+ kfree(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 store_poweron_clock_level(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned 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 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);
+}
+
+
+/*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_info("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;
+ }
+
+ synchronize_irq(vdec_core->isr_context[num].irq);
+
+ /*
+ *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;
+}
+EXPORT_SYMBOL(vdec_free_irq);
+
+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 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_type() >= 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_type() >= 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_type() >= MESON_CPU_MAJOR_ID_M8)
+ mutex_unlock(&vdec_mutex);
+ else if (get_cpu_type() >= 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;
+
+ 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 += sprintf(pbuf,
+ "\tvdec (%p (%s)), status = %s,\ttype = %s\n",
+ vdec, vdec_device_name[vdec->format * 2],
+ vdec_status_str(vdec),
+ vdec_type_str(vdec));
+ }
+ }
+
+ return pbuf - buf;
+}
+
+static struct class_attribute vdec_class_attrs[] = {
+ __ATTR_RO(amrisc_regs),
+ __ATTR_RO(dump_trace),
+ __ATTR_RO(clock_level),
+ __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_NULL
+};
+
+static struct class vdec_class = {
+ .name = "vdec",
+ .class_attrs = vdec_class_attrs,
+ };
+
+
+/*
+*pre alloced enough memory for decoder
+*fast start.
+*/
+void pre_alloc_vdec_memory(void)
+{
+ if (!keep_vdec_mem || vdec_core->mem_start)
+ return;
+
+ vdec_core->mem_start = codec_mm_alloc_for_dma(MEM_NAME,
+ CMA_ALLOC_SIZE / PAGE_SIZE, 4 + PAGE_SHIFT,
+ CODEC_MM_FLAGS_CMA_CLEAR |
+ CODEC_MM_FLAGS_FOR_VDECODER);
+ if (!vdec_core->mem_start)
+ return;
+ pr_debug("vdec base memory alloced %p\n",
+ (void *)vdec_core->mem_start);
+
+ vdec_core->mem_end = vdec_core->mem_start + CMA_ALLOC_SIZE - 1;
+ vdec_mem_alloced_from_codec = 1;
+ delay_release = 3;
+}
+EXPORT_SYMBOL(pre_alloc_vdec_memory);
+
+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_1, NULL, NULL,
+ IRQF_ONESHOT, "vdec-1", NULL);
+ if (r < 0) {
+ pr_err("vdec interrupt request failed\n");
+ return r;
+ }
+
+ 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_type() < MESON_CPU_MAJOR_ID_M8) {
+ /* default to 250MHz */
+ vdec_clock_hi_enable();
+ }
+
+ if (get_cpu_type() == MESON_CPU_MAJOR_ID_GXBB) {
+ /* set vdec dmc request to urgent */
+ WRITE_DMCREG(DMC_AM5_CHAN_CTRL, 0x3f203cf);
+ }
+ if (codec_mm_get_reserved_size() >= 48 * SZ_1M
+ && codec_mm_get_reserved_size() <= 96 * SZ_1M) {
+#ifdef CONFIG_MULTI_DEC
+ vdec_default_buf_size[VFORMAT_H264_4K2K * 2] =
+ codec_mm_get_reserved_size() / SZ_1M;
+#else
+ vdec_default_buf_size[VFORMAT_H264_4K2K] =
+ codec_mm_get_reserved_size() / SZ_1M;
+#endif
+
+ /*all reserved size for prealloc*/
+ }
+ pre_alloc_vdec_memory();
+
+ INIT_LIST_HEAD(&vdec_core->connected_vdec_list);
+ spin_lock_init(&vdec_core->lock);
+
+ vdec_core->thread = kthread_run(vdec_core_thread, vdec_core,
+ "vdec-core");
+
+ 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);
+
+ class_unregister(&vdec_class);
+
+ return 0;
+}
+
+static const struct of_device_id amlogic_vdec_dt_match[] = {
+ {
+ .compatible = "amlogic, vdec",
+ },
+ {},
+};
+
+static struct platform_driver vdec_driver = {
+ .probe = vdec_probe,
+ .remove = vdec_remove,
+ .driver = {
+ .name = "vdec",
+ .of_match_table = amlogic_vdec_dt_match,
+ }
+};
+
+int vdec_module_init(void)
+{
+ if (platform_driver_register(&vdec_driver)) {
+ pr_info("failed to register vdec module\n");
+ return -ENODEV;
+ }
+
+ 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;
+ }
+
+ 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)
+{
+ unsigned long start, end;
+
+ start = rmem->base;
+ end = rmem->base + rmem->size - 1;
+ pr_info("init vdec memsource %lx->%lx\n", start, end);
+
+ vdec_core->mem_start = start;
+ vdec_core->mem_end = end;
+ 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;
+}
+
+RESERVEDMEM_OF_DECLARE(vdec, "amlogic, vdec-memory", vdec_mem_setup);
+
+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_init(vdec_module_init);
+*module_exit(vdec_module_exit);
+*/
+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..cb63f8d
--- a/dev/null
+++ b/drivers/frame_provider/decoder/utils/vdec.h
@@ -0,0 +1,306 @@
+/*
+ * 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>
+
+#include "vdec_input.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 DEC_FLAG_HEVC_WORKAROUND 0x01
+
+enum vdec_type_e {
+ VDEC_1 = 0,
+ VDEC_HCODEC,
+ VDEC_2,
+ VDEC_HEVC,
+ VDEC_MAX
+};
+
+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);
+
+/*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_MAX,
+};
+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);
+
+enum vdec2_usage_e {
+ USAGE_NONE,
+ USAGE_DEC_4K2K,
+ USAGE_ENCODE,
+};
+
+extern void set_vdec2_usage(enum vdec2_usage_e usage);
+extern enum vdec2_usage_e get_vdec2_usage(void);
+
+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
+
+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 40
+
+#define VDEC_FLAG_INPUT_KEEP_CONTEXT 0x01
+
+struct vdec_s {
+ u32 magic;
+ struct list_head list;
+ int id;
+
+ struct vdec_s *master;
+ struct vdec_s *slave;
+ struct stream_port_s *port;
+ int status;
+ int next_status;
+ int type;
+ int port_flag;
+ int format;
+ u32 pts;
+ u64 pts64;
+ bool pts_valid;
+ int flag;
+ int sched;
+
+ struct completion inactive_done;
+
+ /* config (temp) */
+ unsigned long mem_start;
+ unsigned long mem_end;
+
+ 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;
+
+ /* mc cache */
+ u32 mc[4096 * 4];
+ bool mc_loaded;
+
+ /* 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;
+ bool use_vfm_path;
+ char config[PAGE_SIZE];
+ int config_len;
+
+ /* canvas */
+ int (*get_canvas)(unsigned int index, unsigned int base);
+
+ int (*dec_status)(struct vdec_s *vdec, struct vdec_status *vstatus);
+ int (*set_trickmode)(struct vdec_s *vdec, unsigned long trickmode);
+
+ bool (*run_ready)(struct vdec_s *vdec);
+ void (*run)(struct vdec_s *vdec,
+ void (*callback)(struct vdec_s *, void *), void *);
+ void (*reset)(struct vdec_s *vdec);
+ irqreturn_t (*irq_handler)(struct vdec_s *);
+ irqreturn_t (*threaded_irq_handler)(struct vdec_s *);
+
+ /* private */
+ void *private; /* decoder per instance specific data */
+};
+
+/* 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)
+
+/* 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);
+
+/* add frame data to input chain */
+extern int vdec_write_vframe(struct vdec_s *vdec, const char *buf,
+ size_t count);
+
+/* 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);
+
+/* enable decoder input */
+extern void vdec_enable_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 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_status *vstatus);
+
+extern int vdec_set_trickmode(struct vdec_s *vdec, unsigned long trickmode);
+
+extern void vdec_set_flag(struct vdec_s *vdec, u32 flag);
+
+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);
+
+#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..d6acac1
--- a/dev/null
+++ b/drivers/frame_provider/decoder/utils/vdec_input.c
@@ -0,0 +1,544 @@
+/*
+ * 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"
+
+#define VFRAME_BLOCK_SIZE (4*SZ_1M)
+#define VFRAME_BLOCK_PAGESIZE (PAGE_ALIGN(VFRAME_BLOCK_SIZE)/PAGE_SIZE)
+#define VFRAME_BLOCK_PAGEALIGN 4
+#define VFRAME_BLOCK_MAX_LEVEL (8*SZ_1M)
+#define VFRAME_BLOCK_HOLE (SZ_64K)
+
+#define FRAME_PADDING_SIZE 1024U
+#define MEM_NAME "VFRAME_INPUT"
+
+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) {
+ if (copy_from_user(p, buf, count))
+ return -EFAULT;
+
+ p += count;
+
+ memset(p, 0, FRAME_PADDING_SIZE);
+
+ dma_sync_single_for_device(get_vdec_device(),
+ block->start + block->wp,
+ count + FRAME_PADDING_SIZE, DMA_TO_DEVICE);
+
+ } else if (block->type == VDEC_TYPE_FRAME_CIRCULAR) {
+ size_t len = min((size_t)(block->size - block->wp), count);
+ u32 wp;
+
+ if (copy_from_user(p, buf, len))
+ return -EFAULT;
+
+ dma_sync_single_for_device(get_vdec_device(),
+ block->start + block->wp,
+ len, DMA_TO_DEVICE);
+
+ p += len;
+
+ if (count > len) {
+ p = (u8 *)block->start_virt;
+ if (copy_from_user(p, buf, count - len))
+ return -EFAULT;
+
+ dma_sync_single_for_device(get_vdec_device(),
+ block->start,
+ count-len, DMA_TO_DEVICE);
+
+ p += count - len;
+ }
+
+ wp = block->wp + count;
+ if (wp >= block->size)
+ wp -= block->size;
+
+ len = min(block->size - wp, FRAME_PADDING_SIZE);
+
+ memset(p, 0, len);
+
+ dma_sync_single_for_device(get_vdec_device(),
+ block->start + wp,
+ len, DMA_TO_DEVICE);
+
+ if (len < FRAME_PADDING_SIZE) {
+ p = (u8 *)block->start_virt;
+
+ memset(p, 0, count - len);
+
+ dma_sync_single_for_device(get_vdec_device(),
+ block->start,
+ count - 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 + FRAME_PADDING_SIZE;
+ if (block->wp >= block->size)
+ block->wp -= block->size;
+ block->chunk_count++;
+ chunk->block = block;
+ block->input->wr_block = block;
+ chunk->sequence = block->input->sequence;
+ block->input->sequence++;
+}
+
+static void vframe_block_free_storage(struct vframe_block_list_s *block)
+{
+ if (block->addr) {
+ dma_unmap_single(
+ get_vdec_device(),
+ block->start,
+ VFRAME_BLOCK_PAGESIZE,
+ DMA_TO_DEVICE);
+
+ codec_mm_free_for_dma(MEM_NAME, block->addr);
+
+ block->addr = 0;
+ block->start_virt = NULL;
+ block->start = 0;
+ }
+
+ block->size = 0;
+}
+
+static int vframe_block_init_alloc_storage(struct vdec_input_s *input,
+ struct vframe_block_list_s *block)
+{
+ block->magic = 0x4b434c42;
+ block->input = input;
+ block->type = input->type;
+
+ /*
+ * todo: for different type use different size
+ */
+ block->addr = codec_mm_alloc_for_dma(
+ MEM_NAME,
+ VFRAME_BLOCK_PAGESIZE,
+ VFRAME_BLOCK_PAGEALIGN,
+ CODEC_MM_FLAGS_DMA_CPU | CODEC_MM_FLAGS_FOR_VDECODER);
+
+ if (!block->addr) {
+ pr_err("Input block allocation failed\n");
+ return -ENOMEM;
+ }
+
+ block->start_virt = (void *)codec_mm_phys_to_virt(block->addr);
+ block->start = dma_map_single(
+ get_vdec_device(),
+ block->start_virt,
+ VFRAME_BLOCK_PAGESIZE,
+ DMA_TO_DEVICE);
+ block->size = VFRAME_BLOCK_PAGESIZE * PAGE_SIZE;
+
+ 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_chunk_list);
+ spin_lock_init(&input->lock);
+
+ input->vdec = vdec;
+}
+EXPORT_SYMBOL(vdec_input_init);
+
+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_page = alloc_page(GFP_KERNEL);
+
+ if (input->swap_page == NULL)
+ 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;
+}
+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);
+
+ list_add_tail(&block->list, &input->vframe_block_list);
+ input->size += block->size;
+
+ vdec_input_unlock(input, flags);
+}
+
+static void vdec_input_remove_block(struct vdec_input_s *input,
+ struct vframe_block_list_s *block)
+{
+ unsigned long flags;
+
+ flags = vdec_input_lock(input);
+
+ list_del(&block->list);
+ input->size -= block->size;
+
+ vdec_input_unlock(input, flags);
+
+ vframe_block_free_storage(block);
+
+ kfree(block);
+
+ pr_info("block %p removed\n", block);
+}
+
+int vdec_input_level(struct vdec_input_s *input)
+{
+ return input->total_wr_count - input->total_rd_count;
+}
+EXPORT_SYMBOL(vdec_input_level);
+
+int vdec_input_add_frame(struct vdec_input_s *input, const char *buf,
+ size_t count)
+{
+ unsigned long flags;
+ struct vframe_chunk_s *chunk;
+ struct vdec_s *vdec = input->vdec;
+ struct vframe_block_list_s *block = input->wr_block;
+
+#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;
+
+ /* prepare block to write */
+ if ((!block) || (block &&
+ (vframe_block_space(block) < (count + FRAME_PADDING_SIZE)))) {
+ /* switch to another block for the added chunk */
+ struct vframe_block_list_s *new_block;
+
+#if 0
+ pr_info("Adding new block, total level = %d, total_wr_count=%d, total_rd_count=%d\n",
+ vdec_input_level(input),
+ (int)input->total_wr_count,
+ (int)input->total_rd_count);
+#endif
+
+ if ((!list_empty(&input->vframe_block_list)) &&
+ (block->type == VDEC_TYPE_FRAME_CIRCULAR))
+ return -EAGAIN;
+ /*
+ *todo: add input limit check for
+ * VDEC_TYPE_FRAME_BLOCK
+ */
+ if (vdec_input_level(input) >
+ VFRAME_BLOCK_MAX_LEVEL) {
+ pr_info("vdec_input %p reaching max size\n",
+ input);
+ return -EAGAIN;
+ }
+
+ /*
+ *check next block of current wr_block, it should be an empty
+ * block to use
+ */
+ if ((block) && (!list_is_last(
+ &block->list, &input->vframe_block_list))) {
+ block = list_next_entry(block, list);
+
+ if (vframe_block_space(block) != VFRAME_BLOCK_SIZE)
+ /* should never happen */
+ pr_err("next writing block not empty.\n");
+ } else {
+ /* add a new block into input list */
+ new_block = kzalloc(sizeof(struct vframe_block_list_s),
+ GFP_KERNEL);
+ if (new_block == NULL) {
+ pr_err("vframe_block structure allocation failed\n");
+ return -EAGAIN;
+ }
+
+ if (vframe_block_init_alloc_storage(input,
+ new_block) != 0) {
+ kfree(new_block);
+ pr_err("vframe_block storage allocation failed\n");
+ return -EAGAIN;
+ }
+
+ INIT_LIST_HEAD(&new_block->list);
+
+ vdec_input_add_block(input, new_block);
+
+ /* pr_info("added new block %p\n", new_block); */
+
+ block = new_block;
+ }
+ }
+
+ chunk = kzalloc(sizeof(struct vframe_chunk_s), GFP_KERNEL);
+
+ if (!chunk) {
+ pr_err("vframe_chunk structure allocation failed\n");
+ return -ENOMEM;
+ }
+
+ chunk->magic = 0x4b554843;
+ if (vdec->pts_valid) {
+ chunk->pts = vdec->pts;
+ chunk->pts64 = vdec->pts64;
+ }
+ chunk->pts_valid = vdec->pts_valid;
+ vdec->pts_valid = false;
+ chunk->offset = block->wp;
+ chunk->size = count;
+
+ INIT_LIST_HEAD(&chunk->list);
+
+ 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);
+
+ vdec_input_unlock(input, flags);
+
+ input->total_wr_count += count;
+
+#if 0
+ if (add_count == 2)
+ input->total_wr_count += 38;
+#endif
+
+ return count;
+}
+EXPORT_SYMBOL(vdec_input_add_frame);
+
+struct vframe_chunk_s *vdec_input_next_chunk(struct vdec_input_s *input)
+{
+ if (list_empty(&input->vframe_chunk_list))
+ return NULL;
+
+ return list_first_entry(&input->vframe_chunk_list,
+ struct vframe_chunk_s, list);
+}
+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;
+
+ 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;
+ }
+ }
+
+ return chunk;
+}
+EXPORT_SYMBOL(vdec_input_next_input_chunk);
+
+void vdec_input_release_chunk(struct vdec_input_s *input,
+ struct vframe_chunk_s *chunk)
+{
+ unsigned long flags;
+ struct vframe_block_list_s *block = chunk->block;
+
+ flags = vdec_input_lock(input);
+
+ list_del(&chunk->list);
+
+ block->rp += chunk->size;
+ if (block->rp >= block->size)
+ block->rp -= block->size;
+ block->chunk_count--;
+ input->total_rd_count += chunk->size;
+
+ if (block->chunk_count == 0) {
+ /* reuse the block */
+ block->wp = 0;
+ block->rp = 0;
+
+ if ((input->wr_block == block) &&
+ (!list_is_last(&block->list,
+ &input->vframe_block_list)))
+ input->wr_block = list_next_entry(block, list);
+
+ list_move_tail(&block->list, &input->vframe_block_list);
+ }
+
+ vdec_input_unlock(input, flags);
+
+ 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);
+ }
+
+ /* release 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);
+ vdec_input_remove_block(input, block);
+ }
+
+ /* release swap page */
+ if (input->swap_page) {
+ __free_page(input->swap_page);
+ input->swap_page = NULL;
+ input->swap_valid = false;
+ }
+}
+EXPORT_SYMBOL(vdec_input_release);
+
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..b029b89
--- a/dev/null
+++ b/drivers/frame_provider/decoder/utils/vdec_input.h
@@ -0,0 +1,131 @@
+/*
+ * 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;
+
+struct vframe_block_list_s {
+ u32 magic;
+ struct list_head list;
+ ulong start;
+ void *start_virt;
+ ulong addr;
+ int type;
+ u32 size;
+ u32 wp;
+ u32 rp;
+ int chunk_count;
+ 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;
+ u64 pts64;
+ bool pts_valid;
+ u64 sequence;
+ struct vframe_block_list_s *block;
+};
+
+#define VDEC_INPUT_TARGET_VLD 0
+#define VDEC_INPUT_TARGET_HEVC 1
+
+struct vdec_input_s {
+ struct list_head vframe_block_list;
+ struct list_head vframe_chunk_list;
+ struct vframe_block_list_s *wr_block;
+ spinlock_t lock;
+ int type;
+ int target;
+ struct vdec_s *vdec;
+ bool swap_valid;
+ bool swap_needed;
+ struct page *swap_page;
+ int total_wr_count;
+ int total_rd_count;
+ u64 sequence;
+ unsigned start;
+ unsigned size;
+ int stream_cookie; /* wrap count for vld_mem and*/
+ /*HEVC_SHIFT_BYTE_COUNT for hevc */
+};
+
+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);
+
+/* 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);
+
+/* 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);
+
+#endif /* VDEC_INPUT_H */
diff --git a/drivers/frame_provider/decoder/vc1/vvc1.c b/drivers/frame_provider/decoder/vc1/vvc1.c
new file mode 100644
index 0000000..3495d92
--- a/dev/null
+++ b/drivers/frame_provider/decoder/vc1/vvc1.c
@@ -0,0 +1,1170 @@
+/*
+ * 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.
+ *
+*/
+
+#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"
+
+#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 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 32
+#define DECODE_BUFFER_NUM_MAX 8
+#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 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 void vvc1_prot_init(void);
+static void vvc1_local_init(void);
+
+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 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 unsigned long buf_start;
+static u32 buf_size, buf_offset;
+static u32 avi_flag;
+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;
+
+#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 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:
+ ar = (vf->height * vvc1_ratio) / vf->width;
+ break;
+ case 2:
+ ar = (vf->height * 11 * vvc1_ratio) / (vf->width * 12);
+ break;
+ case 3:
+ ar = (vf->height * 11 * vvc1_ratio) / (vf->width * 10);
+ break;
+ case 4:
+ ar = (vf->height * 11 * vvc1_ratio) / (vf->width * 16);
+ break;
+ case 5:
+ ar = (vf->height * 33 * vvc1_ratio) / (vf->width * 40);
+ break;
+ case 6:
+ ar = (vf->height * 11 * vvc1_ratio) / (vf->width * 24);
+ break;
+ case 7:
+ ar = (vf->height * 11 * vvc1_ratio) / (vf->width * 20);
+ break;
+ case 8:
+ ar = (vf->height * 11 * vvc1_ratio) / (vf->width * 32);
+ break;
+ case 9:
+ ar = (vf->height * 33 * vvc1_ratio) / (vf->width * 80);
+ break;
+ case 10:
+ ar = (vf->height * 11 * vvc1_ratio) / (vf->width * 18);
+ break;
+ case 11:
+ ar = (vf->height * 11 * vvc1_ratio) / (vf->width * 15);
+ break;
+ case 12:
+ ar = (vf->height * 33 * vvc1_ratio) / (vf->width * 64);
+ break;
+ case 13:
+ ar = (vf->height * 99 * vvc1_ratio) /
+ (vf->width * 160);
+ break;
+ default:
+ 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 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;
+ u32 v_width, v_height;
+ u64 pts_us64 = 0;
+
+ reg = READ_VREG(VC1_BUFFEROUT);
+
+ if (reg) {
+ v_width = READ_VREG(AV_SCRATCH_J);
+ v_height = READ_VREG(AV_SCRATCH_K);
+
+ 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, 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;
+ 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 (0 == vvc1_amstream_dec_info.rate)
+ 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;
+ }
+ } 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 +=
+ ((vf->duration) -
+ ((vf->duration) >> 4)) *
+ 100 / 9;
+ }
+ } else {
+ vf->duration =
+ vvc1_amstream_dec_info.rate >> 1;
+ next_pts = 0;
+ next_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]++;
+
+ kfifo_put(&display_q, (const struct vframe_s *)vf);
+
+ 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 += ((vf->duration) -
+ ((vf->duration) >> 4)) * 100 / 9;
+ }
+ } else {
+ vf->duration =
+ vvc1_amstream_dec_info.rate >> 1;
+ next_pts = 0;
+ next_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]++;
+
+ kfifo_put(&display_q, (const struct vframe_s *)vf);
+
+ 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;
+ }
+ } 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 +=
+ ((vf->duration) -
+ ((vf->duration) >> 4)) *
+ 100 / 9;
+ }
+ } else {
+ vf->duration =
+ vvc1_amstream_dec_info.rate;
+ next_pts = 0;
+ next_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]++;
+
+ kfifo_put(&display_q, (const struct vframe_s *)vf);
+
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY,
+ NULL);
+ }
+ frame_dur = vvc1_amstream_dec_info.rate;
+ total_frame++;
+
+ /* 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();
+ vvc1_prot_init();
+ spin_unlock_irqrestore(&lock, flags);
+#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vf_reg_provider(&vvc1_vf_prov);
+#endif
+ amvdec_start();
+ }
+ return 0;
+}
+
+int vvc1_dec_status(struct vdec_s *vdec, struct vdec_status *vstatus)
+{
+ vstatus->width = vvc1_amstream_dec_info.width;
+ vstatus->height = vvc1_amstream_dec_info.height;
+ if (0 != vvc1_amstream_dec_info.rate)
+ vstatus->fps = 96000 / vvc1_amstream_dec_info.rate;
+ else
+ vstatus->fps = 96000;
+ vstatus->error_count = READ_VREG(AV_SCRATCH_4);
+ vstatus->status = stat;
+
+ return 0;
+}
+
+/****************************************/
+static void vvc1_canvas_init(void)
+{
+ int i;
+ u32 canvas_width, canvas_height;
+ u32 decbuf_size, decbuf_y_size, decbuf_uv_size;
+ u32 disp_addr = 0xffffffff;
+
+ 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;
+ }
+
+ if (is_vpp_postblend()) {
+ struct canvas_s cur_canvas;
+
+ canvas_read((READ_VCBUS_REG(VD1_IF0_CANVAS0) & 0xff),
+ &cur_canvas);
+ disp_addr = (cur_canvas.addr + 7) >> 3;
+ }
+
+ for (i = 0; i < 8; i++) {
+ if (((buf_start + i * decbuf_size + 7) >> 3) == disp_addr) {
+#ifdef NV21
+ canvas_config(2 * i + 0,
+ buf_start + 8 * decbuf_size,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+ canvas_config(2 * i + 1,
+ buf_start + 8 * decbuf_size +
+ decbuf_y_size, canvas_width,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+#else
+ canvas_config(3 * i + 0,
+ buf_start + 8 * decbuf_size,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+ canvas_config(3 * i + 1,
+ buf_start + 8 * decbuf_size +
+ decbuf_y_size, canvas_width / 2,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+ canvas_config(3 * i + 2,
+ buf_start + 8 * decbuf_size +
+ decbuf_y_size + decbuf_uv_size,
+ canvas_width / 2, canvas_height / 2,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+#endif
+ } else {
+#ifdef NV21
+ canvas_config(2 * i + 0,
+ buf_start + i * decbuf_size,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+ canvas_config(2 * i + 1,
+ buf_start + i * decbuf_size +
+ decbuf_y_size, canvas_width,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+#else
+ canvas_config(3 * i + 0,
+ buf_start + i * decbuf_size,
+ canvas_width, canvas_height,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+ canvas_config(3 * i + 1,
+ buf_start + i * decbuf_size +
+ decbuf_y_size, canvas_width / 2,
+ canvas_height / 2, CANVAS_ADDR_NOWRAP,
+ CANVAS_BLKMODE_32X32);
+ canvas_config(3 * i + 2,
+ buf_start + i * decbuf_size +
+ decbuf_y_size + decbuf_uv_size,
+ canvas_width / 2, canvas_height / 2,
+ CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32);
+#endif
+ }
+ }
+}
+
+static void vvc1_prot_init(void)
+{
+#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_MPEG_REG(RESET0_REGISTER,
+ RESET_IQIDCT | RESET_MC | RESET_VLD_PART);
+ READ_MPEG_REG(RESET0_REGISTER);
+ WRITE_MPEG_REG(RESET0_REGISTER,
+ RESET_IQIDCT | RESET_MC | RESET_VLD_PART);
+
+ WRITE_MPEG_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);
+
+ 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
+}
+
+static void vvc1_local_init(void)
+{
+ int i;
+
+ /* vvc1_ratio = vvc1_amstream_dec_info.ratio; */
+ vvc1_ratio = 0x100;
+
+ avi_flag = (unsigned long) vvc1_amstream_dec_info.param;
+
+ 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));
+
+ 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);
+ }
+}
+
+#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();
+
+ /* vf_notify_receiver(PROVIDER_NAME,
+ * VFRAME_EVENT_PROVIDER_START,NULL); */
+
+ pr_info("vvc1dec: vf_ppmgr_reset\n");
+}
+#endif
+
+static void vvc1_put_timer_func(unsigned long arg)
+{
+ struct timer_list *timer = (struct timer_list *)arg;
+
+#if 1
+ if (READ_VREG(VC1_SOS_COUNT) > 10) {
+ amvdec_stop();
+#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
+ vvc1_ppmgr_reset();
+#else
+ vf_light_unreg_provider(&vvc1_vf_prov);
+ vvc1_local_init();
+ vf_reg_provider(&vvc1_vf_prov);
+#endif
+ vvc1_prot_init();
+ amvdec_start();
+ }
+#endif
+
+ 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)) {
+ int fps = 96000 / frame_dur;
+ saved_resolution = frame_width * frame_height * fps;
+ vdec_source_changed(VFORMAT_VC1,
+ frame_width, frame_height, fps);
+ }
+ timer->expires = jiffies + PUT_INTERVAL;
+
+ add_timer(timer);
+}
+
+static s32 vvc1_init(void)
+{
+ int size = -1;
+ char *buf = vmalloc(0x1000 * 16);
+ 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();
+
+ 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");
+
+ size = get_firmware_data(VIDEO_DEC_VC1, buf);
+ if (size < 0) {
+ pr_err("get firmware fail.");
+ vfree(buf);
+ return -1;
+ }
+
+ if (amvdec_loadmc_ex(VFORMAT_VC1, NULL, buf) < 0) {
+ amvdec_disable();
+ vfree(buf);
+ return -EBUSY;
+ }
+
+ vfree(buf);
+
+ stat |= STAT_MC_LOAD;
+
+ /* enable AMRISC side protocol */
+ vvc1_prot_init();
+
+ 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
+
+ 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;
+ }
+
+ buf_start = pdata->mem_start;
+ buf_size = pdata->mem_end - pdata->mem_start + 1;
+ buf_offset = buf_start - ORI_BUFFER_START_ADDR;
+
+ if (pdata->sys_info)
+ vvc1_amstream_dec_info = *pdata->sys_info;
+
+ pdata->dec_status = vvc1_dec_status;
+
+ if (vvc1_init() < 0) {
+ pr_info("amvdec_vc1 init failed.\n");
+
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int amvdec_vc1_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 *)vvc1_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) {
+ vf_notify_receiver(PROVIDER_NAME,
+ VFRAME_EVENT_PROVIDER_FR_END_HINT, NULL);
+
+ vf_unreg_provider(&vvc1_vf_prov);
+ stat &= ~STAT_VF_HOOK;
+ }
+
+ amvdec_disable();
+
+#ifdef DEBUG_PTS
+ pr_info("pts hit %d, pts missed %d, i hit %d, missed %d\n", pts_hit,
+ pts_missed, pts_i_hit, pts_i_missed);
+ pr_info("total frame %d, avi_flag %d, rate %d\n",
+ total_frame, avi_flag,
+ vvc1_amstream_dec_info.rate);
+#endif
+
+ return 0;
+}
+
+/****************************************/
+
+static struct platform_driver amvdec_vc1_driver = {
+ .probe = amvdec_vc1_probe,
+ .remove = amvdec_vc1_remove,
+#ifdef CONFIG_PM
+ .suspend = amvdec_suspend,
+ .resume = amvdec_resume,
+#endif
+ .driver = {
+ .name = DRIVER_NAME,
+ }
+};
+
+#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(stat, uint, 0664);
+MODULE_PARM_DESC(stat, "\n amvdec_vc1 stat\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/vvp9.c b/drivers/frame_provider/decoder/vp9/vvp9.c
new file mode 100644
index 0000000..0e819e7
--- a/dev/null
+++ b/drivers/frame_provider/decoder/vp9/vvp9.c
@@ -0,0 +1,6922 @@
+ /*
+ * 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.
+ *
+*/
+#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 "../../../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"
+
+#include <linux/amlogic/media/video_sink/video.h>
+
+#define MIX_STREAM_SUPPORT
+#define SUPPORT_4K2K
+
+#include "vvp9.h"
+#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_SAO_MMU_STATUS 0x3639
+
+
+#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 VP9_HEAD_PARSER_DONE 0xf0
+#define VP9_HEAD_SEARCH_DONE 0xf1
+#define VP9_EOS 0xf2
+#define HEVC_ACTION_DONE 0xff
+
+#define MAX_BUF_NUM 24
+#define MAX_REF_ACTIVE 16
+#define VF_POOL_SIZE 32
+
+#undef pr_info
+#define pr_info printk
+
+#define DECODE_MODE_SINGLE 0
+#define DECODE_MODE_MULTI_STREAMBASE 1
+#define DECODE_MODE_MULTI_FRAMEBASE 2
+
+/*---------------------------------------------------
+ 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
+};
+/*#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 */
+#if 0 /* MESON_CPU_TYPE == MESON_CPU_TYPE_MESON8B*/
+#undef SUPPORT_4K2K
+#else
+#define SUPPORT_4K2K
+#endif
+
+#ifndef STAT_KTHREAD
+#define STAT_KTHREAD 0x40
+#endif
+
+#ifdef MULTI_INSTANCE_SUPPORT
+#define MAX_DECODE_INSTANCE_NUM 5
+#define MULTI_DRIVER_NAME "ammvdec_vp9"
+#endif
+
+#define DRIVER_NAME "amvdec_vp9"
+#define MODULE_NAME "amvdec_vp9"
+
+#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);
+static s32 vvp9_init(struct VP9Decoder_s *pbi);
+static void vvp9_prot_init(struct VP9Decoder_s *pbi);
+static int vvp9_local_init(struct VP9Decoder_s *pbi);
+static void vvp9_put_timer_func(unsigned long arg);
+#ifdef VP9_10B_MMU
+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);
+#endif
+
+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 pts_unstable;
+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 FRAME_MMU_MAP_SIZE (MAX_FRAME_4K_NUM * 4)
+
+static inline int div_r32(int64_t m, int n)
+{
+/*
+return (int)(m/n)
+*/
+#ifndef CONFIG_ARM64
+ do_div(m, n);
+ return (int)m;
+#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;
+} /*BUF_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*/
+#define MCRCC_ENABLE
+
+#ifdef VP9_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
+
+#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_UCODE 0x04
+#define VP9_DEBUG_REG 0x08
+#define VP9_DEBUG_MERGE 0x10
+#define VP9_DEBUG_BASIC 0x40
+#define VP9_DEBUG_SEND_PARAM_WITH_REG 0x100
+#define VP9_DEBUG_NO_DISPLAY 0x200
+#define VP9_DEBUG_DBG_LF_PRINT 0x400
+#define VP9_DEBUG_OUT_PTS 0x800
+#define VP9_DEBUG_VF_REF 0x1000
+#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_HW_RESET 0x100000
+#define VP9_DEBUG_LOAD_UCODE_FROM_FILE 0x200000
+#define VP9_DEBUG_ERROR_TRIG 0x400000
+#define VP9_DEBUG_NOWAIT_DECODE_DONE_WHEN_STOP 0x4000000
+#ifdef MULTI_INSTANCE_SUPPORT
+#define PRINT_FLAG_ERROR 0
+#define PRINT_FLAG_UCODE_EVT 0x10000000
+#define PRINT_FLAG_VDEC_STATUS 0x20000000
+#define PRINT_FLAG_VDEC_DETAIL 0x40000000
+#define PRINT_FLAG_VDEC_DATA 0x80000000
+#endif
+
+static u32 debug;
+
+#define DEBUG_REG
+#ifdef DEBUG_REG
+void WRITE_VREG_DBG2(unsigned adr, unsigned 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
+
+/**************************************************
+
+VP9 buffer management start
+
+***************************************************/
+#ifdef VP9_10B_MMU
+#define MMU_COMPRESS_HEADER_SIZE 0x48000
+#endif
+
+#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 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 num_reorder_pic;
+ int stream_offset;
+ uint8_t used_by_display;
+ uint8_t referenced;
+ uint8_t output_mark;
+ uint8_t recon_mark;
+ uint8_t output_ready;
+ uint8_t error_mark;
+ /**/
+ int slice_idx;
+ /*buffer*/
+#ifdef VP9_10B_MMU
+ unsigned long header_adr;
+#endif
+ unsigned long mpred_mv_wr_start_addr;
+ 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;
+} 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)
+
+/*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 + 7)
+
+#define FRAME_CONTEXTS_LOG2 2
+#define FRAME_CONTEXTS (1 << FRAME_CONTEXTS_LOG2)
+#define MAX_BMMU_BUFFER_NUM (FRAME_BUFFERS + 1)
+#define WORK_SPACE_BUF_ID (FRAME_BUFFERS)
+
+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;
+
+static void lock_buffer_pool(struct BufferPool_s *pool)
+{
+ spin_lock_irqsave(&pool->lock, pool->flags);
+}
+static void unlock_buffer_pool(struct BufferPool_s *pool)
+{
+ spin_unlock_irqrestore(&pool->lock, pool->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;
+
+ /*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;
+
+} VP9_COMMON;
+
+static void set_canvas(struct PIC_BUFFER_CONFIG_s *pic_config);
+static int prepare_display_buf(struct VP9Decoder_s *pbi,
+ struct PIC_BUFFER_CONFIG_s *pic_config);
+static int get_free_fb(struct VP9_Common_s *cm)
+{
+ struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs;
+ int i;
+
+ lock_buffer_pool(cm->buffer_pool);
+ for (i = 0; i < FRAME_BUFFERS; ++i) {
+ if (debug & VP9_DEBUG_BUFMGR_MORE)
+ pr_info("%s:%d, ref_count %d vf_ref %d used_by_d %d index %d\r\n",
+ __func__, i, frame_bufs[i].ref_count,
+ frame_bufs[i].buf.vf_ref,
+ frame_bufs[i].buf.used_by_display,
+ frame_bufs[i].buf.index);
+ if ((frame_bufs[i].ref_count == 0) &&
+ (frame_bufs[i].buf.vf_ref == 0) &&
+ (frame_bufs[i].buf.used_by_display == 0) &&
+ (frame_bufs[i].buf.index != -1)
+ )
+ break;
+ }
+ if (i != FRAME_BUFFERS) {
+ 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);
+ return i;
+}
+
+static unsigned char is_buffer_empty(struct VP9_Common_s *cm)
+{
+ struct RefCntBuffer_s *const frame_bufs = cm->buffer_pool->frame_bufs;
+ int i;
+
+ for (i = 0; i < FRAME_BUFFERS; ++i)
+ if ((frame_bufs[i].ref_count == 0) &&
+ (frame_bufs[i].buf.vf_ref == 0) &&
+ (frame_bufs[i].buf.used_by_display == 0) &&
+ (frame_bufs[i].buf.index != -1)
+ )
+ break;
+ if (i != FRAME_BUFFERS)
+ return 0;
+
+ return 1;
+}
+
+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");
+ }
+}
+
+static void resize_context_buffers(struct VP9_Common_s *cm, int width,
+ int height)
+{
+ if (cm->width != width || cm->height != height) {
+ /* to do ..*/
+ cm->width = width;
+ cm->height = height;
+ pr_info("%s (%d,%d)=>(%d,%d)\r\n", __func__, cm->width,
+ cm->height, width, 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;
+ /*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_MMU
+ /* 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 mmu1,idx %d ret =%d\n",
+ cm->new_fb_idx,
+ ret);
+ return ret;
+ }
+#endif
+
+ resize_context_buffers(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);
+ 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 (width <= 0 || height <= 0) {
+ pr_err("Error: Invalid frame size\r\n");
+ return -1;
+ }
+
+ params->p.width = width;
+ params->p.height = height;
+
+ WRITE_VREG(HEVC_PARSER_PICTURE_SIZE, (height << 16) | width);
+#ifdef VP9_10B_MMU
+ /*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;
+ }
+#endif
+
+ /*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(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);
+ 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;
+}
+
+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;
+#ifdef VP9_10B_MMU
+ struct buff_s mmu_vbh;
+ struct buff_s cm_header;
+#endif
+ struct buff_s mpred_above;
+ struct buff_s mpred_mv;
+ 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
+
+static void vp9_work(struct work_struct *work);
+#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 BuffInfo_s work_space_buf_store;
+ unsigned long buf_start;
+ u32 buf_size;
+ u32 cma_alloc_count;
+ unsigned long cma_alloc_addr;
+#endif
+ 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 process_busy;
+ 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;
+
+#if 1
+ /*VP9_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];
+ 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];
+ 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 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*/
+
+ u32 pre_stream_offset;
+
+ unsigned int dec_status;
+ u32 last_put_idx;
+ int new_frame_displayed;
+ void *mmu_box;
+ void *bmmu_box;
+} VP9Decoder;
+
+static int vp9_print(struct VP9Decoder_s *pbi,
+ int flag, const char *fmt, ...)
+{
+#define HEVC_PRINT_BUF 128
+ 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_info("%s", buf);
+ va_end(args);
+ }
+ return 0;
+}
+
+#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_info("%s", buf);
+ va_end(args);
+ }
+ return 0;
+}
+#endif
+
+#ifdef VP9_10B_MMU
+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;
+
+ picture_size = compute_losless_comp_body_size(pic_width, pic_height,
+ bit_depth_10);
+ cur_mmu_4k_number = ((picture_size + (1 << 12) - 1) >> 12);
+ return decoder_mmu_box_alloc_idx(
+ pbi->mmu_box,
+ cur_buf_idx,
+ cur_mmu_4k_number,
+ mmu_index_adr);
+}
+#endif
+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;
+
+ /* Generate next_ref_frame_map.*/
+ lock_buffer_pool(pool);
+ 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);
+ 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;
+
+ lock_buffer_pool(pool);
+ 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);
+ 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;
+ 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;
+#ifdef VP9_10B_MMU
+ if (cm->prev_fb_idx >= 0) {
+ long used_4k_num = (READ_VREG(HEVC_SAO_MMU_STATUS) >> 16);
+ decoder_mmu_box_free_idx_tail(pbi->mmu_box,
+ cm->prev_fb_idx, 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);*/
+ cm->new_fb_idx = get_free_fb(cm);
+ 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);*/
+ if (cm->new_fb_idx == INVALID_IDX) {
+ pr_info("get_free_fb error\r\n");
+ return -1;
+ }
+ pbi->cur_buf = &frame_bufs[cm->new_fb_idx];
+#ifdef VP9_10B_MMU
+ /* 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;
+#endif
+ /*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;
+ 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);
+ if (frame_to_show < 0 ||
+ frame_bufs[frame_to_show].ref_count < 1) {
+ unlock_buffer_pool(pool);
+ 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);
+ 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->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*/
+ }
+ }
+ }
+
+ get_frame_new_buffer(cm)->bit_depth = cm->bit_depth;
+ get_frame_new_buffer(cm)->color_space = cm->color_space;
+ get_frame_new_buffer(cm)->slice_type = cm->frame_type;
+
+ if (pbi->need_resync)
+ pr_err
+ ("Error: Keyframe/intra-only frame required to reset\r\n");
+ 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);*/
+ 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;
+ refresh_ref_frames(pbi);
+ pbi->hold_ref_buf = 0;
+ cm->frame_to_show = get_frame_new_buffer(cm);
+
+ /*if (!pbi->frame_parallel_decode || !cm->show_frame) {*/
+ lock_buffer_pool(pool);
+ --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);
+ /*}*/
+
+ /*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;
+
+ 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));*/
+ 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;
+ pr_info
+ ("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;
+ 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 VP9_Common_s *cm = &pbi->common;
+ struct PIC_BUFFER_CONFIG_s sd;
+ 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;
+ 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;
+}
+
+struct VP9Decoder_s vp9_decoder;
+union param_u vp9_param;
+
+/**************************************************
+
+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
+/* 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
+ 0x10, double write only
+*/
+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 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_stop_pos;
+static u32 decode_stop_pos_pre;
+static u32 decode_pic_begin;
+static uint slice_parse_begin;
+static u32 step;
+#ifdef MIX_STREAM_SUPPORT
+#ifdef SUPPORT_4K2K
+static u32 buf_alloc_width = 4096;
+static u32 buf_alloc_height = 2304;
+#else
+static u32 buf_alloc_width = 1920;
+static u32 buf_alloc_height = 1088;
+#endif
+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;
+
+/*
+use_cma: 1, use both reserver memory and cma for buffers
+2, only use cma for buffers
+*/
+static u32 use_cma = 2;
+
+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;*/
+
+static u32 max_buf_num = 12;
+
+
+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
+#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 WORK_BUF_SPEC_NUM 2
+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 = 0x4000,
+ },
+ .sao_abv = {
+ .buf_size = 0x30000,
+ },
+ .sao_vb = {
+ .buf_size = 0x30000,
+ },
+ .short_term_rps = {
+ /* SHORT_TERM_RPS - Max 64 set, 16 entry every set,
+ total 64x16x2 = 2048 bytes (0x800) */
+ .buf_size = 0x800,
+ },
+ .vps = {
+ /* VPS STORE AREA - Max 16 VPS, each has 0x80 bytes,
+ total 0x0800 bytes */
+ .buf_size = 0x800,
+ },
+ .sps = {
+ /* SPS STORE AREA - Max 16 SPS, each has 0x80 bytes,
+ total 0x0800 bytes */
+ .buf_size = 0x800,
+ },
+ .pps = {
+ /* PPS STORE AREA - Max 64 PPS, each has 0x80 bytes,
+ total 0x2000 bytes */
+ .buf_size = 0x2000,
+ },
+ .sao_up = {
+ /* SAO UP STORE AREA - Max 640(10240/16) LCU,
+ each has 16 bytes total 0x2800 bytes */
+ .buf_size = 0x2800,
+ },
+ .swap_buf = {
+ /* 256cyclex64bit = 2K bytes 0x800
+ (only 144 cycles valid) */
+ .buf_size = 0x800,
+ },
+ .swap_buf2 = {
+ .buf_size = 0x800,
+ },
+ .scalelut = {
+ /* support up to 32 SCALELUT 1024x32 =
+ 32Kbytes (0x8000) */
+ .buf_size = 0x8000,
+ },
+ .dblk_para = {
+ /* DBLK -> Max 256(4096/16) LCU,
+ each para 1024bytes(total:0x40000),
+ data 1024bytes(total:0x40000)*/
+ .buf_size = 0x80000,
+ },
+ .dblk_data = {
+ .buf_size = 0x80000,
+ },
+ .seg_map = {
+ /*4096x2304/64/64 *24 = 0xd800 Bytes*/
+ .buf_size = 0xd800,
+ },
+#ifdef VP9_10B_MMU
+ .mmu_vbh = {
+ .buf_size = 0x5000, /*2*16*(more than 2304)/4, 4K*/
+ },
+ .cm_header = {
+ /*add one for keeper.*/
+ .buf_size = MMU_COMPRESS_HEADER_SIZE *
+ (FRAME_BUFFERS + 1),
+ /* 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) */
+ },
+#endif
+ .mpred_above = {
+ .buf_size = 0x10000, /* 2 * size of hevc*/
+ },
+ .mpred_mv = {/* 1080p, 0x40000 per buffer */
+ .buf_size = 0x40000 * FRAME_BUFFERS,
+ },
+ .rpm = {
+ .buf_size = RPM_BUF_SIZE,
+ },
+ .lmem = {
+ .buf_size = 0x400 * 2,
+ }
+ },
+ {
+ .max_width = 4096,
+ .max_height = 2304,
+ .ipp = {
+ /* IPP work space calculation :
+ 4096 * (Y+CbCr+Flags) = 12k, round to 16k */
+ .buf_size = 0x4000,
+ },
+ .sao_abv = {
+ .buf_size = 0x30000,
+ },
+ .sao_vb = {
+ .buf_size = 0x30000,
+ },
+ .short_term_rps = {
+ /* SHORT_TERM_RPS - Max 64 set, 16 entry every set,
+ total 64x16x2 = 2048 bytes (0x800) */
+ .buf_size = 0x800,
+ },
+ .vps = {
+ /* VPS STORE AREA - Max 16 VPS, each has 0x80 bytes,
+ total 0x0800 bytes */
+ .buf_size = 0x800,
+ },
+ .sps = {
+ /* SPS STORE AREA - Max 16 SPS, each has 0x80 bytes,
+ total 0x0800 bytes */
+ .buf_size = 0x800,
+ },
+ .pps = {
+ /* PPS STORE AREA - Max 64 PPS, each has 0x80 bytes,
+ total 0x2000 bytes */
+ .buf_size = 0x2000,
+ },
+ .sao_up = {
+ /* SAO UP STORE AREA - Max 640(10240/16) LCU,
+ each has 16 bytes total 0x2800 bytes */
+ .buf_size = 0x2800,
+ },
+ .swap_buf = {
+ /* 256cyclex64bit = 2K bytes 0x800
+ (only 144 cycles valid) */
+ .buf_size = 0x800,
+ },
+ .swap_buf2 = {
+ .buf_size = 0x800,
+ },
+ .scalelut = {
+ /* support up to 32 SCALELUT 1024x32 = 32Kbytes
+ (0x8000) */
+ .buf_size = 0x8000,
+ },
+ .dblk_para = {
+ /* DBLK -> Max 256(4096/16) LCU,
+ each para 1024bytes(total:0x40000),
+ data 1024bytes(total:0x40000)*/
+ .buf_size = 0x80000,
+ },
+ .dblk_data = {
+ .buf_size = 0x80000,
+ },
+ .seg_map = {
+ /*4096x2304/64/64 *24 = 0xd800 Bytes*/
+ .buf_size = 0xd800,
+ },
+#ifdef VP9_10B_MMU
+ .mmu_vbh = {
+ .buf_size = 0x5000,/*2*16*(more than 2304)/4, 4K*/
+ },
+ .cm_header = {
+ /*add one for keeper.*/
+ .buf_size = MMU_COMPRESS_HEADER_SIZE *
+ (FRAME_BUFFERS + 1),
+ /* 0x44000 = ((1088*2*1024*4)/32/4)*(32/8) */
+ },
+#endif
+ .mpred_above = {
+ .buf_size = 0x10000, /* 2 * size of hevc*/
+ },
+ .mpred_mv = {
+ /* .buf_size = 0x100000*16,
+ //4k2k , 0x100000 per buffer */
+ /* 4096x2304 , 0x120000 per buffer */
+ .buf_size = 0x120000 * FRAME_BUFFERS,
+ },
+ .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;
+#ifdef VP9_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
+ 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;
+#ifdef VP9_10B_MMU
+ buf_spec->mmu_vbh.buf_start =
+ buf_spec->seg_map.buf_start + buf_spec->seg_map.buf_size;
+ buf_spec->cm_header.buf_start =
+ buf_spec->mmu_vbh.buf_start + buf_spec->mmu_vbh.buf_size;
+ buf_spec->mpred_above.buf_start =
+ buf_spec->cm_header.buf_start + buf_spec->cm_header.buf_size;
+#else
+ buf_spec->mpred_above.buf_start =
+ buf_spec->seg_map.buf_start + buf_spec->seg_map.buf_size;
+#endif
+ buf_spec->mpred_mv.buf_start =
+ buf_spec->mpred_above.buf_start +
+ buf_spec->mpred_above.buf_size;
+ if (debug & VP9_DEBUG_SEND_PARAM_WITH_REG) {
+ buf_spec->end_adr =
+ buf_spec->mpred_mv.buf_start +
+ buf_spec->mpred_mv.buf_size;
+ } else {
+ buf_spec->rpm.buf_start =
+ buf_spec->mpred_mv.buf_start +
+ buf_spec->mpred_mv.buf_size;
+ if (debug & VP9_DEBUG_UCODE) {
+ 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;
+ } else {
+ buf_spec->end_adr =
+ buf_spec->rpm.buf_start +
+ buf_spec->rpm.buf_size;
+ }
+ }
+ 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("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);
+#ifdef VP9_10B_MMU
+ pr_info("mmu_vbh.buf_start :%x\n",
+ buf_spec->mmu_vbh.buf_start);
+ pr_info("cm_header.buf_start :%x\n",
+ buf_spec->cm_header.buf_start);
+#endif
+ pr_info("mpred_above.buf_start :%x\n",
+ buf_spec->mpred_above.buf_start);
+ pr_info("mpred_mv.buf_start :%x\n",
+ buf_spec->mpred_mv.buf_start);
+ if ((debug & VP9_DEBUG_SEND_PARAM_WITH_REG) == 0) {
+ pr_info("rpm.buf_start :%x\n",
+ buf_spec->rpm.buf_start);
+ }
+ }
+
+}
+
+/*====================================================
+========================================================================
+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 void uninit_mmu_buffers(struct VP9Decoder_s *pbi)
+{
+
+ 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;
+}
+
+#ifndef VP9_10B_MMU
+static void init_buf_list(struct VP9Decoder_s *pbi)
+{
+ int i;
+ int buf_size;
+#ifndef VP9_10B_MMU
+ int mc_buffer_end = pbi->mc_buf->buf_start + pbi->mc_buf->buf_size;
+#endif
+ pbi->used_buf_num = max_buf_num;
+
+ if (pbi->used_buf_num > MAX_BUF_NUM)
+ pbi->used_buf_num = MAX_BUF_NUM;
+ if (buf_alloc_size > 0) {
+ buf_size = buf_alloc_size;
+ if (debug)
+ pr_info("[Buffer Management] init_buf_list:\n");
+ } else {
+ int pic_width = pbi->init_pic_w;
+ int pic_height = pbi->init_pic_h;
+
+ /*SUPPORT_10BIT*/
+ 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;
+ if (double_write_mode) {
+ int pic_width_dw = (double_write_mode == 2) ?
+ pic_width / 2 : pic_width;
+ int pic_height_dw = (double_write_mode == 2) ?
+ pic_height / 2 : pic_height;
+ 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 ((double_write_mode & 0x10) == 0)
+ buf_size += (mc_buffer_size_h << 16);
+ if (debug) {
+ pr_info
+ ("init_buf_list num %d (width %d height %d):\n",
+ pbi->used_buf_num, pic_width, pic_height);
+ }
+ }
+
+ for (i = 0; i < pbi->used_buf_num; i++) {
+ if (((i + 1) * buf_size) > pbi->mc_buf->buf_size) {
+ if (use_cma)
+ pbi->use_cma_flag = 1;
+ else {
+ if (debug) {
+ pr_info("%s maximum buf size is used\n",
+ __func__);
+ }
+ break;
+ }
+ }
+#ifndef VP9_10B_MMU
+ pbi->m_BUF[i].alloc_flag = 0;
+ pbi->m_BUF[i].index = i;
+
+ if (use_cma == 2)
+ pbi->use_cma_flag = 1;
+ if (pbi->use_cma_flag) {
+ if (!decoder_bmmu_box_alloc_idx_wait(
+ pbi->bmmu_box,
+ i,
+ buf_size,
+ -1,
+ -1,
+ BMMU_ALLOC_FLAGS_WAITCLEAR)) {
+ pbi->m_BUF[i].alloc_addr =
+ decoder_bmmu_box_get_phy_addr(
+ pbi->bmmu_box,
+ i);
+ pbi->m_BUF[i].cma_page_count =
+ PAGE_ALIGN(buf_size) / PAGE_SIZE;
+ pr_info("CMA malloc ok %d\n", i);
+ } else {
+ pbi->m_BUF[i].cma_page_count = 0;
+ pr_info("CMA malloc failed %d\n", i);
+ if (i <= 5) {
+ pbi->fatal_error |=
+ DECODER_FATAL_ERROR_NO_MEM;
+ }
+ break;
+ }
+ pbi->m_BUF[i].start_adr = pbi->m_BUF[i].alloc_addr;
+ } else {
+ pbi->m_BUF[i].cma_page_count = 0;
+ pbi->m_BUF[i].alloc_addr = 0;
+ pbi->m_BUF[i].start_adr =
+ pbi->mc_buf->buf_start + i * buf_size;
+ }
+ pbi->m_BUF[i].size = buf_size;
+ pbi->m_BUF[i].free_start_adr = pbi->m_BUF[i].start_adr;
+
+ if (((pbi->m_BUF[i].start_adr + buf_size) > mc_buffer_end)
+ && (pbi->m_BUF[i].alloc_addr == 0)) {
+ if (debug) {
+ pr_info
+ ("Max mc buffer or mpred_mv buffer is used\n");
+ }
+ break;
+ }
+
+ if (debug) {
+ pr_info("Buffer %d: start_adr %p size %x\n", i,
+ (void *)pbi->m_BUF[i].start_adr,
+ pbi->m_BUF[i].size);
+ }
+#endif
+ }
+ pbi->buf_num = i;
+}
+#endif
+static int config_pic(struct VP9Decoder_s *pbi,
+ struct PIC_BUFFER_CONFIG_s *pic_config,
+ unsigned long last_disp_addr)
+{
+ int ret = -1;
+ int i;
+ int pic_width = pbi->init_pic_w;
+ int pic_height = pbi->init_pic_h;
+ int MV_MEM_UNIT = 0x240;
+ 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;
+
+ u32 mpred_mv_end = pbi->work_space_buf->mpred_mv.buf_start +
+ pbi->work_space_buf->mpred_mv.buf_size;
+ 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;
+ if (double_write_mode) {
+ int pic_width_dw = (double_write_mode == 2) ?
+ pic_width / 2 : pic_width;
+ int pic_height_dw = (double_write_mode == 2) ?
+ pic_height / 2 : pic_height;
+ 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 VP9_10B_MMU
+ if ((double_write_mode & 0x10) == 0)
+ buf_size += (mc_buffer_size_h << 16);
+#endif
+
+#ifdef VP9_10B_MMU
+ if ((pbi->work_space_buf->cm_header.buf_start +
+ ((pic_config->index + 2)
+ * MMU_COMPRESS_HEADER_SIZE))
+ > (pbi->work_space_buf->cm_header.buf_start +
+ pbi->work_space_buf->cm_header.buf_size)) {
+ pr_info("MMU header_adr allocate fail\n");
+ return -1;
+ }
+
+ pic_config->header_adr = pbi->work_space_buf->cm_header.buf_start
+ + (pic_config->index * MMU_COMPRESS_HEADER_SIZE);
+ if (last_disp_addr && pic_config->header_adr == last_disp_addr) {
+ /*if same as disp add used last one.*/
+ pr_info("same as disp %d: %ld\n",
+ pic_config->index, pic_config->header_adr);
+ pic_config->header_adr =
+ pbi->work_space_buf->cm_header.buf_start +
+ (FRAME_BUFFERS * MMU_COMPRESS_HEADER_SIZE);
+ }
+ if (debug & VP9_DEBUG_BUFMGR) {
+ pr_info("MMU header_adr %d: %ld\n",
+ pic_config->index, pic_config->header_adr);
+ }
+#endif
+
+ i = pic_config->index;
+ if ((pbi->work_space_buf->mpred_mv.buf_start +
+ (((i + 1) * lcu_total) * MV_MEM_UNIT))
+ <= mpred_mv_end
+#ifdef VP9_10B_MMU
+#endif
+ ) {
+ if (debug) {
+ pr_err("start %x .size=%d\n",
+ pbi->mc_buf_spec.buf_start + i * buf_size,
+ buf_size);
+ }
+
+#ifndef VP9_10B_MMU
+ for (i = 0; i < pbi->buf_num; i++) {
+ y_adr = ((pbi->m_BUF[i].free_start_adr
+ + 0xffff) >> 16) << 16;
+ /*64k alignment*/
+ if ((y_adr+buf_size) <= (pbi->m_BUF[i].start_adr+
+ pbi->m_BUF[i].size)) {
+ pbi->m_BUF[i].free_start_adr =
+ y_adr + buf_size;
+ break;
+ }
+ }
+ if (i < pbi->buf_num)
+#else
+ if ((pbi->mc_buf->buf_start + (i + 1) * buf_size) <
+ pbi->mc_buf->buf_end)
+ y_adr = pbi->mc_buf->buf_start + i * buf_size;
+ else {
+ if (!decoder_bmmu_box_alloc_idx_wait(
+ pbi->bmmu_box,
+ i,
+ buf_size,
+ -1,
+ -1,
+ BMMU_ALLOC_FLAGS_WAITCLEAR
+ )) {
+ pic_config->cma_alloc_addr =
+ decoder_bmmu_box_get_phy_addr(
+ pbi->bmmu_box,
+ i);
+ } else {
+ pr_err("alloc cma buffer failed %d\n", i);
+ }
+ if (pic_config->cma_alloc_addr)
+ y_adr = pic_config->cma_alloc_addr;
+ else
+ return -1;
+ }
+#endif
+ {
+ /*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;
+#ifndef VP9_10B_MMU
+ pic_config->mc_y_adr = y_adr;
+#endif
+ pic_config->mc_canvas_y = pic_config->index;
+ pic_config->mc_canvas_u_v = pic_config->index;
+#ifndef VP9_10B_MMU
+ if (double_write_mode & 0x10) {
+ pic_config->mc_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;
+
+ pic_config->dw_y_adr = y_adr;
+ pic_config->dw_u_v_adr = pic_config->mc_u_v_adr;
+ } else
+#endif
+ if (double_write_mode) {
+ pic_config->dw_y_adr = y_adr
+#ifndef VP9_10B_MMU
+ + (mc_buffer_size_h << 16)
+#endif
+ ;
+ pic_config->dw_u_v_adr = pic_config->dw_y_adr +
+ ((mc_buffer_size_u_v_h << 16) << 1);
+ }
+
+ pic_config->mpred_mv_wr_start_addr =
+ pbi->work_space_buf->mpred_mv.buf_start +
+ ((pic_config->index * lcu_total)
+ * MV_MEM_UNIT);
+
+ if (debug) {
+ pr_info
+ ("%s index %d BUF_index %d mc_y_adr %lx ",
+ __func__, pic_config->index,
+ pic_config->BUF_index,
+ pic_config->mc_y_adr);
+ 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;
+ }
+ }
+ return ret;
+}
+
+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;
+ struct vframe_s vf;
+ unsigned long disp_addr = 0;
+
+ if (!get_video0_frame_info(&vf)) {
+ if (vf.type & VIDTYPE_SCATTER) {
+ /*sc only used header.*/
+ disp_addr = vf.compHeadAddr;
+ } else if (vf.type & VIDTYPE_COMPRESS) {
+ /*sc checked body.*/
+ disp_addr = vf.compBodyAddr;
+ } else {
+ struct canvas_s cur_canvas;
+ canvas_read(vf.canvas0Addr & 0xff, &cur_canvas);
+ disp_addr = cur_canvas.addr;
+ }
+ }
+
+ for (i = 0; i < FRAME_BUFFERS; i++) {
+ pic_config = &cm->buffer_pool->frame_bufs[i].buf;
+ pic_config->index = i;
+ pic_config->BUF_index = -1;
+ if (config_pic(pbi, pic_config, disp_addr) < 0) {
+ if (debug)
+ pr_info("Config_pic %d fail\n",
+ pic_config->index);
+ pic_config->index = -1;
+ break;
+ }
+ pic_config->y_crop_width = pbi->init_pic_w;
+ pic_config->y_crop_height = pbi->init_pic_h;
+ /*set_canvas(pic_config);*/
+ }
+ for (; i < FRAME_BUFFERS; i++) {
+ pic_config = &cm->buffer_pool->frame_bufs[i].buf;
+ pic_config->index = -1;
+ pic_config->BUF_index = -1;
+ }
+
+}
+
+
+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 < FRAME_BUFFERS; i++) {
+ pic_config = &cm->buffer_pool->frame_bufs[i].buf;
+ if (pic_config->index < 0)
+ break;
+
+#ifdef VP9_10B_MMU
+ /*WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
+ pic_config->header_adr
+ | (pic_config->mc_canvas_y << 8)|0x1);*/
+ 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->mc_y_adr >> 5);
+#endif
+#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->mc_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)
+{
+ 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;
+ 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);
+
+#ifdef VP9_10B_MMU
+ /*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));
+#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
+ 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)
+ 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;
+
+ 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;
+
+ 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;
+
+ 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);
+#ifdef VP9_10B_MMU
+ WRITE_VREG(VP9D_MPP_REFINFO_DATA, 0);
+#else
+ WRITE_VREG(VP9D_MPP_REFINFO_DATA, ref_pic_body_size >> 5);
+#endif
+ }
+ 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;
+ int MV_MEM_UNIT = 0x240;
+
+
+ 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;
+
+ 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*/
+
+#ifndef VP9_10B_MMU
+ if ((double_write_mode & 0x10) == 0)
+ WRITE_VREG(HEVC_CM_BODY_START_ADDR, pic_config->mc_y_adr);
+#endif
+ if (double_write_mode) {
+ 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);
+ }
+#ifdef VP9_10B_MMU
+ WRITE_VREG(HEVC_CM_HEADER_START_ADDR, pic_config->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, 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 |= (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 (double_write_mode == 0)
+ data32 |= 0x2; /*disable double write*/
+#ifndef VP9_10B_MMU
+ else
+ if (double_write_mode & 0x10)
+ data32 |= 0x1; /*disable cm*/
+#endif
+ WRITE_VREG(HEVC_SAO_CTRL1, data32);
+
+ if (double_write_mode & 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 (double_write_mode != 1)
+ 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 |= 0xf; /* valid only when double write only */
+ /*data32 |= 0x8;*/ /* Big-Endian per 64-bit */
+ WRITE_VREG(HEVCD_IPP_AXIIF_CONFIG, data32);
+#endif
+}
+
+static void vp9_config_work_space_hw(struct VP9Decoder_s *pbi)
+{
+ struct BuffInfo_s *buf_spec = pbi->work_space_buf;
+#ifdef LOSLESS_COMPRESS_MODE
+ int losless_comp_header_size =
+ compute_losless_comp_header_size(pbi->init_pic_w,
+ pbi->init_pic_h);
+ int losless_comp_body_size =
+ compute_losless_comp_body_size(pbi->init_pic_w,
+ pbi->init_pic_h, buf_alloc_depth == 10);
+#endif
+#ifdef VP9_10B_MMU
+ unsigned int data32;
+#endif
+ if (debug)
+ pr_info("%s %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);
+ WRITE_VREG(HEVCD_IPP_LINEBUFF_BASE, buf_spec->ipp.buf_start);
+ 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_SAO_UP, buf_spec->sao_up.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(HEVC_SCALELUT, buf_spec->scalelut.buf_start);
+
+ /* 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);
+
+#ifdef LOSLESS_COMPRESS_MODE
+#ifdef VP9_10B_MMU
+ /*bit[4] : paged_mem_mode*/
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, (0x1 << 4));
+ 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));
+#endif
+ /*WRITE_VREG(P_HEVCD_MPP_DECOMP_CTL2,(losless_comp_body_size >> 5));*/
+ /*WRITE_VREG(P_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 VP9_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
+ + buf_spec->mmu_vbh.buf_size/2);
+ /*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);
+
+#endif
+
+ WRITE_VREG(VP9_SEG_MAP_BUFFER, buf_spec->seg_map.buf_start);
+
+ if (debug & VP9_DEBUG_UCODE)
+ 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);
+#ifdef VP9_10B_MMU
+ WRITE_VREG(VP9_MMU_MAP_BUFFER, pbi->frame_mmu_map_phy_addr);
+#endif
+
+}
+
+
+#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);
+ }
+}
+
+int default_filt_lvl;
+struct loop_filter_info_n *lfi;
+struct loopfilter *lf;
+struct segmentation *seg_4lf;
+
+/*instantiate this function once when decode is started*/
+void vp9_loop_filter_init(void)
+{
+ int i;
+ if (!lfi)
+ lfi = kmalloc(sizeof(struct loop_filter_info_n), GFP_KERNEL);
+ if (!lf)
+ lf = kmalloc(sizeof(struct loopfilter), GFP_KERNEL);
+ if (!seg_4lf)
+ seg_4lf = kmalloc(sizeof(struct segmentation), GFP_KERNEL);
+ if (lfi == NULL || lf == NULL || seg_4lf == NULL) {
+ pr_err("[test.c] vp9_loop_filter init malloc error!!!\n");
+ return;
+ }
+ 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*/
+ WRITE_VREG(HEVC_DBLK_CFGB, 0x40400001);
+}
+ /* 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)
+{
+ unsigned int data32;
+ int i;
+
+ if (debug & VP9_DEBUG_BUFMGR)
+ pr_info("[test.c] Enable HEVC Parser Interrupt\n");
+ 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);
+
+ if (debug & VP9_DEBUG_BUFMGR)
+ pr_info("[test.c] Enable HEVC Parser Shift\n");
+
+ 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);
+
+ /*Initial IQIT_SCALELUT memory -- just to avoid X in simulation*/
+ if (debug & VP9_DEBUG_BUFMGR)
+ pr_info("Initial IQIT_SCALELUT memory\n");
+ 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
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (pbi->platform_dev && vdec_frame_based(hw_to_vdec(pbi)))
+ WRITE_VREG(DECODE_MODE, DECODE_MODE_MULTI_FRAMEBASE);
+ else
+ WRITE_VREG(DECODE_MODE, DECODE_MODE_MULTI_STREAMBASE);
+ 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*/
+ if (debug)
+ pr_info("[test.c] SEND Parser Command ...\n");
+ 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*/
+ );
+ /*Changed to Start MPRED in microcode*/
+ /*
+ pr_info("[test.c] Start MPRED\n");
+ WRITE_VREG(HEVC_MPRED_INT_STATUS,
+ (1<<31)
+ );
+ */
+ if (debug)
+ pr_info("[test.c] Reset IPP\n");
+ 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 VP9_10B_NV21
+ /*Enable NV21 reference read mode for MC*/
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x1 << 31);
+#endif
+
+ /*Initialize mcrcc and decomp perf counters
+ 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 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 0
+ pr_info("before call mcrcc_get_hitrate\r\n");
+ mcrcc_get_hitrate();
+ decomp_get_hitrate();
+ decomp_get_comprate();
+#endif
+
+ 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;
+}
+#endif
+
+
+static struct VP9Decoder_s gHevc;
+
+static void vp9_local_uninit(struct VP9Decoder_s *pbi)
+{
+ pbi->rpm_ptr = NULL;
+ pbi->lmem_ptr = NULL;
+ if (pbi->rpm_addr) {
+ dma_unmap_single(amports_get_dma_device(),
+ pbi->rpm_phy_addr, RPM_BUF_SIZE,
+ DMA_FROM_DEVICE);
+ kfree(pbi->rpm_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;
+ }
+#ifdef VP9_10B_MMU
+ if (pbi->frame_mmu_map_addr) {
+ if (pbi->frame_mmu_map_phy_addr)
+ dma_free_coherent(amports_get_dma_device(),
+ FRAME_MMU_MAP_SIZE, pbi->frame_mmu_map_addr,
+ pbi->frame_mmu_map_phy_addr);
+
+ pbi->frame_mmu_map_addr = NULL;
+ }
+#endif
+
+#ifdef VP9_LPF_LVL_UPDATE
+ kfree(lfi);
+ lfi = NULL;
+ kfree(lf);
+ lf = NULL;
+ kfree(seg_4lf);
+ seg_4lf = NULL;
+#endif
+}
+
+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;
+#ifdef SUPPORT_4K2K
+ memcpy(cur_buf_info, &amvvp9_workbuff_spec[1], /* 4k2k work space */
+ sizeof(struct BuffInfo_s));
+#else
+ memcpy(cur_buf_info, &amvvp9_workbuff_spec[0], /* 1080p work space */
+ sizeof(struct BuffInfo_s));
+#endif
+ cur_buf_info->start_adr = pbi->buf_start;
+ pbi->mc_buf_spec.buf_end = pbi->buf_start + pbi->buf_size;
+#else
+/*! MULTI_INSTANCE_SUPPORT*/
+#ifdef SUPPORT_4K2K
+ cur_buf_info = &amvvp9_workbuff_spec[1]; /* 4k2k work space */
+#else
+ cur_buf_info = &amvvp9_workbuff_spec[0]; /* 1080p work space */
+#endif
+#endif
+
+ init_buff_spec(pbi, cur_buf_info);
+ pbi->mc_buf_spec.buf_start = (cur_buf_info->end_adr + 0xffff)
+ & (~0xffff);
+ pbi->mc_buf_spec.buf_size = (pbi->mc_buf_spec.buf_end
+ - pbi->mc_buf_spec.buf_start);
+ if (debug) {
+ pr_err("pbi->mc_buf_spec.buf_start %x-%x\n",
+ pbi->mc_buf_spec.buf_start,
+ pbi->mc_buf_spec.buf_start +
+ pbi->mc_buf_spec.buf_size);
+ }
+ vp9_bufmgr_init(pbi, cur_buf_info, &pbi->mc_buf_spec);
+
+ pbi->init_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 = buf_alloc_height ? buf_alloc_height :
+ (pbi->vvp9_amstream_dec_info.height ?
+ pbi->vvp9_amstream_dec_info.height :
+ pbi->work_space_buf->max_height);
+#ifndef VP9_10B_MMU
+ init_buf_list(pbi);
+#endif
+ init_pic_list(pbi);
+
+ pts_unstable = ((unsigned long)(pbi->vvp9_amstream_dec_info.param)
+ & 0x40) >> 6;
+
+ pbi->video_signal_type = 0;
+ video_signal_type = pbi->video_signal_type;
+
+ if ((debug & VP9_DEBUG_SEND_PARAM_WITH_REG) == 0) {
+ pbi->rpm_addr = kmalloc(RPM_BUF_SIZE, GFP_KERNEL);
+ if (pbi->rpm_addr == NULL) {
+ pr_err("%s: failed to alloc rpm buffer\n", __func__);
+ return -1;
+ }
+
+ pbi->rpm_phy_addr = dma_map_single(amports_get_dma_device(),
+ pbi->rpm_addr, RPM_BUF_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(amports_get_dma_device(),
+ pbi->rpm_phy_addr)) {
+ pr_err("%s: failed to map rpm buffer\n", __func__);
+ kfree(pbi->rpm_addr);
+ pbi->rpm_addr = NULL;
+ return -1;
+ }
+
+ pbi->rpm_ptr = pbi->rpm_addr;
+ }
+
+ if (debug & VP9_DEBUG_UCODE) {
+ 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_phy_addr = dma_map_single(amports_get_dma_device(),
+ pbi->lmem_addr, LMEM_BUF_SIZE, DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(amports_get_dma_device(),
+ pbi->lmem_phy_addr)) {
+ pr_err("%s: failed to map lmem buffer\n", __func__);
+ kfree(pbi->lmem_addr);
+ pbi->lmem_addr = NULL;
+ 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->prob_buffer_phy_addr = dma_map_single(amports_get_dma_device(),
+ pbi->prob_buffer_addr, PROB_BUF_SIZE, DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(amports_get_dma_device(),
+ pbi->prob_buffer_phy_addr)) {
+ pr_err("%s: failed to map prob_buffer\n", __func__);
+ kfree(pbi->prob_buffer_addr);
+ pbi->prob_buffer_addr = NULL;
+ return -1;
+ }
+*/
+ 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);
+/* pbi->count_buffer_phy_addr = dma_map_single(amports_get_dma_device(),
+ pbi->count_buffer_addr, COUNT_BUF_SIZE, DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(amports_get_dma_device(),
+ pbi->count_buffer_phy_addr)) {
+ pr_err("%s: failed to map count_buffer\n", __func__);
+ kfree(pbi->count_buffer_addr);
+ pbi->count_buffer_addr = NULL;
+ return -1;
+ }
+*/
+#ifdef VP9_10B_MMU
+ pbi->frame_mmu_map_addr = dma_alloc_coherent(amports_get_dma_device(),
+ FRAME_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);
+/* pbi->frame_mmu_map_phy_addr = dma_map_single(amports_get_dma_device(),
+ pbi->frame_mmu_map_addr, FRAME_MMU_MAP_SIZE, DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(amports_get_dma_device(),
+ pbi->frame_mmu_map_phy_addr)) {
+ pr_err("%s: failed to map count_buffer\n", __func__);
+ kfree(pbi->frame_mmu_map_addr);
+ pbi->frame_mmu_map_addr = NULL;
+ return -1;
+ }*/
+#endif
+
+ ret = 0;
+ return ret;
+}
+
+/********************************************
+ * Mailbox command
+ ********************************************/
+#define CMD_FINISHED 0
+#define CMD_ALLOC_VIEW 1
+#define CMD_FRAME_DISPLAY 3
+#define CMD_DEBUG 10
+
+
+#define DECODE_BUFFER_NUM_MAX 32
+#define DISPLAY_BUFFER_NUM 6
+
+#define video_domain_addr(adr) (adr&0x7fffffff)
+#define DECODER_WORK_SPACE_SIZE 0x800000
+
+#define spec2canvas(x) \
+ (((x)->uv_canvas_index << 16) | \
+ ((x)->uv_canvas_index << 8) | \
+ ((x)->y_canvas_index << 0))
+
+
+static void set_canvas(struct PIC_BUFFER_CONFIG_s *pic_config)
+{
+ 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 (double_write_mode) {
+ canvas_w = pic_config->y_crop_width;
+ canvas_h = pic_config->y_crop_height;
+ if (double_write_mode == 2) {
+ canvas_w >>= 2;
+ canvas_h >>= 2;
+ }
+
+ if (mem_map_mode == 0)
+ canvas_w = ALIGN(canvas_w, 32);
+ else
+ canvas_w = ALIGN(canvas_w, 64);
+ canvas_h = ALIGN(canvas_h, 32);
+
+ 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, 0x7);
+ canvas_config_ex(pic_config->uv_canvas_index,
+ pic_config->dw_u_v_adr, canvas_w, canvas_h,
+ CANVAS_ADDR_NOWRAP, blkmode, 0x7);
+#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 = 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 = 7;
+#endif
+ } else {
+ #ifndef VP9_10B_MMU
+ pic_config->y_canvas_index = 128 + pic_config->index;
+ pic_config->uv_canvas_index = 128 + pic_config->index;
+
+ canvas_config_ex(pic_config->y_canvas_index,
+ pic_config->mc_y_adr, canvas_w, canvas_h,
+ CANVAS_ADDR_NOWRAP, blkmode, 0x7);
+ canvas_config_ex(pic_config->uv_canvas_index,
+ pic_config->mc_u_v_adr, canvas_w, canvas_h,
+ CANVAS_ADDR_NOWRAP, blkmode, 0x7);
+ #endif
+ }
+
+}
+
+
+static void set_frame_info(struct VP9Decoder_s *pbi, struct vframe_s *vf)
+{
+ unsigned int ar;
+
+ vf->duration = pbi->frame_dur;
+ vf->duration_pulldown = 0;
+ vf->flag = 0;
+
+ ar = min_t(u32, pbi->frame_ar, DISP_RATIO_ASPECT_RATIO_MAX);
+ vf->ratio_control = (ar << DISP_RATIO_ASPECT_RATIO_BIT);
+
+ return;
+}
+
+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;
+ struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)op_arg;
+ if (step == 2)
+ return NULL;
+
+ if (kfifo_peek(&pbi->display_q, &vf))
+ return vf;
+
+ 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)) {
+ uint8_t index = vf->index & 0xff;
+ if (index >= 0 && index < FRAME_BUFFERS)
+ 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 = vf->index & 0xff;
+
+ kfifo_put(&pbi->newframe_q, (const struct vframe_s *)vf);
+
+ if (index >= 0
+ && index < FRAME_BUFFERS) {
+ struct VP9_Common_s *cm = &pbi->common;
+ struct BufferPool_s *pool = cm->buffer_pool;
+ lock_buffer_pool(pool);
+ if (pool->frame_bufs[index].buf.vf_ref > 0)
+ pool->frame_bufs[index].buf.vf_ref--;
+
+ if (pbi->wait_buf)
+ WRITE_VREG(HEVC_ASSIST_MBOX1_IRQ_REG,
+ 0x1);
+ pbi->last_put_idx = index;
+ pbi->new_frame_displayed++;
+ unlock_buffer_pool(pool);
+ }
+
+}
+
+static int vvp9_event_cb(int type, void *data, void *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
+ }
+
+ 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)
+ pr_info("%s index = %d new vf_ref = %d\r\n",
+ __func__, index,
+ cm->buffer_pool->frame_bufs[index].buf.vf_ref);
+}
+
+
+static int prepare_display_buf(struct VP9Decoder_s *pbi,
+ struct PIC_BUFFER_CONFIG_s *pic_config)
+{
+ struct vframe_s *vf = NULL;
+ int stream_offset = pic_config->stream_offset;
+ unsigned short slice_type = pic_config->slice_type;
+
+ 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;
+ }
+
+ if (double_write_mode) {
+ set_canvas(pic_config);
+ }
+ if (vf) {
+ /* 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, 0,
+ &vf->pts_us64) != 0) {
+#ifdef DEBUG_PTS
+ pbi->pts_missed++;
+#endif
+ vf->pts = 0;
+ vf->pts_us64 = 0;
+ }
+#ifdef DEBUG_PTS
+ else
+ pbi->pts_hit++;
+#endif
+ if (pts_unstable)
+ pbi->pts_mode = PTS_NONE_REF_USE_DURATION;
+
+ 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: vf->pts=%d, vf->pts_us64 = %lld\n",
+ vf->pts, vf->pts_us64);
+ }
+
+ vf->index = 0xff00 | pic_config->index;
+#if 1
+/*SUPPORT_10BIT*/
+ if (double_write_mode & 0x10) {
+ /* double write only */
+ vf->compBodyAddr = 0;
+ vf->compHeadAddr = 0;
+ } else {
+#ifdef VP9_10B_MMU
+ vf->compBodyAddr = 0;
+ vf->compHeadAddr = pic_config->header_adr;
+#else
+ vf->compBodyAddr = pic_config->mc_y_adr; /*body adr*/
+ vf->compHeadAddr = pic_config->mc_y_adr +
+ pic_config->comp_body_size;
+ /*head adr*/
+#endif
+ }
+ if (double_write_mode) {
+ vf->type = VIDTYPE_PROGRESSIVE |
+ VIDTYPE_VIU_FIELD;
+ vf->type |= VIDTYPE_VIU_NV21;
+#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;
+#ifdef VP9_10B_MMU
+ vf->type |= VIDTYPE_SCATTER;
+#endif
+ 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 (pic_config->bit_depth == VPX_BITS_8)
+ vf->bitdepth |= BITDEPTH_SAVING_MODE;
+ }
+#else
+ vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD;
+ vf->type |= VIDTYPE_VIU_NV21;
+ vf->canvas0Addr = vf->canvas1Addr = spec2canvas(pic_config);
+#endif
+ set_frame_info(pbi, vf);
+ /* 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); */
+ if (double_write_mode == 2) {
+ vf->width = pic_config->y_crop_width/4;
+ vf->height = pic_config->y_crop_height/4;
+ } else {
+ vf->width = pic_config->y_crop_width;
+ vf->height = pic_config->y_crop_height;
+ }
+ if (force_w_h != 0) {
+ vf->width = (force_w_h >> 16) & 0xffff;
+ vf->height = force_w_h & 0xffff;
+ }
+ vf->compWidth = pic_config->y_crop_width;
+ vf->compHeight = pic_config->y_crop_height;
+ if (force_fps & 0x100) {
+ u32 rate = force_fps & 0xff;
+ if (rate)
+ vf->duration = 96000/rate;
+ else
+ vf->duration = 0;
+ }
+ if (vf->type & VIDTYPE_SCATTER) {
+ vf->mem_handle = decoder_mmu_box_get_mem_handle(
+ pbi->mmu_box,
+ pic_config->index);
+ } else {
+ vf->mem_handle = decoder_bmmu_box_get_mem_handle(
+ pbi->bmmu_box,
+ pic_config->index);
+ }
+ inc_vf_ref(pbi, pic_config->index);
+ kfifo_put(&pbi->display_q, (const struct vframe_s *)vf);
+ vf_notify_receiver(pbi->provider_name,
+ VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
+ }
+
+ 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 ", vp9_param.l.data[i]);
+ if (((i + 1) & 0xf) == 0)
+ pr_info("\n");
+ }
+ pr_info("=============param==========\r\n");
+ pr_info("profile %x\r\n", vp9_param.p.profile);
+ pr_info("show_existing_frame %x\r\n",
+ vp9_param.p.show_existing_frame);
+ pr_info("frame_to_show_idx %x\r\n",
+ vp9_param.p.frame_to_show_idx);
+ pr_info("frame_type %x\r\n", vp9_param.p.frame_type);
+ pr_info("show_frame %x\r\n", vp9_param.p.show_frame);
+ pr_info("e.r.r.o.r_resilient_mode %x\r\n",
+ vp9_param.p.error_resilient_mode);
+ pr_info("intra_only %x\r\n", vp9_param.p.intra_only);
+ pr_info("display_size_present %x\r\n",
+ vp9_param.p.display_size_present);
+ pr_info("reset_frame_context %x\r\n",
+ vp9_param.p.reset_frame_context);
+ pr_info("refresh_frame_flags %x\r\n",
+ vp9_param.p.refresh_frame_flags);
+ pr_info("bit_depth %x\r\n", vp9_param.p.bit_depth);
+ pr_info("width %x\r\n", vp9_param.p.width);
+ pr_info("height %x\r\n", vp9_param.p.height);
+ pr_info("display_width %x\r\n", vp9_param.p.display_width);
+ pr_info("display_height %x\r\n", vp9_param.p.display_height);
+ pr_info("ref_info %x\r\n", vp9_param.p.ref_info);
+ pr_info("same_frame_size %x\r\n", vp9_param.p.same_frame_size);
+ if (!(debug & VP9_DEBUG_DBG_LF_PRINT))
+ return;
+ pr_info("mode_ref_delta_enabled: 0x%x\r\n",
+ vp9_param.p.mode_ref_delta_enabled);
+ pr_info("sharpness_level: 0x%x\r\n",
+ vp9_param.p.sharpness_level);
+ pr_info("ref_deltas: 0x%x, 0x%x, 0x%x, 0x%x\r\n",
+ vp9_param.p.ref_deltas[0], vp9_param.p.ref_deltas[1],
+ vp9_param.p.ref_deltas[2], vp9_param.p.ref_deltas[3]);
+ pr_info("mode_deltas: 0x%x, 0x%x\r\n", vp9_param.p.mode_deltas[0],
+ vp9_param.p.mode_deltas[1]);
+ pr_info("filter_level: 0x%x\r\n", vp9_param.p.filter_level);
+ pr_info("seg_enabled: 0x%x\r\n", vp9_param.p.seg_enabled);
+ pr_info("seg_abs_delta: 0x%x\r\n", 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",
+ (vp9_param.p.seg_lf_info[0]>>15 & 1),
+ (vp9_param.p.seg_lf_info[1]>>15 & 1),
+ (vp9_param.p.seg_lf_info[2]>>15 & 1),
+ (vp9_param.p.seg_lf_info[3]>>15 & 1),
+ (vp9_param.p.seg_lf_info[4]>>15 & 1),
+ (vp9_param.p.seg_lf_info[5]>>15 & 1),
+ (vp9_param.p.seg_lf_info[6]>>15 & 1),
+ (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",
+ (vp9_param.p.seg_lf_info[0] & 0x13f),
+ (vp9_param.p.seg_lf_info[1] & 0x13f),
+ (vp9_param.p.seg_lf_info[2] & 0x13f),
+ (vp9_param.p.seg_lf_info[3] & 0x13f),
+ (vp9_param.p.seg_lf_info[4] & 0x13f),
+ (vp9_param.p.seg_lf_info[5] & 0x13f),
+ (vp9_param.p.seg_lf_info[6] & 0x13f),
+ (vp9_param.p.seg_lf_info[7] & 0x13f));
+
+}
+
+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;
+ struct VP9_Common_s *const cm = &pbi->common;
+ int i, ret;
+
+ /*if (pbi->wait_buf)
+ pr_info("set wait_buf to 0\r\n");
+ */
+ pbi->wait_buf = 0;
+
+ if (dec_status == VP9_EOS) {
+ 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;
+ return IRQ_HANDLED;
+ }
+
+ if (dec_status != VP9_HEAD_PARSER_DONE) {
+ pbi->process_busy = 0;
+ return IRQ_HANDLED;
+ }
+ if (pbi->frame_count > 0)
+ vp9_bufmgr_postproc(pbi);
+
+ if (debug & VP9_DEBUG_SEND_PARAM_WITH_REG) {
+ get_rpm_param(&vp9_param);
+ } else {
+ dma_sync_single_for_cpu(
+ amports_get_dma_device(),
+ pbi->rpm_phy_addr,
+ RPM_BUF_SIZE,
+ DMA_FROM_DEVICE);
+
+ for (i = 0; i < (RPM_END - RPM_BEGIN); i += 4) {
+ int ii;
+ for (ii = 0; ii < 4; ii++)
+ vp9_param.l.data[i + ii] =
+ pbi->rpm_ptr[i + 3 - ii];
+ }
+ }
+ debug_buffer_mgr_more(pbi);
+
+ bit_depth_luma = vp9_param.p.bit_depth;
+ bit_depth_chroma = vp9_param.p.bit_depth;
+
+ ret = vp9_bufmgr_process(pbi, &vp9_param);
+ pbi->slice_idx++;
+ 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);
+ pbi->process_busy = 0;
+ return IRQ_HANDLED;
+ } else if (ret == 0) {
+ pbi->frame_count++;
+ /*pr_info("Decode Frame Data %d\n", pbi->frame_count);*/
+ config_pic_size(pbi, vp9_param.p.bit_depth);
+ if ((pbi->common.frame_type != KEY_FRAME)
+ && (!pbi->common.intra_only)) {
+ config_mc_buffer(pbi, vp9_param.p.bit_depth);
+ config_mpred_hw(pbi);
+ } else {
+ clear_mpred_hw(pbi);
+ }
+#ifdef MCRCC_ENABLE
+ config_mcrcc_axi_hw(pbi);
+#endif
+ config_sao_hw(pbi, &vp9_param);
+
+#ifdef VP9_LPF_LVL_UPDATE
+ /*
+ * Get loop filter related picture level parameters from Parser
+ */
+ lf->mode_ref_delta_enabled = vp9_param.p.mode_ref_delta_enabled;
+ lf->sharpness_level = vp9_param.p.sharpness_level;
+ for (i = 0; i < 4; i++)
+ lf->ref_deltas[i] = vp9_param.p.ref_deltas[i];
+ for (i = 0; i < 2; i++)
+ lf->mode_deltas[i] = vp9_param.p.mode_deltas[i];
+ default_filt_lvl = vp9_param.p.filter_level;
+ seg_4lf->enabled = vp9_param.p.seg_enabled;
+ seg_4lf->abs_delta = vp9_param.p.seg_abs_delta;
+ for (i = 0; i < MAX_SEGMENTS; i++)
+ seg_4lf->feature_mask[i] = (vp9_param.p.seg_lf_info[i] &
+ 0x8000) ? (1 << SEG_LVL_ALT_LF) : 0;
+
+ for (i = 0; i < MAX_SEGMENTS; i++)
+ seg_4lf->feature_data[i][SEG_LVL_ALT_LF]
+ = (vp9_param.p.seg_lf_info[i]
+ & 0x100) ? -(vp9_param.p.seg_lf_info[i]
+ & 0x3f) : (vp9_param.p.seg_lf_info[i] & 0x3f);
+ /*
+ * 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(seg_4lf, lfi, lf, 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_busy = 0;
+#ifdef VP9_10B_MMU
+ if (pbi->last_put_idx >= 0 && pbi->last_put_idx < FRAME_BUFFERS) {
+ 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.used_by_display == 0) &&
+ (frame_bufs[i].buf.index != -1)) {
+ decoder_mmu_box_free_idx(pbi->mmu_box, i);
+ }
+ pbi->last_put_idx = -1;
+ }
+#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;
+ dec_status = READ_VREG(HEVC_DEC_STATUS_REG);
+ adapt_prob_status = READ_VREG(VP9_ADAPT_PROB_REG);
+ if (pbi->init_flag == 0)
+ return IRQ_HANDLED;
+ if (pbi->process_busy)/*on process.*/
+ return IRQ_HANDLED;
+ pbi->dec_status = dec_status;
+ pbi->process_busy = 1;
+ if (debug & VP9_DEBUG_BUFMGR)
+ pr_info("vp9 isr dec status = %d\n", dec_status);
+
+ if (debug & VP9_DEBUG_UCODE) {
+ if (READ_HREG(DEBUG_REG1) & 0x10000) {
+ dma_sync_single_for_cpu(
+ amports_get_dma_device(),
+ pbi->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 ",
+ pbi->lmem_ptr[i + 3 - ii]);
+ }
+ if (((i + ii) & 0xf) == 0)
+ pr_info("\n");
+ }
+ WRITE_HREG(DEBUG_REG1, 0);
+ } else if (READ_HREG(DEBUG_REG1) != 0) {
+ pr_info("dbg%x: %x\n", READ_HREG(DEBUG_REG1),
+ READ_HREG(DEBUG_REG2));
+ WRITE_HREG(DEBUG_REG1, 0);
+ pbi->process_busy = 0;
+ return IRQ_HANDLED;
+ }
+
+ }
+
+ 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 (is_buffer_empty(cm)) {
+ /*
+ 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;
+ }
+ 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;
+
+ 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;
+
+ /*return IRQ_HANDLED;*/
+ }
+#ifdef MULTI_INSTANCE_SUPPORT
+#if 0
+ if ((dec_status == HEVC_DECPIC_DATA_DONE) && (pbi->m_ins_flag)) {
+ if (pbi->chunk) {
+ pbi->cur_pic->pts = pbi->chunk->pts;
+ pbi->cur_pic->pts64 = pbi->chunk->pts64;
+ } else if (pts_lookup_offset_us64
+ (PTS_TYPE_VIDEO,
+ pbi->cur_pic->stream_offset,
+ &pbi->cur_pic->pts,
+ 0,
+ &pbi->cur_pic->pts64) != 0) {
+#ifdef DEBUG_PTS
+ pbi->pts_missed++;
+#endif
+ pbi->cur_pic->pts = 0;
+ pbi->cur_pic->pts64 = 0;
+ }
+ }
+#endif
+ if (dec_status == HEVC_NAL_DECODE_DONE) {
+ if (pbi->m_ins_flag) {
+#if 0
+ if (!vdec_frame_based(hw_to_vdec(hevc))) {
+ pbi->dec_result = DEC_RESULT_AGAIN;
+ if ((debug &
+ ONLY_RESET_AT_START) == 0)
+ amhevc_stop();
+ } else
+ pbi->dec_result = DEC_RESULT_GET_DATA;
+#else
+ if (!vdec_frame_based(hw_to_vdec(pbi)))
+ pbi->dec_result = DEC_RESULT_AGAIN;
+ else
+ pbi->dec_result = DEC_RESULT_DONE;
+ amhevc_stop();
+#endif
+ schedule_work(&pbi->work);
+ }
+ pbi->process_busy = 0;
+ return IRQ_HANDLED;
+ } else if (dec_status == HEVC_DECPIC_DATA_DONE) {
+ if (pbi->m_ins_flag) {
+ pbi->dec_result = DEC_RESULT_DONE;
+ amhevc_stop();
+ schedule_work(&pbi->work);
+ }
+
+ pbi->process_busy = 0;
+ return IRQ_HANDLED;
+ } else if (
+ (dec_status == HEVC_SEARCH_BUFEMPTY) ||
+ (dec_status == HEVC_DECODE_BUFEMPTY) ||
+ (dec_status == HEVC_DECODE_TIMEOUT)) {
+ if (vdec_frame_based(hw_to_vdec(pbi)) ||
+ (READ_VREG(HEVC_STREAM_LEVEL) > 0x200)) {
+ if (debug & VP9_DEBUG_DIS_LOC_ERROR_PROC) {
+ vp9_print(pbi, PRINT_FLAG_ERROR,
+ "%s decoding error, level 0x%x\n",
+ __func__, READ_VREG(HEVC_STREAM_LEVEL));
+ goto send_again;
+ }
+ amhevc_stop();
+ vp9_print(pbi, PRINT_FLAG_UCODE_EVT,
+ "%s %s\n", __func__,
+ (dec_status == HEVC_SEARCH_BUFEMPTY) ?
+ "HEVC_SEARCH_BUFEMPTY" :
+ (dec_status == HEVC_DECODE_BUFEMPTY) ?
+ "HEVC_DECODE_BUFEMPTY" : "HEVC_DECODE_TIMEOUT");
+ pbi->dec_result = DEC_RESULT_DONE;
+
+ schedule_work(&pbi->work);
+ } else {
+ /* WRITE_VREG(DPB_STATUS_REG, H264_ACTION_INIT); */
+ vp9_print(pbi, PRINT_FLAG_VDEC_STATUS,
+ "%s DEC_RESULT_AGAIN\n", __func__);
+send_again:
+ pbi->dec_result = DEC_RESULT_AGAIN;
+ schedule_work(&pbi->work);
+ }
+ pbi->process_busy = 0;
+ return IRQ_HANDLED;
+ }
+#endif
+
+ return IRQ_WAKE_THREAD;
+}
+
+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->dec_result = DEC_RESULT_DONE;
+ schedule_work(&pbi->work);
+ pr_info(
+ "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_MBOX1_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");
+ }*/
+ }
+ }
+ }
+
+ if (decode_stop_pos != decode_stop_pos_pre) {
+ WRITE_VREG(DECODE_STOP_POS, decode_stop_pos);
+ decode_stop_pos_pre = decode_stop_pos;
+ }
+
+ 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_MBOX1_IRQ_REG, 0x1);
+ debug &= ~VP9_DEBUG_TRIG_SLICE_SEGMENT_PROC;
+ }
+ /*if (debug & VP9_DEBUG_HW_RESET) {
+ }*/
+ if (debug & VP9_DEBUG_ERROR_TRIG) {
+ WRITE_VREG(DECODE_STOP_POS, 1);
+ debug &= ~VP9_DEBUG_ERROR_TRIG;
+ }
+
+ 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_type() >= MESON_CPU_MAJOR_ID_GXBB &&
+ double_write_mode == 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)) {
+ 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;
+ }
+
+ timer->expires = jiffies + PUT_INTERVAL;
+ add_timer(timer);
+}
+
+
+int vvp9_dec_status(struct vdec_s *vdec, struct vdec_status *vstatus)
+{
+ struct VP9Decoder_s *pbi = &gHevc;
+ vstatus->width = frame_width;
+ vstatus->height = frame_height;
+ if (pbi->frame_dur != 0)
+ vstatus->fps = 96000 / pbi->frame_dur;
+ else
+ vstatus->fps = -1;
+ vstatus->error_count = 0;
+ vstatus->status = pbi->stat | pbi->fatal_error;
+ 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)
+{
+ unsigned int data32;
+ /* VP9_DECODE_INIT(); */
+ vp9_config_work_space_hw(pbi);
+ init_pic_list_hw(pbi);
+
+ vp9_init_decoder_hw(pbi);
+
+#ifdef VP9_LPF_LVL_UPDATE
+ vp9_loop_filter_init();
+#endif
+
+#if 1
+ if (debug & VP9_DEBUG_BUFMGR)
+ pr_info("[test.c] Enable BitStream Fetch\n");
+ 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("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_MBOX1_CLR_REG, 1);
+
+ /* enable mailbox interrupt */
+ WRITE_VREG(HEVC_ASSIST_MBOX1_MASK, 1);
+
+ /* disable PSCALE for hardware sharing */
+ WRITE_VREG(HEVC_PSCALE_CTRL, 0);
+
+ if (debug & VP9_DEBUG_UCODE)
+ WRITE_VREG(DEBUG_REG1, 0x1);
+ else
+ WRITE_VREG(DEBUG_REG1, 0x0);
+ /*check vps/sps/pps/i-slice in ucode*/
+ WRITE_VREG(NAL_SEARCH_CTL, 0x8);
+
+ WRITE_VREG(DECODE_STOP_POS, decode_stop_pos);
+
+}
+
+static int vvp9_local_init(struct VP9Decoder_s *pbi)
+{
+ int i;
+ int ret;
+ int width, height;
+#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;
+ width = pbi->vvp9_amstream_dec_info.width;
+ height = pbi->vvp9_amstream_dec_info.height;
+ pbi->frame_dur =
+ (pbi->vvp9_amstream_dec_info.rate ==
+ 0) ? 3600 : 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);
+
+ return ret;
+}
+
+static s32 vvp9_init(struct VP9Decoder_s *pbi)
+{
+ int size = -1;
+ char *buf = vmalloc(0x1000 * 16);
+ if (IS_ERR_OR_NULL(buf))
+ return -ENOMEM;
+
+ init_timer(&pbi->timer);
+
+ pbi->stat |= STAT_TIMER_INIT;
+ if (vvp9_local_init(pbi) < 0) {
+ vfree(buf);
+ return -EBUSY;
+ }
+
+#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;
+
+ INIT_WORK(&pbi->work, vp9_work);
+
+ vfree(buf);
+ return 0;
+ }
+#endif
+
+ amhevc_enable();
+
+ size = get_firmware_data(VIDEO_DEC_VP9_MMU, buf);
+ if (size < 0) {
+ pr_err("get firmware fail.\n");
+ vfree(buf);
+ return -1;
+ }
+
+ if (amhevc_loadmc_ex(VFORMAT_VP9, NULL, buf) < 0) {
+ amhevc_disable();
+ vfree(buf);
+ return -EBUSY;
+ }
+
+ vfree(buf);
+
+ pbi->stat |= STAT_MC_LOAD;
+
+ /* enable AMRISC side protocol */
+ vvp9_prot_init(pbi);
+
+ if (vdec_request_threaded_irq(VDEC_IRQ_1,
+ 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;
+ 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);
+
+ vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_FR_HINT,
+ (void *)((unsigned long)pbi->frame_dur));
+
+ pbi->stat |= STAT_VF_HOOK;
+
+ pbi->timer.data = (ulong)pbi;
+ pbi->timer.function = vvp9_put_timer_func;
+ pbi->timer.expires = jiffies + PUT_INTERVAL;
+
+
+ add_timer(&pbi->timer);
+
+ pbi->stat |= STAT_TIMER_ARM;
+
+ /* pbi->stat |= STAT_KTHREAD; */
+
+ amhevc_start();
+
+ pbi->stat |= STAT_VDEC_RUN;
+
+ 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 vvp9_stop(struct VP9Decoder_s *pbi)
+{
+
+ pbi->init_flag = 0;
+ /*
+ if ((debug & VP9_DEBUG_NOWAIT_DECODE_DONE_WHEN_STOP) == 0) {
+ int wait_timeout_count = 0;
+ while ((READ_VREG(HEVC_DEC_STATUS_REG) ==
+ VP9_10B_DECODE_SLICE &&
+ wait_timeout_count < 10) ||
+ pbi->process_busy){
+ wait_timeout_count++;
+ msleep(20);
+ }
+ }
+ */
+ if (pbi->stat & STAT_VDEC_RUN) {
+ amhevc_stop();
+ pbi->stat &= ~STAT_VDEC_RUN;
+ }
+
+ if (pbi->stat & STAT_ISR_REG) {
+ WRITE_VREG(HEVC_ASSIST_MBOX1_MASK, 0);
+ vdec_free_irq(VDEC_IRQ_1, (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) {
+ 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);
+
+#ifdef MULTI_INSTANCE_SUPPORT
+ if (pbi->m_ins_flag) {
+ cancel_work_sync(&pbi->work);
+ } else {
+ amhevc_disable();
+ }
+#else
+ amhevc_disable();
+#endif
+ uninit_mmu_buffers(pbi);
+
+ return 0;
+}
+
+static int amvdec_vp9_mmu_init(struct VP9Decoder_s *pbi)
+{
+#ifdef VP9_10B_MMU
+ pbi->mmu_box = decoder_mmu_box_alloc_box(DRIVER_NAME,
+ 0, FRAME_BUFFERS,
+ 48 * SZ_1M
+ );
+ if (!pbi->mmu_box) {
+ pr_err("vp9 alloc mmu box failed!!\n");
+ return -1;
+ }
+#endif
+ 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);
+ if (!pbi->bmmu_box) {
+ pr_err("vp9 alloc bmmu box failed!!\n");
+ return -1;
+ }
+ return 0;
+}
+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 = &gHevc;
+ pr_info("%s\n", __func__);
+ mutex_lock(&vvp9_mutex);
+
+ memcpy(&BUF[0], &pbi->m_BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM);
+ memset(pbi, 0, sizeof(VP9Decoder));
+ memcpy(&pbi->m_BUF[0], &BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM);
+
+ pbi->init_flag = 0;
+ pbi->fatal_error = 0;
+ pbi->show_frame_num = 0;
+ if (pdata == NULL) {
+ pr_info("\namvdec_vp9 memory resource undefined.\n");
+ mutex_unlock(&vvp9_mutex);
+ return -EFAULT;
+ }
+ pbi->m_ins_flag = 0;
+#ifdef MULTI_INSTANCE_SUPPORT
+ pbi->buf_start = pdata->mem_start;
+ pbi->buf_size = pdata->mem_end - pdata->mem_start + 1;
+#else
+ pbi->mc_buf_spec.buf_end = pdata->mem_end + 1;
+ for (i = 0; i < WORK_BUF_SPEC_NUM; i++)
+ amvvp9_workbuff_spec[i].start_adr = pdata->mem_start;
+#endif
+ if (amvdec_vp9_mmu_init(pbi) < 0) {
+ pr_err("vp9 alloc bmmu box failed!!\n");
+ return -1;
+ }
+ if (debug) {
+ pr_info("===VP9 decoder mem resource 0x%lx -- 0x%lx\n",
+ pdata->mem_start, pdata->mem_end + 1);
+ }
+
+ 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;
+ }
+#ifdef MULTI_INSTANCE_SUPPORT
+ pbi->cma_dev = pdata->cma_dev;
+#else
+ cma_dev = pdata->cma_dev;
+#endif
+ pdata->dec_status = vvp9_dec_status;
+
+ if (vvp9_init(pbi) < 0) {
+ pr_info("\namvdec_vp9 init failed.\n");
+ vp9_local_uninit(pbi);
+ 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 int amvdec_vp9_remove(struct platform_device *pdev)
+{
+ struct VP9Decoder_s *pbi = &gHevc;
+ if (debug)
+ pr_info("amvdec_vp9_remove\n");
+
+ mutex_lock(&vvp9_mutex);
+
+ vvp9_stop(pbi);
+
+
+ hevc_source_changed(VFORMAT_VP9, 0, 0, 0);
+
+
+#ifdef DEBUG_PTS
+ pr_info("pts missed %ld, pts hit %ld, duration %d\n",
+ pbi->pts_missed, pbi->pts_hit, pbi->frame_dur);
+#endif
+
+ mutex_unlock(&vvp9_mutex);
+
+ return 0;
+}
+
+/****************************************/
+
+static struct platform_driver amvdec_vp9_driver = {
+ .probe = amvdec_vp9_probe,
+ .remove = amvdec_vp9_remove,
+#ifdef CONFIG_PM
+ .suspend = amhevc_suspend,
+ .resume = amhevc_resume,
+#endif
+ .driver = {
+ .name = DRIVER_NAME,
+ }
+};
+
+static struct codec_profile_t amvdec_vp9_profile = {
+ .name = "vp9",
+ .profile = ""
+};
+
+#ifdef MULTI_INSTANCE_SUPPORT
+static unsigned int start_decode_buf_level = 0x8000;
+#ifdef VP9_10B_MMU
+static u32 work_buf_size = 24 * 1024 * 1024;
+#else
+static u32 work_buf_size = 32 * 1024 * 1024;
+#endif
+
+static unsigned char decoder_id_used[MAX_DECODE_INSTANCE_NUM];
+static unsigned int get_free_decoder_id(struct vdec_s *vdec)
+{
+ /*stream base decoder always has id of 0*/
+ int i;
+ if (vdec_frame_based(vdec)) {
+ for (i = 1; i < decoder_id_used[i]; i++) {
+ if (!decoder_id_used[i]) {
+ decoder_id_used[i] = 1;
+ return i;
+ }
+ }
+ }
+ return 0;
+}
+
+static unsigned char get_data_check_sum
+ (struct VP9Decoder_s *pbi, int size)
+{
+ int jj;
+ int sum = 0;
+ u8 *data = ((u8 *)pbi->chunk->block->start_virt) +
+ pbi->chunk->offset;
+ for (jj = 0; jj < size; jj++)
+ sum += data[jj];
+ return sum;
+}
+
+static void dump_data(struct VP9Decoder_s *pbi, int size)
+{
+ int jj;
+ u8 *data = ((u8 *)pbi->chunk->block->start_virt) +
+ pbi->chunk->offset;
+ 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");
+}
+
+static void vp9_work(struct work_struct *work)
+{
+ struct VP9Decoder_s *pbi = container_of(work,
+ struct VP9Decoder_s, work);
+ struct VP9_Common_s *const cm = &pbi->common;
+ struct vdec_s *vdec = hw_to_vdec(pbi);
+ /* finished decoding one frame or error,
+ * notify vdec core to switch context
+ */
+
+ if ((pbi->dec_result == DEC_RESULT_GET_DATA) ||
+ (pbi->dec_result == DEC_RESULT_GET_DATA_RETRY)) {
+ 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 (!is_buffer_empty(cm)) {
+ int r;
+ 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");
+
+ 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);
+ WRITE_VREG(HEVC_DECODE_SIZE, r);
+
+ vdec_enable_input(vdec);
+
+ WRITE_VREG(HEVC_DEC_STATUS_REG, HEVC_ACTION_DONE);
+ } else{
+ pbi->dec_result = DEC_RESULT_GET_DATA_RETRY;
+
+ vp9_print(pbi, PRINT_FLAG_VDEC_DETAIL,
+ "amvdec_vh265: Insufficient data\n");
+
+ schedule_work(&pbi->work);
+ }
+ return;
+ } else if (pbi->dec_result == DEC_RESULT_DONE) {
+ /* if (!pbi->ctx_valid)
+ pbi->ctx_valid = 1; */
+ vp9_print(pbi, PRINT_FLAG_VDEC_STATUS,
+ "%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));
+ vdec_vframe_dirty(hw_to_vdec(pbi), pbi->chunk);
+ } else {
+ 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));
+ }
+
+ /* mark itself has all HW resource released and input released */
+ vdec_set_status(hw_to_vdec(pbi), VDEC_STATUS_CONNECTED);
+
+ if (pbi->vdec_cb)
+ pbi->vdec_cb(hw_to_vdec(pbi), pbi->vdec_cb_arg);
+}
+
+static int vp9_hw_ctx_restore(struct VP9Decoder_s *pbi)
+{
+ /* new to do ... */
+ vvp9_prot_init(pbi);
+ return 0;
+}
+
+static bool run_ready(struct vdec_s *vdec)
+{
+ struct VP9Decoder_s *pbi =
+ (struct VP9Decoder_s *)vdec->private;
+ struct VP9_Common_s *const cm = &pbi->common;
+
+ vp9_print(pbi,
+ PRINT_FLAG_VDEC_DETAIL, "%s\r\n", __func__);
+
+ if ((!vdec_frame_based(vdec)) && (start_decode_buf_level > 0)) {
+ u32 rp, wp;
+ u32 level;
+
+ rp = READ_MPEG_REG(PARSER_VIDEO_RP);
+ wp = READ_MPEG_REG(PARSER_VIDEO_WP);
+
+ if (wp < rp)
+ level = vdec->input.size + wp - rp;
+ else
+ level = wp - rp;
+
+ if (level < start_decode_buf_level) {
+ vp9_print(pbi, 0,
+ "level %d not run_ready\n", level);
+ return false;
+ }
+ } else if (vdec_frame_based(vdec)) {
+ if (!vdec_input_next_input_chunk(&vdec->input))
+ return false;
+ }
+
+ return !is_buffer_empty(cm);
+}
+
+static void reset_dec_hw(struct vdec_s *vdec)
+{
+ if (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
+ */
+ 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);
+}
+
+static void run(struct vdec_s *vdec,
+ void (*callback)(struct vdec_s *, void *), void *arg)
+{
+ struct VP9Decoder_s *pbi =
+ (struct VP9Decoder_s *)vdec->private;
+ int r, size = -1;
+
+ char *buf = vmalloc(0x1000 * 16);
+ if (IS_ERR_OR_NULL(buf))
+ return;
+
+ pbi->vdec_cb_arg = arg;
+ pbi->vdec_cb = callback;
+ /* pbi->chunk = vdec_prepare_input(vdec); */
+ reset_dec_hw(vdec);
+
+ r = vdec_prepare_input(vdec, &pbi->chunk);
+ if (r < 0) {
+ pbi->dec_result = DEC_RESULT_AGAIN;
+
+ vp9_print(pbi, PRINT_FLAG_VDEC_DETAIL,
+ "ammvdec_vh265: Insufficient data\n");
+
+ schedule_work(&pbi->work);
+ return;
+ }
+ pbi->dec_result = DEC_RESULT_NONE;
+
+ vp9_print(pbi, PRINT_FLAG_VDEC_STATUS,
+ "%s: size 0x%x sum 0x%x (%x %x %x)\n",
+ __func__, r,
+ (vdec_frame_based(vdec) &&
+ (debug & PRINT_FLAG_VDEC_STATUS)) ?
+ get_data_check_sum(pbi, r) : 0,
+ READ_VREG(HEVC_STREAM_LEVEL),
+ READ_VREG(HEVC_STREAM_WR_PTR),
+ READ_VREG(HEVC_STREAM_RD_PTR));
+
+ size = get_firmware_data(VIDEO_DEC_VP9_MMU, buf);
+ if (size < 0) {
+ pr_err("get firmware fail.\n");
+ vfree(buf);
+ return;
+ }
+
+ if (amhevc_loadmc_ex(VFORMAT_VP9, NULL, buf) < 0) {
+ amhevc_disable();
+ vfree(buf);
+ return;
+ }
+
+ vfree(buf);
+
+ if (vp9_hw_ctx_restore(pbi) < 0) {
+ 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);
+ }
+ WRITE_VREG(HEVC_DECODE_SIZE, r);
+ WRITE_VREG(HEVC_DECODE_COUNT, pbi->slice_idx);
+ pbi->init_flag = 1;
+
+ vp9_print(pbi, PRINT_FLAG_VDEC_STATUS,
+ "%s: start hevc (%x %x %x)\n",
+ __func__,
+ READ_VREG(HEVC_DEC_STATUS_REG),
+ READ_VREG(HEVC_MPC_E),
+ READ_VREG(HEVC_MPSR));
+
+ amhevc_start();
+
+}
+
+static void reset(struct vdec_s *vdec)
+{
+
+ struct VP9Decoder_s *pbi =
+ (struct VP9Decoder_s *)vdec->private;
+
+ vp9_print(pbi,
+ PRINT_FLAG_VDEC_DETAIL, "%s\r\n", __func__);
+
+}
+
+static irqreturn_t vp9_irq_cb(struct vdec_s *vdec)
+{
+ 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)
+{
+ struct VP9Decoder_s *pbi =
+ (struct VP9Decoder_s *)vdec->private;
+ return vvp9_isr_thread_fn(0, pbi);
+}
+
+
+static int ammvdec_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 = NULL;
+ pr_info("%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);
+ if (pbi == NULL) {
+ pr_info("\nammvdec_vp9 device data allocation failed\n");
+ return -ENOMEM;
+ }
+ 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->id = pdev->id;
+
+
+ memcpy(&BUF[0], &pbi->m_BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM);
+ memset(pbi, 0, sizeof(VP9Decoder));
+ memcpy(&pbi->m_BUF[0], &BUF[0], sizeof(struct BUF_s) * MAX_BUF_NUM);
+
+ pbi->index = get_free_decoder_id(pdata);
+
+ 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;
+#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);
+ return -1;
+ }
+
+ pbi->cma_alloc_count = PAGE_ALIGN(work_buf_size) / PAGE_SIZE;
+ if (!decoder_bmmu_box_alloc_idx_wait(
+ pbi->bmmu_box,
+ WORK_SPACE_BUF_ID,
+ pbi->cma_alloc_count * PAGE_SIZE,
+ -1,
+ -1,
+ BMMU_ALLOC_FLAGS_WAITCLEAR
+ )) {
+ pbi->cma_alloc_addr = decoder_bmmu_box_get_phy_addr(
+ pbi->bmmu_box,
+ WORK_SPACE_BUF_ID);
+ } else {
+ vp9_print(pbi, 0,
+ "codec_mm alloc failed, request buf size 0x%lx\n",
+ pbi->cma_alloc_count * PAGE_SIZE);
+ pbi->cma_alloc_count = 0;
+ uninit_mmu_buffers(pbi);
+ devm_kfree(&pdev->dev, (void *)pbi);
+ return -ENOMEM;
+ }
+ pbi->buf_start = pbi->cma_alloc_addr;
+ pbi->buf_size = work_buf_size;
+#endif
+ pbi->m_ins_flag = 1;
+
+ pbi->init_flag = 0;
+ pbi->fatal_error = 0;
+ pbi->show_frame_num = 0;
+ if (pdata == NULL) {
+ pr_info("\namvdec_vp9 memory resource undefined.\n");
+ uninit_mmu_buffers(pbi);
+ devm_kfree(&pdev->dev, (void *)pbi);
+ return -EFAULT;
+ }
+
+ if (debug) {
+ pr_info("===VP9 decoder mem resource 0x%lx -- 0x%lx\n",
+ pbi->buf_start,
+ pbi->buf_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->cma_dev = pdata->cma_dev;
+
+ if (vvp9_init(pbi) < 0) {
+ pr_info("\namvdec_vp9 init failed.\n");
+ vp9_local_uninit(pbi);
+ uninit_mmu_buffers(pbi);
+ devm_kfree(&pdev->dev, (void *)pbi);
+ return -ENODEV;
+ }
+ 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);
+ if (debug)
+ pr_info("amvdec_vp9_remove\n");
+
+ vvp9_stop(pbi);
+
+ vdec_set_status(hw_to_vdec(pbi), VDEC_STATUS_DISCONNECTED);
+
+
+#ifdef DEBUG_PTS
+ pr_info("pts missed %ld, pts hit %ld, duration %d\n",
+ pbi->pts_missed, pbi->pts_hit, pbi->frame_dur);
+#endif
+ devm_kfree(&pdev->dev, (void *)pbi);
+ return 0;
+}
+
+static struct platform_driver ammvdec_vp9_driver = {
+ .probe = ammvdec_vp9_probe,
+ .remove = ammvdec_vp9_remove,
+#ifdef CONFIG_PM
+ .suspend = amvdec_suspend,
+ .resume = amvdec_resume,
+#endif
+ .driver = {
+ .name = MULTI_DRIVER_NAME,
+ }
+};
+#endif
+
+static int __init amvdec_vp9_driver_init_module(void)
+{
+ 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
+ decode_stop_pos = 0;
+ decode_stop_pos_pre = 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_type() >= MESON_CPU_MAJOR_ID_GXL) {
+ amvdec_vp9_profile.profile =
+ "4k, 10bit, dwrite, compressed";
+ } else {
+ amvdec_vp9_profile.name = "vp9_unsupport";
+ }
+
+ vcodec_profile_register(&amvdec_vp9_profile);
+
+ 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(stat, uint, 0664);
+MODULE_PARM_DESC(stat, "\n amvdec_vp9 stat\n");
+*/
+module_param(use_cma, uint, 0664);
+MODULE_PARM_DESC(use_cma, "\n amvdec_vp9 use_cma\n");
+
+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, "\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_vp9 step\n");
+
+module_param(decode_stop_pos, uint, 0664);
+MODULE_PARM_DESC(decode_stop_pos, "\n amvdec_vp9 decode_stop_pos\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(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(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 MULTI_INSTANCE_SUPPORT
+module_param(start_decode_buf_level, uint, 0664);
+MODULE_PARM_DESC(start_decode_buf_level,
+ "\n ammvdec_h264 start_decode_buf_level\n");
+#endif
+
+module_init(amvdec_vp9_driver_init_module);
+module_exit(amvdec_vp9_driver_remove_module);
+
+MODULE_DESCRIPTION("AMLOGIC vp9 Video Decoder Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tim Yao <tim.yao@amlogic.com>");
diff --git a/drivers/frame_provider/decoder/vp9/vvp9.h b/drivers/frame_provider/decoder/vp9/vvp9.h
new file mode 100644
index 0000000..4cf3254
--- a/dev/null
+++ b/drivers/frame_provider/decoder/vp9/vvp9.h
@@ -0,0 +1,25 @@
+/*
+ * 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
+#ifndef CONFIG_MULTI_DEC
+#define VP9_10B_MMU
+#endif
+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
--- a/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..9afecec
--- a/dev/null
+++ b/drivers/frame_sink/encoder/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_AMLOGIC_MEDIA_VENC_H264) += h264/
+obj-$(CONFIG_AMLOGIC_MEDIA_VENC_H265) += h265/
diff --git a/drivers/frame_sink/encoder/h264/Makefile b/drivers/frame_sink/encoder/h264/Makefile
new file mode 100644
index 0000000..c12d7c3
--- a/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..9badd53
--- a/dev/null
+++ b/drivers/frame_sink/encoder/h264/encoder.c
@@ -0,0 +1,4237 @@
+/*
+ * 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.
+ *
+*/
+
+#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/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/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 <linux/amlogic/media/utils/amlog.h>
+#include "../../../stream_input/amports/amports_priv.h"
+#include <linux/of_reserved_mem.h>
+#ifdef CONFIG_AM_JPEG_ENCODER
+#include "jpegenc.h"
+#endif
+
+#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 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 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 seperate 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_GX,
+ UCODE_GXTV,
+ UCODE_GXL,
+ UCODE_TXL,
+ UCODE_MAX
+};
+
+const char *ucode_name[] = {
+ "h264_enc_mc_gx",
+ "h264_enc_mc_gxtv",
+ "gx_h264_enc",
+ "h264_enc_mc_txl",
+};
+
+static void dma_flush(u32 buf_start, u32 buf_size);
+static void cache_flush(u32 buf_start , u32 buf_size);
+
+static const char *select_ucode(u32 ucode_index)
+{
+ enum ucode_type_e ucode = UCODE_GX;
+ switch (ucode_index) {
+ case UCODE_MODE_FULL:
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_TXL)
+ ucode = UCODE_TXL;
+ else if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXL)
+ ucode = UCODE_GXL;
+ else if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXTVBB)
+ ucode = UCODE_GXTV;
+ else /* if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXBB) */
+ ucode = UCODE_GX;
+ 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]);
+ return;
+}
+
+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.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));
+ 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_AM_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;
+ if (canvas) {
+ if ((request->fmt == FMT_NV21)
+ || (request->fmt == FMT_NV12)) {
+ src_canvas = src_addr & 0xffff;
+ input_format = GE2D_FORMAT_M24_NV21;
+ } 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 {
+ 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 = cs0.width;
+ ge2d_config->src_planes[0].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 = cd.width;
+ ge2d_config->dst_planes[0].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 = request->src_w;
+ ge2d_config->src_para.height = 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;
+ 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;
+ 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)) {
+ 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 {
+ src_addr = input;
+ picsize_y = wq->pic.encoder_height;
+ }
+ if (request->scale_enable) {
+#ifdef CONFIG_AM_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;
+ 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;
+ 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_AM_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;
+ }
+
+ 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_seperate_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));
+ 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)
+{
+ 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)
+{
+ 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;
+ }
+ 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_decoder_firmware_data(VFORMAT_H264_ENC, p,
+ (u8 *)mc_addr, MC_SIZE);
+ 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);
+
+ 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) & (~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);
+
+ /* Remove HCODEC ISO */
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ (READ_AOREG(AO_RTI_GEN_PWR_ISO0) & (~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);
+
+ /* 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 */
+ hvdec_clock_disable();
+
+ /* 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;
+}
+
+static s32 reload_mc(struct encode_wq_s *wq)
+{
+ const char *p = select_ucode(encode_manager.ucode_index);
+
+ amvenc_stop();
+
+ 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;
+ 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];
+ 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];
+ 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
+ } 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) {
+ 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)) {
+ 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, wq:%p.\n", (void *)wq);
+}
+
+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:%p.\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:%p. 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 sucess, 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 sucess, 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 50
+ 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: %p.\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;
+ }
+ wq->pic.encoder_width = addr_info[2];
+ wq->pic.encoder_height = addr_info[3];
+ 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) {
+ wq->pic.frame_number++;
+ wq->pic.pic_order_cnt_lsb += 2;
+ if (wq->pic.frame_number > 65535)
+ wq->pic.frame_number = 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;
+ 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;
+ 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;
+
+#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 =
+ phys_to_virt(wq->mem.cbr_info_ddr_start_addr);
+ ConvertTable2Risc(vaddr, 0xa00);
+ buf_start = getbuffer(wq, ENCODER_BUFFER_CBR);
+ dma_flush(buf_start, wq->mem.cbr_info_ddr_size);
+ }
+ }
+#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: %p\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);
+ }
+ }
+ 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));
+ memset(&wq->request, 0, sizeof(struct encode_request_s));
+ 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;
+ 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 sucess, %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--Destory 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) {
+ 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, &param);
+ 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_AM_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_AM_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_INFO, "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 * 2)) ?
+ (MIN_SIZE * 2) : 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
+ }
+
+ 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();
+ 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;
+}
+
+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");
+
+#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..db4f255
--- a/dev/null
+++ b/drivers/frame_sink/encoder/h264/encoder.h
@@ -0,0 +1,465 @@
+/*
+ * 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_AM_GE2D
+#include <linux/amlogic/ge2d/ge2d.h>
+#endif
+
+#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
+
+/* 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 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,
+ 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,
+ 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 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 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;
+
+ 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;
+};
+
+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_AM_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
+
+/* --------------------------------------------------- */
+/* 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..e7414bf
--- a/dev/null
+++ b/drivers/frame_sink/encoder/h265/Makefile
@@ -0,0 +1 @@
+obj-m += 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..cb0112e
--- a/dev/null
+++ b/drivers/frame_sink/encoder/h265/vmm.h
@@ -0,0 +1,661 @@
+/*
+ * 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 (NULL == mm)
+ 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(%ld)\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..26c40fd
--- a/dev/null
+++ b/drivers/frame_sink/encoder/h265/vpu.c
@@ -0,0 +1,1997 @@
+/*
+ * 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/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_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 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 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 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_config(u32 enable)
+{
+ if (enable)
+ HevcEnc_clock_enable(clock_level);
+ else
+ HevcEnc_clock_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;
+ }
+
+ vb->base = (ulong)(s_video_memory.base +
+ (vb->phys_addr - s_video_memory.phys_addr));
+ return 0;
+}
+
+static void vpu_free_dma_buffer(struct vpudrv_buffer_t *vb)
+{
+ if (!vb)
+ return;
+
+ if (vb->base)
+ 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.base) {
+ 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,
+ CODEC_MM_FLAGS_CPU);
+ if (s_video_memory.phys_addr)
+ s_video_memory.base =
+ (ulong)phys_to_virt(s_video_memory.phys_addr);
+ else
+ s_video_memory.base = 0;
+ if (s_video_memory.base) {
+ 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.base) {
+ 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");
+ return -EFAULT;
+ }
+ s_vpu_irq_requested = true;
+ }
+ amports_switch_gate("vdec", 1);
+ spin_lock_irqsave(&s_vpu_lock, flags);
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~(0x3<<24));
+ udelay(10);
+
+ data32 = 0x700;
+ data32 |= READ_VREG(DOS_SW_RESET4);
+ WRITE_VREG(DOS_SW_RESET4, data32);
+ data32 &= ~0x700;
+ WRITE_VREG(DOS_SW_RESET4, data32);
+
+ 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);
+
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~(0x3<<12));
+ udelay(10);
+
+ spin_unlock_irqrestore(&s_vpu_lock, flags);
+ }
+Err:
+ 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;
+ 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.base =
+ (ulong)buf32.base;
+ 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.base =
+ (compat_ulong_t)vbp->vb.base;
+ 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;
+ 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.base)
+ vpu_free_dma_buffer(&vb);
+
+ spin_lock(&s_vpu_lock);
+ list_for_each_entry_safe(vbp, n,
+ &s_vbp_head, list)
+ {
+ if (vbp->vb.base == vb.base) {
+ 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;
+ 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.base =
+ (ulong)buf32.base;
+ vb.virt_addr =
+ (ulong)buf32.virt_addr;
+
+ if (vb.base)
+ 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;
+ case VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO:
+ {
+ enc_pr(LOG_ALL,
+ "[+]VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO\n");
+ if (s_video_memory.base != 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;
+ 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.base =
+ (compat_ulong_t)s_video_memory.base;
+ buf32.virt_addr =
+ (compat_ulong_t)s_video_memory.virt_addr;
+ if (s_video_memory.base != 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;
+ 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;
+ }
+ 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;
+ 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.base =
+ (compat_ulong_t)
+ s_instance_pool.base;
+ 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;
+ case VDI_IOCTL_GET_COMMON_MEMORY:
+ {
+ enc_pr(LOG_ALL,
+ "[+]VDI_IOCTL_GET_COMMON_MEMORY\n");
+ if (s_common_memory.base != 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;
+ 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.base =
+ (compat_ulong_t)
+ s_common_memory.base;
+ buf32.virt_addr =
+ (compat_ulong_t)
+ s_common_memory.virt_addr;
+ if (s_common_memory.base != 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.base =
+ (compat_ulong_t)
+ s_common_memory.base;
+ 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;
+ 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;
+ 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.base =
+ (compat_ulong_t)
+ s_vpu_register.base;
+ 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;
+ 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;
+ default:
+ {
+ enc_pr(LOG_ERROR,
+ "No such IOCTL, cmd is %d\n", cmd);
+ }
+ 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) {
+ 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.base) {
+ enc_pr(LOG_DEBUG, "free common memory\n");
+ vpu_free_dma_buffer(&s_common_memory);
+ s_common_memory.base = 0;
+ }
+
+ if (s_video_memory.base && !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 >= 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);
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) | (0x3<<12));
+ udelay(10);
+
+ WRITE_VREG(DOS_MEM_PD_WAVE420L, 0xffffffff);
+#ifndef VPU_SUPPORT_CLOCK_CONTROL
+ vpu_clk_config(0);
+#endif
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | (0x3<<24));
+ udelay(10);
+ spin_unlock_irqrestore(&s_vpu_lock, flags);
+ 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); */
+ 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 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");
+}
+
+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,
+};
+
+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;
+ s_video_memory.base =
+ (ulong)phys_to_virt(s_video_memory.phys_addr);
+ if (!s_video_memory.base) {
+ enc_pr(LOG_ERROR, "fail to remap video memory ");
+ enc_pr(LOG_ERROR,
+ "physical phys_addr=0x%lx, base=0x%lx, size=0x%x\n",
+ (ulong)s_video_memory.phys_addr,
+ (ulong)s_video_memory.base,
+ (u32)s_video_memory.size);
+ s_video_memory.phys_addr = 0;
+ r = -EFAULT;
+ }
+ 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\n");
+
+ 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
+
+#ifdef VPU_SUPPORT_CLOCK_CONTROL
+#else
+ 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_INFO, "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.base) {
+ vmem_exit(&s_vmem);
+ memset(&s_video_memory, 0, sizeof(struct vpudrv_buffer_t));
+ memset(&s_vmem, 0, sizeof(struct video_mm_t));
+ }
+
+ vpu_clk_config(0);
+
+ 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.base) {
+ vpu_free_dma_buffer(&s_common_memory);
+ s_common_memory.base = 0;
+ }
+
+ if (s_video_memory.base) {
+ 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;
+ vpu_clk_config(0);
+
+ 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);
+ return;
+}
+
+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);
+
+ 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) {
+ enc_pr(LOG_DEBUG,
+ "The chip is not support hevc encoder\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)
+ platform_driver_unregister(&vpu_driver);
+ return;
+}
+
+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_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(cnm_hevc, "cnm, 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..eaed0b7
--- a/dev/null
+++ b/drivers/frame_sink/encoder/h265/vpu.h
@@ -0,0 +1,288 @@
+/*
+ * 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>
+
+#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)));
+
+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 */
+};
+
+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];
+};
+
+#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_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)
+
+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_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/include/dummy-for-git-empty-dir b/drivers/include/dummy-for-git-empty-dir
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/drivers/include/dummy-for-git-empty-dir
diff --git a/drivers/stream_input/Makefile b/drivers/stream_input/Makefile
new file mode 100644
index 0000000..7d6a2c0
--- a/dev/null
+++ b/drivers/stream_input/Makefile
@@ -0,0 +1,10 @@
+obj-m += stream_input.o
+stream_input-objs += amports/amstream.o
+stream_input-objs += amports/amstream_profile.o
+stream_input-objs += amports/adec.o
+stream_input-objs += parser/thread_rw.o
+stream_input-objs += parser/streambuf.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
diff --git a/drivers/stream_input/amports/Makefile b/drivers/stream_input/amports/Makefile
new file mode 100644
index 0000000..55fbdce
--- a/dev/null
+++ b/drivers/stream_input/amports/Makefile
@@ -0,0 +1,2 @@
+obj-y += amports.o
+amports-objs += amstream.o amstream_profile.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..220c888
--- a/dev/null
+++ b/drivers/stream_input/amports/adec.c
@@ -0,0 +1,295 @@
+/*
+ * 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 "../parser/streambuf.h"
+#include <linux/module.h>
+#include "amports_priv.h"
+
+#define INFO_VALID ((astream_dev) && (astream_dev->format))
+
+struct astream_device_s {
+ char *name;
+ char *format;
+ s32 channum;
+ s32 samplerate;
+ s32 datawidth;
+
+ 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_wmavoi"
+};
+
+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;
+ u32 pts_margin = 0;
+
+ if (astream_dev->samplerate <= 12000)
+ pts_margin = 512;
+
+ if (INFO_VALID && (pts_lookup(PTS_TYPE_AUDIO, &pts, pts_margin) >= 0))
+ return sprintf(buf, "0x%x\n", pts);
+ else
+ return sprintf(buf, "%s\n", na_string);
+}
+
+static struct class_attribute astream_class_attrs[] = {
+ __ATTR_RO(format),
+ __ATTR_RO(samplerate),
+ __ATTR_RO(channum),
+ __ATTR_RO(datawidth),
+ __ATTR_RO(pts),
+ __ATTR_NULL
+};
+
+static struct class astream_class = {
+ .name = "astream",
+ .class_attrs = astream_class_attrs,
+ };
+
+#if 1
+#define IO_CBUS_PHY_BASE 0xc1100000
+#define CBUS_REG_OFFSET(reg) ((reg) << 2)
+#define IO_SECBUS_PHY_BASE 0xda000000
+
+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,
+ },
+ [3] = {
+ .name = "CBUS",
+ .memtype = UIO_MEM_PHYS,
+ .addr =
+ (IO_CBUS_PHY_BASE + CBUS_REG_OFFSET(ASSIST_HW_REV))
+ &(PAGE_MASK),
+ .size = PAGE_SIZE,
+ },
+ [4] = {
+ .name = "CBUS-START",
+ .memtype = UIO_MEM_PHYS,
+ .addr = (IO_CBUS_PHY_BASE + CBUS_REG_OFFSET(0x1000)),
+ .size = PAGE_SIZE * 4,
+ },
+ },
+};
+#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;
+}
+
+s32 adec_release(enum aformat_e vf)
+{
+ pr_info("adec_release\n");
+
+ if (!astream_dev)
+ return -ENODEV;
+
+ astream_dev->format = NULL;
+
+ return 0;
+}
+
+s32 astream_dev_register(void)
+{
+ s32 r;
+
+ 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) {
+ r = -ENOMEM;
+ goto err_3;
+ }
+
+ astream_dev->dev.class = &astream_class;
+ astream_dev->dev.release = astream_release;
+
+ 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 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
+
+ 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..545ac76
--- a/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 "../parser/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..4b6f96e
--- a/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 "../parser/streambuf.h"
+#include "../../common/media_clock/switch/amports_gate.h"
+#include <linux/amlogic/media/vfm/vframe.h>
+#include "../../common/firmware/firmware.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 stream_buf_s *get_buf_by_type(u32 type);
+
+extern void amvenc_dos_top_reg_fix(void);
+
+/*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);
+#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);
+int amports_get_debug_flags(void);
+
+#endif
diff --git a/drivers/stream_input/amports/amstream.c b/drivers/stream_input/amports/amstream.c
new file mode 100644
index 0000000..f1d2c74
--- a/dev/null
+++ b/drivers/stream_input/amports/amstream.c
@@ -0,0 +1,3651 @@
+/*
+ * 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.
+ *
+*/
+
+#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/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/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 "../parser/streambuf.h"
+#include "../parser/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 "../parser/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>
+#include "../../common/firmware/firmware.h"
+#ifdef CONFIG_COMPAT
+#include <linux/compat.h>
+#endif
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+
+#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;
+
+#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
+
+
+static int debugflags;
+
+#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 debugflags;
+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);
+
+/*
+*bit0:no threadrw
+*/
+int amports_get_debug_flags(void)
+{
+ return debugflags;
+}
+
+#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 ssize_t amstream_userdata_read
+(struct file *file, char *buf, size_t count, loff_t *ppos);
+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
+
+static const struct file_operations vbuf_fops = {
+ .owner = THIS_MODULE,
+ .open = amstream_open,
+ .release = amstream_release,
+ .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,
+ .read = amstream_userdata_read,
+ .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 = 0, userdata_poc_wi;
+
+static struct stream_port_s ports[] = {
+#ifdef CONFIG_MULTI_DEC
+ {
+ .name = "amstream_vbuf",
+ .type = PORT_TYPE_ES | PORT_TYPE_VIDEO,
+ .fops = &vbuf_fops,
+ },
+ {
+ .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,
+ },
+#else
+ {
+ .name = "amstream_vbuf",
+ .type = PORT_TYPE_ES | PORT_TYPE_VIDEO,
+ .fops = &vbuf_fops,
+ },
+#endif
+ {
+ .name = "amstream_abuf",
+ .type = PORT_TYPE_ES | PORT_TYPE_AUDIO,
+ .fops = &abuf_fops,
+ },
+#ifdef CONFIG_MULTI_DEC
+ {
+ .name = "amstream_mpts",
+ .type = PORT_TYPE_MPTS | PORT_TYPE_VIDEO |
+ PORT_TYPE_AUDIO | PORT_TYPE_SUB,
+ .fops = &mpts_fops,
+ },
+ {
+ .name = "amstream_mpts_sched",
+ .type = PORT_TYPE_MPTS | PORT_TYPE_VIDEO |
+ PORT_TYPE_AUDIO | PORT_TYPE_SUB |
+ PORT_TYPE_DECODER_SCHED,
+ .fops = &mpts_fops,
+ },
+#else
+ {
+ .name = "amstream_mpts",
+ .type = PORT_TYPE_MPTS | PORT_TYPE_VIDEO |
+ PORT_TYPE_AUDIO | PORT_TYPE_SUB,
+ .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,
+ },
+#ifdef CONFIG_MULTI_DEC
+ {
+ .name = "amstream_hevc",
+#ifdef CONFIG_AM_VDEC_DV
+/*test dobly vision, remove later*/
+ .type = PORT_TYPE_ES | PORT_TYPE_VIDEO | PORT_TYPE_HEVC |
+ PORT_TYPE_DECODER_SCHED | PORT_TYPE_DUALDEC,
+ .fops = &vbuf_fops,
+ .vformat = VFORMAT_HEVC,
+#else
+ .type = PORT_TYPE_ES | PORT_TYPE_VIDEO | PORT_TYPE_HEVC,
+ .fops = &vbuf_fops,
+ .vformat = VFORMAT_HEVC,
+#endif
+ },
+ {
+ .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_AM_VDEC_DV
+ ,
+ {
+ .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,
+ }
+#endif
+#else
+ {
+ .name = "amstream_hevc",
+ .type = PORT_TYPE_ES | PORT_TYPE_VIDEO | PORT_TYPE_HEVC,
+ .fops = &vbuf_fops,
+ .vformat = VFORMAT_HEVC,
+ }
+#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) {
+ pr_info("streambuf is alloced before\n");
+ return;
+ }
+ if (pvbuf->for_4k) {
+ pvbuf->buf_size = def_4k_vstreambuf_sizeM * SZ_1M;
+ if (codec_mm_video_tvp_enabled())
+ 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 (codec_mm_video_tvp_enabled())
+ pvbuf->buf_size = DEFAULT_VIDEO_BUFFER_SIZE_TVP;
+ } else {
+ pvbuf->buf_size = def_vstreambuf_sizeM * SZ_1M;
+ if (codec_mm_video_tvp_enabled())
+ 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->port_flag & PORT_FLAG_INITED;
+ }
+
+ 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;
+ } 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 stream_port_s *port = priv->port;
+ struct vdec_s *vdec = priv->vdec;
+
+ switch (release_num) {
+ default:
+ /*fallthrough*/
+ case 0: /*release all */
+ /*fallthrough*/
+ case 4:
+ if ((port->type & PORT_TYPE_FRAME) == 0)
+ esparser_release(pbuf);
+ /*fallthrough*/
+ case 3:
+ if (vdec->slave)
+ vdec_release(vdec->slave);
+ vdec_release(vdec);
+ priv->vdec = NULL;
+ /*fallthrough*/
+ case 2:
+ if ((port->type & PORT_TYPE_FRAME) == 0)
+ stbuf_release(pbuf);
+ /*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 ((port->flag & PORT_FLAG_VFORMAT) == 0) {
+ pr_err("vformat not set\n");
+ return -EPERM;
+ }
+
+ if (port->vformat == VFORMAT_H264_4K2K ||
+ (priv->vdec->sys_info->height *
+ priv->vdec->sys_info->width) > 1920*1088) {
+ pbuf->for_4k = 1;
+ } else {
+ pbuf->for_4k = 0;
+ }
+
+ 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__);
+ video_port_release(priv, pbuf, 2);
+ return r;
+ }
+
+ 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);
+ }
+ }
+
+ r = stbuf_init(pbuf, vdec);
+ if (r < 0) {
+ pr_err("video_port_init %d, stbuf_init failed\n", __LINE__);
+ return r;
+ }
+
+ /* 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__);
+ video_port_release(priv, pbuf, 2);
+ return r;
+ }
+
+ 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__);
+ video_port_release(priv, pbuf, 2);
+ return r;
+ }
+ }
+
+ if (port->type & PORT_TYPE_ES) {
+ r = esparser_init(pbuf, vdec);
+ if (r < 0) {
+ video_port_release(priv, pbuf, 3);
+ pr_err("esparser_init() failed\n");
+ return r;
+ }
+ }
+
+ pbuf->flag |= BUF_FLAG_IN_USE;
+
+ vdec_connect(priv->vdec);
+
+ return 0;
+}
+
+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:
+ ;
+ }
+}
+
+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;
+ }
+
+ 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;
+
+ pts_start(PTS_TYPE_AUDIO);
+
+ return 0;
+}
+
+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;
+
+ if ((port->flag & PORT_FLAG_SID) == 0) {
+ pr_err("subtitle id not set\n");
+ return 0;
+ }
+
+ r = stbuf_init(pbuf, NULL);
+ if (r < 0)
+ return r;
+
+ 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 int amstream_port_init(struct port_priv_s *priv)
+{
+ int r;
+ 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_buf_s *pubuf = &bufs[BUF_TYPE_USERDATA];
+ struct stream_port_s *port = priv->port;
+ struct vdec_s *vdec = priv->vdec;
+
+ mutex_lock(&amstream_mutex);
+
+ stbuf_fetch_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)) {
+ pubuf->buf_size = 0;
+ pubuf->buf_start = 0;
+ pubuf->buf_wp = 0;
+ pubuf->buf_rp = 0;
+ pvbuf->for_4k = 0;
+ if (has_hevc_vdec()) {
+ if (port->vformat == VFORMAT_HEVC ||
+ port->vformat == VFORMAT_VP9)
+ pvbuf = &bufs[BUF_TYPE_HEVC];
+ }
+ r = video_port_init(priv, pvbuf);
+ if (r < 0) {
+ pr_err("video_port_init failed\n");
+ goto error2;
+ }
+ }
+
+ 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 error3;
+ }
+ }
+
+ if (port->type & PORT_TYPE_MPTS) {
+ if (has_hevc_vdec()) {
+ r = tsdemux_init(
+ (port->flag & PORT_FLAG_VID) ? port->vid : 0xffff,
+ (port->flag & PORT_FLAG_AID) ? port->aid : 0xffff,
+ (port->flag & PORT_FLAG_SID) ? port->sid : 0xffff,
+ (port->pcr_inited == 1) ? port->pcrid : 0xffff,
+ (port->vformat == VFORMAT_HEVC) ||
+ (port->vformat == VFORMAT_VP9),
+ vdec);
+ } else {
+ r = tsdemux_init(
+ (port->flag & PORT_FLAG_VID) ? port->vid : 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 error4;
+ }
+ tsync_pcr_start();
+ }
+ if (port->type & PORT_TYPE_MPPS) {
+ r = psparser_init(
+ (port->flag & PORT_FLAG_VID) ? port->vid : 0xffff,
+ (port->flag & PORT_FLAG_AID) ? port->aid : 0xffff,
+ (port->flag & PORT_FLAG_SID) ? port->sid : 0xffff,
+ priv->vdec);
+ if (r < 0) {
+ pr_err("psparser_init failed\n");
+ goto error5;
+ }
+ }
+#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) &&
+ (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 */
+error5:
+ tsdemux_release();
+error4:
+ sub_port_release(port, psbuf);
+error3:
+ video_port_release(priv, pvbuf, 0);
+error2:
+ 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 = &bufs[BUF_TYPE_VIDEO];
+ struct stream_buf_s *pabuf = &bufs[BUF_TYPE_AUDIO];
+ struct stream_buf_s *psbuf = &bufs[BUF_TYPE_SUBTITLE];
+
+ 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_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;
+ 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_port_s *port = priv->port;
+ struct stream_buf_s *pbuf = NULL;
+ int r;
+
+
+ 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 = 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);
+ 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;
+#ifdef DATA_DEBUG
+ debug_file_write(buf, count);
+#endif
+ return vdec_write_vframe(priv->vdec, buf, count);
+}
+
+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 = NULL;
+ int r = 0;
+
+ if (has_hevc_vdec()) {
+ pvbuf = (port->vformat == VFORMAT_HEVC ||
+ port->vformat == VFORMAT_VP9) ?
+ &bufs[BUF_TYPE_HEVC] : &bufs[BUF_TYPE_VIDEO];
+ } else
+ pvbuf = &bufs[BUF_TYPE_VIDEO];
+
+ 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;
+
+ 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);
+ if (res >= 0)
+ 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);
+ if (res >= 0) {
+ 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);
+
+ if (res >= 0) {
+ 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);
+
+ if (res >= 0)
+ 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;
+}
+
+void set_userdata_poc(struct userdata_poc_info_t poc)
+{
+ /*
+ *pr_err("id %d, slicetype %d\n",
+ * userdata_slicetype_wi, slicetype);
+ */
+ 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;
+}
+EXPORT_SYMBOL(init_userdata_fifo);
+
+int wakeup_userdata_poll(int wp, unsigned long start_phyaddr, int buf_size,
+ int data_length)
+{
+ struct stream_buf_s *userdata_buf = &bufs[BUF_TYPE_USERDATA];
+
+ 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;
+ wake_up_interruptible(&amstream_userdata_wait);
+ return userdata_buf->buf_rp;
+}
+EXPORT_SYMBOL(wakeup_userdata_poll);
+
+static unsigned int amstream_userdata_poll(struct file *file,
+ poll_table *wait_table)
+{
+ poll_wait(file, &amstream_userdata_wait, wait_table);
+ if (atomic_read(&userdata_ready)) {
+ atomic_set(&userdata_ready, 0);
+ return POLLIN | POLLRDNORM;
+ }
+ return 0;
+}
+
+static ssize_t amstream_userdata_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ u32 data_size, res, retVal = 0, buf_wp;
+ struct stream_buf_s *userdata_buf = &bufs[BUF_TYPE_USERDATA];
+
+ buf_wp = userdata_buf->buf_wp;
+ if (userdata_buf->buf_start == 0 || userdata_buf->buf_size == 0)
+ return 0;
+ if (buf_wp == userdata_buf->buf_rp)
+ return 0;
+ if (buf_wp > userdata_buf->buf_rp)
+ data_size = buf_wp - userdata_buf->buf_rp;
+ else {
+ data_size =
+ userdata_buf->buf_size - userdata_buf->buf_rp + buf_wp;
+ }
+ if (data_size > count)
+ data_size = count;
+ if (buf_wp < userdata_buf->buf_rp) {
+ int first_num = userdata_buf->buf_size - userdata_buf->buf_rp;
+
+ if (data_size <= first_num) {
+ res = copy_to_user((void *)buf,
+ (void *)((userdata_buf->buf_rp +
+ userdata_buf->buf_start)), data_size);
+ userdata_buf->buf_rp += data_size - res;
+ retVal = data_size - res;
+ } else {
+ if (first_num > 0) {
+ res = copy_to_user((void *)buf,
+ (void *)((userdata_buf->buf_rp +
+ userdata_buf->buf_start)), first_num);
+ userdata_buf->buf_rp += first_num - res;
+ retVal = first_num - res;
+ } else {
+ res = copy_to_user((void *)buf,
+ (void *)((userdata_buf->buf_start)),
+ data_size - first_num);
+ userdata_buf->buf_rp =
+ data_size - first_num - res;
+ retVal = data_size - first_num - res;
+ }
+ }
+ } else {
+ res = copy_to_user((void *)buf,
+ (void *)((userdata_buf->buf_rp +
+ userdata_buf->buf_start)),
+ data_size);
+ userdata_buf->buf_rp += data_size - res;
+ retVal = data_size - res;
+ }
+ return retVal;
+}
+
+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;
+
+ if (iminor(inode) >= amstream_port_num)
+ return -ENODEV;
+
+ mutex_lock(&amstream_mutex);
+
+ if (port->type & PORT_TYPE_VIDEO) {
+ for (s = &ports[0], i = 0; i < amstream_port_num; i++, s++) {
+ if (((s->type & PORT_TYPE_DECODER_SCHED) == 0) &&
+ (s->type & PORT_TYPE_VIDEO) &&
+ (s->flag & PORT_FLAG_IN_USE)) {
+ mutex_unlock(&amstream_mutex);
+ return -EBUSY;
+ }
+ }
+ }
+
+ if ((port->flag & PORT_FLAG_IN_USE) &&
+ ((port->type & PORT_TYPE_FRAME) == 0)) {
+ mutex_unlock(&amstream_mutex);
+ return -EBUSY;
+ }
+
+ /* 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)
+ return -ENOMEM;
+
+ priv->port = port;
+
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_M6) {
+ /* TODO: mod gate */
+ /* switch_mod_gate_by_name("demux", 1); */
+ amports_switch_gate("demux", 1);
+ if (get_cpu_type() >= 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);
+ amports_switch_gate("clk_vdec_mux", 1);
+ amports_switch_gate("clk_hcodec_mux", 1);
+
+ if (has_hevc_vdec()) {
+ amports_switch_gate("clk_hevc_mux", 1);
+ 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_type() >= 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_DUALDEC) {
+ 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;
+
+ if (iminor(inode) >= amstream_port_num)
+ return -ENODEV;
+
+ mutex_lock(&amstream_mutex);
+
+ if (port_get_inited(priv))
+ amstream_port_release(priv);
+
+ if (priv->vdec) {
+ if (priv->vdec->slave)
+ vdec_release(priv->vdec->slave);
+
+ vdec_release(priv->vdec);
+ 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);
+ }
+ 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_type() >= MESON_CPU_MAJOR_ID_M6) {
+ if (port->type & PORT_TYPE_VIDEO) {
+ if (get_cpu_type() >= MESON_CPU_MAJOR_ID_M8) {
+#ifndef CONFIG_MULTI_DEC
+ if (has_hevc_vdec())
+ vdec_poweroff(VDEC_HEVC);
+
+ vdec_poweroff(VDEC_1);
+#else
+ if ((port->type & PORT_TYPE_MPTS) &&
+ ((port->flag & PORT_FLAG_VFORMAT) == 0)) {
+ vdec_poweroff(VDEC_1);
+ vdec_poweroff(VDEC_HEVC);
+ } else if ((port->vformat == VFORMAT_HEVC
+ || 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);
+ amports_switch_gate("clk_hcodec_mux", 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_type() >= 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);
+ }
+
+ 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;
+
+ 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, offset;
+
+ offset = parm.data_32;
+ pts_lookup_offset(PTS_TYPE_AUDIO, offset, &pts, 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_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;
+ 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;
+
+ 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) &&
+ ((bufs[BUF_TYPE_VIDEO].flag & BUF_FLAG_IN_USE) == 0)) {
+ if (has_hevc_vdec())
+ bufs[BUF_TYPE_HEVC].buf_start = parm.data_32;
+ bufs[BUF_TYPE_VIDEO].buf_start = parm.data_32;
+ } else
+ r = -EINVAL;
+ break;
+ case AMSTREAM_SET_VB_SIZE:
+ if ((this->type & PORT_TYPE_VIDEO) &&
+ ((bufs[BUF_TYPE_VIDEO].flag & BUF_FLAG_IN_USE) == 0)) {
+ if (bufs[BUF_TYPE_VIDEO].flag & BUF_FLAG_ALLOC) {
+ if (has_hevc_vdec()) {
+ r = stbuf_change_size(
+ &bufs[BUF_TYPE_HEVC],
+ parm.data_32);
+ }
+ r = stbuf_change_size(
+ &bufs[BUF_TYPE_VIDEO],
+ parm.data_32);
+ }
+ } 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);
+ }
+ } 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 (has_hevc_vdec() && this->type & PORT_TYPE_HEVC)
+ r = es_vpts_checkin(&bufs[BUF_TYPE_HEVC],
+ parm.data_32);
+ else if (this->type & PORT_TYPE_VIDEO)
+ r = es_vpts_checkin(&bufs[BUF_TYPE_VIDEO],
+ 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 (has_hevc_vdec()) {
+ if (this->type & PORT_TYPE_HEVC) {
+ r = es_vpts_checkin_us64(
+ &bufs[BUF_TYPE_HEVC], pts);
+ } else if (this->type & PORT_TYPE_VIDEO) {
+ r = es_vpts_checkin_us64(
+ &bufs[BUF_TYPE_VIDEO], pts);
+ } else if (this->type & PORT_TYPE_AUDIO) {
+ r = es_vpts_checkin_us64(
+ &bufs[BUF_TYPE_AUDIO], pts);
+ }
+ } else {
+ if (this->type & PORT_TYPE_VIDEO) {
+ r = es_vpts_checkin_us64(
+ &bufs[BUF_TYPE_VIDEO], 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];
+
+ r = audio_port_reset(this, pabuf);
+ } 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:
+ if (parm.data_32 >= 0)
+ tsdemux_set_skipbyte(parm.data_32);
+ else
+ r = -EINVAL;
+ 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:
+ if (has_hevc_vdec())
+ bufs[BUF_TYPE_HEVC].max_buffer_delay_ms = parm.data_32;
+ bufs[BUF_TYPE_VIDEO].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_err("set drmmode\n");
+ this->flag |= PORT_FLAG_DRM;
+ } else {
+ this->flag &= (~PORT_FLAG_DRM);
+ pr_err("no drmmode\n");
+ }
+ 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 ((this->type & PORT_TYPE_DECODER_SCHED) &&
+ (parm.frame_base_video_path < FRAME_BASE_PATH_MAX)) {
+ vdec_set_video_path(priv->vdec, parm.data_32);
+ } else
+ r = -EINVAL;
+ break;
+ default:
+ r = -ENOIOCTLCMD;
+ break;
+ }
+ return r;
+}
+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;
+
+ buf = (this->vformat == VFORMAT_HEVC ||
+ this->vformat == VFORMAT_VP9) ?
+ &bufs[BUF_TYPE_HEVC] :
+ &bufs[BUF_TYPE_VIDEO];
+
+ if (p == NULL) {
+ r = -EINVAL;
+ break;
+ }
+
+ if (this->type & PORT_TYPE_FRAME) {
+ struct vdec_input_status_s status;
+
+ /*
+ *todo: check upper layer for decoder
+ * handler lifecycle
+ */
+ if (priv->vdec == NULL) {
+ r = -EINVAL;
+ break;
+ }
+
+ 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;
+ }
+ break;
+ }
+
+ 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_AB_STATUS:
+ if (this->type & PORT_TYPE_AUDIO) {
+ struct am_ioctl_parm_ex *p = &parm;
+ struct stream_buf_s *buf = &bufs[BUF_TYPE_AUDIO];
+
+ if (p == NULL)
+ r = -EINVAL;
+
+ 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_status vstatus;
+ struct am_ioctl_parm_ex *p = &parm;
+
+ if (p == NULL)
+ return -EINVAL;
+ if (vdec_status(priv->vdec, &vstatus) == -1)
+ return -ENODEV;
+ p->vstatus.width = vstatus.width;
+ p->vstatus.height = vstatus.height;
+ p->vstatus.fps = vstatus.fps;
+ p->vstatus.error_count = vstatus.error_count;
+ p->vstatus.status = vstatus.status;
+ }
+ 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;
+
+ if (p == NULL)
+ return -EINVAL;
+ 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_FIFO_NUM == userdata_poc_ri)
+ userdata_poc_ri = 0;
+ } else
+ r = -EINVAL;
+ 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)))
+ r = -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)
+ memcpy((void *)&audio_dec_info,
+ (void *)parm.pdata_audio_info,
+ sizeof(audio_dec_info));
+ } 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;
+ 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;
+ 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;
+
+ switch (cmd) {
+
+ case AMSTREAM_IOC_VB_START:
+ if ((this->type & PORT_TYPE_VIDEO) &&
+ ((bufs[BUF_TYPE_VIDEO].flag & BUF_FLAG_IN_USE) == 0)) {
+ if (has_hevc_vdec())
+ bufs[BUF_TYPE_HEVC].buf_start = arg;
+ bufs[BUF_TYPE_VIDEO].buf_start = arg;
+ } else
+ r = -EINVAL;
+ break;
+
+ case AMSTREAM_IOC_VB_SIZE:
+ if ((this->type & PORT_TYPE_VIDEO) &&
+ ((bufs[BUF_TYPE_VIDEO].flag & BUF_FLAG_IN_USE) == 0)) {
+ if (bufs[BUF_TYPE_VIDEO].flag & BUF_FLAG_ALLOC) {
+ if (has_hevc_vdec()) {
+ r = stbuf_change_size(
+ &bufs[BUF_TYPE_HEVC], arg);
+ }
+ r = stbuf_change_size(
+ &bufs[BUF_TYPE_VIDEO], arg);
+ }
+ } 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);
+ }
+ } 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 = &para;
+ struct stream_buf_s *buf = NULL;
+
+ buf = (this->vformat == VFORMAT_HEVC ||
+ this->vformat == VFORMAT_VP9) ?
+ &bufs[BUF_TYPE_HEVC] :
+ &bufs[BUF_TYPE_VIDEO];
+
+ if (p == NULL) {
+ r = -EINVAL;
+ break;
+ }
+
+ if (this->type & PORT_TYPE_FRAME) {
+ struct vdec_input_status_s status;
+
+ /*
+ *todo: check upper layer for decoder
+ * handler lifecycle
+ */
+ if (priv->vdec == NULL) {
+ r = -EINVAL;
+ break;
+ }
+
+ 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;
+ }
+ break;
+ }
+
+ 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_AB_STATUS:
+ if (this->type & PORT_TYPE_AUDIO) {
+ struct am_io_param para;
+ struct am_io_param *p = &para;
+ struct stream_buf_s *buf = &bufs[BUF_TYPE_AUDIO];
+
+ if (p == NULL)
+ r = -EINVAL;
+
+ 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 (has_hevc_vdec() && this->type & PORT_TYPE_HEVC)
+ r = es_vpts_checkin(&bufs[BUF_TYPE_HEVC], arg);
+ else if (this->type & PORT_TYPE_VIDEO)
+ r = es_vpts_checkin(&bufs[BUF_TYPE_VIDEO], 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 (has_hevc_vdec()) {
+ if (this->type & PORT_TYPE_HEVC) {
+ r = es_vpts_checkin_us64(
+ &bufs[BUF_TYPE_HEVC], pts);
+ } else if (this->type & PORT_TYPE_VIDEO) {
+ r = es_vpts_checkin_us64(
+ &bufs[BUF_TYPE_VIDEO], pts);
+ } else if (this->type & PORT_TYPE_AUDIO) {
+ r = es_vpts_checkin_us64(
+ &bufs[BUF_TYPE_AUDIO], pts);
+ }
+ } else {
+ if (this->type & PORT_TYPE_VIDEO) {
+ r = es_vpts_checkin_us64(
+ &bufs[BUF_TYPE_VIDEO], 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_status vstatus;
+ struct am_io_param para;
+ struct am_io_param *p = &para;
+
+ if (p == NULL)
+ return -EINVAL;
+ if (vdec_status(priv->vdec, &vstatus) == -1)
+ return -ENODEV;
+ p->vstatus.width = vstatus.width;
+ p->vstatus.height = vstatus.height;
+ p->vstatus.fps = vstatus.fps;
+ p->vstatus.error_count = vstatus.error_count;
+ p->vstatus.status = vstatus.status;
+ if (copy_to_user((void *)arg, p, 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 = &para;
+
+ if (p == NULL)
+ return -EINVAL;
+ 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];
+
+ r = audio_port_reset(this, pabuf);
+ } 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, (unsigned long __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 res;
+ struct userdata_poc_info_t userdata_poc =
+ userdata_poc_info[userdata_poc_ri];
+ /*
+ *put_user(userdata_poc.poc_number,
+ * (unsigned long __user *)arg);
+ */
+ res =
+ copy_to_user((unsigned long __user *)arg,
+ &userdata_poc,
+ sizeof(struct userdata_poc_info_t));
+ if (res < 0)
+ r = -EFAULT;
+ userdata_poc_ri++;
+ if (USERDATA_FIFO_NUM == userdata_poc_ri)
+ userdata_poc_ri = 0;
+ } 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, offset;
+
+ get_user(offset, (unsigned long __user *)arg);
+ pts_lookup_offset(PTS_TYPE_AUDIO, offset, &pts, 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:
+ if (has_hevc_vdec())
+ bufs[BUF_TYPE_HEVC].max_buffer_delay_ms = (int)arg;
+ bufs[BUF_TYPE_VIDEO].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(bufs[BUF_TYPE_VIDEO].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\n");
+ this->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;
+ }
+ 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:
+ r = amstream_do_ioctl_new(priv, cmd, arg);
+ break;
+ default:
+ r = amstream_do_ioctl_old(priv, cmd, arg);
+ break;
+ }
+ if (r != 0)
+ pr_err("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 __user *data32 = arg;
+ int ret;
+
+ data = compat_alloc_user_space(sizeof(*data));
+ if (!access_ok(VERIFY_WRITE, data, sizeof(*data)))
+ return -EFAULT;
+
+ if (put_user(data32->cmd, &data->cmd) ||
+ put_user(compat_ptr(data32->pointer), &data->pointer) ||
+ put_user(data32->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;
+
+ 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(data32->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;
+}
+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));
+ 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 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];
+ /*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_type() >= 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_type() >= 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)
+ );
+ }
+ }
+
+ 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;
+ struct stream_buf_s *p_hevc = NULL;
+
+ p = &bufs[0];
+ if (has_hevc_vdec())
+ p_hevc = &bufs[BUF_TYPE_HEVC];
+
+ if (p->flag & BUF_FLAG_IN_USE)
+ pbuf += sprintf(pbuf, "%d ", 1);
+ else if (has_hevc_vdec() && (p_hevc->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 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 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 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_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;
+}
+
+/*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;
+ }
+
+ 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();
+ 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_VIDEO].flag & BUF_FLAG_ALLOC)
+ stbuf_change_size(&bufs[BUF_TYPE_VIDEO], 0);
+ if (bufs[BUF_TYPE_AUDIO].flag & BUF_FLAG_ALLOC)
+ stbuf_change_size(&bufs[BUF_TYPE_AUDIO], 0);
+ 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;
+}
+
+/*get pes buffers */
+
+struct stream_buf_s *get_stream_buffer(int id)
+{
+ if (id >= BUF_MAX_NUM)
+ return 0;
+ return &bufs[id];
+}
+
+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;
+ }
+ return 0;
+}
+
+static void __exit amstream_module_exit(void)
+{
+ platform_driver_unregister(&amstream_driver);
+ return;
+}
+
+module_init(amstream_module_init);
+module_exit(amstream_module_exit);
+
+module_param(debugflags, uint, 0664);
+MODULE_PARM_DESC(debugflags, "\n amstream debugflags\n");
+
+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/amstream_profile.c b/drivers/stream_input/amports/amstream_profile.c
new file mode 100644
index 0000000..d65ee5c
--- a/dev/null
+++ b/drivers/stream_input/amports/amstream_profile.c
@@ -0,0 +1,54 @@
+/*
+ * drivers/amlogic/media/stream_input/amports/amstream_profile.c
+ *
+ * Copyright (C) 2016 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+*/
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/amlogic/media/utils/amstream.h>
+#include "amports_priv.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 += sprintf(pbuf, "%s:%s;\n", vcodec_profile[i]->name,
+ vcodec_profile[i]->profile);
+ }
+
+ return pbuf - buf;
+}
+
+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);
+
diff --git a/drivers/stream_input/parser/esparser.c b/drivers/stream_input/parser/esparser.c
new file mode 100644
index 0000000..a9b8e29
--- a/dev/null
+++ b/drivers/stream_input/parser/esparser.c
@@ -0,0 +1,940 @@
+/*
+ * 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 "streambuf_reg.h"
+#include "streambuf.h"
+#include "esparser.h"
+#include "../amports/amports_priv.h"
+#include "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_MPEG_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)
+
+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_MPEG_REG(AIU_MEM_AIFIFO_MAN_WP, wp/* & 0xffffff00*/);
+ }
+}
+
+static irqreturn_t esparser_isr(int irq, void *dev_id)
+{
+ u32 int_status = READ_MPEG_REG(PARSER_INT_STATUS);
+
+ WRITE_MPEG_REG(PARSER_INT_STATUS, int_status);
+
+ if (int_status & PARSER_INTSTAT_SC_FOUND) {
+ WRITE_MPEG_REG(PFIFO_RD_PTR, 0);
+ WRITE_MPEG_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_MPEG_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_MPEG_REG(AIU_MEM_AIFIFO_MAN_WP) :
+ READ_MPEG_REG(PARSER_SUB_START_PTR);
+ } else {
+ wp =
+#if 1/* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
+ (type == BUF_TYPE_HEVC) ? READ_MPEG_REG(PARSER_VIDEO_WP) :
+#endif
+ (type == BUF_TYPE_VIDEO) ? READ_MPEG_REG(PARSER_VIDEO_WP) :
+ (type == BUF_TYPE_AUDIO) ?
+ READ_MPEG_REG(AIU_MEM_AIFIFO_MAN_WP) :
+ READ_MPEG_REG(PARSER_SUB_START_PTR);
+ }
+
+ return wp;
+}
+
+static ssize_t _esparser_write(const char __user *buf,
+ size_t count, u32 type, int isphybuf)
+{
+ 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;
+
+ 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 (isphybuf)
+ 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_MPEG_REG(PFIFO_RD_PTR, 0);
+ WRITE_MPEG_REG(PFIFO_WR_PTR, 0);
+
+ WRITE_MPEG_REG_BITS(PARSER_CONTROL, len, ES_PACK_SIZE_BIT,
+ ES_PACK_SIZE_WID);
+ WRITE_MPEG_REG_BITS(PARSER_CONTROL,
+ parser_type | PARSER_WRITE |
+ PARSER_AUTOSEARCH, ES_CTRL_BIT,
+ ES_CTRL_WID);
+
+ if (isphybuf) {
+ u32 buf_32 = (unsigned long)buf & 0xffffffff;
+
+ WRITE_MPEG_REG(PARSER_FETCH_ADDR, buf_32);
+ } else {
+ WRITE_MPEG_REG(PARSER_FETCH_ADDR, dma_addr);
+ dma_unmap_single(amports_get_dma_device(), dma_addr,
+ FETCHBUF_SIZE, DMA_TO_DEVICE);
+ }
+
+ search_done = 0;
+ if (!(isphybuf & TYPE_PATTERN)) {
+ WRITE_MPEG_REG(PARSER_FETCH_CMD,
+ (7 << FETCH_ENDIAN) | len);
+ WRITE_MPEG_REG(PARSER_FETCH_ADDR, search_pattern_map);
+ WRITE_MPEG_REG(PARSER_FETCH_CMD,
+ (7 << FETCH_ENDIAN) | SEARCH_PATTERN_LEN);
+ } else {
+ WRITE_MPEG_REG(PARSER_FETCH_CMD,
+ (7 << FETCH_ENDIAN) | (len + 512));
+ }
+ ret = wait_event_interruptible_timeout(wq, search_done != 0,
+ HZ / 5);
+ if (ret == 0) {
+ WRITE_MPEG_REG(PARSER_FETCH_CMD, 0);
+
+ if (wp == buf_wp(type))
+ /*no data fetched */
+ return -EAGAIN;
+
+ pr_info("W Timeout, but fetch ok,");
+ pr_info("type %d len=%d,wpdiff=%d, isphy %x\n",
+ type, len, wp - buf_wp(type), isphybuf);
+
+ } 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;
+
+ return len;
+}
+
+static ssize_t _esparser_write_s(const char __user *buf,
+ size_t count, u32 type)
+{
+ size_t r = count;
+ const char __user *p = buf;
+ u32 len = 0;
+ int ret;
+ u32 wp, buf_start, buf_end;
+ dma_addr_t buf_wp_map;
+
+ if (type != BUF_TYPE_AUDIO)
+ WARN_ON(1);/*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) {
+ ret = copy_from_user(codec_mm_phys_to_virt(wp),
+ p, buf_end - wp);
+ if (ret > 0) {
+ len += buf_end - wp - ret;
+ buf_wp_map = dma_map_single(amports_get_dma_device(),
+ codec_mm_phys_to_virt(wp), len, DMA_TO_DEVICE);
+ wp += len;
+ pr_info("copy from user not finished\n");
+ dma_unmap_single(NULL, buf_wp_map, len, DMA_TO_DEVICE);
+ set_buf_wp(type, wp);
+ goto end_write;
+ } else if (ret == 0) {
+ len += buf_end - wp;
+ buf_wp_map = dma_map_single(amports_get_dma_device(),
+ codec_mm_phys_to_virt(wp), len, DMA_TO_DEVICE);
+ wp = buf_start;
+ r = count - len;
+ dma_unmap_single(NULL, buf_wp_map, len, DMA_TO_DEVICE);
+ 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;
+ }
+ }
+ ret = copy_from_user(codec_mm_phys_to_virt(wp), p + len, r);
+ if (ret >= 0) {
+ len += r - ret;
+ buf_wp_map = dma_map_single(amports_get_dma_device(),
+ codec_mm_phys_to_virt(wp), r - ret, DMA_TO_DEVICE);
+
+ if (ret > 0)
+ pr_info("copy from user not finished 2\n");
+ wp += r - ret;
+ dma_unmap_single(NULL, buf_wp_map, r - ret, DMA_TO_DEVICE);
+ 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;
+
+ 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 = video_data_parsed + threadrw_buffer_level(buf);
+
+ 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 = audio_data_parsed + threadrw_buffer_level(buf);
+
+ 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 */
+ 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_MPEG_REG(PARSER_SUB_START_PTR);
+ parser_sub_end_ptr = READ_MPEG_REG(PARSER_SUB_END_PTR);
+ parser_sub_rp = READ_MPEG_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_MPEG_REG(RESET1_REGISTER, RESET_PARSER);
+
+ /* TS data path */
+#ifndef CONFIG_AM_DVB
+ WRITE_MPEG_REG(FEC_INPUT_CONTROL, 0);
+#else
+ tsdemux_set_reset_flag();
+#endif
+ CLEAR_MPEG_REG_MASK(TS_HIU_CTL, 1 << USE_HI_BSF_INTERFACE);
+ CLEAR_MPEG_REG_MASK(TS_HIU_CTL_2, 1 << USE_HI_BSF_INTERFACE);
+ CLEAR_MPEG_REG_MASK(TS_HIU_CTL_3, 1 << USE_HI_BSF_INTERFACE);
+
+ CLEAR_MPEG_REG_MASK(TS_FILE_CONFIG, (1 << TS_HIU_ENABLE));
+
+ WRITE_MPEG_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_MPEG_REG(PFIFO_RD_PTR, 0);
+ WRITE_MPEG_REG(PFIFO_WR_PTR, 0);
+
+ WRITE_MPEG_REG(PARSER_SEARCH_PATTERN, ES_START_CODE_PATTERN);
+ WRITE_MPEG_REG(PARSER_SEARCH_MASK, ES_START_CODE_MASK);
+
+ WRITE_MPEG_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_MPEG_REG(PARSER_CONTROL, PARSER_AUTOSEARCH);
+
+ }
+ /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
+ /* hook stream buffer with PARSER */
+ if (has_hevc_vdec() && (pts_type == PTS_TYPE_HEVC)) {
+ WRITE_MPEG_REG(PARSER_VIDEO_START_PTR, vdec->input.start);
+ WRITE_MPEG_REG(PARSER_VIDEO_END_PTR, vdec->input.start
+ + vdec->input.size - 8);
+
+ if (vdec_single(vdec)) {
+ CLEAR_MPEG_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_MPEG_REG_MASK(PARSER_ES_CONTROL,
+ ES_VID_MAN_RD_PTR);
+ WRITE_MPEG_REG(PARSER_VIDEO_WP, vdec->input.start);
+ WRITE_MPEG_REG(PARSER_VIDEO_RP, vdec->input.start);
+ }
+ video_data_parsed = 0;
+ } else if (pts_type == PTS_TYPE_VIDEO) {
+ WRITE_MPEG_REG(PARSER_VIDEO_START_PTR,
+ vdec->input.start);
+ WRITE_MPEG_REG(PARSER_VIDEO_END_PTR,
+ vdec->input.start + vdec->input.size - 8);
+ if (vdec_single(vdec)) {
+ CLEAR_MPEG_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_MPEG_REG_MASK(PARSER_ES_CONTROL,
+ ES_VID_MAN_RD_PTR);
+ WRITE_MPEG_REG(PARSER_VIDEO_WP,
+ vdec->input.start);
+ WRITE_MPEG_REG(PARSER_VIDEO_RP,
+ vdec->input.start);
+ }
+ video_data_parsed = 0;
+ } else if (pts_type == PTS_TYPE_AUDIO) {
+ /* set wp as buffer start */
+ SET_MPEG_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL,
+ MEM_BUFCTRL_MANUAL);
+ WRITE_MPEG_REG(AIU_MEM_AIFIFO_MAN_RP,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_MPEG_REG_BITS(AIU_MEM_AIFIFO_CONTROL, 7, 3, 3);
+ SET_MPEG_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL,
+ MEM_BUFCTRL_INIT);
+ CLEAR_MPEG_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL,
+ MEM_BUFCTRL_INIT);
+ WRITE_MPEG_REG(AIU_MEM_AIFIFO_MAN_WP,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_START_PTR));
+ audio_data_parsed = 0;
+ audio_buf_start =
+ READ_MPEG_REG(AIU_MEM_AIFIFO_START_PTR);
+ audio_real_wp = audio_buf_start;
+ audio_buf_end = READ_MPEG_REG(AIU_MEM_AIFIFO_END_PTR);
+ } else if (buf->type == BUF_TYPE_SUBTITLE) {
+ WRITE_MPEG_REG(PARSER_SUB_START_PTR,
+ parser_sub_start_ptr);
+ WRITE_MPEG_REG(PARSER_SUB_END_PTR,
+ parser_sub_end_ptr);
+ WRITE_MPEG_REG(PARSER_SUB_RP, parser_sub_rp);
+ SET_MPEG_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;
+ }
+
+ WRITE_MPEG_REG(PARSER_INT_STATUS, 0xffff);
+ WRITE_MPEG_REG(PARSER_INT_ENABLE,
+ PARSER_INTSTAT_SC_FOUND <<
+ PARSER_INT_HOST_EN_BIT);
+ }
+ mutex_unlock(&esparser_mutex);
+ if (!(amports_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;
+}
+
+void esparser_audio_reset_s(struct stream_buf_s *buf)
+{
+ ulong flags;
+ DEFINE_SPINLOCK(lock);
+
+ spin_lock_irqsave(&lock, flags);
+
+ SET_MPEG_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_MANUAL);
+ WRITE_MPEG_REG(AIU_MEM_AIFIFO_MAN_RP,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_MPEG_REG_BITS(AIU_MEM_AIFIFO_CONTROL, 7, 3, 3);
+ SET_MPEG_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ CLEAR_MPEG_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ WRITE_MPEG_REG(AIU_MEM_AIFIFO_MAN_WP,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_START_PTR));
+
+ buf->flag |= BUF_FLAG_PARSER;
+
+ audio_data_parsed = 0;
+ audio_real_wp = READ_MPEG_REG(AIU_MEM_AIFIFO_START_PTR);
+ spin_unlock_irqrestore(&lock, flags);
+
+}
+
+void esparser_audio_reset(struct stream_buf_s *buf)
+{
+ ulong flags;
+ DEFINE_SPINLOCK(lock);
+
+ spin_lock_irqsave(&lock, flags);
+
+ WRITE_MPEG_REG(PARSER_AUDIO_WP,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_MPEG_REG(PARSER_AUDIO_RP,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_START_PTR));
+
+ WRITE_MPEG_REG(PARSER_AUDIO_START_PTR,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_MPEG_REG(PARSER_AUDIO_END_PTR,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_END_PTR));
+ CLEAR_MPEG_REG_MASK(PARSER_ES_CONTROL, ES_AUD_MAN_RD_PTR);
+
+ WRITE_MPEG_REG(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ CLEAR_MPEG_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_MPEG_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);
+}
+
+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 re_count = count;
+ u32 havewritebytes = 0;
+ u32 leftcount = 0;
+
+ struct drm_info tmpmm;
+ struct drm_info *drm = &tmpmm;
+ u32 res = 0;
+ int isphybuf = 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)) {
+ /* buf only has drminfo not have esdata; */
+ realbuf = drm->drm_phy;
+ realcount = drm->drm_pktsize;
+ isphybuf = 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; */
+ realcount = drm->drm_pktsize;
+ realbuf = (unsigned long)buf + sizeof(struct drm_info);
+ isphybuf = 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;
+ isphybuf = 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;
+
+ while (len > 0) {
+ if (stbuf->type != BUF_TYPE_SUBTITLE
+ && stbuf_space(stbuf) < count) {
+ len = min(stbuf_canusesize(stbuf) / 8, len);
+ if (stbuf_space(stbuf) < len) {
+ r = stbuf_wait_space(stbuf, len);
+ /* write part data , not allow return ; */
+ if ((r < leftcount) && (leftcount > 0))
+ continue;
+ else if ((r < 0) && (leftcount == 0))/*full; */
+ 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->type, isphybuf);
+ else
+ r = _esparser_write_s((const char __user *)realbuf, len,
+ stbuf->type);
+ if (r < 0) {
+ pr_info("drm_write _esparser_write failed [%d]\n", r);
+ 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);
+ }
+
+ return re_count;
+}
+/*
+*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 (stbuf->type == BUF_TYPE_AUDIO)
+ r = _esparser_write_s(buf, len, stbuf->type);
+ else
+ r = _esparser_write(buf, len, stbuf->type, 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);
+}
+
+
+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_MPEG_REG(PARSER_SUB_START_PTR);
+ parser_sub_end_ptr = READ_MPEG_REG(PARSER_SUB_END_PTR);
+
+ WRITE_MPEG_REG(PARSER_SUB_START_PTR, parser_sub_start_ptr);
+ WRITE_MPEG_REG(PARSER_SUB_END_PTR, parser_sub_end_ptr);
+ WRITE_MPEG_REG(PARSER_SUB_RP, parser_sub_start_ptr);
+ WRITE_MPEG_REG(PARSER_SUB_WP, parser_sub_start_ptr);
+ SET_MPEG_REG_MASK(PARSER_ES_CONTROL,
+ (7 << ES_SUB_WR_ENDIAN_BIT) | ES_SUB_MAN_RD_PTR);
+
+ spin_unlock_irqrestore(&lock, flags);
+}
diff --git a/drivers/stream_input/parser/esparser.h b/drivers/stream_input/parser/esparser.h
new file mode 100644
index 0000000..62396a2
--- a/dev/null
+++ b/drivers/stream_input/parser/esparser.h
@@ -0,0 +1,149 @@
+/*
+ * 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/psparser.c b/drivers/stream_input/parser/psparser.c
new file mode 100644
index 0000000..5c8a8b1
--- a/dev/null
+++ b/drivers/stream_input/parser/psparser.c
@@ -0,0 +1,1160 @@
+/*
+ * 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 "streambuf_reg.h"
+#include "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_MPEG_REG(PFIFO_DATA)
+#define SET_BLOCK(size) \
+WRITE_MPEG_REG_BITS(PARSER_CONTROL, size, ES_PACK_SIZE_BIT, ES_PACK_SIZE_WID)
+#define SET_DISCARD_SIZE(size) WRITE_MPEG_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 first_apts, first_vpts;
+static unsigned 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_MPEG_REG
+ (PARSER_PARAMETER,
+ 16 <<
+ PARSER_PARAMETER_LENGTH_BIT);
+ WRITE_MPEG_REG
+ (PARSER_INSERT_DATA,
+ SUB_INSERT_START_CODE_HIGH);
+ WRITE_MPEG_REG
+ (PARSER_INSERT_DATA,
+ SUB_INSERT_START_CODE_LOW |
+ get_sub_type());
+ WRITE_MPEG_REG
+ (PARSER_INSERT_DATA,
+ packet_len);
+ WRITE_MPEG_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;
+ }
+
+ if (!packet_len)
+ return SEARCH_START_CODE;
+
+ else {
+ SET_BLOCK(packet_len);
+ audio_data_parsed += packet_len;
+ return SEND_AUDIO_SEARCH;
+ }
+ }
+
+ return SEARCH_START_CODE;
+}
+
+static void on_start_code_found(int start_code)
+{
+ unsigned short packet_len;
+ unsigned short temp;
+ unsigned next_action;
+#if SAVE_SCR
+ unsigned 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_MPEG_REG(PARSER_CONTROL, PARSER_AUTOSEARCH);
+ break;
+
+ case SEND_VIDEO_SEARCH:
+ WRITE_MPEG_REG_BITS(PARSER_CONTROL,
+ PARSER_AUTOSEARCH | PARSER_VIDEO |
+ PARSER_WRITE, ES_CTRL_BIT, ES_CTRL_WID);
+ break;
+
+ case SEND_AUDIO_SEARCH:
+ WRITE_MPEG_REG_BITS(PARSER_CONTROL,
+ PARSER_AUTOSEARCH | PARSER_AUDIO |
+ PARSER_WRITE, ES_CTRL_BIT, ES_CTRL_WID);
+ break;
+
+ case SEND_SUBPIC_SEARCH:
+ WRITE_MPEG_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_MPEG_REG_BITS(PARSER_CONTROL,
+ PARSER_AUTOSEARCH | PARSER_DISCARD,
+ ES_CTRL_BIT, ES_CTRL_WID);
+ break;
+
+ case DISCARD_ONLY:
+ WRITE_MPEG_REG_BITS(PARSER_CONTROL,
+ PARSER_DISCARD, ES_CTRL_BIT, ES_CTRL_WID);
+ break;
+
+#ifdef VIDEO_AUTO_FLUSH
+ case SEARCH_START_CODE_VIDEO_FLUSH:
+ WRITE_MPEG_REG(PARSER_INSERT_DATA, 0xffffffff);
+ WRITE_MPEG_REG(PARSER_INSERT_DATA, 0xffffffff);
+ WRITE_MPEG_REG(PARSER_PARAMETER,
+ ((VIDEO_AUTO_FLUSH_BYTE_COUNT /
+ 8) << PARSER_PARAMETER_LOOP_BIT) | (8 <<
+ PARSER_PARAMETER_LENGTH_BIT));
+ WRITE_MPEG_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_MPEG_REG(PARSER_INT_STATUS);
+
+ WRITE_MPEG_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_MPEG_REG(PARSER_FETCH_ADDR, dma_addr);
+
+ WRITE_MPEG_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_MPEG_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_MPEG_REG(PARSER_SUB_START_PTR);
+ parser_sub_end_ptr = READ_MPEG_REG(PARSER_SUB_END_PTR);
+ parser_sub_rp = READ_MPEG_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_MPEG_REG(RESET1_REGISTER, RESET_PARSER);
+
+ /* TS data path */
+#ifndef CONFIG_AM_DVB
+ WRITE_MPEG_REG(FEC_INPUT_CONTROL, 0);
+#else
+ tsdemux_set_reset_flag();
+#endif
+ CLEAR_MPEG_REG_MASK(TS_HIU_CTL, 1 << USE_HI_BSF_INTERFACE);
+ CLEAR_MPEG_REG_MASK(TS_HIU_CTL_2, 1 << USE_HI_BSF_INTERFACE);
+ CLEAR_MPEG_REG_MASK(TS_HIU_CTL_3, 1 << USE_HI_BSF_INTERFACE);
+ CLEAR_MPEG_REG_MASK(TS_FILE_CONFIG, (1 << TS_HIU_ENABLE));
+
+ /* hook stream buffer with PARSER */
+ WRITE_MPEG_REG(PARSER_VIDEO_START_PTR, vdec->input.start);
+ WRITE_MPEG_REG(PARSER_VIDEO_END_PTR,
+ vdec->input.start + vdec->input.size - 8);
+
+ if (vdec_single(vdec)) {
+ CLEAR_MPEG_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_MPEG_REG_MASK(PARSER_ES_CONTROL, ES_VID_MAN_RD_PTR);
+ WRITE_MPEG_REG(PARSER_VIDEO_WP, vdec->input.start);
+ WRITE_MPEG_REG(PARSER_VIDEO_RP, vdec->input.start);
+ }
+
+ WRITE_MPEG_REG(PARSER_AUDIO_START_PTR,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_MPEG_REG(PARSER_AUDIO_END_PTR,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_END_PTR));
+ CLEAR_MPEG_REG_MASK(PARSER_ES_CONTROL, ES_AUD_MAN_RD_PTR);
+
+ WRITE_MPEG_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_MPEG_REG(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ CLEAR_MPEG_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+
+ WRITE_MPEG_REG(PARSER_SUB_START_PTR, parser_sub_start_ptr);
+ WRITE_MPEG_REG(PARSER_SUB_END_PTR, parser_sub_end_ptr);
+ WRITE_MPEG_REG(PARSER_SUB_RP, parser_sub_start_ptr);
+ WRITE_MPEG_REG(PARSER_SUB_WP, parser_sub_start_ptr);
+ SET_MPEG_REG_MASK(PARSER_ES_CONTROL,
+ (7 << ES_SUB_WR_ENDIAN_BIT) | ES_SUB_MAN_RD_PTR);
+
+ WRITE_MPEG_REG(PFIFO_RD_PTR, 0);
+ WRITE_MPEG_REG(PFIFO_WR_PTR, 0);
+
+ WRITE_MPEG_REG(PARSER_SEARCH_PATTERN, MPEG_START_CODE_PATTERN);
+ WRITE_MPEG_REG(PARSER_SEARCH_MASK, MPEG_START_CODE_MASK);
+
+ WRITE_MPEG_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_MPEG_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_MPEG_REG(PARSER_INT_STATUS, 0xffff);
+ WRITE_MPEG_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_MPEG_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
+}
+
+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_MPEG_REG(PARSER_AUDIO_WP,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_MPEG_REG(PARSER_AUDIO_RP,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_START_PTR));
+
+ WRITE_MPEG_REG(PARSER_AUDIO_START_PTR,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_MPEG_REG(PARSER_AUDIO_END_PTR,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_END_PTR));
+ CLEAR_MPEG_REG_MASK(PARSER_ES_CONTROL, ES_AUD_MAN_RD_PTR);
+
+ WRITE_MPEG_REG(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ CLEAR_MPEG_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_MPEG_REG(PARSER_SUB_START_PTR);
+ parser_sub_end_ptr = READ_MPEG_REG(PARSER_SUB_END_PTR);
+
+ WRITE_MPEG_REG(PARSER_SUB_START_PTR, parser_sub_start_ptr);
+ WRITE_MPEG_REG(PARSER_SUB_END_PTR, parser_sub_end_ptr);
+ WRITE_MPEG_REG(PARSER_SUB_RP, parser_sub_start_ptr);
+ WRITE_MPEG_REG(PARSER_SUB_WP, parser_sub_start_ptr);
+ SET_MPEG_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
+}
diff --git a/drivers/stream_input/parser/psparser.h b/drivers/stream_input/parser/psparser.h
new file mode 100644
index 0000000..1280b6a
--- a/dev/null
+++ b/drivers/stream_input/parser/psparser.h
@@ -0,0 +1,141 @@
+/*
+ * 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..63d7a63
--- a/dev/null
+++ b/drivers/stream_input/parser/rmparser.c
@@ -0,0 +1,337 @@
+/*
+ * 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 "streambuf.h"
+#include "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_MPEG_REG(PARSER_INT_STATUS);
+
+ if (int_status & PARSER_INTSTAT_FETCH_CMD) {
+ WRITE_MPEG_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_MPEG_REG(RESET1_REGISTER, RESET_PARSER);
+
+ /* TS data path */
+#ifndef CONFIG_AM_DVB
+ WRITE_MPEG_REG(FEC_INPUT_CONTROL, 0);
+#else
+ tsdemux_set_reset_flag();
+#endif
+ CLEAR_MPEG_REG_MASK(TS_HIU_CTL, 1 << USE_HI_BSF_INTERFACE);
+ CLEAR_MPEG_REG_MASK(TS_HIU_CTL_2, 1 << USE_HI_BSF_INTERFACE);
+ CLEAR_MPEG_REG_MASK(TS_HIU_CTL_3, 1 << USE_HI_BSF_INTERFACE);
+
+ CLEAR_MPEG_REG_MASK(TS_FILE_CONFIG, (1 << TS_HIU_ENABLE));
+
+ /* hook stream buffer with PARSER */
+ WRITE_MPEG_REG(PARSER_VIDEO_START_PTR, vdec->input.start);
+ WRITE_MPEG_REG(PARSER_VIDEO_END_PTR,
+ vdec->input.start + vdec->input.size - 8);
+
+ CLEAR_MPEG_REG_MASK(PARSER_ES_CONTROL, ES_VID_MAN_RD_PTR);
+
+ WRITE_MPEG_REG(PARSER_AUDIO_START_PTR,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_MPEG_REG(PARSER_AUDIO_END_PTR,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_END_PTR));
+ CLEAR_MPEG_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_MPEG_REG(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ CLEAR_MPEG_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+
+ WRITE_MPEG_REG(PFIFO_RD_PTR, 0);
+ WRITE_MPEG_REG(PFIFO_WR_PTR, 0);
+
+ WRITE_MPEG_REG(PARSER_SEARCH_MASK, 0);
+ WRITE_MPEG_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_MPEG_REG(PARSER_INT_STATUS, 0xffff);
+ WRITE_MPEG_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_MPEG_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
+
+ return;
+}
+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_MPEG_REG(AIU_MEM_AIFIFO_MAN_WP) :
+ READ_MPEG_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_MPEG_REG(PARSER_FETCH_ADDR, dma_addr);
+
+ WRITE_MPEG_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_MPEG_REG(PARSER_FETCH_CMD, 0);
+ parse_halt++;
+ pr_info
+ ("write timeout,retry,halt_count=%d parse_control=%x\n",
+ parse_halt, READ_MPEG_REG(PARSER_CONTROL));
+
+ //vreal_set_fatal_flag(1);//DEBUG_TMP
+
+ if (parse_halt > 10) {
+ WRITE_MPEG_REG(PARSER_CONTROL,
+ (ES_SEARCH | ES_PARSER_START));
+ pr_info("reset parse_control=%x\n",
+ READ_MPEG_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_MPEG_REG(PARSER_CONTROL,
+ (ES_SEARCH | ES_PARSER_START));
+ pr_info("reset parse_control=%x\n",
+ READ_MPEG_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);
+}
+EXPORT_SYMBOL(rmparser_write);
+
+void rm_set_vasid(u32 vid, u32 aid)
+{
+ pr_info("rm_set_vasid aid %d, vid %d\n", aid, vid);
+ WRITE_MPEG_REG(VAS_STREAM_ID, (aid << 8) | vid);
+
+ return;
+}
+EXPORT_SYMBOL(rm_set_vasid);
+
+void rm_audio_reset(void)
+{
+ ulong flags;
+ DEFINE_SPINLOCK(lock);
+
+ spin_lock_irqsave(&lock, flags);
+
+ WRITE_MPEG_REG(PARSER_AUDIO_WP,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_MPEG_REG(PARSER_AUDIO_RP,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_START_PTR));
+
+ WRITE_MPEG_REG(PARSER_AUDIO_START_PTR,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_MPEG_REG(PARSER_AUDIO_END_PTR,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_END_PTR));
+ CLEAR_MPEG_REG_MASK(PARSER_ES_CONTROL, ES_AUD_MAN_RD_PTR);
+
+ WRITE_MPEG_REG(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ CLEAR_MPEG_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+
+ spin_unlock_irqrestore(&lock, flags);
+
+ return;
+}
+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..5d258ee
--- a/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/streambuf.c b/drivers/stream_input/parser/streambuf.c
new file mode 100644
index 0000000..8b9aa33
--- a/dev/null
+++ b/drivers/stream_input/parser/streambuf.c
@@ -0,0 +1,418 @@
+/*
+ * 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.
+ *
+*/
+
+#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;
+
+static s32 _stbuf_alloc(struct stream_buf_s *buf)
+{
+ 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;
+ }
+
+ 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;
+ }
+ pr_info("%s stbuf alloced at %p, 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->buf_size);
+ }
+ if (buf->buf_size < buf->canusebuf_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)
+{
+ unsigned long old_buf;
+ int old_size, old_pagenum;
+ int ret;
+
+ pr_info("buffersize=%d,%d,start=%p\n", size, buf->buf_size,
+ (void *)buf->buf_start);
+
+ 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) == 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);
+
+ pr_info("changed the (%d) buffer size from %d to %d\n",
+ buf->type, old_size, size);
+ return 0;
+ }
+ /* 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;
+}
+
+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 (READ_MPEG_REG(PARSER_ES_CONTROL) & 1) {
+ int level = READ_MPEG_REG(PARSER_VIDEO_WP) -
+ READ_MPEG_REG(PARSER_VIDEO_RP);
+ if (level < 0)
+ level += READ_MPEG_REG(PARSER_VIDEO_END_PTR) -
+ READ_MPEG_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 (READ_MPEG_REG(PARSER_ES_CONTROL) & 1)
+ return READ_MPEG_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->type == BUF_TYPE_VIDEO)
+ || (has_hevc_vdec() && buf->type == BUF_TYPE_HEVC))
+ size -= READ_MPEG_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;
+
+ if (!buf->buf_start) {
+ r = _stbuf_alloc(buf);
+ if (r < 0)
+ return r;
+ }
+ addr32 = buf->buf_start & 0xffffffff;
+ init_waitqueue_head(&buf->wq);
+
+ if ((buf->type == BUF_TYPE_VIDEO) || (buf->type == BUF_TYPE_HEVC)) {
+ if (vdec) {
+ if (vdec_stream_based(vdec))
+ vdec_input_set_buffer(&vdec->input, addr32,
+ buf->buf_size);
+ else
+ return vdec_input_set_buffer(&vdec->input,
+ addr32, buf->buf_size);
+ }
+ }
+
+ buf->write_thread = 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) {
+ _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_MPEG_REG(RESET0_REGISTER, RESET_VLD);
+#endif
+
+ dummy = READ_MPEG_REG(RESET0_REGISTER);
+ WRITE_VREG(POWER_CTL_VLD, 1 << 4);
+ } else if (buf->type == BUF_TYPE_AUDIO) {
+ _WRITE_ST_REG(CONTROL, 0);
+
+ WRITE_MPEG_REG(AIU_AIFIFO_GBIT, 0x80);
+ }
+
+ if (buf->type == BUF_TYPE_SUBTITLE) {
+ WRITE_MPEG_REG(PARSER_SUB_RP, addr32);
+ WRITE_MPEG_REG(PARSER_SUB_START_PTR, addr32);
+ WRITE_MPEG_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);
+ return 0;
+}
+
+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 = 20;
+
+ 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, 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)
+{
+ buf->first_tstamp = INVALID_PTS;
+
+ stbuf_init(buf, NULL); /* reinit buffer */
+
+ 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->flag &= ~BUF_FLAG_IN_USE;
+}
+
+u32 stbuf_sub_rp_get(void)
+{
+ return READ_MPEG_REG(PARSER_SUB_RP);
+}
+
+void stbuf_sub_rp_set(unsigned int sub_rp)
+{
+ WRITE_MPEG_REG(PARSER_SUB_RP, sub_rp);
+}
+
+u32 stbuf_sub_wp_get(void)
+{
+ return READ_MPEG_REG(PARSER_SUB_WP);
+}
+
+u32 stbuf_sub_start_get(void)
+{
+ return READ_MPEG_REG(PARSER_SUB_START_PTR);
+}
diff --git a/drivers/stream_input/parser/streambuf.h b/drivers/stream_input/parser/streambuf.h
new file mode 100644
index 0000000..cdae0a8
--- a/dev/null
+++ b/drivers/stream_input/parser/streambuf.h
@@ -0,0 +1,136 @@
+/*
+ * 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)
+
+struct vdec_s;
+
+struct stream_buf_s {
+ 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;
+} /*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;
+} /*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 extpad[8];
+} /*drminfo_t */;
+
+#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);
+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);
+
+#endif /* STREAMBUF_H */
diff --git a/drivers/stream_input/parser/streambuf_reg.h b/drivers/stream_input/parser/streambuf_reg.h
new file mode 100644
index 0000000..f00c705
--- a/dev/null
+++ b/drivers/stream_input/parser/streambuf_reg.h
@@ -0,0 +1,111 @@
+/*
+ * 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_cbus_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_cbus_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/parser/thread_rw.c b/drivers/stream_input/parser/thread_rw.c
new file mode 100644
index 0000000..deeaf19
--- a/dev/null
+++ b/drivers/stream_input/parser/thread_rw.c
@@ -0,0 +1,606 @@
+/*
+ * 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 "../../stream_input/parser/streambuf.h"
+#include "../../stream_input/amports/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 left = count;
+ int wait_num = 0;
+ unsigned long flags;
+
+ while (left > 0) {
+ ret = threadrw_write_onece(task,
+ task->file,
+ stbuf, buf + off, left);
+ if (ret >= left) {
+ off = count;
+ left = 0;
+ } else if (ret > 0) {
+ off += ret;
+ left -= ret;
+
+ } else 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 */
+ }
+ }
+
+ /*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;
+ task->buffered_data_size -= 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;
+*/
+
+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/parser/thread_rw.h b/drivers/stream_input/parser/thread_rw.h
new file mode 100644
index 0000000..f03a6e6
--- a/dev/null
+++ b/drivers/stream_input/parser/thread_rw.h
@@ -0,0 +1,52 @@
+/*
+ * 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/parser/streambuf_reg.h"
+#include "../../stream_input/parser/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);
+
+#endif
diff --git a/drivers/stream_input/parser/tsdemux.c b/drivers/stream_input/parser/tsdemux.c
new file mode 100644
index 0000000..ba9a590
--- a/dev/null
+++ b/drivers/stream_input/parser/tsdemux.c
@@ -0,0 +1,1131 @@
+/*
+ * 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/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 "streambuf_reg.h"
+#include "streambuf.h"
+#include <linux/amlogic/media/utils/amports_config.h>
+
+#include "tsdemux.h"
+#include <linux/reset.h>
+#include "../amports/amports_priv.h"
+
+
+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 int demux_skipbyte;
+
+static struct tsdemux_ops *demux_ops;
+static DEFINE_SPINLOCK(demux_ops_lock);
+
+static int enable_demux_driver(void)
+{
+#ifdef ENABLE_DEMUX_DRIVER
+ return demux_ops ? 1 : 0;
+#else
+ return 0;
+#endif
+}
+
+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;
+
+ 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;
+
+ 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;
+
+ 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;
+}
+
+/*TODO irq*/
+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_MPEG_REG(STB_INT_STATUS);
+ } else {
+ if (id == 0)
+ int_status = READ_MPEG_REG(STB_INT_STATUS);
+ else if (id == 1)
+ int_status = READ_MPEG_REG(STB_INT_STATUS_2);
+ else if (id == 2)
+ int_status = READ_MPEG_REG(STB_INT_STATUS_3);
+ }
+
+ if (int_status & (1 << NEW_PDTS_READY)) {
+ if (!enable_demux_driver()) {
+ u32 pdts_status = READ_MPEG_REG(STB_PTS_DTS_STATUS);
+
+ if (pdts_status & (1 << VIDEO_PTS_READY))
+ pts_checkin_wrptr(PTS_TYPE_VIDEO,
+ READ_MPEG_REG(VIDEO_PDTS_WR_PTR),
+ READ_MPEG_REG(VIDEO_PTS_DEMUX));
+
+ if (pdts_status & (1 << AUDIO_PTS_READY))
+ pts_checkin_wrptr(PTS_TYPE_AUDIO,
+ READ_MPEG_REG(AUDIO_PDTS_WR_PTR),
+ READ_MPEG_REG(AUDIO_PTS_DEMUX));
+
+ WRITE_MPEG_REG(STB_PTS_DTS_STATUS, pdts_status);
+ } else {
+#define DMX_READ_REG(i, r)\
+ ((i) ? ((i == 1) ? READ_MPEG_REG(r##_2) : \
+ READ_MPEG_REG(r##_3)) : READ_MPEG_REG(r))
+
+ u32 pdts_status = DMX_READ_REG(id, STB_PTS_DTS_STATUS);
+
+ if (pdts_status & (1 << VIDEO_PTS_READY))
+ pts_checkin_wrptr(PTS_TYPE_VIDEO,
+ DMX_READ_REG(id, VIDEO_PDTS_WR_PTR),
+ DMX_READ_REG(id, VIDEO_PTS_DEMUX));
+
+ 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_MPEG_REG(STB_PTS_DTS_STATUS_2,
+ pdts_status);
+ else if (id == 2)
+ WRITE_MPEG_REG(STB_PTS_DTS_STATUS_3,
+ pdts_status);
+ else
+ WRITE_MPEG_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 (!enable_demux_driver())
+ WRITE_MPEG_REG(STB_INT_STATUS, int_status);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t parser_isr(int irq, void *dev_id)
+{
+ u32 int_status = READ_MPEG_REG(PARSER_INT_STATUS);
+
+ WRITE_MPEG_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_MPEG_REG(PARSER_FETCH_ADDR, buf_32);
+ } else {
+ WRITE_MPEG_REG(PARSER_FETCH_ADDR, dma_addr);
+ dma_unmap_single(amports_get_dma_device(), dma_addr,
+ FETCHBUF_SIZE, DMA_TO_DEVICE);
+ }
+
+ WRITE_MPEG_REG(PARSER_FETCH_CMD, (7 << FETCH_ENDIAN) | len);
+
+
+ ret =
+ wait_event_interruptible_timeout(wq, fetch_done != 0,
+ HZ / 2);
+ if (ret == 0) {
+ WRITE_MPEG_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;
+}
+
+static int reset_pcr_regs(void)
+{
+ u32 pcr_num;
+
+ if (curr_pcr_id >= 0x1FFF)
+ return 0;
+
+ /* set parameter 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_sys("clk81", "clk81");
+ 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 / 80000;
+
+ pr_info("[%s:%d] clk_81 = %x clk_unit =%x\n", __func__,
+ __LINE__, clk_81, clk_unit);
+
+ if (READ_MPEG_REG(TS_HIU_CTL_2) & 0x80) {
+ WRITE_MPEG_REG(PCR90K_CTL_2, (12 << 1) | clk_unit);
+ WRITE_MPEG_REG(ASSIGN_PID_NUMBER_2, pcr_num);
+ pr_info("[tsdemux_init] To use device 2,pcr_num=%d\n",
+ pcr_num);
+ } else if (READ_MPEG_REG(TS_HIU_CTL_3) & 0x80) {
+ WRITE_MPEG_REG(PCR90K_CTL_3, (12 << 1) | clk_unit);
+ WRITE_MPEG_REG(ASSIGN_PID_NUMBER_3, pcr_num);
+ pr_info("[tsdemux_init] To use device 3,pcr_num=%d\n",
+ pcr_num);
+ } else {
+ WRITE_MPEG_REG(PCR90K_CTL, (12 << 1) | clk_unit);
+ WRITE_MPEG_REG(ASSIGN_PID_NUMBER, pcr_num);
+ pr_info("[tsdemux_init] To use device 1,pcr_num=%d\n",
+ pcr_num);
+ }
+
+ 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;
+
+ /* #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_MPEG_REG(PARSER_SUB_START_PTR);
+ parser_sub_end_ptr = READ_MPEG_REG(PARSER_SUB_END_PTR);
+ parser_sub_rp = READ_MPEG_REG(PARSER_SUB_RP);
+
+ WRITE_MPEG_REG(RESET1_REGISTER, RESET_PARSER);
+
+ if (enable_demux_driver()) {
+ tsdemux_reset();
+ } else {
+ WRITE_MPEG_REG(RESET1_REGISTER, RESET_PARSER | RESET_DEMUXSTB);
+
+ WRITE_MPEG_REG(STB_TOP_CONFIG, 0);
+ WRITE_MPEG_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_MPEG_REG(FM_WR_DATA,
+ (((vid < 0x1fff)
+ ? (vid & 0x1fff) | (VIDEO_PACKET << 13)
+ : 0xffff) << 16)
+ | ((aid < 0x1fff)
+ ? (aid & 0x1fff) | (AUDIO_PACKET << 13)
+ : 0xffff));
+ WRITE_MPEG_REG(FM_WR_ADDR, 0x8000);
+ while (READ_MPEG_REG(FM_WR_ADDR) & 0x8000)
+ ;
+
+ WRITE_MPEG_REG(FM_WR_DATA,
+ (((sid < 0x1fff)
+ ? (sid & 0x1fff) | (SUB_PACKET << 13)
+ : 0xffff) << 16)
+ | 0xffff);
+ WRITE_MPEG_REG(FM_WR_ADDR, 0x8001);
+ while (READ_MPEG_REG(FM_WR_ADDR) & 0x8000)
+ ;
+
+ WRITE_MPEG_REG(MAX_FM_COMP_ADDR, 1);
+
+ WRITE_MPEG_REG(STB_INT_MASK, 0);
+ WRITE_MPEG_REG(STB_INT_STATUS, 0xffff);
+
+ /* TS data path */
+ WRITE_MPEG_REG(FEC_INPUT_CONTROL, 0x7000);
+ WRITE_MPEG_REG(DEMUX_MEM_REQ_EN,
+ (1 << VIDEO_PACKET) |
+ (1 << AUDIO_PACKET) | (1 << SUB_PACKET));
+ WRITE_MPEG_REG(DEMUX_ENDIAN,
+ (7 << OTHER_ENDIAN) |
+ (7 << BYPASS_ENDIAN) | (0 << SECTION_ENDIAN));
+ WRITE_MPEG_REG(TS_HIU_CTL, 1 << USE_HI_BSF_INTERFACE);
+ WRITE_MPEG_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_MPEG_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_MPEG_REG(PARSER_VIDEO_START_PTR, vdec->input.start);
+ WRITE_MPEG_REG(PARSER_VIDEO_END_PTR, vdec->input.start +
+ vdec->input.size - 8);
+
+ if (vdec_single(vdec)) {
+ CLEAR_MPEG_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_MPEG_REG_MASK(PARSER_ES_CONTROL, ES_VID_MAN_RD_PTR);
+ WRITE_MPEG_REG(PARSER_VIDEO_WP, vdec->input.start);
+ WRITE_MPEG_REG(PARSER_VIDEO_RP, vdec->input.start);
+ }
+ } else
+ /* #endif */
+ {
+ WRITE_MPEG_REG(PARSER_VIDEO_START_PTR, vdec->input.start);
+ WRITE_MPEG_REG(PARSER_VIDEO_END_PTR, vdec->input.start +
+ vdec->input.size - 8);
+
+ if (vdec_single(vdec)) {
+ CLEAR_MPEG_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_MPEG_REG_MASK(PARSER_ES_CONTROL, ES_VID_MAN_RD_PTR);
+ WRITE_MPEG_REG(PARSER_VIDEO_WP, vdec->input.start);
+ WRITE_MPEG_REG(PARSER_VIDEO_RP, vdec->input.start);
+ }
+ }
+
+ WRITE_MPEG_REG(PARSER_AUDIO_START_PTR,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_MPEG_REG(PARSER_AUDIO_END_PTR,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_END_PTR));
+ CLEAR_MPEG_REG_MASK(PARSER_ES_CONTROL, ES_AUD_MAN_RD_PTR);
+
+ WRITE_MPEG_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_MPEG_REG(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ CLEAR_MPEG_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+
+ WRITE_MPEG_REG(PARSER_SUB_START_PTR, parser_sub_start_ptr);
+ WRITE_MPEG_REG(PARSER_SUB_END_PTR, parser_sub_end_ptr);
+ WRITE_MPEG_REG(PARSER_SUB_RP, parser_sub_rp);
+ SET_MPEG_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 (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) {
+ pr_info("Video pts start failed.(%d)\n", r);
+ goto err1;
+ }
+ r = pts_start(PTS_TYPE_AUDIO);
+ if (r < 0) {
+ 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_MPEG_REG(PARSER_INT_STATUS, 0xffff);
+ WRITE_MPEG_REG(PARSER_INT_ENABLE,
+ PARSER_INTSTAT_FETCH_CMD << PARSER_INT_HOST_EN_BIT);
+
+ WRITE_MPEG_REG(PARSER_VIDEO_HOLE, 0x400);
+ WRITE_MPEG_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_MPEG_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);
+ }
+ if (aid < 0x1FFF) {
+ curr_aud_id = aid;
+ tsdemux_set_aid(aid);
+ }
+ if (sid < 0x1FFF) {
+ curr_sub_id = sid;
+ tsdemux_set_sid(sid);
+ }
+
+ curr_pcr_id = pcrid;
+ if ((pcrid < 0x1FFF) && (pcrid != vid) && (pcrid != aid)
+ && (pcrid != sid))
+ tsdemux_set_pcrid(pcrid);
+ }
+
+ pcrscr_valid = reset_pcr_regs();
+ 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;
+
+ WRITE_MPEG_REG(PARSER_INT_ENABLE, 0);
+ WRITE_MPEG_REG(PARSER_VIDEO_HOLE, 0);
+ WRITE_MPEG_REG(PARSER_AUDIO_HOLE, 0);
+
+#ifdef CONFIG_MULTI_DEC
+ SET_MPEG_REG_MASK(PARSER_ES_CONTROL, ES_VID_MAN_RD_PTR);
+ WRITE_MPEG_REG(PARSER_VIDEO_WP, 0);
+ WRITE_MPEG_REG(PARSER_VIDEO_RP, 0);
+#endif
+
+ /*TODO irq */
+
+ vdec_free_irq(PARSER_IRQ, (void *)tsdemux_fetch_id);
+
+ if (!enable_demux_driver()) {
+ WRITE_MPEG_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_MPEG_REG(RESET1_REGISTER, RESET_PARSER);
+
+ /* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+ /*TODO clk */
+ /*
+ *switch_mod_gate_by_type(MOD_DEMUX, 0);
+ */
+ /* #endif */
+ amports_switch_gate("demux", 0);
+
+}
+
+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)
+{
+ int write_size;
+
+ 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 re_count = 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; */
+ realcount = drm->drm_pktsize;
+ 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) {
+ 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;
+ }
+ }
+ }
+ }
+
+ write_size = min(stbuf_space(vbuf), stbuf_space(abuf));
+ write_size = min(count, write_size);
+ /* pr_info("write_size = %d,count = %d,\n",*/
+ /*write_size, count); */
+ if (write_size > 0)
+ r = _tsdemux_write((const char __user *)realbuf,
+ write_size, isphybuf);
+ 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\n");
+
+ count -= r;
+ }
+ return re_count;
+}
+
+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;
+}
+
+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_MPEG_REG(FM_WR_DATA,
+ (((vid & 0x1fff) | (VIDEO_PACKET << 13)) << 16)
+ | ((aid & 0x1fff) | (AUDIO_PACKET << 13)));
+ WRITE_MPEG_REG(FM_WR_ADDR, 0x8000);
+ while (READ_MPEG_REG(FM_WR_ADDR) & 0x8000)
+ ;
+ } else {
+ curr_vid_id = vid;
+ curr_aud_id = aid;
+
+ tsdemux_set_vid(vid);
+ tsdemux_set_aid(aid);
+
+ reset_pcr_regs();
+ }
+
+}
+
+void tsdemux_change_sid(unsigned int sid)
+{
+ if (!enable_demux_driver()) {
+ WRITE_MPEG_REG(FM_WR_DATA,
+ (((sid & 0x1fff) | (SUB_PACKET << 13)) << 16)
+ | 0xffff);
+ WRITE_MPEG_REG(FM_WR_ADDR, 0x8001);
+ while (READ_MPEG_REG(FM_WR_ADDR) & 0x8000)
+ ;
+ } else {
+ curr_sub_id = sid;
+
+ tsdemux_set_sid(sid);
+
+ reset_pcr_regs();
+ }
+
+}
+
+void tsdemux_audio_reset(void)
+{
+ ulong flags;
+
+ DEFINE_SPINLOCK(lock);
+
+ spin_lock_irqsave(&lock, flags);
+
+ WRITE_MPEG_REG(PARSER_AUDIO_WP,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_MPEG_REG(PARSER_AUDIO_RP,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_START_PTR));
+
+ WRITE_MPEG_REG(PARSER_AUDIO_START_PTR,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_START_PTR));
+ WRITE_MPEG_REG(PARSER_AUDIO_END_PTR,
+ READ_MPEG_REG(AIU_MEM_AIFIFO_END_PTR));
+ CLEAR_MPEG_REG_MASK(PARSER_ES_CONTROL, ES_AUD_MAN_RD_PTR);
+
+ WRITE_MPEG_REG(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+ CLEAR_MPEG_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
+
+ spin_unlock_irqrestore(&lock, flags);
+
+}
+
+void tsdemux_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_MPEG_REG(PARSER_SUB_START_PTR);
+ parser_sub_end_ptr = READ_MPEG_REG(PARSER_SUB_END_PTR);
+
+ WRITE_MPEG_REG(PARSER_SUB_START_PTR, parser_sub_start_ptr);
+ WRITE_MPEG_REG(PARSER_SUB_END_PTR, parser_sub_end_ptr);
+ WRITE_MPEG_REG(PARSER_SUB_RP, parser_sub_start_ptr);
+ WRITE_MPEG_REG(PARSER_SUB_WP, parser_sub_start_ptr);
+ SET_MPEG_REG_MASK(PARSER_ES_CONTROL,
+ (7 << ES_SUB_WR_ENDIAN_BIT) | ES_SUB_MAN_RD_PTR);
+
+ spin_unlock_irqrestore(&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_MPEG_REG(TS_HIU_CTL_2) & 0x80)
+ pcr = READ_MPEG_REG(PCR_DEMUX_2);
+ else if (READ_MPEG_REG(TS_HIU_CTL_3) & 0x80)
+ pcr = READ_MPEG_REG(PCR_DEMUX_3);
+ else
+ pcr = READ_MPEG_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_MPEG_REG(TS_HIU_CTL_2) & 0x80)
+ pcr = READ_MPEG_REG(PCR_DEMUX_2);
+ else if (READ_MPEG_REG(TS_HIU_CTL_3) & 0x80)
+ pcr = READ_MPEG_REG(PCR_DEMUX_3);
+ else
+ pcr = READ_MPEG_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;
+}
diff --git a/drivers/stream_input/parser/tsdemux.h b/drivers/stream_input/parser/tsdemux.h
new file mode 100644
index 0000000..5e11c44
--- a/dev/null
+++ b/drivers/stream_input/parser/tsdemux.h
@@ -0,0 +1,95 @@
+/*
+ * 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 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 u32 tsdemux_first_pcrscr_get(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);
+#endif /* TSDEMUX_H */
diff --git a/firmware/video_ucode.bin b/firmware/video_ucode.bin
new file mode 100644
index 0000000..e495e37
--- a/dev/null
+++ b/firmware/video_ucode.bin
@@ -0,0 +1,8294 @@
+KCAP
+
+
+
+B<
+
+ 
+?@ 
+
+GL @x
+
+
+Ox 
+Px   Lx
+
+
+
+
+
+) 
+
+ J@
+  J
+. 8 
+
+GI ,
+O
+I@
+I
+
+o
+I@
+=Lʀ
+I
+ bp
+ 
+
+ 
+
+Q R P PC L
+
+@J
+A
+A
+ &
+%
+(
+\
+! p! 
+
+J
+
+
+
+
+LJ
+ 
+a
+A
+
+x J e
+B
+a
+@ x H
+
+
+ H  G
+G@
+`
+ x M`
+
+x
+
+x oG`
+@x @x y
+ QL
+FL @LBLȂ@
+G
+
+
+q@
+
+
+
+
+ 
+ t
+
+
+
+ 
+Iʁ
+
+
+
+
+B@Ȃ
+
+
+
+
+
+
+
+
+G
+
+GI
+I
+d
+
+`
+@x
+$
+
+
+
+@x $@
+W(Ǥ
+*e@-UU 
+ \! @x U@-U 
+¢V
+
+@TeP W| NB 
+EE@
+BV
+@@x AՀe
+& N U
+TeP W| NB 
+U@%$U@x $&)
+bV
+`aV0
+& N U ' $
+
+
+$`
+
+
+
+
+ u V, E
+@
+
+
+B
+@A Ǡ
+
+A 
+ 
+
+@@x
+N N N@
+ 
+
+@ @ II24 A"
+
+ Iɐ ɐ  @ I  
+
+@ I@
+I
+
+K
+K
+<
+`
+ x J
+
+ x Iǀ!
+<
+J
+
+x J
+x J
+G2
+H"
+
+
+2
+x J
+3@
+G4
+
+
+~ $
+H
+!
+
+N,@x
+
+ @x
+
+c
+ x .I,J)
+`
+,@
+I
+,@Ȅ@ -, -
+@Ǡ  A+,-
+
+@
+G
+;H -%
+<
+  I
+
+
+  H
+H@a
+
+
+;I
+
+
+
+
+GǑ@ʡ
+
+GH;ȡ@ʡ
+
+
+G @ @@
+
+G  
+
+G @ @
+
+G  @ 
+I ;
+B
+ J
+J
+
+J9
+@b
+;
+
+
+
+
+!sstG
+@b
+
+GuuG
+
+@b
+
+
+~ 
+
+
+o
+
+
+H
+ $ɀ
+@Ip p  QIs Q #G)!D G)d
+
+P;!
+
+
+
+
+
+
+
+
+
+G," ,@a
+QI
+
+
+Q
+?
+R
+
+
+
+ȼo
+
+@
+G
+ 
+ G#
+#
+ q@) #q s 
+ s s
+ '
+L! o
+!*!
+G) 
+))Wx  @Ix 
+))@%x   x
+G) 
+))Ox  Ax 
+))x  
+G$)
+
+
+$
+@o
+
+
+
+' x   'LI! & ' ( ) ) a '   'LI!      H$ a '   CI #x % > ?L> @
+#LGB0
+@
+@
+*
+
+
+ @o
+I@
+((#LB0 o
+
+ A R K
+(@x GB
+% B
+G
+H
+
+`
+x
+
+
+
+
+S@ & NI HB
+ @
+ N @o
+ @ N @n
+$ m
+
+G$)
+
+'   
+' x   'LI! & ' ) a '   'LI!   H$ a '  #% $
+o
+
+!L"L%'L e! ,a
+*
+$ʀ
+
+
+
+(
+% & & & r ! G%@
+G
+ 
+S&
+]
+
+*
+
+$ @o
+&I@b &@x * H"P ! & % 
+
+
+,
+
+-x B
+
+G
+
+-J
+Fa
+
+
+
++
+
+
+f
+J+J
+  
+
+Q
+?
+R P 
+@ #\ a
+L+L
+  @4
+x ,
+I@ `
+ @ I,D b
+@x
+-J
+
+ +-G%
+!
+
+-J+
+
+x 
+!
+ +
+ @a
+
+x
+ b@ʢ c
+$ "L2@
+
+
+
+ CAL c
+AA K)`
+!
+
+
+@
+ a  $a    '  
+    N,
+?G)á
+,@Ǡ  A+
++?a Ǡ A+PCG
+
+
+
+ߏN LJ
+J2 x 
+@Ȇ
+
+0
+`
+
+
+
+ 1
+ @
+M* @I
+G
+ *,@ 
+ @@
+M* @I
+ *,@ 
+ @
+M* @I
+
+ql
+ @0
+G
+ ,@ 
+ @@0
+ ,@ 
+ @0
+qp
+
+qp
+`
+
+qIq
+
+
+J
+O+
+a `
+z
+
+."@
+o@l
+
+J
+
+O+
+
+a `
+z
+
+."@
+o@l
+
+G@@
+
+
+
+
+
+H
+Hs
+
+
+@r
+
+@
+
+@
+
+x 
+
+@
+x 
+@q~
+ @e # LJ
+
+
+
+
+r
+
+ I
+
+@B # G@H Q
+
+Q
+Q
+
+
+
+
+GG@Q
+@
+ /
+B
+ /
+
+@* # 
+;p ;
+
+GС@ʡ
+
+G@@!x 
+
+
+G
+!I@
+R B@h
+ H
+H:  B G) 
+@!D #
+G
+G
+GB G
+G
+
+x Q
+
+;Gp ;
+
+GБ@ʡ
+
+ ;R` G)"j !  (! )I
+
+
+   @
+
+Aa a
+  
+ @G1
+N
+
+ I
+
+
+   @
+G
+Aa a
+@  
+ @
+}
+
+
+
+}
+bP L
+x G
+
+
+Gǡ@ʡ
+@}  # +#L
+G@
+
+ 
+/R
+ 
+
+2@
+ #@
+x 
+GpqG,H:Q 9qp # ~  =!^ HL <" !Z H=a  ==a  >H>a  >>a a  9 ȁP  G
+
+@x  
+
+
+
+Hƒ
+
+t@^ # sRP @] # tR` G)"j ! 
+
+
+ Ѐ)`
+
+B @V # BH U # BP B @   s؀@ 
+ tx
+s
+
+B L # BH K # BP B @ 
+ H
+
+ 
+a 
+G@GA
+I
+I
+
+ @
+ > # "@
+@x "@
+
+
+G 
+ @
+
+G"@ @6 # 7
+x
+@ `
+x
+
+@x
+ `
+9x
+
+ 
+
+
+
+
+
+
+
+@
+EFQ@
+
+
+
+
+
+1 1
+N 
+O
+N! 
+N
+
+
+
+
+
+
+
+A@A`
+
+
+
+
+@`AA0@
+A
+
+
+ 
+
+
+ I @x p
+
+
+CL
+ 
+
+
+
+ 
+Š
+x
+I
+I
+ b
+
+H
+H
+`
+x
+`
+Lx  @cx
+
+
+
+
+
+
+
+`
+
+  
+H@
+ 
+
+
+
+
+
+
+
+@
+ I 
+B 
+ I 
+
+
+IJ
+  IHrR
+
+FLAKȂ
+
+
+N
+
+IJ
+  IH@
+@
+Q
+HR
+
+@
+H
+I a
+
+
+b
+H@ n
+b
+HrR b
+ H2
+
+a
+
+
+IJ2
+
+
+H2
+
+ @a
+ H2
+
+
+@7
+
+
+H
+H
+ x
+
+H)
+B 
+    @
+
+Aa a
+  
+M@
+2
+
+   
+
+Aa a
+
+M@
+
+
+@<
+
+
+M@a
+x
+ @
+Ȁ Ȁ ) 
+
+
+@
+
+
+
+ 
+
+`
+
+ɂP
+
+J
+
+
+
+
+@
+
+@
+`
+@
+
+@
+`
+
+
+8
+J
+
+
+8
+R
+IJ
+Q P PCII
+
+
+X
+L  ^ J@
+I
+K@ ɂp ɂ` 
+Aɂ@    a 
+
+ IK! 
+Hb
+
+   K
+
+@
+
+
+H
+ x I
+
+
+@
+
+
+"@  # 
+1 
+@x 
+s
+!@
+
+Hr
+ H@I
+
+
+ B @ # EBH  # EBP B @ 
+@IH @ 
+
+
+
+ @ # E"@ ! 
+@l
+!@
+
+Hr
+ H@I
+
+H
+!@
+
+HHr
+  H@I
+V
+@
+S
+
+ B @ # EBH  # EBP B @ 
+؀@ 
+I@I`
+H@ I
+ )I!
+@
+
+
+H@H` 
+# @x 
+
+
+N
+C @
+
+
+
+
+I
+ 
+΃ 
+@P  
+
+
+I΃ @n
+QRa 
+II@
+
+b
+O
+
+x 
+x d
+ 
+
+
+
+K
+
+
+O
+@l
+
+  @L" Il
+ 
+
+
+ @ `J
+2
+@M
+
+ @ `J
+
+
+
+8
+ @b 
+
+
+ @ `@
+ 
+#
+K#
+ @ `H
+II@
+
+E
+
+
+ @ `2@ʢ
+R
+I
+
+@
+
+@`< # 
+E
+
+
+
+@
+
+
+ 2@ʤ
+5
+
+
+
+!Hr@
+
+ @ 
+
+
+T
+$ x R
+x  P
+
+
+
+ I
+ @ `J
+
+S
+@I
+ @ `3@
+ @@
+
+@
+
+ @ `J
+
+L!
+
+
+
+L 
+
+ @ `3@
+ Ѐ @Q
+
+
+
+L
+L
+I@&l
+
+@
+ D  @ +
+
+
+CL
+ 
+
+
+ 
+@NH2
+
+$
+
+
+
+
+@Hx
+1x ox
+
+
+I
+
+
+Jʀ
+@I Ȁ  QIȃ Q ' 
+"D  d
+
+B@ H
+
+"x Q IH  I  
+$KH 
+
+ 
+ ȃ
+ I&
+L" o
+[)
+ 
+
+
+)
+)
+
+
+)
+)
+ 
+
+
+)
+)
+
+
+)
+)
+))
+( @o
+
+
+'L!  ! " # )Ja '  
+'L!     )Ja '  
+CJ +@ x % LLLL'L ! !c
+I)
+
+o
+@
+*Q !ʂp L+H'*#LHB0 o
+H
+ B R
+H'@x ,
+e
+l@b
+
+ LB ¤ "@BY
+ x
+
+L2 K
+"
+ x
+
+% B
+H
+I
+
+`
+x
+
+(( o
+
+(& & &  (
+
+@%x
+(%
+U@ (
+ N B
+ @
+ N  @o
+M@ N  @n
+( m
+
+(
+))
+
+'L!  ! )Ja '  
+'L!   )Ja '  +% ( o
+
+*Q !ʂp @x LL'L ! !a
+I)
+
+( @o
+
+*Q !ʂp H'*#LHB0 o
+B H'
+% & & &  ! $@
+ H
+ 
+CJ 
+ f
+U@&
+*
+K(
+(
+@o
+(@
+o
+
+"P
+! & 
+
+
+
+I
+Iy
+!%
+ 
+%G
+ "K
+Fa
+
+ d
+#K
+   I
+!
+H‚ 
+H 
+"J@ J
+JI %b
+@
+x
+
+x @ 
+J#"H'
+
+"
+ "K+
+
+x 
+
+`  
+
+"
+"
+J#
+
+
+a I
+
+
+=LȀ 
+@a
+
+x
+ c@ c
+$ "L 3@
+
+ 
+IA IσA I  A   3@e
+
+
+A JA  
+
+%e
+ ]a  a    '  
+   O
+O
+?H#
+H#?a Ǡ AH#PCH
+
+
+
+I
+ #
+I
+
+ @
+ H
+ 
+"P
+! & J
+@,x '
+
+@x &
+i*%
+&#i@("(h
+ (\(! x Y@("h
+'¢h
+'')
+'@iP | '&
+'zB'zB'@i9@(I'z'h$(@
+'Bh
+'@@x 'Ad
+(( N(
+ &J
+'iP | '
+@''&@x &'%%f%% a '@i()'z'% ! g%9@(I'z'h$(@
+'bh
+'`'a*(
+(( N(
+ &j %(%% h%
+ (
+'
+&'
+@g" &&(
+
+
+
+ y h
+&z &J
+ &b
+
+ a
+&B'
+&@&A& %Ǡ
+
+a &
+
+N J
+
+
+JG
+ 
+ I
+ ʠ
+ 
+ ʠ
+  I
+D 
+
+E 
+2
+   QIKbp I Q 
+ IJ
+
+@ I@
+ I
+ ʠ
+ 
+ ʠ
+ 
+
+
+@ @
+ߏN LJ
+J2 x 
+@Ȇ
+
+0
+`
+
+-x
+@ `
+5x
+
+@7x
+ `
+Tx
+L L 
+  
+
+ GI˂ !KO
+@
+ I
+
+ 
+
+ P 
+
+ o
+@ =Lˢˀ
+
+N J
+
+
+
+ 
+
+
+
+
+
+
+
+@
+EFQ@
+
+
+
+
+
+1 1
+N 
+O
+N! 
+N
+
+
+
+
+
+
+
+A@A`
+
+
+
+
+@`AA0@
+A
+
+
+ 
+
+
+ I @x p
+
+
+CL
+ 
+
+
+
+ 
+Š
+x
+I
+I
+ b
+
+H
+H
+`
+x
+`
+Lx  @cx
+
+
+
+
+
+
+
+`
+
+  
+H@
+ 
+
+
+
+
+
+
+
+@
+ I 
+B
+ I 
+
+
+IJ
+  IHrR
+
+FLAKȂ
+
+
+N
+
+IJ
+  IH@
+
+Q
+HB
+I
+
+H
+I a
+
+
+
+
+b
+H@ n
+b
+HrR b
+ H2
+
+a
+
+
+IJ2
+
+
+H2
+
+ @a
+ H2
+
+
+@7
+
+
+H
+H
+ x
+
+H)
+B 
+    @
+
+Aa a
+  
+M@
+2
+
+   
+
+Aa a
+
+M@
+
+
+@;
+
+
+M@a
+x
+ @
+Ȁ Ȁ ) 
+
+
+@
+
+
+
+ 
+
+`
+
+ɂP
+
+J
+
+
+
+
+@
+
+@
+`
+@
+
+@
+`
+
+
+8
+J
+
+
+8
+R
+IJ
+Q P PCII
+
+
+X
+L  ^ J@
+I
+K@ ɂp ɂ` 
+Aɂ@    a 
+
+ IK! A
+Hb
+
+   K
+
+@
+
+
+H
+ x I
+
+
+
+
+
+"@
+1 ~  H
+@x 
+t
+!@
+
+Hr
+ H@I
+
+
+ B  # EBH
+@IH @ 
+
+
+
+   # E"@ ! 
+
+!@
+
+Hr
+ H@I
+
+H
+!@
+
+HHr
+  H@I
+V
+
+S
+
+ B  # EBH
+؀@ 
+I@I`
+H@ I
+ )I!
+
+
+
+H@H` 
+# @x 
+
+
+N
+C @
+
+
+
+
+I
+ 
+΃ 
+@P  
+
+
+I΃ @n
+QRa 
+II@
+
+b
+O
+
+x 
+x d
+ 
+
+
+
+K
+
+
+O
+@l
+
+  @L" Il
+ 
+
+
+ @ `J
+2
+@M
+
+ @ `J
+
+
+
+8
+ @b 
+
+
+ @ `@
+ 
+#
+K#
+ @ `H
+II@
+
+E
+
+
+ @ `2@ʢ
+R
+I
+
+@
+
+@`V # @
+E
+
+
+
+
+
+
+ 2@ʤ
+5
+
+
+
+!Hr@
+
+ @ 
+
+
+T
+$ x R
+x  P
+
+
+
+ I
+ @ `J
+
+S
+@I
+ @ `3@
+ @@
+
+@
+
+ @ `J
+
+L!
+
+
+
+L 
+
+ @ `3@
+ Ѐ @Q
+
+@
+
+L
+L
+I@&l
+
+@
+ D  @ +
+
+
+CL
+ 
+
+
+  @
+@NH2
+
+$
+
+
+
+
+@Hx
+1x ox
+
+
+I
+
+
+Jʀ
+@I Ȁ  QIȃ Q ' 
+"D  d
+
+B@ H
+
+"x Q IH  I  
+䉁dKH 
+
+ 
+ ȃ @
+ I&
+L" o
+[)
+ 
+
+
+)
+)
+
+
+)
+)
+ 
+
+
+)
+)
+
+
+)
+)
+))
+( @o
+
+
+'L!  ! " # )Ja '  
+'L!     )Ja '  
+CJ +@ x % LLLL'L ! !c
+I)
+
+o
+@
+*Q !ʂp L+H'*#LHB0 o
+H
+ B R
+H'@x ,
+e
+l@b
+
+ LB ¤ "@BY
+ x
+
+L2 K
+"
+ x
+
+% B
+H
+I
+
+`
+x
+
+(( o
+
+(& & &  (
+
+@%x
+(%
+U@ (
+ N B
+ @
+ N  @o
+M@ N  @n
+( m
+
+(
+))
+
+'L!  ! )Ja '  
+'L!   )Ja '  +% ( o
+
+*Q !ʂp @x LL'L ! !a
+I)
+
+( @o
+
+*Q !ʂp H'*#LHB0 o
+B H'
+% & & &  ! $@
+ H
+ 
+CJ 
+ f
+U@&
+*
+K(
+(
+@o
+(@
+o
+
+"P
+! & 
+
+
+
+I
+Iy
+!%
+ 
+%G
+ "K
+Fa
+
+ d
+#K
+   I
+!
+H‚ 
+H 
+"J@ J
+JI %b
+@
+x
+
+x @ 
+J#"H'
+
+"
+ "K+
+
+x 
+
+`  
+
+"
+"
+J#
+
+
+a I
+
+
+=LȀ 
+@a
+
+x
+ c@ c
+$ "L 3@
+
+ 
+IA IσA I  A   3@e
+
+
+A JA  
+
+%e
+ ]a  a    '  
+   O
+O
+?H#
+H#?a Ǡ AH#PCH
+
+
+
+I
+ #
+I
+
+ @
+ H
+ 
+"P
+! & J
+@,x '
+
+@x &
+i*%
+&#i@("(h
+ (\(! x Y@("h
+'¢h
+'')
+'@iP | '&
+'zB'zB'@i9@(I'z'h$(@
+'Bh
+'@@x 'Ad
+(( N(
+ &J
+'iP | '
+@''&@x &'%%f%% a '@i()'z'% ! g%9@(I'z'h$(@
+'bh
+'`'a*(
+(( N(
+ &j %(%% h%
+ (
+'
+&'
+@g" &&(
+
+
+
+ y h
+&z &J
+ &b
+
+ a
+&B'
+&@&A& %Ǡ
+
+a &
+
+N J
+
+
+JG
+ 
+ I
+ ʠ
+ 
+ ʠ
+  I
+D 
+
+E 
+2
+   QIKbp I Q 
+ IJ
+
+@ I@
+ I
+ ʠ
+ 
+ ʠ
+ 
+
+
+@ @
+ߏN LJ
+J2 x 
+@Ȇ
+
+0
+`
+
+
+
+
+@z
+
+
+@ s@
+J AHR0  AH! I AH!  AHB8  AH0  @
+
+ A @
+J>
+ A A A AJ<
+ A"@@ @ AH>  `
+
+
+
+
+
+ AH>
+ I
+H
+ s@@y
+x
+
+H22 IH0 H
+
+@y s@
+J
+s@ AHR0  AH!  AH! I A AH0 K @
+
+ A @
+J>
+ A A A AJ<
+ A"@@ @
+
+p s@ 
+ FI> o
+
+ @ I @  @  @ I  AH> K `
+
+
+
+ 
+IIIb IIbI@
+IIIR IIRI 
+II
+ I
+
+I AH>
+
+
+
+ 
+
+@ I
+ AH0 H.  @ AH> H< H: 
+M
+. s@
+
+
+
+x GK`
+
+
+
+@A
+C
+C @
+C O
+C C
+
+`
+
+
+J
+@
+
+
+x NCh @x NC@ x NCH @x NCP
+K@
+ x @ x x  
+
+K@
+
+`
+JB@Jb@H
+
+@x Nb@
+N@@ I
+
+
+\
+
+ A>
+
+ @b
+
+
+x M@Q
+S$S$AL
+S
+
+@@ AH>
+
+
+
+
+
+
+@ P 
+
+ AH!  AH!  AH>
+H<  AH> @
+H$ H I AH6 @
+
+J
+ A `
+
+ A `
+x  AH!  AH!  AH! I AH!  AH>
+@= I
+J
+`
+x
+ A> @
+ AH0  AHR6 H4 HR*  AHB8 HB0
+ AHB8  AHR6 HR, HR"
+
+
+
+
+
+@
+s@
+HB
+J
+s@ AH> H< H26 H4 IH2 % 
+
+
+
+x @ H@ HH AH>  @
+{
+
+
+
+
+ !I!!@x ! AH> !H< a
+I!@  !
+ ! AH> b
+H
+H
+
+
+x
+
+
+
+
+
+
+
+
+
+`
+
+x I
+Ib
+
+
+
+
+H
+H
+
+@Jo
+
+
+
+x
+
+
+x
+@x
+@|x
+
+I<
+ HR
+g
+
+s@
+J@k
+s@
+ @j s@
+HB
+Jb
+s@#
+#@x #@
+
+J@ɑ ##
+
+ȁ 
+I
+ a
+
+J@ɑ $ AH> @a
+ @
+ x J
+@
+
+x
+HH
+J@ɑ  AH>  AH>
+@
+
+H%
+
+A AH> b
+bT % `
+
+
+
+ -I 
+
+Al
+I& @
+
+ @a
+I
+
+ &%I
+
+I {
+
+
+(
+
+I!(! )!x I) AH> a
+(
+
+%@a
+(
+@x
+ `
+@x z
+y
+
+@  A H
+@"
+@v
+
+F> o
+
+
+
+
+H7 # `
+ $
+
+
+
+
+
+
+HH++
+HH+,x #Hb
+'
+
+ 
+
++@
+
+
+
+`
+
+I I L F
+ɗ ɗ H a * + a + , a @II@ a H
+ER
+
+
+E "`  "d * + `  ~ + ,`
+ȇ J,,` @
+
++J` a
+
++B@
+I,*"
+@x @H
+@
+
+
+,H
+@ @@
+
+ @K
+H01DH
+HR n
+
+H,@a
+ 
+
+
+
+
+@
+
+
+
+$
+@a
+ @
+& }
+> ~ @ M@ @LÀ
+J
+> ~ @ M@ @LÀL
+
+
+@
+@
+ b
+H
+
+
+
+
+"Ab
+!H!
+@Y
+_ 
+
+ x
+ +
+
+@
+
+A
+
+
+
++H2
+
+
+x
+x +I
++@
+,+
+!
+
+!
+J J
+@x BX H`
+x BP `
+
+!
+JH H@
+JH
+JH JH
+A1
+
+
+v}
+x I
+
+@
+ `
+x
+x I
+
+@
+ `
+x
+@@
+@
+@@
+@"@I
+@
+K
+
+K
+
+
+
+
+
+K
+
+ 3@H
+
+
+
+
+
+ 3@H
+
+
+
+I@J@
+B` H  "|
+I@J@
+Bh H %GI @ B D I  "H  G "@  "H "P  D @  B  D "@  "D  
+HHH-HI@HHIHIHIIJHJHJJK HK!K!L)HLH)LLM#HMNHNHNN  BH OXHHXXXYHYHOOHY
+ H
+H I H
+  H
+!ɐ H
+H! H
+(I H
+( H
+H%ɑ H
+% H
+)I H
+
+P. 
+
+
+
+
+2@ @ I
+
+
+
+
+@
+I-
+
+I-I I-
+J@ɑ  A H@M
+ @
+
+
+
+H,^a Ѐ
+$@
+Y@hB&i
+
+%A#$AdIA
+#
+@#A
+
+$$
+
+
+
+
+
+
+
+
+
+a @樀
+@
+@V
+
+
+
+$$f
+$"x
+
+e;`
+ x %`
+
+d
+%
+@x
+$$$$$
+
+
+$A$> $
+#Dc/
+
+c
+d@!
+
+Q f9@
+@ x e<&a
+d)e
+x Ia
+de
+@ x $@@ $) a
+c7 @c@
+c%
+fH
+
+
+#$
+d@
+#
+f! x &
+c
+@
+e
+
+
+%`
+
+
+i2 $$$$$
+d
+
+
+f! $e
+$<
+d&I@
+i2 
+d
+
+
+f $$<
+
+
+hr
+#
+
+C@
+
+`b
+
+`b
+
+
+
+
+
+
+)
+
+'@) g@a
+
+
+
+
+
+
+z
+
+
+ s@
+J AHR0  AH! I AH!  AHB8  AH0  @
+
+ A @
+J>
+ A A A AJ<
+ A"@@ @ AH>  `
+
+
+
+
+
+ AH>
+
+H
+
+x
+@y
+H22 IH0 H
+
+} s@
+J
+s@ AHR0  AH!  AH! I A AH0 K @
+
+ A @
+J>
+ A A A AJ<
+ A"@@ @@ I
+
+
+ FI> o
+
+  I
+
+
+
+ 
+IIIb IIbI@
+IIIR IIRI 
+II
+ I
+
+I AH>
+
+
+
+ 
+
+ I
+ AH0 H.  @ AH> H< H: 
+M
+
+
+
+
+x GK`
+
+
+
+@A
+C
+C @
+C O
+C C
+
+`
+
+
+J
+@
+
+
+x NCh @x NC@ x NCH @x NCP
+K@
+ x @ x x  @ I
+
+K@
+
+`
+JB@Jb@H
+
+@x Nb@
+N@ I
+
+
+\
+
+ A>
+
+ @b
+
+
+x M@Q
+S$S$AL
+S
+
+@@ AH>
+
+
+
+
+
+
+@ P 
+
+ AH!  AH!  AH>
+H<  AH> @
+H$ H I AH6 @
+
+N
+ A `
+
+ A `
+x  AH!  AH!  AH! I AH!  AH>
+A I
+J
+`
+x
+ A> @
+ AH0  AHR6 H4 HR*  AHB8 HB0
+ AHB8  AHR6 HR, HR"
+
+@3y
+
+@ s@0 Ib
+
+
+s@
+HB
+J
+s@ AH> H< H26 H4 IH2 
+
+@}
+
+x  H HH AH>  @
+
+
+
+
+
+ !I!!@x ! AH> !H< a
+I! !
+H
+H
+
+@ s@@y
+x
+
+
+
+
+
+
+
+
+
+`
+
+x I
+Ib
+
+
+
+
+H
+H
+
+@Jo
+
+
+
+x
+
+
+x
+@x
+@|x
+
+I<
+ HR
+g
+
+s@
+Jo
+s@
+ n s@
+HB
+J
+s@#
+#@x #@
+
+J@ɑ ##
+
+ȁ @
+I
+ a
+
+J@ɑ $ AH> @a
+ @
+ x J
+@
+
+x
+HH
+J@ɑ  AH>  AH>
+
+
+H%
+
+A AH> b
+bT % `
+
+@
+
+ -I 
+
+Al
+I& @
+
+ @a
+I
+
+ &%I
+
+I {
+
+@
+(
+
+I!(! )!x I) AH> a
+(
+
+%@a
+(
+@x
+ `
+@x
+
+
+@  A H
+@"
+z
+
+F> o
+
+
+
+
+H7 # `
+ $
+
+
+
+Kx
+
+
+HH++
+HH+,x #Hb
+' #_x
+
+ 
+
+@ 
++@
+
+
+
+`
+
+I I L F
+ɗ ɗ H a * + a + , a @II@ a H
+ER
+
+
+E "`  "d * + `  ~ + ,`
+ȇ J,,` @
+
++J` a
+
++B@
+I,*"
+@x @H
+@
+
+
+,H
+@ @@
+
+ @K
+H01DH
+HR n
+
+H,@a
+ 
+@
+
+
+
+
+
+
+
+$
+@a
+ @
+& }
+> ~ @ M@ @LÀ
+J
+> ~ @ M@ @LÀL
+
+
+
+
+ b
+H
+
+
+
+
+"Ab
+!H!
+@Y
+_ 
+
+ x
+ +
+
+@
+
+A
+
+
+
++H2
+
+
+x
+x +I
++@
+,+
+!
+
+!
+J J
+@x BX H`
+x BP `
+
+!
+JH H@
+JH
+JH JH
+A1
+
+
+r}
+x I
+
+@
+ `
+x
+x I
+
+@
+ `
+x
+@@
+@
+@@
+@"@I
+@
+K
+
+K
+
+
+
+
+
+K
+
+ 3@H
+
+
+
+
+
+ 3@H
+
+
+
+I@J@
+B` H  "|
+I@J@
+Bh H %GI @ B D I  "H  G "@  "H "P  D @  B  D "@  "D  
+HHH-HI@HHIHIHIIJHJHJJK HK!K!L)HLH)LLM#HMNHNHNN  BH OXHHXXXYHYHOOHY
+ H
+H I H
+  H
+!ɐ H
+H! H
+(I H
+( H
+H%ɑ H
+% H
+)I H
+
+P. 
+
+
+
+
+2@ @ I
+
+
+
+
+@
+I-
+
+I-I I-
+J@ɑ  A H@M
+ @
+
+
+
+H,^a Ѐ
+$@
+Y@hB&i
+
+8
+b I@@
+%A#$AdIA
+#
+@#A
+
+$$
+
+
+@
+
+
+
+
+
+
+a @樀
+@
+@V
+
+
+
+$$f
+$"x
+
+e;`
+ x %`
+
+d
+%
+@x
+$$$$$
+
+
+$A$> $
+#Dc/
+
+c
+d@!
+
+Q f9@
+@ x e<&a
+d)e
+x Ia
+de
+@ x $@@ $) a
+c7 @c@
+c%
+fH
+
+
+#$
+d@
+#
+f! x &
+c
+@
+e
+
+
+%`
+
+
+i2 $$$$$
+d
+
+
+f! $e
+$<
+d&I@
+i2 
+d
+
+
+f $$<
+
+
+hr
+#
+
+C@
+
+`b
+
+`b
+
+
+
+
+
+
+)
+
+'@) g@a
+
+
+
+@x
+@ `
+@x
+
+
+ `
+@7x
+
+ 
+
+
+
+
+
+
+
+
+EFQ@
+
+
+
+
+
+1 1
+N 
+O
+N! 
+N
+
+
+
+
+
+
+
+A@A`
+
+
+
+@`AA0@
+
+
+CL
+ 
+
+
+
+ 
+Š
+x
+I
+I
+ b
+
+H
+H
+`
+
+`
+@Fx @ ^x
+
+
+
+
+
+
+
+
+
+ H @
+ 
+
+
+
+
+
+
+
+@
+ 
+B @
+ 
+
+
+IJ
+  IHrR @
+
+FLHA Ȃ
+
+
+H
+
+IJ
+  IH@ z
+Q
+
+
+!`
+
+
+H
+H
+
+ɿ
+H2@
+
+b
+H@ p
+b
+HrR @d
+
+
+H 
+
+
+J2
+
+
+IH2
+
+@e
+H
+@a
+H2
+
+
+@7
+H`
+
+
+H
+H
+ x
+
+)
+B 
+    @
+
+Aa a
+  
+M@H
+2
+
+   
+
+Aa a
+
+M@
+A
+
+?
+
+
+M@a
+x
+ @
+Ȁ Ȁ )  
+
+
+H@
+
+
+
+
+
+J
+
+
+
+
+@
+
+@
+`
+@
+
+@
+`
+
+
+8
+
+
+8
+R
+IJ
+Q P PCII
+
+
+X
+I
+K@ɂp
+ɂ` 
+
+ IK! @H
+b
+
+@X
+   
+
+@
+
+
+H
+@?
+ x I
+
+
+
+
+
+"@  # @ 
+1 ~  H
+
+
+ @
+
+HHr
+IH H@I
+@
+
+J
+ B  # EBH
+
+
+
+  # E"@ ! @
+
+ @
+
+HHr
+IH H@I
+@
+
+
+ @
+
+Hr
+H H@I
+HѕH@H
+HѕH@H
+J
+
+ B  # EBH  # EBP B @ ! ؀@   
+I@I`
+H@ I
+H 
+
+ˀ
+K
+
+
+K
+
+H@H` 
+ &
+
+ @x K@@
+N
+C @
+
+
+H@H`  
+@x
+N
+C @
+
+
+
+
+ 
+
+I
+ 
+I> 
+΃ 
+@P  
+
+
+@b
+I΃ m
+QRa 
+II@
+
+Ob
+
+
+x 
+x d
+ 
+
+P
+
+P
+
+
+K
+
+
+O
+@l
+
+  @L" Il
+ 
+
+
+ @ `J
+2
+@M
+ @ `J
+
+
+
+8
+ @b 
+ b@ 
+
+
+
+
+
+@@
+ @ `
+@  
+#
+K#
+
+ @ `H
+II@
+
+
+E
+
+
+ @ `J
+ 2@ʢ
+I
+
+@
+
+U
+Q
+@
+@` # @
+@
+E
+
+
+
+
+URAU@2@ AP
+
+
+
+ 2@ʤ
+5
+ 
+ 2@ʤ
+5
+
+URAU@P  PA # 
+
+
+
+  
+`
+P
+O
+$ x R
+x  P
+
+$`
+
+
+
+
+ @ `J
+
+
+
+
+ @ `3@
+ @@
+
+@
+
+ @ `J
+
+
+
+
+
+
+ @ `3@
+ Ѐ @Q
+
+@
+
+L
+L
+
+@  D  @ *
+
+
+CL
+ 
+
+
+ 
+@NH2
+
+$
+
+
+H`
+x
+
+
+
+H
+@Hx
+1x ix
+
+I
+
+I
+ʀ
+@I Ȁ  QIȃ Q & 
+"D c
+
+B@
+
+y Q IH  H
+dL
+
+ 
+ ȃ
+  %
+L" o
+[(
+ 
+
+
+(
+(
+
+
+(
+(
+ 
+
+
+(
+(
+
+
+(
+(
+((
+' @o
+
+
+'L!  ! " # (Ja '  
+'L!     (Ja '  
+CJ *@ x % LLLL'L ! H!c
+I(
+
+o
+@
+)Q J!ʂp L*&)#LHB0 o
+H
+ B R
+&@x HB
+% B
+H
+I
+
+`
+x
+
+'' o
+
+'& & &  '
+
+@%x
+'%
+U@ '
+ N B
+ @
+ N  @o
+M@ N  @n
+' m
+
+'
+((
+
+'L!  ! (Ja '  
+'L!   (Ja '  *% ' o
+
+)Q J!ʂp @x LL'L ! H!a
+I(
+
+' @o
+
+)Q J!ʂp &)#LHB0 o
+B &
+% & & &  ! #@
+ H
+ 
+CJ  f
+U@&
+)
+K'
+'
+@o
+'@@m
+"P
+! & 
+
+
+
+I
+K!%
+ 
+%G
+!K
+Fa
+
+ d
+ #K
+  
+
+H!
+ JI %b
+@
+x
+
+x @ 
+"!H'
+
+"
+!K+
+
+x 
+
+`  
+
+"
+"
+"
+
+
+a I
+
+
+=LȀ 
+%e
+ ]a  a    '  
+    O
+?"
+"?a Ǡ A"PCH
+
+
+I
+@ K#
+
+I
+
+ @
+ H
+ 
+"P
+! & J
+'
+*x '
+V
+@x %
+i)%G
+"i@!('
+ (\(! x Y@!'
+'¢h
+'')
+'@iP | '&
+'zB'zBf&& a @i9@'#(@
+'Bh
+'@@x 'Ad
+'( N(
+ &j
+'iP | '
+@%%@ x %g$$f&& a @i(('zg$9@'#(@
+'bh
+'`'a)(
+'( N(
+ &J $
+ '
+'
+%'
+@g" %&'
+
+V
+
+ y ( &j &:
+ 
+V
+'$@
+&B'
+&@&A& %Ǡ
+
+a &
+
+N J
+
+
+JG
+ 
+ I
+ ʠ
+ 
+ ʠ
+ 
+
+D 
+
+E 
+ IJ
+
+@ I@
+ I
+ ʠ
+ 
+ ʠ
+ 
+
+
+@ @
+ߏN LJ
+J2 x 
+@Ȇ
+
+0
+`
+
+ y
+G@,
+%
+I`
+
+
+@x
+@:La
+
+
+
+
+@-y
+o
+c
+HCc
+I
+x
+*L6Lǁ Q ;LH2 
+H
+L `
+
+@@ I
+
+x
+ 
+
+@x  
+
+2
+
+( GGCG
+
+<L 
+
+
+ B
+
+@x
+BD HAd
+
+` H
+
+
+`
+
+X  ȃ 
+, 
+
+q@BD HH@d
+
+x
+
+
+@ 
+HA
+
+
+
+ȃ X 
+
+x ! GG
+G$L x 0! $L @$ N
+@
+" 
+N" HD 2P @x ! x A! 
+@<
+` @
+
+
+`
+
+
+Hz o
+
+
+
+@x
+
+
+GI 
+O
+I@
+I
+
+o
+I@
+I
+ Rp
+ 
+
+  I`O
+
+
+
+
+
+LJ
+ 
+
+`
+1x G`
+G
+G
+ 
+
+
+]
+G IGa @
+a  
+G
+
+
+
+`
+ x 
+
+@
+
+P 
+
+
+ IG @
+@
+
+P 
+
+
+
+GG
+b
+
+
+
+H`
+`
+
+ 
+
+*L 6L @˂@
+@`
+I
+@ b$ r
+@ I2@
+C
+B r@@x r@
+
+ Gr
+Gr
+
+
+
+
+
+``
+
+
+G
+b
+
+
+o
+
+H
+
+
+
+
+
+G
+`
+ x @
+I
+x  
+Br
+@
+G
+ I@
+
+ 
+x 
+
+
+HIa $
+HJIIa "
+IJa !
+ G
+
+A Q@
+G
+ `
+@x  I  IB@HB@ 
+ 
+
+
+
+
+
+
+
+
+
+J
+
+x GGP ! @$ N
+@
+" 
+N" HD 2P @x ! x A! 
+GG
+G
+G`
+
+@
+
+@
+H! "
+ 
+
+I
+x F! x
+@
+
+N
+  r
+
+ ! RGIba IGa 
+a  
+ 
+
+ @@
+
+
+
+"B @x @@ o
+
+@
+T~
+
+(
+! (@( hQ
+(
+*
+kè
+냨
++B
+
+*
+*
+
+
+! ( 銂( (
+@$ ("Lh
+! ( 銂( hЈ0D x ( D *k
+Q
+*
+*
+k
+p
+*
+
+! h (( m-^ ( (
+@$ ("L( (
+! h (( -^ ( (X0D ( (0D ( (
+$ /"L/ /
+! h (( -^ ( (
+P$ ("L( (
+! h (( --^ ( h؎0D ( $ $("L./(
+
+
+
+! ( 銂( @$ ("Lh
+! ( 銂( hи0D @x ( *
+Q x +kA
+k
+p
+0D ( ) (
+! h (( -^ ( @$ ("L( (
+! h (( ( (X0D ( (0D ( (
+! h (( m-^ ( P$ ("L( (
+! h (( 胂 ( hؾ0D ( $ $("L./((
+
+
+@ x 
+@@x  U@U5
+`a@
+
+U@
+
+@V
+
+
+E NNN$ " N
+
+x Ad
+V U@U5
+
+E
+
+G
+G
+c
+
+N N N
+
+  
+@
+!
+G
+
+ߏN Lȃ JB
+
+`
+
+,
+ *C(I(
+,J@($ ,*F ( ) ("L(h ! ( 튂( (
+,J@ ($ ("Lh ! ( 튂(  ,
+("Lh ! ( 튂( 
+
+G+
+%
+ @
+I`
+@y `
+@y $
+x
+@:La
+
+
+
+
+*y
+
+
+
+
+
+ , 
+
+
+B I
+
+
+
+
+@
+
+o
+c
+HCc
+I
+x
+*L6Lǁ Q ;LH2 
+H
+L `
+
+@@ I
+
+x y o
+ 
+
+@x  
+
+2
+
+( GG$ $" $" 
+
+<L 
+
+
+@ B
+
+@x
+BD HAd
+
+` H
+
+
+`
+
+X  ȃ 
+, 
+
+q@BD HH@d
+
+x
+
+
+@ 
+HA
+
+
+
+ȃ X 
+
+x ! GG
+G$L x 0! $L @$ N
+@
+" 
+N" HD 2P @x ! x A! 
+
+` @
+
+
+`
+
+
+HR o
+
+
+
+@x
+
+
+GI 
+O
+I@
+I
+
+o
+I@
+I
+ Rp
+ 
+
+  I`O
+
+
+
+
+
+LJ
+ 
+
+1x G`
+G
+G
+ 
+
+
+
+G IGa @
+a  
+G
+
+
+
+`
+ x 
+
+@
+
+P 
+
+
+ IG @
+@
+
+P 
+
+
+
+GG
+B
+
+
+
+H`
+ %
+
+
+
+
+G
+`
+ x @
+x  
+Br
+@
+
+
+ 
+x 
+
+
+HIa $
+HJIIa "
+IJa !
+ G
+A Q@
+G
+ `
+I IB@HB@ 
+ 
+
+
+
+
+
+
+
+
+
+J
+
+@x GGP ! @$ N
+@
+" 
+N" HD 2P @x ! x A! 
+GG
+G
+G`
+
+@
+
+@
+H! "
+ 
+
+I
+x F! x
+@
+
+N
+  r
+
+ ! RGIba IGa 
+a  
+ 
+
+ @@
+
+
+
+"B @x @@ o
+
+@
+
+
+(
+! (@( hQ2x ( (o
+(
+*
+kè
+냨
++B
+
+*
+*
+
+
+! ( 銂( (
+@$ ("Lh
+! ( 銂( hЈ0D
+,J@($ ,*F ( ) ("L(h ! ( 튂( (
+,J@ ($ ("Lh ! ( 튂(  ,
+("Lh ! ( 튂( 
+*
+*
+k
+p
+*
+
+! h (( m-^ ( (
+@$ ("L( (
+! h (( -^ ( (X0D ( (0D ( (
+$ /"L/ /
+! h (( -^ ( (
+P$ ("L( (
+! h (( --^ ( h؎0D ( $ $("L./(
+
+
+
+! ( 銂( @$ ("Lh
+! ( 銂( hи0D x ( *
+k
+p
+0D ( ) (
+! h (( -^ ( @$ ("L( (
+! h (( ( (X0D ( (0D ( (
+! h (( m-^ ( P$ ("L( (
+! h (( 胂 ( hؾ0D ( $ $("L./((
+"x IU
+
+@ x 
+@@x  U@U5
+`a@
+
+U@
+
+@V
+
+
+E NNN$ " N
+ x Ad
+V U@U5
+x
+E
+
+G
+G
+c
+
+N N N
+
+  
+@
+!
+G
+
+ y
+G@,
+%
+I`
+
+
+@x
+@:La
+
+
+
+
+@-y
+o
+c
+HCc
+I
+x
+*L6Lǁ Q ;LH2 
+H
+L `
+
+@@ I
+
+x
+ 
+
+@x  
+
+2
+
+( GGCG
+
+<L 
+
+
+ B
+
+@x
+BD HAd
+
+` H
+
+
+`
+
+X  ȃ 
+, 
+
+q@BD HH@d
+
+x
+
+
+@ 
+HA
+
+
+
+ȃ X 
+
+x ! GG
+G$L x 0! $L @$ N
+@
+" 
+N" HD 2P @x ! x A! 
+@<
+` @
+
+
+`
+
+
+Hz o
+
+
+
+@x
+
+
+GI 
+O
+I@
+I
+
+o
+I@
+I
+ Rp
+ 
+
+  I`O
+
+
+
+
+
+LJ
+ 
+
+`
+1x G`
+G
+G
+ 
+
+
+]
+G IGa @
+a  
+G
+
+
+
+`
+ x 
+
+@
+
+P 
+
+
+ IG @
+@
+
+P 
+
+
+
+GG
+b
+
+
+
+H`
+`
+
+ 
+
+*L 6L @˂@
+@`
+I
+@ b$ r
+@ I2@
+C
+B r@@x r@
+
+ Gr
+Gr
+
+
+
+
+
+``
+
+
+G
+b
+
+
+o
+
+H
+
+
+
+
+
+G
+`
+ x @
+I
+x  
+Br
+@
+G
+ I@
+
+ 
+x 
+
+
+HIa $
+HJIIa "
+IJa !
+ G
+
+A Q@
+G
+ `
+@x  I  IB@HB@ 
+ 
+
+
+
+
+
+
+
+
+
+J
+
+x GGP ! @$ N
+@
+" 
+N" HD 2P @x ! x A! 
+GG
+G
+G`
+
+@
+
+@
+H! "
+ 
+
+I
+x F! x
+@
+
+N
+  r
+
+ ! RGIba 
+a  
+ 
+
+ @@
+
+
+
+"B @x @@ o
+
+@
+T~
+
+(
+! (@( hQ
+(
+*
+kè
+냨
++B
+
+*
+*
+
+
+! ( 銂( (
+@$ ("Lh
+! ( 銂( hЈ0D x ( D *k
+Q
+*
+*
+k
+p
+*
+
+! h (( m-^ ( (
+@$ ("L( (
+! h (( -^ ( (X0D ( (0D ( (
+$ /"L/ /
+! h (( -^ ( (
+P$ ("L( (
+! h (( --^ ( h؎0D ( $ $("L./(
+
+
+
+! ( 銂( @$ ("Lh
+! ( 銂( hи0D @x ( *
+Q x +kA
+k
+p
+0D ( ) (
+! h (( -^ ( @$ ("L( (
+! h (( ( (X0D ( (0D ( (
+! h (( m-^ ( P$ ("L( (
+! h (( 胂 ( hؾ0D ( $ $("L./((
+
+
+@ x 
+@@x  U@U5
+`a@
+
+U@
+
+@V
+
+
+E NNN$ " N
+
+x Ad
+V U@U5
+
+E
+
+G
+G
+c
+
+N N N
+
+  
+@
+!
+G
+
+ߏN Lȃ JB
+
+`
+
+,
+ *C(I(
+,J@($ ,*F ( ) ("L(h ! ( 튂( (
+,J@ ($ ("Lh ! ( 튂(  ,
+("Lh ! ( 튂( 
+I`
+x `
+x  x
+
+
+
+
+
+
+G
+
+
+@
+( G%
+
+GG
+x ( (LG/
+ I
+@
+
+ 
+a
+
+
+
+H@
+
+x
+ %
+ (  ( (LG/
+ Gb
+Gb I
+Gb
+
+aB
+
+IB HJ , 
+`
+
+
+` x
+ H
+G H
+  x ȑ@@ ë ȁ
+Q
+Ff e @@ ȉ 
+Bc
+
+
+
+NR` Rj 
+@
+I I  $$2@HbF HT * G@d
+ߏNȁG
+
+
+
+G@
+
+_
+
+ 9I  9LJ! ! l
+`
+
+a  
+@a
+&
+
+
+
+
+G
+
+
+o
+
+
+ %
+H
+
+
+
+x @
+IA
+
+
+x 
+
+
+./a #
+HJ//a "
+/0a `!
+G
+
+ A Q@
+G
+ 
+@x  I  IB@HB@ 
+ 
+
+
+IAII
+
+IAI
+
+A
+
+N@@@ N
+
+
+Α@
+Q@
+
+
+A@
+
+
+ 
+GG
+ @x
+
+O
+ O
+O @x
+
+
+O 
+G
+S@
+
+MSI@
+G
+
+x OÀ
+6HC
+
+H 
+  Bx  `
+
+ x 6HC a
+ 
+ 
+H!
+B x D Bx  b
+H!
+ @x 
+
+ b
+H!
+D x BB x  Db
+  `
+ B 
+6HC @
+ b
+H!
+D x B@x  a
+  Bx  `
+
+6HC
+ `
+ a
+"
+
+
+x 6HC `
+
+@ b
+H!
+ 
+ 
+x 6HC a
+H%
+
+H!
+B Bx D 
+ `
+ 
+6HC
+
+ 
+ `
+
+ 
+
+I
+x ! x
+IB
+IW¦
+IC
+IՌGå
+SC
+Ӌä
+IRD
+IҊGģ
+ QD
+ щĢ
+ E
+ PGš
+ ψE
+ Š
+INI@x
+Ƣ
+ F
+Ĭǡ
+ɋGG
+I Ǡ
+ʅI@Aa@ǁ@@x ȁ@ G
+A
+\
+Y
+ 
+
+~
+
++
+*`
+*
+kC
+
++£
+
+*
+*
+
+( @
+节( (
+
+( 
+*
+k
++¢
+
+*
+*
+@
+k
+h
+(@( x
+(@( (( (@(( m-^ ( (
+k
+
+(@( x ( (@( (( (@(( -^ ( (X( (( (
+k
+(@( x ((@( h( (@(( -^ ( (
+k
+h(@( x (@( h( (@(( --^ ( h؎
+
+
+"x U
+ x 
+@@x  U@U5
+`a
+
+
+
+@x V U@U5
+
+x 
+
+E NNN V N:@x :
+@x d
+V UU@U5
+x
+E
+`
+@x 
+
+GG
+G
+ I &
+
+ I !
+ `iI@ C
+      @
+I
+.x
+(x 
+@x
+
+
+@  `
+
+`
+
+Go
+ 
+~x
+
+
+6L k
+
+K
+ˠ
+@yx Ti
+Q"N
+
+
+
+
+
+rx a
+@
+@ @qx
+
+@ @ II24 A"
+
+ Iɐ ɐ  @ I  SIH@!
+
+@ I@
+
+x @
+Iɀ
+ɡ
+IG#
+
+I
+H
+IA"
+
+I!
+
+
+G A Q@
+G
+ 
+ 
+ G
+
+ Ĩ
+H(H(  BL Q IGv v  P 
+GHLȁP GL G  A
+q@
+  q@I
+ Go
+
+ 
+QI Q 
+@I
+
+H
+H
+
+G@x GMG
+)L x
+q@
+
+
+
+G@
+ 
+
+d
+
+H
+
+
+G ȁ `
+
+
+
+ , ( (LG/
+
+
+o
+
+GG
+
+y
+
+"& 
+
+
+
+޿. @n
+I
+  
+@  # ` d `
+
+T 
+
+
+ 
+
+H & ( G`
+GMG(LG@.
+C G( (LG/
+G
+@
+
+@Aa
+x 
+
+
+B
+
+G 
+
+ Ba
+G
+?
+
+"& 
+G
+G
+`
+@x ;
+@x , 
+
+x
+
+
+G 
+
+
+2@    
+ EE@
+G
+ǀ`
+ x
+
+ @ 
+
+
+
+
+GG  
+
+ @
+ @
+BX J
+BP 
+BH J
+
+(`ih@ (C(
+((
+HH
+G@
+R
+
+x 
+@@
+@
+O
+
+M NC@
+@ x LM
+O
+
+
+@ @ M@
+x MMM@ NNNNNNNQUNY
+
+M@
+B
+@Ix x
+
+ O
+   
+ O
+   M@ 
+OO
+x
+MC@ 
+ `
+@
+ x  P3@ @$
+x
+  
+@x
+  @ NMӀ M3@M@ X IM tr M#
+
+
+G@b
+
+IGB
+
+
+
+
+@
+
+!L@
+"L @
+
+J
+@
+A
+
+@x o
+r
+ @x J JM`
+
+
+
+
+@"
+
+
+@
+
+@
+@
+x V JM`
+
+
+@
+
+
+
+
+
+
+
+ J JY" !L MJ" !\ @
+
+
+J
+
+c
+@x K`
+JAb
+x
+`
+
+
+J
+
+
+
+
+pIrIB
+
+
+I @ x 
+ ,IB
+ɱ@
+
+   @
+II @
+
+x ,IB
+ɱ@
+
+   @
+II @
+ , C 
+
+  C
+A
+
+2@ 
+
+@}
+
+@
+ @ x
+x hi! V hi!  T
+U@e)hiqiU
+TqiU5@
+
+o)Q `)
+
+e)hi% V
+
+ր`
+x hi%@
+
+ U
+
+@!~
+
+H
+(G@
+,
+<@
+P
+XGA
+
+
+
+ G@
+ !
+ $@
+ <
+ HGA
+ x@@Gr1
+ -G@
+ Z
+ 
+
+Gb@
+GB@
+
+@x #
+x I
+x
+$
+$Y@@
+$
+$)@S
+d
+
+H
+@
+p r 
+r 
+ ÿ 
+
+
+
+H 
+
+
+ s 
+q  u ILI
+@I@HP U SI
+I UIǁ O
+
+K<K4 T 
+
+
+
+!`ia@ !C!
+
+
+
+
+
+ I 
+A
+
+
+ ¥
+I 
+
+A
+
+Di
+
+
+
+
+G`
+
+x  B  I D`
+
+EG@
+ŀ
+EŁx
+
+EG
+ł
+EŃ " K`
+@" `
+
+G`
+
+
+EG
+ń
+EŅ "  
+EG
+ņ
+EŇ " 
+ I !
+ `iI@ C
+      @
+I
+
+
+@x
+
+
+@ @ `
+Rx L
+`
+
+Go
+ 
+
+
+6L Kl
+
+K
+ˠ
+
+QBN
+
+
+
+
+
+@x a
+@
+@ 
+
+@ @ II24 A"
+
+ Iɐ ɐ  @ I  SIH@!
+
+@ I@
+
+x @
+Iɀ
+ɡ
+IG#
+
+I
+H
+IA"
+
+I!
+
+
+G A Q@
+G
+ 
+ 
+ G
+
+ 
+GHLȁP GL G  A
+q@
+ 
+ Go
+
+ 
+@I
+
+
+H
+
+Gx GMG
+)L
+q@
+
+
+
+G@
+ 
+
+@F
+
+  @a
+
+G ȁ `
+
+
+
+B J@
+B
+B B
+K,@x BX I`
+x BP `
+
+ , ( (LG/
+
+
+o
+
+GG
+
+d
+
+"& 
+
+
+
+޿.
+I
+  %
+GMG
+@
+G
+
+
+
+G@
+
+@
+H
+
+
+@; 
+
+
+ 
+
+
+@Aa
+x 
+
+
+B
+
+G 
+
+ Ba
+G
+
+
+"& 
+G
+@x  
+
+x
+
+
+G 
+
+
+2@  
+ 
+G
+ǀ`
+ x
+
+ @
+
+
+
+
+GG  
+
+ @
+ @
+BX J
+BP 
+BH J
+
+(`ih@ (C(
+((
+x 
+@@
+@
+O
+
+M NC@
+@ x LM
+O
+
+
+@ @ M@
+x MMM@ NNNNNNNQUNY
+
+M@
+B
+@Ix x
+
+ O
+   
+ O
+   M@ 
+OO
+x
+MC@ 
+ `
+@
+ x  P3@ @$
+x
+  
+@x
+  @ NMӀ M3@M@ X IM tr M#
+
+
+G@b
+
+IGB
+
+
+
+
+@
+
+!L@
+"L @
+
+J
+@
+A
+
+@x o
+r
+ @x J JM`
+
+
+
+
+@"
+
+
+@
+
+@
+@
+x V JM`
+
+
+@
+
+
+
+
+
+
+
+ J JY" !L MJ" !\ @
+
+
+J
+
+c
+@x K`
+JAb
+x
+`
+
+
+J
+
+
+
+
+pIrIB
+
+
+I @ x 
+
+@}
+
+@
+ @ x
+x hi! V hi!  T
+U@e)hiqiU
+TqiU5@
+
+o)Q `)
+
+e)hi% V
+
+ր`
+x hi%@
+
+ U
+
+
+ @
+@x #
+x I
+x
+$
+$Y@@
+$
+$)@S
+d
+ " !@ " !D MH
+
+H
+
+p r 
+r ] B
+
+ ÿ 
+
+
+
+H 
+@
+
+ s 
+q L 
+ € u HRJ RT v I@
+@I@
+@HP U SI
+I UIǁ O
+
+@
+HP SI
+
+
+
+!`ia@ !C!
+
+
+
+
+
+ I 
+A
+
+
+ ¥
+I 
+
+A
+
+Di
+
+
+
+
+G`
+
+x  B  I D`
+
+EG@
+ŀ
+EŁx
+
+EG
+ł
+EŃ " @" `
+
+G`
+
+
+
+EG
+ń@
+EŅ@x
+EG
+ŀ
+EŁ
+
+EG
+ņ@
+EŇ@x
+EG
+ł
+EŃ@
+`
+
++@+@
+
+
+
+y
+
+I
+
+@
+
+
+H
+ AH2: @ 
+h OI
+@x
+
+H
+ II
+ I AH2: `
+
+
+ AH0  AH! I
+
+J
+ AH> `
+x  AH>
+0 
+
+Hb2
+
+0 
+
+Hb2
+
+0 
+
+Hb2
+
+0 
+
+Hb2
+
+0 
+
+Hb2
+
+0 
+
+Hb2
+
+4 
+
+HB6
+
+4 
+
+HB6
+
+4 
+
+HB6
+
+
+ a
+ @a
+
+`
+
+I
+
+OAI
+ n
+ p
+ r  t O
+
+
+@K2
+ 
+ 
+@
+ AH> J
+ H
+`
+`
+
+
+A
+
+ʣ @ x
+ MA
+
+
+
+H0
+
+I
+
+
+
+H0
+
+
+H
+
+a
+ @a
+H `
+
+
+"
+AAAH o
+H J
+2X O
+b
+HAAAH o
+
+
+H @
+Hb
+"| AAAH @m
+
+B@ 
+
+
+x HAAAH o
+
+HAAAH o
+
+
+OAHH
+O JB@
+
+
+
+H
+
+
+H
+J
+OA
+"T O
+HAAAH o
+
+H"HAAAH o
+
+
+HAAAH o
+
+
+
+AAAH o
+
+
+
+ @
+ 
+
+9A
+
+
+9J2@ɗ :H
+
+ 
+
+
+H2@ 2
+
+J`  JJ` 
+I
+I
+
+OAH
+
+O
+
+H @
+ ȇ $H 
+ `
+
+
+
+
+
+@
+h O@a
+
+   AH0  AH( I   b
+ 
+  OAJb@ O
+#
+
+
+
+H": ` 
+2` O
+
+*CAf
+#G
+
+
+I  
+ @|
+@
+
+ KKa AK@/
+
+IH2
+
+x J "
+$
+
+
+A1
+@~
+( (+@Q R PPCH
+
+
+2@ @ I
+@ F>
+o
+
+
+ x J
+-
+
+? AH0 ˂@ɂ@ ʀ 
+`
+
+- AH> 
+
+
+
+? AH0 ˂@ɂ@ 
+ x
+
+
+V  AHb4 b@ bH H2 P T B
+
+@ AH>
+F  AH"< "B  AH> @ 2l ˷ a F 
+ 
+
+
+
+
+?
+
+?
+
+
+?
+
+? 
+@
+
+`
+
+
+
+
+
+H @H
+ I
+@x I
+
+@a
+ I
+b
+IB
+@
+
+`
+
+
+
+
+
+ H2@"@H
+`
+
+P/
+H@
+
+H0
+
+
+H0
+
+H? "P 
+J
+b I@@
+@bA˷ a F
+
+b
++@o
+
+a . AB+@+
+
+
+!+ A/@
+
+
+
+,@l@!
+
+o
+
+
+
+
+
+
+1
+/@+ o@a
+
+
+J`  JJ` 
+
++@+@
+
+
+
+y
+
+I
+
+@
+
+
+H
+ AH2: 
+h OI
+x
+
+H
+ II
+ I AH2: `
+
+
+ AH0  AH! I
+
+J
+ 
+ AH> `
+x  AH>
+0 
+
+Hb2
+
+0 
+
+Hb2
+
+0 
+
+Hb2
+
+0 
+
+Hb2
+
+0 
+
+Hb2
+
+0 
+
+Hb2
+
+4 
+
+HB6
+
+4 
+
+HB6
+
+4 
+
+HB6
+
+
+ a
+ @a
+
+`
+
+I
+
+OAI
+ n
+ p
+ r  t O@
+
+
+@K2
+ 
+ 
+@
+ AH> J
+ H
+`
+`
+
+
+A
+
+ʣ @ x
+ MA@
+
+
+
+H0
+
+I
+
+
+
+H0
+
+
+H
+
+a
+ @a
+H `
+
+
+"
+AAAH o
+H J
+2X O
+b
+HAAAH o
+
+
+H @
+Hb
+"| AAAH @m
+
+B@ 
+
+
+x HAAAH o
+
+HAAAH o
+
+
+OAHH
+O JB@
+
+
+
+H
+
+
+H
+J
+OA
+"T O
+HAAAH o
+
+H"HAAAH o
+
+
+HAAAH o
+
+
+
+AAAH o
+
+
+
+ 
+ 
+
+9A
+
+
+9J2@ɗ :H
+
+ 
+
+
+H2@ 2
+
+J`  JJ` 
+I
+I
+
+OAH
+
+O
+
+H @
+ ȇ $H @d
+ c
+
+
+
+
+
+
+h O@a
+
+  AH0  AH( I   b
+ 
+  OAJb@ O
+#
+
+
+
+H": ` 
+2` O@
+
+*CAf
+#G
+
+
+I  
+ @|
+@
+
+ KKa AK@/
+
+IH2
+
+x J "
+$
+
+
+A1
+~
+( (+@Q R PPCH
+
+
+2@ @ I
+@ F>
+o
+
+
+ x J
+-
+
+? AH0 ˂@ɂ@ ʀ 
+`
+
+- AH> 
+
+
+
+? AH0 ˂@ɂ@ 
+ x
+
+
+V  AHb4 b@ bH H2 P T B
+
+@ AH>
+F  AH"< "B  AH> @ 2l ˷ a F 
+ 
+
+
+
+
+?
+
+?
+
+
+?
+
+? 
+@
+
+`
+
+
+
+
+
+H @H
+ I
+@x I
+
+@a
+ I
+b
+IB
+@
+
+`
+
+
+
+
+
+ H2@"@H
+`
+
+P/
+H@
+
+H0
+
+
+H0
+
+H? "P 
+J
+b I@@
+@bA˷ a F
+
+b
++@o
+
+a . AB+@+
+
+
+!+ A/@
+
+
+
+,@l@!
+
+o
+
+
+
+
+
+
+1
+/@+ o@a
+
+
+J`  JJ` 
+ FL  CL R@ 
+I`
+
+x H!
+
+G @a
+
+@x
+
+
+
+, 
+ 
+
+
+@
+
+!
+
+
+J
+
+
+, !
+
+ G$
+`
+
+
+
+@I
+
+GIǁ 
+I@
+o
+I@Ip v Gv v Gw  p v Gv v Gw  
+
+kW Rk@4P `gP "k@IP rk\P 
+
+
+r
+H
+
+@I
+ `
+
+G `
+x
+ G`HR@
+`"@
+
+
+ b
+
+2 x
+B 
+ 
+
+
+
+
+
+c
+
+
+
+
+
+J`
+
+
+
+ @I  ^ G \ G Z 
+I
+
+
+
+I
+@
+QGbɑ@I2
+QHbIb P PCII b
+
+Q RIc P PCII ?Hba  t
+x @
+ ɀ
+
+
+ɱ
+
+
+
+GIǁ a
+O
+I@I
+
+
+
+@Lr@ǁ
+I
+
+@a
+
+
+L
+H2X
+ 
+
+
+ Ɂ x
+
+
+
+ G x 
+H
+
+ &
+
+a
+%
+
+ 
+$
+ a #
+HJ ! "
+  !
+ G
+
+A Q@
+G
+
+@x GH `
+x GP `
+x GX `
+@x G@ H`
+x GH `
+
+ 
+ G
+@x  I IB@HB@ 
+ 
+
+
+
+
+
+
+
+
+I 
+I 
+
+AL"CLh @
+
+
+(
+x (h
+@
+i
+(A
+h
+A
+
+߿
+(
+( )CL):
+
+
+
+
+
+
+
+@x  a
+
+I
+A@_`
+
+A@
+
+
+
+
+
+
+s s Eg
+
+a
+
+
+L@a
+
+
+
+
+E@a
+
+L
+
+D
+   !
+<Ȁa
+E<B
+
+B
+
+ =
+E===  E DL>L
+b
+
+D@ @
+
+x HR& b@I"@J@Hb
+  @
+I`
+x `
+x "
+@}x
+
+)L G@c
+G"
+
+
+)`
+
+`
+.y
+& & & 
+H@o @
+@
+
+@ J
+@
+
+
+@Aɑ
+G
+G
+G
+
+
+
+! `% #LB0 
+! I
+&  & Hb
+
+
+#
+H
+
+
+
+& & &  & 
+
+H
+! 
+H
+
+!
+& x
+H
+
+
+
+
+
+
+GI 
+O
+I@
+I
+
+o
+I@
+=Lʀ
+I
+ Rp
+ 
+
+ P$
+
+
+
+
+
+LJ
+ 
+
+
+    ȁ
+h
+G@G@ M
+b
+ G
+
+
+
+Ja
+
+
+b
+
+
+x
+
+
+x
+ 
+
+
+ 
+
+
+
+AG
+
+J@
+
+
+
+@
+
+
+mx
+QLFLAH
+p @ȁ
+CL@
+@L@HG
+cx
+@`x 
+
+a  
+Ix @b
+
+Vx
+@
+9 x 8 
+
+@+x
+
+ x @
+I
+x I@
+r
+
+H
+
+
+
+H
+
+G
+G
+
+A Q@
+G
+@H
+ȁ @
+I@@x @4@
+ 
+ 
+ I
+
+`
+
+
+
+
+
+G
+
+
+ `
+
+
+GGb
+m6
+m\
+-mNLǁ @4
+ G`
+
+ x "
+
+G.
+ x
+ r@"
+
+@
+%G
+
+
+x @ H
+
+
+
+
+x
+$`
+~
+* Ij@
+ꠂ )(`
+*A꧂ * * I* * * * j 
+)
+(5)
+
+
+
+
+Fx
+ a
+
+J* J* h
+
+* )J 
+ )
+
+ `
+:x
+
+G
+@x
+x
+! 1
+" 
+! 1
+! 1
+! 1
+@
+@x *H* &
+
+x
+@
+Q
+G
+
+ @
+Q
+Q
+Q
+G
+$G@
+L
+L
+
+
+G@
+G
+H
+
+\ PPCG
+
+J@" 
+`
+
+
+K! @
+`
+
+
+K! @
+
+@x
+` 
+ 
+
+I
+@ 
+
+ 
+
+
+( (
+G 
+x U
+@ x 
+@@#L
+
+W
+@@! NU 
+
+
+@V
+@c
+c
+
+Gx 
+
+
+2@
+b
+I Gp G` NG
+G
+x   2@   I2@ @a
+
+
+x I Gp G` K"\ GX  NI
+
+
+I
+
+@
+x
+x
+ @
+
+x
+ 
+
+K
+
+
+x
+ 
+ B@r
+%" ! 1@F! 
+
+H
+
+ x 
+
+x "
+H"
+#
+"
+G
+
+Ga
+
+
+
+"
+
+
+G@c
+G
+
+` @ 
+@x
+,
+1 c
+A 
+H
+ `
+
+
+
+@x )
+
+
+H
+
+-
+
+@
+&H&H  
+
+GG@c
+
+,
+
+@b
+
+G
+`
+Rx )
+
+
+H
+
+
+
+
+
+H
+GG
+
+
+
+e
+
+
+H
+
+
+
+
+
+
+H
+
+
+
+
+
+
+
+
+ax
+a*aG*G@
+`
+ x
+@x @x
+
+x ! h J
+
+
+
+
+
+
+
+@b
+
+
+H
+
+
+H
+
+
+
+
+
+
+
+
+G$
+
+
+G
+Ap &AX H'AP ! 
+
+
+,
+ 
+,I
+
+H$a
+ 
+
+
+`
+
+
+
+`
+
+
+
+
+`
+
+
+`
+
+
+I
+
+
+
+
+H
+
+H
+G
+
+(#@
+
+
+H&ȁ
+Gt Gt
+(I( *SI
+
+
+
+
+
+
++ @x , + 
+`
+
+HH@f
+@
+
+
+G@
+HPx 
+HH
+
+H%H
+HPG
+HH
+HP
+@
+
+HC@ r
+HCH C
+HCP HCX "@Ir
+C
+C 3
+C C @ Ir
+C
+C 3
+C C B LCH
+  @
+I`
+@*y `
+y #
+@~x
+ 
+ 
+"
+
+Cc
+)L 
+
+
+cy
+
+GGG> % & & & C
+De
+&Lo
+
+
+
+
+G
+ 
+
+
+@o
+@? 
+
+
+
+
+/G
+J
+Fa
+
+
+;
+
+
+Gd
+J
+  
+
+Q
+?
+R P
+
+C.
+
+
+? NI HB
+ @GA
+GRA @ HH
+Da
+C
+
+
+
+
+
+o
+G#LB0 o
+
+ A R LI
+
+% £
+H
+c
+C
+
+G
+@c
+&Lo
+
+
+G
+
+
+&Lo
+
+
+Z`
+
+
+
+ @
+
+x
+ h
+
+
+
+
+LJ
+ @j
+D`
+`
+
+I
+
+ 
+L
+
+    
+
+I
+,
+
++
+x 
+@
+ 
+
+r@ b
+D
+C
+@~ 
+q
+
+
+
+G
+
+A
+@ # G
+\
+
+
+
+H
+
+
+
+
+
+r@ b
+D
+C
+@e @a
+q!G`
+x Z
+@x
+
+
+G
+
+
+A
+
+\
+
+
+
+
+
+H
+ 
+
+ 
+@GG
+ 
+@
+ 
+@@ x 
+ 
+1@ @H
+ 
+1@ @H
+ 
+1
+GA`
+@x 
+G
+
+
+
+   x 
+I@D # D
+ Hx  !#(HH5a
+  @x 
+7 # @8
+I@
+
+
+QLFLAIH
+p "@ȁ
+CL@
+@L@ G
+H
+a  @r
+
+
+ G
+
+
+
+ID `
+
+
+@x @
+I@
+
+
+
+@
+
+@a
+G
+H
+
+
+@
+ J
+@ʢ
+
+A Q@
+G
+ Z`
+@
+ @ 
+I@@x @@
+ 
+ 
+ 
+@x 
+
+a H
+
+@
+
+mg
+
+
+b
+D
+C
+
+J
+
+@ J
+ b
+
+
+GB
+ 
+
+@x
+G
+
+@
+C`
+@x
+ s s 
+ 
+L! o
+
+H
+
+
+ 
+
+ 
+
+
+x
+x DL 
+
+
+
+P
+!x 
+
+
+/ǣ
+Pd@QQ 
+¢R
+@
+BR
+@@x Ac
+ N
+Q@Q@
+bR
+`a
+ N D  
+@
+Q@Q& 
+
+
+x /Ǡ
+
+ t 4 T
+ 
+
+
+B
+@A /Ǡ
+ P@PP4@a
+ 
+
+
+I|
+ I
+"p   "h  
+ 
+bp
+
+@ @ I ɐ  ɐ 
+SI
+
+@ I@
+I
+
+o
+I@
+=Lʀ
+I
+ bp
+ 
+
+ :Lb
+ L L 8L
+    8 
+ /$
+@
+! a " a #  Λ
+?
+?a Ǡ APCG
+
+
+
+ȁ
+
+
+Q
+?
+R P#LG
+q@
+
+. 
+
+. 
+
+. 
+
+
+gZ
+
+. 
+
+Lx
+ `
+
+
+
+ x @ @ Hbd 0 H@ @H Hbd 0 r@G@r@@GR  Hbd 0  Hbd 0 
+
+@@x 
+
+@
+
+@H@x 
+@H
+@
+@`
+
+@
+@
+@`
+
+@
+
+x 
+x @ #
+
+
+
+
+I
+
+@@
+L@
+
+I@I@
+L@
+I
+  @x       
+Z
+
+Xш
+PH Ȉ
+X
+H
+
+H
+
+
+
+
+
+
+I
+v
+G
+2x
+ Ha
+
+@2x U@
+IL
+
+
+
+x
+
+@ x Z@
+
+G2
+
+
+A
+
+
+x
+
+
+
+
+H
+ .
+ta
+ -
+_x
+
+G7
+mW Bl
+
+HR
+ II
+
+
+
+
+@Lr@ǁ
+
+@x
+I
+
+
+
+ @}
+
+
+
+x 
+H@
+ 
+@
+H
+
+@}
+
+@_
+
+ A
+E
+Q
+ , 
+D
+FA 
+
+
+A  * 1@1
+$A
+4X
+Q
+@
+
+!
+Q
+ F
+F@q@x F F
+F@FF @x F F
+
+ J`
+F" I
+F" I
+@x D!H EP
+ H
+
+D
+@@ D $L
+M3
+M AH a   t
+
+
+
+
+2a
+-Iȁ
+@L3
+
+3
+
+ 
+
+ɑ z I
++ @
+I`
+z ɀ`
+
+&x P 
+Ex 
+Ex  
+
+
+
+
+
+) 
+
+ J@
+  J
+. 8 
+
+GI ,
+O
+I@
+I
+
+o
+I@
+=Lʀ
+I
+ bp
+ 
+
+ 
+
+Q R P PC L
+
+@J
+A
+A
+ &
+%
+(
+\
+! p! 
+
+J
+
+
+
+
+LJ
+ @
+I
+P!
+Ga
+
+ x
+ H  G
+G@
+`
+@x ׁ`
+x
+x MuG`
+@x
+ QL
+FLHA Ȃ
+ t
+x
+G
+
+
+q@
+
+
+ 
+
+
+B
+
+<B/L'  @ 0@
+
+
+G
+
+GI
+@LBLAQ
+`
+ 
+
+$
+
+
+
+@x $@
+W(Ǥ
+*e@-UU 
+ \! @x U@-U 
+¢V
+
+@TeP W| NB 
+EE@
+BV
+@@x AՀe
+& N U
+TeP W| NB 
+U@%$U@x $&)
+bV
+`aV0
+& N U ' $
+
+
+$`
+
+
+
+
+ u V, E
+@
+
+
+B
+@A Ǡ
+
+A 
+ 
+
+@@x
+N N N@
+ 
+
+@ @ II24 A"
+
+ Iɐ ɐ  @ I  
+
+@ I@
+I
+
+K
+K
+@
+@
+G
+
+<G@S ;
+<
+`
+ x J
+
+ x Iǀ!
+<
+J
+
+x J
+x J
+G2
+H"
+
+
+2
+x J
+3@
+G4
+
+
+~ $
+H
+!
+
+N,x 
+
+
+s x
+ @
+
+S
+ x .I,J)
+`
+,@
+I
+,@Ȅ@ -, -
+@Ǡ  A+,-
+
+G
+;H -%
+<
+@ I
+
+@  H
+H@a
+
+ H
+;I
+
+
+
+
+GǑ@ʡ
+ ;GR N;3
+x H;;G
+
+G  @
+
+GH;ȡ@ʡ
+
+ N;
+
+
+G @ @
+
+G  
+
+G @ 
+
+G  @ 
+I ;
+
+ J
+J
+
+J9
+
+
+J
+
+
+
+!sstG
+@b
+
+GuuG
+
+@b
+
+!x 2 
+
+<
+
+x @
+x  "
+J 
+@b
+
+.
+
+
+
+J
+
+
+
+
+
+
+
+
+
+@~ ;
+
+
+~ 
+
+
+o
+
+
+
+H
+ $ɀ
+@Ip p  QIs Q #G)!D G)d
+
+Q;!
+
+
+
+
+@~ 
+
+
+
+G," ,@a
+QI
+
+
+Q
+?
+R+y P
+
+
+
+N" $
+> ?L ?LIB
+A
+
+ á
+ H!
+
+ à
+G
+x
+
+
+
+~
+
+~
+ @
+A
+bP L
+x G
+
+
+Gǡ@ʡ
+|~ x # +#L
+G@
+
+ 
++
+/R
+ 
+
+ G#
+#
+ q@) #q s 
+ s s
+ '
+L! o
+!*!
+G) 
+))Yx  Jx 
+))%x   x
+G) 
+))Qx  
+))
+G$)
+
+
+$
+@o
+
+
+
+' x   'LI! & ' ( ) ) a '   'LI!      H$ a '   CI #G D 
+#LGB0
+@
+@
+*
+
+
+ @o
+I@
+(@ (` } 
+ A R K
+(@x GB
+% B
+G
+H
+
+`
+x
+
+
+
+'x I*
+S@ & NI HB
+ @
+ N @o
+ @ N @n
+$ m
+
+G$)
+
+'   
+' x   'LI! & ' ) a '   'LI!   H$ a '  #G D % $
+o
+
+!L"L%'L e! ,a
+*
+$ʀ
+
+
+
+(
+% & & & r ! G%@
+G
+ 
+S&
+O
+
+*
+
+$ @o
+&I@
+
+
+,
+
+-x B
+
+G
+
+-J
+Fa
+
+
+
++
+
+
+g
+J+J
+  
+
+Q
+?
+R P 
+@ #\ a
+L+L
+  @$
+,
+
+
+I@ `
+ ~ I,D b
+@x
+-J
+
+ +-G%
+!
+
+-J+
+
+x 
+!
+ +
+ @a
+
+x
+ b@ʢ c
+$ "L2@
+
+
+
+ CAL c
+AA K)`
+!
+
+
+@
+ a  $a    '  
+    N,
+?G)á
+,@Ǡ  A+
++?a Ǡ A+PCG
+
+
+
+@
+G
+ 
+ߏN LJ
+J2 x 
+@Ȇ
+
+0
+`
+
+
+ C!?C`
+
+ 1
+ @
+M* @I
+G
+ *,@ 
+ @@
+M* @I
+ *,@ 
+ @
+M* @I
+
+ql
+ @0
+G
+ ,@ 
+ @@0
+ ,@ 
+ @0
+qp
+
+qp
+`
+
+qIq
+
+
+J
+O+
+a `
+z
+
+."@
+o@l
+
+J
+
+O+
+
+a `
+z
+
+."@
+o@l
+
+G@@
+
+
+
+
+
+H
+Hs
+
+
+@r
+
+@
+
+@
+
+x 
+
+@
+x 
+@^~
+ 
+
+
+
+
+r
+
+ I
+>~
+
+
+
+x H@B H@
+Q
+Q
+
+
+
+
+G@Q
+@
+ /
+B
+ /
+
+@ # 
+;p ;
+
+GС@ʡ
+
+G@!x 
+
+
+G
+!I@
+R B@h
+  ?@ C
+H:  B G) 
+@!D #
+G
+G
+GB G
+G
+}
+x Q
+
+;Gp ;
+
+GБ@ʡ
+
+ ;R` G)"j !  (! )I
+
+
+   @
+
+Aa a
+  
+ @G1
+N
+
+ I
+
+
+   @
+G
+Aa a
+@  
+ @
+
+I,J: 9>>>G@
+@
+ s@
+c@
+T@
+
+G$@
+@&x 
+
+
+
+
+
+
+
+G @c @J
+ I
+
+CJ
+G:G@c
+q@1@ɑ
+ I
+
+
+
+
+
+@x
+@x @9
+x jst
+r,s-nuu a u
+qs@!
+
+
+@@
+
+@@
+
+}
+
+
+   a
+I
+0020ȁ
+
+
+
+zJa CG
+
+
+Hƒ
+
+t@ # sRP @ # tR` G)"j ! 
+
+
+
+B @ # BH  # BP B @ @ s؀@ @ tx
+s
+
+B   # BH  # BP B @  s@IGr @ G 
+ H
+
+ 
+a 
+G@GA
+I
+I
+
+ @
+  # "@
+ I
+
+@*x 
+@
+O
+
+"
+x $  r$ 
+O
+,
+"
+
+
+
+G @ @ # 
+
+G"@  # @
+
+L
+
+A
+pA
+
+B@
+p3@
+
+
+
+
+1@A @@N  @ @
+
+@x
+
+
+
+
+
+P
+
+
+
+
+x @
+C
+
+
+
+
+@x 
+
+
+
+
+
+
+
+
+ C!?C`
+
+q
+
+
+
+K
+@ x
+PH NL
+x qMЀ @ LF
+PJ N,
+
+@x M @ Ҁ
+
+@
+0 q\
+J@
+@K<@Oq
+
+q
+L@
+A@
+A@
+c @
+0A a ,@
+
+`!
+
+
+A@
+0
+
+Db 
+DD0J 0!0
+
+
+ p T p0X  
+02p0
+K@
+
+1L3
+
+
+
+
+0
+p
+q
+  
+q @
+
+@
+
+@
+
+pF<@Op
+a@
+
+Q
+
+ 2@
+
+A
+
+
+
+ 2@
+
+A
+
+
+
+ 2@
+
+A
+
+
+ 2@
+
+A
+
+
+
+q 
+ 1@
+@ @ P 1I
+
+ 0P
+0@
+
+
+
+
+
+@% 1
+ @
+
+@M
+@" 1