From nobody Sat Feb 7 16:26:24 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4417E426D22; Tue, 20 Jan 2026 22:21:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768947669; cv=none; b=qi3ujTS18s5qvj+5puN74G+niIZp/dqVrDI/H88g2ifo5zSFMu/HvU//HQh0M8jW1TX1HInYWG7lPqDcjA5Icp/83nidNvF1Bmk6L4khhH1CHod2/tT1PnOgYR7czkMsvus5pw73LeAd924ZJDYAJMUYSs3ygK98a8sZBNHybBc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768947669; c=relaxed/simple; bh=DLIxYBS94BOwjjRYUMCC/2rCFMOROJD30xpgJKl14ms=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LwJYetuk75bU14ousb2J0p4ClsbDSwKJWO4L7QKJTe44nJexIUvsjY9vp3TELDKFRQXt8At0M24aRCi66oup9iZ4i7ygphzQOn00qpRyDShqh3SLQ6GlZftVACMjNItbEH1sVe+s+PAM0rxnOOiFoRBOn3NaZNGXLQcpaQ6dDzY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=hzLDutC2; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="hzLDutC2" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1768947661; bh=DLIxYBS94BOwjjRYUMCC/2rCFMOROJD30xpgJKl14ms=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=hzLDutC2byJ4v47L8te94udWMRiL/crv/Lu+jlFXx7oQ4MLLnNTquDJ3np8+IPGlp FkHwuDnhbpKJNiAEdxKhWInd1uslL9fx4W1T5cW8iV0pdDpMl6mZY5LeIp7umrxlm5 J8revA+fMPvbUlEDPLqrQ/74603RZIxD81fRYdkO6NqjQ88gaOTDIw4kA+YpdL9l6d 3AjqI7iflumOkFV/U/D4x4YNxGCN9tggXyb6ab7qPZA6se8lfN9pSMLe/SyMmULUds 4QvBhVGVV6MMxexKRYwqrlmX7tsQ8y4q2w8zF+XTUR07TCgN1SkUySBdBb3hj0w106 iQtBV6SBX8E2A== 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 960D417E1513; Tue, 20 Jan 2026 23:20:57 +0100 (CET) From: Detlev Casanova To: linux-kernel@vger.kernel.org Cc: Mauro Carvalho Chehab , Detlev Casanova , Ezequiel Garcia , Heiko Stuebner , Daniel Almeida , Jonathan Corbet , Ricardo Ribalda , Hans Verkuil , Yunke Cao , Hans de Goede , Laurent Pinchart , Nicolas Dufresne , Pavan Bobba , Sakari Ailus , James Cowgill , linux-media@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Jonas Karlman , Diederik de Haas Subject: [PATCH v9 10/17] media: rkvdec: Add RCB and SRAM support Date: Tue, 20 Jan 2026 17:20:10 -0500 Message-ID: <20260120222018.404741-11-detlev.casanova@collabora.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260120222018.404741-1-detlev.casanova@collabora.com> References: <20260120222018.404741-1-detlev.casanova@collabora.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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. Tested-by: Diederik de Haas # Rock 5B Reviewed-by: Nicolas Dufresne Signed-off-by: Detlev Casanova --- .../media/platform/rockchip/rkvdec/Makefile | 1 + .../platform/rockchip/rkvdec/rkvdec-rcb.c | 179 ++++++++++++++++++ .../platform/rockchip/rkvdec/rkvdec-rcb.h | 29 +++ .../media/platform/rockchip/rkvdec/rkvdec.c | 27 ++- .../media/platform/rockchip/rkvdec/rkvdec.h | 13 ++ 5 files changed, 247 insertions(+), 2 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/medi= a/platform/rockchip/rkvdec/Makefile index 1b4bc44be23ee..3d75103e536d2 100644 --- a/drivers/media/platform/rockchip/rkvdec/Makefile +++ b/drivers/media/platform/rockchip/rkvdec/Makefile @@ -7,4 +7,5 @@ rockchip-vdec-y +=3D \ rkvdec-h264-common.o \ rkvdec-hevc.o \ rkvdec-hevc-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..fdcf1f1773797 --- /dev/null +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c @@ -0,0 +1,179 @@ +// 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 +#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 =3D=3D PIC_HEIGHT ? heigh= t : 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 =3D ctx->dev; + struct rkvdec_rcb_config *cfg =3D ctx->rcb_config; + unsigned long virt_addr; + int i; + + if (!cfg) + return; + + for (i =3D 0; i < cfg->rcb_count; i++) { + size_t rcb_size =3D cfg->rcb_bufs[i].size; + + if (!cfg->rcb_bufs[i].cpu) + continue; + + switch (cfg->rcb_bufs[i].type) { + case RKVDEC_ALLOC_SRAM: + virt_addr =3D (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 RKVDEC_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 =3D ctx->dev; + struct rkvdec_rcb_config *cfg; + + if (!size_info || !rcb_count) { + ctx->rcb_config =3D NULL; + return 0; + } + + ctx->rcb_config =3D devm_kzalloc(rkvdec->dev, sizeof(*ctx->rcb_config), G= FP_KERNEL); + if (!ctx->rcb_config) + return -ENOMEM; + + cfg =3D ctx->rcb_config; + + cfg->rcb_bufs =3D devm_kzalloc(rkvdec->dev, sizeof(*cfg->rcb_bufs) * rcb_= count, GFP_KERNEL); + if (!cfg->rcb_bufs) { + ret =3D -ENOMEM; + goto err_alloc; + } + + width =3D ctx->decoded_fmt.fmt.pix_mp.width; + height =3D ctx->decoded_fmt.fmt.pix_mp.height; + + for (i =3D 0; i < rcb_count; i++) { + void *cpu =3D NULL; + dma_addr_t dma; + size_t rcb_size =3D rkvdec_rcb_size(&size_info[i], width, height); + enum rkvdec_alloc_type alloc_type =3D RKVDEC_ALLOC_SRAM; + + /* Try allocating an SRAM buffer */ + if (ctx->dev->sram_pool) { + if (rkvdec->iommu_domain) + rcb_size =3D ALIGN(rcb_size, SZ_4K); + + cpu =3D gen_pool_dma_zalloc_align(ctx->dev->sram_pool, + rcb_size, + &dma, + SZ_4K); + } + + /* If an IOMMU is used, map the SRAM address through it */ + if (cpu && rkvdec->iommu_domain) { + unsigned long virt_addr =3D (unsigned long)cpu; + phys_addr_t phys_addr =3D dma; + + ret =3D 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 =3D NULL; + goto ram_fallback; + } + + /* + * The registers will be configured with the virtual + * address so that it goes through the IOMMU + */ + dma =3D virt_addr; + } + +ram_fallback: + /* Fallback to RAM */ + if (!cpu) { + cpu =3D dma_alloc_coherent(ctx->dev->dev, + rcb_size, + &dma, + GFP_KERNEL); + alloc_type =3D RKVDEC_ALLOC_DMA; + } + + if (!cpu) { + ret =3D -ENOMEM; + goto err_alloc; + } + + cfg->rcb_bufs[i].cpu =3D cpu; + cfg->rcb_bufs[i].dma =3D dma; + cfg->rcb_bufs[i].size =3D rcb_size; + cfg->rcb_bufs[i].type =3D alloc_type; + + cfg->rcb_count +=3D 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 =3D 0, + PIC_HEIGHT =3D 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/medi= a/platform/rockchip/rkvdec/rkvdec.c index 92b1c7b62bd20..ff6a09e45462e 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c @@ -10,6 +10,7 @@ */ =20 #include +#include #include #include #include @@ -28,6 +29,7 @@ =20 #include "rkvdec.h" #include "rkvdec-regs.h" +#include "rkvdec-rcb.h" =20 static bool rkvdec_image_fmt_match(enum rkvdec_image_fmt fmt1, enum rkvdec_image_fmt fmt2) @@ -778,6 +780,7 @@ static int rkvdec_start_streaming(struct vb2_queue *q, = unsigned int count) { struct rkvdec_ctx *ctx =3D vb2_get_drv_priv(q); const struct rkvdec_coded_fmt_desc *desc; + const struct rkvdec_variant *variant =3D ctx->dev->variant; int ret; =20 if (V4L2_TYPE_IS_CAPTURE(q->type)) @@ -787,13 +790,22 @@ static int rkvdec_start_streaming(struct vb2_queue *q= , unsigned int count) if (WARN_ON(!desc)) return -EINVAL; =20 + ret =3D rkvdec_allocate_rcb(ctx, variant->rcb_sizes, variant->num_rcb_siz= es); + if (ret) + return ret; + if (desc->ops->start) { ret =3D desc->ops->start(ctx); if (ret) - return ret; + goto err_ops_start; } =20 return 0; + +err_ops_start: + rkvdec_free_rcb(ctx); + + return ret; } =20 static void rkvdec_queue_cleanup(struct vb2_queue *vq, u32 state) @@ -829,6 +841,8 @@ static void rkvdec_stop_streaming(struct vb2_queue *q) =20 if (desc->ops->stop) desc->ops->stop(ctx); + + rkvdec_free_rcb(ctx); } =20 rkvdec_queue_cleanup(q, VB2_BUF_STATE_ERROR); @@ -1345,6 +1359,10 @@ static int rkvdec_probe(struct platform_device *pdev) return ret; } =20 + rkvdec->sram_pool =3D of_gen_pool_get(pdev->dev.of_node, "sram", 0); + if (!rkvdec->sram_pool && rkvdec->variant->num_rcb_sizes > 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); @@ -1353,7 +1371,8 @@ static int rkvdec_probe(struct platform_device *pdev) if (ret) goto err_disable_runtime_pm; =20 - if (iommu_get_domain_for_dev(&pdev->dev)) { + rkvdec->iommu_domain =3D iommu_get_domain_for_dev(&pdev->dev); + if (rkvdec->iommu_domain) { rkvdec->empty_domain =3D iommu_paging_domain_alloc(rkvdec->dev); =20 if (IS_ERR(rkvdec->empty_domain)) { @@ -1367,6 +1386,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; } =20 diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/medi= a/platform/rockchip/rkvdec/rkvdec.h index 8c4f96ba5cdea..751f39afe7e2d 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h @@ -19,12 +19,14 @@ #include #include #include +#include #include #include =20 #define RKVDEC_QUIRK_DISABLE_QOS BIT(0) =20 struct rkvdec_ctx; +struct rkvdec_rcb_config; =20 struct rkvdec_ctrl_desc { struct v4l2_ctrl_config cfg; @@ -69,6 +71,8 @@ struct rkvdec_variant { unsigned int num_regs; const struct rkvdec_coded_fmt_desc *coded_fmts; size_t num_coded_fmts; + const struct rcb_size_info *rcb_sizes; + size_t num_rcb_sizes; unsigned int quirks; }; =20 @@ -119,6 +123,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; const struct rkvdec_variant *variant; }; @@ -131,6 +137,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; }; =20 @@ -139,10 +146,16 @@ static inline struct rkvdec_ctx *file_to_rkvdec_ctx(s= truct file *filp) return container_of(file_to_v4l2_fh(filp), struct rkvdec_ctx, fh); } =20 +enum rkvdec_alloc_type { + RKVDEC_ALLOC_DMA =3D 0, + RKVDEC_ALLOC_SRAM =3D 1, +}; + struct rkvdec_aux_buf { void *cpu; dma_addr_t dma; size_t size; + enum rkvdec_alloc_type type; }; =20 void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run); --=20 2.52.0