You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openwrt/target/linux/layerscape/patches-5.4/805-display-0028-drm-imx-hd...

188 lines
6.2 KiB
Diff

From 1a8c7e6db6898ea62820bdd4fc9ef70b04ea528a Mon Sep 17 00:00:00 2001
From: Laurentiu Palcu <laurentiu.palcu@nxp.com>
Date: Thu, 7 Nov 2019 15:23:41 +0200
Subject: [PATCH] drm/imx/hdp: handle the various deep-color settings
iMX8MQ has the ability to handle color depths up to 12bpc. This patch adds
support for higher color depths for various modes.
Signed-off-by: Laurentiu Palcu <laurentiu.palcu@nxp.com>
---
drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 132 ++++++++++++++----------
1 file changed, 75 insertions(+), 57 deletions(-)
--- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
@@ -67,58 +67,20 @@ static void hdmi_lanes_config(struct cdn
cdns_mhdp_reg_write(mhdp, LANES_CONFIG, 0x00400000 | mhdp->lane_mapping);
}
-#define RGB_ALLOWED_COLORIMETRY (BIT(HDMI_EXTENDED_COLORIMETRY_BT2020) |\
- BIT(HDMI_EXTENDED_COLORIMETRY_OPRGB))
-#define YCC_ALLOWED_COLORIMETRY (BIT(HDMI_EXTENDED_COLORIMETRY_BT2020) |\
- BIT(HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM) |\
- BIT(HDMI_EXTENDED_COLORIMETRY_OPYCC_601) |\
- BIT(HDMI_EXTENDED_COLORIMETRY_S_YCC_601) |\
- BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_709) |\
- BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_601))
static int hdmi_avi_info_set(struct cdns_mhdp_device *mhdp,
- struct drm_display_mode *mode)
+ struct drm_display_mode *mode)
{
struct hdmi_avi_infoframe frame;
-#if 0
- struct drm_display_info *di = &mhdp->connector.base.display_info;
- enum hdmi_extended_colorimetry ext_col;
- u32 sink_col, allowed_col;
-#endif
int format = mhdp->video_info.color_fmt;
+ struct drm_connector_state *conn_state = mhdp->connector.base.state;
+ struct drm_display_mode *adj_mode;
+ enum hdmi_quantization_range qr;
u8 buf[32];
int ret;
/* Initialise info frame from DRM mode */
- drm_hdmi_avi_infoframe_from_display_mode(&frame, &mhdp->connector.base, mode);
-
-#if 0 //TODO to DCSS
- /* Set up colorimetry */
- allowed_col = format == PXL_RGB ? RGB_ALLOWED_COLORIMETRY :
- YCC_ALLOWED_COLORIMETRY;
-
- sink_col = di->hdmi.colorimetry & allowed_col;
-
- if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_BT2020))
- ext_col = HDMI_EXTENDED_COLORIMETRY_BT2020;
- else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM))
- ext_col = HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM;
- else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_OPRGB))
- ext_col = HDMI_EXTENDED_COLORIMETRY_OPRGB;
- else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_709))
- ext_col = HDMI_EXTENDED_COLORIMETRY_XV_YCC_709;
- else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_OPYCC_601))
- ext_col = HDMI_EXTENDED_COLORIMETRY_OPYCC_601;
- else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_S_YCC_601))
- ext_col = HDMI_EXTENDED_COLORIMETRY_S_YCC_601;
- else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_601))
- ext_col = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
- else
- ext_col = 0;
-
- frame.colorimetry = sink_col ? HDMI_COLORIMETRY_EXTENDED :
- HDMI_COLORIMETRY_NONE;
- frame.extended_colorimetry = ext_col;
-#endif
+ drm_hdmi_avi_infoframe_from_display_mode(&frame, &mhdp->connector.base,
+ mode);
switch (format) {
case YCBCR_4_4_4:
@@ -135,6 +97,19 @@ static int hdmi_avi_info_set(struct cdns
break;
}
+ drm_hdmi_avi_infoframe_colorspace(&frame, conn_state);
+
+ adj_mode = &mhdp->bridge.base.encoder->crtc->state->adjusted_mode;
+
+ qr = drm_default_rgb_quant_range(adj_mode);
+
+ drm_hdmi_avi_infoframe_quant_range(&frame, &mhdp->connector.base,
+ adj_mode, qr);
+
+ ret = hdmi_avi_infoframe_check(&frame);
+ if (WARN_ON(ret))
+ return false;
+
ret = hdmi_avi_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
if (ret < 0) {
DRM_ERROR("failed to pack AVI infoframe: %d\n", ret);
@@ -404,19 +379,6 @@ static void cdns_hdmi_bridge_mode_set(st
struct drm_display_info *display_info = &mhdp->connector.base.display_info;
struct video_info *video = &mhdp->video_info;
- switch (display_info->bpc) {
- case 10:
- video->color_depth = 10;
- break;
- case 6:
- video->color_depth = 6;
- break;
- default:
- video->color_depth = 8;
- break;
- }
-
- video->color_fmt = PXL_RGB;
video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
@@ -428,10 +390,66 @@ static void cdns_hdmi_bridge_mode_set(st
mutex_unlock(&mhdp->lock);
}
+bool cdns_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct cdns_mhdp_device *mhdp = bridge->driver_private;
+ struct drm_display_info *di = &mhdp->connector.base.display_info;
+ struct video_info *video = &mhdp->video_info;
+ int vic = drm_match_cea_mode(mode);
+
+ video->color_depth = 8;
+ video->color_fmt = PXL_RGB;
+
+ /* for all other platforms, other than imx8mq */
+ if (strncmp("imx8mq-hdmi", mhdp->plat_data->plat_name, 11)) {
+ if (di->bpc == 10 || di->bpc == 6)
+ video->color_depth = di->bpc;
+
+ return true;
+ }
+
+ /* imx8mq */
+ if (vic == 97 || vic == 96) {
+ if (di->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36)
+ video->color_depth = 12;
+ else if (di->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30)
+ video->color_depth = 10;
+
+ if (drm_mode_is_420_only(di, mode) ||
+ (drm_mode_is_420_also(di, mode) &&
+ video->color_depth > 8)) {
+ video->color_fmt = YCBCR_4_2_0;
+
+ adjusted_mode->private_flags = 1;
+ return true;
+ }
+
+ video->color_depth = 8;
+ return true;
+ }
+
+ /* Any defined maximum tmds clock limit we must not exceed*/
+ if ((di->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_36) &&
+ (mode->clock * 3 / 2 <= di->max_tmds_clock))
+ video->color_depth = 12;
+ else if ((di->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30) &&
+ (mode->clock * 5 / 4 <= di->max_tmds_clock))
+ video->color_depth = 10;
+
+ /* 10-bit color depth for the following modes is not supported */
+ if ((vic == 95 || vic == 94 || vic == 93) && video->color_depth == 10)
+ video->color_depth = 8;
+
+ return true;
+}
+
static const struct drm_bridge_funcs cdns_hdmi_bridge_funcs = {
.attach = cdns_hdmi_bridge_attach,
.mode_set = cdns_hdmi_bridge_mode_set,
.mode_valid = cdns_hdmi_bridge_mode_valid,
+ .mode_fixup = cdns_hdmi_bridge_mode_fixup,
};
static void hotplug_work_func(struct work_struct *work)