1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
"""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('<I', bytes(b5[o:o+4]))[0]
wr = lambda o, v: b5.__setitem__(slice(o, o+4), struct.pack('<I', v & 0xFFFFFFFF))
row("BAR5 register read", OK, "C2PMSG_115=%#010x" % rd(0x582CC))
# --- SMN window -------------------------------------------------------------
def smn(a): wr(14*4, a); return rd(15*4)
mp0 = smn(0x03810ACC)
row("SMN window -> 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))
|