Out-of-tree DKMS module for the Rockchip NPU (RKNPU) driver, extracted from the Rockchip kernel (6.6.y). Enables NPU hardware on Rockchip SoCs when using a vanilla/mainline kernel.
| SoC | Compatible String | Cores |
|---|---|---|
| RK3566 / RK3568 | rockchip,rknpu / rockchip,rk3568-rknpu |
1 |
| RK3562 | rockchip,rk3562-rknpu |
1 |
| RK3576 | rockchip,rk3576-rknpu |
2 |
| RK3588 / RK3583 | rockchip,rk3588-rknpu |
3 / 2 |
| RV1106 | rockchip,rv1106-rknpu |
1 |
- Linux kernel 6.1.y - 6.12.y (arm64) with the following enabled:
CONFIG_DRM=morCONFIG_DRM=yCONFIG_IOMMU_API=yCONFIG_ROCKCHIP_IOMMU=yCONFIG_SYNC_FILE=yCONFIG_PROC_FS=y
- Appropriate device tree with RKNPU node and IOMMU phandle
- Kernel headers installed (for DKMS build)
# Copy to DKMS source directory
sudo cp -r . /usr/src/rknpu-0.9.8
# Add and build
sudo dkms add rknpu/0.9.8
sudo dkms build rknpu/0.9.8
sudo dkms install rknpu/0.9.8
# Load the module
sudo modprobe rknpu# Native build
make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
# Cross-compile for aarch64
make -C <kernel-source> ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- M=$(pwd) modulesThe driver registers as a DRM render node (/dev/dri/renderD*) and exposes
custom ioctls for NPU job submission and memory management via DRM GEM.
- DRM GEM memory management — standard kernel DRM subsystem
- DMA fence support — for synchronization between CPU and NPU
- procfs interface —
/proc/rknpu/for status, load, freq, power monitoring
- devfreq / DVFS — requires Rockchip OPP framework (
rockchip_opp_select.h) - SRAM allocation — requires
CONFIG_NO_GKI(Rockchip-specific) - DMA Heap backend — requires
rk-dma-heap(Rockchip-specific) - debugfs — not critical; enable
CONFIG_DEBUG_FSin kernel if desired
This module provides stub headers under compat/ for Rockchip-specific kernel
APIs that don't exist in vanilla kernels:
soc/rockchip/rockchip_opp_select.h— OPP/DVFS stubssoc/rockchip/rockchip_system_monitor.h— thermal monitor stubssoc/rockchip/rockchip_ipa.h— IPA power model stubssoc/rockchip/rockchip_iommu.h— IOMMU helper stubslinux/version_compat_defs.h—vm_flags_set/clearcompat for pre-6.3
The driver will function correctly for NPU inference workloads. Dynamic frequency/voltage scaling will not be available without the Rockchip OPP framework — the NPU runs at whatever frequency is set by the bootloader or device tree.
Upstream kernels do not include the NPU or its IOMMU device-tree nodes.
You need to patch two layers: the SoC DTSI (rk356x.dtsi) shared by
all RK3566/RK3568 boards, then one small addition in the board DTS to
wire the supply regulator and enable the node.
Important — NPU supply regulator must be always-on. The upstream
rockchip-pm-domaindriver has no per-domain regulator support (unlike the Radxa/Rockchip vendor kernel). When the genpd framework powers onPD_NPUduring driver probe, the NPU silicon must already be receiving voltage. If the supply regulator (vdd_npuon most boards) is not enabled, the NIU bus interconnect cannot leave its idle state and a subsequent QoS register write triggers an SError / kernel panic. Addingregulator-always-on; regulator-boot-on;to the NPU supply regulator in the board DTS prevents this.
To quickly extract the patches, run:
sed -n -e '/^```diff/,/^```/{/^```/d; p}' README.mdApply this to arch/arm64/boot/dts/rockchip/rk356x.dtsi:
--- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
@@ -550,6 +550,14 @@ power: power-controller {
#address-cells = <1>;
#size-cells = <0>;
+ /* These power domains are grouped by VD_NPU */
+ power-domain@RK3568_PD_NPU {
+ reg = <RK3568_PD_NPU>;
+ clocks = <&cru ACLK_NPU_PRE>,
+ <&cru HCLK_NPU_PRE>,
+ <&cru PCLK_NPU_PRE>;
+ pm_qos = <&qos_npu>;
+ };
/* These power domains are grouped by VD_GPU */
power-domain@RK3568_PD_GPU {
reg = <RK3568_PD_GPU>;
@@ -619,6 +627,33 @@ power-domain@RK3568_PD_RKVENC {
};
};
+ rknpu: npu@fde40000 {
+ compatible = "rockchip,rk3568-rknpu", "rockchip,rknpu";
+ reg = <0x0 0xfde40000 0x0 0x10000>;
+ interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&scmi_clk 2>, <&cru CLK_NPU>,
+ <&cru ACLK_NPU>, <&cru HCLK_NPU>;
+ clock-names = "scmi_clk", "clk", "aclk", "hclk";
+ assigned-clocks = <&cru CLK_NPU>;
+ assigned-clock-rates = <600000000>;
+ resets = <&cru SRST_A_NPU>, <&cru SRST_H_NPU>;
+ reset-names = "srst_a", "srst_h";
+ power-domains = <&power RK3568_PD_NPU>;
+ iommus = <&rknpu_mmu>;
+ status = "disabled";
+ };
+
+ rknpu_mmu: iommu@fde4b000 {
+ compatible = "rockchip,iommu";
+ reg = <0x0 0xfde4b000 0x0 0x40>;
+ interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru ACLK_NPU>, <&cru HCLK_NPU>;
+ clock-names = "aclk", "iface";
+ power-domains = <&power RK3568_PD_NPU>;
+ #iommu-cells = <0>;
+ status = "disabled";
+ };
+
gpu: gpu@fde60000 {
compatible = "rockchip,rk3568-mali", "arm,mali-bifrost";
reg = <0x0 0xfde60000 0x0 0x4000>;The &vdd_npu override ensures the NPU power rail (DCDC_REG4 on the
RK809 PMIC) is enabled at boot so PD_NPU can power on without an SError.
--- a/arch/arm64/boot/dts/rockchip/rk3568-rock-3a.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3568-rock-3a.dts
@@ -867,3 +867,42 @@ vp0_out_hdmi: endpoint@ROCKCHIP_VOP2_EP_HDMI0 {
remote-endpoint = <&hdmi_in_vp0>;
};
};
+
+&vdd_npu {
+ regulator-always-on;
+ regulator-boot-on;
+};
+
+&rknpu {
+ rknpu-supply = <&vdd_npu>;
+ status = "okay";
+};
+
+&rknpu_mmu {
+ status = "okay";
+};
+
+// These are only necessary for 6.6.y and later. See README.md
+&vpu {
+ status = "disabled";
+};
+
+&vdpu_mmu {
+ status = "disabled";
+};
+
+&vepu {
+ status = "disabled";
+};
+
+&vepu_mmu {
+ status = "disabled";
+};
+
+&vop {
+ status = "disabled";
+};
+
+&vop_mmu {
+ status = "disabled";
+};Same regulator fix as Rock 3A — vdd_npu is DCDC_REG4 on the RK809 PMIC.
--- a/arch/arm64/boot/dts/rockchip/rk3566-rock-3c.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-rock-3c.dts
@@ -725,3 +725,42 @@ vp0_out_hdmi: endpoint@ROCKCHIP_VOP2_EP_HDMI0 {
remote-endpoint = <&hdmi_in_vp0>;
};
};
+
+&vdd_npu {
+ regulator-always-on;
+ regulator-boot-on;
+};
+
+&rknpu {
+ rknpu-supply = <&vdd_npu>;
+ status = "okay";
+};
+
+&rknpu_mmu {
+ status = "okay";
+};
+
+// These are only necessary for 6.6.y and later. See README.md
+&vpu {
+ status = "disabled";
+};
+
+&vdpu_mmu {
+ status = "disabled";
+};
+
+&vepu {
+ status = "disabled";
+};
+
+&vepu_mmu {
+ status = "disabled";
+};
+
+&vop {
+ status = "disabled";
+};
+
+&vop_mmu {
+ status = "disabled";
+};The ZERO 3E shares its GPU/NPU supply rail (vdd_gpu, DCDC_REG2 on the
RK817 PMIC). This regulator is typically already regulator-always-on in the
board DTS (since it also powers the GPU), so no extra override is needed.
--- a/arch/arm64/boot/dts/rockchip/rk3566-radxa-zero-3e.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-radxa-zero-3e.dts
@@ -50,3 +50,37 @@ gmac1_rstn: gmac1-rstn {
};
};
};
+
+&rknpu {
+ rknpu-supply = <&vdd_gpu_npu>;
+ status = "okay";
+};
+
+&rknpu_mmu {
+ status = "okay";
+};
+
+// These are only necessary for 6.6.y and later. See README.md
+&vpu {
+ status = "disabled";
+};
+
+&vdpu_mmu {
+ status = "disabled";
+};
+
+&vepu {
+ status = "disabled";
+};
+
+&vepu_mmu {
+ status = "disabled";
+};
+
+&vop {
+ status = "disabled";
+};
+
+&vop_mmu {
+ status = "disabled";
+};# From the kernel source tree, after applying the patches above:
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs
# Copy the resulting DTB to your board:
scp arch/arm64/boot/dts/rockchip/rk3568-rock-3a.dtb root@board:/boot/dtbs/Replace the DTB your bootloader loads (path depends on distro) and reboot.
Some intermediate 6.6.y kernel versions made drm_gem_prime_handle_to_fd and
drm_gem_prime_fd_to_handle private symbols, causing compilation errors on
those specific versions. Later 6.6.y releases made these functions public
again. If you encounter such errors, they are transitory and a newer 6.6.y
kernel version should resolve them.
Important: On kernel 6.6 and later, the Rockchip 356x NPU IOMMU only works
reliably with the v1 compatible string, rockchip,iommu.
A commit
enables IOMMU page table allocations above the 32 bit address space. The lack of
NPU documentation and the available kernel driver suggests
that the NPU cannot access memory above the 32 bit address space. The Rockchip
iommu-v1 and iommu-v2 drivers page table handling is equivalent for addresses in
the 32 bit space. Thus using the v1 compatible string (rockchip,iommu)
for the NPU MMU node forces the Rockchip IOMMU driver to allocate page tables
from the 32-bit region, which matches the apparent NPU limitation. In other words,
rockchip,iommu is required here not because the NPU needs an older page-table
format, but because it ensures the page tables land in address space the NPU can
actually reach.
The problem is that the current upstream rockchip-iommu driver does not allow
multiple Rockchip IOMMU variants to coexist in the same system. Once the NPU is
switched to rockchip,iommu, the other Rockchip IOMMU devices and their devices
must be turned off (i.e. disabled).
In practice this means that using NPU is exclusive with other IOMMU subsystems (VOP, VEPU, VDPU).
GPL-2.0 — see source file headers for details.
Extracted from Rockchip's kernel tree (drivers/rknpu/), version 0.9.8 (2024-08-28).