Files
bfe-core1106-sdk/kernel/rv1106-enablement/npu/rknpu_version_test.c
T
BFE EngineeringandClaude Opus 4.8 7e76553bd7 kernel/rv1106: HPMCU mailbox 100% VERIFIED + open NPU driver VERIFIED
MAILBOX (fully open A7<->RISC-V SCR1 round-trip, 5/5 exact echoes on c8a3):
- rockchip-mailbox.c: rv1106 has 1 shared IRQ, not 4/channel -> added
  rv1106_drv_data{num_chans=1} + compatible (rk3368 fallback assumed 4 -> probe
  failed 'IRQ index 1 not found').
- clk-rv1106.c: CLK_CORE_MCU (SCR1 core clock) marked CLK_IGNORE_UNUSED -
  6.18's clk_disable_unused() was switching off the coprocessor clock so a
  loaded firmware never ran (5.10 left it on).
- Open SCR1 echo firmware (scr1-echo/, 154B RV32IMC) + load/test scripts;
  A2B_INTEN on the MCU side + CMD-then-DAT (DAT=doorbell) order. Loaded via the
  proven hpmcu.rs SRAM path; do NOT kill warden-flared (dw-wdt). mailbox/VERIFIED.md.

NPU (open GPL rknpu 0.9.2 kernel driver on 6.18):
- DT fix: base npu node lacks interrupt-names, driver requests IRQ byname
  'npu_irq' -> probe bailed -ENXIO. Added interrupt-names='npu_irq'.
- Verified: [drm] Initialized rknpu 0.9.2 on minor 1; /dev/dri/card1;
  rknpu_version_test PASS (0.9.2 + hw version, full power/clock/reset path).
- Honest ceiling: open compute (regcmd compiler) is a from-scratch ~person-year
  RE project, no RV1106 prior art; ship the driver, no blob. npu/VERIFIED.md.

DRIVER-PARITY + CAPABILITIES-AUDIT updated; dts snapshot refreshed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017wB8KB3MMQztRDXCMCkPrf
2026-08-25 08:36:56 -06:00

138 lines
4.3 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* rknpu_version_test.c -- standalone hardware smoke test for the RKNPU
* kernel driver port (see PORT-PLAN.md / PORT-PROGRESS.md in this
* directory).
*
* Opens a DRM node (tries /dev/dri/card0, then card1, then renderD128),
* issues DRM_IOCTL_RKNPU_ACTION with RKNPU_GET_DRV_VERSION and then
* RKNPU_GET_HW_VERSION, and prints the decoded results. This exercises the
* full ioctl-dispatch -> power-get/put -> clock/reset path with zero
* dependency on a regcmd buffer or the (closed) RKNN runtime -- see
* OPEN-NPU-PLAN.md §1.4 Tier A and PORT-PLAN.md §3 step 5.
*
* Dependency-free beyond the UAPI header: build with
* -I<kernel-tree>/include/uapi
* so both <drm/drm.h> and <drm/rknpu_ioctl.h> (and the linux/types.h,
* linux/ioctl.h they need) resolve entirely out of the kernel tree's own
* include/uapi/ -- no libdrm, no target sysroot headers required.
*
* Cross-compile (see PORT-PROGRESS.md for the full recipe):
*
* export PATH="<flare-edge>/sdk/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin:/usr/bin:/bin"
* arm-rockchip830-linux-uclibcgnueabihf-gcc \
* -I<flare-edge>/research/linux-6.18.46/include/uapi \
* -Wall -O2 -static -o rknpu_version_test rknpu_version_test.c
*
* (add -static if the target rootfs's libc version/ABI is in doubt; drop it
* for a smaller dynamically-linked binary if the rootfs libc is known good.)
*
* Expected output on a working probe:
*
* opened /dev/dri/card0 (fd=3)
* driver version: 0.9.2 (raw code 902)
* hw version: 0x.... (raw)
* PASS: /dev/dri/card0 answered both version-query ioctls -- probe,
* power-get/put, and clock/reset all exercised.
*
* "0.9.2" is DRIVER_MAJOR/MINOR/PATCHLEVEL from the vendor source
* (rknpu_drv.h) unmodified by this port -- a match confirms the ioctl
* round-trip reached real driver code, not a stub. The hw version is a raw
* value read directly off the NPU core's VERSION/VERSION_NUM registers
* (rknpu_job.c:rknpu_get_hw_version()) -- any non-zero, non-0xffffffff
* value is a plausible "the register block is alive" signal; there is no
* published decode table for it beyond that (PORT-PLAN.md §3 step 5).
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <drm/rknpu_ioctl.h>
static const char *const candidates[] = {
"/dev/dri/card0",
"/dev/dri/card1",
"/dev/dri/renderD128",
NULL,
};
static int do_action(int fd, __u32 flags, __u32 *value)
{
struct rknpu_action act;
memset(&act, 0, sizeof(act));
act.flags = flags;
if (ioctl(fd, DRM_IOCTL_RKNPU_ACTION, &act) < 0)
return -errno;
*value = act.value;
return 0;
}
int main(void)
{
int fd = -1;
const char *path = NULL;
__u32 drv_version = 0;
__u32 hw_version = 0;
int ret;
int i;
/* There may be several DRM cards (the VOP display registers card0, the
* NPU registers its own). Try each candidate and keep the FIRST that
* actually answers the RKNPU version ioctl -- opening successfully is not
* enough (the display card opens fine but returns EINVAL). */
for (i = 0; candidates[i] != NULL; i++) {
int f = open(candidates[i], O_RDWR | O_CLOEXEC);
if (f < 0) {
fprintf(stderr, "open(%s): %s\n", candidates[i],
strerror(errno));
continue;
}
if (do_action(f, RKNPU_GET_DRV_VERSION, &drv_version) == 0) {
fd = f;
path = candidates[i];
break;
}
fprintf(stderr, "%s: not an rknpu node (version ioctl: %s)\n",
candidates[i], strerror(errno));
close(f);
}
if (fd < 0) {
fprintf(stderr,
"FAIL: no DRM node answered the RKNPU version ioctl -- "
"is CONFIG_ROCKCHIP_RKNPU probed? check "
"`dmesg | grep -i rknpu` and `ls -la /dev/dri/`\n");
return 1;
}
printf("opened %s (fd=%d)\n", path, fd);
ret = 0;
printf("driver version: %u.%u.%u (raw code %u)\n",
RKNPU_GET_DRV_VERSION_MAJOR(drv_version),
RKNPU_GET_DRV_VERSION_MINOR(drv_version),
RKNPU_GET_DRV_VERSION_PATCHLEVEL(drv_version), drv_version);
ret = do_action(fd, RKNPU_GET_HW_VERSION, &hw_version);
if (ret) {
fprintf(stderr,
"FAIL: DRM_IOCTL_RKNPU_ACTION(RKNPU_GET_HW_VERSION): %s\n",
strerror(-ret));
close(fd);
return 1;
}
printf("hw version: 0x%08x (raw)\n", hw_version);
printf("PASS: %s answered both version-query ioctls -- probe, "
"power-get/put, and clock/reset all exercised.\n", path);
close(fd);
return 0;
}