From 988c1c83ea7e13142609897f991e16c73e541bc9 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 28 Aug 2023 21:45:46 +0200 Subject: [PATCH 01/21] display: Use dcp iboot SetSurface instead of SwapLayer iboot uses this and it's simpler. m1n1 doesn't need to swap surfaces for tear free display. Signed-off-by: Janne Grunau --- src/dcp_iboot.c | 9 +++++++++ src/dcp_iboot.h | 1 + src/display.c | 18 +++--------------- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/dcp_iboot.c b/src/dcp_iboot.c index a3ede720f..b76f21278 100644 --- a/src/dcp_iboot.c +++ b/src/dcp_iboot.c @@ -44,6 +44,7 @@ struct dcp_iboot_if { }; enum IBootCmd { + IBOOT_SET_SURFACE = 1, IBOOT_SET_POWER = 2, IBOOT_GET_HPD = 3, IBOOT_GET_TIMING_MODES = 4, @@ -146,6 +147,14 @@ static int dcp_ib_cmd(dcp_iboot_if_t *iboot, int op, size_t in_size) sizeof(struct txcmd) + in_size, iboot->rxbuf, &rxsize); } +int dcp_ib_set_surface(dcp_iboot_if_t *iboot, dcp_layer_t *layer) +{ + dcp_layer_t *cmd = (void *)iboot->txcmd.payload; + *cmd = *layer; + + return dcp_ib_cmd(iboot, IBOOT_SET_SURFACE, sizeof(*layer)); +} + int dcp_ib_set_power(dcp_iboot_if_t *iboot, bool power) { u32 *pwr = (void *)iboot->txcmd.payload; diff --git a/src/dcp_iboot.h b/src/dcp_iboot.h index adb449e37..c0fc5225d 100644 --- a/src/dcp_iboot.h +++ b/src/dcp_iboot.h @@ -98,6 +98,7 @@ typedef struct { dcp_iboot_if_t *dcp_ib_init(dcp_dev_t *dcp); int dcp_ib_shutdown(dcp_iboot_if_t *iboot); +int dcp_ib_set_surface(dcp_iboot_if_t *iboot, dcp_layer_t *layer); int dcp_ib_set_power(dcp_iboot_if_t *iboot, bool power); int dcp_ib_get_hpd(dcp_iboot_if_t *iboot, int *timing_cnt, int *color_cnt); int dcp_ib_get_timing_modes(dcp_iboot_if_t *iboot, dcp_timing_mode_t **modes); diff --git a/src/display.c b/src/display.c index 70864a3fb..73d4d4da6 100644 --- a/src/display.c +++ b/src/display.c @@ -250,11 +250,6 @@ int display_parse_mode(const char *config, dcp_timing_mode_t *mode, struct displ static int display_swap(u64 iova, u32 stride, u32 width, u32 height) { int ret; - int swap_id = ret = dcp_ib_swap_begin(iboot); - if (swap_id < 0) { - printf("display: failed to start swap\n"); - return -1; - } dcp_layer_t layer = { .planes = {{ @@ -271,19 +266,12 @@ static int display_swap(u64 iova, u32 stride, u32 width, u32 height) .transform = XFRM_NONE, }; - dcp_rect_t rect = {width, height, 0, 0}; - - if ((ret = dcp_ib_swap_set_layer(iboot, 0, &layer, &rect, &rect)) < 0) { - printf("display: failed to set layer\n"); + if ((ret = dcp_ib_set_surface(iboot, &layer)) < 0) { + printf("display: failed to set surface\n"); return -1; } - if ((ret = dcp_ib_swap_end(iboot)) < 0) { - printf("display: failed to complete swap\n"); - return -1; - } - - return swap_id; + return 0; } int display_configure(const char *config) From 6b24255c8c60745224df89252c8e6db4c62a9c68 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 30 Aug 2023 00:40:43 +0200 Subject: [PATCH 02/21] rtkit: Add rtkit_can_recv() Required non-blocking handling of multiple AFK endpoints for the same mailbox. Signed-off-by: Janne Grunau --- src/rtkit.c | 8 ++++++++ src/rtkit.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/rtkit.c b/src/rtkit.c index 7e22b0a71..5528cebf0 100644 --- a/src/rtkit.c +++ b/src/rtkit.c @@ -345,6 +345,14 @@ static void rtkit_crashed(rtkit_dev_t *rtk) } } +bool rtkit_can_recv(rtkit_dev_t *rtk) +{ + if (rtk->crashed) + return false; + + return asc_can_recv(rtk->asc); +} + int rtkit_recv(rtkit_dev_t *rtk, struct rtkit_message *msg) { struct asc_message asc_msg; diff --git a/src/rtkit.h b/src/rtkit.h index 9d87ee19a..dcefcd9ca 100644 --- a/src/rtkit.h +++ b/src/rtkit.h @@ -31,6 +31,8 @@ void rtkit_free(rtkit_dev_t *rtk); bool rtkit_start_ep(rtkit_dev_t *rtk, u8 ep); bool rtkit_boot(rtkit_dev_t *rtk); +bool rtkit_can_recv(rtkit_dev_t *rtk); + int rtkit_recv(rtkit_dev_t *rtk, struct rtkit_message *msg); bool rtkit_send(rtkit_dev_t *rtk, const struct rtkit_message *msg); From b1578033b4253f6cdf7c4eddd0cc6d7cbfd0d385 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 2 Sep 2023 15:05:52 +0200 Subject: [PATCH 03/21] dart: limit vm-base to 36-bit io address space Required for t602x dcp*. Signed-off-by: Janne Grunau --- src/dart.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dart.c b/src/dart.c index ff4819ea4..907cc15bd 100644 --- a/src/dart.c +++ b/src/dart.c @@ -324,6 +324,8 @@ dart_dev_t *dart_init_adt(const char *path, int instance, int device, bool keep_ } if (ADT_GETPROP(adt, node, "vm-base", &dart->vm_base) < 0) dart->vm_base = 0; + else + dart->vm_base &= (1LLU << 36) - 1; return dart; } From 5a939c68fd265f0ccc54840bf12ce441fa2a9bf7 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 31 Jan 2023 14:03:52 +0100 Subject: [PATCH 04/21] dcp/parser: Add parser from linux DCP required for parsing dcp AFK/EPIC Signed-off-by: Janne Grunau --- Makefile | 8 +- src/dcp/parser.c | 273 +++++++++++++++++++++++++++++++++++++++++++++++ src/dcp/parser.h | 18 ++++ 3 files changed, 297 insertions(+), 2 deletions(-) create mode 100644 src/dcp/parser.c create mode 100644 src/dcp/parser.h diff --git a/Makefile b/Makefile index 5ada7a245..655155c10 100644 --- a/Makefile +++ b/Makefile @@ -73,6 +73,9 @@ LIBFDT_OBJECTS := $(patsubst %,libfdt/%, \ fdt_addresses.o fdt_empty_tree.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_sw.o \ fdt_wip.o fdt.o) +DCP_OBJECTS := $(patsubst %,dcp/%, \ + parser.o) + OBJECTS := \ adt.o \ afk.o \ @@ -129,6 +132,7 @@ OBJECTS := \ utils.o utils_asm.o \ vsprintf.o \ wdt.o \ + $(DCP_OBJECTS) \ $(MINILZLIB_OBJECTS) $(TINF_OBJECTS) $(DLMALLOC_OBJECTS) $(LIBFDT_OBJECTS) $(RUST_LIBS) FP_OBJECTS := \ @@ -152,9 +156,9 @@ all: update_tag update_cfg build/$(TARGET) build/$(TARGET_RAW) clean: rm -rf build/* format: - $(CLANG_FORMAT) -i src/*.c src/math/*.c src/*.h src/math/*.h sysinc/*.h + $(CLANG_FORMAT) -i src/*.c src/dcp/*.c src/math/*.c src/*.h src/dcp/*.h src/math/*.h sysinc/*.h format-check: - $(CLANG_FORMAT) --dry-run --Werror src/*.c src/*.h sysinc/*.h + $(CLANG_FORMAT) --dry-run --Werror src/*.c src/*.h src/dcp/*.c src/dcp/*.h sysinc/*.h rustfmt: cd rust && cargo fmt rustfmt-check: diff --git a/src/dcp/parser.c b/src/dcp/parser.c new file mode 100644 index 000000000..d721fda2e --- /dev/null +++ b/src/dcp/parser.c @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright 2021 Alyssa Rosenzweig */ + +#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; +} + +// currently unused +#if 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; +} +#endif + +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, char **name, 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; +} diff --git a/src/dcp/parser.h b/src/dcp/parser.h new file mode 100644 index 000000000..394eaa6d9 --- /dev/null +++ b/src/dcp/parser.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright 2021 Alyssa Rosenzweig */ + +#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, char **name, char **class, s64 *unit); + +#endif From 16af84925cb8d2358f66a8380002a1920d16036b Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 1 Feb 2023 14:08:35 +0100 Subject: [PATCH 05/21] dcp: Add (lp)dptx-phy support for M2* desktops Phy "implementation" is simplified a replay of a macos trace with on t8112 with a 1920x1080 display. Signed-off-by: Janne Grunau --- Makefile | 1 + src/dcp/dptx_phy.c | 514 +++++++++++++++++++++++++++++++++++++++++++++ src/dcp/dptx_phy.h | 19 ++ 3 files changed, 534 insertions(+) create mode 100644 src/dcp/dptx_phy.c create mode 100644 src/dcp/dptx_phy.h diff --git a/Makefile b/Makefile index 655155c10..d010056eb 100644 --- a/Makefile +++ b/Makefile @@ -74,6 +74,7 @@ LIBFDT_OBJECTS := $(patsubst %,libfdt/%, \ fdt_wip.o fdt.o) DCP_OBJECTS := $(patsubst %,dcp/%, \ + dptx_phy.o \ parser.o) OBJECTS := \ diff --git a/src/dcp/dptx_phy.c b/src/dcp/dptx_phy.c new file mode 100644 index 000000000..8e2f6149d --- /dev/null +++ b/src/dcp/dptx_phy.c @@ -0,0 +1,514 @@ +/* SPDX-License-Identifier: MIT */ + +#include "dptx_phy.h" +#include "malloc.h" + +#include "../adt.h" +#include "../utils.h" + +#define DPTX_MAX_LANES 4 + +enum dptx_type { + DPTX_PHY_T8112, + DPTX_PHY_T602X, +}; + +typedef struct dptx_phy { + u64 regs[2]; + enum dptx_type type; + u32 dcp_index; + u32 active_lanes; +} dptx_phy_t; + +int dptx_phy_activate(dptx_phy_t *phy) +{ + // MMIO: R.4 0x23c500010 (dptx-phy[1], offset 0x10) = 0x0 + // MMIO: W.4 0x23c500010 (dptx-phy[1], offset 0x10) = 0x0 + read32(phy->regs[1] + 0x10); + write32(phy->regs[1] + 0x10, phy->dcp_index); + + // 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); + + dptx_phy_set_active_lane_count(phy, 0); + + // 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); + + return 0; +} + +int dptx_phy_set_active_lane_count(dptx_phy_t *phy, u32 num_lanes) +{ + u32 l; + + printf("DPTX-PHY: set_active_lane_count(%u) phy_regs = {0x%lx, 0x%lx}\n", num_lanes, + phy->regs[0], phy->regs[1]); + + if (num_lanes == 3 || num_lanes > DPTX_MAX_LANES) + return -1; + + u32 ctrl = read32(phy->regs[0] + 0x4000); + write32(phy->regs[0] + 0x4000, ctrl); + + for (l = 0; l < num_lanes; l++) { + u64 offset = 0x5000 + 0x1000 * l; + read32(phy->regs[0] + offset); + write32(phy->regs[0] + offset, 0x100); + } + for (; l < DPTX_MAX_LANES; l++) { + u64 offset = 0x5000 + 0x1000 * l; + read32(phy->regs[0] + offset); + write32(phy->regs[0] + offset, 0x300); + } + for (l = 0; l < num_lanes; l++) { + u64 offset = 0x5000 + 0x1000 * l; + read32(phy->regs[0] + offset); + write32(phy->regs[0] + offset, 0x0); + } + for (; l < DPTX_MAX_LANES; l++) { + u64 offset = 0x5000 + 0x1000 * l; + read32(phy->regs[0] + offset); + write32(phy->regs[0] + offset, 0x300); + } + + if (num_lanes > 0) { + // clear32(phy->regs[0] + 0x4000, 0x4000000); + ctrl = read32(phy->regs[0] + 0x4000); + ctrl &= ~0x4000000; + write32(phy->regs[0] + 0x4000, ctrl); + } + phy->active_lanes = num_lanes; + + return 0; +} + +int dptx_phy_set_link_rate(dptx_phy_t *phy, u32 link_rate) +{ + UNUSED(link_rate); + // 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); + // 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; +} + +u32 dptx_phy_dcp_output(dptx_phy_t *phy) +{ + switch (phy->type) { + case DPTX_PHY_T8112: + return 5; + case DPTX_PHY_T602X: + return 4; + default: + return 5; + } +} + +dptx_phy_t *dptx_phy_init(const char *phy_node, u32 dcp_index) +{ + enum dptx_type type; + 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; + } + + if (adt_is_compatible(adt, node, "dptx-phy,t8112")) + type = DPTX_PHY_T8112; + else if (adt_is_compatible(adt, node, "dptx-phy,t602x")) + type = DPTX_PHY_T602X; + else { + printf("DPtx-phy: dptx-phy node %s is not compatible\n", phy_node); + return NULL; + } + + dptx_phy_t *phy = calloc(sizeof *phy, 1); + if (!phy) + return NULL; + + phy->type = type; + phy->dcp_index = dcp_index; + + 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); +} diff --git a/src/dcp/dptx_phy.h b/src/dcp/dptx_phy.h new file mode 100644 index 000000000..731654089 --- /dev/null +++ b/src/dcp/dptx_phy.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: MIT */ + +#ifndef DCP_DPTX_PHY_H +#define DCP_DPTX_PHY_H + +#include "../types.h" + +typedef struct dptx_phy dptx_phy_t; + +int dptx_phy_activate(dptx_phy_t *phy); +int dptx_phy_set_active_lane_count(dptx_phy_t *phy, u32 num_lanes); +int dptx_phy_set_link_rate(dptx_phy_t *phy, u32 link_rate); + +u32 dptx_phy_dcp_output(dptx_phy_t *phy); + +dptx_phy_t *dptx_phy_init(const char *phy_path, u32 dcp_index); +void dptx_phy_shutdown(dptx_phy_t *phy); + +#endif /* DCP_DPTX_PHY_H */ From a1ac36e04eb243615afc7495d1451ce94b6380cb Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 2 Sep 2023 10:14:52 +0200 Subject: [PATCH 06/21] dcp: dptx-phy: rewrite dptx_phy_activate() for dptx/lpdptx-phy Signed-off-by: Janne Grunau --- src/dcp/dptx_phy.c | 165 ++++++++++++++++++++------------------------- 1 file changed, 73 insertions(+), 92 deletions(-) diff --git a/src/dcp/dptx_phy.c b/src/dcp/dptx_phy.c index 8e2f6149d..a601e37d7 100644 --- a/src/dcp/dptx_phy.c +++ b/src/dcp/dptx_phy.c @@ -6,7 +6,10 @@ #include "../adt.h" #include "../utils.h" -#define DPTX_MAX_LANES 4 +#define DPTX_MAX_LANES 4 +#define DPTX_LANE0_OFFSET 0x5000 +#define DPTX_LANE_STRIDE 0x1000 +#define DPTX_LANE_END (DPTX_LANE0_OFFSET + DPTX_MAX_LANES * DPTX_LANE_STRIDE) enum dptx_type { DPTX_PHY_T8112, @@ -28,157 +31,135 @@ int dptx_phy_activate(dptx_phy_t *phy) write32(phy->regs[1] + 0x10, phy->dcp_index); // 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); + set32(phy->regs[1] + 0x48, 0x010); // 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); + set32(phy->regs[1] + 0x48, 0x020); // 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); + clear32(phy->regs[1] + 0x48, 0x040); // 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); + set32(phy->regs[1] + 0x48, 0x100); // 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); + set32(phy->regs[1] + 0x48, 0x200); // 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); + clear32(phy->regs[1] + 0x48, 0x400); // 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); + set32(phy->regs[1] + 0x48, 0x001); // 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); + set32(phy->regs[1] + 0x48, 0x002); // 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); + clear32(phy->regs[1] + 0x48, 0x004); + // MMIO: R.4 0x23c542014 (dptx-phy[0], offset 0x2014) = 0x80a0c - read32(phy->regs[0] + 0x2014); + u32 val_2014 = read32(phy->regs[0] + 0x2014); // MMIO: W.4 0x23c542014 (dptx-phy[0], offset 0x2014) = 0x300a0c - write32(phy->regs[0] + 0x2014, 0x300a0c); + write32(phy->regs[0] + 0x2014, (0x30 << 16) | (val_2014 & 0xffff)); + // 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); + set32(phy->regs[0] + 0x20b8, 0x010000); + // 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); + clear32(phy->regs[0] + 0x2220, 0x0000002); + // 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); + set32(phy->regs[0] + 0x222c, 0x000800); // 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); + set32(phy->regs[0] + 0x222c, 0x000100); + // 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); + clear32(phy->regs[0] + 0x2230, 0x0100000); + // 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); + clear32(phy->regs[0] + 0x2278, 0x08000000); + // 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); + set32(phy->regs[0] + 0x22a4, 0x0000001); + // MMIO: R.4 0x23c544008 (dptx-phy[0], offset 0x4008) = 0x18030 - read32(phy->regs[0] + 0x4008); + u32 val_4008 = read32(phy->regs[0] + 0x4008); // MMIO: W.4 0x23c544008 (dptx-phy[0], offset 0x4008) = 0x30030 - write32(phy->regs[0] + 0x4008, 0x30030); + write32(phy->regs[0] + 0x4008, (0x6 << 15) | (val_4008 & 0x7fff)); // 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); + clear32(phy->regs[0] + 0x4008, 0x00020); + // 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); + clear32(phy->regs[0] + 0x420c, 0x0020); + // 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); + set32(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); + for (u32 loff = DPTX_LANE0_OFFSET; loff < DPTX_LANE_END; loff += DPTX_LANE_STRIDE) + set32(phy->regs[0] + loff + 0x40, 0x200000); + // 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); + for (u32 loff = DPTX_LANE0_OFFSET; loff < DPTX_LANE_END; loff += DPTX_LANE_STRIDE) + set32(phy->regs[0] + loff + 0x40, 0x080000); + // 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); + for (u32 loff = DPTX_LANE0_OFFSET; loff < DPTX_LANE_END; loff += DPTX_LANE_STRIDE) + clear32(phy->regs[0] + loff + 0x244, 0x10); + // 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); + set32(phy->regs[0] + 0x2214, 0x001); + // 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); + clear32(phy->regs[0] + 0x2224, 0x00000001); + // 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); + set32(phy->regs[0] + 0x2200, 0x0002); + // 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); + clear32(phy->regs[0] + 0x1000, 0x00000002); + // 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); + set32(phy->regs[0] + 0x4004, 0x08); + + /* TODO: no idea what happens here, supposedly setting/clearing some bits */ // 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 @@ -191,35 +172,35 @@ int dptx_phy_activate(dptx_phy_t *phy) dptx_phy_set_active_lane_count(phy, 0); // 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); + clear32(phy->regs[0] + 0x4200, 0x0000010); + // 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); + clear32(phy->regs[0] + 0x4600, 0x0000001); // 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); + set32(phy->regs[0] + 0x4600, 0x0000001); // 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); + set32(phy->regs[0] + 0x4600, 0x0000002); // 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); + /* TODO: read first to check if the previous set(...,0x2) sticked? */ + read32(phy->regs[0] + 0x4600); + clear32(phy->regs[0] + 0x4600, 0x0000001); + // 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); + /* TODO: probably a set32 of an already set bit */ + u32 val_4408 = read32(phy->regs[0] + 0x4408); + if (val_4408 != 0x482 && val_4408 != 0x483) + printf("DPTX-PHY: unexpected initial value at regs[0] offset 0x4408: 0x%03x\n", val_4408); + write32(phy->regs[0] + 0x4408, val_4408); // 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); + set32(phy->regs[0] + 0x4408, 0x001); return 0; } From 74f427b3024934b56df107f4d2004dc90e3ac537 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 2 Sep 2023 10:14:52 +0200 Subject: [PATCH 07/21] dcp: dptx-phy: make dptx_phy_set_link_rate() SoC independent Signed-off-by: Janne Grunau --- src/dcp/dptx_phy.c | 190 ++++++++++++++++++++++++--------------------- 1 file changed, 102 insertions(+), 88 deletions(-) diff --git a/src/dcp/dptx_phy.c b/src/dcp/dptx_phy.c index a601e37d7..59442169b 100644 --- a/src/dcp/dptx_phy.c +++ b/src/dcp/dptx_phy.c @@ -253,182 +253,196 @@ int dptx_phy_set_active_lane_count(dptx_phy_t *phy, u32 num_lanes) int dptx_phy_set_link_rate(dptx_phy_t *phy, u32 link_rate) { UNUSED(link_rate); + u32 sts_1008, sts_1014; + // 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); + set32(phy->regs[0] + 0x4004, 0x08); + // 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); + clear32(phy->regs[0] + 0x4000, 0x0000040); + // 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); + clear32(phy->regs[0] + 0x4004, 0x08); + // 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); - // regs[0] + 0x4000, 0x2000000); // 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); + set32(phy->regs[0] + 0x4000, 0x1000000); + // 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); + /* TODO: what is this read checking for? */ + read32(phy->regs[0] + 0x2200); + clear32(phy->regs[0] + 0x2200, 0x0002); + // 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); + /* TODO: what is the setting/clearing? */ + u32 val_100c = read32(phy->regs[0] + 0x100c); + write32(phy->regs[0] + 0x100c, val_100c); + set32(phy->regs[0] + 0x100c, 0x0008); + // MMIO: R.4 0x23c541014 (dptx-phy[0], offset 0x1014) = 0x1 - read32(phy->regs[0] + 0x1014); + sts_1014 = read32(phy->regs[0] + 0x1014); + UNUSED(sts_1014); /* TODO: assert(sts_1014 == 0x1); */ + // 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); + clear32(phy->regs[0] + 0x100c, 0x0008); + // MMIO: R.4 0x23c541008 (dptx-phy[0], offset 0x1008) = 0x1 - read32(phy->regs[0] + 0x1008); + sts_1008 = read32(phy->regs[0] + 0x1008); + UNUSED(sts_1008); /* TODO: assert(sts_1008 == 0x1); */ + // 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); + clear32(phy->regs[0] + 0x2220, 0x0000080); + // 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); + u32 val_20b0 = read32(phy->regs[0] + 0x20b0); + /* TODO: what happens on dptx-phy */ + if (phy->type == DPTX_PHY_T602X) + val_20b0 = (val_20b0 & ~0x3ff) | 0x2a3; + write32(phy->regs[0] + 0x20b0, val_20b0); + // 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); + u32 val_20b4 = read32(phy->regs[0] + 0x20b4); + /* TODO: what happens on dptx-phy */ + if (phy->type == DPTX_PHY_T602X) + val_20b4 = (val_20b4 | 0x4000000) & ~0x0008000; + write32(phy->regs[0] + 0x20b4, val_20b4); + // 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); + val_20b4 = read32(phy->regs[0] + 0x20b4); + /* TODO: what happens on dptx-phy */ + if (phy->type == DPTX_PHY_T602X) + val_20b4 = (val_20b4 | 0x0000001) & ~0x0000004; + write32(phy->regs[0] + 0x20b4, val_20b4); + // 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); + /* TODO: unclear */ + set32(phy->regs[0] + 0x20b8, 0); // 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); + /* TODO: unclear */ + set32(phy->regs[0] + 0x20b8, 0); // 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); + /* TODO: unclear */ + if (phy->type == DPTX_PHY_T602X) + set32(phy->regs[0] + 0x20b8, 0x010000); + else + set32(phy->regs[0] + 0x20b8, 0); // 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); + clear32(phy->regs[0] + 0x20b8, 0x200000); + // 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); + /* TODO: unclear */ + set32(phy->regs[0] + 0x20b8, 0); + // 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); + set32(phy->regs[1] + 0xa0, 0x8); + set32(phy->regs[1] + 0xa0, 0x4); + set32(phy->regs[1] + 0xa0, 0x40000); + clear32(phy->regs[1] + 0xa0, 0x40000); + set32(phy->regs[1] + 0xa0, 0x80000); + clear32(phy->regs[1] + 0xa0, 0x80000); + clear32(phy->regs[1] + 0xa0, 0x4); + clear32(phy->regs[1] + 0xa0, 0x8); + // 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); + /* TODO: unclear */ + set32(phy->regs[0] + 0x2000, 0x0); + // 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); + clear32(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); + set32(phy->regs[0] + 0x100c, 0x0007); // 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); + set32(phy->regs[0] + 0x100c, 0x0008); + // MMIO: R.4 0x23c541014 (dptx-phy[0], offset 0x1014) = 0x38f - read32(phy->regs[0] + 0x1014); + sts_1014 = read32(phy->regs[0] + 0x1014); + /* TODO: assert(sts_1014 == 0x38f); */ + // 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); + clear32(phy->regs[0] + 0x100c, 0x0008); + // MMIO: R.4 0x23c541008 (dptx-phy[0], offset 0x1008) = 0x9 - read32(phy->regs[0] + 0x1008); + sts_1008 = read32(phy->regs[0] + 0x1008); + /* TODO: assert(sts_1008 == 0x9); */ + // 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); + set32(phy->regs[0] + 0x2200, 0x0002); + // 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); + for (u32 loff = DPTX_LANE0_OFFSET; loff < DPTX_LANE_END; loff += DPTX_LANE_STRIDE) { + u32 val_l010 = read32(phy->regs[0] + loff + 0x10); + write32(phy->regs[0] + loff + 0x10, val_l010); + } + // 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); + set32(phy->regs[0] + 0x4000, 0x1000000); // 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); + set32(phy->regs[0] + 0x4000, 0x2000000); + // 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); + set32(phy->regs[0] + 0x4004, 0x08); + // 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); + set32(phy->regs[0] + 0x4000, 0x0000040); + // 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); + clear32(phy->regs[0] + 0x4004, 0x01); return 0; } From ab72df18e5c78d5bd2e7f399935f8d39b505fdfa Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 30 Aug 2023 08:33:48 +0200 Subject: [PATCH 08/21] afk: Sync structs/names with proxyclient's python definitions Signed-off-by: Janne Grunau --- src/afk.c | 25 ++++++++++++++----------- src/afk.h | 2 +- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/afk.c b/src/afk.c index aa62edff5..b8db14bf6 100644 --- a/src/afk.c +++ b/src/afk.c @@ -38,7 +38,7 @@ enum EPICCategory { }; enum EPICMessage { - CODE_ANNOUNCE = 0x30, + SUBTYPE_ANNOUNCE = 0x30, }; struct afk_qe { @@ -61,11 +61,12 @@ struct epic_sub_hdr { u32 length; u8 version; u8 category; - u16 code; + u16 type; u64 timestamp; u16 seq; - u16 unk; - u32 unk2; + u8 unk; + u8 flags; + u32 inline_len; } PACKED; struct epic_announce { @@ -79,6 +80,8 @@ struct epic_cmd { u64 txbuf; u32 rxlen; u32 txlen; + u8 rxcookie; + u8 txcookie; } PACKED; struct afk_epic_ep { @@ -347,7 +350,7 @@ static void afk_epic_rx_ack(afk_epic_ep_t *epic) rb->hdr->rptr = rptr; } -int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 code, void *txbuf, size_t txsize, +int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 sub_type, void *txbuf, size_t txsize, void *rxbuf, size_t *rxsize) { struct { @@ -364,9 +367,9 @@ int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 code, void *txbuf, si msg.hdr.version = 2; msg.hdr.seq = 0; msg.sub.length = sizeof(msg.cmd); - msg.sub.version = 3; + msg.sub.version = 4; msg.sub.category = CAT_COMMAND; - msg.sub.code = code; + msg.sub.type = sub_type; msg.sub.seq = 0; msg.cmd.txbuf = epic->txbuf.dva; msg.cmd.txlen = txsize; @@ -398,9 +401,9 @@ int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 code, void *txbuf, si struct epic_hdr *hdr = (void *)(rmsg + 1); struct epic_sub_hdr *sub = (void *)(hdr + 1); - if (sub->category != CAT_REPLY || sub->code != code) { + if (sub->category != CAT_REPLY || sub->type != sub_type) { printf("EPIC: got unexpected message %02x:%04x during command\n", sub->category, - sub->code); + sub->type); afk_epic_rx_ack(epic); continue; } @@ -505,9 +508,9 @@ int afk_epic_start_interface(afk_epic_ep_t *epic, char *name, size_t txsize, siz struct epic_hdr *hdr = (void *)(msg + 1); struct epic_sub_hdr *sub = (void *)(hdr + 1); - if (sub->category != CAT_REPORT || sub->code != CODE_ANNOUNCE) { + if (sub->category != CAT_REPORT || sub->type != SUBTYPE_ANNOUNCE) { printf("EPIC: got unexpected message %02x:%04x during iface start\n", sub->category, - sub->code); + sub->type); afk_epic_rx_ack(epic); continue; } diff --git a/src/afk.h b/src/afk.h index e76ade38d..37e8e2a78 100644 --- a/src/afk.h +++ b/src/afk.h @@ -11,7 +11,7 @@ afk_epic_ep_t *afk_epic_init(rtkit_dev_t *rtkit, int endpoint); 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); -int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 code, void *txbuf, size_t txsize, +int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 sub_type, void *txbuf, size_t txsize, void *rxbuf, size_t *rxsize); #endif From 6a2bbbd9166cafb5ca604e75348ccadab4ca93d4 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 30 Aug 2023 01:07:39 +0200 Subject: [PATCH 09/21] afk: Prepare afk/epic for handling of multiple endpoints This needs to ensure that the data processing does not block on message retrieval from the mailbox. Command processing must not block and have to ensure that afk_epic_command() receives the reply to its command. DCP's dptx-port endpoint (endpoint 0x2a) can send notifies at any time which needs to be processed in the right context. Signed-off-by: Janne Grunau --- src/afk.c | 194 ++++++++++++++++++++++++++++++++++++++---------- src/afk.h | 12 ++- src/dcp.c | 8 ++ src/dcp.h | 2 + src/dcp_iboot.c | 6 +- 5 files changed, 177 insertions(+), 45 deletions(-) diff --git a/src/afk.c b/src/afk.c index b8db14bf6..d0a6df102 100644 --- a/src/afk.c +++ b/src/afk.c @@ -84,9 +84,15 @@ struct epic_cmd { u8 txcookie; } PACKED; +struct afk_epic { + rtkit_dev_t *rtk; + + afk_epic_ep_t *endpoint[0x10]; +}; + struct afk_epic_ep { int ep; - rtkit_dev_t *rtk; + afk_epic_t *afk; struct rtkit_buffer buf; u16 tag; @@ -98,6 +104,8 @@ struct afk_epic_ep { struct rtkit_buffer rxbuf; bool started; + + void (*recv_handler)(afk_epic_ep_t *epic); }; enum RBEP_MSG { @@ -130,6 +138,8 @@ enum RBEP_MSG { #define SEND_WPTR GENMASK(31, 0) +#define EPIC_DATA_READY 13 + bool afk_rb_init(afk_epic_ep_t *epic, struct afk_rb *rb, u64 base, u64 size) { rb->hdr = epic->buf.bfr + base; @@ -146,21 +156,32 @@ bool afk_rb_init(afk_epic_ep_t *epic, struct afk_rb *rb, u64 base, u64 size) return true; } -static int afk_epic_poll(afk_epic_ep_t *epic) +static int afk_epic_poll(afk_epic_t *afk, int endpoint, bool block) { int ret; struct rtkit_message msg; - while ((ret = rtkit_recv(epic->rtk, &msg)) == 0) - ; + while ((ret = rtkit_recv(afk->rtk, &msg)) == 0) + if (!block) + break; if (ret < 0) { printf("EPIC: rtkit_recv failed!\n"); return ret; } - if (msg.ep != epic->ep) { - printf("EPIC: received message for unexpected endpoint %d\n", msg.ep); + if (ret == 0) { + return 0; + } + + if (msg.ep < 0x20 || msg.ep >= 0x30 || !afk->endpoint[msg.ep - 0x20]) { + printf("EPIC: received message for unexpected endpoint 0x%02x\n", msg.ep); + return 0; + } + + afk_epic_ep_t *epic = afk->endpoint[msg.ep - 0x20]; + if (!epic) { + printf("EPIC: received message for idle endpoint 0x%02x\n", msg.ep); return 0; } @@ -173,13 +194,13 @@ static int afk_epic_poll(afk_epic_ep_t *epic) case RBEP_GETBUF: size = FIELD_GET(GETBUF_SIZE, msg.msg) << BLOCK_SHIFT; epic->tag = FIELD_GET(GETBUF_TAG, msg.msg); - if (!rtkit_alloc_buffer(epic->rtk, &epic->buf, size)) { + if (!rtkit_alloc_buffer(epic->afk->rtk, &epic->buf, size)) { printf("EPIC: failed to allocate buffer\n"); return -1; } msg.msg = (FIELD_PREP(RBEP_TYPE, RBEP_GETBUF_ACK) | FIELD_PREP(GETBUF_ACK_DVA, epic->buf.dva)); - if (!rtkit_send(epic->rtk, &msg)) { + if (!rtkit_send(epic->afk->rtk, &msg)) { printf("EPIC: failed to send buffer address\n"); return -1; } @@ -206,16 +227,24 @@ static int afk_epic_poll(afk_epic_ep_t *epic) if (epic->rx.ready && epic->tx.ready) { msg.msg = FIELD_PREP(RBEP_TYPE, RBEP_START); - if (!rtkit_send(epic->rtk, &msg)) { + if (!rtkit_send(epic->afk->rtk, &msg)) { printf("EPIC: failed to send start\n"); return -1; } } break; - case RBEP_RECV: - return 1; - + case RBEP_RECV: { + dma_rmb(); + struct afk_rb *rb = &epic->rx; + if (rb->hdr->rptr != rb->hdr->wptr) { + if (endpoint == epic->ep) + return EPIC_DATA_READY; + else if (epic->recv_handler) + epic->recv_handler(epic); + } + break; + } case RBEP_START_ACK: epic->started = true; break; @@ -235,20 +264,8 @@ static int afk_epic_poll(afk_epic_ep_t *epic) static int afk_epic_rx(afk_epic_ep_t *epic, struct afk_qe **qe) { - int ret; struct afk_rb *rb = &epic->rx; - u32 rptr = rb->hdr->rptr; - - while (rptr == rb->hdr->wptr) { - do { - ret = afk_epic_poll(epic); - if (ret < 0) - return ret; - } while (ret == 0); - dma_rmb(); - } - struct afk_qe *hdr = rb->buf + rptr; if (hdr->magic != QE_MAGIC) { @@ -319,7 +336,7 @@ static int afk_epic_tx(afk_epic_ep_t *epic, u32 channel, u32 type, void *data, s FIELD_PREP(RBEP_TYPE, RBEP_SEND) | FIELD_PREP(SEND_WPTR, wptr), }; - if (!rtkit_send(epic->rtk, &msg)) { + if (!rtkit_send(epic->afk->rtk, &msg)) { printf("EPIC: failed to send TX WPTR message\n"); return -1; } @@ -350,6 +367,44 @@ static void afk_epic_rx_ack(afk_epic_ep_t *epic) rb->hdr->rptr = rptr; } +int afk_epic_work(afk_epic_t *afk, int endpoint) +{ + int i = 0; + + while (i < 0x10) { + afk_epic_ep_t *cur = afk->endpoint[i++]; + if (cur) { + struct afk_rb *rb = &cur->rx; + if (rb->hdr->rptr != rb->hdr->wptr) { + if (cur->ep == endpoint) { + return EPIC_DATA_READY; + } + if (cur->recv_handler) + cur->recv_handler(cur); + else { + struct afk_qe *rmsg; + // will net block + int ret = afk_epic_rx(cur, &rmsg); + if (ret < 0) { + return ret; + } + printf("EPIC[0x%02x]: ignoring message type %d\n", cur->ep, rmsg->type); + afk_epic_rx_ack(cur); + } + } + } + if (rtkit_can_recv(afk->rtk)) { + int ret = afk_epic_poll(afk, endpoint, false); + if (ret < 0 || ret == EPIC_DATA_READY) + return ret; + i = 0; + continue; + } + } + + return 0; +} + int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 sub_type, void *txbuf, size_t txsize, void *rxbuf, size_t *rxsize) { @@ -388,6 +443,12 @@ int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 sub_type, void *txbuf struct epic_cmd *rcmd; while (true) { + ret = afk_epic_work(epic->afk, epic->ep); + if (ret < 0) + return ret; + else if (ret != EPIC_DATA_READY) + continue; + // will not block ret = afk_epic_rx(epic, &rmsg); if (ret < 0) return ret; @@ -429,7 +490,31 @@ int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 sub_type, void *txbuf 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; + // will not block + int ret = afk_epic_rx(epic, &rmsg); + if (ret < 0) + return; + + if (rmsg->type != TYPE_NOTIFY) { + printf("EPIC[0x%02x]: got unexpected message type %d in %s\n", epic->ep, rmsg->type, + __func__); + afk_epic_rx_ack(epic); + return; + } + + struct epic_hdr *hdr = (void *)(rmsg + 1); + struct epic_sub_hdr *sub = (void *)(hdr + 1); + + printf("EPIC[0x%02x]: %s: rx: Ch %u, Type:0x%02x sub cat:%x type:%x \n", epic->ep, __func__, + rmsg->channel, rmsg->type, sub->category, sub->type); + + afk_epic_rx_ack(epic); +} + +afk_epic_ep_t *afk_epic_start_ep(afk_epic_t *afk, int endpoint, bool notify) { afk_epic_ep_t *epic = malloc(sizeof(afk_epic_ep_t)); if (!epic) @@ -437,21 +522,25 @@ afk_epic_ep_t *afk_epic_init(rtkit_dev_t *rtk, int endpoint) memset(epic, 0, sizeof(*epic)); epic->ep = endpoint; - epic->rtk = rtk; + epic->afk = afk; + afk->endpoint[endpoint - 0x20] = epic; + + if (notify) + epic->recv_handler = afk_epic_notify_handler; - if (!rtkit_start_ep(rtk, endpoint)) { + if (!rtkit_start_ep(epic->afk->rtk, endpoint)) { printf("EPIC: failed to start endpoint %d\n", endpoint); goto err; } struct rtkit_message msg = {endpoint, FIELD_PREP(RBEP_TYPE, RBEP_INIT)}; - if (!rtkit_send(rtk, &msg)) { + if (!rtkit_send(epic->afk->rtk, &msg)) { printf("EPIC: failed to send init message\n"); goto err; } while (!epic->started) { - int ret = afk_epic_poll(epic); + int ret = afk_epic_poll(epic->afk, endpoint, true); if (ret < 0) break; else if (ret > 0) @@ -461,27 +550,30 @@ afk_epic_ep_t *afk_epic_init(rtkit_dev_t *rtk, int endpoint) return epic; err: + afk->endpoint[endpoint - 0x20] = NULL; free(epic); return NULL; } -int afk_epic_shutdown(afk_epic_ep_t *epic) +int afk_epic_shutdown_ep(afk_epic_ep_t *epic) { struct rtkit_message msg = {epic->ep, FIELD_PREP(RBEP_TYPE, RBEP_SHUTDOWN)}; - if (!rtkit_send(epic->rtk, &msg)) { + if (!rtkit_send(epic->afk->rtk, &msg)) { printf("EPIC: failed to send shutdown message\n"); return -1; } while (epic->started) { - int ret = afk_epic_poll(epic); + int ret = afk_epic_poll(epic->afk, epic->ep, true); if (ret < 0) break; } - rtkit_free_buffer(epic->rtk, &epic->buf); - rtkit_free_buffer(epic->rtk, &epic->rxbuf); - rtkit_free_buffer(epic->rtk, &epic->txbuf); + rtkit_free_buffer(epic->afk->rtk, &epic->buf); + rtkit_free_buffer(epic->afk->rtk, &epic->rxbuf); + rtkit_free_buffer(epic->afk->rtk, &epic->txbuf); + + epic->afk->endpoint[epic->ep - 0x20] = NULL; free(epic); return 0; @@ -532,19 +624,41 @@ int afk_epic_start_interface(afk_epic_ep_t *epic, char *name, size_t txsize, siz return -1; } - if (!rtkit_alloc_buffer(epic->rtk, &epic->rxbuf, rxsize)) { + if (!rtkit_alloc_buffer(epic->afk->rtk, &epic->rxbuf, rxsize)) { printf("EPIC: failed to allocate rx buffer\n"); return -1; } - if (!rtkit_alloc_buffer(epic->rtk, &epic->txbuf, txsize)) { + if (!rtkit_alloc_buffer(epic->afk->rtk, &epic->txbuf, txsize)) { printf("EPIC: failed to allocate tx buffer\n"); return -1; } printf("EPIC: started interface %d (%s)\n", msg->channel, announce->name); - afk_epic_rx_ack(epic); - 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; +} diff --git a/src/afk.h b/src/afk.h index 37e8e2a78..ac7704099 100644 --- a/src/afk.h +++ b/src/afk.h @@ -4,12 +4,20 @@ #define DCP_AFK_H #include "rtkit.h" +#include "types.h" +typedef struct afk_epic afk_epic_t; typedef struct afk_epic_ep afk_epic_ep_t; -afk_epic_ep_t *afk_epic_init(rtkit_dev_t *rtkit, int endpoint); -int afk_epic_shutdown(afk_epic_ep_t *epic); +typedef struct afk_epic_service_ops afk_epic_service_ops_t; +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_work(afk_epic_t *afk, int endpoint); int afk_epic_start_interface(afk_epic_ep_t *epic, char *name, size_t insize, size_t outsize); int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 sub_type, void *txbuf, size_t txsize, void *rxbuf, size_t *rxsize); diff --git a/src/dcp.c b/src/dcp.c index e9f0503d2..75671680d 100644 --- a/src/dcp.c +++ b/src/dcp.c @@ -60,8 +60,15 @@ dcp_dev_t *dcp_init(const char *dcp_path, const char *dcp_dart_path, const char goto out_iovad; } + dcp->afk = afk_epic_init(dcp->rtkit); + if (!dcp->afk) { + printf("dcp: failed to initialize AFK\n"); + goto out_rtkit; + } + return dcp; +out_rtkit: rtkit_quiesce(dcp->rtkit); rtkit_free(dcp->rtkit); out_iovad: @@ -76,6 +83,7 @@ dcp_dev_t *dcp_init(const char *dcp_path, const char *dcp_dart_path, const char int dcp_shutdown(dcp_dev_t *dcp, bool sleep) { + afk_epic_shutdown(dcp->afk); if (sleep) { rtkit_sleep(dcp->rtkit); pmgr_reset(0, "DISP0_CPU0"); diff --git a/src/dcp.h b/src/dcp.h index c9de8f2ef..edc33bbb3 100644 --- a/src/dcp.h +++ b/src/dcp.h @@ -3,6 +3,7 @@ #ifndef DCP_H #define DCP_H +#include "afk.h" #include "asc.h" #include "dart.h" #include "rtkit.h" @@ -13,6 +14,7 @@ typedef struct { iova_domain_t *iovad_dcp; asc_dev_t *asc; rtkit_dev_t *rtkit; + afk_epic_t *afk; } dcp_dev_t; dcp_dev_t *dcp_init(const char *dcp_path, const char *dcp_dart_path, const char *disp_dart_path); diff --git a/src/dcp_iboot.c b/src/dcp_iboot.c index b76f21278..8ae9a51ca 100644 --- a/src/dcp_iboot.c +++ b/src/dcp_iboot.c @@ -105,7 +105,7 @@ dcp_iboot_if_t *dcp_ib_init(dcp_dev_t *dcp) return NULL; iboot->dcp = dcp; - iboot->epic = afk_epic_init(dcp->rtkit, DCP_IBOOT_ENDPOINT); + iboot->epic = afk_epic_start_ep(dcp->afk, DCP_IBOOT_ENDPOINT, false); if (!iboot->epic) { printf("dcp-iboot: failed to initialize EPIC\n"); goto err_free; @@ -121,7 +121,7 @@ dcp_iboot_if_t *dcp_ib_init(dcp_dev_t *dcp) return iboot; err_shutdown: - afk_epic_shutdown(iboot->epic); + afk_epic_shutdown_ep(iboot->epic); err_free: free(iboot); return NULL; @@ -129,7 +129,7 @@ dcp_iboot_if_t *dcp_ib_init(dcp_dev_t *dcp) int dcp_ib_shutdown(dcp_iboot_if_t *iboot) { - afk_epic_shutdown(iboot->epic); + afk_epic_shutdown_ep(iboot->epic); free(iboot); return 0; From 32881dc968fe0e39f4dc6c8522b21f2581205bd5 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 30 Aug 2023 23:13:02 +0200 Subject: [PATCH 10/21] afk: Fix a NULL pointer dereference in adfk_epic_send() Signed-off-by: Janne Grunau --- src/afk.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/afk.c b/src/afk.c index d0a6df102..c7a4f209d 100644 --- a/src/afk.c +++ b/src/afk.c @@ -479,11 +479,13 @@ int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 sub_type, void *txbuf return rcmd->retcode; // should be negative already } - assert(*rxsize >= rcmd->rxlen); - *rxsize = rcmd->rxlen; + if (rxsize) { + assert(*rxsize >= rcmd->rxlen); + *rxsize = rcmd->rxlen; - if (rxsize && *rxsize && rcmd->rxbuf) - memcpy(rxbuf, epic->rxbuf.bfr, *rxsize); + if (*rxsize && rcmd->rxbuf) + memcpy(rxbuf, epic->rxbuf.bfr, *rxsize); + } afk_epic_rx_ack(epic); From aebaa1c378fbc3679e6ea0412ef73a2a712ae1c5 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 31 Aug 2023 23:27:34 +0200 Subject: [PATCH 11/21] afk: Introduce EPIC services To be used on the dptx-port endpoint. Signed-off-by: Janne Grunau --- src/afk.c | 124 +++++++++++++++++++++++++++++++++++++++++------- src/afk.h | 24 +++++++++- src/dcp_iboot.c | 32 +++++++++++-- 3 files changed, 158 insertions(+), 22 deletions(-) diff --git a/src/afk.c b/src/afk.c index c7a4f209d..e235bfafc 100644 --- a/src/afk.c +++ b/src/afk.c @@ -6,6 +6,8 @@ #include "string.h" #include "utils.h" +#include "dcp/parser.h" + struct afk_rb_hdr { u32 bufsz; u32 unk; @@ -90,6 +92,8 @@ struct afk_epic { afk_epic_ep_t *endpoint[0x10]; }; +#define AFK_MAX_CHANNEL 32 + struct afk_epic_ep { int ep; afk_epic_t *afk; @@ -105,6 +109,9 @@ struct afk_epic_ep { bool started; + const afk_epic_service_ops_t *ops; + afk_epic_service_t services[AFK_MAX_CHANNEL]; + void (*recv_handler)(afk_epic_ep_t *epic); }; @@ -516,7 +523,8 @@ static void afk_epic_notify_handler(afk_epic_ep_t *epic) 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 *afk_epic_start_ep(afk_epic_t *afk, int endpoint, const afk_epic_service_ops_t *ops, + bool notify) { afk_epic_ep_t *epic = malloc(sizeof(afk_epic_ep_t)); if (!epic) @@ -525,6 +533,7 @@ afk_epic_ep_t *afk_epic_start_ep(afk_epic_t *afk, int endpoint, bool notify) memset(epic, 0, sizeof(*epic)); epic->ep = endpoint; epic->afk = afk; + epic->ops = ops; afk->endpoint[endpoint - 0x20] = epic; if (notify) @@ -581,20 +590,60 @@ int afk_epic_shutdown_ep(afk_epic_ep_t *epic) return 0; } -int afk_epic_start_interface(afk_epic_ep_t *epic, char *name, size_t txsize, size_t rxsize) +static const afk_epic_service_ops_t *afk_match_service(afk_epic_ep_t *ep, const char *name) +{ + const afk_epic_service_ops_t *ops; + + if (!name[0]) + return NULL; + if (!ep->ops) + return NULL; + + for (ops = ep->ops; ops->name[0]; ops++) { + if (strcmp(ops->name, name)) + continue; + + return ops; + } + + return NULL; +} + +int afk_epic_start_interface(afk_epic_ep_t *epic, void *intf, size_t txsize, size_t rxsize) { - int channel = -1; + int channels = 0; struct afk_qe *msg; struct epic_announce *announce; + /* consume messages for other endpoints, syslog or ioreport might be noisy + * at startup */ + while (1) { + int ret = afk_epic_work(epic->afk, epic->ep); + if (ret < 0) + return ret; + if (ret == EPIC_DATA_READY) + break; + } + for (int tries = 0; tries < 20; tries += 1) { + s64 epic_unit = -1; + char *epic_name = NULL; + char *epic_class = NULL; + const char *service_name = NULL; - int ret = afk_epic_rx(epic, &msg); + int ret = afk_epic_work(epic->afk, epic->ep); + if (ret < 0) + return ret; + else if (ret != EPIC_DATA_READY) + continue; + + ret = afk_epic_rx(epic, &msg); if (ret < 0) return ret; if (msg->type != TYPE_NOTIFY && msg->type != TYPE_REPLY) { - printf("EPIC: got unexpected message type %d during iface start\n", msg->type); + printf("AFK[ep:%02x]: got unexpected message type %d during iface start\n", epic->ep, + msg->type); afk_epic_rx_ack(epic); continue; } @@ -603,42 +652,83 @@ int afk_epic_start_interface(afk_epic_ep_t *epic, char *name, size_t txsize, siz struct epic_sub_hdr *sub = (void *)(hdr + 1); if (sub->category != CAT_REPORT || sub->type != SUBTYPE_ANNOUNCE) { - printf("EPIC: got unexpected message %02x:%04x during iface start\n", sub->category, - sub->type); + printf("AFK[ep:%02x]: got unexpected message %02x:%04x during iface start\n", epic->ep, + sub->category, sub->type); afk_epic_rx_ack(epic); continue; } announce = (void *)(sub + 1); - if (strncmp(name, announce->name, sizeof(announce->name))) { - printf("EPIC: ignoring channel %d: %s\n", msg->channel, announce->name); + size_t props_size = sub->length - offsetof(struct epic_announce, props); + + if (props_size > 36) { + struct dcp_parse_ctx ctx; + + int ret = parse(announce->props, props_size, &ctx); + if (ret) { + printf("AFK[ep:%02x]: Failed to parse service init props (len=%zu) for %s\n", + epic->ep, props_size, announce->name); + afk_epic_rx_ack(epic); + continue; + } + ret = parse_epic_service_init(&ctx, &epic_name, &epic_class, &epic_unit); + if (ret) { + printf("AFK[ep:%02x]: failed to extract init props (len=%zu): %d\n", epic->ep, + props_size, ret); + hexdump(announce->props, props_size); + afk_epic_rx_ack(epic); + continue; + } + service_name = epic_class; + } else { + service_name = announce->name; + } + + const afk_epic_service_ops_t *ops = afk_match_service(epic, service_name); + if (!ops) { + printf("AFK[ep:%02x]: unable to match service %s on channel %d\n", epic->ep, + service_name, msg->channel); afk_epic_rx_ack(epic); continue; } - channel = msg->channel; - break; + afk_epic_service_t *service = &epic->services[msg->channel]; + service->enabled = true; + service->ops = ops; + service->intf = intf; + service->epic = epic; + service->channel = msg->channel; + service->seq = 0; + + ops->init(service, epic_name, service_name, epic_unit); + printf("AFK[ep:%02x]: new service %s on channel %d\n", epic->ep, service_name, + msg->channel); + free(epic_name); + free(epic_class); + + channels++; + afk_epic_rx_ack(epic); } - if (channel == -1) { - printf("EPIC: too many unexpected messages, giving up\n"); + if (!channels) { + printf("AFK[ep:%02x]: too many unexpected messages, giving up\n", epic->ep); return -1; } if (!rtkit_alloc_buffer(epic->afk->rtk, &epic->rxbuf, rxsize)) { - printf("EPIC: failed to allocate rx buffer\n"); + printf("AFK[ep:%02x]: failed to allocate rx buffer\n", epic->ep); return -1; } if (!rtkit_alloc_buffer(epic->afk->rtk, &epic->txbuf, txsize)) { - printf("EPIC: failed to allocate tx buffer\n"); + printf("AFK[ep:%02x]: failed to allocate tx buffer\n", epic->ep); return -1; } - printf("EPIC: started interface %d (%s)\n", msg->channel, announce->name); + printf("AFK[ep:%02x]: started interface with %d services\n", epic->ep, channels); - return channel; + return 0; } afk_epic_t *afk_epic_init(rtkit_dev_t *rtkit) diff --git a/src/afk.h b/src/afk.h index ac7704099..bc3f6ff82 100644 --- a/src/afk.h +++ b/src/afk.h @@ -11,14 +11,34 @@ typedef struct afk_epic_ep afk_epic_ep_t; typedef struct afk_epic_service_ops afk_epic_service_ops_t; +typedef struct afk_epic_service { + void *cookie; + const afk_epic_service_ops_t *ops; + afk_epic_ep_t *epic; + void *intf; + u32 channel; + u16 seq; + bool enabled; + +} afk_epic_service_t; + +typedef struct afk_epic_service_ops { + const char name[32]; + + void (*init)(afk_epic_service_t *service, const char *name, const char *eclass, s64 unit); + 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); +afk_epic_ep_t *afk_epic_start_ep(afk_epic_t *afk, int endpoint, const afk_epic_service_ops_t *ops, + bool notify); int afk_epic_shutdown_ep(afk_epic_ep_t *epic); int afk_epic_work(afk_epic_t *afk, int endpoint); -int afk_epic_start_interface(afk_epic_ep_t *epic, char *name, size_t insize, size_t outsize); +int afk_epic_start_interface(afk_epic_ep_t *epic, void *intf, size_t insize, size_t outsize); int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 sub_type, void *txbuf, size_t txsize, void *rxbuf, size_t *rxsize); diff --git a/src/dcp_iboot.c b/src/dcp_iboot.c index 8ae9a51ca..8a3841aaf 100644 --- a/src/dcp_iboot.c +++ b/src/dcp_iboot.c @@ -31,6 +31,7 @@ struct dcp_iboot_if { dcp_dev_t *dcp; afk_epic_ep_t *epic; int channel; + bool enabled; union { u8 txbuf[TXBUF_LEN]; @@ -98,6 +99,31 @@ struct swap_set_layer_cmd_v13_3 { u32 unk2; } PACKED; +void dcp_ib_service_init(afk_epic_service_t *service, const char *name, const char *eclass, + s64 unit) +{ + dcp_iboot_if_t *iboot = service->intf; + if (strncmp("disp0-service", eclass, 32) == 0) { + if (iboot->enabled) { + printf("dcp-iboot: service init for enabled 'disp0-service' on channel: %d\n", + iboot->channel); + return; + } + iboot->enabled = true; + iboot->channel = service->channel; + } + UNUSED(name); + UNUSED(unit); +} + +static const afk_epic_service_ops_t iboot_service_ops[] = { + { + .name = "disp0-service", + .init = dcp_ib_service_init, + }, + {}, +}; + dcp_iboot_if_t *dcp_ib_init(dcp_dev_t *dcp) { dcp_iboot_if_t *iboot = malloc(sizeof(dcp_iboot_if_t)); @@ -105,15 +131,15 @@ dcp_iboot_if_t *dcp_ib_init(dcp_dev_t *dcp) return NULL; iboot->dcp = dcp; - iboot->epic = afk_epic_start_ep(dcp->afk, DCP_IBOOT_ENDPOINT, false); + iboot->epic = afk_epic_start_ep(dcp->afk, DCP_IBOOT_ENDPOINT, iboot_service_ops, false); if (!iboot->epic) { printf("dcp-iboot: failed to initialize EPIC\n"); goto err_free; } - iboot->channel = afk_epic_start_interface(iboot->epic, "disp0-service", TXBUF_LEN, RXBUF_LEN); + int err = afk_epic_start_interface(iboot->epic, iboot, TXBUF_LEN, RXBUF_LEN); - if (iboot->channel < 0) { + if (err < 0 || !iboot->enabled) { printf("dcp-iboot: failed to initialize disp0 service\n"); goto err_shutdown; } From b9b07556640df27d3690e55cdecaf8967f9838e7 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 3 Sep 2023 00:00:41 +0200 Subject: [PATCH 12/21] afk: use increasing EPIC sequence numbers Signed-off-by: Janne Grunau --- src/afk.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/afk.c b/src/afk.c index e235bfafc..3956934c8 100644 --- a/src/afk.c +++ b/src/afk.c @@ -108,6 +108,7 @@ struct afk_epic_ep { struct rtkit_buffer rxbuf; bool started; + u16 seq; const afk_epic_service_ops_t *ops; afk_epic_service_t services[AFK_MAX_CHANNEL]; @@ -427,7 +428,7 @@ int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 sub_type, void *txbuf memset(&msg, 0, sizeof(msg)); msg.hdr.version = 2; - msg.hdr.seq = 0; + msg.hdr.seq = epic->seq++; msg.sub.length = sizeof(msg.cmd); msg.sub.version = 4; msg.sub.category = CAT_COMMAND; From 26fa2290b49243e61489afc593a7e07eab882361 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 3 Sep 2023 00:04:02 +0200 Subject: [PATCH 13/21] afk: Add EPIC std services IOp -> AP calls Used on dptx-port endpoint. Signed-off-by: Janne Grunau --- src/afk.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 3 deletions(-) diff --git a/src/afk.c b/src/afk.c index 3956934c8..25237cea6 100644 --- a/src/afk.c +++ b/src/afk.c @@ -41,6 +41,7 @@ enum EPICCategory { enum EPICMessage { SUBTYPE_ANNOUNCE = 0x30, + SUBTYPE_STD_SERVICE = 0xc0, }; struct afk_qe { @@ -413,6 +414,79 @@ int afk_epic_work(afk_epic_t *afk, int endpoint) return 0; } +struct epic_std_service_ap_call { + u32 unk0; + u32 unk1; + u32 type; + u32 len; + u32 magic; + u8 _unk[48]; +} PACKED; + +static int afk_epic_handle_std_service(afk_epic_ep_t *epic, int channel, u8 category, u16 sub_seq, + void *payload, size_t payload_size) +{ + afk_epic_service_t *service = &epic->services[channel]; + + if (service->ops->call && 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); + + 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 = SUBTYPE_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, category); + + return -1; +} + int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 sub_type, void *txbuf, size_t txsize, void *rxbuf, size_t *rxsize) { @@ -470,7 +544,15 @@ int afk_epic_command(afk_epic_ep_t *epic, int channel, u16 sub_type, void *txbuf struct epic_hdr *hdr = (void *)(rmsg + 1); struct epic_sub_hdr *sub = (void *)(hdr + 1); - if (sub->category != CAT_REPLY || sub->type != sub_type) { + if (sub->category == CAT_NOTIFY && sub->type == SUBTYPE_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, sub->category, sub->seq, payload, + payload_size); + continue; + } else if (sub->category != CAT_REPLY || sub->type != sub_type) { printf("EPIC: got unexpected message %02x:%04x during command\n", sub->category, sub->type); afk_epic_rx_ack(epic); @@ -518,8 +600,15 @@ static void afk_epic_notify_handler(afk_epic_ep_t *epic) struct epic_hdr *hdr = (void *)(rmsg + 1); struct epic_sub_hdr *sub = (void *)(hdr + 1); - printf("EPIC[0x%02x]: %s: rx: Ch %u, Type:0x%02x sub cat:%x type:%x \n", epic->ep, __func__, - rmsg->channel, rmsg->type, sub->category, sub->type); + if (sub->category == CAT_NOTIFY && sub->type == SUBTYPE_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, sub->category, sub->seq, payload, + payload_size); + } else { + printf("EPIC[0x%02x]: %s: rx: Ch %u, Type:0x%02x sub cat:%x type:%x \n", epic->ep, __func__, + rmsg->channel, rmsg->type, sub->category, sub->type); + } afk_epic_rx_ack(epic); } From 6f4cc406ce46213af09c687f2377d488d20775de Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Fri, 8 Sep 2023 21:59:48 +0200 Subject: [PATCH 14/21] afk: epic channel/interface numbers do not reset They exceed 256 with repeated chainloading of m1n1.bin on j473. Do not hold a service for every possible channel but keep a fixed array of 8 services identified by the channel number. Signed-off-by: Janne Grunau --- src/afk.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/afk.c b/src/afk.c index 25237cea6..5d9e4e920 100644 --- a/src/afk.c +++ b/src/afk.c @@ -93,7 +93,7 @@ struct afk_epic { afk_epic_ep_t *endpoint[0x10]; }; -#define AFK_MAX_CHANNEL 32 +#define AFK_MAX_CHANNEL 8 struct afk_epic_ep { int ep; @@ -111,6 +111,8 @@ struct afk_epic_ep { bool started; u16 seq; + u32 num_channels; + const afk_epic_service_ops_t *ops; afk_epic_service_t services[AFK_MAX_CHANNEL]; @@ -414,6 +416,15 @@ int afk_epic_work(afk_epic_t *afk, int endpoint) return 0; } +static afk_epic_service_t *afk_epic_find_service(afk_epic_ep_t *epic, u32 channel) +{ + for (u32 i = 0; i < epic->num_channels; i++) + if (epic->services[i].enabled && epic->services[i].channel == channel) + return &epic->services[i]; + + return NULL; +} + struct epic_std_service_ap_call { u32 unk0; u32 unk1; @@ -426,9 +437,9 @@ struct epic_std_service_ap_call { static int afk_epic_handle_std_service(afk_epic_ep_t *epic, int channel, u8 category, u16 sub_seq, void *payload, size_t payload_size) { - afk_epic_service_t *service = &epic->services[channel]; + afk_epic_service_t *service = afk_epic_find_service(epic, channel); - if (service->ops->call && category == CAT_NOTIFY) { + if (service && service->ops->call && category == CAT_NOTIFY) { struct epic_std_service_ap_call *call = payload; size_t call_size; void *reply; @@ -748,6 +759,13 @@ int afk_epic_start_interface(afk_epic_ep_t *epic, void *intf, size_t txsize, siz continue; } + if (epic->num_channels >= AFK_MAX_CHANNEL) { + printf("AFK[ep:%02x]: Out of free service for service on channel %d\n", epic->ep, + msg->channel); + afk_epic_rx_ack(epic); + continue; + } + announce = (void *)(sub + 1); size_t props_size = sub->length - offsetof(struct epic_announce, props); @@ -783,7 +801,7 @@ int afk_epic_start_interface(afk_epic_ep_t *epic, void *intf, size_t txsize, siz continue; } - afk_epic_service_t *service = &epic->services[msg->channel]; + afk_epic_service_t *service = &epic->services[epic->num_channels++]; service->enabled = true; service->ops = ops; service->intf = intf; From ac32c0e4e1a74f7f155eb70ede5783ff0d29e741 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 30 Aug 2023 09:35:09 +0200 Subject: [PATCH 15/21] dcp: Do not use an anonymous struct for dcp_dev_t typedef This allows forward declarations in other headers. Signed-off-by: Janne Grunau --- src/dcp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dcp.h b/src/dcp.h index edc33bbb3..e4f2c6fd3 100644 --- a/src/dcp.h +++ b/src/dcp.h @@ -8,7 +8,7 @@ #include "dart.h" #include "rtkit.h" -typedef struct { +typedef struct dcp_dev { dart_dev_t *dart_dcp; dart_dev_t *dart_disp; iova_domain_t *iovad_dcp; From 20442d3ad60de19fafd0ce53c2c462df7c9d4e30 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 30 Aug 2023 01:08:59 +0200 Subject: [PATCH 16/21] dcp/dptx: Add dptx-port endpoint Based on the linux kernel implementation with updates for the macOS 13.5 based DCP firmware. Signed-off-by: Janne Grunau --- Makefile | 1 + src/afk.c | 5 - src/afk.h | 5 + src/dcp/dptx_port_ep.c | 582 +++++++++++++++++++++++++++++++++++++++++ src/dcp/dptx_port_ep.h | 63 +++++ 5 files changed, 651 insertions(+), 5 deletions(-) create mode 100644 src/dcp/dptx_port_ep.c create mode 100644 src/dcp/dptx_port_ep.h diff --git a/Makefile b/Makefile index d010056eb..c5cb5e30d 100644 --- a/Makefile +++ b/Makefile @@ -75,6 +75,7 @@ LIBFDT_OBJECTS := $(patsubst %,libfdt/%, \ DCP_OBJECTS := $(patsubst %,dcp/%, \ dptx_phy.o \ + dptx_port_ep.o \ parser.o) OBJECTS := \ diff --git a/src/afk.c b/src/afk.c index 5d9e4e920..5ce943f34 100644 --- a/src/afk.c +++ b/src/afk.c @@ -39,11 +39,6 @@ enum EPICCategory { CAT_COMMAND = 0x30, }; -enum EPICMessage { - SUBTYPE_ANNOUNCE = 0x30, - SUBTYPE_STD_SERVICE = 0xc0, -}; - struct afk_qe { u32 magic; u32 size; diff --git a/src/afk.h b/src/afk.h index bc3f6ff82..a8816f055 100644 --- a/src/afk.h +++ b/src/afk.h @@ -6,6 +6,11 @@ #include "rtkit.h" #include "types.h" +enum EPICMessage { + SUBTYPE_ANNOUNCE = 0x30, + SUBTYPE_STD_SERVICE = 0xc0, +}; + typedef struct afk_epic afk_epic_t; typedef struct afk_epic_ep afk_epic_ep_t; diff --git a/src/dcp/dptx_port_ep.c b/src/dcp/dptx_port_ep.c new file mode 100644 index 000000000..6314cf9fc --- /dev/null +++ b/src/dcp/dptx_port_ep.c @@ -0,0 +1,582 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright 2022 Sven Peter */ + +#include +#include + +#include "dptx_port_ep.h" +#include "dptx_phy.h" +#include "malloc.h" + +#include "../afk.h" +#include "../dcp.h" +#include "../types.h" +#include "../utils.h" + +#define DCP_DPTX_PORT_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_lane_count { + u32 retcode; + u8 _unk0[12]; + u64 lane_count; + u8 _unk1[8]; +} __attribute__((packed)); + +struct dptxport_apcall_set_active_lane_count { + u32 retcode; + u8 _unk0[12]; + u64 lane_count; + u8 _unk1[8]; +} __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]; +} __attribute__((packed)); + +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 dptx_port { + bool enabled; + u32 unit; + afk_epic_service_t *service; + dptx_phy_t *phy; + u32 link_rate, pending_link_rate; +} dptx_port_t; + +typedef struct dcp_dptx_if { + afk_epic_ep_t *epic; + dcp_dev_t *dcp; + dptx_phy_t *phy; + + 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, SUBTYPE_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) +{ + 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, 12, &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) +{ + 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, 11, &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, 6, NULL, 0, 16, NULL, 0, 16); +} + +int dptxport_release_display(afk_epic_service_t *service) +{ + return afk_service_call(service, 0, 7, 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, 8, &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) +{ + UNUSED(service); + 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) +{ + UNUSED(service); + 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_max_lane_count(afk_epic_service_t *service, void *reply_, + size_t reply_size) +{ + UNUSED(service); + struct dptxport_apcall_lane_count *reply = reply_; + + if (reply_size < sizeof(*reply)) + return -1; + + reply->retcode = 0; + reply->lane_count = 4; + + return 0; +} + +static int dptxport_call_set_active_lane_count(afk_epic_service_t *service, const void *data, + size_t data_size, void *reply_, size_t reply_size) +{ + struct dptx_port *port = service->cookie; + const struct dptxport_apcall_set_active_lane_count *request = data; + struct dptxport_apcall_set_active_lane_count *reply = reply_; + int ret = 0; + int retcode = 0; + + if (reply_size < sizeof(*reply)) + return -1; + if (data_size < sizeof(*request)) + return -1; + + u64 lane_count = request->lane_count; + + switch (lane_count) { + case 0 ... 2: + case 4: + ret = dptx_phy_set_active_lane_count(port->phy, lane_count); + break; + default: + printf("DPTX-PORT: set_active_lane_count: invalid lane count:%lu\n", lane_count); + retcode = 1; + lane_count = 0; + break; + } + + reply->retcode = retcode; + reply->lane_count = lane_count; + + return ret; +} + +static int dptxport_call_get_link_rate(afk_epic_service_t *service, void *reply_, size_t reply_size) +{ + struct dptx_port *port = service->cookie; + struct dptxport_apcall_link_rate *reply = reply_; + + if (reply_size < sizeof(*reply)) + return -1; + + reply->retcode = 0; + reply->link_rate = port->link_rate; + + return 0; +} + +static int dptxport_call_will_change_link_config(afk_epic_service_t *service) +{ + UNUSED(service); + return 0; +} + +static int dptxport_call_did_change_link_config(afk_epic_service_t *service) +{ + UNUSED(service); + // struct dptx_port *dptx = service->intf; + // int ret = 0; + + mdelay(100); + // 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 *port = 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; + + 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_set_link_rate(port->phy, phy_link_rate); + + port->link_rate = port->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) +{ + UNUSED(service); + 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) +{ + UNUSED(service); + 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) +{ + UNUSED(service); + 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 = (dcp_dptx_if_t *)service->intf; + + 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_MAX_LANE_COUNT: + return dptxport_call_get_max_lane_count(service, reply, reply_size); + case DPTX_APCALL_SET_ACTIVE_LANE_COUNT: + return dptxport_call_set_active_lane_count(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); + case DPTX_APCALL_ACTIVATE: + dptx_phy_activate(dptx->phy); + memcpy(reply, data, min(reply_size, data_size)); + if (reply_size > 4) + memset(reply, 0, 4); + return 0; + 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_DEACTIVATE: + case DPTX_APCALL_SET_DRIVE_SETTINGS: + case DPTX_APCALL_GET_DRIVE_SETTINGS: + memcpy(reply, data, min(reply_size, data_size)); + if (reply_size > 4) + memset(reply, 0, 4); + return 0; + } +} + +static void dptxport_init(afk_epic_service_t *service, const char *name, const char *eclass, + s64 unit) +{ + dcp_dptx_if_t *dptx = (dcp_dptx_if_t *)service->intf; + + if (strcmp(name, "dcpdptx-port-epic")) + return; + if (strcmp(eclass, "AppleDCPDPTXRemotePort")) + return; + + switch (unit) { + case 0: + case 1: + if (dptx->port[unit].enabled) { + printf("DPTXPort: unit %ld already exists\n", unit); + return; + } + dptx->port[unit].unit = unit; + dptx->port[unit].service = service; + dptx->port[unit].enabled = true; + service->cookie = (void *)&dptx->port[unit]; + break; + default: + printf("DPTXPort: invalid unit %ld\n", unit); + return; + } +} + +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 (port > 1) + return -1; + if (!dptx->port[port].service) { + printf("DPTXPort: port %u not initialized. enabled:%d\n", port, dptx->port[port].enabled); + return -1; + } + + dptx->port[port].phy = dptx->phy = phy; + + dptxport_connect(dptx->port[port].service, 0, dptx_phy_dcp_output(phy), 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) +{ + dcp_dptx_if_t *dptx = calloc(1, sizeof(dcp_dptx_if_t)); + if (!dptx) + return NULL; + + dptx->dcp = dcp; + dptx->epic = afk_epic_start_ep(dcp->afk, DCP_DPTX_PORT_ENDPOINT, dcp_dptx_ops, true); + if (!dptx->epic) { + printf("dcp-dptx: failed to initialize EPIC\n"); + goto err_free; + } + + int err = afk_epic_start_interface(dptx->epic, dptx, TXBUF_LEN, RXBUF_LEN); + if (err < 0) { + printf("dcp-dptx: failed to initialize DPTXRemotePort interface\n"); + goto err_shutdown; + } + + 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) +{ + if (dptx) { + afk_epic_shutdown_ep(dptx->epic); + free(dptx); + } + return 0; +} diff --git a/src/dcp/dptx_port_ep.h b/src/dcp/dptx_port_ep.h new file mode 100644 index 000000000..8e520c2eb --- /dev/null +++ b/src/dcp/dptx_port_ep.h @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright 2022 Sven Peter */ + +#ifndef __APPLE_DCP_DPTX_PORT_EP_H__ +#define __APPLE_DCP_DPTX_PORT_EP_H__ + +#include "../types.h" + +typedef struct dcp_dev dcp_dev_t; + +typedef struct dptx_phy dptx_phy_t; + +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_MAX_LANE_COUNT = 10, + DPTX_APCALL_GET_ACTIVE_LANE_COUNT = 11, + DPTX_APCALL_SET_ACTIVE_LANE_COUNT = 12, + DPTX_APCALL_GET_SUPPORTS_DOWN_SPREAD = 13, + DPTX_APCALL_GET_DOWN_SPREAD = 14, + DPTX_APCALL_SET_DOWN_SPREAD = 15, + DPTX_APCALL_GET_SUPPORTS_LANE_MAPPING = 16, + DPTX_APCALL_SET_LANE_MAP = 17, + DPTX_APCALL_GET_SUPPORTS_HPD = 18, + DPTX_APCALL_FORCE_HOTPLUG_DETECT = 19, + DPTX_APCALL_INACTIVE_SINK_DETECTED = 20, + DPTX_APCALL_SET_TILED_DISPLAY_HINTS = 21, + DPTX_APCALL_DEVICE_NOT_RESPONDING = 22, + DPTX_APCALL_DEVICE_BUSY_TIMEOUT = 23, + DPTX_APCALL_DEVICE_NOT_STARTED = 24, +}; + +#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_hpd(dcp_dptx_if_t *dptx, u32 port, bool hpd); +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 From 1705397ae61065ecb07c895f84c06f8d90ff5edf Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 24 Aug 2023 23:04:55 +0200 Subject: [PATCH 17/21] dcp/dpav: Add DPAV endpoint Signed-off-by: Janne Grunau --- Makefile | 1 + src/dcp/dpav_ep.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++ src/dcp/dpav_ep.h | 16 ++++++++++ 3 files changed, 95 insertions(+) create mode 100644 src/dcp/dpav_ep.c create mode 100644 src/dcp/dpav_ep.h diff --git a/Makefile b/Makefile index c5cb5e30d..231f7d3c8 100644 --- a/Makefile +++ b/Makefile @@ -74,6 +74,7 @@ LIBFDT_OBJECTS := $(patsubst %,libfdt/%, \ fdt_wip.o fdt.o) DCP_OBJECTS := $(patsubst %,dcp/%, \ + dpav_ep.o \ dptx_phy.o \ dptx_port_ep.o \ parser.o) diff --git a/src/dcp/dpav_ep.c b/src/dcp/dpav_ep.c new file mode 100644 index 000000000..b8df58cd1 --- /dev/null +++ b/src/dcp/dpav_ep.c @@ -0,0 +1,78 @@ + +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright 2022 Sven Peter */ + +#include +#include + +#include "dpav_ep.h" +#include "malloc.h" +#include "parser.h" + +#include "../afk.h" +#include "../dcp.h" +#include "../types.h" +#include "../utils.h" + +#define DCP_DPAV_ENDPOINT 0x24 +#define TXBUF_LEN 0x4000 +#define RXBUF_LEN 0x4000 + +typedef struct dcp_dpav_if { + afk_epic_ep_t *epic; + dcp_dev_t *dcp; +} dcp_dpav_if_t; + +static void dpav_init(afk_epic_service_t *service, const char *name, const char *eclass, s64 unit) +{ + UNUSED(service); + UNUSED(name); + UNUSED(eclass); + UNUSED(unit); + // printf("DPAV: init(name='%s', class='%s' unit=%ld:\n", name, eclass, unit); +} + +static const afk_epic_service_ops_t dcp_dpav_ops[] = { + { + .name = "AppleDCPDPTXController", + .init = dpav_init, + }, + {}, +}; + +dcp_dpav_if_t *dcp_dpav_init(dcp_dev_t *dcp) +{ + dcp_dpav_if_t *dpav = malloc(sizeof(dcp_dpav_if_t)); + if (!dpav) + return NULL; + + dpav->dcp = dcp; + dpav->epic = afk_epic_start_ep(dcp->afk, DCP_DPAV_ENDPOINT, dcp_dpav_ops, true); + if (!dpav->epic) { + printf("dpav: failed to initialize EPIC\n"); + goto err_free; + } + + int err = afk_epic_start_interface(dpav->epic, dpav, TXBUF_LEN, RXBUF_LEN); + if (err < 0) { + printf("dpav: failed to initialize DPAV interface\n"); + goto err_shutdown; + } + + return dpav; + +err_shutdown: + afk_epic_shutdown_ep(dpav->epic); +err_free: + free(dpav); + return NULL; +} + +int dcp_dpav_shutdown(dcp_dpav_if_t *dpav) +{ + if (dpav) { + afk_epic_shutdown_ep(dpav->epic); + free(dpav); + } + return 0; +} diff --git a/src/dcp/dpav_ep.h b/src/dcp/dpav_ep.h new file mode 100644 index 000000000..1eda41865 --- /dev/null +++ b/src/dcp/dpav_ep.h @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright 2023 Janne Grunau */ + +#ifndef __APPLE_DCP_DPAV_EP_H__ +#define __APPLE_DCP_DPAV_EP_H__ + +#include "../types.h" + +typedef struct dcp_dev dcp_dev_t; + +typedef struct dcp_dpav_if dcp_dpav_if_t; + +dcp_dpav_if_t *dcp_dpav_init(dcp_dev_t *dcp); +int dcp_dpav_shutdown(dcp_dpav_if_t *dpav); + +#endif From 7c99be9880a7340d7618583549cf746680642eea Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 28 Aug 2023 00:16:41 +0200 Subject: [PATCH 18/21] dcp/system: Add system endpoint This on is boring but allows turning additional logging on. Signed-off-by: Janne Grunau --- Makefile | 3 +- src/dcp/system_ep.c | 147 ++++++++++++++++++++++++++++++++++++++++++++ src/dcp/system_ep.h | 17 +++++ 3 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 src/dcp/system_ep.c create mode 100644 src/dcp/system_ep.h diff --git a/Makefile b/Makefile index 231f7d3c8..6c0c25ac3 100644 --- a/Makefile +++ b/Makefile @@ -77,7 +77,8 @@ DCP_OBJECTS := $(patsubst %,dcp/%, \ dpav_ep.o \ dptx_phy.o \ dptx_port_ep.o \ - parser.o) + parser.o \ + system_ep.o) OBJECTS := \ adt.o \ diff --git a/src/dcp/system_ep.c b/src/dcp/system_ep.c new file mode 100644 index 000000000..8d2457529 --- /dev/null +++ b/src/dcp/system_ep.c @@ -0,0 +1,147 @@ + +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright 2022 Sven Peter */ + +#include +#include + +#include "system_ep.h" +#include "malloc.h" +#include "parser.h" + +#include "../afk.h" +#include "../dcp.h" +#include "../types.h" +#include "../utils.h" + +#define DCP_SYSTEM_ENDPOINT 0x20 +#define TXBUF_LEN 0x4000 +#define RXBUF_LEN 0x4000 + +typedef struct dcp_system_if { + afk_epic_ep_t *epic; + dcp_dev_t *dcp; + + afk_epic_service_t *sys_service; + afk_epic_service_t *powerlog; +} dcp_system_if_t; + +static void system_service_init(afk_epic_service_t *service, const char *name, const char *eclass, + s64 unit) +{ + UNUSED(name); + UNUSED(unit); + dcp_system_if_t *system = (dcp_system_if_t *)service->intf; + if (strcmp(eclass, "system") == 0) { + if (system->sys_service) { + printf("SYSTEM[%p]: system services already started!\n", system); + return; + } + system->sys_service = service; + service->cookie = system; + } +} + +static void powerlog_service_init(afk_epic_service_t *service, const char *name, const char *eclass, + s64 unit) +{ + UNUSED(name); + UNUSED(unit); + dcp_system_if_t *system = (dcp_system_if_t *)service->intf; + if (strcmp(eclass, "powerlog-service") == 0) { + if (system->powerlog) { + printf("SYSTEM[%p]: powerlog service already started!\n", system); + return; + } + system->powerlog = service; + service->cookie = system; + } +} + +struct OSSerializedInt { + u32 code; // constant little endian 0xd3 + u32 tag; // 24 bit size in bits, 8 bit type (constant 4 for integers) + u64 value; +} PACKED; + +int dcp_system_set_property_u64(dcp_system_if_t *system, const char *name, u64 value) +{ + size_t name_len = strlen(name); + u32 aligned_len = ALIGN_UP(name_len, 4); + struct OSSerializedInt val = { + .code = 0xd3, + .tag = 0x80000000 | (4 << 24) | 64, + .value = value, + }; + size_t bfr_len = sizeof(aligned_len) + aligned_len + sizeof(val); + + u8 *bfr = calloc(1, bfr_len); + if (!bfr) + return -1; + + memcpy(bfr, &aligned_len, sizeof(aligned_len)); + memcpy(bfr + sizeof(aligned_len), name, name_len); + memcpy(bfr + sizeof(aligned_len) + aligned_len, &val, sizeof(val)); + + afk_epic_service_t *service = system->sys_service; + if (!service) { + free(bfr); + printf("SYSTEM: sys_service-service not started\n"); + return -1; + } + int ret = afk_epic_command(service->epic, service->channel, 0x43, bfr, bfr_len, NULL, NULL); + + free(bfr); + + return ret; +} + +static const afk_epic_service_ops_t dcp_system_ops[] = { + { + .name = "system", + .init = system_service_init, + }, + { + .name = "powerlog-service", + .init = powerlog_service_init, + }, + {}, +}; + +dcp_system_if_t *dcp_system_init(dcp_dev_t *dcp) +{ + dcp_system_if_t *system = calloc(1, sizeof(dcp_system_if_t)); + if (!system) + return NULL; + + system->dcp = dcp; + system->epic = afk_epic_start_ep(dcp->afk, DCP_SYSTEM_ENDPOINT, dcp_system_ops, true); + if (!system->epic) { + // printf("system: failed to initialize EPIC\n"); + goto err_free; + } + + int err = afk_epic_start_interface(system->epic, system, TXBUF_LEN, RXBUF_LEN); + + if (err < 0 || !system->sys_service) { + printf("dcp-system: failed to initialize system-service\n"); + goto err_shutdown; + } + + return system; + +err_shutdown: + afk_epic_shutdown_ep(system->epic); +err_free: + free(system); + return NULL; +} + +int dcp_system_shutdown(dcp_system_if_t *system) +{ + if (system) { + afk_epic_shutdown_ep(system->epic); + free(system); + } + return 0; +} diff --git a/src/dcp/system_ep.h b/src/dcp/system_ep.h new file mode 100644 index 000000000..8a4e4a002 --- /dev/null +++ b/src/dcp/system_ep.h @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright 2023 Janne Grunau */ + +#ifndef DCP_SYSTEM_EP_H +#define DCP_SYSTEM_EP_H + +#include "../types.h" + +typedef struct dcp_dev dcp_dev_t; + +typedef struct dcp_system_if dcp_system_if_t; + +dcp_system_if_t *dcp_system_init(dcp_dev_t *dcp); +int dcp_system_set_property_u64(dcp_system_if_t *system, const char *name, u64 value); +int dcp_system_shutdown(dcp_system_if_t *system); + +#endif From 327ce3437e883072a3989b2bf0f7038cdc443a98 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 3 Sep 2023 15:17:22 +0200 Subject: [PATCH 19/21] rtkit: Support usage with SRAM Will be used by SMC. Signed-off-by: Janne Grunau --- src/dcp.c | 2 +- src/nvme.c | 4 ++-- src/rtkit.c | 20 ++++++++++++++++++-- src/rtkit.h | 2 +- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/dcp.c b/src/dcp.c index 75671680d..d58fdbb53 100644 --- a/src/dcp.c +++ b/src/dcp.c @@ -49,7 +49,7 @@ dcp_dev_t *dcp_init(const char *dcp_path, const char *dcp_dart_path, const char goto out_iovad; } - dcp->rtkit = rtkit_init("dcp", dcp->asc, dcp->dart_dcp, dcp->iovad_dcp, NULL); + dcp->rtkit = rtkit_init("dcp", dcp->asc, dcp->dart_dcp, dcp->iovad_dcp, NULL, false); if (!dcp->rtkit) { printf("dcp: failed to initialize RTKit\n"); goto out_iovad; diff --git a/src/nvme.c b/src/nvme.c index e40df4db8..30634cda0 100644 --- a/src/nvme.c +++ b/src/nvme.c @@ -335,7 +335,7 @@ bool nvme_init(void) if (!nvme_sart) goto out_asc; - nvme_rtkit = rtkit_init("nvme", nvme_asc, NULL, NULL, nvme_sart); + nvme_rtkit = rtkit_init("nvme", nvme_asc, NULL, NULL, nvme_sart, false); if (!nvme_rtkit) goto out_sart; @@ -446,7 +446,7 @@ void nvme_ensure_shutdown(void) if (!nvme_sart) goto fail; - nvme_rtkit = rtkit_init("nvme", nvme_asc, NULL, NULL, nvme_sart); + nvme_rtkit = rtkit_init("nvme", nvme_asc, NULL, NULL, nvme_sart, false); if (!nvme_rtkit) goto fail; diff --git a/src/rtkit.c b/src/rtkit.c index 5528cebf0..b31ec60b3 100644 --- a/src/rtkit.c +++ b/src/rtkit.c @@ -87,6 +87,7 @@ struct rtkit_dev { dart_dev_t *dart; iova_domain_t *dart_iovad; sart_dev_t *sart; + bool sram; u64 dva_base; @@ -126,7 +127,7 @@ struct crashlog_entry { }; rtkit_dev_t *rtkit_init(const char *name, asc_dev_t *asc, dart_dev_t *dart, - iova_domain_t *dart_iovad, sart_dev_t *sart) + iova_domain_t *dart_iovad, sart_dev_t *sart, bool sram) { if (dart && sart) { printf("rtkit: Cannot use both SART and DART simultaneously\n"); @@ -138,6 +139,11 @@ rtkit_dev_t *rtkit_init(const char *name, asc_dev_t *asc, dart_dev_t *dart, return NULL; } + if (sram && (dart || sart)) { + printf("rtkit: cannot use SRAM with DART or SART \n"); + return NULL; + } + rtkit_dev_t *rtk = malloc(sizeof(*rtk)); if (!rtk) return NULL; @@ -153,6 +159,7 @@ rtkit_dev_t *rtkit_init(const char *name, asc_dev_t *asc, dart_dev_t *dart, rtk->dart = dart; rtk->dart_iovad = dart_iovad; rtk->sart = sart; + rtk->sram = sram; rtk->iop_power = RTKIT_POWER_OFF; rtk->ap_power = RTKIT_POWER_OFF; rtk->dva_base = 0; @@ -277,7 +284,16 @@ static bool rtkit_handle_buffer_request(rtkit_dev_t *rtk, struct rtkit_message * size_t sz = n_4kpages << 12; u64 addr = FIELD_GET(MSG_BUFFER_REQUEST_IOVA, msg->msg); - if (addr) { + if (rtk->sram) { + if (!addr) { + rtkit_printf("SRAM buffers needs to be provided by the IOP\n"); + return false; + } + bfr->dva = addr; + bfr->bfr = (void *)addr; + bfr->sz = sz; + return true; + } else if (addr) { bfr->dva = addr & ~rtk->dva_base; bfr->sz = sz; bfr->bfr = dart_translate(rtk->dart, bfr->dva & IOVA_MASK); diff --git a/src/rtkit.h b/src/rtkit.h index dcefcd9ca..8461875c9 100644 --- a/src/rtkit.h +++ b/src/rtkit.h @@ -23,7 +23,7 @@ struct rtkit_buffer { }; rtkit_dev_t *rtkit_init(const char *name, asc_dev_t *asc, dart_dev_t *dart, - iova_domain_t *dart_iovad, sart_dev_t *sart); + iova_domain_t *dart_iovad, sart_dev_t *sart, bool sram); bool rtkit_quiesce(rtkit_dev_t *rtk); bool rtkit_sleep(rtkit_dev_t *rtk); void rtkit_free(rtkit_dev_t *rtk); From 075267ef079ec00fb78125806c81a0deb3ad7890 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 3 Sep 2023 16:15:34 +0200 Subject: [PATCH 20/21] smc: Add minimal smc client Only supported operation is smc_write_u32() for turning the dp2hdmi converter on M2 desktop systems on. Signed-off-by: Janne Grunau --- Makefile | 1 + src/smc.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/smc.h | 17 +++++ 3 files changed, 199 insertions(+) create mode 100644 src/smc.c create mode 100644 src/smc.h diff --git a/Makefile b/Makefile index 6c0c25ac3..426d3c0be 100644 --- a/Makefile +++ b/Makefile @@ -124,6 +124,7 @@ OBJECTS := \ sart.o \ sep.o \ sio.o \ + smc.o \ smp.o \ start.o \ startup.o \ diff --git a/src/smc.c b/src/smc.c new file mode 100644 index 000000000..ddcf8d995 --- /dev/null +++ b/src/smc.c @@ -0,0 +1,181 @@ +/* SPDX-License-Identifier: MIT */ + +#include "assert.h" +#include "malloc.h" +#include "smc.h" +#include "string.h" +#include "types.h" +#include "utils.h" + +#define SMC_READ_KEY 0x10 +#define SMC_WRITE_KEY 0x11 +#define SMC_GET_KEY_BY_INDEX 0x12 +#define SMC_GET_KEY_INFO 0x13 +#define SMC_INITIALIZE 0x17 +#define SMC_NOTIFICATION 0x18 +#define SMC_RW_KEY 0x20 + +#define SMC_MSG_TYPE GENMASK(7, 0) +#define SMC_MSG_ID GENMASK(15, 12) + +#define SMC_WRITE_KEY_SIZE GENMASK(23, 16) +#define SMC_WRITE_KEY_KEY GENMASK(63, 32) + +#define SMC_RESULT_RESULT GENMASK(7, 0) +#define SMC_RESULT_ID GENMASK(15, 12) +#define SMC_RESULT_SIZE GENMASK(31, 16) +#define SMC_RESULT_VALUE GENMASK(63, 32) + +#define SMC_NUM_IDS 16 + +#define SMC_ENDPOINT 0x20 + +struct smc_dev { + asc_dev_t *asc; + rtkit_dev_t *rtkit; + + void *shmem; + u32 msgid; + + bool outstanding[SMC_NUM_IDS]; + u64 ret[SMC_NUM_IDS]; +}; + +static void smc_handle_msg(smc_dev_t *smc, u64 msg) +{ + if (!smc->shmem) + smc->shmem = (void *)msg; + else { + u8 result = FIELD_GET(SMC_RESULT_RESULT, msg); + u8 id = FIELD_GET(SMC_RESULT_ID, msg); + if (result == SMC_NOTIFICATION) { + printf("SMC: Notification: 0x%08lx\n", FIELD_GET(SMC_RESULT_VALUE, msg)); + return; + } + smc->outstanding[id] = false; + smc->ret[id] = msg; + } +} + +static int smc_work(smc_dev_t *smc) +{ + int ret; + struct rtkit_message msg; + + while ((ret = rtkit_recv(smc->rtkit, &msg)) == 0) + ; + + if (ret < 0) { + printf("SMC: rtkit_recv failed!\n"); + return ret; + } + + if (msg.ep != SMC_ENDPOINT) { + printf("SMC: received message for unexpected endpoint 0x%02x\n", msg.ep); + return 0; + } + + smc_handle_msg(smc, msg.msg); + + return 0; +} + +static void smc_send(smc_dev_t *smc, u64 message) +{ + struct rtkit_message msg; + + msg.ep = SMC_ENDPOINT; + msg.msg = message; + + rtkit_send(smc->rtkit, &msg); +} + +static int smc_cmd(smc_dev_t *smc, u64 message) +{ + u8 id = smc->msgid++ & 0xF; + assert(!smc->outstanding[id]); + smc->outstanding[id] = true; + + message |= FIELD_PREP(SMC_MSG_ID, id); + + smc_send(smc, message); + while (smc->outstanding[id]) + smc_work(smc); + + u64 result = smc->ret[id]; + u32 ret = FIELD_GET(SMC_RESULT_RESULT, result); + if (ret) { + printf("SMC: smc_cmd[0x%x] failed: %u\n", id, ret); + return ret; + } + + return 0; +} + +void smc_shutdown(smc_dev_t *smc) +{ + rtkit_quiesce(smc->rtkit); + rtkit_free(smc->rtkit); + asc_free(smc->asc); + free(smc); +} + +smc_dev_t *smc_init() +{ + smc_dev_t *smc = calloc(1, sizeof(smc_dev_t)); + if (!smc) + return NULL; + + smc->asc = asc_init("/arm-io/smc"); + if (!smc->asc) { + printf("SMC: failed to initialize ASC\n"); + goto out_free; + } + + smc->rtkit = rtkit_init("smc", smc->asc, NULL, NULL, NULL, true); + if (!smc->rtkit) { + printf("SMC: failed to initialize RTKit\n"); + goto out_asc; + } + + if (!rtkit_boot(smc->rtkit)) { + printf("SMC: failed to boot RTKit\n"); + goto out_rtkit; + } + + if (!rtkit_start_ep(smc->rtkit, SMC_ENDPOINT)) { + printf("SMC: failed start SMC endpoint\n"); + goto out_rtkit; + } + + u64 initialize = + FIELD_PREP(SMC_MSG_TYPE, SMC_INITIALIZE) | FIELD_PREP(SMC_MSG_ID, smc->msgid++); + + smc_send(smc, initialize); + + while (!smc->shmem) { + int ret = smc_work(smc); + if (ret < 0) + goto out_rtkit; + } + + return smc; + +out_rtkit: + rtkit_free(smc->rtkit); +out_asc: + asc_free(smc->asc); +out_free: + free(smc); + return NULL; +} + +int smc_write_u32(smc_dev_t *smc, u32 key, u32 value) +{ + memcpy(smc->shmem, &value, sizeof(value)); + u64 msg = FIELD_PREP(SMC_MSG_TYPE, SMC_WRITE_KEY); + msg |= FIELD_PREP(SMC_WRITE_KEY_SIZE, sizeof(value)); + msg |= FIELD_PREP(SMC_WRITE_KEY_KEY, key); + + return smc_cmd(smc, msg); +} diff --git a/src/smc.h b/src/smc.h new file mode 100644 index 000000000..3cb470457 --- /dev/null +++ b/src/smc.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: MIT */ + +#ifndef SMC_H +#define SMC_H + +#include "asc.h" +#include "rtkit.h" +#include "types.h" + +typedef struct smc_dev smc_dev_t; + +int smc_write_u32(smc_dev_t *smc, u32 key, u32 value); + +smc_dev_t *smc_init(void); +void smc_shutdown(smc_dev_t *smc); + +#endif From ae41be12fab4fcb3b2a3fd33d0ab1f3e51d49571 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 30 Aug 2023 00:47:26 +0200 Subject: [PATCH 21/21] display: Support the HDMI output on M2* desktop systems On M2* desktop systems the HDMI output is not managed by dcp/dcp0. This allows more flexibility, for example dcp on the M2 Mac mini can be routed to the USB-C/ThunderBolt ports. For m1n1 this adds quite ab bit of complexity. In addition to the DCP iboot endpoint/protocol two additional endpoints have to be started. Only the dptx-port endpoint has a meaningful AP <=> DCP communication. In addition we start the system endpoint to optionally enable more verbose syslog messages (if RTKIT_SYSLOG is defined). In addition the dptx-phy or lpdptx-phy has to be programmed. Those two phy look mostly identical. MacOS seems to use a static DP configuration (4 lanes, HBR3*) regardless of the connected display. The added SMC gpio support is used to power the MCDP29xx DP to HDMI converter on. Config is unfortunately a mess since Apple can't name the device tree nodes consistently. On M2 Ultra devices only the four dcpext*/dispext* on each die are used. M2 Ultra support is untested. * link rate might differ on t602x based devices for 8k60 support Signed-off-by: Janne Grunau --- src/dcp.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++---- src/dcp.h | 26 ++++++++- src/display.c | 96 +++++++++++++++++++++++-------- 3 files changed, 240 insertions(+), 34 deletions(-) diff --git a/src/dcp.c b/src/dcp.c index d58fdbb53..7a208922d 100644 --- a/src/dcp.c +++ b/src/dcp.c @@ -1,19 +1,129 @@ /* SPDX-License-Identifier: MIT */ -#include "dcp.h" +#include "../config.h" + #include "adt.h" +#include "afk.h" +#include "dcp.h" +#include "firmware.h" #include "malloc.h" #include "pmgr.h" #include "rtkit.h" +#include "smc.h" +#include "string.h" #include "utils.h" -dcp_dev_t *dcp_init(const char *dcp_path, const char *dcp_dart_path, const char *disp_dart_path) +#include "dcp/dptx_phy.h" + +struct adt_function_smc_gpio { + u32 phandle; + char four_cc[4]; + u32 gpio; + u32 unk; +}; + +static char dcp_pmgr_dev[16] = "DISP0_CPU0"; +static u32 dcp_die; + +static int dcp_hdmi_dptx_init(dcp_dev_t *dcp, const display_config_t *cfg) +{ + int node = adt_path_offset(adt, cfg->dp2hdmi_gpio); + if (node < 0) { + printf("dcp: failed to find dp2hdmi-gpio node '%s'\n", cfg->dp2hdmi_gpio); + return -1; + } + struct adt_function_smc_gpio dp2hdmi_pwr, hdmi_pwr; + + int err = + adt_getprop_copy(adt, node, "function-dp2hdmi_pwr_en", &dp2hdmi_pwr, sizeof(dp2hdmi_pwr)); + if (err < 0) + printf("dcp: failed to get dp2hdmi_pwr_en gpio\n"); + else + dcp->dp2hdmi_pwr_gpio = dp2hdmi_pwr.gpio; + err = adt_getprop_copy(adt, node, "function-hdmi_pwr_en", &hdmi_pwr, sizeof(hdmi_pwr)); + if (err < 0) + printf("dcp: failed to get hdmi_pwr_en gpio\n"); + else + dcp->hdmi_pwr_gpio = hdmi_pwr.gpio; + + if (dcp->dp2hdmi_pwr_gpio && dcp->hdmi_pwr_gpio) { + smc_dev_t *smc = smc_init(); + if (smc) { + smc_write_u32(smc, dcp->dp2hdmi_pwr_gpio, 0x800001); + smc_write_u32(smc, dcp->hdmi_pwr_gpio, 0x800001); + smc_shutdown(smc); + } + } + + dcp->phy = dptx_phy_init(cfg->dptx_phy, cfg->dcp_index); + if (!dcp->phy) { + printf("dcp: failed to init (lp)dptx-phy '%s'\n", cfg->dptx_phy); + return -1; + } + + dcp->dpav_ep = dcp_dpav_init(dcp); + if (!dcp->dpav_ep) { + printf("dcp: failed to initialize dpav endpoint\n"); + dcp_system_shutdown(dcp->system_ep); + return -1; + } + + dcp->dptx_ep = dcp_dptx_init(dcp); + if (!dcp->dptx_ep) { + printf("dcp: failed to initialize dptx-port endpoint\n"); + dcp_dpav_shutdown(dcp->dpav_ep); + dcp_system_shutdown(dcp->system_ep); + return -1; + } + +#ifdef RTKIT_SYSLOG + // start system endpoint when extended logging is requested + dcp->system_ep = dcp_system_init(dcp); + if (!dcp->system_ep) { + printf("dcp: failed to initialize system endpoint\n"); + return -1; + } + + dcp_system_set_property_u64(dcp->system_ep, "gAFKConfigLogMask", 0xffff); +#endif + + return 0; +} + +int dcp_connect_dptx(dcp_dev_t *dcp) +{ + if (dcp->dptx_ep && dcp->phy) { + return dcp_dptx_connect(dcp->dptx_ep, dcp->phy, 0); + } + + return 0; +} + +int dcp_work(dcp_dev_t *dcp) +{ + return afk_epic_work(dcp->afk, -1); +} + +dcp_dev_t *dcp_init(const display_config_t *cfg) { u32 sid; - int node = adt_path_offset(adt, "/arm-io/dart-dcp/mapper-dcp"); + if (cfg && cfg->dptx_phy[0]) { + if (os_firmware.version != V13_5) { + printf("dcp: dtpx-port is only supported with V13_5 OS firmware.\n"); + return NULL; + } + + strncpy(dcp_pmgr_dev, cfg->pmgr_dev, sizeof(dcp_pmgr_dev)); + dcp_die = cfg->die; + pmgr_adt_power_enable(cfg->dcp); + pmgr_adt_power_enable(cfg->dptx_phy); + } + + int dart_node = adt_path_offset(adt, cfg->dcp_dart); + int node = adt_first_child_offset(adt, dart_node); if (node < 0) { - printf("dcp: mapper-dcp not found!\n"); + printf("dcp: mapper-dcp* not found!\n"); return NULL; } if (ADT_GETPROP(adt, node, "reg", &sid) < 0) { @@ -21,29 +131,29 @@ dcp_dev_t *dcp_init(const char *dcp_path, const char *dcp_dart_path, const char return NULL; } - dcp_dev_t *dcp = malloc(sizeof(dcp_dev_t)); + dcp_dev_t *dcp = calloc(1, sizeof(dcp_dev_t)); if (!dcp) return NULL; - dcp->dart_dcp = dart_init_adt(dcp_dart_path, 0, sid, true); + dcp->dart_dcp = dart_init_adt(cfg->dcp_dart, 0, sid, true); if (!dcp->dart_dcp) { printf("dcp: failed to initialize DCP DART\n"); goto out_free; } u64 vm_base = dart_vm_base(dcp->dart_dcp); - dart_setup_pt_region(dcp->dart_dcp, dcp_dart_path, sid, vm_base); + dart_setup_pt_region(dcp->dart_dcp, cfg->dcp_dart, sid, vm_base); - dcp->dart_disp = dart_init_adt(disp_dart_path, 0, 0, true); + dcp->dart_disp = dart_init_adt(cfg->disp_dart, 0, 0, true); if (!dcp->dart_disp) { printf("dcp: failed to initialize DISP DART\n"); goto out_dart_dcp; } // set disp0's page tables at dart-dcp's vm-base - dart_setup_pt_region(dcp->dart_disp, disp_dart_path, 0, vm_base); + dart_setup_pt_region(dcp->dart_disp, cfg->disp_dart, 0, vm_base); dcp->iovad_dcp = iovad_init(vm_base + 0x10000000, vm_base + 0x20000000); - dcp->asc = asc_init(dcp_path); + dcp->asc = asc_init(cfg->dcp); if (!dcp->asc) { printf("dcp: failed to initialize ASC\n"); goto out_iovad; @@ -66,8 +176,18 @@ dcp_dev_t *dcp_init(const char *dcp_path, const char *dcp_dart_path, const char goto out_rtkit; } + if (cfg && cfg->dptx_phy[0]) { + int ret = dcp_hdmi_dptx_init(dcp, cfg); + if (ret < 0) + goto out_afk; + } + return dcp; +out_afk: + afk_epic_shutdown(dcp->afk); + rtkit_sleep(dcp->rtkit); + pmgr_reset(dcp_die, dcp_pmgr_dev); out_rtkit: rtkit_quiesce(dcp->rtkit); rtkit_free(dcp->rtkit); @@ -83,10 +203,20 @@ dcp_dev_t *dcp_init(const char *dcp_path, const char *dcp_dart_path, const char int dcp_shutdown(dcp_dev_t *dcp, bool sleep) { + if (dcp->dptx_ep) { + if (sleep) { + printf("DCP: dcp_shutdown(sleep=true) is broken with dptx-port, quiesce instead\n"); + sleep = false; + } + } + dcp_dptx_shutdown(dcp->dptx_ep); + dcp_dpav_shutdown(dcp->dpav_ep); + dcp_system_shutdown(dcp->system_ep); + free(dcp->phy); afk_epic_shutdown(dcp->afk); if (sleep) { rtkit_sleep(dcp->rtkit); - pmgr_reset(0, "DISP0_CPU0"); + pmgr_reset(dcp_die, dcp_pmgr_dev); } else { rtkit_quiesce(dcp->rtkit); } diff --git a/src/dcp.h b/src/dcp.h index e4f2c6fd3..5046b3d5d 100644 --- a/src/dcp.h +++ b/src/dcp.h @@ -8,6 +8,21 @@ #include "dart.h" #include "rtkit.h" +#include "dcp/dpav_ep.h" +#include "dcp/dptx_port_ep.h" +#include "dcp/system_ep.h" + +typedef struct { + const char dcp[24]; + const char dcp_dart[24]; + const char disp_dart[24]; + const char dptx_phy[24]; + const char dp2hdmi_gpio[24]; + const char pmgr_dev[24]; + u32 dcp_index; + u8 die; +} display_config_t; + typedef struct dcp_dev { dart_dev_t *dart_dcp; dart_dev_t *dart_disp; @@ -15,9 +30,18 @@ typedef struct dcp_dev { asc_dev_t *asc; rtkit_dev_t *rtkit; afk_epic_t *afk; + dcp_system_if_t *system_ep; + dcp_dpav_if_t *dpav_ep; + dcp_dptx_if_t *dptx_ep; + dptx_phy_t *phy; + u32 dp2hdmi_pwr_gpio; + u32 hdmi_pwr_gpio; } dcp_dev_t; -dcp_dev_t *dcp_init(const char *dcp_path, const char *dcp_dart_path, const char *disp_dart_path); +int dcp_connect_dptx(dcp_dev_t *dcp); +int dcp_work(dcp_dev_t *dcp); + +dcp_dev_t *dcp_init(const display_config_t *config); int dcp_shutdown(dcp_dev_t *dcp, bool sleep); diff --git a/src/display.c b/src/display.c index 73d4d4da6..160d0cb0f 100644 --- a/src/display.c +++ b/src/display.c @@ -12,8 +12,8 @@ #include "utils.h" #include "xnuboot.h" -#define DISPLAY_STATUS_DELAY 100 -#define DISPLAY_STATUS_RETRIES 20 +#define DISPLAY_STATUS_DELAY 100 +#define DISPLAY_STATUS_RETRIES(dptx) ((dptx) ? 100 : 20) #define COMPARE(a, b) \ if ((a) > (b)) { \ @@ -28,6 +28,45 @@ static dcp_iboot_if_t *iboot; static u64 fb_dva; static u64 fb_size; bool display_is_external; +bool display_is_dptx; + +static const display_config_t display_config_m1 = { + .dcp = "/arm-io/dcp", + .dcp_dart = "/arm-io/dart-dcp", + .disp_dart = "/arm-io/dart-disp0", + .pmgr_dev = "DISP0_CPU0", +}; + +static const display_config_t display_config_m2 = { + .dcp = "/arm-io/dcp", + .dcp_dart = "/arm-io/dart-dcp", + .disp_dart = "/arm-io/dart-disp0", + .dp2hdmi_gpio = "/arm-io/dp2hdmi-gpio", + .dptx_phy = "/arm-io/dptx-phy", + .pmgr_dev = "DISP0_CPU0", + .dcp_index = 0, +}; + +static const display_config_t display_config_m2_pro_max = { + .dcp = "/arm-io/dcp0", + .dcp_dart = "/arm-io/dart-dcp0", + .disp_dart = "/arm-io/dart-disp0", + .dp2hdmi_gpio = "/arm-io/dp2hdmi-gpio0", + .dptx_phy = "/arm-io/lpdptx-phy0", + .pmgr_dev = "DISP0_CPU0", + .dcp_index = 0, +}; + +static const display_config_t display_config_m2_ultra = { + .dcp = "/arm-io/dcpext4", + .dcp_dart = "/arm-io/dart-dcpext4", + .disp_dart = "/arm-io/dart-dispext4", + .dp2hdmi_gpio = "/arm-io/dp2hdmi-gpio1", + .dptx_phy = "/arm-io/lpdptx-phy1", + .pmgr_dev = "DISPEXT4_CPU0", + .dcp_index = 1, + .die = 1, +}; #define abs(x) ((x) >= 0 ? (x) : -(x)) @@ -165,7 +204,18 @@ int display_start_dcp(void) if (iboot) return 0; - dcp = dcp_init("/arm-io/dcp", "/arm-io/dart-dcp", "/arm-io/dart-disp0"); + const display_config_t *disp_cfg = &display_config_m1; + + if (adt_is_compatible(adt, 0, "J473AP")) + disp_cfg = &display_config_m2; + else if (adt_is_compatible(adt, 0, "J474sAP") || adt_is_compatible(adt, 0, "J475cAP")) + disp_cfg = &display_config_m2_pro_max; + else if (adt_is_compatible(adt, 0, "J180dAP") || adt_is_compatible(adt, 0, "J475dAP")) + disp_cfg = &display_config_m2_ultra; + + display_is_dptx = !!disp_cfg->dptx_phy[0]; + + dcp = dcp_init(disp_cfg); if (!dcp) { printf("display: failed to initialize DCP\n"); return -1; @@ -287,10 +337,11 @@ int display_configure(const char *config) if (ret < 0) return ret; - // Power on - if ((ret = dcp_ib_set_power(iboot, true)) < 0) { - printf("display: failed to set power\n"); - return ret; + // connect dptx if necessary + if (display_is_dptx) { + ret = dcp_connect_dptx(dcp); + if (ret < 0) + return ret; } // Detect if display is connected @@ -300,13 +351,14 @@ int display_configure(const char *config) /* After boot DCP does not immediately report a connected display. Retry getting display * information for 2 seconds. */ - while (retries++ < DISPLAY_STATUS_RETRIES) { + while (retries++ < (DISPLAY_STATUS_RETRIES(display_is_dptx))) { + dcp_work(dcp); hpd = dcp_ib_get_hpd(iboot, &timing_cnt, &color_cnt); if (hpd < 0) ret = hpd; else if (hpd && timing_cnt && color_cnt) break; - if (retries < DISPLAY_STATUS_RETRIES) + if (retries < DISPLAY_STATUS_RETRIES(display_is_dptx)) mdelay(DISPLAY_STATUS_DELAY); } printf("display: waited %d ms for display status\n", (retries - 1) * DISPLAY_STATUS_DELAY); @@ -320,6 +372,12 @@ int display_configure(const char *config) if (!hpd || !timing_cnt || !color_cnt) return 0; + // Power on + if ((ret = dcp_ib_set_power(iboot, true)) < 0) { + printf("display: failed to set power\n"); + return ret; + } + // Find best modes dcp_timing_mode_t *tmodes, tbest; if ((ret = dcp_ib_get_timing_modes(iboot, &tmodes)) < 0) { @@ -446,10 +504,15 @@ int display_configure(const char *config) int display_init(void) { - int node = adt_path_offset(adt, "/arm-io/disp0"); + const char *disp_path; + if (adt_is_compatible(adt, 0, "J180dAP") || adt_is_compatible(adt, 0, "J475dAP")) + disp_path = "/arm-io/dispext4"; + else + disp_path = "/arm-io/disp0"; + int node = adt_path_offset(adt, disp_path); if (node < 0) { - printf("DISP0 node not found!\n"); + printf("%s node not found!\n", disp_path); return -1; } @@ -459,17 +522,6 @@ int display_init(void) else printf("display: Display is internal\n"); - // HACK: disable non-working display config on j473/j474s/etc - if (display_is_external) { - switch (chip_id) { - case T8112: - case T6020 ... T6022: - printf("display: skipping init on non-supported M2+ platform\n"); - return 0; - break; - } - } - if (cur_boot_args.video.width == 640 && cur_boot_args.video.height == 1136) { printf("display: Dummy framebuffer found, initializing display\n"); return display_configure(NULL);