mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-10 01:34:12 +00:00
Merge remote-tracking branch 'jannau/m2_dptx' into m2-13_2
This commit is contained in:
commit
fe4037365b
29 changed files with 2694 additions and 129 deletions
9
Makefile
9
Makefile
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
46
proxyclient/experiments/dp2hdmi.py
Executable file
46
proxyclient/experiments/dp2hdmi.py
Executable 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!")
|
|
@ -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"
|
||||
|
|
24
proxyclient/hv/trace_dptx.py
Normal file
24
proxyclient/hv/trace_dptx.py
Normal 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")
|
||||
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
@ -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,22 +681,38 @@ 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)),
|
||||
unkBool=bool_,
|
||||
unkFloat=Float64l,
|
||||
unkInt=uint,
|
||||
unkOutBool=OutPtr(bool_))
|
||||
else:
|
||||
swap_submit_dcp = Call(uint32_t, "swap_submit_dcp",
|
||||
swap_rec=InPtr(IOMFBSwapRec),
|
||||
surfaces=Array(4, InPtr(IOSurface)),
|
||||
surfAddr=Array(4, Hex(ulong)),
|
||||
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_))
|
||||
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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
324
src/afk.c
324
src/afk.c
|
@ -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:
|
||||
return 1;
|
||||
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;
|
||||
}
|
||||
|
|
70
src/afk.h
70
src/afk.h
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
23
src/dcp.h
23
src/dcp.h
|
@ -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
12
src/dcp/dp_phy.h
Normal 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
529
src/dcp/dptx_phy.c
Normal 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
554
src/dcp/dptxep.c
Normal 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
60
src/dcp/dptxep.h
Normal 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
271
src/dcp/parser.c
Normal 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
19
src/dcp/parser.h
Normal 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
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
161
src/kboot.c
161
src/kboot.c
|
@ -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,
|
||||
region[i].paddr, region[i].size);
|
||||
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,
|
||||
region[i].paddr, region[i].size);
|
||||
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, ®ion, 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;
|
||||
|
|
|
@ -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) ||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
249
src/sio.c
Normal 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 = ©_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
24
src/sio.h
Normal 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
|
20
src/utils.c
20
src/utils.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue