mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-24 23:53:04 +00:00
dcp: Add DCP and iBoot protocol support
Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
parent
3f9bd38b6f
commit
eaadc43fbb
5 changed files with 427 additions and 0 deletions
2
Makefile
2
Makefile
|
@ -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
69
src/dcp.c
Normal 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
22
src/dcp.h
Normal 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
223
src/dcp_iboot.c
Normal 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
111
src/dcp_iboot.h
Normal 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
|
Loading…
Reference in a new issue