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
99 lines
3.6 KiB
C
99 lines
3.6 KiB
C
/*
|
|
* 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;
|
|
}
|
|
}
|
|
}
|
|
}
|