Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] vcodec: mediatek: Add Mediatek V4L2 Video Encoder Driver

Add v4l2 layer encoder driver for MT8173

Signed-off-by: Tiffany Lin <tiffany.lin@mediatek.com>
[hans.verkuil@cisco.com: drop unnecessary ARM || ARM64 dependency]
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>

Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>

authored by

Tiffany Lin and committed by
Mauro Carvalho Chehab
4e855a6e e6d28fd6

+3137
+17
drivers/media/platform/Kconfig
··· 166 166 To compile this driver as a module, choose M here: the 167 167 module will be called mtk-vpu. 168 168 169 + config VIDEO_MEDIATEK_VCODEC 170 + tristate "Mediatek Video Codec driver" 171 + depends on MTK_IOMMU 172 + depends on VIDEO_DEV && VIDEO_V4L2 173 + depends on ARCH_MEDIATEK || COMPILE_TEST 174 + select VIDEOBUF2_DMA_CONTIG 175 + select V4L2_MEM2MEM_DEV 176 + select VIDEO_MEDIATEK_VPU 177 + default n 178 + ---help--- 179 + Mediatek video codec driver provides HW capability to 180 + encode and decode in a range of video formats 181 + This driver rely on VPU driver to communicate with VPU. 182 + 183 + To compile this driver as a module, choose M here: the 184 + module will be called mtk-vcodec 185 + 169 186 config VIDEO_MEM2MEM_DEINTERLACE 170 187 tristate "Deinterlace support" 171 188 depends on VIDEO_DEV && VIDEO_V4L2 && DMA_ENGINE
+2
drivers/media/platform/Makefile
··· 60 60 ccflags-y += -I$(srctree)/drivers/media/i2c 61 61 62 62 obj-$(CONFIG_VIDEO_MEDIATEK_VPU) += mtk-vpu/ 63 + 64 + obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec/
+14
drivers/media/platform/mtk-vcodec/Makefile
··· 1 + 2 + obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-enc.o mtk-vcodec-common.o 3 + 4 + 5 + 6 + mtk-vcodec-enc-y := mtk_vcodec_enc.o \ 7 + mtk_vcodec_enc_drv.o \ 8 + mtk_vcodec_enc_pm.o \ 9 + venc_drv_if.o \ 10 + 11 + mtk-vcodec-common-y := mtk_vcodec_intr.o \ 12 + mtk_vcodec_util.o\ 13 + 14 + ccflags-y += -I$(srctree)/drivers/media/platform/mtk-vpu
+338
drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
··· 1 + /* 2 + * Copyright (c) 2016 MediaTek Inc. 3 + * Author: PC Chen <pc.chen@mediatek.com> 4 + * Tiffany Lin <tiffany.lin@mediatek.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + */ 15 + 16 + #ifndef _MTK_VCODEC_DRV_H_ 17 + #define _MTK_VCODEC_DRV_H_ 18 + 19 + #include <linux/platform_device.h> 20 + #include <linux/videodev2.h> 21 + #include <media/v4l2-ctrls.h> 22 + #include <media/v4l2-device.h> 23 + #include <media/v4l2-ioctl.h> 24 + #include <media/videobuf2-core.h> 25 + 26 + #include "mtk_vcodec_util.h" 27 + 28 + #define MTK_VCODEC_DRV_NAME "mtk_vcodec_drv" 29 + #define MTK_VCODEC_ENC_NAME "mtk-vcodec-enc" 30 + #define MTK_PLATFORM_STR "platform:mt8173" 31 + 32 + 33 + #define MTK_VCODEC_MAX_PLANES 3 34 + #define MTK_V4L2_BENCHMARK 0 35 + #define WAIT_INTR_TIMEOUT_MS 1000 36 + 37 + /** 38 + * enum mtk_hw_reg_idx - MTK hw register base index 39 + */ 40 + enum mtk_hw_reg_idx { 41 + VDEC_SYS, 42 + VDEC_MISC, 43 + VDEC_LD, 44 + VDEC_TOP, 45 + VDEC_CM, 46 + VDEC_AD, 47 + VDEC_AV, 48 + VDEC_PP, 49 + VDEC_HWD, 50 + VDEC_HWQ, 51 + VDEC_HWB, 52 + VDEC_HWG, 53 + NUM_MAX_VDEC_REG_BASE, 54 + /* h264 encoder */ 55 + VENC_SYS = NUM_MAX_VDEC_REG_BASE, 56 + /* vp8 encoder */ 57 + VENC_LT_SYS, 58 + NUM_MAX_VCODEC_REG_BASE 59 + }; 60 + 61 + /** 62 + * enum mtk_instance_type - The type of an MTK Vcodec instance. 63 + */ 64 + enum mtk_instance_type { 65 + MTK_INST_DECODER = 0, 66 + MTK_INST_ENCODER = 1, 67 + }; 68 + 69 + /** 70 + * enum mtk_instance_state - The state of an MTK Vcodec instance. 71 + * @MTK_STATE_FREE - default state when instance is created 72 + * @MTK_STATE_INIT - vcodec instance is initialized 73 + * @MTK_STATE_HEADER - vdec had sps/pps header parsed or venc 74 + * had sps/pps header encoded 75 + * @MTK_STATE_FLUSH - vdec is flushing. Only used by decoder 76 + * @MTK_STATE_ABORT - vcodec should be aborted 77 + */ 78 + enum mtk_instance_state { 79 + MTK_STATE_FREE = 0, 80 + MTK_STATE_INIT = 1, 81 + MTK_STATE_HEADER = 2, 82 + MTK_STATE_FLUSH = 3, 83 + MTK_STATE_ABORT = 4, 84 + }; 85 + 86 + /** 87 + * struct mtk_encode_param - General encoding parameters type 88 + */ 89 + enum mtk_encode_param { 90 + MTK_ENCODE_PARAM_NONE = 0, 91 + MTK_ENCODE_PARAM_BITRATE = (1 << 0), 92 + MTK_ENCODE_PARAM_FRAMERATE = (1 << 1), 93 + MTK_ENCODE_PARAM_INTRA_PERIOD = (1 << 2), 94 + MTK_ENCODE_PARAM_FORCE_INTRA = (1 << 3), 95 + MTK_ENCODE_PARAM_GOP_SIZE = (1 << 4), 96 + }; 97 + 98 + enum mtk_fmt_type { 99 + MTK_FMT_DEC = 0, 100 + MTK_FMT_ENC = 1, 101 + MTK_FMT_FRAME = 2, 102 + }; 103 + 104 + /** 105 + * struct mtk_video_fmt - Structure used to store information about pixelformats 106 + */ 107 + struct mtk_video_fmt { 108 + u32 fourcc; 109 + enum mtk_fmt_type type; 110 + u32 num_planes; 111 + }; 112 + 113 + /** 114 + * struct mtk_codec_framesizes - Structure used to store information about 115 + * framesizes 116 + */ 117 + struct mtk_codec_framesizes { 118 + u32 fourcc; 119 + struct v4l2_frmsize_stepwise stepwise; 120 + }; 121 + 122 + /** 123 + * struct mtk_q_type - Type of queue 124 + */ 125 + enum mtk_q_type { 126 + MTK_Q_DATA_SRC = 0, 127 + MTK_Q_DATA_DST = 1, 128 + }; 129 + 130 + /** 131 + * struct mtk_q_data - Structure used to store information about queue 132 + */ 133 + struct mtk_q_data { 134 + unsigned int visible_width; 135 + unsigned int visible_height; 136 + unsigned int coded_width; 137 + unsigned int coded_height; 138 + enum v4l2_field field; 139 + unsigned int bytesperline[MTK_VCODEC_MAX_PLANES]; 140 + unsigned int sizeimage[MTK_VCODEC_MAX_PLANES]; 141 + struct mtk_video_fmt *fmt; 142 + }; 143 + 144 + /** 145 + * struct mtk_enc_params - General encoding parameters 146 + * @bitrate: target bitrate in bits per second 147 + * @num_b_frame: number of b frames between p-frame 148 + * @rc_frame: frame based rate control 149 + * @rc_mb: macroblock based rate control 150 + * @seq_hdr_mode: H.264 sequence header is encoded separately or joined 151 + * with the first frame 152 + * @intra_period: I frame period 153 + * @gop_size: group of picture size, it's used as the intra frame period 154 + * @framerate_num: frame rate numerator. ex: framerate_num=30 and 155 + * framerate_denom=1 menas FPS is 30 156 + * @framerate_denom: frame rate denominator. ex: framerate_num=30 and 157 + * framerate_denom=1 menas FPS is 30 158 + * @h264_max_qp: Max value for H.264 quantization parameter 159 + * @h264_profile: V4L2 defined H.264 profile 160 + * @h264_level: V4L2 defined H.264 level 161 + * @force_intra: force/insert intra frame 162 + */ 163 + struct mtk_enc_params { 164 + unsigned int bitrate; 165 + unsigned int num_b_frame; 166 + unsigned int rc_frame; 167 + unsigned int rc_mb; 168 + unsigned int seq_hdr_mode; 169 + unsigned int intra_period; 170 + unsigned int gop_size; 171 + unsigned int framerate_num; 172 + unsigned int framerate_denom; 173 + unsigned int h264_max_qp; 174 + unsigned int h264_profile; 175 + unsigned int h264_level; 176 + unsigned int force_intra; 177 + }; 178 + 179 + /** 180 + * struct mtk_vcodec_pm - Power management data structure 181 + */ 182 + struct mtk_vcodec_pm { 183 + struct clk *vcodecpll; 184 + struct clk *univpll_d2; 185 + struct clk *clk_cci400_sel; 186 + struct clk *vdecpll; 187 + struct clk *vdec_sel; 188 + struct clk *vencpll_d2; 189 + struct clk *venc_sel; 190 + struct clk *univpll1_d2; 191 + struct clk *venc_lt_sel; 192 + struct device *larbvdec; 193 + struct device *larbvenc; 194 + struct device *larbvenclt; 195 + struct device *dev; 196 + struct mtk_vcodec_dev *mtkdev; 197 + }; 198 + 199 + /** 200 + * struct mtk_vcodec_ctx - Context (instance) private data. 201 + * 202 + * @type: type of the instance - decoder or encoder 203 + * @dev: pointer to the mtk_vcodec_dev of the device 204 + * @list: link to ctx_list of mtk_vcodec_dev 205 + * @fh: struct v4l2_fh 206 + * @m2m_ctx: pointer to the v4l2_m2m_ctx of the context 207 + * @q_data: store information of input and output queue 208 + * of the context 209 + * @id: index of the context that this structure describes 210 + * @state: state of the context 211 + * @param_change: indicate encode parameter type 212 + * @enc_params: encoding parameters 213 + * @enc_if: hoooked encoder driver interface 214 + * @drv_handle: driver handle for specific decode/encode instance 215 + * 216 + * @int_cond: variable used by the waitqueue 217 + * @int_type: type of the last interrupt 218 + * @queue: waitqueue that can be used to wait for this context to 219 + * finish 220 + * @irq_status: irq status 221 + * 222 + * @ctrl_hdl: handler for v4l2 framework 223 + * @encode_work: worker for the encoding 224 + * 225 + * @colorspace: enum v4l2_colorspace; supplemental to pixelformat 226 + * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding 227 + * @quantization: enum v4l2_quantization, colorspace quantization 228 + * @xfer_func: enum v4l2_xfer_func, colorspace transfer function 229 + */ 230 + struct mtk_vcodec_ctx { 231 + enum mtk_instance_type type; 232 + struct mtk_vcodec_dev *dev; 233 + struct list_head list; 234 + 235 + struct v4l2_fh fh; 236 + struct v4l2_m2m_ctx *m2m_ctx; 237 + struct mtk_q_data q_data[2]; 238 + int id; 239 + enum mtk_instance_state state; 240 + enum mtk_encode_param param_change; 241 + struct mtk_enc_params enc_params; 242 + 243 + struct venc_common_if *enc_if; 244 + unsigned long drv_handle; 245 + 246 + int int_cond; 247 + int int_type; 248 + wait_queue_head_t queue; 249 + unsigned int irq_status; 250 + 251 + struct v4l2_ctrl_handler ctrl_hdl; 252 + struct work_struct encode_work; 253 + 254 + enum v4l2_colorspace colorspace; 255 + enum v4l2_ycbcr_encoding ycbcr_enc; 256 + enum v4l2_quantization quantization; 257 + enum v4l2_xfer_func xfer_func; 258 + }; 259 + 260 + /** 261 + * struct mtk_vcodec_dev - driver data 262 + * @v4l2_dev: V4L2 device to register video devices for. 263 + * @vfd_enc: Video device for encoder. 264 + * 265 + * @m2m_dev_enc: m2m device for encoder. 266 + * @plat_dev: platform device 267 + * @vpu_plat_dev: mtk vpu platform device 268 + * @alloc_ctx: VB2 allocator context 269 + * (for allocations without kernel mapping). 270 + * @ctx_list: list of struct mtk_vcodec_ctx 271 + * @irqlock: protect data access by irq handler and work thread 272 + * @curr_ctx: The context that is waiting for codec hardware 273 + * 274 + * @reg_base: Mapped address of MTK Vcodec registers. 275 + * 276 + * @id_counter: used to identify current opened instance 277 + * @num_instances: counter of active MTK Vcodec instances 278 + * 279 + * @encode_workqueue: encode work queue 280 + * 281 + * @int_cond: used to identify interrupt condition happen 282 + * @int_type: used to identify what kind of interrupt condition happen 283 + * @dev_mutex: video_device lock 284 + * @queue: waitqueue for waiting for completion of device commands 285 + * 286 + * @enc_irq: h264 encoder irq resource 287 + * @enc_lt_irq: vp8 encoder irq resource 288 + * 289 + * @enc_mutex: encoder hardware lock. 290 + * 291 + * @pm: power management control 292 + * @dec_capability: used to identify decode capability, ex: 4k 293 + * @enc_capability: used to identify encode capability 294 + */ 295 + struct mtk_vcodec_dev { 296 + struct v4l2_device v4l2_dev; 297 + struct video_device *vfd_enc; 298 + 299 + struct v4l2_m2m_dev *m2m_dev_enc; 300 + struct platform_device *plat_dev; 301 + struct platform_device *vpu_plat_dev; 302 + struct vb2_alloc_ctx *alloc_ctx; 303 + struct list_head ctx_list; 304 + spinlock_t irqlock; 305 + struct mtk_vcodec_ctx *curr_ctx; 306 + void __iomem *reg_base[NUM_MAX_VCODEC_REG_BASE]; 307 + 308 + unsigned long id_counter; 309 + int num_instances; 310 + 311 + struct workqueue_struct *encode_workqueue; 312 + 313 + int int_cond; 314 + int int_type; 315 + struct mutex dev_mutex; 316 + wait_queue_head_t queue; 317 + 318 + int enc_irq; 319 + int enc_lt_irq; 320 + 321 + struct mutex enc_mutex; 322 + 323 + struct mtk_vcodec_pm pm; 324 + unsigned int dec_capability; 325 + unsigned int enc_capability; 326 + }; 327 + 328 + static inline struct mtk_vcodec_ctx *fh_to_ctx(struct v4l2_fh *fh) 329 + { 330 + return container_of(fh, struct mtk_vcodec_ctx, fh); 331 + } 332 + 333 + static inline struct mtk_vcodec_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl) 334 + { 335 + return container_of(ctrl->handler, struct mtk_vcodec_ctx, ctrl_hdl); 336 + } 337 + 338 + #endif /* _MTK_VCODEC_DRV_H_ */
+1288
drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
··· 1 + /* 2 + * Copyright (c) 2016 MediaTek Inc. 3 + * Author: PC Chen <pc.chen@mediatek.com> 4 + * Tiffany Lin <tiffany.lin@mediatek.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + */ 15 + 16 + #include <media/v4l2-event.h> 17 + #include <media/v4l2-mem2mem.h> 18 + #include <media/videobuf2-dma-contig.h> 19 + #include <soc/mediatek/smi.h> 20 + 21 + #include "mtk_vcodec_drv.h" 22 + #include "mtk_vcodec_enc.h" 23 + #include "mtk_vcodec_intr.h" 24 + #include "mtk_vcodec_util.h" 25 + #include "venc_drv_if.h" 26 + 27 + #define MTK_VENC_MIN_W 160U 28 + #define MTK_VENC_MIN_H 128U 29 + #define MTK_VENC_MAX_W 1920U 30 + #define MTK_VENC_MAX_H 1088U 31 + #define DFT_CFG_WIDTH MTK_VENC_MIN_W 32 + #define DFT_CFG_HEIGHT MTK_VENC_MIN_H 33 + #define MTK_MAX_CTRLS_HINT 20 34 + #define OUT_FMT_IDX 0 35 + #define CAP_FMT_IDX 4 36 + 37 + 38 + static void mtk_venc_worker(struct work_struct *work); 39 + 40 + static struct mtk_video_fmt mtk_video_formats[] = { 41 + { 42 + .fourcc = V4L2_PIX_FMT_NV12M, 43 + .type = MTK_FMT_FRAME, 44 + .num_planes = 2, 45 + }, 46 + { 47 + .fourcc = V4L2_PIX_FMT_NV21M, 48 + .type = MTK_FMT_FRAME, 49 + .num_planes = 2, 50 + }, 51 + { 52 + .fourcc = V4L2_PIX_FMT_YUV420M, 53 + .type = MTK_FMT_FRAME, 54 + .num_planes = 3, 55 + }, 56 + { 57 + .fourcc = V4L2_PIX_FMT_YVU420M, 58 + .type = MTK_FMT_FRAME, 59 + .num_planes = 3, 60 + }, 61 + { 62 + .fourcc = V4L2_PIX_FMT_H264, 63 + .type = MTK_FMT_ENC, 64 + .num_planes = 1, 65 + }, 66 + { 67 + .fourcc = V4L2_PIX_FMT_VP8, 68 + .type = MTK_FMT_ENC, 69 + .num_planes = 1, 70 + }, 71 + }; 72 + 73 + #define NUM_FORMATS ARRAY_SIZE(mtk_video_formats) 74 + 75 + static const struct mtk_codec_framesizes mtk_venc_framesizes[] = { 76 + { 77 + .fourcc = V4L2_PIX_FMT_H264, 78 + .stepwise = { MTK_VENC_MIN_W, MTK_VENC_MAX_W, 16, 79 + MTK_VENC_MIN_H, MTK_VENC_MAX_H, 16 }, 80 + }, 81 + { 82 + .fourcc = V4L2_PIX_FMT_VP8, 83 + .stepwise = { MTK_VENC_MIN_W, MTK_VENC_MAX_W, 16, 84 + MTK_VENC_MIN_H, MTK_VENC_MAX_H, 16 }, 85 + }, 86 + }; 87 + 88 + #define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_venc_framesizes) 89 + 90 + static int vidioc_venc_s_ctrl(struct v4l2_ctrl *ctrl) 91 + { 92 + struct mtk_vcodec_ctx *ctx = ctrl_to_ctx(ctrl); 93 + struct mtk_enc_params *p = &ctx->enc_params; 94 + int ret = 0; 95 + 96 + switch (ctrl->id) { 97 + case V4L2_CID_MPEG_VIDEO_BITRATE: 98 + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_BITRATE val = %d", 99 + ctrl->val); 100 + p->bitrate = ctrl->val; 101 + ctx->param_change |= MTK_ENCODE_PARAM_BITRATE; 102 + break; 103 + case V4L2_CID_MPEG_VIDEO_B_FRAMES: 104 + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_B_FRAMES val = %d", 105 + ctrl->val); 106 + p->num_b_frame = ctrl->val; 107 + break; 108 + case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: 109 + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE val = %d", 110 + ctrl->val); 111 + p->rc_frame = ctrl->val; 112 + break; 113 + case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: 114 + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_H264_MAX_QP val = %d", 115 + ctrl->val); 116 + p->h264_max_qp = ctrl->val; 117 + break; 118 + case V4L2_CID_MPEG_VIDEO_HEADER_MODE: 119 + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_HEADER_MODE val = %d", 120 + ctrl->val); 121 + p->seq_hdr_mode = ctrl->val; 122 + break; 123 + case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: 124 + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE val = %d", 125 + ctrl->val); 126 + p->rc_mb = ctrl->val; 127 + break; 128 + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: 129 + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_H264_PROFILE val = %d", 130 + ctrl->val); 131 + p->h264_profile = ctrl->val; 132 + break; 133 + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: 134 + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_H264_LEVEL val = %d", 135 + ctrl->val); 136 + p->h264_level = ctrl->val; 137 + break; 138 + case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: 139 + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_H264_I_PERIOD val = %d", 140 + ctrl->val); 141 + p->intra_period = ctrl->val; 142 + ctx->param_change |= MTK_ENCODE_PARAM_INTRA_PERIOD; 143 + break; 144 + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: 145 + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_GOP_SIZE val = %d", 146 + ctrl->val); 147 + p->gop_size = ctrl->val; 148 + ctx->param_change |= MTK_ENCODE_PARAM_GOP_SIZE; 149 + break; 150 + case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: 151 + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME"); 152 + p->force_intra = 1; 153 + ctx->param_change |= MTK_ENCODE_PARAM_FORCE_INTRA; 154 + break; 155 + default: 156 + ret = -EINVAL; 157 + break; 158 + } 159 + 160 + return ret; 161 + } 162 + 163 + static const struct v4l2_ctrl_ops mtk_vcodec_enc_ctrl_ops = { 164 + .s_ctrl = vidioc_venc_s_ctrl, 165 + }; 166 + 167 + static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) 168 + { 169 + struct mtk_video_fmt *fmt; 170 + int i, j = 0; 171 + 172 + for (i = 0; i < NUM_FORMATS; ++i) { 173 + if (output_queue && mtk_video_formats[i].type != MTK_FMT_FRAME) 174 + continue; 175 + if (!output_queue && mtk_video_formats[i].type != MTK_FMT_ENC) 176 + continue; 177 + 178 + if (j == f->index) { 179 + fmt = &mtk_video_formats[i]; 180 + f->pixelformat = fmt->fourcc; 181 + memset(f->reserved, 0, sizeof(f->reserved)); 182 + return 0; 183 + } 184 + ++j; 185 + } 186 + 187 + return -EINVAL; 188 + } 189 + 190 + static int vidioc_enum_framesizes(struct file *file, void *fh, 191 + struct v4l2_frmsizeenum *fsize) 192 + { 193 + int i = 0; 194 + 195 + if (fsize->index != 0) 196 + return -EINVAL; 197 + 198 + for (i = 0; i < NUM_SUPPORTED_FRAMESIZE; ++i) { 199 + if (fsize->pixel_format != mtk_venc_framesizes[i].fourcc) 200 + continue; 201 + 202 + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; 203 + fsize->stepwise = mtk_venc_framesizes[i].stepwise; 204 + return 0; 205 + } 206 + 207 + return -EINVAL; 208 + } 209 + 210 + static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv, 211 + struct v4l2_fmtdesc *f) 212 + { 213 + return vidioc_enum_fmt(f, false); 214 + } 215 + 216 + static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov, 217 + struct v4l2_fmtdesc *f) 218 + { 219 + return vidioc_enum_fmt(f, true); 220 + } 221 + 222 + static int vidioc_venc_querycap(struct file *file, void *priv, 223 + struct v4l2_capability *cap) 224 + { 225 + strlcpy(cap->driver, MTK_VCODEC_ENC_NAME, sizeof(cap->driver)); 226 + strlcpy(cap->bus_info, MTK_PLATFORM_STR, sizeof(cap->bus_info)); 227 + strlcpy(cap->card, MTK_PLATFORM_STR, sizeof(cap->card)); 228 + 229 + return 0; 230 + } 231 + 232 + static int vidioc_venc_s_parm(struct file *file, void *priv, 233 + struct v4l2_streamparm *a) 234 + { 235 + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); 236 + 237 + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 238 + return -EINVAL; 239 + 240 + ctx->enc_params.framerate_num = 241 + a->parm.output.timeperframe.denominator; 242 + ctx->enc_params.framerate_denom = 243 + a->parm.output.timeperframe.numerator; 244 + ctx->param_change |= MTK_ENCODE_PARAM_FRAMERATE; 245 + 246 + return 0; 247 + } 248 + 249 + static int vidioc_venc_g_parm(struct file *file, void *priv, 250 + struct v4l2_streamparm *a) 251 + { 252 + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); 253 + 254 + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 255 + return -EINVAL; 256 + 257 + a->parm.output.timeperframe.denominator = 258 + ctx->enc_params.framerate_num; 259 + a->parm.output.timeperframe.numerator = 260 + ctx->enc_params.framerate_denom; 261 + 262 + return 0; 263 + } 264 + 265 + static struct mtk_q_data *mtk_venc_get_q_data(struct mtk_vcodec_ctx *ctx, 266 + enum v4l2_buf_type type) 267 + { 268 + if (V4L2_TYPE_IS_OUTPUT(type)) 269 + return &ctx->q_data[MTK_Q_DATA_SRC]; 270 + 271 + return &ctx->q_data[MTK_Q_DATA_DST]; 272 + } 273 + 274 + static struct mtk_video_fmt *mtk_venc_find_format(struct v4l2_format *f) 275 + { 276 + struct mtk_video_fmt *fmt; 277 + unsigned int k; 278 + 279 + for (k = 0; k < NUM_FORMATS; k++) { 280 + fmt = &mtk_video_formats[k]; 281 + if (fmt->fourcc == f->fmt.pix.pixelformat) 282 + return fmt; 283 + } 284 + 285 + return NULL; 286 + } 287 + 288 + /* V4L2 specification suggests the driver corrects the format struct if any of 289 + * the dimensions is unsupported 290 + */ 291 + static int vidioc_try_fmt(struct v4l2_format *f, struct mtk_video_fmt *fmt) 292 + { 293 + struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; 294 + int i; 295 + 296 + pix_fmt_mp->field = V4L2_FIELD_NONE; 297 + 298 + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { 299 + pix_fmt_mp->num_planes = 1; 300 + pix_fmt_mp->plane_fmt[0].bytesperline = 0; 301 + } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { 302 + int tmp_w, tmp_h; 303 + 304 + pix_fmt_mp->height = clamp(pix_fmt_mp->height, 305 + MTK_VENC_MIN_H, 306 + MTK_VENC_MAX_H); 307 + pix_fmt_mp->width = clamp(pix_fmt_mp->width, 308 + MTK_VENC_MIN_W, 309 + MTK_VENC_MAX_W); 310 + 311 + /* find next closer width align 16, heign align 32, size align 312 + * 64 rectangle 313 + */ 314 + tmp_w = pix_fmt_mp->width; 315 + tmp_h = pix_fmt_mp->height; 316 + v4l_bound_align_image(&pix_fmt_mp->width, 317 + MTK_VENC_MIN_W, 318 + MTK_VENC_MAX_W, 4, 319 + &pix_fmt_mp->height, 320 + MTK_VENC_MIN_H, 321 + MTK_VENC_MAX_H, 5, 6); 322 + 323 + if (pix_fmt_mp->width < tmp_w && 324 + (pix_fmt_mp->width + 16) <= MTK_VENC_MAX_W) 325 + pix_fmt_mp->width += 16; 326 + if (pix_fmt_mp->height < tmp_h && 327 + (pix_fmt_mp->height + 32) <= MTK_VENC_MAX_H) 328 + pix_fmt_mp->height += 32; 329 + 330 + mtk_v4l2_debug(0, 331 + "before resize width=%d, height=%d, after resize width=%d, height=%d, sizeimage=%d", 332 + tmp_w, tmp_h, pix_fmt_mp->width, 333 + pix_fmt_mp->height, 334 + pix_fmt_mp->width * pix_fmt_mp->height); 335 + 336 + pix_fmt_mp->num_planes = fmt->num_planes; 337 + pix_fmt_mp->plane_fmt[0].sizeimage = 338 + pix_fmt_mp->width * pix_fmt_mp->height + 339 + ((ALIGN(pix_fmt_mp->width, 16) * 2) * 16); 340 + pix_fmt_mp->plane_fmt[0].bytesperline = pix_fmt_mp->width; 341 + 342 + if (pix_fmt_mp->num_planes == 2) { 343 + pix_fmt_mp->plane_fmt[1].sizeimage = 344 + (pix_fmt_mp->width * pix_fmt_mp->height) / 2 + 345 + (ALIGN(pix_fmt_mp->width, 16) * 16); 346 + pix_fmt_mp->plane_fmt[2].sizeimage = 0; 347 + pix_fmt_mp->plane_fmt[1].bytesperline = 348 + pix_fmt_mp->width; 349 + pix_fmt_mp->plane_fmt[2].bytesperline = 0; 350 + } else if (pix_fmt_mp->num_planes == 3) { 351 + pix_fmt_mp->plane_fmt[1].sizeimage = 352 + pix_fmt_mp->plane_fmt[2].sizeimage = 353 + (pix_fmt_mp->width * pix_fmt_mp->height) / 4 + 354 + ((ALIGN(pix_fmt_mp->width, 16) / 2) * 16); 355 + pix_fmt_mp->plane_fmt[1].bytesperline = 356 + pix_fmt_mp->plane_fmt[2].bytesperline = 357 + pix_fmt_mp->width / 2; 358 + } 359 + } 360 + 361 + for (i = 0; i < pix_fmt_mp->num_planes; i++) 362 + memset(&(pix_fmt_mp->plane_fmt[i].reserved[0]), 0x0, 363 + sizeof(pix_fmt_mp->plane_fmt[0].reserved)); 364 + 365 + pix_fmt_mp->flags = 0; 366 + memset(&pix_fmt_mp->reserved, 0x0, 367 + sizeof(pix_fmt_mp->reserved)); 368 + 369 + return 0; 370 + } 371 + 372 + static void mtk_venc_set_param(struct mtk_vcodec_ctx *ctx, 373 + struct venc_enc_param *param) 374 + { 375 + struct mtk_q_data *q_data_src = &ctx->q_data[MTK_Q_DATA_SRC]; 376 + struct mtk_enc_params *enc_params = &ctx->enc_params; 377 + 378 + switch (q_data_src->fmt->fourcc) { 379 + case V4L2_PIX_FMT_YUV420M: 380 + param->input_yuv_fmt = VENC_YUV_FORMAT_I420; 381 + break; 382 + case V4L2_PIX_FMT_YVU420M: 383 + param->input_yuv_fmt = VENC_YUV_FORMAT_YV12; 384 + break; 385 + case V4L2_PIX_FMT_NV12M: 386 + param->input_yuv_fmt = VENC_YUV_FORMAT_NV12; 387 + break; 388 + case V4L2_PIX_FMT_NV21M: 389 + param->input_yuv_fmt = VENC_YUV_FORMAT_NV21; 390 + break; 391 + default: 392 + mtk_v4l2_err("Unsupport fourcc =%d", q_data_src->fmt->fourcc); 393 + break; 394 + } 395 + param->h264_profile = enc_params->h264_profile; 396 + param->h264_level = enc_params->h264_level; 397 + 398 + /* Config visible resolution */ 399 + param->width = q_data_src->visible_width; 400 + param->height = q_data_src->visible_height; 401 + /* Config coded resolution */ 402 + param->buf_width = q_data_src->coded_width; 403 + param->buf_height = q_data_src->coded_height; 404 + param->frm_rate = enc_params->framerate_num / 405 + enc_params->framerate_denom; 406 + param->intra_period = enc_params->intra_period; 407 + param->gop_size = enc_params->gop_size; 408 + param->bitrate = enc_params->bitrate; 409 + 410 + mtk_v4l2_debug(0, 411 + "fmt 0x%x, P/L %d/%d, w/h %d/%d, buf %d/%d, fps/bps %d/%d, gop %d, i_period %d", 412 + param->input_yuv_fmt, param->h264_profile, 413 + param->h264_level, param->width, param->height, 414 + param->buf_width, param->buf_height, 415 + param->frm_rate, param->bitrate, 416 + param->gop_size, param->intra_period); 417 + } 418 + 419 + static int vidioc_venc_s_fmt_cap(struct file *file, void *priv, 420 + struct v4l2_format *f) 421 + { 422 + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); 423 + struct vb2_queue *vq; 424 + struct mtk_q_data *q_data; 425 + int i, ret; 426 + struct mtk_video_fmt *fmt; 427 + 428 + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); 429 + if (!vq) { 430 + mtk_v4l2_err("fail to get vq"); 431 + return -EINVAL; 432 + } 433 + 434 + if (vb2_is_busy(vq)) { 435 + mtk_v4l2_err("queue busy"); 436 + return -EBUSY; 437 + } 438 + 439 + q_data = mtk_venc_get_q_data(ctx, f->type); 440 + if (!q_data) { 441 + mtk_v4l2_err("fail to get q data"); 442 + return -EINVAL; 443 + } 444 + 445 + fmt = mtk_venc_find_format(f); 446 + if (!fmt) { 447 + f->fmt.pix.pixelformat = mtk_video_formats[CAP_FMT_IDX].fourcc; 448 + fmt = mtk_venc_find_format(f); 449 + } 450 + 451 + q_data->fmt = fmt; 452 + ret = vidioc_try_fmt(f, q_data->fmt); 453 + if (ret) 454 + return ret; 455 + 456 + q_data->coded_width = f->fmt.pix_mp.width; 457 + q_data->coded_height = f->fmt.pix_mp.height; 458 + q_data->field = f->fmt.pix_mp.field; 459 + 460 + for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { 461 + struct v4l2_plane_pix_format *plane_fmt; 462 + 463 + plane_fmt = &f->fmt.pix_mp.plane_fmt[i]; 464 + q_data->bytesperline[i] = plane_fmt->bytesperline; 465 + q_data->sizeimage[i] = plane_fmt->sizeimage; 466 + } 467 + 468 + if (ctx->state == MTK_STATE_FREE) { 469 + ret = venc_if_init(ctx, q_data->fmt->fourcc); 470 + if (ret) { 471 + mtk_v4l2_err("venc_if_init failed=%d, codec type=%x", 472 + ret, q_data->fmt->fourcc); 473 + return -EBUSY; 474 + } 475 + ctx->state = MTK_STATE_INIT; 476 + } 477 + 478 + return 0; 479 + } 480 + 481 + static int vidioc_venc_s_fmt_out(struct file *file, void *priv, 482 + struct v4l2_format *f) 483 + { 484 + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); 485 + struct vb2_queue *vq; 486 + struct mtk_q_data *q_data; 487 + int ret, i; 488 + struct mtk_video_fmt *fmt; 489 + unsigned int pitch_w_div16; 490 + struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; 491 + 492 + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); 493 + if (!vq) { 494 + mtk_v4l2_err("fail to get vq"); 495 + return -EINVAL; 496 + } 497 + 498 + if (vb2_is_busy(vq)) { 499 + mtk_v4l2_err("queue busy"); 500 + return -EBUSY; 501 + } 502 + 503 + q_data = mtk_venc_get_q_data(ctx, f->type); 504 + if (!q_data) { 505 + mtk_v4l2_err("fail to get q data"); 506 + return -EINVAL; 507 + } 508 + 509 + fmt = mtk_venc_find_format(f); 510 + if (!fmt) { 511 + f->fmt.pix.pixelformat = mtk_video_formats[OUT_FMT_IDX].fourcc; 512 + fmt = mtk_venc_find_format(f); 513 + } 514 + 515 + pix_fmt_mp->height = clamp(pix_fmt_mp->height, 516 + MTK_VENC_MIN_H, 517 + MTK_VENC_MAX_H); 518 + pix_fmt_mp->width = clamp(pix_fmt_mp->width, 519 + MTK_VENC_MIN_W, 520 + MTK_VENC_MAX_W); 521 + 522 + q_data->visible_width = f->fmt.pix_mp.width; 523 + q_data->visible_height = f->fmt.pix_mp.height; 524 + q_data->fmt = fmt; 525 + ret = vidioc_try_fmt(f, q_data->fmt); 526 + if (ret) 527 + return ret; 528 + 529 + q_data->coded_width = f->fmt.pix_mp.width; 530 + q_data->coded_height = f->fmt.pix_mp.height; 531 + 532 + pitch_w_div16 = DIV_ROUND_UP(q_data->visible_width, 16); 533 + if (pitch_w_div16 % 8 != 0) { 534 + /* Adjust returned width/height, so application could correctly 535 + * allocate hw required memory 536 + */ 537 + q_data->visible_height += 32; 538 + vidioc_try_fmt(f, q_data->fmt); 539 + } 540 + 541 + q_data->field = f->fmt.pix_mp.field; 542 + ctx->colorspace = f->fmt.pix_mp.colorspace; 543 + ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; 544 + ctx->quantization = f->fmt.pix_mp.quantization; 545 + ctx->xfer_func = f->fmt.pix_mp.xfer_func; 546 + 547 + for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { 548 + struct v4l2_plane_pix_format *plane_fmt; 549 + 550 + plane_fmt = &f->fmt.pix_mp.plane_fmt[i]; 551 + q_data->bytesperline[i] = plane_fmt->bytesperline; 552 + q_data->sizeimage[i] = plane_fmt->sizeimage; 553 + } 554 + 555 + return 0; 556 + } 557 + 558 + static int vidioc_venc_g_fmt(struct file *file, void *priv, 559 + struct v4l2_format *f) 560 + { 561 + struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; 562 + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); 563 + struct vb2_queue *vq; 564 + struct mtk_q_data *q_data; 565 + int i; 566 + 567 + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); 568 + if (!vq) 569 + return -EINVAL; 570 + 571 + q_data = mtk_venc_get_q_data(ctx, f->type); 572 + 573 + pix->width = q_data->coded_width; 574 + pix->height = q_data->coded_height; 575 + pix->pixelformat = q_data->fmt->fourcc; 576 + pix->field = q_data->field; 577 + pix->num_planes = q_data->fmt->num_planes; 578 + for (i = 0; i < pix->num_planes; i++) { 579 + pix->plane_fmt[i].bytesperline = q_data->bytesperline[i]; 580 + pix->plane_fmt[i].sizeimage = q_data->sizeimage[i]; 581 + memset(&(pix->plane_fmt[i].reserved[0]), 0x0, 582 + sizeof(pix->plane_fmt[i].reserved)); 583 + } 584 + 585 + pix->flags = 0; 586 + pix->colorspace = ctx->colorspace; 587 + pix->ycbcr_enc = ctx->ycbcr_enc; 588 + pix->quantization = ctx->quantization; 589 + pix->xfer_func = ctx->xfer_func; 590 + 591 + return 0; 592 + } 593 + 594 + static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, 595 + struct v4l2_format *f) 596 + { 597 + struct mtk_video_fmt *fmt; 598 + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); 599 + 600 + fmt = mtk_venc_find_format(f); 601 + if (!fmt) { 602 + f->fmt.pix.pixelformat = mtk_video_formats[CAP_FMT_IDX].fourcc; 603 + fmt = mtk_venc_find_format(f); 604 + } 605 + f->fmt.pix_mp.colorspace = ctx->colorspace; 606 + f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc; 607 + f->fmt.pix_mp.quantization = ctx->quantization; 608 + f->fmt.pix_mp.xfer_func = ctx->xfer_func; 609 + 610 + return vidioc_try_fmt(f, fmt); 611 + } 612 + 613 + static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, 614 + struct v4l2_format *f) 615 + { 616 + struct mtk_video_fmt *fmt; 617 + 618 + fmt = mtk_venc_find_format(f); 619 + if (!fmt) { 620 + f->fmt.pix.pixelformat = mtk_video_formats[OUT_FMT_IDX].fourcc; 621 + fmt = mtk_venc_find_format(f); 622 + } 623 + if (!f->fmt.pix_mp.colorspace) { 624 + f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709; 625 + f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; 626 + f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; 627 + f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; 628 + } 629 + 630 + return vidioc_try_fmt(f, fmt); 631 + } 632 + 633 + static int vidioc_venc_qbuf(struct file *file, void *priv, 634 + struct v4l2_buffer *buf) 635 + { 636 + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); 637 + 638 + if (ctx->state == MTK_STATE_ABORT) { 639 + mtk_v4l2_err("[%d] Call on QBUF after unrecoverable error", 640 + ctx->id); 641 + return -EIO; 642 + } 643 + 644 + return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); 645 + } 646 + 647 + static int vidioc_venc_dqbuf(struct file *file, void *priv, 648 + struct v4l2_buffer *buf) 649 + { 650 + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); 651 + 652 + if (ctx->state == MTK_STATE_ABORT) { 653 + mtk_v4l2_err("[%d] Call on QBUF after unrecoverable error", 654 + ctx->id); 655 + return -EIO; 656 + } 657 + 658 + return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); 659 + } 660 + 661 + const struct v4l2_ioctl_ops mtk_venc_ioctl_ops = { 662 + .vidioc_streamon = v4l2_m2m_ioctl_streamon, 663 + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, 664 + 665 + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, 666 + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, 667 + .vidioc_qbuf = vidioc_venc_qbuf, 668 + .vidioc_dqbuf = vidioc_venc_dqbuf, 669 + 670 + .vidioc_querycap = vidioc_venc_querycap, 671 + .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane, 672 + .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane, 673 + .vidioc_enum_framesizes = vidioc_enum_framesizes, 674 + 675 + .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap_mplane, 676 + .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out_mplane, 677 + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, 678 + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 679 + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 680 + 681 + .vidioc_s_parm = vidioc_venc_s_parm, 682 + .vidioc_g_parm = vidioc_venc_g_parm, 683 + .vidioc_s_fmt_vid_cap_mplane = vidioc_venc_s_fmt_cap, 684 + .vidioc_s_fmt_vid_out_mplane = vidioc_venc_s_fmt_out, 685 + 686 + .vidioc_g_fmt_vid_cap_mplane = vidioc_venc_g_fmt, 687 + .vidioc_g_fmt_vid_out_mplane = vidioc_venc_g_fmt, 688 + 689 + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, 690 + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, 691 + }; 692 + 693 + static int vb2ops_venc_queue_setup(struct vb2_queue *vq, 694 + unsigned int *nbuffers, 695 + unsigned int *nplanes, 696 + unsigned int sizes[], void *alloc_ctxs[]) 697 + { 698 + struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vq); 699 + struct mtk_q_data *q_data; 700 + unsigned int i; 701 + 702 + q_data = mtk_venc_get_q_data(ctx, vq->type); 703 + 704 + if (q_data == NULL) 705 + return -EINVAL; 706 + 707 + if (*nplanes) { 708 + for (i = 0; i < *nplanes; i++) { 709 + if (sizes[i] < q_data->sizeimage[i]) 710 + return -EINVAL; 711 + alloc_ctxs[i] = ctx->dev->alloc_ctx; 712 + } 713 + } else { 714 + *nplanes = q_data->fmt->num_planes; 715 + for (i = 0; i < *nplanes; i++) { 716 + sizes[i] = q_data->sizeimage[i]; 717 + alloc_ctxs[i] = ctx->dev->alloc_ctx; 718 + } 719 + } 720 + 721 + return 0; 722 + } 723 + 724 + static int vb2ops_venc_buf_prepare(struct vb2_buffer *vb) 725 + { 726 + struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 727 + struct mtk_q_data *q_data; 728 + int i; 729 + 730 + q_data = mtk_venc_get_q_data(ctx, vb->vb2_queue->type); 731 + 732 + for (i = 0; i < q_data->fmt->num_planes; i++) { 733 + if (vb2_plane_size(vb, i) < q_data->sizeimage[i]) { 734 + mtk_v4l2_err("data will not fit into plane %d (%lu < %d)", 735 + i, vb2_plane_size(vb, i), 736 + q_data->sizeimage[i]); 737 + return -EINVAL; 738 + } 739 + } 740 + 741 + return 0; 742 + } 743 + 744 + static void vb2ops_venc_buf_queue(struct vb2_buffer *vb) 745 + { 746 + struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 747 + struct vb2_v4l2_buffer *vb2_v4l2 = 748 + container_of(vb, struct vb2_v4l2_buffer, vb2_buf); 749 + 750 + struct mtk_video_enc_buf *mtk_buf = 751 + container_of(vb2_v4l2, struct mtk_video_enc_buf, vb); 752 + 753 + if ((vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) && 754 + (ctx->param_change != MTK_ENCODE_PARAM_NONE)) { 755 + mtk_v4l2_debug(1, "[%d] Before id=%d encode parameter change %x", 756 + ctx->id, 757 + mtk_buf->vb.vb2_buf.index, 758 + ctx->param_change); 759 + mtk_buf->param_change = ctx->param_change; 760 + mtk_buf->enc_params = ctx->enc_params; 761 + ctx->param_change = MTK_ENCODE_PARAM_NONE; 762 + } 763 + 764 + v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb)); 765 + } 766 + 767 + static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count) 768 + { 769 + struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q); 770 + struct venc_enc_param param; 771 + int ret; 772 + int i; 773 + 774 + /* Once state turn into MTK_STATE_ABORT, we need stop_streaming 775 + * to clear it 776 + */ 777 + if ((ctx->state == MTK_STATE_ABORT) || (ctx->state == MTK_STATE_FREE)) { 778 + ret = -EIO; 779 + goto err_set_param; 780 + } 781 + 782 + /* Do the initialization when both start_streaming have been called */ 783 + if (V4L2_TYPE_IS_OUTPUT(q->type)) { 784 + if (!vb2_start_streaming_called(&ctx->m2m_ctx->cap_q_ctx.q)) 785 + return 0; 786 + } else { 787 + if (!vb2_start_streaming_called(&ctx->m2m_ctx->out_q_ctx.q)) 788 + return 0; 789 + } 790 + 791 + mtk_venc_set_param(ctx, &param); 792 + ret = venc_if_set_param(ctx, VENC_SET_PARAM_ENC, &param); 793 + if (ret) { 794 + mtk_v4l2_err("venc_if_set_param failed=%d", ret); 795 + ctx->state = MTK_STATE_ABORT; 796 + goto err_set_param; 797 + } 798 + ctx->param_change = MTK_ENCODE_PARAM_NONE; 799 + 800 + if ((ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_H264) && 801 + (ctx->enc_params.seq_hdr_mode != 802 + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE)) { 803 + ret = venc_if_set_param(ctx, 804 + VENC_SET_PARAM_PREPEND_HEADER, 805 + NULL); 806 + if (ret) { 807 + mtk_v4l2_err("venc_if_set_param failed=%d", ret); 808 + ctx->state = MTK_STATE_ABORT; 809 + goto err_set_param; 810 + } 811 + ctx->state = MTK_STATE_HEADER; 812 + } 813 + 814 + return 0; 815 + 816 + err_set_param: 817 + for (i = 0; i < q->num_buffers; ++i) { 818 + if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) { 819 + mtk_v4l2_debug(0, "[%d] id=%d, type=%d, %d -> VB2_BUF_STATE_QUEUED", 820 + ctx->id, i, q->type, 821 + (int)q->bufs[i]->state); 822 + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(q->bufs[i]), 823 + VB2_BUF_STATE_QUEUED); 824 + } 825 + } 826 + 827 + return ret; 828 + } 829 + 830 + static void vb2ops_venc_stop_streaming(struct vb2_queue *q) 831 + { 832 + struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q); 833 + struct vb2_buffer *src_buf, *dst_buf; 834 + int ret; 835 + 836 + mtk_v4l2_debug(2, "[%d]-> type=%d", ctx->id, q->type); 837 + 838 + if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { 839 + while ((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) { 840 + dst_buf->planes[0].bytesused = 0; 841 + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), 842 + VB2_BUF_STATE_ERROR); 843 + } 844 + } else { 845 + while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) 846 + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), 847 + VB2_BUF_STATE_ERROR); 848 + } 849 + 850 + if ((q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && 851 + vb2_is_streaming(&ctx->m2m_ctx->out_q_ctx.q)) || 852 + (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && 853 + vb2_is_streaming(&ctx->m2m_ctx->cap_q_ctx.q))) { 854 + mtk_v4l2_debug(1, "[%d]-> q type %d out=%d cap=%d", 855 + ctx->id, q->type, 856 + vb2_is_streaming(&ctx->m2m_ctx->out_q_ctx.q), 857 + vb2_is_streaming(&ctx->m2m_ctx->cap_q_ctx.q)); 858 + return; 859 + } 860 + 861 + /* Release the encoder if both streams are stopped. */ 862 + ret = venc_if_deinit(ctx); 863 + if (ret) 864 + mtk_v4l2_err("venc_if_deinit failed=%d", ret); 865 + 866 + ctx->state = MTK_STATE_FREE; 867 + } 868 + 869 + static struct vb2_ops mtk_venc_vb2_ops = { 870 + .queue_setup = vb2ops_venc_queue_setup, 871 + .buf_prepare = vb2ops_venc_buf_prepare, 872 + .buf_queue = vb2ops_venc_buf_queue, 873 + .wait_prepare = vb2_ops_wait_prepare, 874 + .wait_finish = vb2_ops_wait_finish, 875 + .start_streaming = vb2ops_venc_start_streaming, 876 + .stop_streaming = vb2ops_venc_stop_streaming, 877 + }; 878 + 879 + static int mtk_venc_encode_header(void *priv) 880 + { 881 + struct mtk_vcodec_ctx *ctx = priv; 882 + int ret; 883 + struct vb2_buffer *dst_buf; 884 + struct mtk_vcodec_mem bs_buf; 885 + struct venc_done_result enc_result; 886 + 887 + dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); 888 + if (!dst_buf) { 889 + mtk_v4l2_debug(1, "No dst buffer"); 890 + return -EINVAL; 891 + } 892 + 893 + bs_buf.va = vb2_plane_vaddr(dst_buf, 0); 894 + bs_buf.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); 895 + bs_buf.size = (size_t)dst_buf->planes[0].length; 896 + 897 + mtk_v4l2_debug(1, 898 + "[%d] buf id=%d va=0x%p dma_addr=0x%llx size=%zu", 899 + ctx->id, 900 + dst_buf->index, bs_buf.va, 901 + (u64)bs_buf.dma_addr, 902 + bs_buf.size); 903 + 904 + ret = venc_if_encode(ctx, 905 + VENC_START_OPT_ENCODE_SEQUENCE_HEADER, 906 + NULL, &bs_buf, &enc_result); 907 + 908 + if (ret) { 909 + dst_buf->planes[0].bytesused = 0; 910 + ctx->state = MTK_STATE_ABORT; 911 + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), 912 + VB2_BUF_STATE_ERROR); 913 + mtk_v4l2_err("venc_if_encode failed=%d", ret); 914 + return -EINVAL; 915 + } 916 + 917 + ctx->state = MTK_STATE_HEADER; 918 + dst_buf->planes[0].bytesused = enc_result.bs_size; 919 + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), VB2_BUF_STATE_DONE); 920 + 921 + return 0; 922 + } 923 + 924 + static int mtk_venc_param_change(struct mtk_vcodec_ctx *ctx) 925 + { 926 + struct venc_enc_param enc_prm; 927 + struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx); 928 + struct vb2_v4l2_buffer *vb2_v4l2 = 929 + container_of(vb, struct vb2_v4l2_buffer, vb2_buf); 930 + struct mtk_video_enc_buf *mtk_buf = 931 + container_of(vb2_v4l2, struct mtk_video_enc_buf, vb); 932 + 933 + int ret = 0; 934 + 935 + memset(&enc_prm, 0, sizeof(enc_prm)); 936 + if (mtk_buf->param_change == MTK_ENCODE_PARAM_NONE) 937 + return 0; 938 + 939 + if (mtk_buf->param_change & MTK_ENCODE_PARAM_BITRATE) { 940 + enc_prm.bitrate = mtk_buf->enc_params.bitrate; 941 + mtk_v4l2_debug(1, "[%d] id=%d, change param br=%d", 942 + ctx->id, 943 + mtk_buf->vb.vb2_buf.index, 944 + enc_prm.bitrate); 945 + ret |= venc_if_set_param(ctx, 946 + VENC_SET_PARAM_ADJUST_BITRATE, 947 + &enc_prm); 948 + } 949 + if (!ret && mtk_buf->param_change & MTK_ENCODE_PARAM_FRAMERATE) { 950 + enc_prm.frm_rate = mtk_buf->enc_params.framerate_num / 951 + mtk_buf->enc_params.framerate_denom; 952 + mtk_v4l2_debug(1, "[%d] id=%d, change param fr=%d", 953 + ctx->id, 954 + mtk_buf->vb.vb2_buf.index, 955 + enc_prm.frm_rate); 956 + ret |= venc_if_set_param(ctx, 957 + VENC_SET_PARAM_ADJUST_FRAMERATE, 958 + &enc_prm); 959 + } 960 + if (!ret && mtk_buf->param_change & MTK_ENCODE_PARAM_GOP_SIZE) { 961 + enc_prm.gop_size = mtk_buf->enc_params.gop_size; 962 + mtk_v4l2_debug(1, "change param intra period=%d", 963 + enc_prm.gop_size); 964 + ret |= venc_if_set_param(ctx, 965 + VENC_SET_PARAM_GOP_SIZE, 966 + &enc_prm); 967 + } 968 + if (!ret && mtk_buf->param_change & MTK_ENCODE_PARAM_FORCE_INTRA) { 969 + mtk_v4l2_debug(1, "[%d] id=%d, change param force I=%d", 970 + ctx->id, 971 + mtk_buf->vb.vb2_buf.index, 972 + mtk_buf->enc_params.force_intra); 973 + if (mtk_buf->enc_params.force_intra) 974 + ret |= venc_if_set_param(ctx, 975 + VENC_SET_PARAM_FORCE_INTRA, 976 + NULL); 977 + } 978 + 979 + mtk_buf->param_change = MTK_ENCODE_PARAM_NONE; 980 + 981 + if (ret) { 982 + ctx->state = MTK_STATE_ABORT; 983 + mtk_v4l2_err("venc_if_set_param %d failed=%d", 984 + mtk_buf->param_change, ret); 985 + return -1; 986 + } 987 + 988 + return 0; 989 + } 990 + 991 + /* 992 + * v4l2_m2m_streamoff() holds dev_mutex and waits mtk_venc_worker() 993 + * to call v4l2_m2m_job_finish(). 994 + * If mtk_venc_worker() tries to acquire dev_mutex, it will deadlock. 995 + * So this function must not try to acquire dev->dev_mutex. 996 + * This means v4l2 ioctls and mtk_venc_worker() can run at the same time. 997 + * mtk_venc_worker() should be carefully implemented to avoid bugs. 998 + */ 999 + static void mtk_venc_worker(struct work_struct *work) 1000 + { 1001 + struct mtk_vcodec_ctx *ctx = container_of(work, struct mtk_vcodec_ctx, 1002 + encode_work); 1003 + struct vb2_buffer *src_buf, *dst_buf; 1004 + struct venc_frm_buf frm_buf; 1005 + struct mtk_vcodec_mem bs_buf; 1006 + struct venc_done_result enc_result; 1007 + int ret, i; 1008 + struct vb2_v4l2_buffer *vb2_v4l2; 1009 + 1010 + /* check dst_buf, dst_buf may be removed in device_run 1011 + * to stored encdoe header so we need check dst_buf and 1012 + * call job_finish here to prevent recursion 1013 + */ 1014 + dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); 1015 + if (!dst_buf) { 1016 + v4l2_m2m_job_finish(ctx->dev->m2m_dev_enc, ctx->m2m_ctx); 1017 + return; 1018 + } 1019 + 1020 + src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); 1021 + memset(&frm_buf, 0, sizeof(frm_buf)); 1022 + for (i = 0; i < src_buf->num_planes ; i++) { 1023 + frm_buf.fb_addr[i].va = vb2_plane_vaddr(src_buf, i); 1024 + frm_buf.fb_addr[i].dma_addr = 1025 + vb2_dma_contig_plane_dma_addr(src_buf, i); 1026 + frm_buf.fb_addr[i].size = 1027 + (size_t)src_buf->planes[i].length; 1028 + } 1029 + bs_buf.va = vb2_plane_vaddr(dst_buf, 0); 1030 + bs_buf.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); 1031 + bs_buf.size = (size_t)dst_buf->planes[0].length; 1032 + 1033 + mtk_v4l2_debug(2, 1034 + "Framebuf VA=%p PA=%llx Size=0x%lx;VA=%p PA=0x%llx Size=0x%lx;VA=%p PA=0x%llx Size=%zu", 1035 + frm_buf.fb_addr[0].va, 1036 + (u64)frm_buf.fb_addr[0].dma_addr, 1037 + frm_buf.fb_addr[0].size, 1038 + frm_buf.fb_addr[1].va, 1039 + (u64)frm_buf.fb_addr[1].dma_addr, 1040 + frm_buf.fb_addr[1].size, 1041 + frm_buf.fb_addr[2].va, 1042 + (u64)frm_buf.fb_addr[2].dma_addr, 1043 + frm_buf.fb_addr[2].size); 1044 + 1045 + ret = venc_if_encode(ctx, VENC_START_OPT_ENCODE_FRAME, 1046 + &frm_buf, &bs_buf, &enc_result); 1047 + 1048 + vb2_v4l2 = container_of(dst_buf, struct vb2_v4l2_buffer, vb2_buf); 1049 + if (enc_result.is_key_frm) 1050 + vb2_v4l2->flags |= V4L2_BUF_FLAG_KEYFRAME; 1051 + 1052 + if (ret) { 1053 + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), 1054 + VB2_BUF_STATE_ERROR); 1055 + dst_buf->planes[0].bytesused = 0; 1056 + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), 1057 + VB2_BUF_STATE_ERROR); 1058 + mtk_v4l2_err("venc_if_encode failed=%d", ret); 1059 + } else { 1060 + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), 1061 + VB2_BUF_STATE_DONE); 1062 + dst_buf->planes[0].bytesused = enc_result.bs_size; 1063 + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), 1064 + VB2_BUF_STATE_DONE); 1065 + mtk_v4l2_debug(2, "venc_if_encode bs size=%d", 1066 + enc_result.bs_size); 1067 + } 1068 + 1069 + v4l2_m2m_job_finish(ctx->dev->m2m_dev_enc, ctx->m2m_ctx); 1070 + 1071 + mtk_v4l2_debug(1, "<=== src_buf[%d] dst_buf[%d] venc_if_encode ret=%d Size=%u===>", 1072 + src_buf->index, dst_buf->index, ret, 1073 + enc_result.bs_size); 1074 + } 1075 + 1076 + static void m2mops_venc_device_run(void *priv) 1077 + { 1078 + struct mtk_vcodec_ctx *ctx = priv; 1079 + 1080 + if ((ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_H264) && 1081 + (ctx->state != MTK_STATE_HEADER)) { 1082 + /* encode h264 sps/pps header */ 1083 + mtk_venc_encode_header(ctx); 1084 + queue_work(ctx->dev->encode_workqueue, &ctx->encode_work); 1085 + return; 1086 + } 1087 + 1088 + mtk_venc_param_change(ctx); 1089 + queue_work(ctx->dev->encode_workqueue, &ctx->encode_work); 1090 + } 1091 + 1092 + static int m2mops_venc_job_ready(void *m2m_priv) 1093 + { 1094 + struct mtk_vcodec_ctx *ctx = m2m_priv; 1095 + 1096 + if (ctx->state == MTK_STATE_ABORT || ctx->state == MTK_STATE_FREE) { 1097 + mtk_v4l2_debug(3, "[%d]Not ready: state=0x%x.", 1098 + ctx->id, ctx->state); 1099 + return 0; 1100 + } 1101 + 1102 + return 1; 1103 + } 1104 + 1105 + static void m2mops_venc_job_abort(void *priv) 1106 + { 1107 + struct mtk_vcodec_ctx *ctx = priv; 1108 + 1109 + ctx->state = MTK_STATE_ABORT; 1110 + } 1111 + 1112 + static void m2mops_venc_lock(void *m2m_priv) 1113 + { 1114 + struct mtk_vcodec_ctx *ctx = m2m_priv; 1115 + 1116 + mutex_lock(&ctx->dev->dev_mutex); 1117 + } 1118 + 1119 + static void m2mops_venc_unlock(void *m2m_priv) 1120 + { 1121 + struct mtk_vcodec_ctx *ctx = m2m_priv; 1122 + 1123 + mutex_unlock(&ctx->dev->dev_mutex); 1124 + } 1125 + 1126 + const struct v4l2_m2m_ops mtk_venc_m2m_ops = { 1127 + .device_run = m2mops_venc_device_run, 1128 + .job_ready = m2mops_venc_job_ready, 1129 + .job_abort = m2mops_venc_job_abort, 1130 + .lock = m2mops_venc_lock, 1131 + .unlock = m2mops_venc_unlock, 1132 + }; 1133 + 1134 + void mtk_vcodec_enc_set_default_params(struct mtk_vcodec_ctx *ctx) 1135 + { 1136 + struct mtk_q_data *q_data; 1137 + 1138 + ctx->m2m_ctx->q_lock = &ctx->dev->dev_mutex; 1139 + ctx->fh.m2m_ctx = ctx->m2m_ctx; 1140 + ctx->fh.ctrl_handler = &ctx->ctrl_hdl; 1141 + INIT_WORK(&ctx->encode_work, mtk_venc_worker); 1142 + 1143 + ctx->colorspace = V4L2_COLORSPACE_REC709; 1144 + ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; 1145 + ctx->quantization = V4L2_QUANTIZATION_DEFAULT; 1146 + ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT; 1147 + 1148 + q_data = &ctx->q_data[MTK_Q_DATA_SRC]; 1149 + memset(q_data, 0, sizeof(struct mtk_q_data)); 1150 + q_data->visible_width = DFT_CFG_WIDTH; 1151 + q_data->visible_height = DFT_CFG_HEIGHT; 1152 + q_data->coded_width = DFT_CFG_WIDTH; 1153 + q_data->coded_height = DFT_CFG_HEIGHT; 1154 + q_data->field = V4L2_FIELD_NONE; 1155 + 1156 + q_data->fmt = &mtk_video_formats[OUT_FMT_IDX]; 1157 + 1158 + v4l_bound_align_image(&q_data->coded_width, 1159 + MTK_VENC_MIN_W, 1160 + MTK_VENC_MAX_W, 4, 1161 + &q_data->coded_height, 1162 + MTK_VENC_MIN_H, 1163 + MTK_VENC_MAX_H, 5, 6); 1164 + 1165 + if (q_data->coded_width < DFT_CFG_WIDTH && 1166 + (q_data->coded_width + 16) <= MTK_VENC_MAX_W) 1167 + q_data->coded_width += 16; 1168 + if (q_data->coded_height < DFT_CFG_HEIGHT && 1169 + (q_data->coded_height + 32) <= MTK_VENC_MAX_H) 1170 + q_data->coded_height += 32; 1171 + 1172 + q_data->sizeimage[0] = q_data->coded_width * q_data->coded_height; 1173 + q_data->bytesperline[0] = q_data->coded_width; 1174 + q_data->sizeimage[1] = q_data->sizeimage[0] / 2; 1175 + q_data->bytesperline[1] = q_data->coded_width; 1176 + 1177 + q_data = &ctx->q_data[MTK_Q_DATA_DST]; 1178 + memset(q_data, 0, sizeof(struct mtk_q_data)); 1179 + q_data->coded_width = DFT_CFG_WIDTH; 1180 + q_data->coded_height = DFT_CFG_HEIGHT; 1181 + q_data->fmt = &mtk_video_formats[CAP_FMT_IDX]; 1182 + q_data->field = V4L2_FIELD_NONE; 1183 + ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] = 1184 + DFT_CFG_WIDTH * DFT_CFG_HEIGHT; 1185 + ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] = 0; 1186 + 1187 + } 1188 + 1189 + int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx) 1190 + { 1191 + const struct v4l2_ctrl_ops *ops = &mtk_vcodec_enc_ctrl_ops; 1192 + struct v4l2_ctrl_handler *handler = &ctx->ctrl_hdl; 1193 + 1194 + v4l2_ctrl_handler_init(handler, MTK_MAX_CTRLS_HINT); 1195 + 1196 + v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_BITRATE, 1197 + 1, 4000000, 1, 4000000); 1198 + v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_B_FRAMES, 1199 + 0, 2, 1, 0); 1200 + v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, 1201 + 0, 1, 1, 1); 1202 + v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 1203 + 0, 51, 1, 51); 1204 + v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, 1205 + 0, 65535, 1, 0); 1206 + v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1207 + 0, 65535, 1, 0); 1208 + v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, 1209 + 0, 1, 1, 0); 1210 + v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, 1211 + 0, 0, 0, 0); 1212 + v4l2_ctrl_new_std_menu(handler, ops, 1213 + V4L2_CID_MPEG_VIDEO_HEADER_MODE, 1214 + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, 1215 + 0, V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE); 1216 + v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE, 1217 + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, 1218 + 0, V4L2_MPEG_VIDEO_H264_PROFILE_MAIN); 1219 + v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, 1220 + V4L2_MPEG_VIDEO_H264_LEVEL_4_2, 1221 + 0, V4L2_MPEG_VIDEO_H264_LEVEL_4_0); 1222 + if (handler->error) { 1223 + mtk_v4l2_err("Init control handler fail %d", 1224 + handler->error); 1225 + return handler->error; 1226 + } 1227 + 1228 + v4l2_ctrl_handler_setup(&ctx->ctrl_hdl); 1229 + 1230 + return 0; 1231 + } 1232 + 1233 + int mtk_vcodec_enc_queue_init(void *priv, struct vb2_queue *src_vq, 1234 + struct vb2_queue *dst_vq) 1235 + { 1236 + struct mtk_vcodec_ctx *ctx = priv; 1237 + int ret; 1238 + 1239 + /* Note: VB2_USERPTR works with dma-contig because mt8173 1240 + * support iommu 1241 + * https://patchwork.kernel.org/patch/8335461/ 1242 + * https://patchwork.kernel.org/patch/7596181/ 1243 + */ 1244 + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; 1245 + src_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR; 1246 + src_vq->drv_priv = ctx; 1247 + src_vq->buf_struct_size = sizeof(struct mtk_video_enc_buf); 1248 + src_vq->ops = &mtk_venc_vb2_ops; 1249 + src_vq->mem_ops = &vb2_dma_contig_memops; 1250 + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 1251 + src_vq->lock = &ctx->dev->dev_mutex; 1252 + 1253 + ret = vb2_queue_init(src_vq); 1254 + if (ret) 1255 + return ret; 1256 + 1257 + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 1258 + dst_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR; 1259 + dst_vq->drv_priv = ctx; 1260 + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); 1261 + dst_vq->ops = &mtk_venc_vb2_ops; 1262 + dst_vq->mem_ops = &vb2_dma_contig_memops; 1263 + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 1264 + dst_vq->lock = &ctx->dev->dev_mutex; 1265 + 1266 + return vb2_queue_init(dst_vq); 1267 + } 1268 + 1269 + int mtk_venc_unlock(struct mtk_vcodec_ctx *ctx) 1270 + { 1271 + struct mtk_vcodec_dev *dev = ctx->dev; 1272 + 1273 + mutex_unlock(&dev->enc_mutex); 1274 + return 0; 1275 + } 1276 + 1277 + int mtk_venc_lock(struct mtk_vcodec_ctx *ctx) 1278 + { 1279 + struct mtk_vcodec_dev *dev = ctx->dev; 1280 + 1281 + mutex_lock(&dev->enc_mutex); 1282 + return 0; 1283 + } 1284 + 1285 + void mtk_vcodec_enc_release(struct mtk_vcodec_ctx *ctx) 1286 + { 1287 + venc_if_deinit(ctx); 1288 + }
+58
drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h
··· 1 + /* 2 + * Copyright (c) 2016 MediaTek Inc. 3 + * Author: PC Chen <pc.chen@mediatek.com> 4 + * Tiffany Lin <tiffany.lin@mediatek.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + */ 15 + 16 + #ifndef _MTK_VCODEC_ENC_H_ 17 + #define _MTK_VCODEC_ENC_H_ 18 + 19 + #include <media/videobuf2-core.h> 20 + #include <media/videobuf2-v4l2.h> 21 + 22 + #define MTK_VENC_IRQ_STATUS_SPS 0x1 23 + #define MTK_VENC_IRQ_STATUS_PPS 0x2 24 + #define MTK_VENC_IRQ_STATUS_FRM 0x4 25 + #define MTK_VENC_IRQ_STATUS_DRAM 0x8 26 + #define MTK_VENC_IRQ_STATUS_PAUSE 0x10 27 + #define MTK_VENC_IRQ_STATUS_SWITCH 0x20 28 + 29 + #define MTK_VENC_IRQ_STATUS_OFFSET 0x05C 30 + #define MTK_VENC_IRQ_ACK_OFFSET 0x060 31 + 32 + /** 33 + * struct mtk_video_enc_buf - Private data related to each VB2 buffer. 34 + * @vb: Pointer to related VB2 buffer. 35 + * @list: list that buffer link to 36 + * @param_change: Types of encode parameter change before encoding this 37 + * buffer 38 + * @enc_params: Encode parameters changed before encode this buffer 39 + */ 40 + struct mtk_video_enc_buf { 41 + struct vb2_v4l2_buffer vb; 42 + struct list_head list; 43 + u32 param_change; 44 + struct mtk_enc_params enc_params; 45 + }; 46 + 47 + extern const struct v4l2_ioctl_ops mtk_venc_ioctl_ops; 48 + extern const struct v4l2_m2m_ops mtk_venc_m2m_ops; 49 + 50 + int mtk_venc_unlock(struct mtk_vcodec_ctx *ctx); 51 + int mtk_venc_lock(struct mtk_vcodec_ctx *ctx); 52 + int mtk_vcodec_enc_queue_init(void *priv, struct vb2_queue *src_vq, 53 + struct vb2_queue *dst_vq); 54 + void mtk_vcodec_enc_release(struct mtk_vcodec_ctx *ctx); 55 + int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx); 56 + void mtk_vcodec_enc_set_default_params(struct mtk_vcodec_ctx *ctx); 57 + 58 + #endif /* _MTK_VCODEC_ENC_H_ */
+454
drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
··· 1 + /* 2 + * Copyright (c) 2016 MediaTek Inc. 3 + * Author: PC Chen <pc.chen@mediatek.com> 4 + * Tiffany Lin <tiffany.lin@mediatek.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + */ 15 + 16 + #include <linux/slab.h> 17 + #include <linux/interrupt.h> 18 + #include <linux/irq.h> 19 + #include <linux/module.h> 20 + #include <linux/of_device.h> 21 + #include <linux/of.h> 22 + #include <media/v4l2-event.h> 23 + #include <media/v4l2-mem2mem.h> 24 + #include <media/videobuf2-dma-contig.h> 25 + #include <linux/pm_runtime.h> 26 + 27 + #include "mtk_vcodec_drv.h" 28 + #include "mtk_vcodec_enc.h" 29 + #include "mtk_vcodec_enc_pm.h" 30 + #include "mtk_vcodec_intr.h" 31 + #include "mtk_vcodec_util.h" 32 + #include "mtk_vpu.h" 33 + 34 + module_param(mtk_v4l2_dbg_level, int, S_IRUGO | S_IWUSR); 35 + module_param(mtk_vcodec_dbg, bool, S_IRUGO | S_IWUSR); 36 + 37 + /* Wake up context wait_queue */ 38 + static void wake_up_ctx(struct mtk_vcodec_ctx *ctx, unsigned int reason) 39 + { 40 + ctx->int_cond = 1; 41 + ctx->int_type = reason; 42 + wake_up_interruptible(&ctx->queue); 43 + } 44 + 45 + static void clean_irq_status(unsigned int irq_status, void __iomem *addr) 46 + { 47 + if (irq_status & MTK_VENC_IRQ_STATUS_PAUSE) 48 + writel(MTK_VENC_IRQ_STATUS_PAUSE, addr); 49 + 50 + if (irq_status & MTK_VENC_IRQ_STATUS_SWITCH) 51 + writel(MTK_VENC_IRQ_STATUS_SWITCH, addr); 52 + 53 + if (irq_status & MTK_VENC_IRQ_STATUS_DRAM) 54 + writel(MTK_VENC_IRQ_STATUS_DRAM, addr); 55 + 56 + if (irq_status & MTK_VENC_IRQ_STATUS_SPS) 57 + writel(MTK_VENC_IRQ_STATUS_SPS, addr); 58 + 59 + if (irq_status & MTK_VENC_IRQ_STATUS_PPS) 60 + writel(MTK_VENC_IRQ_STATUS_PPS, addr); 61 + 62 + if (irq_status & MTK_VENC_IRQ_STATUS_FRM) 63 + writel(MTK_VENC_IRQ_STATUS_FRM, addr); 64 + 65 + } 66 + static irqreturn_t mtk_vcodec_enc_irq_handler(int irq, void *priv) 67 + { 68 + struct mtk_vcodec_dev *dev = priv; 69 + struct mtk_vcodec_ctx *ctx; 70 + unsigned long flags; 71 + void __iomem *addr; 72 + 73 + spin_lock_irqsave(&dev->irqlock, flags); 74 + ctx = dev->curr_ctx; 75 + spin_unlock_irqrestore(&dev->irqlock, flags); 76 + 77 + mtk_v4l2_debug(1, "id=%d", ctx->id); 78 + addr = dev->reg_base[VENC_SYS] + MTK_VENC_IRQ_ACK_OFFSET; 79 + 80 + ctx->irq_status = readl(dev->reg_base[VENC_SYS] + 81 + (MTK_VENC_IRQ_STATUS_OFFSET)); 82 + 83 + clean_irq_status(ctx->irq_status, addr); 84 + 85 + wake_up_ctx(ctx, MTK_INST_IRQ_RECEIVED); 86 + return IRQ_HANDLED; 87 + } 88 + 89 + static irqreturn_t mtk_vcodec_enc_lt_irq_handler(int irq, void *priv) 90 + { 91 + struct mtk_vcodec_dev *dev = priv; 92 + struct mtk_vcodec_ctx *ctx; 93 + unsigned long flags; 94 + void __iomem *addr; 95 + 96 + spin_lock_irqsave(&dev->irqlock, flags); 97 + ctx = dev->curr_ctx; 98 + spin_unlock_irqrestore(&dev->irqlock, flags); 99 + 100 + mtk_v4l2_debug(1, "id=%d", ctx->id); 101 + ctx->irq_status = readl(dev->reg_base[VENC_LT_SYS] + 102 + (MTK_VENC_IRQ_STATUS_OFFSET)); 103 + 104 + addr = dev->reg_base[VENC_LT_SYS] + MTK_VENC_IRQ_ACK_OFFSET; 105 + 106 + clean_irq_status(ctx->irq_status, addr); 107 + 108 + wake_up_ctx(ctx, MTK_INST_IRQ_RECEIVED); 109 + return IRQ_HANDLED; 110 + } 111 + 112 + static void mtk_vcodec_enc_reset_handler(void *priv) 113 + { 114 + struct mtk_vcodec_dev *dev = priv; 115 + struct mtk_vcodec_ctx *ctx; 116 + 117 + mtk_v4l2_debug(0, "Watchdog timeout!!"); 118 + 119 + mutex_lock(&dev->dev_mutex); 120 + list_for_each_entry(ctx, &dev->ctx_list, list) { 121 + ctx->state = MTK_STATE_ABORT; 122 + mtk_v4l2_debug(0, "[%d] Change to state MTK_STATE_ABORT", 123 + ctx->id); 124 + } 125 + mutex_unlock(&dev->dev_mutex); 126 + } 127 + 128 + static int fops_vcodec_open(struct file *file) 129 + { 130 + struct mtk_vcodec_dev *dev = video_drvdata(file); 131 + struct mtk_vcodec_ctx *ctx = NULL; 132 + int ret = 0; 133 + 134 + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 135 + if (!ctx) 136 + return -ENOMEM; 137 + 138 + mutex_lock(&dev->dev_mutex); 139 + /* 140 + * Use simple counter to uniquely identify this context. Only 141 + * used for logging. 142 + */ 143 + ctx->id = dev->id_counter++; 144 + v4l2_fh_init(&ctx->fh, video_devdata(file)); 145 + file->private_data = &ctx->fh; 146 + v4l2_fh_add(&ctx->fh); 147 + INIT_LIST_HEAD(&ctx->list); 148 + ctx->dev = dev; 149 + init_waitqueue_head(&ctx->queue); 150 + 151 + ctx->type = MTK_INST_ENCODER; 152 + ret = mtk_vcodec_enc_ctrls_setup(ctx); 153 + if (ret) { 154 + mtk_v4l2_err("Failed to setup controls() (%d)", 155 + ret); 156 + goto err_ctrls_setup; 157 + } 158 + ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev_enc, ctx, 159 + &mtk_vcodec_enc_queue_init); 160 + if (IS_ERR((__force void *)ctx->m2m_ctx)) { 161 + ret = PTR_ERR((__force void *)ctx->m2m_ctx); 162 + mtk_v4l2_err("Failed to v4l2_m2m_ctx_init() (%d)", 163 + ret); 164 + goto err_m2m_ctx_init; 165 + } 166 + mtk_vcodec_enc_set_default_params(ctx); 167 + 168 + if (v4l2_fh_is_singular(&ctx->fh)) { 169 + /* 170 + * vpu_load_firmware checks if it was loaded already and 171 + * does nothing in that case 172 + */ 173 + ret = vpu_load_firmware(dev->vpu_plat_dev); 174 + if (ret < 0) { 175 + /* 176 + * Return 0 if downloading firmware successfully, 177 + * otherwise it is failed 178 + */ 179 + mtk_v4l2_err("vpu_load_firmware failed!"); 180 + goto err_load_fw; 181 + } 182 + 183 + dev->enc_capability = 184 + vpu_get_venc_hw_capa(dev->vpu_plat_dev); 185 + mtk_v4l2_debug(0, "encoder capability %x", dev->enc_capability); 186 + } 187 + 188 + mtk_v4l2_debug(2, "Create instance [%d]@%p m2m_ctx=%p ", 189 + ctx->id, ctx, ctx->m2m_ctx); 190 + 191 + dev->num_instances++; 192 + list_add(&ctx->list, &dev->ctx_list); 193 + 194 + mutex_unlock(&dev->dev_mutex); 195 + mtk_v4l2_debug(0, "%s encoder [%d]", dev_name(&dev->plat_dev->dev), 196 + ctx->id); 197 + return ret; 198 + 199 + /* Deinit when failure occurred */ 200 + err_load_fw: 201 + v4l2_m2m_ctx_release(ctx->m2m_ctx); 202 + err_m2m_ctx_init: 203 + v4l2_ctrl_handler_free(&ctx->ctrl_hdl); 204 + err_ctrls_setup: 205 + v4l2_fh_del(&ctx->fh); 206 + v4l2_fh_exit(&ctx->fh); 207 + kfree(ctx); 208 + mutex_unlock(&dev->dev_mutex); 209 + 210 + return ret; 211 + } 212 + 213 + static int fops_vcodec_release(struct file *file) 214 + { 215 + struct mtk_vcodec_dev *dev = video_drvdata(file); 216 + struct mtk_vcodec_ctx *ctx = fh_to_ctx(file->private_data); 217 + 218 + mtk_v4l2_debug(1, "[%d] encoder", ctx->id); 219 + mutex_lock(&dev->dev_mutex); 220 + 221 + mtk_vcodec_enc_release(ctx); 222 + v4l2_fh_del(&ctx->fh); 223 + v4l2_fh_exit(&ctx->fh); 224 + v4l2_ctrl_handler_free(&ctx->ctrl_hdl); 225 + v4l2_m2m_ctx_release(ctx->m2m_ctx); 226 + 227 + list_del_init(&ctx->list); 228 + dev->num_instances--; 229 + kfree(ctx); 230 + mutex_unlock(&dev->dev_mutex); 231 + return 0; 232 + } 233 + 234 + static const struct v4l2_file_operations mtk_vcodec_fops = { 235 + .owner = THIS_MODULE, 236 + .open = fops_vcodec_open, 237 + .release = fops_vcodec_release, 238 + .poll = v4l2_m2m_fop_poll, 239 + .unlocked_ioctl = video_ioctl2, 240 + .mmap = v4l2_m2m_fop_mmap, 241 + }; 242 + 243 + static int mtk_vcodec_probe(struct platform_device *pdev) 244 + { 245 + struct mtk_vcodec_dev *dev; 246 + struct video_device *vfd_enc; 247 + struct resource *res; 248 + int i, j, ret; 249 + DEFINE_DMA_ATTRS(attrs); 250 + 251 + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); 252 + if (!dev) 253 + return -ENOMEM; 254 + 255 + INIT_LIST_HEAD(&dev->ctx_list); 256 + dev->plat_dev = pdev; 257 + 258 + dev->vpu_plat_dev = vpu_get_plat_device(dev->plat_dev); 259 + if (dev->vpu_plat_dev == NULL) { 260 + mtk_v4l2_err("[VPU] vpu device in not ready"); 261 + return -EPROBE_DEFER; 262 + } 263 + 264 + vpu_wdt_reg_handler(dev->vpu_plat_dev, mtk_vcodec_enc_reset_handler, 265 + dev, VPU_RST_ENC); 266 + 267 + ret = mtk_vcodec_init_enc_pm(dev); 268 + if (ret < 0) { 269 + dev_err(&pdev->dev, "Failed to get mt vcodec clock source!"); 270 + return ret; 271 + } 272 + 273 + for (i = VENC_SYS, j = 0; i < NUM_MAX_VCODEC_REG_BASE; i++, j++) { 274 + res = platform_get_resource(pdev, IORESOURCE_MEM, j); 275 + if (res == NULL) { 276 + dev_err(&pdev->dev, "get memory resource failed."); 277 + ret = -ENXIO; 278 + goto err_res; 279 + } 280 + dev->reg_base[i] = devm_ioremap_resource(&pdev->dev, res); 281 + if (IS_ERR((__force void *)dev->reg_base[i])) { 282 + dev_err(&pdev->dev, 283 + "devm_ioremap_resource %d failed.", i); 284 + ret = PTR_ERR((__force void *)dev->reg_base[i]); 285 + goto err_res; 286 + } 287 + mtk_v4l2_debug(2, "reg[%d] base=0x%p", i, dev->reg_base[i]); 288 + } 289 + 290 + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 291 + if (res == NULL) { 292 + dev_err(&pdev->dev, "failed to get irq resource"); 293 + ret = -ENOENT; 294 + goto err_res; 295 + } 296 + 297 + dev->enc_irq = platform_get_irq(pdev, 0); 298 + ret = devm_request_irq(&pdev->dev, dev->enc_irq, 299 + mtk_vcodec_enc_irq_handler, 300 + 0, pdev->name, dev); 301 + if (ret) { 302 + dev_err(&pdev->dev, "Failed to install dev->enc_irq %d (%d)", 303 + dev->enc_irq, 304 + ret); 305 + ret = -EINVAL; 306 + goto err_res; 307 + } 308 + 309 + dev->enc_lt_irq = platform_get_irq(pdev, 1); 310 + ret = devm_request_irq(&pdev->dev, 311 + dev->enc_lt_irq, mtk_vcodec_enc_lt_irq_handler, 312 + 0, pdev->name, dev); 313 + if (ret) { 314 + dev_err(&pdev->dev, 315 + "Failed to install dev->enc_lt_irq %d (%d)", 316 + dev->enc_lt_irq, ret); 317 + ret = -EINVAL; 318 + goto err_res; 319 + } 320 + 321 + disable_irq(dev->enc_irq); 322 + disable_irq(dev->enc_lt_irq); /* VENC_LT */ 323 + mutex_init(&dev->enc_mutex); 324 + mutex_init(&dev->dev_mutex); 325 + spin_lock_init(&dev->irqlock); 326 + 327 + snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s", 328 + "[MTK_V4L2_VENC]"); 329 + 330 + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); 331 + if (ret) { 332 + mtk_v4l2_err("v4l2_device_register err=%d", ret); 333 + goto err_res; 334 + } 335 + 336 + init_waitqueue_head(&dev->queue); 337 + 338 + /* allocate video device for encoder and register it */ 339 + vfd_enc = video_device_alloc(); 340 + if (!vfd_enc) { 341 + mtk_v4l2_err("Failed to allocate video device"); 342 + ret = -ENOMEM; 343 + goto err_enc_alloc; 344 + } 345 + vfd_enc->fops = &mtk_vcodec_fops; 346 + vfd_enc->ioctl_ops = &mtk_venc_ioctl_ops; 347 + vfd_enc->release = video_device_release; 348 + vfd_enc->lock = &dev->dev_mutex; 349 + vfd_enc->v4l2_dev = &dev->v4l2_dev; 350 + vfd_enc->vfl_dir = VFL_DIR_M2M; 351 + vfd_enc->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | 352 + V4L2_CAP_STREAMING; 353 + 354 + snprintf(vfd_enc->name, sizeof(vfd_enc->name), "%s", 355 + MTK_VCODEC_ENC_NAME); 356 + video_set_drvdata(vfd_enc, dev); 357 + dev->vfd_enc = vfd_enc; 358 + platform_set_drvdata(pdev, dev); 359 + 360 + dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); 361 + if (IS_ERR((__force void *)dev->alloc_ctx)) { 362 + mtk_v4l2_err("Failed to alloc vb2 dma context 0"); 363 + ret = PTR_ERR((__force void *)dev->alloc_ctx); 364 + dev->alloc_ctx = NULL; 365 + goto err_vb2_ctx_init; 366 + } 367 + 368 + dev->m2m_dev_enc = v4l2_m2m_init(&mtk_venc_m2m_ops); 369 + if (IS_ERR((__force void *)dev->m2m_dev_enc)) { 370 + mtk_v4l2_err("Failed to init mem2mem enc device"); 371 + ret = PTR_ERR((__force void *)dev->m2m_dev_enc); 372 + goto err_enc_mem_init; 373 + } 374 + 375 + dev->encode_workqueue = 376 + alloc_ordered_workqueue(MTK_VCODEC_ENC_NAME, 377 + WQ_MEM_RECLAIM | 378 + WQ_FREEZABLE); 379 + if (!dev->encode_workqueue) { 380 + mtk_v4l2_err("Failed to create encode workqueue"); 381 + ret = -EINVAL; 382 + goto err_event_workq; 383 + } 384 + 385 + ret = video_register_device(vfd_enc, VFL_TYPE_GRABBER, 1); 386 + if (ret) { 387 + mtk_v4l2_err("Failed to register video device"); 388 + goto err_enc_reg; 389 + } 390 + 391 + /* Avoid the iommu eat big hunks */ 392 + dma_set_attr(DMA_ATTR_ALLOC_SINGLE_PAGES, &attrs); 393 + 394 + mtk_v4l2_debug(0, "encoder registered as /dev/video%d", 395 + vfd_enc->num); 396 + 397 + return 0; 398 + 399 + err_enc_reg: 400 + destroy_workqueue(dev->encode_workqueue); 401 + err_event_workq: 402 + v4l2_m2m_release(dev->m2m_dev_enc); 403 + err_enc_mem_init: 404 + vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); 405 + err_vb2_ctx_init: 406 + video_unregister_device(vfd_enc); 407 + err_enc_alloc: 408 + v4l2_device_unregister(&dev->v4l2_dev); 409 + err_res: 410 + mtk_vcodec_release_enc_pm(dev); 411 + return ret; 412 + } 413 + 414 + static const struct of_device_id mtk_vcodec_enc_match[] = { 415 + {.compatible = "mediatek,mt8173-vcodec-enc",}, 416 + {}, 417 + }; 418 + MODULE_DEVICE_TABLE(of, mtk_vcodec_enc_match); 419 + 420 + static int mtk_vcodec_enc_remove(struct platform_device *pdev) 421 + { 422 + struct mtk_vcodec_dev *dev = platform_get_drvdata(pdev); 423 + 424 + mtk_v4l2_debug_enter(); 425 + flush_workqueue(dev->encode_workqueue); 426 + destroy_workqueue(dev->encode_workqueue); 427 + if (dev->m2m_dev_enc) 428 + v4l2_m2m_release(dev->m2m_dev_enc); 429 + if (dev->alloc_ctx) 430 + vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); 431 + 432 + if (dev->vfd_enc) 433 + video_unregister_device(dev->vfd_enc); 434 + 435 + v4l2_device_unregister(&dev->v4l2_dev); 436 + mtk_vcodec_release_enc_pm(dev); 437 + return 0; 438 + } 439 + 440 + static struct platform_driver mtk_vcodec_enc_driver = { 441 + .probe = mtk_vcodec_probe, 442 + .remove = mtk_vcodec_enc_remove, 443 + .driver = { 444 + .name = MTK_VCODEC_ENC_NAME, 445 + .owner = THIS_MODULE, 446 + .of_match_table = mtk_vcodec_enc_match, 447 + }, 448 + }; 449 + 450 + module_platform_driver(mtk_vcodec_enc_driver); 451 + 452 + 453 + MODULE_LICENSE("GPL v2"); 454 + MODULE_DESCRIPTION("Mediatek video codec V4L2 encoder driver");
+137
drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
··· 1 + /* 2 + * Copyright (c) 2016 MediaTek Inc. 3 + * Author: Tiffany Lin <tiffany.lin@mediatek.com> 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + */ 14 + 15 + #include <linux/clk.h> 16 + #include <linux/of_address.h> 17 + #include <linux/of_platform.h> 18 + #include <linux/pm_runtime.h> 19 + #include <soc/mediatek/smi.h> 20 + 21 + #include "mtk_vcodec_enc_pm.h" 22 + #include "mtk_vcodec_util.h" 23 + #include "mtk_vpu.h" 24 + 25 + 26 + int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev) 27 + { 28 + struct device_node *node; 29 + struct platform_device *pdev; 30 + struct device *dev; 31 + struct mtk_vcodec_pm *pm; 32 + int ret = 0; 33 + 34 + pdev = mtkdev->plat_dev; 35 + pm = &mtkdev->pm; 36 + memset(pm, 0, sizeof(struct mtk_vcodec_pm)); 37 + pm->mtkdev = mtkdev; 38 + pm->dev = &pdev->dev; 39 + dev = &pdev->dev; 40 + 41 + node = of_parse_phandle(dev->of_node, "mediatek,larb", 0); 42 + if (!node) { 43 + mtk_v4l2_err("no mediatek,larb found"); 44 + return -1; 45 + } 46 + pdev = of_find_device_by_node(node); 47 + if (!pdev) { 48 + mtk_v4l2_err("no mediatek,larb device found"); 49 + return -1; 50 + } 51 + pm->larbvenc = &pdev->dev; 52 + 53 + node = of_parse_phandle(dev->of_node, "mediatek,larb", 1); 54 + if (!node) { 55 + mtk_v4l2_err("no mediatek,larb found"); 56 + return -1; 57 + } 58 + 59 + pdev = of_find_device_by_node(node); 60 + if (!pdev) { 61 + mtk_v4l2_err("no mediatek,larb device found"); 62 + return -1; 63 + } 64 + 65 + pm->larbvenclt = &pdev->dev; 66 + pdev = mtkdev->plat_dev; 67 + pm->dev = &pdev->dev; 68 + 69 + pm->vencpll_d2 = devm_clk_get(&pdev->dev, "venc_sel_src"); 70 + if (pm->vencpll_d2 == NULL) { 71 + mtk_v4l2_err("devm_clk_get vencpll_d2 fail"); 72 + ret = -1; 73 + } 74 + 75 + pm->venc_sel = devm_clk_get(&pdev->dev, "venc_sel"); 76 + if (pm->venc_sel == NULL) { 77 + mtk_v4l2_err("devm_clk_get venc_sel fail"); 78 + ret = -1; 79 + } 80 + 81 + pm->univpll1_d2 = devm_clk_get(&pdev->dev, "venc_lt_sel_src"); 82 + if (pm->univpll1_d2 == NULL) { 83 + mtk_v4l2_err("devm_clk_get univpll1_d2 fail"); 84 + ret = -1; 85 + } 86 + 87 + pm->venc_lt_sel = devm_clk_get(&pdev->dev, "venc_lt_sel"); 88 + if (pm->venc_lt_sel == NULL) { 89 + mtk_v4l2_err("devm_clk_get venc_lt_sel fail"); 90 + ret = -1; 91 + } 92 + 93 + return ret; 94 + } 95 + 96 + void mtk_vcodec_release_enc_pm(struct mtk_vcodec_dev *mtkdev) 97 + { 98 + } 99 + 100 + 101 + void mtk_vcodec_enc_clock_on(struct mtk_vcodec_pm *pm) 102 + { 103 + int ret; 104 + 105 + ret = clk_prepare_enable(pm->venc_sel); 106 + if (ret) 107 + mtk_v4l2_err("clk_prepare_enable fail %d", ret); 108 + 109 + ret = clk_set_parent(pm->venc_sel, pm->vencpll_d2); 110 + if (ret) 111 + mtk_v4l2_err("clk_set_parent fail %d", ret); 112 + 113 + ret = clk_prepare_enable(pm->venc_lt_sel); 114 + if (ret) 115 + mtk_v4l2_err("clk_prepare_enable fail %d", ret); 116 + 117 + ret = clk_set_parent(pm->venc_lt_sel, pm->univpll1_d2); 118 + if (ret) 119 + mtk_v4l2_err("clk_set_parent fail %d", ret); 120 + 121 + ret = mtk_smi_larb_get(pm->larbvenc); 122 + if (ret) 123 + mtk_v4l2_err("mtk_smi_larb_get larb3 fail %d", ret); 124 + 125 + ret = mtk_smi_larb_get(pm->larbvenclt); 126 + if (ret) 127 + mtk_v4l2_err("mtk_smi_larb_get larb4 fail %d", ret); 128 + 129 + } 130 + 131 + void mtk_vcodec_enc_clock_off(struct mtk_vcodec_pm *pm) 132 + { 133 + mtk_smi_larb_put(pm->larbvenc); 134 + mtk_smi_larb_put(pm->larbvenclt); 135 + clk_disable_unprepare(pm->venc_lt_sel); 136 + clk_disable_unprepare(pm->venc_sel); 137 + }
+26
drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.h
··· 1 + /* 2 + * Copyright (c) 2016 MediaTek Inc. 3 + * Author: Tiffany Lin <tiffany.lin@mediatek.com> 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + */ 14 + 15 + #ifndef _MTK_VCODEC_ENC_PM_H_ 16 + #define _MTK_VCODEC_ENC_PM_H_ 17 + 18 + #include "mtk_vcodec_drv.h" 19 + 20 + int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *dev); 21 + void mtk_vcodec_release_enc_pm(struct mtk_vcodec_dev *dev); 22 + 23 + void mtk_vcodec_enc_clock_on(struct mtk_vcodec_pm *pm); 24 + void mtk_vcodec_enc_clock_off(struct mtk_vcodec_pm *pm); 25 + 26 + #endif /* _MTK_VCODEC_ENC_PM_H_ */
+54
drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c
··· 1 + /* 2 + * Copyright (c) 2016 MediaTek Inc. 3 + * Author: Tiffany Lin <tiffany.lin@mediatek.com> 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + */ 14 + 15 + #include <linux/errno.h> 16 + #include <linux/wait.h> 17 + 18 + #include "mtk_vcodec_drv.h" 19 + #include "mtk_vcodec_intr.h" 20 + #include "mtk_vcodec_util.h" 21 + 22 + int mtk_vcodec_wait_for_done_ctx(struct mtk_vcodec_ctx *ctx, int command, 23 + unsigned int timeout_ms) 24 + { 25 + wait_queue_head_t *waitqueue; 26 + long timeout_jiff, ret; 27 + int status = 0; 28 + 29 + waitqueue = (wait_queue_head_t *)&ctx->queue; 30 + timeout_jiff = msecs_to_jiffies(timeout_ms); 31 + 32 + ret = wait_event_interruptible_timeout(*waitqueue, 33 + (ctx->int_cond && 34 + (ctx->int_type == command)), 35 + timeout_jiff); 36 + 37 + if (!ret) { 38 + status = -1; /* timeout */ 39 + mtk_v4l2_err("[%d] cmd=%d, ctx->type=%d, wait_event_interruptible_timeout time=%ums out %d %d!", 40 + ctx->id, ctx->type, command, timeout_ms, 41 + ctx->int_cond, ctx->int_type); 42 + } else if (-ERESTARTSYS == ret) { 43 + mtk_v4l2_err("[%d] cmd=%d, ctx->type=%d, wait_event_interruptible_timeout interrupted by a signal %d %d", 44 + ctx->id, ctx->type, command, ctx->int_cond, 45 + ctx->int_type); 46 + status = -1; 47 + } 48 + 49 + ctx->int_cond = 0; 50 + ctx->int_type = 0; 51 + 52 + return status; 53 + } 54 + EXPORT_SYMBOL(mtk_vcodec_wait_for_done_ctx);
+27
drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h
··· 1 + /* 2 + * Copyright (c) 2016 MediaTek Inc. 3 + * Author: Tiffany Lin <tiffany.lin@mediatek.com> 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + */ 14 + 15 + #ifndef _MTK_VCODEC_INTR_H_ 16 + #define _MTK_VCODEC_INTR_H_ 17 + 18 + #define MTK_INST_IRQ_RECEIVED 0x1 19 + #define MTK_INST_WORK_THREAD_ABORT_DONE 0x2 20 + 21 + struct mtk_vcodec_ctx; 22 + 23 + /* timeout is ms */ 24 + int mtk_vcodec_wait_for_done_ctx(struct mtk_vcodec_ctx *data, int command, 25 + unsigned int timeout_ms); 26 + 27 + #endif /* _MTK_VCODEC_INTR_H_ */
+94
drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c
··· 1 + /* 2 + * Copyright (c) 2016 MediaTek Inc. 3 + * Author: PC Chen <pc.chen@mediatek.com> 4 + * Tiffany Lin <tiffany.lin@mediatek.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + */ 15 + 16 + #include <linux/module.h> 17 + 18 + #include "mtk_vcodec_drv.h" 19 + #include "mtk_vcodec_util.h" 20 + #include "mtk_vpu.h" 21 + 22 + /* For encoder, this will enable logs in venc/*/ 23 + bool mtk_vcodec_dbg; 24 + EXPORT_SYMBOL(mtk_vcodec_dbg); 25 + 26 + /* The log level of v4l2 encoder or decoder driver. 27 + * That is, files under mtk-vcodec/. 28 + */ 29 + int mtk_v4l2_dbg_level; 30 + EXPORT_SYMBOL(mtk_v4l2_dbg_level); 31 + 32 + void __iomem *mtk_vcodec_get_reg_addr(struct mtk_vcodec_ctx *data, 33 + unsigned int reg_idx) 34 + { 35 + struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)data; 36 + 37 + if (!data || reg_idx >= NUM_MAX_VCODEC_REG_BASE) { 38 + mtk_v4l2_err("Invalid arguments, reg_idx=%d", reg_idx); 39 + return NULL; 40 + } 41 + return ctx->dev->reg_base[reg_idx]; 42 + } 43 + EXPORT_SYMBOL(mtk_vcodec_get_reg_addr); 44 + 45 + int mtk_vcodec_mem_alloc(struct mtk_vcodec_ctx *data, 46 + struct mtk_vcodec_mem *mem) 47 + { 48 + unsigned long size = mem->size; 49 + struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)data; 50 + struct device *dev = &ctx->dev->plat_dev->dev; 51 + 52 + mem->va = dma_alloc_coherent(dev, size, &mem->dma_addr, GFP_KERNEL); 53 + 54 + if (!mem->va) { 55 + mtk_v4l2_err("%s dma_alloc size=%ld failed!", dev_name(dev), 56 + size); 57 + return -ENOMEM; 58 + } 59 + 60 + memset(mem->va, 0, size); 61 + 62 + mtk_v4l2_debug(3, "[%d] - va = %p", ctx->id, mem->va); 63 + mtk_v4l2_debug(3, "[%d] - dma = 0x%lx", ctx->id, 64 + (unsigned long)mem->dma_addr); 65 + mtk_v4l2_debug(3, "[%d] size = 0x%lx", ctx->id, size); 66 + 67 + return 0; 68 + } 69 + EXPORT_SYMBOL(mtk_vcodec_mem_alloc); 70 + 71 + void mtk_vcodec_mem_free(struct mtk_vcodec_ctx *data, 72 + struct mtk_vcodec_mem *mem) 73 + { 74 + unsigned long size = mem->size; 75 + struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)data; 76 + struct device *dev = &ctx->dev->plat_dev->dev; 77 + 78 + if (!mem->va) { 79 + mtk_v4l2_err("%s dma_free size=%ld failed!", dev_name(dev), 80 + size); 81 + return; 82 + } 83 + 84 + dma_free_coherent(dev, size, mem->va, mem->dma_addr); 85 + mem->va = NULL; 86 + mem->dma_addr = 0; 87 + mem->size = 0; 88 + 89 + mtk_v4l2_debug(3, "[%d] - va = %p", ctx->id, mem->va); 90 + mtk_v4l2_debug(3, "[%d] - dma = 0x%lx", ctx->id, 91 + (unsigned long)mem->dma_addr); 92 + mtk_v4l2_debug(3, "[%d] size = 0x%lx", ctx->id, size); 93 + } 94 + EXPORT_SYMBOL(mtk_vcodec_mem_free);
+87
drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h
··· 1 + /* 2 + * Copyright (c) 2016 MediaTek Inc. 3 + * Author: PC Chen <pc.chen@mediatek.com> 4 + * Tiffany Lin <tiffany.lin@mediatek.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + */ 15 + 16 + #ifndef _MTK_VCODEC_UTIL_H_ 17 + #define _MTK_VCODEC_UTIL_H_ 18 + 19 + #include <linux/types.h> 20 + #include <linux/dma-direction.h> 21 + 22 + struct mtk_vcodec_mem { 23 + size_t size; 24 + void *va; 25 + dma_addr_t dma_addr; 26 + }; 27 + 28 + struct mtk_vcodec_ctx; 29 + 30 + extern int mtk_v4l2_dbg_level; 31 + extern bool mtk_vcodec_dbg; 32 + 33 + #define DEBUG 1 34 + 35 + #if defined(DEBUG) 36 + 37 + #define mtk_v4l2_debug(level, fmt, args...) \ 38 + do { \ 39 + if (mtk_v4l2_dbg_level >= level) \ 40 + pr_info("[MTK_V4L2] level=%d %s(),%d: " fmt "\n",\ 41 + level, __func__, __LINE__, ##args); \ 42 + } while (0) 43 + 44 + #define mtk_v4l2_err(fmt, args...) \ 45 + pr_err("[MTK_V4L2][ERROR] %s:%d: " fmt "\n", __func__, __LINE__, \ 46 + ##args) 47 + 48 + 49 + #define mtk_v4l2_debug_enter() mtk_v4l2_debug(3, "+") 50 + #define mtk_v4l2_debug_leave() mtk_v4l2_debug(3, "-") 51 + 52 + #define mtk_vcodec_debug(h, fmt, args...) \ 53 + do { \ 54 + if (mtk_vcodec_dbg) \ 55 + pr_info("[MTK_VCODEC][%d]: %s() " fmt "\n", \ 56 + ((struct mtk_vcodec_ctx *)h->ctx)->id, \ 57 + __func__, ##args); \ 58 + } while (0) 59 + 60 + #define mtk_vcodec_err(h, fmt, args...) \ 61 + pr_err("[MTK_VCODEC][ERROR][%d]: %s() " fmt "\n", \ 62 + ((struct mtk_vcodec_ctx *)h->ctx)->id, __func__, ##args) 63 + 64 + #define mtk_vcodec_debug_enter(h) mtk_vcodec_debug(h, "+") 65 + #define mtk_vcodec_debug_leave(h) mtk_vcodec_debug(h, "-") 66 + 67 + #else 68 + 69 + #define mtk_v4l2_debug(level, fmt, args...) 70 + #define mtk_v4l2_err(fmt, args...) 71 + #define mtk_v4l2_debug_enter() 72 + #define mtk_v4l2_debug_leave() 73 + 74 + #define mtk_vcodec_debug(h, fmt, args...) 75 + #define mtk_vcodec_err(h, fmt, args...) 76 + #define mtk_vcodec_debug_enter(h) 77 + #define mtk_vcodec_debug_leave(h) 78 + 79 + #endif 80 + 81 + void __iomem *mtk_vcodec_get_reg_addr(struct mtk_vcodec_ctx *data, 82 + unsigned int reg_idx); 83 + int mtk_vcodec_mem_alloc(struct mtk_vcodec_ctx *data, 84 + struct mtk_vcodec_mem *mem); 85 + void mtk_vcodec_mem_free(struct mtk_vcodec_ctx *data, 86 + struct mtk_vcodec_mem *mem); 87 + #endif /* _MTK_VCODEC_UTIL_H_ */
+62
drivers/media/platform/mtk-vcodec/venc_drv_base.h
··· 1 + /* 2 + * Copyright (c) 2016 MediaTek Inc. 3 + * Author: Daniel Hsiao <daniel.hsiao@mediatek.com> 4 + * Jungchang Tsao <jungchang.tsao@mediatek.com> 5 + * Tiffany Lin <tiffany.lin@mediatek.com> 6 + * 7 + * This program is free software; you can redistribute it and/or 8 + * modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + */ 17 + 18 + #ifndef _VENC_DRV_BASE_ 19 + #define _VENC_DRV_BASE_ 20 + 21 + #include "mtk_vcodec_drv.h" 22 + 23 + #include "venc_drv_if.h" 24 + 25 + struct venc_common_if { 26 + /** 27 + * (*init)() - initialize driver 28 + * @ctx: [in] mtk v4l2 context 29 + * @handle: [out] driver handle 30 + */ 31 + int (*init)(struct mtk_vcodec_ctx *ctx, unsigned long *handle); 32 + 33 + /** 34 + * (*encode)() - trigger encode 35 + * @handle: [in] driver handle 36 + * @opt: [in] encode option 37 + * @frm_buf: [in] frame buffer to store input frame 38 + * @bs_buf: [in] bitstream buffer to store output bitstream 39 + * @result: [out] encode result 40 + */ 41 + int (*encode)(unsigned long handle, enum venc_start_opt opt, 42 + struct venc_frm_buf *frm_buf, 43 + struct mtk_vcodec_mem *bs_buf, 44 + struct venc_done_result *result); 45 + 46 + /** 47 + * (*set_param)() - set driver's parameter 48 + * @handle: [in] driver handle 49 + * @type: [in] parameter type 50 + * @in: [in] buffer to store the parameter 51 + */ 52 + int (*set_param)(unsigned long handle, enum venc_set_param_type type, 53 + struct venc_enc_param *in); 54 + 55 + /** 56 + * (*deinit)() - deinitialize driver. 57 + * @handle: [in] driver handle 58 + */ 59 + int (*deinit)(unsigned long handle); 60 + }; 61 + 62 + #endif
+106
drivers/media/platform/mtk-vcodec/venc_drv_if.c
··· 1 + /* 2 + * Copyright (c) 2016 MediaTek Inc. 3 + * Author: Daniel Hsiao <daniel.hsiao@mediatek.com> 4 + * Jungchang Tsao <jungchang.tsao@mediatek.com> 5 + * Tiffany Lin <tiffany.lin@mediatek.com> 6 + * 7 + * This program is free software; you can redistribute it and/or 8 + * modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + */ 17 + 18 + #include <linux/interrupt.h> 19 + #include <linux/kernel.h> 20 + #include <linux/slab.h> 21 + 22 + #include "venc_drv_if.h" 23 + #include "mtk_vcodec_enc.h" 24 + #include "mtk_vcodec_enc_pm.h" 25 + #include "mtk_vpu.h" 26 + 27 + #include "venc_drv_base.h" 28 + 29 + int venc_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) 30 + { 31 + int ret = 0; 32 + 33 + switch (fourcc) { 34 + case V4L2_PIX_FMT_VP8: 35 + case V4L2_PIX_FMT_H264: 36 + default: 37 + return -EINVAL; 38 + } 39 + 40 + mtk_venc_lock(ctx); 41 + mtk_vcodec_enc_clock_on(&ctx->dev->pm); 42 + ret = ctx->enc_if->init(ctx, (unsigned long *)&ctx->drv_handle); 43 + mtk_vcodec_enc_clock_off(&ctx->dev->pm); 44 + mtk_venc_unlock(ctx); 45 + 46 + return ret; 47 + } 48 + 49 + int venc_if_set_param(struct mtk_vcodec_ctx *ctx, 50 + enum venc_set_param_type type, struct venc_enc_param *in) 51 + { 52 + int ret = 0; 53 + 54 + mtk_venc_lock(ctx); 55 + mtk_vcodec_enc_clock_on(&ctx->dev->pm); 56 + ret = ctx->enc_if->set_param(ctx->drv_handle, type, in); 57 + mtk_vcodec_enc_clock_off(&ctx->dev->pm); 58 + mtk_venc_unlock(ctx); 59 + 60 + return ret; 61 + } 62 + 63 + int venc_if_encode(struct mtk_vcodec_ctx *ctx, 64 + enum venc_start_opt opt, struct venc_frm_buf *frm_buf, 65 + struct mtk_vcodec_mem *bs_buf, 66 + struct venc_done_result *result) 67 + { 68 + int ret = 0; 69 + unsigned long flags; 70 + 71 + mtk_venc_lock(ctx); 72 + 73 + spin_lock_irqsave(&ctx->dev->irqlock, flags); 74 + ctx->dev->curr_ctx = ctx; 75 + spin_unlock_irqrestore(&ctx->dev->irqlock, flags); 76 + 77 + mtk_vcodec_enc_clock_on(&ctx->dev->pm); 78 + ret = ctx->enc_if->encode(ctx->drv_handle, opt, frm_buf, 79 + bs_buf, result); 80 + mtk_vcodec_enc_clock_off(&ctx->dev->pm); 81 + 82 + spin_lock_irqsave(&ctx->dev->irqlock, flags); 83 + ctx->dev->curr_ctx = NULL; 84 + spin_unlock_irqrestore(&ctx->dev->irqlock, flags); 85 + 86 + mtk_venc_unlock(ctx); 87 + return ret; 88 + } 89 + 90 + int venc_if_deinit(struct mtk_vcodec_ctx *ctx) 91 + { 92 + int ret = 0; 93 + 94 + if (ctx->drv_handle == 0) 95 + return 0; 96 + 97 + mtk_venc_lock(ctx); 98 + mtk_vcodec_enc_clock_on(&ctx->dev->pm); 99 + ret = ctx->enc_if->deinit(ctx->drv_handle); 100 + mtk_vcodec_enc_clock_off(&ctx->dev->pm); 101 + mtk_venc_unlock(ctx); 102 + 103 + ctx->drv_handle = 0; 104 + 105 + return ret; 106 + }
+163
drivers/media/platform/mtk-vcodec/venc_drv_if.h
··· 1 + /* 2 + * Copyright (c) 2016 MediaTek Inc. 3 + * Author: Daniel Hsiao <daniel.hsiao@mediatek.com> 4 + * Jungchang Tsao <jungchang.tsao@mediatek.com> 5 + * Tiffany Lin <tiffany.lin@mediatek.com> 6 + * 7 + * This program is free software; you can redistribute it and/or 8 + * modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + */ 17 + 18 + #ifndef _VENC_DRV_IF_H_ 19 + #define _VENC_DRV_IF_H_ 20 + 21 + #include "mtk_vcodec_drv.h" 22 + #include "mtk_vcodec_util.h" 23 + 24 + /* 25 + * enum venc_yuv_fmt - The type of input yuv format 26 + * (VPU related: If you change the order, you must also update the VPU codes.) 27 + * @VENC_YUV_FORMAT_I420: I420 YUV format 28 + * @VENC_YUV_FORMAT_YV12: YV12 YUV format 29 + * @VENC_YUV_FORMAT_NV12: NV12 YUV format 30 + * @VENC_YUV_FORMAT_NV21: NV21 YUV format 31 + */ 32 + enum venc_yuv_fmt { 33 + VENC_YUV_FORMAT_I420 = 3, 34 + VENC_YUV_FORMAT_YV12 = 5, 35 + VENC_YUV_FORMAT_NV12 = 6, 36 + VENC_YUV_FORMAT_NV21 = 7, 37 + }; 38 + 39 + /* 40 + * enum venc_start_opt - encode frame option used in venc_if_encode() 41 + * @VENC_START_OPT_ENCODE_SEQUENCE_HEADER: encode SPS/PPS for H264 42 + * @VENC_START_OPT_ENCODE_FRAME: encode normal frame 43 + */ 44 + enum venc_start_opt { 45 + VENC_START_OPT_ENCODE_SEQUENCE_HEADER, 46 + VENC_START_OPT_ENCODE_FRAME, 47 + }; 48 + 49 + /* 50 + * enum venc_set_param_type - The type of set parameter used in 51 + * venc_if_set_param() 52 + * (VPU related: If you change the order, you must also update the VPU codes.) 53 + * @VENC_SET_PARAM_ENC: set encoder parameters 54 + * @VENC_SET_PARAM_FORCE_INTRA: force an intra frame 55 + * @VENC_SET_PARAM_ADJUST_BITRATE: adjust bitrate (in bps) 56 + * @VENC_SET_PARAM_ADJUST_FRAMERATE: set frame rate 57 + * @VENC_SET_PARAM_GOP_SIZE: set IDR interval 58 + * @VENC_SET_PARAM_INTRA_PERIOD: set I frame interval 59 + * @VENC_SET_PARAM_SKIP_FRAME: set H264 skip one frame 60 + * @VENC_SET_PARAM_PREPEND_HEADER: set H264 prepend SPS/PPS before IDR 61 + * @VENC_SET_PARAM_TS_MODE: set VP8 temporal scalability mode 62 + */ 63 + enum venc_set_param_type { 64 + VENC_SET_PARAM_ENC, 65 + VENC_SET_PARAM_FORCE_INTRA, 66 + VENC_SET_PARAM_ADJUST_BITRATE, 67 + VENC_SET_PARAM_ADJUST_FRAMERATE, 68 + VENC_SET_PARAM_GOP_SIZE, 69 + VENC_SET_PARAM_INTRA_PERIOD, 70 + VENC_SET_PARAM_SKIP_FRAME, 71 + VENC_SET_PARAM_PREPEND_HEADER, 72 + VENC_SET_PARAM_TS_MODE, 73 + }; 74 + 75 + /* 76 + * struct venc_enc_prm - encoder settings for VENC_SET_PARAM_ENC used in 77 + * venc_if_set_param() 78 + * @input_fourcc: input yuv format 79 + * @h264_profile: V4L2 defined H.264 profile 80 + * @h264_level: V4L2 defined H.264 level 81 + * @width: image width 82 + * @height: image height 83 + * @buf_width: buffer width 84 + * @buf_height: buffer height 85 + * @frm_rate: frame rate in fps 86 + * @intra_period: intra frame period 87 + * @bitrate: target bitrate in bps 88 + * @gop_size: group of picture size 89 + */ 90 + struct venc_enc_param { 91 + enum venc_yuv_fmt input_yuv_fmt; 92 + unsigned int h264_profile; 93 + unsigned int h264_level; 94 + unsigned int width; 95 + unsigned int height; 96 + unsigned int buf_width; 97 + unsigned int buf_height; 98 + unsigned int frm_rate; 99 + unsigned int intra_period; 100 + unsigned int bitrate; 101 + unsigned int gop_size; 102 + }; 103 + 104 + /* 105 + * struct venc_frm_buf - frame buffer information used in venc_if_encode() 106 + * @fb_addr: plane frame buffer addresses 107 + */ 108 + struct venc_frm_buf { 109 + struct mtk_vcodec_mem fb_addr[MTK_VCODEC_MAX_PLANES]; 110 + }; 111 + 112 + /* 113 + * struct venc_done_result - This is return information used in venc_if_encode() 114 + * @bs_size: output bitstream size 115 + * @is_key_frm: output is key frame or not 116 + */ 117 + struct venc_done_result { 118 + unsigned int bs_size; 119 + bool is_key_frm; 120 + }; 121 + 122 + /* 123 + * venc_if_init - Create the driver handle 124 + * @ctx: device context 125 + * @fourcc: encoder input format 126 + * Return: 0 if creating handle successfully, otherwise it is failed. 127 + */ 128 + int venc_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc); 129 + 130 + /* 131 + * venc_if_deinit - Release the driver handle 132 + * @ctx: device context 133 + * Return: 0 if releasing handle successfully, otherwise it is failed. 134 + */ 135 + int venc_if_deinit(struct mtk_vcodec_ctx *ctx); 136 + 137 + /* 138 + * venc_if_set_param - Set parameter to driver 139 + * @ctx: device context 140 + * @type: parameter type 141 + * @in: input parameter 142 + * Return: 0 if setting param successfully, otherwise it is failed. 143 + */ 144 + int venc_if_set_param(struct mtk_vcodec_ctx *ctx, 145 + enum venc_set_param_type type, 146 + struct venc_enc_param *in); 147 + 148 + /* 149 + * venc_if_encode - Encode one frame 150 + * @ctx: device context 151 + * @opt: encode frame option 152 + * @frm_buf: input frame buffer information 153 + * @bs_buf: output bitstream buffer infomraiton 154 + * @result: encode result 155 + * Return: 0 if encoding frame successfully, otherwise it is failed. 156 + */ 157 + int venc_if_encode(struct mtk_vcodec_ctx *ctx, 158 + enum venc_start_opt opt, 159 + struct venc_frm_buf *frm_buf, 160 + struct mtk_vcodec_mem *bs_buf, 161 + struct venc_done_result *result); 162 + 163 + #endif /* _VENC_DRV_IF_H_ */
+210
drivers/media/platform/mtk-vcodec/venc_ipi_msg.h
··· 1 + /* 2 + * Copyright (c) 2016 MediaTek Inc. 3 + * Author: Jungchang Tsao <jungchang.tsao@mediatek.com> 4 + * Daniel Hsiao <daniel.hsiao@mediatek.com> 5 + * Tiffany Lin <tiffany.lin@mediatek.com> 6 + * 7 + * This program is free software; you can redistribute it and/or 8 + * modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + */ 17 + 18 + #ifndef _VENC_IPI_MSG_H_ 19 + #define _VENC_IPI_MSG_H_ 20 + 21 + #define AP_IPIMSG_VENC_BASE 0xC000 22 + #define VPU_IPIMSG_VENC_BASE 0xD000 23 + 24 + /** 25 + * enum venc_ipi_msg_id - message id between AP and VPU 26 + * (ipi stands for inter-processor interrupt) 27 + * @AP_IPIMSG_ENC_XXX: AP to VPU cmd message id 28 + * @VPU_IPIMSG_ENC_XXX_DONE: VPU ack AP cmd message id 29 + */ 30 + enum venc_ipi_msg_id { 31 + AP_IPIMSG_ENC_INIT = AP_IPIMSG_VENC_BASE, 32 + AP_IPIMSG_ENC_SET_PARAM, 33 + AP_IPIMSG_ENC_ENCODE, 34 + AP_IPIMSG_ENC_DEINIT, 35 + 36 + VPU_IPIMSG_ENC_INIT_DONE = VPU_IPIMSG_VENC_BASE, 37 + VPU_IPIMSG_ENC_SET_PARAM_DONE, 38 + VPU_IPIMSG_ENC_ENCODE_DONE, 39 + VPU_IPIMSG_ENC_DEINIT_DONE, 40 + }; 41 + 42 + /** 43 + * struct venc_ap_ipi_msg_init - AP to VPU init cmd structure 44 + * @msg_id: message id (AP_IPIMSG_XXX_ENC_INIT) 45 + * @reserved: reserved for future use. vpu is running in 32bit. Without 46 + * this reserved field, if kernel run in 64bit. this struct size 47 + * will be different between kernel and vpu 48 + * @venc_inst: AP encoder instance 49 + * (struct venc_vp8_inst/venc_h264_inst *) 50 + */ 51 + struct venc_ap_ipi_msg_init { 52 + uint32_t msg_id; 53 + uint32_t reserved; 54 + uint64_t venc_inst; 55 + }; 56 + 57 + /** 58 + * struct venc_ap_ipi_msg_set_param - AP to VPU set_param cmd structure 59 + * @msg_id: message id (AP_IPIMSG_XXX_ENC_SET_PARAM) 60 + * @vpu_inst_addr: VPU encoder instance addr 61 + * (struct venc_vp8_vsi/venc_h264_vsi *) 62 + * @param_id: parameter id (venc_set_param_type) 63 + * @data_item: number of items in the data array 64 + * @data[8]: data array to store the set parameters 65 + */ 66 + struct venc_ap_ipi_msg_set_param { 67 + uint32_t msg_id; 68 + uint32_t vpu_inst_addr; 69 + uint32_t param_id; 70 + uint32_t data_item; 71 + uint32_t data[8]; 72 + }; 73 + 74 + /** 75 + * struct venc_ap_ipi_msg_enc - AP to VPU enc cmd structure 76 + * @msg_id: message id (AP_IPIMSG_XXX_ENC_ENCODE) 77 + * @vpu_inst_addr: VPU encoder instance addr 78 + * (struct venc_vp8_vsi/venc_h264_vsi *) 79 + * @bs_mode: bitstream mode for h264 80 + * (H264_BS_MODE_SPS/H264_BS_MODE_PPS/H264_BS_MODE_FRAME) 81 + * @input_addr: pointer to input image buffer plane 82 + * @bs_addr: pointer to output bit stream buffer 83 + * @bs_size: bit stream buffer size 84 + */ 85 + struct venc_ap_ipi_msg_enc { 86 + uint32_t msg_id; 87 + uint32_t vpu_inst_addr; 88 + uint32_t bs_mode; 89 + uint32_t input_addr[3]; 90 + uint32_t bs_addr; 91 + uint32_t bs_size; 92 + }; 93 + 94 + /** 95 + * struct venc_ap_ipi_msg_deinit - AP to VPU deinit cmd structure 96 + * @msg_id: message id (AP_IPIMSG_XXX_ENC_DEINIT) 97 + * @vpu_inst_addr: VPU encoder instance addr 98 + * (struct venc_vp8_vsi/venc_h264_vsi *) 99 + */ 100 + struct venc_ap_ipi_msg_deinit { 101 + uint32_t msg_id; 102 + uint32_t vpu_inst_addr; 103 + }; 104 + 105 + /** 106 + * enum venc_ipi_msg_status - VPU ack AP cmd status 107 + */ 108 + enum venc_ipi_msg_status { 109 + VENC_IPI_MSG_STATUS_OK, 110 + VENC_IPI_MSG_STATUS_FAIL, 111 + }; 112 + 113 + /** 114 + * struct venc_vpu_ipi_msg_common - VPU ack AP cmd common structure 115 + * @msg_id: message id (VPU_IPIMSG_XXX_DONE) 116 + * @status: cmd status (venc_ipi_msg_status) 117 + * @venc_inst: AP encoder instance (struct venc_vp8_inst/venc_h264_inst *) 118 + */ 119 + struct venc_vpu_ipi_msg_common { 120 + uint32_t msg_id; 121 + uint32_t status; 122 + uint64_t venc_inst; 123 + }; 124 + 125 + /** 126 + * struct venc_vpu_ipi_msg_init - VPU ack AP init cmd structure 127 + * @msg_id: message id (VPU_IPIMSG_XXX_ENC_SET_PARAM_DONE) 128 + * @status: cmd status (venc_ipi_msg_status) 129 + * @venc_inst: AP encoder instance (struct venc_vp8_inst/venc_h264_inst *) 130 + * @vpu_inst_addr: VPU encoder instance addr 131 + * (struct venc_vp8_vsi/venc_h264_vsi *) 132 + * @reserved: reserved for future use. vpu is running in 32bit. Without 133 + * this reserved field, if kernel run in 64bit. this struct size 134 + * will be different between kernel and vpu 135 + */ 136 + struct venc_vpu_ipi_msg_init { 137 + uint32_t msg_id; 138 + uint32_t status; 139 + uint64_t venc_inst; 140 + uint32_t vpu_inst_addr; 141 + uint32_t reserved; 142 + }; 143 + 144 + /** 145 + * struct venc_vpu_ipi_msg_set_param - VPU ack AP set_param cmd structure 146 + * @msg_id: message id (VPU_IPIMSG_XXX_ENC_SET_PARAM_DONE) 147 + * @status: cmd status (venc_ipi_msg_status) 148 + * @venc_inst: AP encoder instance (struct venc_vp8_inst/venc_h264_inst *) 149 + * @param_id: parameter id (venc_set_param_type) 150 + * @data_item: number of items in the data array 151 + * @data[6]: data array to store the return result 152 + */ 153 + struct venc_vpu_ipi_msg_set_param { 154 + uint32_t msg_id; 155 + uint32_t status; 156 + uint64_t venc_inst; 157 + uint32_t param_id; 158 + uint32_t data_item; 159 + uint32_t data[6]; 160 + }; 161 + 162 + /** 163 + * enum venc_ipi_msg_enc_state - Type of encode state 164 + * VEN_IPI_MSG_ENC_STATE_FRAME: one frame being encoded 165 + * VEN_IPI_MSG_ENC_STATE_PART: bit stream buffer full 166 + * VEN_IPI_MSG_ENC_STATE_SKIP: encoded skip frame 167 + * VEN_IPI_MSG_ENC_STATE_ERROR: encounter error 168 + */ 169 + enum venc_ipi_msg_enc_state { 170 + VEN_IPI_MSG_ENC_STATE_FRAME, 171 + VEN_IPI_MSG_ENC_STATE_PART, 172 + VEN_IPI_MSG_ENC_STATE_SKIP, 173 + VEN_IPI_MSG_ENC_STATE_ERROR, 174 + }; 175 + 176 + /** 177 + * struct venc_vpu_ipi_msg_enc - VPU ack AP enc cmd structure 178 + * @msg_id: message id (VPU_IPIMSG_XXX_ENC_ENCODE_DONE) 179 + * @status: cmd status (venc_ipi_msg_status) 180 + * @venc_inst: AP encoder instance (struct venc_vp8_inst/venc_h264_inst *) 181 + * @state: encode state (venc_ipi_msg_enc_state) 182 + * @is_key_frm: whether the encoded frame is key frame 183 + * @bs_size: encoded bitstream size 184 + * @reserved: reserved for future use. vpu is running in 32bit. Without 185 + * this reserved field, if kernel run in 64bit. this struct size 186 + * will be different between kernel and vpu 187 + */ 188 + struct venc_vpu_ipi_msg_enc { 189 + uint32_t msg_id; 190 + uint32_t status; 191 + uint64_t venc_inst; 192 + uint32_t state; 193 + uint32_t is_key_frm; 194 + uint32_t bs_size; 195 + uint32_t reserved; 196 + }; 197 + 198 + /** 199 + * struct venc_vpu_ipi_msg_deinit - VPU ack AP deinit cmd structure 200 + * @msg_id: message id (VPU_IPIMSG_XXX_ENC_DEINIT_DONE) 201 + * @status: cmd status (venc_ipi_msg_status) 202 + * @venc_inst: AP encoder instance (struct venc_vp8_inst/venc_h264_inst *) 203 + */ 204 + struct venc_vpu_ipi_msg_deinit { 205 + uint32_t msg_id; 206 + uint32_t status; 207 + uint64_t venc_inst; 208 + }; 209 + 210 + #endif /* _VENC_IPI_MSG_H_ */