};
};
};
+&vpu_decoder {
+ status = "okay";
+ };
+
+&vpu_encoder {
+ status = "okay";
+};
no-map;
reg = <0 0x8e000000 0 0x1ffffff>;
};
-
+ decoder_boot: decoder_boot@0x88000000 {
+ no-map;
+ reg = <0 0x88000000 0 0x2000000>;
+ };
+ encoder_boot: encoder_boot@0x8A000000 {
+ no-map;
+ reg = <0 0x8A000000 0 0x2000000>;
+ };
/* global autoconfigured region for contiguous allocations */
linux,cma {
compatible = "shared-dma-pool";
alloc-ranges = <0 0x90000000 0 0x28000000>;
linux,cma-default;
};
-
rpmsg_reserved: rpmsg@0xb8000000 {
no-map;
reg = <0 0xb8000000 0 0x400000>;
};
+ decoder_rpc: decoder_rpc@0xB9000000 {
+ no-map;
+ reg = <0 0xB9000000 0 0x1000000>;
+ };
+ encoder_rpc: encoder_rpc@0xBA000000 {
+ no-map;
+ reg = <0 0xBA000000 0 0x1000000>;
+ };
};
gic: interrupt-controller@51a00000 {
fsl,hifi_ap_mu_id = <13>;
status = "okay";
};
+ mu_m4: mu_m4@37440000 {
+ compatible = "fsl,imx8-mu0-vpu-m4";
+ reg = <0x0 0x37440000 0x0 0x10000>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+ fsl,vpu_ap_mu_id = <15>;
+ status = "okay";
+ };
+ mu_m0: mu_m0@2d000000 {
+ compatible = "fsl,imx8-mu0-vpu-m0";
+ reg = <0x0 0x2d000000 0x0 0x10000>;
+ interrupts = <GIC_SPI 469 IRQ_TYPE_LEVEL_HIGH>;
+ fsl,vpu_ap_mu_id = <16>;
+ status = "okay";
+ };
+
+ mu1_m0: mu1_m0@2d020000 {
+ compatible = "fsl,imx8-mu1-vpu-m0";
+ reg = <0x0 0x2d020000 0x0 0x10000>;
+ interrupts = <GIC_SPI 470 IRQ_TYPE_LEVEL_HIGH>;
+ fsl,vpu_ap_mu_id = <17>;
+ status = "okay";
+ };
clk: clk {
compatible = "fsl,imx8qxp-clk";
#clock-cells = <1>;
status = "disabled";
};
+ vpu_decoder: vpu_decoder@2c000000 {
+ compatible = "nxp,imx8qm-vpu-decoder", "nxp,imx8qxp-vpu-decoder";
+ boot-region = <&decoder_boot>;
+ rpc-region = <&decoder_rpc>;
+ reg = <0x0 0x2c000000 0x0 0x1000000>;
+ reg-names = "vpu_regs";
+ clocks = <&clk IMX8QXP_VPU_DEC_CLK>;
+ clock-names = "vpu_clk";
+ assigned-clocks = <&clk IMX8QXP_VPU_DEC_CLK>;
+ assigned-clock-rates = <600000000>;
+ power-domains = <&pd_vpu_dec>;
+ status = "disabled";
+ };
+
+ vpu_encoder: vpu_encoder@2d000000 {
+ compatible = "nxp,imx8qm-vpu-encoder", "nxp,imx8qxp-vpu-encoder";
+ boot-region = <&encoder_boot>;
+ rpc-region = <&encoder_rpc>;
+ reg = <0x0 0x2d000000 0x0 0x1000000>;
+ reg-names = "vpu_regs";
+ clocks = <&clk IMX8QXP_VPU_ENC_CLK>;
+ clock-names = "vpu_encoder_clk";
+ assigned-clocks = <&clk IMX8QXP_VPU_ENC_CLK>;
+ assigned-clock-rates = <600000000>;
+ power-domains = <&pd_vpu_enc>;
+ status = "disabled";
+ };
imx_rpmsg: imx_rpmsg {
compatible = "fsl,rpmsg-bus", "simple-bus";
#address-cells = <2>;
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
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/
--- /dev/null
+#
+# 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
--- /dev/null
+##
+## 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)
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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)");
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+#
+# 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
--- /dev/null
+##
+## 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)
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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)");
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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