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 2C0B1C61DF0 for ; Mon, 31 Aug 2026 04:10:26 +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:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=dkrqqZhM7WlyaP2wiDCA1VTmGxSMLxzEHskNyNB2USg=; b=v3KiTCOX9UGo8gjDMqRGAKqIge sGP2XHelfT7u187DuJefCpl/QaK9jFHI+Sb/Cj0d5bn9oLDFlGIhCUQKMhOaPxpf3aKTajtWbhf6v VErUXnnnKRyPQZEHI8H/PiUh4DyweG/FIKWNW5YK0x574oPE22lDsGV8dcizgNkNO2bFrc9dNaZru S4xAJocmlZC1P3eQFKRs9HjdGFNodCt0h/WxAvhaq8zjJVLgtSiWWHH/7ctZQ2tR/3mc9yboFjzbd xcjjyVFGmCrFv9ov9WysLLeEhbBLrJDXr29D16gNnrfca7BN+XrUyB7eOkri89YfnjFp00bNNcZw+ opG2xUUw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.99.1 #2 (Red Hat Linux)) id 1x0tLb-00000008SPH-1nou; Mon, 31 Aug 2026 04:10:15 +0000 Received: from fhigh-b1-smtp.messagingengine.com ([202.12.124.152]) by bombadil.infradead.org with esmtps (Exim 4.99.1 #2 (Red Hat Linux)) id 1x0tLY-00000008SMT-1zTj; Mon, 31 Aug 2026 04:10:13 +0000 Received: from phl-compute-03.internal (phl-compute-03.internal [10.202.2.43]) by mailfhigh.stl.internal (Postfix) with ESMTP id 278D87A00F3; Mon, 31 Aug 2026 00:10:11 -0400 (EDT) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-03.internal (MEProxy); Mon, 31 Aug 2026 00:10:11 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gahingwoo.com; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm2; t=1788149411; x= 1788235811; bh=dkrqqZhM7WlyaP2wiDCA1VTmGxSMLxzEHskNyNB2USg=; b=R mFtFEcfH3AygIP32TW89vQzSeflivZfWNaFoGlbsgUvO0K0IzCVWIUJLZyDf63f6 d31USqSSPsV/Uajw2nOhfZsaDDFePfp+hUrUqF4Q4eUqcO/W9XKWdOrNVczRyqhT RND/OguBJ/8E/DcA7LpdxO/klr7f3/ww03jYA3X5CHb+I83VydubxDPi0l5Layp/ InkWGL6tOV654iWm2DZrRkDzecxnRHOA8H6zcwKdH5/CA6WgRdSho362Ucp/vyCd tLZoKsajsp3Khx9L4M64/uw+n/XI3/XPJ8ADPCK5SnR2Pvu3PtCb33Uy8RW65pW1 nLSaC8bbUzjF7DPgGsBzQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm3; t=1788149411; x=1788235811; bh=d krqqZhM7WlyaP2wiDCA1VTmGxSMLxzEHskNyNB2USg=; b=UwecJr2XXSZxOgLQW /BAwnf2vMKQgge547QkNi/RLWHQc+Wg9kiiYVtUQbmLA47i5WaA+xjNq1xwCC9W+ 7WtwMtEBif/8ctymROb2rj4Tk1+jtPOMv7DAg022MbDhcQzB797MdC3VrL0hvulR Kcf+dSHqOcJKwn3k+Xte/wf8i0/aNEsJ2uFsJst3QanLhAwGmWU1hmpwn93fXFoP ura2drcZ+qw4yjBRVS15K+dkhcHUue7Wd/tGssBNEk5uIQSke3Y+7x89oc4XRsj+ cytFUADi+GB2m3DOJcvzFFMrIzYjBcWfj0Xbydmeh6Xl+cdEt1+eEglNCVIVvfJV AW94A== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTGw3IOwPJckTRSvpM29nlKjSGj+wD8vIPThg3Wssg5jMWRbh2Z4cgZ7GZ++5pW084 vv6JQuTrbsiN3dnNVDHEo7KJ0TSCOKK8QmUV7kniPB44X8mt+PdEKBP4Y8U2Nb6OUZEHSh 3VZQnrewb1ZoIJJ5vzmDk+aeGXPXlG2D0UeSwLTcfZVmEhkLc/q7ND9LLqLVU/iCerjAIo k6VmI5TaiEyGI7sZ6T++ObYjIk+GT+jy3+hZXcGD952OqSszFQFnnylEiG0I/W8uV1Nenq pMo0PTvs+NQZK6Bf+2JtZ87xFd8zFfR2Cn+1D5TYk5nFvHiMwoxRwkHQuQ+T8cLRojVPWe oL7PIEIs6/7Zb0LPMU6otTUYiZ29VaHb1yCDzZIynO35pjc0lK42Ig3nixEt13zn/oUvjj k/Ajw65lQHqoXL353716zc5JTn+YxdByoUq3eg+311VWWv5RSBkdtuwfwvyp1mlLiPHsVu SH3sVHOZscsXuzPhReYYVuIkQyXbCP1/KIa3iGKwSq4Zh6IFTPHE2KfEgU/O+B5DHfH0W5 MVNWzO9Nf020g10gE7g2lWFWiZy1NsBP9kJZ9Gz8znLTaDw2aDWq0kvV49lUh2LmwiTCIM 3TCuJzcc4I3CRfjTykbqRugI5GHlyRU4NuMqJZj2fl4OzI+lYkn4hWOt401w X-ME-Proxy: Feedback-ID: i7a5e4b5f:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 31 Aug 2026 00:10:03 -0400 (EDT) From: Jiaxing Hu To: tomeu@tomeuvizoso.net, heiko@sntech.de, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, joro@8bytes.org, will@kernel.org, robin.murphy@arm.com, ulfh@kernel.org, p.zabel@pengutronix.de, ogabbay@kernel.org, zhangqing@rock-chips.com Cc: royalnet026@gmail.com, u.kleine-koenig@baylibre.com, chaoyi.chen@rock-chips.com, diederik@cknow-tech.com, alchark@flipper.net, dri-devel@lists.freedesktop.org, linux-rockchip@lists.infradead.org, iommu@lists.linux.dev, linux-pm@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Jiaxing Hu Subject: [PATCH v10 11/13] accel/rocket: add RK3576 NPU (RKNN) support Date: Mon, 31 Aug 2026 16:08:02 +1200 Message-ID: <20260831040804.24111-12-gahing@gahingwoo.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260831040804.24111-1-gahing@gahingwoo.com> References: <20260831040804.24111-1-gahing@gahingwoo.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.9.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20260830_211012_612300_98B0C668 X-CRM114-Status: GOOD ( 31.29 ) 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 The RK3576 has two cores of the same RKNN block and a few platform differences: - the CBUF (convolution buffer) has its own clock domain, so the core needs six clocks rather than four; - there is no per-core hclk reset. The CRU has SRST_A_RKNN0 and SRST_A_RKNN1 but no SRST_H_RKNN0 or SRST_H_RKNN1, so a core takes one reset where RK3588 takes two; - the NPU spans two power domains, and a device with more than one is skipped by the driver-core single-domain auto-attach, so the list has to be attached explicitly; - PC_TASK_CON packs the task number with sixteen bits rather than twelve, moving the three controls above it up by four. That last one is the reason this series has been reporting, since v3, that the block accepts exactly one task per reset. rocket_registers.h is generated from the RK3588 description, so writing it unchanged to an RK3576 asks for task_number 0x7001, which is 28673 tasks, and puts TASK_COUNT_CLEAR on a bit that does nothing. The counter is then only ever cleared by a reset. The layout was confirmed by Chaoyi Chen of Rockchip, including a fourth control at BIT(18), task_last_layer_clear, which belongs on every submit alongside the count clear: https://lore.kernel.org/all/4f300b78-d96d-4d98-8819-dc292b0c9b97@rock-chips.com/ With that written correctly a job of several tasks runs to completion, the completion interrupt arrives, and /proc/interrupts counts up. A convolution submitted three times with three different inputs is byte exact against the CPU reference each time, with no reset in between and with nothing retiring the job but the interrupt. Counting the cores now walks the driver's own match table instead of a second, hand-kept list of compatibles. The array sized from that count is indexed by every core that goes on to probe, so the two lists cannot be allowed to disagree. All of it hangs off the soc_data added earlier, so the RK3588 path keeps its existing counts and behaviour. The match table moves to rocket_drv.h so rocket_device.c can walk it with for_each_matching_node() rather than repeating a for_each_compatible_node() loop per SoC, which also keeps num_cores in step with the table that sizes the array it counts into. The declaration needs struct of_device_id, taken from rather than , which carries every subsystem's tables with it. Signed-off-by: Jiaxing Hu --- drivers/accel/rocket/rocket_core.c | 20 +++++++++++++++ drivers/accel/rocket/rocket_core.h | 8 +++--- drivers/accel/rocket/rocket_device.c | 7 ++++- drivers/accel/rocket/rocket_drv.c | 16 +++++++++--- drivers/accel/rocket/rocket_drv.h | 2 ++ drivers/accel/rocket/rocket_job.c | 38 +++++++++++++++++++++++++--- 6 files changed, 80 insertions(+), 11 deletions(-) diff --git a/drivers/accel/rocket/rocket_core.c b/drivers/accel/rocket/rocket_core.c index b202d1581..91f690176 100644 --- a/drivers/accel/rocket/rocket_core.c +++ b/drivers/accel/rocket/rocket_core.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -21,6 +22,7 @@ int rocket_core_init(struct rocket_core *core) u32 version; int err = 0; + /* RK3576 has no per-core hclk reset, so it takes srst_a alone. */ core->resets[0].id = "srst_a"; core->resets[1].id = "srst_h"; err = devm_reset_control_bulk_get_exclusive(&pdev->dev, core->soc->num_resets, @@ -32,6 +34,9 @@ int rocket_core_init(struct rocket_core *core) core->clks[1].id = "hclk"; core->clks[2].id = "npu"; core->clks[3].id = "pclk"; + /* RK3576 clocks the CBUF separately; the compute path stalls without these. */ + core->clks[4].id = "aclk_cbuf"; + core->clks[5].id = "hclk_cbuf"; err = devm_clk_bulk_get(dev, core->soc->num_clks, core->clks); if (err) return dev_err_probe(dev, err, "failed to get clocks for core %d\n", core->index); @@ -60,6 +65,21 @@ int rocket_core_init(struct rocket_core *core) if (err) return err; + /* + * RK3576 spans two power domains, and a multi-domain device is skipped + * by the driver-core single-domain auto-attach, so attach the list here. + * This goes before the first thing that would have to be unwound, so a + * failure can simply return. + */ + if (core->soc->multi_power_domain) { + struct dev_pm_domain_list *pd_list; + + err = devm_pm_domain_attach_list(dev, NULL, &pd_list); + if (err < 0) + return dev_err_probe(dev, err, + "failed to attach NPU power domains\n"); + } + core->iommu_group = iommu_group_get(dev); err = rocket_job_init(core); diff --git a/drivers/accel/rocket/rocket_core.h b/drivers/accel/rocket/rocket_core.h index ba74c5339..8c8d1f453 100644 --- a/drivers/accel/rocket/rocket_core.h +++ b/drivers/accel/rocket/rocket_core.h @@ -29,8 +29,10 @@ /* Per-SoC differences, selected by the of_device_id match data. */ struct rocket_soc_data { - unsigned int num_clks; /* clk_bulk count */ - unsigned int num_resets; /* reset_bulk count */ + unsigned int num_clks; /* clk_bulk count: 4 base, 6 with CBUF */ + unsigned int num_resets; /* reset_bulk count: 2 base, 1 on RK3576 */ + bool multi_power_domain; /* device spans more than one PM domain */ + bool task_con_16bit; /* PC_TASK_CON uses the 16-bit task number */ }; struct rocket_core { @@ -43,7 +45,7 @@ struct rocket_core { void __iomem *pc_iomem; void __iomem *cna_iomem; void __iomem *core_iomem; - struct clk_bulk_data clks[4]; + struct clk_bulk_data clks[6]; struct reset_control_bulk_data resets[2]; struct iommu_group *iommu_group; diff --git a/drivers/accel/rocket/rocket_device.c b/drivers/accel/rocket/rocket_device.c index 46e6ee1e7..923add5bd 100644 --- a/drivers/accel/rocket/rocket_device.c +++ b/drivers/accel/rocket/rocket_device.c @@ -9,6 +9,7 @@ #include #include "rocket_device.h" +#include "rocket_drv.h" struct rocket_device *rocket_device_init(struct platform_device *pdev, const struct drm_driver *rocket_drm_driver) @@ -27,7 +28,11 @@ struct rocket_device *rocket_device_init(struct platform_device *pdev, ddev = &rdev->ddev; dev_set_drvdata(dev, rdev); - for_each_compatible_node(core_node, NULL, "rockchip,rk3588-rknn-core") + /* + * Count over the same match table the platform driver binds with, so + * that a core added there is counted here without a second edit. + */ + for_each_matching_node(core_node, rocket_dt_match) if (of_device_is_available(core_node)) num_cores++; diff --git a/drivers/accel/rocket/rocket_drv.c b/drivers/accel/rocket/rocket_drv.c index 6e7dc91c5..e46962949 100644 --- a/drivers/accel/rocket/rocket_drv.c +++ b/drivers/accel/rocket/rocket_drv.c @@ -217,13 +217,23 @@ static void rocket_remove(struct platform_device *pdev) static const struct rocket_soc_data rk3588_soc_data = { .num_clks = 4, .num_resets = 2, + .multi_power_domain = false, + .task_con_16bit = false, }; -static const struct of_device_id dt_match[] = { +static const struct rocket_soc_data rk3576_soc_data = { + .num_clks = 6, + .num_resets = 1, + .multi_power_domain = true, + .task_con_16bit = true, +}; + +const struct of_device_id rocket_dt_match[] = { { .compatible = "rockchip,rk3588-rknn-core", .data = &rk3588_soc_data }, + { .compatible = "rockchip,rk3576-rknn-core", .data = &rk3576_soc_data }, {} }; -MODULE_DEVICE_TABLE(of, dt_match); +MODULE_DEVICE_TABLE(of, rocket_dt_match); static int find_core_for_dev(struct device *dev) { @@ -282,7 +292,7 @@ static struct platform_driver rocket_driver = { .driver = { .name = "rocket", .pm = pm_ptr(&rocket_pm_ops), - .of_match_table = dt_match, + .of_match_table = rocket_dt_match, }, }; diff --git a/drivers/accel/rocket/rocket_drv.h b/drivers/accel/rocket/rocket_drv.h index 2c673bb99..0cd692a66 100644 --- a/drivers/accel/rocket/rocket_drv.h +++ b/drivers/accel/rocket/rocket_drv.h @@ -6,10 +6,12 @@ #include #include +#include #include "rocket_device.h" extern const struct dev_pm_ops rocket_pm_ops; +extern const struct of_device_id rocket_dt_match[]; struct rocket_iommu_domain { struct iommu_domain *domain; diff --git a/drivers/accel/rocket/rocket_job.c b/drivers/accel/rocket/rocket_job.c index 69e29f40f..2a272c2ef 100644 --- a/drivers/accel/rocket/rocket_job.c +++ b/drivers/accel/rocket/rocket_job.c @@ -21,6 +21,29 @@ #define JOB_TIMEOUT_MS 500 +/* + * PC_TASK_CON packs the task number with three controls, and the field widths + * are not the same on every SoC. rocket_registers.h is generated from the + * RK3588 description, where the task number is twelve bits: + * + * RK3588 BIT[11:0] task_number, BIT[12] pp_en, BIT[13] count_clear + * RK3576 BIT[15:0] task_number, BIT[16] pp_en, BIT[17] count_clear, + * BIT[18] last_layer_clear + * + * The RK3576 layout was confirmed by Chaoyi Chen of Rockchip: + * https://lore.kernel.org/all/4f300b78-d96d-4d98-8819-dc292b0c9b97@rock-chips.com/ + * + * Writing the RK3588 layout to an RK3576 therefore asks for task_number + * 0x7001, that is 28673 tasks, and lands the count clear on a bit that does + * nothing. The task counter is then only ever cleared by a reset, which is + * exactly the "one task per reset" behaviour this series has been reporting + * since v3. + */ +#define RK3576_PC_TASK_CON_TASK_NUMBER(n) ((n) & 0xffff) +#define RK3576_PC_TASK_CON_PP_EN BIT(16) +#define RK3576_PC_TASK_CON_COUNT_CLEAR BIT(17) +#define RK3576_PC_TASK_CON_LAST_LAYER_CLEAR BIT(18) + static struct rocket_job * to_rocket_job(struct drm_sched_job *sched_job) { @@ -142,10 +165,17 @@ static void rocket_job_hw_submit(struct rocket_core *core, struct rocket_job *jo rocket_pc_writel(core, INTERRUPT_MASK, PC_INTERRUPT_MASK_DPU_0 | PC_INTERRUPT_MASK_DPU_1); rocket_pc_writel(core, INTERRUPT_CLEAR, PC_INTERRUPT_CLEAR_DPU_0 | PC_INTERRUPT_CLEAR_DPU_1); - rocket_pc_writel(core, TASK_CON, PC_TASK_CON_RESERVED_0(1) | - PC_TASK_CON_TASK_COUNT_CLEAR(1) | - PC_TASK_CON_TASK_NUMBER(1) | - PC_TASK_CON_TASK_PP_EN(1)); + if (core->soc->task_con_16bit) + rocket_pc_writel(core, TASK_CON, + RK3576_PC_TASK_CON_LAST_LAYER_CLEAR | + RK3576_PC_TASK_CON_COUNT_CLEAR | + RK3576_PC_TASK_CON_PP_EN | + RK3576_PC_TASK_CON_TASK_NUMBER(1)); + else + rocket_pc_writel(core, TASK_CON, PC_TASK_CON_RESERVED_0(1) | + PC_TASK_CON_TASK_COUNT_CLEAR(1) | + PC_TASK_CON_TASK_NUMBER(1) | + PC_TASK_CON_TASK_PP_EN(1)); rocket_pc_writel(core, TASK_DMA_BASE_ADDR, PC_TASK_DMA_BASE_ADDR_DMA_BASE_ADDR(0x0)); -- 2.43.0