Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Detlev Casanova <detlev.casanova@collabora.com>
To: Mauro Carvalho Chehab <mchehab@kernel.org>,
	 Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>,
	 Heiko Stuebner <heiko@sntech.de>,
	 Nicolas Dufresne <nicolas.dufresne@collabora.com>,
	 Hans Verkuil <hverkuil+cisco@kernel.org>,
	Jonas Karlman <jonas@kwiboo.se>
Cc: "Sven Püschel" <s.pueschel@pengutronix.de>,
	kernel@collabora.com, linux-media@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	"Detlev Casanova" <detlev.casanova@collabora.com>
Subject: [PATCH v2 4/5] media: rkvdec: Split into core and master platform drivers
Date: Mon, 10 Aug 2026 11:22:14 -0400	[thread overview]
Message-ID: <20260810-rkvdec-multicore-v2-4-986f89d22cdc@collabora.com> (raw)
In-Reply-To: <20260810-rkvdec-multicore-v2-0-986f89d22cdc@collabora.com>

Prepare the driver for multi-core support by restructuring around the
component framework, based on what rga does.
This commit only adds the plumbing and does not yet enable more
than a single core to run (Each additionnal core adding will return
-EBUSY).

Core specific resources are moved to a rkvdec_core struct and rkvdec_dev
only retains v4l2 device info, variant info and the main_core pointer.

Even though only 1 core is being used, a core pointer is added to the
rkvdec_ctx struct to prepare the variant backends to retrieve information
based on the core selected for the job.

Signed-off-by: Detlev Casanova <detlev.casanova@collabora.com>
---
 .../media/platform/rockchip/rkvdec/rkvdec-h264.c   |  17 +-
 .../media/platform/rockchip/rkvdec/rkvdec-hevc.c   |  16 +-
 .../media/platform/rockchip/rkvdec/rkvdec-rcb.c    |  61 +--
 .../media/platform/rockchip/rkvdec/rkvdec-rcb.h    |   7 +-
 .../platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c |  24 +-
 .../platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c |  24 +-
 .../platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c |  24 +-
 .../platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c |  26 +-
 .../media/platform/rockchip/rkvdec/rkvdec-vp9.c    |  27 +-
 drivers/media/platform/rockchip/rkvdec/rkvdec.c    | 506 ++++++++++++++-------
 drivers/media/platform/rockchip/rkvdec/rkvdec.h    |  23 +-
 11 files changed, 472 insertions(+), 283 deletions(-)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
index ffa606038192..d3841dc84d35 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c
@@ -227,6 +227,7 @@ static void set_poc_reg(struct rkvdec_regs *regs, uint32_t poc, int id, bool bot
 static void config_registers(struct rkvdec_ctx *ctx,
 			     struct rkvdec_h264_run *run)
 {
+	struct rkvdec_core *core = ctx->core;
 	struct rkvdec_dev *rkvdec = ctx->dev;
 	const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
 	const struct v4l2_ctrl_h264_sps *sps = run->sps;
@@ -333,7 +334,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	offset = offsetof(struct rkvdec_h264_priv_tbl, err_info);
 	regs->h26x.errorinfo_base = priv_start_addr + offset;
 
-	rkvdec_memcpy_toio(rkvdec->regs, regs,
+	rkvdec_memcpy_toio(core->regs, regs,
 			   MIN(sizeof(*regs), sizeof(u32) * rkvdec->variant->num_regs));
 }
 
@@ -358,7 +359,7 @@ static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
 	if (!h264_ctx)
 		return -ENOMEM;
 
-	priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
+	priv_tbl = dma_alloc_coherent(rkvdec->main_core->dev, sizeof(*priv_tbl),
 				      &h264_ctx->priv_tbl.dma, GFP_KERNEL);
 	if (!priv_tbl) {
 		ret = -ENOMEM;
@@ -383,7 +384,7 @@ static void rkvdec_h264_stop(struct rkvdec_ctx *ctx)
 	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
 	struct rkvdec_dev *rkvdec = ctx->dev;
 
-	dma_free_coherent(rkvdec->dev, h264_ctx->priv_tbl.size,
+	dma_free_coherent(rkvdec->main_core->dev, h264_ctx->priv_tbl.size,
 			  h264_ctx->priv_tbl.cpu, h264_ctx->priv_tbl.dma);
 	kfree(h264_ctx);
 }
@@ -391,7 +392,7 @@ static void rkvdec_h264_stop(struct rkvdec_ctx *ctx)
 static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
 {
 	struct v4l2_h264_reflist_builder reflist_builder;
-	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_core *core = ctx->core;
 	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
 	struct rkvdec_h264_run run;
 	struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu;
@@ -413,15 +414,15 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
 
 	rkvdec_run_postamble(ctx, &run.base);
 
-	schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000));
+	schedule_delayed_work(&core->watchdog_work, msecs_to_jiffies(2000));
 
-	writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
-	writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
+	writel(1, core->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
+	writel(1, core->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
 
 	/* Start decoding! */
 	writel(RKVDEC_INTERRUPT_DEC_E | RKVDEC_CONFIG_DEC_CLK_GATE_E |
 	       RKVDEC_TIMEOUT_E | RKVDEC_BUF_EMPTY_E,
-	       rkvdec->regs + RKVDEC_REG_INTERRUPT);
+	       core->regs + RKVDEC_REG_INTERRUPT);
 
 	return 0;
 }
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
index 87abf93dfd5e..c9d0913e90ee 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
@@ -381,6 +381,7 @@ static void assemble_sw_rps(struct rkvdec_ctx *ctx,
 static void config_registers(struct rkvdec_ctx *ctx,
 			     struct rkvdec_hevc_run *run)
 {
+	struct rkvdec_core *core = ctx->core;
 	struct rkvdec_dev *rkvdec = ctx->dev;
 	const struct v4l2_ctrl_hevc_decode_params *decode_params = run->decode_params;
 	const struct v4l2_ctrl_hevc_sps *sps = run->sps;
@@ -477,7 +478,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	offset = offsetof(struct rkvdec_hevc_priv_tbl, rps);
 	regs->h26x.rps_base = priv_start_addr + offset;
 
-	rkvdec_memcpy_toio(rkvdec->regs, regs,
+	rkvdec_memcpy_toio(core->regs, regs,
 			   MIN(sizeof(*regs), sizeof(u32) * rkvdec->variant->num_regs));
 }
 
@@ -511,7 +512,7 @@ static int rkvdec_hevc_start(struct rkvdec_ctx *ctx)
 	if (!hevc_ctx)
 		return -ENOMEM;
 
-	priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
+	priv_tbl = dma_alloc_coherent(rkvdec->main_core->dev, sizeof(*priv_tbl),
 				      &hevc_ctx->priv_tbl.dma, GFP_KERNEL);
 	if (!priv_tbl) {
 		kfree(hevc_ctx);
@@ -532,13 +533,14 @@ static void rkvdec_hevc_stop(struct rkvdec_ctx *ctx)
 	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
 	struct rkvdec_dev *rkvdec = ctx->dev;
 
-	dma_free_coherent(rkvdec->dev, hevc_ctx->priv_tbl.size,
+	dma_free_coherent(rkvdec->main_core->dev, hevc_ctx->priv_tbl.size,
 			  hevc_ctx->priv_tbl.cpu, hevc_ctx->priv_tbl.dma);
 	kfree(hevc_ctx);
 }
 
 static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
 {
+	struct rkvdec_core *core = ctx->core;
 	struct rkvdec_dev *rkvdec = ctx->dev;
 	struct rkvdec_hevc_run run;
 	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
@@ -555,10 +557,10 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
 
 	rkvdec_run_postamble(ctx, &run.base);
 
-	schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000));
+	schedule_delayed_work(&core->watchdog_work, msecs_to_jiffies(2000));
 
-	writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
-	writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
+	writel(1, core->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
+	writel(1, core->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
 
 	if (rkvdec->variant->quirks & RKVDEC_QUIRK_DISABLE_QOS)
 		rkvdec_quirks_disable_qos(ctx);
@@ -568,7 +570,7 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
 		0 : RKVDEC_WR_DDR_ALIGN_EN;
 	writel(RKVDEC_INTERRUPT_DEC_E | RKVDEC_CONFIG_DEC_CLK_GATE_E |
 	       RKVDEC_TIMEOUT_E | RKVDEC_BUF_EMPTY_E | reg,
-	       rkvdec->regs + RKVDEC_REG_INTERRUPT);
+	       core->regs + RKVDEC_REG_INTERRUPT);
 
 	return 0;
 }
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
index 191f78278c01..44df5b6df80c 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
@@ -29,38 +29,37 @@ static size_t rkvdec_rcb_size(const struct rcb_size_info *size_info,
 
 dma_addr_t rkvdec_rcb_buf_dma_addr(struct rkvdec_ctx *ctx, int id)
 {
-	return ctx->rcb_config->rcb_bufs[id].dma;
+	return ctx->core->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;
+	return ctx->core->rcb_config->rcb_bufs[id].size;
 }
 
 int rkvdec_rcb_buf_count(struct rkvdec_ctx *ctx)
 {
-	return ctx->rcb_config->rcb_count;
+	return ctx->core->rcb_config->rcb_count;
 }
 
 bool rkvdec_rcb_buf_validate_size(struct rkvdec_ctx *ctx)
 {
-	struct rkvdec_rcb_config *cfg = ctx->rcb_config;
+	struct rkvdec_rcb_config *cfg = ctx->core->rcb_config;
 
 	bool ret = cfg && cfg->height >= ctx->decoded_fmt.fmt.pix_mp.height &&
 		   cfg->width >= ctx->decoded_fmt.fmt.pix_mp.width;
 
 	if (!ret && cfg) {
-		dev_dbg(ctx->dev->dev, "RCB size %ux%u -> %ux%u\n", cfg->width, cfg->height,
+		dev_dbg(ctx->core->dev, "RCB size %ux%u -> %ux%u\n", cfg->width, cfg->height,
 			ctx->decoded_fmt.fmt.pix_mp.width, ctx->decoded_fmt.fmt.pix_mp.height);
 	}
 
 	return ret;
 }
 
-void rkvdec_free_rcb(struct rkvdec_ctx *ctx)
+void rkvdec_free_rcb(struct rkvdec_dev *rkvdec, struct rkvdec_core *core)
 {
-	struct rkvdec_dev *dev = ctx->dev;
-	struct rkvdec_rcb_config *cfg = ctx->rcb_config;
+	struct rkvdec_rcb_config *cfg = core->rcb_config;
 	unsigned long virt_addr;
 	int i;
 
@@ -77,12 +76,13 @@ void rkvdec_free_rcb(struct rkvdec_ctx *ctx)
 		case RKVDEC_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);
+			if (iommu_get_domain_for_dev(core->dev))
+				iommu_unmap(iommu_get_domain_for_dev(core->dev),
+					    virt_addr, rcb_size);
+			gen_pool_free(core->sram_pool, virt_addr, rcb_size);
 			break;
 		case RKVDEC_ALLOC_DMA:
-			dma_free_coherent(dev->dev,
+			dma_free_coherent(rkvdec->main_core->dev,
 					  rcb_size,
 					  cfg->rcb_bufs[i].cpu,
 					  cfg->rcb_bufs[i].dma);
@@ -91,33 +91,33 @@ void rkvdec_free_rcb(struct rkvdec_ctx *ctx)
 	}
 
 	if (cfg->rcb_bufs)
-		devm_kfree(dev->dev, cfg->rcb_bufs);
+		devm_kfree(core->dev, cfg->rcb_bufs);
 
-	devm_kfree(dev->dev, cfg);
+	devm_kfree(core->dev, cfg);
 
-	ctx->rcb_config = NULL;
+	core->rcb_config = NULL;
 }
 
-int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx, u32 width, u32 height,
+int rkvdec_allocate_rcb(struct rkvdec_dev *rkvdec, struct rkvdec_core *core,
+			u32 width, u32 height,
 			const struct rcb_size_info *size_info,
 			size_t rcb_count)
 {
 	int ret, i;
-	struct rkvdec_dev *rkvdec = ctx->dev;
 	struct rkvdec_rcb_config *cfg;
 
 	if (!size_info || !rcb_count) {
-		ctx->rcb_config = NULL;
+		core->rcb_config = NULL;
 		return 0;
 	}
 
-	ctx->rcb_config = devm_kzalloc(rkvdec->dev, sizeof(*ctx->rcb_config), GFP_KERNEL);
-	if (!ctx->rcb_config)
+	core->rcb_config = devm_kzalloc(core->dev, sizeof(*core->rcb_config), GFP_KERNEL);
+	if (!core->rcb_config)
 		return -ENOMEM;
 
-	cfg = ctx->rcb_config;
+	cfg = core->rcb_config;
 
-	cfg->rcb_bufs = devm_kzalloc(rkvdec->dev, sizeof(*cfg->rcb_bufs) * rcb_count, GFP_KERNEL);
+	cfg->rcb_bufs = devm_kzalloc(core->dev, sizeof(*cfg->rcb_bufs) * rcb_count, GFP_KERNEL);
 	if (!cfg->rcb_bufs) {
 		ret = -ENOMEM;
 		goto err_alloc;
@@ -133,25 +133,26 @@ int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx, u32 width, u32 height,
 		enum rkvdec_alloc_type alloc_type = RKVDEC_ALLOC_SRAM;
 
 		/* Try allocating an SRAM buffer */
-		if (ctx->dev->sram_pool) {
-			if (rkvdec->iommu_domain)
+		if (core->sram_pool) {
+			if (iommu_get_domain_for_dev(core->dev))
 				rcb_size = ALIGN(rcb_size, SZ_4K);
 
-			cpu = gen_pool_dma_zalloc_align(ctx->dev->sram_pool,
+			cpu = gen_pool_dma_zalloc_align(core->sram_pool,
 							rcb_size,
 							&dma,
 							SZ_4K);
 		}
 
 		/* If an IOMMU is used, map the SRAM address through it */
-		if (cpu && rkvdec->iommu_domain) {
+		if (cpu && iommu_get_domain_for_dev(core->dev)) {
 			unsigned long virt_addr = (unsigned long)cpu;
 			phys_addr_t phys_addr = dma;
 
-			ret = iommu_map(rkvdec->iommu_domain, virt_addr, phys_addr,
+			ret = iommu_map(iommu_get_domain_for_dev(core->dev),
+					virt_addr, phys_addr,
 					rcb_size, IOMMU_READ | IOMMU_WRITE, 0);
 			if (ret) {
-				gen_pool_free(ctx->dev->sram_pool,
+				gen_pool_free(core->sram_pool,
 					      (unsigned long)cpu,
 					      rcb_size);
 				cpu = NULL;
@@ -168,7 +169,7 @@ int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx, u32 width, u32 height,
 ram_fallback:
 		/* Fallback to RAM */
 		if (!cpu) {
-			cpu = dma_alloc_coherent(ctx->dev->dev,
+			cpu = dma_alloc_coherent(rkvdec->main_core->dev,
 						 rcb_size,
 						 &dma,
 						 GFP_KERNEL);
@@ -191,7 +192,7 @@ int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx, u32 width, u32 height,
 	return 0;
 
 err_alloc:
-	rkvdec_free_rcb(ctx);
+	rkvdec_free_rcb(rkvdec, core);
 
 	return ret;
 }
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
index 0662a4359bdf..d1149afe7fda 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
@@ -8,7 +8,9 @@
 
 #include <linux/types.h>
 
+struct rkvdec_dev;
 struct rkvdec_ctx;
+struct rkvdec_core;
 
 enum rcb_axis {
 	PIC_WIDTH = 0,
@@ -20,11 +22,12 @@ struct rcb_size_info {
 	enum rcb_axis axis;
 };
 
-int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx, u32 width, u32 height,
+int rkvdec_allocate_rcb(struct rkvdec_dev *rkvdec, struct rkvdec_core *core,
+			u32 width, u32 height,
 			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);
 bool rkvdec_rcb_buf_validate_size(struct rkvdec_ctx *ctx);
-void rkvdec_free_rcb(struct rkvdec_ctx *ctx);
+void rkvdec_free_rcb(struct rkvdec_dev *rkvdec, struct rkvdec_core *core);
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c
index b961fddc8583..667c5d36f3ea 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c
@@ -185,22 +185,22 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
 
 static void rkvdec_write_regs(struct rkvdec_ctx *ctx)
 {
-	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_core *core = ctx->core;
 	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
 
-	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_REGS,
+	rkvdec_memcpy_toio(core->regs + OFFSET_COMMON_REGS,
 			   &h264_ctx->regs.common,
 			   sizeof(h264_ctx->regs.common));
-	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_PARAMS_REGS,
+	rkvdec_memcpy_toio(core->regs + OFFSET_CODEC_PARAMS_REGS,
 			   &h264_ctx->regs.h264_param,
 			   sizeof(h264_ctx->regs.h264_param));
-	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_ADDR_REGS,
+	rkvdec_memcpy_toio(core->regs + OFFSET_COMMON_ADDR_REGS,
 			   &h264_ctx->regs.common_addr,
 			   sizeof(h264_ctx->regs.common_addr));
-	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_ADDR_REGS,
+	rkvdec_memcpy_toio(core->regs + OFFSET_CODEC_ADDR_REGS,
 			   &h264_ctx->regs.h264_addr,
 			   sizeof(h264_ctx->regs.h264_addr));
-	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_POC_HIGHBIT_REGS,
+	rkvdec_memcpy_toio(core->regs + OFFSET_POC_HIGHBIT_REGS,
 			   &h264_ctx->regs.h264_highpoc,
 			   sizeof(h264_ctx->regs.h264_highpoc));
 }
@@ -368,7 +368,6 @@ static void config_registers(struct rkvdec_ctx *ctx,
 
 static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
 {
-	struct rkvdec_dev *rkvdec = ctx->dev;
 	struct rkvdec_h264_priv_tbl *priv_tbl;
 	struct rkvdec_h264_ctx *h264_ctx;
 	struct v4l2_ctrl *ctrl;
@@ -387,7 +386,7 @@ static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
 	if (!h264_ctx)
 		return -ENOMEM;
 
-	priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
+	priv_tbl = dma_alloc_coherent(ctx->dev->main_core->dev, sizeof(*priv_tbl),
 				      &h264_ctx->priv_tbl.dma, GFP_KERNEL);
 	if (!priv_tbl) {
 		ret = -ENOMEM;
@@ -410,9 +409,8 @@ static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
 static void rkvdec_h264_stop(struct rkvdec_ctx *ctx)
 {
 	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
-	struct rkvdec_dev *rkvdec = ctx->dev;
 
-	dma_free_coherent(rkvdec->dev, h264_ctx->priv_tbl.size,
+	dma_free_coherent(ctx->dev->main_core->dev, h264_ctx->priv_tbl.size,
 			  h264_ctx->priv_tbl.cpu, h264_ctx->priv_tbl.dma);
 	kfree(h264_ctx);
 }
@@ -420,7 +418,7 @@ static void rkvdec_h264_stop(struct rkvdec_ctx *ctx)
 static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
 {
 	struct v4l2_h264_reflist_builder reflist_builder;
-	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_core *core = ctx->core;
 	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
 	struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu;
 	struct rkvdec_h264_run run;
@@ -443,10 +441,10 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
 
 	rkvdec_run_postamble(ctx, &run.base);
 
-	rkvdec_schedule_watchdog(rkvdec, h264_ctx->regs.common.reg032_timeout_threshold);
+	rkvdec_schedule_watchdog(core, h264_ctx->regs.common.reg032_timeout_threshold);
 
 	/* Start decoding! */
-	writel(VDPU381_DEC_E_BIT, rkvdec->regs + VDPU381_REG_DEC_E);
+	writel(VDPU381_DEC_E_BIT, core->regs + VDPU381_REG_DEC_E);
 
 	return 0;
 }
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
index fe6414a17551..bd68120b74c6 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
@@ -356,22 +356,22 @@ static void set_ref_valid(struct rkvdec_vdpu381_regs_hevc *regs, int id, u32 val
 
 static void rkvdec_write_regs(struct rkvdec_ctx *ctx)
 {
-	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_core *core = ctx->core;
 	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
 
-	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_REGS,
+	rkvdec_memcpy_toio(core->regs + OFFSET_COMMON_REGS,
 			   &hevc_ctx->regs.common,
 			   sizeof(hevc_ctx->regs.common));
-	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_PARAMS_REGS,
+	rkvdec_memcpy_toio(core->regs + OFFSET_CODEC_PARAMS_REGS,
 			   &hevc_ctx->regs.hevc_param,
 			   sizeof(hevc_ctx->regs.hevc_param));
-	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_ADDR_REGS,
+	rkvdec_memcpy_toio(core->regs + OFFSET_COMMON_ADDR_REGS,
 			   &hevc_ctx->regs.common_addr,
 			   sizeof(hevc_ctx->regs.common_addr));
-	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_ADDR_REGS,
+	rkvdec_memcpy_toio(core->regs + OFFSET_CODEC_ADDR_REGS,
 			   &hevc_ctx->regs.hevc_addr,
 			   sizeof(hevc_ctx->regs.hevc_addr));
-	rkvdec_memcpy_toio(rkvdec->regs + OFFSET_POC_HIGHBIT_REGS,
+	rkvdec_memcpy_toio(core->regs + OFFSET_POC_HIGHBIT_REGS,
 			   &hevc_ctx->regs.hevc_highpoc,
 			   sizeof(hevc_ctx->regs.hevc_highpoc));
 }
@@ -555,7 +555,7 @@ static int rkvdec_hevc_start(struct rkvdec_ctx *ctx)
 	if (!hevc_ctx)
 		return -ENOMEM;
 
-	priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
+	priv_tbl = dma_alloc_coherent(rkvdec->main_core->dev, sizeof(*priv_tbl),
 				      &hevc_ctx->priv_tbl.dma, GFP_KERNEL);
 	if (!priv_tbl) {
 		ret = -ENOMEM;
@@ -580,14 +580,14 @@ static void rkvdec_hevc_stop(struct rkvdec_ctx *ctx)
 	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
 	struct rkvdec_dev *rkvdec = ctx->dev;
 
-	dma_free_coherent(rkvdec->dev, hevc_ctx->priv_tbl.size,
+	dma_free_coherent(rkvdec->main_core->dev, hevc_ctx->priv_tbl.size,
 			  hevc_ctx->priv_tbl.cpu, hevc_ctx->priv_tbl.dma);
 	kfree(hevc_ctx);
 }
 
 static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
 {
-	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_core *core = ctx->core;
 	struct rkvdec_hevc_run run;
 	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
 	struct rkvdec_hevc_priv_tbl *tbl = hevc_ctx->priv_tbl.cpu;
@@ -604,7 +604,7 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
 	 */
 	if ((!ctx->has_sps_lt_rps && run.sps->num_long_term_ref_pics_sps) ||
 	    (!ctx->has_sps_st_rps && run.sps->num_short_term_ref_pic_sets)) {
-		dev_warn_ratelimited(rkvdec->dev, "Long and short term RPS not set\n");
+		dev_warn_ratelimited(core->dev, "Long and short term RPS not set\n");
 	} else {
 		rkvdec_hevc_assemble_hw_rps(&run, &tbl->rps, &hevc_ctx->st_cache);
 	}
@@ -613,10 +613,10 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
 
 	rkvdec_run_postamble(ctx, &run.base);
 
-	rkvdec_schedule_watchdog(rkvdec, hevc_ctx->regs.common.reg032_timeout_threshold);
+	rkvdec_schedule_watchdog(core, hevc_ctx->regs.common.reg032_timeout_threshold);
 
 	/* Start decoding! */
-	writel(VDPU381_DEC_E_BIT, rkvdec->regs + VDPU381_REG_DEC_E);
+	writel(VDPU381_DEC_E_BIT, ctx->core->regs + VDPU381_REG_DEC_E);
 
 	return 0;
 }
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
index 5ec755733916..a737a7799b71 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
@@ -216,19 +216,19 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
 
 static void rkvdec_write_regs(struct rkvdec_ctx *ctx)
 {
-	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_core *core = ctx->core;
 	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
 
-	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_COMMON_REGS,
+	rkvdec_memcpy_toio(core->regs + VDPU383_OFFSET_COMMON_REGS,
 			   &h264_ctx->regs.common,
 			   sizeof(h264_ctx->regs.common));
-	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_COMMON_ADDR_REGS,
+	rkvdec_memcpy_toio(core->regs + VDPU383_OFFSET_COMMON_ADDR_REGS,
 			   &h264_ctx->regs.common_addr,
 			   sizeof(h264_ctx->regs.common_addr));
-	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_CODEC_PARAMS_REGS,
+	rkvdec_memcpy_toio(core->regs + VDPU383_OFFSET_CODEC_PARAMS_REGS,
 			   &h264_ctx->regs.h26x_params,
 			   sizeof(h264_ctx->regs.h26x_params));
-	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_CODEC_ADDR_REGS,
+	rkvdec_memcpy_toio(core->regs + VDPU383_OFFSET_CODEC_ADDR_REGS,
 			   &h264_ctx->regs.h26x_addr,
 			   sizeof(h264_ctx->regs.h26x_addr));
 }
@@ -380,7 +380,7 @@ static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
 	if (!h264_ctx)
 		return -ENOMEM;
 
-	priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
+	priv_tbl = dma_alloc_coherent(rkvdec->main_core->dev, sizeof(*priv_tbl),
 				      &h264_ctx->priv_tbl.dma, GFP_KERNEL);
 	if (!priv_tbl) {
 		ret = -ENOMEM;
@@ -406,7 +406,7 @@ static void rkvdec_h264_stop(struct rkvdec_ctx *ctx)
 	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
 	struct rkvdec_dev *rkvdec = ctx->dev;
 
-	dma_free_coherent(rkvdec->dev, h264_ctx->priv_tbl.size,
+	dma_free_coherent(rkvdec->main_core->dev, h264_ctx->priv_tbl.size,
 			  h264_ctx->priv_tbl.cpu, h264_ctx->priv_tbl.dma);
 	kfree(h264_ctx);
 }
@@ -414,7 +414,7 @@ static void rkvdec_h264_stop(struct rkvdec_ctx *ctx)
 static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
 {
 	struct v4l2_h264_reflist_builder reflist_builder;
-	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_core *core = ctx->core;
 	struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
 	struct rkvdec_h264_run run;
 	struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu;
@@ -439,12 +439,12 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
 	rkvdec_run_postamble(ctx, &run.base);
 
 	timeout_threshold = h264_ctx->regs.common.reg013_core_timeout_threshold;
-	rkvdec_schedule_watchdog(rkvdec, timeout_threshold);
+	rkvdec_schedule_watchdog(core, timeout_threshold);
 
 	/* Start decoding! */
-	writel(timeout_threshold, rkvdec->link + VDPU383_LINK_TIMEOUT_THRESHOLD);
-	writel(0, rkvdec->link + VDPU383_LINK_IP_ENABLE);
-	writel(VDPU383_DEC_E_BIT, rkvdec->link + VDPU383_LINK_DEC_ENABLE);
+	writel(timeout_threshold, core->link + VDPU383_LINK_TIMEOUT_THRESHOLD);
+	writel(0, core->link + VDPU383_LINK_IP_ENABLE);
+	writel(VDPU383_DEC_E_BIT, core->link + VDPU383_LINK_DEC_ENABLE);
 
 	return 0;
 }
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c
index 3575338a531a..2862231b17f2 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c
@@ -323,19 +323,19 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
 
 static void rkvdec_write_regs(struct rkvdec_ctx *ctx)
 {
-	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_core *core = ctx->core;
 	struct rkvdec_hevc_ctx *h265_ctx = ctx->priv;
 
-	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_COMMON_REGS,
+	rkvdec_memcpy_toio(core->regs + VDPU383_OFFSET_COMMON_REGS,
 			   &h265_ctx->regs.common,
 			   sizeof(h265_ctx->regs.common));
-	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_COMMON_ADDR_REGS,
+	rkvdec_memcpy_toio(core->regs + VDPU383_OFFSET_COMMON_ADDR_REGS,
 			   &h265_ctx->regs.common_addr,
 			   sizeof(h265_ctx->regs.common_addr));
-	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_CODEC_PARAMS_REGS,
+	rkvdec_memcpy_toio(core->regs + VDPU383_OFFSET_CODEC_PARAMS_REGS,
 			   &h265_ctx->regs.h26x_params,
 			   sizeof(h265_ctx->regs.h26x_params));
-	rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_CODEC_ADDR_REGS,
+	rkvdec_memcpy_toio(core->regs + VDPU383_OFFSET_CODEC_ADDR_REGS,
 			   &h265_ctx->regs.h26x_addr,
 			   sizeof(h265_ctx->regs.h26x_addr));
 }
@@ -505,7 +505,7 @@ static int rkvdec_hevc_start(struct rkvdec_ctx *ctx)
 	if (!hevc_ctx)
 		return -ENOMEM;
 
-	priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
+	priv_tbl = dma_alloc_coherent(rkvdec->main_core->dev, sizeof(*priv_tbl),
 				      &hevc_ctx->priv_tbl.dma, GFP_KERNEL);
 	if (!priv_tbl) {
 		ret = -ENOMEM;
@@ -530,14 +530,14 @@ static void rkvdec_hevc_stop(struct rkvdec_ctx *ctx)
 	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
 	struct rkvdec_dev *rkvdec = ctx->dev;
 
-	dma_free_coherent(rkvdec->dev, hevc_ctx->priv_tbl.size,
+	dma_free_coherent(rkvdec->main_core->dev, hevc_ctx->priv_tbl.size,
 			  hevc_ctx->priv_tbl.cpu, hevc_ctx->priv_tbl.dma);
 	kfree(hevc_ctx);
 }
 
 static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
 {
-	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_core *core = ctx->core;
 	struct rkvdec_hevc_run run;
 	struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv;
 	struct rkvdec_hevc_priv_tbl *tbl = hevc_ctx->priv_tbl.cpu;
@@ -552,7 +552,7 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
 	 */
 	if ((!ctx->has_sps_lt_rps && run.sps->num_long_term_ref_pics_sps) ||
 	    (!ctx->has_sps_st_rps && run.sps->num_short_term_ref_pic_sets)) {
-		dev_err_ratelimited(rkvdec->dev, "Long and short term RPS not set\n");
+		dev_err_ratelimited(core->dev, "Long and short term RPS not set\n");
 		return -EINVAL;
 	}
 
@@ -566,12 +566,12 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx)
 	rkvdec_run_postamble(ctx, &run.base);
 
 	timeout_threshold = hevc_ctx->regs.common.reg013_core_timeout_threshold;
-	rkvdec_schedule_watchdog(rkvdec, timeout_threshold);
+	rkvdec_schedule_watchdog(core, timeout_threshold);
 
 	/* Start decoding! */
-	writel(timeout_threshold, rkvdec->link + VDPU383_LINK_TIMEOUT_THRESHOLD);
-	writel(VDPU383_IP_CRU_MODE, rkvdec->link + VDPU383_LINK_IP_ENABLE);
-	writel(VDPU383_DEC_E_BIT, rkvdec->link + VDPU383_LINK_DEC_ENABLE);
+	writel(timeout_threshold, core->link + VDPU383_LINK_TIMEOUT_THRESHOLD);
+	writel(VDPU383_IP_CRU_MODE, core->link + VDPU383_LINK_IP_ENABLE);
+	writel(VDPU383_DEC_E_BIT, core->link + VDPU383_LINK_DEC_ENABLE);
 
 	return 0;
 }
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
index 2751f5396ee8..0b7d6b29bcfa 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
@@ -482,6 +482,7 @@ static void config_registers(struct rkvdec_ctx *ctx,
 	struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
 	struct rkvdec_regs *regs = &vp9_ctx->regs;
 	const struct v4l2_vp9_segmentation *seg;
+	struct rkvdec_core *core = ctx->core;
 	struct rkvdec_dev *rkvdec = ctx->dev;
 	dma_addr_t addr;
 	bool intra_only;
@@ -657,18 +658,19 @@ static void config_registers(struct rkvdec_ctx *ctx,
 
 	regs->vp9.reg44.strmd_error_e = 0xe;
 
-	rkvdec_memcpy_toio(rkvdec->regs, regs,
+	rkvdec_memcpy_toio(core->regs, regs,
 			   MIN(sizeof(*regs), sizeof(u32) * rkvdec->variant->num_regs));
 }
 
 static int validate_dec_params(struct rkvdec_ctx *ctx,
 			       const struct v4l2_ctrl_vp9_frame *dec_params)
 {
+	struct rkvdec_core *core = ctx->core;
 	unsigned int aligned_width, aligned_height;
 
 	/* We only support profile 0. */
 	if (dec_params->profile != 0) {
-		dev_err(ctx->dev->dev, "unsupported profile %d\n",
+		dev_err(core->dev, "unsupported profile %d\n",
 			dec_params->profile);
 		return -EINVAL;
 	}
@@ -682,7 +684,7 @@ static int validate_dec_params(struct rkvdec_ctx *ctx,
 	 */
 	if (aligned_width != ctx->decoded_fmt.fmt.pix_mp.width ||
 	    aligned_height != ctx->decoded_fmt.fmt.pix_mp.height) {
-		dev_err(ctx->dev->dev,
+		dev_err(core->dev,
 			"unexpected bitstream resolution %dx%d\n",
 			dec_params->frame_width_minus_1 + 1,
 			dec_params->frame_height_minus_1 + 1);
@@ -768,6 +770,7 @@ static int rkvdec_vp9_run_preamble(struct rkvdec_ctx *ctx,
 
 static int rkvdec_vp9_run(struct rkvdec_ctx *ctx)
 {
+	struct rkvdec_core *core = ctx->core;
 	struct rkvdec_dev *rkvdec = ctx->dev;
 	struct rkvdec_vp9_run run = { };
 	int ret;
@@ -786,10 +789,10 @@ static int rkvdec_vp9_run(struct rkvdec_ctx *ctx)
 
 	rkvdec_run_postamble(ctx, &run.base);
 
-	schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000));
+	schedule_delayed_work(&core->watchdog_work, msecs_to_jiffies(2000));
 
-	writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
-	writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
+	writel(1, core->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
+	writel(1, core->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
 
 	if (rkvdec->variant->quirks & RKVDEC_QUIRK_DISABLE_QOS)
 		rkvdec_quirks_disable_qos(ctx);
@@ -797,7 +800,7 @@ static int rkvdec_vp9_run(struct rkvdec_ctx *ctx)
 	/* Start decoding! */
 	writel(RKVDEC_INTERRUPT_DEC_E | RKVDEC_CONFIG_DEC_CLK_GATE_E |
 	       RKVDEC_TIMEOUT_E | RKVDEC_BUF_EMPTY_E,
-	       rkvdec->regs + RKVDEC_REG_INTERRUPT);
+	       core->regs + RKVDEC_REG_INTERRUPT);
 
 	return 0;
 }
@@ -979,7 +982,7 @@ static int rkvdec_vp9_start(struct rkvdec_ctx *ctx)
 	ctx->priv = vp9_ctx;
 
 	BUILD_BUG_ON(sizeof(priv_tbl->probs) % 16); /* ensure probs size is 128-bit aligned */
-	priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
+	priv_tbl = dma_alloc_coherent(rkvdec->main_core->dev, sizeof(*priv_tbl),
 				      &vp9_ctx->priv_tbl.dma, GFP_KERNEL);
 	if (!priv_tbl) {
 		ret = -ENOMEM;
@@ -989,7 +992,7 @@ static int rkvdec_vp9_start(struct rkvdec_ctx *ctx)
 	vp9_ctx->priv_tbl.size = sizeof(*priv_tbl);
 	vp9_ctx->priv_tbl.cpu = priv_tbl;
 
-	count_tbl = dma_alloc_coherent(rkvdec->dev, RKVDEC_VP9_COUNT_SIZE,
+	count_tbl = dma_alloc_coherent(rkvdec->main_core->dev, RKVDEC_VP9_COUNT_SIZE,
 				       &vp9_ctx->count_tbl.dma, GFP_KERNEL);
 	if (!count_tbl) {
 		ret = -ENOMEM;
@@ -1003,7 +1006,7 @@ static int rkvdec_vp9_start(struct rkvdec_ctx *ctx)
 	return 0;
 
 err_free_priv_tbl:
-	dma_free_coherent(rkvdec->dev, vp9_ctx->priv_tbl.size,
+	dma_free_coherent(rkvdec->main_core->dev, vp9_ctx->priv_tbl.size,
 			  vp9_ctx->priv_tbl.cpu, vp9_ctx->priv_tbl.dma);
 
 err_free_ctx:
@@ -1016,9 +1019,9 @@ static void rkvdec_vp9_stop(struct rkvdec_ctx *ctx)
 	struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
 	struct rkvdec_dev *rkvdec = ctx->dev;
 
-	dma_free_coherent(rkvdec->dev, vp9_ctx->count_tbl.size,
+	dma_free_coherent(rkvdec->main_core->dev, vp9_ctx->count_tbl.size,
 			  vp9_ctx->count_tbl.cpu, vp9_ctx->count_tbl.dma);
-	dma_free_coherent(rkvdec->dev, vp9_ctx->priv_tbl.size,
+	dma_free_coherent(rkvdec->main_core->dev, vp9_ctx->priv_tbl.size,
 			  vp9_ctx->priv_tbl.cpu, vp9_ctx->priv_tbl.dma);
 	kfree(vp9_ctx);
 }
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index db2731af06cf..d3b13132b751 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -11,12 +11,14 @@
 
 #include <linux/hw_bitfield.h>
 #include <linux/clk.h>
+#include <linux/component.h>
 #include <linux/genalloc.h>
 #include <linux/interrupt.h>
 #include <linux/iommu.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
@@ -652,14 +654,11 @@ static int rkvdec_enum_framesizes(struct file *file, void *priv,
 static int rkvdec_querycap(struct file *file, void *priv,
 			   struct v4l2_capability *cap)
 {
-	struct rkvdec_dev *rkvdec = video_drvdata(file);
 	struct video_device *vdev = video_devdata(file);
 
-	strscpy(cap->driver, rkvdec->dev->driver->name,
-		sizeof(cap->driver));
+	strscpy(cap->driver, "rkvdec", sizeof(cap->driver));
 	strscpy(cap->card, vdev->name, sizeof(cap->card));
-	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
-		 rkvdec->dev->driver->name);
+	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:rkvdec");
 	return 0;
 }
 
@@ -1026,8 +1025,6 @@ 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);
@@ -1062,26 +1059,28 @@ static const struct media_device_ops rkvdec_media_ops = {
 };
 
 static void rkvdec_job_finish_no_pm(struct rkvdec_ctx *ctx,
-				    enum vb2_buffer_state result)
+				  enum vb2_buffer_state result)
 {
+	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
+	struct v4l2_m2m_dev *m2m_dev = m2m_ctx->m2m_dev;
+
 	if (ctx->coded_fmt_desc->ops->done) {
 		struct vb2_v4l2_buffer *src_buf, *dst_buf;
 
-		src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
-		dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+		src_buf = v4l2_m2m_next_src_buf(m2m_ctx);
+		dst_buf = v4l2_m2m_next_dst_buf(m2m_ctx);
 		ctx->coded_fmt_desc->ops->done(ctx, src_buf, dst_buf, result);
 	}
 
-	v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx,
-					 result);
+	v4l2_m2m_buf_done_and_job_finish(m2m_dev, m2m_ctx, result);
 }
 
 static void rkvdec_job_finish(struct rkvdec_ctx *ctx,
-			      enum vb2_buffer_state result)
+			    enum vb2_buffer_state result)
 {
-	struct rkvdec_dev *rkvdec = ctx->dev;
+	pm_runtime_mark_last_busy(ctx->core->dev);
+	pm_runtime_put_autosuspend(ctx->core->dev);
 
-	pm_runtime_put_autosuspend(rkvdec->dev);
 	rkvdec_job_finish_no_pm(ctx, result);
 }
 
@@ -1112,14 +1111,14 @@ void rkvdec_run_postamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run)
 
 void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx)
 {
-	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_core *core = ctx->core;
 	u32 reg;
 
 	/* Set undocumented swreg_block_gating_e field */
-	reg = readl(rkvdec->regs + RKVDEC_REG_QOS_CTRL);
+	reg = readl(core->regs + RKVDEC_REG_QOS_CTRL);
 	reg &= GENMASK(31, 16);
 	reg |= 0xEFFF;
-	writel(reg, rkvdec->regs + RKVDEC_REG_QOS_CTRL);
+	writel(reg, core->regs + RKVDEC_REG_QOS_CTRL);
 }
 
 void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len)
@@ -1131,40 +1130,42 @@ void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len)
 #endif
 }
 
-void rkvdec_schedule_watchdog(struct rkvdec_dev *rkvdec, u32 timeout_threshold)
+void rkvdec_schedule_watchdog(struct rkvdec_core *core, u32 timeout_threshold)
 {
 	/* Set watchdog at 2 times the hardware timeout threshold */
 	u32 watchdog_time;
-	unsigned long axi_rate = clk_get_rate(rkvdec->axi_clk);
+	unsigned long axi_rate = clk_get_rate(core->axi_clk);
 
 	if (axi_rate)
 		watchdog_time = 2 * div_u64(1000 * (u64)timeout_threshold, axi_rate);
 	else
 		watchdog_time = 2000;
 
-	schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(watchdog_time));
+	schedule_delayed_work(&core->watchdog_work, msecs_to_jiffies(watchdog_time));
 }
 
 static void rkvdec_device_run(void *priv)
 {
 	struct rkvdec_ctx *ctx = priv;
-	struct rkvdec_dev *rkvdec = ctx->dev;
 	const struct rkvdec_coded_fmt_desc *desc = ctx->coded_fmt_desc;
 	int ret;
 
 	if (WARN_ON(!desc))
 		return;
 
-	ret = pm_runtime_resume_and_get(rkvdec->dev);
+	ctx->core = ctx->dev->main_core;
+	ctx->core->curr_ctx = ctx;
+
+	ret = pm_runtime_resume_and_get(ctx->core->dev);
 	if (ret < 0) {
 		rkvdec_job_finish_no_pm(ctx, VB2_BUF_STATE_ERROR);
 		return;
 	}
 
 	if (!rkvdec_rcb_buf_validate_size(ctx)) {
-		rkvdec_free_rcb(ctx);
+		rkvdec_free_rcb(ctx->dev, ctx->core);
 
-		ret = rkvdec_allocate_rcb(ctx,
+		ret = rkvdec_allocate_rcb(ctx->dev, ctx->core,
 					  ctx->decoded_fmt.fmt.pix_mp.width,
 					  ctx->decoded_fmt.fmt.pix_mp.height,
 					  ctx->dev->variant->rcb_sizes,
@@ -1340,10 +1341,11 @@ static const struct v4l2_file_operations rkvdec_fops = {
 static int rkvdec_v4l2_init(struct rkvdec_dev *rkvdec)
 {
 	int ret;
+	struct device *dev = rkvdec->main_core->dev;
 
-	ret = v4l2_device_register(rkvdec->dev, &rkvdec->v4l2_dev);
+	ret = v4l2_device_register(dev, &rkvdec->v4l2_dev);
 	if (ret) {
-		dev_err(rkvdec->dev, "Failed to register V4L2 device\n");
+		dev_err(dev, "Failed to register V4L2 device\n");
 		return ret;
 	}
 
@@ -1354,7 +1356,7 @@ static int rkvdec_v4l2_init(struct rkvdec_dev *rkvdec)
 		goto err_unregister_v4l2;
 	}
 
-	rkvdec->mdev.dev = rkvdec->dev;
+	rkvdec->mdev.dev = dev;
 	strscpy(rkvdec->mdev.model, "rkvdec", sizeof(rkvdec->mdev.model));
 	strscpy(rkvdec->mdev.bus_info, "platform:rkvdec",
 		sizeof(rkvdec->mdev.bus_info));
@@ -1420,9 +1422,9 @@ static void rkvdec_v4l2_cleanup(struct rkvdec_dev *rkvdec)
 	v4l2_device_unregister(&rkvdec->v4l2_dev);
 }
 
-static void rkvdec_iommu_restore(struct rkvdec_dev *rkvdec)
+static void rkvdec_iommu_restore(struct rkvdec_core *core)
 {
-	if (rkvdec->empty_domain) {
+	if (core->empty_domain) {
 		/*
 		 * To rewrite mapping into the attached IOMMU core, attach a new empty domain that
 		 * will program an empty table, then detach it to restore the default domain and
@@ -1430,29 +1432,29 @@ static void rkvdec_iommu_restore(struct rkvdec_dev *rkvdec)
 		 * This is safely done in this interrupt handler to make sure no memory get mapped
 		 * through the IOMMU while the empty domain is attached.
 		 */
-		iommu_attach_device(rkvdec->empty_domain, rkvdec->dev);
-		iommu_detach_device(rkvdec->empty_domain, rkvdec->dev);
+		iommu_attach_device(core->empty_domain, core->dev);
+		iommu_detach_device(core->empty_domain, core->dev);
 	}
 }
 
 static irqreturn_t rk3399_irq_handler(struct rkvdec_ctx *ctx)
 {
-	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_core *core = ctx->core;
 	enum vb2_buffer_state state;
 	u32 status;
 
-	status = readl(rkvdec->regs + RKVDEC_REG_INTERRUPT);
-	writel(0, rkvdec->regs + RKVDEC_REG_INTERRUPT);
+	status = readl(core->regs + RKVDEC_REG_INTERRUPT);
+	writel(0, core->regs + RKVDEC_REG_INTERRUPT);
 
 	if (status & RKVDEC_RDY_STA) {
 		state = VB2_BUF_STATE_DONE;
 	} else {
 		state = VB2_BUF_STATE_ERROR;
 		if (status & RKVDEC_SOFTRESET_RDY)
-			rkvdec_iommu_restore(rkvdec);
+			rkvdec_iommu_restore(core);
 	}
 
-	if (cancel_delayed_work(&rkvdec->watchdog_work))
+	if (cancel_delayed_work(&core->watchdog_work))
 		rkvdec_job_finish(ctx, state);
 
 	return IRQ_HANDLED;
@@ -1460,12 +1462,12 @@ static irqreturn_t rk3399_irq_handler(struct rkvdec_ctx *ctx)
 
 static irqreturn_t vdpu381_irq_handler(struct rkvdec_ctx *ctx)
 {
-	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_core *core = ctx->core;
 	enum vb2_buffer_state state;
 	u32 status;
 
-	status = readl(rkvdec->regs + VDPU381_REG_STA_INT);
-	writel(0, rkvdec->regs + VDPU381_REG_STA_INT);
+	status = readl(core->regs + VDPU381_REG_STA_INT);
+	writel(0, core->regs + VDPU381_REG_STA_INT);
 
 	if (status & VDPU381_STA_INT_DEC_RDY_STA) {
 		state = VB2_BUF_STATE_DONE;
@@ -1474,10 +1476,10 @@ static irqreturn_t vdpu381_irq_handler(struct rkvdec_ctx *ctx)
 		if (status & (VDPU381_STA_INT_SOFTRESET_RDY |
 			      VDPU381_STA_INT_TIMEOUT |
 			      VDPU381_STA_INT_ERROR))
-			rkvdec_iommu_restore(rkvdec);
+			rkvdec_iommu_restore(core);
 	}
 
-	if (cancel_delayed_work(&rkvdec->watchdog_work))
+	if (cancel_delayed_work(&core->watchdog_work))
 		rkvdec_job_finish(ctx, state);
 
 	return IRQ_HANDLED;
@@ -1485,24 +1487,24 @@ static irqreturn_t vdpu381_irq_handler(struct rkvdec_ctx *ctx)
 
 static irqreturn_t vdpu383_irq_handler(struct rkvdec_ctx *ctx)
 {
-	struct rkvdec_dev *rkvdec = ctx->dev;
+	struct rkvdec_core *core = ctx->core;
 	enum vb2_buffer_state state;
 	u32 status;
 
-	status = readl(rkvdec->link + VDPU383_LINK_STA_INT);
-	writel(FIELD_PREP_WM16(VDPU383_STA_INT_ALL, 0), rkvdec->link + VDPU383_LINK_STA_INT);
+	status = readl(core->link + VDPU383_LINK_STA_INT);
+	writel(FIELD_PREP_WM16(VDPU383_STA_INT_ALL, 0), core->link + VDPU383_LINK_STA_INT);
 	/* On vdpu383, the interrupts must be disabled */
 	writel(FIELD_PREP_WM16(VDPU383_INT_EN_IRQ | VDPU383_INT_EN_LINE_IRQ, 0),
-	       rkvdec->link + VDPU383_LINK_INT_EN);
+	       core->link + VDPU383_LINK_INT_EN);
 
 	if (status & VDPU383_STA_INT_DEC_RDY_STA) {
 		state = VB2_BUF_STATE_DONE;
 	} else {
 		state = VB2_BUF_STATE_ERROR;
-		rkvdec_iommu_restore(rkvdec);
+		rkvdec_iommu_restore(core);
 	}
 
-	if (cancel_delayed_work(&rkvdec->watchdog_work))
+	if (cancel_delayed_work(&core->watchdog_work))
 		rkvdec_job_finish(ctx, state);
 
 	return IRQ_HANDLED;
@@ -1510,11 +1512,14 @@ static irqreturn_t vdpu383_irq_handler(struct rkvdec_ctx *ctx)
 
 static irqreturn_t rkvdec_irq_handler(int irq, void *priv)
 {
-	struct rkvdec_dev *rkvdec = priv;
-	struct rkvdec_ctx *ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev);
-	const struct rkvdec_variant *variant = rkvdec->variant;
+	irqreturn_t ret;
+	struct rkvdec_core *core = priv;
+	struct rkvdec_ctx *ctx = core->curr_ctx;
+	const struct rkvdec_variant *variant = ctx->dev->variant;
+
+	ret = variant->ops->irq_handler(ctx);
 
-	return variant->ops->irq_handler(ctx);
+	return ret;
 }
 
 /*
@@ -1591,62 +1596,19 @@ static void vdpu383_flatten_matrices(u8 *output, const u8 *input, int matrices,
 
 static void rkvdec_watchdog_func(struct work_struct *work)
 {
-	struct rkvdec_dev *rkvdec;
+	struct rkvdec_core *core;
 	struct rkvdec_ctx *ctx;
 
-	rkvdec = container_of(to_delayed_work(work), struct rkvdec_dev,
+	core = container_of(to_delayed_work(work), struct rkvdec_core,
 			      watchdog_work);
-	ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev);
+	ctx = core->curr_ctx;
 	if (ctx) {
-		dev_err(rkvdec->dev, "Frame processing timed out!\n");
-		writel(RKVDEC_IRQ_DIS, rkvdec->regs + RKVDEC_REG_INTERRUPT);
+		dev_err(core->dev, "Frame processing timed out!\n");
+		writel(RKVDEC_IRQ_DIS, core->regs + RKVDEC_REG_INTERRUPT);
 		rkvdec_job_finish(ctx, VB2_BUF_STATE_ERROR);
 	}
 }
 
-/*
- * Some SoCs, like RK3588 have multiple identical VDPU cores, but the
- * kernel is currently missing support for multi-core handling. Exposing
- * separate devices for each core to userspace is bad, since that does
- * not allow scheduling tasks properly (and creates ABI). With this workaround
- * the driver will only probe for the first core and early exit for the other
- * cores. Once the driver gains multi-core support, the same technique
- * for detecting the first core can be used to cluster all cores together.
- */
-static int rkvdec_disable_multicore(struct rkvdec_dev *rkvdec)
-{
-	struct device_node *node = NULL;
-	const char *compatible;
-	bool is_first_core;
-	int ret;
-
-	/* Intentionally ignores the fallback strings */
-	ret = of_property_read_string(rkvdec->dev->of_node, "compatible", &compatible);
-	if (ret)
-		return ret;
-
-	/* The first compatible and available node found is considered the main core */
-	do {
-		node = of_find_compatible_node(node, NULL, compatible);
-		if (of_device_is_available(node))
-			break;
-	} while (node);
-
-	if (!node)
-		return -EINVAL;
-
-	is_first_core = (rkvdec->dev->of_node == node);
-
-	of_node_put(node);
-
-	if (!is_first_core) {
-		dev_info(rkvdec->dev, "missing multi-core support, ignoring this instance\n");
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
 static const struct rkvdec_variant_ops rk3399_variant_ops = {
 	.irq_handler = rk3399_irq_handler,
 	.colmv_size = rkvdec_colmv_size,
@@ -1757,49 +1719,75 @@ static const struct of_device_id of_rkvdec_match[] = {
 };
 MODULE_DEVICE_TABLE(of, of_rkvdec_match);
 
-static int rkvdec_probe(struct platform_device *pdev)
+static int rkvdec_core_bind(struct device *dev, struct device *master, void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rkvdec_core *core = platform_get_drvdata(pdev);
+	struct rkvdec_dev *rkvdec = data;
+
+	if (rkvdec->main_core)
+		return dev_err_probe(dev, -EBUSY,
+				     "rkvdec already has a bound core\n");
+
+	rkvdec->main_core = core;
+
+	dev_info(dev, "Registered core\n");
+
+	return 0;
+}
+
+static const struct component_ops rkvdec_core_ops = {
+	.bind = rkvdec_core_bind,
+};
+
+static int rkvdec_core_probe(struct platform_device *pdev)
 {
 	const struct rkvdec_variant *variant;
-	struct rkvdec_dev *rkvdec;
+	struct rkvdec_core *core;
 	int ret, irq;
 
+	if (!pdev->dev.of_node)
+		return -ENODEV;
+
 	variant = of_device_get_match_data(&pdev->dev);
 	if (!variant)
-		return -EINVAL;
+		return dev_err_probe(&pdev->dev, -ENODEV, "failed to get match data\n");
 
-	rkvdec = devm_kzalloc(&pdev->dev, sizeof(*rkvdec), GFP_KERNEL);
-	if (!rkvdec)
+	core = devm_kzalloc(&pdev->dev, sizeof(*core), GFP_KERNEL);
+	if (!core)
 		return -ENOMEM;
 
-	platform_set_drvdata(pdev, rkvdec);
-	rkvdec->dev = &pdev->dev;
-	rkvdec->variant = variant;
-	mutex_init(&rkvdec->vdev_lock);
-	INIT_DELAYED_WORK(&rkvdec->watchdog_work, rkvdec_watchdog_func);
-
-	ret = rkvdec_disable_multicore(rkvdec);
-	if (ret)
-		return ret;
+	core->dev = &pdev->dev;
+	INIT_DELAYED_WORK(&core->watchdog_work, rkvdec_watchdog_func);
 
-	ret = devm_clk_bulk_get_all_enabled(&pdev->dev, &rkvdec->clocks);
+	ret = devm_clk_bulk_get_all_enabled(&pdev->dev, &core->clocks);
 	if (ret < 0)
 		return ret;
+	core->num_clocks = ret;
 
-	rkvdec->num_clocks = ret;
-	rkvdec->axi_clk = devm_clk_get(&pdev->dev, "axi");
+	core->axi_clk = devm_clk_get(&pdev->dev, "axi");
 
-	if (rkvdec->variant->has_single_reg_region) {
-		rkvdec->regs = devm_platform_ioremap_resource(pdev, 0);
-		if (IS_ERR(rkvdec->regs))
-			return PTR_ERR(rkvdec->regs);
+	if (variant->has_single_reg_region) {
+		core->regs = devm_platform_ioremap_resource(pdev, 0);
+		if (IS_ERR(core->regs))
+			return PTR_ERR(core->regs);
 	} else {
-		rkvdec->regs = devm_platform_ioremap_resource_byname(pdev, "function");
-		if (IS_ERR(rkvdec->regs))
-			return PTR_ERR(rkvdec->regs);
+		core->regs = devm_platform_ioremap_resource_byname(pdev, "function");
+		if (IS_ERR(core->regs))
+			return PTR_ERR(core->regs);
+
+		core->link = devm_platform_ioremap_resource_byname(pdev, "link");
+		if (IS_ERR(core->link))
+			return PTR_ERR(core->link);
+	}
+
+	if (iommu_get_domain_for_dev(&pdev->dev)) {
+		core->empty_domain = iommu_paging_domain_alloc(core->dev);
 
-		rkvdec->link = devm_platform_ioremap_resource_byname(pdev, "link");
-		if (IS_ERR(rkvdec->link))
-			return PTR_ERR(rkvdec->link);
+		if (IS_ERR(core->empty_domain)) {
+			dev_warn(core->dev, "cannot alloc new empty domain\n");
+			core->empty_domain = NULL;
+		}
 	}
 
 	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
@@ -1816,32 +1804,26 @@ static int rkvdec_probe(struct platform_device *pdev)
 
 	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
 					rkvdec_irq_handler, IRQF_ONESHOT,
-					dev_name(&pdev->dev), rkvdec);
+					dev_name(&pdev->dev), core);
 	if (ret) {
-		dev_err(&pdev->dev, "Could not request vdec IRQ\n");
+		dev_err(&pdev->dev, "Could not request core IRQ\n");
 		return ret;
 	}
 
-	rkvdec->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0);
-	if (!rkvdec->sram_pool && rkvdec->variant->num_rcb_sizes > 0)
+	core->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0);
+	if (!core->sram_pool && 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);
 
-	ret = rkvdec_v4l2_init(rkvdec);
-	if (ret)
-		goto err_disable_runtime_pm;
+	platform_set_drvdata(pdev, core);
 
-	rkvdec->iommu_domain = iommu_get_domain_for_dev(&pdev->dev);
-	if (rkvdec->iommu_domain) {
-		rkvdec->empty_domain = iommu_paging_domain_alloc(rkvdec->dev);
-
-		if (IS_ERR(rkvdec->empty_domain)) {
-			rkvdec->empty_domain = NULL;
-			dev_warn(rkvdec->dev, "cannot alloc new empty domain\n");
-		}
+	ret = component_add(&pdev->dev, &rkvdec_core_ops);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to register component: %d\n", ret);
+		goto err_disable_runtime_pm;
 	}
 
 	return 0;
@@ -1849,60 +1831,254 @@ 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);
+	if (core->empty_domain)
+		iommu_domain_free(core->empty_domain);
 
 	return ret;
 }
 
-static void rkvdec_remove(struct platform_device *pdev)
+static void rkvdec_core_remove(struct platform_device *pdev)
 {
-	struct rkvdec_dev *rkvdec = platform_get_drvdata(pdev);
+	struct rkvdec_core *core = platform_get_drvdata(pdev);
 
-	cancel_delayed_work_sync(&rkvdec->watchdog_work);
+	component_del(&pdev->dev, &rkvdec_core_ops);
 
-	rkvdec_v4l2_cleanup(rkvdec);
-	pm_runtime_disable(&pdev->dev);
 	pm_runtime_dont_use_autosuspend(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
 
-	if (rkvdec->empty_domain)
-		iommu_domain_free(rkvdec->empty_domain);
+	if (core->empty_domain)
+		iommu_domain_free(core->empty_domain);
 }
 
 #ifdef CONFIG_PM
-static int rkvdec_runtime_resume(struct device *dev)
+static int rkvdec_core_runtime_resume(struct device *dev)
 {
-	struct rkvdec_dev *rkvdec = dev_get_drvdata(dev);
+	struct rkvdec_core *core = dev_get_drvdata(dev);
 
-	return clk_bulk_prepare_enable(rkvdec->num_clocks, rkvdec->clocks);
+	return clk_bulk_prepare_enable(core->num_clocks, core->clocks);
 }
 
-static int rkvdec_runtime_suspend(struct device *dev)
+static int rkvdec_core_runtime_suspend(struct device *dev)
 {
-	struct rkvdec_dev *rkvdec = dev_get_drvdata(dev);
+	struct rkvdec_core *core = dev_get_drvdata(dev);
+
+	clk_bulk_disable_unprepare(core->num_clocks, core->clocks);
 
-	clk_bulk_disable_unprepare(rkvdec->num_clocks, rkvdec->clocks);
 	return 0;
 }
 #endif
 
-static const struct dev_pm_ops rkvdec_pm_ops = {
+static const struct dev_pm_ops rkvdec_core_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
 				pm_runtime_force_resume)
-	SET_RUNTIME_PM_OPS(rkvdec_runtime_suspend, rkvdec_runtime_resume, NULL)
+	SET_RUNTIME_PM_OPS(rkvdec_core_runtime_suspend,
+			   rkvdec_core_runtime_resume, NULL)
+};
+
+static struct platform_driver rkvdec_core_pdrv = {
+	.probe = rkvdec_core_probe,
+	.remove = rkvdec_core_remove,
+	.driver = {
+		   .name = "rkvdec-core",
+		   .of_match_table = of_rkvdec_match,
+		   .pm = &rkvdec_core_pm_ops,
+	},
+};
+
+static int rkvdec_bind(struct device *dev)
+{
+	struct rkvdec_dev *rkvdec = dev_get_drvdata(dev);
+	int ret;
+
+	ret = component_bind_all(dev, rkvdec);
+	if (ret) {
+		dev_err(dev, "component bind failed\n");
+		return ret;
+	}
+
+	ret = rkvdec_v4l2_init(rkvdec);
+	if (ret)
+		goto err_unbind;
+
+	return 0;
+
+err_unbind:
+	component_unbind_all(dev, NULL);
+	return ret;
+}
+
+static void rkvdec_unbind(struct device *dev)
+{
+	struct rkvdec_dev *rkvdec = dev_get_drvdata(dev);
+
+	cancel_delayed_work_sync(&rkvdec->main_core->watchdog_work);
+
+	rkvdec_v4l2_cleanup(rkvdec);
+
+	rkvdec_free_rcb(rkvdec, rkvdec->main_core);
+
+	component_unbind_all(dev, NULL);
+}
+
+static const struct component_master_ops rkvdec_master_ops = {
+	.bind = rkvdec_bind,
+	.unbind = rkvdec_unbind,
 };
 
-static struct platform_driver rkvdec_driver = {
+static int rkvdec_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *match_desc = pdev->dev.platform_data;
+	struct device *dev = &pdev->dev;
+	struct component_match *match = NULL;
+	struct device_node *core_node;
+	struct rkvdec_dev *rkvdec;
+
+	if (!match_desc)
+		return dev_err_probe(dev, -ENODEV, "missing platform data\n");
+
+	for_each_compatible_node(core_node, NULL, match_desc->compatible) {
+		if (!of_device_is_available(core_node))
+			continue;
+
+		of_node_get(core_node);
+		component_match_add_release(dev, &match, component_release_of,
+					    component_compare_of, core_node);
+	}
+
+	if (!match)
+		return dev_err_probe(dev, -ENODEV,
+				     "no matching available component devices found\n");
+
+	rkvdec = devm_kzalloc(dev, sizeof(*rkvdec), GFP_KERNEL);
+	if (!rkvdec)
+		return -ENOMEM;
+
+	rkvdec->variant = match_desc->data;
+	if (!rkvdec->variant)
+		return dev_err_probe(dev, -ENODEV, "failed to get match data\n");
+
+	mutex_init(&rkvdec->vdev_lock);
+
+	dev_set_drvdata(dev, rkvdec);
+
+	return component_master_add_with_match(dev, &rkvdec_master_ops, match);
+}
+
+static void rkvdec_remove(struct platform_device *pdev)
+{
+	component_master_del(&pdev->dev, &rkvdec_master_ops);
+}
+
+static struct platform_driver rkvdec_pdrv = {
 	.probe = rkvdec_probe,
 	.remove = rkvdec_remove,
 	.driver = {
-		   .name = "rkvdec",
-		   .of_match_table = of_rkvdec_match,
-		   .pm = &rkvdec_pm_ops,
+		.name = "rkvdec",
 	},
 };
-module_platform_driver(rkvdec_driver);
+
+static bool rkvdec_of_has_available_node(const char *compat)
+{
+	struct device_node *node;
+
+	for_each_compatible_node(node, NULL, compat) {
+		if (of_device_is_available(node)) {
+			of_node_put(node);
+			return true;
+		}
+	}
+
+	return false;
+}
+
+static int rkvdec_create_platform_device(struct platform_device **ppdev,
+					 const struct of_device_id *match)
+{
+	struct platform_device *pdev;
+	int ret;
+
+	pdev = platform_device_alloc(match->compatible, PLATFORM_DEVID_NONE);
+	if (!pdev)
+		return -ENOMEM;
+
+	ret = platform_device_add_data(pdev, match, sizeof(*match));
+	if (ret)
+		goto free_platform_device;
+
+	ret = platform_device_add(pdev);
+	if (ret)
+		goto free_platform_device;
+
+	ret = device_driver_attach(&rkvdec_pdrv.driver, &pdev->dev);
+	if (ret)
+		goto del_platform_device;
+
+	*ppdev = pdev;
+
+	return 0;
+
+del_platform_device:
+	platform_device_del(pdev);
+free_platform_device:
+	platform_device_put(pdev);
+	return ret;
+}
+
+static struct platform_device *master_pdevs[ARRAY_SIZE(of_rkvdec_match) - 1];
+
+static int __init rkvdec_init(void)
+{
+	unsigned int i;
+	int ret;
+
+	ret = platform_driver_register(&rkvdec_core_pdrv);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&rkvdec_pdrv);
+	if (ret)
+		goto unregister_core_driver;
+
+	for (i = 0; i < ARRAY_SIZE(master_pdevs); i++) {
+		if (!rkvdec_of_has_available_node(of_rkvdec_match[i].compatible))
+			continue;
+
+		ret = rkvdec_create_platform_device(&master_pdevs[i],
+						    &of_rkvdec_match[i]);
+		if (ret)
+			goto unregister_platform_devices;
+	}
+
+	return 0;
+
+unregister_platform_devices:
+	for (i = 0; i < ARRAY_SIZE(master_pdevs); i++) {
+		if (master_pdevs[i]) {
+			platform_device_unregister(master_pdevs[i]);
+			master_pdevs[i] = NULL;
+		}
+	}
+	platform_driver_unregister(&rkvdec_pdrv);
+unregister_core_driver:
+	platform_driver_unregister(&rkvdec_core_pdrv);
+	return ret;
+}
+module_init(rkvdec_init);
+
+static void __exit rkvdec_exit(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(master_pdevs); i++) {
+		if (master_pdevs[i]) {
+			platform_device_unregister(master_pdevs[i]);
+			master_pdevs[i] = NULL;
+		}
+	}
+	platform_driver_unregister(&rkvdec_pdrv);
+	platform_driver_unregister(&rkvdec_core_pdrv);
+}
+module_exit(rkvdec_exit);
 
 MODULE_AUTHOR("Boris Brezillon <boris.brezillon@collabora.com>");
 MODULE_DESCRIPTION("Rockchip Video Decoder driver");
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
index a24be6638b6b..36eadcfcabdb 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
@@ -125,23 +125,28 @@ struct rkvdec_coded_fmt_desc {
 	u32 subsystem_flags;
 };
 
-struct rkvdec_dev {
-	struct v4l2_device v4l2_dev;
-	struct media_device mdev;
-	struct video_device vdev;
-	struct v4l2_m2m_dev *m2m_dev;
+struct rkvdec_core {
 	struct device *dev;
 	struct clk_bulk_data *clocks;
 	unsigned int num_clocks;
 	struct clk *axi_clk;
 	void __iomem *regs;
 	void __iomem *link;
-	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_rcb_config *rcb_config;
+	struct rkvdec_ctx *curr_ctx;
+};
+
+struct rkvdec_dev {
+	struct v4l2_device v4l2_dev;
+	struct media_device mdev;
+	struct video_device vdev;
+	struct v4l2_m2m_dev *m2m_dev;
+	struct mutex vdev_lock; /* serializes ioctls */
 	const struct rkvdec_variant *variant;
+	struct rkvdec_core *main_core;
 };
 
 struct rkvdec_ctx {
@@ -152,8 +157,8 @@ 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;
 	u32 colmv_offset;
+	struct rkvdec_core *core;
 	void *priv;
 	u8 has_sps_st_rps: 1;
 	u8 has_sps_lt_rps: 1;
@@ -179,7 +184,7 @@ struct rkvdec_aux_buf {
 void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);
 void rkvdec_run_postamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);
 void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len);
-void rkvdec_schedule_watchdog(struct rkvdec_dev *rkvdec, u32 timeout_threshold);
+void rkvdec_schedule_watchdog(struct rkvdec_core *core, u32 timeout_threshold);
 
 void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx);
 

-- 
2.55.0



  parent reply	other threads:[~2026-08-10 15:22 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-10 15:22 [PATCH v2 0/5] media: rkvdec: Enable multi-core support Detlev Casanova
2026-08-10 15:22 ` [PATCH v2 1/5] media: rkvdec: Keep RCB to the correct size Detlev Casanova
2026-08-10 15:22 ` [PATCH v2 2/5] media: rkvdec: Remove unused need_reset Detlev Casanova
2026-08-10 15:22 ` [PATCH v2 3/5] v4l2: export v4l2_m2m_set_max_parallel_jobs Detlev Casanova
2026-08-10 15:22 ` Detlev Casanova [this message]
2026-08-10 15:22 ` [PATCH v2 5/5] media: rkvdec: Add multicore support Detlev Casanova

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260810-rkvdec-multicore-v2-4-986f89d22cdc@collabora.com \
    --to=detlev.casanova@collabora.com \
    --cc=ezequiel@vanguardiasur.com.ar \
    --cc=heiko@sntech.de \
    --cc=hverkuil+cisco@kernel.org \
    --cc=jonas@kwiboo.se \
    --cc=kernel@collabora.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=linux-rockchip@lists.infradead.org \
    --cc=mchehab@kernel.org \
    --cc=nicolas.dufresne@collabora.com \
    --cc=s.pueschel@pengutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox