summaryrefslogtreecommitdiff
path: root/tools/src/dcp_iboot.c
diff options
context:
space:
mode:
authormagh <magh@maghmogh.com>2023-03-06 18:44:55 -0600
committermagh <magh@maghmogh.com>2023-03-06 18:44:55 -0600
commite80d9d8871b325a04b18f90a9ea4bb7fd148fb25 (patch)
tree79dbdb8506b7ff1e92549188d1b94cfc0b3503ae /tools/src/dcp_iboot.c
add m1n1HEADmaster
Diffstat (limited to 'tools/src/dcp_iboot.c')
-rw-r--r--tools/src/dcp_iboot.c224
1 files changed, 224 insertions, 0 deletions
diff --git a/tools/src/dcp_iboot.c b/tools/src/dcp_iboot.c
new file mode 100644
index 0000000..8f8a374
--- /dev/null
+++ b/tools/src/dcp_iboot.c
@@ -0,0 +1,224 @@
+/* SPDX-License-Identifier: MIT */
+
+#include "dcp_iboot.h"
+#include "afk.h"
+#include "assert.h"
+#include "malloc.h"
+#include "string.h"
+#include "utils.h"
+
+#define DCP_IBOOT_ENDPOINT 0x23
+
+#define TXBUF_LEN 0x4000
+#define RXBUF_LEN 0x4000
+
+struct txcmd {
+ u32 op;
+ u32 len;
+ u32 unk1;
+ u32 unk2;
+ u8 payload[];
+};
+
+struct rxcmd {
+ u32 op;
+ u32 len;
+ u8 payload[];
+};
+
+struct dcp_iboot_if {
+ dcp_dev_t *dcp;
+ afk_epic_ep_t *epic;
+ int channel;
+
+ union {
+ u8 txbuf[TXBUF_LEN];
+ struct txcmd txcmd;
+ };
+
+ union {
+ u8 rxbuf[RXBUF_LEN];
+ struct rxcmd rxcmd;
+ };
+};
+
+enum IBootCmd {
+ IBOOT_SET_POWER = 2,
+ IBOOT_GET_HPD = 3,
+ IBOOT_GET_TIMING_MODES = 4,
+ IBOOT_GET_COLOR_MODES = 5,
+ IBOOT_SET_MODE = 6,
+ IBOOT_SWAP_BEGIN = 15,
+ IBOOT_SWAP_SET_LAYER = 16,
+ IBOOT_SWAP_END = 18,
+};
+
+struct get_hpd_resp {
+ u8 hpd;
+ u8 pad[3];
+ u32 timing_cnt;
+ u32 color_cnt;
+};
+
+struct get_tmode_resp {
+ u32 count;
+ dcp_timing_mode_t modes[];
+};
+
+struct get_cmode_resp {
+ u32 count;
+ dcp_color_mode_t modes[];
+};
+
+struct swap_start_resp {
+ u32 unk1, unk2, unk3;
+ u32 swap_id;
+ u32 unk4;
+};
+
+struct swap_set_layer_cmd {
+ u32 unk;
+ u32 layer_id;
+ dcp_layer_t layer;
+ dcp_rect_t src;
+ dcp_rect_t dst;
+ u32 unk2;
+} PACKED;
+
+dcp_iboot_if_t *dcp_ib_init(dcp_dev_t *dcp)
+{
+ dcp_iboot_if_t *iboot = malloc(sizeof(dcp_iboot_if_t));
+ if (!iboot)
+ return NULL;
+
+ iboot->dcp = dcp;
+ iboot->epic = afk_epic_init(dcp->rtkit, DCP_IBOOT_ENDPOINT);
+ 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);
+
+ if (iboot->channel < 0) {
+ printf("dcp-iboot: failed to initialize disp0 service\n");
+ goto err_shutdown;
+ }
+
+ return iboot;
+
+err_shutdown:
+ afk_epic_shutdown(iboot->epic);
+err_free:
+ free(iboot);
+ return NULL;
+}
+
+int dcp_ib_shutdown(dcp_iboot_if_t *iboot)
+{
+ afk_epic_shutdown(iboot->epic);
+
+ free(iboot);
+ return 0;
+}
+
+static int dcp_ib_cmd(dcp_iboot_if_t *iboot, int op, size_t in_size)
+{
+ size_t rxsize = RXBUF_LEN;
+ assert(in_size <= TXBUF_LEN - sizeof(struct txcmd));
+
+ iboot->txcmd.op = op;
+ iboot->txcmd.len = sizeof(struct txcmd) + in_size;
+
+ return afk_epic_command(iboot->epic, iboot->channel, 0xc0, iboot->txbuf,
+ sizeof(struct txcmd) + in_size, iboot->rxbuf, &rxsize);
+}
+
+int dcp_ib_set_power(dcp_iboot_if_t *iboot, bool power)
+{
+ u32 *pwr = (void *)iboot->txcmd.payload;
+ *pwr = power;
+
+ return dcp_ib_cmd(iboot, IBOOT_SET_POWER, 1);
+}
+
+int dcp_ib_get_hpd(dcp_iboot_if_t *iboot, int *timing_cnt, int *color_cnt)
+{
+ struct get_hpd_resp *resp = (void *)iboot->rxcmd.payload;
+ int ret = dcp_ib_cmd(iboot, IBOOT_GET_HPD, 0);
+
+ if (ret < 0)
+ return ret;
+
+ if (timing_cnt)
+ *timing_cnt = resp->timing_cnt;
+ if (color_cnt)
+ *color_cnt = resp->color_cnt;
+
+ return !!resp->hpd;
+}
+
+int dcp_ib_get_timing_modes(dcp_iboot_if_t *iboot, dcp_timing_mode_t **modes)
+{
+ struct get_tmode_resp *resp = (void *)iboot->rxcmd.payload;
+ int ret = dcp_ib_cmd(iboot, IBOOT_GET_TIMING_MODES, 0);
+
+ if (ret < 0)
+ return ret;
+
+ *modes = resp->modes;
+ return resp->count;
+}
+
+int dcp_ib_get_color_modes(dcp_iboot_if_t *iboot, dcp_color_mode_t **modes)
+{
+ struct get_cmode_resp *resp = (void *)iboot->rxcmd.payload;
+ int ret = dcp_ib_cmd(iboot, IBOOT_GET_COLOR_MODES, 0);
+
+ if (ret < 0)
+ return ret;
+
+ *modes = resp->modes;
+ return resp->count;
+}
+
+int dcp_ib_set_mode(dcp_iboot_if_t *iboot, dcp_timing_mode_t *tmode, dcp_color_mode_t *cmode)
+{
+ struct {
+ dcp_timing_mode_t tmode;
+ dcp_color_mode_t cmode;
+ } *cmd = (void *)iboot->txcmd.payload;
+
+ cmd->tmode = *tmode;
+ cmd->cmode = *cmode;
+ return dcp_ib_cmd(iboot, IBOOT_SET_MODE, sizeof(*cmd));
+}
+
+int dcp_ib_swap_begin(dcp_iboot_if_t *iboot)
+{
+ struct swap_start_resp *resp = (void *)iboot->rxcmd.payload;
+ int ret = dcp_ib_cmd(iboot, IBOOT_SWAP_BEGIN, 0);
+ if (ret < 0)
+ return ret;
+
+ return resp->swap_id;
+}
+
+int dcp_ib_swap_set_layer(dcp_iboot_if_t *iboot, int layer_id, dcp_layer_t *layer,
+ dcp_rect_t *src_rect, dcp_rect_t *dst_rect)
+{
+ struct swap_set_layer_cmd *cmd = (void *)iboot->txcmd.payload;
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->layer_id = layer_id;
+ cmd->layer = *layer;
+ cmd->src = *src_rect;
+ cmd->dst = *dst_rect;
+
+ return dcp_ib_cmd(iboot, IBOOT_SWAP_SET_LAYER, sizeof(*cmd));
+}
+
+int dcp_ib_swap_end(dcp_iboot_if_t *iboot)
+{
+ memset(iboot->txcmd.payload, 0, 12);
+ return dcp_ib_cmd(iboot, IBOOT_SWAP_END, 12);
+}