From patchwork Tue Jun 30 06:27:03 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Courbot X-Patchwork-Id: 11633253 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 05A9592A for ; Tue, 30 Jun 2020 06:27:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A4C1920672 for ; Tue, 30 Jun 2020 06:27:38 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="bzEYisiD" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730225AbgF3G1f (ORCPT ); Tue, 30 Jun 2020 02:27:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35696 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729901AbgF3G1c (ORCPT ); Tue, 30 Jun 2020 02:27:32 -0400 Received: from mail-pg1-x544.google.com (mail-pg1-x544.google.com [IPv6:2607:f8b0:4864:20::544]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2C841C03E979 for ; Mon, 29 Jun 2020 23:27:32 -0700 (PDT) Received: by mail-pg1-x544.google.com with SMTP id d4so9464936pgk.4 for ; Mon, 29 Jun 2020 23:27:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=l2xwjo/lUAFj8r2ZP2eint24TqBTPGdGiXHosamkL7Y=; b=bzEYisiD6KBYIWJvkwaIjOD48XxbNzxtffwK+1bbcOYrixbxf1GWFIzWP8WaKO5BiI l+2y5xu7dl+PUqtzOAo+TUhYTOWhv7h/wIodammA+myRmsNG/xFZtDEmT9OmLvlJ+u23 yTVL/iw9Y4DobiY5kvKtfpJi4SlbmproNoteU= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=l2xwjo/lUAFj8r2ZP2eint24TqBTPGdGiXHosamkL7Y=; b=JGgwsH250kvRG4jjBXi9hBkvlGnQ1w+ybUFyN9/Y/tHn4OIJxFi1xI0Vsh4Az+FbP/ kxi6FhaF6gOv7AcV9r7sjA4bXyyLjTwoO76zWNFgBQ+bBRqfTU3j2HPxCW0F5GDBVVE2 ULj4ocSaRM2JGorgxB/eAXhhu4KZ64lsU+SJEjulPKbjwP36c/ffVQq/ctirK0vWs6cA 7/gqhw5Xo2VSjcH0mi7StjlxoJuCADZcU174h2JOC46e15SOOoQ2esww+S+whFSd3mgX vvKVB66qygun4IurWRNN6vU04UtKg5yfBUBvvdHEdEdd0C5S02aguvCDRGHb+53IOCSr NV2w== X-Gm-Message-State: AOAM530bzpo1/0uMOk37SQlRP5kO1tqXv/GvVodeiHMq2KJk1xaDH+/1 whE/9mqGkOJf0vOnO9mfIR3bcQ== X-Google-Smtp-Source: ABdhPJxV9WghYn5+cSvdfaJYAmL5SlGemXpvo9a2iPKPaM2qo1NUCY0p3sIJJLmDg7J04LmV6SJFvg== X-Received: by 2002:a63:9353:: with SMTP id w19mr13450073pgm.13.1593498451205; Mon, 29 Jun 2020 23:27:31 -0700 (PDT) Received: from acourbot.tok.corp.google.com ([2401:fa00:8f:203:93d9:de4d:e834:3086]) by smtp.gmail.com with ESMTPSA id d1sm1463366pfq.113.2020.06.29.23.27.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Jun 2020 23:27:30 -0700 (PDT) From: Alexandre Courbot To: Tiffany Lin , Andrew-CT Chen , Rui Wang , Yunfei Dong , Pi-Hsun Shih , Maoguang Meng Cc: linux-media@vger.kernel.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, Alexandre Courbot Subject: [PATCH 1/9] media: mtk-vcodec: vdec: move stateful ops into their own file Date: Tue, 30 Jun 2020 15:27:03 +0900 Message-Id: <20200630062711.4169601-2-acourbot@chromium.org> X-Mailer: git-send-email 2.27.0.212.ge8ba1cc988-goog In-Reply-To: <20200630062711.4169601-1-acourbot@chromium.org> References: <20200630062711.4169601-1-acourbot@chromium.org> MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org From: Yunfei Dong We are planning to add support for stateless decoders to this driver. Part of the driver will be shared between stateful and stateless codecs, but a few ops need to be specialized for both. Extract the stateful part of the driver and move it into its own file, accessible through ops that the common driver parts can call. This patch only moves code around and introduces a set of abstractions ; the behavior of the driver should not be changed in any way. Signed-off-by: Yunfei Dong [acourbot: refactor, cleanup and split] Co-developed-by: Alexandre Courbot Signed-off-by: Alexandre Courbot --- drivers/media/platform/mtk-vcodec/Makefile | 1 + .../platform/mtk-vcodec/mtk_vcodec_dec.c | 697 ++---------------- .../platform/mtk-vcodec/mtk_vcodec_dec.h | 19 +- .../platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 10 +- .../mtk-vcodec/mtk_vcodec_dec_stateful.c | 633 ++++++++++++++++ .../platform/mtk-vcodec/mtk_vcodec_drv.h | 41 ++ 6 files changed, 755 insertions(+), 646 deletions(-) create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c diff --git a/drivers/media/platform/mtk-vcodec/Makefile b/drivers/media/platform/mtk-vcodec/Makefile index b8636119ed0a..a9e189af5ba4 100644 --- a/drivers/media/platform/mtk-vcodec/Makefile +++ b/drivers/media/platform/mtk-vcodec/Makefile @@ -11,6 +11,7 @@ mtk-vcodec-dec-y := vdec/vdec_h264_if.o \ vdec_drv_if.o \ vdec_vpu_if.o \ mtk_vcodec_dec.o \ + mtk_vcodec_dec_stateful.o \ mtk_vcodec_dec_pm.o \ mtk_vcodec_fw.o diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 0f3e710aed4e..7e01ac03887e 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -16,68 +16,17 @@ #include "vdec_drv_if.h" #include "mtk_vcodec_dec_pm.h" -#define OUT_FMT_IDX 0 -#define CAP_FMT_IDX 3 - -#define MTK_VDEC_MIN_W 64U -#define MTK_VDEC_MIN_H 64U #define DFT_CFG_WIDTH MTK_VDEC_MIN_W #define DFT_CFG_HEIGHT MTK_VDEC_MIN_H -static const struct mtk_video_fmt mtk_video_formats[] = { - { - .fourcc = V4L2_PIX_FMT_H264, - .type = MTK_FMT_DEC, - .num_planes = 1, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, - }, - { - .fourcc = V4L2_PIX_FMT_VP8, - .type = MTK_FMT_DEC, - .num_planes = 1, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, - }, - { - .fourcc = V4L2_PIX_FMT_VP9, - .type = MTK_FMT_DEC, - .num_planes = 1, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, - }, - { - .fourcc = V4L2_PIX_FMT_MT21C, - .type = MTK_FMT_FRAME, - .num_planes = 2, - }, -}; - -static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = { - { - .fourcc = V4L2_PIX_FMT_H264, - .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, - MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, - }, - { - .fourcc = V4L2_PIX_FMT_VP8, - .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, - MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, - }, - { - .fourcc = V4L2_PIX_FMT_VP9, - .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, - MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, - }, -}; - -#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_vdec_framesizes) -#define NUM_FORMATS ARRAY_SIZE(mtk_video_formats) - -static const struct mtk_video_fmt *mtk_vdec_find_format(struct v4l2_format *f) +static const struct mtk_video_fmt *mtk_vdec_find_format(struct v4l2_format *f, + const struct mtk_vcodec_dec_pdata *dec_pdata) { const struct mtk_video_fmt *fmt; unsigned int k; - for (k = 0; k < NUM_FORMATS; k++) { - fmt = &mtk_video_formats[k]; + for (k = 0; k < dec_pdata->num_formats; k++) { + fmt = &dec_pdata->vdec_formats[k]; if (fmt->fourcc == f->fmt.pix_mp.pixelformat) return fmt; } @@ -94,394 +43,6 @@ static struct mtk_q_data *mtk_vdec_get_q_data(struct mtk_vcodec_ctx *ctx, return &ctx->q_data[MTK_Q_DATA_DST]; } -/* - * This function tries to clean all display buffers, the buffers will return - * in display order. - * Note the buffers returned from codec driver may still be in driver's - * reference list. - */ -static struct vb2_buffer *get_display_buffer(struct mtk_vcodec_ctx *ctx) -{ - struct vdec_fb *disp_frame_buffer = NULL; - struct mtk_video_dec_buf *dstbuf; - struct vb2_v4l2_buffer *vb; - - mtk_v4l2_debug(3, "[%d]", ctx->id); - if (vdec_if_get_param(ctx, - GET_PARAM_DISP_FRAME_BUFFER, - &disp_frame_buffer)) { - mtk_v4l2_err("[%d]Cannot get param : GET_PARAM_DISP_FRAME_BUFFER", - ctx->id); - return NULL; - } - - if (disp_frame_buffer == NULL) { - mtk_v4l2_debug(3, "No display frame buffer"); - return NULL; - } - - dstbuf = container_of(disp_frame_buffer, struct mtk_video_dec_buf, - frame_buffer); - vb = &dstbuf->m2m_buf.vb; - mutex_lock(&ctx->lock); - if (dstbuf->used) { - vb2_set_plane_payload(&vb->vb2_buf, 0, - ctx->picinfo.fb_sz[0]); - if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) - vb2_set_plane_payload(&vb->vb2_buf, 1, - ctx->picinfo.fb_sz[1]); - - mtk_v4l2_debug(2, - "[%d]status=%x queue id=%d to done_list %d", - ctx->id, disp_frame_buffer->status, - vb->vb2_buf.index, - dstbuf->queued_in_vb2); - - v4l2_m2m_buf_done(vb, VB2_BUF_STATE_DONE); - ctx->decoded_frame_cnt++; - } - mutex_unlock(&ctx->lock); - return &vb->vb2_buf; -} - -/* - * This function tries to clean all capture buffers that are not used as - * reference buffers by codec driver any more - * In this case, we need re-queue buffer to vb2 buffer if user space - * already returns this buffer to v4l2 or this buffer is just the output of - * previous sps/pps/resolution change decode, or do nothing if user - * space still owns this buffer - */ -static struct vb2_buffer *get_free_buffer(struct mtk_vcodec_ctx *ctx) -{ - struct mtk_video_dec_buf *dstbuf; - struct vdec_fb *free_frame_buffer = NULL; - struct vb2_v4l2_buffer *vb; - - if (vdec_if_get_param(ctx, - GET_PARAM_FREE_FRAME_BUFFER, - &free_frame_buffer)) { - mtk_v4l2_err("[%d] Error!! Cannot get param", ctx->id); - return NULL; - } - if (free_frame_buffer == NULL) { - mtk_v4l2_debug(3, " No free frame buffer"); - return NULL; - } - - mtk_v4l2_debug(3, "[%d] tmp_frame_addr = 0x%p", - ctx->id, free_frame_buffer); - - dstbuf = container_of(free_frame_buffer, struct mtk_video_dec_buf, - frame_buffer); - vb = &dstbuf->m2m_buf.vb; - - mutex_lock(&ctx->lock); - if (dstbuf->used) { - if ((dstbuf->queued_in_vb2) && - (dstbuf->queued_in_v4l2) && - (free_frame_buffer->status == FB_ST_FREE)) { - /* - * After decode sps/pps or non-display buffer, we don't - * need to return capture buffer to user space, but - * just re-queue this capture buffer to vb2 queue. - * This reduce overheads that dq/q unused capture - * buffer. In this case, queued_in_vb2 = true. - */ - mtk_v4l2_debug(2, - "[%d]status=%x queue id=%d to rdy_queue %d", - ctx->id, free_frame_buffer->status, - vb->vb2_buf.index, - dstbuf->queued_in_vb2); - v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); - } else if ((dstbuf->queued_in_vb2 == false) && - (dstbuf->queued_in_v4l2 == true)) { - /* - * If buffer in v4l2 driver but not in vb2 queue yet, - * and we get this buffer from free_list, it means - * that codec driver do not use this buffer as - * reference buffer anymore. We should q buffer to vb2 - * queue, so later work thread could get this buffer - * for decode. In this case, queued_in_vb2 = false - * means this buffer is not from previous decode - * output. - */ - mtk_v4l2_debug(2, - "[%d]status=%x queue id=%d to rdy_queue", - ctx->id, free_frame_buffer->status, - vb->vb2_buf.index); - v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); - dstbuf->queued_in_vb2 = true; - } else { - /* - * Codec driver do not need to reference this capture - * buffer and this buffer is not in v4l2 driver. - * Then we don't need to do any thing, just add log when - * we need to debug buffer flow. - * When this buffer q from user space, it could - * directly q to vb2 buffer - */ - mtk_v4l2_debug(3, "[%d]status=%x err queue id=%d %d %d", - ctx->id, free_frame_buffer->status, - vb->vb2_buf.index, - dstbuf->queued_in_vb2, - dstbuf->queued_in_v4l2); - } - dstbuf->used = false; - } - mutex_unlock(&ctx->lock); - return &vb->vb2_buf; -} - -static void clean_display_buffer(struct mtk_vcodec_ctx *ctx) -{ - struct vb2_buffer *framptr; - - do { - framptr = get_display_buffer(ctx); - } while (framptr); -} - -static void clean_free_buffer(struct mtk_vcodec_ctx *ctx) -{ - struct vb2_buffer *framptr; - - do { - framptr = get_free_buffer(ctx); - } while (framptr); -} - -static void mtk_vdec_queue_res_chg_event(struct mtk_vcodec_ctx *ctx) -{ - static const struct v4l2_event ev_src_ch = { - .type = V4L2_EVENT_SOURCE_CHANGE, - .u.src_change.changes = - V4L2_EVENT_SRC_CH_RESOLUTION, - }; - - mtk_v4l2_debug(1, "[%d]", ctx->id); - v4l2_event_queue_fh(&ctx->fh, &ev_src_ch); -} - -static void mtk_vdec_flush_decoder(struct mtk_vcodec_ctx *ctx) -{ - bool res_chg; - int ret = 0; - - ret = vdec_if_decode(ctx, NULL, NULL, &res_chg); - if (ret) - mtk_v4l2_err("DecodeFinal failed, ret=%d", ret); - - clean_display_buffer(ctx); - clean_free_buffer(ctx); -} - -static void mtk_vdec_update_fmt(struct mtk_vcodec_ctx *ctx, - unsigned int pixelformat) -{ - const struct mtk_video_fmt *fmt; - struct mtk_q_data *dst_q_data; - unsigned int k; - - dst_q_data = &ctx->q_data[MTK_Q_DATA_DST]; - for (k = 0; k < NUM_FORMATS; k++) { - fmt = &mtk_video_formats[k]; - if (fmt->fourcc == pixelformat) { - mtk_v4l2_debug(1, "Update cap fourcc(%d -> %d)", - dst_q_data->fmt->fourcc, pixelformat); - dst_q_data->fmt = fmt; - return; - } - } - - mtk_v4l2_err("Cannot get fourcc(%d), using init value", pixelformat); -} - -static int mtk_vdec_pic_info_update(struct mtk_vcodec_ctx *ctx) -{ - unsigned int dpbsize = 0; - int ret; - - if (vdec_if_get_param(ctx, - GET_PARAM_PIC_INFO, - &ctx->last_decoded_picinfo)) { - mtk_v4l2_err("[%d]Error!! Cannot get param : GET_PARAM_PICTURE_INFO ERR", - ctx->id); - return -EINVAL; - } - - if (ctx->last_decoded_picinfo.pic_w == 0 || - ctx->last_decoded_picinfo.pic_h == 0 || - ctx->last_decoded_picinfo.buf_w == 0 || - ctx->last_decoded_picinfo.buf_h == 0) { - mtk_v4l2_err("Cannot get correct pic info"); - return -EINVAL; - } - - if (ctx->last_decoded_picinfo.cap_fourcc != ctx->picinfo.cap_fourcc && - ctx->picinfo.cap_fourcc != 0) - mtk_vdec_update_fmt(ctx, ctx->picinfo.cap_fourcc); - - if ((ctx->last_decoded_picinfo.pic_w == ctx->picinfo.pic_w) || - (ctx->last_decoded_picinfo.pic_h == ctx->picinfo.pic_h)) - return 0; - - mtk_v4l2_debug(1, - "[%d]-> new(%d,%d), old(%d,%d), real(%d,%d)", - ctx->id, ctx->last_decoded_picinfo.pic_w, - ctx->last_decoded_picinfo.pic_h, - ctx->picinfo.pic_w, ctx->picinfo.pic_h, - ctx->last_decoded_picinfo.buf_w, - ctx->last_decoded_picinfo.buf_h); - - ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize); - if (dpbsize == 0) - mtk_v4l2_err("Incorrect dpb size, ret=%d", ret); - - ctx->dpb_size = dpbsize; - - return ret; -} - -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 *src_buf, *dst_buf; - struct mtk_vcodec_mem buf; - struct vdec_fb *pfb; - bool res_chg = false; - int ret; - struct mtk_video_dec_buf *dst_buf_info, *src_buf_info; - - src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); - if (src_buf == NULL) { - v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); - mtk_v4l2_debug(1, "[%d] src_buf empty!!", ctx->id); - return; - } - - dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); - if (dst_buf == NULL) { - v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); - mtk_v4l2_debug(1, "[%d] dst_buf empty!!", ctx->id); - return; - } - - src_buf_info = container_of(src_buf, struct mtk_video_dec_buf, - m2m_buf.vb); - dst_buf_info = container_of(dst_buf, struct mtk_video_dec_buf, - m2m_buf.vb); - - pfb = &dst_buf_info->frame_buffer; - pfb->base_y.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); - pfb->base_y.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); - pfb->base_y.size = ctx->picinfo.fb_sz[0]; - - pfb->base_c.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 1); - pfb->base_c.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 1); - pfb->base_c.size = ctx->picinfo.fb_sz[1]; - pfb->status = 0; - mtk_v4l2_debug(3, "===>[%d] vdec_if_decode() ===>", ctx->id); - - mtk_v4l2_debug(3, - "id=%d Framebuf pfb=%p VA=%p Y_DMA=%pad C_DMA=%pad Size=%zx", - dst_buf->vb2_buf.index, pfb, - pfb->base_y.va, &pfb->base_y.dma_addr, - &pfb->base_c.dma_addr, pfb->base_y.size); - - if (src_buf_info->lastframe) { - mtk_v4l2_debug(1, "Got empty flush input buffer."); - src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); - - /* update dst buf status */ - dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); - mutex_lock(&ctx->lock); - dst_buf_info->used = false; - mutex_unlock(&ctx->lock); - - vdec_if_decode(ctx, NULL, NULL, &res_chg); - clean_display_buffer(ctx); - vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); - if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) - vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0); - dst_buf->flags |= V4L2_BUF_FLAG_LAST; - v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); - clean_free_buffer(ctx); - v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); - return; - } - buf.va = vb2_plane_vaddr(&src_buf->vb2_buf, 0); - buf.dma_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); - buf.size = (size_t)src_buf->vb2_buf.planes[0].bytesused; - if (!buf.va) { - v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); - mtk_v4l2_err("[%d] id=%d src_addr is NULL!!", - ctx->id, src_buf->vb2_buf.index); - return; - } - mtk_v4l2_debug(3, "[%d] Bitstream VA=%p DMA=%pad Size=%zx vb=%p", - ctx->id, buf.va, &buf.dma_addr, buf.size, src_buf); - dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp; - dst_buf->timecode = src_buf->timecode; - mutex_lock(&ctx->lock); - dst_buf_info->used = true; - mutex_unlock(&ctx->lock); - src_buf_info->used = true; - - ret = vdec_if_decode(ctx, &buf, pfb, &res_chg); - - if (ret) { - mtk_v4l2_err( - " <===[%d], src_buf[%d] sz=0x%zx pts=%llu dst_buf[%d] vdec_if_decode() ret=%d res_chg=%d===>", - ctx->id, - src_buf->vb2_buf.index, - buf.size, - src_buf->vb2_buf.timestamp, - dst_buf->vb2_buf.index, - ret, res_chg); - src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); - if (ret == -EIO) { - mutex_lock(&ctx->lock); - src_buf_info->error = true; - mutex_unlock(&ctx->lock); - } - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); - } else if (res_chg == false) { - /* - * we only return src buffer with VB2_BUF_STATE_DONE - * when decode success without resolution change - */ - src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - } - - dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); - clean_display_buffer(ctx); - clean_free_buffer(ctx); - - if (!ret && res_chg) { - mtk_vdec_pic_info_update(ctx); - /* - * On encountering a resolution change in the stream. - * The driver must first process and decode all - * remaining buffers from before the resolution change - * point, so call flush decode here - */ - mtk_vdec_flush_decoder(ctx); - /* - * After all buffers containing decoded frames from - * before the resolution change point ready to be - * dequeued on the CAPTURE queue, the driver sends a - * V4L2_EVENT_SOURCE_CHANGE event for source change - * type V4L2_EVENT_SRC_CH_RESOLUTION - */ - mtk_vdec_queue_res_chg_event(ctx); - } - v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); -} - static int vidioc_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { @@ -562,10 +123,12 @@ void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx) { struct mtk_q_data *q_data; + ctx->dev->vdec_pdata->init_vdec_params(ctx); + ctx->m2m_ctx->q_lock = &ctx->dev->dev_mutex; ctx->fh.m2m_ctx = ctx->m2m_ctx; ctx->fh.ctrl_handler = &ctx->ctrl_hdl; - INIT_WORK(&ctx->decode_work, mtk_vdec_worker); + INIT_WORK(&ctx->decode_work, ctx->dev->vdec_pdata->worker); ctx->colorspace = V4L2_COLORSPACE_REC709; ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; ctx->quantization = V4L2_QUANTIZATION_DEFAULT; @@ -575,7 +138,7 @@ void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx) memset(q_data, 0, sizeof(struct mtk_q_data)); q_data->visible_width = DFT_CFG_WIDTH; q_data->visible_height = DFT_CFG_HEIGHT; - q_data->fmt = &mtk_video_formats[OUT_FMT_IDX]; + q_data->fmt = ctx->dev->vdec_pdata->default_out_fmt; q_data->field = V4L2_FIELD_NONE; q_data->sizeimage[0] = DFT_CFG_WIDTH * DFT_CFG_HEIGHT; @@ -587,7 +150,7 @@ void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx) q_data->visible_height = DFT_CFG_HEIGHT; q_data->coded_width = DFT_CFG_WIDTH; q_data->coded_height = DFT_CFG_HEIGHT; - q_data->fmt = &mtk_video_formats[CAP_FMT_IDX]; + q_data->fmt = ctx->dev->vdec_pdata->default_cap_fmt; q_data->field = V4L2_FIELD_NONE; v4l_bound_align_image(&q_data->coded_width, @@ -729,11 +292,14 @@ static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) { const struct mtk_video_fmt *fmt; + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata; - fmt = mtk_vdec_find_format(f); + fmt = mtk_vdec_find_format(f, dec_pdata); if (!fmt) { - f->fmt.pix.pixelformat = mtk_video_formats[CAP_FMT_IDX].fourcc; - fmt = mtk_vdec_find_format(f); + f->fmt.pix.pixelformat = + ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc; + fmt = mtk_vdec_find_format(f, dec_pdata); } return vidioc_try_fmt(f, fmt); @@ -744,11 +310,14 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, { struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; const struct mtk_video_fmt *fmt; + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata; - fmt = mtk_vdec_find_format(f); + fmt = mtk_vdec_find_format(f, dec_pdata); if (!fmt) { - f->fmt.pix.pixelformat = mtk_video_formats[OUT_FMT_IDX].fourcc; - fmt = mtk_vdec_find_format(f); + f->fmt.pix.pixelformat = + ctx->q_data[MTK_Q_DATA_SRC].fmt->fourcc; + fmt = mtk_vdec_find_format(f, dec_pdata); } if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) { @@ -838,6 +407,7 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, struct mtk_q_data *q_data; int ret = 0; const struct mtk_video_fmt *fmt; + const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata; mtk_v4l2_debug(3, "[%d]", ctx->id); @@ -866,16 +436,16 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, ret = -EBUSY; } - fmt = mtk_vdec_find_format(f); + fmt = mtk_vdec_find_format(f, dec_pdata); if (fmt == NULL) { if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { f->fmt.pix.pixelformat = - mtk_video_formats[OUT_FMT_IDX].fourcc; - fmt = mtk_vdec_find_format(f); + dec_pdata->default_out_fmt->fourcc; + fmt = mtk_vdec_find_format(f, dec_pdata); } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { f->fmt.pix.pixelformat = - mtk_video_formats[CAP_FMT_IDX].fourcc; - fmt = mtk_vdec_find_format(f); + dec_pdata->default_cap_fmt->fourcc; + fmt = mtk_vdec_find_format(f, dec_pdata); } } if (fmt == NULL) @@ -912,16 +482,17 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, { int i = 0; struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata; if (fsize->index != 0) return -EINVAL; - for (i = 0; i < NUM_SUPPORTED_FRAMESIZE; ++i) { - if (fsize->pixel_format != mtk_vdec_framesizes[i].fourcc) + for (i = 0; i < dec_pdata->num_framesizes; ++i) { + if (fsize->pixel_format != dec_pdata->vdec_framesizes[i].fourcc) continue; fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; - fsize->stepwise = mtk_vdec_framesizes[i].stepwise; + fsize->stepwise = dec_pdata->vdec_framesizes[i].stepwise; if (!(ctx->dev->dec_capability & VCODEC_CAPABILITY_4K_DISABLED)) { mtk_v4l2_debug(3, "4K is enabled"); @@ -944,16 +515,20 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, return -EINVAL; } -static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) +static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, void *priv, + bool output_queue) { + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata; const struct mtk_video_fmt *fmt; int i, j = 0; - for (i = 0; i < NUM_FORMATS; i++) { - if (output_queue && (mtk_video_formats[i].type != MTK_FMT_DEC)) + for (i = 0; i < dec_pdata->num_formats; i++) { + if (output_queue && + (dec_pdata->vdec_formats[i].type != MTK_FMT_DEC)) continue; if (!output_queue && - (mtk_video_formats[i].type != MTK_FMT_FRAME)) + (dec_pdata->vdec_formats[i].type != MTK_FMT_FRAME)) continue; if (j == f->index) @@ -961,10 +536,10 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) ++j; } - if (i == NUM_FORMATS) + if (i == dec_pdata->num_formats) return -EINVAL; - fmt = &mtk_video_formats[i]; + fmt = &dec_pdata->vdec_formats[i]; f->pixelformat = fmt->fourcc; f->flags = fmt->flags; @@ -974,13 +549,13 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) static int vidioc_vdec_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - return vidioc_enum_fmt(f, false); + return vidioc_enum_fmt(f, priv, false); } static int vidioc_vdec_enum_fmt_vid_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - return vidioc_enum_fmt(f, true); + return vidioc_enum_fmt(f, priv, true); } static int vidioc_vdec_g_fmt(struct file *file, void *priv, @@ -1071,7 +646,7 @@ static int vidioc_vdec_g_fmt(struct file *file, void *priv, return 0; } -static int vb2ops_vdec_queue_setup(struct vb2_queue *vq, +int vb2ops_vdec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], @@ -1095,7 +670,7 @@ static int vb2ops_vdec_queue_setup(struct vb2_queue *vq, } } else { if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - *nplanes = 2; + *nplanes = q_data->fmt->num_planes; else *nplanes = 1; @@ -1111,7 +686,7 @@ static int vb2ops_vdec_queue_setup(struct vb2_queue *vq, return 0; } -static int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb) +int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb) { struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct mtk_q_data *q_data; @@ -1133,128 +708,7 @@ static int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb) return 0; } -static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *src_buf; - struct mtk_vcodec_mem src_mem; - bool res_chg = false; - int ret = 0; - unsigned int dpbsize = 1, i = 0; - struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct vb2_v4l2_buffer *vb2_v4l2 = NULL; - struct mtk_video_dec_buf *buf = NULL; - struct mtk_q_data *dst_q_data; - - mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p", - ctx->id, vb->vb2_queue->type, - vb->index, vb); - /* - * check if this buffer is ready to be used after decode - */ - if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - vb2_v4l2 = to_vb2_v4l2_buffer(vb); - buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, - m2m_buf.vb); - mutex_lock(&ctx->lock); - if (buf->used == false) { - v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2); - buf->queued_in_vb2 = true; - buf->queued_in_v4l2 = true; - } else { - buf->queued_in_vb2 = false; - buf->queued_in_v4l2 = true; - } - mutex_unlock(&ctx->lock); - return; - } - - v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb)); - - if (ctx->state != MTK_STATE_INIT) { - mtk_v4l2_debug(3, "[%d] already init driver %d", - ctx->id, ctx->state); - return; - } - - src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); - if (!src_buf) { - mtk_v4l2_err("No src buffer"); - return; - } - buf = container_of(src_buf, struct mtk_video_dec_buf, m2m_buf.vb); - if (buf->lastframe) { - /* This shouldn't happen. Just in case. */ - mtk_v4l2_err("Invalid flush buffer."); - v4l2_m2m_src_buf_remove(ctx->m2m_ctx); - return; - } - - src_mem.va = vb2_plane_vaddr(&src_buf->vb2_buf, 0); - src_mem.dma_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); - src_mem.size = (size_t)src_buf->vb2_buf.planes[0].bytesused; - mtk_v4l2_debug(2, - "[%d] buf id=%d va=%p dma=%pad size=%zx", - ctx->id, src_buf->vb2_buf.index, - src_mem.va, &src_mem.dma_addr, - src_mem.size); - - ret = vdec_if_decode(ctx, &src_mem, NULL, &res_chg); - if (ret || !res_chg) { - /* - * fb == NULL means to parse SPS/PPS header or - * resolution info in src_mem. Decode can fail - * if there is no SPS header or picture info - * in bs - */ - - src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); - if (ret == -EIO) { - mtk_v4l2_err("[%d] Unrecoverable error in vdec_if_decode.", - ctx->id); - ctx->state = MTK_STATE_ABORT; - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); - } else { - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - } - mtk_v4l2_debug(ret ? 0 : 1, - "[%d] vdec_if_decode() src_buf=%d, size=%zu, fail=%d, res_chg=%d", - ctx->id, src_buf->vb2_buf.index, - src_mem.size, ret, res_chg); - return; - } - - if (vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, &ctx->picinfo)) { - mtk_v4l2_err("[%d]Error!! Cannot get param : GET_PARAM_PICTURE_INFO ERR", - ctx->id); - return; - } - - ctx->last_decoded_picinfo = ctx->picinfo; - dst_q_data = &ctx->q_data[MTK_Q_DATA_DST]; - for (i = 0; i < dst_q_data->fmt->num_planes; i++) { - dst_q_data->sizeimage[i] = ctx->picinfo.fb_sz[i]; - dst_q_data->bytesperline[i] = ctx->picinfo.buf_w; - } - - mtk_v4l2_debug(2, "[%d] vdec_if_init() OK wxh=%dx%d pic wxh=%dx%d sz[0]=0x%x sz[1]=0x%x", - ctx->id, - ctx->picinfo.buf_w, ctx->picinfo.buf_h, - ctx->picinfo.pic_w, ctx->picinfo.pic_h, - dst_q_data->sizeimage[0], - dst_q_data->sizeimage[1]); - - ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize); - if (dpbsize == 0) - mtk_v4l2_err("[%d] GET_PARAM_DPB_SIZE fail=%d", ctx->id, ret); - - ctx->dpb_size = dpbsize; - ctx->state = MTK_STATE_HEADER; - mtk_v4l2_debug(1, "[%d] dpbsize=%d", ctx->id, ctx->dpb_size); - - mtk_vdec_queue_res_chg_event(ctx); -} - -static void vb2ops_vdec_buf_finish(struct vb2_buffer *vb) +void vb2ops_vdec_buf_finish(struct vb2_buffer *vb) { struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct vb2_v4l2_buffer *vb2_v4l2; @@ -1277,7 +731,7 @@ static void vb2ops_vdec_buf_finish(struct vb2_buffer *vb) } } -static int vb2ops_vdec_buf_init(struct vb2_buffer *vb) +int vb2ops_vdec_buf_init(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf); @@ -1294,7 +748,7 @@ static int vb2ops_vdec_buf_init(struct vb2_buffer *vb) return 0; } -static int vb2ops_vdec_start_streaming(struct vb2_queue *q, unsigned int count) +int vb2ops_vdec_start_streaming(struct vb2_queue *q, unsigned int count) { struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q); @@ -1304,7 +758,7 @@ static int vb2ops_vdec_start_streaming(struct vb2_queue *q, unsigned int count) return 0; } -static void vb2ops_vdec_stop_streaming(struct vb2_queue *q) +void vb2ops_vdec_stop_streaming(struct vb2_queue *q) { struct vb2_v4l2_buffer *src_buf = NULL, *dst_buf = NULL; struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q); @@ -1341,7 +795,7 @@ static void vb2ops_vdec_stop_streaming(struct vb2_queue *q) ctx->last_decoded_picinfo.buf_w, ctx->last_decoded_picinfo.buf_h); - mtk_vdec_flush_decoder(ctx); + ctx->dev->vdec_pdata->flush_decoder(ctx); } ctx->state = MTK_STATE_FLUSH; @@ -1388,7 +842,7 @@ static void m2mops_vdec_job_abort(void *priv) ctx->state = MTK_STATE_ABORT; } -static int mtk_vdec_g_v_ctrl(struct v4l2_ctrl *ctrl) +int mtk_vdec_g_v_ctrl(struct v4l2_ctrl *ctrl) { struct mtk_vcodec_ctx *ctx = ctrl_to_ctx(ctrl); int ret = 0; @@ -1408,55 +862,12 @@ static int mtk_vdec_g_v_ctrl(struct v4l2_ctrl *ctrl) return ret; } -static const struct v4l2_ctrl_ops mtk_vcodec_dec_ctrl_ops = { - .g_volatile_ctrl = mtk_vdec_g_v_ctrl, -}; - -int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_ctx *ctx) -{ - struct v4l2_ctrl *ctrl; - - v4l2_ctrl_handler_init(&ctx->ctrl_hdl, 1); - - ctrl = v4l2_ctrl_new_std(&ctx->ctrl_hdl, - &mtk_vcodec_dec_ctrl_ops, - V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, - 0, 32, 1, 1); - ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; - v4l2_ctrl_new_std_menu(&ctx->ctrl_hdl, - &mtk_vcodec_dec_ctrl_ops, - V4L2_CID_MPEG_VIDEO_VP9_PROFILE, - V4L2_MPEG_VIDEO_VP9_PROFILE_0, - 0, V4L2_MPEG_VIDEO_VP9_PROFILE_0); - - if (ctx->ctrl_hdl.error) { - mtk_v4l2_err("Adding control failed %d", - ctx->ctrl_hdl.error); - return ctx->ctrl_hdl.error; - } - - v4l2_ctrl_handler_setup(&ctx->ctrl_hdl); - return 0; -} - const struct v4l2_m2m_ops mtk_vdec_m2m_ops = { .device_run = m2mops_vdec_device_run, .job_ready = m2mops_vdec_job_ready, .job_abort = m2mops_vdec_job_abort, }; -static const struct vb2_ops mtk_vdec_vb2_ops = { - .queue_setup = vb2ops_vdec_queue_setup, - .buf_prepare = vb2ops_vdec_buf_prepare, - .buf_queue = vb2ops_vdec_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .buf_init = vb2ops_vdec_buf_init, - .buf_finish = vb2ops_vdec_buf_finish, - .start_streaming = vb2ops_vdec_start_streaming, - .stop_streaming = vb2ops_vdec_stop_streaming, -}; - const struct v4l2_ioctl_ops mtk_vdec_ioctl_ops = { .vidioc_streamon = v4l2_m2m_ioctl_streamon, .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, @@ -1503,7 +914,7 @@ int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq, src_vq->io_modes = VB2_DMABUF | VB2_MMAP; src_vq->drv_priv = ctx; src_vq->buf_struct_size = sizeof(struct mtk_video_dec_buf); - src_vq->ops = &mtk_vdec_vb2_ops; + src_vq->ops = ctx->dev->vdec_pdata->vdec_vb2_ops; src_vq->mem_ops = &vb2_dma_contig_memops; src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; src_vq->lock = &ctx->dev->dev_mutex; @@ -1518,7 +929,7 @@ int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; dst_vq->drv_priv = ctx; dst_vq->buf_struct_size = sizeof(struct mtk_video_dec_buf); - dst_vq->ops = &mtk_vdec_vb2_ops; + dst_vq->ops = ctx->dev->vdec_pdata->vdec_vb2_ops; dst_vq->mem_ops = &vb2_dma_contig_memops; dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; dst_vq->lock = &ctx->dev->dev_mutex; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h index cf26b6c1486a..97a8304f6600 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h @@ -16,6 +16,8 @@ #define VCODEC_DEC_4K_CODED_HEIGHT 2304U #define MTK_VDEC_MAX_W 2048U #define MTK_VDEC_MAX_H 1088U +#define MTK_VDEC_MIN_W 64U +#define MTK_VDEC_MIN_H 64U #define MTK_VDEC_IRQ_STATUS_DEC_SUCCESS 0x10000 @@ -73,7 +75,22 @@ int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq); void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx); void mtk_vcodec_dec_release(struct mtk_vcodec_ctx *ctx); -int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_ctx *ctx); + +int mtk_vdec_g_v_ctrl(struct v4l2_ctrl *ctrl); + +/* + * VB2 ops + */ +int vb2ops_vdec_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, + unsigned int *nplanes, + unsigned int sizes[], + struct device *alloc_devs[]); +int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb); +void vb2ops_vdec_buf_finish(struct vb2_buffer *vb); +int vb2ops_vdec_buf_init(struct vb2_buffer *vb); +int vb2ops_vdec_start_streaming(struct vb2_queue *q, unsigned int count); +void vb2ops_vdec_stop_streaming(struct vb2_queue *q); #endif /* _MTK_VCODEC_DEC_H_ */ 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 5b5765b98e57..3d8eaf0746c2 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c @@ -106,7 +106,7 @@ static int fops_vcodec_open(struct file *file) mutex_init(&ctx->lock); ctx->type = MTK_INST_DECODER; - ret = mtk_vcodec_dec_ctrls_setup(ctx); + ret = dev->vdec_pdata->ctrls_setup(ctx); if (ret) { mtk_v4l2_err("Failed to setup mt vcodec controls"); goto err_ctrls_setup; @@ -222,6 +222,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev) INIT_LIST_HEAD(&dev->ctx_list); dev->plat_dev = pdev; + dev->vdec_pdata = of_device_get_match_data(&pdev->dev); if (!of_property_read_u32(pdev->dev.of_node, "mediatek,vpu", &rproc_phandle)) { fw_type = VPU; @@ -347,8 +348,13 @@ static int mtk_vcodec_probe(struct platform_device *pdev) return ret; } +extern const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata; + static const struct of_device_id mtk_vcodec_match[] = { - {.compatible = "mediatek,mt8173-vcodec-dec",}, + { + .compatible = "mediatek,mt8173-vcodec-dec", + .data = &mtk_vdec_8173_pdata, + }, {}, }; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c new file mode 100644 index 000000000000..3224c8049255 --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c @@ -0,0 +1,633 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include + +#include "mtk_vcodec_drv.h" +#include "mtk_vcodec_dec.h" +#include "mtk_vcodec_intr.h" +#include "mtk_vcodec_util.h" +#include "vdec_drv_if.h" +#include "mtk_vcodec_dec_pm.h" + +static const struct mtk_video_fmt mtk_video_formats[] = { + { + .fourcc = V4L2_PIX_FMT_H264, + .type = MTK_FMT_DEC, + .num_planes = 1, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, + }, + { + .fourcc = V4L2_PIX_FMT_VP8, + .type = MTK_FMT_DEC, + .num_planes = 1, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, + }, + { + .fourcc = V4L2_PIX_FMT_VP9, + .type = MTK_FMT_DEC, + .num_planes = 1, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, + }, + { + .fourcc = V4L2_PIX_FMT_MT21C, + .type = MTK_FMT_FRAME, + .num_planes = 2, + }, +}; + +#define NUM_FORMATS ARRAY_SIZE(mtk_video_formats) +#define DEFAULT_OUT_FMT_IDX 0 +#define DEFAULT_CAP_FMT_IDX 3 + +static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = { + { + .fourcc = V4L2_PIX_FMT_H264, + .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, + MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, + }, + { + .fourcc = V4L2_PIX_FMT_VP8, + .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, + MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, + }, + { + .fourcc = V4L2_PIX_FMT_VP9, + .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, + MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, + }, +}; + +#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_vdec_framesizes) + +/* + * This function tries to clean all display buffers, the buffers will return + * in display order. + * Note the buffers returned from codec driver may still be in driver's + * reference list. + */ +static struct vb2_buffer *get_display_buffer(struct mtk_vcodec_ctx *ctx) +{ + struct vdec_fb *disp_frame_buffer = NULL; + struct mtk_video_dec_buf *dstbuf; + struct vb2_v4l2_buffer *vb; + + mtk_v4l2_debug(3, "[%d]", ctx->id); + if (vdec_if_get_param(ctx, + GET_PARAM_DISP_FRAME_BUFFER, + &disp_frame_buffer)) { + mtk_v4l2_err("[%d]Cannot get param : GET_PARAM_DISP_FRAME_BUFFER", + ctx->id); + return NULL; + } + + if (disp_frame_buffer == NULL) { + mtk_v4l2_debug(3, "No display frame buffer"); + return NULL; + } + + dstbuf = container_of(disp_frame_buffer, struct mtk_video_dec_buf, + frame_buffer); + vb = &dstbuf->m2m_buf.vb; + mutex_lock(&ctx->lock); + if (dstbuf->used) { + vb2_set_plane_payload(&vb->vb2_buf, 0, + ctx->picinfo.fb_sz[0]); + if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) + vb2_set_plane_payload(&vb->vb2_buf, 1, + ctx->picinfo.fb_sz[1]); + + mtk_v4l2_debug(2, + "[%d]status=%x queue id=%d to done_list %d", + ctx->id, disp_frame_buffer->status, + vb->vb2_buf.index, + dstbuf->queued_in_vb2); + + v4l2_m2m_buf_done(vb, VB2_BUF_STATE_DONE); + ctx->decoded_frame_cnt++; + } + mutex_unlock(&ctx->lock); + return &vb->vb2_buf; +} + +/* + * This function tries to clean all capture buffers that are not used as + * reference buffers by codec driver any more + * In this case, we need re-queue buffer to vb2 buffer if user space + * already returns this buffer to v4l2 or this buffer is just the output of + * previous sps/pps/resolution change decode, or do nothing if user + * space still owns this buffer + */ +static struct vb2_buffer *get_free_buffer(struct mtk_vcodec_ctx *ctx) +{ + struct mtk_video_dec_buf *dstbuf; + struct vdec_fb *free_frame_buffer = NULL; + struct vb2_v4l2_buffer *vb; + + if (vdec_if_get_param(ctx, + GET_PARAM_FREE_FRAME_BUFFER, + &free_frame_buffer)) { + mtk_v4l2_err("[%d] Error!! Cannot get param", ctx->id); + return NULL; + } + if (free_frame_buffer == NULL) { + mtk_v4l2_debug(3, " No free frame buffer"); + return NULL; + } + + mtk_v4l2_debug(3, "[%d] tmp_frame_addr = 0x%p", + ctx->id, free_frame_buffer); + + dstbuf = container_of(free_frame_buffer, struct mtk_video_dec_buf, + frame_buffer); + vb = &dstbuf->m2m_buf.vb; + + mutex_lock(&ctx->lock); + if (dstbuf->used) { + if ((dstbuf->queued_in_vb2) && + (dstbuf->queued_in_v4l2) && + (free_frame_buffer->status == FB_ST_FREE)) { + /* + * After decode sps/pps or non-display buffer, we don't + * need to return capture buffer to user space, but + * just re-queue this capture buffer to vb2 queue. + * This reduce overheads that dq/q unused capture + * buffer. In this case, queued_in_vb2 = true. + */ + mtk_v4l2_debug(2, + "[%d]status=%x queue id=%d to rdy_queue %d", + ctx->id, free_frame_buffer->status, + vb->vb2_buf.index, + dstbuf->queued_in_vb2); + v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); + } else if ((dstbuf->queued_in_vb2 == false) && + (dstbuf->queued_in_v4l2 == true)) { + /* + * If buffer in v4l2 driver but not in vb2 queue yet, + * and we get this buffer from free_list, it means + * that codec driver do not use this buffer as + * reference buffer anymore. We should q buffer to vb2 + * queue, so later work thread could get this buffer + * for decode. In this case, queued_in_vb2 = false + * means this buffer is not from previous decode + * output. + */ + mtk_v4l2_debug(2, + "[%d]status=%x queue id=%d to rdy_queue", + ctx->id, free_frame_buffer->status, + vb->vb2_buf.index); + v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); + dstbuf->queued_in_vb2 = true; + } else { + /* + * Codec driver do not need to reference this capture + * buffer and this buffer is not in v4l2 driver. + * Then we don't need to do any thing, just add log when + * we need to debug buffer flow. + * When this buffer q from user space, it could + * directly q to vb2 buffer + */ + mtk_v4l2_debug(3, "[%d]status=%x err queue id=%d %d %d", + ctx->id, free_frame_buffer->status, + vb->vb2_buf.index, + dstbuf->queued_in_vb2, + dstbuf->queued_in_v4l2); + } + dstbuf->used = false; + } + mutex_unlock(&ctx->lock); + return &vb->vb2_buf; +} + +static void clean_display_buffer(struct mtk_vcodec_ctx *ctx) +{ + struct vb2_buffer *framptr; + + do { + framptr = get_display_buffer(ctx); + } while (framptr); +} + +static void clean_free_buffer(struct mtk_vcodec_ctx *ctx) +{ + struct vb2_buffer *framptr; + + do { + framptr = get_free_buffer(ctx); + } while (framptr); +} + +static void mtk_vdec_queue_res_chg_event(struct mtk_vcodec_ctx *ctx) +{ + static const struct v4l2_event ev_src_ch = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = + V4L2_EVENT_SRC_CH_RESOLUTION, + }; + + mtk_v4l2_debug(1, "[%d]", ctx->id); + v4l2_event_queue_fh(&ctx->fh, &ev_src_ch); +} + +static void mtk_vdec_flush_decoder(struct mtk_vcodec_ctx *ctx) +{ + bool res_chg; + int ret = 0; + + ret = vdec_if_decode(ctx, NULL, NULL, &res_chg); + if (ret) + mtk_v4l2_err("DecodeFinal failed, ret=%d", ret); + + clean_display_buffer(ctx); + clean_free_buffer(ctx); +} + +static void mtk_vdec_update_fmt(struct mtk_vcodec_ctx *ctx, + unsigned int pixelformat) +{ + const struct mtk_video_fmt *fmt; + struct mtk_q_data *dst_q_data; + unsigned int k; + + dst_q_data = &ctx->q_data[MTK_Q_DATA_DST]; + for (k = 0; k < NUM_FORMATS; k++) { + fmt = &mtk_video_formats[k]; + if (fmt->fourcc == pixelformat) { + mtk_v4l2_debug(1, "Update cap fourcc(%d -> %d)", + dst_q_data->fmt->fourcc, pixelformat); + dst_q_data->fmt = fmt; + return; + } + } + + mtk_v4l2_err("Cannot get fourcc(%d), using init value", pixelformat); +} + +static int mtk_vdec_pic_info_update(struct mtk_vcodec_ctx *ctx) +{ + unsigned int dpbsize = 0; + int ret; + + if (vdec_if_get_param(ctx, + GET_PARAM_PIC_INFO, + &ctx->last_decoded_picinfo)) { + mtk_v4l2_err("[%d]Error!! Cannot get param : GET_PARAM_PICTURE_INFO ERR", + ctx->id); + return -EINVAL; + } + + if (ctx->last_decoded_picinfo.pic_w == 0 || + ctx->last_decoded_picinfo.pic_h == 0 || + ctx->last_decoded_picinfo.buf_w == 0 || + ctx->last_decoded_picinfo.buf_h == 0) { + mtk_v4l2_err("Cannot get correct pic info"); + return -EINVAL; + } + + if (ctx->last_decoded_picinfo.cap_fourcc != ctx->picinfo.cap_fourcc && + ctx->picinfo.cap_fourcc != 0) + mtk_vdec_update_fmt(ctx, ctx->picinfo.cap_fourcc); + + if ((ctx->last_decoded_picinfo.pic_w == ctx->picinfo.pic_w) || + (ctx->last_decoded_picinfo.pic_h == ctx->picinfo.pic_h)) + return 0; + + mtk_v4l2_debug(1, + "[%d]-> new(%d,%d), old(%d,%d), real(%d,%d)", + ctx->id, ctx->last_decoded_picinfo.pic_w, + ctx->last_decoded_picinfo.pic_h, + ctx->picinfo.pic_w, ctx->picinfo.pic_h, + ctx->last_decoded_picinfo.buf_w, + ctx->last_decoded_picinfo.buf_h); + + ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize); + if (dpbsize == 0) + mtk_v4l2_err("Incorrect dpb size, ret=%d", ret); + + ctx->dpb_size = dpbsize; + + return ret; +} + +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 *src_buf, *dst_buf; + struct mtk_vcodec_mem buf; + struct vdec_fb *pfb; + bool res_chg = false; + int ret; + struct mtk_video_dec_buf *dst_buf_info, *src_buf_info; + + src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + if (src_buf == NULL) { + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + mtk_v4l2_debug(1, "[%d] src_buf empty!!", ctx->id); + return; + } + + dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + if (dst_buf == NULL) { + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + mtk_v4l2_debug(1, "[%d] dst_buf empty!!", ctx->id); + return; + } + + src_buf_info = container_of(src_buf, struct mtk_video_dec_buf, + m2m_buf.vb); + dst_buf_info = container_of(dst_buf, struct mtk_video_dec_buf, + m2m_buf.vb); + + pfb = &dst_buf_info->frame_buffer; + pfb->base_y.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); + pfb->base_y.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); + pfb->base_y.size = ctx->picinfo.fb_sz[0]; + + pfb->base_c.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 1); + pfb->base_c.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 1); + pfb->base_c.size = ctx->picinfo.fb_sz[1]; + pfb->status = 0; + mtk_v4l2_debug(3, "===>[%d] vdec_if_decode() ===>", ctx->id); + + mtk_v4l2_debug(3, + "id=%d Framebuf pfb=%p VA=%p Y_DMA=%pad C_DMA=%pad Size=%zx", + dst_buf->vb2_buf.index, pfb, + pfb->base_y.va, &pfb->base_y.dma_addr, + &pfb->base_c.dma_addr, pfb->base_y.size); + + if (src_buf_info->lastframe) { + mtk_v4l2_debug(1, "Got empty flush input buffer."); + src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + + /* update dst buf status */ + dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); + mutex_lock(&ctx->lock); + dst_buf_info->used = false; + mutex_unlock(&ctx->lock); + + vdec_if_decode(ctx, NULL, NULL, &res_chg); + clean_display_buffer(ctx); + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); + if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) + vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0); + dst_buf->flags |= V4L2_BUF_FLAG_LAST; + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); + clean_free_buffer(ctx); + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + return; + } + buf.va = vb2_plane_vaddr(&src_buf->vb2_buf, 0); + buf.dma_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); + buf.size = (size_t)src_buf->vb2_buf.planes[0].bytesused; + if (!buf.va) { + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + mtk_v4l2_err("[%d] id=%d src_addr is NULL!!", + ctx->id, src_buf->vb2_buf.index); + return; + } + mtk_v4l2_debug(3, "[%d] Bitstream VA=%p DMA=%pad Size=%zx vb=%p", + ctx->id, buf.va, &buf.dma_addr, buf.size, src_buf); + dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp; + dst_buf->timecode = src_buf->timecode; + mutex_lock(&ctx->lock); + dst_buf_info->used = true; + mutex_unlock(&ctx->lock); + src_buf_info->used = true; + + ret = vdec_if_decode(ctx, &buf, pfb, &res_chg); + + if (ret) { + mtk_v4l2_err( + " <===[%d], src_buf[%d] sz=0x%zx pts=%llu dst_buf[%d] vdec_if_decode() ret=%d res_chg=%d===>", + ctx->id, + src_buf->vb2_buf.index, + buf.size, + src_buf->vb2_buf.timestamp, + dst_buf->vb2_buf.index, + ret, res_chg); + src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + if (ret == -EIO) { + mutex_lock(&ctx->lock); + src_buf_info->error = true; + mutex_unlock(&ctx->lock); + } + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + } else if (res_chg == false) { + /* + * we only return src buffer with VB2_BUF_STATE_DONE + * when decode success without resolution change + */ + src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + } + + dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); + clean_display_buffer(ctx); + clean_free_buffer(ctx); + + if (!ret && res_chg) { + mtk_vdec_pic_info_update(ctx); + /* + * On encountering a resolution change in the stream. + * The driver must first process and decode all + * remaining buffers from before the resolution change + * point, so call flush decode here + */ + mtk_vdec_flush_decoder(ctx); + /* + * After all buffers containing decoded frames from + * before the resolution change point ready to be + * dequeued on the CAPTURE queue, the driver sends a + * V4L2_EVENT_SOURCE_CHANGE event for source change + * type V4L2_EVENT_SRC_CH_RESOLUTION + */ + mtk_vdec_queue_res_chg_event(ctx); + } + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); +} + +static void vb2ops_vdec_stateful_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *src_buf; + struct mtk_vcodec_mem src_mem; + bool res_chg = false; + int ret = 0; + unsigned int dpbsize = 1, i = 0; + struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vb2_v4l2 = NULL; + struct mtk_video_dec_buf *buf = NULL; + struct mtk_q_data *dst_q_data; + + mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p", + ctx->id, vb->vb2_queue->type, + vb->index, vb); + /* + * check if this buffer is ready to be used after decode + */ + if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + vb2_v4l2 = to_vb2_v4l2_buffer(vb); + buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, + m2m_buf.vb); + mutex_lock(&ctx->lock); + if (buf->used == false) { + v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2); + buf->queued_in_vb2 = true; + buf->queued_in_v4l2 = true; + } else { + buf->queued_in_vb2 = false; + buf->queued_in_v4l2 = true; + } + mutex_unlock(&ctx->lock); + return; + } + + v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb)); + + if (ctx->state != MTK_STATE_INIT) { + mtk_v4l2_debug(3, "[%d] already init driver %d", + ctx->id, ctx->state); + return; + } + + src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + if (!src_buf) { + mtk_v4l2_err("No src buffer"); + return; + } + buf = container_of(src_buf, struct mtk_video_dec_buf, m2m_buf.vb); + if (buf->lastframe) { + /* This shouldn't happen. Just in case. */ + mtk_v4l2_err("Invalid flush buffer."); + v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + return; + } + + src_mem.va = vb2_plane_vaddr(&src_buf->vb2_buf, 0); + src_mem.dma_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); + src_mem.size = (size_t)src_buf->vb2_buf.planes[0].bytesused; + mtk_v4l2_debug(2, + "[%d] buf id=%d va=%p dma=%pad size=%zx", + ctx->id, src_buf->vb2_buf.index, + src_mem.va, &src_mem.dma_addr, + src_mem.size); + + ret = vdec_if_decode(ctx, &src_mem, NULL, &res_chg); + if (ret || !res_chg) { + /* + * fb == NULL means to parse SPS/PPS header or + * resolution info in src_mem. Decode can fail + * if there is no SPS header or picture info + * in bs + */ + + src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + if (ret == -EIO) { + mtk_v4l2_err("[%d] Unrecoverable error in vdec_if_decode.", + ctx->id); + ctx->state = MTK_STATE_ABORT; + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + } else { + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + } + mtk_v4l2_debug(ret ? 0 : 1, + "[%d] vdec_if_decode() src_buf=%d, size=%zu, fail=%d, res_chg=%d", + ctx->id, src_buf->vb2_buf.index, + src_mem.size, ret, res_chg); + return; + } + + if (vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, &ctx->picinfo)) { + mtk_v4l2_err("[%d]Error!! Cannot get param : GET_PARAM_PICTURE_INFO ERR", + ctx->id); + return; + } + + ctx->last_decoded_picinfo = ctx->picinfo; + dst_q_data = &ctx->q_data[MTK_Q_DATA_DST]; + for (i = 0; i < dst_q_data->fmt->num_planes; i++) { + dst_q_data->sizeimage[i] = ctx->picinfo.fb_sz[i]; + dst_q_data->bytesperline[i] = ctx->picinfo.buf_w; + } + + mtk_v4l2_debug(2, "[%d] vdec_if_init() OK wxh=%dx%d pic wxh=%dx%d sz[0]=0x%x sz[1]=0x%x", + ctx->id, + ctx->picinfo.buf_w, ctx->picinfo.buf_h, + ctx->picinfo.pic_w, ctx->picinfo.pic_h, + dst_q_data->sizeimage[0], + dst_q_data->sizeimage[1]); + + ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize); + if (dpbsize == 0) + mtk_v4l2_err("[%d] GET_PARAM_DPB_SIZE fail=%d", ctx->id, ret); + + ctx->dpb_size = dpbsize; + ctx->state = MTK_STATE_HEADER; + mtk_v4l2_debug(1, "[%d] dpbsize=%d", ctx->id, ctx->dpb_size); + + mtk_vdec_queue_res_chg_event(ctx); +} + +static const struct v4l2_ctrl_ops mtk_vcodec_dec_ctrl_ops = { + .g_volatile_ctrl = mtk_vdec_g_v_ctrl, +}; + +static int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_ctx *ctx) +{ + struct v4l2_ctrl *ctrl; + + v4l2_ctrl_handler_init(&ctx->ctrl_hdl, 1); + + ctrl = v4l2_ctrl_new_std(&ctx->ctrl_hdl, + &mtk_vcodec_dec_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + 0, 32, 1, 1); + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + v4l2_ctrl_new_std_menu(&ctx->ctrl_hdl, + &mtk_vcodec_dec_ctrl_ops, + V4L2_CID_MPEG_VIDEO_VP9_PROFILE, + V4L2_MPEG_VIDEO_VP9_PROFILE_0, + 0, V4L2_MPEG_VIDEO_VP9_PROFILE_0); + + if (ctx->ctrl_hdl.error) { + mtk_v4l2_err("Adding control failed %d", + ctx->ctrl_hdl.error); + return ctx->ctrl_hdl.error; + } + + v4l2_ctrl_handler_setup(&ctx->ctrl_hdl); + return 0; +} + +static void mtk_init_vdec_params(struct mtk_vcodec_ctx *ctx) +{ +} + +static struct vb2_ops mtk_vdec_frame_vb2_ops = { + .queue_setup = vb2ops_vdec_queue_setup, + .buf_prepare = vb2ops_vdec_buf_prepare, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = vb2ops_vdec_start_streaming, + + .buf_queue = vb2ops_vdec_stateful_buf_queue, + .buf_init = vb2ops_vdec_buf_init, + .buf_finish = vb2ops_vdec_buf_finish, + .stop_streaming = vb2ops_vdec_stop_streaming, +}; + +const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata = { + .init_vdec_params = mtk_init_vdec_params, + .ctrls_setup = mtk_vcodec_dec_ctrls_setup, + .vdec_vb2_ops = &mtk_vdec_frame_vb2_ops, + .vdec_formats = mtk_video_formats, + .num_formats = NUM_FORMATS, + .default_out_fmt = &mtk_video_formats[DEFAULT_OUT_FMT_IDX], + .default_cap_fmt = &mtk_video_formats[DEFAULT_CAP_FMT_IDX], + .vdec_framesizes = mtk_vdec_framesizes, + .num_framesizes = NUM_SUPPORTED_FRAMESIZE, + .worker = mtk_vdec_worker, + .flush_decoder = mtk_vdec_flush_decoder, +}; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index a271611750ad..388659c28603 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -305,6 +305,45 @@ enum mtk_chip { MTK_MT8183, }; +/** + * struct mtk_vcodec_dec_pdata - compatible data for each IC + * @init_vdec_params: init vdec params + * @ctrls_setup: init vcodec dec ctrls + * @worker: worker to start a decode job + * @flush_decoder: function that flushes the decoder + * + * @vdec_vb2_ops: struct vb2_ops + * + * @vdec_formats: supported video decoder formats + * @num_formats: count of video decoder formats + * @default_out_fmt: default output buffer format + * @default_cap_fmt: default capture buffer format + * + * @vdec_framesizes: supported video decoder frame sizes + * @num_framesizes: count of video decoder frame sizes + * + * @uses_stateless_api: whether the decoder uses the stateless API with requests + */ + +struct mtk_vcodec_dec_pdata { + void (*init_vdec_params)(struct mtk_vcodec_ctx *ctx); + int (*ctrls_setup)(struct mtk_vcodec_ctx *ctx); + void (*worker)(struct work_struct *work); + void (*flush_decoder)(struct mtk_vcodec_ctx *ctx); + + struct vb2_ops *vdec_vb2_ops; + + const struct mtk_video_fmt *vdec_formats; + const int num_formats; + const struct mtk_video_fmt *default_out_fmt; + const struct mtk_video_fmt *default_cap_fmt; + + const struct mtk_codec_framesizes *vdec_framesizes; + const int num_framesizes; + + bool uses_stateless_api; +}; + /** * struct mtk_vcodec_enc_pdata - compatible data for each IC * @@ -346,6 +385,7 @@ struct mtk_vcodec_enc_pdata { * @curr_ctx: The context that is waiting for codec hardware * * @reg_base: Mapped address of MTK Vcodec registers. + * @vdec_pdata: Current arch private data. * * @fw_handler: used to communicate with the firmware. * @id_counter: used to identify current opened instance @@ -380,6 +420,7 @@ struct mtk_vcodec_dev { spinlock_t irqlock; struct mtk_vcodec_ctx *curr_ctx; void __iomem *reg_base[NUM_MAX_VCODEC_REG_BASE]; + const struct mtk_vcodec_dec_pdata *vdec_pdata; const struct mtk_vcodec_enc_pdata *venc_pdata; struct mtk_vcodec_fw *fw_handler; From patchwork Tue Jun 30 06:27:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Courbot X-Patchwork-Id: 11633289 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CAD8A13B4 for ; Tue, 30 Jun 2020 06:28:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B4417207FB for ; Tue, 30 Jun 2020 06:28:38 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="J+2x/+M7" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730357AbgF3G2h (ORCPT ); Tue, 30 Jun 2020 02:28:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35764 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730236AbgF3G1x (ORCPT ); Tue, 30 Jun 2020 02:27:53 -0400 Received: from mail-pl1-x641.google.com (mail-pl1-x641.google.com [IPv6:2607:f8b0:4864:20::641]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5AE32C03E979 for ; Mon, 29 Jun 2020 23:27:53 -0700 (PDT) Received: by mail-pl1-x641.google.com with SMTP id 35so8081551ple.0 for ; Mon, 29 Jun 2020 23:27:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=IHSDE3MCRa+j8pKcxUh7y14LEBciAICiE97iwJ5rqDM=; b=J+2x/+M77MfBW8HPgwGdfrtkc3vJUvLveNcRe8PHu861Z/YU8S/AkPNT9wC+6bsHZ/ 1+JGpmnqFFkdabkpZbCQnGcsFXQiRehA2+YDSKXcfWTjo8o7SU9mIER/DNWC8DAi7W0y 6xK29NE+PVVinquGJjTjxsWSjcoAv893gIeO0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=IHSDE3MCRa+j8pKcxUh7y14LEBciAICiE97iwJ5rqDM=; b=AML20NQUxYL3d0Hz8gYMSdUo2uBwGWiJTQH1OttfX2GPtlSrJ1WoIvzrI4/5k5oM2w kfMUqv4gihVmVaP+SIt97ZsBC6RysdwIFuRbzFLJAqjM2DPTgIbsKWixo9bWyAOsf+8a kim7/QRLV7+P/NKxVC5MNDy+nONp98MbUXUb6jcUYXxWfbE6tEfe3p9DvxaOxIAhjXRt DZ1SsiJ9CPzkHefU23LUGmvG43iPsuBeVECUNeYW8mxBbrqFZTUmRqhc8CmyBKY7Y8Ye QQlu+2W+ltxQwwJcaK679odd+GQM+x4dPScq3+6At5KmVhCD0Dlj7fruzyi1ncoceTB3 K4+g== X-Gm-Message-State: AOAM532MFkdEiw1ZxSVu9N/4hdY7lHqK40fxsX3wgXxfvIdVkZmo6ui2 180GWOa+Grpcw3hb67lPeI6dBg== X-Google-Smtp-Source: ABdhPJxabatUBNTtvr2Hv5NoLC7MLhlWxkg/fu+mXY41IkelDvc0R4c6tp8WIOAa9KUU6JPrZayROA== X-Received: by 2002:a17:90a:3624:: with SMTP id s33mr9581648pjb.148.1593498454259; Mon, 29 Jun 2020 23:27:34 -0700 (PDT) Received: from acourbot.tok.corp.google.com ([2401:fa00:8f:203:93d9:de4d:e834:3086]) by smtp.gmail.com with ESMTPSA id d1sm1463366pfq.113.2020.06.29.23.27.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Jun 2020 23:27:33 -0700 (PDT) From: Alexandre Courbot To: Tiffany Lin , Andrew-CT Chen , Rui Wang , Yunfei Dong , Pi-Hsun Shih , Maoguang Meng Cc: linux-media@vger.kernel.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, Alexandre Courbot Subject: [PATCH 2/9] media: mtk-vcodec: vdec: handle firmware version field Date: Tue, 30 Jun 2020 15:27:04 +0900 Message-Id: <20200630062711.4169601-3-acourbot@chromium.org> X-Mailer: git-send-email 2.27.0.212.ge8ba1cc988-goog In-Reply-To: <20200630062711.4169601-1-acourbot@chromium.org> References: <20200630062711.4169601-1-acourbot@chromium.org> MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Firmwares for decoders newer than MT8173 will include an ABI version number in their initialization ack message. Add the capacity to manage it and make initialization fail if the firmware ABI is of a version that we don't support. For MT8173, this ABI version field does not exist ; thus ignore it on this chip. There should only be one firmware version available for it anyway. Signed-off-by: Alexandre Courbot --- .../mtk-vcodec/mtk_vcodec_dec_stateful.c | 1 + .../platform/mtk-vcodec/mtk_vcodec_drv.h | 4 ++++ .../media/platform/mtk-vcodec/vdec_ipi_msg.h | 5 +++++ .../media/platform/mtk-vcodec/vdec_vpu_if.c | 21 +++++++++++++++++-- 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c index 3224c8049255..b4dad8767f3c 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c @@ -619,6 +619,7 @@ static struct vb2_ops mtk_vdec_frame_vb2_ops = { }; const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata = { + .chip = MTK_MT8173, .init_vdec_params = mtk_init_vdec_params, .ctrls_setup = mtk_vcodec_dec_ctrls_setup, .vdec_vb2_ops = &mtk_vdec_frame_vb2_ops, diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index 388659c28603..386712f9bffc 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -322,6 +322,8 @@ enum mtk_chip { * @vdec_framesizes: supported video decoder frame sizes * @num_framesizes: count of video decoder frame sizes * + * @chip: chip this decoder is compatible with + * * @uses_stateless_api: whether the decoder uses the stateless API with requests */ @@ -341,6 +343,8 @@ struct mtk_vcodec_dec_pdata { const struct mtk_codec_framesizes *vdec_framesizes; const int num_framesizes; + enum mtk_chip chip; + bool uses_stateless_api; }; diff --git a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h index 47a1c1c0fd04..eb66729fda63 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h +++ b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h @@ -83,12 +83,17 @@ struct vdec_ap_ipi_dec_start { * @status : VPU exeuction result * @ap_inst_addr : AP vcodec_vpu_inst instance address * @vpu_inst_addr : VPU decoder instance address + * @vdec_abi_version: ABI version of the firmware. Kernel can use it to + * ensure that it is compatible with the firmware. + * This field is not valid for MT8173 and must not be + * accessed for this chip. */ struct vdec_vpu_ipi_init_ack { uint32_t msg_id; int32_t status; uint64_t ap_inst_addr; uint32_t vpu_inst_addr; + uint32_t vdec_abi_version; }; #endif diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c index 58b0e6fa8fd2..203089213e67 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c @@ -24,6 +24,22 @@ static void handle_init_ack_msg(const struct vdec_vpu_ipi_init_ack *msg) vpu->inst_addr = msg->vpu_inst_addr; mtk_vcodec_debug(vpu, "- vpu_inst_addr = 0x%x", vpu->inst_addr); + + /* Firmware version field does not exist on MT8173. */ + if (vpu->ctx->dev->vdec_pdata->chip == MTK_MT8173) + return; + + /* Check firmware version. */ + mtk_vcodec_debug(vpu, "firmware version 0x%x\n", msg->vdec_abi_version); + switch (msg->vdec_abi_version) { + case 1: + break; + default: + mtk_vcodec_err(vpu, "unhandled firmware version 0x%x\n", + msg->vdec_abi_version); + vpu->failure = 1; + break; + } } /* @@ -44,6 +60,9 @@ static void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv) mtk_vcodec_debug(vpu, "+ id=%X", msg->msg_id); + vpu->failure = msg->status; + vpu->signaled = 1; + if (msg->status == 0) { switch (msg->msg_id) { case VPU_IPIMSG_DEC_INIT_ACK: @@ -63,8 +82,6 @@ static void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv) } mtk_vcodec_debug(vpu, "- id=%X", msg->msg_id); - vpu->failure = msg->status; - vpu->signaled = 1; } static int vcodec_vpu_send_msg(struct vdec_vpu_inst *vpu, void *msg, int len) From patchwork Tue Jun 30 06:27:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Courbot X-Patchwork-Id: 11633287 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1F64D138C for ; Tue, 30 Jun 2020 06:28:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0258E20829 for ; Tue, 30 Jun 2020 06:28:36 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="PG4Iie45" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730257AbgF3G15 (ORCPT ); Tue, 30 Jun 2020 02:27:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35770 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730248AbgF3G1z (ORCPT ); Tue, 30 Jun 2020 02:27:55 -0400 Received: from mail-pl1-x641.google.com (mail-pl1-x641.google.com [IPv6:2607:f8b0:4864:20::641]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 40940C061755 for ; Mon, 29 Jun 2020 23:27:55 -0700 (PDT) Received: by mail-pl1-x641.google.com with SMTP id j4so8072426plk.3 for ; Mon, 29 Jun 2020 23:27:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=s2pO4L1a3ERIETLNInBHqYAlx7Y/nJKu8b0lmcLiwBY=; b=PG4Iie451m7kdRRNoADr+68T27E1VRuuDU/UvbYf+T2hdaDn2AN07VwQT0hVmHZOW+ z0cD/gwUe5pnimNGKbBF5/XBcOpuJPBexzz3fWyx2xn+KWKQuOruBEYaDA6+QcDCoCAY Q8VLN+ba93w8te3eMs9BAocU3+2iRe3r+Z7Tc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=s2pO4L1a3ERIETLNInBHqYAlx7Y/nJKu8b0lmcLiwBY=; b=fQP5ev+KKd3VGII+c3R+xNP0NoQOnUH38NGJVPeq4mzwFJtYkC4llIiYDULyDWlWzp zb/nO4soC1jj8tXR5sCMspyhuRxs68ZmljWL0bDlP/uXJtcAgMKsc/YQm/t+BcAT5HJf K2uD0UdimqX943MqrPoClJBqDk6klQmVc3s6+CPu/AQThlvnohzkPSJqUiqZowj5uTVR k0U7i82osMp1PpknkRvb2hzLlmCx2YcA8UJVOcb8HRyzC/mfzREcBeTH2XxBfvvafYjL MvVPCRYEN4xgdkbByA02kmY/TxRtweERYxEFK4Je4FY5msOT/cORZLuJXduyZbjIf/tq wr3w== X-Gm-Message-State: AOAM530r9dypIkgRtON4LIP2gy4wtS1NLS6j+QH1C8Qs6a6HZIY8A59J 9MX6CnHimK5ljZEXmlmRXJRt1g== X-Google-Smtp-Source: ABdhPJzW56aq6cC2dMDiHiI8jMvBTwnwOkR07rO4mTv5K+dFHI3zdIubNtowt84OUK+ljiTgIvT4kg== X-Received: by 2002:a17:90b:102:: with SMTP id p2mr21406114pjz.227.1593498474783; Mon, 29 Jun 2020 23:27:54 -0700 (PDT) Received: from acourbot.tok.corp.google.com ([2401:fa00:8f:203:93d9:de4d:e834:3086]) by smtp.gmail.com with ESMTPSA id d1sm1463366pfq.113.2020.06.29.23.27.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Jun 2020 23:27:53 -0700 (PDT) From: Alexandre Courbot To: Tiffany Lin , Andrew-CT Chen , Rui Wang , Yunfei Dong , Pi-Hsun Shih , Maoguang Meng Cc: linux-media@vger.kernel.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, Alexandre Courbot Subject: [PATCH 3/9] media: mtk-vcodec: support version 2 of decoder firmware ABI Date: Tue, 30 Jun 2020 15:27:05 +0900 Message-Id: <20200630062711.4169601-4-acourbot@chromium.org> X-Mailer: git-send-email 2.27.0.212.ge8ba1cc988-goog In-Reply-To: <20200630062711.4169601-1-acourbot@chromium.org> References: <20200630062711.4169601-1-acourbot@chromium.org> MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Add support for decoder firmware version 2, which makes the kernel responsible for managing the VSI context and is used for stateless codecs. Signed-off-by: Alexandre Courbot --- .../media/platform/mtk-vcodec/vdec_ipi_msg.h | 18 +++++++++--- .../media/platform/mtk-vcodec/vdec_vpu_if.c | 28 +++++++++++++++---- .../media/platform/mtk-vcodec/vdec_vpu_if.h | 5 ++++ 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h index eb66729fda63..a0e773ae3ab3 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h +++ b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h @@ -29,11 +29,15 @@ enum vdec_ipi_msgid { /** * struct vdec_ap_ipi_cmd - generic AP to VPU ipi command format * @msg_id : vdec_ipi_msgid - * @vpu_inst_addr : VPU decoder instance address + * @vpu_inst_addr : VPU decoder instance address. Used if ABI version < 2. + * @inst_id : instance ID. Used if the ABI version >= 2. */ struct vdec_ap_ipi_cmd { uint32_t msg_id; - uint32_t vpu_inst_addr; + union { + uint32_t vpu_inst_addr; + uint32_t inst_id; + }; }; /** @@ -63,7 +67,8 @@ struct vdec_ap_ipi_init { /** * struct vdec_ap_ipi_dec_start - for AP_IPIMSG_DEC_START * @msg_id : AP_IPIMSG_DEC_START - * @vpu_inst_addr : VPU decoder instance address + * @vpu_inst_addr : VPU decoder instance address. Used if ABI version < 2. + * @inst_id : instance ID. Used if the ABI version >= 2. * @data : Header info * H264 decoder [0]:buf_sz [1]:nal_start * VP8 decoder [0]:width/height @@ -72,7 +77,10 @@ struct vdec_ap_ipi_init { */ struct vdec_ap_ipi_dec_start { uint32_t msg_id; - uint32_t vpu_inst_addr; + union { + uint32_t vpu_inst_addr; + uint32_t inst_id; + }; uint32_t data[3]; uint32_t reserved; }; @@ -87,6 +95,7 @@ struct vdec_ap_ipi_dec_start { * ensure that it is compatible with the firmware. * This field is not valid for MT8173 and must not be * accessed for this chip. + * @inst_id : instance ID. Valid only if the ABI version >= 2. */ struct vdec_vpu_ipi_init_ack { uint32_t msg_id; @@ -94,6 +103,7 @@ struct vdec_vpu_ipi_init_ack { uint64_t ap_inst_addr; uint32_t vpu_inst_addr; uint32_t vdec_abi_version; + uint32_t inst_id; }; #endif diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c index 203089213e67..5dffc459a33d 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c @@ -25,18 +25,30 @@ static void handle_init_ack_msg(const struct vdec_vpu_ipi_init_ack *msg) mtk_vcodec_debug(vpu, "- vpu_inst_addr = 0x%x", vpu->inst_addr); + /* Set default ABI version if dealing with unversioned firmware. */ + vpu->fw_abi_version = 0; + /* + * Instance ID is only used if ABI version >= 2. Initialize it with + * garbage by default. + */ + vpu->inst_id = 0xdeadbeef; + /* Firmware version field does not exist on MT8173. */ if (vpu->ctx->dev->vdec_pdata->chip == MTK_MT8173) return; /* Check firmware version. */ - mtk_vcodec_debug(vpu, "firmware version 0x%x\n", msg->vdec_abi_version); - switch (msg->vdec_abi_version) { + vpu->fw_abi_version = msg->vdec_abi_version; + mtk_vcodec_debug(vpu, "firmware version 0x%x\n", vpu->fw_abi_version); + switch (vpu->fw_abi_version) { case 1: break; + case 2: + vpu->inst_id = msg->inst_id; + break; default: mtk_vcodec_err(vpu, "unhandled firmware version 0x%x\n", - msg->vdec_abi_version); + vpu->fw_abi_version); vpu->failure = 1; break; } @@ -113,7 +125,10 @@ static int vcodec_send_ap_ipi(struct vdec_vpu_inst *vpu, unsigned int msg_id) memset(&msg, 0, sizeof(msg)); msg.msg_id = msg_id; - msg.vpu_inst_addr = vpu->inst_addr; + if (vpu->fw_abi_version < 2) + msg.vpu_inst_addr = vpu->inst_addr; + else + msg.inst_id = vpu->inst_id; err = vcodec_vpu_send_msg(vpu, &msg, sizeof(msg)); mtk_vcodec_debug(vpu, "- id=%X ret=%d", msg_id, err); @@ -163,7 +178,10 @@ int vpu_dec_start(struct vdec_vpu_inst *vpu, uint32_t *data, unsigned int len) memset(&msg, 0, sizeof(msg)); msg.msg_id = AP_IPIMSG_DEC_START; - msg.vpu_inst_addr = vpu->inst_addr; + if (vpu->fw_abi_version < 2) + msg.vpu_inst_addr = vpu->inst_addr; + else + msg.inst_id = vpu->inst_id; for (i = 0; i < len; i++) msg.data[i] = data[i]; diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h index 85224eb7e34b..c2ed5b6cab8b 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h +++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h @@ -18,6 +18,9 @@ struct mtk_vcodec_ctx; * for control and info share * @failure : VPU execution result status, 0: success, others: fail * @inst_addr : VPU decoder instance address + * @fw_abi_version : ABI version of the firmware. + * @inst_id : if fw_abi_version >= 2, contains the instance ID to be given + * in place of inst_addr in messages. * @signaled : 1 - Host has received ack message from VPU, 0 - not received * @ctx : context for v4l2 layer integration * @dev : platform device of VPU @@ -29,6 +32,8 @@ struct vdec_vpu_inst { void *vsi; int32_t failure; uint32_t inst_addr; + uint32_t fw_abi_version; + uint32_t inst_id; unsigned int signaled; struct mtk_vcodec_ctx *ctx; wait_queue_head_t wq; From patchwork Tue Jun 30 06:27:06 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Courbot X-Patchwork-Id: 11633259 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A260C92A for ; Tue, 30 Jun 2020 06:28:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8A95C20775 for ; Tue, 30 Jun 2020 06:28:02 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="ZC9CqbyP" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730271AbgF3G2A (ORCPT ); Tue, 30 Jun 2020 02:28:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35780 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730262AbgF3G16 (ORCPT ); Tue, 30 Jun 2020 02:27:58 -0400 Received: from mail-pl1-x642.google.com (mail-pl1-x642.google.com [IPv6:2607:f8b0:4864:20::642]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 34651C061755 for ; Mon, 29 Jun 2020 23:27:58 -0700 (PDT) Received: by mail-pl1-x642.google.com with SMTP id f2so8066075plr.8 for ; Mon, 29 Jun 2020 23:27:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=cLo9gWn34oxY8J/ohLJn1cwxm8tKGqTGHLzQqnvI/9s=; b=ZC9CqbyPemgUVWTi1ogG0chtstSnPpLx9j7x9lJY+aXbGpRQoMF0xQYCt/I8FK7GsR vrcebnckZJZhiemHHok5fIQoC/H78X3+pwJjY1RIwILg5Swg8vEXRQ5po7j8oPWJFH6s AOGydT+6StJymBvgF8jhgZK9wUZV5NnHZJ250= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=cLo9gWn34oxY8J/ohLJn1cwxm8tKGqTGHLzQqnvI/9s=; b=oriq/gTL0brnl0w3DrFjzaPGcIPr61G0iqAbFBEM2N8Etxnq9BSU/Lsjiyb8ipBXXB XJCcPh0HNxmg8IkmPCHqzdSVFBjdVi//RNRFjfscVQH/exJpRbRTAkvvQBNBUMdNVhuT VYrAzQtPdFDpRzLvjXyHRlgtHqYnXt+OzxpSs2f3BRv7grsT7R6dmb+3ynux4HkzC2nt d9JpJ1PIa76ZwGOCCa1gvs4QfbX2wc9bsTai+5qwYvUIj8CEz8qzHMnFN5KxQy49EXvf DXkWvmEQjjMbgZNbcqzt8OSLD6ZCh2PSSUIEukwmLu9uRXVypEea8e9B81kbC5M1j42n ITrQ== X-Gm-Message-State: AOAM531TfzCkjOx2Ib85xXP5QzG+VkN/CEhHTKrUJb9qdkgKjlnnkP/a M/aWdQI3kBCsyE1Evzwz8PTn3g== X-Google-Smtp-Source: ABdhPJzqEeELCaxH4ShNgfLDy3Z0zrZ0tXhBT5akKY7mXJeeLYO76PPIbsZcHg2K+9fLQgWJMSVpPQ== X-Received: by 2002:a17:90b:1013:: with SMTP id gm19mr8675125pjb.143.1593498477799; Mon, 29 Jun 2020 23:27:57 -0700 (PDT) Received: from acourbot.tok.corp.google.com ([2401:fa00:8f:203:93d9:de4d:e834:3086]) by smtp.gmail.com with ESMTPSA id d1sm1463366pfq.113.2020.06.29.23.27.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Jun 2020 23:27:57 -0700 (PDT) From: Alexandre Courbot To: Tiffany Lin , Andrew-CT Chen , Rui Wang , Yunfei Dong , Pi-Hsun Shih , Maoguang Meng Cc: linux-media@vger.kernel.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, Alexandre Courbot Subject: [PATCH 4/9] media: add Mediatek's MM21 format Date: Tue, 30 Jun 2020 15:27:06 +0900 Message-Id: <20200630062711.4169601-5-acourbot@chromium.org> X-Mailer: git-send-email 2.27.0.212.ge8ba1cc988-goog In-Reply-To: <20200630062711.4169601-1-acourbot@chromium.org> References: <20200630062711.4169601-1-acourbot@chromium.org> MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Add Mediatek's non-compressed 8 bit block video mode. This format is produced by the MT8183 codec and can be converted to a non-proprietary format by the MDP3 component. Signed-off-by: Alexandre Courbot --- drivers/media/v4l2-core/v4l2-ioctl.c | 1 + include/uapi/linux/videodev2.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 02bfef0da76d..612be602bf76 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1398,6 +1398,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_META_FMT_UVC: descr = "UVC Payload Header Metadata"; break; case V4L2_META_FMT_D4XX: descr = "Intel D4xx UVC Metadata"; break; case V4L2_META_FMT_VIVID: descr = "Vivid Metadata"; break; + case V4L2_PIX_FMT_MM21: descr = "Mediatek 8-bit block format"; break; default: /* Compressed formats */ diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 303805438814..a35f65115bca 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -738,6 +738,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_Y12I v4l2_fourcc('Y', '1', '2', 'I') /* Greyscale 12-bit L/R interleaved */ #define V4L2_PIX_FMT_Z16 v4l2_fourcc('Z', '1', '6', ' ') /* Depth data 16-bit */ #define V4L2_PIX_FMT_MT21C v4l2_fourcc('M', 'T', '2', '1') /* Mediatek compressed block mode */ +#define V4L2_PIX_FMT_MM21 v4l2_fourcc('M', 'M', '2', '1') /* Mediatek 8-bit block mode, two non-contiguous planes */ #define V4L2_PIX_FMT_INZI v4l2_fourcc('I', 'N', 'Z', 'I') /* Intel Planar Greyscale 10-bit and Depth 16-bit */ #define V4L2_PIX_FMT_SUNXI_TILED_NV12 v4l2_fourcc('S', 'T', '1', '2') /* Sunxi Tiled NV12 Format */ #define V4L2_PIX_FMT_CNF4 v4l2_fourcc('C', 'N', 'F', '4') /* Intel 4-bit packed depth confidence information */ From patchwork Tue Jun 30 06:27:07 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Courbot X-Patchwork-Id: 11633285 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CCB2692A for ; Tue, 30 Jun 2020 06:28:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AEA222081A for ; Tue, 30 Jun 2020 06:28:30 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="cmed1dyd" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730285AbgF3G2F (ORCPT ); Tue, 30 Jun 2020 02:28:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35798 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730274AbgF3G2B (ORCPT ); Tue, 30 Jun 2020 02:28:01 -0400 Received: from mail-pg1-x542.google.com (mail-pg1-x542.google.com [IPv6:2607:f8b0:4864:20::542]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C4454C03E979 for ; Mon, 29 Jun 2020 23:28:01 -0700 (PDT) Received: by mail-pg1-x542.google.com with SMTP id e9so9452844pgo.9 for ; Mon, 29 Jun 2020 23:28:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=4+m+EOx/bPV2OJ8zGLqFJloVPu2avFww3EyhIHm4v8o=; b=cmed1dydaqDKDtx1RmHs1kqZauxFjY4lnEAVe/49uNG8NEKq62Gk1okvzz2J/Uzv95 95sQDG1MYukobUoCRUvbCU8d+iUybF1b4xKkpolf/4pXLfnMZ+NbQ08CDlnwvRtpSeuP Bn2I/3xjd02mw0WCHUUr9RYxWl0bQe5kjxemk= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=4+m+EOx/bPV2OJ8zGLqFJloVPu2avFww3EyhIHm4v8o=; b=ktNuZTYWOSiiJwVkHuccxR1HIx4RzuC8WkTxL5ZfJyEzdgyvveoY6AgyzBXZk9GSwo kdMJU23Ff6DK4m30A4PGNoQdkTl6yhBghSdvgq7xPp0YbC3le+CI/S9GTXcX7y3YdZqu vkmTS6xtRBBlNKI0C0OzsKV2xFUCtEjqZ7V8PAwYgBqw7pzqA04pMu6sQn+fa+2kfaNG FzcD0X9+6n5DsIHyoUmaSXB0+qsSK+w9vrnYIwaJtsKuNuGQKNl+i2KppPZd+c7P6CWV mns7X4BpKWZShj41+OQLmobM0qg3Y58DA01iKQFa13DtO7QLjXPKHIxKh2L5ciSdSeEx utXQ== X-Gm-Message-State: AOAM533RsBWUrCMn6a5MTAWHdCeLltNbZpK6/WvGjxSPidAv8nI5qFQ4 mq+vXRPg2rRaBbqsY/liBVSSzQ== X-Google-Smtp-Source: ABdhPJywvI4QonObi2Y9OESNM/N548cmryxDIhqh7TOrf6BOT3a70TgoJWrz0fA11Y28qfLNqCdoMA== X-Received: by 2002:a62:6446:: with SMTP id y67mr10603794pfb.299.1593498481133; Mon, 29 Jun 2020 23:28:01 -0700 (PDT) Received: from acourbot.tok.corp.google.com ([2401:fa00:8f:203:93d9:de4d:e834:3086]) by smtp.gmail.com with ESMTPSA id d1sm1463366pfq.113.2020.06.29.23.27.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Jun 2020 23:28:00 -0700 (PDT) From: Alexandre Courbot To: Tiffany Lin , Andrew-CT Chen , Rui Wang , Yunfei Dong , Pi-Hsun Shih , Maoguang Meng Cc: linux-media@vger.kernel.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, Alexandre Courbot Subject: [PATCH 5/9] media: mtk-vcodec: vdec: support stateless API Date: Tue, 30 Jun 2020 15:27:07 +0900 Message-Id: <20200630062711.4169601-6-acourbot@chromium.org> X-Mailer: git-send-email 2.27.0.212.ge8ba1cc988-goog In-Reply-To: <20200630062711.4169601-1-acourbot@chromium.org> References: <20200630062711.4169601-1-acourbot@chromium.org> MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org From: Yunfei Dong Support the stateless codec API that will be used by MT8183. Signed-off-by: Yunfei Dong [acourbot: refactor, cleanup and split] Co-developed-by: Alexandre Courbot Signed-off-by: Alexandre Courbot --- drivers/media/platform/mtk-vcodec/Makefile | 1 + .../platform/mtk-vcodec/mtk_vcodec_dec.c | 66 ++- .../platform/mtk-vcodec/mtk_vcodec_dec.h | 9 +- .../mtk-vcodec/mtk_vcodec_dec_stateless.c | 469 ++++++++++++++++++ .../platform/mtk-vcodec/mtk_vcodec_drv.h | 3 + 5 files changed, 545 insertions(+), 3 deletions(-) create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c diff --git a/drivers/media/platform/mtk-vcodec/Makefile b/drivers/media/platform/mtk-vcodec/Makefile index a9e189af5ba4..057e2519aafd 100644 --- a/drivers/media/platform/mtk-vcodec/Makefile +++ b/drivers/media/platform/mtk-vcodec/Makefile @@ -12,6 +12,7 @@ mtk-vcodec-dec-y := vdec/vdec_h264_if.o \ vdec_vpu_if.o \ mtk_vcodec_dec.o \ mtk_vcodec_dec_stateful.o \ + mtk_vcodec_dec_stateless.o \ mtk_vcodec_dec_pm.o \ mtk_vcodec_fw.o diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 7e01ac03887e..8de72879b1a0 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -46,6 +46,13 @@ static struct mtk_q_data *mtk_vdec_get_q_data(struct mtk_vcodec_ctx *ctx, static int vidioc_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + + /* Use M2M stateless helper if relevant */ + if (ctx->dev->vdec_pdata->uses_stateless_api) + return v4l2_m2m_ioctl_stateless_try_decoder_cmd(file, priv, + cmd); + switch (cmd->cmd) { case V4L2_DEC_CMD_STOP: case V4L2_DEC_CMD_START: @@ -72,6 +79,10 @@ static int vidioc_decoder_cmd(struct file *file, void *priv, if (ret) return ret; + /* Use M2M stateless helper if relevant */ + if (ctx->dev->vdec_pdata->uses_stateless_api) + return v4l2_m2m_ioctl_stateless_decoder_cmd(file, priv, cmd); + mtk_v4l2_debug(1, "decoder cmd=%u", cmd->cmd); dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); @@ -420,7 +431,8 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, * Setting OUTPUT format after OUTPUT buffers are allocated is invalid * if using the stateful API. */ - if ((f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) && + if (!dec_pdata->uses_stateless_api && + (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) && vb2_is_busy(&ctx->m2m_ctx->out_q_ctx.q)) { mtk_v4l2_err("out_q_ctx buffers already requested"); ret = -EBUSY; @@ -463,6 +475,7 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, ctx->quantization = pix_mp->quantization; ctx->xfer_func = pix_mp->xfer_func; + ctx->current_codec = fmt->fourcc; if (ctx->state == MTK_STATE_FREE) { ret = vdec_if_init(ctx, q_data->fmt->fourcc); if (ret) { @@ -474,6 +487,49 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, } } + /* + * If using the stateless API, S_FMT should have the effect of setting + * the CAPTURE queue resolution no matter which queue it was called on. + */ + if (dec_pdata->uses_stateless_api) { + ctx->picinfo.pic_w = pix_mp->width; + ctx->picinfo.pic_h = pix_mp->height; + + 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; + + if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 1) { + ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] = + ctx->picinfo.fb_sz[0] + + ctx->picinfo.fb_sz[1]; + ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] = + ctx->picinfo.buf_w; + } else { + ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] = + ctx->picinfo.fb_sz[0]; + ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] = + ctx->picinfo.buf_w; + ctx->q_data[MTK_Q_DATA_DST].sizeimage[1] = + ctx->picinfo.fb_sz[1]; + ctx->q_data[MTK_Q_DATA_DST].bytesperline[1] = + ctx->picinfo.buf_w; + } + + ctx->q_data[MTK_Q_DATA_DST].coded_width = ctx->picinfo.buf_w; + ctx->q_data[MTK_Q_DATA_DST].coded_height = ctx->picinfo.buf_h; + mtk_v4l2_debug(2, "[%d] vdec_if_init() num_plane = %d wxh=%dx%d pic wxh=%dx%d sz[0]=0x%x sz[1]=0x%x", + ctx->id, pix_mp->num_planes, + ctx->picinfo.buf_w, ctx->picinfo.buf_h, + ctx->picinfo.pic_w, ctx->picinfo.pic_h, + ctx->q_data[MTK_Q_DATA_DST].sizeimage[0], + ctx->q_data[MTK_Q_DATA_DST].sizeimage[1]); + } return 0; } @@ -770,9 +826,15 @@ void vb2ops_vdec_stop_streaming(struct vb2_queue *q) while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) { struct mtk_video_dec_buf *buf_info = container_of( src_buf, struct mtk_video_dec_buf, m2m_buf.vb); - if (!buf_info->lastframe) + if (!buf_info->lastframe) { + struct media_request *req = + src_buf->vb2_buf.req_obj.req; v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + if (req) + v4l2_ctrl_request_complete(req, + &ctx->ctrl_hdl); + } } return; } diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h index 97a8304f6600..a2949e1bc7fe 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h @@ -45,6 +45,7 @@ struct vdec_fb { * @lastframe: Intput buffer is last buffer - EOS * @error: An unrecoverable error occurs on this buffer. * @frame_buffer: Decode status, and buffer information of Capture buffer + * @bs_buffer: Output buffer info * * Note : These status information help us track and debug buffer state */ @@ -55,12 +56,18 @@ struct mtk_video_dec_buf { bool queued_in_vb2; bool queued_in_v4l2; bool lastframe; + bool error; - struct vdec_fb frame_buffer; + + union { + struct vdec_fb frame_buffer; + struct mtk_vcodec_mem bs_buffer; + }; }; extern const struct v4l2_ioctl_ops mtk_vdec_ioctl_ops; extern const struct v4l2_m2m_ops mtk_vdec_m2m_ops; +extern const struct media_device_ops mtk_vcodec_media_ops; /* diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c new file mode 100644 index 000000000000..9fad965af1c8 --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c @@ -0,0 +1,469 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include + +#include "mtk_vcodec_drv.h" +#include "mtk_vcodec_dec.h" +#include "mtk_vcodec_intr.h" +#include "mtk_vcodec_util.h" +#include "vdec_drv_if.h" +#include "mtk_vcodec_dec_pm.h" + +/** + * struct mtk_stateless_control - CID control type + * @id: CID control id + * @v4l2_ctrl_type: CID control type + * @codec_type codec type (V4L2 pixel format) for CID control type + */ +struct mtk_stateless_control { + u32 id; + enum v4l2_ctrl_type type; + int codec_type; +}; + +static const struct mtk_stateless_control mtk_stateless_controls[] = { + { + .id = V4L2_CID_MPEG_VIDEO_H264_SPS, + .type = V4L2_CTRL_TYPE_H264_SPS, + .codec_type = V4L2_PIX_FMT_H264_SLICE, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_PPS, + .type = V4L2_CTRL_TYPE_H264_PPS, + .codec_type = V4L2_PIX_FMT_H264_SLICE, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, + .type = V4L2_CTRL_TYPE_H264_SCALING_MATRIX, + .codec_type = V4L2_PIX_FMT_H264_SLICE, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS, + .type = V4L2_CTRL_TYPE_H264_SLICE_PARAMS, + .codec_type = V4L2_PIX_FMT_H264_SLICE, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, + .type = V4L2_CTRL_TYPE_H264_DECODE_PARAMS, + .codec_type = V4L2_PIX_FMT_H264_SLICE, + }, +}; + +#define NUM_CTRLS ARRAY_SIZE(mtk_stateless_controls) + +static const struct mtk_video_fmt mtk_video_formats[] = { + { + .fourcc = V4L2_PIX_FMT_H264_SLICE, + .type = MTK_FMT_DEC, + .num_planes = 1, + }, + { + .fourcc = V4L2_PIX_FMT_MM21, + .type = MTK_FMT_FRAME, + .num_planes = 2, + }, +}; + +#define NUM_FORMATS ARRAY_SIZE(mtk_video_formats) +#define DEFAULT_OUT_FMT_IDX 0 +#define DEFAULT_CAP_FMT_IDX 1 + +static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = { + { + .fourcc = V4L2_PIX_FMT_H264_SLICE, + .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, + MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, + }, +}; + +#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_vdec_framesizes) + +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 *out_buf; + struct vb2_v4l2_buffer *vb; + + if (bs == NULL) { + 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); +} + +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 = 0, cap_c_size = 0; + + if (fb == NULL) { + 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; + if (error == 1) { + cap_y_size = 0; + cap_c_size = 0; + } else { + 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 == 1) + vb->flags |= V4L2_BUF_FLAG_LAST; + v4l2_m2m_buf_done(vb, VB2_BUF_STATE_DONE); +} + +static struct vdec_fb *vdec_get_cap_buffer(struct mtk_vcodec_ctx *ctx) +{ + 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 == NULL) { + mtk_v4l2_debug(1, "[%d] dst_buf empty!!", ctx->id); + return 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 = 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]; + } + mtk_v4l2_debug(1, + "id=%d Framebuf pfb=%p VA=%p Y_DMA=%pad C_DMA=%pad Size=%zx frame_count = %d", + dst_buf->index, pfb, + pfb->base_y.va, &pfb->base_y.dma_addr, + &pfb->base_c.dma_addr, pfb->base_y.size, + ctx->decoded_frame_cnt); + + return pfb; +} + +static void vb2ops_vdec_buf_request_complete(struct vb2_buffer *vb) +{ + struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->ctrl_hdl); +} + +static int fops_media_request_validate(struct media_request *mreq) +{ + struct mtk_vcodec_ctx *ctx = NULL; + struct media_request_object *req_obj; + struct v4l2_ctrl_handler *parent_hdl, *hdl; + struct v4l2_ctrl *ctrl_test; + unsigned int buffer_cnt; + unsigned int i; + + buffer_cnt = vb2_request_buffer_cnt(mreq); + if (!buffer_cnt) { + mtk_v4l2_err("Request count is zero"); + return -ENOENT; + } else if (buffer_cnt > 1) { + mtk_v4l2_err("Request count is too much %d", buffer_cnt); + return -EINVAL; + } + + list_for_each_entry(req_obj, &mreq->objects, list) { + struct vb2_buffer *vb; + + if (vb2_request_object_is_buffer(req_obj)) { + vb = container_of(req_obj, struct vb2_buffer, req_obj); + ctx = vb2_get_drv_priv(vb->vb2_queue); + break; + } + } + + if (!ctx) + return -ENOENT; + + parent_hdl = &ctx->ctrl_hdl; + + hdl = v4l2_ctrl_request_hdl_find(mreq, parent_hdl); + if (!hdl) { + mtk_v4l2_err("Missing codec control(s)\n"); + return -ENOENT; + } + + for (i = 0; i < NUM_CTRLS; i++) { + if (mtk_stateless_controls[i].codec_type != ctx->current_codec) + continue; + + ctrl_test = v4l2_ctrl_request_hdl_ctrl_find(hdl, + mtk_stateless_controls[i].id); + if (!ctrl_test) { + mtk_v4l2_err("Missing required codec control\n"); + return -ENOENT; + } + } + + v4l2_ctrl_request_hdl_put(hdl); + + return vb2_request_validate(mreq); +} + +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_buffer *src_buf; + struct vdec_fb *dst_buf; + struct mtk_vcodec_mem *buf; + struct mtk_video_dec_buf *src_buf_info; + struct vb2_v4l2_buffer *src_vb2_v4l2; + struct media_request *src_buf_req; + bool res_chg = false; + int ret; + + src_vb2_v4l2 = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + if (src_vb2_v4l2 == NULL) { + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + mtk_v4l2_debug(1, "[%d] src_buf empty!!", ctx->id); + return; + } + + src_buf = &src_vb2_v4l2->vb2_buf; + src_buf_info = container_of(src_vb2_v4l2, struct mtk_video_dec_buf, + m2m_buf.vb); + + mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p buf_info = %p", + ctx->id, src_buf->vb2_queue->type, + src_buf->index, src_buf, src_buf_info); + + buf = &src_buf_info->bs_buffer; + buf->va = vb2_plane_vaddr(src_buf, 0); + buf->dma_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); + buf->size = (size_t)src_buf->planes[0].bytesused; + if (!buf->va) { + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + mtk_v4l2_err("[%d] id=%d src_addr is NULL!!", + ctx->id, src_buf->index); + return; + } + + mtk_v4l2_debug(3, "[%d] Bitstream VA=%p DMA=%pad Size=%zx vb=%p", + ctx->id, buf->va, &buf->dma_addr, buf->size, src_buf); + /* Apply request controls. */ + src_buf_req = src_vb2_v4l2->vb2_buf.req_obj.req; + if (src_buf_req) + v4l2_ctrl_request_setup(src_buf_req, &ctx->ctrl_hdl); + else + mtk_v4l2_err("vb2 buffer media request is NULL"); + + dst_buf = vdec_get_cap_buffer(ctx); + + v4l2_m2m_buf_copy_metadata(src_vb2_v4l2, + v4l2_m2m_next_dst_buf(ctx->m2m_ctx), true); + ret = vdec_if_decode(ctx, buf, dst_buf, &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, + src_buf->index, + buf->size, + src_buf->timestamp, + ret, res_chg); + if (ret == -EIO) { + mutex_lock(&ctx->lock); + src_buf_info->error = true; + mutex_unlock(&ctx->lock); + } + } + + mtk_vdec_stateless_out_to_done(ctx, buf, ret); + if (!ret) + mtk_vdec_stateless_cap_to_disp(ctx, dst_buf, 0); + + 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) +{ + struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vb2_v4l2 = NULL; + struct mtk_video_dec_buf *dst_buf = NULL; + struct mtk_video_dec_buf *src_buf = NULL; + + mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p", + ctx->id, vb->vb2_queue->type, + vb->index, vb); + + /* + * check if this buffer is ready to be used after decode + */ + vb2_v4l2 = to_vb2_v4l2_buffer(vb); + if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + dst_buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, + m2m_buf.vb); + mutex_lock(&ctx->lock); + v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2); + mutex_unlock(&ctx->lock); + return; + } + + src_buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, m2m_buf.vb); + mutex_lock(&ctx->lock); + v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2); + mutex_unlock(&ctx->lock); + + mtk_v4l2_debug(3, "(%d) id=%d, bs=%p", + vb->vb2_queue->type, vb->index, src_buf); + + if (ctx->state == MTK_STATE_INIT) { + ctx->state = MTK_STATE_HEADER; + mtk_v4l2_debug(1, "Init driver from init to header."); + } else + mtk_v4l2_debug(3, "[%d] already init driver %d", + ctx->id, ctx->state); + +} + +static void mtk_vdec_flush_decoder(struct mtk_vcodec_ctx *ctx) +{ + bool res_chg; + + vdec_if_decode(ctx, NULL, NULL, &res_chg); +} + +static const struct v4l2_ctrl_ops mtk_vcodec_dec_ctrl_ops = { + .g_volatile_ctrl = mtk_vdec_g_v_ctrl, +}; + +static int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_ctx *ctx) +{ + struct v4l2_ctrl *ctrl; + unsigned int i; + + v4l2_ctrl_handler_init(&ctx->ctrl_hdl, NUM_CTRLS); + if (ctx->ctrl_hdl.error) { + mtk_v4l2_err("v4l2_ctrl_handler_init failed\n"); + return ctx->ctrl_hdl.error; + } + + ctrl = v4l2_ctrl_new_std(&ctx->ctrl_hdl, + &mtk_vcodec_dec_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + 0, 32, 1, 1); + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + if (ctx->ctrl_hdl.error) { + mtk_v4l2_err("Adding control failed %d", + ctx->ctrl_hdl.error); + return ctx->ctrl_hdl.error; + } + + for (i = 0; i < NUM_CTRLS; i++) { + struct v4l2_ctrl_config cfg = { 0 }; + + cfg.ops = &mtk_vcodec_dec_ctrl_ops; + cfg.id = mtk_stateless_controls[i].id; + cfg.type = mtk_stateless_controls[i].type; + + v4l2_ctrl_new_custom(&ctx->ctrl_hdl, &cfg, NULL); + if (ctx->ctrl_hdl.error) { + mtk_v4l2_err("Adding control failed %d", + ctx->ctrl_hdl.error); + return ctx->ctrl_hdl.error; + } + } + + v4l2_ctrl_handler_setup(&ctx->ctrl_hdl); + + return 0; +} + +const struct media_device_ops mtk_vcodec_media_ops = { + .req_validate = fops_media_request_validate, + .req_queue = v4l2_m2m_request_queue, +}; + +static void mtk_init_vdec_params(struct mtk_vcodec_ctx *ctx) +{ + struct vb2_queue *src_vq; + + src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + + /* Support request api for output plane */ + src_vq->supports_requests = true; + src_vq->requires_requests = true; +} + +static int vb2ops_vdec_out_buf_validate(struct vb2_buffer *vb) +{ + return 0; +} + +static struct vb2_ops mtk_vdec_request_vb2_ops = { + .queue_setup = vb2ops_vdec_queue_setup, + .buf_prepare = vb2ops_vdec_buf_prepare, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = vb2ops_vdec_start_streaming, + + .buf_queue = vb2ops_vdec_stateless_buf_queue, + .buf_out_validate = vb2ops_vdec_out_buf_validate, + .buf_init = vb2ops_vdec_buf_init, + .buf_finish = vb2ops_vdec_buf_finish, + .stop_streaming = vb2ops_vdec_stop_streaming, + .buf_request_complete = vb2ops_vdec_buf_request_complete, +}; + +const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata = { + .chip = MTK_MT8183, + .init_vdec_params = mtk_init_vdec_params, + .ctrls_setup = mtk_vcodec_dec_ctrls_setup, + .vdec_vb2_ops = &mtk_vdec_request_vb2_ops, + .vdec_formats = mtk_video_formats, + .num_formats = NUM_FORMATS, + .default_out_fmt = &mtk_video_formats[DEFAULT_OUT_FMT_IDX], + .default_cap_fmt = &mtk_video_formats[DEFAULT_CAP_FMT_IDX], + .vdec_framesizes = mtk_vdec_framesizes, + .num_framesizes = NUM_SUPPORTED_FRAMESIZE, + .uses_stateless_api = true, + .worker = mtk_vdec_worker, + .flush_decoder = mtk_vdec_flush_decoder, +}; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index 386712f9bffc..755631d0fe92 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -251,6 +251,7 @@ struct vdec_pic_info { * @encode_work: worker for the encoding * @last_decoded_picinfo: pic information get from latest decode * @empty_flush_buf: a fake size-0 capture buffer that indicates flush + * @current_codec: current set input codec, in V4L2 pixel format * * @colorspace: enum v4l2_colorspace; supplemental to pixelformat * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding @@ -290,6 +291,8 @@ struct mtk_vcodec_ctx { struct vdec_pic_info last_decoded_picinfo; struct mtk_video_dec_buf *empty_flush_buf; + u32 current_codec; + enum v4l2_colorspace colorspace; enum v4l2_ycbcr_encoding ycbcr_enc; enum v4l2_quantization quantization; From patchwork Tue Jun 30 06:27:08 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Courbot X-Patchwork-Id: 11633281 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9FE43138C for ; Tue, 30 Jun 2020 06:28:28 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 75ED120759 for ; Tue, 30 Jun 2020 06:28:28 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="ZIuUv++X" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730301AbgF3G2L (ORCPT ); Tue, 30 Jun 2020 02:28:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35810 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730284AbgF3G2F (ORCPT ); Tue, 30 Jun 2020 02:28:05 -0400 Received: from mail-pg1-x542.google.com (mail-pg1-x542.google.com [IPv6:2607:f8b0:4864:20::542]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F1A26C03E979 for ; Mon, 29 Jun 2020 23:28:04 -0700 (PDT) Received: by mail-pg1-x542.google.com with SMTP id p3so9468209pgh.3 for ; Mon, 29 Jun 2020 23:28:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=OtOeixb7mccS5LB6aqSec7TAqhmpOggKk1PCiEhjqwA=; b=ZIuUv++XwmntjHjZsrVuempnAWF+xOvalvYgRG+AZ0Usbl2cEqtMU5LPOuzYcUifQB pNOhu1GXeWwIIlmXX71BLRcC+95MxxYZpZPvP6Zfmy+o/c5KCZW4QCf27eB/qTYKM9yv 7cMyaZFHmz6mUFQR6oEt2aaKsICK5kFJVKZYE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=OtOeixb7mccS5LB6aqSec7TAqhmpOggKk1PCiEhjqwA=; b=GYgQ8Sq0IwDpjo/9LhJVn4KiTMTPj5Pv1G7fJIsc4LEzS2OEw3XafxImMGO0mKt89c gKVyprbueT4b6EMHXbyAF6GEqxAtyaDeCycS1nbQwxM1QRgTaaZopgaTpOLB3OIYYuNW CGhdXfOa7a6nnMeRT3j0AZRWLG8BeWJhgQOF+8QumPp6Rl2hfzO7m13+jf+Vl9GmUF9J /reptlZ+8EaAWxoGzym93H7ITj3K7gtb4xA3ESj95xyD2t2ho53KemVCN9ahW1Koafhu p6QgKoqPH1TqhYDyp2A6UFmfvWqO9EBQHeyAvm5I1dGJS/lp2sIsfJ5WmPanQRhs3Y43 s3rg== X-Gm-Message-State: AOAM532nnWhcK74/QH9weuNlGmUJE6yvHfGyfBmf9qqcEnIwngFu3fq9 TYyoMSxlkFUj53kvUNpQ9PWfHg== X-Google-Smtp-Source: ABdhPJz4N4tXtxXvOixQeratjjXIFAHYukWiVaRMQvGMN4PUAT2PsW0bCL3G1HFLurm6oFTToRkXRQ== X-Received: by 2002:aa7:8f03:: with SMTP id x3mr16831468pfr.64.1593498484259; Mon, 29 Jun 2020 23:28:04 -0700 (PDT) Received: from acourbot.tok.corp.google.com ([2401:fa00:8f:203:93d9:de4d:e834:3086]) by smtp.gmail.com with ESMTPSA id d1sm1463366pfq.113.2020.06.29.23.28.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Jun 2020 23:28:03 -0700 (PDT) From: Alexandre Courbot To: Tiffany Lin , Andrew-CT Chen , Rui Wang , Yunfei Dong , Pi-Hsun Shih , Maoguang Meng Cc: linux-media@vger.kernel.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, Alexandre Courbot Subject: [PATCH 6/9] media: mtk-vcodec: vdec: support stateless H.264 decoding Date: Tue, 30 Jun 2020 15:27:08 +0900 Message-Id: <20200630062711.4169601-7-acourbot@chromium.org> X-Mailer: git-send-email 2.27.0.212.ge8ba1cc988-goog In-Reply-To: <20200630062711.4169601-1-acourbot@chromium.org> References: <20200630062711.4169601-1-acourbot@chromium.org> MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org From: Yunfei Dong Add support for H.264 decoding using the stateless API, as supported by MT8183. This support takes advantage of the V4L2 H.264 reference list builders. Signed-off-by: Yunfei Dong [acourbot: refactor, cleanup and split] Co-developed-by: Alexandre Courbot Signed-off-by: Alexandre Courbot --- drivers/media/platform/Kconfig | 1 + drivers/media/platform/mtk-vcodec/Makefile | 1 + .../mtk-vcodec/vdec/vdec_h264_req_if.c | 802 ++++++++++++++++++ .../media/platform/mtk-vcodec/vdec_drv_if.c | 3 + .../media/platform/mtk-vcodec/vdec_drv_if.h | 1 + 5 files changed, 808 insertions(+) create mode 100644 drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_if.c diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index f0dbe048efea..ff77c6db55db 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -255,6 +255,7 @@ config VIDEO_MEDIATEK_VCODEC depends on ARCH_MEDIATEK || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV + select V4L2_H264 select VIDEO_MEDIATEK_VPU select MTK_SCP help diff --git a/drivers/media/platform/mtk-vcodec/Makefile b/drivers/media/platform/mtk-vcodec/Makefile index 057e2519aafd..f7c1d27a85d5 100644 --- a/drivers/media/platform/mtk-vcodec/Makefile +++ b/drivers/media/platform/mtk-vcodec/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-dec.o \ 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 \ 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_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_if.c new file mode 100644 index 000000000000..f90518910d8d --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_if.c @@ -0,0 +1,802 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include + +#include "../vdec_drv_if.h" +#include "../mtk_vcodec_util.h" +#include "../mtk_vcodec_dec.h" +#include "../mtk_vcodec_intr.h" +#include "../vdec_vpu_if.h" +#include "../vdec_drv_base.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 + +/* 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_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 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_* */ +}; + +/** + * struct mtk_h264_dec_slice_param - parameters for decode current frame + */ +struct mtk_h264_dec_slice_param { + struct mtk_h264_sps_param sps; + struct mtk_h264_pps_param pps; + struct slice_api_h264_scaling_matrix scaling_matrix; + struct slice_api_h264_decode_param decode_params; + 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 { + uint64_t vdec_fb_va; + uint64_t y_fb_dma; + uint64_t c_fb_dma; + int32_t poc; + uint32_t reserved; +}; + +/** + * struct vdec_h264_dec_info - decode information + * @dpb_sz : decoding picture buffer size + * @resolution_changed : resoltion change happen + * @realloc_mv_buf : flag to notify driver to re-allocate mv buffer + * @cap_num_planes : number planes of capture buffer + * @bs_dma : Input bit-stream buffer dma address + * @y_fb_dma : Y frame buffer dma address + * @c_fb_dma : C frame buffer dma address + * @vdec_fb_va : VDEC frame buffer struct virtual address + */ +struct vdec_h264_dec_info { + uint32_t dpb_sz; + uint32_t resolution_changed; + uint32_t realloc_mv_buf; + uint32_t cap_num_planes; + uint64_t bs_dma; + uint64_t y_fb_dma; + uint64_t c_fb_dma; + uint64_t vdec_fb_va; +}; + +/** + * struct vdec_h264_vsi - shared memory for decode information exchange + * between VPU and Host. + * The memory is allocated by VPU then mapping to Host + * in vpu_dec_init() and freed in vpu_dec_deinit() + * by VPU. + * AP-W/R : AP is writer/reader on this item + * VPU-W/R: VPU is write/reader on this item + * @pred_buf_dma : HW working predication buffer dma address (AP-W, VPU-R) + * @mv_buf_dma : HW working motion vector buffer dma address (AP-W, VPU-R) + * @dec : decode information (AP-R, VPU-W) + * @pic : picture information (AP-R, VPU-W) + * @crop : crop information (AP-R, VPU-W) + */ +struct vdec_h264_vsi { + uint64_t pred_buf_dma; + uint64_t mv_buf_dma[H264_MAX_MV_NUM]; + struct vdec_h264_dec_info dec; + struct vdec_pic_info pic; + struct v4l2_rect crop; + struct mtk_h264_dec_slice_param h264_slice_params; +}; + +/** + * struct vdec_h264_slice_inst - h264 decoder instance + * @num_nalu : how many nalus be decoded + * @ctx : point to mtk_vcodec_ctx + * @pred_buf : HW working predication buffer + * @mv_buf : HW working motion vector buffer + * @vpu : VPU instance + * @vsi_ctx : Local VSI data for this decoding context + */ +struct vdec_h264_slice_inst { + unsigned int num_nalu; + struct mtk_vcodec_ctx *ctx; + struct mtk_vcodec_mem pred_buf; + struct mtk_vcodec_mem mv_buf[H264_MAX_MV_NUM]; + struct vdec_vpu_inst vpu; + struct vdec_h264_vsi vsi_ctx; + struct mtk_h264_dec_slice_param h264_slice_param; + + 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 < 16; 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_PIC_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) +{ + 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 = + &src_params->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; + } + + dst_params->num_slices = src_params->num_slices; + 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); + } +} + +static void get_vdec_decode_parameters(struct vdec_h264_slice_inst *inst) +{ + struct mtk_h264_dec_slice_param *slice_param = &inst->h264_slice_param; + const struct v4l2_ctrl_h264_decode_params *dec_params = + get_ctrl_ptr(inst->ctx, V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS); + const struct v4l2_ctrl_h264_slice_params *slice_params = + get_ctrl_ptr(inst->ctx, V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS); + const struct v4l2_ctrl_h264_sps *sps = + get_ctrl_ptr(inst->ctx, V4L2_CID_MPEG_VIDEO_H264_SPS); + struct v4l2_ctrl_h264_decode_params fixed_params = *dec_params; + struct v4l2_h264_reflist_builder reflist_builder; + + update_dpb(dec_params, inst->dpb); + memcpy(fixed_params.dpb, inst->dpb, sizeof(inst->dpb)); + + get_h264_sps_parameters(&slice_param->sps, + get_ctrl_ptr(inst->ctx, + V4L2_CID_MPEG_VIDEO_H264_SPS)); + get_h264_pps_parameters(&slice_param->pps, + get_ctrl_ptr(inst->ctx, + V4L2_CID_MPEG_VIDEO_H264_PPS)); + get_h264_scaling_matrix( + &slice_param->scaling_matrix, + get_ctrl_ptr(inst->ctx, + V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX)); + get_h264_decode_parameters(&slice_param->decode_params, &fixed_params); + get_h264_dpb_list(inst, slice_param); + + /* The firmware expects unused reference list entries to be set to 32 */ + memset(&slice_param->decode_params.ref_pic_list_p0, 32, + sizeof(slice_param->decode_params.ref_pic_list_p0)); + memset(&slice_param->decode_params.ref_pic_list_b0, 32, + sizeof(slice_param->decode_params.ref_pic_list_b0)); + memset(&slice_param->decode_params.ref_pic_list_b1, 32, + sizeof(slice_param->decode_params.ref_pic_list_b1)); + + /* Build the reference frames lists */ + v4l2_h264_init_reflist_builder(&reflist_builder, dec_params, + slice_params, sps, inst->dpb); + v4l2_h264_build_p_ref_list(&reflist_builder, + slice_param->decode_params.ref_pic_list_p0); + v4l2_h264_build_b_ref_lists(&reflist_builder, + slice_param->decode_params.ref_pic_list_b0, + slice_param->decode_params.ref_pic_list_b1); + + 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 = 0; + + inst->pred_buf.size = BUF_PREDICTION_SZ; + err = mtk_vcodec_mem_alloc(inst->ctx, &inst->pred_buf); + if (err) { + mtk_vcodec_err(inst, "failed to allocate ppl buf"); + return err; + } + + inst->vsi_ctx.pred_buf_dma = inst->pred_buf.dma_addr; + return 0; +} + +static void free_predication_buf(struct vdec_h264_slice_inst *inst) +{ + struct mtk_vcodec_mem *mem = NULL; + + mtk_vcodec_debug_enter(inst); + + inst->vsi_ctx.pred_buf_dma = 0; + mem = &inst->pred_buf; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); +} + +static int alloc_mv_buf(struct vdec_h264_slice_inst *inst, + struct vdec_pic_info *pic) +{ + int i; + int err; + struct mtk_vcodec_mem *mem = NULL; + unsigned int buf_sz = get_mv_buf_size(pic->buf_w, pic->buf_h); + + mtk_v4l2_debug(3, "size = 0x%lx", buf_sz); + for (i = 0; i < H264_MAX_MV_NUM; i++) { + mem = &inst->mv_buf[i]; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + mem->size = buf_sz; + err = mtk_vcodec_mem_alloc(inst->ctx, mem); + if (err) { + mtk_vcodec_err(inst, "failed to allocate mv buf"); + return err; + } + inst->vsi_ctx.mv_buf_dma[i] = mem->dma_addr; + } + + return 0; +} + +static void free_mv_buf(struct vdec_h264_slice_inst *inst) +{ + int i; + struct mtk_vcodec_mem *mem = NULL; + + for (i = 0; i < H264_MAX_MV_NUM; i++) { + inst->vsi_ctx.mv_buf_dma[i] = 0; + mem = &inst->mv_buf[i]; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + } +} + +static void get_pic_info(struct vdec_h264_slice_inst *inst, + struct vdec_pic_info *pic) +{ + struct mtk_vcodec_ctx *ctx = inst->ctx; + + ctx->picinfo.buf_w = (ctx->picinfo.pic_w + 15) & 0xFFFFFFF0; + ctx->picinfo.buf_h = (ctx->picinfo.pic_h + 31) & 0xFFFFFFE0; + ctx->picinfo.fb_sz[0] = ctx->picinfo.buf_w * ctx->picinfo.buf_h; + ctx->picinfo.fb_sz[1] = ctx->picinfo.fb_sz[0] >> 1; + inst->vsi_ctx.dec.cap_num_planes = + ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes; + + pic = &ctx->picinfo; + mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)", + ctx->picinfo.pic_w, ctx->picinfo.pic_h, + ctx->picinfo.buf_w, ctx->picinfo.buf_h); + mtk_vcodec_debug(inst, "Y/C(%d, %d)", ctx->picinfo.fb_sz[0], + ctx->picinfo.fb_sz[1]); + + if ((ctx->last_decoded_picinfo.pic_w != ctx->picinfo.pic_w) || + (ctx->last_decoded_picinfo.pic_h != ctx->picinfo.pic_h)) { + inst->vsi_ctx.dec.resolution_changed = true; + if ((ctx->last_decoded_picinfo.buf_w != ctx->picinfo.buf_w) || + (ctx->last_decoded_picinfo.buf_h != ctx->picinfo.buf_h)) + inst->vsi_ctx.dec.realloc_mv_buf = true; + + mtk_v4l2_debug(1, "ResChg: (%d %d) : old(%d, %d) -> new(%d, %d)", + inst->vsi_ctx.dec.resolution_changed, + inst->vsi_ctx.dec.realloc_mv_buf, + ctx->last_decoded_picinfo.pic_w, + ctx->last_decoded_picinfo.pic_h, + ctx->picinfo.pic_w, ctx->picinfo.pic_h); + } +} + +static void get_crop_info(struct vdec_h264_slice_inst *inst, + struct v4l2_rect *cr) +{ + cr->left = inst->vsi_ctx.crop.left; + cr->top = inst->vsi_ctx.crop.top; + cr->width = inst->vsi_ctx.crop.width; + cr->height = inst->vsi_ctx.crop.height; + + mtk_vcodec_debug(inst, "l=%d, t=%d, w=%d, h=%d", + cr->left, cr->top, cr->width, cr->height); +} + +static void get_dpb_size(struct vdec_h264_slice_inst *inst, + unsigned int *dpb_sz) +{ + *dpb_sz = inst->vsi_ctx.dec.dpb_sz; + mtk_vcodec_debug(inst, "sz=%d", *dpb_sz); +} + +static int vdec_h264_slice_init(struct mtk_vcodec_ctx *ctx) +{ + struct vdec_h264_slice_inst *inst = NULL; + int err; + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + inst->ctx = ctx; + + inst->vpu.id = SCP_IPI_VDEC_H264; + inst->vpu.ctx = ctx; + + err = vpu_dec_init(&inst->vpu); + if (err) { + mtk_vcodec_err(inst, "vdec_h264 init err=%d", err); + goto error_free_inst; + } + + memcpy(&inst->vsi_ctx, inst->vpu.vsi, sizeof(inst->vsi_ctx)); + inst->vsi_ctx.dec.resolution_changed = true; + inst->vsi_ctx.dec.realloc_mv_buf = true; + + err = allocate_predication_buf(inst); + if (err) + goto error_deinit; + + mtk_vcodec_debug(inst, "struct size = %d,%d,%d,%d\n", + sizeof(struct mtk_h264_sps_param), + sizeof(struct mtk_h264_pps_param), + sizeof(struct mtk_h264_dec_slice_param), + sizeof(struct mtk_h264_dpb_info)); + + mtk_vcodec_debug(inst, "H264 Instance >> %p", inst); + + ctx->drv_handle = inst; + return 0; + +error_deinit: + vpu_dec_deinit(&inst->vpu); + +error_free_inst: + kfree(inst); + return err; +} + +static void vdec_h264_slice_deinit(void *h_vdec) +{ + struct vdec_h264_slice_inst *inst = + (struct vdec_h264_slice_inst *)h_vdec; + + mtk_vcodec_debug_enter(inst); + + vpu_dec_deinit(&inst->vpu); + free_predication_buf(inst); + free_mv_buf(inst); + + kfree(inst); +} + +static int 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; +} + +static int vdec_h264_slice_decode(void *h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg) +{ + struct vdec_h264_slice_inst *inst = + (struct vdec_h264_slice_inst *)h_vdec; + struct vdec_vpu_inst *vpu = &inst->vpu; + struct mtk_video_dec_buf *src_buf_info; + struct mtk_video_dec_buf *dst_buf_info; + int nal_start_idx = 0, err = 0; + uint32_t nal_type, data[2]; + unsigned char *buf; + uint64_t y_fb_dma; + uint64_t c_fb_dma; + + mtk_vcodec_debug(inst, "+ [%d] FB y_dma=%llx c_dma=%llx va=%p", + ++inst->num_nalu, y_fb_dma, c_fb_dma, fb); + + /* bs NULL means flush decoder */ + if (bs == NULL) + return vpu_dec_reset(vpu); + + 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; + + buf = (unsigned char *)bs->va; + nal_start_idx = find_start_code(buf, bs->size); + if (nal_start_idx < 0) + goto err_free_fb_out; + + data[0] = bs->size; + data[1] = buf[nal_start_idx]; + nal_type = NAL_TYPE(buf[nal_start_idx]); + mtk_vcodec_debug(inst, "\n + NALU[%d] type %d +\n", inst->num_nalu, + nal_type); + + 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; + + get_vdec_decode_parameters(inst); + *res_chg = inst->vsi_ctx.dec.resolution_changed; + if (*res_chg) { + mtk_vcodec_debug(inst, "- resolution changed -"); + if (inst->vsi_ctx.dec.realloc_mv_buf) { + err = alloc_mv_buf(inst, &(inst->ctx->picinfo)); + inst->vsi_ctx.dec.realloc_mv_buf = false; + if (err) + goto err_free_fb_out; + } + *res_chg = false; + } + + memcpy(inst->vpu.vsi, &inst->vsi_ctx, sizeof(inst->vsi_ctx)); + err = vpu_dec_start(vpu, data, 2); + if (err) + goto err_free_fb_out; + + if (nal_type == NAL_NON_IDR_SLICE || nal_type == NAL_IDR_SLICE) { + /* wait decoder done interrupt */ + err = mtk_vcodec_wait_for_done_ctx(inst->ctx, + MTK_INST_IRQ_RECEIVED, + WAIT_INTR_TIMEOUT_MS); + if (err) + goto err_free_fb_out; + + vpu_dec_end(vpu); + } + + memcpy(&inst->vsi_ctx, inst->vpu.vsi, sizeof(inst->vsi_ctx)); + mtk_vcodec_debug(inst, "\n - NALU[%d] type=%d -\n", inst->num_nalu, + nal_type); + return 0; + +err_free_fb_out: + mtk_vcodec_err(inst, "\n - NALU[%d] err=%d -\n", inst->num_nalu, err); + return err; +} + +static int vdec_h264_slice_get_param(void *h_vdec, + enum vdec_get_param_type type, void *out) +{ + struct vdec_h264_slice_inst *inst = + (struct vdec_h264_slice_inst *)h_vdec; + + switch (type) { + case GET_PARAM_PIC_INFO: + get_pic_info(inst, out); + break; + + case GET_PARAM_DPB_SIZE: + get_dpb_size(inst, out); + break; + + case GET_PARAM_CROP_INFO: + get_crop_info(inst, out); + break; + + default: + mtk_vcodec_err(inst, "invalid get parameter type=%d", type); + return -EINVAL; + } + + return 0; +} + +const struct vdec_common_if vdec_h264_slice_if = { + .init = vdec_h264_slice_init, + .decode = vdec_h264_slice_decode, + .get_param = vdec_h264_slice_get_param, + .deinit = vdec_h264_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 b18743b906ea..42008243ceac 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c @@ -19,6 +19,9 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) int ret = 0; switch (fourcc) { + case V4L2_PIX_FMT_H264_SLICE: + ctx->dec_if = &vdec_h264_slice_if; + break; case V4L2_PIX_FMT_H264: ctx->dec_if = &vdec_h264_if; break; diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h index 270d8dc9984b..961b2b6072b5 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h @@ -55,6 +55,7 @@ struct vdec_fb_node { }; extern const struct vdec_common_if vdec_h264_if; +extern const struct vdec_common_if vdec_h264_slice_if; extern const struct vdec_common_if vdec_vp8_if; extern const struct vdec_common_if vdec_vp9_if; From patchwork Tue Jun 30 06:27:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Courbot X-Patchwork-Id: 11633265 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 422EB138C for ; Tue, 30 Jun 2020 06:28:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 28E4220759 for ; Tue, 30 Jun 2020 06:28:11 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="NgxNazi/" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730296AbgF3G2K (ORCPT ); Tue, 30 Jun 2020 02:28:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35820 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730291AbgF3G2H (ORCPT ); Tue, 30 Jun 2020 02:28:07 -0400 Received: from mail-pf1-x441.google.com (mail-pf1-x441.google.com [IPv6:2607:f8b0:4864:20::441]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C3398C03E979 for ; Mon, 29 Jun 2020 23:28:07 -0700 (PDT) Received: by mail-pf1-x441.google.com with SMTP id f9so8987776pfn.0 for ; Mon, 29 Jun 2020 23:28:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=fI8HnXoHL36NipPIacNI9gsuTmN2YmF4x8kkOxnjHJM=; b=NgxNazi/4NDPHZazkyx72vObQoLThGuPLwjaDWkOz/me6q5ikQwO9toW9ubWJKpPz4 MAeQsnLtgzDJNq20N5wTPrTFydudGufvClwM7ODIDFm81qNGD5AKNBLJDNda4IjeNTzH 6jQ6PUVlksjmph6b9wW1UAGs3tNkWU68ujN1s= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=fI8HnXoHL36NipPIacNI9gsuTmN2YmF4x8kkOxnjHJM=; b=Ua+cBLJ9si8msiUiFUn4mD6UhlRMkA8Uc8zEwfvQZ1VN8D+aGhzixHPFkAG4zIjfVe 6SsrY4YDvD8cVkGOBhKWt7Aakub4UhGCeIVxEcfks+MlAOhDg00tH96QvRpLaGWUsVJY WezEHS/Sj0d9AYJJsZxkF4gmJxDBkaKZQNLAr3rLb6yEae58QuQgRsByCAQdq9dgI3eD ISEGjQnwYN2AHAon543+gIiYKDezQ+nHNJoBBgo0E6AVblGddPOiUZB4/dFvAiIRuSiu dGDMK6CwluDcHOMLHC0y0vt9dghJW/LkCermek43Ct4CQ8IIFyEGyX3NNjTvVTFVVMKC Uymg== X-Gm-Message-State: AOAM533H9go+kDo6w6KDfziuL3NvavLlWhOA7P4cPR/KcRYU/I6Wu1rq is+1+fnVTLpKBZ1g+SDo5ic8Vg== X-Google-Smtp-Source: ABdhPJyqQPQLx66yCaLhyl3uQCAVHiz7CJM/ZYhIR5tsBTwfptdnq5A03XpzQZFsy3TRMntZxzoPcg== X-Received: by 2002:aa7:9e5c:: with SMTP id z28mr5770994pfq.49.1593498487276; Mon, 29 Jun 2020 23:28:07 -0700 (PDT) Received: from acourbot.tok.corp.google.com ([2401:fa00:8f:203:93d9:de4d:e834:3086]) by smtp.gmail.com with ESMTPSA id d1sm1463366pfq.113.2020.06.29.23.28.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Jun 2020 23:28:06 -0700 (PDT) From: Alexandre Courbot To: Tiffany Lin , Andrew-CT Chen , Rui Wang , Yunfei Dong , Pi-Hsun Shih , Maoguang Meng Cc: linux-media@vger.kernel.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, Alexandre Courbot Subject: [PATCH 7/9] media: mtk-vcodec: vdec: add media device if using stateless api Date: Tue, 30 Jun 2020 15:27:09 +0900 Message-Id: <20200630062711.4169601-8-acourbot@chromium.org> X-Mailer: git-send-email 2.27.0.212.ge8ba1cc988-goog In-Reply-To: <20200630062711.4169601-1-acourbot@chromium.org> References: <20200630062711.4169601-1-acourbot@chromium.org> MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org From: Yunfei Dong The stateless API requires a media device for issuing requests. Add one if we are being instantiated as a stateless decoder. Signed-off-by: Yunfei Dong [acourbot: refactor, cleanup and split] Co-developed-by: Alexandre Courbot Signed-off-by: Alexandre Courbot --- drivers/media/platform/Kconfig | 1 + .../platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 39 +++++++++++++++++++ .../platform/mtk-vcodec/mtk_vcodec_drv.h | 2 + 3 files changed, 42 insertions(+) diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index ff77c6db55db..cb5ffb98dc09 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -258,6 +258,7 @@ config VIDEO_MEDIATEK_VCODEC select V4L2_H264 select VIDEO_MEDIATEK_VPU select MTK_SCP + select MEDIA_CONTROLLER help Mediatek video codec driver provides HW capability to encode and decode in a range of video formats 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 3d8eaf0746c2..e723f8573322 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "mtk_vcodec_drv.h" #include "mtk_vcodec_dec.h" @@ -322,6 +323,31 @@ static int mtk_vcodec_probe(struct platform_device *pdev) goto err_event_workq; } + if (dev->vdec_pdata->uses_stateless_api) { + dev->mdev_dec.dev = &pdev->dev; + strscpy(dev->mdev_dec.model, MTK_VCODEC_DEC_NAME, + sizeof(dev->mdev_dec.model)); + + media_device_init(&dev->mdev_dec); + dev->mdev_dec.ops = &mtk_vcodec_media_ops; + dev->v4l2_dev.mdev = &dev->mdev_dec; + + ret = v4l2_m2m_register_media_controller(dev->m2m_dev_dec, + dev->vfd_dec, MEDIA_ENT_F_PROC_VIDEO_DECODER); + if (ret) { + mtk_v4l2_err("Failed to register media controller"); + goto err_reg_cont; + } + + ret = media_device_register(&dev->mdev_dec); + if (ret) { + mtk_v4l2_err("Failed to register media device"); + goto err_media_reg; + } + + mtk_v4l2_debug(0, "media registered as /dev/media%d", + vfd_dec->num); + } ret = video_register_device(vfd_dec, VFL_TYPE_VIDEO, 0); if (ret) { mtk_v4l2_err("Failed to register video device"); @@ -334,6 +360,12 @@ static int mtk_vcodec_probe(struct platform_device *pdev) return 0; err_dec_reg: + if (dev->vdec_pdata->uses_stateless_api) + media_device_unregister(&dev->mdev_dec); +err_media_reg: + if (dev->vdec_pdata->uses_stateless_api) + v4l2_m2m_unregister_media_controller(dev->m2m_dev_dec); +err_reg_cont: destroy_workqueue(dev->decode_workqueue); err_event_workq: v4l2_m2m_release(dev->m2m_dev_dec); @@ -366,6 +398,13 @@ static int mtk_vcodec_dec_remove(struct platform_device *pdev) flush_workqueue(dev->decode_workqueue); destroy_workqueue(dev->decode_workqueue); + + if (media_devnode_is_registered(dev->mdev_dec.devnode)) { + media_device_unregister(&dev->mdev_dec); + v4l2_m2m_unregister_media_controller(dev->m2m_dev_dec); + media_device_cleanup(&dev->mdev_dec); + } + if (dev->m2m_dev_dec) v4l2_m2m_release(dev->m2m_dev_dec); diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index 755631d0fe92..7071434b5c5b 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -382,6 +382,7 @@ struct mtk_vcodec_enc_pdata { * struct mtk_vcodec_dev - driver data * @v4l2_dev: V4L2 device to register video devices for. * @vfd_dec: Video device for decoder + * @mdev_dec: Media device for decoder * @vfd_enc: Video device for encoder. * * @m2m_dev_dec: m2m device for decoder @@ -418,6 +419,7 @@ struct mtk_vcodec_enc_pdata { struct mtk_vcodec_dev { struct v4l2_device v4l2_dev; struct video_device *vfd_dec; + struct media_device mdev_dec; struct video_device *vfd_enc; struct v4l2_m2m_dev *m2m_dev_dec; From patchwork Tue Jun 30 06:27:10 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Courbot X-Patchwork-Id: 11633283 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1DF07138C for ; Tue, 30 Jun 2020 06:28:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 05F4020759 for ; Tue, 30 Jun 2020 06:28:30 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="M7C4kgCj" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730302AbgF3G22 (ORCPT ); Tue, 30 Jun 2020 02:28:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35834 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730164AbgF3G2L (ORCPT ); Tue, 30 Jun 2020 02:28:11 -0400 Received: from mail-pj1-x1044.google.com (mail-pj1-x1044.google.com [IPv6:2607:f8b0:4864:20::1044]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0E716C03E979 for ; Mon, 29 Jun 2020 23:28:11 -0700 (PDT) Received: by mail-pj1-x1044.google.com with SMTP id o22so3992035pjw.2 for ; Mon, 29 Jun 2020 23:28:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Vnusw8KVqmLccr+Bdv13JEwKXnPkBiMBiOXb/M8oVMY=; b=M7C4kgCjEpA50jHKkWe85wOubmGWK8xwuqsTPKt+wHoE27ZCA1qckzlDHJCq6NmChV KvWaoJiBVO6rhLrZB3uImVw8sLEznZpDoVqfqGNaBJOJAdDs9ar2ahNJ9OQ4Biu0mBG+ tYRqQeUuhqnHrVQCowSF6tPkhBpUrdmQIfI3Y= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Vnusw8KVqmLccr+Bdv13JEwKXnPkBiMBiOXb/M8oVMY=; b=LL5PDtpmwG2TqT4SrCWolSvGozBStUi12j1DvU8+8C0ge/4sTIyIXv7b3X2ZNdtxPo pULDEE9leqvi+hASVVFI1CQ/T7q1HGLtJ7Likxj8dwQM5Q+6UHmw95KSicxqrkEGedQj rVt5N5wVBNSDmZ1mjksvnulfRJIJ0wn3fyjf4suTBRzjrSOicOyuWRzXl2htrVuL/EdO bRUFZJe8AiXZWFmvYOSQC57pAFbDCg+HjchLUuLU8agzzxyA1p328QQkJ52rmtIl5Kct xBPi5fczedAO7XA5FgO87H2b6VCtDDdqsP/zG02Cl9dII81a7tkqi4A7hiKEB5PKctNZ Godw== X-Gm-Message-State: AOAM533IYJnyiXitXRK83jJXv3Dgum07yIGtCdA5lbwemOLMZruw+fxB nHzXQMOfUYmBzKBjb1oAE4M/qg== X-Google-Smtp-Source: ABdhPJw8i9JTTps6ZptKXBHaxLspml/Eo/P9js2FIrue/Tbn2dxpRndQnCqSmtPZXoqxK5wFrl9TUg== X-Received: by 2002:a17:90a:70c6:: with SMTP id a6mr19142972pjm.16.1593498490609; Mon, 29 Jun 2020 23:28:10 -0700 (PDT) Received: from acourbot.tok.corp.google.com ([2401:fa00:8f:203:93d9:de4d:e834:3086]) by smtp.gmail.com with ESMTPSA id d1sm1463366pfq.113.2020.06.29.23.28.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Jun 2020 23:28:09 -0700 (PDT) From: Alexandre Courbot To: Tiffany Lin , Andrew-CT Chen , Rui Wang , Yunfei Dong , Pi-Hsun Shih , Maoguang Meng Cc: linux-media@vger.kernel.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, Alexandre Courbot Subject: [PATCH 8/9] media: mtk-vcodec: enable MT8183 decoder Date: Tue, 30 Jun 2020 15:27:10 +0900 Message-Id: <20200630062711.4169601-9-acourbot@chromium.org> X-Mailer: git-send-email 2.27.0.212.ge8ba1cc988-goog In-Reply-To: <20200630062711.4169601-1-acourbot@chromium.org> References: <20200630062711.4169601-1-acourbot@chromium.org> MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org From: Yunfei Dong Now that all the supporting blocks are present, enable decoder for MT8183. Signed-off-by: Yunfei Dong [acourbot: refactor, cleanup and split] Co-developed-by: Alexandre Courbot Signed-off-by: Alexandre Courbot --- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 5 +++++ 1 file changed, 5 insertions(+) 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 e723f8573322..e7d90973e626 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c @@ -381,12 +381,17 @@ static int mtk_vcodec_probe(struct platform_device *pdev) } extern const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata; +extern const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata; static const struct of_device_id mtk_vcodec_match[] = { { .compatible = "mediatek,mt8173-vcodec-dec", .data = &mtk_vdec_8173_pdata, }, + { + .compatible = "mediatek,mt8183-vcodec-dec", + .data = &mtk_vdec_8183_pdata, + }, {}, }; From patchwork Tue Jun 30 06:27:11 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Courbot X-Patchwork-Id: 11633269 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id EC42D92A for ; Tue, 30 Jun 2020 06:28:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D504E20672 for ; Tue, 30 Jun 2020 06:28:18 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="lsjiIug4" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730321AbgF3G2Q (ORCPT ); Tue, 30 Jun 2020 02:28:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35842 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730292AbgF3G2O (ORCPT ); Tue, 30 Jun 2020 02:28:14 -0400 Received: from mail-pf1-x441.google.com (mail-pf1-x441.google.com [IPv6:2607:f8b0:4864:20::441]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 11320C061755 for ; Mon, 29 Jun 2020 23:28:14 -0700 (PDT) Received: by mail-pf1-x441.google.com with SMTP id 67so4905710pfg.5 for ; Mon, 29 Jun 2020 23:28:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=WrH62sNOsIyA+bZUWvdaT8mtXVgNLKJ4Ma1LMcNUAKU=; b=lsjiIug4X6wJnLGMoqdnf2EtlRQdyHztqYifj+F9DWxMaUDWjC6VtcPJIP78h0kPu1 KmgKxbrCDYhjm7+oQxOXI8pq0zvO3C6GktlJ4Th7zd1Zs3SF0kSjfa05rZ5kXqTVDJtP SfRHve4FD0yo4vE1OSWND44Ixw6FZ9l9ufmSc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=WrH62sNOsIyA+bZUWvdaT8mtXVgNLKJ4Ma1LMcNUAKU=; b=D3WY00PuivGU5wetpCpPd3nXa3q1Y7quGIUrqO8NueGQW9vHtOPiWeWgQZqRPuBH0p 70rQtZCNpaIjRfffyzV7b4CxWnDXZJTnWpYOtmhYUH6RZkBIkqLdEqZ1EMggiZFCOAWL L0i8UMDDV5Ryp2/MTFOW6IA+SEPQxjLzrPYXK8MvrH3hkFjJETXQJeGcZ4zlygcABu4G E0zs8dJmsJ4Ub3dHgtNTd6WQwCbkfdpbGxe7GpGSdIe3rozc6Wsxuy9EBIvC6Ej+7hoZ Xuc4UTnxZTxJpgSbx7SCkXHJoLKxhMz9pmcLUTfjHZ8ESunA1hqOWa6FQWC5w6Xgw4Vt xbIQ== X-Gm-Message-State: AOAM532eU5AyqGlMUFLw5SurzD0q2XCIboZ0FNSnFc+GG1ygSbcQQMq6 OYBr3xCJyAfTlWOoCjBkeBv7aw== X-Google-Smtp-Source: ABdhPJz3j1bYUqaPRUaPXgTjd0S72OVpblIcbiEiGszIAsdQ2p3a/yRuBNlTRr46ige0lND/m0u8rA== X-Received: by 2002:a05:6a00:1511:: with SMTP id q17mr17923876pfu.16.1593498493649; Mon, 29 Jun 2020 23:28:13 -0700 (PDT) Received: from acourbot.tok.corp.google.com ([2401:fa00:8f:203:93d9:de4d:e834:3086]) by smtp.gmail.com with ESMTPSA id d1sm1463366pfq.113.2020.06.29.23.28.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Jun 2020 23:28:12 -0700 (PDT) From: Alexandre Courbot To: Tiffany Lin , Andrew-CT Chen , Rui Wang , Yunfei Dong , Pi-Hsun Shih , Maoguang Meng Cc: linux-media@vger.kernel.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, Alexandre Courbot Subject: [PATCH 9/9] dt-bindings: media: document mediatek,mt8183-vcodec-dec Date: Tue, 30 Jun 2020 15:27:11 +0900 Message-Id: <20200630062711.4169601-10-acourbot@chromium.org> X-Mailer: git-send-email 2.27.0.212.ge8ba1cc988-goog In-Reply-To: <20200630062711.4169601-1-acourbot@chromium.org> References: <20200630062711.4169601-1-acourbot@chromium.org> MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org MT8183's decoder is instantiated similarly to MT8173's. Signed-off-by: Alexandre Courbot --- Documentation/devicetree/bindings/media/mediatek-vcodec.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/media/mediatek-vcodec.txt b/Documentation/devicetree/bindings/media/mediatek-vcodec.txt index 8093335afecb..b844800e0153 100644 --- a/Documentation/devicetree/bindings/media/mediatek-vcodec.txt +++ b/Documentation/devicetree/bindings/media/mediatek-vcodec.txt @@ -7,6 +7,7 @@ Required properties: - compatible : "mediatek,mt8173-vcodec-enc" for MT8173 encoder "mediatek,mt8183-vcodec-enc" for MT8183 encoder. "mediatek,mt8173-vcodec-dec" for MT8173 decoder. + "mediatek,mt8183-vcodec-dec" for MT8183 decoder. - reg : Physical base address of the video codec registers and length of memory mapped region. - interrupts : interrupt number to the cpu.