From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 48498C87FDA for ; Fri, 8 Aug 2025 20:22:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=YIqC7ZRrzcGbjBM44+Tht5sd1VZlYdGA+gGMr6w3QpE=; b=HhN108Lpemrw8G mYJxMBoKFKClNQ7kt5F+Dp6JWjhX66lnAqT8m7mHOdXjxjH9creZ+yK+x5WCuC3aYDaEh5ZURtaZ1 EhRfu8Xvh2AUZ6BXSeIVeIs813uvmonZGYWNTe1LnBA9xr+bGvtKyLMb+8oveNT2XJcpANPwnvwRA wtBMZ2m0ZsHPn9YesMCdRRpxmUbwQv3kbXZ9AZKrEGLTqe5FdEcBNM7PRA4wKqpbORC7m2c0X6OwG xXulpbknuZx5W8oY/JFxGovKNlarponBxj/gM7ofa3NJ6biZo6AnxkB23guXeXcu8p0Cr35SLdqyL 2/8bsg3h/d6c8nFjnRog==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux)) id 1ukTbD-00000003cKK-3uMS; Fri, 08 Aug 2025 20:21:59 +0000 Received: from bali.collaboradmins.com ([2a01:4f8:201:9162::2]) by bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux)) id 1ukTJl-00000003a8B-2s1R; Fri, 08 Aug 2025 20:03:59 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1754683436; bh=YrvUtegmo23fxwFf79xVFdziS5YscXEdSSJGPLuYr6k=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VIULNBAmi1UWAN84xlqiSUIeObKgnU+OT1+7+Femq3kY4Fp3wumyfWaFOGSWRsccl B+PM3wKIdW5bqJi8ICve2U3DJnoYBjgmYYRRg/m6HA21UAVnghrfUMqZNtJpsPT0/U zKRwC5xYWnFbgdDvT7TyibKbjDvWYWAtUBbG2XfDiInOJuxp47RBe62cG+jYzcupB/ mq/XE00vsWBOtSH1gqLKMqsErOX2NMXSMCqM8EyHJ3jQPtISrQFLb+tMM3DDT6rmki cMWU+WEX6OrP4iG1Y37KjCYggF0R+tuXlDET6xIWNWqMd3tJtypOo6YJcWi9nE5hoJ DXEs4SKrkOkdQ== Received: from earth.mtl.collabora.ca (mtl.collabora.ca [66.171.169.34]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: detlev) by bali.collaboradmins.com (Postfix) with ESMTPSA id 4508C17E1322; Fri, 8 Aug 2025 22:03:55 +0200 (CEST) From: Detlev Casanova To: linux-kernel@vger.kernel.org Cc: Detlev Casanova , Mauro Carvalho Chehab , Heiko Stuebner , linux-media@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com Subject: [PATCH v2 06/12] media: rkvdec: Add RCB and SRAM support Date: Fri, 8 Aug 2025 16:03:28 -0400 Message-ID: <20250808200340.156393-7-detlev.casanova@collabora.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20250808200340.156393-1-detlev.casanova@collabora.com> References: <20250808200340.156393-1-detlev.casanova@collabora.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250808_130357_872095_EBAB6DA5 X-CRM114-Status: GOOD ( 28.62 ) X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+linux-rockchip=archiver.kernel.org@lists.infradead.org The RCB (Rows and Cols Buffers) are a set of buffers used by other variations of the decoder to store temporary data. Those variation come with a dedicated SRAM area used to store those buffers for better performances. The buffer sizes are either the width or height of the frame being decoded multiplied by a documented factor and can be stored either in SRAM or RAM. A fallback to RAM is provided if the SRAM is full (e.g.: multiple streams are being decoded at the same time). To manage the different kind of allocation, an enum is added to the rkvdec_aux_buf struct to specify how the buffer was allocated, and so, how to free it. This commit is in preparation of other variants support. Signed-off-by: Detlev Casanova --- .../media/platform/rockchip/rkvdec/Makefile | 1 + .../platform/rockchip/rkvdec/rkvdec-rcb.c | 174 ++++++++++++++++++ .../platform/rockchip/rkvdec/rkvdec-rcb.h | 29 +++ .../media/platform/rockchip/rkvdec/rkvdec.c | 29 ++- .../media/platform/rockchip/rkvdec/rkvdec.h | 13 ++ 5 files changed, 242 insertions(+), 4 deletions(-) create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile index 94c067084acd1..2b7ba9f7de286 100644 --- a/drivers/media/platform/rockchip/rkvdec/Makefile +++ b/drivers/media/platform/rockchip/rkvdec/Makefile @@ -5,4 +5,5 @@ rockchip-vdec-y += \ rkvdec-cabac.o \ rkvdec-h264.o \ rkvdec-h264-common.o \ + rkvdec-rcb.o \ rkvdec-vp9.o diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c new file mode 100644 index 0000000000000..210e59db2c622 --- /dev/null +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Rockchip video decoder Rows and Cols Buffers manager + * + * Copyright (C) 2025 Collabora, Ltd. + * Detlev Casanova + */ + +#include "rkvdec.h" +#include "rkvdec-rcb.h" + +#include +#include +#include + +struct rkvdec_rcb_config { + struct rkvdec_aux_buf *rcb_bufs; + size_t rcb_count; +}; + +static size_t rkvdec_rcb_size(const struct rcb_size_info *size_info, + unsigned int width, unsigned int height) +{ + return size_info->multiplier * (size_info->axis == PIC_HEIGHT ? height : width); +} + +dma_addr_t rkvdec_rcb_buf_dma_addr(struct rkvdec_ctx *ctx, int id) +{ + return ctx->rcb_config->rcb_bufs[id].dma; +} + +size_t rkvdec_rcb_buf_size(struct rkvdec_ctx *ctx, int id) +{ + return ctx->rcb_config->rcb_bufs[id].size; +} + +int rkvdec_rcb_buf_count(struct rkvdec_ctx *ctx) +{ + return ctx->rcb_config->rcb_count; +} + +void rkvdec_free_rcb(struct rkvdec_ctx *ctx) +{ + struct rkvdec_dev *dev = ctx->dev; + struct rkvdec_rcb_config *cfg = ctx->rcb_config; + unsigned long virt_addr; + int i; + + if (!cfg) + return; + + for (i = 0; i < cfg->rcb_count; i++) { + size_t rcb_size = cfg->rcb_bufs[i].size; + + if (!cfg->rcb_bufs[i].cpu) + continue; + + switch (cfg->rcb_bufs[i].type) { + case RKVDEC2_ALLOC_SRAM: + virt_addr = (unsigned long)cfg->rcb_bufs[i].cpu; + + if (dev->iommu_domain) + iommu_unmap(dev->iommu_domain, virt_addr, rcb_size); + gen_pool_free(dev->sram_pool, virt_addr, rcb_size); + break; + case RKVDEC2_ALLOC_DMA: + dma_free_coherent(dev->dev, + rcb_size, + cfg->rcb_bufs[i].cpu, + cfg->rcb_bufs[i].dma); + break; + } + } + + if (cfg->rcb_bufs) + devm_kfree(dev->dev, cfg->rcb_bufs); + + devm_kfree(dev->dev, cfg); +} + +int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx, + const struct rcb_size_info *size_info, + size_t rcb_count) +{ + int ret, i; + u32 width, height; + struct rkvdec_dev *rkvdec = ctx->dev; + struct rkvdec_rcb_config *cfg; + + ctx->rcb_config = devm_kzalloc(rkvdec->dev, sizeof(*ctx->rcb_config), GFP_KERNEL); + if (!ctx->rcb_config) + return -ENOMEM; + + cfg = ctx->rcb_config; + + cfg->rcb_bufs = devm_kzalloc(rkvdec->dev, sizeof(*cfg->rcb_bufs) * rcb_count, GFP_KERNEL); + if (!cfg->rcb_bufs) { + ret = -ENOMEM; + goto err_alloc; + } + + width = ctx->decoded_fmt.fmt.pix_mp.width; + height = ctx->decoded_fmt.fmt.pix_mp.height; + + for (i = 0; i < rcb_count; i++) { + void *cpu = NULL; + dma_addr_t dma; + size_t rcb_size = rkvdec_rcb_size(&size_info[i], width, height); + enum rkvdec_alloc_type alloc_type = RKVDEC2_ALLOC_SRAM; + + /* Try allocating an SRAM buffer */ + if (ctx->dev->sram_pool) { + if (rkvdec->iommu_domain) + rcb_size = ALIGN(rcb_size, 0x1000); + + cpu = gen_pool_dma_zalloc_align(ctx->dev->sram_pool, + rcb_size, + &dma, + 0x1000); + } + + /* If an IOMMU is used, map the SRAM address through it */ + if (cpu && rkvdec->iommu_domain) { + unsigned long virt_addr = (unsigned long)cpu; + phys_addr_t phys_addr = dma; + + ret = iommu_map(rkvdec->iommu_domain, virt_addr, phys_addr, + rcb_size, IOMMU_READ | IOMMU_WRITE, 0); + if (ret) { + gen_pool_free(ctx->dev->sram_pool, + (unsigned long)cpu, + rcb_size); + cpu = NULL; + goto ram_fallback; + } + + /* + * The registers will be configured with the virtual + * address so that it goes through the IOMMU + */ + dma = virt_addr; + } + +ram_fallback: + /* Fallback to RAM */ + if (!cpu) { + cpu = dma_alloc_coherent(ctx->dev->dev, + rcb_size, + &dma, + GFP_KERNEL); + alloc_type = RKVDEC2_ALLOC_DMA; + } + + if (!cpu) { + ret = -ENOMEM; + goto err_alloc; + } + + cfg->rcb_bufs[i].cpu = cpu; + cfg->rcb_bufs[i].dma = dma; + cfg->rcb_bufs[i].size = rcb_size; + cfg->rcb_bufs[i].type = alloc_type; + + cfg->rcb_count += 1; + } + + return 0; + +err_alloc: + rkvdec_free_rcb(ctx); + + return ret; +} + diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h new file mode 100644 index 0000000000000..30e8002555c8a --- /dev/null +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Rockchip video decoder Rows and Cols Buffers manager + * + * Copyright (C) 2025 Collabora, Ltd. + * Detlev Casanova + */ + +#include + +struct rkvdec_ctx; + +enum rcb_axis { + PIC_WIDTH = 0, + PIC_HEIGHT = 1 +}; + +struct rcb_size_info { + u8 multiplier; + enum rcb_axis axis; +}; + +int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx, + const struct rcb_size_info *size_info, + size_t rcb_count); +dma_addr_t rkvdec_rcb_buf_dma_addr(struct rkvdec_ctx *ctx, int id); +size_t rkvdec_rcb_buf_size(struct rkvdec_ctx *ctx, int id); +int rkvdec_rcb_buf_count(struct rkvdec_ctx *ctx); +void rkvdec_free_rcb(struct rkvdec_ctx *ctx); diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c index 28585522523c7..2602676a047a1 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -27,6 +28,7 @@ #include "rkvdec.h" #include "rkvdec-regs.h" +#include "rkvdec-rcb.h" static bool rkvdec_image_fmt_match(enum rkvdec_image_fmt fmt1, enum rkvdec_image_fmt fmt2) @@ -668,6 +670,7 @@ static int rkvdec_start_streaming(struct vb2_queue *q, unsigned int count) { struct rkvdec_ctx *ctx = vb2_get_drv_priv(q); const struct rkvdec_coded_fmt_desc *desc; + struct rkvdec_config *cfg = ctx->dev->config; int ret; if (V4L2_TYPE_IS_CAPTURE(q->type)) @@ -677,13 +680,22 @@ static int rkvdec_start_streaming(struct vb2_queue *q, unsigned int count) if (WARN_ON(!desc)) return -EINVAL; + ret = rkvdec_allocate_rcb(ctx, cfg->rcb_size_info, cfg->rcb_num); + if (ret) + return ret; + if (desc->ops->start) { ret = desc->ops->start(ctx); if (ret) - return ret; + goto err_ops_start; } return 0; + +err_ops_start: + rkvdec_free_rcb(ctx); + + return ret; } static void rkvdec_queue_cleanup(struct vb2_queue *vq, u32 state) @@ -719,6 +731,8 @@ static void rkvdec_stop_streaming(struct vb2_queue *q) if (desc->ops->stop) desc->ops->stop(ctx); + + rkvdec_free_rcb(ctx); } rkvdec_queue_cleanup(q, VB2_BUF_STATE_ERROR); @@ -1183,15 +1197,14 @@ static int rkvdec_probe(struct platform_device *pdev) return ret; } - if (iommu_get_domain_for_dev(&pdev->dev)) { + rkvdec->iommu_domain = iommu_get_domain_for_dev(&pdev->dev); + if (rkvdec->iommu_domain) { rkvdec->empty_domain = iommu_paging_domain_alloc(rkvdec->dev); if (!rkvdec->empty_domain) dev_warn(rkvdec->dev, "cannot alloc new empty domain\n"); } - vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); - irq = platform_get_irq(pdev, 0); if (irq <= 0) return -ENXIO; @@ -1204,6 +1217,10 @@ static int rkvdec_probe(struct platform_device *pdev) return ret; } + rkvdec->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0); + if (!rkvdec->sram_pool && rkvdec->config->rcb_num > 0) + dev_info(&pdev->dev, "No sram node, RCB will be stored in RAM\n"); + pm_runtime_set_autosuspend_delay(&pdev->dev, 100); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); @@ -1217,6 +1234,10 @@ static int rkvdec_probe(struct platform_device *pdev) err_disable_runtime_pm: pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_disable(&pdev->dev); + + if (rkvdec->sram_pool) + gen_pool_destroy(rkvdec->sram_pool); + return ret; } diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h index 14717c646c665..3a073883d21eb 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h @@ -19,10 +19,12 @@ #include #include #include +#include #include #include struct rkvdec_ctx; +struct rkvdec_rcb_config; struct rkvdec_ctrl_desc { struct v4l2_ctrl_config cfg; @@ -103,6 +105,8 @@ struct rkvdec_coded_fmt_desc { struct rkvdec_config { struct rkvdec_coded_fmt_desc *coded_fmts; size_t coded_fmts_num; + struct rcb_size_info *rcb_size_info; + size_t rcb_num; }; struct rkvdec_dev { @@ -115,6 +119,8 @@ struct rkvdec_dev { void __iomem *regs; struct mutex vdev_lock; /* serializes ioctls */ struct delayed_work watchdog_work; + struct gen_pool *sram_pool; + struct iommu_domain *iommu_domain; struct iommu_domain *empty_domain; struct rkvdec_config *config; }; @@ -127,6 +133,7 @@ struct rkvdec_ctx { struct v4l2_ctrl_handler ctrl_hdl; struct rkvdec_dev *dev; enum rkvdec_image_fmt image_fmt; + struct rkvdec_rcb_config *rcb_config; void *priv; }; @@ -135,10 +142,16 @@ static inline struct rkvdec_ctx *fh_to_rkvdec_ctx(struct v4l2_fh *fh) return container_of(fh, struct rkvdec_ctx, fh); } +enum rkvdec_alloc_type { + RKVDEC2_ALLOC_DMA = 0, + RKVDEC2_ALLOC_SRAM = 1, +}; + struct rkvdec_aux_buf { void *cpu; dma_addr_t dma; size_t size; + enum rkvdec_alloc_type type; }; void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run); -- 2.50.1 _______________________________________________ Linux-rockchip mailing list Linux-rockchip@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-rockchip