From nobody Sat Dec 27 18:57:17 2025 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DD096381B2; Mon, 18 Dec 2023 11:40:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=quicinc.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com header.b="m9IQQP6A" Received: from pps.filterd (m0279862.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.24/8.17.1.24) with ESMTP id 3BIAslf2028697; Mon, 18 Dec 2023 11:40:05 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h= from:to:cc:subject:date:message-id:in-reply-to:references; s= qcppdkim1; bh=N8s5yYXwEHYgj9TDxp9LJSATexqdj9j0R5d1BKVwOlA=; b=m9 IQQP6A6smD7brqB/UO4AswFn7kCbqLzWTEuMvD95J0FVOlt4zkAqwshSbs5YfkHR Lq6exVdweHFAVEVsNEIvurkiuxOzeGfgfwA+5K35jmUYQnDz8Q36oDH9rfHotujt /mMq7h2UbSo4HF4bBxt6uTx0uzUuZvbSiScwAFwDYP+Ky8yMu8e+Sx/jValqFVFX tPa9gJAqMm5WDPnQFM68OdDM+2shC+CJjVyPJ26bd5R2A69yPjN1NMxw8zSt5h+A 2Pq7KSmeyZ+tDLrAQWX5D/pLQd6P3HCiy3DFddH9SZWC2Pe7oSCGY5t0Tbk5Yb0D uMV+WgnuOnmn8wunhPog== Received: from apblrppmta01.qualcomm.com (blr-bdr-fw-01_GlobalNAT_AllZones-Outside.qualcomm.com [103.229.18.19]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3v2ghdgnc2-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 18 Dec 2023 11:40:04 +0000 (GMT) Received: from pps.filterd (APBLRPPMTA01.qualcomm.com [127.0.0.1]) by APBLRPPMTA01.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTP id 3BIBe0x0004854; Mon, 18 Dec 2023 11:40:00 GMT Received: from pps.reinject (localhost [127.0.0.1]) by APBLRPPMTA01.qualcomm.com (PPS) with ESMTP id 3v14ym00ag-4; Mon, 18 Dec 2023 11:40:00 +0000 Received: from APBLRPPMTA01.qualcomm.com (APBLRPPMTA01.qualcomm.com [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 3BIBX8ra030072; Mon, 18 Dec 2023 11:36:09 GMT Received: from hu-sgudaval-hyd.qualcomm.com (hu-dikshita-hyd.qualcomm.com [10.213.110.13]) by APBLRPPMTA01.qualcomm.com (PPS) with ESMTP id 3BIBX8qi030067; Mon, 18 Dec 2023 11:36:09 +0000 Received: by hu-sgudaval-hyd.qualcomm.com (Postfix, from userid 347544) id 6E9B2238D; Mon, 18 Dec 2023 17:03:04 +0530 (+0530) From: Dikshita Agarwal To: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, stanimir.k.varbanov@gmail.com, quic_vgarodia@quicinc.com, agross@kernel.org, andersson@kernel.org, konrad.dybcio@linaro.org, mchehab@kernel.org, bryan.odonoghue@linaro.org Cc: linux-arm-msm@vger.kernel.org, quic_abhinavk@quicinc.com, Dikshita Agarwal Subject: [PATCH v2 32/34] media: iris: implement iris v4l2 ioctl ops supported by encoder Date: Mon, 18 Dec 2023 17:02:27 +0530 Message-Id: <1702899149-21321-33-git-send-email-quic_dikshita@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1702899149-21321-1-git-send-email-quic_dikshita@quicinc.com> References: <1702899149-21321-1-git-send-email-quic_dikshita@quicinc.com> X-QCInternal: smtphost X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-GUID: xg1w6oxGrxLf3k8OAReWWYDLMPGW0hk5 X-Proofpoint-ORIG-GUID: xg1w6oxGrxLf3k8OAReWWYDLMPGW0hk5 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.272,Aquarius:18.0.997,Hydra:6.0.619,FMLib:17.11.176.26 definitions=2023-12-09_01,2023-12-07_01,2023-05-22_02 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 bulkscore=0 spamscore=0 impostorscore=0 phishscore=0 clxscore=1015 adultscore=0 suspectscore=0 priorityscore=1501 malwarescore=0 mlxlogscore=999 mlxscore=0 lowpriorityscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2311290000 definitions=main-2312180084 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Implement all iris v4l2 ioctls ops supported by encoder. Add state checks to ensure ioctl are allowed in valid instance state only. Codec format can be changed by client during s_fmt. Update the v4l2 control values according to the updated codec format. Signed-off-by: Dikshita Agarwal --- drivers/media/platform/qcom/vcodec/iris/Makefile | 1 + .../media/platform/qcom/vcodec/iris/iris_core.h | 8 +- .../media/platform/qcom/vcodec/iris/iris_ctrls.c | 59 ++- .../media/platform/qcom/vcodec/iris/iris_helpers.c | 89 +++- .../media/platform/qcom/vcodec/iris/iris_helpers.h | 3 + .../platform/qcom/vcodec/iris/iris_instance.h | 5 + .../media/platform/qcom/vcodec/iris/iris_probe.c | 3 +- .../media/platform/qcom/vcodec/iris/iris_state.c | 5 +- .../media/platform/qcom/vcodec/iris/iris_vdec.c | 80 +--- .../media/platform/qcom/vcodec/iris/iris_venc.c | 525 +++++++++++++++++= ++++ .../media/platform/qcom/vcodec/iris/iris_venc.h | 24 + .../media/platform/qcom/vcodec/iris/iris_vidc.c | 415 ++++++++++++++-- .../platform/qcom/vcodec/iris/platform_common.h | 2 + .../platform/qcom/vcodec/iris/platform_sm8550.c | 1 + 14 files changed, 1088 insertions(+), 132 deletions(-) create mode 100644 drivers/media/platform/qcom/vcodec/iris/iris_venc.c create mode 100644 drivers/media/platform/qcom/vcodec/iris/iris_venc.h diff --git a/drivers/media/platform/qcom/vcodec/iris/Makefile b/drivers/med= ia/platform/qcom/vcodec/iris/Makefile index 4c8f8f6..b95d627 100644 --- a/drivers/media/platform/qcom/vcodec/iris/Makefile +++ b/drivers/media/platform/qcom/vcodec/iris/Makefile @@ -6,6 +6,7 @@ iris-objs +=3D iris_probe.o \ iris_vidc.o \ iris_vb2.o \ iris_vdec.o \ + iris_venc.o \ iris_state.o \ iris_ctrls.o \ iris_helpers.o \ diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_core.h b/drivers/= media/platform/qcom/vcodec/iris/iris_core.h index c56eb24..baced21 100644 --- a/drivers/media/platform/qcom/vcodec/iris/iris_core.h +++ b/drivers/media/platform/qcom/vcodec/iris/iris_core.h @@ -25,7 +25,8 @@ * @vdev_dec: iris video device structure for decoder * @vdev_enc: iris video device structure for encoder * @v4l2_file_ops: iris v4l2 file ops - * @v4l2_ioctl_ops: iris v4l2 ioctl ops + * @v4l2_ioctl_ops_dec: iris v4l2 ioctl ops for decoder + * @v4l2_ioctl_ops_enc: iris v4l2 ioctl ops for encoder * @bus_tbl: table of iris buses * @bus_count: count of iris buses * @power_domain_tbl: table of iris power domains @@ -52,6 +53,7 @@ * @packet_id: id of packet * @vpu_ops: a pointer to vpu ops * @session_ops: a pointer to session level ops + * @enc_codecs_count: supported codec count for encoder * @dec_codecs_count: supported codec count for decoder * @platform_data: a structure for platform data * @cap: an array for supported core capabilities @@ -69,7 +71,8 @@ struct iris_core { struct video_device *vdev_dec; struct video_device *vdev_enc; const struct v4l2_file_operations *v4l2_file_ops; - const struct v4l2_ioctl_ops *v4l2_ioctl_ops; + const struct v4l2_ioctl_ops *v4l2_ioctl_ops_dec; + const struct v4l2_ioctl_ops *v4l2_ioctl_ops_enc; struct bus_info *bus_tbl; u32 bus_count; struct power_domain_info *power_domain_tbl; @@ -97,6 +100,7 @@ struct iris_core { const struct vpu_ops *vpu_ops; const struct vpu_session_ops *session_ops; u32 dec_codecs_count; + u32 enc_codecs_count; struct platform_data *platform_data; struct plat_core_cap cap[CORE_CAP_MAX + 1]; struct plat_inst_caps *inst_caps; diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_ctrls.c b/drivers= /media/platform/qcom/vcodec/iris/iris_ctrls.c index a648cc1..af99ac73 100644 --- a/drivers/media/platform/qcom/vcodec/iris/iris_ctrls.c +++ b/drivers/media/platform/qcom/vcodec/iris/iris_ctrls.c @@ -217,7 +217,7 @@ static int set_dynamic_property(struct iris_inst *inst, return ret; } =20 -static int vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +static int iris_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { enum plat_inst_cap_type cap_id; struct iris_inst *inst =3D NULL; @@ -242,7 +242,7 @@ static int vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ct= rl) return ret; } =20 -static int vdec_op_s_ctrl(struct v4l2_ctrl *ctrl) +static int iris_op_s_ctrl(struct v4l2_ctrl *ctrl) { struct cap_entry *entry =3D NULL, *temp =3D NULL; struct list_head children_list, firmware_list; @@ -273,7 +273,8 @@ static int vdec_op_s_ctrl(struct v4l2_ctrl *ctrl) =20 cap[cap_id].flags |=3D CAP_FLAG_CLIENT_SET; =20 - if (!inst->vb2q_src->streaming) { + if ((inst->domain =3D=3D ENCODER && !inst->vb2q_dst->streaming) || + (inst->domain =3D=3D DECODER && !inst->vb2q_src->streaming)) { inst->cap[cap_id].value =3D ctrl->val; } else { ret =3D adjust_dynamic_property(inst, cap_id, ctrl, @@ -300,16 +301,16 @@ static int vdec_op_s_ctrl(struct v4l2_ctrl *ctrl) } =20 static const struct v4l2_ctrl_ops ctrl_ops =3D { - .s_ctrl =3D vdec_op_s_ctrl, - .g_volatile_ctrl =3D vdec_op_g_volatile_ctrl, + .s_ctrl =3D iris_op_s_ctrl, + .g_volatile_ctrl =3D iris_op_g_volatile_ctrl, }; =20 int ctrls_init(struct iris_inst *inst, bool init) { int num_ctrls =3D 0, ctrl_idx =3D 0; + u64 codecs_count, step_or_mask; struct plat_inst_cap *cap; struct iris_core *core; - u64 step_or_mask; int idx =3D 0; int ret =3D 0; =20 @@ -324,8 +325,11 @@ int ctrls_init(struct iris_inst *inst, bool init) return -EINVAL; =20 if (init) { + codecs_count =3D inst->domain =3D=3D ENCODER ? + core->enc_codecs_count : + core->dec_codecs_count; ret =3D v4l2_ctrl_handler_init(&inst->ctrl_handler, - INST_CAP_MAX * core->dec_codecs_count); + INST_CAP_MAX * codecs_count); if (ret) return ret; } @@ -451,29 +455,49 @@ static int update_inst_capability(struct plat_inst_ca= p *in, int iris_init_instance_caps(struct iris_core *core) { struct plat_inst_cap *inst_plat_cap_data =3D NULL; - u8 dec_codecs_count =3D 0; - int num_inst_cap; - u32 dec_valid_codecs; + u8 enc_codecs_count =3D 0, dec_codecs_count =3D 0; + u32 enc_valid_codecs, dec_valid_codecs; int i, j, check_bit =3D 0; + u8 codecs_count =3D 0; + int num_inst_cap; int ret =3D 0; =20 inst_plat_cap_data =3D core->platform_data->inst_cap_data; if (!inst_plat_cap_data) return -EINVAL; =20 + enc_valid_codecs =3D core->cap[ENC_CODECS].value; + enc_codecs_count =3D hweight32(enc_valid_codecs); + core->enc_codecs_count =3D enc_codecs_count; + dec_valid_codecs =3D core->cap[DEC_CODECS].value; dec_codecs_count =3D hweight32(dec_valid_codecs); core->dec_codecs_count =3D dec_codecs_count; =20 + codecs_count =3D enc_codecs_count + dec_codecs_count; core->inst_caps =3D devm_kzalloc(core->dev, - dec_codecs_count * sizeof(struct plat_inst_caps), + codecs_count * sizeof(struct plat_inst_caps), GFP_KERNEL); if (!core->inst_caps) return -ENOMEM; =20 - for (i =3D 0; i < dec_codecs_count; i++) { + for (i =3D 0; i < enc_codecs_count; i++) { + while (check_bit < (sizeof(enc_valid_codecs) * 8)) { + if (enc_valid_codecs & BIT(check_bit)) { + core->inst_caps[i].domain =3D ENCODER; + core->inst_caps[i].codec =3D enc_valid_codecs & + BIT(check_bit); + check_bit++; + break; + } + check_bit++; + } + } + + for (; i < codecs_count; i++) { while (check_bit < (sizeof(dec_valid_codecs) * 8)) { if (dec_valid_codecs & BIT(check_bit)) { + core->inst_caps[i].domain =3D DECODER; core->inst_caps[i].codec =3D dec_valid_codecs & BIT(check_bit); check_bit++; @@ -486,9 +510,9 @@ int iris_init_instance_caps(struct iris_core *core) num_inst_cap =3D core->platform_data->inst_cap_data_size; =20 for (i =3D 0; i < num_inst_cap; i++) { - for (j =3D 0; j < dec_codecs_count; j++) { - if ((inst_plat_cap_data[i].codec & - core->inst_caps[j].codec)) { + for (j =3D 0; j < codecs_count; j++) { + if ((inst_plat_cap_data[i].domain & core->inst_caps[j].domain) && + (inst_plat_cap_data[i].codec & core->inst_caps[j].codec)) { ret =3D update_inst_capability(&inst_plat_cap_data[i], &core->inst_caps[j]); if (ret) @@ -503,11 +527,14 @@ int iris_init_instance_caps(struct iris_core *core) int get_inst_capability(struct iris_inst *inst) { struct iris_core *core; + u32 codecs_count =3D 0; int i; =20 core =3D inst->core; =20 - for (i =3D 0; i < core->dec_codecs_count; i++) { + codecs_count =3D core->enc_codecs_count + core->dec_codecs_count; + + for (i =3D 0; i < codecs_count; i++) { if (core->inst_caps[i].codec =3D=3D inst->codec) { memcpy(&inst->cap[0], &core->inst_caps[i].cap[0], (INST_CAP_MAX + 1) * sizeof(struct plat_inst_cap)); diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_helpers.c b/drive= rs/media/platform/qcom/vcodec/iris/iris_helpers.c index d9d22e2..c84bb51 100644 --- a/drivers/media/platform/qcom/vcodec/iris/iris_helpers.c +++ b/drivers/media/platform/qcom/vcodec/iris/iris_helpers.c @@ -7,6 +7,7 @@ =20 #include "hfi_defines.h" #include "iris_core.h" +#include "iris_ctrls.h" #include "iris_helpers.h" #include "iris_hfi.h" #include "iris_hfi_packet.h" @@ -273,7 +274,7 @@ int close_session(struct iris_inst *inst) return ret; } =20 -static int check_core_mbps_mbpf(struct iris_inst *inst) +int check_core_mbps_mbpf(struct iris_inst *inst) { u32 mbpf =3D 0, mbps =3D 0, total_mbpf =3D 0, total_mbps =3D 0; struct iris_core *core; @@ -284,7 +285,9 @@ static int check_core_mbps_mbpf(struct iris_inst *inst) =20 mutex_lock(&core->lock); list_for_each_entry(instance, &core->instances, list) { - fps =3D inst->cap[QUEUED_RATE].value >> 16; + fps =3D max3(inst->cap[QUEUED_RATE].value >> 16, + inst->cap[FRAME_RATE].value >> 16, + inst->cap[OPERATING_RATE].value >> 16); mbpf =3D get_mbpf(inst); mbps =3D mbpf * fps; total_mbpf +=3D mbpf; @@ -814,6 +817,88 @@ int session_streamoff(struct iris_inst *inst, u32 plan= e) return ret; } =20 +int process_resume(struct iris_inst *inst) +{ + enum iris_inst_sub_state clear_sub_state =3D IRIS_INST_SUB_NONE; + int ret; + + if (inst->sub_state & IRIS_INST_SUB_DRC && + inst->sub_state & IRIS_INST_SUB_DRC_LAST) { + clear_sub_state =3D IRIS_INST_SUB_DRC | IRIS_INST_SUB_DRC_LAST; + + if (inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) { + ret =3D iris_hfi_resume(inst, INPUT_MPLANE, HFI_CMD_SETTINGS_CHANGE); + if (ret) + return ret; + clear_sub_state |=3D IRIS_INST_SUB_INPUT_PAUSE; + } + if (inst->sub_state & IRIS_INST_SUB_OUTPUT_PAUSE) { + ret =3D iris_hfi_resume(inst, OUTPUT_MPLANE, HFI_CMD_SETTINGS_CHANGE); + if (ret) + return ret; + clear_sub_state |=3D IRIS_INST_SUB_OUTPUT_PAUSE; + } + } else if (inst->sub_state & IRIS_INST_SUB_DRAIN && + inst->sub_state & IRIS_INST_SUB_DRAIN_LAST) { + clear_sub_state =3D IRIS_INST_SUB_DRAIN | IRIS_INST_SUB_DRAIN_LAST; + if (inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) { + ret =3D iris_hfi_resume(inst, INPUT_MPLANE, HFI_CMD_DRAIN); + if (ret) + return ret; + clear_sub_state |=3D IRIS_INST_SUB_INPUT_PAUSE; + } + if (inst->sub_state & IRIS_INST_SUB_OUTPUT_PAUSE) { + ret =3D iris_hfi_resume(inst, OUTPUT_MPLANE, HFI_CMD_DRAIN); + if (ret) + return ret; + clear_sub_state |=3D IRIS_INST_SUB_OUTPUT_PAUSE; + } + } + + ret =3D iris_inst_change_sub_state(inst, clear_sub_state, 0); + + return ret; +} + +int codec_change(struct iris_inst *inst, u32 v4l2_codec) +{ + bool session_init =3D false; + int ret; + + if (!inst->codec) + session_init =3D true; + + if (inst->codec && + ((inst->domain =3D=3D DECODER && inst->fmt_src->fmt.pix_mp.pixelforma= t =3D=3D v4l2_codec) || + (inst->domain =3D=3D ENCODER && inst->fmt_dst->fmt.pix_mp.pixelforma= t =3D=3D v4l2_codec))) + return 0; + + inst->codec =3D v4l2_codec_to_driver(inst, v4l2_codec); + if (!inst->codec) + return -EINVAL; + + if (inst->domain =3D=3D DECODER) + inst->fmt_src->fmt.pix_mp.pixelformat =3D v4l2_codec; + else if (inst->domain =3D=3D ENCODER) + inst->fmt_dst->fmt.pix_mp.pixelformat =3D v4l2_codec; + + ret =3D get_inst_capability(inst); + if (ret) + return ret; + + ret =3D ctrls_init(inst, session_init); + if (ret) + return ret; + + ret =3D update_buffer_count(inst, INPUT_MPLANE); + if (ret) + return ret; + + ret =3D update_buffer_count(inst, OUTPUT_MPLANE); + + return ret; +} + int iris_pm_get(struct iris_core *core) { int ret; diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_helpers.h b/drive= rs/media/platform/qcom/vcodec/iris/iris_helpers.h index c628b2e..39cec8c 100644 --- a/drivers/media/platform/qcom/vcodec/iris/iris_helpers.h +++ b/drivers/media/platform/qcom/vcodec/iris/iris_helpers.h @@ -41,6 +41,7 @@ enum codec_type v4l2_codec_to_driver(struct iris_inst *in= st, u32 v4l2_codec); u32 v4l2_colorformat_from_driver(struct iris_inst *inst, enum colorformat_= type colorformat); enum colorformat_type v4l2_colorformat_to_driver(struct iris_inst *inst, u= 32 v4l2_colorformat); struct vb2_queue *get_vb2q(struct iris_inst *inst, u32 type); +int check_core_mbps_mbpf(struct iris_inst *inst); int check_session_supported(struct iris_inst *inst); =20 struct iris_buffer *get_driver_buf(struct iris_inst *inst, u32 plane, u32 = index); @@ -51,6 +52,8 @@ int iris_vb2_buffer_done(struct iris_inst *inst, int iris_release_nonref_buffers(struct iris_inst *inst); void iris_destroy_buffers(struct iris_inst *inst); int session_streamoff(struct iris_inst *inst, u32 plane); +int process_resume(struct iris_inst *inst); +int codec_change(struct iris_inst *inst, u32 v4l2_codec); int iris_pm_get(struct iris_core *core); int iris_pm_put(struct iris_core *core, bool autosuspend); int iris_pm_get_put(struct iris_core *core); diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_instance.h b/driv= ers/media/platform/qcom/vcodec/iris/iris_instance.h index 70f4c7d..a1547c5 100644 --- a/drivers/media/platform/qcom/vcodec/iris/iris_instance.h +++ b/drivers/media/platform/qcom/vcodec/iris/iris_instance.h @@ -8,6 +8,7 @@ =20 #include =20 +#include "hfi_defines.h" #include "iris_buffer.h" #include "iris_common.h" #include "iris_core.h" @@ -29,6 +30,7 @@ * @fmt_dst: structure of v4l2_format for destination * @ctrl_handler: reference of v4l2 ctrl handler * @crop: structure of crop info + * @compose: structure of compose info * @packet: HFI packet * @packet_size: HFI packet size * @completions: structure of signal completions @@ -36,6 +38,7 @@ * @num_ctrls: supported number of controls * @caps_list: list head of capability * @codec: codec type + * @domain: domain type: encoder or decoder * @buffers: structure of buffer info * @fw_min_count: minimnum count of buffers needed by fw * @state: instance state @@ -70,6 +73,7 @@ struct iris_inst { struct v4l2_format *fmt_dst; struct v4l2_ctrl_handler ctrl_handler; struct rect_desc crop; + struct rect_desc compose; void *packet; u32 packet_size; struct completion completions[MAX_SIGNAL]; @@ -77,6 +81,7 @@ struct iris_inst { u32 num_ctrls; struct list_head caps_list; enum codec_type codec; + enum domain_type domain; struct iris_buffers_info buffers; u32 fw_min_count; enum iris_inst_state state; diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_probe.c b/drivers= /media/platform/qcom/vcodec/iris/iris_probe.c index b487e83..49d2701 100644 --- a/drivers/media/platform/qcom/vcodec/iris/iris_probe.c +++ b/drivers/media/platform/qcom/vcodec/iris/iris_probe.c @@ -42,13 +42,13 @@ static int iris_register_video_device(struct iris_core = *core, enum domain_type t =20 vdev->release =3D video_device_release; vdev->fops =3D core->v4l2_file_ops; - vdev->ioctl_ops =3D core->v4l2_ioctl_ops; vdev->vfl_dir =3D VFL_DIR_M2M; vdev->v4l2_dev =3D &core->v4l2_dev; vdev->device_caps =3D V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; =20 if (type =3D=3D DECODER) { strscpy(vdev->name, "qcom-iris-decoder", sizeof(vdev->name)); + vdev->ioctl_ops =3D core->v4l2_ioctl_ops_dec; =20 ret =3D video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret) @@ -57,6 +57,7 @@ static int iris_register_video_device(struct iris_core *c= ore, enum domain_type t core->vdev_dec =3D vdev; } else if (type =3D=3D ENCODER) { strscpy(vdev->name, "qcom-iris-encoder", sizeof(vdev->name)); + vdev->ioctl_ops =3D core->v4l2_ioctl_ops_enc; =20 ret =3D video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret) diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_state.c b/drivers= /media/platform/qcom/vcodec/iris/iris_state.c index 952ba2a..e853aec 100644 --- a/drivers/media/platform/qcom/vcodec/iris/iris_state.c +++ b/drivers/media/platform/qcom/vcodec/iris/iris_state.c @@ -198,8 +198,9 @@ bool allow_s_ctrl(struct iris_inst *inst, u32 cap_id) { return ((inst->state =3D=3D IRIS_INST_OPEN) || ((inst->cap[cap_id].flags & CAP_FLAG_DYNAMIC_ALLOWED) && - (inst->state =3D=3D IRIS_INST_INPUT_STREAMING || - inst->state =3D=3D IRIS_INST_STREAMING))); + ((inst->state =3D=3D IRIS_INST_INPUT_STREAMING && inst->domain =3D=3D D= ECODER) || + (inst->state =3D=3D IRIS_INST_OUTPUT_STREAMING && inst->domain =3D=3D = ENCODER) || + (inst->state =3D=3D IRIS_INST_STREAMING)))); } =20 int iris_inst_state_change_streamon(struct iris_inst *inst, u32 plane) diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_vdec.c b/drivers/= media/platform/qcom/vcodec/iris/iris_vdec.c index 371615e..300d0e9 100644 --- a/drivers/media/platform/qcom/vcodec/iris/iris_vdec.c +++ b/drivers/media/platform/qcom/vcodec/iris/iris_vdec.c @@ -22,39 +22,6 @@ struct vdec_prop_type_handle { int (*handle)(struct iris_inst *inst); }; =20 -static int vdec_codec_change(struct iris_inst *inst, u32 v4l2_codec) -{ - bool session_init =3D false; - int ret; - - if (!inst->codec) - session_init =3D true; - - if (inst->codec && inst->fmt_src->fmt.pix_mp.pixelformat =3D=3D v4l2_code= c) - return 0; - - inst->codec =3D v4l2_codec_to_driver(inst, v4l2_codec); - if (!inst->codec) - return -EINVAL; - - inst->fmt_src->fmt.pix_mp.pixelformat =3D v4l2_codec; - ret =3D get_inst_capability(inst); - if (ret) - return ret; - - ret =3D ctrls_init(inst, session_init); - if (ret) - return ret; - - ret =3D update_buffer_count(inst, INPUT_MPLANE); - if (ret) - return ret; - - ret =3D update_buffer_count(inst, OUTPUT_MPLANE); - - return ret; -} - int vdec_inst_init(struct iris_inst *inst) { struct v4l2_format *f; @@ -93,7 +60,7 @@ int vdec_inst_init(struct iris_inst *inst) inst->buffers.output.size =3D f->fmt.pix_mp.plane_fmt[0].sizeimage; inst->fw_min_count =3D 0; =20 - ret =3D vdec_codec_change(inst, inst->fmt_src->fmt.pix_mp.pixelformat); + ret =3D codec_change(inst, inst->fmt_src->fmt.pix_mp.pixelformat); =20 return ret; } @@ -233,7 +200,7 @@ int vdec_s_fmt(struct iris_inst *inst, struct v4l2_form= at *f) if (f->type =3D=3D INPUT_MPLANE) { if (inst->fmt_src->fmt.pix_mp.pixelformat !=3D f->fmt.pix_mp.pixelformat) { - ret =3D vdec_codec_change(inst, f->fmt.pix_mp.pixelformat); + ret =3D codec_change(inst, f->fmt.pix_mp.pixelformat); if (ret) return ret; } @@ -1304,49 +1271,6 @@ int vdec_qbuf(struct iris_inst *inst, struct vb2_buf= fer *vb2) return ret; } =20 -static int process_resume(struct iris_inst *inst) -{ - enum iris_inst_sub_state clear_sub_state =3D IRIS_INST_SUB_NONE; - int ret; - - if (inst->sub_state & IRIS_INST_SUB_DRC && - inst->sub_state & IRIS_INST_SUB_DRC_LAST) { - clear_sub_state =3D IRIS_INST_SUB_DRC | IRIS_INST_SUB_DRC_LAST; - - if (inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) { - ret =3D iris_hfi_resume(inst, INPUT_MPLANE, HFI_CMD_SETTINGS_CHANGE); - if (ret) - return ret; - clear_sub_state |=3D IRIS_INST_SUB_INPUT_PAUSE; - } - if (inst->sub_state & IRIS_INST_SUB_OUTPUT_PAUSE) { - ret =3D iris_hfi_resume(inst, OUTPUT_MPLANE, HFI_CMD_SETTINGS_CHANGE); - if (ret) - return ret; - clear_sub_state |=3D IRIS_INST_SUB_OUTPUT_PAUSE; - } - } else if (inst->sub_state & IRIS_INST_SUB_DRAIN && - inst->sub_state & IRIS_INST_SUB_DRAIN_LAST) { - clear_sub_state =3D IRIS_INST_SUB_DRAIN | IRIS_INST_SUB_DRAIN_LAST; - if (inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) { - ret =3D iris_hfi_resume(inst, INPUT_MPLANE, HFI_CMD_DRAIN); - if (ret) - return ret; - clear_sub_state |=3D IRIS_INST_SUB_INPUT_PAUSE; - } - if (inst->sub_state & IRIS_INST_SUB_OUTPUT_PAUSE) { - ret =3D iris_hfi_resume(inst, OUTPUT_MPLANE, HFI_CMD_DRAIN); - if (ret) - return ret; - clear_sub_state |=3D IRIS_INST_SUB_OUTPUT_PAUSE; - } - } - - ret =3D iris_inst_change_sub_state(inst, clear_sub_state, 0); - - return ret; -} - int vdec_start_cmd(struct iris_inst *inst) { int ret; diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_venc.c b/drivers/= media/platform/qcom/vcodec/iris/iris_venc.c new file mode 100644 index 0000000..802db40 --- /dev/null +++ b/drivers/media/platform/qcom/vcodec/iris/iris_venc.c @@ -0,0 +1,525 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights res= erved. + */ + +#include "hfi_defines.h" +#include "iris_buffer.h" +#include "iris_common.h" +#include "iris_ctrls.h" +#include "iris_helpers.h" +#include "iris_hfi.h" +#include "iris_hfi_packet.h" +#include "iris_power.h" +#include "iris_venc.h" + +int venc_inst_init(struct iris_inst *inst) +{ + struct v4l2_format *f; + int ret; + + inst->fmt_src =3D kzalloc(sizeof(*inst->fmt_src), GFP_KERNEL); + if (!inst->fmt_src) + return -ENOMEM; + + inst->fmt_dst =3D kzalloc(sizeof(*inst->fmt_dst), GFP_KERNEL); + if (!inst->fmt_dst) + return -ENOMEM; + + inst->vb2q_src =3D kzalloc(sizeof(*inst->vb2q_src), GFP_KERNEL); + if (!inst->vb2q_src) + return -ENOMEM; + + inst->vb2q_dst =3D kzalloc(sizeof(*inst->vb2q_dst), GFP_KERNEL); + if (!inst->vb2q_dst) + return -ENOMEM; + + f =3D inst->fmt_dst; + f->type =3D OUTPUT_MPLANE; + f->fmt.pix_mp.width =3D DEFAULT_WIDTH; + f->fmt.pix_mp.height =3D DEFAULT_HEIGHT; + f->fmt.pix_mp.pixelformat =3D V4L2_PIX_FMT_H264; + f->fmt.pix_mp.num_planes =3D 1; + f->fmt.pix_mp.plane_fmt[0].bytesperline =3D 0; + f->fmt.pix_mp.plane_fmt[0].sizeimage =3D iris_get_buffer_size(inst, BUF_O= UTPUT); + f->fmt.pix_mp.field =3D V4L2_FIELD_NONE; + f->fmt.pix_mp.colorspace =3D V4L2_COLORSPACE_DEFAULT; + f->fmt.pix_mp.xfer_func =3D V4L2_XFER_FUNC_DEFAULT; + f->fmt.pix_mp.ycbcr_enc =3D V4L2_YCBCR_ENC_DEFAULT; + f->fmt.pix_mp.quantization =3D V4L2_QUANTIZATION_DEFAULT; + inst->buffers.output.min_count =3D iris_get_buf_min_count(inst, BUF_OUTPU= T); + inst->buffers.output.actual_count =3D inst->buffers.output.min_count; + inst->buffers.output.size =3D f->fmt.pix_mp.plane_fmt[0].sizeimage; + + inst->crop.left =3D 0; + inst->crop.top =3D 0; + inst->crop.width =3D f->fmt.pix_mp.width; + inst->crop.height =3D f->fmt.pix_mp.height; + + inst->compose.left =3D 0; + inst->compose.top =3D 0; + inst->compose.width =3D f->fmt.pix_mp.width; + inst->compose.height =3D f->fmt.pix_mp.height; + + f =3D inst->fmt_src; + f->type =3D INPUT_MPLANE; + f->fmt.pix_mp.pixelformat =3D V4L2_PIX_FMT_QC08C; + f->fmt.pix_mp.width =3D DEFAULT_WIDTH; + f->fmt.pix_mp.height =3D DEFAULT_HEIGHT; + f->fmt.pix_mp.num_planes =3D 1; + f->fmt.pix_mp.plane_fmt[0].bytesperline =3D ALIGN(DEFAULT_WIDTH, 128); + f->fmt.pix_mp.plane_fmt[0].sizeimage =3D iris_get_buffer_size(inst, BUF_I= NPUT); + f->fmt.pix_mp.field =3D V4L2_FIELD_NONE; + f->fmt.pix_mp.colorspace =3D V4L2_COLORSPACE_DEFAULT; + f->fmt.pix_mp.xfer_func =3D V4L2_XFER_FUNC_DEFAULT; + f->fmt.pix_mp.ycbcr_enc =3D V4L2_YCBCR_ENC_DEFAULT; + f->fmt.pix_mp.quantization =3D V4L2_QUANTIZATION_DEFAULT; + inst->buffers.input.min_count =3D iris_get_buf_min_count(inst, BUF_INPUT); + inst->buffers.input.actual_count =3D inst->buffers.input.min_count; + inst->buffers.input.size =3D f->fmt.pix_mp.plane_fmt[0].sizeimage; + + inst->hfi_rc_type =3D HFI_RC_VBR_CFR; + inst->hfi_layer_type =3D HFI_HIER_P_SLIDING_WINDOW; + + ret =3D codec_change(inst, inst->fmt_dst->fmt.pix_mp.pixelformat); + + return ret; +} + +void venc_inst_deinit(struct iris_inst *inst) +{ + kfree(inst->fmt_dst); + kfree(inst->fmt_src); +} + +int venc_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f) +{ + struct iris_core *core; + u32 array[32] =3D {0}; + u32 i =3D 0; + + core =3D inst->core; + + if (f->type =3D=3D OUTPUT_MPLANE) { + u32 codecs =3D core->cap[ENC_CODECS].value; + u32 idx =3D 0; + + for (i =3D 0; i <=3D 31; i++) { + if (codecs & BIT(i)) { + if (idx >=3D ARRAY_SIZE(array)) + break; + array[idx] =3D codecs & BIT(i); + idx++; + } + } + if (!array[f->index]) + return -EINVAL; + f->pixelformat =3D v4l2_codec_from_driver(inst, array[f->index]); + if (!f->pixelformat) + return -EINVAL; + f->flags =3D V4L2_FMT_FLAG_COMPRESSED; + strscpy(f->description, "codec", sizeof(f->description)); + } else if (f->type =3D=3D INPUT_MPLANE) { + u32 formats =3D inst->cap[PIX_FMTS].step_or_mask; + u32 idx =3D 0; + + for (i =3D 0; i <=3D 31; i++) { + if (formats & BIT(i)) { + if (idx >=3D ARRAY_SIZE(array)) + break; + array[idx] =3D formats & BIT(i); + idx++; + } + } + if (!array[f->index]) + return -EINVAL; + f->pixelformat =3D v4l2_colorformat_from_driver(inst, array[f->index]); + if (!f->pixelformat) + return -EINVAL; + strscpy(f->description, "colorformat", sizeof(f->description)); + } + + memset(f->reserved, 0, sizeof(f->reserved)); + + return 0; +} + +int venc_try_fmt(struct iris_inst *inst, struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pixmp =3D &f->fmt.pix_mp; + u32 pix_fmt; + + memset(pixmp->reserved, 0, sizeof(pixmp->reserved)); + + if (f->type =3D=3D INPUT_MPLANE) { + pix_fmt =3D v4l2_colorformat_to_driver(inst, f->fmt.pix_mp.pixelformat); + if (!pix_fmt) { + f->fmt.pix_mp.pixelformat =3D inst->fmt_src->fmt.pix_mp.pixelformat; + f->fmt.pix_mp.width =3D inst->fmt_src->fmt.pix_mp.width; + f->fmt.pix_mp.height =3D inst->fmt_src->fmt.pix_mp.height; + } + } else if (f->type =3D=3D OUTPUT_MPLANE) { + pix_fmt =3D v4l2_codec_to_driver(inst, f->fmt.pix_mp.pixelformat); + if (!pix_fmt) { + f->fmt.pix_mp.width =3D inst->fmt_dst->fmt.pix_mp.width; + f->fmt.pix_mp.height =3D inst->fmt_dst->fmt.pix_mp.height; + f->fmt.pix_mp.pixelformat =3D inst->fmt_dst->fmt.pix_mp.pixelformat; + } + } else { + return -EINVAL; + } + + if (pixmp->field =3D=3D V4L2_FIELD_ANY) + pixmp->field =3D V4L2_FIELD_NONE; + pixmp->num_planes =3D 1; + + return 0; +} + +static int venc_s_fmt_output(struct iris_inst *inst, struct v4l2_format *f) +{ + struct v4l2_format *fmt; + enum codec_type codec; + u32 codec_align; + u32 width, height; + int ret =3D 0; + + venc_try_fmt(inst, f); + + fmt =3D inst->fmt_dst; + if (fmt->fmt.pix_mp.pixelformat !=3D f->fmt.pix_mp.pixelformat) { + ret =3D codec_change(inst, f->fmt.pix_mp.pixelformat); + if (ret) + return ret; + } + fmt->type =3D OUTPUT_MPLANE; + + codec =3D v4l2_codec_to_driver(inst, f->fmt.pix_mp.pixelformat); + + codec_align =3D (codec =3D=3D HEVC) ? 32 : 16; + width =3D inst->compose.width; + height =3D inst->compose.height; + if (inst->cap[ROTATION].value =3D=3D 90 || inst->cap[ROTATION].value =3D= =3D 270) { + width =3D inst->compose.height; + height =3D inst->compose.width; + } + fmt->fmt.pix_mp.width =3D ALIGN(width, codec_align); + fmt->fmt.pix_mp.height =3D ALIGN(height, codec_align); + fmt->fmt.pix_mp.num_planes =3D 1; + fmt->fmt.pix_mp.plane_fmt[0].bytesperline =3D 0; + fmt->fmt.pix_mp.plane_fmt[0].sizeimage =3D + iris_get_buffer_size(inst, BUF_OUTPUT); + if (f->fmt.pix_mp.colorspace !=3D V4L2_COLORSPACE_DEFAULT && + f->fmt.pix_mp.colorspace !=3D V4L2_COLORSPACE_REC709) + f->fmt.pix_mp.colorspace =3D V4L2_COLORSPACE_DEFAULT; + fmt->fmt.pix_mp.colorspace =3D f->fmt.pix_mp.colorspace; + fmt->fmt.pix_mp.xfer_func =3D f->fmt.pix_mp.xfer_func; + fmt->fmt.pix_mp.ycbcr_enc =3D f->fmt.pix_mp.ycbcr_enc; + fmt->fmt.pix_mp.quantization =3D f->fmt.pix_mp.quantization; + inst->buffers.output.min_count =3D iris_get_buf_min_count(inst, BUF_OUTPU= T); + if (inst->buffers.output.actual_count < + inst->buffers.output.min_count) { + inst->buffers.output.actual_count =3D + inst->buffers.output.min_count; + } + inst->buffers.output.size =3D + fmt->fmt.pix_mp.plane_fmt[0].sizeimage; + + memcpy(f, fmt, sizeof(struct v4l2_format)); + + return ret; +} + +static int venc_s_fmt_input(struct iris_inst *inst, struct v4l2_format *f) +{ + u32 pix_fmt, width, height, size, bytesperline; + struct v4l2_format *fmt, *output_fmt; + int ret =3D 0; + + venc_try_fmt(inst, f); + + pix_fmt =3D v4l2_colorformat_to_driver(inst, f->fmt.pix_mp.pixelformat); + inst->cap[PIX_FMTS].value =3D pix_fmt; + + width =3D f->fmt.pix_mp.width; + height =3D f->fmt.pix_mp.height; + + bytesperline =3D pix_fmt =3D=3D FMT_TP10C ? + ALIGN(ALIGN(f->fmt.pix_mp.width, 192) * 4 / 3, 256) : + ALIGN(f->fmt.pix_mp.width, 128); + + fmt =3D inst->fmt_src; + fmt->type =3D INPUT_MPLANE; + fmt->fmt.pix_mp.width =3D width; + fmt->fmt.pix_mp.height =3D height; + fmt->fmt.pix_mp.num_planes =3D 1; + fmt->fmt.pix_mp.pixelformat =3D f->fmt.pix_mp.pixelformat; + fmt->fmt.pix_mp.plane_fmt[0].bytesperline =3D bytesperline; + size =3D iris_get_buffer_size(inst, BUF_INPUT); + fmt->fmt.pix_mp.plane_fmt[0].sizeimage =3D size; + fmt->fmt.pix_mp.colorspace =3D f->fmt.pix_mp.colorspace; + fmt->fmt.pix_mp.xfer_func =3D f->fmt.pix_mp.xfer_func; + fmt->fmt.pix_mp.ycbcr_enc =3D f->fmt.pix_mp.ycbcr_enc; + fmt->fmt.pix_mp.quantization =3D f->fmt.pix_mp.quantization; + + output_fmt =3D inst->fmt_dst; + output_fmt->fmt.pix_mp.colorspace =3D fmt->fmt.pix_mp.colorspace; + output_fmt->fmt.pix_mp.xfer_func =3D fmt->fmt.pix_mp.xfer_func; + output_fmt->fmt.pix_mp.ycbcr_enc =3D fmt->fmt.pix_mp.ycbcr_enc; + output_fmt->fmt.pix_mp.quantization =3D fmt->fmt.pix_mp.quantization; + + inst->buffers.input.min_count =3D iris_get_buf_min_count(inst, BUF_INPUT); + if (inst->buffers.input.actual_count < + inst->buffers.input.min_count) { + inst->buffers.input.actual_count =3D + inst->buffers.input.min_count; + } + inst->buffers.input.size =3D size; + + if (f->fmt.pix_mp.width !=3D inst->crop.width || + f->fmt.pix_mp.height !=3D inst->crop.height) { + inst->crop.top =3D 0; + inst->crop.left =3D 0; + inst->crop.width =3D f->fmt.pix_mp.width; + inst->crop.height =3D f->fmt.pix_mp.height; + + inst->compose.top =3D 0; + inst->compose.left =3D 0; + inst->compose.width =3D f->fmt.pix_mp.width; + inst->compose.height =3D f->fmt.pix_mp.height; + + ret =3D venc_s_fmt_output(inst, output_fmt); + if (ret) + return ret; + } + + memcpy(f, fmt, sizeof(struct v4l2_format)); + + return ret; +} + +int venc_s_fmt(struct iris_inst *inst, struct v4l2_format *f) +{ + int ret; + + if (f->type =3D=3D INPUT_MPLANE) + ret =3D venc_s_fmt_input(inst, f); + else if (f->type =3D=3D OUTPUT_MPLANE) + ret =3D venc_s_fmt_output(inst, f); + else + ret =3D -EINVAL; + + return ret; +} + +int venc_s_selection(struct iris_inst *inst, struct v4l2_selection *s) +{ + struct v4l2_format *output_fmt; + int ret; + + if (s->type !=3D INPUT_MPLANE && s->type !=3D V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + switch (s->target) { + case V4L2_SEL_TGT_CROP: + if (s->r.left || s->r.top) { + s->r.left =3D 0; + s->r.top =3D 0; + } + if (s->r.width > inst->fmt_src->fmt.pix_mp.width) + s->r.width =3D inst->fmt_src->fmt.pix_mp.width; + + if (s->r.height > inst->fmt_src->fmt.pix_mp.height) + s->r.height =3D inst->fmt_src->fmt.pix_mp.height; + + inst->crop.left =3D s->r.left; + inst->crop.top =3D s->r.top; + inst->crop.width =3D s->r.width; + inst->crop.height =3D s->r.height; + inst->compose.left =3D inst->crop.left; + inst->compose.top =3D inst->crop.top; + inst->compose.width =3D inst->crop.width; + inst->compose.height =3D inst->crop.height; + output_fmt =3D inst->fmt_dst; + ret =3D venc_s_fmt_output(inst, output_fmt); + if (ret) + return ret; + break; + case V4L2_SEL_TGT_COMPOSE: + if (s->r.left < inst->crop.left) + s->r.left =3D inst->crop.left; + + if (s->r.top < inst->crop.top) + s->r.top =3D inst->crop.top; + + if (s->r.width > inst->crop.width) + s->r.width =3D inst->crop.width; + + if (s->r.height > inst->crop.height) + s->r.height =3D inst->crop.height; + inst->compose.left =3D s->r.left; + inst->compose.top =3D s->r.top; + inst->compose.width =3D s->r.width; + inst->compose.height =3D s->r.height; + + output_fmt =3D inst->fmt_dst; + ret =3D venc_s_fmt_output(inst, output_fmt); + if (ret) + return ret; + break; + default: + ret =3D -EINVAL; + break; + } + + return ret; +} + +int venc_s_param(struct iris_inst *inst, struct v4l2_streamparm *s_parm) +{ + struct v4l2_fract *timeperframe =3D NULL; + u32 q16_rate, max_rate, default_rate; + u64 us_per_frame =3D 0, input_rate =3D 0; + bool is_frame_rate =3D false; + int ret =3D 0; + + if (s_parm->type =3D=3D V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + timeperframe =3D &s_parm->parm.output.timeperframe; + max_rate =3D inst->cap[OPERATING_RATE].max >> 16; + default_rate =3D inst->cap[OPERATING_RATE].value >> 16; + s_parm->parm.output.capability =3D V4L2_CAP_TIMEPERFRAME; + } else { + timeperframe =3D &s_parm->parm.capture.timeperframe; + is_frame_rate =3D true; + max_rate =3D inst->cap[FRAME_RATE].max >> 16; + default_rate =3D inst->cap[FRAME_RATE].value >> 16; + s_parm->parm.capture.capability =3D V4L2_CAP_TIMEPERFRAME; + } + + if (!timeperframe->denominator || !timeperframe->numerator) { + if (!timeperframe->numerator) + timeperframe->numerator =3D 1; + if (!timeperframe->denominator) + timeperframe->denominator =3D default_rate; + } + + us_per_frame =3D timeperframe->numerator * (u64)USEC_PER_SEC; + us_per_frame =3D div64_u64(us_per_frame, timeperframe->denominator); + + if (!us_per_frame) { + ret =3D -EINVAL; + goto exit; + } + + input_rate =3D (u64)USEC_PER_SEC; + input_rate =3D div64_u64(input_rate, us_per_frame); + + q16_rate =3D (u32)input_rate << 16; + if (is_frame_rate) + inst->cap[FRAME_RATE].value =3D q16_rate; + else + inst->cap[OPERATING_RATE].value =3D q16_rate; + + if ((s_parm->type =3D=3D INPUT_MPLANE && inst->vb2q_src->streaming) || + (s_parm->type =3D=3D OUTPUT_MPLANE && inst->vb2q_dst->streaming)) { + ret =3D check_core_mbps_mbpf(inst); + if (ret) + goto reset_rate; + ret =3D input_rate > max_rate; + if (ret) { + ret =3D -ENOMEM; + goto reset_rate; + } + } + + if (is_frame_rate) + inst->cap[FRAME_RATE].flags |=3D CAP_FLAG_CLIENT_SET; + else + inst->cap[OPERATING_RATE].flags |=3D CAP_FLAG_CLIENT_SET; + + if (inst->vb2q_dst->streaming) { + ret =3D iris_hfi_set_property(inst, + HFI_PROP_FRAME_RATE, + HFI_HOST_FLAGS_NONE, + HFI_PORT_BITSTREAM, + HFI_PAYLOAD_Q16, + &q16_rate, + sizeof(u32)); + if (ret) + goto exit; + } + + return ret; + +reset_rate: + if (ret) { + if (is_frame_rate) + inst->cap[FRAME_RATE].value =3D default_rate << 16; + else + inst->cap[OPERATING_RATE].value =3D default_rate << 16; + } +exit: + return ret; +} + +int venc_g_param(struct iris_inst *inst, struct v4l2_streamparm *s_parm) +{ + struct v4l2_fract *timeperframe =3D NULL; + + if (s_parm->type =3D=3D V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + timeperframe =3D &s_parm->parm.output.timeperframe; + timeperframe->numerator =3D 1; + timeperframe->denominator =3D + inst->cap[OPERATING_RATE].value >> 16; + s_parm->parm.output.capability =3D V4L2_CAP_TIMEPERFRAME; + } else { + timeperframe =3D &s_parm->parm.capture.timeperframe; + timeperframe->numerator =3D 1; + timeperframe->denominator =3D + inst->cap[FRAME_RATE].value >> 16; + s_parm->parm.capture.capability =3D V4L2_CAP_TIMEPERFRAME; + } + + return 0; +} + +int venc_subscribe_event(struct iris_inst *inst, + const struct v4l2_event_subscription *sub) +{ + int ret; + + switch (sub->type) { + case V4L2_EVENT_EOS: + ret =3D v4l2_event_subscribe(&inst->fh, sub, MAX_EVENTS, NULL); + break; + case V4L2_EVENT_CTRL: + ret =3D v4l2_ctrl_subscribe_event(&inst->fh, sub); + break; + default: + return -EINVAL; + } + + return ret; +} + +int venc_start_cmd(struct iris_inst *inst) +{ + vb2_clear_last_buffer_dequeued(inst->vb2q_dst); + + return process_resume(inst); +} + +int venc_stop_cmd(struct iris_inst *inst) +{ + int ret; + + ret =3D iris_hfi_drain(inst, INPUT_MPLANE); + if (ret) + return ret; + + ret =3D iris_inst_change_sub_state(inst, 0, IRIS_INST_SUB_DRAIN); + + iris_scale_power(inst); + + return ret; +} diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_venc.h b/drivers/= media/platform/qcom/vcodec/iris/iris_venc.h new file mode 100644 index 0000000..24da63f --- /dev/null +++ b/drivers/media/platform/qcom/vcodec/iris/iris_venc.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights res= erved. + */ + +#ifndef _IRIS_VENC_H_ +#define _IRIS_VENC_H_ + +#include "iris_instance.h" + +int venc_inst_init(struct iris_inst *inst); +void venc_inst_deinit(struct iris_inst *inst); +int venc_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f); +int venc_try_fmt(struct iris_inst *inst, struct v4l2_format *f); +int venc_s_fmt(struct iris_inst *inst, struct v4l2_format *f); +int venc_s_selection(struct iris_inst *inst, struct v4l2_selection *s); +int venc_s_param(struct iris_inst *inst, struct v4l2_streamparm *s_parm); +int venc_g_param(struct iris_inst *inst, struct v4l2_streamparm *s_parm); +int venc_subscribe_event(struct iris_inst *inst, + const struct v4l2_event_subscription *sub); +int venc_start_cmd(struct iris_inst *inst); +int venc_stop_cmd(struct iris_inst *inst); + +#endif diff --git a/drivers/media/platform/qcom/vcodec/iris/iris_vidc.c b/drivers/= media/platform/qcom/vcodec/iris/iris_vidc.c index 437d6b4..aa19978 100644 --- a/drivers/media/platform/qcom/vcodec/iris/iris_vidc.c +++ b/drivers/media/platform/qcom/vcodec/iris/iris_vidc.c @@ -15,6 +15,7 @@ #include "iris_instance.h" #include "iris_power.h" #include "iris_vdec.h" +#include "iris_venc.h" #include "iris_vidc.h" #include "iris_vb2.h" =20 @@ -30,7 +31,11 @@ static int vidc_v4l2_fh_init(struct iris_inst *inst) if (inst->fh.vdev) return -EINVAL; =20 - v4l2_fh_init(&inst->fh, core->vdev_dec); + if (inst->domain =3D=3D ENCODER) + v4l2_fh_init(&inst->fh, core->vdev_enc); + else if (inst->domain =3D=3D DECODER) + v4l2_fh_init(&inst->fh, core->vdev_dec); + inst->fh.ctrl_handler =3D &inst->ctrl_handler; v4l2_fh_add(&inst->fh); =20 @@ -160,9 +165,20 @@ int vidc_open(struct file *filp) { struct iris_core *core =3D video_drvdata(filp); struct iris_inst *inst =3D NULL; + struct video_device *vdev; + u32 session_type =3D 0; int i =3D 0; int ret; =20 + vdev =3D video_devdata(filp); + if (strcmp(vdev->name, "qcom-iris-decoder") =3D=3D 0) + session_type =3D DECODER; + else if (strcmp(vdev->name, "qcom-iris-encoder") =3D=3D 0) + session_type =3D ENCODER; + + if (session_type !=3D DECODER && session_type !=3D ENCODER) + return -EINVAL; + ret =3D iris_pm_get(core); if (ret) return ret; @@ -182,6 +198,7 @@ int vidc_open(struct file *filp) } =20 inst->core =3D core; + inst->domain =3D session_type; inst->session_id =3D hash32_ptr(inst); inst->ipsc_properties_set =3D false; inst->opsc_properties_set =3D false; @@ -213,7 +230,12 @@ int vidc_open(struct file *filp) if (ret) goto fail_remove_session; =20 - vdec_inst_init(inst); + if (inst->domain =3D=3D DECODER) + ret =3D vdec_inst_init(inst); + else if (inst->domain =3D=3D ENCODER) + ret =3D venc_inst_init(inst); + if (ret) + goto fail_fh_deinit; =20 ret =3D vidc_vb2_queue_init(inst); if (ret) @@ -238,7 +260,11 @@ int vidc_open(struct file *filp) iris_core_deinit(core); vidc_vb2_queue_deinit(inst); fail_inst_deinit: - vdec_inst_deinit(inst); + if (inst->domain =3D=3D DECODER) + vdec_inst_deinit(inst); + else if (inst->domain =3D=3D ENCODER) + venc_inst_deinit(inst); +fail_fh_deinit: vidc_v4l2_fh_deinit(inst); fail_remove_session: vidc_remove_session(inst); @@ -264,7 +290,11 @@ int vidc_close(struct file *filp) core =3D inst->core; =20 v4l2_ctrl_handler_free(&inst->ctrl_handler); - vdec_inst_deinit(inst); + if (inst->domain =3D=3D DECODER) + vdec_inst_deinit(inst); + else if (inst->domain =3D=3D ENCODER) + venc_inst_deinit(inst); + mutex_lock(&inst->lock); iris_pm_get(core); close_session(inst); @@ -342,7 +372,7 @@ static __poll_t vidc_poll(struct file *filp, struct pol= l_table_struct *pt) static int vidc_enum_fmt(struct file *filp, void *fh, struct v4l2_fmtdesc = *f) { struct iris_inst *inst; - int ret; + int ret =3D 0; =20 inst =3D get_vidc_inst(filp, fh); if (!inst) @@ -354,7 +384,10 @@ static int vidc_enum_fmt(struct file *filp, void *fh, = struct v4l2_fmtdesc *f) goto unlock; } =20 - ret =3D vdec_enum_fmt(inst, f); + if (inst->domain =3D=3D DECODER) + ret =3D vdec_enum_fmt(inst, f); + else if (inst->domain =3D=3D ENCODER) + ret =3D venc_enum_fmt(inst, f); =20 unlock: mutex_unlock(&inst->lock); @@ -365,7 +398,7 @@ static int vidc_enum_fmt(struct file *filp, void *fh, s= truct v4l2_fmtdesc *f) static int vidc_try_fmt(struct file *filp, void *fh, struct v4l2_format *f) { struct iris_inst *inst; - int ret; + int ret =3D 0; =20 inst =3D get_vidc_inst(filp, fh); if (!inst) @@ -382,7 +415,10 @@ static int vidc_try_fmt(struct file *filp, void *fh, s= truct v4l2_format *f) goto unlock; } =20 - ret =3D vdec_try_fmt(inst, f); + if (inst->domain =3D=3D DECODER) + ret =3D vdec_try_fmt(inst, f); + else if (inst->domain =3D=3D ENCODER) + ret =3D venc_try_fmt(inst, f); =20 unlock: mutex_unlock(&inst->lock); @@ -393,7 +429,7 @@ static int vidc_try_fmt(struct file *filp, void *fh, st= ruct v4l2_format *f) static int vidc_s_fmt(struct file *filp, void *fh, struct v4l2_format *f) { struct iris_inst *inst; - int ret; + int ret =3D 0; =20 inst =3D get_vidc_inst(filp, fh); if (!inst) @@ -410,7 +446,10 @@ static int vidc_s_fmt(struct file *filp, void *fh, str= uct v4l2_format *f) goto unlock; } =20 - ret =3D vdec_s_fmt(inst, f); + if (inst->domain =3D=3D DECODER) + ret =3D vdec_s_fmt(inst, f); + else if (inst->domain =3D=3D ENCODER) + ret =3D venc_s_fmt(inst, f); =20 unlock: mutex_unlock(&inst->lock); @@ -488,6 +527,70 @@ static int vidc_enum_framesizes(struct file *filp, voi= d *fh, return ret; } =20 +static int vidc_enum_frameintervals(struct file *filp, void *fh, + struct v4l2_frmivalenum *fival) + +{ + enum colorformat_type colorfmt; + struct iris_inst *inst; + struct iris_core *core; + u32 fps, mbpf; + int ret =3D 0; + + inst =3D get_vidc_inst(filp, fh); + if (!inst || !fival) + return -EINVAL; + + mutex_lock(&inst->lock); + if (IS_SESSION_ERROR(inst)) { + ret =3D -EBUSY; + goto unlock; + } + + if (inst->domain =3D=3D DECODER) { + ret =3D -ENOTTY; + goto unlock; + } + + core =3D inst->core; + + if (fival->index) { + ret =3D -EINVAL; + goto unlock; + } + + colorfmt =3D v4l2_colorformat_to_driver(inst, fival->pixel_format); + if (colorfmt =3D=3D FMT_NONE) { + ret =3D -EINVAL; + goto unlock; + } + + if (fival->width > inst->cap[FRAME_WIDTH].max || + fival->width < inst->cap[FRAME_WIDTH].min || + fival->height > inst->cap[FRAME_HEIGHT].max || + fival->height < inst->cap[FRAME_HEIGHT].min) { + ret =3D -EINVAL; + goto unlock; + } + + mbpf =3D NUM_MBS_PER_FRAME(fival->height, fival->width); + fps =3D core->cap[MAX_MBPS].value / mbpf; + + fival->type =3D V4L2_FRMIVAL_TYPE_STEPWISE; + fival->stepwise.min.numerator =3D 1; + fival->stepwise.min.denominator =3D + min_t(u32, fps, inst->cap[FRAME_RATE].max); + fival->stepwise.max.numerator =3D 1; + fival->stepwise.max.denominator =3D 1; + fival->stepwise.step.numerator =3D 1; + fival->stepwise.step.denominator =3D inst->cap[FRAME_RATE].max; + +unlock: + mutex_unlock(&inst->lock); + + return ret; +} + static int vidc_reqbufs(struct file *filp, void *fh, struct v4l2_requestbu= ffers *b) { struct vb2_queue *vb2q =3D NULL; @@ -751,7 +854,11 @@ static int vidc_querycap(struct file *filp, void *fh, = struct v4l2_capability *ca strscpy(cap->driver, VIDC_DRV_NAME, sizeof(cap->driver)); strscpy(cap->bus_info, VIDC_BUS_NAME, sizeof(cap->bus_info)); memset(cap->reserved, 0, sizeof(cap->reserved)); - strscpy(cap->card, "iris_decoder", sizeof(cap->card)); + + if (inst->domain =3D=3D DECODER) + strscpy(cap->card, "iris_decoder", sizeof(cap->card)); + else if (inst->domain =3D=3D ENCODER) + strscpy(cap->card, "iris_encoder", sizeof(cap->card)); =20 unlock: mutex_unlock(&inst->lock); @@ -839,7 +946,7 @@ static int vidc_querymenu(struct file *filp, void *fh, = struct v4l2_querymenu *qm static int vidc_subscribe_event(struct v4l2_fh *fh, const struct v4l2_even= t_subscription *sub) { struct iris_inst *inst; - int ret; + int ret =3D 0; =20 inst =3D container_of(fh, struct iris_inst, fh); =20 @@ -849,7 +956,10 @@ static int vidc_subscribe_event(struct v4l2_fh *fh, co= nst struct v4l2_event_subs goto unlock; } =20 - ret =3D vdec_subscribe_event(inst, sub); + if (inst->domain =3D=3D DECODER) + ret =3D vdec_subscribe_event(inst, sub); + else if (inst->domain =3D=3D ENCODER) + ret =3D venc_subscribe_event(inst, sub); =20 unlock: mutex_unlock(&inst->lock); @@ -893,28 +1003,152 @@ static int vidc_g_selection(struct file *filp, void= *fh, struct v4l2_selection * goto unlock; } =20 - if (s->type !=3D OUTPUT_MPLANE && s->type !=3D V4L2_BUF_TYPE_VIDEO_CAPTUR= E) { + if (s->type !=3D OUTPUT_MPLANE && s->type !=3D V4L2_BUF_TYPE_VIDEO_CAPTUR= E && + inst->domain =3D=3D DECODER) { ret =3D -EINVAL; goto unlock; } =20 - switch (s->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_CROP_DEFAULT: - case V4L2_SEL_TGT_CROP: - case V4L2_SEL_TGT_COMPOSE_BOUNDS: - case V4L2_SEL_TGT_COMPOSE_PADDED: - case V4L2_SEL_TGT_COMPOSE_DEFAULT: - case V4L2_SEL_TGT_COMPOSE: - s->r.left =3D inst->crop.left; - s->r.top =3D inst->crop.top; - s->r.width =3D inst->crop.width; - s->r.height =3D inst->crop.height; - break; - default: + if (s->type !=3D INPUT_MPLANE && s->type !=3D V4L2_BUF_TYPE_VIDEO_OUTPUT = && + inst->domain =3D=3D ENCODER) { ret =3D -EINVAL; + goto unlock; } =20 + if (inst->domain =3D=3D DECODER) { + switch (s->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_COMPOSE_PADDED: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE: + s->r.left =3D inst->crop.left; + s->r.top =3D inst->crop.top; + s->r.width =3D inst->crop.width; + s->r.height =3D inst->crop.height; + break; + default: + ret =3D -EINVAL; + break; + } + } else if (inst->domain =3D=3D ENCODER) { + switch (s->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP: + s->r.left =3D inst->crop.left; + s->r.top =3D inst->crop.top; + s->r.width =3D inst->crop.width; + s->r.height =3D inst->crop.height; + break; + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_COMPOSE_PADDED: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE: + s->r.left =3D inst->compose.left; + s->r.top =3D inst->compose.top; + s->r.width =3D inst->compose.width; + s->r.height =3D inst->compose.height; + break; + default: + ret =3D -EINVAL; + break; + } + } + +unlock: + mutex_unlock(&inst->lock); + + return ret; +} + +static int vidc_s_selection(struct file *filp, void *fh, struct v4l2_selec= tion *s) +{ + struct iris_inst *inst; + int ret =3D 0; + + inst =3D get_vidc_inst(filp, fh); + if (!inst || !s) + return -EINVAL; + + mutex_lock(&inst->lock); + if (IS_SESSION_ERROR(inst)) { + ret =3D -EBUSY; + goto unlock; + } + if (inst->domain =3D=3D DECODER) { + ret =3D -EINVAL; + goto unlock; + } else if (inst->domain =3D=3D ENCODER) { + ret =3D venc_s_selection(inst, s); + } + +unlock: + mutex_unlock(&inst->lock); + + return ret; +} + +static int vidc_s_parm(struct file *filp, void *fh, struct v4l2_streamparm= *a) +{ + struct iris_inst *inst; + int ret =3D 0; + + inst =3D get_vidc_inst(filp, fh); + if (!inst || !a) + return -EINVAL; + + mutex_lock(&inst->lock); + if (IS_SESSION_ERROR(inst)) { + ret =3D -EBUSY; + goto unlock; + } + + if (a->type !=3D V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && + a->type !=3D V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + ret =3D -EINVAL; + goto unlock; + } + + if (inst->domain =3D=3D ENCODER) + ret =3D venc_s_param(inst, a); + else + ret =3D -EINVAL; + +unlock: + mutex_unlock(&inst->lock); + + return ret; +} + +static int vidc_g_parm(struct file *filp, void *fh, struct v4l2_streamparm= *a) +{ + struct iris_inst *inst; + int ret =3D 0; + + inst =3D get_vidc_inst(filp, fh); + if (!inst || !a) + return -EINVAL; + + mutex_lock(&inst->lock); + if (IS_SESSION_ERROR(inst)) { + ret =3D -EBUSY; + goto unlock; + } + + if (a->type !=3D V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && + a->type !=3D V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + ret =3D -EINVAL; + goto unlock; + } + + if (inst->domain =3D=3D ENCODER) + ret =3D venc_g_param(inst, a); + else + ret =3D -EINVAL; + unlock: mutex_unlock(&inst->lock); =20 @@ -955,6 +1189,39 @@ static int vidc_try_dec_cmd(struct file *filp, void *= fh, return ret; } =20 +static int vidc_try_enc_cmd(struct file *filp, void *fh, + struct v4l2_encoder_cmd *enc) +{ + struct iris_inst *inst; + int ret =3D 0; + + inst =3D get_vidc_inst(filp, fh); + if (!inst || !enc) + return -EINVAL; + + mutex_lock(&inst->lock); + if (IS_SESSION_ERROR(inst)) { + ret =3D -EBUSY; + goto unlock; + } + + if (inst->domain !=3D ENCODER) { + ret =3D -ENOTTY; + goto unlock; + } + + if (enc->cmd !=3D V4L2_ENC_CMD_STOP && enc->cmd !=3D V4L2_ENC_CMD_START) { + ret =3D -EINVAL; + goto unlock; + } + enc->flags =3D 0; + +unlock: + mutex_unlock(&inst->lock); + + return ret; +} + static int vidc_dec_cmd(struct file *filp, void *fh, struct v4l2_decoder_cmd *dec) { @@ -1002,6 +1269,60 @@ static int vidc_dec_cmd(struct file *filp, void *fh, return ret; } =20 +static int vidc_enc_cmd(struct file *filp, void *fh, + struct v4l2_encoder_cmd *enc) +{ + struct iris_inst *inst; + int ret =3D 0; + + inst =3D get_vidc_inst(filp, fh); + if (!inst || !enc) + return -EINVAL; + + mutex_lock(&inst->lock); + if (IS_SESSION_ERROR(inst)) { + ret =3D -EBUSY; + goto unlock; + } + + if (inst->domain !=3D ENCODER) { + ret =3D -ENOTTY; + goto unlock; + } + + if (enc->cmd !=3D V4L2_ENC_CMD_START && + enc->cmd !=3D V4L2_ENC_CMD_STOP) { + ret =3D -EINVAL; + goto unlock; + } + + if (enc->cmd =3D=3D V4L2_ENC_CMD_STOP && inst->state =3D=3D IRIS_INST_OPE= N) { + ret =3D 0; + goto unlock; + } + + if (!allow_cmd(inst, enc->cmd)) { + ret =3D -EBUSY; + goto unlock; + } + + ret =3D iris_pm_get(inst->core); + if (ret) + goto unlock; + + if (enc->cmd =3D=3D V4L2_ENC_CMD_START) + ret =3D venc_start_cmd(inst); + else if (enc->cmd =3D=3D V4L2_ENC_CMD_STOP) + ret =3D venc_stop_cmd(inst); + + iris_pm_put(inst->core, true); + +unlock: + mutex_unlock(&inst->lock); + + return ret; +} + static struct v4l2_file_operations v4l2_file_ops =3D { .owner =3D THIS_MODULE, .open =3D vidc_open, @@ -1027,7 +1348,7 @@ static struct vb2_mem_ops iris_vb2_mem_ops =3D { .unmap_dmabuf =3D iris_vb2_unmap_dmabuf, }; =20 -static const struct v4l2_ioctl_ops v4l2_ioctl_ops =3D { +static const struct v4l2_ioctl_ops v4l2_ioctl_ops_dec =3D { .vidioc_enum_fmt_vid_cap =3D vidc_enum_fmt, .vidioc_enum_fmt_vid_out =3D vidc_enum_fmt, .vidioc_try_fmt_vid_cap_mplane =3D vidc_try_fmt, @@ -1055,12 +1376,44 @@ static const struct v4l2_ioctl_ops v4l2_ioctl_ops = =3D { .vidioc_decoder_cmd =3D vidc_dec_cmd, }; =20 +static const struct v4l2_ioctl_ops v4l2_ioctl_ops_enc =3D { + .vidioc_enum_fmt_vid_cap =3D vidc_enum_fmt, + .vidioc_enum_fmt_vid_out =3D vidc_enum_fmt, + .vidioc_try_fmt_vid_cap_mplane =3D vidc_try_fmt, + .vidioc_try_fmt_vid_out_mplane =3D vidc_try_fmt, + .vidioc_s_fmt_vid_cap_mplane =3D vidc_s_fmt, + .vidioc_s_fmt_vid_out_mplane =3D vidc_s_fmt, + .vidioc_g_fmt_vid_cap_mplane =3D vidc_g_fmt, + .vidioc_g_fmt_vid_out_mplane =3D vidc_g_fmt, + .vidioc_enum_framesizes =3D vidc_enum_framesizes, + .vidioc_enum_frameintervals =3D vidc_enum_frameintervals, + .vidioc_reqbufs =3D vidc_reqbufs, + .vidioc_querybuf =3D vidc_querybuf, + .vidioc_create_bufs =3D vidc_create_bufs, + .vidioc_prepare_buf =3D vidc_prepare_buf, + .vidioc_qbuf =3D vidc_qbuf, + .vidioc_dqbuf =3D vidc_dqbuf, + .vidioc_streamon =3D vidc_streamon, + .vidioc_streamoff =3D vidc_streamoff, + .vidioc_querycap =3D vidc_querycap, + .vidioc_queryctrl =3D vidc_queryctrl, + .vidioc_querymenu =3D vidc_querymenu, + .vidioc_subscribe_event =3D vidc_subscribe_event, + .vidioc_unsubscribe_event =3D vidc_unsubscribe_event, + .vidioc_g_selection =3D vidc_g_selection, + .vidioc_s_selection =3D vidc_s_selection, + .vidioc_s_parm =3D vidc_s_parm, + .vidioc_g_parm =3D vidc_g_parm, + .vidioc_try_encoder_cmd =3D vidc_try_enc_cmd, + .vidioc_encoder_cmd =3D vidc_enc_cmd, +}; + int init_ops(struct iris_core *core) { core->v4l2_file_ops =3D &v4l2_file_ops; core->vb2_ops =3D &iris_vb2_ops; core->vb2_mem_ops =3D &iris_vb2_mem_ops; - core->v4l2_ioctl_ops =3D &v4l2_ioctl_ops; - + core->v4l2_ioctl_ops_dec =3D &v4l2_ioctl_ops_dec; + core->v4l2_ioctl_ops_enc =3D &v4l2_ioctl_ops_enc; return 0; } diff --git a/drivers/media/platform/qcom/vcodec/iris/platform_common.h b/dr= ivers/media/platform/qcom/vcodec/iris/platform_common.h index 443894c..effecbb 100644 --- a/drivers/media/platform/qcom/vcodec/iris/platform_common.h +++ b/drivers/media/platform/qcom/vcodec/iris/platform_common.h @@ -115,6 +115,7 @@ struct iris_inst_power { enum plat_core_cap_type { CORE_CAP_NONE =3D 0, DEC_CODECS, + ENC_CODECS, MAX_SESSION_COUNT, MAX_MBPF, MAX_MBPS, @@ -249,6 +250,7 @@ struct plat_inst_cap { =20 struct plat_inst_caps { enum codec_type codec; + enum domain_type domain; struct plat_inst_cap cap[INST_CAP_MAX + 1]; }; =20 diff --git a/drivers/media/platform/qcom/vcodec/iris/platform_sm8550.c b/dr= ivers/media/platform/qcom/vcodec/iris/platform_sm8550.c index 6d5192a..ef0aad7 100644 --- a/drivers/media/platform/qcom/vcodec/iris/platform_sm8550.c +++ b/drivers/media/platform/qcom/vcodec/iris/platform_sm8550.c @@ -63,6 +63,7 @@ static struct color_format_info color_format_data_sm8550[= ] =3D { =20 static struct plat_core_cap core_data_sm8550[] =3D { {DEC_CODECS, H264 | HEVC | VP9}, + {ENC_CODECS, H264 | HEVC}, {MAX_SESSION_COUNT, 16}, {MAX_MBPF, 278528}, /* ((8192x4352)/256) * 2 */ {MAX_MBPS, 7833600}, /* max_load 7680x4320@60fps */ --=20 2.7.4