"""What can we still reach on the card in its current state? Tested, not assumed. READ-ONLY except the TSU mailbox liveness command (a documented read-only query) and a scratch write-readback on an already-open mailbox. Deliberately does NOT read BAR0 at high offsets: that triggers a TLP error which wedges PCIe access until a power cycle. """ import struct, sys, time sys.path.insert(0, "/Users/user/dev/amd-psp-re/psp_out") from regguard import byteswap from tinygrad.runtime.support.usb import USB3 from tinygrad.runtime.support.system import USBPCIDevice OK, NO, PART = "YES", "no", "partial" rows = [] def row(cap, verdict, detail): rows.append((cap, verdict, detail)) # --- bridge ----------------------------------------------------------------- devs = [] for vid, pid in ((0x3801, 0x0001), (0xADD1, 0x0001)): devs += list(USB3.list_devices(vid, pid)) if not devs: sys.exit("no bridge") gpu = USBPCIDevice("AM", *devs[0]) ctrl = gpu.usb; usb = ctrl.usb row("USB bridge vendor cmds", OK, "product=%s" % usb.product) lt = usb.control_read(0xE4, 1, value=0xB450)[0] row("PCIe link", OK if lt == 0x78 else NO, "LTSSM=%#04x" % lt) # --- BAR5 MMIO -------------------------------------------------------------- b5 = gpu.map_bar(5, fmt='B') rd = lambda o: struct.unpack(' MP0 block", OK if mp0 == rd(0x582CC) else NO, "0x03810ACC=%#010x (matches BAR5)" % mp0) for name, addr in (("DF scratch", 0x12400F80), ("Route-C window", 0x21500), ("perm array", 0x0381069C), ("SPI flash regs", 0x0005A384)): v = smn(addr) row("SMN -> %s" % name, NO if v == byteswap(addr) else OK, "%#010x -> %#010x %s" % (addr, v, "(MIRROR = not decoded)" if v == byteswap(addr) else "")) # --- BAR0 low --------------------------------------------------------------- try: b0 = gpu.map_bar(0) row("BAR0 low aperture", PART, "reads %s (high offsets FAULT - avoid)" % bytes(b0[0:8]).hex()) except Exception as e: row("BAR0", NO, str(e)[:40]) # --- PSP TSU mailbox -------------------------------------------------------- C2P = lambda n: 0x58224 + 4*(n-73) def tsu(cmd, arg=0, to=2.0): wr(C2P(116), arg); wr(C2P(115), (cmd & 0xFF) << 16); wr(C2P(73), 1) t0 = time.time() while time.time() - t0 < to: v = rd(C2P(115)) if v & 0x80000000: return v & 0xFFFF, rd(C2P(116)) time.sleep(0.001) return None, None s, d = tsu(0x0B) row("PSP TSU mailbox", OK if s == 0 else PART, "flash_info_get -> status=%s data=%s" % (("%#06x" % s) if s is not None else "TIMEOUT", ("%#010x" % d) if d is not None else "-")) s2, d2 = tsu(0x07) row(" PSP boot state", OK, "transfer_type=%s (0x180 = wants off-chip item 0x80)" % (("%#010x" % d2) if d2 is not None else "-")) # --- memory ----------------------------------------------------------------- ms = rd(0xde3*4) row("VRAM / memory training", NO if ms == 0 else OK, "mmRCC_CONFIG_MEMSIZE=%#x" % ms) row("SMU (MP1)", NO, "MP1 C2PMSG_72 via SMN = %#010x" % smn(0x03B10A20)) print("%-28s %-8s %s" % ("CAPABILITY", "USABLE", "DETAIL")) print("-" * 92) for c, v, d in rows: print("%-28s %-8s %s" % (c, v, d))