summaryrefslogtreecommitdiff
path: root/drivers/mxc
diff options
context:
space:
mode:
authornxa13443 <chaofan.huang@nxp.com>2018-03-23 20:20:37 +0800
committerJason Liu <jason.hui.liu@nxp.com>2019-02-12 10:31:04 +0800
commit0495089d39ed6810dd27b8ae2d0041604d69022e (patch)
tree4e201b395dfd607507a816613dbb103ec7c817ed /drivers/mxc
parent25b185abac34d8efb65a0a1bdce175a92c2e64a7 (diff)
MLK-17902 [IMX8QXP B0]VPU ENCODER and DECODER on IMX8QXP B0 board
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>
Diffstat (limited to 'drivers/mxc')
-rwxr-xr-xdrivers/mxc/Kconfig2
-rwxr-xr-xdrivers/mxc/Makefile2
-rwxr-xr-xdrivers/mxc/vpu-decoder-b0/Kconfig20
-rw-r--r--drivers/mxc/vpu-decoder-b0/Makefile15
-rw-r--r--drivers/mxc/vpu-decoder-b0/mediasys_types.h767
-rwxr-xr-xdrivers/mxc/vpu-decoder-b0/vpu_b0.c2636
-rw-r--r--drivers/mxc/vpu-decoder-b0/vpu_b0.h257
-rw-r--r--drivers/mxc/vpu-decoder-b0/vpu_rpc.c352
-rw-r--r--drivers/mxc/vpu-decoder-b0/vpu_rpc.h114
-rwxr-xr-xdrivers/mxc/vpu-encoder-b0/Kconfig20
-rw-r--r--drivers/mxc/vpu-encoder-b0/Makefile12
-rw-r--r--drivers/mxc/vpu-encoder-b0/mediasys_types.h701
-rw-r--r--drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.c2076
-rw-r--r--drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.h243
-rw-r--r--drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.c298
-rw-r--r--drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.h114
16 files changed, 7629 insertions, 0 deletions
diff --git a/drivers/mxc/Kconfig b/drivers/mxc/Kconfig
index fa91a1d583ef..4c7e87c99cac 100755
--- a/drivers/mxc/Kconfig
+++ b/drivers/mxc/Kconfig
@@ -19,6 +19,8 @@ source "drivers/mxc/sim/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
diff --git a/drivers/mxc/Makefile b/drivers/mxc/Makefile
index 632f46541759..f564c472a688 100755
--- a/drivers/mxc/Makefile
+++ b/drivers/mxc/Makefile
@@ -7,3 +7,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
index 000000000000..094d6566a421
--- /dev/null
+++ b/drivers/mxc/vpu-decoder-b0/Kconfig
@@ -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
index 000000000000..af74ce4d31c9
--- /dev/null
+++ b/drivers/mxc/vpu-decoder-b0/Makefile
@@ -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
index 000000000000..26f8fb72cca4
--- /dev/null
+++ b/drivers/mxc/vpu-decoder-b0/mediasys_types.h
@@ -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
index 000000000000..e1a235627908
--- /dev/null
+++ b/drivers/mxc/vpu-decoder-b0/vpu_b0.c
@@ -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
index 000000000000..371668b147f4
--- /dev/null
+++ b/drivers/mxc/vpu-decoder-b0/vpu_b0.h
@@ -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
index 000000000000..232f481ef4c2
--- /dev/null
+++ b/drivers/mxc/vpu-decoder-b0/vpu_rpc.c
@@ -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
index 000000000000..b777e5852e7c
--- /dev/null
+++ b/drivers/mxc/vpu-decoder-b0/vpu_rpc.h
@@ -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
index 000000000000..40b1fcecd86f
--- /dev/null
+++ b/drivers/mxc/vpu-encoder-b0/Kconfig
@@ -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
index 000000000000..b8a8fc117d93
--- /dev/null
+++ b/drivers/mxc/vpu-encoder-b0/Makefile
@@ -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
index 000000000000..caa05cb6aa59
--- /dev/null
+++ b/drivers/mxc/vpu-encoder-b0/mediasys_types.h
@@ -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
index 000000000000..7ff1aed6f616
--- /dev/null
+++ b/drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.c
@@ -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
index 000000000000..532beb423c9b
--- /dev/null
+++ b/drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.h
@@ -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
index 000000000000..17e6adb54078
--- /dev/null
+++ b/drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.c
@@ -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
index 000000000000..1056453436be
--- /dev/null
+++ b/drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.h
@@ -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