drm/rockchip: dw_hdmi: Support 8K HDMI output

Support hdmi frl mode and dsc function.
Support max 8K-60Hz RGB 10bit output.

Signed-off-by: Algea Cao <algea.cao@rock-chips.com>
Change-Id: Ibc2d48e2b25bc94e4be7ffa9703c400436bdee36
This commit is contained in:
Algea Cao
2021-11-21 16:16:04 +08:00
committed by Tao Huang
parent 857aaf9db3
commit b53d1f9467
3 changed files with 387 additions and 425 deletions

View File

@@ -110,31 +110,21 @@ static const struct dw_hdmi_audio_tmds_n common_tmds_n_table[] = {
};
static const struct drm_display_mode dw_hdmi_default_modes[] = {
/* 16 - 1920x1080@60Hz 16:9 */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 2 - 720x480@60Hz 4:3 */
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736,
798, 858, 0, 480, 489, 495, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
.picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
/* 95 - 3840x2160@30Hz 16:9 */
{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4016,
4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 97 - 3840x2160@60Hz 16:9 */
{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016,
4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 4 - 1280x720@60Hz 16:9 */
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390,
1430, 1650, 0, 720, 725, 730, 750, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 16 - 1920x1080@60Hz 16:9 */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 31 - 1920x1080@50Hz 16:9 */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
@@ -277,7 +267,6 @@ struct dw_hdmi_qp {
struct regmap *regm;
bool initialized; /* hdmi is enabled before bind */
struct completion scdc_cmp;
struct completion flt_cmp;
struct completion earc_cmp;
@@ -1073,12 +1062,14 @@ static void hdmi_config_CVTEM(struct dw_hdmi_qp *hdmi)
u8 data_set_length = 136;
u8 hb1[6] = { 0x80, 0, 0, 0, 0, 0x40 };
u8 *pps_body;
u32 val, i;
u32 val, i, reg;
struct drm_display_mode *mode = &hdmi->previous_mode;
int hsync, hfront, hback;
struct dw_hdmi_link_config *link_cfg;
void *data = hdmi->plat_data->phy_data;
hdmi_modb(hdmi, 0, PKTSCHED_EMP_CVTEM_TX_EN, PKTSCHED_PKT_EN);
if (hdmi->plat_data->get_link_cfg) {
link_cfg = hdmi->plat_data->get_link_cfg(data);
} else {
@@ -1086,14 +1077,16 @@ static void hdmi_config_CVTEM(struct dw_hdmi_qp *hdmi)
return;
}
if (!link_cfg->dsc_mode)
if (!link_cfg->dsc_mode) {
dev_info(hdmi->dev, "don't use dsc mode\n");
return;
}
pps_body = link_cfg->pps_payload;
hsync = mode->hsync_end - mode->hsync_start;
hfront = mode->htotal - mode->hsync_end;
hback = mode->hsync_start - mode->hdisplay;
hback = mode->htotal - mode->hsync_end;
hfront = mode->hsync_start - mode->hdisplay;
for (i = 0; i < 6; i++) {
val = i << 16 | hb1[i] << 8;
@@ -1107,13 +1100,28 @@ static void hdmi_config_CVTEM(struct dw_hdmi_qp *hdmi)
val = data_set_length << 16 | pps_body[0] << 24;
hdmi_writel(hdmi, val, PKT0_EMP_CVTEM_CONTENTS2);
for (i = 0; i < 35; i++) {
if ((i == 5) | (i == 13) | (i == 21) | (i == 29))
reg = PKT0_EMP_CVTEM_CONTENTS3;
for (i = 1; i < 125; i++) {
if (reg == PKT1_EMP_CVTEM_CONTENTS0 ||
reg == PKT2_EMP_CVTEM_CONTENTS0 ||
reg == PKT3_EMP_CVTEM_CONTENTS0 ||
reg == PKT4_EMP_CVTEM_CONTENTS0 ||
reg == PKT5_EMP_CVTEM_CONTENTS0) {
reg += 4;
i--;
continue;
val = pps_body[i * 4 + 1] | pps_body[i * 4 + 2] << 8 |
pps_body[i * 4 + 3] << 16 | pps_body[i * 4 + 4] << 24;
hdmi_writel(hdmi, val, PKT0_EMP_CVTEM_CONTENTS3 + i * 4);
}
if (i % 4 == 1)
val = pps_body[i];
if (i % 4 == 2)
val |= pps_body[i] << 8;
if (i % 4 == 3)
val |= pps_body[i] << 16;
if (!(i % 4)) {
val |= pps_body[i] << 24;
hdmi_writel(hdmi, val, reg);
reg += 4;
}
}
val = (hfront & 0xff) << 24 | pps_body[127] << 16 |
@@ -1127,6 +1135,9 @@ static void hdmi_config_CVTEM(struct dw_hdmi_qp *hdmi)
val = link_cfg->hcactive << 8 | ((hback >> 8) & 0xff);
hdmi_writel(hdmi, val, PKT5_EMP_CVTEM_CONTENTS1);
for (i = PKT5_EMP_CVTEM_CONTENTS2; i <= PKT5_EMP_CVTEM_CONTENTS7; i += 4)
hdmi_writel(hdmi, 0, i);
hdmi_modb(hdmi, PKTSCHED_EMP_CVTEM_TX_EN, PKTSCHED_EMP_CVTEM_TX_EN,
PKTSCHED_PKT_EN);
}
@@ -1221,11 +1232,13 @@ static int hdmi_start_flt(struct dw_hdmi_qp *hdmi, u8 rate)
u8 ffe_lv = 0;
int i = 0, stat;
/* Step:1 disable AVP_DATAPATH_VIDEO */
hdmi_modb(hdmi, AVP_DATAPATH_VIDEO_SWDISABLE,
AVP_DATAPATH_VIDEO_SWDISABLE, GLOBAL_SWDISABLE);
hdmi_modb(hdmi, SCDC_UPD_FLAGS_RD_IRQ, SCDC_UPD_FLAGS_RD_IRQ,
MAINUNIT_1_INT_MASK_N);
hdmi_modb(hdmi, SCDC_UPD_FLAGS_POLL_EN | SCDC_UPD_FLAGS_AUTO_CLR,
SCDC_UPD_FLAGS_POLL_EN | SCDC_UPD_FLAGS_AUTO_CLR,
SCDC_CONFIG0);
/* Step:2 FLT_READY & FFE_LEVELS read */
/* FLT_READY & FFE_LEVELS read */
for (i = 0; i < 20; i++) {
drm_scdc_readb(hdmi->ddc, SCDC_STATUS_FLAGS_0, &val);
if (val & BIT(6))
@@ -1238,56 +1251,31 @@ static int hdmi_start_flt(struct dw_hdmi_qp *hdmi, u8 rate)
return -EINVAL;
}
/* Step:3 select FRL_RATE & FFE_LEVELS */
hdmi_writel(hdmi, ffe_lv, FLT_CONFIG0);
val = ffe_lv << 4 | hdmi_set_frl_mask(rate);
/* max ffe level 3 */
val = 3 << 4 | hdmi_set_frl_mask(rate);
drm_scdc_writeb(hdmi->ddc, 0x31, val);
/* Step:5 Start LTS_3 state in source DUT */
/* select FRL_RATE & FFE_LEVELS */
hdmi_writel(hdmi, ffe_lv, FLT_CONFIG0);
/* Start LTS_3 state in source DUT */
reinit_completion(&hdmi->flt_cmp);
hdmi_modb(hdmi, FLT_EXIT_TO_LTSP_IRQ, FLT_EXIT_TO_LTSP_IRQ,
MAINUNIT_1_INT_MASK_N);
hdmi_writel(hdmi, 1, FLT_CONTROL0);
/* Step:6 wait for completed link training at source side */
stat = wait_for_completion_timeout(&hdmi->flt_cmp, HZ / 10);
if (!stat)
/* wait for completed link training at source side */
stat = wait_for_completion_timeout(&hdmi->flt_cmp, HZ * 2);
if (!stat) {
dev_err(hdmi->dev, "wait lts3 finish time out\n");
return -EAGAIN;
}
if (!(hdmi->flt_intr & FLT_EXIT_TO_LTSP_IRQ)) {
dev_err(hdmi->dev, "not to ltsp\n");
return -EINVAL;
}
/* Step:7 clear FLT_Update */
drm_scdc_writeb(hdmi->ddc, SCDC_UPDATE_0, BIT(5));
/* Step:8 check FLT_UPDATE set or not */
reinit_completion(&hdmi->scdc_cmp);
hdmi_modb(hdmi, SCDC_UPD_FLAGS_RD_IRQ, SCDC_UPD_FLAGS_RD_IRQ,
MAINUNIT_1_INT_MASK_N);
hdmi_modb(hdmi, SCDC_UPD_FLAGS_POLL_EN, SCDC_UPD_FLAGS_POLL_EN,
SCDC_CONFIG0);
/* Step:9 wait for FRL_Start is set */
stat = wait_for_completion_timeout(&hdmi->scdc_cmp, HZ / 10);
if (!stat)
return -EAGAIN;
if (hdmi->scdc_intr & SCDC_UPD_FLAGS_RD_IRQ) {
val = hdmi_readl(hdmi, SCDC_STATUS0);
/* frl start is set */
if (val & BIT(4))
drm_scdc_writeb(hdmi->ddc, SCDC_UPDATE_0, BIT(4));
} else {
dev_err(hdmi->dev, "frl is not start\n");
return -EINVAL;
}
/* Step:10 enable AVP_DATAPATH_VIDEO */
hdmi_modb(hdmi, 0, AVP_DATAPATH_VIDEO_SWDISABLE, GLOBAL_SWDISABLE);
return 0;
}
@@ -1298,9 +1286,13 @@ static void hdmi_set_op_mode(struct dw_hdmi_qp *hdmi,
{
int frl_rate;
hdmi_writel(hdmi, 0, FLT_CONFIG0);
drm_scdc_writeb(hdmi->ddc, 0x31, 0);
msleep(20);
if (!link_cfg->frl_mode) {
dev_info(hdmi->dev, "dw hdmi qp use tmds mode\n");
hdmi_modb(hdmi, 0, OPMODE_FRL, LINK_CONFIG0);
hdmi_modb(hdmi, 0, OPMODE_FRL_4LANES, LINK_CONFIG0);
return;
}
@@ -1310,8 +1302,9 @@ static void hdmi_set_op_mode(struct dw_hdmi_qp *hdmi,
else
hdmi_modb(hdmi, 0, OPMODE_FRL_4LANES, LINK_CONFIG0);
frl_rate = link_cfg->frl_lanes * link_cfg->rate_per_rate;
hdmi_modb(hdmi, 1, OPMODE_FRL, LINK_CONFIG0);
frl_rate = link_cfg->frl_lanes * link_cfg->rate_per_lane;
hdmi_start_flt(hdmi, frl_rate);
}
@@ -1436,7 +1429,7 @@ static int dw_hdmi_qp_setup(struct dw_hdmi_qp *hdmi,
vmode->mtmdsclock = hdmi_get_tmdsclock(hdmi, vmode->mpixelclock);
if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format))
vmode->mtmdsclock /= 2;
dev_dbg(hdmi->dev, "final tmdsclk = %d\n", vmode->mtmdsclock);
dev_info(hdmi->dev, "final tmdsclk = %d\n", vmode->mtmdsclock);
ret = hdmi->phy.ops->init(hdmi, hdmi->phy.data, &hdmi->previous_mode);
if (ret)
@@ -1452,26 +1445,28 @@ static int dw_hdmi_qp_setup(struct dw_hdmi_qp *hdmi,
/* not for DVI mode */
if (hdmi->sink_is_hdmi) {
dev_info(hdmi->dev, "%s HDMI mode\n", __func__);
dev_dbg(hdmi->dev, "%s HDMI mode\n", __func__);
hdmi_modb(hdmi, 0, OPMODE_DVI, LINK_CONFIG0);
hdmi_set_op_mode(hdmi, link_cfg);
hdmi_modb(hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0);
drm_scdc_readb(hdmi->ddc, SCDC_SINK_VERSION, &bytes);
drm_scdc_writeb(hdmi->ddc, SCDC_SOURCE_VERSION,
min_t(u8, bytes, SCDC_MIN_SOURCE_VERSION));
if (mode->clock > 340000) {
drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 1);
drm_scdc_set_scrambling(hdmi->ddc, 1);
hdmi_writel(hdmi, 1, SCRAMB_CONFIG0);
} else {
drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 0);
drm_scdc_set_scrambling(hdmi->ddc, 0);
hdmi_writel(hdmi, 0, SCRAMB_CONFIG0);
if (!link_cfg->frl_mode) {
drm_scdc_readb(hdmi->ddc, SCDC_SINK_VERSION, &bytes);
drm_scdc_writeb(hdmi->ddc, SCDC_SOURCE_VERSION,
min_t(u8, bytes, SCDC_MIN_SOURCE_VERSION));
if (vmode->mtmdsclock > HDMI14_MAX_TMDSCLK) {
drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 1);
drm_scdc_set_scrambling(hdmi->ddc, 1);
hdmi_writel(hdmi, 1, SCRAMB_CONFIG0);
} else {
drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 0);
drm_scdc_set_scrambling(hdmi->ddc, 0);
hdmi_writel(hdmi, 0, SCRAMB_CONFIG0);
}
}
/* HDMI Initialization Step F - Configure AVI InfoFrame */
hdmi_config_AVI(hdmi, connector, mode);
hdmi_config_CVTEM(hdmi);
hdmi_config_drm_infoframe(hdmi, connector);
hdmi_set_op_mode(hdmi, link_cfg);
} else {
hdmi_modb(hdmi, OPMODE_DVI, OPMODE_DVI, LINK_CONFIG0);
dev_info(hdmi->dev, "%s DVI mode\n", __func__);
@@ -1508,10 +1503,41 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force)
return result;
}
static int
dw_hdmi_update_hdr_property(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct dw_hdmi_qp *hdmi = container_of(connector, struct dw_hdmi_qp,
connector);
void *data = hdmi->plat_data->phy_data;
const struct hdr_static_metadata *metadata =
&connector->hdr_sink_metadata.hdmi_type1;
size_t size = sizeof(*metadata);
struct drm_property *property;
struct drm_property_blob *blob;
int ret;
if (hdmi->plat_data->get_hdr_property)
property = hdmi->plat_data->get_hdr_property(data);
else
return -EINVAL;
if (hdmi->plat_data->get_hdr_blob)
blob = hdmi->plat_data->get_hdr_blob(data);
else
return -EINVAL;
ret = drm_property_replace_global_blob(dev, &blob, size, metadata,
&connector->base, property);
return ret;
}
static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
{
struct dw_hdmi_qp *hdmi =
container_of(connector, struct dw_hdmi_qp, connector);
struct hdr_static_metadata *metedata =
&connector->hdr_sink_metadata.hdmi_type1;
struct edid *edid;
struct drm_display_mode *mode;
struct drm_display_info *info = &connector->display_info;
@@ -1521,6 +1547,7 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
if (!hdmi->ddc)
return 0;
memset(metedata, 0, sizeof(*metedata));
edid = drm_get_edid(connector, hdmi->ddc);
if (edid) {
dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n",
@@ -1533,6 +1560,7 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
if (hdmi->plat_data->get_edid_dsc_info)
hdmi->plat_data->get_edid_dsc_info(data, edid);
ret = drm_add_edid_modes(connector, edid);
dw_hdmi_update_hdr_property(connector);
kfree(edid);
} else {
hdmi->sink_is_hdmi = true;
@@ -1754,8 +1782,14 @@ static void dw_hdmi_connector_force(struct drm_connector *connector)
mutex_unlock(&hdmi->mutex);
}
static int dw_hdmi_qp_fill_modes(struct drm_connector *connector, u32 max_x,
u32 max_y)
{
return drm_helper_probe_single_connector_modes(connector, 9000, 9000);
}
static const struct drm_connector_funcs dw_hdmi_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.fill_modes = dw_hdmi_qp_fill_modes,
.detect = dw_hdmi_connector_detect,
.destroy = drm_connector_cleanup,
.force = dw_hdmi_connector_force,
@@ -1854,6 +1888,7 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
mutex_lock(&hdmi->mutex);
hdmi->disabled = true;
hdmi->curr_conn = NULL;
hdmi_writel(hdmi, 0, PKTSCHED_PKT_EN);
if (hdmi->phy.ops->disable)
hdmi->phy.ops->disable(hdmi, hdmi->phy.data);
mutex_unlock(&hdmi->mutex);
@@ -1917,23 +1952,35 @@ static irqreturn_t dw_hdmi_qp_main_hardirq(int irq, void *dev_id)
if (i2c->stat) {
hdmi_writel(hdmi, i2c->stat, MAINUNIT_1_INT_CLEAR);
complete(&i2c->cmp);
return IRQ_HANDLED;
}
if (hdmi->scdc_intr) {
hdmi_writel(hdmi, hdmi->scdc_intr, MAINUNIT_1_INT_CLEAR);
complete(&hdmi->scdc_cmp);
return IRQ_HANDLED;
}
if (hdmi->flt_intr) {
dev_dbg(hdmi->dev, "i2c flt irq:%#x\n", hdmi->flt_intr);
hdmi_writel(hdmi, hdmi->flt_intr, MAINUNIT_1_INT_CLEAR);
complete(&hdmi->flt_cmp);
return IRQ_HANDLED;
}
if (hdmi->scdc_intr) {
u8 val;
dev_dbg(hdmi->dev, "i2c scdc irq:%#x\n", hdmi->scdc_intr);
hdmi_writel(hdmi, hdmi->scdc_intr, MAINUNIT_1_INT_CLEAR);
val = hdmi_readl(hdmi, SCDC_STATUS0);
/* frl start */
if (val & BIT(4)) {
hdmi_modb(hdmi, 0, SCDC_UPD_FLAGS_POLL_EN |
SCDC_UPD_FLAGS_AUTO_CLR, SCDC_CONFIG0);
hdmi_modb(hdmi, 0, SCDC_UPD_FLAGS_RD_IRQ,
MAINUNIT_1_INT_MASK_N);
dev_info(hdmi->dev, "frl start\n");
}
}
if (stat)
return IRQ_HANDLED;
return IRQ_NONE;
}
@@ -2237,7 +2284,6 @@ __dw_hdmi_probe(struct platform_device *pdev,
if (hdmi->i2c)
dw_hdmi_i2c_init(hdmi);
init_completion(&hdmi->scdc_cmp);
init_completion(&hdmi->flt_cmp);
init_completion(&hdmi->earc_cmp);

View File

@@ -120,6 +120,9 @@
#define HDMI_FRL_MODE BIT(30)
#define HDMI_EARC_MODE BIT(29)
#define HDMI20_MAX_RATE 600000
#define HDMI_8K60_RATE 2376000
/**
* struct rockchip_hdmi_chip_data - splite the grf setting of kind of chips
* @lcdsel_grf_reg: grf register offset of lcdc select
@@ -155,6 +158,14 @@ enum dw_hdmi_rockchip_color_depth {
ROCKCHIP_HDMI_DEPTH_420_16
};
enum hdmi_frl_rate_per_lane {
FRL_12G_PER_LANE = 12,
FRL_10G_PER_LANE = 10,
FRL_8G_PER_LANE = 8,
FRL_6G_PER_LANE = 6,
FRL_3G_PER_LANE = 3,
};
struct rockchip_hdmi {
struct device *dev;
struct regmap *regmap;
@@ -206,8 +217,6 @@ struct rockchip_hdmi {
struct drm_property_blob *hdr_panel_blob_ptr;
struct drm_property_blob *next_hdr_data_ptr;
struct drm_dsc_picture_parameter_set pps_payload;
unsigned int colordepth;
unsigned int colorimetry;
unsigned int hdmi_quant_range;
@@ -455,7 +464,7 @@ enum COLUMN_INDEX_BPC {
MAX_COLUMN_INDEX
};
#define PPS_TABLE_LEN 1
#define PPS_TABLE_LEN 8
#define PPS_BPP_LEN 4
#define PPS_BPC_LEN 2
@@ -493,8 +502,9 @@ struct pps_data {
u32 slice_width;
u32 slice_height;
bool convert_rgb;
struct rc_parameters rc_parameters[PPS_BPP_LEN][PPS_BPC_LEN];
u8 bpc;
u8 bpp;
u8 raw_pps[128];
};
/*
@@ -503,129 +513,179 @@ struct pps_data {
*/
static struct pps_data pps_datas[PPS_TABLE_LEN] = {
{
/* 7680x4320/960X2160 rgb */
7680, 4320, 960, 96, 1,
/* 7680x4320/960X96 rgb 8bpc 12bpp */
7680, 4320, 960, 96, 1, 8, 192,
{
{
/* 8BPP/8BPC */
{ 0x200, 0x0358, 0x20, 0x0a63, 0x00d, 0x0f, 0x0144, 0x0099, 0x1800,
0x10f0, 0x03, 0x0c, 0x2000, 0x6, 0x0b, 0x0b, 0x3, 0x3,
{
{ 0x00, 0x04, 0x02, }, { 0x00, 0x04, 0x00, },
{ 0x01, 0x05, 0x00, }, { 0x01, 0x06, 0x3e, },
{ 0x03, 0x07, 0x3c, }, { 0x03, 0x07, 0x3a, },
{ 0x03, 0x07, 0x38, }, { 0x03, 0x08, 0x38, },
{ 0x03, 0x09, 0x38, }, { 0x04, 0x0a, 0x36, },
{ 0x05, 0x0a, 0x36, }, { 0x05, 0x0b, 0x36, },
{ 0x05, 0x0b, 0x34, }, { 0x08, 0x0c, 0x34, },
{ 0x0c, 0x0d, 0x34, },
},
},
/* 8BPP/10BPC */
{ 0x200, 0x0358, 0x20, 0x0a63, 0x00d, 0x0f, 0x0144, 0x0099, 0x1800,
0x10f0, 0x07, 0x10, 0x2000, 0x6, 0x0f, 0x0f, 0x3, 0x3,
{
{ 0x00, 0x08, 0x02, }, { 0x04, 0x08, 0x00, },
{ 0x05, 0x09, 0x00, }, { 0x05, 0x0a, 0x3e, },
{ 0x07, 0x0b, 0x3c, }, { 0x07, 0x0b, 0x3a, },
{ 0x07, 0x0b, 0x38, }, { 0x07, 0x0c, 0x38, },
{ 0x07, 0x0d, 0x38, }, { 0x08, 0x0e, 0x36, },
{ 0x09, 0x0e, 0x36, }, { 0x09, 0x0f, 0x36, },
{ 0x09, 0x0f, 0x34, }, { 0x0c, 0x10, 0x34, },
{ 0x10, 0x11, 0x34, },
},
},
},
{
/* 10BPP/8BPC */
{ 0x19a, 0x02e0, 0x19, 0x09b0, 0x012, 0x0f, 0x0144, 0x00bb, 0x1600,
0x10ec, 0x03, 0x0c, 0x2000, 0x6, 0x0b, 0x0b, 0x3, 0x3,
{
{ 0x00, 0x03, 0x02, }, { 0x00, 0x04, 0x00, },
{ 0x01, 0x05, 0x00, }, { 0x01, 0x06, 0x3e, },
{ 0x03, 0x07, 0x3c, }, { 0x03, 0x07, 0x3a, },
{ 0x03, 0x07, 0x38, }, { 0x03, 0x08, 0x38, },
{ 0x03, 0x09, 0x38, }, { 0x03, 0x09, 0x36, },
{ 0x05, 0x0a, 0x36, }, { 0x05, 0x0a, 0x36, },
{ 0x05, 0x0b, 0x34, }, { 0x07, 0x0b, 0x34, },
{ 0x0b, 0x0c, 0x34, },
},
},
/* 10BPP/10BPC */
{ 0x19a, 0x02e0, 0x19, 0x09b0, 0x012, 0x0f, 0x0144, 0x00bb, 0x1600,
0x10ec, 0x07, 0x10, 0x2000, 0x6, 0x0f, 0x0f, 0x3, 0x3,
{
{ 0x00, 0x07, 0x02, }, { 0x04, 0x08, 0x00, },
{ 0x05, 0x09, 0x00, }, { 0x05, 0x0a, 0x3e, },
{ 0x07, 0x0b, 0x3c, }, { 0x07, 0x0b, 0x3a, },
{ 0x07, 0x0b, 0x38, }, { 0x07, 0x0c, 0x38, },
{ 0x07, 0x0d, 0x38, }, { 0x07, 0x0d, 0x36, },
{ 0x09, 0x0e, 0x36, }, { 0x09, 0x0e, 0x36, },
{ 0x09, 0x0f, 0x34, }, { 0x0c, 0x0f, 0x34, },
{ 0x0f, 0x10, 0x34, },
},
},
},
{
/* 12BPP/8BPC */
{ 0x155, 0x0390, 0x0a, 0x05c9, 0x0a0, 0x0f, 0x0144, 0x01aa, 0x0800,
0x10f4, 0x03, 0x0c, 0x2000, 0x6, 0x0b, 0x0b, 0x3, 0x3,
{
{ 0x00, 0x02, 0x02, }, { 0x00, 0x03, 0x00, },
{ 0x01, 0x04, 0x00, }, { 0x01, 0x05, 0x3e, },
{ 0x03, 0x06, 0x3c, }, { 0x03, 0x06, 0x3a, },
{ 0x03, 0x07, 0x38, }, { 0x03, 0x08, 0x38, },
{ 0x03, 0x08, 0x38, }, { 0x03, 0x09, 0x36, },
{ 0x05, 0x09, 0x36, }, { 0x05, 0x09, 0x36, },
{ 0x05, 0x09, 0x34, }, { 0x07, 0x0a, 0x34, },
{ 0x0a, 0x0b, 0x34, },
},
},
/* 12BPP/10BPC */
{ 0x155, 0x0390, 0x0a, 0x05c9, 0x0a0, 0x0f, 0x0144, 0x01aa, 0x0800,
0x10f4, 0x07, 0x10, 0x2000, 0x6, 0x0f, 0x0f, 0x3, 0x3,
{
{ 0x00, 0x04, 0x02, }, { 0x02, 0x06, 0x00, },
{ 0x04, 0x08, 0x00, }, { 0x04, 0x09, 0x3e, },
{ 0x06, 0x0a, 0x3c, }, { 0x06, 0x0a, 0x3a, },
{ 0x07, 0x0b, 0x38, }, { 0x07, 0x0c, 0x38, },
{ 0x07, 0x0c, 0x38, }, { 0x07, 0x0d, 0x36, },
{ 0x09, 0x0d, 0x36, }, { 0x09, 0x0d, 0x36, },
{ 0x09, 0x0d, 0x34, }, { 0x0b, 0x0e, 0x34, },
{ 0x0e, 0x0f, 0x34, },
},
},
},
{
/* 23BPP/8BPC */
{ 0x0b2, 0x0189, 0x0a, 0x06fc, 0x0a0, 0x09, 0x00c3, 0x01aa, 0x0800,
0x10f2, 0x03, 0x0c, 0x2000, 0x6, 0x0b, 0x0b, 0x3, 0x3,
{
{ 0x00, 0x00, 0x0a, }, { 0x00, 0x00, 0x08, },
{ 0x00, 0x00, 0x06, }, { 0x00, 0x01, 0x04, },
{ 0x00, 0x01, 0x02, }, { 0x00, 0x01, 0x00, },
{ 0x00, 0x01, 0x3e, }, { 0x00, 0x01, 0x3c, },
{ 0x00, 0x01, 0x3a, }, { 0x00, 0x01, 0x38, },
{ 0x01, 0x02, 0x36, }, { 0x01, 0x02, 0x36, },
{ 0x01, 0x02, 0x34, }, { 0x01, 0x02, 0x34, },
{ 0x03, 0x04, 0x34, },
},
},
/* 23BPP/10BPC */
{ 0x0b2, 0x01dc, 0x0a, 0x05c8, 0x0a0, 0x0f, 0x0144, 0x01aa, 0x0800,
0x10f2, 0x07, 0x10, 0x2000, 0x6, 0x0f, 0x0f, 0x3, 0x3,
{
{ 0x00, 0x01, 0x0a, }, { 0x00, 0x01, 0x08, },
{ 0x01, 0x02, 0x06, }, { 0x02, 0x03, 0x04, },
{ 0x02, 0x03, 0x02, }, { 0x02, 0x03, 0x00, },
{ 0x03, 0x04, 0x3e, }, { 0x03, 0x04, 0x3c, },
{ 0x03, 0x03, 0x3a, }, { 0x03, 0x04, 0x38, },
{ 0x05, 0x06, 0x36, }, { 0x05, 0x06, 0x36, },
{ 0x05, 0x06, 0x34, }, { 0x05, 0x06, 0x34, },
{ 0x07, 0x08, 0x34, },
},
},
},
0x12, 0x00, 0x00, 0x8d, 0x30, 0xc0, 0x10, 0xe0,
0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x05, 0xa0,
0x01, 0x55, 0x03, 0x90, 0x00, 0x0a, 0x05, 0xc9,
0x00, 0xa0, 0x00, 0x0f, 0x01, 0x44, 0x01, 0xaa,
0x08, 0x00, 0x10, 0xf4, 0x03, 0x0c, 0x20, 0x00,
0x06, 0x0b, 0x0b, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
0x7d, 0x7e, 0x00, 0x82, 0x00, 0xc0, 0x09, 0x00,
0x09, 0x7e, 0x19, 0xbc, 0x19, 0xba, 0x19, 0xf8,
0x1a, 0x38, 0x1a, 0x38, 0x1a, 0x76, 0x2a, 0x76,
0x2a, 0x76, 0x2a, 0x74, 0x3a, 0xb4, 0x52, 0xf4,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
},
{
/* 7680x4320/960X96 rgb 8bpc 11bpp */
7680, 4320, 960, 96, 1, 8, 176,
{
0x12, 0x00, 0x00, 0x8d, 0x30, 0xb0, 0x10, 0xe0,
0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x05, 0x28,
0x01, 0x74, 0x03, 0x40, 0x00, 0x0f, 0x06, 0xe0,
0x00, 0x2d, 0x00, 0x0f, 0x01, 0x44, 0x01, 0x33,
0x0f, 0x00, 0x10, 0xf4, 0x03, 0x0c, 0x20, 0x00,
0x06, 0x0b, 0x0b, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
0x7d, 0x7e, 0x00, 0x82, 0x01, 0x00, 0x09, 0x40,
0x09, 0xbe, 0x19, 0xfc, 0x19, 0xfa, 0x19, 0xf8,
0x1a, 0x38, 0x1a, 0x38, 0x1a, 0x76, 0x2a, 0x76,
0x2a, 0x76, 0x2a, 0xb4, 0x3a, 0xb4, 0x52, 0xf4,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
},
{
/* 7680x4320/960X96 rgb 8bpc 10bpp */
7680, 4320, 960, 96, 1, 8, 160,
{
0x12, 0x00, 0x00, 0x8d, 0x30, 0xa0, 0x10, 0xe0,
0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x04, 0xb0,
0x01, 0x9a, 0x02, 0xe0, 0x00, 0x19, 0x09, 0xb0,
0x00, 0x12, 0x00, 0x0f, 0x01, 0x44, 0x00, 0xbb,
0x16, 0x00, 0x10, 0xec, 0x03, 0x0c, 0x20, 0x00,
0x06, 0x0b, 0x0b, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
0x7d, 0x7e, 0x00, 0xc2, 0x01, 0x00, 0x09, 0x40,
0x09, 0xbe, 0x19, 0xfc, 0x19, 0xfa, 0x19, 0xf8,
0x1a, 0x38, 0x1a, 0x78, 0x1a, 0x76, 0x2a, 0xb6,
0x2a, 0xb6, 0x2a, 0xf4, 0x3a, 0xf4, 0x5b, 0x34,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
},
{
/* 7680x4320/960X96 rgb 8bpc 9bpp */
7680, 4320, 960, 96, 1, 8, 144,
{
0x12, 0x00, 0x00, 0x8d, 0x30, 0x90, 0x10, 0xe0,
0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x04, 0x38,
0x01, 0xc7, 0x03, 0x16, 0x00, 0x1c, 0x08, 0xc7,
0x00, 0x10, 0x00, 0x0f, 0x01, 0x44, 0x00, 0xaa,
0x17, 0x00, 0x10, 0xf1, 0x03, 0x0c, 0x20, 0x00,
0x06, 0x0b, 0x0b, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
0x7d, 0x7e, 0x00, 0xc2, 0x01, 0x00, 0x09, 0x40,
0x09, 0xbe, 0x19, 0xfc, 0x19, 0xfa, 0x19, 0xf8,
0x1a, 0x38, 0x1a, 0x78, 0x1a, 0x76, 0x2a, 0xb6,
0x2a, 0xb6, 0x2a, 0xf4, 0x3a, 0xf4, 0x63, 0x74,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
},
{
/* 7680x4320/960X96 rgb 10bpc 12bpp */
7680, 4320, 960, 96, 1, 10, 192,
{
0x12, 0x00, 0x00, 0xad, 0x30, 0xc0, 0x10, 0xe0,
0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x05, 0xa0,
0x01, 0x55, 0x03, 0x90, 0x00, 0x0a, 0x05, 0xc9,
0x00, 0xa0, 0x00, 0x0f, 0x01, 0x44, 0x01, 0xaa,
0x08, 0x00, 0x10, 0xf4, 0x07, 0x10, 0x20, 0x00,
0x06, 0x0f, 0x0f, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
0x7d, 0x7e, 0x01, 0x02, 0x11, 0x80, 0x22, 0x00,
0x22, 0x7e, 0x32, 0xbc, 0x32, 0xba, 0x3a, 0xf8,
0x3b, 0x38, 0x3b, 0x38, 0x3b, 0x76, 0x4b, 0x76,
0x4b, 0x76, 0x4b, 0x74, 0x5b, 0xb4, 0x73, 0xf4,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
},
{
/* 7680x4320/960X96 rgb 10bpc 11bpp */
7680, 4320, 960, 96, 1, 10, 176,
{
0x12, 0x00, 0x00, 0xad, 0x30, 0xb0, 0x10, 0xe0,
0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x05, 0x28,
0x01, 0x74, 0x03, 0x40, 0x00, 0x0f, 0x06, 0xe0,
0x00, 0x2d, 0x00, 0x0f, 0x01, 0x44, 0x01, 0x33,
0x0f, 0x00, 0x10, 0xf4, 0x07, 0x10, 0x20, 0x00,
0x06, 0x0f, 0x0f, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
0x7d, 0x7e, 0x01, 0x42, 0x19, 0xc0, 0x2a, 0x40,
0x2a, 0xbe, 0x3a, 0xfc, 0x3a, 0xfa, 0x3a, 0xf8,
0x3b, 0x38, 0x3b, 0x38, 0x3b, 0x76, 0x4b, 0x76,
0x4b, 0x76, 0x4b, 0xb4, 0x5b, 0xb4, 0x73, 0xf4,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
},
{
/* 7680x4320/960X96 rgb 10bpc 10bpp */
7680, 4320, 960, 96, 1, 10, 160,
{
0x12, 0x00, 0x00, 0xad, 0x30, 0xa0, 0x10, 0xe0,
0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x04, 0xb0,
0x01, 0x9a, 0x02, 0xe0, 0x00, 0x19, 0x09, 0xb0,
0x00, 0x12, 0x00, 0x0f, 0x01, 0x44, 0x00, 0xbb,
0x16, 0x00, 0x10, 0xec, 0x07, 0x10, 0x20, 0x00,
0x06, 0x0f, 0x0f, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
0x7d, 0x7e, 0x01, 0xc2, 0x22, 0x00, 0x2a, 0x40,
0x2a, 0xbe, 0x3a, 0xfc, 0x3a, 0xfa, 0x3a, 0xf8,
0x3b, 0x38, 0x3b, 0x78, 0x3b, 0x76, 0x4b, 0xb6,
0x4b, 0xb6, 0x4b, 0xf4, 0x63, 0xf4, 0x7c, 0x34,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
},
{
/* 7680x4320/960X96 rgb 10bpc 9bpp */
7680, 4320, 960, 96, 1, 10, 144,
{
0x12, 0x00, 0x00, 0xad, 0x30, 0x90, 0x10, 0xe0,
0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x04, 0x38,
0x01, 0xc7, 0x03, 0x16, 0x00, 0x1c, 0x08, 0xc7,
0x00, 0x10, 0x00, 0x0f, 0x01, 0x44, 0x00, 0xaa,
0x17, 0x00, 0x10, 0xf1, 0x07, 0x10, 0x20, 0x00,
0x06, 0x0f, 0x0f, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
0x7d, 0x7e, 0x01, 0xc2, 0x22, 0x00, 0x2a, 0x40,
0x2a, 0xbe, 0x3a, 0xfc, 0x3a, 0xfa, 0x3a, 0xf8,
0x3b, 0x38, 0x3b, 0x78, 0x3b, 0x76, 0x4b, 0xb6,
0x4b, 0xb6, 0x4b, 0xf4, 0x63, 0xf4, 0x84, 0x74,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
},
};
@@ -681,7 +741,7 @@ static bool hdmi_bus_fmt_is_yuv420(unsigned int bus_format)
return true;
default:
return false;
return false;
}
}
@@ -742,23 +802,6 @@ hdmi_get_tmdsclock(struct rockchip_hdmi *hdmi, unsigned long pixelclock)
return tmdsclock;
}
static unsigned long hdmi_get_frl_bit_rate(struct rockchip_hdmi *hdmi,
unsigned long pixel_clk)
{
unsigned long frl_rate;
unsigned int depth =
hdmi_bus_fmt_color_depth(hdmi->output_bus_format);
if (hdmi_bus_fmt_is_yuv420(hdmi->output_bus_format))
depth = depth / 2;
else if (hdmi_bus_fmt_is_yuv422(hdmi->output_bus_format))
depth = 8;
frl_rate = DIV_ROUND_UP(pixel_clk * 1000 * 3 * depth * 18, 16);
return frl_rate;
}
static void hdmi_select_link_config(struct rockchip_hdmi *hdmi,
struct drm_crtc_state *crtc_state)
{
@@ -766,7 +809,7 @@ static void hdmi_select_link_config(struct rockchip_hdmi *hdmi,
int max_lanes, max_rate_per_lane;
int max_dsc_lanes, max_dsc_rate_per_lane;
int val;
unsigned long frl_rate, max_frl_rate;
unsigned long max_frl_rate;
bool is_hdmi0;
if (!hdmi->id)
@@ -776,13 +819,13 @@ static void hdmi_select_link_config(struct rockchip_hdmi *hdmi,
max_lanes = hdmi->max_lanes;
max_rate_per_lane = hdmi->max_frl_rate_per_lane;
max_frl_rate = max_lanes * max_rate_per_lane * 10^9;
max_frl_rate = max_lanes * max_rate_per_lane * 1000000;
hdmi->link_cfg.dsc_mode = false;
hdmi->link_cfg.frl_lanes = max_lanes;
hdmi->link_cfg.rate_per_rate = max_rate_per_lane;
hdmi->link_cfg.rate_per_lane = max_rate_per_lane;
if (!max_frl_rate || mode->clock <= 594000) {
if (!max_frl_rate || mode->clock < HDMI20_MAX_RATE) {
dev_info(hdmi->dev, "use tmds mode\n");
hdmi->link_cfg.frl_mode = false;
val = HIWORD_UPDATE(0, RK3588_HDMI21_MASK);
@@ -790,6 +833,12 @@ static void hdmi_select_link_config(struct rockchip_hdmi *hdmi,
regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON4, val);
else
regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON7, val);
val = HIWORD_UPDATE(0, RK3588_COMPRESS_MODE_MASK | RK3588_COLOR_FORMAT_MASK);
if (is_hdmi0)
regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON3, val);
else
regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON6, val);
return;
}
@@ -807,12 +856,10 @@ static void hdmi_select_link_config(struct rockchip_hdmi *hdmi,
max_dsc_rate_per_lane =
hdmi->dsc_cap.max_frl_rate_per_lane;
frl_rate = hdmi_get_frl_bit_rate(hdmi, mode->clock);
if (frl_rate > max_frl_rate) {
if (mode->clock >= HDMI_8K60_RATE) {
hdmi->link_cfg.dsc_mode = true;
hdmi->link_cfg.frl_lanes = max_dsc_lanes;
hdmi->link_cfg.rate_per_rate = max_dsc_rate_per_lane;
hdmi->link_cfg.rate_per_lane = max_dsc_rate_per_lane;
val = HIWORD_UPDATE(RK3588_COMPRESS_MODE_MASK | RK3588_COMPRESSED_DATA,
RK3588_COMPRESS_MODE_MASK | RK3588_COLOR_FORMAT_MASK);
if (is_hdmi0)
@@ -822,7 +869,7 @@ static void hdmi_select_link_config(struct rockchip_hdmi *hdmi,
} else {
hdmi->link_cfg.dsc_mode = false;
hdmi->link_cfg.frl_lanes = max_lanes;
hdmi->link_cfg.rate_per_rate = max_rate_per_lane;
hdmi->link_cfg.rate_per_lane = max_rate_per_lane;
val = HIWORD_UPDATE(0, RK3588_COMPRESS_MODE_MASK | RK3588_COLOR_FORMAT_MASK);
if (is_hdmi0)
regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON3, val);
@@ -980,19 +1027,9 @@ hdmi_dsc_get_bpp(struct rockchip_hdmi *hdmi, int src_fractional_bpp,
* for each bpp we check if no of bytes can be supported by HDMI sink
*/
/* Assuming: bpc as 8*/
if (hdmi_bus_fmt_is_yuv420(hdmi->output_bus_format)) {
min_dsc_bpp = 6;
max_dsc_bpp = 3 * 4; /* 3*bpc/2 */
} else if (hdmi_bus_fmt_is_yuv444(hdmi->output_bus_format) ||
hdmi_bus_fmt_is_rgb(hdmi->output_bus_format)) {
min_dsc_bpp = 8;
max_dsc_bpp = 3 * 8; /* 3*bpc */
} else {
/* Assuming 4:2:2 encoding */
min_dsc_bpp = 7;
max_dsc_bpp = 2 * 8; /* 2*bpc */
}
/* only 9\10\12 bpp was tested */
min_dsc_bpp = 9;
max_dsc_bpp = 12;
/*
* Taking into account if all dsc_all_bpp supported by HDMI2.1 sink
@@ -1026,7 +1063,7 @@ hdmi_dsc_get_bpp(struct rockchip_hdmi *hdmi, int src_fractional_bpp,
if (!src_fractional_bpp)
src_fractional_bpp = 1;
bpp_decrement_x16 = DIV_ROUND_UP(16, src_fractional_bpp);
bpp_target_x16 = (bpp_target * 16) - bpp_decrement_x16;
bpp_target_x16 = bpp_target * 16;
while (bpp_target_x16 > (min_dsc_bpp * 16)) {
int bpp;
@@ -1058,57 +1095,20 @@ dw_hdmi_dsc_bpp(struct rockchip_hdmi *hdmi,
hdmi_max_chunk_bytes);
}
static int get_row_index_for_rc_params(u16 compressed_bpp)
{
int bpp = compressed_bpp / 16;
switch (bpp) {
case 8:
return ROW_INDEX_8BPP;
case 10:
return ROW_INDEX_10BPP;
case 12:
return ROW_INDEX_12BPP;
case 23:
return ROW_INDEX_12BPP;
default:
return -EINVAL;
}
}
static int get_column_index_for_rc_params(u8 bits_per_component)
{
switch (bits_per_component) {
case 8:
return COLUMN_INDEX_8BPC;
case 10:
return COLUMN_INDEX_10BPC;
default:
return -EINVAL;
}
}
static int dw_hdmi_qp_set_vdsc_cfg(struct rockchip_hdmi *hdmi,
struct drm_dsc_config *vdsc_cfg,
static int dw_hdmi_qp_set_link_cfg(struct rockchip_hdmi *hdmi,
u16 pic_width, u16 pic_height,
u16 slice_width, u16 slice_height,
u16 bits_per_pixel, u8 bits_per_component)
{
int i, row_index, column_index;
struct rc_parameters *rc_params;
vdsc_cfg->pic_width = pic_width;
vdsc_cfg->pic_height = pic_height;
vdsc_cfg->slice_width = slice_width;
vdsc_cfg->slice_height = slice_height;
vdsc_cfg->bits_per_pixel = bits_per_pixel;
vdsc_cfg->bits_per_component = bits_per_component;
int i;
for (i = 0; i < PPS_TABLE_LEN; i++)
if (vdsc_cfg->pic_width == pps_datas[i].pic_width &&
vdsc_cfg->pic_height == pps_datas[i].pic_height &&
vdsc_cfg->slice_width == pps_datas[i].slice_width &&
vdsc_cfg->slice_height == pps_datas[i].slice_height &&
if (pic_width == pps_datas[i].pic_width &&
pic_height == pps_datas[i].pic_height &&
slice_width == pps_datas[i].slice_width &&
slice_height == pps_datas[i].slice_height &&
bits_per_component == pps_datas[i].bpc &&
bits_per_pixel == pps_datas[i].bpp &&
hdmi_bus_fmt_is_rgb(hdmi->output_bus_format) == pps_datas[i].convert_rgb)
break;
@@ -1117,97 +1117,9 @@ static int dw_hdmi_qp_set_vdsc_cfg(struct rockchip_hdmi *hdmi,
return -EINVAL;
}
row_index = get_row_index_for_rc_params(vdsc_cfg->bits_per_pixel);
if (row_index < 0)
return row_index;
column_index =
get_column_index_for_rc_params(vdsc_cfg->bits_per_component);
if (column_index < 0)
return column_index;
rc_params = &pps_datas[i].rc_parameters[row_index][column_index];
vdsc_cfg->line_buf_depth = 13;
vdsc_cfg->convert_rgb = hdmi_bus_fmt_is_rgb(hdmi->output_bus_format);
vdsc_cfg->block_pred_enable = true;
/* does not support native YCbCr */
vdsc_cfg->native_422 = false;
vdsc_cfg->native_420 = false;
vdsc_cfg->simple_422 = false;
/* does not support VBR */
vdsc_cfg->vbr_enable = false;
/* not supoort native yuv422/yuv420 */
vdsc_cfg->second_line_bpg_offset = 0;
vdsc_cfg->nsl_bpg_offset = 0;
vdsc_cfg->second_line_offset_adj = 0;
vdsc_cfg->slice_chunk_size = DIV_ROUND_UP(vdsc_cfg->slice_width *
vdsc_cfg->bits_per_pixel,
(8 * 16));
for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++) {
/*
* six 0s are appended to the lsb of each threshold value
* internally in h/w.
* Only 8 bits are allowed for programming RcBufThreshold
*/
vdsc_cfg->rc_buf_thresh[i] = rc_buf_thresh[i];
}
/*
* For 6bpp, RC Buffer threshold 12 and 13 need a different value
* as per C Model
*/
if (vdsc_cfg->bits_per_pixel == 6) {
vdsc_cfg->rc_buf_thresh[12] = 0x7C;
vdsc_cfg->rc_buf_thresh[13] = 0x7D;
}
vdsc_cfg->initial_xmit_delay = rc_params->initial_xmit_delay;
vdsc_cfg->initial_dec_delay = rc_params->initial_dec_delay;
vdsc_cfg->initial_scale_value = rc_params->initial_scale_value;
vdsc_cfg->scale_increment_interval = rc_params->scale_increment_interval;
vdsc_cfg->scale_decrement_interval = rc_params->scale_decrement_interval;
vdsc_cfg->first_line_bpg_offset = rc_params->first_line_bpg_offset;
vdsc_cfg->nfl_bpg_offset = rc_params->nfl_bpg_offset;
vdsc_cfg->slice_bpg_offset = rc_params->slice_bpg_offset;
vdsc_cfg->initial_offset = rc_params->initial_offset;
vdsc_cfg->final_offset = rc_params->final_offset;
vdsc_cfg->flatness_min_qp = rc_params->flatness_min_qp;
vdsc_cfg->flatness_max_qp = rc_params->flatness_max_qp;
vdsc_cfg->rc_model_size = rc_params->rc_model_size;
vdsc_cfg->rc_edge_factor = rc_params->rc_edge_factor;
vdsc_cfg->rc_quant_incr_limit0 = rc_params->rc_quant_incr_limit0;
vdsc_cfg->rc_quant_incr_limit1 = rc_params->rc_quant_incr_limit1;
vdsc_cfg->rc_tgt_offset_high = rc_params->rc_tgt_offset_hi;
vdsc_cfg->rc_tgt_offset_low = rc_params->rc_tgt_offset_lo;
for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
vdsc_cfg->rc_range_params[i].range_min_qp =
rc_params->rc_range_params[i].range_min_qp;
vdsc_cfg->rc_range_params[i].range_max_qp =
rc_params->rc_range_params[i].range_max_qp;
vdsc_cfg->rc_range_params[i].range_bpg_offset =
rc_params->rc_range_params[i].range_bpg_offset;
}
/*
* BitsPerComponent value determines mux_word_size:
* When BitsPerComponent is 12bpc, muxWordSize will be equal to 64 bits
* When BitsPerComponent is 8 or 10bpc, muxWordSize will be equal to
* 48 bits
*/
if (vdsc_cfg->bits_per_component == 8 ||
vdsc_cfg->bits_per_component == 10)
vdsc_cfg->mux_word_size = DSC_MUX_WORD_SIZE_8_10_BPC;
else if (vdsc_cfg->bits_per_component == 12)
vdsc_cfg->mux_word_size = DSC_MUX_WORD_SIZE_12_BPC;
vdsc_cfg->dsc_version_minor = 2;
vdsc_cfg->dsc_version_major = 1;
memcpy(hdmi->link_cfg.pps_payload, pps_datas[i].raw_pps, 128);
hdmi->link_cfg.hcactive = DIV_ROUND_UP(slice_width * (bits_per_pixel / 16), 8) *
(pic_width / slice_width);
return 0;
}
@@ -1220,8 +1132,8 @@ static void dw_hdmi_qp_dsc_configure(struct rockchip_hdmi *hdmi,
int slice_height;
int slice_width;
int bits_per_pixel;
int slice_count;
bool hdmi_is_dsc_1_2;
struct drm_dsc_config vdsc_cfg;
unsigned int depth = hdmi_bus_fmt_color_depth(hdmi->output_bus_format);
if (!crtc_state)
@@ -1236,20 +1148,17 @@ static void dw_hdmi_qp_dsc_configure(struct rockchip_hdmi *hdmi,
if (!slice_height)
return;
vdsc_cfg.slice_count = hdmi_dsc_slices(hdmi, crtc_state);
if (!vdsc_cfg.slice_count)
slice_count = hdmi_dsc_slices(hdmi, crtc_state);
if (!slice_count)
return;
slice_width = DIV_ROUND_UP(crtc_state->mode.hdisplay,
vdsc_cfg.slice_count);
slice_width = DIV_ROUND_UP(crtc_state->mode.hdisplay, slice_count);
bits_per_pixel = dw_hdmi_dsc_bpp(hdmi, vdsc_cfg.slice_count,
slice_width);
bits_per_pixel = dw_hdmi_dsc_bpp(hdmi, slice_count, slice_width);
if (!bits_per_pixel)
return;
ret = dw_hdmi_qp_set_vdsc_cfg(hdmi, &vdsc_cfg,
crtc_state->mode.hdisplay,
ret = dw_hdmi_qp_set_link_cfg(hdmi, crtc_state->mode.hdisplay,
crtc_state->mode.vdisplay, slice_width,
slice_height, bits_per_pixel, depth);
@@ -1257,22 +1166,17 @@ static void dw_hdmi_qp_dsc_configure(struct rockchip_hdmi *hdmi,
dev_err(hdmi->dev, "set vdsc cfg failed\n");
return;
}
drm_dsc_pps_payload_pack(&hdmi->pps_payload, &vdsc_cfg);
hdmi->link_cfg.hcactive = vdsc_cfg.slice_chunk_size;
hdmi->link_cfg.pps_payload = (u8 *)&hdmi->pps_payload;
dev_info(hdmi->dev, "dsc_enable\n");
s->dsc_enable = 1;
s->dsc_sink_cap.version_major = vdsc_cfg.dsc_version_major;
s->dsc_sink_cap.version_minor = vdsc_cfg.dsc_version_minor;
s->dsc_sink_cap.slice_width = vdsc_cfg.slice_width;
s->dsc_sink_cap.slice_height = vdsc_cfg.slice_height;
s->dsc_sink_cap.target_bits_per_pixel_x16 = vdsc_cfg.bits_per_pixel << 4;
s->dsc_sink_cap.block_pred = vdsc_cfg.block_pred_enable;
s->dsc_sink_cap.version_major = 1;
s->dsc_sink_cap.version_minor = 2;
s->dsc_sink_cap.slice_width = slice_width;
s->dsc_sink_cap.slice_height = slice_height;
s->dsc_sink_cap.target_bits_per_pixel_x16 = bits_per_pixel;
s->dsc_sink_cap.block_pred = 1;
s->dsc_sink_cap.native_420 = 0;
memcpy(&s->pps, &hdmi->pps_payload, sizeof(struct drm_dsc_picture_parameter_set));
memcpy(&s->pps, hdmi->link_cfg.pps_payload, 128);
}
/////////////////////////////////////////////////////////////////////////////////////////
@@ -1741,7 +1645,8 @@ dw_hdmi_rockchip_select_output(struct drm_connector_state *conn_state,
else if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
*color_format = DRM_HDMI_OUTPUT_YCBCR422;
else if (conn_state->connector->ycbcr_420_allowed &&
drm_mode_is_420(info, mode) && pixclock >= 594000)
drm_mode_is_420(info, mode) &&
(pixclock >= 594000 && !hdmi->is_hdmi_qp))
*color_format = DRM_HDMI_OUTPUT_YCBCR420;
break;
case DRM_HDMI_OUTPUT_YCBCR_LQ:
@@ -1843,7 +1748,7 @@ dw_hdmi_rockchip_select_output(struct drm_connector_state *conn_state,
max_tmds_clock = min(max_tmds_clock, hdmi->max_tmdsclk);
if (tmdsclock > max_tmds_clock) {
if ((tmdsclock > max_tmds_clock) && !hdmi->is_hdmi_qp) {
if (max_tmds_clock >= 594000) {
color_depth = 8;
} else if (max_tmds_clock > 340000) {
@@ -1856,6 +1761,9 @@ dw_hdmi_rockchip_select_output(struct drm_connector_state *conn_state,
}
}
if (mode->clock >= HDMI_8K60_RATE && !hdmi->dsc_cap.v_1p2)
*color_format = DRM_HDMI_OUTPUT_YCBCR420;
if (*color_format == DRM_HDMI_OUTPUT_YCBCR420) {
*output_mode = ROCKCHIP_OUT_MODE_YUV420;
if (color_depth > 8)
@@ -1939,7 +1847,6 @@ dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
&output_mode, &bus_format, &bus_width,
&hdmi->enc_out_encoding, &s->eotf);
if (hdmi->is_hdmi_qp) {
color_depth = hdmi_bus_fmt_color_depth(bus_format);
rk3588_set_color_format(hdmi, bus_format, color_depth);
@@ -1947,8 +1854,13 @@ dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
if (hdmi->link_cfg.frl_mode) {
gpiod_set_value(hdmi->enable_gpio, 0);
/* in the current version, support max 40G frl */
if (hdmi->link_cfg.rate_per_lane >= 10) {
hdmi->link_cfg.frl_lanes = 4;
hdmi->link_cfg.rate_per_lane = 10;
}
bus_width = hdmi->link_cfg.frl_lanes *
hdmi->link_cfg.rate_per_rate * 1000000;
hdmi->link_cfg.rate_per_lane * 1000000;
/* 10 bit color depth and frl mode */
if (color_depth == 10)
bus_width |=
@@ -1959,6 +1871,8 @@ dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
gpiod_set_value(hdmi->enable_gpio, 1);
bus_width = hdmi_get_tmdsclock(hdmi,
crtc_state->mode.clock);
if (hdmi_bus_fmt_is_yuv420(hdmi->output_bus_format))
bus_width /= 2;
/* change to bit rate */
bus_width *= 10;
@@ -1994,6 +1908,8 @@ dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
else
s->color_space = V4L2_COLORSPACE_SMPTE170M;
s->dsc_enable = 0;
if (hdmi->link_cfg.dsc_mode)
dw_hdmi_qp_dsc_configure(hdmi, s, crtc_state);

View File

@@ -126,9 +126,9 @@ struct dw_hdmi_link_config {
bool dsc_mode;
bool frl_mode;
int frl_lanes;
int rate_per_rate;
int rate_per_lane;
int hcactive;
u8 *pps_payload;
u8 pps_payload[128];
};
struct dw_hdmi_phy_ops {