Skip to content

Caliptra I3C Peripheral Driver - #417

Draft
rusty1968 wants to merge 10 commits into
OpenPRoT:mainfrom
rusty1968:ss-i3c-peripheral
Draft

Caliptra I3C Peripheral Driver#417
rusty1968 wants to merge 10 commits into
OpenPRoT:mainfrom
rusty1968:ss-i3c-peripheral

Conversation

@rusty1968

Copy link
Copy Markdown
Collaborator

No description provided.

The stock caliptra-mcu-sw emulator main only drains the I3C socket's
command channel into the emulated target when built with one of its
test-* cargo features; in a featureless build, frames written to
--i3c-port accumulate in an mpsc channel nobody reads, so the firmware's
TTI RX queue never fills and the smoke test could not pass.

Replace the emulator's entry point with a local main (linking the
unmodified upstream emulator_lib) that unconditionally calls the public
start_i3c_controller() before the run loop, following the same
local-main pattern as the signer target.

Also harden the test itself:
- target.rs: drop enable_rx_interrupt() and pure-poll instead; the
  system image has an empty interrupt table, and a delivered frame
  would vector the CPU to address zero (observed as a terminal
  mcause=1 exception at epc=0).
- host harness: treat only the firmware's "waiting for private write"
  log line as readiness (the emulator's socket banner prints minutes
  before firmware boots), and keep sending frames until the runner
  exits instead of 15 attempts fired during boot.

i3c_smoke_test now passes in ~16s (previously failed after 161s).
The i3c-core TTI expects the descriptor before the data: the TX
descriptor write opens the buffer that subsequent tx_data_port writes
fill, and the first word written to the IBI port is parsed as the IBI
descriptor. The driver had both orders inverted (data first), which
panicked the emulator's I3C model on the first tx_write and would have
corrupted any IBI with a payload. Matches the upstream caliptra-mcu-sw
runtime driver (runtime/kernel/drivers/i3c/src/core.rs).

Found by the new i3c_echo test; the smoke test never transmits, so it
could not catch this.
Firmware raises an IBI (MDB 0xA5 with a 4-byte payload) on each received
private write; the host asserts the MDB arrives over the I3C socket.
Gives the descriptor-first ibi_raise() ordering fix behavioral coverage.
Only the MDB is asserted: the emulator's IBI model does not yet forward
the payload to the controller side (upstream TODO in check_ibi_buffer).
Unlike the polling smoke test, the firmware discovers the frame solely
via the TTI RX-descriptor interrupt: IRQ 2 on the VeeR PIC, wired
through the pw_kernel interrupt table to a handler that masks the
level-triggered enable and flags the main thread.

Getting this to work surfaced a real platform gap: the emulated VeeR
core delivers external interrupts by jumping through the MEIVT redirect
table (which must live in DCCM), but pw_kernel never programs MEIVT.
The first external interrupt therefore escalated to a "table not in
DCCM" NMI with an unprogrammed vector, sending the CPU to address 0 --
the terminal mcause=1/epc=0 exception originally seen when the smoke
test enabled the RX interrupt. The firmware works around it by filling
a redirect table in DCCM with the mtvec trap vector before enabling the
interrupt; the proper fix belongs in pigweed's veer_pic early_init.
Move the external-interrupt redirect table setup from the i3c_irq test
firmware into the kernel where it belongs: veer_pic early_init now fills
a target-provided MEIVT table (every entry pointing at the mtvec trap
vector, so redirected interrupts take the standard trap path and the
claim id is read from MEIHAP) and writes the MEIVT CSR. The table
location comes from a new optional MEIVT_BASE_ADDRESS on
VeerPicConfigInterface, defaulting to None so other pigweed users are
unaffected; target/veer places it at DCCM base 0x50000000 as the VeeR
core requires.

All veer system images now get working external interrupts, not just
the one test that carried the workaround. Candidate for upstreaming to
pigweed.

Note: syscall_latency still fails with a similar epc=0 signature, but
after its measurement completes, in the userspace process exit path --
a separate pw_kernel bug, unrelated to MEIVT.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant