File Index
Files and directories
Sign in
FILE

venc_vpu_if.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/platform/mediatek/vcodec/encoder/venc_vpu_if.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (c) 2016 MediaTek Inc.
  4 * Author: PoChun Lin <pochun.lin@mediatek.com>
  5 */
  6
  7#include "mtk_vcodec_enc_drv.h"
  8#include "venc_ipi_msg.h"
  9#include "venc_vpu_if.h"
 10
 11static void handle_enc_init_msg(struct venc_vpu_inst *vpu, const void *data)
 12{
 13	const struct venc_vpu_ipi_msg_init *msg = data;
 14
 15	vpu->inst_addr = msg->vpu_inst_addr;
 16	vpu->vsi = mtk_vcodec_fw_map_dm_addr(vpu->ctx->dev->fw_handler,
 17					     msg->vpu_inst_addr);
 18
 19	/* Firmware version field value is unspecified on MT8173. */
 20	if (mtk_vcodec_fw_get_type(vpu->ctx->dev->fw_handler) == VPU)
 21		return;
 22
 23	/* Check firmware version. */
 24	mtk_venc_debug(vpu->ctx, "firmware version: 0x%x\n", msg->venc_abi_version);
 25	switch (msg->venc_abi_version) {
 26	case 1:
 27		break;
 28	default:
 29		mtk_venc_err(vpu->ctx, "unhandled firmware version 0x%x\n",
 30			     msg->venc_abi_version);
 31		vpu->failure = 1;
 32		break;
 33	}
 34}
 35
 36static void handle_enc_encode_msg(struct venc_vpu_inst *vpu, const void *data)
 37{
 38	const struct venc_vpu_ipi_msg_enc *msg = data;
 39
 40	vpu->state = msg->state;
 41	vpu->bs_size = msg->bs_size;
 42	vpu->is_key_frm = msg->is_key_frm;
 43}
 44
 45static bool vpu_enc_check_ap_inst(struct mtk_vcodec_enc_dev *enc_dev, struct venc_vpu_inst *vpu)
 46{
 47	struct mtk_vcodec_enc_ctx *ctx;
 48	unsigned long flags;
 49	int ret = false;
 50
 51	spin_lock_irqsave(&enc_dev->dev_ctx_lock, flags);
 52	list_for_each_entry(ctx, &enc_dev->ctx_list, list) {
 53		if (!IS_ERR_OR_NULL(ctx) && ctx->vpu_inst == vpu) {
 54			ret = true;
 55			break;
 56		}
 57	}
 58	spin_unlock_irqrestore(&enc_dev->dev_ctx_lock, flags);
 59
 60	return ret;
 61}
 62
 63static void vpu_enc_ipi_handler(void *data, unsigned int len, void *priv)
 64{
 65	struct mtk_vcodec_enc_dev *enc_dev;
 66	const struct venc_vpu_ipi_msg_common *msg = data;
 67	struct venc_vpu_inst *vpu;
 68
 69	enc_dev = (struct mtk_vcodec_enc_dev *)priv;
 70	vpu = (struct venc_vpu_inst *)(unsigned long)msg->venc_inst;
 71	if (!priv || !vpu) {
 72		pr_err(MTK_DBG_V4L2_STR "venc_inst is NULL, did the SCP hang or crash?");
 73		return;
 74	}
 75
 76	mtk_venc_debug(vpu->ctx, "msg_id %x inst %p status %d", msg->msg_id, vpu, msg->status);
 77	if (!vpu_enc_check_ap_inst(enc_dev, vpu) || msg->msg_id < VPU_IPIMSG_ENC_INIT_DONE ||
 78	    msg->msg_id > VPU_IPIMSG_ENC_DEINIT_DONE) {
 79		mtk_v4l2_venc_err(vpu->ctx, "venc msg id not correctly => 0x%x", msg->msg_id);
 80		vpu->failure = -EINVAL;
 81		goto error;
 82	}
 83
 84	vpu->failure = (msg->status != VENC_IPI_MSG_STATUS_OK);
 85	if (vpu->failure) {
 86		mtk_venc_err(vpu->ctx, "vpu enc status failure %d", vpu->failure);
 87		goto error;
 88	}
 89
 90	switch (msg->msg_id) {
 91	case VPU_IPIMSG_ENC_INIT_DONE:
 92		handle_enc_init_msg(vpu, data);
 93		break;
 94	case VPU_IPIMSG_ENC_SET_PARAM_DONE:
 95		break;
 96	case VPU_IPIMSG_ENC_ENCODE_DONE:
 97		handle_enc_encode_msg(vpu, data);
 98		break;
 99	case VPU_IPIMSG_ENC_DEINIT_DONE:
100		break;
101	default:
102		mtk_venc_err(vpu->ctx, "unknown msg id %x", msg->msg_id);
103		break;
104	}
105
106error:
107	vpu->signaled = 1;
108}
109
110static int vpu_enc_send_msg(struct venc_vpu_inst *vpu, void *msg,
111			    int len)
112{
113	int status;
114
115	if (!vpu->ctx->dev->fw_handler) {
116		mtk_venc_err(vpu->ctx, "inst dev is NULL");
117		return -EINVAL;
118	}
119
120	status = mtk_vcodec_fw_ipi_send(vpu->ctx->dev->fw_handler, vpu->id, msg,
121					len, 2000);
122	if (status) {
123		mtk_venc_err(vpu->ctx, "vpu_ipi_send msg_id %x len %d fail %d",
124			     *(uint32_t *)msg, len, status);
125		return -EINVAL;
126	}
127	if (vpu->failure)
128		return -EINVAL;
129
130	return 0;
131}
132
133int vpu_enc_init(struct venc_vpu_inst *vpu)
134{
135	int status;
136	struct venc_ap_ipi_msg_init out;
137
138	init_waitqueue_head(&vpu->wq_hd);
139	vpu->signaled = 0;
140	vpu->failure = 0;
141	vpu->ctx->vpu_inst = vpu;
142
143	status = mtk_vcodec_fw_ipi_register(vpu->ctx->dev->fw_handler, vpu->id,
144					    vpu_enc_ipi_handler, "venc",
145					    vpu->ctx->dev);
146
147	if (status) {
148		mtk_venc_err(vpu->ctx, "vpu_ipi_register fail %d", status);
149		return -EINVAL;
150	}
151
152	memset(&out, 0, sizeof(out));
153	out.msg_id = AP_IPIMSG_ENC_INIT;
154	out.venc_inst = (unsigned long)vpu;
155	if (vpu_enc_send_msg(vpu, &out, sizeof(out))) {
156		mtk_venc_err(vpu->ctx, "AP_IPIMSG_ENC_INIT fail");
157		return -EINVAL;
158	}
159
160	if (IS_ERR_OR_NULL(vpu->vsi)) {
161		mtk_venc_err(vpu->ctx, "invalid venc vsi");
162		return -EINVAL;
163	}
164
165	return 0;
166}
167
168static unsigned int venc_enc_param_crop_right(struct venc_vpu_inst *vpu,
169					      struct venc_enc_param *enc_prm)
170{
171	unsigned int img_crop_right = enc_prm->buf_width - enc_prm->width;
172
173	return img_crop_right % 16;
174}
175
176static unsigned int venc_enc_param_crop_bottom(struct venc_enc_param *enc_prm)
177{
178	return round_up(enc_prm->height, 16) - enc_prm->height;
179}
180
181static unsigned int venc_enc_param_num_mb(struct venc_enc_param *enc_prm)
182{
183	return DIV_ROUND_UP(enc_prm->width, 16) *
184	       DIV_ROUND_UP(enc_prm->height, 16);
185}
186
187int vpu_enc_set_param(struct venc_vpu_inst *vpu,
188		      enum venc_set_param_type id,
189		      struct venc_enc_param *enc_param)
190{
191	const bool is_ext = MTK_ENC_CTX_IS_EXT(vpu->ctx);
192	size_t msg_size = is_ext ?
193		sizeof(struct venc_ap_ipi_msg_set_param_ext) :
194		sizeof(struct venc_ap_ipi_msg_set_param);
195	struct venc_ap_ipi_msg_set_param_ext out;
196
197	mtk_venc_debug(vpu->ctx, "id %d ->", id);
198
199	memset(&out, 0, sizeof(out));
200	out.base.msg_id = AP_IPIMSG_ENC_SET_PARAM;
201	out.base.vpu_inst_addr = vpu->inst_addr;
202	out.base.param_id = id;
203	switch (id) {
204	case VENC_SET_PARAM_ENC:
205		if (is_ext) {
206			out.base.data_item = 3;
207			out.base.data[0] =
208				venc_enc_param_crop_right(vpu, enc_param);
209			out.base.data[1] =
210				venc_enc_param_crop_bottom(enc_param);
211			out.base.data[2] = venc_enc_param_num_mb(enc_param);
212		} else {
213			out.base.data_item = 0;
214		}
215		break;
216	case VENC_SET_PARAM_FORCE_INTRA:
217		out.base.data_item = 0;
218		break;
219	case VENC_SET_PARAM_ADJUST_BITRATE:
220		out.base.data_item = 1;
221		out.base.data[0] = enc_param->bitrate;
222		break;
223	case VENC_SET_PARAM_ADJUST_FRAMERATE:
224		out.base.data_item = 1;
225		out.base.data[0] = enc_param->frm_rate;
226		break;
227	case VENC_SET_PARAM_GOP_SIZE:
228		out.base.data_item = 1;
229		out.base.data[0] = enc_param->gop_size;
230		break;
231	case VENC_SET_PARAM_INTRA_PERIOD:
232		out.base.data_item = 1;
233		out.base.data[0] = enc_param->intra_period;
234		break;
235	case VENC_SET_PARAM_SKIP_FRAME:
236		out.base.data_item = 0;
237		break;
238	default:
239		mtk_venc_err(vpu->ctx, "id %d not supported", id);
240		return -EINVAL;
241	}
242	if (vpu_enc_send_msg(vpu, &out, msg_size)) {
243		mtk_venc_err(vpu->ctx, "AP_IPIMSG_ENC_SET_PARAM %d fail", id);
244		return -EINVAL;
245	}
246
247	mtk_venc_debug(vpu->ctx, "id %d <-", id);
248
249	return 0;
250}
251
252static int vpu_enc_encode_32bits(struct venc_vpu_inst *vpu,
253				 unsigned int bs_mode,
254				 struct venc_frm_buf *frm_buf,
255				 struct mtk_vcodec_mem *bs_buf,
256				 struct venc_frame_info *frame_info)
257{
258	const bool is_ext = MTK_ENC_CTX_IS_EXT(vpu->ctx);
259	size_t msg_size = is_ext ?
260		sizeof(struct venc_ap_ipi_msg_enc_ext) :
261		sizeof(struct venc_ap_ipi_msg_enc);
262	struct venc_ap_ipi_msg_enc_ext out;
263
264	mtk_venc_debug(vpu->ctx, "bs_mode %d ->", bs_mode);
265
266	memset(&out, 0, sizeof(out));
267	out.base.msg_id = AP_IPIMSG_ENC_ENCODE;
268	out.base.vpu_inst_addr = vpu->inst_addr;
269	out.base.bs_mode = bs_mode;
270	if (frm_buf) {
271		if ((frm_buf->fb_addr[0].dma_addr % 16 == 0) &&
272		    (frm_buf->fb_addr[1].dma_addr % 16 == 0) &&
273		    (frm_buf->fb_addr[2].dma_addr % 16 == 0)) {
274			out.base.input_addr[0] = frm_buf->fb_addr[0].dma_addr;
275			out.base.input_addr[1] = frm_buf->fb_addr[1].dma_addr;
276			out.base.input_addr[2] = frm_buf->fb_addr[2].dma_addr;
277		} else {
278			mtk_venc_err(vpu->ctx, "dma_addr not align to 16");
279			return -EINVAL;
280		}
281	}
282	if (bs_buf) {
283		out.base.bs_addr = bs_buf->dma_addr;
284		out.base.bs_size = bs_buf->size;
285	}
286	if (is_ext && frame_info) {
287		out.data_item = 3;
288		out.data[0] = frame_info->frm_count;
289		out.data[1] = frame_info->skip_frm_count;
290		out.data[2] = frame_info->frm_type;
291	}
292	if (vpu_enc_send_msg(vpu, &out, msg_size)) {
293		mtk_venc_err(vpu->ctx, "AP_IPIMSG_ENC_ENCODE %d fail", bs_mode);
294		return -EINVAL;
295	}
296
297	return 0;
298}
299
300static int vpu_enc_encode_34bits(struct venc_vpu_inst *vpu,
301				 unsigned int bs_mode,
302				 struct venc_frm_buf *frm_buf,
303				 struct mtk_vcodec_mem *bs_buf,
304				 struct venc_frame_info *frame_info)
305{
306	struct venc_ap_ipi_msg_enc_ext_34 out;
307	size_t msg_size = sizeof(struct venc_ap_ipi_msg_enc_ext_34);
308
309	mtk_venc_debug(vpu->ctx, "bs_mode %d ->", bs_mode);
310
311	memset(&out, 0, sizeof(out));
312	out.msg_id = AP_IPIMSG_ENC_ENCODE;
313	out.vpu_inst_addr = vpu->inst_addr;
314	out.bs_mode = bs_mode;
315
316	if (frm_buf) {
317		if ((frm_buf->fb_addr[0].dma_addr % 16 == 0) &&
318		    (frm_buf->fb_addr[1].dma_addr % 16 == 0) &&
319		    (frm_buf->fb_addr[2].dma_addr % 16 == 0)) {
320			out.input_addr[0] = frm_buf->fb_addr[0].dma_addr;
321			out.input_addr[1] = frm_buf->fb_addr[1].dma_addr;
322			out.input_addr[2] = frm_buf->fb_addr[2].dma_addr;
323		} else {
324			mtk_venc_err(vpu->ctx, "dma_addr not align to 16");
325			return -EINVAL;
326		}
327	}
328	if (bs_buf) {
329		out.bs_addr = bs_buf->dma_addr;
330		out.bs_size = bs_buf->size;
331	}
332	if (frame_info) {
333		out.data_item = 3;
334		out.data[0] = frame_info->frm_count;
335		out.data[1] = frame_info->skip_frm_count;
336		out.data[2] = frame_info->frm_type;
337	}
338	if (vpu_enc_send_msg(vpu, &out, msg_size)) {
339		mtk_venc_err(vpu->ctx, "AP_IPIMSG_ENC_ENCODE %d fail", bs_mode);
340		return -EINVAL;
341	}
342
343	return 0;
344}
345
346int vpu_enc_encode(struct venc_vpu_inst *vpu, unsigned int bs_mode,
347		   struct venc_frm_buf *frm_buf,
348		   struct mtk_vcodec_mem *bs_buf,
349		   struct venc_frame_info *frame_info)
350{
351	int ret;
352
353	if (MTK_ENC_IOVA_IS_34BIT(vpu->ctx))
354		ret = vpu_enc_encode_34bits(vpu, bs_mode,
355					    frm_buf, bs_buf, frame_info);
356	else
357		ret = vpu_enc_encode_32bits(vpu, bs_mode,
358					    frm_buf, bs_buf, frame_info);
359
360	if (ret)
361		return ret;
362
363	mtk_venc_debug(vpu->ctx, "bs_mode %d state %d size %d key_frm %d <-",
364		       bs_mode, vpu->state, vpu->bs_size, vpu->is_key_frm);
365
366	return 0;
367}
368
369int vpu_enc_deinit(struct venc_vpu_inst *vpu)
370{
371	struct venc_ap_ipi_msg_deinit out;
372
373	memset(&out, 0, sizeof(out));
374	out.msg_id = AP_IPIMSG_ENC_DEINIT;
375	out.vpu_inst_addr = vpu->inst_addr;
376	if (vpu_enc_send_msg(vpu, &out, sizeof(out))) {
377		mtk_venc_err(vpu->ctx, "AP_IPIMSG_ENC_DEINIT fail");
378		return -EINVAL;
379	}
380
381	return 0;
382}
~/ Read-only file preview.