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
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
54f961c6b6
commit
7e76553bd7
@@ -0,0 +1,37 @@
|
||||
# HPMCU mailbox-echo firmware — bare-metal RV32IMC for the RV1106 SCR1 core.
|
||||
# Same xPack riscv-none-embed-gcc 10.2.0 + flags as the watchdog firmware.
|
||||
|
||||
XPACK ?= <flare-edge>/sdk/sysdrv/source/mcu/prebuilts/gcc/linux-x86/riscv64/xpack-riscv-none-embed-gcc-10.2.0-1.2/bin
|
||||
CROSS ?= $(XPACK)/riscv-none-embed-
|
||||
|
||||
CC = $(CROSS)gcc
|
||||
OBJCOPY = $(CROSS)objcopy
|
||||
SIZE = $(CROSS)size
|
||||
|
||||
CFLAGS = -march=rv32imc -mabi=ilp32 -mcmodel=medany -Os -g \
|
||||
-ffreestanding -nostdlib -fno-builtin \
|
||||
-ffunction-sections -fdata-sections -Wall -Wextra
|
||||
LDFLAGS = -T link.lds -nostdlib -Wl,--gc-sections -Wl,-Map=mailbox-echo.map
|
||||
|
||||
OBJS = start.o main.o
|
||||
|
||||
all: hpmcu-mailbox-echo.bin
|
||||
|
||||
hpmcu-mailbox-echo.elf: $(OBJS) link.lds
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS)
|
||||
$(SIZE) $@
|
||||
|
||||
hpmcu-mailbox-echo.bin: hpmcu-mailbox-echo.elf
|
||||
$(OBJCOPY) -O binary $< $@
|
||||
@ls -la $@
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
%.o: %.S
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f *.o *.elf *.bin *.map
|
||||
|
||||
.PHONY: all clean
|
||||
@@ -0,0 +1,39 @@
|
||||
0x00000297
|
||||
0x03228293
|
||||
0x30529073
|
||||
0x00002117
|
||||
0xef410113
|
||||
0x00000517
|
||||
0x08850513
|
||||
0x00000597
|
||||
0x08058593
|
||||
0x00b57663
|
||||
0x00052023
|
||||
0xbfdd0511
|
||||
0xa0012011
|
||||
0x584f4737
|
||||
0xff7007b7
|
||||
0x24d70713
|
||||
0xf0e7a423
|
||||
0xf007a623
|
||||
0xf007a823
|
||||
0x07b7473d
|
||||
0xc398ff5c
|
||||
0x06374681
|
||||
0x4885ff5c
|
||||
0xff7005b7
|
||||
0x2e034311
|
||||
0x07930046
|
||||
0x47010086
|
||||
0x00e89833
|
||||
0x01c87533
|
||||
0x4388cd11
|
||||
0x0047ae83
|
||||
0xd7880685
|
||||
0x03d7a623
|
||||
0x01062223
|
||||
0xf0a5a623
|
||||
0xf0d5a823
|
||||
0x07a10705
|
||||
0xfc671ce3
|
||||
0x0000b7e9
|
||||
Binary file not shown.
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* HPMCU watchdog supervisor — linked into the hpmcu_sram carve-out.
|
||||
*
|
||||
* The RV1106's 256K on-chip SRAM at 0xFF6C0000 is split by the kernel DT
|
||||
* (rv1106.dtsi sram@ff6c0000) into rkisp_sram (0x0..0x3e000) and hpmcu_sram
|
||||
* (0x3e000..0x40000, i.e. 0xFF6FE000..0xFF700000). We live entirely inside
|
||||
* the 8K hpmcu region:
|
||||
*
|
||||
* 0xFF6FE000 +0x0000 .text/.rodata/.data/.bss (this script: 0x1C00)
|
||||
* 0xFF6FFC00 +0x1C00 stack (grows down from 0xFF6FFF00)
|
||||
* 0xFF6FFF00 +0x1F00 heartbeat mailbox (shared with Linux, see main.c)
|
||||
*/
|
||||
OUTPUT_ARCH(riscv)
|
||||
ENTRY(_start)
|
||||
|
||||
MEMORY
|
||||
{
|
||||
SRAM (rwx) : ORIGIN = 0xFF6FE000, LENGTH = 0x1C00
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text : {
|
||||
*(.text.start)
|
||||
*(.text*)
|
||||
} > SRAM
|
||||
|
||||
.rodata : { *(.rodata*) *(.srodata*) } > SRAM
|
||||
.data : { *(.data*) *(.sdata*) } > SRAM
|
||||
|
||||
.bss (NOLOAD) : {
|
||||
. = ALIGN(4);
|
||||
__bss_start = .;
|
||||
*(.bss*) *(.sbss*) *(COMMON)
|
||||
. = ALIGN(4);
|
||||
__bss_end = .;
|
||||
} > SRAM
|
||||
|
||||
/* Stack: from the mailbox floor down toward .bss. */
|
||||
__stack_top = 0xFF6FFF00;
|
||||
|
||||
/DISCARD/ : { *(.eh_frame) *(.riscv.attributes) *(.comment) }
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#!/bin/sh
|
||||
# Load the SCR1 mailbox-echo firmware into hpmcu_sram (0xFF6FE000) and start the
|
||||
# core, replicating flared/hpmcu.rs load_and_release() EXACTLY (the proven
|
||||
# sequence): GRF uncached peripheral window -> CORECRU hold -> firmware to SRAM
|
||||
# -> clear SRAM mailbox -> SGRF boot addr -> CORECRU release. SRAM path only
|
||||
# (NOT the 0x40000 boot-load brick hazard).
|
||||
#
|
||||
# Do NOT kill warden-flared: it does a ONE-SHOT firmware load at boot then just
|
||||
# beats the SRAM heartbeat + pets the kernel dw-wdt. Killing it stops the dw-wdt
|
||||
# petting and the board resets ~15s later. We simply reset the SCR1 and reload;
|
||||
# flared won't re-load over us (one-shot), and its heartbeat writes are to a
|
||||
# different SRAM word than our echo firmware uses. (clk_core_mcu is kept alive by
|
||||
# CLK_IGNORE_UNUSED in clk-rv1106.c, so the released core actually runs.)
|
||||
FW=${1:-/userdata/echo-fw-words.txt}
|
||||
|
||||
# GRF uncached peripheral window (covers CRU + this SRAM + the mailbox
|
||||
# 0xff5c0000) — WITHOUT this the MCU's peripheral/SRAM accesses are cached and
|
||||
# invisible to Linux. hpmcu.rs: GRF_BASE 0xff040000 +0x24/+0x28 = 0xff000/0xffc00.
|
||||
devmem 0xff040024 32 0xff000
|
||||
devmem 0xff040028 32 0xffc00
|
||||
|
||||
# hold CORECRU MCU core in reset while we (re)write firmware
|
||||
devmem 0xff3b8a04 32 0x001e001e
|
||||
|
||||
# write firmware words to 0xFF6FE000 (devmem uses mmap -> SRAM writable)
|
||||
i=0
|
||||
while read w; do
|
||||
a=$(printf '0x%x' $((0xff6fe000 + i * 4)))
|
||||
devmem "$a" 32 "$w"
|
||||
i=$((i + 1))
|
||||
done < "$FW"
|
||||
|
||||
# clear the SRAM mailbox/debug area (0xFF6FFF00, 8 words) so stale state can't
|
||||
# be mistaken for a live echo
|
||||
j=0
|
||||
while [ $j -lt 8 ]; do
|
||||
devmem "$(printf '0x%x' $((0xff6fff00 + j * 4)))" 32 0
|
||||
j=$((j + 1))
|
||||
done
|
||||
|
||||
# set HPMCU boot addr, then release from reset
|
||||
devmem 0xff076044 32 0xff6fe000
|
||||
devmem 0xff3b8a04 32 0x001e0000
|
||||
sleep 1
|
||||
echo "loaded $i words; SCR1 released."
|
||||
echo " DBG_STATE = $(devmem 0xff6fff08 32) (expect 0x584F424D = 'MBOX')"
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* HPMCU mailbox echo firmware for the RV1106 (Syntacore SCR1, RV32IMC).
|
||||
*
|
||||
* Purpose: prove a fully-open A7 <-> HPMCU hardware-mailbox round-trip on our
|
||||
* self-built Linux 6.18. The A7 (Linux) writes a {cmd,dat} pair into the
|
||||
* mailbox A2B registers; this core polls A2B_STATUS, reads the pair, echoes it
|
||||
* verbatim into the B2A registers (which raises the B2A doorbell IRQ back to
|
||||
* Linux), and acks. No RT-Thread, no interrupts on the MCU side, machine mode
|
||||
* only: a polling loop, exactly like the watchdog firmware.
|
||||
*
|
||||
* The mailbox IP is at 0xFF5C0000 (the HPMCU-connected instance: Linux resets
|
||||
* it via SRST_CORE_MCU, the vendor MCU CMSIS header hard-codes MBOX_BASE
|
||||
* 0xFF5C0000). Register model is IP-identical to rk3368 (mainline
|
||||
* rockchip-mailbox.c): writing A2B_CMD(x) is the doorbell (hardware sets the
|
||||
* A2B_STATUS bit); writing B2A_CMD(x) signals Linux (B2A_STATUS + IRQ).
|
||||
*
|
||||
* Both the mailbox registers and hpmcu_sram sit in the GRF "peripheral
|
||||
* uncached" window (0xFF000000..0xFFC00000) configured at MCU release, so both
|
||||
* sides see each other's writes with no cache maintenance (same property the
|
||||
* watchdog SRAM mailbox relies on).
|
||||
*
|
||||
* Loaded + started by the proven flared/hpmcu.rs SRAM sequence
|
||||
* (0xFF6FE000 load addr, CORECRU reset hold/release) — NOT the 0x40000
|
||||
* boot-load path (that bricks a non-TB board; see boot-loaded-mcu-0x40000
|
||||
* hazard). Fits the 8K hpmcu_sram budget (this is a few hundred bytes).
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define REG32(a) (*(volatile uint32_t *)(uintptr_t)(a))
|
||||
|
||||
/* Mailbox IP (HPMCU-connected instance) — offsets match rockchip-mailbox.c. */
|
||||
#define MBOX_BASE 0xFF5C0000u
|
||||
#define A2B_INTEN REG32(MBOX_BASE + 0x00)
|
||||
#define A2B_STATUS REG32(MBOX_BASE + 0x04)
|
||||
#define A2B_CMD(x) REG32(MBOX_BASE + 0x08 + (x) * 8)
|
||||
#define A2B_DAT(x) REG32(MBOX_BASE + 0x0c + (x) * 8)
|
||||
#define B2A_STATUS REG32(MBOX_BASE + 0x2C)
|
||||
#define B2A_CMD(x) REG32(MBOX_BASE + 0x30 + (x) * 8)
|
||||
#define B2A_DAT(x) REG32(MBOX_BASE + 0x34 + (x) * 8)
|
||||
|
||||
#define NUM_CHANS 4
|
||||
|
||||
/*
|
||||
* Liveness window in hpmcu_sram (reuse the watchdog mailbox layout at
|
||||
* 0xFF6FFF00 so Linux tooling can read it the same way). We only touch the
|
||||
* MCU-owned slots; the echo firmware does NOT run the watchdog, so it never
|
||||
* touches MB_MAGIC/MB_COUNTER or fires a reset.
|
||||
*
|
||||
* +0x08 mcu_state : 'M','B','O','X' (0x584F424D LE) once the echo loop runs
|
||||
* +0x0c last_cmd : the last cmd echoed (debug)
|
||||
* +0x10 echo_cnt : number of messages echoed (heartbeat / proof-of-life)
|
||||
*/
|
||||
#define SRAM_DBG_BASE 0xFF6FFF00u
|
||||
#define DBG_STATE REG32(SRAM_DBG_BASE + 0x08)
|
||||
#define DBG_LASTCMD REG32(SRAM_DBG_BASE + 0x0c)
|
||||
#define DBG_ECHOCNT REG32(SRAM_DBG_BASE + 0x10)
|
||||
|
||||
#define STATE_MBOX 0x584F424Du /* "MBOX" (LE bytes 'M','B','O','X') */
|
||||
|
||||
void main(void)
|
||||
{
|
||||
uint32_t echoes = 0;
|
||||
|
||||
DBG_STATE = STATE_MBOX;
|
||||
DBG_LASTCMD = 0;
|
||||
DBG_ECHOCNT = 0;
|
||||
|
||||
/* Enable the A2B doorbell for all channels: without A2B_INTEN set on the
|
||||
* receiver (MCU) side, an A7 write to A2B_CMD does not raise A2B_STATUS,
|
||||
* so our poll below never sees a message. (Symmetric to the A7 controller
|
||||
* setting B2A_INTEN in its startup.) */
|
||||
A2B_INTEN = (1u << NUM_CHANS) - 1;
|
||||
|
||||
for (;;) {
|
||||
uint32_t status = A2B_STATUS;
|
||||
int ch;
|
||||
|
||||
for (ch = 0; ch < NUM_CHANS; ch++) {
|
||||
if (status & (1u << ch)) {
|
||||
uint32_t cmd = A2B_CMD(ch);
|
||||
uint32_t dat = A2B_DAT(ch);
|
||||
|
||||
/* Echo verbatim. Writing B2A_CMD raises the B2A
|
||||
* doorbell (hardware sets B2A_STATUS -> Linux
|
||||
* IRQ / readable status). */
|
||||
B2A_CMD(ch) = cmd;
|
||||
B2A_DAT(ch) = dat;
|
||||
|
||||
/* Ack: clear our A2B_STATUS bit (write-1-clear). */
|
||||
A2B_STATUS = (1u << ch);
|
||||
|
||||
DBG_LASTCMD = cmd;
|
||||
DBG_ECHOCNT = ++echoes;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
# Prove the A7<->HPMCU mailbox round-trip on channel 0. Write A2B_CMD first, then
|
||||
# A2B_DAT — the A2B_DAT write is the doorbell (raises A2B_STATUS on the MCU side,
|
||||
# whose echo firmware has enabled A2B_INTEN), so both CMD and DAT are current when
|
||||
# the SCR1 reads them. The SCR1 echoes {cmd,dat} verbatim into B2A_CMD/B2A_DAT.
|
||||
CMD=${1:-0x00001234}
|
||||
DAT=${2:-0xcafef00d}
|
||||
echo "liveness: DBG_STATE=$(devmem 0xff6fff08 32) (want 0x584F424D 'MBOX') echoes_before=$(devmem 0xff6fff10 32)"
|
||||
devmem 0xff5c0008 32 "$CMD" # A2B_CMD(0)
|
||||
devmem 0xff5c000c 32 "$DAT" # A2B_DAT(0) -- doorbell
|
||||
sleep 1
|
||||
echo "sent CMD=$CMD DAT=$DAT"
|
||||
echo "echoed B2A_CMD=$(devmem 0xff5c0030 32) B2A_DAT=$(devmem 0xff5c0034 32)"
|
||||
echo "echoes_after=$(devmem 0xff6fff10 32)"
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* HPMCU watchdog entry. The BootROM-style loader (or flared's runtime
|
||||
* loader) points CORE_SGRF_HPMCU_BOOT_ADDR here and releases the SCR1 core
|
||||
* from CORECRU reset; there is no CRT, no interrupts, machine mode only.
|
||||
*/
|
||||
.section .text.start, "ax"
|
||||
.globl _start
|
||||
_start:
|
||||
/* Belt-and-braces: no traps expected, but if one fires, land on a
|
||||
* tight loop at a known address rather than executing garbage. */
|
||||
la t0, _trap
|
||||
csrw mtvec, t0
|
||||
|
||||
la sp, __stack_top
|
||||
|
||||
/* Clear .bss */
|
||||
la a0, __bss_start
|
||||
la a1, __bss_end
|
||||
1: bgeu a0, a1, 2f
|
||||
sw zero, 0(a0)
|
||||
addi a0, a0, 4
|
||||
j 1b
|
||||
|
||||
2: call main
|
||||
/* main never returns; if it does, spin. */
|
||||
_trap:
|
||||
3: j 3b
|
||||
Reference in New Issue
Block a user