mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-12-18 09:53:04 +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_addresses.o fdt_empty_tree.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_sw.o \
|
||||||
fdt_wip.o fdt.o)
|
fdt_wip.o fdt.o)
|
||||||
|
|
||||||
|
DCP_OBJECTS := $(patsubst %,dcp/%, \
|
||||||
|
dptx_phy.o dptxep.o parser.o)
|
||||||
|
|
||||||
OBJECTS := \
|
OBJECTS := \
|
||||||
adt.o \
|
adt.o \
|
||||||
afk.o \
|
afk.o \
|
||||||
|
@ -116,6 +119,7 @@ OBJECTS := \
|
||||||
rtkit.o \
|
rtkit.o \
|
||||||
sart.o \
|
sart.o \
|
||||||
sep.o \
|
sep.o \
|
||||||
|
sio.o \
|
||||||
smp.o \
|
smp.o \
|
||||||
start.o \
|
start.o \
|
||||||
startup.o \
|
startup.o \
|
||||||
|
@ -128,6 +132,7 @@ OBJECTS := \
|
||||||
utils.o utils_asm.o \
|
utils.o utils_asm.o \
|
||||||
vsprintf.o \
|
vsprintf.o \
|
||||||
wdt.o \
|
wdt.o \
|
||||||
|
$(DCP_OBJECTS) \
|
||||||
$(MINILZLIB_OBJECTS) $(TINF_OBJECTS) $(DLMALLOC_OBJECTS) $(LIBFDT_OBJECTS) $(RUST_LIBS)
|
$(MINILZLIB_OBJECTS) $(TINF_OBJECTS) $(DLMALLOC_OBJECTS) $(LIBFDT_OBJECTS) $(RUST_LIBS)
|
||||||
|
|
||||||
FP_OBJECTS := \
|
FP_OBJECTS := \
|
||||||
|
@ -149,9 +154,9 @@ all: update_tag update_cfg build/$(TARGET) build/$(TARGET_RAW)
|
||||||
clean:
|
clean:
|
||||||
rm -rf build/*
|
rm -rf build/*
|
||||||
format:
|
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:
|
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:
|
rustfmt:
|
||||||
cd rust && cargo fmt
|
cd rust && cargo fmt
|
||||||
rustfmt-check:
|
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.dva_offset = getattr(u.adt["/arm-io/dcp"][0], "asc_dram_mask", 0)
|
||||||
|
|
||||||
dcp.start()
|
dcp.start()
|
||||||
|
dcp.start_ep(0x20)
|
||||||
dcp.start_ep(0x37)
|
dcp.start_ep(0x37)
|
||||||
dcp.dcpep.initialize()
|
dcp.dcpep.initialize()
|
||||||
|
|
||||||
|
dcp.system.wait_for("system")
|
||||||
|
dcp.system.system.setProperty("gAFKConfigLogMask", 0xffff)
|
||||||
|
|
||||||
mgr = DCPManager(dcp.dcpep, compat)
|
mgr = DCPManager(dcp.dcpep, compat)
|
||||||
|
|
||||||
mon.poll()
|
mon.poll()
|
||||||
|
@ -193,16 +197,28 @@ width = mgr.display_width()
|
||||||
height = mgr.display_height()
|
height = mgr.display_height()
|
||||||
|
|
||||||
surface_id = 3
|
surface_id = 3
|
||||||
|
surface_ov_id = 4
|
||||||
|
|
||||||
|
ov_dst_x = 200
|
||||||
|
ov_dst_y = 100
|
||||||
|
ov_height = 256
|
||||||
|
ov_width = 256
|
||||||
|
|
||||||
swap_rec = Container(
|
swap_rec = Container(
|
||||||
flags1 = 0x861202,
|
flags1 = 0x861202,
|
||||||
flags2 = 0x04,
|
flags2 = 0x04,
|
||||||
swap_id = swapid.val,
|
swap_id = swapid.val,
|
||||||
surf_ids = [surface_id, 0, 0, 0],
|
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_flags = [1, 0, 0, 0],
|
||||||
surf_unk = [0, 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_enabled = 0x80000007,
|
||||||
swap_completed = 0x80000007,
|
swap_completed = 0x80000007,
|
||||||
bl_unk = 0x1,
|
bl_unk = 0x1,
|
||||||
|
@ -213,7 +229,7 @@ swap_rec = Container(
|
||||||
surf = Container(
|
surf = Container(
|
||||||
is_tiled = False,
|
is_tiled = False,
|
||||||
unk_1 = False,
|
unk_1 = False,
|
||||||
unk_2 = False,
|
unk_2 = True, # needs be true for overlay with "xf4p"
|
||||||
plane_cnt = 0,
|
plane_cnt = 0,
|
||||||
plane_cnt2 = 0,
|
plane_cnt2 = 0,
|
||||||
format = "BGRA",
|
format = "BGRA",
|
||||||
|
@ -235,6 +251,32 @@ surf = Container(
|
||||||
unk_1f9 = 0,
|
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(
|
compressed_surf = Container(
|
||||||
is_tiled = False,
|
is_tiled = False,
|
||||||
unk_1 = False,
|
unk_1 = False,
|
||||||
|
@ -329,9 +371,17 @@ for i, color in enumerate(colors):
|
||||||
|
|
||||||
iova = disp_dart.iomap(0, buf, fb_size)
|
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]
|
#surfaces = [compressed_surf, None, None, None]
|
||||||
surfAddr = [iova, 0, 0, 0]
|
surfAddr = [iova, ov_iova, 0, 0]
|
||||||
|
|
||||||
def submit():
|
def submit():
|
||||||
swap_rec.swap_id = swapid.val
|
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 enum import IntEnum
|
||||||
|
|
||||||
|
from m1n1.constructutils import Ver
|
||||||
from m1n1.proxyutils import RegMonitor
|
from m1n1.proxyutils import RegMonitor
|
||||||
from m1n1.utils import *
|
from m1n1.utils import *
|
||||||
from m1n1.trace.dart import DARTTracer
|
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.rbep import *
|
||||||
from m1n1.fw.afk.epic import *
|
from m1n1.fw.afk.epic import *
|
||||||
|
|
||||||
|
Ver.set_version(hv.u)
|
||||||
|
|
||||||
if True:
|
if True:
|
||||||
dcp_adt_path = "/arm-io/dcp"
|
dcp_adt_path = "/arm-io/dcp"
|
||||||
dcp_dart_adt_path = "/arm-io/dart-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 ..asc import StandardASC
|
||||||
from .dcpep import DCPEndpoint
|
from .dcpep import DCPEndpoint
|
||||||
|
from ..afk.epic import *
|
||||||
|
|
||||||
class DCPClient(StandardASC):
|
class DCPClient(StandardASC):
|
||||||
ENDPOINTS = {
|
ENDPOINTS = {
|
||||||
|
0x20: AFKSystemEndpoint,
|
||||||
0x37: DCPEndpoint,
|
0x37: DCPEndpoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ from enum import IntEnum
|
||||||
from ..common import *
|
from ..common import *
|
||||||
from m1n1.utils import *
|
from m1n1.utils import *
|
||||||
from construct import *
|
from construct import *
|
||||||
|
from m1n1.constructutils import Ver
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ByRef:
|
class ByRef:
|
||||||
|
@ -419,7 +420,10 @@ IOMFBParameterName = Int32ul
|
||||||
BufferDescriptor = uint64_t
|
BufferDescriptor = uint64_t
|
||||||
|
|
||||||
SwapCompleteData = Bytes(0x12)
|
SwapCompleteData = Bytes(0x12)
|
||||||
SwapInfoBlob = Bytes(0x6c4)
|
SwapInfoBlob = Struct(
|
||||||
|
"unk" / Bytes(0x6c4),
|
||||||
|
Ver("V >= V13_2", "unk_13_2" / Bytes(0x10)),
|
||||||
|
)
|
||||||
|
|
||||||
SWAP_SURFACES = 4
|
SWAP_SURFACES = 4
|
||||||
|
|
||||||
|
@ -454,15 +458,15 @@ IOMFBSwapRec = Struct(
|
||||||
"unk_2c8" / Hex(Default(Int32ul, 0)),
|
"unk_2c8" / Hex(Default(Int32ul, 0)),
|
||||||
"unk_2cc" / UnkBytes(0x14),
|
"unk_2cc" / UnkBytes(0x14),
|
||||||
"unk_2e0" / Hex(Default(Int32ul, 0)),
|
"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_unk" / Hex(Int64ul), # seen: 0x0, 0x1, 0x101, 0x1_0000, 0x101_010101
|
||||||
"bl_val" / Hex(Int32ul), # range 0x10000000 - approximately 0x7fe07fc0 for 4 - 510 nits
|
"bl_val" / Hex(Int32ul), # range 0x10000000 - approximately 0x7fe07fc0 for 4 - 510 nits
|
||||||
"bl_power" / Hex(Int8ul), # constant 0x40, 0x00: backlight off
|
"bl_power" / Hex(Int8ul), # constant 0x40, 0x00: backlight off
|
||||||
"unk_2f3" / UnkBytes(0x2d),
|
"unk_2f3" / UnkBytes(0x2d),
|
||||||
|
Ver("V >= V13_2", "unk_320" / UnkBytes(0x13f)),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert IOMFBSwapRec.sizeof() == 0x320
|
|
||||||
|
|
||||||
MAX_PLANES = 3
|
MAX_PLANES = 3
|
||||||
|
|
||||||
ComponentTypes = Struct(
|
ComponentTypes = Struct(
|
||||||
|
@ -535,7 +539,7 @@ CompressionInfo = Struct(
|
||||||
"pad2" / Padding(1),
|
"pad2" / Padding(1),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert PlaneInfo.sizeof() == 0x34
|
assert CompressionInfo.sizeof() == 0x34
|
||||||
|
|
||||||
IOSurface = Struct(
|
IOSurface = Struct(
|
||||||
"is_tiled" / bool_,
|
"is_tiled" / bool_,
|
||||||
|
@ -567,19 +571,26 @@ IOSurface = Struct(
|
||||||
"unk_1f5" / Int32ul,
|
"unk_1f5" / Int32ul,
|
||||||
"unk_1f9" / Int32ul,
|
"unk_1f9" / Int32ul,
|
||||||
"padding" / UnkBytes(7),
|
"padding" / UnkBytes(7),
|
||||||
|
Ver("V >= V13_2", "padding_13_2" / UnkBytes(40)),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert IOSurface.sizeof() == 0x204
|
|
||||||
|
|
||||||
IOMFBColorFixedMatrix = Array(5, Array(3, ulong))
|
IOMFBColorFixedMatrix = Array(5, Array(3, ulong))
|
||||||
|
|
||||||
class PropID(IntEnum):
|
class PropID(IntEnum):
|
||||||
BrightnessCorrection = 14
|
BrightnessCorrection = 14
|
||||||
|
|
||||||
class UPPipeAP_H13P(IPCObject):
|
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")
|
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")
|
A035 = Call(bool_, "is_hilo")
|
||||||
A036 = Call(bool_, "apt_supported")
|
A036 = Call(bool_, "apt_supported")
|
||||||
A037 = Call(uint, "get_dfb_info", InOutPtr(uint), InOutPtr(Array(4, ulong)), InOutPtr(uint))
|
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
|
IdleCachingState = uint32_t
|
||||||
|
|
||||||
class UnifiedPipeline2(IPCObject):
|
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)
|
A352 = Call(bool_, "applyProperty", uint, uint)
|
||||||
A353 = Call(uint, "get_system_type")
|
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")
|
D100 = Callback(void, "match_pmu_service")
|
||||||
D101 = Callback(uint32_t, "UNK_get_some_field")
|
D101 = Callback(uint32_t, "UNK_get_some_field")
|
||||||
|
@ -608,15 +628,37 @@ class UnifiedPipeline2(IPCObject):
|
||||||
D109 = Callback(bool_, "create_PMU_service")
|
D109 = Callback(bool_, "create_PMU_service")
|
||||||
D110 = Callback(bool_, "create_iomfb_service")
|
D110 = Callback(bool_, "create_iomfb_service")
|
||||||
D111 = Callback(bool_, "create_backlight_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)
|
# FW version dependent Callback tags
|
||||||
D123 = Callback(bool_, "setDCPAVPropChunk", data=HexDump(SizedBytes(0x1000, "length")), offset=uint, length=uint)
|
create_nvram_service = Callback(bool_, "create_nvram_service") # guessed
|
||||||
D124 = Callback(bool_, "setDCPAVPropEnd", key=string(0x40))
|
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):
|
class UPPipe2(IPCObject):
|
||||||
A102 = Call(uint64_t, "test_control", cmd=uint64_t, arg=uint)
|
A102 = Call(uint64_t, "test_control", cmd=uint64_t, arg=uint)
|
||||||
|
@ -639,10 +681,9 @@ class PropRelay(IPCObject):
|
||||||
D300 = Callback(void, "pr_publish", prop_id=uint32_t, value=int_)
|
D300 = Callback(void, "pr_publish", prop_id=uint32_t, value=int_)
|
||||||
|
|
||||||
class IOMobileFramebufferAP(IPCObject):
|
class IOMobileFramebufferAP(IPCObject):
|
||||||
A401 = Call(uint32_t, "start_signal")
|
# FW version dependent Calls
|
||||||
|
if Ver.check("V < V13_2"):
|
||||||
A407 = Call(uint32_t, "swap_start", swap_id=InOutPtr(uint), client=InOutPtr(IOUserClient))
|
swap_submit_dcp = Call(uint32_t, "swap_submit_dcp",
|
||||||
A408 = Call(uint32_t, "swap_submit_dcp",
|
|
||||||
swap_rec=InPtr(IOMFBSwapRec),
|
swap_rec=InPtr(IOMFBSwapRec),
|
||||||
surfaces=Array(4, InPtr(IOSurface)),
|
surfaces=Array(4, InPtr(IOSurface)),
|
||||||
surfAddr=Array(4, Hex(ulong)),
|
surfAddr=Array(4, Hex(ulong)),
|
||||||
|
@ -650,11 +691,28 @@ class IOMobileFramebufferAP(IPCObject):
|
||||||
unkFloat=Float64l,
|
unkFloat=Float64l,
|
||||||
unkInt=uint,
|
unkInt=uint,
|
||||||
unkOutBool=OutPtr(bool_))
|
unkOutBool=OutPtr(bool_))
|
||||||
|
else:
|
||||||
|
swap_submit_dcp = Call(uint32_t, "swap_submit_dcp",
|
||||||
|
swap_rec=InPtr(IOMFBSwapRec),
|
||||||
|
surfaces=Array(SWAP_SURFACES, InPtr(IOSurface)),
|
||||||
|
surfAddr=Array(SWAP_SURFACES, Hex(ulong)),
|
||||||
|
unkU64Array=Array(SWAP_SURFACES, Hex(ulong)),
|
||||||
|
surfaces2=Array(5, InPtr(IOSurface)),
|
||||||
|
surfAddr2=Array(5, Hex(ulong)),
|
||||||
|
unkBool=bool_,
|
||||||
|
unkFloat=Float64l,
|
||||||
|
unkU64=ulong,
|
||||||
|
unkBool2=bool_,
|
||||||
|
unkInt=uint,
|
||||||
|
unkOutBool=OutPtr(bool_),
|
||||||
|
unkCUintArray=InPtr(uint),
|
||||||
|
unkUintPtr=OutPtr(uint))
|
||||||
|
|
||||||
|
A401 = Call(uint32_t, "start_signal")
|
||||||
|
A407 = Call(uint32_t, "swap_start", swap_id=InOutPtr(uint), client=InOutPtr(IOUserClient))
|
||||||
|
A408 = swap_submit_dcp
|
||||||
A410 = Call(uint32_t, "set_display_device", uint)
|
A410 = Call(uint32_t, "set_display_device", uint)
|
||||||
A411 = Call(bool_, "is_main_display")
|
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)
|
A412 = Call(uint32_t, "set_digital_out_mode", uint, uint)
|
||||||
A413 = Call(uint32_t, "get_digital_out_state", InOutPtr(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))
|
A426 = Call(uint32_t, "get_color_remap_mode", InOutPtr(uint32_t))
|
||||||
A427 = Call(uint32_t, "setBrightnessCorrection", uint)
|
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)
|
# FW version dependent Call tags
|
||||||
A439 = Call(uint32_t, "set_parameter_dcp", param=IOMFBParameterName, value=Lazy(SizedArray(4, "count", ulong)), count=uint)
|
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")
|
if Ver.check("V < V13_2"):
|
||||||
A441 = Call(uint, "display_height")
|
A435 = set_block_dcp
|
||||||
A442 = Call(void, "get_display_size", OutPtr(uint), OutPtr(uint))
|
A436 = get_block_dcp
|
||||||
A443 = Call(int_, "do_create_default_frame_buffer")
|
A438 = swap_set_color_matrix
|
||||||
A444 = Call(void, "printRegs")
|
A439 = set_parameter_dcp
|
||||||
A447 = Call(int_, "enable_disable_video_power_savings", uint)
|
A440 = display_width
|
||||||
A454 = Call(void, "first_client_open")
|
A441 = display_height
|
||||||
A455 = Call(void, "last_client_close_dcp", OutPtr(uint))
|
A442 = get_display_size
|
||||||
A456 = Call(bool_, "writeDebugInfo", ulong)
|
A443 = do_create_default_frame_buffer
|
||||||
A457 = Call(void, "flush_debug_flags", uint)
|
A444 = printRegs
|
||||||
A458 = Call(bool_, "io_fence_notify", uint, uint, ulong, IOMFBStatus)
|
A447 = enable_disable_video_power_savings
|
||||||
A460 = Call(bool_, "setDisplayRefreshProperties")
|
A454 = first_client_open
|
||||||
A463 = Call(void, "flush_supportsPower", bool_)
|
A455 = last_client_close_dcp
|
||||||
A464 = Call(uint, "abort_swaps_dcp", InOutPtr(IOMobileFramebufferUserClient))
|
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))
|
# FW version dependent callbacks
|
||||||
A468 = Call(uint32_t, "setPowerState", ulong, bool_, OutPtr(uint))
|
if Ver.check("V < V13_2"):
|
||||||
A469 = Call(bool_, "isKeepOnScreen")
|
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())))
|
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())))
|
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_)
|
D574 = Callback(IOMFBStatus, "powerUpDART", bool_)
|
||||||
|
|
||||||
D575 = Callback(bool_, "get_dot_pitch", OutPtr(uint))
|
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_)
|
D577 = Callback(void, "powerstate_notify", bool_, bool_)
|
||||||
D578 = Callback(bool_, "idle_fence_create", IdleCachingState)
|
D578 = Callback(bool_, "idle_fence_create", IdleCachingState)
|
||||||
D579 = Callback(void, "idle_fence_complete")
|
D579 = Callback(void, "idle_fence_complete")
|
||||||
|
@ -718,12 +829,18 @@ class IOMobileFramebufferAP(IPCObject):
|
||||||
D598 = Callback(void, "find_swap_function_gated")
|
D598 = Callback(void, "find_swap_function_gated")
|
||||||
|
|
||||||
class ServiceRelay(IPCObject):
|
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))
|
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))
|
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)
|
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)
|
D406 = Callback(void, "set_fx_prop", obj=FourCC, key=string(0x40), value=uint)
|
||||||
D408 = Callback(uint64_t, "sr_getClockFrequency", obj=FourCC, arg=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())))
|
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))
|
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)))
|
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)
|
method.print_long_args(indent, self.in_vals, self.out_vals)
|
||||||
#if len(method.out_fields) - (self.ret is not None):
|
#if len(method.out_fields) - (self.ret is not None):
|
||||||
#print(self.out_vals)
|
#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
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
from m1n1.utils import *
|
from m1n1.utils import *
|
||||||
|
from m1n1.constructutils import Ver
|
||||||
from m1n1.fw.dcp.ipc import *
|
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):
|
def parse_log(fd):
|
||||||
op_stack = {}
|
op_stack = {}
|
||||||
for line in fd:
|
for line in fd:
|
||||||
|
@ -17,6 +46,12 @@ def parse_log(fd):
|
||||||
op = op_stack[chan].pop()
|
op = op_stack[chan].pop()
|
||||||
assert int(off, 0) == op.off
|
assert int(off, 0) == op.off
|
||||||
op.ack(bytes.fromhex(out_data))
|
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:
|
else:
|
||||||
raise Exception(f"Unknown log cmd {optype}")
|
raise Exception(f"Unknown log cmd {optype}")
|
||||||
|
|
||||||
|
@ -27,8 +62,24 @@ def dump_log(fd):
|
||||||
"": 0,
|
"": 0,
|
||||||
"OOB": 0,
|
"OOB": 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handler = DCPAVPropHandler()
|
||||||
|
|
||||||
for op in parse_log(fd):
|
for op in parse_log(fd):
|
||||||
ctx = ""
|
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:
|
if "OOB" in op.chan:
|
||||||
ctx = "[OOB] -----------> "
|
ctx = "[OOB] -----------> "
|
||||||
if not op.complete:
|
if not op.complete:
|
||||||
|
|
|
@ -47,6 +47,14 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$initramfs" ]; then
|
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"
|
cat "$initramfs" >>"$TMPDIR/m1n1-linux.bin"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
322
src/afk.c
322
src/afk.c
|
@ -38,10 +38,6 @@ enum EPICCategory {
|
||||||
CAT_COMMAND = 0x30,
|
CAT_COMMAND = 0x30,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum EPICMessage {
|
|
||||||
CODE_ANNOUNCE = 0x30,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct afk_qe {
|
struct afk_qe {
|
||||||
u32 magic;
|
u32 magic;
|
||||||
u32 size;
|
u32 size;
|
||||||
|
@ -62,11 +58,12 @@ struct epic_sub_hdr {
|
||||||
u32 length;
|
u32 length;
|
||||||
u8 version;
|
u8 version;
|
||||||
u8 category;
|
u8 category;
|
||||||
u16 code;
|
u16 type;
|
||||||
u64 timestamp;
|
u64 timestamp;
|
||||||
u16 seq;
|
u16 seq;
|
||||||
u16 unk;
|
u8 unk;
|
||||||
u32 unk2;
|
u8 flags;
|
||||||
|
u32 inline_len;
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
struct epic_announce {
|
struct epic_announce {
|
||||||
|
@ -80,12 +77,21 @@ struct epic_cmd {
|
||||||
u64 txbuf;
|
u64 txbuf;
|
||||||
u32 rxlen;
|
u32 rxlen;
|
||||||
u32 txlen;
|
u32 txlen;
|
||||||
|
u16 pad;
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
|
#define AFK_MAX_CHANNEL 16
|
||||||
|
|
||||||
|
struct afk_epic {
|
||||||
|
rtkit_dev_t *rtk;
|
||||||
|
|
||||||
|
afk_epic_ep_t *endpoint[0x10];
|
||||||
|
};
|
||||||
|
|
||||||
struct afk_epic_ep {
|
struct afk_epic_ep {
|
||||||
int ep;
|
int ep;
|
||||||
rtkit_dev_t *rtk;
|
|
||||||
|
|
||||||
|
afk_epic_t *afk;
|
||||||
struct rtkit_buffer buf;
|
struct rtkit_buffer buf;
|
||||||
u16 tag;
|
u16 tag;
|
||||||
|
|
||||||
|
@ -96,6 +102,12 @@ struct afk_epic_ep {
|
||||||
struct rtkit_buffer rxbuf;
|
struct rtkit_buffer rxbuf;
|
||||||
|
|
||||||
bool started;
|
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 {
|
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;
|
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;
|
int ret;
|
||||||
struct rtkit_message msg;
|
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) {
|
if (ret < 0) {
|
||||||
|
@ -157,11 +169,22 @@ static int afk_epic_poll(afk_epic_ep_t *epic)
|
||||||
return ret;
|
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);
|
printf("EPIC: received message for unexpected endpoint %d\n", msg.ep);
|
||||||
return 0;
|
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);
|
int type = FIELD_GET(RBEP_TYPE, msg.msg);
|
||||||
u64 base, size, tag;
|
u64 base, size, tag;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -171,13 +194,13 @@ static int afk_epic_poll(afk_epic_ep_t *epic)
|
||||||
case RBEP_GETBUF:
|
case RBEP_GETBUF:
|
||||||
size = FIELD_GET(GETBUF_SIZE, msg.msg) << BLOCK_SHIFT;
|
size = FIELD_GET(GETBUF_SIZE, msg.msg) << BLOCK_SHIFT;
|
||||||
epic->tag = FIELD_GET(GETBUF_TAG, msg.msg);
|
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");
|
printf("EPIC: failed to allocate buffer\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
msg.msg = (FIELD_PREP(RBEP_TYPE, RBEP_GETBUF_ACK) |
|
msg.msg = (FIELD_PREP(RBEP_TYPE, RBEP_GETBUF_ACK) |
|
||||||
FIELD_PREP(GETBUF_ACK_DVA, epic->buf.dva));
|
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");
|
printf("EPIC: failed to send buffer address\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -204,7 +227,7 @@ static int afk_epic_poll(afk_epic_ep_t *epic)
|
||||||
|
|
||||||
if (epic->rx.ready && epic->tx.ready) {
|
if (epic->rx.ready && epic->tx.ready) {
|
||||||
msg.msg = FIELD_PREP(RBEP_TYPE, RBEP_START);
|
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");
|
printf("EPIC: failed to send start\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -212,7 +235,11 @@ static int afk_epic_poll(afk_epic_ep_t *epic)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RBEP_RECV:
|
case RBEP_RECV:
|
||||||
|
if (endpoint == epic->ep)
|
||||||
return 1;
|
return 1;
|
||||||
|
if (epic->recv_handler)
|
||||||
|
epic->recv_handler(epic);
|
||||||
|
break;
|
||||||
|
|
||||||
case RBEP_START_ACK:
|
case RBEP_START_ACK:
|
||||||
epic->started = true;
|
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;
|
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) {
|
while (rptr == rb->hdr->wptr) {
|
||||||
do {
|
do {
|
||||||
ret = afk_epic_poll(epic);
|
ret = afk_epic_poll(epic->afk, epic->ep, UINT32_MAX);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
} while (ret == 0);
|
} 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),
|
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");
|
printf("EPIC: failed to send TX WPTR message\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -345,8 +381,118 @@ static void afk_epic_rx_ack(afk_epic_ep_t *epic)
|
||||||
rb->hdr->rptr = rptr;
|
rb->hdr->rptr = rptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 code, void *txbuf, size_t txsize,
|
struct epic_std_service_ap_call {
|
||||||
void *rxbuf, size_t *rxsize)
|
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 {
|
||||||
struct epic_hdr hdr;
|
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));
|
memset(&msg, 0, sizeof(msg));
|
||||||
|
|
||||||
|
u32 tag = epic->seq;
|
||||||
|
|
||||||
msg.hdr.version = 2;
|
msg.hdr.version = 2;
|
||||||
msg.hdr.seq = 0;
|
msg.hdr.seq = epic->seq++;
|
||||||
msg.sub.length = sizeof(msg.cmd);
|
msg.sub.length = sizeof(msg.cmd);
|
||||||
msg.sub.version = 3;
|
msg.sub.version = 4;
|
||||||
msg.sub.category = CAT_COMMAND;
|
msg.sub.category = CAT_COMMAND;
|
||||||
msg.sub.code = code;
|
msg.sub.type = code;
|
||||||
msg.sub.seq = 0;
|
msg.sub.seq = sub_seq;
|
||||||
msg.cmd.txbuf = epic->txbuf.dva;
|
msg.cmd.txbuf = epic->txbuf.dva;
|
||||||
msg.cmd.txlen = txsize;
|
msg.cmd.txlen = txsize;
|
||||||
msg.cmd.rxbuf = epic->rxbuf.dva;
|
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_hdr *hdr = (void *)(rmsg + 1);
|
||||||
struct epic_sub_hdr *sub = (void *)(hdr + 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,
|
printf("EPIC: got unexpected message %02x:%04x during command\n", sub->category,
|
||||||
sub->code);
|
sub->type);
|
||||||
afk_epic_rx_ack(epic);
|
afk_epic_rx_ack(epic);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -424,7 +579,34 @@ int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 code, void *txbuf, si
|
||||||
return 0;
|
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));
|
afk_epic_ep_t *epic = malloc(sizeof(afk_epic_ep_t));
|
||||||
if (!epic)
|
if (!epic)
|
||||||
|
@ -432,21 +614,25 @@ afk_epic_ep_t *afk_epic_init(rtkit_dev_t *rtk, int endpoint)
|
||||||
|
|
||||||
memset(epic, 0, sizeof(*epic));
|
memset(epic, 0, sizeof(*epic));
|
||||||
epic->ep = endpoint;
|
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);
|
printf("EPIC: failed to start endpoint %d\n", endpoint);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct rtkit_message msg = {endpoint, FIELD_PREP(RBEP_TYPE, RBEP_INIT)};
|
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");
|
printf("EPIC: failed to send init message\n");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!epic->started) {
|
while (!epic->started) {
|
||||||
int ret = afk_epic_poll(epic);
|
int ret = afk_epic_poll(epic->afk, endpoint, UINT32_MAX);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
break;
|
break;
|
||||||
else if (ret > 0)
|
else if (ret > 0)
|
||||||
|
@ -456,33 +642,37 @@ afk_epic_ep_t *afk_epic_init(rtkit_dev_t *rtk, int endpoint)
|
||||||
return epic;
|
return epic;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
afk->endpoint[endpoint - 0x20] = NULL;
|
||||||
free(epic);
|
free(epic);
|
||||||
return NULL;
|
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)};
|
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");
|
printf("EPIC: failed to send shutdown message\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (epic->started) {
|
while (epic->started) {
|
||||||
int ret = afk_epic_poll(epic);
|
int ret = afk_epic_poll(epic->afk, epic->ep, UINT32_MAX);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtkit_free_buffer(epic->rtk, &epic->buf);
|
rtkit_free_buffer(epic->afk->rtk, &epic->buf);
|
||||||
rtkit_free_buffer(epic->rtk, &epic->rxbuf);
|
rtkit_free_buffer(epic->afk->rtk, &epic->rxbuf);
|
||||||
rtkit_free_buffer(epic->rtk, &epic->txbuf);
|
rtkit_free_buffer(epic->afk->rtk, &epic->txbuf);
|
||||||
|
|
||||||
|
epic->afk->endpoint[epic->ep - 0x20] = NULL;
|
||||||
|
|
||||||
free(epic);
|
free(epic);
|
||||||
return 0;
|
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;
|
int channel = -1;
|
||||||
struct afk_qe *msg;
|
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_hdr *hdr = (void *)(msg + 1);
|
||||||
struct epic_sub_hdr *sub = (void *)(hdr + 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,
|
printf("EPIC: got unexpected message %02x:%04x during iface start\n", sub->category,
|
||||||
sub->code);
|
sub->type);
|
||||||
afk_epic_rx_ack(epic);
|
afk_epic_rx_ack(epic);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -518,28 +708,74 @@ int afk_epic_start_interface(afk_epic_ep_t *epic, char *name, size_t txsize, siz
|
||||||
continue;
|
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;
|
channel = msg->channel;
|
||||||
break;
|
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) {
|
if (channel == -1) {
|
||||||
printf("EPIC: too many unexpected messages, giving up\n");
|
printf("EPIC: too many unexpected messages, giving up\n");
|
||||||
return -1;
|
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");
|
printf("EPIC: failed to allocate rx buffer\n");
|
||||||
return -1;
|
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");
|
printf("EPIC: failed to allocate tx buffer\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("EPIC: started interface %d (%s)\n", msg->channel, announce->name);
|
printf("EPIC: started interface %d (%s)\n", channel, name);
|
||||||
|
|
||||||
afk_epic_rx_ack(epic);
|
|
||||||
|
|
||||||
return channel;
|
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
|
#ifndef DCP_AFK_H
|
||||||
#define DCP_AFK_H
|
#define DCP_AFK_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "rtkit.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;
|
typedef struct afk_epic_ep afk_epic_ep_t;
|
||||||
|
|
||||||
afk_epic_ep_t *afk_epic_init(rtkit_dev_t *rtkit, int endpoint);
|
typedef struct afk_epic_service_ops afk_epic_service_ops_t;
|
||||||
int afk_epic_shutdown(afk_epic_ep_t *epic);
|
|
||||||
|
|
||||||
int afk_epic_start_interface(afk_epic_ep_t *epic, char *name, size_t insize, size_t outsize);
|
enum EPICMessage {
|
||||||
int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 code, void *txbuf, size_t txsize,
|
CODE_ANNOUNCE = 0x30,
|
||||||
void *rxbuf, size_t *rxsize);
|
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
|
#endif
|
||||||
|
|
|
@ -60,8 +60,15 @@ dcp_dev_t *dcp_init(const char *dcp_path, const char *dcp_dart_path, const char
|
||||||
goto out_iovad;
|
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;
|
return dcp;
|
||||||
|
|
||||||
|
out_rtkit:
|
||||||
rtkit_quiesce(dcp->rtkit);
|
rtkit_quiesce(dcp->rtkit);
|
||||||
rtkit_free(dcp->rtkit);
|
rtkit_free(dcp->rtkit);
|
||||||
out_iovad:
|
out_iovad:
|
||||||
|
@ -76,6 +83,7 @@ out_free:
|
||||||
|
|
||||||
int dcp_shutdown(dcp_dev_t *dcp, bool sleep)
|
int dcp_shutdown(dcp_dev_t *dcp, bool sleep)
|
||||||
{
|
{
|
||||||
|
afk_epic_shutdown(dcp->afk);
|
||||||
if (sleep) {
|
if (sleep) {
|
||||||
rtkit_sleep(dcp->rtkit);
|
rtkit_sleep(dcp->rtkit);
|
||||||
pmgr_reset(0, "DISP0_CPU0");
|
pmgr_reset(0, "DISP0_CPU0");
|
||||||
|
|
23
src/dcp.h
23
src/dcp.h
|
@ -3,16 +3,39 @@
|
||||||
#ifndef DCP_H
|
#ifndef DCP_H
|
||||||
#define DCP_H
|
#define DCP_H
|
||||||
|
|
||||||
|
#include "afk.h"
|
||||||
#include "asc.h"
|
#include "asc.h"
|
||||||
#include "dart.h"
|
#include "dart.h"
|
||||||
#include "rtkit.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 {
|
typedef struct {
|
||||||
dart_dev_t *dart_dcp;
|
dart_dev_t *dart_dcp;
|
||||||
dart_dev_t *dart_disp;
|
dart_dev_t *dart_disp;
|
||||||
iova_domain_t *iovad_dcp;
|
iova_domain_t *iovad_dcp;
|
||||||
asc_dev_t *asc;
|
asc_dev_t *asc;
|
||||||
rtkit_dev_t *rtkit;
|
rtkit_dev_t *rtkit;
|
||||||
|
afk_epic_t *afk;
|
||||||
|
|
||||||
|
dptx_port_t *port;
|
||||||
} dcp_dev_t;
|
} dcp_dev_t;
|
||||||
|
|
||||||
dcp_dev_t *dcp_init(const char *dcp_path, const char *dcp_dart_path, const char *disp_dart_path);
|
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;
|
return NULL;
|
||||||
|
|
||||||
iboot->dcp = dcp;
|
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) {
|
if (!iboot->epic) {
|
||||||
printf("dcp-iboot: failed to initialize EPIC\n");
|
printf("dcp-iboot: failed to initialize EPIC\n");
|
||||||
goto err_free;
|
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) {
|
if (iboot->channel < 0) {
|
||||||
printf("dcp-iboot: failed to initialize disp0 service\n");
|
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;
|
return iboot;
|
||||||
|
|
||||||
err_shutdown:
|
err_shutdown:
|
||||||
afk_epic_shutdown(iboot->epic);
|
afk_epic_shutdown_ep(iboot->epic);
|
||||||
err_free:
|
err_free:
|
||||||
free(iboot);
|
free(iboot);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -116,7 +117,7 @@ err_free:
|
||||||
|
|
||||||
int dcp_ib_shutdown(dcp_iboot_if_t *iboot)
|
int dcp_ib_shutdown(dcp_iboot_if_t *iboot)
|
||||||
{
|
{
|
||||||
afk_epic_shutdown(iboot->epic);
|
afk_epic_shutdown_ep(iboot->epic);
|
||||||
|
|
||||||
free(iboot);
|
free(iboot);
|
||||||
return 0;
|
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.op = op;
|
||||||
iboot->txcmd.len = sizeof(struct txcmd) + in_size;
|
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);
|
sizeof(struct txcmd) + in_size, iboot->rxbuf, &rxsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "xnuboot.h"
|
#include "xnuboot.h"
|
||||||
|
|
||||||
|
#include "dcp/dp_phy.h"
|
||||||
|
#include "dcp/dptxep.h"
|
||||||
|
|
||||||
#define DISPLAY_STATUS_DELAY 100
|
#define DISPLAY_STATUS_DELAY 100
|
||||||
#define DISPLAY_STATUS_RETRIES 20
|
#define DISPLAY_STATUS_RETRIES 20
|
||||||
|
|
||||||
|
@ -24,6 +27,7 @@
|
||||||
|
|
||||||
static dcp_dev_t *dcp;
|
static dcp_dev_t *dcp;
|
||||||
static dcp_iboot_if_t *iboot;
|
static dcp_iboot_if_t *iboot;
|
||||||
|
static dcp_dptx_if_t *dptx;
|
||||||
static u64 fb_dva;
|
static u64 fb_dva;
|
||||||
static u64 fb_size;
|
static u64 fb_size;
|
||||||
bool display_is_external;
|
bool display_is_external;
|
||||||
|
@ -199,6 +203,25 @@ int display_start_dcp(void)
|
||||||
return -1;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,6 +331,13 @@ int display_configure(const char *config)
|
||||||
int timing_cnt, color_cnt;
|
int timing_cnt, color_cnt;
|
||||||
int hpd = 0, retries = 0;
|
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
|
/* After boot DCP does not immediately report a connected display. Retry getting display
|
||||||
* information for 2 seconds.
|
* information for 2 seconds.
|
||||||
*/
|
*/
|
||||||
|
@ -369,12 +399,7 @@ int display_configure(const char *config)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_boot_args.mem_size -= size;
|
fb_pa = top_of_memory_alloc(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;
|
|
||||||
|
|
||||||
memset((void *)fb_pa, 0, size);
|
memset((void *)fb_pa, 0, size);
|
||||||
|
|
||||||
tmp_dva = iova_alloc(dcp->iovad_dcp, size);
|
tmp_dva = iova_alloc(dcp->iovad_dcp, size);
|
||||||
|
@ -469,6 +494,13 @@ int display_init(void)
|
||||||
return -1;
|
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);
|
display_is_external = adt_getprop(adt, node, "external", NULL);
|
||||||
if (display_is_external)
|
if (display_is_external)
|
||||||
printf("display: Display is external\n");
|
printf("display: Display is external\n");
|
||||||
|
@ -491,6 +523,8 @@ int display_init(void)
|
||||||
void display_shutdown(dcp_shutdown_mode mode)
|
void display_shutdown(dcp_shutdown_mode mode)
|
||||||
{
|
{
|
||||||
if (iboot) {
|
if (iboot) {
|
||||||
|
if (dptx)
|
||||||
|
dcp_dptx_shutdown(dptx);
|
||||||
dcp_ib_shutdown(iboot);
|
dcp_ib_shutdown(iboot);
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case DCP_QUIESCED:
|
case DCP_QUIESCED:
|
||||||
|
|
157
src/kboot.c
157
src/kboot.c
|
@ -14,6 +14,7 @@
|
||||||
#include "pcie.h"
|
#include "pcie.h"
|
||||||
#include "pmgr.h"
|
#include "pmgr.h"
|
||||||
#include "sep.h"
|
#include "sep.h"
|
||||||
|
#include "sio.h"
|
||||||
#include "smp.h"
|
#include "smp.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "usb.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;
|
return iova;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dt_device_set_reserved_mem(int node, dart_dev_t *dart, const char *name,
|
static int dt_device_set_reserved_mem(int node, const char *name, uint32_t phandle, u64 iova,
|
||||||
uint32_t phandle, u64 paddr, u64 size)
|
u64 size)
|
||||||
{
|
{
|
||||||
int ret;
|
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);
|
ret = fdt_appendprop_u32(dt, node, "iommu-addresses", phandle);
|
||||||
if (ret != 0)
|
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);
|
ret = fdt_appendprop_u64(dt, node, "iommu-addresses", iova);
|
||||||
if (ret != 0)
|
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;
|
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,
|
static int dt_get_or_add_reserved_mem(const char *node_name, const char *compat, u64 paddr,
|
||||||
size_t size)
|
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)
|
if (dev_node < 0)
|
||||||
bail("DT: failed to update node for alias '%s'\n", alias);
|
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);
|
ret = fdt_appendprop_string(dt, dev_node, "memory-region-names", name);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
bail("DT: failed to append to 'memory-region-names' property\n");
|
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);
|
uint32_t mem_phandle = fdt_get_phandle(dt, mem_node);
|
||||||
|
|
||||||
if (maps[i].map_dcp && dart_dcp) {
|
if (maps[i].map_dcp && dart_dcp) {
|
||||||
ret = dt_device_set_reserved_mem(mem_node, dart_dcp, node_name, dcp_phandle,
|
ret = dt_device_set_reserved_mem_from_dart(mem_node, dart_dcp, node_name, dcp_phandle,
|
||||||
region[i].paddr, region[i].size);
|
region[i].paddr, region[i].size);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if (maps[i].map_disp && dart_disp) {
|
if (maps[i].map_disp && dart_disp) {
|
||||||
ret = dt_device_set_reserved_mem(mem_node, dart_disp, node_name, disp_phandle,
|
ret = dt_device_set_reserved_mem_from_dart(mem_node, dart_disp, node_name, disp_phandle,
|
||||||
region[i].paddr, region[i].size);
|
region[i].paddr, region[i].size);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if (maps[i].map_piodma && dart_piodma) {
|
if (maps[i].map_piodma && dart_piodma) {
|
||||||
ret = dt_device_set_reserved_mem(mem_node, dart_piodma, node_name, piodma_phandle,
|
ret = dt_device_set_reserved_mem_from_dart(
|
||||||
region[i].paddr, region[i].size);
|
mem_node, dart_piodma, node_name, piodma_phandle, region[i].paddr, region[i].size);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
goto err;
|
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);
|
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[] = {
|
static struct disp_mapping disp_reserved_regions_t8103[] = {
|
||||||
{"region-id-50", "dcp_data", true, false, false},
|
{"region-id-50", "dcp_data", true, false, false},
|
||||||
{"region-id-57", "region57", 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");
|
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)
|
static int dt_disable_missing_devs(const char *adt_prefix, const char *dt_prefix, int max_devs)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
@ -1952,6 +2083,10 @@ int kboot_prepare_dt(void *fdt)
|
||||||
return -1;
|
return -1;
|
||||||
if (dt_disable_missing_devs("i2c", "i2c@", 8))
|
if (dt_disable_missing_devs("i2c", "i2c@", 8))
|
||||||
return -1;
|
return -1;
|
||||||
|
if (dt_reserve_asc_firmware("/arm-io/sio", "/soc/sio"))
|
||||||
|
return -1;
|
||||||
|
if (dt_set_sio_fwdata())
|
||||||
|
return -1;
|
||||||
#ifndef RELEASE
|
#ifndef RELEASE
|
||||||
if (dt_transfer_virtios())
|
if (dt_transfer_virtios())
|
||||||
return 1;
|
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 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 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 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 const u8 empty[] = {0, 0, 0, 0};
|
||||||
|
|
||||||
static char expect_compatible[256];
|
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);
|
printf("Found a m1n1 signature at %p, skipping 0x%x bytes\n", p, size);
|
||||||
return 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)) {
|
} else if (check_var(&p)) {
|
||||||
return p;
|
return p;
|
||||||
} else if (!memcmp(p, empty, sizeof empty) ||
|
} 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)
|
int rtkit_recv(rtkit_dev_t *rtk, struct rtkit_message *msg)
|
||||||
{
|
{
|
||||||
struct asc_message asc_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_start_ep(rtkit_dev_t *rtk, u8 ep);
|
||||||
bool rtkit_boot(rtkit_dev_t *rtk);
|
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);
|
int rtkit_recv(rtkit_dev_t *rtk, struct rtkit_message *msg);
|
||||||
bool rtkit_send(rtkit_dev_t *rtk, const 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;
|
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);
|
void deep_wfi(void);
|
||||||
|
|
||||||
bool is_heap(void *addr);
|
bool is_heap(void *addr);
|
||||||
|
u64 top_of_memory_alloc(size_t size);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue