From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id BCA7DC5AD7B for ; Mon, 10 Aug 2026 15:22:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References :Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=vqihGsirOvjtMSMz5xyeMjclPA4lP+0QIk+fMmAAdYQ=; b=OcuQcsigC3tb7EaGtVgjbOce9W 8u4qf14eC/kUUJnfhlKSgpLOPTPX/d8g+SlyDrS4LnRgUxFEm+Obl88XpCVeY812PdJvWVS3vq4Lw gyoH3zZlwnwjDdvkqeIcrWRttbqz//X7P93+hSyoRzqHRvpBrhkz/CL7ypE847HvablLVBgM6Lk0c NTbozWToxhJ1GGb/rkWPDMISeP1HqLNv7K+hPzaSuQCDHhMrEBbKbOZA/wHSexDlNMo8qKfSYPZ3P R/yzu+Vl3uR3/z1O9V2Bd950dBNhUgzlfm+FmengbRibYomFVD3uj4xoqe6lCrTCsXoSlnqWHD+h7 ZfcM9Cjw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.99.1 #2 (Red Hat Linux)) id 1wtRpk-0000000CDWE-22RE; Mon, 10 Aug 2026 15:22:36 +0000 Received: from bali.collaboradmins.com ([148.251.105.195]) by bombadil.infradead.org with esmtps (Exim 4.99.1 #2 (Red Hat Linux)) id 1wtRpe-0000000CDMo-3AZ6; Mon, 10 Aug 2026 15:22:34 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1786375348; bh=auOzmHsFn0rFEi5FtlFoqqg8Y9HPG59fE0Dm5z3CiBk=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=WbPHhxtRSFCP9G8z/DOhV4JBXa5wokISgDvP7v5lgNnOAasEavjFt3c3BvPTlg6dT ZYeRTRbniJa8MARqG+BIWMdiqE+jUmcv0A/puWgct5+A9Z3d76tcXTjMvNSr2wzYej T8BxFdZElF7XBy0d/GS+is7pva5bueu96c9vylYq1t+mM1wIGQabbtLIwt1ONeWNVt D2bav9AlxbZaQGVN2uDHERkAeyuplYvbkK8lpIIQ6BYUCCicnL4ilRYxhlSvwdLitf 93StBb5om9+6WiQ6bUjU6VjctWoH2d5NSTCOIBSZLBNL30abeVnjmhy4gvJvHbJaN/ Yd4tqNqgml+Qw== Received: from [192.168.0.15] (unknown [100.64.0.170]) (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 02F4917E0D7E; Mon, 10 Aug 2026 17:22:26 +0200 (CEST) From: Detlev Casanova Date: Mon, 10 Aug 2026 11:22:14 -0400 Subject: [PATCH v2 4/5] media: rkvdec: Split into core and master platform drivers MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20260810-rkvdec-multicore-v2-4-986f89d22cdc@collabora.com> References: <20260810-rkvdec-multicore-v2-0-986f89d22cdc@collabora.com> In-Reply-To: <20260810-rkvdec-multicore-v2-0-986f89d22cdc@collabora.com> To: Mauro Carvalho Chehab , Ezequiel Garcia , Heiko Stuebner , Nicolas Dufresne , Hans Verkuil , Jonas Karlman Cc: =?utf-8?q?Sven_P=C3=BCschel?= , 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 X-Mailer: b4 0.15.2 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.9.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20260810_082231_424374_139F5BE6 X-CRM114-Status: GOOD ( 21.60 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org 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 --- .../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 +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 #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -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 "); 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