From nobody Sat Feb 7 07:24:29 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 E93B0357725; Wed, 22 Oct 2025 16:25:56 +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=1761150359; cv=none; b=FAHYPWuOvUeOZx/BSk7NhCcdvBj1bT19cvhGxVZqDZvkpMBhYtil5Hx4ZgTe6TtL26ttkG+m27GsuSb+JwgrfGGYvq6ieovEYVCckxFzxzF3re2lhEjDh6HOKm66jJG72lDMY2w4+nOF0ar4EDFylBDkLaoWkLmhBv3/uvm6mj4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761150359; c=relaxed/simple; bh=3DNL3ewdtZ7oUDJlJifx6EL8cleCbSj+6x/r1+VSu7E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=A2tGGEHgeOEGpG8mb4Kw9PI6VE/addZNH29wx9clIMnYNfUZ3pZNY5idND/5P8VNiOtYO0Lj8Vyi0j6C0p8rKADpiLgm6PV6zV1hcnKeFHo3sObiLPynMbHO2fH4jITHrXH/wSDNdqlnHYieDLw6/xhy5FAoo0/FktTQHpJzKzc= 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=Qv36012g; 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="Qv36012g" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1761150355; bh=3DNL3ewdtZ7oUDJlJifx6EL8cleCbSj+6x/r1+VSu7E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Qv36012g4JiPgUqkP7c9MLqg0KEwzGzml7wTbPT7z8Jz9Zr0khSsV5bg2kXucCiF5 DI/Ukm30orSah7TT6ogJJj0ukSvAcepfknsrx9XQ42EoVF7UKymac8RmbTegSFKl6p 81X4fPUpwVseUqTqLOZGblGgWaoiCRS7E1APLUrjkZiVAxiXgKyNWKgZWoIe80/t6x XaOyp78u2xBbQknKQXkPYnZkvkYTInG2o4S91KNNrLnIe9AsASSC2sqz+7RDjqZ0wo fD6xZR8o52ycHvumCT/r4QJnLBg+k0i1nSgUrhPMcGFlkUhvwIyrw9DfZJFv8dmqsN EfIfiUDVpFmmQ== Received: from trenzalore (unknown [23.233.251.139]) (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 D596117E1404; Wed, 22 Oct 2025 18:25:52 +0200 (CEST) From: Detlev Casanova To: linux-kernel@vger.kernel.org Cc: Mauro Carvalho Chehab , Detlev Casanova , Ezequiel Garcia , Heiko Stuebner , Ricardo Ribalda , Hans Verkuil , Hans de Goede , Yunke Cao , Jonathan Corbet , Laurent Pinchart , Sakari Ailus , James Cowgill , linux-media@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, kernel@collabora.com, Nicolas Dufresne , Diederik de Haas Subject: [PATCH v3 09/15] media: rkvdec: Add RCB and SRAM support Date: Wed, 22 Oct 2025 12:22:08 -0400 Message-ID: <20251022162459.271603-10-detlev.casanova@collabora.com> X-Mailer: git-send-email 2.51.1.dirty In-Reply-To: <20251022162459.271603-1-detlev.casanova@collabora.com> References: <20251022162459.271603-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 Signed-off-by: Detlev Casanova --- .../media/platform/rockchip/rkvdec/Makefile | 1 + .../platform/rockchip/rkvdec/rkvdec-rcb.c | 173 ++++++++++++++++++ .../platform/rockchip/rkvdec/rkvdec-rcb.h | 29 +++ .../media/platform/rockchip/rkvdec/rkvdec.c | 27 ++- .../media/platform/rockchip/rkvdec/rkvdec.h | 13 ++ 5 files changed, 241 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 1b4bc44be23e..3d75103e536d 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 000000000000..5a4959c239e3 --- /dev/null +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c @@ -0,0 +1,173 @@ +// 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 =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; + + 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, 0x1000); + + cpu =3D 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 =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 000000000000..30e8002555c8 --- /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 a7af1e3fdebd..5dd486edd64d 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) @@ -771,6 +773,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_config *cfg =3D ctx->dev->variant->config; int ret; =20 if (V4L2_TYPE_IS_CAPTURE(q->type)) @@ -780,13 +783,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, cfg->rcb_size_info, cfg->rcb_num); + 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) @@ -822,6 +834,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); @@ -1350,6 +1364,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->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); @@ -1358,7 +1376,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)) { @@ -1372,6 +1391,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 3b1cc511412e..74f71542e031 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include =20 @@ -29,6 +30,7 @@ #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; @@ -117,6 +119,8 @@ struct rkvdec_coded_fmt_desc { struct rkvdec_config { const struct rkvdec_coded_fmt_desc *coded_fmts; size_t coded_fmts_num; + const struct rcb_size_info *rcb_size_info; + size_t rcb_num; }; =20 struct rkvdec_dev { @@ -129,6 +133,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; }; @@ -141,6 +147,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 @@ -149,10 +156,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.51.1.dirty