From b53d1f94678b30af5e098daafb828b0fb41de247 Mon Sep 17 00:00:00 2001 From: Algea Cao Date: Sun, 21 Nov 2021 16:16:04 +0800 Subject: [PATCH] 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 Change-Id: Ibc2d48e2b25bc94e4be7ffa9703c400436bdee36 --- drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 232 +++++--- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 576 ++++++++----------- include/drm/bridge/dw_hdmi.h | 4 +- 3 files changed, 387 insertions(+), 425 deletions(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c index 28c0d290cff9..78660d71eb20 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c @@ -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); diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index e788cf8fb912..af2a8e71e4ab 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -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); diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 33fc3c89a7f2..51203f874e8e 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -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 {