Merge remote-tracking branch 'jannau/m2_dptx' into m2-13_2

This commit is contained in:
Hector Martin 2023-04-11 21:29:01 +09:00
commit fe4037365b
29 changed files with 2694 additions and 129 deletions

View file

@ -73,6 +73,9 @@ LIBFDT_OBJECTS := $(patsubst %,libfdt/%, \
fdt_addresses.o fdt_empty_tree.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_sw.o \
fdt_wip.o fdt.o)
DCP_OBJECTS := $(patsubst %,dcp/%, \
dptx_phy.o dptxep.o parser.o)
OBJECTS := \
adt.o \
afk.o \
@ -116,6 +119,7 @@ OBJECTS := \
rtkit.o \
sart.o \
sep.o \
sio.o \
smp.o \
start.o \
startup.o \
@ -128,6 +132,7 @@ OBJECTS := \
utils.o utils_asm.o \
vsprintf.o \
wdt.o \
$(DCP_OBJECTS) \
$(MINILZLIB_OBJECTS) $(TINF_OBJECTS) $(DLMALLOC_OBJECTS) $(LIBFDT_OBJECTS) $(RUST_LIBS)
FP_OBJECTS := \
@ -149,9 +154,9 @@ all: update_tag update_cfg build/$(TARGET) build/$(TARGET_RAW)
clean:
rm -rf build/*
format:
$(CLANG_FORMAT) -i src/*.c src/math/*.c src/*.h src/math/*.h sysinc/*.h
$(CLANG_FORMAT) -i src/*.c src/dcp/*.c src/math/*.c src/*.h src/dcp/*.h src/math/*.h sysinc/*.h
format-check:
$(CLANG_FORMAT) --dry-run --Werror src/*.c src/*.h sysinc/*.h
$(CLANG_FORMAT) --dry-run --Werror src/*.c src/*.h src/dcp/*.c src/dcp/*.h sysinc/*.h
rustfmt:
cd rust && cargo fmt
rustfmt-check:

View file

@ -110,9 +110,13 @@ dcp = DCPClient(u, dcp_addr, dart, disp_dart)
dcp.dva_offset = getattr(u.adt["/arm-io/dcp"][0], "asc_dram_mask", 0)
dcp.start()
dcp.start_ep(0x20)
dcp.start_ep(0x37)
dcp.dcpep.initialize()
dcp.system.wait_for("system")
dcp.system.system.setProperty("gAFKConfigLogMask", 0xffff)
mgr = DCPManager(dcp.dcpep, compat)
mon.poll()
@ -193,16 +197,28 @@ width = mgr.display_width()
height = mgr.display_height()
surface_id = 3
surface_ov_id = 4
ov_dst_x = 200
ov_dst_y = 100
ov_height = 256
ov_width = 256
swap_rec = Container(
flags1 = 0x861202,
flags2 = 0x04,
swap_id = swapid.val,
surf_ids = [surface_id, 0, 0, 0],
src_rect = [[0, 0, width, height],[0,0,0,0],[0,0,0,0],[0,0,0,0]],
src_rect = [[0, 0, width, height],
[0,0,ov_height,ov_width],
[0,0,0,0],
[0,0,0,0]],
surf_flags = [1, 0, 0, 0],
surf_unk = [0, 0, 0, 0],
dst_rect = [[0, 0, width, height],[0,0,0,0],[0,0,0,0],[0,0,0,0]],
dst_rect = [[0, 0, width, height],
[ov_dst_x,ov_dst_y,ov_dst_x + ov_height,ov_dst_y + ov_width],
[0,0,0,0],
[0,0,0,0]],
swap_enabled = 0x80000007,
swap_completed = 0x80000007,
bl_unk = 0x1,
@ -213,7 +229,7 @@ swap_rec = Container(
surf = Container(
is_tiled = False,
unk_1 = False,
unk_2 = False,
unk_2 = True, # needs be true for overlay with "xf4p"
plane_cnt = 0,
plane_cnt2 = 0,
format = "BGRA",
@ -235,6 +251,32 @@ surf = Container(
unk_1f9 = 0,
)
surf_ov = Container(
is_tiled = False,
unk_1 = True,
unk_2 = True,
plane_cnt = 0,
plane_cnt2 = 0,
format = "xf4p",
xfer_func = 1,
colorspace = 2,
stride = ov_width * 4, # has to be 64-byte aligned
pix_size = 4,
pel_w = 1,
pel_h = 1,
offset = 0,
width = ov_width,
height = ov_height,
buf_size = ov_width * ov_height * 4,
surface_id = surface_ov_id,
has_comp = True,
has_planes = True,
has_planes = True,
has_compr_info = False,
unk_1f5 = 0,
unk_1f9 = 0,
)
compressed_surf = Container(
is_tiled = False,
unk_1 = False,
@ -329,9 +371,17 @@ for i, color in enumerate(colors):
iova = disp_dart.iomap(0, buf, fb_size)
surfaces = [surf, None, None, None]
ov_size = align_up(ov_width * ov_height * 4, 2 * 0x4000)
ov_buf = u.memalign(0x4000, ov_size)
p.memset32(ov_buf, 230 | 768 << 10 | 768 << 20, ov_width * ov_height * 4)
ov_iova = disp_dart.iomap(0, ov_buf, ov_size)
surfaces = [surf, surf_ov, None, None]
#surfaces = [compressed_surf, None, None, None]
surfAddr = [iova, 0, 0, 0]
surfAddr = [iova, ov_iova, 0, 0]
def submit():
swap_rec.swap_id = swapid.val

View file

@ -0,0 +1,46 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
import sys, pathlib
sys.path.append(str(pathlib.Path(__file__).resolve().parents[1]))
from m1n1.setup import *
from m1n1.shell import run_shell
from m1n1.fw.smc import SMCClient
smc_addr = u.adt["arm-io/smc"].get_reg(0)[0]
smc = SMCClient(u, smc_addr, None)
smc.verbose = 3
smc.start()
smc.start_ep(0x20)
smcep = smc.epmap[0x20]
# dp2hdmi-gpio.function-reset - not used at all by macos
# smcep.write('gP09', struct.pack("<I", 0x100001))
# smcep.write('gP09', struct.pack("<I", 0x100000))
smcep.write('gP16', struct.pack("<I", 0x800001))
smcep.write('gP15', struct.pack("<I", 0x800001))
force_dfp_pin = 0x28
hpd_pin = 0x31
gpio = u.adt["/arm-io/aop-gpio"]
base, size = gpio.get_reg(0)
print(f"gpio base: {base:#x}")
# macos reads force_dfp_pin only?
# p.write32(base + force_dfp_pin*4, 0x76a03)
p.write32(base + hpd_pin*4, 0x54b8d)
hdmi_hpd = p.read32(base + hpd_pin*4) & 0x1
print(f"HDMI hpd:{hdmi_hpd}")
# manual display config
config = u.malloc(256)
p.iface.writemem(config, b'1920x1080@60\0')
p.display_configure(config)
run_shell(globals(), msg="Have fun!")

View file

@ -5,6 +5,7 @@ from io import BytesIO
from enum import IntEnum
from m1n1.constructutils import Ver
from m1n1.proxyutils import RegMonitor
from m1n1.utils import *
from m1n1.trace.dart import DARTTracer
@ -12,6 +13,8 @@ from m1n1.trace.asc import ASCTracer, EP, EPState, msg, msg_log, DIR
from m1n1.fw.afk.rbep import *
from m1n1.fw.afk.epic import *
Ver.set_version(hv.u)
if True:
dcp_adt_path = "/arm-io/dcp"
dcp_dart_adt_path = "/arm-io/dart-dcp"

View file

@ -0,0 +1,24 @@
# SPDX-License-Identifier: MIT
from m1n1.trace.gpio import GPIOTracer
# trace gpio interrups, useful to follow the cascaded interrupts
aic_phandle = getattr(hv.adt["/arm-io/aic"], "AAPL,phandle")
node = hv.adt["/arm-io/aop-gpio"]
path = "/arm-io/aop-gpio"
if getattr(node, "interrupt-parent") == aic_phandle:
for irq in getattr(node, "interrupts"):
hv.trace_irq(node.name, irq, 1, hv.IRQTRACE_IRQ)
PIN_NAMES_DP2HDMI_J473 = {
0x28: "force_dfp",
0x31: "hdmi_hpd",
}
GPIOTracer = GPIOTracer._reloadcls()
gpio_tracer = GPIOTracer(hv, path, PIN_NAMES_DP2HDMI_J473, verbose=0)
gpio_tracer.start()
trace_device("/arm-io/dptx-phy")

View file

@ -3,9 +3,11 @@ from ...utils import *
from ..asc import StandardASC
from .dcpep import DCPEndpoint
from ..afk.epic import *
class DCPClient(StandardASC):
ENDPOINTS = {
0x20: AFKSystemEndpoint,
0x37: DCPEndpoint,
}

View file

@ -7,6 +7,7 @@ from enum import IntEnum
from ..common import *
from m1n1.utils import *
from construct import *
from m1n1.constructutils import Ver
@dataclass
class ByRef:
@ -419,7 +420,10 @@ IOMFBParameterName = Int32ul
BufferDescriptor = uint64_t
SwapCompleteData = Bytes(0x12)
SwapInfoBlob = Bytes(0x6c4)
SwapInfoBlob = Struct(
"unk" / Bytes(0x6c4),
Ver("V >= V13_2", "unk_13_2" / Bytes(0x10)),
)
SWAP_SURFACES = 4
@ -454,15 +458,15 @@ IOMFBSwapRec = Struct(
"unk_2c8" / Hex(Default(Int32ul, 0)),
"unk_2cc" / UnkBytes(0x14),
"unk_2e0" / Hex(Default(Int32ul, 0)),
"unk_2e2" / UnkBytes(0x2),
Ver("V < V13_2", "unk_2e2" / UnkBytes(0x2)),
Ver("V >= V13_2", "unk_2e2" / UnkBytes(0x3)),
"bl_unk" / Hex(Int64ul), # seen: 0x0, 0x1, 0x101, 0x1_0000, 0x101_010101
"bl_val" / Hex(Int32ul), # range 0x10000000 - approximately 0x7fe07fc0 for 4 - 510 nits
"bl_power" / Hex(Int8ul), # constant 0x40, 0x00: backlight off
"unk_2f3" / UnkBytes(0x2d),
Ver("V >= V13_2", "unk_320" / UnkBytes(0x13f)),
)
assert IOMFBSwapRec.sizeof() == 0x320
MAX_PLANES = 3
ComponentTypes = Struct(
@ -535,7 +539,7 @@ CompressionInfo = Struct(
"pad2" / Padding(1),
)
assert PlaneInfo.sizeof() == 0x34
assert CompressionInfo.sizeof() == 0x34
IOSurface = Struct(
"is_tiled" / bool_,
@ -567,19 +571,26 @@ IOSurface = Struct(
"unk_1f5" / Int32ul,
"unk_1f9" / Int32ul,
"padding" / UnkBytes(7),
Ver("V >= V13_2", "padding_13_2" / UnkBytes(40)),
)
assert IOSurface.sizeof() == 0x204
IOMFBColorFixedMatrix = Array(5, Array(3, ulong))
class PropID(IntEnum):
BrightnessCorrection = 14
class UPPipeAP_H13P(IPCObject):
A000 = Call(bool_, "late_init_signal")
# FW version dependent Calls
if Ver.check("V < V13_2"):
late_init_signal = Call(bool_, "late_init_signal")
update_notify_clients_dcp = Call(void, "update_notify_clients_dcp", Array(26, uint))
else:
late_init_signal = Call(bool_, "late_init_signal", bool_)
update_notify_clients_dcp = Call(void, "update_notify_clients_dcp", Array(26, uint))
A000 = late_init_signal
A029 = Call(void, "setup_video_limits")
A034 = Call(void, "update_notify_clients_dcp", Array(14, uint))
A034 = update_notify_clients_dcp
A035 = Call(bool_, "is_hilo")
A036 = Call(bool_, "apt_supported")
A037 = Call(uint, "get_dfb_info", InOutPtr(uint), InOutPtr(Array(4, ulong)), InOutPtr(uint))
@ -593,10 +604,19 @@ class UPPipeAP_H13P(IPCObject):
IdleCachingState = uint32_t
class UnifiedPipeline2(IPCObject):
# FW version dependent Call tags
set_create_DFB = Call(void, "set_create_DFB")
vi_set_temperature_hint = Call(IOMFBStatus, "vi_set_temperature_hint")
if Ver.check("V < V13_2"):
A357 = set_create_DFB
A358 = vi_set_temperature_hint
else:
A373 = set_create_DFB
A374 = vi_set_temperature_hint
A352 = Call(bool_, "applyProperty", uint, uint)
A353 = Call(uint, "get_system_type")
A357 = Call(void, "set_create_DFB")
A358 = Call(IOMFBStatus, "vi_set_temperature_hint")
D100 = Callback(void, "match_pmu_service")
D101 = Callback(uint32_t, "UNK_get_some_field")
@ -608,15 +628,37 @@ class UnifiedPipeline2(IPCObject):
D109 = Callback(bool_, "create_PMU_service")
D110 = Callback(bool_, "create_iomfb_service")
D111 = Callback(bool_, "create_backlight_service")
D112 = Callback(void, "set_idle_caching_state_ap", IdleCachingState, uint)
D116 = Callback(bool_, "start_hardware_boot")
D117 = Callback(bool_, "is_dark_boot")
D118 = Callback(bool_, "is_waking_from_hibernate")
D120 = Callback(bool_, "read_edt_data", key=string(0x40), count=uint, value=InOut(Lazy(SizedArray(8, "count", uint32_t))))
D122 = Callback(bool_, "setDCPAVPropStart", length=uint)
D123 = Callback(bool_, "setDCPAVPropChunk", data=HexDump(SizedBytes(0x1000, "length")), offset=uint, length=uint)
D124 = Callback(bool_, "setDCPAVPropEnd", key=string(0x40))
# FW version dependent Callback tags
create_nvram_service = Callback(bool_, "create_nvram_service") # guessed
set_idle_caching_state_ap = Callback(void, "set_idle_caching_state_ap", IdleCachingState, uint)
start_hardware_boot = Callback(bool_, "start_hardware_boot")
is_dark_boot = Callback(bool_, "is_dark_boot")
is_waking_from_hibernate = Callback(bool_, "is_waking_from_hibernate")
read_edt_data = Callback(bool_, "read_edt_data", key=string(0x40), count=uint, value=InOut(Lazy(SizedArray(8, "count", uint32_t))))
setDCPAVPropStart = Callback(bool_, "setDCPAVPropStart", length=uint)
setDCPAVPropChunk = Callback(bool_, "setDCPAVPropChunk", data=HexDump(SizedBytes(0x1000, "length")), offset=uint, length=uint)
setDCPAVPropEnd = Callback(bool_, "setDCPAVPropEnd", key=string(0x40))
if Ver.check("V < V13_2"):
D112 = set_idle_caching_state_ap
D116 = start_hardware_boot
D117 = is_dark_boot
D118 = is_waking_from_hibernate
D120 = read_edt_data
D122 = setDCPAVPropStart
D123 = setDCPAVPropChunk
D124 = setDCPAVPropEnd
else:
D112 = create_nvram_service
D113 = set_idle_caching_state_ap
D119 = start_hardware_boot
D120 = is_dark_boot
D121 = is_waking_from_hibernate
D123 = read_edt_data
D125 = setDCPAVPropStart
D126 = setDCPAVPropChunk
D127 = setDCPAVPropEnd
class UPPipe2(IPCObject):
A102 = Call(uint64_t, "test_control", cmd=uint64_t, arg=uint)
@ -639,10 +681,9 @@ class PropRelay(IPCObject):
D300 = Callback(void, "pr_publish", prop_id=uint32_t, value=int_)
class IOMobileFramebufferAP(IPCObject):
A401 = Call(uint32_t, "start_signal")
A407 = Call(uint32_t, "swap_start", swap_id=InOutPtr(uint), client=InOutPtr(IOUserClient))
A408 = Call(uint32_t, "swap_submit_dcp",
# FW version dependent Calls
if Ver.check("V < V13_2"):
swap_submit_dcp = Call(uint32_t, "swap_submit_dcp",
swap_rec=InPtr(IOMFBSwapRec),
surfaces=Array(4, InPtr(IOSurface)),
surfAddr=Array(4, Hex(ulong)),
@ -650,11 +691,28 @@ class IOMobileFramebufferAP(IPCObject):
unkFloat=Float64l,
unkInt=uint,
unkOutBool=OutPtr(bool_))
else:
swap_submit_dcp = Call(uint32_t, "swap_submit_dcp",
swap_rec=InPtr(IOMFBSwapRec),
surfaces=Array(SWAP_SURFACES, InPtr(IOSurface)),
surfAddr=Array(SWAP_SURFACES, Hex(ulong)),
unkU64Array=Array(SWAP_SURFACES, Hex(ulong)),
surfaces2=Array(5, InPtr(IOSurface)),
surfAddr2=Array(5, Hex(ulong)),
unkBool=bool_,
unkFloat=Float64l,
unkU64=ulong,
unkBool2=bool_,
unkInt=uint,
unkOutBool=OutPtr(bool_),
unkCUintArray=InPtr(uint),
unkUintPtr=OutPtr(uint))
A401 = Call(uint32_t, "start_signal")
A407 = Call(uint32_t, "swap_start", swap_id=InOutPtr(uint), client=InOutPtr(IOUserClient))
A408 = swap_submit_dcp
A410 = Call(uint32_t, "set_display_device", uint)
A411 = Call(bool_, "is_main_display")
A438 = Call(uint32_t, "swap_set_color_matrix", matrix=InOutPtr(IOMFBColorFixedMatrix), func=uint32_t, unk=uint)
#"A438": "IOMobileFramebufferAP::swap_set_color_matrix(IOMFBColorFixedMatrix*, IOMFBColorMatrixFunction, unsigned int)",
A412 = Call(uint32_t, "set_digital_out_mode", uint, uint)
A413 = Call(uint32_t, "get_digital_out_state", InOutPtr(uint))
@ -665,27 +723,80 @@ class IOMobileFramebufferAP(IPCObject):
A426 = Call(uint32_t, "get_color_remap_mode", InOutPtr(uint32_t))
A427 = Call(uint32_t, "setBrightnessCorrection", uint)
A435 = Call(uint32_t, "set_block_dcp", arg1=uint64_t, arg2=uint, arg3=uint, arg4=Array(8, ulong), arg5=uint, data=SizedBytes(0x1000, "length"), length=ulong)
A439 = Call(uint32_t, "set_parameter_dcp", param=IOMFBParameterName, value=Lazy(SizedArray(4, "count", ulong)), count=uint)
# FW version dependent Call tags
set_block_dcp = Call(uint32_t, "set_block_dcp", arg1=uint64_t, arg2=uint, arg3=uint, arg4=Array(8, ulong), arg5=uint, data=SizedBytes(0x1000, "length"), length=ulong, unknArry=Array(4, uint))
get_block_dcp = Call(uint32_t, "get_block_dcp", arg1=uint64_t, arg2=uint, arg3=uint, arg4=Array(8, ulong), arg5=uint, data=OutPtr(SizedBytes(0x1000, "length")), length=uint)
swap_set_color_matrix = Call(uint32_t, "swap_set_color_matrix", matrix=InOutPtr(IOMFBColorFixedMatrix), func=uint32_t, unk=uint)
set_parameter_dcp = Call(uint32_t, "set_parameter_dcp", param=IOMFBParameterName, value=Lazy(SizedArray(4, "count", ulong)), count=uint)
display_width = Call(uint, "display_width")
display_height = Call(uint, "display_height")
get_display_size = Call(void, "get_display_size", OutPtr(uint), OutPtr(uint))
do_create_default_frame_buffer = Call(int_, "do_create_default_frame_buffer")
printRegs = Call(void, "printRegs")
enable_disable_video_power_savings = Call(int_, "enable_disable_video_power_savings", uint)
first_client_open = Call(void, "first_client_open")
last_client_close_dcp = Call(void, "last_client_close_dcp", OutPtr(uint))
writeDebugInfo = Call(bool_, "writeDebugInfo", ulong)
flush_debug_flags = Call(void, "flush_debug_flags", uint)
io_fence_notify = Call(bool_, "io_fence_notify", uint, uint, ulong, IOMFBStatus)
setDisplayRefreshProperties = Call(bool_, "setDisplayRefreshProperties")
flush_supportsPower = Call(void, "flush_supportsPower", bool_)
abort_swaps_dcp = Call(uint, "abort_swaps_dcp", InOutPtr(IOMobileFramebufferUserClient))
update_dfb = Call(uint, "update_dfb", surf=InPtr(IOSurface))
setPowerState = Call(uint32_t, "setPowerState", ulong, bool_, OutPtr(uint))
isKeepOnScreen = Call(bool_, "isKeepOnScreen")
A440 = Call(uint, "display_width")
A441 = Call(uint, "display_height")
A442 = Call(void, "get_display_size", OutPtr(uint), OutPtr(uint))
A443 = Call(int_, "do_create_default_frame_buffer")
A444 = Call(void, "printRegs")
A447 = Call(int_, "enable_disable_video_power_savings", uint)
A454 = Call(void, "first_client_open")
A455 = Call(void, "last_client_close_dcp", OutPtr(uint))
A456 = Call(bool_, "writeDebugInfo", ulong)
A457 = Call(void, "flush_debug_flags", uint)
A458 = Call(bool_, "io_fence_notify", uint, uint, ulong, IOMFBStatus)
A460 = Call(bool_, "setDisplayRefreshProperties")
A463 = Call(void, "flush_supportsPower", bool_)
A464 = Call(uint, "abort_swaps_dcp", InOutPtr(IOMobileFramebufferUserClient))
if Ver.check("V < V13_2"):
A435 = set_block_dcp
A436 = get_block_dcp
A438 = swap_set_color_matrix
A439 = set_parameter_dcp
A440 = display_width
A441 = display_height
A442 = get_display_size
A443 = do_create_default_frame_buffer
A444 = printRegs
A447 = enable_disable_video_power_savings
A454 = first_client_open
A455 = last_client_close_dcp
A456 = writeDebugInfo
A457 = flush_debug_flags
A458 = io_fence_notify
A460 = setDisplayRefreshProperties
A463 = flush_supportsPower
A464 = abort_swaps_dcp
A467 = update_dfb
A468 = setPowerState
A469 = isKeepOnScreen
else:
A437 = set_block_dcp
A438 = get_block_dcp
A440 = swap_set_color_matrix
A441 = set_parameter_dcp
A442 = display_width
A443 = display_height
A444 = get_display_size
A445 = do_create_default_frame_buffer
A446 = printRegs
A449 = enable_disable_video_power_savings
A456 = first_client_open
A457 = last_client_close_dcp
A458 = writeDebugInfo
A459 = flush_debug_flags
A460 = io_fence_notify
A462 = setDisplayRefreshProperties
A465 = flush_supportsPower
A466 = abort_swaps_dcp
A469 = update_dfb
A471 = setPowerState
A472 = isKeepOnScreen
A467 = Call(uint, "update_dfb", surf=InPtr(IOSurface))
A468 = Call(uint32_t, "setPowerState", ulong, bool_, OutPtr(uint))
A469 = Call(bool_, "isKeepOnScreen")
# FW version dependent callbacks
if Ver.check("V < V13_2"):
hotPlug_notify_gated = Callback(void, "hotPlug_notify_gated", ulong)
else:
# TODO: is this sensible?
hotPlug_notify_gated = Callback(void, "hotPlug_notify_gated", uint, InOutPtr(Bytes(0x4c)))
D552 = Callback(bool_, "setProperty_dict", key=string(0x40), value=InPtr(Padded(0x1000, OSDictionary())))
D561 = Callback(bool_, "setProperty_dict", key=string(0x40), value=InPtr(Padded(0x1000, OSDictionary())))
@ -696,7 +807,7 @@ class IOMobileFramebufferAP(IPCObject):
D574 = Callback(IOMFBStatus, "powerUpDART", bool_)
D575 = Callback(bool_, "get_dot_pitch", OutPtr(uint))
D576 = Callback(void, "hotPlug_notify_gated", ulong)
D576 = hotPlug_notify_gated
D577 = Callback(void, "powerstate_notify", bool_, bool_)
D578 = Callback(bool_, "idle_fence_create", IdleCachingState)
D579 = Callback(void, "idle_fence_complete")
@ -718,12 +829,18 @@ class IOMobileFramebufferAP(IPCObject):
D598 = Callback(void, "find_swap_function_gated")
class ServiceRelay(IPCObject):
# FW version dependent Callbacks
if Ver.check("V < V13_2"):
sr_mapDeviceMemoryWithIndex = Callback(IOMFBStatus, "sr_mapDeviceMemoryWithIndex", obj=FourCC, index=uint, flags=uint, addr=OutPtr(ulong), length=OutPtr(ulong))
else:
sr_mapDeviceMemoryWithIndex = Callback(IOMFBStatus, "sr_mapDeviceMemoryWithIndex", obj=FourCC, index=uint, flags=uint, unk_u64=OutPtr(ulong), addr=OutPtr(ulong), length=OutPtr(ulong))
D400 = Callback(void, "get_property", obj=FourCC, key=string(0x40), value=OutPtr(Bytes(0x200)), lenght=InOutPtr(uint))
D401 = Callback(bool_, "sr_get_uint_prop", obj=FourCC, key=string(0x40), value=InOutPtr(ulong))
D404 = Callback(void, "sr_set_uint_prop", obj=FourCC, key=string(0x40), value=uint)
D406 = Callback(void, "set_fx_prop", obj=FourCC, key=string(0x40), value=uint)
D408 = Callback(uint64_t, "sr_getClockFrequency", obj=FourCC, arg=uint)
D411 = Callback(IOMFBStatus, "sr_mapDeviceMemoryWithIndex", obj=FourCC, index=uint, flags=uint, addr=OutPtr(ulong), length=OutPtr(ulong))
D411 = sr_mapDeviceMemoryWithIndex
D413 = Callback(bool_, "sr_setProperty_dict", obj=FourCC, key=string(0x40), value=InPtr(Padded(0x1000, OSDictionary())))
D414 = Callback(bool_, "sr_setProperty_int", obj=FourCC, key=string(0x40), value=InPtr(uint64_t))
D415 = Callback(bool_, "sr_setProperty_bool", obj=FourCC, key=string(0x40), value=InPtr(Bool(uint32_t)))
@ -840,3 +957,7 @@ class Call:
method.print_long_args(indent, self.in_vals, self.out_vals)
#if len(method.out_fields) - (self.ret is not None):
#print(self.out_vals)
def get_method(self):
cls, method = ALL_METHODS.get(self.msg, (None, None))
return method

View file

@ -1,8 +1,37 @@
# SPDX-License-Identifier: MIT
from m1n1.utils import *
from m1n1.constructutils import Ver
from m1n1.fw.dcp.ipc import *
class DCPAVPropHandler:
def __init__(self):
self.dcpav_prop = {}
def setDCPAVPropStart(self, length):
# print(f"setDCPAVPropStart({length:#x})")
self.dcpav_prop_len = length - 1 # off by one?
self.dcpav_prop_off = 0
self.dcpav_prop_data = []
return True
def setDCPAVPropChunk(self, data, offset, length):
# print(f"setDCPAVPropChunk(..., {offset:#x}, {length:#x})")
assert offset == self.dcpav_prop_off
self.dcpav_prop_data.append(data)
self.dcpav_prop_off += len(data)
return True
def setDCPAVPropEnd(self, key):
# print(f"setDCPAVPropEnd({key!r})")
blob = b"".join(self.dcpav_prop_data)
assert self.dcpav_prop_len == len(blob)
self.dcpav_prop[key] = OSSerialize().parse(blob)
self.dcpav_prop_data = self.dcpav_prop_len = self.dcpav_prop_off = None
pprint.pprint(self.dcpav_prop[key])
return True
def parse_log(fd):
op_stack = {}
for line in fd:
@ -17,6 +46,12 @@ def parse_log(fd):
op = op_stack[chan].pop()
assert int(off, 0) == op.off
op.ack(bytes.fromhex(out_data))
elif optype == "VERSION":
for arg in args.strip().split(" "):
version = arg.split(":")
if len(version) == 2:
Ver.set_version_key(version[0], version[1])
continue
else:
raise Exception(f"Unknown log cmd {optype}")
@ -27,8 +62,24 @@ def dump_log(fd):
"": 0,
"OOB": 0,
}
handler = DCPAVPropHandler()
for op in parse_log(fd):
ctx = ""
if Ver.check("V < V13_2"):
dcpavprop_cbs = ["D122", "D123", "D124"]
else:
dcpavprop_cbs = ["D125", "D126", "D127"]
if not op.complete and op.msg in dcpavprop_cbs:
method = op.get_method()
if op.msg == dcpavprop_cbs[0]:
method.callback(handler.setDCPAVPropStart, op.in_data)
if op.msg == dcpavprop_cbs[1]:
method.callback(handler.setDCPAVPropChunk, op.in_data)
if op.msg == dcpavprop_cbs[2]:
method.callback(handler.setDCPAVPropEnd, op.in_data)
if "OOB" in op.chan:
ctx = "[OOB] -----------> "
if not op.complete:

View file

@ -47,6 +47,14 @@ else
fi
if [ -n "$initramfs" ]; then
initramfs_size=$(stat --printf='%s' "$initramfs")
python - << EOF >>"$TMPDIR/m1n1-linux.bin"
import os, sys
magic = b'm1n1_initramfs'
size = int(${initramfs_size}).to_bytes(4, byteorder='little')
os.write(sys.stdout.fileno(), magic + size)
EOF
cat "$initramfs" >>"$TMPDIR/m1n1-linux.bin"
fi

322
src/afk.c
View file

@ -38,10 +38,6 @@ enum EPICCategory {
CAT_COMMAND = 0x30,
};
enum EPICMessage {
CODE_ANNOUNCE = 0x30,
};
struct afk_qe {
u32 magic;
u32 size;
@ -62,11 +58,12 @@ struct epic_sub_hdr {
u32 length;
u8 version;
u8 category;
u16 code;
u16 type;
u64 timestamp;
u16 seq;
u16 unk;
u32 unk2;
u8 unk;
u8 flags;
u32 inline_len;
} PACKED;
struct epic_announce {
@ -80,12 +77,21 @@ struct epic_cmd {
u64 txbuf;
u32 rxlen;
u32 txlen;
u16 pad;
} PACKED;
#define AFK_MAX_CHANNEL 16
struct afk_epic {
rtkit_dev_t *rtk;
afk_epic_ep_t *endpoint[0x10];
};
struct afk_epic_ep {
int ep;
rtkit_dev_t *rtk;
afk_epic_t *afk;
struct rtkit_buffer buf;
u16 tag;
@ -96,6 +102,12 @@ struct afk_epic_ep {
struct rtkit_buffer rxbuf;
bool started;
u16 seq;
const afk_epic_service_ops_t *ops;
afk_epic_service_t services[AFK_MAX_CHANNEL];
void (*recv_handler)(afk_epic_ep_t *epic);
};
enum RBEP_MSG {
@ -144,12 +156,12 @@ bool afk_rb_init(afk_epic_ep_t *epic, struct afk_rb *rb, u64 base, u64 size)
return true;
}
static int afk_epic_poll(afk_epic_ep_t *epic)
static int afk_epic_poll(afk_epic_t *afk, int endpoint, u32 count)
{
int ret;
struct rtkit_message msg;
while ((ret = rtkit_recv(epic->rtk, &msg)) == 0)
while (count-- > 0 && (ret = rtkit_recv(afk->rtk, &msg)) == 0)
;
if (ret < 0) {
@ -157,11 +169,22 @@ static int afk_epic_poll(afk_epic_ep_t *epic)
return ret;
}
if (msg.ep != epic->ep) {
if (ret == 0) {
printf("EPIC: rtkit_recv timed out!\n");
return -1;
}
if (msg.ep < 0x20 || msg.ep >= 0x30 || !afk->endpoint[msg.ep - 0x20]) {
printf("EPIC: received message for unexpected endpoint %d\n", msg.ep);
return 0;
}
afk_epic_ep_t *epic = afk->endpoint[msg.ep - 0x20];
if (!epic) {
printf("EPIC: received message for idle endpoint %d\n", msg.ep);
return 0;
}
int type = FIELD_GET(RBEP_TYPE, msg.msg);
u64 base, size, tag;
switch (type) {
@ -171,13 +194,13 @@ static int afk_epic_poll(afk_epic_ep_t *epic)
case RBEP_GETBUF:
size = FIELD_GET(GETBUF_SIZE, msg.msg) << BLOCK_SHIFT;
epic->tag = FIELD_GET(GETBUF_TAG, msg.msg);
if (!rtkit_alloc_buffer(epic->rtk, &epic->buf, size)) {
if (!rtkit_alloc_buffer(epic->afk->rtk, &epic->buf, size)) {
printf("EPIC: failed to allocate buffer\n");
return -1;
}
msg.msg = (FIELD_PREP(RBEP_TYPE, RBEP_GETBUF_ACK) |
FIELD_PREP(GETBUF_ACK_DVA, epic->buf.dva));
if (!rtkit_send(epic->rtk, &msg)) {
if (!rtkit_send(epic->afk->rtk, &msg)) {
printf("EPIC: failed to send buffer address\n");
return -1;
}
@ -204,7 +227,7 @@ static int afk_epic_poll(afk_epic_ep_t *epic)
if (epic->rx.ready && epic->tx.ready) {
msg.msg = FIELD_PREP(RBEP_TYPE, RBEP_START);
if (!rtkit_send(epic->rtk, &msg)) {
if (!rtkit_send(epic->afk->rtk, &msg)) {
printf("EPIC: failed to send start\n");
return -1;
}
@ -212,7 +235,11 @@ static int afk_epic_poll(afk_epic_ep_t *epic)
break;
case RBEP_RECV:
if (endpoint == epic->ep)
return 1;
if (epic->recv_handler)
epic->recv_handler(epic);
break;
case RBEP_START_ACK:
epic->started = true;
@ -238,9 +265,18 @@ static int afk_epic_rx(afk_epic_ep_t *epic, struct afk_qe **qe)
u32 rptr = rb->hdr->rptr;
if (epic->ep == 0x2a && rptr != rb->hdr->wptr) {
bool can_read = rtkit_can_recv(epic->afk->rtk);
if (can_read) {
ret = afk_epic_poll(epic->afk, epic->ep, 1);
if (ret < 0)
return ret;
}
}
while (rptr == rb->hdr->wptr) {
do {
ret = afk_epic_poll(epic);
ret = afk_epic_poll(epic->afk, epic->ep, UINT32_MAX);
if (ret < 0)
return ret;
} while (ret == 0);
@ -318,7 +354,7 @@ static int afk_epic_tx(afk_epic_ep_t *epic, u32 channel, u32 type, void *data, s
FIELD_PREP(RBEP_TYPE, RBEP_SEND) | FIELD_PREP(SEND_WPTR, wptr),
};
if (!rtkit_send(epic->rtk, &msg)) {
if (!rtkit_send(epic->afk->rtk, &msg)) {
printf("EPIC: failed to send TX WPTR message\n");
return -1;
}
@ -345,8 +381,118 @@ static void afk_epic_rx_ack(afk_epic_ep_t *epic)
rb->hdr->rptr = rptr;
}
int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 code, void *txbuf, size_t txsize,
void *rxbuf, size_t *rxsize)
struct epic_std_service_ap_call {
u32 unk0;
u32 unk1;
u32 type;
u32 len;
u32 magic;
u8 _unk[48];
} PACKED;
static int afk_epic_handle_std_service(afk_epic_ep_t *epic, int channel, struct epic_hdr *hdr,
struct epic_sub_hdr *sub, void *payload, size_t payload_size)
{
afk_epic_service_t *service = &epic->services[channel];
if (sub->category == CAT_NOTIFY) {
struct epic_std_service_ap_call *call = payload;
size_t call_size;
void *reply;
int ret;
if (payload_size < sizeof(*call))
return -1;
call_size = call->len;
if (payload_size < sizeof(*call) + call_size)
return -1;
if (!service->ops->call)
return 0;
reply = calloc(payload_size, 1);
if (!reply)
return -1;
ret = service->ops->call(service, call->type, payload + sizeof(*call), call_size,
reply + sizeof(*call), call_size);
if (ret) {
free(reply);
return ret;
}
memcpy(reply, call, sizeof(*call));
size_t tx_size = sizeof(struct epic_hdr) + sizeof(struct epic_sub_hdr) + payload_size;
void *msg = calloc(tx_size, 1);
u32 sub_seq = sub->seq;
struct epic_hdr *hdr = msg;
struct epic_sub_hdr *sub = msg + sizeof(struct epic_hdr);
hdr->version = 2;
hdr->seq = epic->seq++;
sub->length = payload_size;
sub->version = 4;
sub->category = CAT_REPLY;
sub->type = CODE_STD_SERVICE;
sub->seq = sub_seq; // service->seq++;
sub->flags = 0x08;
sub->inline_len = payload_size - 4;
memcpy(msg + sizeof(struct epic_hdr) + sizeof(struct epic_sub_hdr), reply, payload_size);
afk_epic_tx(epic, channel, TYPE_NOTIFY_ACK, msg, tx_size);
free(reply);
free(msg);
return 0;
}
printf("AFK: channel %d received unhandled standard service message: %x\n", channel,
sub->category);
return -1;
}
int afk_epic_report(afk_epic_ep_t *epic, int channel, u32 type, u16 sub_seq, void *payload,
size_t payload_size)
{
struct epic_hdr *hdr;
struct epic_sub_hdr *sub;
size_t bfr_size = sizeof(*hdr) + sizeof(*sub) + payload_size;
void *bfr = calloc(bfr_size, 1);
if (!bfr)
return -1;
memset(bfr, 0, bfr_size);
hdr = bfr;
sub = bfr + sizeof(*hdr);
hdr->version = 2;
hdr->seq = epic->seq++;
sub->length = payload_size;
sub->version = 4;
sub->category = CAT_REPORT;
sub->type = type;
sub->seq = sub_seq;
memcpy(bfr + sizeof(*hdr) + sizeof(*sub), payload, payload_size);
int ret = afk_epic_tx(epic, channel, TYPE_NOTIFY, bfr, bfr_size);
free(bfr);
if (ret < 0) {
printf("EPIC: failed to transmit notify\n");
return ret;
}
return 0;
}
int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 sub_seq, u16 code, void *txbuf,
size_t txsize, void *rxbuf, size_t *rxsize)
{
struct {
struct epic_hdr hdr;
@ -359,13 +505,15 @@ int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 code, void *txbuf, si
memset(&msg, 0, sizeof(msg));
u32 tag = epic->seq;
msg.hdr.version = 2;
msg.hdr.seq = 0;
msg.hdr.seq = epic->seq++;
msg.sub.length = sizeof(msg.cmd);
msg.sub.version = 3;
msg.sub.version = 4;
msg.sub.category = CAT_COMMAND;
msg.sub.code = code;
msg.sub.seq = 0;
msg.sub.type = code;
msg.sub.seq = sub_seq;
msg.cmd.txbuf = epic->txbuf.dva;
msg.cmd.txlen = txsize;
msg.cmd.rxbuf = epic->rxbuf.dva;
@ -396,9 +544,16 @@ int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 code, void *txbuf, si
struct epic_hdr *hdr = (void *)(rmsg + 1);
struct epic_sub_hdr *sub = (void *)(hdr + 1);
if (sub->category != CAT_REPLY || sub->code != code) {
if (sub->category == CAT_NOTIFY && sub->type == CODE_STD_SERVICE) {
void *payload = rmsg->data + sizeof(struct epic_hdr) + sizeof(struct epic_sub_hdr);
size_t payload_size =
rmsg->size - sizeof(struct epic_hdr) - sizeof(struct epic_sub_hdr);
afk_epic_rx_ack(epic);
afk_epic_handle_std_service(epic, channel, hdr, sub, payload, payload_size);
continue;
} else if (sub->category != CAT_REPLY || sub->type != code) {
printf("EPIC: got unexpected message %02x:%04x during command\n", sub->category,
sub->code);
sub->type);
afk_epic_rx_ack(epic);
continue;
}
@ -424,7 +579,34 @@ int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 code, void *txbuf, si
return 0;
}
afk_epic_ep_t *afk_epic_init(rtkit_dev_t *rtk, int endpoint)
static void afk_epic_notify_handler(afk_epic_ep_t *epic)
{
struct afk_qe *rmsg;
int ret = afk_epic_rx(epic, &rmsg);
if (ret < 0)
return;
if (rmsg->type != TYPE_NOTIFY) {
printf("EPIC: got unexpected message type %d in %s command\n", rmsg->type, __func__);
afk_epic_rx_ack(epic);
return;
}
struct epic_hdr *hdr = (void *)(rmsg + 1);
struct epic_sub_hdr *sub = (void *)(hdr + 1);
if (sub->category == CAT_NOTIFY && sub->type == CODE_STD_SERVICE) {
void *payload = rmsg->data + sizeof(struct epic_hdr) + sizeof(struct epic_sub_hdr);
size_t payload_size = rmsg->size - sizeof(struct epic_hdr) - sizeof(struct epic_sub_hdr);
afk_epic_handle_std_service(epic, rmsg->channel, hdr, sub, payload, payload_size);
} else
printf("EPIC: %s: rx: Ch %u, Type:0x%02x sub cat:%x type:%x \n", __func__, rmsg->channel,
rmsg->type, sub->category, sub->type);
afk_epic_rx_ack(epic);
}
afk_epic_ep_t *afk_epic_start_ep(afk_epic_t *afk, int endpoint, bool notify)
{
afk_epic_ep_t *epic = malloc(sizeof(afk_epic_ep_t));
if (!epic)
@ -432,21 +614,25 @@ afk_epic_ep_t *afk_epic_init(rtkit_dev_t *rtk, int endpoint)
memset(epic, 0, sizeof(*epic));
epic->ep = endpoint;
epic->rtk = rtk;
epic->afk = afk;
afk->endpoint[endpoint - 0x20] = epic;
if (!rtkit_start_ep(rtk, endpoint)) {
if (notify)
epic->recv_handler = afk_epic_notify_handler;
if (!rtkit_start_ep(epic->afk->rtk, endpoint)) {
printf("EPIC: failed to start endpoint %d\n", endpoint);
goto err;
}
struct rtkit_message msg = {endpoint, FIELD_PREP(RBEP_TYPE, RBEP_INIT)};
if (!rtkit_send(rtk, &msg)) {
if (!rtkit_send(epic->afk->rtk, &msg)) {
printf("EPIC: failed to send init message\n");
goto err;
}
while (!epic->started) {
int ret = afk_epic_poll(epic);
int ret = afk_epic_poll(epic->afk, endpoint, UINT32_MAX);
if (ret < 0)
break;
else if (ret > 0)
@ -456,33 +642,37 @@ afk_epic_ep_t *afk_epic_init(rtkit_dev_t *rtk, int endpoint)
return epic;
err:
afk->endpoint[endpoint - 0x20] = NULL;
free(epic);
return NULL;
}
int afk_epic_shutdown(afk_epic_ep_t *epic)
int afk_epic_shutdown_ep(afk_epic_ep_t *epic)
{
struct rtkit_message msg = {epic->ep, FIELD_PREP(RBEP_TYPE, RBEP_SHUTDOWN)};
if (!rtkit_send(epic->rtk, &msg)) {
if (!rtkit_send(epic->afk->rtk, &msg)) {
printf("EPIC: failed to send shutdown message\n");
return -1;
}
while (epic->started) {
int ret = afk_epic_poll(epic);
int ret = afk_epic_poll(epic->afk, epic->ep, UINT32_MAX);
if (ret < 0)
break;
}
rtkit_free_buffer(epic->rtk, &epic->buf);
rtkit_free_buffer(epic->rtk, &epic->rxbuf);
rtkit_free_buffer(epic->rtk, &epic->txbuf);
rtkit_free_buffer(epic->afk->rtk, &epic->buf);
rtkit_free_buffer(epic->afk->rtk, &epic->rxbuf);
rtkit_free_buffer(epic->afk->rtk, &epic->txbuf);
epic->afk->endpoint[epic->ep - 0x20] = NULL;
free(epic);
return 0;
}
int afk_epic_start_interface(afk_epic_ep_t *epic, char *name, size_t txsize, size_t rxsize)
int afk_epic_start_channel(afk_epic_ep_t *epic, const afk_epic_service_ops_t *ops, void *intf,
const char *name)
{
int channel = -1;
struct afk_qe *msg;
@ -503,9 +693,9 @@ int afk_epic_start_interface(afk_epic_ep_t *epic, char *name, size_t txsize, siz
struct epic_hdr *hdr = (void *)(msg + 1);
struct epic_sub_hdr *sub = (void *)(hdr + 1);
if (sub->category != CAT_REPORT || sub->code != CODE_ANNOUNCE) {
if (sub->category != CAT_REPORT || sub->type != CODE_ANNOUNCE) {
printf("EPIC: got unexpected message %02x:%04x during iface start\n", sub->category,
sub->code);
sub->type);
afk_epic_rx_ack(epic);
continue;
}
@ -518,28 +708,74 @@ int afk_epic_start_interface(afk_epic_ep_t *epic, char *name, size_t txsize, siz
continue;
}
size_t props_size = sub->length - offsetof(struct epic_announce, props);
afk_epic_service_t *service = &epic->services[msg->channel];
service->ops = ops;
service->epic = epic;
service->intf = intf;
service->channel = msg->channel;
if (ops && ops->init && !ops->init(service, announce->props, props_size)) {
printf("EPIC: ignoring channel %d: %s\n", msg->channel, announce->name);
afk_epic_rx_ack(epic);
memset(service, 0, sizeof(*service));
continue;
}
channel = msg->channel;
break;
}
afk_epic_rx_ack(epic);
return channel;
}
int afk_epic_start_interface(afk_epic_ep_t *epic, const afk_epic_service_ops_t *ops, void *intf,
const char *name, size_t txsize, size_t rxsize)
{
int channel = afk_epic_start_channel(epic, ops, intf, name);
if (channel == -1) {
printf("EPIC: too many unexpected messages, giving up\n");
return -1;
}
if (!rtkit_alloc_buffer(epic->rtk, &epic->rxbuf, rxsize)) {
if (!rtkit_alloc_buffer(epic->afk->rtk, &epic->rxbuf, rxsize)) {
printf("EPIC: failed to allocate rx buffer\n");
return -1;
}
if (!rtkit_alloc_buffer(epic->rtk, &epic->txbuf, txsize)) {
if (!rtkit_alloc_buffer(epic->afk->rtk, &epic->txbuf, txsize)) {
printf("EPIC: failed to allocate tx buffer\n");
return -1;
}
printf("EPIC: started interface %d (%s)\n", msg->channel, announce->name);
afk_epic_rx_ack(epic);
printf("EPIC: started interface %d (%s)\n", channel, name);
return channel;
}
afk_epic_t *afk_epic_init(rtkit_dev_t *rtkit)
{
afk_epic_t *afk = calloc(sizeof(*afk), 1);
if (!afk)
return NULL;
afk->rtk = rtkit;
return afk;
}
int afk_epic_shutdown(afk_epic_t *afk)
{
for (int i = 0; i < 0x10; i++)
if (afk->endpoint[i])
afk_epic_shutdown_ep(afk->endpoint[i]);
free(afk);
return 0;
}

View file

@ -3,15 +3,75 @@
#ifndef DCP_AFK_H
#define DCP_AFK_H
#include <stddef.h>
#include "rtkit.h"
#define MAX_PENDING_CMDS 8
typedef struct afk_epic afk_epic_t;
typedef struct afk_epic_ep afk_epic_ep_t;
afk_epic_ep_t *afk_epic_init(rtkit_dev_t *rtkit, int endpoint);
int afk_epic_shutdown(afk_epic_ep_t *epic);
typedef struct afk_epic_service_ops afk_epic_service_ops_t;
int afk_epic_start_interface(afk_epic_ep_t *epic, char *name, size_t insize, size_t outsize);
int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 code, void *txbuf, size_t txsize,
void *rxbuf, size_t *rxsize);
enum EPICMessage {
CODE_ANNOUNCE = 0x30,
CODE_STD_SERVICE = 0xc0,
};
struct epic_cmd_info {
u16 code;
void *rxbuf;
void *txbuf;
u64 rxbuf_dma;
u64 txbuf_dma;
size_t rxlen;
size_t txlen;
u32 retcode;
bool done;
bool free_on_ack;
};
typedef struct afk_epic_service {
const afk_epic_service_ops_t *ops;
afk_epic_ep_t *epic;
void *intf;
struct epic_cmd_info cmds[MAX_PENDING_CMDS];
u8 cmd_tag;
u32 channel;
bool enabled;
u16 seq;
void *cookie;
} afk_epic_service_t;
typedef struct afk_epic_service_ops {
const char name[32];
bool (*init)(afk_epic_service_t *service, u8 *props, size_t props_size);
int (*call)(afk_epic_service_t *service, u32 idx, const void *data, size_t data_size,
void *reply, size_t reply_size);
} afk_epic_service_ops_t;
afk_epic_t *afk_epic_init(rtkit_dev_t *rtkit);
int afk_epic_shutdown(afk_epic_t *afk);
afk_epic_ep_t *afk_epic_start_ep(afk_epic_t *afk, int endpoint, bool notify);
int afk_epic_shutdown_ep(afk_epic_ep_t *epic);
int afk_epic_start_channel(afk_epic_ep_t *epic, const afk_epic_service_ops_t *ops, void *intf,
const char *name);
int afk_epic_start_interface(afk_epic_ep_t *epic, const afk_epic_service_ops_t *ops, void *intf,
const char *name, size_t insize, size_t outsize);
int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 sub_seq, u16 code, void *txbuf,
size_t txsize, void *rxbuf, size_t *rxsize);
int afk_epic_report(afk_epic_ep_t *epic, int channel, u32 type, u16 sub_seq, void *payload,
size_t payload_size);
#endif

View file

@ -60,8 +60,15 @@ dcp_dev_t *dcp_init(const char *dcp_path, const char *dcp_dart_path, const char
goto out_iovad;
}
dcp->afk = afk_epic_init(dcp->rtkit);
if (!dcp->afk) {
printf("dcp: failed to initialize AFK\n");
goto out_rtkit;
}
return dcp;
out_rtkit:
rtkit_quiesce(dcp->rtkit);
rtkit_free(dcp->rtkit);
out_iovad:
@ -76,6 +83,7 @@ out_free:
int dcp_shutdown(dcp_dev_t *dcp, bool sleep)
{
afk_epic_shutdown(dcp->afk);
if (sleep) {
rtkit_sleep(dcp->rtkit);
pmgr_reset(0, "DISP0_CPU0");

View file

@ -3,16 +3,39 @@
#ifndef DCP_H
#define DCP_H
#include "afk.h"
#include "asc.h"
#include "dart.h"
#include "rtkit.h"
typedef struct dp_phy_configure_opts {
u32 link_rate;
u32 lanes;
bool set_rate;
bool set_lanes;
} dp_phy_configure_opts_t;
typedef struct dptx_phy dptx_phy_t;
typedef struct afk_epic_service afk_epic_service_t;
typedef struct dptx_port {
bool enabled;
u32 unit;
afk_epic_service_t *service;
dp_phy_configure_opts_t phy_opts;
dptx_phy_t *phy;
u32 link_rate, pending_link_rate;
} dptx_port_t;
typedef struct {
dart_dev_t *dart_dcp;
dart_dev_t *dart_disp;
iova_domain_t *iovad_dcp;
asc_dev_t *asc;
rtkit_dev_t *rtkit;
afk_epic_t *afk;
dptx_port_t *port;
} dcp_dev_t;
dcp_dev_t *dcp_init(const char *dcp_path, const char *dcp_dart_path, const char *disp_dart_path);

12
src/dcp/dp_phy.h Normal file
View file

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: MIT */
#ifndef DCP_DP_PHY_H
#define DCP_DP_PHY_H
typedef struct dptx_phy dptx_phy_t;
int dptx_phy_configure(dptx_phy_t *phy, int state);
dptx_phy_t *dptx_phy_init(const char *phy_path);
void dptx_phy_shutdown(dptx_phy_t *phy);
#endif /* DCP_DP_PHY_H */

529
src/dcp/dptx_phy.c Normal file
View file

@ -0,0 +1,529 @@
/* SPDX-License-Identifier: MIT */
#include "dp_phy.h"
#include "dptxep.h"
#include "malloc.h"
#include "../adt.h"
#include "../utils.h"
typedef struct dptx_phy {
u64 regs[2];
} dptx_phy_t;
static int dptx_phy_activate(dptx_phy_t *phy)
{
#if 1
// MMIO: R.4 0x23c500010 (dptx-phy[1], offset 0x10) = 0x0
read32(phy->regs[1] + 0x10);
// MMIO: W.4 0x23c500010 (dptx-phy[1], offset 0x10) = 0x0
write32(phy->regs[1] + 0x10, 0x0);
// MMIO: R.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x444
read32(phy->regs[1] + 0x48);
// MMIO: W.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x454
write32(phy->regs[1] + 0x48, 0x454);
// MMIO: R.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x454
read32(phy->regs[1] + 0x48);
// MMIO: W.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x474
write32(phy->regs[1] + 0x48, 0x474);
// MMIO: R.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x474
read32(phy->regs[1] + 0x48);
// MMIO: W.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x434
write32(phy->regs[1] + 0x48, 0x434);
// MMIO: R.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x434
read32(phy->regs[1] + 0x48);
// MMIO: W.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x534
write32(phy->regs[1] + 0x48, 0x534);
// MMIO: R.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x534
read32(phy->regs[1] + 0x48);
// MMIO: W.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x734
write32(phy->regs[1] + 0x48, 0x734);
// MMIO: R.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x734
read32(phy->regs[1] + 0x48);
// MMIO: W.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x334
write32(phy->regs[1] + 0x48, 0x334);
// MMIO: R.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x334
read32(phy->regs[1] + 0x48);
// MMIO: W.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x335
write32(phy->regs[1] + 0x48, 0x335);
// MMIO: R.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x335
read32(phy->regs[1] + 0x48);
// MMIO: W.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x337
write32(phy->regs[1] + 0x48, 0x337);
// MMIO: R.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x337
read32(phy->regs[1] + 0x48);
// MMIO: W.4 0x23c500048 (dptx-phy[1], offset 0x48) = 0x333
write32(phy->regs[1] + 0x48, 0x333);
// MMIO: R.4 0x23c542014 (dptx-phy[0], offset 0x2014) = 0x80a0c
read32(phy->regs[0] + 0x2014);
// MMIO: W.4 0x23c542014 (dptx-phy[0], offset 0x2014) = 0x300a0c
write32(phy->regs[0] + 0x2014, 0x300a0c);
// MMIO: R.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x644800
read32(phy->regs[0] + 0x20b8);
// MMIO: W.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x654800
write32(phy->regs[0] + 0x20b8, 0x654800);
// MMIO: R.4 0x23c542220 (dptx-phy[0], offset 0x2220) = 0x11090a2
read32(phy->regs[0] + 0x2220);
// MMIO: W.4 0x23c542220 (dptx-phy[0], offset 0x2220) = 0x11090a0
write32(phy->regs[0] + 0x2220, 0x11090a0);
// MMIO: R.4 0x23c54222c (dptx-phy[0], offset 0x222c) = 0x103003
read32(phy->regs[0] + 0x222c);
// MMIO: W.4 0x23c54222c (dptx-phy[0], offset 0x222c) = 0x103803
write32(phy->regs[0] + 0x222c, 0x103803);
// MMIO: R.4 0x23c54222c (dptx-phy[0], offset 0x222c) = 0x103803
read32(phy->regs[0] + 0x222c);
// MMIO: W.4 0x23c54222c (dptx-phy[0], offset 0x222c) = 0x103903
write32(phy->regs[0] + 0x222c, 0x103903);
// MMIO: R.4 0x23c542230 (dptx-phy[0], offset 0x2230) = 0x2308804
read32(phy->regs[0] + 0x2230);
// MMIO: W.4 0x23c542230 (dptx-phy[0], offset 0x2230) = 0x2208804
write32(phy->regs[0] + 0x2230, 0x2208804);
// MMIO: R.4 0x23c542278 (dptx-phy[0], offset 0x2278) = 0x18300811
read32(phy->regs[0] + 0x2278);
// MMIO: W.4 0x23c542278 (dptx-phy[0], offset 0x2278) = 0x10300811
write32(phy->regs[0] + 0x2278, 0x10300811);
// MMIO: R.4 0x23c5422a4 (dptx-phy[0], offset 0x22a4) = 0x1044200
read32(phy->regs[0] + 0x22a4);
// MMIO: W.4 0x23c5422a4 (dptx-phy[0], offset 0x22a4) = 0x1044201
write32(phy->regs[0] + 0x22a4, 0x1044201);
// MMIO: R.4 0x23c544008 (dptx-phy[0], offset 0x4008) = 0x18030
read32(phy->regs[0] + 0x4008);
// MMIO: W.4 0x23c544008 (dptx-phy[0], offset 0x4008) = 0x30030
write32(phy->regs[0] + 0x4008, 0x30030);
// MMIO: R.4 0x23c544008 (dptx-phy[0], offset 0x4008) = 0x30030
read32(phy->regs[0] + 0x4008);
// MMIO: W.4 0x23c544008 (dptx-phy[0], offset 0x4008) = 0x30010
write32(phy->regs[0] + 0x4008, 0x30010);
// MMIO: R.4 0x23c54420c (dptx-phy[0], offset 0x420c) = 0x88e3
read32(phy->regs[0] + 0x420c);
// MMIO: W.4 0x23c54420c (dptx-phy[0], offset 0x420c) = 0x88c3
write32(phy->regs[0] + 0x420c, 0x88c3);
// MMIO: R.4 0x23c544600 (dptx-phy[0], offset 0x4600) = 0x0
read32(phy->regs[0] + 0x4600);
// MMIO: W.4 0x23c544600 (dptx-phy[0], offset 0x4600) = 0x8000000
write32(phy->regs[0] + 0x4600, 0x8000000);
// MMIO: R.4 0x23c545040 (dptx-phy[0], offset 0x5040) = 0x21780
read32(phy->regs[0] + 0x5040);
// MMIO: W.4 0x23c545040 (dptx-phy[0], offset 0x5040) = 0x221780
write32(phy->regs[0] + 0x5040, 0x221780);
// MMIO: R.4 0x23c546040 (dptx-phy[0], offset 0x6040) = 0x21780
read32(phy->regs[0] + 0x6040);
// MMIO: W.4 0x23c546040 (dptx-phy[0], offset 0x6040) = 0x221780
write32(phy->regs[0] + 0x6040, 0x221780);
// MMIO: R.4 0x23c547040 (dptx-phy[0], offset 0x7040) = 0x21780
read32(phy->regs[0] + 0x7040);
// MMIO: W.4 0x23c547040 (dptx-phy[0], offset 0x7040) = 0x221780
write32(phy->regs[0] + 0x7040, 0x221780);
// MMIO: R.4 0x23c548040 (dptx-phy[0], offset 0x8040) = 0x21780
read32(phy->regs[0] + 0x8040);
// MMIO: W.4 0x23c548040 (dptx-phy[0], offset 0x8040) = 0x221780
write32(phy->regs[0] + 0x8040, 0x221780);
// MMIO: R.4 0x23c545040 (dptx-phy[0], offset 0x5040) = 0x221780
read32(phy->regs[0] + 0x5040);
// MMIO: W.4 0x23c545040 (dptx-phy[0], offset 0x5040) = 0x2a1780
write32(phy->regs[0] + 0x5040, 0x2a1780);
// MMIO: R.4 0x23c546040 (dptx-phy[0], offset 0x6040) = 0x221780
read32(phy->regs[0] + 0x6040);
// MMIO: W.4 0x23c546040 (dptx-phy[0], offset 0x6040) = 0x2a1780
write32(phy->regs[0] + 0x6040, 0x2a1780);
// MMIO: R.4 0x23c547040 (dptx-phy[0], offset 0x7040) = 0x221780
read32(phy->regs[0] + 0x7040);
// MMIO: W.4 0x23c547040 (dptx-phy[0], offset 0x7040) = 0x2a1780
write32(phy->regs[0] + 0x7040, 0x2a1780);
// MMIO: R.4 0x23c548040 (dptx-phy[0], offset 0x8040) = 0x221780
read32(phy->regs[0] + 0x8040);
// MMIO: W.4 0x23c548040 (dptx-phy[0], offset 0x8040) = 0x2a1780
write32(phy->regs[0] + 0x8040, 0x2a1780);
// MMIO: R.4 0x23c545244 (dptx-phy[0], offset 0x5244) = 0x18
read32(phy->regs[0] + 0x5244);
// MMIO: W.4 0x23c545244 (dptx-phy[0], offset 0x5244) = 0x8
write32(phy->regs[0] + 0x5244, 0x8);
// MMIO: R.4 0x23c546244 (dptx-phy[0], offset 0x6244) = 0x18
read32(phy->regs[0] + 0x6244);
// MMIO: W.4 0x23c546244 (dptx-phy[0], offset 0x6244) = 0x8
write32(phy->regs[0] + 0x6244, 0x8);
// MMIO: R.4 0x23c547244 (dptx-phy[0], offset 0x7244) = 0x18
read32(phy->regs[0] + 0x7244);
// MMIO: W.4 0x23c547244 (dptx-phy[0], offset 0x7244) = 0x8
write32(phy->regs[0] + 0x7244, 0x8);
// MMIO: R.4 0x23c548244 (dptx-phy[0], offset 0x8244) = 0x18
read32(phy->regs[0] + 0x8244);
// MMIO: W.4 0x23c548244 (dptx-phy[0], offset 0x8244) = 0x8
write32(phy->regs[0] + 0x8244, 0x8);
// MMIO: R.4 0x23c542214 (dptx-phy[0], offset 0x2214) = 0x1e0
read32(phy->regs[0] + 0x2214);
// MMIO: W.4 0x23c542214 (dptx-phy[0], offset 0x2214) = 0x1e1
write32(phy->regs[0] + 0x2214, 0x1e1);
// MMIO: R.4 0x23c542224 (dptx-phy[0], offset 0x2224) = 0x20086001
read32(phy->regs[0] + 0x2224);
// MMIO: W.4 0x23c542224 (dptx-phy[0], offset 0x2224) = 0x20086000
write32(phy->regs[0] + 0x2224, 0x20086000);
// MMIO: R.4 0x23c542200 (dptx-phy[0], offset 0x2200) = 0x2000
read32(phy->regs[0] + 0x2200);
// MMIO: W.4 0x23c542200 (dptx-phy[0], offset 0x2200) = 0x2002
write32(phy->regs[0] + 0x2200, 0x2002);
// MMIO: R.4 0x23c541000 (dptx-phy[0], offset 0x1000) = 0xe0000003
read32(phy->regs[0] + 0x1000);
// MMIO: W.4 0x23c541000 (dptx-phy[0], offset 0x1000) = 0xe0000001
write32(phy->regs[0] + 0x1000, 0xe0000001);
// MMIO: R.4 0x23c544004 (dptx-phy[0], offset 0x4004) = 0x41
read32(phy->regs[0] + 0x4004);
// MMIO: W.4 0x23c544004 (dptx-phy[0], offset 0x4004) = 0x49
write32(phy->regs[0] + 0x4004, 0x49);
// MMIO: R.4 0x23c544404 (dptx-phy[0], offset 0x4404) = 0x555d444
read32(phy->regs[0] + 0x4404);
// MMIO: W.4 0x23c544404 (dptx-phy[0], offset 0x4404) = 0x555d444
write32(phy->regs[0] + 0x4404, 0x555d444);
// MMIO: R.4 0x23c544404 (dptx-phy[0], offset 0x4404) = 0x555d444
read32(phy->regs[0] + 0x4404);
// MMIO: W.4 0x23c544404 (dptx-phy[0], offset 0x4404) = 0x555d444
write32(phy->regs[0] + 0x4404, 0x555d444);
// MMIO: R.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x41021ac
read32(phy->regs[0] + 0x4000);
// MMIO: W.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x41021ac
write32(phy->regs[0] + 0x4000, 0x41021ac);
// MMIO: R.4 0x23c545000 (dptx-phy[0], offset 0x5000) = 0x300
read32(phy->regs[0] + 0x5000);
// MMIO: W.4 0x23c545000 (dptx-phy[0], offset 0x5000) = 0x300
write32(phy->regs[0] + 0x5000, 0x300);
// MMIO: R.4 0x23c546000 (dptx-phy[0], offset 0x6000) = 0x300
read32(phy->regs[0] + 0x6000);
// MMIO: W.4 0x23c546000 (dptx-phy[0], offset 0x6000) = 0x300
write32(phy->regs[0] + 0x6000, 0x300);
// MMIO: R.4 0x23c547000 (dptx-phy[0], offset 0x7000) = 0x300
read32(phy->regs[0] + 0x7000);
// MMIO: W.4 0x23c547000 (dptx-phy[0], offset 0x7000) = 0x300
write32(phy->regs[0] + 0x7000, 0x300);
// MMIO: R.4 0x23c548000 (dptx-phy[0], offset 0x8000) = 0x300
read32(phy->regs[0] + 0x8000);
// MMIO: W.4 0x23c548000 (dptx-phy[0], offset 0x8000) = 0x300
write32(phy->regs[0] + 0x8000, 0x300);
// MMIO: R.4 0x23c545000 (dptx-phy[0], offset 0x5000) = 0x300
read32(phy->regs[0] + 0x5000);
// MMIO: W.4 0x23c545000 (dptx-phy[0], offset 0x5000) = 0x300
write32(phy->regs[0] + 0x5000, 0x300);
// MMIO: R.4 0x23c546000 (dptx-phy[0], offset 0x6000) = 0x300
read32(phy->regs[0] + 0x6000);
// MMIO: W.4 0x23c546000 (dptx-phy[0], offset 0x6000) = 0x300
write32(phy->regs[0] + 0x6000, 0x300);
// MMIO: R.4 0x23c547000 (dptx-phy[0], offset 0x7000) = 0x300
read32(phy->regs[0] + 0x7000);
// MMIO: W.4 0x23c547000 (dptx-phy[0], offset 0x7000) = 0x300
write32(phy->regs[0] + 0x7000, 0x300);
// MMIO: R.4 0x23c548000 (dptx-phy[0], offset 0x8000) = 0x300
read32(phy->regs[0] + 0x8000);
// MMIO: W.4 0x23c548000 (dptx-phy[0], offset 0x8000) = 0x300
write32(phy->regs[0] + 0x8000, 0x300);
// MMIO: R.4 0x23c544200 (dptx-phy[0], offset 0x4200) = 0x4002430
read32(phy->regs[0] + 0x4200);
// MMIO: W.4 0x23c544200 (dptx-phy[0], offset 0x4200) = 0x4002420
write32(phy->regs[0] + 0x4200, 0x4002420);
// MMIO: R.4 0x23c544600 (dptx-phy[0], offset 0x4600) = 0x8000000
read32(phy->regs[0] + 0x4600);
// MMIO: W.4 0x23c544600 (dptx-phy[0], offset 0x4600) = 0x8000000
write32(phy->regs[0] + 0x4600, 0x8000000);
// MMIO: R.4 0x23c544600 (dptx-phy[0], offset 0x4600) = 0x8000000
read32(phy->regs[0] + 0x4600);
// MMIO: W.4 0x23c544600 (dptx-phy[0], offset 0x4600) = 0x8000001
write32(phy->regs[0] + 0x4600, 0x8000001);
// MMIO: R.4 0x23c544600 (dptx-phy[0], offset 0x4600) = 0x8000001
read32(phy->regs[0] + 0x4600);
// MMIO: W.4 0x23c544600 (dptx-phy[0], offset 0x4600) = 0x8000003
write32(phy->regs[0] + 0x4600, 0x8000003);
// MMIO: R.4 0x23c544600 (dptx-phy[0], offset 0x4600) = 0x8000043
read32(phy->regs[0] + 0x4600);
// MMIO: R.4 0x23c544600 (dptx-phy[0], offset 0x4600) = 0x8000043
read32(phy->regs[0] + 0x4600);
// MMIO: W.4 0x23c544600 (dptx-phy[0], offset 0x4600) = 0x8000041
write32(phy->regs[0] + 0x4600, 0x8000041);
// MMIO: R.4 0x23c544408 (dptx-phy[0], offset 0x4408) = 0x482
read32(phy->regs[0] + 0x4408);
// MMIO: W.4 0x23c544408 (dptx-phy[0], offset 0x4408) = 0x482
write32(phy->regs[0] + 0x4408, 0x482);
// MMIO: R.4 0x23c544408 (dptx-phy[0], offset 0x4408) = 0x482
read32(phy->regs[0] + 0x4408);
// MMIO: W.4 0x23c544408 (dptx-phy[0], offset 0x4408) = 0x483
write32(phy->regs[0] + 0x4408, 0x483);
#endif
return 0;
}
static int dptx_phy_set_active_lane_count(dptx_phy_t *phy)
{
// MMIO: R.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x41021ac
read32(phy->regs[0] + 0x4000);
// <ep:27 0085000000000000 ()
// MMIO: W.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x41021ac
write32(phy->regs[0] + 0x4000, 0x41021ac);
// MMIO: R.4 0x23c545000 (dptx-phy[0], offset 0x5000) = 0x300
read32(phy->regs[0] + 0x5000);
// MMIO: W.4 0x23c545000 (dptx-phy[0], offset 0x5000) = 0x300
write32(phy->regs[0] + 0x5000, 0x300);
// MMIO: R.4 0x23c546000 (dptx-phy[0], offset 0x6000) = 0x300
read32(phy->regs[0] + 0x6000);
// MMIO: W.4 0x23c546000 (dptx-phy[0], offset 0x6000) = 0x300
write32(phy->regs[0] + 0x6000, 0x300);
// MMIO: R.4 0x23c547000 (dptx-phy[0], offset 0x7000) = 0x300
read32(phy->regs[0] + 0x7000);
// MMIO: W.4 0x23c547000 (dptx-phy[0], offset 0x7000) = 0x300
write32(phy->regs[0] + 0x7000, 0x300);
// MMIO: R.4 0x23c548000 (dptx-phy[0], offset 0x8000) = 0x300
read32(phy->regs[0] + 0x8000);
// MMIO: W.4 0x23c548000 (dptx-phy[0], offset 0x8000) = 0x300
write32(phy->regs[0] + 0x8000, 0x300);
// MMIO: R.4 0x23c545000 (dptx-phy[0], offset 0x5000) = 0x300
read32(phy->regs[0] + 0x5000);
// MMIO: W.4 0x23c545000 (dptx-phy[0], offset 0x5000) = 0x300
write32(phy->regs[0] + 0x5000, 0x300);
// >ep:28 00a2000000000280 ()
// MMIO: R.4 0x23c546000 (dptx-phy[0], offset 0x6000) = 0x300
read32(phy->regs[0] + 0x6000);
// <ep:28 0085000000000000 ()
// MMIO: W.4 0x23c546000 (dptx-phy[0], offset 0x6000) = 0x300
write32(phy->regs[0] + 0x6000, 0x300);
// MMIO: R.4 0x23c547000 (dptx-phy[0], offset 0x7000) = 0x300
read32(phy->regs[0] + 0x7000);
// MMIO: W.4 0x23c547000 (dptx-phy[0], offset 0x7000) = 0x300
write32(phy->regs[0] + 0x7000, 0x300);
// MMIO: R.4 0x23c548000 (dptx-phy[0], offset 0x8000) = 0x300
read32(phy->regs[0] + 0x8000);
// MMIO: W.4 0x23c548000 (dptx-phy[0], offset 0x8000) = 0x300
write32(phy->regs[0] + 0x8000, 0x300);
return 0;
}
static int dptx_phy_set_link_rate(dptx_phy_t *phy)
{
// MMIO: R.4 0x23c544004 (dptx-phy[0], offset 0x4004) = 0x49
read32(phy->regs[0] + 0x4004);
// MMIO: W.4 0x23c544004 (dptx-phy[0], offset 0x4004) = 0x49
write32(phy->regs[0] + 0x4004, 0x49);
// MMIO: R.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x41021ac
read32(phy->regs[0] + 0x4000);
// MMIO: W.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x41021ac
write32(phy->regs[0] + 0x4000, 0x41021ac);
// MMIO: R.4 0x23c544004 (dptx-phy[0], offset 0x4004) = 0x49
read32(phy->regs[0] + 0x4004);
// MMIO: W.4 0x23c544004 (dptx-phy[0], offset 0x4004) = 0x41
write32(phy->regs[0] + 0x4004, 0x41);
// MMIO: R.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x41021ac
read32(phy->regs[0] + 0x4000);
// >ep:27 00a2000000000300 ()
// MMIO: W.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x41021ac
write32(phy->regs[0] + 0x4000, 0x41021ac);
// <ep:27 0085000000000000 ()
// MMIO: R.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x41021ac
read32(phy->regs[0] + 0x4000);
// MMIO: W.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x41021ac
write32(phy->regs[0] + 0x4000, 0x41021ac);
// MMIO: R.4 0x23c542200 (dptx-phy[0], offset 0x2200) = 0x2002
read32(phy->regs[0] + 0x2200);
// MMIO: R.4 0x23c542200 (dptx-phy[0], offset 0x2200) = 0x2002
read32(phy->regs[0] + 0x2200);
// MMIO: W.4 0x23c542200 (dptx-phy[0], offset 0x2200) = 0x2000
write32(phy->regs[0] + 0x2200, 0x2000);
// MMIO: R.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf000
read32(phy->regs[0] + 0x100c);
// MMIO: W.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf000
write32(phy->regs[0] + 0x100c, 0xf000);
// MMIO: R.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf000
read32(phy->regs[0] + 0x100c);
// MMIO: W.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf008
write32(phy->regs[0] + 0x100c, 0xf008);
// MMIO: R.4 0x23c541014 (dptx-phy[0], offset 0x1014) = 0x1
read32(phy->regs[0] + 0x1014);
// MMIO: R.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf008
read32(phy->regs[0] + 0x100c);
// MMIO: W.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf000
write32(phy->regs[0] + 0x100c, 0xf000);
// MMIO: R.4 0x23c541008 (dptx-phy[0], offset 0x1008) = 0x1
read32(phy->regs[0] + 0x1008);
// MMIO: R.4 0x23c542220 (dptx-phy[0], offset 0x2220) = 0x11090a0
read32(phy->regs[0] + 0x2220);
// MMIO: W.4 0x23c542220 (dptx-phy[0], offset 0x2220) = 0x1109020
write32(phy->regs[0] + 0x2220, 0x1109020);
// MMIO: R.4 0x23c5420b0 (dptx-phy[0], offset 0x20b0) = 0x1e0e01c2
read32(phy->regs[0] + 0x20b0);
// MMIO: W.4 0x23c5420b0 (dptx-phy[0], offset 0x20b0) = 0x1e0e01c2
write32(phy->regs[0] + 0x20b0, 0x1e0e01c2);
// MMIO: R.4 0x23c5420b4 (dptx-phy[0], offset 0x20b4) = 0x7fffffe
read32(phy->regs[0] + 0x20b4);
// MMIO: W.4 0x23c5420b4 (dptx-phy[0], offset 0x20b4) = 0x7fffffe
write32(phy->regs[0] + 0x20b4, 0x7fffffe);
// MMIO: R.4 0x23c5420b4 (dptx-phy[0], offset 0x20b4) = 0x7fffffe
read32(phy->regs[0] + 0x20b4);
// MMIO: W.4 0x23c5420b4 (dptx-phy[0], offset 0x20b4) = 0x7fffffe
write32(phy->regs[0] + 0x20b4, 0x7fffffe);
// MMIO: R.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x654800
read32(phy->regs[0] + 0x20b8);
// MMIO: W.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x654800
write32(phy->regs[0] + 0x20b8, 0x654800);
// MMIO: R.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x654800
read32(phy->regs[0] + 0x20b8);
// MMIO: W.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x654800
write32(phy->regs[0] + 0x20b8, 0x654800);
// MMIO: R.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x654800
read32(phy->regs[0] + 0x20b8);
// MMIO: W.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x654800
write32(phy->regs[0] + 0x20b8, 0x654800);
// MMIO: R.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x654800
read32(phy->regs[0] + 0x20b8);
// MMIO: W.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x454800
write32(phy->regs[0] + 0x20b8, 0x454800);
// MMIO: R.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x454800
read32(phy->regs[0] + 0x20b8);
// MMIO: W.4 0x23c5420b8 (dptx-phy[0], offset 0x20b8) = 0x454800
write32(phy->regs[0] + 0x20b8, 0x454800);
// MMIO: R.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0x0
read32(phy->regs[1] + 0xa0);
// MMIO: W.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0x8
write32(phy->regs[1] + 0xa0, 0x8);
// MMIO: R.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0x8
read32(phy->regs[1] + 0xa0);
// MMIO: W.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0xc
write32(phy->regs[1] + 0xa0, 0xc);
// MMIO: R.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0xc
read32(phy->regs[1] + 0xa0);
// MMIO: W.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0x4000c
write32(phy->regs[1] + 0xa0, 0x4000c);
// MMIO: R.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0x4000c
read32(phy->regs[1] + 0xa0);
// MMIO: W.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0xc
write32(phy->regs[1] + 0xa0, 0xc);
// MMIO: R.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0xc
read32(phy->regs[1] + 0xa0);
// MMIO: W.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0x8000c
write32(phy->regs[1] + 0xa0, 0x8000c);
// MMIO: R.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0x8000c
read32(phy->regs[1] + 0xa0);
// MMIO: W.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0xc
write32(phy->regs[1] + 0xa0, 0xc);
// MMIO: R.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0xc
read32(phy->regs[1] + 0xa0);
// MMIO: W.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0x8
write32(phy->regs[1] + 0xa0, 0x8);
// MMIO: R.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0x8
read32(phy->regs[1] + 0xa0);
// MMIO: W.4 0x23c5000a0 (dptx-phy[1], offset 0xa0) = 0x0
write32(phy->regs[1] + 0xa0, 0x0);
// MMIO: R.4 0x23c542000 (dptx-phy[0], offset 0x2000) = 0x2
read32(phy->regs[0] + 0x2000);
// MMIO: W.4 0x23c542000 (dptx-phy[0], offset 0x2000) = 0x2
write32(phy->regs[0] + 0x2000, 0x2);
// MMIO: R.4 0x23c542018 (dptx-phy[0], offset 0x2018) = 0x0
read32(phy->regs[0] + 0x2018);
// MMIO: W.4 0x23c542018 (dptx-phy[0], offset 0x2018) = 0x0
write32(phy->regs[0] + 0x2018, 0x0);
// MMIO: R.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf000
read32(phy->regs[0] + 0x100c);
// MMIO: W.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf007
write32(phy->regs[0] + 0x100c, 0xf007);
// MMIO: R.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf007
read32(phy->regs[0] + 0x100c);
// MMIO: W.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf00f
write32(phy->regs[0] + 0x100c, 0xf00f);
// MMIO: R.4 0x23c541014 (dptx-phy[0], offset 0x1014) = 0x38f
read32(phy->regs[0] + 0x1014);
// MMIO: R.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf00f
read32(phy->regs[0] + 0x100c);
// MMIO: W.4 0x23c54100c (dptx-phy[0], offset 0x100c) = 0xf007
write32(phy->regs[0] + 0x100c, 0xf007);
// MMIO: R.4 0x23c541008 (dptx-phy[0], offset 0x1008) = 0x9
read32(phy->regs[0] + 0x1008);
// MMIO: R.4 0x23c542200 (dptx-phy[0], offset 0x2200) = 0x2000
read32(phy->regs[0] + 0x2200);
// MMIO: W.4 0x23c542200 (dptx-phy[0], offset 0x2200) = 0x2002
write32(phy->regs[0] + 0x2200, 0x2002);
// MMIO: R.4 0x23c545010 (dptx-phy[0], offset 0x5010) = 0x18003000
read32(phy->regs[0] + 0x5010);
// MMIO: W.4 0x23c545010 (dptx-phy[0], offset 0x5010) = 0x18003000
write32(phy->regs[0] + 0x5010, 0x18003000);
// MMIO: R.4 0x23c546010 (dptx-phy[0], offset 0x6010) = 0x18003000
read32(phy->regs[0] + 0x6010);
// MMIO: W.4 0x23c546010 (dptx-phy[0], offset 0x6010) = 0x18003000
write32(phy->regs[0] + 0x6010, 0x18003000);
// MMIO: R.4 0x23c547010 (dptx-phy[0], offset 0x7010) = 0x18003000
read32(phy->regs[0] + 0x7010);
// MMIO: W.4 0x23c547010 (dptx-phy[0], offset 0x7010) = 0x18003000
write32(phy->regs[0] + 0x7010, 0x18003000);
// MMIO: R.4 0x23c548010 (dptx-phy[0], offset 0x8010) = 0x18003000
read32(phy->regs[0] + 0x8010);
// MMIO: W.4 0x23c548010 (dptx-phy[0], offset 0x8010) = 0x18003000
write32(phy->regs[0] + 0x8010, 0x18003000);
// MMIO: R.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x41021ac
read32(phy->regs[0] + 0x4000);
// MMIO: W.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x51021ac
write32(phy->regs[0] + 0x4000, 0x51021ac);
// MMIO: R.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x51021ac
read32(phy->regs[0] + 0x4000);
// MMIO: W.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x71021ac
write32(phy->regs[0] + 0x4000, 0x71021ac);
// MMIO: R.4 0x23c544004 (dptx-phy[0], offset 0x4004) = 0x41
read32(phy->regs[0] + 0x4004);
// MMIO: W.4 0x23c544004 (dptx-phy[0], offset 0x4004) = 0x49
write32(phy->regs[0] + 0x4004, 0x49);
// MMIO: R.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x71021ac
read32(phy->regs[0] + 0x4000);
// MMIO: W.4 0x23c544000 (dptx-phy[0], offset 0x4000) = 0x71021ec
write32(phy->regs[0] + 0x4000, 0x71021ec);
// MMIO: R.4 0x23c544004 (dptx-phy[0], offset 0x4004) = 0x49
read32(phy->regs[0] + 0x4004);
// MMIO: W.4 0x23c544004 (dptx-phy[0], offset 0x4004) = 0x48
write32(phy->regs[0] + 0x4004, 0x48);
return 0;
}
int dptx_phy_configure(dptx_phy_t *phy, int state)
{
switch (state) {
case DPTX_APCALL_ACTIVATE:
return dptx_phy_activate(phy);
case DPTX_APCALL_SET_ACTIVE_LANE_COUNT:
return dptx_phy_set_active_lane_count(phy);
case DPTX_APCALL_SET_LINK_RATE:
return dptx_phy_set_link_rate(phy);
default:
printf("DPtx-phy: ignore unkown state:%d\n", state);
return 0;
}
}
dptx_phy_t *dptx_phy_init(const char *phy_node)
{
int adt_phy_path[8];
int node = adt_path_offset_trace(adt, phy_node, adt_phy_path);
if (node < 0) {
printf("DPtx-phy: Error getting phy node %s\n", phy_node);
return NULL;
}
dptx_phy_t *phy = calloc(sizeof *phy, 1);
if (!phy)
return NULL;
if (adt_get_reg(adt, adt_phy_path, "reg", 0, &phy->regs[0], NULL) < 0) {
printf("DPtx-phy: failed to get %s.reg[0]\n", phy_node);
goto out_err;
}
if (adt_get_reg(adt, adt_phy_path, "reg", 1, &phy->regs[1], NULL) < 0) {
printf("DPtx-phy: failed to get %s.reg[1]\n", phy_node);
goto out_err;
}
return phy;
out_err:
free(phy);
return NULL;
}
void dptx_phy_shutdown(dptx_phy_t *phy)
{
free(phy);
}

554
src/dcp/dptxep.c Normal file
View file

@ -0,0 +1,554 @@
// SPDX-License-Identifier: GPL-2.0-only OR MIT
/* Copyright 2022 Sven Peter <sven@svenpeter.dev> */
#include <stdbool.h>
#include <string.h>
#include "dptxep.h"
#include "dp_phy.h"
#include "malloc.h"
#include "parser.h"
#include "../afk.h"
#include "../dcp.h"
#include "../types.h"
#include "../utils.h"
#define DCP_DPTX_ENDPOINT 0x2a
#define TXBUF_LEN 0x4000
#define RXBUF_LEN 0x4000
struct dcpdptx_connection_cmd {
u32 unk;
u32 target;
} __attribute__((packed));
struct dcpdptx_hotplug_cmd {
u8 _pad0[16];
u32 unk;
} __attribute__((packed));
struct dptxport_apcall_link_rate {
u32 retcode;
u8 _unk0[12];
u32 link_rate;
u8 _unk1[12];
} __attribute__((packed));
struct dptxport_apcall_get_support {
u32 retcode;
u8 _unk0[12];
u32 supported;
u8 _unk1[12];
} __attribute__((packed));
struct dptxport_apcall_max_drive_settings {
u32 retcode;
u8 _unk0[12];
u32 max_drive_settings[2];
u8 _unk1[8];
};
struct dptxport_apcall_set_tiled {
u32 retcode;
};
struct epic_service_call {
u8 _pad0[2];
u16 group;
u32 command;
u32 data_len;
#define EPIC_SERVICE_CALL_MAGIC 0x69706378
u32 magic;
u8 _pad1[48];
} __attribute__((packed));
typedef struct dcp_dptx_if {
afk_epic_ep_t *epic; // ensure an afk_epic_ep_t pointer can be used as dcp_dptx_if_t
dcp_dev_t *dcp;
dptx_phy_t *phy;
int channel;
struct dptx_port port[2];
} dcp_dptx_if_t;
static int afk_service_call(afk_epic_service_t *service, u16 group, u32 command, const void *data,
size_t data_len, size_t data_pad, void *output, size_t output_len,
size_t output_pad)
{
struct epic_service_call *call;
void *bfr;
size_t bfr_len = max(data_len + data_pad, output_len + output_pad) + sizeof(*call);
int ret;
u32 retlen;
size_t rx_len = bfr_len;
bfr = calloc(bfr_len, 1);
if (!bfr)
return -1;
call = bfr;
call->group = group;
call->command = command;
call->data_len = data_len + data_pad;
call->magic = EPIC_SERVICE_CALL_MAGIC;
memcpy(bfr + sizeof(*call), data, data_len);
ret = afk_epic_command(service->epic, service->channel, service->seq++, CODE_STD_SERVICE, bfr,
bfr_len, bfr, &rx_len);
if (ret)
goto out;
if (call->magic != EPIC_SERVICE_CALL_MAGIC || call->group != group ||
call->command != command) {
ret = -1;
goto out;
}
retlen = call->data_len;
if (output_len < retlen)
retlen = output_len;
if (output && output_len) {
memset(output, 0, output_len);
memcpy(output, bfr + sizeof(*call), retlen);
}
out:
free(bfr);
return ret;
}
int dptxport_validate_connection(afk_epic_service_t *service, u8 core, u8 atc, u8 die)
{
dptx_port_t *dptx = service->cookie;
struct dcpdptx_connection_cmd cmd, resp;
int ret;
u32 target = FIELD_PREP(DCPDPTX_REMOTE_PORT_CORE, core) |
FIELD_PREP(DCPDPTX_REMOTE_PORT_DFP, atc) |
FIELD_PREP(DCPDPTX_REMOTE_PORT_DIE, die) | DCPDPTX_REMOTE_PORT_CONNECTED;
cmd.target = target;
cmd.unk = 0x100;
ret = afk_service_call(service, 0, 14, &cmd, sizeof(cmd), 40, &resp, sizeof(resp), 40);
if (ret)
return ret;
if (resp.target != target)
return -1;
if (resp.unk != 0x100)
return -1;
return 0;
}
int dptxport_connect(afk_epic_service_t *service, u8 core, u8 atc, u8 die)
{
dptx_port_t *dptx = service->cookie;
struct dcpdptx_connection_cmd cmd = {0}, resp = {0};
int ret;
u32 target = FIELD_PREP(DCPDPTX_REMOTE_PORT_CORE, core) |
FIELD_PREP(DCPDPTX_REMOTE_PORT_DFP, atc) |
FIELD_PREP(DCPDPTX_REMOTE_PORT_DIE, die) | DCPDPTX_REMOTE_PORT_CONNECTED;
cmd.target = target;
// cmd.unk = 0x100;
ret = afk_service_call(service, 0, 13, &cmd, sizeof(cmd), 24, &resp, sizeof(resp), 24);
if (ret)
return ret;
if (resp.target != target)
return -1;
if (resp.unk != 0x100)
return -1;
return 0;
}
int dptxport_request_display(afk_epic_service_t *service)
{
return afk_service_call(service, 0, 8, NULL, 0, 16, NULL, 0, 16);
}
int dptxport_release_display(afk_epic_service_t *service)
{
return afk_service_call(service, 0, 9, NULL, 0, 16, NULL, 0, 16);
}
int dptxport_set_hpd(afk_epic_service_t *service, bool hpd)
{
struct dcpdptx_hotplug_cmd cmd, resp;
int ret;
memset(&cmd, 0, sizeof(cmd));
if (hpd)
cmd.unk = 1;
ret = afk_service_call(service, 8, 10, &cmd, sizeof(cmd), 12, &resp, sizeof(resp), 12);
if (ret)
return ret;
if (resp.unk != 1)
return -1;
return 0;
}
static int dptxport_call_get_max_drive_settings(afk_epic_service_t *service, void *reply_,
size_t reply_size)
{
struct dptxport_apcall_max_drive_settings *reply = reply_;
if (reply_size < sizeof(*reply))
return -1;
reply->retcode = 0;
reply->max_drive_settings[0] = 0x3;
reply->max_drive_settings[1] = 0x3;
return 0;
}
static int dptxport_call_get_max_link_rate(afk_epic_service_t *service, void *reply_,
size_t reply_size)
{
struct dptxport_apcall_link_rate *reply = reply_;
if (reply_size < sizeof(*reply))
return -1;
reply->retcode = 0;
reply->link_rate = LINK_RATE_HBR3;
return 0;
}
static int dptxport_call_get_link_rate(afk_epic_service_t *service, void *reply_, size_t reply_size)
{
dptx_port_t *dptx = service->cookie;
struct dptxport_apcall_link_rate *reply = reply_;
if (reply_size < sizeof(*reply))
return -1;
reply->retcode = 0;
reply->link_rate = dptx->link_rate;
return 0;
}
static int dptxport_call_will_change_link_config(afk_epic_service_t *service)
{
dptx_port_t *dptx = service->cookie;
dptx->phy_opts.set_lanes = 0;
dptx->phy_opts.set_rate = 0;
return 0;
}
static int dptxport_call_did_change_link_config(afk_epic_service_t *service)
{
// struct dptx_port *dptx = service->cookie;
// int ret = 0;
mdelay(1000);
// dispext0,0 -> atcph1,dpphy
// mux_control_select(dptx->mux, 0);
return 0;
}
static int dptxport_call_set_link_rate(afk_epic_service_t *service, const void *data,
size_t data_size, void *reply_, size_t reply_size)
{
dptx_port_t *dptx = service->cookie;
const struct dptxport_apcall_link_rate *request = data;
struct dptxport_apcall_link_rate *reply = reply_;
u32 link_rate, phy_link_rate;
bool phy_set_rate = false;
int ret;
if (reply_size < sizeof(*reply))
return -1;
if (data_size < sizeof(*request))
return -1;
link_rate = request->link_rate;
switch (link_rate) {
case LINK_RATE_RBR:
phy_link_rate = 1620;
phy_set_rate = true;
break;
case LINK_RATE_HBR:
phy_link_rate = 2700;
phy_set_rate = true;
break;
case LINK_RATE_HBR2:
phy_link_rate = 5400;
phy_set_rate = true;
break;
case LINK_RATE_HBR3:
phy_link_rate = 8100;
phy_set_rate = true;
break;
case 0:
phy_link_rate = 0;
phy_set_rate = true;
break;
default:
printf("DPTXPort: Unsupported link rate 0x%x requested\n", link_rate);
link_rate = 0;
phy_set_rate = false;
break;
}
if (phy_set_rate) {
dptx->phy_opts.link_rate = phy_link_rate;
dptx->phy_opts.set_rate = 1;
if (dptx->phy) {
ret = 0; // phy_configure(dptx->atcphy, &dptx->phy_ops);
if (ret)
return ret;
}
// if (dptx->phy_ops.dp.set_rate)
dptx->link_rate = dptx->pending_link_rate = link_rate;
}
// dptx->pending_link_rate = link_rate;
reply->retcode = 0;
reply->link_rate = link_rate;
return 0;
}
static int dptxport_call_get_supports_hpd(afk_epic_service_t *service, void *reply_,
size_t reply_size)
{
struct dptxport_apcall_get_support *reply = reply_;
if (reply_size < sizeof(*reply))
return -1;
reply->retcode = 0;
reply->supported = 0;
return 0;
}
static int dptxport_call_get_supports_downspread(afk_epic_service_t *service, void *reply_,
size_t reply_size)
{
struct dptxport_apcall_get_support *reply = reply_;
if (reply_size < sizeof(*reply))
return -1;
reply->retcode = 0;
reply->supported = 0;
return 0;
}
static int dptxport_call_set_tiled_display_hint(afk_epic_service_t *service, void *reply_,
size_t reply_size)
{
struct dptxport_apcall_set_tiled *reply = reply_;
if (reply_size < sizeof(*reply))
return -1;
reply->retcode = 1;
return 0;
}
static int dptxport_call(afk_epic_service_t *service, u32 idx, const void *data, size_t data_size,
void *reply, size_t reply_size)
{
dcp_dptx_if_t *dptx = service->intf;
if (dptx->phy)
dptx_phy_configure(dptx->phy, idx);
switch (idx) {
case DPTX_APCALL_WILL_CHANGE_LINKG_CONFIG:
return dptxport_call_will_change_link_config(service);
case DPTX_APCALL_DID_CHANGE_LINK_CONFIG:
return dptxport_call_did_change_link_config(service);
case DPTX_APCALL_GET_MAX_LINK_RATE:
return dptxport_call_get_max_link_rate(service, reply, reply_size);
case DPTX_APCALL_GET_LINK_RATE:
return dptxport_call_get_link_rate(service, reply, reply_size);
case DPTX_APCALL_SET_LINK_RATE:
return dptxport_call_set_link_rate(service, data, data_size, reply, reply_size);
case DPTX_APCALL_GET_SUPPORTS_HPD:
return dptxport_call_get_supports_hpd(service, reply, reply_size);
case DPTX_APCALL_GET_SUPPORTS_DOWN_SPREAD:
return dptxport_call_get_supports_downspread(service, reply, reply_size);
case DPTX_APCALL_GET_MAX_DRIVE_SETTINGS:
return dptxport_call_get_max_drive_settings(service, reply, reply_size);
case DPTX_APCALL_SET_TILED_DISPLAY_HINTS:
memcpy(reply, data, min(reply_size, data_size));
return dptxport_call_set_tiled_display_hint(service, reply, reply_size);
default:
/* just try to ACK and hope for the best... */
printf("DPTXPort: unhandled call %d\n", idx);
// fallthrough
/* we can silently ignore and just ACK these calls */
case DPTX_APCALL_ACTIVATE:
case DPTX_APCALL_DEACTIVATE:
case DPTX_APCALL_SET_DRIVE_SETTINGS:
case DPTX_APCALL_GET_DRIVE_SETTINGS:
case DPTX_APCALL_SET_ACTIVE_LANE_COUNT:
memcpy(reply, data, min(reply_size, data_size));
if (reply_size > 4)
memset(reply, 0, 4);
return 0;
}
}
static bool dptxport_init(afk_epic_service_t *service, u8 *props, size_t props_size)
{
s64 unit;
const char *name = NULL, *class = NULL;
struct dcp_parse_ctx ctx;
dcp_dptx_if_t *dptx = (dcp_dptx_if_t *)service->epic;
int ret;
dptx = service->intf;
ret = parse(props, props_size, &ctx);
if (ret) {
printf("DPTXPort: failed to parse init props: %d\n", ret);
return false;
}
ret = parse_epic_service_init(&ctx, &name, &class, &unit);
if (ret) {
printf("DPTXPort: failed to extract init props: %d\n", ret);
return false;
}
printf("DPTXPort: parsed: name:'%s' class:'%s' unit:'%ld'\n", name, class, unit);
if (strcmp(name, "dcpdptx-port-epic"))
goto free;
if (strcmp(class, "AppleDCPDPTXRemotePort"))
goto free;
free((void *)name);
free((void *)class);
switch (unit) {
case 0:
case 1:
if (dptx->port[unit].enabled) {
printf("DPTXPort: unit %ld already exists\n", unit);
return false;
}
dptx->port[unit].unit = unit;
dptx->port[unit].service = service;
dptx->port[unit].enabled = true;
service->cookie = (void *)&dptx->port[unit];
printf("%s:%d port %ld enabled service:%p\n", __func__, __LINE__, unit, service);
break;
default:
printf("DPTXPort: invalid unit %ld\n", unit);
return false;
}
return true;
free:
free((void *)name);
free((void *)class);
return false;
}
static const afk_epic_service_ops_t dcp_dptx_ops = {
.name = "AppleDCPDPTXRemotePort",
.init = dptxport_init,
.call = dptxport_call,
};
int dcp_dptx_connect(dcp_dptx_if_t *dptx, dptx_phy_t *phy, u32 port)
{
if (!dptx->port[port].service)
return -1;
dptx->phy = phy;
// dptx->port[port].atcphy = phy;
// dptxport_validate_connection(dptx->port[port].service, 0, 5, 0);
dptxport_connect(dptx->port[port].service, 0, 5, 0);
dptxport_request_display(dptx->port[port].service);
return 0;
}
int dcp_dptx_hpd(dcp_dptx_if_t *dptx, u32 port, bool hpd)
{
if (!dptx->port[port].service)
return -1;
dptxport_set_hpd(dptx->port[port].service, hpd);
return 0;
}
int dcp_dptx_disconnect(dcp_dptx_if_t *dptx, u32 port)
{
dptxport_release_display(dptx->port[port].service);
dptxport_set_hpd(dptx->port[port].service, false);
return 0;
}
dcp_dptx_if_t *dcp_dptx_init(dcp_dev_t *dcp)
{
int channel;
dcp_dptx_if_t *dptx = malloc(sizeof(dcp_dptx_if_t));
if (!dptx)
return NULL;
dptx->dcp = dcp;
dptx->epic = afk_epic_start_ep(dcp->afk, DCP_DPTX_ENDPOINT, true);
if (!dptx->epic) {
printf("dcp-dptx: failed to initialize EPIC\n");
goto err_free;
}
channel = afk_epic_start_interface(dptx->epic, &dcp_dptx_ops, dptx,
"dispext4294967295:dcpdptx-port-", TXBUF_LEN, RXBUF_LEN);
if (channel < 0) {
printf("dcp-dptx: failed to initialize DPTXRemotePort service\n");
goto err_shutdown;
}
channel =
afk_epic_start_channel(dptx->epic, &dcp_dptx_ops, dptx, "dispext4294967295:dcpdptx-port-");
if (channel < 0) {
printf("dcp-dptx: failed to initialize DPTXRemotePort service\n");
goto err_shutdown;
}
u8 report_1[8] = {0x62, 0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00};
afk_epic_report(dptx->epic, 1, 0x12, 0, report_1, sizeof(report_1));
u8 report_3[8] = {0x63, 0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00};
afk_epic_report(dptx->epic, 3, 0x12, 0, report_3, sizeof(report_3));
return dptx;
err_shutdown:
afk_epic_shutdown_ep(dptx->epic);
err_free:
free(dptx);
return NULL;
}
int dcp_dptx_shutdown(dcp_dptx_if_t *dptx)
{
afk_epic_shutdown_ep(dptx->epic);
free(dptx);
return 0;
}

60
src/dcp/dptxep.h Normal file
View file

@ -0,0 +1,60 @@
// SPDX-License-Identifier: GPL-2.0-only OR MIT
/* Copyright 2022 Sven Peter <sven@svenpeter.dev> */
#ifndef __APPLE_DCP_DPTXEP_H__
#define __APPLE_DCP_DPTXEP_H__
#include "dp_phy.h"
#include "../dcp.h"
#include "../types.h"
typedef struct dcp_dptx_if dcp_dptx_if_t;
enum dptx_apcall {
DPTX_APCALL_ACTIVATE = 0,
DPTX_APCALL_DEACTIVATE = 1,
DPTX_APCALL_GET_MAX_DRIVE_SETTINGS = 2,
DPTX_APCALL_SET_DRIVE_SETTINGS = 3,
DPTX_APCALL_GET_DRIVE_SETTINGS = 4,
DPTX_APCALL_WILL_CHANGE_LINKG_CONFIG = 5,
DPTX_APCALL_DID_CHANGE_LINK_CONFIG = 6,
DPTX_APCALL_GET_MAX_LINK_RATE = 7,
DPTX_APCALL_GET_LINK_RATE = 8,
DPTX_APCALL_SET_LINK_RATE = 9,
DPTX_APCALL_GET_ACTIVE_LANE_COUNT = 10,
DPTX_APCALL_SET_ACTIVE_LANE_COUNT = 11,
DPTX_APCALL_GET_SUPPORTS_DOWN_SPREAD = 12,
DPTX_APCALL_GET_DOWN_SPREAD = 13,
DPTX_APCALL_SET_DOWN_SPREAD = 14,
DPTX_APCALL_GET_SUPPORTS_LANE_MAPPING = 15,
DPTX_APCALL_SET_LANE_MAP = 16,
DPTX_APCALL_GET_SUPPORTS_HPD = 17,
DPTX_APCALL_FORCE_HOTPLUG_DETECT = 18,
DPTX_APCALL_INACTIVE_SINK_DETECTED = 19,
DPTX_APCALL_SET_TILED_DISPLAY_HINTS = 20,
DPTX_APCALL_DEVICE_NOT_RESPONDING = 21,
DPTX_APCALL_DEVICE_BUSY_TIMEOUT = 22,
DPTX_APCALL_DEVICE_NOT_STARTED = 23,
};
#define DCPDPTX_REMOTE_PORT_CORE GENMASK(3, 0)
#define DCPDPTX_REMOTE_PORT_DFP GENMASK(7, 4)
#define DCPDPTX_REMOTE_PORT_DIE GENMASK(11, 8)
#define DCPDPTX_REMOTE_PORT_CONNECTED BIT(15)
enum dptx_link_rate {
LINK_RATE_RBR = 0x06,
LINK_RATE_HBR = 0x0a,
LINK_RATE_HBR2 = 0x14,
LINK_RATE_HBR3 = 0x1e,
};
dcp_dptx_if_t *dcp_dptx_init(dcp_dev_t *dcp);
int dcp_dptx_shutdown(dcp_dptx_if_t *dptx);
int dcp_dptx_connect(dcp_dptx_if_t *dptx, dptx_phy_t *phy, u32 port);
int dcp_dptx_disconnect(dcp_dptx_if_t *dptx, u32 port);
int dcp_dptx_hpd(dcp_dptx_if_t *dptx, u32 port, bool hpd);
#endif

271
src/dcp/parser.c Normal file
View file

@ -0,0 +1,271 @@
// SPDX-License-Identifier: GPL-2.0-only OR MIT
/* Copyright 2021 Alyssa Rosenzweig <alyssa@rosenzweig.io> */
#include "malloc.h"
#include "parser.h"
#include "string.h"
#include "../utils.h"
#define DCP_PARSE_HEADER 0xd3
enum dcp_parse_type {
DCP_TYPE_DICTIONARY = 1,
DCP_TYPE_ARRAY = 2,
DCP_TYPE_INT64 = 4,
DCP_TYPE_STRING = 9,
DCP_TYPE_BLOB = 10,
DCP_TYPE_BOOL = 11
};
struct dcp_parse_tag {
unsigned int size : 24;
enum dcp_parse_type type : 5;
unsigned int padding : 2;
bool last : 1;
} __packed;
static void *parse_bytes(struct dcp_parse_ctx *ctx, size_t count)
{
void *ptr = ctx->blob + ctx->pos;
if (ctx->pos + count > ctx->len)
return NULL;
ctx->pos += count;
return ptr;
}
static u32 *parse_u32(struct dcp_parse_ctx *ctx)
{
return parse_bytes(ctx, sizeof(u32));
}
static struct dcp_parse_tag *parse_tag(struct dcp_parse_ctx *ctx)
{
struct dcp_parse_tag *tag;
/* Align to 32-bits */
ctx->pos = ALIGN_UP(ctx->pos, 4);
tag = parse_bytes(ctx, sizeof(struct dcp_parse_tag));
if (!tag)
return NULL;
if (tag->padding)
return NULL;
return tag;
}
static struct dcp_parse_tag *parse_tag_of_type(struct dcp_parse_ctx *ctx, enum dcp_parse_type type)
{
struct dcp_parse_tag *tag = parse_tag(ctx);
if (!tag)
return NULL;
if (tag->type != type)
return NULL;
return tag;
}
static int skip(struct dcp_parse_ctx *handle)
{
struct dcp_parse_tag *tag = parse_tag(handle);
int ret = 0;
int i;
if (!tag)
return -1;
switch (tag->type) {
case DCP_TYPE_DICTIONARY:
for (i = 0; i < tag->size; ++i) {
ret |= skip(handle); /* key */
ret |= skip(handle); /* value */
}
return ret;
case DCP_TYPE_ARRAY:
for (i = 0; i < tag->size; ++i)
ret |= skip(handle);
return ret;
case DCP_TYPE_INT64:
handle->pos += sizeof(s64);
return 0;
case DCP_TYPE_STRING:
case DCP_TYPE_BLOB:
handle->pos += tag->size;
return 0;
case DCP_TYPE_BOOL:
return 0;
default:
return -1;
}
}
/* Caller must free the result */
static char *parse_string(struct dcp_parse_ctx *handle)
{
struct dcp_parse_tag *tag = parse_tag_of_type(handle, DCP_TYPE_STRING);
const char *in;
char *out;
if (!tag)
return NULL;
in = parse_bytes(handle, tag->size);
if (!in)
return NULL;
out = malloc(tag->size + 1);
memcpy(out, in, tag->size);
out[tag->size] = '\0';
return out;
}
static int parse_int(struct dcp_parse_ctx *handle, s64 *value)
{
void *tag = parse_tag_of_type(handle, DCP_TYPE_INT64);
s64 *in;
if (!tag)
return -1;
in = parse_bytes(handle, sizeof(s64));
if (!in)
return -1;
memcpy(value, in, sizeof(*value));
return 0;
}
static int parse_bool(struct dcp_parse_ctx *handle, bool *b)
{
struct dcp_parse_tag *tag = parse_tag_of_type(handle, DCP_TYPE_BOOL);
if (!tag)
return -1;
*b = !!tag->size;
return 0;
}
struct iterator {
struct dcp_parse_ctx *handle;
u32 idx, len;
};
static int iterator_begin(struct dcp_parse_ctx *handle, struct iterator *it, bool dict)
{
struct dcp_parse_tag *tag;
enum dcp_parse_type type = dict ? DCP_TYPE_DICTIONARY : DCP_TYPE_ARRAY;
*it = (struct iterator){.handle = handle, .idx = 0};
tag = parse_tag_of_type(it->handle, type);
if (!tag)
return -1;
it->len = tag->size;
return 0;
}
#define dcp_parse_foreach_in_array(handle, it) \
for (iterator_begin(handle, &it, false); it.idx < it.len; ++it.idx)
#define dcp_parse_foreach_in_dict(handle, it) \
for (iterator_begin(handle, &it, true); it.idx < it.len; ++it.idx)
int parse(void *blob, size_t size, struct dcp_parse_ctx *ctx)
{
u32 *header;
*ctx = (struct dcp_parse_ctx){
.blob = blob,
.len = size,
.pos = 0,
};
header = parse_u32(ctx);
if (!header)
return -1;
if (*header != DCP_PARSE_HEADER)
return -1;
return 0;
}
int parse_epic_service_init(struct dcp_parse_ctx *handle, const char **name, const char **class,
s64 *unit)
{
int ret = 0;
struct iterator it;
bool parsed_unit = false;
bool parsed_name = false;
bool parsed_class = false;
*name = NULL;
*class = NULL;
dcp_parse_foreach_in_dict(handle, it)
{
char *key = parse_string(it.handle);
if (!key) {
ret = -1;
break;
}
if (!strcmp(key, "EPICName")) {
*name = parse_string(it.handle);
if (!*name)
ret = -1;
else
parsed_name = true;
} else if (!strcmp(key, "EPICProviderClass")) {
*class = parse_string(it.handle);
if (!*class)
ret = -1;
else
parsed_class = true;
} else if (!strcmp(key, "EPICUnit")) {
ret = parse_int(it.handle, unit);
if (!ret)
parsed_unit = true;
} else {
skip(it.handle);
}
free(key);
if (ret)
break;
}
if (!parsed_unit || !parsed_name || !parsed_class)
ret = -1;
if (ret) {
if (*name) {
free(*name);
*name = NULL;
}
if (*class) {
free(*class);
*class = NULL;
}
}
return ret;
}

19
src/dcp/parser.h Normal file
View file

@ -0,0 +1,19 @@
// SPDX-License-Identifier: GPL-2.0-only OR MIT
/* Copyright 2021 Alyssa Rosenzweig <alyssa@rosenzweig.io> */
#ifndef __APPLE_DCP_PARSER_H__
#define __APPLE_DCP_PARSER_H__
#include "../types.h"
struct dcp_parse_ctx {
void *blob;
u32 pos, len;
};
int parse(void *blob, size_t size, struct dcp_parse_ctx *ctx);
int parse_epic_service_init(struct dcp_parse_ctx *handle, const char **name, const char **class,
s64 *unit);
#endif

View file

@ -92,13 +92,14 @@ dcp_iboot_if_t *dcp_ib_init(dcp_dev_t *dcp)
return NULL;
iboot->dcp = dcp;
iboot->epic = afk_epic_init(dcp->rtkit, DCP_IBOOT_ENDPOINT);
iboot->epic = afk_epic_start_ep(dcp->afk, DCP_IBOOT_ENDPOINT, false);
if (!iboot->epic) {
printf("dcp-iboot: failed to initialize EPIC\n");
goto err_free;
}
iboot->channel = afk_epic_start_interface(iboot->epic, "disp0-service", TXBUF_LEN, RXBUF_LEN);
iboot->channel =
afk_epic_start_interface(iboot->epic, NULL, NULL, "disp0-service", TXBUF_LEN, RXBUF_LEN);
if (iboot->channel < 0) {
printf("dcp-iboot: failed to initialize disp0 service\n");
@ -108,7 +109,7 @@ dcp_iboot_if_t *dcp_ib_init(dcp_dev_t *dcp)
return iboot;
err_shutdown:
afk_epic_shutdown(iboot->epic);
afk_epic_shutdown_ep(iboot->epic);
err_free:
free(iboot);
return NULL;
@ -116,7 +117,7 @@ err_free:
int dcp_ib_shutdown(dcp_iboot_if_t *iboot)
{
afk_epic_shutdown(iboot->epic);
afk_epic_shutdown_ep(iboot->epic);
free(iboot);
return 0;
@ -130,7 +131,7 @@ static int dcp_ib_cmd(dcp_iboot_if_t *iboot, int op, size_t in_size)
iboot->txcmd.op = op;
iboot->txcmd.len = sizeof(struct txcmd) + in_size;
return afk_epic_command(iboot->epic, iboot->channel, 0xc0, iboot->txbuf,
return afk_epic_command(iboot->epic, iboot->channel, 0, 0xc0, iboot->txbuf,
sizeof(struct txcmd) + in_size, iboot->rxbuf, &rxsize);
}

View file

@ -11,6 +11,9 @@
#include "utils.h"
#include "xnuboot.h"
#include "dcp/dp_phy.h"
#include "dcp/dptxep.h"
#define DISPLAY_STATUS_DELAY 100
#define DISPLAY_STATUS_RETRIES 20
@ -24,6 +27,7 @@
static dcp_dev_t *dcp;
static dcp_iboot_if_t *iboot;
static dcp_dptx_if_t *dptx;
static u64 fb_dva;
static u64 fb_size;
bool display_is_external;
@ -199,6 +203,25 @@ int display_start_dcp(void)
return -1;
}
// Power on
int ret;
if ((ret = dcp_ib_set_power(iboot, true)) < 0) {
printf("display: failed to set power\n");
return ret;
}
dptx = dcp_dptx_init(dcp);
if (!dptx) {
printf("display: failed to initialize DCP iBoot interface\n");
dcp_ib_shutdown(iboot);
iboot = NULL;
dcp_shutdown(dcp, false);
return -1;
}
dptx_phy_t *dpphy = dptx_phy_init("/arm-io/dptx-phy");
dcp_dptx_connect(dptx, dpphy, 0);
return 0;
}
@ -308,6 +331,13 @@ int display_configure(const char *config)
int timing_cnt, color_cnt;
int hpd = 0, retries = 0;
/* trigger HPD on dptx endpoint, triggers a request from dcp to configure
* the dptx-phy config (lane count/link rate) but according to dcp's
* syslog the AP is not ready for hotplug event and dcp_ib_get_hpd() will
* timeout.
*/
dcp_dptx_hpd(dptx, 0, true);
/* After boot DCP does not immediately report a connected display. Retry getting display
* information for 2 seconds.
*/
@ -369,12 +399,7 @@ int display_configure(const char *config)
return -1;
}
cur_boot_args.mem_size -= size;
fb_pa = cur_boot_args.phys_base + cur_boot_args.mem_size;
/* add guard page between RAM and framebuffer */
// TODO: update mapping?
cur_boot_args.mem_size -= SZ_16K;
fb_pa = top_of_memory_alloc(size);
memset((void *)fb_pa, 0, size);
tmp_dva = iova_alloc(dcp->iovad_dcp, size);
@ -469,6 +494,13 @@ int display_init(void)
return -1;
}
// HACK: disable non-working display config on j473ap
int model_node = adt_path_offset(adt, "/");
if (model_node >= 0 && adt_is_compatible(adt, model_node, "J473AP")) {
printf("display: j473 is not support\n");
return 0;
}
display_is_external = adt_getprop(adt, node, "external", NULL);
if (display_is_external)
printf("display: Display is external\n");
@ -491,6 +523,8 @@ int display_init(void)
void display_shutdown(dcp_shutdown_mode mode)
{
if (iboot) {
if (dptx)
dcp_dptx_shutdown(dptx);
dcp_ib_shutdown(iboot);
switch (mode) {
case DCP_QUIESCED:

View file

@ -14,6 +14,7 @@
#include "pcie.h"
#include "pmgr.h"
#include "sep.h"
#include "sio.h"
#include "smp.h"
#include "types.h"
#include "usb.h"
@ -1155,18 +1156,14 @@ static u64 dart_get_mapping(dart_dev_t *dart, const char *path, u64 paddr, size_
return iova;
}
static int dt_device_set_reserved_mem(int node, dart_dev_t *dart, const char *name,
uint32_t phandle, u64 paddr, u64 size)
static int dt_device_set_reserved_mem(int node, const char *name, uint32_t phandle, u64 iova,
u64 size)
{
int ret;
u64 iova = dart_get_mapping(dart, name, paddr, size);
if (DART_IS_ERR(iova))
bail("ADT: no mapping found for '%s' 0x%012lx iova:0x%08lx)\n", name, paddr, iova);
ret = fdt_appendprop_u32(dt, node, "iommu-addresses", phandle);
if (ret != 0)
bail("DT: could not append phandle '%s.compatible' property: %d\n", name, ret);
bail("DT: could not append phandle to '%s.iommu-addresses' property: %d\n", name, ret);
ret = fdt_appendprop_u64(dt, node, "iommu-addresses", iova);
if (ret != 0)
@ -1179,6 +1176,16 @@ static int dt_device_set_reserved_mem(int node, dart_dev_t *dart, const char *na
return 0;
}
static int dt_device_set_reserved_mem_from_dart(int node, dart_dev_t *dart, const char *name,
uint32_t phandle, u64 paddr, u64 size)
{
u64 iova = dart_get_mapping(dart, name, paddr, size);
if (DART_IS_ERR(iova))
bail("ADT: no mapping found for '%s' 0x%012lx iova:0x%08lx)\n", name, paddr, iova);
return dt_device_set_reserved_mem(node, name, phandle, iova, size);
}
static int dt_get_or_add_reserved_mem(const char *node_name, const char *compat, u64 paddr,
size_t size)
{
@ -1235,6 +1242,9 @@ static int dt_device_add_mem_region(const char *alias, uint32_t phandle, const c
if (dev_node < 0)
bail("DT: failed to update node for alias '%s'\n", alias);
if (!name)
return 0;
ret = fdt_appendprop_string(dt, dev_node, "memory-region-names", name);
if (ret != 0)
bail("DT: failed to append to 'memory-region-names' property\n");
@ -1350,20 +1360,20 @@ static int dt_add_reserved_regions(const char *dcp_alias, const char *disp_alias
uint32_t mem_phandle = fdt_get_phandle(dt, mem_node);
if (maps[i].map_dcp && dart_dcp) {
ret = dt_device_set_reserved_mem(mem_node, dart_dcp, node_name, dcp_phandle,
ret = dt_device_set_reserved_mem_from_dart(mem_node, dart_dcp, node_name, dcp_phandle,
region[i].paddr, region[i].size);
if (ret != 0)
goto err;
}
if (maps[i].map_disp && dart_disp) {
ret = dt_device_set_reserved_mem(mem_node, dart_disp, node_name, disp_phandle,
ret = dt_device_set_reserved_mem_from_dart(mem_node, dart_disp, node_name, disp_phandle,
region[i].paddr, region[i].size);
if (ret != 0)
goto err;
}
if (maps[i].map_piodma && dart_piodma) {
ret = dt_device_set_reserved_mem(mem_node, dart_piodma, node_name, piodma_phandle,
region[i].paddr, region[i].size);
ret = dt_device_set_reserved_mem_from_dart(
mem_node, dart_piodma, node_name, piodma_phandle, region[i].paddr, region[i].size);
if (ret != 0)
goto err;
}
@ -1490,6 +1500,61 @@ static int dt_vram_reserved_region(const char *dcp_alias, const char *disp_alias
disp_reserved_regions_vram, &region, 1);
}
static int dt_reserve_asc_firmware(const char *adt_path, const char *fdt_path)
{
int ret = 0;
int fdt_node = fdt_path_offset(dt, fdt_path);
if (fdt_node < 0) {
printf("DT: '%s' not found\n", fdt_path);
return 0;
}
int node = adt_path_offset(adt, adt_path);
if (node < 0)
bail("ADT: '%s' not found\n", adt_path);
uint32_t dev_phandle = fdt_get_phandle(dt, fdt_node);
if (!dev_phandle) {
ret = fdt_generate_phandle(dt, &dev_phandle);
if (!ret)
ret = fdt_setprop_u32(dt, fdt_node, "phandle", dev_phandle);
if (ret != 0)
bail("DT: couldn't set '%s.phandle' property: %d\n", fdt_path, ret);
}
const uint64_t *segments;
u32 segments_len;
segments = adt_getprop(adt, node, "segment-ranges", &segments_len);
unsigned int num_maps = segments_len / 32;
for (unsigned i = 0; i < num_maps; i++) {
u64 paddr = segments[0];
u64 iova = segments[2];
u32 size = segments[3];
segments += 4;
char node_name[64];
snprintf(node_name, sizeof(node_name), "asc-firmware@%lx", paddr);
int mem_node = dt_get_or_add_reserved_mem(node_name, "apple,asc-mem", paddr, size);
if (mem_node < 0)
return ret;
uint32_t mem_phandle = fdt_get_phandle(dt, mem_node);
ret = dt_device_set_reserved_mem(mem_node, node_name, dev_phandle, iova, size);
if (ret < 0)
return ret;
ret = dt_device_add_mem_region(fdt_path, mem_phandle, NULL);
if (ret < 0)
return ret;
}
return 0;
}
static struct disp_mapping disp_reserved_regions_t8103[] = {
{"region-id-50", "dcp_data", true, false, false},
{"region-id-57", "region57", true, false, false},
@ -1644,6 +1709,72 @@ static int dt_set_display(void)
return dt_vram_reserved_region("dcp", "disp0");
}
static int dt_set_sio_fwdata(void)
{
const char *path = "/soc/sio";
int node = fdt_path_offset(dt, path);
if (node < 0) {
printf("FDT: '%s' node not found\n", path);
return 0;
}
int ret = sio_setup_fwdata();
if (ret < 0)
bail("DT: failed to set up SIO firmware data: %d\n", ret);
int phandle = fdt_get_phandle(dt, node);
uint32_t max_phandle;
ret = fdt_find_max_phandle(dt, &max_phandle);
if (ret)
bail("DT: failed to get max phandle: %d\n", ret);
if (!phandle) {
phandle = ++max_phandle;
ret = fdt_setprop_u32(dt, node, "phandle", phandle);
if (ret != 0)
bail("DT: couldn't set '%s.phandle' property: %d\n", path, ret);
}
for (int i = 0; i < sio_num_fwdata; i++) {
struct sio_mapping *mapping = &sio_fwdata[i];
char node_name[64];
snprintf(node_name, sizeof(node_name), "sio-firmware-data@%lx", mapping->phys);
int mem_node =
dt_get_or_add_reserved_mem(node_name, "apple,asc-mem", mapping->phys, mapping->size);
if (mem_node < 0)
return ret;
uint32_t mem_phandle = fdt_get_phandle(dt, mem_node);
int ret =
dt_device_set_reserved_mem(mem_node, node_name, phandle, mapping->iova, mapping->size);
if (ret < 0)
return ret;
ret = dt_device_add_mem_region(path, mem_phandle, NULL);
if (ret < 0)
return ret;
}
node = fdt_path_offset(dt, path);
if (node < 0)
bail("DT: '%s' not found\n", path);
for (int i = 0; i < sio_num_fwparams; i++) {
struct sio_fwparam *param = &sio_fwparams[i];
if (fdt_appendprop_u32(dt, node, "apple,sio-firmware-params", param->key))
bail("DT: couldn't append to SIO parameters\n");
if (fdt_appendprop_u32(dt, node, "apple,sio-firmware-params", param->value))
bail("DT: couldn't append to SIO parameters\n");
}
return 0;
}
static int dt_disable_missing_devs(const char *adt_prefix, const char *dt_prefix, int max_devs)
{
int ret = -1;
@ -1952,6 +2083,10 @@ int kboot_prepare_dt(void *fdt)
return -1;
if (dt_disable_missing_devs("i2c", "i2c@", 8))
return -1;
if (dt_reserve_asc_firmware("/arm-io/sio", "/soc/sio"))
return -1;
if (dt_set_sio_fwdata())
return -1;
#ifndef RELEASE
if (dt_transfer_virtios())
return 1;

View file

@ -24,6 +24,9 @@ static const u8 kernel_magic[] = {'A', 'R', 'M', 0x64}; // at 0x38
static const u8 cpio_magic[] = {'0', '7', '0', '7', '0'}; // '1' or '2' next
static const u8 img4_magic[] = {0x16, 0x04, 'I', 'M', 'G', '4'}; // IA5String 'IMG4'
static const u8 sig_magic[] = {'m', '1', 'n', '1', '_', 's', 'i', 'g'};
static const u8 initramfs_magic[] = {
'm', '1', 'n', '1', '_', 'i', 'n',
'i', 't', 'r', 'a', 'm', 'f', 's'}; // followed by size as little endian uint32_t
static const u8 empty[] = {0, 0, 0, 0};
static char expect_compatible[256];
@ -218,6 +221,12 @@ static void *load_one_payload(void *start, size_t size)
printf("Found a m1n1 signature at %p, skipping 0x%x bytes\n", p, size);
return p + size;
} else if (!memcmp(p, initramfs_magic, sizeof(initramfs_magic))) {
u32 size;
memcpy(&size, p + sizeof(initramfs_magic), 4);
printf("Found a m1n1 initramfs payload at %p, 0x%x bytes\n", p, size);
p += sizeof(initramfs_magic) + 4;
return load_cpio(p, size);
} else if (check_var(&p)) {
return p;
} else if (!memcmp(p, empty, sizeof empty) ||

View file

@ -345,6 +345,14 @@ static void rtkit_crashed(rtkit_dev_t *rtk)
}
}
bool rtkit_can_recv(rtkit_dev_t *rtk)
{
if (rtk->crashed)
return false;
return asc_can_recv(rtk->asc);
}
int rtkit_recv(rtkit_dev_t *rtk, struct rtkit_message *msg)
{
struct asc_message asc_msg;

View file

@ -31,6 +31,8 @@ void rtkit_free(rtkit_dev_t *rtk);
bool rtkit_start_ep(rtkit_dev_t *rtk, u8 ep);
bool rtkit_boot(rtkit_dev_t *rtk);
bool rtkit_can_recv(rtkit_dev_t *rtk);
int rtkit_recv(rtkit_dev_t *rtk, struct rtkit_message *msg);
bool rtkit_send(rtkit_dev_t *rtk, const struct rtkit_message *msg);

249
src/sio.c Normal file
View file

@ -0,0 +1,249 @@
/* SPDX-License-Identifier: MIT */
#include "adt.h"
#include "errno.h"
#include "malloc.h"
#include "sio.h"
#include "types.h"
#include "utils.h"
// Reuse pages for different data sections, if space allows it
#define MERGE_SIO_FWDATA
#define SIO_KEY(s) _SIO_KEY(#s)
#define _SIO_KEY(s) (((s)[0] << 24) | ((s)[1] << 16) | ((s)[2] << 8) | (s)[3])
#define MAX_FWDATA 6
#define MAX_FWPARAMS 16
int sio_num_fwdata;
struct sio_mapping *sio_fwdata;
int sio_num_fwparams;
struct sio_fwparam *sio_fwparams;
static void *alloc_mapped_data(size_t size, u64 *iova)
{
if (sio_num_fwdata >= MAX_FWDATA)
return NULL;
struct sio_mapping *mapping = &sio_fwdata[sio_num_fwdata];
#ifdef MERGE_SIO_FWDATA
if (sio_num_fwdata && ALIGN_UP((mapping - 1)->size, SZ_16K) >= (mapping - 1)->size + size) {
mapping--;
*iova = mapping->iova + mapping->size;
mapping->size = ALIGN_UP(mapping->size + size, SZ_4K);
goto done;
}
#endif
if (!sio_num_fwdata++)
mapping->iova = *iova = 0x30000;
else
mapping->iova = *iova = ALIGN_UP((mapping - 1)->iova + (mapping - 1)->size, SZ_16K);
mapping->size = ALIGN_UP(size, SZ_4K);
mapping->phys = top_of_memory_alloc(size);
memset64((void *)mapping->phys, 0, ALIGN_UP(mapping->size, SZ_16K));
done:
return (void *)((*iova - mapping->iova) + mapping->phys);
}
static void mapping_fixup(void)
{
for (int i = 0; i < sio_num_fwdata; i++) {
struct sio_mapping *mapping = &sio_fwdata[i];
mapping->size = ALIGN_UP(mapping->size, SZ_16K);
}
}
static void *add_fwdata(size_t size, u32 param_id)
{
if (sio_num_fwparams + 1 >= MAX_FWPARAMS)
return NULL;
u64 iova;
void *p = alloc_mapped_data(size, &iova);
struct sio_fwparam *param = &sio_fwparams[sio_num_fwparams];
param->key = param_id;
param->value = iova >> 12;
param++;
param->key = param_id + 1;
param->value = size;
sio_num_fwparams += 2;
return p;
}
#define PARAM_UNK_000b 0x000b
#define PARAM_PANIC_BUFFER 0x000f
#define PARAM_MAP_RANGE 0x001a
#define PARAM_DEVICE_TYPE 0x001c
#define PARAM_TUNABLES 0x001e
#define PARAM_DMASHIM_DATA 0x0022
#define PARAM_UNK_030d 0x030d
struct copy_rule {
const char *prop;
int fw_param;
bool keyed;
int blobsize;
u32 nkeys;
const char *keys[9];
};
#define SPACER "\xff\xff\xff\xff"
struct copy_rule copy_rules[] = {
{
.prop = "asio-ascwrap-tunables",
.fw_param = PARAM_TUNABLES,
},
{
.blobsize = 0x1b80,
.fw_param = PARAM_UNK_000b,
},
{
.blobsize = 0x1e000,
.fw_param = PARAM_PANIC_BUFFER,
},
{
// peformance endpoint? FIFO?
.blobsize = 0x4000,
.fw_param = PARAM_UNK_030d,
},
{
.prop = "map-range",
.fw_param = PARAM_MAP_RANGE,
.blobsize = 16,
.keyed = true,
.keys = {SPACER, SPACER, SPACER, "MISC", NULL},
},
{
.prop = "dmashim",
.fw_param = PARAM_DMASHIM_DATA,
.blobsize = 32,
.keyed = true,
.keys = {"SSPI", "SUAR", "SAUD", "ADMA", "AAUD", NULL},
},
{
// it seems 'device_type' must go after 'dmashim'
.prop = "device-type",
.fw_param = PARAM_DEVICE_TYPE,
.blobsize = 8,
.keyed = true,
.keys = {"dSPI", "dUAR", "dMCA", "dDPA", "dPDM", "dALE", "dAMC", "dAPD", NULL},
},
};
int find_key_index(const char *keylist[], u32 needle)
{
int i;
for (i = 0; keylist[i]; i++) {
const char *s = keylist[i];
u32 key = ((u32)s[0]) << 24 | ((u32)s[1]) << 16 | ((u32)s[2]) << 8 | s[3];
if (key == needle)
break;
}
return i;
}
int sio_setup_fwdata(void)
{
int ret = -ENOMEM;
if (sio_fwdata)
return 0;
sio_fwdata = calloc(MAX_FWDATA, sizeof(*sio_fwdata));
if (!sio_fwdata)
return -ENOMEM;
sio_num_fwdata = 0;
sio_fwparams = calloc(MAX_FWPARAMS, sizeof(*sio_fwdata));
if (!sio_fwparams) {
free(sio_fwdata);
return -ENOMEM;
}
sio_num_fwparams = 0;
int node = adt_path_offset(adt, "/arm-io/sio");
if (node < 0) {
printf("%s: missing node\n", __func__);
goto err_inval;
}
for (int i = 0; i < (int)ARRAY_SIZE(copy_rules); i++) {
struct copy_rule *rule = &copy_rules[i];
u32 len;
if (!rule->prop) {
if (!add_fwdata(rule->blobsize, rule->fw_param))
goto err_nomem;
continue;
}
const u8 *adt_blob = adt_getprop(adt, node, rule->prop, &len);
if (!adt_blob) {
printf("%s: missing ADT property '%s'\n", __func__, rule->prop);
goto err_inval;
}
if (!rule->keyed) {
u8 *sio_blob = add_fwdata(len, rule->fw_param);
if (!sio_blob)
goto err_nomem;
memcpy8(sio_blob, (void *)adt_blob, len);
continue;
}
int nkeys = find_key_index(rule->keys, 0);
u8 *sio_blob = add_fwdata(nkeys * rule->blobsize, rule->fw_param);
if (len % (rule->blobsize + 4) != 0) {
printf("%s: bad length %d of ADT property '%s', expected multiple of %d + 4\n",
__func__, len, rule->prop, rule->blobsize);
}
for (u32 off = 0; off + rule->blobsize <= len; off += (rule->blobsize + 4)) {
const u8 *p = &adt_blob[off];
u32 key = *((u32 *)p);
int key_idx = find_key_index(rule->keys, key);
if (key_idx >= nkeys) {
printf("%s: unknown key %x found in ADT property '%s'\n", __func__, key,
rule->prop);
goto err_inval;
}
memcpy8(sio_blob + (key_idx * rule->blobsize), (void *)(p + 4), rule->blobsize);
}
}
mapping_fixup();
return 0;
err_inval:
ret = -EINVAL;
goto err;
err_nomem:
ret = -ENOMEM;
goto err;
err:
for (int i = 0; i < MAX_FWDATA; i++) {
if (!sio_fwdata[i].size)
break;
// No way to give back memory with the top of memory
// allocator.
// free((void *)sio_fwdata[i].phys);
}
free(sio_fwdata);
free(sio_fwparams);
sio_fwdata = NULL;
sio_fwparams = NULL;
return ret;
}

24
src/sio.h Normal file
View file

@ -0,0 +1,24 @@
/* SPDX-License-Identifier: MIT */
#ifndef SIO_H
#define SIO_H
struct sio_mapping {
u64 phys;
u64 iova;
u64 size;
};
struct sio_fwparam {
u32 key;
u32 value;
};
extern int sio_num_fwdata;
extern struct sio_mapping *sio_fwdata;
extern int sio_num_fwparams;
extern struct sio_fwparam *sio_fwparams;
int sio_setup_fwdata(void);
#endif

View file

@ -180,3 +180,23 @@ bool is_heap(void *addr)
return p > top_of_kernel_data && p < top_of_ram;
}
// TODO: update mapping?
u64 top_of_memory_alloc(size_t size)
{
static bool guard_page_inserted = false;
cur_boot_args.mem_size -= ALIGN_UP(size, SZ_16K);
u64 ret = cur_boot_args.phys_base + cur_boot_args.mem_size;
if (!guard_page_inserted) {
cur_boot_args.mem_size -= SZ_16K;
guard_page_inserted = true;
} else {
// If the guard page was already there, move it down and allocate
// above it -- this is accomplished by simply shifting the allocated
// region by one page up.
ret += SZ_16K;
}
return ret;
}

View file

@ -440,5 +440,6 @@ extern struct vector_args next_stage;
void deep_wfi(void);
bool is_heap(void *addr);
u64 top_of_memory_alloc(size_t size);
#endif