From patchwork Mon Jan 10 08:34:28 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?WXVuZmVpIERvbmcgKOiRo+S6kemjnik=?= X-Patchwork-Id: 531016 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B2939C4332F for ; Mon, 10 Jan 2022 08:35:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240912AbiAJIfm (ORCPT ); Mon, 10 Jan 2022 03:35:42 -0500 Received: from mailgw01.mediatek.com ([60.244.123.138]:50560 "EHLO mailgw01.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S241379AbiAJIev (ORCPT ); Mon, 10 Jan 2022 03:34:51 -0500 X-UUID: c7b7e9cf2a9c45708ace9b1060dd4acd-20220110 X-UUID: c7b7e9cf2a9c45708ace9b1060dd4acd-20220110 Received: from mtkmbs10n2.mediatek.inc [(172.21.101.183)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 353680647; Mon, 10 Jan 2022 16:34:48 +0800 Received: from mtkexhb02.mediatek.inc (172.21.101.103) by mtkmbs10n2.mediatek.inc (172.21.101.183) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.2.792.3; Mon, 10 Jan 2022 16:34:47 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkexhb02.mediatek.inc (172.21.101.103) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Mon, 10 Jan 2022 16:34:46 +0800 Received: from localhost.localdomain (10.17.3.154) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Mon, 10 Jan 2022 16:34:45 +0800 From: Yunfei Dong To: Yunfei Dong , Alexandre Courbot , Hans Verkuil , "Tzung-Bi Shih" , Tiffany Lin , Andrew-CT Chen , Mauro Carvalho Chehab , Rob Herring , Matthias Brugger , Tomasz Figa CC: George Sun , Xiaoyong Lu , Hsin-Yi Wang , Fritz Koenig , Dafna Hirschfeld , Benjamin Gaignard , Daniel Vetter , dri-devel , Irui Wang , AngeloGioacchino Del Regno , Steve Cho , , , , , , , Subject: [PATCH v4, 01/15] media: mtk-vcodec: Add vdec enable/disable hardware helpers Date: Mon, 10 Jan 2022 16:34:28 +0800 Message-ID: <20220110083442.32604-2-yunfei.dong@mediatek.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220110083442.32604-1-yunfei.dong@mediatek.com> References: <20220110083442.32604-1-yunfei.dong@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Lock, power and clock are highly coupled operations. Adds vdec enable/disable hardware helpers and uses them. Signed-off-by: Yunfei Dong Reviewed-by: Tzung-Bi Shih --- .../platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 5 - .../platform/mtk-vcodec/mtk_vcodec_dec_pm.c | 168 +++++++++++------- .../platform/mtk-vcodec/mtk_vcodec_dec_pm.h | 6 +- .../media/platform/mtk-vcodec/vdec_drv_if.c | 20 +-- .../platform/mtk-vcodec/vdec_msg_queue.c | 2 + 5 files changed, 117 insertions(+), 84 deletions(-) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c index d44894fa2f6e..fc3e272d2059 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c @@ -195,9 +195,6 @@ static int fops_vcodec_open(struct file *file) mtk_vcodec_dec_set_default_params(ctx); if (v4l2_fh_is_singular(&ctx->fh)) { - ret = mtk_vcodec_dec_pw_on(dev, MTK_VDEC_LAT0); - if (ret < 0) - goto err_load_fw; /* * Does nothing if firmware was already loaded. */ @@ -254,8 +251,6 @@ static int fops_vcodec_release(struct file *file) v4l2_m2m_ctx_release(ctx->m2m_ctx); mtk_vcodec_dec_release(ctx); - if (v4l2_fh_is_singular(&ctx->fh)) - mtk_vcodec_dec_pw_off(dev, MTK_VDEC_LAT0); v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->ctrl_hdl); diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c index b9f5ef979c69..c2ed79bce686 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c @@ -80,74 +80,31 @@ int mtk_vcodec_init_dec_clk(struct platform_device *pdev, } EXPORT_SYMBOL_GPL(mtk_vcodec_init_dec_clk); -int mtk_vcodec_dec_pw_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx) +static int mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm) { - struct mtk_vdec_hw_dev *subdev_dev; - struct mtk_vcodec_pm *pm; int ret; - if (vdec_dev->vdec_pdata->is_subdev_supported) { - subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx); - if (!subdev_dev) { - mtk_v4l2_err("Failed to get hw dev\n"); - return -EINVAL; - } - pm = &subdev_dev->pm; - } else { - pm = &vdec_dev->pm; - } - ret = pm_runtime_resume_and_get(pm->dev); if (ret) mtk_v4l2_err("pm_runtime_resume_and_get fail %d", ret); return ret; } -EXPORT_SYMBOL_GPL(mtk_vcodec_dec_pw_on); -void mtk_vcodec_dec_pw_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx) +static void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm) { - struct mtk_vdec_hw_dev *subdev_dev; - struct mtk_vcodec_pm *pm; int ret; - if (vdec_dev->vdec_pdata->is_subdev_supported) { - subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx); - if (!subdev_dev) { - mtk_v4l2_err("Failed to get hw dev\n"); - return; - } - pm = &subdev_dev->pm; - } else { - pm = &vdec_dev->pm; - } - ret = pm_runtime_put_sync(pm->dev); if (ret) mtk_v4l2_err("pm_runtime_put_sync fail %d", ret); } -EXPORT_SYMBOL_GPL(mtk_vcodec_dec_pw_off); -void mtk_vcodec_dec_clock_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx) +static void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm) { - struct mtk_vdec_hw_dev *subdev_dev; - struct mtk_vcodec_pm *pm; struct mtk_vcodec_clk *dec_clk; int ret, i; - if (vdec_dev->vdec_pdata->is_subdev_supported) { - subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx); - if (!subdev_dev) { - mtk_v4l2_err("Failed to get hw dev\n"); - return; - } - pm = &subdev_dev->pm; - enable_irq(subdev_dev->dec_irq); - } else { - pm = &vdec_dev->pm; - enable_irq(vdec_dev->dec_irq); - } - dec_clk = &pm->vdec_clk; for (i = 0; i < dec_clk->clk_num; i++) { ret = clk_prepare_enable(dec_clk->clk_info[i].vcodec_clk); @@ -169,31 +126,120 @@ void mtk_vcodec_dec_clock_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx) for (i -= 1; i >= 0; i--) clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk); } -EXPORT_SYMBOL_GPL(mtk_vcodec_dec_clock_on); -void mtk_vcodec_dec_clock_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx) +static void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm) { - struct mtk_vdec_hw_dev *subdev_dev; - struct mtk_vcodec_pm *pm; struct mtk_vcodec_clk *dec_clk; int i; + dec_clk = &pm->vdec_clk; + mtk_smi_larb_put(pm->larbvdec); + for (i = dec_clk->clk_num - 1; i >= 0; i--) + clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk); +} + +static void mtk_vcodec_dec_enable_irq(struct mtk_vcodec_dev *vdec_dev, int hw_idx) + { + struct mtk_vdec_hw_dev *subdev_dev; + + if (!test_bit(hw_idx, vdec_dev->subdev_bitmap)) + return; + if (vdec_dev->vdec_pdata->is_subdev_supported) { subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx); - if (!subdev_dev) { + if (subdev_dev) + enable_irq(subdev_dev->dec_irq); + else + mtk_v4l2_err("Failed to get hw dev\n"); + } else { + enable_irq(vdec_dev->dec_irq); + } +} + +static void mtk_vcodec_dec_disable_irq(struct mtk_vcodec_dev *vdec_dev, int hw_idx) +{ + struct mtk_vdec_hw_dev *subdev_dev; + + if (!test_bit(hw_idx, vdec_dev->subdev_bitmap)) + return; + + if (vdec_dev->vdec_pdata->is_subdev_supported) { + subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx); + if (subdev_dev) + disable_irq(subdev_dev->dec_irq); + else mtk_v4l2_err("Failed to get hw dev\n"); - return; - } - pm = &subdev_dev->pm; - disable_irq(subdev_dev->dec_irq); } else { - pm = &vdec_dev->pm; disable_irq(vdec_dev->dec_irq); } +} - dec_clk = &pm->vdec_clk; - mtk_smi_larb_put(pm->larbvdec); - for (i = dec_clk->clk_num - 1; i >= 0; i--) - clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk); +static struct mtk_vcodec_pm *mtk_vcodec_dec_get_pm(struct mtk_vcodec_dev *vdec_dev, + int hw_idx) +{ + struct mtk_vdec_hw_dev *subdev_dev; + + if (!test_bit(hw_idx, vdec_dev->subdev_bitmap)) + return NULL; + + if (vdec_dev->vdec_pdata->is_subdev_supported) { + subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx); + if (subdev_dev) + return &subdev_dev->pm; + + mtk_v4l2_err("Failed to get hw dev\n"); + return NULL; + } + + return &vdec_dev->pm; +} + +static void mtk_vcodec_dec_child_dev_on(struct mtk_vcodec_dev *vdec_dev, + int hw_idx) +{ + struct mtk_vcodec_pm *pm; + + pm = mtk_vcodec_dec_get_pm(vdec_dev, hw_idx); + if (pm) { + mtk_vcodec_dec_pw_on(pm); + mtk_vcodec_dec_clock_on(pm); + } +} + +static void mtk_vcodec_dec_child_dev_off(struct mtk_vcodec_dev *vdec_dev, + int hw_idx) +{ + struct mtk_vcodec_pm *pm; + + pm = mtk_vcodec_dec_get_pm(vdec_dev, hw_idx); + if (pm) { + mtk_vcodec_dec_clock_off(pm); + mtk_vcodec_dec_pw_off(pm); + } +} + +void mtk_vcodec_dec_enable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx) +{ + mutex_lock(&ctx->dev->dec_mutex[hw_idx]); + + if (IS_VDEC_LAT_ARCH(ctx->dev->vdec_pdata->hw_arch) && + hw_idx == MTK_VDEC_CORE) + mtk_vcodec_dec_child_dev_on(ctx->dev, MTK_VDEC_LAT0); + mtk_vcodec_dec_child_dev_on(ctx->dev, hw_idx); + + mtk_vcodec_dec_enable_irq(ctx->dev, hw_idx); +} +EXPORT_SYMBOL_GPL(mtk_vcodec_dec_enable_hardware); + +void mtk_vcodec_dec_disable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx) +{ + mtk_vcodec_dec_disable_irq(ctx->dev, hw_idx); + + mtk_vcodec_dec_child_dev_off(ctx->dev, hw_idx); + if (IS_VDEC_LAT_ARCH(ctx->dev->vdec_pdata->hw_arch) && + hw_idx == MTK_VDEC_CORE) + mtk_vcodec_dec_child_dev_off(ctx->dev, MTK_VDEC_LAT0); + + mutex_unlock(&ctx->dev->dec_mutex[hw_idx]); } -EXPORT_SYMBOL_GPL(mtk_vcodec_dec_clock_off); +EXPORT_SYMBOL_GPL(mtk_vcodec_dec_disable_hardware); diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h index c4121df9764f..b420739b373d 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h @@ -12,9 +12,7 @@ int mtk_vcodec_init_dec_clk(struct platform_device *pdev, struct mtk_vcodec_pm *pm); -int mtk_vcodec_dec_pw_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx); -void mtk_vcodec_dec_pw_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx); -void mtk_vcodec_dec_clock_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx); -void mtk_vcodec_dec_clock_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx); +void mtk_vcodec_dec_enable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx); +void mtk_vcodec_dec_disable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx); #endif /* _MTK_VCODEC_DEC_PM_H_ */ diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c index 05a5b240e906..c93dd0ea3537 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c @@ -38,11 +38,9 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) return -EINVAL; } - mtk_vdec_lock(ctx); - mtk_vcodec_dec_clock_on(ctx->dev, ctx->hw_id); + mtk_vcodec_dec_enable_hardware(ctx, ctx->hw_id); ret = ctx->dec_if->init(ctx); - mtk_vcodec_dec_clock_off(ctx->dev, ctx->hw_id); - mtk_vdec_unlock(ctx); + mtk_vcodec_dec_disable_hardware(ctx, ctx->hw_id); return ret; } @@ -70,15 +68,11 @@ int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs, if (!ctx->drv_handle) return -EIO; - mtk_vdec_lock(ctx); - + mtk_vcodec_dec_enable_hardware(ctx, ctx->hw_id); mtk_vcodec_set_curr_ctx(ctx->dev, ctx, ctx->hw_id); - mtk_vcodec_dec_clock_on(ctx->dev, ctx->hw_id); ret = ctx->dec_if->decode(ctx->drv_handle, bs, fb, res_chg); - mtk_vcodec_dec_clock_off(ctx->dev, ctx->hw_id); mtk_vcodec_set_curr_ctx(ctx->dev, NULL, ctx->hw_id); - - mtk_vdec_unlock(ctx); + mtk_vcodec_dec_disable_hardware(ctx, ctx->hw_id); return ret; } @@ -103,11 +97,9 @@ void vdec_if_deinit(struct mtk_vcodec_ctx *ctx) if (!ctx->drv_handle) return; - mtk_vdec_lock(ctx); - mtk_vcodec_dec_clock_on(ctx->dev, ctx->hw_id); + mtk_vcodec_dec_enable_hardware(ctx, ctx->hw_id); ctx->dec_if->deinit(ctx->drv_handle); - mtk_vcodec_dec_clock_off(ctx->dev, ctx->hw_id); - mtk_vdec_unlock(ctx); + mtk_vcodec_dec_disable_hardware(ctx, ctx->hw_id); ctx->drv_handle = NULL; } diff --git a/drivers/media/platform/mtk-vcodec/vdec_msg_queue.c b/drivers/media/platform/mtk-vcodec/vdec_msg_queue.c index 576e08200a10..900d04fd4e66 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_msg_queue.c +++ b/drivers/media/platform/mtk-vcodec/vdec_msg_queue.c @@ -212,11 +212,13 @@ static void vdec_msg_queue_core_work(struct work_struct *work) return; ctx = lat_buf->ctx; + mtk_vcodec_dec_enable_hardware(ctx, MTK_VDEC_CORE); mtk_vcodec_set_curr_ctx(dev, ctx, MTK_VDEC_CORE); lat_buf->core_decode(lat_buf); mtk_vcodec_set_curr_ctx(dev, NULL, MTK_VDEC_CORE); + mtk_vcodec_dec_disable_hardware(ctx, MTK_VDEC_CORE); vdec_msg_queue_qbuf(&ctx->msg_queue.lat_ctx, lat_buf); if (!list_empty(&ctx->msg_queue.lat_ctx.ready_queue)) { From patchwork Mon Jan 10 08:34:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?WXVuZmVpIERvbmcgKOiRo+S6kemjnik=?= X-Patchwork-Id: 531015 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2540CC4332F for ; Mon, 10 Jan 2022 08:35:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241270AbiAJIfu (ORCPT ); Mon, 10 Jan 2022 03:35:50 -0500 Received: from mailgw02.mediatek.com ([210.61.82.184]:52604 "EHLO mailgw02.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S241401AbiAJIe4 (ORCPT ); Mon, 10 Jan 2022 03:34:56 -0500 X-UUID: 6300b06f1fac464fa6cc25a6e74fd4cb-20220110 X-UUID: 6300b06f1fac464fa6cc25a6e74fd4cb-20220110 Received: from mtkexhb01.mediatek.inc [(172.21.101.102)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 1744730731; Mon, 10 Jan 2022 16:34:53 +0800 Received: from mtkexhb02.mediatek.inc (172.21.101.103) by mtkmbs10n1.mediatek.inc (172.21.101.34) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.2.792.15; Mon, 10 Jan 2022 16:34:52 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkexhb02.mediatek.inc (172.21.101.103) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Mon, 10 Jan 2022 16:34:51 +0800 Received: from localhost.localdomain (10.17.3.154) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Mon, 10 Jan 2022 16:34:49 +0800 From: Yunfei Dong To: Yunfei Dong , Alexandre Courbot , Hans Verkuil , "Tzung-Bi Shih" , Tiffany Lin , Andrew-CT Chen , Mauro Carvalho Chehab , Rob Herring , Matthias Brugger , Tomasz Figa CC: George Sun , Xiaoyong Lu , Hsin-Yi Wang , Fritz Koenig , Dafna Hirschfeld , Benjamin Gaignard , Daniel Vetter , dri-devel , Irui Wang , AngeloGioacchino Del Regno , Steve Cho , , , , , , , Subject: [PATCH v4, 04/15] media: mtk-vcodec: Read max resolution from dec_capability Date: Mon, 10 Jan 2022 16:34:31 +0800 Message-ID: <20220110083442.32604-5-yunfei.dong@mediatek.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220110083442.32604-1-yunfei.dong@mediatek.com> References: <20220110083442.32604-1-yunfei.dong@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Supported max resolution for different platforms are not the same: 2K or 4K, getting it according to dec_capability. Signed-off-by: Yunfei Dong Reviewed-by: Tzung-Bi Shih --- .../platform/mtk-vcodec/mtk_vcodec_dec.c | 31 +++++++++++-------- .../platform/mtk-vcodec/mtk_vcodec_drv.h | 4 +++ 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 130ecef2e766..65a224d788bf 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -152,13 +152,15 @@ void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx) q_data->coded_height = DFT_CFG_HEIGHT; q_data->fmt = ctx->dev->vdec_pdata->default_cap_fmt; q_data->field = V4L2_FIELD_NONE; + ctx->max_width = MTK_VDEC_MAX_W; + ctx->max_height = MTK_VDEC_MAX_H; v4l_bound_align_image(&q_data->coded_width, MTK_VDEC_MIN_W, - MTK_VDEC_MAX_W, 4, + ctx->max_width, 4, &q_data->coded_height, MTK_VDEC_MIN_H, - MTK_VDEC_MAX_H, 5, 6); + ctx->max_height, 5, 6); q_data->sizeimage[0] = q_data->coded_width * q_data->coded_height; q_data->bytesperline[0] = q_data->coded_width; @@ -217,17 +219,17 @@ static int vidioc_vdec_subscribe_evt(struct v4l2_fh *fh, } } -static int vidioc_try_fmt(struct v4l2_format *f, - const struct mtk_video_fmt *fmt) +static int vidioc_try_fmt(struct mtk_vcodec_ctx *ctx, + struct v4l2_format *f, const struct mtk_video_fmt *fmt) { struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; pix_fmt_mp->field = V4L2_FIELD_NONE; pix_fmt_mp->width = - clamp(pix_fmt_mp->width, MTK_VDEC_MIN_W, MTK_VDEC_MAX_W); + clamp(pix_fmt_mp->width, MTK_VDEC_MIN_W, ctx->max_width); pix_fmt_mp->height = - clamp(pix_fmt_mp->height, MTK_VDEC_MIN_H, MTK_VDEC_MAX_H); + clamp(pix_fmt_mp->height, MTK_VDEC_MIN_H, ctx->max_height); if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { pix_fmt_mp->num_planes = 1; @@ -245,16 +247,16 @@ static int vidioc_try_fmt(struct v4l2_format *f, tmp_h = pix_fmt_mp->height; v4l_bound_align_image(&pix_fmt_mp->width, MTK_VDEC_MIN_W, - MTK_VDEC_MAX_W, 6, + ctx->max_width, 6, &pix_fmt_mp->height, MTK_VDEC_MIN_H, - MTK_VDEC_MAX_H, 6, 9); + ctx->max_height, 6, 9); if (pix_fmt_mp->width < tmp_w && - (pix_fmt_mp->width + 64) <= MTK_VDEC_MAX_W) + (pix_fmt_mp->width + 64) <= ctx->max_width) pix_fmt_mp->width += 64; if (pix_fmt_mp->height < tmp_h && - (pix_fmt_mp->height + 64) <= MTK_VDEC_MAX_H) + (pix_fmt_mp->height + 64) <= ctx->max_height) pix_fmt_mp->height += 64; mtk_v4l2_debug(0, @@ -294,7 +296,7 @@ static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, fmt = mtk_vdec_find_format(f, dec_pdata); } - return vidioc_try_fmt(f, fmt); + return vidioc_try_fmt(ctx, f, fmt); } static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, @@ -317,7 +319,7 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, return -EINVAL; } - return vidioc_try_fmt(f, fmt); + return vidioc_try_fmt(ctx, f, fmt); } static int vidioc_vdec_g_selection(struct file *file, void *priv, @@ -445,7 +447,7 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, return -EINVAL; q_data->fmt = fmt; - vidioc_try_fmt(f, q_data->fmt); + vidioc_try_fmt(ctx, f, q_data->fmt); if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { q_data->sizeimage[0] = pix_mp->plane_fmt[0].sizeimage; q_data->coded_width = pix_mp->width; @@ -545,6 +547,9 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, fsize->stepwise.min_height, fsize->stepwise.max_height, fsize->stepwise.step_height); + + ctx->max_width = fsize->stepwise.max_width; + ctx->max_height = fsize->stepwise.max_height; return 0; } diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index 45d9e1be7063..199f5f0b9152 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -287,6 +287,8 @@ struct vdec_pic_info { * mtk_video_dec_buf. * @hw_id: hardware index used to identify different hardware. * + * @max_width: hardware supported max width + * @max_height: hardware supported max height * @msg_queue: msg queue used to store lat buffer information. */ struct mtk_vcodec_ctx { @@ -332,6 +334,8 @@ struct mtk_vcodec_ctx { struct mutex lock; int hw_id; + unsigned int max_width; + unsigned int max_height; struct vdec_msg_queue msg_queue; }; From patchwork Mon Jan 10 08:34:32 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?WXVuZmVpIERvbmcgKOiRo+S6kemjnik=?= X-Patchwork-Id: 531014 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 33255C4332F for ; Mon, 10 Jan 2022 08:35:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241321AbiAJIfy (ORCPT ); Mon, 10 Jan 2022 03:35:54 -0500 Received: from mailgw02.mediatek.com ([210.61.82.184]:52746 "EHLO mailgw02.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S241420AbiAJIfB (ORCPT ); Mon, 10 Jan 2022 03:35:01 -0500 X-UUID: 4105c63c9c854f688ca04e17c63c4662-20220110 X-UUID: 4105c63c9c854f688ca04e17c63c4662-20220110 Received: from mtkmbs10n2.mediatek.inc [(172.21.101.183)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 784916521; Mon, 10 Jan 2022 16:34:54 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs07n1.mediatek.inc (172.21.101.16) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Mon, 10 Jan 2022 16:34:52 +0800 Received: from localhost.localdomain (10.17.3.154) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Mon, 10 Jan 2022 16:34:51 +0800 From: Yunfei Dong To: Yunfei Dong , Alexandre Courbot , Hans Verkuil , Tzung-Bi Shih , Tiffany Lin , Andrew-CT Chen , Mauro Carvalho Chehab , Rob Herring , Matthias Brugger , Tomasz Figa CC: George Sun , Xiaoyong Lu , Hsin-Yi Wang , Fritz Koenig , Dafna Hirschfeld , Benjamin Gaignard , Daniel Vetter , dri-devel , Irui Wang , AngeloGioacchino Del Regno , Steve Cho , , , , , , , Subject: [PATCH v4, 05/15] media: mtk-vcodec: Call v4l2_m2m_set_dst_buffered() set capture buffer buffered Date: Mon, 10 Jan 2022 16:34:32 +0800 Message-ID: <20220110083442.32604-6-yunfei.dong@mediatek.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220110083442.32604-1-yunfei.dong@mediatek.com> References: <20220110083442.32604-1-yunfei.dong@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org lat thread: output queue \ -> lat hardware -> lat trans buffer lat trans buffer / core thread: capture queue \ ->core hardware -> capture queue lat trans buffer / Lat and core work in different thread, setting capture buffer buffered. Signed-off-by: Yunfei Dong --- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c index 5aebf88f997b..23a154c4e321 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c @@ -314,6 +314,9 @@ static void mtk_init_vdec_params(struct mtk_vcodec_ctx *ctx) src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (ctx->dev->vdec_pdata->hw_arch != MTK_VDEC_PURE_SINGLE_CORE) + v4l2_m2m_set_dst_buffered(ctx->m2m_ctx, 1); + /* Support request api for output plane */ src_vq->supports_requests = true; src_vq->requires_requests = true; From patchwork Mon Jan 10 08:34:33 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?WXVuZmVpIERvbmcgKOiRo+S6kemjnik=?= X-Patchwork-Id: 531013 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 97E25C433F5 for ; Mon, 10 Jan 2022 08:36:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241366AbiAJIf7 (ORCPT ); Mon, 10 Jan 2022 03:35:59 -0500 Received: from mailgw01.mediatek.com ([60.244.123.138]:50918 "EHLO mailgw01.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S241426AbiAJIfB (ORCPT ); Mon, 10 Jan 2022 03:35:01 -0500 X-UUID: 40cc74532e6245ae958ef841f0589080-20220110 X-UUID: 40cc74532e6245ae958ef841f0589080-20220110 Received: from mtkmbs10n2.mediatek.inc [(172.21.101.183)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 598753482; Mon, 10 Jan 2022 16:34:55 +0800 Received: from mtkexhb01.mediatek.inc (172.21.101.102) by mtkmbs10n2.mediatek.inc (172.21.101.183) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.2.792.3; Mon, 10 Jan 2022 16:34:55 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkexhb01.mediatek.inc (172.21.101.102) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Mon, 10 Jan 2022 16:34:54 +0800 Received: from localhost.localdomain (10.17.3.154) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Mon, 10 Jan 2022 16:34:53 +0800 From: Yunfei Dong To: Yunfei Dong , Alexandre Courbot , Hans Verkuil , "Tzung-Bi Shih" , Tiffany Lin , Andrew-CT Chen , Mauro Carvalho Chehab , Rob Herring , Matthias Brugger , Tomasz Figa CC: George Sun , Xiaoyong Lu , Hsin-Yi Wang , Fritz Koenig , Dafna Hirschfeld , Benjamin Gaignard , Daniel Vetter , dri-devel , Irui Wang , AngeloGioacchino Del Regno , Steve Cho , , , , , , , Subject: [PATCH v4, 06/15] media: mtk-vcodec: Refactor get and put capture buffer flow Date: Mon, 10 Jan 2022 16:34:33 +0800 Message-ID: <20220110083442.32604-7-yunfei.dong@mediatek.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220110083442.32604-1-yunfei.dong@mediatek.com> References: <20220110083442.32604-1-yunfei.dong@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org For lat and core decode in parallel, need to get capture buffer when core start to decode and put put capture buffer to display list when core decode done. Signed-off-by: Yunfei Dong --- .../mtk-vcodec/mtk_vcodec_dec_stateless.c | 123 ++++++++++++------ .../platform/mtk-vcodec/mtk_vcodec_drv.h | 5 +- .../mtk-vcodec/vdec/vdec_h264_req_if.c | 16 ++- 3 files changed, 104 insertions(+), 40 deletions(-) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c index 23a154c4e321..f3036c3f223b 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c @@ -108,37 +108,89 @@ static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = { #define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_vdec_framesizes) -static void mtk_vdec_stateless_set_dst_payload(struct mtk_vcodec_ctx *ctx, - struct vdec_fb *fb) +static void mtk_vdec_stateless_out_to_done(struct mtk_vcodec_ctx *ctx, + struct mtk_vcodec_mem *bs, int error) { - struct mtk_video_dec_buf *vdec_frame_buf = - container_of(fb, struct mtk_video_dec_buf, frame_buffer); - struct vb2_v4l2_buffer *vb = &vdec_frame_buf->m2m_buf.vb; - unsigned int cap_y_size = ctx->q_data[MTK_Q_DATA_DST].sizeimage[0]; + struct mtk_video_dec_buf *out_buf; + struct vb2_v4l2_buffer *vb; - vb2_set_plane_payload(&vb->vb2_buf, 0, cap_y_size); - if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) { - unsigned int cap_c_size = - ctx->q_data[MTK_Q_DATA_DST].sizeimage[1]; + if (!bs) { + mtk_v4l2_err("Free bitstream buffer fail."); + return; + } + out_buf = container_of(bs, struct mtk_video_dec_buf, bs_buffer); + vb = &out_buf->m2m_buf.vb; + + mtk_v4l2_debug(2, + "Free bitsteam buffer id = %d to done_list", + vb->vb2_buf.index); + + v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + if (error) { + v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR); + if (error == -EIO) + out_buf->error = true; + } else { + v4l2_m2m_buf_done(vb, VB2_BUF_STATE_DONE); + } +} - vb2_set_plane_payload(&vb->vb2_buf, 1, cap_c_size); +static void mtk_vdec_stateless_cap_to_disp(struct mtk_vcodec_ctx *ctx, + struct vdec_fb *fb, int error) +{ + struct mtk_video_dec_buf *vdec_frame_buf; + struct vb2_v4l2_buffer *vb; + unsigned int cap_y_size, cap_c_size; + + if (!fb) { + mtk_v4l2_err("Free frame buffer fail."); + return; } + vdec_frame_buf = container_of(fb, struct mtk_video_dec_buf, + frame_buffer); + vb = &vdec_frame_buf->m2m_buf.vb; + + cap_y_size = ctx->q_data[MTK_Q_DATA_DST].sizeimage[0]; + cap_c_size = ctx->q_data[MTK_Q_DATA_DST].sizeimage[1]; + + v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); + + vb2_set_plane_payload(&vb->vb2_buf, 0, cap_y_size); + if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) + vb2_set_plane_payload(&vb->vb2_buf, 1, cap_c_size); + + mtk_v4l2_debug(2, + "Free frame buffer id = %d to done_list", + vb->vb2_buf.index); + if (error) + v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR); + else + v4l2_m2m_buf_done(vb, VB2_BUF_STATE_DONE); } -static struct vdec_fb *vdec_get_cap_buffer(struct mtk_vcodec_ctx *ctx, - struct vb2_v4l2_buffer *vb2_v4l2) +static struct vdec_fb *vdec_get_cap_buffer(struct mtk_vcodec_ctx *ctx) { - struct mtk_video_dec_buf *framebuf = - container_of(vb2_v4l2, struct mtk_video_dec_buf, m2m_buf.vb); - struct vdec_fb *pfb = &framebuf->frame_buffer; - struct vb2_buffer *dst_buf = &vb2_v4l2->vb2_buf; + struct mtk_video_dec_buf *framebuf; + struct vb2_v4l2_buffer *vb2_v4l2; + struct vb2_buffer *dst_buf; + struct vdec_fb *pfb; + + vb2_v4l2 = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + if (!vb2_v4l2) { + mtk_v4l2_debug(1, "[%d] dst_buf empty!!", ctx->id); + return NULL; + } - pfb->base_y.va = NULL; + dst_buf = &vb2_v4l2->vb2_buf; + framebuf = container_of(vb2_v4l2, struct mtk_video_dec_buf, m2m_buf.vb); + + pfb = &framebuf->frame_buffer; + pfb->base_y.va = vb2_plane_vaddr(dst_buf, 0); pfb->base_y.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); pfb->base_y.size = ctx->q_data[MTK_Q_DATA_DST].sizeimage[0]; if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) { - pfb->base_c.va = NULL; + pfb->base_c.va = vb2_plane_vaddr(dst_buf, 1); pfb->base_c.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 1); pfb->base_c.size = ctx->q_data[MTK_Q_DATA_DST].sizeimage[1]; @@ -162,12 +214,11 @@ static void mtk_vdec_worker(struct work_struct *work) struct mtk_vcodec_ctx *ctx = container_of(work, struct mtk_vcodec_ctx, decode_work); struct mtk_vcodec_dev *dev = ctx->dev; - struct vb2_v4l2_buffer *vb2_v4l2_src, *vb2_v4l2_dst; + struct vb2_v4l2_buffer *vb2_v4l2_src; struct vb2_buffer *vb2_src; struct mtk_vcodec_mem *bs_src; struct mtk_video_dec_buf *dec_buf_src; struct media_request *src_buf_req; - struct vdec_fb *dst_buf; bool res_chg = false; int ret; @@ -178,13 +229,6 @@ static void mtk_vdec_worker(struct work_struct *work) return; } - vb2_v4l2_dst = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); - if (!vb2_v4l2_dst) { - v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); - mtk_v4l2_debug(1, "[%d] no available destination buffer", ctx->id); - return; - } - vb2_src = &vb2_v4l2_src->vb2_buf; dec_buf_src = container_of(vb2_v4l2_src, struct mtk_video_dec_buf, m2m_buf.vb); @@ -193,9 +237,15 @@ static void mtk_vdec_worker(struct work_struct *work) mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p", ctx->id, vb2_src->vb2_queue->type, vb2_src->index, vb2_src); - bs_src->va = NULL; + bs_src->va = vb2_plane_vaddr(vb2_src, 0); bs_src->dma_addr = vb2_dma_contig_plane_dma_addr(vb2_src, 0); bs_src->size = (size_t)vb2_src->planes[0].bytesused; + if (!bs_src->va) { + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + mtk_v4l2_err("[%d] id=%d source buffer is NULL", ctx->id, + vb2_src->index); + return; + } mtk_v4l2_debug(3, "[%d] Bitstream VA=%p DMA=%pad Size=%zx vb=%p", ctx->id, bs_src->va, &bs_src->dma_addr, bs_src->size, vb2_src); @@ -206,9 +256,7 @@ static void mtk_vdec_worker(struct work_struct *work) else mtk_v4l2_err("vb2 buffer media request is NULL"); - dst_buf = vdec_get_cap_buffer(ctx, vb2_v4l2_dst); - v4l2_m2m_buf_copy_metadata(vb2_v4l2_src, vb2_v4l2_dst, true); - ret = vdec_if_decode(ctx, bs_src, dst_buf, &res_chg); + ret = vdec_if_decode(ctx, bs_src, NULL, &res_chg); if (ret) { mtk_v4l2_err(" <===[%d], src_buf[%d] sz=0x%zx pts=%llu vdec_if_decode() ret=%d res_chg=%d===>", ctx->id, vb2_src->index, bs_src->size, @@ -220,12 +268,9 @@ static void mtk_vdec_worker(struct work_struct *work) } } - mtk_vdec_stateless_set_dst_payload(ctx, dst_buf); - - v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx, - ret ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); - + mtk_vdec_stateless_out_to_done(ctx, bs_src, ret); v4l2_ctrl_request_complete(src_buf_req, &ctx->ctrl_hdl); + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); } static void vb2ops_vdec_stateless_buf_queue(struct vb2_buffer *vb) @@ -358,6 +403,8 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata = { .uses_stateless_api = true, .worker = mtk_vdec_worker, .flush_decoder = mtk_vdec_flush_decoder, + .cap_to_disp = mtk_vdec_stateless_cap_to_disp, + .get_cap_buffer = vdec_get_cap_buffer, .is_subdev_supported = false, .hw_arch = MTK_VDEC_PURE_SINGLE_CORE, }; @@ -376,6 +423,8 @@ const struct mtk_vcodec_dec_pdata mtk_lat_sig_core_pdata = { .uses_stateless_api = true, .worker = mtk_vdec_worker, .flush_decoder = mtk_vdec_flush_decoder, + .cap_to_disp = mtk_vdec_stateless_cap_to_disp, + .get_cap_buffer = vdec_get_cap_buffer, .is_subdev_supported = true, .hw_arch = MTK_VDEC_LAT_SINGLE_CORE, }; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index 199f5f0b9152..009f9124a57d 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -353,7 +353,8 @@ enum mtk_vdec_hw_arch { * @ctrls_setup: init vcodec dec ctrls * @worker: worker to start a decode job * @flush_decoder: function that flushes the decoder - * + * @get_cap_buffer: get capture buffer from capture queue + * @cap_to_disp: put capture buffer to disp list * @vdec_vb2_ops: struct vb2_ops * * @vdec_formats: supported video decoder formats @@ -375,6 +376,8 @@ struct mtk_vcodec_dec_pdata { int (*ctrls_setup)(struct mtk_vcodec_ctx *ctx); void (*worker)(struct work_struct *work); int (*flush_decoder)(struct mtk_vcodec_ctx *ctx); + struct vdec_fb *(*get_cap_buffer)(struct mtk_vcodec_ctx *ctx); + void (*cap_to_disp)(struct mtk_vcodec_ctx *ctx, struct vdec_fb *fb, int error); struct vb2_ops *vdec_vb2_ops; diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_if.c index 43542de11e9c..d00219a7587c 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_if.c @@ -670,32 +670,42 @@ static void vdec_h264_slice_deinit(void *h_vdec) } static int vdec_h264_slice_decode(void *h_vdec, struct mtk_vcodec_mem *bs, - struct vdec_fb *fb, bool *res_chg) + struct vdec_fb *unused, bool *res_chg) { struct vdec_h264_slice_inst *inst = h_vdec; const struct v4l2_ctrl_h264_decode_params *dec_params = get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS); struct vdec_vpu_inst *vpu = &inst->vpu; + struct mtk_video_dec_buf *src_buf_info; + struct mtk_video_dec_buf *dst_buf_info; + struct vdec_fb *fb; u32 data[2]; u64 y_fb_dma; u64 c_fb_dma; int err; + inst->num_nalu++; /* bs NULL means flush decoder */ if (!bs) return vpu_dec_reset(vpu); + fb = inst->ctx->dev->vdec_pdata->get_cap_buffer(inst->ctx); + src_buf_info = container_of(bs, struct mtk_video_dec_buf, bs_buffer); + dst_buf_info = container_of(fb, struct mtk_video_dec_buf, frame_buffer); + y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0; c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0; mtk_vcodec_debug(inst, "+ [%d] FB y_dma=%llx c_dma=%llx va=%p", - ++inst->num_nalu, y_fb_dma, c_fb_dma, fb); + inst->num_nalu, y_fb_dma, c_fb_dma, fb); inst->vsi_ctx.dec.bs_dma = (uint64_t)bs->dma_addr; inst->vsi_ctx.dec.y_fb_dma = y_fb_dma; inst->vsi_ctx.dec.c_fb_dma = c_fb_dma; inst->vsi_ctx.dec.vdec_fb_va = (u64)(uintptr_t)fb; + v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, + &dst_buf_info->m2m_buf.vb, true); get_vdec_decode_parameters(inst); data[0] = bs->size; /* @@ -734,6 +744,8 @@ static int vdec_h264_slice_decode(void *h_vdec, struct mtk_vcodec_mem *bs, memcpy(&inst->vsi_ctx, inst->vpu.vsi, sizeof(inst->vsi_ctx)); mtk_vcodec_debug(inst, "\n - NALU[%d]", inst->num_nalu); + + inst->ctx->dev->vdec_pdata->cap_to_disp(inst->ctx, fb, 0); return 0; err_free_fb_out: From patchwork Mon Jan 10 08:34:37 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?WXVuZmVpIERvbmcgKOiRo+S6kemjnik=?= X-Patchwork-Id: 531012 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0D039C4332F for ; Mon, 10 Jan 2022 08:36:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240732AbiAJIgC (ORCPT ); Mon, 10 Jan 2022 03:36:02 -0500 Received: from mailgw02.mediatek.com ([210.61.82.184]:53080 "EHLO mailgw02.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S241446AbiAJIfG (ORCPT ); Mon, 10 Jan 2022 03:35:06 -0500 X-UUID: 04d5fbe3b250478d8922c361320a5616-20220110 X-UUID: 04d5fbe3b250478d8922c361320a5616-20220110 Received: from mtkmbs10n1.mediatek.inc [(172.21.101.34)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1173358465; Mon, 10 Jan 2022 16:35:02 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs10n1.mediatek.inc (172.21.101.34) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.2.792.15; Mon, 10 Jan 2022 16:35:00 +0800 Received: from localhost.localdomain (10.17.3.154) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Mon, 10 Jan 2022 16:34:59 +0800 From: Yunfei Dong To: Yunfei Dong , Alexandre Courbot , Hans Verkuil , "Tzung-Bi Shih" , Tiffany Lin , Andrew-CT Chen , Mauro Carvalho Chehab , Rob Herring , Matthias Brugger , Tomasz Figa CC: George Sun , Xiaoyong Lu , Hsin-Yi Wang , Fritz Koenig , Dafna Hirschfeld , Benjamin Gaignard , Daniel Vetter , dri-devel , Irui Wang , AngeloGioacchino Del Regno , Steve Cho , , , , , , , Subject: [PATCH v4, 10/15] media: mtk-vcodec: Fix v4l2-compliance fail Date: Mon, 10 Jan 2022 16:34:37 +0800 Message-ID: <20220110083442.32604-11-yunfei.dong@mediatek.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220110083442.32604-1-yunfei.dong@mediatek.com> References: <20220110083442.32604-1-yunfei.dong@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Need to use default pic info when get pic info fail. Signed-off-by: Yunfei Dong --- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 34ee4a0092ff..75210eb829d0 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -478,11 +478,14 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, ctx->picinfo.pic_w = pix_mp->width; ctx->picinfo.pic_h = pix_mp->height; + /* + * If get pic info fail, need to use the default pic info params, or + * v4l2-compliance will fail + */ ret = vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, &ctx->picinfo); if (ret) { mtk_v4l2_err("[%d]Error!! Get GET_PARAM_PICTURE_INFO Fail", ctx->id); - return -EINVAL; } ctx->last_decoded_picinfo = ctx->picinfo; From patchwork Mon Jan 10 08:34:38 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?WXVuZmVpIERvbmcgKOiRo+S6kemjnik=?= X-Patchwork-Id: 531011 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 02BE5C433FE for ; Mon, 10 Jan 2022 08:36:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240878AbiAJIgZ (ORCPT ); Mon, 10 Jan 2022 03:36:25 -0500 Received: from mailgw02.mediatek.com ([210.61.82.184]:52604 "EHLO mailgw02.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S241243AbiAJIfn (ORCPT ); Mon, 10 Jan 2022 03:35:43 -0500 X-UUID: 06c9cec9eff64ddfaeb02d59d55730f2-20220110 X-UUID: 06c9cec9eff64ddfaeb02d59d55730f2-20220110 Received: from mtkcas11.mediatek.inc [(172.21.101.40)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 1936200613; Mon, 10 Jan 2022 16:35:04 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs10n2.mediatek.inc (172.21.101.183) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.2.792.3; Mon, 10 Jan 2022 16:35:02 +0800 Received: from localhost.localdomain (10.17.3.154) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Mon, 10 Jan 2022 16:35:00 +0800 From: Yunfei Dong To: Yunfei Dong , Alexandre Courbot , Hans Verkuil , "Tzung-Bi Shih" , Tiffany Lin , Andrew-CT Chen , Mauro Carvalho Chehab , Rob Herring , Matthias Brugger , Tomasz Figa CC: George Sun , Xiaoyong Lu , Hsin-Yi Wang , Fritz Koenig , Dafna Hirschfeld , Benjamin Gaignard , Daniel Vetter , dri-devel , Irui Wang , AngeloGioacchino Del Regno , Steve Cho , , , , , , , Subject: [PATCH v4, 11/15] media: mtk-vcodec: record capture queue format type Date: Mon, 10 Jan 2022 16:34:38 +0800 Message-ID: <20220110083442.32604-12-yunfei.dong@mediatek.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220110083442.32604-1-yunfei.dong@mediatek.com> References: <20220110083442.32604-1-yunfei.dong@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Capture queue format type is difference for different platform, need to calculate capture buffer size according to capture queue format type in scp. Signed-off-by: Yunfei Dong --- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 2 ++ drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 75210eb829d0..4533cb44551d 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -468,6 +468,8 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, } ctx->state = MTK_STATE_INIT; } + } else { + ctx->capture_fourcc = fmt->fourcc; } /* diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index 12a2baaf9e81..4981760226b5 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -277,6 +277,7 @@ struct vdec_pic_info { * to be used with encoder and stateful decoder. * @is_flushing: set to true if flushing is in progress. * @current_codec: current set input codec, in V4L2 pixel format + * @capture_fourcc: capture queue type in V4L2 pixel format * * @colorspace: enum v4l2_colorspace; supplemental to pixelformat * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding @@ -324,6 +325,7 @@ struct mtk_vcodec_ctx { bool is_flushing; u32 current_codec; + u32 capture_fourcc; enum v4l2_colorspace colorspace; enum v4l2_ycbcr_encoding ycbcr_enc; From patchwork Mon Jan 10 08:34:39 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?WXVuZmVpIERvbmcgKOiRo+S6kemjnik=?= X-Patchwork-Id: 531010 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8AF72C43217 for ; Mon, 10 Jan 2022 08:36:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241597AbiAJIg2 (ORCPT ); Mon, 10 Jan 2022 03:36:28 -0500 Received: from mailgw01.mediatek.com ([60.244.123.138]:50560 "EHLO mailgw01.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S240902AbiAJIfm (ORCPT ); Mon, 10 Jan 2022 03:35:42 -0500 X-UUID: 669ed7b174e14fc79afdacbc1ea158d7-20220110 X-UUID: 669ed7b174e14fc79afdacbc1ea158d7-20220110 Received: from mtkmbs10n2.mediatek.inc [(172.21.101.183)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 658045988; Mon, 10 Jan 2022 16:35:05 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs10n2.mediatek.inc (172.21.101.183) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.2.792.3; Mon, 10 Jan 2022 16:35:04 +0800 Received: from localhost.localdomain (10.17.3.154) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Mon, 10 Jan 2022 16:35:02 +0800 From: Yunfei Dong To: Yunfei Dong , Alexandre Courbot , Hans Verkuil , "Tzung-Bi Shih" , Tiffany Lin , Andrew-CT Chen , Mauro Carvalho Chehab , Rob Herring , Matthias Brugger , Tomasz Figa CC: George Sun , Xiaoyong Lu , Hsin-Yi Wang , Fritz Koenig , Dafna Hirschfeld , Benjamin Gaignard , Daniel Vetter , dri-devel , Irui Wang , AngeloGioacchino Del Regno , Steve Cho , , , , , , , Subject: [PATCH v4, 12/15] media: mtk-vcodec: Extract H264 common code Date: Mon, 10 Jan 2022 16:34:39 +0800 Message-ID: <20220110083442.32604-13-yunfei.dong@mediatek.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220110083442.32604-1-yunfei.dong@mediatek.com> References: <20220110083442.32604-1-yunfei.dong@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Mt8192 can use some of common code with mt8183. Moves them to a new file in order to reuse. Signed-off-by: Yunfei Dong --- drivers/media/platform/mtk-vcodec/Makefile | 1 + .../mtk-vcodec/vdec/vdec_h264_req_common.c | 311 ++++++++++++++ .../mtk-vcodec/vdec/vdec_h264_req_common.h | 254 +++++++++++ .../mtk-vcodec/vdec/vdec_h264_req_if.c | 400 +----------------- 4 files changed, 589 insertions(+), 377 deletions(-) create mode 100644 drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_common.c create mode 100644 drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_common.h diff --git a/drivers/media/platform/mtk-vcodec/Makefile b/drivers/media/platform/mtk-vcodec/Makefile index 359619653a0e..3f41d748eee5 100644 --- a/drivers/media/platform/mtk-vcodec/Makefile +++ b/drivers/media/platform/mtk-vcodec/Makefile @@ -9,6 +9,7 @@ mtk-vcodec-dec-y := vdec/vdec_h264_if.o \ vdec/vdec_vp8_if.o \ vdec/vdec_vp9_if.o \ vdec/vdec_h264_req_if.o \ + vdec/vdec_h264_req_common.o \ mtk_vcodec_dec_drv.o \ vdec_drv_if.o \ vdec_vpu_if.o \ diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_common.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_common.c new file mode 100644 index 000000000000..c8113ca251f5 --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_common.c @@ -0,0 +1,311 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + * Author: Yunfei Dong + */ + +#include "vdec_h264_req_common.h" + +/* get used parameters for sps/pps */ +#define GET_MTK_VDEC_FLAG(cond, flag) \ + { dst_param->cond = ((src_param->flags & flag) ? (1) : (0)); } +#define GET_MTK_VDEC_PARAM(param) \ + { dst_param->param = src_param->param; } + +/* + * The firmware expects unused reflist entries to have the value 0x20. + */ +void mtk_vdec_h264_fixup_ref_list(u8 *ref_list, size_t num_valid) +{ + memset(&ref_list[num_valid], 0x20, 32 - num_valid); +} + +void *mtk_vdec_h264_get_ctrl_ptr(struct mtk_vcodec_ctx *ctx, int id) +{ + struct v4l2_ctrl *ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, id); + + return ctrl->p_cur.p; +} + +void mtk_vdec_h264_fill_dpb_info(struct mtk_vcodec_ctx *ctx, + struct slice_api_h264_decode_param *decode_params, + struct mtk_h264_dpb_info *h264_dpb_info) +{ + struct vb2_queue *vq; + struct vb2_buffer *vb; + struct vb2_v4l2_buffer *vb2_v4l2; + int index; + + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + + for (index = 0; index < V4L2_H264_NUM_DPB_ENTRIES; index++) { + const struct slice_h264_dpb_entry *dpb; + int vb2_index; + + dpb = &decode_params->dpb[index]; + if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) { + h264_dpb_info[index].reference_flag = 0; + continue; + } + + vb2_index = vb2_find_timestamp(vq, dpb->reference_ts, 0); + if (vb2_index < 0) { + dev_err(&ctx->dev->plat_dev->dev, + "Reference invalid: dpb_index(%d) reference_ts(%lld)", + index, dpb->reference_ts); + continue; + } + + /* 1 for short term reference, 2 for long term reference */ + if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) + h264_dpb_info[index].reference_flag = 1; + else + h264_dpb_info[index].reference_flag = 2; + + vb = vq->bufs[vb2_index]; + vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf); + h264_dpb_info[index].field = vb2_v4l2->field; + + h264_dpb_info[index].y_dma_addr = + vb2_dma_contig_plane_dma_addr(vb, 0); + if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) + h264_dpb_info[index].c_dma_addr = + vb2_dma_contig_plane_dma_addr(vb, 1); + else + h264_dpb_info[index].c_dma_addr = + h264_dpb_info[index].y_dma_addr + + ctx->picinfo.fb_sz[0]; + } +} + +void mtk_vdec_h264_copy_sps_params(struct mtk_h264_sps_param *dst_param, + const struct v4l2_ctrl_h264_sps *src_param) +{ + GET_MTK_VDEC_PARAM(chroma_format_idc); + GET_MTK_VDEC_PARAM(bit_depth_luma_minus8); + GET_MTK_VDEC_PARAM(bit_depth_chroma_minus8); + GET_MTK_VDEC_PARAM(log2_max_frame_num_minus4); + GET_MTK_VDEC_PARAM(pic_order_cnt_type); + GET_MTK_VDEC_PARAM(log2_max_pic_order_cnt_lsb_minus4); + GET_MTK_VDEC_PARAM(max_num_ref_frames); + GET_MTK_VDEC_PARAM(pic_width_in_mbs_minus1); + GET_MTK_VDEC_PARAM(pic_height_in_map_units_minus1); + + GET_MTK_VDEC_FLAG(separate_colour_plane_flag, + V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE); + GET_MTK_VDEC_FLAG(qpprime_y_zero_transform_bypass_flag, + V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS); + GET_MTK_VDEC_FLAG(delta_pic_order_always_zero_flag, + V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO); + GET_MTK_VDEC_FLAG(frame_mbs_only_flag, + V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY); + GET_MTK_VDEC_FLAG(mb_adaptive_frame_field_flag, + V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD); + GET_MTK_VDEC_FLAG(direct_8x8_inference_flag, + V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE); +} + +void mtk_vdec_h264_copy_pps_params(struct mtk_h264_pps_param *dst_param, + const struct v4l2_ctrl_h264_pps *src_param) +{ + GET_MTK_VDEC_PARAM(num_ref_idx_l0_default_active_minus1); + GET_MTK_VDEC_PARAM(num_ref_idx_l1_default_active_minus1); + GET_MTK_VDEC_PARAM(weighted_bipred_idc); + GET_MTK_VDEC_PARAM(pic_init_qp_minus26); + GET_MTK_VDEC_PARAM(chroma_qp_index_offset); + GET_MTK_VDEC_PARAM(second_chroma_qp_index_offset); + + GET_MTK_VDEC_FLAG(entropy_coding_mode_flag, + V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE); + GET_MTK_VDEC_FLAG(pic_order_present_flag, + V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT); + GET_MTK_VDEC_FLAG(weighted_pred_flag, + V4L2_H264_PPS_FLAG_WEIGHTED_PRED); + GET_MTK_VDEC_FLAG(deblocking_filter_control_present_flag, + V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT); + GET_MTK_VDEC_FLAG(constrained_intra_pred_flag, + V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED); + GET_MTK_VDEC_FLAG(redundant_pic_cnt_present_flag, + V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT); + GET_MTK_VDEC_FLAG(transform_8x8_mode_flag, + V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE); + GET_MTK_VDEC_FLAG(scaling_matrix_present_flag, + V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT); +} + +void mtk_vdec_h264_copy_slice_hd_params( + struct mtk_h264_slice_hd_param *dst_param, + const struct v4l2_ctrl_h264_slice_params *src_param, + const struct v4l2_ctrl_h264_decode_params *dec_param) +{ + int temp; + + GET_MTK_VDEC_PARAM(first_mb_in_slice); + GET_MTK_VDEC_PARAM(slice_type); + GET_MTK_VDEC_PARAM(cabac_init_idc); + GET_MTK_VDEC_PARAM(slice_qp_delta); + GET_MTK_VDEC_PARAM(disable_deblocking_filter_idc); + GET_MTK_VDEC_PARAM(slice_alpha_c0_offset_div2); + GET_MTK_VDEC_PARAM(slice_beta_offset_div2); + GET_MTK_VDEC_PARAM(num_ref_idx_l0_active_minus1); + GET_MTK_VDEC_PARAM(num_ref_idx_l1_active_minus1); + + dst_param->frame_num = dec_param->frame_num; + dst_param->pic_order_cnt_lsb = dec_param->pic_order_cnt_lsb; + + dst_param->delta_pic_order_cnt_bottom = + dec_param->delta_pic_order_cnt_bottom; + dst_param->delta_pic_order_cnt0 = + dec_param->delta_pic_order_cnt0; + dst_param->delta_pic_order_cnt1 = + dec_param->delta_pic_order_cnt1; + + temp = dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC; + dst_param->field_pic_flag = temp ? 1 : 0; + + temp = dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD; + dst_param->bottom_field_flag = temp ? 1 : 0; + + GET_MTK_VDEC_FLAG(direct_spatial_mv_pred_flag, + V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED); +} + +void mtk_vdec_h264_copy_scaling_matrix( + struct slice_api_h264_scaling_matrix *dst_matrix, + const struct v4l2_ctrl_h264_scaling_matrix *src_matrix) +{ + memcpy(dst_matrix->scaling_list_4x4, src_matrix->scaling_list_4x4, + sizeof(dst_matrix->scaling_list_4x4)); + + memcpy(dst_matrix->scaling_list_8x8, src_matrix->scaling_list_8x8, + sizeof(dst_matrix->scaling_list_8x8)); +} + +void mtk_vdec_h264_copy_decode_params( + struct slice_api_h264_decode_param *dst_params, + const struct v4l2_ctrl_h264_decode_params *src_params, + const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dst_params->dpb); i++) { + struct slice_h264_dpb_entry *dst_entry = &dst_params->dpb[i]; + const struct v4l2_h264_dpb_entry *src_entry = &dpb[i]; + + dst_entry->reference_ts = src_entry->reference_ts; + dst_entry->frame_num = src_entry->frame_num; + dst_entry->pic_num = src_entry->pic_num; + dst_entry->top_field_order_cnt = src_entry->top_field_order_cnt; + dst_entry->bottom_field_order_cnt = + src_entry->bottom_field_order_cnt; + dst_entry->flags = src_entry->flags; + } + + /* num_slices is a leftover from the old H.264 support and is ignored + * by the firmware. + */ + dst_params->num_slices = 0; + dst_params->nal_ref_idc = src_params->nal_ref_idc; + dst_params->top_field_order_cnt = src_params->top_field_order_cnt; + dst_params->bottom_field_order_cnt = src_params->bottom_field_order_cnt; + dst_params->flags = src_params->flags; +} + +static bool mtk_vdec_h264_dpb_entry_match( + const struct v4l2_h264_dpb_entry *a, + const struct v4l2_h264_dpb_entry *b) +{ + return a->top_field_order_cnt == b->top_field_order_cnt && + a->bottom_field_order_cnt == b->bottom_field_order_cnt; +} + +/* + * Move DPB entries of dec_param that refer to a frame already existing in dpb + * into the already existing slot in dpb, and move other entries into new slots. + * + * This function is an adaptation of the similarly-named function in + * hantro_h264.c. + */ +void mtk_vdec_h264_update_dpb(const struct v4l2_ctrl_h264_decode_params *dec_param, + struct v4l2_h264_dpb_entry *dpb) +{ + DECLARE_BITMAP(new, ARRAY_SIZE(dec_param->dpb)) = { 0, }; + DECLARE_BITMAP(in_use, ARRAY_SIZE(dec_param->dpb)) = { 0, }; + DECLARE_BITMAP(used, ARRAY_SIZE(dec_param->dpb)) = { 0, }; + unsigned int i, j; + + /* Disable all entries by default, and mark the ones in use. */ + for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) { + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) + set_bit(i, in_use); + dpb[i].flags &= ~V4L2_H264_DPB_ENTRY_FLAG_ACTIVE; + } + + /* Try to match new DPB entries with existing ones by their POCs. */ + for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) { + const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; + + if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) + continue; + + /* + * To cut off some comparisons, iterate only on target DPB + * entries were already used. + */ + for_each_set_bit(j, in_use, ARRAY_SIZE(dec_param->dpb)) { + struct v4l2_h264_dpb_entry *cdpb; + + cdpb = &dpb[j]; + if (!mtk_vdec_h264_dpb_entry_match(cdpb, ndpb)) + continue; + + *cdpb = *ndpb; + set_bit(j, used); + /* Don't reiterate on this one. */ + clear_bit(j, in_use); + break; + } + + if (j == ARRAY_SIZE(dec_param->dpb)) + set_bit(i, new); + } + + /* For entries that could not be matched, use remaining free slots. */ + for_each_set_bit(i, new, ARRAY_SIZE(dec_param->dpb)) { + const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; + struct v4l2_h264_dpb_entry *cdpb; + + /* + * Both arrays are of the same sizes, so there is no way + * we can end up with no space in target array, unless + * something is buggy. + */ + j = find_first_zero_bit(used, ARRAY_SIZE(dec_param->dpb)); + if (WARN_ON(j >= ARRAY_SIZE(dec_param->dpb))) + return; + + cdpb = &dpb[j]; + *cdpb = *ndpb; + set_bit(j, used); + } +} + +unsigned int mtk_vdec_h264_get_mv_buf_size( + unsigned int width, unsigned int height) +{ + int unit_size = (width / MB_UNIT_LEN) * (height / MB_UNIT_LEN) + 8; + + return HW_MB_STORE_SZ * unit_size; +} + +int mtk_vdec_h264_find_start_code(unsigned char *data, unsigned int data_sz) +{ + if (data_sz > 3 && data[0] == 0 && data[1] == 0 && data[2] == 1) + return 3; + + if (data_sz > 4 && data[0] == 0 && data[1] == 0 && data[2] == 0 && + data[3] == 1) + return 4; + + return -1; +} diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_common.h b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_common.h new file mode 100644 index 000000000000..0d32fe6a0d29 --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_common.h @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + * Author: Yunfei Dong + */ + +#ifndef _VDEC_H264_REQ_COMMON_H_ +#define _VDEC_H264_REQ_COMMON_H_ + +#include +#include +#include +#include +#include + +#include "../mtk_vcodec_drv.h" + +#define NAL_NON_IDR_SLICE 0x01 +#define NAL_IDR_SLICE 0x05 +#define NAL_TYPE(value) ((value) & 0x1F) + +#define BUF_PREDICTION_SZ (64 * 4096) +#define MB_UNIT_LEN 16 + +/* motion vector size (bytes) for every macro block */ +#define HW_MB_STORE_SZ 64 + +#define H264_MAX_MV_NUM 32 + +/** + * struct mtk_h264_dpb_info - h264 dpb information + * @y_dma_addr: Y bitstream physical address + * @c_dma_addr: CbCr bitstream physical address + * @reference_flag: reference picture flag (short/long term reference picture) + * @field: field picture flag + */ +struct mtk_h264_dpb_info { + dma_addr_t y_dma_addr; + dma_addr_t c_dma_addr; + int reference_flag; + int field; +}; + +/** + * struct mtk_h264_sps_param - parameters for sps + */ +struct mtk_h264_sps_param { + unsigned char chroma_format_idc; + unsigned char bit_depth_luma_minus8; + unsigned char bit_depth_chroma_minus8; + unsigned char log2_max_frame_num_minus4; + unsigned char pic_order_cnt_type; + unsigned char log2_max_pic_order_cnt_lsb_minus4; + unsigned char max_num_ref_frames; + unsigned char separate_colour_plane_flag; + unsigned short pic_width_in_mbs_minus1; + unsigned short pic_height_in_map_units_minus1; + unsigned int max_frame_nums; + unsigned char qpprime_y_zero_transform_bypass_flag; + unsigned char delta_pic_order_always_zero_flag; + unsigned char frame_mbs_only_flag; + unsigned char mb_adaptive_frame_field_flag; + unsigned char direct_8x8_inference_flag; + unsigned char reserved[3]; +}; + +/** + * struct mtk_h264_pps_param - parameters for pps + */ +struct mtk_h264_pps_param { + unsigned char num_ref_idx_l0_default_active_minus1; + unsigned char num_ref_idx_l1_default_active_minus1; + unsigned char weighted_bipred_idc; + char pic_init_qp_minus26; + char chroma_qp_index_offset; + char second_chroma_qp_index_offset; + unsigned char entropy_coding_mode_flag; + unsigned char pic_order_present_flag; + unsigned char deblocking_filter_control_present_flag; + unsigned char constrained_intra_pred_flag; + unsigned char weighted_pred_flag; + unsigned char redundant_pic_cnt_present_flag; + unsigned char transform_8x8_mode_flag; + unsigned char scaling_matrix_present_flag; + unsigned char reserved[2]; +}; + +/** + * struct mtk_h264_slice_hd_param - parameters for slice header + */ +struct mtk_h264_slice_hd_param { + unsigned int first_mb_in_slice; + unsigned int field_pic_flag; + unsigned int slice_type; + unsigned int frame_num; + int pic_order_cnt_lsb; + int delta_pic_order_cnt_bottom; + unsigned int bottom_field_flag; + unsigned int direct_spatial_mv_pred_flag; + int delta_pic_order_cnt0; + int delta_pic_order_cnt1; + unsigned int cabac_init_idc; + int slice_qp_delta; + unsigned int disable_deblocking_filter_idc; + int slice_alpha_c0_offset_div2; + int slice_beta_offset_div2; + unsigned int num_ref_idx_l0_active_minus1; + unsigned int num_ref_idx_l1_active_minus1; + unsigned int reserved; +}; + +struct slice_api_h264_scaling_matrix { + unsigned char scaling_list_4x4[6][16]; + unsigned char scaling_list_8x8[6][64]; +}; + +struct slice_h264_dpb_entry { + unsigned long long reference_ts; + unsigned short frame_num; + unsigned short pic_num; + /* Note that field is indicated by v4l2_buffer.field */ + int top_field_order_cnt; + int bottom_field_order_cnt; + unsigned int flags; /* V4L2_H264_DPB_ENTRY_FLAG_* */ +}; + +/** + * struct slice_api_h264_decode_param - parameters for decode. + */ +struct slice_api_h264_decode_param { + struct slice_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]; + unsigned short num_slices; + unsigned short nal_ref_idc; + unsigned char ref_pic_list_p0[32]; + unsigned char ref_pic_list_b0[32]; + unsigned char ref_pic_list_b1[32]; + int top_field_order_cnt; + int bottom_field_order_cnt; + unsigned int flags; /* V4L2_H264_DECODE_PARAM_FLAG_* */ +}; + +/** + * struct h264_fb - h264 decode frame buffer information + * @vdec_fb_va : virtual address of struct vdec_fb + * @y_fb_dma : dma address of Y frame buffer (luma) + * @c_fb_dma : dma address of C frame buffer (chroma) + * @poc : picture order count of frame buffer + * @reserved : for 8 bytes alignment + */ +struct h264_fb { + uint64_t vdec_fb_va; + uint64_t y_fb_dma; + uint64_t c_fb_dma; + int32_t poc; + uint32_t reserved; +}; + +/** + * mtk_vdec_h264_fixup_ref_list - fixup unused reference to 0x20. + * @ref_list: reference picture list + * @num_valid: used reference number + */ +void mtk_vdec_h264_fixup_ref_list(u8 *ref_list, size_t num_valid); + +/** + * mtk_vdec_h264_get_ctrl_ptr - get each CID contrl address. + * @ctx: v4l2 ctx + * @id: CID control ID + */ +void *mtk_vdec_h264_get_ctrl_ptr(struct mtk_vcodec_ctx *ctx, int id); + +/** + * mtk_vdec_h264_fill_dpb_info - get each CID contrl address. + * @ctx: v4l2 ctx + * @decode_params: slice decode params + * @h264_dpb_info: dpb buffer information + */ +void mtk_vdec_h264_fill_dpb_info(struct mtk_vcodec_ctx *ctx, + struct slice_api_h264_decode_param *decode_params, + struct mtk_h264_dpb_info *h264_dpb_info); + +/** + * mtk_vdec_h264_copy_sps_params - get sps params. + * @dst_params: sps params for hw decoder + * @src_params: sps params from user driver + */ +void mtk_vdec_h264_copy_sps_params(struct mtk_h264_sps_param *dst_param, + const struct v4l2_ctrl_h264_sps *src_param); + +/** + * mtk_vdec_h264_copy_pps_params - get pps params. + * @dst_params: pps params for hw decoder + * @src_params: pps params from user driver + */ +void mtk_vdec_h264_copy_pps_params(struct mtk_h264_pps_param *dst_param, + const struct v4l2_ctrl_h264_pps *src_param); + +/** + * mtk_vdec_h264_copy_slice_hd_params - get slice header params. + * @dst_params: slice params for hw decoder + * @src_params: slice params from user driver + * @dec_param: decode params from user driver + */ +void mtk_vdec_h264_copy_slice_hd_params( + struct mtk_h264_slice_hd_param *dst_param, + const struct v4l2_ctrl_h264_slice_params *src_param, + const struct v4l2_ctrl_h264_decode_params *dec_param); + +/** + * mtk_vdec_h264_copy_scaling_matrix - get each CID contrl address. + * @dst_matrix: scaling list params for hw decoder + * @src_matrix: scaling list params from user driver + */ +void mtk_vdec_h264_copy_scaling_matrix( + struct slice_api_h264_scaling_matrix *dst_matrix, + const struct v4l2_ctrl_h264_scaling_matrix *src_matrix); + +/** + * mtk_vdec_h264_copy_decode_params - get decode params. + * @dst_params: dst params for hw decoder + * @src_params: decode params from user driver + * @dpb: dpb information + */ +void mtk_vdec_h264_copy_decode_params( + struct slice_api_h264_decode_param *dst_params, + const struct v4l2_ctrl_h264_decode_params *src_params, + const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]); + + +/** + * mtk_vdec_h264_update_dpb - updata dpb list. + * @dec_param: v4l2 control decode params + * @dpb: dpb entry informaton + */ +void mtk_vdec_h264_update_dpb( + const struct v4l2_ctrl_h264_decode_params *dec_param, + struct v4l2_h264_dpb_entry *dpb); + +/** + * mtk_vdec_h264_find_start_code - find h264 start code using sofeware. + * @data: input buffer address + * @data_sz: input buffer size + */ +int mtk_vdec_h264_find_start_code(unsigned char *data, unsigned int data_sz); + +/** + * mtk_vdec_h264_get_mv_buf_size - get mv buffer size. + * @width: picture width + * @height: picture height + */ +unsigned int mtk_vdec_h264_get_mv_buf_size( + unsigned int width, unsigned int height); + +#endif diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_if.c index d00219a7587c..ee28686639c9 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_if.c @@ -12,109 +12,7 @@ #include "../vdec_drv_base.h" #include "../vdec_drv_if.h" #include "../vdec_vpu_if.h" - -#define BUF_PREDICTION_SZ (64 * 4096) -#define MB_UNIT_LEN 16 - -/* get used parameters for sps/pps */ -#define GET_MTK_VDEC_FLAG(cond, flag) \ - { dst_param->cond = ((src_param->flags & (flag)) ? (1) : (0)); } -#define GET_MTK_VDEC_PARAM(param) \ - { dst_param->param = src_param->param; } -/* motion vector size (bytes) for every macro block */ -#define HW_MB_STORE_SZ 64 - -#define H264_MAX_FB_NUM 17 -#define H264_MAX_MV_NUM 32 -#define HDR_PARSING_BUF_SZ 1024 - -/** - * struct mtk_h264_dpb_info - h264 dpb information - * @y_dma_addr: Y bitstream physical address - * @c_dma_addr: CbCr bitstream physical address - * @reference_flag: reference picture flag (short/long term reference picture) - * @field: field picture flag - */ -struct mtk_h264_dpb_info { - dma_addr_t y_dma_addr; - dma_addr_t c_dma_addr; - int reference_flag; - int field; -}; - -/* - * struct mtk_h264_sps_param - parameters for sps - */ -struct mtk_h264_sps_param { - unsigned char chroma_format_idc; - unsigned char bit_depth_luma_minus8; - unsigned char bit_depth_chroma_minus8; - unsigned char log2_max_frame_num_minus4; - unsigned char pic_order_cnt_type; - unsigned char log2_max_pic_order_cnt_lsb_minus4; - unsigned char max_num_ref_frames; - unsigned char separate_colour_plane_flag; - unsigned short pic_width_in_mbs_minus1; - unsigned short pic_height_in_map_units_minus1; - unsigned int max_frame_nums; - unsigned char qpprime_y_zero_transform_bypass_flag; - unsigned char delta_pic_order_always_zero_flag; - unsigned char frame_mbs_only_flag; - unsigned char mb_adaptive_frame_field_flag; - unsigned char direct_8x8_inference_flag; - unsigned char reserved[3]; -}; - -/* - * struct mtk_h264_pps_param - parameters for pps - */ -struct mtk_h264_pps_param { - unsigned char num_ref_idx_l0_default_active_minus1; - unsigned char num_ref_idx_l1_default_active_minus1; - unsigned char weighted_bipred_idc; - char pic_init_qp_minus26; - char chroma_qp_index_offset; - char second_chroma_qp_index_offset; - unsigned char entropy_coding_mode_flag; - unsigned char pic_order_present_flag; - unsigned char deblocking_filter_control_present_flag; - unsigned char constrained_intra_pred_flag; - unsigned char weighted_pred_flag; - unsigned char redundant_pic_cnt_present_flag; - unsigned char transform_8x8_mode_flag; - unsigned char scaling_matrix_present_flag; - unsigned char reserved[2]; -}; - -struct slice_api_h264_scaling_matrix { - unsigned char scaling_list_4x4[6][16]; - unsigned char scaling_list_8x8[6][64]; -}; - -struct slice_h264_dpb_entry { - unsigned long long reference_ts; - unsigned short frame_num; - unsigned short pic_num; - /* Note that field is indicated by v4l2_buffer.field */ - int top_field_order_cnt; - int bottom_field_order_cnt; - unsigned int flags; /* V4L2_H264_DPB_ENTRY_FLAG_* */ -}; - -/* - * struct slice_api_h264_decode_param - parameters for decode. - */ -struct slice_api_h264_decode_param { - struct slice_h264_dpb_entry dpb[16]; - unsigned short num_slices; - unsigned short nal_ref_idc; - unsigned char ref_pic_list_p0[32]; - unsigned char ref_pic_list_b0[32]; - unsigned char ref_pic_list_b1[32]; - int top_field_order_cnt; - int bottom_field_order_cnt; - unsigned int flags; /* V4L2_H264_DECODE_PARAM_FLAG_* */ -}; +#include "vdec_h264_req_common.h" /* * struct mtk_h264_dec_slice_param - parameters for decode current frame @@ -127,22 +25,6 @@ struct mtk_h264_dec_slice_param { struct mtk_h264_dpb_info h264_dpb_info[16]; }; -/** - * struct h264_fb - h264 decode frame buffer information - * @vdec_fb_va : virtual address of struct vdec_fb - * @y_fb_dma : dma address of Y frame buffer (luma) - * @c_fb_dma : dma address of C frame buffer (chroma) - * @poc : picture order count of frame buffer - * @reserved : for 8 bytes alignment - */ -struct h264_fb { - u64 vdec_fb_va; - u64 y_fb_dma; - u64 c_fb_dma; - s32 poc; - u32 reserved; -}; - /** * struct vdec_h264_dec_info - decode information * @dpb_sz : decoding picture buffer size @@ -212,265 +94,35 @@ struct vdec_h264_slice_inst { struct v4l2_h264_dpb_entry dpb[16]; }; -static void *get_ctrl_ptr(struct mtk_vcodec_ctx *ctx, int id) -{ - struct v4l2_ctrl *ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, id); - - return ctrl->p_cur.p; -} - -static void get_h264_dpb_list(struct vdec_h264_slice_inst *inst, - struct mtk_h264_dec_slice_param *slice_param) -{ - struct vb2_queue *vq; - struct vb2_buffer *vb; - struct vb2_v4l2_buffer *vb2_v4l2; - u64 index; - - vq = v4l2_m2m_get_vq(inst->ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - - for (index = 0; index < ARRAY_SIZE(slice_param->decode_params.dpb); index++) { - const struct slice_h264_dpb_entry *dpb; - int vb2_index; - - dpb = &slice_param->decode_params.dpb[index]; - if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) { - slice_param->h264_dpb_info[index].reference_flag = 0; - continue; - } - - vb2_index = vb2_find_timestamp(vq, dpb->reference_ts, 0); - if (vb2_index < 0) { - mtk_vcodec_err(inst, "Reference invalid: dpb_index(%lld) reference_ts(%lld)", - index, dpb->reference_ts); - continue; - } - /* 1 for short term reference, 2 for long term reference */ - if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) - slice_param->h264_dpb_info[index].reference_flag = 1; - else - slice_param->h264_dpb_info[index].reference_flag = 2; - - vb = vq->bufs[vb2_index]; - vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf); - slice_param->h264_dpb_info[index].field = vb2_v4l2->field; - - slice_param->h264_dpb_info[index].y_dma_addr = - vb2_dma_contig_plane_dma_addr(vb, 0); - if (inst->ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) { - slice_param->h264_dpb_info[index].c_dma_addr = - vb2_dma_contig_plane_dma_addr(vb, 1); - } - } -} - -static void get_h264_sps_parameters(struct mtk_h264_sps_param *dst_param, - const struct v4l2_ctrl_h264_sps *src_param) -{ - GET_MTK_VDEC_PARAM(chroma_format_idc); - GET_MTK_VDEC_PARAM(bit_depth_luma_minus8); - GET_MTK_VDEC_PARAM(bit_depth_chroma_minus8); - GET_MTK_VDEC_PARAM(log2_max_frame_num_minus4); - GET_MTK_VDEC_PARAM(pic_order_cnt_type); - GET_MTK_VDEC_PARAM(log2_max_pic_order_cnt_lsb_minus4); - GET_MTK_VDEC_PARAM(max_num_ref_frames); - GET_MTK_VDEC_PARAM(pic_width_in_mbs_minus1); - GET_MTK_VDEC_PARAM(pic_height_in_map_units_minus1); - - GET_MTK_VDEC_FLAG(separate_colour_plane_flag, - V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE); - GET_MTK_VDEC_FLAG(qpprime_y_zero_transform_bypass_flag, - V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS); - GET_MTK_VDEC_FLAG(delta_pic_order_always_zero_flag, - V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO); - GET_MTK_VDEC_FLAG(frame_mbs_only_flag, - V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY); - GET_MTK_VDEC_FLAG(mb_adaptive_frame_field_flag, - V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD); - GET_MTK_VDEC_FLAG(direct_8x8_inference_flag, - V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE); -} - -static void get_h264_pps_parameters(struct mtk_h264_pps_param *dst_param, - const struct v4l2_ctrl_h264_pps *src_param) -{ - GET_MTK_VDEC_PARAM(num_ref_idx_l0_default_active_minus1); - GET_MTK_VDEC_PARAM(num_ref_idx_l1_default_active_minus1); - GET_MTK_VDEC_PARAM(weighted_bipred_idc); - GET_MTK_VDEC_PARAM(pic_init_qp_minus26); - GET_MTK_VDEC_PARAM(chroma_qp_index_offset); - GET_MTK_VDEC_PARAM(second_chroma_qp_index_offset); - - GET_MTK_VDEC_FLAG(entropy_coding_mode_flag, - V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE); - GET_MTK_VDEC_FLAG(pic_order_present_flag, - V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT); - GET_MTK_VDEC_FLAG(weighted_pred_flag, - V4L2_H264_PPS_FLAG_WEIGHTED_PRED); - GET_MTK_VDEC_FLAG(deblocking_filter_control_present_flag, - V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT); - GET_MTK_VDEC_FLAG(constrained_intra_pred_flag, - V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED); - GET_MTK_VDEC_FLAG(redundant_pic_cnt_present_flag, - V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT); - GET_MTK_VDEC_FLAG(transform_8x8_mode_flag, - V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE); - GET_MTK_VDEC_FLAG(scaling_matrix_present_flag, - V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT); -} - -static void -get_h264_scaling_matrix(struct slice_api_h264_scaling_matrix *dst_matrix, - const struct v4l2_ctrl_h264_scaling_matrix *src_matrix) -{ - memcpy(dst_matrix->scaling_list_4x4, src_matrix->scaling_list_4x4, - sizeof(dst_matrix->scaling_list_4x4)); - - memcpy(dst_matrix->scaling_list_8x8, src_matrix->scaling_list_8x8, - sizeof(dst_matrix->scaling_list_8x8)); -} - -static void -get_h264_decode_parameters(struct slice_api_h264_decode_param *dst_params, - const struct v4l2_ctrl_h264_decode_params *src_params, - const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(dst_params->dpb); i++) { - struct slice_h264_dpb_entry *dst_entry = &dst_params->dpb[i]; - const struct v4l2_h264_dpb_entry *src_entry = &dpb[i]; - - dst_entry->reference_ts = src_entry->reference_ts; - dst_entry->frame_num = src_entry->frame_num; - dst_entry->pic_num = src_entry->pic_num; - dst_entry->top_field_order_cnt = src_entry->top_field_order_cnt; - dst_entry->bottom_field_order_cnt = - src_entry->bottom_field_order_cnt; - dst_entry->flags = src_entry->flags; - } - - /* - * num_slices is a leftover from the old H.264 support and is ignored - * by the firmware. - */ - dst_params->num_slices = 0; - dst_params->nal_ref_idc = src_params->nal_ref_idc; - dst_params->top_field_order_cnt = src_params->top_field_order_cnt; - dst_params->bottom_field_order_cnt = src_params->bottom_field_order_cnt; - dst_params->flags = src_params->flags; -} - -static bool dpb_entry_match(const struct v4l2_h264_dpb_entry *a, - const struct v4l2_h264_dpb_entry *b) -{ - return a->top_field_order_cnt == b->top_field_order_cnt && - a->bottom_field_order_cnt == b->bottom_field_order_cnt; -} - -/* - * Move DPB entries of dec_param that refer to a frame already existing in dpb - * into the already existing slot in dpb, and move other entries into new slots. - * - * This function is an adaptation of the similarly-named function in - * hantro_h264.c. - */ -static void update_dpb(const struct v4l2_ctrl_h264_decode_params *dec_param, - struct v4l2_h264_dpb_entry *dpb) -{ - DECLARE_BITMAP(new, ARRAY_SIZE(dec_param->dpb)) = { 0, }; - DECLARE_BITMAP(in_use, ARRAY_SIZE(dec_param->dpb)) = { 0, }; - DECLARE_BITMAP(used, ARRAY_SIZE(dec_param->dpb)) = { 0, }; - unsigned int i, j; - - /* Disable all entries by default, and mark the ones in use. */ - for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) { - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) - set_bit(i, in_use); - dpb[i].flags &= ~V4L2_H264_DPB_ENTRY_FLAG_ACTIVE; - } - - /* Try to match new DPB entries with existing ones by their POCs. */ - for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) { - const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; - - if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) - continue; - - /* - * To cut off some comparisons, iterate only on target DPB - * entries were already used. - */ - for_each_set_bit(j, in_use, ARRAY_SIZE(dec_param->dpb)) { - struct v4l2_h264_dpb_entry *cdpb; - - cdpb = &dpb[j]; - if (!dpb_entry_match(cdpb, ndpb)) - continue; - - *cdpb = *ndpb; - set_bit(j, used); - /* Don't reiterate on this one. */ - clear_bit(j, in_use); - break; - } - - if (j == ARRAY_SIZE(dec_param->dpb)) - set_bit(i, new); - } - - /* For entries that could not be matched, use remaining free slots. */ - for_each_set_bit(i, new, ARRAY_SIZE(dec_param->dpb)) { - const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; - struct v4l2_h264_dpb_entry *cdpb; - - /* - * Both arrays are of the same sizes, so there is no way - * we can end up with no space in target array, unless - * something is buggy. - */ - j = find_first_zero_bit(used, ARRAY_SIZE(dec_param->dpb)); - if (WARN_ON(j >= ARRAY_SIZE(dec_param->dpb))) - return; - - cdpb = &dpb[j]; - *cdpb = *ndpb; - set_bit(j, used); - } -} - -/* - * The firmware expects unused reflist entries to have the value 0x20. - */ -static void fixup_ref_list(u8 *ref_list, size_t num_valid) -{ - memset(&ref_list[num_valid], 0x20, 32 - num_valid); -} - static void get_vdec_decode_parameters(struct vdec_h264_slice_inst *inst) { const struct v4l2_ctrl_h264_decode_params *dec_params = - get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS); + mtk_vdec_h264_get_ctrl_ptr(inst->ctx, + V4L2_CID_STATELESS_H264_DECODE_PARAMS); const struct v4l2_ctrl_h264_sps *sps = - get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SPS); + mtk_vdec_h264_get_ctrl_ptr(inst->ctx, + V4L2_CID_STATELESS_H264_SPS); const struct v4l2_ctrl_h264_pps *pps = - get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_PPS); + mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_PPS); const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix = - get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SCALING_MATRIX); + mtk_vdec_h264_get_ctrl_ptr(inst->ctx, + V4L2_CID_STATELESS_H264_SCALING_MATRIX); struct mtk_h264_dec_slice_param *slice_param = &inst->h264_slice_param; struct v4l2_h264_reflist_builder reflist_builder; u8 *p0_reflist = slice_param->decode_params.ref_pic_list_p0; u8 *b0_reflist = slice_param->decode_params.ref_pic_list_b0; u8 *b1_reflist = slice_param->decode_params.ref_pic_list_b1; - update_dpb(dec_params, inst->dpb); + mtk_vdec_h264_update_dpb(dec_params, inst->dpb); - get_h264_sps_parameters(&slice_param->sps, sps); - get_h264_pps_parameters(&slice_param->pps, pps); - get_h264_scaling_matrix(&slice_param->scaling_matrix, scaling_matrix); - get_h264_decode_parameters(&slice_param->decode_params, dec_params, - inst->dpb); - get_h264_dpb_list(inst, slice_param); + mtk_vdec_h264_copy_sps_params(&slice_param->sps, sps); + mtk_vdec_h264_copy_pps_params(&slice_param->pps, pps); + mtk_vdec_h264_copy_scaling_matrix(&slice_param->scaling_matrix, + scaling_matrix); + mtk_vdec_h264_copy_decode_params(&slice_param->decode_params, + dec_params, inst->dpb); + mtk_vdec_h264_fill_dpb_info(inst->ctx, &slice_param->decode_params, + slice_param->h264_dpb_info); /* Build the reference lists */ v4l2_h264_init_reflist_builder(&reflist_builder, dec_params, sps, @@ -478,21 +130,14 @@ static void get_vdec_decode_parameters(struct vdec_h264_slice_inst *inst) v4l2_h264_build_p_ref_list(&reflist_builder, p0_reflist); v4l2_h264_build_b_ref_lists(&reflist_builder, b0_reflist, b1_reflist); /* Adapt the built lists to the firmware's expectations */ - fixup_ref_list(p0_reflist, reflist_builder.num_valid); - fixup_ref_list(b0_reflist, reflist_builder.num_valid); - fixup_ref_list(b1_reflist, reflist_builder.num_valid); + mtk_vdec_h264_fixup_ref_list(p0_reflist, reflist_builder.num_valid); + mtk_vdec_h264_fixup_ref_list(b0_reflist, reflist_builder.num_valid); + mtk_vdec_h264_fixup_ref_list(b1_reflist, reflist_builder.num_valid); memcpy(&inst->vsi_ctx.h264_slice_params, slice_param, sizeof(inst->vsi_ctx.h264_slice_params)); } -static unsigned int get_mv_buf_size(unsigned int width, unsigned int height) -{ - int unit_size = (width / MB_UNIT_LEN) * (height / MB_UNIT_LEN) + 8; - - return HW_MB_STORE_SZ * unit_size; -} - static int allocate_predication_buf(struct vdec_h264_slice_inst *inst) { int err; @@ -525,7 +170,7 @@ static int alloc_mv_buf(struct vdec_h264_slice_inst *inst, int i; int err; struct mtk_vcodec_mem *mem = NULL; - unsigned int buf_sz = get_mv_buf_size(pic->buf_w, pic->buf_h); + unsigned int buf_sz = mtk_vdec_h264_get_mv_buf_size(pic->buf_w, pic->buf_h); mtk_v4l2_debug(3, "size = 0x%x", buf_sz); for (i = 0; i < H264_MAX_MV_NUM; i++) { @@ -674,7 +319,8 @@ static int vdec_h264_slice_decode(void *h_vdec, struct mtk_vcodec_mem *bs, { struct vdec_h264_slice_inst *inst = h_vdec; const struct v4l2_ctrl_h264_decode_params *dec_params = - get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS); + mtk_vdec_h264_get_ctrl_ptr(inst->ctx, + V4L2_CID_STATELESS_H264_DECODE_PARAMS); struct vdec_vpu_inst *vpu = &inst->vpu; struct mtk_video_dec_buf *src_buf_info; struct mtk_video_dec_buf *dst_buf_info; From patchwork Mon Jan 10 08:34:42 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?WXVuZmVpIERvbmcgKOiRo+S6kemjnik=?= X-Patchwork-Id: 531009 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 804A5C433EF for ; Mon, 10 Jan 2022 08:37:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241275AbiAJIgm (ORCPT ); Mon, 10 Jan 2022 03:36:42 -0500 Received: from mailgw02.mediatek.com ([210.61.82.184]:52746 "EHLO mailgw02.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S241313AbiAJIfz (ORCPT ); Mon, 10 Jan 2022 03:35:55 -0500 X-UUID: 2cb378de08c2489c9b696abf5c5bc74f-20220110 X-UUID: 2cb378de08c2489c9b696abf5c5bc74f-20220110 Received: from mtkexhb01.mediatek.inc [(172.21.101.102)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 2095534069; Mon, 10 Jan 2022 16:35:10 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs10n1.mediatek.inc (172.21.101.34) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.2.792.15; Mon, 10 Jan 2022 16:35:09 +0800 Received: from localhost.localdomain (10.17.3.154) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Mon, 10 Jan 2022 16:35:07 +0800 From: Yunfei Dong To: Yunfei Dong , Alexandre Courbot , Hans Verkuil , "Tzung-Bi Shih" , Tiffany Lin , Andrew-CT Chen , Mauro Carvalho Chehab , Rob Herring , Matthias Brugger , Tomasz Figa CC: George Sun , Xiaoyong Lu , Hsin-Yi Wang , Fritz Koenig , Dafna Hirschfeld , Benjamin Gaignard , Daniel Vetter , dri-devel , Irui Wang , AngeloGioacchino Del Regno , Steve Cho , , , , , , , Subject: [PATCH v4, 15/15] media: mtk-vcodec: support stateless VP9 decoding Date: Mon, 10 Jan 2022 16:34:42 +0800 Message-ID: <20220110083442.32604-16-yunfei.dong@mediatek.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220110083442.32604-1-yunfei.dong@mediatek.com> References: <20220110083442.32604-1-yunfei.dong@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Add support for VP9 decoding using the stateless API, as supported by MT8192. And the drivers is lat and core architecture. Signed-off-by: George Sun Co-developed-by: Yunfei Dong --- drivers/media/platform/mtk-vcodec/Makefile | 1 + .../mtk-vcodec/mtk_vcodec_dec_stateless.c | 26 +- .../platform/mtk-vcodec/mtk_vcodec_drv.h | 1 + .../mtk-vcodec/vdec/vdec_vp9_req_lat_if.c | 2066 +++++++++++++++++ .../media/platform/mtk-vcodec/vdec_drv_if.c | 4 + .../media/platform/mtk-vcodec/vdec_drv_if.h | 1 + 6 files changed, 2096 insertions(+), 3 deletions(-) create mode 100644 drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_req_lat_if.c diff --git a/drivers/media/platform/mtk-vcodec/Makefile b/drivers/media/platform/mtk-vcodec/Makefile index b457daf2d196..93e7a343b5b0 100644 --- a/drivers/media/platform/mtk-vcodec/Makefile +++ b/drivers/media/platform/mtk-vcodec/Makefile @@ -9,6 +9,7 @@ mtk-vcodec-dec-y := vdec/vdec_h264_if.o \ vdec/vdec_vp8_if.o \ vdec/vdec_vp8_req_if.o \ vdec/vdec_vp9_if.o \ + vdec/vdec_vp9_req_lat_if.o \ vdec/vdec_h264_req_if.o \ vdec/vdec_h264_req_common.o \ vdec/vdec_h264_req_multi_if.o \ diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c index 019055a0807d..03c1c873361a 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c @@ -91,13 +91,28 @@ static const struct mtk_stateless_control mtk_stateless_controls[] = { .max = V4L2_MPEG_VIDEO_VP8_PROFILE_3, }, .codec_type = V4L2_PIX_FMT_VP8_FRAME, - } + }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_DECODE_PARAMS, + }, + .codec_type = V4L2_PIX_FMT_VP9_FRAME, + }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_VP9_PROFILE, + .min = V4L2_MPEG_VIDEO_VP9_PROFILE_0, + .def = V4L2_MPEG_VIDEO_VP9_PROFILE_0, + .max = V4L2_MPEG_VIDEO_VP9_PROFILE_3, + }, + .codec_type = V4L2_PIX_FMT_VP9_FRAME, + }, }; #define NUM_CTRLS ARRAY_SIZE(mtk_stateless_controls) -static struct mtk_video_fmt mtk_video_formats[4]; -static struct mtk_codec_framesizes mtk_vdec_framesizes[2]; +static struct mtk_video_fmt mtk_video_formats[5]; +static struct mtk_codec_framesizes mtk_vdec_framesizes[3]; static struct mtk_video_fmt default_out_format; static struct mtk_video_fmt default_cap_format; @@ -368,6 +383,7 @@ static void mtk_vcodec_add_formats(unsigned int fourcc, switch (fourcc) { case V4L2_PIX_FMT_H264_SLICE: case V4L2_PIX_FMT_VP8_FRAME: + case V4L2_PIX_FMT_VP9_FRAME: mtk_video_formats[count_formats].fourcc = fourcc; mtk_video_formats[count_formats].type = MTK_FMT_DEC; mtk_video_formats[count_formats].num_planes = 1; @@ -416,6 +432,10 @@ static void mtk_vcodec_get_supported_formats(struct mtk_vcodec_ctx *ctx) mtk_vcodec_add_formats(V4L2_PIX_FMT_VP8_FRAME, ctx); out_format_count++; } + if (ctx->dev->dec_capability & MTK_VDEC_FORMAT_VP9_FRAME) { + mtk_vcodec_add_formats(V4L2_PIX_FMT_VP9_FRAME, ctx); + out_format_count++; + } if (cap_format_count) default_cap_format = mtk_video_formats[cap_format_count - 1]; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index 63ca6458929b..24bfbd1a6b3a 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -358,6 +358,7 @@ enum mtk_vdec_format_types { MTK_VDEC_FORMAT_MT21C = 0x40, MTK_VDEC_FORMAT_H264_SLICE = 0x100, MTK_VDEC_FORMAT_VP8_FRAME = 0x200, + MTK_VDEC_FORMAT_VP9_FRAME = 0x400, }; /** diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_req_lat_if.c new file mode 100644 index 000000000000..ca93bdc77165 --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_req_lat_if.c @@ -0,0 +1,2066 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + * Author: George Sun + */ + +#include +#include +#include + +#include "../mtk_vcodec_util.h" +#include "../mtk_vcodec_dec.h" +#include "../mtk_vcodec_intr.h" +#include "../vdec_drv_base.h" +#include "../vdec_drv_if.h" +#include "../vdec_vpu_if.h" + +/* reset_frame_context defined in VP9 spec */ +#define VP9_RESET_FRAME_CONTEXT_NONE0 0 +#define VP9_RESET_FRAME_CONTEXT_NONE1 1 +#define VP9_RESET_FRAME_CONTEXT_SPEC 2 +#define VP9_RESET_FRAME_CONTEXT_ALL 3 + +#define VP9_TILE_BUF_SIZE 4096 +#define VP9_PROB_BUF_SIZE 2560 +#define VP9_COUNTS_BUF_SIZE 16384 + +#define FOR_EACH_COEF_PROBS_BAND(t, i, j, k) \ + for (t = 0; t < 4; t++) \ + for (i = 0; i < 2; i++) \ + for (j = 0; j < 2; j++) \ + for (k = 0; k < 6; k++) + +#define HDR_FLAG(x) (!!((hdr)->flags & V4L2_VP9_FRAME_FLAG_##x)) +#define LF_FLAG(x) (!!((lf)->flags & V4L2_VP9_LOOP_FILTER_FLAG_##x)) +#define SEG_FLAG(x) (!!((seg)->flags & V4L2_VP9_SEGMENTATION_FLAG_##x)) + +/** + * struct vdec_vp9_slice_frame_ctx - vp9 prob tables footprint + */ +struct vdec_vp9_slice_frame_ctx { + struct { + __u8 probs[6][3]; + __u8 padding[2]; + } coef_probs[4][2][2][6]; + + __u8 y_mode_prob[4][16]; + __u8 switch_interp_prob[4][16]; + __u8 seg[32]; /* ignore */ + __u8 comp_inter_prob[16]; + __u8 comp_ref_prob[16]; + __u8 single_ref_prob[5][2]; + __u8 single_ref_prob_padding[6]; + + __u8 joint[3]; + __u8 joint_padding[13]; + struct { + __u8 sign; + __u8 classes[10]; + __u8 padding[5]; + } sign_classes[2]; + struct { + __u8 class0[1]; + __u8 bits[10]; + __u8 padding[5]; + } class0_bits[2]; + struct { + __u8 class0_fp[2][3]; + __u8 fp[3]; + __u8 class0_hp; + __u8 hp; + __u8 padding[5]; + } class0_fp_hp[2]; + + __u8 uv_mode_prob[10][16]; + __u8 uv_mode_prob_padding[2][16]; + + __u8 partition_prob[16][4]; + + __u8 inter_mode_probs[7][4]; + __u8 skip_probs[4]; + + __u8 tx_p8x8[2][4]; + __u8 tx_p16x16[2][4]; + __u8 tx_p32x32[2][4]; + __u8 intra_inter_prob[8]; +}; + +/** + * struct vdec_vp9_slice_frame_counts - vp9 counts tables footprint + */ +struct vdec_vp9_slice_frame_counts { + union { + struct { + __u32 band_0[3]; + __u32 padding0[1]; + __u32 band_1_5[5][6]; + __u32 padding1[2]; + } eob_branch[4][2][2]; + __u32 eob_branch_space[256 * 4]; + }; + + struct { + __u32 band_0[3][4]; + __u32 band_1_5[5][6][4]; + } coef_probs[4][2][2]; + + __u32 intra_inter[4][2]; + __u32 comp_inter[5][2]; + __u32 comp_inter_padding[2]; + __u32 comp_ref[5][2]; + __u32 comp_ref_padding[2]; + __u32 single_ref[5][2][2]; + __u32 inter_mode[7][4]; + __u32 y_mode[4][12]; + __u32 uv_mode[10][10]; + __u32 partition[16][4]; + __u32 switchable_interp[4][4]; + + __u32 tx_p8x8[2][2]; + __u32 tx_p16x16[2][4]; + __u32 tx_p32x32[2][4]; + + __u32 skip[3][4]; + + __u32 joint[4]; + + struct { + __u32 sign[2]; + __u32 class0[2]; + __u32 classes[12]; + __u32 bits[10][2]; + __u32 padding[4]; + __u32 class0_fp[2][4]; + __u32 fp[4]; + __u32 class0_hp[2]; + __u32 hp[2]; + } mvcomp[2]; + + __u32 reserved[126][4]; +}; + +/** + * struct vdec_vp9_slice_uncompressed_header - vp9 uncompressed header syntax + * used for decoding + */ +struct vdec_vp9_slice_uncompressed_header { + __u8 profile; + __u8 last_frame_type; + __u8 frame_type; + + __u8 last_show_frame; + __u8 show_frame; + __u8 error_resilient_mode; + + __u8 bit_depth; + __u8 padding0[1]; + __u16 last_frame_width; + __u16 last_frame_height; + __u16 frame_width; + __u16 frame_height; + + __u8 intra_only; + __u8 reset_frame_context; + __u8 ref_frame_sign_bias[4]; + __u8 allow_high_precision_mv; + __u8 interpolation_filter; + + __u8 refresh_frame_context; + __u8 frame_parallel_decoding_mode; + __u8 frame_context_idx; + + /* loop_filter_params */ + __u8 loop_filter_level; + __u8 loop_filter_sharpness; + __u8 loop_filter_delta_enabled; + __s8 loop_filter_ref_deltas[4]; + __s8 loop_filter_mode_deltas[2]; + + /* quantization_params */ + __u8 base_q_idx; + __s8 delta_q_y_dc; + __s8 delta_q_uv_dc; + __s8 delta_q_uv_ac; + + /* segmentation_params */ + __u8 segmentation_enabled; + __u8 segmentation_update_map; + __u8 segmentation_tree_probs[7]; + __u8 padding1[1]; + __u8 segmentation_temporal_udpate; + __u8 segmentation_pred_prob[3]; + __u8 segmentation_update_data; + __u8 segmentation_abs_or_delta_update; + __u8 feature_enabled[8]; + __s16 feature_value[8][4]; + + /* tile_info */ + __u8 tile_cols_log2; + __u8 tile_rows_log2; + __u8 padding2[2]; + + __u16 uncompressed_header_size; + __u16 header_size_in_bytes; + + /* LAT OUT, CORE IN */ + __u32 dequant[8][4]; +}; + +/** + * struct vdec_vp9_slice_compressed_header - vp9 compressed header syntax + * used for decoding. + */ +struct vdec_vp9_slice_compressed_header { + __u8 tx_mode; + __u8 ref_mode; + __u8 comp_fixed_ref; + __u8 comp_var_ref[2]; + __u8 padding[3]; +}; + +/** + * struct vdec_vp9_slice_tiles - vp9 tile syntax + */ +struct vdec_vp9_slice_tiles { + __u32 size[4][64]; + __u32 mi_rows[4]; + __u32 mi_cols[64]; + __u8 actual_rows; + __u8 padding[7]; +}; + +/** + * struct vdec_vp9_slice_reference - vp9 reference frame information + */ +struct vdec_vp9_slice_reference { + __u16 frame_width; + __u16 frame_height; + __u8 bit_depth; + __u8 subsampling_x; + __u8 subsampling_y; + __u8 padding; +}; + +/** + * struct vdec_vp9_slice_frame - vp9 syntax used for decoding + */ +struct vdec_vp9_slice_frame { + struct vdec_vp9_slice_uncompressed_header uh; + struct vdec_vp9_slice_compressed_header ch; + struct vdec_vp9_slice_tiles tiles; + struct vdec_vp9_slice_reference ref[3]; +}; + +/** + * struct vdec_vp9_slice_init_vsi - VSI used to initialize instance + */ +struct vdec_vp9_slice_init_vsi { + unsigned int architecture; + unsigned int reserved; + uint64_t core_vsi; + /* default frame context's position in MicroP */ + uint64_t default_frame_ctx; +}; + +/** + * struct vdec_vp9_slice_mem - memory address and size + */ +struct vdec_vp9_slice_mem { + union { + uint64_t buf; + dma_addr_t dma_addr; + }; + union { + size_t size; + dma_addr_t dma_addr_end; + uint64_t padding; + }; +}; + +/** + * struct vdec_vp9_slice_bs - input buffer for decoding + */ +struct vdec_vp9_slice_bs { + struct vdec_vp9_slice_mem buf; + struct vdec_vp9_slice_mem frame; +}; + +/** + * struct vdec_vp9_slice_fb - frame buffer for decoding + */ +struct vdec_vp9_slice_fb { + struct vdec_vp9_slice_mem y; + struct vdec_vp9_slice_mem c; +}; + +/** + * struct vdec_vp9_slice_state - decoding state + */ +struct vdec_vp9_slice_state { + int err; + unsigned int full; + unsigned int timeout; + unsigned int perf; + + unsigned int crc[12]; +}; + +/* + * struct vdec_vp9_slice_vsi - exchange decoding information + * between Main CPU and MicroP + * @bs : input buffer + * @fb : output buffer + * @ref : 3 reference buffers + * @mv : mv working buffer + * @seg : segmentation working buffer + * @tile : tile buffer + * @prob : prob table buffer, used to set/update prob table + * @counts : counts table buffer, used to update prob table + * @ube : general buffer + * @trans : trans buffer position in general buffer + * @err_map : error buffer + * @row_info : row info buffer + * @frame : decoding syntax + * @state : decoding state + */ +struct vdec_vp9_slice_vsi { + /* used in LAT stage */ + struct vdec_vp9_slice_bs bs; + /* used in Core stage */ + struct vdec_vp9_slice_fb fb; + struct vdec_vp9_slice_fb ref[3]; + + struct vdec_vp9_slice_mem mv[2]; + struct vdec_vp9_slice_mem seg[2]; + struct vdec_vp9_slice_mem tile; + struct vdec_vp9_slice_mem prob; + struct vdec_vp9_slice_mem counts; + + /* LAT stage's output, Core stage's input */ + struct vdec_vp9_slice_mem ube; + struct vdec_vp9_slice_mem trans; + struct vdec_vp9_slice_mem err_map; + struct vdec_vp9_slice_mem row_info; + + /* decoding parameters */ + struct vdec_vp9_slice_frame frame; + + struct vdec_vp9_slice_state state; +}; + +/* + * struct vdec_vp9_slice_pfc - per-frame context that contains a local vsi. + * pass it from lat to core + * @vsi : local vsi. copy to/from remote vsi before/after decoding + * @ref_idx : reference buffer index + * @seq : picture sequence + * @state : decoding state + */ +struct vdec_vp9_slice_pfc { + struct vdec_vp9_slice_vsi vsi; + + u64 ref_idx[3]; + + int seq; + + /* LAT/Core CRC */ + struct vdec_vp9_slice_state state[2]; +}; + +/* + * enum vdec_vp9_slice_resolution_level + */ +enum vdec_vp9_slice_resolution_level { + VP9_RES_NONE, + VP9_RES_FHD, + VP9_RES_4K, + VP9_RES_8K, +}; + +/* + * struct vdec_vp9_slice_ref - picture's width & height should kept + * for later decoding as reference picture + */ +struct vdec_vp9_slice_ref { + unsigned int width; + unsigned int height; +}; + +/* + * struct vdec_vp9_slice_instance - represent one vp9 instance + * @ctx : pointer to codec's context + * @vpu : VPU instance + * @seq : global picture sequence + * @level : level of current resolution + * @width : width of last picture + * @height : height of last picture + * @frame_type : frame_type of last picture + * @irq : irq to Main CPU or MicroP + * @show_frame : show_frame of last picture + * @dpb : picture information (width/height) for reference + * @mv : mv working buffer + * @seg : segmentation working buffer + * @tile : tile buffer + * @prob : prob table buffer, used to set/update prob table + * @counts : counts table buffer, used to update prob table + * @frame_ctx : 4 frame context according to VP9 Spec + * @dirty : state of each frame context + * @init_vsi : vsi used for initialized VP9 instance + * @vsi : vsi used for decoding/flush ... + * @core_vsi : vsi used for Core stage + */ +struct vdec_vp9_slice_instance { + struct mtk_vcodec_ctx *ctx; + struct vdec_vpu_inst vpu; + + int seq; + + enum vdec_vp9_slice_resolution_level level; + + /* for resolution change and get_pic_info */ + unsigned int width; + unsigned int height; + + /* for last_frame_type */ + unsigned int frame_type; + unsigned int irq; + + unsigned int show_frame; + + /* maintain vp9 reference frame state */ + struct vdec_vp9_slice_ref dpb[VB2_MAX_FRAME]; + + /* + * normal working buffers + * mv[0]/seg[0]/tile/prob/counts is used for LAT + * mv[1]/seg[1] is used for CORE + */ + struct mtk_vcodec_mem mv[2]; + struct mtk_vcodec_mem seg[2]; + struct mtk_vcodec_mem tile; + struct mtk_vcodec_mem prob; + struct mtk_vcodec_mem counts; + + /* 4 prob tables */ + struct vdec_vp9_slice_frame_ctx frame_ctx[4]; + unsigned char dirty[4]; + + /* MicroP vsi */ + union { + struct vdec_vp9_slice_init_vsi *init_vsi; + struct vdec_vp9_slice_vsi *vsi; + }; + struct vdec_vp9_slice_vsi *core_vsi; +}; + +/* + * (2, (0, (1, 3))) + * max level = 2 + */ +static const signed char vdec_vp9_slice_inter_mode_tree[6] = { + -2, 2, 0, 4, -1, -3 +}; + +/* max level = 6 */ +static const signed char vdec_vp9_slice_intra_mode_tree[18] = { + 0, 2, -9, 4, -1, 6, 8, 12, -2, 10, -4, -5, -3, 14, -8, 16, -6, -7 +}; + +/* max level = 2 */ +static const signed char vdec_vp9_slice_partition_tree[6] = { + 0, 2, -1, 4, -2, -3 +}; + +/* max level = 1 */ +static const signed char vdec_vp9_slice_switchable_interp_tree[4] = { + 0, 2, -1, -2 +}; + +/* max level = 2 */ +static const signed char vdec_vp9_slice_mv_joint_tree[6] = { + 0, 2, -1, 4, -2, -3 +}; + +/* max level = 6 */ +static const signed char vdec_vp9_slice_mv_class_tree[20] = { + 0, 2, -1, 4, 6, 8, -2, -3, 10, 12, + -4, -5, -6, 14, 16, 18, -7, -8, -9, -10 +}; + +/* max level = 0 */ +static const signed char vdec_vp9_slice_mv_class0_tree[2] = { + 0, -1 +}; + +/* max level = 2 */ +static const signed char vdec_vp9_slice_mv_fp_tree[6] = { + 0, 2, -1, 4, -2, -3 +}; + +/* + * all VP9 instances could share this default frame context. + */ +static struct vdec_vp9_slice_frame_ctx *vdec_vp9_slice_default_frame_ctx; +static DEFINE_MUTEX(vdec_vp9_slice_frame_ctx_lock); + +static int vdec_vp9_slice_core_decode( + struct vdec_lat_buf *lat_buf); + +static int vdec_vp9_slice_init_default_frame_ctx( + struct vdec_vp9_slice_instance *instance) +{ + struct vdec_vp9_slice_frame_ctx *remote_frame_ctx; + struct vdec_vp9_slice_frame_ctx *frame_ctx; + struct mtk_vcodec_ctx *ctx; + struct vdec_vp9_slice_init_vsi *vsi; + int ret = 0; + + ctx = instance->ctx; + vsi = instance->vpu.vsi; + if (!ctx || !vsi) { + mtk_vcodec_err(instance, "invalid ctx or vsi 0x%px 0x%px\n", + ctx, vsi); + return -EINVAL; + } + + remote_frame_ctx = mtk_vcodec_fw_map_dm_addr(ctx->dev->fw_handler, + (u32)vsi->default_frame_ctx); + if (!remote_frame_ctx) { + mtk_vcodec_err(instance, "failed to map default frame ctx\n"); + return -EINVAL; + } + + mtk_vcodec_debug(instance, "map default frame ctx to 0x%px\n", + remote_frame_ctx); + + mutex_lock(&vdec_vp9_slice_frame_ctx_lock); + + if (vdec_vp9_slice_default_frame_ctx) + goto out; + + frame_ctx = kmalloc(sizeof(*frame_ctx), GFP_KERNEL); + if (!frame_ctx) { + ret = -ENOMEM; + goto out; + } + + memcpy_fromio(frame_ctx, remote_frame_ctx, sizeof(*frame_ctx)); + vdec_vp9_slice_default_frame_ctx = frame_ctx; + +out: + mutex_unlock(&vdec_vp9_slice_frame_ctx_lock); + + return ret; +} + +static int vdec_vp9_slice_alloc_working_buffer( + struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_vsi *vsi) +{ + struct mtk_vcodec_ctx *ctx = instance->ctx; + enum vdec_vp9_slice_resolution_level level; + /* super blocks */ + unsigned int max_sb_w; + unsigned int max_sb_h; + unsigned int max_w; + unsigned int max_h; + unsigned int w; + unsigned int h; + size_t size; + int ret; + int i; + + w = vsi->frame.uh.frame_width; + h = vsi->frame.uh.frame_height; + + if (w > VCODEC_DEC_4K_CODED_WIDTH || + h > VCODEC_DEC_4K_CODED_HEIGHT) { + /* 8K? */ + return -EINVAL; + } else if (w > MTK_VDEC_MAX_W || h > MTK_VDEC_MAX_H) { + /* 4K */ + level = VP9_RES_4K; + max_w = VCODEC_DEC_4K_CODED_WIDTH; + max_h = VCODEC_DEC_4K_CODED_HEIGHT; + } else { + /* FHD */ + level = VP9_RES_FHD; + max_w = MTK_VDEC_MAX_W; + max_h = MTK_VDEC_MAX_H; + } + + if (level == instance->level) + return 0; + + mtk_vcodec_debug(instance, + "resolution level changed, from %u to %u, %ux%u", + instance->level, level, w, h); + + max_sb_w = DIV_ROUND_UP(max_w, 64); + max_sb_h = DIV_ROUND_UP(max_h, 64); + ret = -ENOMEM; + + /* + * Lat-flush must wait core idle, otherwise core will + * use released buffers + */ + + size = (max_sb_w * max_sb_h + 2) * 576; + for (i = 0; i < 2; i++) { + if (instance->mv[i].va) + mtk_vcodec_mem_free(ctx, &instance->mv[i]); + instance->mv[i].size = size; + if (mtk_vcodec_mem_alloc(ctx, &instance->mv[i])) + goto err; + } + + size = (max_sb_w * max_sb_h * 32) + 256; + for (i = 0; i < 2; i++) { + if (instance->seg[i].va) + mtk_vcodec_mem_free(ctx, &instance->seg[i]); + instance->seg[i].size = size; + if (mtk_vcodec_mem_alloc(ctx, &instance->seg[i])) + goto err; + } + + if (!instance->tile.va) { + instance->tile.size = VP9_TILE_BUF_SIZE; + if (mtk_vcodec_mem_alloc(ctx, &instance->tile)) + goto err; + } + + if (!instance->prob.va) { + instance->prob.size = VP9_PROB_BUF_SIZE; + if (mtk_vcodec_mem_alloc(ctx, &instance->prob)) + goto err; + } + + if (!instance->counts.va) { + instance->counts.size = VP9_COUNTS_BUF_SIZE; + if (mtk_vcodec_mem_alloc(ctx, &instance->counts)) + goto err; + } + + instance->level = level; + return 0; + +err: + instance->level = VP9_RES_NONE; + return ret; +} + +static void vdec_vp9_slice_free_working_buffer( + struct vdec_vp9_slice_instance *instance) +{ + struct mtk_vcodec_ctx *ctx = instance->ctx; + int i; + + for (i = 0; i < ARRAY_SIZE(instance->mv); i++) { + if (instance->mv[i].va) + mtk_vcodec_mem_free(ctx, &instance->mv[i]); + } + for (i = 0; i < ARRAY_SIZE(instance->seg); i++) { + if (instance->seg[i].va) + mtk_vcodec_mem_free(ctx, &instance->seg[i]); + } + if (instance->tile.va) + mtk_vcodec_mem_free(ctx, &instance->tile); + if (instance->prob.va) + mtk_vcodec_mem_free(ctx, &instance->prob); + if (instance->counts.va) + mtk_vcodec_mem_free(ctx, &instance->counts); + + instance->level = VP9_RES_NONE; +} + +static void vdec_vp9_slice_vsi_from_remote( + struct vdec_vp9_slice_vsi *vsi, + struct vdec_vp9_slice_vsi *remote_vsi, + int skip) +{ + struct vdec_vp9_slice_frame *rf; + struct vdec_vp9_slice_frame *f; + + /* + * compressed header + * dequant + * buffer position + * decode state + */ + if (!skip) { + rf = &remote_vsi->frame; + f = &vsi->frame; + memcpy_fromio(&f->ch, &rf->ch, sizeof(f->ch)); + memcpy_fromio(&f->uh.dequant, &rf->uh.dequant, + sizeof(f->uh.dequant)); + memcpy_fromio(&vsi->trans, &remote_vsi->trans, + sizeof(vsi->trans)); + } + + memcpy_fromio(&vsi->state, &remote_vsi->state, sizeof(vsi->state)); +} + +static void vdec_vp9_slice_vsi_to_remote( + struct vdec_vp9_slice_vsi *vsi, + struct vdec_vp9_slice_vsi *remote_vsi) +{ + memcpy_toio(remote_vsi, vsi, sizeof(*vsi)); +} + +static int vdec_vp9_slice_tile_offset(int idx, + int mi_num, int tile_log2) +{ + int sbs = (mi_num + 7) >> 3; + int offset = ((idx * sbs) >> tile_log2) << 3; + return offset < mi_num ? offset : mi_num; +} + +static int vdec_vp9_slice_setup_lat_from_src_buf( + struct vdec_vp9_slice_instance *instance, + struct vdec_lat_buf *lat_buf) +{ + struct vb2_v4l2_buffer *src; + struct vb2_v4l2_buffer *dst; + + src = v4l2_m2m_next_src_buf(instance->ctx->m2m_ctx); + if (!src) + return -EINVAL; + + dst = &lat_buf->ts_info; + v4l2_m2m_buf_copy_metadata(src, dst, true); + return 0; +} + +static void vdec_vp9_slice_setup_hdr( + struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_uncompressed_header *uh, + struct v4l2_ctrl_vp9_frame_decode_params *hdr) +{ + int i; + + uh->profile = hdr->profile; + uh->last_frame_type = instance->frame_type; + uh->frame_type = !HDR_FLAG(KEY_FRAME); + uh->last_show_frame = instance->show_frame; + uh->show_frame = HDR_FLAG(SHOW_FRAME); + uh->error_resilient_mode = HDR_FLAG(ERROR_RESILIENT); + uh->bit_depth = hdr->bit_depth; + uh->last_frame_width = instance->width; + uh->last_frame_height = instance->height; + uh->frame_width = hdr->frame_width_minus_1 + 1; + uh->frame_height = hdr->frame_height_minus_1 + 1; + uh->intra_only = HDR_FLAG(INTRA_ONLY); + /* map v4l2 enum to values defined in VP9 spec for firmware */ + switch (hdr->reset_frame_context) { + case V4L2_VP9_RESET_FRAME_CTX_NONE: + uh->reset_frame_context = VP9_RESET_FRAME_CONTEXT_NONE0; + break; + case V4L2_VP9_RESET_FRAME_CTX_SPEC: + uh->reset_frame_context = VP9_RESET_FRAME_CONTEXT_SPEC; + break; + case V4L2_VP9_RESET_FRAME_CTX_ALL: + uh->reset_frame_context = VP9_RESET_FRAME_CONTEXT_ALL; + break; + default: + uh->reset_frame_context = VP9_RESET_FRAME_CONTEXT_NONE0; + break; + } + /* + * ref_frame_sign_bias specifies the intended direction + * of the motion vector in time for each reference frame. + * - INTRA_FRAME = 0, + * - LAST_FRAME = 1, + * - GOLDEN_FRAME = 2, + * - ALTREF_FRAME = 3, + * ref_frame_sign_biases[INTRA_FRAME] is always 0 + * and VDA only passes another 3 directions + */ + uh->ref_frame_sign_bias[0] = 0; + for (i = 0; i < 3; i++) + uh->ref_frame_sign_bias[i + 1] = + !!(hdr->ref_frame_sign_biases & (1 << i)); + uh->allow_high_precision_mv = HDR_FLAG(ALLOW_HIGH_PREC_MV); + uh->interpolation_filter = hdr->interpolation_filter; + uh->refresh_frame_context = HDR_FLAG(REFRESH_FRAME_CTX); + uh->frame_parallel_decoding_mode = HDR_FLAG(PARALLEL_DEC_MODE); + uh->frame_context_idx = hdr->frame_context_idx; + + /* tile info */ + uh->tile_cols_log2 = hdr->tile_cols_log2; + uh->tile_rows_log2 = hdr->tile_rows_log2; + + uh->uncompressed_header_size = hdr->uncompressed_header_size; + uh->header_size_in_bytes = hdr->compressed_header_size; +} + +static void vdec_vp9_slice_setup_frame_ctx( + struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_uncompressed_header *uh, + struct v4l2_ctrl_vp9_frame_decode_params *hdr) +{ + int error_resilient_mode; + int reset_frame_context; + int key_frame; + int intra_only; + int i; + + key_frame = HDR_FLAG(KEY_FRAME); + intra_only = HDR_FLAG(INTRA_ONLY); + error_resilient_mode = HDR_FLAG(ERROR_RESILIENT); + reset_frame_context = uh->reset_frame_context; + + /* + * according to "6.2 Uncompressed header syntax" in + * "VP9 Bitstream & Decoding Process Specification", + * reset @frame_context_idx when (FrameIsIntra || error_resilient_mode) + */ + if (key_frame || intra_only || error_resilient_mode) { + /* + * @reset_frame_context specifies + * whether the frame context should be + * reset to default values: + * 0 or 1 means do not reset any frame context + * 2 resets just the context specified in the frame header + * 3 resets all contexts + */ + if (key_frame || error_resilient_mode || + reset_frame_context == 3) { + /* use default table */ + for (i = 0; i < 4; i++) + instance->dirty[i] = 0; + } else if (reset_frame_context == 2) { + instance->dirty[uh->frame_context_idx] = 0; + } else { + ; + } + uh->frame_context_idx = 0; + } +} + +static void vdec_vp9_slice_setup_loop_filter( + struct vdec_vp9_slice_uncompressed_header *uh, + struct v4l2_vp9_loop_filter *lf) +{ + int i; + + uh->loop_filter_level = lf->level; + uh->loop_filter_sharpness = lf->sharpness; + uh->loop_filter_delta_enabled = LF_FLAG(DELTA_ENABLED); + for (i = 0; i < 4; i++) + uh->loop_filter_ref_deltas[i] = lf->ref_deltas[i]; + for (i = 0; i < 2; i++) + uh->loop_filter_mode_deltas[i] = lf->mode_deltas[i]; +} + +static void vdec_vp9_slice_setup_quantization( + struct vdec_vp9_slice_uncompressed_header *uh, + struct v4l2_vp9_quantization *quant) +{ + uh->base_q_idx = quant->base_q_idx; + uh->delta_q_y_dc = quant->delta_q_y_dc; + uh->delta_q_uv_dc = quant->delta_q_uv_dc; + uh->delta_q_uv_ac = quant->delta_q_uv_ac; +} + +static void vdec_vp9_slice_setup_segmentation( + struct vdec_vp9_slice_uncompressed_header *uh, + struct v4l2_vp9_segmentation *seg) +{ + int i; + int j; + + uh->segmentation_enabled = SEG_FLAG(ENABLED); + uh->segmentation_update_map = SEG_FLAG(UPDATE_MAP); + for (i = 0; i < 7; i++) + uh->segmentation_tree_probs[i] = seg->tree_probs[i]; + uh->segmentation_temporal_udpate = SEG_FLAG(TEMPORAL_UPDATE); + for (i = 0; i < 3; i++) + uh->segmentation_pred_prob[i] = seg->pred_probs[i]; + uh->segmentation_update_data = SEG_FLAG(UPDATE_DATA); + uh->segmentation_abs_or_delta_update = SEG_FLAG(ABS_OR_DELTA_UPDATE); + for (i = 0; i < 8; i++) { + uh->feature_enabled[i] = seg->feature_enabled[i]; + for (j = 0; j < 4; j++) + uh->feature_value[i][j] = seg->feature_data[i][j]; + } +} + +static int vdec_vp9_slice_setup_tile(struct vdec_vp9_slice_vsi *vsi, + struct v4l2_ctrl_vp9_frame_decode_params *hdr) +{ + unsigned int rows_log2; + unsigned int cols_log2; + unsigned int rows; + unsigned int cols; + unsigned int mi_rows; + unsigned int mi_cols; + struct vdec_vp9_slice_tiles *tiles; + int offset; + int start; + int end; + int i; + + rows_log2 = hdr->tile_rows_log2; + cols_log2 = hdr->tile_cols_log2; + rows = 1 << rows_log2; + cols = 1 << cols_log2; + tiles = &vsi->frame.tiles; + tiles->actual_rows = 0; + + if (rows > 4 || cols > 64) + return -EINVAL; + + /* setup mi rows/cols information */ + mi_rows = (hdr->frame_height_minus_1 + 1 + 7) >> 3; + mi_cols = (hdr->frame_width_minus_1 + 1 + 7) >> 3; + + for (i = 0; i < rows; i++) { + start = vdec_vp9_slice_tile_offset(i, mi_rows, rows_log2); + end = vdec_vp9_slice_tile_offset(i + 1, mi_rows, rows_log2); + offset = end - start; + tiles->mi_rows[i] = (offset + 7) >> 3; + if (tiles->mi_rows[i]) + tiles->actual_rows++; + } + + for (i = 0; i < cols; i++) { + start = vdec_vp9_slice_tile_offset(i, mi_cols, cols_log2); + end = vdec_vp9_slice_tile_offset(i + 1, mi_cols, cols_log2); + offset = end - start; + tiles->mi_cols[i] = (offset + 7) >> 3; + } + + return 0; +} + +static void vdec_vp9_slice_setup_state(struct vdec_vp9_slice_vsi *vsi) +{ + memset(&vsi->state, 0, sizeof(vsi->state)); +} + +static void vdec_vp9_slice_setup_ref_idx( + struct vdec_vp9_slice_pfc *pfc, + struct v4l2_ctrl_vp9_frame_decode_params *hdr) +{ + int i; + + for (i = 0; i < 3; i++) + pfc->ref_idx[i] = hdr->refs[i]; +} + +static int vdec_vp9_slice_setup_pfc( + struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_pfc *pfc) +{ + struct v4l2_ctrl_vp9_frame_decode_params *hdr; + struct vdec_vp9_slice_uncompressed_header *uh; + struct v4l2_ctrl *hdr_ctrl; + struct vdec_vp9_slice_vsi *vsi; + int ret; + + /* frame header */ + hdr_ctrl = v4l2_ctrl_find(&instance->ctx->ctrl_hdl, + V4L2_CID_MPEG_VIDEO_VP9_FRAME_DECODE_PARAMS); + if (!hdr_ctrl || !hdr_ctrl->p_cur.p) + return -EINVAL; + hdr = hdr_ctrl->p_cur.p; + + vsi = &pfc->vsi; + uh = &vsi->frame.uh; + + /* setup vsi information */ + vdec_vp9_slice_setup_hdr(instance, uh, hdr); + vdec_vp9_slice_setup_frame_ctx(instance, uh, hdr); + vdec_vp9_slice_setup_loop_filter(uh, &hdr->lf); + vdec_vp9_slice_setup_quantization(uh, &hdr->quant); + vdec_vp9_slice_setup_segmentation(uh, &hdr->seg); + ret = vdec_vp9_slice_setup_tile(vsi, hdr); + if (ret) + return ret; + vdec_vp9_slice_setup_state(vsi); + + /* core stage needs buffer index to get ref y/c ... */ + vdec_vp9_slice_setup_ref_idx(pfc, hdr); + + pfc->seq = instance->seq; + instance->seq++; + + return 0; +} + +static int vdec_vp9_slice_setup_lat_buffer( + struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_vsi *vsi, + struct mtk_vcodec_mem *bs, + struct vdec_lat_buf *lat_buf) +{ + int i; + + vsi->bs.buf.dma_addr = bs->dma_addr; + vsi->bs.buf.size = bs->size; + vsi->bs.frame.dma_addr = bs->dma_addr; + vsi->bs.frame.size = bs->size; + + for (i = 0; i < 2; i++) { + vsi->mv[i].dma_addr = instance->mv[i].dma_addr; + vsi->mv[i].size = instance->mv[i].size; + } + for (i = 0; i < 2; i++) { + vsi->seg[i].dma_addr = instance->seg[i].dma_addr; + vsi->seg[i].size = instance->seg[i].size; + } + vsi->tile.dma_addr = instance->tile.dma_addr; + vsi->tile.size = instance->tile.size; + vsi->prob.dma_addr = instance->prob.dma_addr; + vsi->prob.size = instance->prob.size; + vsi->counts.dma_addr = instance->counts.dma_addr; + vsi->counts.size = instance->counts.size; + + vsi->ube.dma_addr = lat_buf->ctx->msg_queue.wdma_addr.dma_addr; + vsi->ube.size = lat_buf->ctx->msg_queue.wdma_addr.size; + vsi->trans.dma_addr = lat_buf->ctx->msg_queue.wdma_wptr_addr; + /* used to store trans end */ + vsi->trans.dma_addr_end = lat_buf->ctx->msg_queue.wdma_rptr_addr; + vsi->err_map.dma_addr = lat_buf->wdma_err_addr.dma_addr; + vsi->err_map.size = lat_buf->wdma_err_addr.size; + + vsi->row_info.buf = 0; + vsi->row_info.size = 0; + + return 0; +} + +static int vdec_vp9_slice_setup_prob_buffer( + struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_vsi *vsi) +{ + struct vdec_vp9_slice_frame_ctx *frame_ctx; + struct vdec_vp9_slice_uncompressed_header *uh; + + uh = &vsi->frame.uh; + + mtk_vcodec_debug(instance, "ctx dirty %u idx %d\n", + instance->dirty[uh->frame_context_idx], uh->frame_context_idx); + + if (instance->dirty[uh->frame_context_idx]) + frame_ctx = &instance->frame_ctx[uh->frame_context_idx]; + else + frame_ctx = vdec_vp9_slice_default_frame_ctx; + memcpy(instance->prob.va, frame_ctx, sizeof(*frame_ctx)); + + return 0; +} + +static void vdec_vp9_slice_setup_seg_buffer( + struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_vsi *vsi, + struct mtk_vcodec_mem *buf) +{ + struct vdec_vp9_slice_uncompressed_header *uh; + + /* reset segment buffer */ + uh = &vsi->frame.uh; + if (uh->frame_type == 0 || + uh->intra_only || + uh->error_resilient_mode || + uh->frame_width != instance->width || + uh->frame_height != instance->height) { + mtk_vcodec_debug(instance, "reset seg\n"); + memset(buf->va, 0, buf->size); + } +} + +/* + * parse tiles according to `6.4 Decode tiles syntax` + * in "vp9-bitstream-specification" + * + * frame contains uncompress header, compressed header and several tiles. + * this function parses tiles' position and size, stores them to tile buffer + * for decoding. + */ +static int vdec_vp9_slice_setup_tile_buffer( + struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_vsi * vsi, + struct mtk_vcodec_mem *bs) +{ + struct vdec_vp9_slice_uncompressed_header *uh; + unsigned int rows_log2; + unsigned int cols_log2; + unsigned int rows; + unsigned int cols; + unsigned int mi_row; + unsigned int mi_col; + unsigned int offset; + unsigned int pa; + unsigned int size; + struct vdec_vp9_slice_tiles *tiles; + unsigned char *pos; + unsigned char *end; + unsigned char *va; + unsigned int *tb; + int i; + int j; + + uh = &vsi->frame.uh; + rows_log2 = uh->tile_rows_log2; + cols_log2 = uh->tile_cols_log2; + rows = 1 << rows_log2; + cols = 1 << cols_log2; + + if (rows > 4 || cols > 64) { + mtk_vcodec_err(instance, "tile_rows %u tile_cols %u\n", + rows, cols); + return -EINVAL; + } + + offset = uh->uncompressed_header_size + + uh->header_size_in_bytes; + if (bs->size <= offset) { + mtk_vcodec_err(instance, "bs size %zu tile offset %u\n", + bs->size, offset); + return -EINVAL; + } + + tiles = &vsi->frame.tiles; + /* setup tile buffer */ + + va = (unsigned char *)bs->va; + pos = va + offset; + end = va + bs->size; + /* truncated */ + pa = (unsigned int)bs->dma_addr + offset; + tb = instance->tile.va; + for (i = 0; i < rows; i++) { + for (j = 0; j < cols; j++) { + if (i == rows - 1 && + j == cols - 1) { + size = (unsigned int)(end - pos); + } else { + if (end - pos < 4) { + mtk_vcodec_err(instance, + "tile %px %px\n", end, pos); + return -EINVAL; + } + size = (pos[0] << 24) | (pos[1] << 16) | + (pos[2] << 8) | pos[3]; + pos += 4; + pa += 4; + offset += 4; + if (end - pos < size) { + mtk_vcodec_err(instance, + "tile %px %px %u\n", + end, pos, size); + return -EINVAL; + } + } + tiles->size[i][j] = size; + if (tiles->mi_rows[i]) { + *tb++ = (size << 3) + ((offset << 3) & 0x7f); + *tb++ = pa &~0xf; + *tb++ = (pa << 3) & 0x7f; + mi_row = (tiles->mi_rows[i] - 1) & 0x1ff; + mi_col = (tiles->mi_cols[j] - 1) & 0x3f; + *tb++ = (mi_row << 6) + mi_col; + } + pos += size; + pa += size; + offset += size; + } + } + + return 0; +} + +static int vdec_vp9_slice_setup_lat( + struct vdec_vp9_slice_instance *instance, + struct mtk_vcodec_mem *bs, + struct vdec_lat_buf *lat_buf, + struct vdec_vp9_slice_pfc *pfc) +{ + struct vdec_vp9_slice_vsi *vsi = &pfc->vsi; + int ret; + + ret = vdec_vp9_slice_setup_lat_from_src_buf(instance, lat_buf); + if (ret) + goto err; + + ret = vdec_vp9_slice_setup_pfc(instance, pfc); + if (ret) + goto err; + + ret = vdec_vp9_slice_alloc_working_buffer(instance, vsi); + if (ret) + goto err; + + ret = vdec_vp9_slice_setup_lat_buffer(instance, vsi, bs, lat_buf); + if (ret) + goto err; + + vdec_vp9_slice_setup_seg_buffer(instance, vsi, &instance->seg[0]); + + /* setup prob/tile buffers for LAT */ + + ret = vdec_vp9_slice_setup_prob_buffer(instance, vsi); + if (ret) + goto err; + + ret = vdec_vp9_slice_setup_tile_buffer(instance, vsi, bs); + if (ret) + goto err; + + return 0; + +err: + return ret; +} + +/* implement merge prob process defined in 8.4.1 */ +static unsigned char vdec_vp9_slice_merge_prob(unsigned char pre, + unsigned int ct0, + unsigned int ct1, + unsigned int cs, + unsigned int uf) +{ + unsigned int den; + unsigned int prob; + unsigned int count; + unsigned int factor; + + /* + * The variable den representing the total times + * this boolean has been decoded is set equal to ct0 + ct1. + */ + den = ct0 + ct1; + if (!den) + return pre; /* => count = 0 => factor = 0 */ + /* + * The variable prob estimating the probability that + * the boolean is decoded as a 0 is set equal to + * (den == 0) ? 128 : Clip3(1, 255, (ct0 * 256 + (den >> 1)) / den). + */ + prob = ((ct0 << 8) + (den >> 1)) / den; + prob = prob < 1 ? 1 : (prob > 255 ? 255 : prob); + /* The variable count is set equal to Min(ct0 + ct1, countSat) */ + count = den < cs ? den : cs; + /* + * The variable factor is set equal to + * maxUpdateFactor * count / countSat. + */ + factor = uf * count / cs; + /* + * The return variable outProb is set equal to + * Round2(preProb * (256 - factor) + prob * factor, 8). + */ + return pre + (((prob - pre) * factor + 128) >> 8); +} + +static inline unsigned char vdec_vp9_slice_adapt_prob( + unsigned char pre, + unsigned int ct0, + unsigned int ct1) +{ + return vdec_vp9_slice_merge_prob(pre, ct0, ct1, 20, 128); +} + +/* implement merge probs process defined in 8.4.2 */ +static unsigned int vdec_vp9_slice_merge_probs( + const signed char *tree, + int location, + unsigned char *pre_probs, + unsigned int *counts, + unsigned char *probs, + unsigned int cs, + unsigned int uf) +{ + int left = tree[location]; + int right = tree[location + 1]; + unsigned int left_count; + unsigned int right_count; + + if (left <= 0) + left_count = counts[-left]; + else + left_count = vdec_vp9_slice_merge_probs(tree, left, + pre_probs, counts, probs, cs, uf); + + if (right <= 0) + right_count = counts[-right]; + else + right_count = vdec_vp9_slice_merge_probs(tree, right, + pre_probs, counts, probs, cs, uf); + + /* merge left and right */ + probs[location >> 1] = + vdec_vp9_slice_merge_prob(pre_probs[location >> 1], + left_count, right_count, cs, uf); + return left_count + right_count; +} + +static inline void vdec_vp9_slice_adapt_probs( + const signed char *tree, + unsigned char *pre_probs, + unsigned int *counts, + unsigned char *probs) +{ + vdec_vp9_slice_merge_probs(tree, 0, pre_probs, counts, probs, 20, 128); +} + +/* 8.4 Probability adaptation process */ +static void vdec_vp9_slice_adapt_table( + struct vdec_vp9_slice_vsi *vsi, + struct vdec_vp9_slice_frame_ctx *ctx, + struct vdec_vp9_slice_frame_ctx *pre_ctx, + struct vdec_vp9_slice_frame_counts *counts) +{ + unsigned char *pp; + unsigned char *p; + unsigned int *c; + unsigned int *e; + unsigned int uf; + int t, i, j, k, l; + + uf = 128; + if (!vsi->frame.uh.frame_type || vsi->frame.uh.intra_only || + vsi->frame.uh.last_frame_type) + uf = 112; + + p = (unsigned char *)&ctx->coef_probs; + pp = (unsigned char *)&pre_ctx->coef_probs; + c = (unsigned int *)&counts->coef_probs; + e = (unsigned int *)&counts->eob_branch; + + /* 8.4.3 Coefficient probability adaption process */ + FOR_EACH_COEF_PROBS_BAND(t, i, j, k) { + for (l = 0; l < (k == 0 ? 3 : 6); l++) { + p[0] = vdec_vp9_slice_merge_prob(pp[0], + c[3], e[0] - c[3], 24, uf); + p[1] = vdec_vp9_slice_merge_prob(pp[1], + c[0], c[1] + c[2], 24, uf); + p[2] = vdec_vp9_slice_merge_prob(pp[2], + c[1], c[2], 24, uf); + p += 3; + pp += 3; + c += 4; + e++; + } + if (k == 0) { + /* 3*3 unused values and 2 bytes padding */ + p += 11; + pp += 11; + e++; + } else { + /* extra 2 bytes could make 4 bytes align (3*6+2) */ + p += 2; + pp += 2; + /* 5*6=30, extra 2 int */ + if (k == 5) + e += 2; + } + } + + if (!vsi->frame.uh.frame_type || vsi->frame.uh.intra_only) + return; + + /* 8.4.4 Non coefficient probability adaption process */ + + for (i = 0; i < 4; i++) { + ctx->intra_inter_prob[i] = vdec_vp9_slice_adapt_prob( + pre_ctx->intra_inter_prob[i], + counts->intra_inter[i][0], + counts->intra_inter[i][1]); + } + + for (i = 0; i < 5; i++) { + ctx->comp_inter_prob[i] = vdec_vp9_slice_adapt_prob( + pre_ctx->comp_inter_prob[i], + counts->comp_inter[i][0], + counts->comp_inter[i][1]); + } + + for (i = 0; i < 5; i++) { + ctx->comp_ref_prob[i] = vdec_vp9_slice_adapt_prob( + pre_ctx->comp_ref_prob[i], + counts->comp_ref[i][0], + counts->comp_ref[i][1]); + } + + for (i = 0; i < 5; i++) { + for (j = 0; j < 2; j++) { + ctx->single_ref_prob[i][j] = + vdec_vp9_slice_adapt_prob( + pre_ctx->single_ref_prob[i][j], + counts->single_ref[i][j][0], + counts->single_ref[i][j][1]); + } + } + + for (i = 0; i < 7; i++) { + vdec_vp9_slice_adapt_probs(vdec_vp9_slice_inter_mode_tree, + &pre_ctx->inter_mode_probs[i][0], + &counts->inter_mode[i][0], + &ctx->inter_mode_probs[i][0]); + } + + for (i = 0; i < 4; i++) { + vdec_vp9_slice_adapt_probs(vdec_vp9_slice_intra_mode_tree, + &pre_ctx->y_mode_prob[i][0], + &counts->y_mode[i][0], + &ctx->y_mode_prob[i][0]); + } + + for (i = 0; i < 10; i++) { + vdec_vp9_slice_adapt_probs(vdec_vp9_slice_intra_mode_tree, + &pre_ctx->uv_mode_prob[i][0], + &counts->uv_mode[i][0], + &ctx->uv_mode_prob[i][0]); + } + + for (i = 0; i < 16; i++) { + vdec_vp9_slice_adapt_probs(vdec_vp9_slice_partition_tree, + &pre_ctx->partition_prob[i][0], + &counts->partition[i][0], + &ctx->partition_prob[i][0]); + } + + if (vsi->frame.uh.interpolation_filter == 4) { + for (i = 0; i < 4; i++) { + vdec_vp9_slice_adapt_probs( + vdec_vp9_slice_switchable_interp_tree, + &pre_ctx->switch_interp_prob[i][0], + &counts->switchable_interp[i][0], + &ctx->switch_interp_prob[i][0]); + } + } + + if (vsi->frame.ch.tx_mode == 4) { + for (i = 0; i < 2; i++) { + ctx->tx_p8x8[i][0] = vdec_vp9_slice_adapt_prob( + pre_ctx->tx_p8x8[i][0], + counts->tx_p8x8[i][0], + counts->tx_p8x8[i][1]); + ctx->tx_p16x16[i][0] = vdec_vp9_slice_adapt_prob( + pre_ctx->tx_p16x16[i][0], + counts->tx_p16x16[i][0], + counts->tx_p16x16[i][1] + + counts->tx_p16x16[i][2]); + ctx->tx_p16x16[i][1] = vdec_vp9_slice_adapt_prob( + pre_ctx->tx_p16x16[i][1], + counts->tx_p16x16[i][1], + counts->tx_p16x16[i][2]); + ctx->tx_p32x32[i][0] = vdec_vp9_slice_adapt_prob( + pre_ctx->tx_p32x32[i][0], + counts->tx_p32x32[i][0], + counts->tx_p32x32[i][1] + + counts->tx_p32x32[i][2] + + counts->tx_p32x32[i][3]); + ctx->tx_p32x32[i][1] = vdec_vp9_slice_adapt_prob( + pre_ctx->tx_p32x32[i][1], + counts->tx_p32x32[i][1], + counts->tx_p32x32[i][2] + + counts->tx_p32x32[i][3]); + ctx->tx_p32x32[i][2] = vdec_vp9_slice_adapt_prob( + pre_ctx->tx_p32x32[i][2], + counts->tx_p32x32[i][2], + counts->tx_p32x32[i][3]); + } + } + + for (i = 0; i < 3; i++) { + ctx->skip_probs[i] = vdec_vp9_slice_adapt_prob( + pre_ctx->skip_probs[i], + counts->skip[i][0], + counts->skip[i][1]); + } + + vdec_vp9_slice_adapt_probs(vdec_vp9_slice_mv_joint_tree, + &pre_ctx->joint[0], + &counts->joint[0], + &ctx->joint[0]); + + for (i = 0; i < 2; i++) { + ctx->sign_classes[i].sign = vdec_vp9_slice_adapt_prob( + pre_ctx->sign_classes[i].sign, + counts->mvcomp[i].sign[0], + counts->mvcomp[i].sign[1]); + vdec_vp9_slice_adapt_probs(vdec_vp9_slice_mv_class_tree, + &pre_ctx->sign_classes[i].classes[0], + &counts->mvcomp[i].classes[0], + &ctx->sign_classes[i].classes[0]); + + vdec_vp9_slice_adapt_probs(vdec_vp9_slice_mv_class0_tree, + pre_ctx->class0_bits[i].class0, + counts->mvcomp[i].class0, + ctx->class0_bits[i].class0); + for (j = 0; j < 10; j++) { + ctx->class0_bits[i].bits[j] = + vdec_vp9_slice_adapt_prob( + pre_ctx->class0_bits[i].bits[j], + counts->mvcomp[i].bits[j][0], + counts->mvcomp[i].bits[j][1]); + } + + for (j = 0; j < 2; ++j) { + vdec_vp9_slice_adapt_probs(vdec_vp9_slice_mv_fp_tree, + pre_ctx->class0_fp_hp[i].class0_fp[j], + counts->mvcomp[i].class0_fp[j], + ctx->class0_fp_hp[i].class0_fp[j]); + } + vdec_vp9_slice_adapt_probs(vdec_vp9_slice_mv_fp_tree, + pre_ctx->class0_fp_hp[i].fp, + counts->mvcomp[i].fp, + ctx->class0_fp_hp[i].fp); + if (vsi->frame.uh.allow_high_precision_mv) { + ctx->class0_fp_hp[i].class0_hp = + vdec_vp9_slice_adapt_prob( + pre_ctx->class0_fp_hp[i].class0_hp, + counts->mvcomp[i].class0_hp[0], + counts->mvcomp[i].class0_hp[1]); + ctx->class0_fp_hp[i].hp = + vdec_vp9_slice_adapt_prob( + pre_ctx->class0_fp_hp[i].hp, + counts->mvcomp[i].hp[0], + counts->mvcomp[i].hp[1]); + } + } +} + +static int vdec_vp9_slice_update_prob( + struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_vsi *vsi) +{ + struct vdec_vp9_slice_frame_ctx *pre_frame_ctx; + struct vdec_vp9_slice_frame_ctx *frame_ctx; + struct vdec_vp9_slice_frame_counts *counts; + struct vdec_vp9_slice_uncompressed_header *uh; + + uh = &vsi->frame.uh; + pre_frame_ctx = &instance->frame_ctx[uh->frame_context_idx]; + frame_ctx = (struct vdec_vp9_slice_frame_ctx *)instance->prob.va; + counts = (struct vdec_vp9_slice_frame_counts *)instance->counts.va; + + if (!uh->refresh_frame_context) + return 0; + + if (!uh->frame_parallel_decoding_mode) { + /* uh->error_resilient_mode must be 0 */ + vdec_vp9_slice_adapt_table(vsi, + frame_ctx, + /* use default frame ctx? */ + instance->dirty[uh->frame_context_idx] ? + pre_frame_ctx : + vdec_vp9_slice_default_frame_ctx, + counts); + } + + memcpy(pre_frame_ctx, frame_ctx, sizeof(*frame_ctx)); + instance->dirty[uh->frame_context_idx] = 1; + + return 0; +} + +static int vdec_vp9_slice_update_lat( + struct vdec_vp9_slice_instance *instance, + struct vdec_lat_buf *lat_buf, + struct vdec_vp9_slice_pfc *pfc) +{ + struct vdec_vp9_slice_vsi *vsi; + + vsi = &pfc->vsi; + memcpy(&pfc->state[0], &vsi->state, sizeof(vsi->state)); + + mtk_vcodec_debug(instance, + "Frame %u LAT CRC 0x%08x\n", pfc->seq, vsi->state.crc[0]); + + /* buffer full, need to re-decode */ + if (vsi->state.full) { + /* buffer not enough */ + if (vsi->trans.dma_addr_end - vsi->trans.dma_addr == + vsi->ube.size) + return -ENOMEM; + return -EAGAIN; + } + + vdec_vp9_slice_update_prob(instance, vsi); + + instance->width = vsi->frame.uh.frame_width; + instance->height = vsi->frame.uh.frame_height; + instance->frame_type = vsi->frame.uh.frame_type; + instance->show_frame = vsi->frame.uh.show_frame; + + return 0; +} + +static int vdec_vp9_slice_setup_core_to_dst_buf( + struct vdec_vp9_slice_instance *instance, + struct vdec_lat_buf *lat_buf) +{ + struct vb2_v4l2_buffer *src; + struct vb2_v4l2_buffer *dst; + + dst = v4l2_m2m_next_dst_buf(instance->ctx->m2m_ctx); + if (!dst) + return -EINVAL; + + src = &lat_buf->ts_info; + dst->vb2_buf.timestamp = src->vb2_buf.timestamp; + dst->timecode = src->timecode; + dst->field = src->field; + dst->flags = src->flags; + dst->vb2_buf.copied_timestamp = src->vb2_buf.copied_timestamp; + return 0; +} + +static int vdec_vp9_slice_setup_core_buffer( + struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_pfc *pfc, + struct vdec_vp9_slice_vsi *vsi, + struct vdec_fb *fb, + struct vdec_lat_buf *lat_buf) +{ + struct vb2_buffer *vb; + struct vb2_queue *vq; + struct vdec_vp9_slice_reference *ref; + int plane; + int size; + int idx; + int w; + int h; + int i; + + plane = instance->ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes; + w = vsi->frame.uh.frame_width; + h = vsi->frame.uh.frame_height; + size = ALIGN(w, 64) * ALIGN(h, 64); + + /* frame buffer */ + vsi->fb.y.dma_addr = fb->base_y.dma_addr; + if (plane == 1) + vsi->fb.c.dma_addr = fb->base_y.dma_addr + size; + else + vsi->fb.c.dma_addr = fb->base_c.dma_addr; + + /* reference buffers */ + vq = v4l2_m2m_get_vq(instance->ctx->m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (!vq) + return -EINVAL; + + /* get current output buffer */ + vb = &v4l2_m2m_next_dst_buf(instance->ctx->m2m_ctx)->vb2_buf; + if (!vb) + return -EINVAL; + + /* update internal buffer's width/height */ + for (i = 0; i < vq->num_buffers; i++) { + if (vb == vq->bufs[i]) { + instance->dpb[i].width = w; + instance->dpb[i].height = h; + break; + } + } + + /* + * get buffer's width/height from instance + * get buffer address from vb2buf + */ + for (i = 0; i < 3; i++) { + ref = &vsi->frame.ref[i]; + idx = vb2_find_timestamp(vq, pfc->ref_idx[i], 0); + if (idx < 0) { + ref->frame_width = w; + ref->frame_height = h; + memset(&vsi->ref[i], 0, sizeof(vsi->ref[i])); + } else { + ref->frame_width = instance->dpb[idx].width; + ref->frame_height = instance->dpb[idx].height; + vb = vq->bufs[idx]; + vsi->ref[i].y.dma_addr = + vb2_dma_contig_plane_dma_addr(vb, 0); + if (plane == 1) + vsi->ref[i].c.dma_addr = + vsi->ref[i].y.dma_addr + size; + else + vsi->ref[i].c.dma_addr = + vb2_dma_contig_plane_dma_addr(vb, 1); + } + } + + return 0; +} + +static int vdec_vp9_slice_setup_core( + struct vdec_vp9_slice_instance *instance, + struct vdec_fb *fb, + struct vdec_lat_buf *lat_buf, + struct vdec_vp9_slice_pfc *pfc) +{ + struct vdec_vp9_slice_vsi *vsi = &pfc->vsi; + int ret; + + vdec_vp9_slice_setup_state(vsi); + + ret = vdec_vp9_slice_setup_core_to_dst_buf(instance, lat_buf); + if (ret) + goto err; + + ret = vdec_vp9_slice_setup_core_buffer(instance, pfc, vsi, + fb, lat_buf); + if (ret) + goto err; + + vdec_vp9_slice_setup_seg_buffer(instance, vsi, &instance->seg[1]); + + return 0; + +err: + return ret; +} + +static int vdec_vp9_slice_update_core( + struct vdec_vp9_slice_instance *instance, + struct vdec_lat_buf *lat_buf, + struct vdec_vp9_slice_pfc *pfc) +{ + struct vdec_vp9_slice_vsi *vsi; + + vsi = &pfc->vsi; + memcpy(&pfc->state[1], &vsi->state, sizeof(vsi->state)); + + mtk_vcodec_debug(instance, "Frame %u Y_CRC %08x %08x %08x %08x\n", + pfc->seq, + vsi->state.crc[0], vsi->state.crc[1], + vsi->state.crc[2], vsi->state.crc[3]); + mtk_vcodec_debug(instance, "Frame %u C_CRC %08x %08x %08x %08x\n", + pfc->seq, + vsi->state.crc[4], vsi->state.crc[5], + vsi->state.crc[6], vsi->state.crc[7]); + + return 0; +} + +static int vdec_vp9_slice_init(struct mtk_vcodec_ctx *ctx) +{ + struct vdec_vp9_slice_instance *instance; + struct vdec_vp9_slice_init_vsi *vsi; + int ret; + + instance = kzalloc(sizeof(*instance), GFP_KERNEL); + if (!instance) + return -ENOMEM; + + instance->ctx = ctx; + instance->vpu.id = SCP_IPI_VDEC_LAT; + instance->vpu.core_id = SCP_IPI_VDEC_CORE; + instance->vpu.ctx = ctx; + instance->vpu.codec_type = ctx->current_codec; + + ret = vpu_dec_init(&instance->vpu); + if (ret) { + mtk_vcodec_err(instance, "failed to init vpu dec, ret %d\n", + ret); + goto error_vpu_init; + } + + /* init vsi and global flags */ + + vsi = instance->vpu.vsi; + if (!vsi) { + mtk_vcodec_err(instance, "failed to get VP9 vsi\n"); + ret = -EINVAL; + goto error_vsi; + } + instance->init_vsi = vsi; + instance->core_vsi = mtk_vcodec_fw_map_dm_addr(ctx->dev->fw_handler, + (u32)vsi->core_vsi); + if (!instance->core_vsi) { + mtk_vcodec_err(instance, "failed to get VP9 core vsi\n"); + ret = -EINVAL; + goto error_vsi; + } + + instance->irq = 1; + + mtk_vcodec_debug(instance, "vsi 0x%px core_vsi 0x%llx 0x%px\n", + vsi, vsi->core_vsi, instance->core_vsi); + + ret = vdec_vp9_slice_init_default_frame_ctx(instance); + if (ret) + goto error_default_frame_ctx; + + ctx->drv_handle = instance; + + return 0; + +error_default_frame_ctx: +error_vsi: + vpu_dec_deinit(&instance->vpu); +error_vpu_init: + kfree(instance); + return ret; +} + +static void vdec_vp9_slice_deinit(void *h_vdec) +{ + struct vdec_vp9_slice_instance *instance = h_vdec; + + if (!instance) + return; + + mtk_vcodec_debug(instance, "h_vdec 0x%px\n", h_vdec); + + vpu_dec_deinit(&instance->vpu); + vdec_vp9_slice_free_working_buffer(instance); + vdec_msg_queue_deinit(&instance->ctx->msg_queue, instance->ctx); + kfree(instance); +} + +static int vdec_vp9_slice_flush(void *h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg) +{ + struct vdec_vp9_slice_instance *instance = h_vdec; + + mtk_vcodec_debug(instance, "flush ...\n"); + + vdec_msg_queue_wait_lat_buf_full(&instance->ctx->msg_queue); + return vpu_dec_reset(&instance->vpu); +} + +static void vdec_vp9_slice_get_pic_info( + struct vdec_vp9_slice_instance *instance) +{ + struct mtk_vcodec_ctx *ctx = instance->ctx; + unsigned int data[3]; + + mtk_vcodec_debug(instance, "w %u h %u\n", + ctx->picinfo.pic_w, ctx->picinfo.pic_h); + + data[0] = ctx->picinfo.pic_w; + data[1] = ctx->picinfo.pic_h; + data[2] = ctx->capture_fourcc; + vpu_dec_get_param(&instance->vpu, data, 3, GET_PARAM_PIC_INFO); + + ctx->picinfo.buf_w = ALIGN(ctx->picinfo.pic_w, 64); + ctx->picinfo.buf_h = ALIGN(ctx->picinfo.pic_h, 64); + ctx->picinfo.fb_sz[0] = instance->vpu.fb_sz[0]; + ctx->picinfo.fb_sz[1] = instance->vpu.fb_sz[1]; +} + +static void vdec_vp9_slice_get_dpb_size( + struct vdec_vp9_slice_instance *instance, + unsigned int *dpb_sz) +{ + /* refer VP9 specification */ + *dpb_sz = 9; +} + +static void vdec_vp9_slice_get_crop_info( + struct vdec_vp9_slice_instance *instance, + struct v4l2_rect *cr) +{ + struct mtk_vcodec_ctx *ctx = instance->ctx; + + cr->left = 0; + cr->top = 0; + cr->width = ctx->picinfo.pic_w; + cr->height = ctx->picinfo.pic_h; + + mtk_vcodec_debug(instance, "l=%d, t=%d, w=%d, h=%d\n", + cr->left, cr->top, cr->width, cr->height); +} + +static int vdec_vp9_slice_get_param(void *h_vdec, + enum vdec_get_param_type type, void *out) +{ + struct vdec_vp9_slice_instance *instance = h_vdec; + + switch (type) { + case GET_PARAM_PIC_INFO: + vdec_vp9_slice_get_pic_info(instance); + break; + case GET_PARAM_DPB_SIZE: + vdec_vp9_slice_get_dpb_size(instance, out); + break; + case GET_PARAM_CROP_INFO: + vdec_vp9_slice_get_crop_info(instance, out); + break; + default: + mtk_vcodec_err(instance, "invalid get parameter type=%d\n", + type); + return -EINVAL; + } + + return 0; +} + +static int vdec_vp9_slice_lat_decode(void *h_vdec, + struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, + bool *res_chg) +{ + struct vdec_vp9_slice_instance *instance = h_vdec; + struct vdec_lat_buf *lat_buf; + struct vdec_vp9_slice_pfc *pfc; + struct vdec_vp9_slice_vsi *vsi; + struct mtk_vcodec_ctx *ctx; + int ret; + + if (!instance || !instance->ctx) + return -EINVAL; + ctx = instance->ctx; + + /* init msgQ for the first time */ + if (vdec_msg_queue_init(&ctx->msg_queue, ctx, + vdec_vp9_slice_core_decode, sizeof(*pfc))) { + mtk_vcodec_err(instance, + "Failed to init VP9 msg queue\n"); + return -ENOMEM; + } + + /* bs NULL means flush decoder */ + if (!bs) + return vdec_vp9_slice_flush(h_vdec, bs, fb, res_chg); + + lat_buf = vdec_msg_queue_dqbuf(&instance->ctx->msg_queue.lat_ctx); + if (!lat_buf) { + mtk_vcodec_err(instance, "Failed to get VP9 lat buf\n"); + return -EBUSY; + } + pfc = (struct vdec_vp9_slice_pfc *)lat_buf->private_data; + if (!pfc) + return -EINVAL; + vsi = &pfc->vsi; + + ret = vdec_vp9_slice_setup_lat(instance, bs, lat_buf, pfc); + if (ret) { + mtk_vcodec_err(instance, + "Failed to setup VP9 lat ret %d\n", ret); + return ret; + } + vdec_vp9_slice_vsi_to_remote(vsi, instance->vsi); + + ret = vpu_dec_start(&instance->vpu, 0, 0); + if (ret) { + mtk_vcodec_err(instance, + "Failed to dec VP9 ret %d\n", ret); + return ret; + } + + if (instance->irq) { + ret = mtk_vcodec_wait_for_done_ctx(ctx, + MTK_INST_IRQ_RECEIVED, + WAIT_INTR_TIMEOUT_MS, MTK_VDEC_LAT0); + /* update remote vsi if decode timeout */ + if (ret) { + mtk_vcodec_err(instance, + "VP9 decode timeout %d\n", ret); + writel(1, &instance->vsi->state.timeout); + } + vpu_dec_end(&instance->vpu); + } + + vdec_vp9_slice_vsi_from_remote(vsi, instance->vsi, 0); + ret = vdec_vp9_slice_update_lat(instance, lat_buf, pfc); + + /* LAT trans full, no more UBE or decode timeout */ + if (ret) { + mtk_vcodec_err(instance, "VP9 decode error: %d\n", ret); + return ret; + } + + mtk_vcodec_debug(instance, "lat dma 1 0x%llx 0x%llx\n", + pfc->vsi.trans.dma_addr, pfc->vsi.trans.dma_addr_end); + + vdec_msg_queue_update_ube_wptr(&ctx->msg_queue, + vsi->trans.dma_addr_end + ctx->msg_queue.wdma_addr.dma_addr); + vdec_msg_queue_qbuf(&ctx->dev->msg_queue_core_ctx, lat_buf); + + return 0; +} + +static int vdec_vp9_slice_core_decode( + struct vdec_lat_buf *lat_buf) +{ + struct vdec_vp9_slice_instance *instance; + struct vdec_vp9_slice_pfc *pfc; + struct mtk_vcodec_ctx *ctx = NULL; + struct vdec_fb *fb = NULL; + int ret = -EINVAL; + + if (!lat_buf) + goto err; + + pfc = lat_buf->private_data; + ctx = lat_buf->ctx; + if (!pfc || !ctx) + goto err; + + instance = ctx->drv_handle; + if (!instance) + goto err; + + fb = ctx->dev->vdec_pdata->get_cap_buffer(ctx); + if (!fb) { + ret = -EBUSY; + goto err; + } + + ret = vdec_vp9_slice_setup_core(instance, fb, lat_buf, pfc); + if (ret) { + mtk_vcodec_err(instance, "vdec_vp9_slice_setup_core\n"); + goto err; + } + vdec_vp9_slice_vsi_to_remote(&pfc->vsi, instance->core_vsi); + + ret = vpu_dec_core(&instance->vpu); + if (ret) { + mtk_vcodec_err(instance, "vpu_dec_core\n"); + goto err; + } + + if (instance->irq) { + ret = mtk_vcodec_wait_for_done_ctx(ctx, + MTK_INST_IRQ_RECEIVED, + WAIT_INTR_TIMEOUT_MS, MTK_VDEC_CORE); + /* update remote vsi if decode timeout */ + if (ret) { + mtk_vcodec_err(instance, "VP9 core timeout\n"); + writel(1, &instance->core_vsi->state.timeout); + } + vpu_dec_core_end(&instance->vpu); + } + + vdec_vp9_slice_vsi_from_remote(&pfc->vsi, instance->core_vsi, 1); + ret = vdec_vp9_slice_update_core(instance, lat_buf, pfc); + if (ret) { + mtk_vcodec_err(instance, "vdec_vp9_slice_update_core\n"); + goto err; + } + + pfc->vsi.trans.dma_addr_end += ctx->msg_queue.wdma_addr.dma_addr; + mtk_vcodec_debug(instance, "core dma_addr_end 0x%llx\n", + pfc->vsi.trans.dma_addr_end); + vdec_msg_queue_update_ube_rptr(&ctx->msg_queue, + pfc->vsi.trans.dma_addr_end); + ctx->dev->vdec_pdata->cap_to_disp(ctx, fb, 0); + + return 0; + +err: + if (ctx) { + /* always update read pointer */ + vdec_msg_queue_update_ube_rptr(&ctx->msg_queue, + pfc->vsi.trans.dma_addr_end); + + if (fb) + ctx->dev->vdec_pdata->cap_to_disp(ctx, fb, 1); + } + return ret; +} + +const struct vdec_common_if vdec_vp9_slice_lat_if = { + .init = vdec_vp9_slice_init, + .decode = vdec_vp9_slice_lat_decode, + .get_param = vdec_vp9_slice_get_param, + .deinit = vdec_vp9_slice_deinit, +}; diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c index 9db9a57da2c1..2d3a45781359 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c @@ -44,6 +44,10 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) ctx->dec_if = &vdec_vp9_if; ctx->hw_id = MTK_VDEC_CORE; break; + case V4L2_PIX_FMT_VP9_FRAME: + ctx->dec_if = &vdec_vp9_slice_lat_if; + ctx->hw_id = MTK_VDEC_LAT0; + break; default: return -EINVAL; } diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h index e3adf8f36342..e383a04db7b8 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h @@ -60,6 +60,7 @@ extern const struct vdec_common_if vdec_h264_slice_lat_if; extern const struct vdec_common_if vdec_vp8_if; extern const struct vdec_common_if vdec_vp8_slice_if; extern const struct vdec_common_if vdec_vp9_if; +extern const struct vdec_common_if vdec_vp9_slice_lat_if; /** * vdec_if_init() - initialize decode driver