The Original Goal
The plan was straightforward: enable USB host mode on the PSP so it could supply 5V VBUS power and communicate with microcontrollers like the Luckfox Pico. Sony's first-party accessories (Go!Cam, GPS, TV tuner) proved the hardware could do it. We just needed to find the right register writes.
What followed was three weeks of increasingly deep reverse engineering across two PSP models (PSP-1001 and PSP-3001), dozens of firmware experiments, and the decryption of Sony's USB firmware blob — ultimately leading to a fundamental discovery about how PSP accessories actually work.
The Discovery: PSP Accessories Are the Host
After exhaustively testing every accessible register, Syscon command, and GPIO pin, we discovered that the PSP never acts as a USB host. Sony's accessories contain their own USB host controller chips. The PSP is always the device. The accessories power themselves from dedicated side contact pins on the PSP's USB port, not from VBUS.
How PSP Accessories Actually Work
What we assumed:
PSP (host) ──VBUS 5V──> Accessory (device)
PSP enumerates and controls the peripheral
What actually happens:
PSP (device) <──data──> Accessory (host)
Accessory has its own host chip + power
PSP presents itself as a custom USB device
Accessory controls the conversation
The Reverse Engineering Journey
Phase 0–1: VBUS Experiments
Built kernel-mode Rust EBOOTs to probe the PSP's USB hardware. Tested GPIO pins, Syscon SPI commands (0x00–0x50), SYSCTL registers, and USB PHY configuration. No VBUS appeared on either PSP model despite setting every accessible bit.
Phase 2: Firmware Decryption
Extracted and decrypted the USB firmware blob embedded within usb_cam.prx:
- Located encrypted
~PSPheader at offset 0x7D580 in kernel memory dump - Decrypted with
pspdecrypt(tag0x4C9494F0) - Decompressed KL3E format → 77,320 bytes of raw MIPS code
- Loaded into Ghidra at base 0x88600000, decompiled 40+ functions
Phase 3: Register Map Discovery
The firmware analysis revealed three previously undocumented register blocks:
| Address Block | Purpose | Key Finding |
|---|---|---|
0xBE4C0000 |
USB PHY serial controller | Clock, mode, features — configures the physical layer |
0xBD101000 |
OHCI host controller | Gated by BC100050 bit 13 — fully functional OHCI 1.0 rev 3 |
0xBDE00000 |
Raw SPI/DMA controller | Dead code in firmware — never called |
We also mapped the complete Syscon command set for Baryon 0x00040600 (256 GET commands,
14 SET commands identified from kernel disassembly) and found the _sceSysconCommonWrite
function with its GET/SET pairing (e.g., GET=0x46, SET=0x47 for USB power).
The Pivot: Custom USB Device Driver
With USB host mode ruled out, we pivoted to the correct architecture: the PSP as a USB device with custom bulk endpoints. If we want the PSP to talk to a Luckfox Pico, the Pico should be the USB host and the PSP should present a custom device interface.
PSP Thin Client Architecture
┌─────────────────┐ USB 2.0 ┌──────────────────┐
│ Luckfox Pico │◄───────────►│ PSP │
│ (USB Host) │ 480Mbps │ (USB Device) │
│ │ bulk xfer │ │
│ ARM Cortex-A7 │ │ Custom driver: │
│ Linux + libusb │ │ sceUsbbdRegister│
│ AI / compute │ │ EP1 IN (0x81) │
│ networking │ │ EP2 OUT (0x02) │
│ $9, 51x21mm │ │ │
└─────────────────┘ └──────────────────┘
sceUsbbd: The Undocumented Kernel API
The PSP's sceUsbBus_driver exports functions for registering custom USB
device drivers — the same API that Sony's mass storage and camera drivers use
internally. These functions are kernel-only and not documented in any public SDK:
| Function | NID (6.61) | Purpose |
|---|---|---|
sceUsbbdRegister |
0xB1644BE7 |
Register a custom USB device driver |
sceUsbbdReqSend |
0x913EC15D |
Queue async bulk IN transfer (device→host) |
sceUsbbdReqRecv |
0x7B87815D |
Queue async bulk OUT transfer (host→device) |
The NIDs were resolved from the PSP-3001's kernel memory dump — the standard PSPSDK NIDs are wrong for 6.61 firmware. The functions require direct address calls rather than NID-resolved stubs on ARK-4 CFW.
It Works
The custom USB device driver successfully registers with the PSP's USB bus driver and presents itself to any connected USB host:
$ lsusb
Bus 003 Device 073: ID 054c:1337 Sony Corp.
$ lsusb -v -d 054c:1337
idVendor 0x054c Sony Corp.
idProduct 0x1337
Interface Descriptor:
bInterfaceClass 255 Vendor Specific Class
bNumEndpoints 2
Endpoint Descriptor:
bEndpointAddress 0x81 EP 1 IN (Bulk, 512 bytes)
Endpoint Descriptor:
bEndpointAddress 0x02 EP 2 OUT (Bulk, 512 bytes)
Two high-speed bulk endpoints at 512 bytes per packet — enough for ~30 MB/s sustained throughput. A full 480×272 RGBA framebuffer (522 KB) can be transferred in under 20ms, enabling 30+ FPS thin client rendering.
Phase 2: VBUS Power Output Research (Ongoing)
While the thin client architecture works over USB device mode, the original goal of powering a Luckfox Pico from the PSP's USB port remains compelling. We returned to the VBUS problem with new tools.
On-Device PRX Decryption
Built a kernel-mode EBOOT (oasis-prx-decrypt-psp) that uses the PSP's own
Kirk hardware crypto engine (memlmd NID 0xEF73E85B) to decrypt firmware
modules. Successfully decrypted all 15 USB/system PRX files from
flash0:/kd/ — something desktop tools couldn't do with 6.61 keys.
NID Analysis: The MUSB Discovery
A standalone binary analyzer (scripts/psp_nid_analyze.py) scanned the
decrypted usb.prx and revealed a critical finding: the USB driver
has 143 references to the MUSB (Mentor USB OTG) controller at
0xBD80xxxx and zero to the OHCI controller we'd been testing.
We'd been probing the wrong USB controller.
| PRX File | Key Finding |
|---|---|
usb.prx |
143 MUSB accesses, GPIO pin 23 VBUS enable at offset 0x8C74, 14 sceSysreg imports |
lowio.prx |
50 GPIO accesses, 90 sceSysreg — the actual GPIO hardware driver |
syscon.prx |
Also controls GPIO pin 23 directly, accesses BC100083 |
Interactive VBUS Test Tool
The 19-step interactive EBOOT (oasis-usb-vbus-psp) tested every accessible
approach to enabling VBUS on the PSP-3001 (TA-090v2):
- All 14
sceSysreg_driverNIDs resolved and called (14/14) - Syscon SET commands (0x47 values 0–4) accepted but no VBUS effect
- GPIO pin 23 direction and set registers accept writes, but output doesn't latch
- USB PHY already configured for host mode (
0x301) - MUSB controller at
0xBD80xxxxbus-faults — its bus gate is unknown 0xBE500000peripheral alive (offsets +0x18=0x99, +0x2C=0x71) — purpose unknown
The Verdict: Silicon-Level Lock
Ghidra decompilation of lowio.prx (run via an amd64 Docker container on
our ARM64 host) revealed the GPIO output enable register at 0xBE240024
— written by sceGpioSetPortMode2 with 1 << pin.
On-device testing confirmed this register rejects all writes on TA-090v2,
along with AltFunc (0xBE240040) and BC1000C4.
An exhaustive search followed: all 14 sceSysreg NIDs, every Syscon command 0x00–0xFF,
the sysreg GPIO port enable (BC10007C), USB bus gates, scePower functions,
OTG ID pin grounding with two different adapters, and live register monitoring during
cable plug/unplug. Nothing unlocks the GPIO output enable.
The lock is set by the Tachyon SoC's mask ROM during the earliest boot phase, before any firmware code executes. It cannot be overridden from kernel mode. Sony's Go!Cam accessory likely triggers VBUS through a hardware detection circuit in the Syscon or Pommel chip that monitors USB connector pin voltages — not through any software command or the standard OTG ID pin.
What's Next
- Thin client streaming: The USB device driver achieves 105 FPS / 28 MB/s framebuffer streaming — integrate with the Luckfox Pico for external AI compute
- Go!Cam PSP-300: Acquiring the camera accessory would reveal whether VBUS is triggered by hardware detection (likely) or a privileged command path
- Hardware mod: Bypass the MOSFET gate by soldering a wire from the PSP's 5V rail to the USB VBUS pin — the simplest path to single-cable operation
- Convert to PRX: Move from game-slot EBOOT to kernel PRX loaded via
PLUGINS.TXTfor always-on USB device mode