# beyond_synaptics repo — findings

Source: `C:\Users\decid\Documents\projects\beyond_synaptics` (read-only survey, 2026-06-09).
Branch: `main` @ 78c279d ("Wiki"). Current firmware version 0.3.19 (`src/sw_ver.h`).
Remote branches: `add-eeprom-crc`, `build-cmake` (adds CMake/VSCode build), `fan-sticktion`,
`nofio_72hz` (important, see below), `prox-trim-no-vxr-shutdown`, `tracking-flex-test-station`
(mic-only test build), `usb-boost-settings`, `user-prox-trim`. The older copy at
`projects\bigscreen\beyond_synaptics` is at the identical commit — no diff needed.
Paths below are repo-relative.

## 1. What this repo IS

Firmware for the Beyond **main display board MCU** — an **ATSAMG55G19** (Cortex-M4 @120MHz,
512KB flash, 128KB RAM), C + FreeRTOS 10 + Atmel ASF, built with Microchip Studio 7.0.2542
(`Beyond_Synaptics.atsln`, `README.md`, `wiki/Home.md`). It is **not** VXR7200 firmware source.
The Synaptics VXR7200 firmware ships only as opaque prebuilt 512KB images in
`vxr7200_firmware/*.fullrom`, produced by a Synaptics firmware-generation tool (per comment in
`src/Devices/vxr_interface.c` ~line 438). Also included:

- `scripts/` — Python host tooling (HID lib, config editor, VXR/MCU flashers, monitors,
  factory test GUIs); `scripts/direct_mode_dx12.exe` (NVIDIA direct-mode test app) and
  `scripts/set_extended_dsc_8bpp.py` (drives NVIDIA `NvDpTestUtil.exe` to force DSC 8bpp —
  evidence they tested extended-desktop DSC).
- `docs/` — `HID_Commands.md` (full 64-byte HID protocol), `Config_Format.md` (TLV config in
  MCU user-signature flash), `Bootloader_Info.md` (MCU bootloader protocol).
- `wiki/` — excellent per-subsystem docs incl. `VXR7200-Display-SoC.md`, `Display-System.md`.
- `build/` — released MCU .hex images v0.2.x–v0.3.x; `testgui/`, `crash_debug/`.

## 2. Display chain / VXR7200 role

```
PC (DP 1.4 source, GPU)
  └─ Linkbox ── captive USB-C cable ──> headset
       cable carries: 4x DP main lanes (HBR/HBR2/HBR3) + DP AUX + USB2.0 D+/D- + VBUS + CC
  └─ PI3USB31532 USB-C crossbar mux (in headset, DDIC_I2C addr 0xA8) — orientation flip only,
       always configured "DP 4-lane" mode (src/Devices/usbc_mux.h)
  └─ Synaptics VXR7200 (DP1.4-to-dual-MIPI VR bridge, DDIC_I2C addr 0x72)
       - autonomous: boots from its own SPI flash, does DP link training, serves EDID,
         generates HPD, splits the double-wide SST stream, drives 2x MIPI-DSI TX
       - DSC is NOT decoded here: it is passed through to the panels
  └─ 2x SeeYA SY103WAM01 1.03" microOLED panels (DDIC embedded in panel)
       - left panel on DDIC_I2C bus, right on MCU_I2C bus, both at I2C addr 0x98
       - each uses 2 MIPI ports, decodes DSC itself (PPS written to reg 0x70),
         has an internal 1.33:1 upscaler (1920->2560-class) and X/Y window offsets
```
(`src/ASF/sam/boards/displayboard/displayboard.h` lines 136–153 list every I2C device;
"DDIC" bus name is legacy — the bridge is the VXR7200, the real DDICs are in the panels.)

- Host sees **one display** (SST, double-wide side-by-side), not MST. VXR7200 splits it:
  TX0 = left eye, TX1 = right eye. MST per-eye EDID RAM exists (0x3200/0x3380,
  `src/Devices/vxr_interface.h`) and the flash config contains per-TX "SYNA" EDIDs
  (fullrom offsets 0x200/0x380), so MST appears silicon-supported but unused. (speculation
  on usability; registers/config slots verified.)
- Link rate/lanes read back from VXR reg 0x1880; per-lane PHY error counters 0x22011C–28;
  MSA H/V active/total + bpc + pixel-clock-derived frame rate read from RX registers
  (`vxr_interface.h` 114–162; frame-rate formula in `wiki/VXR7200-Display-SoC.md`).
- DSC detection: MCU reads the PPS the VXR captured (TX0 @0x0780+5, 88 bytes); if header
  `11 00 00 89` it forwards the PPS to both panels and sets dsc_enabled
  (`src/video_proc.c` ~600–620).
- DSC can be disabled at runtime by clearing DPCD DSC+FEC capability bits in VXR reg 0x1730
  (`VXR_Disable_DSC`, `vxr_interface.c` 379–390) — i.e. **the DPCD the GPU sees is editable
  from the MCU**.
- `VXR_Reset_Rx` (reg 0x07001810) reinits TX/MIPI without dropping the DP link.

## 3. Video modes / EDID (who serves what)

Persistent EDID lives in the **VXR7200 SPI-flash config bank** (fullrom offset 0x0000 = main,
0x200/0x380 = MST TX0/TX1). The stock flash EDID is mfr "BIG", product **0x5095**, DisplayID
**1.2** ext with 5088x2544@75 + 3840x1920@90 — the Synaptics config tool refuses DisplayID 2.0
in storage. So at every boot the **MCU overwrites the VXR EDID RAM** (reg 0x3000, 256 bytes)
over I2C with a DisplayID-2.0 EDID from `src/edid.h` (`load_edid()` in `src/video_proc.c`).
The runtime default `edid_with_color` is mfr "BIG" (bytes 09 27), product **0x1234**, with
DID2.0 header `70 20 79 07` — use-case byte 0x07 = VR HMD — plus a VESA vendor block
`7E 00 07 3A 02 92 81 00 08` advertising **DSC pass-through 8bpp**.

EDID variants in `src/edid.h` (selectable via HID `d`, config tag 0x0D, or FATP HID `@`):

| EDID | Host modes (double-wide) | Per-eye | DSC | Notes |
|---|---|---|---|---|
| `edid_with_color` (default) | 5088x2544@75 (preferred), 3840x1920@90 | 2544²/1920² | 75Hz yes, 90Hz no | product 0x1234, HMD flag |
| `full_edid_with_75_72_and_90` | + 5088x2544@72 | | | 72Hz disabled — VXR7200 bug (CHANGELOG v0.2.14) |
| `edid_with_90hz_only` / `_75hz_only` / `_72hz_only` | single mode | | | |
| `edid_for_optical_fatp` (FATP 0) | 3840x1920@60 + 5120x2560@30 | | no (DSC force-disabled via 0x1730) | product **0x5095**, DID1.2, **enumerates as a normal desktop monitor** |
| `edid_for_fatp_mode1` (FATP 1) | 3840x1920@60 only | | no | same, desktop monitor |
| `edid_for_fatp_mode2` (FATP 2) | 5088x2544@60 only | 2544² | yes | keeps product 0x1234 "which tells Nvidia and AMD drivers to still apply all of the DSC encoder fixes we require" |

Mode acceptance is enforced by `check_format()` in `src/video_proc.c` (exact Hactive/Vactive +
frame-rate windows); unknown timings = panels never initialized. Pixel clocks (comments in
edid.h): 5088x2544@75 ≈ 1004.6MHz, 3840x1920@90 ≈ 718.1MHz. 2544@60 requires VXR firmware
v03 (`vxr7200_firmware/Beyond_v03_20231221.fullrom`). 75Hz was made preferred (v0.2.13)
because AMD GPUs fail to bind SteamVR if Watchman JSON and Windows mode mismatch; changelog
also notes "After entering direct mode, Windows OS cannot control resolution."

**Direct mode vs desktop:** with product 0x1234 + HMD use-case the GPU drivers hide it as an
HMD; with FATP EDIDs (0x5095, DID1.2, no HMD flag) it "will simply appear as a desktop
monitor" (`scripts/display_test_60Hz.py` ~line 182). NVIDIA/AMD HMD classification is
EDID-vendor/product keyed (whitelist — speculation, but strongly implied by the comments).

## 4. VXR7200 control, flashing, recovery

MCU controls the VXR via an I2C "Remote Control" debug-register protocol (addr 0x72,
trigger 0x002000FC, command/offset/length/data regs 0x00200110–0x0020013C; enable key
"VXR00"): commands for memory R/W, SPI-flash erase/program/read, checksum, and **MIPI DSI
read/write passthrough to either panel** (offset 0x100=left, 0x400=right)
(`src/Devices/vxr_interface.c/h`, `wiki/VXR7200-Display-SoC.md`).

VXR SPI flash (512KB, inside/attached to VXR): dual banks — Config0 0x00000(32KB) /
FW0 0x08000(96KB) / Config1 0x20000 / FW1 0x28000, upper 256KB = "ESM" region for HDCP 2.2.
Each region ends in a 16-byte validity tag read by the **VXR ROM bootloader**; zeroing
first+last tag bytes forces fallback to the other bank — that is the recovery story, plus
the MCU can always reflash via RC (RC interface appears ROM-resident — speculation).
Config and firmware are independently bank-selectable. Flash data reads use a hack:
checksum-of-1-byte (`VXR_Tag_Valid`, `VXR_Get_Firmware_Name` reads name at cfg+0x5F0).

Update path: host → USB HID (`D` erase w/ "VXRDELETE" phrase, `A` program 32B chunks,
`K` checksum, `Y` reset; `T` tags, `N` fw name). 4KB-sector erase added (v0.2.11) so the
**config can be updated without touching firmware**. Nine fullroms are in
`vxr7200_firmware/`; one (`BigScreenVR_v02_0906_HBR2.FullRom`) suggests an HBR2-limited
build; `FATPMODE_v02_1202_nativ.fullrom` a factory variant; `nofio_bigscreen_230727.fullrom`
(on branch `nofio_72hz`) a custom-mode variant.

`vxr7200_firmware/mipi_cmds_220815.txt` is in the Synaptics config-tool input format: mode
sections keyed by **total** timings (`[ 2672x2568@73-76_24_2 ]`, `[ 2176x1948@88-91_24_2 ]`,
`[ 2048x1944@70-73_24_2 ]` — per-eye Htotal x Vtotal @ refresh-range, 24bpp, 2 ports) each
containing the full panel DDIC MIPI init script (DSC on, PPS, timing, brightness, sleep-out,
display-on, delays). So the **VXR config flash contains a fixed mode table + per-mode panel
init scripts the VXR can replay itself** — confirmed by `src/video_proc.c` ~574: "the VXR7200
will just send out the sleep-out and display-on commands at some point after MIPI TX have
entered video mode". New input timings ⇒ new VXR config blob from the Synaptics tool.

## 5. Boot / display init sequence (who does what)

1. MCU boots (16KB bootloader → app @0x404000, CRC-checked; `wiki/Bootloader.md`); FreeRTOS
   starts ~12 tasks (`src/main.c`).
2. `task_timed_startup` (`src/test_and_debug.c` ~486): EEPROM/config init → linkbox HPD
   polarity from config tag 0x05 → HPD forced inactive → USB hub init (board-version detect:
   BS1=2x USB3803, BS2=3x USB3803, BS2-EVT=USB2517) → USB-C orientation from CC1/CC2 ADC →
   program PI3USB31532 mux → **1.0V rail on + VXR reset released** (3.3V before 1.0V, reset
   ≥10ms after 1.0V, I2C ≥250ms after reset — Synaptics training slides quoted in
   `src/Drivers/power_control.c`) → panel rails (VDDI 1.8V, +1ms AVDD +6.3V, +2ms AVEE -4.5V,
   +1ms reset release; SY103 sequence) → notify video task.
3. `task_video_proc` (`src/video_proc.c`): wait 275ms → `VXR_Start_Interface` → read VXR fw
   name → **overwrite EDID RAM with DID2.0 EDID** → release panel reset (PIN_OLED_RESX) →
   copy current VXR HPD level (PIN_DDIC_HPD input) to the linkbox (PIN_USBCC_EN) and enable
   the HPD-forwarding IRQ. From here the GPU enumerates the display and trains the link with
   zero MCU involvement.
4. VXR raises GPIO7/GPIO4 (= left/right TX panel-reset status, IRQ-monitored in `src/main.c`)
   when video starts; MCU polls TX0/TX1 video-enable regs (0x310040/0x350040). When both
   active: read MSA format → match `check_format()` → fan+LED on → **panel init over I2C**
   (`OLED_Startup` per-mode script from `src/Devices/oled_control.c`: DSC on/off, gamma,
   scaling, 2-MIPI-port, PPS, resolution/timing regs 0x80/0x81/0x82, temp-comp, OSC tracking,
   SeeYA TC trigger table, vert-bars fix) → forward captured PPS if DSC → sleep-out →
   brightness 0 → display-on → post-init dimming (0xC0 0xFF after 20ms) → restore brightness.
5. Video loss (VXR drops GPIO4/7) ⇒ panels reset, fan/LED off, optional VXR power-down timer.

Panel-side notes: brightness = 10-bit 0–1023 via panel reg 0xC2 (PWM/emission duty; default
266 ≈26%), with readback-verify retry; **pulse-emission mode** (0xC2 byte9 0x82 vs 0x02) used
at 30/60Hz to avoid visible strobing — i.e. **low-persistence emission control is in the
panel, set over I2C**, brightness path is MCU→panel I2C, never through the DP/video stream.
Panels report temperature (reg 0xBF) and a 14-byte ID (reg 0x84). Vertical flip via DCS 0x36.

## 6. Linkbox / USB-C facts (all that exists in this repo)

- No PD controller anywhere on the headset. CC1/CC2 go to MCU ADC channels for orientation
  sensing only (`src/Drivers/adc.c` `get_flip_status`, incl. "JcnBoxWrongWay" = junction-box
  cable end inserted backwards).
- **Proprietary HPD-over-CC signaling**: asserting PIN_USBCC_EN switches an extra 1.24k CC
  pulldown in parallel with the standard 5.1k → ~1.0k effective, which tells the linkbox to
  drive DisplayPort HPD high toward the PC; Linkbox V1 used inverted logic (config tag 0x05)
  (`displayboard.h` 30–37, `src/Devices/linkbox_hpd.c`, `testgui/testgui.py` 83–84).
- So the headset⇄linkbox link is a *dedicated* pinout reusing a USB-C connector — it is NOT
  USB-C DP alt mode and performs no PD negotiation. A standard USB-C DP-alt-mode host port
  will not light it up as-is (no PD sink/alt-mode engine in the headset). (Inference from
  absence of any PD hardware/code; marked as near-certain.)
- USB side is USB 2.0 only (USB3803 hi-speed hubs); composite MCU device VID 0x35BD PID
  0x0101 (HID cmd channel + UAC mic + CDC debug; PC→HMD uses HID *feature* reports).
  Upstream hub PHY boost/squelch tunable via config (v0.3.15+).
- Linkbox internals are otherwise out of scope of this repo. Nothing about HDMI anywhere;
  VXR7200 input is DP 1.4 only.

## 7. BS1 vs BS2 (Beyond 1 vs Beyond 2 boards)

Unified binary, runtime detection by hub topology (`src/test_and_debug.c` 532–545).
- BS1: 2x USB3803; 1.8V rail switchable (panel hot-swap HID cmds `-`/`+`).
- BS2: 3x USB3803, 1.8V always on, **eye-tracking FPGA** (Gowin GW5A-LV25 @ I2C 0x78 — IR LED
  PWM/current monitor/overcurrent latch, camera-sensor register bridge; `wiki/Eye-Tracking.md`),
  **VXR7200 1.0V power gating** + optional auto-sleep (config 0x0F): VXR off after 30s of no
  video; **wake on Tundra tracker UART activity** (PA5 pin-change IRQ → `VXR_Power_On`).
- Same VXR7200 and same SeeYA SY103WAM01 panels on both. Tracking is a Tundra TL448K6D-VR
  SteamVR module; MCU only snoops its debug UART at 460800 and forwards to HID
  (`src/Devices/tundra_uart.c`).

## 8. Host-relevant HID command surface (v0.3.19, `src/usbhid_interface.h`)

Brightness `I`, EDID switch `d`, FATP `@`, OLED raw register write `o`, OLED flip `P`,
prox disable/enable `p`/`[`, prox trim `t`, VXR delete/program/checksum/reset/name/tags
`D A K Y N T`, VXR connection check `X`, VXR 1.0V rail `1`, colorbar `=`, fan `F/f`,
LED `L`, config read/write/save `U W V`, bootloader `B`, reset `C`, usage timers `Z/z`,
FPGA `e`, HW self-tests `J`. Periodic 24-byte telemetry includes CC ADC values, panel temps,
brightness, video mode, DP link rate/lanes, DSC flag, VXR power state (byte 26).

## 9. nofio_72hz branch (proof of custom-mode workflow)

Adds a 3648x1824@72Hz **non-DSC** double-wide mode (per-eye 1800x1800-class, panel upscale
1.33:1 to 2400x2400 with X/Y window offsets 0x2A/0x2B for centering black borders) for the
Nofio wireless adapter, based on v0.2.13. Required all four layers: new EDID timing in
`video_proc.c`, new `check_format()` entry, new `oled_startup_1800_72Hz[]` panel script, and
a **custom VXR fullrom** (`nofio_bigscreen_230727.fullrom`). This is the template for any new
video mode.

## 10. Constraints for "extended desktop display" use

- **Already possible in principle**: FATP modes 0/1 make the Beyond enumerate as a plain
  desktop monitor today (3840x1920@60 non-DSC; survives until power cycle / `@ 0xFF`).
  Limitations: 60Hz, 1920² per eye upscaled, double-wide desktop spanned across both eyes.
- Full-res desktop (5088x2544) needs DSC; desktop DSC was tested via NVIDIA NvDpTestUtil
  (`scripts/set_extended_dsc_8bpp.py`). DSC behavior on desktop is GPU-driver-quirk
  territory keyed to EDID product 0x1234.
- Blockers for "normal monitor" UX are all **EDID-policy, not hardware**: HMD use-case flag +
  product ID cause GPU direct-mode capture; the MCU can change both at runtime.
- The image is stereo side-by-side; a plain desktop will straddle the eyes. Options: host
  software renders per-eye, or (speculation) a VXR config that feeds the same half to both
  TX ports / a single-eye mode — unknown whether the Synaptics tool supports TX mirroring.
- Display-on is gated by the proximity sensor (disable via HID `p` or config 0x04) and
  brightness defaults to 26% (config 0x0A) — both trivially configurable.
- Non-SteamVR use has no firmware blocker: SteamVR is only relevant via the Tundra module
  and the watchman JSON; the display pipeline never touches it.

## Relevance to sauna

**What the VXR7200 (config/firmware) change could enable**
- The VXR is the EDID server, link trainer, HPD generator and mode table. A modified *config
  bank* (32KB, field-updatable in 4KB sectors over existing HID path, dual-bank safe
  fallback) could: ship a desktop-monitor EDID by default (no MCU runtime patch needed),
  add/remove modes, add per-mode panel init scripts so panels light without MCU help, and
  possibly mirror one eye to both panels for monitor mode (unverified). The config tool
  format is partially understood (`mipi_cmds_220815.txt`, EDIDs at fixed offsets, name at
  +0x5F0); reverse-engineering a .fullrom config diff pair (v02 vs v03, HBR2 variant) is the
  obvious next step — we have 9 samples.
- VXR *firmware* (96KB code for an unknown core; strings show "$SYNA", "/dev/hl_dev") is a
  much heavier lift; likely unnecessary — everything sauna needs looks config/MCU-side.
  Known VXR firmware bug: 72Hz DSC timing broken (v0.2.14 note) — fixed only by Synaptics.

**Linkbox-less operation**
- Headset-side hardware is fixed: no PD engine, DP must simply *be present* on the USB-C
  pins, plus 5V VBUS, plus something host-side must sense the CC-resistance HPD signal
  (5.1k→1.0k). So linkbox-less ≠ firmware problem — it needs a small host-side adapter
  ("mini linkbox": DP source pins straight through, CC sense comparator → HPD, 5V supply).
  The protocol on the cable is now fully documented above; no auth, no handshake beyond CC
  resistance and ordinary DP link training. MCU firmware could optionally hold HPD always
  asserted to simplify a dumb adapter (one-line change in `linkbox_hpd.c` policy).
- Direct USB-C alt-mode from a laptop port would additionally require a PD sink + alt-mode
  negotiation in that adapter (the headset cannot do it).

**Monitor-mode (no SteamVR) with zero hardware changes — cheapest path**
1. MCU firmware (this repo, full source + toolchain + flashing path): add a "desktop EDID"
   profile (non-HMD product ID, optional 1920²@90 non-DSC for max compatibility, or DSC
   2544²) selectable via HID/config — FATP mode 1 already proves the concept end-to-end.
2. Keep brightness/prox/fan control over the existing HID protocol (fully documented).
3. For per-eye correctness on desktop: render side-by-side from the host (sauna compositor),
   or investigate VXR config TX-mirroring.

**Fixed in hardware (cannot change)**: DP-1.4-only input (no HDMI — converters won't carry
DSC, capping non-DSC at 1920²@90); DSC decode lives in the SeeYA panels; panel mode windows
(2544²@60/72/75 DSC, 1920²@60/90, 2560²@30 class, plus whatever new VXR-config+panel-script
combos allow within MIPI/panel limits); USB 2.0 only; CC-resistance HPD scheme; per-eye
brightness/persistence only via I2C from the MCU.
