culvert
Typed access to the HDMI 2.1 SCDC register map.
culvert sits on top of [hdmi_hal::scdc::ScdcTransport] and gives raw SCDC register
bytes meaning: named structs, typed enums, and one method per register group for
scrambling control, FRL training primitives, version negotiation, update flags, and
Character Error Detection. It is the SCDC layer that [plumbob]'s link training state
machine drives, and is equally usable without it.
Sequencing of register operations — rate selection, timeout handling, retry logic — is out of scope. Culvert provides the typed primitives; the caller decides when to call them.
Usage
[]
= "0.2"
Wrap your transport in Scdc and call typed methods:
use ;
let mut scdc = new;
// Version negotiation
let sink_ver = scdc.read_sink_version?;
scdc.write_source_version?;
// Enable TMDS scrambling
scdc.write_tmds_config?;
// Wait for the sink to be ready, then request an FRL rate
let flags = scdc.read_status_flags?;
if flags.flt_ready
// On FLT_Update, read the pattern each lane requests, then acknowledge the flag
let updates = scdc.read_update_flags?;
if updates.flt_update
// Read per-lane character error counts
let ced = scdc.read_ced?;
if let Some = ced.lane0
To use culvert as the SCDC backend for plumbob's link training state machine, enable
the plumbob feature:
[]
= { = "0.1", = ["plumbob"] }
= "0.1"
Scdc<T> then implements plumbob::ScdcClient, one culvert method per training
operation. Scdc does not wait between calls: plumbob polls FLT_ready and Update_0
in loops whose limits assume one poll every 2 ms, so enforce that interval in the
transport (or a wrapper around it).
Register coverage
| Register group | Addresses | Methods |
|---|---|---|
| Version | 0x01–0x02 | read_sink_version, write_source_version |
| Update flags | 0x10 | read_update_flags, clear_update_flags |
| TMDS / scrambling | 0x20–0x21 | write_tmds_config, read_scrambler_status |
| FRL config | 0x30–0x31 | write_config_0, write_frl_config |
| Source test configuration | 0x35 | read_source_test_config |
| Status flags | 0x40 | read_status_flags |
| LTP requests | 0x41–0x42 | read_ltp_requests |
| Character Error Detection | 0x50–0x55, 0x57–0x58 | read_ced |
| RS correction count | 0x59–0x5A | read_rs_correction |
The register map and its sources are described in
doc/architecture.md. Registers not yet
covered (the CED checksum, manufacturer identification) are
documented in doc/roadmap.md.
Features
| Feature | Default | Description |
|---|---|---|
plumbob |
no | Implements plumbob::ScdcClient for Scdc<T> |
no_std
culvert is #![no_std] throughout. All output types are stack-allocated; no allocator
is required in any configuration.
Stack position
flowchart LR
dt["display-types"]
hal["hdmi-hal"]
culvert["culvert"]
plumbob["plumbob"]
integration["integration layer (planned)"]
dt --> culvert
hal --> culvert
culvert -->|"implements ScdcClient"| plumbob
plumbob -.->|"will implement LinkTrainer"| integration
culvert does not depend on plumbob. The relationship runs the other way: enabling the
plumbob feature makes Scdc<T> implement plumbob::ScdcClient, and any crate that
implements ScdcClient is substitutable.
Out of scope
- Async API — the async client is the separate
culvert-asynccrate. Both clients use the I/O-freeculvert::codecmodule (register addresses and per-register encoding and decoding), so the register map exists once. - Link training state machine — the sequencing of FRL training (rate selection, polling, fallback to TMDS) belongs in the link training crate. Culvert provides the register operations; the state machine decides when to call them.
- PHY configuration —
HdmiPhyoperations are the link training layer's concern. - I²C / DDC transport — platform backends implement
ScdcTransportfromhdmi-hal. Culvert never touches I²C directly.
Documentation
doc/setup.md— build, test, and coverage commandsdoc/testing.md— testing strategy, transport harness, and CI expectationsdoc/architecture.md— role, scope, register map, type reference, design principles, and the culvert / link training boundarydoc/roadmap.md— SCDC registers deferred to future releases
Verifying releases
Releases are built on GitHub Actions and attested with
SLSA Build Level 2 provenance (from 0.2.0). To verify a release
.crate against its signed provenance, install the
GitHub CLI and run:
The attested .crate is attached to each
GitHub release.
Releases from 0.2.0 are uploaded through crates.io trusted publishing: the publish workflow obtains a short-lived token via OpenID Connect instead of using a stored API token. crates.io can also reject uploads made with an API token for this crate; the badge above shows whether that setting is on. Each version's publishing details, including the workflow run and commit, are available from the crates.io API:
# see .version.trustpub_data
Versions up to 0.1.2 were uploaded with an API token (0.1.0 by hand, 0.1.1 and 0.1.2 from CI). They carry no provenance and have no GitHub release.
License
Licensed under the Mozilla Public License 2.0.