MLK-17902 [IMX8QXP B0]VPU ENCODER and DECODER on IMX8QXP B0 board
authornxa13443 <chaofan.huang@nxp.com>
Fri, 23 Mar 2018 12:20:37 +0000 (20:20 +0800)
committerHaibo Chen <haibo.chen@nxp.com>
Thu, 12 Apr 2018 10:45:54 +0000 (18:45 +0800)
Add vpu decoder and encoder for imx8qxp b0 board,
decoder can support H265 H264 MPEG2 MPEG4 H263 etc
encoder can support H264

Signed-off-by: nxa13443 <chaofan.huang@nxp.com>
18 files changed:
arch/arm64/boot/dts/freescale/fsl-imx8qxp-lpddr4-arm2.dts
arch/arm64/boot/dts/freescale/fsl-imx8qxp.dtsi
drivers/mxc/Kconfig
drivers/mxc/Makefile
drivers/mxc/vpu-decoder-b0/Kconfig [new file with mode: 0755]
drivers/mxc/vpu-decoder-b0/Makefile [new file with mode: 0644]
drivers/mxc/vpu-decoder-b0/mediasys_types.h [new file with mode: 0644]
drivers/mxc/vpu-decoder-b0/vpu_b0.c [new file with mode: 0755]
drivers/mxc/vpu-decoder-b0/vpu_b0.h [new file with mode: 0644]
drivers/mxc/vpu-decoder-b0/vpu_rpc.c [new file with mode: 0644]
drivers/mxc/vpu-decoder-b0/vpu_rpc.h [new file with mode: 0644]
drivers/mxc/vpu-encoder-b0/Kconfig [new file with mode: 0755]
drivers/mxc/vpu-encoder-b0/Makefile [new file with mode: 0644]
drivers/mxc/vpu-encoder-b0/mediasys_types.h [new file with mode: 0644]
drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.c [new file with mode: 0644]
drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.h [new file with mode: 0644]
drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.c [new file with mode: 0644]
drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.h [new file with mode: 0644]

index 986d258..07cf13d 100644 (file)
                };
        };
 };
+&vpu_decoder {
+       status = "okay";
+ };
+
+&vpu_encoder {
+       status = "okay";
+};
index 3e4bd84..e9f1cb4 100644 (file)
                        no-map;
                        reg = <0 0x8e000000 0 0x1ffffff>;
                };
-
+               decoder_boot: decoder_boot@0x88000000 {
+                       no-map;
+                       reg = <0 0x88000000 0 0x2000000>;
+               };
+               encoder_boot: encoder_boot@0x8A000000 {
+                       no-map;
+                       reg = <0 0x8A000000 0 0x2000000>;
+               };
                /* global autoconfigured region for contiguous allocations */
                linux,cma {
                        compatible = "shared-dma-pool";
                        alloc-ranges = <0 0x90000000 0 0x28000000>;
                        linux,cma-default;
                };
-
                rpmsg_reserved: rpmsg@0xb8000000 {
                        no-map;
                        reg = <0 0xb8000000 0 0x400000>;
                };
+               decoder_rpc: decoder_rpc@0xB9000000 {
+                       no-map;
+                       reg = <0 0xB9000000 0 0x1000000>;
+               };
+               encoder_rpc: encoder_rpc@0xBA000000 {
+                       no-map;
+                       reg = <0 0xBA000000 0 0x1000000>;
+               };
        };
 
        gic: interrupt-controller@51a00000 {
                fsl,hifi_ap_mu_id = <13>;
                status = "okay";
        };
+       mu_m4: mu_m4@37440000 {
+               compatible = "fsl,imx8-mu0-vpu-m4";
+               reg = <0x0 0x37440000 0x0 0x10000>;
+               interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+               fsl,vpu_ap_mu_id = <15>;
+               status = "okay";
+       };
 
+       mu_m0: mu_m0@2d000000 {
+               compatible = "fsl,imx8-mu0-vpu-m0";
+               reg = <0x0 0x2d000000 0x0 0x10000>;
+               interrupts = <GIC_SPI 469 IRQ_TYPE_LEVEL_HIGH>;
+               fsl,vpu_ap_mu_id = <16>;
+               status = "okay";
+       };
+
+       mu1_m0: mu1_m0@2d020000 {
+               compatible = "fsl,imx8-mu1-vpu-m0";
+               reg = <0x0 0x2d020000 0x0 0x10000>;
+               interrupts = <GIC_SPI 470 IRQ_TYPE_LEVEL_HIGH>;
+               fsl,vpu_ap_mu_id = <17>;
+               status = "okay";
+       };
        clk: clk {
                compatible = "fsl,imx8qxp-clk";
                #clock-cells = <1>;
                status = "disabled";
        };
 
+       vpu_decoder: vpu_decoder@2c000000 {
+               compatible = "nxp,imx8qm-vpu-decoder", "nxp,imx8qxp-vpu-decoder";
+               boot-region = <&decoder_boot>;
+               rpc-region = <&decoder_rpc>;
+               reg = <0x0 0x2c000000 0x0 0x1000000>;
+               reg-names = "vpu_regs";
+               clocks = <&clk IMX8QXP_VPU_DEC_CLK>;
+               clock-names = "vpu_clk";
+               assigned-clocks = <&clk IMX8QXP_VPU_DEC_CLK>;
+               assigned-clock-rates = <600000000>;
+               power-domains = <&pd_vpu_dec>;
+               status = "disabled";
+       };
+
+       vpu_encoder: vpu_encoder@2d000000 {
+               compatible = "nxp,imx8qm-vpu-encoder", "nxp,imx8qxp-vpu-encoder";
+               boot-region = <&encoder_boot>;
+               rpc-region = <&encoder_rpc>;
+               reg = <0x0 0x2d000000 0x0 0x1000000>;
+               reg-names = "vpu_regs";
+               clocks = <&clk IMX8QXP_VPU_ENC_CLK>;
+               clock-names = "vpu_encoder_clk";
+               assigned-clocks = <&clk IMX8QXP_VPU_ENC_CLK>;
+               assigned-clock-rates = <600000000>;
+               power-domains = <&pd_vpu_enc>;
+               status = "disabled";
+       };
        imx_rpmsg: imx_rpmsg {
                compatible = "fsl,rpmsg-bus", "simple-bus";
                #address-cells = <2>;
index f5c177e..fc6fa30 100755 (executable)
@@ -11,6 +11,8 @@ source "drivers/mxc/hdp/Kconfig"
 
 if ARCH_MXC_ARM64
 source "drivers/mxc/vpu-malone/Kconfig"
+source "drivers/mxc/vpu-decoder-b0/Kconfig"
+source "drivers/mxc/vpu-encoder-b0/Kconfig"
 endif
 
 if ARCH_MXC
index 3347c47..302c309 100755 (executable)
@@ -8,3 +8,5 @@ obj-$(CONFIG_MXC_MIPI_CSI2) += mipi/
 obj-$(CONFIG_MXC_HANTRO) += hantro/
 obj-$(CONFIG_MXC_VPU_MALONE) += vpu-malone/
 obj-$(CONFIG_MX8_HDP)  += hdp/
+obj-$(CONFIG_MXC_VPU_DECODER) += vpu-decoder-b0/
+obj-$(CONFIG_MXC_VPU_ENCODER) += vpu-encoder-b0/
diff --git a/drivers/mxc/vpu-decoder-b0/Kconfig b/drivers/mxc/vpu-decoder-b0/Kconfig
new file mode 100755 (executable)
index 0000000..094d656
--- /dev/null
@@ -0,0 +1,20 @@
+#
+# Codec configuration
+#
+
+menu "MXC VPU(Video Processing Unit) B0 DECODER support"
+
+config MXC_VPU_DECODER
+         tristate "Support for MXC VPU(Video Processing Unit) DECODER"
+         default y
+       ---help---
+         The VPU codec device provides codec function for H.265 H.264 MPEG2 MPEG4 etc.
+
+config MXC_VPU_DECODER_DEBUG
+       bool "MXC VPU DECODER debugging"
+       depends on MXC_VPU_DECODER != n
+       help
+         This is an option for the developers; most people should
+         say N here.  This enables MXC VPU driver debugging.
+
+endmenu
diff --git a/drivers/mxc/vpu-decoder-b0/Makefile b/drivers/mxc/vpu-decoder-b0/Makefile
new file mode 100644 (file)
index 0000000..af74ce4
--- /dev/null
@@ -0,0 +1,15 @@
+##
+## Makefile for the VPU and M0 driver
+##
+DEFINES += -D HANDLE_EOS \
+                  -D REBOOT=1 \
+                  -D BOOT_ARCH=0
+
+EXTRA_CFLAGS += $(DEFINES)
+
+obj-y = vpu-decoder.o
+vpu-decoder-objs = vpu_b0.o \
+       vpu_rpc.o
+
+clean:
+       rm -rf $(vpu-decoder-objs)
diff --git a/drivers/mxc/vpu-decoder-b0/mediasys_types.h b/drivers/mxc/vpu-decoder-b0/mediasys_types.h
new file mode 100644 (file)
index 0000000..26f8fb7
--- /dev/null
@@ -0,0 +1,767 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MEDIASYS_TYPES_H_
+#define _MEDIASYS_TYPES_H_
+
+typedef unsigned int u_int32;
+typedef unsigned char u_int8;
+typedef unsigned long u_int64;
+typedef unsigned int BOOL;
+#define FALSE 0
+#define TRUE 1
+#define VPU_MAX_NUM_STREAMS 4
+#define VID_API_NUM_STREAMS 4
+#define VID_API_MAX_BUF_PER_STR 3
+#define VID_API_MAX_NUM_MVC_VIEWS 4
+#define MEDIAIP_MAX_NUM_MALONES 2
+#define MEDIAIP_MAX_NUM_MALONE_IRQ_PINS 2
+#define MEDIAIP_MAX_NUM_WINDSORS 1
+#define MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS 2
+#define MEDIAIP_MAX_NUM_CMD_IRQ_PINS 2
+#define MEDIAIP_MAX_NUM_MSG_IRQ_PINS 1
+#define MEDIAIP_MAX_NUM_TIMER_IRQ_PINS 4
+#define MEDIAIP_MAX_NUM_TIMER_IRQ_SLOTS 4
+#define VID_API_COMMAND_LIMIT    64
+#define VID_API_MESSAGE_LIMIT    256
+
+#define API_CMD_AVAILABLE            0x0
+#define API_CMD_INCOMPLETE           0x1
+#define API_CMD_BUFFER_ERROR         0x2
+#define API_CMD_UNAVAILABLE          0x3
+#define API_MSG_AVAILABLE            0x0
+#define API_MSG_INCOMPLETE           0x1
+#define API_MSG_BUFFER_ERROR         0x2
+#define API_MSG_UNAVAILABLE          0x3
+
+typedef enum {
+       FRAME_ALLOC = 0,
+       FRAME_FREE,
+       FRAME_DECODED,
+       FRAME_READY,
+       FRAME_RELEASE,
+} FRAME_BUFFER_STAT;
+
+typedef enum {
+       VPU_APP,
+       VPU_DRIVER,
+       VPU_DECODER,
+} FRAME_BUFFER_OWNER;
+
+typedef enum {
+       MEDIAIP_FRAME_REQ = 0,
+       MEDIAIP_MBI_REQ,
+       MEDIAIP_DCP_REQ,
+       MEDIAIP_REQ_LAST = MEDIAIP_DCP_REQ
+
+} MEDIAIP_MEM_REQ;
+
+typedef struct {
+       u_int32          uNum;
+       MEDIAIP_MEM_REQ  eType;
+} MEDIA_PLAYER_FSREQ;
+
+typedef struct {
+       u_int32          uFSIdx;
+       MEDIAIP_MEM_REQ  eType;
+       BOOL             bNotDisplayed;
+} MEDIA_PLAYER_FSREL;
+
+typedef enum {
+       /* Non-Stream Specific messages   */
+       MEDIA_PLAYER_API_MODE_INVALID     = 0x00,
+       MEDIA_PLAYER_API_MODE_PARSE_STEP  = 0x01,
+       MEDIA_PLAYER_API_MODE_DECODE_STEP = 0x02,
+       MEDIA_PLAYER_API_MODE_CONTINUOUS  = 0x03
+} MEDIA_PLAYER_API_MODE;
+
+typedef enum {
+       /* Non-Stream Specific messages   */
+       MEDIA_PLAYER_FS_CTRL_MODE_INTERNAL    = 0x00,
+       MEDIA_PLAYER_FS_CTRL_MODE_EXTERNAL    = 0x01
+} MEDIA_PLAYER_FS_CTRL_MODE;
+
+typedef enum {
+       /* Non-Stream Specific messages   */
+       VID_API_CMD_NULL              = 0x00,
+       VID_API_CMD_PARSE_NEXT_SEQ    = 0x01,
+       VID_API_CMD_PARSE_NEXT_I      = 0x02,
+       VID_API_CMD_PARSE_NEXT_IP     = 0x03,
+       VID_API_CMD_PARSE_NEXT_ANY    = 0x04,
+       VID_API_CMD_DEC_PIC           = 0x05,
+       VID_API_CMD_UPDATE_ES_WR_PTR  = 0x06,
+       VID_API_CMD_UPDATE_ES_RD_PTR  = 0x07,
+       VID_API_CMD_UPDATE_UDATA      = 0x08,
+       VID_API_CMD_GET_FSINFO        = 0x09,
+       VID_API_CMD_SKIP_PIC          = 0x0a,
+       VID_API_CMD_DEC_CHUNK         = 0x0b,
+       VID_API_CMD_START             = 0x10,
+       VID_API_CMD_STOP              = 0x11,
+       VID_API_CMD_ABORT             = 0x12,
+       VID_API_CMD_RST_BUF           = 0x13,
+       VID_API_CMD_FS_RELEASE        = 0x15,
+       VID_API_CMD_MEM_REGION_ATTACH = 0x16,
+       VID_API_CMD_MEM_REGION_DETACH = 0x17,
+       VID_API_CMD_MVC_VIEW_SELECT   = 0x18,
+       VID_API_CMD_FS_ALLOC          = 0x19,
+       VID_API_CMD_DBG_GET_STATUS    = 0x1C,
+       VID_API_CMD_DBG_START_LOG     = 0x1D,
+       VID_API_CMD_DBG_STOP_LOG      = 0x1E,
+       VID_API_CMD_DBG_DUMP_LOG      = 0x1F,
+       /* Begin Encode CMDs */
+       VID_API_CMD_YUV_READY         = 0x20,
+#if BOOT_ARCH == REBOOT
+       VID_API_CMD_SNAPSHOT          = 0xAA,
+       VID_API_CMD_ROLL_SNAPSHOT     = 0xAB,
+       VID_API_CMD_LOCK_SCHEDULER    = 0xAC,
+       VID_API_CMD_UNLOCK_SCHEDULER  = 0xAD,
+#endif
+       VID_API_CMD_CQ_FIFO_DUMP      = 0xAE,
+       VID_API_CMD_DBG_FIFO_DUMP     = 0xAF,
+       VID_API_CMD_SVC_ILP           = 0xBB,
+       VID_API_CMD_INVALID           = 0xFF
+
+} TB_API_DEC_CMD;
+
+typedef enum {
+       /* Non-Stream Specific messages    */
+       VID_API_EVENT_NULL            = 0x00,
+       VID_API_EVENT_RESET_DONE      = 0x01,
+       VID_API_EVENT_SEQ_HDR_FOUND   = 0x02,
+       VID_API_EVENT_PIC_HDR_FOUND   = 0x03,
+       VID_API_EVENT_PIC_DECODED     = 0x04,
+       VID_API_EVENT_FIFO_LOW        = 0x05,
+       VID_API_EVENT_FIFO_HIGH       = 0x06,
+       VID_API_EVENT_FIFO_EMPTY      = 0x07,
+       VID_API_EVENT_FIFO_FULL       = 0x08,
+       VID_API_EVENT_BS_ERROR        = 0x09,
+       VID_API_EVENT_UDATA_FIFO_UPTD = 0x0A,
+       VID_API_EVENT_RES_CHANGE      = 0x0B,
+       VID_API_EVENT_FIFO_OVF        = 0x0C,
+       VID_API_EVENT_CHUNK_DECODED   = 0x0D,
+       VID_API_EVENT_REQ_FRAME_BUFF  = 0x10,
+       VID_API_EVENT_FRAME_BUFF_RDY  = 0x11,
+       VID_API_EVENT_REL_FRAME_BUFF  = 0x12,
+       VID_API_EVENT_STR_BUF_RST     = 0x13,
+       VID_API_EVENT_RET_PING        = 0x14,      /* Temp here - rationalise debug events at bottom */
+       VID_API_EVENT_QMETER          = 0x15,
+       VID_API_EVENT_STR_FMT_CHANGE  = 0x16,
+       VID_API_EVENT_MIPS_XCPT       = 0x17,
+       VID_API_EVENT_START_DONE      = 0x18,
+       VID_API_EVENT_STOPPED         = 0x19,
+       VID_API_EVENT_ABORT_DONE      = 0x1A,
+       VID_API_EVENT_FINISHED        = 0x1B,
+       VID_API_EVENT_DBG_STAT_UPDATE = 0x1C,
+       VID_API_EVENT_DBG_LOG_STARTED = 0x1D,
+       VID_API_EVENT_DBG_LOG_STOPPED = 0x1E,
+       VID_API_EVENT_DBG_LOG_UPDATED = 0x1F,
+       VID_API_EVENT_DBG_MSG_DEC     = 0x20,
+       VID_API_EVENT_DEC_SC_ERR      = 0x21,
+       VID_API_EVENT_CQ_FIFO_DUMP    = 0x22,
+       VID_API_EVENT_DBG_FIFO_DUMP   = 0x23,
+       VID_API_EVENT_DEC_CHECK_RES   = 0x24,
+       VID_API_EVENT_DEC_CFG_INFO    = 0x25,
+       VID_API_EVENT_INVALID         = 0xFF
+
+} TB_API_DEC_EVENT;
+
+typedef enum {
+       MEDIAIP_PLAYMODE_CONNECTIVITY = 0,
+       MEDIAIP_PLAYMODE_BROADCAST,
+       MEDIAIP_PLAYMODE_BROADCAST_DSS,
+       MEDIAIP_PLAYMODE_LAST = MEDIAIP_PLAYMODE_BROADCAST_DSS
+
+} MEDIA_IP_PLAYMODE;
+
+typedef enum {
+       MEDIA_IP_FMT_NULL        = 0x0,
+       MEDIA_IP_FMT_AVC         = 0x1,
+       MEDIA_IP_FMT_VC1         = 0x2,
+       MEDIA_IP_FMT_MP2         = 0x3,
+       MEDIA_IP_FMT_AVS         = 0x4,
+       MEDIA_IP_FMT_ASP         = 0x5,
+       MEDIA_IP_FMT_JPG         = 0x6,
+       MEDIA_IP_FMT_RV          = 0x7,
+       MEDIA_IP_FMT_VP6         = 0x8,
+       MEDIA_IP_FMT_SPK         = 0x9,
+       MEDIA_IP_FMT_VP8         = 0xA,
+       MEDIA_IP_FMT_MVC         = 0xB,
+       MEDIA_IP_FMT_VP3         = 0xC,
+       MEDIA_IP_FMT_HEVC        = 0xD,
+       MEDIA_IP_FMT_AUTO_DETECT = 0xAD00,
+       MEDIA_IP_FMT_ALL         = (int)0xAAAAAAAA,
+       MEDIA_IP_FMT_UNSUPPORTED = (int)0xFFFFFFFF,
+       MEDIA_IP_FMT_LAST = MEDIA_IP_FMT_UNSUPPORTED
+
+} MEDIA_IP_FORMAT;
+
+typedef enum {
+       VSys_FrmtNull = 0x0,
+       VSys_AvcFrmt  = 0x1,
+       VSys_Mp2Frmt  = 0x2,
+       VSys_Vc1Frmt  = 0x3,
+       VSys_AvsFrmt  = 0x4,
+       VSys_AspFrmt  = 0x5,
+       VSys_JpgFrmt  = 0x6,
+       VSys_RvFrmt   = 0x7,
+       VSys_Vp6Frmt  = 0x8,
+       VSys_SpkFrmt  = 0x9,
+       VSys_Vp8Frmt  = 0xA,
+       VSys_HevcFrmt = 0xB,
+       VSys_LastFrmt = VSys_HevcFrmt
+} TB_API_DEC_FMT;
+
+typedef struct {
+       u_int32 bTopFldFirst;
+       u_int32 bRptFstField;
+       u_int32 uDispVerRes;
+       u_int32 uDispHorRes;
+       u_int32 uCentreVerOffset;
+       u_int32 uCentreHorOffset;
+       u_int32 uCropLeftRightOffset;
+       u_int32 uCropTopBotOffset;
+
+} MediaIPFW_Video_PicDispInfo;
+
+typedef struct MediaIPFW_PicPerfInfo {
+       u_int32 uMemCRC;
+       u_int32 uBSCRC;
+       u_int32 uSlcActiveCnt;
+       u_int32 uIBEmptyCnt;
+       u_int32 uBaseMemCRC;
+
+       u_int32 uBaseCRCSkip;
+       u_int32 uBaseCRCDrop;
+       BOOL    bBaseCRCValid;
+
+       u_int32 uCRC0;
+       u_int32 uCRC1;
+       u_int32 uCRC2;
+       u_int32 uCRC3;
+       u_int32 uCRC4;
+       u_int32 uCRC5;
+
+       u_int32 uFrameActCount;
+       u_int32 uRbspBytesCount;
+       u_int32 uDpbReadCount;
+       u_int32 uMprWaitCount;
+       u_int32 uAccQP;
+       u_int32 uCacheStat;
+       u_int32 mbq_full;
+       u_int32 mbq_empty;
+       u_int32 slice_cnt;
+       u_int32 mb_count;
+
+       u_int32 uTotalTime_us;
+       u_int32 uTotalFwTime_us;
+
+       u_int32 uProcIaccTotRdCnt;
+       u_int32 uProcDaccTotRdCnt;
+       u_int32 uProcDaccTotWrCnt;
+       u_int32 uProcDaccRegRdCnt;
+       u_int32 uProcDaccRegWrCnt;
+       u_int32 uProcDaccRngRdCnt;
+       u_int32 uProcDaccRngWrCnt;
+
+} MediaIPFW_Video_PicPerfInfo;
+
+typedef struct {
+       u_int32 mb_count;
+       u_int32 slice_cnt;
+
+       /* Front End Metrics */
+       u_int32 uDFEBinsUsed;
+       u_int32 uDFECycleCount;
+       u_int32 uDFESliceCycleCount;
+       u_int32 uDFEIBWaitCount;
+       u_int32 uDFENumBytes;
+
+       u_int32 uProcIaccTotRdCnt;
+       u_int32 uProcDaccTotRdCnt;
+       u_int32 uProcDaccTotWrCnt;
+       u_int32 uProcDaccRegRdCnt;
+       u_int32 uProcDaccRegWrCnt;
+       u_int32 uProcDaccRngRdCnt;
+       u_int32 uProcDaccRngWrCnt;
+
+       /* Back End metrics */
+       u_int32 uNumBEUsed;
+       u_int32 uTotalTime_us;
+       u_int32 uTotalFwTime_us;
+       u_int32 uDBECycleCount[0x2];
+       u_int32 uDBESliceCycleCount[0x2];
+       u_int32 uDBEMprWaitCount[0x2];
+       u_int32 uDBEWaitCount[0x2];
+       u_int32 uDBECRC[0x2];
+       u_int32 uDBETotalTime_us[0x2];
+
+       u_int32 uDBEMPRPRXWaitCount[0x2];
+       u_int32 uDBEPXDPRXWaitCount[0x2];
+       u_int32 uDBEFCHPLQWaitCount[0x2];
+       u_int32 uDBEPXDPLQWaitCount[0x2];
+
+       u_int32 uDBEFchWordsCount[0x2];
+       u_int32 uDBEDpbCRC[0x2];
+       u_int32 uDBEDpbReadCount[0x2];
+       u_int32 uDBECacheStats[0x2];
+
+} MediaIPFW_Video_PicPerfDcpInfo, *pMediaIPFW_Video_PicPerfDcpInfo;
+
+typedef struct {
+       u_int32 uPicType;
+       u_int32 uPicStruct;
+       u_int32 bLastPicNPF;
+       u_int32 uPicStAddr;
+       u_int32 uFrameStoreID;
+       MediaIPFW_Video_PicDispInfo    DispInfo;
+       MediaIPFW_Video_PicPerfInfo    PerfInfo;
+       MediaIPFW_Video_PicPerfDcpInfo PerfDcpInfo;
+       u_int32 bUserDataAvail;
+       u_int32 uPercentInErr;
+
+       u_int32 uBbdHorActive;
+       u_int32 uBbdVerActive;
+       u_int32 uBbdLogoActive;
+       u_int32 uBbdBotPrev;
+       u_int32 uBbdMinColPrj;
+       u_int32 uBbdMinRowPrj;
+       u_int32 uFSBaseAddr;
+
+       /* Only for RealVideo RPR */
+       u_int32 uRprPicWidth;
+       u_int32 uRprPicHeight;
+
+       /*only for divx3*/
+       u_int32 uFrameRate;
+
+} MediaIPFW_Video_PicInfo;
+
+
+typedef struct {
+       u_int32 bClosedGop;
+       u_int32 bBrokenLink;
+} MediaIPFW_Video_GopInfo;
+
+typedef struct {
+       u_int32 uIQuant;
+       u_int32 uIQuantAvail;
+       u_int32 uGopBitRate;
+       u_int32 uGopBitRateAvail;
+
+} MediaIPFW_Video_QMeterInfo;
+
+typedef struct {
+       u_int32                  pPicInfoArrayBase;
+       u_int32 uNumSizeDescriptors;
+} MediaIPFW_Video_PicInfoBuffTabDesc;
+
+typedef struct {
+       u_int32                  pGopInfoArrayBase;
+       u_int32 uNumSizeDescriptors;
+} MediaIPFW_Video_GopInfoBuffTabDesc;
+
+typedef struct {
+       u_int32                     pQMeterInfoArrayBase;
+       u_int32 uNumSizeDescriptors;
+} MediaIPFW_Video_QMeterInfoTabDesc;
+
+typedef struct {
+       u_int32 uMemChunkBase;
+       u_int32 uMemChunkSize;
+
+} MediaIPFW_Video_FrameBuffer;
+
+typedef struct {
+       u_int32 uUDataBase;
+       u_int32 uUDataTotalSize;
+       u_int32 uUDataSlotSize;
+
+} MediaIPFW_Video_UData;
+
+typedef struct {
+       u_int32 uDecStatusLogBase;
+       u_int32 uDecStatusLogSize;
+       u_int32 uDTVLogBase[VID_API_NUM_STREAMS];
+       u_int32 uDTVLogSize[VID_API_NUM_STREAMS];
+
+} MediaIPFW_Video_DbgLogDesc;
+
+typedef struct {
+       u_int32 uDTVLogBase[VID_API_NUM_STREAMS];
+       u_int32 uDTVLogSize[VID_API_NUM_STREAMS];
+
+} MediaIPFW_Video_EngAccessLogDesc;
+
+typedef struct MediaIPFW_FrameStore {
+       u_int32 uFrameStoreLumaBase;
+       u_int32 uFrameStoreChromaBase;
+
+} MediaIPFW_Video_FrameStore;
+
+typedef struct {
+       u_int32 uAddrFirstDescriptor;
+       u_int32 uNumSizeDescriptors;
+
+} MediaIPFW_Video_StreamBuffTabDesc;
+
+typedef struct {
+       u_int32 uAddrFirstDescriptor;
+       u_int32 uNumSizeDescriptors;
+} MediaIPFW_Video_UserDataBuffTabDesc;
+
+typedef struct {
+       u_int32 uNumRefFrms;
+       u_int32 uNumDPBFrms;
+       u_int32 uNumDFEAreas;
+       u_int32 uColorDesc;
+       u_int32 uProgressive;
+       u_int32 uVerRes;
+       u_int32 uHorRes;
+       u_int32 uParWidth;
+       u_int32 uParHeight;
+       u_int32 FrameRate;
+       u_int32 UDispAspRatio;
+       u_int32 uLevelIDC;
+       u_int32 uVerDecodeRes;
+       u_int32 uHorDecodeRes;
+       u_int32 uOverScan;
+       u_int32 uChromaFmt;
+       u_int32 uPAFF;
+       u_int32 uMBAFF;
+       u_int32 uBitDepthLuma;
+       u_int32 uBitDepthChroma;
+       u_int32 uMVCNumViews;
+       u_int32 uMVCViewList[VID_API_MAX_NUM_MVC_VIEWS];
+       u_int32 uFBCInUse;
+
+} MediaIPFW_Video_SeqInfo;
+
+typedef struct {
+       u_int32                  pSeqInfoArrayBase;
+       u_int32 uNumSizeDescriptors;
+} MediaIPFW_Video_SeqInfoBuffTabDesc;
+
+typedef struct {
+       u_int32 wptr;
+       u_int32 rptr;
+       u_int32 start;
+       u_int32 end;
+
+} BUFFER_DESCRIPTOR_TYPE, *pBUFFER_DESCRIPTOR_TYPE;
+
+typedef struct {
+       volatile u_int32 wptr;
+       volatile u_int32 rptr;
+       volatile u_int32 start;
+       volatile u_int32 end;
+       volatile u_int32 LWM;
+
+} STREAM_BUFFER_DESCRIPTOR_TYPE, *pSTREAM_BUFFER_DESCRIPTOR_TYPE;
+
+typedef struct {
+       u_int32 uRotationAngle;
+       u_int32 uHorizScaleFactor;
+       u_int32 uVertScaleFactor;
+       u_int32 uRotationMode;
+       u_int32 uRGBMode;
+       u_int32 uChunkMode; /* 0 ~ 1 */
+       u_int32 uLastChunk; /* 0 ~ 1 */
+       u_int32 uChunkRows; /* 0 ~ 255 */
+       u_int32 uNumBytes;
+       u_int32 uJpgCropXStart;
+       u_int32 uJpgCropYStart;
+       u_int32 uJpgCropWidth;
+       u_int32 uJpgCropHeight;
+       u_int32 uJpgMjpegMode;
+       u_int32 uJpgMjpegInterlaced;
+
+} MediaIPFW_Video_JpegParams;
+
+typedef struct {
+       u_int32                     pJpegParamArrayBase;
+       u_int32                    uNumSizeDescriptors;
+
+} MediaIPFW_Video_JpegParamTabDesc;
+
+typedef struct {
+       u_int32 uDispImm;
+       u_int32 uFourCC;
+       u_int32 uCodecVersion;
+       u_int32 uFrameRate;
+       u_int32 bbd_logo_width;
+       u_int32 bbd_lum_thr;
+       u_int32 bbd_coring;
+       u_int32 bbd_s_thr_row;
+       u_int32 bbd_p_thr_row;
+       u_int32 bbd_s_thr_logo_row;
+       u_int32 bbd_p_thr_logo_row;
+       u_int32 bbd_s_thr_col;
+       u_int32 bbd_p_thr_col;
+       u_int32 bbd_chr_thr_row;
+       u_int32 bbd_chr_thr_col;
+       u_int32 bbd_uv_mid_level;
+       u_int32 bbd_excl_win_mb_left;
+       u_int32 bbd_excl_win_mb_right;
+
+} MediaIPFW_Video_CodecParams;
+
+typedef struct {
+       u_int32 uFramePitch;
+
+} MediaIPFW_Video_PitchInfo;
+
+typedef struct {
+       u_int32 uWrPtr;
+       u_int32 uRdPtr;
+       u_int32 uStart;
+       u_int32 uEnd;
+       u_int32 uLo;
+       u_int32 uHi;
+
+} MediaIPFW_Video_BufDesc;
+
+typedef struct {
+       u_int32                      pCodecParamArrayBase;
+       u_int32                      uNumSizeDescriptors;
+
+} MediaIPFW_Video_CodecParamTabDesc;
+
+typedef struct {
+       u_int32 uRC4Key[0x8];
+       u_int32 uMemObfuscVal;
+
+} MediaIPFW_Video_Encrypt_Info, *pMediaIPFW_Video_Encrypt_Info;
+
+typedef struct {
+       u_int32 uCfgCookie;
+
+       u_int32 uNumMalones;
+       u_int32 uMaloneBaseAddress[MEDIAIP_MAX_NUM_MALONES];
+       u_int32 uHifOffset[MEDIAIP_MAX_NUM_MALONES];
+       u_int32 uMaloneIrqPin[MEDIAIP_MAX_NUM_MALONES][MEDIAIP_MAX_NUM_MALONE_IRQ_PINS];
+       u_int32 uMaloneIrqTarget[MEDIAIP_MAX_NUM_MALONES][MEDIAIP_MAX_NUM_MALONE_IRQ_PINS];
+
+       u_int32 uNumWindsors;
+       u_int32 uWindsorBaseAddress[MEDIAIP_MAX_NUM_WINDSORS];
+       u_int32 uWindsorIrqPin[MEDIAIP_MAX_NUM_WINDSORS][MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS];
+       u_int32 uWindsorIrqTarget[MEDIAIP_MAX_NUM_WINDSORS][MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS];
+
+       u_int32 uCmdIrqPin[MEDIAIP_MAX_NUM_CMD_IRQ_PINS];
+       u_int32 uCmdIrqTarget[MEDIAIP_MAX_NUM_CMD_IRQ_PINS];
+
+       u_int32 uMsgIrqPin[MEDIAIP_MAX_NUM_MSG_IRQ_PINS];
+       u_int32 uMsgIrqTarget[MEDIAIP_MAX_NUM_MSG_IRQ_PINS];
+
+       u_int32 uSysClkFreq;
+       u_int32 uNumTimers;
+       u_int32 uTimerBaseAddr;
+       u_int32 uTimerIrqPin[MEDIAIP_MAX_NUM_TIMER_IRQ_PINS];
+       u_int32 uTimerIrqTarget[MEDIAIP_MAX_NUM_TIMER_IRQ_PINS];
+       u_int32 uTimerSlots[MEDIAIP_MAX_NUM_TIMER_IRQ_SLOTS];
+
+       u_int32 uGICBaseAddr;
+       u_int32 uUartBaseAddr;
+
+       u_int32 uDPVBaseAddr;
+       u_int32 uDPVIrqPin;
+       u_int32 uDPVIrqTarget;
+
+       u_int32 uPixIfBaseAddr;
+
+       u_int32 pal_trace_level;
+       u_int32 pal_trace_destination;
+
+       u_int32 pal_trace_level1;
+       u_int32 pal_trace_destination1;
+
+       u_int32 uHeapBase;
+       u_int32 uHeapSize;
+
+       u_int32 uFSLCacheBaseAddr;
+
+} MEDIAIP_FW_SYSTEM_CONFIG, *pMEDIAIP_FW_SYSTEM_CONFIG;
+
+typedef struct {
+       u_int32                                FwExecBaseAddr;
+       u_int32                                FwExecAreaSize;
+       MediaIPFW_Video_BufDesc                StreamCmdBufferDesc;
+       MediaIPFW_Video_BufDesc                StreamMsgBufferDesc;
+       u_int32                                StreamCmdIntEnable[VID_API_NUM_STREAMS];
+       MediaIPFW_Video_PitchInfo              StreamPitchInfo[VID_API_NUM_STREAMS];
+       u_int32                                StreamConfig[VID_API_NUM_STREAMS];
+       MediaIPFW_Video_CodecParamTabDesc          CodecParamTabDesc;                       /* TODO-KMC  should we just go ahead and remove the concept of tabdesc? It is basicaly a bad coding style used for pinkys anyway */
+       MediaIPFW_Video_JpegParamTabDesc       JpegParamTabDesc;
+#ifdef COREPLAY_API
+       pBUFFER_DESCRIPTOR_TYPE                pStreamBuffDesc[VID_API_NUM_STREAMS][VID_API_MAX_BUF_PER_STR];
+#else
+       u_int32                                pStreamBuffDesc[VID_API_NUM_STREAMS][VID_API_MAX_BUF_PER_STR];
+#endif
+       MediaIPFW_Video_SeqInfoBuffTabDesc     SeqInfoTabDesc;
+       MediaIPFW_Video_PicInfoBuffTabDesc     PicInfoTabDesc;
+       MediaIPFW_Video_GopInfoBuffTabDesc     GopInfoTabDesc;
+       MediaIPFW_Video_QMeterInfoTabDesc      QMeterInfoTabDesc;
+       u_int32                                StreamError[VID_API_NUM_STREAMS];
+       u_int32                                FWVersion;
+       u_int32                                uMVDMipsOffset;
+       u_int32                                uMaxDecoderStreams;
+       MediaIPFW_Video_DbgLogDesc             DbgLogDesc;
+       MediaIPFW_Video_FrameBuffer            StreamFrameBuffer[VID_API_NUM_STREAMS];
+       MediaIPFW_Video_FrameBuffer            StreamDCPBuffer[VID_API_NUM_STREAMS];
+       MediaIPFW_Video_UData                  UDataBuffer[VID_API_NUM_STREAMS];
+       MediaIPFW_Video_BufDesc                DebugBufferDesc;
+       MediaIPFW_Video_BufDesc                EngAccessBufferDesc[VID_API_NUM_STREAMS];
+       u_int32                                ptEncryptInfo[VID_API_NUM_STREAMS];
+       MEDIAIP_FW_SYSTEM_CONFIG               sSystemCfg;
+       u_int32                                uApiVersion;
+} DEC_RPC_HOST_IFACE, *pDEC_RPC_HOST_IFACE;
+
+//x means source data , y means destination data
+#define VID_STREAM_CONFIG_FORMAT_MASK            0x0000000F
+#define VID_STREAM_CONFIG_FORMAT_POS             0
+#define VID_STREAM_CONFIG_FORMAT_SET(x, y)          (*y = (*y | ((x << VID_STREAM_CONFIG_FORMAT_POS)&VID_STREAM_CONFIG_FORMAT_MASK)))
+
+#define VID_STREAM_CONFIG_STRBUFIDX_MASK         0x00000300
+#define VID_STREAM_CONFIG_STRBUFIDX_POS          8
+#define VID_STREAM_CONFIG_STRBUFIDX_SET(x, y)       (*y = (*y | ((x << VID_STREAM_CONFIG_STRBUFIDX_POS)&VID_STREAM_CONFIG_STRBUFIDX_MASK)))
+
+#define VID_STREAM_CONFIG_NOSEQ_MASK             0x00000400
+#define VID_STREAM_CONFIG_NOSEQ_POS              10
+#define VID_STREAM_CONFIG_NOSEQ_SET(x, y)          (*y = (*y | ((x << VID_STREAM_CONFIG_NOSEQ_POS)&VID_STREAM_CONFIG_NOSEQ_MASK)))
+
+#define VID_STREAM_CONFIG_DEBLOCK_MASK           0x00000800
+#define VID_STREAM_CONFIG_DEBLOCK_POS            11
+#define VID_STREAM_CONFIG_DEBLOCK_SET(x, y)         (*y = (*y | ((x << VID_STREAM_CONFIG_DEBLOCK_POS)&VID_STREAM_CONFIG_DEBLOCK_MASK)))
+
+#define VID_STREAM_CONFIG_DERING_MASK            0x00001000
+#define VID_STREAM_CONFIG_DERING_POS             12
+#define VID_STREAM_CONFIG_DERING_SET(x, y)          (*y = (*y | ((x << VID_STREAM_CONFIG_DERING_POS)&VID_STREAM_CONFIG_DERING_MASK)))
+
+#define VID_STREAM_CONFIG_IBWAIT_MASK            0x00002000
+#define VID_STREAM_CONFIG_IBWAIT_POS             13
+#define VID_STREAM_CONFIG_IBWAIT_SET(x, y)          (*y = (*y | ((x << VID_STREAM_CONFIG_IBWAIT_POS)&VID_STREAM_CONFIG_IBWAIT_MASK)))
+
+#define VID_STREAM_CONFIG_FBC_MASK               0x00004000
+#define VID_STREAM_CONFIG_FBC_POS                14
+#define VID_STREAM_CONFIG_FBC_SET(x, y)             (*y = (*y | ((x << VID_STREAM_CONFIG_FBC_POS)&VID_STREAM_CONFIG_FBC_MASK)))
+
+#define VID_STREAM_CONFIG_PLAY_MODE_MASK         0x00030000
+#define VID_STREAM_CONFIG_PLAY_MODE_POS          16
+#define VID_STREAM_CONFIG_PLAY_MODE_SET(x, y)       (*y = (*y | ((x << VID_STREAM_CONFIG_PLAY_MODE_POS)&VID_STREAM_CONFIG_PLAY_MODE_MASK)))
+
+#define VID_STREAM_CONFIG_ENABLE_DCP_MASK      0x00100000
+#define VID_STREAM_CONFIG_ENABLE_DCP_POS       20
+#define VID_STREAM_CONFIG_ENABLE_DCP_SET(x, y)    (*y = (*y | ((x << VID_STREAM_CONFIG_ENABLE_DCP_POS)&VID_STREAM_CONFIG_ENABLE_DCP_MASK)))
+
+#define VID_STREAM_CONFIG_NUM_STR_BUF_MASK       0x00600000
+#define VID_STREAM_CONFIG_NUM_STR_BUF_POS        21
+#define VID_STREAM_CONFIG_NUM_STR_BUF_SET(x, y)     (*y = (*y | ((x << VID_STREAM_CONFIG_NUM_STR_BUF_POS)&VID_STREAM_CONFIG_NUM_STR_BUF_MASK)))
+
+#define VID_STREAM_CONFIG_MALONE_USAGE_MASK      0x01800000
+#define VID_STREAM_CONFIG_MALONE_USAGE_POS       23
+#define VID_STREAM_CONFIG_MALONE_USAGE_SET(x, y)    (*y = (*y | ((x << VID_STREAM_CONFIG_MALONE_USAGE_POS)&VID_STREAM_CONFIG_MALONE_USAGE_MASK)))
+
+#define VID_STREAM_CONFIG_MULTI_VID_MASK         0x02000000
+#define VID_STREAM_CONFIG_MULTI_VID_POS          25
+#define VID_STREAM_CONFIG_MULTI_VID_SET(x, y)       (*y = (*y | ((x << VID_STREAM_CONFIG_MULTI_VID_POS)&VID_STREAM_CONFIG_MULTI_VID_MASK)))
+
+#define VID_STREAM_CONFIG_OBFUSC_EN_MASK         0x04000000
+#define VID_STREAM_CONFIG_OBFUSC_EN_POS          26
+#define VID_STREAM_CONFIG_OBFUSC_EN_SET(x, y)       (*y = (*y | ((x << VID_STREAM_CONFIG_OBFUSC_EN_POS)&VID_STREAM_CONFIG_OBFUSC_EN_MASK)))
+
+#define VID_STREAM_CONFIG_RC4_EN_MASK            0x08000000
+#define VID_STREAM_CONFIG_RC4_EN_POS             27
+#define VID_STREAM_CONFIG_RC4_EN_SET(x, y)          (*y = (*y | ((x << VID_STREAM_CONFIG_RC4_EN_POS)&VID_STREAM_CONFIG_RC4_EN_MASK)))
+
+#define VID_STREAM_CONFIG_MCX_MASK               0x10000000
+#define VID_STREAM_CONFIG_MCX_POS                28
+#define VID_STREAM_CONFIG_MCX_SET(x, y)             (*y = (*y | ((x << VID_STREAM_CONFIG_MCX_POS)&VID_STREAM_CONFIG_MCX_MASK)))
+
+#define VID_STREAM_CONFIG_PES_MASK               0x20000000
+#define VID_STREAM_CONFIG_PES_POS                29
+#define VID_STREAM_CONFIG_PES_SET(x, y)             ((*y = (*y | ((x << VID_STREAM_CONFIG_PES_POS)&VID_STREAM_CONFIG_PES_MASK))))
+
+#define VID_STREAM_CONFIG_NUM_DBE_MASK           0x40000000
+#define VID_STREAM_CONFIG_NUM_DBE_POS            30
+#define VID_STREAM_CONFIG_NUM_DBE_SET(x, y)         (*y = (*y | ((x << VID_STREAM_CONFIG_NUM_DBE_POS)&VID_STREAM_CONFIG_NUM_DBE_MASK)))
+
+#define VID_STREAM_CONFIG_FS_CTRL_MODE_MASK   0x80000000
+#define VID_STREAM_CONFIG_FS_CTRL_MODE_POS    31
+#define VID_STREAM_CONFIG_FS_CTRL_MODE_SET(x, y) (*y = (*y | ((x << VID_STREAM_CONFIG_FS_CTRL_MODE_POS)&VID_STREAM_CONFIG_FS_CTRL_MODE_MASK)))
+
+#define SCB_XREG_SLV_BASE                               0x00000000
+#define SCB_SCB_BLK_CTRL                                0x00070000
+#define SCB_BLK_CTRL_XMEM_RESET_SET                     0x00000090
+#define SCB_BLK_CTRL_CACHE_RESET_SET                    0x000000A0
+#define SCB_BLK_CTRL_CACHE_RESET_CLR                    0x000000A4
+#define SCB_BLK_CTRL_SCB_CLK_ENABLE_SET                 0x00000100
+
+#define XMEM_CONTROL                                    0x00041000
+
+#define DEC_MFD_XREG_SLV_BASE                           0x00180000
+
+#define MFD_HIF                                         0x0001C000
+#define MFD_HIF_MSD_REG_INTERRUPT_STATUS                0x00000018
+#define MFD_SIF                                         0x0001D000
+#define MFD_SIF_CTRL_STATUS                             0x000000F0
+#define MFD_SIF_INTR_STATUS                             0x000000F4
+#define MFD_MCX                                         0x00020800
+#define MFD_MCX_OFF                                     0x00000020
+
+#define MFD_BLK_CTRL                                    0x00030000
+#define MFD_BLK_CTRL_MFD_SYS_RESET_SET                  0x00000000
+#define MFD_BLK_CTRL_MFD_SYS_RESET_CLR                  0x00000004
+#define MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_SET           0x00000100
+#define MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_CLR           0x00000104
+
+#endif
diff --git a/drivers/mxc/vpu-decoder-b0/vpu_b0.c b/drivers/mxc/vpu-decoder-b0/vpu_b0.c
new file mode 100755 (executable)
index 0000000..e1a2356
--- /dev/null
@@ -0,0 +1,2636 @@
+/*
+ * Copyright 2018 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file vpu-b0.c
+ *
+ * copyright here may be changed later
+ *
+ *
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/file.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/platform_data/dma-imx.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/pm_runtime.h>
+#include <linux/mx8_mu.h>
+#include <linux/uaccess.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-dma-sg.h>
+
+#include "vpu_b0.h"
+
+unsigned int vpu_dbg_level_decoder = 0;
+
+static void vpu_api_event_handler(struct vpu_ctx *ctx, u_int32 uStrIdx, u_int32 uEvent, u_int32 *event_data);
+static void v4l2_vpu_send_cmd(struct vpu_ctx *ctx, uint32_t idx, uint32_t cmdid, uint32_t cmdnum, uint32_t *local_cmddata);
+static void add_eos(struct vpu_ctx *ctx, u_int32 uStrBufIdx);
+static void v4l2_update_stream_addr(struct vpu_ctx *ctx, uint32_t uStrBufIdx);
+
+static char *cmd2str[] = {
+       "VID_API_CMD_NULL",   /*0x0*/
+       "VID_API_CMD_PARSE_NEXT_SEQ", /*0x1*/
+       "VID_API_CMD_PARSE_NEXT_I",
+       "VID_API_CMD_PARSE_NEXT_IP",
+       "VID_API_CMD_PARSE_NEXT_ANY",
+       "VID_API_CMD_DEC_PIC",
+       "VID_API_CMD_UPDATE_ES_WR_PTR",
+       "VID_API_CMD_UPDATE_ES_RD_PTR",
+       "VID_API_CMD_UPDATE_UDATA",
+       "VID_API_CMD_GET_FSINFO",
+       "VID_API_CMD_SKIP_PIC",
+       "VID_API_CMD_DEC_CHUNK",  /*0x0b*/
+       "VID_API_CMD_UNDEFINED",
+       "VID_API_CMD_UNDEFINED",
+       "VID_API_CMD_UNDEFINED",
+       "VID_API_CMD_UNDEFINED",
+       "VID_API_CMD_START",         /*0x10*/
+       "VID_API_CMD_STOP",
+       "VID_API_CMD_ABORT",
+       "VID_API_CMD_RST_BUF",
+       "VID_API_CMD_UNDEFINED",
+       "VID_API_CMD_FS_RELEASE",
+       "VID_API_CMD_MEM_REGION_ATTACH",
+       "VID_API_CMD_MEM_REGION_DETACH",
+       "VID_API_CMD_MVC_VIEW_SELECT",
+       "VID_API_CMD_FS_ALLOC",   /*0x19*/
+       "VID_API_CMD_UNDEFINED",
+       "VID_API_CMD_UNDEFINED",
+       "VID_API_CMD_DBG_GET_STATUS", /*0x1C*/
+       "VID_API_CMD_DBG_START_LOG",
+       "VID_API_CMD_DBG_STOP_LOG",
+       "VID_API_CMD_DBG_DUMP_LOG",
+       "VID_API_CMD_YUV_READY",   /*0x20*/
+};
+
+static char *event2str[] = {
+       "VID_API_EVENT_NULL",  /*0x0*/
+       "VID_API_EVENT_RESET_DONE",  /*0x1*/
+       "VID_API_EVENT_SEQ_HDR_FOUND",
+       "VID_API_EVENT_PIC_HDR_FOUND",
+       "VID_API_EVENT_PIC_DECODED",
+       "VID_API_EVENT_FIFO_LOW",
+       "VID_API_EVENT_FIFO_HIGH",
+       "VID_API_EVENT_FIFO_EMPTY",
+       "VID_API_EVENT_FIFO_FULL",
+       "VID_API_EVENT_BS_ERROR",
+       "VID_API_EVENT_UDATA_FIFO_UPTD",
+       "VID_API_EVENT_RES_CHANGE",
+       "VID_API_EVENT_FIFO_OVF",
+       "VID_API_EVENT_CHUNK_DECODED",  /*0x0D*/
+       "VID_API_EVENT_UNDEFINED",
+       "VID_API_EVENT_UNDEFINED",
+       "VID_API_EVENT_REQ_FRAME_BUFF",  /*0x10*/
+       "VID_API_EVENT_FRAME_BUFF_RDY",
+       "VID_API_EVENT_REL_FRAME_BUFF",
+       "VID_API_EVENT_STR_BUF_RST",
+       "VID_API_EVENT_RET_PING",
+       "VID_API_EVENT_QMETER",
+       "VID_API_EVENT_STR_FMT_CHANGED",
+       "VID_API_EVENT_MIPS_XCPT",
+       "VID_API_EVENT_START_DONE",
+       "VID_API_EVENT_STOPPED",
+       "VID_API_EVENT_ABORT_DONE",
+       "VID_API_EVENT_FINISHED",
+       "VID_API_EVENT_DBG_STAT_UPDATE",
+       "VID_API_EVENT_DBG_LOG_STARTED",
+       "VID_API_EVENT_DBG_LOG_STOPPED",
+       "VID_API_EVENT_DBG_LOG_UPFATED",
+       "VID_API_EVENT_DBG_MSG_DEC",  /*0x20*/
+       "VID_API_EVENT_DEC_SC_ERR",
+       "VID_API_EVENT_CQ_FIFO_DUMP",
+       "VID_API_EVENT_DBG_FIFO_DUMP",
+       "VID_API_EVENT_DEC_CHECK_RES",
+       "VID_API_EVENT_DEC_CFG_INFO",  /*0x25*/
+};
+
+static char *bufstat[] = {
+       "FRAME_ALLOC",
+       "FRAME_FREE",
+       "FRAME_DECODED",
+       "FRAME_READY",
+       "FRAME_RELEASE",
+};
+
+static void vpu_log_event(u_int32 uEvent, u_int32 ctxid)
+{
+       if (uEvent > sizeof(event2str)-1)
+               vpu_dbg(LVL_INFO, "reveive event: 0x%X, ctx id:%d\n", uEvent, ctxid);
+       else
+               vpu_dbg(LVL_INFO, "recevie event: %s, ctx id:%d\n", event2str[uEvent], ctxid);
+}
+
+static void vpu_log_cmd(u_int32 cmdid, u_int32 ctxid)
+{
+       if (cmdid > sizeof(cmd2str)-1)
+               vpu_dbg(LVL_INFO, "send cmd: 0x%X, ctx id:%d\n", cmdid, ctxid);
+       else
+               vpu_dbg(LVL_INFO, "send cmd: %s ctx id:%d\n", cmd2str[cmdid], ctxid);
+}
+#ifdef DEBUG
+static void vpu_log_stat(u_int32 status, u_int32 bufferid, u_int32 ctxid)
+{
+       if (status > sizeof(bufstat)-1)
+               vpu_dbg(LVL_INFO, "buffer status: 0x%X, buffer id:%d ctx id:%d\n", status, bufferid, ctxid);
+       else
+               vpu_dbg(LVL_INFO, "buffer status: %s, buffer id:%d ctx id:%d\n", bufstat[status], bufferid, ctxid);
+}
+#endif
+static int find_buffer_id(struct vpu_ctx *ctx, u_int32 addr)
+{
+       struct vb2_data_req *p_data_req;
+       u_int32 LumaAddr;
+       u_int32 *pphy_address;
+       u_int32 i;
+
+       for (i = 0; i < VPU_MAX_BUFFER; i++) {
+               p_data_req = &ctx->q_data[V4L2_DST].vb2_reqs[i];
+               if (p_data_req->vb2_buf != NULL) {
+                       pphy_address = (u_int32 *)vb2_plane_cookie(p_data_req->vb2_buf, 0);
+                       LumaAddr = *pphy_address;
+                       if (LumaAddr == addr - ctx->dev->cm_offset)
+                               return i;
+               }
+       }
+
+       vpu_dbg(LVL_ERR, "error: %s() can't find suitable id based on address(0x%x)\n", __func__, addr);
+       return -1;
+}
+
+static void MU_sendMesgToFW(void __iomem *base, MSG_Type type, uint32_t value)
+{
+       MU_SendMessage(base, 1, value);
+       MU_SendMessage(base, 0, type);
+}
+#ifdef DEBUG
+static void vpu_log_shared_mem(struct vpu_ctx *ctx)
+{
+       struct vpu_dev *dev = ctx->dev;
+       struct shared_addr *This = &dev->shared_mem;
+       pDEC_RPC_HOST_IFACE pSharedInterface = (pDEC_RPC_HOST_IFACE)This->shared_mem_vir;
+       MediaIPFW_Video_BufDesc *pMsgDesc = &pSharedInterface->StreamMsgBufferDesc;
+       MediaIPFW_Video_BufDesc *pCmdDesc = &pSharedInterface->StreamCmdBufferDesc;
+       pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+       u_int32 index = ctx->str_index;
+
+       vpu_dbg(LVL_INFO, "msg: wr: 0x%x, rd: 0x%x, cmd: wr : 0x%x, rd: 0x%x\n",
+                       pMsgDesc->uWrPtr, pMsgDesc->uRdPtr, pCmdDesc->uWrPtr, pCmdDesc->uRdPtr);
+
+       pStrBufDesc = dev->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_MCX + MFD_MCX_OFF * index;
+       vpu_dbg(LVL_INFO, "data: wptr(0x%x) rptr(0x%x) start(0x%x) end(0x%x) uStrIdx(%d)\n",
+                       pStrBufDesc->wptr, pStrBufDesc->rptr, pStrBufDesc->start, pStrBufDesc->end, index);
+}
+#endif
+/*
+ * v4l2 ioctl() operation
+ *
+ */
+static struct vpu_v4l2_fmt  formats_compressed_dec[] = {
+       {
+               .name       = "H264 Encoded Stream",
+               .fourcc     = V4L2_PIX_FMT_H264,
+               .num_planes = 1,
+               .vdec_std   = VPU_VIDEO_AVC,
+       },
+       {
+               .name       = "VC1 Encoded Stream",
+               .fourcc     = V4L2_PIX_FMT_VC1_ANNEX_G,
+               .num_planes = 1,
+               .vdec_std   = VPU_VIDEO_VC1,
+       },
+       {
+               .name       = "VC1 RCV Encoded Stream",
+               .fourcc     = V4L2_PIX_FMT_VC1_ANNEX_L,
+               .num_planes = 1,
+               .vdec_std   = VPU_VIDEO_VC1,
+       },
+       {
+               .name       = "MPEG2 Encoded Stream",
+               .fourcc     = V4L2_PIX_FMT_MPEG2,
+               .num_planes = 1,
+               .vdec_std   = VPU_VIDEO_MPEG2,
+       },
+
+       {
+               .name       = "AVS Encoded Stream",
+               .fourcc     = VPU_PIX_FMT_AVS,
+               .num_planes = 1,
+               .vdec_std   = VPU_VIDEO_AVS,
+       },
+       {
+               .name       = "MPEG4 ASP Encoded Stream",
+               .fourcc     = VPU_PIX_FMT_ASP,
+               .num_planes = 1,
+               .vdec_std   = VPU_VIDEO_ASP,
+       },
+       {
+               .name       = "JPEG stills",
+               .fourcc     = V4L2_PIX_FMT_JPEG,
+               .num_planes = 1,
+               .vdec_std   = VPU_VIDEO_JPEG,
+       },
+       {
+               .name       = "RV8 Encoded Stream",
+               .fourcc     = VPU_PIX_FMT_RV8,
+               .num_planes = 1,
+               .vdec_std   = VPU_VIDEO_RV8,
+       },
+       {
+               .name       = "RV9 Encoded Stream",
+               .fourcc     = VPU_PIX_FMT_RV9,
+               .num_planes = 1,
+               .vdec_std   = VPU_VIDEO_RV9,
+       },
+       {
+               .name       = "VP6 Encoded Stream",
+               .fourcc     = VPU_PIX_FMT_VP6,
+               .num_planes = 1,
+               .vdec_std   = VPU_VIDEO_VP6,
+       },
+       {
+               .name       = "VP6 SPK Encoded Stream",
+               .fourcc     = VPU_PIX_FMT_SPK,
+               .num_planes = 1,
+               .vdec_std   = VPU_VIDEO_SPK,
+       },
+       {
+               .name       = "VP8 Encoded Stream",
+               .fourcc     = V4L2_PIX_FMT_VP8,
+               .num_planes = 1,
+               .vdec_std   = VPU_VIDEO_VP8,
+       },
+       {
+               .name       = "H264/MVC Encoded Stream",
+               .fourcc     = V4L2_PIX_FMT_H264_MVC,
+               .num_planes = 1,
+               .vdec_std   = VPU_VIDEO_AVC_MVC,
+       },
+       {
+               .name       = "H265 HEVC Encoded Stream",
+               .fourcc     = VPU_PIX_FMT_HEVC,
+               .num_planes = 1,
+               .vdec_std   = VPU_VIDEO_HEVC,
+       },
+       {
+               .name       = "VP9 Encoded Stream",
+               .fourcc     = VPU_PIX_FMT_VP9,
+               .num_planes = 1,
+               .vdec_std   = VPU_VIDEO_VP9,
+       },
+       {
+               .name       = "Logo",
+               .fourcc     = VPU_PIX_FMT_LOGO,
+               .num_planes = 1,
+               .vdec_std   = VPU_VIDEO_UNDEFINED,
+       },
+};
+
+static struct vpu_v4l2_fmt  formats_yuv_dec[] = {
+       {
+               .name       = "4:2:0 2 Planes Y/CbCr",
+               .fourcc     = V4L2_PIX_FMT_NV12,
+               .num_planes     = 2,
+               .vdec_std   = VPU_PF_YUV420_SEMIPLANAR,
+       },
+       {
+               .name       = "4:2:0 Y/Cb/Cr",
+               .fourcc     = V4L2_PIX_FMT_YUV420M,
+               .num_planes     = 2,
+               .vdec_std   = VPU_PF_YUV420_PLANAR,
+       },
+       {
+               .name       = "4:2:2 UYVY",
+               .fourcc     = V4L2_PIX_FMT_UYVY,
+               .num_planes     = 1,
+               .vdec_std   = VPU_PF_YUV420_PLANAR,
+       },
+       {
+               .name       = "8 bit tiles",
+               .fourcc     = VPU_PIX_FMT_TILED_8,
+               .num_planes     = 2,
+               .vdec_std   = VPU_PF_TILED_8BPP,
+       },
+       {
+               .name       = "10 bit tiles",
+               .fourcc     = VPU_PIX_FMT_TILED_10,
+               .num_planes     = 2,
+               .vdec_std   = VPU_PF_TILED_10BPP,
+       },
+};
+
+static int v4l2_ioctl_querycap(struct file *file,
+               void *fh,
+               struct v4l2_capability *cap
+               )
+{
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+       strncpy(cap->driver, "vpu B0", sizeof(cap->driver) - 1);
+       strlcpy(cap->card, "vpu B0", sizeof(cap->card));
+       strlcpy(cap->bus_info, "platform:", sizeof(cap->bus_info));
+       cap->version = KERNEL_VERSION(0, 0, 1);
+       cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+       return 0;
+}
+
+static int v4l2_ioctl_enum_fmt_vid_cap_mplane(struct file *file,
+               void *fh,
+               struct v4l2_fmtdesc *f
+               )
+{
+       struct vpu_v4l2_fmt *fmt;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+       if (f->index >= sizeof(formats_yuv_dec)/sizeof(formats_yuv_dec[0]))
+               return -EINVAL;
+
+       fmt = &formats_yuv_dec[f->index];
+       strlcpy(f->description, fmt->name, sizeof(f->description));
+       f->pixelformat = fmt->fourcc;
+       return 0;
+}
+static int v4l2_ioctl_enum_fmt_vid_out_mplane(struct file *file,
+               void *fh,
+               struct v4l2_fmtdesc *f
+               )
+{
+       struct vpu_v4l2_fmt *fmt;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (f->index >= sizeof(formats_compressed_dec)/sizeof(formats_compressed_dec[0]))
+               return -EINVAL;
+
+       fmt = &formats_compressed_dec[f->index];
+       strlcpy(f->description, fmt->name, sizeof(f->description));
+       f->pixelformat = fmt->fourcc;
+       f->flags |= V4L2_FMT_FLAG_COMPRESSED;
+       return 0;
+}
+
+static void caculate_frame_size(struct vpu_ctx *ctx)
+{
+       u_int32 width = ctx->pSeqinfo->uHorRes;
+       u_int32 height = ctx->pSeqinfo->uVerRes;
+       u_int32 luma_size;
+       u_int32 chroma_size;
+       u_int32 chroma_height;
+       bool bfield = false; //WARN need get it
+       bool bOffsetPadding = false; //WARN need get it
+       u_int32 uVertAlign = 256-1;
+
+       struct queue_data *q_data;
+
+       q_data = &ctx->q_data[V4L2_DST];
+
+       width = ((width + uVertAlign) & ~uVertAlign);
+       q_data->stride = width;
+       if (bfield)
+               height = ctx->pSeqinfo->uVerRes >> 0x1;
+       if (bOffsetPadding) {
+               height = ((height + 0xF) & 0xFFFFFFF0);
+               height += 0x10;
+       }
+
+       chroma_height = height >> 1;
+       height = ((height + uVertAlign) & ~uVertAlign);
+       chroma_height = ((chroma_height + uVertAlign) & ~uVertAlign);
+       luma_size = width * height;
+       chroma_size = width * chroma_height;
+       ctx->q_data[V4L2_DST].sizeimage[0] = luma_size;
+       ctx->q_data[V4L2_DST].sizeimage[1] = chroma_size;
+}
+
+static int v4l2_ioctl_g_fmt(struct file *file,
+               void *fh,
+               struct v4l2_format *f
+               )
+{
+       struct vpu_ctx *ctx =           v4l2_fh_to_ctx(fh);
+       struct v4l2_pix_format_mplane   *pix_mp = &f->fmt.pix_mp;
+       unsigned int i;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               pix_mp->pixelformat = V4L2_PIX_FMT_NV12;
+               pix_mp->width = ctx->pSeqinfo->uHorRes;
+               pix_mp->height = ctx->pSeqinfo->uVerRes;
+               pix_mp->field = V4L2_FIELD_ANY;
+               pix_mp->num_planes = 2;
+               pix_mp->colorspace = V4L2_COLORSPACE_REC709;
+
+               for (i = 0; i < pix_mp->num_planes; i++) {
+                       pix_mp->plane_fmt[i].bytesperline = ctx->q_data[V4L2_DST].stride;
+                       pix_mp->plane_fmt[i].sizeimage = ctx->q_data[V4L2_DST].sizeimage[i];
+               }
+       } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               pix_mp->width = 0;
+               pix_mp->height = 0;
+               pix_mp->field = V4L2_FIELD_ANY;
+               pix_mp->plane_fmt[0].bytesperline = 0;
+               pix_mp->plane_fmt[0].sizeimage = 0;
+               pix_mp->pixelformat = ctx->q_data[V4L2_SRC].fourcc;
+               pix_mp->num_planes = 1;
+       } else
+               return -EINVAL;
+       return 0;
+}
+
+static void set_video_standard(struct queue_data *q_data,
+               struct v4l2_format *f,
+               struct vpu_v4l2_fmt *pformat_table,
+               uint32_t table_size)
+{
+       unsigned int i;
+
+       for (i = 0; i < table_size; i++) {
+               if (pformat_table[i].fourcc == f->fmt.pix_mp.pixelformat)
+                       q_data->vdec_std = pformat_table[i].vdec_std;
+       }
+}
+
+static int v4l2_ioctl_s_fmt(struct file *file,
+               void *fh,
+               struct v4l2_format *f
+               )
+{
+       struct vpu_ctx                  *ctx = v4l2_fh_to_ctx(fh);
+       int                             ret = 0;
+       struct v4l2_pix_format_mplane   *pix_mp = &f->fmt.pix_mp;
+       struct queue_data               *q_data;
+       u_int32                         i;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               q_data = &ctx->q_data[V4L2_DST];
+
+               pix_mp->num_planes = 2;
+               pix_mp->colorspace = V4L2_COLORSPACE_REC709;
+               for (i = 0; i < pix_mp->num_planes; i++) {
+                       pix_mp->plane_fmt[i].bytesperline = ctx->q_data[V4L2_DST].stride;
+                       pix_mp->plane_fmt[i].sizeimage = ctx->q_data[V4L2_DST].sizeimage[i];
+               }
+               q_data->fourcc = pix_mp->pixelformat;
+               q_data->width = pix_mp->width;
+               q_data->height = pix_mp->height;
+               q_data->sizeimage[0] = pix_mp->plane_fmt[0].sizeimage;
+               q_data->rect.left = 0;
+               q_data->rect.top = 0;
+               q_data->rect.width = pix_mp->width;
+               q_data->rect.height = pix_mp->height;
+               set_video_standard(q_data, f, formats_yuv_dec, ARRAY_SIZE(formats_yuv_dec));
+       } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               q_data = &ctx->q_data[V4L2_SRC];
+               q_data->fourcc = pix_mp->pixelformat;
+               q_data->sizeimage[0] = pix_mp->plane_fmt[0].sizeimage;
+               set_video_standard(q_data, f, formats_compressed_dec, ARRAY_SIZE(formats_compressed_dec));
+       } else
+               ret = -EINVAL;
+
+       return ret;
+}
+
+static int v4l2_ioctl_expbuf(struct file *file,
+               void *fh,
+               struct v4l2_exportbuffer *buf
+               )
+{
+       struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+       struct queue_data *q_data;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               q_data = &ctx->q_data[V4L2_SRC];
+       else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               q_data = &ctx->q_data[V4L2_DST];
+       else
+               return -EINVAL;
+
+       return (vb2_expbuf(&q_data->vb2_q,
+                               buf
+                               ));
+}
+
+static int v4l2_ioctl_subscribe_event(struct v4l2_fh *fh,
+               const struct v4l2_event_subscription *sub
+               )
+{
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       switch (sub->type) {
+       case V4L2_EVENT_EOS:
+               return v4l2_event_subscribe(fh, sub, 0, NULL);
+       case V4L2_EVENT_SOURCE_CHANGE:
+               return v4l2_src_change_event_subscribe(fh, sub);
+       default:
+               return -EINVAL;
+       }
+}
+static void alloc_mbi_buffer(struct vpu_ctx *ctx,
+               struct queue_data *This,
+               u_int32 count)
+{
+       u_int32 uAlign = 0x800-1;
+       u_int32 mbi_num;
+       u_int32 mbi_size;
+       u_int32 i;
+
+
+       if (count >= MAX_MBI_NUM)
+               mbi_num = MAX_MBI_NUM;
+       else
+               mbi_num = count;
+       ctx->mbi_num = mbi_num;
+
+       mbi_size = (This->sizeimage[0]+This->sizeimage[1])/4;
+       mbi_size = ((mbi_size + uAlign) & ~uAlign);
+       ctx->mbi_size = mbi_size;
+       for (i = 0; i < mbi_num; i++) {
+               ctx->mbi_dma_virt[i] = dma_alloc_coherent(&ctx->dev->plat_dev->dev,
+                       ctx->mbi_size,
+                       (dma_addr_t *)&ctx->mbi_dma_phy[i],
+                       GFP_KERNEL | GFP_DMA32
+                       );
+       if (!ctx->mbi_dma_virt[i])
+               vpu_dbg(LVL_ERR, "error: %s() mbi buffer alloc size(%x) fail!\n", __func__,  mbi_size);
+       }
+}
+static int v4l2_ioctl_reqbufs(struct file *file,
+               void *fh,
+               struct v4l2_requestbuffers *reqbuf
+               )
+{
+       struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+       struct queue_data *q_data;
+       u_int32 i;
+       int ret;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               q_data = &ctx->q_data[V4L2_SRC];
+       else if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               q_data = &ctx->q_data[V4L2_DST];
+       else
+               return -EINVAL;
+
+       ret = vb2_reqbufs(&q_data->vb2_q, reqbuf);
+       if (!ret) {
+               if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+                       for (i = 0; i < reqbuf->count; i++)
+                               q_data->vb2_reqs[i].status = FRAME_ALLOC;
+                       alloc_mbi_buffer(ctx, q_data, reqbuf->count);
+               }
+       } else
+               vpu_dbg(LVL_ERR, "error: %s() can't request (%d) buffer\n", __func__, reqbuf->count);
+
+       return ret;
+}
+
+static int v4l2_ioctl_querybuf(struct file *file,
+               void *fh,
+               struct v4l2_buffer *buf
+               )
+{
+       struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+       struct queue_data *q_data;
+       unsigned int i;
+       int ret;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               q_data = &ctx->q_data[V4L2_SRC];
+       else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               q_data = &ctx->q_data[V4L2_DST];
+       else
+               return -EINVAL;
+
+       ret = vb2_querybuf(&q_data->vb2_q, buf);
+       if (!ret) {
+               if (buf->memory == V4L2_MEMORY_MMAP) {
+                       if (V4L2_TYPE_IS_MULTIPLANAR(buf->type)) {
+                               for (i = 0; i < buf->length; i++)
+                                       buf->m.planes[i].m.mem_offset |= (q_data->type << MMAP_BUF_TYPE_SHIFT);
+                       } else
+                               buf->m.offset |= (q_data->type << MMAP_BUF_TYPE_SHIFT);
+               }
+       }
+
+       return ret;
+}
+
+static int v4l2_ioctl_qbuf(struct file *file,
+               void *fh,
+               struct v4l2_buffer *buf
+               )
+{
+       struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+       struct queue_data *q_data;
+       int ret;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               q_data = &ctx->q_data[V4L2_SRC];
+               v4l2_update_stream_addr(ctx, 0);
+       } else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               q_data = &ctx->q_data[V4L2_DST];
+       else
+               return -EINVAL;
+
+       ret = vb2_qbuf(&q_data->vb2_q, buf);
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               wake_up_interruptible(&ctx->buffer_wq);
+       v4l2_update_stream_addr(ctx, 0);
+
+       return ret;
+}
+
+static int v4l2_ioctl_dqbuf(struct file *file,
+               void *fh,
+               struct v4l2_buffer *buf
+               )
+{
+       struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+       struct queue_data *q_data;
+       int ret;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               q_data = &ctx->q_data[V4L2_SRC];
+       else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               q_data = &ctx->q_data[V4L2_DST];
+       else
+               return -EINVAL;
+
+       ret = vb2_dqbuf(&q_data->vb2_q, buf, file->f_flags & O_NONBLOCK);
+
+       v4l2_update_stream_addr(ctx, 0);
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               if (ctx->pSeqinfo->uBitDepthLuma > 8)
+                       buf->reserved = 1;
+
+       return ret;
+}
+
+static bool format_is_support(struct vpu_v4l2_fmt *format_table,
+               unsigned int table_size,
+               struct v4l2_format *f)
+{
+       unsigned int i;
+
+       for (i = 0; i < table_size; i++) {
+               if (format_table[i].fourcc == f->fmt.pix_mp.pixelformat)
+                       return true;
+       }
+       return false;
+}
+
+static int v4l2_ioctl_try_fmt(struct file *file,
+               void *fh,
+               struct v4l2_format *f
+               )
+{
+       unsigned int table_size;
+
+       if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               table_size = ARRAY_SIZE(formats_compressed_dec);
+               if (!format_is_support(formats_compressed_dec, table_size, f))
+                       return -EINVAL;
+       } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               table_size = ARRAY_SIZE(formats_yuv_dec);
+               if (!format_is_support(formats_yuv_dec, table_size, f))
+                       return -EINVAL;
+       } else
+               return -EINVAL;
+
+       return 0;
+}
+
+static int v4l2_ioctl_g_crop(struct file *file,
+               void *fh,
+               struct v4l2_crop *cr
+               )
+{
+       struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+       cr->c.left = 0;
+       cr->c.top = 0;
+       cr->c.width = ctx->pSeqinfo->uHorDecodeRes;
+       cr->c.height = ctx->pSeqinfo->uVerDecodeRes;
+
+       return 0;
+}
+
+static int v4l2_ioctl_decoder_cmd(struct file *file,
+               void *fh,
+               struct v4l2_decoder_cmd *cmd
+               )
+{
+       struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       switch (cmd->cmd) {
+       case V4L2_DEC_CMD_START:
+               break;
+       case V4L2_DEC_CMD_STOP: {
+       vpu_dbg(LVL_INFO, "receive V4L2_DEC_CMD_STOP\n");
+       v4l2_vpu_send_cmd(ctx, ctx->str_index, VID_API_CMD_STOP, 0, NULL);
+       } break;
+       case V4L2_DEC_CMD_PAUSE:
+               break;
+       case V4L2_DEC_CMD_RESUME:
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int v4l2_ioctl_streamon(struct file *file,
+               void *fh,
+               enum v4l2_buf_type i
+               )
+{
+       struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+       struct queue_data *q_data;
+       int ret;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (i == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               q_data = &ctx->q_data[V4L2_SRC];
+       else if (i == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               q_data = &ctx->q_data[V4L2_DST];
+       else
+               return -EINVAL;
+       ret = vb2_streamon(&q_data->vb2_q,
+                       i);
+       return ret;
+}
+
+static int v4l2_ioctl_streamoff(struct file *file,
+               void *fh,
+               enum v4l2_buf_type i
+               )
+{
+       struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+       struct queue_data *q_data;
+       int ret;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (i == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               q_data = &ctx->q_data[V4L2_SRC];
+       else if (i == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               q_data = &ctx->q_data[V4L2_DST];
+       else
+               return -EINVAL;
+       ret = vb2_streamoff(&q_data->vb2_q,
+                       i);
+
+       if (!ctx->firmware_stopped) {
+#ifdef HANDLE_EOS
+               add_eos(ctx, 0);
+#endif
+               ctx->wait_rst_done = true;
+               v4l2_vpu_send_cmd(ctx, ctx->str_index, VID_API_CMD_ABORT, 0, NULL);
+               wait_for_completion(&ctx->completion);
+       }
+
+       return ret;
+}
+
+const struct v4l2_ioctl_ops v4l2_decoder_ioctl_ops = {
+       .vidioc_querycap                = v4l2_ioctl_querycap,
+       .vidioc_enum_fmt_vid_cap_mplane = v4l2_ioctl_enum_fmt_vid_cap_mplane,
+       .vidioc_enum_fmt_vid_out_mplane = v4l2_ioctl_enum_fmt_vid_out_mplane,
+       .vidioc_g_fmt_vid_cap_mplane    = v4l2_ioctl_g_fmt,
+       .vidioc_g_fmt_vid_out_mplane    = v4l2_ioctl_g_fmt,
+       .vidioc_try_fmt_vid_cap_mplane  = v4l2_ioctl_try_fmt,
+       .vidioc_try_fmt_vid_out_mplane  = v4l2_ioctl_try_fmt,
+       .vidioc_s_fmt_vid_cap_mplane    = v4l2_ioctl_s_fmt,
+       .vidioc_s_fmt_vid_out_mplane    = v4l2_ioctl_s_fmt,
+       .vidioc_expbuf                  = v4l2_ioctl_expbuf,
+       .vidioc_g_crop                  = v4l2_ioctl_g_crop,
+       .vidioc_decoder_cmd             = v4l2_ioctl_decoder_cmd,
+       .vidioc_subscribe_event         = v4l2_ioctl_subscribe_event,
+       .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
+       .vidioc_reqbufs                 = v4l2_ioctl_reqbufs,
+       .vidioc_querybuf                = v4l2_ioctl_querybuf,
+       .vidioc_qbuf                    = v4l2_ioctl_qbuf,
+       .vidioc_dqbuf                   = v4l2_ioctl_dqbuf,
+       .vidioc_streamon                = v4l2_ioctl_streamon,
+       .vidioc_streamoff               = v4l2_ioctl_streamoff,
+};
+
+// Set/Get controls - v4l2 control framework
+
+static struct vpu_v4l2_control vpu_controls_dec[] = {
+       {
+               .id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 1,
+               .maximum = 32,
+               .step = 1,
+               .default_value = 4,
+               .is_volatile = true,
+       },
+};
+
+#define NUM_CTRLS_DEC   ARRAY_SIZE(vpu_controls_dec)
+
+static int v4l2_dec_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       switch (ctrl->id) {
+       default:
+               vpu_dbg(LVL_INFO, "%s() Invalid control(%d)\n",
+                               __func__, ctrl->id);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int v4l2_dec_g_v_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+
+       vpu_dbg(LVL_INFO, "%s() control(%d)\n",
+                       __func__, ctrl->id);
+
+       switch (ctrl->id) {
+       case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
+               ctrl->val = ctx->pSeqinfo->uNumDPBFrms;
+               break;
+       default:
+               vpu_dbg(LVL_INFO, "%s() Invalid control(%d)\n",
+                               __func__, ctrl->id);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops   vpu_dec_ctrl_ops = {
+       .s_ctrl             = v4l2_dec_s_ctrl,
+       .g_volatile_ctrl    = v4l2_dec_g_v_ctrl,
+};
+
+static int ctrls_setup_decoder(struct vpu_ctx *This)
+{
+       int i;
+
+       v4l2_ctrl_handler_init(&This->ctrl_handler,
+                       NUM_CTRLS_DEC + 1
+                       );
+       if (This->ctrl_handler.error) {
+               vpu_dbg(LVL_INFO, "%s() v4l2_ctrl_handler_init failed(%d)\n",
+                               __func__, This->ctrl_handler.error);
+
+               return This->ctrl_handler.error;
+       } else {
+               vpu_dbg(LVL_INFO, "%s() v4l2_ctrl_handler_init ctrls(%ld)\n",
+                               __func__, NUM_CTRLS_DEC);
+               This->ctrl_inited = true;
+       }
+
+       for (i = 0; i < NUM_CTRLS_DEC; i++) {
+               This->ctrls[i] = v4l2_ctrl_new_std(&This->ctrl_handler,
+                               &vpu_dec_ctrl_ops,
+                               vpu_controls_dec[i].id,
+                               vpu_controls_dec[i].minimum,
+                               vpu_controls_dec[i].maximum,
+                               vpu_controls_dec[i].step,
+                               vpu_controls_dec[i].default_value
+                               );
+               if (This->ctrl_handler.error ||
+                               !This->ctrls[i]
+                               ) {
+                       vpu_dbg(LVL_INFO, "%s() v4l2_ctrl_new_std failed(%d) This->ctrls[%d](%p)\n",
+                                       __func__, This->ctrl_handler.error, i, This->ctrls[i]);
+                       return This->ctrl_handler.error;
+               }
+
+               if (vpu_controls_dec[i].is_volatile &&
+                               This->ctrls[i]
+                               )
+                       This->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE;
+       }
+
+       v4l2_ctrl_handler_setup(&This->ctrl_handler);
+
+       return 0;
+}
+
+static void ctrls_delete_decoder(struct vpu_ctx *This)
+{
+       int i;
+
+       if (This->ctrl_inited) {
+               v4l2_ctrl_handler_free(&This->ctrl_handler);
+               This->ctrl_inited = false;
+       }
+       for (i = 0; i < NUM_CTRLS_DEC; i++)
+               This->ctrls[i] = NULL;
+}
+
+static void add_eos(struct vpu_ctx *ctx, u_int32 uStrBufIdx)
+{
+       struct vpu_dev *dev = ctx->dev;
+       pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+       struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+       uint32_t start;
+       uint32_t end;
+       uint32_t wptr;
+       uint32_t rptr;
+       uint8_t *pbbuffer;
+       uint8_t buffer[MIN_SPACE];
+       uint32_t *plbuffer = (uint32_t *)buffer;
+       uint32_t last;
+       uint32_t last2 = 0x0;
+       uint32_t i;
+
+       vpu_dbg(LVL_INFO, "enter %s\n", __func__);
+       pStrBufDesc = ctx->dev->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_MCX + MFD_MCX_OFF * ctx->str_index;
+       start = pStrBufDesc->start;
+       end = pStrBufDesc->end;
+       wptr = pStrBufDesc->wptr;
+       rptr = pStrBufDesc->rptr;
+
+       pbbuffer = (uint8_t *)(ctx->stream_buffer_virt + wptr - start);
+       switch (q_data->vdec_std) {
+       case VPU_VIDEO_AVC:
+               last = 0x0B010000;
+               break;
+       case VPU_VIDEO_VC1:
+               last = 0x0a010000;
+               break;
+       case VPU_VIDEO_MPEG2:
+               last = 0xb7010000;
+               break;
+       case VPU_VIDEO_ASP:
+               last = 0xb1010000;
+               break;
+       case VPU_VIDEO_SPK:
+       case VPU_VIDEO_VP6:
+       case VPU_VIDEO_VP8:
+       case VPU_VIDEO_RV8:
+       case VPU_VIDEO_RV9:
+               last = 0x34010000;
+               break;
+       case VPU_VIDEO_HEVC:
+               last = 0x4A010000;
+               last2 = 0x20;
+               break;
+       default:
+               last = 0x0;
+               break;
+       }
+
+       plbuffer[0] = last;
+       plbuffer[1] = last2;
+
+       for (i = 2; i < MIN_SPACE >> 2;  i++)
+               plbuffer[i] = 0;
+
+       if ((wptr == rptr) || (wptr > rptr)) {
+               if (end - wptr >= MIN_SPACE) {
+                       memcpy(pbbuffer, buffer, MIN_SPACE);
+                       wptr += MIN_SPACE;
+                       if (wptr == end)
+                               wptr = start;
+               } else {
+                       memcpy(pbbuffer, buffer, end-wptr);
+                       memcpy(ctx->stream_buffer_virt, buffer + (end-wptr), MIN_SPACE - (end-wptr));
+                       wptr = start + MIN_SPACE-(end-wptr);
+               }
+       } else {
+               memcpy(pbbuffer, buffer, MIN_SPACE);
+               wptr += MIN_SPACE;
+       }
+
+       pStrBufDesc->wptr = wptr;
+       dev->shared_mem.pSharedInterface->pStreamBuffDesc[ctx->str_index][uStrBufIdx] =
+               (VPU_REG_BASE + DEC_MFD_XREG_SLV_BASE + MFD_MCX + MFD_MCX_OFF * ctx->str_index);
+       vpu_dbg(LVL_INFO, "add eos MCX address virt=%p, phy=0x%x, index=%d\n", pStrBufDesc, dev->shared_mem.pSharedInterface->pStreamBuffDesc[ctx->str_index][uStrBufIdx], ctx->str_index);
+}
+
+TB_API_DEC_FMT vpu_format_remap(uint32_t vdec_std)
+{
+       TB_API_DEC_FMT malone_format = VSys_FrmtNull;
+
+       switch (vdec_std) {
+       case VPU_VIDEO_AVC:
+               malone_format = VSys_AvcFrmt;
+               vpu_dbg(LVL_INFO, "format translated to AVC");
+               break;
+       case VPU_VIDEO_VC1:
+               malone_format = VSys_Vc1Frmt;
+               vpu_dbg(LVL_INFO, "format translated to VC1");
+               break;
+       case VPU_VIDEO_MPEG2:
+               malone_format = VSys_Mp2Frmt;
+               vpu_dbg(LVL_INFO, "format translated to MP2");
+               break;
+       case VPU_VIDEO_AVS:
+               malone_format = VSys_AvsFrmt;
+               vpu_dbg(LVL_INFO, "format translated to AVS");
+               break;
+       case VPU_VIDEO_ASP:
+               malone_format = VSys_AspFrmt;
+               vpu_dbg(LVL_INFO, "format translated to ASP");
+               break;
+       case VPU_VIDEO_JPEG:
+               malone_format = VSys_JpgFrmt;
+               vpu_dbg(LVL_INFO, "format translated to JPG");
+               break;
+       case VPU_VIDEO_VP6:
+               malone_format = VSys_Vp6Frmt;
+               vpu_dbg(LVL_INFO, "format translated to VP6");
+               break;
+       case VPU_VIDEO_SPK:
+               malone_format = VSys_SpkFrmt;
+               vpu_dbg(LVL_INFO, "format translated to SPK");
+               break;
+       case VPU_VIDEO_VP8:
+               malone_format = VSys_Vp8Frmt;
+               vpu_dbg(LVL_INFO, "format translated to VP8");
+               break;
+       case VPU_VIDEO_HEVC:
+               malone_format = VSys_HevcFrmt;
+               vpu_dbg(LVL_INFO, "format translated to HEVC");
+               break;
+       case VPU_VIDEO_RV8:
+               malone_format = VSys_RvFrmt;
+               vpu_dbg(LVL_INFO, "format translated to RV");
+               break;
+       case VPU_VIDEO_RV9:
+               malone_format = VSys_RvFrmt;
+               vpu_dbg(LVL_INFO, "format translated to RV");
+               break;
+       case VPU_VIDEO_AVC_MVC:
+               malone_format = VSys_AvcFrmt;
+               vpu_dbg(LVL_INFO, "format translated to AVC");
+               break;
+       default:
+               malone_format = VSys_FrmtNull;
+               vpu_dbg(LVL_INFO, "unspport format");
+               break;
+       }
+       vpu_dbg(LVL_INFO, "\n");
+
+       return malone_format;
+}
+
+static void v4l2_vpu_send_cmd(struct vpu_ctx *ctx, uint32_t idx, uint32_t cmdid, uint32_t cmdnum, uint32_t *local_cmddata)
+{
+       vpu_log_cmd(cmdid, idx);
+       rpc_send_cmd_buf(&ctx->dev->shared_mem, idx, cmdid, cmdnum, local_cmddata);
+       MU_SendMessage(ctx->dev->mu_base_virtaddr, 0, COMMAND);
+}
+static void transfer_buffer_to_firmware(struct vpu_ctx *ctx, void *input_buffer, uint32_t buffer_size, uint32_t vdec_std)
+{
+       pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+       u_int32 uStrBufIdx = 0; //set to be default 0, FIX_ME later
+       MediaIPFW_Video_UData *pUdataBuf =
+               &ctx->dev->shared_mem.pSharedInterface->UDataBuffer[ctx->str_index];
+       pDEC_RPC_HOST_IFACE pSharedInterface = ctx->dev->shared_mem.pSharedInterface;
+       unsigned int *CurrStrfg = &pSharedInterface->StreamConfig[ctx->str_index];
+
+       vpu_dbg(LVL_INFO, "enter %s, start_flag %d, index=%d\n", __func__, ctx->start_flag, ctx->str_index);
+       if (ctx->stream_buffer_size < buffer_size + MIN_SPACE)
+               vpu_dbg(LVL_INFO, "circular buffer size is too small\n");
+       memcpy(ctx->stream_buffer_virt, input_buffer, buffer_size);
+       vpu_dbg(LVL_INFO, "transfer data from virt 0x%p: size:%d\n", ctx->stream_buffer_virt, buffer_size);
+
+       pStrBufDesc = ctx->dev->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_MCX + MFD_MCX_OFF * ctx->str_index;
+       // CAUTION: wptr must not be end
+       pStrBufDesc->wptr = ctx->stream_buffer_phy + buffer_size - ctx->dev->cm_offset;
+       pStrBufDesc->rptr = ctx->stream_buffer_phy - ctx->dev->cm_offset;
+       pStrBufDesc->start = ctx->stream_buffer_phy - ctx->dev->cm_offset;
+       pStrBufDesc->end = ctx->stream_buffer_phy + ctx->stream_buffer_size - ctx->dev->cm_offset;
+       pStrBufDesc->LWM = 0x01;
+
+       ctx->dev->shared_mem.pSharedInterface->pStreamBuffDesc[ctx->str_index][uStrBufIdx] =
+               (VPU_REG_BASE + DEC_MFD_XREG_SLV_BASE + MFD_MCX + MFD_MCX_OFF * ctx->str_index);
+
+       vpu_dbg(LVL_INFO, "transfer MCX address virt=%p, phy=0x%x, index=%d\n", pStrBufDesc, ctx->dev->shared_mem.pSharedInterface->pStreamBuffDesc[ctx->str_index][uStrBufIdx], ctx->str_index);
+       pUdataBuf->uUDataBase = ctx->udata_buffer_phy - ctx->dev->cm_offset;
+       pUdataBuf->uUDataSlotSize = ctx->udata_buffer_size;
+       VID_STREAM_CONFIG_FORMAT_SET(vpu_format_remap(vdec_std), CurrStrfg);
+}
+
+static void v4l2_transfer_buffer_to_firmware(struct queue_data *This, struct vb2_buffer *vb)
+{
+       struct vpu_ctx *ctx = container_of(This, struct vpu_ctx, q_data[V4L2_SRC]);
+       struct vb2_data_req *p_data_req;
+       void *data_mapped;
+       uint32_t buffer_size = vb->planes[0].bytesused;
+
+       data_mapped = (void *)vb2_plane_vaddr(vb, 0);
+
+       if (ctx->start_flag == true) {
+               transfer_buffer_to_firmware(ctx, data_mapped, buffer_size, This->vdec_std);
+#ifdef HANDLE_EOS
+               if (vb->planes[0].bytesused < vb->planes[0].length)
+                       add_eos(ctx, 0);
+#endif
+               v4l2_vpu_send_cmd(ctx, ctx->str_index, VID_API_CMD_START, 0, NULL);
+               down(&This->drv_q_lock);
+               p_data_req = list_first_entry(&This->drv_q,
+                               typeof(*p_data_req), list);
+               list_del(&p_data_req->list);
+               vb2_buffer_done(p_data_req->vb2_buf,
+                               VB2_BUF_STATE_DONE
+                               );
+               up(&This->drv_q_lock);
+               ctx->start_flag = false;
+       }
+}
+
+static int update_stream_addr(struct vpu_ctx *ctx, void *input_buffer, uint32_t buffer_size, uint32_t uStrBufIdx)
+{
+       struct vpu_dev *dev = ctx->dev;
+       uint32_t index = ctx->str_index;
+       pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+       uint32_t nfreespace = 0;
+       uint32_t wptr;
+       uint32_t rptr;
+       uint32_t start;
+       uint32_t end;
+       void *wptr_virt;
+       uint32_t ret = 1;
+
+       vpu_dbg(LVL_INFO, "enter %s\n", __func__);
+
+       // changed to virtual address and back
+       pStrBufDesc = dev->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_MCX + MFD_MCX_OFF * index;
+       vpu_dbg(LVL_INFO, "%s wptr(%x) rptr(%x) start(%x) end(%x) uStrBufIdx(%d)\n",
+                       __func__,
+                       pStrBufDesc->wptr,
+                       pStrBufDesc->rptr,
+                       pStrBufDesc->start,
+                       pStrBufDesc->end,
+                       uStrBufIdx
+             );
+       wptr = pStrBufDesc->wptr;
+       rptr = pStrBufDesc->rptr;
+
+       start = pStrBufDesc->start;
+       end = pStrBufDesc->end;
+       wptr_virt = (void *)ctx->stream_buffer_virt + wptr - start;
+
+       vpu_dbg(LVL_INFO, "update_stream_addr down\n");
+
+       if (wptr == rptr)
+               nfreespace = end - start;
+       if (wptr < rptr)
+               nfreespace = rptr - wptr;
+       if (wptr > rptr)
+               nfreespace = (end - wptr) + (rptr - start);
+
+       if (nfreespace-buffer_size < MIN_SPACE)
+                       return 0;
+
+       if (nfreespace >= buffer_size) {
+               if ((wptr == rptr) || (wptr > rptr)) {
+                       if (end - wptr >= buffer_size) {
+                               memcpy(wptr_virt, input_buffer, buffer_size);
+                               wptr += buffer_size;
+                               if (wptr == end)
+                                       wptr = start;
+                       } else {
+                               memcpy(wptr_virt, input_buffer, end-wptr);
+                               memcpy(ctx->stream_buffer_virt, input_buffer + (end-wptr), buffer_size - (end-wptr));
+                               wptr = start + buffer_size - (end-wptr);
+                       }
+               } else {
+                       memcpy(wptr_virt, input_buffer, buffer_size);
+                       wptr += buffer_size;
+               }
+       } else {
+               vpu_dbg(LVL_INFO, "buffer_full: the circular buffer freespace < buffer_size, treat as full");
+               return 0; //do not consider this situation now
+       }
+
+       pStrBufDesc->wptr = wptr;
+                       vpu_dbg(LVL_INFO, "update_stream_addr up, wptr 0x%x\n", wptr);
+
+       dev->shared_mem.pSharedInterface->pStreamBuffDesc[index][uStrBufIdx] =
+               (VPU_REG_BASE + DEC_MFD_XREG_SLV_BASE + MFD_MCX + MFD_MCX_OFF * index);
+
+       vpu_dbg(LVL_INFO, "update address virt=%p, phy=0x%x, index=%d\n", pStrBufDesc, dev->shared_mem.pSharedInterface->pStreamBuffDesc[ctx->str_index][uStrBufIdx], ctx->str_index);
+       return ret;
+}
+//warn uStrIdx need to refine how to handle it
+static void v4l2_update_stream_addr(struct vpu_ctx *ctx, uint32_t uStrBufIdx)
+{
+       struct vb2_data_req *p_data_req;
+       struct queue_data *This = &ctx->q_data[V4L2_SRC];
+       void *input_buffer;
+       uint32_t buffer_size;
+
+       down(&This->drv_q_lock);
+       while (!list_empty(&This->drv_q)) {
+               p_data_req = list_first_entry(&This->drv_q,
+                               typeof(*p_data_req), list);
+
+               buffer_size = p_data_req->vb2_buf->planes[0].bytesused;
+               input_buffer = (void *)vb2_plane_vaddr(p_data_req->vb2_buf, 0);
+               if (!update_stream_addr(ctx, input_buffer, buffer_size, uStrBufIdx)) {
+                       up(&This->drv_q_lock);
+                       vpu_dbg(LVL_INFO, " %s no space to write\n", __func__);
+                       return;
+               }
+#ifdef HANDLE_EOS
+               if (buffer_size < p_data_req->vb2_buf->planes[0].length)
+                       add_eos(ctx, uStrBufIdx); //WARN EOS should be refined later, as need to add eos by userspace or pass a flag to deal with when buffer_size == p_data_req->vb2_buf->planes[0].length
+#endif
+               list_del(&p_data_req->list);
+               vb2_buffer_done(p_data_req->vb2_buf,
+                               VB2_BUF_STATE_DONE
+                              );
+       }
+       up(&This->drv_q_lock);
+
+}
+
+static void report_buffer_done(struct vpu_ctx *ctx, void *frame_info)
+{
+       struct vb2_data_req *p_data_req;
+       struct queue_data *This = &ctx->q_data[V4L2_DST];
+       u_int32 *FrameInfo = (u_int32 *)frame_info;
+       u_int32 fs_id = FrameInfo[0x0];
+       uint32_t stride = FrameInfo[3];
+       bool b10BitFormat = (ctx->pSeqinfo->uBitDepthLuma >> 8) || (ctx->pSeqinfo->uBitDepthChroma >> 8);
+       u_int32 buffer_id;
+
+       vpu_dbg(LVL_INFO, "report_buffer_done fs_id=%d, ulFsLumaBase[0]=%x, stride=%d, b10BitFormat=%d\n", fs_id, FrameInfo[1], stride, b10BitFormat);
+       v4l2_update_stream_addr(ctx, 0);
+
+       buffer_id = find_buffer_id(ctx, FrameInfo[1]);
+
+       if (buffer_id != fs_id)
+               vpu_dbg(LVL_ERR, "error: find buffer_id(%d) and firmware return id(%d) doesn't match\n",
+                               buffer_id, fs_id);
+       if (ctx->q_data[V4L2_DST].vb2_reqs[buffer_id].status == FRAME_DECODED)
+               ctx->q_data[V4L2_DST].vb2_reqs[buffer_id].status = FRAME_READY;
+       else
+               vpu_dbg(LVL_ERR, "error: buffer(%d) need to set FRAME_READY, but previous state %s is not FRAME_DECODED\n",
+                               buffer_id, bufstat[ctx->q_data[V4L2_DST].vb2_reqs[buffer_id].status]);
+
+       p_data_req = &This->vb2_reqs[buffer_id];
+       p_data_req->vb2_buf->planes[0].bytesused = This->sizeimage[0];
+       p_data_req->vb2_buf->planes[1].bytesused = This->sizeimage[1];
+       vb2_buffer_done(p_data_req->vb2_buf,
+                       VB2_BUF_STATE_DONE
+                       );
+       vpu_dbg(LVL_INFO, "leave %s\n", __func__);
+}
+
+static void vpu_api_event_handler(struct vpu_ctx *ctx, u_int32 uStrIdx, u_int32 uEvent, u_int32 *event_data)
+{
+       struct vpu_dev *dev = ctx->dev;
+       pDEC_RPC_HOST_IFACE pSharedInterface = (pDEC_RPC_HOST_IFACE)dev->shared_mem.shared_mem_vir;
+
+       vpu_log_event(uEvent, uStrIdx);
+
+       switch (uEvent) {
+       case VID_API_EVENT_START_DONE:
+               break;
+       case VID_API_EVENT_STOPPED: {
+               const struct v4l2_event ev = {
+                       .type = V4L2_EVENT_EOS
+               };
+               v4l2_event_queue_fh(&ctx->fh, &ev);
+               ctx->firmware_stopped = true;
+               vpu_dbg(LVL_INFO, "send V4L2_EVENT_EOS\n");
+               }
+               break;
+       case VID_API_EVENT_RESET_DONE:
+               break;
+       case VID_API_EVENT_PIC_DECODED: {
+               MediaIPFW_Video_QMeterInfo *pQMeterInfo = (MediaIPFW_Video_QMeterInfo *)dev->shared_mem.qmeter_mem_vir;
+               MediaIPFW_Video_PicInfo *pPicInfo = (MediaIPFW_Video_PicInfo *)dev->shared_mem.pic_mem_vir;
+               MediaIPFW_Video_PicDispInfo *pDispInfo = &pPicInfo[uStrIdx].DispInfo;
+               MediaIPFW_Video_PicPerfInfo *pPerfInfo = &pPicInfo[uStrIdx].PerfInfo;
+               MediaIPFW_Video_PicPerfDcpInfo *pPerfDcpInfo = &pPicInfo[uStrIdx].PerfDcpInfo;
+               u_int32 buffer_id;
+
+               vpu_dbg(LVL_INFO, "PICINFO GET: uPicType:%d uPicStruct:%d uPicStAddr:0x%x uFrameStoreID:%d uPercentInErr:%d, uRbspBytesCount=%d, ulLumBaseAddr[0]=%x, pQMeterInfo:%p, pPicInfo:%p, pDispInfo:%p, pPerfInf:%p, pPerfDcpInfo:%p\n",
+                               pPicInfo[uStrIdx].uPicType, pPicInfo[uStrIdx].uPicStruct,
+                               pPicInfo[uStrIdx].uPicStAddr, pPicInfo[uStrIdx].uFrameStoreID,
+                               pPicInfo[uStrIdx].uPercentInErr, pPerfInfo->uRbspBytesCount, event_data[0],
+                               pQMeterInfo, pPicInfo, pDispInfo, pPerfInfo, pPerfDcpInfo);
+
+               buffer_id = find_buffer_id(ctx, event_data[0]);
+               if (buffer_id != pPicInfo[uStrIdx].uFrameStoreID)
+                       vpu_dbg(LVL_ERR, "error: VID_API_EVENT_PIC_DECODED address and id doesn't match\n");
+               if (ctx->q_data[V4L2_DST].vb2_reqs[buffer_id].status == FRAME_FREE)
+                       ctx->q_data[V4L2_DST].vb2_reqs[buffer_id].status = FRAME_DECODED;
+               else
+                       vpu_dbg(LVL_ERR, "error: buffer(%d) need to set FRAME_DECODED, but previous state %s is not FRAME_FREE\n",
+                                       buffer_id, bufstat[ctx->q_data[V4L2_DST].vb2_reqs[buffer_id].status]);
+               }
+               break;
+       case VID_API_EVENT_SEQ_HDR_FOUND: {
+               MediaIPFW_Video_SeqInfo *pSeqInfo = (MediaIPFW_Video_SeqInfo *)dev->shared_mem.seq_mem_vir;
+//             MediaIPFW_Video_FrameBuffer *pStreamFrameBuffer = &pSharedInterface->StreamFrameBuffer[uStrIdx];
+//             MediaIPFW_Video_FrameBuffer *pStreamDCPBuffer = &pSharedInterface->StreamDCPBuffer[uStrIdx];
+               MediaIPFW_Video_PitchInfo   *pStreamPitchInfo = &pSharedInterface->StreamPitchInfo[uStrIdx];
+               unsigned int num = pSharedInterface->SeqInfoTabDesc.uNumSizeDescriptors;
+
+               if (ctx->pSeqinfo == NULL)
+                       ctx->pSeqinfo = kzalloc(sizeof(MediaIPFW_Video_SeqInfo), GFP_KERNEL);
+               else
+                       vpu_dbg(LVL_INFO, "pSeqinfo is not NULL, need not to realloc\n");
+               memcpy(ctx->pSeqinfo, &pSeqInfo[ctx->str_index], sizeof(MediaIPFW_Video_SeqInfo));
+
+               caculate_frame_size(ctx);
+               vpu_dbg(LVL_INFO, "SEQINFO GET: uHorRes:%d uVerRes:%d uHorDecodeRes:%d uVerDecodeRes:%d uNumDPBFrms:%d, num=%d\n",
+                               ctx->pSeqinfo->uHorRes, ctx->pSeqinfo->uVerRes,
+                               ctx->pSeqinfo->uHorDecodeRes, ctx->pSeqinfo->uVerDecodeRes,
+                               ctx->pSeqinfo->uNumDPBFrms, num);
+               if (ctx->b_firstseq) {
+                       const struct v4l2_event ev = {
+                               .type = V4L2_EVENT_SOURCE_CHANGE,
+                               .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION
+                       };
+                       v4l2_event_queue_fh(&ctx->fh, &ev);
+
+                       pStreamPitchInfo->uFramePitch = 0x4000;
+                       ctx->b_firstseq = false;
+               }
+               }
+               break;
+       case VID_API_EVENT_PIC_HDR_FOUND:
+               break;
+       case VID_API_EVENT_REQ_FRAME_BUFF: {
+               MEDIA_PLAYER_FSREQ *pFSREQ = (MEDIA_PLAYER_FSREQ *)event_data;
+               u_int32 local_cmddata[10];
+               struct vb2_data_req *p_data_req, *p_temp;
+               struct queue_data *This = &ctx->q_data[V4L2_DST];
+               u_int32 LumaAddr, ChromaAddr;
+               u_int32 *pphy_address;
+               struct vb2_data_req;
+               void *dcp_dma_virt;
+               dma_addr_t dcp_dma_phy;
+               u_int32 timeout_count = 0;
+               bool buffer_flag = false;
+
+               vpu_dbg(LVL_INFO, "VID_API_EVENT_REQ_FRAME_BUFF, type=%d, size=%ld\n", pFSREQ->eType, sizeof(MEDIA_PLAYER_FSREQ));
+               if (pFSREQ->eType == MEDIAIP_DCP_REQ) {
+                       if (ctx->dcp_count >= MAX_DCP_NUM)
+                               vpu_dbg(LVL_ERR, "error: request dcp buffers number is over MAX_DCP_NUM\n");
+                       ctx->uDCPSize = DCP_SIZE;
+                       dcp_dma_virt = dma_alloc_coherent(&ctx->dev->plat_dev->dev,
+                                       ctx->uDCPSize,
+                                       (dma_addr_t *)&dcp_dma_phy,
+                                       GFP_KERNEL | GFP_DMA32
+                                       );
+                       if (!dcp_dma_virt)
+                               vpu_dbg(LVL_ERR, "error: %s() dcp buffer alloc size(%x) fail!\n", __func__, DCP_SIZE);
+                       ctx->dcp_dma_virt[ctx->dcp_count] = dcp_dma_virt;
+                       ctx->dcp_dma_phy[ctx->dcp_count] = dcp_dma_phy;
+
+                       local_cmddata[0] = ctx->dcp_count;
+                       local_cmddata[1] = dcp_dma_phy - ctx->dev->cm_offset;
+                       local_cmddata[2] = DCP_SIZE;
+                       local_cmddata[3] = 0;
+                       local_cmddata[4] = 0;
+                       local_cmddata[5] = 0;
+                       local_cmddata[6] = pFSREQ->eType;
+                       v4l2_vpu_send_cmd(ctx, uStrIdx, VID_API_CMD_FS_ALLOC, 7, local_cmddata);
+                       vpu_dbg(LVL_INFO, "VID_API_CMD_FS_ALLOC, eType=%d, index=%d\n", pFSREQ->eType, ctx->dcp_count);
+                       ctx->dcp_count++;
+               } else if (pFSREQ->eType == MEDIAIP_MBI_REQ) {
+                       if (ctx->mbi_count >= ctx->mbi_num)
+                               vpu_dbg(LVL_ERR, "error: request mbi buffers number(%d) is over allocted buffer number(%d)\n",
+                                               ctx->mbi_count, ctx->mbi_num);
+                       local_cmddata[0] = ctx->mbi_count;
+                       local_cmddata[1] = ctx->mbi_dma_phy[ctx->mbi_count] - ctx->dev->cm_offset;
+                       local_cmddata[2] = ctx->mbi_size;
+                       local_cmddata[3] = 0;
+                       local_cmddata[4] = 0;
+                       local_cmddata[5] = 0;
+                       local_cmddata[6] = pFSREQ->eType;
+                       v4l2_vpu_send_cmd(ctx, uStrIdx, VID_API_CMD_FS_ALLOC, 7, local_cmddata);
+                       vpu_dbg(LVL_INFO, "VID_API_CMD_FS_ALLOC, eType=%d, index=%d\n", pFSREQ->eType, ctx->mbi_count);
+                       ctx->mbi_count++;
+               } else {
+                       while (timeout_count < MAX_TIMEOUT_COUNT) {
+                               if (!wait_event_interruptible_timeout(ctx->buffer_wq,
+                                                       !list_empty(&This->drv_q),
+                                                       msecs_to_jiffies(1000)))
+                                       vpu_dbg(LVL_ERR, " error: wait_event_interruptible_timeout wait timeout\n");
+                               else {
+                                       vpu_dbg(LVL_INFO, " wait_event_interruptible_timeout list is not empty now\n");
+                                       if (!list_empty(&This->drv_q))
+                                               break;
+                               }
+                               if (!list_empty(&This->drv_q))
+                                       break;
+                               timeout_count++;
+                       }
+
+                       if (!list_empty(&This->drv_q)) {
+                               down(&This->drv_q_lock);
+                               list_for_each_entry_safe(p_data_req, p_temp, &This->drv_q, list) {
+                                       if (p_data_req->status == FRAME_ALLOC
+                                                       || p_data_req->status == FRAME_RELEASE){
+                                               pphy_address = (u_int32 *)vb2_plane_cookie(p_data_req->vb2_buf, 0);
+                                               LumaAddr = *pphy_address;
+                                               pphy_address = (u_int32 *)vb2_plane_cookie(p_data_req->vb2_buf, 1);
+                                               ChromaAddr = *pphy_address;
+                                               vpu_dbg(LVL_INFO, "%s :LumaAddr(%x) ChromaAddr(%x) buf_id (%d)\n",
+                                                               __func__,
+                                                               LumaAddr,
+                                                               ChromaAddr,
+                                                               p_data_req->id
+                                                               );
+
+                                               local_cmddata[0] = p_data_req->id;
+                                               local_cmddata[1] = LumaAddr - ctx->dev->cm_offset;
+                                               local_cmddata[2] = local_cmddata[1] + This->sizeimage[0]/2;
+                                               local_cmddata[3] = ChromaAddr - ctx->dev->cm_offset;
+                                               local_cmddata[4] = local_cmddata[3] + This->sizeimage[1]/2;
+                                               local_cmddata[5] = ctx->q_data[V4L2_DST].stride;
+                                               local_cmddata[6] = pFSREQ->eType;
+                                               //WARN :need to check the call back VID_API_EVENT_REL_FRAME_BUFF later, when it is received, the corepond id can be released, now just do a temporary workaround
+                                               if (p_data_req->status == FRAME_RELEASE)
+                                                       v4l2_vpu_send_cmd(ctx, uStrIdx, VID_API_CMD_FS_RELEASE, 1, &p_data_req->id);
+
+                                               v4l2_vpu_send_cmd(ctx, uStrIdx, VID_API_CMD_FS_ALLOC, 7, local_cmddata);
+                                               p_data_req->status = FRAME_FREE;
+                                               vpu_dbg(LVL_INFO, "VID_API_CMD_FS_ALLOC, data_req->vb2_buf=%p, data_req->id=%d\n", p_data_req->vb2_buf, p_data_req->id);
+                                               list_del(&p_data_req->list);
+                                               buffer_flag = true;
+                                               break;
+                                       } else {
+                                               vpu_dbg(LVL_ERR, "error: buffer %d status=0x%x is not right, find next\n", p_data_req->id, p_data_req->status);
+                                               continue;
+                                       }
+                               }
+                               up(&This->drv_q_lock);
+                               if (buffer_flag == false)
+                                       vpu_dbg(LVL_ERR, "error: don't find the right buffer for VID_API_CMD_FS_ALLOC\n");
+                       } else
+                               vpu_dbg(LVL_ERR, "error: wait timeout, but the list is still empty");
+               }
+               }
+               break;
+       case VID_API_EVENT_REL_FRAME_BUFF: {
+               MEDIA_PLAYER_FSREL *fsrel = (MEDIA_PLAYER_FSREL *)event_data;
+               struct queue_data *This = &ctx->q_data[V4L2_DST];
+               struct vb2_data_req *p_data_req;
+
+               if (fsrel->eType == MEDIAIP_FRAME_REQ) {
+                       p_data_req = &This->vb2_reqs[fsrel->uFSIdx];
+
+                       if (p_data_req->status == FRAME_READY)
+                               p_data_req->status = FRAME_RELEASE;
+                       else {
+                               if (ctx->wait_rst_done == true) {
+                                       p_data_req->status = FRAME_RELEASE;
+                                       down(&This->drv_q_lock);
+                                       list_add_tail(&p_data_req->list, &This->drv_q);
+                                       up(&This->drv_q_lock);
+                               } else
+                                       vpu_dbg(LVL_ERR, "error: normal release need to set status to FRAME_RELEASE but previous status %s is not FRAME_READY\n", bufstat[p_data_req->status]);
+                       }
+               }
+               vpu_dbg(LVL_INFO, "VID_API_EVENT_REL_FRAME_BUFF uFSIdx=%d, eType=%d, size=%ld\n", fsrel->uFSIdx, fsrel->eType, sizeof(MEDIA_PLAYER_FSREL));
+       } break;
+       case VID_API_EVENT_FRAME_BUFF_RDY: {
+               u_int32 *FrameInfo = (u_int32 *)event_data;
+
+               report_buffer_done(ctx, FrameInfo);
+       }
+               break;
+       case VID_API_EVENT_CHUNK_DECODED:
+               break;
+       case VID_API_EVENT_FIFO_LOW: {
+               struct vpu_dev *dev = ctx->dev;
+               u_int32 uStrBufIdx = 0; //use buffer 0 for the stream
+               pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+
+
+               pStrBufDesc = dev->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_MCX + MFD_MCX_OFF * ctx->str_index;
+               vpu_dbg(LVL_INFO, "%s wptr(%x) rptr(%x) start(%x) end(%x) uStrIdx(%d)\n",
+                               __func__,
+                               pStrBufDesc->wptr,
+                               pStrBufDesc->rptr,
+                               pStrBufDesc->start,
+                               pStrBufDesc->end,
+                               uStrIdx
+             );
+
+               v4l2_update_stream_addr(ctx, uStrBufIdx);
+               }
+               break;
+       case VID_API_EVENT_FIFO_HIGH:
+               break;
+       case  VID_API_EVENT_FIFO_EMPTY:
+               break;
+       case  VID_API_EVENT_FIFO_FULL:
+               break;
+       case  VID_API_EVENT_FIFO_OVF:
+               break;
+       case  VID_API_EVENT_BS_ERROR:
+               break;
+       case  VID_API_EVENT_UDATA_FIFO_UPTD:
+               break;
+       case VID_API_EVENT_DBG_STAT_UPDATE:
+               break;
+       case VID_API_EVENT_DBG_LOG_STARTED:
+               break;
+       case VID_API_EVENT_DBG_LOG_STOPPED:
+               break;
+       case VID_API_EVENT_ABORT_DONE:
+               v4l2_vpu_send_cmd(ctx, uStrIdx, VID_API_CMD_RST_BUF, 0, NULL);
+               break;
+       case VID_API_EVENT_RES_CHANGE:
+               {
+                       const struct v4l2_event ev = {
+                       .type = V4L2_EVENT_SOURCE_CHANGE,
+                       .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION
+               };
+               v4l2_event_queue_fh(&ctx->fh, &ev);
+               }
+               break;
+       case VID_API_EVENT_STR_BUF_RST: {
+               pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+               struct vb2_data_req *p_data_req;
+               u_int32 i;
+
+               pStrBufDesc = dev->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_MCX + MFD_MCX_OFF * ctx->str_index;
+               vpu_dbg(LVL_INFO, "%s wptr(%x) rptr(%x) start(%x) end(%x)\n",
+                               __func__,
+                               pStrBufDesc->wptr,
+                               pStrBufDesc->rptr,
+                               pStrBufDesc->start,
+                               pStrBufDesc->end
+                         );
+               pStrBufDesc->wptr = pStrBufDesc->start;
+               ctx->wait_rst_done = false;
+               for (i = 0; i < VPU_MAX_BUFFER; i++) {
+                       p_data_req = &ctx->q_data[V4L2_DST].vb2_reqs[i];
+                       if (p_data_req->vb2_buf != NULL)
+                               if (p_data_req->status != FRAME_RELEASE)
+                                       vpu_dbg(LVL_ERR, "error: buffer(%d) status is %s when receive VID_API_EVENT_STR_BUF_RST\n", i, bufstat[p_data_req->status]);
+               }
+               complete(&ctx->completion);
+               }
+               break;
+       case VID_API_EVENT_RET_PING:
+               break;
+       case VID_API_EVENT_STR_FMT_CHANGE:
+               break;
+       case VID_API_EVENT_FINISHED:
+               v4l2_vpu_send_cmd(ctx, uStrIdx, VID_API_CMD_STOP, 0, NULL);
+               break;
+       default:
+               break;
+       }
+       vpu_dbg(LVL_INFO, "leave %s, uEvent %d\n", __func__, uEvent);
+}
+
+
+
+//This code is added for MU
+
+static irqreturn_t fsl_vpu_mu_isr(int irq, void *This)
+{
+       struct vpu_dev *dev = This;
+       u32 msg;
+
+       MU_ReceiveMsg(dev->mu_base_virtaddr, 0, &msg);
+       if (msg == 0xaa) {
+#ifdef CM4
+               MU_sendMesgToFW(dev->mu_base_virtaddr, RPC_BUF_OFFSET, dev->m0_rpc_phy); //CM4 use absolute address
+#else
+               MU_sendMesgToFW(dev->mu_base_virtaddr, PRINT_BUF_OFFSET, dev->m0_rpc_phy - dev->m0_p_fw_space_phy + M0_PRINT_OFFSET);
+               MU_sendMesgToFW(dev->mu_base_virtaddr, RPC_BUF_OFFSET, dev->m0_rpc_phy - dev->m0_p_fw_space_phy); //CM0 use relative address
+               MU_sendMesgToFW(dev->mu_base_virtaddr, BOOT_ADDRESS, dev->m0_p_fw_space_phy);
+#endif
+               MU_sendMesgToFW(dev->mu_base_virtaddr, INIT_DONE, 2);
+       } else
+               schedule_work(&dev->msg_work);
+
+       return IRQ_HANDLED;
+}
+
+/* Initialization of the MU code. */
+static int vpu_mu_init(struct vpu_dev *dev)
+{
+       struct device_node *np;
+       unsigned int    vpu_mu_id;
+       u32 irq;
+       int ret = 0;
+
+       /*
+        * Get the address of MU to be used for communication with the M0 core
+        */
+#ifdef CM4
+       np = of_find_compatible_node(NULL, NULL, "fsl,imx8-mu0-vpu-m4");
+       if (!np) {
+               vpu_dbg(LVL_ERR, "error: Cannot find MU entry in device tree\n");
+               return -EINVAL;
+       }
+#else
+       np = of_find_compatible_node(NULL, NULL, "fsl,imx8-mu0-vpu-m0");
+       if (!np) {
+               vpu_dbg(LVL_ERR, "error: Cannot find MU entry in device tree\n");
+               return -EINVAL;
+       }
+#endif
+       dev->mu_base_virtaddr = of_iomap(np, 0);
+       WARN_ON(!dev->mu_base_virtaddr);
+
+       ret = of_property_read_u32_index(np,
+                               "fsl,vpu_ap_mu_id", 0, &vpu_mu_id);
+       if (ret) {
+               vpu_dbg(LVL_ERR, "error: Cannot get mu_id %d\n", ret);
+               return -EINVAL;
+       }
+
+       dev->vpu_mu_id = vpu_mu_id;
+
+       irq = of_irq_get(np, 0);
+
+       ret = devm_request_irq(&dev->plat_dev->dev, irq, fsl_vpu_mu_isr,
+                               IRQF_EARLY_RESUME, "vpu_mu_isr", (void *)dev);
+       if (ret) {
+               vpu_dbg(LVL_ERR, "error: request_irq failed %d, error = %d\n", irq, ret);
+               return -EINVAL;
+       }
+
+       if (!dev->vpu_mu_init) {
+               MU_Init(dev->mu_base_virtaddr);
+               MU_EnableRxFullInt(dev->mu_base_virtaddr, 0);
+               dev->vpu_mu_init = 1;
+       }
+
+       return ret;
+}
+
+static int vpu_next_free_instance(struct vpu_dev *dev)
+{
+       int idx = ffz(dev->instance_mask);
+
+       if (idx < 0 || idx > VPU_MAX_NUM_STREAMS)
+               return -EBUSY;
+
+       return idx;
+}
+
+extern u_int32 rpc_MediaIPFW_Video_message_check(struct shared_addr *This);
+static void vpu_msg_run_work(struct work_struct *work)
+{
+       struct vpu_dev *dev = container_of(work, struct vpu_dev, msg_work);
+       struct vpu_ctx *ctx;
+       struct event_msg msg;
+       struct shared_addr *This = &dev->shared_mem;
+
+       while (rpc_MediaIPFW_Video_message_check(This) == API_MSG_AVAILABLE) {
+               rpc_receive_msg_buf(This, &msg);
+               ctx = dev->ctx[msg.idx];
+               vpu_api_event_handler(ctx, msg.idx, msg.msgid, msg.msgdata);
+       }
+       if (rpc_MediaIPFW_Video_message_check(This) == API_MSG_BUFFER_ERROR)
+               vpu_dbg(LVL_ERR, "error: message size is too big to handle\n");
+}
+
+static int vpu_queue_setup(struct vb2_queue *vq,
+               unsigned int *buf_count,
+               unsigned int *plane_count,
+               unsigned int psize[],
+               struct device *allocators[])
+{
+       struct queue_data  *This = (struct queue_data *)vq->drv_priv;
+
+       vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+
+       if ((vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ||
+               (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               ) {
+               if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+                       *plane_count = 2;
+                       psize[0] = This->sizeimage[0];//check alignment
+                       psize[1] = This->sizeimage[1];//check colocated_size
+               } else {
+                       psize[0] = This->sizeimage[0] + This->sizeimage[1];
+                       *plane_count = 1;
+               }
+       } else {
+               *plane_count = 1;
+               psize[0] = This->sizeimage[0];
+       }
+       return 0;
+}
+
+static int vpu_buf_prepare(struct vb2_buffer *vb)
+{
+       vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+
+       return 0;
+}
+
+
+static int vpu_start_streaming(struct vb2_queue *q,
+               unsigned int count
+               )
+{
+       int ret = 0;
+
+       vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+       return ret;
+}
+
+
+static void vpu_stop_streaming(struct vb2_queue *q)
+{
+       struct queue_data *This = (struct queue_data *)q->drv_priv;
+       struct vb2_data_req *p_data_req = NULL;
+       struct vb2_data_req *p_temp;
+       struct vb2_buffer *vb;
+
+       vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+       down(&This->drv_q_lock);
+       if (This->type == V4L2_SRC) {
+               if (!list_empty(&This->drv_q)) {
+                       list_for_each_entry_safe(p_data_req, p_temp, &This->drv_q, list) {
+                               vpu_dbg(LVL_INFO, "%s(%d) - list_del(%p)\n",
+                                               __func__,
+                                               p_data_req->id,
+                                               p_data_req);
+                               list_del(&p_data_req->list);
+                               vb2_buffer_done(p_data_req->vb2_buf, VB2_BUF_STATE_ERROR);
+                       }
+               }
+       } else
+               if (!list_empty(&q->queued_list))
+                       list_for_each_entry(vb, &q->queued_list, queued_entry)
+                               vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+       INIT_LIST_HEAD(&This->drv_q);
+       up(&This->drv_q_lock);
+}
+
+static void vpu_buf_queue(struct vb2_buffer *vb)
+{
+       struct vb2_queue    *vq = vb->vb2_queue;
+       struct queue_data   *This = (struct queue_data *)vq->drv_priv;
+       struct vb2_data_req *data_req;
+
+       vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+
+       down(&This->drv_q_lock);
+       vpu_dbg(LVL_INFO, "c_port_buf_queue down\n");
+       data_req = &This->vb2_reqs[vb->index];
+       data_req->vb2_buf = vb;
+       data_req->id = vb->index;
+
+       list_add_tail(&data_req->list, &This->drv_q);
+
+       vpu_dbg(LVL_INFO, "before c_port_buf_queue up, vq->type=%d, vb->index=%d\n", vq->type, vb->index);
+       up(&This->drv_q_lock);
+       vpu_dbg(LVL_INFO, "c_port_buf_queue up\n");
+
+       if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               v4l2_transfer_buffer_to_firmware(This, vb);
+}
+
+static void vpu_prepare(struct vb2_queue *q)
+{
+       vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+}
+
+static void vpu_finish(struct vb2_queue *q)
+{
+       vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+}
+
+struct vb2_ops v4l2_qops = {
+       .queue_setup        = vpu_queue_setup,
+       .wait_prepare       = vpu_prepare,
+       .wait_finish        = vpu_finish,
+       .buf_prepare        = vpu_buf_prepare,
+       .start_streaming    = vpu_start_streaming,
+       .stop_streaming     = vpu_stop_streaming,
+       .buf_queue          = vpu_buf_queue,
+};
+
+static void init_vb2_queue(struct queue_data *This, unsigned int type, struct vpu_ctx *ctx)
+{
+       struct vb2_queue  *vb2_q = &This->vb2_q;
+       int ret;
+       u_int32 i;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       for (i = 0; i < VPU_MAX_BUFFER; i++)
+               This->vb2_reqs[i].status = 0;
+       // initialze driver queue
+       INIT_LIST_HEAD(&This->drv_q);
+       // initialize vb2 queue
+       vb2_q->type = type;
+       vb2_q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+       vb2_q->gfp_flags = GFP_DMA32;
+       vb2_q->ops = &v4l2_qops;
+       vb2_q->drv_priv = This;
+       vb2_q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
+       vb2_q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       vb2_q->dev = &ctx->dev->plat_dev->dev;
+       ret = vb2_queue_init(vb2_q);
+       if (ret)
+               vpu_dbg(LVL_ERR, "error: %s vb2_queue_init() failed (%d)!\n",
+                               __func__,
+                               ret
+                               );
+       else
+               This->vb2_q_inited = true;
+}
+
+static void init_queue_data(struct vpu_ctx *ctx)
+{
+       init_vb2_queue(&ctx->q_data[V4L2_SRC], V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, ctx);
+       ctx->q_data[V4L2_SRC].type = V4L2_SRC;
+       sema_init(&ctx->q_data[V4L2_SRC].drv_q_lock, 1);
+       init_vb2_queue(&ctx->q_data[V4L2_DST], V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, ctx);
+       ctx->q_data[V4L2_DST].type = V4L2_DST;
+       sema_init(&ctx->q_data[V4L2_DST].drv_q_lock, 1);
+}
+
+static void flush_drv_q(struct queue_data *This)
+{
+       struct vb2_data_req *p_data_req = NULL;
+       struct vb2_data_req *p_temp;
+
+       vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+       down(&This->drv_q_lock);
+       if (!list_empty(&This->drv_q)) {
+               list_for_each_entry_safe(p_data_req, p_temp, &This->drv_q, list) {
+                       vpu_dbg(LVL_INFO, "%s(%d) - list_del(%p)\n",
+                                       __func__,
+                                       p_data_req->id,
+                                       p_data_req);
+                       list_del(&p_data_req->list);
+                       vb2_buffer_done(p_data_req->vb2_buf, VB2_BUF_STATE_ERROR);
+               }
+       }
+       INIT_LIST_HEAD(&This->drv_q);
+
+       up(&This->drv_q_lock);
+
+}
+
+static void release_queue_data(struct vpu_ctx *ctx)
+{
+       struct queue_data *This = &ctx->q_data[V4L2_SRC];
+
+       if (This->vb2_q_inited) {
+               flush_drv_q(This);
+               vb2_queue_release(&This->vb2_q);
+       }
+       This = &ctx->q_data[V4L2_DST];
+       if (This->vb2_q_inited) {
+               flush_drv_q(This);
+               vb2_queue_release(&This->vb2_q);
+       }
+}
+
+#ifdef CM4
+static int power_CM4_up(struct vpu_dev *dev)
+{
+       sc_ipc_t ipcHndl;
+       sc_rsrc_t core_rsrc, mu_rsrc = -1;
+
+       ipcHndl = dev->mu_ipcHandle;
+       core_rsrc = SC_R_M4_0_PID0;
+       mu_rsrc = SC_R_M4_0_MU_1A;
+
+       if (sc_pm_set_resource_power_mode(ipcHndl, core_rsrc, SC_PM_PW_MODE_ON) != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "error: failed to power up core_rsrc\n");
+               return -EIO;
+       }
+
+       if (mu_rsrc != -1) {
+               if (sc_pm_set_resource_power_mode(ipcHndl, mu_rsrc, SC_PM_PW_MODE_ON) != SC_ERR_NONE) {
+                       vpu_dbg(LVL_ERR, "error: failed to power up mu_rsrc\n");
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+static int boot_CM4_up(struct vpu_dev *dev, void *boot_addr)
+{
+       sc_ipc_t ipcHndl;
+       sc_rsrc_t core_rsrc;
+       sc_faddr_t aux_core_ram;
+       void *core_ram_vir;
+       u32 size;
+
+       ipcHndl = dev->mu_ipcHandle;
+       core_rsrc = SC_R_M4_0_PID0;
+       aux_core_ram = 0x34FE0000;
+       size = SZ_128K;
+
+       core_ram_vir = ioremap(aux_core_ram,
+                       size
+                       );
+       if (!core_ram_vir)
+               vpu_dbg(LVL_ERR, "error: failed to remap space for core ram\n");
+
+       memcpy((void *)core_ram_vir, (void *)boot_addr, size);
+
+       if (sc_pm_cpu_start(ipcHndl, core_rsrc, true, aux_core_ram) != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "error: failed to start core_rsrc\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+#endif
+
+static int vpu_firmware_download(struct vpu_dev *This)
+{
+       unsigned char *image;
+       unsigned int FW_Size = 0;
+       void *csr_offset, *csr_cpuwait;
+       int ret = 0;
+
+       ret = request_firmware((const struct firmware **)&This->m0_pfw,
+                       M0FW_FILENAME,
+                       This->generic_dev
+                       );
+       if (ret) {
+               vpu_dbg(LVL_ERR, "error: %s() request fw %s failed(%d)\n",
+                       __func__, M0FW_FILENAME, ret);
+
+               if (This->m0_pfw) {
+                       release_firmware(This->m0_pfw);
+                       This->m0_pfw = NULL;
+               }
+               return ret;
+       } else {
+               vpu_dbg(LVL_INFO, "%s() request fw %s got size(%d)\n",
+                       __func__, M0FW_FILENAME, (int)This->m0_pfw->size);
+               image = (uint8_t *)This->m0_pfw->data;
+               FW_Size = This->m0_pfw->size;
+       }
+       memcpy(This->m0_p_fw_space_vir,
+                       image,
+                       FW_Size
+                       );
+#ifdef CM4
+       boot_CM4_up(This, This->m0_p_fw_space_vir);
+#else
+       csr_offset = ioremap(0x2d040000, 4);
+       writel(This->m0_p_fw_space_phy, csr_offset);
+       csr_cpuwait = ioremap(0x2d040004, 4);
+       writel(0x0, csr_cpuwait);
+#endif
+       return ret;
+}
+
+static int v4l2_open(struct file *filp)
+{
+       struct video_device *vdev = video_devdata(filp);
+       struct vpu_dev *dev = video_get_drvdata(vdev);
+       struct vpu_ctx *ctx = NULL;
+       int idx;
+       int ret;
+       u_int32 i;
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+       idx = vpu_next_free_instance(dev);
+       if (idx < 0) {
+               ret = idx;
+               return ret;
+       }
+       set_bit(idx, &dev->instance_mask);
+       init_completion(&ctx->completion);
+
+       v4l2_fh_init(&ctx->fh, video_devdata(filp));
+       filp->private_data = &ctx->fh;
+       v4l2_fh_add(&ctx->fh);
+
+       ctx->ctrl_inited = false;
+       ctrls_setup_decoder(ctx);
+       ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+
+       ctx->dev = dev;
+       ctx->str_index = idx;
+       dev->ctx[idx] = ctx;
+       ctx->b_firstseq = true;
+       ctx->start_flag = true;
+       ctx->wait_rst_done = false;
+       ctx->firmware_stopped = false;
+       ctx->pSeqinfo = kzalloc(sizeof(MediaIPFW_Video_SeqInfo), GFP_KERNEL);
+       if (!ctx->pSeqinfo)
+               vpu_dbg(LVL_ERR, "error: pSeqinfo alloc fail\n");
+       init_queue_data(ctx);
+       init_waitqueue_head(&ctx->buffer_wq);
+       mutex_lock(&dev->dev_mutex);
+       if (!dev->fw_is_ready) {
+               ret = vpu_firmware_download(dev);
+               if (ret) {
+                       vpu_dbg(LVL_ERR, "error: vpu_firmware_download fail\n");
+                       mutex_unlock(&dev->dev_mutex);
+                       return ret;
+               }
+               dev->fw_is_ready = true;
+       }
+       mutex_unlock(&dev->dev_mutex);
+
+       rpc_set_stream_cfg_value(dev->shared_mem.pSharedInterface, ctx->str_index);
+       for (i = 0; i < MAX_DCP_NUM; i++) {
+               ctx->dcp_dma_virt[i] = NULL;
+               ctx->dcp_dma_phy[i] = 0;
+       }
+       ctx->dcp_count = 0;
+       for (i = 0; i < MAX_MBI_NUM; i++) {
+               ctx->mbi_dma_virt[i] = NULL;
+               ctx->mbi_dma_phy[i] = 0;
+       }
+       ctx->mbi_count = 0;
+       ctx->mbi_num = 0;
+       ctx->mbi_size = 0;
+       ctx->stream_buffer_size = MAX_BUFFER_SIZE;
+       ctx->stream_buffer_virt = dma_alloc_coherent(&ctx->dev->plat_dev->dev,
+                       ctx->stream_buffer_size,
+                       (dma_addr_t *)&ctx->stream_buffer_phy,
+                       GFP_KERNEL | GFP_DMA32
+                       );
+       if (!ctx->stream_buffer_virt)
+               vpu_dbg(LVL_ERR, "error: %s() stream buffer alloc size(%x) fail!\n", __func__, ctx->stream_buffer_size);
+       else
+               vpu_dbg(LVL_INFO, "%s() stream_buffer_size(%d) stream_buffer_virt(%p) stream_buffer_phy(%p)\n",
+                               __func__, ctx->stream_buffer_size, ctx->stream_buffer_virt, (void *)ctx->stream_buffer_phy);
+       ctx->udata_buffer_size = UDATA_BUFFER_SIZE;
+       ctx->udata_buffer_virt = dma_alloc_coherent(&ctx->dev->plat_dev->dev,
+                       ctx->udata_buffer_size,
+                       (dma_addr_t *)&ctx->udata_buffer_phy,
+                       GFP_KERNEL | GFP_DMA32
+                       );
+
+       if (!ctx->udata_buffer_virt)
+               vpu_dbg(LVL_ERR, "error: %s() udata buffer alloc size(%x) fail!\n", __func__, ctx->udata_buffer_size);
+       else
+               vpu_dbg(LVL_INFO, "%s() udata_buffer_size(%d) udata_buffer_virt(%p) udata_buffer_phy(%p)\n",
+                               __func__, ctx->udata_buffer_size, ctx->udata_buffer_virt, (void *)ctx->udata_buffer_phy);
+
+       return 0;
+}
+
+static int v4l2_release(struct file *filp)
+{
+       struct video_device *vdev = video_devdata(filp);
+       struct vpu_dev *dev = video_get_drvdata(vdev);
+       struct vpu_ctx *ctx = v4l2_fh_to_ctx(filp->private_data);
+       u_int32 i;
+
+       release_queue_data(ctx);
+       ctrls_delete_decoder(ctx);
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       clear_bit(ctx->str_index, &dev->instance_mask);
+
+       for (i = 0; i < MAX_DCP_NUM; i++)
+               if (ctx->dcp_dma_virt[i] != NULL)
+               dma_free_coherent(&ctx->dev->plat_dev->dev,
+                               ctx->uDCPSize,
+                               ctx->dcp_dma_virt[i],
+                               ctx->dcp_dma_phy[i]
+                               );
+       for (i = 0; i < MAX_MBI_NUM; i++)
+               if (ctx->mbi_dma_virt[i] != NULL)
+               dma_free_coherent(&ctx->dev->plat_dev->dev,
+                               ctx->mbi_size,
+                               ctx->mbi_dma_virt[i],
+                               ctx->mbi_dma_phy[i]
+                               );
+       if (ctx->stream_buffer_virt)
+               dma_free_coherent(&ctx->dev->plat_dev->dev,
+                               ctx->stream_buffer_size,
+                               ctx->stream_buffer_virt,
+                               ctx->stream_buffer_phy
+                               );
+       if (ctx->udata_buffer_virt)
+               dma_free_coherent(&ctx->dev->plat_dev->dev,
+                               ctx->udata_buffer_size,
+                               ctx->udata_buffer_virt,
+                               ctx->udata_buffer_phy
+                               );
+
+       if (ctx->pSeqinfo) {
+               kfree(ctx->pSeqinfo);
+               ctx->pSeqinfo = NULL;
+       }
+       kfree(ctx);
+       return 0;
+}
+
+static unsigned int v4l2_poll(struct file *filp, poll_table *wait)
+{
+       struct vpu_ctx *ctx = v4l2_fh_to_ctx(filp->private_data);
+       struct vb2_queue *src_q, *dst_q;
+       unsigned int rc = 0;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (ctx) {
+               poll_wait(filp, &ctx->fh.wait, wait);
+
+               if (v4l2_event_pending(&ctx->fh)) {
+                       vpu_dbg(LVL_INFO, "%s() v4l2_event_pending\n", __func__);
+                       rc |= POLLPRI;
+               }
+
+               src_q = &ctx->q_data[V4L2_SRC].vb2_q;
+               dst_q = &ctx->q_data[V4L2_DST].vb2_q;
+
+               if ((!src_q->streaming || list_empty(&src_q->queued_list))
+                               && (!dst_q->streaming || list_empty(&dst_q->queued_list))) {
+                       return rc;
+               }
+
+               poll_wait(filp, &src_q->done_wq, wait);
+               if (!list_empty(&src_q->done_list))
+                       rc |= POLLOUT | POLLWRNORM;
+               poll_wait(filp, &dst_q->done_wq, wait);
+               if (!list_empty(&dst_q->done_list))
+                       rc |= POLLIN | POLLWRNORM;
+       } else
+               rc = POLLERR;
+
+       return rc;
+}
+
+static int v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       long ret = -EPERM;
+       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       struct queue_data *q_data;
+       enum QUEUE_TYPE type;
+
+       struct vpu_ctx *ctx = v4l2_fh_to_ctx(filp->private_data);
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (ctx) {
+               type = offset >> MMAP_BUF_TYPE_SHIFT;
+               q_data = &ctx->q_data[type];
+
+               offset &= ~MMAP_BUF_TYPE_MASK;
+               offset = offset >> PAGE_SHIFT;
+               vma->vm_pgoff = offset;
+               ret = vb2_mmap(&q_data->vb2_q,
+                                               vma
+                                               );
+       }
+
+       return ret;
+}
+
+static const struct v4l2_file_operations v4l2_decoder_fops = {
+       .owner = THIS_MODULE,
+       .open  = v4l2_open,
+       .unlocked_ioctl = video_ioctl2,
+       .release = v4l2_release,
+       .poll = v4l2_poll,
+       .mmap = v4l2_mmap,
+};
+
+static struct video_device v4l2_videodevice_decoder = {
+       .name   = "vpu decoder",
+       .fops   = &v4l2_decoder_fops,
+       .ioctl_ops = &v4l2_decoder_ioctl_ops,
+       .vfl_dir = VFL_DIR_M2M,
+};
+
+static int set_vpu_pwr(sc_ipc_t ipcHndl,
+               sc_pm_power_mode_t pm
+               )
+{
+       int rv = -1;
+       sc_err_t sciErr;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+       if (!ipcHndl) {
+               vpu_dbg(LVL_ERR, "error: --- set_vpu_pwr no IPC handle\n");
+               goto set_vpu_pwrexit;
+       }
+
+       // Power on or off PID0, DEC, ENC
+       sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_PID0, pm);
+       if (sciErr != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU_PID0,%d) SCI error! (%d)\n", sciErr, pm);
+               goto set_vpu_pwrexit;
+       }
+       sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_PID1, pm);
+       if (sciErr != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU_PID1,%d) SCI error! (%d)\n", sciErr, pm);
+               goto set_vpu_pwrexit;
+       }
+       sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_PID2, pm);
+       if (sciErr != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU_PID2,%d) SCI error! (%d)\n", sciErr, pm);
+               goto set_vpu_pwrexit;
+       }
+       sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_PID3, pm);
+       if (sciErr != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU_PID3,%d) SCI error! (%d)\n", sciErr, pm);
+               goto set_vpu_pwrexit;
+       }
+       sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_PID4, pm);
+       if (sciErr != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU_PID4,%d) SCI error! (%d)\n", sciErr, pm);
+               goto set_vpu_pwrexit;
+       }
+       sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_PID5, pm);
+       if (sciErr != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU_PID5,%d) SCI error! (%d)\n", sciErr, pm);
+               goto set_vpu_pwrexit;
+       }
+       sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_PID6, pm);
+       if (sciErr != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU_PID6,%d) SCI error! (%d)\n", sciErr, pm);
+               goto set_vpu_pwrexit;
+       }
+       sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_PID7, pm);
+       if (sciErr != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU_PID7,%d) SCI error! (%d)\n", sciErr, pm);
+               goto set_vpu_pwrexit;
+       }
+#ifdef TEST_BUILD
+       sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_DEC, pm);
+       if (sciErr != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU_DEC,%d) SCI error! (%d)\n", sciErr, pm);
+               goto set_vpu_pwrexit;
+       }
+       sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_ENC, pm);
+       if (sciErr != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU_ENC,%d) SCI error! (%d)\n", sciErr, pm);
+               goto set_vpu_pwrexit;
+       }
+#else
+       sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_DEC_0, pm);
+       if (sciErr != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU_DEC_0,%d) SCI error! (%d)\n", sciErr, pm);
+               goto set_vpu_pwrexit;
+       }
+       sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_ENC_0, pm);
+       if (sciErr != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU_ENC_0,%d) SCI error! (%d)\n", sciErr, pm);
+               goto set_vpu_pwrexit;
+       }
+#endif
+
+       rv = 0;
+
+set_vpu_pwrexit:
+       return rv;
+}
+
+static void vpu_set_power(struct vpu_dev *dev, bool on)
+{
+       int ret;
+
+       if (on) {
+               ret = set_vpu_pwr(dev->mu_ipcHandle, SC_PM_PW_MODE_ON);
+               if (ret)
+                       vpu_dbg(LVL_ERR, "error: failed to power on\n");
+               pm_runtime_get_sync(dev->generic_dev);
+       } else {
+               pm_runtime_put_sync_suspend(dev->generic_dev);
+               ret = set_vpu_pwr(dev->mu_ipcHandle, SC_PM_PW_MODE_OFF);
+               if (ret)
+                       vpu_dbg(LVL_ERR, "error: failed to power off\n");
+       }
+}
+
+static void vpu_setup(struct vpu_dev *This)
+{
+       uint32_t read_data = 0;
+
+       vpu_dbg(LVL_INFO, "enter %s\n", __func__);
+       writel(0x1, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_SCB_CLK_ENABLE_SET);
+       writel(0xffffffff, This->regs_base + 0x70190);
+       writel(0xffffffff, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_XMEM_RESET_SET);
+
+       writel(0xE, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_SCB_CLK_ENABLE_SET);
+       writel(0x7, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_CACHE_RESET_SET);
+
+       writel(0x1f, This->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_BLK_CTRL + MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_SET);
+       writel(0xffffffff, This->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_BLK_CTRL + MFD_BLK_CTRL_MFD_SYS_RESET_SET);
+
+       writel(0x102, This->regs_base + XMEM_CONTROL);
+
+       read_data = readl(This->regs_base+0x70108);
+       vpu_dbg(LVL_IRQ, "%s read_data=%x\n", __func__, read_data);
+}
+
+static void vpu_reset(struct vpu_dev *This)
+{
+       vpu_dbg(LVL_INFO, "enter %s\n", __func__);
+       writel(0x7, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_CACHE_RESET_CLR);
+       writel(0xffffffff, This->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_BLK_CTRL + MFD_BLK_CTRL_MFD_SYS_RESET_CLR);
+}
+
+static int vpu_enable_hw(struct vpu_dev *This)
+{
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+       vpu_set_power(This, true);
+       This->vpu_clk = clk_get(&This->plat_dev->dev, "vpu_clk");
+       if (IS_ERR(This->vpu_clk)) {
+               vpu_dbg(LVL_ERR, "vpu_clk get error\n");
+               return -ENOENT;
+       }
+       clk_set_rate(This->vpu_clk, 600000000);
+       clk_prepare_enable(This->vpu_clk);
+       vpu_setup(This);
+       return 0;
+}
+static void vpu_disable_hw(struct vpu_dev *This)
+{
+       vpu_reset(This);
+       if (This->regs_base) {
+               devm_iounmap(&This->plat_dev->dev,
+                               This->regs_base);
+       }
+       clk_disable_unprepare(This->vpu_clk);
+       if (This->vpu_clk) {
+               clk_put(This->vpu_clk);
+               This->vpu_clk = NULL;
+       }
+       vpu_set_power(This, false);
+}
+
+static int vpu_probe(struct platform_device *pdev)
+{
+       struct vpu_dev *dev;
+       struct resource *res;
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *reserved_node;
+       struct resource reserved_res;
+       unsigned int mu_id;
+       int ret;
+
+       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+
+       dev->plat_dev = pdev;
+       dev->generic_dev = &pdev->dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       dev->regs_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(dev->regs_base)) {
+               vpu_dbg(LVL_ERR, "error: %s could not map regs_base\n", __func__);
+               return PTR_ERR(dev->regs_base);
+       }
+
+       if (np) {
+               reserved_node = of_parse_phandle(np, "boot-region", 0);
+               if (!reserved_node) {
+                       vpu_dbg(LVL_ERR, "error: boot-region of_parse_phandle error\n");
+                       return -ENODEV;
+               }
+
+               if (of_address_to_resource(reserved_node, 0, &reserved_res)) {
+                       vpu_dbg(LVL_ERR, "error: boot-region of_address_to_resource error\n");
+                       return -EINVAL;
+               }
+               dev->m0_p_fw_space_phy = reserved_res.start;
+               dev->cm_offset = 0;
+               reserved_node = of_parse_phandle(np, "rpc-region", 0);
+               if (!reserved_node) {
+                       vpu_dbg(LVL_ERR, "error: rpc-region of_parse_phandle error\n");
+                       return -ENODEV;
+               }
+
+               if (of_address_to_resource(reserved_node, 0, &reserved_res)) {
+                       vpu_dbg(LVL_ERR, "error: rpc-region of_address_to_resource error\n");
+                       return -EINVAL;
+               }
+               dev->m0_rpc_phy = reserved_res.start;
+       } else
+               vpu_dbg(LVL_ERR, "error: %s of_node is NULL\n", __func__);
+
+       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+       if (ret) {
+               vpu_dbg(LVL_ERR, "error: %s unable to register v4l2 dev\n", __func__);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, dev);
+
+       dev->pvpu_decoder_dev = video_device_alloc();
+       if (dev->pvpu_decoder_dev) {
+               strncpy(dev->pvpu_decoder_dev->name, v4l2_videodevice_decoder.name, sizeof(v4l2_videodevice_decoder.name));
+               dev->pvpu_decoder_dev->fops = v4l2_videodevice_decoder.fops;
+               dev->pvpu_decoder_dev->ioctl_ops = v4l2_videodevice_decoder.ioctl_ops;
+               dev->pvpu_decoder_dev->release = video_device_release;
+               dev->pvpu_decoder_dev->vfl_dir = v4l2_videodevice_decoder.vfl_dir;
+               dev->pvpu_decoder_dev->v4l2_dev = &dev->v4l2_dev;
+
+               video_set_drvdata(dev->pvpu_decoder_dev, dev);
+
+               if (video_register_device(dev->pvpu_decoder_dev,
+                                       VFL_TYPE_GRABBER,
+                                       -1)) {
+                       vpu_dbg(LVL_ERR, "error: %s unable to register video decoder device\n",
+                                       __func__
+                                       );
+                       video_device_release(dev->pvpu_decoder_dev);
+                       dev->pvpu_decoder_dev = NULL;
+               } else {
+                       vpu_dbg(LVL_INFO, "error: %s  register video decoder device\n",
+                                       __func__
+                                  );
+               }
+       }
+
+       if (!dev->mu_ipcHandle) {
+               ret = sc_ipc_getMuID(&mu_id);
+               if (ret) {
+                       vpu_dbg(LVL_ERR, "error: --- sc_ipc_getMuID() cannot obtain mu id SCI error! (%d)\n", ret);
+                       return ret;
+               }
+
+               ret = sc_ipc_open(&dev->mu_ipcHandle, mu_id);
+               if (ret) {
+                       vpu_dbg(LVL_ERR, "error: --- sc_ipc_getMuID() cannot open MU channel to SCU error! (%d)\n", ret);
+                       return ret;
+               }
+       }
+
+       vpu_enable_hw(dev);
+
+       mutex_init(&dev->dev_mutex);
+       dev->fw_is_ready = false;
+       dev->workqueue = alloc_workqueue("vpu", WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+       if (!dev->workqueue) {
+               vpu_dbg(LVL_ERR, "error: %s unable to alloc workqueue\n", __func__);
+               ret = -ENOMEM;
+               return ret;
+       }
+
+       INIT_WORK(&dev->msg_work, vpu_msg_run_work);
+#ifdef CM4
+       ret = power_CM4_up(dev);
+       if (ret) {
+               vpu_dbg(LVL_ERR, "error: failed to power on CM4\n");
+               return ret;
+       }
+#endif
+       ret = vpu_mu_init(dev);
+       if (ret) {
+               vpu_dbg(LVL_ERR, "error: %s vpu mu init failed\n", __func__);
+               return ret;
+       }
+
+       //firmware space for M0
+       dev->m0_p_fw_space_vir = ioremap(dev->m0_p_fw_space_phy,
+                       M0_BOOT_SIZE
+                       );
+       if (!dev->m0_p_fw_space_vir)
+               vpu_dbg(LVL_ERR, "error: failed to remap space for M0 firmware\n");
+
+       memset_io(dev->m0_p_fw_space_vir, 0, M0_BOOT_SIZE);
+
+       dev->m0_rpc_virt = ioremap(dev->m0_rpc_phy,
+                       SHARED_SIZE
+                       );
+       if (!dev->m0_rpc_virt)
+               vpu_dbg(LVL_ERR, "error: failed to remap space for rpc shared memory\n");
+
+       memset_io(dev->m0_rpc_virt, 0, SHARED_SIZE);
+#ifdef CM4
+       rpc_init_shared_memory(&dev->shared_mem, dev->m0_rpc_phy, dev->m0_rpc_virt, SHARED_SIZE);
+#else
+       rpc_init_shared_memory(&dev->shared_mem, dev->m0_rpc_phy - dev->m0_p_fw_space_phy, dev->m0_rpc_virt, SHARED_SIZE);
+#endif
+       rpc_set_system_cfg_value(dev->shared_mem.pSharedInterface, VPU_REG_BASE);
+
+       return 0;
+}
+
+static int vpu_remove(struct platform_device *pdev)
+{
+       struct vpu_dev *dev = platform_get_drvdata(pdev);
+
+       destroy_workqueue(dev->workqueue);
+       if (dev->m0_p_fw_space_vir)
+               iounmap(dev->m0_p_fw_space_vir);
+       if (dev->m0_pfw) {
+               release_firmware(dev->m0_pfw);
+               dev->m0_pfw = NULL;
+       }
+       dev->m0_p_fw_space_vir = NULL;
+       dev->m0_p_fw_space_phy = 0;
+       dev->m0_rpc_virt = NULL;
+       dev->m0_rpc_phy = 0;
+       if (dev->shared_mem.shared_mem_vir)
+               iounmap(dev->shared_mem.shared_mem_vir);
+       dev->shared_mem.shared_mem_vir = NULL;
+       dev->shared_mem.shared_mem_phy = 0;
+
+       vpu_disable_hw(dev);
+
+       if (video_get_drvdata(dev->pvpu_decoder_dev))
+               video_unregister_device(dev->pvpu_decoder_dev);
+
+       v4l2_device_unregister(&dev->v4l2_dev);
+       return 0;
+}
+
+static int vpu_runtime_suspend(struct device *dev)
+{
+       return 0;
+}
+
+static int vpu_runtime_resume(struct device *dev)
+{
+       return 0;
+}
+
+static int vpu_suspend(struct device *dev)
+{
+       return 0;
+}
+
+static int vpu_resume(struct device *dev)
+{
+       return 0;
+}
+
+static const struct dev_pm_ops vpu_pm_ops = {
+       SET_RUNTIME_PM_OPS(vpu_runtime_suspend, vpu_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(vpu_suspend, vpu_resume)
+};
+
+static const struct of_device_id vpu_of_match[] = {
+       { .compatible = "nxp,imx8qm-vpu-decoder", },
+       { .compatible = "nxp,imx8qxp-vpu-decoder", },
+       {}
+}
+MODULE_DEVICE_TABLE(of, vpu_of_match);
+
+static struct platform_driver vpu_driver = {
+       .probe = vpu_probe,
+       .remove = vpu_remove,
+       .driver = {
+               .name = "vpu-b0",
+               .of_match_table = vpu_of_match,
+               .pm = &vpu_pm_ops,
+       },
+};
+module_platform_driver(vpu_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Linux VPU driver for Freescale i.MX/MXC");
+MODULE_LICENSE("GPL");
+
+module_param(vpu_dbg_level_decoder, int, 0644);
+MODULE_PARM_DESC(vpu_dbg_level_decoder, "Debug level (0-2)");
+
diff --git a/drivers/mxc/vpu-decoder-b0/vpu_b0.h b/drivers/mxc/vpu-decoder-b0/vpu_b0.h
new file mode 100644 (file)
index 0000000..371668b
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2018 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU Lesser General
+ * Public License.  You may obtain a copy of the GNU Lesser General
+ * Public License Version 2.1 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/lgpl-license.html
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+/*!
+ * @file vpu_b0.h
+ *
+ * @brief VPU B0 definition
+ *
+ */
+#ifndef __VPU_B0_H
+#define __VPU_B0_H
+
+#include <linux/irqreturn.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/videobuf2-v4l2.h>
+#include <soc/imx8/sc/svc/irq/api.h>
+#include <soc/imx8/sc/ipc.h>
+#include <soc/imx8/sc/sci.h>
+#include <linux/mx8_mu.h>
+#include <media/v4l2-event.h>
+#include "vpu_rpc.h"
+
+extern unsigned int vpu_dbg_level_decoder;
+
+#define v4l2_fh_to_ctx(__fh) \
+       container_of(__fh, struct vpu_ctx, fh)
+#define v4l2_ctrl_to_ctx(__ctrl) \
+       container_of((__ctrl)->handler, struct vpu_ctx, ctrl_handler)
+
+#define MIN_SPACE 2048
+
+#define VPU_MAX_FORMATS 4
+#define VPU_MAX_BUFFER 32
+#define M0FW_FILENAME "decoder_main.bin"
+#define MMAP_BUF_TYPE_SHIFT 28
+#define MMAP_BUF_TYPE_MASK 0xF0000000
+#define M0_BOOT_SIZE 0x1000000
+#define M0_PRINT_OFFSET 0x500000
+#define DCP_SIZE 0x3000000
+#define MAX_BUFFER_SIZE 5242880
+#define UDATA_BUFFER_SIZE 0x1000
+#define SHARED_SIZE 0x00400000
+#define MAX_DCP_NUM 2
+#define MAX_MBI_NUM 18 // same with MEDIA_PLAYER_MAX_MBI_UNIT defined in firmware
+#define MAX_TIMEOUT_COUNT 10
+#ifdef CM4
+#define VPU_REG_BASE 0x2c000000
+#else
+#define VPU_REG_BASE 0x40000000
+#endif
+
+#define V4L2_MAX_CTRLS 12
+
+struct vpu_v4l2_control {
+       uint32_t id;
+       enum v4l2_ctrl_type type;
+       uint32_t minimum;
+       uint32_t maximum;
+       uint32_t step;
+       uint32_t default_value;
+       uint32_t menu_skip_mask;
+       bool is_volatile;
+};
+
+typedef enum{
+       INIT_DONE = 1,
+       RPC_BUF_OFFSET,
+       PRINT_BUF_OFFSET,
+       BOOT_ADDRESS,
+       COMMAND,
+       EVENT
+} MSG_Type;
+
+
+enum QUEUE_TYPE {
+       V4L2_SRC = 0,
+       V4L2_DST = 1,
+};
+
+enum vpu_video_standard {
+       VPU_VIDEO_UNDEFINED = 0,
+       VPU_VIDEO_AVC = 1,
+       VPU_VIDEO_VC1 = 2,
+       VPU_VIDEO_MPEG2 = 3,
+       VPU_VIDEO_AVS = 4,
+       VPU_VIDEO_ASP = 5,
+       VPU_VIDEO_JPEG = 6,
+       VPU_VIDEO_RV8 = 7,
+       VPU_VIDEO_RV9 = 8,
+       VPU_VIDEO_VP6 = 9,
+       VPU_VIDEO_SPK = 10,
+       VPU_VIDEO_VP8 = 11,
+       VPU_VIDEO_AVC_MVC = 12,
+       VPU_VIDEO_HEVC = 13,
+       VPU_VIDEO_VP9 = 14,
+};
+
+#define VPU_PIX_FMT_AVS         v4l2_fourcc('A', 'V', 'S', '0')
+#define VPU_PIX_FMT_ASP         v4l2_fourcc('A', 'S', 'P', '0')
+#define VPU_PIX_FMT_RV8         v4l2_fourcc('R', 'V', '8', '0')
+#define VPU_PIX_FMT_RV9         v4l2_fourcc('R', 'V', '9', '0')
+#define VPU_PIX_FMT_VP6         v4l2_fourcc('V', 'P', '6', '0')
+#define VPU_PIX_FMT_SPK         v4l2_fourcc('S', 'P', 'K', '0')
+#define VPU_PIX_FMT_HEVC        v4l2_fourcc('H', 'E', 'V', 'C')
+#define VPU_PIX_FMT_VP9         v4l2_fourcc('V', 'P', '9', '0')
+#define VPU_PIX_FMT_LOGO        v4l2_fourcc('L', 'O', 'G', 'O')
+
+#define VPU_PIX_FMT_TILED_8     v4l2_fourcc('Z', 'T', '0', '8')
+#define VPU_PIX_FMT_TILED_10    v4l2_fourcc('Z', 'T', '1', '0')
+
+enum vpu_pixel_format {
+       VPU_HAS_COLOCATED = 0x00000001,
+       VPU_HAS_SPLIT_FLD = 0x00000002,
+       VPU_PF_MASK       = ~(VPU_HAS_COLOCATED | VPU_HAS_SPLIT_FLD),
+
+       VPU_IS_TILED      = 0x000000100,
+       VPU_HAS_10BPP     = 0x00000200,
+
+       VPU_IS_PLANAR     = 0x00001000,
+       VPU_IS_SEMIPLANAR = 0x00002000,
+       VPU_IS_PACKED     = 0x00004000,
+
+       // Merged definitions using above flags:
+       VPU_PF_UNDEFINED  = 0,
+       VPU_PF_YUV420_SEMIPLANAR = 0x00010000 | VPU_IS_SEMIPLANAR,
+       VPU_PF_YUV420_PLANAR = 0x00020000 | VPU_IS_PLANAR,
+       VPU_PF_UYVY = 0x00040000 | VPU_IS_PACKED,
+       VPU_PF_TILED_8BPP = 0x00080000 | VPU_IS_TILED | VPU_IS_SEMIPLANAR,
+       VPU_PF_TILED_10BPP = 0x00100000 | VPU_IS_TILED | VPU_IS_SEMIPLANAR | VPU_HAS_10BPP,
+};
+
+struct vpu_v4l2_fmt {
+       char *name;
+       unsigned int fourcc;
+       unsigned int num_planes;
+       unsigned int vdec_std;
+};
+
+struct vb2_data_req {
+       struct list_head  list;
+       struct vb2_buffer *vb2_buf;
+       int id;
+       u_int32 status;
+};
+
+struct queue_data {
+       unsigned int width;
+       unsigned int height;
+       unsigned int stride;
+       unsigned int bytesperline;
+       unsigned int sizeimage[2];
+       unsigned int fourcc;
+       unsigned int vdec_std;
+       struct v4l2_rect rect;
+       int buf_type; // v4l2_buf_type
+       bool vb2_q_inited;
+       struct vb2_queue vb2_q;    // vb2 queue
+       struct list_head drv_q;    // driver queue
+       struct semaphore drv_q_lock;
+       struct vb2_data_req vb2_reqs[VPU_MAX_BUFFER];
+       enum QUEUE_TYPE type;
+};
+struct vpu_ctx;
+struct vpu_dev {
+       struct device *generic_dev;
+       struct v4l2_device v4l2_dev;
+       struct video_device *pvpu_decoder_dev;
+       struct platform_device *plat_dev;
+       struct firmware *m0_pfw;
+       void *m0_p_fw_space_vir;
+       u_int32 m0_p_fw_space_phy;
+       void *m0_rpc_virt;
+       u_int32 m0_rpc_phy;
+       struct mutex dev_mutex;
+       bool fw_is_ready;
+       struct completion msg_complete;
+       struct workqueue_struct *workqueue;
+       struct work_struct msg_work;
+       unsigned long instance_mask;
+       sc_ipc_t mu_ipcHandle;
+       struct clk *vpu_clk;
+       void __iomem *mu_base_virtaddr;
+       unsigned int vpu_mu_id;
+       int vpu_mu_init;
+
+       struct clk *clk_m0;
+       void __iomem *regs_base;
+       u_int32 cm_offset;
+
+       struct shared_addr shared_mem;
+       struct vpu_ctx *ctx[VPU_MAX_NUM_STREAMS];
+};
+
+struct vpu_ctx {
+       struct vpu_dev *dev;
+       struct v4l2_fh fh;
+
+       struct v4l2_ctrl *ctrls[V4L2_MAX_CTRLS];
+       struct v4l2_ctrl_handler ctrl_handler;
+       bool ctrl_inited;
+
+       int str_index;
+       struct queue_data q_data[2];
+//     struct work_struct msg_work;
+       struct completion completion;
+       MediaIPFW_Video_SeqInfo *pSeqinfo;
+       bool b_firstseq;
+       bool start_flag;
+       bool wait_rst_done;
+       bool firmware_stopped;
+       wait_queue_head_t buffer_wq;
+       void *dpb_dma_virt;
+       u_int32 uSize;
+       dma_addr_t dpb_dma_phy;
+       void *dcp_dma_virt[MAX_DCP_NUM];
+       u_int32 uDCPSize;
+       dma_addr_t dcp_dma_phy[MAX_DCP_NUM];
+       u_int32 dcp_count;
+       void *mbi_dma_virt[MAX_MBI_NUM];
+       u_int32 mbi_size;
+       dma_addr_t mbi_dma_phy[MAX_MBI_NUM];
+       u_int32 mbi_count;
+       u_int32 mbi_num;
+       void *stream_buffer_virt;
+       u_int32 stream_buffer_size;
+       dma_addr_t stream_buffer_phy;
+       void *udata_buffer_virt;
+       u_int32 udata_buffer_size;
+       dma_addr_t udata_buffer_phy;
+};
+
+#define LVL_INFO 3
+#define LVL_IRQ  2
+#define LVL_ALL  1
+#define LVL_ERR  0
+
+#define vpu_dbg(level, fmt, arg...) \
+       do { \
+               if (vpu_dbg_level_decoder >= (level)) \
+                       printk("[DEBUG]\t " fmt, ## arg); \
+       } while (0)
+
+#endif
diff --git a/drivers/mxc/vpu-decoder-b0/vpu_rpc.c b/drivers/mxc/vpu-decoder-b0/vpu_rpc.c
new file mode 100644 (file)
index 0000000..232f481
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "vpu_rpc.h"
+
+void rpc_init_shared_memory(struct shared_addr *This,
+               unsigned long long base_phy_addr,
+               void *base_virt_addr,
+               u_int32 total_size)
+{
+       pDEC_RPC_HOST_IFACE pSharedInterface;
+       unsigned int phy_addr;
+       unsigned int i;
+       MediaIPFW_Video_BufDesc *pSharedCmdBufDescPtr;
+       MediaIPFW_Video_BufDesc *pSharedMsgBufDescPtr;
+       MediaIPFW_Video_BufDesc *pDebugBufferDesc;
+       MediaIPFW_Video_BufDesc *pEngAccessBufferDesc;
+
+       This->shared_mem_phy = base_phy_addr;
+       This->shared_mem_vir = base_virt_addr;
+
+       pSharedInterface = (pDEC_RPC_HOST_IFACE)This->shared_mem_vir;
+       This->pSharedInterface = pSharedInterface;
+
+       pSharedInterface->FwExecBaseAddr = base_phy_addr;
+       pSharedInterface->FwExecAreaSize = total_size;
+
+       pSharedCmdBufDescPtr = (MediaIPFW_Video_BufDesc *)&pSharedInterface->StreamCmdBufferDesc;
+       pSharedMsgBufDescPtr = (MediaIPFW_Video_BufDesc *)&pSharedInterface->StreamMsgBufferDesc;
+
+       phy_addr = base_phy_addr + sizeof(DEC_RPC_HOST_IFACE);
+       This->cmd_mem_phy = phy_addr;
+       This->cmd_mem_vir = This->shared_mem_vir + sizeof(DEC_RPC_HOST_IFACE);
+
+       pSharedCmdBufDescPtr->uWrPtr = phy_addr;
+       pSharedCmdBufDescPtr->uRdPtr = pSharedCmdBufDescPtr->uWrPtr;
+       pSharedCmdBufDescPtr->uStart = pSharedCmdBufDescPtr->uWrPtr;
+       pSharedCmdBufDescPtr->uEnd = pSharedCmdBufDescPtr->uStart + CMD_SIZE;
+
+       phy_addr += CMD_SIZE;
+       This->msg_mem_phy = phy_addr;
+       This->msg_mem_vir = This->cmd_mem_vir + CMD_SIZE;
+
+       pSharedMsgBufDescPtr->uWrPtr = phy_addr;
+       pSharedMsgBufDescPtr->uRdPtr = pSharedMsgBufDescPtr->uWrPtr;
+       pSharedMsgBufDescPtr->uStart = pSharedMsgBufDescPtr->uWrPtr;
+       pSharedMsgBufDescPtr->uEnd = pSharedMsgBufDescPtr->uStart + MSG_SIZE;
+
+       phy_addr += MSG_SIZE;
+       This->codec_mem_phy = phy_addr;
+       This->codec_mem_vir = This->msg_mem_vir + MSG_SIZE;
+       pSharedInterface->CodecParamTabDesc.pCodecParamArrayBase = This->codec_mem_phy;
+
+       phy_addr += CODEC_SIZE;
+       This->jpeg_mem_phy = phy_addr;
+       This->jpeg_mem_vir = This->codec_mem_vir + CODEC_SIZE;
+       pSharedInterface->JpegParamTabDesc.pJpegParamArrayBase = This->jpeg_mem_phy;
+
+       phy_addr += JPEG_SIZE;
+       This->seq_mem_phy = phy_addr;
+       This->seq_mem_vir = This->jpeg_mem_vir + JPEG_SIZE;
+
+       pSharedInterface->SeqInfoTabDesc.pSeqInfoArrayBase = This->seq_mem_phy;
+
+       phy_addr += SEQ_SIZE;
+       This->pic_mem_phy = phy_addr;
+       This->pic_mem_vir = This->seq_mem_vir + SEQ_SIZE;
+
+       pSharedInterface->PicInfoTabDesc.pPicInfoArrayBase = This->pic_mem_phy;
+
+       phy_addr += PIC_SIZE;
+       This->gop_mem_phy = phy_addr;
+       This->gop_mem_vir = This->pic_mem_vir + PIC_SIZE;
+
+       pSharedInterface->GopInfoTabDesc.pGopInfoArrayBase = This->gop_mem_phy;
+
+       phy_addr += GOP_SIZE;
+       This->qmeter_mem_phy = phy_addr;
+       This->qmeter_mem_vir = This->gop_mem_vir + GOP_SIZE;
+
+       pSharedInterface->QMeterInfoTabDesc.pQMeterInfoArrayBase = This->qmeter_mem_phy;
+
+       phy_addr += QMETER_SIZE;
+       pDebugBufferDesc = &pSharedInterface->DebugBufferDesc;
+       pDebugBufferDesc->uWrPtr = phy_addr;
+       pDebugBufferDesc->uRdPtr = pDebugBufferDesc->uWrPtr;
+       pDebugBufferDesc->uStart = pDebugBufferDesc->uWrPtr;
+       pDebugBufferDesc->uEnd = pDebugBufferDesc->uStart + DEBUG_SIZE;
+
+       phy_addr += DEBUG_SIZE;
+       for (i = 0; i < VPU_MAX_NUM_STREAMS; i++) {
+               pEngAccessBufferDesc = &pSharedInterface->EngAccessBufferDesc[i];
+               pEngAccessBufferDesc->uWrPtr = phy_addr;
+               pEngAccessBufferDesc->uRdPtr = pEngAccessBufferDesc->uWrPtr;
+               pEngAccessBufferDesc->uStart = pEngAccessBufferDesc->uWrPtr;
+               pEngAccessBufferDesc->uEnd = pEngAccessBufferDesc->uStart + ENG_SIZE;
+               phy_addr += ENG_SIZE;
+       }
+
+       for (i = 0; i < VPU_MAX_NUM_STREAMS; i++) {
+               pSharedInterface->ptEncryptInfo[i] = phy_addr;
+               phy_addr += sizeof(MediaIPFW_Video_Encrypt_Info);
+       }
+}
+
+void rpc_set_stream_cfg_value(void *Interface, u_int32 str_idx)
+{
+       pDEC_RPC_HOST_IFACE pSharedInterface;
+       u_int32 *CurrStrfg;
+
+       pSharedInterface = (pDEC_RPC_HOST_IFACE)Interface;
+       CurrStrfg = &pSharedInterface->StreamConfig[str_idx];
+       *CurrStrfg = 0;
+       //the value should be passed from application
+       VID_STREAM_CONFIG_STRBUFIDX_SET(0, CurrStrfg);
+       VID_STREAM_CONFIG_NOSEQ_SET(FALSE, CurrStrfg);
+       VID_STREAM_CONFIG_DEBLOCK_SET(FALSE, CurrStrfg);
+       VID_STREAM_CONFIG_DERING_SET(FALSE, CurrStrfg);
+       VID_STREAM_CONFIG_PLAY_MODE_SET(MEDIA_PLAYER_API_MODE_CONTINUOUS, CurrStrfg);
+       VID_STREAM_CONFIG_FS_CTRL_MODE_SET(MEDIA_PLAYER_FS_CTRL_MODE_EXTERNAL, CurrStrfg);
+       VID_STREAM_CONFIG_ENABLE_DCP_SET(TRUE, CurrStrfg);
+       VID_STREAM_CONFIG_NUM_STR_BUF_SET(1, CurrStrfg);
+       VID_STREAM_CONFIG_MALONE_USAGE_SET(1, CurrStrfg);
+       VID_STREAM_CONFIG_MULTI_VID_SET(FALSE, CurrStrfg);
+       VID_STREAM_CONFIG_OBFUSC_EN_SET(FALSE, CurrStrfg);
+       VID_STREAM_CONFIG_RC4_EN_SET(FALSE, CurrStrfg);
+       VID_STREAM_CONFIG_MCX_SET(TRUE, CurrStrfg);
+       VID_STREAM_CONFIG_PES_SET(FALSE, CurrStrfg);
+       VID_STREAM_CONFIG_NUM_DBE_SET(1, CurrStrfg);
+}
+
+void rpc_set_system_cfg_value(void *Interface, u_int32 regs_base)
+{
+       pDEC_RPC_HOST_IFACE pSharedInterface;
+       MEDIAIP_FW_SYSTEM_CONFIG *pSystemCfg;
+
+       pSharedInterface = (pDEC_RPC_HOST_IFACE)Interface;
+       pSystemCfg = &pSharedInterface->sSystemCfg;
+       pSystemCfg->uNumMalones = 1;
+       pSystemCfg->uMaloneBaseAddress[0] = (unsigned int)(regs_base + 0x180000);
+
+       pSystemCfg->uMaloneBaseAddress[0x1] = 0x0;
+       pSystemCfg->uHifOffset[0x0] = 0x1C000;
+       pSystemCfg->uHifOffset[0x1] = 0x0;
+
+       pSystemCfg->uDPVBaseAddr = 0x0;
+       pSystemCfg->uDPVIrqPin = 0x0;
+       pSystemCfg->uPixIfBaseAddr = (unsigned int)(regs_base + 0x180000 + 0x20000);
+       pSystemCfg->uFSLCacheBaseAddr = (unsigned int)(regs_base + 0x60000);
+}
+
+u_int32 rpc_MediaIPFW_Video_buffer_space_check(MediaIPFW_Video_BufDesc *pBufDesc,
+       BOOL bFull,
+       u_int32 uSize,
+       u_int32 *puUpdateAddress)
+{
+       u_int32 uPtr1;
+       u_int32 uPtr2;
+       u_int32 uStart;
+       u_int32 uEnd;
+       u_int32 uTemp;
+
+       /* bFull is FALSE when send message, write data   */
+       /* bFull is TRUE when process commands, read data */
+       uPtr1 = (bFull) ? pBufDesc->uRdPtr : pBufDesc->uWrPtr;
+       uPtr2 = (bFull) ? pBufDesc->uWrPtr : pBufDesc->uRdPtr;
+
+       if (uPtr1 == uPtr2) {
+               if (bFull)
+                       /* No data at all to read */
+                       return 0;
+               else {
+                       /* wrt pointer equal to read pointer thus the     */
+                       /* buffer is completely empty for further writes  */
+                       uStart = pBufDesc->uStart;
+                       uEnd   = pBufDesc->uEnd;
+                       /* The address to be returned in this case is for */
+                       /* the updated write pointer.                     */
+                       uTemp = uPtr1 + uSize;
+                       if (uTemp >= uEnd)
+                               uTemp += (uStart - uEnd);
+                       *puUpdateAddress = uTemp;
+                       return (uEnd - uStart);
+               }
+       } else if (uPtr1 < uPtr2) {
+               /* return updated rd pointer address                */
+               /* In this case if size was too big - we expect the */
+               /* external ftn to compare the size against the     */
+               /* space returned.
+                */
+               *puUpdateAddress = uPtr1 + uSize;
+               return (uPtr2 - uPtr1);
+       }
+       /* We know the system has looped!! */
+       uStart = pBufDesc->uStart;
+       uEnd   = pBufDesc->uEnd;
+       uTemp  = uPtr1 + uSize;
+       if (uTemp >= uEnd)
+               uTemp += (uStart - uEnd);
+       *puUpdateAddress = uTemp;
+       return ((uEnd - uPtr1) + (uPtr2 - uStart));
+}
+
+static void rpc_update_cmd_buffer_ptr(MediaIPFW_Video_BufDesc *pCmdDesc)
+{
+       u_int32 uWritePtr;
+
+       uWritePtr = pCmdDesc->uWrPtr + 4;
+       if (uWritePtr >= pCmdDesc->uEnd)
+               uWritePtr = pCmdDesc->uStart;
+       pCmdDesc->uWrPtr = uWritePtr;
+}
+
+void rpc_send_cmd_buf(struct shared_addr *This,
+               u_int32 idx,
+               u_int32 cmdid,
+               u_int32 cmdnum,
+               u_int32 *local_cmddata)
+{
+       pDEC_RPC_HOST_IFACE pSharedInterface = (pDEC_RPC_HOST_IFACE)This->shared_mem_vir;
+       MediaIPFW_Video_BufDesc *pCmdDesc = &pSharedInterface->StreamCmdBufferDesc;
+       u_int32 *cmddata;
+       u_int32 i;
+       u_int32 *cmdword = (u_int32 *)(This->cmd_mem_vir+pCmdDesc->uWrPtr - pCmdDesc->uStart);
+
+       *cmdword = 0;
+       *cmdword |= ((idx & 0x000000ff) << 24);
+       *cmdword |= ((cmdnum & 0x000000ff) << 16);
+       *cmdword |= ((cmdid & 0x00003fff) << 0);
+       rpc_update_cmd_buffer_ptr(pCmdDesc);
+
+       for (i = 0; i < cmdnum; i++) {
+               cmddata = (u_int32 *)(This->cmd_mem_vir+pCmdDesc->uWrPtr - pCmdDesc->uStart);
+               *cmddata = local_cmddata[i];
+               rpc_update_cmd_buffer_ptr(pCmdDesc);
+       }
+}
+
+u_int32 rpc_MediaIPFW_Video_message_check(struct shared_addr *This)
+{
+       u_int32 uSpace;
+       u_int32 uIgnore;
+       pDEC_RPC_HOST_IFACE pSharedInterface = (pDEC_RPC_HOST_IFACE)This->shared_mem_vir;
+       MediaIPFW_Video_BufDesc *pMsgDesc = &pSharedInterface->StreamMsgBufferDesc;
+       u_int32 msgword;
+       u_int32 msgnum;
+
+       uSpace = rpc_MediaIPFW_Video_buffer_space_check(pMsgDesc, TRUE, 0, &uIgnore);
+       uSpace = (uSpace >> 2);
+       if (uSpace) {
+               /* get current msgword word */
+               msgword      = *((u_int32 *)(This->msg_mem_vir+pMsgDesc->uRdPtr - pMsgDesc->uStart));
+               /* Find the number of additional words */
+               msgnum  = ((msgword & 0x00ff0000) >> 16);
+
+               /*
+                * * Check the number of message words against
+                * * 1) a limit - some sort of maximum or at least
+                * * the size of the SW buffer the message is read into
+                * * 2) The space reported (where space is write ptr - read ptr in 32bit words)
+                * * It must be less than space (as opposed to <=) because
+                * * the message itself is not included in msgword
+                */
+               if (msgnum < VID_API_MESSAGE_LIMIT) {
+                       if (msgnum < uSpace)
+                               return API_MSG_AVAILABLE;
+                       else
+                               return API_MSG_INCOMPLETE;
+               } else
+                       return API_MSG_BUFFER_ERROR;
+       }
+       return API_MSG_UNAVAILABLE;
+}
+
+static void rpc_update_msg_buffer_ptr(MediaIPFW_Video_BufDesc *pMsgDesc)
+{
+       u_int32 uReadPtr;
+
+       uReadPtr = pMsgDesc->uRdPtr + 4;
+       if (uReadPtr >= pMsgDesc->uEnd)
+               uReadPtr = pMsgDesc->uStart;
+       pMsgDesc->uRdPtr = uReadPtr;
+}
+
+void rpc_receive_msg_buf(struct shared_addr *This, struct event_msg *msg)
+{
+       unsigned int i;
+       pDEC_RPC_HOST_IFACE pSharedInterface = (pDEC_RPC_HOST_IFACE)This->shared_mem_vir;
+       MediaIPFW_Video_BufDesc *pMsgDesc = &pSharedInterface->StreamMsgBufferDesc;
+       u_int32 msgword = *((u_int32 *)(This->msg_mem_vir+pMsgDesc->uRdPtr - pMsgDesc->uStart));
+
+       msg->idx = ((msgword & 0xff000000) >> 24);
+       msg->msgnum = ((msgword & 0x00ff0000) >> 16);
+       msg->msgid = ((msgword & 0x00003fff) >> 0);
+       rpc_update_msg_buffer_ptr(pMsgDesc);
+
+       for (i = 0; i < msg->msgnum; i++) {
+               msg->msgdata[i] = *((u_int32 *)(This->msg_mem_vir+pMsgDesc->uRdPtr - pMsgDesc->uStart));
+               rpc_update_msg_buffer_ptr(pMsgDesc);
+       }
+}
diff --git a/drivers/mxc/vpu-decoder-b0/vpu_rpc.h b/drivers/mxc/vpu-decoder-b0/vpu_rpc.h
new file mode 100644 (file)
index 0000000..b777e58
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __VPU_IPC_H
+#define __VPU_IPC_H
+
+#include "mediasys_types.h"
+
+#define CMD_SIZE 25600
+#define MSG_SIZE 25600
+#define CODEC_SIZE 0x1000
+#define JPEG_SIZE 0x1000
+#define SEQ_SIZE 0x1000
+#define GOP_SIZE 0x1000
+#define PIC_SIZE 0x1000
+#define QMETER_SIZE 0x1000
+#define DEBUG_SIZE 0x1000
+#define ENG_SIZE 0x1000
+#define LOCAL_MSG_NUM VID_API_MESSAGE_LIMIT
+
+struct shared_addr {
+       pDEC_RPC_HOST_IFACE pSharedInterface;
+       unsigned long long shared_mem_phy;
+       void *shared_mem_vir;
+       unsigned long long cmd_mem_phy;
+       void *cmd_mem_vir;
+       unsigned long long msg_mem_phy;
+       void *msg_mem_vir;
+       unsigned long long codec_mem_phy;
+       void *codec_mem_vir;
+       unsigned long long jpeg_mem_phy;
+       void *jpeg_mem_vir;
+       unsigned long long seq_mem_phy;
+       void *seq_mem_vir;
+       unsigned long long pic_mem_phy;
+       void *pic_mem_vir;
+       unsigned long long gop_mem_phy;
+       void *gop_mem_vir;
+       unsigned long long qmeter_mem_phy;
+       void *qmeter_mem_vir;
+};
+
+struct event_msg {
+       u_int32 idx;
+       u_int32 msgnum;
+       u_int32 msgid;
+       u_int32 msgdata[LOCAL_MSG_NUM];
+};
+
+void rpc_init_shared_memory(struct shared_addr *This,
+               unsigned long long base_phy_addr,
+               void *base_virt_addr,
+               u_int32 total_size);
+void rpc_set_system_cfg_value(void *Interface, u_int32 regs_base);
+void rpc_set_stream_cfg_value(void *Interface, u_int32 str_idx);
+void rpc_send_cmd_buf(struct shared_addr *This,
+               u_int32 idx,
+               u_int32 cmdid,
+               u_int32 cmdnum,
+               u_int32 *local_cmddata);
+void rpc_receive_msg_buf(struct shared_addr *This, struct event_msg *msg);
+
+#endif
diff --git a/drivers/mxc/vpu-encoder-b0/Kconfig b/drivers/mxc/vpu-encoder-b0/Kconfig
new file mode 100755 (executable)
index 0000000..40b1fce
--- /dev/null
@@ -0,0 +1,20 @@
+#
+# Codec configuration
+#
+
+menu "MXC VPU(Video Processing Unit) B0 ENCODER support"
+
+config MXC_VPU_ENCODER
+         tristate "Support for MXC VPU(Video Processing Unit) ENCODER"
+         default y
+       ---help---
+         The VPU codec device provides codec function for H.264 etc.
+
+config MXC_VPU_ENCODER_DEBUG
+       bool "MXC VPU ENCODER debugging"
+       depends on MXC_VPU_ENCODER != n
+       help
+         This is an option for the developers; most people should
+         say N here.  This enables MXC VPU driver debugging.
+
+endmenu
diff --git a/drivers/mxc/vpu-encoder-b0/Makefile b/drivers/mxc/vpu-encoder-b0/Makefile
new file mode 100644 (file)
index 0000000..b8a8fc1
--- /dev/null
@@ -0,0 +1,12 @@
+##
+## Makefile for the VPU and M0 driver
+##
+
+EXTRA_CFLAGS += $(DEFINES)
+
+obj-y = vpu-encoder.o
+vpu-encoder-objs = vpu_encoder_b0.o \
+       vpu_encoder_rpc.o
+
+clean:
+       rm -rf $(vpu-encoder-objs)
diff --git a/drivers/mxc/vpu-encoder-b0/mediasys_types.h b/drivers/mxc/vpu-encoder-b0/mediasys_types.h
new file mode 100644 (file)
index 0000000..caa05cb
--- /dev/null
@@ -0,0 +1,701 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MEDIASYS_TYPES_H_
+#define _MEDIASYS_TYPES_H_
+
+typedef unsigned int u_int32;
+typedef unsigned char u_int8;
+typedef unsigned long u_int64;
+typedef unsigned int BOOL;
+typedef int int32;
+#define FALSE 0
+#define TRUE 1
+#define VPU_MAX_NUM_STREAMS 4
+#define VID_API_NUM_STREAMS 4
+#define VID_API_MAX_BUF_PER_STR 3
+#define VID_API_MAX_NUM_MVC_VIEWS 4
+#define MEDIAIP_MAX_NUM_MALONES 2
+#define MEDIAIP_MAX_NUM_MALONE_IRQ_PINS 2
+#define MEDIAIP_MAX_NUM_WINDSORS 1
+#define MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS 2
+#define MEDIAIP_MAX_NUM_CMD_IRQ_PINS 2
+#define MEDIAIP_MAX_NUM_MSG_IRQ_PINS 1
+#define MEDIAIP_MAX_NUM_TIMER_IRQ_PINS 4
+#define MEDIAIP_MAX_NUM_TIMER_IRQ_SLOTS 4
+#define VID_API_COMMAND_LIMIT    64
+#define VID_API_MESSAGE_LIMIT    256
+
+#define API_CMD_AVAILABLE            0x0
+#define API_CMD_INCOMPLETE           0x1
+#define API_CMD_BUFFER_ERROR         0x2
+#define API_CMD_UNAVAILABLE          0x3
+#define API_MSG_AVAILABLE            0x0
+#define API_MSG_INCOMPLETE           0x1
+#define API_MSG_BUFFER_ERROR         0x2
+#define API_MSG_UNAVAILABLE          0x3
+#define MEDIAIP_ENC_USER_DATA_WORDS  16
+#define MEDIAIP_MAX_NUM_WINDSOR_SRC_FRAMES 0x6
+#define MEDIAIP_MAX_NUM_WINDSOR_REF_FRAMES 0x3
+
+typedef enum {
+       GTB_ENC_CMD_NOOP        = 0x0,
+       GTB_ENC_CMD_STREAM_START,
+       GTB_ENC_CMD_FRAME_ENCODE,
+       GTB_ENC_CMD_FRAME_SKIP,
+       GTB_ENC_CMD_STREAM_STOP,
+       GTB_ENC_CMD_PARAMETER_UPD,
+       GTB_ENC_CMD_TERMINATE,
+       GTB_ENC_CMD_SNAPSHOT,
+       GTB_ENC_CMD_ROLL_SNAPSHOT,
+       GTB_ENC_CMD_LOCK_SCHEDULER,
+       GTB_ENC_CMD_UNLOCK_SCHEDULER,
+       GTB_ENC_CMD_CONFIGURE_CODEC,
+       GTB_ENC_CMD_DEAD_MARK
+} GTB_ENC_CMD;
+
+typedef enum {
+       VID_API_ENC_EVENT_RESET_DONE = 0x1,
+       VID_API_ENC_EVENT_START_DONE,
+       VID_API_ENC_EVENT_STOP_DONE,
+       VID_API_ENC_EVENT_TERMINATE_DONE,
+       VID_API_ENC_EVENT_FRAME_INPUT_DONE,
+       VID_API_ENC_EVENT_FRAME_DONE,
+       VID_API_ENC_EVENT_FRAME_RELEASE,
+       VID_API_ENC_EVENT_PARA_UPD_DONE,
+       VID_API_ENC_EVENT_MEM_REQUEST
+
+} ENC_TB_API_ENC_EVENT;
+
+typedef enum {
+       MEDIAIP_ENC_PIC_TYPE_B_FRAME = 0,
+       MEDIAIP_ENC_PIC_TYPE_P_FRAME,
+       MEDIAIP_ENC_PIC_TYPE_I_FRAME,
+       MEDIAIP_ENC_PIC_TYPE_IDR_FRAME,
+       MEDIAIP_ENC_PIC_TYPE_BI_FRAME
+
+} MEDIAIP_ENC_PIC_TYPE, *pMEDIAIP_ENC_PIC_TYPE;
+
+typedef struct {
+       u_int32                   uMemPhysAddr;
+       u_int32                   uMemVirtAddr;
+       u_int32                   uMemSize;
+} MEDIAIP_ENC_MEM_RESOURCE, *pMEDIAIP_ENC_MEM_RESOURCE;
+
+typedef struct {
+       u_int32                    uEncFrmSize;
+       u_int32                    uEncFrmNum;
+       u_int32                    uRefFrmSize;
+       u_int32                    uRefFrmNum;
+       u_int32                    uActBufSize;
+       u_int32                    uAlignmentMask;
+} MEDIAIP_ENC_MEM_REQ_DATA, *pMEDIAIP_ENC_MEM_REQ_DATA;
+
+typedef struct {
+       MEDIAIP_ENC_MEM_RESOURCE  tEncFrameBuffers[MEDIAIP_MAX_NUM_WINDSOR_SRC_FRAMES];
+       MEDIAIP_ENC_MEM_RESOURCE  tRefFrameBuffers[MEDIAIP_MAX_NUM_WINDSOR_REF_FRAMES];
+       MEDIAIP_ENC_MEM_RESOURCE  tActFrameBufferArea;
+} MEDIAIP_ENC_MEM_POOL, *pMEDIAIP_ENC_MEM_POOL;
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_PIC_TYPE
+
+typedef struct {
+       u_int32              uFrameID;
+       u_int32              uPicEncodDone;
+       MEDIAIP_ENC_PIC_TYPE ePicType;
+       u_int32              uSkippedFrame;
+       u_int32              uErrorFlag;
+       u_int32              uPSNR;
+       u_int32              uFlushDone;
+       u_int32              uMBy;
+       u_int32              uMBx;
+       u_int32              uFrameSize;
+       u_int32              uFrameEncTtlCycles;
+       u_int32              uFrameEncTtlFrmCycles;
+       u_int32              uFrameEncTtlSlcCycles;
+       u_int32              uFrameEncTtlEncCycles;
+       u_int32              uFrameEncTtlHmeCycles;
+       u_int32              uFrameEncTtlDsaCycles;
+       u_int32              uFrameEncFwCycles;
+       u_int32              uFrameCrc;
+       u_int32              uNumInterrupts_1;
+       u_int32              uNumInterrupts_2;
+       u_int32              uH264POC;
+       u_int32              uRefInfo;
+       u_int32              uPicNum;
+       u_int32              uPicActivity;
+       u_int32              uSceneChange;
+       u_int32              uMBStats;
+       u_int32              uEncCacheCount0;
+       u_int32              uEncCacheCount1;
+       u_int32              uMtlWrStrbCnt;
+       u_int32              uMtlRdStrbCnt;
+       u_int32              uStrBuffWrPtr;
+       u_int32              uDiagnosticEvents;
+
+       u_int32              uProcIaccTotRdCnt;
+       u_int32              uProcDaccTotRdCnt;
+       u_int32              uProcDaccTotWrCnt;
+       u_int32              uProcDaccRegRdCnt;
+       u_int32              uProcDaccRegWrCnt;
+       u_int32              uProcDaccRngRdCnt;
+       u_int32              uProcDaccRngWrCnt;
+
+} MEDIAIP_ENC_PIC_INFO, *pMEDIAIP_ENC_PIC_INFO;
+
+typedef enum {
+       MEDIAIP_PLAYMODE_CONNECTIVITY = 0,
+       MEDIAIP_PLAYMODE_BROADCAST,
+       MEDIAIP_PLAYMODE_BROADCAST_DSS,
+       MEDIAIP_PLAYMODE_LAST = MEDIAIP_PLAYMODE_BROADCAST_DSS
+
+} MEDIA_IP_PLAYMODE;
+
+typedef struct {
+       u_int32 wptr;
+       u_int32 rptr;
+       u_int32 start;
+       u_int32 end;
+
+} BUFFER_DESCRIPTOR_TYPE, *pBUFFER_DESCRIPTOR_TYPE;
+
+typedef struct {
+       u_int32 uWrPtr;
+       u_int32 uRdPtr;
+       u_int32 uStart;
+       u_int32 uEnd;
+       u_int32 uLo;
+       u_int32 uHi;
+
+} MediaIPFW_Video_BufDesc;
+
+typedef struct {
+       u_int32 uCfgCookie;
+
+       u_int32 uNumMalones;
+       u_int32 uMaloneBaseAddress[MEDIAIP_MAX_NUM_MALONES];
+       u_int32 uHifOffset[MEDIAIP_MAX_NUM_MALONES];
+       u_int32 uMaloneIrqPin[MEDIAIP_MAX_NUM_MALONES][MEDIAIP_MAX_NUM_MALONE_IRQ_PINS];
+       u_int32 uMaloneIrqTarget[MEDIAIP_MAX_NUM_MALONES][MEDIAIP_MAX_NUM_MALONE_IRQ_PINS];
+
+       u_int32 uNumWindsors;
+       u_int32 uWindsorBaseAddress[MEDIAIP_MAX_NUM_WINDSORS];
+       u_int32 uWindsorIrqPin[MEDIAIP_MAX_NUM_WINDSORS][MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS];
+       u_int32 uWindsorIrqTarget[MEDIAIP_MAX_NUM_WINDSORS][MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS];
+
+       u_int32 uCmdIrqPin[MEDIAIP_MAX_NUM_CMD_IRQ_PINS];
+       u_int32 uCmdIrqTarget[MEDIAIP_MAX_NUM_CMD_IRQ_PINS];
+
+       u_int32 uMsgIrqPin[MEDIAIP_MAX_NUM_MSG_IRQ_PINS];
+       u_int32 uMsgIrqTarget[MEDIAIP_MAX_NUM_MSG_IRQ_PINS];
+
+       u_int32 uSysClkFreq;
+       u_int32 uNumTimers;
+       u_int32 uTimerBaseAddr;
+       u_int32 uTimerIrqPin[MEDIAIP_MAX_NUM_TIMER_IRQ_PINS];
+       u_int32 uTimerIrqTarget[MEDIAIP_MAX_NUM_TIMER_IRQ_PINS];
+       u_int32 uTimerSlots[MEDIAIP_MAX_NUM_TIMER_IRQ_SLOTS];
+
+       u_int32 uGICBaseAddr;
+       u_int32 uUartBaseAddr;
+
+       u_int32 uDPVBaseAddr;
+       u_int32 uDPVIrqPin;
+       u_int32 uDPVIrqTarget;
+
+       u_int32 uPixIfBaseAddr;
+
+       u_int32 pal_trace_level;
+       u_int32 pal_trace_destination;
+
+       u_int32 pal_trace_level1;
+       u_int32 pal_trace_destination1;
+
+       u_int32 uHeapBase;
+       u_int32 uHeapSize;
+
+       u_int32 uFSLCacheBaseAddr;
+
+} MEDIAIP_FW_SYSTEM_CONFIG, *pMEDIAIP_FW_SYSTEM_CONFIG;
+
+typedef struct {
+       u_int32   uFrameID;
+       u_int32   uLumaBase;
+       u_int32   uChromaBase;
+       u_int32   uParamIdx;
+
+} MEDIAIP_ENC_YUV_BUFFER_DESC, *pMEDIAIP_ENC_YUV_BUFFER_DESC;
+
+typedef struct {
+       u_int32 use_ame;
+
+       u_int32 cme_mvx_max;
+       u_int32 cme_mvy_max;
+       u_int32 ame_prefresh_y0;
+       u_int32 ame_prefresh_y1;
+       u_int32 fme_min_sad;
+       u_int32 cme_min_sad;
+
+       u_int32 fme_pred_int_weight;
+       u_int32 fme_pred_hp_weight;
+       u_int32 fme_pred_qp_weight;
+       u_int32 fme_cost_weight;
+       u_int32 fme_act_thold;
+       u_int32 fme_sad_thold;
+       u_int32 fme_zero_sad_thold;
+
+       u_int32 fme_lrg_mvx_lmt;
+       u_int32 fme_lrg_mvy_lmt;
+       u_int32 fme_force_mode;
+       u_int32 fme_force4mvcost;
+       u_int32 fme_force2mvcost;
+
+       u_int32 h264_inter_thrd;
+
+       u_int32 i16x16_mode_cost;
+       u_int32 i4x4_mode_lambda;
+       u_int32 i8x8_mode_lambda;
+
+       u_int32 inter_mod_mult;
+       u_int32 inter_sel_mult;
+       u_int32 inter_bid_cost;
+       u_int32 inter_bwd_cost;
+       u_int32 inter_4mv_cost;
+       int32   one_mv_i16_cost;
+       int32   one_mv_i4x4_cost;
+       int32   one_mv_i8x8_cost;
+       int32   two_mv_i16_cost;
+       int32   two_mv_i4x4_cost;
+       int32   two_mv_i8x8_cost;
+       int32   four_mv_i16_cost;
+       int32   four_mv_i4x4_cost;
+       int32   four_mv_i8x8_cost;
+
+       u_int32 intra_pred_enab;
+       u_int32 intra_chr_pred;
+       u_int32 intra16_pred;
+       u_int32 intra4x4_pred;
+       u_int32 intra8x8_pred;
+
+       u_int32 cb_base;
+       u_int32 cb_size;
+       u_int32 cb_head_room;
+
+       u_int32 mem_page_width;
+       u_int32 mem_page_height;
+       u_int32 mem_total_size;
+       u_int32 mem_chunk_phys_addr;
+       u_int32 mem_chunk_virt_addr;
+       u_int32 mem_chunk_size;
+       u_int32 mem_y_stride;
+       u_int32 mem_uv_stride;
+
+       u_int32 split_wr_enab;
+       u_int32 split_wr_req_size;
+       u_int32 split_rd_enab;
+       u_int32 split_rd_req_size;
+
+} MEDIAIP_ENC_CALIB_PARAMS, *pMEDIAIP_ENC_CALIB_PARAMS;
+
+typedef struct {
+       u_int32 ParamChange;
+
+       u_int32 start_frame;                // These variables are for debugging purposes only
+       u_int32 end_frame;
+
+       u_int32 userdata_enable;
+       u_int32 userdata_id[4];
+       u_int32 userdata_message[MEDIAIP_ENC_USER_DATA_WORDS];
+       u_int32 userdata_length;
+
+       u_int32 h264_profile_idc;
+       u_int32 h264_level_idc;
+       u_int32 h264_au_delimiter;          // Enable the use of Access Unit Delimiters
+       u_int32 h264_seq_end_code;          // Enable the use of Sequence End Codes
+       u_int32 h264_recovery_points;       // Enable the use of Recovery Points (must be with a fixed GOP structure)
+       u_int32 h264_vui_parameters;        // Enable the use of VUI parameters (for rate control purposes)
+       u_int32 h264_aspect_ratio_present;
+       u_int32 h264_aspect_ratio_sar_width;
+       u_int32 h264_aspect_ratio_sar_height;
+       u_int32 h264_overscan_present;
+       u_int32 h264_video_type_present;
+       u_int32 h264_video_format;
+       u_int32 h264_video_full_range;
+       u_int32 h264_video_colour_descriptor;
+       u_int32 h264_video_colour_primaries;
+       u_int32 h264_video_transfer_char;
+       u_int32 h264_video_matrix_coeff;
+       u_int32 h264_chroma_loc_info_present;
+       u_int32 h264_chroma_loc_type_top;
+       u_int32 h264_chroma_loc_type_bot;
+       u_int32 h264_timing_info_present;
+       u_int32 h264_buffering_period_present;
+       u_int32 h264_low_delay_hrd_flag;
+
+       u_int32 aspect_ratio;
+       u_int32 test_mode;                  // Automated firmware test mode
+       u_int32 dsa_test_mode;              // Automated test mode for the DSA.
+       u_int32 fme_test_mode;              // Automated test mode for the fme
+
+       u_int32 cbr_row_mode;               //0: FW mode; 1: HW mode
+       u_int32 windsor_mode;               //0: normal mode; 1: intra only mode; 2: intra+0MV mode
+       u_int32 encode_mode;                // H264, VC1, MPEG2, DIVX
+       u_int32 frame_width;                // display width
+       u_int32 frame_height;               // display height
+       u_int32 enc_frame_width;            // encoding width, should be 16-pix align
+       u_int32 enc_frame_height;           // encoding height, should be 16-pix aligned for progressive and 32-pix aligned for interlace
+       u_int32 frame_rate_num;
+       u_int32 frame_rate_den;
+
+       u_int32 vi_field_source;              // vi input source is frame or field
+       u_int32 vi_frame_width;
+       u_int32 vi_frame_height;
+       u_int32 crop_frame_width;
+       u_int32 crop_frame_height;
+       u_int32 crop_x_start_posn;
+       u_int32 crop_y_start_posn;
+       u_int32 mode422;
+       u_int32 mode_yuy2;
+       u_int32 dsa_luma_en;
+       u_int32 dsa_chroma_en;
+       u_int32 dsa_ext_hfilt_en;
+       u_int32 dsa_di_en;
+       u_int32 dsa_di_top_ref;
+       u_int32 dsa_vertf_disable;   // disable the vertical filter.
+       u_int32 dsa_disable_pwb;
+       u_int32 dsa_hor_phase;
+       u_int32 dsa_ver_phase;
+
+       u_int32 dsa_iac_enable;      // IAC / DSA cannot operate independently in FW so this variable controls
+       u_int32 iac_sc_threshold;
+       u_int32 iac_vm_threshold;
+       u_int32 iac_skip_mode;
+       u_int32 iac_grp_width;
+       u_int32 iac_grp_height;
+
+       u_int32 rate_control_mode;
+       u_int32 rate_control_resolution;
+       u_int32 buffer_size;
+       u_int32 buffer_level_init;
+       u_int32 buffer_I_bit_budget;
+
+       u_int32 top_field_first;
+
+       u_int32 intra_lum_qoffset;
+       u_int32 intra_chr_qoffset;
+       u_int32 inter_lum_qoffset;
+       u_int32 inter_chr_qoffset;
+       u_int32 use_def_scaling_mtx;
+
+       u_int32 inter_8x8_enab;
+       u_int32 inter_4x4_enab;
+
+       u_int32 fme_enable_qpel;
+       u_int32 fme_enable_hpel;
+       u_int32 fme_nozeromv;               // can force the FME not to do the (0,0) search.
+       u_int32 fme_predmv_en;
+       u_int32 fme_pred_2mv4mv;
+       u_int32 fme_smallsadthresh;
+
+       u_int32 ame_en_lmvc;
+       u_int32 ame_x_mult;
+       u_int32 cme_enable_4mv;             // Enable the use of 4MV partitioning
+       u_int32 cme_enable_1mv;
+       u_int32 hme_enable_16x8mv;
+       u_int32 hme_enable_8x16mv;
+       u_int32 cme_mv_weight;              // CME motion vector decisions are made by combining these
+       u_int32 cme_mv_cost;                // cost and weight variables
+       u_int32 ame_mult_mv;
+       u_int32 ame_shift_mv;
+
+       u_int32 hme_forceto1mv_en;
+       u_int32 hme_2mv_cost;               // the cost of choosing a 2MV mode over 1MV.
+       u_int32 hme_pred_mode;
+       u_int32 hme_sc_rnge;
+       u_int32 hme_sw_rnge;
+
+       // for windsor pes , add by fulin
+       u_int32 output_format;     // 0: output ES; 1: output PES
+       u_int32 timestamp_enab;    // 0: have timestamps in all frame; 1: have timestamps in I and P frame; 2: have timestamps only in I frame
+       u_int32 initial_PTS_enab;  // if enabled , use following value,else compute by fw
+       u_int32 initial_PTS;       // the initial value of PTS in the first frame (ms)
+
+} MEDIAIP_ENC_CONFIG_PARAMS, *pMEDIAIP_ENC_CONFIG_PARAMS;
+
+typedef struct {
+       u_int32 ParamChange;
+
+       u_int32 gop_length;
+
+       u_int32 rate_control_bitrate;
+       u_int32 rate_control_bitrate_min;
+       u_int32 rate_control_bitrate_max;
+       u_int32 rate_control_content_models;
+       u_int32 rate_control_iframe_maxsize; // Maximum size of I frame generated by BPM in comparison to ideal (/4)
+       u_int32 rate_control_qp_init;
+       u_int32 rate_control_islice_qp;
+       u_int32 rate_control_pslice_qp;
+       u_int32 rate_control_bslice_qp;
+
+       u_int32 adaptive_quantization;      // Enable the use of activity measures from VIPP in QP assignment
+       u_int32 aq_variance;
+       u_int32 cost_optimization;          // Enable picture/frame level adjustments of the cost parameters by FW.
+       u_int32 fdlp_mode;                  // Frequency-domain low-pass filter control, 0: off, 1-4: specific, 5: adaptive
+       u_int32 enable_isegbframes;         // Enable the use of B frames in the first segment of a GOP
+       u_int32 enable_adaptive_keyratio;   // Enable the use of an adaptive I to P/B ratio (aims to reduce distortion)
+       u_int32 keyratio_imin;              // Clamps applied to picture size ratios
+       u_int32 keyratio_imax;
+       u_int32 keyratio_pmin;
+       u_int32 keyratio_pmax;
+       u_int32 keyratio_bmin;
+       u_int32 keyratio_bmax;
+       int32   keyratio_istep;
+       int32   keyratio_pstep;
+       int32   keyratio_bstep;
+
+       u_int32 enable_paff;                // Enable Picture Adaptive Frame/Field
+       u_int32 enable_b_frame_ref;         // Enable B frame as references
+       u_int32 enable_adaptive_gop;        // Enable an adaptive GOP structure
+       u_int32 enable_closed_gop;          // Enable a closed GOP structure
+                                                                         // i.e. if enabled, the first consecutive B frames following
+                                                                         // an I frame in each GOP will be intra or backwards only coded
+                                                                         // and do not rely on previous reference pictures.
+       u_int32 open_gop_refresh_freq;      // Controls the insertion of closed GOP's (or IDR GOP's in H.264)
+       u_int32 enable_adaptive_sc;         // Enable adaptive scene change GOP structure (0:off, 1:adaptive, 2:IDR)
+       u_int32 enable_fade_detection;      // Enable fade detection and associated motion estimation restrictions
+       int32   fade_detection_threshold;   // Threshold at which the activity slope indicates a possible fading event
+       u_int32 enable_repeat_b;            // Enalbe the repeated B frame mode at CBR
+       u_int32 enable_low_delay_b;         // Use low delay-b frames with an IPPPP style GOP
+
+} MEDIAIP_ENC_STATIC_PARAMS, *pMEDIAIP_ENC_STATIC_PARAMS;
+
+typedef struct {
+       u_int32 ParamChange;
+
+       u_int32 rows_per_slice;
+
+       u_int32 mbaff_enable;                // Macroblock adaptive frame/field enable
+       u_int32 dbf_enable;                  // Enable the deblocking filter
+
+       u_int32 field_source;                // progressive/interlaced control
+       u_int32 gop_b_length;                // Number of B frames between anchor frames
+                                                                         //  (only to be changed at a GOP segment boundary)
+       u_int32 mb_group_size;               // Number of macroblocks normally assigned to a group
+                                                                         // (implications for performance, interrupts and rate control)
+
+       u_int32 cbr_rows_per_group;
+
+       u_int32 skip_enable;                 // Enable the use of skipped macroblocks
+
+       u_int32 pts_bits_0_to_31;            // TO BE REMOVED...
+       u_int32 pts_bit_32;
+
+       u_int32 rm_expsv_cff;
+       u_int32 const_ipred;
+       int32 chr_qp_offset;
+       u_int32 intra_mb_qp_offset;
+
+       u_int32 h264_cabac_init_method;
+       u_int32 h264_cabac_init_idc;
+       u_int32 h264_cabac_enable;                 // Main and stream
+
+       int32 alpha_c0_offset_div2;
+       int32 beta_offset_div2;
+
+       u_int32 intra_prefresh_y0; // for setting intra limits for prog refresh.
+       u_int32 intra_prefresh_y1;
+
+       u_int32 dbg_dump_rec_src;
+
+} MEDIAIP_ENC_DYN_PARAMS, *pMEDIAIP_ENC_DYN_PARAMS;
+
+typedef struct {
+       MEDIAIP_ENC_CALIB_PARAMS   Calib;
+       MEDIAIP_ENC_CONFIG_PARAMS  Config;
+       MEDIAIP_ENC_STATIC_PARAMS  Static;
+       MEDIAIP_ENC_DYN_PARAMS     Dynamic;
+} MEDIAIP_ENC_EXPERT_MODE_PARAM, *pMEDIAIP_ENC_EXPERT_MODE_PARAM;
+
+typedef enum {
+       MEDIAIP_ENC_FMT_H264 = 0,
+       MEDIAIP_ENC_FMT_VC1,
+       MEDIAIP_ENC_FMT_MPEG2,
+       MEDIAIP_ENC_FMT_MPEG4SP,
+       MEDIAIP_ENC_FMT_H263,
+       MEDIAIP_ENC_FMT_MPEG1,
+       MEDIAIP_ENC_FMT_SHORT_HEADER,
+       MEDIAIP_ENC_FMT_NULL
+
+} MEDIAIP_ENC_FMT;
+
+typedef enum {
+       MEDIAIP_ENC_PROF_MPEG2_SP = 0,
+       MEDIAIP_ENC_PROF_MPEG2_MP,
+       MEDIAIP_ENC_PROF_MPEG2_HP,
+       MEDIAIP_ENC_PROF_H264_BP,
+       MEDIAIP_ENC_PROF_H264_MP,
+       MEDIAIP_ENC_PROF_H264_HP,
+       MEDIAIP_ENC_PROF_MPEG4_SP,
+       MEDIAIP_ENC_PROF_MPEG4_ASP,
+       MEDIAIP_ENC_PROF_VC1_SP,
+       MEDIAIP_ENC_PROF_VC1_MP,
+       MEDIAIP_ENC_PROF_VC1_AP
+
+} MEDIAIP_ENC_PROFILE;
+
+typedef enum {
+       MEDIAIP_ENC_BITRATECONTROLMODE_VBR          = 0x00000001,
+       MEDIAIP_ENC_BITRATECONTROLMODE_CBR          = 0x00000002,
+       MEDIAIP_ENC_BITRATECONTROLMODE_CONSTANT_QP  = 0x00000004   /* Only in debug mode */
+
+} MEDIAIP_ENC_BITRATE_MODE, *pMEDIAIP_ENC_BITRATE_MODE;
+
+typedef struct {
+       MEDIAIP_ENC_FMT           eCodecMode;
+       MEDIAIP_ENC_PROFILE       eProfile;
+
+       MEDIAIP_ENC_MEM_RESOURCE  tEncMemDesc;
+
+       u_int32                   uFrameRate;
+       u_int32                   uSrcStride;
+       u_int32                   uSrcWidth;
+       u_int32                   uSrcHeight;
+       u_int32                   uSrcOffset_x;
+       u_int32                   uSrcOffset_y;
+       u_int32                   uSrcCropWidth;
+       u_int32                   uSrcCropHeight;
+       u_int32                   uOutWidth;
+       u_int32                   uOutHeight;
+       u_int32                   uIFrameInterval;
+       u_int32                   uGopBLength;
+       u_int32                   uLowLatencyMode;
+
+       MEDIAIP_ENC_BITRATE_MODE  eBitRateMode;
+       u_int32                   uTargetBitrate;
+       u_int32                   uMaxBitRate;
+       u_int32                   uMinBitRate;
+       u_int32                   uInitSliceQP;
+
+} MEDIAIP_ENC_PARAM, *pMEDIAIP_ENC_PARAM;
+
+typedef struct {
+       u_int32   uFrameID;
+       u_int32   uErrorFlag;   //Error type
+       u_int32   uMBy;
+       u_int32   uMBx;
+       u_int32   uReserved[12];
+
+} ENC_ENCODING_STATUS, *pENC_ENCODING_STATUS;
+
+typedef struct {
+       u_int32   uFrameID;
+       u_int32   uDsaCyle;
+       u_int32   uMBy;
+       u_int32   uMBx;
+       u_int32   uReserved[4];
+
+} ENC_DSA_STATUS_t, *pENC_DSA_STATUS_t;
+
+typedef struct {
+       u_int32                                  pEncYUVBufferDesc;
+       u_int32                                  pEncStreamBufferDesc;
+       u_int32                                  pEncExpertModeParam;
+       u_int32                                  pEncParam;
+       u_int32                                  pEncMemPool;
+       /* Status information for master to read */
+       u_int32                                  pEncEncodingStatus;
+       u_int32                                  pEncDSAStatus;
+} MEDIA_ENC_API_CONTROL_INTERFACE, *pMEDIA_ENC_API_CONTROL_INTERFACE;
+
+typedef struct {
+       u_int32                                FwExecBaseAddr;
+       u_int32                                FwExecAreaSize;
+       BUFFER_DESCRIPTOR_TYPE                 StreamCmdBufferDesc;
+       BUFFER_DESCRIPTOR_TYPE                 StreamMsgBufferDesc;
+       u_int32                                StreamCmdIntEnable[VID_API_NUM_STREAMS];
+       u_int32                                FWVersion;
+       u_int32                                uMVDFWOffset;
+       u_int32                                uMaxEncoderStreams;
+       u_int32                                pEncCtrlInterface[VID_API_NUM_STREAMS];
+       MEDIAIP_FW_SYSTEM_CONFIG               sSystemCfg;
+       u_int32                                uApiVersion;
+} ENC_RPC_HOST_IFACE, *pENC_RPC_HOST_IFACE;
+
+#define SCB_XREG_SLV_BASE                               0x00000000
+#define SCB_SCB_BLK_CTRL                                0x00070000
+#define SCB_BLK_CTRL_XMEM_RESET_SET                     0x00000090
+#define SCB_BLK_CTRL_CACHE_RESET_SET                    0x000000A0
+#define SCB_BLK_CTRL_CACHE_RESET_CLR                    0x000000A4
+#define SCB_BLK_CTRL_SCB_CLK_ENABLE_SET                 0x00000100
+
+#define XMEM_CONTROL                                    0x00041000
+
+#define DEC_MFD_XREG_SLV_BASE                           0x00180000
+
+#define MFD_HIF                                         0x0001C000
+#define MFD_HIF_MSD_REG_INTERRUPT_STATUS                0x00000018
+#define MFD_SIF                                         0x0001D000
+#define MFD_SIF_CTRL_STATUS                             0x000000F0
+#define MFD_SIF_INTR_STATUS                             0x000000F4
+#define MFD_MCX                                         0x00020800
+#define MFD_MCX_OFF                                     0x00000020
+
+#define MFD_BLK_CTRL                                    0x00030000
+#define MFD_BLK_CTRL_MFD_SYS_RESET_SET                  0x00000000
+#define MFD_BLK_CTRL_MFD_SYS_RESET_CLR                  0x00000004
+#define MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_SET           0x00000100
+#define MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_CLR           0x00000104
+
+#endif
diff --git a/drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.c b/drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.c
new file mode 100644 (file)
index 0000000..7ff1aed
--- /dev/null
@@ -0,0 +1,2076 @@
+/*
+ * Copyright 2018 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file vpu_encoder_b0.c
+ *
+ * copyright here may be changed later
+ *
+ *
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/file.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/platform_data/dma-imx.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/pm_runtime.h>
+#include <linux/mx8_mu.h>
+#include <linux/uaccess.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-dma-sg.h>
+
+#include "vpu_encoder_b0.h"
+
+unsigned int vpu_dbg_level_encoder = 0;
+#ifdef DUMP_DATA
+#define DATA_NUM 10
+#endif
+/*
+ * v4l2 ioctl() operation
+ *
+ */
+static struct vpu_v4l2_fmt  formats_compressed_enc[] = {
+       {
+               .name       = "H264 Encoded Stream",
+               .fourcc     = V4L2_PIX_FMT_H264,
+               .num_planes = 1,
+               .venc_std   = VPU_VIDEO_AVC,
+       },
+       {
+               .name       = "VC1 Encoded Stream",
+               .fourcc     = V4L2_PIX_FMT_VC1_ANNEX_G,
+               .num_planes = 1,
+               .venc_std   = VPU_VIDEO_VC1,
+       },
+       {
+               .name       = "VC1 RCV Encoded Stream",
+               .fourcc     = V4L2_PIX_FMT_VC1_ANNEX_L,
+               .num_planes = 1,
+               .venc_std   = VPU_VIDEO_VC1,
+       },
+       {
+               .name       = "MPEG2 Encoded Stream",
+               .fourcc     = V4L2_PIX_FMT_MPEG2,
+               .num_planes = 1,
+               .venc_std   = VPU_VIDEO_MPEG2,
+       },
+
+       {
+               .name       = "AVS Encoded Stream",
+               .fourcc     = VPU_PIX_FMT_AVS,
+               .num_planes = 1,
+               .venc_std   = VPU_VIDEO_AVS,
+       },
+       {
+               .name       = "MPEG4 ASP Encoded Stream",
+               .fourcc     = VPU_PIX_FMT_ASP,
+               .num_planes = 1,
+               .venc_std   = VPU_VIDEO_ASP,
+       },
+       {
+               .name       = "JPEG stills",
+               .fourcc     = V4L2_PIX_FMT_JPEG,
+               .num_planes = 1,
+               .venc_std   = VPU_VIDEO_JPEG,
+       },
+       {
+               .name       = "RV8 Encoded Stream",
+               .fourcc     = VPU_PIX_FMT_RV8,
+               .num_planes = 1,
+               .venc_std   = VPU_VIDEO_RV8,
+       },
+       {
+               .name       = "RV9 Encoded Stream",
+               .fourcc     = VPU_PIX_FMT_RV9,
+               .num_planes = 1,
+               .venc_std   = VPU_VIDEO_RV9,
+       },
+       {
+               .name       = "VP6 Encoded Stream",
+               .fourcc     = VPU_PIX_FMT_VP6,
+               .num_planes = 1,
+               .venc_std   = VPU_VIDEO_VP6,
+       },
+       {
+               .name       = "VP6 SPK Encoded Stream",
+               .fourcc     = VPU_PIX_FMT_SPK,
+               .num_planes = 1,
+               .venc_std   = VPU_VIDEO_SPK,
+       },
+       {
+               .name       = "VP8 Encoded Stream",
+               .fourcc     = V4L2_PIX_FMT_VP8,
+               .num_planes = 1,
+               .venc_std   = VPU_VIDEO_VP8,
+       },
+       {
+               .name       = "H264/MVC Encoded Stream",
+               .fourcc     = V4L2_PIX_FMT_H264_MVC,
+               .num_planes = 1,
+               .venc_std   = VPU_VIDEO_AVC_MVC,
+       },
+       {
+               .name       = "H265 HEVC Encoded Stream",
+               .fourcc     = VPU_PIX_FMT_HEVC,
+               .num_planes = 1,
+               .venc_std   = VPU_VIDEO_HEVC,
+       },
+       {
+               .name       = "VP9 Encoded Stream",
+               .fourcc     = VPU_PIX_FMT_VP9,
+               .num_planes = 1,
+               .venc_std   = VPU_VIDEO_VP9,
+       },
+       {
+               .name       = "Logo",
+               .fourcc     = VPU_PIX_FMT_LOGO,
+               .num_planes = 1,
+               .venc_std   = VPU_VIDEO_UNDEFINED,
+       },
+};
+
+static struct vpu_v4l2_fmt  formats_yuv_enc[] = {
+       {
+               .name       = "4:2:0 2 Planes Y/CbCr",
+               .fourcc     = V4L2_PIX_FMT_NV12,
+               .num_planes     = 2,
+               .venc_std   = VPU_PF_YUV420_SEMIPLANAR,
+       },
+};
+
+static void MU_sendMesgToFW(void __iomem *base, MSG_Type type, uint32_t value)
+{
+       MU_SendMessage(base, 1, value);
+       MU_SendMessage(base, 0, type);
+}
+
+static int v4l2_ioctl_querycap(struct file *file,
+               void *fh,
+               struct v4l2_capability *cap
+               )
+{
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+       strncpy(cap->driver, "vpu encoder", sizeof(cap->driver) - 1);
+       strlcpy(cap->card, "vpu encoder", sizeof(cap->card));
+       strlcpy(cap->bus_info, "platform:", sizeof(cap->bus_info));
+       cap->version = KERNEL_VERSION(0, 0, 1);
+       cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+       return 0;
+}
+
+static int v4l2_ioctl_enum_fmt_vid_cap_mplane(struct file *file,
+               void *fh,
+               struct v4l2_fmtdesc *f
+               )
+{
+       struct vpu_v4l2_fmt *fmt;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+       if (f->index >= VPU_MAX_FORMATS)
+               return -EINVAL;
+
+       fmt = &formats_yuv_enc[f->index];
+       strlcpy(f->description, fmt->name, sizeof(f->description));
+       f->pixelformat = fmt->fourcc;
+       return 0;
+}
+static int v4l2_ioctl_enum_fmt_vid_out_mplane(struct file *file,
+               void *fh,
+               struct v4l2_fmtdesc *f
+               )
+{
+       struct vpu_v4l2_fmt *fmt;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (f->index >= VPU_MAX_FORMATS)
+               return -EINVAL;
+
+       fmt = &formats_compressed_enc[f->index];
+       strlcpy(f->description, fmt->name, sizeof(f->description));
+       f->pixelformat = fmt->fourcc;
+       f->flags |= V4L2_FMT_FLAG_COMPRESSED;
+       return 0;
+}
+
+static int v4l2_ioctl_g_fmt(struct file *file,
+               void *fh,
+               struct v4l2_format *f
+               )
+{
+       struct vpu_ctx *ctx =           v4l2_fh_to_ctx(fh);
+       struct v4l2_pix_format_mplane   *pix_mp = &f->fmt.pix_mp;
+       unsigned int i;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               pix_mp->pixelformat = V4L2_PIX_FMT_NV12;
+               pix_mp->width = ctx->q_data[V4L2_SRC].width;
+               pix_mp->height = ctx->q_data[V4L2_SRC].height;
+               pix_mp->field = V4L2_FIELD_ANY;
+               pix_mp->num_planes = 2;
+               pix_mp->colorspace = V4L2_COLORSPACE_REC709;
+
+               for (i = 0; i < pix_mp->num_planes; i++)
+                       pix_mp->plane_fmt[i].sizeimage = ctx->q_data[V4L2_SRC].sizeimage[i];
+       } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               pix_mp->width = 0;
+               pix_mp->height = 0;
+               pix_mp->field = V4L2_FIELD_ANY;
+               pix_mp->plane_fmt[0].bytesperline = 0;
+               pix_mp->plane_fmt[0].sizeimage = ctx->q_data[V4L2_DST].sizeimage[0];
+               pix_mp->pixelformat = V4L2_PIX_FMT_H264;
+               pix_mp->num_planes = 1;
+       } else
+               return -EINVAL;
+       return 0;
+}
+
+static void get_param_from_v4l2(pMEDIAIP_ENC_PARAM pEncParam,
+               struct v4l2_pix_format_mplane *pix_mp,
+               struct vpu_ctx *ctx
+               )
+{
+       //get the param and update gpParameters
+       pEncParam->eCodecMode           = MEDIAIP_ENC_FMT_H264;
+
+       pEncParam->tEncMemDesc.uMemPhysAddr = ctx->encoder_mem.phy_addr;
+       pEncParam->tEncMemDesc.uMemVirtAddr = ctx->encoder_mem.phy_addr;
+       pEncParam->tEncMemDesc.uMemSize     = ctx->encoder_mem.size;
+
+       pEncParam->uFrameRate           = 30;
+       pEncParam->uSrcStride           = pix_mp->width;
+       pEncParam->uSrcWidth            = pix_mp->width;
+       pEncParam->uSrcHeight           = pix_mp->height;
+       pEncParam->uSrcOffset_x         = 0;
+       pEncParam->uSrcOffset_y         = 0;
+       pEncParam->uSrcCropWidth        = pix_mp->width;
+       pEncParam->uSrcCropHeight       = pix_mp->height;
+       pEncParam->uOutWidth            = pix_mp->width;
+       pEncParam->uOutHeight           = pix_mp->height;
+       pEncParam->uLowLatencyMode      = 0;
+
+       pEncParam->uIFrameInterval      = 10;
+
+       vpu_dbg(LVL_INFO, "eCodecMode(%d) eProfile(%d) uSrcStride(%d) uSrcWidth(%d) uSrcHeight(%d) uSrcOffset_x(%d) uSrcOffset_y(%d) uSrcCropWidth(%d) uSrcCropHeight(%d) uOutWidth(%d) uOutHeight(%d) uGopBLength(%d) uLowLatencyMode(%d) uInitSliceQP(%d) uIFrameInterval(%d) eBitRateMode(%d) uTargetBitrate(%d) uMaxBitRate(%d) uMinBitRate(%d) uFrameRate(%d)\n",
+                       pEncParam->eCodecMode, pEncParam->eProfile, pEncParam->uSrcStride, pEncParam->uSrcWidth,
+                       pEncParam->uSrcHeight, pEncParam->uSrcOffset_x, pEncParam->uSrcOffset_y, pEncParam->uSrcCropWidth, pEncParam->uSrcCropHeight,
+                       pEncParam->uOutWidth, pEncParam->uOutHeight, pEncParam->uGopBLength, pEncParam->uLowLatencyMode, pEncParam->uInitSliceQP, pEncParam->uIFrameInterval, pEncParam->eBitRateMode, pEncParam->uTargetBitrate, pEncParam->uMaxBitRate, pEncParam->uMinBitRate, pEncParam->uFrameRate);
+}
+
+static void *phy_to_virt(u_int32 src, unsigned long long offset)
+{
+       void *result;
+
+       result = (void *)(src + offset);
+       return result;
+}
+
+static int v4l2_ioctl_s_fmt(struct file *file,
+               void *fh,
+               struct v4l2_format *f
+               )
+{
+       struct vpu_ctx                  *ctx = v4l2_fh_to_ctx(fh);
+       int                             ret = 0;
+       struct v4l2_pix_format_mplane   *pix_mp = &f->fmt.pix_mp;
+       struct queue_data               *q_data;
+       pENC_RPC_HOST_IFACE pSharedInterface = ctx->dev->shared_mem.pSharedInterface;
+       pMEDIA_ENC_API_CONTROL_INTERFACE pEncCtrlInterface;
+       pMEDIAIP_ENC_PARAM  pEncParam;
+       pMEDIAIP_ENC_EXPERT_MODE_PARAM pEncExpertModeParam;
+
+       pEncCtrlInterface = (pMEDIA_ENC_API_CONTROL_INTERFACE)phy_to_virt(pSharedInterface->pEncCtrlInterface[ctx->str_index],
+                       ctx->dev->shared_mem.base_offset);
+       pEncParam = (pMEDIAIP_ENC_PARAM)phy_to_virt(pEncCtrlInterface->pEncParam,
+                       ctx->dev->shared_mem.base_offset);
+       pEncExpertModeParam = (pMEDIAIP_ENC_EXPERT_MODE_PARAM)phy_to_virt(pEncCtrlInterface->pEncExpertModeParam,
+                       ctx->dev->shared_mem.base_offset);
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               q_data = &ctx->q_data[V4L2_SRC];
+
+               get_param_from_v4l2(pEncParam, pix_mp, ctx);
+               q_data->fourcc = pix_mp->pixelformat;
+               q_data->width = pix_mp->width;
+               q_data->height = pix_mp->height;
+               q_data->rect.left = 0;
+               q_data->rect.top = 0;
+               q_data->rect.width = pix_mp->width;
+               q_data->rect.height = pix_mp->height;
+               q_data->sizeimage[0] = pix_mp->width * pix_mp->height;
+               q_data->sizeimage[1] = pix_mp->width * pix_mp->height / 2;
+       } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               q_data = &ctx->q_data[V4L2_DST];
+               q_data->fourcc = pix_mp->pixelformat;
+               q_data->sizeimage[0] = pix_mp->plane_fmt[0].sizeimage;
+       } else
+               ret = -EINVAL;
+
+       return ret;
+}
+
+static int v4l2_ioctl_expbuf(struct file *file,
+               void *fh,
+               struct v4l2_exportbuffer *buf
+               )
+{
+       struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+       struct queue_data *q_data;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               q_data = &ctx->q_data[V4L2_SRC];
+       else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               q_data = &ctx->q_data[V4L2_DST];
+       else
+               return -EINVAL;
+
+       return (vb2_expbuf(&q_data->vb2_q,
+                               buf
+                               ));
+}
+
+static int v4l2_ioctl_subscribe_event(struct v4l2_fh *fh,
+               const struct v4l2_event_subscription *sub
+               )
+{
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       switch (sub->type) {
+       case V4L2_EVENT_EOS:
+               return v4l2_event_subscribe(fh, sub, 0, NULL);
+       case V4L2_EVENT_SOURCE_CHANGE:
+               return v4l2_src_change_event_subscribe(fh, sub);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int v4l2_ioctl_reqbufs(struct file *file,
+               void *fh,
+               struct v4l2_requestbuffers *reqbuf
+               )
+{
+       struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+       struct queue_data *q_data;
+       int ret;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               q_data = &ctx->q_data[V4L2_SRC];
+       else if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               q_data = &ctx->q_data[V4L2_DST];
+       else
+               return -EINVAL;
+
+       ret = vb2_reqbufs(&q_data->vb2_q, reqbuf);
+
+       vpu_dbg(LVL_INFO, "%s() c_port_req_buf(%d)\n",
+                       __func__, ret);
+
+       return ret;
+}
+
+static int v4l2_ioctl_querybuf(struct file *file,
+               void *fh,
+               struct v4l2_buffer *buf
+               )
+{
+       struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+       struct queue_data *q_data;
+       unsigned int i;
+       int ret;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               q_data = &ctx->q_data[V4L2_SRC];
+       else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               q_data = &ctx->q_data[V4L2_DST];
+       else
+               return -EINVAL;
+
+       ret = vb2_querybuf(&q_data->vb2_q, buf);
+       if (!ret) {
+               if (buf->memory == V4L2_MEMORY_MMAP) {
+                       if (V4L2_TYPE_IS_MULTIPLANAR(buf->type)) {
+                               for (i = 0; i < buf->length; i++)
+                                       buf->m.planes[i].m.mem_offset |= (q_data->type << MMAP_BUF_TYPE_SHIFT);
+                       } else
+                               buf->m.offset |= (q_data->type << MMAP_BUF_TYPE_SHIFT);
+               }
+       }
+
+       return ret;
+}
+
+static int v4l2_ioctl_qbuf(struct file *file,
+               void *fh,
+               struct v4l2_buffer *buf
+               )
+{
+       struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+       struct queue_data *q_data;
+       int ret;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               q_data = &ctx->q_data[V4L2_SRC];
+       else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               q_data = &ctx->q_data[V4L2_DST];
+       else
+               return -EINVAL;
+
+       ret = vb2_qbuf(&q_data->vb2_q, buf);
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               wake_up_interruptible(&ctx->buffer_wq_output);
+       else
+               wake_up_interruptible(&ctx->buffer_wq_input);
+
+       return ret;
+}
+
+static int v4l2_ioctl_dqbuf(struct file *file,
+               void *fh,
+               struct v4l2_buffer *buf
+               )
+{
+       struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+       struct queue_data *q_data;
+       int ret;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               q_data = &ctx->q_data[V4L2_SRC];
+       else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               q_data = &ctx->q_data[V4L2_DST];
+       else
+               return -EINVAL;
+
+       ret = vb2_dqbuf(&q_data->vb2_q, buf, file->f_flags & O_NONBLOCK);
+
+       return ret;
+}
+
+static bool format_is_support(struct vpu_v4l2_fmt *format_table,
+               unsigned int table_size,
+               struct v4l2_format *f)
+{
+       unsigned int i;
+
+       for (i = 0; i < table_size; i++) {
+               if (format_table[i].fourcc == f->fmt.pix_mp.pixelformat)
+                       return true;
+       }
+       return false;
+}
+
+static int v4l2_ioctl_try_fmt(struct file *file,
+               void *fh,
+               struct v4l2_format *f
+               )
+{
+       unsigned int table_size;
+
+       if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               table_size = ARRAY_SIZE(formats_compressed_enc);
+               if (!format_is_support(formats_compressed_enc, table_size, f))
+                       return -EINVAL;
+       } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               table_size = ARRAY_SIZE(formats_yuv_enc);
+               if (!format_is_support(formats_yuv_enc, table_size, f))
+                       return -EINVAL;
+       } else
+               return -EINVAL;
+
+       return 0;
+}
+
+static int v4l2_ioctl_g_crop(struct file *file,
+               void *fh,
+               struct v4l2_crop *cr
+               )
+{
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+       cr->c.left = 0;
+       cr->c.top = 0;
+       cr->c.width = 0;
+       cr->c.height = 0;
+
+       return 0;
+}
+
+static int v4l2_ioctl_encoder_cmd(struct file *file,
+               void *fh,
+               struct v4l2_encoder_cmd *cmd
+               )
+{
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       switch (cmd->cmd) {
+       case V4L2_ENC_CMD_START:
+               break;
+       case V4L2_ENC_CMD_STOP:
+               break;
+       case V4L2_ENC_CMD_PAUSE:
+               break;
+       case V4L2_ENC_CMD_RESUME:
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int v4l2_ioctl_streamon(struct file *file,
+               void *fh,
+               enum v4l2_buf_type i
+               )
+{
+       struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+       struct queue_data *q_data;
+       int ret;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (i == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               q_data = &ctx->q_data[V4L2_SRC];
+       else if (i == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               q_data = &ctx->q_data[V4L2_DST];
+       else
+               return -EINVAL;
+       ret = vb2_streamon(&q_data->vb2_q,
+                       i);
+       return ret;
+}
+
+static int v4l2_ioctl_streamoff(struct file *file,
+               void *fh,
+               enum v4l2_buf_type i
+               )
+{
+       struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+       struct queue_data *q_data;
+       int ret;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (i == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               q_data = &ctx->q_data[V4L2_SRC];
+       else if (i == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               q_data = &ctx->q_data[V4L2_DST];
+       else
+               return -EINVAL;
+       ret = vb2_streamoff(&q_data->vb2_q,
+                       i);
+       return ret;
+}
+
+const struct v4l2_ioctl_ops v4l2_encoder_ioctl_ops = {
+       .vidioc_querycap                = v4l2_ioctl_querycap,
+       .vidioc_enum_fmt_vid_cap_mplane = v4l2_ioctl_enum_fmt_vid_cap_mplane,
+       .vidioc_enum_fmt_vid_out_mplane = v4l2_ioctl_enum_fmt_vid_out_mplane,
+       .vidioc_g_fmt_vid_cap_mplane    = v4l2_ioctl_g_fmt,
+       .vidioc_g_fmt_vid_out_mplane    = v4l2_ioctl_g_fmt,
+       .vidioc_try_fmt_vid_cap_mplane  = v4l2_ioctl_try_fmt,
+       .vidioc_try_fmt_vid_out_mplane  = v4l2_ioctl_try_fmt,
+       .vidioc_s_fmt_vid_cap_mplane    = v4l2_ioctl_s_fmt,
+       .vidioc_s_fmt_vid_out_mplane    = v4l2_ioctl_s_fmt,
+       .vidioc_expbuf                  = v4l2_ioctl_expbuf,
+       .vidioc_g_crop                  = v4l2_ioctl_g_crop,
+       .vidioc_encoder_cmd             = v4l2_ioctl_encoder_cmd,
+       .vidioc_subscribe_event         = v4l2_ioctl_subscribe_event,
+       .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
+       .vidioc_reqbufs                 = v4l2_ioctl_reqbufs,
+       .vidioc_querybuf                = v4l2_ioctl_querybuf,
+       .vidioc_qbuf                    = v4l2_ioctl_qbuf,
+       .vidioc_dqbuf                   = v4l2_ioctl_dqbuf,
+       .vidioc_streamon                = v4l2_ioctl_streamon,
+       .vidioc_streamoff               = v4l2_ioctl_streamoff,
+};
+
+static int v4l2_enc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+       pENC_RPC_HOST_IFACE pSharedInterface = ctx->dev->shared_mem.pSharedInterface;
+       pMEDIA_ENC_API_CONTROL_INTERFACE pEncCtrlInterface;
+       pMEDIAIP_ENC_PARAM  pEncParam;
+       pMEDIAIP_ENC_EXPERT_MODE_PARAM pEncExpertModeParam;
+
+       pEncCtrlInterface = (pMEDIA_ENC_API_CONTROL_INTERFACE)phy_to_virt(pSharedInterface->pEncCtrlInterface[ctx->str_index],
+                       ctx->dev->shared_mem.base_offset);
+       pEncParam = (pMEDIAIP_ENC_PARAM)phy_to_virt(pEncCtrlInterface->pEncParam,
+                       ctx->dev->shared_mem.base_offset);
+       pEncExpertModeParam = (pMEDIAIP_ENC_EXPERT_MODE_PARAM)phy_to_virt(pEncCtrlInterface->pEncExpertModeParam,
+                       ctx->dev->shared_mem.base_offset);
+
+       vpu_dbg(LVL_INFO, "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val);
+
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: {
+               if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
+                       pEncParam->eBitRateMode = MEDIAIP_ENC_BITRATECONTROLMODE_CONSTANT_QP;
+
+                       // Not used for CQ mode - set zero
+                       pEncParam->uTargetBitrate       = 0;
+                       pEncParam->uMaxBitRate          = 0;
+                       pEncParam->uMinBitRate          = 0;
+               } else if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) {
+                       pEncParam->eBitRateMode = MEDIAIP_ENC_BITRATECONTROLMODE_CBR;
+                       if (!pEncParam->uTargetBitrate) {
+                               // Setup some default values if not set, these should really be
+                               // resolution specific
+                               pEncParam->uTargetBitrate = 200;
+                               pEncParam->uMaxBitRate    = 4000;
+                               pEncParam->uMinBitRate    = 50;
+                       }
+               } else
+                       // Only CQ and CBR supported at present, force CQ mode
+                       pEncParam->eBitRateMode = MEDIAIP_ENC_BITRATECONTROLMODE_CONSTANT_QP;
+       }
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+               if (V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE == ctrl->val)
+               pEncParam->eProfile = MEDIAIP_ENC_PROF_H264_BP;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               pEncParam->uTargetBitrate = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               pEncParam->uGopBLength = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+               pEncParam->uInitSliceQP = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+               pEncParam->uInitSliceQP = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+               pEncParam->uInitSliceQP = ctrl->val;
+               break;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops   vpu_enc_ctrl_ops = {
+       .s_ctrl             = v4l2_enc_s_ctrl,
+};
+
+static void vpu_encoder_ctrls(struct vpu_ctx *ctx)
+{
+       v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &vpu_enc_ctrl_ops,
+                       V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+                       V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0x0,
+                       V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
+       v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &vpu_enc_ctrl_ops,
+                       V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+                       V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH, 0x0,
+                       V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE
+                       );
+       v4l2_ctrl_new_std(&ctx->ctrl_handler, &vpu_enc_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1, 100);
+       v4l2_ctrl_new_std(&ctx->ctrl_handler, &vpu_enc_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 60, 1, 16);
+       v4l2_ctrl_new_std(&ctx->ctrl_handler, &vpu_enc_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 0, 51, 1, 25);
+       v4l2_ctrl_new_std(&ctx->ctrl_handler, &vpu_enc_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 0, 51, 1, 25);
+       v4l2_ctrl_new_std(&ctx->ctrl_handler, &vpu_enc_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, 0, 51, 1, 25);
+}
+
+static int ctrls_setup_encoder(struct vpu_ctx *ctx)
+{
+       v4l2_ctrl_handler_init(&ctx->ctrl_handler, 2);
+       vpu_encoder_ctrls(ctx);
+       if (ctx->ctrl_handler.error) {
+               vpu_dbg(LVL_ERR,
+                       "control initialization error (%d)",
+                       ctx->ctrl_handler.error);
+               return -EINVAL;
+       } else
+               ctx->ctrl_inited = true;
+
+       return v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+}
+
+static void ctrls_delete_encoder(struct vpu_ctx *This)
+{
+       int i;
+
+       if (This->ctrl_inited) {
+               v4l2_ctrl_handler_free(&This->ctrl_handler);
+               This->ctrl_inited = false;
+       }
+       for (i = 0; i < 2; i++)
+               This->ctrls[i] = NULL;
+}
+
+static void v4l2_vpu_send_cmd(struct vpu_ctx *ctx, uint32_t idx, uint32_t cmdid, uint32_t cmdnum, uint32_t *local_cmddata)
+{
+       rpc_send_cmd_buf_encoder(&ctx->dev->shared_mem, idx, cmdid, cmdnum, local_cmddata);
+       MU_SendMessage(ctx->dev->mu_base_virtaddr, 0, COMMAND);
+}
+
+/**the function is used for to convert yuv420p to yuv420sp
+ * yyyy yyyy
+ * uu vv
+ * ->
+ * yyyy yyyy
+ * uv uv
+ **/
+static void convert_feed_stream(struct queue_data *This, struct vb2_buffer *vb)
+{
+       u_int8 *y_start;
+       u_int8 *u_start;
+       u_int8 *v_start;
+       u_int8 *uv_temp;
+       u_int32 i, j;
+       u_int32 height = This->height;
+       u_int32 width = This->width;
+       u_int32 y_size, uv_size;
+       y_size = height * width;
+       uv_size = height * width/2;
+       uv_temp = kmalloc(sizeof(u_int8)*uv_size, GFP_KERNEL);
+
+       y_start = (u_int8 *)vb2_plane_vaddr(vb, 0);
+       u_start = y_start + y_size;
+       v_start = y_start + y_size*5/4;
+       for (i = 0, j = 0; j < uv_size; j += 2, i++) {
+               uv_temp[j] = u_start[i];
+               uv_temp[j+1] = v_start[i];
+       }
+       memcpy(u_start, uv_temp, sizeof(u_int8)*uv_size);
+
+       kfree(uv_temp);
+}
+
+static void v4l2_transfer_buffer_to_firmware(struct queue_data *This, struct vb2_buffer *vb)
+{
+       struct vpu_ctx *ctx = container_of(This, struct vpu_ctx, q_data[V4L2_SRC]);
+#ifdef DUMP_DATA
+       char *read_data;
+       u_int32 read_idx;
+#endif
+       pBUFFER_DESCRIPTOR_TYPE pEncStrBuffDesc;
+       pMEDIAIP_ENC_EXPERT_MODE_PARAM pEncExpertModeParam;
+       pENC_RPC_HOST_IFACE pSharedInterface = ctx->dev->shared_mem.pSharedInterface;
+       pMEDIA_ENC_API_CONTROL_INTERFACE pEncCtrlInterface;
+       u_int32 uStrIdx = 0;
+
+       vpu_dbg(LVL_INFO, "ENC_RPC_HOST_IFACE(%ld)MEDIA_ENC_API_CONTROL_INTERFACE(%ld) EncYUVBufferDesc(%ld) expertParam(%ld) encparam(%ld) MEDIAIP_ENC_FMT(%ld)\n",
+                       sizeof(ENC_RPC_HOST_IFACE), sizeof(MEDIA_ENC_API_CONTROL_INTERFACE),
+                       sizeof(BUFFER_DESCRIPTOR_TYPE), sizeof(MEDIAIP_ENC_EXPERT_MODE_PARAM),
+                       sizeof(MEDIAIP_ENC_PARAM), sizeof(MEDIAIP_ENC_FMT)
+                       );
+       if (ctx->start_flag == true) {
+               pEncCtrlInterface = (pMEDIA_ENC_API_CONTROL_INTERFACE)phy_to_virt(pSharedInterface->pEncCtrlInterface[uStrIdx],
+                               ctx->dev->shared_mem.base_offset);
+               pEncStrBuffDesc = (pBUFFER_DESCRIPTOR_TYPE)phy_to_virt(pEncCtrlInterface->pEncStreamBufferDesc,
+                               ctx->dev->shared_mem.base_offset);
+               pEncStrBuffDesc->start = ctx->encoder_stream.phy_addr;
+               pEncStrBuffDesc->wptr = pEncStrBuffDesc->start;
+               pEncStrBuffDesc->rptr = pEncStrBuffDesc->start;
+               pEncStrBuffDesc->end = ctx->encoder_stream.phy_addr + ctx->encoder_stream.size;
+
+               vpu_dbg(LVL_INFO, "pEncStrBuffDesc->start=%x, pEncStrBuffDesc->wptr=0x%x, pEncStrBuffDesc->rptr=%x, pEncStrBuffDesc->end=%x\n", pEncStrBuffDesc->start, pEncStrBuffDesc->wptr, pEncStrBuffDesc->rptr, pEncStrBuffDesc->end);
+
+               pEncExpertModeParam = (pMEDIAIP_ENC_EXPERT_MODE_PARAM)phy_to_virt(pEncCtrlInterface->pEncExpertModeParam,
+                               ctx->dev->shared_mem.base_offset);
+               pEncExpertModeParam->Calib.mem_chunk_phys_addr = ctx->encoder_mem.phy_addr;
+               pEncExpertModeParam->Calib.mem_chunk_virt_addr = ctx->encoder_mem.phy_addr;
+               pEncExpertModeParam->Calib.mem_chunk_size = ctx->encoder_mem.size;
+               pEncExpertModeParam->Calib.cb_base = ctx->encoder_stream.phy_addr;
+               pEncExpertModeParam->Calib.cb_size = ctx->encoder_stream.size;
+
+#ifdef DUMP_DATA
+               read_data = (char *)vb2_plane_vaddr(vb, 0);
+               vpu_dbg(LVL_INFO, "transfer data from virt 0x%p: ", read_data);
+               for (read_idx = 0; read_idx < DATA_NUM; read_idx++)
+                       vpu_dbg(LVL_INFO, " 0x%x", read_data[read_idx]);
+               vpu_dbg(LVL_INFO, "\n");
+ #endif
+               v4l2_vpu_send_cmd(ctx, 0, GTB_ENC_CMD_CONFIGURE_CODEC, 0, NULL);
+               vpu_dbg(LVL_INFO, "send command GTB_ENC_CMD_CONFIGURE_CODEC\n");
+
+               ctx->start_flag = false;
+       }
+}
+
+static bool update_yuv_addr(struct vpu_ctx *ctx, u_int32 uStrIdx)
+{
+       bool bGotAFrame = FALSE;
+
+       struct vb2_data_req *p_data_req;
+       struct queue_data *This = &ctx->q_data[V4L2_SRC];
+       pENC_RPC_HOST_IFACE pSharedInterface = ctx->dev->shared_mem.pSharedInterface;
+       pMEDIA_ENC_API_CONTROL_INTERFACE pEncCtrlInterface;
+       pMEDIAIP_ENC_YUV_BUFFER_DESC pParamYuvBuffDesc;
+       u_int32 *pphy_address;
+#ifdef DUMP_DATA
+       char *read_data;
+       u_int32 read_idx;
+#endif
+
+       pEncCtrlInterface = (pMEDIA_ENC_API_CONTROL_INTERFACE)phy_to_virt(pSharedInterface->pEncCtrlInterface[uStrIdx],
+                       ctx->dev->shared_mem.base_offset);
+       pParamYuvBuffDesc = (pMEDIAIP_ENC_YUV_BUFFER_DESC)phy_to_virt(pEncCtrlInterface->pEncYUVBufferDesc,
+                       ctx->dev->shared_mem.base_offset);
+
+       wait_event_interruptible(ctx->buffer_wq_input,
+                       !list_empty(&This->drv_q)
+                       );
+
+       down(&This->drv_q_lock);
+       if (!list_empty(&This->drv_q)) {
+               p_data_req = list_first_entry(&This->drv_q,
+                               typeof(*p_data_req), list);
+
+#ifdef DUMP_DATA
+               read_data = (char *)vb2_plane_vaddr(p_data_req->vb2_buf, 0);
+               vpu_dbg(LVL_INFO, "transfer data from virt 0x%p: ", read_data);
+               for (read_idx = 0; read_idx < DATA_NUM; read_idx++)
+                       vpu_dbg(LVL_INFO, " 0x%x", read_data[read_idx]);
+               vpu_dbg(LVL_INFO, "\n");
+ #endif
+               convert_feed_stream(This, p_data_req->vb2_buf);
+               pphy_address = (u_int32 *)vb2_plane_cookie(p_data_req->vb2_buf, 0);
+               pParamYuvBuffDesc->uLumaBase = *pphy_address;
+    /* Not sure what the test should be here for a valid frame return from vb2_plane_cookie */
+               if (pParamYuvBuffDesc->uLumaBase != 0)
+                       bGotAFrame = TRUE;
+
+    /* keeps increasing, so just a frame input count rather than a Frame buffer ID */
+               pParamYuvBuffDesc->uFrameID = p_data_req->id;
+               list_del(&p_data_req->list);
+       }
+       up(&This->drv_q_lock);
+       return bGotAFrame;
+
+}
+
+static void report_stream_done(struct vpu_ctx *ctx,  MEDIAIP_ENC_PIC_INFO *pEncPicInfo)
+{
+       struct vb2_data_req *p_data_req;
+       struct queue_data *This = &ctx->q_data[V4L2_DST];
+       u_int32 wptr;
+       u_int32 rptr;
+       u_int32 start;
+       u_int32 end;
+
+       void *data_mapped;
+       u_int32 length;
+       u_int32 data_length = 0;
+       void *rptr_virt;
+
+       pBUFFER_DESCRIPTOR_TYPE pEncStrBuffDesc;
+       pMEDIA_ENC_API_CONTROL_INTERFACE pEncCtrlInterface;
+       pENC_RPC_HOST_IFACE pSharedInterface = ctx->dev->shared_mem.pSharedInterface;
+
+       /* Windsor stream buffer descriptor
+        * pEncStrBuffDesc = &RecCmdData.tEncStreamBufferDesc;
+        *
+        * VPU driver stream buffer descriptor with full address
+        * pVpuEncStrBuffDesc
+        * *
+        * Note the wprt is updated prior to calling this function
+        */
+       pEncCtrlInterface = (pMEDIA_ENC_API_CONTROL_INTERFACE)phy_to_virt(pSharedInterface->pEncCtrlInterface[ctx->str_index],
+                       ctx->dev->shared_mem.base_offset);
+       pEncStrBuffDesc = (pBUFFER_DESCRIPTOR_TYPE)phy_to_virt(pEncCtrlInterface->pEncStreamBufferDesc,
+                       ctx->dev->shared_mem.base_offset);
+
+
+       wptr = pEncStrBuffDesc->wptr | 0x80000000;
+       rptr = pEncStrBuffDesc->rptr | 0x80000000;
+       start = pEncStrBuffDesc->start | 0x80000000;
+       end = pEncStrBuffDesc->end | 0x80000000;
+       rptr_virt = ctx->encoder_stream.virt_addr + rptr - start;
+
+       vpu_dbg(LVL_INFO, "report_stream_done eptr=%x, rptr=%x, start=%x, end=%x\n", wptr, rptr, start, end);
+       wait_event_interruptible(ctx->buffer_wq_output,
+                       !list_empty(&This->drv_q)
+                       );
+
+       if (!list_empty(&This->drv_q)) {
+               down(&This->drv_q_lock);
+
+               vpu_dbg(LVL_INFO, "report_stream_done down\n");
+
+               p_data_req = list_first_entry(&This->drv_q, typeof(*p_data_req), list);
+
+               vpu_dbg(LVL_INFO, "%s :p_data_req(%p)\n", __func__, p_data_req);
+               vpu_dbg(LVL_INFO, "%s buf_id %d\n", __func__, p_data_req->vb2_buf->index);
+
+               // Calculate length - the amount of space remaining in output stream buffer
+               length = p_data_req->vb2_buf->planes[0].length;
+               data_mapped = (void *)vb2_plane_vaddr(p_data_req->vb2_buf, 0);
+               if (wptr == rptr && rptr != start)
+                       data_length = end - start;
+               else if (rptr < wptr)
+                       data_length = wptr - rptr;
+               else if (rptr > wptr)
+                       data_length = (end - rptr) + (wptr - start);
+
+       //update the bytesused for the output buffer
+       if (data_length >= length)
+               p_data_req->vb2_buf->planes[0].bytesused = length;
+       else
+               p_data_req->vb2_buf->planes[0].bytesused = data_length;
+
+       vpu_dbg(LVL_INFO, "%s data_length %d, length %d\n", __func__, data_length, length);
+       /* Following calculations determine how much data we can transfer into p_vb2_buf
+        * and then only copy that ammount, so rptr is the actual consumed ammount at the end*/
+       if ((wptr == rptr) || (rptr > wptr)) {
+               if (end - rptr >= length) {
+                       memcpy(data_mapped, rptr_virt, length);
+                       rptr += length;
+                       if (rptr == end)
+                               rptr = start;
+               } else {
+                       memcpy(data_mapped, rptr_virt, end-rptr);
+                       if ((length-(end-rptr)) >= (wptr-start)) {
+                               memcpy(data_mapped + (end-rptr), ctx->encoder_stream.virt_addr, wptr-start);
+                               rptr = wptr;
+                       } else {
+                               memcpy(data_mapped + (end-rptr), ctx->encoder_stream.virt_addr, length-(end-rptr));
+                               rptr = start+length-(end-rptr);
+                       }
+               }
+       } else {
+               if (wptr - rptr >= length) {
+                       memcpy(data_mapped, rptr_virt, length);
+                       rptr += length;
+               } else {
+                       memcpy(data_mapped, rptr_virt, wptr - rptr);
+                       rptr = wptr;
+               }
+       }
+
+       /* Update VPU stream buffer descriptor and Windsor FW stream buffer descriptors respectively*/
+       pEncStrBuffDesc->rptr = rptr;
+
+       list_del(&p_data_req->list);
+       up(&This->drv_q_lock);
+       //memcpy to vb2 buffer from encpicinfo
+       vb2_buffer_done(p_data_req->vb2_buf, VB2_BUF_STATE_DONE);
+       }
+       vpu_dbg(LVL_INFO, "report_buffer_done return\n");
+}
+
+static void enc_mem_alloc(struct vpu_ctx *ctx, MEDIAIP_ENC_MEM_REQ_DATA *req_data)
+{
+       pMEDIA_ENC_API_CONTROL_INTERFACE pEncCtrlInterface;
+       pMEDIAIP_ENC_MEM_POOL pEncMemPool;
+       pENC_RPC_HOST_IFACE pSharedInterface = ctx->dev->shared_mem.pSharedInterface;
+       u_int32 i;
+
+       pEncCtrlInterface = (pMEDIA_ENC_API_CONTROL_INTERFACE)phy_to_virt(pSharedInterface->pEncCtrlInterface[ctx->str_index],
+                       ctx->dev->shared_mem.base_offset);
+       pEncMemPool = (pMEDIAIP_ENC_MEM_POOL)phy_to_virt(pEncCtrlInterface->pEncMemPool,
+                       ctx->dev->shared_mem.base_offset);
+
+       for (i = 0; i < req_data->uEncFrmNum; i++) {
+               ctx->encFrame[i].size = ((req_data->uEncFrmSize + (~req_data->uAlignmentMask))&req_data->uAlignmentMask);
+               ctx->encFrame[i].virt_addr = dma_alloc_coherent(&ctx->dev->plat_dev->dev,
+                               ctx->encFrame[i].size,
+                               (dma_addr_t *)&ctx->encFrame[i].phy_addr,
+                               GFP_KERNEL | GFP_DMA32
+                               );
+               if (!ctx->encFrame[i].virt_addr)
+               vpu_dbg(LVL_ERR, "%s() encFrame alloc size(%x) fail!\n", __func__, ctx->encFrame[i].size);
+               else
+                       vpu_dbg(LVL_INFO, "%s() encFrame size(%d) encFrame virt(%p) encFrame phy(%p)\n", __func__, ctx->encFrame[i].size, ctx->encFrame[i].virt_addr, (void *)ctx->encFrame[i].phy_addr);
+
+               pEncMemPool->tEncFrameBuffers[i].uMemPhysAddr = ctx->encFrame[i].phy_addr;
+#ifdef CM4
+               pEncMemPool->tEncFrameBuffers[i].uMemVirtAddr = ctx->encFrame[i].phy_addr;
+#else
+               pEncMemPool->tEncFrameBuffers[i].uMemVirtAddr = ctx->encFrame[i].phy_addr - ctx->dev->m0_p_fw_space_phy;
+#endif
+               pEncMemPool->tEncFrameBuffers[i].uMemSize = ctx->encFrame[i].size;
+       }
+
+       for (i = 0; i < req_data->uRefFrmNum; i++) {
+               ctx->refFrame[i].size = ((req_data->uRefFrmSize + (~req_data->uAlignmentMask))&req_data->uAlignmentMask);
+               ctx->refFrame[i].virt_addr = dma_alloc_coherent(&ctx->dev->plat_dev->dev,
+                               ctx->refFrame[i].size,
+                               (dma_addr_t *)&ctx->refFrame[i].phy_addr,
+                               GFP_KERNEL | GFP_DMA32
+                               );
+
+               if (!ctx->refFrame[i].virt_addr)
+               vpu_dbg(LVL_ERR, "%s() refFrame alloc size(%x) fail!\n", __func__, ctx->refFrame[i].size);
+               else
+                       vpu_dbg(LVL_INFO, "%s() refFrame size(%d) refFrame virt(%p) refFrame phy(%p)\n", __func__, ctx->refFrame[i].size, ctx->refFrame[i].virt_addr, (void *)ctx->refFrame[i].phy_addr);
+
+               pEncMemPool->tRefFrameBuffers[i].uMemPhysAddr = ctx->refFrame[i].phy_addr;
+#ifdef CM4
+               pEncMemPool->tRefFrameBuffers[i].uMemVirtAddr = ctx->refFrame[i].phy_addr;
+#else
+               pEncMemPool->tRefFrameBuffers[i].uMemVirtAddr = ctx->refFrame[i].phy_addr - ctx->dev->m0_p_fw_space_phy;
+#endif
+               pEncMemPool->tRefFrameBuffers[i].uMemSize = ctx->refFrame[i].size;
+       }
+
+       ctx->actFrame.size = ((req_data->uActBufSize + (~req_data->uAlignmentMask))&req_data->uAlignmentMask);
+       ctx->actFrame.virt_addr = dma_alloc_coherent(&ctx->dev->plat_dev->dev,
+                       ctx->actFrame.size,
+                       (dma_addr_t *)&ctx->actFrame.phy_addr,
+                       GFP_KERNEL | GFP_DMA32
+                       );
+
+       if (!ctx->actFrame.virt_addr)
+               vpu_dbg(LVL_ERR, "%s() actFrame alloc size(%x) fail!\n", __func__, ctx->actFrame.size);
+       else
+               vpu_dbg(LVL_INFO, "%s() actFrame size(%d) actFrame virt(%p) actFrame phy(%p)\n", __func__, ctx->actFrame.size, ctx->actFrame.virt_addr, (void *)ctx->actFrame.phy_addr);
+
+       pEncMemPool->tActFrameBufferArea.uMemPhysAddr = ctx->actFrame.phy_addr;
+#ifdef CM4
+       pEncMemPool->tActFrameBufferArea.uMemVirtAddr = ctx->actFrame.phy_addr;
+#else
+       pEncMemPool->tActFrameBufferArea.uMemVirtAddr = ctx->actFrame.phy_addr - ctx->dev->m0_p_fw_space_phy;
+#endif
+       pEncMemPool->tActFrameBufferArea.uMemSize = ctx->actFrame.size;
+
+}
+
+static void vpu_api_event_handler(struct vpu_ctx *ctx, u_int32 uStrIdx, u_int32 uEvent, u_int32 *event_data)
+{
+       vpu_dbg(LVL_INFO, "vpu_encoder_event_handler is called\n");
+       if (uStrIdx < VID_API_NUM_STREAMS) {
+               switch (uEvent) {
+               case VID_API_ENC_EVENT_START_DONE: {
+               vpu_dbg(LVL_INFO, "VID_API_ENC_EVENT_START_DONE : Encoder configuration complete\n");
+               update_yuv_addr(ctx, 0);
+               v4l2_vpu_send_cmd(ctx, 0, GTB_ENC_CMD_FRAME_ENCODE, 0, NULL);
+               } break;
+               case VID_API_ENC_EVENT_MEM_REQUEST: {
+                       MEDIAIP_ENC_MEM_REQ_DATA *req_data = (MEDIAIP_ENC_MEM_REQ_DATA *)event_data;
+                       vpu_dbg(LVL_INFO, "VID_API_ENC_EVENT_MEM_REQUEST: need to request memory\n");
+                       vpu_dbg(LVL_INFO, "uEncFrmSize = %d, uEncFrmNum=%d, uRefFrmSize=%d, uRefFrmNum=%d, uActBufSize=%d, uAlignmentMask=0x%x\n", req_data->uEncFrmSize, req_data->uEncFrmNum, req_data->uRefFrmSize, req_data->uRefFrmNum, req_data->uActBufSize, req_data->uAlignmentMask);
+                       enc_mem_alloc(ctx, req_data);
+                       //update_yuv_addr(ctx,0);
+                       v4l2_vpu_send_cmd(ctx, 0, GTB_ENC_CMD_STREAM_START, 0, NULL);
+
+               } break;
+               case VID_API_ENC_EVENT_PARA_UPD_DONE: {
+               vpu_dbg(LVL_INFO, "VID_API_ENC_EVENT_PARA_UPD_DONE : Parameter update complete\n");
+               } break;
+               case VID_API_ENC_EVENT_FRAME_DONE: {
+               MEDIAIP_ENC_PIC_INFO *pEncPicInfo = (MEDIAIP_ENC_PIC_INFO *)event_data;
+
+               vpu_dbg(LVL_INFO, "VID_API_ENC_EVENT_FRAME_DONE pEncPicInfo->uPicEncodDone=%d: Encode picture done\n", pEncPicInfo->uPicEncodDone);
+               if (pEncPicInfo->uPicEncodDone) {
+#ifdef TB_REC_DBG
+               vpu_dbg(LVL_INFO, "VID_API_ENC_EVENT_FRAME_DONE : Encode picture done\n");
+               vpu_dbg(LVL_INFO, "       - Frame ID      : 0x%x\n", pEncPicInfo->uFrameID);
+
+               vpu_dbg(LVL_INFO, "       - Picture Type  : %s\n", pEncPicInfo->ePicType == MEDIAIP_ENC_PIC_TYPE_B_FRAME ? "B picture" :
+               pEncPicInfo->ePicType == MEDIAIP_ENC_PIC_TYPE_P_FRAME ? "P picture" :
+               pEncPicInfo->ePicType == MEDIAIP_ENC_PIC_TYPE_I_FRAME ? "I picture" :
+               pEncPicInfo->ePicType == MEDIAIP_ENC_PIC_TYPE_IDR_FRAME ? "IDR picture" : "BI picture");
+               vpu_dbg(LVL_INFO, "       - Skipped frame : 0x%x\n", pEncPicInfo->uSkippedFrame);
+               vpu_dbg(LVL_INFO, "       - Frame size    : 0x%x\n", pEncPicInfo->uFrameSize);
+               vpu_dbg(LVL_INFO, "       - Frame CRC     : 0x%x\n", pEncPicInfo->uFrameCrc);
+#endif
+
+               /* Sync the write pointer to the local view of it */
+
+               report_stream_done(ctx, pEncPicInfo);
+               }
+               } break;
+               case VID_API_ENC_EVENT_FRAME_RELEASE: {
+               struct queue_data *This = &ctx->q_data[V4L2_SRC];
+               u_int32 *uFrameID = (u_int32 *)event_data;
+               struct vb2_data_req *p_data_req;
+
+               vpu_dbg(LVL_INFO, "VID_API_ENC_EVENT_FRAME_RELEASE : Frame release - uFrameID = 0x%x\n", *uFrameID);
+               p_data_req = &This->vb2_reqs[*uFrameID];
+               vb2_buffer_done(p_data_req->vb2_buf,
+                               VB2_BUF_STATE_DONE
+                               );
+
+               } break;
+               case VID_API_ENC_EVENT_STOP_DONE:
+               vpu_dbg(LVL_INFO, "VID_API_ENC_EVENT_STOP_DONE : Stop done\n");
+               break;
+               case VID_API_ENC_EVENT_FRAME_INPUT_DONE: {
+               vpu_dbg(LVL_INFO, "VID_API_ENC_EVENT_FRAME_INPUT_DONE : Input done\n");
+               update_yuv_addr(ctx, 0);
+               v4l2_vpu_send_cmd(ctx, 0, GTB_ENC_CMD_FRAME_ENCODE, 0, NULL);
+               } break;
+               case VID_API_ENC_EVENT_TERMINATE_DONE:
+               vpu_dbg(LVL_INFO, "VID_API_ENC_EVENT_TERMINATE_DONE : Codec terminated\n");
+               break;
+               default:
+               vpu_dbg(LVL_INFO, "........unknown event : 0x%x\n", uEvent);
+               break;
+               }
+       }
+}
+
+//This code is added for MU
+static irqreturn_t fsl_vpu_mu_isr(int irq, void *This)
+{
+       struct vpu_dev *dev = This;
+       u32 msg;
+
+       MU_ReceiveMsg(dev->mu_base_virtaddr, 0, &msg);
+       if (msg == 0xaa) {
+#ifdef CM4
+               MU_sendMesgToFW(dev->mu_base_virtaddr, RPC_BUF_OFFSET, dev->m0_rpc_phy); //CM4 use absolute address
+#else
+               MU_sendMesgToFW(dev->mu_base_virtaddr, PRINT_BUF_OFFSET, dev->m0_rpc_phy - dev->m0_p_fw_space_phy + M0_PRINT_OFFSET);
+               MU_sendMesgToFW(dev->mu_base_virtaddr, RPC_BUF_OFFSET, dev->m0_rpc_phy - dev->m0_p_fw_space_phy); //CM0 use relative address
+               MU_sendMesgToFW(dev->mu_base_virtaddr, BOOT_ADDRESS, dev->m0_p_fw_space_phy);
+#endif
+               MU_sendMesgToFW(dev->mu_base_virtaddr, INIT_DONE, 2);
+       } else
+               schedule_work(&dev->msg_work);
+       return IRQ_HANDLED;
+}
+
+/* Initialization of the MU code. */
+static int vpu_mu_init(struct vpu_dev *dev)
+{
+       struct device_node *np;
+       unsigned int    vpu_mu_id;
+       u32 irq;
+       int ret = 0;
+
+       /*
+        * Get the address of MU to be used for communication with the M0 core
+        */
+#ifdef CM4
+       np = of_find_compatible_node(NULL, NULL, "fsl,imx8-mu0-vpu-m4");
+       if (!np) {
+               vpu_dbg(LVL_ERR, "error: Cannot find MU entry in device tree\n");
+               return -EINVAL;
+       }
+#else
+       np = of_find_compatible_node(NULL, NULL, "fsl,imx8-mu1-vpu-m0");
+       if (!np) {
+               vpu_dbg(LVL_ERR, "error: Cannot find MU entry in device tree\n");
+               return -EINVAL;
+       }
+#endif
+       dev->mu_base_virtaddr = of_iomap(np, 0);
+       WARN_ON(!dev->mu_base_virtaddr);
+
+       ret = of_property_read_u32_index(np,
+                               "fsl,vpu_ap_mu_id", 0, &vpu_mu_id);
+       if (ret) {
+               vpu_dbg(LVL_ERR, "Cannot get mu_id %d\n", ret);
+               return -EINVAL;
+       }
+
+       dev->vpu_mu_id = vpu_mu_id;
+
+       irq = of_irq_get(np, 0);
+
+       ret = devm_request_irq(&dev->plat_dev->dev, irq, fsl_vpu_mu_isr,
+                               IRQF_EARLY_RESUME, "vpu_mu_isr", (void *)dev);
+       if (ret) {
+               vpu_dbg(LVL_ERR, "request_irq failed %d, error = %d\n", irq, ret);
+               return -EINVAL;
+       }
+
+       if (!dev->vpu_mu_init) {
+               MU_Init(dev->mu_base_virtaddr);
+               MU_EnableRxFullInt(dev->mu_base_virtaddr, 0);
+               dev->vpu_mu_init = 1;
+       }
+
+       return ret;
+}
+
+static int vpu_next_free_instance(struct vpu_dev *dev)
+{
+       int idx = ffz(dev->instance_mask);
+
+       if (idx < 0 || idx > VPU_MAX_NUM_STREAMS)
+               return -EBUSY;
+
+       return idx;
+}
+
+extern u_int32 rpc_MediaIPFW_Video_message_check_encoder(struct shared_addr *This);
+static void vpu_msg_run_work(struct work_struct *work)
+{
+       struct vpu_dev *dev = container_of(work, struct vpu_dev, msg_work);
+       struct vpu_ctx *ctx;
+       struct event_msg msg;
+       struct shared_addr *This = &dev->shared_mem;
+
+       while (rpc_MediaIPFW_Video_message_check_encoder(This) == API_MSG_AVAILABLE) {
+               rpc_receive_msg_buf_encoder(This, &msg);
+               ctx = dev->ctx[msg.idx];
+               vpu_api_event_handler(ctx, msg.idx, msg.msgid, msg.msgdata);
+       }
+       if (rpc_MediaIPFW_Video_message_check_encoder(This) == API_MSG_BUFFER_ERROR)
+               vpu_dbg(LVL_ERR, "MSG num is too big to handle");
+
+}
+
+static int vpu_queue_setup(struct vb2_queue *vq,
+               unsigned int *buf_count,
+               unsigned int *plane_count,
+               unsigned int psize[],
+               struct device *allocators[])
+{
+       struct queue_data  *This = (struct queue_data *)vq->drv_priv;
+
+       vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+
+       if ((vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ||
+               (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               ) {
+                       *plane_count = 1;
+                       psize[0] = This->sizeimage[0];//check alignment
+       } else {
+               *plane_count = 1;
+               psize[0] = This->sizeimage[0] + This->sizeimage[1];
+       }
+       return 0;
+}
+
+static int vpu_buf_prepare(struct vb2_buffer *vb)
+{
+       vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+       return 0;
+}
+
+
+static int vpu_start_streaming(struct vb2_queue *q,
+               unsigned int count
+               )
+{
+       vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+       return 0;
+}
+
+
+static void vpu_stop_streaming(struct vb2_queue *q)
+{
+       struct queue_data *This = (struct queue_data *)q->drv_priv;
+       struct vb2_data_req *p_data_req;
+       struct vb2_data_req *p_temp;
+       struct vb2_buffer *vb;
+
+       vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+
+       down(&This->drv_q_lock);
+       if (!list_empty(&This->drv_q)) {
+               list_for_each_entry_safe(p_data_req, p_temp, &This->drv_q, list) {
+                       vpu_dbg(LVL_INFO, "%s(%d) - list_del(%p)\n",
+                                       __func__,
+                                       p_data_req->id,
+                                       p_data_req
+                                       );
+                       list_del(&p_data_req->list);
+               }
+       }
+       if (!list_empty(&q->queued_list))
+               list_for_each_entry(vb, &q->queued_list, queued_entry)
+                       vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+       INIT_LIST_HEAD(&This->drv_q);
+       up(&This->drv_q_lock);
+}
+
+static void vpu_buf_queue(struct vb2_buffer *vb)
+{
+       struct vb2_queue    *vq = vb->vb2_queue;
+       struct queue_data   *This = (struct queue_data *)vq->drv_priv;
+       struct vb2_data_req *data_req;
+
+       vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+
+       down(&This->drv_q_lock);
+       vpu_dbg(LVL_INFO, "c_port_buf_queue down\n");
+       data_req = &This->vb2_reqs[vb->index];
+       data_req->vb2_buf = vb;
+       data_req->id = vb->index;
+       list_add_tail(&data_req->list, &This->drv_q);
+
+       up(&This->drv_q_lock);
+       vpu_dbg(LVL_INFO, "c_port_buf_queue up vq->type=%d\n", vq->type);
+
+       if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               v4l2_transfer_buffer_to_firmware(This, vb);
+}
+
+static void vpu_prepare(struct vb2_queue *q)
+{
+       vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+}
+
+static void vpu_finish(struct vb2_queue *q)
+{
+       vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+}
+
+static struct vb2_ops v4l2_qops = {
+       .queue_setup        = vpu_queue_setup,
+       .wait_prepare       = vpu_prepare,
+       .wait_finish        = vpu_finish,
+       .buf_prepare        = vpu_buf_prepare,
+       .start_streaming    = vpu_start_streaming,
+       .stop_streaming     = vpu_stop_streaming,
+       .buf_queue          = vpu_buf_queue,
+};
+
+static void init_vb2_queue(struct queue_data *This, unsigned int type, struct vpu_ctx *ctx)
+{
+       struct vb2_queue  *vb2_q = &This->vb2_q;
+       int ret;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       // initialze driver queue
+       INIT_LIST_HEAD(&This->drv_q);
+       // initialize vb2 queue
+       vb2_q->type = type;
+       vb2_q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+       vb2_q->gfp_flags = GFP_DMA32;
+       vb2_q->ops = &v4l2_qops;
+       vb2_q->drv_priv = This;
+       vb2_q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
+       vb2_q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       vb2_q->dev = &ctx->dev->plat_dev->dev;
+       ret = vb2_queue_init(vb2_q);
+       if (ret)
+               vpu_dbg(LVL_ERR, "%s vb2_queue_init() failed (%d)!\n",
+                               __func__,
+                               ret
+                               );
+       else
+               This->vb2_q_inited = true;
+}
+
+static void init_queue_data(struct vpu_ctx *ctx)
+{
+       init_vb2_queue(&ctx->q_data[V4L2_SRC], V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, ctx);
+       ctx->q_data[V4L2_SRC].type = V4L2_SRC;
+       sema_init(&ctx->q_data[V4L2_SRC].drv_q_lock, 1);
+       init_vb2_queue(&ctx->q_data[V4L2_DST], V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, ctx);
+       ctx->q_data[V4L2_DST].type = V4L2_DST;
+       sema_init(&ctx->q_data[V4L2_DST].drv_q_lock, 1);
+}
+
+static void release_queue_data(struct vpu_ctx *ctx)
+{
+       struct queue_data *This = &ctx->q_data[V4L2_SRC];
+
+       if (This->vb2_q_inited)
+               vb2_queue_release(&This->vb2_q);
+       This = &ctx->q_data[V4L2_DST];
+       if (This->vb2_q_inited)
+               vb2_queue_release(&This->vb2_q);
+}
+
+#ifdef CM4
+static int power_CM4_up(struct vpu_dev *dev)
+{
+       sc_ipc_t ipcHndl;
+       sc_rsrc_t core_rsrc, mu_rsrc = -1;
+
+       ipcHndl = dev->mu_ipcHandle;
+       core_rsrc = SC_R_M4_0_PID0;
+       mu_rsrc = SC_R_M4_0_MU_1A;
+
+       if (sc_pm_set_resource_power_mode(ipcHndl, core_rsrc, SC_PM_PW_MODE_ON) != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "error: failed to power up core_rsrc\n");
+               return -EIO;
+       }
+
+       if (mu_rsrc != -1) {
+               if (sc_pm_set_resource_power_mode(ipcHndl, mu_rsrc, SC_PM_PW_MODE_ON) != SC_ERR_NONE) {
+                       vpu_dbg(LVL_ERR, "error: failed to power up mu_rsrc\n");
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+static int boot_CM4_up(struct vpu_dev *dev, void *boot_addr)
+{
+       sc_ipc_t ipcHndl;
+       sc_rsrc_t core_rsrc;
+       sc_faddr_t aux_core_ram;
+       void *core_ram_vir;
+       u32 size;
+
+       ipcHndl = dev->mu_ipcHandle;
+       core_rsrc = SC_R_M4_0_PID0;
+       aux_core_ram = 0x34FE0000;
+       size = SZ_128K;
+
+       core_ram_vir = ioremap(aux_core_ram,
+                       size
+                       );
+       if (!core_ram_vir)
+               vpu_dbg(LVL_ERR, "error: failed to remap space for core ram\n");
+
+       memcpy((void *)core_ram_vir, (void *)boot_addr, size);
+
+       if (sc_pm_cpu_start(ipcHndl, core_rsrc, true, aux_core_ram) != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "error: failed to start core_rsrc\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+#endif
+
+static int vpu_firmware_download(struct vpu_dev *This)
+{
+       unsigned char *image;
+       unsigned int FW_Size = 0;
+       void *csr_offset, *csr_cpuwait;
+       int ret = 0;
+
+       ret = request_firmware((const struct firmware **)&This->m0_pfw,
+                       M0FW_FILENAME,
+                       This->generic_dev
+                       );
+       if (ret) {
+               vpu_dbg(LVL_ERR, "%s() request fw %s failed(%d)\n",
+                       __func__, M0FW_FILENAME, ret);
+
+               if (This->m0_pfw) {
+                       release_firmware(This->m0_pfw);
+                       This->m0_pfw = NULL;
+               }
+               return ret;
+       } else {
+               vpu_dbg(LVL_INFO, "%s() request fw %s got size(%d)\n",
+                       __func__, M0FW_FILENAME, (int)This->m0_pfw->size);
+               image = (uint8_t *)This->m0_pfw->data;
+               FW_Size = This->m0_pfw->size;
+       }
+       memcpy(This->m0_p_fw_space_vir,
+                       image,
+                       FW_Size
+                       );
+#ifdef CM4
+       boot_CM4_up(This, This->m0_p_fw_space_vir);
+#else
+       csr_offset = ioremap(0x2d050000, 4);
+       writel(This->m0_p_fw_space_phy, csr_offset);
+       csr_cpuwait = ioremap(0x2d050004, 4);
+       writel(0x0, csr_cpuwait);
+#endif
+       return ret;
+}
+
+static int v4l2_open(struct file *filp)
+{
+       struct video_device *vdev = video_devdata(filp);
+       struct vpu_dev *dev = video_get_drvdata(vdev);
+       struct vpu_ctx *ctx = NULL;
+       int idx;
+       int ret;
+       u_int32 i;
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+       idx = vpu_next_free_instance(dev);
+       if (idx < 0) {
+               ret = idx;
+               return ret;
+       }
+       set_bit(idx, &dev->instance_mask);
+       init_completion(&ctx->completion);
+
+       v4l2_fh_init(&ctx->fh, video_devdata(filp));
+       filp->private_data = &ctx->fh;
+       v4l2_fh_add(&ctx->fh);
+
+       ctx->str_index = idx;
+       ctx->dev = dev;
+       ctx->ctrl_inited = false;
+       ctrls_setup_encoder(ctx);
+       ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+
+       dev->ctx[idx] = ctx;
+       ctx->b_firstseq = true;
+       ctx->start_flag = true;
+       init_queue_data(ctx);
+       init_waitqueue_head(&ctx->buffer_wq_output);
+       init_waitqueue_head(&ctx->buffer_wq_input);
+       mutex_lock(&dev->dev_mutex);
+       if (!dev->fw_is_ready) {
+               ret = vpu_firmware_download(dev);
+               if (ret) {
+                       vpu_dbg(LVL_ERR, "error: vpu_firmware_download fail\n");
+                       mutex_unlock(&dev->dev_mutex);
+                       return ret;
+               }
+               dev->fw_is_ready = true;
+       }
+       mutex_unlock(&dev->dev_mutex);
+       ctx->encoder_stream.size = STREAM_SIZE;
+       ctx->encoder_stream.virt_addr = dma_alloc_coherent(&ctx->dev->plat_dev->dev,
+                       ctx->encoder_stream.size,
+                       (dma_addr_t *)&ctx->encoder_stream.phy_addr,
+                       GFP_KERNEL | GFP_DMA32
+                       );
+
+       if (!ctx->encoder_stream.virt_addr)
+               vpu_dbg(LVL_ERR, "%s() encoder stream buffer alloc size(%x) fail!\n", __func__, ctx->encoder_stream.size);
+       else
+               vpu_dbg(LVL_INFO, "%s() encoder_stream_size(%d) encoder_stream_virt(%p) encoder_stream_phy(%p)\n", __func__, ctx->encoder_stream.size, ctx->encoder_stream.virt_addr, (void *)ctx->encoder_stream.phy_addr);
+
+       ctx->encoder_mem.size = 0;
+       ctx->encoder_mem.virt_addr = NULL;
+       ctx->encoder_mem.phy_addr = 0;
+
+       for (i = 0; i < MEDIAIP_MAX_NUM_WINDSOR_SRC_FRAMES; i++) {
+               ctx->encFrame[i].virt_addr = NULL;
+               ctx->encFrame[i].phy_addr = 0;
+               ctx->encFrame[i].size = 0;
+       }
+
+       for (i = 0; i < MEDIAIP_MAX_NUM_WINDSOR_REF_FRAMES; i++) {
+               ctx->refFrame[i].virt_addr = NULL;
+               ctx->refFrame[i].phy_addr = 0;
+               ctx->refFrame[i].size = 0;
+       }
+       ctx->actFrame.virt_addr = NULL;
+       ctx->actFrame.phy_addr = 0;
+       ctx->actFrame.size = 0;
+
+       return 0;
+}
+
+static int v4l2_release(struct file *filp)
+{
+       struct video_device *vdev = video_devdata(filp);
+       struct vpu_dev *dev = video_get_drvdata(vdev);
+       struct vpu_ctx *ctx = v4l2_fh_to_ctx(filp->private_data);
+       u_int32 i;
+
+       release_queue_data(ctx);
+       ctrls_delete_encoder(ctx);
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       clear_bit(ctx->str_index, &dev->instance_mask);
+
+       dma_free_coherent(&ctx->dev->plat_dev->dev,
+                       ctx->encoder_stream.size,
+                       ctx->encoder_stream.virt_addr,
+                       ctx->encoder_stream.phy_addr
+                       );
+       for (i = 0; i < MEDIAIP_MAX_NUM_WINDSOR_SRC_FRAMES; i++)
+               if (ctx->encFrame[i].virt_addr != NULL)
+                       dma_free_coherent(&ctx->dev->plat_dev->dev,
+                                       ctx->encFrame[i].size,
+                                       ctx->encFrame[i].virt_addr,
+                                       ctx->encFrame[i].phy_addr
+                                       );
+       for (i = 0; i < MEDIAIP_MAX_NUM_WINDSOR_REF_FRAMES; i++)
+               if (ctx->refFrame[i].virt_addr != NULL)
+                       dma_free_coherent(&ctx->dev->plat_dev->dev,
+                                       ctx->refFrame[i].size,
+                                       ctx->refFrame[i].virt_addr,
+                                       ctx->refFrame[i].phy_addr
+                                       );
+       if (ctx->actFrame.virt_addr != NULL)
+               dma_free_coherent(&ctx->dev->plat_dev->dev,
+                               ctx->actFrame.size,
+                               ctx->actFrame.virt_addr,
+                               ctx->actFrame.phy_addr
+                               );
+       kfree(ctx);
+       return 0;
+}
+
+static unsigned int v4l2_poll(struct file *filp, poll_table *wait)
+{
+       struct vpu_ctx *ctx = v4l2_fh_to_ctx(filp->private_data);
+       struct vb2_queue *src_q, *dst_q;
+       unsigned int rc = 0;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (ctx) {
+               poll_wait(filp, &ctx->fh.wait, wait);
+
+               if (v4l2_event_pending(&ctx->fh)) {
+                       vpu_dbg(LVL_INFO, "%s() v4l2_event_pending\n", __func__);
+                       rc |= POLLPRI;
+               }
+
+               src_q = &ctx->q_data[V4L2_SRC].vb2_q;
+               dst_q = &ctx->q_data[V4L2_DST].vb2_q;
+
+               if ((!src_q->streaming || list_empty(&src_q->queued_list))
+                               && (!dst_q->streaming || list_empty(&dst_q->queued_list))) {
+                       return rc;
+               }
+
+               poll_wait(filp, &src_q->done_wq, wait);
+               if (!list_empty(&src_q->done_list))
+                       rc |= POLLOUT | POLLWRNORM;
+               poll_wait(filp, &dst_q->done_wq, wait);
+               if (!list_empty(&dst_q->done_list))
+                       rc |= POLLIN | POLLWRNORM;
+       } else
+               rc = POLLERR;
+
+       return rc;
+}
+
+static int v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       long ret = -EPERM;
+       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       struct queue_data *q_data;
+       enum QUEUE_TYPE type;
+
+       struct vpu_ctx *ctx = v4l2_fh_to_ctx(filp->private_data);
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+       if (ctx) {
+               type = offset >> MMAP_BUF_TYPE_SHIFT;
+               q_data = &ctx->q_data[type];
+
+               offset &= ~MMAP_BUF_TYPE_MASK;
+               offset = offset >> PAGE_SHIFT;
+               vma->vm_pgoff = offset;
+               ret = vb2_mmap(&q_data->vb2_q,
+                                               vma
+                                               );
+       }
+
+       return ret;
+}
+
+static const struct v4l2_file_operations v4l2_encoder_fops = {
+       .owner = THIS_MODULE,
+       .open  = v4l2_open,
+       .unlocked_ioctl = video_ioctl2,
+       .release = v4l2_release,
+       .poll = v4l2_poll,
+       .mmap = v4l2_mmap,
+};
+
+static struct video_device v4l2_videodevice_encoder = {
+       .name   = "vpu encoder",
+       .fops   = &v4l2_encoder_fops,
+       .ioctl_ops = &v4l2_encoder_ioctl_ops,
+       .vfl_dir = VFL_DIR_M2M,
+};
+
+static int set_vpu_pwr(sc_ipc_t ipcHndl,
+               sc_pm_power_mode_t pm
+               )
+{
+       int rv = -1;
+       sc_err_t sciErr;
+
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+       if (!ipcHndl) {
+               vpu_dbg(LVL_ERR, "--- set_vpu_pwr no IPC handle\n");
+               goto set_vpu_pwrexit;
+       }
+
+       // Power on or off PID0, ENC
+       sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_PID0, pm);
+       if (sciErr != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "--- sc_pm_set_resource_power_mode(SC_R_VPU_PID0,%d) SCI error! (%d)\n", sciErr, pm);
+               goto set_vpu_pwrexit;
+       }
+       sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_PID1, pm);
+       if (sciErr != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "--- sc_pm_set_resource_power_mode(SC_R_VPU_PID1,%d) SCI error! (%d)\n", sciErr, pm);
+               goto set_vpu_pwrexit;
+       }
+       sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_PID2, pm);
+       if (sciErr != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "--- sc_pm_set_resource_power_mode(SC_R_VPU_PID2,%d) SCI error! (%d)\n", sciErr, pm);
+               goto set_vpu_pwrexit;
+       }
+       sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_PID3, pm);
+       if (sciErr != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "--- sc_pm_set_resource_power_mode(SC_R_VPU_PID3,%d) SCI error! (%d)\n", sciErr, pm);
+               goto set_vpu_pwrexit;
+       }
+       sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_PID4, pm);
+       if (sciErr != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "--- sc_pm_set_resource_power_mode(SC_R_VPU_PID4,%d) SCI error! (%d)\n", sciErr, pm);
+               goto set_vpu_pwrexit;
+       }
+       sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_PID5, pm);
+       if (sciErr != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "--- sc_pm_set_resource_power_mode(SC_R_VPU_PID5,%d) SCI error! (%d)\n", sciErr, pm);
+               goto set_vpu_pwrexit;
+       }
+       sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_PID6, pm);
+       if (sciErr != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "--- sc_pm_set_resource_power_mode(SC_R_VPU_PID6,%d) SCI error! (%d)\n", sciErr, pm);
+               goto set_vpu_pwrexit;
+       }
+       sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_PID7, pm);
+       if (sciErr != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "--- sc_pm_set_resource_power_mode(SC_R_VPU_PID7,%d) SCI error! (%d)\n", sciErr, pm);
+               goto set_vpu_pwrexit;
+       }
+#ifdef TEST_BUILD
+       sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_ENC, pm);
+       if (sciErr != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "--- sc_pm_set_resource_power_mode(SC_R_VPU_ENC,%d) SCI error! (%d)\n", sciErr, pm);
+               goto set_vpu_pwrexit;
+       }
+#else
+       sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_ENC_0, pm);
+       if (sciErr != SC_ERR_NONE) {
+               vpu_dbg(LVL_ERR, "--- sc_pm_set_resource_power_mode(SC_R_VPU_ENC_0,%d) SCI error! (%d)\n", sciErr, pm);
+               goto set_vpu_pwrexit;
+       }
+#endif
+
+       rv = 0;
+
+set_vpu_pwrexit:
+       return rv;
+}
+
+static void vpu_set_power(struct vpu_dev *dev, bool on)
+{
+       int ret;
+
+       if (on) {
+               ret = set_vpu_pwr(dev->mu_ipcHandle, SC_PM_PW_MODE_ON);
+               if (ret)
+                       vpu_dbg(LVL_ERR, "failed to power on\n");
+               pm_runtime_get_sync(dev->generic_dev);
+       } else {
+               pm_runtime_put_sync_suspend(dev->generic_dev);
+               ret = set_vpu_pwr(dev->mu_ipcHandle, SC_PM_PW_MODE_OFF);
+               if (ret)
+                       vpu_dbg(LVL_ERR, "failed to power off\n");
+       }
+}
+
+static void vpu_setup(struct vpu_dev *This)
+{
+       uint32_t read_data = 0;
+
+       vpu_dbg(LVL_INFO, "enter %s\n", __func__);
+       writel(0x1, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_SCB_CLK_ENABLE_SET);
+       writel(0xffffffff, This->regs_base + 0x70190);
+       writel(0xffffffff, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_XMEM_RESET_SET);
+
+       writel(0xE, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_SCB_CLK_ENABLE_SET);
+       writel(0x7, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_CACHE_RESET_SET);
+
+       writel(0x1f, This->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_BLK_CTRL + MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_SET);
+       writel(0xffffffff, This->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_BLK_CTRL + MFD_BLK_CTRL_MFD_SYS_RESET_SET);
+
+       writel(0x102, This->regs_base + XMEM_CONTROL);
+
+       read_data = readl(This->regs_base+0x70108);
+       vpu_dbg(LVL_IRQ, "%s read_data=%x\n", __func__, read_data);
+}
+
+static void vpu_reset(struct vpu_dev *This)
+{
+       vpu_dbg(LVL_INFO, "enter %s\n", __func__);
+       writel(0x7, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_CACHE_RESET_CLR);
+       writel(0xffffffff, This->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_BLK_CTRL + MFD_BLK_CTRL_MFD_SYS_RESET_CLR);
+}
+
+static int vpu_enable_hw(struct vpu_dev *This)
+{
+       vpu_dbg(LVL_INFO, "%s()\n", __func__);
+       vpu_set_power(This, true);
+       This->vpu_clk = clk_get(&This->plat_dev->dev, "vpu_encoder_clk");
+       if (IS_ERR(This->vpu_clk)) {
+               vpu_dbg(LVL_ERR, "vpu_clk get error\n");
+               return -ENOENT;
+       }
+       clk_set_rate(This->vpu_clk, 600000000);
+       clk_prepare_enable(This->vpu_clk);
+       vpu_setup(This);
+       return 0;
+}
+
+static void vpu_disable_hw(struct vpu_dev *This)
+{
+       vpu_reset(This);
+       if (This->regs_base) {
+               devm_iounmap(&This->plat_dev->dev,
+                               This->regs_base);
+       }
+       clk_disable_unprepare(This->vpu_clk);
+       if (This->vpu_clk) {
+               clk_put(This->vpu_clk);
+               This->vpu_clk = NULL;
+       }
+       vpu_set_power(This, false);
+}
+
+static int vpu_probe(struct platform_device *pdev)
+{
+       struct vpu_dev *dev;
+       struct resource *res;
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *reserved_node;
+       struct resource reserved_res;
+       unsigned int mu_id;
+       int ret;
+
+       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+       dev->plat_dev = pdev;
+       dev->generic_dev = &pdev->dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       dev->regs_base = ioremap(ENC_REG_BASE, 0x1000000);
+       if (!dev->regs_base) {
+               vpu_dbg(LVL_ERR, "%s could not map regs_base\n", __func__);
+               return PTR_ERR(dev->regs_base);
+       }
+
+       if (np) {
+               reserved_node = of_parse_phandle(np, "boot-region", 0);
+               if (!reserved_node) {
+                       vpu_dbg(LVL_ERR, "error: boot-region of_parse_phandle error\n");
+                       return -ENODEV;
+               }
+
+               if (of_address_to_resource(reserved_node, 0, &reserved_res)) {
+                       vpu_dbg(LVL_ERR, "error: boot-region of_address_to_resource error\n");
+                       return -EINVAL;
+               }
+               dev->m0_p_fw_space_phy = reserved_res.start;
+               reserved_node = of_parse_phandle(np, "rpc-region", 0);
+               if (!reserved_node) {
+                       vpu_dbg(LVL_ERR, "error: rpc-region of_parse_phandle error\n");
+                       return -ENODEV;
+               }
+
+               if (of_address_to_resource(reserved_node, 0, &reserved_res)) {
+                       vpu_dbg(LVL_ERR, "error: rpc-region of_address_to_resource error\n");
+                       return -EINVAL;
+               }
+               dev->m0_rpc_phy = reserved_res.start;
+       } else
+               vpu_dbg(LVL_ERR, "error: %s of_node is NULL\n", __func__);
+
+       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+       if (ret) {
+               vpu_dbg(LVL_ERR, "%s unable to register v4l2 dev\n", __func__);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, dev);
+
+       dev->pvpu_encoder_dev = video_device_alloc();
+       if (dev->pvpu_encoder_dev) {
+               strncpy(dev->pvpu_encoder_dev->name, v4l2_videodevice_encoder.name, sizeof(v4l2_videodevice_encoder.name));
+               dev->pvpu_encoder_dev->fops = v4l2_videodevice_encoder.fops;
+               dev->pvpu_encoder_dev->ioctl_ops = v4l2_videodevice_encoder.ioctl_ops;
+               dev->pvpu_encoder_dev->release = video_device_release;
+               dev->pvpu_encoder_dev->vfl_dir = v4l2_videodevice_encoder.vfl_dir;
+               dev->pvpu_encoder_dev->v4l2_dev = &dev->v4l2_dev;
+
+               video_set_drvdata(dev->pvpu_encoder_dev, dev);
+
+               if (video_register_device(dev->pvpu_encoder_dev,
+                                       VFL_TYPE_GRABBER,
+                                       -1)) {
+                       vpu_dbg(LVL_ERR, "%s unable to register video encoder device\n",
+                                       __func__
+                                       );
+                       video_device_release(dev->pvpu_encoder_dev);
+                       dev->pvpu_encoder_dev = NULL;
+               } else {
+                       vpu_dbg(LVL_INFO, "%s  register video encoder device\n",
+                                       __func__
+                                  );
+               }
+       }
+
+       if (!dev->mu_ipcHandle) {
+               ret = sc_ipc_getMuID(&mu_id);
+               if (ret) {
+                       vpu_dbg(LVL_ERR, "--- sc_ipc_getMuID() cannot obtain mu id SCI error! (%d)\n", ret);
+                       return ret;
+               }
+
+               ret = sc_ipc_open(&dev->mu_ipcHandle, mu_id);
+               if (ret) {
+                       vpu_dbg(LVL_ERR, "--- sc_ipc_getMuID() cannot open MU channel to SCU error! (%d)\n", ret);
+                       return ret;
+               }
+       }
+
+       vpu_enable_hw(dev);
+
+       mutex_init(&dev->dev_mutex);
+       dev->fw_is_ready = false;
+       dev->workqueue = alloc_workqueue("vpu", WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+       if (!dev->workqueue) {
+               vpu_dbg(LVL_ERR, "%s unable to alloc workqueue\n", __func__);
+               ret = -ENOMEM;
+               return ret;
+       }
+
+       INIT_WORK(&dev->msg_work, vpu_msg_run_work);
+#ifdef CM4
+       ret = power_CM4_up(dev);
+       if (ret) {
+               vpu_dbg(LVL_ERR, "error: failed to power on CM4\n");
+               return ret;
+       }
+#endif
+       ret = vpu_mu_init(dev);
+       if (ret) {
+               vpu_dbg(LVL_ERR, "%s vpu mu init failed\n", __func__);
+               return ret;
+       }
+       //firmware space for M0
+       dev->m0_p_fw_space_vir = ioremap(dev->m0_p_fw_space_phy,
+                       M0_BOOT_SIZE
+                       );
+       if (!dev->m0_p_fw_space_vir)
+               vpu_dbg(LVL_ERR, "failed to remap space for M0 firmware\n");
+
+       memset_io(dev->m0_p_fw_space_vir, 0, M0_BOOT_SIZE);
+
+       dev->m0_rpc_virt = ioremap(dev->m0_rpc_phy,
+                       SHARED_SIZE
+                       );
+       if (!dev->m0_rpc_virt)
+               vpu_dbg(LVL_ERR, "failed to remap space for shared memory\n");
+
+       memset_io(dev->m0_rpc_virt, 0, SHARED_SIZE);
+
+#ifdef CM4
+       rpc_init_shared_memory_encoder(&dev->shared_mem, dev->m0_rpc_phy, dev->m0_rpc_virt, SHARED_SIZE);
+#else
+       rpc_init_shared_memory_encoder(&dev->shared_mem, dev->m0_rpc_phy - dev->m0_p_fw_space_phy, dev->m0_rpc_virt, SHARED_SIZE);
+#endif
+       rpc_set_system_cfg_value_encoder(dev->shared_mem.pSharedInterface, VPU_REG_BASE);
+       return 0;
+}
+
+static int vpu_remove(struct platform_device *pdev)
+{
+       struct vpu_dev *dev = platform_get_drvdata(pdev);
+
+       destroy_workqueue(dev->workqueue);
+       if (dev->m0_p_fw_space_vir)
+               iounmap(dev->m0_p_fw_space_vir);
+       if (dev->m0_pfw) {
+               release_firmware(dev->m0_pfw);
+               dev->m0_pfw = NULL;
+       }
+       dev->m0_p_fw_space_vir = NULL;
+       dev->m0_p_fw_space_phy = 0;
+       if (dev->shared_mem.shared_mem_vir)
+               iounmap(dev->shared_mem.shared_mem_vir);
+       dev->shared_mem.shared_mem_vir = NULL;
+       dev->shared_mem.shared_mem_phy = 0;
+
+       vpu_disable_hw(dev);
+
+       if (video_get_drvdata(dev->pvpu_encoder_dev))
+               video_unregister_device(dev->pvpu_encoder_dev);
+
+       v4l2_device_unregister(&dev->v4l2_dev);
+       return 0;
+}
+
+static int vpu_runtime_suspend(struct device *dev)
+{
+       return 0;
+}
+
+static int vpu_runtime_resume(struct device *dev)
+{
+       return 0;
+}
+
+static int vpu_suspend(struct device *dev)
+{
+       return 0;
+}
+
+static int vpu_resume(struct device *dev)
+{
+       return 0;
+}
+
+static const struct dev_pm_ops vpu_pm_ops = {
+       SET_RUNTIME_PM_OPS(vpu_runtime_suspend, vpu_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(vpu_suspend, vpu_resume)
+};
+
+static const struct of_device_id vpu_of_match[] = {
+       { .compatible = "nxp,imx8qm-vpu-encoder", },
+       { .compatible = "nxp,imx8qxp-vpu-encoder", },
+       {}
+}
+MODULE_DEVICE_TABLE(of, vpu_of_match);
+
+static struct platform_driver vpu_driver = {
+       .probe = vpu_probe,
+       .remove = vpu_remove,
+       .driver = {
+               .name = "vpu-b0-encoder",
+               .of_match_table = vpu_of_match,
+               .pm = &vpu_pm_ops,
+       },
+};
+module_platform_driver(vpu_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Linux VPU driver for Freescale i.MX/MXC");
+MODULE_LICENSE("GPL");
+
+module_param(vpu_dbg_level_encoder, int, 0644);
+MODULE_PARM_DESC(vpu_dbg_level_encoder, "Debug level (0-2)");
+
diff --git a/drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.h b/drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.h
new file mode 100644 (file)
index 0000000..532beb4
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2018 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU Lesser General
+ * Public License.  You may obtain a copy of the GNU Lesser General
+ * Public License Version 2.1 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/lgpl-license.html
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+/*!
+ * @file vpu_encoder_b0.h
+ *
+ * @brief VPU ENCODER B0 definition
+ *
+ */
+#ifndef __VPU_ENCODER_B0_H__
+#define __VPU_ENCODER_B0_H__
+
+#include <linux/irqreturn.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/videobuf2-v4l2.h>
+#include <soc/imx8/sc/svc/irq/api.h>
+#include <soc/imx8/sc/ipc.h>
+#include <soc/imx8/sc/sci.h>
+#include <linux/mx8_mu.h>
+#include <media/v4l2-event.h>
+#include "vpu_encoder_rpc.h"
+
+extern unsigned int vpu_dbg_level_encoder;
+
+#define v4l2_fh_to_ctx(__fh) \
+       container_of(__fh, struct vpu_ctx, fh)
+#define v4l2_ctrl_to_ctx(__ctrl) \
+       container_of((__ctrl)->handler, struct vpu_ctx, ctrl_handler)
+
+#define MIN_SPACE 2048
+
+#define VPU_MAX_FORMATS 4
+#define VPU_MAX_BUFFER 32
+#define M0FW_FILENAME "encoder_main.bin"
+#define MMAP_BUF_TYPE_SHIFT 28
+#define MMAP_BUF_TYPE_MASK 0xF0000000
+#define M0_BOOT_SIZE 0x1000000
+#define M0_PRINT_OFFSET 0x500000
+#define SHARED_SIZE 0x00400000
+#define MEM_SIZE  0x2800000
+#define YUV_SIZE  0x4000000
+#define STREAM_SIZE 0x600000
+#ifdef CM4
+#define VPU_REG_BASE 0x2c000000
+#else
+#define VPU_REG_BASE 0x40000000
+#endif
+#define ENC_REG_BASE 0x2c000000
+
+#define V4L2_MAX_CTRLS 12
+struct vpu_v4l2_control {
+       uint32_t id;
+       enum v4l2_ctrl_type type;
+       uint32_t minimum;
+       uint32_t maximum;
+       uint32_t step;
+       uint32_t default_value;
+       uint32_t menu_skip_mask;
+       bool is_volatile;
+};
+
+typedef enum{
+       INIT_DONE = 1,
+       RPC_BUF_OFFSET,
+       PRINT_BUF_OFFSET,
+       BOOT_ADDRESS,
+       COMMAND,
+       EVENT
+} MSG_Type;
+
+enum QUEUE_TYPE {
+       V4L2_SRC = 0,
+       V4L2_DST = 1,
+};
+
+enum vpu_video_standard {
+       VPU_VIDEO_UNDEFINED = 0,
+       VPU_VIDEO_AVC = 1,
+       VPU_VIDEO_VC1 = 2,
+       VPU_VIDEO_MPEG2 = 3,
+       VPU_VIDEO_AVS = 4,
+       VPU_VIDEO_ASP = 5,
+       VPU_VIDEO_JPEG = 6,
+       VPU_VIDEO_RV8 = 7,
+       VPU_VIDEO_RV9 = 8,
+       VPU_VIDEO_VP6 = 9,
+       VPU_VIDEO_SPK = 10,
+       VPU_VIDEO_VP8 = 11,
+       VPU_VIDEO_AVC_MVC = 12,
+       VPU_VIDEO_HEVC = 13,
+       VPU_VIDEO_VP9 = 14,
+};
+
+#define VPU_PIX_FMT_AVS         v4l2_fourcc('A', 'V', 'S', '0')
+#define VPU_PIX_FMT_ASP         v4l2_fourcc('A', 'S', 'P', '0')
+#define VPU_PIX_FMT_RV8         v4l2_fourcc('R', 'V', '8', '0')
+#define VPU_PIX_FMT_RV9         v4l2_fourcc('R', 'V', '9', '0')
+#define VPU_PIX_FMT_VP6         v4l2_fourcc('V', 'P', '6', '0')
+#define VPU_PIX_FMT_SPK         v4l2_fourcc('S', 'P', 'K', '0')
+#define VPU_PIX_FMT_HEVC        v4l2_fourcc('H', 'E', 'V', 'C')
+#define VPU_PIX_FMT_VP9         v4l2_fourcc('V', 'P', '9', '0')
+#define VPU_PIX_FMT_LOGO        v4l2_fourcc('L', 'O', 'G', 'O')
+
+#define VPU_PIX_FMT_TILED_8     v4l2_fourcc('Z', 'T', '0', '8')
+#define VPU_PIX_FMT_TILED_10    v4l2_fourcc('Z', 'T', '1', '0')
+
+enum vpu_pixel_format {
+       VPU_HAS_COLOCATED = 0x00000001,
+       VPU_HAS_SPLIT_FLD = 0x00000002,
+       VPU_PF_MASK       = ~(VPU_HAS_COLOCATED | VPU_HAS_SPLIT_FLD),
+
+       VPU_IS_TILED      = 0x000000100,
+       VPU_HAS_10BPP     = 0x00000200,
+
+       VPU_IS_PLANAR     = 0x00001000,
+       VPU_IS_SEMIPLANAR = 0x00002000,
+       VPU_IS_PACKED     = 0x00004000,
+
+       // Merged definitions using above flags:
+       VPU_PF_UNDEFINED  = 0,
+       VPU_PF_YUV420_SEMIPLANAR = 0x00010000 | VPU_IS_SEMIPLANAR,
+       VPU_PF_YUV420_PLANAR = 0x00020000 | VPU_IS_PLANAR,
+       VPU_PF_UYVY = 0x00040000 | VPU_IS_PACKED,
+       VPU_PF_TILED_8BPP = 0x00080000 | VPU_IS_TILED | VPU_IS_SEMIPLANAR,
+       VPU_PF_TILED_10BPP = 0x00100000 | VPU_IS_TILED | VPU_IS_SEMIPLANAR | VPU_HAS_10BPP,
+};
+
+struct vpu_v4l2_fmt {
+       char *name;
+       unsigned int fourcc;
+       unsigned int num_planes;
+       unsigned int venc_std;
+};
+
+struct vb2_data_req {
+       struct list_head  list;
+       struct vb2_buffer *vb2_buf;
+       int id;
+};
+
+struct queue_data {
+       unsigned int width;
+       unsigned int height;
+       unsigned int bytesperline;
+       unsigned int sizeimage[2];
+       unsigned int fourcc;
+       unsigned int vdec_std;
+       struct v4l2_rect rect;
+       int buf_type; // v4l2_buf_type
+       bool vb2_q_inited;
+       struct vb2_queue vb2_q;    // vb2 queue
+       struct list_head drv_q;    // driver queue
+       struct semaphore drv_q_lock;
+       struct vb2_data_req vb2_reqs[VPU_MAX_BUFFER];
+       enum QUEUE_TYPE type;
+};
+struct vpu_ctx;
+struct vpu_dev {
+       struct device *generic_dev;
+       struct v4l2_device v4l2_dev;
+       struct video_device *pvpu_encoder_dev;
+       struct platform_device *plat_dev;
+       struct firmware *m0_pfw;
+       void *m0_p_fw_space_vir;
+       u_int32 m0_p_fw_space_phy;
+       void *m0_rpc_virt;
+       u_int32 m0_rpc_phy;
+       struct mutex dev_mutex;
+       bool fw_is_ready;
+       struct completion msg_complete;
+       struct workqueue_struct *workqueue;
+       struct work_struct msg_work;
+       unsigned long instance_mask;
+       sc_ipc_t mu_ipcHandle;
+       struct clk *vpu_clk;
+       void __iomem *mu_base_virtaddr;
+       unsigned int vpu_mu_id;
+       int vpu_mu_init;
+
+       struct clk *clk_m0;
+       void __iomem *regs_base;
+
+       struct shared_addr shared_mem;
+       struct vpu_ctx *ctx[VPU_MAX_NUM_STREAMS];
+};
+
+struct buffer_addr {
+       void *virt_addr;
+       dma_addr_t phy_addr;
+       u_int32 size;
+};
+
+struct vpu_ctx {
+       struct vpu_dev *dev;
+       struct v4l2_fh fh;
+
+       struct v4l2_ctrl *ctrls[V4L2_MAX_CTRLS];
+       struct v4l2_ctrl_handler ctrl_handler;
+       bool ctrl_inited;
+
+       int str_index;
+       struct queue_data q_data[2];
+//     struct work_struct msg_work;
+       struct completion completion;
+       bool b_firstseq;
+       bool start_flag;
+       wait_queue_head_t buffer_wq_output;
+       wait_queue_head_t buffer_wq_input;
+       struct buffer_addr encoder_buffer;
+       struct buffer_addr encoder_stream;
+       struct buffer_addr encoder_mem;
+       struct buffer_addr encFrame[MEDIAIP_MAX_NUM_WINDSOR_SRC_FRAMES];
+       struct buffer_addr refFrame[MEDIAIP_MAX_NUM_WINDSOR_REF_FRAMES];
+       struct buffer_addr actFrame;
+
+};
+
+#define LVL_INFO 3
+#define LVL_ERR  2
+#define LVL_IRQ  1
+#define LVL_ALL  0
+
+#define vpu_dbg(level, fmt, arg...) \
+       do { \
+               if (vpu_dbg_level_encoder >= (level)) \
+                       printk("[DEBUG]\t " fmt, ## arg); \
+       } while (0)
+
+#endif
diff --git a/drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.c b/drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.c
new file mode 100644 (file)
index 0000000..17e6adb
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "vpu_encoder_rpc.h"
+
+void rpc_init_shared_memory_encoder(struct shared_addr *This,
+               unsigned long long base_phy_addr,
+               void *base_virt_addr,
+               u_int32 total_size)
+{
+       pENC_RPC_HOST_IFACE pSharedInterface;
+       unsigned int phy_addr;
+       unsigned int i;
+       unsigned int temp_addr;
+       BUFFER_DESCRIPTOR_TYPE *pSharedCmdBufDescPtr;
+       BUFFER_DESCRIPTOR_TYPE *pSharedMsgBufDescPtr;
+       pMEDIA_ENC_API_CONTROL_INTERFACE pEncCtrlInterface;
+
+       This->shared_mem_phy = base_phy_addr;
+       This->shared_mem_vir = base_virt_addr;
+       This->base_offset = (unsigned long long)(base_virt_addr - base_phy_addr);
+
+       pSharedInterface = (pENC_RPC_HOST_IFACE)This->shared_mem_vir;
+       This->pSharedInterface = pSharedInterface;
+
+       pSharedInterface->FwExecBaseAddr = base_phy_addr;
+       pSharedInterface->FwExecAreaSize = total_size;
+
+       pSharedCmdBufDescPtr = (BUFFER_DESCRIPTOR_TYPE *)&pSharedInterface->StreamCmdBufferDesc;
+       pSharedMsgBufDescPtr = (BUFFER_DESCRIPTOR_TYPE *)&pSharedInterface->StreamMsgBufferDesc;
+
+       phy_addr = base_phy_addr + sizeof(ENC_RPC_HOST_IFACE);
+       This->cmd_mem_phy = phy_addr;
+       This->cmd_mem_vir = This->shared_mem_vir + sizeof(ENC_RPC_HOST_IFACE);
+
+       pSharedCmdBufDescPtr->wptr = phy_addr;
+       pSharedCmdBufDescPtr->rptr = pSharedCmdBufDescPtr->wptr;
+       pSharedCmdBufDescPtr->start = pSharedCmdBufDescPtr->wptr;
+       pSharedCmdBufDescPtr->end = pSharedCmdBufDescPtr->start + CMD_SIZE;
+
+       phy_addr += CMD_SIZE;
+       This->msg_mem_phy = phy_addr;
+       This->msg_mem_vir = This->cmd_mem_vir + CMD_SIZE;
+
+       pSharedMsgBufDescPtr->wptr = phy_addr;
+       pSharedMsgBufDescPtr->rptr = pSharedMsgBufDescPtr->wptr;
+       pSharedMsgBufDescPtr->start = pSharedMsgBufDescPtr->wptr;
+       pSharedMsgBufDescPtr->end = pSharedMsgBufDescPtr->start + MSG_SIZE;
+
+       phy_addr += MSG_SIZE;
+
+       for (i = 0; i < VPU_MAX_NUM_STREAMS; i++) {
+               pSharedInterface->pEncCtrlInterface[i] = phy_addr;
+               phy_addr += sizeof(MEDIA_ENC_API_CONTROL_INTERFACE);
+       }
+
+       for (i = 0; i < VPU_MAX_NUM_STREAMS; i++) {
+               temp_addr = pSharedInterface->pEncCtrlInterface[i];
+               pEncCtrlInterface = (pMEDIA_ENC_API_CONTROL_INTERFACE)(temp_addr + This->base_offset);
+               pEncCtrlInterface->pEncYUVBufferDesc = phy_addr;
+               phy_addr += sizeof(MEDIAIP_ENC_YUV_BUFFER_DESC);
+               pEncCtrlInterface->pEncStreamBufferDesc = phy_addr;
+               phy_addr += sizeof(BUFFER_DESCRIPTOR_TYPE);
+               pEncCtrlInterface->pEncExpertModeParam = phy_addr;
+               phy_addr += sizeof(MEDIAIP_ENC_EXPERT_MODE_PARAM);
+               pEncCtrlInterface->pEncParam = phy_addr;
+               phy_addr += sizeof(MEDIAIP_ENC_PARAM);
+               pEncCtrlInterface->pEncMemPool = phy_addr;
+               phy_addr += sizeof(MEDIAIP_ENC_MEM_POOL);
+               pEncCtrlInterface->pEncEncodingStatus = phy_addr;
+               phy_addr += sizeof(ENC_ENCODING_STATUS);
+               pEncCtrlInterface->pEncDSAStatus = phy_addr;
+               phy_addr += sizeof(ENC_DSA_STATUS_t);
+       }
+}
+
+void rpc_set_system_cfg_value_encoder(void *Interface, u_int32 regs_base)
+{
+       pENC_RPC_HOST_IFACE pSharedInterface;
+       MEDIAIP_FW_SYSTEM_CONFIG *pSystemCfg;
+
+       pSharedInterface = (pENC_RPC_HOST_IFACE)Interface;
+       pSystemCfg = &pSharedInterface->sSystemCfg;
+       pSystemCfg->uNumWindsors = 1;
+       pSystemCfg->uWindsorIrqPin[0x0][0x0] = 0x4; // PAL_IRQ_WINDSOR_LOW
+       pSystemCfg->uWindsorIrqPin[0x0][0x1] = 0x5; // PAL_IRQ_WINDSOR_HI
+       pSystemCfg->uMaloneBaseAddress[0] = (unsigned int)(regs_base + 0x180000);
+       pSystemCfg->uWindsorBaseAddress[0] = (unsigned int)(regs_base + 0x800000);
+       pSystemCfg->uMaloneBaseAddress[0x1] = 0x0;
+       pSystemCfg->uHifOffset[0x0] = 0x1C000;
+       pSystemCfg->uHifOffset[0x1] = 0x0;
+
+       pSystemCfg->uDPVBaseAddr = 0x0;
+       pSystemCfg->uDPVIrqPin = 0x0;
+       pSystemCfg->uPixIfBaseAddr = (unsigned int)(regs_base + 0x180000 + 0x20000);
+       pSystemCfg->uFSLCacheBaseAddr = (unsigned int)(regs_base + 0x60000);
+}
+
+u_int32 rpc_MediaIPFW_Video_buffer_space_check_encoder(BUFFER_DESCRIPTOR_TYPE *pBufDesc,
+       BOOL bFull,
+       u_int32 uSize,
+       u_int32 *puUpdateAddress)
+{
+       u_int32 uPtr1;
+       u_int32 uPtr2;
+       u_int32 start;
+       u_int32 end;
+       u_int32 uTemp;
+
+       /* bFull is FALSE when send message, write data   */
+       /* bFull is TRUE when process commands, read data */
+       uPtr1 = (bFull) ? pBufDesc->rptr : pBufDesc->wptr;
+       uPtr2 = (bFull) ? pBufDesc->wptr : pBufDesc->rptr;
+
+       if (uPtr1 == uPtr2) {
+               if (bFull)
+                       /* No data at all to read */
+                       return 0;
+               else {
+                       /* wrt pointer equal to read pointer thus the     */
+                       /* buffer is completely empty for further writes  */
+                       start = pBufDesc->start;
+                       end   = pBufDesc->end;
+                       /* The address to be returned in this case is for */
+                       /* the updated write pointer.                     */
+                       uTemp = uPtr1 + uSize;
+                       if (uTemp >= end)
+                               uTemp += (start - end);
+                       *puUpdateAddress = uTemp;
+                       return (end - start);
+               }
+       } else if (uPtr1 < uPtr2) {
+               /* return updated rd pointer address                */
+               /* In this case if size was too big - we expect the */
+               /* external ftn to compare the size against the     */
+               /* space returned.
+                */
+               *puUpdateAddress = uPtr1 + uSize;
+               return (uPtr2 - uPtr1);
+       }
+       /* We know the system has looped!! */
+       start = pBufDesc->start;
+       end   = pBufDesc->end;
+       uTemp  = uPtr1 + uSize;
+       if (uTemp >= end)
+               uTemp += (start - end);
+       *puUpdateAddress = uTemp;
+       return ((end - uPtr1) + (uPtr2 - start));
+}
+
+static void rpc_update_cmd_buffer_ptr_encoder(BUFFER_DESCRIPTOR_TYPE *pCmdDesc)
+{
+       u_int32 uWritePtr;
+
+       uWritePtr = pCmdDesc->wptr + 4;
+       if (uWritePtr >= pCmdDesc->end)
+               uWritePtr = pCmdDesc->start;
+       pCmdDesc->wptr = uWritePtr;
+}
+
+void rpc_send_cmd_buf_encoder(struct shared_addr *This,
+               u_int32 idx,
+               u_int32 cmdid,
+               u_int32 cmdnum,
+               u_int32 *local_cmddata)
+{
+       pENC_RPC_HOST_IFACE pSharedInterface = (pENC_RPC_HOST_IFACE)This->shared_mem_vir;
+       BUFFER_DESCRIPTOR_TYPE *pCmdDesc = &pSharedInterface->StreamCmdBufferDesc;
+       u_int32 *cmddata;
+       u_int32 i;
+       u_int32 *cmdword = (u_int32 *)(This->cmd_mem_vir+pCmdDesc->wptr - pCmdDesc->start);
+
+       *cmdword |= ((idx & 0x000000ff) << 24);
+       *cmdword |= ((cmdnum & 0x000000ff) << 16);
+       *cmdword |= ((cmdid & 0x00003fff) << 0);
+       rpc_update_cmd_buffer_ptr_encoder(pCmdDesc);
+
+       for (i = 0; i < cmdnum; i++) {
+               cmddata = (u_int32 *)(This->cmd_mem_vir+pCmdDesc->wptr - pCmdDesc->start);
+               *cmddata = local_cmddata[i];
+               rpc_update_cmd_buffer_ptr_encoder(pCmdDesc);
+       }
+}
+
+u_int32 rpc_MediaIPFW_Video_message_check_encoder(struct shared_addr *This)
+{
+       u_int32 uSpace;
+       u_int32 uIgnore;
+       pENC_RPC_HOST_IFACE pSharedInterface = (pENC_RPC_HOST_IFACE)This->shared_mem_vir;
+       BUFFER_DESCRIPTOR_TYPE *pMsgDesc = &pSharedInterface->StreamMsgBufferDesc;
+       u_int32 msgword;
+       u_int32 msgnum;
+
+       uSpace = rpc_MediaIPFW_Video_buffer_space_check_encoder(pMsgDesc, TRUE, 0, &uIgnore);
+       uSpace = (uSpace >> 2);
+       if (uSpace) {
+               /* get current msgword word */
+               msgword      = *((u_int32 *)(This->msg_mem_vir+pMsgDesc->rptr - pMsgDesc->start));
+               /* Find the number of additional words */
+               msgnum  = ((msgword & 0x00ff0000) >> 16);
+
+               /*
+                * * Check the number of message words against
+                * * 1) a limit - some sort of maximum or at least
+                * * the size of the SW buffer the message is read into
+                * * 2) The space reported (where space is write ptr - read ptr in 32bit words)
+                * * It must be less than space (as opposed to <=) because
+                * * the message itself is not included in msgword
+                */
+               if (msgnum < VID_API_MESSAGE_LIMIT) {
+                       if (msgnum < uSpace)
+                               return API_MSG_AVAILABLE;
+                       else
+                               return API_MSG_INCOMPLETE;
+               } else
+                       return API_MSG_BUFFER_ERROR;
+       }
+       return API_MSG_UNAVAILABLE;
+}
+
+static void rpc_update_msg_buffer_ptr_encoder(BUFFER_DESCRIPTOR_TYPE *pMsgDesc)
+{
+       u_int32 uReadPtr;
+
+       uReadPtr = pMsgDesc->rptr + 4;
+       if (uReadPtr >= pMsgDesc->end)
+               uReadPtr = pMsgDesc->start;
+       pMsgDesc->rptr = uReadPtr;
+}
+
+void rpc_receive_msg_buf_encoder(struct shared_addr *This, struct event_msg *msg)
+{
+       unsigned int i;
+       pENC_RPC_HOST_IFACE pSharedInterface = (pENC_RPC_HOST_IFACE)This->shared_mem_vir;
+       BUFFER_DESCRIPTOR_TYPE *pMsgDesc = &pSharedInterface->StreamMsgBufferDesc;
+       u_int32 msgword = *((u_int32 *)(This->msg_mem_vir+pMsgDesc->rptr - pMsgDesc->start));
+
+       msg->idx = ((msgword & 0xff000000) >> 24);
+       msg->msgnum = ((msgword & 0x00ff0000) >> 16);
+       msg->msgid = ((msgword & 0x00003fff) >> 0);
+       rpc_update_msg_buffer_ptr_encoder(pMsgDesc);
+
+       for (i = 0; i < msg->msgnum; i++) {
+               msg->msgdata[i] = *((u_int32 *)(This->msg_mem_vir+pMsgDesc->rptr - pMsgDesc->start));
+               rpc_update_msg_buffer_ptr_encoder(pMsgDesc);
+       }
+}
diff --git a/drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.h b/drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.h
new file mode 100644 (file)
index 0000000..1056453
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __VPU_ENCODER_RPC_H__
+#define __VPU_ENCODER_RPC_H__
+
+#include "mediasys_types.h"
+
+#define CMD_SIZE 2560
+#define MSG_SIZE 25600
+#define CODEC_SIZE 0x1000
+#define JPEG_SIZE 0x1000
+#define SEQ_SIZE 0x1000
+#define GOP_SIZE 0x1000
+#define PIC_SIZE 0x1000
+#define QMETER_SIZE 0x1000
+#define DEBUG_SIZE 0x1000
+#define ENG_SIZE 0x1000
+#define LOCAL_MSG_NUM VID_API_MESSAGE_LIMIT
+
+struct shared_addr {
+       pENC_RPC_HOST_IFACE pSharedInterface;
+       unsigned long long shared_mem_phy;
+       void *shared_mem_vir;
+       unsigned long long cmd_mem_phy;
+       void *cmd_mem_vir;
+       unsigned long long msg_mem_phy;
+       void *msg_mem_vir;
+       unsigned long long codec_mem_phy;
+       void *codec_mem_vir;
+       unsigned long long jpeg_mem_phy;
+       void *jpeg_mem_vir;
+       unsigned long long seq_mem_phy;
+       void *seq_mem_vir;
+       unsigned long long pic_mem_phy;
+       void *pic_mem_vir;
+       unsigned long long gop_mem_phy;
+       void *gop_mem_vir;
+       unsigned long long qmeter_mem_phy;
+       void *qmeter_mem_vir;
+       unsigned long long base_offset;
+};
+
+struct event_msg {
+       u_int32 idx;
+       u_int32 msgnum;
+       u_int32 msgid;
+       u_int32 msgdata[LOCAL_MSG_NUM];
+};
+
+void rpc_init_shared_memory_encoder(struct shared_addr *This,
+               unsigned long long base_phy_addr,
+               void *base_virt_addr,
+               u_int32 total_size);
+void rpc_set_system_cfg_value_encoder(void *Interface, u_int32 regs_base);
+void rpc_send_cmd_buf_encoder(struct shared_addr *This,
+               u_int32 idx,
+               u_int32 cmdid,
+               u_int32 cmdnum,
+               u_int32 *local_cmddata);
+void rpc_receive_msg_buf_encoder(struct shared_addr *This, struct event_msg *msg);
+
+#endif