* [PATCH v16 01/16] accel/rocket: request the core clocks by name
2026-11-08 6:59 [PATCH v16 00/16] accel/rocket: RK3576 NPU (RKNN) enablement Jiaxing Hu
@ 2026-11-08 6:59 ` Jiaxing Hu
2026-11-08 6:59 ` [PATCH v16 02/16] accel/rocket: take the completion register writes under job_lock Jiaxing Hu
` (14 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Jiaxing Hu @ 2026-11-08 6:59 UTC (permalink / raw)
To: tomeu, heiko, robh, krzk+dt, conor+dt, joro, will, robin.murphy,
ulfh, p.zabel, ogabbay, zhangqing
Cc: royalnet026, abel.vesa, sebastian.reichel, sidong.yang,
u.kleine-koenig, chaoyi.chen, shawn.lin, finley.xiao, diederik,
alchark, leonard, jeff.hugo, rfoss, dri-devel, linux-rockchip,
iommu, linux-pm, devicetree, linux-arm-kernel, linux-kernel,
Jiaxing Hu
From: Igor Paunovic <royalnet026@gmail.com>
rocket_core_init() never sets the .id of the clocks, so all four are
requested with a NULL name and each one resolves to the first clock in the
DT, aclk.
As a result aclk is taken and enabled four times, while hclk, pclk and the
NPU compute clock are never enabled by the driver. It only works today
because the power-domain driver enables those clocks for it.
Give the four clocks their names, in the order the binding defines: aclk,
hclk, npu and pclk.
With that, a DT that lacks any of these clock-names fails probe with
-ENOENT instead of running on the wrong clock.
Fixes: ed98261b4168 ("accel/rocket: Add a new driver for Rockchip's NPU")
Signed-off-by: Igor Paunovic <royalnet026@gmail.com>
Tested-by: Sidong Yang <sidong.yang@furiosa.ai>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, NanoPC-T6 Plus
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Reviewed-by: Jiaxing Hu <gahing@gahingwoo.com>
[Jiaxing: shortened the commit message]
Signed-off-by: Jiaxing Hu <gahing@gahingwoo.com>
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
---
drivers/accel/rocket/rocket_core.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/accel/rocket/rocket_core.c b/drivers/accel/rocket/rocket_core.c
index b3b2fa9ba645..5dd260bacbff 100644
--- a/drivers/accel/rocket/rocket_core.c
+++ b/drivers/accel/rocket/rocket_core.c
@@ -28,6 +28,10 @@ int rocket_core_init(struct rocket_core *core)
if (err)
return dev_err_probe(dev, err, "failed to get resets for core %d\n", core->index);
+ core->clks[0].id = "aclk";
+ core->clks[1].id = "hclk";
+ core->clks[2].id = "npu";
+ core->clks[3].id = "pclk";
err = devm_clk_bulk_get(dev, ARRAY_SIZE(core->clks), core->clks);
if (err)
return dev_err_probe(dev, err, "failed to get clocks for core %d\n", core->index);
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH v16 02/16] accel/rocket: take the completion register writes under job_lock
2026-11-08 6:59 [PATCH v16 00/16] accel/rocket: RK3576 NPU (RKNN) enablement Jiaxing Hu
2026-11-08 6:59 ` [PATCH v16 01/16] accel/rocket: request the core clocks by name Jiaxing Hu
@ 2026-11-08 6:59 ` Jiaxing Hu
2026-11-08 6:59 ` [PATCH v16 03/16] accel/rocket: wait for a running IRQ handler before resetting a core Jiaxing Hu
` (13 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Jiaxing Hu @ 2026-11-08 6:59 UTC (permalink / raw)
To: tomeu, heiko, robh, krzk+dt, conor+dt, joro, will, robin.murphy,
ulfh, p.zabel, ogabbay, zhangqing
Cc: royalnet026, abel.vesa, sebastian.reichel, sidong.yang,
u.kleine-koenig, chaoyi.chen, shawn.lin, finley.xiao, diederik,
alchark, leonard, jeff.hugo, rfoss, dri-devel, linux-rockchip,
iommu, linux-pm, devicetree, linux-arm-kernel, linux-kernel,
Jiaxing Hu
The IRQ handler writes OPERATION_ENABLE and INTERRUPT_CLEAR before it
takes job_lock, while rocket_job_hw_submit() sets OPERATION_ENABLE to 1
under that lock.
If the two run at the same time, the 0 written by the IRQ handler can
overwrite the 1 written for a new task and stop a task that has just
started.
Move both writes into the existing scoped_guard(), so they are under the
same lock as the submit.
Fixes: 0810d5ad88a1 ("accel/rocket: Add job submission IOCTL")
Signed-off-by: Jiaxing Hu <gahing@gahingwoo.com>
Tested-by: Igor Paunovic <royalnet026@gmail.com> # RK3588, three cores, induced reset, JOB_TIMEOUT_MS=2
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
---
drivers/accel/rocket/rocket_job.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/accel/rocket/rocket_job.c b/drivers/accel/rocket/rocket_job.c
index c3edb94355a3..03e5f094f60b 100644
--- a/drivers/accel/rocket/rocket_job.c
+++ b/drivers/accel/rocket/rocket_job.c
@@ -369,10 +369,15 @@ static void rocket_job_handle_irq(struct rocket_core *core)
{
pm_runtime_mark_last_busy(core->dev);
- rocket_pc_writel(core, OPERATION_ENABLE, 0x0);
- rocket_pc_writel(core, INTERRUPT_CLEAR, 0x1ffff);
+ scoped_guard(mutex, &core->job_lock) {
+ /*
+ * Stopping the block belongs under the lock. hw_submit() writes
+ * OPERATION_ENABLE too, and outside the lock this zero can land
+ * after that one and stop a task that has only just started.
+ */
+ rocket_pc_writel(core, OPERATION_ENABLE, 0x0);
+ rocket_pc_writel(core, INTERRUPT_CLEAR, 0x1ffff);
- scoped_guard(mutex, &core->job_lock)
if (core->in_flight_job) {
if (core->in_flight_job->next_task_idx < core->in_flight_job->task_count) {
rocket_job_hw_submit(core, core->in_flight_job);
@@ -384,6 +389,7 @@ static void rocket_job_handle_irq(struct rocket_core *core)
pm_runtime_put_autosuspend(core->dev);
core->in_flight_job = NULL;
}
+ }
}
static void
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH v16 03/16] accel/rocket: wait for a running IRQ handler before resetting a core
2026-11-08 6:59 [PATCH v16 00/16] accel/rocket: RK3576 NPU (RKNN) enablement Jiaxing Hu
2026-11-08 6:59 ` [PATCH v16 01/16] accel/rocket: request the core clocks by name Jiaxing Hu
2026-11-08 6:59 ` [PATCH v16 02/16] accel/rocket: take the completion register writes under job_lock Jiaxing Hu
@ 2026-11-08 6:59 ` Jiaxing Hu
2026-11-08 6:59 ` [PATCH v16 04/16] accel/rocket: let the core suspend after a reset Jiaxing Hu
` (12 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Jiaxing Hu @ 2026-11-08 6:59 UTC (permalink / raw)
To: tomeu, heiko, robh, krzk+dt, conor+dt, joro, will, robin.murphy,
ulfh, p.zabel, ogabbay, zhangqing
Cc: royalnet026, abel.vesa, sebastian.reichel, sidong.yang,
u.kleine-koenig, chaoyi.chen, shawn.lin, finley.xiao, diederik,
alchark, leonard, jeff.hugo, rfoss, dri-devel, linux-rockchip,
iommu, linux-pm, devicetree, linux-arm-kernel, linux-kernel,
Jiaxing Hu
drm_sched_stop() does not wait for a threaded IRQ handler that is already
running, so call synchronize_irq() after it to make sure the handler has
finished before the reset.
Before synchronize_irq(), mask the interrupt and clear the raw status, so
that the NPU core cannot report a completion afterwards.
Do this under job_lock, because the submit path sets the interrupt mask
under the same lock.
Only touch these registers when the device is powered: check with
pm_runtime_get_if_active(), so that a register access with the power
domain off cannot raise an SError.
Suggested-by: Igor Paunovic <royalnet026@gmail.com>
Signed-off-by: Jiaxing Hu <gahing@gahingwoo.com>
Tested-by: Igor Paunovic <royalnet026@gmail.com> # RK3588, three cores, induced reset, JOB_TIMEOUT_MS=2
---
drivers/accel/rocket/rocket_job.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/accel/rocket/rocket_job.c b/drivers/accel/rocket/rocket_job.c
index 03e5f094f60b..abef12b86d48 100644
--- a/drivers/accel/rocket/rocket_job.c
+++ b/drivers/accel/rocket/rocket_job.c
@@ -400,6 +400,16 @@ rocket_reset(struct rocket_core *core, struct drm_sched_job *bad)
drm_sched_stop(&core->sched, bad);
+ scoped_guard(mutex, &core->job_lock) {
+ if (pm_runtime_get_if_active(core->dev) > 0) {
+ rocket_pc_writel(core, INTERRUPT_MASK, 0x0);
+ rocket_pc_writel(core, INTERRUPT_CLEAR, 0x1ffff);
+ pm_runtime_put_autosuspend(core->dev);
+ }
+ }
+
+ synchronize_irq(core->irq);
+
/*
* Remaining interrupts have been handled, but we might still have
* stuck jobs. Let's make sure the PM counters stay balanced by
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH v16 04/16] accel/rocket: let the core suspend after a reset
2026-11-08 6:59 [PATCH v16 00/16] accel/rocket: RK3576 NPU (RKNN) enablement Jiaxing Hu
` (2 preceding siblings ...)
2026-11-08 6:59 ` [PATCH v16 03/16] accel/rocket: wait for a running IRQ handler before resetting a core Jiaxing Hu
@ 2026-11-08 6:59 ` Jiaxing Hu
2026-11-08 6:59 ` [PATCH v16 05/16] accel/rocket: factor the completion tail out of the IRQ handler Jiaxing Hu
` (11 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Jiaxing Hu @ 2026-11-08 6:59 UTC (permalink / raw)
To: tomeu, heiko, robh, krzk+dt, conor+dt, joro, will, robin.murphy,
ulfh, p.zabel, ogabbay, zhangqing
Cc: royalnet026, abel.vesa, sebastian.reichel, sidong.yang,
u.kleine-koenig, chaoyi.chen, shawn.lin, finley.xiao, diederik,
alchark, leonard, jeff.hugo, rfoss, dri-devel, linux-rockchip,
iommu, linux-pm, devicetree, linux-arm-kernel, linux-kernel,
Jiaxing Hu
The reset path drops the runtime PM reference with
pm_runtime_put_noidle(), which does not let the device suspend, so the
power domain is never switched off and on again.
On the RK3576, powering the domain on resets the NPU bus interface. If
that does not happen after a reset, the IOMMU may not respond and the
next job after a timeout fails.
Use pm_runtime_put_autosuspend() instead, so the reset path handles
runtime PM the same way as a normal job completion.
Also drop the runtime PM reference after rocket_core_reset(), so the NPU
core stays powered during the reset.
The earlier test on the ROCK 4D was done on the v15 code: the job after a
timeout went from all 128 channels wrong to all 128 correct.
Repeated resets were triggered with a 2 ms job timeout.
v15 (put, then reset): tested twice; both times the board hung within the
same second as the first batch of job timeouts, with nothing printed.
v16 (reset, then put): tested four times; the board never hung.
So moving pm_runtime_put_autosuspend() after rocket_core_reset() avoids
the board hanging during a reset.
Link: https://lore.kernel.org/all/20260819073530.6087-1-royalnet026@gmail.com/
Fixes: 0810d5ad88a1 ("accel/rocket: Add job submission IOCTL")
Signed-off-by: Jiaxing Hu <gahing@gahingwoo.com>
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
---
drivers/accel/rocket/rocket_job.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/accel/rocket/rocket_job.c b/drivers/accel/rocket/rocket_job.c
index abef12b86d48..4a577b642849 100644
--- a/drivers/accel/rocket/rocket_job.c
+++ b/drivers/accel/rocket/rocket_job.c
@@ -395,6 +395,8 @@ static void rocket_job_handle_irq(struct rocket_core *core)
static void
rocket_reset(struct rocket_core *core, struct drm_sched_job *bad)
{
+ bool put_job_ref;
+
if (!atomic_read(&core->reset.pending))
return;
@@ -413,11 +415,10 @@ rocket_reset(struct rocket_core *core, struct drm_sched_job *bad)
/*
* Remaining interrupts have been handled, but we might still have
* stuck jobs. Let's make sure the PM counters stay balanced by
- * manually calling pm_runtime_put_noidle().
+ * dropping the job's reference once the core has been reset.
*/
scoped_guard(mutex, &core->job_lock) {
- if (core->in_flight_job)
- pm_runtime_put_noidle(core->dev);
+ put_job_ref = core->in_flight_job;
iommu_detach_group(NULL, core->iommu_group);
@@ -427,6 +428,9 @@ rocket_reset(struct rocket_core *core, struct drm_sched_job *bad)
/* Proceed with reset now. */
rocket_core_reset(core);
+ if (put_job_ref)
+ pm_runtime_put_autosuspend(core->dev);
+
/* NPU has been reset, we can clear the reset pending bit. */
atomic_set(&core->reset.pending, 0);
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH v16 05/16] accel/rocket: factor the completion tail out of the IRQ handler
2026-11-08 6:59 [PATCH v16 00/16] accel/rocket: RK3576 NPU (RKNN) enablement Jiaxing Hu
` (3 preceding siblings ...)
2026-11-08 6:59 ` [PATCH v16 04/16] accel/rocket: let the core suspend after a reset Jiaxing Hu
@ 2026-11-08 6:59 ` Jiaxing Hu
2026-11-08 6:59 ` [PATCH v16 06/16] dt-bindings: npu: rockchip: add rockchip,rk3576-rknn-core Jiaxing Hu
` (10 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Jiaxing Hu @ 2026-11-08 6:59 UTC (permalink / raw)
To: tomeu, heiko, robh, krzk+dt, conor+dt, joro, will, robin.murphy,
ulfh, p.zabel, ogabbay, zhangqing
Cc: royalnet026, abel.vesa, sebastian.reichel, sidong.yang,
u.kleine-koenig, chaoyi.chen, shawn.lin, finley.xiao, diederik,
alchark, leonard, jeff.hugo, rfoss, dri-devel, linux-rockchip,
iommu, linux-pm, devicetree, linux-arm-kernel, linux-kernel,
Jiaxing Hu
Move the part of the IRQ handler that starts the next task or finishes
the current job into rocket_job_next_locked(). This makes the code easier
to follow and does not change behaviour.
Signed-off-by: Jiaxing Hu <gahing@gahingwoo.com>
Reviewed-by: Igor Paunovic <royalnet026@gmail.com>
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
---
drivers/accel/rocket/rocket_job.c | 30 +++++++++++++++++++-----------
1 file changed, 19 insertions(+), 11 deletions(-)
diff --git a/drivers/accel/rocket/rocket_job.c b/drivers/accel/rocket/rocket_job.c
index 4a577b642849..ea23a44b1d9e 100644
--- a/drivers/accel/rocket/rocket_job.c
+++ b/drivers/accel/rocket/rocket_job.c
@@ -365,6 +365,24 @@ static struct dma_fence *rocket_job_run(struct drm_sched_job *sched_job)
return ERR_PTR(ret);
}
+static void rocket_job_next_locked(struct rocket_core *core)
+{
+ lockdep_assert_held(&core->job_lock);
+
+ if (!core->in_flight_job)
+ return;
+
+ if (core->in_flight_job->next_task_idx < core->in_flight_job->task_count) {
+ rocket_job_hw_submit(core, core->in_flight_job);
+ return;
+ }
+
+ iommu_detach_group(NULL, iommu_group_get(core->dev));
+ dma_fence_signal(core->in_flight_job->done_fence);
+ pm_runtime_put_autosuspend(core->dev);
+ core->in_flight_job = NULL;
+}
+
static void rocket_job_handle_irq(struct rocket_core *core)
{
pm_runtime_mark_last_busy(core->dev);
@@ -378,17 +396,7 @@ static void rocket_job_handle_irq(struct rocket_core *core)
rocket_pc_writel(core, OPERATION_ENABLE, 0x0);
rocket_pc_writel(core, INTERRUPT_CLEAR, 0x1ffff);
- if (core->in_flight_job) {
- if (core->in_flight_job->next_task_idx < core->in_flight_job->task_count) {
- rocket_job_hw_submit(core, core->in_flight_job);
- return;
- }
-
- iommu_detach_group(NULL, iommu_group_get(core->dev));
- dma_fence_signal(core->in_flight_job->done_fence);
- pm_runtime_put_autosuspend(core->dev);
- core->in_flight_job = NULL;
- }
+ rocket_job_next_locked(core);
}
}
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH v16 06/16] dt-bindings: npu: rockchip: add rockchip,rk3576-rknn-core
2026-11-08 6:59 [PATCH v16 00/16] accel/rocket: RK3576 NPU (RKNN) enablement Jiaxing Hu
` (4 preceding siblings ...)
2026-11-08 6:59 ` [PATCH v16 05/16] accel/rocket: factor the completion tail out of the IRQ handler Jiaxing Hu
@ 2026-11-08 6:59 ` Jiaxing Hu
2026-11-08 6:59 ` [PATCH v16 07/16] dt-bindings: power: rockchip: allow resets in a power domain node Jiaxing Hu
` (9 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Jiaxing Hu @ 2026-11-08 6:59 UTC (permalink / raw)
To: tomeu, heiko, robh, krzk+dt, conor+dt, joro, will, robin.murphy,
ulfh, p.zabel, ogabbay, zhangqing
Cc: royalnet026, abel.vesa, sebastian.reichel, sidong.yang,
u.kleine-koenig, chaoyi.chen, shawn.lin, finley.xiao, diederik,
alchark, leonard, jeff.hugo, rfoss, dri-devel, linux-rockchip,
iommu, linux-pm, devicetree, linux-arm-kernel, linux-kernel,
Jiaxing Hu, Krzysztof Kozlowski
The RK3576 and the RK3588 use the same NPU block, with different hardware
resources.
The RK3576 has two cores. Each core needs six clocks, two more than the
RK3588 (aclk_cbuf and hclk_cbuf), needs only one reset, and has no
sram-supply.
Define the requirements of each SoC in allOf. The RK3588 still requires
sram-supply.
Signed-off-by: Jiaxing Hu <gahing@gahingwoo.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
.../npu/rockchip,rk3588-rknn-core.yaml | 40 ++++++++++++++++++-
1 file changed, 38 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/npu/rockchip,rk3588-rknn-core.yaml b/Documentation/devicetree/bindings/npu/rockchip,rk3588-rknn-core.yaml
index caca2a4903cd..2eb9337819e6 100644
--- a/Documentation/devicetree/bindings/npu/rockchip,rk3588-rknn-core.yaml
+++ b/Documentation/devicetree/bindings/npu/rockchip,rk3588-rknn-core.yaml
@@ -21,6 +21,7 @@ properties:
compatible:
enum:
+ - rockchip,rk3576-rknn-core
- rockchip,rk3588-rknn-core
reg:
@@ -33,14 +34,18 @@ properties:
- const: core # Main NPU core processing unit registers
clocks:
- maxItems: 4
+ minItems: 4
+ maxItems: 6
clock-names:
+ minItems: 4
items:
- const: aclk
- const: hclk
- const: npu
- const: pclk
+ - const: aclk_cbuf
+ - const: hclk_cbuf
interrupts:
maxItems: 1
@@ -54,9 +59,11 @@ properties:
maxItems: 1
resets:
+ minItems: 1
maxItems: 2
reset-names:
+ minItems: 1
items:
- const: srst_a
- const: srst_h
@@ -75,7 +82,36 @@ required:
- resets
- reset-names
- npu-supply
- - sram-supply
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: rockchip,rk3588-rknn-core
+ then:
+ properties:
+ clocks:
+ maxItems: 4
+ clock-names:
+ maxItems: 4
+ resets:
+ minItems: 2
+ reset-names:
+ minItems: 2
+ required:
+ - sram-supply
+ else:
+ properties:
+ clocks:
+ minItems: 6
+ clock-names:
+ minItems: 6
+ resets:
+ maxItems: 1
+ reset-names:
+ maxItems: 1
+ sram-supply: false
additionalProperties: false
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH v16 07/16] dt-bindings: power: rockchip: allow resets in a power domain node
2026-11-08 6:59 [PATCH v16 00/16] accel/rocket: RK3576 NPU (RKNN) enablement Jiaxing Hu
` (5 preceding siblings ...)
2026-11-08 6:59 ` [PATCH v16 06/16] dt-bindings: npu: rockchip: add rockchip,rk3576-rknn-core Jiaxing Hu
@ 2026-11-08 6:59 ` Jiaxing Hu
2026-11-08 6:59 ` [PATCH v16 08/16] dt-bindings: iommu: rockchip: describe the RK3576 NPU MMU Jiaxing Hu
` (8 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Jiaxing Hu @ 2026-11-08 6:59 UTC (permalink / raw)
To: tomeu, heiko, robh, krzk+dt, conor+dt, joro, will, robin.murphy,
ulfh, p.zabel, ogabbay, zhangqing
Cc: royalnet026, abel.vesa, sebastian.reichel, sidong.yang,
u.kleine-koenig, chaoyi.chen, shawn.lin, finley.xiao, diederik,
alchark, leonard, jeff.hugo, rfoss, dri-devel, linux-rockchip,
iommu, linux-pm, devicetree, linux-arm-kernel, linux-kernel,
Jiaxing Hu, Conor Dooley
Some power domains need a reset after they are powered on before the
hardware can be accessed.
The RK3576 NPU power domains are like this: without the reset, the first
access to the hardware after power-on can raise an SError.
Allow a resets property in power domain nodes to describe this.
Signed-off-by: Jiaxing Hu <gahing@gahingwoo.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
---
.../bindings/power/rockchip,power-controller.yaml | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/Documentation/devicetree/bindings/power/rockchip,power-controller.yaml b/Documentation/devicetree/bindings/power/rockchip,power-controller.yaml
index b41db576f95d..83741f048716 100644
--- a/Documentation/devicetree/bindings/power/rockchip,power-controller.yaml
+++ b/Documentation/devicetree/bindings/power/rockchip,power-controller.yaml
@@ -136,6 +136,13 @@ $defs:
A number of phandles to clocks that need to be enabled
while power domain switches state.
+ resets:
+ maxItems: 1
+ description:
+ A phandle to a reset that needs to be cycled once the power domain has
+ been switched on, for domains whose logic does not come up in a usable
+ state by itself.
+
domain-supply:
description: domain regulator supply.
@@ -216,6 +223,7 @@ examples:
reg = <RK3399_PD_IEP>;
clocks = <&cru ACLK_IEP>,
<&cru HCLK_IEP>;
+ resets = <&cru SRST_A_IEP>;
pm_qos = <&qos_iep>;
#power-domain-cells = <0>;
};
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH v16 08/16] dt-bindings: iommu: rockchip: describe the RK3576 NPU MMU
2026-11-08 6:59 [PATCH v16 00/16] accel/rocket: RK3576 NPU (RKNN) enablement Jiaxing Hu
` (6 preceding siblings ...)
2026-11-08 6:59 ` [PATCH v16 07/16] dt-bindings: power: rockchip: allow resets in a power domain node Jiaxing Hu
@ 2026-11-08 6:59 ` Jiaxing Hu
2026-11-08 6:59 ` [PATCH v16 09/16] pmdomain: rockchip: add optional per-domain power-on settle delay Jiaxing Hu
` (7 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Jiaxing Hu @ 2026-11-08 6:59 UTC (permalink / raw)
To: tomeu, heiko, robh, krzk+dt, conor+dt, joro, will, robin.murphy,
ulfh, p.zabel, ogabbay, zhangqing
Cc: royalnet026, abel.vesa, sebastian.reichel, sidong.yang,
u.kleine-koenig, chaoyi.chen, shawn.lin, finley.xiao, diederik,
alchark, leonard, jeff.hugo, rfoss, dri-devel, linux-rockchip,
iommu, linux-pm, devicetree, linux-arm-kernel, linux-kernel,
Jiaxing Hu, Conor Dooley
The RK3576 NPU IOMMU is compatible with rk3568-iommu but needs four
clocks: aclk, iface and the two CBUF clocks.
Measured: with only aclk and iface, the IOMMU reset fails and the NPU does
not probe. Without either one of the CBUF clocks it fails as well, and one
of those configurations does not even boot.
With all four clocks the IOMMU works, and the npu clock is not needed.
rk_iommu enables every clock listed in the device tree (841363ebb508), so
this list decides whether the IOMMU can reset.
Signed-off-by: Jiaxing Hu <gahing@gahingwoo.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
---
.../bindings/iommu/rockchip,iommu.yaml | 26 +++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/Documentation/devicetree/bindings/iommu/rockchip,iommu.yaml b/Documentation/devicetree/bindings/iommu/rockchip,iommu.yaml
index 6ce41d11ff5e..e40c9ac2b463 100644
--- a/Documentation/devicetree/bindings/iommu/rockchip,iommu.yaml
+++ b/Documentation/devicetree/bindings/iommu/rockchip,iommu.yaml
@@ -26,6 +26,7 @@ properties:
- items:
- enum:
- rockchip,rk3576-iommu
+ - rockchip,rk3576-npu-iommu
- rockchip,rk3588-iommu
- const: rockchip,rk3568-iommu
@@ -42,14 +43,20 @@ properties:
minItems: 1
clocks:
+ minItems: 2
items:
- description: Core clock
- description: Interface clock
+ - description: Convolution buffer core clock
+ - description: Convolution buffer interface clock
clock-names:
+ minItems: 2
items:
- const: aclk
- const: iface
+ - const: aclk_cbuf
+ - const: hclk_cbuf
"#iommu-cells":
const: 0
@@ -72,6 +79,25 @@ required:
- clock-names
- "#iommu-cells"
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: rockchip,rk3576-npu-iommu
+ then:
+ properties:
+ clocks:
+ minItems: 4
+ clock-names:
+ minItems: 4
+ else:
+ properties:
+ clocks:
+ maxItems: 2
+ clock-names:
+ maxItems: 2
+
additionalProperties: false
examples:
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH v16 09/16] pmdomain: rockchip: add optional per-domain power-on settle delay
2026-11-08 6:59 [PATCH v16 00/16] accel/rocket: RK3576 NPU (RKNN) enablement Jiaxing Hu
` (7 preceding siblings ...)
2026-11-08 6:59 ` [PATCH v16 08/16] dt-bindings: iommu: rockchip: describe the RK3576 NPU MMU Jiaxing Hu
@ 2026-11-08 6:59 ` Jiaxing Hu
2026-11-08 6:59 ` [PATCH v16 10/16] pmdomain: rockchip: cycle an optional power-domain reset on power-on Jiaxing Hu
` (6 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Jiaxing Hu @ 2026-11-08 6:59 UTC (permalink / raw)
To: tomeu, heiko, robh, krzk+dt, conor+dt, joro, will, robin.murphy,
ulfh, p.zabel, ogabbay, zhangqing
Cc: royalnet026, abel.vesa, sebastian.reichel, sidong.yang,
u.kleine-koenig, chaoyi.chen, shawn.lin, finley.xiao, diederik,
alchark, leonard, jeff.hugo, rfoss, dri-devel, linux-rockchip,
iommu, linux-pm, devicetree, linux-arm-kernel, linux-kernel,
Jiaxing Hu
The RK3576 NPU power domains need some time to settle after the idle
request is released.
Without that wait, the QoS registers are written while the domain is not
fully up, and the first cold power-on raises an SError.
Add an optional delay_us field and wait that long after releasing the
idle request and before restoring QoS.
Rename the DOMAIN_M_O_R_G macro to DOMAIN_M_O_R_G_W.
The NPU power domain is switched off when the driver probes, so the first
power-on goes through this wait even when the bootloader left the NPU on.
With delay_us set to 0, an SError still happens even with the regulator
kept always on; with 15 us, 536 cold power-ons in a row are all clean.
Signed-off-by: Jiaxing Hu <gahing@gahingwoo.com>
Reviewed-by: Abel Vesa <abel.vesa@oss.qualcomm.com>
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
---
drivers/pmdomain/rockchip/pm-domains.c | 56 ++++++++++++++++----------
1 file changed, 34 insertions(+), 22 deletions(-)
diff --git a/drivers/pmdomain/rockchip/pm-domains.c b/drivers/pmdomain/rockchip/pm-domains.c
index db3879846db6..e3cc60fa2277 100644
--- a/drivers/pmdomain/rockchip/pm-domains.c
+++ b/drivers/pmdomain/rockchip/pm-domains.c
@@ -18,6 +18,7 @@
#include <linux/of_address.h>
#include <linux/of_clk.h>
#include <linux/clk.h>
+#include <linux/delay.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/mfd/syscon.h>
@@ -59,6 +60,7 @@ struct rockchip_domain_info {
u32 pwr_offset;
u32 mem_offset;
u32 req_offset;
+ u32 delay_us;
};
struct rockchip_pmu_info {
@@ -185,7 +187,7 @@ struct rockchip_pmu {
.need_regulator = regulator, \
}
-#define DOMAIN_M_O_R_G(_name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, ack, g_mask, wakeup) \
+#define DOMAIN_M_O_R_G_W(_name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, ack, g_mask, delay, wakeup, regulator) \
{ \
.name = _name, \
.pwr_offset = p_offset, \
@@ -200,8 +202,10 @@ struct rockchip_pmu {
.req_mask = (req), \
.idle_mask = (idle), \
.clk_ungate_mask = (g_mask), \
+ .delay_us = (delay), \
.ack_mask = (ack), \
.active_wakeup = wakeup, \
+ .need_regulator = regulator, \
}
#define DOMAIN_M_R(_name, pwr, status, req, idle, ack, wakeup, regulator) \
@@ -258,8 +262,11 @@ struct rockchip_pmu {
#define DOMAIN_RK3568(name, pwr, req, wakeup, regulator) \
DOMAIN_M_R(name, pwr, pwr, req, req, req, wakeup, regulator)
-#define DOMAIN_RK3576(name, p_offset, pwr, status, r_status, r_offset, req, idle, g_mask, wakeup) \
- DOMAIN_M_O_R_G(name, p_offset, pwr, status, 0, r_status, r_status, r_offset, req, idle, idle, g_mask, wakeup)
+#define DOMAIN_RK3576(name, p_offset, pwr, status, r_status, r_offset, req, idle, g_mask, delay, wakeup) \
+ DOMAIN_M_O_R_G_W(name, p_offset, pwr, status, 0, r_status, r_status, r_offset, req, idle, idle, g_mask, delay, wakeup, false)
+
+#define DOMAIN_RK3576_R(name, p_offset, pwr, status, r_status, r_offset, req, idle, g_mask, delay, wakeup) \
+ DOMAIN_M_O_R_G_W(name, p_offset, pwr, status, 0, r_status, r_status, r_offset, req, idle, idle, g_mask, delay, wakeup, true)
/*
* Dynamic Memory Controller may need to coordinate with us -- see
@@ -681,6 +688,10 @@ static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
if (ret < 0)
goto out;
+ /* Some domains need to settle before the QoS registers answer. */
+ if (pd->info->delay_us)
+ udelay(pd->info->delay_us);
+
rockchip_pmu_restore_qos(pd);
}
@@ -1314,25 +1325,26 @@ static const struct rockchip_domain_info rk3568_pm_domains[] = {
};
static const struct rockchip_domain_info rk3576_pm_domains[] = {
- [RK3576_PD_NPU] = DOMAIN_RK3576("npu", 0x0, BIT(0), BIT(0), 0, 0x0, 0, 0, 0, false),
- [RK3576_PD_NVM] = DOMAIN_RK3576("nvm", 0x0, BIT(6), 0, BIT(6), 0x4, BIT(2), BIT(18), BIT(2), false),
- [RK3576_PD_SDGMAC] = DOMAIN_RK3576("sdgmac", 0x0, BIT(7), 0, BIT(7), 0x4, BIT(1), BIT(17), 0x6, false),
- [RK3576_PD_AUDIO] = DOMAIN_RK3576("audio", 0x0, BIT(8), 0, BIT(8), 0x4, BIT(0), BIT(16), BIT(0), false),
- [RK3576_PD_PHP] = DOMAIN_RK3576("php", 0x0, BIT(9), 0, BIT(9), 0x0, BIT(15), BIT(15), BIT(15), false),
- [RK3576_PD_SUBPHP] = DOMAIN_RK3576("subphp", 0x0, BIT(10), 0, BIT(10), 0x0, 0, 0, 0, false),
- [RK3576_PD_VOP] = DOMAIN_RK3576("vop", 0x0, BIT(11), 0, BIT(11), 0x0, 0x6000, 0x6000, 0x6000, false),
- [RK3576_PD_VO1] = DOMAIN_RK3576("vo1", 0x0, BIT(14), 0, BIT(14), 0x0, BIT(12), BIT(12), 0x7000, false),
- [RK3576_PD_VO0] = DOMAIN_RK3576("vo0", 0x0, BIT(15), 0, BIT(15), 0x0, BIT(11), BIT(11), 0x6800, false),
- [RK3576_PD_USB] = DOMAIN_RK3576("usb", 0x4, BIT(0), 0, BIT(16), 0x0, BIT(10), BIT(10), 0x6400, true),
- [RK3576_PD_VI] = DOMAIN_RK3576("vi", 0x4, BIT(1), 0, BIT(17), 0x0, BIT(9), BIT(9), BIT(9), false),
- [RK3576_PD_VEPU0] = DOMAIN_RK3576("vepu0", 0x4, BIT(2), 0, BIT(18), 0x0, BIT(7), BIT(7), 0x280, false),
- [RK3576_PD_VEPU1] = DOMAIN_RK3576("vepu1", 0x4, BIT(3), 0, BIT(19), 0x0, BIT(8), BIT(8), BIT(8), false),
- [RK3576_PD_VDEC] = DOMAIN_RK3576("vdec", 0x4, BIT(4), 0, BIT(20), 0x0, BIT(6), BIT(6), BIT(6), false),
- [RK3576_PD_VPU] = DOMAIN_RK3576("vpu", 0x4, BIT(5), 0, BIT(21), 0x0, BIT(5), BIT(5), BIT(5), false),
- [RK3576_PD_NPUTOP] = DOMAIN_RK3576("nputop", 0x4, BIT(6), 0, BIT(22), 0x0, 0x18, 0x18, 0x18, false),
- [RK3576_PD_NPU0] = DOMAIN_RK3576("npu0", 0x4, BIT(7), 0, BIT(23), 0x0, BIT(1), BIT(1), 0x1a, false),
- [RK3576_PD_NPU1] = DOMAIN_RK3576("npu1", 0x4, BIT(8), 0, BIT(24), 0x0, BIT(2), BIT(2), 0x1c, false),
- [RK3576_PD_GPU] = DOMAIN_RK3576("gpu", 0x4, BIT(9), 0, BIT(25), 0x0, BIT(0), BIT(0), BIT(0), false),
+ /* name p_offset pwr status r_status r_offset req idle g_mask delay wakeup */
+ [RK3576_PD_NPU] = DOMAIN_RK3576_R("npu", 0x0, BIT(0), BIT(0), 0, 0x0, 0, 0, 0, 0, false),
+ [RK3576_PD_NVM] = DOMAIN_RK3576("nvm", 0x0, BIT(6), 0, BIT(6), 0x4, BIT(2), BIT(18), BIT(2), 0, false),
+ [RK3576_PD_SDGMAC] = DOMAIN_RK3576("sdgmac", 0x0, BIT(7), 0, BIT(7), 0x4, BIT(1), BIT(17), 0x6, 0, false),
+ [RK3576_PD_AUDIO] = DOMAIN_RK3576("audio", 0x0, BIT(8), 0, BIT(8), 0x4, BIT(0), BIT(16), BIT(0), 0, false),
+ [RK3576_PD_PHP] = DOMAIN_RK3576("php", 0x0, BIT(9), 0, BIT(9), 0x0, BIT(15), BIT(15), BIT(15), 0, false),
+ [RK3576_PD_SUBPHP] = DOMAIN_RK3576("subphp", 0x0, BIT(10), 0, BIT(10), 0x0, 0, 0, 0, 0, false),
+ [RK3576_PD_VOP] = DOMAIN_RK3576("vop", 0x0, BIT(11), 0, BIT(11), 0x0, 0x6000, 0x6000, 0x6000, 0, false),
+ [RK3576_PD_VO1] = DOMAIN_RK3576("vo1", 0x0, BIT(14), 0, BIT(14), 0x0, BIT(12), BIT(12), 0x7000, 0, false),
+ [RK3576_PD_VO0] = DOMAIN_RK3576("vo0", 0x0, BIT(15), 0, BIT(15), 0x0, BIT(11), BIT(11), 0x6800, 0, false),
+ [RK3576_PD_USB] = DOMAIN_RK3576("usb", 0x4, BIT(0), 0, BIT(16), 0x0, BIT(10), BIT(10), 0x6400, 0, true),
+ [RK3576_PD_VI] = DOMAIN_RK3576("vi", 0x4, BIT(1), 0, BIT(17), 0x0, BIT(9), BIT(9), BIT(9), 0, false),
+ [RK3576_PD_VEPU0] = DOMAIN_RK3576("vepu0", 0x4, BIT(2), 0, BIT(18), 0x0, BIT(7), BIT(7), 0x280, 0, false),
+ [RK3576_PD_VEPU1] = DOMAIN_RK3576("vepu1", 0x4, BIT(3), 0, BIT(19), 0x0, BIT(8), BIT(8), BIT(8), 0, false),
+ [RK3576_PD_VDEC] = DOMAIN_RK3576("vdec", 0x4, BIT(4), 0, BIT(20), 0x0, BIT(6), BIT(6), BIT(6), 0, false),
+ [RK3576_PD_VPU] = DOMAIN_RK3576("vpu", 0x4, BIT(5), 0, BIT(21), 0x0, BIT(5), BIT(5), BIT(5), 0, false),
+ [RK3576_PD_NPUTOP] = DOMAIN_RK3576("nputop", 0x4, BIT(6), 0, BIT(22), 0x0, 0x18, 0x18, 0x18, 15, false),
+ [RK3576_PD_NPU0] = DOMAIN_RK3576("npu0", 0x4, BIT(7), 0, BIT(23), 0x0, BIT(1), BIT(1), 0x1a, 15, false),
+ [RK3576_PD_NPU1] = DOMAIN_RK3576("npu1", 0x4, BIT(8), 0, BIT(24), 0x0, BIT(2), BIT(2), 0x1c, 15, false),
+ [RK3576_PD_GPU] = DOMAIN_RK3576("gpu", 0x4, BIT(9), 0, BIT(25), 0x0, BIT(0), BIT(0), BIT(0), 0, false),
};
static const struct rockchip_domain_info rk3588_pm_domains[] = {
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH v16 10/16] pmdomain: rockchip: cycle an optional power-domain reset on power-on
2026-11-08 6:59 [PATCH v16 00/16] accel/rocket: RK3576 NPU (RKNN) enablement Jiaxing Hu
` (8 preceding siblings ...)
2026-11-08 6:59 ` [PATCH v16 09/16] pmdomain: rockchip: add optional per-domain power-on settle delay Jiaxing Hu
@ 2026-11-08 6:59 ` Jiaxing Hu
2026-11-08 6:59 ` [PATCH v16 11/16] accel/rocket: select the per-core clock and reset counts from match data Jiaxing Hu
` (5 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Jiaxing Hu @ 2026-11-08 6:59 UTC (permalink / raw)
To: tomeu, heiko, robh, krzk+dt, conor+dt, joro, will, robin.murphy,
ulfh, p.zabel, ogabbay, zhangqing
Cc: royalnet026, abel.vesa, sebastian.reichel, sidong.yang,
u.kleine-koenig, chaoyi.chen, shawn.lin, finley.xiao, diederik,
alchark, leonard, jeff.hugo, rfoss, dri-devel, linux-rockchip,
iommu, linux-pm, devicetree, linux-arm-kernel, linux-kernel,
Jiaxing Hu
The bus interface of some power domains can be left in an undefined state
after power-on.
On the RK3576 NPU this shows up as a hang on the first register access
after power-on. Resetting the power domain once makes access work again.
When the power domain node has a reset, the driver gets it and cycles it
after releasing the idle request and before restoring QoS.
This is optional. Power domains without a reset are not affected.
Signed-off-by: Jiaxing Hu <gahing@gahingwoo.com>
Reviewed-by: Abel Vesa <abel.vesa@oss.qualcomm.com>
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
---
drivers/pmdomain/rockchip/pm-domains.c | 33 +++++++++++++++++++++++++-
1 file changed, 32 insertions(+), 1 deletion(-)
diff --git a/drivers/pmdomain/rockchip/pm-domains.c b/drivers/pmdomain/rockchip/pm-domains.c
index e3cc60fa2277..0f4ea5471792 100644
--- a/drivers/pmdomain/rockchip/pm-domains.c
+++ b/drivers/pmdomain/rockchip/pm-domains.c
@@ -19,6 +19,7 @@
#include <linux/of_clk.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/reset.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/mfd/syscon.h>
@@ -103,6 +104,7 @@ struct rockchip_pm_domain {
struct clk_bulk_data *clks;
struct device_node *node;
struct regulator *supply;
+ struct reset_control *reset;
};
struct rockchip_pmu {
@@ -688,6 +690,21 @@ static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
if (ret < 0)
goto out;
+ /*
+ * Optional: some domains need their reset cycled once power
+ * is on. This goes BEFORE the settle delay, not after: a
+ * domain that asks for both is asking to settle before the
+ * QoS registers answer, and a reset deasserted after the
+ * delay would leave nothing between it and the QoS writes.
+ * On RK3576 the reset being cycled is the NPU core's bus
+ * interface, which is what those writes go through.
+ */
+ if (pd->reset) {
+ reset_control_assert(pd->reset);
+ usleep_range(10, 20);
+ reset_control_deassert(pd->reset);
+ }
+
/* Some domains need to settle before the QoS registers answer. */
if (pd->info->delay_us)
udelay(pd->info->delay_us);
@@ -873,6 +890,14 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
if (error)
goto err_put_clocks;
+ pd->reset = of_reset_control_get_optional_exclusive(node, NULL);
+ if (IS_ERR(pd->reset)) {
+ error = dev_err_probe(pmu->dev, PTR_ERR(pd->reset),
+ "%pOFn: failed to get reset\n", node);
+ pd->reset = NULL;
+ goto err_unprepare_clocks;
+ }
+
pd->num_qos = of_count_phandle_with_args(node, "pm_qos",
NULL);
@@ -943,11 +968,13 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
clk_bulk_unprepare(pd->num_clks, pd->clks);
err_put_clocks:
clk_bulk_put(pd->num_clks, pd->clks);
+ reset_control_put(pd->reset);
return error;
}
static void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd)
{
+ struct reset_control *reset;
int ret;
/*
@@ -962,11 +989,15 @@ static void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd)
clk_bulk_unprepare(pd->num_clks, pd->clks);
clk_bulk_put(pd->num_clks, pd->clks);
- /* protect the zeroing of pm->num_clks */
+ /* protect the zeroing of pd->num_clks and pd->reset */
mutex_lock(&pd->pmu->mutex);
pd->num_clks = 0;
+ reset = pd->reset;
+ pd->reset = NULL;
mutex_unlock(&pd->pmu->mutex);
+ reset_control_put(reset);
+
/* devm will free our memory */
}
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH v16 11/16] accel/rocket: select the per-core clock and reset counts from match data
2026-11-08 6:59 [PATCH v16 00/16] accel/rocket: RK3576 NPU (RKNN) enablement Jiaxing Hu
` (9 preceding siblings ...)
2026-11-08 6:59 ` [PATCH v16 10/16] pmdomain: rockchip: cycle an optional power-domain reset on power-on Jiaxing Hu
@ 2026-11-08 6:59 ` Jiaxing Hu
2026-11-08 6:59 ` [PATCH v16 12/16] accel/rocket: add RK3576 NPU (RKNN) support Jiaxing Hu
` (4 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Jiaxing Hu @ 2026-11-08 6:59 UTC (permalink / raw)
To: tomeu, heiko, robh, krzk+dt, conor+dt, joro, will, robin.murphy,
ulfh, p.zabel, ogabbay, zhangqing
Cc: royalnet026, abel.vesa, sebastian.reichel, sidong.yang,
u.kleine-koenig, chaoyi.chen, shawn.lin, finley.xiao, diederik,
alchark, leonard, jeff.hugo, rfoss, dri-devel, linux-rockchip,
iommu, linux-pm, devicetree, linux-arm-kernel, linux-kernel,
Jiaxing Hu
The RK3576 and the RK3588 use the same NPU block, but with different
numbers of clocks and resets.
Take the number of clocks and resets for each core from soc_data in the
match data, so the driver uses the right count on each SoC.
The RK3588 keeps four clocks and two resets.
A device without match data fails before any resource is allocated.
Signed-off-by: Jiaxing Hu <gahing@gahingwoo.com>
---
drivers/accel/rocket/rocket_core.c | 8 ++++----
drivers/accel/rocket/rocket_core.h | 6 ++++++
drivers/accel/rocket/rocket_drv.c | 18 +++++++++++++++---
3 files changed, 25 insertions(+), 7 deletions(-)
diff --git a/drivers/accel/rocket/rocket_core.c b/drivers/accel/rocket/rocket_core.c
index 5dd260bacbff..b202d15816a3 100644
--- a/drivers/accel/rocket/rocket_core.c
+++ b/drivers/accel/rocket/rocket_core.c
@@ -23,7 +23,7 @@ int rocket_core_init(struct rocket_core *core)
core->resets[0].id = "srst_a";
core->resets[1].id = "srst_h";
- err = devm_reset_control_bulk_get_exclusive(&pdev->dev, ARRAY_SIZE(core->resets),
+ err = devm_reset_control_bulk_get_exclusive(&pdev->dev, core->soc->num_resets,
core->resets);
if (err)
return dev_err_probe(dev, err, "failed to get resets for core %d\n", core->index);
@@ -32,7 +32,7 @@ int rocket_core_init(struct rocket_core *core)
core->clks[1].id = "hclk";
core->clks[2].id = "npu";
core->clks[3].id = "pclk";
- err = devm_clk_bulk_get(dev, ARRAY_SIZE(core->clks), core->clks);
+ 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);
@@ -109,9 +109,9 @@ void rocket_core_fini(struct rocket_core *core)
void rocket_core_reset(struct rocket_core *core)
{
- reset_control_bulk_assert(ARRAY_SIZE(core->resets), core->resets);
+ reset_control_bulk_assert(core->soc->num_resets, core->resets);
udelay(10);
- reset_control_bulk_deassert(ARRAY_SIZE(core->resets), core->resets);
+ reset_control_bulk_deassert(core->soc->num_resets, core->resets);
}
diff --git a/drivers/accel/rocket/rocket_core.h b/drivers/accel/rocket/rocket_core.h
index f6d7382854ca..bfbf5110b524 100644
--- a/drivers/accel/rocket/rocket_core.h
+++ b/drivers/accel/rocket/rocket_core.h
@@ -27,9 +27,15 @@
#define rocket_core_writel(core, reg, value) \
writel(value, (core)->core_iomem + (REG_CORE_##reg) - REG_CORE_S_STATUS)
+struct rocket_soc_data {
+ unsigned int num_clks;
+ unsigned int num_resets;
+};
+
struct rocket_core {
struct device *dev;
struct rocket_device *rdev;
+ const struct rocket_soc_data *soc;
unsigned int index;
int irq;
diff --git a/drivers/accel/rocket/rocket_drv.c b/drivers/accel/rocket/rocket_drv.c
index 5d7805c41dc3..1030d8407b78 100644
--- a/drivers/accel/rocket/rocket_drv.c
+++ b/drivers/accel/rocket/rocket_drv.c
@@ -159,8 +159,14 @@ static const struct drm_driver rocket_drm_driver = {
static int rocket_probe(struct platform_device *pdev)
{
+ const struct rocket_soc_data *soc = of_device_get_match_data(&pdev->dev);
int ret;
+ if (!soc) {
+ dev_err(&pdev->dev, "no match data for this device\n");
+ return -ENODEV;
+ }
+
if (rdev == NULL) {
/* First core probing, initialize DRM device. */
rdev = rocket_device_init(drm_dev, &rocket_drm_driver);
@@ -179,6 +185,7 @@ static int rocket_probe(struct platform_device *pdev)
rdev->cores[core].rdev = rdev;
rdev->cores[core].dev = &pdev->dev;
+ rdev->cores[core].soc = soc;
rdev->cores[core].index = core;
rdev->num_cores++;
@@ -216,8 +223,13 @@ static void rocket_remove(struct platform_device *pdev)
}
}
+static const struct rocket_soc_data rk3588_soc_data = {
+ .num_clks = 4,
+ .num_resets = 2,
+};
+
static const struct of_device_id dt_match[] = {
- { .compatible = "rockchip,rk3588-rknn-core" },
+ { .compatible = "rockchip,rk3588-rknn-core", .data = &rk3588_soc_data },
{}
};
MODULE_DEVICE_TABLE(of, dt_match);
@@ -243,7 +255,7 @@ static int rocket_device_runtime_resume(struct device *dev)
if (core < 0)
return -ENODEV;
- err = clk_bulk_prepare_enable(ARRAY_SIZE(rdev->cores[core].clks), rdev->cores[core].clks);
+ err = clk_bulk_prepare_enable(rdev->cores[core].soc->num_clks, rdev->cores[core].clks);
if (err) {
dev_err(dev, "failed to enable (%d) clocks for core %d\n", err, core);
return err;
@@ -263,7 +275,7 @@ static int rocket_device_runtime_suspend(struct device *dev)
if (!rocket_job_is_idle(&rdev->cores[core]))
return -EBUSY;
- clk_bulk_disable_unprepare(ARRAY_SIZE(rdev->cores[core].clks), rdev->cores[core].clks);
+ clk_bulk_disable_unprepare(rdev->cores[core].soc->num_clks, rdev->cores[core].clks);
return 0;
}
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH v16 12/16] accel/rocket: add RK3576 NPU (RKNN) support
2026-11-08 6:59 [PATCH v16 00/16] accel/rocket: RK3576 NPU (RKNN) enablement Jiaxing Hu
` (10 preceding siblings ...)
2026-11-08 6:59 ` [PATCH v16 11/16] accel/rocket: select the per-core clock and reset counts from match data Jiaxing Hu
@ 2026-11-08 6:59 ` Jiaxing Hu
2026-11-08 6:59 ` [PATCH v16 13/16] accel/rocket: add a GET_PARAM ioctl for the hardware version Jiaxing Hu
` (3 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Jiaxing Hu @ 2026-11-08 6:59 UTC (permalink / raw)
To: tomeu, heiko, robh, krzk+dt, conor+dt, joro, will, robin.murphy,
ulfh, p.zabel, ogabbay, zhangqing
Cc: royalnet026, abel.vesa, sebastian.reichel, sidong.yang,
u.kleine-koenig, chaoyi.chen, shawn.lin, finley.xiao, diederik,
alchark, leonard, jeff.hugo, rfoss, dri-devel, linux-rockchip,
iommu, linux-pm, devicetree, linux-arm-kernel, linux-kernel,
Jiaxing Hu
Add support for the RK3576 NPU. It has two cores; each core needs six
clocks and one reset, with aclk_cbuf and hclk_cbuf on top of what the
RK3588 has.
The task number in PC_TASK_CON is 16 bits wide, not 12. BIT16, BIT17 and
BIT18 are pp_en, count_clear and last_layer_clear. Chaoyi Chen confirmed
this layout on the list:
https://lore.kernel.org/all/4f300b78-d96d-4d98-8819-dc292b0c9b97@rock-chips.com/
The number of NPU cores is taken from the driver's own match table.
Signed-off-by: Jiaxing Hu <gahing@gahingwoo.com>
---
drivers/accel/rocket/rocket_core.c | 2 ++
drivers/accel/rocket/rocket_core.h | 3 ++-
drivers/accel/rocket/rocket_device.c | 3 ++-
drivers/accel/rocket/rocket_drv.c | 14 +++++++++++---
drivers/accel/rocket/rocket_drv.h | 2 ++
drivers/accel/rocket/rocket_job.c | 20 ++++++++++++++++----
6 files changed, 35 insertions(+), 9 deletions(-)
diff --git a/drivers/accel/rocket/rocket_core.c b/drivers/accel/rocket/rocket_core.c
index b202d15816a3..128ebb4f19fb 100644
--- a/drivers/accel/rocket/rocket_core.c
+++ b/drivers/accel/rocket/rocket_core.c
@@ -32,6 +32,8 @@ int rocket_core_init(struct rocket_core *core)
core->clks[1].id = "hclk";
core->clks[2].id = "npu";
core->clks[3].id = "pclk";
+ 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);
diff --git a/drivers/accel/rocket/rocket_core.h b/drivers/accel/rocket/rocket_core.h
index bfbf5110b524..d5d353cc38e7 100644
--- a/drivers/accel/rocket/rocket_core.h
+++ b/drivers/accel/rocket/rocket_core.h
@@ -30,6 +30,7 @@
struct rocket_soc_data {
unsigned int num_clks;
unsigned int num_resets;
+ bool task_con_16bit;
};
struct rocket_core {
@@ -42,7 +43,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 efd004194c1a..39e8b7c49896 100644
--- a/drivers/accel/rocket/rocket_device.c
+++ b/drivers/accel/rocket/rocket_device.c
@@ -9,6 +9,7 @@
#include <linux/of.h>
#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,7 @@ 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")
+ 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 1030d8407b78..fff31c1ebe52 100644
--- a/drivers/accel/rocket/rocket_drv.c
+++ b/drivers/accel/rocket/rocket_drv.c
@@ -226,13 +226,21 @@ static void rocket_remove(struct platform_device *pdev)
static const struct rocket_soc_data rk3588_soc_data = {
.num_clks = 4,
.num_resets = 2,
+ .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,
+ .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)
{
@@ -291,7 +299,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 2c673bb99ccc..0cd692a66b85 100644
--- a/drivers/accel/rocket/rocket_drv.h
+++ b/drivers/accel/rocket/rocket_drv.h
@@ -6,10 +6,12 @@
#include <drm/drm_mm.h>
#include <drm/gpu_scheduler.h>
+#include <linux/device-id/of.h>
#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 ea23a44b1d9e..a33c9ea694f0 100644
--- a/drivers/accel/rocket/rocket_job.c
+++ b/drivers/accel/rocket/rocket_job.c
@@ -31,6 +31,11 @@
/* Bits 3:0 of PC_BASE_ADDRESS hold the mode selection bit and reserved bits */
#define ROCKET_REGCMD_ALIGN 16
+#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)
{
@@ -166,10 +171,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
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH v16 13/16] accel/rocket: add a GET_PARAM ioctl for the hardware version
2026-11-08 6:59 [PATCH v16 00/16] accel/rocket: RK3576 NPU (RKNN) enablement Jiaxing Hu
` (11 preceding siblings ...)
2026-11-08 6:59 ` [PATCH v16 12/16] accel/rocket: add RK3576 NPU (RKNN) support Jiaxing Hu
@ 2026-11-08 6:59 ` Jiaxing Hu
2026-11-08 6:59 ` [PATCH v16 14/16] arm64: dts: rockchip: add NPU core domain clocks and resets to rk3576 Jiaxing Hu
` (2 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Jiaxing Hu @ 2026-11-08 6:59 UTC (permalink / raw)
To: tomeu, heiko, robh, krzk+dt, conor+dt, joro, will, robin.murphy,
ulfh, p.zabel, ogabbay, zhangqing
Cc: royalnet026, abel.vesa, sebastian.reichel, sidong.yang,
u.kleine-koenig, chaoyi.chen, shawn.lin, finley.xiao, diederik,
alchark, leonard, jeff.hugo, rfoss, dri-devel, linux-rockchip,
iommu, linux-pm, devicetree, linux-arm-kernel, linux-kernel,
Jiaxing Hu
Add DRM_IOCTL_ROCKET_GET_PARAM so that userspace can query the NPU
hardware version and pick the matching hardware description, such as the
SRAM configuration and the register layout.
Add DRM_ROCKET_PARAM_HW_VERSION, which returns a hardware version enum
that matches the device tree compatible.
The enum starts at 1 and 0 is not used:
RK3588: 1
RK3576: 2
An unknown parameter or a non-zero reserved field returns -EINVAL.
Signed-off-by: Jiaxing Hu <gahing@gahingwoo.com>
---
drivers/accel/rocket/rocket_core.h | 1 +
drivers/accel/rocket/rocket_drv.c | 29 ++++++++++++++++++++++
include/uapi/drm/rocket_accel.h | 40 ++++++++++++++++++++++++++++++
3 files changed, 70 insertions(+)
diff --git a/drivers/accel/rocket/rocket_core.h b/drivers/accel/rocket/rocket_core.h
index d5d353cc38e7..13d962467ff0 100644
--- a/drivers/accel/rocket/rocket_core.h
+++ b/drivers/accel/rocket/rocket_core.h
@@ -31,6 +31,7 @@ struct rocket_soc_data {
unsigned int num_clks;
unsigned int num_resets;
bool task_con_16bit;
+ u32 hw_version;
};
struct rocket_core {
diff --git a/drivers/accel/rocket/rocket_drv.c b/drivers/accel/rocket/rocket_drv.c
index fff31c1ebe52..c094f6843095 100644
--- a/drivers/accel/rocket/rocket_drv.c
+++ b/drivers/accel/rocket/rocket_drv.c
@@ -5,6 +5,7 @@
#include <drm/drm_drv.h>
#include <drm/drm_gem.h>
#include <drm/drm_ioctl.h>
+#include <drm/drm_print.h>
#include <drm/rocket_accel.h>
#include <linux/clk.h>
#include <linux/err.h>
@@ -129,6 +130,31 @@ rocket_postclose(struct drm_device *dev, struct drm_file *file)
module_put(THIS_MODULE);
}
+static int
+rocket_ioctl_get_param(struct drm_device *dev, void *data, struct drm_file *file)
+{
+ struct rocket_device *rdev = to_rocket_device(dev);
+ struct drm_rocket_get_param *args = data;
+ const struct rocket_soc_data *soc;
+
+ if (args->reserved != 0) {
+ drm_dbg(dev, "Reserved field in drm_rocket_get_param struct should be 0.\n");
+ return -EINVAL;
+ }
+
+ soc = READ_ONCE(rdev->cores[0].soc);
+ if (!soc)
+ return -ENODEV;
+
+ switch (args->param) {
+ case DRM_ROCKET_PARAM_HW_VERSION:
+ args->value = soc->hw_version;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
static const struct drm_ioctl_desc rocket_drm_driver_ioctls[] = {
#define ROCKET_IOCTL(n, func) \
DRM_IOCTL_DEF_DRV(ROCKET_##n, rocket_ioctl_##func, 0)
@@ -137,6 +163,7 @@ static const struct drm_ioctl_desc rocket_drm_driver_ioctls[] = {
ROCKET_IOCTL(SUBMIT, submit),
ROCKET_IOCTL(PREP_BO, prep_bo),
ROCKET_IOCTL(FINI_BO, fini_bo),
+ ROCKET_IOCTL(GET_PARAM, get_param),
};
DEFINE_DRM_ACCEL_FOPS(rocket_accel_driver_fops);
@@ -227,12 +254,14 @@ static const struct rocket_soc_data rk3588_soc_data = {
.num_clks = 4,
.num_resets = 2,
.task_con_16bit = false,
+ .hw_version = DRM_ROCKET_HW_RK3588,
};
static const struct rocket_soc_data rk3576_soc_data = {
.num_clks = 6,
.num_resets = 1,
.task_con_16bit = true,
+ .hw_version = DRM_ROCKET_HW_RK3576,
};
const struct of_device_id rocket_dt_match[] = {
diff --git a/include/uapi/drm/rocket_accel.h b/include/uapi/drm/rocket_accel.h
index d0685e372b79..597bf892c96d 100644
--- a/include/uapi/drm/rocket_accel.h
+++ b/include/uapi/drm/rocket_accel.h
@@ -15,11 +15,13 @@ extern "C" {
#define DRM_ROCKET_SUBMIT 0x01
#define DRM_ROCKET_PREP_BO 0x02
#define DRM_ROCKET_FINI_BO 0x03
+#define DRM_ROCKET_GET_PARAM 0x04
#define DRM_IOCTL_ROCKET_CREATE_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_ROCKET_CREATE_BO, struct drm_rocket_create_bo)
#define DRM_IOCTL_ROCKET_SUBMIT DRM_IOW(DRM_COMMAND_BASE + DRM_ROCKET_SUBMIT, struct drm_rocket_submit)
#define DRM_IOCTL_ROCKET_PREP_BO DRM_IOW(DRM_COMMAND_BASE + DRM_ROCKET_PREP_BO, struct drm_rocket_prep_bo)
#define DRM_IOCTL_ROCKET_FINI_BO DRM_IOW(DRM_COMMAND_BASE + DRM_ROCKET_FINI_BO, struct drm_rocket_fini_bo)
+#define DRM_IOCTL_ROCKET_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_ROCKET_GET_PARAM, struct drm_rocket_get_param)
/**
* struct drm_rocket_create_bo - ioctl argument for creating Rocket BOs.
@@ -185,6 +187,44 @@ struct drm_rocket_submit {
__u64 reserved;
};
+/**
+ * enum drm_rocket_param - parameters for DRM_IOCTL_ROCKET_GET_PARAM
+ * @DRM_ROCKET_PARAM_HW_VERSION: an enum drm_rocket_hw_version value.
+ */
+enum drm_rocket_param {
+ DRM_ROCKET_PARAM_HW_VERSION = 0,
+};
+
+/**
+ * enum drm_rocket_hw_version - the NPU, one value per DT compatible
+ * @DRM_ROCKET_HW_RK3588: "rockchip,rk3588-rknn-core"
+ * @DRM_ROCKET_HW_RK3576: "rockchip,rk3576-rknn-core"
+ */
+enum drm_rocket_hw_version {
+ DRM_ROCKET_HW_RK3588 = 1,
+ DRM_ROCKET_HW_RK3576 = 2,
+};
+
+/**
+ * struct drm_rocket_get_param - ioctl argument for querying a parameter.
+ */
+struct drm_rocket_get_param {
+ /**
+ * @param: Input: an enum drm_rocket_param value.
+ */
+ __u32 param;
+
+ /**
+ * @reserved: Reserved, must be zero.
+ */
+ __u32 reserved;
+
+ /**
+ * @value: Output: the value of the parameter.
+ */
+ __u64 value;
+};
+
#if defined(__cplusplus)
}
#endif
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH v16 14/16] arm64: dts: rockchip: add NPU core domain clocks and resets to rk3576
2026-11-08 6:59 [PATCH v16 00/16] accel/rocket: RK3576 NPU (RKNN) enablement Jiaxing Hu
` (12 preceding siblings ...)
2026-11-08 6:59 ` [PATCH v16 13/16] accel/rocket: add a GET_PARAM ioctl for the hardware version Jiaxing Hu
@ 2026-11-08 6:59 ` Jiaxing Hu
2026-11-08 6:59 ` [PATCH v16 15/16] arm64: dts: rockchip: add NPU (RKNN) nodes " Jiaxing Hu
2026-11-08 6:59 ` [PATCH v16 16/16] arm64: dts: rockchip: enable the NPU on rk3576-rock-4d Jiaxing Hu
15 siblings, 0 replies; 17+ messages in thread
From: Jiaxing Hu @ 2026-11-08 6:59 UTC (permalink / raw)
To: tomeu, heiko, robh, krzk+dt, conor+dt, joro, will, robin.murphy,
ulfh, p.zabel, ogabbay, zhangqing
Cc: royalnet026, abel.vesa, sebastian.reichel, sidong.yang,
u.kleine-koenig, chaoyi.chen, shawn.lin, finley.xiao, diederik,
alchark, leonard, jeff.hugo, rfoss, dri-devel, linux-rockchip,
iommu, linux-pm, devicetree, linux-arm-kernel, linux-kernel,
Jiaxing Hu
The two NPU cores of the RK3576 share the CBUF and the DSU, so PD_NPU0
and PD_NPU1 also need the three clocks that PD_NPUTOP already lists.
Also add a BIU reset to each NPU power domain. The pmdomain driver cycles
it when the domain powers on, so the bus interface works.
Signed-off-by: Jiaxing Hu <gahing@gahingwoo.com>
---
arch/arm64/boot/dts/rockchip/rk3576.dtsi | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3576.dtsi b/arch/arm64/boot/dts/rockchip/rk3576.dtsi
index 7828736bf9ac..508ed48b7bee 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3576.dtsi
@@ -1159,14 +1159,22 @@ power-domain@RK3576_PD_NPUTOP {
power-domain@RK3576_PD_NPU0 {
reg = <RK3576_PD_NPU0>;
clocks = <&cru HCLK_RKNN_ROOT>,
- <&cru ACLK_RKNN0>;
+ <&cru ACLK_RKNN0>,
+ <&cru CLK_RKNN_DSU0>,
+ <&cru ACLK_RKNN_CBUF>,
+ <&cru HCLK_RKNN_CBUF>;
+ resets = <&cru SRST_A_RKNN0_BIU>;
pm_qos = <&qos_npu_m0>;
#power-domain-cells = <0>;
};
power-domain@RK3576_PD_NPU1 {
reg = <RK3576_PD_NPU1>;
clocks = <&cru HCLK_RKNN_ROOT>,
- <&cru ACLK_RKNN1>;
+ <&cru ACLK_RKNN1>,
+ <&cru CLK_RKNN_DSU0>,
+ <&cru ACLK_RKNN_CBUF>,
+ <&cru HCLK_RKNN_CBUF>;
+ resets = <&cru SRST_A_RKNN1_BIU>;
pm_qos = <&qos_npu_m1>;
#power-domain-cells = <0>;
};
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH v16 15/16] arm64: dts: rockchip: add NPU (RKNN) nodes to rk3576
2026-11-08 6:59 [PATCH v16 00/16] accel/rocket: RK3576 NPU (RKNN) enablement Jiaxing Hu
` (13 preceding siblings ...)
2026-11-08 6:59 ` [PATCH v16 14/16] arm64: dts: rockchip: add NPU core domain clocks and resets to rk3576 Jiaxing Hu
@ 2026-11-08 6:59 ` Jiaxing Hu
2026-11-08 6:59 ` [PATCH v16 16/16] arm64: dts: rockchip: enable the NPU on rk3576-rock-4d Jiaxing Hu
15 siblings, 0 replies; 17+ messages in thread
From: Jiaxing Hu @ 2026-11-08 6:59 UTC (permalink / raw)
To: tomeu, heiko, robh, krzk+dt, conor+dt, joro, will, robin.murphy,
ulfh, p.zabel, ogabbay, zhangqing
Cc: royalnet026, abel.vesa, sebastian.reichel, sidong.yang,
u.kleine-koenig, chaoyi.chen, shawn.lin, finley.xiao, diederik,
alchark, leonard, jeff.hugo, rfoss, dri-devel, linux-rockchip,
iommu, linux-pm, devicetree, linux-arm-kernel, linux-kernel,
Jiaxing Hu
Add the two NPU cores and their two IOMMUs, disabled by default; boards
enable them.
Each core is on its own power domain only: core 0 on PD_NPU0, core 1 on
PD_NPU1. Measured with both cores running, the results are correct, and
the nputop and npu domains above them are powered through the domain
hierarchy.
Label PD_NPU so a board can connect the NPU supply. The IOMMUs use four
clocks.
Also set CLK_RKNN_DSU0 to 594 MHz. Mainline sets neither its rate nor the
NPU voltage. On the ROCK 4D the DSU runs at 786 MHz by default and the
rail boots at 750 mV; with both cores running, each pass of the 5400-row
test has 11 to 25 wrong words. At 594 MHz the test is all correct. In the
vendor OPP table, the 500 MHz and 600 MHz steps both need 725 mV.
Signed-off-by: Jiaxing Hu <gahing@gahingwoo.com>
---
arch/arm64/boot/dts/rockchip/rk3576.dtsi | 70 +++++++++++++++++++++++-
1 file changed, 69 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3576.dtsi b/arch/arm64/boot/dts/rockchip/rk3576.dtsi
index 508ed48b7bee..667cbb6ad7b7 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3576.dtsi
@@ -1131,7 +1131,7 @@ power: power-controller {
#address-cells = <1>;
#size-cells = <0>;
- power-domain@RK3576_PD_NPU {
+ pd_npu: power-domain@RK3576_PD_NPU {
reg = <RK3576_PD_NPU>;
#power-domain-cells = <1>;
#address-cells = <1>;
@@ -1358,6 +1358,74 @@ power-domain@RK3576_PD_VO1 {
};
};
+ rknn_core_0: npu@27700000 {
+ compatible = "rockchip,rk3576-rknn-core";
+ reg = <0x0 0x27700000 0x0 0x1000>,
+ <0x0 0x27701000 0x0 0x1000>,
+ <0x0 0x27703000 0x0 0x1000>;
+ reg-names = "pc", "cna", "core";
+ interrupts = <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru ACLK_RKNN0>, <&cru HCLK_RKNN_ROOT>,
+ <&cru CLK_RKNN_DSU0>, <&cru PCLK_NPUTOP_ROOT>,
+ <&cru ACLK_RKNN_CBUF>, <&cru HCLK_RKNN_CBUF>;
+ clock-names = "aclk", "hclk", "npu", "pclk",
+ "aclk_cbuf", "hclk_cbuf";
+ assigned-clocks = <&cru CLK_RKNN_DSU0>;
+ assigned-clock-rates = <594000000>;
+ resets = <&cru SRST_A_RKNN0>;
+ reset-names = "srst_a";
+ power-domains = <&power RK3576_PD_NPU0>;
+ iommus = <&rknn_mmu_0>;
+ status = "disabled";
+ };
+
+ rknn_mmu_0: iommu@27702000 {
+ compatible = "rockchip,rk3576-npu-iommu", "rockchip,rk3568-iommu";
+ reg = <0x0 0x27702000 0x0 0x100>,
+ <0x0 0x27702100 0x0 0x100>;
+ interrupts = <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru ACLK_RKNN0>, <&cru HCLK_RKNN_ROOT>,
+ <&cru ACLK_RKNN_CBUF>, <&cru HCLK_RKNN_CBUF>;
+ clock-names = "aclk", "iface", "aclk_cbuf", "hclk_cbuf";
+ #iommu-cells = <0>;
+ power-domains = <&power RK3576_PD_NPU0>;
+ status = "disabled";
+ };
+
+ rknn_core_1: npu@27708000 {
+ compatible = "rockchip,rk3576-rknn-core";
+ reg = <0x0 0x27708000 0x0 0x1000>,
+ <0x0 0x27709000 0x0 0x1000>,
+ <0x0 0x2770b000 0x0 0x1000>;
+ reg-names = "pc", "cna", "core";
+ interrupts = <GIC_SPI 248 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru ACLK_RKNN1>, <&cru HCLK_RKNN_ROOT>,
+ <&cru CLK_RKNN_DSU0>, <&cru PCLK_NPUTOP_ROOT>,
+ <&cru ACLK_RKNN_CBUF>, <&cru HCLK_RKNN_CBUF>;
+ clock-names = "aclk", "hclk", "npu", "pclk",
+ "aclk_cbuf", "hclk_cbuf";
+ assigned-clocks = <&cru CLK_RKNN_DSU0>;
+ assigned-clock-rates = <594000000>;
+ resets = <&cru SRST_A_RKNN1>;
+ reset-names = "srst_a";
+ power-domains = <&power RK3576_PD_NPU1>;
+ iommus = <&rknn_mmu_1>;
+ status = "disabled";
+ };
+
+ rknn_mmu_1: iommu@2770a000 {
+ compatible = "rockchip,rk3576-npu-iommu", "rockchip,rk3568-iommu";
+ reg = <0x0 0x2770a000 0x0 0x100>,
+ <0x0 0x2770a100 0x0 0x100>;
+ interrupts = <GIC_SPI 248 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru ACLK_RKNN1>, <&cru HCLK_RKNN_ROOT>,
+ <&cru ACLK_RKNN_CBUF>, <&cru HCLK_RKNN_CBUF>;
+ clock-names = "aclk", "iface", "aclk_cbuf", "hclk_cbuf";
+ #iommu-cells = <0>;
+ power-domains = <&power RK3576_PD_NPU1>;
+ status = "disabled";
+ };
+
gpu: gpu@27800000 {
compatible = "rockchip,rk3576-mali", "arm,mali-bifrost";
reg = <0x0 0x27800000 0x0 0x20000>;
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH v16 16/16] arm64: dts: rockchip: enable the NPU on rk3576-rock-4d
2026-11-08 6:59 [PATCH v16 00/16] accel/rocket: RK3576 NPU (RKNN) enablement Jiaxing Hu
` (14 preceding siblings ...)
2026-11-08 6:59 ` [PATCH v16 15/16] arm64: dts: rockchip: add NPU (RKNN) nodes " Jiaxing Hu
@ 2026-11-08 6:59 ` Jiaxing Hu
15 siblings, 0 replies; 17+ messages in thread
From: Jiaxing Hu @ 2026-11-08 6:59 UTC (permalink / raw)
To: tomeu, heiko, robh, krzk+dt, conor+dt, joro, will, robin.murphy,
ulfh, p.zabel, ogabbay, zhangqing
Cc: royalnet026, abel.vesa, sebastian.reichel, sidong.yang,
u.kleine-koenig, chaoyi.chen, shawn.lin, finley.xiao, diederik,
alchark, leonard, jeff.hugo, rfoss, dri-devel, linux-rockchip,
iommu, linux-pm, devicetree, linux-arm-kernel, linux-kernel,
Jiaxing Hu
Enable both NPU cores and their IOMMUs in the ROCK 4D device tree.
Make vdd_npu_s0 the supply of the NPU power domain, so the NPU rail is
switched on and off with the domain.
Signed-off-by: Jiaxing Hu <gahing@gahingwoo.com>
---
.../boot/dts/rockchip/rk3576-rock-4d.dts | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3576-rock-4d.dts b/arch/arm64/boot/dts/rockchip/rk3576-rock-4d.dts
index f068794e48d4..72b251d396fe 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576-rock-4d.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3576-rock-4d.dts
@@ -722,6 +722,10 @@ &pcie0 {
status = "okay";
};
+&pd_npu {
+ domain-supply = <&vdd_npu_s0>;
+};
+
&pinctrl {
hdmi {
hdmi_tx_on_h: hdmi-tx-on-h {
@@ -779,6 +783,24 @@ wifi_en_h: wifi-en-h {
};
};
+&rknn_core_0 {
+ npu-supply = <&vdd_npu_s0>;
+ status = "okay";
+};
+
+&rknn_mmu_0 {
+ status = "okay";
+};
+
+&rknn_core_1 {
+ npu-supply = <&vdd_npu_s0>;
+ status = "okay";
+};
+
+&rknn_mmu_1 {
+ status = "okay";
+};
+
&sai6 {
status = "okay";
};
--
2.43.0
^ permalink raw reply [flat|nested] 17+ messages in thread