Skip to content

Commit e5640db

Browse files
cazouHans Verkuil
authored andcommitted
media: rkvdec: Add RCB and SRAM support
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 <didi.debian@cknow.org> # Rock 5B Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com> Signed-off-by: Detlev Casanova <detlev.casanova@collabora.com> Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com> Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
1 parent ae2070c commit e5640db

5 files changed

Lines changed: 247 additions & 2 deletions

File tree

drivers/media/platform/rockchip/rkvdec/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ rockchip-vdec-y += \
77
rkvdec-h264-common.o \
88
rkvdec-hevc.o \
99
rkvdec-hevc-common.o \
10+
rkvdec-rcb.o \
1011
rkvdec-vp9.o
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Rockchip video decoder Rows and Cols Buffers manager
4+
*
5+
* Copyright (C) 2025 Collabora, Ltd.
6+
* Detlev Casanova <detlev.casanova@collabora.com>
7+
*/
8+
9+
#include "rkvdec.h"
10+
#include "rkvdec-rcb.h"
11+
12+
#include <linux/iommu.h>
13+
#include <linux/genalloc.h>
14+
#include <linux/sizes.h>
15+
#include <linux/types.h>
16+
17+
struct rkvdec_rcb_config {
18+
struct rkvdec_aux_buf *rcb_bufs;
19+
size_t rcb_count;
20+
};
21+
22+
static size_t rkvdec_rcb_size(const struct rcb_size_info *size_info,
23+
unsigned int width, unsigned int height)
24+
{
25+
return size_info->multiplier * (size_info->axis == PIC_HEIGHT ? height : width);
26+
}
27+
28+
dma_addr_t rkvdec_rcb_buf_dma_addr(struct rkvdec_ctx *ctx, int id)
29+
{
30+
return ctx->rcb_config->rcb_bufs[id].dma;
31+
}
32+
33+
size_t rkvdec_rcb_buf_size(struct rkvdec_ctx *ctx, int id)
34+
{
35+
return ctx->rcb_config->rcb_bufs[id].size;
36+
}
37+
38+
int rkvdec_rcb_buf_count(struct rkvdec_ctx *ctx)
39+
{
40+
return ctx->rcb_config->rcb_count;
41+
}
42+
43+
void rkvdec_free_rcb(struct rkvdec_ctx *ctx)
44+
{
45+
struct rkvdec_dev *dev = ctx->dev;
46+
struct rkvdec_rcb_config *cfg = ctx->rcb_config;
47+
unsigned long virt_addr;
48+
int i;
49+
50+
if (!cfg)
51+
return;
52+
53+
for (i = 0; i < cfg->rcb_count; i++) {
54+
size_t rcb_size = cfg->rcb_bufs[i].size;
55+
56+
if (!cfg->rcb_bufs[i].cpu)
57+
continue;
58+
59+
switch (cfg->rcb_bufs[i].type) {
60+
case RKVDEC_ALLOC_SRAM:
61+
virt_addr = (unsigned long)cfg->rcb_bufs[i].cpu;
62+
63+
if (dev->iommu_domain)
64+
iommu_unmap(dev->iommu_domain, virt_addr, rcb_size);
65+
gen_pool_free(dev->sram_pool, virt_addr, rcb_size);
66+
break;
67+
case RKVDEC_ALLOC_DMA:
68+
dma_free_coherent(dev->dev,
69+
rcb_size,
70+
cfg->rcb_bufs[i].cpu,
71+
cfg->rcb_bufs[i].dma);
72+
break;
73+
}
74+
}
75+
76+
if (cfg->rcb_bufs)
77+
devm_kfree(dev->dev, cfg->rcb_bufs);
78+
79+
devm_kfree(dev->dev, cfg);
80+
}
81+
82+
int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx,
83+
const struct rcb_size_info *size_info,
84+
size_t rcb_count)
85+
{
86+
int ret, i;
87+
u32 width, height;
88+
struct rkvdec_dev *rkvdec = ctx->dev;
89+
struct rkvdec_rcb_config *cfg;
90+
91+
if (!size_info || !rcb_count) {
92+
ctx->rcb_config = NULL;
93+
return 0;
94+
}
95+
96+
ctx->rcb_config = devm_kzalloc(rkvdec->dev, sizeof(*ctx->rcb_config), GFP_KERNEL);
97+
if (!ctx->rcb_config)
98+
return -ENOMEM;
99+
100+
cfg = ctx->rcb_config;
101+
102+
cfg->rcb_bufs = devm_kzalloc(rkvdec->dev, sizeof(*cfg->rcb_bufs) * rcb_count, GFP_KERNEL);
103+
if (!cfg->rcb_bufs) {
104+
ret = -ENOMEM;
105+
goto err_alloc;
106+
}
107+
108+
width = ctx->decoded_fmt.fmt.pix_mp.width;
109+
height = ctx->decoded_fmt.fmt.pix_mp.height;
110+
111+
for (i = 0; i < rcb_count; i++) {
112+
void *cpu = NULL;
113+
dma_addr_t dma;
114+
size_t rcb_size = rkvdec_rcb_size(&size_info[i], width, height);
115+
enum rkvdec_alloc_type alloc_type = RKVDEC_ALLOC_SRAM;
116+
117+
/* Try allocating an SRAM buffer */
118+
if (ctx->dev->sram_pool) {
119+
if (rkvdec->iommu_domain)
120+
rcb_size = ALIGN(rcb_size, SZ_4K);
121+
122+
cpu = gen_pool_dma_zalloc_align(ctx->dev->sram_pool,
123+
rcb_size,
124+
&dma,
125+
SZ_4K);
126+
}
127+
128+
/* If an IOMMU is used, map the SRAM address through it */
129+
if (cpu && rkvdec->iommu_domain) {
130+
unsigned long virt_addr = (unsigned long)cpu;
131+
phys_addr_t phys_addr = dma;
132+
133+
ret = iommu_map(rkvdec->iommu_domain, virt_addr, phys_addr,
134+
rcb_size, IOMMU_READ | IOMMU_WRITE, 0);
135+
if (ret) {
136+
gen_pool_free(ctx->dev->sram_pool,
137+
(unsigned long)cpu,
138+
rcb_size);
139+
cpu = NULL;
140+
goto ram_fallback;
141+
}
142+
143+
/*
144+
* The registers will be configured with the virtual
145+
* address so that it goes through the IOMMU
146+
*/
147+
dma = virt_addr;
148+
}
149+
150+
ram_fallback:
151+
/* Fallback to RAM */
152+
if (!cpu) {
153+
cpu = dma_alloc_coherent(ctx->dev->dev,
154+
rcb_size,
155+
&dma,
156+
GFP_KERNEL);
157+
alloc_type = RKVDEC_ALLOC_DMA;
158+
}
159+
160+
if (!cpu) {
161+
ret = -ENOMEM;
162+
goto err_alloc;
163+
}
164+
165+
cfg->rcb_bufs[i].cpu = cpu;
166+
cfg->rcb_bufs[i].dma = dma;
167+
cfg->rcb_bufs[i].size = rcb_size;
168+
cfg->rcb_bufs[i].type = alloc_type;
169+
170+
cfg->rcb_count += 1;
171+
}
172+
173+
return 0;
174+
175+
err_alloc:
176+
rkvdec_free_rcb(ctx);
177+
178+
return ret;
179+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Rockchip video decoder Rows and Cols Buffers manager
4+
*
5+
* Copyright (C) 2025 Collabora, Ltd.
6+
* Detlev Casanova <detlev.casanova@collabora.com>
7+
*/
8+
9+
#include <linux/types.h>
10+
11+
struct rkvdec_ctx;
12+
13+
enum rcb_axis {
14+
PIC_WIDTH = 0,
15+
PIC_HEIGHT = 1
16+
};
17+
18+
struct rcb_size_info {
19+
u8 multiplier;
20+
enum rcb_axis axis;
21+
};
22+
23+
int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx,
24+
const struct rcb_size_info *size_info,
25+
size_t rcb_count);
26+
dma_addr_t rkvdec_rcb_buf_dma_addr(struct rkvdec_ctx *ctx, int id);
27+
size_t rkvdec_rcb_buf_size(struct rkvdec_ctx *ctx, int id);
28+
int rkvdec_rcb_buf_count(struct rkvdec_ctx *ctx);
29+
void rkvdec_free_rcb(struct rkvdec_ctx *ctx);

drivers/media/platform/rockchip/rkvdec/rkvdec.c

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
*/
1111

1212
#include <linux/clk.h>
13+
#include <linux/genalloc.h>
1314
#include <linux/interrupt.h>
1415
#include <linux/iommu.h>
1516
#include <linux/module.h>
@@ -28,6 +29,7 @@
2829

2930
#include "rkvdec.h"
3031
#include "rkvdec-regs.h"
32+
#include "rkvdec-rcb.h"
3133

3234
static bool rkvdec_image_fmt_match(enum rkvdec_image_fmt fmt1,
3335
enum rkvdec_image_fmt fmt2)
@@ -778,6 +780,7 @@ static int rkvdec_start_streaming(struct vb2_queue *q, unsigned int count)
778780
{
779781
struct rkvdec_ctx *ctx = vb2_get_drv_priv(q);
780782
const struct rkvdec_coded_fmt_desc *desc;
783+
const struct rkvdec_variant *variant = ctx->dev->variant;
781784
int ret;
782785

783786
if (V4L2_TYPE_IS_CAPTURE(q->type))
@@ -787,13 +790,22 @@ static int rkvdec_start_streaming(struct vb2_queue *q, unsigned int count)
787790
if (WARN_ON(!desc))
788791
return -EINVAL;
789792

793+
ret = rkvdec_allocate_rcb(ctx, variant->rcb_sizes, variant->num_rcb_sizes);
794+
if (ret)
795+
return ret;
796+
790797
if (desc->ops->start) {
791798
ret = desc->ops->start(ctx);
792799
if (ret)
793-
return ret;
800+
goto err_ops_start;
794801
}
795802

796803
return 0;
804+
805+
err_ops_start:
806+
rkvdec_free_rcb(ctx);
807+
808+
return ret;
797809
}
798810

799811
static void rkvdec_queue_cleanup(struct vb2_queue *vq, u32 state)
@@ -829,6 +841,8 @@ static void rkvdec_stop_streaming(struct vb2_queue *q)
829841

830842
if (desc->ops->stop)
831843
desc->ops->stop(ctx);
844+
845+
rkvdec_free_rcb(ctx);
832846
}
833847

834848
rkvdec_queue_cleanup(q, VB2_BUF_STATE_ERROR);
@@ -1345,6 +1359,10 @@ static int rkvdec_probe(struct platform_device *pdev)
13451359
return ret;
13461360
}
13471361

1362+
rkvdec->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0);
1363+
if (!rkvdec->sram_pool && rkvdec->variant->num_rcb_sizes > 0)
1364+
dev_info(&pdev->dev, "No sram node, RCB will be stored in RAM\n");
1365+
13481366
pm_runtime_set_autosuspend_delay(&pdev->dev, 100);
13491367
pm_runtime_use_autosuspend(&pdev->dev);
13501368
pm_runtime_enable(&pdev->dev);
@@ -1353,7 +1371,8 @@ static int rkvdec_probe(struct platform_device *pdev)
13531371
if (ret)
13541372
goto err_disable_runtime_pm;
13551373

1356-
if (iommu_get_domain_for_dev(&pdev->dev)) {
1374+
rkvdec->iommu_domain = iommu_get_domain_for_dev(&pdev->dev);
1375+
if (rkvdec->iommu_domain) {
13571376
rkvdec->empty_domain = iommu_paging_domain_alloc(rkvdec->dev);
13581377

13591378
if (IS_ERR(rkvdec->empty_domain)) {
@@ -1367,6 +1386,10 @@ static int rkvdec_probe(struct platform_device *pdev)
13671386
err_disable_runtime_pm:
13681387
pm_runtime_dont_use_autosuspend(&pdev->dev);
13691388
pm_runtime_disable(&pdev->dev);
1389+
1390+
if (rkvdec->sram_pool)
1391+
gen_pool_destroy(rkvdec->sram_pool);
1392+
13701393
return ret;
13711394
}
13721395

drivers/media/platform/rockchip/rkvdec/rkvdec.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@
1919
#include <media/v4l2-ctrls.h>
2020
#include <media/v4l2-device.h>
2121
#include <media/v4l2-ioctl.h>
22+
#include <media/v4l2-mem2mem.h>
2223
#include <media/videobuf2-core.h>
2324
#include <media/videobuf2-dma-contig.h>
2425

2526
#define RKVDEC_QUIRK_DISABLE_QOS BIT(0)
2627

2728
struct rkvdec_ctx;
29+
struct rkvdec_rcb_config;
2830

2931
struct rkvdec_ctrl_desc {
3032
struct v4l2_ctrl_config cfg;
@@ -69,6 +71,8 @@ struct rkvdec_variant {
6971
unsigned int num_regs;
7072
const struct rkvdec_coded_fmt_desc *coded_fmts;
7173
size_t num_coded_fmts;
74+
const struct rcb_size_info *rcb_sizes;
75+
size_t num_rcb_sizes;
7276
unsigned int quirks;
7377
};
7478

@@ -119,6 +123,8 @@ struct rkvdec_dev {
119123
void __iomem *regs;
120124
struct mutex vdev_lock; /* serializes ioctls */
121125
struct delayed_work watchdog_work;
126+
struct gen_pool *sram_pool;
127+
struct iommu_domain *iommu_domain;
122128
struct iommu_domain *empty_domain;
123129
const struct rkvdec_variant *variant;
124130
};
@@ -131,6 +137,7 @@ struct rkvdec_ctx {
131137
struct v4l2_ctrl_handler ctrl_hdl;
132138
struct rkvdec_dev *dev;
133139
enum rkvdec_image_fmt image_fmt;
140+
struct rkvdec_rcb_config *rcb_config;
134141
void *priv;
135142
};
136143

@@ -139,10 +146,16 @@ static inline struct rkvdec_ctx *file_to_rkvdec_ctx(struct file *filp)
139146
return container_of(file_to_v4l2_fh(filp), struct rkvdec_ctx, fh);
140147
}
141148

149+
enum rkvdec_alloc_type {
150+
RKVDEC_ALLOC_DMA = 0,
151+
RKVDEC_ALLOC_SRAM = 1,
152+
};
153+
142154
struct rkvdec_aux_buf {
143155
void *cpu;
144156
dma_addr_t dma;
145157
size_t size;
158+
enum rkvdec_alloc_type type;
146159
};
147160

148161
void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);

0 commit comments

Comments
 (0)