dcp: Add DCP and iBoot protocol support

Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
Hector Martin 2022-01-17 04:29:36 +09:00
parent 3f9bd38b6f
commit eaadc43fbb
5 changed files with 427 additions and 0 deletions

View file

@ -60,6 +60,8 @@ OBJECTS := \
chickens.o \
cpufreq.o \
dart.o \
dcp.o \
dcp_iboot.o \
exception.o exception_asm.o \
fb.o font.o font_retina.o \
gxf.o gxf_asm.o \

69
src/dcp.c Normal file
View file

@ -0,0 +1,69 @@
/* SPDX-License-Identifier: MIT */
#include "dcp.h"
#include "adt.h"
#include "malloc.h"
#include "rtkit.h"
#include "utils.h"
dcp_dev_t *dcp_init(const char *dcp_path, const char *dcp_dart_path, const char *disp_dart_path)
{
dcp_dev_t *dcp = malloc(sizeof(dcp_dev_t));
if (!dcp)
return NULL;
dcp->dart_dcp = dart_init_adt(dcp_dart_path, 0, 0, true);
if (!dcp->dart_dcp) {
printf("dcp: failed to initialize DCP DART\n");
goto out_free;
}
dcp->dart_disp = dart_init_adt(disp_dart_path, 0, 0, true);
if (!dcp->dart_disp) {
printf("dcp: failed to initialize DISP DART\n");
goto out_dart_dcp;
}
dcp->iovad_dcp = iovad_init(0x10000000, 0xf0000000);
dcp->asc = asc_init(dcp_path);
if (!dcp->asc) {
printf("dcp: failed to initialize ASC\n");
goto out_iovad;
}
dcp->rtkit = rtkit_init("dcp", dcp->asc, dcp->dart_dcp, dcp->iovad_dcp, NULL);
if (!dcp->rtkit) {
printf("dcp: failed to initialize RTKit\n");
goto out_iovad;
}
if (!rtkit_boot(dcp->rtkit)) {
printf("dcp: failed to boot RTKit\n");
goto out_iovad;
}
return dcp;
rtkit_shutdown(dcp->rtkit);
rtkit_free(dcp->rtkit);
out_iovad:
iovad_shutdown(dcp->iovad_dcp);
dart_shutdown(dcp->dart_disp);
out_dart_dcp:
dart_shutdown(dcp->dart_dcp);
out_free:
free(dcp);
return NULL;
}
int dcp_shutdown(dcp_dev_t *dcp)
{
rtkit_shutdown(dcp->rtkit);
rtkit_free(dcp->rtkit);
dart_shutdown(dcp->dart_disp);
dart_shutdown(dcp->dart_dcp);
free(dcp);
return 0;
}

22
src/dcp.h Normal file
View file

@ -0,0 +1,22 @@
/* SPDX-License-Identifier: MIT */
#ifndef DCP_H
#define DCP_H
#include "asc.h"
#include "dart.h"
#include "rtkit.h"
typedef struct {
dart_dev_t *dart_dcp;
dart_dev_t *dart_disp;
iova_domain_t *iovad_dcp;
asc_dev_t *asc;
rtkit_dev_t *rtkit;
} dcp_dev_t;
dcp_dev_t *dcp_init(const char *dcp_path, const char *dcp_dart_path, const char *disp_dart_path);
int dcp_shutdown(dcp_dev_t *dcp);
#endif

223
src/dcp_iboot.c Normal file
View file

@ -0,0 +1,223 @@
/* 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 {
u32 hpd;
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);
}

111
src/dcp_iboot.h Normal file
View file

@ -0,0 +1,111 @@
/* SPDX-License-Identifier: MIT */
#ifndef DCP_IBOOT_H
#define DCP_IBOOT_H
#include "dcp.h"
typedef struct dcp_iboot_if dcp_iboot_if_t;
enum DCPEOTF {
EOTF_GAMMA_SDR = 1,
EOTF_GAMMA_HDR = 2,
};
enum DCPEncoding {
ENC_RGB = 1,
ENC_YCBCR_444 = 3,
ENC_YCBCR_422 = 4,
ENC_YCBCR_420 = 5,
};
enum DCPColorimetry {
CLR_BT601_709 = 1,
CLR_BT2020 = 2,
CLR_DCIP3 = 3,
};
enum DCPSurfaceFmt {
FMT_BGRA = 1,
FMT_RGBA = 3,
FMT_w18p = 4,
FMT_444v = 6,
FMT_422v = 7,
FMT_420v = 8,
FMT_w30r = 9,
FMT_w40a = 10,
};
enum DCPTransform {
XFRM_NONE = 0,
XFRM_XFLIP = 1,
XFRM_YFLIP = 2,
XFRM_ROT_90 = 3,
XFRM_ROT_180 = 4,
XFRM_ROT_270 = 5,
};
enum AddrFormat {
ADDR_PLANAR = 1,
ADDR_TILED = 2,
ADDR_AGX = 3,
};
typedef struct {
u32 valid;
u32 width;
u32 height;
u32 fps;
u8 pad[8];
} PACKED dcp_timing_mode_t;
typedef struct {
u32 valid;
u32 colorimetry;
u32 eotf;
u32 encoding;
u32 bpp;
u8 pad[4];
} PACKED dcp_color_mode_t;
typedef struct {
u32 unk1;
u64 addr;
u32 tile_size;
u32 stride;
u32 unk2[4];
u32 addr_format;
u32 unk3;
} PACKED dcp_plane_t;
typedef struct {
dcp_plane_t planes[3];
u32 unk;
u32 plane_cnt;
u32 width;
u32 height;
u32 surface_fmt;
u32 colorspace;
u32 eotf;
u8 transform;
u8 padding[3];
} PACKED dcp_layer_t;
typedef struct {
u32 w, h, x, y;
} PACKED dcp_rect_t;
dcp_iboot_if_t *dcp_ib_init(dcp_dev_t *dcp);
int dcp_ib_shutdown(dcp_iboot_if_t *iboot);
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);
int dcp_ib_get_color_modes(dcp_iboot_if_t *iboot, dcp_color_mode_t **modes);
int dcp_ib_set_mode(dcp_iboot_if_t *iboot, dcp_timing_mode_t *timing, dcp_color_mode_t *color);
int dcp_ib_swap_begin(dcp_iboot_if_t *iboot);
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);
int dcp_ib_swap_end(dcp_iboot_if_t *iboot);
#endif