soc/mediatek/common/dp: Move common functions to dptx_common.c
Move the functions that can be shared with MT8196 to dptx_common.c. BUG=b:382363408 TEST=emerge-geralt coreboot && emerge-cherry coreboot Change-Id: Ic5074feee9efa62f27c118eaf7adb25875ba4c16 Signed-off-by: Yidi Lin <yidilin@chromium.org> Reviewed-on: https://review.coreboot.org/c/coreboot/+/85860 Reviewed-by: Yu-Ping Wu <yupingso@google.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
parent
3f362cced5
commit
10be8c5ace
5 changed files with 645 additions and 617 deletions
|
|
@ -12,512 +12,6 @@
|
|||
#include <soc/dp_intf.h>
|
||||
#include <string.h>
|
||||
|
||||
#define ONE_BLOCK_SIZE 128
|
||||
|
||||
#define DP_LINK_CONSTANT_N_VALUE 0x8000
|
||||
#define DP_LINK_STATUS_SIZE 6
|
||||
|
||||
#define DP_LANE0_1_STATUS 0x202
|
||||
#define DP_LANE2_3_STATUS 0x203
|
||||
#define DP_LANE_CR_DONE (1 << 0)
|
||||
#define DP_LANE_CHANNEL_EQ_DONE (1 << 1)
|
||||
#define DP_LANE_SYMBOL_LOCKED (1 << 2)
|
||||
|
||||
#define DP_BRANCH_OUI_HEADER_SIZE 0xc
|
||||
#define DP_RECEIVER_CAP_SIZE 0xf
|
||||
#define DP_DSC_RECEIVER_CAP_SIZE 0xf
|
||||
#define EDP_PSR_RECEIVER_CAP_SIZE 2
|
||||
#define EDP_DISPLAY_CTL_CAP_SIZE 3
|
||||
#define DP_LTTPR_COMMON_CAP_SIZE 8
|
||||
#define DP_LTTPR_PHY_CAP_SIZE 3
|
||||
|
||||
#define DP_TRAINING_AUX_RD_INTERVAL 0x00e
|
||||
#define DP_TRAINING_AUX_RD_MASK 0x7f
|
||||
#define DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT (1 << 7)
|
||||
|
||||
#define DP_EDP_DPCD_REV 0x700
|
||||
#define DP_EDP_11 0x00
|
||||
#define DP_EDP_12 0x01
|
||||
#define DP_EDP_13 0x02
|
||||
#define DP_EDP_14 0x03
|
||||
#define DP_EDP_14a 0x04
|
||||
#define DP_EDP_14b 0x05
|
||||
|
||||
/* Receiver Capability */
|
||||
#define DP_DPCD_REV 0x000
|
||||
#define DP_DPCD_REV_10 0x10
|
||||
#define DP_DPCD_REV_11 0x11
|
||||
#define DP_DPCD_REV_12 0x12
|
||||
#define DP_DPCD_REV_13 0x13
|
||||
#define DP_DPCD_REV_14 0x14
|
||||
|
||||
#define DP_CHANNEL_EQ_BITS (DP_LANE_CR_DONE | \
|
||||
DP_LANE_CHANNEL_EQ_DONE | \
|
||||
DP_LANE_SYMBOL_LOCKED)
|
||||
|
||||
#define DP_LANE_ALIGN_STATUS_UPDATED 0x204
|
||||
#define DP_INTERLANE_ALIGN_DONE (1 << 0)
|
||||
#define DP_DOWNSTREAM_PORT_STATUS_CHANGED (1 << 6)
|
||||
#define DP_LINK_STATUS_UPDATED (1 << 7)
|
||||
|
||||
#define DP_SINK_STATUS 0x205
|
||||
#define DP_RECEIVE_PORT_0_STATUS (1 << 0)
|
||||
#define DP_RECEIVE_PORT_1_STATUS (1 << 1)
|
||||
#define DP_STREAM_REGENERATION_STATUS (1 << 2)
|
||||
|
||||
#define DP_AUX_MAX_PAYLOAD_BYTES 16
|
||||
|
||||
#define MAX_LANECOUNT 4
|
||||
|
||||
enum {
|
||||
DP_LANECOUNT_1 = 0x1,
|
||||
DP_LANECOUNT_2 = 0x2,
|
||||
DP_LANECOUNT_4 = 0x4,
|
||||
};
|
||||
|
||||
enum {
|
||||
DP_VERSION_11 = 0x11,
|
||||
DP_VERSION_12 = 0x12,
|
||||
DP_VERSION_14 = 0x14,
|
||||
DP_VERSION_12_14 = 0x16,
|
||||
DP_VERSION_14_14 = 0x17,
|
||||
DP_VERSION_MAX,
|
||||
};
|
||||
|
||||
enum {
|
||||
DPTX_SWING0 = 0x00,
|
||||
DPTX_SWING1 = 0x01,
|
||||
DPTX_SWING2 = 0x02,
|
||||
DPTX_SWING3 = 0x03,
|
||||
};
|
||||
|
||||
enum {
|
||||
DPTX_PREEMPHASIS0 = 0x00,
|
||||
DPTX_PREEMPHASIS1 = 0x01,
|
||||
DPTX_PREEMPHASIS2 = 0x02,
|
||||
DPTX_PREEMPHASIS3 = 0x03,
|
||||
};
|
||||
|
||||
enum {
|
||||
DPTX_PASS = 0,
|
||||
DPTX_PLUG_OUT = 1,
|
||||
DPTX_TIMEOUT = 2,
|
||||
DPTX_AUTH_FAIL = 3,
|
||||
DPTX_EDID_FAIL = 4,
|
||||
DPTX_TRANING_FAIL = 5,
|
||||
DPTX_TRANING_STATE_CHANGE = 6,
|
||||
};
|
||||
|
||||
enum {
|
||||
FEC_ERROR_COUNT_DISABLE = 0x0,
|
||||
FEC_UNCORRECTED_BLOCK_ERROR_COUNT = 0x1,
|
||||
FEC_CORRECTED_BLOCK_ERROR_COUNT = 0x2,
|
||||
FEC_BIT_ERROR_COUNT = 0x3,
|
||||
FEC_PARITY_BLOCK_ERROR_COUNT = 0x4,
|
||||
FEC_PARITY_BIT_ERROR_COUNT = 0x5,
|
||||
};
|
||||
|
||||
enum {
|
||||
DPTX_NTSTATE_STARTUP = 0x0,
|
||||
DPTX_NTSTATE_CHECKCAP = 0x1,
|
||||
DPTX_NTSTATE_CHECKEDID = 0x2,
|
||||
DPTX_NTSTATE_TRAINING_PRE = 0x3,
|
||||
DPTX_NTSTATE_TRAINING = 0x4,
|
||||
DPTX_NTSTATE_CHECKTIMING = 0x5,
|
||||
DPTX_NTSTATE_NORMAL = 0x6,
|
||||
DPTX_NTSTATE_POWERSAVE = 0x7,
|
||||
DPTX_NTSTATE_DPIDLE = 0x8,
|
||||
DPTX_NTSTATE_MAX,
|
||||
};
|
||||
|
||||
enum {
|
||||
DPTX_DISP_NONE = 0,
|
||||
DPTX_DISP_RESUME = 1,
|
||||
DPTX_DISP_SUSPEND = 2,
|
||||
};
|
||||
|
||||
enum {
|
||||
TRAIN_STEP_SUCCESS = 0,
|
||||
TRAIN_STEP_FAIL_BREAK = 1,
|
||||
TRAIN_STEP_FAIL_NOT_BREAK = 2,
|
||||
};
|
||||
|
||||
#define DPTX_TRAIN_RETRY_LIMIT 0x8
|
||||
#define DPTX_TRAIN_MAX_ITERATION 0x5
|
||||
|
||||
#define HPD_INT_EVNET BIT(3)
|
||||
#define HPD_CONNECT BIT(2)
|
||||
#define HPD_DISCONNECT BIT(1)
|
||||
#define HPD_INITIAL_STATE 0
|
||||
|
||||
static bool dptx_auxwrite_bytes(struct mtk_dp *mtk_dp, u8 cmd,
|
||||
u32 dpcd_addr, size_t length, u8 *data)
|
||||
{
|
||||
if (retry(7, dptx_hal_auxwrite_bytes(mtk_dp, cmd, dpcd_addr, length, data),
|
||||
mdelay(1)))
|
||||
return true;
|
||||
|
||||
printk(BIOS_ERR, "aux write fail: cmd = %d, addr = %#x, len = %ld\n",
|
||||
cmd, dpcd_addr, length);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool dptx_auxwrite_dpcd(struct mtk_dp *mtk_dp, u8 cmd,
|
||||
u32 dpcd_addr, size_t length, u8 *data)
|
||||
{
|
||||
bool ret = true;
|
||||
size_t offset = 0;
|
||||
size_t len;
|
||||
|
||||
while (offset < length) {
|
||||
len = MIN(length - offset, DP_AUX_MAX_PAYLOAD_BYTES);
|
||||
ret &= dptx_auxwrite_bytes(mtk_dp, cmd, dpcd_addr + offset,
|
||||
len, data + offset);
|
||||
offset += len;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool dptx_auxread_bytes(struct mtk_dp *mtk_dp, u8 cmd,
|
||||
u32 dpcd_addr, size_t length, u8 *data)
|
||||
{
|
||||
if (retry(7, dptx_hal_auxread_bytes(mtk_dp, cmd, dpcd_addr, length, data),
|
||||
mdelay(1)))
|
||||
return true;
|
||||
|
||||
printk(BIOS_ERR, "aux read fail: cmd = %d, addr = %#x, len = %ld\n",
|
||||
cmd, dpcd_addr, length);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool dptx_auxread_dpcd(struct mtk_dp *mtk_dp, u8 cmd,
|
||||
u32 dpcd_addr, size_t length, u8 *rxbuf)
|
||||
{
|
||||
bool ret = true;
|
||||
size_t offset = 0;
|
||||
size_t len;
|
||||
|
||||
while (offset < length) {
|
||||
len = MIN(length - offset, DP_AUX_MAX_PAYLOAD_BYTES);
|
||||
ret &= dptx_auxread_bytes(mtk_dp, cmd, dpcd_addr + offset,
|
||||
len, rxbuf + offset);
|
||||
offset += len;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dptx_get_edid(struct mtk_dp *mtk_dp, struct edid *out)
|
||||
{
|
||||
int ret;
|
||||
u8 edid[ONE_BLOCK_SIZE];
|
||||
u8 tmp = 0;
|
||||
|
||||
dptx_auxwrite_dpcd(mtk_dp, DP_AUX_I2C_WRITE, 0x50, 0x1, &tmp);
|
||||
|
||||
for (tmp = 0; tmp < ONE_BLOCK_SIZE / DP_AUX_MAX_PAYLOAD_BYTES; tmp++)
|
||||
dptx_auxread_dpcd(mtk_dp, DP_AUX_I2C_READ,
|
||||
0x50, DP_AUX_MAX_PAYLOAD_BYTES,
|
||||
edid + tmp * 16);
|
||||
|
||||
ret = decode_edid(edid, ONE_BLOCK_SIZE, out);
|
||||
if (ret != EDID_CONFORMANT) {
|
||||
printk(BIOS_ERR, "failed to decode edid(%d).\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mtk_dp->edid = out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 dptx_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r)
|
||||
{
|
||||
return link_status[r - DP_LANE0_1_STATUS];
|
||||
}
|
||||
|
||||
static u8 dptx_get_lane_status(const u8 link_status[DP_LINK_STATUS_SIZE],
|
||||
int lane)
|
||||
{
|
||||
int i = DP_LANE0_1_STATUS + (lane >> 1);
|
||||
int s = (lane & 1) * 4;
|
||||
u8 l = dptx_link_status(link_status, i);
|
||||
|
||||
return (l >> s) & 0xf;
|
||||
}
|
||||
|
||||
static bool dptx_clock_recovery_ok(const u8 link_status[DP_LINK_STATUS_SIZE],
|
||||
int lane_count)
|
||||
{
|
||||
int lane;
|
||||
u8 lane_status;
|
||||
|
||||
for (lane = 0; lane < lane_count; lane++) {
|
||||
lane_status = dptx_get_lane_status(link_status, lane);
|
||||
if ((lane_status & DP_LANE_CR_DONE) == 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dptx_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
|
||||
{
|
||||
u32 rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
|
||||
DP_TRAINING_AUX_RD_MASK;
|
||||
|
||||
if (rd_interval > 4)
|
||||
printk(BIOS_ERR, "aux interval %d, out of range (max 4)\n",
|
||||
rd_interval);
|
||||
|
||||
if (rd_interval == 0 || dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14)
|
||||
rd_interval = 1;
|
||||
else
|
||||
rd_interval *= 4;
|
||||
|
||||
mdelay(rd_interval);
|
||||
}
|
||||
|
||||
static void dptx_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
|
||||
{
|
||||
u32 rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
|
||||
DP_TRAINING_AUX_RD_MASK;
|
||||
|
||||
if (rd_interval > 4)
|
||||
printk(BIOS_ERR, "aux interval %d, out of range (max 4)\n",
|
||||
rd_interval);
|
||||
|
||||
if (rd_interval == 0)
|
||||
rd_interval = 1;
|
||||
else
|
||||
rd_interval *= 4;
|
||||
|
||||
mdelay(rd_interval);
|
||||
}
|
||||
|
||||
static bool dptx_channel_eq_ok(const u8 link_status[DP_LINK_STATUS_SIZE],
|
||||
int lane_count)
|
||||
{
|
||||
u8 lane_align;
|
||||
u8 lane_status;
|
||||
int lane;
|
||||
|
||||
lane_align = dptx_link_status(link_status,
|
||||
DP_LANE_ALIGN_STATUS_UPDATED);
|
||||
|
||||
if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
|
||||
return false;
|
||||
|
||||
for (lane = 0; lane < lane_count; lane++) {
|
||||
lane_status = dptx_get_lane_status(link_status, lane);
|
||||
if ((lane_status & DP_CHANNEL_EQ_BITS) != DP_CHANNEL_EQ_BITS)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dptx_videomute(struct mtk_dp *mtk_dp, bool enable)
|
||||
{
|
||||
dptx_hal_videomute(mtk_dp, enable);
|
||||
}
|
||||
|
||||
static void dptx_fec_ready(struct mtk_dp *mtk_dp, u8 err_cnt_sel)
|
||||
{
|
||||
u8 i, data[3];
|
||||
|
||||
dptx_auxread_dpcd(mtk_dp, DP_AUX_NATIVE_READ, 0x90, 0x1, data);
|
||||
printk(BIOS_DEBUG, "FEC Capable[0], [0:3] should be 1: %#x\n",
|
||||
data[0]);
|
||||
|
||||
/*
|
||||
* FEC error count select 120[3:1]:
|
||||
* 000b: FEC_ERROR_COUNT_DIS
|
||||
* 001b: UNCORRECTED_BLOCK_ERROR_COUNT
|
||||
* 010b: CORRECTED_BLOCK_ERROR_COUNT
|
||||
* 011b: BIT_ERROR_COUNT
|
||||
* 100b: PARITY_BLOCK_ERROR_COUNT
|
||||
* 101b: PARITY_BIT_ERROR_COUNT
|
||||
*/
|
||||
if (data[0] & BIT(0)) {
|
||||
mtk_dp->has_fec = true;
|
||||
data[0] = (err_cnt_sel << 1) | 0x1;
|
||||
|
||||
dptx_auxwrite_dpcd(mtk_dp, DP_AUX_NATIVE_WRITE,
|
||||
0x120, 0x1, data);
|
||||
dptx_auxread_dpcd(mtk_dp, DP_AUX_NATIVE_READ,
|
||||
0x280, 0x3, data);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
printk(BIOS_DEBUG, "FEC status & error Count: %#x\n",
|
||||
data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void dptx_init_variable(struct mtk_dp *mtk_dp)
|
||||
{
|
||||
mtk_dp->regs = (void *)EDP_BASE;
|
||||
mtk_dp->train_info.sys_max_linkrate = DP_LINKRATE_HBR3;
|
||||
mtk_dp->train_info.linkrate = DP_LINKRATE_HBR2;
|
||||
mtk_dp->train_info.linklane_count = DP_LANECOUNT_4;
|
||||
mtk_dp->train_info.sink_extcap_en = false;
|
||||
mtk_dp->train_info.sink_ssc_en = false;
|
||||
mtk_dp->train_info.tps3 = true;
|
||||
mtk_dp->train_info.tps4 = true;
|
||||
mtk_dp->training_state = DPTX_NTSTATE_STARTUP;
|
||||
mtk_dp->info.format = DP_COLOR_FORMAT_RGB_444;
|
||||
mtk_dp->info.depth = DP_COLOR_DEPTH_8BIT;
|
||||
mtk_dp->power_on = false;
|
||||
mtk_dp->video_enable = false;
|
||||
mtk_dp->dp_ready = false;
|
||||
mtk_dp->has_dsc = false;
|
||||
mtk_dp->has_fec = false;
|
||||
mtk_dp->dsc_enable = false;
|
||||
}
|
||||
|
||||
static inline bool dptx_check_res_sample_rate(const struct edid *edid)
|
||||
{
|
||||
return edid->mode.va + edid->mode.vbl <= 525;
|
||||
}
|
||||
|
||||
static void dptx_setsdp_downcnt_init(struct mtk_dp *mtk_dp, u16 sram_read_start)
|
||||
{
|
||||
u32 count = 0; /* count: sdp_down_cnt_init */
|
||||
u8 offset;
|
||||
|
||||
if (mtk_dp->edid->mode.pixel_clock > 0)
|
||||
count = (sram_read_start * 2700 * 8 *
|
||||
mtk_dp->train_info.linkrate) /
|
||||
(mtk_dp->edid->mode.pixel_clock * 4);
|
||||
|
||||
switch (mtk_dp->train_info.linklane_count) {
|
||||
case DP_LANECOUNT_1:
|
||||
count = (count > 0x1a) ? count : 0x1a;
|
||||
break;
|
||||
case DP_LANECOUNT_2:
|
||||
/* Case for LowResolution and High Audio Sample Rate. */
|
||||
offset = dptx_check_res_sample_rate(mtk_dp->edid) ?
|
||||
0x04 : 0x00;
|
||||
count = (count > 0x10) ? count : 0x10 + offset;
|
||||
break;
|
||||
case DP_LANECOUNT_4:
|
||||
default:
|
||||
count = (count > 0x06) ? count : 0x06;
|
||||
break;
|
||||
}
|
||||
|
||||
printk(BIOS_DEBUG, "pixel rate(khz) = %d, sdp_dc_init = %#x\n",
|
||||
mtk_dp->edid->mode.pixel_clock, count);
|
||||
|
||||
dptx_hal_setsdp_downcnt_init(mtk_dp, count);
|
||||
}
|
||||
|
||||
static void dptx_setsdp_downcnt_init_inhblanking(struct mtk_dp *mtk_dp)
|
||||
{
|
||||
int pixclk_mhz = mtk_dp->edid->mode.pixel_clock / 1000;
|
||||
u8 offset;
|
||||
u16 count = 0; /* count: sdp_down_cnt_init*/
|
||||
|
||||
switch (mtk_dp->train_info.linklane_count) {
|
||||
case DP_LANECOUNT_1:
|
||||
count = 0x20;
|
||||
break;
|
||||
case DP_LANECOUNT_2:
|
||||
offset = dptx_check_res_sample_rate(mtk_dp->edid) ?
|
||||
0x14 : 0x00;
|
||||
count = 0x0018 + offset;
|
||||
break;
|
||||
case DP_LANECOUNT_4:
|
||||
default:
|
||||
offset = dptx_check_res_sample_rate(mtk_dp->edid) ?
|
||||
0x08 : 0x00;
|
||||
if (pixclk_mhz > mtk_dp->train_info.linkrate * 27) {
|
||||
count = 0x8;
|
||||
printk(BIOS_ERR, "Pixclk > LinkRateChange\n");
|
||||
} else {
|
||||
count = 0x10 + offset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
dptx_hal_setsdp_downcnt_init_inhblanking(mtk_dp, count);
|
||||
}
|
||||
|
||||
static void dptx_set_tu(struct mtk_dp *mtk_dp)
|
||||
{
|
||||
u8 bpp;
|
||||
u16 sram_read_start = DPTX_TBC_BUF_READSTARTADRTHRD;
|
||||
int tu_size, f_value, pixclk_mhz;
|
||||
|
||||
bpp = dptx_hal_get_colorbpp(mtk_dp);
|
||||
pixclk_mhz = mtk_dp->edid->mode.pixel_clock / 1000;
|
||||
tu_size = (640 * pixclk_mhz * bpp) /
|
||||
(mtk_dp->train_info.linkrate * 27 *
|
||||
mtk_dp->train_info.linklane_count * 8);
|
||||
|
||||
f_value = tu_size % 10;
|
||||
printk(BIOS_DEBUG, "TU_size %d, FValue %d\n", tu_size, f_value);
|
||||
|
||||
if (mtk_dp->train_info.linklane_count > 0) {
|
||||
sram_read_start = mtk_dp->edid->mode.ha /
|
||||
(mtk_dp->train_info.linklane_count *
|
||||
4 * 2 * 2);
|
||||
sram_read_start = MIN(sram_read_start,
|
||||
DPTX_TBC_BUF_READSTARTADRTHRD);
|
||||
dptx_hal_settu_sramrd_start(mtk_dp, sram_read_start);
|
||||
}
|
||||
|
||||
dptx_hal_settu_setencoder(mtk_dp);
|
||||
dptx_setsdp_downcnt_init_inhblanking(mtk_dp);
|
||||
dptx_setsdp_downcnt_init(mtk_dp, sram_read_start);
|
||||
}
|
||||
|
||||
static void dptx_set_misc(struct mtk_dp *mtk_dp)
|
||||
{
|
||||
u8 format, depth;
|
||||
union misc_t dptx_misc;
|
||||
|
||||
format = mtk_dp->info.format;
|
||||
depth = mtk_dp->info.depth;
|
||||
|
||||
/*
|
||||
* MISC 0/1 reference to spec 1.4a p143 Table 2-96.
|
||||
* MISC0[7:5] color depth.
|
||||
*/
|
||||
dptx_misc.dp_misc.color_depth = depth;
|
||||
|
||||
/*
|
||||
* MISC0[3]: 0->RGB, 1->YUV
|
||||
* MISC0[2:1]: 01b->4:2:2, 10b->4:4:4
|
||||
*/
|
||||
switch (format) {
|
||||
case DP_COLOR_FORMAT_YUV_444:
|
||||
dptx_misc.dp_misc.color_format = 0x1;
|
||||
break;
|
||||
case DP_COLOR_FORMAT_YUV_422:
|
||||
dptx_misc.dp_misc.color_format = 0x2;
|
||||
break;
|
||||
case DP_COLOR_FORMAT_RAW:
|
||||
dptx_misc.dp_misc.color_format = 0x1;
|
||||
dptx_misc.dp_misc.spec_def2 = 0x1;
|
||||
break;
|
||||
case DP_COLOR_FORMAT_YONLY:
|
||||
dptx_misc.dp_misc.color_format = 0x0;
|
||||
dptx_misc.dp_misc.spec_def2 = 0x1;
|
||||
break;
|
||||
case DP_COLOR_FORMAT_YUV_420:
|
||||
case DP_COLOR_FORMAT_RGB_444:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
dptx_hal_setmisc(mtk_dp, dptx_misc.cmisc);
|
||||
}
|
||||
|
||||
static void dptx_set_dptxout(struct mtk_dp *mtk_dp)
|
||||
{
|
||||
dptx_hal_bypassmsa_en(mtk_dp, false);
|
||||
dptx_set_tu(mtk_dp);
|
||||
}
|
||||
|
||||
static bool dptx_training_checkswingpre(struct mtk_dp *mtk_dp,
|
||||
u8 target_lane_count,
|
||||
const u8 *dpcp202_x, u8 *dpcp_buf)
|
||||
|
|
@ -864,80 +358,6 @@ static int dptx_trainingflow(struct mtk_dp *mtk_dp,
|
|||
return DPTX_PASS;
|
||||
}
|
||||
|
||||
static void dptx_check_sinkcap(struct mtk_dp *mtk_dp)
|
||||
{
|
||||
u8 buffer[16];
|
||||
|
||||
memset(buffer, 0x0, sizeof(buffer));
|
||||
|
||||
buffer[0] = 0x1;
|
||||
dptx_auxwrite_dpcd(mtk_dp, DP_AUX_NATIVE_WRITE,
|
||||
DPCD_00600, 0x1, buffer);
|
||||
|
||||
mdelay(2);
|
||||
|
||||
dptx_auxread_dpcd(mtk_dp, DP_AUX_NATIVE_READ,
|
||||
DPCD_00000, 0x10, buffer);
|
||||
|
||||
mtk_dp->train_info.sink_extcap_en = false;
|
||||
mtk_dp->train_info.dpcd_rev = buffer[0];
|
||||
|
||||
printk(BIOS_INFO, "SINK DPCD version: %#x\n",
|
||||
mtk_dp->train_info.dpcd_rev);
|
||||
|
||||
memcpy(mtk_dp->rx_cap, buffer, sizeof(mtk_dp->rx_cap));
|
||||
|
||||
mtk_dp->rx_cap[14] &= 0x7f;
|
||||
|
||||
if (mtk_dp->train_info.dpcd_rev >= 0x14)
|
||||
dptx_fec_ready(mtk_dp, FEC_BIT_ERROR_COUNT);
|
||||
|
||||
mtk_dp->train_info.linkrate = MIN(buffer[0x1],
|
||||
mtk_dp->train_info.sys_max_linkrate);
|
||||
mtk_dp->train_info.linklane_count = MIN(buffer[2] & 0x1F,
|
||||
MAX_LANECOUNT);
|
||||
|
||||
mtk_dp->train_info.tps3 = (buffer[2] & BIT(6)) >> 0x6;
|
||||
mtk_dp->train_info.tps4 = (buffer[3] & BIT(7)) >> 0x7;
|
||||
|
||||
mtk_dp->train_info.down_stream_port_present = (buffer[5] & BIT(0));
|
||||
|
||||
if ((buffer[3] & BIT(0)) == 0x1) {
|
||||
printk(BIOS_INFO, "SINK SUPPORT SSC!\n");
|
||||
mtk_dp->train_info.sink_ssc_en = true;
|
||||
} else {
|
||||
printk(BIOS_INFO, "SINK NOT SUPPORT SSC!\n");
|
||||
mtk_dp->train_info.sink_ssc_en = false;
|
||||
}
|
||||
|
||||
dptx_auxread_dpcd(mtk_dp, DP_AUX_NATIVE_READ,
|
||||
DPCD_00021, 0x1, buffer);
|
||||
mtk_dp->train_info.dp_mstcap = (buffer[0] & BIT(0));
|
||||
mtk_dp->train_info.dp_mstbranch = false;
|
||||
|
||||
if (mtk_dp->train_info.dp_mstcap == BIT(0)) {
|
||||
if (mtk_dp->train_info.down_stream_port_present == 0x1)
|
||||
mtk_dp->train_info.dp_mstbranch = true;
|
||||
|
||||
dptx_auxread_dpcd(mtk_dp, DP_AUX_NATIVE_READ,
|
||||
DPCD_02003, 0x1, buffer);
|
||||
if (buffer[0] != 0x0)
|
||||
dptx_auxwrite_dpcd(mtk_dp, DP_AUX_NATIVE_WRITE,
|
||||
DPCD_02003, 0x1, buffer);
|
||||
}
|
||||
|
||||
dptx_auxread_dpcd(mtk_dp, DP_AUX_NATIVE_READ,
|
||||
DPCD_00600, 0x1, buffer);
|
||||
if (buffer[0] != 0x1) {
|
||||
buffer[0] = 0x1;
|
||||
dptx_auxwrite_dpcd(mtk_dp, DP_AUX_NATIVE_WRITE,
|
||||
DPCD_00600, 0x1, buffer);
|
||||
}
|
||||
|
||||
dptx_auxread_dpcd(mtk_dp, DP_AUX_NATIVE_READ,
|
||||
DPCD_00200, 0x2, buffer);
|
||||
}
|
||||
|
||||
static void dptx_training_changemode(struct mtk_dp *mtk_dp)
|
||||
{
|
||||
dptx_hal_phyd_reset(mtk_dp);
|
||||
|
|
@ -1058,43 +478,6 @@ static void dptx_init_port(struct mtk_dp *mtk_dp)
|
|||
dptx_hal_hpd_int_en(mtk_dp, true);
|
||||
}
|
||||
|
||||
static void dptx_video_enable(struct mtk_dp *mtk_dp, bool enable)
|
||||
{
|
||||
printk(BIOS_INFO, "Output Video %s!\n", enable ?
|
||||
"enable" : "disable");
|
||||
|
||||
if (enable) {
|
||||
dptx_set_dptxout(mtk_dp);
|
||||
dptx_videomute(mtk_dp, false);
|
||||
dptx_hal_verify_clock(mtk_dp);
|
||||
} else
|
||||
dptx_videomute(mtk_dp, true);
|
||||
}
|
||||
|
||||
static void dptx_set_color_format(struct mtk_dp *mtk_dp, u8 color_format)
|
||||
{
|
||||
dptx_hal_set_color_format(mtk_dp, color_format);
|
||||
}
|
||||
|
||||
static void dptx_set_color_depth(struct mtk_dp *mtk_dp, u8 color_depth)
|
||||
{
|
||||
dptx_hal_set_color_depth(mtk_dp, color_depth);
|
||||
}
|
||||
|
||||
static void dptx_video_config(struct mtk_dp *mtk_dp)
|
||||
{
|
||||
u32 mvid = 0;
|
||||
bool overwrite = false;
|
||||
|
||||
dptx_hal_overwrite_mn(mtk_dp, overwrite, mvid, 0x8000);
|
||||
|
||||
/* Interlace does not support. */
|
||||
dptx_hal_set_msa(mtk_dp);
|
||||
dptx_set_misc(mtk_dp);
|
||||
dptx_set_color_depth(mtk_dp, mtk_dp->info.depth);
|
||||
dptx_set_color_format(mtk_dp, mtk_dp->info.format);
|
||||
}
|
||||
|
||||
int mtk_edp_init(struct edid *edid)
|
||||
{
|
||||
struct mtk_dp mtk_edp;
|
||||
|
|
|
|||
490
src/soc/mediatek/common/dp/dptx_common.c
Normal file
490
src/soc/mediatek/common/dp/dptx_common.c
Normal file
|
|
@ -0,0 +1,490 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#include <commonlib/bsd/helpers.h>
|
||||
#include <console/console.h>
|
||||
#include <delay.h>
|
||||
#include <device/mmio.h>
|
||||
#include <edid.h>
|
||||
#include <soc/addressmap.h>
|
||||
#include <soc/dptx.h>
|
||||
#include <soc/dptx_hal.h>
|
||||
#include <soc/dptx_reg.h>
|
||||
#include <soc/dp_intf.h>
|
||||
#include <string.h>
|
||||
|
||||
static bool dptx_auxwrite_bytes(struct mtk_dp *mtk_dp, u8 cmd, u32 dpcd_addr,
|
||||
size_t length, u8 *data)
|
||||
{
|
||||
if (retry(7, dptx_hal_auxwrite_bytes(mtk_dp, cmd, dpcd_addr, length, data),
|
||||
mdelay(1)))
|
||||
return true;
|
||||
|
||||
printk(BIOS_ERR, "aux write fail: cmd = %d, addr = %#x, len = %ld\n",
|
||||
cmd, dpcd_addr, length);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool dptx_auxwrite_dpcd(struct mtk_dp *mtk_dp, u8 cmd, u32 dpcd_addr,
|
||||
size_t length, u8 *data)
|
||||
{
|
||||
bool ret = true;
|
||||
size_t offset = 0;
|
||||
size_t len;
|
||||
|
||||
while (offset < length) {
|
||||
len = MIN(length - offset, DP_AUX_MAX_PAYLOAD_BYTES);
|
||||
ret &= dptx_auxwrite_bytes(mtk_dp, cmd, dpcd_addr + offset,
|
||||
len, data + offset);
|
||||
offset += len;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool dptx_auxread_bytes(struct mtk_dp *mtk_dp, u8 cmd,
|
||||
u32 dpcd_addr, size_t length, u8 *data)
|
||||
{
|
||||
if (retry(7, dptx_hal_auxread_bytes(mtk_dp, cmd, dpcd_addr, length, data),
|
||||
mdelay(1)))
|
||||
return true;
|
||||
|
||||
printk(BIOS_ERR, "aux read fail: cmd = %d, addr = %#x, len = %ld\n",
|
||||
cmd, dpcd_addr, length);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool dptx_auxread_dpcd(struct mtk_dp *mtk_dp, u8 cmd, u32 dpcd_addr,
|
||||
size_t length, u8 *rxbuf)
|
||||
{
|
||||
bool ret = true;
|
||||
size_t offset = 0;
|
||||
size_t len;
|
||||
|
||||
while (offset < length) {
|
||||
len = MIN(length - offset, DP_AUX_MAX_PAYLOAD_BYTES);
|
||||
ret &= dptx_auxread_bytes(mtk_dp, cmd, dpcd_addr + offset,
|
||||
len, rxbuf + offset);
|
||||
offset += len;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dptx_get_edid(struct mtk_dp *mtk_dp, struct edid *out)
|
||||
{
|
||||
int ret;
|
||||
u8 edid[ONE_BLOCK_SIZE];
|
||||
u8 tmp = 0;
|
||||
|
||||
dptx_auxwrite_dpcd(mtk_dp, DP_AUX_I2C_WRITE, 0x50, 0x1, &tmp);
|
||||
|
||||
for (tmp = 0; tmp < ONE_BLOCK_SIZE / DP_AUX_MAX_PAYLOAD_BYTES; tmp++)
|
||||
dptx_auxread_dpcd(mtk_dp, DP_AUX_I2C_READ,
|
||||
0x50, DP_AUX_MAX_PAYLOAD_BYTES,
|
||||
edid + tmp * 16);
|
||||
|
||||
ret = decode_edid(edid, ONE_BLOCK_SIZE, out);
|
||||
if (ret != EDID_CONFORMANT) {
|
||||
printk(BIOS_ERR, "failed to decode edid(%d).\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mtk_dp->edid = out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 dptx_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r)
|
||||
{
|
||||
return link_status[r - DP_LANE0_1_STATUS];
|
||||
}
|
||||
|
||||
static u8 dptx_get_lane_status(const u8 link_status[DP_LINK_STATUS_SIZE], int lane)
|
||||
{
|
||||
int i = DP_LANE0_1_STATUS + (lane >> 1);
|
||||
int s = (lane & 1) * 4;
|
||||
u8 l = dptx_link_status(link_status, i);
|
||||
|
||||
return (l >> s) & 0xf;
|
||||
}
|
||||
|
||||
bool dptx_clock_recovery_ok(const u8 link_status[DP_LINK_STATUS_SIZE], int lane_count)
|
||||
{
|
||||
int lane;
|
||||
u8 lane_status;
|
||||
|
||||
for (lane = 0; lane < lane_count; lane++) {
|
||||
lane_status = dptx_get_lane_status(link_status, lane);
|
||||
if ((lane_status & DP_LANE_CR_DONE) == 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void dptx_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
|
||||
{
|
||||
u32 rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
|
||||
DP_TRAINING_AUX_RD_MASK;
|
||||
|
||||
if (rd_interval > 4)
|
||||
printk(BIOS_ERR, "aux interval %d, out of range (max 4)\n",
|
||||
rd_interval);
|
||||
|
||||
if (rd_interval == 0 || dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14)
|
||||
rd_interval = 1;
|
||||
else
|
||||
rd_interval *= 4;
|
||||
|
||||
mdelay(rd_interval);
|
||||
}
|
||||
|
||||
void dptx_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
|
||||
{
|
||||
u32 rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
|
||||
DP_TRAINING_AUX_RD_MASK;
|
||||
|
||||
if (rd_interval > 4)
|
||||
printk(BIOS_ERR, "aux interval %d, out of range (max 4)\n",
|
||||
rd_interval);
|
||||
|
||||
if (rd_interval == 0)
|
||||
rd_interval = 1;
|
||||
else
|
||||
rd_interval *= 4;
|
||||
|
||||
mdelay(rd_interval);
|
||||
}
|
||||
|
||||
bool dptx_channel_eq_ok(const u8 link_status[DP_LINK_STATUS_SIZE],
|
||||
int lane_count)
|
||||
{
|
||||
u8 lane_align;
|
||||
u8 lane_status;
|
||||
int lane;
|
||||
|
||||
lane_align = dptx_link_status(link_status,
|
||||
DP_LANE_ALIGN_STATUS_UPDATED);
|
||||
|
||||
if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
|
||||
return false;
|
||||
|
||||
for (lane = 0; lane < lane_count; lane++) {
|
||||
lane_status = dptx_get_lane_status(link_status, lane);
|
||||
if ((lane_status & DP_CHANNEL_EQ_BITS) != DP_CHANNEL_EQ_BITS)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dptx_videomute(struct mtk_dp *mtk_dp, bool enable)
|
||||
{
|
||||
dptx_hal_videomute(mtk_dp, enable);
|
||||
}
|
||||
|
||||
static void dptx_fec_ready(struct mtk_dp *mtk_dp, u8 err_cnt_sel)
|
||||
{
|
||||
u8 i, data[3];
|
||||
|
||||
dptx_auxread_dpcd(mtk_dp, DP_AUX_NATIVE_READ, 0x90, 0x1, data);
|
||||
printk(BIOS_DEBUG, "FEC Capable[0], [0:3] should be 1: %#x\n",
|
||||
data[0]);
|
||||
|
||||
/*
|
||||
* FEC error count select 120[3:1]:
|
||||
* 000b: FEC_ERROR_COUNT_DIS
|
||||
* 001b: UNCORRECTED_BLOCK_ERROR_COUNT
|
||||
* 010b: CORRECTED_BLOCK_ERROR_COUNT
|
||||
* 011b: BIT_ERROR_COUNT
|
||||
* 100b: PARITY_BLOCK_ERROR_COUNT
|
||||
* 101b: PARITY_BIT_ERROR_COUNT
|
||||
*/
|
||||
if (data[0] & BIT(0)) {
|
||||
mtk_dp->has_fec = true;
|
||||
data[0] = (err_cnt_sel << 1) | 0x1;
|
||||
|
||||
dptx_auxwrite_dpcd(mtk_dp, DP_AUX_NATIVE_WRITE,
|
||||
0x120, 0x1, data);
|
||||
dptx_auxread_dpcd(mtk_dp, DP_AUX_NATIVE_READ,
|
||||
0x280, 0x3, data);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
printk(BIOS_DEBUG, "FEC status & error Count: %#x\n",
|
||||
data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void dptx_init_variable(struct mtk_dp *mtk_dp)
|
||||
{
|
||||
mtk_dp->regs = (void *)EDP_BASE;
|
||||
mtk_dp->train_info.sys_max_linkrate = DP_LINKRATE_HBR3;
|
||||
mtk_dp->train_info.linkrate = DP_LINKRATE_HBR2;
|
||||
mtk_dp->train_info.linklane_count = DP_LANECOUNT_4;
|
||||
mtk_dp->train_info.sink_extcap_en = false;
|
||||
mtk_dp->train_info.sink_ssc_en = false;
|
||||
mtk_dp->train_info.tps3 = true;
|
||||
mtk_dp->train_info.tps4 = true;
|
||||
mtk_dp->training_state = DPTX_NTSTATE_STARTUP;
|
||||
mtk_dp->info.format = DP_COLOR_FORMAT_RGB_444;
|
||||
mtk_dp->info.depth = DP_COLOR_DEPTH_8BIT;
|
||||
mtk_dp->power_on = false;
|
||||
mtk_dp->video_enable = false;
|
||||
mtk_dp->dp_ready = false;
|
||||
mtk_dp->has_dsc = false;
|
||||
mtk_dp->has_fec = false;
|
||||
mtk_dp->dsc_enable = false;
|
||||
}
|
||||
|
||||
static inline bool dptx_check_res_sample_rate(const struct edid *edid)
|
||||
{
|
||||
return edid->mode.va + edid->mode.vbl <= 525;
|
||||
}
|
||||
|
||||
static void dptx_setsdp_downcnt_init(struct mtk_dp *mtk_dp, u16 sram_read_start)
|
||||
{
|
||||
u32 count = 0; /* count: sdp_down_cnt_init */
|
||||
u8 offset;
|
||||
|
||||
if (mtk_dp->edid->mode.pixel_clock > 0)
|
||||
count = (sram_read_start * 2700 * 8 *
|
||||
mtk_dp->train_info.linkrate) /
|
||||
(mtk_dp->edid->mode.pixel_clock * 4);
|
||||
|
||||
switch (mtk_dp->train_info.linklane_count) {
|
||||
case DP_LANECOUNT_1:
|
||||
count = (count > 0x1a) ? count : 0x1a;
|
||||
break;
|
||||
case DP_LANECOUNT_2:
|
||||
/* Case for LowResolution and High Audio Sample Rate. */
|
||||
offset = dptx_check_res_sample_rate(mtk_dp->edid) ?
|
||||
0x04 : 0x00;
|
||||
count = (count > 0x10) ? count : 0x10 + offset;
|
||||
break;
|
||||
case DP_LANECOUNT_4:
|
||||
default:
|
||||
count = (count > 0x06) ? count : 0x06;
|
||||
break;
|
||||
}
|
||||
|
||||
printk(BIOS_DEBUG, "pixel rate(khz) = %d, sdp_dc_init = %#x\n",
|
||||
mtk_dp->edid->mode.pixel_clock, count);
|
||||
|
||||
dptx_hal_setsdp_downcnt_init(mtk_dp, count);
|
||||
}
|
||||
|
||||
static void dptx_setsdp_downcnt_init_inhblanking(struct mtk_dp *mtk_dp)
|
||||
{
|
||||
int pixclk_mhz = mtk_dp->edid->mode.pixel_clock / 1000;
|
||||
u8 offset;
|
||||
u16 count = 0; /* count: sdp_down_cnt_init*/
|
||||
|
||||
switch (mtk_dp->train_info.linklane_count) {
|
||||
case DP_LANECOUNT_1:
|
||||
count = 0x20;
|
||||
break;
|
||||
case DP_LANECOUNT_2:
|
||||
offset = dptx_check_res_sample_rate(mtk_dp->edid) ?
|
||||
0x14 : 0x00;
|
||||
count = 0x0018 + offset;
|
||||
break;
|
||||
case DP_LANECOUNT_4:
|
||||
default:
|
||||
offset = dptx_check_res_sample_rate(mtk_dp->edid) ?
|
||||
0x08 : 0x00;
|
||||
if (pixclk_mhz > mtk_dp->train_info.linkrate * 27) {
|
||||
count = 0x8;
|
||||
printk(BIOS_ERR, "Pixclk > LinkRateChange\n");
|
||||
} else {
|
||||
count = 0x10 + offset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
dptx_hal_setsdp_downcnt_init_inhblanking(mtk_dp, count);
|
||||
}
|
||||
|
||||
static void dptx_set_tu(struct mtk_dp *mtk_dp)
|
||||
{
|
||||
u8 bpp;
|
||||
u16 sram_read_start = DPTX_TBC_BUF_READSTARTADRTHRD;
|
||||
int tu_size, f_value, pixclk_mhz;
|
||||
|
||||
bpp = dptx_hal_get_colorbpp(mtk_dp);
|
||||
pixclk_mhz = mtk_dp->edid->mode.pixel_clock / 1000;
|
||||
tu_size = (640 * pixclk_mhz * bpp) /
|
||||
(mtk_dp->train_info.linkrate * 27 *
|
||||
mtk_dp->train_info.linklane_count * 8);
|
||||
|
||||
f_value = tu_size % 10;
|
||||
printk(BIOS_DEBUG, "TU_size %d, FValue %d\n", tu_size, f_value);
|
||||
|
||||
if (mtk_dp->train_info.linklane_count > 0) {
|
||||
sram_read_start = mtk_dp->edid->mode.ha /
|
||||
(mtk_dp->train_info.linklane_count *
|
||||
4 * 2 * 2);
|
||||
sram_read_start = MIN(sram_read_start,
|
||||
DPTX_TBC_BUF_READSTARTADRTHRD);
|
||||
dptx_hal_settu_sramrd_start(mtk_dp, sram_read_start);
|
||||
}
|
||||
|
||||
dptx_hal_settu_setencoder(mtk_dp);
|
||||
dptx_setsdp_downcnt_init_inhblanking(mtk_dp);
|
||||
dptx_setsdp_downcnt_init(mtk_dp, sram_read_start);
|
||||
}
|
||||
|
||||
static void dptx_set_misc(struct mtk_dp *mtk_dp)
|
||||
{
|
||||
u8 format, depth;
|
||||
union misc_t dptx_misc;
|
||||
|
||||
format = mtk_dp->info.format;
|
||||
depth = mtk_dp->info.depth;
|
||||
|
||||
/*
|
||||
* MISC 0/1 reference to spec 1.4a p143 Table 2-96.
|
||||
* MISC0[7:5] color depth.
|
||||
*/
|
||||
dptx_misc.dp_misc.color_depth = depth;
|
||||
|
||||
/*
|
||||
* MISC0[3]: 0->RGB, 1->YUV
|
||||
* MISC0[2:1]: 01b->4:2:2, 10b->4:4:4
|
||||
*/
|
||||
switch (format) {
|
||||
case DP_COLOR_FORMAT_YUV_444:
|
||||
dptx_misc.dp_misc.color_format = 0x1;
|
||||
break;
|
||||
case DP_COLOR_FORMAT_YUV_422:
|
||||
dptx_misc.dp_misc.color_format = 0x2;
|
||||
break;
|
||||
case DP_COLOR_FORMAT_RAW:
|
||||
dptx_misc.dp_misc.color_format = 0x1;
|
||||
dptx_misc.dp_misc.spec_def2 = 0x1;
|
||||
break;
|
||||
case DP_COLOR_FORMAT_YONLY:
|
||||
dptx_misc.dp_misc.color_format = 0x0;
|
||||
dptx_misc.dp_misc.spec_def2 = 0x1;
|
||||
break;
|
||||
case DP_COLOR_FORMAT_YUV_420:
|
||||
case DP_COLOR_FORMAT_RGB_444:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
dptx_hal_setmisc(mtk_dp, dptx_misc.cmisc);
|
||||
}
|
||||
|
||||
static void dptx_set_dptxout(struct mtk_dp *mtk_dp)
|
||||
{
|
||||
dptx_hal_bypassmsa_en(mtk_dp, false);
|
||||
dptx_set_tu(mtk_dp);
|
||||
}
|
||||
|
||||
void dptx_check_sinkcap(struct mtk_dp *mtk_dp)
|
||||
{
|
||||
u8 buffer[16];
|
||||
|
||||
memset(buffer, 0x0, sizeof(buffer));
|
||||
|
||||
buffer[0] = 0x1;
|
||||
dptx_auxwrite_dpcd(mtk_dp, DP_AUX_NATIVE_WRITE,
|
||||
DPCD_00600, 0x1, buffer);
|
||||
|
||||
mdelay(2);
|
||||
|
||||
dptx_auxread_dpcd(mtk_dp, DP_AUX_NATIVE_READ,
|
||||
DPCD_00000, 0x10, buffer);
|
||||
|
||||
mtk_dp->train_info.sink_extcap_en = false;
|
||||
mtk_dp->train_info.dpcd_rev = buffer[0];
|
||||
|
||||
printk(BIOS_INFO, "SINK DPCD version: %#x\n",
|
||||
mtk_dp->train_info.dpcd_rev);
|
||||
|
||||
memcpy(mtk_dp->rx_cap, buffer, sizeof(mtk_dp->rx_cap));
|
||||
|
||||
mtk_dp->rx_cap[14] &= 0x7f;
|
||||
|
||||
if (mtk_dp->train_info.dpcd_rev >= 0x14)
|
||||
dptx_fec_ready(mtk_dp, FEC_BIT_ERROR_COUNT);
|
||||
|
||||
mtk_dp->train_info.linkrate = MIN(buffer[0x1],
|
||||
mtk_dp->train_info.sys_max_linkrate);
|
||||
mtk_dp->train_info.linklane_count = MIN(buffer[2] & 0x1F,
|
||||
MAX_LANECOUNT);
|
||||
|
||||
mtk_dp->train_info.tps3 = (buffer[2] & BIT(6)) >> 0x6;
|
||||
mtk_dp->train_info.tps4 = (buffer[3] & BIT(7)) >> 0x7;
|
||||
|
||||
mtk_dp->train_info.down_stream_port_present = (buffer[5] & BIT(0));
|
||||
|
||||
if ((buffer[3] & BIT(0)) == 0x1) {
|
||||
printk(BIOS_INFO, "SINK SUPPORT SSC!\n");
|
||||
mtk_dp->train_info.sink_ssc_en = true;
|
||||
} else {
|
||||
printk(BIOS_INFO, "SINK NOT SUPPORT SSC!\n");
|
||||
mtk_dp->train_info.sink_ssc_en = false;
|
||||
}
|
||||
|
||||
dptx_auxread_dpcd(mtk_dp, DP_AUX_NATIVE_READ,
|
||||
DPCD_00021, 0x1, buffer);
|
||||
mtk_dp->train_info.dp_mstcap = (buffer[0] & BIT(0));
|
||||
mtk_dp->train_info.dp_mstbranch = false;
|
||||
|
||||
if (mtk_dp->train_info.dp_mstcap == BIT(0)) {
|
||||
if (mtk_dp->train_info.down_stream_port_present == 0x1)
|
||||
mtk_dp->train_info.dp_mstbranch = true;
|
||||
|
||||
dptx_auxread_dpcd(mtk_dp, DP_AUX_NATIVE_READ,
|
||||
DPCD_02003, 0x1, buffer);
|
||||
if (buffer[0] != 0x0)
|
||||
dptx_auxwrite_dpcd(mtk_dp, DP_AUX_NATIVE_WRITE,
|
||||
DPCD_02003, 0x1, buffer);
|
||||
}
|
||||
|
||||
dptx_auxread_dpcd(mtk_dp, DP_AUX_NATIVE_READ,
|
||||
DPCD_00600, 0x1, buffer);
|
||||
if (buffer[0] != 0x1) {
|
||||
buffer[0] = 0x1;
|
||||
dptx_auxwrite_dpcd(mtk_dp, DP_AUX_NATIVE_WRITE,
|
||||
DPCD_00600, 0x1, buffer);
|
||||
}
|
||||
|
||||
dptx_auxread_dpcd(mtk_dp, DP_AUX_NATIVE_READ,
|
||||
DPCD_00200, 0x2, buffer);
|
||||
}
|
||||
|
||||
void dptx_video_enable(struct mtk_dp *mtk_dp, bool enable)
|
||||
{
|
||||
printk(BIOS_INFO, "Output Video %s!\n", enable ?
|
||||
"enable" : "disable");
|
||||
|
||||
if (enable) {
|
||||
dptx_set_dptxout(mtk_dp);
|
||||
dptx_videomute(mtk_dp, false);
|
||||
dptx_hal_verify_clock(mtk_dp);
|
||||
} else
|
||||
dptx_videomute(mtk_dp, true);
|
||||
}
|
||||
|
||||
static void dptx_set_color_format(struct mtk_dp *mtk_dp, u8 color_format)
|
||||
{
|
||||
dptx_hal_set_color_format(mtk_dp, color_format);
|
||||
}
|
||||
|
||||
static void dptx_set_color_depth(struct mtk_dp *mtk_dp, u8 color_depth)
|
||||
{
|
||||
dptx_hal_set_color_depth(mtk_dp, color_depth);
|
||||
}
|
||||
|
||||
void dptx_video_config(struct mtk_dp *mtk_dp)
|
||||
{
|
||||
u32 mvid = 0;
|
||||
bool overwrite = false;
|
||||
|
||||
dptx_hal_overwrite_mn(mtk_dp, overwrite, mvid, 0x8000);
|
||||
|
||||
/* Interlace does not support. */
|
||||
dptx_hal_set_msa(mtk_dp);
|
||||
dptx_set_misc(mtk_dp);
|
||||
dptx_set_color_depth(mtk_dp, mtk_dp->info.depth);
|
||||
dptx_set_color_format(mtk_dp, mtk_dp->info.format);
|
||||
}
|
||||
|
|
@ -7,6 +7,144 @@
|
|||
#define ENABLE_DPTX_EF_MODE 0x1
|
||||
#define DPTX_AUX_SET_ENAHNCED_FRAME 0x80
|
||||
|
||||
#define ONE_BLOCK_SIZE 128
|
||||
|
||||
#define DP_LINK_CONSTANT_N_VALUE 0x8000
|
||||
#define DP_LINK_STATUS_SIZE 6
|
||||
|
||||
#define DP_LANE0_1_STATUS 0x202
|
||||
#define DP_LANE2_3_STATUS 0x203
|
||||
#define DP_LANE_CR_DONE (1 << 0)
|
||||
#define DP_LANE_CHANNEL_EQ_DONE (1 << 1)
|
||||
#define DP_LANE_SYMBOL_LOCKED (1 << 2)
|
||||
|
||||
#define DP_BRANCH_OUI_HEADER_SIZE 0xc
|
||||
#define DP_RECEIVER_CAP_SIZE 0xf
|
||||
#define DP_DSC_RECEIVER_CAP_SIZE 0xf
|
||||
#define EDP_PSR_RECEIVER_CAP_SIZE 2
|
||||
#define EDP_DISPLAY_CTL_CAP_SIZE 3
|
||||
#define DP_LTTPR_COMMON_CAP_SIZE 8
|
||||
#define DP_LTTPR_PHY_CAP_SIZE 3
|
||||
|
||||
#define DP_TRAINING_AUX_RD_INTERVAL 0x00e
|
||||
#define DP_TRAINING_AUX_RD_MASK 0x7f
|
||||
#define DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT (1 << 7)
|
||||
|
||||
#define DP_EDP_DPCD_REV 0x700
|
||||
#define DP_EDP_11 0x00
|
||||
#define DP_EDP_12 0x01
|
||||
#define DP_EDP_13 0x02
|
||||
#define DP_EDP_14 0x03
|
||||
#define DP_EDP_14a 0x04
|
||||
#define DP_EDP_14b 0x05
|
||||
|
||||
/* Receiver Capability */
|
||||
#define DP_DPCD_REV 0x000
|
||||
#define DP_DPCD_REV_10 0x10
|
||||
#define DP_DPCD_REV_11 0x11
|
||||
#define DP_DPCD_REV_12 0x12
|
||||
#define DP_DPCD_REV_13 0x13
|
||||
#define DP_DPCD_REV_14 0x14
|
||||
|
||||
#define DP_CHANNEL_EQ_BITS (DP_LANE_CR_DONE | \
|
||||
DP_LANE_CHANNEL_EQ_DONE | \
|
||||
DP_LANE_SYMBOL_LOCKED)
|
||||
|
||||
#define DP_LANE_ALIGN_STATUS_UPDATED 0x204
|
||||
#define DP_INTERLANE_ALIGN_DONE (1 << 0)
|
||||
#define DP_DOWNSTREAM_PORT_STATUS_CHANGED (1 << 6)
|
||||
#define DP_LINK_STATUS_UPDATED (1 << 7)
|
||||
|
||||
#define DP_SINK_STATUS 0x205
|
||||
#define DP_RECEIVE_PORT_0_STATUS (1 << 0)
|
||||
#define DP_RECEIVE_PORT_1_STATUS (1 << 1)
|
||||
#define DP_STREAM_REGENERATION_STATUS (1 << 2)
|
||||
|
||||
#define DP_AUX_MAX_PAYLOAD_BYTES 16
|
||||
|
||||
#define MAX_LANECOUNT 4
|
||||
|
||||
enum {
|
||||
DP_LANECOUNT_1 = 0x1,
|
||||
DP_LANECOUNT_2 = 0x2,
|
||||
DP_LANECOUNT_4 = 0x4,
|
||||
};
|
||||
|
||||
enum {
|
||||
DP_VERSION_11 = 0x11,
|
||||
DP_VERSION_12 = 0x12,
|
||||
DP_VERSION_14 = 0x14,
|
||||
DP_VERSION_12_14 = 0x16,
|
||||
DP_VERSION_14_14 = 0x17,
|
||||
DP_VERSION_MAX,
|
||||
};
|
||||
|
||||
enum {
|
||||
DPTX_SWING0 = 0x00,
|
||||
DPTX_SWING1 = 0x01,
|
||||
DPTX_SWING2 = 0x02,
|
||||
DPTX_SWING3 = 0x03,
|
||||
};
|
||||
|
||||
enum {
|
||||
DPTX_PREEMPHASIS0 = 0x00,
|
||||
DPTX_PREEMPHASIS1 = 0x01,
|
||||
DPTX_PREEMPHASIS2 = 0x02,
|
||||
DPTX_PREEMPHASIS3 = 0x03,
|
||||
};
|
||||
|
||||
enum {
|
||||
DPTX_PASS = 0,
|
||||
DPTX_PLUG_OUT = 1,
|
||||
DPTX_TIMEOUT = 2,
|
||||
DPTX_AUTH_FAIL = 3,
|
||||
DPTX_EDID_FAIL = 4,
|
||||
DPTX_TRANING_FAIL = 5,
|
||||
DPTX_TRANING_STATE_CHANGE = 6,
|
||||
};
|
||||
|
||||
enum {
|
||||
FEC_ERROR_COUNT_DISABLE = 0x0,
|
||||
FEC_UNCORRECTED_BLOCK_ERROR_COUNT = 0x1,
|
||||
FEC_CORRECTED_BLOCK_ERROR_COUNT = 0x2,
|
||||
FEC_BIT_ERROR_COUNT = 0x3,
|
||||
FEC_PARITY_BLOCK_ERROR_COUNT = 0x4,
|
||||
FEC_PARITY_BIT_ERROR_COUNT = 0x5,
|
||||
};
|
||||
|
||||
enum {
|
||||
DPTX_NTSTATE_STARTUP = 0x0,
|
||||
DPTX_NTSTATE_CHECKCAP = 0x1,
|
||||
DPTX_NTSTATE_CHECKEDID = 0x2,
|
||||
DPTX_NTSTATE_TRAINING_PRE = 0x3,
|
||||
DPTX_NTSTATE_TRAINING = 0x4,
|
||||
DPTX_NTSTATE_CHECKTIMING = 0x5,
|
||||
DPTX_NTSTATE_NORMAL = 0x6,
|
||||
DPTX_NTSTATE_POWERSAVE = 0x7,
|
||||
DPTX_NTSTATE_DPIDLE = 0x8,
|
||||
DPTX_NTSTATE_MAX,
|
||||
};
|
||||
|
||||
enum {
|
||||
DPTX_DISP_NONE = 0,
|
||||
DPTX_DISP_RESUME = 1,
|
||||
DPTX_DISP_SUSPEND = 2,
|
||||
};
|
||||
|
||||
enum {
|
||||
TRAIN_STEP_SUCCESS = 0,
|
||||
TRAIN_STEP_FAIL_BREAK = 1,
|
||||
TRAIN_STEP_FAIL_NOT_BREAK = 2,
|
||||
};
|
||||
|
||||
#define DPTX_TRAIN_RETRY_LIMIT 0x8
|
||||
#define DPTX_TRAIN_MAX_ITERATION 0x5
|
||||
|
||||
#define HPD_INT_EVNET BIT(3)
|
||||
#define HPD_CONNECT BIT(2)
|
||||
#define HPD_DISCONNECT BIT(1)
|
||||
#define HPD_INITIAL_STATE 0
|
||||
|
||||
union misc_t {
|
||||
struct {
|
||||
u8 is_sync_clock : 1;
|
||||
|
|
@ -73,5 +211,20 @@ struct mtk_dp {
|
|||
};
|
||||
|
||||
int mtk_edp_init(struct edid *edid);
|
||||
bool dptx_auxread_dpcd(struct mtk_dp *mtk_dp, u8 cmd, u32 dpcd_addr,
|
||||
size_t length, u8 *rxbuf);
|
||||
bool dptx_auxwrite_dpcd(struct mtk_dp *mtk_dp, u8 cmd, u32 dpcd_addr,
|
||||
size_t length, u8 *data);
|
||||
bool dptx_channel_eq_ok(const u8 link_status[DP_LINK_STATUS_SIZE],
|
||||
int lane_count);
|
||||
void dptx_check_sinkcap(struct mtk_dp *mtk_dp);
|
||||
bool dptx_clock_recovery_ok(const u8 link_status[DP_LINK_STATUS_SIZE],
|
||||
int lane_count);
|
||||
void dptx_init_variable(struct mtk_dp *mtk_dp);
|
||||
int dptx_get_edid(struct mtk_dp *mtk_dp, struct edid *out);
|
||||
void dptx_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]);
|
||||
void dptx_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]);
|
||||
void dptx_video_config(struct mtk_dp *mtk_dp);
|
||||
void dptx_video_enable(struct mtk_dp *mtk_dp, bool enable);
|
||||
|
||||
#endif /* SOC_MEDIATEK_COMMON_DP_DPTX_COMMON_H */
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ ramstage-y += ../common/ddp.c ddp.c
|
|||
ramstage-y += ../common/devapc.c devapc.c
|
||||
ramstage-y += ../common/dfd.c
|
||||
ramstage-y += ../common/display.c
|
||||
ramstage-y += ../common/dp/dptx_common.c
|
||||
ramstage-y += ../common/dp/dp_intf.c ../common/dp/dptx.c ../common/dp/dptx_hal.c dp_intf.c
|
||||
ramstage-y += ../common/dpm_v1.c
|
||||
ramstage-$(CONFIG_DPM_FOUR_CHANNEL) += ../common/dpm_4ch.c
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ ramstage-y += ../common/dfd.c
|
|||
ramstage-y += ../common/display.c
|
||||
ramstage-y += ../common/dpm_v1.c
|
||||
ramstage-$(CONFIG_DPM_FOUR_CHANNEL) += ../common/dpm_4ch.c
|
||||
ramstage-y += ../common/dp/dptx_common.c
|
||||
ramstage-y += ../common/dp/dp_intf.c ../common/dp/dptx.c ../common/dp/dptx_hal.c dp_intf.c
|
||||
ramstage-y += emi.c
|
||||
ramstage-y += hdmi.c
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue